summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.gitignore1
-rw-r--r--.mailmap8
-rw-r--r--CREDITS9
-rw-r--r--Documentation/ABI/testing/debugfs-dell-wmi-ddv21
-rw-r--r--Documentation/ABI/testing/debugfs-pktcdvd18
-rw-r--r--Documentation/ABI/testing/sysfs-bus-nvdimm14
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci10
-rw-r--r--Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor6
-rw-r--r--Documentation/ABI/testing/sysfs-class-pktcdvd97
-rw-r--r--Documentation/ABI/testing/sysfs-devices-mapping30
-rw-r--r--Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon75
-rw-r--r--Documentation/ABI/testing/sysfs-driver-intel_sdsi47
-rw-r--r--Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv7
-rw-r--r--Documentation/Makefile11
-rw-r--r--Documentation/PCI/msi-howto.rst10
-rw-r--r--Documentation/PCI/pci-error-recovery.rst7
-rw-r--r--Documentation/RCU/Design/Requirements/Requirements.rst2
-rw-r--r--Documentation/RCU/arrayRCU.rst165
-rw-r--r--Documentation/RCU/checklist.rst244
-rw-r--r--Documentation/RCU/index.rst1
-rw-r--r--Documentation/RCU/listRCU.rst174
-rw-r--r--Documentation/RCU/lockdep.rst4
-rw-r--r--Documentation/accel/index.rst17
-rw-r--r--Documentation/accel/introduction.rst110
-rw-r--r--Documentation/admin-guide/bootconfig.rst2
-rw-r--r--Documentation/admin-guide/device-mapper/dm-init.rst8
-rw-r--r--Documentation/admin-guide/devices.txt5
-rw-r--r--Documentation/admin-guide/hw_random.rst6
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt68
-rw-r--r--Documentation/admin-guide/media/cec-drivers.rst10
-rw-r--r--Documentation/admin-guide/media/cec.rst369
-rw-r--r--Documentation/admin-guide/media/index.rst3
-rw-r--r--Documentation/admin-guide/media/pulse8-cec.rst13
-rw-r--r--Documentation/admin-guide/media/v4l-drivers.rst1
-rw-r--r--Documentation/admin-guide/media/vimc.rst8
-rw-r--r--Documentation/admin-guide/media/visl.rst175
-rw-r--r--Documentation/admin-guide/media/vivid.rst2
-rw-r--r--Documentation/admin-guide/mm/zswap.rst8
-rw-r--r--Documentation/admin-guide/perf/hisi-pcie-pmu.rst112
-rw-r--r--Documentation/admin-guide/perf/index.rst2
-rw-r--r--Documentation/admin-guide/perf/meson-ddr-pmu.rst70
-rw-r--r--Documentation/admin-guide/perf/nvidia-pmu.rst299
-rw-r--r--Documentation/admin-guide/pm/amd-pstate.rst220
-rw-r--r--Documentation/admin-guide/sysctl/fs.rst240
-rw-r--r--Documentation/admin-guide/sysctl/kernel.rst26
-rw-r--r--Documentation/arm/marvell.rst12
-rw-r--r--Documentation/arm64/acpi_object_usage.rst2
-rw-r--r--Documentation/arm64/booting.rst7
-rw-r--r--Documentation/arm64/elf_hwcaps.rst9
-rw-r--r--Documentation/arm64/silicon-errata.rst2
-rw-r--r--Documentation/arm64/sve.rst1
-rw-r--r--Documentation/block/inline-encryption.rst12
-rw-r--r--Documentation/conf.py211
-rw-r--r--Documentation/core-api/kernel-api.rst3
-rw-r--r--Documentation/core-api/local_ops.rst2
-rw-r--r--Documentation/cpu-freq/index.rst9
-rw-r--r--Documentation/dev-tools/kmsan.rst1
-rw-r--r--Documentation/dev-tools/ktap.rst4
-rw-r--r--Documentation/dev-tools/kunit/architecture.rst115
-rw-r--r--Documentation/dev-tools/kunit/index.rst20
-rw-r--r--Documentation/dev-tools/kunit/start.rst18
-rw-r--r--Documentation/dev-tools/kunit/tips.rst190
-rw-r--r--Documentation/dev-tools/kunit/usage.rst92
-rw-r--r--Documentation/devicetree/bindings/arm/amlogic.yaml1
-rw-r--r--Documentation/devicetree/bindings/arm/apple.yaml14
-rw-r--r--Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml3
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml2
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.yaml2
-rw-r--r--Documentation/devicetree/bindings/arm/fsl.yaml3
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek.yaml2
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml14
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml1
-rw-r--r--Documentation/devicetree/bindings/arm/qcom-soc.yaml66
-rw-r--r--Documentation/devicetree/bindings/arm/qcom.yaml232
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip.yaml42
-rw-r--r--Documentation/devicetree/bindings/arm/socionext/uniphier.yaml6
-rw-r--r--Documentation/devicetree/bindings/arm/stm32/stm32.yaml6
-rw-r--r--Documentation/devicetree/bindings/arm/swir.txt12
-rw-r--r--Documentation/devicetree/bindings/arm/ti/k3.yaml1
-rw-r--r--Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml1
-rw-r--r--Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/fsl,imx8m-anatop.yaml51
-rw-r--r--Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt2
-rw-r--r--Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml2
-rw-r--r--Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml117
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml31
-rw-r--r--Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml30
-rw-r--r--Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml182
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml1
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-common.yaml52
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml223
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml222
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml235
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml239
-rw-r--r--Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml217
-rw-r--r--Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml5
-rw-r--r--Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml1
-rw-r--r--Documentation/devicetree/bindings/display/msm/mdp5.txt30
-rw-r--r--Documentation/devicetree/bindings/display/msm/mdss-common.yaml83
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml196
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml95
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml268
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml84
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml198
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml95
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml304
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml98
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml422
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml90
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml270
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sm6115-dpu.yaml94
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml182
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml92
-rw-r--r--Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml330
-rw-r--r--Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml70
-rw-r--r--Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml63
-rw-r--r--Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml67
-rw-r--r--Documentation/devicetree/bindings/dma/apple,admac.yaml3
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.yaml1
-rw-r--r--Documentation/devicetree/bindings/firmware/qcom,scm.yaml3
-rw-r--r--Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.yaml156
-rw-r--r--Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml38
-rw-r--r--Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml29
-rw-r--r--Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml7
-rw-r--r--Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml94
-rw-r--r--Documentation/devicetree/bindings/input/goodix,gt7375p.yaml5
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/apple,aic2.yaml29
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt26
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.yaml60
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-lapic.yaml71
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml34
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt33
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml68
-rw-r--r--Documentation/devicetree/bindings/iommu/apple,dart.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml1
-rw-r--r--Documentation/devicetree/bindings/media/allwinner,sun50i-h6-vpu-g2.yaml5
-rw-r--r--Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml101
-rw-r--r--Documentation/devicetree/bindings/media/i2c/imx290.txt57
-rw-r--r--Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml3
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov5645.txt54
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml134
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov5645.yaml104
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml3
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml14
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml129
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml113
-rw-r--r--Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.yaml178
-rw-r--r--Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml3
-rw-r--r--Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml168
-rw-r--r--Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml147
-rw-r--r--Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml12
-rw-r--r--Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml1
-rw-r--r--Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml1
-rw-r--r--Documentation/devicetree/bindings/media/microchip,xisc.yaml3
-rw-r--r--Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml157
-rw-r--r--Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml149
-rw-r--r--Documentation/devicetree/bindings/media/s5p-mfc.txt10
-rw-r--r--Documentation/devicetree/bindings/media/samsung-s5c73m3.txt2
-rw-r--r--Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/video-interfaces.yaml5
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml (renamed from Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml)80
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-channel.yaml146
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-props.yaml74
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml48
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr3.yaml44
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr4.yaml35
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr5.yaml46
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml38
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml5
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi-props.yaml144
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml138
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ti,gpmc-child.yaml7
-rw-r--r--Documentation/devicetree/bindings/mfd/google,cros-ec.yaml103
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml1
-rw-r--r--Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt8
-rw-r--r--Documentation/devicetree/bindings/mips/brcm/soc.yaml96
-rw-r--r--Documentation/devicetree/bindings/mips/cpus.yaml115
-rw-r--r--Documentation/devicetree/bindings/mips/ingenic/ingenic,cpu.yaml69
-rw-r--r--Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml34
-rw-r--r--Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml5
-rw-r--r--Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml32
-rw-r--r--Documentation/devicetree/bindings/mtd/atmel-nand.txt6
-rw-r--r--Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml96
-rw-r--r--Documentation/devicetree/bindings/mtd/denali,nand.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/ingenic,nand.yaml146
-rw-r--r--Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml50
-rw-r--r--Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml20
-rw-r--r--Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt2
-rw-r--r--Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt2
-rw-r--r--Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml16
-rw-r--r--Documentation/devicetree/bindings/mtd/mtd-physmap.yaml7
-rw-r--r--Documentation/devicetree/bindings/mtd/mtd.yaml24
-rw-r--r--Documentation/devicetree/bindings/mtd/mtk-nand.txt2
-rw-r--r--Documentation/devicetree/bindings/mtd/nand-chip.yaml4
-rw-r--r--Documentation/devicetree/bindings/mtd/nand-controller.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/partition.txt33
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml30
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml2
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml4
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/partition.yaml5
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/partitions.yaml41
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml38
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml6
-rw-r--r--Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml57
-rw-r--r--Documentation/devicetree/bindings/mtd/qcom,nandc.yaml131
-rw-r--r--Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml4
-rw-r--r--Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml47
-rw-r--r--Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml36
-rw-r--r--Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml3
-rw-r--r--Documentation/devicetree/bindings/net/engleder,tsnep.yaml2
-rw-r--r--Documentation/devicetree/bindings/net/micrel,ks8851.yaml1
-rw-r--r--Documentation/devicetree/bindings/nvmem/snvs-lpgpr.yaml20
-rw-r--r--Documentation/devicetree/bindings/opp/opp-v2-base.yaml6
-rw-r--r--Documentation/devicetree/bindings/opp/opp-v2.yaml2
-rw-r--r--Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.yaml34
-rw-r--r--Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml2
-rw-r--r--Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml54
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra-pinmux-common.yaml178
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt131
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.yaml155
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt153
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.yaml176
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt107
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.yaml284
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt143
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.yaml112
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt166
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.yaml142
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt144
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.yaml176
-rw-r--r--Documentation/devicetree/bindings/power/qcom,rpmpd.yaml4
-rw-r--r--Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml4
-rw-r--r--Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml1
-rw-r--r--Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml4
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt77
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.yaml96
-rw-r--r--Documentation/devicetree/bindings/regulator/google,cros-ec-regulator.yaml1
-rw-r--r--Documentation/devicetree/bindings/riscv/cpus.yaml13
-rw-r--r--Documentation/devicetree/bindings/riscv/starfive.yaml4
-rw-r--r--Documentation/devicetree/bindings/soc/mediatek/pwrap.txt3
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml2
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml54
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml171
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml5
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml28
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml2
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml3
-rw-r--r--Documentation/devicetree/bindings/soc/renesas/renesas,r9a09g011-sys.yaml43
-rw-r--r--Documentation/devicetree/bindings/soc/renesas/renesas.yaml (renamed from Documentation/devicetree/bindings/arm/renesas.yaml)5
-rw-r--r--Documentation/devicetree/bindings/sound/adi,adau1372.yaml7
-rw-r--r--Documentation/devicetree/bindings/sound/adi,adau1977.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/adi,adau7118.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/ak4375.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/ak4613.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/ak4642.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml12
-rw-r--r--Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,aiu.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,t9015.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/apple,mca.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/awinic,aw8738.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,madera.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/dai-common.yaml (renamed from Documentation/devicetree/bindings/sound/name-prefix.yaml)6
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/dmic-codec.yaml55
-rw-r--r--Documentation/devicetree/bindings/sound/dmic.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/everest,es8316.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,micfil.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml36
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,sai.yaml100
-rw-r--r--Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/ingenic,aic.yaml15
-rw-r--r--Documentation/devicetree/bindings/sound/ingenic,codec.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/linux,bt-sco.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/max98357a.txt28
-rw-r--r--Documentation/devicetree/bindings/sound/max98504.txt44
-rw-r--r--Documentation/devicetree/bindings/sound/maxim,max98357a.yaml52
-rw-r--r--Documentation/devicetree/bindings/sound/maxim,max98504.yaml86
-rw-r--r--Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml18
-rw-r--r--Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/microchip,pdmc.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml14
-rw-r--r--Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/mvebu-audio.txt14
-rw-r--r--Documentation/devicetree/bindings/sound/nau8315.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra186-asrc.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml27
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6adm.yaml51
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6afe.yaml68
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml19
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml35
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6apm.yaml68
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml48
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6asm.yaml68
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6core.yaml39
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml40
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml57
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6prm.yaml50
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wcd9335.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml15
-rw-r--r--Documentation/devicetree/bindings/sound/realtek,rt1015p.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml31
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,fsi.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/richtek,rt9120.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml7
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,pdm.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-i2s.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-spdif.yaml23
-rw-r--r--Documentation/devicetree/bindings/sound/rohm,bd28623.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rt5659.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/rt5682.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/samsung-i2s.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/sgtl5000.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/simple-audio-mux.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml30
-rw-r--r--Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/tas2562.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/tas2770.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/tas27xx.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/ti,src4xxx.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,arizona.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8731.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8940.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8961.yaml43
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8962.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8978.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/zl38060.yaml5
-rw-r--r--Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml4
-rw-r--r--Documentation/devicetree/bindings/sram/qcom,imem.yaml1
-rw-r--r--Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml6
-rw-r--r--Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml8
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,cmt.yaml2
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,tmu.yaml1
-rw-r--r--Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ehci.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ohci.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt132
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.yaml202
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra186-xusb.yaml173
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra194-xusb.yaml179
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra210-xusb.yaml199
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml12
-rw-r--r--Documentation/doc-guide/sphinx.rst16
-rw-r--r--Documentation/driver-api/dma-buf.rst6
-rw-r--r--Documentation/driver-api/driver-model/devres.rst8
-rw-r--r--Documentation/driver-api/eisa.rst2
-rw-r--r--Documentation/driver-api/miscellaneous.rst5
-rw-r--r--Documentation/fault-injection/fault-injection.rst10
-rw-r--r--Documentation/fb/modedb.rst5
-rw-r--r--Documentation/features/core/cBPF-JIT/arch-support.txt2
-rw-r--r--Documentation/features/core/eBPF-JIT/arch-support.txt2
-rw-r--r--Documentation/features/core/generic-idle-thread/arch-support.txt2
-rw-r--r--Documentation/features/core/jump-labels/arch-support.txt4
-rw-r--r--Documentation/features/core/thread-info-in-task/arch-support.txt2
-rw-r--r--Documentation/features/core/tracehook/arch-support.txt2
-rw-r--r--Documentation/features/debug/KASAN/arch-support.txt4
-rw-r--r--Documentation/features/debug/debug-vm-pgtable/arch-support.txt2
-rw-r--r--Documentation/features/debug/gcov-profile-all/arch-support.txt2
-rw-r--r--Documentation/features/debug/kcov/arch-support.txt2
-rw-r--r--Documentation/features/debug/kgdb/arch-support.txt2
-rw-r--r--Documentation/features/debug/kmemleak/arch-support.txt2
-rw-r--r--Documentation/features/debug/kprobes-on-ftrace/arch-support.txt2
-rw-r--r--Documentation/features/debug/kprobes/arch-support.txt2
-rw-r--r--Documentation/features/debug/kretprobes/arch-support.txt2
-rw-r--r--Documentation/features/debug/optprobes/arch-support.txt2
-rw-r--r--Documentation/features/debug/stackprotector/arch-support.txt2
-rw-r--r--Documentation/features/debug/uprobes/arch-support.txt2
-rw-r--r--Documentation/features/debug/user-ret-profiler/arch-support.txt2
-rw-r--r--Documentation/features/io/dma-contiguous/arch-support.txt2
-rw-r--r--Documentation/features/locking/cmpxchg-local/arch-support.txt2
-rw-r--r--Documentation/features/locking/lockdep/arch-support.txt2
-rw-r--r--Documentation/features/locking/queued-rwlocks/arch-support.txt2
-rw-r--r--Documentation/features/locking/queued-spinlocks/arch-support.txt4
-rw-r--r--Documentation/features/perf/kprobes-event/arch-support.txt2
-rw-r--r--Documentation/features/perf/perf-regs/arch-support.txt2
-rw-r--r--Documentation/features/perf/perf-stackdump/arch-support.txt2
-rw-r--r--Documentation/features/sched/membarrier-sync-core/arch-support.txt2
-rw-r--r--Documentation/features/sched/numa-balancing/arch-support.txt2
-rwxr-xr-xDocumentation/features/scripts/features-refresh.sh2
-rw-r--r--Documentation/features/seccomp/seccomp-filter/arch-support.txt2
-rw-r--r--Documentation/features/time/arch-tick-broadcast/arch-support.txt2
-rw-r--r--Documentation/features/time/clockevents/arch-support.txt2
-rw-r--r--Documentation/features/time/context-tracking/arch-support.txt2
-rw-r--r--Documentation/features/time/irq-time-acct/arch-support.txt2
-rw-r--r--Documentation/features/time/virt-cpuacct/arch-support.txt2
-rw-r--r--Documentation/features/vm/ELF-ASLR/arch-support.txt2
-rw-r--r--Documentation/features/vm/PG_uncached/arch-support.txt2
-rw-r--r--Documentation/features/vm/THP/arch-support.txt2
-rw-r--r--Documentation/features/vm/TLB/arch-support.txt2
-rw-r--r--Documentation/features/vm/huge-vmap/arch-support.txt2
-rw-r--r--Documentation/features/vm/ioremap_prot/arch-support.txt2
-rw-r--r--Documentation/features/vm/pte_special/arch-support.txt2
-rw-r--r--Documentation/filesystems/configfs.rst48
-rw-r--r--Documentation/filesystems/debugfs.rst8
-rw-r--r--Documentation/filesystems/erofs.rst38
-rw-r--r--Documentation/filesystems/fscrypt.rst7
-rw-r--r--Documentation/filesystems/locking.rst10
-rw-r--r--Documentation/filesystems/mount_api.rst12
-rw-r--r--Documentation/filesystems/porting.rst4
-rw-r--r--Documentation/filesystems/proc.rst20
-rw-r--r--Documentation/filesystems/sysfs.rst41
-rw-r--r--Documentation/filesystems/vfs.rst5
-rw-r--r--Documentation/gpu/amdgpu/amdgpu-glossary.rst23
-rw-r--r--Documentation/gpu/amdgpu/driver-core.rst4
-rw-r--r--Documentation/gpu/amdgpu/index.rst2
-rw-r--r--Documentation/gpu/drm-kms-helpers.rst3
-rw-r--r--Documentation/gpu/drm-usage-stats.rst1
-rw-r--r--Documentation/gpu/i915.rst2
-rw-r--r--Documentation/gpu/todo.rst11
-rw-r--r--Documentation/ia64/aliasing.rst2
-rw-r--r--Documentation/kernel-hacking/locking.rst17
-rw-r--r--Documentation/loongarch/booting.rst42
-rw-r--r--Documentation/loongarch/index.rst1
-rw-r--r--Documentation/loongarch/introduction.rst8
-rw-r--r--Documentation/memory-barriers.txt2
-rw-r--r--Documentation/mm/slub.rst2
-rw-r--r--Documentation/networking/generic_netlink.rst2
-rw-r--r--Documentation/process/code-of-conduct-interpretation.rst2
-rw-r--r--Documentation/process/kernel-docs.rst477
-rw-r--r--Documentation/riscv/vm-layout.rst36
-rw-r--r--Documentation/sphinx-static/custom.css29
-rw-r--r--Documentation/sphinx/requirements.txt1
-rw-r--r--Documentation/subsystem-apis.rst1
-rw-r--r--Documentation/timers/hrtimers.rst2
-rw-r--r--Documentation/tools/index.rst1
-rw-r--r--Documentation/tools/rv/Makefile52
-rw-r--r--Documentation/tools/rv/common_appendix.rst16
-rw-r--r--Documentation/tools/rv/common_ikm.rst21
-rw-r--r--Documentation/tools/rv/index.rst24
-rw-r--r--Documentation/tools/rv/rv-list.rst43
-rw-r--r--Documentation/tools/rv/rv-mon-wip.rst44
-rw-r--r--Documentation/tools/rv/rv-mon-wwnr.rst43
-rw-r--r--Documentation/tools/rv/rv-mon.rst55
-rw-r--r--Documentation/tools/rv/rv.rst63
-rw-r--r--Documentation/trace/ftrace.rst2
-rw-r--r--Documentation/translations/index.rst1
-rw-r--r--Documentation/translations/it_IT/kernel-hacking/locking.rst14
-rw-r--r--Documentation/translations/ja_JP/howto.rst66
-rw-r--r--Documentation/translations/ko_KR/memory-barriers.txt149
-rw-r--r--Documentation/translations/sp_SP/disclaimer-sp.rst6
-rw-r--r--Documentation/translations/sp_SP/howto.rst617
-rw-r--r--Documentation/translations/sp_SP/index.rst81
-rw-r--r--Documentation/translations/sp_SP/memory-barriers.txt3134
-rw-r--r--Documentation/translations/sp_SP/process/coding-style.rst1315
-rw-r--r--Documentation/translations/sp_SP/process/index.rst15
-rw-r--r--Documentation/translations/sp_SP/process/kernel-docs.rst187
-rw-r--r--Documentation/translations/sp_SP/process/submitting-patches.rst894
-rw-r--r--Documentation/translations/sp_SP/wrappers/memory-barriers.rst19
-rw-r--r--Documentation/translations/zh_CN/core-api/errseq.rst145
-rw-r--r--Documentation/translations/zh_CN/core-api/index.rst6
-rw-r--r--Documentation/translations/zh_CN/core-api/local_ops.rst2
-rw-r--r--Documentation/translations/zh_CN/core-api/this_cpu_ops.rst285
-rw-r--r--Documentation/translations/zh_CN/doc-guide/index.rst2
-rw-r--r--Documentation/translations/zh_CN/index.rst11
-rw-r--r--Documentation/translations/zh_CN/loongarch/booting.rst48
-rw-r--r--Documentation/translations/zh_CN/loongarch/index.rst1
-rw-r--r--Documentation/translations/zh_CN/loongarch/introduction.rst12
-rw-r--r--Documentation/translations/zh_CN/rust/arch-support.rst23
-rw-r--r--Documentation/translations/zh_CN/rust/coding-guidelines.rst192
-rw-r--r--Documentation/translations/zh_CN/rust/general-information.rst75
-rw-r--r--Documentation/translations/zh_CN/rust/index.rst28
-rw-r--r--Documentation/translations/zh_CN/rust/quick-start.rst211
-rw-r--r--Documentation/translations/zh_CN/staging/index.rst26
-rw-r--r--Documentation/translations/zh_CN/staging/xz.rst100
-rw-r--r--Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst168
-rw-r--r--Documentation/translations/zh_CN/userspace-api/ebpf/index.rst22
-rw-r--r--Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst29
-rw-r--r--Documentation/translations/zh_CN/userspace-api/futex2.rst80
-rw-r--r--Documentation/translations/zh_CN/userspace-api/index.rst50
-rw-r--r--Documentation/translations/zh_CN/userspace-api/no_new_privs.rst57
-rw-r--r--Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst293
-rw-r--r--Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst40
-rw-r--r--Documentation/usb/CREDITS6
-rw-r--r--Documentation/usb/functionfs.rst2
-rw-r--r--Documentation/usb/gadget_multi.rst2
-rw-r--r--Documentation/userspace-api/landlock.rst67
-rw-r--r--Documentation/userspace-api/media/Makefile3
-rw-r--r--Documentation/userspace-api/media/cec/cec-pin-error-inj.rst2
-rw-r--r--Documentation/userspace-api/media/drivers/aspeed-video.rst65
-rw-r--r--Documentation/userspace-api/media/drivers/index.rst2
-rw-r--r--Documentation/userspace-api/media/drivers/st-vgxy61.rst25
-rw-r--r--Documentation/userspace-api/media/dvb/fe_property_parameters.rst25
-rw-r--r--Documentation/userspace-api/media/frontend.h.rst.exceptions28
-rw-r--r--Documentation/userspace-api/media/v4l/buffer.rst11
-rw-r--r--Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst8
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-reserved.rst17
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst8
-rw-r--r--Documentation/userspace-api/media/v4l/subdev-formats.rst37
-rw-r--r--Documentation/virt/coco/tdx-guest.rst52
-rw-r--r--Documentation/virt/index.rst1
-rw-r--r--Documentation/virt/kvm/api.rst15
-rw-r--r--Documentation/virt/kvm/devices/vm.rst3
-rw-r--r--Documentation/virt/kvm/halt-polling.rst (renamed from Documentation/virt/kvm/x86/halt-polling.rst)13
-rw-r--r--Documentation/virt/kvm/index.rst1
-rw-r--r--Documentation/virt/kvm/x86/index.rst1
-rw-r--r--Documentation/x86/boot.rst1
-rw-r--r--Documentation/x86/tdx.rst43
-rw-r--r--MAINTAINERS292
-rw-r--r--Makefile12
-rw-r--r--arch/Kconfig10
-rw-r--r--arch/alpha/include/asm/elf.h6
-rw-r--r--arch/alpha/include/asm/ptrace.h1
-rw-r--r--arch/alpha/include/asm/thread_info.h6
-rw-r--r--arch/alpha/kernel/entry.S14
-rw-r--r--arch/alpha/kernel/process.c8
-rw-r--r--arch/arc/kernel/ptrace.c2
-rw-r--r--arch/arm/boot/dts/Makefile13
-rw-r--r--arch/arm/boot/dts/am335x-baltos-leds.dtsi6
-rw-r--r--arch/arm/boot/dts/am335x-boneblack-hdmi.dtsi7
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts4
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts2
-rw-r--r--arch/arm/boot/dts/am335x-guardian.dts3
-rw-r--r--arch/arm/boot/dts/am335x-igep0033.dtsi4
-rw-r--r--arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi10
-rw-r--r--arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi10
-rw-r--r--arch/arm/boot/dts/am335x-myirtech-myd.dts7
-rw-r--r--arch/arm/boot/dts/am335x-pcm-953.dtsi28
-rw-r--r--arch/arm/boot/dts/am335x-pepper.dts4
-rw-r--r--arch/arm/boot/dts/am335x-pocketbeagle.dts8
-rw-r--r--arch/arm/boot/dts/am3517-evm.dts18
-rw-r--r--arch/arm/boot/dts/am3517.dtsi38
-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/am57xx-idk-common.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-370-dlink-dns327l.dts6
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn102.dts10
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn104.dts10
-rw-r--r--arch/arm/boot/dts/armada-370-rd.dts16
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts4
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi8
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-370-synology-ds213j.dts6
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-375.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-380.dtsi4
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-caiman.dts4
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-cobra.dts4
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-rango.dts8
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-shelby.dts4
-rw-r--r--arch/arm/boot/dts/armada-385-linksys.dtsi4
-rw-r--r--arch/arm/boot/dts/armada-385-synology-ds116.dts2
-rw-r--r--arch/arm/boot/dts/armada-385-turris-omnia.dts18
-rw-r--r--arch/arm/boot/dts/armada-385.dtsi6
-rw-r--r--arch/arm/boot/dts/armada-38x.dtsi4
-rw-r--r--arch/arm/boot/dts/armada-39x.dtsi10
-rw-r--r--arch/arm/boot/dts/armada-xp-98dx3236.dtsi1
-rw-r--r--arch/arm/boot/dts/armada-xp-linksys-mamba.dts2
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78230.dtsi8
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78260.dtsi16
-rw-r--r--arch/arm/boot/dts/armada-xp-netgear-rn2120.dts10
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi1
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts12
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ampere-mtmitchell.dts4
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-delta-ahe50dc.dts418
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts213
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-cloudripper.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-elbert.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ibm-bonnell.dts921
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts57
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts244
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts1381
-rw-r--r--arch/arm/boot/dts/aspeed-g6.dtsi4
-rw-r--r--arch/arm/boot/dts/ast2600-facebook-netbmc-common.dtsi2
-rw-r--r--arch/arm/boot/dts/at91-sam9x60ek.dts4
-rw-r--r--arch/arm/boot/dts/at91-sama7g5ek.dts5
-rw-r--r--arch/arm/boot/dts/at91rm9200.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi9
-rw-r--r--arch/arm/boot/dts/axp22x.dtsi6
-rw-r--r--arch/arm/boot/dts/axp809.dtsi7
-rw-r--r--arch/arm/boot/dts/axp81x.dtsi14
-rw-r--r--arch/arm/boot/dts/bcm2711-rpi-4-b.dts31
-rw-r--r--arch/arm/boot/dts/bcm2711-rpi-400.dts16
-rw-r--r--arch/arm/boot/dts/bcm2711-rpi-cm4-io.dts27
-rw-r--r--arch/arm/boot/dts/bcm2711-rpi-cm4.dtsi4
-rw-r--r--arch/arm/boot/dts/bcm2711.dtsi95
-rw-r--r--arch/arm/boot/dts/bcm2835-common.dtsi18
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a-plus.dts28
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a.dts12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-plus.dts28
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi6
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-common.dtsi17
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-zero-w.dts12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-zero.dts12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi10
-rw-r--r--arch/arm/boot/dts/bcm2835.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm2836-rpi-2-b.dts27
-rw-r--r--arch/arm/boot/dts/bcm2836-rpi.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm2836.dtsi4
-rw-r--r--arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts27
-rw-r--r--arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts27
-rw-r--r--arch/arm/boot/dts/bcm2837-rpi-3-b.dts11
-rw-r--r--arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi8
-rw-r--r--arch/arm/boot/dts/bcm2837-rpi-zero-2-w.dts11
-rw-r--r--arch/arm/boot/dts/bcm2837.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm283x-rpi-led-deprecated.dtsi18
-rw-r--r--arch/arm/boot/dts/bcm283x.dtsi70
-rw-r--r--arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts15
-rw-r--r--arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts8
-rw-r--r--arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi16
-rw-r--r--arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts16
-rw-r--r--arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts6
-rw-r--r--arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts2
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6250.dts10
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts10
-rw-r--r--arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts22
-rw-r--r--arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts10
-rw-r--r--arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts14
-rw-r--r--arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts16
-rw-r--r--arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts6
-rw-r--r--arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts20
-rw-r--r--arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts43
-rw-r--r--arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts6
-rw-r--r--arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts18
-rw-r--r--arch/arm/boot/dts/bcm4709-netgear-r7000.dts16
-rw-r--r--arch/arm/boot/dts/bcm4709-netgear-r8000.dts22
-rw-r--r--arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts43
-rw-r--r--arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts12
-rw-r--r--arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts14
-rw-r--r--arch/arm/boot/dts/bcm47094-dlink-dir-890l.dts211
-rw-r--r--arch/arm/boot/dts/bcm47094-linksys-panamera.dts28
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts4
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts6
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts4
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts2
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts20
-rw-r--r--arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts10
-rw-r--r--arch/arm/boot/dts/bcm47094-netgear-r8500.dts14
-rw-r--r--arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts4
-rw-r--r--arch/arm/boot/dts/bcm47189-luxul-xap-810.dts10
-rw-r--r--arch/arm/boot/dts/bcm47189-tenda-ac9.dts14
-rw-r--r--arch/arm/boot/dts/bcm47622.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm53016-dlink-dwl-8610ap.dts131
-rw-r--r--arch/arm/boot/dts/bcm53016-meraki-mr32.dts6
-rw-r--r--arch/arm/boot/dts/bcm63148.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm63178.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm6756.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm6846.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm6855.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm6878.dtsi1
-rw-r--r--arch/arm/boot/dts/bcm947189acdbmr.dts6
-rw-r--r--arch/arm/boot/dts/dove.dtsi2
-rw-r--r--arch/arm/boot/dts/dra7-evm-common.dtsi2
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts2
-rw-r--r--arch/arm/boot/dts/dra72-evm-common.dtsi4
-rw-r--r--arch/arm/boot/dts/e60k02.dtsi11
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6dl-colibri-aster.dts1
-rw-r--r--arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts1
-rw-r--r--arch/arm/boot/dts/imx6dl-colibri-iris.dts1
-rw-r--r--arch/arm/boot/dts/imx6q-prti6q.dts4
-rw-r--r--arch/arm/boot/dts/imx6qdl-colibri.dtsi22
-rw-r--r--arch/arm/boot/dts/imx6qdl-pico.dtsi1
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabrelite.dtsi5
-rw-r--r--arch/arm/boot/dts/imx6qdl-wandboard.dtsi1
-rw-r--r--arch/arm/boot/dts/imx6sl-kobo-aura2.dts555
-rw-r--r--arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts30
-rw-r--r--arch/arm/boot/dts/imx6sl-tolino-shine3.dts7
-rw-r--r--arch/arm/boot/dts/imx6sll-kobo-clarahd.dts7
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi4
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-aster.dts40
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts24
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-iris-v2.dts48
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-iris.dts22
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-iris.dtsi4
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-wifi-aster.dts40
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts24
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-wifi-iris-v2.dts32
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri-wifi-iris.dts20
-rw-r--r--arch/arm/boot/dts/imx6ull-colibri.dtsi37
-rw-r--r--arch/arm/boot/dts/imx7-colibri.dtsi5
-rw-r--r--arch/arm/boot/dts/imx7d-remarkable2.dts62
-rw-r--r--arch/arm/boot/dts/kirkwood-b3.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-db-88f6281.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-db-88f6282.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-dir665.dts14
-rw-r--r--arch/arm/boot/dts/kirkwood-ds112.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-ds411.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-iconnect.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-km_common.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-l-50.dts24
-rw-r--r--arch/arm/boot/dts/kirkwood-laplug.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-linkstation.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-mplcec4.dts16
-rw-r--r--arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-nas2big.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-net2big.dts10
-rw-r--r--arch/arm/boot/dts/kirkwood-net5big.dts10
-rw-r--r--arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts12
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa310.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa310s.dts259
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa320.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa325.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-rd88f6192.dts60
-rw-r--r--arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-rd88f6281.dtsi4
-rw-r--r--arch/arm/boot/dts/kirkwood-rs212.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-synology.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-t5325.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-ts219.dtsi4
-rw-r--r--arch/arm/boot/dts/kirkwood.dtsi34
-rw-r--r--arch/arm/boot/dts/lan966x-pcb8290.dts16
-rw-r--r--arch/arm/boot/dts/lan966x-pcb8291.dts20
-rw-r--r--arch/arm/boot/dts/lan966x.dtsi5
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi2
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-som.dtsi2
-rw-r--r--arch/arm/boot/dts/lpc32xx.dtsi2
-rw-r--r--arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts10
-rw-r--r--arch/arm/boot/dts/motorola-mapphone-common.dtsi4
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730-gbs.dts2
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730-gsj.dts2
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730-kudo.dts6
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-evb.dts4
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts6
-rw-r--r--arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts36
-rw-r--r--arch/arm/boot/dts/nuvoton-wpcm450.dtsi34
-rw-r--r--arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi6
-rw-r--r--arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi6
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts6
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3517.dts12
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000-common.dtsi8
-rw-r--r--arch/arm/boot/dts/omap3-echo.dts2
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi8
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts42
-rw-r--r--arch/arm/boot/dts/omap3-overo-alto35-common.dtsi8
-rw-r--r--arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo35-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-summit-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-tobi-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-zoom3.dts44
-rw-r--r--arch/arm/boot/dts/omap3.dtsi40
-rw-r--r--arch/arm/boot/dts/omap34xx.dtsi4
-rw-r--r--arch/arm/boot/dts/omap36xx.dtsi4
-rw-r--r--arch/arm/boot/dts/omap4-cpu-thermal.dtsi24
-rw-r--r--arch/arm/boot/dts/omap4-panda-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap4-panda-es.dts4
-rw-r--r--arch/arm/boot/dts/omap5-cm-t54.dts64
-rw-r--r--arch/arm/boot/dts/pxa168.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts2
-rw-r--r--arch/arm/boot/dts/qcom-apq8026-huawei-sturgeon.dts376
-rw-r--r--arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts9
-rw-r--r--arch/arm/boot/dts/qcom-apq8026-samsung-matisse-wifi.dts453
-rw-r--r--arch/arm/boot/dts/qcom-apq8060-dragonboard.dts1754
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts524
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts390
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-ifc6410.dts561
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts650
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi149
-rw-r--r--arch/arm/boot/dts/qcom-apq8074-dragonboard.dts60
-rw-r--r--arch/arm/boot/dts/qcom-apq8084.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts6
-rw-r--r--arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts6
-rw-r--r--arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts2
-rw-r--r--arch/arm/boot/dts/qcom-ipq4019.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom-ipq8064-rb3011.dts5
-rw-r--r--arch/arm/boot/dts/qcom-ipq8064.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts59
-rw-r--r--arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi61
-rw-r--r--arch/arm/boot/dts/qcom-mdm9615.dtsi123
-rw-r--r--arch/arm/boot/dts/qcom-msm8226-samsung-s3ve3g.dts1
-rw-r--r--arch/arm/boot/dts/qcom-msm8226.dtsi78
-rw-r--r--arch/arm/boot/dts/qcom-msm8660.dtsi42
-rw-r--r--arch/arm/boot/dts/qcom-msm8960-cdp.dts23
-rw-r--r--arch/arm/boot/dts/qcom-msm8960.dtsi92
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts83
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-amami.dts1
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-honami.dts1
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi70
-rw-r--r--arch/arm/boot/dts/qcom-msm8974.dtsi174
-rw-r--r--arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts75
-rw-r--r--arch/arm/boot/dts/qcom-msm8974pro-oneplus-bacon.dts417
-rw-r--r--arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts83
-rw-r--r--arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts86
-rw-r--r--arch/arm/boot/dts/qcom-pm8226.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom-pm8941.dtsi33
-rw-r--r--arch/arm/boot/dts/qcom-pma8084.dtsi19
-rw-r--r--arch/arm/boot/dts/qcom-pmx65.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts45
-rw-r--r--arch/arm/boot/dts/qcom-sdx55.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom-sdx65.dtsi4
-rw-r--r--arch/arm/boot/dts/r8a7742.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7793.dtsi2
-rw-r--r--arch/arm/boot/dts/r9a06g032.dtsi10
-rw-r--r--arch/arm/boot/dts/rk3036-evb.dts3
-rw-r--r--arch/arm/boot/dts/rk3066a-mk808.dts2
-rw-r--r--arch/arm/boot/dts/rk3188-radxarock.dts2
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi3
-rw-r--r--arch/arm/boot/dts/rk3288-evb-act8846.dts2
-rw-r--r--arch/arm/boot/dts/rk3288-evb.dtsi6
-rw-r--r--arch/arm/boot/dts/rk3288-firefly.dtsi3
-rw-r--r--arch/arm/boot/dts/rk3288-miqi.dts3
-rw-r--r--arch/arm/boot/dts/rk3288-rock2-square.dts3
-rw-r--r--arch/arm/boot/dts/rk3288-vmarc-som.dtsi1
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi7
-rw-r--r--arch/arm/boot/dts/sama7g5-pinfunc.h4
-rw-r--r--arch/arm/boot/dts/sama7g5.dtsi67
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi4
-rw-r--r--arch/arm/boot/dts/socfpga_arria10.dtsi4
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts4
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts1
-rw-r--r--arch/arm/boot/dts/socfpga_arria5.dtsi3
-rw-r--r--arch/arm/boot/dts/socfpga_arria5_socdk.dts8
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5.dtsi3
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dts2
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_socdk.dts8
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts2
-rw-r--r--arch/arm/boot/dts/socfpga_vt.dts2
-rw-r--r--arch/arm/boot/dts/spear600.dtsi32
-rw-r--r--arch/arm/boot/dts/ste-dbx5x0.dtsi6
-rw-r--r--arch/arm/boot/dts/ste-ux500-samsung-codina-tmo.dts2
-rw-r--r--arch/arm/boot/dts/ste-ux500-samsung-codina.dts2
-rw-r--r--arch/arm/boot/dts/ste-ux500-samsung-gavini.dts2
-rw-r--r--arch/arm/boot/dts/ste-ux500-samsung-janice.dts16
-rw-r--r--arch/arm/boot/dts/ste-ux500-samsung-kyle.dts29
-rw-r--r--arch/arm/boot/dts/stih410-b2260.dts8
-rw-r--r--arch/arm/boot/dts/stih418-b2199.dts4
-rw-r--r--arch/arm/boot/dts/stih418-b2264.dts2
-rw-r--r--arch/arm/boot/dts/stihxxx-b2120.dtsi4
-rw-r--r--arch/arm/boot/dts/stm32h743.dtsi2
-rw-r--r--arch/arm/boot/dts/stm32mp13-pinctrl.dtsi21
-rw-r--r--arch/arm/boot/dts/stm32mp131.dtsi126
-rw-r--r--arch/arm/boot/dts/stm32mp133.dtsi31
-rw-r--r--arch/arm/boot/dts/stm32mp135f-dk.dts144
-rw-r--r--arch/arm/boot/dts/stm32mp151.dtsi3
-rw-r--r--arch/arm/boot/dts/stm32mp151a-dhcor-testbench.dts17
-rw-r--r--arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts1
-rw-r--r--arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi2
-rw-r--r--arch/arm/boot/dts/stm32mp157c-ev1.dts15
-rw-r--r--arch/arm/boot/dts/stm32mp157c-lxa-mc1.dts2
-rw-r--r--arch/arm/boot/dts/stm32mp157c-odyssey.dts2
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi4
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi2
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi7
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi2
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dhcor-testbench.dtsi171
-rw-r--r--arch/arm/boot/dts/stm32mp15xx-dkx.dtsi6
-rw-r--r--arch/arm/boot/dts/suniv-f1c100s.dtsi70
-rw-r--r--arch/arm/boot/dts/sunplus-sp7021.dtsi3
-rw-r--r--arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi14
-rw-r--r--arch/arm/boot/dts/sunxi-h3-h5.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra114-asus-tf701t.dts24
-rw-r--r--arch/arm/boot/dts/tegra124-nyan-big.dts3
-rw-r--r--arch/arm/boot/dts/tegra124-nyan-blaze.dts3
-rw-r--r--arch/arm/boot/dts/tegra124-venice2.dts3
-rw-r--r--arch/arm/boot/dts/tegra20-acer-a500-picasso.dts6
-rw-r--r--arch/arm/boot/dts/tegra20-asus-tf101.dts8
-rw-r--r--arch/arm/boot/dts/tegra20-seaboard.dts6
-rw-r--r--arch/arm/boot/dts/tegra20-tamonten.dtsi6
-rw-r--r--arch/arm/boot/dts/tegra20-ventana.dts6
-rw-r--r--arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi10
-rw-r--r--arch/arm/boot/dts/tegra30-pegatron-chagall.dts11
-rw-r--r--arch/arm/boot/dts/uniphier-pro5-epcore.dts76
-rw-r--r--arch/arm/boot/dts/uniphier-pro5-proex.dts59
-rw-r--r--arch/arm/boot/dts/vexpress-v2m.dtsi16
-rw-r--r--arch/arm/boot/dts/vf610-zii-dev-rev-c.dts2
-rw-r--r--arch/arm/configs/clps711x_defconfig3
-rw-r--r--arch/arm/configs/collie_defconfig3
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig5
-rw-r--r--arch/arm/configs/multi_v4t_defconfig3
-rw-r--r--arch/arm/configs/multi_v7_defconfig8
-rw-r--r--arch/arm/configs/omap1_defconfig3
-rw-r--r--arch/arm/configs/pxa_defconfig3
-rw-r--r--arch/arm/configs/qcom_defconfig5
-rw-r--r--arch/arm/configs/sama5_defconfig2
-rw-r--r--arch/arm/configs/sama7_defconfig11
-rw-r--r--arch/arm/configs/spear6xx_defconfig7
-rw-r--r--arch/arm/configs/tct_hammer_defconfig3
-rw-r--r--arch/arm/configs/xcep_defconfig3
-rw-r--r--arch/arm/include/asm/perf_event.h2
-rw-r--r--arch/arm/include/asm/pgtable-nommu.h6
-rw-r--r--arch/arm/include/asm/pgtable.h16
-rw-r--r--arch/arm/include/asm/stackprotector.h9
-rw-r--r--arch/arm/kernel/machine_kexec.c2
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/arm/kernel/ptrace.c8
-rw-r--r--arch/arm/mach-at91/pm_suspend.S7
-rw-r--r--arch/arm/mach-at91/sama5.c2
-rw-r--r--arch/arm/mach-imx/mm-imx3.c1
-rw-r--r--arch/arm/mach-ixp4xx/ixp4xx-of.c42
-rw-r--r--arch/arm/mach-keystone/Makefile4
-rw-r--r--arch/arm/mach-keystone/keystone.c2
-rw-r--r--arch/arm/mach-keystone/keystone.h5
-rw-r--r--arch/arm/mach-keystone/platsmp.c41
-rw-r--r--arch/arm/mach-keystone/smc.S26
-rw-r--r--arch/arm/mach-mmp/time.c11
-rw-r--r--arch/arm/mach-mvebu/pm-board.c28
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c5
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c5
-rw-r--r--arch/arm/mach-omap2/common-board-devices.h2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c99
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c1
-rw-r--r--arch/arm/mach-shmobile/Kconfig2
-rw-r--r--arch/arm/mach-spear/time.c8
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c1
-rw-r--r--arch/arm/mach-ux500/db8500-regs.h195
-rw-r--r--arch/arm/mach-ux500/platsmp.c2
-rw-r--r--arch/arm/mach-ux500/pm.c4
-rw-r--r--arch/arm/mm/dma-mapping.c17
-rw-r--r--arch/arm/mm/fault.c18
-rw-r--r--arch/arm/mm/fault.h9
-rw-r--r--arch/arm/mm/nommu.c19
-rw-r--r--arch/arm/xen/enlighten.c2
-rw-r--r--arch/arm64/Kconfig50
-rw-r--r--arch/arm64/Kconfig.platforms2
-rw-r--r--arch/arm64/Makefile17
-rw-r--r--arch/arm64/boot/dts/allwinner/axp803.dtsi10
-rw-r--r--arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts14
-rw-r--r--arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi1
-rw-r--r--arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts41
-rw-r--r--arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts25
-rw-r--r--arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi160
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi1
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts7
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts6
-rw-r--r--arch/arm64/boot/dts/amlogic/Makefile1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-a1.dtsi1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-axg.dtsi1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi6
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-g12a.dtsi5
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-g12b-odroid-go-ultra.dts722
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi42
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-g12b.dtsi5
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gx.dtsi1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi14
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxl.dtsi14
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-sm1.dtsi5
-rw-r--r--arch/arm64/boot/dts/apple/Makefile6
-rw-r--r--arch/arm64/boot/dts/apple/multi-die-cpp.h22
-rw-r--r--arch/arm64/boot/dts/apple/t6000-j314s.dts18
-rw-r--r--arch/arm64/boot/dts/apple/t6000-j316s.dts18
-rw-r--r--arch/arm64/boot/dts/apple/t6000.dtsi18
-rw-r--r--arch/arm64/boot/dts/apple/t6001-j314c.dts18
-rw-r--r--arch/arm64/boot/dts/apple/t6001-j316c.dts18
-rw-r--r--arch/arm64/boot/dts/apple/t6001-j375c.dts18
-rw-r--r--arch/arm64/boot/dts/apple/t6001.dtsi63
-rw-r--r--arch/arm64/boot/dts/apple/t6002-j375d.dts50
-rw-r--r--arch/arm64/boot/dts/apple/t6002.dtsi301
-rw-r--r--arch/arm64/boot/dts/apple/t600x-common.dtsi374
-rw-r--r--arch/arm64/boot/dts/apple/t600x-die0.dtsi361
-rw-r--r--arch/arm64/boot/dts/apple/t600x-dieX.dtsi121
-rw-r--r--arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi45
-rw-r--r--arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi114
-rw-r--r--arch/arm64/boot/dts/apple/t600x-j375.dtsi117
-rw-r--r--arch/arm64/boot/dts/apple/t600x-nvme.dtsi42
-rw-r--r--arch/arm64/boot/dts/apple/t600x-pmgr.dtsi2012
-rw-r--r--arch/arm64/boot/dts/apple/t8103-j456.dts2
-rw-r--r--arch/arm64/boot/dts/apple/t8103-j457.dts2
-rw-r--r--arch/arm64/boot/dts/apple/t8103-jxxx.dtsi4
-rw-r--r--arch/arm64/boot/dts/apple/t8103-pmgr.dtsi2
-rw-r--r--arch/arm64/boot/dts/apple/t8103.dtsi322
-rw-r--r--arch/arm64/boot/dts/arm/corstone1000.dtsi1
-rw-r--r--arch/arm64/boot/dts/arm/foundation-v8.dtsi6
-rw-r--r--arch/arm64/boot/dts/arm/fvp-base-revc.dts73
-rw-r--r--arch/arm64/boot/dts/arm/juno-r1.dts2
-rw-r--r--arch/arm64/boot/dts/arm/juno-r2.dts2
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts2
-rw-r--r--arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts1
-rw-r--r--arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi6
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi20
-rw-r--r--arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts2
-rw-r--r--arch/arm64/boot/dts/broadcom/northstar2/ns2-xmc.dts2
-rw-r--r--arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi1
-rw-r--r--arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/Makefile2
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtso (renamed from arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi8
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi39
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi164
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi17
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl-evk.dts107
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi20
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi10
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl-ss-lsio.dtsi46
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl.dtsi7
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts24
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-evk.dts6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15-evk.dts146
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15.dtsi480
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-phg.dts266
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts32
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-var-som.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi30
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso (renamed from arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dts)0
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts54
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts66
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts42
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts54
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi16
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm.dtsi10
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn-evk.dts3
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi47
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts62
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn.dtsi9
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi31
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-evk.dts117
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts159
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts48
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi49
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp.dtsi34
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq-evk.dts9
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts22
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi2
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq.dtsi16
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi38
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qm.dtsi2
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi2
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi25
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qxp.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/imx8ulp.dtsi1
-rw-r--r--[-rwxr-xr-x]arch/arm64/boot/dts/freescale/imx93-pinfunc.h0
-rw-r--r--arch/arm64/boot/dts/freescale/imx93.dtsi111
-rw-r--r--arch/arm64/boot/dts/freescale/mba8mx.dtsi1
-rw-r--r--arch/arm64/boot/dts/freescale/s32g2.dtsi2
-rw-r--r--arch/arm64/boot/dts/freescale/s32v234.dtsi2
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi3660.dtsi2
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220.dtsi2
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05.dtsi4
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip06.dtsi4
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip07.dtsi16
-rw-r--r--arch/arm64/boot/dts/intel/socfpga_agilex.dtsi1
-rw-r--r--arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts1
-rw-r--r--arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts1
-rw-r--r--arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi1
-rw-r--r--arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts4
-rw-r--r--arch/arm64/boot/dts/marvell/armada-37xx.dtsi5
-rw-r--r--arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi1
-rw-r--r--arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi2
-rw-r--r--arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi2
-rw-r--r--arch/arm64/boot/dts/marvell/armada-ap80x.dtsi5
-rw-r--r--arch/arm64/boot/dts/mediatek/Makefile1
-rw-r--r--arch/arm64/boot/dts/mediatek/mt2712-evb.dts12
-rw-r--r--arch/arm64/boot/dts/mediatek/mt2712e.dtsi28
-rw-r--r--arch/arm64/boot/dts/mediatek/mt6779.dtsi10
-rw-r--r--arch/arm64/boot/dts/mediatek/mt6795-sony-xperia-m5.dts88
-rw-r--r--arch/arm64/boot/dts/mediatek/mt6795.dtsi109
-rw-r--r--arch/arm64/boot/dts/mediatek/mt6797.dtsi2
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts1
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts1
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts135
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7986a.dtsi74
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts57
-rw-r--r--arch/arm64/boot/dts/mediatek/mt7986b.dtsi3
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi6
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8186.dtsi3
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8192.dtsi3
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi86
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8195.dtsi233
-rw-r--r--arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi6
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra132-norrin.dts2
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra132.dtsi1
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra186.dtsi12
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi2
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi4
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi2
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra194.dtsi70
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi5
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts4
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra210.dtsi61
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra234-p3701-0000.dtsi8
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts21
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra234-p3737-0000.dtsi14
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra234.dtsi666
-rw-r--r--arch/arm64/boot/dts/qcom/Makefile27
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dts114
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts70
-rw-r--r--arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts11
-rw-r--r--arch/arm64/boot/dts/qcom/ipq6018.dtsi25
-rw-r--r--arch/arm64/boot/dts/qcom/ipq8074-hk01.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi21
-rw-r--r--arch/arm64/boot/dts/qcom/ipq8074.dtsi136
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts80
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts24
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts24
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts22
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts8
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-pins.dtsi276
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi112
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts14
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi28
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts45
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts47
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi17
-rw-r--r--arch/arm64/boot/dts/qcom/msm8953.dtsi314
-rw-r--r--arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-kugo.dts35
-rw-r--r--arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-suzu.dts17
-rw-r--r--arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire.dtsi282
-rw-r--r--arch/arm64/boot/dts/qcom/msm8956.dtsi18
-rw-r--r--arch/arm64/boot/dts/qcom/msm8976.dtsi1198
-rw-r--r--arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-10.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-101.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi45
-rw-r--r--arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/msm8992.dtsi3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi12
-rw-r--r--arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi10
-rw-r--r--arch/arm64/boot/dts/qcom/msm8994.dtsi135
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-oneplus-common.dtsi787
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-oneplus3.dts44
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-oneplus3t.dts45
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi29
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi17
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts11
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi391
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-natrium.dts (renamed from arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts)9
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-scorpio.dts (renamed from arch/arm64/boot/dts/qcom/msm8996-xiaomi-scorpio.dts)13
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996pro.dtsi291
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts28
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-mtp.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts12
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi22
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi67
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998-xiaomi-sagit.dts711
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998.dtsi95
-rw-r--r--arch/arm64/boot/dts/qcom/pm6125.dtsi154
-rw-r--r--arch/arm64/boot/dts/qcom/pm6150.dtsi6
-rw-r--r--arch/arm64/boot/dts/qcom/pm6150l.dtsi44
-rw-r--r--arch/arm64/boot/dts/qcom/pm6350.dtsi41
-rw-r--r--arch/arm64/boot/dts/qcom/pm660.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/pm660l.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pm7325.dtsi6
-rw-r--r--arch/arm64/boot/dts/qcom/pm8005.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pm8150b.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pm8450a.dtsi77
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pm8950.dtsi165
-rw-r--r--arch/arm64/boot/dts/qcom/pm8994.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pm8998.dtsi12
-rw-r--r--arch/arm64/boot/dts/qcom/pmi8950.dtsi97
-rw-r--r--arch/arm64/boot/dts/qcom/pmi8994.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/pmi8998.dtsi10
-rw-r--r--arch/arm64/boot/dts/qcom/pmk8350.dtsi22
-rw-r--r--arch/arm64/boot/dts/qcom/pmp8074.dtsi125
-rw-r--r--arch/arm64/boot/dts/qcom/pms405.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts24
-rw-r--r--arch/arm64/boot/dts/qcom/qcs404-evb.dtsi58
-rw-r--r--arch/arm64/boot/dts/qcom/qcs404.dtsi70
-rw-r--r--arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts62
-rw-r--r--arch/arm64/boot/dts/qcom/qrb5165-rb5.dts22
-rw-r--r--arch/arm64/boot/dts/qcom/sa8155p-adp.dts71
-rw-r--r--arch/arm64/boot/dts/qcom/sa8295p-adp.dts187
-rw-r--r--arch/arm64/boot/dts/qcom/sa8540p-ride.dts270
-rw-r--r--arch/arm64/boot/dts/qcom/sa8540p.dtsi98
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-idp.dts236
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi36
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi51
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi25
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi78
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-parade-ps8640.dtsi34
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi8
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-lte.dts22
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-wifi.dts17
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360.dtsi50
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi14
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi60
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts8
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-ti-sn65dsi86.dtsi16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi25
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts1
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts1
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi78
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi668
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180.dtsi606
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi15
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-crd-r3.dts8
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682-3mic.dtsi187
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682.dtsi122
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi20
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts1
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-lte.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dtsi (renamed from arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-r0.dts)24
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts6
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi19
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1-lte.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dts31
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dtsi37
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-villager.dtsi11
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi11
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie-lte.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dtsi312
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi73
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi10
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-idp.dts6
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-idp.dtsi55
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi22
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280.dtsi435
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp-crd.dts213
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts439
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi84
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp.dtsi808
-rw-r--r--arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts14
-rw-r--r--arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi24
-rw-r--r--arch/arm64/boot/dts/qcom/sdm630.dtsi140
-rw-r--r--arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/sdm660.dtsi3
-rw-r--r--arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts531
-rw-r--r--arch/arm64/boot/dts/qcom/sdm670.dtsi1160
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi49
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts104
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-db845c.dts169
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi39
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts460
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts9
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi (renamed from arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts)46
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts15
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-tianma.dts15
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts36
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845.dtsi177
-rw-r--r--arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts24
-rw-r--r--arch/arm64/boot/dts/qcom/sm4250-oneplus-billie2.dts241
-rw-r--r--arch/arm64/boot/dts/qcom/sm4250.dtsi38
-rw-r--r--arch/arm64/boot/dts/qcom/sm6115.dtsi1425
-rw-r--r--arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts164
-rw-r--r--arch/arm64/boot/dts/qcom/sm6125.dtsi8
-rw-r--r--arch/arm64/boot/dts/qcom/sm6350-sony-xperia-lena-pdx213.dts335
-rw-r--r--arch/arm64/boot/dts/qcom/sm6350.dtsi56
-rw-r--r--arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts406
-rw-r--r--arch/arm64/boot/dts/qcom/sm6375.dtsi1396
-rw-r--r--arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts37
-rw-r--r--arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/sm8150.dtsi407
-rw-r--r--arch/arm64/boot/dts/qcom/sm8250-mtp.dts40
-rw-r--r--arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi35
-rw-r--r--arch/arm64/boot/dts/qcom/sm8250.dtsi1206
-rw-r--r--arch/arm64/boot/dts/qcom/sm8350-hdk.dts8
-rw-r--r--arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami-pdx215.dts206
-rw-r--r--arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi604
-rw-r--r--arch/arm64/boot/dts/qcom/sm8350.dtsi98
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450-hdk.dts205
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450-qrd.dts19
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts831
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx224.dts234
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi631
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450.dtsi600
-rw-r--r--arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi1
-rw-r--r--arch/arm64/boot/dts/renesas/condor-common.dtsi1
-rw-r--r--arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dtso (renamed from arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts)0
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779a0.dtsi24
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi30
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi90
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779f0.dtsi126
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi89
-rw-r--r--arch/arm64/boot/dts/renesas/r8a779g0.dtsi735
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g043.dtsi362
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g043u.dtsi73
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts2
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g044.dtsi17
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g044c2-smarc.dts30
-rw-r--r--arch/arm64/boot/dts/renesas/r9a07g054.dtsi17
-rw-r--r--arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts4
-rw-r--r--arch/arm64/boot/dts/renesas/r9a09g011.dtsi31
-rw-r--r--arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi5
-rw-r--r--arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi5
-rw-r--r--arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi28
-rw-r--r--arch/arm64/boot/dts/renesas/rzg2ul-smarc-pinfunction.dtsi7
-rw-r--r--arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi7
-rw-r--r--arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dtso (renamed from arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts)0
-rw-r--r--arch/arm64/boot/dts/rockchip/Makefile10
-rw-r--r--arch/arm64/boot/dts/rockchip/px30-evb.dts10
-rw-r--r--arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts232
-rw-r--r--arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi382
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3308-evb.dts12
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3308.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts33
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi600
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3326-odroid-go2-v11.dts156
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts620
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts185
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3328.dtsi12
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-r88.dts3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts76
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts6
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399.dtsi20
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts109
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts114
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts87
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353x.dtsi60
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts79
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi47
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts503
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts7
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts42
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts194
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts11
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts232
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi75
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts744
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts147
-rw-r--r--arch/arm64/boot/dts/rockchip/rk356x.dtsi50
-rw-r--r--arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi34
-rw-r--r--arch/arm64/boot/dts/tesla/fsd-pinctrl.h6
-rw-r--r--arch/arm64/boot/dts/ti/Makefile1
-rw-r--r--arch/arm64/boot/dts/ti/k3-am62-main.dtsi122
-rw-r--r--arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi49
-rw-r--r--arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi4
-rw-r--r--arch/arm64/boot/dts/ti/k3-am625-sk.dts90
-rw-r--r--arch/arm64/boot/dts/ti/k3-am625.dtsi51
-rw-r--r--arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi2
-rw-r--r--arch/arm64/boot/dts/ti/k3-am64-main.dtsi44
-rw-r--r--arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi6
-rw-r--r--arch/arm64/boot/dts/ti/k3-am642-evm.dts119
-rw-r--r--arch/arm64/boot/dts/ti/k3-am642-sk.dts142
-rw-r--r--arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi101
-rw-r--r--arch/arm64/boot/dts/ti/k3-am65-main.dtsi207
-rw-r--r--arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi85
-rw-r--r--arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi2
-rw-r--r--arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi1
-rw-r--r--arch/arm64/boot/dts/ti/k3-am654-base-board.dts113
-rw-r--r--arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi4
-rw-r--r--arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts48
-rw-r--r--arch/arm64/boot/dts/ti/k3-j7200-main.dtsi29
-rw-r--r--arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi8
-rw-r--r--arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi42
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts1055
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts143
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-main.dtsi125
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi11
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-sk.dts205
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi33
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts132
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi79
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi9
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi98
-rw-r--r--arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts20
-rw-r--r--arch/arm64/boot/dts/xilinx/zynqmp.dtsi24
-rw-r--r--arch/arm64/configs/defconfig43
-rw-r--r--arch/arm64/include/asm/alternative-macros.h4
-rw-r--r--arch/arm64/include/asm/archrandom.h48
-rw-r--r--arch/arm64/include/asm/assembler.h33
-rw-r--r--arch/arm64/include/asm/cpufeature.h3
-rw-r--r--arch/arm64/include/asm/cputype.h4
-rw-r--r--arch/arm64/include/asm/efi.h8
-rw-r--r--arch/arm64/include/asm/exception.h7
-rw-r--r--arch/arm64/include/asm/fpsimd.h17
-rw-r--r--arch/arm64/include/asm/ftrace.h72
-rw-r--r--arch/arm64/include/asm/hugetlb.h9
-rw-r--r--arch/arm64/include/asm/hwcap.h3
-rw-r--r--arch/arm64/include/asm/insn.h156
-rw-r--r--arch/arm64/include/asm/jump_label.h8
-rw-r--r--arch/arm64/include/asm/kernel-pgtable.h11
-rw-r--r--arch/arm64/include/asm/kvm_host.h12
-rw-r--r--arch/arm64/include/asm/lse.h1
-rw-r--r--arch/arm64/include/asm/mmu_context.h10
-rw-r--r--arch/arm64/include/asm/module.lds.h8
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h1
-rw-r--r--arch/arm64/include/asm/pgtable.h18
-rw-r--r--arch/arm64/include/asm/processor.h24
-rw-r--r--arch/arm64/include/asm/scs.h49
-rw-r--r--arch/arm64/include/asm/spectre.h2
-rw-r--r--arch/arm64/include/asm/stackprotector.h9
-rw-r--r--arch/arm64/include/asm/stacktrace.h2
-rw-r--r--arch/arm64/include/asm/syscall_wrapper.h2
-rw-r--r--arch/arm64/include/asm/sysreg.h150
-rw-r--r--arch/arm64/include/asm/traps.h19
-rw-r--r--arch/arm64/include/asm/uprobes.h2
-rw-r--r--arch/arm64/include/uapi/asm/hwcap.h3
-rw-r--r--arch/arm64/include/uapi/asm/sigcontext.h4
-rw-r--r--arch/arm64/kernel/Makefile2
-rw-r--r--arch/arm64/kernel/acpi.c106
-rw-r--r--arch/arm64/kernel/alternative.c6
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c567
-rw-r--r--arch/arm64/kernel/asm-offsets.c13
-rw-r--r--arch/arm64/kernel/cpu_errata.c7
-rw-r--r--arch/arm64/kernel/cpufeature.c253
-rw-r--r--arch/arm64/kernel/cpuinfo.c3
-rw-r--r--arch/arm64/kernel/efi-rt-wrapper.S33
-rw-r--r--arch/arm64/kernel/efi.c78
-rw-r--r--arch/arm64/kernel/entry-common.c24
-rw-r--r--arch/arm64/kernel/entry-ftrace.S158
-rw-r--r--arch/arm64/kernel/entry.S3
-rw-r--r--arch/arm64/kernel/fpsimd.c169
-rw-r--r--arch/arm64/kernel/ftrace.c87
-rw-r--r--arch/arm64/kernel/head.S3
-rw-r--r--arch/arm64/kernel/irq.c11
-rw-r--r--arch/arm64/kernel/module.c11
-rw-r--r--arch/arm64/kernel/paravirt.c4
-rw-r--r--arch/arm64/kernel/patch-scs.c257
-rw-r--r--arch/arm64/kernel/perf_event.c21
-rw-r--r--arch/arm64/kernel/pi/Makefile1
-rw-r--r--arch/arm64/kernel/probes/decode-insn.c2
-rw-r--r--arch/arm64/kernel/probes/kprobes.c86
-rw-r--r--arch/arm64/kernel/process.c4
-rw-r--r--arch/arm64/kernel/proton-pack.c26
-rw-r--r--arch/arm64/kernel/ptrace.c21
-rw-r--r--arch/arm64/kernel/sdei.c2
-rw-r--r--arch/arm64/kernel/setup.c4
-rw-r--r--arch/arm64/kernel/signal.c7
-rw-r--r--arch/arm64/kernel/stacktrace.c10
-rw-r--r--arch/arm64/kernel/suspend.c2
-rw-r--r--arch/arm64/kernel/syscall.c19
-rw-r--r--arch/arm64/kernel/traps.c93
-rw-r--r--arch/arm64/kernel/vdso.c22
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S13
-rw-r--r--arch/arm64/kvm/fpsimd.c26
-rw-r--r--arch/arm64/kvm/hyp/nvhe/Makefile1
-rw-r--r--arch/arm64/kvm/sys_regs.c4
-rw-r--r--arch/arm64/lib/insn.c165
-rw-r--r--arch/arm64/lib/mte.S2
-rw-r--r--arch/arm64/mm/dma-mapping.c17
-rw-r--r--arch/arm64/mm/fault.c12
-rw-r--r--arch/arm64/mm/hugetlbpage.c21
-rw-r--r--arch/arm64/mm/init.c25
-rw-r--r--arch/arm64/mm/mmu.c23
-rw-r--r--arch/arm64/mm/pageattr.c5
-rw-r--r--arch/arm64/mm/proc.S4
-rw-r--r--arch/arm64/tools/cpucaps2
-rwxr-xr-xarch/arm64/tools/gen-sysreg.awk2
-rw-r--r--arch/arm64/tools/sysreg766
-rw-r--r--arch/csky/include/asm/stackprotector.h10
-rw-r--r--arch/csky/kernel/process.c4
-rw-r--r--arch/hexagon/kernel/ptrace.c7
-rw-r--r--arch/ia64/hp/common/aml_nfw.c4
-rw-r--r--arch/ia64/include/asm/io.h4
-rw-r--r--arch/ia64/include/asm/kprobes.h2
-rw-r--r--arch/ia64/kernel/ptrace.c20
-rw-r--r--arch/ia64/kernel/sys_ia64.c6
-rw-r--r--arch/loongarch/Kconfig1
-rw-r--r--arch/loongarch/Makefile2
-rw-r--r--arch/loongarch/include/asm/acpi.h142
-rw-r--r--arch/loongarch/include/asm/irq.h4
-rw-r--r--arch/loongarch/include/asm/pgtable.h17
-rw-r--r--arch/loongarch/include/asm/smp.h38
-rw-r--r--arch/loongarch/kernel/acpi.c31
-rw-r--r--arch/loongarch/kernel/irq.c2
-rw-r--r--arch/loongarch/kernel/process.c11
-rw-r--r--arch/loongarch/kernel/setup.c1
-rw-r--r--arch/loongarch/kernel/smp.c55
-rw-r--r--arch/loongarch/kernel/unwind_prologue.c3
-rw-r--r--arch/loongarch/kernel/vdso.c2
-rw-r--r--arch/loongarch/mm/tlbex.S30
-rw-r--r--arch/m68k/configs/amiga_defconfig42
-rw-r--r--arch/m68k/configs/apollo_defconfig42
-rw-r--r--arch/m68k/configs/atari_defconfig42
-rw-r--r--arch/m68k/configs/bvme6000_defconfig42
-rw-r--r--arch/m68k/configs/hp300_defconfig42
-rw-r--r--arch/m68k/configs/mac_defconfig42
-rw-r--r--arch/m68k/configs/multi_defconfig42
-rw-r--r--arch/m68k/configs/mvme147_defconfig42
-rw-r--r--arch/m68k/configs/mvme16x_defconfig42
-rw-r--r--arch/m68k/configs/q40_defconfig42
-rw-r--r--arch/m68k/configs/sun3_defconfig42
-rw-r--r--arch/m68k/configs/sun3x_defconfig42
-rw-r--r--arch/m68k/emu/nfcon.c9
-rw-r--r--arch/m68k/include/asm/mac_via.h8
-rw-r--r--arch/m68k/kernel/process.c4
-rw-r--r--arch/m68k/mac/misc.c2
-rw-r--r--arch/microblaze/Kconfig8
-rw-r--r--arch/microblaze/Makefile4
-rw-r--r--arch/microblaze/configs/mmu_defconfig1
-rw-r--r--arch/microblaze/include/asm/pci-bridge.h92
-rw-r--r--arch/microblaze/include/asm/pci.h29
-rw-r--r--arch/microblaze/kernel/process.c2
-rw-r--r--arch/microblaze/pci/Makefile3
-rw-r--r--arch/microblaze/pci/indirect_pci.c158
-rw-r--r--arch/microblaze/pci/iomap.c36
-rw-r--r--arch/microblaze/pci/pci-common.c1067
-rw-r--r--arch/microblaze/pci/xilinx_pci.c170
-rw-r--r--arch/mips/Makefile2
-rw-r--r--arch/mips/alchemy/common/gpiolib.c2
-rw-r--r--arch/mips/bcm63xx/clk.c2
-rw-r--r--arch/mips/boot/compressed/decompress.c1
-rw-r--r--arch/mips/boot/dts/brcm/bcm63268.dtsi5
-rw-r--r--arch/mips/boot/dts/brcm/bcm7435.dtsi1
-rw-r--r--arch/mips/boot/dts/ingenic/ci20.dts2
-rw-r--r--arch/mips/boot/dts/mscc/jaguar2_pcb110.dts4
-rw-r--r--arch/mips/boot/dts/qca/ar9331.dtsi1
-rw-r--r--arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts2
-rw-r--r--arch/mips/boot/dts/ralink/mt7621.dtsi11
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-bootmem.c3
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-board.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper.c2
-rw-r--r--arch/mips/include/asm/asm-prototypes.h3
-rw-r--r--arch/mips/include/asm/fw/fw.h2
-rw-r--r--arch/mips/include/asm/mach-ralink/mt7621.h4
-rw-r--r--arch/mips/include/asm/pgtable.h1
-rw-r--r--arch/mips/include/asm/stackprotector.h9
-rw-r--r--arch/mips/kernel/jump_label.c2
-rw-r--r--arch/mips/kernel/process.c2
-rw-r--r--arch/mips/kernel/ptrace.c9
-rw-r--r--arch/mips/kernel/relocate_kernel.S15
-rw-r--r--arch/mips/kernel/vdso.c2
-rw-r--r--arch/mips/kernel/vpe-cmp.c4
-rw-r--r--arch/mips/kernel/vpe-mt.c4
-rw-r--r--arch/mips/loongson64/reset.c10
-rw-r--r--arch/mips/pci/pci-rt3883.c4
-rw-r--r--arch/mips/pic32/pic32mzda/early_console.c13
-rw-r--r--arch/mips/pic32/pic32mzda/init.c2
-rw-r--r--arch/mips/ralink/mt7621.c97
-rw-r--r--arch/mips/vdso/Makefile2
-rw-r--r--arch/nios2/boot/Makefile2
-rw-r--r--arch/nios2/kernel/ptrace.c6
-rw-r--r--arch/openrisc/configs/or1ksim_defconfig3
-rw-r--r--arch/openrisc/configs/simple_smp_defconfig3
-rw-r--r--arch/openrisc/kernel/ptrace.c8
-rw-r--r--arch/parisc/kernel/ptrace.c15
-rw-r--r--arch/parisc/kernel/vdso.c2
-rw-r--r--arch/powerpc/configs/microwatt_defconfig1
-rw-r--r--arch/powerpc/crypto/crc-vpmsum_test.c4
-rw-r--r--arch/powerpc/include/asm/ftrace.h24
-rw-r--r--arch/powerpc/include/asm/interrupt.h1
-rw-r--r--arch/powerpc/include/asm/stackprotector.h10
-rw-r--r--arch/powerpc/kernel/process.c2
-rw-r--r--arch/powerpc/kernel/ptrace/ptrace-tm.c10
-rw-r--r--arch/powerpc/kernel/ptrace/ptrace-view.c15
-rw-r--r--arch/powerpc/kernel/vdso.c22
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S2
-rw-r--r--arch/powerpc/kexec/file_load_64.c2
-rw-r--r--arch/powerpc/kexec/ranges.c8
-rw-r--r--arch/powerpc/net/bpf_jit_comp32.c52
-rw-r--r--arch/powerpc/perf/core-book3s.c8
-rw-r--r--arch/powerpc/platforms/pseries/msi.c7
-rw-r--r--arch/riscv/Kconfig6
-rw-r--r--arch/riscv/Kconfig.socs5
-rw-r--r--arch/riscv/boot/dts/Makefile1
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi33
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts36
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi4
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi4
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi29
-rw-r--r--arch/riscv/boot/dts/microchip/mpfs.dtsi32
-rw-r--r--arch/riscv/boot/dts/renesas/Makefile2
-rw-r--r--arch/riscv/boot/dts/renesas/r9a07g043f.dtsi59
-rw-r--r--arch/riscv/boot/dts/renesas/r9a07g043f01-smarc.dts27
-rw-r--r--arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi47
-rw-r--r--arch/riscv/boot/dts/renesas/rzfive-smarc.dtsi64
-rw-r--r--arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts38
-rw-r--r--arch/riscv/boot/dts/starfive/Makefile2
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts153
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100-common.dtsi161
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts20
-rw-r--r--arch/riscv/configs/defconfig3
-rw-r--r--arch/riscv/configs/nommu_k210_defconfig3
-rw-r--r--arch/riscv/configs/nommu_k210_sdcard_defconfig3
-rw-r--r--arch/riscv/configs/nommu_virt_defconfig3
-rw-r--r--arch/riscv/include/asm/asm.h1
-rw-r--r--arch/riscv/include/asm/efi.h6
-rw-r--r--arch/riscv/include/asm/pgalloc.h11
-rw-r--r--arch/riscv/include/asm/pgtable.h1
-rw-r--r--arch/riscv/include/asm/smp.h3
-rw-r--r--arch/riscv/include/asm/stackprotector.h10
-rw-r--r--arch/riscv/kernel/entry.S13
-rw-r--r--arch/riscv/kernel/machine_kexec.c46
-rw-r--r--arch/riscv/kernel/process.c2
-rw-r--r--arch/riscv/kernel/setup.c10
-rw-r--r--arch/riscv/kernel/smp.c97
-rw-r--r--arch/riscv/kernel/traps.c18
-rw-r--r--arch/riscv/kernel/vdso.c22
-rw-r--r--arch/riscv/kernel/vdso/Makefile6
-rw-r--r--arch/riscv/kernel/vdso/vdso.lds.S2
-rw-r--r--arch/riscv/mm/init.c1
-rw-r--r--arch/s390/Kconfig14
-rw-r--r--arch/s390/Makefile2
-rw-r--r--arch/s390/appldata/appldata_base.c113
-rw-r--r--arch/s390/boot/Makefile3
-rw-r--r--arch/s390/boot/ipl_parm.c9
-rw-r--r--arch/s390/boot/startup.c3
-rw-r--r--arch/s390/configs/btf.config1
-rw-r--r--arch/s390/configs/debug_defconfig67
-rw-r--r--arch/s390/configs/defconfig69
-rw-r--r--arch/s390/configs/kasan.config3
-rw-r--r--arch/s390/configs/zfcpdump_defconfig2
-rw-r--r--arch/s390/hypfs/hypfs_diag.c8
-rw-r--r--arch/s390/include/asm/bugs.h21
-rw-r--r--arch/s390/include/asm/checksum.h7
-rw-r--r--arch/s390/include/asm/ftrace.h29
-rw-r--r--arch/s390/include/asm/ipl.h11
-rw-r--r--arch/s390/include/asm/pai.h6
-rw-r--r--arch/s390/include/asm/pgtable.h1
-rw-r--r--arch/s390/include/asm/processor.h11
-rw-r--r--arch/s390/include/asm/sclp.h2
-rw-r--r--arch/s390/include/asm/serial.h7
-rw-r--r--arch/s390/include/asm/shmparam.h12
-rw-r--r--arch/s390/include/asm/vga.h7
-rw-r--r--arch/s390/include/asm/vx-insn-asm.h681
-rw-r--r--arch/s390/include/asm/vx-insn.h671
-rw-r--r--arch/s390/include/uapi/asm/ipl.h29
-rw-r--r--arch/s390/kernel/crash_dump.c4
-rw-r--r--arch/s390/kernel/debug.c7
-rw-r--r--arch/s390/kernel/entry.S34
-rw-r--r--arch/s390/kernel/fpu.c3
-rw-r--r--arch/s390/kernel/ipl.c403
-rw-r--r--arch/s390/kernel/kprobes.c3
-rw-r--r--arch/s390/kernel/kprobes.h9
-rw-r--r--arch/s390/kernel/nmi.c181
-rw-r--r--arch/s390/kernel/perf_pai_crypto.c50
-rw-r--r--arch/s390/kernel/perf_pai_ext.c14
-rw-r--r--arch/s390/kernel/process.c2
-rw-r--r--arch/s390/kernel/setup.c3
-rw-r--r--arch/s390/kernel/vdso.c22
-rw-r--r--arch/s390/kvm/kvm-s390.c26
-rw-r--r--arch/s390/kvm/kvm-s390.h1
-rw-r--r--arch/s390/kvm/pci.c2
-rw-r--r--arch/s390/kvm/vsie.c4
-rw-r--r--arch/s390/mm/init.c39
-rw-r--r--arch/s390/mm/maccess.c2
-rw-r--r--arch/s390/mm/page-states.c11
-rw-r--r--arch/s390/pci/pci_irq.c2
-rw-r--r--arch/sh/configs/rsk7201_defconfig3
-rw-r--r--arch/sh/configs/rsk7203_defconfig3
-rw-r--r--arch/sh/configs/se7206_defconfig3
-rw-r--r--arch/sh/configs/shmin_defconfig3
-rw-r--r--arch/sh/configs/shx3_defconfig3
-rw-r--r--arch/sh/include/asm/stackprotector.h10
-rw-r--r--arch/sh/kernel/ptrace_32.c8
-rw-r--r--arch/sparc/include/asm/pgtable_64.h1
-rw-r--r--arch/sparc/kernel/ptrace_32.c9
-rw-r--r--arch/sparc/kernel/ptrace_64.c23
-rw-r--r--arch/sparc/vdso/vma.c2
-rw-r--r--arch/um/drivers/Kconfig1
-rw-r--r--arch/um/include/asm/pci.h2
-rw-r--r--arch/um/kernel/kmsg_dump.c24
-rw-r--r--arch/um/kernel/process.c5
-rw-r--r--arch/x86/Kconfig7
-rw-r--r--arch/x86/boot/Makefile2
-rw-r--r--arch/x86/boot/compressed/kaslr.c2
-rw-r--r--arch/x86/boot/string.c2
-rw-r--r--arch/x86/coco/tdx/tdx.c40
-rw-r--r--arch/x86/entry/entry_64_compat.S4
-rw-r--r--arch/x86/entry/vdso/vdso.lds.S2
-rw-r--r--arch/x86/entry/vdso/vma.c32
-rw-r--r--arch/x86/events/amd/brs.c2
-rw-r--r--arch/x86/events/amd/core.c5
-rw-r--r--arch/x86/events/amd/ibs.c4
-rw-r--r--arch/x86/events/amd/lbr.c6
-rw-r--r--arch/x86/events/amd/uncore.c1
-rw-r--r--arch/x86/events/core.c48
-rw-r--r--arch/x86/events/intel/core.c23
-rw-r--r--arch/x86/events/intel/ds.c4
-rw-r--r--arch/x86/events/intel/lbr.c30
-rw-r--r--arch/x86/events/intel/p4.c2
-rw-r--r--arch/x86/events/intel/pt.c9
-rw-r--r--arch/x86/events/intel/uncore.h24
-rw-r--r--arch/x86/events/intel/uncore_snb.c3
-rw-r--r--arch/x86/events/intel/uncore_snbep.c495
-rw-r--r--arch/x86/events/perf_event.h31
-rw-r--r--arch/x86/hyperv/hv_init.c77
-rw-r--r--arch/x86/ia32/Makefile2
-rw-r--r--arch/x86/include/asm/apic.h3
-rw-r--r--arch/x86/include/asm/cpufeatures.h4
-rw-r--r--arch/x86/include/asm/elf.h5
-rw-r--r--arch/x86/include/asm/fpu/signal.h7
-rw-r--r--arch/x86/include/asm/ftrace.h49
-rw-r--r--arch/x86/include/asm/hyperv-tlfs.h11
-rw-r--r--arch/x86/include/asm/hyperv_timer.h9
-rw-r--r--arch/x86/include/asm/irq_remapping.h4
-rw-r--r--arch/x86/include/asm/irqdomain.h4
-rw-r--r--arch/x86/include/asm/kvm_host.h7
-rw-r--r--arch/x86/include/asm/mshyperv.h2
-rw-r--r--arch/x86/include/asm/msi.h6
-rw-r--r--arch/x86/include/asm/msr-index.h29
-rw-r--r--arch/x86/include/asm/nospec-branch.h2
-rw-r--r--arch/x86/include/asm/pci.h5
-rw-r--r--arch/x86/include/asm/pgtable.h9
-rw-r--r--arch/x86/include/asm/qspinlock_paravirt.h2
-rw-r--r--arch/x86/include/asm/resctrl.h8
-rw-r--r--arch/x86/include/asm/segment.h2
-rw-r--r--arch/x86/include/asm/sgx.h33
-rw-r--r--arch/x86/include/asm/sighandling.h9
-rw-r--r--arch/x86/include/asm/signal.h5
-rw-r--r--arch/x86/include/asm/spec-ctrl.h10
-rw-r--r--arch/x86/include/asm/stackprotector.h14
-rw-r--r--arch/x86/include/asm/tdx.h2
-rw-r--r--arch/x86/kernel/Makefile4
-rw-r--r--arch/x86/kernel/alternative.c4
-rw-r--r--arch/x86/kernel/apic/apic.c13
-rw-r--r--arch/x86/kernel/apic/msi.c211
-rw-r--r--arch/x86/kernel/apic/vector.c4
-rw-r--r--arch/x86/kernel/asm-offsets.c6
-rw-r--r--arch/x86/kernel/cpu/amd.c6
-rw-r--r--arch/x86/kernel/cpu/bugs.c36
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/cpuid-deps.c1
-rw-r--r--arch/x86/kernel/cpu/hygon.c4
-rw-r--r--arch/x86/kernel/cpu/intel.c63
-rw-r--r--arch/x86/kernel/cpu/mce/amd.c33
-rw-r--r--arch/x86/kernel/cpu/mce/severity.c8
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c2
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c6
-rw-r--r--arch/x86/kernel/cpu/resctrl/core.c4
-rw-r--r--arch/x86/kernel/cpu/resctrl/ctrlmondata.c3
-rw-r--r--arch/x86/kernel/cpu/resctrl/internal.h10
-rw-r--r--arch/x86/kernel/cpu/resctrl/pseudo_lock.c4
-rw-r--r--arch/x86/kernel/cpu/scattered.c1
-rw-r--r--arch/x86/kernel/cpu/sgx/encl.c35
-rw-r--r--arch/x86/kernel/cpu/sgx/ioctl.c9
-rw-r--r--arch/x86/kernel/cpu/sgx/main.c8
-rw-r--r--arch/x86/kernel/cpu/tsx.c38
-rw-r--r--arch/x86/kernel/crash_dump_64.c2
-rw-r--r--arch/x86/kernel/devicetree.c18
-rw-r--r--arch/x86/kernel/espfix_64.c12
-rw-r--r--arch/x86/kernel/fpu/core.c21
-rw-r--r--arch/x86/kernel/fpu/init.c7
-rw-r--r--arch/x86/kernel/fpu/regset.c2
-rw-r--r--arch/x86/kernel/fpu/signal.c2
-rw-r--r--arch/x86/kernel/fpu/xstate.c64
-rw-r--r--arch/x86/kernel/fpu/xstate.h4
-rw-r--r--arch/x86/kernel/head_32.S22
-rw-r--r--arch/x86/kernel/i8259.c2
-rw-r--r--arch/x86/kernel/module.c13
-rw-r--r--arch/x86/kernel/process.c4
-rw-r--r--arch/x86/kernel/ptrace.c174
-rw-r--r--arch/x86/kernel/setup_percpu.c2
-rw-r--r--arch/x86/kernel/signal.c654
-rw-r--r--arch/x86/kernel/signal_32.c (renamed from arch/x86/ia32/ia32_signal.c)117
-rw-r--r--arch/x86/kernel/signal_64.c383
-rw-r--r--arch/x86/kernel/smpboot.c1
-rw-r--r--arch/x86/kernel/traps.c11
-rw-r--r--arch/x86/kernel/tsc.c2
-rw-r--r--arch/x86/kernel/uprobes.c4
-rw-r--r--arch/x86/kvm/.gitignore2
-rw-r--r--arch/x86/kvm/Makefile12
-rw-r--r--arch/x86/kvm/cpuid.c6
-rw-r--r--arch/x86/kvm/kvm-asm-offsets.c29
-rw-r--r--arch/x86/kvm/mmu/mmu.c17
-rw-r--r--arch/x86/kvm/pmu.c2
-rw-r--r--arch/x86/kvm/reverse_cpuid.h3
-rw-r--r--arch/x86/kvm/svm/nested.c12
-rw-r--r--arch/x86/kvm/svm/pmu.c7
-rw-r--r--arch/x86/kvm/svm/sev.c6
-rw-r--r--arch/x86/kvm/svm/svm.c131
-rw-r--r--arch/x86/kvm/svm/svm.h11
-rw-r--r--arch/x86/kvm/svm/svm_ops.h5
-rw-r--r--arch/x86/kvm/svm/vmenter.S260
-rw-r--r--arch/x86/kvm/vmx/nested.c4
-rw-r--r--arch/x86/kvm/vmx/pmu_intel.c4
-rw-r--r--arch/x86/kvm/vmx/vmenter.S2
-rw-r--r--arch/x86/kvm/x86.c54
-rw-r--r--arch/x86/kvm/xen.c32
-rw-r--r--arch/x86/lib/usercopy.c3
-rw-r--r--arch/x86/mm/hugetlbpage.c4
-rw-r--r--arch/x86/mm/ioremap.c8
-rw-r--r--arch/x86/mm/pat/cpa-test.c4
-rw-r--r--arch/x86/mm/pat/set_memory.c18
-rw-r--r--arch/x86/net/bpf_jit_comp.c13
-rw-r--r--arch/x86/platform/olpc/olpc-xo15-sci.c3
-rw-r--r--arch/x86/power/cpu.c22
-rw-r--r--arch/x86/um/asm/elf.h4
-rw-r--r--arch/x86/xen/enlighten_pv.c5
-rw-r--r--arch/x86/xen/setup.c3
-rw-r--r--arch/x86/xen/smp.c24
-rw-r--r--arch/x86/xen/smp_pv.c12
-rw-r--r--arch/x86/xen/spinlock.c6
-rw-r--r--arch/x86/xen/xen-asm.S8
-rw-r--r--arch/xtensa/include/asm/stackprotector.h9
-rw-r--r--block/bdev.c4
-rw-r--r--block/bfq-cgroup.c16
-rw-r--r--block/bfq-iosched.c102
-rw-r--r--block/bfq-iosched.h32
-rw-r--r--block/bfq-wf2q.c157
-rw-r--r--block/bio.c146
-rw-r--r--block/blk-cgroup.c96
-rw-r--r--block/blk-cgroup.h10
-rw-r--r--block/blk-core.c84
-rw-r--r--block/blk-crypto-internal.h22
-rw-r--r--block/blk-crypto-profile.c1
-rw-r--r--block/blk-crypto-sysfs.c11
-rw-r--r--block/blk-crypto.c43
-rw-r--r--block/blk-ia-ranges.c3
-rw-r--r--block/blk-iocost.c57
-rw-r--r--block/blk-iolatency.c37
-rw-r--r--block/blk-map.c14
-rw-r--r--block/blk-merge.c44
-rw-r--r--block/blk-mq-sched.c8
-rw-r--r--block/blk-mq-sysfs.c11
-rw-r--r--block/blk-mq.c236
-rw-r--r--block/blk-mq.h14
-rw-r--r--block/blk-settings.c15
-rw-r--r--block/blk-sysfs.c137
-rw-r--r--block/blk-throttle.c102
-rw-r--r--block/blk-wbt.c26
-rw-r--r--block/blk-wbt.h17
-rw-r--r--block/blk.h28
-rw-r--r--block/bsg-lib.c2
-rw-r--r--block/bsg.c11
-rw-r--r--block/elevator.c254
-rw-r--r--block/elevator.h20
-rw-r--r--block/fops.c7
-rw-r--r--block/genhd.c35
-rw-r--r--block/holder.c103
-rw-r--r--block/ioctl.c12
-rw-r--r--block/mq-deadline.c83
-rw-r--r--block/sed-opal.c71
-rw-r--r--crypto/rsa-pkcs1pad.c2
-rw-r--r--crypto/testmgr.c90
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/accel/Kconfig24
-rw-r--r--drivers/accel/drm_accel.c323
-rw-r--r--drivers/accessibility/speakup/main.c2
-rw-r--r--drivers/accessibility/speakup/utils.h2
-rw-r--r--drivers/acpi/Kconfig12
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/ac.c8
-rw-r--r--drivers/acpi/acpi_ffh.c55
-rw-r--r--drivers/acpi/acpi_pad.c7
-rw-r--r--drivers/acpi/acpi_pcc.c47
-rw-r--r--drivers/acpi/acpi_video.c8
-rw-r--r--drivers/acpi/acpica/Makefile1
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/actables.h5
-rw-r--r--drivers/acpi/acpica/acutils.h13
-rw-r--r--drivers/acpi/acpica/dsmethod.c10
-rw-r--r--drivers/acpi/acpica/evevent.c11
-rw-r--r--drivers/acpi/acpica/evregion.c9
-rw-r--r--drivers/acpi/acpica/exconfig.c4
-rw-r--r--drivers/acpi/acpica/exfield.c8
-rw-r--r--drivers/acpi/acpica/exserial.c6
-rw-r--r--drivers/acpi/acpica/hwsleep.c14
-rw-r--r--drivers/acpi/acpica/tbdata.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbprint.c77
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c32
-rw-r--r--drivers/acpi/acpica/utcksum.c170
-rw-r--r--drivers/acpi/acpica/utcopy.c7
-rw-r--r--drivers/acpi/acpica/utglobal.c4
-rw-r--r--drivers/acpi/acpica/utstring.c10
-rw-r--r--drivers/acpi/apei/apei-base.c2
-rw-r--r--drivers/acpi/apei/einj.c56
-rw-r--r--drivers/acpi/apei/ghes.c128
-rw-r--r--drivers/acpi/arm64/Kconfig3
-rw-r--r--drivers/acpi/arm64/Makefile1
-rw-r--r--drivers/acpi/arm64/apmt.c178
-rw-r--r--drivers/acpi/arm64/iort.c16
-rw-r--r--drivers/acpi/battery.c16
-rw-r--r--drivers/acpi/bus.c5
-rw-r--r--drivers/acpi/button.c5
-rw-r--r--drivers/acpi/cppc_acpi.c4
-rw-r--r--drivers/acpi/ec.c15
-rw-r--r--drivers/acpi/fan_attr.c16
-rw-r--r--drivers/acpi/fan_core.c1
-rw-r--r--drivers/acpi/hed.c3
-rw-r--r--drivers/acpi/irq.c5
-rw-r--r--drivers/acpi/nfit/core.c3
-rw-r--r--drivers/acpi/nfit/intel.c30
-rw-r--r--drivers/acpi/numa/hmat.c27
-rw-r--r--drivers/acpi/pci_irq.c6
-rw-r--r--drivers/acpi/pci_root.c1
-rw-r--r--drivers/acpi/pfr_telemetry.c6
-rw-r--r--drivers/acpi/pfr_update.c8
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_idle.c9
-rw-r--r--drivers/acpi/processor_perflib.c100
-rw-r--r--drivers/acpi/processor_throttling.c4
-rw-r--r--drivers/acpi/sbs.c9
-rw-r--r--drivers/acpi/sbshc.c7
-rw-r--r--drivers/acpi/scan.c2
-rw-r--r--drivers/acpi/sysfs.c5
-rw-r--r--drivers/acpi/tables.c17
-rw-r--r--drivers/acpi/thermal.c9
-rw-r--r--drivers/acpi/tiny-power-button.c10
-rw-r--r--drivers/acpi/video_detect.c113
-rw-r--r--drivers/acpi/x86/utils.c24
-rw-r--r--drivers/android/binder_alloc.c7
-rw-r--r--drivers/ata/Kconfig13
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c1
-rw-r--r--drivers/ata/ahci.h245
-rw-r--r--drivers/ata/libahci.c20
-rw-r--r--drivers/ata/libahci_platform.c2
-rw-r--r--drivers/ata/libata-acpi.c4
-rw-r--r--drivers/ata/libata-core.c7
-rw-r--r--drivers/ata/libata-eh.c40
-rw-r--r--drivers/ata/libata-sata.c50
-rw-r--r--drivers/ata/libata-scsi.c31
-rw-r--r--drivers/ata/libata-sff.c56
-rw-r--r--drivers/ata/libata-transport.c19
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/pata_bk3710.c380
-rw-r--r--drivers/ata/pata_ep93xx.c3
-rw-r--r--drivers/ata/pata_ftide010.c2
-rw-r--r--drivers/ata/pata_mpc52xx.c2
-rw-r--r--drivers/ata/sata_dwc_460ex.c12
-rw-r--r--drivers/ata/sata_gemini.c2
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_sx4.c2
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/platform-msi.c6
-rw-r--r--drivers/base/power/domain.c176
-rw-r--r--drivers/base/power/domain_governor.c3
-rw-r--r--drivers/base/power/runtime.c145
-rw-r--r--drivers/base/regmap/Kconfig6
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regmap-fsi.c231
-rw-r--r--drivers/base/regmap/regmap-irq.c59
-rw-r--r--drivers/base/regmap/regmap.c13
-rw-r--r--drivers/block/Kconfig43
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/drbd/Kconfig2
-rw-r--r--drivers/block/drbd/Makefile2
-rw-r--r--drivers/block/drbd/drbd_actlog.c8
-rw-r--r--drivers/block/drbd/drbd_bitmap.c62
-rw-r--r--drivers/block/drbd/drbd_debugfs.c2
-rw-r--r--drivers/block/drbd/drbd_debugfs.h2
-rw-r--r--drivers/block/drbd/drbd_int.h78
-rw-r--r--drivers/block/drbd/drbd_interval.c2
-rw-r--r--drivers/block/drbd/drbd_interval.h2
-rw-r--r--drivers/block/drbd/drbd_main.c27
-rw-r--r--drivers/block/drbd/drbd_nl.c27
-rw-r--r--drivers/block/drbd/drbd_nla.c2
-rw-r--r--drivers/block/drbd/drbd_nla.h2
-rw-r--r--drivers/block/drbd/drbd_polymorph_printk.h141
-rw-r--r--drivers/block/drbd/drbd_proc.c2
-rw-r--r--drivers/block/drbd/drbd_protocol.h2
-rw-r--r--drivers/block/drbd/drbd_receiver.c105
-rw-r--r--drivers/block/drbd/drbd_req.c8
-rw-r--r--drivers/block/drbd/drbd_req.h2
-rw-r--r--drivers/block/drbd/drbd_state.c2
-rw-r--r--drivers/block/drbd/drbd_state.h2
-rw-r--r--drivers/block/drbd/drbd_state_change.h2
-rw-r--r--drivers/block/drbd/drbd_strings.c2
-rw-r--r--drivers/block/drbd/drbd_strings.h2
-rw-r--r--drivers/block/drbd/drbd_vli.h2
-rw-r--r--drivers/block/drbd/drbd_worker.c18
-rw-r--r--drivers/block/floppy.c4
-rw-r--r--drivers/block/loop.c12
-rw-r--r--drivers/block/nbd.c10
-rw-r--r--drivers/block/null_blk/main.c22
-rw-r--r--drivers/block/null_blk/null_blk.h8
-rw-r--r--drivers/block/null_blk/zoned.c95
-rw-r--r--drivers/block/pktcdvd.c2944
-rw-r--r--drivers/block/ublk_drv.c82
-rw-r--r--drivers/block/virtio_blk.c8
-rw-r--r--drivers/block/xen-blkfront.c1
-rw-r--r--drivers/bluetooth/btusb.c6
-rw-r--r--drivers/bluetooth/hci_qca.c10
-rw-r--r--drivers/bus/fsl-mc/Kconfig2
-rw-r--r--drivers/bus/fsl-mc/dprc-driver.c1
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c1
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-msi.c25
-rw-r--r--drivers/bus/intel-ixp4xx-eb.c9
-rw-r--r--drivers/bus/mhi/host/internal.h2
-rw-r--r--drivers/bus/sunxi-rsb.c38
-rw-r--r--drivers/bus/ti-sysc.c6
-rw-r--r--drivers/char/Kconfig36
-rw-r--r--drivers/char/hw_random/core.c8
-rw-r--r--drivers/char/random.c265
-rw-r--r--drivers/char/sonypi.c3
-rw-r--r--drivers/char/tpm/eventlog/acpi.c12
-rw-r--r--drivers/char/tpm/st33zp24/i2c.c142
-rw-r--r--drivers/char/tpm/st33zp24/spi.c145
-rw-r--r--drivers/char/tpm/st33zp24/st33zp24.c39
-rw-r--r--drivers/char/tpm/st33zp24/st33zp24.h7
-rw-r--r--drivers/char/tpm/tpm-chip.c7
-rw-r--r--drivers/char/tpm/tpm-dev-common.c4
-rw-r--r--drivers/char/tpm/tpm-interface.c5
-rw-r--r--drivers/char/tpm/tpm_crb.c35
-rw-r--r--drivers/char/tpm/tpm_ftpm_tee.c8
-rw-r--r--drivers/char/tpm/tpm_tis.c9
-rw-r--r--drivers/char/tpm/tpm_tis_core.c20
-rw-r--r--drivers/char/tpm/tpm_tis_core.h1
-rw-r--r--drivers/char/tpm/tpm_tis_i2c.c3
-rw-r--r--drivers/clk/at91/at91rm9200.c2
-rw-r--r--drivers/clk/bcm/clk-raspberrypi.c19
-rw-r--r--drivers/clk/qcom/gcc-sc8280xp.c6
-rw-r--r--drivers/clk/qcom/gdsc.c61
-rw-r--r--drivers/clk/qcom/gdsc.h2
-rw-r--r--drivers/clk/samsung/clk-exynos-clkout.c6
-rw-r--r--drivers/clk/samsung/clk-exynos7885.c4
-rw-r--r--drivers/clk/tegra/clk-bpmp.c37
-rw-r--r--drivers/clocksource/arm_arch_timer.c22
-rw-r--r--drivers/clocksource/hyperv_timer.c86
-rw-r--r--drivers/clocksource/ingenic-ost.c10
-rw-r--r--drivers/clocksource/sh_cmt.c88
-rw-r--r--drivers/clocksource/timer-npcm7xx.c10
-rw-r--r--drivers/clocksource/timer-riscv.c2
-rw-r--r--drivers/clocksource/timer-sp804.c6
-rw-r--r--drivers/clocksource/timer-ti-dm-systimer.c4
-rw-r--r--drivers/clocksource/timer-ti-dm.c21
-rw-r--r--drivers/cpufreq/Kconfig.arm13
-rw-r--r--drivers/cpufreq/Kconfig.x862
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c43
-rw-r--r--drivers/cpufreq/amd-pstate-ut.c2
-rw-r--r--drivers/cpufreq/amd-pstate.c49
-rw-r--r--drivers/cpufreq/amd_freq_sensitivity.c2
-rw-r--r--drivers/cpufreq/apple-soc-cpufreq.c352
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c3
-rw-r--r--drivers/cpufreq/cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq_stats.c16
-rw-r--r--drivers/cpufreq/intel_pstate.c10
-rw-r--r--drivers/cpufreq/longhaul.c4
-rw-r--r--drivers/cpufreq/mediatek-cpufreq-hw.c14
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c206
-rw-r--r--drivers/cpufreq/spear-cpufreq.c2
-rw-r--r--drivers/cpufreq/tegra186-cpufreq.c11
-rw-r--r--drivers/cpufreq/ti-cpufreq.c36
-rw-r--r--drivers/cpuidle/cpuidle-psci-domain.c3
-rw-r--r--drivers/cpuidle/dt_idle_states.c11
-rw-r--r--drivers/cxl/Kconfig18
-rw-r--r--drivers/cxl/Makefile2
-rw-r--r--drivers/cxl/acpi.c275
-rw-r--r--drivers/cxl/core/core.h8
-rw-r--r--drivers/cxl/core/hdm.c45
-rw-r--r--drivers/cxl/core/mbox.c102
-rw-r--r--drivers/cxl/core/memdev.c1
-rw-r--r--drivers/cxl/core/pci.c5
-rw-r--r--drivers/cxl/core/pmem.c109
-rw-r--r--drivers/cxl/core/port.c216
-rw-r--r--drivers/cxl/core/region.c112
-rw-r--r--drivers/cxl/core/regs.c242
-rw-r--r--drivers/cxl/cxl.h140
-rw-r--r--drivers/cxl/cxlmem.h64
-rw-r--r--drivers/cxl/cxlpci.h9
-rw-r--r--drivers/cxl/mem.c74
-rw-r--r--drivers/cxl/pci.c228
-rw-r--r--drivers/cxl/pmem.c407
-rw-r--r--drivers/cxl/security.c202
-rw-r--r--drivers/dax/hmem/device.c24
-rw-r--r--drivers/devfreq/devfreq-event.c2
-rw-r--r--drivers/devfreq/devfreq.c8
-rw-r--r--drivers/devfreq/event/exynos-nocp.c3
-rw-r--r--drivers/devfreq/governor_userspace.c12
-rw-r--r--drivers/dma-buf/dma-buf.c248
-rw-r--r--drivers/dma-buf/dma-heap.c28
-rw-r--r--drivers/dma-buf/heaps/cma_heap.c3
-rw-r--r--drivers/dma-buf/heaps/system_heap.c3
-rw-r--r--drivers/dma-buf/st-dma-fence-chain.c6
-rw-r--r--drivers/dma-buf/udmabuf.c3
-rw-r--r--drivers/dma/Kconfig2
-rw-r--r--drivers/dma/apple-admac.c2
-rw-r--r--drivers/dma/at_hdmac.c153
-rw-r--r--drivers/dma/at_hdmac_regs.h10
-rw-r--r--drivers/dma/idxd/cdev.c18
-rw-r--r--drivers/dma/idxd/device.c26
-rw-r--r--drivers/dma/idxd/idxd.h32
-rw-r--r--drivers/dma/idxd/init.c4
-rw-r--r--drivers/dma/idxd/sysfs.c2
-rw-r--r--drivers/dma/mv_xor_v2.c1
-rw-r--r--drivers/dma/pxa_dma.c4
-rw-r--r--drivers/dma/qcom/hidma.c8
-rw-r--r--drivers/dma/stm32-dma.c14
-rw-r--r--drivers/dma/stm32-mdma.c1
-rw-r--r--drivers/dma/ti/k3-udma-glue.c3
-rw-r--r--drivers/edac/Kconfig5
-rw-r--r--drivers/edac/amd64_edac.c3
-rw-r--r--drivers/edac/armada_xp_edac.c3
-rw-r--r--drivers/edac/edac_mc_sysfs.c24
-rw-r--r--drivers/edac/edac_module.h1
-rw-r--r--drivers/edac/ghes_edac.c90
-rw-r--r--drivers/edac/i10nm_base.c6
-rw-r--r--drivers/edac/i5400_edac.c3
-rw-r--r--drivers/edac/igen6_edac.c5
-rw-r--r--drivers/edac/layerscape_edac.c3
-rw-r--r--drivers/edac/pnd2_edac.c3
-rw-r--r--drivers/edac/sb_edac.c3
-rw-r--r--drivers/edac/skx_base.c3
-rw-r--r--drivers/edac/thunderx_edac.c3
-rw-r--r--drivers/edac/xgene_edac.c3
-rw-r--r--drivers/extcon/extcon-usbc-tusb320.c8
-rw-r--r--drivers/firmware/arm_ffa/driver.c101
-rw-r--r--drivers/firmware/broadcom/bcm47xx_nvram.c18
-rw-r--r--drivers/firmware/cirrus/Kconfig2
-rw-r--r--drivers/firmware/cirrus/Makefile2
-rw-r--r--drivers/firmware/cirrus/cs_dsp.c79
-rw-r--r--drivers/firmware/efi/cper.c3
-rw-r--r--drivers/firmware/efi/earlycon.c8
-rw-r--r--drivers/firmware/efi/efi-pstore.c2
-rw-r--r--drivers/firmware/efi/efi.c19
-rw-r--r--drivers/firmware/efi/libstub/Makefile3
-rw-r--r--drivers/firmware/efi/libstub/arm64-stub.c17
-rw-r--r--drivers/firmware/efi/libstub/efistub.h28
-rw-r--r--drivers/firmware/efi/libstub/smbios.c48
-rw-r--r--drivers/firmware/google/coreboot_table.c37
-rw-r--r--drivers/firmware/imx/scu-pd.c1
-rw-r--r--drivers/firmware/raspberrypi.c47
-rw-r--r--drivers/firmware/tegra/Kconfig1
-rw-r--r--drivers/firmware/tegra/bpmp-debugfs.c62
-rw-r--r--drivers/firmware/tegra/bpmp-tegra186.c36
-rw-r--r--drivers/firmware/tegra/bpmp-tegra210.c15
-rw-r--r--drivers/firmware/tegra/bpmp.c33
-rw-r--r--drivers/firmware/tegra/ivc.c150
-rw-r--r--drivers/firmware/ti_sci.c24
-rw-r--r--drivers/fpga/Kconfig4
-rw-r--r--drivers/fsi/fsi-sbefifo.c6
-rw-r--r--drivers/gpio/gpio-amd8111.c4
-rw-r--r--drivers/gpio/gpio-rockchip.c1
-rw-r--r--drivers/gpio/gpiolib.c42
-rw-r--r--drivers/gpu/drm/Kconfig63
-rw-r--r--drivers/gpu/drm/Makefile113
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Kconfig29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c94
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c110
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c238
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c39
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c54
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c215
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c (renamed from drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c)101
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.h (renamed from drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h)15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c56
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.c90
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.h17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c136
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c217
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c43
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c72
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c514
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.h103
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c56
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c200
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c87
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c69
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h41
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c71
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_encoders.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v6_0.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c66
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c330
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c79
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c81
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.h7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v10_1.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v11_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmsch_v4_0.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nv.c28
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v10_0.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v12_0.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v13_0.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v3_1.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dma.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc15.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc15d.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc21.c57
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v6_7.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v6_7.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v8_10.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v8_10.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c103
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega20_ih.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c34
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.c377
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.h36
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c23
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_iommu.c29
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c26
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h291
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c12
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c27
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c371
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.h6
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c436
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h30
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c157
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h12
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c13
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c80
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c53
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c265
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h12
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h64
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c50
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c46
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c32
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c23
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c71
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c39
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_smu13_driver_if.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c688
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c233
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c256
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h107
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c185
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h37
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h36
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_trace.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c81
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c34
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c46
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c44
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h363
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c32
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c127
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c27
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mmhubbub.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c46
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c29
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c45
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c113
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/Makefile20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dc_features.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c36
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c59
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c173
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c47
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c82
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h36
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h66
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_hwss.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/irq_service.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h69
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c52
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c25
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h55
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.c2
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c8
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h3
-rw-r--r--drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c6
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.c9
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h1
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h1
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_offset.h3
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_sh_mask.h27
-rw-r--r--drivers/gpu/drm/amd/include/atombios.h34
-rw-r--r--drivers/gpu/drm/amd/include/atomfirmware.h63
-rw-r--r--drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_4_0.h3
-rw-r--r--drivers/gpu/drm/amd/include/kgd_pp_interface.h3
-rw-r--r--drivers/gpu/drm/amd/include/mes_v11_api_def.h6
-rw-r--r--drivers/gpu/drm/amd/include/yellow_carp_offset.h1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c5
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c25
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c29
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h117
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_4_ppsmc.h15
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h10
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c30
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c43
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c122
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c17
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c31
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c18
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h3
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_drv.c2
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.c2
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c25
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c43
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.h2
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c7
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c71
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h2
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c10
-rw-r--r--drivers/gpu/drm/arm/malidp_mw.c6
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c32
-rw-r--r--drivers/gpu/drm/armada/armada_fbdev.c6
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c8
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_drv.c2
-rw-r--r--drivers/gpu/drm/ast/Kconfig4
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c5
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h35
-rw-r--r--drivers/gpu/drm/ast/ast_main.c5
-rw-r--r--drivers/gpu/drm/ast/ast_mm.c14
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c499
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c2
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h3
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c24
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7533.c45
-rw-r--r--drivers/gpu/drm/bridge/ite-it6505.c164
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8640.c9
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c6
-rw-r--r--drivers/gpu/drm/bridge/tc358762.c2
-rw-r--r--drivers/gpu/drm/bridge/tc358775.c2
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c4
-rw-r--r--drivers/gpu/drm/display/Makefile14
-rw-r--r--drivers/gpu/drm/display/drm_dp_dual_mode_helper.c51
-rw-r--r--drivers/gpu/drm/display/drm_dp_mst_topology.c2
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c94
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c6
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c4
-rw-r--r--drivers/gpu/drm/drm_client.c10
-rw-r--r--drivers/gpu/drm/drm_client_modeset.c4
-rw-r--r--drivers/gpu/drm/drm_connector.c4
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c27
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h15
-rw-r--r--drivers/gpu/drm/drm_debugfs.c8
-rw-r--r--drivers/gpu/drm/drm_drv.c103
-rw-r--r--drivers/gpu/drm/drm_edid.c704
-rw-r--r--drivers/gpu/drm/drm_edid_load.c112
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c1014
-rw-r--r--drivers/gpu/drm/drm_fbdev_generic.c494
-rw-r--r--drivers/gpu/drm/drm_file.c2
-rw-r--r--drivers/gpu/drm/drm_format_helper.c10
-rw-r--r--drivers/gpu/drm/drm_fourcc.c8
-rw-r--r--drivers/gpu/drm/drm_gem.c24
-rw-r--r--drivers/gpu/drm/drm_gem_atomic_helper.c66
-rw-r--r--drivers/gpu/drm/drm_gem_dma_helper.c6
-rw-r--r--drivers/gpu/drm/drm_gem_framebuffer_helper.c7
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c18
-rw-r--r--drivers/gpu/drm/drm_gem_ttm_helper.c9
-rw-r--r--drivers/gpu/drm/drm_gem_vram_helper.c18
-rw-r--r--drivers/gpu/drm/drm_internal.h3
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c2
-rw-r--r--drivers/gpu/drm/drm_mode_config.c3
-rw-r--r--drivers/gpu/drm/drm_modes.c116
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c12
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c4
-rw-r--r--drivers/gpu/drm/drm_prime.c8
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c3
-rw-r--r--drivers/gpu/drm/drm_rect.c2
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c32
-rw-r--r--drivers/gpu/drm/drm_sysfs.c24
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h3
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_dump.c7
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.c19
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.h1
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c6
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c58
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h23
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_hwdb.c31
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.c27
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.h1
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c6
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c2
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c12
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h1
-rw-r--r--drivers/gpu/drm/gud/gud_connector.c2
-rw-r--r--drivers/gpu/drm/gud/gud_drv.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c17
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h4
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c2
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_drv.c2
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_modeset.c1
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c2
-rw-r--r--drivers/gpu/drm/i915/Kconfig.profile26
-rw-r--r--drivers/gpu/drm/i915/Makefile20
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.c1
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.h2
-rw-r--r--drivers/gpu/drm/i915/display/g4x_hdmi.c19
-rw-r--r--drivers/gpu/drm/i915/display/hsw_ips.c8
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_plane.c4
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c22
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi_regs.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.c64
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c682
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio_regs.h89
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight_regs.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_bw.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c92
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c946
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.h6
-rw-r--r--drivers/gpu/drm/i915/display/intel_combo_phy.c19
-rw-r--r--drivers/gpu/drm/i915/display/intel_connector.c18
-rw-r--r--drivers/gpu/drm/i915/display/intel_connector.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_crt.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc_state_dump.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c137
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c197
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h46
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h26
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c311
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c45
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.h15
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_map.c69
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_well.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_well.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_reg_defs.h53
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_trace.h206
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h82
-rw-r--r--drivers/gpu/drm/i915/display/intel_dkl_phy.c33
-rw-r--r--drivers/gpu/drm/i915/display/intel_dkl_phy.h10
-rw-r--r--drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h204
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.c26
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c111
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_hdcp.c21
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c47
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.c43
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.h19
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c126
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpt.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_drrs.c113
-rw-r--r--drivers/gpu/drm/i915/display/intel_drrs.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi_vbt.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo_dev.h8
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb_pin.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c35
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbdev.c14
-rw-r--r--drivers/gpu/drm/i915/display/intel_fdi.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_fifo_underrun.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_frontbuffer.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_global_state.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_global_state.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c22
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp_regs.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c58
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.h8
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c216
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_hti.c38
-rw-r--r--drivers/gpu/drm/i915/display/intel_hti.h18
-rw-r--r--drivers/gpu/drm/i915/display/intel_hti_regs.h16
-rw-r--r--drivers/gpu/drm/i915/display/intel_lpe_audio.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_lspcon.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_lvds.c48
-rw-r--r--drivers/gpu/drm/i915/display/intel_mg_phy_regs.h (renamed from drivers/gpu/drm/i915/display/intel_tc_phy_regs.h)8
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_setup.c23
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_verify.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_panel.c31
-rw-r--r--drivers/gpu/drm/i915/display/intel_pch_display.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_pch_refclk.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_pipe_crc.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c57
-rw-r--r--drivers/gpu/drm/i915/display/intel_sdvo.c173
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_phy.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_phy_regs.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c78
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_tv.c89
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_vga.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c1
-rw-r--r--drivers/gpu/drm/i915/display/skl_scaler.c2
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.c7
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.h1
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.c26
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi.c23
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi_regs.h2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_clflush.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_context.c5
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c55
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c51
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_internal.c5
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_mman.c23
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.c26
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.h7
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_pages.c19
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_phys.c9
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_pm.c35
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shmem.c6
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_stolen.c263
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm.c131
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm.h18
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_userptr.c12
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c2
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/huge_pages.c167
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c22
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c4
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c134
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c95
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c12
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c8
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h14
-rw-r--r--drivers/gpu/drm/i915/gt/gen8_engine_cs.c55
-rw-r--r--drivers/gpu/drm/i915/gt/gen8_engine_cs.h12
-rw-r--r--drivers/gpu/drm/i915/gt/gen8_ppgtt.c92
-rw-r--r--drivers/gpu/drm/i915/gt/intel_context.h8
-rw-r--r--drivers/gpu/drm/i915/gt/intel_context_types.h9
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine.h6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c124
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c39
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_regs.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_types.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_user.c28
-rw-r--r--drivers/gpu/drm/i915/gt/intel_execlists_submission.c20
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt.c20
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gpu_commands.h4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gsc.c23
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.c163
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c38
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_irq.c104
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_mcr.c307
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_mcr.h24
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_pm.c28
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c284
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_regs.h210
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_requests.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_sysfs.c15
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_sysfs.h7
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c477
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_types.h25
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.c44
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.h3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c143
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.h2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_migrate.c1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_mocs.c12
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rc6.c64
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rc6.h11
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rc6_types.h15
-rw-r--r--drivers/gpu/drm/i915/gt/intel_renderstate.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_reset.c20
-rw-r--r--drivers/gpu/drm/i915/gt/intel_reset.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring_submission.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.c318
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.h5
-rw-r--r--drivers/gpu/drm/i915/gt/intel_sseu.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_wopcm.c (renamed from drivers/gpu/drm/i915/intel_wopcm.c)43
-rw-r--r--drivers/gpu/drm/i915/gt/intel_wopcm.h (renamed from drivers/gpu/drm/i915/intel_wopcm.h)0
-rw-r--r--drivers/gpu/drm/i915/gt/intel_workarounds.c713
-rw-r--r--drivers/gpu/drm/i915/gt/intel_workarounds_types.h12
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_engine_cs.c22
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_engine_pm.c2
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_execlists.c64
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_gt_pm.c36
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_hangcheck.c86
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_lrc.c33
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_migrate.c1
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_mocs.c5
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rc6.c6
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rps.c20
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_slpc.c260
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_workarounds.c28
-rw-r--r--drivers/gpu/drm/i915/gt/sysfs_engines.c25
-rw-r--r--drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h1
-rw-r--r--drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h9
-rw-r--r--drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h9
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.c48
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.h21
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c82
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c132
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c61
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c12
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h50
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_log.c6
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c13
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h2
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c103
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h4
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h3
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c348
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc.c316
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc.h31
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c34
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h1
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.c13
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c70
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h14
-rw-r--r--drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c8
-rw-r--r--drivers/gpu/drm/i915/gvt/cfg_space.c6
-rw-r--r--drivers/gpu/drm/i915/gvt/cmd_parser.c1
-rw-r--r--drivers/gpu/drm/i915/gvt/display.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/dmabuf.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/dmabuf.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/firmware.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.c7
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c5
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c12
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.c1
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio_context.c15
-rw-r--r--drivers/gpu/drm/i915/gvt/page_track.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.c5
-rw-r--r--drivers/gpu/drm/i915/gvt/vgpu.c6
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c4
-rw-r--r--drivers/gpu/drm/i915/i915_driver.c34
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h67
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c57
-rw-r--r--drivers/gpu/drm/i915/i915_getparam.c5
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c13
-rw-r--r--drivers/gpu/drm/i915/i915_hwmon.c732
-rw-r--r--drivers/gpu/drm/i915/i915_hwmon.h20
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c293
-rw-r--r--drivers/gpu/drm/i915/i915_irq.h9
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c13
-rw-r--r--drivers/gpu/drm/i915/i915_perf.c601
-rw-r--r--drivers/gpu/drm/i915/i915_perf.h2
-rw-r--r--drivers/gpu/drm/i915/i915_perf_oa_regs.h6
-rw-r--r--drivers/gpu/drm/i915/i915_perf_types.h47
-rw-r--r--drivers/gpu/drm/i915/i915_pmu.c9
-rw-r--r--drivers/gpu/drm/i915/i915_query.c12
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h354
-rw-r--r--drivers/gpu/drm/i915/i915_reg_defs.h57
-rw-r--r--drivers/gpu/drm/i915/i915_request.c24
-rw-r--r--drivers/gpu/drm/i915/i915_request.h5
-rw-r--r--drivers/gpu/drm/i915/i915_scatterlist.c4
-rw-r--r--drivers/gpu/drm/i915/i915_selftest.h2
-rw-r--r--drivers/gpu/drm/i915/i915_sw_fence.c1
-rw-r--r--drivers/gpu/drm/i915/i915_sw_fence.h1
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c3
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h16
-rw-r--r--drivers/gpu/drm/i915/i915_ttm_buddy_manager.c12
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c30
-rw-r--r--drivers/gpu/drm/i915/i915_vma.h1
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.c85
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.h20
-rw-r--r--drivers/gpu/drm/i915/intel_dram.c3
-rw-r--r--drivers/gpu/drm/i915/intel_gvt_mmio_table.c3
-rw-r--r--drivers/gpu/drm/i915/intel_mchbar_regs.h21
-rw-r--r--drivers/gpu/drm/i915/intel_memory_region.c4
-rw-r--r--drivers/gpu/drm/i915/intel_pci_config.h28
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c472
-rw-r--r--drivers/gpu/drm/i915/intel_region_ttm.c2
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c5
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.h22
-rw-r--r--drivers/gpu/drm/i915/intel_step.c32
-rw-r--r--drivers/gpu/drm/i915/intel_step.h28
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c302
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.h54
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp.c32
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp.h32
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_42.h28
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h26
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h35
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_huc.c70
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_huc.h13
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_irq.h8
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_session.c9
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_session.h11
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_tee.c154
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_tee.h5
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h36
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_types.h6
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_gem_gtt.c15
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_perf.c16
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_request.c266
-rw-r--r--drivers/gpu/drm/i915/selftests/igt_spinner.c20
-rw-r--r--drivers/gpu/drm/i915/selftests/intel_uncore.c4
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_gem_device.c1
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_region.c2
-rw-r--r--drivers/gpu/drm/i915/vlv_sideband.c2
-rw-r--r--drivers/gpu/drm/i915/vlv_suspend.c28
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c3
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c2
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c2
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c1
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c2
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c9
-rw-r--r--drivers/gpu/drm/kmb/kmb_drv.c2
-rw-r--r--drivers/gpu/drm/kmb/kmb_plane.c1
-rw-r--r--drivers/gpu/drm/lima/lima_devfreq.c15
-rw-r--r--drivers/gpu/drm/lima/lima_sched.c4
-rw-r--r--drivers/gpu/drm/logicvc/logicvc_drm.c2
-rw-r--r--drivers/gpu/drm/logicvc/logicvc_mode.c2
-rw-r--r--drivers/gpu/drm/mcde/mcde_drv.c3
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl.c57
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c29
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c10
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.c74
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.h8
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c9
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c2
-rw-r--r--drivers/gpu/drm/meson/meson_encoder_cvbs.c7
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c1
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h1
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200se.c3
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c11
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a4xx_gpu.c5
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c29
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_preempt.c4
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c12
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.c117
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c3
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c29
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h9
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c7
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c24
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c104
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h1
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c11
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c19
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c19
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c27
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c14
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.c21
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c7
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c121
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c2
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.h1
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c17
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c352
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h3
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c29
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h8
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c6
-rw-r--r--drivers/gpu/drm/msm/msm_gem_shrinker.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c3
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c31
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h22
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c20
-rw-r--r--drivers/gpu/drm/msm/msm_mdss.c85
-rw-r--r--drivers/gpu/drm/msm/msm_mmu.h3
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.h28
-rw-r--r--drivers/gpu/drm/mxsfb/lcdif_drv.c2
-rw-r--r--drivers/gpu/drm/mxsfb/lcdif_kms.c269
-rw-r--r--drivers/gpu/drm/mxsfb/lcdif_regs.h42
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c2
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c43
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.c15
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h7
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/crc.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c406
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/head.c25
-rw-r--r--drivers/gpu/drm/nouveau/include/nvfw/acr.h85
-rw-r--r--drivers/gpu/drm/nouveau/include/nvfw/hs.h28
-rw-r--r--drivers/gpu/drm/nouveau/include/nvfw/ls.h51
-rw-r--r--drivers/gpu/drm/nouveau/include/nvfw/sec2.h45
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl0046.h23
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl006b.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl0080.h4
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl506e.h13
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl506f.h14
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl5070.h92
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl826e.h15
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl826f.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl906f.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cla06f.h18
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/class.h45
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/clb069.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/clc36f.h19
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/conn.h10
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/disp.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/event.h91
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/head.h23
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0004.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if000e.h26
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0010.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0011.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0012.h98
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0013.h35
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0020.h45
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0021.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/ioctl.h51
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/notify.h35
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/outp.h19
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/client.h15
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/device.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/engine.h8
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/event.h64
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h167
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h25
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/intr.h73
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/layout.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/memory.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/notify.h39
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/object.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/os.h20
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h42
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h9
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h66
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h86
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h29
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h7
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h7
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h3
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h19
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo0039.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo5039.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo74c1.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo85b5.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo9039.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo90b5.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_boa0b5.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c306
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.h14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c81
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_crtc.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c86
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c40
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c57
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h82
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c53
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_nvif.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c50
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_usif.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vga.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c257
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c299
-rw-r--r--drivers/gpu/drm/nouveau/nv84_fence.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fbcon.c297
-rw-r--r--drivers/gpu/drm/nouveau/nvif/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvif/conn.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvif/disp.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvif/event.c81
-rw-r--r--drivers/gpu/drm/nouveau/nvif/head.c58
-rw-r--r--drivers/gpu/drm/nouveau/nvif/notify.c210
-rw-r--r--drivers/gpu/drm/nouveau/nvif/outp.c178
-rw-r--r--drivers/gpu/drm/nouveau/nvif/user.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/client.c130
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/engine.c85
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/event.c158
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/firmware.c127
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/intr.c442
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/ioctl.c115
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/notify.c163
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/oproxy.c20
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/subdev.c117
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/uevent.c157
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c82
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/fifo/usergv100.c)35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c104
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/user.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c39
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c283
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c91
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c85
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c89
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c95
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h23
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c250
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c75
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c127
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c250
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/falcon.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild30
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c448
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c252
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h76
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c633
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h99
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c263
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h29
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h52
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h29
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c276
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c111
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c226
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c97
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c98
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c254
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c253
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c70
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c550
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c292
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c942
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c1506
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h168
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c105
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c59
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c33
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c45
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c99
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c46
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c95
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c308
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c361
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c241
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c81
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c252
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c344
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h23
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c94
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c198
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c381
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h20
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h223
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c430
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h125
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c45
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h31
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c471
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c125
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c409
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c77
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c224
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h77
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c71
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c80
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c60
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c347
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c488
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h80
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c119
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c203
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c47
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c98
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c197
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c116
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c26
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c20
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/base.c245
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/fw.c354
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c148
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c345
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c82
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/priv.h8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/v1.c210
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c41
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c39
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c152
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c326
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c199
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c31
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c55
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c67
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c177
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c145
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h104
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c41
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c120
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c30
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c59
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c31
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c130
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c50
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c82
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c126
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c63
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c23
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c29
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h50
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c136
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c50
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c32
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c33
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c)58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c47
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c)27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c108
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c67
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c8
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c6
-rw-r--r--drivers/gpu/drm/panel/Kconfig19
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c2
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9341.c3
-rw-r--r--drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c473
-rw-r--r--drivers/gpu/drm/panel/panel-newvision-nv3051d.c504
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-db7430.c7
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c2
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7701.c70
-rw-r--r--drivers/gpu/drm/panel/panel-tpo-tpg110.c7
-rw-r--r--drivers/gpu/drm/panel/panel-widechips-ws2401.c7
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_dump.c4
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_mmu.c11
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_perfcnt.c6
-rw-r--r--drivers/gpu/drm/pl111/pl111_drv.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h1
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c17
-rw-r--r--drivers/gpu/drm/qxl/qxl_prime.c4
-rw-r--r--drivers/gpu/drm/radeon/Kconfig30
-rw-r--r--drivers/gpu/drm/radeon/atombios.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.c117
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_trace.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c8
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig19
-rw-r--r--drivers/gpu/drm/rcar-du/Makefile2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c816
-rw-r--r--drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h151
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.c2
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c8
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.c2
-rw-r--r--drivers/gpu/drm/rockchip/rk3066_hdmi.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.c45
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.h6
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop2.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_lvds.c10
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop2_reg.c2
-rw-r--r--drivers/gpu/drm/scheduler/sched_entity.c216
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c229
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c37
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c2
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c2
-rw-r--r--drivers/gpu/drm/stm/drv.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c61
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h7
-rw-r--r--drivers/gpu/drm/tegra/Makefile3
-rw-r--r--drivers/gpu/drm/tegra/dc.c4
-rw-r--r--drivers/gpu/drm/tegra/drm.c5
-rw-r--r--drivers/gpu/drm/tegra/fb.c9
-rw-r--r--drivers/gpu/drm/tegra/gem.c19
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c9
-rw-r--r--drivers/gpu/drm/tegra/nvdec.c171
-rw-r--r--drivers/gpu/drm/tegra/output.c10
-rw-r--r--drivers/gpu/drm/tegra/riscv.c106
-rw-r--r--drivers/gpu/drm/tegra/riscv.h30
-rw-r--r--drivers/gpu/drm/tegra/submit.c13
-rw-r--r--drivers/gpu/drm/tegra/uapi.c2
-rw-r--r--drivers/gpu/drm/tests/Makefile15
-rw-r--r--drivers/gpu/drm/tests/drm_buddy_test.c6
-rw-r--r--drivers/gpu/drm/tests/drm_client_modeset_test.c98
-rw-r--r--drivers/gpu/drm/tests/drm_dp_mst_helper_test.c445
-rw-r--r--drivers/gpu/drm/tests/drm_format_helper_test.c12
-rw-r--r--drivers/gpu/drm/tests/drm_kunit_helpers.c71
-rw-r--r--drivers/gpu/drm/tests/drm_kunit_helpers.h11
-rw-r--r--drivers/gpu/drm/tests/drm_mm_test.c8
-rw-r--r--drivers/gpu/drm/tests/drm_plane_helper_test.c467
-rw-r--r--drivers/gpu/drm/tidss/tidss_drv.c2
-rw-r--r--drivers/gpu/drm/tidss/tidss_kms.c1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c2
-rw-r--r--drivers/gpu/drm/tiny/Kconfig13
-rw-r--r--drivers/gpu/drm/tiny/Makefile1
-rw-r--r--drivers/gpu/drm/tiny/arcpgu.c2
-rw-r--r--drivers/gpu/drm/tiny/bochs.c3
-rw-r--r--drivers/gpu/drm/tiny/cirrus.c2
-rw-r--r--drivers/gpu/drm/tiny/gm12u320.c2
-rw-r--r--drivers/gpu/drm/tiny/hx8357d.c2
-rw-r--r--drivers/gpu/drm/tiny/ili9163.c2
-rw-r--r--drivers/gpu/drm/tiny/ili9225.c2
-rw-r--r--drivers/gpu/drm/tiny/ili9341.c2
-rw-r--r--drivers/gpu/drm/tiny/ili9486.c2
-rw-r--r--drivers/gpu/drm/tiny/mi0283qt.c2
-rw-r--r--drivers/gpu/drm/tiny/ofdrm.c1429
-rw-r--r--drivers/gpu/drm/tiny/panel-mipi-dbi.c2
-rw-r--r--drivers/gpu/drm/tiny/repaper.c2
-rw-r--r--drivers/gpu/drm/tiny/simpledrm.c18
-rw-r--r--drivers/gpu/drm/tiny/st7586.c2
-rw-r--r--drivers/gpu/drm/tiny/st7735r.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_pool.c82
-rw-r--r--drivers/gpu/drm/ttm/ttm_range_manager.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c14
-rw-r--r--drivers/gpu/drm/tve200/tve200_drv.c3
-rw-r--r--drivers/gpu/drm/udl/Makefile2
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c139
-rw-r--r--drivers/gpu/drm/udl/udl_connector.h15
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c2
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h42
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c566
-rw-r--r--drivers/gpu/drm/udl/udl_proto.h68
-rw-r--r--drivers/gpu/drm/udl/udl_transfer.c7
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.c1
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c17
-rw-r--r--drivers/gpu/drm/v3d/v3d_perfmon.c6
-rw-r--r--drivers/gpu/drm/vboxvideo/vbox_drv.c4
-rw-r--r--drivers/gpu/drm/vboxvideo/vbox_main.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h16
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c86
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.h9
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c26
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c21
-rw-r--r--drivers/gpu/drm/vc4/vc4_vec.c8
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.c1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h1
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/Kconfig7
-rw-r--r--drivers/gpu/drm/vmwgfx/Makefile4
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_object.c123
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_object.h20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_blit.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c22
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c62
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c31
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c129
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h53
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c17
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c831
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c199
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h83
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c669
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h31
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_msg.c65
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c35
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c26
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c14
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.c55
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.h26
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_gem.c1
-rw-r--r--drivers/gpu/drm/xlnx/Makefile2
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_disp.c646
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_disp.h48
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dp.c477
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dp.h4
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dpsub.c300
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dpsub.h46
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_kms.c534
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_kms.h46
-rw-r--r--drivers/gpu/host1x/context.c4
-rw-r--r--drivers/gpu/host1x/debug.c28
-rw-r--r--drivers/gpu/host1x/dev.c16
-rw-r--r--drivers/gpu/host1x/fence.c2
-rw-r--r--drivers/hid/hid-asus.c4
-rw-r--r--drivers/hid/hid-core.c3
-rw-r--r--drivers/hid/hid-hyperv.c2
-rw-r--r--drivers/hid/hid-ids.h4
-rw-r--r--drivers/hid/hid-ite.c5
-rw-r--r--drivers/hid/hid-lg4ff.c6
-rw-r--r--drivers/hid/hid-logitech-hidpp.c28
-rw-r--r--drivers/hid/hid-quirks.c3
-rw-r--r--drivers/hid/hid-uclogic-core.c1
-rw-r--r--drivers/hid/hid-uclogic-rdesc.c2
-rw-r--r--drivers/hid/i2c-hid/Kconfig4
-rw-r--r--drivers/hid/wacom_wac.c11
-rw-r--r--drivers/hv/channel_mgmt.c6
-rw-r--r--drivers/hv/hv_balloon.c96
-rw-r--r--drivers/hv/ring_buffer.c13
-rw-r--r--drivers/hv/vmbus_drv.c111
-rw-r--r--drivers/hwmon/acpi_power_meter.c5
-rw-r--r--drivers/hwmon/asus-ec-sensors.c2
-rw-r--r--drivers/hwmon/asus_atk0110.c6
-rw-r--r--drivers/hwmon/coretemp.c9
-rw-r--r--drivers/hwmon/i5500_temp.c2
-rw-r--r--drivers/hwmon/ibmpex.c1
-rw-r--r--drivers/hwmon/ina3221.c4
-rw-r--r--drivers/hwmon/ltc2947-core.c2
-rw-r--r--drivers/hwspinlock/qcom_hwspinlock.c42
-rw-r--r--drivers/i2c/busses/i2c-cadence.c11
-rw-r--r--drivers/i2c/busses/i2c-imx.c6
-rw-r--r--drivers/i2c/busses/i2c-npcm7xx.c11
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c1
-rw-r--r--drivers/i2c/i2c-core-base.c9
-rw-r--r--drivers/iio/accel/bma400_core.c28
-rw-r--r--drivers/iio/adc/aspeed_adc.c11
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c6
-rw-r--r--drivers/iio/adc/at91_adc.c4
-rw-r--r--drivers/iio/adc/mp2629_adc.c5
-rw-r--r--drivers/iio/health/afe4403.c5
-rw-r--r--drivers/iio/health/afe4404.c12
-rw-r--r--drivers/iio/imu/bno055/bno055.c2
-rw-r--r--drivers/iio/industrialio-sw-trigger.c6
-rw-r--r--drivers/iio/light/Kconfig2
-rw-r--r--drivers/iio/light/apds9960.c12
-rw-r--r--drivers/iio/pressure/ms5611.h12
-rw-r--r--drivers/iio/pressure/ms5611_core.c51
-rw-r--r--drivers/iio/pressure/ms5611_spi.c2
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c6
-rw-r--r--drivers/infiniband/core/cm_trace.h2
-rw-r--r--drivers/infiniband/core/cma.c2
-rw-r--r--drivers/infiniband/core/cma_trace.h2
-rw-r--r--drivers/infiniband/core/umem_dmabuf.c7
-rw-r--r--drivers/infiniband/hw/cxgb4/id_table.c4
-rw-r--r--drivers/infiniband/hw/hfi1/init.c21
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_ah.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c21
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt.c4
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c8
-rw-r--r--drivers/input/misc/atlas_btns.c4
-rw-r--r--drivers/input/misc/soc_button_array.c14
-rw-r--r--drivers/input/mouse/synaptics.c1
-rw-r--r--drivers/input/serio/i8042-acpipnpio.h8
-rw-r--r--drivers/input/serio/i8042.c4
-rw-r--r--drivers/input/touchscreen/goodix.c11
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c4
-rw-r--r--drivers/iommu/Kconfig8
-rw-r--r--drivers/iommu/amd/amd_iommu_types.h1
-rw-r--r--drivers/iommu/amd/iommu.c44
-rw-r--r--drivers/iommu/dma-iommu.c3
-rw-r--r--drivers/iommu/hyperv-iommu.c11
-rw-r--r--drivers/iommu/intel/dmar.c1
-rw-r--r--drivers/iommu/intel/iommu.c81
-rw-r--r--drivers/iommu/intel/iommu.h5
-rw-r--r--drivers/iommu/intel/irq_remapping.c52
-rw-r--r--drivers/iommu/intel/pasid.c5
-rw-r--r--drivers/iommu/intel/svm.c19
-rw-r--r--drivers/iommu/of_iommu.c1
-rw-r--r--drivers/irqchip/Kconfig9
-rw-r--r--drivers/irqchip/irq-apple-aic.c6
-rw-r--r--drivers/irqchip/irq-gic-pm.c2
-rw-r--r--drivers/irqchip/irq-gic-v2m.c11
-rw-r--r--drivers/irqchip/irq-gic-v3.c3
-rw-r--r--drivers/irqchip/irq-gic.c7
-rw-r--r--drivers/irqchip/irq-loongarch-cpu.c48
-rw-r--r--drivers/irqchip/irq-loongson-eiointc.c63
-rw-r--r--drivers/irqchip/irq-loongson-htvec.c176
-rw-r--r--drivers/irqchip/irq-loongson-liointc.c37
-rw-r--r--drivers/irqchip/irq-loongson-pch-lpc.c25
-rw-r--r--drivers/irqchip/irq-loongson-pch-pic.c76
-rw-r--r--drivers/irqchip/irq-ls-extirq.c2
-rw-r--r--drivers/irqchip/irq-mips-gic.c2
-rw-r--r--drivers/irqchip/irq-mtk-cirq.c95
-rw-r--r--drivers/irqchip/irq-mvebu-icu.c4
-rw-r--r--drivers/irqchip/irq-sifive-plic.c6
-rw-r--r--drivers/irqchip/irq-sl28cpld.c3
-rw-r--r--drivers/irqchip/irq-st.c7
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c2
-rw-r--r--drivers/irqchip/irq-wpcm450-aic.c1
-rw-r--r--drivers/isdn/mISDN/core.c2
-rw-r--r--drivers/isdn/mISDN/dsp_pipeline.c3
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/mailbox/Kconfig2
-rw-r--r--drivers/mailbox/pcc.c1
-rw-r--r--drivers/md/bcache/movinggc.c2
-rw-r--r--drivers/md/bcache/request.c4
-rw-r--r--drivers/md/bcache/writeback.c4
-rw-r--r--drivers/md/dm-bufio.c2
-rw-r--r--drivers/md/dm-cache-metadata.c54
-rw-r--r--drivers/md/dm-cache-target.c11
-rw-r--r--drivers/md/dm-clone-target.c1
-rw-r--r--drivers/md/dm-crypt.c1
-rw-r--r--drivers/md/dm-init.c22
-rw-r--r--drivers/md/dm-integrity.c23
-rw-r--r--drivers/md/dm-ioctl.c10
-rw-r--r--drivers/md/dm-log-writes.c1
-rw-r--r--drivers/md/dm-table.c2
-rw-r--r--drivers/md/dm-thin-metadata.c60
-rw-r--r--drivers/md/dm-thin.c20
-rw-r--r--drivers/md/dm.c138
-rw-r--r--drivers/md/md-bitmap.c47
-rw-r--r--drivers/md/md.c323
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/raid0.c1
-rw-r--r--drivers/md/raid1.c13
-rw-r--r--drivers/md/raid10.c20
-rw-r--r--drivers/md/raid5-cache.c10
-rw-r--r--drivers/md/raid5-ppl.c5
-rw-r--r--drivers/media/Kconfig2
-rw-r--r--drivers/media/cec/platform/stm32/stm32-cec.c9
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c8
-rw-r--r--drivers/media/common/videobuf2/frame_vector.c78
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c128
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-contig.c28
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-sg.c26
-rw-r--r--drivers/media/common/videobuf2/videobuf2-memops.c6
-rw-r--r--drivers/media/common/videobuf2/videobuf2-vmalloc.c24
-rw-r--r--drivers/media/dvb-core/dmxdev.c8
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c2
-rw-r--r--drivers/media/dvb-core/dvb_demux.c4
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c33
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.c4
-rw-r--r--drivers/media/dvb-core/dvbdev.c36
-rw-r--r--drivers/media/dvb-frontends/a8293.c160
-rw-r--r--drivers/media/dvb-frontends/a8293.h3
-rw-r--r--drivers/media/dvb-frontends/af9013.c5
-rw-r--r--drivers/media/dvb-frontends/af9033.c5
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c5
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c1
-rw-r--r--drivers/media/dvb-frontends/cxd2099.c5
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c7
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c1
-rw-r--r--drivers/media/dvb-frontends/helene.c5
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c5
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c5
-rw-r--r--drivers/media/dvb-frontends/mn88472.c5
-rw-r--r--drivers/media/dvb-frontends/mn88473.c5
-rw-r--r--drivers/media/dvb-frontends/mxl5xx.c2
-rw-r--r--drivers/media/dvb-frontends/mxl692.c5
-rw-r--r--drivers/media/dvb-frontends/rtl2830.c5
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c5
-rw-r--r--drivers/media/dvb-frontends/si2165.c5
-rw-r--r--drivers/media/dvb-frontends/si2168.c5
-rw-r--r--drivers/media/dvb-frontends/sp2.c5
-rw-r--r--drivers/media/dvb-frontends/stv0288.c5
-rw-r--r--drivers/media/dvb-frontends/stv090x.c5
-rw-r--r--drivers/media/dvb-frontends/stv6110x.c5
-rw-r--r--drivers/media/dvb-frontends/tda10071.c5
-rw-r--r--drivers/media/dvb-frontends/ts2020.c5
-rw-r--r--drivers/media/i2c/Kconfig62
-rw-r--r--drivers/media/i2c/Makefile5
-rw-r--r--drivers/media/i2c/ad5820.c33
-rw-r--r--drivers/media/i2c/ad9389b.c4
-rw-r--r--drivers/media/i2c/adp1653.c5
-rw-r--r--drivers/media/i2c/adv7170.c5
-rw-r--r--drivers/media/i2c/adv7175.c5
-rw-r--r--drivers/media/i2c/adv7183.c5
-rw-r--r--drivers/media/i2c/adv7393.c5
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c4
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h3
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c4
-rw-r--r--drivers/media/i2c/adv7842.c5
-rw-r--r--drivers/media/i2c/ak881x.c5
-rw-r--r--drivers/media/i2c/aptina-pll.c1
-rw-r--r--drivers/media/i2c/ar0521.c352
-rw-r--r--drivers/media/i2c/bt819.c5
-rw-r--r--drivers/media/i2c/bt856.c5
-rw-r--r--drivers/media/i2c/bt866.c5
-rw-r--r--drivers/media/i2c/cs3308.c5
-rw-r--r--drivers/media/i2c/cs5345.c5
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c5
-rw-r--r--drivers/media/i2c/dw9768.c33
-rw-r--r--drivers/media/i2c/hi846.c14
-rw-r--r--drivers/media/i2c/imx208.c4
-rw-r--r--drivers/media/i2c/imx274.c5
-rw-r--r--drivers/media/i2c/imx290.c786
-rw-r--r--drivers/media/i2c/imx319.c4
-rw-r--r--drivers/media/i2c/imx355.c4
-rw-r--r--drivers/media/i2c/imx412.c9
-rw-r--r--drivers/media/i2c/isl7998x.c2
-rw-r--r--drivers/media/i2c/ks0127.c4
-rw-r--r--drivers/media/i2c/lm3560.c5
-rw-r--r--drivers/media/i2c/lm3646.c5
-rw-r--r--drivers/media/i2c/m52790.c5
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c5
-rw-r--r--drivers/media/i2c/ml86v7667.c5
-rw-r--r--drivers/media/i2c/mt9m032.c5
-rw-r--r--drivers/media/i2c/mt9p031.c9
-rw-r--r--drivers/media/i2c/mt9t001.c5
-rw-r--r--drivers/media/i2c/mt9t112.c5
-rw-r--r--drivers/media/i2c/mt9v011.c5
-rw-r--r--drivers/media/i2c/noon010pc30.c5
-rw-r--r--drivers/media/i2c/ov08d10.c5
-rw-r--r--drivers/media/i2c/ov08x40.c3325
-rw-r--r--drivers/media/i2c/ov13858.c5
-rw-r--r--drivers/media/i2c/ov2640.c2
-rw-r--r--drivers/media/i2c/ov2680.c2
-rw-r--r--drivers/media/i2c/ov2740.c134
-rw-r--r--drivers/media/i2c/ov4689.c1018
-rw-r--r--drivers/media/i2c/ov5640.c25
-rw-r--r--drivers/media/i2c/ov5645.c148
-rw-r--r--drivers/media/i2c/ov5648.c1
-rw-r--r--drivers/media/i2c/ov5693.c10
-rw-r--r--drivers/media/i2c/ov6650.c5
-rw-r--r--drivers/media/i2c/ov7640.c5
-rw-r--r--drivers/media/i2c/ov7670.c1
-rw-r--r--drivers/media/i2c/ov8856.c33
-rw-r--r--drivers/media/i2c/ov9282.c611
-rw-r--r--drivers/media/i2c/ov9640.c5
-rw-r--r--drivers/media/i2c/ov9650.c49
-rw-r--r--drivers/media/i2c/rj54n1cb0c.c5
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c107
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c1
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h10
-rw-r--r--drivers/media/i2c/s5k4ecgx.c1032
-rw-r--r--drivers/media/i2c/s5k5baf.c64
-rw-r--r--drivers/media/i2c/s5k6a3.c30
-rw-r--r--drivers/media/i2c/s5k6aa.c5
-rw-r--r--drivers/media/i2c/saa6588.c5
-rw-r--r--drivers/media/i2c/saa6752hs.c5
-rw-r--r--drivers/media/i2c/saa7110.c5
-rw-r--r--drivers/media/i2c/saa717x.c5
-rw-r--r--drivers/media/i2c/saa7185.c5
-rw-r--r--drivers/media/i2c/sony-btf-mpx.c5
-rw-r--r--drivers/media/i2c/sr030pc30.c5
-rw-r--r--drivers/media/i2c/st-vgxy61.c1963
-rw-r--r--drivers/media/i2c/tc358743.c9
-rw-r--r--drivers/media/i2c/tc358746.c1694
-rw-r--r--drivers/media/i2c/tda7432.c5
-rw-r--r--drivers/media/i2c/tda9840.c5
-rw-r--r--drivers/media/i2c/tea6415c.c5
-rw-r--r--drivers/media/i2c/tea6420.c5
-rw-r--r--drivers/media/i2c/ths7303.c5
-rw-r--r--drivers/media/i2c/tlv320aic23b.c5
-rw-r--r--drivers/media/i2c/tw2804.c5
-rw-r--r--drivers/media/i2c/tw9903.c5
-rw-r--r--drivers/media/i2c/tw9906.c5
-rw-r--r--drivers/media/i2c/tw9910.c5
-rw-r--r--drivers/media/i2c/uda1342.c5
-rw-r--r--drivers/media/i2c/upd64031a.c5
-rw-r--r--drivers/media/i2c/upd64083.c5
-rw-r--r--drivers/media/i2c/vp27smpx.c5
-rw-r--r--drivers/media/i2c/vpx3220.c5
-rw-r--r--drivers/media/i2c/vs6624.c5
-rw-r--r--drivers/media/i2c/wm8739.c5
-rw-r--r--drivers/media/i2c/wm8775.c5
-rw-r--r--drivers/media/pci/bt8xx/bttv.h1
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.h3
-rw-r--r--drivers/media/pci/intel/ipu3/Kconfig1
-rw-r--r--drivers/media/pci/mantis/Kconfig2
-rw-r--r--drivers/media/pci/pt3/pt3.c16
-rw-r--r--drivers/media/pci/saa7134/saa7134.h4
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c10
-rw-r--r--drivers/media/pci/saa7164/saa7164.h2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-core.c1
-rw-r--r--drivers/media/pci/zoran/zoran_device.h2
-rw-r--r--drivers/media/platform/Kconfig1
-rw-r--r--drivers/media/platform/Makefile1
-rw-r--r--drivers/media/platform/amphion/vdec.c218
-rw-r--r--drivers/media/platform/amphion/venc.c41
-rw-r--r--drivers/media/platform/amphion/vpu.h5
-rw-r--r--drivers/media/platform/amphion/vpu_cmds.c39
-rw-r--r--drivers/media/platform/amphion/vpu_dbg.c8
-rw-r--r--drivers/media/platform/amphion/vpu_drv.c6
-rw-r--r--drivers/media/platform/amphion/vpu_helpers.c45
-rw-r--r--drivers/media/platform/amphion/vpu_helpers.h2
-rw-r--r--drivers/media/platform/amphion/vpu_malone.c4
-rw-r--r--drivers/media/platform/amphion/vpu_msgs.c2
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.c199
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.h3
-rw-r--r--drivers/media/platform/amphion/vpu_windsor.c9
-rw-r--r--drivers/media/platform/aspeed/Kconfig1
-rw-r--r--drivers/media/platform/aspeed/aspeed-video.c346
-rw-r--r--drivers/media/platform/atmel/Kconfig51
-rw-r--r--drivers/media/platform/atmel/Makefile7
-rw-r--r--drivers/media/platform/chips-media/coda-bit.c14
-rw-r--r--drivers/media/platform/chips-media/coda-jpeg.c10
-rw-r--r--drivers/media/platform/mediatek/jpeg/Makefile14
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c490
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h169
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c325
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h6
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h1
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c255
-rw-r--r--drivers/media/platform/mediatek/mdp/mtk_mdp_comp.c5
-rw-r--r--drivers/media/platform/mediatek/mdp3/Kconfig1
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h76
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c51
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c24
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c15
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c13
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c5
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c60
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c15
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c2
-rw-r--r--drivers/media/platform/microchip/Kconfig61
-rw-r--r--drivers/media/platform/microchip/Makefile9
-rw-r--r--drivers/media/platform/microchip/microchip-csi2dc.c (renamed from drivers/media/platform/atmel/microchip-csi2dc.c)0
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c2040
-rw-r--r--drivers/media/platform/microchip/microchip-isc-clk.c311
-rw-r--r--drivers/media/platform/microchip/microchip-isc-regs.h413
-rw-r--r--drivers/media/platform/microchip/microchip-isc-scaler.c267
-rw-r--r--drivers/media/platform/microchip/microchip-isc.h400
-rw-r--r--drivers/media/platform/microchip/microchip-sama5d2-isc.c683
-rw-r--r--drivers/media/platform/microchip/microchip-sama7g5-isc.c646
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c6
-rw-r--r--drivers/media/platform/nxp/Kconfig13
-rw-r--r--drivers/media/platform/nxp/Makefile1
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c4
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c612
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h10
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c (renamed from drivers/staging/media/imx/imx7-media-csi.c)138
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-170.c20
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-480.c20
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c3
-rw-r--r--drivers/media/platform/qcom/camss/camss.c61
-rw-r--r--drivers/media/platform/qcom/camss/camss.h1
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c20
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c4
-rw-r--r--drivers/media/platform/renesas/Kconfig1
-rw-r--r--drivers/media/platform/renesas/Makefile1
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-core.c22
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c104
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c93
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-vin.h9
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/Kconfig33
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/Makefile6
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c338
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h154
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c875
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c255
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c1058
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-params.c4
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-core.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.c14
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c73
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c4
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c12
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c14
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c9
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c31
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/Makefile2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c779
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h145
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c868
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h69
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c1102
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h89
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h362
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c733
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h35
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c23
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c23
-rw-r--r--drivers/media/platform/ti/omap3isp/isp.c3
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c8
-rw-r--r--drivers/media/radio/radio-tea5764.c5
-rw-r--r--drivers/media/radio/radio-terratec.c3
-rw-r--r--drivers/media/radio/saa7706h.c5
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c4
-rw-r--r--drivers/media/radio/tef6862.c5
-rw-r--r--drivers/media/rc/gpio-ir-recv.c10
-rw-r--r--drivers/media/rc/gpio-ir-tx.c9
-rw-r--r--drivers/media/rc/imon.c6
-rw-r--r--drivers/media/rc/ir-rx51.c9
-rw-r--r--drivers/media/rc/ir-spi.c7
-rw-r--r--drivers/media/test-drivers/Kconfig1
-rw-r--r--drivers/media/test-drivers/Makefile1
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_bridge.c22
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_demod.c13
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_tuner.c5
-rw-r--r--drivers/media/test-drivers/vimc/vimc-core.c2
-rw-r--r--drivers/media/test-drivers/visl/Kconfig29
-rw-r--r--drivers/media/test-drivers/visl/Makefile8
-rw-r--r--drivers/media/test-drivers/visl/visl-core.c541
-rw-r--r--drivers/media/test-drivers/visl/visl-debugfs.c112
-rw-r--r--drivers/media/test-drivers/visl/visl-debugfs.h40
-rw-r--r--drivers/media/test-drivers/visl/visl-dec.c499
-rw-r--r--drivers/media/test-drivers/visl/visl-dec.h67
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-fwht.h66
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-h264.h349
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-hevc.h405
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-mpeg2.h99
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-points.c10
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-vp8.h156
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-vp9.h292
-rw-r--r--drivers/media/test-drivers/visl/visl-video.c767
-rw-r--r--drivers/media/test-drivers/visl/visl-video.h27
-rw-r--r--drivers/media/test-drivers/visl/visl.h176
-rw-r--r--drivers/media/test-drivers/vivid/vivid-ctrls.c28
-rw-r--r--drivers/media/test-drivers/vivid/vivid-kthread-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-kthread-out.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-radio-rx.c4
-rw-r--r--drivers/media/test-drivers/vivid/vivid-sdr-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-touch-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-gen.c1
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c1
-rw-r--r--drivers/media/tuners/e4000.c5
-rw-r--r--drivers/media/tuners/fc2580.c5
-rw-r--r--drivers/media/tuners/m88rs6000t.c5
-rw-r--r--drivers/media/tuners/mt2060.c5
-rw-r--r--drivers/media/tuners/mxl301rf.c5
-rw-r--r--drivers/media/tuners/mxl5005s.c2
-rw-r--r--drivers/media/tuners/qm1d1b0004.c4
-rw-r--r--drivers/media/tuners/qm1d1c0042.c5
-rw-r--r--drivers/media/tuners/tda18212.c5
-rw-r--r--drivers/media/tuners/tda18250.c5
-rw-r--r--drivers/media/tuners/tua9001.c5
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c2
-rw-r--r--drivers/media/usb/au0828/au0828-video.c1
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c4
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h1
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c7
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c6
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c16
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c6
-rw-r--r--drivers/media/usb/go7007/s2250-board.c5
-rw-r--r--drivers/media/usb/pwc/pwc-uncompress.c2
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c9
-rw-r--r--drivers/media/v4l2-core/tuner-core.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-core.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-defs.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c20
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c23
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c121
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c17
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c22
-rw-r--r--drivers/memory/omap-gpmc.c122
-rw-r--r--drivers/memory/renesas-rpc-if.c22
-rw-r--r--drivers/memory/tegra/mc.c25
-rw-r--r--drivers/memory/tegra/tegra186-emc.c15
-rw-r--r--drivers/memory/tegra/tegra20-emc.c15
-rw-r--r--drivers/memory/tegra/tegra210-emc-core.c15
-rw-r--r--drivers/memory/tegra/tegra234.c165
-rw-r--r--drivers/memory/tegra/tegra30-emc.c15
-rw-r--r--drivers/misc/fastrpc.c9
-rw-r--r--drivers/misc/mei/bus.c146
-rw-r--r--drivers/misc/mei/client.c55
-rw-r--r--drivers/misc/mei/hbm.c13
-rw-r--r--drivers/misc/mei/hw-me.c7
-rw-r--r--drivers/misc/mei/hw.h89
-rw-r--r--drivers/misc/mei/interrupt.c47
-rw-r--r--drivers/misc/mei/mei_dev.h8
-rw-r--r--drivers/misc/mei/pxp/mei_pxp.c38
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c8
-rw-r--r--drivers/mmc/core/core.c21
-rw-r--r--drivers/mmc/core/mmc_test.c3
-rw-r--r--drivers/mmc/host/dw_mmc.c2
-rw-r--r--drivers/mmc/host/mtk-sd.c6
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c3
-rw-r--r--drivers/mmc/host/sdhci-cqhci.h24
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c9
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c3
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c2
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c7
-rw-r--r--drivers/mmc/host/sdhci-sprd.c4
-rw-r--r--drivers/mmc/host/sdhci-tegra.c3
-rw-r--r--drivers/mmc/host/sdhci.c61
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/sdhci_am654.c7
-rw-r--r--drivers/mtd/devices/Kconfig8
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/lart.c682
-rw-r--r--drivers/mtd/inftlcore.c2
-rw-r--r--drivers/mtd/lpddr/lpddr2_nvm.c2
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c2
-rw-r--r--drivers/mtd/mtdcore.c55
-rw-r--r--drivers/mtd/mtdoops.c109
-rw-r--r--drivers/mtd/nand/core.c3
-rw-r--r--drivers/mtd/nand/onenand/Kconfig1
-rw-r--r--drivers/mtd/nand/raw/Kconfig6
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c70
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c12
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_mlc.c46
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_slc.c43
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c4
-rw-r--r--drivers/mtd/nand/raw/mpc5121_nfc.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c4
-rw-r--r--drivers/mtd/nand/raw/nandsim.c4
-rw-r--r--drivers/mtd/nand/raw/qcom_nandc.c12
-rw-r--r--drivers/mtd/nand/spi/winbond.c79
-rw-r--r--drivers/mtd/parsers/Kconfig19
-rw-r--r--drivers/mtd/parsers/Makefile1
-rw-r--r--drivers/mtd/parsers/tplink_safeloader.c150
-rw-r--r--drivers/mtd/spi-nor/core.c85
-rw-r--r--drivers/mtd/spi-nor/core.h5
-rw-r--r--drivers/mtd/spi-nor/debugfs.c2
-rw-r--r--drivers/mtd/spi-nor/gigadevice.c24
-rw-r--r--drivers/mtd/spi-nor/issi.c5
-rw-r--r--drivers/mtd/spi-nor/micron-st.c12
-rw-r--r--drivers/mtd/spi-nor/sfdp.c37
-rw-r--r--drivers/mtd/spi-nor/sfdp.h2
-rw-r--r--drivers/mtd/spi-nor/spansion.c61
-rw-r--r--drivers/mtd/spi-nor/sysfs.c20
-rw-r--r--drivers/mtd/spi-nor/winbond.c3
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c10
-rw-r--r--drivers/mtd/tests/stresstest.c8
-rw-r--r--drivers/mtd/ubi/debug.c2
-rw-r--r--drivers/mtd/ubi/debug.h6
-rw-r--r--drivers/net/arcnet/com20020_cs.c11
-rw-r--r--drivers/net/bonding/bond_main.c17
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/c_can/c_can_main.c2
-rw-r--r--drivers/net/can/can327.c23
-rw-r--r--drivers/net/can/cc770/cc770.c2
-rw-r--r--drivers/net/can/cc770/cc770_isa.c10
-rw-r--r--drivers/net/can/ctucanfd/ctucanfd_base.c2
-rw-r--r--drivers/net/can/dev/skb.c10
-rw-r--r--drivers/net/can/flexcan/flexcan-core.c2
-rw-r--r--drivers/net/can/grcan.c2
-rw-r--r--drivers/net/can/ifi_canfd/ifi_canfd.c2
-rw-r--r--drivers/net/can/janz-ican3.c2
-rw-r--r--drivers/net/can/kvaser_pciefd.c2
-rw-r--r--drivers/net/can/m_can/m_can.c4
-rw-r--r--drivers/net/can/m_can/m_can_pci.c9
-rw-r--r--drivers/net/can/mscan/mscan.c2
-rw-r--r--drivers/net/can/pch_can.c2
-rw-r--r--drivers/net/can/peak_canfd/peak_canfd.c2
-rw-r--r--drivers/net/can/rcar/rcar_can.c2
-rw-r--r--drivers/net/can/rcar/rcar_canfd.c15
-rw-r--r--drivers/net/can/sja1000/sja1000.c2
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c10
-rw-r--r--drivers/net/can/slcan/slcan-core.c12
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/can/spi/hi311x.c2
-rw-r--r--drivers/net/can/spi/mcp251x.c2
-rw-r--r--drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c2
-rw-r--r--drivers/net/can/sun4i_can.c2
-rw-r--r--drivers/net/can/ti_hecc.c2
-rw-r--r--drivers/net/can/usb/ems_usb.c2
-rw-r--r--drivers/net/can/usb/esd_usb.c8
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c7
-rw-r--r--drivers/net/can/usb/gs_usb.c2
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c2
-rw-r--r--drivers/net/can/usb/mcba_usb.c12
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c2
-rw-r--r--drivers/net/can/usb/ucan.c2
-rw-r--r--drivers/net/can/usb/usb_8dev.c2
-rw-r--r--drivers/net/can/xilinx_can.c2
-rw-r--r--drivers/net/dsa/lan9303-core.c2
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c7
-rw-r--r--drivers/net/dsa/sja1105/sja1105_devlink.c2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_mdio.c6
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c1
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c1
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c8
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c4
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c5
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_macsec.c2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_main.c4
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_main.h2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/macsec/macsec_api.c18
-rw-r--r--drivers/net/ethernet/atheros/ag71xx.c3
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig1
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c12
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c64
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c3
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c8
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c34
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c4
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c2
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c4
-rw-r--r--drivers/net/ethernet/davicom/dm9051.c4
-rw-r--r--drivers/net/ethernet/engleder/tsnep_main.c57
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c4
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c8
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h1
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_qos.c21
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c23
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.c9
-rw-r--r--drivers/net/ethernet/hisilicon/hisi_femac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c20
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c167
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c19
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c9
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c3
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h1
-rw-r--r--drivers/net/ethernet/intel/e100.c5
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c12
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c30
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h1
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c50
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c25
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c20
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c5
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c10
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c1
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c2
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c8
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_main.c16
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/Kconfig1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mcs.c2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c7
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c135
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_struct.h57
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c7
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c32
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h1
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_main.c1
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_router.c2
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_router_hw.c4
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_rxtx.c7
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c17
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe.c19
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe.h1
-rw-r--r--drivers/net/ethernet/mediatek/mtk_star_emac.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c62
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/cmd_tracepoint.h45
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c31
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c92
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c141
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c27
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c31
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c27
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c100
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c88
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c2
-rw-r--r--drivers/net/ethernet/microchip/encx24j600-regmap.c4
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c3
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c3
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c2
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.c6
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c14
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_packet.c41
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_tc.c7
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma.h9
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c16
-rw-r--r--drivers/net/ethernet/neterion/s2io.c29
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfdk/dp.c6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_devlink.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c9
-rw-r--r--drivers/net/ethernet/ni/nixge.c30
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c6
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_main.c8
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.c24
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c4
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c3
-rw-r--r--drivers/net/ethernet/sfc/ef100_netdev.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c8
-rw-r--r--drivers/net/ethernet/sunplus/spl2sw_driver.c1
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c6
-rw-r--r--drivers/net/ethernet/ti/cpsw.c2
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c5
-rw-r--r--drivers/net/fjes/fjes_main.c4
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/ieee802154/ca8210.c2
-rw-r--r--drivers/net/ieee802154/cc2520.c2
-rw-r--r--drivers/net/ipvlan/ipvlan.h1
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c2
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/macsec.c52
-rw-r--r--drivers/net/macvlan.c8
-rw-r--r--drivers/net/mctp/mctp-i2c.c47
-rw-r--r--drivers/net/mdio/fwnode_mdio.c6
-rw-r--r--drivers/net/mdio/of_mdio.c3
-rw-r--r--drivers/net/mhi_net.c2
-rw-r--r--drivers/net/netconsole.c21
-rw-r--r--drivers/net/netdevsim/dev.c1
-rw-r--r--drivers/net/ntb_netdev.c9
-rw-r--r--drivers/net/phy/at803x.c6
-rw-r--r--drivers/net/phy/dp83867.c7
-rw-r--r--drivers/net/phy/marvell.c16
-rw-r--r--drivers/net/phy/mdio_device.c2
-rw-r--r--drivers/net/phy/mscc/mscc_macsec.c1
-rw-r--r--drivers/net/phy/mxl-gpy.c85
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/phy/phylink.c22
-rw-r--r--drivers/net/plip/plip.c4
-rw-r--r--drivers/net/ppp/ppp_generic.c2
-rw-r--r--drivers/net/team/team_mode_random.c2
-rw-r--r--drivers/net/thunderbolt.c20
-rw-r--r--drivers/net/tun.c22
-rw-r--r--drivers/net/usb/cdc_ncm.c1
-rw-r--r--drivers/net/usb/qmi_wwan.c2
-rw-r--r--drivers/net/usb/smsc95xx.c46
-rw-r--r--drivers/net/virtio_net.c3
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c27
-rw-r--r--drivers/net/wan/lapbether.c3
-rw-r--r--drivers/net/wireguard/selftest/allowedips.c20
-rw-r--r--drivers/net/wireguard/timers.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/reg.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c2
-rw-r--r--drivers/net/wireless/cisco/airo.c18
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c2
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c5
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.c39
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.c21
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2400pci.c8
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500pci.c8
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500usb.c8
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c60
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.h8
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00usb.c6
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt61pci.c4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt73usb.c4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt73usb.h2
-rw-r--r--drivers/net/wwan/Kconfig2
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_coredump.c1
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_devlink.c1
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_imem_ops.c8
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux.c1
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux.h1
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux_codec.c26
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_pcie.c18
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_protocol.h2
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_wwan.c43
-rw-r--r--drivers/net/wwan/mhi_wwan_mbim.c1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_modem_ops.c2
-rw-r--r--drivers/net/xen-netback/common.h2
-rw-r--r--drivers/net/xen-netback/interface.c6
-rw-r--r--drivers/net/xen-netback/netback.c225
-rw-r--r--drivers/net/xen-netback/rx.c8
-rw-r--r--drivers/net/xen-netfront.c6
-rw-r--r--drivers/nfc/nfcmrvl/i2c.c4
-rw-r--r--drivers/nfc/nxp-nci/core.c8
-rw-r--r--drivers/nfc/s3fwrn5/core.c1
-rw-r--r--drivers/nfc/st-nci/se.c49
-rw-r--r--drivers/nvdimm/Kconfig12
-rw-r--r--drivers/nvdimm/dimm_devs.c9
-rw-r--r--drivers/nvdimm/region.c11
-rw-r--r--drivers/nvdimm/region_devs.c50
-rw-r--r--drivers/nvdimm/security.c43
-rw-r--r--drivers/nvme/host/apple.c30
-rw-r--r--drivers/nvme/host/auth.c258
-rw-r--r--drivers/nvme/host/core.c332
-rw-r--r--drivers/nvme/host/fc.c59
-rw-r--r--drivers/nvme/host/ioctl.c118
-rw-r--r--drivers/nvme/host/multipath.c29
-rw-r--r--drivers/nvme/host/nvme.h69
-rw-r--r--drivers/nvme/host/pci.c614
-rw-r--r--drivers/nvme/host/rdma.c42
-rw-r--r--drivers/nvme/host/tcp.c49
-rw-r--r--drivers/nvme/target/admin-cmd.c11
-rw-r--r--drivers/nvme/target/auth.c2
-rw-r--r--drivers/nvme/target/configfs.c146
-rw-r--r--drivers/nvme/target/core.c44
-rw-r--r--drivers/nvme/target/io-cmd-file.c20
-rw-r--r--drivers/nvme/target/loop.c16
-rw-r--r--drivers/nvme/target/nvmet.h6
-rw-r--r--drivers/nvme/target/tcp.c2
-rw-r--r--drivers/nvmem/brcm_nvram.c3
-rw-r--r--drivers/nvmem/lan9662-otpc.c4
-rw-r--r--drivers/nvmem/rmem.c4
-rw-r--r--drivers/nvmem/u-boot-env.c2
-rw-r--r--drivers/of/property.c4
-rw-r--r--drivers/of/unittest-data/Makefile66
-rw-r--r--drivers/of/unittest-data/overlay.dtso (renamed from drivers/of/unittest-data/overlay.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_0.dtso (renamed from drivers/of/unittest-data/overlay_0.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_1.dtso (renamed from drivers/of/unittest-data/overlay_1.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_10.dtso (renamed from drivers/of/unittest-data/overlay_10.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_11.dtso (renamed from drivers/of/unittest-data/overlay_11.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_12.dtso (renamed from drivers/of/unittest-data/overlay_12.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_13.dtso (renamed from drivers/of/unittest-data/overlay_13.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_15.dtso (renamed from drivers/of/unittest-data/overlay_15.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_16.dtso (renamed from drivers/of/unittest-data/overlay_16.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_17.dtso (renamed from drivers/of/unittest-data/overlay_17.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_18.dtso (renamed from drivers/of/unittest-data/overlay_18.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_19.dtso (renamed from drivers/of/unittest-data/overlay_19.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_2.dtso (renamed from drivers/of/unittest-data/overlay_2.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_20.dtso (renamed from drivers/of/unittest-data/overlay_20.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_3.dtso (renamed from drivers/of/unittest-data/overlay_3.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_4.dtso (renamed from drivers/of/unittest-data/overlay_4.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_5.dtso (renamed from drivers/of/unittest-data/overlay_5.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_6.dtso (renamed from drivers/of/unittest-data/overlay_6.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_7.dtso (renamed from drivers/of/unittest-data/overlay_7.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_8.dtso (renamed from drivers/of/unittest-data/overlay_8.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_9.dtso (renamed from drivers/of/unittest-data/overlay_9.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_bad_add_dup_node.dtso (renamed from drivers/of/unittest-data/overlay_bad_add_dup_node.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_bad_add_dup_prop.dtso (renamed from drivers/of/unittest-data/overlay_bad_add_dup_prop.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_bad_phandle.dtso (renamed from drivers/of/unittest-data/overlay_bad_phandle.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_bad_symbol.dtso (renamed from drivers/of/unittest-data/overlay_bad_symbol.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_base.dtso (renamed from drivers/of/unittest-data/overlay_base.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_01.dtso (renamed from drivers/of/unittest-data/overlay_gpio_01.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_02a.dtso (renamed from drivers/of/unittest-data/overlay_gpio_02a.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_02b.dtso (renamed from drivers/of/unittest-data/overlay_gpio_02b.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_03.dtso (renamed from drivers/of/unittest-data/overlay_gpio_03.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_04a.dtso (renamed from drivers/of/unittest-data/overlay_gpio_04a.dts)0
-rw-r--r--drivers/of/unittest-data/overlay_gpio_04b.dtso (renamed from drivers/of/unittest-data/overlay_gpio_04b.dts)0
-rw-r--r--drivers/of/unittest-data/testcases.dtso (renamed from drivers/of/unittest-data/testcases.dts)0
-rw-r--r--drivers/of/unittest.c48
-rw-r--r--drivers/opp/of.c228
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/pci/Kconfig7
-rw-r--r--drivers/pci/controller/Kconfig30
-rw-r--r--drivers/pci/controller/dwc/Kconfig48
-rw-r--r--drivers/pci/controller/mobiveil/Kconfig6
-rw-r--r--drivers/pci/controller/pci-hyperv.c131
-rw-r--r--drivers/pci/msi/Makefile3
-rw-r--r--drivers/pci/msi/api.c458
-rw-r--r--drivers/pci/msi/irqdomain.c369
-rw-r--r--drivers/pci/msi/msi.c1078
-rw-r--r--drivers/pci/msi/msi.h114
-rw-r--r--drivers/pci/p2pdma.c126
-rw-r--r--drivers/pci/pci-sysfs.c7
-rw-r--r--drivers/pci/pcie/aer.c8
-rw-r--r--drivers/pci/probe.c8
-rw-r--r--drivers/perf/Kconfig6
-rw-r--r--drivers/perf/Makefile2
-rw-r--r--drivers/perf/amlogic/Kconfig10
-rw-r--r--drivers/perf/amlogic/Makefile5
-rw-r--r--drivers/perf/amlogic/meson_ddr_pmu_core.c561
-rw-r--r--drivers/perf/amlogic/meson_g12_ddr_pmu.c394
-rw-r--r--drivers/perf/arm_cspmu/Kconfig13
-rw-r--r--drivers/perf/arm_cspmu/Makefile6
-rw-r--r--drivers/perf/arm_cspmu/arm_cspmu.c1303
-rw-r--r--drivers/perf/arm_cspmu/arm_cspmu.h151
-rw-r--r--drivers/perf/arm_cspmu/nvidia_cspmu.c400
-rw-r--r--drivers/perf/arm_cspmu/nvidia_cspmu.h17
-rw-r--r--drivers/perf/arm_dmc620_pmu.c8
-rw-r--r--drivers/perf/arm_dsu_pmu.c6
-rw-r--r--drivers/perf/arm_pmu.c36
-rw-r--r--drivers/perf/arm_pmu_acpi.c114
-rw-r--r--drivers/perf/arm_smmuv3_pmu.c8
-rw-r--r--drivers/perf/hisilicon/hisi_pcie_pmu.c22
-rw-r--r--drivers/perf/marvell_cn10k_tad_pmu.c6
-rw-r--r--drivers/phy/phy-core-mipi-dphy.c31
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c2
-rw-r--r--drivers/phy/ralink/phy-mt7621-pci.c3
-rw-r--r--drivers/phy/st/phy-stm32-usbphyc.c2
-rw-r--r--drivers/phy/sunplus/phy-sunplus-usb2.c4
-rw-r--r--drivers/phy/tegra/xusb.c20
-rw-r--r--drivers/pinctrl/devicetree.c2
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c27
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.c43
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.h6
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2701.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2712.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6765.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6779.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6795.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7622.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7623.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7629.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7986.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8167.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8183.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8186.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8188.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8192.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8195.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8365.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8516.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c3
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c40
-rw-r--r--drivers/pinctrl/pinctrl-single.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc8280xp.c4
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/chrome/Kconfig10
-rw-r--r--drivers/platform/chrome/Makefile1
-rw-r--r--drivers/platform/chrome/chromeos_privacy_screen.c3
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c1
-rw-r--r--drivers/platform/chrome/cros_ec_i2c.c5
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c4
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c15
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.c6
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.h7
-rw-r--r--drivers/platform/chrome/cros_ec_spi.c1
-rw-r--r--drivers/platform/chrome/cros_ec_typec.c3
-rw-r--r--drivers/platform/chrome/cros_hps_i2c.c160
-rw-r--r--drivers/platform/chrome/cros_usbpd_notify.c6
-rw-r--r--drivers/platform/chrome/wilco_ec/core.c5
-rw-r--r--drivers/platform/chrome/wilco_ec/event.c4
-rw-r--r--drivers/platform/mellanox/mlxbf-pmc.c2
-rw-r--r--drivers/platform/mellanox/mlxbf-tmfifo-regs.h10
-rw-r--r--drivers/platform/mellanox/mlxbf-tmfifo.c86
-rw-r--r--drivers/platform/mips/Kconfig1
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.c24
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c37
-rw-r--r--drivers/platform/surface/surfacepro3_button.c3
-rw-r--r--drivers/platform/x86/Kconfig43
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wmi.c9
-rw-r--r--drivers/platform/x86/amd/pmc.c9
-rw-r--r--drivers/platform/x86/amd/pmf/cnqf.c92
-rw-r--r--drivers/platform/x86/asus-laptop.c3
-rw-r--r--drivers/platform/x86/asus-wireless.c3
-rw-r--r--drivers/platform/x86/asus-wmi.c6
-rw-r--r--drivers/platform/x86/classmate-laptop.c20
-rw-r--r--drivers/platform/x86/dell/Kconfig13
-rw-r--r--drivers/platform/x86/dell/Makefile1
-rw-r--r--drivers/platform/x86/dell/alienware-wmi.c41
-rw-r--r--drivers/platform/x86/dell/dell-rbtn.c6
-rw-r--r--drivers/platform/x86/dell/dell-wmi-ddv.c375
-rw-r--r--drivers/platform/x86/eeepc-laptop.c3
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c4
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c3
-rw-r--r--drivers/platform/x86/hp/Kconfig63
-rw-r--r--drivers/platform/x86/hp/Makefile10
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c (renamed from drivers/platform/x86/hp-wmi.c)15
-rw-r--r--drivers/platform/x86/hp/hp_accel.c (renamed from drivers/platform/x86/hp_accel.c)2
-rw-r--r--drivers/platform/x86/hp/tc1100-wmi.c (renamed from drivers/platform/x86/tc1100-wmi.c)0
-rw-r--r--drivers/platform/x86/huawei-wmi.c51
-rw-r--r--drivers/platform/x86/ideapad-laptop.c408
-rw-r--r--drivers/platform/x86/intel/Kconfig8
-rw-r--r--drivers/platform/x86/intel/hid.c39
-rw-r--r--drivers/platform/x86/intel/pmc/Makefile3
-rw-r--r--drivers/platform/x86/intel/pmc/adl.c325
-rw-r--r--drivers/platform/x86/intel/pmc/cnp.c210
-rw-r--r--drivers/platform/x86/intel/pmc/core.c994
-rw-r--r--drivers/platform/x86/intel/pmc/core.h91
-rw-r--r--drivers/platform/x86/intel/pmc/icl.c56
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c52
-rw-r--r--drivers/platform/x86/intel/pmc/pltdrv.c9
-rw-r--r--drivers/platform/x86/intel/pmc/spt.c140
-rw-r--r--drivers/platform/x86/intel/pmc/tgl.c269
-rw-r--r--drivers/platform/x86/intel/pmt/class.c31
-rw-r--r--drivers/platform/x86/intel/rst.c4
-rw-r--r--drivers/platform/x86/intel/sdsi.c136
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_if_common.c2
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c1
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c2
-rw-r--r--drivers/platform/x86/lg-laptop.c8
-rw-r--r--drivers/platform/x86/mxm-wmi.c8
-rw-r--r--drivers/platform/x86/p2sb.c15
-rw-r--r--drivers/platform/x86/panasonic-laptop.c8
-rw-r--r--drivers/platform/x86/sony-laptop.c19
-rw-r--r--drivers/platform/x86/system76_acpi.c8
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c71
-rw-r--r--drivers/platform/x86/topstar-laptop.c3
-rw-r--r--drivers/platform/x86/toshiba_acpi.c8
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c6
-rw-r--r--drivers/platform/x86/toshiba_haps.c4
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c25
-rw-r--r--drivers/platform/x86/uv_sysfs.c16
-rw-r--r--drivers/platform/x86/wireless-hotkey.c63
-rw-r--r--drivers/platform/x86/wmi.c1
-rw-r--r--drivers/platform/x86/x86-android-tablets.c285
-rw-r--r--drivers/platform/x86/xo15-ebook.c3
-rw-r--r--drivers/pnp/core.c4
-rw-r--r--drivers/pnp/driver.c3
-rw-r--r--drivers/power/supply/ab8500_btemp.c9
-rw-r--r--drivers/power/supply/ip5xxx_power.c2
-rw-r--r--drivers/power/supply/rk817_charger.c14
-rw-r--r--drivers/powercap/Kconfig13
-rw-r--r--drivers/powercap/Makefile1
-rw-r--r--drivers/powercap/arm_scmi_powercap.c509
-rw-r--r--drivers/powercap/idle_inject.c3
-rw-r--r--drivers/powercap/powercap_sys.c3
-rw-r--r--drivers/ptp/ptp_vmw.c3
-rw-r--r--drivers/rapidio/devices/rio_mport_cdev.c15
-rw-r--r--drivers/rapidio/devices/tsi721.c3
-rw-r--r--drivers/rapidio/rio-scan.c8
-rw-r--r--drivers/rapidio/rio.c9
-rw-r--r--drivers/ras/debugfs.c2
-rw-r--r--drivers/regulator/core.c8
-rw-r--r--drivers/regulator/rt5759-regulator.c1
-rw-r--r--drivers/regulator/slg51000-regulator.c2
-rw-r--r--drivers/regulator/twl6030-regulator.c17
-rw-r--r--drivers/s390/block/dasd_devmap.c2
-rw-r--r--drivers/s390/block/dasd_eckd.c43
-rw-r--r--drivers/s390/block/dasd_ioctl.c2
-rw-r--r--drivers/s390/block/dcssblk.c1
-rw-r--r--drivers/s390/char/con3215.c275
-rw-r--r--drivers/s390/char/raw3270.c12
-rw-r--r--drivers/s390/char/sclp.c25
-rw-r--r--drivers/s390/char/sclp.h2
-rw-r--r--drivers/s390/char/sclp_early.c4
-rw-r--r--drivers/s390/char/sclp_early_core.c26
-rw-r--r--drivers/s390/char/zcore.c6
-rw-r--r--drivers/s390/cio/chsc_sch.c3
-rw-r--r--drivers/s390/cio/cio.c14
-rw-r--r--drivers/s390/cio/device.c2
-rw-r--r--drivers/s390/cio/device_fsm.c13
-rw-r--r--drivers/s390/cio/device_id.c2
-rw-r--r--drivers/s390/cio/device_pgid.c11
-rw-r--r--drivers/s390/cio/device_status.c3
-rw-r--r--drivers/s390/cio/eadm_sch.c9
-rw-r--r--drivers/s390/cio/fcx.c23
-rw-r--r--drivers/s390/cio/itcw.c3
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c4
-rw-r--r--drivers/s390/cio/vfio_ccw_fsm.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c5
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c21
-rw-r--r--drivers/s390/net/ism_drv.c3
-rw-r--r--drivers/s390/net/qeth_l2_main.c2
-rw-r--r--drivers/s390/scsi/zfcp_fc.c2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/sbus/char/envctrl.c4
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c4
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c14
-rw-r--r--drivers/scsi/libsas/sas_ata.c2
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c3
-rw-r--r--drivers/scsi/qedi/qedi_main.c2
-rw-r--r--drivers/scsi/scsi_debug.c19
-rw-r--r--drivers/scsi/scsi_error.c2
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_scan.c1
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c31
-rw-r--r--drivers/scsi/scsi_transport_sas.c13
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/storvsc_drv.c69
-rw-r--r--drivers/siox/siox-core.c2
-rw-r--r--drivers/slimbus/Kconfig2
-rw-r--r--drivers/slimbus/stream.c8
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/apple/rtkit.c7
-rw-r--r--drivers/soc/apple/sart.c7
-rw-r--r--drivers/soc/fsl/dpio/dpio-driver.c1
-rw-r--r--drivers/soc/fsl/qe/gpio.c77
-rw-r--r--drivers/soc/imx/gpcv2.c3
-rw-r--r--drivers/soc/imx/imx8m-blk-ctrl.c11
-rw-r--r--drivers/soc/imx/soc-imx8m.c11
-rw-r--r--drivers/soc/loongson/Kconfig18
-rw-r--r--drivers/soc/loongson/Makefile6
-rw-r--r--drivers/soc/loongson/loongson2_guts.c192
-rw-r--r--drivers/soc/mediatek/mt8186-mmsys.h8
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c176
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.h6
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c114
-rw-r--r--drivers/soc/pxa/ssp.c4
-rw-r--r--drivers/soc/qcom/Kconfig2
-rw-r--r--drivers/soc/qcom/apr.c15
-rw-r--r--drivers/soc/qcom/cmd-db.c2
-rw-r--r--drivers/soc/qcom/llcc-qcom.c168
-rw-r--r--drivers/soc/qcom/pdr_internal.h20
-rw-r--r--drivers/soc/qcom/qcom_stats.c2
-rw-r--r--drivers/soc/qcom/rpmh-internal.h20
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c321
-rw-r--r--drivers/soc/qcom/rpmh.c14
-rw-r--r--drivers/soc/qcom/rpmhpd.c95
-rw-r--r--drivers/soc/qcom/rpmpd.c18
-rw-r--r--drivers/soc/qcom/smd-rpm.c3
-rw-r--r--drivers/soc/qcom/smp2p.c2
-rw-r--r--drivers/soc/qcom/socinfo.c280
-rw-r--r--drivers/soc/qcom/spm.c46
-rw-r--r--drivers/soc/qcom/trace-rpmh.h11
-rw-r--r--drivers/soc/renesas/Kconfig2
-rw-r--r--drivers/soc/renesas/renesas-soc.c22
-rw-r--r--drivers/soc/sifive/sifive_ccache.c33
-rw-r--r--drivers/soc/tegra/Kconfig1
-rw-r--r--drivers/soc/tegra/cbb/tegra-cbb.c13
-rw-r--r--drivers/soc/tegra/cbb/tegra194-cbb.c18
-rw-r--r--drivers/soc/tegra/cbb/tegra234-cbb.c170
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c134
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c278
-rw-r--r--drivers/soc/tegra/fuse/fuse.h4
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c1
-rw-r--r--drivers/soc/tegra/pmc.c878
-rw-r--r--drivers/soc/ti/Kconfig4
-rw-r--r--drivers/soc/ti/k3-ringacc.c28
-rw-r--r--drivers/soc/ti/k3-socinfo.c1
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c3
-rw-r--r--drivers/soc/ti/smartreflex.c1
-rw-r--r--drivers/soc/ti/ti_sci_inta_msi.c12
-rw-r--r--drivers/soc/ux500/ux500-soc-id.c10
-rw-r--r--drivers/soundwire/intel.c1
-rw-r--r--drivers/soundwire/intel_init.c37
-rw-r--r--drivers/soundwire/qcom.c9
-rw-r--r--drivers/spi/spi-amd.c2
-rw-r--r--drivers/spi/spi-dw-dma.c3
-rw-r--r--drivers/spi/spi-imx.c13
-rw-r--r--drivers/spi/spi-intel.c8
-rw-r--r--drivers/spi/spi-meson-spicc.c24
-rw-r--r--drivers/spi/spi-mt65xx.c31
-rw-r--r--drivers/spi/spi-stm32.c3
-rw-r--r--drivers/spi/spi-tegra210-quad.c9
-rw-r--r--drivers/staging/media/Kconfig1
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c14
-rw-r--r--drivers/staging/media/atomisp/i2c/gc0310.h1
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h46
-rw-r--r--drivers/staging/media/atomisp/include/hmm/hmm.h3
-rw-r--r--drivers/staging/media/atomisp/include/hmm/hmm_bo.h4
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c442
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.h17
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_common.h6
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_compat.h14
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_compat_css20.c96
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.c535
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.h13
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_internal.h1
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.c615
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.h10
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_v4l2.c104
-rw-r--r--drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h13
-rw-r--r--drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h5
-rw-r--r--drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c55
-rw-r--r--drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c21
-rw-r--r--drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h2
-rw-r--r--drivers/staging/media/atomisp/pci/hive_types.h2
-rw-r--r--drivers/staging/media/atomisp/pci/hmm/hmm.c20
-rw-r--r--drivers/staging/media/atomisp/pci/hmm/hmm_bo.c64
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_frame_public.h108
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_pipe.h3
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_pipe_public.h69
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c10
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c10
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c2
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c4
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c42
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c33
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c203
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h2
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c8
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c646
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_internal.h13
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_legacy.h1
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_param_shading.c19
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_params.c17
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_sp.c54
-rw-r--r--drivers/staging/media/deprecated/atmel/Kconfig47
-rw-r--r--drivers/staging/media/deprecated/atmel/Makefile8
-rw-r--r--drivers/staging/media/deprecated/atmel/TODO34
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-isc-base.c (renamed from drivers/media/platform/atmel/atmel-isc-base.c)20
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-isc-clk.c (renamed from drivers/media/platform/atmel/atmel-isc-clk.c)8
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-isc-regs.h (renamed from drivers/media/platform/atmel/atmel-isc-regs.h)0
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-isc.h (renamed from drivers/media/platform/atmel/atmel-isc.h)16
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c (renamed from drivers/media/platform/atmel/atmel-sama5d2-isc.c)18
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c (renamed from drivers/media/platform/atmel/atmel-sama7g5-isc.c)18
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/Kconfig2
-rw-r--r--drivers/staging/media/imx/Kconfig17
-rw-r--r--drivers/staging/media/imx/Makefile3
-rw-r--r--drivers/staging/media/imx/TODO41
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c135
-rw-r--r--drivers/staging/media/imx/imx-media-fim.c57
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c33
-rw-r--r--drivers/staging/media/imx/imx-media.h1
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c57
-rw-r--r--drivers/staging/media/meson/vdec/codec_vp9.c10
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c2
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h18
-rw-r--r--drivers/staging/media/rkvdec/rkvdec-vp9.c3
-rw-r--r--drivers/staging/media/sunxi/Kconfig1
-rw-r--r--drivers/staging/media/sunxi/Makefile1
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c112
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h38
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c4
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h264.c120
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h265.c125
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c18
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_regs.h18
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c184
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_vp8.c2
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/Kconfig15
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/Makefile4
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/TODO.txt6
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c555
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.h90
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c742
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.h78
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c566
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.h52
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c577
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h66
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_reg.h275
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h43
-rw-r--r--drivers/staging/media/tegra-video/csi.c4
-rw-r--r--drivers/staging/media/tegra-video/csi.h2
-rw-r--r--drivers/staging/media/tegra-video/vi.c2
-rw-r--r--drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dtso (renamed from drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts)0
-rw-r--r--drivers/staging/pi433/Documentation/devicetree/pi433.txt6
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c9
-rw-r--r--drivers/staging/sm750fb/Kconfig1
-rw-r--r--drivers/staging/sm750fb/sm750.c3
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c4
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c4
-rw-r--r--drivers/target/loopback/tcm_loop.c3
-rw-r--r--drivers/target/target_core_file.c4
-rw-r--r--drivers/tee/optee/core.c4
-rw-r--r--drivers/tee/optee/device.c2
-rw-r--r--drivers/thermal/gov_fair_share.c6
-rw-r--r--drivers/thermal/intel/intel_hfi.c34
-rw-r--r--drivers/thermal/intel/intel_menlow.c8
-rw-r--r--drivers/thermal/intel/intel_tcc_cooling.c11
-rw-r--r--drivers/thermal/intel/therm_throt.c25
-rw-r--r--drivers/thermal/intel/thermal_interrupt.h6
-rw-r--r--drivers/thermal/intel/x86_pkg_temp_thermal.c9
-rw-r--r--drivers/thermal/tegra/tegra-bpmp-thermal.c15
-rw-r--r--drivers/thermal/thermal_core.c110
-rw-r--r--drivers/thermal/thermal_core.h3
-rw-r--r--drivers/thermal/thermal_helpers.c67
-rw-r--r--drivers/thermal/thermal_hwmon.c10
-rw-r--r--drivers/thermal/thermal_sysfs.c116
-rw-r--r--drivers/tty/hvc/hvc_console.c4
-rw-r--r--drivers/tty/n_gsm.c71
-rw-r--r--drivers/tty/serial/8250/8250_core.c2
-rw-r--r--drivers/tty/serial/8250/8250_lpss.c17
-rw-r--r--drivers/tty/serial/8250/8250_omap.c52
-rw-r--r--drivers/tty/serial/8250/8250_port.c7
-rw-r--r--drivers/tty/serial/earlycon.c4
-rw-r--r--drivers/tty/serial/fsl_lpuart.c76
-rw-r--r--drivers/tty/serial/imx.c1
-rw-r--r--drivers/tty/serial/kgdboc.c46
-rw-r--r--drivers/tty/serial/pic32_uart.c4
-rw-r--r--drivers/tty/serial/samsung_tty.c2
-rw-r--r--drivers/tty/serial/serial_core.c14
-rw-r--r--drivers/tty/serial/sh-sci.c20
-rw-r--r--drivers/tty/serial/xilinx_uartps.c2
-rw-r--r--drivers/tty/tty_io.c18
-rw-r--r--drivers/ufs/core/ufshcd.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.c12
-rw-r--r--drivers/usb/cdns3/cdnsp-ring.c17
-rw-r--r--drivers/usb/cdns3/host.c56
-rw-r--r--drivers/usb/chipidea/otg_fsm.c2
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--drivers/usb/dwc3/core.c10
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c11
-rw-r--r--drivers/usb/dwc3/gadget.c17
-rw-r--r--drivers/usb/dwc3/host.c10
-rw-r--r--drivers/usb/early/xhci-dbc.c2
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c72
-rw-r--r--drivers/usb/host/bcma-hcd.c10
-rw-r--r--drivers/usb/host/fhci-hcd.c2
-rw-r--r--drivers/usb/serial/option.c19
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c15
-rw-r--r--drivers/usb/typec/tipd/core.c6
-rw-r--r--drivers/usb/usbip/usbip_common.c2
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c1
-rw-r--r--drivers/vfio/pci/vfio_pci_core.c10
-rw-r--r--drivers/vfio/vfio_main.c26
-rw-r--r--drivers/vhost/net.c6
-rw-r--r--drivers/vhost/scsi.c10
-rw-r--r--drivers/vhost/vhost.c6
-rw-r--r--drivers/vhost/vringh.c4
-rw-r--r--drivers/vhost/vsock.c4
-rw-r--r--drivers/video/Kconfig4
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/backlight/apple_bl.c3
-rw-r--r--drivers/video/fbdev/Kconfig38
-rw-r--r--drivers/video/fbdev/arkfb.c5
-rw-r--r--drivers/video/fbdev/asiliantfb.c3
-rw-r--r--drivers/video/fbdev/aty/aty128fb.c5
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c5
-rw-r--r--drivers/video/fbdev/aty/radeon_base.c5
-rw-r--r--drivers/video/fbdev/carminefb.c3
-rw-r--r--drivers/video/fbdev/chipsfb.c3
-rw-r--r--drivers/video/fbdev/cirrusfb.c5
-rw-r--r--drivers/video/fbdev/core/fbcon.c2
-rw-r--r--drivers/video/fbdev/core/fbmem.c15
-rw-r--r--drivers/video/fbdev/cyber2000fb.c6
-rw-r--r--drivers/video/fbdev/geode/Kconfig3
-rw-r--r--drivers/video/fbdev/geode/gx1fb_core.c5
-rw-r--r--drivers/video/fbdev/geode/gxfb_core.c5
-rw-r--r--drivers/video/fbdev/geode/lxfb_core.c5
-rw-r--r--drivers/video/fbdev/gxt4500.c3
-rw-r--r--drivers/video/fbdev/hyperv_fb.c20
-rw-r--r--drivers/video/fbdev/i740fb.c5
-rw-r--r--drivers/video/fbdev/i810/i810_main.c6
-rw-r--r--drivers/video/fbdev/imsttfb.c5
-rw-r--r--drivers/video/fbdev/intelfb/intelfbdrv.c3
-rw-r--r--drivers/video/fbdev/kyro/fbdev.c5
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.c3
-rw-r--r--drivers/video/fbdev/mb862xx/mb862xxfbdrv.c3
-rw-r--r--drivers/video/fbdev/neofb.c5
-rw-r--r--drivers/video/fbdev/nvidia/nvidia.c5
-rw-r--r--drivers/video/fbdev/pm2fb.c5
-rw-r--r--drivers/video/fbdev/pm3fb.c5
-rw-r--r--drivers/video/fbdev/pvr2fb.c5
-rw-r--r--drivers/video/fbdev/riva/fbdev.c5
-rw-r--r--drivers/video/fbdev/s3fb.c5
-rw-r--r--drivers/video/fbdev/savage/savagefb_driver.c3
-rw-r--r--drivers/video/fbdev/sis/sis_main.c5
-rw-r--r--drivers/video/fbdev/skeletonfb.c5
-rw-r--r--drivers/video/fbdev/sm712fb.c3
-rw-r--r--drivers/video/fbdev/sstfb.c3
-rw-r--r--drivers/video/fbdev/sunxvr2500.c3
-rw-r--r--drivers/video/fbdev/sunxvr500.c3
-rw-r--r--drivers/video/fbdev/tdfxfb.c5
-rw-r--r--drivers/video/fbdev/tgafb.c5
-rw-r--r--drivers/video/fbdev/tridentfb.c5
-rw-r--r--drivers/video/fbdev/vermilion/vermilion.c5
-rw-r--r--drivers/video/fbdev/via/via-core.c3
-rw-r--r--drivers/video/fbdev/vt8623fb.c5
-rw-r--r--drivers/video/fbdev/xen-fbfront.c12
-rw-r--r--drivers/video/nomodeset.c (renamed from drivers/gpu/drm/drm_nomodeset.c)12
-rw-r--r--drivers/virt/Kconfig2
-rw-r--r--drivers/virt/Makefile1
-rw-r--r--drivers/virt/coco/sev-guest/sev-guest.c84
-rw-r--r--drivers/virt/coco/tdx-guest/Kconfig10
-rw-r--r--drivers/virt/coco/tdx-guest/Makefile2
-rw-r--r--drivers/virt/coco/tdx-guest/tdx-guest.c102
-rw-r--r--drivers/watchdog/ni903x_wdt.c4
-rw-r--r--drivers/xen/gntdev-dmabuf.c8
-rw-r--r--drivers/xen/grant-dma-ops.c105
-rw-r--r--drivers/xen/pcpu.c2
-rw-r--r--drivers/xen/platform-pci.c10
-rw-r--r--drivers/xen/privcmd.c2
-rw-r--r--drivers/xen/pvcalls-back.c8
-rw-r--r--drivers/xen/xen-acpi-pad.c3
-rw-r--r--drivers/xen/xen-pciback/conf_space_capability.c9
-rw-r--r--fs/9p/acl.c295
-rw-r--r--fs/9p/acl.h8
-rw-r--r--fs/9p/vfs_addr.c4
-rw-r--r--fs/9p/vfs_dir.c2
-rw-r--r--fs/9p/vfs_inode_dotl.c4
-rw-r--r--fs/9p/xattr.c11
-rw-r--r--fs/9p/xattr.h2
-rw-r--r--fs/afs/cmservice.c2
-rw-r--r--fs/afs/dir.c2
-rw-r--r--fs/afs/file.c4
-rw-r--r--fs/afs/fs_probe.c4
-rw-r--r--fs/afs/internal.h4
-rw-r--r--fs/afs/rxrpc.c10
-rw-r--r--fs/afs/server.c2
-rw-r--r--fs/afs/write.c4
-rw-r--r--fs/aio.c4
-rw-r--r--fs/attr.c74
-rw-r--r--fs/bad_inode.c4
-rw-r--r--fs/binfmt_elf.c299
-rw-r--r--fs/binfmt_elf_fdpic.c7
-rw-r--r--fs/binfmt_misc.c8
-rw-r--r--fs/btrfs/Makefile6
-rw-r--r--fs/btrfs/accessors.c (renamed from fs/btrfs/struct-funcs.c)12
-rw-r--r--fs/btrfs/accessors.h1073
-rw-r--r--fs/btrfs/acl.c5
-rw-r--r--fs/btrfs/acl.h27
-rw-r--r--fs/btrfs/backref.c1001
-rw-r--r--fs/btrfs/backref.h195
-rw-r--r--fs/btrfs/bio.c381
-rw-r--r--fs/btrfs/bio.h127
-rw-r--r--fs/btrfs/block-group.c152
-rw-r--r--fs/btrfs/block-group.h30
-rw-r--r--fs/btrfs/block-rsv.c43
-rw-r--r--fs/btrfs/block-rsv.h6
-rw-r--r--fs/btrfs/btrfs_inode.h161
-rw-r--r--fs/btrfs/check-integrity.c4
-rw-r--r--fs/btrfs/compression.c32
-rw-r--r--fs/btrfs/compression.h11
-rw-r--r--fs/btrfs/ctree.c363
-rw-r--r--fs/btrfs/ctree.h3462
-rw-r--r--fs/btrfs/defrag.c1376
-rw-r--r--fs/btrfs/defrag.h22
-rw-r--r--fs/btrfs/delalloc-space.c61
-rw-r--r--fs/btrfs/delalloc-space.h3
-rw-r--r--fs/btrfs/delayed-inode.c17
-rw-r--r--fs/btrfs/delayed-inode.h2
-rw-r--r--fs/btrfs/delayed-ref.c21
-rw-r--r--fs/btrfs/dev-replace.c28
-rw-r--r--fs/btrfs/dev-replace.h8
-rw-r--r--fs/btrfs/dir-item.c60
-rw-r--r--fs/btrfs/dir-item.h42
-rw-r--r--fs/btrfs/discard.c112
-rw-r--r--fs/btrfs/disk-io.c251
-rw-r--r--fs/btrfs/disk-io.h35
-rw-r--r--fs/btrfs/export.c25
-rw-r--r--fs/btrfs/export.h3
-rw-r--r--fs/btrfs/extent-io-tree.c192
-rw-r--r--fs/btrfs/extent-io-tree.h100
-rw-r--r--fs/btrfs/extent-tree.c55
-rw-r--r--fs/btrfs/extent-tree.h78
-rw-r--r--fs/btrfs/extent_io.c482
-rw-r--r--fs/btrfs/extent_io.h67
-rw-r--r--fs/btrfs/extent_map.c75
-rw-r--r--fs/btrfs/file-item.c258
-rw-r--r--fs/btrfs/file-item.h69
-rw-r--r--fs/btrfs/file.c621
-rw-r--r--fs/btrfs/file.h33
-rw-r--r--fs/btrfs/free-space-cache.c52
-rw-r--r--fs/btrfs/free-space-cache.h13
-rw-r--r--fs/btrfs/free-space-tree.c15
-rw-r--r--fs/btrfs/fs.c94
-rw-r--r--fs/btrfs/fs.h976
-rw-r--r--fs/btrfs/inode-item.c79
-rw-r--r--fs/btrfs/inode-item.h20
-rw-r--r--fs/btrfs/inode.c912
-rw-r--r--fs/btrfs/ioctl.c972
-rw-r--r--fs/btrfs/ioctl.h17
-rw-r--r--fs/btrfs/locking.c1
-rw-r--r--fs/btrfs/locking.h76
-rw-r--r--fs/btrfs/lzo.c4
-rw-r--r--fs/btrfs/messages.c353
-rw-r--r--fs/btrfs/messages.h245
-rw-r--r--fs/btrfs/misc.h24
-rw-r--r--fs/btrfs/ordered-data.c31
-rw-r--r--fs/btrfs/ordered-data.h3
-rw-r--r--fs/btrfs/orphan.c1
-rw-r--r--fs/btrfs/orphan.h11
-rw-r--r--fs/btrfs/print-tree.c21
-rw-r--r--fs/btrfs/props.c8
-rw-r--r--fs/btrfs/props.h2
-rw-r--r--fs/btrfs/qgroup.c87
-rw-r--r--fs/btrfs/qgroup.h11
-rw-r--r--fs/btrfs/raid56.c2052
-rw-r--r--fs/btrfs/raid56.h33
-rw-r--r--fs/btrfs/rcu-string.h6
-rw-r--r--fs/btrfs/ref-verify.c3
-rw-r--r--fs/btrfs/reflink.c30
-rw-r--r--fs/btrfs/relocation.c94
-rw-r--r--fs/btrfs/relocation.h23
-rw-r--r--fs/btrfs/root-tree.c24
-rw-r--r--fs/btrfs/root-tree.h34
-rw-r--r--fs/btrfs/scrub.c84
-rw-r--r--fs/btrfs/scrub.h16
-rw-r--r--fs/btrfs/send.c512
-rw-r--r--fs/btrfs/send.h6
-rw-r--r--fs/btrfs/space-info.c86
-rw-r--r--fs/btrfs/space-info.h78
-rw-r--r--fs/btrfs/subpage.c1
-rw-r--r--fs/btrfs/super.c554
-rw-r--r--fs/btrfs/super.h29
-rw-r--r--fs/btrfs/sysfs.c23
-rw-r--r--fs/btrfs/tests/btrfs-tests.c5
-rw-r--r--fs/btrfs/tests/extent-buffer-tests.c1
-rw-r--r--fs/btrfs/tests/extent-io-tests.c4
-rw-r--r--fs/btrfs/tests/free-space-tree-tests.c3
-rw-r--r--fs/btrfs/tests/inode-tests.c58
-rw-r--r--fs/btrfs/tests/qgroup-tests.c52
-rw-r--r--fs/btrfs/transaction.c92
-rw-r--r--fs/btrfs/transaction.h22
-rw-r--r--fs/btrfs/tree-checker.c10
-rw-r--r--fs/btrfs/tree-checker.h35
-rw-r--r--fs/btrfs/tree-defrag.c132
-rw-r--r--fs/btrfs/tree-log.c511
-rw-r--r--fs/btrfs/tree-log.h5
-rw-r--r--fs/btrfs/tree-mod-log.c36
-rw-r--r--fs/btrfs/tree-mod-log.h4
-rw-r--r--fs/btrfs/ulist.c38
-rw-r--r--fs/btrfs/ulist.h2
-rw-r--r--fs/btrfs/uuid-tree.c5
-rw-r--r--fs/btrfs/uuid-tree.h12
-rw-r--r--fs/btrfs/verity.c6
-rw-r--r--fs/btrfs/verity.h28
-rw-r--r--fs/btrfs/volumes.c481
-rw-r--r--fs/btrfs/volumes.h118
-rw-r--r--fs/btrfs/xattr.c4
-rw-r--r--fs/btrfs/zlib.c6
-rw-r--r--fs/btrfs/zoned.c67
-rw-r--r--fs/btrfs/zoned.h12
-rw-r--r--fs/btrfs/zstd.c4
-rw-r--r--fs/cachefiles/io.c77
-rw-r--r--fs/ceph/acl.c3
-rw-r--r--fs/ceph/addr.c4
-rw-r--r--fs/ceph/caps.c48
-rw-r--r--fs/ceph/dir.c2
-rw-r--r--fs/ceph/file.c4
-rw-r--r--fs/ceph/inode.c8
-rw-r--r--fs/ceph/locks.c4
-rw-r--r--fs/ceph/mdsmap.c2
-rw-r--r--fs/ceph/snap.c3
-rw-r--r--fs/ceph/super.h2
-rw-r--r--fs/cifs/cifsacl.c139
-rw-r--r--fs/cifs/cifsfs.c8
-rw-r--r--fs/cifs/cifsproto.h20
-rw-r--r--fs/cifs/cifssmb.c206
-rw-r--r--fs/cifs/connect.c20
-rw-r--r--fs/cifs/file.c6
-rw-r--r--fs/cifs/fscache.c4
-rw-r--r--fs/cifs/ioctl.c4
-rw-r--r--fs/cifs/sess.c4
-rw-r--r--fs/cifs/smb2ops.c8
-rw-r--r--fs/cifs/transport.c6
-rw-r--r--fs/cifs/xattr.c68
-rw-r--r--fs/configfs/dir.c2
-rw-r--r--fs/coredump.c12
-rw-r--r--fs/crypto/fscrypt_private.h13
-rw-r--r--fs/crypto/inline_crypt.c14
-rw-r--r--fs/crypto/keyring.c14
-rw-r--r--fs/crypto/keysetup.c17
-rw-r--r--fs/crypto/policy.c12
-rw-r--r--fs/debugfs/file.c28
-rw-r--r--fs/dlm/ast.c322
-rw-r--r--fs/dlm/ast.h17
-rw-r--r--fs/dlm/config.c4
-rw-r--r--fs/dlm/debug_fs.c2
-rw-r--r--fs/dlm/dlm_internal.h25
-rw-r--r--fs/dlm/lock.c190
-rw-r--r--fs/dlm/lockspace.c14
-rw-r--r--fs/dlm/lowcomms.c1538
-rw-r--r--fs/dlm/lowcomms.h6
-rw-r--r--fs/dlm/main.c7
-rw-r--r--fs/dlm/member.c5
-rw-r--r--fs/dlm/memory.c30
-rw-r--r--fs/dlm/memory.h4
-rw-r--r--fs/dlm/midcomms.c141
-rw-r--r--fs/dlm/midcomms.h7
-rw-r--r--fs/dlm/rcom.c4
-rw-r--r--fs/dlm/requestqueue.c3
-rw-r--r--fs/dlm/user.c74
-rw-r--r--fs/dlm/user.h2
-rw-r--r--fs/ecryptfs/inode.c32
-rw-r--r--fs/erofs/data.c10
-rw-r--r--fs/erofs/fscache.c431
-rw-r--r--fs/erofs/inode.c8
-rw-r--r--fs/erofs/internal.h19
-rw-r--r--fs/erofs/namei.c2
-rw-r--r--fs/erofs/super.c41
-rw-r--r--fs/erofs/sysfs.c8
-rw-r--r--fs/erofs/xattr.c8
-rw-r--r--fs/erofs/zdata.c101
-rw-r--r--fs/erofs/zmap.c15
-rw-r--r--fs/eventfd.c37
-rw-r--r--fs/eventpoll.c18
-rw-r--r--fs/exec.c50
-rw-r--r--fs/exportfs/expfs.c8
-rw-r--r--fs/ext2/acl.c3
-rw-r--r--fs/ext2/acl.h2
-rw-r--r--fs/ext2/balloc.c12
-rw-r--r--fs/ext2/dir.c41
-rw-r--r--fs/ext2/file.c2
-rw-r--r--fs/ext2/ialloc.c2
-rw-r--r--fs/ext2/inode.c8
-rw-r--r--fs/ext2/namei.c4
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext4/acl.c3
-rw-r--r--fs/ext4/acl.h2
-rw-r--r--fs/ext4/ext4.h13
-rw-r--r--fs/ext4/ext4_jbd2.c14
-rw-r--r--fs/ext4/ext4_jbd2.h10
-rw-r--r--fs/ext4/extents.c34
-rw-r--r--fs/ext4/extents_status.c11
-rw-r--r--fs/ext4/fast_commit.c205
-rw-r--r--fs/ext4/fast_commit.h3
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/ext4/ialloc.c8
-rw-r--r--fs/ext4/indirect.c9
-rw-r--r--fs/ext4/inline.c3
-rw-r--r--fs/ext4/inode.c254
-rw-r--r--fs/ext4/ioctl.c24
-rw-r--r--fs/ext4/mballoc.c10
-rw-r--r--fs/ext4/mmp.c8
-rw-r--r--fs/ext4/namei.c51
-rw-r--r--fs/ext4/orphan.c2
-rw-r--r--fs/ext4/page-io.c44
-rw-r--r--fs/ext4/readpage.c13
-rw-r--r--fs/ext4/resize.c36
-rw-r--r--fs/ext4/super.c65
-rw-r--r--fs/ext4/verity.c2
-rw-r--r--fs/ext4/xattr.c22
-rw-r--r--fs/f2fs/acl.c4
-rw-r--r--fs/f2fs/acl.h2
-rw-r--r--fs/f2fs/compress.c64
-rw-r--r--fs/f2fs/data.c53
-rw-r--r--fs/f2fs/file.c4
-rw-r--r--fs/f2fs/gc.c2
-rw-r--r--fs/f2fs/namei.c4
-rw-r--r--fs/f2fs/segment.c8
-rw-r--r--fs/fat/nfs.c4
-rw-r--r--fs/file.c11
-rw-r--r--fs/fs-writeback.c30
-rw-r--r--fs/fs_parser.c3
-rw-r--r--fs/fscache/cookie.c8
-rw-r--r--fs/fscache/io.c2
-rw-r--r--fs/fscache/volume.c7
-rw-r--r--fs/fuse/acl.c5
-rw-r--r--fs/fuse/cuse.c5
-rw-r--r--fs/fuse/dev.c7
-rw-r--r--fs/fuse/dir.c47
-rw-r--r--fs/fuse/file.c82
-rw-r--r--fs/fuse/fuse_i.h6
-rw-r--r--fs/fuse/ioctl.c4
-rw-r--r--fs/fuse/readdir.c4
-rw-r--r--fs/gfs2/acl.c3
-rw-r--r--fs/gfs2/acl.h2
-rw-r--r--fs/gfs2/inode.c6
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hfs/trans.c2
-rw-r--r--fs/hfsplus/hfsplus_fs.h2
-rw-r--r--fs/hfsplus/inode.c4
-rw-r--r--fs/hfsplus/options.c4
-rw-r--r--fs/hugetlbfs/inode.c13
-rw-r--r--fs/inode.c75
-rw-r--r--fs/internal.h35
-rw-r--r--fs/iomap/direct-io.c3
-rw-r--r--fs/jbd2/commit.c5
-rw-r--r--fs/jffs2/acl.c3
-rw-r--r--fs/jffs2/acl.h2
-rw-r--r--fs/jffs2/dir.c2
-rw-r--r--fs/jffs2/file.c2
-rw-r--r--fs/jffs2/fs.c2
-rw-r--r--fs/jfs/acl.c3
-rw-r--r--fs/jfs/file.c4
-rw-r--r--fs/jfs/jfs_acl.h2
-rw-r--r--fs/jfs/jfs_dmap.c27
-rw-r--r--fs/jfs/jfs_extent.h2
-rw-r--r--fs/jfs/jfs_imap.c2
-rw-r--r--fs/jfs/jfs_mount.c4
-rw-r--r--fs/jfs/jfs_umount.c4
-rw-r--r--fs/jfs/jfs_xattr.h2
-rw-r--r--fs/jfs/jfs_xtree.h4
-rw-r--r--fs/jfs/namei.c4
-rw-r--r--fs/jfs/super.c6
-rw-r--r--fs/kernfs/dir.c14
-rw-r--r--fs/ksmbd/smb2pdu.c8
-rw-r--r--fs/ksmbd/smbacl.c6
-rw-r--r--fs/ksmbd/vfs.c29
-rw-r--r--fs/ksmbd/vfs.h4
-rw-r--r--fs/libfs.c22
-rw-r--r--fs/lockd/svc4proc.c1
-rw-r--r--fs/lockd/svclock.c17
-rw-r--r--fs/lockd/svcproc.c1
-rw-r--r--fs/lockd/svcsubs.c21
-rw-r--r--fs/locks.c50
-rw-r--r--fs/mbcache.c14
-rw-r--r--fs/namei.c49
-rw-r--r--fs/namespace.c179
-rw-r--r--fs/netfs/buffered_read.c20
-rw-r--r--fs/netfs/io.c9
-rw-r--r--fs/nfs/Kconfig8
-rw-r--r--fs/nfs/delegation.c2
-rw-r--r--fs/nfs/dir.c32
-rw-r--r--fs/nfs/fs_context.c6
-rw-r--r--fs/nfs/fscache.c4
-rw-r--r--fs/nfs/inode.c3
-rw-r--r--fs/nfs/internal.h6
-rw-r--r--fs/nfs/namespace.c4
-rw-r--r--fs/nfs/nfs3_fs.h2
-rw-r--r--fs/nfs/nfs3acl.c9
-rw-r--r--fs/nfs/nfs3proc.c4
-rw-r--r--fs/nfs/nfs42xdr.c9
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4file.c12
-rw-r--r--fs/nfs/nfs4proc.c57
-rw-r--r--fs/nfs/nfs4state.c7
-rw-r--r--fs/nfs/nfs4trace.h10
-rw-r--r--fs/nfs/nfs4xdr.c22
-rw-r--r--fs/nfs/nfstrace.h6
-rw-r--r--fs/nfs/pagelist.c2
-rw-r--r--fs/nfs/sysfs.c2
-rw-r--r--fs/nfs/unlink.c1
-rw-r--r--fs/nfs/write.c4
-rw-r--r--fs/nfsd/Kconfig19
-rw-r--r--fs/nfsd/Makefile5
-rw-r--r--fs/nfsd/blocklayout.c1
-rw-r--r--fs/nfsd/blocklayoutxdr.c1
-rw-r--r--fs/nfsd/export.h1
-rw-r--r--fs/nfsd/filecache.c242
-rw-r--r--fs/nfsd/filecache.h4
-rw-r--r--fs/nfsd/flexfilelayout.c1
-rw-r--r--fs/nfsd/nfs2acl.c18
-rw-r--r--fs/nfsd/nfs3acl.c38
-rw-r--r--fs/nfsd/nfs3proc.c10
-rw-r--r--fs/nfsd/nfs4acl.c4
-rw-r--r--fs/nfsd/nfs4callback.c72
-rw-r--r--fs/nfsd/nfs4idmap.c1
-rw-r--r--fs/nfsd/nfs4proc.c49
-rw-r--r--fs/nfsd/nfs4state.c348
-rw-r--r--fs/nfsd/nfs4xdr.c771
-rw-r--r--fs/nfsd/nfsctl.c6
-rw-r--r--fs/nfsd/nfsd.h3
-rw-r--r--fs/nfsd/nfsfh.h10
-rw-r--r--fs/nfsd/nfsproc.c66
-rw-r--r--fs/nfsd/nfssvc.c8
-rw-r--r--fs/nfsd/state.h11
-rw-r--r--fs/nfsd/trace.h149
-rw-r--r--fs/nfsd/vfs.c102
-rw-r--r--fs/nfsd/vfs.h4
-rw-r--r--fs/nfsd/xdr4.h5
-rw-r--r--fs/nfsd/xdr4cb.h6
-rw-r--r--fs/nilfs2/dat.c7
-rw-r--r--fs/nilfs2/segment.c15
-rw-r--r--fs/nilfs2/sufile.c8
-rw-r--r--fs/nilfs2/super.c2
-rw-r--r--fs/nilfs2/the_nilfs.c75
-rw-r--r--fs/ntfs3/file.c4
-rw-r--r--fs/ntfs3/namei.c4
-rw-r--r--fs/ntfs3/ntfs_fs.h4
-rw-r--r--fs/ntfs3/xattr.c9
-rw-r--r--fs/ocfs2/acl.c3
-rw-r--r--fs/ocfs2/acl.h2
-rw-r--r--fs/ocfs2/cluster/heartbeat.c38
-rw-r--r--fs/ocfs2/cluster/heartbeat.h2
-rw-r--r--fs/ocfs2/cluster/netdebug.c2
-rw-r--r--fs/ocfs2/cluster/nodemanager.c2
-rw-r--r--fs/ocfs2/cluster/tcp.c8
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h2
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c19
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c30
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c2
-rw-r--r--fs/ocfs2/file.c8
-rw-r--r--fs/ocfs2/journal.c2
-rw-r--r--fs/ocfs2/journal.h1
-rw-r--r--fs/ocfs2/namei.c2
-rw-r--r--fs/ocfs2/ocfs2.h3
-rw-r--r--fs/ocfs2/stack_o2cb.c6
-rw-r--r--fs/ocfs2/stackglue.c8
-rw-r--r--fs/ocfs2/super.c5
-rw-r--r--fs/open.c10
-rw-r--r--fs/orangefs/acl.c47
-rw-r--r--fs/orangefs/inode.c62
-rw-r--r--fs/orangefs/namei.c2
-rw-r--r--fs/orangefs/orangefs-kernel.h7
-rw-r--r--fs/overlayfs/Kconfig2
-rw-r--r--fs/overlayfs/copy_up.c38
-rw-r--r--fs/overlayfs/dir.c68
-rw-r--r--fs/overlayfs/export.c8
-rw-r--r--fs/overlayfs/file.c31
-rw-r--r--fs/overlayfs/inode.c187
-rw-r--r--fs/overlayfs/namei.c12
-rw-r--r--fs/overlayfs/overlayfs.h53
-rw-r--r--fs/overlayfs/readdir.c58
-rw-r--r--fs/overlayfs/super.c114
-rw-r--r--fs/overlayfs/util.c15
-rw-r--r--fs/posix_acl.c727
-rw-r--r--fs/proc/cmdline.c6
-rw-r--r--fs/proc/consoles.c21
-rw-r--r--fs/proc/fd.c45
-rw-r--r--fs/proc/meminfo.c2
-rw-r--r--fs/proc/vmcore.c7
-rw-r--r--fs/pstore/platform.c25
-rw-r--r--fs/pstore/ram.c44
-rw-r--r--fs/pstore/ram_core.c20
-rw-r--r--fs/pstore/ram_internal.h98
-rw-r--r--fs/pstore/zone.c2
-rw-r--r--fs/quota/dquot.c2
-rw-r--r--fs/read_write.c31
-rw-r--r--fs/reiserfs/acl.h6
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/reiserfs/namei.c8
-rw-r--r--fs/reiserfs/xattr_acl.c11
-rw-r--r--fs/reiserfs/xattr_security.c2
-rw-r--r--fs/remap_range.c9
-rw-r--r--fs/seq_file.c2
-rw-r--r--fs/splice.c10
-rw-r--r--fs/squashfs/Kconfig51
-rw-r--r--fs/squashfs/block.c2
-rw-r--r--fs/squashfs/decompressor.c2
-rw-r--r--fs/squashfs/decompressor_multi.c20
-rw-r--r--fs/squashfs/decompressor_multi_percpu.c23
-rw-r--r--fs/squashfs/decompressor_single.c15
-rw-r--r--fs/squashfs/squashfs.h23
-rw-r--r--fs/squashfs/squashfs_fs_sb.h4
-rw-r--r--fs/squashfs/super.c102
-rw-r--r--fs/stat.c7
-rw-r--r--fs/super.c60
-rw-r--r--fs/sysv/itree.c2
-rw-r--r--fs/ubifs/debug.c8
-rw-r--r--fs/ubifs/lpt_commit.c14
-rw-r--r--fs/ubifs/tnc_commit.c2
-rw-r--r--fs/udf/inode.c83
-rw-r--r--fs/udf/namei.c10
-rw-r--r--fs/udf/super.c4
-rw-r--r--fs/udf/truncate.c48
-rw-r--r--fs/udf/udf_sb.h6
-rw-r--r--fs/userfaultfd.c3
-rw-r--r--fs/verity/fsverity_private.h5
-rw-r--r--fs/verity/hash_algs.c6
-rw-r--r--fs/verity/measure.c19
-rw-r--r--fs/verity/verify.c12
-rw-r--r--fs/xattr.c440
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c2
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c2
-rw-r--r--fs/xfs/xfs_acl.c3
-rw-r--r--fs/xfs/xfs_acl.h2
-rw-r--r--fs/xfs/xfs_error.c2
-rw-r--r--fs/xfs/xfs_iops.c16
-rw-r--r--fs/zonefs/super.c60
-rw-r--r--fs/zonefs/sysfs.c5
-rw-r--r--fs/zonefs/zonefs.h6
-rw-r--r--include/acpi/acconfig.h2
-rw-r--r--include/acpi/acpi_bus.h2
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/acpi/actbl1.h151
-rw-r--r--include/acpi/actbl2.h162
-rw-r--r--include/acpi/actypes.h10
-rw-r--r--include/acpi/acuuid.h3
-rw-r--r--include/acpi/battery.h4
-rw-r--r--include/acpi/ghes.h34
-rw-r--r--include/acpi/processor.h10
-rw-r--r--include/asm-generic/hyperv-tlfs.h9
-rw-r--r--include/asm-generic/msi.h4
-rw-r--r--include/asm-generic/tlb.h4
-rw-r--r--include/asm-generic/vmlinux.lds.h11
-rw-r--r--include/clocksource/hyperv_timer.h11
-rw-r--r--include/clocksource/timer-ti-dm.h2
-rw-r--r--include/drm/drm_accel.h97
-rw-r--r--include/drm/drm_atomic_helper.h3
-rw-r--r--include/drm/drm_atomic_state_helper.h2
-rw-r--r--include/drm/drm_connector.h33
-rw-r--r--include/drm/drm_crtc_helper.h2
-rw-r--r--include/drm/drm_device.h3
-rw-r--r--include/drm/drm_drv.h16
-rw-r--r--include/drm/drm_edid.h24
-rw-r--r--include/drm/drm_fb_helper.h68
-rw-r--r--include/drm/drm_fbdev_generic.h15
-rw-r--r--include/drm/drm_file.h21
-rw-r--r--include/drm/drm_gem.h3
-rw-r--r--include/drm/drm_gem_atomic_helper.h20
-rw-r--r--include/drm/drm_mode_config.h2
-rw-r--r--include/drm/drm_modeset_helper_vtables.h41
-rw-r--r--include/drm/drm_simple_kms_helper.h20
-rw-r--r--include/drm/gpu_scheduler.h51
-rw-r--r--include/drm/i915_pxp_tee_interface.h5
-rw-r--r--include/drm/ttm/ttm_resource.h4
-rw-r--r--include/drm/ttm/ttm_tt.h2
-rw-r--r--include/dt-bindings/arm/qcom,ids.h170
-rw-r--r--include/dt-bindings/clock/rk3399-cru.h6
-rw-r--r--include/dt-bindings/clock/tegra234-clock.h639
-rw-r--r--include/dt-bindings/firmware/imx/rsrc.h302
-rw-r--r--include/dt-bindings/iio/qcom,spmi-adc7-pm8350.h90
-rw-r--r--include/dt-bindings/media/video-interfaces.h16
-rw-r--r--include/dt-bindings/memory/tegra234-mc.h440
-rw-r--r--include/dt-bindings/power/qcom-rpmpd.h42
-rw-r--r--include/dt-bindings/power/tegra234-powergate.h15
-rw-r--r--include/dt-bindings/reset/tegra234-reset.h111
-rw-r--r--include/kunit/assert.h74
-rw-r--r--include/kunit/test-bug.h53
-rw-r--r--include/kunit/test.h118
-rw-r--r--include/kunit/visibility.h33
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/acpi_apmt.h19
-rw-r--r--include/linux/arm_ffa.h85
-rw-r--r--include/linux/ata.h31
-rw-r--r--include/linux/bcm47xx_nvram.h6
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blk-crypto-profile.h12
-rw-r--r--include/linux/blk-crypto.h14
-rw-r--r--include/linux/blk-mq.h9
-rw-r--r--include/linux/blk_types.h7
-rw-r--r--include/linux/blkdev.h48
-rw-r--r--include/linux/bpf.h60
-rw-r--r--include/linux/can/dev.h16
-rw-r--r--include/linux/can/platform/sja1000.h2
-rw-r--r--include/linux/cgroup.h99
-rw-r--r--include/linux/cgroup_refcnt.h96
-rw-r--r--include/linux/compat.h2
-rw-r--r--include/linux/configfs.h3
-rw-r--r--include/linux/console.h129
-rw-r--r--include/linux/coredump.h2
-rw-r--r--include/linux/cpufreq.h28
-rw-r--r--include/linux/damon.h2
-rw-r--r--include/linux/debugfs.h19
-rw-r--r--include/linux/devfreq.h7
-rw-r--r--include/linux/device.h8
-rw-r--r--include/linux/dma-buf.h17
-rw-r--r--include/linux/efi.h1
-rw-r--r--include/linux/elfcore.h13
-rw-r--r--include/linux/eventfd.h9
-rw-r--r--include/linux/evm.h49
-rw-r--r--include/linux/fault-inject.h7
-rw-r--r--include/linux/fb.h9
-rw-r--r--include/linux/fs.h103
-rw-r--r--include/linux/fs_context.h16
-rw-r--r--include/linux/fs_parser.h1
-rw-r--r--include/linux/fscache.h2
-rw-r--r--include/linux/ftrace.h47
-rw-r--r--include/linux/gfp.h18
-rw-r--r--include/linux/gpio/driver.h2
-rw-r--r--include/linux/host1x.h2
-rw-r--r--include/linux/hyperv.h4
-rw-r--r--include/linux/ima.h24
-rw-r--r--include/linux/init.h3
-rw-r--r--include/linux/io-mapping.h4
-rw-r--r--include/linux/io_uring.h10
-rw-r--r--include/linux/io_uring_types.h5
-rw-r--r--include/linux/ioport.h2
-rw-r--r--include/linux/irqdomain.h143
-rw-r--r--include/linux/irqdomain_defs.h31
-rw-r--r--include/linux/irqreturn.h8
-rw-r--r--include/linux/jbd2.h2
-rw-r--r--include/linux/kasan.h5
-rw-r--r--include/linux/kcov.h2
-rw-r--r--include/linux/kexec.h7
-rw-r--r--include/linux/kvm_host.h3
-rw-r--r--include/linux/libata.h7
-rw-r--r--include/linux/libnvdimm.h7
-rw-r--r--include/linux/lru_cache.h3
-rw-r--r--include/linux/lsm_hook_defs.h9
-rw-r--r--include/linux/lsm_hooks.h263
-rw-r--r--include/linux/maple_tree.h7
-rw-r--r--include/linux/math64.h26
-rw-r--r--include/linux/mbcache.h9
-rw-r--r--include/linux/mei_cl_bus.h6
-rw-r--r--include/linux/mempool.h5
-rw-r--r--include/linux/memregion.h38
-rw-r--r--include/linux/minmax.h26
-rw-r--r--include/linux/mlx5/driver.h1
-rw-r--r--include/linux/mm.h32
-rw-r--r--include/linux/mmc/mmc.h2
-rw-r--r--include/linux/mmzone.h24
-rw-r--r--include/linux/mnt_idmapping.h108
-rw-r--r--include/linux/mount.h9
-rw-r--r--include/linux/msi.h357
-rw-r--r--include/linux/msi_api.h73
-rw-r--r--include/linux/mtd/nand.h1
-rw-r--r--include/linux/mtd/spi-nor.h3
-rw-r--r--include/linux/netfs.h8
-rw-r--r--include/linux/nfs4.h13
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nodemask.h2
-rw-r--r--include/linux/nsproxy.h1
-rw-r--r--include/linux/nvme.h2
-rw-r--r--include/linux/pci.h49
-rw-r--r--include/linux/percpu.h9
-rw-r--r--include/linux/perf/arm_pmu.h3
-rw-r--r--include/linux/perf_event.h125
-rw-r--r--include/linux/pgtable.h18
-rw-r--r--include/linux/phy/phy-mipi-dphy.h3
-rw-r--r--include/linux/pktcdvd.h197
-rw-r--r--include/linux/platform_data/gpmc-omap.h8
-rw-r--r--include/linux/platform_data/st33zp24.h16
-rw-r--r--include/linux/pm_domain.h7
-rw-r--r--include/linux/posix_acl.h41
-rw-r--r--include/linux/posix_acl_xattr.h47
-rw-r--r--include/linux/prandom.h19
-rw-r--r--include/linux/psi_types.h4
-rw-r--r--include/linux/pstore_ram.h99
-rw-r--r--include/linux/ptrace.h9
-rw-r--r--include/linux/raid/pq.h8
-rw-r--r--include/linux/random.h102
-rw-r--r--include/linux/rcupdate.h14
-rw-r--r--include/linux/rcutiny.h8
-rw-r--r--include/linux/rcutree.h4
-rw-r--r--include/linux/regmap.h49
-rw-r--r--include/linux/regset.h15
-rw-r--r--include/linux/resctrl.h6
-rw-r--r--include/linux/ring_buffer.h2
-rw-r--r--include/linux/sbitmap.h16
-rw-r--r--include/linux/sched.h5
-rw-r--r--include/linux/scs.h18
-rw-r--r--include/linux/seccomp.h1
-rw-r--r--include/linux/security.h46
-rw-r--r--include/linux/sed-opal.h3
-rw-r--r--include/linux/serial_core.h10
-rw-r--r--include/linux/skmsg.h2
-rw-r--r--include/linux/slab.h98
-rw-r--r--include/linux/slab_def.h2
-rw-r--r--include/linux/slub_def.h8
-rw-r--r--include/linux/soc/mediatek/mtk-mmsys.h7
-rw-r--r--include/linux/soc/qcom/llcc-qcom.h12
-rw-r--r--include/linux/soundwire/sdw_intel.h2
-rw-r--r--include/linux/srcu.h72
-rw-r--r--include/linux/srcutree.h5
-rw-r--r--include/linux/stackprotector.h19
-rw-r--r--include/linux/sunrpc/svc.h8
-rw-r--r--include/linux/swapops.h8
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/linux/thermal.h1
-rw-r--r--include/linux/time_namespace.h6
-rw-r--r--include/linux/timer.h35
-rw-r--r--include/linux/timerqueue.h2
-rw-r--r--include/linux/trace.h4
-rw-r--r--include/linux/uio.h9
-rw-r--r--include/linux/vfio.h1
-rw-r--r--include/linux/wait.h2
-rw-r--r--include/linux/xattr.h50
-rw-r--r--include/media/davinci/vpbe.h2
-rw-r--r--include/media/dvb_ringbuffer.h2
-rw-r--r--include/media/dvbdev.h38
-rw-r--r--include/media/frame_vector.h2
-rw-r--r--include/media/i2c/ov9650.h24
-rw-r--r--include/media/i2c/s5c73m3.h15
-rw-r--r--include/media/i2c/s5k4ecgx.h33
-rw-r--r--include/media/i2c/ths7303.h4
-rw-r--r--include/media/media-entity.h4
-rw-r--r--include/media/v4l2-mediabus.h17
-rw-r--r--include/media/v4l2-subdev.h11
-rw-r--r--include/media/videobuf2-core.h14
-rw-r--r--include/media/videobuf2-memops.h3
-rw-r--r--include/memory/renesas-rpc-if.h1
-rw-r--r--include/net/bluetooth/hci.h12
-rw-r--r--include/net/inet_hashtables.h3
-rw-r--r--include/net/ip.h2
-rw-r--r--include/net/ipv6.h2
-rw-r--r--include/net/neighbour.h2
-rw-r--r--include/net/ping.h3
-rw-r--r--include/net/sctp/stream_sched.h2
-rw-r--r--include/net/sock.h2
-rw-r--r--include/scsi/scsi_proto.h4
-rw-r--r--include/soc/amlogic/meson_ddr_pmu.h66
-rw-r--r--include/soc/at91/sama7-ddr.h5
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h52
-rw-r--r--include/soc/fsl/qe/qe.h5
-rw-r--r--include/soc/qcom/qcom-spmi-pmic.h17
-rw-r--r--include/soc/tegra/bpmp-abi.h1796
-rw-r--r--include/soc/tegra/bpmp.h17
-rw-r--r--include/soc/tegra/fuse.h15
-rw-r--r--include/soc/tegra/ivc.h12
-rw-r--r--include/soc/tegra/mc.h11
-rw-r--r--include/soc/tegra/pmc.h6
-rw-r--r--include/sound/acp63_chip_offset_byte.h (renamed from include/sound/acp62_chip_offset_byte.h)216
-rw-r--r--include/sound/hdaudio.h27
-rw-r--r--include/sound/hdaudio_ext.h69
-rw-r--r--include/sound/hdmi-codec.h4
-rw-r--r--include/sound/pcm.h36
-rw-r--r--include/sound/sdw.h49
-rw-r--r--include/sound/simple_card_utils.h2
-rw-r--r--include/sound/soc-dapm.h188
-rw-r--r--include/sound/soc-dpcm.h2
-rw-r--r--include/sound/sof.h10
-rw-r--r--include/sound/sof/dai-amd.h1
-rw-r--r--include/sound/sof/dai.h4
-rw-r--r--include/sound/sof/info.h4
-rw-r--r--include/sound/sof/ipc4/header.h4
-rw-r--r--include/sound/tlv320aic3x.h65
-rw-r--r--include/trace/events/btrfs.h27
-rw-r--r--include/trace/events/cachefiles.h27
-rw-r--r--include/trace/events/cxl.h112
-rw-r--r--include/trace/events/dlm.h303
-rw-r--r--include/trace/events/ext4.h64
-rw-r--r--include/trace/events/fscache.h2
-rw-r--r--include/trace/events/huge_memory.h8
-rw-r--r--include/trace/events/iocost.h4
-rw-r--r--include/trace/events/jbd2.h44
-rw-r--r--include/trace/events/rpcgss.h2
-rw-r--r--include/trace/events/rpcrdma.h4
-rw-r--r--include/trace/events/sunrpc.h6
-rw-r--r--include/trace/misc/fs.h (renamed from include/trace/events/fs.h)0
-rw-r--r--include/trace/misc/nfs.h (renamed from include/trace/events/nfs.h)12
-rw-r--r--include/trace/misc/rdma.h (renamed from include/trace/events/rdma.h)0
-rw-r--r--include/trace/misc/sunrpc.h (renamed from include/trace/events/sunrpc_base.h)0
-rw-r--r--include/uapi/drm/amdgpu_drm.h14
-rw-r--r--include/uapi/drm/drm_fourcc.h29
-rw-r--r--include/uapi/drm/drm_mode.h63
-rw-r--r--include/uapi/drm/i915_drm.h62
-rw-r--r--include/uapi/drm/msm_drm.h1
-rw-r--r--include/uapi/drm/panfrost_drm.h2
-rw-r--r--include/uapi/linux/aspeed-video.h14
-rw-r--r--include/uapi/linux/audit.h2
-rw-r--r--include/uapi/linux/btrfs.h36
-rw-r--r--include/uapi/linux/btrfs_tree.h235
-rw-r--r--include/uapi/linux/capability.h2
-rw-r--r--include/uapi/linux/dvb/audio.h15
-rw-r--r--include/uapi/linux/dvb/ca.h15
-rw-r--r--include/uapi/linux/dvb/dmx.h15
-rw-r--r--include/uapi/linux/dvb/frontend.h77
-rw-r--r--include/uapi/linux/dvb/net.h15
-rw-r--r--include/uapi/linux/dvb/osd.h15
-rw-r--r--include/uapi/linux/dvb/version.h15
-rw-r--r--include/uapi/linux/dvb/video.h15
-rw-r--r--include/uapi/linux/elf.h14
-rw-r--r--include/uapi/linux/eventpoll.h6
-rw-r--r--include/uapi/linux/fscrypt.h4
-rw-r--r--include/uapi/linux/fuse.h16
-rw-r--r--include/uapi/linux/idxd.h1
-rw-r--r--include/uapi/linux/in.h1
-rw-r--r--include/uapi/linux/io_uring.h20
-rw-r--r--include/uapi/linux/ip.h6
-rw-r--r--include/uapi/linux/ipv6.h6
-rw-r--r--include/uapi/linux/landlock.h21
-rw-r--r--include/uapi/linux/media-bus-format.h3
-rw-r--r--include/uapi/linux/pci_regs.h1
-rw-r--r--include/uapi/linux/pktcdvd.h112
-rw-r--r--include/uapi/linux/sed-opal.h8
-rw-r--r--include/uapi/linux/tdx-guest.h42
-rw-r--r--include/uapi/linux/v4l2-common.h39
-rw-r--r--include/uapi/linux/v4l2-controls.h46
-rw-r--r--include/uapi/linux/v4l2-dv-timings.h9
-rw-r--r--include/uapi/linux/v4l2-mediabus.h4
-rw-r--r--include/uapi/linux/v4l2-subdev.h13
-rw-r--r--include/uapi/linux/videodev2.h5
-rw-r--r--include/uapi/sound/asequencer.h8
-rw-r--r--include/uapi/sound/snd_ar_tokens.h27
-rw-r--r--include/uapi/sound/sof/tokens.h14
-rw-r--r--include/video/nomodeset.h8
-rw-r--r--include/xen/arm/xen-ops.h4
-rw-r--r--include/xen/xen-ops.h16
-rw-r--r--include/xen/xen.h4
-rw-r--r--init/Kconfig2
-rw-r--r--init/initramfs.c2
-rw-r--r--init/main.c7
-rw-r--r--io_uring/filetable.c2
-rw-r--r--io_uring/io_uring.c368
-rw-r--r--io_uring/io_uring.h71
-rw-r--r--io_uring/kbuf.c16
-rw-r--r--io_uring/msg_ring.c168
-rw-r--r--io_uring/msg_ring.h1
-rw-r--r--io_uring/net.c110
-rw-r--r--io_uring/notif.c57
-rw-r--r--io_uring/notif.h15
-rw-r--r--io_uring/opdef.c8
-rw-r--r--io_uring/opdef.h2
-rw-r--r--io_uring/poll.c181
-rw-r--r--io_uring/rsrc.c71
-rw-r--r--io_uring/rsrc.h1
-rw-r--r--io_uring/rw.c19
-rw-r--r--io_uring/timeout.c10
-rw-r--r--io_uring/uring_cmd.c2
-rw-r--r--io_uring/xattr.c8
-rw-r--r--ipc/mqueue.c6
-rw-r--r--ipc/sem.c3
-rw-r--r--ipc/shm.c34
-rw-r--r--kernel/acct.c6
-rw-r--r--kernel/auditsc.c75
-rw-r--r--kernel/bpf/bpf_local_storage.c2
-rw-r--r--kernel/bpf/core.c4
-rw-r--r--kernel/bpf/dispatcher.c28
-rw-r--r--kernel/bpf/percpu_freelist.c23
-rw-r--r--kernel/bpf/verifier.c31
-rw-r--r--kernel/capability.c4
-rw-r--r--kernel/cgroup/cgroup-internal.h1
-rw-r--r--kernel/cgroup/cgroup.c8
-rw-r--r--kernel/cgroup/cpuset.c48
-rw-r--r--kernel/configs/tiny.config5
-rw-r--r--kernel/cpu.c61
-rw-r--r--kernel/crash_core.c3
-rw-r--r--kernel/debug/kdb/kdb_io.c18
-rw-r--r--kernel/dma/mapping.c8
-rw-r--r--kernel/dma/swiotlb.c63
-rw-r--r--kernel/events/core.c2165
-rw-r--r--kernel/fork.c28
-rw-r--r--kernel/futex/core.c26
-rw-r--r--kernel/gcov/clang.c2
-rw-r--r--kernel/irq/Kconfig7
-rw-r--r--kernel/irq/chip.c8
-rw-r--r--kernel/irq/internals.h2
-rw-r--r--kernel/irq/irqdesc.c15
-rw-r--r--kernel/irq/manage.c4
-rw-r--r--kernel/irq/msi.c914
-rw-r--r--kernel/jump_label.c8
-rw-r--r--kernel/kcsan/Makefile1
-rw-r--r--kernel/kcsan/core.c50
-rw-r--r--kernel/kcsan/selftest.c12
-rw-r--r--kernel/kexec_core.c10
-rw-r--r--kernel/kexec_file.c2
-rw-r--r--kernel/kprobes.c8
-rw-r--r--kernel/livepatch/patch.c2
-rw-r--r--kernel/livepatch/transition.c54
-rw-r--r--kernel/locking/test-ww_mutex.c4
-rw-r--r--kernel/notifier.c6
-rw-r--r--kernel/nsproxy.c23
-rw-r--r--kernel/panic.c5
-rw-r--r--kernel/power/process.c25
-rw-r--r--kernel/power/snapshot.c12
-rw-r--r--kernel/printk/printk.c498
-rw-r--r--kernel/printk/printk_ringbuffer.c2
-rw-r--r--kernel/rcu/Kconfig22
-rw-r--r--kernel/rcu/Kconfig.debug3
-rw-r--r--kernel/rcu/rcu.h16
-rw-r--r--kernel/rcu/rcuscale.c69
-rw-r--r--kernel/rcu/rcutorture.c72
-rw-r--r--kernel/rcu/srcutiny.c10
-rw-r--r--kernel/rcu/srcutree.c100
-rw-r--r--kernel/rcu/sync.c2
-rw-r--r--kernel/rcu/tasks.h2
-rw-r--r--kernel/rcu/tiny.c2
-rw-r--r--kernel/rcu/tree.c152
-rw-r--r--kernel/rcu/tree.h12
-rw-r--r--kernel/rcu/tree_exp.h2
-rw-r--r--kernel/rcu/tree_nocb.h259
-rw-r--r--kernel/rcu/tree_plugin.h5
-rw-r--r--kernel/rcu/update.c18
-rw-r--r--kernel/relay.c8
-rw-r--r--kernel/resource.c13
-rw-r--r--kernel/rseq.c19
-rw-r--r--kernel/sched/core.c311
-rw-r--r--kernel/sched/cpufreq_schedutil.c30
-rw-r--r--kernel/sched/deadline.c7
-rw-r--r--kernel/sched/fair.c305
-rw-r--r--kernel/sched/psi.c100
-rw-r--r--kernel/sched/sched.h92
-rw-r--r--kernel/sched/stats.h22
-rw-r--r--kernel/sched/wait.c18
-rw-r--r--kernel/scs.c14
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/sysctl.c30
-rw-r--r--kernel/time/clockevents.c2
-rw-r--r--kernel/time/clocksource.c2
-rw-r--r--kernel/time/namespace.c18
-rw-r--r--kernel/time/timer.c427
-rw-r--r--kernel/trace/Kconfig6
-rw-r--r--kernel/trace/blktrace.c7
-rw-r--r--kernel/trace/ftrace.c8
-rw-r--r--kernel/trace/kprobe_event_gen_test.c48
-rw-r--r--kernel/trace/rethook.c4
-rw-r--r--kernel/trace/ring_buffer.c71
-rw-r--r--kernel/trace/synth_event_gen_test.c16
-rw-r--r--kernel/trace/trace.c23
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_dynevent.c2
-rw-r--r--kernel/trace/trace_eprobe.c8
-rw-r--r--kernel/trace/trace_events.c13
-rw-r--r--kernel/trace/trace_events_hist.c7
-rw-r--r--kernel/trace/trace_events_synth.c7
-rw-r--r--kernel/trace/trace_events_user.c6
-rw-r--r--kernel/trace/trace_osnoise.c6
-rw-r--r--kernel/trace/trace_syscalls.c2
-rw-r--r--kernel/workqueue.c2
-rw-r--r--lib/Kconfig7
-rw-r--r--lib/Kconfig.debug42
-rw-r--r--lib/Kconfig.kasan2
-rw-r--r--lib/Kconfig.kcsan6
-rw-r--r--lib/Kconfig.kmsan1
-rw-r--r--lib/Makefile1
-rw-r--r--lib/debugobjects.c14
-rw-r--r--lib/fault-inject.c15
-rw-r--r--lib/find_bit_benchmark.c4
-rw-r--r--lib/fonts/fonts.c4
-rw-r--r--lib/iov_iter.c82
-rw-r--r--lib/is_signed_type_kunit.c4
-rw-r--r--lib/kobject.c2
-rw-r--r--lib/kunit/assert.c62
-rw-r--r--lib/kunit/debugfs.c2
-rw-r--r--lib/kunit/executor.c6
-rw-r--r--lib/kunit/kunit-example-test.c7
-rw-r--r--lib/kunit/string-stream.c5
-rw-r--r--lib/kunit/test.c15
-rw-r--r--lib/llist.c4
-rw-r--r--lib/lru_cache.c59
-rw-r--r--lib/maple_tree.c58
-rw-r--r--lib/math/div64.c15
-rw-r--r--lib/notifier-error-inject.c2
-rw-r--r--lib/oid_registry.c1
-rw-r--r--lib/percpu-refcount.c3
-rw-r--r--lib/radix-tree.c2
-rw-r--r--lib/raid6/algos.c2
-rw-r--r--lib/raid6/s390vx.uc3
-rw-r--r--lib/reed_solomon/test_rslib.c6
-rw-r--r--lib/sbitmap.c148
-rw-r--r--lib/scatterlist.c25
-rw-r--r--lib/slub_kunit.c58
-rw-r--r--lib/test-string_helpers.c2
-rw-r--r--lib/test_fprobe.c5
-rw-r--r--lib/test_hexdump.c10
-rw-r--r--lib/test_kprobes.c5
-rw-r--r--lib/test_list_sort.c2
-rw-r--r--lib/test_maple_tree.c35930
-rw-r--r--lib/test_printf.c40
-rw-r--r--lib/test_rhashtable.c6
-rw-r--r--lib/test_vmalloc.c8
-rw-r--r--lib/vdso/Makefile2
-rw-r--r--lib/vsprintf.c16
-rw-r--r--mm/Kconfig38
-rw-r--r--mm/Kconfig.debug2
-rw-r--r--mm/compaction.c22
-rw-r--r--mm/damon/dbgfs.c7
-rw-r--r--mm/damon/sysfs.c50
-rw-r--r--mm/failslab.c12
-rw-r--r--mm/gup.c47
-rw-r--r--mm/huge_memory.c28
-rw-r--r--mm/hugetlb.c58
-rw-r--r--mm/hugetlb_vmemmap.c1
-rw-r--r--mm/kasan/generic.c19
-rw-r--r--mm/kasan/kasan_test.c6
-rw-r--r--mm/kfence/core.c4
-rw-r--r--mm/kfence/kfence_test.c4
-rw-r--r--mm/kfence/report.c13
-rw-r--r--mm/khugepaged.c97
-rw-r--r--mm/kmsan/kmsan.h2
-rw-r--r--mm/maccess.c2
-rw-r--r--mm/madvise.c8
-rw-r--r--mm/memcontrol.c17
-rw-r--r--mm/memory-failure.c5
-rw-r--r--mm/memory.c27
-rw-r--r--mm/memremap.c1
-rw-r--r--mm/migrate.c16
-rw-r--r--mm/migrate_device.c8
-rw-r--r--mm/mmap.c25
-rw-r--r--mm/mmu_gather.c4
-rw-r--r--mm/page_alloc.c7
-rw-r--r--mm/page_ext.c2
-rw-r--r--mm/page_io.c4
-rw-r--r--mm/page_reporting.c50
-rw-r--r--mm/percpu.c44
-rw-r--r--mm/process_vm_access.c2
-rw-r--r--mm/shmem.c15
-rw-r--r--mm/slab.c113
-rw-r--r--mm/slab.h86
-rw-r--r--mm/slab_common.c51
-rw-r--r--mm/slub.c558
-rw-r--r--mm/swapfile.c13
-rw-r--r--mm/userfaultfd.c2
-rw-r--r--mm/vmscan.c82
-rw-r--r--net/802/garp.c2
-rw-r--r--net/802/mrp.c2
-rw-r--r--net/9p/client.c2
-rw-r--r--net/9p/trans_fd.c28
-rw-r--r--net/9p/trans_xen.c9
-rw-r--r--net/batman-adv/bat_iv_ogm.c4
-rw-r--r--net/batman-adv/bat_v_elp.c2
-rw-r--r--net/batman-adv/bat_v_ogm.c4
-rw-r--r--net/batman-adv/network-coding.c2
-rw-r--r--net/bluetooth/6lowpan.c3
-rw-r--r--net/bluetooth/a2mp.c2
-rw-r--r--net/bluetooth/af_bluetooth.c4
-rw-r--r--net/bluetooth/hci_codec.c19
-rw-r--r--net/bluetooth/hci_core.c8
-rw-r--r--net/bluetooth/hci_request.c2
-rw-r--r--net/bluetooth/hci_sync.c19
-rw-r--r--net/bluetooth/iso.c1
-rw-r--r--net/bluetooth/l2cap_core.c3
-rw-r--r--net/bluetooth/mgmt.c5
-rw-r--r--net/bluetooth/smp.c2
-rw-r--r--net/bpf/test_run.c1
-rw-r--r--net/bridge/br_vlan.c17
-rw-r--r--net/caif/chnl_net.c3
-rw-r--r--net/can/af_can.c9
-rw-r--r--net/can/isotp.c71
-rw-r--r--net/can/j1939/main.c3
-rw-r--r--net/can/j1939/socket.c2
-rw-r--r--net/can/j1939/transport.c2
-rw-r--r--net/ceph/messenger_v1.c4
-rw-r--r--net/ceph/messenger_v2.c14
-rw-r--r--net/ceph/mon_client.c2
-rw-r--r--net/ceph/osd_client.c2
-rw-r--r--net/compat.c3
-rw-r--r--net/core/dev_addr_lists_test.c4
-rw-r--r--net/core/dst.c2
-rw-r--r--net/core/flow_dissector.c2
-rw-r--r--net/core/lwtunnel.c4
-rw-r--r--net/core/neighbour.c62
-rw-r--r--net/core/pktgen.c37
-rw-r--r--net/core/skbuff.c36
-rw-r--r--net/core/skmsg.c7
-rw-r--r--net/core/sock.c3
-rw-r--r--net/core/sock_map.c7
-rw-r--r--net/core/stream.c2
-rw-r--r--net/dccp/ipv4.c23
-rw-r--r--net/dccp/ipv6.c24
-rw-r--r--net/dccp/proto.c3
-rw-r--r--net/dsa/dsa2.c10
-rw-r--r--net/dsa/dsa_priv.h1
-rw-r--r--net/dsa/master.c3
-rw-r--r--net/dsa/port.c16
-rw-r--r--net/dsa/tag_hellcreek.c3
-rw-r--r--net/dsa/tag_ksz.c3
-rw-r--r--net/dsa/tag_sja1105.c3
-rw-r--r--net/hsr/hsr_forward.c5
-rw-r--r--net/ipv4/Kconfig10
-rw-r--r--net/ipv4/af_inet.c11
-rw-r--r--net/ipv4/devinet.c19
-rw-r--r--net/ipv4/esp4_offload.c3
-rw-r--r--net/ipv4/fib_frontend.c3
-rw-r--r--net/ipv4/fib_semantics.c9
-rw-r--r--net/ipv4/fib_trie.c6
-rw-r--r--net/ipv4/icmp.c2
-rw-r--r--net/ipv4/igmp.c6
-rw-r--r--net/ipv4/inet_connection_sock.c2
-rw-r--r--net/ipv4/inet_hashtables.c96
-rw-r--r--net/ipv4/ip_gre.c48
-rw-r--r--net/ipv4/ip_input.c5
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c4
-rw-r--r--net/ipv4/ping.c7
-rw-r--r--net/ipv4/route.c4
-rw-r--r--net/ipv4/tcp.c9
-rw-r--r--net/ipv4/tcp_bbr.c2
-rw-r--r--net/ipv4/tcp_bpf.c8
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv4/tcp_ipv4.c21
-rw-r--r--net/ipv6/addrconf.c8
-rw-r--r--net/ipv6/addrlabel.c1
-rw-r--r--net/ipv6/esp6_offload.c3
-rw-r--r--net/ipv6/ip6_output.c5
-rw-r--r--net/ipv6/mcast.c10
-rw-r--r--net/ipv6/output_core.c8
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/tcp_ipv6.c20
-rw-r--r--net/ipv6/xfrm6_policy.c6
-rw-r--r--net/kcm/kcmsock.c58
-rw-r--r--net/key/af_key.c34
-rw-r--r--net/l2tp/l2tp_core.c22
-rw-r--r--net/mac80211/airtime.c3
-rw-r--r--net/mac80211/main.c8
-rw-r--r--net/mac80211/mesh_pathtbl.c2
-rw-r--r--net/mac80211/s1g.c3
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac802154/iface.c1
-rw-r--r--net/mctp/af_mctp.c4
-rw-r--r--net/mctp/route.c2
-rw-r--r--net/mptcp/protocol.c13
-rw-r--r--net/mptcp/subflow.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_twos.c4
-rw-r--r--net/netfilter/nf_conntrack_core.c12
-rw-r--r--net/netfilter/nf_conntrack_netlink.c21
-rw-r--r--net/netfilter/nf_conntrack_standalone.c2
-rw-r--r--net/netfilter/nf_flow_table_offload.c10
-rw-r--r--net/netfilter/nf_nat_helper.c2
-rw-r--r--net/netfilter/nf_tables_api.c9
-rw-r--r--net/netfilter/nfnetlink.c1
-rw-r--r--net/netfilter/nft_ct.c6
-rw-r--r--net/netfilter/nft_set_pipapo.c5
-rw-r--r--net/netfilter/xt_connmark.c18
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/nfc/nci/core.c2
-rw-r--r--net/nfc/nci/data.c4
-rw-r--r--net/nfc/nci/ntf.c6
-rw-r--r--net/openvswitch/conntrack.c8
-rw-r--r--net/packet/af_packet.c10
-rw-r--r--net/rxrpc/ar-internal.h1
-rw-r--r--net/rxrpc/conn_client.c38
-rw-r--r--net/sched/Kconfig2
-rw-r--r--net/sched/act_connmark.c4
-rw-r--r--net/sched/act_ct.c8
-rw-r--r--net/sched/act_ctinfo.c6
-rw-r--r--net/sched/act_gact.c2
-rw-r--r--net/sched/act_sample.c2
-rw-r--r--net/sched/sch_choke.c2
-rw-r--r--net/sched/sch_netem.c4
-rw-r--r--net/sctp/outqueue.c13
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/sctp/stream.c25
-rw-r--r--net/sctp/stream_sched.c5
-rw-r--r--net/sctp/stream_sched_prio.c19
-rw-r--r--net/sctp/stream_sched_rr.c5
-rw-r--r--net/sctp/transport.c2
-rw-r--r--net/smc/smc_clc.c6
-rw-r--r--net/smc/smc_tx.c2
-rw-r--r--net/socket.c12
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c64
-rw-r--r--net/sunrpc/cache.c2
-rw-r--r--net/sunrpc/clnt.c2
-rw-r--r--net/sunrpc/socklib.c6
-rw-r--r--net/sunrpc/svc.c4
-rw-r--r--net/sunrpc/svcsock.c4
-rw-r--r--net/sunrpc/xdr.c22
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--net/sunrpc/xprtrdma/verbs.c2
-rw-r--r--net/sunrpc/xprtsock.c8
-rw-r--r--net/tipc/crypto.c3
-rw-r--r--net/tipc/discover.c5
-rw-r--r--net/tipc/link.c4
-rw-r--r--net/tipc/netlink_compat.c2
-rw-r--r--net/tipc/node.c12
-rw-r--r--net/tipc/socket.c2
-rw-r--r--net/tipc/topsrv.c22
-rw-r--r--net/tls/tls_device.c4
-rw-r--r--net/tls/tls_device_fallback.c5
-rw-r--r--net/unix/diag.c20
-rw-r--r--net/vmw_vsock/af_vsock.c3
-rw-r--r--net/wireless/reg.c12
-rw-r--r--net/wireless/scan.c14
-rw-r--r--net/wireless/util.c6
-rw-r--r--net/x25/x25_dev.c2
-rw-r--r--net/xfrm/espintcp.c2
-rw-r--r--net/xfrm/xfrm_device.c15
-rw-r--r--net/xfrm/xfrm_replay.c2
-rw-r--r--net/xfrm/xfrm_state.c2
-rw-r--r--rust/Makefile22
-rw-r--r--rust/alloc/raw_vec.rs33
-rw-r--r--rust/alloc/vec/mod.rs89
-rw-r--r--rust/build_error.rs31
-rw-r--r--rust/exports.c5
-rw-r--r--rust/kernel/build_assert.rs82
-rw-r--r--rust/kernel/error.rs90
-rw-r--r--rust/kernel/lib.rs9
-rw-r--r--rust/kernel/prelude.rs20
-rw-r--r--rust/kernel/print.rs214
-rw-r--r--rust/kernel/static_assert.rs34
-rw-r--r--rust/kernel/std_vendor.rs163
-rw-r--r--rust/kernel/str.rs523
-rw-r--r--rust/kernel/types.rs37
-rw-r--r--rust/macros/concat_idents.rs23
-rw-r--r--rust/macros/helpers.rs24
-rw-r--r--rust/macros/lib.rs108
-rw-r--r--rust/macros/module.rs10
-rw-r--r--rust/macros/vtable.rs95
-rw-r--r--samples/landlock/sandboxer.c29
-rw-r--r--samples/rust/Kconfig10
-rw-r--r--samples/rust/Makefile1
-rw-r--r--samples/rust/rust_minimal.rs8
-rw-r--r--samples/rust/rust_print.rs54
-rw-r--r--scripts/Makefile.build2
-rw-r--r--scripts/Makefile.lib23
-rw-r--r--scripts/Makefile.package4
-rwxr-xr-xscripts/checkpatch.pl20
-rwxr-xr-xscripts/faddr2line7
-rwxr-xr-xscripts/generate_rust_analyzer.py8
-rw-r--r--scripts/head-object-list.txt1
-rwxr-xr-xscripts/kernel-doc54
-rwxr-xr-xscripts/min-tool-version.sh2
-rw-r--r--scripts/module.lds.S6
-rwxr-xr-xscripts/package/mkdebian2
-rw-r--r--scripts/spelling.txt33
-rwxr-xr-xscripts/sphinx-pre-install8
-rw-r--r--security/apparmor/Kconfig4
-rw-r--r--security/apparmor/Makefile3
-rw-r--r--security/apparmor/domain.c11
-rw-r--r--security/apparmor/file.c4
-rw-r--r--security/apparmor/include/policy_unpack.h50
-rw-r--r--security/apparmor/lsm.c60
-rw-r--r--security/apparmor/policy_unpack.c238
-rw-r--r--security/apparmor/policy_unpack_test.c69
-rw-r--r--security/commoncap.c73
-rw-r--r--security/device_cgroup.c33
-rw-r--r--security/integrity/evm/evm_crypto.c5
-rw-r--r--security/integrity/evm/evm_main.c153
-rw-r--r--security/integrity/ima/ima.h5
-rw-r--r--security/integrity/ima/ima_appraise.c15
-rw-r--r--security/integrity/ima/ima_main.c6
-rw-r--r--security/integrity/ima/ima_policy.c34
-rw-r--r--security/integrity/ima/ima_template_lib.c11
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--security/keys/trusted-keys/trusted_tee.c3
-rw-r--r--security/landlock/fs.c206
-rw-r--r--security/landlock/fs.h24
-rw-r--r--security/landlock/limits.h2
-rw-r--r--security/landlock/setup.c1
-rw-r--r--security/landlock/syscalls.c2
-rw-r--r--security/lsm_audit.c1
-rw-r--r--security/security.c109
-rw-r--r--security/selinux/hooks.c35
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/services.c54
-rw-r--r--security/selinux/ss/services.h15
-rw-r--r--security/selinux/ss/sidtab.c23
-rw-r--r--security/selinux/ss/sidtab.h3
-rw-r--r--security/smack/smack_lsm.c90
-rw-r--r--security/tomoyo/tomoyo.c13
-rw-r--r--sound/aoa/codecs/onyx.c5
-rw-r--r--sound/aoa/codecs/tas.c5
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c4
-rw-r--r--sound/core/memalloc.c64
-rw-r--r--sound/core/pcm_native.c24
-rw-r--r--sound/core/pcm_trace.h6
-rw-r--r--sound/core/rawmidi.c2
-rw-r--r--sound/core/seq/seq_memory.c11
-rw-r--r--sound/drivers/mts64.c3
-rw-r--r--sound/firewire/dice/Makefile2
-rw-r--r--sound/firewire/dice/dice-focusrite.c23
-rw-r--r--sound/firewire/dice/dice-stream.c12
-rw-r--r--sound/firewire/dice/dice.c10
-rw-r--r--sound/firewire/dice/dice.h1
-rw-r--r--sound/hda/ext/hdac_ext_controller.c116
-rw-r--r--sound/hda/ext/hdac_ext_stream.c203
-rw-r--r--sound/hda/hdac_stream.c158
-rw-r--r--sound/hda/hdac_sysfs.c4
-rw-r--r--sound/hda/intel-dsp-config.c5
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/asihpi/hpioctl.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c4
-rw-r--r--sound/pci/hda/Kconfig2
-rw-r--r--sound/pci/hda/cs35l41_hda.c1
-rw-r--r--sound/pci/hda/cs35l41_hda_i2c.c4
-rw-r--r--sound/pci/hda/hda_cs_dsp_ctl.c1
-rw-r--r--sound/pci/hda/hda_intel.c11
-rw-r--r--sound/pci/hda/patch_ca0132.c1
-rw-r--r--sound/pci/hda/patch_cs8409.c2
-rw-r--r--sound/pci/hda/patch_realtek.c43
-rw-r--r--sound/ppc/keywest.c5
-rw-r--r--sound/soc/amd/Kconfig4
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c3
-rw-r--r--sound/soc/amd/acp/acp-i2s.c16
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c62
-rw-r--r--sound/soc/amd/acp/acp-platform.c8
-rw-r--r--sound/soc/amd/ps/acp63.h (renamed from sound/soc/amd/ps/acp62.h)25
-rw-r--r--sound/soc/amd/ps/pci-ps.c141
-rw-r--r--sound/soc/amd/ps/ps-mach.c30
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c188
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c14
-rw-r--r--sound/soc/atmel/mchp-spdiftx.c165
-rw-r--r--sound/soc/codecs/Kconfig10
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/adau1372.c32
-rw-r--r--sound/soc/codecs/adau1373.c1
-rw-r--r--sound/soc/codecs/adau17x1.c1
-rw-r--r--sound/soc/codecs/ak4458.c13
-rw-r--r--sound/soc/codecs/cs35l36.c4
-rw-r--r--sound/soc/codecs/cs42l51.c2
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c2
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c28
-rw-r--r--sound/soc/codecs/cs42xx8.c22
-rw-r--r--sound/soc/codecs/cs42xx8.h3
-rw-r--r--sound/soc/codecs/da7219-aad.c46
-rw-r--r--sound/soc/codecs/da7219-aad.h1
-rw-r--r--sound/soc/codecs/da7219.c9
-rwxr-xr-xsound/soc/codecs/es8326.c5
-rw-r--r--sound/soc/codecs/hda.c12
-rw-r--r--sound/soc/codecs/hdac_hda.c6
-rw-r--r--sound/soc/codecs/hdac_hda.h4
-rw-r--r--sound/soc/codecs/hdac_hdmi.c8
-rw-r--r--sound/soc/codecs/hdmi-codec.c30
-rw-r--r--sound/soc/codecs/jz4725b.c81
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c149
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c6
-rw-r--r--sound/soc/codecs/max98373-i2c.c4
-rw-r--r--sound/soc/codecs/max98373-sdw.c31
-rw-r--r--sound/soc/codecs/max98396.c6
-rw-r--r--sound/soc/codecs/max9867.c33
-rw-r--r--sound/soc/codecs/nau8315.c2
-rw-r--r--sound/soc/codecs/nau8825.c135
-rw-r--r--sound/soc/codecs/nau8825.h23
-rw-r--r--sound/soc/codecs/pcm512x.c8
-rw-r--r--sound/soc/codecs/rt1308-sdw.c72
-rw-r--r--sound/soc/codecs/rt1308-sdw.h2
-rw-r--r--sound/soc/codecs/rt1316-sdw.c71
-rw-r--r--sound/soc/codecs/rt1316-sdw.h2
-rw-r--r--sound/soc/codecs/rt1318-sdw.c884
-rw-r--r--sound/soc/codecs/rt1318-sdw.h101
-rw-r--r--sound/soc/codecs/rt298.c7
-rw-r--r--sound/soc/codecs/rt5514-spi.c15
-rw-r--r--sound/soc/codecs/rt5640.c8
-rw-r--r--sound/soc/codecs/rt5677-spi.c19
-rw-r--r--sound/soc/codecs/rt5682-sdw.c28
-rw-r--r--sound/soc/codecs/rt5682.c2
-rw-r--r--sound/soc/codecs/rt5682.h2
-rw-r--r--sound/soc/codecs/rt5682s.c22
-rw-r--r--sound/soc/codecs/rt5682s.h2
-rw-r--r--sound/soc/codecs/rt700.c32
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/rt711-sdca.c27
-rw-r--r--sound/soc/codecs/rt711.c27
-rw-r--r--sound/soc/codecs/rt715-sdca.c25
-rw-r--r--sound/soc/codecs/rt715.c73
-rw-r--r--sound/soc/codecs/sdw-mockup.c28
-rw-r--r--sound/soc/codecs/sgtl5000.c1
-rw-r--r--sound/soc/codecs/simple-mux.c9
-rw-r--r--sound/soc/codecs/src4xxx-i2c.c5
-rw-r--r--sound/soc/codecs/tas2764.c19
-rw-r--r--sound/soc/codecs/tas2770.c20
-rw-r--r--sound/soc/codecs/tas2780.c24
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c120
-rw-r--r--sound/soc/codecs/tlv320aic3x.h43
-rw-r--r--sound/soc/codecs/twl4030.c6
-rw-r--r--sound/soc/codecs/wcd938x.c4
-rw-r--r--sound/soc/codecs/wm8961.c7
-rw-r--r--sound/soc/codecs/wm8962.c8
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c39
-rw-r--r--sound/soc/codecs/wm_adsp.h1
-rw-r--r--sound/soc/codecs/wsa883x.c28
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/fsl/fsl_micfil.c466
-rw-r--r--sound/soc/fsl/fsl_micfil.h6
-rw-r--r--sound/soc/fsl/fsl_rpmsg.c6
-rw-r--r--sound/soc/fsl/fsl_sai.c25
-rw-r--r--sound/soc/fsl/fsl_sai.h1
-rw-r--r--sound/soc/fsl/fsl_xcvr.c40
-rw-r--r--sound/soc/fsl/fsl_xcvr.h21
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c3
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c10
-rw-r--r--sound/soc/fsl/imx-rpmsg.c6
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.dtsi10
-rw-r--r--sound/soc/generic/audio-graph-card2.c6
-rw-r--r--sound/soc/generic/simple-card-utils.c35
-rw-r--r--sound/soc/intel/Kconfig2
-rw-r--r--sound/soc/intel/avs/apl.c6
-rw-r--r--sound/soc/intel/avs/avs.h12
-rw-r--r--sound/soc/intel/avs/board_selection.c22
-rw-r--r--sound/soc/intel/avs/boards/Kconfig10
-rw-r--r--sound/soc/intel/avs/boards/Makefile2
-rw-r--r--sound/soc/intel/avs/boards/da7219.c41
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c1
-rw-r--r--sound/soc/intel/avs/boards/max98373.c2
-rw-r--r--sound/soc/intel/avs/boards/max98927.c236
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c35
-rw-r--r--sound/soc/intel/avs/boards/rt274.c30
-rw-r--r--sound/soc/intel/avs/boards/rt286.c37
-rw-r--r--sound/soc/intel/avs/boards/rt298.c61
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c31
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c2
-rw-r--r--sound/soc/intel/avs/core.c116
-rw-r--r--sound/soc/intel/avs/ipc.c8
-rw-r--r--sound/soc/intel/avs/loader.c28
-rw-r--r--sound/soc/intel/avs/messages.c19
-rw-r--r--sound/soc/intel/avs/messages.h2
-rw-r--r--sound/soc/intel/avs/pcm.c416
-rw-r--r--sound/soc/intel/avs/skl.c4
-rw-r--r--sound/soc/intel/avs/topology.c10
-rw-r--r--sound/soc/intel/boards/Kconfig1
-rw-r--r--sound/soc/intel/boards/Makefile4
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c2
-rw-r--r--sound/soc/intel/boards/bdw_rt286.c55
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c3
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c2
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c2
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c9
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c2
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c3
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c3
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c2
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.c2
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c4
-rw-r--r--sound/soc/intel/boards/sof_es8336.c60
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c16
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c7
-rw-r--r--sound/soc/intel/boards/sof_sdw.c50
-rw-r--r--sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h300
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h10
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1308.c120
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1316.c119
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1318.c120
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c16
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c13
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c59
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c157
-rw-r--r--sound/soc/intel/skylake/skl-messages.c6
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c35
-rw-r--r--sound/soc/intel/skylake/skl.c11
-rw-r--r--sound/soc/jz4740/Kconfig1
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c485
-rw-r--r--sound/soc/jz4740/jz4740-i2s.h10
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c135
-rw-r--r--sound/soc/kirkwood/kirkwood.h2
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c6
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c1
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c1
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-mt6351.c1
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c20
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c4
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c1
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c7
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c105
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c1
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c1
-rw-r--r--sound/soc/meson/axg-pdm.c2
-rw-r--r--sound/soc/pxa/mmp-pcm.c2
-rw-r--r--sound/soc/qcom/Kconfig16
-rw-r--r--sound/soc/qcom/common.c2
-rw-r--r--sound/soc/qcom/common.h23
-rw-r--r--sound/soc/qcom/lpass-sc7180.c23
-rw-r--r--sound/soc/qcom/lpass-sc7280.c19
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c310
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.h47
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c84
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h6
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.c2
-rw-r--r--sound/soc/qcom/qdsp6/topology.c243
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c3
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c19
-rw-r--r--sound/soc/sh/Kconfig2
-rw-r--r--sound/soc/sh/rcar/adg.c4
-rw-r--r--sound/soc/sh/rcar/core.c7
-rw-r--r--sound/soc/soc-core.c25
-rw-r--r--sound/soc/soc-dai.c11
-rw-r--r--sound/soc/soc-dapm.c191
-rw-r--r--sound/soc/soc-ops.c11
-rw-r--r--sound/soc/soc-pcm.c19
-rw-r--r--sound/soc/soc-utils.c2
-rw-r--r--sound/soc/sof/Kconfig20
-rw-r--r--sound/soc/sof/Makefile6
-rw-r--r--sound/soc/sof/amd/Kconfig1
-rw-r--r--sound/soc/sof/amd/acp-common.c109
-rw-r--r--sound/soc/sof/amd/acp-ipc.c43
-rw-r--r--sound/soc/sof/amd/acp-loader.c6
-rw-r--r--sound/soc/sof/amd/acp.c12
-rw-r--r--sound/soc/sof/amd/acp.h18
-rw-r--r--sound/soc/sof/amd/rembrandt.c16
-rw-r--r--sound/soc/sof/amd/renoir.c16
-rw-r--r--sound/soc/sof/intel/Kconfig2
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/apl.c4
-rw-r--r--sound/soc/sof/intel/bdw.c6
-rw-r--r--sound/soc/sof/intel/byt.c12
-rw-r--r--sound/soc/sof/intel/cnl.c35
-rw-r--r--sound/soc/sof/intel/hda-bus.c23
-rw-r--r--sound/soc/sof/intel/hda-codec.c252
-rw-r--r--sound/soc/sof/intel/hda-common-ops.c6
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c102
-rw-r--r--sound/soc/sof/intel/hda-dai.c95
-rw-r--r--sound/soc/sof/intel/hda-dsp.c83
-rw-r--r--sound/soc/sof/intel/hda-ipc.c27
-rw-r--r--sound/soc/sof/intel/hda-loader-skl.c37
-rw-r--r--sound/soc/sof/intel/hda-loader.c98
-rw-r--r--sound/soc/sof/intel/hda-mlink.c89
-rw-r--r--sound/soc/sof/intel/hda-pcm.c3
-rw-r--r--sound/soc/sof/intel/hda-stream.c93
-rw-r--r--sound/soc/sof/intel/hda.c139
-rw-r--r--sound/soc/sof/intel/hda.h113
-rw-r--r--sound/soc/sof/intel/icl.c6
-rw-r--r--sound/soc/sof/intel/mtl.c161
-rw-r--r--sound/soc/sof/intel/mtl.h2
-rw-r--r--sound/soc/sof/intel/pci-apl.c6
-rw-r--r--sound/soc/sof/intel/pci-cnl.c9
-rw-r--r--sound/soc/sof/intel/pci-icl.c6
-rw-r--r--sound/soc/sof/intel/pci-mtl.c3
-rw-r--r--sound/soc/sof/intel/pci-tgl.c24
-rw-r--r--sound/soc/sof/intel/pci-tng.c6
-rw-r--r--sound/soc/sof/intel/shim.h3
-rw-r--r--sound/soc/sof/intel/tgl.c15
-rw-r--r--sound/soc/sof/ipc.c14
-rw-r--r--sound/soc/sof/ipc3-loader.c26
-rw-r--r--sound/soc/sof/ipc3-pcm.c2
-rw-r--r--sound/soc/sof/ipc3-topology.c51
-rw-r--r--sound/soc/sof/ipc3.c4
-rw-r--r--sound/soc/sof/ipc4-loader.c244
-rw-r--r--sound/soc/sof/ipc4-pcm.c4
-rw-r--r--sound/soc/sof/ipc4-priv.h67
-rw-r--r--sound/soc/sof/ipc4-topology.c214
-rw-r--r--sound/soc/sof/ipc4.c45
-rw-r--r--sound/soc/sof/loader.c25
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c7
-rw-r--r--sound/soc/sof/ops.h51
-rw-r--r--sound/soc/sof/sof-audio.c5
-rw-r--r--sound/soc/sof/sof-audio.h43
-rw-r--r--sound/soc/sof/sof-client-probes-ipc3.c236
-rw-r--r--sound/soc/sof/sof-client-probes-ipc4.c281
-rw-r--r--sound/soc/sof/sof-client-probes.c278
-rw-r--r--sound/soc/sof/sof-client-probes.h34
-rw-r--r--sound/soc/sof/sof-client.c34
-rw-r--r--sound/soc/sof/sof-client.h6
-rw-r--r--sound/soc/sof/sof-pci-dev.c26
-rw-r--r--sound/soc/sof/sof-priv.h36
-rw-r--r--sound/soc/sof/topology.c207
-rw-r--r--sound/soc/stm/stm32_adfsdm.c11
-rw-r--r--sound/soc/stm/stm32_i2s.c2
-rw-r--r--sound/soc/sunxi/sun50i-dmic.c5
-rw-r--r--sound/soc/tegra/tegra210_mbdrc.c4
-rw-r--r--sound/soc/tegra/tegra210_mbdrc.h2
-rw-r--r--sound/soc/ti/davinci-mcasp.c7
-rw-r--r--sound/soc/uniphier/aio-core.c11
-rw-r--r--sound/usb/card.c29
-rw-r--r--sound/usb/endpoint.c10
-rw-r--r--sound/usb/midi.c4
-rw-r--r--sound/usb/pcm.c13
-rw-r--r--sound/usb/quirks-table.h4
-rw-r--r--sound/usb/quirks.c49
-rw-r--r--sound/usb/usbaudio.h7
-rw-r--r--tools/accounting/procacct.c7
-rw-r--r--tools/arch/x86/include/asm/msr-index.h8
-rw-r--r--tools/arch/x86/intel_sdsi/intel_sdsi.c464
-rw-r--r--tools/bpf/bpftool/common.c3
-rw-r--r--tools/iio/iio_generic_buffer.c4
-rw-r--r--tools/include/uapi/linux/in.h1
-rw-r--r--tools/include/uapi/linux/stddef.h47
-rwxr-xr-xtools/kvm/kvm_stat/kvm_stat98
-rw-r--r--tools/lib/bpf/libbpf.c2
-rw-r--r--tools/lib/bpf/libbpf_probes.c2
-rw-r--r--tools/lib/bpf/ringbuf.c26
-rw-r--r--tools/memory-model/Documentation/explanation.txt7
-rw-r--r--tools/objtool/check.c10
-rw-r--r--tools/perf/.gitignore1
-rwxr-xr-xtools/perf/tests/shell/test_brstack.sh5
-rw-r--r--tools/perf/util/parse-branch-options.c4
-rw-r--r--tools/perf/util/stat-display.c6
-rw-r--r--tools/power/acpi/tools/acpidump/Makefile1
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c4
-rw-r--r--tools/power/cpupower/Makefile15
-rw-r--r--tools/power/cpupower/lib/powercap.c290
-rw-r--r--tools/power/cpupower/lib/powercap.h54
-rw-r--r--tools/power/cpupower/man/cpupower-powercap-info.125
-rw-r--r--tools/power/cpupower/po/ka.po983
-rw-r--r--tools/power/cpupower/utils/builtin.h2
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c4
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c4
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c4
-rw-r--r--tools/power/cpupower/utils/cpupower.c1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c7
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/rapl_monitor.c148
-rw-r--r--tools/power/cpupower/utils/powercap-info.c117
-rwxr-xr-xtools/power/pm-graph/sleepgraph.py2
-rw-r--r--tools/testing/cxl/Kbuild2
-rw-r--r--tools/testing/cxl/config_check.c2
-rw-r--r--tools/testing/cxl/test/cxl.c303
-rw-r--r--tools/testing/cxl/test/mem.c453
-rw-r--r--tools/testing/cxl/test/mock.c19
-rw-r--r--tools/testing/cxl/test/mock.h3
-rwxr-xr-xtools/testing/ktest/ktest.pl32
-rw-r--r--tools/testing/ktest/sample.conf8
-rwxr-xr-xtools/testing/kunit/kunit.py36
-rw-r--r--tools/testing/kunit/kunit_parser.py188
-rwxr-xr-xtools/testing/kunit/kunit_tool_test.py164
-rw-r--r--tools/testing/kunit/test_data/test_parse_ktap_output.log8
-rw-r--r--tools/testing/kunit/test_data/test_parse_subtest_header.log7
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/dimm_devs.c30
-rw-r--r--tools/testing/radix-tree/.gitignore1
-rw-r--r--tools/testing/radix-tree/Makefile19
-rw-r--r--tools/testing/radix-tree/generated/autoconf.h2
-rw-r--r--tools/testing/radix-tree/linux.c4
-rw-r--r--tools/testing/radix-tree/maple.c35770
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/alsa/.gitignore1
-rw-r--r--tools/testing/selftests/alsa/Makefile15
-rw-r--r--tools/testing/selftests/alsa/alsa-local.h24
-rw-r--r--tools/testing/selftests/alsa/conf.c448
-rw-r--r--tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf79
-rw-r--r--tools/testing/selftests/alsa/mixer-test.c53
-rw-r--r--tools/testing/selftests/alsa/pcm-test.c489
-rw-r--r--tools/testing/selftests/amd-pstate/Makefile11
-rwxr-xr-xtools/testing/selftests/amd-pstate/amd-pstate-ut.sh56
-rwxr-xr-xtools/testing/selftests/amd-pstate/basic.sh38
-rwxr-xr-xtools/testing/selftests/amd-pstate/gitsource.sh354
-rwxr-xr-xtools/testing/selftests/amd-pstate/run.sh387
-rwxr-xr-xtools/testing/selftests/amd-pstate/tbench.sh339
-rw-r--r--tools/testing/selftests/arm64/abi/hwcap.c32
-rw-r--r--tools/testing/selftests/arm64/abi/syscall-abi-asm.S4
-rw-r--r--tools/testing/selftests/arm64/fp/fp-stress.c120
-rw-r--r--tools/testing/selftests/arm64/mte/check_buffer_fill.c12
-rw-r--r--tools/testing/selftests/arm64/mte/check_mmap_options.c9
-rw-r--r--tools/testing/selftests/arm64/signal/testcases/TODO1
-rw-r--r--tools/testing/selftests/arm64/signal/testcases/testcases.c21
-rw-r--r--tools/testing/selftests/bpf/map_tests/sk_storage_map.c36
-rw-r--r--tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c8
-rw-r--r--tools/testing/selftests/bpf/prog_tests/varlen.c7
-rw-r--r--tools/testing/selftests/bpf/progs/test_varlen.c5
-rw-r--r--tools/testing/selftests/bpf/test_progs.c2
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c2
-rw-r--r--tools/testing/selftests/bpf/verifier/ref_tracking.c36
-rw-r--r--tools/testing/selftests/cgroup/cgroup_util.c5
-rwxr-xr-xtools/testing/selftests/cgroup/test_cpuset_prs.sh19
-rw-r--r--tools/testing/selftests/cgroup/test_kmem.c6
-rwxr-xr-xtools/testing/selftests/efivarfs/efivarfs.sh5
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc15
-rw-r--r--tools/testing/selftests/ftrace/test.d/functions8
-rw-r--r--tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc8
-rw-r--r--tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc7
-rw-r--r--tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc7
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-eprobe.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-dynstring.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc2
-rwxr-xr-xtools/testing/selftests/gpio/gpio-sim.sh2
-rwxr-xr-xtools/testing/selftests/kselftest_deps.sh2
-rw-r--r--tools/testing/selftests/kvm/.gitignore1
-rw-r--r--tools/testing/selftests/kvm/Makefile1
-rw-r--r--tools/testing/selftests/kvm/include/x86_64/processor.h13
-rw-r--r--tools/testing/selftests/kvm/lib/x86_64/processor.c13
-rw-r--r--tools/testing/selftests/kvm/x86_64/svm_nested_shutdown_test.c67
-rw-r--r--tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c73
-rw-r--r--tools/testing/selftests/landlock/base_test.c38
-rw-r--r--tools/testing/selftests/landlock/common.h85
-rw-r--r--tools/testing/selftests/landlock/fs_test.c468
-rw-r--r--tools/testing/selftests/lib.mk5
-rw-r--r--tools/testing/selftests/net/.gitignore1
-rw-r--r--tools/testing/selftests/net/af_unix/Makefile2
-rw-r--r--tools/testing/selftests/net/af_unix/diag_uid.c178
-rw-r--r--tools/testing/selftests/net/config2
-rwxr-xr-xtools/testing/selftests/net/fcnal-test.sh11
-rwxr-xr-xtools/testing/selftests/net/fib_nexthops.sh11
-rwxr-xr-xtools/testing/selftests/net/fib_tests.sh37
-rwxr-xr-xtools/testing/selftests/net/io_uring_zerocopy_tx.sh2
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_join.sh6
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_sockopt.sh9
-rwxr-xr-xtools/testing/selftests/net/mptcp/simult_flows.sh5
-rwxr-xr-xtools/testing/selftests/net/pmtu.sh10
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh2
-rwxr-xr-xtools/testing/selftests/net/toeplitz.sh2
-rwxr-xr-xtools/testing/selftests/net/udpgro.sh12
-rwxr-xr-xtools/testing/selftests/net/udpgro_bench.sh10
-rwxr-xr-xtools/testing/selftests/net/udpgro_frglist.sh10
-rwxr-xr-xtools/testing/selftests/net/udpgro_fwd.sh3
-rwxr-xr-xtools/testing/selftests/net/veth.sh11
-rwxr-xr-xtools/testing/selftests/netfilter/rpath.sh14
-rw-r--r--tools/testing/selftests/nolibc/Makefile3
-rw-r--r--tools/testing/selftests/nolibc/nolibc-test.c7
-rw-r--r--tools/testing/selftests/proc/proc-uptime-002.c3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/config2csv.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/config_override.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configcheck.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configinit.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-again.sh49
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-assign-cpus.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-build.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-end-run-stats.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-remote.sh13
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run-batch.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run-qemu.sh5
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-transform.sh68
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-build.sh3
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/torture.sh145
-rw-r--r--tools/testing/selftests/rtc/rtctest.c33
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c6
-rwxr-xr-xtools/testing/selftests/splice/short_splice_read.sh4
-rw-r--r--tools/testing/selftests/tdx/Makefile7
-rw-r--r--tools/testing/selftests/tdx/config1
-rw-r--r--tools/testing/selftests/tdx/tdx_guest_test.c163
-rw-r--r--tools/testing/selftests/timens/.gitignore1
-rw-r--r--tools/testing/selftests/timens/Makefile2
-rw-r--r--tools/testing/selftests/timens/vfork_exec.c139
-rw-r--r--tools/testing/selftests/tpm2/Makefile2
-rwxr-xr-xtools/testing/selftests/tpm2/test_async.sh10
-rwxr-xr-xtools/testing/selftests/tpm2/test_smoke.sh1
-rw-r--r--tools/testing/selftests/vDSO/vdso_test_getcpu.c4
-rw-r--r--tools/testing/selftests/vDSO/vdso_test_gettimeofday.c3
-rw-r--r--tools/testing/selftests/vm/.gitignore2
-rw-r--r--tools/testing/selftests/vm/pkey-x86.h12
-rw-r--r--tools/testing/selftests/vm/protection_keys.c131
-rw-r--r--tools/testing/selftests/watchdog/watchdog-test.c106
-rw-r--r--tools/testing/selftests/wireguard/qemu/kernel.config2
-rw-r--r--tools/tracing/rtla/src/osnoise.c9
-rw-r--r--tools/tracing/rtla/src/rtla.c12
-rw-r--r--tools/tracing/rtla/src/timerlat.c9
-rw-r--r--tools/verification/rv/Makefile141
-rw-r--r--tools/verification/rv/README.txt38
-rw-r--r--tools/verification/rv/include/in_kernel.h3
-rw-r--r--tools/verification/rv/include/rv.h12
-rw-r--r--tools/verification/rv/include/trace.h16
-rw-r--r--tools/verification/rv/include/utils.h8
-rw-r--r--tools/verification/rv/src/in_kernel.c698
-rw-r--r--tools/verification/rv/src/rv.c188
-rw-r--r--tools/verification/rv/src/trace.c133
-rw-r--r--tools/verification/rv/src/utils.c47
-rw-r--r--tools/vm/slabinfo-gnuplot.sh4
-rw-r--r--tools/vm/slabinfo.c6
-rw-r--r--virt/kvm/kvm_main.c52
-rw-r--r--virt/kvm/pfncache.c7
6659 files changed, 271596 insertions, 141274 deletions
diff --git a/.clang-format b/.clang-format
index 1247d54f9e49..bcf60344f9f5 100644
--- a/.clang-format
+++ b/.clang-format
@@ -222,6 +222,7 @@ ForEachMacros:
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_console'
+ - 'for_each_console_srcu'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
@@ -535,6 +536,7 @@ ForEachMacros:
- 'perf_hpp_list__for_each_sort_list_safe'
- 'perf_pmu__for_each_hybrid_pmu'
- 'ping_portaddr_for_each_entry'
+ - 'ping_portaddr_for_each_entry_rcu'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
diff --git a/.gitignore b/.gitignore
index 5da004814678..3ec73ead6757 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@
*.dtb
*.dtbo
*.dtb.S
+*.dtbo.S
*.dwo
*.elf
*.gcno
diff --git a/.mailmap b/.mailmap
index fdd7989492fc..ccba4cf0d893 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,6 +29,7 @@ Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electr
Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com>
Alexei Starovoitov <ast@kernel.org> <ast@fb.com>
Alexei Starovoitov <ast@kernel.org> <ast@plumgrid.com>
+Alex Hung <alexhung@gmail.com> <alex.hung@canonical.com>
Alex Shi <alexs@kernel.org> <alex.shi@intel.com>
Alex Shi <alexs@kernel.org> <alex.shi@linaro.org>
Alex Shi <alexs@kernel.org> <alex.shi@linux.alibaba.com>
@@ -227,6 +228,7 @@ Juha Yrjola <at solidboot.com>
Juha Yrjola <juha.yrjola@nokia.com>
Juha Yrjola <juha.yrjola@solidboot.com>
Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com>
+Iskren Chernev <me@iskren.info> <iskren.chernev@gmail.com>
Kalle Valo <kvalo@kernel.org> <kvalo@codeaurora.org>
Kalyan Thota <quic_kalyant@quicinc.com> <kalyan_t@codeaurora.org>
Kay Sievers <kay.sievers@vrfy.org>
@@ -286,6 +288,7 @@ Matthew Wilcox <willy@infradead.org> <willy@linux.intel.com>
Matthew Wilcox <willy@infradead.org> <willy@parisc-linux.org>
Matthias Fuchs <socketcan@esd.eu> <matthias.fuchs@esd.eu>
Matthieu CASTET <castet.matthieu@free.fr>
+Matti Vaittinen <mazziesaccount@gmail.com> <matti.vaittinen@fi.rohmeurope.com>
Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting>
Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com>
Matt Ranostay <mranostay@gmail.com> <matt.ranostay@intel.com>
@@ -371,6 +374,8 @@ Ricardo Ribalda <ribalda@kernel.org> <ricardo.ribalda@gmail.com>
Roman Gushchin <roman.gushchin@linux.dev> <guro@fb.com>
Roman Gushchin <roman.gushchin@linux.dev> <guroan@gmail.com>
Roman Gushchin <roman.gushchin@linux.dev> <klamm@yandex-team.ru>
+Muchun Song <muchun.song@linux.dev> <songmuchun@bytedance.com>
+Muchun Song <muchun.song@linux.dev> <smuchun@gmail.com>
Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com>
Rudolf Marek <R.Marek@sh.cvut.cz>
Rui Saraiva <rmps@joel.ist.utl.pt>
@@ -382,6 +387,7 @@ Santosh Shilimkar <santosh.shilimkar@oracle.org>
Santosh Shilimkar <ssantosh@kernel.org>
Sarangdhar Joshi <spjoshi@codeaurora.org>
Sascha Hauer <s.hauer@pengutronix.de>
+Satya Priya <quic_c_skakit@quicinc.com> <skakit@codeaurora.org>
S.Çağlar Onur <caglar@pardus.org.tr>
Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com>
Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
@@ -389,6 +395,7 @@ Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
Sebastian Reichel <sre@kernel.org> <sre@debian.org>
Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de>
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
+Shannon Nelson <shannon.nelson@amd.com> <snelson@pensando.io>
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
@@ -416,6 +423,7 @@ TripleX Chung <xxx.phy@gmail.com> <triplex@zh-kernel.org>
TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws>
+Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com>
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Uwe Kleine-König <ukleinek@strlen.de>
diff --git a/CREDITS b/CREDITS
index 1841184c834d..198f675c419e 100644
--- a/CREDITS
+++ b/CREDITS
@@ -918,6 +918,11 @@ S: Ottawa, Ontario
S: K1N 6Z9
S: CANADA
+N: Vivien Didelot
+E: vivien.didelot@gmail.com
+D: DSA framework and MV88E6XXX driver
+S: Montreal, Quebec, Canada
+
N: Jeff Dike
E: jdike@karaya.com
W: http://user-mode-linux.sourceforge.net
@@ -2447,6 +2452,10 @@ S: 482 Shadowgraph Dr.
S: San Jose, CA 95110
S: USA
+N: Michal Marek
+E: michal.lkml@markovi.net
+D: Kbuild Maintainer 2009-2017
+
N: Martin Mares
E: mj@ucw.cz
W: http://www.ucw.cz/~mj/
diff --git a/Documentation/ABI/testing/debugfs-dell-wmi-ddv b/Documentation/ABI/testing/debugfs-dell-wmi-ddv
new file mode 100644
index 000000000000..fbcc5d6f7388
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-dell-wmi-ddv
@@ -0,0 +1,21 @@
+What: /sys/kernel/debug/dell-wmi-ddv-<wmi_device_name>/fan_sensor_information
+Date: September 2022
+KernelVersion: 6.1
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ This file contains the contents of the fan sensor information buffer,
+ which contains fan sensor entries and a terminating character (0xFF).
+
+ Each fan sensor entry consists of three bytes with an unknown meaning,
+ interested people may use this file for reverse-engineering.
+
+What: /sys/kernel/debug/dell-wmi-ddv-<wmi_device_name>/thermal_sensor_information
+Date: September 2022
+KernelVersion: 6.1
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ This file contains the contents of the thermal sensor information buffer,
+ which contains thermal sensor entries and a terminating character (0xFF).
+
+ Each thermal sensor entry consists of five bytes with an unknown meaning,
+ interested people may use this file for reverse-engineering.
diff --git a/Documentation/ABI/testing/debugfs-pktcdvd b/Documentation/ABI/testing/debugfs-pktcdvd
deleted file mode 100644
index f6f65a4faea0..000000000000
--- a/Documentation/ABI/testing/debugfs-pktcdvd
+++ /dev/null
@@ -1,18 +0,0 @@
-What: /sys/kernel/debug/pktcdvd/pktcdvd[0-7]
-Date: Oct. 2006
-KernelVersion: 2.6.20
-Contact: Thomas Maier <balagi@justmail.de>
-Description:
-
-The pktcdvd module (packet writing driver) creates
-these files in debugfs:
-
-/sys/kernel/debug/pktcdvd/pktcdvd[0-7]/
-
- ==== ====== ====================================
- info 0444 Lots of driver statistics and infos.
- ==== ====== ====================================
-
-Example::
-
- cat /sys/kernel/debug/pktcdvd/pktcdvd0/info
diff --git a/Documentation/ABI/testing/sysfs-bus-nvdimm b/Documentation/ABI/testing/sysfs-bus-nvdimm
index 1c1f5acbf53d..de8c5a59c77f 100644
--- a/Documentation/ABI/testing/sysfs-bus-nvdimm
+++ b/Documentation/ABI/testing/sysfs-bus-nvdimm
@@ -41,3 +41,17 @@ KernelVersion: 5.18
Contact: Kajol Jain <kjain@linux.ibm.com>
Description: (RO) This sysfs file exposes the cpumask which is designated to
to retrieve nvdimm pmu event counter data.
+
+What: /sys/bus/nd/devices/nmemX/cxl/id
+Date: November 2022
+KernelVersion: 6.2
+Contact: Dave Jiang <dave.jiang@intel.com>
+Description: (RO) Show the id (serial) of the device. This is CXL specific.
+
+What: /sys/bus/nd/devices/nmemX/cxl/provider
+Date: November 2022
+KernelVersion: 6.2
+Contact: Dave Jiang <dave.jiang@intel.com>
+Description: (RO) Shows the CXL bridge device that ties to a CXL memory device
+ to this NVDIMM device. I.e. the parent of the device returned is
+ a /sys/bus/cxl/devices/memX instance.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 840727fc75dc..ecf47559f495 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -407,6 +407,16 @@ Description:
file contains a '1' if the memory has been published for
use outside the driver that owns the device.
+What: /sys/bus/pci/devices/.../p2pmem/allocate
+Date: August 2022
+Contact: Logan Gunthorpe <logang@deltatee.com>
+Description:
+ This file allows mapping p2pmem into userspace. For each
+ mmap() call on this file, the kernel will allocate a chunk
+ of Peer-to-Peer memory for use in Peer-to-Peer transactions.
+ This memory can be used in O_DIRECT calls to NVMe backed
+ files for Peer-to-Peer copies.
+
What: /sys/bus/pci/devices/.../link/clkpm
/sys/bus/pci/devices/.../link/l0s_aspm
/sys/bus/pci/devices/.../link/l1_aspm
diff --git a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor
index d76cd3946434..c800621eff95 100644
--- a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor
+++ b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor
@@ -5,6 +5,9 @@ Contact: linux-mtd@lists.infradead.org
Description: (RO) The JEDEC ID of the SPI NOR flash as reported by the
flash device.
+ The attribute is not present if the flash doesn't support
+ the "Read JEDEC ID" command (9Fh). This is the case for
+ non-JEDEC compliant flashes.
What: /sys/bus/spi/devices/.../spi-nor/manufacturer
Date: April 2021
@@ -12,6 +15,9 @@ KernelVersion: 5.14
Contact: linux-mtd@lists.infradead.org
Description: (RO) Manufacturer of the SPI NOR flash.
+ The attribute is not present if the flash device isn't
+ known to the kernel and is only probed by its SFDP
+ tables.
What: /sys/bus/spi/devices/.../spi-nor/partname
Date: April 2021
diff --git a/Documentation/ABI/testing/sysfs-class-pktcdvd b/Documentation/ABI/testing/sysfs-class-pktcdvd
deleted file mode 100644
index ba1ce626591d..000000000000
--- a/Documentation/ABI/testing/sysfs-class-pktcdvd
+++ /dev/null
@@ -1,97 +0,0 @@
-sysfs interface
----------------
-The pktcdvd module (packet writing driver) creates the following files in the
-sysfs: (<devid> is in the format major:minor)
-
-What: /sys/class/pktcdvd/add
-What: /sys/class/pktcdvd/remove
-What: /sys/class/pktcdvd/device_map
-Date: Oct. 2006
-KernelVersion: 2.6.20
-Contact: Thomas Maier <balagi@justmail.de>
-Description:
-
- ========== ==============================================
- add (WO) Write a block device id (major:minor) to
- create a new pktcdvd device and map it to the
- block device.
-
- remove (WO) Write the pktcdvd device id (major:minor)
- to remove the pktcdvd device.
-
- device_map (RO) Shows the device mapping in format:
- pktcdvd[0-7] <pktdevid> <blkdevid>
- ========== ==============================================
-
-
-What: /sys/class/pktcdvd/pktcdvd[0-7]/dev
-What: /sys/class/pktcdvd/pktcdvd[0-7]/uevent
-Date: Oct. 2006
-KernelVersion: 2.6.20
-Contact: Thomas Maier <balagi@justmail.de>
-Description:
- dev: (RO) Device id
-
- uevent: (WO) To send a uevent
-
-
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/packets_started
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/packets_finished
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/kb_written
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/kb_read
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/kb_read_gather
-What: /sys/class/pktcdvd/pktcdvd[0-7]/stat/reset
-Date: Oct. 2006
-KernelVersion: 2.6.20
-Contact: Thomas Maier <balagi@justmail.de>
-Description:
- packets_started: (RO) Number of started packets.
-
- packets_finished: (RO) Number of finished packets.
-
- kb_written: (RO) kBytes written.
-
- kb_read: (RO) kBytes read.
-
- kb_read_gather: (RO) kBytes read to fill write packets.
-
- reset: (WO) Write any value to it to reset
- pktcdvd device statistic values, like
- bytes read/written.
-
-
-What: /sys/class/pktcdvd/pktcdvd[0-7]/write_queue/size
-What: /sys/class/pktcdvd/pktcdvd[0-7]/write_queue/congestion_off
-What: /sys/class/pktcdvd/pktcdvd[0-7]/write_queue/congestion_on
-Date: Oct. 2006
-KernelVersion: 2.6.20
-Contact: Thomas Maier <balagi@justmail.de>
-Description:
- ============== ================================================
- size (RO) Contains the size of the bio write queue.
-
- congestion_off (RW) If bio write queue size is below this mark,
- accept new bio requests from the block layer.
-
- congestion_on (RW) If bio write queue size is higher as this
- mark, do no longer accept bio write requests
- from the block layer and wait till the pktcdvd
- device has processed enough bio's so that bio
- write queue size is below congestion off mark.
- A value of <= 0 disables congestion control.
- ============== ================================================
-
-
-Example:
---------
-To use the pktcdvd sysfs interface directly, you can do::
-
- # create a new pktcdvd device mapped to /dev/hdc
- echo "22:0" >/sys/class/pktcdvd/add
- cat /sys/class/pktcdvd/device_map
- # assuming device pktcdvd0 was created, look at stat's
- cat /sys/class/pktcdvd/pktcdvd0/stat/kb_written
- # print the device id of the mapped block device
- fgrep pktcdvd0 /sys/class/pktcdvd/device_map
- # remove device, using pktcdvd0 device id 253:0
- echo "253:0" >/sys/class/pktcdvd/remove
diff --git a/Documentation/ABI/testing/sysfs-devices-mapping b/Documentation/ABI/testing/sysfs-devices-mapping
index 8d202bac9394..2eee1446ad4c 100644
--- a/Documentation/ABI/testing/sysfs-devices-mapping
+++ b/Documentation/ABI/testing/sysfs-devices-mapping
@@ -1,6 +1,6 @@
What: /sys/devices/uncore_iio_x/dieX
Date: February 2020
-Contact: Roman Sudarikov <roman.sudarikov@linux.intel.com>
+Contact: Alexander Antonov <alexander.antonov@linux.intel.com>
Description:
Each IIO stack (PCIe root port) has its own IIO PMON block, so
each dieX file (where X is die number) holds "Segment:Root Bus"
@@ -32,3 +32,31 @@ Description:
IIO PMU 0 on die 1 belongs to PCI RP on bus 0x40, domain 0x0000
IIO PMU 0 on die 2 belongs to PCI RP on bus 0x80, domain 0x0000
IIO PMU 0 on die 3 belongs to PCI RP on bus 0xc0, domain 0x0000
+
+What: /sys/devices/uncore_upi_x/dieX
+Date: March 2022
+Contact: Alexander Antonov <alexander.antonov@linux.intel.com>
+Description:
+ Each /sys/devices/uncore_upi_X/dieY file holds "upi_Z,die_W"
+ value that means UPI link number X on die Y is connected to UPI
+ link Z on die W and this link between sockets can be monitored
+ by UPI PMON block.
+ For example, 4-die Sapphire Rapids platform has the following
+ UPI 0 topology::
+
+ # tail /sys/devices/uncore_upi_0/die*
+ ==> /sys/devices/uncore_upi_0/die0 <==
+ upi_1,die_1
+ ==> /sys/devices/uncore_upi_0/die1 <==
+ upi_0,die_3
+ ==> /sys/devices/uncore_upi_0/die2 <==
+ upi_1,die_3
+ ==> /sys/devices/uncore_upi_0/die3 <==
+ upi_0,die_1
+
+ Which means::
+
+ UPI link 0 on die 0 is connected to UPI link 1 on die 1
+ UPI link 0 on die 1 is connected to UPI link 0 on die 3
+ UPI link 0 on die 2 is connected to UPI link 1 on die 3
+ UPI link 0 on die 3 is connected to UPI link 0 on die 1 \ No newline at end of file
diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
new file mode 100644
index 000000000000..2d6a472eef88
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
@@ -0,0 +1,75 @@
+What: /sys/devices/.../hwmon/hwmon<i>/in0_input
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RO. Current Voltage in millivolt.
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/power1_max
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RW. Card reactive sustained (PL1/Tau) power limit in microwatts.
+
+ The power controller will throttle the operating frequency
+ if the power averaged over a window (typically seconds)
+ exceeds this limit.
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/power1_rated_max
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RO. Card default power limit (default TDP setting).
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/power1_max_interval
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RW. Sustained power limit interval (Tau in PL1/Tau) in
+ milliseconds over which sustained power is averaged.
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/power1_crit
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RW. Card reactive critical (I1) power limit in microwatts.
+
+ Card reactive critical (I1) power limit in microwatts is exposed
+ for client products. The power controller will throttle the
+ operating frequency if the power averaged over a window exceeds
+ this limit.
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/curr1_crit
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RW. Card reactive critical (I1) power limit in milliamperes.
+
+ Card reactive critical (I1) power limit in milliamperes is
+ exposed for server products. The power controller will throttle
+ the operating frequency if the power averaged over a window
+ exceeds this limit.
+
+ Only supported for particular Intel i915 graphics platforms.
+
+What: /sys/devices/.../hwmon/hwmon<i>/energy1_input
+Date: February 2023
+KernelVersion: 6.2
+Contact: intel-gfx@lists.freedesktop.org
+Description: RO. Energy input of device or gt in microjoules.
+
+ For i915 device level hwmon devices (name "i915") this
+ reflects energy input for the entire device. For gt level
+ hwmon devices (name "i915_gtN") this reflects energy input
+ for the gt.
+
+ Only supported for particular Intel i915 graphics platforms.
diff --git a/Documentation/ABI/testing/sysfs-driver-intel_sdsi b/Documentation/ABI/testing/sysfs-driver-intel_sdsi
index 96b92c105ec4..f8afed127107 100644
--- a/Documentation/ABI/testing/sysfs-driver-intel_sdsi
+++ b/Documentation/ABI/testing/sysfs-driver-intel_sdsi
@@ -4,21 +4,21 @@ KernelVersion: 5.18
Contact: "David E. Box" <david.e.box@linux.intel.com>
Description:
This directory contains interface files for accessing Intel
- Software Defined Silicon (SDSi) features on a CPU. X
- represents the socket instance (though not the socket ID).
- The socket ID is determined by reading the registers file
- and decoding it per the specification.
+ On Demand (formerly Software Defined Silicon or SDSi) features
+ on a CPU. X represents the socket instance (though not the
+ socket ID). The socket ID is determined by reading the
+ registers file and decoding it per the specification.
- Some files communicate with SDSi hardware through a mailbox.
- Should the operation fail, one of the following error codes
- may be returned:
+ Some files communicate with On Demand hardware through a
+ mailbox. Should the operation fail, one of the following error
+ codes may be returned:
========== =====
Error Code Cause
========== =====
EIO General mailbox failure. Log may indicate cause.
EBUSY Mailbox is owned by another agent.
- EPERM SDSI capability is not enabled in hardware.
+ EPERM On Demand capability is not enabled in hardware.
EPROTO Failure in mailbox protocol detected by driver.
See log for details.
EOVERFLOW For provision commands, the size of the data
@@ -54,8 +54,8 @@ KernelVersion: 5.18
Contact: "David E. Box" <david.e.box@linux.intel.com>
Description:
(WO) Used to write an Authentication Key Certificate (AKC) to
- the SDSi NVRAM for the CPU. The AKC is used to authenticate a
- Capability Activation Payload. Mailbox command.
+ the On Demand NVRAM for the CPU. The AKC is used to authenticate
+ a Capability Activation Payload. Mailbox command.
What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_cap
Date: Feb 2022
@@ -63,17 +63,28 @@ KernelVersion: 5.18
Contact: "David E. Box" <david.e.box@linux.intel.com>
Description:
(WO) Used to write a Capability Activation Payload (CAP) to the
- SDSi NVRAM for the CPU. CAPs are used to activate a given CPU
- feature. A CAP is validated by SDSi hardware using a previously
- provisioned AKC file. Upon successful authentication, the CPU
- configuration is updated. A cold reboot is required to fully
- activate the feature. Mailbox command.
+ On Demand NVRAM for the CPU. CAPs are used to activate a given
+ CPU feature. A CAP is validated by On Demand hardware using a
+ previously provisioned AKC file. Upon successful authentication,
+ the CPU configuration is updated. A cold reboot is required to
+ fully activate the feature. Mailbox command.
+
+What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/meter_certificate
+Date: Nov 2022
+KernelVersion: 6.2
+Contact: "David E. Box" <david.e.box@linux.intel.com>
+Description:
+ (RO) Used to read back the current meter certificate for the CPU
+ from Intel On Demand hardware. The meter certificate contains
+ utilization metrics of On Demand enabled features. Mailbox
+ command.
What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/state_certificate
Date: Feb 2022
KernelVersion: 5.18
Contact: "David E. Box" <david.e.box@linux.intel.com>
Description:
- (RO) Used to read back the current State Certificate for the CPU
- from SDSi hardware. The State Certificate contains information
- about the current licenses on the CPU. Mailbox command.
+ (RO) Used to read back the current state certificate for the CPU
+ from On Demand hardware. The state certificate contains
+ information about the current licenses on the CPU. Mailbox
+ command.
diff --git a/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv b/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
new file mode 100644
index 000000000000..1d97ad615c66
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
@@ -0,0 +1,7 @@
+What: /sys/class/power_supply/<battery_name>/eppid
+Date: September 2022
+KernelVersion: 6.1
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Reports the Dell ePPID (electronic Dell Piece Part Identification)
+ of the ACPI battery.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 64d44c1ecad3..bb73dcb5ed05 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -95,6 +95,15 @@ htmldocs:
@$(srctree)/scripts/sphinx-pre-install --version-check
@+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var)))
+texinfodocs:
+ @$(srctree)/scripts/sphinx-pre-install --version-check
+ @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,texinfo,$(var),texinfo,$(var)))
+
+# Note: the 'info' Make target is generated by sphinx itself when
+# running the texinfodocs target define above.
+infodocs: texinfodocs
+ $(MAKE) -C $(BUILDDIR)/texinfo info
+
linkcheckdocs:
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,linkcheck,$(var),,$(var)))
@@ -143,6 +152,8 @@ cleandocs:
dochelp:
@echo ' Linux kernel internal documentation in different formats from ReST:'
@echo ' htmldocs - HTML'
+ @echo ' texinfodocs - Texinfo'
+ @echo ' infodocs - Info'
@echo ' latexdocs - LaTeX'
@echo ' pdfdocs - PDF'
@echo ' epubdocs - EPUB'
diff --git a/Documentation/PCI/msi-howto.rst b/Documentation/PCI/msi-howto.rst
index aa2046af69f7..8ae461e97c54 100644
--- a/Documentation/PCI/msi-howto.rst
+++ b/Documentation/PCI/msi-howto.rst
@@ -285,3 +285,13 @@ to bridges between the PCI root and the device, MSIs are disabled.
It is also worth checking the device driver to see whether it supports MSIs.
For example, it may contain calls to pci_alloc_irq_vectors() with the
PCI_IRQ_MSI or PCI_IRQ_MSIX flags.
+
+
+List of device drivers MSI(-X) APIs
+===================================
+
+The PCI/MSI subystem has a dedicated C file for its exported device driver
+APIs — `drivers/pci/msi/api.c`. The following functions are exported:
+
+.. kernel-doc:: drivers/pci/msi/api.c
+ :export:
diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst
index 187f43a03200..bdafeb4b66dc 100644
--- a/Documentation/PCI/pci-error-recovery.rst
+++ b/Documentation/PCI/pci-error-recovery.rst
@@ -83,6 +83,7 @@ This structure has the form::
int (*mmio_enabled)(struct pci_dev *dev);
int (*slot_reset)(struct pci_dev *dev);
void (*resume)(struct pci_dev *dev);
+ void (*cor_error_detected)(struct pci_dev *dev);
};
The possible channel states are::
@@ -422,5 +423,11 @@ That is, the recovery API only requires that:
- drivers/net/cxgb3
- drivers/net/s2io.c
+ The cor_error_detected() callback is invoked in handle_error_source() when
+ the error severity is "correctable". The callback is optional and allows
+ additional logging to be done if desired. See example:
+
+ - drivers/cxl/pci.c
+
The End
-------
diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst
index a0f8164c8513..49387d823619 100644
--- a/Documentation/RCU/Design/Requirements/Requirements.rst
+++ b/Documentation/RCU/Design/Requirements/Requirements.rst
@@ -1858,7 +1858,7 @@ 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 mod_timer() must be dealt
-with via del_timer_sync() or similar.
+with via timer_shutdown_sync() or similar.
Unfortunately, there is no way to cancel an RCU callback; once you
invoke call_rcu(), the callback function is eventually going to be
diff --git a/Documentation/RCU/arrayRCU.rst b/Documentation/RCU/arrayRCU.rst
deleted file mode 100644
index a5f2ff8fc54c..000000000000
--- a/Documentation/RCU/arrayRCU.rst
+++ /dev/null
@@ -1,165 +0,0 @@
-.. _array_rcu_doc:
-
-Using RCU to Protect Read-Mostly Arrays
-=======================================
-
-Although RCU is more commonly used to protect linked lists, it can
-also be used to protect arrays. Three situations are as follows:
-
-1. :ref:`Hash Tables <hash_tables>`
-
-2. :ref:`Static Arrays <static_arrays>`
-
-3. :ref:`Resizable Arrays <resizable_arrays>`
-
-Each of these three situations involves an RCU-protected pointer to an
-array that is separately indexed. It might be tempting to consider use
-of RCU to instead protect the index into an array, however, this use
-case is **not** supported. The problem with RCU-protected indexes into
-arrays is that compilers can play way too many optimization games with
-integers, which means that the rules governing handling of these indexes
-are far more trouble than they are worth. If RCU-protected indexes into
-arrays prove to be particularly valuable (which they have not thus far),
-explicit cooperation from the compiler will be required to permit them
-to be safely used.
-
-That aside, each of the three RCU-protected pointer situations are
-described in the following sections.
-
-.. _hash_tables:
-
-Situation 1: Hash Tables
-------------------------
-
-Hash tables are often implemented as an array, where each array entry
-has a linked-list hash chain. Each hash chain can be protected by RCU
-as described in listRCU.rst. This approach also applies to other
-array-of-list situations, such as radix trees.
-
-.. _static_arrays:
-
-Situation 2: Static Arrays
---------------------------
-
-Static arrays, where the data (rather than a pointer to the data) is
-located in each array element, and where the array is never resized,
-have not been used with RCU. Rik van Riel recommends using seqlock in
-this situation, which would also have minimal read-side overhead as long
-as updates are rare.
-
-Quick Quiz:
- Why is it so important that updates be rare when using seqlock?
-
-:ref:`Answer to Quick Quiz <answer_quick_quiz_seqlock>`
-
-.. _resizable_arrays:
-
-Situation 3: Resizable Arrays
-------------------------------
-
-Use of RCU for resizable arrays is demonstrated by the grow_ary()
-function formerly used by the System V IPC code. The array is used
-to map from semaphore, message-queue, and shared-memory IDs to the data
-structure that represents the corresponding IPC construct. The grow_ary()
-function does not acquire any locks; instead its caller must hold the
-ids->sem semaphore.
-
-The grow_ary() function, shown below, does some limit checks, allocates a
-new ipc_id_ary, copies the old to the new portion of the new, initializes
-the remainder of the new, updates the ids->entries pointer to point to
-the new array, and invokes ipc_rcu_putref() to free up the old array.
-Note that rcu_assign_pointer() is used to update the ids->entries pointer,
-which includes any memory barriers required on whatever architecture
-you are running on::
-
- static int grow_ary(struct ipc_ids* ids, int newsize)
- {
- struct ipc_id_ary* new;
- struct ipc_id_ary* old;
- int i;
- int size = ids->entries->size;
-
- if(newsize > IPCMNI)
- newsize = IPCMNI;
- if(newsize <= size)
- return newsize;
-
- new = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*newsize +
- sizeof(struct ipc_id_ary));
- if(new == NULL)
- return size;
- new->size = newsize;
- memcpy(new->p, ids->entries->p,
- sizeof(struct kern_ipc_perm *)*size +
- sizeof(struct ipc_id_ary));
- for(i=size;i<newsize;i++) {
- new->p[i] = NULL;
- }
- old = ids->entries;
-
- /*
- * Use rcu_assign_pointer() to make sure the memcpyed
- * contents of the new array are visible before the new
- * array becomes visible.
- */
- rcu_assign_pointer(ids->entries, new);
-
- ipc_rcu_putref(old);
- return newsize;
- }
-
-The ipc_rcu_putref() function decrements the array's reference count
-and then, if the reference count has dropped to zero, uses call_rcu()
-to free the array after a grace period has elapsed.
-
-The array is traversed by the ipc_lock() function. This function
-indexes into the array under the protection of rcu_read_lock(),
-using rcu_dereference() to pick up the pointer to the array so
-that it may later safely be dereferenced -- memory barriers are
-required on the Alpha CPU. Since the size of the array is stored
-with the array itself, there can be no array-size mismatches, so
-a simple check suffices. The pointer to the structure corresponding
-to the desired IPC object is placed in "out", with NULL indicating
-a non-existent entry. After acquiring "out->lock", the "out->deleted"
-flag indicates whether the IPC object is in the process of being
-deleted, and, if not, the pointer is returned::
-
- struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
- {
- struct kern_ipc_perm* out;
- int lid = id % SEQ_MULTIPLIER;
- struct ipc_id_ary* entries;
-
- rcu_read_lock();
- entries = rcu_dereference(ids->entries);
- if(lid >= entries->size) {
- rcu_read_unlock();
- return NULL;
- }
- out = entries->p[lid];
- if(out == NULL) {
- rcu_read_unlock();
- return NULL;
- }
- spin_lock(&out->lock);
-
- /* ipc_rmid() may have already freed the ID while ipc_lock
- * was spinning: here verify that the structure is still valid
- */
- if (out->deleted) {
- spin_unlock(&out->lock);
- rcu_read_unlock();
- return NULL;
- }
- return out;
- }
-
-.. _answer_quick_quiz_seqlock:
-
-Answer to Quick Quiz:
- Why is it so important that updates be rare when using seqlock?
-
- The reason that it is important that updates be rare when
- using seqlock is that frequent updates can livelock readers.
- One way to avoid this problem is to assign a seqlock for
- each array entry rather than to the entire array.
diff --git a/Documentation/RCU/checklist.rst b/Documentation/RCU/checklist.rst
index 048c5bc1f813..cc361fb01ed4 100644
--- a/Documentation/RCU/checklist.rst
+++ b/Documentation/RCU/checklist.rst
@@ -32,8 +32,8 @@ over a rather long period of time, but improvements are always welcome!
for lockless updates. This does result in the mildly
counter-intuitive situation where rcu_read_lock() and
rcu_read_unlock() are used to protect updates, however, this
- approach provides the same potential simplifications that garbage
- collectors do.
+ approach can provide the same simplifications to certain types
+ of lockless algorithms that garbage collectors do.
1. Does the update code have proper mutual exclusion?
@@ -49,12 +49,12 @@ over a rather long period of time, but improvements are always welcome!
them -- even x86 allows later loads to be reordered to precede
earlier stores), and be prepared to explain why this added
complexity is worthwhile. If you choose #c, be prepared to
- explain how this single task does not become a major bottleneck on
- big multiprocessor machines (for example, if the task is updating
- information relating to itself that other tasks can read, there
- by definition can be no bottleneck). Note that the definition
- of "large" has changed significantly: Eight CPUs was "large"
- in the year 2000, but a hundred CPUs was unremarkable in 2017.
+ explain how this single task does not become a major bottleneck
+ on large systems (for example, if the task is updating information
+ relating to itself that other tasks can read, there by definition
+ can be no bottleneck). Note that the definition of "large" has
+ changed significantly: Eight CPUs was "large" in the year 2000,
+ but a hundred CPUs was unremarkable in 2017.
2. Do the RCU read-side critical sections make proper use of
rcu_read_lock() and friends? These primitives are needed
@@ -97,33 +97,38 @@ over a rather long period of time, but improvements are always welcome!
b. Proceed as in (a) above, but also maintain per-element
locks (that are acquired by both readers and writers)
- that guard per-element state. Of course, fields that
- the readers refrain from accessing can be guarded by
- some other lock acquired only by updaters, if desired.
+ that guard per-element state. Fields that the readers
+ refrain from accessing can be guarded by some other lock
+ acquired only by updaters, if desired.
- This works quite well, also.
+ This also works quite well.
c. Make updates appear atomic to readers. For example,
pointer updates to properly aligned fields will
appear atomic, as will individual atomic primitives.
Sequences of operations performed under a lock will *not*
appear to be atomic to RCU readers, nor will sequences
- of multiple atomic primitives.
+ of multiple atomic primitives. One alternative is to
+ move multiple individual fields to a separate structure,
+ thus solving the multiple-field problem by imposing an
+ additional level of indirection.
This can work, but is starting to get a bit tricky.
- d. Carefully order the updates and the reads so that
- readers see valid data at all phases of the update.
- This is often more difficult than it sounds, especially
- given modern CPUs' tendency to reorder memory references.
- One must usually liberally sprinkle memory barriers
- (smp_wmb(), smp_rmb(), smp_mb()) through the code,
- making it difficult to understand and to test.
-
- It is usually better to group the changing data into
- a separate structure, so that the change may be made
- to appear atomic by updating a pointer to reference
- a new structure containing updated values.
+ d. Carefully order the updates and the reads so that readers
+ see valid data at all phases of the update. This is often
+ more difficult than it sounds, especially given modern
+ CPUs' tendency to reorder memory references. One must
+ usually liberally sprinkle memory-ordering operations
+ through the code, making it difficult to understand and
+ to test. Where it works, it is better to use things
+ like smp_store_release() and smp_load_acquire(), but in
+ some cases the smp_mb() full memory barrier is required.
+
+ As noted earlier, it is usually better to group the
+ changing data into a separate structure, so that the
+ change may be made to appear atomic by updating a pointer
+ to reference a new structure containing updated values.
4. Weakly ordered CPUs pose special challenges. Almost all CPUs
are weakly ordered -- even x86 CPUs allow later loads to be
@@ -188,26 +193,29 @@ over a rather long period of time, but improvements are always welcome!
when publicizing a pointer to a structure that can
be traversed by an RCU read-side critical section.
-5. If call_rcu() or call_srcu() is used, the callback function will
- be called from softirq context. In particular, it cannot block.
- If you need the callback to block, run that code in a workqueue
- handler scheduled from the callback. The queue_rcu_work()
- function does this for you in the case of call_rcu().
+5. If any of call_rcu(), call_srcu(), call_rcu_tasks(),
+ call_rcu_tasks_rude(), or call_rcu_tasks_trace() is used,
+ the callback function may be invoked from softirq context,
+ and in any case with bottom halves disabled. In particular,
+ this callback function cannot block. If you need the callback
+ to block, run that code in a workqueue handler scheduled from
+ the callback. The queue_rcu_work() function does this for you
+ in the case of call_rcu().
6. Since synchronize_rcu() can block, it cannot be called
from any sort of irq context. The same rule applies
- for synchronize_srcu(), synchronize_rcu_expedited(), and
- synchronize_srcu_expedited().
+ for synchronize_srcu(), synchronize_rcu_expedited(),
+ synchronize_srcu_expedited(), synchronize_rcu_tasks(),
+ synchronize_rcu_tasks_rude(), and synchronize_rcu_tasks_trace().
The expedited forms of these primitives have the same semantics
- as the non-expedited forms, but expediting is both expensive and
- (with the exception of synchronize_srcu_expedited()) unfriendly
- to real-time workloads. Use of the expedited primitives should
- be restricted to rare configuration-change operations that would
- not normally be undertaken while a real-time workload is running.
- However, real-time workloads can use rcupdate.rcu_normal kernel
- boot parameter to completely disable expedited grace periods,
- though this might have performance implications.
+ as the non-expedited forms, but expediting is more CPU intensive.
+ Use of the expedited primitives should be restricted to rare
+ configuration-change operations that would not normally be
+ undertaken while a real-time workload is running. Note that
+ IPI-sensitive real-time workloads can use the rcupdate.rcu_normal
+ kernel boot parameter to completely disable expedited grace
+ periods, though this might have performance implications.
In particular, if you find yourself invoking one of the expedited
primitives repeatedly in a loop, please do everyone a favor:
@@ -215,8 +223,9 @@ over a rather long period of time, but improvements are always welcome!
a single non-expedited primitive to cover the entire batch.
This will very likely be faster than the loop containing the
expedited primitive, and will be much much easier on the rest
- of the system, especially to real-time workloads running on
- the rest of the system.
+ of the system, especially to real-time workloads running on the
+ rest of the system. Alternatively, instead use asynchronous
+ primitives such as call_rcu().
7. As of v4.20, a given kernel implements only one RCU flavor, which
is RCU-sched for PREEMPTION=n and RCU-preempt for PREEMPTION=y.
@@ -239,7 +248,8 @@ over a rather long period of time, but improvements are always welcome!
the corresponding readers must use rcu_read_lock_trace() and
rcu_read_unlock_trace(). If an updater uses call_rcu_tasks_rude()
or synchronize_rcu_tasks_rude(), then the corresponding readers
- must use anything that disables interrupts.
+ must use anything that disables preemption, for example,
+ preempt_disable() and preempt_enable().
Mixing things up will result in confusion and broken kernels, and
has even resulted in an exploitable security issue. Therefore,
@@ -253,15 +263,16 @@ over a rather long period of time, but improvements are always welcome!
that this usage is safe is that readers can use anything that
disables BH when updaters use call_rcu() or synchronize_rcu().
-8. Although synchronize_rcu() is slower than is call_rcu(), it
- usually results in simpler code. So, unless update performance is
- critically important, the updaters cannot block, or the latency of
- synchronize_rcu() is visible from userspace, synchronize_rcu()
- should be used in preference to call_rcu(). Furthermore,
- kfree_rcu() usually results in even simpler code than does
- synchronize_rcu() without synchronize_rcu()'s multi-millisecond
- latency. So please take advantage of kfree_rcu()'s "fire and
- forget" memory-freeing capabilities where it applies.
+8. Although synchronize_rcu() is slower than is call_rcu(),
+ it usually results in simpler code. So, unless update
+ performance is critically important, the updaters cannot block,
+ or the latency of synchronize_rcu() is visible from userspace,
+ synchronize_rcu() should be used in preference to call_rcu().
+ Furthermore, kfree_rcu() and kvfree_rcu() usually result
+ in even simpler code than does synchronize_rcu() without
+ synchronize_rcu()'s multi-millisecond latency. So please take
+ advantage of kfree_rcu()'s and kvfree_rcu()'s "fire and forget"
+ memory-freeing capabilities where it applies.
An especially important property of the synchronize_rcu()
primitive is that it automatically self-limits: if grace periods
@@ -271,8 +282,8 @@ over a rather long period of time, but improvements are always welcome!
cases where grace periods are delayed, as failing to do so can
result in excessive realtime latencies or even OOM conditions.
- Ways of gaining this self-limiting property when using call_rcu()
- include:
+ Ways of gaining this self-limiting property when using call_rcu(),
+ kfree_rcu(), or kvfree_rcu() include:
a. Keeping a count of the number of data-structure elements
used by the RCU-protected data structure, including
@@ -304,18 +315,21 @@ over a rather long period of time, but improvements are always welcome!
here is that superuser already has lots of ways to crash
the machine.
- d. Periodically invoke synchronize_rcu(), permitting a limited
- number of updates per grace period. Better yet, periodically
- invoke rcu_barrier() to wait for all outstanding callbacks.
+ d. Periodically invoke rcu_barrier(), permitting a limited
+ number of updates per grace period.
- The same cautions apply to call_srcu() and kfree_rcu().
+ The same cautions apply to call_srcu(), call_rcu_tasks(),
+ call_rcu_tasks_rude(), and call_rcu_tasks_trace(). This is
+ why there is an srcu_barrier(), rcu_barrier_tasks(),
+ rcu_barrier_tasks_rude(), and rcu_barrier_tasks_rude(),
+ respectively.
- Note that although these primitives do take action to avoid memory
- exhaustion when any given CPU has too many callbacks, a determined
- user could still exhaust memory. This is especially the case
- if a system with a large number of CPUs has been configured to
- offload all of its RCU callbacks onto a single CPU, or if the
- system has relatively little free memory.
+ Note that although these primitives do take action to avoid
+ memory exhaustion when any given CPU has too many callbacks,
+ a determined user or administrator can still exhaust memory.
+ This is especially the case if a system with a large number of
+ CPUs has been configured to offload all of its RCU callbacks onto
+ a single CPU, or if the system has relatively little free memory.
9. All RCU list-traversal primitives, which include
rcu_dereference(), list_for_each_entry_rcu(), and
@@ -344,14 +358,14 @@ over a rather long period of time, but improvements are always welcome!
and you don't hold the appropriate update-side lock, you *must*
use the "_rcu()" variants of the list macros. Failing to do so
will break Alpha, cause aggressive compilers to generate bad code,
- and confuse people trying to read your code.
+ and confuse people trying to understand your code.
11. Any lock acquired by an RCU callback must be acquired elsewhere
- with softirq disabled, e.g., via spin_lock_irqsave(),
- spin_lock_bh(), etc. Failing to disable softirq on a given
- acquisition of that lock will result in deadlock as soon as
- the RCU softirq handler happens to run your RCU callback while
- interrupting that acquisition's critical section.
+ with softirq disabled, e.g., via spin_lock_bh(). Failing to
+ disable softirq on a given acquisition of that lock will result
+ in deadlock as soon as the RCU softirq handler happens to run
+ your RCU callback while interrupting that acquisition's critical
+ section.
12. RCU callbacks can be and are executed in parallel. In many cases,
the callback code simply wrappers around kfree(), so that this
@@ -372,7 +386,17 @@ over a rather long period of time, but improvements are always welcome!
for some real-time workloads, this is the whole point of using
the rcu_nocbs= kernel boot parameter.
-13. Unlike other forms of RCU, it *is* permissible to block in an
+ In addition, do not assume that callbacks queued in a given order
+ will be invoked in that order, even if they all are queued on the
+ same CPU. Furthermore, do not assume that same-CPU callbacks will
+ be invoked serially. For example, in recent kernels, CPUs can be
+ switched between offloaded and de-offloaded callback invocation,
+ and while a given CPU is undergoing such a switch, its callbacks
+ might be concurrently invoked by that CPU's softirq handler and
+ that CPU's rcuo kthread. At such times, that CPU's callbacks
+ might be executed both concurrently and out of order.
+
+13. Unlike most flavors of RCU, it *is* permissible to block in an
SRCU read-side critical section (demarked by srcu_read_lock()
and srcu_read_unlock()), hence the "SRCU": "sleepable RCU".
Please note that if you don't need to sleep in read-side critical
@@ -412,6 +436,12 @@ over a rather long period of time, but improvements are always welcome!
never sends IPIs to other CPUs, so it is easier on
real-time workloads than is synchronize_rcu_expedited().
+ It is also permissible to sleep in RCU Tasks Trace read-side
+ critical, which are delimited by rcu_read_lock_trace() and
+ rcu_read_unlock_trace(). However, this is a specialized flavor
+ of RCU, and you should not use it without first checking with
+ its current users. In most cases, you should instead use SRCU.
+
Note that rcu_assign_pointer() relates to SRCU just as it does to
other forms of RCU, but instead of rcu_dereference() you should
use srcu_dereference() in order to avoid lockdep splats.
@@ -442,50 +472,62 @@ over a rather long period of time, but improvements are always welcome!
find problems as follows:
CONFIG_PROVE_LOCKING:
- check that accesses to RCU-protected data
- structures are carried out under the proper RCU
- read-side critical section, while holding the right
- combination of locks, or whatever other conditions
- are appropriate.
+ check that accesses to RCU-protected data structures
+ are carried out under the proper RCU read-side critical
+ section, while holding the right combination of locks,
+ or whatever other conditions are appropriate.
CONFIG_DEBUG_OBJECTS_RCU_HEAD:
- check that you don't pass the
- same object to call_rcu() (or friends) before an RCU
- grace period has elapsed since the last time that you
- passed that same object to call_rcu() (or friends).
+ check that you don't pass the same object to call_rcu()
+ (or friends) before an RCU grace period has elapsed
+ since the last time that you passed that same object to
+ call_rcu() (or friends).
__rcu sparse checks:
- tag the pointer to the RCU-protected data
- structure with __rcu, and sparse will warn you if you
- access that pointer without the services of one of the
- variants of rcu_dereference().
+ tag the pointer to the RCU-protected data structure
+ with __rcu, and sparse will warn you if you access that
+ pointer without the services of one of the variants
+ of rcu_dereference().
These debugging aids can help you find problems that are
otherwise extremely difficult to spot.
-17. If you register a callback using call_rcu() or call_srcu(), and
- pass in a function defined within a loadable module, then it in
- necessary to wait for all pending callbacks to be invoked after
- the last invocation and before unloading that module. Note that
- it is absolutely *not* sufficient to wait for a grace period!
- The current (say) synchronize_rcu() implementation is *not*
- guaranteed to wait for callbacks registered on other CPUs.
- Or even on the current CPU if that CPU recently went offline
- and came back online.
+17. If you pass a callback function defined within a module to one of
+ call_rcu(), call_srcu(), call_rcu_tasks(), call_rcu_tasks_rude(),
+ or call_rcu_tasks_trace(), then it is necessary to wait for all
+ pending callbacks to be invoked before unloading that module.
+ Note that it is absolutely *not* sufficient to wait for a grace
+ period! For example, synchronize_rcu() implementation is *not*
+ guaranteed to wait for callbacks registered on other CPUs via
+ call_rcu(). Or even on the current CPU if that CPU recently
+ went offline and came back online.
You instead need to use one of the barrier functions:
- call_rcu() -> rcu_barrier()
- call_srcu() -> srcu_barrier()
+ - call_rcu_tasks() -> rcu_barrier_tasks()
+ - call_rcu_tasks_rude() -> rcu_barrier_tasks_rude()
+ - call_rcu_tasks_trace() -> rcu_barrier_tasks_trace()
However, these barrier functions are absolutely *not* guaranteed
- to wait for a grace period. In fact, if there are no call_rcu()
- callbacks waiting anywhere in the system, rcu_barrier() is within
- its rights to return immediately.
-
- So if you need to wait for both an RCU grace period and for
- all pre-existing call_rcu() callbacks, you will need to execute
- both rcu_barrier() and synchronize_rcu(), if necessary, using
- something like workqueues to execute them concurrently.
+ to wait for a grace period. For example, if there are no
+ call_rcu() callbacks queued anywhere in the system, rcu_barrier()
+ can and will return immediately.
+
+ So if you need to wait for both a grace period and for all
+ pre-existing callbacks, you will need to invoke both functions,
+ with the pair depending on the flavor of RCU:
+
+ - Either synchronize_rcu() or synchronize_rcu_expedited(),
+ together with rcu_barrier()
+ - Either synchronize_srcu() or synchronize_srcu_expedited(),
+ together with and srcu_barrier()
+ - synchronize_rcu_tasks() and rcu_barrier_tasks()
+ - synchronize_tasks_rude() and rcu_barrier_tasks_rude()
+ - synchronize_tasks_trace() and rcu_barrier_tasks_trace()
+
+ If necessary, you can use something like workqueues to execute
+ the requisite pair of functions concurrently.
See rcubarrier.rst for more information.
diff --git a/Documentation/RCU/index.rst b/Documentation/RCU/index.rst
index e703d3dbe60c..84a79903f6a8 100644
--- a/Documentation/RCU/index.rst
+++ b/Documentation/RCU/index.rst
@@ -9,7 +9,6 @@ RCU concepts
.. toctree::
:maxdepth: 3
- arrayRCU
checklist
lockdep
lockdep-splat
diff --git a/Documentation/RCU/listRCU.rst b/Documentation/RCU/listRCU.rst
index 2a643e293fb4..bdc4bcc5289f 100644
--- a/Documentation/RCU/listRCU.rst
+++ b/Documentation/RCU/listRCU.rst
@@ -3,11 +3,10 @@
Using RCU to Protect Read-Mostly Linked Lists
=============================================
-One of the best applications of RCU is to protect read-mostly linked lists
-(``struct list_head`` in list.h). One big advantage of this approach
-is that all of the required memory barriers are included for you in
-the list macros. This document describes several applications of RCU,
-with the best fits first.
+One of the most common uses of RCU is protecting read-mostly linked lists
+(``struct list_head`` in list.h). One big advantage of this approach is
+that all of the required memory ordering is provided by the list macros.
+This document describes several list-based RCU use cases.
Example 1: Read-mostly list: Deferred Destruction
@@ -35,7 +34,8 @@ The code traversing the list of all processes typically looks like::
}
rcu_read_unlock();
-The simplified code for removing a process from a task list is::
+The simplified and heavily inlined code for removing a process from a
+task list is::
void release_task(struct task_struct *p)
{
@@ -45,39 +45,48 @@ The simplified code for removing a process from a task list is::
call_rcu(&p->rcu, delayed_put_task_struct);
}
-When a process exits, ``release_task()`` calls ``list_del_rcu(&p->tasks)`` under
-``tasklist_lock`` writer lock protection, to remove the task from the list of
-all tasks. The ``tasklist_lock`` prevents concurrent list additions/removals
-from corrupting the list. Readers using ``for_each_process()`` are not protected
-with the ``tasklist_lock``. To prevent readers from noticing changes in the list
-pointers, the ``task_struct`` object is freed only after one or more grace
-periods elapse (with the help of call_rcu()). This deferring of destruction
-ensures that any readers traversing the list will see valid ``p->tasks.next``
-pointers and deletion/freeing can happen in parallel with traversal of the list.
-This pattern is also called an **existence lock**, since RCU pins the object in
-memory until all existing readers finish.
+When a process exits, ``release_task()`` calls ``list_del_rcu(&p->tasks)``
+via __exit_signal() and __unhash_process() under ``tasklist_lock``
+writer lock protection. The list_del_rcu() invocation removes
+the task from the list of all tasks. The ``tasklist_lock``
+prevents concurrent list additions/removals from corrupting the
+list. Readers using ``for_each_process()`` are not protected with the
+``tasklist_lock``. To prevent readers from noticing changes in the list
+pointers, the ``task_struct`` object is freed only after one or more
+grace periods elapse, with the help of call_rcu(), which is invoked via
+put_task_struct_rcu_user(). This deferring of destruction ensures that
+any readers traversing the list will see valid ``p->tasks.next`` pointers
+and deletion/freeing can happen in parallel with traversal of the list.
+This pattern is also called an **existence lock**, since RCU refrains
+from invoking the delayed_put_task_struct() callback function until
+all existing readers finish, which guarantees that the ``task_struct``
+object in question will remain in existence until after the completion
+of all RCU readers that might possibly have a reference to that object.
Example 2: Read-Side Action Taken Outside of Lock: No In-Place Updates
----------------------------------------------------------------------
-The best applications are cases where, if reader-writer locking were
-used, the read-side lock would be dropped before taking any action
-based on the results of the search. The most celebrated example is
-the routing table. Because the routing table is tracking the state of
-equipment outside of the computer, it will at times contain stale data.
-Therefore, once the route has been computed, there is no need to hold
-the routing table static during transmission of the packet. After all,
-you can hold the routing table static all you want, but that won't keep
-the external Internet from changing, and it is the state of the external
-Internet that really matters. In addition, routing entries are typically
-added or deleted, rather than being modified in place.
-
-A straightforward example of this use of RCU may be found in the
-system-call auditing support. For example, a reader-writer locked
+Some reader-writer locking use cases compute a value while holding
+the read-side lock, but continue to use that value after that lock is
+released. These use cases are often good candidates for conversion
+to RCU. One prominent example involves network packet routing.
+Because the packet-routing data tracks the state of equipment outside
+of the computer, it will at times contain stale data. Therefore, once
+the route has been computed, there is no need to hold the routing table
+static during transmission of the packet. After all, you can hold the
+routing table static all you want, but that won't keep the external
+Internet from changing, and it is the state of the external Internet
+that really matters. In addition, routing entries are typically added
+or deleted, rather than being modified in place. This is a rare example
+of the finite speed of light and the non-zero size of atoms actually
+helping make synchronization be lighter weight.
+
+A straightforward example of this type of RCU use case may be found in
+the system-call auditing support. For example, a reader-writer locked
implementation of ``audit_filter_task()`` might be as follows::
- static enum audit_state audit_filter_task(struct task_struct *tsk)
+ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
{
struct audit_entry *e;
enum audit_state state;
@@ -86,6 +95,8 @@ implementation of ``audit_filter_task()`` might be as follows::
/* Note: audit_filter_mutex held by caller. */
list_for_each_entry(e, &audit_tsklist, list) {
if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+ if (state == AUDIT_STATE_RECORD)
+ *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
read_unlock(&auditsc_lock);
return state;
}
@@ -101,7 +112,7 @@ you are turning auditing off, it is OK to audit a few extra system calls.
This means that RCU can be easily applied to the read side, as follows::
- static enum audit_state audit_filter_task(struct task_struct *tsk)
+ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
{
struct audit_entry *e;
enum audit_state state;
@@ -110,6 +121,8 @@ This means that RCU can be easily applied to the read side, as follows::
/* Note: audit_filter_mutex held by caller. */
list_for_each_entry_rcu(e, &audit_tsklist, list) {
if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+ if (state == AUDIT_STATE_RECORD)
+ *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
rcu_read_unlock();
return state;
}
@@ -118,13 +131,15 @@ This means that RCU can be easily applied to the read side, as follows::
return AUDIT_BUILD_CONTEXT;
}
-The ``read_lock()`` and ``read_unlock()`` calls have become rcu_read_lock()
-and rcu_read_unlock(), respectively, and the list_for_each_entry() has
-become list_for_each_entry_rcu(). The **_rcu()** list-traversal primitives
-insert the read-side memory barriers that are required on DEC Alpha CPUs.
+The read_lock() and read_unlock() calls have become rcu_read_lock()
+and rcu_read_unlock(), respectively, and the list_for_each_entry()
+has become list_for_each_entry_rcu(). The **_rcu()** list-traversal
+primitives add READ_ONCE() and diagnostic checks for incorrect use
+outside of an RCU read-side critical section.
The changes to the update side are also straightforward. A reader-writer lock
-might be used as follows for deletion and insertion::
+might be used as follows for deletion and insertion in these simplified
+versions of audit_del_rule() and audit_add_rule()::
static inline int audit_del_rule(struct audit_rule *rule,
struct list_head *list)
@@ -188,16 +203,16 @@ Following are the RCU equivalents for these two functions::
return 0;
}
-Normally, the ``write_lock()`` and ``write_unlock()`` would be replaced by a
+Normally, the write_lock() and write_unlock() would be replaced by a
spin_lock() and a spin_unlock(). But in this case, all callers hold
``audit_filter_mutex``, so no additional locking is required. The
-``auditsc_lock`` can therefore be eliminated, since use of RCU eliminates the
+auditsc_lock can therefore be eliminated, since use of RCU eliminates the
need for writers to exclude readers.
The list_del(), list_add(), and list_add_tail() primitives have been
replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu().
-The **_rcu()** list-manipulation primitives add memory barriers that are needed on
-weakly ordered CPUs (most of them!). The list_del_rcu() primitive omits the
+The **_rcu()** list-manipulation primitives add memory barriers that are
+needed on weakly ordered CPUs. The list_del_rcu() primitive omits the
pointer poisoning debug-assist code that would otherwise cause concurrent
readers to fail spectacularly.
@@ -238,7 +253,9 @@ need to be filled in)::
The RCU version creates a copy, updates the copy, then replaces the old
entry with the newly updated entry. This sequence of actions, allowing
concurrent reads while making a copy to perform an update, is what gives
-RCU (*read-copy update*) its name. The RCU code is as follows::
+RCU (*read-copy update*) its name.
+
+The RCU version of audit_upd_rule() is as follows::
static inline int audit_upd_rule(struct audit_rule *rule,
struct list_head *list,
@@ -267,6 +284,9 @@ RCU (*read-copy update*) its name. The RCU code is as follows::
Again, this assumes that the caller holds ``audit_filter_mutex``. Normally, the
writer lock would become a spinlock in this sort of code.
+The update_lsm_rule() does something very similar, for those who would
+prefer to look at real Linux-kernel code.
+
Another use of this pattern can be found in the openswitch driver's *connection
tracking table* code in ``ct_limit_set()``. The table holds connection tracking
entries and has a limit on the maximum entries. There is one such table
@@ -281,9 +301,10 @@ Example 4: Eliminating Stale Data
---------------------------------
The auditing example above tolerates stale data, as do most algorithms
-that are tracking external state. Because there is a delay from the
-time the external state changes before Linux becomes aware of the change,
-additional RCU-induced staleness is generally not a problem.
+that are tracking external state. After all, given there is a delay
+from the time the external state changes before Linux becomes aware
+of the change, and so as noted earlier, a small quantity of additional
+RCU-induced staleness is generally not a problem.
However, there are many examples where stale data cannot be tolerated.
One example in the Linux kernel is the System V IPC (see the shm_lock()
@@ -302,7 +323,7 @@ Quick Quiz:
If the system-call audit module were to ever need to reject stale data, one way
to accomplish this would be to add a ``deleted`` flag and a ``lock`` spinlock to the
-audit_entry structure, and modify ``audit_filter_task()`` as follows::
+``audit_entry`` structure, and modify audit_filter_task() as follows::
static enum audit_state audit_filter_task(struct task_struct *tsk)
{
@@ -319,6 +340,8 @@ audit_entry structure, and modify ``audit_filter_task()`` as follows::
return AUDIT_BUILD_CONTEXT;
}
rcu_read_unlock();
+ if (state == AUDIT_STATE_RECORD)
+ *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
return state;
}
}
@@ -326,12 +349,6 @@ audit_entry structure, and modify ``audit_filter_task()`` as follows::
return AUDIT_BUILD_CONTEXT;
}
-Note that this example assumes that entries are only added and deleted.
-Additional mechanism is required to deal correctly with the update-in-place
-performed by ``audit_upd_rule()``. For one thing, ``audit_upd_rule()`` would
-need additional memory barriers to ensure that the list_add_rcu() was really
-executed before the list_del_rcu().
-
The ``audit_del_rule()`` function would need to set the ``deleted`` flag under the
spinlock as follows::
@@ -357,24 +374,32 @@ spinlock as follows::
This too assumes that the caller holds ``audit_filter_mutex``.
+Note that this example assumes that entries are only added and deleted.
+Additional mechanism is required to deal correctly with the update-in-place
+performed by audit_upd_rule(). For one thing, audit_upd_rule() would
+need to hold the locks of both the old ``audit_entry`` and its replacement
+while executing the list_replace_rcu().
+
Example 5: Skipping Stale Objects
---------------------------------
-For some usecases, reader performance can be improved by skipping stale objects
-during read-side list traversal if the object in concern is pending destruction
-after one or more grace periods. One such example can be found in the timerfd
-subsystem. When a ``CLOCK_REALTIME`` clock is reprogrammed - for example due to
-setting of the system time, then all programmed timerfds that depend on this
-clock get triggered and processes waiting on them to expire are woken up in
-advance of their scheduled expiry. To facilitate this, all such timers are added
-to an RCU-managed ``cancel_list`` when they are setup in
+For some use cases, reader performance can be improved by skipping
+stale objects during read-side list traversal, where stale objects
+are those that will be removed and destroyed after one or more grace
+periods. One such example can be found in the timerfd subsystem. When a
+``CLOCK_REALTIME`` clock is reprogrammed (for example due to setting
+of the system time) then all programmed ``timerfds`` that depend on
+this clock get triggered and processes waiting on them are awakened in
+advance of their scheduled expiry. To facilitate this, all such timers
+are added to an RCU-managed ``cancel_list`` when they are setup in
``timerfd_setup_cancel()``::
static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
{
spin_lock(&ctx->cancel_lock);
- if ((ctx->clockid == CLOCK_REALTIME &&
+ if ((ctx->clockid == CLOCK_REALTIME ||
+ ctx->clockid == CLOCK_REALTIME_ALARM) &&
(flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
if (!ctx->might_cancel) {
ctx->might_cancel = true;
@@ -382,13 +407,16 @@ to an RCU-managed ``cancel_list`` when they are setup in
list_add_rcu(&ctx->clist, &cancel_list);
spin_unlock(&cancel_lock);
}
+ } else {
+ __timerfd_remove_cancel(ctx);
}
spin_unlock(&ctx->cancel_lock);
}
-When a timerfd is freed (fd is closed), then the ``might_cancel`` flag of the
-timerfd object is cleared, the object removed from the ``cancel_list`` and
-destroyed::
+When a timerfd is freed (fd is closed), then the ``might_cancel``
+flag of the timerfd object is cleared, the object removed from the
+``cancel_list`` and destroyed, as shown in this simplified and inlined
+version of timerfd_release()::
int timerfd_release(struct inode *inode, struct file *file)
{
@@ -403,7 +431,10 @@ destroyed::
}
spin_unlock(&ctx->cancel_lock);
- hrtimer_cancel(&ctx->t.tmr);
+ if (isalarm(ctx))
+ alarm_cancel(&ctx->t.alarm);
+ else
+ hrtimer_cancel(&ctx->t.tmr);
kfree_rcu(ctx, rcu);
return 0;
}
@@ -416,6 +447,7 @@ objects::
void timerfd_clock_was_set(void)
{
+ ktime_t moffs = ktime_mono_to_real(0);
struct timerfd_ctx *ctx;
unsigned long flags;
@@ -424,7 +456,7 @@ objects::
if (!ctx->might_cancel)
continue;
spin_lock_irqsave(&ctx->wqh.lock, flags);
- if (ctx->moffs != ktime_mono_to_real(0)) {
+ if (ctx->moffs != moffs) {
ctx->moffs = KTIME_MAX;
ctx->ticks++;
wake_up_locked_poll(&ctx->wqh, EPOLLIN);
@@ -434,10 +466,10 @@ objects::
rcu_read_unlock();
}
-The key point here is, because RCU-traversal of the ``cancel_list`` happens
-while objects are being added and removed to the list, sometimes the traversal
-can step on an object that has been removed from the list. In this example, it
-is seen that it is better to skip such objects using a flag.
+The key point is that because RCU-protected traversal of the
+``cancel_list`` happens concurrently with object addition and removal,
+sometimes the traversal can access an object that has been removed from
+the list. In this example, a flag is used to skip such objects.
Summary
diff --git a/Documentation/RCU/lockdep.rst b/Documentation/RCU/lockdep.rst
index a94f55991a71..9308f1bdba05 100644
--- a/Documentation/RCU/lockdep.rst
+++ b/Documentation/RCU/lockdep.rst
@@ -17,7 +17,9 @@ state::
rcu_read_lock_held() for normal RCU.
rcu_read_lock_bh_held() for RCU-bh.
rcu_read_lock_sched_held() for RCU-sched.
+ rcu_read_lock_any_held() for any of normal RCU, RCU-bh, and RCU-sched.
srcu_read_lock_held() for SRCU.
+ rcu_read_lock_trace_held() for RCU Tasks Trace.
These functions are conservative, and will therefore return 1 if they
aren't certain (for example, if CONFIG_DEBUG_LOCK_ALLOC is not set).
@@ -53,6 +55,8 @@ checking of rcu_dereference() primitives:
is invoked by both SRCU readers and updaters.
rcu_dereference_raw(p):
Don't check. (Use sparingly, if at all.)
+ rcu_dereference_raw_check(p):
+ Don't do lockdep at all. (Use sparingly, if at all.)
rcu_dereference_protected(p, c):
Use explicit check expression "c", and omit all barriers
and compiler constraints. This is useful when the data
diff --git a/Documentation/accel/index.rst b/Documentation/accel/index.rst
new file mode 100644
index 000000000000..2b43c9a7f67b
--- /dev/null
+++ b/Documentation/accel/index.rst
@@ -0,0 +1,17 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================
+Compute Accelerators
+====================
+
+.. toctree::
+ :maxdepth: 1
+
+ introduction
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/accel/introduction.rst b/Documentation/accel/introduction.rst
new file mode 100644
index 000000000000..6f31af14b1fc
--- /dev/null
+++ b/Documentation/accel/introduction.rst
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Introduction
+============
+
+The Linux compute accelerators subsystem is designed to expose compute
+accelerators in a common way to user-space and provide a common set of
+functionality.
+
+These devices can be either stand-alone ASICs or IP blocks inside an SoC/GPU.
+Although these devices are typically designed to accelerate
+Machine-Learning (ML) and/or Deep-Learning (DL) computations, the accel layer
+is not limited to handling these types of accelerators.
+
+Typically, a compute accelerator will belong to one of the following
+categories:
+
+- Edge AI - doing inference at an edge device. It can be an embedded ASIC/FPGA,
+ or an IP inside a SoC (e.g. laptop web camera). These devices
+ are typically configured using registers and can work with or without DMA.
+
+- Inference data-center - single/multi user devices in a large server. This
+ type of device can be stand-alone or an IP inside a SoC or a GPU. It will
+ have on-board DRAM (to hold the DL topology), DMA engines and
+ command submission queues (either kernel or user-space queues).
+ It might also have an MMU to manage multiple users and might also enable
+ virtualization (SR-IOV) to support multiple VMs on the same device. In
+ addition, these devices will usually have some tools, such as profiler and
+ debugger.
+
+- Training data-center - Similar to Inference data-center cards, but typically
+ have more computational power and memory b/w (e.g. HBM) and will likely have
+ a method of scaling-up/out, i.e. connecting to other training cards inside
+ the server or in other servers, respectively.
+
+All these devices typically have different runtime user-space software stacks,
+that are tailored-made to their h/w. In addition, they will also probably
+include a compiler to generate programs to their custom-made computational
+engines. Typically, the common layer in user-space will be the DL frameworks,
+such as PyTorch and TensorFlow.
+
+Sharing code with DRM
+=====================
+
+Because this type of devices can be an IP inside GPUs or have similar
+characteristics as those of GPUs, the accel subsystem will use the
+DRM subsystem's code and functionality. i.e. the accel core code will
+be part of the DRM subsystem and an accel device will be a new type of DRM
+device.
+
+This will allow us to leverage the extensive DRM code-base and
+collaborate with DRM developers that have experience with this type of
+devices. In addition, new features that will be added for the accelerator
+drivers can be of use to GPU drivers as well.
+
+Differentiation from GPUs
+=========================
+
+Because we want to prevent the extensive user-space graphic software stack
+from trying to use an accelerator as a GPU, the compute accelerators will be
+differentiated from GPUs by using a new major number and new device char files.
+
+Furthermore, the drivers will be located in a separate place in the kernel
+tree - drivers/accel/.
+
+The accelerator devices will be exposed to the user space with the dedicated
+261 major number and will have the following convention:
+
+- device char files - /dev/accel/accel*
+- sysfs - /sys/class/accel/accel*/
+- debugfs - /sys/kernel/debug/accel/accel*/
+
+Getting Started
+===============
+
+First, read the DRM documentation at Documentation/gpu/index.rst.
+Not only it will explain how to write a new DRM driver but it will also
+contain all the information on how to contribute, the Code Of Conduct and
+what is the coding style/documentation. All of that is the same for the
+accel subsystem.
+
+Second, make sure the kernel is configured with CONFIG_DRM_ACCEL.
+
+To expose your device as an accelerator, two changes are needed to
+be done in your driver (as opposed to a standard DRM driver):
+
+- Add the DRIVER_COMPUTE_ACCEL feature flag in your drm_driver's
+ driver_features field. It is important to note that this driver feature is
+ mutually exclusive with DRIVER_RENDER and DRIVER_MODESET. Devices that want
+ to expose both graphics and compute device char files should be handled by
+ two drivers that are connected using the auxiliary bus framework.
+
+- Change the open callback in your driver fops structure to accel_open().
+ Alternatively, your driver can use DEFINE_DRM_ACCEL_FOPS macro to easily
+ set the correct function operations pointers structure.
+
+External References
+===================
+
+email threads
+-------------
+
+* `Initial discussion on the New subsystem for acceleration devices <https://lkml.org/lkml/2022/7/31/83>`_ - Oded Gabbay (2022)
+* `patch-set to add the new subsystem <https://lkml.org/lkml/2022/10/22/544>`_ - Oded Gabbay (2022)
+
+Conference talks
+----------------
+
+* `LPC 2022 Accelerators BOF outcomes summary <https://airlied.blogspot.com/2022/09/accelerators-bof-outcomes-summary.html>`_ - Dave Airlie (2022)
diff --git a/Documentation/admin-guide/bootconfig.rst b/Documentation/admin-guide/bootconfig.rst
index d99994345d41..9355c525fbe0 100644
--- a/Documentation/admin-guide/bootconfig.rst
+++ b/Documentation/admin-guide/bootconfig.rst
@@ -229,7 +229,7 @@ In addition to the kernel command line, the boot config can be used for
passing the kernel parameters. All the key-value pairs under ``kernel``
key will be passed to kernel cmdline directly. Moreover, the key-value
pairs under ``init`` will be passed to init process via the cmdline.
-The parameters are concatinated with user-given kernel cmdline string
+The parameters are concatenated with user-given kernel cmdline string
as the following order, so that the command line parameter can override
bootconfig parameters (this depends on how the subsystem handles parameters
but in general, earlier parameter will be overwritten by later one.)::
diff --git a/Documentation/admin-guide/device-mapper/dm-init.rst b/Documentation/admin-guide/device-mapper/dm-init.rst
index e5242ff17e9b..981d6a907699 100644
--- a/Documentation/admin-guide/device-mapper/dm-init.rst
+++ b/Documentation/admin-guide/device-mapper/dm-init.rst
@@ -123,3 +123,11 @@ Other examples (per target):
0 1638400 verity 1 8:1 8:2 4096 4096 204800 1 sha256
fb1a5a0f00deb908d8b53cb270858975e76cf64105d412ce764225d53b8f3cfd
51934789604d1b92399c52e7cb149d1b3a1b74bbbcb103b2a0aaacbed5c08584
+
+For setups using device-mapper on top of asynchronously probed block
+devices (MMC, USB, ..), it may be necessary to tell dm-init to
+explicitly wait for them to become available before setting up the
+device-mapper tables. This can be done with the "dm-mod.waitfor="
+module parameter, which takes a list of devices to wait for::
+
+ dm-mod.waitfor=<device1>[,..,<deviceN>]
diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt
index 9764d6edb189..06c525e01ea5 100644
--- a/Documentation/admin-guide/devices.txt
+++ b/Documentation/admin-guide/devices.txt
@@ -3080,6 +3080,11 @@
...
255 = /dev/osd255 256th OSD Device
+ 261 char Compute Acceleration Devices
+ 0 = /dev/accel/accel0 First acceleration device
+ 1 = /dev/accel/accel1 Second acceleration device
+ ...
+
384-511 char RESERVED FOR DYNAMIC ASSIGNMENT
Character devices that request a dynamic allocation of major
number will take numbers starting from 511 and downward,
diff --git a/Documentation/admin-guide/hw_random.rst b/Documentation/admin-guide/hw_random.rst
index 121de96e395e..d494601717f1 100644
--- a/Documentation/admin-guide/hw_random.rst
+++ b/Documentation/admin-guide/hw_random.rst
@@ -1,6 +1,6 @@
-==========================================================
-Linux support for random number generator in i8xx chipsets
-==========================================================
+=================================
+Hardware random number generators
+=================================
Introduction
============
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a465d5242774..fb388c6c8c60 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -703,6 +703,17 @@
condev= [HW,S390] console device
conmode=
+ con3215_drop= [S390] 3215 console drop mode.
+ Format: y|n|Y|N|1|0
+ When set to true, drop data on the 3215 console when
+ the console buffer is full. In this case the
+ operator using a 3270 terminal emulator (for example
+ x3270) does not have to enter the clear key for the
+ console output to advance and the kernel to continue.
+ This leads to a much faster boot time when a 3270
+ terminal emulator is active. If no 3270 terminal
+ emulator is used, this parameter has no effect.
+
console= [KNL] Output console device and options.
tty<n> Use the virtual console device <n>.
@@ -831,7 +842,7 @@
memory region [offset, offset + size] for that kernel
image. If '@offset' is omitted, then a suitable offset
is selected automatically.
- [KNL, X86-64] Select a region under 4G first, and
+ [KNL, X86-64, ARM64] Select a region under 4G first, and
fall back to reserve region above 4G when '@offset'
hasn't been specified.
See Documentation/admin-guide/kdump/kdump.rst for further details.
@@ -851,26 +862,23 @@
available.
It will be ignored if crashkernel=X is specified.
crashkernel=size[KMG],low
- [KNL, X86-64] range under 4G. When crashkernel=X,high
+ [KNL, X86-64, ARM64] range under 4G. When crashkernel=X,high
is passed, kernel could allocate physical memory region
above 4G, that cause second kernel crash on system
that require some amount of low memory, e.g. swiotlb
requires at least 64M+32K low memory, also enough extra
low memory is needed to make sure DMA buffers for 32-bit
devices won't run out. Kernel would try to allocate
- at least 256M below 4G automatically.
+ default size of memory below 4G automatically. The default
+ size is platform dependent.
+ --> x86: max(swiotlb_size_or_default() + 8MiB, 256MiB)
+ --> arm64: 128MiB
This one lets the user specify own low range under 4G
for second kernel instead.
0: to disable low allocation.
It will be ignored when crashkernel=X,high is not used
or memory reserved is below 4G.
- [KNL, ARM64] range in low memory.
- This one lets the user specify a low range in the
- DMA zone for the crash dump kernel.
- It will be ignored when crashkernel=X,high is not used
- or memory reserved is located in the DMA zones.
-
cryptomgr.notests
[KNL] Disable crypto self-tests
@@ -3777,12 +3785,15 @@
shutdown the other cpus. Instead use the REBOOT_VECTOR
irq.
- nomodeset Disable kernel modesetting. DRM drivers will not perform
- display-mode changes or accelerated rendering. Only the
- system framebuffer will be available for use if this was
- set-up by the firmware or boot loader.
+ nomodeset Disable kernel modesetting. Most systems' firmware
+ sets up a display mode and provides framebuffer memory
+ for output. With nomodeset, DRM and fbdev drivers will
+ not load if they could possibly displace the pre-
+ initialized output. Only the system framebuffer will
+ be available for use. The respective drivers will not
+ perform display-mode changes or accelerated rendering.
- Useful as fallback, or for testing and debugging.
+ Useful as error fallback, or for testing and debugging.
nomodule Disable module load
@@ -4566,17 +4577,15 @@
ramdisk_start= [RAM] RAM disk image start address
- random.trust_cpu={on,off}
- [KNL] Enable or disable trusting the use of the
- CPU's random number generator (if available) to
- fully seed the kernel's CRNG. Default is controlled
- by CONFIG_RANDOM_TRUST_CPU.
+ random.trust_cpu=off
+ [KNL] Disable trusting the use of the CPU's
+ random number generator (if available) to
+ initialize the kernel's RNG.
- random.trust_bootloader={on,off}
- [KNL] Enable or disable trusting the use of a
- seed passed by the bootloader (if available) to
- fully seed the kernel's CRNG. Default is controlled
- by CONFIG_RANDOM_TRUST_BOOTLOADER.
+ random.trust_bootloader=off
+ [KNL] Disable trusting the use of the a seed
+ passed by the bootloader (if available) to
+ initialize the kernel's RNG.
randomize_kstack_offset=
[KNL] Enable or disable kernel stack offset
@@ -6959,3 +6968,14 @@
memory, and other data can't be written using
xmon commands.
off xmon is disabled.
+
+ amd_pstate= [X86]
+ disable
+ Do not enable amd_pstate as the default
+ scaling driver for the supported processors
+ passive
+ Use amd_pstate as a scaling driver, driver requests a
+ desired performance on this abstract scale and the power
+ management firmware translates the requests into actual
+ hardware states (core frequency, data fabric and memory
+ clocks etc.)
diff --git a/Documentation/admin-guide/media/cec-drivers.rst b/Documentation/admin-guide/media/cec-drivers.rst
deleted file mode 100644
index 8d9686c08df9..000000000000
--- a/Documentation/admin-guide/media/cec-drivers.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-=================================
-CEC driver-specific documentation
-=================================
-
-.. toctree::
- :maxdepth: 2
-
- pulse8-cec
diff --git a/Documentation/admin-guide/media/cec.rst b/Documentation/admin-guide/media/cec.rst
new file mode 100644
index 000000000000..5c7259371494
--- /dev/null
+++ b/Documentation/admin-guide/media/cec.rst
@@ -0,0 +1,369 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========
+HDMI CEC
+========
+
+Supported hardware in mainline
+==============================
+
+HDMI Transmitters:
+
+- Exynos4
+- Exynos5
+- STIH4xx HDMI CEC
+- V4L2 adv7511 (same HW, but a different driver from the drm adv7511)
+- stm32
+- Allwinner A10 (sun4i)
+- Raspberry Pi
+- dw-hdmi (Synopsis IP)
+- amlogic (meson ao-cec and ao-cec-g12a)
+- drm adv7511/adv7533
+- omap4
+- tegra
+- rk3288, rk3399
+- tda998x
+- DisplayPort CEC-Tunneling-over-AUX on i915, nouveau and amdgpu
+- ChromeOS EC CEC
+- CEC for SECO boards (UDOO x86).
+- Chrontel CH7322
+
+
+HDMI Receivers:
+
+- adv7604/11/12
+- adv7842
+- tc358743
+
+USB Dongles (see below for additional information on how to use these
+dongles):
+
+- Pulse-Eight: the pulse8-cec driver implements the following module option:
+ ``persistent_config``: by default this is off, but when set to 1 the driver
+ will store the current settings to the device's internal eeprom and restore
+ it the next time the device is connected to the USB port.
+- RainShadow Tech. Note: this driver does not support the persistent_config
+ module option of the Pulse-Eight driver. The hardware supports it, but I
+ have no plans to add this feature. But I accept patches :-)
+
+Miscellaneous:
+
+- vivid: emulates a CEC receiver and CEC transmitter.
+ Can be used to test CEC applications without actual CEC hardware.
+
+- cec-gpio. If the CEC pin is hooked up to a GPIO pin then
+ you can control the CEC line through this driver. This supports error
+ injection as well.
+
+
+Utilities
+=========
+
+Utilities are available here: https://git.linuxtv.org/v4l-utils.git
+
+``utils/cec-ctl``: control a CEC device
+
+``utils/cec-compliance``: test compliance of a remote CEC device
+
+``utils/cec-follower``: emulate a CEC follower device
+
+Note that ``cec-ctl`` has support for the CEC Hospitality Profile as is
+used in some hotel displays. See http://www.htng.org.
+
+Note that the libcec library (https://github.com/Pulse-Eight/libcec) supports
+the linux CEC framework.
+
+If you want to get the CEC specification, then look at the References of
+the HDMI wikipedia page: https://en.wikipedia.org/wiki/HDMI. CEC is part
+of the HDMI specification. HDMI 1.3 is freely available (very similar to
+HDMI 1.4 w.r.t. CEC) and should be good enough for most things.
+
+
+DisplayPort to HDMI Adapters with working CEC
+=============================================
+
+Background: most adapters do not support the CEC Tunneling feature,
+and of those that do many did not actually connect the CEC pin.
+Unfortunately, this means that while a CEC device is created, it
+is actually all alone in the world and will never be able to see other
+CEC devices.
+
+This is a list of known working adapters that have CEC Tunneling AND
+that properly connected the CEC pin. If you find adapters that work
+but are not in this list, then drop me a note.
+
+To test: hook up your DP-to-HDMI adapter to a CEC capable device
+(typically a TV), then run::
+
+ cec-ctl --playback # Configure the PC as a CEC Playback device
+ cec-ctl -S # Show the CEC topology
+
+The ``cec-ctl -S`` command should show at least two CEC devices,
+ourselves and the CEC device you are connected to (i.e. typically the TV).
+
+General note: I have only seen this work with the Parade PS175, PS176 and
+PS186 chipsets and the MegaChips 2900. While MegaChips 28x0 claims CEC support,
+I have never seen it work.
+
+USB-C to HDMI
+-------------
+
+Samsung Multiport Adapter EE-PW700: https://www.samsung.com/ie/support/model/EE-PW700BBEGWW/
+
+Kramer ADC-U31C/HF: https://www.kramerav.com/product/ADC-U31C/HF
+
+Club3D CAC-2504: https://www.club-3d.com/en/detail/2449/usb_3.1_type_c_to_hdmi_2.0_uhd_4k_60hz_active_adapter/
+
+DisplayPort to HDMI
+-------------------
+
+Club3D CAC-1080: https://www.club-3d.com/en/detail/2442/displayport_1.4_to_hdmi_2.0b_hdr/
+
+CableCreation (SKU: CD0712): https://www.cablecreation.com/products/active-displayport-to-hdmi-adapter-4k-hdr
+
+HP DisplayPort to HDMI True 4k Adapter (P/N 2JA63AA): https://www.hp.com/us-en/shop/pdp/hp-displayport-to-hdmi-true-4k-adapter
+
+Mini-DisplayPort to HDMI
+------------------------
+
+Club3D CAC-1180: https://www.club-3d.com/en/detail/2443/mini_displayport_1.4_to_hdmi_2.0b_hdr/
+
+Note that passive adapters will never work, you need an active adapter.
+
+The Club3D adapters in this list are all MegaChips 2900 based. Other Club3D adapters
+are PS176 based and do NOT have the CEC pin hooked up, so only the three Club3D
+adapters above are known to work.
+
+I suspect that MegaChips 2900 based designs in general are likely to work
+whereas with the PS176 it is more hit-and-miss (mostly miss). The PS186 is
+likely to have the CEC pin hooked up, it looks like they changed the reference
+design for that chipset.
+
+
+USB CEC Dongles
+===============
+
+These dongles appear as ``/dev/ttyACMX`` devices and need the ``inputattach``
+utility to create the ``/dev/cecX`` devices. Support for the Pulse-Eight
+has been added to ``inputattach`` 1.6.0. Support for the Rainshadow Tech has
+been added to ``inputattach`` 1.6.1.
+
+You also need udev rules to automatically start systemd services::
+
+ SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="2548", ATTRS{idProduct}=="1002", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="pulse8-cec-inputattach@%k.service"
+ SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="2548", ATTRS{idProduct}=="1001", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="pulse8-cec-inputattach@%k.service"
+ SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="ff59", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rainshadow-cec-inputattach@%k.service"
+
+and these systemd services:
+
+For Pulse-Eight make /lib/systemd/system/pulse8-cec-inputattach@.service::
+
+ [Unit]
+ Description=inputattach for pulse8-cec device on %I
+
+ [Service]
+ Type=simple
+ ExecStart=/usr/bin/inputattach --pulse8-cec /dev/%I
+
+For the RainShadow Tech make /lib/systemd/system/rainshadow-cec-inputattach@.service::
+
+ [Unit]
+ Description=inputattach for rainshadow-cec device on %I
+
+ [Service]
+ Type=simple
+ ExecStart=/usr/bin/inputattach --rainshadow-cec /dev/%I
+
+
+For proper suspend/resume support create: /lib/systemd/system/restart-cec-inputattach.service::
+
+ [Unit]
+ Description=restart inputattach for cec devices
+ After=suspend.target
+
+ [Service]
+ Type=forking
+ ExecStart=/bin/bash -c 'for d in /dev/serial/by-id/usb-Pulse-Eight*; do /usr/bin/inputattach --daemon --pulse8-cec $d; done; for d in /dev/serial/by-id/usb-RainShadow_Tech*; do /usr/bin/inputattach --daemon --rainshadow-cec $d; done'
+
+ [Install]
+ WantedBy=suspend.target
+
+And run ``systemctl enable restart-cec-inputattach``.
+
+To automatically set the physical address of the CEC device whenever the
+EDID changes, you can use ``cec-ctl`` with the ``-E`` option::
+
+ cec-ctl -E /sys/class/drm/card0-DP-1/edid
+
+This assumes the dongle is connected to the card0-DP-1 output (``xrandr`` will tell
+you which output is used) and it will poll for changes to the EDID and update
+the Physical Address whenever they occur.
+
+To automatically run this command you can use cron. Edit crontab with
+``crontab -e`` and add this line::
+
+ @reboot /usr/local/bin/cec-ctl -E /sys/class/drm/card0-DP-1/edid
+
+This only works for display drivers that expose the EDID in ``/sys/class/drm``,
+such as the i915 driver.
+
+
+CEC Without HPD
+===============
+
+Some displays when in standby mode have no HDMI Hotplug Detect signal, but
+CEC is still enabled so connected devices can send an <Image View On> CEC
+message in order to wake up such displays. Unfortunately, not all CEC
+adapters can support this. An example is the Odroid-U3 SBC that has a
+level-shifter that is powered off when the HPD signal is low, thus
+blocking the CEC pin. Even though the SoC can use CEC without a HPD,
+the level-shifter will prevent this from functioning.
+
+There is a CEC capability flag to signal this: ``CEC_CAP_NEEDS_HPD``.
+If set, then the hardware cannot wake up displays with this behavior.
+
+Note for CEC application implementers: the <Image View On> message must
+be the first message you send, don't send any other messages before.
+Certain very bad but unfortunately not uncommon CEC implementations
+get very confused if they receive anything else but this message and
+they won't wake up.
+
+When writing a driver it can be tricky to test this. There are two
+ways to do this:
+
+1) Get a Pulse-Eight USB CEC dongle, connect an HDMI cable from your
+ device to the Pulse-Eight, but do not connect the Pulse-Eight to
+ the display.
+
+ Now configure the Pulse-Eight dongle::
+
+ cec-ctl -p0.0.0.0 --tv
+
+ and start monitoring::
+
+ sudo cec-ctl -M
+
+ On the device you are testing run::
+
+ cec-ctl --playback
+
+ It should report a physical address of f.f.f.f. Now run this
+ command::
+
+ cec-ctl -t0 --image-view-on
+
+ The Pulse-Eight should see the <Image View On> message. If not,
+ then something (hardware and/or software) is preventing the CEC
+ message from going out.
+
+ To make sure you have the wiring correct just connect the
+ Pulse-Eight to a CEC-enabled display and run the same command
+ on your device: now there is a HPD, so you should see the command
+ arriving at the Pulse-Eight.
+
+2) If you have another linux device supporting CEC without HPD, then
+ you can just connect your device to that device. Yes, you can connect
+ two HDMI outputs together. You won't have a HPD (which is what we
+ want for this test), but the second device can monitor the CEC pin.
+
+ Otherwise use the same commands as in 1.
+
+If CEC messages do not come through when there is no HPD, then you
+need to figure out why. Typically it is either a hardware restriction
+or the software powers off the CEC core when the HPD goes low. The
+first cannot be corrected of course, the second will likely required
+driver changes.
+
+
+Microcontrollers & CEC
+======================
+
+We have seen some CEC implementations in displays that use a microcontroller
+to sample the bus. This does not have to be a problem, but some implementations
+have timing issues. This is hard to discover unless you can hook up a low-level
+CEC debugger (see the next section).
+
+You will see cases where the CEC transmitter holds the CEC line high or low for
+a longer time than is allowed. For directed messages this is not a problem since
+if that happens the message will not be Acked and it will be retransmitted.
+For broadcast messages no such mechanism exists.
+
+It's not clear what to do about this. It is probably wise to transmit some
+broadcast messages twice to reduce the chance of them being lost. Specifically
+<Standby> and <Active Source> are candidates for that.
+
+
+Making a CEC debugger
+=====================
+
+By using a Raspberry Pi 2B/3/4 and some cheap components you can make
+your own low-level CEC debugger.
+
+Here is a picture of my setup:
+
+https://hverkuil.home.xs4all.nl/rpi3-cec.jpg
+
+It's a Raspberry Pi 3 together with a breadboard and some breadboard wires:
+
+http://www.dx.com/p/diy-40p-male-to-female-male-to-male-female-to-female-dupont-line-wire-3pcs-356089#.WYLOOXWGN7I
+
+Finally on of these HDMI female-female passthrough connectors (full soldering type 1):
+
+https://elabbay.myshopify.com/collections/camera/products/hdmi-af-af-v1a-hdmi-type-a-female-to-hdmi-type-a-female-pass-through-adapter-breakout-board?variant=45533926147
+
+We've tested this and it works up to 4kp30 (297 MHz). The quality is not high
+enough to pass-through 4kp60 (594 MHz).
+
+I also added an RTC and a breakout shield:
+
+https://www.amazon.com/Makerfire%C2%AE-Raspberry-Module-DS1307-Battery/dp/B00ZOXWHK4
+
+https://www.dx.com/p/raspberry-pi-gpio-expansion-board-breadboard-easy-multiplexing-board-one-to-three-with-screw-for-raspberry-pi-2-3-b-b-2729992.html#.YGRCG0MzZ7I
+
+These two are not needed but they make life a bit easier.
+
+If you want to monitor the HPD line as well, then you need one of these
+level shifters:
+
+https://www.adafruit.com/product/757
+
+(This is just where I got these components, there are many other places you
+can get similar things).
+
+The CEC pin of the HDMI connector needs to be connected to these pins:
+CE0/IO8 and CE1/IO7 (pull-up GPIOs). The (optional) HPD pin of the HDMI
+connector should be connected (via a level shifter to convert the 5V
+to 3.3V) to these pins: IO17 and IO27. The (optional) 5V pin of the HDMI
+connector should be connected (via a level shifter) to these pins: IO22
+and IO24. Monitoring the HPD an 5V lines is not necessary, but it is helpful.
+
+This kernel patch will hook up the cec-gpio driver correctly to
+e.g. ``arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts``::
+
+ cec-gpio@7 {
+ compatible = "cec-gpio";
+ cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+ hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+ v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
+ };
+
+ cec-gpio@8 {
+ compatible = "cec-gpio";
+ cec-gpios = <&gpio 8 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+ hpd-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
+ v5-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
+ };
+
+This dts change will enable two cec GPIO devices: I typically use one to
+send/receive CEC commands and the other to monitor. If you monitor using
+an unconfigured CEC adapter then it will use GPIO interrupts which makes
+monitoring very accurate.
+
+The documentation on how to use the error injection is here: :ref:`cec_pin_error_inj`.
+
+``cec-ctl --monitor-pin`` will do low-level CEC bus sniffing and analysis.
+You can also store the CEC traffic to file using ``--store-pin`` and analyze
+it later using ``--analyze-pin``.
+
+You can also use this as a full-fledged CEC device by configuring it
+using ``cec-ctl --tv -p0.0.0.0`` or ``cec-ctl --playback -p1.0.0.0``.
diff --git a/Documentation/admin-guide/media/index.rst b/Documentation/admin-guide/media/index.rst
index c676af665111..43f4a292b245 100644
--- a/Documentation/admin-guide/media/index.rst
+++ b/Documentation/admin-guide/media/index.rst
@@ -38,13 +38,14 @@ The media subsystem
remote-controller
+ cec
+
dvb
cardlist
v4l-drivers
dvb-drivers
- cec-drivers
**Copyright** |copy| 1999-2020 : LinuxTV Developers
diff --git a/Documentation/admin-guide/media/pulse8-cec.rst b/Documentation/admin-guide/media/pulse8-cec.rst
deleted file mode 100644
index 356d08b519f3..000000000000
--- a/Documentation/admin-guide/media/pulse8-cec.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-Pulse-Eight CEC Adapter driver
-==============================
-
-The pulse8-cec driver implements the following module option:
-
-``persistent_config``
----------------------
-
-By default this is off, but when set to 1 the driver will store the current
-settings to the device's internal eeprom and restore it the next time the
-device is connected to the USB port.
diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
index 9c7ebe2ca3bd..90a026ee05c6 100644
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -31,4 +31,5 @@ Video4Linux (V4L) driver-specific documentation
si4713
si476x
vimc
+ visl
vivid
diff --git a/Documentation/admin-guide/media/vimc.rst b/Documentation/admin-guide/media/vimc.rst
index 3b4d2b36b4f3..29d843a8ddb1 100644
--- a/Documentation/admin-guide/media/vimc.rst
+++ b/Documentation/admin-guide/media/vimc.rst
@@ -35,11 +35,11 @@ of commands fits for the default topology:
media-ctl -d platform:vimc -V '"Sensor A":0[fmt:SBGGR8_1X8/640x480]'
media-ctl -d platform:vimc -V '"Debayer A":0[fmt:SBGGR8_1X8/640x480]'
- media-ctl -d platform:vimc -V '"Sensor B":0[fmt:SBGGR8_1X8/640x480]'
- media-ctl -d platform:vimc -V '"Debayer B":0[fmt:SBGGR8_1X8/640x480]'
- v4l2-ctl -z platform:vimc -d "RGB/YUV Capture" -v width=1920,height=1440
+ media-ctl -d platform:vimc -V '"Scaler":0[fmt:RGB888_1X24/640x480]'
+ media-ctl -d platform:vimc -V '"Scaler":0[crop:(100,50)/400x150]'
+ media-ctl -d platform:vimc -V '"Scaler":1[fmt:RGB888_1X24/300x700]'
+ v4l2-ctl -z platform:vimc -d "RGB/YUV Capture" -v width=300,height=700
v4l2-ctl -z platform:vimc -d "Raw Capture 0" -v pixelformat=BA81
- v4l2-ctl -z platform:vimc -d "Raw Capture 1" -v pixelformat=BA81
Subdevices
----------
diff --git a/Documentation/admin-guide/media/visl.rst b/Documentation/admin-guide/media/visl.rst
new file mode 100644
index 000000000000..7d2dc78341c9
--- /dev/null
+++ b/Documentation/admin-guide/media/visl.rst
@@ -0,0 +1,175 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+The Virtual Stateless Decoder Driver (visl)
+===========================================
+
+A virtual stateless decoder device for stateless uAPI development
+purposes.
+
+This tool's objective is to help the development and testing of
+userspace applications that use the V4L2 stateless API to decode media.
+
+A userspace implementation can use visl to run a decoding loop even when
+no hardware is available or when the kernel uAPI for the codec has not
+been upstreamed yet. This can reveal bugs at an early stage.
+
+This driver can also trace the contents of the V4L2 controls submitted
+to it. It can also dump the contents of the vb2 buffers through a
+debugfs interface. This is in many ways similar to the tracing
+infrastructure available for other popular encode/decode APIs out there
+and can help develop a userspace application by using another (working)
+one as a reference.
+
+.. note::
+
+ No actual decoding of video frames is performed by visl. The
+ V4L2 test pattern generator is used to write various debug information
+ to the capture buffers instead.
+
+Module parameters
+-----------------
+
+- visl_debug: Activates debug info, printing various debug messages through
+ dprintk. Also controls whether per-frame debug info is shown. Defaults to off.
+ Note that enabling this feature can result in slow performance through serial.
+
+- visl_transtime_ms: Simulated process time in milliseconds. Slowing down the
+ decoding speed can be useful for debugging.
+
+- visl_dprintk_frame_start, visl_dprintk_frame_nframes: Dictates a range of
+ frames where dprintk is activated. This only controls the dprintk tracing on a
+ per-frame basis. Note that printing a lot of data can be slow through serial.
+
+- keep_bitstream_buffers: Controls whether bitstream (i.e. OUTPUT) buffers are
+ kept after a decoding session. Defaults to false so as to reduce the amount of
+ clutter. keep_bitstream_buffers == false works well when live debugging the
+ client program with GDB.
+
+- bitstream_trace_frame_start, bitstream_trace_nframes: Similar to
+ visl_dprintk_frame_start, visl_dprintk_nframes, but controls the dumping of
+ buffer data through debugfs instead.
+
+What is the default use case for this driver?
+---------------------------------------------
+
+This driver can be used as a way to compare different userspace implementations.
+This assumes that a working client is run against visl and that the ftrace and
+OUTPUT buffer data is subsequently used to debug a work-in-progress
+implementation.
+
+Information on reference frames, their timestamps, the status of the OUTPUT and
+CAPTURE queues and more can be read directly from the CAPTURE buffers.
+
+Supported codecs
+----------------
+
+The following codecs are supported:
+
+- FWHT
+- MPEG2
+- VP8
+- VP9
+- H.264
+- HEVC
+
+visl trace events
+-----------------
+The trace events are defined on a per-codec basis, e.g.:
+
+.. code-block:: bash
+
+ $ ls /sys/kernel/debug/tracing/events/ | grep visl
+ visl_fwht_controls
+ visl_h264_controls
+ visl_hevc_controls
+ visl_mpeg2_controls
+ visl_vp8_controls
+ visl_vp9_controls
+
+For example, in order to dump HEVC SPS data:
+
+.. code-block:: bash
+
+ $ echo 1 > /sys/kernel/debug/tracing/events/visl_hevc_controls/v4l2_ctrl_hevc_sps/enable
+
+The SPS data will be dumped to the trace buffer, i.e.:
+
+.. code-block:: bash
+
+ $ cat /sys/kernel/debug/tracing/trace
+ video_parameter_set_id 0
+ seq_parameter_set_id 0
+ pic_width_in_luma_samples 1920
+ pic_height_in_luma_samples 1080
+ bit_depth_luma_minus8 0
+ bit_depth_chroma_minus8 0
+ log2_max_pic_order_cnt_lsb_minus4 4
+ sps_max_dec_pic_buffering_minus1 6
+ sps_max_num_reorder_pics 2
+ sps_max_latency_increase_plus1 0
+ log2_min_luma_coding_block_size_minus3 0
+ log2_diff_max_min_luma_coding_block_size 3
+ log2_min_luma_transform_block_size_minus2 0
+ log2_diff_max_min_luma_transform_block_size 3
+ max_transform_hierarchy_depth_inter 2
+ max_transform_hierarchy_depth_intra 2
+ pcm_sample_bit_depth_luma_minus1 0
+ pcm_sample_bit_depth_chroma_minus1 0
+ log2_min_pcm_luma_coding_block_size_minus3 0
+ log2_diff_max_min_pcm_luma_coding_block_size 0
+ num_short_term_ref_pic_sets 0
+ num_long_term_ref_pics_sps 0
+ chroma_format_idc 1
+ sps_max_sub_layers_minus1 0
+ flags AMP_ENABLED|SAMPLE_ADAPTIVE_OFFSET|TEMPORAL_MVP_ENABLED|STRONG_INTRA_SMOOTHING_ENABLED
+
+
+Dumping OUTPUT buffer data through debugfs
+------------------------------------------
+
+If the **VISL_DEBUGFS** Kconfig is enabled, visl will populate
+**/sys/kernel/debug/visl/bitstream** with OUTPUT buffer data according to the
+values of bitstream_trace_frame_start and bitstream_trace_nframes. This can
+highlight errors as broken clients may fail to fill the buffers properly.
+
+A single file is created for each processed OUTPUT buffer. Its name contains an
+integer that denotes the buffer sequence, i.e.:
+
+.. code-block:: c
+
+ snprintf(name, 32, "bitstream%d", run->src->sequence);
+
+Dumping the values is simply a matter of reading from the file, i.e.:
+
+For the buffer with sequence == 0:
+
+.. code-block:: bash
+
+ $ xxd /sys/kernel/debug/visl/bitstream/bitstream0
+ 00000000: 2601 af04 d088 bc25 a173 0e41 a4f2 3274 &......%.s.A..2t
+ 00000010: c668 cb28 e775 b4ac f53a ba60 f8fd 3aa1 .h.(.u...:.`..:.
+ 00000020: 46b4 bcfc 506c e227 2372 e5f5 d7ea 579f F...Pl.'#r....W.
+ 00000030: 6371 5eb5 0eb8 23b5 ca6a 5de5 983a 19e4 cq^...#..j]..:..
+ 00000040: e8c3 4320 b4ba a226 cbc1 4138 3a12 32d6 ..C ...&..A8:.2.
+ 00000050: fef3 247b 3523 4e90 9682 ac8e eb0c a389 ..${5#N.........
+ 00000060: ddd0 6cfc 0187 0e20 7aae b15b 1812 3d33 ..l.... z..[..=3
+ 00000070: e1c5 f425 a83a 00b7 4f18 8127 3c4c aefb ...%.:..O..'<L..
+
+For the buffer with sequence == 1:
+
+.. code-block:: bash
+
+ $ xxd /sys/kernel/debug/visl/bitstream/bitstream1
+ 00000000: 0201 d021 49e1 0c40 aa11 1449 14a6 01dc ...!I..@...I....
+ 00000010: 7023 889a c8cd 2cd0 13b4 dab0 e8ca 21fe p#....,.......!.
+ 00000020: c4c8 ab4c 486e 4e2f b0df 96cc c74e 8dde ...LHnN/.....N..
+ 00000030: 8ce7 ee36 d880 4095 4d64 30a0 ff4f 0c5e ...6..@.Md0..O.^
+ 00000040: f16b a6a1 d806 ca2a 0ece a673 7bea 1f37 .k.....*...s{..7
+ 00000050: 370f 5bb9 1dc4 ba21 6434 bc53 0173 cba0 7.[....!d4.S.s..
+ 00000060: dfe6 bc99 01ea b6e0 346b 92b5 c8de 9f5d ........4k.....]
+ 00000070: e7cc 3484 1769 fef2 a693 a945 2c8b 31da ..4..i.....E,.1.
+
+And so on.
+
+By default, the files are removed during STREAMOFF. This is to reduce the amount
+of clutter.
diff --git a/Documentation/admin-guide/media/vivid.rst b/Documentation/admin-guide/media/vivid.rst
index abd90ed31090..672a8371f6ad 100644
--- a/Documentation/admin-guide/media/vivid.rst
+++ b/Documentation/admin-guide/media/vivid.rst
@@ -392,7 +392,7 @@ Which one is returned depends on the chosen channel, each next valid channel
will cycle through the possible audio subchannel combinations. This allows
you to test the various combinations by just switching channels..
-Finally, for these inputs the v4l2_timecode struct is filled in in the
+Finally, for these inputs the v4l2_timecode struct is filled in the
dequeued v4l2_buffer struct.
diff --git a/Documentation/admin-guide/mm/zswap.rst b/Documentation/admin-guide/mm/zswap.rst
index 6e6f7b0d6562..f67de481c7f6 100644
--- a/Documentation/admin-guide/mm/zswap.rst
+++ b/Documentation/admin-guide/mm/zswap.rst
@@ -14,13 +14,7 @@ for potentially reduced swap I/O. This trade-off can also result in a
significant performance improvement if reads from the compressed cache are
faster than reads from a swap device.
-.. note::
- Zswap is a new feature as of v3.11 and interacts heavily with memory
- reclaim. This interaction has not been fully explored on the large set of
- potential configurations and workloads that exist. For this reason, zswap
- is a work in progress and should be considered experimental.
-
- Some potential benefits:
+Some potential benefits:
* Desktop/laptop users with limited RAM capacities can mitigate the
performance impact of swapping.
diff --git a/Documentation/admin-guide/perf/hisi-pcie-pmu.rst b/Documentation/admin-guide/perf/hisi-pcie-pmu.rst
index 294ebbdb22af..7e863662e2d4 100644
--- a/Documentation/admin-guide/perf/hisi-pcie-pmu.rst
+++ b/Documentation/admin-guide/perf/hisi-pcie-pmu.rst
@@ -15,10 +15,10 @@ HiSilicon PCIe PMU driver
The PCIe PMU driver registers a perf PMU with the name of its sicl-id and PCIe
Core id.::
- /sys/bus/event_source/hisi_pcie<sicl>_<core>
+ /sys/bus/event_source/hisi_pcie<sicl>_core<core>
PMU driver provides description of available events and filter options in sysfs,
-see /sys/bus/event_source/devices/hisi_pcie<sicl>_<core>.
+see /sys/bus/event_source/devices/hisi_pcie<sicl>_core<core>.
The "format" directory describes all formats of the config (events) and config1
(filter options) fields of the perf_event_attr structure. The "events" directory
@@ -33,13 +33,13 @@ monitored by PMU.
Example usage of perf::
$# perf list
- hisi_pcie0_0/rx_mwr_latency/ [kernel PMU event]
- hisi_pcie0_0/rx_mwr_cnt/ [kernel PMU event]
+ hisi_pcie0_core0/rx_mwr_latency/ [kernel PMU event]
+ hisi_pcie0_core0/rx_mwr_cnt/ [kernel PMU event]
------------------------------------------
- $# perf stat -e hisi_pcie0_0/rx_mwr_latency/
- $# perf stat -e hisi_pcie0_0/rx_mwr_cnt/
- $# perf stat -g -e hisi_pcie0_0/rx_mwr_latency/ -e hisi_pcie0_0/rx_mwr_cnt/
+ $# perf stat -e hisi_pcie0_core0/rx_mwr_latency/
+ $# perf stat -e hisi_pcie0_core0/rx_mwr_cnt/
+ $# perf stat -g -e hisi_pcie0_core0/rx_mwr_latency/ -e hisi_pcie0_core0/rx_mwr_cnt/
The current driver does not support sampling. So "perf record" is unsupported.
Also attach to a task is unsupported for PCIe PMU.
@@ -48,59 +48,83 @@ Filter options
--------------
1. Target filter
-PMU could only monitor the performance of traffic downstream target Root Ports
-or downstream target Endpoint. PCIe PMU driver support "port" and "bdf"
-interfaces for users, and these two interfaces aren't supported at the same
-time.
--port
-"port" filter can be used in all PCIe PMU events, target Root Port can be
-selected by configuring the 16-bits-bitmap "port". Multi ports can be selected
-for AP-layer-events, and only one port can be selected for TL/DL-layer-events.
+ PMU could only monitor the performance of traffic downstream target Root
+ Ports or downstream target Endpoint. PCIe PMU driver support "port" and
+ "bdf" interfaces for users, and these two interfaces aren't supported at the
+ same time.
-For example, if target Root Port is 0000:00:00.0 (x8 lanes), bit0 of bitmap
-should be set, port=0x1; if target Root Port is 0000:00:04.0 (x4 lanes),
-bit8 is set, port=0x100; if these two Root Ports are both monitored, port=0x101.
+ - port
-Example usage of perf::
+ "port" filter can be used in all PCIe PMU events, target Root Port can be
+ selected by configuring the 16-bits-bitmap "port". Multi ports can be
+ selected for AP-layer-events, and only one port can be selected for
+ TL/DL-layer-events.
- $# perf stat -e hisi_pcie0_0/rx_mwr_latency,port=0x1/ sleep 5
+ For example, if target Root Port is 0000:00:00.0 (x8 lanes), bit0 of
+ bitmap should be set, port=0x1; if target Root Port is 0000:00:04.0 (x4
+ lanes), bit8 is set, port=0x100; if these two Root Ports are both
+ monitored, port=0x101.
--bdf
+ Example usage of perf::
-"bdf" filter can only be used in bandwidth events, target Endpoint is selected
-by configuring BDF to "bdf". Counter only counts the bandwidth of message
-requested by target Endpoint.
+ $# perf stat -e hisi_pcie0_core0/rx_mwr_latency,port=0x1/ sleep 5
-For example, "bdf=0x3900" means BDF of target Endpoint is 0000:39:00.0.
+ - bdf
-Example usage of perf::
+ "bdf" filter can only be used in bandwidth events, target Endpoint is
+ selected by configuring BDF to "bdf". Counter only counts the bandwidth of
+ message requested by target Endpoint.
+
+ For example, "bdf=0x3900" means BDF of target Endpoint is 0000:39:00.0.
+
+ Example usage of perf::
- $# perf stat -e hisi_pcie0_0/rx_mrd_flux,bdf=0x3900/ sleep 5
+ $# perf stat -e hisi_pcie0_core0/rx_mrd_flux,bdf=0x3900/ sleep 5
2. Trigger filter
-Event statistics start when the first time TLP length is greater/smaller
-than trigger condition. You can set the trigger condition by writing "trig_len",
-and set the trigger mode by writing "trig_mode". This filter can only be used
-in bandwidth events.
-For example, "trig_len=4" means trigger condition is 2^4 DW, "trig_mode=0"
-means statistics start when TLP length > trigger condition, "trig_mode=1"
-means start when TLP length < condition.
+ Event statistics start when the first time TLP length is greater/smaller
+ than trigger condition. You can set the trigger condition by writing
+ "trig_len", and set the trigger mode by writing "trig_mode". This filter can
+ only be used in bandwidth events.
-Example usage of perf::
+ For example, "trig_len=4" means trigger condition is 2^4 DW, "trig_mode=0"
+ means statistics start when TLP length > trigger condition, "trig_mode=1"
+ means start when TLP length < condition.
+
+ Example usage of perf::
- $# perf stat -e hisi_pcie0_0/rx_mrd_flux,trig_len=0x4,trig_mode=1/ sleep 5
+ $# perf stat -e hisi_pcie0_core0/rx_mrd_flux,trig_len=0x4,trig_mode=1/ sleep 5
3. Threshold filter
-Counter counts when TLP length within the specified range. You can set the
-threshold by writing "thr_len", and set the threshold mode by writing
-"thr_mode". This filter can only be used in bandwidth events.
-For example, "thr_len=4" means threshold is 2^4 DW, "thr_mode=0" means
-counter counts when TLP length >= threshold, and "thr_mode=1" means counts
-when TLP length < threshold.
+ Counter counts when TLP length within the specified range. You can set the
+ threshold by writing "thr_len", and set the threshold mode by writing
+ "thr_mode". This filter can only be used in bandwidth events.
-Example usage of perf::
+ For example, "thr_len=4" means threshold is 2^4 DW, "thr_mode=0" means
+ counter counts when TLP length >= threshold, and "thr_mode=1" means counts
+ when TLP length < threshold.
+
+ Example usage of perf::
+
+ $# perf stat -e hisi_pcie0_core0/rx_mrd_flux,thr_len=0x4,thr_mode=1/ sleep 5
+
+4. TLP Length filter
+
+ When counting bandwidth, the data can be composed of certain parts of TLP
+ packets. You can specify it through "len_mode":
+
+ - 2'b00: Reserved (Do not use this since the behaviour is undefined)
+ - 2'b01: Bandwidth of TLP payloads
+ - 2'b10: Bandwidth of TLP headers
+ - 2'b11: Bandwidth of both TLP payloads and headers
+
+ For example, "len_mode=2" means only counting the bandwidth of TLP headers
+ and "len_mode=3" means the final bandwidth data is composed of both TLP
+ headers and payloads. Default value if not specified is 2'b11.
+
+ Example usage of perf::
- $# perf stat -e hisi_pcie0_0/rx_mrd_flux,thr_len=0x4,thr_mode=1/ sleep 5
+ $# perf stat -e hisi_pcie0_core0/rx_mrd_flux,len_mode=0x1/ sleep 5
diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst
index 793e1970bc05..9de64a40adab 100644
--- a/Documentation/admin-guide/perf/index.rst
+++ b/Documentation/admin-guide/perf/index.rst
@@ -19,3 +19,5 @@ Performance monitor support
arm_dsu_pmu
thunderx2-pmu
alibaba_pmu
+ nvidia-pmu
+ meson-ddr-pmu
diff --git a/Documentation/admin-guide/perf/meson-ddr-pmu.rst b/Documentation/admin-guide/perf/meson-ddr-pmu.rst
new file mode 100644
index 000000000000..8e71be1d6346
--- /dev/null
+++ b/Documentation/admin-guide/perf/meson-ddr-pmu.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================================================
+Amlogic SoC DDR Bandwidth Performance Monitoring Unit (PMU)
+===========================================================
+
+The Amlogic Meson G12 SoC contains a bandwidth monitor inside DRAM controller.
+The monitor includes 4 channels. Each channel can count the request accessing
+DRAM. The channel can count up to 3 AXI port simultaneously. It can be helpful
+to show if the performance bottleneck is on DDR bandwidth.
+
+Currently, this driver supports the following 5 perf events:
+
++ meson_ddr_bw/total_rw_bytes/
++ meson_ddr_bw/chan_1_rw_bytes/
++ meson_ddr_bw/chan_2_rw_bytes/
++ meson_ddr_bw/chan_3_rw_bytes/
++ meson_ddr_bw/chan_4_rw_bytes/
+
+meson_ddr_bw/chan_{1,2,3,4}_rw_bytes/ events are channel-specific events.
+Each channel support filtering, which can let the channel to monitor
+individual IP module in SoC.
+
+Below are DDR access request event filter keywords:
+
++ arm - from CPU
++ vpu_read1 - from OSD + VPP read
++ gpu - from 3D GPU
++ pcie - from PCIe controller
++ hdcp - from HDCP controller
++ hevc_front - from HEVC codec front end
++ usb3_0 - from USB3.0 controller
++ hevc_back - from HEVC codec back end
++ h265enc - from HEVC encoder
++ vpu_read2 - from DI read
++ vpu_write1 - from VDIN write
++ vpu_write2 - from di write
++ vdec - from legacy codec video decoder
++ hcodec - from H264 encoder
++ ge2d - from ge2d
++ spicc1 - from SPI controller 1
++ usb0 - from USB2.0 controller 0
++ dma - from system DMA controller 1
++ arb0 - from arb0
++ sd_emmc_b - from SD eMMC b controller
++ usb1 - from USB2.0 controller 1
++ audio - from Audio module
++ sd_emmc_c - from SD eMMC c controller
++ spicc2 - from SPI controller 2
++ ethernet - from Ethernet controller
+
+
+Examples:
+
+ + Show the total DDR bandwidth per seconds:
+
+ .. code-block:: bash
+
+ perf stat -a -e meson_ddr_bw/total_rw_bytes/ -I 1000 sleep 10
+
+
+ + Show individual DDR bandwidth from CPU and GPU respectively, as well as
+ sum of them:
+
+ .. code-block:: bash
+
+ perf stat -a -e meson_ddr_bw/chan_1_rw_bytes,arm=1/ -I 1000 sleep 10
+ perf stat -a -e meson_ddr_bw/chan_2_rw_bytes,gpu=1/ -I 1000 sleep 10
+ perf stat -a -e meson_ddr_bw/chan_3_rw_bytes,arm=1,gpu=1/ -I 1000 sleep 10
+
diff --git a/Documentation/admin-guide/perf/nvidia-pmu.rst b/Documentation/admin-guide/perf/nvidia-pmu.rst
new file mode 100644
index 000000000000..2e0d47cfe7ea
--- /dev/null
+++ b/Documentation/admin-guide/perf/nvidia-pmu.rst
@@ -0,0 +1,299 @@
+=========================================================
+NVIDIA Tegra SoC Uncore Performance Monitoring Unit (PMU)
+=========================================================
+
+The NVIDIA Tegra SoC includes various system PMUs to measure key performance
+metrics like memory bandwidth, latency, and utilization:
+
+* Scalable Coherency Fabric (SCF)
+* NVLink-C2C0
+* NVLink-C2C1
+* CNVLink
+* PCIE
+
+PMU Driver
+----------
+
+The PMUs in this document are based on ARM CoreSight PMU Architecture as
+described in document: ARM IHI 0091. Since this is a standard architecture, the
+PMUs are managed by a common driver "arm-cs-arch-pmu". This driver describes
+the available events and configuration of each PMU in sysfs. Please see the
+sections below to get the sysfs path of each PMU. Like other uncore PMU drivers,
+the driver provides "cpumask" sysfs attribute to show the CPU id used to handle
+the PMU event. There is also "associated_cpus" sysfs attribute, which contains a
+list of CPUs associated with the PMU instance.
+
+.. _SCF_PMU_Section:
+
+SCF PMU
+-------
+
+The SCF PMU monitors system level cache events, CPU traffic, and
+strongly-ordered (SO) PCIE write traffic to local/remote memory. Please see
+:ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section` for more info about the PMU
+traffic coverage.
+
+The events and configuration options of this PMU device are described in sysfs,
+see /sys/bus/event_sources/devices/nvidia_scf_pmu_<socket-id>.
+
+Example usage:
+
+* Count event id 0x0 in socket 0::
+
+ perf stat -a -e nvidia_scf_pmu_0/event=0x0/
+
+* Count event id 0x0 in socket 1::
+
+ perf stat -a -e nvidia_scf_pmu_1/event=0x0/
+
+NVLink-C2C0 PMU
+--------------------
+
+The NVLink-C2C0 PMU monitors incoming traffic from a GPU/CPU connected with
+NVLink-C2C (Chip-2-Chip) interconnect. The type of traffic captured by this PMU
+varies dependent on the chip configuration:
+
+* NVIDIA Grace Hopper Superchip: Hopper GPU is connected with Grace SoC.
+
+ In this config, the PMU captures GPU ATS translated or EGM traffic from the GPU.
+
+* NVIDIA Grace CPU Superchip: two Grace CPU SoCs are connected.
+
+ In this config, the PMU captures read and relaxed ordered (RO) writes from
+ PCIE device of the remote SoC.
+
+Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section` for more info about
+the PMU traffic coverage.
+
+The events and configuration options of this PMU device are described in sysfs,
+see /sys/bus/event_sources/devices/nvidia_nvlink_c2c0_pmu_<socket-id>.
+
+Example usage:
+
+* Count event id 0x0 from the GPU/CPU connected with socket 0::
+
+ perf stat -a -e nvidia_nvlink_c2c0_pmu_0/event=0x0/
+
+* Count event id 0x0 from the GPU/CPU connected with socket 1::
+
+ perf stat -a -e nvidia_nvlink_c2c0_pmu_1/event=0x0/
+
+* Count event id 0x0 from the GPU/CPU connected with socket 2::
+
+ perf stat -a -e nvidia_nvlink_c2c0_pmu_2/event=0x0/
+
+* Count event id 0x0 from the GPU/CPU connected with socket 3::
+
+ perf stat -a -e nvidia_nvlink_c2c0_pmu_3/event=0x0/
+
+NVLink-C2C1 PMU
+-------------------
+
+The NVLink-C2C1 PMU monitors incoming traffic from a GPU connected with
+NVLink-C2C (Chip-2-Chip) interconnect. This PMU captures untranslated GPU
+traffic, in contrast with NvLink-C2C0 PMU that captures ATS translated traffic.
+Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section` for more info about
+the PMU traffic coverage.
+
+The events and configuration options of this PMU device are described in sysfs,
+see /sys/bus/event_sources/devices/nvidia_nvlink_c2c1_pmu_<socket-id>.
+
+Example usage:
+
+* Count event id 0x0 from the GPU connected with socket 0::
+
+ perf stat -a -e nvidia_nvlink_c2c1_pmu_0/event=0x0/
+
+* Count event id 0x0 from the GPU connected with socket 1::
+
+ perf stat -a -e nvidia_nvlink_c2c1_pmu_1/event=0x0/
+
+* Count event id 0x0 from the GPU connected with socket 2::
+
+ perf stat -a -e nvidia_nvlink_c2c1_pmu_2/event=0x0/
+
+* Count event id 0x0 from the GPU connected with socket 3::
+
+ perf stat -a -e nvidia_nvlink_c2c1_pmu_3/event=0x0/
+
+CNVLink PMU
+---------------
+
+The CNVLink PMU monitors traffic from GPU and PCIE device on remote sockets
+to local memory. For PCIE traffic, this PMU captures read and relaxed ordered
+(RO) write traffic. Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section`
+for more info about the PMU traffic coverage.
+
+The events and configuration options of this PMU device are described in sysfs,
+see /sys/bus/event_sources/devices/nvidia_cnvlink_pmu_<socket-id>.
+
+Each SoC socket can be connected to one or more sockets via CNVLink. The user can
+use "rem_socket" bitmap parameter to select the remote socket(s) to monitor.
+Each bit represents the socket number, e.g. "rem_socket=0xE" corresponds to
+socket 1 to 3.
+/sys/bus/event_sources/devices/nvidia_cnvlink_pmu_<socket-id>/format/rem_socket
+shows the valid bits that can be set in the "rem_socket" parameter.
+
+The PMU can not distinguish the remote traffic initiator, therefore it does not
+provide filter to select the traffic source to monitor. It reports combined
+traffic from remote GPU and PCIE devices.
+
+Example usage:
+
+* Count event id 0x0 for the traffic from remote socket 1, 2, and 3 to socket 0::
+
+ perf stat -a -e nvidia_cnvlink_pmu_0/event=0x0,rem_socket=0xE/
+
+* Count event id 0x0 for the traffic from remote socket 0, 2, and 3 to socket 1::
+
+ perf stat -a -e nvidia_cnvlink_pmu_1/event=0x0,rem_socket=0xD/
+
+* Count event id 0x0 for the traffic from remote socket 0, 1, and 3 to socket 2::
+
+ perf stat -a -e nvidia_cnvlink_pmu_2/event=0x0,rem_socket=0xB/
+
+* Count event id 0x0 for the traffic from remote socket 0, 1, and 2 to socket 3::
+
+ perf stat -a -e nvidia_cnvlink_pmu_3/event=0x0,rem_socket=0x7/
+
+
+PCIE PMU
+------------
+
+The PCIE PMU monitors all read/write traffic from PCIE root ports to
+local/remote memory. Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section`
+for more info about the PMU traffic coverage.
+
+The events and configuration options of this PMU device are described in sysfs,
+see /sys/bus/event_sources/devices/nvidia_pcie_pmu_<socket-id>.
+
+Each SoC socket can support multiple root ports. The user can use
+"root_port" bitmap parameter to select the port(s) to monitor, i.e.
+"root_port=0xF" corresponds to root port 0 to 3.
+/sys/bus/event_sources/devices/nvidia_pcie_pmu_<socket-id>/format/root_port
+shows the valid bits that can be set in the "root_port" parameter.
+
+Example usage:
+
+* Count event id 0x0 from root port 0 and 1 of socket 0::
+
+ perf stat -a -e nvidia_pcie_pmu_0/event=0x0,root_port=0x3/
+
+* Count event id 0x0 from root port 0 and 1 of socket 1::
+
+ perf stat -a -e nvidia_pcie_pmu_1/event=0x0,root_port=0x3/
+
+.. _NVIDIA_Uncore_PMU_Traffic_Coverage_Section:
+
+Traffic Coverage
+----------------
+
+The PMU traffic coverage may vary dependent on the chip configuration:
+
+* **NVIDIA Grace Hopper Superchip**: Hopper GPU is connected with Grace SoC.
+
+ Example configuration with two Grace SoCs::
+
+ ********************************* *********************************
+ * SOCKET-A * * SOCKET-B *
+ * * * *
+ * :::::::: * * :::::::: *
+ * : PCIE : * * : PCIE : *
+ * :::::::: * * :::::::: *
+ * | * * | *
+ * | * * | *
+ * ::::::: ::::::::: * * ::::::::: ::::::: *
+ * : : : : * * : : : : *
+ * : GPU :<--NVLink-->: Grace :<---CNVLink--->: Grace :<--NVLink-->: GPU : *
+ * : : C2C : SoC : * * : SoC : C2C : : *
+ * ::::::: ::::::::: * * ::::::::: ::::::: *
+ * | | * * | | *
+ * | | * * | | *
+ * &&&&&&&& &&&&&&&& * * &&&&&&&& &&&&&&&& *
+ * & GMEM & & CMEM & * * & CMEM & & GMEM & *
+ * &&&&&&&& &&&&&&&& * * &&&&&&&& &&&&&&&& *
+ * * * *
+ ********************************* *********************************
+
+ GMEM = GPU Memory (e.g. HBM)
+ CMEM = CPU Memory (e.g. LPDDR5X)
+
+ |
+ | Following table contains traffic coverage of Grace SoC PMU in socket-A:
+
+ ::
+
+ +--------------+-------+-----------+-----------+-----+----------+----------+
+ | | Source |
+ + +-------+-----------+-----------+-----+----------+----------+
+ | Destination | |GPU ATS |GPU Not-ATS| | Socket-B | Socket-B |
+ | |PCI R/W|Translated,|Translated | CPU | CPU/PCIE1| GPU/PCIE2|
+ | | |EGM | | | | |
+ +==============+=======+===========+===========+=====+==========+==========+
+ | Local | PCIE |NVLink-C2C0|NVLink-C2C1| SCF | SCF PMU | CNVLink |
+ | SYSRAM/CMEM | PMU |PMU |PMU | PMU | | PMU |
+ +--------------+-------+-----------+-----------+-----+----------+----------+
+ | Local GMEM | PCIE | N/A |NVLink-C2C1| SCF | SCF PMU | CNVLink |
+ | | PMU | |PMU | PMU | | PMU |
+ +--------------+-------+-----------+-----------+-----+----------+----------+
+ | Remote | PCIE |NVLink-C2C0|NVLink-C2C1| SCF | | |
+ | SYSRAM/CMEM | PMU |PMU |PMU | PMU | N/A | N/A |
+ | over CNVLink | | | | | | |
+ +--------------+-------+-----------+-----------+-----+----------+----------+
+ | Remote GMEM | PCIE |NVLink-C2C0|NVLink-C2C1| SCF | | |
+ | over CNVLink | PMU |PMU |PMU | PMU | N/A | N/A |
+ +--------------+-------+-----------+-----------+-----+----------+----------+
+
+ PCIE1 traffic represents strongly ordered (SO) writes.
+ PCIE2 traffic represents reads and relaxed ordered (RO) writes.
+
+* **NVIDIA Grace CPU Superchip**: two Grace CPU SoCs are connected.
+
+ Example configuration with two Grace SoCs::
+
+ ******************* *******************
+ * SOCKET-A * * SOCKET-B *
+ * * * *
+ * :::::::: * * :::::::: *
+ * : PCIE : * * : PCIE : *
+ * :::::::: * * :::::::: *
+ * | * * | *
+ * | * * | *
+ * ::::::::: * * ::::::::: *
+ * : : * * : : *
+ * : Grace :<--------NVLink------->: Grace : *
+ * : SoC : * C2C * : SoC : *
+ * ::::::::: * * ::::::::: *
+ * | * * | *
+ * | * * | *
+ * &&&&&&&& * * &&&&&&&& *
+ * & CMEM & * * & CMEM & *
+ * &&&&&&&& * * &&&&&&&& *
+ * * * *
+ ******************* *******************
+
+ GMEM = GPU Memory (e.g. HBM)
+ CMEM = CPU Memory (e.g. LPDDR5X)
+
+ |
+ | Following table contains traffic coverage of Grace SoC PMU in socket-A:
+
+ ::
+
+ +-----------------+-----------+---------+----------+-------------+
+ | | Source |
+ + +-----------+---------+----------+-------------+
+ | Destination | | | Socket-B | Socket-B |
+ | | PCI R/W | CPU | CPU/PCIE1| PCIE2 |
+ | | | | | |
+ +=================+===========+=========+==========+=============+
+ | Local | PCIE PMU | SCF PMU | SCF PMU | NVLink-C2C0 |
+ | SYSRAM/CMEM | | | | PMU |
+ +-----------------+-----------+---------+----------+-------------+
+ | Remote | | | | |
+ | SYSRAM/CMEM | PCIE PMU | SCF PMU | N/A | N/A |
+ | over NVLink-C2C | | | | |
+ +-----------------+-----------+---------+----------+-------------+
+
+ PCIE1 traffic represents strongly ordered (SO) writes.
+ PCIE2 traffic represents reads and relaxed ordered (RO) writes.
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index 8f3d30c5a0d8..5376d53faaa8 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -283,23 +283,19 @@ efficiency frequency management method on AMD processors.
Kernel Module Options for ``amd-pstate``
=========================================
-.. _shared_mem:
+Passive Mode
+------------
-``shared_mem``
-Use a module param (shared_mem) to enable related processors manually with
-**amd_pstate.shared_mem=1**.
-Due to the performance issue on the processors with `Shared Memory Support
-<perf_cap_>`_, we disable it presently and will re-enable this by default
-once we address performance issue with this solution.
+``amd_pstate=passive``
-To check whether the current processor is using `Full MSR Support <perf_cap_>`_
-or `Shared Memory Support <perf_cap_>`_ : ::
-
- ray@hr-test1:~$ lscpu | grep cppc
- Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
-
-If the CPU flags have ``cppc``, then this processor supports `Full MSR Support
-<perf_cap_>`_. Otherwise, it supports `Shared Memory Support <perf_cap_>`_.
+It will be enabled if the ``amd_pstate=passive`` is passed to the kernel in the command line.
+In this mode, ``amd_pstate`` driver software specifies a desired QoS target in the CPPC
+performance scale as a relative number. This can be expressed as percentage of nominal
+performance (infrastructure max). Below the nominal sustained performance level,
+desired performance expresses the average performance level of the processor subject
+to the Performance Reduction Tolerance register. Above the nominal performance level,
+processor must provide at least nominal performance requested and go higher if current
+operating conditions allow.
``cpupower`` tool support for ``amd-pstate``
@@ -409,37 +405,55 @@ Unit Tests for amd-pstate
1. Test case decriptions
+ 1). Basic tests
+
+ Test prerequisite and basic functions for the ``amd-pstate`` driver.
+
+---------+--------------------------------+------------------------------------------------------------------------------------+
| Index | Functions | Description |
+=========+================================+====================================================================================+
- | 0 | amd_pstate_ut_acpi_cpc_valid || Check whether the _CPC object is present in SBIOS. |
+ | 1 | amd_pstate_ut_acpi_cpc_valid || Check whether the _CPC object is present in SBIOS. |
| | || |
| | || The detail refer to `Processor Support <processor_support_>`_. |
+---------+--------------------------------+------------------------------------------------------------------------------------+
- | 1 | amd_pstate_ut_check_enabled || Check whether AMD P-State is enabled. |
+ | 2 | amd_pstate_ut_check_enabled || Check whether AMD P-State is enabled. |
| | || |
| | || AMD P-States and ACPI hardware P-States always can be supported in one processor. |
| | | But AMD P-States has the higher priority and if it is enabled with |
| | | :c:macro:`MSR_AMD_CPPC_ENABLE` or ``cppc_set_enable``, it will respond to the |
| | | request from AMD P-States. |
+---------+--------------------------------+------------------------------------------------------------------------------------+
- | 2 | amd_pstate_ut_check_perf || Check if the each performance values are reasonable. |
+ | 3 | amd_pstate_ut_check_perf || Check if the each performance values are reasonable. |
| | || highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0. |
+---------+--------------------------------+------------------------------------------------------------------------------------+
- | 3 | amd_pstate_ut_check_freq || Check if the each frequency values and max freq when set support boost mode |
+ | 4 | amd_pstate_ut_check_freq || Check if the each frequency values and max freq when set support boost mode |
| | | are reasonable. |
| | || max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0 |
| | || If boost is not active but supported, this maximum frequency will be larger than |
| | | the one in ``cpuinfo``. |
+---------+--------------------------------+------------------------------------------------------------------------------------+
+ 2). Tbench test
+
+ Test and monitor the cpu changes when running tbench benchmark under the specified governor.
+ These changes include desire performance, frequency, load, performance, energy etc.
+ The specified governor is ondemand or schedutil.
+ Tbench can also be tested on the ``acpi-cpufreq`` kernel driver for comparison.
+
+ 3). Gitsource test
+
+ Test and monitor the cpu changes when running gitsource benchmark under the specified governor.
+ These changes include desire performance, frequency, load, time, energy etc.
+ The specified governor is ondemand or schedutil.
+ Gitsource can also be tested on the ``acpi-cpufreq`` kernel driver for comparison.
+
#. How to execute the tests
We use test module in the kselftest frameworks to implement it.
- We create amd-pstate-ut module and tie it into kselftest.(for
+ We create ``amd-pstate-ut`` module and tie it into kselftest.(for
details refer to Linux Kernel Selftests [4]_).
- 1. Build
+ 1). Build
+ open the :c:macro:`CONFIG_X86_AMD_PSTATE` configuration option.
+ set the :c:macro:`CONFIG_X86_AMD_PSTATE_UT` configuration option to M.
@@ -449,23 +463,159 @@ Unit Tests for amd-pstate
$ cd linux
$ make -C tools/testing/selftests
- #. Installation & Steps ::
+ + make perf ::
+
+ $ cd tools/perf/
+ $ make
+
+
+ 2). Installation & Steps ::
$ make -C tools/testing/selftests install INSTALL_PATH=~/kselftest
+ $ cp tools/perf/perf /usr/bin/perf
$ sudo ./kselftest/run_kselftest.sh -c amd-pstate
- TAP version 13
- 1..1
- # selftests: amd-pstate: amd-pstate-ut.sh
- # amd-pstate-ut: ok
- ok 1 selftests: amd-pstate: amd-pstate-ut.sh
-
- #. Results ::
-
- $ dmesg | grep "amd_pstate_ut" | tee log.txt
- [12977.570663] amd_pstate_ut: 1 amd_pstate_ut_acpi_cpc_valid success!
- [12977.570673] amd_pstate_ut: 2 amd_pstate_ut_check_enabled success!
- [12977.571207] amd_pstate_ut: 3 amd_pstate_ut_check_perf success!
- [12977.571212] amd_pstate_ut: 4 amd_pstate_ut_check_freq success!
+
+ 3). Specified test case ::
+
+ $ cd ~/kselftest/amd-pstate
+ $ sudo ./run.sh -t basic
+ $ sudo ./run.sh -t tbench
+ $ sudo ./run.sh -t tbench -m acpi-cpufreq
+ $ sudo ./run.sh -t gitsource
+ $ sudo ./run.sh -t gitsource -m acpi-cpufreq
+ $ ./run.sh --help
+ ./run.sh: illegal option -- -
+ Usage: ./run.sh [OPTION...]
+ [-h <help>]
+ [-o <output-file-for-dump>]
+ [-c <all: All testing,
+ basic: Basic testing,
+ tbench: Tbench testing,
+ gitsource: Gitsource testing.>]
+ [-t <tbench time limit>]
+ [-p <tbench process number>]
+ [-l <loop times for tbench>]
+ [-i <amd tracer interval>]
+ [-m <comparative test: acpi-cpufreq>]
+
+
+ 4). Results
+
+ + basic
+
+ When you finish test, you will get the following log info ::
+
+ $ dmesg | grep "amd_pstate_ut" | tee log.txt
+ [12977.570663] amd_pstate_ut: 1 amd_pstate_ut_acpi_cpc_valid success!
+ [12977.570673] amd_pstate_ut: 2 amd_pstate_ut_check_enabled success!
+ [12977.571207] amd_pstate_ut: 3 amd_pstate_ut_check_perf success!
+ [12977.571212] amd_pstate_ut: 4 amd_pstate_ut_check_freq success!
+
+ + tbench
+
+ When you finish test, you will get selftest.tbench.csv and png images.
+ The selftest.tbench.csv file contains the raw data and the drop of the comparative test.
+ The png images shows the performance, energy and performan per watt of each test.
+ Open selftest.tbench.csv :
+
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + Governor | Round | Des-perf | Freq | Load | Performance | Energy | Performance Per Watt |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + Unit | | | GHz | | MB/s | J | MB/J |
+ +=================================================+==============+==========+=========+==========+=============+=========+======================+
+ + amd-pstate-ondemand | 1 | | | | 2504.05 | 1563.67 | 158.5378 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | 2 | | | | 2243.64 | 1430.32 | 155.2941 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | 3 | | | | 2183.88 | 1401.32 | 154.2860 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | Average | | | | 2310.52 | 1465.1 | 156.1268 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 1 | 165.329 | 1.62257 | 99.798 | 2136.54 | 1395.26 | 151.5971 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 2 | 166 | 1.49761 | 99.9993 | 2100.56 | 1380.5 | 150.6377 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 3 | 166 | 1.47806 | 99.9993 | 2084.12 | 1375.76 | 149.9737 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | Average | 165.776 | 1.53275 | 99.9322 | 2107.07 | 1383.84 | 150.7399 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 1 | | | | 2529.9 | 1564.4 | 160.0997 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 2 | | | | 2249.76 | 1432.97 | 155.4297 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 3 | | | | 2181.46 | 1406.88 | 153.5060 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | Average | | | | 2320.37 | 1468.08 | 156.4741 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 1 | | | | 2137.64 | 1385.24 | 152.7723 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 2 | | | | 2107.05 | 1372.23 | 152.0138 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 3 | | | | 2085.86 | 1365.35 | 151.2433 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | Average | | | | 2110.18 | 1374.27 | 152.0136 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand VS acpi-cpufreq-schedutil | Comprison(%) | | | | -9.0584 | -6.3899 | -2.8506 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand VS amd-pstate-schedutil | Comprison(%) | | | | 8.8053 | -5.5463 | -3.4503 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand VS amd-pstate-ondemand | Comprison(%) | | | | -0.4245 | -0.2029 | -0.2219 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil VS amd-pstate-schedutil | Comprison(%) | | | | -0.1473 | 0.6963 | -0.8378 |
+ +-------------------------------------------------+--------------+----------+---------+----------+-------------+---------+----------------------+
+
+ + gitsource
+
+ When you finish test, you will get selftest.gitsource.csv and png images.
+ The selftest.gitsource.csv file contains the raw data and the drop of the comparative test.
+ The png images shows the performance, energy and performan per watt of each test.
+ Open selftest.gitsource.csv :
+
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + Governor | Round | Des-perf | Freq | Load | Time | Energy | Performance Per Watt |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + Unit | | | GHz | | s | J | 1/J |
+ +=================================================+==============+==========+==========+==========+=============+=========+======================+
+ + amd-pstate-ondemand | 1 | 50.119 | 2.10509 | 23.3076 | 475.69 | 865.78 | 0.001155027 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | 2 | 94.8006 | 1.98771 | 56.6533 | 467.1 | 839.67 | 0.001190944 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | 3 | 76.6091 | 2.53251 | 43.7791 | 467.69 | 855.85 | 0.001168429 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand | Average | 73.8429 | 2.20844 | 41.2467 | 470.16 | 853.767 | 0.001171279 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 1 | 165.919 | 1.62319 | 98.3868 | 464.17 | 866.8 | 0.001153668 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 2 | 165.97 | 1.31309 | 99.5712 | 480.15 | 880.4 | 0.001135847 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | 3 | 165.973 | 1.28448 | 99.9252 | 481.79 | 867.02 | 0.001153375 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-schedutil | Average | 165.954 | 1.40692 | 99.2944 | 475.37 | 871.407 | 0.001147569 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 1 | | | | 2379.62 | 742.96 | 0.001345967 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 2 | | | | 441.74 | 817.49 | 0.001223256 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | 3 | | | | 455.48 | 820.01 | 0.001219497 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand | Average | | | | 425.613 | 793.487 | 0.001260260 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 1 | | | | 459.69 | 838.54 | 0.001192548 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 2 | | | | 466.55 | 830.89 | 0.001203528 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | 3 | | | | 470.38 | 837.32 | 0.001194286 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil | Average | | | | 465.54 | 835.583 | 0.001196769 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand VS acpi-cpufreq-schedutil | Comprison(%) | | | | 9.3810 | 5.3051 | -5.0379 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + amd-pstate-ondemand VS amd-pstate-schedutil | Comprison(%) | 124.7392 | -36.2934 | 140.7329 | 1.1081 | 2.0661 | -2.0242 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-ondemand VS amd-pstate-ondemand | Comprison(%) | | | | 10.4665 | 7.5968 | -7.0605 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
+ + acpi-cpufreq-schedutil VS amd-pstate-schedutil | Comprison(%) | | | | 2.1115 | 4.2873 | -4.1110 |
+ +-------------------------------------------------+--------------+----------+----------+----------+-------------+---------+----------------------+
Reference
===========
diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst
index 2a501c9ddc55..a321b84eccaa 100644
--- a/Documentation/admin-guide/sysctl/fs.rst
+++ b/Documentation/admin-guide/sysctl/fs.rst
@@ -2,8 +2,6 @@
Documentation for /proc/sys/fs/
===============================
-kernel version 2.2.10
-
Copyright (c) 1998, 1999, Rik van Riel <riel@nl.linux.org>
Copyright (c) 2009, Shen Feng<shen@cn.fujitsu.com>
@@ -12,58 +10,40 @@ For general info and legal blurb, please look in intro.rst.
------------------------------------------------------------------------------
-This file contains documentation for the sysctl files in
-/proc/sys/fs/ and is valid for Linux kernel version 2.2.
+This file contains documentation for the sysctl files and directories
+in ``/proc/sys/fs/``.
The files in this directory can be used to tune and monitor
miscellaneous and general things in the operation of the Linux
-kernel. Since some of the files _can_ be used to screw up your
+kernel. Since some of the files *can* be used to screw up your
system, it is advisable to read both documentation and source
before actually making adjustments.
1. /proc/sys/fs
===============
-Currently, these files are in /proc/sys/fs:
-
-- aio-max-nr
-- aio-nr
-- dentry-state
-- dquot-max
-- dquot-nr
-- file-max
-- file-nr
-- inode-max
-- inode-nr
-- inode-state
-- nr_open
-- overflowuid
-- overflowgid
-- pipe-user-pages-hard
-- pipe-user-pages-soft
-- protected_fifos
-- protected_hardlinks
-- protected_regular
-- protected_symlinks
-- suid_dumpable
-- super-max
-- super-nr
+Currently, these files might (depending on your configuration)
+show up in ``/proc/sys/fs``:
+
+.. contents:: :local:
aio-nr & aio-max-nr
-------------------
-aio-nr is the running total of the number of events specified on the
-io_setup system call for all currently active aio contexts. If aio-nr
-reaches aio-max-nr then io_setup will fail with EAGAIN. Note that
-raising aio-max-nr does not result in the pre-allocation or re-sizing
-of any kernel data structures.
+``aio-nr`` shows the current system-wide number of asynchronous io
+requests. ``aio-max-nr`` allows you to change the maximum value
+``aio-nr`` can grow to. If ``aio-nr`` reaches ``aio-nr-max`` then
+``io_setup`` will fail with ``EAGAIN``. Note that raising
+``aio-max-nr`` does not result in the
+pre-allocation or re-sizing of any kernel data structures.
dentry-state
------------
-From linux/include/linux/dcache.h::
+This file shows the values in ``struct dentry_stat``, as defined in
+``linux/include/linux/dcache.h``::
struct dentry_stat_t dentry_stat {
int nr_dentry;
@@ -76,95 +56,84 @@ From linux/include/linux/dcache.h::
Dentries are dynamically allocated and deallocated.
-nr_dentry shows the total number of dentries allocated (active
-+ unused). nr_unused shows the number of dentries that are not
+``nr_dentry`` shows the total number of dentries allocated (active
++ unused). ``nr_unused shows`` the number of dentries that are not
actively used, but are saved in the LRU list for future reuse.
-Age_limit is the age in seconds after which dcache entries
-can be reclaimed when memory is short and want_pages is
-nonzero when shrink_dcache_pages() has been called and the
+``age_limit`` is the age in seconds after which dcache entries
+can be reclaimed when memory is short and ``want_pages`` is
+nonzero when ``shrink_dcache_pages()`` has been called and the
dcache isn't pruned yet.
-nr_negative shows the number of unused dentries that are also
+``nr_negative`` shows the number of unused dentries that are also
negative dentries which do not map to any files. Instead,
they help speeding up rejection of non-existing files provided
by the users.
-dquot-max & dquot-nr
---------------------
-
-The file dquot-max shows the maximum number of cached disk
-quota entries.
-
-The file dquot-nr shows the number of allocated disk quota
-entries and the number of free disk quota entries.
-
-If the number of free cached disk quotas is very low and
-you have some awesome number of simultaneous system users,
-you might want to raise the limit.
-
-
file-max & file-nr
------------------
-The value in file-max denotes the maximum number of file-
+The value in ``file-max`` denotes the maximum number of file-
handles that the Linux kernel will allocate. When you get lots
of error messages about running out of file handles, you might
want to increase this limit.
Historically,the kernel was able to allocate file handles
dynamically, but not to free them again. The three values in
-file-nr denote the number of allocated file handles, the number
+``file-nr`` denote the number of allocated file handles, the number
of allocated but unused file handles, and the maximum number of
-file handles. Linux 2.6 always reports 0 as the number of free
+file handles. Linux 2.6 and later always reports 0 as the number of free
file handles -- this is not an error, it just means that the
number of allocated file handles exactly matches the number of
used file handles.
-Attempts to allocate more file descriptors than file-max are
-reported with printk, look for "VFS: file-max limit <number>
-reached".
+Attempts to allocate more file descriptors than ``file-max`` are
+reported with ``printk``, look for::
+ VFS: file-max limit <number> reached
-nr_open
--------
-
-This denotes the maximum number of file-handles a process can
-allocate. Default value is 1024*1024 (1048576) which should be
-enough for most machines. Actual limit depends on RLIMIT_NOFILE
-resource limit.
+in the kernel logs.
-inode-max, inode-nr & inode-state
----------------------------------
+inode-nr & inode-state
+----------------------
As with file handles, the kernel allocates the inode structures
dynamically, but can't free them yet.
-The value in inode-max denotes the maximum number of inode
-handlers. This value should be 3-4 times larger than the value
-in file-max, since stdin, stdout and network sockets also
-need an inode struct to handle them. When you regularly run
-out of inodes, you need to increase this value.
-
-The file inode-nr contains the first two items from
-inode-state, so we'll skip to that file...
+The file ``inode-nr`` contains the first two items from
+``inode-state``, so we'll skip to that file...
-Inode-state contains three actual numbers and four dummies.
-The actual numbers are, in order of appearance, nr_inodes,
-nr_free_inodes and preshrink.
+``inode-state`` contains three actual numbers and four dummies.
+The actual numbers are, in order of appearance, ``nr_inodes``,
+``nr_free_inodes`` and ``preshrink``.
-Nr_inodes stands for the number of inodes the system has
-allocated, this can be slightly more than inode-max because
-Linux allocates them one pageful at a time.
+``nr_inodes`` stands for the number of inodes the system has
+allocated.
-Nr_free_inodes represents the number of free inodes (?) and
-preshrink is nonzero when the nr_inodes > inode-max and the
+``nr_free_inodes`` represents the number of free inodes (?) and
+preshrink is nonzero when the
system needs to prune the inode list instead of allocating
more.
+mount-max
+---------
+
+This denotes the maximum number of mounts that may exist
+in a mount namespace.
+
+
+nr_open
+-------
+
+This denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on ``RLIMIT_NOFILE``
+resource limit.
+
+
overflowgid & overflowuid
-------------------------
@@ -192,7 +161,7 @@ pipe-user-pages-soft
Maximum total number of pages a non-privileged user may allocate for pipes
before the pipe size gets limited to a single page. Once this limit is reached,
new pipes will be limited to a single page in size for this user in order to
-limit total memory usage, and trying to increase them using fcntl() will be
+limit total memory usage, and trying to increase them using ``fcntl()`` will be
denied until usage goes below the limit again. The default value allows to
allocate up to 1024 pipes at their default size. When set to 0, no limit is
applied.
@@ -207,7 +176,7 @@ file.
When set to "0", writing to FIFOs is unrestricted.
-When set to "1" don't allow O_CREAT open on FIFOs that we don't own
+When set to "1" don't allow ``O_CREAT`` open on FIFOs that we don't own
in world writable sticky directories, unless they are owned by the
owner of the directory.
@@ -221,7 +190,7 @@ protected_hardlinks
A long-standing class of security issues is the hardlink-based
time-of-check-time-of-use race, most commonly seen in world-writable
-directories like /tmp. The common method of exploitation of this flaw
+directories like ``/tmp``. The common method of exploitation of this flaw
is to cross privilege boundaries when following a given hardlink (i.e. a
root process follows a hardlink created by another user). Additionally,
on systems without separated partitions, this stops unauthorized users
@@ -239,13 +208,13 @@ This protection is based on the restrictions in Openwall and grsecurity.
protected_regular
-----------------
-This protection is similar to protected_fifos, but it
+This protection is similar to `protected_fifos`_, but it
avoids writes to an attacker-controlled regular file, where a program
expected to create one.
When set to "0", writing to regular files is unrestricted.
-When set to "1" don't allow O_CREAT open on regular files that we
+When set to "1" don't allow ``O_CREAT`` open on regular files that we
don't own in world writable sticky directories, unless they are
owned by the owner of the directory.
@@ -257,7 +226,7 @@ protected_symlinks
A long-standing class of security issues is the symlink-based
time-of-check-time-of-use race, most commonly seen in world-writable
-directories like /tmp. The common method of exploitation of this flaw
+directories like ``/tmp``. The common method of exploitation of this flaw
is to cross privilege boundaries when following a given symlink (i.e. a
root process follows a symlink belonging to another user). For a likely
incomplete list of hundreds of examples across the years, please see:
@@ -272,23 +241,25 @@ follower match, or when the directory owner matches the symlink's owner.
This protection is based on the restrictions in Openwall and grsecurity.
-suid_dumpable:
---------------
+suid_dumpable
+-------------
This value can be used to query and set the core dump mode for setuid
or otherwise protected/tainted binaries. The modes are
= ========== ===============================================================
-0 (default) traditional behaviour. Any process which has changed
+0 (default) Traditional behaviour. Any process which has changed
privilege levels or is execute only will not be dumped.
-1 (debug) all processes dump core when possible. The core dump is
+1 (debug) All processes dump core when possible. The core dump is
owned by the current user and no security is applied. This is
intended for system debugging situations only.
Ptrace is unchecked.
This is insecure as it allows regular users to examine the
memory contents of privileged processes.
-2 (suidsafe) any binary which normally would not be dumped is dumped
- anyway, but only if the "core_pattern" kernel sysctl is set to
+2 (suidsafe) Any binary which normally would not be dumped is dumped
+ anyway, but only if the ``core_pattern`` kernel sysctl (see
+ :ref:`Documentation/admin-guide/sysctl/kernel.rst <core_pattern>`)
+ is set to
either a pipe handler or a fully qualified path. (For more
details on this limitation, see CVE-2006-2451.) This mode is
appropriate when administrators are attempting to debug
@@ -301,36 +272,11 @@ or otherwise protected/tainted binaries. The modes are
= ========== ===============================================================
-super-max & super-nr
---------------------
-
-These numbers control the maximum number of superblocks, and
-thus the maximum number of mounted filesystems the kernel
-can have. You only need to increase super-max if you need to
-mount more filesystems than the current value in super-max
-allows you to.
-
-
-aio-nr & aio-max-nr
--------------------
-
-aio-nr shows the current system-wide number of asynchronous io
-requests. aio-max-nr allows you to change the maximum value
-aio-nr can grow to.
-
-
-mount-max
----------
-
-This denotes the maximum number of mounts that may exist
-in a mount namespace.
-
-
2. /proc/sys/fs/binfmt_misc
===========================
-Documentation for the files in /proc/sys/fs/binfmt_misc is
+Documentation for the files in ``/proc/sys/fs/binfmt_misc`` is
in Documentation/admin-guide/binfmt-misc.rst.
@@ -343,28 +289,32 @@ creation of a user space library that implements the POSIX message queues
API (as noted by the MSG tag in the POSIX 1003.1-2001 version of the System
Interfaces specification.)
-The "mqueue" filesystem contains values for determining/setting the amount of
-resources used by the file system.
+The "mqueue" filesystem contains values for determining/setting the
+amount of resources used by the file system.
-/proc/sys/fs/mqueue/queues_max is a read/write file for setting/getting the
-maximum number of message queues allowed on the system.
+``/proc/sys/fs/mqueue/queues_max`` is a read/write file for
+setting/getting the maximum number of message queues allowed on the
+system.
-/proc/sys/fs/mqueue/msg_max is a read/write file for setting/getting the
-maximum number of messages in a queue value. In fact it is the limiting value
-for another (user) limit which is set in mq_open invocation. This attribute of
-a queue must be less or equal then msg_max.
+``/proc/sys/fs/mqueue/msg_max`` is a read/write file for
+setting/getting the maximum number of messages in a queue value. In
+fact it is the limiting value for another (user) limit which is set in
+``mq_open`` invocation. This attribute of a queue must be less than
+or equal to ``msg_max``.
-/proc/sys/fs/mqueue/msgsize_max is a read/write file for setting/getting the
-maximum message size value (it is every message queue's attribute set during
-its creation).
+``/proc/sys/fs/mqueue/msgsize_max`` is a read/write file for
+setting/getting the maximum message size value (it is an attribute of
+every message queue, set during its creation).
-/proc/sys/fs/mqueue/msg_default is a read/write file for setting/getting the
-default number of messages in a queue value if attr parameter of mq_open(2) is
-NULL. If it exceed msg_max, the default value is initialized msg_max.
+``/proc/sys/fs/mqueue/msg_default`` is a read/write file for
+setting/getting the default number of messages in a queue value if the
+``attr`` parameter of ``mq_open(2)`` is ``NULL``. If it exceeds
+``msg_max``, the default value is initialized to ``msg_max``.
-/proc/sys/fs/mqueue/msgsize_default is a read/write file for setting/getting
-the default message size value if attr parameter of mq_open(2) is NULL. If it
-exceed msgsize_max, the default value is initialized msgsize_max.
+``/proc/sys/fs/mqueue/msgsize_default`` is a read/write file for
+setting/getting the default message size value if the ``attr``
+parameter of ``mq_open(2)`` is ``NULL``. If it exceeds
+``msgsize_max``, the default value is initialized to ``msgsize_max``.
4. /proc/sys/fs/epoll - Configuration options for the epoll interface
=====================================================================
@@ -378,7 +328,7 @@ Every epoll file descriptor can store a number of files to be monitored
for event readiness. Each one of these monitored files constitutes a "watch".
This configuration option sets the maximum number of "watches" that are
allowed for each user.
-Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
-on a 64bit one.
-The current default value for max_user_watches is the 1/25 (4%) of the
-available low memory, divided for the "watch" cost in bytes.
+Each "watch" costs roughly 90 bytes on a 32-bit kernel, and roughly 160 bytes
+on a 64-bit one.
+The current default value for ``max_user_watches`` is 4% of the
+available low memory, divided by the "watch" cost in bytes.
diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index 98d1b198b2b4..39e7a2d46e1e 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -139,6 +139,8 @@ Highest valid capability of the running kernel. Exports
``CAP_LAST_CAP`` from the kernel.
+.. _core_pattern:
+
core_pattern
============
@@ -174,6 +176,7 @@ core_pattern
%f executable filename
%E executable path
%c maximum size of core file by resource limit RLIMIT_CORE
+ %C CPU the task ran on
%<OTHER> both are dropped
======== ==========================================
@@ -1314,6 +1317,29 @@ watchdog work to be queued by the watchdog timer function, otherwise the NMI
watchdog — if enabled — can detect a hard lockup condition.
+split_lock_mitigate (x86 only)
+==============================
+
+On x86, each "split lock" imposes a system-wide performance penalty. On larger
+systems, large numbers of split locks from unprivileged users can result in
+denials of service to well-behaved and potentially more important users.
+
+The kernel mitigates these bad users by detecting split locks and imposing
+penalties: forcing them to wait and only allowing one core to execute split
+locks at a time.
+
+These mitigations can make those bad applications unbearably slow. Setting
+split_lock_mitigate=0 may restore some application performance, but will also
+increase system exposure to denial of service attacks from split lock users.
+
+= ===================================================================
+0 Disable the mitigation mode - just warns the split lock on kernel log
+ and exposes the system to denials of service from the split lockers.
+1 Enable the mitigation mode (this is the default) - penalizes the split
+ lockers with intentional performance degradation.
+= ===================================================================
+
+
stack_erasing
=============
diff --git a/Documentation/arm/marvell.rst b/Documentation/arm/marvell.rst
index 370721518987..3d369a566038 100644
--- a/Documentation/arm/marvell.rst
+++ b/Documentation/arm/marvell.rst
@@ -14,18 +14,20 @@ Orion family
Flavors:
- 88F5082
- - 88F5181
- - 88F5181L
- - 88F5182
+ - 88F5181 a.k.a Orion-1
+ - 88F5181L a.k.a Orion-VoIP
+ - 88F5182 a.k.a Orion-NAS
- Datasheet: https://web.archive.org/web/20210124231420/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-datasheet.pdf
- Programmer's User Guide: https://web.archive.org/web/20210124231536/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-opensource-manual.pdf
- User Manual: https://web.archive.org/web/20210124231631/http://csclub.uwaterloo.ca/~board/ts7800/MV88F5182-usermanual.pdf
- Functional Errata: https://web.archive.org/web/20210704165540/https://www.digriz.org.uk/ts78xx/88F5182_Functional_Errata.pdf
- - 88F5281
+ - 88F5281 a.k.a Orion-2
- Datasheet: https://web.archive.org/web/20131028144728/http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf
- - 88F6183
+ - 88F6183 a.k.a Orion-1-90
+ Homepage:
+ https://web.archive.org/web/20080607215437/http://www.marvell.com/products/media/index.jsp
Core:
Feroceon 88fr331 (88f51xx) or 88fr531-vd (88f52xx) ARMv5 compatible
Linux kernel mach directory:
diff --git a/Documentation/arm64/acpi_object_usage.rst b/Documentation/arm64/acpi_object_usage.rst
index 0609da73970b..484ef9676653 100644
--- a/Documentation/arm64/acpi_object_usage.rst
+++ b/Documentation/arm64/acpi_object_usage.rst
@@ -163,7 +163,7 @@ FPDT Section 5.2.23 (signature == "FPDT")
**Firmware Performance Data Table**
- Optional, not currently supported.
+ Optional, useful for boot performance profiling.
GTDT Section 5.2.24 (signature == "GTDT")
diff --git a/Documentation/arm64/booting.rst b/Documentation/arm64/booting.rst
index 8c324ad638de..96fe10ec6c24 100644
--- a/Documentation/arm64/booting.rst
+++ b/Documentation/arm64/booting.rst
@@ -121,8 +121,9 @@ Header notes:
to the base of DRAM, since memory below it is not
accessible via the linear mapping
1
- 2MB aligned base may be anywhere in physical
- memory
+ 2MB aligned base such that all image_size bytes
+ counted from the start of the image are within
+ the 48-bit addressable range of physical memory
Bits 4-63 Reserved.
============= ===============================================================
@@ -348,7 +349,7 @@ Before jumping into the kernel, the following conditions must be met:
- HWFGWTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01.
- For CPUs with the Scalable Matrix Extension FA64 feature (FEAT_SME_FA64)
+ For CPUs with the Scalable Matrix Extension FA64 feature (FEAT_SME_FA64):
- If EL3 is present:
diff --git a/Documentation/arm64/elf_hwcaps.rst b/Documentation/arm64/elf_hwcaps.rst
index bb34287c8e01..6fed84f935df 100644
--- a/Documentation/arm64/elf_hwcaps.rst
+++ b/Documentation/arm64/elf_hwcaps.rst
@@ -275,6 +275,15 @@ HWCAP2_EBF16
HWCAP2_SVE_EBF16
Functionality implied by ID_AA64ZFR0_EL1.BF16 == 0b0010.
+HWCAP2_CSSC
+ Functionality implied by ID_AA64ISAR2_EL1.CSSC == 0b0001.
+
+HWCAP2_RPRFM
+ Functionality implied by ID_AA64ISAR2_EL1.RPRFM == 0b0001.
+
+HWCAP2_SVE2P1
+ Functionality implied by ID_AA64ZFR0_EL1.SVEver == 0b0010.
+
4. Unused AT_HWCAP bits
-----------------------
diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
index 808ade4cc008..ec5f889d7681 100644
--- a/Documentation/arm64/silicon-errata.rst
+++ b/Documentation/arm64/silicon-errata.rst
@@ -120,6 +120,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A710 | #2224489 | ARM64_ERRATUM_2224489 |
+----------------+-----------------+-----------------+-----------------------------+
+| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
++----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
diff --git a/Documentation/arm64/sve.rst b/Documentation/arm64/sve.rst
index f338ee2df46d..c7a356bf4e8f 100644
--- a/Documentation/arm64/sve.rst
+++ b/Documentation/arm64/sve.rst
@@ -52,6 +52,7 @@ model features for SVE is included in Appendix A.
HWCAP2_SVEBITPERM
HWCAP2_SVESHA3
HWCAP2_SVESM4
+ HWCAP2_SVE2P1
This list may be extended over time as the SVE architecture evolves.
diff --git a/Documentation/block/inline-encryption.rst b/Documentation/block/inline-encryption.rst
index 4d151fbe2058..f9bf18ea6509 100644
--- a/Documentation/block/inline-encryption.rst
+++ b/Documentation/block/inline-encryption.rst
@@ -142,7 +142,7 @@ Therefore, we also introduce *blk-crypto-fallback*, which is an implementation
of inline encryption using the kernel crypto API. blk-crypto-fallback is built
into the block layer, so it works on any block device without any special setup.
Essentially, when a bio with an encryption context is submitted to a
-request_queue that doesn't support that encryption context, the block layer will
+block_device that doesn't support that encryption context, the block layer will
handle en/decryption of the bio using blk-crypto-fallback.
For encryption, the data cannot be encrypted in-place, as callers usually rely
@@ -187,7 +187,7 @@ API presented to users of the block layer
``blk_crypto_config_supported()`` allows users to check ahead of time whether
inline encryption with particular crypto settings will work on a particular
-request_queue -- either via hardware or via blk-crypto-fallback. This function
+block_device -- either via hardware or via blk-crypto-fallback. This function
takes in a ``struct blk_crypto_config`` which is like blk_crypto_key, but omits
the actual bytes of the key and instead just contains the algorithm, data unit
size, etc. This function can be useful if blk-crypto-fallback is disabled.
@@ -195,7 +195,7 @@ size, etc. This function can be useful if blk-crypto-fallback is disabled.
``blk_crypto_init_key()`` allows users to initialize a blk_crypto_key.
Users must call ``blk_crypto_start_using_key()`` before actually starting to use
-a blk_crypto_key on a request_queue (even if ``blk_crypto_config_supported()``
+a blk_crypto_key on a block_device (even if ``blk_crypto_config_supported()``
was called earlier). This is needed to initialize blk-crypto-fallback if it
will be needed. This must not be called from the data path, as this may have to
allocate resources, which may deadlock in that case.
@@ -207,7 +207,7 @@ for en/decryption. Users don't need to worry about freeing the bio_crypt_ctx
later, as that happens automatically when the bio is freed or reset.
Finally, when done using inline encryption with a blk_crypto_key on a
-request_queue, users must call ``blk_crypto_evict_key()``. This ensures that
+block_device, users must call ``blk_crypto_evict_key()``. This ensures that
the key is evicted from all keyslots it may be programmed into and unlinked from
any kernel data structures it may be linked into.
@@ -221,9 +221,9 @@ as follows:
5. ``blk_crypto_evict_key()`` (after all I/O has completed)
6. Zeroize the blk_crypto_key (this has no dedicated function)
-If a blk_crypto_key is being used on multiple request_queues, then
+If a blk_crypto_key is being used on multiple block_devices, then
``blk_crypto_config_supported()`` (if used), ``blk_crypto_start_using_key()``,
-and ``blk_crypto_evict_key()`` must be called on each request_queue.
+and ``blk_crypto_evict_key()`` must be called on each block_device.
API presented to device drivers
===============================
diff --git a/Documentation/conf.py b/Documentation/conf.py
index b50c85083149..a5c45df0bd83 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -194,6 +194,24 @@ finally:
else:
version = release = "unknown version"
+#
+# HACK: there seems to be no easy way for us to get at the version and
+# release information passed in from the makefile...so go pawing through the
+# command-line options and find it for ourselves.
+#
+def get_cline_version():
+ c_version = c_release = ''
+ for arg in sys.argv:
+ if arg.startswith('version='):
+ c_version = arg[8:]
+ elif arg.startswith('release='):
+ c_release = arg[8:]
+ if c_version:
+ if c_release:
+ return c_version + '-' + c_release
+ return c_version
+ return version # Whatever we came up with before
+
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
@@ -247,7 +265,7 @@ highlight_language = 'none'
# a list of builtin themes.
# Default theme
-html_theme = 'sphinx_rtd_theme'
+html_theme = 'alabaster'
html_css_files = []
if "DOCS_THEME" in os.environ:
@@ -278,8 +296,12 @@ if html_theme == 'sphinx_rtd_theme' or html_theme == 'sphinx_rtd_dark_mode':
# Add color-specific RTD normal mode
html_css_files.append('theme_rtd_colors.css')
+ html_theme_options = {
+ 'navigation_depth': -1,
+ }
+
except ImportError:
- html_theme = 'classic'
+ html_theme = 'alabaster'
if "DOCS_CSS" in os.environ:
css = os.environ["DOCS_CSS"].split(" ")
@@ -295,127 +317,29 @@ if major <= 1 and minor < 8:
for l in html_css_files:
html_context['css_files'].append('_static/' + l)
-if html_theme == 'classic':
+if html_theme == 'alabaster':
html_theme_options = {
- 'rightsidebar': False,
- 'stickysidebar': True,
- 'collapsiblesidebar': True,
- 'externalrefs': False,
-
- 'footerbgcolor': "white",
- 'footertextcolor': "white",
- 'sidebarbgcolor': "white",
- 'sidebarbtncolor': "black",
- 'sidebartextcolor': "black",
- 'sidebarlinkcolor': "#686bff",
- 'relbarbgcolor': "#133f52",
- 'relbartextcolor': "white",
- 'relbarlinkcolor': "white",
- 'bgcolor': "white",
- 'textcolor': "black",
- 'headbgcolor': "#f2f2f2",
- 'headtextcolor': "#20435c",
- 'headlinkcolor': "#c60f0f",
- 'linkcolor': "#355f7c",
- 'visitedlinkcolor': "#355f7c",
- 'codebgcolor': "#3f3f3f",
- 'codetextcolor': "white",
-
- 'bodyfont': "serif",
- 'headfont': "sans-serif",
+ 'description': get_cline_version(),
+ 'page_width': '65em',
+ 'sidebar_width': '15em',
+ 'font_size': 'inherit',
+ 'font_family': 'serif',
}
sys.stderr.write("Using %s theme\n" % html_theme)
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['sphinx-static']
-# Add any extra paths that contain custom files (such as robots.txt or
-# .htaccess) here, relative to this directory. These files are copied
-# directly to the root of the documentation.
-#html_extra_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
html_use_smartypants = False
# Custom sidebar templates, maps document names to template names.
-# Note that the RTD theme ignores this.
-html_sidebars = { '**': ['searchbox.html', 'localtoc.html', 'sourcelink.html']}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Language to be used for generating the HTML full-text search index.
-# Sphinx supports the following languages:
-# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
-# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
-#html_search_language = 'en'
-
-# A dictionary with options for the search language support, empty by default.
-# Now only 'ja' uses this config value
-#html_search_options = {'type': 'default'}
-
-# The name of a javascript file (relative to the configuration directory) that
-# implements a search results scorer. If empty, the default will be used.
-#html_search_scorer = 'scorer.js'
+# Note that the RTD theme ignores this
+html_sidebars = { '**': ["about.html", 'searchbox.html', 'localtoc.html', 'sourcelink.html']}
# Output file base name for HTML help builder.
htmlhelp_basename = 'TheLinuxKerneldoc'
@@ -558,19 +482,6 @@ texinfo_documents = [
'Miscellaneous'),
]
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
-
-
# -- Options for Epub output ----------------------------------------------
# Bibliographic Dublin Core info.
@@ -579,67 +490,9 @@ epub_author = author
epub_publisher = author
epub_copyright = copyright
-# The basename for the epub file. It defaults to the project name.
-#epub_basename = project
-
-# The HTML theme for the epub output. Since the default themes are not
-# optimized for small screen space, using the same theme for HTML and epub
-# output is usually not wise. This defaults to 'epub', a theme designed to save
-# visual space.
-#epub_theme = 'epub'
-
-# The language of the text. It defaults to the language option
-# or 'en' if the language is not set.
-#epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-#epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#epub_identifier = ''
-
-# A unique identification for the text.
-#epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-#epub_cover = ()
-
-# A sequence of (type, uri, title) tuples for the guide element of content.opf.
-#epub_guide = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_pre_files = []
-
-# HTML files that should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_post_files = []
-
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
-# The depth of the table of contents in toc.ncx.
-#epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#epub_tocdup = True
-
-# Choose between 'default' and 'includehidden'.
-#epub_tocscope = 'default'
-
-# Fix unsupported image types using the Pillow.
-#epub_fix_images = False
-
-# Scale large images.
-#epub_max_image_width = 0
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#epub_show_urls = 'inline'
-
-# If false, no index is generated.
-#epub_use_index = True
-
#=======
# rst2pdf
#
diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst
index 06f4ab122697..c9412eb85552 100644
--- a/Documentation/core-api/kernel-api.rst
+++ b/Documentation/core-api/kernel-api.rst
@@ -171,9 +171,6 @@ Division Functions
.. kernel-doc:: include/linux/math64.h
:internal:
-.. kernel-doc:: lib/math/div64.c
- :functions: div_s64_rem div64_u64_rem div64_u64 div64_s64
-
.. kernel-doc:: lib/math/gcd.c
:export:
diff --git a/Documentation/core-api/local_ops.rst b/Documentation/core-api/local_ops.rst
index 2ac3f9f29845..0b42ceaaf3c4 100644
--- a/Documentation/core-api/local_ops.rst
+++ b/Documentation/core-api/local_ops.rst
@@ -191,7 +191,7 @@ Here is a sample module which implements a basic per cpu counter using
static void __exit test_exit(void)
{
- del_timer_sync(&test_timer);
+ timer_shutdown_sync(&test_timer);
}
module_init(test_init);
diff --git a/Documentation/cpu-freq/index.rst b/Documentation/cpu-freq/index.rst
index aba7831ab1cb..2fe32dad562a 100644
--- a/Documentation/cpu-freq/index.rst
+++ b/Documentation/cpu-freq/index.rst
@@ -20,18 +20,15 @@ Author: Dominik Brodowski <linux@brodo.de>
Mailing List
------------
-There is a CPU frequency changing CVS commit and general list where
-you can report bugs, problems or submit patches. To post a message,
-send an email to linux-pm@vger.kernel.org.
+There is a CPU frequency general list where you can report bugs,
+problems or submit patches. To post a message, send an email to
+linux-pm@vger.kernel.org.
Links
-----
the FTP archives:
* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
-how to access the CVS repository:
-* http://cvs.arm.linux.org.uk/
-
the CPUFreq Mailing list:
* http://vger.kernel.org/vger-lists.html#linux-pm
diff --git a/Documentation/dev-tools/kmsan.rst b/Documentation/dev-tools/kmsan.rst
index 2a53a801198c..55fa82212eb2 100644
--- a/Documentation/dev-tools/kmsan.rst
+++ b/Documentation/dev-tools/kmsan.rst
@@ -67,6 +67,7 @@ uninitialized in the local variable, as well as the stack where the value was
copied to another memory location before use.
A use of uninitialized value ``v`` is reported by KMSAN in the following cases:
+
- in a condition, e.g. ``if (v) { ... }``;
- in an indexing or pointer dereferencing, e.g. ``array[v]`` or ``*v``;
- when it is copied to userspace or hardware, e.g. ``copy_to_user(..., &v, ...)``;
diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst
index d0a9565b0f44..414c105b10a9 100644
--- a/Documentation/dev-tools/ktap.rst
+++ b/Documentation/dev-tools/ktap.rst
@@ -80,8 +80,8 @@ have the number 1 and the number then must increase by 1 for each additional
subtest within the same test at the same nesting level.
The description is a description of the test, generally the name of
-the test, and can be any string of words (can't include #). The
-description is optional, but recommended.
+the test, and can be any string of characters other than # or a
+newline. The description is optional, but recommended.
The directive and any diagnostic data is optional. If either are present, they
must follow a hash sign, "#".
diff --git a/Documentation/dev-tools/kunit/architecture.rst b/Documentation/dev-tools/kunit/architecture.rst
index 8efe792bdcb9..e95ab05342bb 100644
--- a/Documentation/dev-tools/kunit/architecture.rst
+++ b/Documentation/dev-tools/kunit/architecture.rst
@@ -4,16 +4,17 @@
KUnit Architecture
==================
-The KUnit architecture can be divided into two parts:
+The KUnit architecture is divided into two parts:
- `In-Kernel Testing Framework`_
-- `kunit_tool (Command Line Test Harness)`_
+- `kunit_tool (Command-line Test Harness)`_
In-Kernel Testing Framework
===========================
The kernel testing library supports KUnit tests written in C using
-KUnit. KUnit tests are kernel code. KUnit does several things:
+KUnit. These KUnit tests are kernel code. KUnit performs the following
+tasks:
- Organizes tests
- Reports test results
@@ -22,19 +23,17 @@ KUnit. KUnit tests are kernel code. KUnit does several things:
Test Cases
----------
-The fundamental unit in KUnit is the test case. The KUnit test cases are
-grouped into KUnit suites. A KUnit test case is a function with type
-signature ``void (*)(struct kunit *test)``.
-These test case functions are wrapped in a struct called
-struct kunit_case.
+The test case is the fundamental unit in KUnit. KUnit test cases are organised
+into suites. A KUnit test case is a function with type signature
+``void (*)(struct kunit *test)``. These test case functions are wrapped in a
+struct called struct kunit_case.
.. note:
``generate_params`` is optional for non-parameterized tests.
-Each KUnit test case gets a ``struct kunit`` context
-object passed to it that tracks a running test. The KUnit assertion
-macros and other KUnit utilities use the ``struct kunit`` context
-object. As an exception, there are two fields:
+Each KUnit test case receives a ``struct kunit`` context object that tracks a
+running test. The KUnit assertion macros and other KUnit utilities use the
+``struct kunit`` context object. As an exception, there are two fields:
- ``->priv``: The setup functions can use it to store arbitrary test
user data.
@@ -77,12 +76,13 @@ Executor
The KUnit executor can list and run built-in KUnit tests on boot.
The Test suites are stored in a linker section
-called ``.kunit_test_suites``. For code, see:
-https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v5.15#n945.
+called ``.kunit_test_suites``. For the code, see ``KUNIT_TABLE()`` macro
+definition in
+`include/asm-generic/vmlinux.lds.h <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v6.0#n950>`_.
The linker section consists of an array of pointers to
``struct kunit_suite``, and is populated by the ``kunit_test_suites()``
-macro. To run all tests compiled into the kernel, the KUnit executor
-iterates over the linker section array.
+macro. The KUnit executor iterates over the linker section array in order to
+run all the tests that are compiled into the kernel.
.. kernel-figure:: kunit_suitememorydiagram.svg
:alt: KUnit Suite Memory
@@ -90,17 +90,17 @@ iterates over the linker section array.
KUnit Suite Memory Diagram
On the kernel boot, the KUnit executor uses the start and end addresses
-of this section to iterate over and run all tests. For code, see:
-https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/executor.c
-
+of this section to iterate over and run all tests. For the implementation of the
+executor, see
+`lib/kunit/executor.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/executor.c>`_.
When built as a module, the ``kunit_test_suites()`` macro defines a
``module_init()`` function, which runs all the tests in the compilation
unit instead of utilizing the executor.
In KUnit tests, some error classes do not affect other tests
or parts of the kernel, each KUnit case executes in a separate thread
-context. For code, see:
-https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58
+context. See the ``kunit_try_catch_run()`` function in
+`lib/kunit/try-catch.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58>`_.
Assertion Macros
----------------
@@ -111,37 +111,36 @@ All expectations/assertions are formatted as:
- ``{EXPECT|ASSERT}`` determines whether the check is an assertion or an
expectation.
+ In the event of a failure, the testing flow differs as follows:
- - For an expectation, if the check fails, marks the test as failed
- and logs the failure.
+ - For expectations, the test is marked as failed and the failure is logged.
- - An assertion, on failure, causes the test case to terminate
- immediately.
+ - Failing assertions, on the other hand, result in the test case being
+ terminated immediately.
- - Assertions call function:
+ - Assertions call the function:
``void __noreturn kunit_abort(struct kunit *)``.
- - ``kunit_abort`` calls function:
+ - ``kunit_abort`` calls the function:
``void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)``.
- - ``kunit_try_catch_throw`` calls function:
+ - ``kunit_try_catch_throw`` calls the function:
``void kthread_complete_and_exit(struct completion *, long) __noreturn;``
and terminates the special thread context.
- ``<op>`` denotes a check with options: ``TRUE`` (supplied property
- has the boolean value “true”), ``EQ`` (two supplied properties are
+ has the boolean value "true"), ``EQ`` (two supplied properties are
equal), ``NOT_ERR_OR_NULL`` (supplied pointer is not null and does not
- contain an “err” value).
+ contain an "err" value).
- ``[_MSG]`` prints a custom message on failure.
Test Result Reporting
---------------------
-KUnit prints test results in KTAP format. KTAP is based on TAP14, see:
-https://github.com/isaacs/testanything.github.io/blob/tap14/tap-version-14-specification.md.
-KTAP (yet to be standardized format) works with KUnit and Kselftest.
-The KUnit executor prints KTAP results to dmesg, and debugfs
-(if configured).
+KUnit prints the test results in KTAP format. KTAP is based on TAP14, see
+Documentation/dev-tools/ktap.rst.
+KTAP works with KUnit and Kselftest. The KUnit executor prints KTAP results to
+dmesg, and debugfs (if configured).
Parameterized Tests
-------------------
@@ -150,33 +149,35 @@ Each KUnit parameterized test is associated with a collection of
parameters. The test is invoked multiple times, once for each parameter
value and the parameter is stored in the ``param_value`` field.
The test case includes a KUNIT_CASE_PARAM() macro that accepts a
-generator function.
-The generator function is passed the previous parameter and returns the next
-parameter. It also provides a macro to generate common-case generators based on
-arrays.
+generator function. The generator function is passed the previous parameter
+and returns the next parameter. It also includes a macro for generating
+array-based common-case generators.
-kunit_tool (Command Line Test Harness)
+kunit_tool (Command-line Test Harness)
======================================
-kunit_tool is a Python script ``(tools/testing/kunit/kunit.py)``
-that can be used to configure, build, exec, parse and run (runs other
-commands in order) test results. You can either run KUnit tests using
-kunit_tool or can include KUnit in kernel and parse manually.
+``kunit_tool`` is a Python script, found in ``tools/testing/kunit/kunit.py``. It
+is used to configure, build, execute, parse test results and run all of the
+previous commands in correct order (i.e., configure, build, execute and parse).
+You have two options for running KUnit tests: either build the kernel with KUnit
+enabled and manually parse the results (see
+Documentation/dev-tools/kunit/run_manual.rst) or use ``kunit_tool``
+(see Documentation/dev-tools/kunit/run_wrapper.rst).
- ``configure`` command generates the kernel ``.config`` from a
``.kunitconfig`` file (and any architecture-specific options).
- For some architectures, additional config options are specified in the
- ``qemu_config`` Python script
- (For example: ``tools/testing/kunit/qemu_configs/powerpc.py``).
+ The Python scripts available in ``qemu_configs`` folder
+ (for example, ``tools/testing/kunit/qemu configs/powerpc.py``) contains
+ additional configuration options for specific architectures.
It parses both the existing ``.config`` and the ``.kunitconfig`` files
- and ensures that ``.config`` is a superset of ``.kunitconfig``.
- If this is not the case, it will combine the two and run
- ``make olddefconfig`` to regenerate the ``.config`` file. It then
- verifies that ``.config`` is now a superset. This checks if all
- Kconfig dependencies are correctly specified in ``.kunitconfig``.
- ``kunit_config.py`` includes the parsing Kconfigs code. The code which
- runs ``make olddefconfig`` is a part of ``kunit_kernel.py``. You can
- invoke this command via: ``./tools/testing/kunit/kunit.py config`` and
+ to ensure that ``.config`` is a superset of ``.kunitconfig``.
+ If not, it will combine the two and run ``make olddefconfig`` to regenerate
+ the ``.config`` file. It then checks to see if ``.config`` has become a superset.
+ This verifies that all the Kconfig dependencies are correctly specified in the
+ file ``.kunitconfig``. The ``kunit_config.py`` script contains the code for parsing
+ Kconfigs. The code which runs ``make olddefconfig`` is part of the
+ ``kunit_kernel.py`` script. You can invoke this command through:
+ ``./tools/testing/kunit/kunit.py config`` and
generate a ``.config`` file.
- ``build`` runs ``make`` on the kernel tree with required options
(depends on the architecture and some options, for example: build_dir)
@@ -184,8 +185,8 @@ kunit_tool or can include KUnit in kernel and parse manually.
To build a KUnit kernel from the current ``.config``, you can use the
``build`` argument: ``./tools/testing/kunit/kunit.py build``.
- ``exec`` command executes kernel results either directly (using
- User-mode Linux configuration), or via an emulator such
- as QEMU. It reads results from the log via standard
+ User-mode Linux configuration), or through an emulator such
+ as QEMU. It reads results from the log using standard
output (stdout), and passes them to ``parse`` to be parsed.
If you already have built a kernel with built-in KUnit tests,
you can run the kernel and display the test results with the ``exec``
diff --git a/Documentation/dev-tools/kunit/index.rst b/Documentation/dev-tools/kunit/index.rst
index f5d13f1d37be..b3593ae29ace 100644
--- a/Documentation/dev-tools/kunit/index.rst
+++ b/Documentation/dev-tools/kunit/index.rst
@@ -16,7 +16,6 @@ KUnit - Linux Kernel Unit Testing
api/index
style
faq
- tips
running_tips
This section details the kernel unit testing framework.
@@ -100,14 +99,11 @@ Read also :ref:`kinds-of-tests`.
How do I use it?
================
-* Documentation/dev-tools/kunit/start.rst - for KUnit new users.
-* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
-* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
-* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
-* Documentation/dev-tools/kunit/usage.rst - write tests.
-* Documentation/dev-tools/kunit/tips.rst - best practices with
- examples.
-* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
- used for testing.
-* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
- answers.
+You can find a step-by-step guide to writing and running KUnit tests in
+Documentation/dev-tools/kunit/start.rst
+
+Alternatively, feel free to look through the rest of the KUnit documentation,
+or to experiment with tools/testing/kunit/kunit.py and the example test under
+lib/kunit/kunit-example-test.c
+
+Happy testing!
diff --git a/Documentation/dev-tools/kunit/start.rst b/Documentation/dev-tools/kunit/start.rst
index f4f504f1fb15..c736613c9b19 100644
--- a/Documentation/dev-tools/kunit/start.rst
+++ b/Documentation/dev-tools/kunit/start.rst
@@ -294,13 +294,11 @@ Congrats! You just wrote your first KUnit test.
Next Steps
==========
-* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
-* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
-* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
-* Documentation/dev-tools/kunit/usage.rst - write tests.
-* Documentation/dev-tools/kunit/tips.rst - best practices with
- examples.
-* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
- used for testing.
-* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
- answers.
+If you're interested in using some of the more advanced features of kunit.py,
+take a look at Documentation/dev-tools/kunit/run_wrapper.rst
+
+If you'd like to run tests without using kunit.py, check out
+Documentation/dev-tools/kunit/run_manual.rst
+
+For more information on writing KUnit tests (including some common techniques
+for testing different things), see Documentation/dev-tools/kunit/usage.rst
diff --git a/Documentation/dev-tools/kunit/tips.rst b/Documentation/dev-tools/kunit/tips.rst
deleted file mode 100644
index 492d2ded2f5a..000000000000
--- a/Documentation/dev-tools/kunit/tips.rst
+++ /dev/null
@@ -1,190 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-============================
-Tips For Writing KUnit Tests
-============================
-
-Exiting early on failed expectations
-------------------------------------
-
-``KUNIT_EXPECT_EQ`` and friends will mark the test as failed and continue
-execution. In some cases, it's unsafe to continue and you can use the
-``KUNIT_ASSERT`` variant to exit on failure.
-
-.. code-block:: c
-
- void example_test_user_alloc_function(struct kunit *test)
- {
- void *object = alloc_some_object_for_me();
-
- /* Make sure we got a valid pointer back. */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
- do_something_with_object(object);
- }
-
-Allocating memory
------------------
-
-Where you would use ``kzalloc``, you should prefer ``kunit_kzalloc`` instead.
-KUnit will ensure the memory is freed once the test completes.
-
-This is particularly useful since it lets you use the ``KUNIT_ASSERT_EQ``
-macros to exit early from a test without having to worry about remembering to
-call ``kfree``.
-
-Example:
-
-.. code-block:: c
-
- void example_test_allocation(struct kunit *test)
- {
- char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
- /* Ensure allocation succeeded. */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
-
- KUNIT_ASSERT_STREQ(test, buffer, "");
- }
-
-
-Testing static functions
-------------------------
-
-If you don't want to expose functions or variables just for testing, one option
-is to conditionally ``#include`` the test file at the end of your .c file, e.g.
-
-.. code-block:: c
-
- /* In my_file.c */
-
- static int do_interesting_thing();
-
- #ifdef CONFIG_MY_KUNIT_TEST
- #include "my_kunit_test.c"
- #endif
-
-Injecting test-only code
-------------------------
-
-Similarly to the above, it can be useful to add test-specific logic.
-
-.. code-block:: c
-
- /* In my_file.h */
-
- #ifdef CONFIG_MY_KUNIT_TEST
- /* Defined in my_kunit_test.c */
- void test_only_hook(void);
- #else
- void test_only_hook(void) { }
- #endif
-
-This test-only code can be made more useful by accessing the current kunit
-test, see below.
-
-Accessing the current test
---------------------------
-
-In some cases, you need to call test-only code from outside the test file, e.g.
-like in the example above or if you're providing a fake implementation of an
-ops struct.
-There is a ``kunit_test`` field in ``task_struct``, so you can access it via
-``current->kunit_test``.
-
-Here's a slightly in-depth example of how one could implement "mocking":
-
-.. code-block:: c
-
- #include <linux/sched.h> /* for current */
-
- struct test_data {
- int foo_result;
- int want_foo_called_with;
- };
-
- static int fake_foo(int arg)
- {
- struct kunit *test = current->kunit_test;
- struct test_data *test_data = test->priv;
-
- KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
- return test_data->foo_result;
- }
-
- static void example_simple_test(struct kunit *test)
- {
- /* Assume priv is allocated in the suite's .init */
- struct test_data *test_data = test->priv;
-
- test_data->foo_result = 42;
- test_data->want_foo_called_with = 1;
-
- /* In a real test, we'd probably pass a pointer to fake_foo somewhere
- * like an ops struct, etc. instead of calling it directly. */
- KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
- }
-
-
-Note: here we're able to get away with using ``test->priv``, but if you wanted
-something more flexible you could use a named ``kunit_resource``, see
-Documentation/dev-tools/kunit/api/test.rst.
-
-Failing the current test
-------------------------
-
-But sometimes, you might just want to fail the current test. In that case, we
-have ``kunit_fail_current_test(fmt, args...)`` which is defined in ``<kunit/test-bug.h>`` and
-doesn't require pulling in ``<kunit/test.h>``.
-
-E.g. say we had an option to enable some extra debug checks on some data structure:
-
-.. code-block:: c
-
- #include <kunit/test-bug.h>
-
- #ifdef CONFIG_EXTRA_DEBUG_CHECKS
- static void validate_my_data(struct data *data)
- {
- if (is_valid(data))
- return;
-
- kunit_fail_current_test("data %p is invalid", data);
-
- /* Normal, non-KUnit, error reporting code here. */
- }
- #else
- static void my_debug_function(void) { }
- #endif
-
-
-Customizing error messages
---------------------------
-
-Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG`` variant.
-These take a format string and arguments to provide additional context to the automatically generated error messages.
-
-.. code-block:: c
-
- char some_str[41];
- generate_sha1_hex_string(some_str);
-
- /* Before. Not easy to tell why the test failed. */
- KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
-
- /* After. Now we see the offending string. */
- KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
-
-Alternatively, one can take full control over the error message by using ``KUNIT_FAIL()``, e.g.
-
-.. code-block:: c
-
- /* Before */
- KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
-
- /* After: full control over the failure message. */
- if (some_setup_function())
- KUNIT_FAIL(test, "Failed to setup thing for testing");
-
-Next Steps
-==========
-* Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more
- in-depth explanation of KUnit.
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst
index 2737863ef365..48f8196d5aad 100644
--- a/Documentation/dev-tools/kunit/usage.rst
+++ b/Documentation/dev-tools/kunit/usage.rst
@@ -112,11 +112,45 @@ terminates the test case if the condition is not satisfied. For example:
KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
}
-In this example, the method under test should return pointer to a value. If the
-pointer returns null or an errno, we want to stop the test since the following
-expectation could crash the test case. `ASSERT_NOT_ERR_OR_NULL(...)` allows us
-to bail out of the test case if the appropriate conditions are not satisfied to
-complete the test.
+In this example, we need to be able to allocate an array to test the ``sort()``
+function. So we use ``KUNIT_ASSERT_NOT_ERR_OR_NULL()`` to abort the test if
+there's an allocation error.
+
+.. note::
+ In other test frameworks, ``ASSERT`` macros are often implemented by calling
+ ``return`` so they only work from the test function. In KUnit, we stop the
+ current kthread on failure, so you can call them from anywhere.
+
+Customizing error messages
+--------------------------
+
+Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG``
+variant. These take a format string and arguments to provide additional
+context to the automatically generated error messages.
+
+.. code-block:: c
+
+ char some_str[41];
+ generate_sha1_hex_string(some_str);
+
+ /* Before. Not easy to tell why the test failed. */
+ KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
+
+ /* After. Now we see the offending string. */
+ KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
+
+Alternatively, one can take full control over the error message by using
+``KUNIT_FAIL()``, e.g.
+
+.. code-block:: c
+
+ /* Before */
+ KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
+
+ /* After: full control over the failure message. */
+ if (some_setup_function())
+ KUNIT_FAIL(test, "Failed to setup thing for testing");
+
Test Suites
~~~~~~~~~~~
@@ -546,24 +580,6 @@ By reusing the same ``cases`` array from above, we can write the test as a
{}
};
-Exiting Early on Failed Expectations
-------------------------------------
-
-We can use ``KUNIT_EXPECT_EQ`` to mark the test as failed and continue
-execution. In some cases, it is unsafe to continue. We can use the
-``KUNIT_ASSERT`` variant to exit on failure.
-
-.. code-block:: c
-
- void example_test_user_alloc_function(struct kunit *test)
- {
- void *object = alloc_some_object_for_me();
-
- /* Make sure we got a valid pointer back. */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
- do_something_with_object(object);
- }
-
Allocating Memory
-----------------
@@ -625,17 +641,23 @@ as shown in next section: *Accessing The Current Test*.
Accessing The Current Test
--------------------------
-In some cases, we need to call test-only code from outside the test file.
-For example, see example in section *Injecting Test-Only Code* or if
-we are providing a fake implementation of an ops struct. Using
-``kunit_test`` field in ``task_struct``, we can access it via
-``current->kunit_test``.
+In some cases, we need to call test-only code from outside the test file. This
+is helpful, for example, when providing a fake implementation of a function, or
+to fail any current test from within an error handler.
+We can do this via the ``kunit_test`` field in ``task_struct``, which we can
+access using the ``kunit_get_current_test()`` function in ``kunit/test-bug.h``.
+
+``kunit_get_current_test()`` is safe to call even if KUnit is not enabled. If
+KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is
+running in the current task, it will return ``NULL``. This compiles down to
+either a no-op or a static key check, so will have a negligible performance
+impact when no test is running.
-The example below includes how to implement "mocking":
+The example below uses this to implement a "mock" implementation of a function, ``foo``:
.. code-block:: c
- #include <linux/sched.h> /* for current */
+ #include <kunit/test-bug.h> /* for kunit_get_current_test */
struct test_data {
int foo_result;
@@ -644,7 +666,7 @@ The example below includes how to implement "mocking":
static int fake_foo(int arg)
{
- struct kunit *test = current->kunit_test;
+ struct kunit *test = kunit_get_current_test();
struct test_data *test_data = test->priv;
KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
@@ -675,7 +697,7 @@ Each test can have multiple resources which have string names providing the same
flexibility as a ``priv`` member, but also, for example, allowing helper
functions to create resources without conflicting with each other. It is also
possible to define a clean up function for each resource, making it easy to
-avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/test.rst.
+avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/resource.rst.
Failing The Current Test
------------------------
@@ -703,3 +725,9 @@ structures as shown below:
static void my_debug_function(void) { }
#endif
+``kunit_fail_current_test()`` is safe to call even if KUnit is not enabled. If
+KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is
+running in the current task, it will do nothing. This compiles down to either a
+no-op or a static key check, so will have a negligible performance impact when
+no test is running.
+
diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml
index 9fda2436c618..e16b5fa55847 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.yaml
+++ b/Documentation/devicetree/bindings/arm/amlogic.yaml
@@ -163,6 +163,7 @@ properties:
- azw,gsking-x
- azw,gtking
- azw,gtking-pro
+ - hardkernel,odroid-go-ultra
- hardkernel,odroid-n2
- hardkernel,odroid-n2-plus
- khadas,vim3
diff --git a/Documentation/devicetree/bindings/arm/apple.yaml b/Documentation/devicetree/bindings/arm/apple.yaml
index 7262f3c09867..da78c69774f2 100644
--- a/Documentation/devicetree/bindings/arm/apple.yaml
+++ b/Documentation/devicetree/bindings/arm/apple.yaml
@@ -19,12 +19,14 @@ description: |
- MacBook Air (M1, 2020)
- iMac (24-inch, M1, 2021)
- And devices based on the "M1 Pro" and "M1 Max" SoCs:
+ And devices based on the "M1 Pro", "M1 Max" and "M1 Ultra" SoCs:
- MacBook Pro (14-inch, M1 Pro, 2021)
- MacBook Pro (14-inch, M1 Max, 2021)
- MacBook Pro (16-inch, M1 Pro, 2021)
- MacBook Pro (16-inch, M1 Max, 2021)
+ - Mac Studio (M1 Max, 2022)
+ - Mac Studio (M1 Ultra, 2022)
The compatible property should follow this format:
@@ -67,6 +69,7 @@ properties:
- apple,j457 # iMac (24-inch, 2x USB-C, M1, 2021)
- const: apple,t8103
- const: apple,arm-platform
+
- description: Apple M1 Pro SoC based platforms
items:
- enum:
@@ -74,14 +77,23 @@ properties:
- apple,j316s # MacBook Pro (16-inch, M1 Pro, 2021)
- const: apple,t6000
- const: apple,arm-platform
+
- description: Apple M1 Max SoC based platforms
items:
- enum:
- apple,j314c # MacBook Pro (14-inch, M1 Max, 2021)
- apple,j316c # MacBook Pro (16-inch, M1 Max, 2021)
+ - apple,j375c # Mac Studio (M1 Max, 2022)
- const: apple,t6001
- const: apple,arm-platform
+ - description: Apple M1 Ultra SoC based platforms
+ items:
+ - enum:
+ - apple,j375d # Mac Studio (M1 Ultra, 2022)
+ - const: apple,t6002
+ - const: apple,arm-platform
+
additionalProperties: true
...
diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 217a1d674863..73f272664e83 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -17,6 +17,7 @@ properties:
- description: AST2400 based boards
items:
- enum:
+ - delta,ahe50dc-bmc
- facebook,galaxy100-bmc
- facebook,wedge100-bmc
- facebook,wedge40-bmc
@@ -82,7 +83,7 @@ properties:
- ibm,tacoma-bmc
- inventec,transformer-bmc
- jabil,rbp-bmc
- - nuvia,dc-scm-bmc
+ - qcom,dc-scm-v1-bmc
- quanta,s6q-bmc
- const: aspeed,ast2600
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml
index 958df32b4899..52b575c40599 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml
@@ -66,6 +66,7 @@ properties:
- enum:
- asus,rt-ac88u
- dlink,dir-885l
+ - dlink,dir-890l
- linksys,panamera
- luxul,abr-4500-v1
- luxul,xap-1610-v1
@@ -97,6 +98,7 @@ properties:
- description: BCM53016 based boards
items:
- enum:
+ - dlink,dwl-8610ap
- meraki,mr32
- const: brcm,bcm53016
- const: brcm,bcm4708
diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml
index 5c13b73e4d57..7dd84f8f8e4f 100644
--- a/Documentation/devicetree/bindings/arm/cpus.yaml
+++ b/Documentation/devicetree/bindings/arm/cpus.yaml
@@ -178,11 +178,13 @@ properties:
- qcom,kryo250
- qcom,kryo260
- qcom,kryo280
+ - qcom,kryo360
- qcom,kryo385
- qcom,kryo468
- qcom,kryo485
- qcom,kryo560
- qcom,kryo570
+ - qcom,kryo660
- qcom,kryo685
- qcom,kryo780
- qcom,scorpion
diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index fbfc4f99c01e..0a5c4e29067a 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -520,6 +520,7 @@ properties:
items:
- enum:
- fsl,imx6sl-evk # i.MX6 SoloLite EVK Board
+ - kobo,aura2
- kobo,tolino-shine2hd
- kobo,tolino-shine3
- kobo,tolino-vision5
@@ -814,6 +815,7 @@ properties:
- enum:
- beacon,imx8mm-beacon-kit # i.MX8MM Beacon Development Kit
- boundary,imx8mm-nitrogen8mm # i.MX8MM Nitrogen Board
+ - cloos,imx8mm-phg # i.MX8MM Cloos PHG Board
- dmo,imx8mm-data-modul-edm-sbc # i.MX8MM eDM SBC
- emtrion,emcon-mx8mm-avari # emCON-MX8MM SoM on Avari Base
- fsl,imx8mm-ddr4-evk # i.MX8MM DDR4 EVK Board
@@ -825,6 +827,7 @@ properties:
- gw,imx8mm-gw7901 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7902 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7903 # i.MX8MM Gateworks Board
+ - innocomm,wb15-evk # i.MX8MM Innocomm EVK board with WB15 SoM
- kontron,imx8mm-sl # i.MX8MM Kontron SL (N801X) SOM
- kontron,imx8mm-osm-s # i.MX8MM Kontron OSM-S (N802X) SOM
- menlo,mx8menlo # i.MX8MM Menlo board with Verdin SoM
diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index d76ce4c3819d..2275e5d93721 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -58,6 +58,7 @@ properties:
- items:
- enum:
- mediatek,mt6795-evb
+ - sony,xperia-m5
- const: mediatek,mt6795
- items:
- enum:
@@ -83,6 +84,7 @@ properties:
- const: mediatek,mt7629
- items:
- enum:
+ - bananapi,bpi-r3
- mediatek,mt7986a-rfb
- const: mediatek,mt7986a
- items:
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
index eb451bec23d3..0711f1834fbd 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
@@ -32,14 +32,26 @@ properties:
- mediatek,mt8183-mmsys
- mediatek,mt8186-mmsys
- mediatek,mt8192-mmsys
- - mediatek,mt8195-mmsys
- mediatek,mt8365-mmsys
- const: syscon
+
+ - description: vdosys0 and vdosys1 are 2 display HW pipelines,
+ so mt8195 binding should be deprecated.
+ deprecated: true
+ items:
+ - const: mediatek,mt8195-mmsys
+ - const: syscon
+
- items:
- const: mediatek,mt7623-mmsys
- const: mediatek,mt2701-mmsys
- const: syscon
+ - items:
+ - const: mediatek,mt8195-vdosys0
+ - const: mediatek,mt8195-mmsys
+ - const: syscon
+
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml
index 5ea506412b4e..38efcad56dbd 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml
@@ -31,6 +31,7 @@ properties:
- qcom,sm8250-llcc
- qcom,sm8350-llcc
- qcom,sm8450-llcc
+ - qcom,sm8550-llcc
reg:
items:
diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml
new file mode 100644
index 000000000000..e333ec4a9c5f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom-soc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SoC compatibles naming convention
+
+maintainers:
+ - Bjorn Andersson <andersson@kernel.org>
+
+description: |
+ Guidelines for new compatibles for SoC blocks/components.
+ When adding new compatibles in new bindings, use the format::
+ qcom,SoC-IP
+
+ For example::
+ qcom,sdm845-llcc-bwmon
+
+ When adding new compatibles to existing bindings, use the format in the
+ existing binding, even if it contradicts the above.
+
+select:
+ properties:
+ compatible:
+ pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ required:
+ - compatible
+
+properties:
+ compatible:
+ oneOf:
+ # Preferred naming style for compatibles of SoC components:
+ - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+-.*$"
+ - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$"
+
+ # Legacy namings - variations of existing patterns/compatibles are OK,
+ # but do not add completely new entries to these:
+ - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$"
+ - enum:
+ - qcom,dsi-ctrl-6g-qcm2290
+ - qcom,gpucc-sdm630
+ - qcom,gpucc-sdm660
+ - qcom,lcc-apq8064
+ - qcom,lcc-ipq8064
+ - qcom,lcc-mdm9615
+ - qcom,lcc-msm8960
+ - qcom,lpass-cpu-apq8016
+ - qcom,usb-ss-ipq4019-phy
+ - qcom,usb-hs-ipq4019-phy
+ - qcom,vqmmc-ipq4019-regulator
+
+ # Legacy compatibles with wild-cards - list cannot grow with new bindings:
+ - enum:
+ - qcom,ipq806x-gmac
+ - qcom,ipq806x-nand
+ - qcom,ipq806x-sata-phy
+ - qcom,ipq806x-usb-phy-ss
+ - qcom,ipq806x-usb-phy-hs
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index 1b5ac6b02bc5..27063a045bd0 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -29,17 +29,22 @@ description: |
apq8074
apq8084
apq8096
+ ipq4018
ipq6018
ipq8074
mdm9615
msm8226
msm8916
+ msm8956
msm8974
+ msm8976
msm8992
msm8994
msm8996
msm8998
qcs404
+ qdu1000
+ qru1000
sa8155p
sa8540p
sc7180
@@ -51,11 +56,15 @@ description: |
sdm632
sdm636
sdm660
+ sdm670
sdm845
sdx55
sdx65
+ sm4250
+ sm6115
sm6125
sm6350
+ sm6375
sm7225
sm8150
sm8250
@@ -76,6 +85,7 @@ description: |
mtp
qrd
sbc
+ x100
The 'soc_version' and 'board_version' elements take the form of v<Major>.<Minor>
where the minor number may be omitted when it's zero, i.e. v1.0 is the same
@@ -114,7 +124,9 @@ properties:
- items:
- enum:
- asus,sparrow
+ - huawei,sturgeon
- lg,lenok
+ - samsung,matisse-wifi
- const: qcom,apq8026
- items:
@@ -150,20 +162,32 @@ properties:
- items:
- enum:
+ - sony,kugo-row
+ - sony,suzu-row
+ - const: qcom,msm8956
+
+ - items:
+ - enum:
- qcom,msm8960-cdp
- const: qcom,msm8960
- items:
- enum:
- - fairphone,fp2
- lge,hammerhead
- - samsung,klte
- sony,xperia-amami
- - sony,xperia-castor
- sony,xperia-honami
- const: qcom,msm8974
- items:
+ - enum:
+ - fairphone,fp2
+ - oneplus,bacon
+ - samsung,klte
+ - sony,xperia-castor
+ - const: qcom,msm8974pro
+ - const: qcom,msm8974
+
+ - items:
- const: qcom,msm8916-mtp
- const: qcom,msm8916-mtp/1
- const: qcom,msm8916
@@ -221,13 +245,20 @@ properties:
- items:
- enum:
+ - oneplus,oneplus3
+ - oneplus,oneplus3t
- qcom,msm8996-mtp
- sony,dora-row
- sony,kagura-row
- sony,keyaki-row
- xiaomi,gemini
+ - const: qcom,msm8996
+
+ - items:
+ - enum:
- xiaomi,natrium
- xiaomi,scorpio
+ - const: qcom,msm8996pro
- const: qcom,msm8996
- items:
@@ -242,10 +273,17 @@ properties:
- sony,xperia-lilac
- sony,xperia-maple
- sony,xperia-poplar
+ - xiaomi,sagit
- const: qcom,msm8998
- items:
- enum:
+ - 8dev,jalapeno
+ - alfa-network,ap120c-ac
+ - const: qcom,ipq4018
+
+ - items:
+ - enum:
- qcom,ipq4019-ap-dk01.1-c1
- qcom,ipq4019-ap-dk04.1-c3
- qcom,ipq4019-ap-dk07.1-c1
@@ -255,6 +293,7 @@ properties:
- items:
- enum:
+ - mikrotik,rb3011
- qcom,ipq8064-ap148
- const: qcom,ipq8064
@@ -265,6 +304,25 @@ properties:
- qcom,ipq8074-hk10-c2
- const: qcom,ipq8074
+ - description: Sierra Wireless MangOH Green with WP8548 Module
+ items:
+ - const: swir,mangoh-green-wp8548
+ - const: swir,wp8548
+ - const: qcom,mdm9615
+
+ - description: Qualcomm Technologies, Inc. Distributed Unit 1000 platform
+ items:
+ - enum:
+ - qcom,qdu1000-idp
+ - qcom,qdu1000-x100
+ - const: qcom,qdu1000
+
+ - description: Qualcomm Technologies, Inc. Radio Unit 1000 platform
+ items:
+ - enum:
+ - qcom,qru1000-idp
+ - const: qcom,qru1000
+
- description: Qualcomm Technologies, Inc. SC7180 IDP
items:
- enum:
@@ -463,6 +521,17 @@ properties:
- const: google,pazquel-sku2
- const: qcom,sc7180
+ - description: Google Pazquel360 with LTE (newest rev)
+ items:
+ - const: google,pazquel-sku22
+ - const: google,pazquel-sku20
+ - const: qcom,sc7180
+
+ - description: Google Pazquel360 with WiFi (newest rev)
+ items:
+ - const: google,pazquel-sku21
+ - const: qcom,sc7180
+
- description: Sharp Dynabook Chromebook C1 (rev1)
items:
- const: google,pompom-rev1
@@ -575,6 +644,11 @@ properties:
- const: google,evoker
- const: qcom,sc7280
+ - description: Google Evoker with LTE (newest rev)
+ items:
+ - const: google,evoker-sku512
+ - const: qcom,sc7280
+
- description: Google Herobrine (newest rev)
items:
- const: google,herobrine
@@ -595,6 +669,16 @@ properties:
- const: google,villager-sku512
- const: qcom,sc7280
+ - description: Google Zombie (newest rev)
+ items:
+ - const: google,zombie
+ - const: qcom,sc7280
+
+ - description: Google Zombie with LTE (newest rev)
+ items:
+ - const: google,zombie-sku512
+ - const: qcom,sc7280
+
- items:
- enum:
- lenovo,flex-5g
@@ -639,6 +723,11 @@ properties:
- items:
- enum:
+ - google,sargo
+ - const: qcom,sdm670
+
+ - items:
+ - enum:
- qcom,sdx55-mtp
- qcom,sdx55-telit-fn980-tlb
- qcom,sdx55-t55
@@ -670,10 +759,14 @@ properties:
- items:
- enum:
- qcom,sa8295p-adp
+ - qcom,sa8540p-ride
- const: qcom,sa8540p
- items:
- enum:
+ - google,cheza
+ - google,cheza-rev1
+ - google,cheza-rev2
- lenovo,yoga-c630
- lg,judyln
- lg,judyp
@@ -681,17 +774,24 @@ properties:
- oneplus,fajita
- qcom,sdm845-mtp
- shift,axolotl
+ - samsung,starqltechn
- samsung,w737
- sony,akari-row
- sony,akatsuki-row
- sony,apollo-row
- thundercomm,db845c
- xiaomi,beryllium
+ - xiaomi,beryllium-ebbg
- xiaomi,polaris
- const: qcom,sdm845
- items:
- enum:
+ - oneplus,billie2
+ - const: qcom,sm4250
+
+ - items:
+ - enum:
- sony,pdx201
- const: qcom,sm6125
@@ -702,6 +802,11 @@ properties:
- items:
- enum:
+ - sony,pdx225
+ - const: qcom,sm6375
+
+ - items:
+ - enum:
- fairphone,fp4
- const: qcom,sm7225
@@ -737,8 +842,129 @@ properties:
- qcom,sm8450-hdk
- qcom,sm8450-qrd
- sony,pdx223
+ - sony,pdx224
- const: qcom,sm8450
+ # Board compatibles go above
+
+ qcom,msm-id:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ minItems: 1
+ maxItems: 8
+ items:
+ items:
+ - description: |
+ MSM chipset ID - an exact match value consisting of two bitfields::
+ - bits 0-15 - The unique MSM chipset ID
+ - bits 16-31 - Reserved; should be 0
+ - description: |
+ Hardware revision ID - a chipset specific 32-bit ID representing
+ the version of the chipset. It is best a match value - the
+ bootloader will look for the closest possible match.
+ deprecated: true
+ description:
+ The MSM chipset and hardware revision used Qualcomm bootloaders. It
+ can optionally be an array of these to indicate multiple hardware that
+ use the same device tree. It is expected that the bootloader will use
+ this information at boot-up to decide which device tree to use when given
+ multiple device trees, some of which may not be compatible with the
+ actual hardware. It is the bootloader's responsibility to pass the
+ correct device tree to the kernel.
+ The property is deprecated.
+
+ qcom,board-id:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ minItems: 1
+ maxItems: 8
+ oneOf:
+ - items:
+ - items:
+ - description: |
+ Board ID consisting of three bitfields::
+ - bits 31-24 - Unused
+ - bits 23-16 - Platform Version Major
+ - bits 15-8 - Platform Version Minor
+ - bits 7-0 - Platform Type
+ Platform Type field is an exact match value. The
+ Platform Major/Minor field is a best match. The bootloader will
+ look for the closest possible match.
+ - description: |
+ Subtype ID unique to a Platform Type/Chipset ID. For a given
+ Platform Type, there will typically only be a single board and the
+ subtype_id will be 0. However in some cases board variants may
+ need to be distinguished by different subtype_id values.
+ - items:
+ # OnePlus uses a variant of board-id with four elements:
+ - items:
+ - const: 8
+ - const: 0
+ - description: OnePlus board ID
+ - description: OnePlus subtype ID
+ deprecated: true
+ description:
+ The board type and revision information. It can optionally be an array
+ of these to indicate multiple boards that use the same device tree. It
+ is expected that the bootloader will use this information at boot-up to
+ decide which device tree to use when given multiple device trees, some of
+ which may not be compatible with the actual hardware. It is the
+ bootloader's responsibility to pass the correct device tree to the
+ kernel
+ The property is deprecated.
+
+allOf:
+ # Explicit allow-list for older SoCs. The legacy properties are not allowed
+ # on newer SoCs.
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,apq8026
+ - qcom,apq8094
+ - qcom,apq8096
+ - qcom,msm8992
+ - qcom,msm8994
+ - qcom,msm8996
+ - qcom,msm8998
+ - qcom,sdm630
+ - qcom,sdm632
+ - qcom,sdm845
+ - qcom,sdx55
+ - qcom,sdx65
+ - qcom,sm6125
+ - qcom,sm6350
+ - qcom,sm7225
+ - qcom,sm8150
+ - qcom,sm8250
+ then:
+ properties:
+ qcom,board-id: true
+ qcom,msm-id: true
+ else:
+ properties:
+ qcom,board-id: false
+ qcom,msm-id: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - oneplus,cheeseburger
+ - oneplus,dumpling
+ - oneplus,enchilada
+ - oneplus,fajita
+ then:
+ properties:
+ qcom,board-id:
+ items:
+ minItems: 4
+ else:
+ properties:
+ qcom,board-id:
+ items:
+ maxItems: 2
+
additionalProperties: true
...
diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index c6c69a4e3777..88ff4422a8c1 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -30,11 +30,26 @@ properties:
- const: amarula,vyasa-rk3288
- const: rockchip,rk3288
+ - description: Anbernic RG351M
+ items:
+ - const: anbernic,rg351m
+ - const: rockchip,rk3326
+
- description: Anbernic RG353P
items:
- const: anbernic,rg353p
- const: rockchip,rk3566
+ - description: Anbernic RG353V
+ items:
+ - const: anbernic,rg353v
+ - const: rockchip,rk3566
+
+ - description: Anbernic RG353VS
+ items:
+ - const: anbernic,rg353vs
+ - const: rockchip,rk3566
+
- description: Anbernic RG503
items:
- const: anbernic,rg503
@@ -468,6 +483,21 @@ properties:
- const: hardkernel,rk3326-odroid-go2
- const: rockchip,rk3326
+ - description: Hardkernel Odroid Go Advance Black Edition
+ items:
+ - const: hardkernel,rk3326-odroid-go2-v11
+ - const: rockchip,rk3326
+
+ - description: Hardkernel Odroid Go Super
+ items:
+ - const: hardkernel,rk3326-odroid-go3
+ - const: rockchip,rk3326
+
+ - description: Hardkernel Odroid M1
+ items:
+ - const: rockchip,rk3568-odroid-m1
+ - const: rockchip,rk3568
+
- description: Hugsun X99 TV Box
items:
- const: hugsun,x99
@@ -563,7 +593,9 @@ properties:
- description: Pine64 SoQuartz SoM
items:
- enum:
+ - pine64,soquartz-blade
- pine64,soquartz-cm4io
+ - pine64,soquartz-model-a
- const: pine64,soquartz
- const: rockchip,rk3566
@@ -709,6 +741,11 @@ properties:
- const: rockchip,rv1108-evb
- const: rockchip,rv1108
+ - description: Theobroma Systems PX30-uQ7 with Haikou baseboard
+ items:
+ - const: tsd,px30-ringneck-haikou
+ - const: rockchip,px30
+
- description: Theobroma Systems RK3368-uQ7 with Haikou baseboard
items:
- const: tsd,rk3368-lion-haikou
@@ -729,6 +766,11 @@ properties:
- const: zkmagic,a95x-z2
- const: rockchip,rk3318
+ - description: Rockchip RK3566 BOX Evaluation Demo board
+ items:
+ - const: rockchip,rk3566-box-demo
+ - const: rockchip,rk3566
+
- description: Rockchip RK3568 Evaluation board
items:
- const: rockchip,rk3568-evb1-v10
diff --git a/Documentation/devicetree/bindings/arm/socionext/uniphier.yaml b/Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
index 8c0e91658474..c2cea1c90f3c 100644
--- a/Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
+++ b/Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
@@ -26,6 +26,12 @@ properties:
- socionext,uniphier-pro4-ref
- socionext,uniphier-pro4-sanji
- const: socionext,uniphier-pro4
+ - description: Pro5 SoC boards
+ items:
+ - enum:
+ - socionext,uniphier-pro5-epcore
+ - socionext,uniphier-pro5-proex
+ - const: socionext,uniphier-pro5
- description: sLD8 SoC boards
items:
- enum:
diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
index 4c605bccc474..44f5c5855af8 100644
--- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
+++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
@@ -59,6 +59,12 @@ properties:
- prt,prtt1s # Protonic PRTT1S
- const: st,stm32mp151
+ - description: DH STM32MP151 DHCOR SoM based Boards
+ items:
+ - const: dh,stm32mp151a-dhcor-testbench
+ - const: dh,stm32mp151a-dhcor-som
+ - const: st,stm32mp151
+
- description: DH STM32MP153 DHCOM SoM based Boards
items:
- const: dh,stm32mp153c-dhcom-drc02
diff --git a/Documentation/devicetree/bindings/arm/swir.txt b/Documentation/devicetree/bindings/arm/swir.txt
deleted file mode 100644
index 042be73a95d3..000000000000
--- a/Documentation/devicetree/bindings/arm/swir.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Sierra Wireless Modules device tree bindings
---------------------------------------------
-
-Supported Modules :
- - WP8548 : Includes MDM9615 and PM8018 in a module
-
-Sierra Wireless modules shall have the following properties :
- Required root node property
- - compatible: "swir,wp8548" for the WP8548 CF3 Module
-
-Board compatible values:
- - "swir,mangoh-green-wp8548" for the mangOH green board with the WP8548 module
diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml
index 28b8232e1c5b..09e6845ff243 100644
--- a/Documentation/devicetree/bindings/arm/ti/k3.yaml
+++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml
@@ -61,6 +61,7 @@ properties:
- const: ti,j721e
- items:
- enum:
+ - beagle,j721e-beagleboneai64
- ti,j721e-evm
- ti,j721e-sk
- const: ti,j721e
diff --git a/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml b/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
index 50ebd8c57795..defcf1e12aa1 100644
--- a/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
+++ b/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
@@ -48,6 +48,7 @@ examples:
cros_ec: ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
+ interrupts = <35 0>;
typec {
compatible = "google,cros-ec-typec";
diff --git a/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml b/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml
index 5b875af6a95a..40244d003c32 100644
--- a/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml
+++ b/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml
@@ -27,6 +27,7 @@ examples:
cros_ec: ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
+ interrupts = <15 0>;
kbd-led-backlight {
compatible = "google,cros-kbd-led-backlight";
diff --git a/Documentation/devicetree/bindings/clock/fsl,imx8m-anatop.yaml b/Documentation/devicetree/bindings/clock/fsl,imx8m-anatop.yaml
new file mode 100644
index 000000000000..bbd22e95b319
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/fsl,imx8m-anatop.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/fsl,imx8m-anatop.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX8M Family Anatop Module
+
+maintainers:
+ - Peng Fan <peng.fan@nxp.com>
+
+description: |
+ NXP i.MX8M Family anatop PLL module which generates PLL to CCM root.
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - fsl,imx8mm-anatop
+ - fsl,imx8mq-anatop
+ - items:
+ - enum:
+ - fsl,imx8mn-anatop
+ - fsl,imx8mp-anatop
+ - const: fsl,imx8mm-anatop
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ anatop: clock-controller@30360000 {
+ compatible = "fsl,imx8mn-anatop", "fsl,imx8mm-anatop";
+ reg = <0x30360000 0x10000>;
+ #clock-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt
index 958e0ad78c52..f7d347385b57 100644
--- a/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-dfll.txt
@@ -136,7 +136,7 @@ clock@70110000 {
};
/* pinmux nodes added for completeness. Binding doc can be found in:
- * Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt
+ * Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.yaml
*/
pinmux: pinmux@700008d4 {
diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
index 2ab4642679c0..55c4f94a14d1 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
@@ -148,7 +148,7 @@ allOf:
items:
- const: oscclk
- const: dout_clkcmu_fsys1_bus
- - const: dout_clkcmu_fsys1_mmc_card
+ - const: gout_clkcmu_fsys1_mmc_card
- const: dout_clkcmu_fsys1_usbdrd
- if:
diff --git a/Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml b/Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml
new file mode 100644
index 000000000000..76cb9726660e
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/cpufreq/apple,cluster-cpufreq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple SoC cluster cpufreq device
+
+maintainers:
+ - Hector Martin <marcan@marcan.st>
+
+description: |
+ Apple SoCs (e.g. M1) have a per-cpu-cluster DVFS controller that is part of
+ the cluster management register block. This binding uses the standard
+ operating-points-v2 table to define the CPU performance states, with the
+ opp-level property specifying the hardware p-state index for that level.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - apple,t8103-cluster-cpufreq
+ - apple,t8112-cluster-cpufreq
+ - const: apple,cluster-cpufreq
+ - items:
+ - const: apple,t6000-cluster-cpufreq
+ - const: apple,t8103-cluster-cpufreq
+ - const: apple,cluster-cpufreq
+
+ reg:
+ maxItems: 1
+
+ '#performance-domain-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - '#performance-domain-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ // This example shows a single CPU per domain and 2 domains,
+ // with two p-states per domain.
+ // Shipping hardware has 2-4 CPUs per domain and 2-6 domains.
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "apple,icestorm";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ operating-points-v2 = <&ecluster_opp>;
+ performance-domains = <&cpufreq_e>;
+ };
+
+ cpu@10100 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10100>;
+ operating-points-v2 = <&pcluster_opp>;
+ performance-domains = <&cpufreq_p>;
+ };
+ };
+
+ ecluster_opp: opp-table-0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <7500>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <972000000>;
+ opp-level = <2>;
+ clock-latency-ns = <22000>;
+ };
+ };
+
+ pcluster_opp: opp-table-1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <8000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <828000000>;
+ opp-level = <2>;
+ clock-latency-ns = <19000>;
+ };
+ };
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpufreq_e: performance-controller@210e20000 {
+ compatible = "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x10e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ cpufreq_p: performance-controller@211e20000 {
+ compatible = "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x11e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml
index 24fa3d87a40b..903b31129f01 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml
@@ -25,6 +25,7 @@ properties:
- description: v2 of CPUFREQ HW (EPSS)
items:
- enum:
+ - qcom,qdu1000-cpufreq-epss
- qcom,sm6375-cpufreq-epss
- qcom,sm8250-cpufreq-epss
- const: qcom,cpufreq-epss
@@ -56,6 +57,9 @@ properties:
'#freq-domain-cells':
const: 1
+ '#clock-cells':
+ const: 1
+
required:
- compatible
- reg
@@ -83,11 +87,16 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_0>;
qcom,freq-domain = <&cpufreq_hw 0>;
+ clocks = <&cpufreq_hw 0>;
L2_0: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
L3_0: l3-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <3>;
};
};
};
@@ -99,8 +108,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_100>;
qcom,freq-domain = <&cpufreq_hw 0>;
+ clocks = <&cpufreq_hw 0>;
L2_100: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -112,8 +124,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_200>;
qcom,freq-domain = <&cpufreq_hw 0>;
+ clocks = <&cpufreq_hw 0>;
L2_200: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -125,8 +140,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_300>;
qcom,freq-domain = <&cpufreq_hw 0>;
+ clocks = <&cpufreq_hw 0>;
L2_300: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -138,8 +156,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_400>;
qcom,freq-domain = <&cpufreq_hw 1>;
+ clocks = <&cpufreq_hw 1>;
L2_400: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -151,8 +172,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_500>;
qcom,freq-domain = <&cpufreq_hw 1>;
+ clocks = <&cpufreq_hw 1>;
L2_500: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -164,8 +188,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_600>;
qcom,freq-domain = <&cpufreq_hw 1>;
+ clocks = <&cpufreq_hw 1>;
L2_600: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -177,8 +204,11 @@ examples:
enable-method = "psci";
next-level-cache = <&L2_700>;
qcom,freq-domain = <&cpufreq_hw 1>;
+ clocks = <&cpufreq_hw 1>;
L2_700: l2-cache {
compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
next-level-cache = <&L3_0>;
};
};
@@ -197,6 +227,7 @@ examples:
clock-names = "xo", "alternate";
#freq-domain-cells = <1>;
+ #clock-cells = <1>;
};
};
...
diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml
index 7910831fa4b8..c731fbdc2fe0 100644
--- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml
@@ -12,9 +12,14 @@ maintainers:
properties:
compatible:
- enum:
- - allwinner,sun6i-a31-mipi-dsi
- - allwinner,sun50i-a64-mipi-dsi
+ oneOf:
+ - enum:
+ - allwinner,sun6i-a31-mipi-dsi
+ - allwinner,sun50i-a64-mipi-dsi
+ - allwinner,sun50i-a100-mipi-dsi
+ - items:
+ - const: allwinner,sun20i-d1-mipi-dsi
+ - const: allwinner,sun50i-a100-mipi-dsi
reg:
maxItems: 1
@@ -59,7 +64,6 @@ required:
- phys
- phy-names
- resets
- - vcc-dsi-supply
- port
allOf:
@@ -68,7 +72,9 @@ allOf:
properties:
compatible:
contains:
- const: allwinner,sun6i-a31-mipi-dsi
+ enum:
+ - allwinner,sun6i-a31-mipi-dsi
+ - allwinner,sun50i-a100-mipi-dsi
then:
properties:
@@ -78,16 +84,22 @@ allOf:
required:
- clock-names
+ else:
+ properties:
+ clocks:
+ maxItems: 1
+
- if:
properties:
compatible:
contains:
- const: allwinner,sun50i-a64-mipi-dsi
+ enum:
+ - allwinner,sun6i-a31-mipi-dsi
+ - allwinner,sun50i-a64-mipi-dsi
then:
- properties:
- clocks:
- minItems: 1
+ required:
+ - vcc-dsi-supply
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
index 7cdffdb131ac..74cefdf1b843 100644
--- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
@@ -11,7 +11,7 @@ maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
allOf:
- - $ref: /schemas/sound/name-prefix.yaml#
+ - $ref: /schemas/sound/dai-common.yaml#
description: |
The Amlogic Meson Synopsys Designware Integration is composed of
diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
new file mode 100644
index 000000000000..131d5b63ec4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
@@ -0,0 +1,182 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/renesas,dsi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L MIPI DSI Encoder
+
+maintainers:
+ - Biju Das <biju.das.jz@bp.renesas.com>
+
+description: |
+ This binding describes the MIPI DSI encoder embedded in the Renesas
+ RZ/G2L alike family of SoC's. The encoder can operate in DSI mode, with
+ up to four data lanes.
+
+allOf:
+ - $ref: /schemas/display/dsi-controller.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
+ - const: renesas,rzg2l-mipi-dsi
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: Sequence operation channel 0 interrupt
+ - description: Sequence operation channel 1 interrupt
+ - description: Video-Input operation channel 1 interrupt
+ - description: DSI Packet Receive interrupt
+ - description: DSI Fatal Error interrupt
+ - description: DSI D-PHY PPI interrupt
+ - description: Debug interrupt
+
+ interrupt-names:
+ items:
+ - const: seq0
+ - const: seq1
+ - const: vin1
+ - const: rcv
+ - const: ferr
+ - const: ppi
+ - const: debug
+
+ clocks:
+ items:
+ - description: DSI D-PHY PLL multiplied clock
+ - description: DSI D-PHY system clock
+ - description: DSI AXI bus clock
+ - description: DSI Register access clock
+ - description: DSI Video clock
+ - description: DSI D-PHY Escape mode transmit clock
+
+ clock-names:
+ items:
+ - const: pllclk
+ - const: sysclk
+ - const: aclk
+ - const: pclk
+ - const: vclk
+ - const: lpclk
+
+ resets:
+ items:
+ - description: MIPI_DSI_CMN_RSTB
+ - description: MIPI_DSI_ARESET_N
+ - description: MIPI_DSI_PRESET_N
+
+ reset-names:
+ items:
+ - const: rst
+ - const: arst
+ - const: prst
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Parallel input port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: DSI output port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ description: array of physical DSI data lane indexes.
+ minItems: 1
+ items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ required:
+ - data-lanes
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/r9a07g044-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ dsi0: dsi@10850000 {
+ compatible = "renesas,r9a07g044-mipi-dsi", "renesas,rzg2l-mipi-dsi";
+ reg = <0x10850000 0x20000>;
+ interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "seq0", "seq1", "vin1", "rcv",
+ "ferr", "ppi", "debug";
+ clocks = <&cpg CPG_MOD R9A07G044_MIPI_DSI_PLLCLK>,
+ <&cpg CPG_MOD R9A07G044_MIPI_DSI_SYSCLK>,
+ <&cpg CPG_MOD R9A07G044_MIPI_DSI_ACLK>,
+ <&cpg CPG_MOD R9A07G044_MIPI_DSI_PCLK>,
+ <&cpg CPG_MOD R9A07G044_MIPI_DSI_VCLK>,
+ <&cpg CPG_MOD R9A07G044_MIPI_DSI_LPCLK>;
+ clock-names = "pllclk", "sysclk", "aclk", "pclk", "vclk", "lpclk";
+ resets = <&cpg R9A07G044_MIPI_DSI_CMN_RSTB>,
+ <&cpg R9A07G044_MIPI_DSI_ARESET_N>,
+ <&cpg R9A07G044_MIPI_DSI_PRESET_N>;
+ reset-names = "rst", "arst", "prst";
+ power-domains = <&cpg>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&du_out_dsi0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&adv7535_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
index 5bb23e97cf33..d976380801e3 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
@@ -23,6 +23,7 @@ properties:
- mediatek,mt8173-dpi
- mediatek,mt8183-dpi
- mediatek,mt8186-dpi
+ - mediatek,mt8188-dp-intf
- mediatek,mt8192-dpi
- mediatek,mt8195-dp-intf
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-common.yaml b/Documentation/devicetree/bindings/display/msm/dpu-common.yaml
new file mode 100644
index 000000000000..8ffbc30c6b7f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/dpu-common.yaml
@@ -0,0 +1,52 @@
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/dpu-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU common properties
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ - Rob Clark <robdclark@gmail.com>
+
+description: |
+ Common properties for QCom DPU display controller.
+
+properties:
+ interrupts:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ operating-points-v2: true
+ opp-table:
+ type: object
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ description: |
+ Contains the list of output ports from DPU device. These ports
+ connect to interfaces that are external to the DPU hardware,
+ such as DSI, DP etc.
+
+ patternProperties:
+ "^port@[0-9a-f]+$":
+ $ref: /schemas/graph.yaml#/properties/port
+
+ # at least one port is required
+ required:
+ - port@0
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - clocks
+ - interrupts
+ - power-domains
+ - operating-points-v2
+ - ports
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml
deleted file mode 100644
index 253665c693e6..000000000000
--- a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml
+++ /dev/null
@@ -1,223 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/display/msm/dpu-msm8998.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display DPU dt properties for MSM8998 target
-
-maintainers:
- - AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
-
-description: |
- Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
- sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
- bindings of MDSS and DPU are mentioned for MSM8998 target.
-
-properties:
- compatible:
- items:
- - const: qcom,msm8998-mdss
-
- reg:
- maxItems: 1
-
- reg-names:
- const: mdss
-
- power-domains:
- maxItems: 1
-
- clocks:
- items:
- - description: Display AHB clock
- - description: Display AXI clock
- - description: Display core clock
-
- clock-names:
- items:
- - const: iface
- - const: bus
- - const: core
-
- interrupts:
- maxItems: 1
-
- interrupt-controller: true
-
- "#address-cells": true
-
- "#size-cells": true
-
- "#interrupt-cells":
- const: 1
-
- iommus:
- items:
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
-
- ranges: true
-
-patternProperties:
- "^display-controller@[0-9a-f]+$":
- type: object
- description: Node containing the properties of DPU.
- additionalProperties: false
-
- properties:
- compatible:
- items:
- - const: qcom,msm8998-dpu
-
- reg:
- items:
- - description: Address offset and size for mdp register set
- - description: Address offset and size for regdma register set
- - description: Address offset and size for vbif register set
- - description: Address offset and size for non-realtime vbif register set
-
- reg-names:
- items:
- - const: mdp
- - const: regdma
- - const: vbif
- - const: vbif_nrt
-
- clocks:
- items:
- - description: Display ahb clock
- - description: Display axi clock
- - description: Display mem-noc clock
- - description: Display core clock
- - description: Display vsync clock
-
- clock-names:
- items:
- - const: iface
- - const: bus
- - const: mnoc
- - const: core
- - const: vsync
-
- interrupts:
- maxItems: 1
-
- power-domains:
- maxItems: 1
-
- operating-points-v2: true
- opp-table:
- type: object
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
- Contains the list of output ports from DPU device. These ports
- connect to interfaces that are external to the DPU hardware,
- such as DSI, DP etc. Each output port contains an endpoint that
- describes how it is connected to an external interface.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF1 (DSI1)
-
- port@1:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF2 (DSI2)
-
- required:
- - port@0
- - port@1
-
- required:
- - compatible
- - reg
- - reg-names
- - clocks
- - interrupts
- - power-domains
- - operating-points-v2
- - ports
-
-required:
- - compatible
- - reg
- - reg-names
- - power-domains
- - clocks
- - interrupts
- - interrupt-controller
- - iommus
- - ranges
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/qcom,mmcc-msm8998.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/power/qcom-rpmpd.h>
-
- mdss: display-subsystem@c900000 {
- compatible = "qcom,msm8998-mdss";
- reg = <0x0c900000 0x1000>;
- reg-names = "mdss";
-
- clocks = <&mmcc MDSS_AHB_CLK>,
- <&mmcc MDSS_AXI_CLK>,
- <&mmcc MDSS_MDP_CLK>;
- clock-names = "iface", "bus", "core";
-
- #address-cells = <1>;
- #interrupt-cells = <1>;
- #size-cells = <1>;
-
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- iommus = <&mmss_smmu 0>;
-
- power-domains = <&mmcc MDSS_GDSC>;
- ranges;
-
- display-controller@c901000 {
- compatible = "qcom,msm8998-dpu";
- reg = <0x0c901000 0x8f000>,
- <0x0c9a8e00 0xf0>,
- <0x0c9b0000 0x2008>,
- <0x0c9b8000 0x1040>;
- reg-names = "mdp", "regdma", "vbif", "vbif_nrt";
-
- clocks = <&mmcc MDSS_AHB_CLK>,
- <&mmcc MDSS_AXI_CLK>,
- <&mmcc MNOC_AHB_CLK>,
- <&mmcc MDSS_MDP_CLK>,
- <&mmcc MDSS_VSYNC_CLK>;
- clock-names = "iface", "bus", "mnoc", "core", "vsync";
-
- interrupt-parent = <&mdss>;
- interrupts = <0>;
- operating-points-v2 = <&mdp_opp_table>;
- power-domains = <&rpmpd MSM8998_VDDMX>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
-
- port@1 {
- reg = <1>;
- dpu_intf2_out: endpoint {
- remote-endpoint = <&dsi1_in>;
- };
- };
- };
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml
deleted file mode 100644
index c5824e1d2382..000000000000
--- a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml
+++ /dev/null
@@ -1,222 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/display/msm/dpu-qcm2290.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display DPU dt properties for QCM2290 target
-
-maintainers:
- - Loic Poulain <loic.poulain@linaro.org>
-
-description: |
- Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
- sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS
- and DPU are mentioned for QCM2290 target.
-
-properties:
- compatible:
- items:
- - const: qcom,qcm2290-mdss
-
- reg:
- maxItems: 1
-
- reg-names:
- const: mdss
-
- power-domains:
- maxItems: 1
-
- clocks:
- items:
- - description: Display AHB clock from gcc
- - description: Display AXI clock
- - description: Display core clock
-
- clock-names:
- items:
- - const: iface
- - const: bus
- - const: core
-
- interrupts:
- maxItems: 1
-
- interrupt-controller: true
-
- "#address-cells": true
-
- "#size-cells": true
-
- "#interrupt-cells":
- const: 1
-
- iommus:
- items:
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1
-
- ranges: true
-
- interconnects:
- items:
- - description: Interconnect path specifying the port ids for data bus
-
- interconnect-names:
- const: mdp0-mem
-
- resets:
- items:
- - description: MDSS_CORE reset
-
-patternProperties:
- "^display-controller@[0-9a-f]+$":
- type: object
- description: Node containing the properties of DPU.
- additionalProperties: false
-
- properties:
- compatible:
- items:
- - const: qcom,qcm2290-dpu
-
- reg:
- items:
- - description: Address offset and size for mdp register set
- - description: Address offset and size for vbif register set
-
- reg-names:
- items:
- - const: mdp
- - const: vbif
-
- clocks:
- items:
- - description: Display AXI clock from gcc
- - description: Display AHB clock from dispcc
- - description: Display core clock from dispcc
- - description: Display lut clock from dispcc
- - description: Display vsync clock from dispcc
-
- clock-names:
- items:
- - const: bus
- - const: iface
- - const: core
- - const: lut
- - const: vsync
-
- interrupts:
- maxItems: 1
-
- power-domains:
- maxItems: 1
-
- operating-points-v2: true
- opp-table:
- type: object
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
- Contains the list of output ports from DPU device. These ports
- connect to interfaces that are external to the DPU hardware,
- such as DSI. Each output port contains an endpoint that
- describes how it is connected to an external interface.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF1 (DSI1)
-
- required:
- - port@0
-
- required:
- - compatible
- - reg
- - reg-names
- - clocks
- - interrupts
- - power-domains
- - operating-points-v2
- - ports
-
-required:
- - compatible
- - reg
- - reg-names
- - power-domains
- - clocks
- - interrupts
- - interrupt-controller
- - iommus
- - ranges
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
- #include <dt-bindings/clock/qcom,gcc-qcm2290.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/interconnect/qcom,qcm2290.h>
- #include <dt-bindings/power/qcom-rpmpd.h>
-
- mdss: mdss@5e00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,qcm2290-mdss";
- reg = <0x05e00000 0x1000>;
- reg-names = "mdss";
- power-domains = <&dispcc MDSS_GDSC>;
- clocks = <&gcc GCC_DISP_AHB_CLK>,
- <&gcc GCC_DISP_HF_AXI_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>;
- clock-names = "iface", "bus", "core";
-
- interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- #interrupt-cells = <1>;
-
- interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>;
- interconnect-names = "mdp0-mem";
-
- iommus = <&apps_smmu 0x420 0x2>,
- <&apps_smmu 0x421 0x0>;
- ranges;
-
- mdss_mdp: display-controller@5e01000 {
- compatible = "qcom,qcm2290-dpu";
- reg = <0x05e01000 0x8f000>,
- <0x05eb0000 0x2008>;
- reg-names = "mdp", "vbif";
-
- clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
- <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
- <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
- clock-names = "bus", "iface", "core", "lut", "vsync";
-
- operating-points-v2 = <&mdp_opp_table>;
- power-domains = <&rpmpd QCM2290_VDDCX>;
-
- interrupt-parent = <&mdss>;
- interrupts = <0>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
- };
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml
deleted file mode 100644
index 4890bc25f3fd..000000000000
--- a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml
+++ /dev/null
@@ -1,235 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/display/msm/dpu-sc7180.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display DPU dt properties for SC7180 target
-
-maintainers:
- - Krishna Manikandan <quic_mkrishn@quicinc.com>
-
-description: |
- Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
- sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
- bindings of MDSS and DPU are mentioned for SC7180 target.
-
-properties:
- compatible:
- items:
- - const: qcom,sc7180-mdss
-
- reg:
- maxItems: 1
-
- reg-names:
- const: mdss
-
- power-domains:
- maxItems: 1
-
- clocks:
- items:
- - description: Display AHB clock from gcc
- - description: Display AHB clock from dispcc
- - description: Display core clock
-
- clock-names:
- items:
- - const: iface
- - const: ahb
- - const: core
-
- interrupts:
- maxItems: 1
-
- interrupt-controller: true
-
- "#address-cells": true
-
- "#size-cells": true
-
- "#interrupt-cells":
- const: 1
-
- iommus:
- items:
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
-
- ranges: true
-
- interconnects:
- items:
- - description: Interconnect path specifying the port ids for data bus
-
- interconnect-names:
- const: mdp0-mem
-
- resets:
- items:
- - description: MDSS_CORE reset
-
-patternProperties:
- "^display-controller@[0-9a-f]+$":
- type: object
- description: Node containing the properties of DPU.
- additionalProperties: false
-
- properties:
- compatible:
- items:
- - const: qcom,sc7180-dpu
-
- reg:
- items:
- - description: Address offset and size for mdp register set
- - description: Address offset and size for vbif register set
-
- reg-names:
- items:
- - const: mdp
- - const: vbif
-
- clocks:
- items:
- - description: Display hf axi clock
- - description: Display ahb clock
- - description: Display rotator clock
- - description: Display lut clock
- - description: Display core clock
- - description: Display vsync clock
-
- clock-names:
- items:
- - const: bus
- - const: iface
- - const: rot
- - const: lut
- - const: core
- - const: vsync
-
- interrupts:
- maxItems: 1
-
- power-domains:
- maxItems: 1
-
- operating-points-v2: true
- opp-table:
- type: object
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
- Contains the list of output ports from DPU device. These ports
- connect to interfaces that are external to the DPU hardware,
- such as DSI, DP etc. Each output port contains an endpoint that
- describes how it is connected to an external interface.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF1 (DSI1)
-
- port@2:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF0 (DP)
-
- required:
- - port@0
-
- required:
- - compatible
- - reg
- - reg-names
- - clocks
- - interrupts
- - power-domains
- - operating-points-v2
- - ports
-
-required:
- - compatible
- - reg
- - reg-names
- - power-domains
- - clocks
- - interrupts
- - interrupt-controller
- - iommus
- - ranges
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/qcom,dispcc-sc7180.h>
- #include <dt-bindings/clock/qcom,gcc-sc7180.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/interconnect/qcom,sdm845.h>
- #include <dt-bindings/power/qcom-rpmpd.h>
-
- display-subsystem@ae00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,sc7180-mdss";
- reg = <0xae00000 0x1000>;
- reg-names = "mdss";
- power-domains = <&dispcc MDSS_GDSC>;
- clocks = <&gcc GCC_DISP_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>;
- clock-names = "iface", "ahb", "core";
-
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- #interrupt-cells = <1>;
-
- interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>;
- interconnect-names = "mdp0-mem";
-
- iommus = <&apps_smmu 0x800 0x2>;
- ranges;
-
- display-controller@ae01000 {
- compatible = "qcom,sc7180-dpu";
- reg = <0x0ae01000 0x8f000>,
- <0x0aeb0000 0x2008>;
-
- reg-names = "mdp", "vbif";
-
- clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
- <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_ROT_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>,
- <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
- clock-names = "bus", "iface", "rot", "lut", "core",
- "vsync";
-
- interrupt-parent = <&mdss>;
- interrupts = <0>;
- power-domains = <&rpmhpd SC7180_CX>;
- operating-points-v2 = <&mdp_opp_table>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
-
- port@2 {
- reg = <2>;
- dpu_intf0_out: endpoint {
- remote-endpoint = <&dp_in>;
- };
- };
- };
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml
deleted file mode 100644
index 584d646021d5..000000000000
--- a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml
+++ /dev/null
@@ -1,239 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/display/msm/dpu-sc7280.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display DPU dt properties for SC7280
-
-maintainers:
- - Krishna Manikandan <quic_mkrishn@quicinc.com>
-
-description: |
- Device tree bindings for MSM Mobile Display Subsystem (MDSS) that encapsulates
- sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
- bindings of MDSS and DPU are mentioned for SC7280.
-
-properties:
- compatible:
- const: qcom,sc7280-mdss
-
- reg:
- maxItems: 1
-
- reg-names:
- const: mdss
-
- power-domains:
- maxItems: 1
-
- clocks:
- items:
- - description: Display AHB clock from gcc
- - description: Display AHB clock from dispcc
- - description: Display core clock
-
- clock-names:
- items:
- - const: iface
- - const: ahb
- - const: core
-
- interrupts:
- maxItems: 1
-
- interrupt-controller: true
-
- "#address-cells": true
-
- "#size-cells": true
-
- "#interrupt-cells":
- const: 1
-
- iommus:
- items:
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
-
- ranges: true
-
- interconnects:
- items:
- - description: Interconnect path specifying the port ids for data bus
-
- interconnect-names:
- const: mdp0-mem
-
- resets:
- items:
- - description: MDSS_CORE reset
-
-patternProperties:
- "^display-controller@[0-9a-f]+$":
- type: object
- description: Node containing the properties of DPU.
- additionalProperties: false
-
- properties:
- compatible:
- const: qcom,sc7280-dpu
-
- reg:
- items:
- - description: Address offset and size for mdp register set
- - description: Address offset and size for vbif register set
-
- reg-names:
- items:
- - const: mdp
- - const: vbif
-
- clocks:
- items:
- - description: Display hf axi clock
- - description: Display sf axi clock
- - description: Display ahb clock
- - description: Display lut clock
- - description: Display core clock
- - description: Display vsync clock
-
- clock-names:
- items:
- - const: bus
- - const: nrt_bus
- - const: iface
- - const: lut
- - const: core
- - const: vsync
-
- interrupts:
- maxItems: 1
-
- power-domains:
- maxItems: 1
-
- operating-points-v2: true
- opp-table:
- type: object
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
- Contains the list of output ports from DPU device. These ports
- connect to interfaces that are external to the DPU hardware,
- such as DSI, DP etc. Each output port contains an endpoint that
- describes how it is connected to an external interface.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF1 (DSI)
-
- port@1:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF5 (EDP)
-
- required:
- - port@0
-
- required:
- - compatible
- - reg
- - reg-names
- - clocks
- - interrupts
- - power-domains
- - operating-points-v2
- - ports
-
-required:
- - compatible
- - reg
- - reg-names
- - power-domains
- - clocks
- - interrupts
- - interrupt-controller
- - iommus
- - ranges
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/qcom,dispcc-sc7280.h>
- #include <dt-bindings/clock/qcom,gcc-sc7280.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/interconnect/qcom,sc7280.h>
- #include <dt-bindings/power/qcom-rpmpd.h>
-
- display-subsystem@ae00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,sc7280-mdss";
- reg = <0xae00000 0x1000>;
- reg-names = "mdss";
- power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
- clocks = <&gcc GCC_DISP_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>;
- clock-names = "iface",
- "ahb",
- "core";
-
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- #interrupt-cells = <1>;
-
- interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>;
- interconnect-names = "mdp0-mem";
-
- iommus = <&apps_smmu 0x900 0x402>;
- ranges;
-
- display-controller@ae01000 {
- compatible = "qcom,sc7280-dpu";
- reg = <0x0ae01000 0x8f000>,
- <0x0aeb0000 0x2008>;
-
- reg-names = "mdp", "vbif";
-
- clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
- <&gcc GCC_DISP_SF_AXI_CLK>,
- <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>,
- <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
- clock-names = "bus",
- "nrt_bus",
- "iface",
- "lut",
- "core",
- "vsync";
-
- interrupt-parent = <&mdss>;
- interrupts = <0>;
- power-domains = <&rpmhpd SC7280_CX>;
- operating-points-v2 = <&mdp_opp_table>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
-
- port@1 {
- reg = <1>;
- dpu_intf5_out: endpoint {
- remote-endpoint = <&edp_in>;
- };
- };
- };
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml
deleted file mode 100644
index 7d1037373175..000000000000
--- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml
+++ /dev/null
@@ -1,217 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/display/msm/dpu-sdm845.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display DPU dt properties for SDM845 target
-
-maintainers:
- - Krishna Manikandan <quic_mkrishn@quicinc.com>
-
-description: |
- Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
- sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
- bindings of MDSS and DPU are mentioned for SDM845 target.
-
-properties:
- compatible:
- items:
- - const: qcom,sdm845-mdss
-
- reg:
- maxItems: 1
-
- reg-names:
- const: mdss
-
- power-domains:
- maxItems: 1
-
- clocks:
- items:
- - description: Display AHB clock from gcc
- - description: Display core clock
-
- clock-names:
- items:
- - const: iface
- - const: core
-
- interrupts:
- maxItems: 1
-
- interrupt-controller: true
-
- "#address-cells": true
-
- "#size-cells": true
-
- "#interrupt-cells":
- const: 1
-
- iommus:
- items:
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
- - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1
-
- ranges: true
-
- resets:
- items:
- - description: MDSS_CORE reset
-
-patternProperties:
- "^display-controller@[0-9a-f]+$":
- type: object
- description: Node containing the properties of DPU.
- additionalProperties: false
-
- properties:
- compatible:
- items:
- - const: qcom,sdm845-dpu
-
- reg:
- items:
- - description: Address offset and size for mdp register set
- - description: Address offset and size for vbif register set
-
- reg-names:
- items:
- - const: mdp
- - const: vbif
-
- clocks:
- items:
- - description: Display ahb clock
- - description: Display axi clock
- - description: Display core clock
- - description: Display vsync clock
-
- clock-names:
- items:
- - const: iface
- - const: bus
- - const: core
- - const: vsync
-
- interrupts:
- maxItems: 1
-
- power-domains:
- maxItems: 1
-
- operating-points-v2: true
- opp-table:
- type: object
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
- Contains the list of output ports from DPU device. These ports
- connect to interfaces that are external to the DPU hardware,
- such as DSI, DP etc. Each output port contains an endpoint that
- describes how it is connected to an external interface.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF1 (DSI1)
-
- port@1:
- $ref: /schemas/graph.yaml#/properties/port
- description: DPU_INTF2 (DSI2)
-
- required:
- - port@0
- - port@1
-
- required:
- - compatible
- - reg
- - reg-names
- - clocks
- - interrupts
- - power-domains
- - operating-points-v2
- - ports
-
-required:
- - compatible
- - reg
- - reg-names
- - power-domains
- - clocks
- - interrupts
- - interrupt-controller
- - iommus
- - ranges
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/qcom,dispcc-sdm845.h>
- #include <dt-bindings/clock/qcom,gcc-sdm845.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/power/qcom-rpmpd.h>
-
- display-subsystem@ae00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,sdm845-mdss";
- reg = <0x0ae00000 0x1000>;
- reg-names = "mdss";
- power-domains = <&dispcc MDSS_GDSC>;
-
- clocks = <&gcc GCC_DISP_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>;
- clock-names = "iface", "core";
-
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- #interrupt-cells = <1>;
-
- iommus = <&apps_smmu 0x880 0x8>,
- <&apps_smmu 0xc80 0x8>;
- ranges;
-
- display-controller@ae01000 {
- compatible = "qcom,sdm845-dpu";
- reg = <0x0ae01000 0x8f000>,
- <0x0aeb0000 0x2008>;
- reg-names = "mdp", "vbif";
-
- clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&dispcc DISP_CC_MDSS_AXI_CLK>,
- <&dispcc DISP_CC_MDSS_MDP_CLK>,
- <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
- clock-names = "iface", "bus", "core", "vsync";
-
- interrupt-parent = <&mdss>;
- interrupts = <0>;
- power-domains = <&rpmhpd SDM845_CX>;
- operating-points-v2 = <&mdp_opp_table>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
-
- port@1 {
- reg = <1>;
- dpu_intf2_out: endpoint {
- remote-endpoint = <&dsi1_in>;
- };
- };
- };
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
index 3b609c19e0bc..f2c143730a55 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
@@ -49,6 +49,7 @@ properties:
maxItems: 1
phy-names:
+ deprecated: true
const: dsi
"#address-cells": true
@@ -80,6 +81,9 @@ properties:
operating-points-v2: true
+ opp-table:
+ type: object
+
ports:
$ref: "/schemas/graph.yaml#/properties/ports"
description: |
@@ -131,7 +135,6 @@ required:
- clocks
- clock-names
- phys
- - phy-names
- assigned-clocks
- assigned-clock-parents
- power-domains
diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
index 1342d74ecfe0..819de5ce0bc9 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
@@ -16,6 +16,7 @@ properties:
compatible:
enum:
- qcom,dsi-phy-14nm
+ - qcom,dsi-phy-14nm-2290
- qcom,dsi-phy-14nm-660
- qcom,dsi-phy-14nm-8953
diff --git a/Documentation/devicetree/bindings/display/msm/mdp5.txt b/Documentation/devicetree/bindings/display/msm/mdp5.txt
index 43d11279c925..65d03c58dee6 100644
--- a/Documentation/devicetree/bindings/display/msm/mdp5.txt
+++ b/Documentation/devicetree/bindings/display/msm/mdp5.txt
@@ -2,37 +2,9 @@ Qualcomm adreno/snapdragon MDP5 display controller
Description:
-This is the bindings documentation for the Mobile Display Subsytem(MDSS) that
-encapsulates sub-blocks like MDP5, DSI, HDMI, eDP etc, and the MDP5 display
+This is the bindings documentation for the MDP5 display
controller found in SoCs like MSM8974, APQ8084, MSM8916, MSM8994 and MSM8996.
-MDSS:
-Required properties:
-- compatible:
- * "qcom,mdss" - MDSS
-- reg: Physical base address and length of the controller's registers.
-- reg-names: The names of register regions. The following regions are required:
- * "mdss_phys"
- * "vbif_phys"
-- interrupts: The interrupt signal from MDSS.
-- interrupt-controller: identifies the node as an interrupt controller.
-- #interrupt-cells: specifies the number of cells needed to encode an interrupt
- source, should be 1.
-- power-domains: a power domain consumer specifier according to
- Documentation/devicetree/bindings/power/power_domain.txt
-- clocks: device clocks. See ../clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required.
- * "iface"
- * "bus"
- * "vsync"
-- #address-cells: number of address cells for the MDSS children. Should be 1.
-- #size-cells: Should be 1.
-- ranges: parent bus address space is the same as the child bus address space.
-
-Optional properties:
-- clock-names: the following clocks are optional:
- * "lut"
-
MDP5:
Required properties:
- compatible:
diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
new file mode 100644
index 000000000000..27d7242657b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/mdss-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display MDSS common properties
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ - Rob Clark <robdclark@gmail.com>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc.
+
+properties:
+ reg:
+ maxItems: 1
+
+ reg-names:
+ const: mdss
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ minItems: 2
+ maxItems: 4
+
+ clock-names:
+ minItems: 2
+ maxItems: 4
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ "#address-cells": true
+
+ "#size-cells": true
+
+ "#interrupt-cells":
+ const: 1
+
+ iommus:
+ minItems: 1
+ items:
+ - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0
+ - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1
+
+ ranges: true
+
+ interconnects:
+ minItems: 1
+ items:
+ - description: Interconnect path from mdp0 (or a single mdp) port to the data bus
+ - description: Interconnect path from mdp1 port to the data bus
+
+ interconnect-names:
+ minItems: 1
+ items:
+ - const: mdp0-mem
+ - const: mdp1-mem
+
+ resets:
+ items:
+ - description: MDSS_CORE reset
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - power-domains
+ - clocks
+ - interrupts
+ - interrupt-controller
+ - iommus
+ - ranges
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml
new file mode 100644
index 000000000000..ba0460268731
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Mobile Display SubSystem (MDSS)
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ - Rob Clark <robdclark@gmail.com>
+
+description:
+ This is the bindings documentation for the Mobile Display Subsytem(MDSS) that
+ encapsulates sub-blocks like MDP5, DSI, HDMI, eDP, etc.
+
+properties:
+ compatible:
+ enum:
+ - qcom,mdss
+
+ reg:
+ minItems: 2
+ maxItems: 3
+
+ reg-names:
+ minItems: 2
+ items:
+ - const: mdss_phys
+ - const: vbif_phys
+ - const: vbif_nrt_phys
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ "#interrupt-cells":
+ const: 1
+
+ power-domains:
+ maxItems: 1
+ description: |
+ The MDSS power domain provided by GCC
+
+ clocks:
+ minItems: 1
+ items:
+ - description: Display abh clock
+ - description: Display axi clock
+ - description: Display vsync clock
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: iface
+ - const: bus
+ - const: vsync
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+ ranges: true
+
+ resets:
+ items:
+ - description: MDSS_CORE reset
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - interrupt-controller
+ - "#interrupt-cells"
+ - power-domains
+ - clocks
+ - clock-names
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+
+patternProperties:
+ "^mdp@[1-9a-f][0-9a-f]*$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdp5
+
+ "^dsi@[1-9a-f][0-9a-f]*$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^phy@[1-9a-f][0-9a-f]*$":
+ type: object
+ properties:
+ compatible:
+ enum:
+ - qcom,dsi-phy-14nm
+ - qcom,dsi-phy-14nm-660
+ - qcom,dsi-phy-14nm-8953
+ - qcom,dsi-phy-20nm
+ - qcom,dsi-phy-28nm-hpm
+ - qcom,dsi-phy-28nm-lp
+
+ "^hdmi-phy@[1-9a-f][0-9a-f]*$":
+ type: object
+ properties:
+ compatible:
+ enum:
+ - qcom,hdmi-phy-8084
+ - qcom,hdmi-phy-8660
+ - qcom,hdmi-phy-8960
+ - qcom,hdmi-phy-8974
+ - qcom,hdmi-phy-8996
+
+ "^hdmi-tx@[1-9a-f][0-9a-f]*$":
+ type: object
+ properties:
+ compatible:
+ enum:
+ - qcom,hdmi-tx-8084
+ - qcom,hdmi-tx-8660
+ - qcom,hdmi-tx-8960
+ - qcom,hdmi-tx-8974
+ - qcom,hdmi-tx-8994
+ - qcom,hdmi-tx-8996
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-msm8916.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ mdss@1a00000 {
+ compatible = "qcom,mdss";
+ reg = <0x1a00000 0x1000>,
+ <0x1ac8000 0x3000>;
+ reg-names = "mdss_phys", "vbif_phys";
+
+ power-domains = <&gcc MDSS_GDSC>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface",
+ "bus",
+ "vsync";
+
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mdp@1a01000 {
+ compatible = "qcom,mdp5";
+ reg = <0x01a01000 0x89000>;
+ reg-names = "mdp_phys";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface",
+ "bus",
+ "core",
+ "vsync";
+
+ iommus = <&apps_iommu 4>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mdp5_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml
new file mode 100644
index 000000000000..b02adba36e9e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,msm8998-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for MSM8998 target
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,msm8998-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for regdma register set
+ - description: Address offset and size for vbif register set
+ - description: Address offset and size for non-realtime vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: regdma
+ - const: vbif
+ - const: vbif_nrt
+
+ clocks:
+ items:
+ - description: Display ahb clock
+ - description: Display axi clock
+ - description: Display mem-noc clock
+ - description: Display core clock
+ - description: Display vsync clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: mnoc
+ - const: core
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,mmcc-msm8998.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@c901000 {
+ compatible = "qcom,msm8998-dpu";
+ reg = <0x0c901000 0x8f000>,
+ <0x0c9a8e00 0xf0>,
+ <0x0c9b0000 0x2008>,
+ <0x0c9b8000 0x1040>;
+ reg-names = "mdp", "regdma", "vbif", "vbif_nrt";
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MNOC_AHB_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MDSS_VSYNC_CLK>;
+ clock-names = "iface", "bus", "mnoc", "core", "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd MSM8998_VDDMX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml
new file mode 100644
index 000000000000..cf52ff77a41a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml
@@ -0,0 +1,268 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,msm8998-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm MSM8998 Display MDSS
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
+ bindings of MDSS are mentioned for MSM8998 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,msm8998-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock
+ - description: Display AXI clock
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: core
+
+ iommus:
+ maxItems: 1
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,msm8998-dpu
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-10nm-8998
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,mmcc-msm8998.h>
+ #include <dt-bindings/clock/qcom,rpmcc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-subsystem@c900000 {
+ compatible = "qcom,msm8998-mdss";
+ reg = <0x0c900000 0x1000>;
+ reg-names = "mdss";
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MDSS_MDP_CLK>;
+ clock-names = "iface", "bus", "core";
+
+ #address-cells = <1>;
+ #interrupt-cells = <1>;
+ #size-cells = <1>;
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ iommus = <&mmss_smmu 0>;
+
+ power-domains = <&mmcc MDSS_GDSC>;
+ ranges;
+
+ display-controller@c901000 {
+ compatible = "qcom,msm8998-dpu";
+ reg = <0x0c901000 0x8f000>,
+ <0x0c9a8e00 0xf0>,
+ <0x0c9b0000 0x2008>,
+ <0x0c9b8000 0x1040>;
+ reg-names = "mdp", "regdma", "vbif", "vbif_nrt";
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MNOC_AHB_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MDSS_VSYNC_CLK>;
+ clock-names = "iface", "bus", "mnoc", "core", "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd MSM8998_VDDMX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dpu_intf2_out: endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+
+ dsi@c994000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0c994000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&mmcc MDSS_BYTE0_CLK>,
+ <&mmcc MDSS_BYTE0_INTF_CLK>,
+ <&mmcc MDSS_PCLK0_CLK>,
+ <&mmcc MDSS_ESC0_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&mmcc BYTE0_CLK_SRC>, <&mmcc PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmpd MSM8998_VDDCX>;
+
+ phys = <&dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi0_phy: phy@c994400 {
+ compatible = "qcom,dsi-phy-10nm-8998";
+ reg = <0x0c994400 0x200>,
+ <0x0c994600 0x280>,
+ <0x0c994a00 0x1e0>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "ref";
+
+ vdds-supply = <&pm8998_l1>;
+ };
+
+ dsi@c996000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0c996000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <5>;
+
+ clocks = <&mmcc MDSS_BYTE1_CLK>,
+ <&mmcc MDSS_BYTE1_INTF_CLK>,
+ <&mmcc MDSS_PCLK1_CLK>,
+ <&mmcc MDSS_ESC1_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&mmcc BYTE1_CLK_SRC>, <&mmcc PCLK1_CLK_SRC>;
+ assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmpd MSM8998_VDDCX>;
+
+ phys = <&dsi1_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi1_in: endpoint {
+ remote-endpoint = <&dpu_intf2_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi1_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi1_phy: phy@c996400 {
+ compatible = "qcom,dsi-phy-10nm-8998";
+ reg = <0x0c996400 0x200>,
+ <0x0c996600 0x280>,
+ <0x0c996a00 0x10e>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "ref";
+
+ vdds-supply = <&pm8998_l1>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml
new file mode 100644
index 000000000000..a7b382f01b56
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for QCM2290 target
+
+maintainers:
+ - Loic Poulain <loic.poulain@linaro.org>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,qcm2290-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display AXI clock from gcc
+ - description: Display AHB clock from dispcc
+ - description: Display core clock from dispcc
+ - description: Display lut clock from dispcc
+ - description: Display vsync clock from dispcc
+
+ clock-names:
+ items:
+ - const: bus
+ - const: iface
+ - const: core
+ - const: lut
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
+ #include <dt-bindings/clock/qcom,gcc-qcm2290.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@5e01000 {
+ compatible = "qcom,qcm2290-dpu";
+ reg = <0x05e01000 0x8f000>,
+ <0x05eb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "core", "lut", "vsync";
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd QCM2290_VDDCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml
new file mode 100644
index 000000000000..d6f043a4b08d
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml
@@ -0,0 +1,198 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QCM220 Display MDSS
+
+maintainers:
+ - Loic Poulain <loic.poulain@linaro.org>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS
+ are mentioned for QCM2290 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,qcm2290-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display AXI clock
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: core
+
+ iommus:
+ maxItems: 2
+
+ interconnects:
+ maxItems: 1
+
+ interconnect-names:
+ maxItems: 1
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,qcm2290-dpu
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-ctrl-6g-qcm2290
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-14nm-2290
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
+ #include <dt-bindings/clock/qcom,gcc-qcm2290.h>
+ #include <dt-bindings/clock/qcom,rpmcc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interconnect/qcom,qcm2290.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ mdss@5e00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qcm2290-mdss";
+ reg = <0x05e00000 0x1000>;
+ reg-names = "mdss";
+ power-domains = <&dispcc MDSS_GDSC>;
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface", "bus", "core";
+
+ interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>;
+ interconnect-names = "mdp0-mem";
+
+ iommus = <&apps_smmu 0x420 0x2>,
+ <&apps_smmu 0x421 0x0>;
+ ranges;
+
+ display-controller@5e01000 {
+ compatible = "qcom,qcm2290-dpu";
+ reg = <0x05e01000 0x8f000>,
+ <0x05eb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "core", "lut", "vsync";
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd QCM2290_VDDCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+
+ dsi@5e94000 {
+ compatible = "qcom,dsi-ctrl-6g-qcm2290";
+ reg = <0x05e94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmpd QCM2290_VDDCX>;
+
+ phys = <&dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi0_phy: phy@5e94400 {
+ compatible = "qcom,dsi-phy-14nm-2290";
+ reg = <0x05e94400 0x100>,
+ <0x05e94500 0x300>,
+ <0x05e94800 0x188>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "ref";
+ vcca-supply = <&vreg_dsi_phy>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml
new file mode 100644
index 000000000000..bd590a6b5b96
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sc7180-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for SC7180 target
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sc7180-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display hf axi clock
+ - description: Display ahb clock
+ - description: Display rotator clock
+ - description: Display lut clock
+ - description: Display core clock
+ - description: Display vsync clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: iface
+ - const: rot
+ - const: lut
+ - const: core
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sc7180.h>
+ #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@ae01000 {
+ compatible = "qcom,sc7180-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "rot", "lut", "core",
+ "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SC7180_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ endpoint {
+ remote-endpoint = <&dp_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml
new file mode 100644
index 000000000000..13e396d61a51
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml
@@ -0,0 +1,304 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sc7180-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7180 Display MDSS
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
+ bindings of MDSS are mentioned for SC7180 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sc7180-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display AHB clock from dispcc
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: ahb
+ - const: core
+
+ iommus:
+ maxItems: 1
+
+ interconnects:
+ maxItems: 1
+
+ interconnect-names:
+ maxItems: 1
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sc7180-dpu
+
+ "^displayport-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sc7180-dp
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-10nm
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sc7180.h>
+ #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interconnect/qcom,sdm845.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-subsystem@ae00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,sc7180-mdss";
+ reg = <0xae00000 0x1000>;
+ reg-names = "mdss";
+ power-domains = <&dispcc MDSS_GDSC>;
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface", "ahb", "core";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>;
+ interconnect-names = "mdp0-mem";
+
+ iommus = <&apps_smmu 0x800 0x2>;
+ ranges;
+
+ display-controller@ae01000 {
+ compatible = "qcom,sc7180-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "rot", "lut", "core",
+ "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SC7180_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ dpu_intf0_out: endpoint {
+ remote-endpoint = <&dp_in>;
+ };
+ };
+ };
+ };
+
+ dsi@ae94000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi_phy 0>, <&dsi_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SC7180_CX>;
+
+ phys = <&dsi_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+
+ dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-358000000 {
+ opp-hz = /bits/ 64 <358000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
+ dsi_phy: phy@ae94400 {
+ compatible = "qcom,dsi-phy-10nm";
+ reg = <0x0ae94400 0x200>,
+ <0x0ae94600 0x280>,
+ <0x0ae94a00 0x1e0>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+ vdds-supply = <&vreg_dsi_phy>;
+ };
+
+ displayport-controller@ae90000 {
+ compatible = "qcom,sc7180-dp";
+
+ reg = <0xae90000 0x200>,
+ <0xae90200 0x200>,
+ <0xae90400 0xc00>,
+ <0xae91000 0x400>,
+ <0xae91400 0x400>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <12>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>;
+ clock-names = "core_iface", "core_aux", "ctrl_link",
+ "ctrl_link_iface", "stream_pixel";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+ assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>;
+ phys = <&dp_phy>;
+ phy-names = "dp";
+
+ operating-points-v2 = <&dp_opp_table>;
+ power-domains = <&rpmhpd SC7180_CX>;
+
+ #sound-dai-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ dp_in: endpoint {
+ remote-endpoint = <&dpu_intf0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dp_out: endpoint { };
+ };
+ };
+
+ dp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-270000000 {
+ opp-hz = /bits/ 64 <270000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-540000000 {
+ opp-hz = /bits/ 64 <540000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml
new file mode 100644
index 000000000000..924059b387b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sc7280-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for SC7280
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sc7280-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display hf axi clock
+ - description: Display sf axi clock
+ - description: Display ahb clock
+ - description: Display lut clock
+ - description: Display core clock
+ - description: Display vsync clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: nrt_bus
+ - const: iface
+ - const: lut
+ - const: core
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sc7280.h>
+ #include <dt-bindings/clock/qcom,gcc-sc7280.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@ae01000 {
+ compatible = "qcom,sc7280-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&gcc GCC_DISP_SF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus",
+ "nrt_bus",
+ "iface",
+ "lut",
+ "core",
+ "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SC7280_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&edp_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml
new file mode 100644
index 000000000000..a3de1744ba11
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml
@@ -0,0 +1,422 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sc7280-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7280 Display MDSS
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem (MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
+ bindings of MDSS are mentioned for SC7280.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sc7280-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display AHB clock from dispcc
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: ahb
+ - const: core
+
+ iommus:
+ maxItems: 1
+
+ interconnects:
+ maxItems: 1
+
+ interconnect-names:
+ maxItems: 1
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sc7280-dpu
+
+ "^displayport-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sc7280-dp
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^edp@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sc7280-edp
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ enum:
+ - qcom,sc7280-dsi-phy-7nm
+ - qcom,sc7280-edp-phy
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sc7280.h>
+ #include <dt-bindings/clock/qcom,gcc-sc7280.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interconnect/qcom,sc7280.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-subsystem@ae00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,sc7280-mdss";
+ reg = <0xae00000 0x1000>;
+ reg-names = "mdss";
+ power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface",
+ "ahb",
+ "core";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>;
+ interconnect-names = "mdp0-mem";
+
+ iommus = <&apps_smmu 0x900 0x402>;
+ ranges;
+
+ display-controller@ae01000 {
+ compatible = "qcom,sc7280-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&gcc GCC_DISP_SF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus",
+ "nrt_bus",
+ "iface",
+ "lut",
+ "core",
+ "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SC7280_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dpu_intf5_out: endpoint {
+ remote-endpoint = <&edp_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ dpu_intf0_out: endpoint {
+ remote-endpoint = <&dp_in>;
+ };
+ };
+ };
+ };
+
+ dsi@ae94000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&mdss_dsi_phy 0>, <&mdss_dsi_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SC7280_CX>;
+
+ phys = <&mdss_dsi_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+
+ dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-358000000 {
+ opp-hz = /bits/ 64 <358000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
+ mdss_dsi_phy: phy@ae94400 {
+ compatible = "qcom,sc7280-dsi-phy-7nm";
+ reg = <0x0ae94400 0x200>,
+ <0x0ae94600 0x280>,
+ <0x0ae94900 0x280>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+
+ vdds-supply = <&vreg_dsi_supply>;
+ };
+
+ edp@aea0000 {
+ compatible = "qcom,sc7280-edp";
+ pinctrl-names = "default";
+ pinctrl-0 = <&edp_hot_plug_det>;
+
+ reg = <0xaea0000 0x200>,
+ <0xaea0200 0x200>,
+ <0xaea0400 0xc00>,
+ <0xaea1000 0x400>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <14>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_EDP_AUX_CLK>,
+ <&dispcc DISP_CC_MDSS_EDP_LINK_CLK>,
+ <&dispcc DISP_CC_MDSS_EDP_LINK_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK>;
+ clock-names = "core_iface",
+ "core_aux",
+ "ctrl_link",
+ "ctrl_link_iface",
+ "stream_pixel";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_EDP_LINK_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK_SRC>;
+ assigned-clock-parents = <&mdss_edp_phy 0>, <&mdss_edp_phy 1>;
+
+ phys = <&mdss_edp_phy>;
+ phy-names = "dp";
+
+ operating-points-v2 = <&edp_opp_table>;
+ power-domains = <&rpmhpd SC7280_CX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ edp_in: endpoint {
+ remote-endpoint = <&dpu_intf5_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ mdss_edp_out: endpoint { };
+ };
+ };
+
+ edp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-270000000 {
+ opp-hz = /bits/ 64 <270000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-540000000 {
+ opp-hz = /bits/ 64 <540000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
+ };
+
+ mdss_edp_phy: phy@aec2a00 {
+ compatible = "qcom,sc7280-edp-phy";
+
+ reg = <0xaec2a00 0x19c>,
+ <0xaec2200 0xa0>,
+ <0xaec2600 0xa0>,
+ <0xaec2000 0x1c0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_EDP_CLKREF_EN>;
+ clock-names = "aux",
+ "cfg_ahb";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+ };
+
+ displayport-controller@ae90000 {
+ compatible = "qcom,sc7280-dp";
+
+ reg = <0xae90000 0x200>,
+ <0xae90200 0x200>,
+ <0xae90400 0xc00>,
+ <0xae91000 0x400>,
+ <0xae91400 0x400>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <12>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>;
+ clock-names = "core_iface",
+ "core_aux",
+ "ctrl_link",
+ "ctrl_link_iface",
+ "stream_pixel";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+ assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>;
+ phys = <&dp_phy>;
+ phy-names = "dp";
+
+ operating-points-v2 = <&dp_opp_table>;
+ power-domains = <&rpmhpd SC7280_CX>;
+
+ #sound-dai-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dp_in: endpoint {
+ remote-endpoint = <&dpu_intf0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dp_out: endpoint { };
+ };
+ };
+
+ dp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-270000000 {
+ opp-hz = /bits/ 64 <270000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-540000000 {
+ opp-hz = /bits/ 64 <540000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml
new file mode 100644
index 000000000000..5719b45f2860
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sdm845-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for SDM845 target
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sdm845-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display GCC bus clock
+ - description: Display ahb clock
+ - description: Display axi clock
+ - description: Display core clock
+ - description: Display vsync clock
+
+ clock-names:
+ items:
+ - const: gcc-bus
+ - const: iface
+ - const: bus
+ - const: core
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+ #include <dt-bindings/clock/qcom,gcc-sdm845.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@ae01000 {
+ compatible = "qcom,sdm845-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "gcc-bus", "iface", "bus", "core", "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SDM845_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml
new file mode 100644
index 000000000000..31ca6f99fc22
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml
@@ -0,0 +1,270 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sdm845-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SDM845 Display MDSS
+
+maintainers:
+ - Krishna Manikandan <quic_mkrishn@quicinc.com>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
+ bindings of MDSS are mentioned for SDM845 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sdm845-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: core
+
+ iommus:
+ maxItems: 2
+
+ interconnects:
+ maxItems: 2
+
+ interconnect-names:
+ maxItems: 2
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sdm845-dpu
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-10nm
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+ #include <dt-bindings/clock/qcom,gcc-sdm845.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-subsystem@ae00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,sdm845-mdss";
+ reg = <0x0ae00000 0x1000>;
+ reg-names = "mdss";
+ power-domains = <&dispcc MDSS_GDSC>;
+
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface", "core";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ iommus = <&apps_smmu 0x880 0x8>,
+ <&apps_smmu 0xc80 0x8>;
+ ranges;
+
+ display-controller@ae01000 {
+ compatible = "qcom,sdm845-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "gcc-bus", "iface", "bus", "core", "vsync";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+ power-domains = <&rpmhpd SDM845_CX>;
+ operating-points-v2 = <&mdp_opp_table>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dpu_intf2_out: endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+
+ dsi@ae94000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SDM845_CX>;
+
+ phys = <&dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi0_phy: phy@ae94400 {
+ compatible = "qcom,dsi-phy-10nm";
+ reg = <0x0ae94400 0x200>,
+ <0x0ae94600 0x280>,
+ <0x0ae94a00 0x1e0>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+ vdds-supply = <&vreg_dsi_phy>;
+ };
+
+ dsi@ae96000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae96000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <5>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK1_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC1_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>;
+ assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SDM845_CX>;
+
+ phys = <&dsi1_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi1_in: endpoint {
+ remote-endpoint = <&dpu_intf2_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi1_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi1_phy: phy@ae96400 {
+ compatible = "qcom,dsi-phy-10nm";
+ reg = <0x0ae96400 0x200>,
+ <0x0ae96600 0x280>,
+ <0x0ae96a00 0x10e>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+ vdds-supply = <&vreg_dsi_phy>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-dpu.yaml
new file mode 100644
index 000000000000..4a39a3031409
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-dpu.yaml
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sm6115-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Display DPU dt properties for SM6115 target
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sm6115-dpu
+
+ reg:
+ items:
+ - description: MDP register set
+ - description: VBIF register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display AXI
+ - description: Display AHB
+ - description: Display core
+ - description: Display lut
+ - description: Display rotator
+ - description: Display vsync
+
+ clock-names:
+ items:
+ - const: bus
+ - const: iface
+ - const: core
+ - const: lut
+ - const: rot
+ - const: vsync
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,sm6115-dispcc.h>
+ #include <dt-bindings/clock/qcom,gcc-sm6115.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@5e01000 {
+ compatible = "qcom,sm6115-dpu";
+ reg = <0x05e01000 0x8f000>,
+ <0x05eb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "core", "lut", "rot", "vsync";
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd SM6115_VDDCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml
new file mode 100644
index 000000000000..a86d7f53fa84
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml
@@ -0,0 +1,182 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sm6115-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SM6115 Display MDSS
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS
+ are mentioned for SM6115 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sm6115-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display AXI clock
+ - description: Display core clock
+
+ iommus:
+ maxItems: 2
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sm6115-dpu
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-ctrl-6g-qcm2290
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-14nm-2290
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,sm6115-dispcc.h>
+ #include <dt-bindings/clock/qcom,gcc-sm6115.h>
+ #include <dt-bindings/clock/qcom,rpmcc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ mdss@5e00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,sm6115-mdss";
+ reg = <0x05e00000 0x1000>;
+ reg-names = "mdss";
+ power-domains = <&dispcc MDSS_GDSC>;
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+
+ interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ iommus = <&apps_smmu 0x420 0x2>,
+ <&apps_smmu 0x421 0x0>;
+ ranges;
+
+ display-controller@5e01000 {
+ compatible = "qcom,sm6115-dpu";
+ reg = <0x05e01000 0x8f000>,
+ <0x05eb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus", "iface", "core", "lut", "rot", "vsync";
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd SM6115_VDDCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+
+ dsi@5e94000 {
+ compatible = "qcom,dsi-ctrl-6g-qcm2290";
+ reg = <0x05e94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmpd SM6115_VDDCX>;
+ phys = <&dsi0_phy>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi0_phy: phy@5e94400 {
+ compatible = "qcom,dsi-phy-14nm-2290";
+ reg = <0x05e94400 0x100>,
+ <0x05e94500 0x300>,
+ <0x05e94800 0x188>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "ref";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml
new file mode 100644
index 000000000000..9ff8a265c85f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sm8250-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SM8250 Display DPU
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+$ref: /schemas/display/msm/dpu-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sm8250-dpu
+
+ reg:
+ items:
+ - description: Address offset and size for mdp register set
+ - description: Address offset and size for vbif register set
+
+ reg-names:
+ items:
+ - const: mdp
+ - const: vbif
+
+ clocks:
+ items:
+ - description: Display ahb clock
+ - description: Display hf axi clock
+ - description: Display core clock
+ - description: Display vsync clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: core
+ - const: vsync
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sm8250.h>
+ #include <dt-bindings/clock/qcom,gcc-sm8250.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interconnect/qcom,sm8250.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-controller@ae01000 {
+ compatible = "qcom,sm8250-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "iface", "bus", "core", "vsync";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmhpd SM8250_MMCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml
new file mode 100644
index 000000000000..0d3be5386b3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml
@@ -0,0 +1,330 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,sm8250-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SM8250 Display MDSS
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+description:
+ Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
+ sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree
+ bindings of MDSS are mentioned for SM8250 target.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: qcom,sm8250-mdss
+
+ clocks:
+ items:
+ - description: Display AHB clock from gcc
+ - description: Display hf axi clock
+ - description: Display sf axi clock
+ - description: Display core clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: nrt_bus
+ - const: core
+
+ iommus:
+ maxItems: 1
+
+ interconnects:
+ maxItems: 2
+
+ interconnect-names:
+ maxItems: 2
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,sm8250-dpu
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,mdss-dsi-ctrl
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: qcom,dsi-phy-7nm
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,dispcc-sm8250.h>
+ #include <dt-bindings/clock/qcom,gcc-sm8250.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interconnect/qcom,sm8250.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ display-subsystem@ae00000 {
+ compatible = "qcom,sm8250-mdss";
+ reg = <0x0ae00000 0x1000>;
+ reg-names = "mdss";
+
+ interconnects = <&mmss_noc MASTER_MDP_PORT0 &mc_virt SLAVE_EBI_CH0>,
+ <&mmss_noc MASTER_MDP_PORT1 &mc_virt SLAVE_EBI_CH0>;
+ interconnect-names = "mdp0-mem", "mdp1-mem";
+
+ power-domains = <&dispcc MDSS_GDSC>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&gcc GCC_DISP_SF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface", "bus", "nrt_bus", "core";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ iommus = <&apps_smmu 0x820 0x402>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ display-controller@ae01000 {
+ compatible = "qcom,sm8250-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "iface", "bus", "core", "vsync";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmhpd SM8250_MMCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dpu_intf2_out: endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+
+ mdp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-345000000 {
+ opp-hz = /bits/ 64 <345000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-460000000 {
+ opp-hz = /bits/ 64 <460000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
+ };
+
+ dsi@ae94000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SM8250_MMCX>;
+
+ phys = <&dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+
+ dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-358000000 {
+ opp-hz = /bits/ 64 <358000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
+ dsi0_phy: phy@ae94400 {
+ compatible = "qcom,dsi-phy-7nm";
+ reg = <0x0ae94400 0x200>,
+ <0x0ae94600 0x280>,
+ <0x0ae94900 0x260>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+ vdds-supply = <&vreg_dsi_phy>;
+ };
+
+ dsi@ae96000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae96000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <5>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK1_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC1_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>;
+ assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmhpd SM8250_MMCX>;
+
+ phys = <&dsi1_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi1_in: endpoint {
+ remote-endpoint = <&dpu_intf2_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi1_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi1_phy: phy@ae96400 {
+ compatible = "qcom,dsi-phy-7nm";
+ reg = <0x0ae96400 0x200>,
+ <0x0ae96600 0x280>,
+ <0x0ae96900 0x260>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "ref";
+ vdds-supply = <&vreg_dsi_phy>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml b/Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
new file mode 100644
index 000000000000..c06902e4fe70
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/jadard,jd9365da-h3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Jadard JD9365DA-HE WXGA DSI panel
+
+maintainers:
+ - Jagan Teki <jagan@edgeble.ai>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - chongzhou,cz101b4001
+ - const: jadard,jd9365da-h3
+
+ reg: true
+
+ vdd-supply:
+ description: supply regulator for VDD, usually 3.3V
+
+ vccio-supply:
+ description: supply regulator for VCCIO, usually 1.8V
+
+ reset-gpios: true
+
+ backlight: true
+
+ port: true
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vccio-supply
+ - reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/pinctrl/rockchip.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "chongzhou,cz101b4001", "jadard,jd9365da-h3";
+ reg = <0>;
+ vdd-supply = <&lcd_3v3>;
+ vccio-supply = <&vcca_1v8>;
+ reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>;
+ backlight = <&backlight>;
+
+ port {
+ mipi_in_panel: endpoint {
+ remote-endpoint = <&mipi_out_panel>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml
new file mode 100644
index 000000000000..116c1b6030a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/newvision,nv3051d.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NewVision NV3051D based LCD panel
+
+description: |
+ The NewVision NV3051D is a driver chip used to drive DSI panels. For now,
+ this driver only supports the 640x480 panels found in the Anbernic RG353
+ based devices.
+
+maintainers:
+ - Chris Morgan <macromorgan@hotmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - anbernic,rg353p-panel
+ - anbernic,rg353v-panel
+ - const: newvision,nv3051d
+
+ reg: true
+ backlight: true
+ port: true
+ reset-gpios:
+ description: Active low reset GPIO
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+ - backlight
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ panel@0 {
+ compatible = "anbernic,rg353p-panel", "newvision,nv3051d";
+ reg = <0>;
+ backlight = <&backlight>;
+ reset-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
+ vdd-supply = <&vcc3v3_lcd>;
+
+ port {
+ mipi_in_panel: endpoint {
+ remote-endpoint = <&mipi_out_panel>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml b/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml
index 10ec78ca1c65..554f9d5809d4 100644
--- a/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml
+++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml
@@ -117,6 +117,45 @@ properties:
- const: dp-phy0
- const: dp-phy1
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ description: |
+ Connections to the programmable logic and the DisplayPort PHYs. Each port
+ shall have a single endpoint.
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The live video input from the programmable logic
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The live graphics input from the programmable logic
+
+ port@2:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The live audio input from the programmable logic
+
+ port@3:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The blended video output to the programmable logic
+
+ port@4:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The mixed audio output to the programmable logic
+
+ port@5:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: The DisplayPort output
+
+ required:
+ - port@0
+ - port@1
+ - port@2
+ - port@3
+ - port@4
+ - port@5
+
required:
- compatible
- reg
@@ -130,6 +169,7 @@ required:
- dma-names
- phys
- phy-names
+ - ports
additionalProperties: false
@@ -164,6 +204,33 @@ examples:
<&psgtr 0 PHY_TYPE_DP 1 3>;
phy-names = "dp-phy0", "dp-phy1";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+ port@1 {
+ reg = <1>;
+ };
+ port@2 {
+ reg = <2>;
+ };
+ port@3 {
+ reg = <3>;
+ };
+ port@4 {
+ reg = <4>;
+ };
+ port@5 {
+ reg = <5>;
+ dpsub_dp_out: endpoint {
+ remote-endpoint = <&dp_connector>;
+ };
+ };
+ };
};
...
diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml
index 3b1e667f7ea0..97282469e4af 100644
--- a/Documentation/devicetree/bindings/dma/apple,admac.yaml
+++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml
@@ -56,6 +56,9 @@ properties:
power-domains:
maxItems: 1
+ resets:
+ maxItems: 1
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.yaml b/Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.yaml
index 2d82b44268db..2e5b39881449 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.yaml
+++ b/Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.yaml
@@ -40,6 +40,7 @@ examples:
cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
+ interrupts = <44 0>;
usbc_extcon0: extcon0 {
compatible = "google,extcon-usbc-cros-ec";
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
index c5b76c9f7ad0..25688571ee7c 100644
--- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
+++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
@@ -41,12 +41,14 @@ properties:
- qcom,scm-sc7180
- qcom,scm-sc7280
- qcom,scm-sc8280xp
+ - qcom,scm-sdm670
- qcom,scm-sdm845
- qcom,scm-sdx55
- qcom,scm-sdx65
- qcom,scm-sm6115
- qcom,scm-sm6125
- qcom,scm-sm6350
+ - qcom,scm-sm6375
- qcom,scm-sm8150
- qcom,scm-sm8250
- qcom,scm-sm8350
@@ -88,6 +90,7 @@ allOf:
- qcom,scm-apq8064
- qcom,scm-msm8660
- qcom,scm-msm8960
+ - qcom,scm-sm6375
then:
properties:
clock-names:
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.yaml
new file mode 100644
index 000000000000..7cc2dd525a96
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.yaml
@@ -0,0 +1,156 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra234-nvdec.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Device tree binding for NVIDIA Tegra234 NVDEC
+
+description: |
+ NVDEC is the hardware video decoder present on NVIDIA Tegra210
+ and newer chips. It is located on the Host1x bus and typically
+ programmed through Host1x channels.
+
+maintainers:
+ - Thierry Reding <treding@gmail.com>
+ - Mikko Perttunen <mperttunen@nvidia.com>
+
+properties:
+ $nodename:
+ pattern: "^nvdec@[0-9a-f]*$"
+
+ compatible:
+ enum:
+ - nvidia,tegra234-nvdec
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 3
+
+ clock-names:
+ items:
+ - const: nvdec
+ - const: fuse
+ - const: tsec_pka
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ items:
+ - const: nvdec
+
+ power-domains:
+ maxItems: 1
+
+ iommus:
+ maxItems: 1
+
+ dma-coherent: true
+
+ interconnects:
+ items:
+ - description: DMA read memory client
+ - description: DMA write memory client
+
+ interconnect-names:
+ items:
+ - const: dma-mem
+ - const: write
+
+ nvidia,memory-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ phandle to the memory controller for determining information for the NVDEC
+ firmware secure carveout. This carveout is configured by the bootloader and
+ not accessible to CPU.
+
+ nvidia,bl-manifest-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to bootloader manifest from beginning of firmware that was configured by
+ the bootloader.
+
+ nvidia,bl-code-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to bootloader code section from beginning of firmware that was configured by
+ the bootloader.
+
+ nvidia,bl-data-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to bootloader data section from beginning of firmware that was configured by
+ the bootloader.
+
+ nvidia,os-manifest-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to operating system manifest from beginning of firmware that was configured by
+ the bootloader.
+
+ nvidia,os-code-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to operating system code section from beginning of firmware that was configured by
+ the bootloader.
+
+ nvidia,os-data-offset:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Offset to operating system data section from beginning of firmware that was configured
+ by the bootloader.
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+ - nvidia,memory-controller
+ - nvidia,bl-manifest-offset
+ - nvidia,bl-code-offset
+ - nvidia,bl-data-offset
+ - nvidia,os-manifest-offset
+ - nvidia,os-code-offset
+ - nvidia,os-data-offset
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra234-clock.h>
+ #include <dt-bindings/memory/tegra234-mc.h>
+ #include <dt-bindings/power/tegra234-powergate.h>
+ #include <dt-bindings/reset/tegra234-reset.h>
+
+ nvdec@15480000 {
+ compatible = "nvidia,tegra234-nvdec";
+ reg = <0x15480000 0x00040000>;
+ clocks = <&bpmp TEGRA234_CLK_NVDEC>,
+ <&bpmp TEGRA234_CLK_FUSE>,
+ <&bpmp TEGRA234_CLK_TSEC_PKA>;
+ clock-names = "nvdec", "fuse", "tsec_pka";
+ resets = <&bpmp TEGRA234_RESET_NVDEC>;
+ reset-names = "nvdec";
+ power-domains = <&bpmp TEGRA234_POWER_DOMAIN_NVDEC>;
+ interconnects = <&mc TEGRA234_MEMORY_CLIENT_NVDECSRD &emc>,
+ <&mc TEGRA234_MEMORY_CLIENT_NVDECSWR &emc>;
+ interconnect-names = "dma-mem", "write";
+ iommus = <&smmu_niso1 TEGRA234_SID_NVDEC>;
+ dma-coherent;
+
+ nvidia,memory-controller = <&mc>;
+
+ /* Placeholder values, to be replaced with values from overlay */
+ nvidia,bl-manifest-offset = <0>;
+ nvidia,bl-data-offset = <0>;
+ nvidia,bl-code-offset = <0>;
+ nvidia,os-manifest-offset = <0>;
+ nvidia,os-data-offset = <0>;
+ nvidia,os-code-offset = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
new file mode 100644
index 000000000000..9d0c36ec1982
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwinfo/loongson,ls2k-chipid.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Loongson-2 SoC ChipID
+
+maintainers:
+ - Yinbo Zhu <zhuyinbo@loongson.cn>
+
+description: |
+ Loongson-2 SoC contains many groups of global utilities register
+ blocks, of which the ChipID group registers record SoC version,
+ feature, vendor and id information.
+
+properties:
+ compatible:
+ const: loongson,ls2k-chipid
+
+ reg:
+ maxItems: 1
+
+ little-endian: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ chipid: chipid@1fe00000 {
+ compatible = "loongson,ls2k-chipid";
+ reg = <0x1fe00000 0x3ffc>;
+ little-endian;
+ };
diff --git a/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
index 1c7149f7d171..ee2726149cf3 100644
--- a/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
+++ b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
@@ -15,9 +15,22 @@ description:
properties:
compatible:
- enum:
- - qcom,sfpb-mutex
- - qcom,tcsr-mutex
+ oneOf:
+ - enum:
+ - qcom,sfpb-mutex
+ - qcom,tcsr-mutex
+ - items:
+ - enum:
+ - qcom,apq8084-tcsr-mutex
+ - qcom,ipq6018-tcsr-mutex
+ - qcom,msm8226-tcsr-mutex
+ - qcom,msm8994-tcsr-mutex
+ - const: qcom,tcsr-mutex
+ - items:
+ - enum:
+ - qcom,msm8974-tcsr-mutex
+ - const: qcom,tcsr-mutex
+ - const: syscon
reg:
maxItems: 1
@@ -34,9 +47,9 @@ additionalProperties: false
examples:
- |
- tcsr_mutex: hwlock@1f40000 {
- compatible = "qcom,tcsr-mutex";
- reg = <0x01f40000 0x40000>;
- #hwlock-cells = <1>;
- };
+ hwlock@1f40000 {
+ compatible = "qcom,tcsr-mutex";
+ reg = <0x01f40000 0x40000>;
+ #hwlock-cells = <1>;
+ };
...
diff --git a/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml b/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml
index 6e1c70e9275e..cf523615f5e3 100644
--- a/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml
+++ b/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml
@@ -47,6 +47,7 @@ examples:
compatible = "google,cros-ec-spi";
reg = <0>;
spi-max-frequency = <5000000>;
+ interrupts = <99 0>;
i2c-tunnel {
compatible = "google,cros-ec-i2c-tunnel";
diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
index b283c8ca2bbf..5c08d8b6e995 100644
--- a/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
@@ -62,13 +62,6 @@ properties:
description:
Inform the driver that last channel will be used to sensor battery.
- aspeed,trim-data-valid:
- type: boolean
- description: |
- The ADC reference voltage can be calibrated to obtain the trimming
- data which will be stored in otp. This property informs the driver that
- the data store in the otp is valid.
-
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
index 8bac0c4120dd..e94beb2255ba 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
@@ -238,42 +238,72 @@ additionalProperties: false
examples:
- |
- spmi_bus {
- #address-cells = <1>;
- #size-cells = <0>;
- /* VADC node */
- pmic_vadc: adc@3100 {
- compatible = "qcom,spmi-vadc";
- reg = <0x3100>;
- interrupts = <0x0 0x31 0x0 0x1>;
+ spmi {
#address-cells = <1>;
#size-cells = <0>;
- #io-channel-cells = <1>;
-
- /* Channel node */
- adc-chan@39 {
- reg = <0x39>;
- qcom,decimation = <512>;
- qcom,ratiometric;
- qcom,hw-settle-time = <200>;
- qcom,avg-samples = <1>;
- qcom,pre-scaling = <1 3>;
- };
-
- adc-chan@9 {
- reg = <0x9>;
- };
-
- adc-chan@a {
- reg = <0xa>;
+ /* VADC node */
+ pmic_vadc: adc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100>;
+ interrupts = <0x0 0x31 0x0 0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ /* Channel node */
+ adc-chan@39 {
+ reg = <0x39>;
+ qcom,decimation = <512>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,avg-samples = <1>;
+ qcom,pre-scaling = <1 3>;
+ };
+
+ adc-chan@9 {
+ reg = <0x9>;
+ };
+
+ adc-chan@a {
+ reg = <0xa>;
+ };
+
+ adc-chan@e {
+ reg = <0xe>;
+ };
+
+ adc-chan@f {
+ reg = <0xf>;
+ };
};
+ };
- adc-chan@e {
- reg = <0xe>;
- };
+ - |
+ #include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
+ #include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
- adc-chan@f {
- reg = <0xf>;
+ spmi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ adc@3100 {
+ reg = <0x3100>;
+ compatible = "qcom,spmi-adc7";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ /* Other properties are omitted */
+ xo-therm@44 {
+ reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+
+ conn-therm@47 {
+ reg = <PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
};
- };
};
diff --git a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml
index fe1c5016f7f3..1c191bc5a178 100644
--- a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml
+++ b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml
@@ -16,8 +16,11 @@ description:
properties:
compatible:
- items:
+ oneOf:
- const: goodix,gt7375p
+ - items:
+ - const: goodix,gt7986u
+ - const: goodix,gt7375p
reg:
enum:
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
index 2684562df4d9..be29e0b80995 100644
--- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
+++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
@@ -24,7 +24,7 @@ properties:
oneOf:
- items:
- enum:
- - qcom,sc7280-bwmon
+ - qcom,sc7280-cpu-bwmon
- qcom,sdm845-bwmon
- const: qcom,msm8998-bwmon
- const: qcom,msm8998-bwmon # BWMON v4
diff --git a/Documentation/devicetree/bindings/interrupt-controller/apple,aic2.yaml b/Documentation/devicetree/bindings/interrupt-controller/apple,aic2.yaml
index 47a78a167aba..06948c0e36a5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/apple,aic2.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/apple,aic2.yaml
@@ -69,6 +69,35 @@ properties:
power-domains:
maxItems: 1
+ affinities:
+ type: object
+ additionalProperties: false
+ description:
+ FIQ affinity can be expressed as a single "affinities" node,
+ containing a set of sub-nodes, one per FIQ with a non-default
+ affinity.
+ patternProperties:
+ "^.+-affinity$":
+ type: object
+ additionalProperties: false
+ properties:
+ apple,fiq-index:
+ description:
+ The interrupt number specified as a FIQ, and for which
+ the affinity is not the default.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ maximum: 5
+
+ cpus:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ Should be a list of phandles to CPU nodes (as described in
+ Documentation/devicetree/bindings/arm/cpus.yaml).
+
+ required:
+ - apple,fiq-index
+ - cpus
+
required:
- compatible
- '#interrupt-cells'
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt
deleted file mode 100644
index 7d19f494f19a..000000000000
--- a/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Interrupt chips
----------------
-
-* Intel I/O Advanced Programmable Interrupt Controller (IO APIC)
-
- Required properties:
- --------------------
- compatible = "intel,ce4100-ioapic";
- #interrupt-cells = <2>;
-
- Device's interrupt property:
-
- interrupts = <P S>;
-
- The first number (P) represents the interrupt pin which is wired to the
- IO APIC. The second number (S) represents the sense of interrupt which
- should be configured and can be one of:
- 0 - Edge Rising
- 1 - Level Low
- 2 - Level High
- 3 - Edge Falling
-
-* Local APIC
- Required property:
-
- compatible = "intel,ce4100-lapic";
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.yaml b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.yaml
new file mode 100644
index 000000000000..39ab8cdd19b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/interrupt-controller/intel,ce4100-ioapic.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel I/O Advanced Programmable Interrupt Controller (IO APIC)
+
+maintainers:
+ - Rahul Tanwar <rtanwar@maxlinear.com>
+
+description: |
+ Intel's Advanced Programmable Interrupt Controller (APIC) is a
+ family of interrupt controllers. The APIC is a split
+ architecture design, with a local component (LAPIC) integrated
+ into the processor itself and an external I/O APIC. Local APIC
+ (lapic) receives interrupts from the processor's interrupt pins,
+ from internal sources and from an external I/O APIC (ioapic).
+ And it sends these to the processor core for handling.
+ See [1] Chapter 8 for more details.
+
+ Many of the Intel's generic devices like hpet, ioapic, lapic have
+ the ce4100 name in their compatible property names because they
+ first appeared in CE4100 SoC.
+
+ This schema defines bindings for I/O APIC interrupt controller.
+
+ [1] https://pdos.csail.mit.edu/6.828/2008/readings/ia32/IA32-3A.pdf
+
+properties:
+ compatible:
+ const: intel,ce4100-ioapic
+
+ reg:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupt-controller
+ - '#interrupt-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ ioapic1: interrupt-controller@fec00000 {
+ compatible = "intel,ce4100-ioapic";
+ reg = <0xfec00000 0x1000>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-lapic.yaml b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-lapic.yaml
new file mode 100644
index 000000000000..d2d0145cb889
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-lapic.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/interrupt-controller/intel,ce4100-lapic.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel Local Advanced Programmable Interrupt Controller (LAPIC)
+
+maintainers:
+ - Rahul Tanwar <rtanwar@maxlinear.com>
+
+description: |
+ Intel's Advanced Programmable Interrupt Controller (APIC) is a
+ family of interrupt controllers. The APIC is a split
+ architecture design, with a local component (LAPIC) integrated
+ into the processor itself and an external I/O APIC. Local APIC
+ (lapic) receives interrupts from the processor's interrupt pins,
+ from internal sources and from an external I/O APIC (ioapic).
+ And it sends these to the processor core for handling.
+ See [1] Chapter 8 for more details.
+
+ Many of the Intel's generic devices like hpet, ioapic, lapic have
+ the ce4100 name in their compatible property names because they
+ first appeared in CE4100 SoC.
+
+ This schema defines bindings for local APIC interrupt controller.
+
+ [1] https://pdos.csail.mit.edu/6.828/2008/readings/ia32/IA32-3A.pdf
+
+properties:
+ compatible:
+ const: intel,ce4100-lapic
+
+ reg:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ intel,virtual-wire-mode:
+ description: Intel defines a few possible interrupt delivery
+ modes. With respect to boot/init time, mainly two interrupt
+ delivery modes are possible.
+ PIC Mode - Legacy external 8259 compliant PIC interrupt controller.
+ Virtual Wire Mode - use lapic as virtual wire interrupt delivery mode.
+ For ACPI or MPS spec compliant systems, it is figured out by some read
+ only bit field/s available in their respective defined data structures.
+ For OF based systems, it is by default set to PIC mode.
+ But if this optional boolean property is set, then the interrupt delivery
+ mode is configured to virtual wire compatibility mode.
+ type: boolean
+
+required:
+ - compatible
+ - reg
+ - interrupt-controller
+ - '#interrupt-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ lapic0: interrupt-controller@fee00000 {
+ compatible = "intel,ce4100-lapic";
+ reg = <0xfee00000 0x1000>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ intel,virtual-wire-mode;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml
new file mode 100644
index 000000000000..2a1cf885c99d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/loongarch,cpu-interrupt-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LoongArch CPU Interrupt Controller
+
+maintainers:
+ - Liu Peibao <liupeibao@loongson.cn>
+
+properties:
+ compatible:
+ const: loongarch,cpu-interrupt-controller
+
+ '#interrupt-cells':
+ const: 1
+
+ interrupt-controller: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - '#interrupt-cells'
+ - interrupt-controller
+
+examples:
+ - |
+ interrupt-controller {
+ compatible = "loongarch,cpu-interrupt-controller";
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt
deleted file mode 100644
index 5865f4f2c69d..000000000000
--- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-* Mediatek 27xx cirq
-
-In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to
-work outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC.
-The external interrupts (outside MCUSYS) will feed through CIRQ and connect
-to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
-interrupts and generate a pulse signal to parent interrupt controller when
-flush command is executed. With CIRQ, MCUSYS can be completely turned off
-to improve the system power consumption without losing interrupts.
-
-Required properties:
-- compatible: should be one of
- - "mediatek,mt2701-cirq" for mt2701 CIRQ
- - "mediatek,mt8135-cirq" for mt8135 CIRQ
- - "mediatek,mt8173-cirq" for mt8173 CIRQ
- and "mediatek,cirq" as a fallback.
-- interrupt-controller : Identifies the node as an interrupt controller.
-- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt.
-- reg: Physical base address of the cirq registers and length of memory
- mapped region.
-- mediatek,ext-irq-range: Identifies external irq number range in different
- SOCs.
-
-Example:
- cirq: interrupt-controller@10204000 {
- compatible = "mediatek,mt2701-cirq",
- "mediatek,mtk-cirq";
- interrupt-controller;
- #interrupt-cells = <3>;
- interrupt-parent = <&sysirq>;
- reg = <0 0x10204000 0 0x400>;
- mediatek,ext-irq-start = <32 200>;
- };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml
new file mode 100644
index 000000000000..fdcb4d8db818
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mtk-cirq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek System Interrupt Controller
+
+maintainers:
+ - Youlin Pei <youlin.pei@mediatek.com>
+
+description:
+ In MediaTek SoCs, the CIRQ is a low power interrupt controller designed to
+ work outside of MCUSYS which comprises with Cortex-Ax cores, CCI and GIC.
+ The external interrupts (outside MCUSYS) will feed through CIRQ and connect
+ to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
+ interrupts and generate a pulse signal to parent interrupt controller when
+ flush command is executed. With CIRQ, MCUSYS can be completely turned off
+ to improve the system power consumption without losing interrupts.
+
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - mediatek,mt2701-cirq
+ - mediatek,mt8135-cirq
+ - mediatek,mt8173-cirq
+ - mediatek,mt8192-cirq
+ - const: mediatek,mtk-cirq
+
+ reg:
+ maxItems: 1
+
+ '#interrupt-cells':
+ const: 3
+
+ interrupt-controller: true
+
+ mediatek,ext-irq-range:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ items:
+ - description: First CIRQ interrupt
+ - description: Last CIRQ interrupt
+ description:
+ Identifies the range of external interrupts in different SoCs
+
+required:
+ - compatible
+ - reg
+ - '#interrupt-cells'
+ - interrupt-controller
+ - mediatek,ext-irq-range
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ cirq: interrupt-controller@10204000 {
+ compatible = "mediatek,mt2701-cirq", "mediatek,mtk-cirq";
+ reg = <0x10204000 0x400>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupt-parent = <&sysirq>;
+ mediatek,ext-irq-range = <32 200>;
+ };
diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
index 82ad669feef7..06af2bacbe97 100644
--- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml
+++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
@@ -22,7 +22,9 @@ description: |+
properties:
compatible:
- const: apple,t8103-dart
+ enum:
+ - apple,t8103-dart
+ - apple,t6000-dart
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml
index 704033e21ee8..53945c61325c 100644
--- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml
+++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml
@@ -21,6 +21,7 @@ properties:
- const: allwinner,sun6i-a31-ir
- items:
- enum:
+ - allwinner,suniv-f1c100s-ir
- allwinner,sun8i-a83t-ir
- allwinner,sun8i-r40-ir
- allwinner,sun50i-a64-ir
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun50i-h6-vpu-g2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun50i-h6-vpu-g2.yaml
index 24d7bf21499e..9d44236f2deb 100644
--- a/Documentation/devicetree/bindings/media/allwinner,sun50i-h6-vpu-g2.yaml
+++ b/Documentation/devicetree/bindings/media/allwinner,sun50i-h6-vpu-g2.yaml
@@ -36,6 +36,9 @@ properties:
resets:
maxItems: 1
+ iommus:
+ maxItems: 1
+
required:
- compatible
- reg
@@ -43,6 +46,7 @@ required:
- clocks
- clock-names
- resets
+ - iommus
additionalProperties: false
@@ -59,6 +63,7 @@ examples:
clocks = <&ccu CLK_BUS_VP9>, <&ccu CLK_VP9>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_VP9>;
+ iommus = <&iommu 5>;
};
...
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
index f1ccca35a790..b3d6db922693 100644
--- a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
+++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
@@ -73,6 +73,10 @@ properties:
$ref: /schemas/graph.yaml#/properties/port
description: MIPI CSI-2 bridge input port
+ port@2:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Internal output port to the ISP
+
anyOf:
- required:
- port@0
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml
new file mode 100644
index 000000000000..6bda4f2b94c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allwinner,sun6i-a31-isp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 Image Signal Processor Driver (ISP) Device Tree Bindings
+
+maintainers:
+ - Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+
+properties:
+ compatible:
+ enum:
+ - allwinner,sun6i-a31-isp
+ - allwinner,sun8i-v3s-isp
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Bus Clock
+ - description: Module Clock
+ - description: DRAM Clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: mod
+ - const: ram
+
+ resets:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: CSI0 input port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: CSI1 input port
+
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - allwinner,sun8i-v3s-isp
+ then:
+ required:
+ - port@0
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/sun8i-v3s-ccu.h>
+ #include <dt-bindings/reset/sun8i-v3s-ccu.h>
+
+ isp: isp@1cb8000 {
+ compatible = "allwinner,sun8i-v3s-isp";
+ reg = <0x01cb8000 0x1000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CSI>,
+ <&ccu CLK_CSI1_SCLK>,
+ <&ccu CLK_DRAM_CSI>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_CSI>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ isp_in_csi0: endpoint {
+ remote-endpoint = <&csi0_out_isp>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/imx290.txt b/Documentation/devicetree/bindings/media/i2c/imx290.txt
deleted file mode 100644
index a3cc21410f7c..000000000000
--- a/Documentation/devicetree/bindings/media/i2c/imx290.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-* Sony IMX290 1/2.8-Inch CMOS Image Sensor
-
-The Sony IMX290 is a 1/2.8-Inch CMOS Solid-state image sensor with
-Square Pixel for Color Cameras. It is programmable through I2C and 4-wire
-interfaces. The sensor output is available via CMOS logic parallel SDR output,
-Low voltage LVDS DDR output and CSI-2 serial data output. The CSI-2 bus is the
-default. No bindings have been defined for the other busses.
-
-Required Properties:
-- compatible: Should be "sony,imx290"
-- reg: I2C bus address of the device
-- clocks: Reference to the xclk clock.
-- clock-names: Should be "xclk".
-- clock-frequency: Frequency of the xclk clock in Hz.
-- vdddo-supply: Sensor digital IO regulator.
-- vdda-supply: Sensor analog regulator.
-- vddd-supply: Sensor digital core regulator.
-
-Optional Properties:
-- reset-gpios: Sensor reset GPIO
-
-The imx290 device node should contain one 'port' child node with
-an 'endpoint' subnode. For further reading on port node refer to
-Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Required Properties on endpoint:
-- data-lanes: check ../video-interfaces.txt
-- link-frequencies: check ../video-interfaces.txt
-- remote-endpoint: check ../video-interfaces.txt
-
-Example:
- &i2c1 {
- ...
- imx290: camera-sensor@1a {
- compatible = "sony,imx290";
- reg = <0x1a>;
-
- reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&camera_rear_default>;
-
- clocks = <&gcc GCC_CAMSS_MCLK0_CLK>;
- clock-names = "xclk";
- clock-frequency = <37125000>;
-
- vdddo-supply = <&camera_vdddo_1v8>;
- vdda-supply = <&camera_vdda_2v8>;
- vddd-supply = <&camera_vddd_1v5>;
-
- port {
- imx290_ep: endpoint {
- data-lanes = <1 2 3 4>;
- link-frequencies = /bits/ 64 <445500000>;
- remote-endpoint = <&csiphy0_ep>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
index 39395ea8c318..edde4201116f 100644
--- a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
@@ -104,6 +104,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
i2c2 {
#address-cells = <1>;
@@ -124,7 +125,7 @@ examples:
remote-endpoint = <&csi2a_ep>;
link-frequencies = /bits/ 64 <199200000 210000000
499200000>;
- bus-type = <4>;
+ bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
};
};
};
diff --git a/Documentation/devicetree/bindings/media/i2c/ov5645.txt b/Documentation/devicetree/bindings/media/i2c/ov5645.txt
deleted file mode 100644
index 72ad992f77be..000000000000
--- a/Documentation/devicetree/bindings/media/i2c/ov5645.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-* Omnivision 1/4-Inch 5Mp CMOS Digital Image Sensor
-
-The Omnivision OV5645 is a 1/4-Inch CMOS active pixel digital image sensor with
-an active array size of 2592H x 1944V. It is programmable through a serial I2C
-interface.
-
-Required Properties:
-- compatible: Value should be "ovti,ov5645".
-- clocks: Reference to the xclk clock.
-- clock-names: Should be "xclk".
-- clock-frequency: Frequency of the xclk clock.
-- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds
- to the hardware pin PWDNB which is physically active low.
-- reset-gpios: Chip reset GPIO. Polarity is GPIO_ACTIVE_LOW. This corresponds to
- the hardware pin RESETB.
-- vdddo-supply: Chip digital IO regulator.
-- vdda-supply: Chip analog regulator.
-- vddd-supply: Chip digital core regulator.
-
-The device node must contain one 'port' child node for its digital output
-video port, in accordance with the video interface bindings defined in
-Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Example:
-
- &i2c1 {
- ...
-
- ov5645: ov5645@3c {
- compatible = "ovti,ov5645";
- reg = <0x3c>;
-
- enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&camera_rear_default>;
-
- clocks = <&clks 200>;
- clock-names = "xclk";
- clock-frequency = <24000000>;
-
- vdddo-supply = <&camera_dovdd_1v8>;
- vdda-supply = <&camera_avdd_2v8>;
- vddd-supply = <&camera_dvdd_1v2>;
-
- port {
- ov5645_ep: endpoint {
- clock-lanes = <1>;
- data-lanes = <0 2>;
- remote-endpoint = <&csi0_ep>;
- };
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml
new file mode 100644
index 000000000000..50579c947f3c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov4689.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Omnivision OV4689 CMOS
+
+maintainers:
+ - Mikhail Rudenko <mike.rudenko@gmail.com>
+
+description: |
+ The Omnivision OV4689 is a high performance, 1/3-inch, 4 megapixel
+ image sensor. Ihis chip supports high frame rate speeds up to 90 fps
+ at 2688x1520 resolution. It is programmable through an I2C
+ interface, and sensor output is sent via 1/2/4 lane MIPI CSI-2
+ connection.
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: ovti,ov4689
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description:
+ External clock (XVCLK) for the sensor, 6-64 MHz
+ maxItems: 1
+
+ dovdd-supply:
+ description:
+ Digital I/O voltage supply, 1.7-3.0 V
+
+ avdd-supply:
+ description:
+ Analog voltage supply, 2.6-3.0 V
+
+ dvdd-supply:
+ description:
+ Digital core voltage supply, 1.1-1.3 V
+
+ powerdown-gpios:
+ description:
+ GPIO connected to the powerdown pin (active low)
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the reset pin (active low)
+
+ orientation: true
+
+ rotation: true
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+ description:
+ Output port node, single endpoint describing the CSI-2 transmitter
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ oneOf:
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+ - items:
+ - const: 1
+ - const: 2
+ - items:
+ - const: 1
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - dovdd-supply
+ - avdd-supply
+ - dvdd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ov4689: camera@36 {
+ compatible = "ovti,ov4689";
+ reg = <0x36>;
+
+ clocks = <&ov4689_clk>;
+
+ avdd-supply = <&ov4689_avdd>;
+ dovdd-supply = <&ov4689_dovdd>;
+ dvdd-supply = <&ov4689_dvdd>;
+
+ powerdown-gpios = <&pio 107 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&pio 109 GPIO_ACTIVE_LOW>;
+
+ orientation = <2>;
+ rotation = <0>;
+
+ port {
+ wcam_out: endpoint {
+ remote-endpoint = <&mipi_in_wcam>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <504000000>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5645.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5645.yaml
new file mode 100644
index 000000000000..52c6281a6684
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5645.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov5645.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OV5645 Image Sensor Device Tree Bindings
+
+maintainers:
+ - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+properties:
+ compatible:
+ const: ovti,ov5645
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description: XCLK Input Clock
+
+ clock-frequency:
+ description: Frequency of the xclk clock in Hz.
+
+ vdda-supply:
+ description: Analog voltage supply, 2.8 volts
+
+ vddd-supply:
+ description: Digital core voltage supply, 1.5 volts
+
+ vdddo-supply:
+ description: Digital I/O voltage supply, 1.8 volts
+
+ enable-gpios:
+ maxItems: 1
+ description:
+ Reference to the GPIO connected to the PWDNB pin, if any.
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ Reference to the GPIO connected to the RESETB pin, if any.
+
+ port:
+ description: Digital Output Port
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 2
+ items:
+ enum: [1, 2]
+
+ required:
+ - data-lanes
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - vdddo-supply
+ - vdda-supply
+ - vddd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@3c {
+ compatible = "ovti,ov5645";
+ reg = <0x3c>;
+ clocks = <&clks 1>;
+ clock-frequency = <24000000>;
+ vdddo-supply = <&ov5645_vdddo_1v8>;
+ vdda-supply = <&ov5645_vdda_2v8>;
+ vddd-supply = <&ov5645_vddd_1v5>;
+ enable-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ov5645>;
+
+ port {
+ ov5645_ep: endpoint {
+ remote-endpoint = <&csi0_ep>;
+ data-lanes = <1 2>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml
index 44529425ce3a..161e6d598e1c 100644
--- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml
@@ -105,6 +105,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
i2c0 {
#address-cells = <1>;
@@ -118,7 +119,7 @@ examples:
port {
ov772x_0: endpoint {
- bus-type = <5>;
+ bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
vsync-active = <0>;
hsync-active = <0>;
pclk-sample = <0>;
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml
index bf115ab9d926..0c4654e70d46 100644
--- a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml
@@ -16,10 +16,13 @@ description:
sensor with an active array size of 1296H x 816V. It is programmable through
I2C interface. The I2C client address is fixed to 0x60/0x70 as per sensor data
sheet. Image data is sent through MIPI CSI-2.
+ OV9281 has a different lens chief ray angle.
properties:
compatible:
- const: ovti,ov9282
+ enum:
+ - ovti,ov9281
+ - ovti,ov9282
reg:
description: I2C address
maxItems: 1
@@ -36,6 +39,15 @@ properties:
description: Reference to the GPIO connected to the XCLR pin, if any.
maxItems: 1
+ avdd-supply:
+ description: Analog voltage supply, 2.8 volts
+
+ dvdd-supply:
+ description: Digital core voltage supply, 1.2 volts
+
+ dovdd-supply:
+ description: Digital I/O voltage supply, 1.8 volts
+
port:
additionalProperties: false
$ref: /schemas/graph.yaml#/$defs/port-base
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
new file mode 100644
index 000000000000..21377daae026
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx290.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX290 1/2.8-Inch CMOS Image Sensor
+
+maintainers:
+ - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+description: |-
+ The Sony IMX290 is a 1/2.8-Inch CMOS Solid-state image sensor with Square
+ Pixel for Color Cameras. It is programmable through I2C and 4-wire
+ interfaces. The sensor output is available via CMOS logic parallel SDR
+ output, Low voltage LVDS DDR output and CSI-2 serial data output. The CSI-2
+ bus is the default. No bindings have been defined for the other busses.
+
+properties:
+ compatible:
+ enum:
+ - sony,imx290
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ description: Input clock (37.125 MHz or 74.25 MHz)
+ items:
+ - const: xclk
+
+ clock-frequency:
+ description: Frequency of the xclk clock in Hz
+
+ vdda-supply:
+ description: Analog power supply (2.9V)
+
+ vddd-supply:
+ description: Digital core power supply (1.2V)
+
+ vdddo-supply:
+ description: Digital I/O power supply (1.8V)
+
+ reset-gpios:
+ description: Sensor reset (XCLR) GPIO
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: |
+ Video output port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ anyOf:
+ - items:
+ - const: 1
+ - const: 2
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - clock-frequency
+ - vdda-supply
+ - vddd-supply
+ - vdddo-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ imx290: camera-sensor@1a {
+ compatible = "sony,imx290";
+ reg = <0x1a>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_rear_default>;
+
+ clocks = <&gcc 90>;
+ clock-names = "xclk";
+ clock-frequency = <37125000>;
+
+ vdddo-supply = <&camera_vdddo_1v8>;
+ vdda-supply = <&camera_vdda_2v8>;
+ vddd-supply = <&camera_vddd_1v5>;
+
+ reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>;
+
+ port {
+ imx290_ep: endpoint {
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <445500000>;
+ remote-endpoint = <&csiphy0_ep>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
index 26d1807d0bb6..60dc25ff2b9e 100644
--- a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
@@ -19,7 +19,9 @@ description:
properties:
compatible:
- const: sony,imx412
+ enum:
+ - sony,imx412
+ - sony,imx577
reg:
description: I2C address
maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml b/Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml
new file mode 100644
index 000000000000..6597e1d0e65f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (c) 2022 STMicroelectronics SA.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/st,st-vgxy61.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics VGxy61 HDR Global Shutter Sensor Family Device Tree Bindings
+
+maintainers:
+ - Benjamin Mugnier <benjamin.mugnier@foss.st.com>
+ - Sylvain Petinot <sylvain.petinot@foss.st.com>
+
+description: |-
+ STMicroelectronics VGxy61 family has a CSI-2 output port. CSI-2 output is a
+ quad lanes 800Mbps per lane.
+ Supported formats are RAW8, RAW10, RAW12, RAW14 and RAW16.
+ Following part number are supported
+ - VG5661 and VG6661 are 1.6 Mpx (1464 x 1104) monochrome and color sensors.
+ Maximum frame rate is 75 fps.
+ - VG5761 and VG6761 are 2.3 Mpx (1944 x 1204) monochrome and color sensors.
+ Maximum frame rate is 60 fps.
+
+properties:
+ compatible:
+ const: st,st-vgxy61
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ VCORE-supply:
+ description:
+ Sensor digital core supply. Must be 1.2 volts.
+
+ VDDIO-supply:
+ description:
+ Sensor digital IO supply. Must be 1.8 volts.
+
+ VANA-supply:
+ description:
+ Sensor analog supply. Must be 2.8 volts.
+
+ reset-gpios:
+ description:
+ Reference to the GPIO connected to the reset pin, if any.
+ This is an active low signal to the vgxy61.
+
+ st,strobe-gpios-polarity:
+ description:
+ Invert polarity of illuminator's lights strobe GPIOs.
+ These GPIOs directly drive the illuminator LEDs.
+ type: boolean
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ description:
+ CSI lanes to use
+ items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ remote-endpoint: true
+
+ required:
+ - data-lanes
+
+required:
+ - compatible
+ - clocks
+ - VCORE-supply
+ - VDDIO-supply
+ - VANA-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ vgxy61: csi2tx@10 {
+ compatible = "st,st-vgxy61";
+ reg = <0x10>;
+ clocks = <&clk_ext_camera>;
+ VCORE-supply = <&v1v2>;
+ VDDIO-supply = <&v1v8>;
+ VANA-supply = <&v2v8>;
+ reset-gpios = <&mfxgpio 18 GPIO_ACTIVE_LOW>;
+ port {
+ ep0: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&mipi_csi2_out>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.yaml b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.yaml
new file mode 100644
index 000000000000..b8ba85a2416c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.yaml
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/toshiba,tc358746.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba TC358746 Parallel to MIPI CSI2 Bridge
+
+maintainers:
+ - Marco Felsch <kernel@pengutronix.de>
+
+description: |-
+ The Toshiba TC358746 converts a parallel video stream into a MIPI CSI-2
+ stream. The direction can be either parallel-in -> csi-out or csi-in ->
+ parallel-out The chip is programmable trough I2C and SPI but the SPI
+ interface is only supported in parallel-in -> csi-out mode.
+
+ Note that the current device tree bindings only support the
+ parallel-in -> csi-out path.
+
+properties:
+ compatible:
+ const: toshiba,tc358746
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description:
+ The phandle to the reference clock source. This corresponds to the
+ hardware pin REFCLK.
+ maxItems: 1
+
+ clock-names:
+ const: refclk
+
+ "#clock-cells":
+ description: |
+ The bridge can act as clock provider for the sensor. To enable this
+ support #clock-cells must be specified. Attention if this feature is used
+ then the mclk rate must be at least: (2 * link-frequency) / 8
+ `------------------´ ^
+ internal PLL rate smallest possible
+ mclk-div
+ const: 0
+
+ clock-output-names:
+ description:
+ The clock name of the MCLK output, the default name is tc358746-mclk.
+ maxItems: 1
+
+ vddc-supply:
+ description: Digital core voltage supply, 1.2 volts
+
+ vddio-supply:
+ description: Digital I/O voltage supply, 1.8 volts
+
+ vddmipi-supply:
+ description: MIPI CSI phy voltage supply, 1.2 volts
+
+ reset-gpios:
+ description:
+ The phandle and specifier for the GPIO that controls the chip reset.
+ This corresponds to the hardware pin RESX which is physically active low.
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: Input port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ hsync-active: true
+ vsync-active: true
+ bus-type:
+ enum: [ 5, 6 ]
+
+ required:
+ - hsync-active
+ - vsync-active
+ - bus-type
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: Output port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+
+ clock-noncontinuous: true
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - vddc-supply
+ - vddio-supply
+ - vddmipi-supply
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi-bridge@e {
+ compatible = "toshiba,tc358746";
+ reg = <0xe>;
+
+ clocks = <&refclk>;
+ clock-names = "refclk";
+
+ reset-gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
+
+ vddc-supply = <&v1_2d>;
+ vddio-supply = <&v1_8d>;
+ vddmipi-supply = <&v1_2d>;
+
+ /* sensor mclk provider */
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Input */
+ port@0 {
+ reg = <0>;
+ tc358746_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ bus-type = <5>;
+ };
+ };
+
+ /* Output */
+ port@1 {
+ reg = <1>;
+ tc358746_out: endpoint {
+ remote-endpoint = <&mipi_csi2_in>;
+ data-lanes = <1 2>;
+ clock-noncontinuous;
+ link-frequencies = /bits/ 64 <216000000>;
+ };
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml
index b39b84c5f012..0e3478551e13 100644
--- a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml
+++ b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml
@@ -68,6 +68,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/clock/marvell,mmp2.h>
+ #include <dt-bindings/media/video-interfaces.h>
#include <dt-bindings/power/marvell,mmp2.h>
camera@d420a000 {
@@ -83,7 +84,7 @@ examples:
port {
camera0_0: endpoint {
remote-endpoint = <&ov7670_0>;
- bus-type = <5>; /* Parallel */
+ bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
hsync-active = <1>; /* Active high */
vsync-active = <1>; /* Active high */
pclk-sample = <0>; /* Falling */
diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
new file mode 100644
index 000000000000..71595c013dbb
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
@@ -0,0 +1,168 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek JPEG Decoder
+
+maintainers:
+ - kyrie wu <kyrie.wu@mediatek.corp-partner.google.com>
+
+description:
+ MediaTek JPEG Decoder is the JPEG decode hardware present in MediaTek SoCs
+
+properties:
+ compatible:
+ const: mediatek,mt8195-jpgdec
+
+ power-domains:
+ maxItems: 1
+
+ iommus:
+ maxItems: 6
+ description:
+ Points to the respective IOMMU block with master port as argument, see
+ Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
+ Ports are according to the HW.
+
+ dma-ranges:
+ maxItems: 1
+ description: |
+ Describes the physical address space of IOMMU maps to memory.
+
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 2
+
+ ranges: true
+
+# Required child node:
+patternProperties:
+ "^jpgdec@[0-9a-f]+$":
+ type: object
+ description:
+ The jpeg decoder hardware device node which should be added as subnodes to
+ the main jpeg node.
+
+ properties:
+ compatible:
+ const: mediatek,mt8195-jpgdec-hw
+
+ reg:
+ maxItems: 1
+
+ iommus:
+ minItems: 1
+ maxItems: 32
+ description:
+ List of the hardware port in respective IOMMU block for current Socs.
+ Refer to bindings/iommu/mediatek,iommu.yaml.
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: jpgdec
+
+ power-domains:
+ maxItems: 1
+
+ required:
+ - compatible
+ - reg
+ - iommus
+ - interrupts
+ - clocks
+ - clock-names
+ - power-domains
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - power-domains
+ - iommus
+ - dma-ranges
+ - ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/memory/mt8195-memory-port.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/clock/mt8195-clk.h>
+ #include <dt-bindings/power/mt8195-power.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ jpgdec-master {
+ compatible = "mediatek,mt8195-jpgdec";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDEC1>;
+ iommus = <&iommu_vpp M4U_PORT_L19_JPGDEC_WDMA0>,
+ <&iommu_vpp M4U_PORT_L19_JPGDEC_BSDMA0>,
+ <&iommu_vpp M4U_PORT_L19_JPGDEC_WDMA1>,
+ <&iommu_vpp M4U_PORT_L19_JPGDEC_BSDMA1>,
+ <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>,
+ <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ jpgdec@1a040000 {
+ compatible = "mediatek,mt8195-jpgdec-hw";
+ reg = <0 0x1a040000 0 0x10000>;/* JPGDEC_C0 */
+ iommus = <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA0>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA0>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>;
+ interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vencsys CLK_VENC_JPGDEC>;
+ clock-names = "jpgdec";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDEC0>;
+ };
+
+ jpgdec@1a050000 {
+ compatible = "mediatek,mt8195-jpgdec-hw";
+ reg = <0 0x1a050000 0 0x10000>;/* JPGDEC_C1 */
+ iommus = <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA0>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA0>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>,
+ <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>;
+ interrupts = <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vencsys CLK_VENC_JPGDEC_C1>;
+ clock-names = "jpgdec";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDEC1>;
+ };
+
+ jpgdec@1b040000 {
+ compatible = "mediatek,mt8195-jpgdec-hw";
+ reg = <0 0x1b040000 0 0x10000>;/* JPGDEC_C2 */
+ iommus = <&iommu_vpp M4U_PORT_L20_JPGDEC_WDMA0>,
+ <&iommu_vpp M4U_PORT_L20_JPGDEC_BSDMA0>,
+ <&iommu_vpp M4U_PORT_L20_JPGDEC_WDMA1>,
+ <&iommu_vpp M4U_PORT_L20_JPGDEC_BSDMA1>,
+ <&iommu_vpp M4U_PORT_L20_JPGDEC_BUFF_OFFSET1>,
+ <&iommu_vpp M4U_PORT_L20_JPGDEC_BUFF_OFFSET0>;
+ interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vencsys_core1 CLK_VENC_CORE1_JPGDEC>;
+ clock-names = "jpgdec";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDEC2>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml
new file mode 100644
index 000000000000..95990539f7c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml
@@ -0,0 +1,147 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek JPEG Encoder
+
+maintainers:
+ - kyrie wu <kyrie.wu@mediatek.corp-partner.google.com>
+
+description:
+ MediaTek JPEG Encoder is the JPEG encode hardware present in MediaTek SoCs
+
+properties:
+ compatible:
+ const: mediatek,mt8195-jpgenc
+
+ power-domains:
+ maxItems: 1
+
+ iommus:
+ maxItems: 4
+ description:
+ Points to the respective IOMMU block with master port as argument, see
+ Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
+ Ports are according to the HW.
+
+ dma-ranges:
+ maxItems: 1
+ description: |
+ Describes the physical address space of IOMMU maps to memory.
+
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 2
+
+ ranges: true
+
+# Required child node:
+patternProperties:
+ "^jpgenc@[0-9a-f]+$":
+ type: object
+ description:
+ The jpeg encoder hardware device node which should be added as subnodes to
+ the main jpeg node.
+
+ properties:
+ compatible:
+ const: mediatek,mt8195-jpgenc-hw
+
+ reg:
+ maxItems: 1
+
+ iommus:
+ minItems: 1
+ maxItems: 32
+ description:
+ List of the hardware port in respective IOMMU block for current Socs.
+ Refer to bindings/iommu/mediatek,iommu.yaml.
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: jpgenc
+
+ power-domains:
+ maxItems: 1
+
+ required:
+ - compatible
+ - reg
+ - iommus
+ - interrupts
+ - clocks
+ - clock-names
+ - power-domains
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - power-domains
+ - iommus
+ - dma-ranges
+ - ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/memory/mt8195-memory-port.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/clock/mt8195-clk.h>
+ #include <dt-bindings/power/mt8195-power.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ jpgenc-master {
+ compatible = "mediatek,mt8195-jpgenc";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VENC_CORE1>;
+ iommus = <&iommu_vpp M4U_PORT_L20_JPGENC_Y_RDMA>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ jpgenc@1a030000 {
+ compatible = "mediatek,mt8195-jpgenc-hw";
+ reg = <0 0x1a030000 0 0x10000>;
+ iommus = <&iommu_vdo M4U_PORT_L19_JPGENC_Y_RDMA>,
+ <&iommu_vdo M4U_PORT_L19_JPGENC_C_RDMA>,
+ <&iommu_vdo M4U_PORT_L19_JPGENC_Q_TABLE>,
+ <&iommu_vdo M4U_PORT_L19_JPGENC_BSDMA>;
+ interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vencsys CLK_VENC_JPGENC>;
+ clock-names = "jpgenc";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VENC>;
+ };
+
+ jpgenc@1b030000 {
+ compatible = "mediatek,mt8195-jpgenc-hw";
+ reg = <0 0x1b030000 0 0x10000>;
+ iommus = <&iommu_vpp M4U_PORT_L20_JPGENC_Y_RDMA>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>,
+ <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>;
+ interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vencsys_core1 CLK_VENC_CORE1_JPGENC>;
+ clock-names = "jpgenc";
+ power-domains = <&spm MT8195_POWER_DOMAIN_VENC_CORE1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
index 32aee09aea33..0f2ea8d9a10c 100644
--- a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
@@ -67,6 +67,12 @@ properties:
power-domains:
maxItems: 1
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 2
+
required:
- compatible
- reg
@@ -84,7 +90,9 @@ allOf:
contains:
enum:
- mediatek,mt8183-vcodec-enc
+ - mediatek,mt8188-vcodec-enc
- mediatek,mt8192-vcodec-enc
+ - mediatek,mt8195-vcodec-enc
then:
required:
@@ -107,7 +115,9 @@ allOf:
compatible:
enum:
- mediatek,mt8173-vcodec-enc
+ - mediatek,mt8188-vcodec-enc
- mediatek,mt8192-vcodec-enc
+ - mediatek,mt8195-vcodec-enc
then:
properties:
@@ -118,7 +128,7 @@ allOf:
clock-names:
items:
- const: venc_sel
- else: # for vp8 hw decoder
+ else: # for vp8 hw encoder
properties:
clock:
items:
diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
index 5e8d001492cc..cfabf360f278 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
@@ -22,6 +22,7 @@ properties:
- items:
- enum:
- mediatek,mt7623-jpgdec
+ - mediatek,mt8188-jpgdec
- const: mediatek,mt2701-jpgdec
reg:
diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
index fc727300b493..c8412e8ab353 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
@@ -19,6 +19,7 @@ properties:
- mediatek,mt2701-jpgenc
- mediatek,mt8183-jpgenc
- mediatek,mt8186-jpgenc
+ - mediatek,mt8188-jpgenc
- const: mediatek,mtk-jpgenc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/microchip,xisc.yaml b/Documentation/devicetree/bindings/media/microchip,xisc.yaml
index 8b37fccab5e2..25f5f79d40ce 100644
--- a/Documentation/devicetree/bindings/media/microchip,xisc.yaml
+++ b/Documentation/devicetree/bindings/media/microchip,xisc.yaml
@@ -106,6 +106,7 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/at91.h>
#include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/media/video-interfaces.h>
xisc: xisc@e1408000 {
compatible = "microchip,sama7g5-isc";
@@ -118,7 +119,7 @@ examples:
port {
xisc_in: endpoint {
- bus-type = <5>; /* Parallel */
+ bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
remote-endpoint = <&csi2dc_out>;
hsync-active = <1>;
vsync-active = <1>;
diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml
new file mode 100644
index 000000000000..7dde7967c886
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml
@@ -0,0 +1,157 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2022 Renesas Electronics Corp.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/renesas,rzg2l-cru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L (and alike SoC's) Camera Data Receiving Unit (CRU) Image processing
+
+maintainers:
+ - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+description:
+ The CRU image processing module is a data conversion module equipped with pixel
+ color space conversion, LUT, pixel format conversion, etc. An MIPI CSI-2 input and
+ parallel (including ITU-R BT.656) input are provided as the image sensor interface.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a07g044-cru # RZ/G2{L,LC}
+ - renesas,r9a07g054-cru # RZ/V2L
+ - const: renesas,rzg2l-cru
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 3
+
+ interrupt-names:
+ items:
+ - const: image_conv
+ - const: image_conv_err
+ - const: axi_mst_err
+
+ clocks:
+ items:
+ - description: CRU Main clock
+ - description: CRU Register access clock
+ - description: CRU image transfer clock
+
+ clock-names:
+ items:
+ - const: video
+ - const: apb
+ - const: axi
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: CRU_PRESETN reset terminal
+ - description: CRU_ARESETN reset terminal
+
+ reset-names:
+ items:
+ - const: presetn
+ - const: aresetn
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description:
+ Input port node, single endpoint describing a parallel input source.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ hsync-active: true
+ vsync-active: true
+ bus-width: true
+ data-shift: true
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Input port node, describing the Image Processing module connected to the
+ CSI-2 receiver.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+
+additionalProperties: false
+
+examples:
+ # Device node example with CSI-2
+ - |
+ #include <dt-bindings/clock/r9a07g044-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ cru: video@10830000 {
+ compatible = "renesas,r9a07g044-cru", "renesas,rzg2l-cru";
+ reg = <0x10830000 0x400>;
+ interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "image_conv", "image_conv_err", "axi_mst_err";
+ clocks = <&cpg CPG_MOD R9A07G044_CRU_VCLK>,
+ <&cpg CPG_MOD R9A07G044_CRU_PCLK>,
+ <&cpg CPG_MOD R9A07G044_CRU_ACLK>;
+ clock-names = "video", "apb", "axi";
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G044_CRU_PRESETN>,
+ <&cpg R9A07G044_CRU_ARESETN>;
+ reset-names = "presetn", "aresetn";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ cru_parallel_in: endpoint@0 {
+ reg = <0>;
+ remote-endpoint= <&ov5642>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ cru_csi_in: endpoint@0 {
+ reg = <0>;
+ remote-endpoint= <&csi_cru_in>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
new file mode 100644
index 000000000000..67eea2ac1d22
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
@@ -0,0 +1,149 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2022 Renesas Electronics Corp.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/renesas,rzg2l-csi2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L (and alike SoC's) MIPI CSI-2 receiver
+
+maintainers:
+ - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+description:
+ The CSI-2 receiver device provides MIPI CSI-2 capabilities for the Renesas RZ/G2L
+ (and alike SoCs). MIPI CSI-2 is part of the CRU block which is used in conjunction
+ with the Image Processing module, which provides the video capture capabilities.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
+ - renesas,r9a07g054-csi2 # RZ/V2L
+ - const: renesas,rzg2l-csi2
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Internal clock for connecting CRU and MIPI
+ - description: CRU Main clock
+ - description: CRU Register access clock
+
+ clock-names:
+ items:
+ - const: system
+ - const: video
+ - const: apb
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: CRU_PRESETN reset terminal
+ - description: CRU_CMN_RSTB reset terminal
+
+ reset-names:
+ items:
+ - const: presetn
+ - const: cmn-rstb
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description:
+ Input port node, single endpoint describing the CSI-2 transmitter.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+ items:
+ maximum: 4
+
+ required:
+ - clock-lanes
+ - data-lanes
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Output port node, Image Processing block connected to the CSI-2 receiver.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - power-domains
+ - resets
+ - reset-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/r9a07g044-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ csi: csi@10830400 {
+ compatible = "renesas,r9a07g044-csi2", "renesas,rzg2l-csi2";
+ reg = <0x10830400 0xfc00>;
+ interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD R9A07G044_CRU_SYSCLK>,
+ <&cpg CPG_MOD R9A07G044_CRU_VCLK>,
+ <&cpg CPG_MOD R9A07G044_CRU_PCLK>;
+ clock-names = "system", "video", "apb";
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G044_CRU_PRESETN>,
+ <&cpg R9A07G044_CRU_CMN_RSTB>;
+ reset-names = "presetn", "cmn-rstb";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ csi2_in: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ remote-endpoint = <&ov5645_ep>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ csi2cru: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&crucsi2>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt
index aa54c8159d9f..8eb90c043d5d 100644
--- a/Documentation/devicetree/bindings/media/s5p-mfc.txt
+++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt
@@ -10,10 +10,12 @@ Required properties:
- compatible : value should be either one among the following
(a) "samsung,mfc-v5" for MFC v5 present in Exynos4 SoCs
(b) "samsung,mfc-v6" for MFC v6 present in Exynos5 SoCs
- (c) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC
- (d) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC
- (e) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC
- (f) "samsung,mfc-v10" for MFC v10 present in Exynos7880 SoC
+ (c) "samsung,exynos3250-mfc", "samsung,mfc-v7" for MFC v7
+ present in Exynos3250 SoC
+ (d) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC
+ (e) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC
+ (f) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC
+ (g) "samsung,mfc-v10" for MFC v10 present in Exynos7880 SoC
- reg : Physical base address of the IP registers and length of memory
mapped region.
diff --git a/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt
index 21f31fdf5543..f0ea9adad442 100644
--- a/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt
+++ b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt
@@ -76,7 +76,7 @@ i2c@138a000000 {
clock-frequency = <24000000>;
clocks = <&clk 0>;
clock-names = "cis_extclk";
- reset-gpios = <&gpf1 3 1>;
+ xshutdown-gpios = <&gpf1 3 1>;
standby-gpios = <&gpm0 1 1>;
port {
s5c73m3_ep: endpoint {
diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
index 9c1262a276b5..e80fcdf280f0 100644
--- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
@@ -90,7 +90,9 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
+ #include <dt-bindings/media/video-interfaces.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
+
dcmi: dcmi@4c006000 {
compatible = "st,stm32-dcmi";
reg = <0x4c006000 0x400>;
@@ -104,7 +106,7 @@ examples:
port {
dcmi_0: endpoint {
remote-endpoint = <&ov5640_0>;
- bus-type = <5>;
+ bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
bus-width = <8>;
hsync-active = <0>;
vsync-active = <0>;
diff --git a/Documentation/devicetree/bindings/media/video-interfaces.yaml b/Documentation/devicetree/bindings/media/video-interfaces.yaml
index 68c3b9871cf3..34bdad028180 100644
--- a/Documentation/devicetree/bindings/media/video-interfaces.yaml
+++ b/Documentation/devicetree/bindings/media/video-interfaces.yaml
@@ -145,9 +145,10 @@ properties:
pclk-sample:
$ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 0, 1 ]
+ enum: [ 0, 1, 2 ]
description:
- Sample data on rising (1) or falling (0) edge of the pixel clock signal.
+ Sample data on falling (0), rising (1) or both (2) edges of the pixel
+ clock signal.
sync-on-green-active:
$ref: /schemas/types.yaml#/definitions/uint32
diff --git a/Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml b/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
index 01c9acf9275d..bd23257fe021 100644
--- a/Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
@@ -1,26 +1,31 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/memory-controllers/arm,pl353-smc.yaml#
+$id: http://devicetree.org/schemas/memory-controllers/arm,pl35x-smc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: ARM PL353 Static Memory Controller (SMC) device-tree bindings
+title: Arm PL35x Series Static Memory Controller (SMC)
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
-description:
- The PL353 Static Memory Controller is a bus where you can connect two kinds
+description: |
+ The PL35x Static Memory Controller is a bus where you can connect two kinds
of memory interfaces, which are NAND and memory mapped interfaces (such as
- SRAM or NOR).
+ SRAM or NOR) depending on the specific configuration.
+
+ The TRM is available here:
+ https://documentation-service.arm.com/static/5e8e2524fd977155116a58aa
# We need a select here so we don't match all nodes with 'arm,primecell'
select:
properties:
compatible:
contains:
- const: arm,pl353-smc-r2p1
+ enum:
+ - arm,pl353-smc-r2p1
+ - arm,pl354
required:
- compatible
@@ -30,7 +35,9 @@ properties:
compatible:
items:
- - const: arm,pl353-smc-r2p1
+ - enum:
+ - arm,pl353-smc-r2p1
+ - arm,pl354
- const: arm,primecell
"#address-cells":
@@ -46,30 +53,25 @@ properties:
The three chip select regions are defined in 'ranges'.
clocks:
- items:
- - description: clock for the memory device bus
- - description: main clock of the SMC
+ minItems: 1
+ maxItems: 2
clock-names:
- items:
- - const: memclk
- - const: apb_pclk
+ minItems: 1
+ maxItems: 2
ranges:
minItems: 1
- description: |
- Memory bus areas for interacting with the devices. Reflects
- the memory layout with four integer values following:
- <cs-number> 0 <offset> <size>
- items:
- - description: NAND bank 0
- - description: NOR/SRAM bank 0
- - description: NOR/SRAM bank 1
+ maxItems: 8
- interrupts: true
+ interrupts:
+ minItems: 1
+ items:
+ - description: Combined or Memory interface 0 IRQ
+ - description: Memory interface 1 IRQ
patternProperties:
- "@[0-3],[a-f0-9]+$":
+ "@[0-7],[a-f0-9]+$":
type: object
description: |
The child device node represents the controller connected to the SMC
@@ -87,7 +89,7 @@ patternProperties:
- description: |
Chip-select ID, as in the parent range property.
minimum: 0
- maximum: 2
+ maximum: 7
- description: |
Offset of the memory region requested by the device.
- description: |
@@ -102,12 +104,36 @@ required:
- reg
- clock-names
- clocks
- - "#address-cells"
- - "#size-cells"
- - ranges
additionalProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: arm,pl354
+ then:
+ properties:
+ clocks:
+ # According to TRM, really should be 3 clocks
+ maxItems: 1
+
+ clock-names:
+ const: apb_pclk
+
+ else:
+ properties:
+ clocks:
+ items:
+ - description: clock for the memory device bus
+ - description: main clock of the SMC
+
+ clock-names:
+ items:
+ - const: memclk
+ - const: apb_pclk
+
examples:
- |
smcc: memory-controller@e000e000 {
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-channel.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-channel.yaml
new file mode 100644
index 000000000000..34b5bd153f63
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-channel.yaml
@@ -0,0 +1,146 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr-channel.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPDDR channel with chip/rank topology description
+
+description:
+ An LPDDR channel is a completely independent set of LPDDR pins (DQ, CA, CS,
+ CK, etc.) that connect one or more LPDDR chips to a host system. The main
+ purpose of this node is to overall LPDDR topology of the system, including the
+ amount of individual LPDDR chips and the ranks per chip.
+
+maintainers:
+ - Julius Werner <jwerner@chromium.org>
+
+properties:
+ compatible:
+ enum:
+ - jedec,lpddr2-channel
+ - jedec,lpddr3-channel
+ - jedec,lpddr4-channel
+ - jedec,lpddr5-channel
+
+ io-width:
+ description:
+ The number of DQ pins in the channel. If this number is different
+ from (a multiple of) the io-width of the LPDDR chip, that means that
+ multiple instances of that type of chip are wired in parallel on this
+ channel (with the channel's DQ pins split up between the different
+ chips, and the CA, CS, etc. pins of the different chips all shorted
+ together). This means that the total physical memory controlled by a
+ channel is equal to the sum of the densities of each rank on the
+ connected LPDDR chip, times the io-width of the channel divided by
+ the io-width of the LPDDR chip.
+ enum:
+ - 8
+ - 16
+ - 32
+ - 64
+ - 128
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^rank@[0-9]+$":
+ type: object
+ description:
+ Each physical LPDDR chip may have one or more ranks. Ranks are
+ internal but fully independent sub-units of the chip. Each LPDDR bus
+ transaction on the channel targets exactly one rank, based on the
+ state of the CS pins. Different ranks may have different densities and
+ timing requirements.
+ required:
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: jedec,lpddr2-channel
+ then:
+ patternProperties:
+ "^rank@[0-9]+$":
+ $ref: /schemas/memory-controllers/ddr/jedec,lpddr2.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: jedec,lpddr3-channel
+ then:
+ patternProperties:
+ "^rank@[0-9]+$":
+ $ref: /schemas/memory-controllers/ddr/jedec,lpddr3.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: jedec,lpddr4-channel
+ then:
+ patternProperties:
+ "^rank@[0-9]+$":
+ $ref: /schemas/memory-controllers/ddr/jedec,lpddr4.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: jedec,lpddr5-channel
+ then:
+ patternProperties:
+ "^rank@[0-9]+$":
+ $ref: /schemas/memory-controllers/ddr/jedec,lpddr5.yaml#
+
+required:
+ - compatible
+ - io-width
+ - "#address-cells"
+ - "#size-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ lpddr-channel0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "jedec,lpddr3-channel";
+ io-width = <32>;
+
+ rank@0 {
+ compatible = "lpddr3-ff,0100", "jedec,lpddr3";
+ reg = <0>;
+ density = <8192>;
+ io-width = <16>;
+ revision-id = <1 0>;
+ };
+ };
+
+ lpddr-channel1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "jedec,lpddr4-channel";
+ io-width = <32>;
+
+ rank@0 {
+ compatible = "lpddr4-05,0301", "jedec,lpddr4";
+ reg = <0>;
+ density = <4096>;
+ io-width = <32>;
+ revision-id = <3 1>;
+ };
+
+ rank@1 {
+ compatible = "lpddr4-05,0301", "jedec,lpddr4";
+ reg = <1>;
+ density = <2048>;
+ io-width = <32>;
+ revision-id = <3 1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-props.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-props.yaml
new file mode 100644
index 000000000000..30267ce70124
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr-props.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr-props.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Common properties for LPDDR types
+
+description:
+ Different LPDDR types generally use the same properties and only differ in the
+ range of legal values for each. This file defines the common parts that can be
+ reused for each type. Nodes using this schema should generally be nested under
+ an LPDDR channel node.
+
+maintainers:
+ - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+ compatible:
+ description:
+ Compatible strings can be either explicit vendor names and part numbers
+ (e.g. elpida,ECB240ABACN), or generated strings of the form
+ lpddrX-YY,ZZZZ where X is the LPDDR version, YY is the manufacturer ID
+ (from MR5) and ZZZZ is the revision ID (from MR6 and MR7). Both IDs are
+ formatted in lower case hexadecimal representation with leading zeroes.
+ The latter form can be useful when LPDDR nodes are created at runtime by
+ boot firmware that doesn't have access to static part number information.
+
+ reg:
+ description:
+ The rank number of this LPDDR rank when used as a subnode to an LPDDR
+ channel.
+ minimum: 0
+ maximum: 3
+
+ revision-id:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Revision IDs read from Mode Register 6 and 7. One byte per uint32 cell (i.e. <MR6 MR7>).
+ maxItems: 2
+ items:
+ minimum: 0
+ maximum: 255
+
+ density:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Density in megabits of SDRAM chip. Decoded from Mode Register 8.
+ enum:
+ - 64
+ - 128
+ - 256
+ - 512
+ - 1024
+ - 2048
+ - 3072
+ - 4096
+ - 6144
+ - 8192
+ - 12288
+ - 16384
+ - 24576
+ - 32768
+
+ io-width:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ IO bus width in bits of SDRAM chip. Decoded from Mode Register 8.
+ enum:
+ - 8
+ - 16
+ - 32
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml
index 9d78f140609b..a237bc259273 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml
@@ -9,6 +9,9 @@ title: LPDDR2 SDRAM compliant to JEDEC JESD209-2
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
+allOf:
+ - $ref: jedec,lpddr-props.yaml#
+
properties:
compatible:
oneOf:
@@ -17,13 +20,15 @@ properties:
- elpida,ECB240ABACN
- elpida,B8132B2PB-6D-F
- enum:
- - jedec,lpddr2-s4
- - items:
- - enum:
+ - jedec,lpddr2-nvm
- jedec,lpddr2-s2
+ - jedec,lpddr2-s4
- items:
+ - pattern: "^lpddr2-[0-9a-f]{2},[0-9a-f]{4}$"
- enum:
- jedec,lpddr2-nvm
+ - jedec,lpddr2-s2
+ - jedec,lpddr2-s4
revision-id1:
$ref: /schemas/types.yaml#/definitions/uint32
@@ -41,41 +46,6 @@ properties:
Property is deprecated, use revision-id instead.
deprecated: true
- revision-id:
- $ref: /schemas/types.yaml#/definitions/uint32-array
- description: |
- Revision IDs read from Mode Register 6 and 7. One byte per uint32 cell (i.e. <MR6 MR7>).
- minItems: 2
- maxItems: 2
- items:
- minimum: 0
- maximum: 255
-
- density:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: |
- Density in megabits of SDRAM chip. Obtained from device datasheet.
- enum:
- - 64
- - 128
- - 256
- - 512
- - 1024
- - 2048
- - 4096
- - 8192
- - 16384
- - 32768
-
- io-width:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: |
- IO bus width in bits of SDRAM chip. Obtained from device datasheet.
- enum:
- - 32
- - 16
- - 8
-
tRRD-min-tck:
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 16
@@ -168,7 +138,7 @@ required:
- density
- io-width
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr3.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr3.yaml
index 48908a19473c..e328a1195ba6 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr3.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr3.yaml
@@ -9,35 +9,24 @@ title: LPDDR3 SDRAM compliant to JEDEC JESD209-3
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
+allOf:
+ - $ref: jedec,lpddr-props.yaml#
+
properties:
compatible:
- items:
- - enum:
- - samsung,K3QF2F20DB
- - const: jedec,lpddr3
+ oneOf:
+ - items:
+ - enum:
+ - samsung,K3QF2F20DB
+ - const: jedec,lpddr3
+ - items:
+ - pattern: "^lpddr3-[0-9a-f]{2},[0-9a-f]{4}$"
+ - const: jedec,lpddr3
'#address-cells':
const: 1
deprecated: true
- density:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: |
- Density in megabits of SDRAM chip.
- enum:
- - 4096
- - 8192
- - 16384
- - 32768
-
- io-width:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: |
- IO bus width in bits of SDRAM chip.
- enum:
- - 32
- - 16
-
manufacturer-id:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
@@ -45,15 +34,6 @@ properties:
deprecated, manufacturer should be derived from the compatible.
deprecated: true
- revision-id:
- $ref: /schemas/types.yaml#/definitions/uint32-array
- minItems: 2
- maxItems: 2
- items:
- maximum: 255
- description: |
- Revision value of SDRAM chip read from Mode Registers 6 and 7.
-
'#size-cells':
const: 0
deprecated: true
@@ -206,7 +186,7 @@ required:
- density
- io-width
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr4.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr4.yaml
new file mode 100644
index 000000000000..a078892fecee
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr4.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr4.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPDDR4 SDRAM compliant to JEDEC JESD209-4
+
+maintainers:
+ - Krzysztof Kozlowski <krzk@kernel.org>
+
+allOf:
+ - $ref: jedec,lpddr-props.yaml#
+
+properties:
+ compatible:
+ items:
+ - pattern: "^lpddr4-[0-9a-f]{2},[0-9a-f]{4}$"
+ - const: jedec,lpddr4
+
+required:
+ - compatible
+ - density
+ - io-width
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ lpddr {
+ compatible = "lpddr4-ff,0100", "jedec,lpddr4";
+ density = <8192>;
+ io-width = <16>;
+ revision-id = <1 0>;
+ };
diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr5.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr5.yaml
new file mode 100644
index 000000000000..e441dac5f154
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr5.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr5.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPDDR5 SDRAM compliant to JEDEC JESD209-5
+
+maintainers:
+ - Krzysztof Kozlowski <krzk@kernel.org>
+
+allOf:
+ - $ref: jedec,lpddr-props.yaml#
+
+properties:
+ compatible:
+ items:
+ - pattern: "^lpddr5-[0-9a-f]{2},[0-9a-f]{4}$"
+ - const: jedec,lpddr5
+
+ serial-id:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Serial IDs read from Mode Registers 47 through 54. One byte per uint32
+ cell (i.e. <MR47 MR48 MR49 MR50 MR51 MR52 MR53 MR54>).
+ maxItems: 8
+ items:
+ minimum: 0
+ maximum: 255
+
+required:
+ - compatible
+ - density
+ - io-width
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ lpddr {
+ compatible = "lpddr5-01,0200", "jedec,lpddr5";
+ density = <8192>;
+ io-width = <8>;
+ revision-id = <2 0>;
+ serial-id = <3 1 0 0 0 0 0 0>;
+ };
diff --git a/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml b/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml
new file mode 100644
index 000000000000..53ae995462db
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/mc-peripheral-props.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Peripheral-specific properties for a Memory Controller bus.
+
+description:
+ Many Memory Controllers need to add properties to peripheral devices.
+ They could be common properties like reg or they could be controller
+ specific like delay in clock or data lines, etc. These properties need
+ to be defined in the peripheral node because they are per-peripheral
+ and there can be multiple peripherals attached to a controller. All
+ those properties are listed here. The controller specific properties
+ should go in their own separate schema that should be referenced
+ from here.
+
+maintainers:
+ - Marek Vasut <marex@denx.de>
+
+properties:
+ reg:
+ description: Bank number, base address and size of the device.
+
+ bank-width:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Bank width of the device, in bytes.
+ enum: [1, 2, 4]
+
+required:
+ - reg
+
+# The controller specific properties go here.
+allOf:
+ - $ref: st,stm32-fmc2-ebi-props.yaml#
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
index 645249ea21d1..30a403b1b79a 100644
--- a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
@@ -44,6 +44,11 @@ properties:
- items:
- enum:
+ - renesas,r8a779g0-rpc-if # R-Car V4H
+ - const: renesas,rcar-gen4-rpc-if # a generic R-Car gen4 device
+
+ - items:
+ - enum:
- renesas,r9a07g043-rpc-if # RZ/G2UL
- renesas,r9a07g044-rpc-if # RZ/G2{L,LC}
- renesas,r9a07g054-rpc-if # RZ/V2L
diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi-props.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi-props.yaml
new file mode 100644
index 000000000000..475e4095068c
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi-props.yaml
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/st,stm32-fmc2-ebi-props.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Peripheral properties for ST FMC2 Controller
+
+maintainers:
+ - Christophe Kerello <christophe.kerello@foss.st.com>
+ - Marek Vasut <marex@denx.de>
+
+properties:
+ st,fmc2-ebi-cs-transaction-type:
+ description: |
+ Select one of the transactions type supported
+ 0: Asynchronous mode 1 SRAM/FRAM.
+ 1: Asynchronous mode 1 PSRAM.
+ 2: Asynchronous mode A SRAM/FRAM.
+ 3: Asynchronous mode A PSRAM.
+ 4: Asynchronous mode 2 NOR.
+ 5: Asynchronous mode B NOR.
+ 6: Asynchronous mode C NOR.
+ 7: Asynchronous mode D NOR.
+ 8: Synchronous read synchronous write PSRAM.
+ 9: Synchronous read asynchronous write PSRAM.
+ 10: Synchronous read synchronous write NOR.
+ 11: Synchronous read asynchronous write NOR.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 11
+
+ st,fmc2-ebi-cs-cclk-enable:
+ description: Continuous clock enable (first bank must be configured
+ in synchronous mode). The FMC_CLK is generated continuously
+ during asynchronous and synchronous access. By default, the
+ FMC_CLK is only generated during synchronous access.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-mux-enable:
+ description: Address/Data multiplexed on databus (valid only with
+ NOR and PSRAM transactions type). By default, Address/Data
+ are not multiplexed.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-buswidth:
+ description: Data bus width
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 8, 16 ]
+ default: 16
+
+ st,fmc2-ebi-cs-waitpol-high:
+ description: Wait signal polarity (NWAIT signal active high).
+ By default, NWAIT is active low.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-waitcfg-enable:
+ description: The NWAIT signal indicates wheither the data from the
+ device are valid or if a wait state must be inserted when accessing
+ the device in synchronous mode. By default, the NWAIT signal is
+ active one data cycle before wait state.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-wait-enable:
+ description: The NWAIT signal is enabled (its level is taken into
+ account after the programmed latency period to insert wait states
+ if asserted). By default, the NWAIT signal is disabled.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-asyncwait-enable:
+ description: The NWAIT signal is taken into account during asynchronous
+ transactions. By default, the NWAIT signal is not taken into account
+ during asynchronous transactions.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ st,fmc2-ebi-cs-cpsize:
+ description: CRAM page size. The controller splits the burst access
+ when the memory page is reached. By default, no burst split when
+ crossing page boundary.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 128, 256, 512, 1024 ]
+ default: 0
+
+ st,fmc2-ebi-cs-byte-lane-setup-ns:
+ description: This property configures the byte lane setup timing
+ defined in nanoseconds from NBLx low to Chip Select NEx low.
+
+ st,fmc2-ebi-cs-address-setup-ns:
+ description: This property defines the duration of the address setup
+ phase in nanoseconds used for asynchronous read/write transactions.
+
+ st,fmc2-ebi-cs-address-hold-ns:
+ description: This property defines the duration of the address hold
+ phase in nanoseconds used for asynchronous multiplexed read/write
+ transactions.
+
+ st,fmc2-ebi-cs-data-setup-ns:
+ description: This property defines the duration of the data setup phase
+ in nanoseconds used for asynchronous read/write transactions.
+
+ st,fmc2-ebi-cs-bus-turnaround-ns:
+ description: This property defines the delay in nanoseconds between the
+ end of current read/write transaction and the next transaction.
+
+ st,fmc2-ebi-cs-data-hold-ns:
+ description: This property defines the duration of the data hold phase
+ in nanoseconds used for asynchronous read/write transactions.
+
+ st,fmc2-ebi-cs-clk-period-ns:
+ description: This property defines the FMC_CLK output signal period in
+ nanoseconds.
+
+ st,fmc2-ebi-cs-data-latency-ns:
+ description: This property defines the data latency before reading or
+ writing the first data in nanoseconds.
+
+ st,fmc2-ebi-cs-write-address-setup-ns:
+ description: This property defines the duration of the address setup
+ phase in nanoseconds used for asynchronous write transactions.
+
+ st,fmc2-ebi-cs-write-address-hold-ns:
+ description: This property defines the duration of the address hold
+ phase in nanoseconds used for asynchronous multiplexed write
+ transactions.
+
+ st,fmc2-ebi-cs-write-data-setup-ns:
+ description: This property defines the duration of the data setup
+ phase in nanoseconds used for asynchronous write transactions.
+
+ st,fmc2-ebi-cs-write-bus-turnaround-ns:
+ description: This property defines the delay between the end of current
+ write transaction and the next transaction in nanoseconds.
+
+ st,fmc2-ebi-cs-write-data-hold-ns:
+ description: This property defines the duration of the data hold phase
+ in nanoseconds used for asynchronous write transactions.
+
+ st,fmc2-ebi-cs-max-low-pulse-ns:
+ description: This property defines the maximum chip select low pulse
+ duration in nanoseconds for synchronous transactions. When this timing
+ reaches 0, the controller splits the current access, toggles NE to
+ allow device refresh and restarts a new access.
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml
index 6b516d3895af..d71af02b7f16 100644
--- a/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml
@@ -48,143 +48,7 @@ properties:
patternProperties:
"^.*@[0-4],[a-f0-9]+$":
type: object
-
- properties:
- reg:
- description: Bank number, base address and size of the device.
-
- st,fmc2-ebi-cs-transaction-type:
- description: |
- Select one of the transactions type supported
- 0: Asynchronous mode 1 SRAM/FRAM.
- 1: Asynchronous mode 1 PSRAM.
- 2: Asynchronous mode A SRAM/FRAM.
- 3: Asynchronous mode A PSRAM.
- 4: Asynchronous mode 2 NOR.
- 5: Asynchronous mode B NOR.
- 6: Asynchronous mode C NOR.
- 7: Asynchronous mode D NOR.
- 8: Synchronous read synchronous write PSRAM.
- 9: Synchronous read asynchronous write PSRAM.
- 10: Synchronous read synchronous write NOR.
- 11: Synchronous read asynchronous write NOR.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 0
- maximum: 11
-
- st,fmc2-ebi-cs-cclk-enable:
- description: Continuous clock enable (first bank must be configured
- in synchronous mode). The FMC_CLK is generated continuously
- during asynchronous and synchronous access. By default, the
- FMC_CLK is only generated during synchronous access.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-mux-enable:
- description: Address/Data multiplexed on databus (valid only with
- NOR and PSRAM transactions type). By default, Address/Data
- are not multiplexed.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-buswidth:
- description: Data bus width
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 8, 16 ]
- default: 16
-
- st,fmc2-ebi-cs-waitpol-high:
- description: Wait signal polarity (NWAIT signal active high).
- By default, NWAIT is active low.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-waitcfg-enable:
- description: The NWAIT signal indicates wheither the data from the
- device are valid or if a wait state must be inserted when accessing
- the device in synchronous mode. By default, the NWAIT signal is
- active one data cycle before wait state.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-wait-enable:
- description: The NWAIT signal is enabled (its level is taken into
- account after the programmed latency period to insert wait states
- if asserted). By default, the NWAIT signal is disabled.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-asyncwait-enable:
- description: The NWAIT signal is taken into account during asynchronous
- transactions. By default, the NWAIT signal is not taken into account
- during asynchronous transactions.
- $ref: /schemas/types.yaml#/definitions/flag
-
- st,fmc2-ebi-cs-cpsize:
- description: CRAM page size. The controller splits the burst access
- when the memory page is reached. By default, no burst split when
- crossing page boundary.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 0, 128, 256, 512, 1024 ]
- default: 0
-
- st,fmc2-ebi-cs-byte-lane-setup-ns:
- description: This property configures the byte lane setup timing
- defined in nanoseconds from NBLx low to Chip Select NEx low.
-
- st,fmc2-ebi-cs-address-setup-ns:
- description: This property defines the duration of the address setup
- phase in nanoseconds used for asynchronous read/write transactions.
-
- st,fmc2-ebi-cs-address-hold-ns:
- description: This property defines the duration of the address hold
- phase in nanoseconds used for asynchronous multiplexed read/write
- transactions.
-
- st,fmc2-ebi-cs-data-setup-ns:
- description: This property defines the duration of the data setup phase
- in nanoseconds used for asynchronous read/write transactions.
-
- st,fmc2-ebi-cs-bus-turnaround-ns:
- description: This property defines the delay in nanoseconds between the
- end of current read/write transaction and the next transaction.
-
- st,fmc2-ebi-cs-data-hold-ns:
- description: This property defines the duration of the data hold phase
- in nanoseconds used for asynchronous read/write transactions.
-
- st,fmc2-ebi-cs-clk-period-ns:
- description: This property defines the FMC_CLK output signal period in
- nanoseconds.
-
- st,fmc2-ebi-cs-data-latency-ns:
- description: This property defines the data latency before reading or
- writing the first data in nanoseconds.
-
- st,fmc2_ebi-cs-write-address-setup-ns:
- description: This property defines the duration of the address setup
- phase in nanoseconds used for asynchronous write transactions.
-
- st,fmc2-ebi-cs-write-address-hold-ns:
- description: This property defines the duration of the address hold
- phase in nanoseconds used for asynchronous multiplexed write
- transactions.
-
- st,fmc2-ebi-cs-write-data-setup-ns:
- description: This property defines the duration of the data setup
- phase in nanoseconds used for asynchronous write transactions.
-
- st,fmc2-ebi-cs-write-bus-turnaround-ns:
- description: This property defines the delay between the end of current
- write transaction and the next transaction in nanoseconds.
-
- st,fmc2-ebi-cs-write-data-hold-ns:
- description: This property defines the duration of the data hold phase
- in nanoseconds used for asynchronous write transactions.
-
- st,fmc2-ebi-cs-max-low-pulse-ns:
- description: This property defines the maximum chip select low pulse
- duration in nanoseconds for synchronous transactions. When this timing
- reaches 0, the controller splits the current access, toggles NE to
- allow device refresh and restarts a new access.
-
- required:
- - reg
+ $ref: mc-peripheral-props.yaml#
required:
- "#address-cells"
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti,gpmc-child.yaml b/Documentation/devicetree/bindings/memory-controllers/ti,gpmc-child.yaml
index 6e3995bb1630..4a257fac577e 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ti,gpmc-child.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/ti,gpmc-child.yaml
@@ -230,6 +230,13 @@ properties:
Wait-pin used by client. Must be less than "gpmc,num-waitpins".
$ref: /schemas/types.yaml#/definitions/uint32
+ ti,wait-pin-polarity:
+ description: |
+ Set the desired polarity for the selected wait pin.
+ 0 for active low, 1 for active high.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1]
+
gpmc,wait-on-read:
description: Enables wait monitoring on reads.
type: boolean
diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
index 04962bb29576..3d5efa5578d1 100644
--- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
+++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
@@ -20,19 +20,21 @@ properties:
compatible:
oneOf:
- description:
- For implementations of the EC is connected through I2C.
+ For implementations of the EC connected through I2C.
const: google,cros-ec-i2c
- description:
- For implementations of the EC is connected through SPI.
+ For implementations of the EC connected through SPI.
const: google,cros-ec-spi
- description:
- For implementations of the EC is connected through RPMSG.
+ For implementations of the FPMCU connected through SPI.
+ items:
+ - const: google,cros-ec-fp
+ - const: google,cros-ec-spi
+ - description:
+ For implementations of the EC connected through RPMSG.
const: google,cros-ec-rpmsg
- controller-data:
- description:
- SPI controller data, see bindings/spi/samsung,spi-peripheral-props.yaml
- type: object
+ controller-data: true
google,cros-ec-spi-pre-delay:
description:
@@ -62,8 +64,7 @@ properties:
the SCP.
$ref: "/schemas/types.yaml#/definitions/string"
- spi-max-frequency:
- description: Maximum SPI frequency of the device in Hz.
+ spi-max-frequency: true
reg:
maxItems: 1
@@ -71,6 +72,15 @@ properties:
interrupts:
maxItems: 1
+ reset-gpios:
+ maxItems: 1
+
+ boot0-gpios:
+ maxItems: 1
+ description: Assert for bootloader mode.
+
+ vdd-supply: true
+
wakeup-source:
description: Button can wake-up the system.
@@ -155,18 +165,67 @@ allOf:
- if:
properties:
compatible:
- contains:
- enum:
- - google,cros-ec-i2c
- - google,cros-ec-rpmsg
+ not:
+ contains:
+ const: google,cros-ec-spi
then:
properties:
+ controller-data: false
google,cros-ec-spi-pre-delay: false
google,cros-ec-spi-msg-delay: false
spi-max-frequency: false
else:
$ref: /schemas/spi/spi-peripheral-props.yaml
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ const: google,cros-ec-rpmsg
+ then:
+ properties:
+ mediatek,rpmsg-name: false
+
+ required:
+ - reg
+ - interrupts
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: google,cros-ec-fp
+ then:
+ properties:
+ '#address-cells': false
+ '#size-cells': false
+ typec: false
+ ec-pwm: false
+ kbd-led-backlight: false
+ keyboard-controller: false
+ proximity: false
+ codecs: false
+ cbas: false
+
+ patternProperties:
+ "^i2c-tunnel[0-9]*$": false
+ "^regulator@[0-9]+$": false
+ "^extcon[0-9]*$": false
+
+ # Using additionalProperties: false here and
+ # listing true properties doesn't work
+
+ required:
+ - reset-gpios
+ - boot0-gpios
+ - vdd-supply
+ else:
+ properties:
+ reset-gpios: false
+ boot0-gpios: false
+ vdd-supply: false
+
additionalProperties: false
examples:
@@ -222,4 +281,22 @@ examples:
compatible = "google,cros-ec-rpmsg";
};
};
+
+ # Example for FPMCU
+ - |
+ spi0 {
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+
+ ec@0 {
+ compatible = "google,cros-ec-fp", "google,cros-ec-spi";
+ reg = <0x0>;
+ interrupt-parent = <&gpio_controller>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+ spi-max-frequency = <3000000>;
+ reset-gpios = <&gpio_controller 5 GPIO_ACTIVE_LOW>;
+ boot0-gpios = <&gpio_controller 10 GPIO_ACTIVE_HIGH>;
+ vdd-supply = <&pp3300_fp_mcu>;
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
index 6a3e3ede1ede..a5edab6f2e40 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
@@ -33,6 +33,7 @@ properties:
compatible:
items:
- enum:
+ - qcom,pm6125
- qcom,pm6150
- qcom,pm6150l
- qcom,pm6350
diff --git a/Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt b/Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt
deleted file mode 100644
index 8ef71b4085ca..000000000000
--- a/Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-* Broadcom MIPS (BMIPS) CPUs
-
-Required properties:
-- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380",
- "brcm,bmips5000"
-
-- mips-hpt-frequency: This is common to all CPUs in the system so it lives
- under the "cpus" node.
diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.yaml b/Documentation/devicetree/bindings/mips/brcm/soc.yaml
new file mode 100644
index 000000000000..975945ca2888
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/brcm/soc.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mips/brcm/soc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom cable/DSL/settop platforms
+
+maintainers:
+ - Florian Fainelli <f.fainelli@gmail.com>
+
+description: |
+ Boards Broadcom cable/DSL/settop SoC shall have the following properties.
+ The experimental -viper variants are for running Linux on the 3384's
+ BMIPS4355 cable modem CPU instead of the BMIPS5000 application processor.
+
+properties:
+ $nodename:
+ const: '/'
+
+ compatible:
+ enum:
+ - brcm,bcm3368
+ - brcm,bcm3384
+ - brcm,bcm33843
+ - brcm,bcm3384-viper
+ - brcm,bcm33843-viper
+ - brcm,bcm6328
+ - brcm,bcm6358
+ - brcm,bcm6362
+ - brcm,bcm6368
+ - brcm,bcm63168
+ - brcm,bcm63268
+ - brcm,bcm7125
+ - brcm,bcm7346
+ - brcm,bcm7358
+ - brcm,bcm7360
+ - brcm,bcm7362
+ - brcm,bcm7420
+ - brcm,bcm7425
+
+ cpus:
+ type: object
+ additionalProperties: false
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ mips-hpt-frequency:
+ description: MIPS counter high precision timer frequency.
+ This is common to all CPUs in the system so it lives
+ under the "cpus" node.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ patternProperties:
+ "^cpu@[0-9]$":
+ type: object
+ $ref: /schemas/mips/cpus.yaml#
+ unevaluatedProperties: false
+
+ required:
+ - mips-hpt-frequency
+
+additionalProperties: true
+
+examples:
+ - |
+ / {
+ compatible = "brcm,bcm3368";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ model = "Broadcom 3368";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <150000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/mips/cpus.yaml b/Documentation/devicetree/bindings/mips/cpus.yaml
new file mode 100644
index 000000000000..e991f4c6668d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cpus.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mips/cpus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPS CPUs bindings
+
+maintainers:
+ - Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ - 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+
+description: |
+ The device tree allows to describe the layout of CPUs in a system through
+ the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
+ defining properties for every CPU.
+
+properties:
+ compatible:
+ enum:
+ - brcm,bmips3300
+ - brcm,bmips4350
+ - brcm,bmips4380
+ - brcm,bmips5000
+ - brcm,bmips5200
+ - ingenic,xburst-mxu1.0
+ - ingenic,xburst-fpu1.0-mxu1.1
+ - ingenic,xburst-fpu2.0-mxu2.0
+ - ingenic,xburst2-fpu2.1-mxu2.1-smt
+ - loongson,gs264
+ - mips,m14Kc
+ - mips,mips4Kc
+ - mips,mips4KEc
+ - mips,mips24Kc
+ - mips,mips24KEc
+ - mips,mips74Kc
+ - mips,mips1004Kc
+ - mti,interaptiv
+ - mti,mips24KEc
+ - mti,mips14KEc
+ - mti,mips14Kc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ device_type: true
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - ingenic,xburst-mxu1.0
+ - ingenic,xburst-fpu1.0-mxu1.1
+ - ingenic,xburst-fpu2.0-mxu2.0
+ - ingenic,xburst2-fpu2.1-mxu2.1-smt
+ then:
+ required:
+ - device_type
+ - clocks
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ cpu@0 {
+ compatible = "mips,mips1004Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "mips,mips1004Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ - |
+ // Example 2 (Ingenic CPU)
+ #include <dt-bindings/clock/ingenic,jz4780-cgu.h>
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "ingenic,xburst-fpu1.0-mxu1.1";
+ device_type = "cpu";
+ reg = <0>;
+
+ clocks = <&cgu JZ4780_CLK_CPU>;
+ };
+
+ cpu@1 {
+ compatible = "ingenic,xburst-fpu1.0-mxu1.1";
+ device_type = "cpu";
+ reg = <1>;
+
+ clocks = <&cgu JZ4780_CLK_CORE1>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/mips/ingenic/ingenic,cpu.yaml b/Documentation/devicetree/bindings/mips/ingenic/ingenic,cpu.yaml
deleted file mode 100644
index b7e7fa715437..000000000000
--- a/Documentation/devicetree/bindings/mips/ingenic/ingenic,cpu.yaml
+++ /dev/null
@@ -1,69 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/mips/ingenic/ingenic,cpu.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Bindings for Ingenic XBurst family CPUs
-
-maintainers:
- - 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
-
-description:
- Ingenic XBurst family CPUs shall have the following properties.
-
-properties:
- compatible:
- oneOf:
-
- - description: Ingenic XBurst®1 CPU Cores
- enum:
- - ingenic,xburst-mxu1.0
- - ingenic,xburst-fpu1.0-mxu1.1
- - ingenic,xburst-fpu2.0-mxu2.0
-
- - description: Ingenic XBurst®2 CPU Cores
- enum:
- - ingenic,xburst2-fpu2.1-mxu2.1-smt
-
- reg:
- maxItems: 1
-
- clocks:
- maxItems: 1
-
- device_type: true
-
-required:
- - device_type
- - compatible
- - reg
- - clocks
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/clock/ingenic,jz4780-cgu.h>
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu0: cpu@0 {
- device_type = "cpu";
- compatible = "ingenic,xburst-fpu1.0-mxu1.1";
- reg = <0>;
-
- clocks = <&cgu JZ4780_CLK_CPU>;
- };
-
- cpu1: cpu@1 {
- device_type = "cpu";
- compatible = "ingenic,xburst-fpu1.0-mxu1.1";
- reg = <1>;
-
- clocks = <&cgu JZ4780_CLK_CORE1>;
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
index 4741864da48e..e7ec0c59bca6 100644
--- a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
+++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
@@ -14,9 +14,6 @@ maintainers:
- Maxime Ripard <mripard@kernel.org>
properties:
- "#address-cells": true
- "#size-cells": true
-
compatible:
enum:
- allwinner,sun4i-a10-nand
@@ -49,12 +46,8 @@ properties:
dma-names:
const: rxtx
- pinctrl-names: true
-
patternProperties:
- "^pinctrl-[0-9]+$": true
-
- "^nand@[a-f0-9]+$":
+ "^nand@[a-f0-9]$":
type: object
properties:
reg:
@@ -91,6 +84,29 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/sun6i-rtc.h>
+ #include <dt-bindings/clock/sun8i-a23-a33-ccu.h>
+ #include <dt-bindings/reset/sun8i-a23-a33-ccu.h>
+
+ nand-controller@1c03000 {
+ compatible = "allwinner,sun8i-a23-nand-controller";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_NAND>, <&ccu CLK_NAND>;
+ clock-names = "ahb", "mod";
+ resets = <&ccu RST_BUS_NAND>;
+ reset-names = "ahb";
+ dmas = <&dma 5>;
+ dma-names = "rxtx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins &nand_cs0_pin &nand_rb0_pin>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
...
diff --git a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml
index f013fb976d95..d028269cdbaa 100644
--- a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml
+++ b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml
@@ -35,9 +35,6 @@ properties:
interrupts:
maxItems: 1
- "#address-cells": true
- "#size-cells": true
-
required:
- compatible
- reg
@@ -45,7 +42,7 @@ required:
- clock-names
- interrupts
-additionalProperties: true
+unevaluatedProperties: true
examples:
- |
diff --git a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
index 023f3ef0fa13..e552875040e2 100644
--- a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
+++ b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
@@ -34,20 +34,20 @@ unevaluatedProperties: false
examples:
- |
smcc: memory-controller@e000e000 {
- compatible = "arm,pl353-smc-r2p1", "arm,primecell";
- reg = <0xe000e000 0x0001000>;
- clock-names = "memclk", "apb_pclk";
- clocks = <&clkc 11>, <&clkc 44>;
- ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */
- 0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */
- 0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */
- #address-cells = <2>;
- #size-cells = <1>;
-
- nfc0: nand-controller@0,0 {
- compatible = "arm,pl353-nand-r2p1";
- reg = <0 0 0x1000000>;
- #address-cells = <1>;
- #size-cells = <0>;
- };
+ compatible = "arm,pl353-smc-r2p1", "arm,primecell";
+ reg = <0xe000e000 0x0001000>;
+ clock-names = "memclk", "apb_pclk";
+ clocks = <&clkc 11>, <&clkc 44>;
+ ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */
+ 0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */
+ 0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ nfc0: nand-controller@0,0 {
+ compatible = "arm,pl353-nand-r2p1";
+ reg = <0 0 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index 3aa297c97ab6..50645828ac20 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -45,10 +45,8 @@ Optional properties:
- atmel,rb: an integer identifying the native Ready/Busy pin. Only meaningful
on sama5 SoCs.
-All generic properties described in
-Documentation/devicetree/bindings/mtd/{common,nand}.txt also apply to the NAND
-device node, and NAND partitions should be defined under the NAND node as
-described in Documentation/devicetree/bindings/mtd/partition.txt.
+All generic properties are described in the generic yaml files under
+Documentation/devicetree/bindings/mtd/.
* ECC engine (PMECC) bindings:
diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml
index dd5a64969e37..1571024aa119 100644
--- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml
+++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml
@@ -86,15 +86,15 @@ properties:
minItems: 1
items:
- description: NAND CTLRDY interrupt
- - description: FLASH_DMA_DONE if flash DMA is available
- - description: FLASH_EDU_DONE if EDU is available
+ - description: FLASH_DMA_DONE (if flash DMA is available) or FLASH_EDU_DONE (if EDU is available)
interrupt-names:
minItems: 1
items:
- const: nand_ctlrdy
- - const: flash_dma_done
- - const: flash_edu_done
+ - enum:
+ - flash_dma_done
+ - flash_edu_done
clocks:
maxItems: 1
@@ -173,6 +173,13 @@ allOf:
- const: nand
- const: iproc-idm
- const: iproc-ext
+ - if:
+ properties:
+ interrupts:
+ minItems: 2
+ then:
+ required:
+ - interrupt-names
unevaluatedProperties: false
@@ -184,51 +191,52 @@ required:
examples:
- |
nand-controller@f0442800 {
- compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
- reg = <0xf0442800 0x600>,
- <0xf0443000 0x100>;
- reg-names = "nand", "flash-dma";
- interrupt-parent = <&hif_intr2_intc>;
- interrupts = <24>, <4>;
+ compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
+ reg = <0xf0442800 0x600>,
+ <0xf0443000 0x100>;
+ reg-names = "nand", "flash-dma";
+ interrupt-parent = <&hif_intr2_intc>;
+ interrupts = <24>, <4>;
+ interrupt-names = "nand_ctlrdy", "flash_dma_done";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@1 {
+ compatible = "brcm,nandcs";
+ reg = <1>; // Chip select 1
+ nand-on-flash-bbt;
+ nand-ecc-strength = <12>;
+ nand-ecc-step-size = <512>;
#address-cells = <1>;
- #size-cells = <0>;
-
- nand@1 {
- compatible = "brcm,nandcs";
- reg = <1>; // Chip select 1
- nand-on-flash-bbt;
- nand-ecc-strength = <12>;
- nand-ecc-step-size = <512>;
-
- #address-cells = <1>;
- #size-cells = <1>;
- };
+ #size-cells = <1>;
+ };
};
- |
nand-controller@10000200 {
- compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
- "brcm,brcmnand-v4.0", "brcm,brcmnand";
- reg = <0x10000200 0x180>,
- <0x100000b0 0x10>,
- <0x10000600 0x200>;
- reg-names = "nand", "nand-int-base", "nand-cache";
- interrupt-parent = <&periph_intc>;
- interrupts = <50>;
- clocks = <&periph_clk 20>;
- clock-names = "nand";
+ compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
+ "brcm,brcmnand-v4.0", "brcm,brcmnand";
+ reg = <0x10000200 0x180>,
+ <0x100000b0 0x10>,
+ <0x10000600 0x200>;
+ reg-names = "nand", "nand-int-base", "nand-cache";
+ interrupt-parent = <&periph_intc>;
+ interrupts = <50>;
+ clocks = <&periph_clk 20>;
+ clock-names = "nand";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <1>;
+ nand-ecc-step-size = <512>;
#address-cells = <1>;
- #size-cells = <0>;
-
- nand@0 {
- compatible = "brcm,nandcs";
- reg = <0>;
- nand-on-flash-bbt;
- nand-ecc-strength = <1>;
- nand-ecc-step-size = <512>;
-
- #address-cells = <1>;
- #size-cells = <1>;
- };
+ #size-cells = <1>;
+ };
};
diff --git a/Documentation/devicetree/bindings/mtd/denali,nand.yaml b/Documentation/devicetree/bindings/mtd/denali,nand.yaml
index 1307ed7e7fc6..0be83ad42970 100644
--- a/Documentation/devicetree/bindings/mtd/denali,nand.yaml
+++ b/Documentation/devicetree/bindings/mtd/denali,nand.yaml
@@ -145,6 +145,6 @@ examples:
#size-cells = <0>;
nand@0 {
- reg = <0>;
+ reg = <0>;
};
};
diff --git a/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml b/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml
index 8c272c842bfd..a811a512ecc5 100644
--- a/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml
+++ b/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml
@@ -32,9 +32,9 @@ properties:
partitions:
type: object
+ deprecated: true
description:
Node containing description of fixed partitions.
- See Documentation/devicetree/bindings/mtd/partition.txt
patternProperties:
"^nand@[a-f0-9]$":
@@ -58,78 +58,78 @@ examples:
- |
#include <dt-bindings/clock/ingenic,jz4780-cgu.h>
memory-controller@13410000 {
- compatible = "ingenic,jz4780-nemc";
- reg = <0x13410000 0x10000>;
- #address-cells = <2>;
- #size-cells = <1>;
- ranges = <1 0 0x1b000000 0x1000000>,
- <2 0 0x1a000000 0x1000000>,
- <3 0 0x19000000 0x1000000>,
- <4 0 0x18000000 0x1000000>,
- <5 0 0x17000000 0x1000000>,
- <6 0 0x16000000 0x1000000>;
-
- clocks = <&cgu JZ4780_CLK_NEMC>;
-
- nand-controller@1 {
- compatible = "ingenic,jz4780-nand";
- reg = <1 0 0x1000000>;
-
- #address-cells = <1>;
- #size-cells = <0>;
-
- ecc-engine = <&bch>;
-
- ingenic,nemc-tAS = <10>;
- ingenic,nemc-tAH = <5>;
- ingenic,nemc-tBP = <10>;
- ingenic,nemc-tAW = <15>;
- ingenic,nemc-tSTRV = <100>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&pins_nemc>;
-
- nand@1 {
- reg = <1>;
-
- nand-ecc-step-size = <1024>;
- nand-ecc-strength = <24>;
- nand-ecc-mode = "hw";
- nand-on-flash-bbt;
-
- pinctrl-names = "default";
- pinctrl-0 = <&pins_nemc_cs1>;
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <2>;
- #size-cells = <2>;
-
- partition@0 {
- label = "u-boot-spl";
- reg = <0x0 0x0 0x0 0x800000>;
+ compatible = "ingenic,jz4780-nemc";
+ reg = <0x13410000 0x10000>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <1 0 0x1b000000 0x1000000>,
+ <2 0 0x1a000000 0x1000000>,
+ <3 0 0x19000000 0x1000000>,
+ <4 0 0x18000000 0x1000000>,
+ <5 0 0x17000000 0x1000000>,
+ <6 0 0x16000000 0x1000000>;
+
+ clocks = <&cgu JZ4780_CLK_NEMC>;
+
+ nand-controller@1 {
+ compatible = "ingenic,jz4780-nand";
+ reg = <1 0 0x1000000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ecc-engine = <&bch>;
+
+ ingenic,nemc-tAS = <10>;
+ ingenic,nemc-tAH = <5>;
+ ingenic,nemc-tBP = <10>;
+ ingenic,nemc-tAW = <15>;
+ ingenic,nemc-tSTRV = <100>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pins_nemc>;
+
+ nand@1 {
+ reg = <1>;
+
+ nand-ecc-step-size = <1024>;
+ nand-ecc-strength = <24>;
+ nand-ecc-mode = "hw";
+ nand-on-flash-bbt;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pins_nemc_cs1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ partition@0 {
+ label = "u-boot-spl";
+ reg = <0x0 0x0 0x0 0x800000>;
+ };
+
+ partition@800000 {
+ label = "u-boot";
+ reg = <0x0 0x800000 0x0 0x200000>;
+ };
+
+ partition@a00000 {
+ label = "u-boot-env";
+ reg = <0x0 0xa00000 0x0 0x200000>;
+ };
+
+ partition@c00000 {
+ label = "boot";
+ reg = <0x0 0xc00000 0x0 0x4000000>;
+ };
+
+ partition@4c00000 {
+ label = "system";
+ reg = <0x0 0x4c00000 0x1 0xfb400000>;
+ };
+ };
};
-
- partition@800000 {
- label = "u-boot";
- reg = <0x0 0x800000 0x0 0x200000>;
- };
-
- partition@a00000 {
- label = "u-boot-env";
- reg = <0x0 0xa00000 0x0 0x200000>;
- };
-
- partition@c00000 {
- label = "boot";
- reg = <0x0 0xc00000 0x0 0x4000000>;
- };
-
- partition@4c00000 {
- label = "system";
- reg = <0x0 0x4c00000 0x1 0xfb400000>;
- };
- };
};
- };
};
diff --git a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml
index 741c66ee06c3..8c62c7d3d0cd 100644
--- a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml
+++ b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml
@@ -39,14 +39,8 @@ properties:
- const: tx
- const: rx
- "#address-cells":
- const: 1
-
- "#size-cells":
- const: 0
-
patternProperties:
- "^nand@[a-f0-9]+$":
+ "^nand@[a-f0-9]$":
type: object
properties:
reg:
@@ -67,33 +61,31 @@ required:
- clocks
- dmas
- dma-names
- - "#address-cells"
- - "#size-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
nand-controller@e0f00000 {
- compatible = "intel,lgm-ebunand";
- reg = <0xe0f00000 0x100>,
- <0xe1000000 0x300>,
- <0xe1400000 0x8000>,
- <0xe1c00000 0x1000>,
- <0x17400000 0x4>,
- <0x17c00000 0x4>;
- reg-names = "ebunand", "hsnand", "nand_cs0", "nand_cs1",
- "addr_sel0", "addr_sel1";
- clocks = <&cgu0 125>;
- dmas = <&dma0 8>, <&dma0 9>;
- dma-names = "tx", "rx";
- #address-cells = <1>;
- #size-cells = <0>;
-
- nand@0 {
- reg = <0>;
- nand-ecc-mode = "hw";
- };
+ compatible = "intel,lgm-ebunand";
+ reg = <0xe0f00000 0x100>,
+ <0xe1000000 0x300>,
+ <0xe1400000 0x8000>,
+ <0xe1c00000 0x1000>,
+ <0x17400000 0x4>,
+ <0x17c00000 0x4>;
+ reg-names = "ebunand", "hsnand", "nand_cs0", "nand_cs1",
+ "addr_sel0", "addr_sel1";
+ clocks = <&cgu0 125>;
+ dmas = <&dma0 8>, <&dma0 9>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@0 {
+ reg = <0>;
+ nand-ecc-mode = "hw";
+ };
};
...
diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
index 7149784a36ac..3fe981b14e2c 100644
--- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
+++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
@@ -70,24 +70,17 @@ properties:
be used on such systems, to denote the absence of a reliable reset
mechanism.
- partitions:
- type: object
-
- '#address-cells': true
- '#size-cells': true
-
-patternProperties:
- # Note: use 'partitions' node for new users
- '^partition@':
- type: object
-
- "^otp(-[0-9]+)?$":
- type: object
+ reset-gpios:
+ description:
+ A GPIO line connected to the RESET (active low) signal of the device.
+ If "broken-flash-reset" is present then having this property does not
+ make any difference.
unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
@@ -97,6 +90,7 @@ examples:
reg = <0>;
spi-max-frequency = <40000000>;
m25p,fast-read;
+ reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
};
};
...
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
index 6d60bc3063f5..64c06aa05ac7 100644
--- a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
@@ -19,7 +19,7 @@ accuracy:)
- nxp,wr_low: WR_LOW
Optional subnodes:
-- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml
Example:
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
index d94edc0fc554..39f17630a301 100644
--- a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
@@ -20,7 +20,7 @@ clock speed:)
- nxp,rsetup: Read setup time (R_SETUP)
Optional subnodes:
-- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml
Example:
diff --git a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml
index 8cc2a7ceb5fb..ea9450fe7c9f 100644
--- a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml
+++ b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml
@@ -34,13 +34,13 @@ unevaluatedProperties: false
examples:
- |
spi {
- #address-cells = <1>;
- #size-cells = <0>;
-
- eeram@0 {
- compatible = "microchip,48l640";
- reg = <0>;
- spi-max-frequency = <20000000>;
- };
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeram@0 {
+ compatible = "microchip,48l640";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ };
};
...
diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml
index 82eb4e0f453b..5df94953c34e 100644
--- a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml
+++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml
@@ -13,6 +13,9 @@ description: |
Flash chips (Memory Technology Devices) are often used for solid state
file systems on embedded devices.
+allOf:
+ - $ref: "mtd.yaml#"
+
properties:
compatible:
oneOf:
@@ -121,10 +124,6 @@ properties:
big-endian: true
little-endian: true
-patternProperties:
- '@[0-9a-f]+$':
- $ref: partitions/partition.yaml
-
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/mtd/mtd.yaml b/Documentation/devicetree/bindings/mtd/mtd.yaml
index 3498e485679b..78da129e9985 100644
--- a/Documentation/devicetree/bindings/mtd/mtd.yaml
+++ b/Documentation/devicetree/bindings/mtd/mtd.yaml
@@ -12,7 +12,7 @@ maintainers:
properties:
$nodename:
- pattern: "^flash(@.*)?$"
+ pattern: "^(flash|.*sram)(@.*)?$"
label:
description:
@@ -21,9 +21,28 @@ properties:
based name) in order to ease flash device identification and/or
describe what they are used for.
+ '#address-cells':
+ deprecated: true
+
+ '#size-cells':
+ deprecated: true
+
+ partitions:
+ $ref: /schemas/mtd/partitions/partitions.yaml
+
+ required:
+ - compatible
+
patternProperties:
+ "@[0-9a-f]+$":
+ $ref: partitions/partition.yaml
+ deprecated: true
+
+ "^partition@[0-9a-f]+":
+ $ref: partitions/partition.yaml
+ deprecated: true
+
"^otp(-[0-9]+)?$":
- type: object
$ref: ../nvmem/nvmem.yaml#
description: |
@@ -40,6 +59,7 @@ patternProperties:
required:
- compatible
+# This is a generic file other binding inherit from
additionalProperties: true
examples:
diff --git a/Documentation/devicetree/bindings/mtd/mtk-nand.txt b/Documentation/devicetree/bindings/mtd/mtk-nand.txt
index 4d3ec5e4ff8a..839ea2f93d04 100644
--- a/Documentation/devicetree/bindings/mtd/mtk-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/mtk-nand.txt
@@ -131,7 +131,7 @@ Example:
};
NAND chip optional subnodes:
-- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml
Example:
nand@0 {
diff --git a/Documentation/devicetree/bindings/mtd/nand-chip.yaml b/Documentation/devicetree/bindings/mtd/nand-chip.yaml
index 97ac3a3fbb52..6e2dc025d694 100644
--- a/Documentation/devicetree/bindings/mtd/nand-chip.yaml
+++ b/Documentation/devicetree/bindings/mtd/nand-chip.yaml
@@ -9,6 +9,9 @@ title: NAND Chip and NAND Controller Generic Binding
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
+allOf:
+ - $ref: "mtd.yaml#"
+
description: |
This file covers the generic description of a NAND chip. It implies that the
bus interface should not be taken into account: both raw NAND devices and
@@ -67,4 +70,5 @@ properties:
required:
- reg
+# This file can be referenced by more specific devices (like spi-nands)
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml
index 359a015d4e5a..220aa2c8c0b5 100644
--- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml
+++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml
@@ -51,7 +51,6 @@ properties:
patternProperties:
"^nand@[a-f0-9]$":
- type: object
$ref: "nand-chip.yaml#"
properties:
@@ -130,6 +129,7 @@ required:
- "#address-cells"
- "#size-cells"
+# This is a generic file other binding inherit from and extend
additionalProperties: true
examples:
diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
deleted file mode 100644
index ead90e8274d6..000000000000
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-Flash partitions in device tree
-===============================
-
-Flash devices can be partitioned into one or more functional ranges (e.g. "boot
-code", "nvram", "kernel").
-
-Different devices may be partitioned in a different ways. Some may use a fixed
-flash layout set at production time. Some may use on-flash table that describes
-the geometry and naming/purpose of each functional region. It is also possible
-to see these methods mixed.
-
-To assist system software in locating partitions, we allow describing which
-method is used for a given flash device. To describe the method there should be
-a subnode of the flash device that is named 'partitions'. It must have a
-'compatible' property, which is used to identify the method to use.
-
-When a single partition is represented with a DT node (it depends on a used
-format) it may also be described using above rules ('compatible' and optionally
-some extra properties / subnodes). It allows describing more complex,
-hierarchical (multi-level) layouts and should be used if there is some
-significant relation between partitions or some partition internally uses
-another partitioning method.
-
-Available bindings are listed in the "partitions" subdirectory.
-
-
-Deprecated: partitions defined in flash node
-============================================
-
-For backwards compatibility partitions as direct subnodes of the flash device are
-supported. This use is discouraged.
-NOTE: also for backwards compatibility, direct subnodes that have a compatible
-string are not considered partitions, as they may be used for other bindings.
diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml
index 76c88027b6d2..97618847ee35 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml
@@ -9,6 +9,8 @@ title: ARM Firmware Suite (AFS) Partitions
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
+select: false
+
description: |
The ARM Firmware Suite is a flash partitioning system found on the
ARM reference designs: Integrator AP, Integrator CP, Versatile AB,
diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml
index 7b113e5e3421..5bbb1c01ddee 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml
@@ -17,6 +17,8 @@ description: |
maintainers:
- Rafał Miłecki <rafal@milecki.pl>
+select: false
+
properties:
compatible:
const: brcm,bcm4908-partitions
diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml
index 3484e06d6bcb..939e7b50db22 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml
@@ -35,6 +35,8 @@ description: |
maintainers:
- Rafał Miłecki <rafal@milecki.pl>
+select: false
+
properties:
compatible:
const: brcm,bcm947xx-cfe-partitions
diff --git a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
index ad3ccd250802..331e564f29dc 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
@@ -31,24 +31,17 @@ properties:
patternProperties:
"@[0-9a-f]+$":
- allOf:
- - $ref: "partition.yaml#"
- - if:
- properties:
- compatible:
- contains:
- const: sercomm,sc-partitions
- then:
- properties:
- sercomm,scpart-id:
- description: Partition id in Sercomm partition map. Mtd
- parser uses this id to find a record in the partition map
- containing offset and size of the current partition. The
- values from partition map overrides partition offset and
- size defined in reg property of the dts. Frequently these
- values are the same, but may differ if device has bad
- eraseblocks on a flash.
- $ref: /schemas/types.yaml#/definitions/uint32
+ $ref: partition.yaml#
+
+ properties:
+ sercomm,scpart-id:
+ description: Partition id in Sercomm partition map. Mtd parser
+ uses this id to find a record in the partition map containing
+ offset and size of the current partition. The values from
+ partition map overrides partition offset and size defined in
+ reg property of the dts. Frequently these values are the same,
+ but may differ if device has bad eraseblocks on a flash.
+ $ref: /schemas/types.yaml#/definitions/uint32
required:
- "#address-cells"
@@ -84,6 +77,7 @@ examples:
partition@0 {
label = "filesystem";
reg = <0x00000000 0x1 0x00000000>;
+ linux,rootfs;
};
};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
index 99249cdfbfb3..213858f60375 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
@@ -18,6 +18,8 @@ description: |
maintainers:
- Rafał Miłecki <rafal@milecki.pl>
+select: false
+
properties:
compatible:
const: linksys,ns-partitions
diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
index 5cdd2efa9132..5474d63268dc 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -17,6 +17,7 @@ maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
allOf:
+ - $ref: /schemas/mtd/partitions/partition.yaml#
- $ref: /schemas/nvmem/nvmem.yaml#
properties:
@@ -26,7 +27,7 @@ properties:
required:
- compatible
-additionalProperties: true
+unevaluatedProperties: false
examples:
- |
@@ -84,7 +85,6 @@ examples:
compatible = "nvmem-cells";
label = "calibration";
reg = <0xf00000 0x100000>;
- ranges = <0 0xf00000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/mtd/partitions/partition.yaml b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml
index f1a02d840b12..cdffbb9cedc2 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/partition.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml
@@ -52,6 +52,10 @@ properties:
immune to paired-pages corruptions
type: boolean
+ linux,rootfs:
+ description: Marks partition that contains root filesystem to mount and boot
+ user space from
+
if:
not:
required: [ reg ]
@@ -60,4 +64,5 @@ then:
$nodename:
pattern: '^partition-.*$'
+# This is a generic file other binding inherit from and extend
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml
new file mode 100644
index 000000000000..9aca4e6c6047
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Partitions
+
+description: |
+ This binding is generic and describes the content of the partitions container
+ node. All partition parsers must be referenced here.
+
+maintainers:
+ - Miquel Raynal <miquel.raynal@bootlin.com>
+
+oneOf:
+ - $ref: arm,arm-firmware-suite.yaml
+ - $ref: brcm,bcm4908-partitions.yaml
+ - $ref: brcm,bcm947xx-cfe-partitions.yaml
+ - $ref: fixed-partitions.yaml
+ - $ref: linksys,ns-partitions.yaml
+ - $ref: qcom,smem-part.yaml
+ - $ref: redboot-fis.yaml
+
+properties:
+ compatible: true
+
+ '#address-cells':
+ enum: [1, 2]
+
+ '#size-cells':
+ enum: [1, 2]
+
+patternProperties:
+ "partition(-.+|@[0-9a-f]+)":
+ $ref: partition.yaml
+
+required:
+ - compatible
+
+unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml b/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml
index dc07909af023..61d12bda356e 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml
@@ -15,13 +15,15 @@ description: |
varies between partition table revisions. V3 supports maximum 16 partitions
and V4 supports 48 partitions.
+select: false
+
properties:
compatible:
const: qcom,smem-part
patternProperties:
"^partition-[0-9a-z]+$":
- $ref: partition.yaml#
+ $ref: nvmem-cells.yaml
required:
- compatible
@@ -39,22 +41,22 @@ examples:
- |
/* Example declaring dynamic partition */
flash {
- partitions {
- compatible = "qcom,smem-part";
-
- partition-art {
- compatible = "nvmem-cells";
- #address-cells = <1>;
- #size-cells = <1>;
- label = "0:art";
-
- macaddr_art_0: macaddr@0 {
- reg = <0x0 0x6>;
- };
-
- macaddr_art_6: macaddr@6 {
- reg = <0x6 0x6>;
- };
+ partitions {
+ compatible = "qcom,smem-part";
+
+ partition-art {
+ compatible = "nvmem-cells";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "0:art";
+
+ macaddr_art_0: macaddr@0 {
+ reg = <0x0 0x6>;
+ };
+
+ macaddr_art_6: macaddr@6 {
+ reg = <0x6 0x6>;
+ };
+ };
};
- };
};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml
index fee8d81b5276..ba7445cd69e8 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml
@@ -16,6 +16,8 @@ description: The FLASH Image System (FIS) directory is a flash description
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
+select: false
+
properties:
compatible:
const: redboot-fis
@@ -26,6 +28,10 @@ properties:
device. On a flash memory with 32KB eraseblocks, 0 means the first
eraseblock at 0x00000000, 1 means the second eraseblock at 0x00008000 and so on.
+ '#address-cells': false
+
+ '#size-cells': false
+
required:
- compatible
- fis-index-block
diff --git a/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml
new file mode 100644
index 000000000000..a24bbaac3a90
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/tplink,safeloader-partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TP-Link SafeLoader partitions
+
+description: |
+ TP-Link home routers store various data on flash (e.g. bootloader,
+ flash layout, firmware, product info, configuration, calibration
+ data). That requires flash partitioning.
+
+ Flash space layout of TP-Link devices is stored on flash itself using
+ a custom ASCII-based format. That format was first found in TP-Link
+ devices with a custom SafeLoader bootloader. Later it was adapted to
+ CFE and U-Boot bootloaders.
+
+ Partitions specified in partitions table cover whole flash space. Some
+ contain static data that shouldn't get modified (device's MAC or WiFi
+ calibration data). Others are semi-static (like kernel). Finally some
+ partitions contain fully changeable content (like rootfs).
+
+ This binding describes partitioning method and defines offset of ASCII
+ based partitions table. That offset is picked at manufacturing process
+ and doesn't change.
+
+maintainers:
+ - Rafał Miłecki <rafal@milecki.pl>
+
+properties:
+ compatible:
+ const: tplink,safeloader-partitions
+
+ partitions-table-offset:
+ description: Flash offset of partitions table
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+patternProperties:
+ "^partition-.*$":
+ $ref: partition.yaml#
+
+required:
+ - partitions-table-offset
+
+additionalProperties: false
+
+examples:
+ - |
+ partitions {
+ compatible = "tplink,safeloader-partitions";
+ partitions-table-offset = <0x100000>;
+
+ partition-file-system {
+ linux,rootfs;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
index 482a2c068740..07024ee45951 100644
--- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
+++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
@@ -31,9 +31,6 @@ properties:
- const: core
- const: aon
- "#address-cells": true
- "#size-cells": true
-
patternProperties:
"^nand@[a-f0-9]$":
type: object
@@ -139,85 +136,85 @@ examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
nand-controller@1ac00000 {
- compatible = "qcom,ipq806x-nand";
- reg = <0x1ac00000 0x800>;
+ compatible = "qcom,ipq806x-nand";
+ reg = <0x1ac00000 0x800>;
- clocks = <&gcc EBI2_CLK>,
- <&gcc EBI2_AON_CLK>;
- clock-names = "core", "aon";
+ clocks = <&gcc EBI2_CLK>,
+ <&gcc EBI2_AON_CLK>;
+ clock-names = "core", "aon";
- dmas = <&adm_dma 3>;
- dma-names = "rxtx";
- qcom,cmd-crci = <15>;
- qcom,data-crci = <3>;
+ dmas = <&adm_dma 3>;
+ dma-names = "rxtx";
+ qcom,cmd-crci = <15>;
+ qcom,data-crci = <3>;
- #address-cells = <1>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
- nand@0 {
- reg = <0>;
+ nand@0 {
+ reg = <0>;
- nand-ecc-strength = <4>;
- nand-bus-width = <8>;
+ nand-ecc-strength = <4>;
+ nand-bus-width = <8>;
- qcom,boot-partitions = <0x0 0x58a0000>;
+ qcom,boot-partitions = <0x0 0x58a0000>;
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
- partition@0 {
- label = "boot-nand";
- reg = <0 0x58a0000>;
- };
+ partition@0 {
+ label = "boot-nand";
+ reg = <0 0x58a0000>;
+ };
- partition@58a0000 {
- label = "fs-nand";
- reg = <0x58a0000 0x4000000>;
- };
+ partition@58a0000 {
+ label = "fs-nand";
+ reg = <0x58a0000 0x4000000>;
+ };
+ };
};
- };
};
#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
nand-controller@79b0000 {
- compatible = "qcom,ipq4019-nand";
- reg = <0x79b0000 0x1000>;
-
- clocks = <&gcc GCC_QPIC_CLK>,
- <&gcc GCC_QPIC_AHB_CLK>;
- clock-names = "core", "aon";
-
- dmas = <&qpicbam 0>,
- <&qpicbam 1>,
- <&qpicbam 2>;
- dma-names = "tx", "rx", "cmd";
-
- #address-cells = <1>;
- #size-cells = <0>;
-
- nand@0 {
- reg = <0>;
- nand-ecc-strength = <4>;
- nand-bus-width = <8>;
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "boot-nand";
- reg = <0 0x58a0000>;
- };
-
- partition@58a0000 {
- label = "fs-nand";
- reg = <0x58a0000 0x4000000>;
- };
+ compatible = "qcom,ipq4019-nand";
+ reg = <0x79b0000 0x1000>;
+
+ clocks = <&gcc GCC_QPIC_CLK>,
+ <&gcc GCC_QPIC_AHB_CLK>;
+ clock-names = "core", "aon";
+
+ dmas = <&qpicbam 0>,
+ <&qpicbam 1>,
+ <&qpicbam 2>;
+ dma-names = "tx", "rx", "cmd";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@0 {
+ reg = <0>;
+ nand-ecc-strength = <4>;
+ nand-bus-width = <8>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "boot-nand";
+ reg = <0 0x58a0000>;
+ };
+
+ partition@58a0000 {
+ label = "fs-nand";
+ reg = <0x58a0000 0x4000000>;
+ };
+ };
};
- };
};
...
diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
index d681a4676f06..566f330851f7 100644
--- a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
+++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
@@ -19,7 +19,9 @@ properties:
- const: rockchip,rk2928-nfc
- const: rockchip,rv1108-nfc
- items:
- - const: rockchip,rk3036-nfc
+ - enum:
+ - rockchip,rk3036-nfc
+ - rockchip,rk3128-nfc
- const: rockchip,rk2928-nfc
- items:
- const: rockchip,rk3308-nfc
diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml
index eab8ea3da1fa..8cbfa1504a0f 100644
--- a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml
+++ b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml
@@ -101,31 +101,32 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
+
nand-controller@58002000 {
- compatible = "st,stm32mp15-fmc2";
- reg = <0x58002000 0x1000>,
- <0x80000000 0x1000>,
- <0x88010000 0x1000>,
- <0x88020000 0x1000>,
- <0x81000000 0x1000>,
- <0x89010000 0x1000>,
- <0x89020000 0x1000>;
- interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>,
- <&mdma1 20 0x2 0x12000a08 0x0 0x0>,
- <&mdma1 21 0x2 0x12000a0a 0x0 0x0>;
- dma-names = "tx", "rx", "ecc";
- clocks = <&rcc FMC_K>;
- resets = <&rcc FMC_R>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- nand@0 {
- reg = <0>;
- nand-on-flash-bbt;
+ compatible = "st,stm32mp15-fmc2";
+ reg = <0x58002000 0x1000>,
+ <0x80000000 0x1000>,
+ <0x88010000 0x1000>,
+ <0x88020000 0x1000>,
+ <0x81000000 0x1000>,
+ <0x89010000 0x1000>,
+ <0x89020000 0x1000>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>,
+ <&mdma1 20 0x2 0x12000a08 0x0 0x0>,
+ <&mdma1 21 0x2 0x12000a0a 0x0 0x0>;
+ dma-names = "tx", "rx", "ecc";
+ clocks = <&rcc FMC_K>;
+ resets = <&rcc FMC_R>;
#address-cells = <1>;
- #size-cells = <1>;
- };
+ #size-cells = <0>;
+
+ nand@0 {
+ reg = <0>;
+ nand-on-flash-bbt;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
};
...
diff --git a/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml b/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml
index 30b458c41cac..4774c92e7fc4 100644
--- a/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml
+++ b/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml
@@ -44,26 +44,26 @@ additionalProperties: false
examples:
- |
bus {
- #address-cells = <2>;
- #size-cells = <2>;
-
- hbmc: memory-controller@47034000 {
- compatible = "ti,am654-hbmc";
- reg = <0x0 0x47034000 0x0 0x100>,
- <0x5 0x00000000 0x1 0x0000000>;
- ranges = <0x0 0x0 0x5 0x00000000 0x4000000>, /* CS0 - 64MB */
- <0x1 0x0 0x5 0x04000000 0x4000000>; /* CS1 - 64MB */
- clocks = <&k3_clks 102 0>;
#address-cells = <2>;
- #size-cells = <1>;
- power-domains = <&k3_pds 55>;
- mux-controls = <&hbmc_mux 0>;
+ #size-cells = <2>;
- flash@0,0 {
- compatible = "cypress,hyperflash", "cfi-flash";
- reg = <0x0 0x0 0x4000000>;
- #address-cells = <1>;
+ hbmc: memory-controller@47034000 {
+ compatible = "ti,am654-hbmc";
+ reg = <0x0 0x47034000 0x0 0x100>,
+ <0x5 0x00000000 0x1 0x0000000>;
+ ranges = <0x0 0x0 0x5 0x00000000 0x4000000>, /* CS0 - 64MB */
+ <0x1 0x0 0x5 0x04000000 0x4000000>; /* CS1 - 64MB */
+ clocks = <&k3_clks 102 0>;
+ #address-cells = <2>;
#size-cells = <1>;
+ power-domains = <&k3_pds 55>;
+ mux-controls = <&hbmc_mux 0>;
+
+ flash@0,0 {
+ compatible = "cypress,hyperflash", "cfi-flash";
+ reg = <0x0 0x0 0x4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
};
- };
};
diff --git a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml
index a953f7397c40..8a79ad300216 100644
--- a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml
+++ b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml
@@ -15,6 +15,9 @@ description:
as child nodes of the GPMC controller.
properties:
+ $nodename:
+ pattern: "^onenand@[0-9],[0,9]$"
+
compatible:
const: ti,omap2-onenand
diff --git a/Documentation/devicetree/bindings/net/engleder,tsnep.yaml b/Documentation/devicetree/bindings/net/engleder,tsnep.yaml
index 5bd964a46a9d..a6921e805e37 100644
--- a/Documentation/devicetree/bindings/net/engleder,tsnep.yaml
+++ b/Documentation/devicetree/bindings/net/engleder,tsnep.yaml
@@ -47,7 +47,7 @@ properties:
nvmem-cells: true
- nvmem-cells-names: true
+ nvmem-cell-names: true
phy-connection-type:
enum:
diff --git a/Documentation/devicetree/bindings/net/micrel,ks8851.yaml b/Documentation/devicetree/bindings/net/micrel,ks8851.yaml
index 5aa7cf2eacb1..b44d83554ef5 100644
--- a/Documentation/devicetree/bindings/net/micrel,ks8851.yaml
+++ b/Documentation/devicetree/bindings/net/micrel,ks8851.yaml
@@ -44,6 +44,7 @@ required:
allOf:
- $ref: ethernet-controller.yaml#
+ - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
- if:
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.yaml b/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.yaml
index e374aa7891ae..ec20e33d9b8f 100644
--- a/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.yaml
+++ b/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.yaml
@@ -11,14 +11,18 @@ maintainers:
properties:
compatible:
- enum:
- - fsl,imx6q-snvs-lpgpr
- - fsl,imx6ul-snvs-lpgpr
- - fsl,imx7d-snvs-lpgpr
- - fsl,imx8mm-snvs-lpgpr
- - fsl,imx8mn-snvs-lpgpr
- - fsl,imx8mp-snvs-lpgpr
- - fsl,imx8mq-snvs-lpgpr
+ oneOf:
+ - items:
+ - enum:
+ - fsl,imx8mm-snvs-lpgpr
+ - fsl,imx8mn-snvs-lpgpr
+ - fsl,imx8mp-snvs-lpgpr
+ - fsl,imx8mq-snvs-lpgpr
+ - const: fsl,imx7d-snvs-lpgpr
+ - enum:
+ - fsl,imx6q-snvs-lpgpr
+ - fsl,imx6ul-snvs-lpgpr
+ - fsl,imx7d-snvs-lpgpr
required:
- compatible
diff --git a/Documentation/devicetree/bindings/opp/opp-v2-base.yaml b/Documentation/devicetree/bindings/opp/opp-v2-base.yaml
index 66d0ec763f0b..cf9c2f7bddc2 100644
--- a/Documentation/devicetree/bindings/opp/opp-v2-base.yaml
+++ b/Documentation/devicetree/bindings/opp/opp-v2-base.yaml
@@ -108,7 +108,7 @@ patternProperties:
The power for the OPP in micro-Watts.
Entries for multiple regulators shall be provided in the same field
- separated by angular brackets <>. If current values aren't required
+ separated by angular brackets <>. If power values aren't required
for a regulator, then it shall be filled with 0. If power values
aren't required for any of the regulators, then this field is not
required. The OPP binding doesn't provide any provisions to relate the
@@ -230,9 +230,9 @@ patternProperties:
minItems: 1
maxItems: 8 # Should be enough regulators
- '^opp-microwatt':
+ '^opp-microwatt-':
description:
- Named opp-microwatt property. Similar to opp-microamp property,
+ Named opp-microwatt property. Similar to opp-microamp-<name> property,
but for microwatt instead.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
diff --git a/Documentation/devicetree/bindings/opp/opp-v2.yaml b/Documentation/devicetree/bindings/opp/opp-v2.yaml
index eaf8fba2c691..2f05920fce79 100644
--- a/Documentation/devicetree/bindings/opp/opp-v2.yaml
+++ b/Documentation/devicetree/bindings/opp/opp-v2.yaml
@@ -155,7 +155,7 @@ examples:
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1025000>;
opp-microamp = <90000>;
- lock-latency-ns = <290000>;
+ clock-latency-ns = <290000>;
turbo-mode;
};
};
diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.yaml b/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.yaml
index 75da3e8eecb9..fe81d52c7277 100644
--- a/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.yaml
@@ -27,6 +27,7 @@ properties:
- nvidia,tegra234-pcie
reg:
+ minItems: 4
items:
- description: controller's application logic registers
- description: configuration registers
@@ -35,13 +36,16 @@ properties:
available for software access.
- description: aperture where the Root Port's own configuration
registers are available.
+ - description: aperture to access the configuration space through ECAM.
reg-names:
+ minItems: 4
items:
- const: appl
- const: config
- const: atu_dma
- const: dbi
+ - const: ecam
interrupts:
items:
@@ -202,6 +206,31 @@ properties:
allOf:
- $ref: /schemas/pci/snps,dw-pcie.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra194-pcie
+ then:
+ properties:
+ reg:
+ maxItems: 4
+ reg-names:
+ maxItems: 4
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra234-pcie
+ then:
+ properties:
+ reg:
+ minItems: 5
+ reg-names:
+ minItems: 5
unevaluatedProperties: false
@@ -305,8 +334,9 @@ examples:
reg = <0x00 0x14160000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x36000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x36040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x36080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x36080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x24 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
index 7287d395e1b6..7e0b015f1414 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
@@ -35,7 +35,7 @@ properties:
maxItems: 5
items:
enum: [ dbi, dbi2, config, atu, atu_dma, app, appl, elbi, mgmt, ctrl,
- parf, cfg, link, ulreg, smu, mpu, apb, phy ]
+ parf, cfg, link, ulreg, smu, mpu, apb, phy, ecam ]
num-lanes:
description: |
diff --git a/Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml b/Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
new file mode 100644
index 000000000000..50f46a6898b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/amlogic,g12-ddr-pmu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic G12 DDR performance monitor
+
+maintainers:
+ - Jiucheng Xu <jiucheng.xu@amlogic.com>
+
+description: |
+ Amlogic G12 series SoC integrate DDR bandwidth monitor.
+ A timer is inside and can generate interrupt when timeout.
+ The bandwidth is counted in the timer ISR. Different platform
+ has different subset of event format attribute.
+
+properties:
+ compatible:
+ enum:
+ - amlogic,g12a-ddr-pmu
+ - amlogic,g12b-ddr-pmu
+ - amlogic,sm1-ddr-pmu
+
+ reg:
+ items:
+ - description: DMC bandwidth register space.
+ - description: DMC PLL register space.
+
+ interrupts:
+ items:
+ - description: The IRQ of the inside timer timeout.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ pmu {
+ #address-cells=<2>;
+ #size-cells=<2>;
+
+ pmu@ff638000 {
+ compatible = "amlogic,g12a-ddr-pmu";
+ reg = <0x0 0xff638000 0x0 0x100>,
+ <0x0 0xff638c00 0x0 0x100>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-pinmux-common.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-pinmux-common.yaml
new file mode 100644
index 000000000000..96c608bcb87e
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-pinmux-common.yaml
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra-pinmux-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra Pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jonathan Hunter <jonathanh@nvidia.com>
+
+description: |
+ 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".
+
+ Tegra's 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, tristate, drive strength,
+ etc.
+
+ 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 or tristate parameter. For this
+ reason, even seemingly boolean values are actually tristates in this
+ binding: unspecified, off, or on. Unspecified is represented as an absent
+ property, and off/on are represented as integer values 0 and 1.
+
+ Note that many of these properties are only valid for certain specific pins
+ or groups. See the Tegra TRM and various pinmux spreadsheets for complete
+ details regarding which groups support which functionality. The Linux
+ pinctrl driver may also be a useful reference, since it consolidates,
+ disambiguates, and corrects data from all those sources.
+
+properties:
+ nvidia,pins:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ description: An array of strings. Each string contains the name of a pin
+ or group. Valid values for these names are listed below.
+
+ nvidia,function:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: A string containing the name of the function to mux to the
+ pin or group. Valid values for function names are listed below. See the
+ Tegra TRM to determine which are valid for each pin or group.
+
+ nvidia,pull:
+ description: Pull-down/up setting to apply to the pin.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: none
+ const: 0
+ - description: down
+ const: 1
+ - description: up
+ const: 2
+
+ nvidia,tristate:
+ description: Tristate setting to apply to the pin.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: drive
+ const: 0
+ - description: tristate
+ const: 1
+
+ nvidia,schmitt:
+ description: Enable Schmitt trigger on the input.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: disable Schmitt trigger on the input
+ const: 0
+ - description: enable Schmitt trigger on the input
+ const: 1
+
+ nvidia,pull-down-strength:
+ description: Controls drive strength. 0 is weakest. The range of valid
+ values depends on the pingroup. See "CAL_DRVDN" in the Tegra TRM.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ nvidia,pull-up-strength:
+ description: Controls drive strength. 0 is weakest. The range of valid
+ values depends on the pingroup. See "CAL_DRVUP" in the Tegra TRM.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ nvidia,high-speed-mode:
+ description: Enable high speed mode the pins.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: normal speed mode
+ const: 0
+ - description: high speed mode
+ const: 1
+
+ nvidia,low-power-mode:
+ description: Controls the drive power or current. Valid values are from 0
+ through 3, where 0 specifies the least power and 3 specifies the most
+ power. See "Low Power Mode" or "LPMD1" and "LPMD0" in the Tegra TRM.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1, 2, 3 ]
+
+ nvidia,enable-input:
+ description: Enable the pin's input path.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: disable input (i.e. output only)
+ const: 0
+ - description: enable input
+ const: 1
+
+ nvidia,open-drain:
+ description: Open-drain configuration for the pin.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: disable open-drain
+ const: 0
+ - description: enable open-drain
+ const: 1
+
+ nvidia,lock:
+ description: Lock the pin configuration against further changes until
+ reset.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: disable pin configuration lock
+ const: 0
+ - description: enable pin configuration lock
+ const: 1
+
+ nvidia,io-reset:
+ description: reset the I/O path
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1 ]
+
+ nvidia,rcv-sel:
+ description: select VIL/VIH receivers
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: normal receivers
+ const: 0
+ - description: high-voltage receivers
+ const: 1
+
+ nvidia,drive-type:
+ description: Drive type to configure for the pin.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1, 2, 3 ]
+
+ nvidia,io-hv:
+ description: Select high-voltage receivers.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ oneOf:
+ - description: Use normal receivers.
+ const: 0
+ - description: Use high-voltage receivers.
+ const: 1
+
+ nvidia,slew-rate-rising:
+ description: Controls rising signal slew rate. 0 is fastest. The range of
+ valid values depends on the pingroup. See "DRVDN_SLWR" in the Tegra TRM.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ nvidia,slew-rate-falling:
+ description: Controls falling signal slew rate. 0 is fastest. The range of
+ valid values depends on the pingroup. See "DRVUP_SLWF" in the Tegra TRM.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+additionalProperties: true
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt
deleted file mode 100644
index fb70856c5b51..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt
+++ /dev/null
@@ -1,131 +0,0 @@
-NVIDIA Tegra114 pinmux controller
-
-The Tegra114 pinctrl binding is very similar to the Tegra20 and Tegra30
-pinctrl binding, as described in nvidia,tegra20-pinmux.txt and
-nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as
-a baseline, and only documents the differences between the two bindings.
-
-Required properties:
-- compatible: "nvidia,tegra114-pinmux"
-- reg: Should contain the register physical address and length for each of
- the pad control and mux registers. The first bank of address must be the
- driver strength pad control register address and second bank address must
- be pinmux register address.
-
-Tegra114 adds the following optional properties for pin configuration subnodes:
-- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes.
-- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes.
-- nvidia,lock: Integer. Lock the pin configuration against further changes
- until reset. 0: no, 1: yes.
-- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes.
-- nvidia,rcv-sel: Integer. Select VIL/VIH receivers. 0: normal, 1: high.
-- nvidia,drive-type: Integer. Valid range 0...3.
-
-As with Tegra20 and Terga30, see the Tegra TRM for complete details regarding
-which groups support which functionality.
-
-Valid values for pin and group names are:
-
- per-pin mux groups:
-
- These all support nvidia,function, nvidia,tristate, nvidia,pull,
- nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain,
- nvidia,io-reset and nvidia,rcv-sel.
-
- ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4,
- ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0,
- ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0,
- dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0,
- sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6,
- sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4,
- ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6,
- uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1,
- uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_sda_pc5,
- gen1_i2c_scl_pc4, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7,
- clk3_out_pee0, clk3_req_pee1, gmi_wp_n_pc7, gmi_iordy_pi5, gmi_wait_pi7,
- gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs0_n_pj0, gmi_cs1_n_pj2, gmi_cs2_n_pk3,
- gmi_cs3_n_pk4, gmi_cs4_n_pk2, gmi_cs6_n_pi3, gmi_cs7_n_pi6, gmi_ad0_pg0,
- gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5,
- gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
- gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7,
- gmi_a16_pj7, gmi_a17_pb0, gmi_a18_pb1, gmi_a19_pk7, gmi_wr_n_pi0,
- gmi_oe_n_pi1, gmi_dqs_p_pj3, gmi_rst_n_pi4, gen2_i2c_scl_pt5,
- gen2_i2c_sda_pt6, sdmmc4_clk_pcc4, sdmmc4_cmd_pt7, sdmmc4_dat0_paa0,
- sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4,
- sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, cam_mclk_pcc0,
- pcc1, pbb0, cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6,
- pbb7, pcc2, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1,
- kb_row2_pr2, kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6,
- kb_row7_pr7, kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_col0_pq0,
- kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
- kb_col6_pq6, kb_col7_pq7, clk_32k_out_pa0, sys_clk_req_pz5, core_pwr_req,
- cpu_pwr_req, pwr_int_n, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2,
- dap1_sclk_pn3, clk1_req_pee2, clk1_out_pw4, spdif_in_pk6, spdif_out_pk5,
- dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, dvfs_pwm_px0,
- gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2, gpio_x4_aud_px4,
- gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7, sdmmc3_clk_pa6,
- sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, sdmmc3_dat2_pb5,
- sdmmc3_dat3_pb4, hdmi_cec_pee3, sdmmc1_wp_n_pv3, sdmmc3_cd_n_pv2,
- gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4, usb_vbus_en1_pn5,
- sdmmc3_clk_lb_in_pee5, sdmmc3_clk_lb_out_pee4, reset_out_n.
-
- drive groups:
-
- These all support nvidia,pull-down-strength, nvidia,pull-up-strength,
- nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all
- support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode
- and nvidia,drive-type.
-
- ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4,
- dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg,
- gmh, owr, uda.
-
-Valid values for nvidia,functions are:
-
- blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya,
- displaya_alt, displayb, dtv, emc_dll, extperiph1, extperiph2,
- extperiph3, gmi, gmi_alt, hda, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr,
- i2s0, i2s1, i2s2, i2s3, i2s4, irda, kbc, nand, nand_alt, owr, pmi,
- pwm0, pwm1, pwm2, pwm3, pwron, reset_out_n, rsvd1, rsvd2, rsvd3,
- rsvd4, sdmmc1, sdmmc2, sdmmc3, sdmmc4, soc, spdif, spi1, spi2, spi3,
- spi4, spi5, spi6, sysclk, trace, uarta, uartb, uartc, uartd, ulpi,
- usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, vi, vi_alt1, vi_alt3
-
-Example:
-
- pinmux: pinmux {
- compatible = "nvidia,tegra114-pinmux";
- reg = <0x70000868 0x148 /* Pad control registers */
- 0x70003000 0x40c>; /* PinMux registers */
- };
-
-Example board file extract:
-
- pinctrl {
- sdmmc4_default: pinmux {
- sdmmc4_clk_pcc4 {
- nvidia,pins = "sdmmc4_clk_pcc4",
- nvidia,function = "sdmmc4";
- nvidia,pull = <0>;
- nvidia,tristate = <0>;
- };
- 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,function = "sdmmc4";
- nvidia,pull = <2>;
- nvidia,tristate = <0>;
- };
- };
- };
-
- sdhci@78000400 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc4_default>;
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.yaml
new file mode 100644
index 000000000000..065dedb3573a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.yaml
@@ -0,0 +1,155 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra114-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra114 pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ const: nvidia,tegra114-pinmux
+
+ reg:
+ items:
+ - description: pad control registers
+ - description: mux registers
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ additionalProperties: false
+ properties:
+ nvidia,pins:
+ items:
+ enum: [ ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3,
+ ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6,
+ ulpi_data6_po7, ulpi_data7_po0, ulpi_clk_py0, ulpi_dir_py1,
+ ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0, dap3_din_pp1,
+ dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0,
+ sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5,
+ sdmmc1_dat1_py6, sdmmc1_dat0_py7, clk2_out_pw5,
+ clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4, ddc_sda_pv5,
+ uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6,
+ uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7,
+ uart3_cts_n_pa1, uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4,
+ pu5, pu6, gen1_i2c_sda_pc5, gen1_i2c_scl_pc4, dap4_fs_pp4,
+ dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, clk3_out_pee0,
+ clk3_req_pee1, gmi_wp_n_pc7, gmi_iordy_pi5, gmi_wait_pi7,
+ gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs0_n_pj0, gmi_cs1_n_pj2,
+ gmi_cs2_n_pk3, gmi_cs3_n_pk4, gmi_cs4_n_pk2, gmi_cs6_n_pi3,
+ gmi_cs7_n_pi6, gmi_ad0_pg0, gmi_ad1_pg1, gmi_ad2_pg2,
+ gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, gmi_ad6_pg6,
+ gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
+ gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6,
+ gmi_ad15_ph7, gmi_a16_pj7, gmi_a17_pb0, gmi_a18_pb1,
+ gmi_a19_pk7, gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_p_pj3,
+ gmi_rst_n_pi4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6,
+ sdmmc4_clk_pcc4, sdmmc4_cmd_pt7, sdmmc4_dat0_paa0,
+ sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3,
+ sdmmc4_dat4_paa4, sdmmc4_dat5_paa5, sdmmc4_dat6_paa6,
+ sdmmc4_dat7_paa7, cam_mclk_pcc0, pcc1, pbb0,
+ cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6,
+ pbb7, pcc2, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0,
+ kb_row1_pr1, kb_row2_pr2, kb_row3_pr3, kb_row4_pr4,
+ kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, kb_row8_ps0,
+ kb_row9_ps1, kb_row10_ps2, kb_col0_pq0, kb_col1_pq1,
+ kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
+ kb_col6_pq6, kb_col7_pq7, clk_32k_out_pa0, sys_clk_req_pz5,
+ core_pwr_req, cpu_pwr_req, pwr_int_n, owr, dap1_fs_pn0,
+ dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, clk1_req_pee2,
+ clk1_out_pw4, spdif_in_pk6, spdif_out_pk5, dap2_fs_pa2,
+ dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, dvfs_pwm_px0,
+ gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2,
+ gpio_x4_aud_px4, gpio_x5_aud_px5, gpio_x6_aud_px6,
+ gpio_x7_aud_px7, sdmmc3_clk_pa6, sdmmc3_cmd_pa7,
+ sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, sdmmc3_dat2_pb5,
+ sdmmc3_dat3_pb4, hdmi_cec_pee3, sdmmc1_wp_n_pv3,
+ sdmmc3_cd_n_pv2, gpio_w2_aud_pw2, gpio_w3_aud_pw3,
+ usb_vbus_en0_pn4, usb_vbus_en1_pn5, sdmmc3_clk_lb_in_pee5,
+ sdmmc3_clk_lb_out_pee4, reset_out_n,
+ # drive groups
+ drive_ao1, drive_ao2, drive_at1, drive_at2, drive_at3,
+ drive_at4, drive_at5, drive_cdev1, drive_cdev2, drive_dap1,
+ drive_dap2, drive_dap3, drive_dap4, drive_dbg, drive_sdio3,
+ drive_spi, drive_uaa, drive_uab, drive_uart2, drive_uart3,
+ drive_sdio1, drive_ddc, drive_gma, drive_gme, drive_gmf,
+ drive_gmg, drive_gmh, drive_owr, drive_uda ]
+
+ nvidia,function:
+ enum: [ blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3,
+ displaya, displaya_alt, displayb, dtv, emc_dll, extperiph1,
+ extperiph2, extperiph3, gmi, gmi_alt, hda, hsi, i2c1, i2c2,
+ i2c3, i2c4, i2cpwr, i2s0, i2s1, i2s2, i2s3, i2s4, irda, kbc,
+ nand, nand_alt, owr, pmi, pwm0, pwm1, pwm2, pwm3, pwron,
+ reset_out_n, rsvd1, rsvd2, rsvd3, rsvd4, sdmmc1, sdmmc2,
+ sdmmc3, sdmmc4, soc, spdif, spi1, spi2, spi3, spi4, spi5,
+ spi6, sysclk, trace, uarta, uartb, uartc, uartd, ulpi, usb,
+ vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, vi, vi_alt1, vi_alt3 ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,schmitt: true
+ nvidia,pull-down-strength: true
+ nvidia,pull-up-strength: true
+ nvidia,high-speed-mode: true
+ nvidia,low-power-mode: true
+ nvidia,enable-input: true
+ nvidia,open-drain: true
+ nvidia,lock: true
+ nvidia,io-reset: true
+ nvidia,rcv-sel: true
+ nvidia,drive-type: true
+ nvidia,slew-rate-rising: true
+ nvidia,slew-rate-falling: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ pinmux@70000868 {
+ compatible = "nvidia,tegra114-pinmux";
+ reg = <0x70000868 0x148>, /* Pad control registers */
+ <0x70003000 0x40c>; /* PinMux registers */
+
+ pinmux {
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+
+ 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,function = "sdmmc4";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt
deleted file mode 100644
index f4d06bb0b55a..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt
+++ /dev/null
@@ -1,153 +0,0 @@
-NVIDIA Tegra124 pinmux controller
-
-The Tegra124 pinctrl binding is very similar to the Tegra20 and Tegra30
-pinctrl binding, as described in nvidia,tegra20-pinmux.txt and
-nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as
-a baseline, and only documents the differences between the two bindings.
-
-Required properties:
-- compatible: For Tegra124, must contain "nvidia,tegra124-pinmux". For
- Tegra132, must contain '"nvidia,tegra132-pinmux", "nvidia-tegra124-pinmux"'.
-- reg: Should contain a list of base address and size pairs for:
- -- first entry - the drive strength and pad control registers.
- -- second entry - the pinmux registers
- -- third entry - the MIPI_PAD_CTRL register
-
-Tegra124 adds the following optional properties for pin configuration subnodes.
-The macros for options are defined in the
- include/dt-binding/pinctrl/pinctrl-tegra.h.
-- nvidia,enable-input: Integer. Enable the pin's input path.
- enable :TEGRA_PIN_ENABLE and
- disable or output only: TEGRA_PIN_DISABLE.
-- nvidia,open-drain: Integer.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,lock: Integer. Lock the pin configuration against further changes
- until reset.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,io-reset: Integer. Reset the IO path.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,rcv-sel: Integer. Select VIL/VIH receivers.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-
-Please refer the Tegra TRM for complete details regarding which groups
-support which functionality.
-
-Valid values for pin and group names are:
-
- per-pin mux groups:
-
- These all support nvidia,function, nvidia,tristate, nvidia,pull,
- nvidia,enable-input. Some support nvidia,lock nvidia,open-drain,
- nvidia,io-reset and nvidia,rcv-sel.
-
- ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4,
- ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0,
- ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0,
- dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0,
- sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6,
- sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4,
- ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6,
- uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1,
- uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_scl_pc4,
- gen1_i2c_sda_pc5, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6,
- dap4_sclk_pp7, clk3_out_pee0, clk3_req_pee1, pc7, pi5, pi7, pk0, pk1,
- pj0, pj2, pk3, pk4, pk2, pi3, pi6, pg0, pg1, pg2, pg3, pg4, pg5, pg6,
- pg7, ph0, ph1, ph2, ph3, ph4, ph5, ph6, ph7, pj7, pb0, pb1, pk7, pi0,
- pi1, pi2, pi4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, sdmmc4_clk_pcc4,
- sdmmc4_cmd_pt7, sdmmc4_dat0_paa0, sdmmc4_dat1_paa1, sdmmc4_dat2_paa2,
- sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, sdmmc4_dat5_paa5, sdmmc4_dat6_paa6,
- sdmmc4_dat7_paa7, cam_mclk_pcc0, pcc1, pbb0, cam_i2c_scl_pbb1,
- cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, pcc2, jtag_rtck,
- pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2,
- kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7,
- kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4,
- kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, kb_col0_pq0, kb_col1_pq1,
- kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, kb_col6_pq6,
- kb_col7_pq7, clk_32k_out_pa0, core_pwr_req, cpu_pwr_req, pwr_int_n,
- clk_32k_in, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2,
- dap1_sclk_pn3, dap_mclk1_req_pee2, dap_mclk1_pw4, spdif_in_pk6,
- spdif_out_pk5, dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3,
- dvfs_pwm_px0, gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2,
- gpio_x4_aud_px4, gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7,
- sdmmc3_clk_pa6, sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6,
- sdmmc3_dat2_pb5, sdmmc3_dat3_pb4, pex_l0_rst_n_pdd1,
- pex_l0_clkreq_n_pdd2, pex_wake_n_pdd3, pex_l1_rst_n_pdd5,
- pex_l1_clkreq_n_pdd6, hdmi_cec_pee3, sdmmc1_wp_n_pv3,
- sdmmc3_cd_n_pv2, gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4,
- usb_vbus_en1_pn5, sdmmc3_clk_lb_out_pee4, sdmmc3_clk_lb_in_pee5,
- gmi_clk_lb, reset_out_n, kb_row16_pt0, kb_row17_pt1, usb_vbus_en2_pff1,
- pff2, dp_hpd_pff0,
-
- drive groups:
-
- These all support nvidia,pull-down-strength, nvidia,pull-up-strength,
- nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all
- support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode
- and nvidia,drive-type.
-
- ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4,
- dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg,
- gmh, owr, uda, gpv, dev3, cec, usb_vbus_en, ao3, ao0, hv0, sdio4, ao4.
-
- MIPI pad control groups:
-
- These support only the nvidia,function property.
-
- dsi_b
-
-Valid values for nvidia,functions are:
-
- blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya,
- displaya_alt, displayb, dtv, extperiph1, extperiph2, extperiph3,
- gmi, gmi_alt, hda, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr, i2s0,
- i2s1, i2s2, i2s3, i2s4, irda, kbc, owr, pmi, pwm0, pwm1, pwm2, pwm3,
- pwron, reset_out_n, rsvd1, rsvd2, rsvd3, rsvd4, sdmmc1, sdmmc2, sdmmc3,
- sdmmc4, soc, spdif, spi1, spi2, spi3, spi4, spi5, spi6, trace, uarta,
- uartb, uartc, uartd, ulpi, usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6,
- vi, vi_alt1, vi_alt3, vimclk2, vimclk2_alt, sata, ccla, pe0, pe, pe1,
- dp, rtck, sys, clk tmds, csi, dsi_b
-
-Example:
-
- pinmux: pinmux {
- compatible = "nvidia,tegra124-pinmux";
- reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */
- <0x0 0x70003000 0x0 0x434>, /* Mux registers */
- <0x0 0x70000820 0x0 0x8>; /* MIPI pad control */
- };
-
-Example pinmux entries:
-
- pinctrl {
- sdmmc4_default: pinmux {
- sdmmc4_clk_pcc4 {
- nvidia,pins = "sdmmc4_clk_pcc4",
- 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,function = "sdmmc4";
- nvidia,pull = <TEGRA_PIN_PULL_UP>;
- nvidia,tristate = <TEGRA_PIN_DISABLE>;
- };
- };
- };
-
- sdhci@78000400 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc4_default>;
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.yaml
new file mode 100644
index 000000000000..f924652bef0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.yaml
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra124-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra124 Pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+description: The Tegra124 pinctrl binding is very similar to the Tegra20 and
+ Tegra30 pinctrl binding, as described in nvidia,tegra20-pinmux.yaml and
+ nvidia,tegra30-pinmux.yaml. In fact, this document assumes that binding as a
+ baseline, and only documents the differences between the two bindings.
+
+properties:
+ compatible:
+ oneOf:
+ - const: nvidia,tegra124-pinmux
+ - items:
+ - const: nvidia,tegra132-pinmux
+ - const: nvidia,tegra124-pinmux
+
+ reg:
+ items:
+ - description: driver strength and pad control registers
+ - description: pinmux registers
+ - description: MIPI_PAD_CTRL registers
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ additionalProperties: false
+ properties:
+ nvidia,pins:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ items:
+ enum: [ ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3,
+ ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6,
+ ulpi_data6_po7, ulpi_data7_po0, ulpi_clk_py0, ulpi_dir_py1,
+ ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0, dap3_din_pp1,
+ dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0,
+ sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5,
+ sdmmc1_dat1_py6, sdmmc1_dat0_py7, clk2_out_pw5,
+ clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4, ddc_sda_pv5,
+ uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6,
+ uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7,
+ uart3_cts_n_pa1, uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4,
+ pu5, pu6, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5, dap4_fs_pp4,
+ dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, clk3_out_pee0,
+ clk3_req_pee1, pc7, pi5, pi7, pk0, pk1, pj0, pj2, pk3, pk4,
+ pk2, pi3, pi6, pg0, pg1, pg2, pg3, pg4, pg5, pg6, pg7, ph0,
+ ph1, ph2, ph3, ph4, ph5, ph6, ph7, pj7, pb0, pb1, pk7, pi0,
+ pi1, pi2, pi4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6,
+ sdmmc4_clk_pcc4, sdmmc4_cmd_pt7, sdmmc4_dat0_paa0,
+ sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3,
+ sdmmc4_dat4_paa4, sdmmc4_dat5_paa5, sdmmc4_dat6_paa6,
+ sdmmc4_dat7_paa7, cam_mclk_pcc0, pcc1, pbb0,
+ cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6,
+ pbb7, pcc2, jtag_rtck, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7,
+ kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, kb_row3_pr3,
+ kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7,
+ kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3,
+ kb_row12_ps4, kb_row13_ps5, kb_row14_ps6, kb_row15_ps7,
+ kb_col0_pq0, kb_col1_pq1, kb_col2_pq2, kb_col3_pq3,
+ kb_col4_pq4, kb_col5_pq5, kb_col6_pq6, kb_col7_pq7,
+ clk_32k_out_pa0, core_pwr_req, cpu_pwr_req, pwr_int_n,
+ clk_32k_in, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2,
+ dap1_sclk_pn3, dap_mclk1_req_pee2, dap_mclk1_pw4,
+ spdif_in_pk6, spdif_out_pk5, dap2_fs_pa2, dap2_din_pa4,
+ dap2_dout_pa5, dap2_sclk_pa3, dvfs_pwm_px0,
+ gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2,
+ gpio_x4_aud_px4, gpio_x5_aud_px5, gpio_x6_aud_px6,
+ gpio_x7_aud_px7, sdmmc3_clk_pa6, sdmmc3_cmd_pa7,
+ sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, sdmmc3_dat2_pb5,
+ sdmmc3_dat3_pb4, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2,
+ pex_wake_n_pdd3, pex_l1_rst_n_pdd5, pex_l1_clkreq_n_pdd6,
+ hdmi_cec_pee3, sdmmc1_wp_n_pv3, sdmmc3_cd_n_pv2,
+ gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4,
+ usb_vbus_en1_pn5, sdmmc3_clk_lb_out_pee4,
+ sdmmc3_clk_lb_in_pee5, gmi_clk_lb, reset_out_n,
+ kb_row16_pt0, kb_row17_pt1, usb_vbus_en2_pff1, pff2,
+ dp_hpd_pff0,
+ # drive groups
+ drive_ao1, drive_ao2, drive_at1, drive_at2, drive_at3,
+ drive_at4, drive_at5, drive_cdev1, drive_cdev2, drive_dap1,
+ drive_dap2, drive_dap3, drive_dap4, drive_dbg, drive_sdio3,
+ drive_spi, drive_uaa, drive_uab, drive_uart2, drive_uart3,
+ drive_sdio1, drive_ddc, drive_gma, drive_gme, drive_gmf,
+ drive_gmg, drive_gmh, drive_owr, drive_uda, drive_gpv,
+ drive_dev3, drive_cec, drive_usb_vbus_en, drive_ao3,
+ drive_ao0, drive_hv0, drive_sdio4, drive_ao4,
+ # MIPI pad control groups
+ mipi_pad_ctrl_dsi_b ]
+
+ nvidia,function:
+ enum: [ blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3,
+ displaya, displaya_alt, displayb, dtv, extperiph1,
+ extperiph2, extperiph3, gmi, gmi_alt, hda, hsi, i2c1, i2c2,
+ i2c3, i2c4, i2cpwr, i2s0, i2s1, i2s2, i2s3, i2s4, irda, kbc,
+ owr, pmi, pwm0, pwm1, pwm2, pwm3, pwron, reset_out_n, rsvd1,
+ rsvd2, rsvd3, rsvd4, sdmmc1, sdmmc2, sdmmc3, sdmmc4, soc,
+ spdif, spi1, spi2, spi3, spi4, spi5, spi6, trace, uarta,
+ uartb, uartc, uartd, ulpi, usb, vgp1, vgp2, vgp3, vgp4, vgp5,
+ vgp6, vi, vi_alt1, vi_alt3, vimclk2, vimclk2_alt, sata, ccla,
+ pe0, pe, pe1, dp, rtck, sys, clk, tmds, csi, dsi_b ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,schmitt: true
+ nvidia,pull-down-strength: true
+ nvidia,pull-up-strength: true
+ nvidia,high-speed-mode: true
+ nvidia,low-power-mode: true
+ nvidia,enable-input: true
+ nvidia,open-drain: true
+ nvidia,lock: true
+ nvidia,io-reset: true
+ nvidia,rcv-sel: true
+ nvidia,drive-type: true
+ nvidia,slew-rate-rising: true
+ nvidia,slew-rate-falling: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra124-car.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/pinctrl/pinctrl-tegra.h>
+
+ pinmux@70000868 {
+ compatible = "nvidia,tegra124-pinmux";
+ reg = <0x70000868 0x164>, /* Pad control registers */
+ <0x70003000 0x434>, /* Mux registers */
+ <0x70000820 0x8>; /* MIPI pad control */
+
+ sdmmc4_default: pinmux {
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4";
+ 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,function = "sdmmc4";
+ nvidia,pull = <TEGRA_PIN_PULL_UP>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
deleted file mode 100644
index 90d38f710635..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
+++ /dev/null
@@ -1,107 +0,0 @@
-NVIDIA Tegra194 pinmux controller
-
-Required properties:
-- compatible: "nvidia,tegra194-pinmux"
-- reg: Should contain a list of base address and size pairs for:
- - first entry: The APB_MISC_GP_*_PADCTRL registers (pad control)
- - second entry: The PINMUX_AUX_* registers (pinmux)
-
-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".
-
-Tegra's 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, tristate, drive strength, etc.
-
-See the TRM to determine which properties and values apply to each pin/group.
-Macro values for property values are defined in
-include/dt-binding/pinctrl/pinctrl-tegra.h.
-
-Required subnode-properties:
-- nvidia,pins : An array of strings. Each string contains the name of a pin or
- group. Valid values for these names are listed below.
-
-Optional subnode-properties:
-- nvidia,function: A string containing the name of the function to mux to the
- pin or group.
-- nvidia,pull: Integer, representing the pull-down/up to apply to the pin.
- 0: none, 1: down, 2: up.
-- nvidia,tristate: Integer.
- 0: drive, 1: tristate.
-- nvidia,enable-input: Integer. Enable the pin's input path.
- enable :TEGRA_PIN_ENABLE and
- disable or output only: TEGRA_PIN_DISABLE.
-- nvidia,open-drain: Integer.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,lock: Integer. Lock the pin configuration against further changes
- until reset.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,io-hv: Integer. Select high-voltage receivers.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-- nvidia,drive-type: Integer. Valid range 0...3.
-- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVDN" in the
- Tegra TRM.
-- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVUP" in the
- Tegra TRM.
-
-Valid values for pin and group names (nvidia,pin) are:
-
- These correspond to Tegra PADCTL_* (pinmux) registers.
-
- Mux groups:
-
- These correspond to Tegra PADCTL_* (pinmux) registers. Any property
- that exists in those registers may be set for the following pin names.
-
- pex_l5_clkreq_n_pgg0, pex_l5_rst_n_pgg1
-
- Drive groups:
-
- These registers controls a single pin for which a mux group exists.
- See the list above for the pin name to use when configuring the pinmux.
-
- pex_l5_clkreq_n_pgg0, pex_l5_rst_n_pgg1
-
-Valid values for nvidia,functions are:
-
- pe5
-
-Power Domain:
- pex_l5_clkreq_n_pgg0 and pex_l5_rst_n_pgg1 are part of PCIE C5 power
- partition. Client devices must enable this partition before accessing
- these pins here.
-
-
-Example:
-
- tegra_pinctrl: pinmux: pinmux@2430000 {
- compatible = "nvidia,tegra194-pinmux";
- reg = <0x2430000 0x17000
- 0xc300000 0x4000>;
-
- pinctrl-names = "pex_rst";
- pinctrl-0 = <&pex_rst_c5_out_state>;
-
- pex_rst_c5_out_state: pex_rst_c5_out {
- pex_rst {
- nvidia,pins = "pex_l5_rst_n_pgg1";
- nvidia,schmitt = <TEGRA_PIN_DISABLE>;
- nvidia,lpdr = <TEGRA_PIN_ENABLE>;
- nvidia,enable-input = <TEGRA_PIN_DISABLE>;
- nvidia,io-hv = <TEGRA_PIN_ENABLE>;
- nvidia,tristate = <TEGRA_PIN_DISABLE>;
- nvidia,pull = <TEGRA_PIN_PULL_NONE>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.yaml
new file mode 100644
index 000000000000..60a4bdf01bf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.yaml
@@ -0,0 +1,284 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra194-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra194 Pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ enum:
+ - nvidia,tegra194-pinmux
+ - nvidia,tegra194-pinmux-aon
+
+ reg:
+ items:
+ - description: pinmux registers
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ unevaluatedProperties: false
+ properties:
+ nvidia,function:
+ enum: [ aud, can0, can1, ccla, dca, dcb, dgpu, directdc, directdc1,
+ displaya, displayb, dmic1, dmic2, dmic3, dmic4, dmic5, dp,
+ dspk0, dspk1, eqos, extperiph1, extperiph2, extperiph3,
+ extperiph4, gp, gpio, hdmi, i2c1, i2c2, i2c3, i2c5, i2c8,
+ i2s1, i2s2, i2s3, i2s4, i2s5, i2s6, igpu, iqc1, iqc2, mipi,
+ nv, pe0, pe1, pe2, pe3, pe4, pe5, qspi, qspi0, qspi1, rsvd0,
+ rsvd1, rsvd2, rsvd3, sata, sce, sdmmc1, sdmmc3, sdmmc4, slvs,
+ soc, spdif, spi1, spi2, spi3, touch, uarta, uartb, uartc,
+ uartd, uarte, uartg, ufs0, usb, vgp1, vgp2, vgp3, vgp4, vgp5,
+ vgp6, wdt ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,schmitt: true
+ nvidia,enable-input: true
+ nvidia,open-drain: true
+ nvidia,lock: true
+ nvidia,drive-type: true
+ nvidia,io-hv: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ const: nvidia,tegra194-pinmux
+ then:
+ patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ additionalProperties:
+ properties:
+ nvidia,pins:
+ description: An array of strings. Each string contains the name
+ of a pin or group. Valid values for these names are listed
+ below.
+
+ Note that the pex_l5_clkreq_n_pgg0 and pex_l5_rst_n_pgg1 pins
+ are part of PCIE C5 power partition. Client devices must
+ enable this partition before accessing the configuration for
+ these pins.
+ items:
+ enum: [ dap6_sclk_pa0, dap6_dout_pa1, dap6_din_pa2,
+ dap6_fs_pa3, dap4_sclk_pa4, dap4_dout_pa5,
+ dap4_din_pa6, dap4_fs_pa7, cpu_pwr_req_0_pb0,
+ cpu_pwr_req_1_pb1, qspi0_sck_pc0, qspi0_cs_n_pc1,
+ qspi0_io0_pc2, qspi0_io1_pc3, qspi0_io2_pc4,
+ qspi0_io3_pc5, qspi1_sck_pc6, qspi1_cs_n_pc7,
+ qspi1_io0_pd0, qspi1_io1_pd1, qspi1_io2_pd2,
+ qspi1_io3_pd3, eqos_txc_pe0, eqos_td0_pe1,
+ eqos_td1_pe2, eqos_td2_pe3, eqos_td3_pe4,
+ eqos_tx_ctl_pe5, eqos_rd0_pe6, eqos_rd1_pe7,
+ eqos_rd2_pf0, eqos_rd3_pf1, eqos_rx_ctl_pf2,
+ eqos_rxc_pf3, eqos_sma_mdio_pf4, eqos_sma_mdc_pf5,
+ soc_gpio00_pg0, soc_gpio01_pg1, soc_gpio02_pg2,
+ soc_gpio03_pg3, soc_gpio08_pg4, soc_gpio09_pg5,
+ soc_gpio10_pg6, soc_gpio11_pg7, soc_gpio12_ph0,
+ soc_gpio13_ph1, soc_gpio14_ph2, uart4_tx_ph3,
+ uart4_rx_ph4, uart4_rts_ph5, uart4_cts_ph6,
+ dap2_sclk_ph7, dap2_dout_pi0, dap2_din_pi1,
+ dap2_fs_pi2, gen1_i2c_scl_pi3, gen1_i2c_sda_pi4,
+ sdmmc1_clk_pj0, sdmmc1_cmd_pj1, sdmmc1_dat0_pj2,
+ sdmmc1_dat1_pj3, sdmmc1_dat2_pj4, sdmmc1_dat3_pj5,
+ pex_l0_clkreq_n_pk0, pex_l0_rst_n_pk1,
+ pex_l1_clkreq_n_pk2, pex_l1_rst_n_pk3,
+ pex_l2_clkreq_n_pk4, pex_l2_rst_n_pk5,
+ pex_l3_clkreq_n_pk6, pex_l3_rst_n_pk7,
+ pex_l4_clkreq_n_pl0, pex_l4_rst_n_pl1,
+ pex_wake_n_pl2, sata_dev_slp_pl3, dp_aux_ch0_hpd_pm0,
+ dp_aux_ch1_hpd_pm1, dp_aux_ch2_hpd_pm2,
+ dp_aux_ch3_hpd_pm3, hdmi_cec_pm4, soc_gpio50_pm5,
+ soc_gpio51_pm6, soc_gpio52_pm7, soc_gpio53_pn0,
+ soc_gpio54_pn1, soc_gpio55_pn2, sdmmc3_clk_po0,
+ sdmmc3_cmd_po1, sdmmc3_dat0_po2, sdmmc3_dat1_po3,
+ sdmmc3_dat2_po4, sdmmc3_dat3_po5, extperiph1_clk_pp0,
+ extperiph2_clk_pp1, cam_i2c_scl_pp2, cam_i2c_sda_pp3,
+ soc_gpio04_pp4, soc_gpio05_pp5, soc_gpio06_pp6,
+ soc_gpio07_pp7, soc_gpio20_pq0, soc_gpio21_pq1,
+ soc_gpio22_pq2, soc_gpio23_pq3, soc_gpio40_pq4,
+ soc_gpio41_pq5, soc_gpio42_pq6, soc_gpio43_pq7,
+ soc_gpio44_pr0, soc_gpio45_pr1, uart1_tx_pr2,
+ uart1_rx_pr3, uart1_rts_pr4, uart1_cts_pr5,
+ dap1_sclk_ps0, dap1_dout_ps1, dap1_din_ps2,
+ dap1_fs_ps3, aud_mclk_ps4, soc_gpio30_ps5,
+ soc_gpio31_ps6, soc_gpio32_ps7, soc_gpio33_pt0,
+ dap3_sclk_pt1, dap3_dout_pt2, dap3_din_pt3,
+ dap3_fs_pt4, dap5_sclk_pt5, dap5_dout_pt6,
+ dap5_din_pt7, dap5_fs_pu0, directdc1_clk_pv0,
+ directdc1_in_pv1, directdc1_out0_pv2,
+ directdc1_out1_pv3, directdc1_out2_pv4,
+ directdc1_out3_pv5, directdc1_out4_pv6,
+ directdc1_out5_pv7, directdc1_out6_pw0,
+ directdc1_out7_pw1, gpu_pwr_req_px0, cv_pwr_req_px1,
+ gp_pwm2_px2, gp_pwm3_px3, uart2_tx_px4, uart2_rx_px5,
+ uart2_rts_px6, uart2_cts_px7, spi3_sck_py0,
+ spi3_miso_py1, spi3_mosi_py2, spi3_cs0_py3,
+ spi3_cs1_py4, uart5_tx_py5, uart5_rx_py6,
+ uart5_rts_py7, uart5_cts_pz0, usb_vbus_en0_pz1,
+ usb_vbus_en1_pz2, spi1_sck_pz3, spi1_miso_pz4,
+ spi1_mosi_pz5, spi1_cs0_pz6, spi1_cs1_pz7,
+ ufs0_ref_clk_pff0, ufs0_rst_pff1,
+ pex_l5_clkreq_n_pgg0, pex_l5_rst_n_pgg1,
+ directdc_comp, sdmmc4_clk, sdmmc4_cmd, sdmmc4_dqs,
+ sdmmc4_dat7, sdmmc4_dat6, sdmmc4_dat5, sdmmc4_dat4,
+ sdmmc4_dat3, sdmmc4_dat2, sdmmc4_dat1, sdmmc4_dat0,
+ sdmmc1_comp, sdmmc1_hv_trim, sdmmc3_comp,
+ sdmmc3_hv_trim, eqos_comp, qspi_comp,
+ # drive groups
+ drive_soc_gpio33_pt0, drive_soc_gpio32_ps7,
+ drive_soc_gpio31_ps6, drive_soc_gpio30_ps5,
+ drive_aud_mclk_ps4, drive_dap1_fs_ps3,
+ drive_dap1_din_ps2, drive_dap1_dout_ps1,
+ drive_dap1_sclk_ps0, drive_dap3_fs_pt4,
+ drive_dap3_din_pt3, drive_dap3_dout_pt2,
+ drive_dap3_sclk_pt1, drive_dap5_fs_pu0,
+ drive_dap5_din_pt7, drive_dap5_dout_pt6,
+ drive_dap5_sclk_pt5, drive_dap6_fs_pa3,
+ drive_dap6_din_pa2, drive_dap6_dout_pa1,
+ drive_dap6_sclk_pa0, drive_dap4_fs_pa7,
+ drive_dap4_din_pa6, drive_dap4_dout_pa5,
+ drive_dap4_sclk_pa4, drive_extperiph2_clk_pp1,
+ drive_extperiph1_clk_pp0, drive_cam_i2c_sda_pp3,
+ drive_cam_i2c_scl_pp2, drive_soc_gpio40_pq4,
+ drive_soc_gpio41_pq5, drive_soc_gpio42_pq6,
+ drive_soc_gpio43_pq7, drive_soc_gpio44_pr0,
+ drive_soc_gpio45_pr1, drive_soc_gpio20_pq0,
+ drive_soc_gpio21_pq1, drive_soc_gpio22_pq2,
+ drive_soc_gpio23_pq3, drive_soc_gpio04_pp4,
+ drive_soc_gpio05_pp5, drive_soc_gpio06_pp6,
+ drive_soc_gpio07_pp7, drive_uart1_cts_pr5,
+ drive_uart1_rts_pr4, drive_uart1_rx_pr3,
+ drive_uart1_tx_pr2, drive_dap2_din_pi1,
+ drive_dap2_dout_pi0, drive_dap2_fs_pi2,
+ drive_dap2_sclk_ph7, drive_uart4_cts_ph6,
+ drive_uart4_rts_ph5, drive_uart4_rx_ph4,
+ drive_uart4_tx_ph3, drive_soc_gpio03_pg3,
+ drive_soc_gpio02_pg2, drive_soc_gpio01_pg1,
+ drive_soc_gpio00_pg0, drive_gen1_i2c_scl_pi3,
+ drive_gen1_i2c_sda_pi4, drive_soc_gpio08_pg4,
+ drive_soc_gpio09_pg5, drive_soc_gpio10_pg6,
+ drive_soc_gpio11_pg7, drive_soc_gpio12_ph0,
+ drive_soc_gpio13_ph1, drive_soc_gpio14_ph2,
+ drive_soc_gpio50_pm5, drive_soc_gpio51_pm6,
+ drive_soc_gpio52_pm7, drive_soc_gpio53_pn0,
+ drive_soc_gpio54_pn1, drive_soc_gpio55_pn2,
+ drive_dp_aux_ch0_hpd_pm0, drive_dp_aux_ch1_hpd_pm1,
+ drive_dp_aux_ch2_hpd_pm2, drive_dp_aux_ch3_hpd_pm3,
+ drive_hdmi_cec_pm4, drive_pex_l2_clkreq_n_pk4,
+ drive_pex_wake_n_pl2, drive_pex_l1_clkreq_n_pk2,
+ drive_pex_l1_rst_n_pk3, drive_pex_l0_clkreq_n_pk0,
+ drive_pex_l0_rst_n_pk1, drive_pex_l2_rst_n_pk5,
+ drive_pex_l3_clkreq_n_pk6, drive_pex_l3_rst_n_pk7,
+ drive_pex_l4_clkreq_n_pl0, drive_pex_l4_rst_n_pl1,
+ drive_sata_dev_slp_pl3, drive_pex_l5_clkreq_n_pgg0,
+ drive_pex_l5_rst_n_pgg1, drive_cpu_pwr_req_1_pb1,
+ drive_cpu_pwr_req_0_pb0, drive_sdmmc1_clk_pj0,
+ drive_sdmmc1_cmd_pj1, drive_sdmmc1_dat3_pj5,
+ drive_sdmmc1_dat2_pj4, drive_sdmmc1_dat1_pj3,
+ drive_sdmmc1_dat0_pj2, drive_sdmmc3_dat3_po5,
+ drive_sdmmc3_dat2_po4, drive_sdmmc3_dat1_po3,
+ drive_sdmmc3_dat0_po2, drive_sdmmc3_cmd_po1,
+ drive_sdmmc3_clk_po0, drive_gpu_pwr_req_px0,
+ drive_spi3_miso_py1, drive_spi1_cs0_pz6,
+ drive_spi3_cs0_py3, drive_spi1_miso_pz4,
+ drive_spi3_cs1_py4, drive_gp_pwm3_px3,
+ drive_gp_pwm2_px2, drive_spi1_sck_pz3,
+ drive_spi3_sck_py0, drive_spi1_cs1_pz7,
+ drive_spi1_mosi_pz5, drive_spi3_mosi_py2,
+ drive_cv_pwr_req_px1, drive_uart2_tx_px4,
+ drive_uart2_rx_px5, drive_uart2_rts_px6,
+ drive_uart2_cts_px7, drive_uart5_rx_py6,
+ drive_uart5_tx_py5, drive_uart5_rts_py7,
+ drive_uart5_cts_pz0, drive_usb_vbus_en0_pz1,
+ drive_usb_vbus_en1_pz2, drive_ufs0_rst_pff1,
+ drive_ufs0_ref_clk_pff0 ]
+
+ - if:
+ properties:
+ compatible:
+ const: nvidia,tegra194-pinmux-aon
+ then:
+ patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ additionalProperties:
+ properties:
+ nvidia,pins:
+ items:
+ enum: [ can1_dout_paa0, can1_din_paa1, can0_dout_paa2,
+ can0_din_paa3, can0_stb_paa4, can0_en_paa5,
+ can0_wake_paa6, can0_err_paa7, can1_stb_pbb0,
+ can1_en_pbb1, can1_wake_pbb2, can1_err_pbb3,
+ spi2_sck_pcc0, spi2_miso_pcc1, spi2_mosi_pcc2,
+ spi2_cs0_pcc3, touch_clk_pcc4, uart3_tx_pcc5,
+ uart3_rx_pcc6, gen2_i2c_scl_pcc7, gen2_i2c_sda_pdd0,
+ gen8_i2c_scl_pdd1, gen8_i2c_sda_pdd2,
+ safe_state_pee0, vcomp_alert_pee1,
+ ao_retention_n_pee2, batt_oc_pee3, power_on_pee4,
+ pwr_i2c_scl_pee5, pwr_i2c_sda_pee6, sys_reset_n,
+ shutdown_n, pmu_int_n, soc_pwr_req, clk_32k_in,
+ # drive groups
+ drive_shutdown_n, drive_pmu_int_n,
+ drive_safe_state_pee0, drive_vcomp_alert_pee1,
+ drive_soc_pwr_req, drive_batt_oc_pee3,
+ drive_clk_32k_in, drive_power_on_pee4,
+ drive_pwr_i2c_scl_pee5, drive_pwr_i2c_sda_pee6,
+ drive_ao_retention_n_pee2, drive_touch_clk_pcc4,
+ drive_uart3_rx_pcc6, drive_uart3_tx_pcc5,
+ drive_gen8_i2c_sda_pdd2, drive_gen8_i2c_scl_pdd1,
+ drive_spi2_mosi_pcc2, drive_gen2_i2c_scl_pcc7,
+ drive_spi2_cs0_pcc3, drive_gen2_i2c_sda_pdd0,
+ drive_spi2_sck_pcc0, drive_spi2_miso_pcc1,
+ drive_can1_dout_paa0, drive_can1_din_paa1,
+ drive_can0_dout_paa2, drive_can0_din_paa3,
+ drive_can0_stb_paa4, drive_can0_en_paa5,
+ drive_can0_wake_paa6, drive_can0_err_paa7,
+ drive_can1_stb_pbb0, drive_can1_en_pbb1,
+ drive_can1_wake_pbb2, drive_can1_err_pbb3 ]
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/pinctrl-tegra.h>
+
+ pinmux@2430000 {
+ compatible = "nvidia,tegra194-pinmux";
+ reg = <0x2430000 0x17000>;
+
+ pinctrl-names = "pex_rst";
+ pinctrl-0 = <&pex_rst_c5_out_state>;
+
+ pex_rst_c5_out_state: pinmux-pex-rst-c5-out {
+ pex_rst {
+ nvidia,pins = "pex_l5_rst_n_pgg1";
+ nvidia,schmitt = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+ nvidia,io-hv = <TEGRA_PIN_ENABLE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt
deleted file mode 100644
index 3c8ce28baad6..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt
+++ /dev/null
@@ -1,143 +0,0 @@
-NVIDIA Tegra20 pinmux controller
-
-Required properties:
-- compatible: "nvidia,tegra20-pinmux"
-- reg: Should contain the register physical address and length for each of
- the tri-state, mux, pull-up/down, and pad control register sets.
-
-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".
-
-Tegra's 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, tristate, drive strength, etc.
-
-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 or tristate parameter. For this
-reason, even seemingly boolean values are actually tristates in this binding:
-unspecified, off, or on. Unspecified is represented as an absent property,
-and off/on are represented as integer values 0 and 1.
-
-Required subnode-properties:
-- nvidia,pins : An array of strings. Each string contains the name of a pin or
- group. Valid values for these names are listed below.
-
-Optional subnode-properties:
-- nvidia,function: A string containing the name of the function to mux to the
- pin or group. Valid values for function names are listed below. See the Tegra
- TRM to determine which are valid for each pin or group.
-- nvidia,pull: Integer, representing the pull-down/up to apply to the pin.
- 0: none, 1: down, 2: up.
-- nvidia,tristate: Integer.
- 0: drive, 1: tristate.
-- nvidia,high-speed-mode: Integer. Enable high speed mode the pins.
- 0: no, 1: yes.
-- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input.
- 0: no, 1: yes.
-- nvidia,low-power-mode: Integer. Valid values 0-3. 0 is least power, 3 is
- most power. Controls the drive power or current. See "Low Power Mode"
- or "LPMD1" and "LPMD0" in the Tegra TRM.
-- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVDN" in the
- Tegra TRM.
-- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVUP" in the
- Tegra TRM.
-- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is
- fastest. The range of valid values depends on the pingroup. See
- "DRVDN_SLWR" in the Tegra TRM.
-- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is
- fastest. The range of valid values depends on the pingroup. See
- "DRVUP_SLWF" in the Tegra TRM.
-
-Note that many of these properties are only valid for certain specific pins
-or groups. See the Tegra TRM and various pinmux spreadsheets for complete
-details regarding which groups support which functionality. The Linux pinctrl
-driver may also be a useful reference, since it consolidates, disambiguates,
-and corrects data from all those sources.
-
-Valid values for pin and group names are:
-
- mux groups:
-
- These all support nvidia,function, nvidia,tristate, and many support
- nvidia,pull.
-
- ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1, dap2, dap3, dap4,
- ddc, dta, dtb, dtc, dtd, dte, dtf, gma, gmb, gmc, gmd, gme, gpu, gpu7,
- gpv, hdint, i2cp, irrx, irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn,
- ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12, ld13,
- ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2, lhs, lm0, lm1, lpp,
- lpw0, lpw1, lpw2, lsc0, lsc1, lsck, lsda, lsdi, lspi, lvp0, lvp1, lvs,
- owc, pmc, pta, rm, sdb, sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi,
- spdo, spia, spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac, uad,
- uca, ucb, uda.
-
- tristate groups:
-
- These only support nvidia,pull.
-
- ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls, lc, ld17_0,
- ld19_18, ld21_20, ld23_22.
-
- drive groups:
-
- With some exceptions, these support nvidia,high-speed-mode,
- nvidia,schmitt, nvidia,low-power-mode, nvidia,pull-down-strength,
- nvidia,pull-up-strength, nvidia,slew-rate-rising, nvidia,slew-rate-falling.
-
- drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1, drive_cdev2,
- drive_csus, drive_dap1, drive_dap2, drive_dap3, drive_dap4, drive_dbg,
- drive_lcd1, drive_lcd2, drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa,
- drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2, drive_xm2a,
- drive_xm2c, drive_xm2d, drive_xm2clk, drive_sdio1, drive_crt, drive_ddc,
- drive_gma, drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_owr,
- drive_uda.
-
-Valid values for nvidia,functions are:
-
- ahb_clk, apb_clk, audio_sync, crt, dap1, dap2, dap3, dap4, dap5,
- displaya, displayb, emc_test0_dll, emc_test1_dll, gmi, gmi_int,
- hdmi, i2cp, i2c1, i2c2, i2c3, ide, irda, kbc, mio, mipi_hs, nand,
- osc, owr, pcie, plla_out, pllc_out1, pllm_out1, pllp_out2, pllp_out3,
- pllp_out4, pwm, pwr_intr, pwr_on, rsvd1, rsvd2, rsvd3, rsvd4, rtck,
- sdio1, sdio2, sdio3, sdio4, sflash, spdif, spi1, spi2, spi2_alt,
- spi3, spi4, trace, twc, uarta, uartb, uartc, uartd, uarte, ulpi,
- vi, vi_sensor_clk, xio
-
-Example:
-
- pinctrl@70000000 {
- compatible = "nvidia,tegra20-pinmux";
- reg = < 0x70000014 0x10 /* Tri-state registers */
- 0x70000080 0x20 /* Mux registers */
- 0x700000a0 0x14 /* Pull-up/down registers */
- 0x70000868 0xa8 >; /* Pad control registers */
- };
-
-Example board file extract:
-
- pinctrl@70000000 {
- sdio4_default: sdio4_default {
- atb {
- nvidia,pins = "atb", "gma", "gme";
- nvidia,function = "sdio4";
- nvidia,pull = <0>;
- nvidia,tristate = <0>;
- };
- };
- };
-
- sdhci@c8000600 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdio4_default>;
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.yaml
new file mode 100644
index 000000000000..432ea40209a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra20-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra20 Pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ const: nvidia,tegra20-pinmux
+
+ reg:
+ items:
+ - description: tri-state registers
+ - description: mux register
+ - description: pull-up/down registers
+ - description: pad control registers
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ additionalProperties: false
+ properties:
+ nvidia,pins:
+ items:
+ enum: [ ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1,
+ dap2, dap3, dap4, ddc, dta, dtb, dtc, dtd, dte, dtf, gma,
+ gmb, gmc, gmd, gme, gpu, gpu7, gpv, hdint, i2cp, irrx,
+ irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn, ld0, ld1,
+ ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12,
+ ld13, ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2,
+ lhs, lm0, lm1, lpp, lpw0, lpw1, lpw2, lsc0, lsc1, lsck,
+ lsda, lsdi, lspi, lvp0, lvp1, lvs, owc, pmc, pta, rm, sdb,
+ sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi, spdo, spia,
+ spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac,
+ uad, uca, ucb, uda,
+ # tristate groups
+ ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls,
+ lc, ld17_0, ld19_18, ld21_20, ld23_22,
+ # drive groups
+ drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1,
+ drive_cdev2, drive_csus, drive_dap1, drive_dap2,
+ drive_dap3, drive_dap4, drive_dbg, drive_lcd1, drive_lcd2,
+ drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa,
+ drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2,
+ drive_xm2a, drive_xm2c, drive_xm2d, drive_xm2clk,
+ drive_sdio1, drive_crt, drive_ddc, drive_gma, drive_gmb,
+ drive_gmc, drive_gmd, drive_gme, drive_owr, drive_uda ]
+
+ nvidia,function:
+ enum: [ ahb_clk, apb_clk, audio_sync, crt, dap1, dap2, dap3, dap4,
+ dap5, displaya, displayb, emc_test0_dll, emc_test1_dll, gmi,
+ gmi_int, hdmi, i2cp, i2c1, i2c2, i2c3, ide, irda, kbc, mio,
+ mipi_hs, nand, osc, owr, pcie, plla_out, pllc_out1,
+ pllm_out1, pllp_out2, pllp_out3, pllp_out4, pwm, pwr_intr,
+ pwr_on, rsvd1, rsvd2, rsvd3, rsvd4, rtck, sdio1, sdio2,
+ sdio3, sdio4, sflash, spdif, spi1, spi2, spi2_alt, spi3,
+ spi4, trace, twc, uarta, uartb, uartc, uartd, uarte, ulpi,
+ vi, vi_sensor_clk, xio ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,schmitt: true
+ nvidia,pull-down-strength: true
+ nvidia,pull-up-strength: true
+ nvidia,high-speed-mode: true
+ nvidia,low-power-mode: true
+ nvidia,slew-rate-rising: true
+ nvidia,slew-rate-falling: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra20-car.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ pinctrl@70000000 {
+ compatible = "nvidia,tegra20-pinmux";
+ reg = <0x70000014 0x10>, /* Tri-state registers */
+ <0x70000080 0x20>, /* Mux registers */
+ <0x700000a0 0x14>, /* Pull-up/down registers */
+ <0x70000868 0xa8>; /* Pad control registers */
+
+ pinmux {
+ atb {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt
deleted file mode 100644
index 85f211436b8e..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-NVIDIA Tegra210 pinmux controller
-
-Required properties:
-- compatible: "nvidia,tegra210-pinmux"
-- reg: Should contain a list of base address and size pairs for:
- - first entry: The APB_MISC_GP_*_PADCTRL registers (pad control)
- - second entry: The PINMUX_AUX_* registers (pinmux)
-
-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".
-
-Tegra's 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, tristate, drive strength, etc.
-
-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 or tristate parameter. For this
-reason, even seemingly boolean values are actually tristates in this binding:
-unspecified, off, or on. Unspecified is represented as an absent property,
-and off/on are represented as integer values 0 and 1.
-
-See the TRM to determine which properties and values apply to each pin/group.
-Macro values for property values are defined in
-include/dt-binding/pinctrl/pinctrl-tegra.h.
-
-Required subnode-properties:
-- nvidia,pins : An array of strings. Each string contains the name of a pin or
- group. Valid values for these names are listed below.
-
-Optional subnode-properties:
-- nvidia,function: A string containing the name of the function to mux to the
- pin or group.
-- nvidia,pull: Integer, representing the pull-down/up to apply to the pin.
- 0: none, 1: down, 2: up.
-- nvidia,tristate: Integer.
- 0: drive, 1: tristate.
-- nvidia,enable-input: Integer. Enable the pin's input path.
- enable :TEGRA_PIN_ENABLE and
- disable or output only: TEGRA_PIN_DISABLE.
-- nvidia,open-drain: Integer.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,lock: Integer. Lock the pin configuration against further changes
- until reset.
- enable: TEGRA_PIN_ENABLE.
- disable: TEGRA_PIN_DISABLE.
-- nvidia,io-hv: Integer. Select high-voltage receivers.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-- nvidia,high-speed-mode: Integer. Enable high speed mode the pins.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input.
- normal: TEGRA_PIN_DISABLE
- high: TEGRA_PIN_ENABLE
-- nvidia,drive-type: Integer. Valid range 0...3.
-- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVDN" in the
- Tegra TRM.
-- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest.
- The range of valid values depends on the pingroup. See "CAL_DRVUP" in the
- Tegra TRM.
-- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is
- fastest. The range of valid values depends on the pingroup. See
- "DRVDN_SLWR" in the Tegra TRM.
-- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is
- fastest. The range of valid values depends on the pingroup. See
- "DRVUP_SLWF" in the Tegra TRM.
-
-Valid values for pin and group names (nvidia,pin) are:
-
- Mux groups:
-
- These correspond to Tegra PINMUX_AUX_* (pinmux) registers. Any property
- that exists in those registers may be set for the following pin names.
-
- In Tegra210, many pins also have a dedicated APB_MISC_GP_*_PADCTRL
- register. Where that is true, and property that exists in that register
- may also be set on the following pin names.
-
- als_prox_int_px3, ap_ready_pv5, ap_wake_bt_ph3, ap_wake_nfc_ph7,
- aud_mclk_pbb0, batt_bcl, bt_rst_ph4, bt_wake_ap_ph5, button_home_py1,
- button_power_on_px5, button_slide_sw_py0, button_vol_down_px7,
- button_vol_up_px6, cam1_mclk_ps0, cam1_pwdn_ps7, cam1_strobe_pt1,
- cam2_mclk_ps1, cam2_pwdn_pt0, cam_af_en_ps5, cam_flash_en_ps6,
- cam_i2c_scl_ps2, cam_i2c_sda_ps3, cam_rst_ps4cam_rst_ps4, clk_32k_in,
- clk_32k_out_py5, clk_req, core_pwr_req, cpu_pwr_req, dap1_din_pb1,
- dap1_dout_pb2, dap1_fs_pb0, dap1_sclk_pb3, dap2_din_paa2, dap2_dout_paa3,
- dap2_fs_paa0, dap2_sclk_paa1, dap4_din_pj5, dap4_dout_pj6, dap4_fs_pj4,
- dap4_sclk_pj7, dmic1_clk_pe0, dmic1_dat_pe1, dmic2_clk_pe2, dmic2_dat_pe3,
- dmic3_clk_pe4, dmic3_dat_pe5, dp_hpd0_pcc6, dvfs_clk_pbb2, dvfs_pwm_pbb1,
- gen1_i2c_scl_pj1, gen1_i2c_sda_pj0, gen2_i2c_scl_pj2, gen2_i2c_sda_pj3,
- gen3_i2c_scl_pf0, gen3_i2c_sda_pf1, gpio_x1_aud_pbb3, gpio_x3_aud_pbb4,
- gps_en_pi2, gps_rst_pi3, hdmi_cec_pcc0, hdmi_int_dp_hpd_pcc1, jtag_rtck,
- lcd_bl_en_pv1, lcd_bl_pwm_pv0, lcd_gpio1_pv3, lcd_gpio2_pv4, lcd_rst_pv2,
- lcd_te_py2, modem_wake_ap_px0, motion_int_px2, nfc_en_pi0, nfc_int_pi1,
- pa6, pcc7, pe6, pe7, pex_l0_clkreq_n_pa1, pex_l0_rst_n_pa0,
- pex_l1_clkreq_n_pa4, pex_l1_rst_n_pa3, pex_wake_n_pa2, ph6, pk0, pk1, pk2,
- pk3, pk4, pk5, pk6, pk7, pl0, pl1, pwr_i2c_scl_py3, pwr_i2c_sda_py4,
- pwr_int_n, pz0, pz1, pz2, pz3, pz4, pz5, qspi_cs_n_pee1, qspi_io0_pee2,
- qspi_io1_pee3, qspi_io2_pee4, qspi_io3_pee5, qspi_sck_pee0,
- sata_led_active_pa5, sdmmc1_clk_pm0, sdmmc1_cmd_pm1, sdmmc1_dat0_pm5,
- sdmmc1_dat1_pm4, sdmmc1_dat2_pm3, sdmmc1_dat3_pm2, sdmmc3_clk_pp0,
- sdmmc3_cmd_pp1, sdmmc3_dat0_pp5, sdmmc3_dat1_pp4, sdmmc3_dat2_pp3,
- sdmmc3_dat3_pp2, shutdown, spdif_in_pcc3, spdif_out_pcc2, spi1_cs0_pc3,
- spi1_cs1_pc4, spi1_miso_pc1, spi1_mosi_pc0, spi1_sck_pc2, spi2_cs0_pb7,
- spi2_cs1_pdd0, spi2_miso_pb5, spi2_mosi_pb4, spi2_sck_pb6, spi4_cs0_pc6,
- spi4_miso_pd0, spi4_mosi_pc7, spi4_sck_pc5, temp_alert_px4, touch_clk_pv7,
- touch_int_px1, touch_rst_pv6, uart1_cts_pu3, uart1_rts_pu2, uart1_rx_pu1,
- uart1_tx_pu0, uart2_cts_pg3, uart2_rts_pg2, uart2_rx_pg1, uart2_tx_pg0,
- uart3_cts_pd4, uart3_rts_pd3, uart3_rx_pd2, uart3_tx_pd1, uart4_cts_pi7,
- uart4_rts_pi6, uart4_rx_pi5, uart4_tx_pi4, usb_vbus_en0_pcc4,
- usb_vbus_en1_pcc5, wifi_en_ph0, wifi_rst_ph1, wifi_wake_ap_ph2
-
- Drive groups:
-
- These correspond to the Tegra APB_MISC_GP_*_PADCTRL (pad control)
- registers. Note that where one of these registers controls a single pin
- for which a PINMUX_AUX_* exists, see the list above for the pin name to
- use when configuring the pinmux.
-
- pa6, pcc7, pe6, pe7, ph6, pk0, pk1, pk2, pk3, pk4, pk5, pk6, pk7, pl0, pl1,
- pz0, pz1, pz2, pz3, pz4, pz5, sdmmc1, sdmmc2, sdmmc3, sdmmc4
-
-Valid values for nvidia,functions are:
-
- aud, bcl, blink, ccla, cec, cldvfs, clk, core, cpu, displaya, displayb,
- dmic1, dmic2, dmic3, dp, dtv, extperiph3, i2c1, i2c2, i2c3, i2cpmu, i2cvi,
- i2s1, i2s2, i2s3, i2s4a, i2s4b, i2s5a, i2s5b, iqc0, iqc1, jtag, pe, pe0,
- pe1, pmi, pwm0, pwm1, pwm2, pwm3, qspi, rsvd0, rsvd1, rsvd2, rsvd3, sata,
- sdmmc1, sdmmc3, shutdown, soc, sor0, sor1, spdif, spi1, spi2, spi3, spi4,
- sys, touch, uart, uarta, uartb, uartc, uartd, usb, vgp1, vgp2, vgp3, vgp4,
- vgp5, vgp6, vimclk, vimclk2
-
-Example:
-
- pinmux: pinmux@70000800 {
- compatible = "nvidia,tegra210-pinmux";
- reg = <0x0 0x700008d4 0x0 0x2a8>, /* Pad control registers */
- <0x0 0x70003000 0x0 0x1000>; /* Mux registers */
-
- pinctrl-names = "boot";
- pinctrl-0 = <&state_boot>;
-
- state_boot: pinmux {
- gen1_i2c_scl_pj1 {
- nvidia,pins = "gen1_i2c_scl_pj1",
- nvidia,function = "i2c1";
- nvidia,pull = <TEGRA_PIN_PULL_NONE>;
- nvidia,tristate = <TEGRA_PIN_DISABLE>;
- nvidia,enable-input = <TEGRA_PIN_ENABLE>;
- nvidia,open-drain = <TEGRA_PIN_ENABLE>;
- nvidia,io-hv = <TEGRA_PIN_ENABLE>;
- };
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.yaml
new file mode 100644
index 000000000000..28ae2e6d0cbc
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra210-pinmux.yaml
@@ -0,0 +1,142 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra210-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra210 Pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ const: nvidia,tegra210-pinmux
+
+ reg:
+ items:
+ - description: APB_MISC_GP_*_PADCTRL register (pad control)
+ - description: PINMUX_AUX_* registers (pinmux)
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ additionalProperties: false
+ properties:
+ nvidia,pins:
+ items:
+ enum: [ als_prox_int_px3, ap_ready_pv5, ap_wake_bt_ph3,
+ ap_wake_nfc_ph7, aud_mclk_pbb0, batt_bcl, bt_rst_ph4,
+ bt_wake_ap_ph5, button_home_py1, button_power_on_px5,
+ button_slide_sw_py0, button_vol_down_px7,
+ button_vol_up_px6, cam1_mclk_ps0, cam1_pwdn_ps7,
+ cam1_strobe_pt1, cam2_mclk_ps1, cam2_pwdn_pt0,
+ cam_af_en_ps5, cam_flash_en_ps6, cam_i2c_scl_ps2,
+ cam_i2c_sda_ps3, cam_rst_ps4, clk_32k_in, clk_32k_out_py5,
+ clk_req, core_pwr_req, cpu_pwr_req, dap1_din_pb1,
+ dap1_dout_pb2, dap1_fs_pb0, dap1_sclk_pb3, dap2_din_paa2,
+ dap2_dout_paa3, dap2_fs_paa0, dap2_sclk_paa1, dap4_din_pj5,
+ dap4_dout_pj6, dap4_fs_pj4, dap4_sclk_pj7, dmic1_clk_pe0,
+ dmic1_dat_pe1, dmic2_clk_pe2, dmic2_dat_pe3, dmic3_clk_pe4,
+ dmic3_dat_pe5, dp_hpd0_pcc6, dvfs_clk_pbb2, dvfs_pwm_pbb1,
+ gen1_i2c_scl_pj1, gen1_i2c_sda_pj0, gen2_i2c_scl_pj2,
+ gen2_i2c_sda_pj3, gen3_i2c_scl_pf0, gen3_i2c_sda_pf1,
+ gpio_x1_aud_pbb3, gpio_x3_aud_pbb4, gps_en_pi2,
+ gps_rst_pi3, hdmi_cec_pcc0, hdmi_int_dp_hpd_pcc1,
+ jtag_rtck, lcd_bl_en_pv1, lcd_bl_pwm_pv0, lcd_gpio1_pv3,
+ lcd_gpio2_pv4, lcd_rst_pv2, lcd_te_py2, modem_wake_ap_px0,
+ motion_int_px2, nfc_en_pi0, nfc_int_pi1, pa6, pcc7, pe6,
+ pe7, pex_l0_clkreq_n_pa1, pex_l0_rst_n_pa0,
+ pex_l1_clkreq_n_pa4, pex_l1_rst_n_pa3, pex_wake_n_pa2, ph6,
+ pk0, pk1, pk2, pk3, pk4, pk5, pk6, pk7, pl0, pl1,
+ pwr_i2c_scl_py3, pwr_i2c_sda_py4, pwr_int_n, pz0, pz1, pz2,
+ pz3, pz4, pz5, qspi_cs_n_pee1, qspi_io0_pee2,
+ qspi_io1_pee3, qspi_io2_pee4, qspi_io3_pee5, qspi_sck_pee0,
+ sata_led_active_pa5, sdmmc1_clk_pm0, sdmmc1_cmd_pm1,
+ sdmmc1_dat0_pm5, sdmmc1_dat1_pm4, sdmmc1_dat2_pm3,
+ sdmmc1_dat3_pm2, sdmmc3_clk_pp0, sdmmc3_cmd_pp1,
+ sdmmc3_dat0_pp5, sdmmc3_dat1_pp4, sdmmc3_dat2_pp3,
+ sdmmc3_dat3_pp2, shutdown, spdif_in_pcc3, spdif_out_pcc2,
+ spi1_cs0_pc3, spi1_cs1_pc4, spi1_miso_pc1, spi1_mosi_pc0,
+ spi1_sck_pc2, spi2_cs0_pb7, spi2_cs1_pdd0, spi2_miso_pb5,
+ spi2_mosi_pb4, spi2_sck_pb6, spi4_cs0_pc6, spi4_miso_pd0,
+ spi4_mosi_pc7, spi4_sck_pc5, temp_alert_px4, touch_clk_pv7,
+ touch_int_px1, touch_rst_pv6, uart1_cts_pu3, uart1_rts_pu2,
+ uart1_rx_pu1, uart1_tx_pu0, uart2_cts_pg3, uart2_rts_pg2,
+ uart2_rx_pg1, uart2_tx_pg0, uart3_cts_pd4, uart3_rts_pd3,
+ uart3_rx_pd2, uart3_tx_pd1, uart4_cts_pi7, uart4_rts_pi6,
+ uart4_rx_pi5, uart4_tx_pi4, usb_vbus_en0_pcc4,
+ usb_vbus_en1_pcc5, wifi_en_ph0, wifi_rst_ph1,
+ wifi_wake_ap_ph2,
+ # drive groups
+ drive_pa6, drive_pcc7, drive_pe6, drive_pe7, drive_ph6,
+ drive_pk0, drive_pk1, drive_pk2, drive_pk3, drive_pk4,
+ drive_pk5, drive_pk6, drive_pk7, drive_pl0, drive_pl1,
+ drive_pz0, drive_pz1, drive_pz2, drive_pz3, drive_pz4,
+ drive_pz5, drive_sdmmc1, drive_sdmmc2, drive_sdmmc3,
+ drive_sdmmc4 ]
+
+ nvidia,function:
+ enum: [ aud, bcl, blink, ccla, cec, cldvfs, clk, core, cpu, displaya,
+ displayb, dmic1, dmic2, dmic3, dp, dtv, extperiph3, i2c1,
+ i2c2, i2c3, i2cpmu, i2cvi, i2s1, i2s2, i2s3, i2s4a, i2s4b,
+ i2s5a, i2s5b, iqc0, iqc1, jtag, pe, pe0, pe1, pmi, pwm0,
+ pwm1, pwm2, pwm3, qspi, rsvd0, rsvd1, rsvd2, rsvd3, sata,
+ sdmmc1, sdmmc3, shutdown, soc, sor0, sor1, spdif, spi1, spi2,
+ spi3, spi4, sys, touch, uart, uarta, uartb, uartc, uartd,
+ usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, vimclk, vimclk2 ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,pull-down-strength: true
+ nvidia,pull-up-strength: true
+ nvidia,high-speed-mode: true
+ nvidia,enable-input: true
+ nvidia,open-drain: true
+ nvidia,lock: true
+ nvidia,drive-type: true
+ nvidia,io-hv: true
+ nvidia,slew-rate-rising: true
+ nvidia,slew-rate-falling: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/pinctrl-tegra.h>
+
+ pinmux: pinmux@70000800 {
+ compatible = "nvidia,tegra210-pinmux";
+ reg = <0x700008d4 0x02a8>, /* Pad control registers */
+ <0x70003000 0x1000>; /* Mux registers */
+
+ pinctrl-names = "boot";
+ pinctrl-0 = <&state_boot>;
+
+ state_boot: pinmux {
+ gen1_i2c_scl_pj1 {
+ nvidia,pins = "gen1_i2c_scl_pj1";
+ nvidia,function = "i2c1";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+ nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+ nvidia,io-hv = <TEGRA_PIN_ENABLE>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt
deleted file mode 100644
index 0e6354c11e6d..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt
+++ /dev/null
@@ -1,144 +0,0 @@
-NVIDIA Tegra30 pinmux controller
-
-The Tegra30 pinctrl binding is very similar to the Tegra20 pinctrl binding,
-as described in nvidia,tegra20-pinmux.txt. In fact, this document assumes
-that binding as a baseline, and only documents the differences between the
-two bindings.
-
-Required properties:
-- compatible: "nvidia,tegra30-pinmux"
-- reg: Should contain the register physical address and length for each of
- the pad control and mux registers.
-
-Tegra30 adds the following optional properties for pin configuration subnodes:
-- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes.
-- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes.
-- nvidia,lock: Integer. Lock the pin configuration against further changes
- until reset. 0: no, 1: yes.
-- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes.
-
-As with Tegra20, see the Tegra TRM for complete details regarding which groups
-support which functionality.
-
-Valid values for pin and group names are:
-
- per-pin mux groups:
-
- These all support nvidia,function, nvidia,tristate, nvidia,pull,
- nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain,
- nvidia,io-reset.
-
- clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2, dap2_sclk_pa3,
- dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6, sdmmc3_cmd_pa7, gmi_a17_pb0,
- gmi_a18_pb1, lcd_pwr0_pb2, lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5,
- sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0, lcd_pwr1_pc1,
- uart2_txd_pc2, uart2_rxd_pc3, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5,
- lcd_pwr2_pc6, gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1, lcd_dc1_pd2,
- sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5, vi_vsync_pd6, vi_hsync_pd7,
- lcd_d0_pe0, lcd_d1_pe1, lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5,
- lcd_d6_pe6, lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2, lcd_d11_pf3,
- lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6, lcd_d15_pf7, gmi_ad0_pg0,
- gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5,
- gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
- gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7,
- gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2, gmi_cs6_n_pi3, gmi_rst_n_pi4,
- gmi_iordy_pi5, gmi_cs7_n_pi6, gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1,
- gmi_cs1_n_pj2, lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5,
- uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs4_n_pk2,
- gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5, spdif_in_pk6, gmi_a19_pk7,
- vi_d2_pl0, vi_d3_pl1, vi_d4_pl2, vi_d5_pl3, vi_d6_pl4, vi_d7_pl5,
- vi_d8_pl6, vi_d9_pl7, lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3,
- lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7, dap1_fs_pn0,
- dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, lcd_cs0_n_pn4, lcd_sdout_pn5,
- lcd_dc0_pn6, hdmi_int_pn7, ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2,
- ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6,
- ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3,
- dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0,
- kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
- kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2,
- kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7,
- kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4,
- kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1,
- vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6,
- sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4, pu5, pu6, jtag_rtck_pu7, pv0,
- pv1, pv2, pv3, ddc_scl_pv4, ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7,
- lcd_cs1_n_pw0, lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4,
- clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0, spi2_miso_px1,
- spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4, spi1_sck_px5, spi1_cs0_n_px6,
- spi1_miso_px7, ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3,
- sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7,
- sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3, lcd_sck_pz4,
- sys_clk_req_pz5, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, sdmmc4_dat0_paa0,
- sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4,
- sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0,
- cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7,
- cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3, sdmmc4_clk_pcc4,
- clk2_req_pcc5, pex_l2_rst_n_pcc6, pex_l2_clkreq_n_pcc7,
- pex_l0_prsnt_n_pdd0, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2,
- pex_wake_n_pdd3, pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5,
- pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0, clk3_req_pee1,
- clk1_req_pee2, hdmi_cec_pee3, clk_32k_in, core_pwr_req, cpu_pwr_req, owr,
- pwr_int_n.
-
- drive groups:
-
- These all support nvidia,pull-down-strength, nvidia,pull-up-strength,
- nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all
- support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode.
-
- ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, cec, crt, csus, dap1,
- dap2, dap3, dap4, dbg, ddc, dev3, gma, gmb, gmc, gmd, gme, gmf, gmg,
- gmh, gpv, lcd1, lcd2, owr, sdio1, sdio2, sdio3, spi, uaa, uab, uart2,
- uart3, uda, vi1.
-
-Valid values for nvidia,functions are:
-
- blink, cec, clk_12m_out, clk_32k_in, core_pwr_req, cpu_pwr_req, crt,
- dap, ddr, dev3, displaya, displayb, dtv, extperiph1, extperiph2,
- extperiph3, gmi, gmi_alt, hda, hdcp, hdmi, hsi, i2c1, i2c2, i2c3,
- i2c4, i2cpwr, i2s0, i2s1, i2s2, i2s3, i2s4, invalid, kbc, mio, nand,
- nand_alt, owr, pcie, pwm0, pwm1, pwm2, pwm3, pwr_int_n, rsvd1, rsvd2,
- rsvd3, rsvd4, rtck, sata, sdmmc1, sdmmc2, sdmmc3, sdmmc4, spdif, spi1,
- spi2, spi2_alt, spi3, spi4, spi5, spi6, sysclk, test, trace, uarta,
- uartb, uartc, uartd, uarte, ulpi, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6,
- vi, vi_alt1, vi_alt2, vi_alt3
-
-Example:
-
- pinctrl@70000000 {
- compatible = "nvidia,tegra30-pinmux";
- reg = < 0x70000868 0xd0 /* Pad control registers */
- 0x70003000 0x3e0 >; /* Mux registers */
- };
-
-Example board file extract:
-
- pinctrl@70000000 {
- sdmmc4_default: pinmux {
- sdmmc4_clk_pcc4 {
- nvidia,pins = "sdmmc4_clk_pcc4",
- "sdmmc4_rst_n_pcc3";
- nvidia,function = "sdmmc4";
- nvidia,pull = <0>;
- nvidia,tristate = <0>;
- };
- 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,function = "sdmmc4";
- nvidia,pull = <2>;
- nvidia,tristate = <0>;
- };
- };
- };
-
- sdhci@78000400 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc4_default>;
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.yaml
new file mode 100644
index 000000000000..c0eda7848767
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.yaml
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra30-pinmux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 pinmux Controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ const: nvidia,tegra30-pinmux
+
+ reg:
+ items:
+ - description: pad control registers
+ - description: mux registers
+
+patternProperties:
+ "^pinmux(-[a-z0-9-_]+)?$":
+ type: object
+ properties:
+ phandle: true
+
+ # pin groups
+ additionalProperties:
+ $ref: nvidia,tegra-pinmux-common.yaml
+ additionalProperties: false
+ properties:
+ nvidia,pins:
+ items:
+ enum: [ clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2,
+ dap2_sclk_pa3, dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6,
+ sdmmc3_cmd_pa7, gmi_a17_pb0, gmi_a18_pb1, lcd_pwr0_pb2,
+ lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5,
+ sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0,
+ lcd_pwr1_pc1, uart2_txd_pc2, uart2_rxd_pc3,
+ gen1_i2c_scl_pc4, gen1_i2c_sda_pc5, lcd_pwr2_pc6,
+ gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1,
+ lcd_dc1_pd2, sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5,
+ vi_vsync_pd6, vi_hsync_pd7, lcd_d0_pe0, lcd_d1_pe1,
+ lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5, lcd_d6_pe6,
+ lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2,
+ lcd_d11_pf3, lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6,
+ lcd_d15_pf7, gmi_ad0_pg0, gmi_ad1_pg1, gmi_ad2_pg2,
+ gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, gmi_ad6_pg6,
+ gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
+ gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6,
+ gmi_ad15_ph7, gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2,
+ gmi_cs6_n_pi3, gmi_rst_n_pi4, gmi_iordy_pi5, gmi_cs7_n_pi6,
+ gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1, gmi_cs1_n_pj2,
+ lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5,
+ uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1,
+ gmi_cs4_n_pk2, gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5,
+ spdif_in_pk6, gmi_a19_pk7, vi_d2_pl0, vi_d3_pl1, vi_d4_pl2,
+ vi_d5_pl3, vi_d6_pl4, vi_d7_pl5, vi_d8_pl6, vi_d9_pl7,
+ lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3,
+ lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7,
+ dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3,
+ lcd_cs0_n_pn4, lcd_sdout_pn5, lcd_dc0_pn6, hdmi_int_pn7,
+ ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2,
+ ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5,
+ ulpi_data5_po6, ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1,
+ dap3_dout_pp2, dap3_sclk_pp3, dap4_fs_pp4, dap4_din_pp5,
+ dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0, kb_col1_pq1,
+ kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
+ kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1,
+ kb_row2_pr2, kb_row3_pr3, kb_row4_pr4, kb_row5_pr5,
+ kb_row6_pr6, kb_row7_pr7, kb_row8_ps0, kb_row9_ps1,
+ kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, kb_row13_ps5,
+ kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1,
+ vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5,
+ gen2_i2c_sda_pt6, sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4,
+ pu5, pu6, jtag_rtck_pu7, pv0, pv1, pv2, pv3, ddc_scl_pv4,
+ ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7, lcd_cs1_n_pw0,
+ lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4,
+ clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0,
+ spi2_miso_px1, spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4,
+ spi1_sck_px5, spi1_cs0_n_px6, spi1_miso_px7, ulpi_clk_py0,
+ ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, sdmmc1_dat3_py4,
+ sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7,
+ sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3,
+ lcd_sck_pz4, sys_clk_req_pz5, pwr_i2c_scl_pz6,
+ pwr_i2c_sda_pz7, sdmmc4_dat0_paa0, sdmmc4_dat1_paa1,
+ sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4,
+ sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0,
+ cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6,
+ pbb7, cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3,
+ sdmmc4_clk_pcc4, clk2_req_pcc5, pex_l2_rst_n_pcc6,
+ pex_l2_clkreq_n_pcc7, pex_l0_prsnt_n_pdd0,
+ pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2, pex_wake_n_pdd3,
+ pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5,
+ pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0,
+ clk3_req_pee1, clk1_req_pee2, hdmi_cec_pee3, clk_32k_in,
+ core_pwr_req, cpu_pwr_req, owr, pwr_int_n,
+ # drive groups
+ drive_ao1, drive_ao2, drive_at1, drive_at2, drive_at3,
+ drive_at4, drive_at5, drive_cdev1, drive_cdev2, drive_cec,
+ drive_crt, drive_csus, drive_dap1, drive_dap2, drive_dap3,
+ drive_dap4, drive_dbg, drive_ddc, drive_dev3, drive_gma,
+ drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_gmf,
+ drive_gmg, drive_gmh, drive_gpv, drive_lcd1, drive_lcd2,
+ drive_owr, drive_sdio1, drive_sdio2, drive_sdio3,
+ drive_spi, drive_uaa, drive_uab, drive_uart2, drive_uart3,
+ drive_uda, drive_vi1 ]
+
+ nvidia,function:
+ enum: [ blink, cec, clk_12m_out, clk_32k_in, core_pwr_req,
+ cpu_pwr_req, crt, dap, ddr, dev3, displaya, displayb, dtv,
+ extperiph1, extperiph2, extperiph3, gmi, gmi_alt, hda, hdcp,
+ hdmi, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr, i2s0, i2s1, i2s2,
+ i2s3, i2s4, invalid, kbc, mio, nand, nand_alt, owr, pcie,
+ pwm0, pwm1, pwm2, pwm3, pwr_int_n, rsvd1, rsvd2, rsvd3,
+ rsvd4, rtck, sata, sdmmc1, sdmmc2, sdmmc3, sdmmc4, spdif,
+ spi1, spi2, spi2_alt, spi3, spi4, spi5, spi6, sysclk, test,
+ trace, uarta, uartb, uartc, uartd, uarte, ulpi, vgp1, vgp2,
+ vgp3, vgp4, vgp5, vgp6, vi, vi_alt1, vi_alt2, vi_alt3 ]
+
+ nvidia,pull: true
+ nvidia,tristate: true
+ nvidia,schmitt: true
+ nvidia,pull-down-strength: true
+ nvidia,pull-up-strength: true
+ nvidia,high-speed-mode: true
+ nvidia,low-power-mode: true
+ nvidia,enable-input: true
+ nvidia,open-drain: true
+ nvidia,lock: true
+ nvidia,io-reset: true
+ nvidia,slew-rate-rising: true
+ nvidia,slew-rate-falling: true
+
+ required:
+ - nvidia,pins
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ pinctrl@70000000 {
+ compatible = "nvidia,tegra30-pinmux";
+ reg = <0x70000868 0x0d0>, /* Pad control registers */
+ <0x70003000 0x3e0>; /* Mux registers */
+
+ pinmux {
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ "sdmmc4_rst_n_pcc3";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+
+ 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,function = "sdmmc4";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
index 5b4eda919911..633d49884019 100644
--- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
+++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
@@ -28,15 +28,18 @@ properties:
- qcom,msm8998-rpmpd
- qcom,qcm2290-rpmpd
- qcom,qcs404-rpmpd
+ - qcom,qdu1000-rpmhpd
- qcom,sa8540p-rpmhpd
- qcom,sdm660-rpmpd
- qcom,sc7180-rpmhpd
- qcom,sc7280-rpmhpd
- qcom,sc8180x-rpmhpd
- qcom,sc8280xp-rpmhpd
+ - qcom,sdm670-rpmhpd
- qcom,sdm845-rpmhpd
- qcom,sdx55-rpmhpd
- qcom,sdx65-rpmhpd
+ - qcom,sm4250-rpmpd
- qcom,sm6115-rpmpd
- qcom,sm6125-rpmpd
- qcom,sm6350-rpmhpd
@@ -45,6 +48,7 @@ properties:
- qcom,sm8250-rpmhpd
- qcom,sm8350-rpmhpd
- qcom,sm8450-rpmhpd
+ - qcom,sm8550-rpmhpd
'#power-domain-cells':
const: 1
diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
index 4cc3cc7c50be..66e400f2a3a4 100644
--- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
@@ -25,7 +25,9 @@ properties:
- const: allwinner,sun8i-a83t-pwm
- const: allwinner,sun8i-h3-pwm
- items:
- - const: allwinner,sun8i-v3s-pwm
+ - enum:
+ - allwinner,suniv-f1c100s-pwm
+ - allwinner,sun8i-v3s-pwm
- const: allwinner,sun7i-a20-pwm
- items:
- const: allwinner,sun50i-a64-pwm
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml
index c8577bdf6c94..3afe1480df52 100644
--- a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml
@@ -48,6 +48,7 @@ examples:
cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
+ interrupts = <101 0>;
cros_ec_pwm: pwm {
compatible = "google,cros-ec-pwm";
diff --git a/Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml b/Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
index a7fae1772a81..cd8e9a8907f8 100644
--- a/Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
@@ -30,7 +30,9 @@ properties:
maxItems: 1
"#pwm-cells":
- const: 2
+ enum: [2, 3]
+ description:
+ The only flag supported by the controller is PWM_POLARITY_INVERTED.
microchip,sync-update-mask:
description: |
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
deleted file mode 100644
index 74c41e34c3b6..000000000000
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-Tegra SoC PWFM controller
-
-Required properties:
-- compatible: Must be:
- - "nvidia,tegra20-pwm": for Tegra20
- - "nvidia,tegra30-pwm", "nvidia,tegra20-pwm": for Tegra30
- - "nvidia,tegra114-pwm", "nvidia,tegra20-pwm": for Tegra114
- - "nvidia,tegra124-pwm", "nvidia,tegra20-pwm": for Tegra124
- - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132
- - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
- - "nvidia,tegra186-pwm": for Tegra186
- - "nvidia,tegra194-pwm": for Tegra194
-- reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
- the cells format.
-- clocks: Must contain one entry, for the module clock.
- See ../clocks/clock-bindings.txt for details.
-- resets: Must contain an entry for each entry in reset-names.
- See ../reset/reset.txt for details.
-- reset-names: Must include the following entries:
- - pwm
-
-Optional properties:
-============================
-In some of the interface like PWM based regulator device, it is required
-to configure the pins differently in different states, especially in suspend
-state of the system. The configuration of pin is provided via the pinctrl
-DT node as detailed in the pinctrl DT binding document
- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
-
-The PWM node will have following optional properties.
-pinctrl-names: Pin state names. Must be "default" and "sleep".
-pinctrl-0: phandle for the default/active state of pin configurations.
-pinctrl-1: phandle for the sleep state of pin configurations.
-
-Example:
-
- pwm: pwm@7000a000 {
- compatible = "nvidia,tegra20-pwm";
- reg = <0x7000a000 0x100>;
- #pwm-cells = <2>;
- clocks = <&tegra_car 17>;
- resets = <&tegra_car 17>;
- reset-names = "pwm";
- };
-
-
-Example with the pin configuration for suspend and resume:
-=========================================================
-Suppose pin PE7 (On Tegra210) interfaced with the regulator device and
-it requires PWM output to be tristated when system enters suspend.
-Following will be DT binding to achieve this:
-
-#include <dt-bindings/pinctrl/pinctrl-tegra.h>
-
- pinmux@700008d4 {
- pwm_active_state: pwm_active_state {
- pe7 {
- nvidia,pins = "pe7";
- nvidia,tristate = <TEGRA_PIN_DISABLE>;
- };
- };
-
- pwm_sleep_state: pwm_sleep_state {
- pe7 {
- nvidia,pins = "pe7";
- nvidia,tristate = <TEGRA_PIN_ENABLE>;
- };
- };
- };
-
- pwm@7000a000 {
- /* Mandatory PWM properties */
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&pwm_active_state>;
- pinctrl-1 = <&pwm_sleep_state>;
- };
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.yaml b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.yaml
new file mode 100644
index 000000000000..739d3155dd32
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/nvidia,tegra20-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra PWFM controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - nvidia,tegra20-pwm
+ - nvidia,tegra186-pwm
+
+ - items:
+ - enum:
+ - nvidia,tegra30-pwm
+ - nvidia,tegra114-pwm
+ - nvidia,tegra124-pwm
+ - nvidia,tegra132-pwm
+ - nvidia,tegra210-pwm
+ - enum:
+ - nvidia,tegra20-pwm
+
+ - items:
+ - const: nvidia,tegra194-pwm
+ - const: nvidia,tegra186-pwm
+
+ - items:
+ - const: nvidia,tegra234-pwm
+ - const: nvidia,tegra194-pwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: module reset
+
+ reset-names:
+ items:
+ - const: pwm
+
+ "#pwm-cells":
+ const: 2
+
+ pinctrl-names:
+ items:
+ - const: default
+ - const: sleep
+
+ pinctrl-0:
+ description: configuration for the default/active state
+
+ pinctrl-1:
+ description: configuration for the sleep state
+
+ operating-points-v2:
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ power-domains:
+ items:
+ - description: phandle to the core power domain
+
+allOf:
+ - $ref: pwm.yaml
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - reset-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra20-car.h>
+
+ pwm: pwm@7000a000 {
+ compatible = "nvidia,tegra20-pwm";
+ reg = <0x7000a000 0x100>;
+ #pwm-cells = <2>;
+ clocks = <&tegra_car TEGRA20_CLK_PWM>;
+ resets = <&tegra_car 17>;
+ reset-names = "pwm";
+ };
diff --git a/Documentation/devicetree/bindings/regulator/google,cros-ec-regulator.yaml b/Documentation/devicetree/bindings/regulator/google,cros-ec-regulator.yaml
index 69e5402da761..0921f012c901 100644
--- a/Documentation/devicetree/bindings/regulator/google,cros-ec-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/google,cros-ec-regulator.yaml
@@ -41,6 +41,7 @@ examples:
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
+ interrupts = <99 0>;
regulator@0 {
compatible = "google,cros-ec-regulator";
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index 90a7cabf58fe..83ad177a9043 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -28,17 +28,20 @@ properties:
oneOf:
- items:
- enum:
- - sifive,rocket0
+ - andestech,ax45mp
+ - canaan,k210
- sifive,bullet0
- sifive,e5
- sifive,e7
- sifive,e71
- - sifive,u74-mc
- - sifive,u54
- - sifive,u74
+ - sifive,rocket0
- sifive,u5
+ - sifive,u54
- sifive,u7
- - canaan,k210
+ - sifive,u74
+ - sifive,u74-mc
+ - thead,c906
+ - thead,c910
- const: riscv
- items:
- enum:
diff --git a/Documentation/devicetree/bindings/riscv/starfive.yaml b/Documentation/devicetree/bindings/riscv/starfive.yaml
index 5b36243fd674..5d3fcee52d59 100644
--- a/Documentation/devicetree/bindings/riscv/starfive.yaml
+++ b/Documentation/devicetree/bindings/riscv/starfive.yaml
@@ -19,7 +19,9 @@ properties:
compatible:
oneOf:
- items:
- - const: beagle,beaglev-starlight-jh7100-r0
+ - enum:
+ - beagle,beaglev-starlight-jh7100-r0
+ - starfive,visionfive-v1
- const: starfive,jh7100
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
index d24e2bc444be..12e4b4260b40 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
@@ -30,6 +30,7 @@ Required properties in pwrap device node.
"mediatek,mt8186-pwrap" for MT8186 SoCs
"mediatek,mt8188-pwrap", "mediatek,mt8195-pwrap" for MT8188 SoCs
"mediatek,mt8195-pwrap" for MT8195 SoCs
+ "mediatek,mt8365-pwrap" for MT8365 SoCs
"mediatek,mt8516-pwrap" for MT8516 SoCs
- interrupts: IRQ for pwrap in SOC
- reg-names: "pwrap" is required; "pwrap-bridge" is optional.
@@ -39,6 +40,8 @@ Required properties in pwrap device node.
- clock-names: Must include the following entries:
"spi": SPI bus clock
"wrap": Main module clock
+ "sys": Optional system module clock
+ "tmr": Optional timer module clock
- clocks: Must contain an entry for each entry in clock-names.
Optional properities:
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
index a4eeb7e158e5..98d087cf4fc0 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
@@ -28,12 +28,14 @@ properties:
- qcom,sc7180-aoss-qmp
- qcom,sc7280-aoss-qmp
- qcom,sc8180x-aoss-qmp
+ - qcom,sc8280xp-aoss-qmp
- qcom,sdm845-aoss-qmp
- qcom,sm6350-aoss-qmp
- qcom,sm8150-aoss-qmp
- qcom,sm8250-aoss-qmp
- qcom,sm8350-aoss-qmp
- qcom,sm8450-aoss-qmp
+ - qcom,sm8550-aoss-qmp
- const: qcom,aoss-qmp
reg:
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml
new file mode 100644
index 000000000000..290555426c39
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/qcom/qcom,apr-services.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm APR/GPR services shared parts
+
+maintainers:
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+ Common parts of a static service in Qualcomm APR/GPR (Asynchronous/Generic
+ Packet Router).
+
+properties:
+ reg:
+ minimum: 1
+ maximum: 13
+ description: |
+ APR Service ID
+ 3 = DSP Core Service
+ 4 = Audio Front End Service.
+ 5 = Voice Stream Manager Service.
+ 6 = Voice processing manager.
+ 7 = Audio Stream Manager Service.
+ 8 = Audio Device Manager Service.
+ 9 = Multimode voice manager.
+ 10 = Core voice stream.
+ 11 = Core voice processor.
+ 12 = Ultrasound stream manager.
+ 13 = Listen stream manager.
+ GPR Service ID
+ 1 = Audio Process Manager Service
+ 2 = Proxy Resource Manager Service.
+ 3 = AMDB Service.
+ 4 = Voice processing manager.
+
+ qcom,protection-domain:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ description: |
+ Protection domain service name and path for APR service
+ possible values are::
+ "avs/audio", "msm/adsp/audio_pd".
+ "kernel/elf_loader", "msm/modem/wlan_pd".
+ "tms/servreg", "msm/adsp/audio_pd".
+ "tms/servreg", "msm/modem/wlan_pd".
+ "tms/servreg", "msm/slpi/sensor_pd".
+
+required:
+ - reg
+ - qcom,protection-domain
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml
index f47491aab3b1..a6bc3197d5dd 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml
@@ -17,6 +17,7 @@ description: |
properties:
compatible:
enum:
+ - qcom,apr
- qcom,apr-v2
- qcom,gpr
@@ -58,8 +59,7 @@ properties:
qcom,glink-channels:
$ref: /schemas/types.yaml#/definitions/string-array
description: Channel name used for the communication
- items:
- - const: apr_audio_svc
+ maxItems: 1
qcom,intents:
$ref: /schemas/types.yaml#/definitions/uint32-array
@@ -81,12 +81,13 @@ properties:
'#size-cells':
const: 0
-#APR/GPR Services
patternProperties:
"^service@[1-9a-d]$":
type: object
+ $ref: /schemas/soc/qcom/qcom,apr-services.yaml
+ additionalProperties: true
description:
- APR/GPR node's client devices use subnodes for desired static port services.
+ APR/GPR static port services.
properties:
compatible:
@@ -98,99 +99,6 @@ patternProperties:
- qcom,q6apm
- qcom,q6prm
- reg:
- minimum: 1
- maximum: 13
- description:
- APR Service ID
- 3 = DSP Core Service
- 4 = Audio Front End Service.
- 5 = Voice Stream Manager Service.
- 6 = Voice processing manager.
- 7 = Audio Stream Manager Service.
- 8 = Audio Device Manager Service.
- 9 = Multimode voice manager.
- 10 = Core voice stream.
- 11 = Core voice processor.
- 12 = Ultrasound stream manager.
- 13 = Listen stream manager.
- GPR Service ID
- 1 = Audio Process Manager Service
- 2 = Proxy Resource Manager Service.
- 3 = AMDB Service.
- 4 = Voice processing manager.
-
- clock-controller:
- $ref: /schemas/sound/qcom,q6dsp-lpass-clocks.yaml#
- description: Qualcomm DSP LPASS clock controller
- unevaluatedProperties: false
-
- dais:
- type: object
- oneOf:
- - $ref: /schemas/sound/qcom,q6apm-dai.yaml#
- - $ref: /schemas/sound/qcom,q6dsp-lpass-ports.yaml#
- - $ref: /schemas/sound/qcom,q6asm-dais.yaml#
- unevaluatedProperties: false
- description: Qualcomm DSP audio ports
-
- routing:
- type: object
- $ref: /schemas/sound/qcom,q6adm-routing.yaml#
- unevaluatedProperties: false
- description: Qualcomm DSP LPASS audio routing
-
- qcom,protection-domain:
- $ref: /schemas/types.yaml#/definitions/string-array
- description: protection domain service name and path for apr service
- possible values are
- "avs/audio", "msm/adsp/audio_pd".
- "kernel/elf_loader", "msm/modem/wlan_pd".
- "tms/servreg", "msm/adsp/audio_pd".
- "tms/servreg", "msm/modem/wlan_pd".
- "tms/servreg", "msm/slpi/sensor_pd".
-
- allOf:
- - if:
- properties:
- compatible:
- enum:
- - qcom,q6afe
- then:
- properties:
- dais:
- properties:
- compatible:
- const: qcom,q6afe-dais
-
- - if:
- properties:
- compatible:
- enum:
- - qcom,q6apm
- then:
- properties:
- dais:
- properties:
- compatible:
- enum:
- - qcom,q6apm-dais
- - qcom,q6apm-lpass-dais
-
- - if:
- properties:
- compatible:
- enum:
- - qcom,q6asm
- then:
- properties:
- dais:
- properties:
- compatible:
- const: qcom,q6asm-dais
-
- additionalProperties: false
-
required:
- compatible
- qcom,domain
@@ -203,7 +111,15 @@ allOf:
- qcom,gpr
then:
properties:
+ qcom,glink-channels:
+ items:
+ - const: adsp_apps
power-domains: false
+ else:
+ properties:
+ qcom,glink-channels:
+ items:
+ - const: apr_audio_svc
- if:
required:
@@ -227,31 +143,35 @@ examples:
apr {
compatible = "qcom,apr-v2";
qcom,domain = <APR_DOMAIN_ADSP>;
+ qcom,glink-channels = "apr_audio_svc";
+ qcom,intents = <512 20>;
#address-cells = <1>;
#size-cells = <0>;
q6core: service@3 {
- compatible = "qcom,q6core";
- reg = <APR_SVC_ADSP_CORE>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
- };
-
- q6afe: service@4 {
- compatible = "qcom,q6afe";
- reg = <APR_SVC_AFE>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
- };
-
- q6asm: service@7 {
- compatible = "qcom,q6asm";
- reg = <APR_SVC_ASM>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+ compatible = "qcom,q6core";
+ reg = <APR_SVC_ADSP_CORE>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
- q6adm: service@8 {
- compatible = "qcom,q6adm";
- reg = <APR_SVC_ADM>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+ service@4 {
+ compatible = "qcom,q6afe";
+ reg = <APR_SVC_AFE>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ clock-controller {
+ compatible = "qcom,q6afe-clocks";
+ #clock-cells = <2>;
+ };
+
+ dais {
+ compatible = "qcom,q6afe-dais";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ /* ... */
+ };
+ /* ... */
};
};
@@ -260,12 +180,25 @@ examples:
gpr {
compatible = "qcom,gpr";
qcom,domain = <GPR_DOMAIN_ID_ADSP>;
+ qcom,glink-channels = "adsp_apps";
+ qcom,intents = <512 20>;
#address-cells = <1>;
#size-cells = <0>;
service@1 {
- compatible = "qcom,q6apm";
- reg = <GPR_APM_MODULE_IID>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+ compatible = "qcom,q6apm";
+ reg = <GPR_APM_MODULE_IID>;
+ #sound-dai-cells = <0>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ dais {
+ compatible = "qcom,q6apm-dais";
+ iommus = <&apps_smmu 0x1801 0x0>;
+ };
+
+ bedais {
+ compatible = "qcom,q6apm-lpass-dais";
+ #sound-dai-cells = <1>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
index 4a50f1d27724..b246500d3d5d 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
@@ -99,6 +99,9 @@ properties:
- const: drv-2
- const: drv-3
+ power-domains:
+ maxItems: 1
+
bcm-voter:
$ref: /schemas/interconnect/qcom,bcm-voter.yaml#
@@ -151,6 +154,7 @@ examples:
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 1>;
+ power-domains = <&CLUSTER_PD>;
};
- |
@@ -197,6 +201,7 @@ examples:
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 0>;
+ power-domains = <&CLUSTER_PD>;
clock-controller {
compatible = "qcom,sm8350-rpmh-clk";
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
index 09d5bfa920f2..11c0f4dd797c 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
@@ -4,7 +4,7 @@
$id: "http://devicetree.org/schemas/soc/qcom/qcom,smd-rpm.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
-title: Qualcomm Resource Power Manager (RPM) over SMD
+title: Qualcomm Resource Power Manager (RPM) over SMD/GLINK
description: |
This driver is used to interface with the Resource Power Manager (RPM) found
@@ -12,9 +12,9 @@ description: |
to vote for state of the system resources, such as clocks, regulators and bus
frequencies.
- The SMD information for the RPM edge should be filled out. See qcom,smd.yaml
- for the required edge properties. All SMD related properties will reside
- within the RPM node itself.
+ The SMD or GLINK information for the RPM edge should be filled out. See
+ qcom,smd.yaml for the required edge properties. All SMD/GLINK related
+ properties will reside within the RPM node itself.
The RPM exposes resources to its subnodes. The rpm_requests node must be
present and this subnode may contain children that designate regulator
@@ -45,6 +45,7 @@ properties:
- qcom,rpm-sdm660
- qcom,rpm-sm6115
- qcom,rpm-sm6125
+ - qcom,rpm-sm6375
- qcom,rpm-qcm2290
- qcom,rpm-qcs404
@@ -55,12 +56,23 @@ properties:
power-controller:
$ref: /schemas/power/qcom,rpmpd.yaml#
+ qcom,glink-channels:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ description: Channel name used for the RPM communication
+ items:
+ - const: rpm_requests
+
qcom,smd-channels:
$ref: /schemas/types.yaml#/definitions/string-array
description: Channel name used for the RPM communication
items:
- const: rpm_requests
+patternProperties:
+ "^regulators(-[01])?$":
+ $ref: /schemas/regulator/qcom,smd-rpm-regulator.yaml#
+ unevaluatedProperties: false
+
if:
properties:
compatible:
@@ -69,10 +81,18 @@ if:
- qcom,rpm-apq8084
- qcom,rpm-msm8916
- qcom,rpm-msm8974
+ - qcom,rpm-msm8976
- qcom,rpm-msm8953
then:
+ properties:
+ qcom,glink-channels: false
required:
- qcom,smd-channels
+else:
+ properties:
+ qcom,smd-channels: false
+ required:
+ - qcom,glink-channels
required:
- compatible
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml
index 795bd8cd4104..58500529b90f 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml
@@ -60,7 +60,7 @@ properties:
Two identifiers of the inbound and outbound smem items used for this edge.
patternProperties:
- "^master-kernel|slave-kernel|ipa-ap-to-modem|ipa-modem-to-ap$":
+ "^master-kernel|slave-kernel|ipa-ap-to-modem|ipa-modem-to-ap|wlan-ap-to-wpss|wlan-wpss-to-ap$":
type: object
description:
Each SMP2P pair contain a set of inbound and outbound entries, these are
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
index f433e6e0a19f..38818c37c3ea 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
@@ -24,8 +24,11 @@ properties:
- qcom,msm8998-silver-saw2-v4.1-l2
- qcom,msm8909-saw2-v3.0-cpu
- qcom,msm8916-saw2-v3.0-cpu
+ - qcom,msm8939-saw2-v3.0-cpu
- qcom,msm8226-saw2-v2.1-cpu
- qcom,msm8974-saw2-v2.1-cpu
+ - qcom,msm8976-gold-saw2-v2.3-l2
+ - qcom,msm8976-silver-saw2-v2.3-l2
- qcom,apq8084-saw2-v2.1-cpu
- qcom,apq8064-saw2-v1.1-cpu
- const: qcom,saw2
diff --git a/Documentation/devicetree/bindings/soc/renesas/renesas,r9a09g011-sys.yaml b/Documentation/devicetree/bindings/soc/renesas/renesas,r9a09g011-sys.yaml
new file mode 100644
index 000000000000..1cac3cb5226c
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/renesas/renesas,r9a09g011-sys.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/renesas/renesas,r9a09g011-sys.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/V2M System Configuration (SYS)
+
+maintainers:
+ - Geert Uytterhoeven <geert+renesas@glider.be>
+
+description:
+ The RZ/V2M-alike SYS (System Configuration) controls the overall
+ configuration of the LSI and supports the following functions,
+ - Bank address settings for DMAC
+ - Bank address settings of the units for ICB
+ - ETHER AxCACHE[1] (C bit) control function
+ - RAMA initialization control
+ - MD[7:0] pin monitoring
+ - LSI version
+ - PCIe related settings
+ - WDT stop control
+ - Temperature sensor (TSU) monitor
+
+properties:
+ compatible:
+ const: renesas,r9a09g011-sys
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ sys: system-controller@a3f03000 {
+ compatible = "renesas,r9a09g011-sys";
+ reg = <0xa3f03000 0x400>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/renesas.yaml b/Documentation/devicetree/bindings/soc/renesas/renesas.yaml
index f51464a08aff..2789022b52eb 100644
--- a/Documentation/devicetree/bindings/arm/renesas.yaml
+++ b/Documentation/devicetree/bindings/soc/renesas/renesas.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/arm/renesas.yaml#
+$id: http://devicetree.org/schemas/soc/renesas/renesas.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas SH-Mobile, R-Mobile, and R-Car Platform
@@ -431,11 +431,12 @@ properties:
- renesas,rzn1d400-db # RZN1D-DB (RZ/N1D Demo Board for the RZ/N1D 400 pins package)
- const: renesas,r9a06g032
- - description: RZ/G2UL (R9A07G043)
+ - description: RZ/Five and RZ/G2UL (R9A07G043)
items:
- enum:
- renesas,smarc-evk # SMARC EVK
- enum:
+ - renesas,r9a07g043f01 # RZ/Five
- renesas,r9a07g043u11 # RZ/G2UL Type-1
- renesas,r9a07g043u12 # RZ/G2UL Type-2
- const: renesas,r9a07g043
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1372.yaml b/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
index 59f7c60a14ba..044bcd370d49 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
+++ b/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
@@ -8,12 +8,15 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADAU1372 CODEC
maintainers:
- - Alexandre Belloni <alexandre.belloni@bootlin.om>
+ - Alexandre Belloni <alexandre.belloni@bootlin.com>
description: |
Analog Devices ADAU1372 four inputs and two outputs codec.
https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1372.pdf
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -42,7 +45,7 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.yaml b/Documentation/devicetree/bindings/sound/adi,adau1977.yaml
index 847b83398d3d..dba3023a45e5 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1977.yaml
+++ b/Documentation/devicetree/bindings/sound/adi,adau1977.yaml
@@ -51,6 +51,7 @@ required:
- AVDD-supply
allOf:
+ - $ref: dai-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/sound/adi,adau7118.yaml b/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
index fb78967ee17b..12f60507aed7 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
+++ b/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
@@ -15,6 +15,9 @@ description: |
standalone mode.
https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU7118.pdf
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -57,7 +60,7 @@ required:
- iovdd-supply
- dvdd-supply
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/ak4375.yaml b/Documentation/devicetree/bindings/sound/ak4375.yaml
index 5f0fc584bb38..587598e122c6 100644
--- a/Documentation/devicetree/bindings/sound/ak4375.yaml
+++ b/Documentation/devicetree/bindings/sound/ak4375.yaml
@@ -9,6 +9,9 @@ title: AK4375 DAC and headphones amplifier
maintainers:
- Vincent Knecht <vincent.knecht@mailoo.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: asahi-kasei,ak4375
@@ -35,7 +38,7 @@ required:
- avdd-supply
- tvdd-supply
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/ak4613.yaml b/Documentation/devicetree/bindings/sound/ak4613.yaml
index aa8a258a9f1c..010574645e6a 100644
--- a/Documentation/devicetree/bindings/sound/ak4613.yaml
+++ b/Documentation/devicetree/bindings/sound/ak4613.yaml
@@ -9,6 +9,9 @@ title: AK4613 I2C transmitter
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: asahi-kasei,ak4613
@@ -35,7 +38,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/ak4642.yaml b/Documentation/devicetree/bindings/sound/ak4642.yaml
index 48a5b2c3934e..437fe5d7cae1 100644
--- a/Documentation/devicetree/bindings/sound/ak4642.yaml
+++ b/Documentation/devicetree/bindings/sound/ak4642.yaml
@@ -9,6 +9,9 @@ title: AK4642 I2C transmitter
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -37,7 +40,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
index 292fcb643999..78273647f766 100644
--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
@@ -102,6 +102,7 @@ required:
- dma-names
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
@@ -228,7 +229,7 @@ allOf:
- Mic
- Speaker
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml
index dd30881ad2f5..739114fb6549 100644
--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml
@@ -61,6 +61,7 @@ properties:
maxItems: 1
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
@@ -128,7 +129,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml
index 68c84e29ce57..8108c564dd78 100644
--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml
@@ -54,6 +54,7 @@ properties:
maxItems: 1
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
@@ -104,7 +105,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
index 2f12cabe4c71..763b876047c1 100644
--- a/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
@@ -9,9 +9,17 @@ title: Allwinner H6 DMIC
maintainers:
- Ban Tao <fengzheng923@gmail.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
- const: allwinner,sun50i-h6-dmic
+ oneOf:
+ - items:
+ - enum:
+ - allwinner,sun20i-d1-dmic
+ - const: allwinner,sun50i-h6-dmic
+ - const: allwinner,sun50i-h6-dmic
"#sound-dai-cells":
const: 0
@@ -54,7 +62,7 @@ required:
- dma-names
- resets
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml
index 4eb11a8e622b..63eadc4200ac 100644
--- a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml
@@ -10,6 +10,9 @@ maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Maxime Ripard <mripard@kernel.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
"#sound-dai-cells":
minimum: 0
@@ -49,7 +52,7 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
index 0705f91199a0..6350dfc0a926 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
@@ -10,7 +10,7 @@ maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
index 77469a45bb7a..23f82bb89750 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
@@ -10,7 +10,7 @@ maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
index 580a3d040abc..5f5cccdbeb34 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
@@ -10,7 +10,7 @@ maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/apple,mca.yaml b/Documentation/devicetree/bindings/sound/apple,mca.yaml
index d5dc92b5b654..40e3a202f443 100644
--- a/Documentation/devicetree/bindings/sound/apple,mca.yaml
+++ b/Documentation/devicetree/bindings/sound/apple,mca.yaml
@@ -14,6 +14,9 @@ description: |
maintainers:
- Martin Povišer <povik+lin@cutebit.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
items:
@@ -106,7 +109,7 @@ required:
- power-domains
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/awinic,aw8738.yaml b/Documentation/devicetree/bindings/sound/awinic,aw8738.yaml
index dce86dafe382..bc6c6b172238 100644
--- a/Documentation/devicetree/bindings/sound/awinic,aw8738.yaml
+++ b/Documentation/devicetree/bindings/sound/awinic,aw8738.yaml
@@ -15,7 +15,7 @@ description:
function (primarily the power limit for the amplifier).
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
index 51d815d0c696..82062d80d700 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
@@ -146,6 +146,7 @@ required:
- "#sound-dai-cells"
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
cirrus,boost-type:
@@ -171,7 +172,7 @@ allOf:
cirrus,gpio1-src-select:
enum: [1]
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
index 184a1344ea76..88a0ca474c3d 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
@@ -14,6 +14,9 @@ description: |
CS35L45 is a Boosted Mono Class D Amplifier with DSP
Speaker Protection and Adaptive Battery Management.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -52,7 +55,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
index 963a871e74da..422cbf38bfdb 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
@@ -9,6 +9,9 @@ title: CS42L51 audio codec DT bindings
maintainers:
- Olivier Moysan <olivier.moysan@foss.st.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: cirrus,cs42l51
@@ -46,7 +49,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml b/Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml
index cea612d3d4a7..52f024f5302a 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml
@@ -24,6 +24,9 @@ description: |
This binding must be part of the Lochnagar MFD binding:
[1] ../mfd/cirrus,lochnagar.yaml
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -49,4 +52,4 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/sound/cirrus,madera.yaml b/Documentation/devicetree/bindings/sound/cirrus,madera.yaml
index 23138ddcb62d..014d4eaa8793 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,madera.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,madera.yaml
@@ -22,6 +22,9 @@ description: |
The properties are all contained in the parent MFD node.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
'#sound-dai-cells':
description:
diff --git a/Documentation/devicetree/bindings/sound/name-prefix.yaml b/Documentation/devicetree/bindings/sound/dai-common.yaml
index 2fe57f87ac52..d858eea73ed7 100644
--- a/Documentation/devicetree/bindings/sound/name-prefix.yaml
+++ b/Documentation/devicetree/bindings/sound/dai-common.yaml
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/sound/name-prefix.yaml#
+$id: http://devicetree.org/schemas/sound/dai-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Component sound name prefix
+title: Digital Audio Interface Common Properties
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
@@ -18,4 +18,6 @@ properties:
sink/source names may use this property to prepend the name of their
sinks/sources with the provided string.
+ '#sound-dai-cells': true
+
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
index f46c66bc6b2d..7735e08d35ba 100644
--- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
@@ -167,6 +167,7 @@ required:
- interrupt-names
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
opmode:
@@ -177,7 +178,7 @@ allOf:
required:
- tdm-slots
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
new file mode 100644
index 000000000000..59ef0cf6b6e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/dmic-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic PDM Digital microphone (DMIC) codec
+
+maintainers:
+ - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: dmic-codec
+
+ '#sound-dai-cells':
+ const: 0
+
+ dmicen-gpios:
+ description: GPIO specifier for DMIC to control start and stop
+ maxItems: 1
+
+ num-channels:
+ description: Number of microphones on this DAI
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 8
+ default: 8
+
+ modeswitch-delay-ms:
+ description: Delay (in ms) to complete DMIC mode switch
+
+ wakeup-delay-ms:
+ description: Delay (in ms) after enabling the DMIC
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dmic {
+ compatible = "dmic-codec";
+ dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
+ num-channels = <1>;
+ wakeup-delay-ms = <50>;
+ modeswitch-delay-ms = <35>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt
deleted file mode 100644
index 32e871037269..000000000000
--- a/Documentation/devicetree/bindings/sound/dmic.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-Device-Tree bindings for Digital microphone (DMIC) codec
-
-This device support generic PDM digital microphone.
-
-Required properties:
- - compatible: should be "dmic-codec".
-
-Optional properties:
- - dmicen-gpios: GPIO specifier for dmic to control start and stop
- - num-channels: Number of microphones on this DAI
- - wakeup-delay-ms: Delay (in ms) after enabling the DMIC
- - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
-
-Example node:
-
- dmic_codec: dmic@0 {
- compatible = "dmic-codec";
- dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
- num-channels = <1>;
- wakeup-delay-ms <50>;
- modeswitch-delay-ms <35>;
- };
diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
index 3b752bba748b..d9f8f0c7f6bb 100644
--- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml
+++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
@@ -10,6 +10,9 @@ maintainers:
- Daniel Drake <drake@endlessm.com>
- Katsuhiro Suzuki <katsuhiro@katsuster.net>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: everest,es8316
@@ -33,7 +36,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
index 64d57758ee67..4b99a18c79a0 100644
--- a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
@@ -18,6 +18,7 @@ properties:
enum:
- fsl,imx8mm-micfil
- fsl,imx8mp-micfil
+ - fsl,imx93-micfil
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
index d370c98a62c7..e847611a85f7 100644
--- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
@@ -11,8 +11,11 @@ maintainers:
description: |
fsl_rpmsg is a virtual audio device. Mapping to real hardware devices
- are SAI, DMA controlled by Cortex M core. What we see from Linux
- side is a device which provides audio service by rpmsg channel.
+ are SAI, MICFIL, DMA controlled by Cortex M core. What we see from
+ Linux side is a device which provides audio service by rpmsg channel.
+ We can create different sound cards which access different hardwares
+ such as SAI, MICFIL, .etc through building rpmsg channels between
+ Cortex-A and Cortex-M.
properties:
compatible:
@@ -85,6 +88,16 @@ properties:
This is a boolean property. If present, the receiving function
will be enabled.
+ fsl,rpmsg-channel-name:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: |
+ A string property to assign rpmsg channel this sound card sits on.
+ This property can be omitted if there is only one sound card and it sits
+ on "rpmsg-audio-channel".
+ enum:
+ - rpmsg-audio-channel
+ - rpmsg-micfil-channel
+
required:
- compatible
- model
@@ -107,3 +120,22 @@ examples:
<&clk IMX8MN_AUDIO_PLL2_OUT>;
clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
};
+
+ - |
+ #include <dt-bindings/clock/imx8mm-clock.h>
+
+ rpmsg_micfil: audio-controller {
+ compatible = "fsl,imx8mm-rpmsg-audio";
+ model = "micfil-audio";
+ fsl,rpmsg-channel-name = "rpmsg-micfil-channel";
+ fsl,enable-lpa;
+ fsl,rpmsg-in;
+ clocks = <&clk IMX8MM_CLK_PDM_IPG>,
+ <&clk IMX8MM_CLK_PDM_ROOT>,
+ <&clk IMX8MM_CLK_SDMA3_ROOT>,
+ <&clk IMX8MM_AUDIO_PLL1_OUT>,
+ <&clk IMX8MM_AUDIO_PLL2_OUT>;
+ clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/fsl,sai.yaml b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
index 70c4111d59c7..5b28d2d51327 100644
--- a/Documentation/devicetree/bindings/sound/fsl,sai.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
@@ -18,14 +18,12 @@ description: |
properties:
compatible:
oneOf:
- - enum:
- - fsl,vf610-sai
- - fsl,imx6sx-sai
- - fsl,imx6ul-sai
- - fsl,imx7ulp-sai
- - fsl,imx8mq-sai
- - fsl,imx8qm-sai
- - fsl,imx8ulp-sai
+ - items:
+ - enum:
+ - fsl,imx6ul-sai
+ - fsl,imx7d-sai
+ - const: fsl,imx6sx-sai
+
- items:
- enum:
- fsl,imx8mm-sai
@@ -33,19 +31,18 @@ properties:
- fsl,imx8mp-sai
- const: fsl,imx8mq-sai
+ - items:
+ - enum:
+ - fsl,imx6sx-sai
+ - fsl,imx7ulp-sai
+ - fsl,imx8mq-sai
+ - fsl,imx8qm-sai
+ - fsl,imx8ulp-sai
+ - fsl,vf610-sai
+
reg:
maxItems: 1
- interrupts:
- items:
- - description: receive and transmit interrupt
-
- dmas:
- maxItems: 2
-
- dma-names:
- maxItems: 2
-
clocks:
items:
- description: The ipg clock for register access
@@ -67,7 +64,7 @@ properties:
- const: mclk3
- const: pll8k
- const: pll11k
- minItems: 4
+ minItems: 5
- items:
- const: bus
- const: mclk1
@@ -77,19 +74,37 @@ properties:
- const: pll11k
minItems: 4
- lsb-first:
- description: |
- Configures whether the LSB or the MSB is transmitted
- first for the fifo data. If this property is absent,
- the MSB is transmitted first as default, or the LSB
- is transmitted first.
- type: boolean
+ dmas:
+ maxItems: 2
+
+ dma-names:
+ maxItems: 2
+
+ interrupts:
+ items:
+ - description: receive and transmit interrupt
big-endian:
description: |
required if all the SAI registers are big-endian rather than little-endian.
type: boolean
+ fsl,dataline:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: |
+ Configure the dataline. It has 3 value for each configuration
+ maxItems: 16
+ items:
+ items:
+ - description: format Default(0), I2S(1) or PDM(2)
+ enum: [0, 1, 2]
+ - description: dataline mask for 'rx'
+ - description: dataline mask for 'tx'
+
+ fsl,sai-mclk-direction-output:
+ description: SAI will output the SAI MCLK clock.
+ type: boolean
+
fsl,sai-synchronous-rx:
description: |
SAI will work in the synchronous mode (sync Tx with Rx) which means
@@ -108,31 +123,24 @@ properties:
of transmitter.
type: boolean
- fsl,dataline:
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
- description: |
- Configure the dataline. It has 3 value for each configuration
- maxItems: 16
- items:
- items:
- - description: format Default(0), I2S(1) or PDM(2)
- enum: [0, 1, 2]
- - description: dataline mask for 'rx'
- - description: dataline mask for 'tx'
-
- fsl,sai-mclk-direction-output:
- description: SAI will output the SAI MCLK clock.
- type: boolean
-
fsl,shared-interrupt:
description: Interrupt is shared with other modules.
type: boolean
+ lsb-first:
+ description: |
+ Configures whether the LSB or the MSB is transmitted
+ first for the fifo data. If this property is absent,
+ the MSB is transmitted first as default, or the LSB
+ is transmitted first.
+ type: boolean
+
"#sound-dai-cells":
const: 0
description: optional, some dts node didn't add it.
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
@@ -168,13 +176,13 @@ allOf:
required:
- compatible
- reg
- - interrupts
- - dmas
- - dma-names
- clocks
- clock-names
+ - dmas
+ - dma-names
+ - interrupts
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
index c3e9f3485449..1434f4433738 100644
--- a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
@@ -8,7 +8,7 @@ title: Audio codec controlled by ChromeOS EC
maintainers:
- Cheng-Yi Chiang <cychiang@chromium.org>
- - Tzung-Bi Shih <tzungbi@google.com>
+ - Tzung-Bi Shih <tzungbi@kernel.org>
description: |
Google's ChromeOS EC codec is a digital mic codec provided by the
@@ -17,6 +17,9 @@ description: |
subnode of a cros-ec node.
(see Documentation/devicetree/bindings/mfd/google,cros-ec.yaml).
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: google,cros-ec-codec
@@ -42,7 +45,7 @@ required:
- compatible
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -57,6 +60,7 @@ examples:
cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
+ interrupts = <93 0>;
codecs {
#address-cells = <2>;
diff --git a/Documentation/devicetree/bindings/sound/ingenic,aic.yaml b/Documentation/devicetree/bindings/sound/ingenic,aic.yaml
index d607325f2f15..ba44406c9caf 100644
--- a/Documentation/devicetree/bindings/sound/ingenic,aic.yaml
+++ b/Documentation/devicetree/bindings/sound/ingenic,aic.yaml
@@ -9,6 +9,9 @@ title: Ingenic SoCs AC97 / I2S Controller (AIC) DT bindings
maintainers:
- Paul Cercueil <paul@crapouillou.net>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
$nodename:
pattern: '^audio-controller@'
@@ -37,15 +40,11 @@ properties:
items:
- description: AIC clock
- description: I2S clock
- - description: EXT clock
- - description: PLL/2 clock
clock-names:
items:
- const: aic
- const: i2s
- - const: ext
- - const: pll half
dmas:
items:
@@ -57,7 +56,7 @@ properties:
- const: rx
- const: tx
-additionalProperties: false
+unevaluatedProperties: false
required:
- compatible
@@ -82,10 +81,8 @@ examples:
interrupts = <18>;
clocks = <&cgu JZ4740_CLK_AIC>,
- <&cgu JZ4740_CLK_I2S>,
- <&cgu JZ4740_CLK_EXT>,
- <&cgu JZ4740_CLK_PLL_HALF>;
- clock-names = "aic", "i2s", "ext", "pll half";
+ <&cgu JZ4740_CLK_I2S>;
+ clock-names = "aic", "i2s";
dmas = <&dmac 25 0xffffffff>, <&dmac 24 0xffffffff>;
dma-names = "rx", "tx";
diff --git a/Documentation/devicetree/bindings/sound/ingenic,codec.yaml b/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
index 48aae54dd643..a07d607e9b93 100644
--- a/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
+++ b/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
@@ -9,6 +9,9 @@ title: Ingenic JZ47xx internal codec DT bindings
maintainers:
- Paul Cercueil <paul@crapouillou.net>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
$nodename:
pattern: '^audio-codec@.*'
@@ -37,7 +40,7 @@ properties:
'#sound-dai-cells':
const: 0
-additionalProperties: false
+unevaluatedProperties: false
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
index b2603f611af9..2ac0a4b3cd18 100644
--- a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
@@ -13,6 +13,9 @@ maintainers:
description: |
Intel KeemBay I2S
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -64,7 +67,7 @@ required:
- clock-names
- interrupts
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml
index b97e0fcbdba3..a67b79cbe006 100644
--- a/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml
+++ b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml
@@ -9,6 +9,9 @@ title: Bluetooth SCO Audio Codec
maintainers:
- Mark Brown <broonie@kernel.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
'#sound-dai-cells':
enum:
@@ -26,7 +29,7 @@ required:
- '#sound-dai-cells'
- compatible
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml
index 808f6d2736c7..fe5f0756af2f 100644
--- a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml
+++ b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml
@@ -10,7 +10,7 @@ maintainers:
- Mark Brown <broonie@kernel.org>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml b/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml
index 81f266d66ec5..92d896e0d323 100644
--- a/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml
+++ b/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml
@@ -9,6 +9,9 @@ title: Marvel SSPA Digital Audio Interface Bindings
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
$nodename:
pattern: "^audio-controller(@.*)?$"
@@ -73,7 +76,7 @@ required:
- dma-names
- port
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt
deleted file mode 100644
index 75db84d06240..000000000000
--- a/Documentation/devicetree/bindings/sound/max98357a.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-Maxim MAX98357A/MAX98360A audio DAC
-
-This node models the Maxim MAX98357A/MAX98360A DAC.
-
-Required properties:
-- compatible : "maxim,max98357a" for MAX98357A.
- "maxim,max98360a" for MAX98360A.
-
-Optional properties:
-- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin.
- If this option is not specified then driver does not manage
- the pin state (e.g. chip is always on).
-- sdmode-delay : specify delay time for SD_MODE pin.
- If this option is specified, which means it's required i2s clocks
- ready before SD_MODE is unmuted in order to avoid the speaker pop noise.
- It's observed that 5ms is sufficient.
-
-Example:
-
-max98357a {
- compatible = "maxim,max98357a";
- sdmode-gpios = <&qcom_pinmux 25 0>;
-};
-
-max98360a {
- compatible = "maxim,max98360a";
- sdmode-gpios = <&qcom_pinmux 25 0>;
-};
diff --git a/Documentation/devicetree/bindings/sound/max98504.txt b/Documentation/devicetree/bindings/sound/max98504.txt
deleted file mode 100644
index 583ed5fdfb28..000000000000
--- a/Documentation/devicetree/bindings/sound/max98504.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-Maxim MAX98504 class D mono speaker amplifier
-
-This device supports I2C control interface and an IRQ output signal. It features
-a PCM and PDM digital audio interface (DAI) and a differential analog input.
-
-Required properties:
-
- - compatible : "maxim,max98504"
- - reg : should contain the I2C slave device address
- - DVDD-supply, DIOVDD-supply, PVDD-supply: power supplies for the device,
- as covered in ../regulator/regulator.txt
- - interrupts : should specify the interrupt line the device is connected to,
- as described in ../interrupt-controller/interrupts.txt
-
-Optional properties:
-
- - maxim,brownout-threshold - the PVDD brownout threshold, the value must be
- from 0, 1...21 range, corresponding to 2.6V, 2.65V...3.65V voltage range
- - maxim,brownout-attenuation - the brownout attenuation to the speaker gain
- applied during the "attack hold" and "timed hold" phase, the value must be
- from 0...6 (dB) range
- - maxim,brownout-attack-hold-ms - the brownout attack hold phase time in ms,
- 0...255 (VBATBROWN_ATTK_HOLD, register 0x0018)
- - maxim,brownout-timed-hold-ms - the brownout timed hold phase time in ms,
- 0...255 (VBATBROWN_TIME_HOLD, register 0x0019)
- - maxim,brownout-release-rate-ms - the brownout release phase step time in ms,
- 0...255 (VBATBROWN_RELEASE, register 0x001A)
-
-The default value when the above properties are not specified is 0,
-the maxim,brownout-threshold property must be specified to actually enable
-the PVDD brownout protection.
-
-Example:
-
- max98504@31 {
- compatible = "maxim,max98504";
- reg = <0x31>;
- interrupt-parent = <&gpio_bank_0>;
- interrupts = <2 0>;
-
- DVDD-supply = <&regulator>;
- DIOVDD-supply = <&regulator>;
- PVDD-supply = <&regulator>;
-};
diff --git a/Documentation/devicetree/bindings/sound/maxim,max98357a.yaml b/Documentation/devicetree/bindings/sound/maxim,max98357a.yaml
new file mode 100644
index 000000000000..83ba8666fbb4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/maxim,max98357a.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/maxim,max98357a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim Integrated MAX98357A/MAX98360A amplifier
+
+maintainers:
+ - Tzung-Bi Shih <tzungbi@kernel.org>
+
+description:
+ Maxim Integrated MAX98357A/MAX98360A is a digital pulse-code modulation (PCM)
+ input Class D amplifier.
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - maxim,max98357a
+ - maxim,max98360a
+
+ '#sound-dai-cells':
+ const: 0
+
+ sdmode-gpios:
+ maxItems: 1
+ description:
+ Chip's SD_MODE pin. If missing the chip is always on.
+
+ sdmode-delay:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Delay time for SD_MODE pin changes intended to make I2S clocks ready
+ before SD_MODE is unmuted in order to avoid the speaker pop noise.
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ amplifier {
+ compatible = "maxim,max98360a";
+ #sound-dai-cells = <0>;
+ sdmode-gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/maxim,max98504.yaml b/Documentation/devicetree/bindings/sound/maxim,max98504.yaml
new file mode 100644
index 000000000000..23f19a9d2c06
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/maxim,max98504.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/maxim,max98504.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim Integrated MAX98504 class D mono speaker amplifier
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+description:
+ Maxim Integrated MAX98504 speaker amplifier supports I2C control interface
+ with an IRQ output signal, PCM and PDM digital audio interface (DAI) and a
+ differential analog input.
+
+properties:
+ compatible:
+ const: maxim,max98504
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ DIOVDD-supply: true
+ DVDD-supply: true
+ PVDD-supply: true
+
+ maxim,brownout-threshold:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ maximum: 21
+ default: 0
+ description:
+ PVDD brownout threshold, where values correspond to 2.6V, 2.65V...3.65V
+ voltage range. Property also enables the PVDD brownout protection.
+
+ maxim,brownout-attenuation:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ maximum: 6
+ default: 0
+ description:
+ Brownout attenuation to the speaker gain applied during the "attack hold"
+ and "timed hold" phase, the value must be from 0...6 (dB) range.
+
+ maxim,brownout-attack-hold-ms:
+ maximum: 255
+ default: 0
+ description:
+ Brownout attack hold phase time in ms, VBATBROWN_ATTK_HOLD, register 0x0018.
+
+ maxim,brownout-timed-hold-ms:
+ maximum: 255
+ default: 0
+ description:
+ Brownout timed hold phase time in ms, VBATBROWN_TIME_HOLD, register 0x0019.
+
+ maxim,brownout-release-rate-ms:
+ maximum: 255
+ default: 0
+ description:
+ Brownout release phase step time in ms, VBATBROWN_RELEASE, register 0x001A.
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ amplifier@31 {
+ compatible = "maxim,max98504";
+ reg = <0x31>;
+
+ DIOVDD-supply = <&ldo3_reg>;
+ DVDD-supply = <&ldo3_reg>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml b/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml
index 0481315cb5f2..621022872c8d 100644
--- a/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml
+++ b/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml
@@ -66,13 +66,15 @@ properties:
enum: [0, 1, 2, 3]
default: 0
-if:
- properties:
- compatible:
- const: microchip,sam9x60-i2smcc
-then:
- properties:
- microchip,tdm-data-pair: false
+allOf:
+ - $ref: dai-common.yaml#
+ - if:
+ properties:
+ compatible:
+ const: microchip,sam9x60-i2smcc
+ then:
+ properties:
+ microchip,tdm-data-pair: false
required:
- "#sound-dai-cells"
@@ -84,7 +86,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml b/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml
index d218e4ab9a7a..c383162140bb 100644
--- a/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml
+++ b/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml
@@ -13,6 +13,9 @@ description:
The Microchip Sony/Philips Digital Interface Transmitter is a serial port
compliant with the IEC-60958 standard.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
"#sound-dai-cells":
const: 0
@@ -53,7 +56,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml b/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml
index 04414eb4ada9..c37b89d94c12 100644
--- a/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml
+++ b/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml
@@ -13,6 +13,9 @@ description:
The Microchip Pulse Density Microphone Controller (PDMC) interfaces up to 4
digital microphones having Pulse Density Modulated (PDM) outputs.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: microchip,sama7g5-pdmc
@@ -75,7 +78,7 @@ required:
- dma-names
- microchip,mic-pos
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
index 4fc5b045d3cf..9d3139990237 100644
--- a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
@@ -21,6 +21,13 @@ properties:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8186 ASoC platform.
+ dmic-gpios:
+ maxItems: 1
+ description:
+ dmic-gpios optional prop for switching between two DMICs.
+ Ex, the GPIO can control a MUX HW component to select
+ dmic clk and data form a Front or Rear dmic.
+
headset-codec:
type: object
additionalProperties: false
@@ -63,14 +70,19 @@ required:
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
sound: mt8186-sound {
compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound";
mediatek,platform = <&afe>;
pinctrl-names = "aud_clk_mosi_off",
- "aud_clk_mosi_on";
+ "aud_clk_mosi_on",
+ "aud_gpio_dmic_sec";
pinctrl-0 = <&aud_clk_mosi_off>;
pinctrl-1 = <&aud_clk_mosi_on>;
+ pinctrl-2 = <&aud_gpio_dmic_sec>;
+
+ dmic-gpios = <&pio 23 GPIO_ACTIVE_HIGH>;
headset-codec {
sound-dai = <&rt5682s>;
diff --git a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
index 478be7e3fa29..c6e614c1c30b 100644
--- a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
@@ -34,7 +34,7 @@ properties:
properties:
sound-dai:
- $ref: /schemas/types.yaml#/definitions/phandle
+ maxItems: 1
required:
- sound-dai
@@ -48,7 +48,6 @@ properties:
maxItems: 2
items:
maxItems: 1
- $ref: /schemas/types.yaml#/definitions/phandle-array
required:
- sound-dai
diff --git a/Documentation/devicetree/bindings/sound/mvebu-audio.txt b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
index cb8c07c81ce4..4f5dec5cb3c2 100644
--- a/Documentation/devicetree/bindings/sound/mvebu-audio.txt
+++ b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
@@ -6,9 +6,14 @@ Required properties:
"marvell,kirkwood-audio" for Kirkwood platforms
"marvell,dove-audio" for Dove platforms
"marvell,armada370-audio" for Armada 370 platforms
+ "marvell,armada-380-audio" for Armada 38x platforms
- reg: physical base address of the controller and length of memory mapped
- region.
+ region (named "i2s_regs").
+ With "marvell,armada-380-audio" two other regions are required:
+ first of those is dedicated for Audio PLL Configuration registers
+ (named "pll_regs") and the second one ("soc_ctrl") - for register
+ where one of exceptive I/O types (I2S or S/PDIF) is set.
- interrupts:
with "marvell,kirkwood-audio", the audio interrupt
@@ -23,6 +28,13 @@ Required properties:
"internal" for the internal clock
"extclk" for the external clock
+Optional properties:
+
+- spdif-mode:
+ Enable S/PDIF mode on Armada 38x SoC. Using this property
+ disables standard I2S I/O. Valid only with "marvell,armada-380-audio"
+ compatible string.
+
Example:
i2s1: audio-controller@b4000 {
diff --git a/Documentation/devicetree/bindings/sound/nau8315.txt b/Documentation/devicetree/bindings/sound/nau8315.txt
index 6eaec46f384c..1cd94517d45e 100644
--- a/Documentation/devicetree/bindings/sound/nau8315.txt
+++ b/Documentation/devicetree/bindings/sound/nau8315.txt
@@ -2,6 +2,7 @@ Nuvoton NAU8315 Mono Class-D Amplifier
Required properties:
- compatible : "nuvoton,nau8315"
+ "nuvoton,nau8318"
Optional properties:
- enable-gpios : GPIO specifier for the chip's device enable input(EN) pin.
@@ -16,3 +17,8 @@ nau8315 {
compatible = "nuvoton,nau8315";
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
};
+
+nau8318 {
+ compatible = "nuvoton,nau8318";
+ enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-asrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-asrc.yaml
index d82415c21271..e15f387c4c29 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-asrc.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-asrc.yaml
@@ -23,7 +23,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
index 3d538df878ea..e1362c77472b 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
@@ -18,7 +18,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml
index 60a368a132b8..dc76a4dc0ed2 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml
@@ -16,6 +16,9 @@ maintainers:
- Thierry Reding <treding@nvidia.com>
- Jon Hunter <jonathanh@nvidia.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: nvidia,tegra20-spdif
@@ -66,7 +69,7 @@ required:
- dma-names
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml
index ea0dc0ece1bc..e4c871797fa6 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml
@@ -19,7 +19,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml
index 1aff61f072bb..021b72546ba4 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml
@@ -18,7 +18,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
index 0f9d2b461e02..bff551c35da7 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
@@ -17,7 +17,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
index 12cd17eede99..a82f11fb6c9a 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
@@ -17,7 +17,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml
index 570b03282aeb..049898f02e85 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml
@@ -17,7 +17,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml
index 4aecbc847b98..d0280d8aa3af 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml
@@ -20,7 +20,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
index 9dc9ba590fa3..5fc03b8771b1 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
@@ -17,7 +17,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
index 694f890d6305..185ca0be4f02 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
@@ -17,7 +17,7 @@ maintainers:
- Sameer Pujar <spujar@nvidia.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
$nodename:
diff --git a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
index 7f2e68ff6d34..fd2415e231eb 100644
--- a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
+++ b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
@@ -10,7 +10,7 @@ maintainers:
- Stephan Gerhold <stephan@gerhold.net>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
index ef18a572a1ff..5e26b3e9db2c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
@@ -109,9 +109,10 @@ required:
- interrupt-names
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
index 1de11e7f33bb..23564fd394a2 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
@@ -9,6 +9,9 @@ title: LPASS(Low Power Audio Subsystem) RX Macro audio codec DT bindings
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -43,8 +46,7 @@ properties:
- const: fsgen
clock-output-names:
- items:
- - const: mclk
+ maxItems: 1
power-domains:
maxItems: 2
@@ -59,7 +61,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
index de8297b358e8..38708578ee29 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
@@ -9,6 +9,9 @@ title: LPASS(Low Power Audio Subsystem) TX Macro audio codec DT bindings
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -43,8 +46,7 @@ properties:
- const: fsgen
clock-output-names:
- items:
- - const: mclk
+ maxItems: 1
power-domains:
maxItems: 2
@@ -63,7 +65,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
index 9f473c08cb2e..188883a2e671 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
@@ -9,6 +9,9 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec DT bindings
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -39,8 +42,7 @@ properties:
- const: mclk
clock-output-names:
- items:
- - const: fsgen
+ maxItems: 1
power-domains:
maxItems: 2
@@ -62,7 +64,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
index 4959ad658eac..bebca3e3f86f 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
@@ -9,6 +9,9 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec DT bindings
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -38,8 +41,7 @@ properties:
- const: fsgen
clock-output-names:
- items:
- - const: mclk
+ maxItems: 1
qcom,dmic-sample-rate:
description: dmic sample rate
@@ -53,7 +55,7 @@ required:
- reg
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml b/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml
index d0f7a79e240a..3f11d2e183e1 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml
@@ -14,6 +14,9 @@ description:
Qualcomm Audio Device Manager (Q6ADM) routing node represents routing
specific configuration.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -26,27 +29,11 @@ required:
- compatible
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
- #include <dt-bindings/soc/qcom,apr.h>
- #include <dt-bindings/sound/qcom,q6asm.h>
-
- apr {
- compatible = "qcom,apr-v2";
- qcom,domain = <APR_DOMAIN_ADSP>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- service@8 {
- compatible = "qcom,q6adm";
- reg = <APR_SVC_ADM>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
-
- routing {
- compatible = "qcom,q6adm-routing";
- #sound-dai-cells = <0>;
- };
- };
+ routing {
+ compatible = "qcom,q6adm-routing";
+ #sound-dai-cells = <0>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm.yaml b/Documentation/devicetree/bindings/sound/qcom,q6adm.yaml
new file mode 100644
index 000000000000..fe14a97ea616
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6adm.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6adm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Audio Device Manager (Q6ADM)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6adm
+
+ routing:
+ type: object
+ $ref: /schemas/sound/qcom,q6adm-routing.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP LPASS audio routing
+
+required:
+ - compatible
+ - routing
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,apr.h>
+
+ apr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@8 {
+ compatible = "qcom,q6adm";
+ reg = <APR_SVC_ADM>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ routing {
+ compatible = "qcom,q6adm-routing";
+ #sound-dai-cells = <0>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml b/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml
new file mode 100644
index 000000000000..297aa362aa54
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Audio FrontEnd (Q6AFE)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6afe
+
+ clock-controller:
+ $ref: /schemas/sound/qcom,q6dsp-lpass-clocks.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP LPASS clock controller
+
+ dais:
+ type: object
+ $ref: /schemas/sound/qcom,q6dsp-lpass-ports.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP audio ports
+
+required:
+ - compatible
+ - dais
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,apr.h>
+ #include <dt-bindings/sound/qcom,q6afe.h>
+ apr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@4 {
+ compatible = "qcom,q6afe";
+ reg = <APR_SVC_AFE>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ clock-controller {
+ compatible = "qcom,q6afe-clocks";
+ #clock-cells = <2>;
+ };
+
+ dais {
+ compatible = "qcom,q6afe-dais";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+
+ dai@22 {
+ reg = <QUATERNARY_MI2S_RX>;
+ qcom,sd-lines = <0 1 2 3>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
index 24f7bf2bfd95..73a4afad5a74 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
@@ -27,20 +27,7 @@ additionalProperties: false
examples:
- |
- #include <dt-bindings/soc/qcom,gpr.h>
- gpr {
- compatible = "qcom,gpr";
- #address-cells = <1>;
- #size-cells = <0>;
- qcom,domain = <GPR_DOMAIN_ID_ADSP>;
-
- service@1 {
- compatible = "qcom,q6apm";
- reg = <1>;
-
- dais {
- compatible = "qcom,q6apm-dais";
- iommus = <&apps_smmu 0x1801 0x0>;
- };
- };
+ dais {
+ compatible = "qcom,q6apm-dais";
+ iommus = <&apps_smmu 0x1801 0x0>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
new file mode 100644
index 000000000000..894e653d37d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6apm-lpass-dais.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm DSP LPASS (Low Power Audio SubSystem) Audio Ports
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6apm-lpass-dais
+
+ '#sound-dai-cells':
+ const: 1
+
+required:
+ - compatible
+ - '#sound-dai-cells'
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ dais {
+ compatible = "qcom,q6apm-lpass-dais";
+ #sound-dai-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm.yaml
new file mode 100644
index 000000000000..ef1965aca254
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6apm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Audio Process Manager (Q6APM)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: dai-common.yaml#
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6apm
+
+ bedais:
+ type: object
+ $ref: /schemas/sound/qcom,q6apm-lpass-dais.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP audio ports
+
+ dais:
+ type: object
+ $ref: /schemas/sound/qcom,q6apm-dai.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP audio ports
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - bedais
+ - dais
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,gpr.h>
+
+ gpr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@1 {
+ reg = <GPR_APM_MODULE_IID>;
+ compatible = "qcom,q6apm";
+ #sound-dai-cells = <0>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ dais {
+ compatible = "qcom,q6apm-dais";
+ iommus = <&apps_smmu 0x1801 0x0>;
+ };
+
+ bedais {
+ compatible = "qcom,q6apm-lpass-dais";
+ #sound-dai-cells = <1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml
index 8deb8ffb143b..0110b38f6de9 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml
@@ -73,40 +73,24 @@ additionalProperties: false
examples:
- |
- #include <dt-bindings/soc/qcom,apr.h>
- #include <dt-bindings/sound/qcom,q6asm.h>
-
- apr {
- compatible = "qcom,apr-v2";
- qcom,domain = <APR_DOMAIN_ADSP>;
+ dais {
+ compatible = "qcom,q6asm-dais";
+ iommus = <&apps_smmu 0x1821 0x0>;
#address-cells = <1>;
#size-cells = <0>;
+ #sound-dai-cells = <1>;
+
+ dai@0 {
+ reg = <0>;
+ };
+
+ dai@1 {
+ reg = <1>;
+ };
- service@7 {
- compatible = "qcom,q6asm";
- reg = <APR_SVC_ASM>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
-
- dais {
- compatible = "qcom,q6asm-dais";
- iommus = <&apps_smmu 0x1821 0x0>;
- #address-cells = <1>;
- #size-cells = <0>;
- #sound-dai-cells = <1>;
-
- dai@0 {
- reg = <0>;
- };
-
- dai@1 {
- reg = <1>;
- };
-
- dai@2 {
- reg = <2>;
- is-compress-dai;
- direction = <1>;
- };
- };
+ dai@2 {
+ reg = <2>;
+ is-compress-dai;
+ direction = <1>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm.yaml b/Documentation/devicetree/bindings/sound/qcom,q6asm.yaml
new file mode 100644
index 000000000000..cb49f9667cca
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6asm.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6asm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Audio Stream Manager (Q6ASM)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6asm
+
+ dais:
+ type: object
+ $ref: /schemas/sound/qcom,q6asm-dais.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP audio ports
+
+required:
+ - compatible
+ - dais
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,apr.h>
+
+ apr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@7 {
+ compatible = "qcom,q6asm";
+ reg = <APR_SVC_ASM>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ dais {
+ compatible = "qcom,q6asm-dais";
+ iommus = <&apps_smmu 0x1821 0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+
+ dai@0 {
+ reg = <0>;
+ };
+
+ dai@1 {
+ reg = <1>;
+ };
+
+ dai@2 {
+ reg = <2>;
+ is-compress-dai;
+ direction = <1>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6core.yaml b/Documentation/devicetree/bindings/sound/qcom,q6core.yaml
new file mode 100644
index 000000000000..e240712de9ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6core.yaml
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6core.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Audio Core (Q6Core)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6core
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,apr.h>
+
+ apr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@3 {
+ compatible = "qcom,q6core";
+ reg = <APR_SVC_ADSP_CORE>;
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml
index fd567d20417d..aa6c0ecba5cf 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml
@@ -35,41 +35,7 @@ additionalProperties: false
examples:
- |
- #include <dt-bindings/soc/qcom,apr.h>
- #include <dt-bindings/sound/qcom,q6afe.h>
- apr {
- compatible = "qcom,apr-v2";
- qcom,domain = <APR_DOMAIN_ADSP>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- service@4 {
- compatible = "qcom,q6afe";
- reg = <APR_SVC_AFE>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
-
- clock-controller {
- compatible = "qcom,q6afe-clocks";
- #clock-cells = <2>;
- };
- };
- };
-
- - |
- #include <dt-bindings/soc/qcom,gpr.h>
- gpr {
- compatible = "qcom,gpr";
- qcom,domain = <GPR_DOMAIN_ID_ADSP>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- service@2 {
- reg = <GPR_PRM_MODULE_IID>;
- compatible = "qcom,q6prm";
-
- clock-controller {
- compatible = "qcom,q6prm-lpass-clocks";
- #clock-cells = <2>;
- };
- };
+ clock-controller {
+ compatible = "qcom,q6afe-clocks";
+ #clock-cells = <2>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
index e53fc0960a14..d8ebf2e528d2 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
@@ -16,7 +16,6 @@ properties:
compatible:
enum:
- qcom,q6afe-dais
- - qcom,q6apm-lpass-dais
'#sound-dai-cells':
const: 1
@@ -150,54 +149,16 @@ additionalProperties: false
examples:
- |
- #include <dt-bindings/soc/qcom,apr.h>
- #include <dt-bindings/sound/qcom,q6afe.h>
- apr {
- compatible = "qcom,apr-v2";
- #address-cells = <1>;
- #size-cells = <0>;
- qcom,domain = <APR_DOMAIN_ADSP>;
-
- service@4 {
- compatible = "qcom,q6afe";
- reg = <APR_SVC_AFE>;
- qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
-
- dais {
- compatible = "qcom,q6afe-dais";
- #address-cells = <1>;
- #size-cells = <0>;
- #sound-dai-cells = <1>;
-
- dai@22 {
- reg = <QUATERNARY_MI2S_RX>;
- qcom,sd-lines = <0 1 2 3>;
- };
- };
- };
- };
- - |
- #include <dt-bindings/soc/qcom,gpr.h>
- gpr {
- compatible = "qcom,gpr";
+ #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
+
+ dais {
+ compatible = "qcom,q6afe-dais";
#address-cells = <1>;
#size-cells = <0>;
- qcom,domain = <GPR_DOMAIN_ID_ADSP>;
-
- service@1 {
- compatible = "qcom,q6apm";
- reg = <GPR_APM_MODULE_IID>;
-
- dais {
- compatible = "qcom,q6apm-lpass-dais";
- #address-cells = <1>;
- #size-cells = <0>;
- #sound-dai-cells = <1>;
-
- dai@22 {
- reg = <QUATERNARY_MI2S_RX>;
- qcom,sd-lines = <0 1 2 3>;
- };
- };
+ #sound-dai-cells = <1>;
+
+ dai@22 {
+ reg = <QUATERNARY_MI2S_RX>;
+ qcom,sd-lines = <0 1 2 3>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6prm.yaml b/Documentation/devicetree/bindings/sound/qcom,q6prm.yaml
new file mode 100644
index 000000000000..f6dbb1267bfe
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,q6prm.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6prm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Proxy Resource Manager (Q6PRM)
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+ - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+allOf:
+ - $ref: /schemas/soc/qcom/qcom,apr-services.yaml#
+
+properties:
+ compatible:
+ enum:
+ - qcom,q6prm
+
+ clock-controller:
+ $ref: /schemas/sound/qcom,q6dsp-lpass-clocks.yaml#
+ unevaluatedProperties: false
+ description: Qualcomm DSP LPASS clock controller
+
+required:
+ - compatible
+ - clock-controller
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/qcom,gpr.h>
+
+ gpr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ service@2 {
+ reg = <GPR_PRM_MODULE_IID>;
+ compatible = "qcom,q6prm";
+ qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
+
+ clock-controller {
+ compatible = "qcom,q6prm-lpass-clocks";
+ #clock-cells = <2>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
index 5d6ea66a863f..1f75feec3dec 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
@@ -109,7 +109,7 @@ audio-codec@1{
reg = <1 0>;
interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "intr2"
- reset-gpios = <&msmgpio 64 0>;
+ reset-gpios = <&msmgpio 64 GPIO_ACTIVE_LOW>;
slim-ifc-dev = <&wc9335_ifd>;
clock-names = "mclk", "native";
clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
index 51547190f709..67d84463eaeb 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
@@ -13,6 +13,9 @@ description: |
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
It has RX and TX Soundwire slave devices.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -106,7 +109,7 @@ required:
- qcom,micbias4-microvolt
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
index 6113f65f2990..65b0e67f82a3 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
@@ -15,6 +15,9 @@ description: |
Their primary operating mode uses a SoundWire digital audio
interface. This binding is for SoundWire interface.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: sdw10217020200
@@ -23,7 +26,7 @@ properties:
maxItems: 1
powerdown-gpios:
- description: GPIO spec for Powerdown/Shutdown line to use
+ description: GPIO spec for Powerdown/Shutdown line to use (pin SD_N)
maxItems: 1
vdd-supply:
@@ -43,10 +46,12 @@ required:
- "#thermal-sensor-cells"
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
+
soundwire-controller@3250000 {
#address-cells = <2>;
#size-cells = <0>;
@@ -55,19 +60,21 @@ examples:
speaker@0,1 {
compatible = "sdw10217020200";
reg = <0 1>;
- powerdown-gpios = <&tlmm 1 0>;
+ powerdown-gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
vdd-supply = <&vreg_s10b_1p8>;
#thermal-sensor-cells = <0>;
#sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrLeft";
};
speaker@0,2 {
compatible = "sdw10217020200";
reg = <0 2>;
- powerdown-gpios = <&tlmm 89 0>;
+ powerdown-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>;
vdd-supply = <&vreg_s10b_1p8>;
#thermal-sensor-cells = <0>;
#sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrRight";
};
};
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt1015p.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1015p.yaml
index 1d73204451b1..ea7d4900ee4a 100644
--- a/Documentation/devicetree/bindings/sound/realtek,rt1015p.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt1015p.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek rt1015p codec devicetree bindings
maintainers:
- - Tzung-Bi Shih <tzungbi@google.com>
+ - Tzung-Bi Shih <tzungbi@kernel.org>
description: |
Rt1015p is a rt1015 variant which does not support I2C and
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml
index ca5b8987b749..e631ace7aad1 100644
--- a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml
@@ -12,6 +12,9 @@ maintainers:
description: |
Rt5682s(ALC5682I-VS) is a rt5682i variant which supports I2C only.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: realtek,rt5682s
@@ -87,11 +90,32 @@ properties:
maxItems: 2
description: Name given for DAI word clock and bit clock outputs.
-additionalProperties: false
+ "#sound-dai-cells":
+ const: 1
+
+ AVDD-supply:
+ description: Regulator supplying analog power through the AVDD pin.
+
+ MICVDD-supply:
+ description: Regulator supplying power for the microphone bias through the
+ MICVDD pin.
+
+ DBVDD-supply:
+ description: Regulator supplying I/O power through the DBVDD pin.
+
+ LDO1-IN-supply:
+ description: Regulator supplying power to the digital core and charge pump
+ through the LDO1_IN pin.
+
+unevaluatedProperties: false
required:
- compatible
- reg
+ - AVDD-supply
+ - MICVDD-supply
+ - DBVDD-supply
+ - LDO1-IN-supply
examples:
- |
@@ -117,5 +141,10 @@ examples:
clocks = <&osc>;
clock-names = "mclk";
+
+ AVDD-supply = <&avdd_reg>;
+ MICVDD-supply = <&micvdd_reg>;
+ DBVDD-supply = <&dbvdd_reg>;
+ LDO1-IN-supply = <&ldo1_in_reg>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.yaml b/Documentation/devicetree/bindings/sound/renesas,fsi.yaml
index 0dd3f7361399..df91991699a7 100644
--- a/Documentation/devicetree/bindings/sound/renesas,fsi.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,fsi.yaml
@@ -9,6 +9,9 @@ title: Renesas FIFO-buffered Serial Interface (FSI)
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
$nodename:
pattern: "^sound@.*"
@@ -64,7 +67,7 @@ required:
- power-domains
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
index 679a246dd666..34f015708c11 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
@@ -274,6 +274,7 @@ required:
- "#sound-dai-cells"
allOf:
+ - $ref: dai-common.yaml#
- if:
properties:
compatible:
@@ -304,7 +305,7 @@ allOf:
- ssi
- audmapp
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
index 0d9840375132..196881d94396 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
@@ -9,6 +9,9 @@ title: Renesas RZ/{G2L,V2L} ASoC Sound Serial Interface (SSIF-2)
maintainers:
- Biju Das <biju.das.jz@bp.renesas.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
items:
@@ -90,7 +93,7 @@ required:
- resets
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/richtek,rt9120.yaml b/Documentation/devicetree/bindings/sound/richtek,rt9120.yaml
index 5655ca568240..a1242e8e0687 100644
--- a/Documentation/devicetree/bindings/sound/richtek,rt9120.yaml
+++ b/Documentation/devicetree/bindings/sound/richtek,rt9120.yaml
@@ -16,6 +16,9 @@ description: |
applications like as TV, monitors. home entertainment, electronic music
equipment.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -42,7 +45,7 @@ required:
- dvdd-supply
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml b/Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml
index 6a7c004bef17..4c95895de75e 100644
--- a/Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml
@@ -14,6 +14,9 @@ description:
maintainers:
- Nicolas Frattaroli <frattaroli.nicolas@gmail.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -21,6 +24,7 @@ properties:
- rockchip,rk1808-i2s-tdm
- rockchip,rk3308-i2s-tdm
- rockchip,rk3568-i2s-tdm
+ - rockchip,rk3588-i2s-tdm
- rockchip,rv1126-i2s-tdm
reg:
@@ -135,10 +139,9 @@ required:
- clock-names
- resets
- reset-names
- - rockchip,grf
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml b/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml
index 22e1cf6c0592..ff9e400494f3 100644
--- a/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml
@@ -16,6 +16,9 @@ description:
maintainers:
- Heiko Stuebner <heiko@sntech.de>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -83,7 +86,7 @@ required:
- dma-names
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml
index 75b3b33b5f1f..5cdb8bcc687b 100644
--- a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml
@@ -8,6 +8,9 @@ title: Rockchip rk3328 internal codec
maintainers:
- Heiko Stuebner <heiko@sntech.de>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
@@ -53,7 +56,7 @@ required:
- rockchip,grf
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml b/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
index 7e36e389e976..1cb4da300607 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
@@ -13,6 +13,9 @@ description:
maintainers:
- Heiko Stuebner <heiko@sntech.de>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
oneOf:
@@ -111,7 +114,7 @@ required:
- dma-names
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
index d0a24bf928d6..4f51b2fa82db 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
@@ -75,17 +75,18 @@ required:
- dma-names
- "#sound-dai-cells"
-if:
- properties:
- compatible:
- contains:
- const: rockchip,rk3288-spdif
-
-then:
- required:
- - rockchip,grf
-
-additionalProperties: false
+allOf:
+ - $ref: dai-common.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3288-spdif
+ then:
+ required:
+ - rockchip,grf
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rohm,bd28623.yaml b/Documentation/devicetree/bindings/sound/rohm,bd28623.yaml
index 859ce64da152..5abcf92bc484 100644
--- a/Documentation/devicetree/bindings/sound/rohm,bd28623.yaml
+++ b/Documentation/devicetree/bindings/sound/rohm,bd28623.yaml
@@ -14,6 +14,9 @@ description:
maintainers:
- Katsuhiro Suzuki <katsuhiro@katsuster.net>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: rohm,bd28623
@@ -50,7 +53,7 @@ required:
- VCCP2-supply
- "#sound-dai-cells"
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
index 013f534fa059..8f3f62c0226a 100644
--- a/Documentation/devicetree/bindings/sound/rt5659.txt
+++ b/Documentation/devicetree/bindings/sound/rt5659.txt
@@ -42,7 +42,7 @@ Optional properties:
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
-- sound-name-prefix: Please refer to name-prefix.yaml
+- sound-name-prefix: Please refer to dai-common.yaml
- ports: A Codec may have a single or multiple I2S interfaces. These
interfaces on Codec side can be described under 'ports' or 'port'.
diff --git a/Documentation/devicetree/bindings/sound/rt5682.txt b/Documentation/devicetree/bindings/sound/rt5682.txt
index c5f2b8febcee..5e1d08de18a5 100644
--- a/Documentation/devicetree/bindings/sound/rt5682.txt
+++ b/Documentation/devicetree/bindings/sound/rt5682.txt
@@ -8,6 +8,21 @@ Required properties:
- reg : The I2C address of the device.
+- AVDD-supply: phandle to the regulator supplying analog power through the
+ AVDD pin
+
+- MICVDD-supply: phandle to the regulator supplying power for the microphone
+ bias through the MICVDD pin. Either MICVDD or VBAT should be present.
+
+- VBAT-supply: phandle to the regulator supplying battery power through the
+ VBAT pin. Either MICVDD or VBAT should be present.
+
+- DBVDD-supply: phandle to the regulator supplying I/O power through the DBVDD
+ pin.
+
+- LDO1-IN-supply: phandle to the regulator supplying power to the digital core
+ and charge pump through the LDO1_IN pin.
+
Optional properties:
- interrupts : The CODEC's interrupt output.
@@ -46,7 +61,7 @@ Optional properties:
- realtek,dmic-clk-driving-high : Set the high driving of the DMIC clock out.
-- #sound-dai-cells: Should be set to '<0>'.
+- #sound-dai-cells: Should be set to '<1>'.
Pins on the device (for linking into audio routes) for RT5682:
@@ -75,4 +90,9 @@ rt5682 {
clocks = <&osc>;
clock-names = "mclk";
+
+ AVDD-supply = <&avdd_reg>;
+ MICVDD-supply = <&micvdd_reg>;
+ DBVDD-supply = <&dbvdd_reg>;
+ LDO1-IN-supply = <&ldo1_in_reg>;
};
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml
index 84c4d6cba521..8d5dcf9cd43e 100644
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml
@@ -10,6 +10,9 @@ maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
- Sylwester Nawrocki <s.nawrocki@samsung.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
description: |
@@ -124,7 +127,7 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.yaml b/Documentation/devicetree/bindings/sound/sgtl5000.yaml
index 2bc7f00ce4a2..02059d66b084 100644
--- a/Documentation/devicetree/bindings/sound/sgtl5000.yaml
+++ b/Documentation/devicetree/bindings/sound/sgtl5000.yaml
@@ -9,6 +9,9 @@ title: Freescale SGTL5000 Stereo Codec
maintainers:
- Fabio Estevam <festevam@gmail.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: fsl,sgtl5000
@@ -88,7 +91,7 @@ required:
- VDDA-supply
- VDDIO-supply
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml
index 5428ba9e23a6..5db1f989d050 100644
--- a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml
@@ -10,7 +10,7 @@ maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
index b5fc35ee9b65..9f319caf3db7 100644
--- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
@@ -14,7 +14,7 @@ description: |
their input line is connected to the output line.
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
index 4b0795819064..56e623d4e168 100644
--- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
@@ -50,21 +50,21 @@ properties:
- const: rx
minItems: 1
-if:
- properties:
- compatible:
- contains:
- const: canaan,k210-i2s
-
-then:
- properties:
- "#sound-dai-cells":
- const: 1
-
-else:
- properties:
- "#sound-dai-cells":
- const: 0
+allOf:
+ - $ref: dai-common.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: canaan,k210-i2s
+ then:
+ properties:
+ "#sound-dai-cells":
+ const: 1
+ else:
+ properties:
+ "#sound-dai-cells":
+ const: 0
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml b/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml
index 70f62ecd6eb2..9cf0efaed88e 100644
--- a/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml
+++ b/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml
@@ -9,6 +9,9 @@ title: UniPhier AIO audio system
maintainers:
- <alsa-devel@alsa-project.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -70,7 +73,7 @@ patternProperties:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
-additionalProperties: false
+unevaluatedProperties: false
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml b/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml
index be6acfda9999..985277648de1 100644
--- a/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml
+++ b/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml
@@ -9,6 +9,9 @@ title: UniPhier EVEA SoC-internal sound codec
maintainers:
- <alsa-devel@alsa-project.org>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: socionext,uniphier-evea
@@ -48,7 +51,7 @@ patternProperties:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
-additionalProperties: false
+unevaluatedProperties: false
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
index d3966ae04ad0..a040d4d31412 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
@@ -13,6 +13,9 @@ description:
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
Only some SPI instances support I2S.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -68,7 +71,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml
index 837e830c47ac..bc48151b9adb 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml
+++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml
@@ -13,6 +13,9 @@ description: |
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
IEC-60958 and IEC-61937.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -57,7 +60,7 @@ required:
- dmas
- dma-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml
index 30f6b029ac08..1085592cefcc 100644
--- a/Documentation/devicetree/bindings/sound/tas2562.yaml
+++ b/Documentation/devicetree/bindings/sound/tas2562.yaml
@@ -22,6 +22,9 @@ description: |
https://www.ti.com/lit/gpn/tas2564
https://www.ti.com/lit/gpn/tas2110
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -58,7 +61,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/tas2770.yaml
index bc90e72bf7cf..982949ba8a4b 100644
--- a/Documentation/devicetree/bindings/sound/tas2770.yaml
+++ b/Documentation/devicetree/bindings/sound/tas2770.yaml
@@ -16,6 +16,9 @@ description: |
Integrated speaker voltage and current sense provides for
real time monitoring of loudspeaker behavior.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -60,7 +63,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/tas27xx.yaml
index 66a0df8850ea..0957dd435bb4 100644
--- a/Documentation/devicetree/bindings/sound/tas27xx.yaml
+++ b/Documentation/devicetree/bindings/sound/tas27xx.yaml
@@ -16,6 +16,9 @@ description: |
loudspeakers. Integrated speaker voltage and current sense provides
for real time monitoring of loudspeaker behavior.
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -53,7 +56,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml b/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml
index 9681b72b4918..988ce8d8028f 100644
--- a/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml
@@ -14,7 +14,7 @@ maintainers:
- Matt Flax <flatmax@flatmax.com>
allOf:
- - $ref: name-prefix.yaml#
+ - $ref: dai-common.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
index 83936f594d1a..ede14ca2c07a 100644
--- a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
@@ -14,6 +14,9 @@ description: |
https://www.ti.com/product/TLV320ADC3001
https://www.ti.com/product/TLV320ADC3101
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -106,7 +109,7 @@ required:
- reg
- clocks
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/wlf,arizona.yaml b/Documentation/devicetree/bindings/sound/wlf,arizona.yaml
index 1627c0bb69be..8156f30eadd6 100644
--- a/Documentation/devicetree/bindings/sound/wlf,arizona.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,arizona.yaml
@@ -16,6 +16,9 @@ description: |
This document lists sound specific bindings, see the primary binding
document ../mfd/arizona.yaml
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
'#sound-dai-cells':
description:
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8731.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
index 15795f63b5a3..858c0f689581 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
@@ -61,6 +61,7 @@ required:
- DCVDD-supply
allOf:
+ - $ref: dai-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8940.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8940.yaml
index 7386abb3a250..3e809217c4ca 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8940.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8940.yaml
@@ -9,6 +9,9 @@ title: Wolfson WM8940 Codec
maintainers:
- patches@opensource.cirrus.com
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
'#sound-dai-cells':
const: 0
@@ -27,7 +30,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml
new file mode 100644
index 000000000000..f58078545569
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8961.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wolfson WM8961 Ultra-Low Power Stereo CODEC
+
+maintainers:
+ - patches@opensource.cirrus.com
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: wlf,wm8961
+
+ reg:
+ maxItems: 1
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - '#sound-dai-cells'
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wm8961: codec@4a {
+ compatible = "wlf,wm8961";
+ reg = <0x4a>;
+ #sound-dai-cells = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8962.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8962.yaml
index 5e172e9462b9..5fe0b2c9f99f 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8962.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8962.yaml
@@ -9,6 +9,9 @@ title: Wolfson WM8962 Ultra-Low Power Stereo CODEC
maintainers:
- patches@opensource.cirrus.com
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: wlf,wm8962
@@ -87,7 +90,7 @@ required:
- SPKVDD1-supply
- SPKVDD2-supply
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml
index 1c8985d4dd5a..efb5f9f6cc7a 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml
@@ -9,6 +9,9 @@ title: Wolfson WM8978 Codec
maintainers:
- patches@opensource.cirrus.com
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
'#sound-dai-cells':
const: 0
@@ -27,7 +30,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/zl38060.yaml b/Documentation/devicetree/bindings/sound/zl38060.yaml
index 338e2a13c775..2c5c02e34573 100644
--- a/Documentation/devicetree/bindings/sound/zl38060.yaml
+++ b/Documentation/devicetree/bindings/sound/zl38060.yaml
@@ -15,6 +15,9 @@ maintainers:
- Jaroslav Kysela <perex@perex.cz>
- Takashi Iwai <tiwai@suse.com>
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
const: mscc,zl38060
@@ -48,7 +51,7 @@ required:
- gpio-controller
- '#sound-dai-cells'
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml
index 50df1a40bbe3..12cb76711000 100644
--- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml
+++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml
@@ -23,6 +23,9 @@ properties:
- const: fsl,imx51-ecspi
- const: fsl,imx53-ecspi
- items:
+ - const: fsl,imx8mp-ecspi
+ - const: fsl,imx6ul-ecspi
+ - items:
- enum:
- fsl,imx50-ecspi
- fsl,imx6q-ecspi
@@ -34,7 +37,6 @@ properties:
- fsl,imx8mq-ecspi
- fsl,imx8mm-ecspi
- fsl,imx8mn-ecspi
- - fsl,imx8mp-ecspi
- const: fsl,imx51-ecspi
reg:
diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml
index e9199190198d..665c06e14f79 100644
--- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml
+++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml
@@ -25,6 +25,7 @@ properties:
- qcom,sdm630-imem
- qcom,sdm845-imem
- qcom,sdx55-imem
+ - qcom,sdx65-imem
- const: syscon
- const: simple-mfd
diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
index feb390d50696..d20569b9b763 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
@@ -222,8 +222,8 @@ examples:
qcom,hw-settle-time = <200>;
};
- conn-therm@47 {
- reg = <PM8350_ADC7_AMUX_THM4_100K_PU>;
+ conn-therm@147 {
+ reg = <PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
};
@@ -247,7 +247,7 @@ examples:
conn-therm@1 {
reg = <1>;
- io-channels = <&pmk8350_vadc PM8350_ADC7_AMUX_THM4_100K_PU>;
+ io-channels = <&pmk8350_vadc PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
qcom,avg-samples = <2>;
qcom,ratiometric;
qcom,hw-settle-time-us = <200>;
diff --git a/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml b/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml
index 737af78ad70c..d53e1bb98b8a 100644
--- a/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml
+++ b/Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml
@@ -25,7 +25,13 @@ properties:
- description: The timer interrupt of timer 0
clocks:
- maxItems: 1
+ items:
+ - description: The reference clock for timer 0
+ - description: The reference clock for timer 1
+ - description: The reference clock for timer 2
+ - description: The reference clock for timer 3
+ - description: The reference clock for timer 4
+ minItems: 1
required:
- compatible
diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.yaml b/Documentation/devicetree/bindings/timer/renesas,cmt.yaml
index bde6c9b66bf4..a0be1755ea28 100644
--- a/Documentation/devicetree/bindings/timer/renesas,cmt.yaml
+++ b/Documentation/devicetree/bindings/timer/renesas,cmt.yaml
@@ -102,12 +102,14 @@ properties:
- enum:
- renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U
- renesas,r8a779f0-cmt0 # 32-bit CMT0 on R-Car S4-8
+ - renesas,r8a779g0-cmt0 # 32-bit CMT0 on R-Car V4H
- const: renesas,rcar-gen4-cmt0 # 32-bit CMT0 on R-Car Gen4
- items:
- enum:
- renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U
- renesas,r8a779f0-cmt1 # 48-bit CMT on R-Car S4-8
+ - renesas,r8a779g0-cmt1 # 48-bit CMT on R-Car V4H
- const: renesas,rcar-gen4-cmt1 # 48-bit CMT on R-Car Gen4
reg:
diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
index 60f4c059bcff..a67e427a9e7e 100644
--- a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
+++ b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
@@ -38,6 +38,7 @@ properties:
- renesas,tmu-r8a77995 # R-Car D3
- renesas,tmu-r8a779a0 # R-Car V3U
- renesas,tmu-r8a779f0 # R-Car S4-8
+ - renesas,tmu-r8a779g0 # R-Car V4H
- const: renesas,tmu
reg:
diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml
index dc3bc1e62fe9..b61ed1a431bb 100644
--- a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml
+++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml
@@ -18,6 +18,7 @@ properties:
- enum:
- rockchip,rv1108-timer
- rockchip,rk3036-timer
+ - rockchip,rk3128-timer
- rockchip,rk3188-timer
- rockchip,rk3228-timer
- rockchip,rk3229-timer
diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
index c5f629c5bc61..994818cb6044 100644
--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
@@ -30,6 +30,7 @@ properties:
- allwinner,sun4i-a10-ehci
- allwinner,sun50i-a64-ehci
- allwinner,sun50i-h6-ehci
+ - allwinner,sun50i-h616-ehci
- allwinner,sun5i-a13-ehci
- allwinner,sun6i-a31-ehci
- allwinner,sun7i-a20-ehci
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
index f838f78d6164..4fcbd0add49d 100644
--- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
@@ -20,6 +20,7 @@ properties:
- allwinner,sun4i-a10-ohci
- allwinner,sun50i-a64-ohci
- allwinner,sun50i-h6-ohci
+ - allwinner,sun50i-h616-ohci
- allwinner,sun5i-a13-ohci
- allwinner,sun6i-a31-ohci
- allwinner,sun7i-a20-ohci
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt
deleted file mode 100644
index 5bfcc0b4d6b9..000000000000
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt
+++ /dev/null
@@ -1,132 +0,0 @@
-NVIDIA Tegra xHCI controller
-============================
-
-The Tegra xHCI controller supports both USB2 and USB3 interfaces exposed by
-the Tegra XUSB pad controller.
-
-Required properties:
---------------------
-- compatible: Must be:
- - Tegra124: "nvidia,tegra124-xusb"
- - Tegra132: "nvidia,tegra132-xusb", "nvidia,tegra124-xusb"
- - Tegra210: "nvidia,tegra210-xusb"
- - Tegra186: "nvidia,tegra186-xusb"
-- reg: Must contain the base and length of the xHCI host registers, XUSB FPCI
- registers and XUSB IPFS registers.
-- reg-names: Must contain the following entries:
- - "hcd"
- - "fpci"
- - "ipfs"
-- interrupts: Must contain the xHCI host interrupt and the mailbox interrupt.
-- clocks: Must contain an entry for each entry in clock-names.
- See ../clock/clock-bindings.txt for details.
-- clock-names: Must include the following entries:
- - xusb_host
- - xusb_host_src
- - xusb_falcon_src
- - xusb_ss
- - xusb_ss_src
- - xusb_ss_div2
- - xusb_hs_src
- - xusb_fs_src
- - pll_u_480m
- - clk_m
- - pll_e
-- resets: Must contain an entry for each entry in reset-names.
- See ../reset/reset.txt for details.
-- reset-names: Must include the following entries:
- - xusb_host
- - xusb_ss
- - xusb_src
- Note that xusb_src is the shared reset for xusb_{ss,hs,fs,falcon,host}_src.
-- nvidia,xusb-padctl: phandle to the XUSB pad controller that is used to
- configure the USB pads used by the XHCI controller
-
-For Tegra124 and Tegra132:
-- avddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
-- dvddio-pex-supply: PCIe/USB3 digital logic power supply. Must supply 1.05 V.
-- avdd-usb-supply: USB controller power supply. Must supply 3.3 V.
-- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
-- avdd-pll-erefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
-- avdd-usb-ss-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
-- hvdd-usb-ss-supply: High-voltage PCIe/USB3 power supply. Must supply 3.3 V.
-- hvdd-usb-ss-pll-e-supply: High-voltage PLLE power supply. Must supply 3.3 V.
-
-For Tegra210:
-- dvddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
-- hvddio-pex-supply: High-voltage PCIe/USB3 power supply. Must supply 1.8 V.
-- avdd-usb-supply: USB controller power supply. Must supply 3.3 V.
-- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
-- avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
-- dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
-- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V.
-
-For Tegra210 and Tegra186:
-- power-domains: A list of PM domain specifiers that reference each power-domain
- used by the xHCI controller. This list must comprise of a specifier for the
- XUSBA and XUSBC power-domains. See ../power/power_domain.txt and
- ../arm/tegra/nvidia,tegra20-pmc.txt for details.
-- power-domain-names: A list of names that represent each of the specifiers in
- the 'power-domains' property. Must include 'xusb_ss' and 'xusb_host' which
- represent the power-domains XUSBA and XUSBC, respectively. See
- ../power/power_domain.txt for details.
-
-Optional properties:
---------------------
-- phys: Must contain an entry for each entry in phy-names.
- See ../phy/phy-bindings.txt for details.
-- phy-names: Should include an entry for each PHY used by the controller. The
- following PHYs are available:
- - Tegra124: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1
- - Tegra132: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1
- - Tegra210: usb2-0, usb2-1, usb2-2, usb2-3, hsic-0, usb3-0, usb3-1, usb3-2,
- usb3-3
- - Tegra186: usb2-0, usb2-1, usb2-2, hsic-0, usb3-0, usb3-1, usb3-2
-
-Example:
---------
-
- usb@0,70090000 {
- compatible = "nvidia,tegra124-xusb";
- reg = <0x0 0x70090000 0x0 0x8000>,
- <0x0 0x70098000 0x0 0x1000>,
- <0x0 0x70099000 0x0 0x1000>;
- reg-names = "hcd", "fpci", "ipfs";
-
- interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-
- clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
- <&tegra_car TEGRA124_CLK_XUSB_HOST_SRC>,
- <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
- <&tegra_car TEGRA124_CLK_XUSB_SS>,
- <&tegra_car TEGRA124_CLK_XUSB_SS_DIV2>,
- <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>,
- <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>,
- <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>,
- <&tegra_car TEGRA124_CLK_PLL_U_480M>,
- <&tegra_car TEGRA124_CLK_CLK_M>,
- <&tegra_car TEGRA124_CLK_PLL_E>;
- clock-names = "xusb_host", "xusb_host_src", "xusb_falcon_src",
- "xusb_ss", "xusb_ss_div2", "xusb_ss_src",
- "xusb_hs_src", "xusb_fs_src", "pll_u_480m",
- "clk_m", "pll_e";
- resets = <&tegra_car 89>, <&tegra_car 156>, <&tegra_car 143>;
- reset-names = "xusb_host", "xusb_ss", "xusb_src";
-
- nvidia,xusb-padctl = <&padctl>;
-
- phys = <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-1}>, /* mini-PCIe USB */
- <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-2}>, /* USB A */
- <&{/padctl@0,7009f000/pads/pcie/lanes/pcie-0}>; /* USB A */
- phy-names = "usb2-1", "usb2-2", "usb3-0";
-
- avddio-pex-supply = <&vdd_1v05_run>;
- dvddio-pex-supply = <&vdd_1v05_run>;
- avdd-usb-supply = <&vdd_3v3_lp0>;
- avdd-pll-utmip-supply = <&vddio_1v8>;
- avdd-pll-erefe-supply = <&avdd_1v05_run>;
- avdd-usb-ss-pll-supply = <&vdd_1v05_run>;
- hvdd-usb-ss-supply = <&vdd_3v3_lp0>;
- hvdd-usb-ss-pll-e-supply = <&vdd_3v3_lp0>;
- };
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.yaml
new file mode 100644
index 000000000000..4a6616bf9bab
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.yaml
@@ -0,0 +1,202 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/nvidia,tegra124-xusb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra124 xHCI controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+description: The Tegra xHCI controller supports both USB2 and USB3 interfaces
+ exposed by the Tegra XUSB pad controller.
+
+properties:
+ # required
+ compatible:
+ oneOf:
+ - description: NVIDIA Tegra124
+ const: nvidia,tegra124-xusb
+
+ - description: NVIDIA Tegra132
+ items:
+ - const: nvidia,tegra132-xusb
+ - const: nvidia,tegra124-xusb
+
+ reg:
+ items:
+ - description: base and length of the xHCI host registers
+ - description: base and length of the XUSB FPCI registers
+ - description: base and length of the XUSB IPFS registers
+
+ reg-names:
+ items:
+ - const: hcd
+ - const: fpci
+ - const: ipfs
+
+ interrupts:
+ items:
+ - description: xHCI host interrupt
+ - description: mailbox interrupt
+
+ clocks:
+ items:
+ - description: XUSB host clock
+ - description: XUSB host source clock
+ - description: XUSB Falcon source clock
+ - description: XUSB SuperSpeed clock
+ - description: XUSB SuperSpeed clock divider
+ - description: XUSB SuperSpeed source clock
+ - description: XUSB HighSpeed clock source
+ - description: XUSB FullSpeed clock source
+ - description: USB PLL
+ - description: reference clock
+ - description: I/O PLL
+
+ clock-names:
+ items:
+ - const: xusb_host
+ - const: xusb_host_src
+ - const: xusb_falcon_src
+ - const: xusb_ss
+ - const: xusb_ss_div2
+ - const: xusb_ss_src
+ - const: xusb_hs_src
+ - const: xusb_fs_src
+ - const: pll_u_480m
+ - const: clk_m
+ - const: pll_e
+
+ resets:
+ items:
+ - description: reset for the XUSB host controller
+ - description: reset for the SuperSpeed logic
+ - description: shared reset for xusb_{ss,hs,fs,falcon,host}_src.
+
+ reset-names:
+ items:
+ - const: xusb_host
+ - const: xusb_ss
+ - const: xusb_src
+
+ nvidia,xusb-padctl:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the XUSB pad controller that is used to configure
+ the USB pads used by the XHCI controller
+
+ # optional
+ phys:
+ minItems: 1
+ maxItems: 7
+
+ phy-names:
+ minItems: 1
+ maxItems: 7
+ items:
+ enum:
+ - usb2-0
+ - usb2-1
+ - usb2-2
+ - hsic-0
+ - hsic-1
+ - usb3-0
+ - usb3-1
+
+ avddio-pex-supply:
+ description: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
+
+ dvddio-pex-supply:
+ description: PCIe/USB3 digital logic power supply. Must supply 1.05 V.
+
+ avdd-usb-supply:
+ description: USB controller power supply. Must supply 3.3 V.
+
+ avdd-pll-utmip-supply:
+ description: UTMI PLL power supply. Must supply 1.8 V.
+
+ avdd-pll-erefe-supply:
+ description: PLLE reference PLL power supply. Must supply 1.05 V.
+
+ avdd-usb-ss-pll-supply:
+ description: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+
+ hvdd-usb-ss-supply:
+ description: High-voltage PCIe/USB3 power supply. Must supply 3.3 V.
+
+ hvdd-usb-ss-pll-e-supply:
+ description: High-voltage PLLE power supply. Must supply 3.3 V.
+
+allOf:
+ - $ref: usb-xhci.yaml
+
+unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - nvidia,xusb-padctl
+ - phys
+ - phy-names
+ - avddio-pex-supply
+ - dvddio-pex-supply
+ - avdd-usb-supply
+ - hvdd-usb-ss-supply
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra124-car.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ usb@70090000 {
+ compatible = "nvidia,tegra124-xusb";
+ reg = <0x70090000 0x8000>,
+ <0x70098000 0x1000>,
+ <0x70099000 0x1000>;
+ reg-names = "hcd", "fpci", "ipfs";
+
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+ <&tegra_car TEGRA124_CLK_XUSB_HOST_SRC>,
+ <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+ <&tegra_car TEGRA124_CLK_XUSB_SS>,
+ <&tegra_car TEGRA124_CLK_XUSB_SS_DIV2>,
+ <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>,
+ <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>,
+ <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>,
+ <&tegra_car TEGRA124_CLK_PLL_U_480M>,
+ <&tegra_car TEGRA124_CLK_CLK_M>,
+ <&tegra_car TEGRA124_CLK_PLL_E>;
+ clock-names = "xusb_host", "xusb_host_src", "xusb_falcon_src",
+ "xusb_ss", "xusb_ss_div2", "xusb_ss_src",
+ "xusb_hs_src", "xusb_fs_src", "pll_u_480m",
+ "clk_m", "pll_e";
+ resets = <&tegra_car 89>, <&tegra_car 156>, <&tegra_car 143>;
+ reset-names = "xusb_host", "xusb_ss", "xusb_src";
+
+ nvidia,xusb-padctl = <&padctl>;
+
+ phys = <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-1}>, /* mini-PCIe USB */
+ <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-2}>, /* USB A */
+ <&{/padctl@0,7009f000/pads/pcie/lanes/pcie-0}>; /* USB A */
+ phy-names = "usb2-1", "usb2-2", "usb3-0";
+
+ avddio-pex-supply = <&vdd_1v05_run>;
+ dvddio-pex-supply = <&vdd_1v05_run>;
+ avdd-usb-supply = <&vdd_3v3_lp0>;
+ avdd-pll-utmip-supply = <&vddio_1v8>;
+ avdd-pll-erefe-supply = <&avdd_1v05_run>;
+ avdd-usb-ss-pll-supply = <&vdd_1v05_run>;
+ hvdd-usb-ss-supply = <&vdd_3v3_lp0>;
+ hvdd-usb-ss-pll-e-supply = <&vdd_3v3_lp0>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra186-xusb.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra186-xusb.yaml
new file mode 100644
index 000000000000..6f62944fc597
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra186-xusb.yaml
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/nvidia,tegra186-xusb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra186 xHCI controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+description: The Tegra xHCI controller supports both USB2 and USB3 interfaces
+ exposed by the Tegra XUSB pad controller.
+
+properties:
+ compatible:
+ const: nvidia,tegra186-xusb
+
+ reg:
+ items:
+ - description: base and length of the xHCI host registers
+ - description: base and length of the XUSB FPCI registers
+
+ reg-names:
+ items:
+ - const: hcd
+ - const: fpci
+
+ interrupts:
+ items:
+ - description: xHCI host interrupt
+ - description: mailbox interrupt
+
+ clocks:
+ items:
+ - description: XUSB host clock
+ - description: XUSB Falcon source clock
+ - description: XUSB SuperSpeed clock
+ - description: XUSB SuperSpeed source clock
+ - description: XUSB HighSpeed clock source
+ - description: XUSB FullSpeed clock source
+ - description: USB PLL
+ - description: reference clock
+ - description: I/O PLL
+
+ clock-names:
+ items:
+ - const: xusb_host
+ - const: xusb_falcon_src
+ - const: xusb_ss
+ - const: xusb_ss_src
+ - const: xusb_hs_src
+ - const: xusb_fs_src
+ - const: pll_u_480m
+ - const: clk_m
+ - const: pll_e
+
+ interconnects:
+ items:
+ - description: read client
+ - description: write client
+
+ interconnect-names:
+ items:
+ - const: dma-mem # read
+ - const: write
+
+ iommus:
+ maxItems: 1
+
+ nvidia,xusb-padctl:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the XUSB pad controller that is used to configure
+ the USB pads used by the XHCI controller
+
+ phys:
+ minItems: 1
+ maxItems: 7
+
+ phy-names:
+ minItems: 1
+ maxItems: 7
+ items:
+ enum:
+ - usb2-0
+ - usb2-1
+ - usb2-2
+ - hsic-0
+ - usb3-0
+ - usb3-1
+ - usb3-2
+
+ power-domains:
+ items:
+ - description: XUSBC power domain (for Host and USB 2.0)
+ - description: XUSBA power domain (for SuperSpeed)
+
+ power-domain-names:
+ items:
+ - const: xusb_host
+ - const: xusb_ss
+
+ dvddio-pex-supply:
+ description: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
+
+ hvddio-pex-supply:
+ description: High-voltage PCIe/USB3 power supply. Must supply 1.8 V.
+
+ avdd-usb-supply:
+ description: USB controller power supply. Must supply 3.3 V.
+
+ avdd-pll-utmip-supply:
+ description: UTMI PLL power supply. Must supply 1.8 V.
+
+ avdd-pll-uerefe-supply:
+ description: PLLE reference PLL power supply. Must supply 1.05 V.
+
+ dvdd-usb-ss-pll-supply:
+ description: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+
+ hvdd-usb-ss-pll-e-supply:
+ description: High-voltage PLLE power supply. Must supply 1.8 V.
+
+allOf:
+ - $ref: usb-xhci.yaml
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra186-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/memory/tegra186-mc.h>
+ #include <dt-bindings/power/tegra186-powergate.h>
+ #include <dt-bindings/reset/tegra186-reset.h>
+
+ usb@3530000 {
+ compatible = "nvidia,tegra186-xusb";
+ reg = <0x03530000 0x8000>,
+ <0x03538000 0x1000>;
+ reg-names = "hcd", "fpci";
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bpmp TEGRA186_CLK_XUSB_HOST>,
+ <&bpmp TEGRA186_CLK_XUSB_FALCON>,
+ <&bpmp TEGRA186_CLK_XUSB_SS>,
+ <&bpmp TEGRA186_CLK_XUSB_CORE_SS>,
+ <&bpmp TEGRA186_CLK_CLK_M>,
+ <&bpmp TEGRA186_CLK_XUSB_FS>,
+ <&bpmp TEGRA186_CLK_PLLU>,
+ <&bpmp TEGRA186_CLK_CLK_M>,
+ <&bpmp TEGRA186_CLK_PLLE>;
+ clock-names = "xusb_host", "xusb_falcon_src", "xusb_ss",
+ "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+ "pll_u_480m", "clk_m", "pll_e";
+ power-domains = <&bpmp TEGRA186_POWER_DOMAIN_XUSBC>,
+ <&bpmp TEGRA186_POWER_DOMAIN_XUSBA>;
+ power-domain-names = "xusb_host", "xusb_ss";
+ interconnects = <&mc TEGRA186_MEMORY_CLIENT_XUSB_HOSTR &emc>,
+ <&mc TEGRA186_MEMORY_CLIENT_XUSB_HOSTW &emc>;
+ interconnect-names = "dma-mem", "write";
+ iommus = <&smmu TEGRA186_SID_XUSB_HOST>;
+ nvidia,xusb-padctl = <&padctl>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phys = <&{/padctl@3520000/pads/usb2/lanes/usb2-0}>,
+ <&{/padctl@3520000/pads/usb2/lanes/usb2-1}>,
+ <&{/padctl@3520000/pads/usb3/lanes/usb3-0}>;
+ phy-names = "usb2-0", "usb2-1", "usb3-0";
+ };
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra194-xusb.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra194-xusb.yaml
new file mode 100644
index 000000000000..65ae9ae9b0b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra194-xusb.yaml
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/nvidia,tegra194-xusb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra194 xHCI controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+description: The Tegra xHCI controller supports both USB2 and USB3 interfaces
+ exposed by the Tegra XUSB pad controller.
+
+properties:
+ compatible:
+ const: nvidia,tegra194-xusb
+
+ reg:
+ items:
+ - description: base and length of the xHCI host registers
+ - description: base and length of the XUSB FPCI registers
+
+ reg-names:
+ items:
+ - const: hcd
+ - const: fpci
+
+ interrupts:
+ items:
+ - description: xHCI host interrupt
+ - description: mailbox interrupt
+
+ clocks:
+ items:
+ - description: XUSB host clock
+ - description: XUSB Falcon source clock
+ - description: XUSB SuperSpeed clock
+ - description: XUSB SuperSpeed source clock
+ - description: XUSB HighSpeed clock source
+ - description: XUSB FullSpeed clock source
+ - description: USB PLL
+ - description: reference clock
+ - description: I/O PLL
+
+ clock-names:
+ items:
+ - const: xusb_host
+ - const: xusb_falcon_src
+ - const: xusb_ss
+ - const: xusb_ss_src
+ - const: xusb_hs_src
+ - const: xusb_fs_src
+ - const: pll_u_480m
+ - const: clk_m
+ - const: pll_e
+
+ interconnects:
+ items:
+ - description: read client
+ - description: write client
+
+ interconnect-names:
+ items:
+ - const: dma-mem # read
+ - const: write
+
+ iommus:
+ maxItems: 1
+
+ nvidia,xusb-padctl:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the XUSB pad controller that is used to configure
+ the USB pads used by the XHCI controller
+
+ phys:
+ minItems: 1
+ maxItems: 8
+
+ phy-names:
+ minItems: 1
+ maxItems: 8
+ items:
+ enum:
+ - usb2-0
+ - usb2-1
+ - usb2-2
+ - usb2-3
+ - usb3-0
+ - usb3-1
+ - usb3-2
+ - usb3-3
+
+ power-domains:
+ items:
+ - description: XUSBC power domain (for Host and USB 2.0)
+ - description: XUSBA power domain (for SuperSpeed)
+
+ power-domain-names:
+ items:
+ - const: xusb_host
+ - const: xusb_ss
+
+ dvddio-pex-supply:
+ description: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
+
+ hvddio-pex-supply:
+ description: High-voltage PCIe/USB3 power supply. Must supply 1.8 V.
+
+ avdd-usb-supply:
+ description: USB controller power supply. Must supply 3.3 V.
+
+ avdd-pll-utmip-supply:
+ description: UTMI PLL power supply. Must supply 1.8 V.
+
+ avdd-pll-uerefe-supply:
+ description: PLLE reference PLL power supply. Must supply 1.05 V.
+
+ dvdd-usb-ss-pll-supply:
+ description: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+
+ hvdd-usb-ss-pll-e-supply:
+ description: High-voltage PLLE power supply. Must supply 1.8 V.
+
+allOf:
+ - $ref: usb-xhci.yaml
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra194-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/memory/tegra194-mc.h>
+ #include <dt-bindings/power/tegra194-powergate.h>
+ #include <dt-bindings/reset/tegra194-reset.h>
+
+ usb@3610000 {
+ compatible = "nvidia,tegra194-xusb";
+ reg = <0x03610000 0x40000>,
+ <0x03600000 0x10000>;
+ reg-names = "hcd", "fpci";
+
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&bpmp TEGRA194_CLK_XUSB_CORE_HOST>,
+ <&bpmp TEGRA194_CLK_XUSB_FALCON>,
+ <&bpmp TEGRA194_CLK_XUSB_CORE_SS>,
+ <&bpmp TEGRA194_CLK_XUSB_SS>,
+ <&bpmp TEGRA194_CLK_CLK_M>,
+ <&bpmp TEGRA194_CLK_XUSB_FS>,
+ <&bpmp TEGRA194_CLK_UTMIPLL>,
+ <&bpmp TEGRA194_CLK_CLK_M>,
+ <&bpmp TEGRA194_CLK_PLLE>;
+ clock-names = "xusb_host", "xusb_falcon_src",
+ "xusb_ss", "xusb_ss_src", "xusb_hs_src",
+ "xusb_fs_src", "pll_u_480m", "clk_m",
+ "pll_e";
+ interconnects = <&mc TEGRA194_MEMORY_CLIENT_XUSB_HOSTR &emc>,
+ <&mc TEGRA194_MEMORY_CLIENT_XUSB_HOSTW &emc>;
+ interconnect-names = "dma-mem", "write";
+ iommus = <&smmu TEGRA194_SID_XUSB_HOST>;
+
+ power-domains = <&bpmp TEGRA194_POWER_DOMAIN_XUSBC>,
+ <&bpmp TEGRA194_POWER_DOMAIN_XUSBA>;
+ power-domain-names = "xusb_host", "xusb_ss";
+
+ nvidia,xusb-padctl = <&xusb_padctl>;
+
+ phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>,
+ <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-1}>,
+ <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-3}>,
+ <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-0}>,
+ <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-2}>,
+ <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-3}>;
+ phy-names = "usb2-0", "usb2-1", "usb2-3", "usb3-0", "usb3-2", "usb3-3";
+ };
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra210-xusb.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra210-xusb.yaml
new file mode 100644
index 000000000000..da1e1ec0e7c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra210-xusb.yaml
@@ -0,0 +1,199 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/nvidia,tegra210-xusb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra210 xHCI controller
+
+maintainers:
+ - Thierry Reding <thierry.reding@gmail.com>
+ - Jon Hunter <jonathanh@nvidia.com>
+
+description: The Tegra xHCI controller supports both USB2 and USB3 interfaces
+ exposed by the Tegra XUSB pad controller.
+
+properties:
+ compatible:
+ const: nvidia,tegra210-xusb
+
+ reg:
+ items:
+ - description: base and length of the xHCI host registers
+ - description: base and length of the XUSB FPCI registers
+ - description: base and length of the XUSB IPFS registers
+
+ reg-names:
+ items:
+ - const: hcd
+ - const: fpci
+ - const: ipfs
+
+ interrupts:
+ items:
+ - description: xHCI host interrupt
+ - description: mailbox interrupt
+
+ clocks:
+ items:
+ - description: XUSB host clock
+ - description: XUSB host source clock
+ - description: XUSB Falcon source clock
+ - description: XUSB SuperSpeed clock
+ - description: XUSB SuperSpeed clock divider
+ - description: XUSB SuperSpeed source clock
+ - description: XUSB HighSpeed clock source
+ - description: XUSB FullSpeed clock source
+ - description: USB PLL
+ - description: reference clock
+ - description: I/O PLL
+
+ clock-names:
+ items:
+ - const: xusb_host
+ - const: xusb_host_src
+ - const: xusb_falcon_src
+ - const: xusb_ss
+ - const: xusb_ss_div2
+ - const: xusb_ss_src
+ - const: xusb_hs_src
+ - const: xusb_fs_src
+ - const: pll_u_480m
+ - const: clk_m
+ - const: pll_e
+
+ resets:
+ items:
+ - description: reset for the XUSB host controller
+ - description: reset for the SuperSpeed logic
+ - description: shared reset for xusb_{ss,hs,fs,falcon,host}_src.
+
+ reset-names:
+ items:
+ - const: xusb_host
+ - const: xusb_ss
+ - const: xusb_src
+
+ nvidia,xusb-padctl:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the XUSB pad controller that is used to configure
+ the USB pads used by the XHCI controller
+
+ phys:
+ minItems: 1
+ maxItems: 9
+
+ phy-names:
+ minItems: 1
+ maxItems: 9
+ items:
+ enum:
+ - usb2-0
+ - usb2-1
+ - usb2-2
+ - usb2-3
+ - hsic-0
+ - usb3-0
+ - usb3-1
+ - usb3-2
+ - usb3-3
+
+ power-domains:
+ items:
+ - description: XUSBC power domain (for Host and USB 2.0)
+ - description: XUSBA power domain (for SuperSpeed)
+
+ power-domain-names:
+ items:
+ - const: xusb_host
+ - const: xusb_ss
+
+ dvddio-pex-supply:
+ description: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
+
+ hvddio-pex-supply:
+ description: High-voltage PCIe/USB3 power supply. Must supply 1.8 V.
+
+ avdd-usb-supply:
+ description: USB controller power supply. Must supply 3.3 V.
+
+ avdd-pll-utmip-supply:
+ description: UTMI PLL power supply. Must supply 1.8 V.
+
+ avdd-pll-uerefe-supply:
+ description: PLLE reference PLL power supply. Must supply 1.05 V.
+
+ dvdd-usb-ss-pll-supply:
+ description: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+
+ hvdd-usb-ss-pll-e-supply:
+ description: High-voltage PLLE power supply. Must supply 1.8 V.
+
+allOf:
+ - $ref: usb-xhci.yaml
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra210-car.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ usb@70090000 {
+ compatible = "nvidia,tegra210-xusb";
+ reg = <0x70090000 0x8000>,
+ <0x70098000 0x1000>,
+ <0x70099000 0x1000>;
+ reg-names = "hcd", "fpci", "ipfs";
+
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&tegra_car TEGRA210_CLK_XUSB_HOST>,
+ <&tegra_car TEGRA210_CLK_XUSB_HOST_SRC>,
+ <&tegra_car TEGRA210_CLK_XUSB_FALCON_SRC>,
+ <&tegra_car TEGRA210_CLK_XUSB_SS>,
+ <&tegra_car TEGRA210_CLK_XUSB_SS_DIV2>,
+ <&tegra_car TEGRA210_CLK_XUSB_SS_SRC>,
+ <&tegra_car TEGRA210_CLK_XUSB_HS_SRC>,
+ <&tegra_car TEGRA210_CLK_XUSB_FS_SRC>,
+ <&tegra_car TEGRA210_CLK_PLL_U_480M>,
+ <&tegra_car TEGRA210_CLK_CLK_M>,
+ <&tegra_car TEGRA210_CLK_PLL_E>;
+ clock-names = "xusb_host", "xusb_host_src",
+ "xusb_falcon_src", "xusb_ss",
+ "xusb_ss_div2", "xusb_ss_src",
+ "xusb_hs_src", "xusb_fs_src",
+ "pll_u_480m", "clk_m", "pll_e";
+ resets = <&tegra_car 89>, <&tegra_car 156>,
+ <&tegra_car 143>;
+ reset-names = "xusb_host", "xusb_ss", "xusb_src";
+ power-domains = <&pd_xusbhost>, <&pd_xusbss>;
+ power-domain-names = "xusb_host", "xusb_ss";
+
+ nvidia,xusb-padctl = <&padctl>;
+
+ phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
+ <&{/padctl@7009f000/pads/usb2/lanes/usb2-1}>,
+ <&{/padctl@7009f000/pads/usb2/lanes/usb2-2}>,
+ <&{/padctl@7009f000/pads/usb2/lanes/usb2-3}>,
+ <&{/padctl@7009f000/pads/pcie/lanes/pcie-6}>,
+ <&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>;
+ phy-names = "usb2-0", "usb2-1", "usb2-2", "usb2-3", "usb3-0",
+ "usb3-1";
+ dvddio-pex-supply = <&vdd_pex_1v05>;
+ hvddio-pex-supply = <&vdd_1v8>;
+ avdd-usb-supply = <&vdd_3v3_sys>;
+ avdd-pll-utmip-supply = <&vdd_1v8>;
+ avdd-pll-uerefe-supply = <&vdd_pex_1v05>;
+ dvdd-usb-ss-pll-supply = <&vdd_pex_1v05>;
+ hvdd-usb-ss-pll-e-supply = <&vdd_1v8>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet@1 {
+ compatible = "usb955,9ff";
+ reg = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 6e323a380294..83ba9c4aac67 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -69,6 +69,8 @@ patternProperties:
description: Annapurna Labs
"^alcatel,.*":
description: Alcatel
+ "^alfa-network,.*":
+ description: ALFA Network Inc.
"^allegro,.*":
description: Allegro DVT
"^allo,.*":
@@ -246,6 +248,8 @@ patternProperties:
description: ChipOne
"^chipspark,.*":
description: ChipSPARK
+ "^chongzhou,.*":
+ description: Shenzhen Chongzhou Electronic Technology Co., Ltd
"^chrontel,.*":
description: Chrontel, Inc.
"^chrp,.*":
@@ -260,6 +264,8 @@ patternProperties:
description: Cirrus Logic, Inc.
"^cisco,.*":
description: Cisco Systems, Inc.
+ "^cloos,.*":
+ description: Carl Cloos Schweisstechnik GmbH.
"^cloudengines,.*":
description: Cloud Engines, Inc.
"^cnm,.*":
@@ -605,6 +611,8 @@ patternProperties:
description: Ingenic Semiconductor
"^injoinic,.*":
description: Injoinic Technology Corp.
+ "^innocomm,.*":
+ description: InnoComm Mobile Technology Corp.
"^innolux,.*":
description: Innolux Corporation
"^inside-secure,.*":
@@ -639,6 +647,8 @@ patternProperties:
description: ITian Corporation
"^iwave,.*":
description: iWave Systems Technologies Pvt. Ltd.
+ "^jadard,.*":
+ description: Jadard Technology Inc.
"^jdi,.*":
description: Japan Display Inc.
"^jedec,.*":
@@ -883,6 +893,8 @@ patternProperties:
description: Shenzhen Netxeon Technology CO., LTD
"^neweast,.*":
description: Guangdong Neweast Optoelectronics CO., LTD
+ "^newvision,.*":
+ description: New Vision Display (Shenzhen) Co., Ltd.
"^nexbox,.*":
description: Nexbox
"^nextthing,.*":
diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst
index c708cec889af..23edb427e76f 100644
--- a/Documentation/doc-guide/sphinx.rst
+++ b/Documentation/doc-guide/sphinx.rst
@@ -147,11 +147,9 @@ section of ``make help``. The generated documentation is placed in
format-specific subdirectories under ``Documentation/output``.
To generate documentation, Sphinx (``sphinx-build``) must obviously be
-installed. For prettier HTML output, the Read the Docs Sphinx theme
-(``sphinx_rtd_theme``) is used if available. For PDF output you'll also need
-``XeLaTeX`` and ``convert(1)`` from ImageMagick
-(https://www.imagemagick.org).\ [#ink]_
-All of these are widely available and packaged in distributions.
+installed. For PDF output you'll also need ``XeLaTeX`` and ``convert(1)``
+from ImageMagick (https://www.imagemagick.org).\ [#ink]_ All of these are
+widely available and packaged in distributions.
To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make
variable. For example, use ``make SPHINXOPTS=-v htmldocs`` to get more verbose
@@ -160,12 +158,8 @@ output.
It is also possible to pass an extra DOCS_CSS overlay file, in order to customize
the html layout, by using the ``DOCS_CSS`` make variable.
-By default, the build will try to use the Read the Docs sphinx theme:
-
- https://github.com/readthedocs/sphinx_rtd_theme
-
-If the theme is not available, it will fall-back to the classic one.
-
+By default, the "Alabaster" theme is used to build the HTML documentation;
+this theme is bundled with Sphinx and need not be installed separately.
The Sphinx theme can be overridden by using the ``DOCS_THEME`` make variable.
There is another make variable ``SPHINXDIRS``, which is useful when test
diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
index 36a76cbe9095..622b8156d212 100644
--- a/Documentation/driver-api/dma-buf.rst
+++ b/Documentation/driver-api/dma-buf.rst
@@ -119,6 +119,12 @@ DMA Buffer ioctls
.. kernel-doc:: include/uapi/linux/dma-buf.h
+DMA-BUF locking convention
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/dma-buf/dma-buf.c
+ :doc: locking convention
+
Kernel Functions and Structures Reference
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index fbdaa46e1d10..8abf9dda3241 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -287,12 +287,16 @@ IIO
devm_iio_device_register()
devm_iio_dmaengine_buffer_setup()
devm_iio_kfifo_buffer_setup()
+ devm_iio_kfifo_buffer_setup_ext()
devm_iio_map_array_register()
devm_iio_triggered_buffer_setup()
+ devm_iio_triggered_buffer_setup_ext()
devm_iio_trigger_alloc()
devm_iio_trigger_register()
devm_iio_channel_get()
devm_iio_channel_get_all()
+ devm_iio_hw_consumer_alloc()
+ devm_fwnode_iio_channel_get_by_name()
INPUT
devm_input_allocate_device()
@@ -339,7 +343,10 @@ IRQ
LED
devm_led_classdev_register()
+ devm_led_classdev_register_ext()
devm_led_classdev_unregister()
+ devm_led_trigger_register()
+ devm_of_led_get()
MDIO
devm_mdiobus_alloc()
@@ -403,6 +410,7 @@ POWER
devm_reboot_mode_unregister()
PWM
+ devm_pwmchip_add()
devm_pwm_get()
devm_fwnode_pwm_get()
diff --git a/Documentation/driver-api/eisa.rst b/Documentation/driver-api/eisa.rst
index c07565ba57da..3eac11b7eb01 100644
--- a/Documentation/driver-api/eisa.rst
+++ b/Documentation/driver-api/eisa.rst
@@ -189,7 +189,7 @@ eisa_bus.enable_dev
initialize the device in such conditions.
eisa_bus.disable_dev
- A comma-separated list of slots to be enabled, even if the firmware
+ A comma-separated list of slots to be disabled, even if the firmware
set the card as enabled. The driver won't be called to handle this
device.
diff --git a/Documentation/driver-api/miscellaneous.rst b/Documentation/driver-api/miscellaneous.rst
index 304ffb146cf9..4a5104a368ac 100644
--- a/Documentation/driver-api/miscellaneous.rst
+++ b/Documentation/driver-api/miscellaneous.rst
@@ -16,12 +16,11 @@ Parallel Port Devices
16x50 UART Driver
=================
-.. kernel-doc:: drivers/tty/serial/serial_core.c
- :export:
-
.. kernel-doc:: drivers/tty/serial/8250/8250_core.c
:export:
+See serial/driver.rst for related APIs.
+
Pulse-Width Modulation (PWM)
============================
diff --git a/Documentation/fault-injection/fault-injection.rst b/Documentation/fault-injection/fault-injection.rst
index 17779a2772e5..5f6454b9dbd4 100644
--- a/Documentation/fault-injection/fault-injection.rst
+++ b/Documentation/fault-injection/fault-injection.rst
@@ -83,9 +83,7 @@ configuration of fault-injection capabilities.
- /sys/kernel/debug/fail*/times:
specifies how many times failures may happen at most. A value of -1
- means "no limit". Note, though, that this file only accepts unsigned
- values. So, if you want to specify -1, you better use 'printf' instead
- of 'echo', e.g.: $ printf %#x -1 > times
+ means "no limit".
- /sys/kernel/debug/fail*/space:
@@ -284,7 +282,7 @@ Application Examples
echo Y > /sys/kernel/debug/$FAILTYPE/task-filter
echo 10 > /sys/kernel/debug/$FAILTYPE/probability
echo 100 > /sys/kernel/debug/$FAILTYPE/interval
- printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
+ echo -1 > /sys/kernel/debug/$FAILTYPE/times
echo 0 > /sys/kernel/debug/$FAILTYPE/space
echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
echo Y > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
@@ -338,7 +336,7 @@ Application Examples
echo N > /sys/kernel/debug/$FAILTYPE/task-filter
echo 10 > /sys/kernel/debug/$FAILTYPE/probability
echo 100 > /sys/kernel/debug/$FAILTYPE/interval
- printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
+ echo -1 > /sys/kernel/debug/$FAILTYPE/times
echo 0 > /sys/kernel/debug/$FAILTYPE/space
echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
echo Y > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
@@ -369,7 +367,7 @@ Application Examples
echo N > /sys/kernel/debug/$FAILTYPE/task-filter
echo 100 > /sys/kernel/debug/$FAILTYPE/probability
echo 0 > /sys/kernel/debug/$FAILTYPE/interval
- printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
+ echo -1 > /sys/kernel/debug/$FAILTYPE/times
echo 0 > /sys/kernel/debug/$FAILTYPE/space
echo 1 > /sys/kernel/debug/$FAILTYPE/verbose
diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst
index 4d2411e32ebb..e53375033146 100644
--- a/Documentation/fb/modedb.rst
+++ b/Documentation/fb/modedb.rst
@@ -26,6 +26,11 @@ Valid mode specifiers (mode_option argument)::
with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string.
Things between square brackets are optional.
+Valid names are::
+
+ - NSTC: 480i output, with the CCIR System-M TV mode and NTSC color encoding
+ - PAL: 576i output, with the CCIR System-B TV mode and PAL color encoding
+
If 'M' is specified in the mode_option argument (after <yres> and before
<bpp> and <refresh>, if specified) the timings will be calculated using
VESA(TM) Coordinated Video Timings instead of looking up the mode from a table.
diff --git a/Documentation/features/core/cBPF-JIT/arch-support.txt b/Documentation/features/core/cBPF-JIT/arch-support.txt
index a053667a7a8c..0a1f5bb7eeb9 100644
--- a/Documentation/features/core/cBPF-JIT/arch-support.txt
+++ b/Documentation/features/core/cBPF-JIT/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/core/eBPF-JIT/arch-support.txt b/Documentation/features/core/eBPF-JIT/arch-support.txt
index c0bb9c92937f..6c0f3d759e6a 100644
--- a/Documentation/features/core/eBPF-JIT/arch-support.txt
+++ b/Documentation/features/core/eBPF-JIT/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/core/generic-idle-thread/arch-support.txt b/Documentation/features/core/generic-idle-thread/arch-support.txt
index c9bfff292816..0b94099cf6ac 100644
--- a/Documentation/features/core/generic-idle-thread/arch-support.txt
+++ b/Documentation/features/core/generic-idle-thread/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | ok |
| ia64: | ok |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/jump-labels/arch-support.txt
index 35e2a44b1448..2328eada3a49 100644
--- a/Documentation/features/core/jump-labels/arch-support.txt
+++ b/Documentation/features/core/jump-labels/arch-support.txt
@@ -10,10 +10,10 @@
| arc: | ok |
| arm: | ok |
| arm64: | ok |
- | csky: | TODO |
+ | csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/core/thread-info-in-task/arch-support.txt b/Documentation/features/core/thread-info-in-task/arch-support.txt
index 9b3e2ce12b44..9c5d39eebef2 100644
--- a/Documentation/features/core/thread-info-in-task/arch-support.txt
+++ b/Documentation/features/core/thread-info-in-task/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/core/tracehook/arch-support.txt b/Documentation/features/core/tracehook/arch-support.txt
index 9c7ffec5d51d..aed5679da651 100644
--- a/Documentation/features/core/tracehook/arch-support.txt
+++ b/Documentation/features/core/tracehook/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | ok |
| ia64: | ok |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/KASAN/arch-support.txt b/Documentation/features/debug/KASAN/arch-support.txt
index 2fd5fb6f5f23..bf0124fae643 100644
--- a/Documentation/features/debug/KASAN/arch-support.txt
+++ b/Documentation/features/debug/KASAN/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
@@ -25,7 +25,7 @@
| s390: | ok |
| sh: | TODO |
| sparc: | TODO |
- | um: | TODO |
+ | um: | ok |
| x86: | ok |
| xtensa: | ok |
-----------------------
diff --git a/Documentation/features/debug/debug-vm-pgtable/arch-support.txt b/Documentation/features/debug/debug-vm-pgtable/arch-support.txt
index c45711e55c7b..9ec5d13f4939 100644
--- a/Documentation/features/debug/debug-vm-pgtable/arch-support.txt
+++ b/Documentation/features/debug/debug-vm-pgtable/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/debug/gcov-profile-all/arch-support.txt b/Documentation/features/debug/gcov-profile-all/arch-support.txt
index 0b3ba2415fac..dc4014f7e1f8 100644
--- a/Documentation/features/debug/gcov-profile-all/arch-support.txt
+++ b/Documentation/features/debug/gcov-profile-all/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/debug/kcov/arch-support.txt b/Documentation/features/debug/kcov/arch-support.txt
index 0a91f5ce34a9..ffcc9f2b1d74 100644
--- a/Documentation/features/debug/kcov/arch-support.txt
+++ b/Documentation/features/debug/kcov/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/kgdb/arch-support.txt b/Documentation/features/debug/kgdb/arch-support.txt
index 04120d278c22..958498f9f2a4 100644
--- a/Documentation/features/debug/kgdb/arch-support.txt
+++ b/Documentation/features/debug/kgdb/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | ok |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/debug/kmemleak/arch-support.txt b/Documentation/features/debug/kmemleak/arch-support.txt
index e487c356ab20..0cfa5f0e4db1 100644
--- a/Documentation/features/debug/kmemleak/arch-support.txt
+++ b/Documentation/features/debug/kmemleak/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
index b3697f4c806e..bcc29d3aba9a 100644
--- a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
+++ b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/debug/kprobes/arch-support.txt b/Documentation/features/debug/kprobes/arch-support.txt
index 452385ac9e06..8a77d62a42c5 100644
--- a/Documentation/features/debug/kprobes/arch-support.txt
+++ b/Documentation/features/debug/kprobes/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | ok |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/kretprobes/arch-support.txt b/Documentation/features/debug/kretprobes/arch-support.txt
index daecf046e72b..cf4723c5ac55 100644
--- a/Documentation/features/debug/kretprobes/arch-support.txt
+++ b/Documentation/features/debug/kretprobes/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | ok |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/optprobes/arch-support.txt b/Documentation/features/debug/optprobes/arch-support.txt
index adb1bd055bfd..83a4639a5c0a 100644
--- a/Documentation/features/debug/optprobes/arch-support.txt
+++ b/Documentation/features/debug/optprobes/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/debug/stackprotector/arch-support.txt b/Documentation/features/debug/stackprotector/arch-support.txt
index ddcd7161d14c..71cd4ba18f7d 100644
--- a/Documentation/features/debug/stackprotector/arch-support.txt
+++ b/Documentation/features/debug/stackprotector/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt
index 25121200f9f9..d53f2f94fbda 100644
--- a/Documentation/features/debug/uprobes/arch-support.txt
+++ b/Documentation/features/debug/uprobes/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/debug/user-ret-profiler/arch-support.txt b/Documentation/features/debug/user-ret-profiler/arch-support.txt
index f2fcff8e77b7..059110a5fa6e 100644
--- a/Documentation/features/debug/user-ret-profiler/arch-support.txt
+++ b/Documentation/features/debug/user-ret-profiler/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/io/dma-contiguous/arch-support.txt b/Documentation/features/io/dma-contiguous/arch-support.txt
index 95e485c87e36..bfe0921a3853 100644
--- a/Documentation/features/io/dma-contiguous/arch-support.txt
+++ b/Documentation/features/io/dma-contiguous/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/locking/cmpxchg-local/arch-support.txt b/Documentation/features/locking/cmpxchg-local/arch-support.txt
index 8b1a8d9e1c79..68329e96dffa 100644
--- a/Documentation/features/locking/cmpxchg-local/arch-support.txt
+++ b/Documentation/features/locking/cmpxchg-local/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/locking/lockdep/arch-support.txt b/Documentation/features/locking/lockdep/arch-support.txt
index ab69e8f56a37..ddb945278589 100644
--- a/Documentation/features/locking/lockdep/arch-support.txt
+++ b/Documentation/features/locking/lockdep/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | ok |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/locking/queued-rwlocks/arch-support.txt b/Documentation/features/locking/queued-rwlocks/arch-support.txt
index 0bfb72a08d82..5deb845477e4 100644
--- a/Documentation/features/locking/queued-rwlocks/arch-support.txt
+++ b/Documentation/features/locking/queued-rwlocks/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt
index d2f2201febc8..2d3961bfef5d 100644
--- a/Documentation/features/locking/queued-spinlocks/arch-support.txt
+++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt
@@ -10,10 +10,10 @@
| arc: | TODO |
| arm: | TODO |
| arm64: | ok |
- | csky: | TODO |
+ | csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/perf/kprobes-event/arch-support.txt b/Documentation/features/perf/kprobes-event/arch-support.txt
index 0d0647b06762..641a7d2ff2a3 100644
--- a/Documentation/features/perf/kprobes-event/arch-support.txt
+++ b/Documentation/features/perf/kprobes-event/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | ok |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/perf/perf-regs/arch-support.txt b/Documentation/features/perf/perf-regs/arch-support.txt
index 13c297bbf05c..33866eb242c1 100644
--- a/Documentation/features/perf/perf-regs/arch-support.txt
+++ b/Documentation/features/perf/perf-regs/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/perf/perf-stackdump/arch-support.txt b/Documentation/features/perf/perf-stackdump/arch-support.txt
index 931687eec671..c8e4c7c65012 100644
--- a/Documentation/features/perf/perf-stackdump/arch-support.txt
+++ b/Documentation/features/perf/perf-stackdump/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt
index 336d728b8a45..1e51614c136e 100644
--- a/Documentation/features/sched/membarrier-sync-core/arch-support.txt
+++ b/Documentation/features/sched/membarrier-sync-core/arch-support.txt
@@ -36,7 +36,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/sched/numa-balancing/arch-support.txt b/Documentation/features/sched/numa-balancing/arch-support.txt
index 76d012118372..532cc67cdf92 100644
--- a/Documentation/features/sched/numa-balancing/arch-support.txt
+++ b/Documentation/features/sched/numa-balancing/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | .. |
| hexagon: | .. |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | .. |
| microblaze: | .. |
| mips: | TODO |
diff --git a/Documentation/features/scripts/features-refresh.sh b/Documentation/features/scripts/features-refresh.sh
index 9e72d38a0720..c2288124e94a 100755
--- a/Documentation/features/scripts/features-refresh.sh
+++ b/Documentation/features/scripts/features-refresh.sh
@@ -60,7 +60,7 @@ for F_FILE in Documentation/features/*/*/arch-support.txt; do
echo " | arch |status|" >> $T_FILE
echo " -----------------------" >> $T_FILE
for ARCH_DIR in arch/*/; do
- ARCH=$(echo $ARCH_DIR | sed -e 's/arch//g' | sed -e 's/\///g')
+ ARCH=$(echo $ARCH_DIR | sed -e 's/^arch//g' | sed -e 's/\///g')
K_FILES=$(find $ARCH_DIR -name "Kconfig*")
K_GREP=$(grep "$K" $K_FILES)
#
diff --git a/Documentation/features/seccomp/seccomp-filter/arch-support.txt b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
index a86b8b1f3d10..dc71bf7b1a7e 100644
--- a/Documentation/features/seccomp/seccomp-filter/arch-support.txt
+++ b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/time/arch-tick-broadcast/arch-support.txt b/Documentation/features/time/arch-tick-broadcast/arch-support.txt
index 364169f00ee2..9bffac80019e 100644
--- a/Documentation/features/time/arch-tick-broadcast/arch-support.txt
+++ b/Documentation/features/time/arch-tick-broadcast/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/time/clockevents/arch-support.txt b/Documentation/features/time/clockevents/arch-support.txt
index 6ea274790e47..625160048f68 100644
--- a/Documentation/features/time/clockevents/arch-support.txt
+++ b/Documentation/features/time/clockevents/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | ok |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | ok |
| mips: | ok |
diff --git a/Documentation/features/time/context-tracking/arch-support.txt b/Documentation/features/time/context-tracking/arch-support.txt
index e59071a49090..72bc5bad0348 100644
--- a/Documentation/features/time/context-tracking/arch-support.txt
+++ b/Documentation/features/time/context-tracking/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt
index fd17d8de5ef1..ceb036610d09 100644
--- a/Documentation/features/time/irq-time-acct/arch-support.txt
+++ b/Documentation/features/time/irq-time-acct/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | .. |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/time/virt-cpuacct/arch-support.txt b/Documentation/features/time/virt-cpuacct/arch-support.txt
index 1a859ac05e9e..c063dffd5261 100644
--- a/Documentation/features/time/virt-cpuacct/arch-support.txt
+++ b/Documentation/features/time/virt-cpuacct/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | ok |
| hexagon: | TODO |
| ia64: | ok |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/vm/ELF-ASLR/arch-support.txt b/Documentation/features/vm/ELF-ASLR/arch-support.txt
index b1229953391b..15164f36f224 100644
--- a/Documentation/features/vm/ELF-ASLR/arch-support.txt
+++ b/Documentation/features/vm/ELF-ASLR/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/vm/PG_uncached/arch-support.txt b/Documentation/features/vm/PG_uncached/arch-support.txt
index 02f325fbfcd0..5acd64b97dba 100644
--- a/Documentation/features/vm/PG_uncached/arch-support.txt
+++ b/Documentation/features/vm/PG_uncached/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | ok |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/vm/THP/arch-support.txt b/Documentation/features/vm/THP/arch-support.txt
index 9bfff977ef55..9dd7d75d0465 100644
--- a/Documentation/features/vm/THP/arch-support.txt
+++ b/Documentation/features/vm/THP/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | .. |
| hexagon: | .. |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | .. |
| microblaze: | .. |
| mips: | ok |
diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt
index 039e4e91ada3..7f049c251a79 100644
--- a/Documentation/features/vm/TLB/arch-support.txt
+++ b/Documentation/features/vm/TLB/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | .. |
| microblaze: | .. |
| mips: | TODO |
diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt
index 13b4940e0c3a..82b0be425775 100644
--- a/Documentation/features/vm/huge-vmap/arch-support.txt
+++ b/Documentation/features/vm/huge-vmap/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | TODO |
+ | loongarch: | TODO |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/features/vm/ioremap_prot/arch-support.txt b/Documentation/features/vm/ioremap_prot/arch-support.txt
index 6bd78eb4dc6e..a24149e59d73 100644
--- a/Documentation/features/vm/ioremap_prot/arch-support.txt
+++ b/Documentation/features/vm/ioremap_prot/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/features/vm/pte_special/arch-support.txt b/Documentation/features/vm/pte_special/arch-support.txt
index fc3687b5e89b..d2b22a06945e 100644
--- a/Documentation/features/vm/pte_special/arch-support.txt
+++ b/Documentation/features/vm/pte_special/arch-support.txt
@@ -13,7 +13,7 @@
| csky: | TODO |
| hexagon: | TODO |
| ia64: | TODO |
- | loong: | ok |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | ok |
diff --git a/Documentation/filesystems/configfs.rst b/Documentation/filesystems/configfs.rst
index 1d3d6f4a82a9..8c9342ed6d25 100644
--- a/Documentation/filesystems/configfs.rst
+++ b/Documentation/filesystems/configfs.rst
@@ -289,7 +289,6 @@ config_item_type::
const char *name);
struct config_group *(*make_group)(struct config_group *group,
const char *name);
- int (*commit_item)(struct config_item *item);
void (*disconnect_notify)(struct config_group *group,
struct config_item *item);
void (*drop_item)(struct config_group *group,
@@ -486,50 +485,3 @@ up. Here, the heartbeat code calls configfs_depend_item(). If it
succeeds, then heartbeat knows the region is safe to give to ocfs2.
If it fails, it was being torn down anyway, and heartbeat can gracefully
pass up an error.
-
-Committable Items
-=================
-
-Note:
- Committable items are currently unimplemented.
-
-Some config_items cannot have a valid initial state. That is, no
-default values can be specified for the item's attributes such that the
-item can do its work. Userspace must configure one or more attributes,
-after which the subsystem can start whatever entity this item
-represents.
-
-Consider the FakeNBD device from above. Without a target address *and*
-a target device, the subsystem has no idea what block device to import.
-The simple example assumes that the subsystem merely waits until all the
-appropriate attributes are configured, and then connects. This will,
-indeed, work, but now every attribute store must check if the attributes
-are initialized. Every attribute store must fire off the connection if
-that condition is met.
-
-Far better would be an explicit action notifying the subsystem that the
-config_item is ready to go. More importantly, an explicit action allows
-the subsystem to provide feedback as to whether the attributes are
-initialized in a way that makes sense. configfs provides this as
-committable items.
-
-configfs still uses only normal filesystem operations. An item is
-committed via rename(2). The item is moved from a directory where it
-can be modified to a directory where it cannot.
-
-Any group that provides the ct_group_ops->commit_item() method has
-committable items. When this group appears in configfs, mkdir(2) will
-not work directly in the group. Instead, the group will have two
-subdirectories: "live" and "pending". The "live" directory does not
-support mkdir(2) or rmdir(2) either. It only allows rename(2). The
-"pending" directory does allow mkdir(2) and rmdir(2). An item is
-created in the "pending" directory. Its attributes can be modified at
-will. Userspace commits the item by renaming it into the "live"
-directory. At this point, the subsystem receives the ->commit_item()
-callback. If all required attributes are filled to satisfaction, the
-method returns zero and the item is moved to the "live" directory.
-
-As rmdir(2) does not work in the "live" directory, an item must be
-shutdown, or "uncommitted". Again, this is done via rename(2), this
-time from the "live" directory back to the "pending" one. The subsystem
-is notified by the ct_group_ops->uncommit_object() method.
diff --git a/Documentation/filesystems/debugfs.rst b/Documentation/filesystems/debugfs.rst
index 71b1fee56d2a..dc35da8b8792 100644
--- a/Documentation/filesystems/debugfs.rst
+++ b/Documentation/filesystems/debugfs.rst
@@ -155,8 +155,8 @@ any code which does so in the mainline. Note that all files created with
debugfs_create_blob() are read-only.
If you want to dump a block of registers (something that happens quite
-often during development, even if little such code reaches mainline.
-Debugfs offers two functions: one to make a registers-only file, and
+often during development, even if little such code reaches mainline),
+debugfs offers two functions: one to make a registers-only file, and
another to insert a register block in the middle of another sequential
file::
@@ -183,7 +183,7 @@ The "base" argument may be 0, but you may want to build the reg32 array
using __stringify, and a number of register names (macros) are actually
byte offsets over a base for the register block.
-If you want to dump an u32 array in debugfs, you can create file with::
+If you want to dump a u32 array in debugfs, you can create a file with::
struct debugfs_u32_array {
u32 *array;
@@ -197,7 +197,7 @@ If you want to dump an u32 array in debugfs, you can create file with::
The "array" argument wraps a pointer to the array's data and the number
of its elements. Note: Once array is created its size can not be changed.
-There is a helper function to create device related seq_file::
+There is a helper function to create a device-related seq_file::
void debugfs_create_devm_seqfile(struct device *dev,
const char *name,
diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst
index 05e03d54af1a..067fd1670b1f 100644
--- a/Documentation/filesystems/erofs.rst
+++ b/Documentation/filesystems/erofs.rst
@@ -30,12 +30,18 @@ It is implemented to be a better choice for the following scenarios:
especially for those embedded devices with limited memory and high-density
hosts with numerous containers.
-Here is the main features of EROFS:
+Here are the main features of EROFS:
- Little endian on-disk design;
- - 4KiB block size and 32-bit block addresses, therefore 16TiB address space
- at most for now;
+ - Block-based distribution and file-based distribution over fscache are
+ supported;
+
+ - Support multiple devices to refer to external blobs, which can be used
+ for container images;
+
+ - 4KiB block size and 32-bit block addresses for each device, therefore
+ 16TiB address space at most for now;
- Two inode layouts for different requirements:
@@ -50,28 +56,31 @@ Here is the main features of EROFS:
Metadata reserved 8 bytes 18 bytes
===================== ============ ======================================
- - Metadata and data could be mixed as an option;
-
- - Support extended attributes (xattrs) as an option;
+ - Support extended attributes as an option;
- - Support tailpacking data and xattr inline compared to byte-addressed
- unaligned metadata or smaller block size alternatives;
-
- - Support POSIX.1e ACLs by using xattrs;
+ - Support POSIX.1e ACLs by using extended attributes;
- Support transparent data compression as an option:
LZ4 and MicroLZMA algorithms can be used on a per-file basis; In addition,
inplace decompression is also supported to avoid bounce compressed buffers
and page cache thrashing.
+ - Support chunk-based data deduplication and rolling-hash compressed data
+ deduplication;
+
+ - Support tailpacking inline compared to byte-addressed unaligned metadata
+ or smaller block size alternatives;
+
+ - Support merging tail-end data into a special inode as fragments.
+
+ - Support large folios for uncompressed files.
+
- Support direct I/O on uncompressed files to avoid double caching for loop
devices;
- Support FSDAX on uncompressed images for secure containers and ramdisks in
order to get rid of unnecessary page cache.
- - Support multiple devices for multi blob container images;
-
- Support file-based on-demand loading with the Fscache infrastructure.
The following git tree provides the file system user-space tools under
@@ -259,7 +268,7 @@ By the way, chunk-based files are all uncompressed for now.
Data compression
----------------
-EROFS implements LZ4 fixed-sized output compression which generates fixed-sized
+EROFS implements fixed-sized output compression which generates fixed-sized
compressed data blocks from variable-sized input in contrast to other existing
fixed-sized input solutions. Relatively higher compression ratios can be gotten
by using fixed-sized output compression since nowadays popular data compression
@@ -314,3 +323,6 @@ to understand its delta0 is constantly 1, as illustrated below::
If another HEAD follows a HEAD lcluster, there is no room to record CBLKCNT,
but it's easy to know the size of such pcluster is 1 lcluster as well.
+
+Since Linux v6.1, each pcluster can be used for multiple variable-sized extents,
+therefore it can be used for compressed data deduplication.
diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index 5ba5817c17c2..ef183387da20 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -338,6 +338,7 @@ Currently, the following pairs of encryption modes are supported:
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
- Adiantum for both contents and filenames
- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only)
+- SM4-XTS for contents and SM4-CTS-CBC for filenames (v2 policies only)
If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
@@ -369,6 +370,12 @@ CONFIG_CRYPTO_HCTR2 must be enabled. Also, fast implementations of XCTR and
POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and
CRYPTO_AES_ARM64_CE_BLK for ARM64.
+SM4 is a Chinese block cipher that is an alternative to AES. It has
+not seen as much security review as AES, and it only has a 128-bit key
+size. It may be useful in cases where its use is mandated.
+Otherwise, it should not be used. For SM4 support to be available, it
+also needs to be enabled in the kernel crypto API.
+
New encryption modes can be added relatively easily, without changes
to individual filesystems. However, authenticated encryption (AE)
modes are not currently supported because of the difficulty of dealing
diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst
index 8f737e76935c..36fa2a83d714 100644
--- a/Documentation/filesystems/locking.rst
+++ b/Documentation/filesystems/locking.rst
@@ -70,7 +70,7 @@ prototypes::
const char *(*get_link) (struct dentry *, struct inode *, struct delayed_call *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
- struct posix_acl * (*get_acl)(struct inode *, int, bool);
+ struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
@@ -84,13 +84,14 @@ prototypes::
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
+ struct posix_acl * (*get_acl)(struct user_namespace *, struct dentry *, int);
locking rules:
all may block
-============= =============================================
+============== =============================================
ops i_rwsem(inode)
-============= =============================================
+============== =============================================
lookup: shared
create: exclusive
link: exclusive (both)
@@ -104,6 +105,7 @@ readlink: no
get_link: no
setattr: exclusive
permission: no (may not block if called in rcu-walk mode)
+get_inode_acl: no
get_acl: no
getattr: no
listxattr: no
@@ -113,7 +115,7 @@ atomic_open: shared (exclusive if O_CREAT is set in open flags)
tmpfile: no
fileattr_get: no or exclusive
fileattr_set: exclusive
-============= =============================================
+============== =============================================
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem
diff --git a/Documentation/filesystems/mount_api.rst b/Documentation/filesystems/mount_api.rst
index eb358a00be27..63204d2094fd 100644
--- a/Documentation/filesystems/mount_api.rst
+++ b/Documentation/filesystems/mount_api.rst
@@ -562,17 +562,6 @@ or looking up of superblocks.
The following helpers all wrap sget_fc():
- * ::
-
- int vfs_get_super(struct fs_context *fc,
- enum vfs_get_super_keying keying,
- int (*fill_super)(struct super_block *sb,
- struct fs_context *fc))
-
- This creates/looks up a deviceless superblock. The keying indicates how
- many superblocks of this type may exist and in what manner they may be
- shared:
-
(1) vfs_get_single_super
Only one such superblock may exist in the system. Any further
@@ -814,6 +803,7 @@ process the parameters it is given.
int fs_lookup_param(struct fs_context *fc,
struct fs_parameter *value,
bool want_bdev,
+ unsigned int flags,
struct path *_path);
This takes a parameter that carries a string or filename type and attempts
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index df0dc37e6f58..d2d684ae7798 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -462,8 +462,8 @@ ERR_PTR(...).
argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask.
generic_permission() has also lost the check_acl argument; ACL checking
-has been taken to VFS and filesystems need to provide a non-NULL ->i_op->get_acl
-to read an ACL from disk.
+has been taken to VFS and filesystems need to provide a non-NULL
+->i_op->get_inode_acl to read an ACL from disk.
---
diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
index 898c99eae8e4..f4ee84d7b351 100644
--- a/Documentation/filesystems/proc.rst
+++ b/Documentation/filesystems/proc.rst
@@ -47,6 +47,7 @@ fixes/update part 1.1 Stefani Seibold <stefani@seibold.net> June 9 2009
3.10 /proc/<pid>/timerslack_ns - Task timerslack value
3.11 /proc/<pid>/patch_state - Livepatch patch operation state
3.12 /proc/<pid>/arch_status - Task architecture specific information
+ 3.13 /proc/<pid>/fd - List of symlinks to open files
4 Configuring procfs
4.1 Mount options
@@ -245,7 +246,8 @@ It's slow but very precise.
Ngid NUMA group ID (0 if none)
Pid process id
PPid process id of the parent process
- TracerPid PID of process tracing this process (0 if not)
+ TracerPid PID of process tracing this process (0 if not, or
+ the tracer is outside of the current pid namespace)
Uid Real, effective, saved set, and file system UIDs
Gid Real, effective, saved set, and file system GIDs
FDSize number of file descriptor slots currently allocated
@@ -2149,6 +2151,22 @@ AVX512_elapsed_ms
the task is unlikely an AVX512 user, but depends on the workload and the
scheduling scenario, it also could be a false negative mentioned above.
+3.13 /proc/<pid>/fd - List of symlinks to open files
+-------------------------------------------------------
+This directory contains symbolic links which represent open files
+the process is maintaining. Example output::
+
+ lr-x------ 1 root root 64 Sep 20 17:53 0 -> /dev/null
+ l-wx------ 1 root root 64 Sep 20 17:53 1 -> /dev/null
+ lrwx------ 1 root root 64 Sep 20 17:53 10 -> 'socket:[12539]'
+ lrwx------ 1 root root 64 Sep 20 17:53 11 -> 'socket:[12540]'
+ lrwx------ 1 root root 64 Sep 20 17:53 12 -> 'socket:[12542]'
+
+The number of open files for the process is stored in 'size' member
+of stat() output for /proc/<pid>/fd for fast access.
+-------------------------------------------------------
+
+
Chapter 4: Configuring procfs
=============================
diff --git a/Documentation/filesystems/sysfs.rst b/Documentation/filesystems/sysfs.rst
index 8bba676b1365..f8187d466b97 100644
--- a/Documentation/filesystems/sysfs.rst
+++ b/Documentation/filesystems/sysfs.rst
@@ -12,10 +12,10 @@ Mike Murphy <mamurph@cs.clemson.edu>
:Original: 10 January 2003
-What it is:
-~~~~~~~~~~~
+What it is
+~~~~~~~~~~
-sysfs is a ram-based filesystem initially based on ramfs. It provides
+sysfs is a RAM-based filesystem initially based on ramfs. It provides
a means to export kernel data structures, their attributes, and the
linkages between them to userspace.
@@ -43,7 +43,7 @@ userspace. Top-level directories in sysfs represent the common
ancestors of object hierarchies; i.e. the subsystems the objects
belong to.
-Sysfs internally stores a pointer to the kobject that implements a
+sysfs internally stores a pointer to the kobject that implements a
directory in the kernfs_node object associated with the directory. In
the past this kobject pointer has been used by sysfs to do reference
counting directly on the kobject whenever the file is opened or closed.
@@ -55,7 +55,7 @@ Attributes
~~~~~~~~~~
Attributes can be exported for kobjects in the form of regular files in
-the filesystem. Sysfs forwards file I/O operations to methods defined
+the filesystem. sysfs forwards file I/O operations to methods defined
for the attributes, providing a means to read and write kernel
attributes.
@@ -72,8 +72,8 @@ you publicly humiliated and your code rewritten without notice.
An attribute definition is simply::
struct attribute {
- char * name;
- struct module *owner;
+ char *name;
+ struct module *owner;
umode_t mode;
};
@@ -138,7 +138,7 @@ __ATTR_WO(name):
assumes a name_store only and is restricted to mode
0200 that is root write access only.
__ATTR_RO_MODE(name, mode):
- fore more restrictive RO access currently
+ for more restrictive RO access; currently
only use case is the EFI System Resource Table
(see drivers/firmware/efi/esrt.c)
__ATTR_RW(name):
@@ -207,7 +207,7 @@ IOW, they should take only an object, an attribute, and a buffer as parameters.
sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the
-method. Sysfs will call the method exactly once for each read or
+method. sysfs will call the method exactly once for each read or
write. This forces the following behavior on the method
implementations:
@@ -221,7 +221,7 @@ implementations:
be called again, rearmed, to fill the buffer.
- On write(2), sysfs expects the entire buffer to be passed during the
- first write. Sysfs then passes the entire buffer to the store() method.
+ first write. sysfs then passes the entire buffer to the store() method.
A terminating null is added after the data on stores. This makes
functions like sysfs_streq() safe to use.
@@ -237,7 +237,7 @@ Other notes:
- Writing causes the show() method to be rearmed regardless of current
file position.
-- The buffer will always be PAGE_SIZE bytes in length. On i386, this
+- The buffer will always be PAGE_SIZE bytes in length. On x86, this
is 4096.
- show() methods should return the number of bytes printed into the
@@ -253,7 +253,7 @@ Other notes:
through, be sure to return an error.
- The object passed to the methods will be pinned in memory via sysfs
- referencing counting its embedded object. However, the physical
+ reference counting its embedded object. However, the physical
entity (e.g. device) the object represents may not be present. Be
sure to have a way to check this, if necessary.
@@ -295,8 +295,12 @@ The top level sysfs directory looks like::
dev/
devices/
firmware/
- net/
fs/
+ hypervisor/
+ kernel/
+ module/
+ net/
+ power/
devices/ contains a filesystem representation of the device tree. It maps
directly to the internal kernel device tree, which is a hierarchy of
@@ -317,15 +321,18 @@ span multiple bus types).
fs/ contains a directory for some filesystems. Currently each
filesystem wanting to export attributes must create its own hierarchy
-below fs/ (see ./fuse.txt for an example).
+below fs/ (see ./fuse.rst for an example).
+
+module/ contains parameter values and state information for all
+loaded system modules, for both builtin and loadable modules.
-dev/ contains two directories char/ and block/. Inside these two
+dev/ contains two directories: char/ and block/. Inside these two
directories there are symlinks named <major>:<minor>. These symlinks
point to the sysfs directory for the given device. /sys/dev provides a
quick way to lookup the sysfs interface for a device from the result of
a stat(2) operation.
-More information can driver-model specific features can be found in
+More information on driver-model specific features can be found in
Documentation/driver-api/driver-model/.
@@ -335,7 +342,7 @@ TODO: Finish this section.
Current Interfaces
~~~~~~~~~~~~~~~~~~
-The following interface layers currently exist in sysfs:
+The following interface layers currently exist in sysfs.
devices (include/linux/device.h)
diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst
index 2b55f71e2ae1..2c15e7053113 100644
--- a/Documentation/filesystems/vfs.rst
+++ b/Documentation/filesystems/vfs.rst
@@ -435,7 +435,7 @@ As of kernel 2.6.22, the following members are defined:
const char *(*get_link) (struct dentry *, struct inode *,
struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
- struct posix_acl * (*get_acl)(struct inode *, int, bool);
+ struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*setattr) (struct user_namespace *, struct dentry *, struct iattr *);
int (*getattr) (struct user_namespace *, const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
@@ -443,7 +443,8 @@ As of kernel 2.6.22, the following members are defined:
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *, struct file *, umode_t);
- int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int);
+ struct posix_acl * (*get_acl)(struct user_namespace *, struct dentry *, int);
+ int (*set_acl)(struct user_namespace *, struct dentry *, struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
diff --git a/Documentation/gpu/amdgpu/amdgpu-glossary.rst b/Documentation/gpu/amdgpu/amdgpu-glossary.rst
index 326896e9800d..00a47ebb0b0f 100644
--- a/Documentation/gpu/amdgpu/amdgpu-glossary.rst
+++ b/Documentation/gpu/amdgpu/amdgpu-glossary.rst
@@ -30,12 +30,35 @@ we have a dedicated glossary for Display Core at
EOP
End Of Pipe/Pipeline
+ GART
+ Graphics Address Remapping Table. This is the name we use for the GPUVM
+ page table used by the GPU kernel driver. It remaps system resources
+ (memory or MMIO space) into the GPU's address space so the GPU can access
+ them. The name GART harkens back to the days of AGP when the platform
+ provided an MMU that the GPU could use to get a contiguous view of
+ scattered pages for DMA. The MMU has since moved on to the GPU, but the
+ name stuck.
+
GC
Graphics and Compute
GMC
Graphic Memory Controller
+ GPUVM
+ GPU Virtual Memory. This is the GPU's MMU. The GPU supports multiple
+ virtual address spaces that can be in flight at any given time. These
+ allow the GPU to remap VRAM and system resources into GPU virtual address
+ spaces for use by the GPU kernel driver and applications using the GPU.
+ These provide memory protection for different applications using the GPU.
+
+ GTT
+ Graphics Translation Tables. This is a memory pool managed through TTM
+ which provides access to system resources (memory or MMIO space) for
+ use by the GPU. These addresses can be mapped into the "GART" GPUVM page
+ table for use by the kernel driver or into per process GPUVM page tables
+ for application usage.
+
IH
Interrupt Handler
diff --git a/Documentation/gpu/amdgpu/driver-core.rst b/Documentation/gpu/amdgpu/driver-core.rst
index ebf5932845a9..467e6843aef6 100644
--- a/Documentation/gpu/amdgpu/driver-core.rst
+++ b/Documentation/gpu/amdgpu/driver-core.rst
@@ -148,10 +148,10 @@ PRIME Buffer Sharing
MMU Notifier
============
-.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
+.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
:doc: MMU Notifier
-.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
+.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
:internal:
AMDGPU Virtual Memory
diff --git a/Documentation/gpu/amdgpu/index.rst b/Documentation/gpu/amdgpu/index.rst
index a24e1cfa7407..03c2966cae79 100644
--- a/Documentation/gpu/amdgpu/index.rst
+++ b/Documentation/gpu/amdgpu/index.rst
@@ -3,7 +3,7 @@
==========================
The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core
-Next (GCN) architecture.
+Next (GCN), Radeon DNA (RDNA), and Compute DNA (CDNA) architectures.
.. toctree::
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index dbc85fd7a971..a4860ffd6e86 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -116,6 +116,9 @@ fbdev Helper Functions Reference
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
:export:
+.. kernel-doc:: drivers/gpu/drm/drm_fbdev_generic.c
+ :export:
+
format Helper Functions Reference
=================================
diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst
index 92c5117368d7..b46327356e80 100644
--- a/Documentation/gpu/drm-usage-stats.rst
+++ b/Documentation/gpu/drm-usage-stats.rst
@@ -126,7 +126,6 @@ percentage utilization of the engine, whereas drm-engine-<str> only reflects
time active without considering what frequency the engine is operating as a
percentage of it's maximum frequency.
-===============================
Driver specific implementations
===============================
diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
index 4e59db1cfb00..60ea21734902 100644
--- a/Documentation/gpu/i915.rst
+++ b/Documentation/gpu/i915.rst
@@ -494,7 +494,7 @@ WOPCM
WOPCM Layout
~~~~~~~~~~~~
-.. kernel-doc:: drivers/gpu/drm/i915/intel_wopcm.c
+.. kernel-doc:: drivers/gpu/drm/i915/gt/intel_wopcm.c
:doc: WOPCM Layout
GuC
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 393d218e4a0c..b2c6aaf1edf2 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks.
Contact: Harry Wentland, Alex Deucher
-vmwgfx: Replace hashtable with Linux' implementation
-----------------------------------------------------
-
-The vmwgfx driver uses its own hashtable implementation. Replace the
-code with Linux' implementation and update the callers. It's mostly a
-refactoring task, but the interfaces are different.
-
-Contact: Zack Rusin, Thomas Zimmermann <tzimmermann@suse.de>
-
-Level: Intermediate
-
Bootsplash
==========
diff --git a/Documentation/ia64/aliasing.rst b/Documentation/ia64/aliasing.rst
index a08b36aba015..36a1e1d4842b 100644
--- a/Documentation/ia64/aliasing.rst
+++ b/Documentation/ia64/aliasing.rst
@@ -61,7 +61,7 @@ Memory Map
The efi_memmap table is preserved unmodified because the original
boot-time information is required for kexec.
-Kernel Identify Mappings
+Kernel Identity Mappings
========================
Linux/ia64 identity mappings are done with large pages, currently
diff --git a/Documentation/kernel-hacking/locking.rst b/Documentation/kernel-hacking/locking.rst
index 6805ae6e86e6..c756786e17ae 100644
--- a/Documentation/kernel-hacking/locking.rst
+++ b/Documentation/kernel-hacking/locking.rst
@@ -967,7 +967,7 @@ you might do the following::
while (list) {
struct foo *next = list->next;
- del_timer(&list->timer);
+ timer_delete(&list->timer);
kfree(list);
list = next;
}
@@ -981,7 +981,7 @@ the lock after we spin_unlock_bh(), and then try to free
the element (which has already been freed!).
This can be avoided by checking the result of
-del_timer(): if it returns 1, the timer has been deleted.
+timer_delete(): if it returns 1, the timer has been deleted.
If 0, it means (in this case) that it is currently running, so we can
do::
@@ -990,7 +990,7 @@ do::
while (list) {
struct foo *next = list->next;
- if (!del_timer(&list->timer)) {
+ if (!timer_delete(&list->timer)) {
/* Give timer a chance to delete this */
spin_unlock_bh(&list_lock);
goto retry;
@@ -1005,9 +1005,12 @@ do::
Another common problem is deleting timers which restart themselves (by
calling add_timer() at the end of their timer function).
Because this is a fairly common case which is prone to races, you should
-use del_timer_sync() (``include/linux/timer.h``) to
-handle this case. It returns the number of times the timer had to be
-deleted before we finally stopped it from adding itself back in.
+use timer_delete_sync() (``include/linux/timer.h``) to handle this case.
+
+Before freeing a timer, timer_shutdown() or timer_shutdown_sync() should be
+called which will keep it from being rearmed. Any subsequent attempt to
+rearm the timer will be silently ignored by the core code.
+
Locking Speed
=============
@@ -1335,7 +1338,7 @@ lock.
- kfree()
-- add_timer() and del_timer()
+- add_timer() and timer_delete()
Mutex API reference
===================
diff --git a/Documentation/loongarch/booting.rst b/Documentation/loongarch/booting.rst
new file mode 100644
index 000000000000..91eccd410478
--- /dev/null
+++ b/Documentation/loongarch/booting.rst
@@ -0,0 +1,42 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================
+Booting Linux/LoongArch
+=======================
+
+:Author: Yanteng Si <siyanteng@loongson.cn>
+:Date: 18 Nov 2022
+
+Information passed from BootLoader to kernel
+============================================
+
+LoongArch supports ACPI and FDT. The information that needs to be passed
+to the kernel includes the memmap, the initrd, the command line, optionally
+the ACPI/FDT tables, and so on.
+
+The kernel is passed the following arguments on `kernel_entry` :
+
+ - a0 = efi_boot: `efi_boot` is a flag indicating whether
+ this boot environment is fully UEFI-compliant.
+
+ - a1 = cmdline: `cmdline` is a pointer to the kernel command line.
+
+ - a2 = systemtable: `systemtable` points to the EFI system table.
+ All pointers involved at this stage are in physical addresses.
+
+Header of Linux/LoongArch kernel images
+=======================================
+
+Linux/LoongArch kernel images are EFI images. Being PE files, they have
+a 64-byte header structured like::
+
+ u32 MZ_MAGIC /* "MZ", MS-DOS header */
+ u32 res0 = 0 /* Reserved */
+ u64 kernel_entry /* Kernel entry point */
+ u64 _end - _text /* Kernel image effective size */
+ u64 load_offset /* Kernel image load offset from start of RAM */
+ u64 res1 = 0 /* Reserved */
+ u64 res2 = 0 /* Reserved */
+ u64 res3 = 0 /* Reserved */
+ u32 LINUX_PE_MAGIC /* Magic number */
+ u32 pe_header - _head /* Offset to the PE header */
diff --git a/Documentation/loongarch/index.rst b/Documentation/loongarch/index.rst
index aaba648db907..c779bfa00c05 100644
--- a/Documentation/loongarch/index.rst
+++ b/Documentation/loongarch/index.rst
@@ -9,6 +9,7 @@ LoongArch Architecture
:numbered:
introduction
+ booting
irq-chip-model
features
diff --git a/Documentation/loongarch/introduction.rst b/Documentation/loongarch/introduction.rst
index 6c9160c4e9be..49135d451ced 100644
--- a/Documentation/loongarch/introduction.rst
+++ b/Documentation/loongarch/introduction.rst
@@ -375,15 +375,15 @@ Developer web site of Loongson and LoongArch (Software and Documentation):
Documentation of LoongArch ISA:
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.00-CN.pdf (in Chinese)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (in Chinese)
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.00-EN.pdf (in English)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (in English)
Documentation of LoongArch ELF psABI:
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v1.00-CN.pdf (in Chinese)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-CN.pdf (in Chinese)
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v1.00-EN.pdf (in English)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-EN.pdf (in English)
Linux kernel repository of Loongson and LoongArch:
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 06f80e3785c5..cc621decd943 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -1966,7 +1966,7 @@ There are some more advanced barrier functions:
(*) io_stop_wc();
For memory accesses with write-combining attributes (e.g. those returned
- by ioremap_wc(), the CPU may wait for prior accesses to be merged with
+ by ioremap_wc()), the CPU may wait for prior accesses to be merged with
subsequent ones. io_stop_wc() can be used to prevent the merging of
write-combining memory accesses before this macro with those after it when
such wait has performance implications.
diff --git a/Documentation/mm/slub.rst b/Documentation/mm/slub.rst
index 4e1578186b4f..7f652216dabe 100644
--- a/Documentation/mm/slub.rst
+++ b/Documentation/mm/slub.rst
@@ -116,6 +116,8 @@ options from the ``slub_debug`` parameter translate to the following files::
T trace
A failslab
+failslab file is writable, so writing 1 or 0 will enable or disable
+the option at runtime. Write returns -EINVAL if cache is an alias.
Careful with tracing: It may spew out lots of information and never stop if
used on the wrong slab.
diff --git a/Documentation/networking/generic_netlink.rst b/Documentation/networking/generic_netlink.rst
index 59e04ccf80c1..d960dbd7e80e 100644
--- a/Documentation/networking/generic_netlink.rst
+++ b/Documentation/networking/generic_netlink.rst
@@ -6,4 +6,4 @@ Generic Netlink
A wiki document on how to use Generic Netlink can be found here:
- * http://www.linuxfoundation.org/collaborate/workgroups/networking/generic_netlink_howto
+ * https://wiki.linuxfoundation.org/networking/generic_netlink_howto
diff --git a/Documentation/process/code-of-conduct-interpretation.rst b/Documentation/process/code-of-conduct-interpretation.rst
index 922e0b547bc3..66b07f14714c 100644
--- a/Documentation/process/code-of-conduct-interpretation.rst
+++ b/Documentation/process/code-of-conduct-interpretation.rst
@@ -51,7 +51,7 @@ the Technical Advisory Board (TAB) or other maintainers if you're
uncertain how to handle situations that come up. It will not be
considered a violation report unless you want it to be. If you are
uncertain about approaching the TAB or any other maintainers, please
-reach out to our conflict mediator, Joanna Lee <joanna.lee@gesmer.com>.
+reach out to our conflict mediator, Joanna Lee <jlee@linuxfoundation.org>.
In the end, "be kind to each other" is really what the end goal is for
everybody. We know everyone is human and we all fail at times, but the
diff --git a/Documentation/process/kernel-docs.rst b/Documentation/process/kernel-docs.rst
index 306ad373a002..1c6e2ab92f4e 100644
--- a/Documentation/process/kernel-docs.rst
+++ b/Documentation/process/kernel-docs.rst
@@ -3,9 +3,6 @@
Index of Further Kernel Documentation
=====================================
-Initial Author: Juan-Mariano de Goyeneche (<jmseyas@dit.upm.es>;
-email address is defunct now.)
-
The need for a document like this one became apparent in the
linux-kernel mailing list as the same questions, asking for pointers
to information, appeared again and again.
@@ -31,7 +28,9 @@ All documents are cataloged with the following fields: the document's
.. note::
The documents on each section of this document are ordered by its
- published date, from the newest to the oldest.
+ published date, from the newest to the oldest. The maintainer(s) should
+ periodically retire resources as they become obsolte or outdated; with
+ the exception of foundational books.
Docs at the Linux Kernel tree
-----------------------------
@@ -61,24 +60,6 @@ On-line docs
a brief description of some of the acronyms and terms you may hear
during discussion of the Linux kernel".
- * Title: **Tracing the Way of Data in a TCP Connection through the Linux Kernel**
-
- :Author: Richard Sailer
- :URL: https://archive.org/details/linux_kernel_data_flow_short_paper
- :Date: 2016
- :Keywords: Linux Kernel Networking, TCP, tracing, ftrace
- :Description: A seminar paper explaining ftrace and how to use it for
- understanding linux kernel internals,
- illustrated at tracing the way of a TCP packet through the kernel.
- :Abstract: *This short paper outlines the usage of ftrace a tracing framework
- as a tool to understand a running Linux system.
- Having obtained a trace-log a kernel hacker can read and understand
- source code more determined and with context.
- In a detailed example this approach is demonstrated in tracing
- and the way of data in a TCP Connection through the kernel.
- Finally this trace-log is used as base for more a exact conceptual
- exploration and description of the Linux TCP/IP implementation.*
-
* Title: **The Linux Kernel Module Programming Guide**
:Author: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
@@ -91,379 +72,16 @@ On-line docs
programming. Lots of examples. Currently the new version is being
actively maintained at https://github.com/sysprog21/lkmpg.
- * Title: **On submitting kernel Patches**
-
- :Author: Andi Kleen
- :URL: http://halobates.de/on-submitting-kernel-patches.pdf
- :Date: 2008
- :Keywords: patches, review process, types of submissions, basic rules, case studies
- :Description: This paper gives several experience values on what types of patches
- there are and how likely they get merged.
- :Abstract:
- [...]. This paper examines some common problems for
- submitting larger changes and some strategies to avoid problems.
-
- * Title: **Linux Device Drivers, Third Edition**
-
- :Author: Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman
- :URL: https://lwn.net/Kernel/LDD3/
- :Date: 2005
- :Description: A 600-page book covering the (2.6.10) driver
- programming API and kernel hacking in general. Available under the
- Creative Commons Attribution-ShareAlike 2.0 license.
- :note: You can also :ref:`purchase a copy from O'Reilly or elsewhere <ldd3_published>`.
-
- * Title: **Writing an ALSA Driver**
-
- :Author: Takashi Iwai <tiwai@suse.de>
- :URL: https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
- :Date: 2005
- :Keywords: ALSA, sound, soundcard, driver, lowlevel, hardware.
- :Description: Advanced Linux Sound Architecture for developers,
- both at kernel and user-level sides. ALSA is the Linux kernel
- sound architecture in the 2.6 kernel version.
-
- * Title: **Linux PCMCIA Programmer's Guide**
-
- :Author: David Hinds.
- :URL: http://pcmcia-cs.sourceforge.net/ftp/doc/PCMCIA-PROG.html
- :Date: 2003
- :Keywords: PCMCIA.
- :Description: "This document describes how to write kernel device
- drivers for the Linux PCMCIA Card Services interface. It also
- describes how to write user-mode utilities for communicating with
- Card Services.
-
- * Title: **How NOT to write kernel drivers**
-
- :Author: Arjan van de Ven.
- :URL: https://landley.net/kdocs/ols/2002/ols2002-pages-545-555.pdf
- :Date: 2002
- :Keywords: driver.
- :Description: Programming bugs and Do-nots in kernel driver development
- :Abstract: *Quit a few tutorials, articles and books give an introduction
- on how to write Linux kernel drivers. Unfortunately the things one
- should NOT do in Linux kernel code is either only a minor appendix
- or, more commonly, completely absent. This paper tries to briefly touch
- the areas in which the most common and serious bugs and do-nots are
- encountered.*
-
- * Title: **Global spinlock list and usage**
-
- :Author: Rick Lindsley.
- :URL: http://lse.sourceforge.net/lockhier/global-spin-lock
- :Date: 2001
- :Keywords: spinlock.
- :Description: This is an attempt to document both the existence and
- usage of the spinlocks in the Linux 2.4.5 kernel. Comprehensive
- list of spinlocks showing when they are used, which functions
- access them, how each lock is acquired, under what conditions it
- is held, whether interrupts can occur or not while it is held...
-
- * Title: **A Linux vm README**
-
- :Author: Kanoj Sarcar.
- :URL: http://kos.enix.org/pub/linux-vmm.html
- :Date: 2001
- :Keywords: virtual memory, mm, pgd, vma, page, page flags, page
- cache, swap cache, kswapd.
- :Description: Telegraphic, short descriptions and definitions
- relating the Linux virtual memory implementation.
-
- * Title: **Video4linux Drivers, Part 1: Video-Capture Device**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/406
- :Date: 2000
- :Keywords: video4linux, driver, video capture, capture devices,
- camera driver.
- :Description: The title says it all.
-
- * Title: **Video4linux Drivers, Part 2: Video-capture Devices**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/429
- :Date: 2000
- :Keywords: video4linux, driver, video capture, capture devices,
- camera driver, control, query capabilities, capability, facility.
- :Description: The title says it all.
-
- * Title: **Linux IP Networking. A Guide to the Implementation and Modification of the Linux Protocol Stack.**
-
- :Author: Glenn Herrin.
- :URL: http://www.cs.unh.edu/cnrg/gherrin
- :Date: 2000
- :Keywords: network, networking, protocol, IP, UDP, TCP, connection,
- socket, receiving, transmitting, forwarding, routing, packets,
- modules, /proc, sk_buff, FIB, tags.
- :Description: Excellent paper devoted to the Linux IP Networking,
- explaining anything from the kernel's to the user space
- configuration tools' code. Very good to get a general overview of
- the kernel networking implementation and understand all steps
- packets follow from the time they are received at the network
- device till they are delivered to applications. The studied kernel
- code is from 2.2.14 version. Provides code for a working packet
- dropper example.
-
- * Title: **How To Make Sure Your Driver Will Work On The Power Macintosh**
-
- :Author: Paul Mackerras.
- :URL: http://www.linux-mag.com/id/261
- :Date: 1999
- :Keywords: Mac, Power Macintosh, porting, drivers, compatibility.
- :Description: The title says it all.
-
- * Title: **An Introduction to SCSI Drivers**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/284
- :Date: 1999
- :Keywords: SCSI, device, driver.
- :Description: The title says it all.
-
- * Title: **Advanced SCSI Drivers And Other Tales**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/307
- :Date: 1999
- :Keywords: SCSI, device, driver, advanced.
- :Description: The title says it all.
-
- * Title: **Writing Linux Mouse Drivers**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/330
- :Date: 1999
- :Keywords: mouse, driver, gpm.
- :Description: The title says it all.
-
- * Title: **More on Mouse Drivers**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/356
- :Date: 1999
- :Keywords: mouse, driver, gpm, races, asynchronous I/O.
- :Description: The title still says it all.
-
- * Title: **Writing Video4linux Radio Driver**
-
- :Author: Alan Cox.
- :URL: http://www.linux-mag.com/id/381
- :Date: 1999
- :Keywords: video4linux, driver, radio, radio devices.
- :Description: The title says it all.
-
- * Title: **I/O Event Handling Under Linux**
-
- :Author: Richard Gooch.
- :URL: https://web.mit.edu/~yandros/doc/io-events.html
- :Date: 1999
- :Keywords: IO, I/O, select(2), poll(2), FDs, aio_read(2), readiness
- event queues.
- :Description: From the Introduction: "I/O Event handling is about
- how your Operating System allows you to manage a large number of
- open files (file descriptors in UNIX/POSIX, or FDs) in your
- application. You want the OS to notify you when FDs become active
- (have data ready to be read or are ready for writing). Ideally you
- want a mechanism that is scalable. This means a large number of
- inactive FDs cost very little in memory and CPU time to manage".
-
- * Title: **(nearly) Complete Linux Loadable Kernel Modules. The definitive guide for hackers, virus coders and system administrators.**
-
- :Author: pragmatic/THC.
- :URL: http://packetstormsecurity.org/docs/hack/LKM_HACKING.html
- :Date: 1999
- :Keywords: syscalls, intercept, hide, abuse, symbol table.
- :Description: Interesting paper on how to abuse the Linux kernel in
- order to intercept and modify syscalls, make
- files/directories/processes invisible, become root, hijack ttys,
- write kernel modules based virus... and solutions for admins to
- avoid all those abuses.
- :Notes: For 2.0.x kernels. Gives guidances to port it to 2.2.x
- kernels.
-
- * Name: **Linux Virtual File System**
-
- :Author: Peter J. Braam.
- :URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/
- :Date: 1998
- :Keywords: slides, VFS, inode, superblock, dentry, dcache.
- :Description: Set of slides, presumably from a presentation on the
- Linux VFS layer. Covers version 2.1.x, with dentries and the
- dcache.
-
- * Title: **The Venus kernel interface**
-
- :Author: Peter J. Braam.
- :URL: http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html
- :Date: 1998
- :Keywords: coda, filesystem, venus, cache manager.
- :Description: "This document describes the communication between
- Venus and kernel level file system code needed for the operation
- of the Coda filesystem. This version document is meant to describe
- the current interface (version 1.0) as well as improvements we
- envisage".
-
- * Title: **Design and Implementation of the Second Extended Filesystem**
-
- :Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
- :URL: https://web.mit.edu/tytso/www/linux/ext2intro.html
- :Date: 1998
- :Keywords: ext2, linux fs history, inode, directory, link, devices,
- VFS, physical structure, performance, benchmarks, ext2fs library,
- ext2fs tools, e2fsck.
- :Description: Paper written by three of the top ext2 hackers.
- Covers Linux filesystems history, ext2 motivation, ext2 features,
- design, physical structure on disk, performance, benchmarks,
- e2fsck's passes description... A must read!
- :Notes: This paper was first published in the Proceedings of the
- First Dutch International Symposium on Linux, ISBN 90-367-0385-9.
-
- * Title: **The Linux RAID-1, 4, 5 Code**
-
- :Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza.
- :URL: http://www.linuxjournal.com/article.php?sid=2391
- :Date: 1997
- :Keywords: RAID, MD driver.
- :Description: Linux Journal Kernel Korner article.
- :Abstract: *A description of the implementation of the RAID-1,
- RAID-4 and RAID-5 personalities of the MD device driver in the
- Linux kernel, providing users with high performance and reliable,
- secondary-storage capability using software*.
-
- * Title: **Linux Kernel Hackers' Guide**
-
- :Author: Michael K. Johnson.
- :URL: https://www.tldp.org/LDP/khg/HyperNews/get/khg.html
- :Date: 1997
- :Keywords: device drivers, files, VFS, kernel interface, character vs
- block devices, hardware interrupts, scsi, DMA, access to user memory,
- memory allocation, timers.
- :Description: A guide designed to help you get up to speed on the
- concepts that are not intuitively obvious, and to document the internal
- structures of Linux.
-
- * Title: **Dynamic Kernels: Modularized Device Drivers**
-
- :Author: Alessandro Rubini.
- :URL: http://www.linuxjournal.com/article.php?sid=1219
- :Date: 1996
- :Keywords: device driver, module, loading/unloading modules,
- allocating resources.
- :Description: Linux Journal Kernel Korner article.
- :Abstract: *This is the first of a series of four articles
- co-authored by Alessandro Rubini and Georg Zezchwitz which present
- a practical approach to writing Linux device drivers as kernel
- loadable modules. This installment presents an introduction to the
- topic, preparing the reader to understand next month's
- installment*.
-
- * Title: **Dynamic Kernels: Discovery**
-
- :Author: Alessandro Rubini.
- :URL: http://www.linuxjournal.com/article.php?sid=1220
- :Date: 1996
- :Keywords: character driver, init_module, clean_up module,
- autodetection, mayor number, minor number, file operations,
- open(), close().
- :Description: Linux Journal Kernel Korner article.
- :Abstract: *This article, the second of four, introduces part of
- the actual code to create custom module implementing a character
- device driver. It describes the code for module initialization and
- cleanup, as well as the open() and close() system calls*.
-
- * Title: **The Devil's in the Details**
-
- :Author: Georg v. Zezschwitz and Alessandro Rubini.
- :URL: http://www.linuxjournal.com/article.php?sid=1221
- :Date: 1996
- :Keywords: read(), write(), select(), ioctl(), blocking/non
- blocking mode, interrupt handler.
- :Description: Linux Journal Kernel Korner article.
- :Abstract: *This article, the third of four on writing character
- device drivers, introduces concepts of reading, writing, and using
- ioctl-calls*.
-
- * Title: **Dissecting Interrupts and Browsing DMA**
-
- :Author: Alessandro Rubini and Georg v. Zezschwitz.
- :URL: https://www.linuxjournal.com/article.php?sid=1222
- :Date: 1996
- :Keywords: interrupts, irqs, DMA, bottom halves, task queues.
- :Description: Linux Journal Kernel Korner article.
- :Abstract: *This is the fourth in a series of articles about
- writing character device drivers as loadable kernel modules. This
- month, we further investigate the field of interrupt handling.
- Though it is conceptually simple, practical limitations and
- constraints make this an ''interesting'' part of device driver
- writing, and several different facilities have been provided for
- different situations. We also investigate the complex topic of
- DMA*.
-
- * Title: **Device Drivers Concluded**
-
- :Author: Georg v. Zezschwitz.
- :URL: https://www.linuxjournal.com/article.php?sid=1287
- :Date: 1996
- :Keywords: address spaces, pages, pagination, page management,
- demand loading, swapping, memory protection, memory mapping, mmap,
- virtual memory areas (VMAs), vremap, PCI.
- :Description: Finally, the above turned out into a five articles
- series. This latest one's introduction reads: "This is the last of
- five articles about character device drivers. In this final
- section, Georg deals with memory mapping devices, beginning with
- an overall description of the Linux memory management concepts".
-
- * Title: **Network Buffers And Memory Management**
-
- :Author: Alan Cox.
- :URL: https://www.linuxjournal.com/article.php?sid=1312
- :Date: 1996
- :Keywords: sk_buffs, network devices, protocol/link layer
- variables, network devices flags, transmit, receive,
- configuration, multicast.
- :Description: Linux Journal Kernel Korner.
- :Abstract: *Writing a network device driver for Linux is fundamentally
- simple---most of the complexity (other than talking to the
- hardware) involves managing network packets in memory*.
-
- * Title: **Analysis of the Ext2fs structure**
-
- :Author: Louis-Dominique Dubeau.
- :URL: https://teaching.csse.uwa.edu.au/units/CITS2002/fs-ext2/
- :Date: 1994
- :Keywords: ext2, filesystem, ext2fs.
- :Description: Description of ext2's blocks, directories, inodes,
- bitmaps, invariants...
-
Published books
---------------
- * Title: **Linux Treiber entwickeln**
-
- :Author: Jürgen Quade, Eva-Katharina Kunst
- :Publisher: dpunkt.verlag
- :Date: Oct 2015 (4th edition)
- :Pages: 688
- :ISBN: 978-3-86490-288-8
- :Note: German. The third edition from 2011 is
- much cheaper and still quite up-to-date.
-
- * Title: **Linux Kernel Networking: Implementation and Theory**
-
- :Author: Rami Rosen
- :Publisher: Apress
- :Date: December 22, 2013
- :Pages: 648
- :ISBN: 978-1430261964
-
- * Title: **Embedded Linux Primer: A practical Real-World Approach, 2nd Edition**
+ * Title: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization**
- :Author: Christopher Hallinan
- :Publisher: Pearson
- :Date: November, 2010
- :Pages: 656
- :ISBN: 978-0137017836
+ :Author: Kaiwan N. Billimoria
+ :Publisher: Packt Publishing Ltd
+ :Date: 2021
+ :Pages: 754
+ :ISBN: 978-1789953435
* Title: **Linux Kernel Development, 3rd Edition**
@@ -472,14 +90,7 @@ Published books
:Date: July, 2010
:Pages: 440
:ISBN: 978-0672329463
-
- * Title: **Essential Linux Device Drivers**
-
- :Author: Sreekrishnan Venkateswaran
- :Published: Prentice Hall
- :Date: April, 2008
- :Pages: 744
- :ISBN: 978-0132396554
+ :Notes: Foundational book
.. _ldd3_published:
@@ -490,68 +101,10 @@ Published books
:Date: 2005
:Pages: 636
:ISBN: 0-596-00590-3
- :Notes: Further information in
+ :Notes: Foundational book. Further information in
http://www.oreilly.com/catalog/linuxdrive3/
PDF format, URL: https://lwn.net/Kernel/LDD3/
- * Title: **Linux Kernel Internals**
-
- :Author: Michael Beck
- :Publisher: Addison-Wesley
- :Date: 1997
- :ISBN: 0-201-33143-8 (second edition)
-
- * Title: **Programmation Linux 2.0 API systeme et fonctionnement du noyau**
-
- :Author: Remy Card, Eric Dumas, Franck Mevel
- :Publisher: Eyrolles
- :Date: 1997
- :Pages: 520
- :ISBN: 2-212-08932-5
- :Notes: French
-
- * Title: **The Design and Implementation of the 4.4 BSD UNIX Operating System**
-
- :Author: Marshall Kirk McKusick, Keith Bostic, Michael J. Karels,
- John S. Quarterman
- :Publisher: Addison-Wesley
- :Date: 1996
- :ISBN: 0-201-54979-4
-
- * Title: **Unix internals -- the new frontiers**
-
- :Author: Uresh Vahalia
- :Publisher: Prentice Hall
- :Date: 1996
- :Pages: 600
- :ISBN: 0-13-101908-2
-
- * Title: **Programming for the real world - POSIX.4**
-
- :Author: Bill O. Gallmeister
- :Publisher: O'Reilly & Associates, Inc
- :Date: 1995
- :Pages: 552
- :ISBN: I-56592-074-0
- :Notes: Though not being directly about Linux, Linux aims to be
- POSIX. Good reference.
-
- * Title: **UNIX Systems for Modern Architectures: Symmetric Multiprocessing and Caching for Kernel Programmers**
-
- :Author: Curt Schimmel
- :Publisher: Addison Wesley
- :Date: June, 1994
- :Pages: 432
- :ISBN: 0-201-63338-8
-
- * Title: **The Design and Implementation of the 4.3 BSD UNIX Operating System**
-
- :Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael J
- Karels, John S. Quarterman
- :Publisher: Addison-Wesley
- :Date: 1989 (reprinted with corrections on October, 1990)
- :ISBN: 0-201-06196-1
-
* Title: **The Design of the UNIX Operating System**
:Author: Maurice J. Bach
@@ -559,6 +112,7 @@ Published books
:Date: 1986
:Pages: 471
:ISBN: 0-13-201757-1
+ :Notes: Foundational book
Miscellaneous
-------------
@@ -577,7 +131,7 @@ Miscellaneous
:Keywords: latest kernel news.
:Description: The title says it all. There's a fixed kernel section
summarizing developers' work, bug fixes, new features and versions
- produced during the week. Published every Thursday.
+ produced during the week.
* Name: **The home page of Linux-MM**
@@ -614,7 +168,8 @@ Miscellaneous
-------
-Document last updated on Tue 2016-Sep-20
+This document was originally based on:
-This document is based on:
https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+
+and written by Juan-Mariano de Goyeneche
diff --git a/Documentation/riscv/vm-layout.rst b/Documentation/riscv/vm-layout.rst
index 5b36e45fef60..3be44e74ec5d 100644
--- a/Documentation/riscv/vm-layout.rst
+++ b/Documentation/riscv/vm-layout.rst
@@ -97,3 +97,39 @@ RISC-V Linux Kernel SV48
ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
__________________|____________|__________________|_________|____________________________________________________________
+
+
+RISC-V Linux Kernel SV57
+------------------------
+
+::
+
+ ========================================================================================================================
+ Start addr | Offset | End addr | Size | VM area description
+ ========================================================================================================================
+ | | | |
+ 0000000000000000 | 0 | 00ffffffffffffff | 64 PB | user-space virtual memory, different per mm
+ __________________|____________|__________________|_________|___________________________________________________________
+ | | | |
+ 0100000000000000 | +64 PB | feffffffffffffff | ~16K PB | ... huge, almost 64 bits wide hole of non-canonical
+ | | | | virtual memory addresses up to the -64 PB
+ | | | | starting offset of kernel mappings.
+ __________________|____________|__________________|_________|___________________________________________________________
+ |
+ | Kernel-space virtual memory, shared between all processes:
+ ____________________________________________________________|___________________________________________________________
+ | | | |
+ ff1bfffffee00000 | -57 PB | ff1bfffffeffffff | 2 MB | fixmap
+ ff1bffffff000000 | -57 PB | ff1bffffffffffff | 16 MB | PCI io
+ ff1c000000000000 | -57 PB | ff1fffffffffffff | 1 PB | vmemmap
+ ff20000000000000 | -56 PB | ff5fffffffffffff | 16 PB | vmalloc/ioremap space
+ ff60000000000000 | -40 PB | ffdeffffffffffff | 32 PB | direct mapping of all physical memory
+ ffdf000000000000 | -8 PB | fffffffeffffffff | 8 PB | kasan
+ __________________|____________|__________________|_________|____________________________________________________________
+ |
+ | Identical layout to the 39-bit one from here on:
+ ____________________________________________________________|____________________________________________________________
+ | | | |
+ ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
+ ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
+ __________________|____________|__________________|_________|____________________________________________________________
diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
new file mode 100644
index 000000000000..45a624fdcf2c
--- /dev/null
+++ b/Documentation/sphinx-static/custom.css
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CSS tweaks for the Alabaster theme
+ */
+
+/* Shrink the headers a bit */
+div.body h1 { font-size: 180%; }
+div.body h2 { font-size: 150%; }
+div.body h3 { font-size: 130%; }
+
+/* Tighten up the layout slightly */
+div.body { padding: 0 15px 0 10px; }
+div.sphinxsidebarwrapper { padding: 1em 0.4em; }
+div.sphinxsidebar { font-size: inherit; }
+/* Tweak document margins and don't force width */
+div.document {
+ margin: 20px 10px 0 10px;
+ width: auto;
+}
+
+/*
+ * Parameters for the display of function prototypes and such included
+ * from C source files.
+ */
+dl.function, dl.struct, dl.enum { margin-top: 2em; background-color: #ecf0f3; }
+/* indent lines 2+ of multi-line function prototypes */
+dl.function dt { margin-left: 10em; text-indent: -10em; }
+dt.sig-object { font-size: larger; }
+div.kernelindent { margin-left: 2em; margin-right: 4em; }
diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/requirements.txt
index 2c573541ab71..335b53df35e2 100644
--- a/Documentation/sphinx/requirements.txt
+++ b/Documentation/sphinx/requirements.txt
@@ -1,4 +1,3 @@
# jinja2>=3.1 is not compatible with Sphinx<4.0
jinja2<3.1
-sphinx_rtd_theme
Sphinx==2.4.4
diff --git a/Documentation/subsystem-apis.rst b/Documentation/subsystem-apis.rst
index af65004a80aa..b51f38527e14 100644
--- a/Documentation/subsystem-apis.rst
+++ b/Documentation/subsystem-apis.rst
@@ -43,6 +43,7 @@ needed).
input/index
hwmon/index
gpu/index
+ accel/index
security/index
sound/index
crypto/index
diff --git a/Documentation/timers/hrtimers.rst b/Documentation/timers/hrtimers.rst
index c1c20a693e8f..7ac448908d1f 100644
--- a/Documentation/timers/hrtimers.rst
+++ b/Documentation/timers/hrtimers.rst
@@ -118,7 +118,7 @@ existing timer wheel code, as it is mature and well suited. Sharing code
was not really a win, due to the different data structures. Also, the
hrtimer functions now have clearer behavior and clearer names - such as
hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly
-equivalent to del_timer() and del_timer_sync()] - so there's no direct
+equivalent to timer_delete() and timer_delete_sync()] - so there's no direct
1:1 mapping between them on the algorithmic level, and thus no real
potential for code sharing either.
diff --git a/Documentation/tools/index.rst b/Documentation/tools/index.rst
index 0bb1e61bdcc0..80488e290e10 100644
--- a/Documentation/tools/index.rst
+++ b/Documentation/tools/index.rst
@@ -11,6 +11,7 @@ more additions are needed here:
:maxdepth: 1
rtla/index
+ rv/index
.. only:: subproject and html
diff --git a/Documentation/tools/rv/Makefile b/Documentation/tools/rv/Makefile
new file mode 100644
index 000000000000..ec8713c1b35f
--- /dev/null
+++ b/Documentation/tools/rv/Makefile
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+INSTALL ?= install
+RM ?= rm -f
+RMDIR ?= rmdir --ignore-fail-on-non-empty
+
+PREFIX ?= /usr/share
+MANDIR ?= $(PREFIX)/man
+MAN1DIR = $(MANDIR)/man1
+
+MAN1_RST = $(wildcard rv*.rst)
+
+_DOC_MAN1 = $(patsubst %.rst,%.1,$(MAN1_RST))
+DOC_MAN1 = $(addprefix $(OUTPUT),$(_DOC_MAN1))
+
+RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null)
+RST2MAN_OPTS += --verbose
+
+TEST_RST2MAN = $(shell sh -c "rst2man --version > /dev/null 2>&1 || echo n")
+
+$(OUTPUT)%.1: %.rst
+ifndef RST2MAN_DEP
+ $(info ********************************************)
+ $(info ** NOTICE: rst2man not found)
+ $(info **)
+ $(info ** Consider installing the latest rst2man from your)
+ $(info ** distribution, e.g., 'dnf install python3-docutils' on Fedora,)
+ $(info ** or from source:)
+ $(info **)
+ $(info ** https://docutils.sourceforge.io/docs/dev/repository.html )
+ $(info **)
+ $(info ********************************************)
+ $(error NOTICE: rst2man required to generate man pages)
+endif
+ rst2man $(RST2MAN_OPTS) $< > $@
+
+man1: $(DOC_MAN1)
+man: man1
+
+clean:
+ $(RM) $(DOC_MAN1)
+
+install: man
+ $(INSTALL) -d -m 755 $(DESTDIR)$(MAN1DIR)
+ $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(MAN1DIR)
+
+uninstall:
+ $(RM) $(addprefix $(DESTDIR)$(MAN1DIR)/,$(_DOC_MAN1))
+ $(RMDIR) $(DESTDIR)$(MAN1DIR)
+
+.PHONY: man man1 clean install uninstall
+.DEFAULT_GOAL := man
diff --git a/Documentation/tools/rv/common_appendix.rst b/Documentation/tools/rv/common_appendix.rst
new file mode 100644
index 000000000000..f4239192bee8
--- /dev/null
+++ b/Documentation/tools/rv/common_appendix.rst
@@ -0,0 +1,16 @@
+REPORTING BUGS
+==============
+
+Report bugs to <linux-kernel@vger.kernel.org>
+and <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+=======
+
+**rv** is Free Software licensed under the GNU GPLv2
+
+COPYING
+=======
+
+Copyright \(C) 2022 Red Hat, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/tools/rv/common_ikm.rst b/Documentation/tools/rv/common_ikm.rst
new file mode 100644
index 000000000000..e50a5f8a7142
--- /dev/null
+++ b/Documentation/tools/rv/common_ikm.rst
@@ -0,0 +1,21 @@
+**-h**, **--help**
+
+ Print the monitor's options and the available reactors list.
+
+**-r**, **--reactor** *reactor*
+
+ Enables the *reactor*. See **-h** for a list of available reactors.
+
+**-s**, **--self**
+
+ When tracing (**-t**), also print the events that happened during the **rv**
+ command itself. If the **rv** command itself generates too many events,
+ the tool might get busy processing its own events only.
+
+**-t**, **--trace**
+
+ Trace monitor's events and error.
+
+**-v**, **--verbose**
+
+ Print debug messages.
diff --git a/Documentation/tools/rv/index.rst b/Documentation/tools/rv/index.rst
new file mode 100644
index 000000000000..8fd16d91d639
--- /dev/null
+++ b/Documentation/tools/rv/index.rst
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============================
+Runtime verification (rv) tool
+==============================
+
+**rv** tool provides the interface for a collection of runtime verification
+(rv) monitors.
+
+.. toctree::
+ :maxdepth: 1
+
+ rv
+ rv-list
+ rv-mon
+ rv-mon-wip
+ rv-mon-wwnr
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/tools/rv/rv-list.rst b/Documentation/tools/rv/rv-list.rst
new file mode 100644
index 000000000000..51e4608f9e99
--- /dev/null
+++ b/Documentation/tools/rv/rv-list.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+rv-list
+=======
+-----------------------
+List available monitors
+-----------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv list** [*OPTIONS*]
+
+DESCRIPTION
+===========
+
+The **rv list** command prints all available monitors. These monitors
+can be enabled using the **rv mon** command.
+
+OPTIONS
+=======
+
+**-h**, **--help**
+
+ Print help menu.
+
+SEE ALSO
+========
+
+**rv**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Written by Daniel Bristot de Oliveira <bristot@kernel.org>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/tools/rv/rv-mon-wip.rst b/Documentation/tools/rv/rv-mon-wip.rst
new file mode 100644
index 000000000000..2d42104d63d1
--- /dev/null
+++ b/Documentation/tools/rv/rv-mon-wip.rst
@@ -0,0 +1,44 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========
+rv-mon-wip
+==========
+----------------------------
+Wakeup In Preemptive monitor
+----------------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv mon wip** [*OPTIONS*]
+
+DESCRIPTION
+===========
+
+The wakeup in preemptive (**wip**) monitor is a sample per-cpu monitor that
+checks if the wakeup events always take place with preemption disabled.
+
+See kernel documentation for further information about this monitor:
+<https://docs.kernel.org/trace/rv/monitor_wip.html>
+
+OPTIONS
+=======
+
+.. include:: common_ikm.rst
+
+SEE ALSO
+========
+
+**rv**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Written by Daniel Bristot de Oliveira <bristot@kernel.org>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/tools/rv/rv-mon-wwnr.rst b/Documentation/tools/rv/rv-mon-wwnr.rst
new file mode 100644
index 000000000000..a18f3fd54af4
--- /dev/null
+++ b/Documentation/tools/rv/rv-mon-wwnr.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========
+rv-mon-wwnr
+===========
+--------------------------------
+Wakeup While Not Running monitor
+--------------------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv mon wip** [*OPTIONS*]
+
+DESCRIPTION
+===========
+
+The wakeup while not running (**wwnr**) is a per-task sample monitor.
+
+See kernel documentation for further information about this monitor:
+<https://docs.kernel.org/trace/rv/monitor_wwnr.html>
+
+OPTIONS
+=======
+
+.. include:: common_ikm.rst
+
+SEE ALSO
+========
+
+**rv**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Written by Daniel Bristot de Oliveira <bristot@kernel.org>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/tools/rv/rv-mon.rst b/Documentation/tools/rv/rv-mon.rst
new file mode 100644
index 000000000000..af0f329a7c9c
--- /dev/null
+++ b/Documentation/tools/rv/rv-mon.rst
@@ -0,0 +1,55 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+rv-list
+=======
+-----------------------
+List available monitors
+-----------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv mon** [*-h*] **monitor_name** [*-h*] [*MONITOR OPTIONS*]
+
+DESCRIPTION
+===========
+
+The **rv mon** command runs the monitor named *monitor_name*. Each monitor
+has its own set of options. The **rv list** command shows all available
+monitors.
+
+OPTIONS
+=======
+
+**-h**, **--help**
+
+ Print help menu.
+
+AVAILABLE MONITORS
+==================
+
+The **rv** tool provides the interface for a set of monitors. Use the
+**rv list** command to list all available monitors.
+
+Each monitor has its own set of options. See man **rv-mon**-*monitor_name*
+for details about each specific monitor. Also, running **rv mon**
+**monitor_name** **-h** display the help menu with the available
+options.
+
+SEE ALSO
+========
+
+**rv**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Written by Daniel Bristot de Oliveira <bristot@kernel.org>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/tools/rv/rv.rst b/Documentation/tools/rv/rv.rst
new file mode 100644
index 000000000000..cee93dc21a76
--- /dev/null
+++ b/Documentation/tools/rv/rv.rst
@@ -0,0 +1,63 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==
+rv
+==
+--------------------
+Runtime Verification
+--------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv** *COMMAND* [*OPTIONS*]
+
+DESCRIPTION
+===========
+
+Runtime Verification (**RV**) is a lightweight (yet rigorous) method
+for formal verification with a practical approach for complex systems.
+Instead of relying on a fine-grained model of a system (e.g., a
+re-implementation a instruction level), RV works by analyzing the trace
+of the system's actual execution, comparing it against a formal
+specification of the system behavior.
+
+The **rv** tool provides the interface for a collection of runtime
+verification (rv) monitors.
+
+COMMANDS
+========
+
+**list**
+
+ List all available monitors.
+
+**mon**
+
+ Run monitor.
+
+OPTIONS
+=======
+
+**-h**, **--help**
+
+ Display the help text.
+
+For other options, see the man page for the corresponding command.
+
+SEE ALSO
+========
+
+**rv-list**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Daniel Bristot de Oliveira <bristot@kernel.org>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 60bceb018d6a..21f01d32c959 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -2940,7 +2940,7 @@ Produces::
bash-1994 [000] .... 4342.324898: ima_get_action <-process_measurement
bash-1994 [000] .... 4342.324898: ima_match_policy <-ima_get_action
bash-1994 [000] .... 4342.324899: do_truncate <-do_last
- bash-1994 [000] .... 4342.324899: should_remove_suid <-do_truncate
+ bash-1994 [000] .... 4342.324899: setattr_should_drop_suidgid <-do_truncate
bash-1994 [000] .... 4342.324899: notify_change <-do_truncate
bash-1994 [000] .... 4342.324900: current_fs_time <-notify_change
bash-1994 [000] .... 4342.324900: current_kernel_time <-current_fs_time
diff --git a/Documentation/translations/index.rst b/Documentation/translations/index.rst
index 1175a47d07f0..b826c34791c0 100644
--- a/Documentation/translations/index.rst
+++ b/Documentation/translations/index.rst
@@ -12,6 +12,7 @@ Translations
it_IT/index
ko_KR/index
ja_JP/index
+ sp_SP/index
.. _translations_disclaimer:
diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst
index 51af37f2d621..b8ecf41273c5 100644
--- a/Documentation/translations/it_IT/kernel-hacking/locking.rst
+++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst
@@ -990,7 +990,7 @@ potreste fare come segue::
while (list) {
struct foo *next = list->next;
- del_timer(&list->timer);
+ timer_delete(&list->timer);
kfree(list);
list = next;
}
@@ -1003,7 +1003,7 @@ e prenderà il *lock* solo dopo spin_unlock_bh(), e cercherà
di eliminare il suo oggetto (che però è già stato eliminato).
Questo può essere evitato controllando il valore di ritorno di
-del_timer(): se ritorna 1, il temporizzatore è stato già
+timer_delete(): se ritorna 1, il temporizzatore è stato già
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
esecuzione, quindi possiamo fare come segue::
@@ -1012,7 +1012,7 @@ esecuzione, quindi possiamo fare come segue::
while (list) {
struct foo *next = list->next;
- if (!del_timer(&list->timer)) {
+ if (!timer_delete(&list->timer)) {
/* Give timer a chance to delete this */
spin_unlock_bh(&list_lock);
goto retry;
@@ -1026,10 +1026,8 @@ esecuzione, quindi possiamo fare come segue::
Un altro problema è l'eliminazione dei temporizzatori che si riavviano
da soli (chiamando add_timer() alla fine della loro esecuzione).
Dato che questo è un problema abbastanza comune con una propensione
-alle corse critiche, dovreste usare del_timer_sync()
-(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il
-numero di volte che il temporizzatore è stato interrotto prima che
-fosse in grado di fermarlo senza che si riavviasse.
+alle corse critiche, dovreste usare timer_delete_sync()
+(``include/linux/timer.h``) per gestire questo caso.
Velocità della sincronizzazione
===============================
@@ -1374,7 +1372,7 @@ contesto, o trattenendo un qualsiasi *lock*.
- kfree()
-- add_timer() e del_timer()
+- add_timer() e timer_delete()
Riferimento per l'API dei Mutex
===============================
diff --git a/Documentation/translations/ja_JP/howto.rst b/Documentation/translations/ja_JP/howto.rst
index b8eeb45a02d4..9b0b3436dfcf 100644
--- a/Documentation/translations/ja_JP/howto.rst
+++ b/Documentation/translations/ja_JP/howto.rst
@@ -86,9 +86,14 @@ info ページ( info gcc )を見てください。
--------
Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま
-す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在
-する、COPYING のファイルを見てください。もしライセンスについてさらに質
-問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ
+す。ソースツリーのメインディレクトリにある COPYING のファイルを見てく
+ださい。Linux カーネルのライセンスルールとソースコード内の
+`SPDX <https://spdx.org/>`_ 識別子の使い方は
+:ref:`Documentation/process/license-rules.rst <kernel_licensing>`
+に説明されています。
+
+もしライセンスについてさらに質問があれば、
+Linux Kernel メーリングリストに質問するのではなく、どうぞ
法律家に相談してください。メーリングリストの人達は法律家ではなく、法的
問題については彼らの声明はあてにするべきではありません。
@@ -111,7 +116,7 @@ linux-api@vger.kernel.org に送ることを勧めます。
以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で
す-
- README
+ :ref:`Documentation/admin-guide/README.rst <readme>`
このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注
configure )し、生成(訳注 build )するために必要なことは何かが書かれ
ています。 カーネルに関して初めての人はここからスタートすると良い
@@ -145,7 +150,8 @@ linux-api@vger.kernel.org に送ることを勧めます。
この他にパッチを作る方法についてのよくできた記述は-
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
"Linux kernel patch submission format"
https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html
@@ -237,13 +243,6 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、
れるための基礎を学ぶことができ、そしてもしあなたがまだアイディアを持っ
ていない場合には、次にやる仕事の方向性が見えてくるかもしれません。
-もしあなたが、すでにひとまとまりコードを書いていて、カーネルツリーに入
-れたいと思っていたり、それに関する適切な支援を求めたい場合、カーネルメ
-ンターズプロジェクトはそのような皆さんを助けるためにできました。ここに
-はメーリングリストがあり、以下から参照できます -
-
- https://selenic.com/mailman/listinfo/kernel-mentors
-
実際に Linux カーネルのコードについて修正を加える前に、どうやってその
コードが動作するのかを理解することが必要です。そのためには、特別なツー
ルの助けを借りてでも、それを直接よく読むことが最良の方法です(ほとんど
@@ -280,9 +279,11 @@ https://kernel.org のリポジトリに存在します。
大きな変更は git(カーネルのソース管理ツール、詳細は
http://git-scm.com/ 参照) を使って送るのが好ましいやり方ですが、パッ
チファイルの形式のまま送るのでも十分です。
- - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定
- 性に影響をあたえるような新機能は含まない類のパッチしか取り込むこと
- はできません。新しいドライバ(もしくはファイルシステム)のパッチは
+ - 2週間後 -rc1 カーネルがリリースされ、新しいカーネルを可能な限り堅牢に
+ することに焦点が移ります。この期間のパッチのほとんどは退行を修正する
+ ものとなります。以前から存在していたバグは退行には当たらないため、
+ 送るのは重要な修正だけにしてください。
+ 新しいドライバ (もしくはファイルシステム) のパッチは
-rc1 の後で受け付けられることもあることを覚えておいてください。な
ぜなら、変更が独立していて、追加されたコードの外の領域に影響を与え
ない限り、退行のリスクは無いからです。-rc1 がリリースされた後、
@@ -308,9 +309,12 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
バージョン番号が3つの数字に分かれているカーネルは -stable カーネルです。
これには最初の2つのバージョン番号の数字に対応した、
-メインラインリリースで見つかったセキュリティ問題や
+メジャーメインラインリリースで見つかったセキュリティ問題や
重大な後戻りに対する比較的小さい重要な修正が含まれます。
+メジャー安定版シリーズのそれぞれのリリースは
+バージョン番号の3番目を増加させ、最初の2つの番号は同じ値を保ちます。
+
これは、開発/実験的バージョンのテストに協力することに興味が無く、最新
の安定したカーネルを使いたいユーザに推奨するブランチです。
@@ -366,16 +370,10 @@ linux-next の実行テストを行う冒険好きなテスターは大いに歓
バグレポート
-------------
-https://bugzilla.kernel.org は Linux カーネル開発者がカーネルのバグを追跡する
-場所です。ユーザは見つけたバグの全てをこのツールで報告すべきです。どう
-kernel bugzilla を使うかの詳細は、以下を参照してください -
-
- https://bugzilla.kernel.org/page.cgi?id=faq.html
-
メインカーネルソースディレクトリにあるファイル
-admin-guide/reporting-bugs.rstはカーネルバグらしいものについてどうレポー
-トするかの良いテンプレートであり、問題の追跡を助けるためにカーネル開発
-者にとってどんな情報が必要なのかの詳細が書かれています。
+'Documentation/admin-guide/reporting-issues.rst'
+は、カーネルバグらしきものの報告の仕方、および、カーネル開発者が問題を
+追跡する際の手がかりとなる情報についての詳細を説明しています。
バグレポートの管理
-------------------
@@ -388,15 +386,13 @@ admin-guide/reporting-bugs.rstはカーネルバグらしいものについて
道です、なぜなら多くの人は他人のバグの修正に時間を浪費することを好まな
いからです。
-すでにレポートされたバグのために仕事をするためには、
-https://bugzilla.kernel.org に行ってください。もし今後のバグレポートに
-ついてアドバイスを受けたいのであれば、bugme-new メーリングリスト(新し
-いバグレポートだけがここにメールされる) または bugme-janitor メーリン
-グリスト(bugzilla の変更毎にここにメールされる)を購読できます。
-
- https://lists.linux-foundation.org/mailman/listinfo/bugme-new
-
- https://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
+すでにレポートされたバグの作業をするためには、興味のあるサブシステムを
+見つけ、そのサブシステムのバグの報告先 (多くの場合メーリングリスト、
+稀にバグトラッカー) を MAINTAINERS ファイルで調べてください。
+そのアーカイブで最近の報告を検索し、できそうなものに力を貸してください。
+https://bugzilla.kernel.org でバグ報告を調べようとする人もいるでしょう。
+これは限られた一部のサブシステムのバグ報告と追跡に利用されるとともに、
+とりわけ、カーネル全体に対するバグの登録先となっています。
メーリングリスト
----------------
@@ -621,7 +617,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
ントの ChangeLog セクションを見てください -
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
これらはどれも、実行することが時にはとても困難です。これらの例を完璧に
実施するには数年かかるかもしれません。これは継続的な改善のプロセスであ
diff --git a/Documentation/translations/ko_KR/memory-barriers.txt b/Documentation/translations/ko_KR/memory-barriers.txt
index 75aa5531cc7d..7165927a708e 100644
--- a/Documentation/translations/ko_KR/memory-barriers.txt
+++ b/Documentation/translations/ko_KR/memory-barriers.txt
@@ -80,7 +80,7 @@ Documentation/memory-barriers.txt
- 메모리 배리어의 종류.
- 메모리 배리어에 대해 가정해선 안될 것.
- - 데이터 의존성 배리어 (역사적).
+ - 주소 데이터 의존성 배리어 (역사적).
- 컨트롤 의존성.
- SMP 배리어 짝맞추기.
- 메모리 배리어 시퀀스의 예.
@@ -217,7 +217,7 @@ Documentation/memory-barriers.txt
P = &B D = *Q;
D 로 읽혀지는 값은 CPU 2 에서 P 로부터 읽혀진 주소값에 의존적이기 때문에 여기엔
-분명한 데이터 의존성이 있습니다. 하지만 이 이벤트들의 실행 결과로는 아래의
+분명한 주소 의존성이 있습니다. 하지만 이 이벤트들의 실행 결과로는 아래의
결과들이 모두 나타날 수 있습니다:
(Q == &A) and (D == 1)
@@ -416,19 +416,19 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
하나씩 요청해 집어넣습니다. 쓰기 배리어 앞의 모든 스토어 오퍼레이션들은
쓰기 배리어 뒤의 모든 스토어 오퍼레이션들보다 _앞서_ 수행될 겁니다.
- [!] 쓰기 배리어들은 읽기 또는 데이터 의존성 배리어와 함께 짝을 맞춰
+ [!] 쓰기 배리어들은 읽기 또는 주소 의존성 배리어와 함께 짝을 맞춰
사용되어야만 함을 알아두세요; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
- (2) 데이터 의존성 배리어.
+ (2) 주소 의존성 배리어 (역사적).
- 데이터 의존성 배리어는 읽기 배리어의 보다 완화된 형태입니다. 두개의 로드
+ 주소 의존성 배리어는 읽기 배리어의 보다 완화된 형태입니다. 두개의 로드
오퍼레이션이 있고 두번째 것이 첫번째 것의 결과에 의존하고 있을 때(예:
두번째 로드가 참조할 주소를 첫번째 로드가 읽는 경우), 두번째 로드가 읽어올
데이터는 첫번째 로드에 의해 그 주소가 얻어진 뒤에 업데이트 됨을 보장하기
- 위해서 데이터 의존성 배리어가 필요할 수 있습니다.
+ 위해서 주소 의존성 배리어가 필요할 수 있습니다.
- 데이터 의존성 배리어는 상호 의존적인 로드 오퍼레이션들 사이의 부분적 순서
+ 주소 의존성 배리어는 상호 의존적인 로드 오퍼레이션들 사이의 부분적 순서
세우기입니다; 스토어 오퍼레이션들이나 독립적인 로드들, 또는 중복되는
로드들에 대해서는 어떤 영향도 끼치지 않습니다.
@@ -436,37 +436,41 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
오퍼레이션들을 던져 넣고 있으며, 거기에 관심이 있는 다른 CPU 는 그
오퍼레이션들을 메모리 시스템이 실행한 결과를 인지할 수 있습니다. 이처럼
다른 CPU 의 스토어 오퍼레이션의 결과에 관심을 두고 있는 CPU 가 수행 요청한
- 데이터 의존성 배리어는, 배리어 앞의 어떤 로드 오퍼레이션이 다른 CPU 에서
+ 주소 의존성 배리어는, 배리어 앞의 어떤 로드 오퍼레이션이 다른 CPU 에서
던져 넣은 스토어 오퍼레이션과 같은 영역을 향했다면, 그런 스토어
- 오퍼레이션들이 만들어내는 결과가 데이터 의존성 배리어 뒤의 로드
+ 오퍼레이션들이 만들어내는 결과가 주소 의존성 배리어 뒤의 로드
오퍼레이션들에게는 보일 것을 보장합니다.
이 순서 세우기 제약에 대한 그림을 보기 위해선 "메모리 배리어 시퀀스의 예"
서브섹션을 참고하시기 바랍니다.
- [!] 첫번째 로드는 반드시 _데이터_ 의존성을 가져야지 컨트롤 의존성을 가져야
+ [!] 첫번째 로드는 반드시 _주소_ 의존성을 가져야지 컨트롤 의존성을 가져야
하는게 아님을 알아두십시오. 만약 두번째 로드를 위한 주소가 첫번째 로드에
의존적이지만 그 의존성은 조건적이지 그 주소 자체를 가져오는게 아니라면,
그것은 _컨트롤_ 의존성이고, 이 경우에는 읽기 배리어나 그보다 강력한
무언가가 필요합니다. 더 자세한 내용을 위해서는 "컨트롤 의존성" 서브섹션을
참고하시기 바랍니다.
- [!] 데이터 의존성 배리어는 보통 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
+ [!] 주소 의존성 배리어는 보통 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
합니다; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
+ [!] 커널 v5.9 릴리즈에서 명시적 주소 의존성 배리어를 위한 커널 API 들이
+ 삭제되었습니다. 오늘날에는 공유된 변수들의 로드를 표시하는 READ_ONCE() 나
+ rcu_dereference() 와 같은 API 들은 묵시적으로 주소 의존성 배리어를 제공합니다.
+
(3) 읽기 (또는 로드) 메모리 배리어.
- 읽기 배리어는 데이터 의존성 배리어 기능의 보장사항에 더해서 배리어보다
- 앞서 명시된 모든 LOAD 오퍼레이션들이 배리어 뒤에 명시되는 모든 LOAD
+ 읽기 배리어는 주소 의존성 배리어 기능의 보장사항에 더해서 배리어보다 앞서
+ 명시된 모든 LOAD 오퍼레이션들이 배리어 뒤에 명시되는 모든 LOAD
오퍼레이션들보다 먼저 행해진 것으로 시스템의 다른 컴포넌트들에 보여질 것을
보장합니다.
읽기 배리어는 로드 오퍼레이션에 행해지는 부분적 순서 세우기입니다; 스토어
오퍼레이션에 대해서는 어떤 영향도 끼치지 않습니다.
- 읽기 메모리 배리어는 데이터 의존성 배리어를 내장하므로 데이터 의존성
- 배리어를 대신할 수 있습니다.
+ 읽기 메모리 배리어는 주소 의존성 배리어를 내장하므로 주소 의존성 배리어를
+ 대신할 수 있습니다.
[!] 읽기 배리어는 일반적으로 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
합니다; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
@@ -571,16 +575,20 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
Documentation/core-api/dma-api.rst
-데이터 의존성 배리어 (역사적)
------------------------------
+주소 의존성 배리어 (역사적)
+---------------------------
리눅스 커널 v4.15 기준으로, smp_mb() 가 DEC Alpha 용 READ_ONCE() 코드에
추가되었는데, 이는 이 섹션에 주의를 기울여야 하는 사람들은 DEC Alpha 아키텍쳐
전용 코드를 만드는 사람들과 READ_ONCE() 자체를 만드는 사람들 뿐임을 의미합니다.
-그런 분들을 위해, 그리고 역사에 관심 있는 분들을 위해, 여기 데이터 의존성
+그런 분들을 위해, 그리고 역사에 관심 있는 분들을 위해, 여기 주소 의존성
배리어에 대한 이야기를 적습니다.
-데이터 의존성 배리어의 사용에 있어 지켜야 하는 사항들은 약간 미묘하고, 데이터
+[!] 주소 의존성은 로드에서 로드로와 로드에서 스토어로의 관계들 모두에서
+나타나지만, 주소 의존성 배리어는 로드에서 스토어로의 상황에서는 필요하지
+않습니다.
+
+주소 의존성 배리어의 사용에 있어 지켜야 하는 사항들은 약간 미묘하고, 데이터
의존성 배리어가 사용되어야 하는 상황도 항상 명백하지는 않습니다. 설명을 위해
다음의 이벤트 시퀀스를 생각해 봅시다:
@@ -590,10 +598,13 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
B = 4;
<쓰기 배리어>
WRITE_ONCE(P, &B)
- Q = READ_ONCE(P);
+ Q = READ_ONCE_OLD(P);
D = *Q;
-여기엔 분명한 데이터 의존성이 존재하므로, 이 시퀀스가 끝났을 때 Q 는 &A 또는 &B
+[!] READ_ONCE_OLD() 는 4.15 커널 전의 버전에서의, 주소 의존성 배리어를 내포하지
+않는 READ_ONCE() 에 해당합니다.
+
+여기엔 분명한 주소 의존성이 존재하므로, 이 시퀀스가 끝났을 때 Q 는 &A 또는 &B
일 것이고, 따라서:
(Q == &A) 는 (D == 1) 를,
@@ -608,8 +619,8 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
그렇지 않습니다, 그리고 이 현상은 (DEC Alpha 와 같은) 여러 CPU 에서 실제로
발견될 수 있습니다.
-이 문제 상황을 제대로 해결하기 위해, 데이터 의존성 배리어나 그보다 강화된
-무언가가 주소를 읽어올 때와 데이터를 읽어올 때 사이에 추가되어야만 합니다:
+이 문제 상황을 제대로 해결하기 위해, READ_ONCE() 는 커널 v4.15 릴리즈 부터
+묵시적 주소 의존성 배리어를 제공합니다:
CPU 1 CPU 2
=============== ===============
@@ -618,7 +629,7 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
<쓰기 배리어>
WRITE_ONCE(P, &B);
Q = READ_ONCE(P);
- <데이터 의존성 배리어>
+ <묵시적 주소 의존성 배리어>
D = *Q;
이 변경은 앞의 처음 두가지 결과 중 하나만이 발생할 수 있고, 세번째의 결과는
@@ -634,7 +645,7 @@ P 는 짝수 번호 캐시 라인에 저장되어 있고, 변수 B 는 홀수
중이라면 포인터 P (&B) 의 새로운 값과 변수 B 의 기존 값 (2) 를 볼 수 있습니다.
-의존적 쓰기들의 순서를 맞추는데에는 데이터 의존성 배리어가 필요치 않은데, 이는
+의존적 쓰기들의 순서를 맞추는데에는 주소 의존성 배리어가 필요치 않은데, 이는
리눅스 커널이 지원하는 CPU 들은 (1) 쓰기가 정말로 일어날지, (2) 쓰기가 어디에
이루어질지, 그리고 (3) 쓰여질 값을 확실히 알기 전까지는 쓰기를 수행하지 않기
때문입니다. 하지만 "컨트롤 의존성" 섹션과
@@ -647,12 +658,12 @@ Documentation/RCU/rcu_dereference.rst 파일을 주의 깊게 읽어 주시기
B = 4;
<쓰기 배리어>
WRITE_ONCE(P, &B);
- Q = READ_ONCE(P);
+ Q = READ_ONCE_OLD(P);
WRITE_ONCE(*Q, 5);
-따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 데이터 종속성 배리어가 필요치
-않습니다. 달리 말하면, 데이터 종속성 배리어가 없더라도 다음 결과는 생기지
-않습니다:
+따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 주소 의존성 배리어가 필요치
+않습니다. 달리 말하면, 오늘날의 READ_ONCE() 의 묵시적 주소 의존성 배리어가
+없더라도 다음 결과는 생기지 않습니다:
(Q == &B) && (B == 4)
@@ -663,16 +674,16 @@ Documentation/RCU/rcu_dereference.rst 파일을 주의 깊게 읽어 주시기
해줍니다.
-데이터 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
+주소 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
지역적임을 알아두시기 바랍니다. 더 많은 정보를 위해선 "Multicopy 원자성"
섹션을 참고하세요.
-데이터 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
+주소 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
include/linux/rcupdate.h 의 rcu_assign_pointer() 와 rcu_dereference() 를
-참고하세요. 여기서 데이터 의존성 배리어는 RCU 로 관리되는 포인터의 타겟을 현재
-타겟에서 수정된 새로운 타겟으로 바꾸는 작업에서 새로 수정된 타겟이 초기화가
-완료되지 않은 채로 보여지는 일이 일어나지 않게 해줍니다.
+참고하세요. 이것들은 RCU 로 관리되는 포인터의 타겟을 현재 타겟에서 수정된
+새로운 타겟으로 바꾸는 작업에서 새로 수정된 타겟이 초기화가 완료되지 않은 채로
+보여지는 일이 일어나지 않게 해줍니다.
더 많은 예를 위해선 "캐시 일관성" 서브섹션을 참고하세요.
@@ -684,16 +695,17 @@ include/linux/rcupdate.h 의 rcu_assign_pointer() 와 rcu_dereference() 를
약간 다루기 어려울 수 있습니다. 이 섹션의 목적은 여러분이 컴파일러의 무시로
인해 여러분의 코드가 망가지는 걸 막을 수 있도록 돕는겁니다.
-로드-로드 컨트롤 의존성은 데이터 의존성 배리어만으로는 정확히 동작할 수가
-없어서 읽기 메모리 배리어를 필요로 합니다. 아래의 코드를 봅시다:
+로드-로드 컨트롤 의존성은 (묵시적인) 주소 의존성 배리어만으로는 정확히 동작할
+수가 없어서 읽기 메모리 배리어를 필요로 합니다. 아래의 코드를 봅시다:
q = READ_ONCE(a);
+ <묵시적 주소 의존성 배리어>
if (q) {
- <데이터 의존성 배리어> /* BUG: No data dependency!!! */
+ /* BUG: No address dependency!!! */
p = READ_ONCE(b);
}
-이 코드는 원하는 대로의 효과를 내지 못할 수 있는데, 이 코드에는 데이터 의존성이
+이 코드는 원하는 대로의 효과를 내지 못할 수 있는데, 이 코드에는 주소 의존성이
아니라 컨트롤 의존성이 존재하기 때문으로, 이런 상황에서 CPU 는 실행 속도를 더
빠르게 하기 위해 분기 조건의 결과를 예측하고 코드를 재배치 할 수 있어서 다른
CPU 는 b 로부터의 로드 오퍼레이션이 a 로부터의 로드 오퍼레이션보다 먼저 발생한
@@ -930,9 +942,9 @@ CPU 간 상호작용을 다룰 때에 일부 타입의 메모리 배리어는
범용 배리어들은 범용 배리어끼리도 짝을 맞추지만 multicopy 원자성이 없는
대부분의 다른 타입의 배리어들과도 짝을 맞춥니다. ACQUIRE 배리어는 RELEASE
배리어와 짝을 맞춥니다만, 둘 다 범용 배리어를 포함해 다른 배리어들과도 짝을
-맞출 수 있습니다. 쓰기 배리어는 데이터 의존성 배리어나 컨트롤 의존성, ACQUIRE
+맞출 수 있습니다. 쓰기 배리어는 주소 의존성 배리어나 컨트롤 의존성, ACQUIRE
배리어, RELEASE 배리어, 읽기 배리어, 또는 범용 배리어와 짝을 맞춥니다.
-비슷하게 읽기 배리어나 컨트롤 의존성, 또는 데이터 의존성 배리어는 쓰기 배리어나
+비슷하게 읽기 배리어나 컨트롤 의존성, 또는 주소 의존성 배리어는 쓰기 배리어나
ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추는데, 다음과
같습니다:
@@ -951,7 +963,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
a = 1;
<쓰기 배리어>
WRITE_ONCE(b, &a); x = READ_ONCE(b);
- <데이터 의존성 배리어>
+ <묵시적 주소 의존성 배리어>
y = *x;
또는:
@@ -970,8 +982,8 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
기본적으로, 여기서의 읽기 배리어는 "더 완화된" 타입일 순 있어도 항상 존재해야
합니다.
-[!] 쓰기 배리어 앞의 스토어 오퍼레이션은 일반적으로 읽기 배리어나 데이터
-의존성 배리어 뒤의 로드 오퍼레이션과 매치될 것이고, 반대도 마찬가지입니다:
+[!] 쓰기 배리어 앞의 스토어 오퍼레이션은 일반적으로 읽기 배리어나 주소 의존성
+배리어 뒤의 로드 오퍼레이션과 매치될 것이고, 반대도 마찬가지입니다:
CPU 1 CPU 2
=================== ===================
@@ -1023,7 +1035,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
V
-둘째, 데이터 의존성 배리어는 데이터 의존적 로드 오퍼레이션들의 부분적 순서
+둘째, 주소 의존성 배리어는 데이터 의존적 로드 오퍼레이션들의 부분적 순서
세우기로 동작합니다. 다음 일련의 이벤트들을 보세요:
CPU 1 CPU 2
@@ -1069,7 +1081,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
앞의 예에서, CPU 2 는 (B 의 값이 될) *C 의 값 읽기가 C 의 LOAD 뒤에 이어짐에도
B 가 7 이라는 결과를 얻습니다.
-하지만, 만약 데이터 의존성 배리어가 C 의 로드와 *C (즉, B) 의 로드 사이에
+하지만, 만약 주소 의존성 배리어가 C 의 로드와 *C (즉, B) 의 로드 사이에
있었다면:
CPU 1 CPU 2
@@ -1080,7 +1092,7 @@ B 가 7 이라는 결과를 얻습니다.
<쓰기 배리어>
STORE C = &B LOAD X
STORE D = 4 LOAD C (gets &B)
- <데이터 의존성 배리어>
+ <주소 의존성 배리어>
LOAD *C (reads B)
다음과 같이 됩니다:
@@ -1103,7 +1115,7 @@ B 가 7 이라는 결과를 얻습니다.
| +-------+ | |
| | X->9 |------>| |
| +-------+ | |
- C 로의 스토어 앞의 ---> \ ddddddddddddddddd | |
+ C 로의 스토어 앞의 ---> \ aaaaaaaaaaaaaaaaa | |
모든 이벤트 결과가 \ +-------+ | |
뒤의 로드에게 ----->| B->2 |------>| |
보이게 강제한다 +-------+ | |
@@ -1291,7 +1303,7 @@ A 의 로드 두개가 모두 B 의 로드 뒤에 있지만, 서로 다른 값
즉각 완료한다 : : +-------+
-읽기 배리어나 데이터 의존성 배리어를 두번째 로드 직전에 놓는다면:
+읽기 배리어나 주소 의존성 배리어를 두번째 로드 직전에 놓는다면:
CPU 1 CPU 2
======================= =======================
@@ -1785,21 +1797,20 @@ READ_ONCE(jiffies) 라고 할 필요가 없습니다. READ_ONCE() 와 WRITE_ONC
CPU 메모리 배리어
-----------------
-리눅스 커널은 다음의 여덟개 기본 CPU 메모리 배리어를 가지고 있습니다:
+리눅스 커널은 다음의 일곱개 기본 CPU 메모리 배리어를 가지고 있습니다:
TYPE MANDATORY SMP CONDITIONAL
- =============== ======================= ===========================
+ =============== ======================= ===============
범용 mb() smp_mb()
쓰기 wmb() smp_wmb()
읽기 rmb() smp_rmb()
- 데이터 의존성 READ_ONCE()
+ 주소 의존성 READ_ONCE()
-데이터 의존성 배리어를 제외한 모든 메모리 배리어는 컴파일러 배리어를
-포함합니다. 데이터 의존성은 컴파일러에의 추가적인 순서 보장을 포함하지
-않습니다.
+주소 의존성 배리어를 제외한 모든 메모리 배리어는 컴파일러 배리어를 포함합니다.
+주소 의존성은 컴파일러에의 추가적인 순서 보장을 포함하지 않습니다.
-방백: 데이터 의존성이 있는 경우, 컴파일러는 해당 로드를 올바른 순서로 일으킬
+방백: 주소 의존성이 있는 경우, 컴파일러는 해당 로드를 올바른 순서로 일으킬
것으로 (예: `a[b]` 는 a[b] 를 로드 하기 전에 b 의 값을 먼저 로드한다)
기대되지만, C 언어 사양에는 컴파일러가 b 의 값을 추측 (예: 1 과 같음) 해서
b 로드 전에 a 로드를 하는 코드 (예: tmp = a[1]; if (b != 1) tmp = a[b]; ) 를
@@ -1863,6 +1874,7 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
(*) dma_wmb();
(*) dma_rmb();
+ (*) dma_mb();
이것들은 CPU 와 DMA 가능한 디바이스에서 모두 액세스 가능한 공유 메모리의
읽기, 쓰기 작업들의 순서를 보장하기 위해 consistent memory 에서 사용하기
@@ -1893,12 +1905,13 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
dma_rmb() 는 디스크립터로부터 데이터를 읽어오기 전에 디바이스가 소유권을
내려놓았을 것을 보장하고, dma_wmb() 는 디바이스가 자신이 소유권을 다시
- 가졌음을 보기 전에 디스크립터에 데이터가 쓰였을 것을 보장합니다. 참고로,
- writel() 을 사용하면 캐시 일관성이 있는 메모리 (cache coherent memory)
- 쓰기가 MMIO 영역에의 쓰기 전에 완료되었을 것을 보장하므로 writel() 앞에
- wmb() 를 실행할 필요가 없음을 알아두시기 바랍니다. writel() 보다 비용이
- 저렴한 writel_relaxed() 는 이런 보장을 제공하지 않으므로 여기선 사용되지
- 않아야 합니다.
+ 가졌음을 보기 전에 디스크립터에 데이터가 쓰였을 것을 보장합니다. dma_mb()
+ 는 dma_rmb() 와 dma_wmb() 를 모두 내포합니다. 참고로, writel() 을
+ 사용하면 캐시 일관성이 있는 메모리 (cache coherent memory) 쓰기가 MMIO
+ 영역에의 쓰기 전에 완료되었을 것을 보장하므로 writel() 앞에 wmb() 를
+ 실행할 필요가 없음을 알아두시기 바랍니다. writel() 보다 비용이 저렴한
+ writel_relaxed() 는 이런 보장을 제공하지 않으므로 여기선 사용되지 않아야
+ 합니다.
writel_relaxed() 와 같은 완화된 I/O 접근자들에 대한 자세한 내용을 위해서는
"커널 I/O 배리어의 효과" 섹션을, consistent memory 에 대한 자세한 내용을
@@ -1918,6 +1931,14 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
Persistent memory 에서의 로드를 위해선 현재의 읽기 메모리 배리어로도 읽기
순서를 보장하는데 충분합니다.
+ (*) io_stop_wc();
+
+ 쓰기와 결합된 특성을 갖는 메모리 액세스의 경우 (예: ioremap_wc() 에 의해
+ 리턴되는 것들), CPU 는 앞의 액세스들이 뒤따르는 것들과 병합되게끔 기다릴
+ 수 있습니다. io_stop_wc() 는 그런 기다림이 성능에 영향을 끼칠 수 있을 때,
+ 이 매크로 앞의 쓰기-결합된 메모리 액세스들이 매크로 뒤의 것들과 병합되는
+ 것을 방지하기 위해 사용될 수 있습니다.
+
=========================
암묵적 커널 메모리 배리어
=========================
@@ -2827,9 +2848,9 @@ ld.acq 와 stl.rel 인스트럭션을 각각 만들어 내도록 합니다.
DEC Alpha CPU 는 가장 완화된 메모리 순서의 CPU 중 하나입니다. 뿐만 아니라,
Alpha CPU 의 일부 버전은 분할된 데이터 캐시를 가지고 있어서, 의미적으로
관계되어 있는 두개의 캐시 라인이 서로 다른 시간에 업데이트 되는게 가능합니다.
-이게 데이터 의존성 배리어가 정말 필요해지는 부분인데, 데이터 의존성 배리어는
-메모리 일관성 시스템과 함께 두개의 캐시를 동기화 시켜서, 포인터 변경과 새로운
-데이터의 발견을 올바른 순서로 일어나게 하기 때문입니다.
+이게 주소 의존성 배리어가 정말 필요해지는 부분인데, 주소 의존성 배리어는 메모리
+일관성 시스템과 함께 두개의 캐시를 동기화 시켜서, 포인터 변경과 새로운 데이터의
+발견을 올바른 순서로 일어나게 하기 때문입니다.
리눅스 커널의 메모리 배리어 모델은 Alpha 에 기초해서 정의되었습니다만, v4.15
부터는 Alpha 용 READ_ONCE() 코드 내에 smp_mb() 가 추가되어서 메모리 모델로의
diff --git a/Documentation/translations/sp_SP/disclaimer-sp.rst b/Documentation/translations/sp_SP/disclaimer-sp.rst
new file mode 100644
index 000000000000..a400034e95f9
--- /dev/null
+++ b/Documentation/translations/sp_SP/disclaimer-sp.rst
@@ -0,0 +1,6 @@
+:orphan:
+
+.. warning::
+ Si tiene alguna duda sobre la exactitud del contenido de esta
+ traducción, la única referencia válida es la documentación oficial en
+ inglés.
diff --git a/Documentation/translations/sp_SP/howto.rst b/Documentation/translations/sp_SP/howto.rst
new file mode 100644
index 000000000000..f9818d687b54
--- /dev/null
+++ b/Documentation/translations/sp_SP/howto.rst
@@ -0,0 +1,617 @@
+.. include:: ./disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/howto.rst <process_howto>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_process_howto:
+
+Cómo participar en el desarrollo del kernel de Linux
+====================================================
+
+Este documento es el principal punto de partida. Contiene instrucciones
+sobre cómo convertirse en desarrollador del kernel de Linux y explica cómo
+trabajar con el y en su desarrollo. El documento no tratará ningún aspecto
+técnico relacionado con la programación del kernel, pero le ayudará
+guiándole por el camino correcto.
+
+Si algo en este documento quedara obsoleto, envíe parches al maintainer de
+este archivo, que se encuentra en la parte superior del documento.
+
+Introducción
+------------
+¿De modo que quiere descubrir como convertirse en un/a desarrollador/a del
+kernel de Linux? Tal vez su jefe le haya dicho, "Escriba un driver de
+Linux para este dispositivo." El objetivo de este documento en enseñarle
+todo cuanto necesita para conseguir esto, describiendo el proceso por el
+que debe pasar, y con indicaciones de como trabajar con la comunidad.
+También trata de explicar las razones por las cuales la comunidad trabaja
+de la forma en que lo hace.
+
+El kernel esta principalmente escrito en C, con algunas partes que son
+dependientes de la arquitectura en ensamblador. Un buen conocimiento de C
+es necesario para desarrollar en el kernel. Lenguaje ensamblador (en
+cualquier arquitectura) no es necesario excepto que planee realizar
+desarrollo de bajo nivel para dicha arquitectura. Aunque no es un perfecto
+sustituto para una educación sólida en C y/o años de experiencia, los
+siguientes libros sirven, como mínimo, como referencia:
+
+- "The C Programming Language" de Kernighan e Ritchie [Prentice Hall]
+- "Practical C Programming" de Steve Oualline [O'Reilly]
+- "C: A Reference Manual" de Harbison and Steele [Prentice Hall]
+
+El kernel está escrito usando GNU C y la cadena de herramientas GNU. Si
+bien se adhiere al estándar ISO C89, utiliza una serie de extensiones que
+no aparecen en dicho estándar. El kernel usa un C independiente de entorno,
+sin depender de la biblioteca C estándar, por lo que algunas partes del
+estándar C no son compatibles. Divisiones de long long arbitrarios o
+de coma flotante no son permitidas. En ocasiones, puede ser difícil de
+entender las suposiciones que el kernel hace respecto a la cadena de
+herramientas y las extensiones que usa, y desafortunadamente no hay
+referencia definitiva para estas. Consulte las páginas de información de
+gcc (`info gcc`) para obtener información al respecto.
+
+Recuerde que está tratando de aprender a trabajar con una comunidad de
+desarrollo existente. Es un grupo diverso de personas, con altos estándares
+de código, estilo y procedimiento. Estas normas han sido creadas a lo
+largo del tiempo en función de lo que se ha encontrado que funciona mejor
+para un equipo tan grande y geográficamente disperso. Trate de aprender
+tanto como le sea posible acerca de estos estándares antes de tiempo, ya
+que están bien documentados; no espere que la gente se adapte a usted o a
+la forma de hacer las cosas en su empresa.
+
+Cuestiones legales
+------------------
+El código fuente del kernel de Linux se publica bajo licencia GPL. Por
+favor, revise el archivo COPYING, presente en la carpeta principal del
+código fuente, para detalles de la licencia. Si tiene alguna otra pregunta
+sobre licencias, contacte a un abogado, no pregunte en listas de discusión
+del kernel de Linux. La gente en estas listas no son abogadas, y no debe
+confiar en sus opiniones en materia legal.
+
+Para preguntas y respuestas más frecuentes sobre la licencia GPL, consulte:
+
+ https://www.gnu.org/licenses/gpl-faq.html
+
+Documentación
+--------------
+El código fuente del kernel de Linux tiene una gran variedad de documentos
+que son increíblemente valiosos para aprender a interactuar con la
+comunidad del kernel. Cuando se agregan nuevas funciones al kernel, se
+recomienda que se incluyan nuevos archivos de documentación que expliquen
+cómo usar la función. Cuando un cambio en el kernel hace que la interfaz
+que el kernel expone espacio de usuario cambie, se recomienda que envíe la
+información o un parche en las páginas del manual que expliquen el cambio
+a mtk.manpages@gmail.com, y CC la lista linux-api@vger.kernel.org.
+
+Esta es la lista de archivos que están en el código fuente del kernel y son
+de obligada lectura:
+
+ :ref:`Documentation/admin-guide/README.rst <readme>`
+ Este archivo ofrece una breve descripción del kernel de Linux y
+ describe lo que es necesario hacer para configurar y compilar el
+ kernel. Quienes sean nuevos en el kernel deben comenzar aquí.
+
+ :ref:`Documentation/process/changes.rst <changes>`
+ Este archivo proporciona una lista de los niveles mínimos de varios
+ paquetes que son necesarios para construir y ejecutar el kernel
+ exitosamente.
+
+ :ref:`Documentation/process/coding-style.rst <codingstyle>`
+ Esto describe el estilo de código del kernel de Linux y algunas de los
+ razones detrás de esto. Se espera que todo el código nuevo siga las
+ directrices de este documento. La mayoría de los maintainers solo
+ aceptarán parches si se siguen estas reglas, y muchas personas solo
+ revisan el código si tiene el estilo adecuado.
+
+ :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+ Este archivo describe en gran detalle cómo crear con éxito y enviar un
+ parche, que incluye (pero no se limita a):
+
+ - Contenidos del correo electrónico (email)
+ - Formato del email
+ - A quien se debe enviar
+
+ Seguir estas reglas no garantiza el éxito (ya que todos los parches son
+ sujetos a escrutinio de contenido y estilo), pero en caso de no seguir
+ dichas reglas, el fracaso es prácticamente garantizado.
+ Otras excelentes descripciones de cómo crear parches correctamente son:
+
+ "The Perfect Patch"
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+ "Linux kernel patch submission format"
+ https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html
+
+ :ref:`Documentation/process/stable-api-nonsense.rst <stable_api_nonsense>`
+ Este archivo describe la lógica detrás de la decisión consciente de
+ no tener una API estable dentro del kernel, incluidas cosas como:
+
+ - Capas intermedias del subsistema (por compatibilidad?)
+ - Portabilidad de drivers entre sistemas operativos
+ - Mitigar el cambio rápido dentro del árbol de fuentes del kernel (o
+ prevenir cambios rápidos)
+
+ Este documento es crucial para comprender la filosofía del desarrollo
+ de Linux y es muy importante para las personas que se mudan a Linux
+ tras desarrollar otros sistemas operativos.
+
+ :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
+ Si cree que ha encontrado un problema de seguridad en el kernel de
+ Linux, siga los pasos de este documento para ayudar a notificar a los
+ desarrolladores del kernel y ayudar a resolver el problema.
+
+ :ref:`Documentation/process/management-style.rst <managementstyle>`
+ Este documento describe cómo operan los maintainers del kernel de Linux
+ y los valores compartidos detrás de sus metodologías. Esta es una
+ lectura importante para cualquier persona nueva en el desarrollo del
+ kernel (o cualquier persona que simplemente sienta curiosidad por
+ el campo IT), ya que clarifica muchos conceptos erróneos y confusiones
+ comunes sobre el comportamiento único de los maintainers del kernel.
+
+ :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+ Este archivo describe las reglas sobre cómo se suceden las versiones
+ del kernel estable, y qué hacer si desea obtener un cambio en una de
+ estas publicaciones.
+
+ :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
+ Una lista de documentación externa relativa al desarrollo del kernel.
+ Por favor consulte esta lista si no encuentra lo que están buscando
+ dentro de la documentación del kernel.
+
+ :ref:`Documentation/process/applying-patches.rst <applying_patches>`
+ Una buena introducción que describe exactamente qué es un parche y cómo
+ aplicarlo a las diferentes ramas de desarrollo del kernel.
+
+El kernel también tiene una gran cantidad de documentos que pueden ser
+generados automáticamente desde el propio código fuente o desde
+ReStructuredText markups (ReST), como este. Esto incluye un descripción
+completa de la API en el kernel y reglas sobre cómo manejar cerrojos
+(locking) correctamente.
+
+Todos estos documentos se pueden generar como PDF o HTML ejecutando::
+
+ make pdfdocs
+ make htmldocs
+
+respectivamente desde el directorio fuente principal del kernel.
+
+Los documentos que utilizan el markup ReST se generarán en
+Documentation/output. También se pueden generar en formatos LaTeX y ePub
+con::
+
+ make latexdocs
+ make epubdocs
+
+Convertirse en un/a desarrollador/a de kernel
+---------------------------------------------
+
+Si no sabe nada sobre el desarrollo del kernel de Linux, debería consultar
+el proyecto Linux KernelNewbies:
+
+ https://kernelnewbies.org
+
+Consiste en una útil lista de correo donde puede preguntar casi cualquier
+tipo de pregunta básica de desarrollo del kernel (asegúrese de buscar en
+los archivos primero, antes de preguntar algo que ya ha sido respondido en
+el pasado.) También tiene un canal IRC que puede usar para hacer preguntas
+en tiempo real, y una gran cantidad de documentación útil para ir
+aprendiendo sobre el desarrollo del kernel de Linux.
+
+El sitio web tiene información básica sobre la organización del código,
+subsistemas, y proyectos actuales (tanto dentro como fuera del árbol).
+También describe alguna información logística básica, como cómo compilar
+un kernel y aplicar un parche.
+
+Si no sabe por dónde quiere empezar, pero quieres buscar alguna tarea que
+comenzar a hacer para unirse a la comunidad de desarrollo del kernel,
+acuda al proyecto Linux Kernel Janitor:
+
+ https://kernelnewbies.org/KernelJanitors
+
+Es un gran lugar para comenzar. Describe una lista de problemas
+relativamente simples que deben limpiarse y corregirse dentro del código
+fuente del kernel de Linux árbol de fuentes. Trabajando con los
+desarrolladores a cargo de este proyecto, aprenderá los conceptos básicos
+para incluir su parche en el árbol del kernel de Linux, y posiblemente
+descubrir en la dirección en que trabajar a continuación, si no tiene ya
+una idea.
+
+Antes de realizar cualquier modificación real al código del kernel de
+Linux, es imperativo entender cómo funciona el código en cuestión. Para
+este propósito, nada es mejor que leerlo directamente (lo más complicado
+está bien comentado), tal vez incluso con la ayuda de herramientas
+especializadas. Una de esas herramientas que se recomienda especialmente
+es el proyecto Linux Cross-Reference, que es capaz de presentar el código
+fuente en un formato de página web indexada y autorreferencial. Una
+excelente puesta al día del repositorio del código del kernel se puede
+encontrar en:
+
+ https://elixir.bootlin.com/
+
+El proceso de desarrollo
+------------------------
+
+El proceso de desarrollo del kernel de Linux consiste actualmente de
+diferentes "branches" (ramas) con muchos distintos subsistemas específicos
+a cada una de ellas. Las diferentes ramas son:
+
+ - El código principal de Linus (mainline tree)
+ - Varios árboles estables con múltiples major numbers
+ - Subsistemas específicos
+ - linux-next, para integración y testing
+
+Mainline tree (Árbol principal)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+El mainline tree es mantenido por Linus Torvalds, y puede encontrarse en
+https://kernel.org o en su repo. El proceso de desarrollo es el siguiente:
+
+ - Tan pronto como se lanza un nuevo kernel, se abre una ventana de dos
+ semanas, durante este período de tiempo, los maintainers pueden enviar
+ grandes modificaciones a Linus, por lo general los parches que ya se
+ han incluido en el linux-next durante unas semanas. La forma preferida
+ de enviar grandes cambios es usando git (la herramienta de
+ administración de código fuente del kernel, más información al respecto
+ en https://git-scm.com/), pero los parches simples también son validos.
+ - Después de dos semanas, se lanza un kernel -rc1 y la atención se centra
+ en hacer el kernel nuevo lo más estable ("solido") posible. La mayoría
+ de los parches en este punto deben arreglar una regresión. Los errores
+ que siempre han existido no son regresiones, por lo tanto, solo envíe
+ este tipo de correcciones si son importantes. Tenga en cuenta que se
+ podría aceptar un controlador (o sistema de archivos) completamente
+ nuevo después de -rc1 porque no hay riesgo de causar regresiones con
+ tal cambio, siempre y cuando el cambio sea autónomo y no afecte áreas
+ fuera del código que se está agregando. git se puede usar para enviar
+ parches a Linus después de que se lance -rc1, pero los parches también
+ deben ser enviado a una lista de correo pública para su revisión.
+ - Se lanza un nuevo -rc cada vez que Linus considera que el árbol git
+ actual esta en un estado razonablemente sano y adecuado para la prueba.
+ La meta es lanzar un nuevo kernel -rc cada semana.
+ - El proceso continúa hasta que el kernel se considera "listo", y esto
+ puede durar alrededor de 6 semanas.
+
+Vale la pena mencionar lo que Andrew Morton escribió en las listas de
+correo del kernel de Linux, sobre lanzamientos del kernel (traducido):
+
+ *"Nadie sabe cuándo se publicara un nuevo kernel, pues esto sucede
+ según el estado de los bugs, no de una cronología preconcebida."*
+
+Varios árboles estables con múltiples major numbers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Los kernels con versiones de 3 partes son kernels estables. Estos contienen
+correcciones relativamente pequeñas y críticas para problemas de seguridad
+o importantes regresiones descubiertas para una publicación de código.
+Cada lanzamiento en una gran serie estable incrementa la tercera parte de
+la versión número, manteniendo las dos primeras partes iguales.
+
+Esta es la rama recomendada para los usuarios que quieren la versión
+estable más reciente del kernel, y no están interesados en ayudar a probar
+versiones en desarrollo/experimentales.
+
+Los árboles estables son mantenidos por el equipo "estable"
+<stable@vger.kernel.org>, y se liberan (publican) según lo dicten las
+necesidades. El período de liberación normal es de aproximadamente dos
+semanas, pero puede ser más largo si no hay problemas apremiantes. Un
+problema relacionado con la seguridad, en cambio, puede causar un
+lanzamiento casi instantáneamente.
+
+El archivo :ref:`Documentación/proceso/stable-kernel-rules.rst <stable_kernel_rules>`
+en el árbol del kernel documenta qué tipos de cambios son aceptables para
+el árbol estable y cómo funciona el proceso de lanzamiento.
+
+Subsistemas específicos
+~~~~~~~~~~~~~~~~~~~~~~~~
+Los maintainers de los diversos subsistemas del kernel --- y también muchos
+desarrolladores de subsistemas del kernel --- exponen su estado actual de
+desarrollo en repositorios fuente. De esta manera, otros pueden ver lo que
+está sucediendo en las diferentes áreas del kernel. En áreas donde el
+desarrollo es rápido, se le puede pedir a un desarrollador que base sus
+envíos en tal árbol del subsistema del kernel, para evitar conflictos entre
+este y otros trabajos ya en curso.
+
+La mayoría de estos repositorios son árboles git, pero también hay otros
+SCM en uso, o colas de parches que se publican como series quilt. Las
+direcciones de estos repositorios de subsistemas se enumeran en el archivo
+MAINTAINERS. Muchos de estos se pueden ver en https://git.kernel.org/.
+
+Antes de que un parche propuesto se incluya con dicho árbol de subsistemas,
+es sujeto a revisión, que ocurre principalmente en las listas de correo
+(ver la sección respectiva a continuación). Para varios subsistemas del
+kernel, esta revisión se rastrea con la herramienta patchwork. Patchwork
+ofrece una interfaz web que muestra publicaciones de parches, cualquier
+comentario sobre un parche o revisiones a él, y los maintainers pueden
+marcar los parches como en revisión, aceptado, o rechazado. La mayoría de
+estos sitios de trabajo de parches se enumeran en
+
+https://patchwork.kernel.org/.
+
+linux-next, para integración y testing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Antes de que las actualizaciones de los árboles de subsistemas se combinen
+con el árbol principal, necesitan probar su integración. Para ello, existe
+un repositorio especial de pruebas en el que se encuentran casi todos los
+árboles de subsistema, actualizado casi a diario:
+
+ https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
+
+De esta manera, linux-next ofrece una perspectiva resumida de lo que se
+espera que entre en el kernel principal en el próximo período de "merge"
+(fusión de código). Los testers aventureros son bienvenidos a probar
+linux-next en ejecución.
+
+Reportar bugs
+-------------
+
+El archivo 'Documentación/admin-guide/reporting-issues.rst' en el
+directorio principal del kernel describe cómo informar un posible bug del
+kernel y detalles sobre qué tipo de información necesitan los
+desarrolladores del kernel para ayudar a rastrear la fuente del problema.
+
+Gestión de informes de bugs
+------------------------------
+
+Una de las mejores formas de poner en práctica sus habilidades de hacking
+es arreglando errores reportados por otras personas. No solo ayudará a
+hacer el kernel más estable, también aprenderá a solucionar problemas del
+mundo real y mejora sus habilidades, y otros desarrolladores se darán
+cuenta de tu presencia. La corrección de errores es una de las mejores
+formas de ganar méritos entre desarrolladores, porque no a muchas personas
+les gusta perder el tiempo arreglando los errores de otras personas.
+
+Para trabajar en informes de errores ya reportados, busque un subsistema
+que le interese. Verifique el archivo MAINTAINERS donde se informan los
+errores de ese subsistema; con frecuencia será una lista de correo, rara
+vez un rastreador de errores (bugtracker). Busque en los archivos de dicho
+lugar para informes recientes y ayude donde lo crea conveniente. También es
+posible que desee revisar https://bugzilla.kernel.org para informes de
+errores; solo un puñado de subsistemas del kernel lo emplean activamente
+para informar o rastrear; sin embargo, todos los errores para todo el kernel
+se archivan allí.
+
+Listas de correo
+-----------------
+
+Como se explica en algunos de los documentos anteriores, la mayoría de
+desarrolladores del kernel participan en la lista de correo del kernel de
+Linux. Detalles sobre cómo para suscribirse y darse de baja de la lista se
+pueden encontrar en:
+
+ http://vger.kernel.org/vger-lists.html#linux-kernel
+
+Existen archivos de la lista de correo en la web en muchos lugares
+distintos. Utilice un motor de búsqueda para encontrar estos archivos. Por
+ejemplo:
+
+ http://dir.gmane.org/gmane.linux.kernel
+
+Es muy recomendable que busque en los archivos sobre el tema que desea
+tratar, antes de publicarlo en la lista. Un montón de cosas ya discutidas
+en detalle solo se registran en los archivos de la lista de correo.
+
+La mayoría de los subsistemas individuales del kernel también tienen sus
+propias lista de correo donde hacen sus esfuerzos de desarrollo. Revise el
+archivo MAINTAINERS para obtener referencias de lo que estas listas para
+los diferentes grupos.
+
+Muchas de las listas están alojadas en kernel.org. La información sobre
+estas puede ser encontrada en:
+
+ http://vger.kernel.org/vger-lists.html
+
+Recuerde mantener buenos hábitos de comportamiento al usar las listas.
+Aunque un poco cursi, la siguiente URL tiene algunas pautas simples para
+interactuar con la lista (o cualquier lista):
+
+ http://www.albion.com/netiquette/
+
+Si varias personas responden a su correo, el CC (lista de destinatarios)
+puede hacerse bastante grande. No elimine a nadie de la lista CC: sin una
+buena razón, o no responda solo a la dirección de la lista. Acostúmbrese
+a recibir correos dos veces, una del remitente y otra de la lista, y no
+intente ajustar esto agregando encabezados de correo astutos, a la gente no
+le gustará.
+
+Recuerde mantener intacto el contexto y la atribución de sus respuestas,
+mantenga las líneas "El hacker John Kernel escribió ...:" en la parte
+superior de su respuesta, y agregue sus declaraciones entre las secciones
+individuales citadas en lugar de escribiendo en la parte superior del
+correo electrónico.
+
+Si incluye parches en su correo, asegúrese de que sean texto legible sin
+formato como se indica en :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`.
+Los desarrolladores del kernel no quieren lidiar con archivos adjuntos o
+parches comprimidos; y pueden querer comentar líneas individuales de su
+parche, que funciona sólo de esa manera. Asegúrese de emplear un programa
+de correo que no altere los espacios ni los tabuladores. Una buena primera
+prueba es enviarse el correo a usted mismo, e intentar aplicar su
+propio parche. Si eso no funciona, arregle su programa de correo o
+reemplace hasta que funcione.
+
+Sobretodo, recuerde de ser respetuoso con otros subscriptores.
+
+Colaborando con la comunidad
+----------------------------
+
+El objetivo de la comunidad del kernel es proporcionar el mejor kernel
+posible. Cuando envíe un parche para su aceptación, se revisará en sus
+méritos técnicos solamente. Entonces, ¿qué deberías ser?
+
+ - críticas
+ - comentarios
+ - peticiones de cambios
+ - peticiones de justificaciones
+ - silencio
+
+Recuerde, esto es parte de introducir su parche en el kernel. Tiene que ser
+capaz de recibir críticas y comentarios sobre sus parches, evaluar
+a nivel técnico y re-elaborar sus parches o proporcionar razonamiento claro
+y conciso de por qué no se deben hacer tales cambios. Si no hay respuestas
+a su publicación, espere unos días e intente de nuevo, a veces las cosas se
+pierden dado el gran volumen.
+
+¿Qué no debería hacer?
+
+ - esperar que su parche se acepte sin preguntas
+ - actuar de forma defensiva
+ - ignorar comentarios
+ - enviar el parche de nuevo, sin haber aplicados los cambios pertinentes
+
+En una comunidad que busca la mejor solución técnica posible, siempre habrá
+diferentes opiniones sobre lo beneficioso que es un parche. Tiene que ser
+cooperativo y estar dispuesto a adaptar su idea para que encaje dentro
+del kernel, o al menos esté dispuesto a demostrar que su idea vale la pena.
+Recuerde, estar equivocado es aceptable siempre y cuando estés dispuesto a
+trabajar hacia una solución que sea correcta.
+
+Es normal que las respuestas a su primer parche sean simplemente una lista
+de una docena de cosas que debe corregir. Esto **no** implica que su
+parche no será aceptado, y **no** es personal. Simplemente corrija todos
+los problemas planteados en su parche, y envié otra vez.
+
+Diferencias entre la comunidad kernel y las estructuras corporativas
+--------------------------------------------------------------------
+
+La comunidad del kernel funciona de manera diferente a la mayoría de los
+entornos de desarrollo tradicionales en empresas. Aquí hay una lista de
+cosas que puede intentar hacer para evitar problemas:
+
+ Cosas buenas que decir respecto a los cambios propuestos:
+
+ - "Esto arregla múltiples problemas."
+ - "Esto elimina 2000 lineas de código."
+ - "Aquí hay un parche que explica lo que intento describir."
+ - "Lo he testeado en 5 arquitecturas distintas..."
+ - "Aquí hay una serie de parches menores que..."
+ - "Esto mejora el rendimiento en maquinas típicas..."
+
+ Cosas negativas que debe evitar decir:
+
+ - "Lo hicimos así en AIX/ptx/Solaris, de modo que debe ser bueno..."
+ - "Llevo haciendo esto 20 años, de modo que..."
+ - "Esto lo necesita mi empresa para ganar dinero"
+ - "Esto es para la linea de nuestros productos Enterprise"
+ - "Aquí esta el documento de 1000 paginas describiendo mi idea"
+ - "Llevo 6 meses trabajando en esto..."
+ - "Aquí esta un parche de 5000 lineas que..."
+ - "He rescrito todo el desastre actual, y aquí esta..."
+ - "Tengo un deadline, y este parche debe aplicarse ahora."
+
+Otra forma en que la comunidad del kernel es diferente a la mayoría de los
+entornos de trabajo tradicionales en ingeniería de software, es la
+naturaleza sin rostro de interacción. Una de las ventajas de utilizar el
+correo electrónico y el IRC como formas principales de comunicación es la
+no discriminación por motivos de género o raza. El entorno de trabajo del
+kernel de Linux acepta a mujeres y minorías porque todo lo que eres es una
+dirección de correo electrónico. El aspecto internacional también ayuda a
+nivelar el campo de juego porque no puede adivinar el género basado en
+el nombre de una persona. Un hombre puede llamarse Andrea y una mujer puede
+llamarse Pat. La mayoría de las mujeres que han trabajado en el kernel de
+Linux y han expresado una opinión han tenido experiencias positivas.
+
+La barrera del idioma puede causar problemas a algunas personas que no se
+sientes cómodas con el inglés. Un buen dominio del idioma puede ser
+necesario para transmitir ideas correctamente en las listas de correo, por
+lo que le recomendamos que revise sus correos electrónicos para asegurarse
+de que tengan sentido en inglés antes de enviarlos.
+
+Divida sus cambios
+---------------------
+
+La comunidad del kernel de Linux no acepta con gusto grandes fragmentos de
+código, sobretodo a la vez. Los cambios deben introducirse correctamente,
+discutidos y divididos en pequeñas porciones individuales. Esto es casi
+exactamente lo contrario de lo que las empresas están acostumbradas a hacer.
+Su propuesta también debe introducirse muy temprano en el proceso de
+desarrollo, de modo que pueda recibir comentarios sobre lo que está
+haciendo. También deje que la comunidad sienta que está trabajando con
+ellos, y no simplemente usándolos como un vertedero para su función. Sin
+embargo, no envíe 50 correos electrónicos a una vez a una lista de correo,
+su serie de parches debe casi siempre ser más pequeña que eso.
+
+Las razones para dividir las cosas son las siguientes:
+
+1) Los cambios pequeños aumentan la probabilidad de que sus parches sean
+ aplicados, ya que no requieren mucho tiempo o esfuerzo para verificar su
+ exactitud. Un parche de 5 líneas puede ser aplicado por un maintainer
+ con apenas una segunda mirada. Sin embargo, un parche de 500 líneas
+ puede tardar horas en ser revisado en términos de corrección (el tiempo
+ que toma es exponencialmente proporcional al tamaño del parche, o algo
+ así).
+
+ Los parches pequeños también facilitan la depuración cuando algo falla.
+ Es mucho más fácil retirar los parches uno por uno que diseccionar un
+ parche muy grande después de haber sido aplicado (y roto alguna cosa).
+
+2) Es importante no solo enviar pequeños parches, sino también reescribir
+ y simplificar (o simplemente reordenar) los parches antes de enviarlos.
+
+Esta es una analogía del desarrollador del kernel Al Viro (traducida):
+
+ *"Piense en un maestro que califica la tarea de un estudiante de
+ matemáticas. El maestro no quiere ver los intentos y errores del
+ estudiante antes de que se les ocurriera la solución. Quiere ver la
+ respuesta más limpia y elegante. Un buen estudiante lo sabe, y nunca
+ presentaría su trabajo intermedio antes de tener la solución final.*
+
+ *Lo mismo ocurre con el desarrollo del kernel. Los maintainers y
+ revisores no quieren ver el proceso de pensamiento detrás de la solución
+ al problema que se está resolviendo. Quieren ver un solución simple y
+ elegante."*
+
+Puede resultar un reto mantener el equilibrio entre presentar una solución
+elegante y trabajar junto a la comunidad, discutiendo su trabajo inacabado.
+Por lo tanto, es bueno comenzar temprano en el proceso para obtener
+"feedback" y mejorar su trabajo, pero también mantenga sus cambios en
+pequeños trozos que pueden ser aceptados, incluso cuando toda su labor no
+está listo para inclusión en un momento dado.
+
+También tenga en cuenta que no es aceptable enviar parches para su
+inclusión que están sin terminar y serán "arreglados más tarde".
+
+Justifique sus cambios
+----------------------
+
+Además de dividir sus parches, es muy importante que deje a la comunidad de
+Linux sabe por qué deberían agregar este cambio. Nuevas características
+debe justificarse como necesarias y útiles.
+
+Documente sus cambios
+---------------------
+
+Cuando envíe sus parches, preste especial atención a lo que dice en el
+texto de su correo electrónico. Esta información se convertirá en el
+ChangeLog del parche, y se conservará para que todos la vean, todo el
+tiempo. Debe describir el parche por completo y contener:
+
+ - por qué los cambios son necesarios
+ - el diseño general de su propuesta
+ - detalles de implementación
+ - resultados de sus experimentos
+
+Para obtener más detalles sobre cómo debería quedar todo esto, consulte la
+sección ChangeLog del documento:
+
+ "The Perfect Patch"
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+Todas estas cuestiones son a veces son muy difíciles de conseguir. Puede
+llevar años perfeccionar estas prácticas (si es que lo hace). Es un proceso
+continuo de mejora que requiere mucha paciencia y determinación. Pero no se
+rinda, es posible. Muchos lo han hecho antes, y cada uno tuvo que comenzar
+exactamente donde está usted ahora.
+
+----------
+
+Gracias a Paolo Ciarrocchi que permitió que la sección "Development Process"
+se basara en el texto que había escrito (https://lwn.net/Articles/94386/),
+y a Randy Dunlap y Gerrit Huizenga por algunas de la lista de cosas que
+debes y no debes decir. También gracias a Pat Mochel, Hanna Linder, Randy
+Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook,
+Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk,
+Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael Kerrisk y
+Alex Shepard por su revisión, comentarios y contribuciones. Sin su ayuda,
+este documento no hubiera sido posible.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/translations/sp_SP/index.rst b/Documentation/translations/sp_SP/index.rst
new file mode 100644
index 000000000000..5c2a2131524b
--- /dev/null
+++ b/Documentation/translations/sp_SP/index.rst
@@ -0,0 +1,81 @@
+
+=====================
+Traducción al español
+=====================
+
+.. raw:: latex
+
+ \kerneldocCJKoff
+
+:maintainer: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_disclaimer:
+
+Advertencia
+===========
+
+El objetivo de esta traducción es facilitar la lectura y comprensión para
+aquellos que no entiendan inglés o duden de sus interpretaciones, o
+simplemente para aquellos que prefieran leer en el idioma español. Sin
+embargo, tenga en cuenta que la *única* documentación oficial es la que
+está en inglés: :ref:`linux_doc`
+
+La propagación simultánea de la traducción de una modificación en
+:ref:`linux_doc` es altamente improbable. Los maintainers y colaboradores
+de la traducción intentan mantener sus traducciones al día, en tanto les
+es posible. Por tanto, no existe ninguna garantía de que una traducción
+esté actualizada con las últimas modificaciones. Si lo que lee en una
+traducción no se corresponde con lo que ve en el código fuente, informe
+al maintainer de la traducción y, si puede, consulte la documentación en
+inglés.
+
+Una traducción no es una * bifurcación * de la documentación oficial, por
+lo que los usuarios no encontrarán aquí ninguna información que no sea la
+versión oficial. Cualquier adición, supresión o modificación de los
+contenidos deberá ser realizada anteriormente en los documentos en inglés.
+Posteriormente, y cuando sea posible, dicho cambio debería aplicarse
+también a las traducciones. Los maintainers de las traducciones aceptan
+contribuciones que son puramente de interés relativo a la traducción (por
+ejemplo, nuevas traducciones, actualizaciones, correcciones, etc.).
+
+Las traducciones tratan de ser lo más precisas posible pero no es posible
+convertir directamente un idioma a otro. Cada idioma tiene su propia
+gramática, y una cultura tras ella, por lo tanto, la traducción de una
+oración al inglés se podría modificar para adaptarla al español. Por esta
+razón, cuando lea esta traducción, puede encontrar algunas diferencias en
+la forma, pero todavía transmiten el mensaje original. A pesar de la gran
+difusión del inglés en el idioma hablado, cuando sea posible, expresiones
+en inglés serán reemplazadas por las palabras correspondientes en español.
+
+Si necesita ayuda para comunicarse con la comunidad de Linux pero no se
+siente cómodo escribiendo en inglés, puede pedir ayuda al maintainer para
+obtener una traducción.
+
+Muchos países hablan español, cada uno con su propia cultura, expresiones,
+y diferencias gramaticales en ocasiones significativas. Las traducciones de
+los maintainers pueden utilizar el español con el que dichos maintainers se
+sientan más cómodos. En principio, estas pequeñas diferencias no deberían
+suponer una gran barrera para hablantes de distintas versiones del español,
+pero en caso de duda se puede consultar a los maintainers.
+
+La documentación del kernel Linux
+=================================
+
+Este es el nivel superior de la documentación del kernel en idioma español.
+La traducción es incompleta, y podría encontrar advertencias que indiquen
+la falta de una traducción o de un grupo de traducciones.
+
+En términos más generales, la documentación, como el kernel mismo, están en
+constante desarrollo. Las mejoras en la documentación siempre son
+bienvenidas; de modo que, si desea ayudar, únase a la lista de correo
+linux-doc en vger.kernel.org.
+
+Traducciones al español
+=======================
+
+.. toctree::
+ :maxdepth: 1
+
+ howto
+ process/index
+ wrappers/memory-barriers
diff --git a/Documentation/translations/sp_SP/memory-barriers.txt b/Documentation/translations/sp_SP/memory-barriers.txt
new file mode 100644
index 000000000000..f62bd797216d
--- /dev/null
+++ b/Documentation/translations/sp_SP/memory-barriers.txt
@@ -0,0 +1,3134 @@
+NOTE:
+This is a version of Documentation/memory-barriers.txt translated into
+Spanish by Carlos Bilbao <carlos.bilbao@amd.com>. If you find any
+difference between this document and the original file or a problem with
+the translation, please contact the maintainer of this file. Please also
+note that the purpose of this file is to be easier to read for non English
+(read: Spanish) speakers and is not intended as a fork. So if you have any
+comments or updates for this file please update the original English file
+first. The English version is definitive, and readers should look there if
+they have any doubt.
+
+ ======================================
+ BARRERAS DE MEMORIA EN EL KERNEL LINUX
+ ======================================
+
+Documento original: David Howells <dhowells@redhat.com>
+ Paul E. McKenney <paulmck@linux.ibm.com>
+ Will Deacon <will.deacon@arm.com>
+ Peter Zijlstra <peterz@infradead.org>
+
+Traducido por: Carlos Bilbao <carlos.bilbao@amd.com>
+Nota: Si tiene alguna duda sobre la exactitud del contenido de esta
+traducción, la única referencia válida es la documentación oficial en
+inglés.
+
+===========
+ADVERTENCIA
+===========
+
+Este documento no es una especificación; es intencionalmente (por motivos
+de brevedad) y sin querer (por ser humanos) incompleta. Este documento
+pretende ser una guía para usar las diversas barreras de memoria
+proporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor
+pregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de
+consistencia de memoria formal y documentación en tools/memory-model/. Sin
+embargo, incluso este modelo debe ser visto como la opinión colectiva de
+sus maintainers en lugar de que como un oráculo infalible.
+
+De nuevo, este documento no es una especificación de lo que Linux espera
+del hardware.
+
+El propósito de este documento es doble:
+
+ (1) especificar la funcionalidad mínima en la que se puede confiar para
+ cualquier barrera en concreto, y
+
+ (2) proporcionar una guía sobre cómo utilizar las barreras disponibles.
+
+Tenga en cuenta que una arquitectura puede proporcionar más que el
+requisito mínimo para cualquier barrera en particular, pero si la
+arquitectura proporciona menos de eso, dicha arquitectura es incorrecta.
+
+Tenga en cuenta también que es posible que una barrera no valga (sea no-op)
+para alguna arquitectura porque por la forma en que funcione dicha
+arquitectura, la barrera explícita resulte innecesaria en ese caso.
+
+==========
+CONTENIDOS
+==========
+
+ (*) Modelo abstracto de acceso a memoria.
+
+ - Operaciones del dispositivo.
+ - Garantías.
+
+ (*) ¿Qué son las barreras de memoria?
+
+ - Variedades de barrera de memoria.
+ - ¿Qué no se puede asumir sobre las barreras de memoria?
+ - Barreras de dirección-dependencia (históricas).
+ - Dependencias de control.
+ - Emparejamiento de barreras smp.
+ - Ejemplos de secuencias de barrera de memoria.
+ - Barreras de memoria de lectura frente a especulación de carga.
+ - Atomicidad multicopia.
+
+ (*) Barreras explícitas del kernel.
+
+ - Barrera del compilador.
+ - Barreras de memoria de la CPU.
+
+ (*) Barreras de memoria implícitas del kernel.
+
+ - Funciones de adquisición de cerrojo.
+ - Funciones de desactivación de interrupciones.
+ - Funciones de dormir y despertar.
+ - Funciones varias.
+
+ (*) Efectos de barrera adquiriendo intra-CPU.
+
+ - Adquisición vs accesos a memoria.
+
+ (*) ¿Dónde se necesitan barreras de memoria?
+
+ - Interacción entre procesadores.
+ - Operaciones atómicas.
+ - Acceso a dispositivos.
+ - Interrupciones.
+
+ (*) Efectos de barrera de E/S del kernel.
+
+ (*) Modelo de orden mínimo de ejecución asumido.
+
+ (*) Efectos de la memoria caché de la CPU.
+
+ - Coherencia de caché.
+ - Coherencia de caché frente a DMA.
+ - Coherencia de caché frente a MMIO.
+
+ (*) Cosas que hacen las CPU.
+
+ - Y luego está el Alfa.
+ - Guests de máquinas virtuales.
+
+ (*) Ejemplos de usos.
+
+ - Buffers circulares.
+
+ (*) Referencias.
+
+
+====================================
+MODELO ABSTRACTO DE ACCESO A MEMORIA
+====================================
+
+Considere el siguiente modelo abstracto del sistema:
+
+ : :
+ : :
+ : :
+ +-------+ : +--------+ : +-------+
+ | | : | | : | |
+ | | : | | : | |
+ | CPU 1 |<----->| Memoria|<----->| CPU 2 |
+ | | : | | : | |
+ | | : | | : | |
+ +-------+ : +--------+ : +-------+
+ ^ : ^ : ^
+ | : | : |
+ | : | : |
+ | : v : |
+ | : +--------+ : |
+ | : | | : |
+ | : | Disposi| : |
+ +---------->| tivo |<----------+
+ : | | :
+ : | | :
+ : +--------+ :
+ : :
+
+Cada CPU ejecuta un programa que genera operaciones de acceso a la memoria.
+En la CPU abstracta, el orden de las operaciones de memoria es muy
+relajado, y una CPU en realidad puede realizar las operaciones de memoria
+en el orden que desee, siempre que la causalidad del programa parezca
+mantenerse. De manera similar, el compilador también puede organizar las
+instrucciones que emite en el orden que quiera, siempre que no afecte al
+funcionamiento aparente del programa.
+
+Entonces, en el diagrama anterior, los efectos de las operaciones de
+memoria realizadas por un CPU son percibidos por el resto del sistema a
+medida que las operaciones cruzan la interfaz entre la CPU y el resto del
+sistema (las líneas discontinuas a puntos).
+
+Por ejemplo, considere la siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1; B == 2 }
+ A = 3; x = B;
+ B = 4; y = A;
+
+El conjunto de accesos visto por el sistema de memoria en el medio se puede
+organizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es
+guardar):
+
+STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4
+STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3
+STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4
+STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4
+STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3
+STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4
+STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4
+STORE B=4, ...
+...
+
+y por lo tanto puede resultar en cuatro combinaciones diferentes de
+valores:
+
+x == 2, y == 1
+x == 2, y == 3
+x == 4, y == 1
+x == 4, y == 3
+
+Además, los stores asignados por una CPU al sistema de memoria pueden no
+ser percibidos por los loads realizados por otra CPU en el mismo orden en
+que fueron realizados.
+
+Como otro ejemplo, considere esta secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4; Q = P;
+ P = &B; D = *Q;
+
+Aquí hay una dependencia obvia de la dirección, ya que el valor cargado en
+D depende en la dirección recuperada de P por la CPU 2. Al final de la
+secuencia, cualquiera de los siguientes resultados son posibles:
+
+ (Q == &A) y (D == 1)
+ (Q == &B) y (D == 2)
+ (Q == &B) y (D == 4)
+
+Tenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU
+cargará P en Q antes de emitir la carga de *Q.
+
+OPERACIONES DEL DISPOSITIVO
+---------------------------
+
+Algunos dispositivos presentan sus interfaces de control como colecciones
+de ubicaciones de memoria, pero el orden en que se accede a los registros
+de control es muy importante. Por ejemplo, imagine una tarjeta ethernet con
+un conjunto de registros a los que se accede a través de un registro de
+puerto de dirección (A) y un registro de datos del puerto (D). Para leer el
+registro interno 5, el siguiente código podría entonces ser usado:
+
+ *A = 5;
+ x = *D;
+
+pero esto podría aparecer como cualquiera de las siguientes dos secuencias:
+
+ STORE *A = 5, x = LOAD *D
+ x = LOAD *D, STORE *A = 5
+
+el segundo de las cuales casi con certeza resultará en mal funcionamiento,
+ya que se estableció la dirección _después_ de intentar leer el registro.
+
+
+GARANTÍAS
+---------
+
+Hay algunas garantías mínimas que se pueden esperar de una CPU:
+
+ (*) En cualquier CPU dada, los accesos a la memoria dependiente se
+ emitirán en orden, con respeto a sí mismo. Esto significa que para:
+
+ Q = READ_ONCE(P); D = READ_ONCE(*Q);
+
+ donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes
+ operaciones de memoria:
+
+ Q = LOAD P, D = LOAD *Q
+
+ y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también
+ emite una instrucción de barrera de memoria, de modo que una CPU DEC
+ Alpha, sin embargo emite las siguientes operaciones de memoria:
+
+ Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER
+
+ Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador
+ haga cosas inapropiadas.
+
+ (*) Los loads y stores superpuestos dentro de una CPU en particular
+ parecerán ser ordenados dentro de esa CPU. Esto significa que para:
+
+ a = READ_ONCE(*X); WRITE_ONCE(*X, b);
+
+ donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la
+ siguiente secuencia de operaciones de memoria:
+
+ a = LOAD *X, STORE *X = b
+
+ Y para:
+
+ WRITE_ONCE(*X, c); d = READ_ONCE(*X);
+
+ la CPU solo emitirá:
+
+ STORE *X = c, d = LOAD *X
+
+ (Los loads y stores se superponen si están destinados a piezas
+ superpuestas de memoria).
+
+Y hay una serie de cosas que _deben_ o _no_ deben asumirse:
+
+ (*) _No_debe_ asumirse que el compilador hará lo que usted quiera
+ con referencias de memoria que no están protegidas por READ_ONCE() y
+ WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo
+ de transformaciones "creativas", que se tratan en la sección BARRERA
+ DEL COMPILADOR.
+
+ (*) _No_debe_ suponerse que se emitirán loads y stores independientes
+ en el orden dado. Esto significa que para:
+
+ X = *A; Y = *B; *D = Z;
+
+ podemos obtener cualquiera de las siguientes secuencias:
+
+ X = LOAD *A, Y = LOAD *B, STORE *D = Z
+ X = LOAD *A, STORE *D = Z, Y = LOAD *B
+ Y = LOAD *B, X = LOAD *A, STORE *D = Z
+ Y = LOAD *B, STORE *D = Z, X = LOAD *A
+ STORE *D = Z, X = LOAD *A, Y = LOAD *B
+ STORE *D = Z, Y = LOAD *B, X = LOAD *A
+
+ (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden
+ fusionarse o ser descartados. Esto significa que para:
+
+ X = *A; Y = *(A + 4);
+
+ podemos obtener cualquiera de las siguientes secuencias:
+
+X = LOAD *A; Y = LOAD *(A + 4);
+Y = LOAD *(A + 4); X = LOAD *A;
+{X, Y} = LOAD {*A, *(A + 4) };
+
+ Y para:
+
+*A = X; *(A + 4) = Y;
+
+ podemos obtener cualquiera de:
+
+STORE *A = X; STORE *(A + 4) = Y;
+STORE *(A + 4) = Y; STORE *A = X;
+STORE {*A, *(A + 4) } = {X, Y};
+
+Y hay anti-garantías:
+
+(*) Estas garantías no se aplican a los campos de bits, porque los
+ compiladores a menudo generan código para modificarlos usando
+ secuencias de lectura-modificación-escritura no atómica. No intente
+ utilizar campos de bits para sincronizar algoritmos paralelos.
+
+(*) Incluso en los casos en que los campos de bits están protegidos por
+ cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo
+ de bits dado deben estar protegidos por un candado. Si dos campos en un
+ campo de bits dado están protegidos por diferentes locks, las
+ secuencias de lectura-modificación-escritura no atómicas del lock
+ pueden causar una actualización a una campo para corromper el valor de
+ un campo adyacente.
+
+(*) Estas garantías se aplican solo a escalares correctamente alineados y
+ dimensionados. De "tamaño adecuado" significa actualmente variables que
+ son del mismo tamaño que "char", "short", "int" y "long".
+ "Adecuadamente alineado" significa la alineación natural, por lo tanto,
+ no hay restricciones para "char", alineación de dos bytes para "short",
+ alineación de cuatro bytes para "int", y alineación de cuatro u ocho
+ bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga
+ en cuenta que estos garantías se introdujeron en el estándar C11, así
+ que tenga cuidado cuando utilice compiladores anteriores a C11 (por
+ ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es
+ la Sección 3.14, que define "ubicación de memoria" de la siguiente
+ manera:
+
+ ubicación de memoria
+ ya sea un objeto de tipo escalar, o una secuencia máxima
+ de campos de bits adyacentes, todos con ancho distinto de cero
+
+ NOTE 1: Dos hilos de ejecución pueden actualizar y acceder
+ ubicaciones de memoria separadas sin interferir entre
+ ellos.
+
+ NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de
+ bits están en ubicaciones de memoria separadas. Lo mismo sucede con
+ dos campos de bits, si uno se declara dentro de un declaración de
+ estructura anidada y el otro no, o si las dos están separados por una
+ declaración de campo de bits de longitud cero, o si están separados por
+ un miembro no declarado como campo de bits. No es seguro actualizar
+ simultáneamente dos campos de bits en la misma estructura si entre
+ todos los miembros declarados también hay campos de bits, sin importar
+ cuál resulta ser el tamaño de estos campos de bits intermedios.
+
+
+==================================
+¿QUÉ SON LAS BARRERAS DE MEMORIA?
+==================================
+
+Como se puede leer arriba, las operaciones independientes de memoria se
+realizan de manera efectiva en orden aleatorio, pero esto puede ser un
+problema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se
+requiere es alguna forma de intervenir para instruir al compilador y al
+CPU para restringir el orden.
+
+Las barreras de memoria son este tipo de intervenciones. Imponen una
+percepción de orden parcial, sobre las operaciones de memoria a ambos lados
+de la barrera.
+
+Tal cumplimiento es importante porque las CPUs y otros dispositivos en un
+sistema pueden usar una variedad de trucos para mejorar el rendimiento,
+incluido el reordenamiento, diferimiento y combinación de operaciones de
+memoria; cargas especulativas; predicción de "branches" especulativos y
+varios tipos de almacenamiento en caché. Las barreras de memoria se
+utilizan para anular o suprimir estos trucos, permitiendo que el código
+controle sensatamente la interacción de múltiples CPU y/o dispositivos.
+
+
+VARIEDADES DE BARRERA DE MEMORIA
+---------------------------------
+
+Las barreras de memoria vienen en cuatro variedades básicas:
+
+ (1) Barreras de memoria al escribir o almacenar (Write or store memory
+ barriers).
+
+ Una barrera de memoria de escritura garantiza que todas las
+ operaciones de STORE especificadas antes de que la barrera aparezca
+ suceden antes de todas las operaciones STORE especificadas después
+ de la barrera, con respecto a los otros componentes del sistema.
+
+ Una barrera de escritura es un orden parcial solo en los stores; No
+ es requerido que tenga ningún efecto sobre los loads.
+
+ Se puede considerar que una CPU envía una secuencia de operaciones de
+ store al sistema de memoria a medida que pasa el tiempo. Todos los
+ stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos
+ los stores después de la barrera de escritura.
+
+ [!] Tenga en cuenta que las barreras de escritura normalmente deben
+ combinarse con read o barreras de address-dependency barriers
+ (dependencia de dirección); consulte la subsección
+ "Emparejamiento de barreras smp".
+
+
+ (2) Barrera de dependencia de dirección (histórico).
+
+ Una barrera de dependencia de dirección es una forma más débil de
+ barrera de lectura. En el caso de que se realicen dos loads de manera
+ que la segunda dependa del resultado de la primera (por ejemplo: el
+ primer load recupera la dirección a la que se dirigirá el segundo
+ load), una barrera de dependencia de dirección sería necesaria para
+ asegurarse de que el objetivo de la segunda carga esté actualizado
+ después de acceder a la dirección obtenida por la primera carga.
+
+ Una barrera de dependencia de direcciones es una ordenación parcial en
+ laods de direcciones interdependientes; no se requiere que tenga
+ ningún efecto en los stores, ya sean cargas de memoria o cargas
+ de memoria superpuestas.
+
+ Como se mencionó en (1), las otras CPU en el sistema pueden verse como
+ secuencias de stores en el sistema de memoria que la considerada CPU
+ puede percibir. Una barrera de dependencia de dirección emitida por
+ la CPU en cuestión garantiza que para cualquier carga que la preceda,
+ si esa carga toca alguna secuencia de stores de otra CPU, entonces
+ en el momento en que la barrera se complete, los efectos de todos los
+ stores antes del cambio del load serán perceptibles por cualquier
+ carga emitida después la barrera de la dependencia de la dirección.
+
+ Consulte la subsección "Ejemplos de secuencias de barrera de memoria"
+ para ver los diagramas mostrando las restricciones de orden.
+
+ [!] Tenga en cuenta que la primera carga realmente tiene que tener una
+ dependencia de _dirección_ y no es una dependencia de control. Si la
+ dirección para la segunda carga depende de la primera carga, pero la
+ dependencia es a través de un condicional en lugar de -en realidad-
+ cargando la dirección en sí, entonces es una dependencia de _control_
+ y se requiere una barrera de lectura completa o superior. Consulte la
+ subsección "Dependencias de control" para más información.
+
+ [!] Tenga en cuenta que las barreras de dependencia de dirección
+ normalmente deben combinarse con barreras de escritura; consulte la
+ subsección "Emparejamiento de barreras smp".
+
+ [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras
+ de memoria de direcciones explícitas. Hoy en día, las APIs para marcar
+ cargas de variables compartidas, como READ_ONCE() y rcu_dereference(),
+ proporcionan barreras de dependencia de dirección implícitas.
+
+ (3) Barreras de memoria al leer o cargar (Read or load memory
+ barriers).
+
+ Una barrera de lectura es una barrera de dependencia de direcciones,
+ más una garantía de que todas las operaciones de LOAD especificadas
+ antes de la barrera parecerán ocurrir antes de todas las operaciones
+ de LOAD especificadas después de la barrera con respecto a los demás
+ componentes del sistema.
+
+ Una barrera de lectura es un orden parcial solo en cargas; no es
+ necesario que tenga ningún efecto en los stores.
+
+ Las barreras de memoria de lectura implican barreras de dependencia de
+ direcciones, y por tanto puede sustituirlas por estas.
+
+ [!] Tenga en mente que las barreras de lectura normalmente deben
+ combinarse con barreras de escritura; consulte la subsección
+ "Emparejamiento de barreras smp".
+
+ (4) Barreras de memoria generales
+
+ Una barrera de memoria general proporciona la garantía de que todas
+ las operaciones LOAD y STORE especificadas antes de que la barrera
+ aparezca suceden antes de que todas las operaciones LOAD y STORE
+ especificadas después de la barrera con respecto a los demás
+ componentes del sistema.
+
+ Una barrera de memoria general es un orden parcial tanto en
+ operaciones de carga como de almacenamiento.
+
+ Las barreras de memoria generales implican barreras de memoria tanto
+ de lectura como de escritura, de modo que pueden sustituir a
+ cualquiera.
+
+Y un par de variedades implícitas:
+
+ (5) ACQUIRE (de adquisición).
+
+ Esto actúa como una barrera permeable unidireccional. Garantiza que
+ toda las operaciones de memoria después de la operación ACQUIRE
+ parezcan suceder después de la ACQUIRE con respecto a los demás
+ componentes del sistema. Las operaciones ACQUIRE incluyen operaciones
+ LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire().
+
+ Las operaciones de memoria que ocurren antes de una operación ACQUIRE
+ pueden parecer suceder después de que se complete.
+
+ Una operación ACQUIRE casi siempre debe estar emparejada con una
+ operación RELEASE (de liberación).
+
+
+ (6) Operaciones RELEASE (de liberación).
+
+ Esto también actúa como una barrera permeable unidireccional.
+ Garantiza que todas las operaciones de memoria antes de la operación
+ RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a
+ los demás componentes del sistema. Las operaciones de RELEASE incluyen
+ operaciones de UNLOCK y operaciones smp_store_release().
+
+ Las operaciones de memoria que ocurren después de una operación
+ RELEASE pueden parecer suceder antes de que se complete.
+
+ El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la
+ necesidad de otros tipos de barrera de memoria. Además, un par
+ RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria
+ completa. Sin embargo, después de un ACQUIRE de una variable dada,
+ todos los accesos a la memoria que preceden a cualquier anterior
+ RELEASE en esa misma variable están garantizados como visibles. En
+ otras palabras, dentro de la sección crítica de una variable dada,
+ todos los accesos de todas las secciones críticas anteriores para esa
+ variable habrán terminado de forma garantizada.
+
+ Esto significa que ACQUIRE actúa como una operación mínima de
+ "adquisición" y RELEASE actúa como una operación mínima de
+ "liberación".
+
+Un subconjunto de las operaciones atómicas descritas en atomic_t.txt
+contiene variantes de ACQUIRE y RELEASE, además de definiciones
+completamente ordenadas o relajadas (sin barrera semántica). Para
+composiciones atómicas que realizan tanto un load como store, la semántica
+ACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a
+la parte de la operación del store.
+
+Las barreras de memoria solo son necesarias cuando existe la posibilidad de
+interacción entre dos CPU o entre una CPU y un dispositivo. Si se puede
+garantizar que no habrá tal interacción en ninguna pieza de código en
+particular, entonces las barreras de memoria son innecesarias en ese
+fragmento de código.
+
+Tenga en cuenta que estas son las garantías _mínimas_. Diferentes
+arquitecturas pueden proporcionar garantías más sustanciales, pero no se
+puede confiar en estas fuera de esa arquitectura en específico.
+
+
+¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA?
+---------------------------------------------------------
+
+Hay ciertas cosas que las barreras de memoria del kernel Linux no
+garantizan:
+
+ (*) No hay garantía de que ninguno de los accesos a la memoria
+ especificados antes de una barrera de memoria estará _completo_ al
+ completarse una instrucción de barrera de memoria; se puede considerar
+ que la barrera dibuja una línea en la cola de acceso del CPU que no
+ pueden cruzar los accesos del tipo correspondiente.
+
+ (*) No hay garantía de que la emisión de una barrera de memoria en una CPU
+ tenga cualquier efecto directo en otra CPU o cualquier otro hardware
+ en el sistema. El efecto indirecto será el orden en que la segunda CPU
+ ve los efectos de los primeros accesos que ocurren de la CPU, pero lea
+ el siguiente argumento:
+
+ (*) No hay garantía de que una CPU vea el orden correcto de los efectos
+ de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una
+ barrera de memoria, a menos que la primera CPU _también_ use una
+ barrera de memoria coincidente (vea el subapartado "Emparejamiento de
+ barrera SMP").
+
+ (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*]
+ del CPU no reordenará los accesos a la memoria. Los mecanismos de
+ coherencia de caché del CPU deben propagar los efectos indirectos de
+ una barrera de memoria entre las CPU, pero es posible que no lo hagan
+ en orden.
+
+ [*] Para obtener información sobre bus mastering DMA y coherencia, lea:
+
+ Documentation/driver-api/pci/pci.rst
+ Documentation/core-api/dma-api-howto.rst
+ Documentation/core-api/dma-api.rst
+
+
+BARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO)
+-----------------------------------------------
+
+A partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a
+READ_ONCE() para DEC Alpha, lo que significa que las únicas personas que
+necesitan prestar atención a esta sección son aquellas que trabajan en el
+código específico de la arquitectura DEC Alpha y aquellas que trabajan en
+READ_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que
+estén interesados ​​desde un punto de vista histórico, aquí está la historia
+de las barreras de dependencia de dirección.
+
+[!] Si bien las dependencias de direcciones se observan tanto en carga a
+carga como en relaciones de carga a store, las barreras de dependencia de
+dirección no son necesarias para situaciones de carga a store.
+
+El requisito de las barreras de dependencia de dirección es un poco sutil,
+y no siempre es obvio que sean necesarias. Para ilustrar, considere la
+siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE_OLD(P);
+ D = *Q;
+
+[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15,
+que no implica una barrera de dependencia de direcciones.
+
+Hay una clara dependencia de dirección aquí, y parecería que al final de
+la secuencia, Q debe ser &A o &B, y que:
+
+ (Q == &A) implica (D == 1)
+ (Q == &B) implica (D == 4)
+
+¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su
+percepción de B, por lo tanto dando lugar a la siguiente situación:
+
+ (Q == &B) y (D == 2) ????
+
+Si bien esto puede parecer una falla en el mantenimiento de la coherencia
+o la causalidad, no lo es, y este comportamiento se puede observar en
+ciertas CPU reales (como DEC Alfa).
+
+Para lidiar con esto, READ_ONCE() proporciona una barrera de dependencia
+de dirección implícita desde el lanzamiento del kernel v4.15:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE(P);
+ <barrera de dependencia de dirección implícita>
+ D = *Q;
+
+Esto refuerza la ocurrencia de una de las dos implicaciones, y previene la
+tercera posibilidad de surgir.
+
+
+[!] Tenga en cuenta que esta situación extremadamente contraria a la
+intuición surge más fácilmente en máquinas con cachés divididos, de modo
+que, por ejemplo, un banco de caché procesa líneas de caché pares y el otro
+banco procesa líneas impares de caché. El puntero P podría almacenarse en
+una línea de caché impar y la variable B podría almacenarse en una línea de
+caché con número par. Entonces, si el banco de números pares de la memoria
+caché de la CPU de lectura está extremadamente ocupado mientras que el
+banco impar está inactivo, uno podría ver el nuevo valor del puntero P
+(&B), pero el antiguo valor de la variable B (2).
+
+
+No se requiere una barrera de dependencia de dirección para ordenar
+escrituras dependientes porque las CPU que admite el kernel Linux no
+escriben hasta que están seguros (1) de que la escritura realmente
+sucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir.
+Pero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el
+archivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse
+y romper dependencias en muchas formas altamente creativas.
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C = 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE_OLD(P);
+ WRITE_ONCE(*Q, 5);
+
+Por lo tanto, no se requiere ninguna barrera de dependencia de direcciones
+para ordenar la lectura en Q con el load en *Q. En otras palabras, este
+resultado está prohibido, incluso sin una barrera de dependencia de
+dirección implícita del READ_ONCE() moderno:
+
+ (Q == &B) && (B == 4)
+
+Tenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo
+del orden de dependencia es -prevenir- escrituras en la estructura de
+datos, junto con los costosos errores de caché asociados con tales
+escrituras. Este patrón se puede utilizar para registrar raras condiciones
+de error y similares, y el orden natural de las CPUs evita que se pierdan
+tales registros.
+
+
+Tenga en cuenta que el orden proporcionado por una dependencia de dirección
+es local para la CPU que lo contiene. Lea la sección sobre "Atomicidad
+multicopia" para más información.
+
+
+La barrera de dependencia de dirección es muy importante para el sistema
+RCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en
+include/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero
+RCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo
+del reemplazo parezca estar inicializado de manera incompleta.
+
+Consulte también la subsección sobre "Coherencia de caché" para obtener un
+ejemplo más completo.
+
+DEPENDENCIAS DE CONTROL
+-----------------------
+
+Las dependencias de control pueden ser un poco complicadas porque los
+compiladores actuales no las entienden. El propósito de esta sección es
+ayudarle a prevenir que la ignorancia del compilador rompa su código.
+
+Una dependencia de control load-load (de carga a carga) requiere una
+barrera de memoria de lectura completa, no simplemente una barrera
+(implícita) de dependencia de direcciones para que funcione correctamente.
+Considere el siguiente fragmento de código:
+
+ q = READ_ONCE(a);
+ <barrera implícita de dependencia de direcciones>
+ if (q) {
+ /* BUG: No hay dependencia de dirección!!! */
+ p = READ_ONCE(b);
+ }
+
+Esto no tendrá el efecto deseado porque no hay una dependencia de dirección
+real, sino más bien una dependencia de control que la CPU puede
+cortocircuitar al intentar predecir el resultado por adelantado, para que
+otras CPU vean la carga de b como si hubiera ocurrido antes que la carga de
+a. En cuyo caso lo que realmente se requiere es:
+
+ q = READ_ONCE(a);
+ if (q) {
+ <barrera de lectura>
+ p = READ_ONCE(b);
+ }
+
+Sin embargo, los stores no se especulan. Esto significa que ordenar -es-
+provisto para dependencias de control de load-store, como en el siguiente
+ejemplo:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ }
+
+Las dependencias de control se emparejan normalmente con otros tipos de
+barreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE()
+son opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de
+'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría
+combinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos
+puede dar lugar a efectos en el orden muy contrarios a la intuición.
+
+Peor aún, si el compilador puede probar (decir) que el valor de la
+variable 'a' siempre es distinta de cero, estaría dentro de sus derechos
+para optimizar el ejemplo original eliminando la declaración "if", como:
+
+ q = a;
+ b = 1; /* BUG: Compilador y CPU pueden ambos reordernar!!! */
+
+Así que no deje de lado READ_ONCE().
+
+Es tentador tratar de hacer cumplir el orden en stores idénticos en ambos
+caminos del "if" de la siguiente manera:
+
+ q = READ_ONCE(a);
+ if (q) {
+ barrier();
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ barrier();
+ WRITE_ONCE(b, 1);
+ hacer_otra_cosa();
+ }
+
+Desafortunadamente, los compiladores actuales transformarán esto de la
+siguiente manera en casos de alto nivel de optimización:
+
+ q = READ_ONCE(a);
+ barrier();
+ WRITE_ONCE(b, 1); /* BUG: No hay orden en load de a!!! */
+ if (q) {
+ /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
+ hacer_algo();
+ } else {
+ /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
+ hacer_otra_cosa();
+ }
+
+Ahora no hay condicional entre la carga de 'a' y el store de 'b', lo que
+significa que la CPU está en su derecho de reordenarlos: El condicional es
+absolutamente necesario y debe estar presente en el código ensamblador
+incluso después de que se hayan aplicado todas las optimizaciones del
+compilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita
+explícitamente barreras de memoria, por ejemplo, smp_store_release():
+
+
+ q = READ_ONCE(a);
+ if (q) {
+ smp_store_release(&b, 1);
+ hacer_algo();
+ } else {
+ smp_store_release(&b, 1);
+ hacer_otra_cosa();
+ }
+
+Por el contrario, sin barreras de memoria explícita, el control de un if
+con dos opciones está garantizado solo cuando los stores difieren, por
+ejemplo:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Aún se requiere el inicial READ_ONCE() para evitar que el compilador toque
+el valor de 'a'.
+
+Además, debe tener cuidado con lo que hace con la variable local 'q', de lo
+contrario, el compilador podría adivinar el valor y volver a eliminar el
+necesario condicional. Por ejemplo:
+
+ q = READ_ONCE(a);
+ if (q % MAX) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Si MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual
+a cero, en cuyo caso el compilador tiene derecho a transformar el código
+anterior en el siguiente:
+
+ q = READ_ONCE(a);
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+
+Dada esta transformación, la CPU no está obligada a respetar el orden entre
+la carga de la variable 'a' y el store de la variable 'b'. Es tentador
+agregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la
+barrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe
+asegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera:
+
+ q = READ_ONCE(a);
+ BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */
+ if (q % MAX) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Tenga en cuenta una vez más que los stores de 'b' difieren. Si fueran
+idénticos, como se señaló anteriormente, el compilador podría sacar ese
+store fuera de la declaración 'if'.
+
+También debe tener cuidado de no confiar demasiado en el cortocircuito
+de la evaluación booleana. Considere este ejemplo:
+
+ q = READ_ONCE(a);
+ if (q || 1 > 0)
+ WRITE_ONCE(b, 1);
+
+Debido a que la primera condición no puede fallar y la segunda condición es
+siempre cierta, el compilador puede transformar este ejemplo de la
+siguiente manera, rompiendo la dependencia del control:
+
+ q = READ_ONCE(a);
+ WRITE_ONCE(b, 1);
+
+Este ejemplo subraya la necesidad de asegurarse de que el compilador no
+pueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza
+al compilador para emitir código para una carga dada, no fuerza al
+compilador para usar los resultados.
+
+Además, las dependencias de control se aplican solo a la cláusula then y
+la cláusula else de la sentencia if en cuestión. En particular, no se
+aplica necesariamente al código que sigue a la declaración if:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ } else {
+ WRITE_ONCE(b, 2);
+ }
+ WRITE_ONCE(c, 1); /* BUG: No hay orden para la lectura de 'a'. */
+
+Es tentador argumentar que, de hecho, existe un orden porque el compilador
+no puede reordenar accesos volátiles y tampoco puede reordenar escrituras
+en 'b' con la condición. Desafortunadamente para esta línea de
+razonamiento, el compilador podría compilar las dos escrituras en 'b' como
+instrucciones de movimiento condicional, como en este fantástico idioma
+pseudo-ensamblador:
+
+ ld r1,a
+ cmp r1,$0
+ cmov,ne r4,$1
+ cmov,eq r4,$2
+ st r4,b
+ st $1,c
+
+Una CPU débilmente ordenada no tendría dependencia de ningún tipo entre la
+carga de 'a' y el store de 'c'. Las dependencias de control se extenderían
+solo al par de instrucciones cmov y el store dependiente de ellas. En
+resumen, las dependencias de control se aplican solo a los stores en la
+cláusula then y la cláusula else de la sentencia if en cuestión (incluidas
+las funciones invocado por esas dos cláusulas), no al código que sigue a
+esa declaración if.
+
+
+Tenga muy en cuenta que el orden proporcionado por una dependencia de
+control es local a la CPU que lo contiene. Vea el apartado de "Atomicidad
+multicopia" para más información.
+
+
+En resumen:
+
+ (*) Las dependencias de control pueden ordenar cargas anteriores para
+ stores posteriores. Sin embargo, no garantizan ningún otro tipo de
+ orden: No cargas previas contra cargas posteriores, ni
+ almacenamientos previos y luego nada. Si necesita tales formas de
+ orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y
+ cargas posteriores, smp_mb().
+
+ (*) Si ambos caminos de la declaración "if" comienzan con stores
+ idénticos de la misma variable, entonces esos stores deben ser
+ ordenados, ya sea precediéndoles a ambos con smp_mb() o usando
+ smp_store_release() para realizar el store. Tenga en cuenta que -no-
+ es suficiente usar barrier() al comienzo de cada caso de la
+ declaración "if" porque, como se muestra en el ejemplo anterior, la
+ optimización de los compiladores puede destruir la dependencia de
+ control respetando al pie de la letra la ley de barrier().
+
+ (*) Las dependencias de control requieren al menos un condicional en
+ tiempo de ejecución entre la carga anterior y el almacenamiento
+ posterior, y este condicional debe implicar la carga previa. Si el
+ compilador es capaz de optimizar el condicional y quitarlo, también
+ habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y
+ WRITE_ONCE() puede ayudar a preservar el necesario condicional.
+
+ (*) Las dependencias de control requieren que el compilador evite
+ reordenar las dependencia hasta su inexistencia. El uso cuidadoso de
+ READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la
+ dependencia de control. Consulte la sección BARRERA DEL COMPILADOR
+ para obtener más información al respecto.
+
+ (*) Las dependencias de control se aplican solo a la cláusula then y la
+ cláusula else de la sentencia "if" que contiene la dependencia de
+ control, incluyendo cualquier función a la que llamen dichas dos
+ cláusulas. Las dependencias de control no se aplican al código que
+ sigue a la instrucción if que contiene la dependencia de control.
+
+ (*) Las dependencias de control se emparejan normalmente con otros tipos
+ de barreras.
+
+ (*) Las dependencias de control no proporcionan atomicidad multicopia. Si
+ usted necesita todas las CPU para ver un store dado al mismo tiempo,
+ emplee smp_mb().
+
+ (*) Los compiladores no entienden las dependencias de control. Por lo
+ tanto es su trabajo asegurarse de que no rompan su código.
+
+
+EMPAREJAMIENTO DE BARRERAS SMP
+------------------------------
+
+Cuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de
+memoria deben estar siempre emparejados. La falta del apropiado
+emparejamiento es casi seguro un error.
+
+Las barreras generales se emparejan entre sí, aunque también se emparejan
+con la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia.
+Una barrera de adquisición se empareja con una barrera de liberación, pero
+ambas también pueden emparejarse con otras barreras, incluidas, por
+supuesto, las barreras generales. Una barrera de escritura se empareja con
+una barrera de dependencia de dirección, una dependencia de control, una
+barrera de adquisición, una barrera de liberación, una barrera de lectura
+o una barrera general. Del mismo modo, una barrera de lectura se empareja
+con una de dependencia de control o barrera de dependencia de dirección con
+una barrera de escritura, una barrera de adquisición, una barrera de
+liberación o una barrera general:
+
+ CPU 1 CPU 2
+ =============== ===============
+ WRITE_ONCE(a, 1);
+ <barrera de escritura>
+ WRITE_ONCE(b, 2); x = READ_ONCE(b);
+ <barrera de lectura>
+ y = READ_ONCE(a);
+
+O bien:
+
+ CPU 1 CPU 2
+ =============== ===============================
+ a = 1;
+ <barrera de escritura>
+ WRITE_ONCE(b, &a); x = READ_ONCE(b);
+ <barrera de dependencia de dirección implícita>
+ y = *x;
+
+O incluso:
+
+ CPU 1 CPU 2
+ =============== ===============================
+ r1 = READ_ONCE(y);
+ <barrera general>
+ WRITE_ONCE(x, 1); if (r2 = READ_ONCE(x)) {
+ <barrera de control implícita>
+ WRITE_ONCE(y, 1);
+ }
+
+ assert(r1 == 0 || r2 == 0);
+
+Básicamente, la barrera de lectura siempre tiene que estar ahí, aunque
+puede ser del tipo "más débil".
+
+[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la
+barrera de escritura se hagan coincidir con los stores después de la
+barrera de lectura o la barrera de dependencia de dirección, y viceversa:
+
+ CPU 1 CPU 2
+ =================== ===================
+ WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c);
+ WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d);
+ <barrera de escritura> \ <barrera de lectura>
+ WRITE_ONCE(c, 3); } / \ { x = READ_ONCE(a);
+ WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b);
+
+
+EJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA
+--------------------------------------------
+
+En primer lugar, las barreras de escritura actúan como orden parcial en las
+operaciones de store. Considere la siguiente secuencia de eventos:
+
+ CPU 1
+ =======================
+ STORE A = 1
+ STORE B = 2
+ STORE C = 3
+ <barrera de escritura>
+ STORE D = 4
+ STORE E = 5
+
+Esta secuencia de eventos es finalizado para con el sistema de coherencia
+de memoria en un orden que el resto del sistema podría percibir como el
+conjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del
+conjunto desordenado { STORE D, STORE E}:
+
+
+ +-------+ : :
+ | | +------+
+ | |------>| C=3 | } /\
+ | | : +------+ }----- \ -----> Eventos perceptibles para
+ | | : | A=1 | } \/ el resto del sistema
+ | | : +------+ }
+ | CPU 1 | : | B=2 | }
+ | | +------+ }
+ | | wwwwwwwwwwwwwwww } <--- En este momento la barrera de
+ | | +------+ } escritura requiere que todos los
+ | | : | E=5 | } stores anteriores a la barrera
+ | | : +------+ } sean confirmados antes de que otros
+ | |------>| D=4 | } store puedan suceder
+ | | +------+
+ +-------+ : :
+ |
+ | Secuencia por la cual los stores son confirmados al
+ | sistema de memoria por parte del CPU 1
+ V
+
+En segundo lugar, las barreras de dependencia de dirección actúan como
+órdenes parciales sobre la dirección de cargas dependientes. Considere la
+siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { B = 7; X = 9; Y = 8; C = &Y }
+ STORE A = 1
+ STORE B = 2
+ <barrera de escritura>
+ STORE C = &B LOAD X
+ STORE D = 4 LOAD C (consigue &B)
+ LOAD *C (lee B)
+
+Sin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden
+aleatorio a efectos prácticos, a pesar de la barrera de escritura emitida
+por la CPU 1:
+
+ +-------+ : : : :
+ | | +------+ +-------+ | Secuencia de
+ | |------>| B=2 |----- --->| Y->8 | | actualizado de
+ | | : +------+ \ +-------+ | percepción en CPU 2
+ | CPU 1 | : | A=1 | \ --->| C->&Y | V
+ | | +------+ | +-------+
+ | | wwwwwwwwwwwwwwww | : :
+ | | +------+ | : :
+ | | : | C=&B |--- | : : +-------+
+ | | : +------+ \ | +-------+ | |
+ | |------>| D=4 | ----------->| C->&B |------>| |
+ | | +------+ | +-------+ | |
+ +-------+ : : | : : | |
+ | : : | |
+ | : : | CPU 2 |
+ | +-------+ | |
+ Percepción de B ---> | | B->7 |------>| |
+ aparentemente incorrecta! | +-------+ | |
+ | : : | |
+ | +-------+ | |
+ La carga de X frena ---> \ | X->9 |------>| |
+ el mantenimiento de \ +-------+ | |
+ la coherencia de B ----->| B->2 | +-------+
+ +-------+
+ : :
+
+
+En el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de
+*C (que sería B) viniendo después del LOAD de C.
+
+Sin embargo, si se colocara una barrera de dependencia de dirección entre
+la carga de C y la carga de *C (es decir: B) en la CPU 2:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { B = 7; X = 9; Y = 8; C = &Y }
+ STORE A = 1
+ STORE B = 2
+ <barrera de escritura>
+ STORE C = &B LOAD X
+ STORE D = 4 LOAD C (consigue &B)
+ <barrera de dependencia de dirección>
+ LOAD *C (reads B)
+
+entonces ocurrirá lo siguiente:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| B=2 |----- --->| Y->8 |
+ | | : +------+ \ +-------+
+ | CPU 1 | : | A=1 | \ --->| C->&Y |
+ | | +------+ | +-------+
+ | | wwwwwwwwwwwwwwww | : :
+ | | +------+ | : :
+ | | : | C=&B |--- | : : +-------+
+ | | : +------+ \ | +-------+ | |
+ | |------>| D=4 | ----------->| C->&B |------>| |
+ | | +------+ | +-------+ | |
+ +-------+ : : | : : | |
+ | : : | |
+ | : : | CPU 2 |
+ | +-------+ | |
+ | | X->9 |------>| |
+ | +-------+ | |
+ Se asegura de que ---> \ aaaaaaaaaaaaaaaaa | |
+ los efectos anteriores al \ +-------+ | |
+ store de C sean percibidos ----->| B->2 |------>| |
+ por los siguientes loads +-------+ | |
+ : : +-------+
+
+
+Y en tercer lugar, una barrera de lectura actúa como un orden parcial sobre
+las cargas. Considere la siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ LOAD A
+
+Sin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en
+algún orden aleatorio a efectos prácticos, a pesar de la barrera de
+escritura emitida por la CPU 1:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | | A->0 |------>| |
+ | +-------+ | |
+ | : : +-------+
+ \ : :
+ \ +-------+
+ ---->| A->1 |
+ +-------+
+ : :
+
+Sin embargo, si se colocara una barrera de lectura entre la carga de B y la
+carga de A en la CPU 2:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ <barrera de lectura>
+ LOAD A
+
+entonces el orden parcial impuesto por la CPU 1 será percibido
+correctamente por la CPU 2:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ | : : | |
+ En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | |
+ de lectura consigue que \ +-------+ | |
+ todos los efectos anteriores ---->| A->1 |------>| |
+ al almacenamiento de B sean +-------+ | |
+ perceptibles por la CPU 2 : : +-------+
+
+
+Para ilustrar esto de manera más completa, considere lo que podría pasar si
+el código contenía una carga de A a cada lado de la barrera de lectura:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ LOAD A [primer load de A]
+ <rbarrera de lectura>
+ LOAD A [segundo load de A]
+
+Aunque las dos cargas de A ocurren después de la carga de B, ambas pueden
+obtener diferentes valores:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ | : : | |
+ | +-------+ | |
+ | | A->0 |------>| 1st |
+ | +-------+ | |
+ En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | |
+ de lectura consigue que \ +-------+ | |
+ todos los efectos anteriores ---->| A->1 |------>| |
+ al almacenamiento de B sean +-------+ | |
+ perceptibles por la CPU 2 : : +-------+
+
+Pero puede ser que la actualización a A desde la CPU 1 se vuelva
+perceptible para la CPU 2 antes de que la barrera de lectura se complete de
+todos modos:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ \ : : | |
+ \ +-------+ | |
+ ---->| A->1 |------>| 1st |
+ +-------+ | |
+ rrrrrrrrrrrrrrrrr | |
+ +-------+ | |
+ | A->1 |------>| 2nd |
+ +-------+ | |
+ : : +-------+
+
+La garantía es que la segunda carga siempre dará como resultado A == 1 si
+la carga de B resultó en B == 2. No existe tal garantía para la primera
+carga de A; esto puede dar como resultado A == 0 o A == 1.
+
+
+BARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA
+-------------------------------------------------------------
+
+Muchas CPU especulan con las cargas: es decir, ven que necesitarán cargar
+un elemento de la memoria, y encuentran un momento en el que no están
+usando el bus para ningún otra carga, y también en la carga por adelantado,
+aunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución
+de instrucciones todavía. Esto permite que la instrucción de carga real
+potencialmente complete de inmediato, porque la CPU ya tiene el valor a
+mano.
+
+Puede resultar que la CPU en realidad no necesitara el valor, tal vez
+porque una condición eludió la carga, en cuyo caso puede descartar el valor
+o simplemente almacenar en caché para su uso posterior.
+
+Considere:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ LOAD B
+ DIVIDE } Instrucciones de división
+ DIVIDE } tardan mucho en terminar
+ LOAD A
+
+donde DIVIDE es DIVIDIR. Que podría aparecer como esto:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ Una vez completadas las divisiones --> : : ~-->| |
+ la CPU puede realizar el : : | |
+ LOAD con efecto inmediato : : +-------+
+
+
+Colocando una barrera de lectura o una barrera de dependencia de dirección
+justo antes de la segundo carga:
+
+
+
+ CPU 1 CPU 2
+ ======================= =======================
+ LOAD B
+ DIVIDE
+ DIVIDE
+ <rbarrera de lectura>
+ LOAD A
+
+obligará a reconsiderar cualquier valor obtenido especulativamente en una
+medida dependiente del tipo de barrera utilizada. Si no se hizo ningún
+cambio en la ubicación de memoria especulada, entonces el valor especulado
+solo se usará:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ : : ~ | |
+ rrrrrrrrrrrrrrrr~ | |
+ : : ~ | |
+ : : ~-->| |
+ : : | |
+ : : +-------+
+
+
+pero si había una actualización o una invalidación de otra CPU pendiente,
+entonces la especulación será cancelada y el valor recargado:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ : : ~ | |
+ rrrrrrrrrrrrrrrrr | |
+ +-------+ | |
+ La especulación es descartada ---> --->| A->1 |------>| |
+ y un valor actualizado +-------+ | |
+ es conseguido : : +-------+
+
+ATOMICIDAD MULTICOPIA
+---------------------
+
+La atomicidad multicopia es una noción profundamente intuitiva sobre el
+orden que no es siempre proporcionada por los sistemas informáticos reales,
+a saber, que un determinada store se vuelve visible al mismo tiempo para
+todos las CPU o, alternativamente, que todas las CPU acuerdan el orden en
+que todos los stores se vuelven visibles. Sin embargo, el soporte para
+atomicidad multicopia completa descartaría valiosas optimizaciones
+hardware, por lo que una versión más débil conocida como ``otra atomicidad
+multicopia'' en cambio, solo garantiza que un store dado se vuelva visible
+al mismo tiempo en todas las -otras- CPUs. El resto de este documento
+discute esta versión más débil, pero por brevedad lo llamaremos simplemente
+``atomicidad multicopia''.
+
+El siguiente ejemplo demuestra la atomicidad multicopia:
+
+ CPU 1 CPU 2 CPU 3
+ ======================= ======================= =======================
+ { X = 0, Y = 0 }
+ STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
+ <barrera general> <barrera de lectura>
+ STORE Y=r1 LOAD X
+
+Suponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en
+Y, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de
+la CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 2
+a Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria
+garantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la
+CPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es
+"¿Puede la carga de la CPU 3 desde X devolver 0?"
+
+Debido a que la carga de la CPU 3 desde X en cierto sentido viene después
+de la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde
+X deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia:
+si una carga que se ejecuta en la CPU B sigue una carga de la misma
+variable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente
+el valor que leyó), entonces en sistemas atómicos multicopia, la carga de
+la CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún
+valor posterior. Sin embargo, el kernel Linux no requiere que los sistemas
+sean atómicos multicopia.
+
+El uso de una barrera de memoria general en el ejemplo anterior compensa
+cualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la
+CPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la
+carga de la CPU 3 desde X debe de hecho también devolver 1.
+
+Sin embargo, las dependencias, las barreras de lectura y las barreras de
+escritura no siempre son capaces de compensar la atomicidad no multicopia.
+Por ejemplo, supongamos que la barrera general de la CPU 2 se elimina del
+ejemplo anterior, dejando solo la dependencia de datos que se muestra a
+continuación:
+
+ CPU 1 CPU 2 CPU 3
+ ======================= ======================= =======================
+ { X = 0, Y = 0 }
+ STORE X=1 r1=LOAD X (escribe 1) LOAD Y (lee 1)
+ <dependencia de datos> <barrera de lectura>
+ STORE Y=r1 LOAD X (lee 0)
+
+Esta sustitución permite que la atomicidad no multicopia se desenfrene: en
+este ejemplo, es perfectamente legal que la carga de la CPU 2 desde X
+devuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X
+tenga valor 0.
+
+El punto clave es que aunque la dependencia de datos de la CPU 2 ordena su
+carga y store, no garantiza ordenar el store de la CPU 1. De forma que, si
+este ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 1
+y 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 2
+podría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se
+requieren barreras generales para garantizar que todas las CPU acurden el
+orden combinado de accesos múltiples.
+
+Las barreras generales pueden compensar no solo la atomicidad no
+multicopia, pero también pueden generar orden adicional que puede asegurar
+que -todas- las CPU percibirán el mismo orden de -todas- las operaciones.
+Por el contrario, una cadena de parejas de liberación-adquisición no
+proporciona este orden adicional, lo que significa que solo se garantiza
+que las CPU de la cadena estén de acuerdo en el orden combinado de los
+accesos. Por ejemplo, cambiando a código C en deferencia al fantasma de
+Herman Hollerith:
+
+ int u, v, x, y, z;
+
+ void cpu0(void)
+ {
+ r0 = smp_load_acquire(&x);
+ WRITE_ONCE(u, 1);
+ smp_store_release(&y, 1);
+ }
+
+ void cpu1(void)
+ {
+ r1 = smp_load_acquire(&y);
+ r4 = READ_ONCE(v);
+ r5 = READ_ONCE(u);
+ smp_store_release(&z, 1);
+ }
+
+ void cpu2(void)
+ {
+ r2 = smp_load_acquire(&z);
+ smp_store_release(&x, 1);
+ }
+
+ void cpu3(void)
+ {
+ WRITE_ONCE(v, 1);
+ smp_mb();
+ r3 = READ_ONCE(u);
+ }
+
+Dado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas
+smp_store_release()/smp_load_acquire(), el siguiente resultado estaría
+prohibido:
+
+ r0 == 1 && r1 == 1 && r2 == 1
+
+Además, debido a la relación liberación-adquisición entre cpu0() y cpu1(),
+cpu1() debe ver las escrituras de cpu0(), de modo que el siguiente
+resultado estaría prohibido:
+
+ r1 == 1 && r5 == 0
+
+Sin embargo, el orden proporcionado por una cadena de
+liberación-adquisición es local a las CPU que participan en esa cadena y no
+se aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible
+el siguiente resultado:
+
+ r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
+
+Por otro lado, también el siguiente resultado es posible:
+
+ r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1
+
+Aunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras
+en orden, las CPU que no participan en la cadena de liberación-adquisición
+pueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho
+de que las instrucciones de barrera de memoria débiles utilizadas para
+implementar smp_load_acquire() y smp_store_release() no son necesarios para
+ordenar stores anteriores contra cargas posteriores en todos los casos.
+Esto significa que cpu3() puede ver el store de cpu0() suceder -después- de
+la carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de
+acuerdo en que estas dos operaciones ocurrieron en el orden previsto.
+
+Sin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En
+particular, simplemente lee de su argumento en orden. Es decir, -no-
+asegura que se leerá cualquier valor en particular. Por lo tanto, los
+siguiente resultados son posibles:
+
+ r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0
+
+Tenga en cuenta que este resultado puede ocurrir incluso en un mítico
+sistema, consistente en secuencia, donde nunca se reordena nada.
+
+Para reiterar, si su código requiere un orden completo de todas las
+operaciones, utilice barreras generales en todo momento.
+
+
+==============================
+BARRERAS EXPLÍCITAS DEL KERNEL
+==============================
+
+El kernel Linux tiene una variedad de diferentes barreras que actúan a
+diferentes niveles:
+
+ (*) Barrera del compilador.
+
+ (*) Barreras de memoria de la CPU.
+
+
+BARRERA DEL COMPILADOR
+-----------------------
+
+El kernel de Linux tiene una función de barrera del compilador explícita
+que evita que el el compilador mueva los accesos a la memoria de cualquier
+lado al otro:
+
+ barrier();
+
+Esta es una barrera general: no hay variantes de barrier() para casos de
+lectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y
+WRITE_ONCE() pueden ser considerado como formas débiles de barrier() que
+afectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE().
+
+La función barrier() produce los siguientes efectos:
+
+ (*) Evita que el compilador reordene los accesos tras barrier() para
+ preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso
+ de esta propiedad es facilitar la comunicación entre código del
+ interrupt-handler (encargo de gestionar interrupciones) y el código
+ que fue interrumpido.
+
+ (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las
+ variables utilizadas en ese loop condicional en cada paso a través de
+ ese loop.
+
+Las funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad
+de optimizaciones que, si bien son perfectamente seguras en código de un
+solo subproceso, pueden resultar fatales en código concurrente. Aquí hay
+algunos ejemplos de tal tipo de optimizaciones:
+
+(*) El compilador está en su derecho de reordenar cargas y stores de la
+ misma variable, y en algunos casos, la CPU está dentro de su
+ derecho de reordenar cargas a la misma variable. Esto significa que
+ el siguiente código:
+
+ a[0] = x;
+ a[1] = x;
+
+ Podría resultar en un valor más antiguo de x almacenado en a[1] que en
+ a[0]. Evite que tanto el compilador como la CPU hagan esto de la
+ siguiente manera:
+
+ a[0] = READ_ONCE(x);
+ a[1] = READ_ONCE(x);
+
+ En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de
+ caché para accesos desde múltiples CPUs a una sola variable.
+
+ (*) El compilador tiene derecho a juntar cargas sucesivas de la misma
+ variable. Tal fusión puede hacer que el compilador "optimice" el
+ siguiente código:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ en el siguiente código, que, aunque en cierto sentido es legítimo
+ para un código de un solo subproceso, es casi seguro que no es lo
+ que el desarrollador pretendía:
+
+ if (tmp = a)
+ for (;;)
+ hacer_algo_con(tmp);
+
+ Use READ_ONCE() para evitar que el compilador le haga esto:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ (*) El compilador tiene derecho a recargar una variable, por ejemplo,
+ en los casos en que la alta presión de los registros impida que el
+ compilador mantenga todos los datos de interés en registros. El
+ compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro
+ ejemplo anterior:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ Esto podría resultar en el siguiente código, que es perfectamente
+ seguro en código de subproceso único, pero puede ser fatal en código
+ concurrente:
+
+ while (a)
+ hacer_algo_con(a);
+
+ Por ejemplo, la versión optimizada de este código podría resultar en
+ pasar un cero a hacer_algo_con() en el caso de que la variable a sea
+ modificada por alguna otra CPU, entre la instrucción "while" y la
+ llamada a hacer_algo_con().
+
+ De nuevo, use READ_ONCE() para evitar que el compilador haga esto:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ Tenga en cuenta que si el compilador se queda sin registros, podría
+ guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de
+ este guardado y posterior restauración es por lo que los compiladores
+ recargan las variables. Hacerlo es perfectamente seguro para código de
+ subproceso único, por lo que debe informar al compilador sobre los
+ casos donde no sea seguro.
+
+ (*) El compilador está en su derecho de omitir una carga por completo si
+ sabe cual será su valor. Por ejemplo, si el compilador puede probar
+ que el valor de la variable 'a' siempre es cero, puede optimizar este
+ código:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ En esto:
+
+ do { } while (0);
+
+ Esta transformación es una victoria para un código de un solo
+ subproceso, porque se deshace de una carga y un branch. El problema es
+ que el compilador llevará a cabo su prueba asumiendo que la CPU actual
+ es la única actualizando la variable 'a'. Si la variable 'a' es
+ compartida, entonces la prueba del compilador será errónea. Use
+ READ_ONCE() para decirle al compilador que no sabe tanto como cree:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ Pero, por favor, tenga en cuenta que el compilador también está
+ observando de cerca lo que usted hace con el valor después de
+ READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es
+ una macro de preprocesador con el valor 1:
+
+ while ((tmp = READ_ONCE(a)) % MAX)
+ hacer_algo_con(tmp);
+
+ Entonces el compilador sabe que el resultado del operador "%" aplicado
+ a MAX siempre será cero, nuevamente permitiendo que el compilador
+ optimice el código hasta su casi inexistencia. (Aún se cargará desde
+ la variable 'a'.)
+
+ (*) De manera similar, el compilador tiene derecho a omitir un store por
+ completo si sabe que la variable ya tiene el valor almacenado.
+ Nuevamente, el compilador asume que la CPU actual es la única que
+ almacena la variable, lo que puede hacer que el compilador haga
+ algo incorrecto para las variables compartidas. Por ejemplo, suponga
+ que tiene lo siguiente:
+
+ a = 0;
+ ... Código que no almacena la variable a ...
+ a = 0;
+
+ El compilador observa que el valor de la variable 'a' ya es cero, por
+ lo que bien podría omitir el segundo store. Esto supondría una fatal
+ sorpresa, si alguna otra CPU hubiera almacenado la variable 'a'
+ mientras tanto.
+
+ Use WRITE_ONCE() para evitar que el compilador haga este tipo de
+ suposición equivocada:
+
+ WRITE_ONCE(a, 0);
+ ... Código que no almacena la variable a ...
+ WRITE_ONCE(a, 0);
+
+ (*) El compilador tiene derecho a reordenar los accesos a memoria a menos
+ que le diga que no. Por ejemplo, considere la siguiente interacción
+ entre el código de nivel de proceso y un controlador de interrupción:
+
+ void nivel_de_procesamiento(void)
+ {
+ msg = ACQUIRE_mensaje();
+ flag = true;
+ }
+
+ void controlador_interrupcion(void)
+ {
+ if (flag)
+ procesar_mensaje(msg);
+ }
+
+ No hay nada que impida que el compilador transforme
+ nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser
+ una victoria para código de un solo subproceso:
+
+ void nivel_de_procesamiento(void)
+ {
+ flag = true;
+ msg = ACQUIRE_mensaje();
+ }
+
+ Si la interrupción ocurre entre estas dos declaraciones, entonces
+ controlador_interrupcion() podría recibir un mensaje ilegible. Use
+ READ_ONCE() para evitar esto de la siguiente manera:
+
+ void nivel_de_procesamiento(void)
+ {
+ WRITE_ONCE(msg, ACQUIRE_mensaje());
+ WRITE_ONCE(flag, true);
+ }
+
+ void controlador_interrupcion(void)
+ {
+ if (READ_ONCE(flag))
+ procesar_mensaje(READ_ONCE(msg));
+ }
+
+ Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y
+ WRITE_ONCE() en controlador_interrupcion() son necesarios si este
+ controlador de interrupciones puede ser interrumpido por algo que
+ también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada
+ o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son
+ necesarios en controlador_interrupcion() aparte de con fines de
+ documentación. (Tenga también en cuenta que las interrupciones
+ anidadas no ocurren típicamente en los kernels Linux modernos, de
+ hecho, si un controlador de interrupciones regresa con interrupciones
+ habilitadas, obtendrá un WARN_ONCE().)
+
+ Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE()
+ a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o
+ primitivas similares.
+
+ Este efecto también podría lograrse usando barrier(), pero READ_ONCE()
+ y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el
+ compilador solo necesita olvidar el contenido de ubicaciones de
+ memoria indicadas, mientras que con barrier() el compilador debe
+ descartar el valor de todas las ubicaciones de memoria que tiene
+ actualmente almacenadas en caché, en cualquier registro de la máquina.
+ Por supuesto, el compilador también debe respetar el orden en que
+ ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no
+ necesita hacerlo.
+
+ (*) El compilador tiene derecho a inventar stores para una variable,
+ como en el siguiente ejemplo:
+
+ if (a)
+ b = a;
+ else
+ b = 42;
+
+ El compilador podría ahorrar un branch al optimizar esto de la
+ siguiente manera:
+
+ b = 42;
+ if (a)
+ b = a;
+
+ En el código de un solo subproceso, esto no solo es seguro, sino que
+ también ahorra un branch. Desafortunadamente, en código concurrente,
+ esta optimización podría causar que alguna otra CPU vea un valor falso
+ de 42, incluso si la variable 'a' nunca fue cero, al cargar la
+ variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente
+ manera:
+
+ if (a)
+ WRITE_ONCE(b, a);
+ else
+ WRITE_ONCE(b, 42);
+
+ El compilador también puede inventar cargas. Estos casos suelen ser
+ menos perjudiciales, pero pueden dar como resultado "bouncing" de la
+ línea de caché y, por lo tanto, bajo rendimiento y escalabilidad.
+ Utilice READ_ONCE() para evitar cargas inventadas.
+
+ (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita
+ acceder con una sola instrucción de referencia de memoria, evite el
+ "desgarro de la carga" (load tearing) y "desgarro del store" (store
+ tearing), en el que un solo gran acceso es reemplazado por múltiples
+ accesos menores. Por ejemplo, dada una arquitectura que tiene
+ instrucciones de almacenamiento de 16 bits con campos inmediatos de 7
+ bits, el compilador podría tener la tentación de usar dos
+ instrucciones inmediatas de almacenamiento de 16 bits para implementar
+ el siguiente store de 32 bits:
+
+ p = 0x00010002;
+
+ Tenga en cuenta que GCC realmente usa este tipo de optimización, lo
+ cual no es sorprendente dado que probablemente costaría más de dos
+ instrucciones el construir la constante y luego almacenarla. Por lo
+ tanto, esta optimización puede ser una victoria en un código de un
+ solo subproceso. De hecho, un error reciente (desde que se solucionó)
+ hizo que GCC usara incorrectamente esta optimización en un store
+ volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el
+ desgarro del store en el siguiente ejemplo:
+
+ struct __attribute__((__packed__)) foo {
+ short a;
+ int b;
+ short c;
+ };
+ struct foo foo1, foo2;
+ ...
+
+ foo2.a = foo1.a;
+ foo2.b = foo1.b;
+ foo2.c = foo1.c;
+
+ Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no
+ hay markings volátiles, el compilador estaría en su derecho de
+ implementar estas tres declaraciones de asignación como un par de
+ cargas de 32 bits, seguido de un par de stores de 32 bits. Esto
+ resultaría en una carga con desgarro en 'foo1.b' y store del desgarro
+ en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro
+ en este ejemplo:
+
+ foo2.a = foo1.a;
+ WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));
+ foo2.c = foo1.c;
+
+Aparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una
+variable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies'
+está marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La
+razón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como
+conversiones volátiles, lo que no tiene efecto cuando su argumento ya está
+marcado como volátil.
+
+Tenga en cuenta que estas barreras del compilador no tienen un efecto
+directo en la CPU, que luego puede reordenar las cosas como quiera.
+
+
+BARRERAS DE MEMORIA DE LA CPU
+-----------------------------
+
+El kernel de Linux tiene siete barreras básicas de memoria de CPU:
+
+TIPO OBLIGATORIO SMP CONDICIONAL
+======================= =============== ===============
+GENERAL mb() smp_mb()
+WRITE wmb() smp_wmb()
+READ rmb() smp_rmb()
+DEPEDENCIA DE DIRECCIÓN READ_ONCE()
+
+
+Todas las barreras de memoria, excepto las barreras de dependencia de
+direcciones, implican una barrera del compilador. Las dependencias de
+direcciones no imponen ningún orden de compilación adicional.
+
+Además: en el caso de las dependencias de direcciones, se esperaría que el
+compilador emita las cargas en el orden correcto (por ejemplo, `a[b]`
+tendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay
+garantía alguna en la especificación de C sobre que el compilador no puede
+especular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que
+b (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de
+que un compilador vuelva a cargar b después de haber cargado a[b], teniendo
+así una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso
+acerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen
+lugar para empezar a buscar.
+
+Las barreras de memoria SMP se reducen a barreras de compilador cuando se
+compila a monoprocesador, porque se supone que una CPU parecerá ser
+auto-consistente, y ordenará correctamente los accesos superpuestos
+respecto a sí misma. Sin embargo, consulte la subsección "Guests de
+máquinas virtuales" mas adelante.
+
+[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para
+controlar el orden de referencias a memoria compartida en sistemas SMP,
+aunque el uso de bloqueo en su lugar sea suficiente.
+
+Las barreras obligatorias no deben usarse para controlar los efectos de
+SMP, ya que dichas barreras imponen una sobrecarga innecesaria en los
+sistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos
+MMIO en los accesos a través de ventanas E/S de memoria relajada. Estas
+barreras son necesarias incluso en sistemas que no son SMP, ya que afectan
+al orden en que las operaciones de memoria aparecen en un dispositivo, al
+prohibir tanto al compilador como a la CPU que sean reordenados.
+
+
+Hay algunas funciones de barrera más avanzadas:
+
+ (*) smp_store_mb(var, valor)
+
+ Asigna el valor a la variable y luego inserta una barrera de memoria
+ completa después de ella. No se garantiza insertar nada más que una
+ barrera del compilador en una compilación UP.
+
+
+ (*) smp_mb__before_atomic();
+ (*) smp_mb__after_atomic();
+
+ Estos se pueden usar con funciones RMW atómicas que no implican
+ barreras de memoria, pero donde el código necesita una barrera de
+ memoria. Ejemplos de funciones RMW atómicas que no implican una
+ barrera de memoria son, por ejemplo, agregar, restar, operaciones
+ condicionales (fallidas), funciones _relaxed, pero no atomic_read o
+ atomic_set. Un ejemplo común donde se puede requerir una barrera es
+ cuando se usan operaciones atómicas como referencia de contador.
+
+ Estos también se utilizan para funciones atómicas RMW bitop que no
+ implican una barrera de memoria (como set_bit y clear_bit).
+
+ Como ejemplo, considere una pieza de código que marca un objeto como
+ muerto y luego disminuye el contador de referencias del objeto:
+
+ obj->dead = 1;
+ smp_mb__before_atomic();
+ atomic_dec(&obj->ref_count);
+
+ Esto asegura que la marca de muerte en el objeto se perciba como
+ fijada *antes* de que disminuya el contador de referencia.
+
+ Consulte Documentation/atomic_{t,bitops}.txt para obtener más
+ información.
+
+
+ (*) dma_wmb();
+ (*) dma_rmb();
+ (*) dma_mb();
+
+ Estos son usados con memoria consistente para garantizar el orden de
+ escrituras o lecturas de memoria compartida accesible tanto para la
+ CPU como para un dispositivo compatible con DMA.
+
+ Por ejemplo, considere un controlador de dispositivo que comparte
+ memoria con otro dispositivo y usa un valor de estado del descriptor
+ para indicar si el descriptor pertenece al dispositivo o a la CPU, y
+ un "doorbell" (timbre, punto de acceso) para avisarle cuando haya
+ nuevos descriptores disponibles:
+
+ if (desc->status != DEVICE_OWN) {
+ /* no leer los datos hasta que tengamos el descriptor */
+ dma_rmb();
+
+ /* leer/modificar datos */
+ read_data = desc->data;
+ desc->data = write_data;
+
+ /* flush de modificaciones antes de la actualización de estado */
+ dma_wmb();
+
+ /* asignar propiedad */
+ desc->status = DEVICE_OWN;
+
+ /* notificar al dispositivo de nuevos descriptores */
+ writel(DESC_NOTIFY, doorbell);
+ }
+
+ El dma_rmb() nos permite garantizar que el dispositivo ha liberado su
+ propiedad antes de que leamos los datos del descriptor, y el dma_wmb()
+ permite garantizar que los datos se escriben en el descriptor antes de
+ que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb()
+ implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al
+ usar writel(), no se necesita un wmb() anterior para garantizar que
+ las escrituras de la memoria caché coherente se hayan completado antes
+ escribiendo a la región MMIO. El writel_relaxed() más barato no
+ proporciona esta garantía y no debe utilizarse aquí.
+
+ Consulte la subsección "Efectos de barrera de E/S del kernel" para
+ obtener más información sobre accesorios de E/S relajados y el archivo
+ Documentation/core-api/dma-api.rst para más información sobre memoria
+ consistente.
+
+ (*) pmem_wmb();
+
+ Es es para uso con memoria persistente para garantizar que los stores
+ para los que las modificaciones se escriben en el almacenamiento
+ persistente llegaron a dominio de durabilidad de la plataforma.
+
+ Por ejemplo, después de una escritura no temporal en la región pmem,
+ usamos pmem_wmb() para garantizar que los stores hayan alcanzado el
+ dominio de durabilidad de la plataforma. Esto garantiza que los stores
+ han actualizado el almacenamiento persistente antes de cualquier
+ acceso a datos o transferencia de datos causada por instrucciones
+ posteriores. Esto es además del orden realizado por wmb().
+
+ Para la carga desde memoria persistente, las barreras de memoria de
+ lectura existentes son suficientes para garantizar el orden de
+ lectura.
+
+ (*) io_stop_wc();
+
+ Para accesos a memoria con atributos de combinación de escritura (por
+ ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que
+ los accesos anteriores se junten con posteriores. io_stop_wc() se
+ puede utilizar para evitar la combinación de accesos a memoria de
+ de escritura antes de esta macro, con los posteriores, cuando dicha
+ espera tenga implicaciones en el rendimiento.
+
+=========================================
+BARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL
+=========================================
+
+Algunas de las otras funciones en el kernel Linux implican barreras de
+memoria, entre estas encontramos funciones de bloqueo y planificación
+("scheduling").
+
+Esta especificación es una garantía _mínima_; cualquier arquitectura
+particular puede proporcionar garantías más sustanciales, pero no se puede
+confiar en estas fuera de código específico de arquitectura.
+
+
+FUNCIONES DE ADQUISICIÓN DE CERROJO
+-----------------------------------
+
+El kernel Linux tiene una serie de abstracciones de bloqueo:
+
+ (*) spin locks (cerrojos en loop)
+ (*) R/W spin lock (cerrojos de escritura/lectura)
+ (*) mutex
+ (*) semáforos
+ (*) R/W semáforos
+
+En todos los casos existen variantes de las operaciones "ACQUIRE" y
+"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas
+barreras:
+
+ (1) Implicaciones de la operación ACQUIRE:
+
+ Las operaciones de memoria emitidas después del ACQUIRE se completarán
+ después de que la operación ACQUIRE haya finalizado.
+
+ Las operaciones de memoria emitidas antes de ACQUIRE pueden
+ completarse después que la operación ACQUIRE se ha completado.
+
+ (2) Implicaciones de la operación RELEASE:
+
+ Las operaciones de memoria emitidas antes de la RELEASE se
+ completarán antes de que la operación de RELEASE se haya completado.
+
+ Las operaciones de memoria emitidas después de la RELEASE pueden
+ completarse antes de que la operación de RELEASE se haya completado.
+
+ (3) Implicación de ACQUIRE vs ACQUIRE:
+
+ Todas las operaciones ACQUIRE emitidas antes de otra operación
+ ACQUIRE serán completadas antes de esa operación ACQUIRE.
+
+ (4) Implicación de ACQUIRE vs RELEASE:
+
+ Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE
+ serán completadas antes de la operación RELEASE.
+
+ (5) Implicación de ACQUIRE condicional fallido:
+
+ Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya
+ sea debido a no poder obtener el bloqueo de inmediato, o debido a que
+ recibieron una señal de desbloqueo mientras dormían esperando que el
+ cerrojo estuviera disponible. Los fallos en cerrojos no implican
+ ningún tipo de barrera.
+
+[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE
+sean barreras unidireccionales, es que los efectos de las instrucciones
+fuera de una sección crítica pueden filtrarse al interior de la sección
+crítica.
+
+No se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera
+de memoria completa dado que es posible que un acceso anterior a ACQUIRE
+suceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes
+del RELEASE, y los dos accesos puedan entonces cruzarse:
+
+ *A = a;
+ ACQUIRE M
+ RELEASE M
+ *B = b;
+
+puede ocurrir como:
+
+ ACQUIRE M, STORE *B, STORE *A, RELEASE M
+
+Cuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación,
+respectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y
+RELEASE son para la misma variable de bloqueo, pero solo desde la
+perspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE
+seguido de un RELEASE NO puede entenderse como una barrera de memoria
+completa.
+
+De manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no
+implica una barrera de memoria completa. Por lo tanto, la ejecución de la
+CPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE
+pueden cruzarse, de modo que:
+
+ *A = a;
+ RELEASE M
+ ACQUIRE N
+ *B = b;
+
+puede ocurrir como:
+
+ ACQUIRE N, STORE *B, STORE *A, RELEASE M
+
+Podría parecer que este nuevo orden podría introducir un punto muerto.
+Sin embargo, esto no puede suceder porque si tal punto muerto amenazara
+con suceder, el RELEASE simplemente se completaría, evitando así el
+interbloqueo ("deadlock", punto muerto).
+
+ ¿Por qué funciona esto?
+
+ Un punto clave es que solo estamos hablando de la CPU re-haciendo el
+ orden, no el compilador. Si el compilador (o, ya puestos, el
+ desarrollador) cambió las operaciones, un deadlock -podría- ocurrir.
+
+ Pero supongamos que la CPU reordenó las operaciones. En este caso, el
+ desbloqueo precede al bloqueo en el código ensamblador. La CPU
+ simplemente eligió intentar ejecutar primero la última operación de
+ bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente
+ esperará (o tratará de dormir, pero hablaremos de eso más adelante). La
+ CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la
+ operación de bloqueo en el código ensamblador), lo que desenmascará el
+ potencial punto muerto, permitiendo que la operación de bloqueo tenga
+ éxito.
+
+ Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal
+ caso, el código intentará entrar al scheduler, donde eventualmente
+ encontrará una barrera de memoria, que forzará la operación de desbloqueo
+ anterior para completar, nuevamente desentrañando el punto muerto. Podría
+ haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la
+ primitiva de bloqueo necesita resolver tales carreras correctamente en
+ cualquier caso.
+
+Es posible que los cerrojos y los semáforos no proporcionen ninguna
+garantía de orden en sistemas compilados en UP, por lo que no se puede
+contar con tal situación para lograr realmente nada en absoluto,
+especialmente con respecto a los accesos de E/S, a menos que se combinen
+con operaciones de inhabilitación de interrupciones.
+
+Consulte también la sección "Efectos de barrera adquiriendo intra-CPU".
+
+
+Como ejemplo, considere lo siguiente:
+
+ *A = a;
+ *B = b;
+ ACQUIRE
+ *C = c;
+ *D = d;
+ RELEASE
+ *E = e;
+ *F = f;
+
+La siguiente secuencia de eventos es aceptable:
+
+ ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE
+
+ [+] Tenga en cuenta que {*F,*A} indica un acceso combinado.
+
+Pero ninguno de los siguientes lo son:
+
+ {*F,*A}, *B, ACQUIRE, *C, *D, RELEASE, *E
+ *A, *B, *C, ACQUIRE, *D, RELEASE, *E, *F
+ *A, *B, ACQUIRE, *C, RELEASE, *D, *E, *F
+ *B, ACQUIRE, *C, *D, RELEASE, {*F,*A}, *E
+
+
+
+FUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES
+--------------------------------------------
+
+Las funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y
+habilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como
+barrera del compilador. Por consiguiente, si la memoria o la E/S requieren
+barreras en tal situación, deben ser provistas por algún otro medio.
+
+
+FUNCIONES DE DORMIR Y DESPERTAR
+-------------------------------
+
+Dormir y despertar son eventos marcados ("flagged") en los datos globales
+que se pueden ver como una interacción entre dos piezas de datos: el estado
+de la task (hilo, proceso, tarea) que espera el evento y los datos globales
+utilizados para indicar el evento. Para asegurarse de que estos parezcan
+suceder en el orden correcto, las primitivas para comenzar el proceso de ir
+a dormir, y las primitivas para iniciar un despertar implican ciertas
+barreras.
+
+En primer lugar, el agente durmiente normalmente sigue algo similar a esta
+secuencia de eventos:
+
+ for (;;) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (evento_indicado)
+ break;
+ schedule(); // planificar
+ }
+
+Una barrera de memoria general se obtiene automáticamente mediante
+set_current_state() después de haber alterado el estado de la tarea:
+
+ CPU 1
+ ===============================
+ set_current_state(); // hacer_estado_actual()
+ smp_store_mb();
+ STORE current->state
+ <barrera general>
+ LOAD evento_indicado
+
+set_current_state() puede estar envuelto por:
+
+ prepare_to_wait(); // preparese_para_esperar();
+ prepare_to_wait_exclusive(); // prepararse_para_solo_esperar();
+
+que por lo tanto también implican una barrera de memoria general después de
+establecer el estado. Toda la secuencia anterior está disponible en varias
+formas, todas las cuales obtienen la barrera de memoria en el lugar
+correcto:
+
+ wait_event();
+ wait_event_interruptible();
+ wait_event_interruptible_exclusive();
+ wait_event_interruptible_timeout();
+ wait_event_killable();
+ wait_event_timeout();
+ wait_on_bit();
+ wait_on_bit_lock();
+
+
+En segundo lugar, el código que realiza una activación normalmente se
+asemeja a algo como esto:
+
+ evento_indicado = 1;
+ wake_up(&event_wait_queue); // despertar
+
+o:
+
+ evento_indicado = 1;
+ wake_up_process(event_daemon); // despertar proceso
+
+wake_up() ejecuta una barrera de memoria general si despierta algo. Si no
+despierta nada, entonces una barrera de memoria puede o no ser ejecutada;
+no debe confiar en ello. La barrera se produce antes del acceso al estado
+de la tarea. En particular, se encuentra entre el STORE para indicar el
+evento y el STORE para configurar TASK_RUNNING (hilo ejecutando):
+
+ CPU 1 (Durmiente) CPU 2 (Despertadora)
+ =============================== ===============================
+ set_current_state(); STORE evento_indicado
+ smp_store_mb(); wake_up();
+ STORE current->state ...
+ <barrera general> <barrera general>
+ LOAD evento_indicado if ((LOAD task->state) & TASK_NORMAL)
+ STORE task->state
+
+donde "task" es el subproceso que se está despertando y es igual al
+"current" (hilo actual) de la CPU 1.
+
+Para reiterar, se garantiza la ejecución de una barrera de memoria general
+mediante wake_up() si algo está realmente despierto, pero de lo contrario
+no existe tal garantía. Para entender esto, considere la siguiente
+secuencia de eventos, donde X e Y son ambos cero inicialmente:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ X = 1; Y = 1;
+ smp_mb(); wake_up();
+ LOAD Y LOAD X
+
+Si ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas
+debe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas
+pueden ver 0.
+
+wake_up_process() siempre ejecuta una barrera de memoria general. La
+barrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En
+particular, si wake_up(), en el fragmento anterior, fuera reemplazado por
+una llamada a wake_up_process(), las dos cargas verían 1, garantizado.
+
+Las funciones de activación disponibles incluyen:
+
+ complete();
+ wake_up();
+ wake_up_all();
+ wake_up_bit();
+ wake_up_interruptible();
+ wake_up_interruptible_all();
+ wake_up_interruptible_nr();
+ wake_up_interruptible_poll();
+ wake_up_interruptible_sync();
+ wake_up_interruptible_sync_poll();
+ wake_up_locked();
+ wake_up_locked_poll();
+ wake_up_nr();
+ wake_up_poll();
+ wake_up_process();
+
+En términos de orden de la memoria, todas estas funciones proporcionan las
+mismas garantías que un wake_up() (o más fuertes).
+
+[!] Tenga en cuenta que las barreras de la memoria implicadas por el
+durmiente y el despierto _no_ ordenan varios stores antes del despertar con
+respecto a cargas de los valores guardados después de que el durmiente haya
+llamado a set_current_state(). Por ejemplo, si el durmiente hace:
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (evento_indicado)
+ break;
+ __set_current_state(TASK_RUNNING);
+ hacer_algo(my_data);
+
+y el que despierta hace:
+
+ my_data = valor;
+ evento_indicado = 1;
+ wake_up(&event_wait_queue);
+
+no existe garantía de que el cambio a event_indicated sea percibido por
+el durmiente de manera que venga después del cambio a my_data. En tal
+circunstancia, el código en ambos lados debe sacar sus propias barreras de
+memoria entre los separados accesos a datos. Por lo tanto, el durmiente
+anterior debería hacer:
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (evento_indicado) {
+ smp_rmb();
+ hacer_algo(my_data);
+ }
+
+y el que despierta debería hacer:
+
+ my_data = value;
+ smp_wmb();
+ evento_indicado = 1;
+ wake_up(&event_wait_queue);
+
+FUNCIONES VARIAS
+----------------
+
+Otras funciones que implican barreras:
+
+ (*) schedule() y similares implican barreras completas de memoria.
+
+
+========================================
+EFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU
+========================================
+
+En los sistemas SMP, las primitivas de bloqueo proveen una forma más
+sustancial de barrera: una que afecta el orden de acceso a la memoria en
+otras CPU, dentro del contexto de conflicto en cualquier bloqueo en
+particular.
+
+
+ADQUISICIÓN VS ACCESOS A MEMORIA
+--------------------------------
+
+Considere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y
+tres CPU; entonces la siguiente secuencia de eventos debería ocurrir:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ WRITE_ONCE(*A, a); WRITE_ONCE(*E, e);
+ ACQUIRE M ACQUIRE Q
+ WRITE_ONCE(*B, b); WRITE_ONCE(*F, f);
+ WRITE_ONCE(*C, c); WRITE_ONCE(*G, g);
+ RELEASE M RELEASE Q
+ WRITE_ONCE(*D, d); WRITE_ONCE(*H, h);
+
+Entonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A
+hasta que *H ocurra, además de las restricciones impuestas por los bloqueos
+separados en las distintas CPUs. Podría, por ejemplo, ver:
+
+ *E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M
+
+Pero no verá ninguno de:
+
+ *B, *C or *D preceding ACQUIRE M
+ *A, *B or *C following RELEASE M
+ *F, *G or *H preceding ACQUIRE Q
+ *E, *F or *G following RELEASE Q
+
+========================================
+¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA?
+========================================
+
+Bajo operación normal, el re-ordenamiento de una operación de memoria
+generalmente no va a suponer un problema, ya que para una pieza de código
+lineal de un solo subproceso seguirá pareciendo que funciona correctamente,
+incluso si está en un kernel SMP. Existen, sin embargo, cuatro
+circunstancias en las que reordenar definitivamente _podría_ ser un
+problema:
+
+ (*) Interacción entre procesadores.
+
+ (*) Operaciones atómicas.
+
+ (*) Acceso a dispositivos.
+
+ (*) Interrupciones.
+
+
+INTERACCIÓN ENTRE PROCESADORES
+------------------------------
+
+Cuando se da un sistema con más de un procesador, más de una CPU en el
+sistema puede estar trabajando en el mismo conjunto de datos al mismo
+tiempo. Esto puede causar problemas de sincronización, y la forma habitual
+de tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son
+bastante caros, por lo que puede ser preferible operar sin el uso de un
+cerrojo a ser posible. En cuyo caso, es posible que las operaciones que
+afectan a ambas CPU deban ordenarse cuidadosamente para evitar un
+funcionamiento incorrecto.
+
+Considere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso
+de espera en cola del semáforo, en virtud de que tiene una parte de su pila
+vinculada a la lista de procesos en espera del semáforo:
+
+ struct rw_semaphore {
+ ...
+ spinlock_t lock;
+ struct list_head waiters;
+ };
+
+ struct rwsem_waiter {
+ struct list_head list;
+ struct task_struct *task;
+ };
+
+Para despertar a un proceso que espera ("waiter") en particular, las
+funciones up_read() o up_write() tienen que:
+
+ (1) leer el siguiente puntero del registro de este proceso que espera,
+ para saber dónde está el registro del siguiente waiter;
+
+ (2) leer el puntero a la estructura de tareas del waiter;
+
+ (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado
+ el semáforo;
+
+ (4) llamar a wake_up_process() en la tarea; y
+
+ (5) liberar la referencia retenida en la estructura de tareas del waiter.
+
+En otras palabras, tiene que realizar esta secuencia de eventos:
+
+ LOAD waiter->list.next;
+ LOAD waiter->task;
+ STORE waiter->task;
+ CALL wakeup
+ RELEASE task
+
+y si alguno de estos pasos ocurre fuera de orden, entonces todo puede que
+funcione defectuosamente.
+
+Una vez que se ha puesto en cola y soltado el bloqueo de semáforo, el
+proceso que espera no consigue el candado de nuevo; en cambio, solo espera
+a que se borre su puntero de tarea antes de continuar. Dado que el registro
+está en la pila del proceso que espera, esto significa que si el puntero de
+la tarea se borra _antes_ de que se lea el siguiente puntero de la lista,
+otra CPU podría comenzar a procesar el proceso que espera y podría romper
+el stack del proceso que espera antes de que la función up*() tenga la
+oportunidad de leer el puntero que sigue.
+
+Considere entonces lo que podría suceder con la secuencia de eventos
+anterior:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ down_xxx()
+ Poner waiter en la "queue" (cola)
+ Dormir
+ up_yyy()
+ LOAD waiter->task;
+ STORE waiter->task;
+ Despertado por otro evento
+ <preempt>
+ Reanudar el procesamiento
+ down_xxx() regresa
+ llamada a foo()
+ foo() estropea *waiter
+ </preempt>
+ LOAD waiter->list.next;
+ --- OOPS ---
+
+Esto podría solucionarse usando el bloqueo de semáforo, pero luego la
+función down_xxx() tiene que obtener innecesariamente el spinlock
+nuevamente, después de ser despertado el hilo.
+
+La forma de lidiar con esto es insertar una barrera de memoria SMP general:
+
+ LOAD waiter->list.next;
+ LOAD waiter->task;
+ smp_mb();
+ STORE waiter->task;
+ CALL wakeup
+ RELEASE task
+
+En este caso, la barrera garantiza que todos los accesos a memoria antes de
+la barrera parecerán suceder antes de todos los accesos a memoria después
+de dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza
+que todos los accesos a memoria antes de la barrera se completarán en el
+momento en que la instrucción de la barrera en sí se complete.
+
+En un sistema UP, donde esto no sería un problema, la función smp_mb() es
+solo una barrera del compilador, asegurándose así de que el compilador
+emita las instrucciones en el orden correcto sin realmente intervenir en la
+CPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se
+encargará de todo lo demás.
+
+
+OPERACIONES ATÓMICAS
+--------------------
+
+Si bien son, técnicamente, consideraciones de interacción entre
+procesadores, las operaciones atómicas se destacan especialmente porque
+algunas de ellas implican barreras de memoria completa y algunas otras no,
+pero se confía mucho en ellos en su conjunto a lo largo del kernel.
+
+Consulte Documentation/atomic_t.txt para obtener más información.
+
+
+ACCESO A DISPOSITIVOS
+---------------------
+
+Un driver puede ser interrumpido por su propia rutina de servicio de
+interrupción y, por lo tanto, las dos partes del driver pueden interferir
+con los intentos de controlar o acceder al dispositivo.
+
+Esto puede aliviarse, al menos en parte, desactivando las interrupciones
+locales (una forma de bloqueo), de modo que las operaciones críticas sean
+todas contenidas dentro la sección de interrupción desactivada en el
+controlador. Mientras la interrupción del driver está ejecutando la rutina,
+es posible que el "core" del controlador no se ejecute en la misma CPU y no
+se permita que su interrupción vuelva a ocurrir hasta que la interrupción
+actual haya sido resuelta, por lo tanto, el controlador de interrupción no
+necesita bloquearse contra esto.
+
+Sin embargo, considere un driver que estaba hablando con una tarjeta
+ethernet que tiene un registro de direcciones y un registro de datos. Si
+el core de ese controlador habla con la tarjeta estando en desactivación de
+interrupción y luego se invoca el controlador de interrupción del
+controlador:
+
+ IRQ LOCALES DESACTIVADAS
+ writew(ADDR, 3);
+ writew(DATA, y);
+ IRQ LOCALES ACTIVADAS
+ <interrupción>
+ writew(ADDR, 4);
+ q = readw(DATA);
+ </interrupción>
+
+El almacenamiento en el registro de datos puede ocurrir después del segundo
+almacenamiento en el registro de direcciones si las reglas de orden son lo
+suficientemente relajadas:
+
+ STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
+
+Si se relajan las reglas de orden, se debe asumir que los accesos
+realizados dentro de la sección con interrupción deshabilitada pueden
+filtrarse fuera de esta y pueden intercalarse con accesos realizados en una
+interrupción - y viceversa - a menos que se utilicenn barreras implícita o
+explícitas.
+
+Normalmente, esto no será un problema porque los accesos de E/S realizados
+dentro de tales secciones incluirán operaciones de carga síncronas en
+registros E/S estrictamente ordenados, que forman barreras de E/S
+implícitas.
+
+
+Una situación similar puede ocurrir entre una rutina de interrupción y dos
+rutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal
+caso es probable, entonces se deben usar bloqueos de desactivación de
+interrupciones para garantizar el orden.
+
+
+=====================================
+ Efectos de barrera de E/S del kernel
+=====================================
+
+La interfaz con periféricos a través de accesos de E/S es profundamente
+específica para cada arquitectura y dispositivo. Por lo tanto, los drivers
+que son inherentemente no portátiles pueden depender de comportamientos
+específicos de sus sistemas de destino, con el fin de lograr la
+sincronización de la manera más ligera posible. Para drivers que deseen ser
+portátiles entre múltiples arquitecturas e implementaciones de bus, el
+kernel ofrece una serie de funciones de acceso que proporcionan varios
+grados de garantías de orden:
+
+ (*) readX(), writeX():
+
+ Las funciones de acceso MMIO readX() y writeX() usan un puntero al
+ periférico al que se accede como un parámetro __iomem *. para punteros
+ asignados los atributos de E/S predeterminados (por ejemplo, los
+ devueltos por ioremap()), las garantías de orden son las siguientes:
+
+ 1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico
+ entre estos. Esto asegura que los registros de acceso MMIO por el
+ mismo subproceso de la CPU a un dispositivo en particular llegarán en
+ el orden del programa.
+
+ 2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un
+ spinlock antes de un writeX() al mismo periférico desde otro
+ subproceso de CPU, si emitido después de una adquisición posterior del
+ mismo spinlock. Esto garantiza que ese registro MMIO escribe en un
+ dispositivo en particular, mientras que se obtiene un spinlock en un
+ orden consistente con las adquisiciones del cerrojo.
+
+ 3. Un writeX() por un subproceso de la CPU al periférico primero esperará
+ a la finalización de todas las escrituras anteriores en la memoria
+ emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura
+ que las escrituras de la CPU a un búfer DMA de salida asignadas por
+ dma_alloc_coherent() serán visibles para un motor ("engine") DMA
+ cuando la CPU escriba en sus registros de control MMIO, para activar
+ la transferencia.
+
+ 4. Un readX() de un subproceso del CPU, desde el periférico, se
+ completará antes de que cualquier lectura subsiguiente de memoria por
+ el mismo subproceso pueda comenzar. Esto asegura que las lecturas de
+ la CPU desde un búfer DMA entrantes asignadas por
+ dma_alloc_coherent(), no verán datos obsoletos después de leer el
+ registro de estado MMIO del motor DMA, para establecer que la
+ transferencia DMA se haya completado.
+
+ 5. Un readX() por un subproceso del CPU, desde el periférico, se
+ completará antes de que cualquier bucle delay() subsiguiente pueda
+ comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos
+ escrituras del CPU a registros MMIO en un periférico llegarán al menos
+ con 1us de diferencia, si la primera escritura se lee inmediatamente
+ de vuelta con readX() y se llama a udelay(1) antes del segundo
+ writeX():
+
+ writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ...
+ readl(DEVICE_REGISTER_0);
+ udelay(1);
+ writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto....
+
+Las propiedades de orden de los punteros __iomem obtenidos con valores de
+atributos que no sean los valores por defecto (por ejemplo, los devueltos
+por ioremap_wc()) son específicos de la arquitectura subyacente y, por lo
+tanto, las garantías enumeradas anteriormente no pueden por lo general ser
+aseguradas para accesos a este tipo de "mappings" (asignaciones).
+
+ (*) readX_relaxed(), writeX_relaxed():
+
+ Son similares a readX() y writeX(), pero proporcionan una garantía de
+ orden de memoria más débil. Específicamente, no garantizan orden con
+ respecto al bloqueo, los accesos normales a la memoria o los bucles
+ delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que
+ se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU,
+ al mismo periférico, cuando se opera en punteros __iomem asignados con el
+ valor predeterminado para los atributos de E/S.
+
+ (*) readsX(), writesX():
+
+ Los puntos de entrada readsX() y writesX() MMIO están diseñados para
+ acceder FIFOs mapeados en memoria y basados en registros que residen en
+ periféricos, que no son capaces de realizar DMA. Por tanto, sólo
+ proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como
+ se documentó anteriormente.
+
+ (*) inX(), outX():
+
+ Los puntos de entrada inX() y outX() están destinados a acceder a mapas
+ de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir
+ instrucciones especiales en algunas arquitecturas (especialmente, en
+ x86). El número de puerto del periférico que se está accedido se pasa
+ como un argumento.
+
+ Dado que muchas arquitecturas de CPU acceden finalmente a estos
+ periféricos a través de un mapeo interno de memoria virtual, las
+ garantías de orden portátiles proporcionadas por inX() y outX() son las
+ mismas que las proporcionadas por readX() y writeX(), respectivamente, al
+ acceder a una asignación con los valores de atributos de E/S
+ predeterminados (los que haya por defecto).
+
+ Los drivers de dispositivos pueden esperar que outX() emita una
+ transacción de escritura no publicada, que espera una respuesta de
+ finalización del periférico de E/S antes de regresar. Esto no está
+ garantizado por todas las arquitecturas y por lo tanto no forma parte de
+ la semántica de orden portátil.
+
+ (*) insX(), outsX():
+
+ Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo
+ orden garantizado por readsX() y writesX() respectivamente, al acceder a
+ un mapping con los atributos de E/S predeterminados.
+
+ (*) ioreadX(), iowriteX():
+
+ Estos funcionarán adecuadamente para el tipo de acceso que realmente están
+ haciendo, ya sea inX()/outX() o readX()/writeX().
+
+Con la excepción de los puntos de entrada (insX(), outsX(), readsX() y
+writesX()), todo lo anterior supone que el periférico subyacente es
+little-endian y, por lo tanto, realizará operaciones de intercambio de
+bytes en arquitecturas big-endian.
+
+
+===========================================
+MODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO
+===========================================
+
+Debe suponerse que la CPU conceptual está débilmente ordenada, pero que
+mantiene la apariencia de causalidad del programa con respecto a sí misma.
+Algunas CPU (como i386 o x86_64) están más limitadas que otras (como
+powerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se
+debe asumir fuera de código específico de arquitectura.
+
+Esto significa que se debe considerar que la CPU ejecutará su flujo de
+instrucciones en el orden que se quiera - o incluso en paralelo - siempre
+que si una instrucción en el flujo depende de una instrucción anterior,
+entonces dicha instrucción anterior debe ser lo suficientemente completa[*]
+antes de que la posterior instrucción puede proceder; en otras palabras:
+siempre que la apariencia de causalidad se mantenga.
+
+ [*] Algunas instrucciones tienen más de un efecto, como cambiar el
+ código de condición, cambio de registros o cambio de memoria - y
+ distintas instrucciones pueden depender de diferentes efectos.
+
+Una CPU puede también descartar cualquier secuencia de instrucciones que
+termine sin tener efecto final. Por ejemplo, si dos instrucciones
+adyacentes cargan un valor inmediato en el mismo registro, la primera puede
+descartarse.
+
+
+De manera similar, se debe suponer que el compilador podría reordenar la
+corriente de instrucciones de la manera que crea conveniente, nuevamente
+siempre que la apariencia de causalidad se mantenga.
+
+
+=====================================
+EFECTOS DE LA MEMORIA CACHÉ DE LA CPU
+=====================================
+
+La forma en que se perciben las operaciones de memoria caché en todo el
+sistema se ve afectada, hasta cierto punto, por los cachés que se
+encuentran entre las CPU y la memoria, y por el sistema de coherencia en
+memoria que mantiene la consistencia de estado en el sistema.
+
+En cuanto a la forma en que una CPU interactúa con otra parte del sistema a
+través del caché, el sistema de memoria tiene que incluir los cachés de la
+CPU y barreras de memoria, que en su mayor parte actúan en la interfaz
+entre la CPU y su caché (las barreras de memoria lógicamente actúan sobre
+la línea de puntos en el siguiente diagrama):
+
+ <--- CPU ---> : <----------- Memoria ----------->
+ :
+ +--------+ +--------+ : +--------+ +-----------+
+ | Core | | Cola | : | Cache | | | +---------+
+ | CPU | | de | : | CPU | | | | |
+ | |--->| acceso |----->| |<-->| | | |
+ | | | a | : | | | |--->| Memoria |
+ | | | memoria| : | | | | | |
+ +--------+ +--------+ : +--------+ | Mecanismo | | |
+ : | de | +---------+
+ : | Coherencia|
+ : | de la | +--------+
+ +--------+ +--------+ : +--------+ | cache | | |
+ | Core | | Cola | : | Cache | | | | |
+ | CPU | | de | : | CPU | | |--->| Dispos |
+ | |--->| acceso |----->| |<-->| | | itivo |
+ | | | a | : | | | | | |
+ | | | memoria| : | | | | +--------+
+ +--------+ +--------+ : +--------+ +-----------+
+ :
+ :
+
+Aunque es posible que una carga o store en particular no aparezca fuera de
+la CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio
+caché de la CPU, seguirá pareciendo como si el acceso total a la memoria
+hubiera tenido lugar para las otras CPUs, ya que los mecanismos de
+coherencia de caché migrarán la cacheline sobre la CPU que accede y se
+propagarán los efectos en caso de conflicto.
+
+El núcleo de la CPU puede ejecutar instrucciones en el orden que considere
+adecuado, siempre que parezca mantenerse la causalidad esperada del
+programa. Algunas de las instrucciones generan operaciones de carga y
+almacenamiento que luego van a la cola de accesos a memoria a realizar. El
+núcleo puede colocarlos en la cola en cualquier orden que desee, y
+continuar su ejecución hasta que se vea obligado a esperar que una
+instrucción sea completada.
+
+De lo que se ocupan las barreras de la memoria es de controlar el orden en
+que los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria,
+y el orden en que los otros observadores perciben los efectos en el sistema
+que sucedan por esto.
+
+[!] Las barreras de memoria _no_ son necesarias dentro de una CPU
+determinada, ya que las CPU siempre ven sus propias cargas y stores como si
+hubieran sucedido en el orden del programa.
+
+[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el
+sistema de caché. Esto depende de las propiedades de la ventana de memoria
+a través de la cual se accede a los dispositivos y/o el uso de
+instrucciones especiales de comunicación con dispositivo que pueda tener la
+CPU.
+
+
+COHERENCIA DE CACHÉ FRENTE A DMA
+---------------------------------
+
+No todos los sistemas mantienen coherencia de caché con respecto a los
+dispositivos que realizan DMA. En tales casos, un dispositivo que intente
+DMA puede obtener datos obsoletos de la RAM, porque las líneas de caché
+"sucias" pueden residir en los cachés de varias CPU, y es posible que no
+se hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la
+parte apropiada del kernel debe vaciar los bits superpuestos de caché en
+cada CPU (y tal vez también invalidarlos).
+
+Además, los datos enviados por DMA a RAM, por un dispositivo, pueden ser
+sobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM
+desde el caché de una CPU, después de que el dispositivo haya puesto sus
+propios datos, o las líneas de caché presentes en el caché de la CPU pueden
+simplemente ocultar el hecho de que la memoria RAM se haya actualizado,
+hasta el momento en que la caché se descarta de la memoria caché de la CPU
+y se vuelve a cargar. Para hacer frente a esto, la parte apropiada del
+kernel debe invalidar los bits superpuestos del caché en cada CPU.
+
+Consulte Documentation/core-api/cachetlb.rst para obtener más información
+sobre administración de la memoria caché.
+
+
+COHERENCIA DE CACHÉ FRENTE A MMIO
+---------------------------------
+
+La E/S mapeada en memoria generalmente se lleva a cabo a través de
+ubicaciones de memoria que forman parte de una ventana del espacio de
+memoria de la CPU, que tiene diferentes propiedades asignadas que la
+ventana habitual dirigida a RAM.
+
+Entre dichas propiedades, suele existir el hecho de que tales accesos
+eluden el almacenamiento en caché por completo e ir directamente a los
+buses del dispositivo. Esto significa que los accesos MMIO pueden, en
+efecto, superar los accesos a la memoria caché que se emitieron
+anteriormente. Una barrera de memoria no es suficiente en tal caso, sino
+que el caché debe ser vaciado entre la escritura de la memoria caché, y el
+acceso MMIO, si los dos son de cualquier manera dependiente.
+
+
+=======================
+COSAS QUE HACEN LAS CPU
+=======================
+
+Un programador podría dar por sentado que la CPU realizará las operaciones
+de memoria exactamente en el orden especificado, de modo que si a la CPU se
+entrega, por ejemplo, el siguiente fragmento de código a ejecutar:
+
+ a = READ_ONCE(*A);
+ WRITE_ONCE(*B, b);
+ c = READ_ONCE(*C);
+ d = READ_ONCE(*D);
+ WRITE_ONCE(*E, e);
+
+esperarían entonces que la CPU complete la operación de memoria para cada
+instrucción antes de pasar a la siguiente, lo que lleva a una definida
+secuencia de operaciones vistas por observadores externos en el sistema:
+
+ LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
+
+La realidad es, por supuesto, mucho más intrincada. Para muchas CPU y
+compiladores, la anterior suposición no se sostiene porque:
+
+ (*) es más probable que las cargas deban completarse de inmediato para
+ permitir progreso en la ejecución, mientras que los stores a menudo se
+ pueden aplazar sin problema;
+
+ (*) las cargas se pueden hacer especulativamente, y el resultado es
+ descartado si resulta innecesario;
+
+ (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que
+ se haya obtenido el resultado en el momento equivocado de la secuencia
+ de eventos esperada;
+
+ (*) el orden de los accesos a memoria se puede reorganizar para promover
+ un mejor uso de los buses y cachés de la CPU;
+
+ (*) las cargas y los stores se pueden combinar para mejorar el rendimiento
+ cuando se habla con memoria o hardware de E/S, que puede realizar
+ accesos por lotes a ubicaciones adyacentes, reduciendo así los costes
+ de configuración de transacciones (la memoria y los dispositivos PCI
+ pueden ambos pueden hacer esto); y
+
+ (*) la caché de datos de la CPU puede afectar al orden, y mientras sus
+ mecanismos de coherencia pueden aliviar esto, una vez que el store
+ haya accedido al caché- no hay garantía de que la gestión de la
+ coherencia se propague en orden a otras CPU.
+
+Entonces, digamos que lo que otra CPU podría observar en el fragmento de
+código anterior es:
+
+ LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
+
+ (Donde "LOAD {*C,*D}" es una carga combinada)
+
+
+Sin embargo, se garantiza que una CPU es autoconsistente: verá que sus
+ _propios_ accesos parecen estar correctamente ordenados, sin necesidad de
+barrera de memoria. Por ejemplo con el siguiente código:
+
+ U = READ_ONCE(*A);
+ WRITE_ONCE(*A, V);
+ WRITE_ONCE(*A, W);
+ X = READ_ONCE(*A);
+ WRITE_ONCE(*A, Y);
+ Z = READ_ONCE(*A);
+
+y asumiendo que no hay intervención de una influencia externa, se puede
+suponer que el resultado final se parecerá a:
+
+ U == el valor original de *A
+ X == W
+ Z == Y
+ *A == Y
+
+El código anterior puede hacer que la CPU genere la secuencia completa de
+accesos de memoria:
+
+ U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
+
+en ese orden, pero, sin intervención, la secuencia puede contener casi
+cualquier combinación de elementos combinados o descartados, siempre que la
+perspectiva del programa del mundo siga siendo consistente. Tenga en cuenta
+que READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior,
+ya que hay arquitecturas donde una CPU determinada podría reordenar cargas
+sucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y
+WRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en
+Itanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen
+que GCC emita las instrucciones especiales ld.acq y st.rel
+(respectivamente) que impiden dicha reordenación.
+
+El compilador también puede combinar, descartar o diferir elementos de la
+secuencia antes incluso de que la CPU los vea.
+
+Por ejemplo:
+
+ *A = V;
+ *A = W;
+
+puede reducirse a:
+
+ *A = W;
+
+ya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma
+que el efecto del almacenamiento de V a *A se pierde. Similarmente:
+
+ *A = Y;
+ Z = *A;
+
+puede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto
+sea reducido a:
+
+ *A = Y;
+ Z = Y;
+
+y la operación LOAD nunca aparezca fuera de la CPU.
+
+
+Y LUEGO ESTÁ EL ALFA
+--------------------
+
+La CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso,
+algunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que
+les permite tener dos líneas de caché relacionadas semánticamente,
+actualizadas en momentos separados. Aquí es donde la barrera de dependencia
+de dirección realmente se vuelve necesaria, ya que se sincronizan ambos
+cachés con el sistema de coherencia de memoria, lo que hace que parezca un
+cambio en el puntero, frente a que los nuevos datos se produzcan en el
+orden correcto.
+
+Alpha define el modelo de memoria del kernel Linux, aunque a partir de
+v4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha
+redujo en gran medida su impacto en el modelo de memoria.
+
+
+GUESTS DE MÁQUINAS VIRTUALES
+-----------------------------
+
+Los "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse
+afectados por los efectos de SMP incluso si el "host" (huésped) en sí se
+compila sin compatibilidad con SMP. Este es un efecto de la interacción con
+un host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras
+para este caso de uso sería posible, pero a menudo no son óptimas.
+
+Para hacer frente a este caso de manera óptima, están disponibles macros de
+bajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc.
+cuando SMP está habilitado, pero generan código idéntico para sistemas SMP
+y no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar
+virt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP)
+anfitrión.
+
+Estos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás
+aspectos, en particular, no controlan los efectos MMIO: para controlar los
+efectos MMIO, utilice barreras obligatorias.
+
+
+================
+EJEMPLOS DE USOS
+================
+
+BUFFERS CIRCULARES
+------------------
+
+Las barreras de memoria se pueden utilizar para implementar almacenamiento
+en búfer circular, sin necesidad de un cerrojo para serializar al productor
+con el consumidor. Vea:
+
+ Documentation/core-api/circular-buffers.rst
+
+para más detalles.
+
+
+===========
+REFERENCIAS
+===========
+
+Alpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek,
+Digital Press)
+ Capítulo 5.2: Physical Address Space Characteristics
+ Capítulo 5.4: Caches and Write Buffers
+ Capítulo 5.5: Data Sharing
+ Capítulo 5.6: Read/Write Ordering
+
+AMD64 Architecture Programmer's Manual Volumen 2: System Programming
+ Capítulo 7.1: Memory-Access Ordering
+ Capítulo 7.4: Buffering and Combining Memory Writes
+
+ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
+ Capítulo B2: The AArch64 Application Level Memory Model
+
+IA-32 Intel Architecture Software Developer's Manual, Volumen 3:
+System Programming Guide
+ Capítulo 7.1: Locked Atomic Operations
+ Capítulo 7.2: Memory Ordering
+ Capítulo 7.4: Serializing Instructions
+
+The SPARC Architecture Manual, Version 9
+ Capítulo 8: Memory Models
+ Appendix D: Formal Specification of the Memory Models
+ Appendix J: Programming with the Memory Models
+
+Storage in the PowerPC (por Stone and Fitzgerald)
+
+UltraSPARC Programmer Reference Manual
+ Capítulo 5: Memory Accesses and Cacheability
+ Capítulo 15: Sparc-V9 Memory Models
+
+UltraSPARC III Cu User's Manual
+ Capítulo 9: Memory Models
+
+UltraSPARC IIIi Processor User's Manual
+ Capítulo 8: Memory Models
+
+UltraSPARC Architecture 2005
+ Capítulo 9: Memory
+ Appendix D: Formal Specifications of the Memory Models
+
+UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
+ Capítulo 8: Memory Models
+ Appendix F: Caches and Cache Coherency
+
+Solaris Internals, Core Kernel Architecture, p63-68:
+ Capítulo 3.3: Hardware Considerations for Locks and
+ Synchronization
+
+Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
+for Kernel Programmers:
+ Capítulo 13: Other Memory Models
+
+Intel Itanium Architecture Software Developer's Manual: Volumen 1:
+ Sección 2.6: Speculation
+ Sección 4.4: Memory Access
diff --git a/Documentation/translations/sp_SP/process/coding-style.rst b/Documentation/translations/sp_SP/process/coding-style.rst
new file mode 100644
index 000000000000..a0261ba5b902
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/coding-style.rst
@@ -0,0 +1,1315 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/coding-style.rst <submittingpatches>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_codingstyle:
+
+Estilo en el código del kernel Linux
+=====================================
+
+Este es un breve documento que describe el estilo preferido en el código
+del kernel Linux. El estilo de código es muy personal y no **forzaré** mi
+puntos de vista sobre nadie, pero esto vale para todo lo que tengo que
+mantener, y preferiría que para la mayoría de otras cosas también. Por
+favor, por lo menos considere los argumentos expuestos aquí.
+
+En primer lugar, sugeriría imprimir una copia de los estándares de código
+GNU, y NO leerlo. Quémelos, es un gran gesto simbólico.
+
+De todos modos, aquí va:
+
+
+1) Sangría
+-----------
+
+Las tabulaciones tienen 8 caracteres y, por lo tanto, las sangrías también
+tienen 8 caracteres. Hay movimientos heréticos que intentan hacer sangría
+de 4 (¡o incluso 2!) caracteres de longitud, y eso es similar a tratar de
+definir el valor de PI como 3.
+
+Justificación: La idea detrás de la sangría es definir claramente dónde
+comienza y termina un bloque de control. Especialmente, cuando ha estado
+buscando en su pantalla durante 20 horas seguidas, le resultará mucho más
+fácil ver cómo funciona la sangría si tiene sangrías grandes.
+
+Bueno, algunas personas dirán que tener sangrías de 8 caracteres hace que
+el código se mueva demasiado a la derecha y dificulta la lectura en una
+pantalla de terminal de 80 caracteres. La respuesta a eso es que si
+necesita más de 3 niveles de sangría, está en apuros de todos modos y
+debería arreglar su programa.
+
+En resumen, las sangrías de 8 caracteres facilitan la lectura y tienen la
+ventaja añadida de advertirle cuando está anidando sus funciones demasiado
+profundo. Preste atención a esa advertencia.
+
+La forma preferida de facilitar múltiples niveles de sangría en una
+declaración de switch es para alinear el ``switch`` y sus etiquetas
+``case`` subordinadas en la misma columna, en lugar de hacer ``doble
+sangría`` (``double-indenting``) en etiquetas ``case``. Por ejemplo:
+
+.. code-block:: c
+
+ switch (suffix) {
+ case 'G':
+ case 'g':
+ mem <<= 30;
+ break;
+ case 'M':
+ case 'm':
+ mem <<= 20;
+ break;
+ case 'K':
+ case 'k':
+ mem <<= 10;
+ fallthrough;
+ default:
+ break;
+ }
+
+No ponga varias declaraciones en una sola línea a menos que tenga algo que
+ocultar:
+
+.. code-block:: c
+
+ if (condición) haz_esto;
+ haz_otra_cosa;
+
+No use comas para evitar el uso de llaves:
+
+.. code-block:: c
+
+ if (condición)
+ haz_esto(), haz_eso();
+
+Siempre use llaves para múltiples declaraciones:
+
+.. code-block:: c
+
+ if (condición) {
+ haz_esto();
+ haz_eso();
+ }
+
+Tampoco ponga varias asignaciones en una sola línea. El estilo de código
+del kernel es súper simple. Evite las expresiones engañosas.
+
+
+Aparte de los comentarios, la documentación y excepto en Kconfig, los
+espacios nunca se utilizan para la sangría, y el ejemplo anterior se rompe
+deliberadamente.
+
+Consiga un editor decente y no deje espacios en blanco al final de las
+líneas.
+
+2) Rompiendo líneas y strings largos
+------------------------------------
+
+El estilo de código tiene todo que ver con la legibilidad y la
+mantenibilidad usando herramientas disponibles comúnmente.
+
+El límite preferido en la longitud de una sola línea es de 80 columnas.
+
+Las declaraciones de más de 80 columnas deben dividirse en partes, a menos
+que exceder las 80 columnas aumente significativamente la legibilidad y no
+oculte información.
+
+Los descendientes siempre son sustancialmente más cortos que el padre y
+se colocan sustancialmente a la derecha. Un estilo muy usado es alinear
+descendientes a un paréntesis de función abierto.
+
+Estas mismas reglas se aplican a los encabezados de funciones con una larga
+lista de argumentos.
+
+Sin embargo, nunca rompa los strings visibles para el usuario, como los
+mensajes printk, porque eso rompe la capacidad de grep a estos.
+
+
+3) Colocación de llaves y espacios
+----------------------------------
+
+El otro problema que siempre surge en el estilo C es la colocación de
+llaves. A diferencia del tamaño de la sangría, existen pocas razones
+técnicas para elegir una estrategia de ubicación sobre la otra, pero la
+forma preferida, como mostraron los profetas Kernighan y Ritchie, es poner
+la llave de apertura en la línea, y colocar la llave de cierre primero,
+así:
+
+.. code-block:: c
+
+ if (x es verdad) {
+ hacemos y
+ }
+
+Esto se aplica a todos los bloques de declaraciones que no son funciones
+(if, switch, for, while, do). Por ejemplo:
+
+.. code-block:: c
+
+ switch (action) {
+ case KOBJ_ADD:
+ return "add";
+ case KOBJ_REMOVE:
+ return "remove";
+ case KOBJ_CHANGE:
+ return "change";
+ default:
+ return NULL;
+ }
+
+Sin embargo, hay un caso especial, a saber, las funciones: tienen la llave
+de apertura al comienzo de la siguiente línea, así:
+
+.. code-block:: c
+
+ int funcion(int x)
+ {
+ cuerpo de la función
+ }
+
+Gente hereje de todo el mundo ha afirmado que esta inconsistencia es...
+bueno... inconsistente, pero todas las personas sensatas saben que
+(a) K&R tienen **razón** y (b) K&R tienen razón. Además, las funciones son
+especiales de todos modos (no puede anidarlas en C).
+
+Tenga en cuenta que la llave de cierre está vacía en su línea propia,
+**excepto** en los casos en que es seguida por una continuación de la misma
+declaración, es decir, un ``while`` en una sentencia do o un ``else`` en
+una sentencia if, como en:
+
+.. code-block:: c
+
+ do {
+ cuerpo del bucle do
+ } while (condition);
+
+y
+
+.. code-block:: c
+
+ if (x == y) {
+ ..
+ } else if (x > y) {
+ ...
+ } else {
+ ....
+ }
+
+Justificación: K&R.
+
+Además, tenga en cuenta que esta colocación de llaves también minimiza el
+número de líneas vacías (o casi vacías), sin pérdida de legibilidad. Así,
+como el suministro de nuevas líneas en su pantalla no es un recurso
+renovable (piense en pantallas de terminal de 25 líneas), tienes más líneas
+vacías para poner comentarios.
+
+No use llaves innecesariamente donde una sola declaración sea suficiente.
+
+.. code-block:: c
+
+ if (condition)
+ accion();
+
+y
+
+.. code-block:: none
+
+ if (condición)
+ haz_esto();
+ else
+ haz_eso();
+
+Esto no aplica si solo una rama de una declaración condicional es una sola
+declaración; en este último caso utilice llaves en ambas ramas:
+
+.. code-block:: c
+
+ if (condición) {
+ haz_esto();
+ haz_eso();
+ } else {
+ en_otro_caso();
+ }
+
+Además, use llaves cuando un bucle contenga más de una declaración simple:
+
+.. code-block:: c
+
+ while (condición) {
+ if (test)
+ haz_eso();
+ }
+
+3.1) Espacios
+*************
+
+El estilo del kernel Linux para el uso de espacios depende (principalmente)
+del uso de función versus uso de palabra clave. Utilice un espacio después
+de (la mayoría de) las palabras clave. Las excepciones notables son sizeof,
+typeof, alignof y __attribute__, que parecen algo así como funciones (y
+generalmente se usan con paréntesis en Linux, aunque no son requeridos en
+el idioma, como en: ``sizeof info`` después de que ``struct fileinfo info;``
+se declare).
+
+Así que use un espacio después de estas palabras clave::
+
+ if, switch, case, for, do, while
+
+pero no con sizeof, typeof, alignof, o __attribute__. Por ejemplo,
+
+.. code-block:: c
+
+
+ s = sizeof(struct file);
+
+No agregue espacios alrededor (dentro) de expresiones entre paréntesis.
+Este ejemplo es **malo**:
+
+.. code-block:: c
+
+
+ s = sizeof( struct file );
+
+Al declarar datos de puntero o una función que devuelve un tipo de puntero,
+el uso preferido de ``*`` es adyacente al nombre del dato o nombre de la
+función y no junto al nombre del tipo. Ejemplos:
+
+.. code-block:: c
+
+
+ char *linux_banner;
+ unsigned long long memparse(char *ptr, char **retptr);
+ char *match_strdup(substring_t *s);
+
+Use un espacio alrededor (a cada lado de) la mayoría de los operadores
+binarios y ternarios, como cualquiera de estos::
+
+ = + - < > * / % | & ^ <= >= == != ? :
+
+pero sin espacio después de los operadores unarios::
+
+ & * + - ~ ! sizeof typeof alignof __attribute__ defined
+
+sin espacio antes de los operadores unarios de incremento y decremento del
+sufijo::
+
+ ++ --
+
+y sin espacio alrededor de los operadores de miembros de estructura ``.`` y
+``->``.
+
+No deje espacios en blanco al final de las líneas. Algunos editores con
+``inteligente`` sangría insertarán espacios en blanco al comienzo de las
+nuevas líneas como sea apropiado, para que pueda comenzar a escribir la
+siguiente línea de código de inmediato. Sin embargo, algunos de estos
+editores no eliminan los espacios en blanco si finalmente no termina
+poniendo una línea de código allí, como si dejara una línea en blanco. Como
+resultado, termina con líneas que contienen espacios en blanco al final.
+
+Git le advertirá sobre los parches que introducen espacios en blanco al
+final y puede, opcionalmente, eliminar los espacios en blanco finales por
+usted; sin embargo, si se aplica una serie de parches, esto puede hacer que
+los parches posteriores de la serie fallen al cambiar sus líneas de
+contexto.
+
+
+4) Nomenclatura
+---------------
+
+C es un lenguaje espartano, y sus convenciones de nomenclatura deberían
+seguir su ejemplo. A diferencia de los programadores de Modula-2 y Pascal,
+los programadores de C no usan nombres cuquis como
+EstaVariableEsUnContadorTemporal. Un programador de C lo llamaría
+variable ``tmp``, que es mucho más fácil de escribir, y no es mas difícil
+de comprender.
+
+SIN EMBARGO, mientras que los nombres de mayúsculas y minúsculas están mal
+vistos, los nombres descriptivos para las variables globales son
+imprescindibles. Llamar a una función global ``foo`` es un delito.
+
+Una variable GLOBAL (para usar solo si **realmente** las necesita) necesita
+tener un nombre descriptivo, al igual que las funciones globales. Si tiene
+una función que cuenta el número de usuarios activos, debe llamar a esta
+``contar_usuarios_activos()`` o similar, **no** debe llamarlo ``cntusr()``.
+
+Codificar el tipo de una función en el nombre (lo llamado notación húngara)
+es estúpido: el compilador conoce los tipos de todos modos y puede
+verificar estos, y solo confunde al programador.
+
+Los nombres de las variables LOCALES deben ser breves y directos. Si usted
+tiene algún contador aleatorio de tipo entero, probablemente debería
+llamarse ``i``. Llamarlo ``loop_counter`` no es productivo, si no hay
+posibilidad de ser mal entendido. De manera similar, ``tmp`` puede ser casi
+cualquier tipo de variable que se utiliza para contener un valor temporal.
+
+Si tiene miedo de mezclar los nombres de las variables locales, tiene otro
+problema, que se denomina síndrome de
+función-crecimiento-desequilibrio-de-hormona. Vea el capítulo 6 (Funciones).
+
+Para nombres de símbolos y documentación, evite introducir nuevos usos de
+'master / slave' (maestro / esclavo) (o 'slave' independientemente de
+'master') y 'lista negra / lista blanca' (backlist / whitelist).
+
+Los reemplazos recomendados para 'maestro / esclavo' son:
+ '{primary,main} / {secondary,replica,subordinate}'
+ '{initiator,requester} / {target,responder}'
+ '{controller,host} / {device,worker,proxy}'
+ 'leader / follower'
+ 'director / performer'
+
+Los reemplazos recomendados para 'backlist / whitelist' son:
+ 'denylist / allowlist'
+ 'blocklist / passlist'
+
+Las excepciones para la introducción de nuevos usos son mantener en espacio
+de usuario una ABI/API, o al actualizar la especificación del código de un
+hardware o protocolo existente (a partir de 2020) que requiere esos
+términos. Para nuevas especificaciones, traduzca el uso de la terminología
+de la especificación al estándar de código del kernel donde sea posible.
+
+5) Typedefs
+-----------
+
+Por favor no use cosas como ``vps_t``.
+Es un **error** usar typedef para estructuras y punteros. cuando ve un
+
+.. code-block:: c
+
+
+ vps_t a;
+
+en el código fuente, ¿qué significa?
+En cambio, si dice
+
+.. code-block:: c
+
+ struct virtual_container *a;
+
+puede decir qué es ``a`` en realidad.
+
+Mucha gente piensa que los typedefs ``ayudan a la legibilidad``. No. Son
+útiles solamente para:
+
+ (a) objetos totalmente opacos (donde el typedef se usa activamente para
+ **ocultar** cuál es el objeto).
+
+ Ejemplo: ``pte_t`` etc. objetos opacos a los que solo puede acceder
+ usando las funciones de acceso adecuadas.
+
+ .. note::
+
+ La opacidad y las ``funciones de acceso`` no son buenas por sí
+ mismas. La razón por la que los tenemos para cosas como pte_t, etc.
+ es que hay real y absolutamente **cero** información accesible de
+ forma portátil allí.
+
+ (b) Tipos enteros claros, donde la abstracción **ayuda** a evitar
+ confusiones, ya sea ``int`` o ``long``.
+
+ u8/u16/u32 son definiciones tipográficas perfectamente correctas
+ aunque encajan en la categoría (d) mejor que aquí.
+
+ .. note::
+
+ De nuevo - debe haber una **razón** para esto. si algo es
+ ``unsigned long``, entonces no hay razón para hacerlo
+
+ typedef unsigned long mis_flags_t;
+
+ pero si hay una razón clara de por qué bajo ciertas circunstancias
+ podría ser un ``unsigned int`` y bajo otras configuraciones podría
+ ser ``unsigned long``, entonces, sin duda, adelante y use un typedef.
+
+ (c) cuando lo use para crear literalmente un tipo **nuevo** para
+ comprobación de tipos.
+
+ (d) Nuevos tipos que son idénticos a los tipos estándar C99, en ciertas
+ circunstancias excepcionales.
+
+ Aunque sólo costaría un corto período de tiempo para los ojos y
+ cerebro para acostumbrarse a los tipos estándar como ``uint32_t``,
+ algunas personas se oponen a su uso de todos modos.
+
+ Por lo tanto, los tipos ``u8/u16/u32/u64`` específicos de Linux y sus
+ equivalentes con signo, que son idénticos a los tipos estándar son
+ permitidos, aunque no son obligatorios en el nuevo código de su
+ elección.
+
+ Al editar código existente que ya usa uno u otro conjunto de tipos,
+ debe ajustarse a las opciones existentes en ese código.
+
+ (e) Tipos seguros para usar en el espacio de usuario.
+
+ En ciertas estructuras que son visibles para el espacio de usuario, no
+ podemos requerir tipos C99 y o utilizat el ``u32`` anterior. Por lo
+ tanto, usamos __u32 y tipos similares en todas las estructuras que se
+ comparten con espacio de usuario.
+
+Tal vez también haya otros casos, pero la regla básicamente debería ser
+NUNCA JAMÁS use un typedef a menos que pueda coincidir claramente con una
+de estas reglas.
+
+En general, un puntero o una estructura que tiene elementos que pueden
+ser razonablemente accedidos directamente, **nunca** deben ser un typedef.
+
+6) Funciones
+------------
+
+Las funciones deben ser cortas y dulces, y hacer una sola cosa. Deberían
+caber en una o dos pantallas de texto (el tamaño de pantalla ISO/ANSI es
+80x24, como todos sabemos), y hacer una cosa y hacerla bien.
+
+La longitud máxima de una función es inversamente proporcional a la
+complejidad y el nivel de sangría de esa función. Entonces, si tiene una
+función conceptualmente simple que es solo una larga (pero simple)
+declaración de case, donde tiene que hacer un montón de pequeñas cosas para
+un montón de diferentes casos, está bien tener una función más larga.
+
+Sin embargo, si tiene una función compleja y sospecha que un estudiante de
+primer año de secundaria menos que dotado podría no comprender de qué se
+trata la función, debe adherirse a los límites máximos tanto más de
+cerca. Use funciones auxiliares con nombres descriptivos (puede pedirle al
+compilador que los alinee si cree que es crítico para el rendimiento, y
+probablemente lo hará mejor de lo que usted hubiera hecho).
+
+Otra medida de la función es el número de variables locales. Estas no deben
+exceder de 5 a 10, o está haciendo algo mal. Piense de nuevo en la función
+y divida en partes más pequeñas. Un cerebro humano puede generalmente
+realiza un seguimiento de aproximadamente 7 cosas diferentes, cualquier
+elemento más y se confunde. Usted sabe que es brillante, pero tal vez le
+gustaría entender lo que hizo dentro de 2 semanas.
+
+En los archivos fuente, separe las funciones con una línea en blanco. Si la
+función es exportada, la macro **EXPORT** debería ponerse inmediatamente
+después de la función de cierre de línea de llave. Por ejemplo:
+
+.. code-block:: c
+
+ int sistema_corriendo(void)
+ {
+ return estado_sistema == SISTEMA_CORRIENDO;
+ }
+ EXPORT_SYMBOL(sistema_corriendo);
+
+6.1) Prototipos de funciones
+****************************
+
+En los prototipos de funciones, incluya nombres de parámetros con sus tipos
+de datos. Aunque esto no es requerido por el lenguaje C, se prefiere en
+Linux porque es una forma sencilla de añadir información valiosa para el
+lector.
+
+No utilice la palabra clave ``extern`` con declaraciones de función ya que
+esto hace las líneas más largas y no es estrictamente necesario.
+
+Al escribir prototipos de funciones, mantenga el `orden de los elementos regular
+<https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_.
+Por ejemplo, usando este ejemplo de declaración de función::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+ char *fmt, ...) __printf(4, 5) __malloc;
+
+El orden preferido de elementos para un prototipo de función es:
+
+- clase de almacenamiento (a continuación, ``static __always_inline``,
+ teniendo en cuenta que ``__always_inline`` es técnicamente un atributo
+ pero se trata como ``inline``)
+- atributos de clase de almacenamiento (aquí, ``__init`` -- es decir,
+ declaraciones de sección, pero también cosas como ``__cold``)
+- tipo de retorno (aquí, ``void *``)
+- atributos de tipo de retorno (aquí, ``__must_check``)
+- nombre de la función (aquí, ``action``)
+- parámetros de la función (aquí, ``(enum magic value, size_t size, u8 count, char *fmt, ...)``,
+ teniendo en cuenta que los nombres de los parámetros siempre deben
+ incluirse)
+- atributos de parámetros de función (aquí, ``__printf(4, 5)``)
+- atributos de comportamiento de la función (aquí, ``__malloc``)
+
+Tenga en cuenta que para una **definición** de función (es decir, el cuerpo
+real de la función), el compilador no permite atributos de parámetros de
+función después de parámetros de la función. En estos casos, deberán ir
+tras los atributos de clase (por ejemplo, tenga en cuenta el cambio de
+posición de ``__printf(4, 5)`` a continuación, en comparación con el
+ejemplo de **declaración** anterior)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+ size_t size, u8 count, char *fmt, ...) __malloc
+ {
+ ...
+ }
+
+7) Salida centralizada de funciones
+-----------------------------------
+
+Aunque desaprobado por algunas personas, el equivalente de la instrucción
+goto es utilizado con frecuencia por los compiladores, en forma de
+instrucción de salto incondicional.
+
+La declaración goto es útil cuando una función sale desde múltiples
+ubicaciones y se deben realizar algunos trabajos comunes, como la limpieza.
+Si no se necesita limpieza, entonces simplemente haga return directamente.
+
+Elija nombres de etiquetas que digan qué hace el goto o por qué existe el
+goto. Un ejemplo de un buen nombre podría ser ``out_free_buffer:``
+(``salida_liberar_buffer``) si al irse libera ``buffer``. Evite usar
+nombres GW-BASIC como ``err1:`` y ``err2:``, ya que tendría que volver a
+numerarlos si alguna vez agrega o elimina rutas de salida, y hacen que sea
+difícil de verificar que sean correctos, de todos modos.
+
+La razón para usar gotos es:
+
+- Las declaraciones incondicionales son más fáciles de entender y seguir.
+- se reduce el anidamiento
+- errores al no actualizar los puntos de salida individuales al hacer
+ modificaciones son evitados
+- ahorra el trabajo del compilador de optimizar código redundante ;)
+
+.. code-block:: c
+
+ int fun(int a)
+ {
+ int result = 0;
+ char *buffer;
+
+ buffer = kmalloc(SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (condition1) {
+ while (loop1) {
+ ...
+ }
+ result = 1;
+ goto out_free_buffer;
+ }
+ ...
+ out_free_buffer:
+ kfree(buffer);
+ return result;
+ }
+
+Un tipo común de error a tener en cuenta es "un error de error" que es algo
+así:
+
+.. code-block:: c
+
+ err:
+ kfree(foo->bar);
+ kfree(foo);
+ return ret;
+
+El error en este código es que en algunas rutas de salida, ``foo`` es NULL.
+Normalmente la solución para esto es dividirlo en dos etiquetas de error
+``err_free_bar:`` y ``err_free_foo:``:
+
+.. code-block:: c
+
+ err_free_bar:
+ kfree(foo->bar);
+ err_free_foo:
+ kfree(foo);
+ return ret;
+
+Idealmente, debería simular errores para probar todas las rutas de salida.
+
+
+8) Comentarios
+--------------
+
+Los comentarios son buenos, pero también existe el peligro de comentar
+demasiado. NUNCA trate de explicar CÓMO funciona su código en un
+comentario: es mucho mejor escribir el código para que el
+**funcionamiento** sea obvio y es una pérdida de tiempo explicar código mal
+escrito.
+
+Generalmente, desea que sus comentarios digan QUÉ hace su código, no CÓMO.
+Además, trate de evitar poner comentarios dentro del cuerpo de una función:
+si la función es tan compleja que necesita comentar por separado partes de
+esta, probablemente debería volver al capítulo 6 una temporada. Puede
+hacer pequeños comentarios para notar o advertir sobre algo particularmente
+inteligente (o feo), pero trate de evitar el exceso. En su lugar, ponga los
+comentarios al principio de la función, diga a la gente lo que hace y
+posiblemente POR QUÉ hace esto.
+
+Al comentar las funciones de la API del kernel, utilice el formato
+kernel-doc. Consulte los archivos en :ref:`Documentation/doc-guide/ <doc_guide>`
+y ``scripts/kernel-doc`` para más detalles.
+
+El estilo preferido para comentarios largos (de varias líneas) es:
+
+.. code-block:: c
+
+ /*
+ * Este es el estilo preferido para comentarios
+ * multilínea en el código fuente del kernel Linux.
+ * Por favor, utilícelo constantemente.
+ *
+ * Descripción: Una columna de asteriscos en el lado izquierdo,
+ * con líneas iniciales y finales casi en blanco.
+ */
+
+Para archivos en net/ y drivers/net/, el estilo preferido para comentarios
+largos (multi-linea) es un poco diferente.
+
+.. code-block:: c
+
+ /* El estilo de comentario preferido para archivos en net/ y drivers/net
+ * se asemeja a esto.
+ *
+ * Es casi lo mismo que el estilo de comentario generalmente preferido,
+ * pero no hay una línea inicial casi en blanco.
+ */
+
+También es importante comentar los datos, ya sean tipos básicos o
+derivados. Para este fin, use solo una declaración de datos por línea (sin
+comas para múltiples declaraciones de datos). Esto le deja espacio para un
+pequeño comentario sobre cada elemento, explicando su uso.
+
+9) Has hecho un desastre
+---------------------------
+
+Está bien, todos lo hacemos. Probablemente un antiguo usuario de Unix le
+haya dicho que ``GNU emacs`` formatea automáticamente las fuentes C por
+usted, y ha notado que sí, lo hace, pero los por defecto que tiene son
+menos que deseables (de hecho, son peores que los aleatorios) escribiendo -
+un número infinito de monos escribiendo en GNU emacs nunca harán un buen
+programa).
+
+Por lo tanto, puede deshacerse de GNU emacs o cambiarlo y usar valores más
+sanos. Para hacer esto último, puede pegar lo siguiente en su archivo
+.emacs:
+
+.. code-block:: none
+
+ (defun c-lineup-arglist-tabs-only (ignored)
+ "Line up argument lists by tabs, not spaces"
+ (let* ((anchor (c-langelem-pos c-syntactic-element))
+ (column (c-langelem-2nd-pos c-syntactic-element))
+ (offset (- (1+ column) anchor))
+ (steps (floor offset c-basic-offset)))
+ (* (max steps 1)
+ c-basic-offset)))
+
+ (dir-locals-set-class-variables
+ 'linux-kernel
+ '((c-mode . (
+ (c-basic-offset . 8)
+ (c-label-minimum-indentation . 0)
+ (c-offsets-alist . (
+ (arglist-close . c-lineup-arglist-tabs-only)
+ (arglist-cont-nonempty .
+ (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
+ (arglist-intro . +)
+ (brace-list-intro . +)
+ (c . c-lineup-C-comments)
+ (case-label . 0)
+ (comment-intro . c-lineup-comment)
+ (cpp-define-intro . +)
+ (cpp-macro . -1000)
+ (cpp-macro-cont . +)
+ (defun-block-intro . +)
+ (else-clause . 0)
+ (func-decl-cont . +)
+ (inclass . +)
+ (inher-cont . c-lineup-multi-inher)
+ (knr-argdecl-intro . 0)
+ (label . -1000)
+ (statement . 0)
+ (statement-block-intro . +)
+ (statement-case-intro . +)
+ (statement-cont . +)
+ (substatement . +)
+ ))
+ (indent-tabs-mode . t)
+ (show-trailing-whitespace . t)
+ ))))
+
+ (dir-locals-set-directory-class
+ (expand-file-name "~/src/linux-trees")
+ 'linux-kernel)
+
+Esto hará que emacs funcione mejor con el estilo de código del kernel para
+C en archivos bajo ``~/src/linux-trees``.
+
+Pero incluso si no logra que emacs realice un formateo correcto, no todo
+está perdido: use ``indent``.
+
+Ahora bien, de nuevo, la sangría de GNU tiene la misma configuración de
+muerte cerebral que GNU emacs tiene, por lo que necesita darle algunas
+opciones de línea de comando. Sin embargo, eso no es tan malo, porque
+incluso los creadores de GNU indent reconocen la autoridad de K&R (la gente
+de GNU no es mala, solo están gravemente equivocados en este asunto), por
+lo que simplemente de a la sangría las opciones ``-kr -i8`` (significa
+``K&R, guiones de 8 caracteres``), o use ``scripts/Lindent``, que indenta
+con ese estilo.
+
+``indent`` tiene muchas opciones, y especialmente cuando se trata de
+comentar reformateos, es posible que desee echar un vistazo a la página del
+manual. Pero recuerde: ``indent`` no es la solución para una mala
+programación.
+
+Tenga en cuenta que también puede usar la herramienta ``clang-format`` para
+ayudarlo con estas reglas, para volver a formatear rápidamente partes de su
+código automáticamente, y revisar archivos completos para detectar errores
+de estilo del código, errores tipográficos y posibles mejoras. También es
+útil para ordenar ``#includes``, para alinear variables/macros, para
+redistribuir texto y otras tareas similares. Vea el archivo
+:ref:`Documentation/process/clang-format.rst <clangformat>` para más
+detalles.
+
+10) Archivos de configuración de Kconfig
+----------------------------------------
+
+Para todos los archivos de configuración de Kconfig* en todo el árbol
+fuente, la sangría es algo diferente. Las líneas bajo una definición
+``config`` están indentadas con una tabulación, mientras que el texto de
+ayuda tiene una sangría adicional de dos espacios. Ejemplo::
+
+ config AUDIT
+ bool "Soporte para auditar"
+ depends on NET
+ help
+ Habilita la infraestructura de auditoría que se puede usar con otro
+ subsistema kernel, como SELinux (que requiere esto para
+ registro de salida de mensajes avc). No hace auditoría de llamadas al
+ sistema sin CONFIG_AUDITSYSCALL.
+
+Características seriamente peligrosas (como soporte de escritura para
+ciertos filesystems) deben anunciar esto de forma destacada en su cadena de
+solicitud::
+
+ config ADFS_FS_RW
+ bool "ADFS write support (DANGEROUS)"
+ depends on ADFS_FS
+ ...
+
+Para obtener la documentación completa sobre los archivos de configuración,
+consulte el archivo Documentation/kbuild/kconfig-language.rst.
+
+
+11) Estructuras de datos
+------------------------
+
+Las estructuras de datos que tienen visibilidad fuera del contexto de un
+solo subproceso en el que son creadas y destruidas, siempre debe tener
+contadores de referencia. En el kernel, la recolección de basura no existe
+(y fuera, la recolección de basura del kernel es lenta e ineficiente), lo
+que significa que absolutamente **tiene** para hacer referencia y contar
+todos sus usos.
+
+El conteo de referencias significa que puede evitar el bloqueo y permite
+que múltiples usuarios tengan acceso a la estructura de datos en paralelo -
+y no tengan que preocuparse de que la estructura, de repente, desaparezca
+debajo de su control, solo porque durmieron o hicieron otra cosa por un
+tiempo.
+
+Tenga en cuenta que el bloqueo **no** reemplaza el recuento de referencia.
+El bloqueo se utiliza para mantener la coherencia de las estructuras de
+datos, mientras que la referencia y contar es una técnica de gestión de
+memoria. Por lo general, ambos son necesarios, y no deben confundirse entre
+sí.
+
+De hecho, muchas estructuras de datos pueden tener dos niveles de conteo de
+referencias, cuando hay usuarios de diferentes ``clases``. El conteo de
+subclases cuenta el número de usuarios de la subclase y disminuye el conteo
+global solo una vez, cuando el recuento de subclases llega a cero.
+
+Se pueden encontrar ejemplos de este tipo de ``recuento de referencias de
+niveles múltiples`` en la gestión de memoria (``struct mm_struct``:
+mm_users y mm_count), y en código del sistema de archivos
+(``struct super_block``: s_count y s_active).
+
+Recuerde: si otro hilo puede encontrar su estructura de datos y usted no
+tiene un recuento de referencias, es casi seguro que tiene un error.
+
+12) Macros, Enums y RTL
+------------------------
+
+Los nombres de macros que definen constantes y etiquetas en enumeraciones
+(enums) están en mayúsculas.
+
+.. code-block:: c
+
+ #define CONSTANTE 0x12345
+
+Se prefieren los enums cuando se definen varias constantes relacionadas.
+
+Se aprecian los nombres de macro en MAYÚSCULAS, pero las macros que se
+asemejan a funciones puede ser nombradas en minúscula.
+
+Generalmente, las funciones en línea son preferibles a las macros que se
+asemejan a funciones.
+
+Las macros con varias instrucciones deben contenerse en un bloque do-while:
+
+.. code-block:: c
+
+ #define macrofun(a, b, c) \
+ do { \
+ if (a == 5) \
+ haz_esto(b, c); \
+ } while (0)
+
+Cosas a evitar al usar macros:
+
+1) macros que afectan el flujo de control:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ do { \
+ if (blah(x) < 0) \
+ return -EBUGGERED; \
+ } while (0)
+
+es una **muy** mala idea. Parece una llamada de función pero sale de la
+función de ``llamada``; no rompa los analizadores internos de aquellos que
+leerán el código.
+
+2) macros que dependen de tener una variable local con un nombre mágico:
+
+.. code-block:: c
+
+ #define FOO(val) bar(index, val)
+
+puede parecer algo bueno, pero es confuso como el infierno cuando uno lee
+el código, y es propenso a romperse por cambios aparentemente inocentes.
+
+3) macros con argumentos que se usan como valores l: FOO(x) = y; le van
+a morder si alguien, por ejemplo, convierte FOO en una función en línea.
+
+4) olvidarse de la precedencia: las macros que definen constantes usando
+expresiones deben encerrar la expresión entre paréntesis. Tenga cuidado con
+problemas similares con macros usando parámetros.
+
+.. code-block:: c
+
+ #define CONSTANTE 0x4000
+ #define CONSTEXP (CONSTANTE | 3)
+
+5) colisiones de espacio de nombres ("namespace") al definir variables
+locales en macros que se asemejan a funciones:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ ({ \
+ typeof(x) ret; \
+ ret = calc_ret(x); \
+ (ret); \
+ })
+
+ret es un nombre común para una variable local -es menos probable que
+__foo_ret colisione (coincida) con una variable existente.
+
+El manual de cpp trata las macros de forma exhaustiva. El manual interno de
+gcc también cubre RTL, que se usa frecuentemente con lenguaje ensamblador
+en el kernel.
+
+13) Imprimir mensajes del kernel
+--------------------------------
+
+A los desarrolladores del kernel les gusta ser vistos como alfabetizados.
+Cuide la ortografía de los mensajes del kernel para causar una buena
+impresión. No utilice contracciones incorrectas como ``dont``; use
+``do not`` o ``don't`` en su lugar. Haga sus mensajes concisos, claros e
+inequívocos.
+
+Los mensajes del kernel no tienen que terminar con un punto.
+
+Imprimir números entre paréntesis (%d) no agrega valor y debe evitarse.
+
+Hay varias modelos de macros de diagnóstico de driver en <linux/dev_printk.h>
+que debe usar para asegurarse de que los mensajes coincidan con el
+dispositivo correcto y driver, y están etiquetados con el nivel correcto:
+dev_err(), dev_warn(), dev_info(), y así sucesivamente. Para mensajes que
+no están asociados con un dispositivo particular, <linux/printk.h> define
+pr_notice(), pr_info(), pr_warn(), pr_err(), etc.
+
+Crear buenos mensajes de depuración puede ser todo un desafío; y una vez
+los tiene, pueden ser de gran ayuda para la resolución remota de problemas.
+Sin embargo, la impresión de mensajes de depuración se maneja de manera
+diferente a la impresión de otros mensajes que no son de depuración.
+Mientras que las otras funciones pr_XXX() se imprimen incondicionalmente,
+pr_debug() no lo hace; se compila fuera por defecto, a menos que DEBUG sea
+definido o se establezca CONFIG_DYNAMIC_DEBUG. Eso es cierto para dev_dbg()
+también, y una convención relacionada usa VERBOSE_DEBUG para agregar
+mensajes dev_vdbg() a los ya habilitados por DEBUG.
+
+Muchos subsistemas tienen opciones de depuración de Kconfig para activar
+-DDEBUG en el Makefile correspondiente; en otros casos, los archivos
+usan #define DEBUG. Y cuando un mensaje de depuración debe imprimirse
+incondicionalmente, por ejemplo si es ya dentro de una sección #ifdef
+relacionada con la depuración, printk(KERN_DEBUG ...) puede ser usado.
+
+14) Reservando memoria
+----------------------
+
+El kernel proporciona los siguientes asignadores de memoria de propósito
+general: kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() y
+vzalloc(). Consulte la documentación de la API para obtener más información.
+a cerca de ellos. :ref:`Documentation/core-api/memory-allocation.rst
+<memory_allocation>`
+
+La forma preferida para pasar el tamaño de una estructura es la siguiente:
+
+.. code-block:: c
+
+ p = kmalloc(sizeof(*p), ...);
+
+La forma alternativa donde se deletrea el nombre de la estructura perjudica
+la legibilidad, y presenta una oportunidad para un error cuando se cambia
+el tipo de variable de puntero, pero el tamaño correspondiente de eso que
+se pasa a un asignador de memoria no.
+
+Convertir el valor devuelto, que es un puntero vacío, es redundante. La
+conversión desde el puntero vacío a cualquier otro tipo de puntero está
+garantizado por la programación en idioma C.
+
+La forma preferida para asignar una matriz es la siguiente:
+
+.. code-block:: c
+
+ p = kmalloc_array(n, sizeof(...), ...);
+
+La forma preferida para asignar una matriz a cero es la siguiente:
+
+.. code-block:: c
+
+ p = kcalloc(n, sizeof(...), ...);
+
+Ambos casos verifican el desbordamiento en el tamaño de asignación n *
+sizeof (...), y devuelven NULL si esto ocurrió.
+
+Todas estas funciones de asignación genéricas emiten un volcado de pila
+(" stack dump") en caso de fallo cuando se usan sin __GFP_NOWARN, por lo
+que no sirve de nada emitir un mensaje de fallo adicional cuando se
+devuelva NULL.
+
+15) La enfermedad de inline
+----------------------------
+
+Parece haber una común percepción errónea de que gcc tiene una magica
+opción "hazme más rápido" de aceleración, llamada ``inline`` (en línea).
+Mientras que el uso de inlines puede ser apropiado (por ejemplo, como un
+medio para reemplazar macros, consulte el Capítulo 12), muy a menudo no lo
+es. El uso abundante de la palabra clave inline conduce a una mayor kernel,
+que a su vez ralentiza el sistema en su conjunto, debido a una mayor huella
+de icache para la CPU, y sencillamente porque hay menos memoria disponible
+para el pagecache. Solo piense en esto; un fallo en la memoria caché de la
+página provoca una búsqueda de disco, que tarda fácilmente 5 milisegundos.
+Hay MUCHOS ciclos de CPU que puede entrar en estos 5 milisegundos.
+
+Una razonable regla general es no poner funciones inline que tengan más de
+3 líneas de código en ellas. Una excepción a esta regla son los casos en
+que se sabe que un parámetro es una constante en tiempo de compilación, y
+como resultado de esto, usted *sabe*, el compilador podrá optimizar la
+mayor parte de su función en tiempo de compilación. Para un buen ejemplo de
+este último caso, véase la función en línea kmalloc().
+
+A menudo, la gente argumenta que agregar funciones en línea que son
+estáticas y se usan solo una vez, es siempre una victoria ya que no hay
+perdida de espacio. Mientras esto es técnicamente correcto, gcc es capaz de
+incorporarlos automáticamente sin ayuda, y esta el problema de
+mantenimiento de eliminar el inline, cuando un segundo usuario supera el
+valor potencial de la pista que le dice a gcc que haga algo que habría
+hecho de todos modos.
+
+16) Valores devueltos por función y sus nombres
+-----------------------------------------------
+
+Las funciones pueden devolver valores de muchos tipos diferentes, y uno de
+lo más común es un valor que indica si la función tuvo éxito o ha fallado.
+Dicho valor se puede representar como un número entero de código de error
+(-Exxx = falla, 0 = éxito) o un booleano ``con éxito`` (0 = falla, distinto
+de cero = éxito).
+
+La mezcla de estos dos tipos de representaciones es una fuente fértil de
+errores difíciles de encontrar. Si el lenguaje C incluyera una fuerte
+distinción entre enteros y booleanos, el compilador encontraría estos
+errores por nosotros... pero no lo hace. Para ayudar a prevenir tales
+errores, siga siempre esta convención::
+
+ Si el nombre de una función es una acción o un comando imperativo,
+ la función debe devolver un número entero de código de error. si el nombre
+ es un predicado, la función debe devolver un valor booleano "exitoso".
+
+Por ejemplo, ``agregar trabajo`` es un comando, y la función
+agregar_trabajo() devuelve 0 en caso de éxito o -EBUSY en caso de fracaso.
+De la misma manera, ``dispositivo PCI presente`` es un predicado, y la
+función pci_dev_present() devuelve 1 si tiene éxito en encontrar un
+dispositivo coincidente o 0 si no es así.
+
+Todas las funciones EXPORTed (exportadas) deben respetar esta convención,
+al igual que todas las funciones publicas. Las funciones privadas
+(estáticas) no lo necesitan, pero es recomendado que lo hagan.
+
+Las funciones cuyo valor devuelto es el resultado real de un cálculo, en
+lugar de una indicación de si el cómputo tuvo éxito, no están sujetas a
+esta regla. Generalmente indican fallo al devolver valores fuera del rango
+de resultados. Los ejemplos típicos serían funciones que devuelven
+punteros; estos usan NULL o el mecanismo ERR_PTR para informar de fallos.
+
+17) Usando bool
+----------------
+
+El tipo bool del kernel Linux es un alias para el tipo C99 _Bool. Los
+valores booleanos pueden solo evaluar a 0 o 1, y la conversión implícita o
+explícita a bool convierte automáticamente el valor en verdadero o falso.
+Cuando se utilizan tipos booleanos,
+!! no se necesita construcción, lo que elimina una clase de errores.
+
+Cuando se trabaja con valores booleanos, se deben usar las definiciones
+verdadera y falsa, en lugar de 1 y 0.
+
+Los tipos de devolución de función bool y las variables de pila siempre
+se pueden usar cuando esto sea adecuado. Se recomienda el uso de bool para
+mejorar la legibilidad y, a menudo, es una mejor opción que 'int' para
+almacenar valores booleanos.
+
+No use bool si el diseño de la línea de caché o el tamaño del valor son
+importantes, ya que su tamaño y la alineación varía según la arquitectura
+compilada. Las estructuras que son optimizadas para la alineación y el
+tamaño no debe usar bool.
+
+Si una estructura tiene muchos valores verdadero/falso, considere
+consolidarlos en un bitfield con miembros de 1 bit, o usando un tipo de
+ancho fijo apropiado, como u8.
+
+De manera similar, para los argumentos de función, se pueden consolidar
+muchos valores verdaderos/falsos en un solo argumento bit a bit 'flags' y
+'flags' a menudo, puede ser una alternativa de argumento más legible si los
+sitios de llamada tienen constantes desnudas de tipo verdaderas/falsas.
+
+De lo contrario, el uso limitado de bool en estructuras y argumentos puede
+mejorar la legibilidad.
+
+18) No reinvente las macros del kernel
+---------------------------------------
+
+El archivo de cabecera include/linux/kernel.h contiene una serie de macros
+que debe usar, en lugar de programar explícitamente alguna variante de
+estos por usted mismo. Por ejemplo, si necesita calcular la longitud de una
+matriz, aproveche la macro
+
+.. code-block:: c
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+De manera similar, si necesita calcular el tamaño de algún miembro de la
+estructura, use
+
+.. code-block:: c
+
+ #define sizeof_field(t, f) (sizeof(((t*)0)->f))
+
+También hay macros min() y max() que realizan una verificación estricta de
+tipos si lo necesita. Siéntase libre de leer detenidamente ese archivo de
+encabezado para ver qué más ya está definido y que no debe reproducir en su
+código.
+
+19) Editores modeline y otros desastres
+---------------------------------------
+
+Algunos editores pueden interpretar la información de configuración
+incrustada en los archivos fuente, indicado con marcadores especiales. Por
+ejemplo, emacs interpreta las líneas marcadas como esto:
+
+.. code-block:: c
+
+ -*- mode: c -*-
+
+O así:
+
+.. code-block:: c
+
+ /*
+ Local Variables:
+ compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+ End:
+ */
+
+Vim interpreta los marcadores que se ven así:
+
+.. code-block:: c
+
+ /* vim:set sw=8 noet */
+
+No incluya ninguno de estos en los archivos fuente. La gente tiene sus
+propias configuraciones del editor, y sus archivos de origen no deben
+anularlos. Esto incluye marcadores para sangría y configuración de modo.
+La gente puede usar su propio modo personalizado, o puede tener algún otro
+método mágico para que la sangría funcione correctamente.
+
+
+20) Ensamblador inline
+-----------------------
+
+En el código específico de arquitectura, es posible que deba usar
+ensamblador en línea para interactuar con funcionalidades de CPU o
+plataforma. No dude en hacerlo cuando sea necesario. Sin embargo, no use
+ensamblador en línea de forma gratuita cuando C puede hacer el trabajo.
+Puede y debe empujar el hardware desde C cuando sea posible.
+
+Considere escribir funciones auxiliares simples que envuelvan bits comunes
+de ensamblador, en lugar de escribirlos repetidamente con ligeras
+variaciones. Recuerde que el ensamblador en línea puede usar parámetros C.
+
+Las funciones de ensamblador grandes y no triviales deben ir en archivos .S,
+con su correspondientes prototipos de C definidos en archivos de encabezado
+en C. Los prototipos de C para el ensamblador deben usar ``asmlinkage``.
+
+Es posible que deba marcar su declaración asm como volátil, para evitar que
+GCC la elimine si GCC no nota ningún efecto secundario. No siempre es
+necesario hacerlo, sin embargo, y hacerlo innecesariamente puede limitar la
+optimización.
+
+Al escribir una sola declaración de ensamblador en línea que contiene
+múltiples instrucciones, ponga cada instrucción en una línea separada en
+una string separada, y termine cada string excepto la última con ``\n\t``
+para indentar correctamente la siguiente instrucción en la salida en
+ensamblador:
+
+.. code-block:: c
+
+ asm ("magic %reg1, #42\n\t"
+ "more_magic %reg2, %reg3"
+ : /* outputs */ : /* inputs */ : /* clobbers */);
+
+21) Compilación condicional
+---------------------------
+
+Siempre que sea posible, no use condicionales de preprocesador (#if,
+#ifdef) en archivos .c; de lo contrario, el código es más difícil de leer y
+la lógica más difícil de seguir. En cambio, use dichos condicionales en un
+archivo de encabezado que defina funciones para usar en esos archivos .c,
+proporcionando versiones de código auxiliar sin operación en el caso #else,
+y luego llame a estas funciones incondicionalmente desde archivos .c. El
+compilador evitará generar cualquier código para las llamadas restantes,
+produciendo resultados idénticos, pero la lógica es fácil de seguir.
+
+Prefiera compilar funciones completas, en lugar de porciones de funciones o
+porciones de expresiones. En lugar de poner un ifdef en una expresión,
+divida la totalidad de la expresión con una función de ayuda independiente
+y aplique el condicional a esa función.
+
+Si tiene una función o variable que puede potencialmente quedar sin usar en
+una configuración en particular, y el compilador advertiría sobre su
+definición sin usar, marque la definición como __maybe_unused en lugar de
+envolverla en un preprocesador condicional. (Sin embargo, si una función o
+variable *siempre* acaba sin ser usada, bórrela.)
+
+Dentro del código, cuando sea posible, use la macro IS_ENABLED para
+convertir un símbolo Kconfig en una expresión booleana de C, y utilícelo en
+un condicional de C normal:
+
+.. code-block:: c
+
+ if (IS_ENABLED(CONFIG_SOMETHING)) {
+ ...
+ }
+
+El compilador "doblará"" constantemente el condicional e incluirá o
+excluirá el bloque de código al igual que con un #ifdef, por lo que esto no
+agregará ningún tiempo de gastos generales en ejecución. Sin embargo, este
+enfoque todavía permite que el compilador de C vea el código dentro del
+bloque, y verifique que sea correcto (sintaxis, tipos, símbolo, referencias,
+etc.). Por lo tanto, aún debe usar un #ifdef si el código dentro del bloque
+hace referencia a símbolos que no existirán si no se cumple la condición.
+
+Al final de cualquier bloque #if o #ifdef no trivial (más de unas pocas
+líneas), incluya un comentario después de #endif en la misma línea,
+anotando la expresión condicional utilizada. Por ejemplo:
+
+.. code-block:: c
+
+ #ifdef CONFIG_SOMETHING
+ ...
+ #endif /* CONFIG_SOMETHING */
+
+22) No rompa el kernel
+-----------------------
+
+En general, la decisión de romper el kernel pertenece al usuario, más que
+al desarrollador del kernel.
+
+Evite el panic()
+****************
+
+panic() debe usarse con cuidado y principalmente solo durante el arranque
+del sistema. panic() es, por ejemplo, aceptable cuando se queda sin memoria
+durante el arranque y no puede continuar.
+
+Use WARN() en lugar de BUG()
+****************************
+
+No agregue código nuevo que use cualquiera de las variantes BUG(), como
+BUG(), BUG_ON() o VM_BUG_ON(). En su lugar, use una variante WARN*(),
+preferiblemente WARN_ON_ONCE(), y posiblemente con código de recuperación.
+El código de recuperación no es requerido si no hay una forma razonable de
+recuperar, al menos parcialmente.
+
+"Soy demasiado perezoso para tener en cuenta los errores" no es una excusa
+para usar BUG(). Importantes corrupciones internas sin forma de continuar
+aún pueden usar BUG(), pero necesitan una buena justificación.
+
+Use WARN_ON_ONCE() en lugar de WARN() o WARN_ON()
+*************************************************
+
+Generalmente, se prefiere WARN_ON_ONCE() a WARN() o WARN_ON(), porque es
+común que una condición de advertencia dada, si ocurre, ocurra varias
+veces. Esto puede llenar el registro del kernel, e incluso puede ralentizar
+el sistema lo suficiente como para que el registro excesivo se convierta en
+su propio, adicional problema.
+
+No haga WARN a la ligera
+************************
+
+WARN*() está diseñado para situaciones inesperadas que nunca deberían
+suceder. Las macros WARN*() no deben usarse para nada que se espera que
+suceda durante un funcionamiento normal. No hay "checkeos" previos o
+posteriores a la condición, por ejemplo. De nuevo: WARN*() no debe usarse
+para una condición esperada que vaya a activarse fácilmente, por ejemplo,
+mediante acciones en el espacio del usuario. pr_warn_once() es una
+alternativa posible, si necesita notificar al usuario de un problema.
+
+No se preocupe sobre panic_on_warn de usuarios
+**********************************************
+
+Algunas palabras más sobre panic_on_warn: Recuerde que ``panic_on_warn`` es
+una opción disponible del kernel, y que muchos usuarios configuran esta
+opción. Esta es la razón por la que hay un artículo de "No haga WARN a la
+ligera", arriba. Sin embargo, la existencia de panic_on_warn de usuarios no
+es una razón válida para evitar el uso juicioso de WARN*(). Esto se debe a
+que quien habilita panic_on_warn, explícitamente pidió al kernel que
+fallara si se dispara un WARN*(), y tales usuarios deben estar preparados
+para afrontar las consecuencias de un sistema que es algo más probable que
+se rompa.
+
+Use BUILD_BUG_ON() para aserciones en tiempo de compilación
+***********************************************************
+
+El uso de BUILD_BUG_ON() es aceptable y recomendado, porque es una aserción
+en tiempo de compilación, que no tiene efecto en tiempo de ejecución.
+
+Apéndice I) Referencias
+-----------------------
+
+The C Programming Language, Segunda edicion
+por Brian W. Kernighan and Dennis M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback).
+
+The Practice of Programming
+por Brian W. Kernighan and Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
+
+manuales GCC - en cumplimiento con K&R y este texto - para cpp, gcc,
+detalles de gcc y sangría, todo disponible en https://www.gnu.org/manual/
+
+WG14 es el grupo de trabajo de estandarización internacional de la
+programación en lenguaje C, URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+:ref:`process/coding-style.rst <codingstyle>` del kernel, por greg@kroah.com at OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst
new file mode 100644
index 000000000000..49a05f6a5544
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/index.rst
@@ -0,0 +1,15 @@
+.. raw:: latex
+
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+
+.. include:: ../disclaimer-sp.rst
+
+.. _sp_process_index:
+
+.. toctree::
+ :maxdepth: 1
+
+ submitting-patches
+ kernel-docs
+ coding-style
diff --git a/Documentation/translations/sp_SP/process/kernel-docs.rst b/Documentation/translations/sp_SP/process/kernel-docs.rst
new file mode 100644
index 000000000000..2f9b3df8f8fa
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/kernel-docs.rst
@@ -0,0 +1,187 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_kernel_docs:
+
+Índice de documentación adicional del kernel
+============================================
+
+La necesidad de un documento como este se hizo evidente en la lista de
+correo de linux-kernel cuando las mismas preguntas, solicitando sugerencias
+e información, aparecieron una y otra vez.
+
+Afortunadamente, a medida que más y más gente accede a GNU/Linux, más
+desarrolladores se interesan por el kernel. Sin embargo, leer las fuentes
+no siempre es suficiente. Es fácil entender el código, pero se pierden los
+conceptos, la filosofía y decisiones de diseño detrás de dicho código.
+
+Desafortunadamente, no existen muchos documentos disponibles para que los
+principiantes comiencen. Y, aunque existieran, no habría ningún lugar
+"conocido" que les pudiera seguir la pista. Estas líneas tratan de cubrir
+esta carencia.
+
+POR FAVOR, si conoce algún documento que no figura aquí, o si escribe un
+nuevo documento, incluya una referencia aquí, siguiendo el proceso de envío
+de parches del kernel. Cualquier corrección, idea o comentario también es
+bienvenida.
+
+Todos los documentos se catalogan con los siguientes campos: el "Título",
+el "Autor"/es, la "URL" donde se encuentran, algunas "Palabras clave"
+útiles para buscar temas específicos, y una breve "Descripción" del
+documento en cuestión.
+
+.. note::
+
+ Los documentos de cada sección en este documento están ordenados por su
+ fecha de publicación, del más reciente al más antiguo. Los maintainers
+ deben ir retirando recursos obsoletos o anticuados.
+
+Documentos en el árbol del kernel Linux
+-----------------------------------------
+
+Los libros de Sphinx deben compilarse con ``make {htmldocs | pdfdocs | epubdocs}``.
+
+ * Título: **linux/Documentation**
+
+ :Autor: Many.
+ :Ubicación: Documentation/
+ :Palabras Clave: archivos de texto, Sphinx.
+ :Descripción: Documentación que viene con las fuentes del kernel,
+ dentro del directorio Documentation. Algunas páginas de este documento
+ (incluido este documento en sí) se han trasladado allí, y podrían
+ estar más actualizadas que la versión web.
+
+Documentos en línea
+-------------------
+
+ * Título: **Linux Kernel Mailing List Glossary**
+
+ :Autor: various
+ :URL: https://kernelnewbies.org/KernelGlossary
+ :Fecha: rolling version
+ :Palabras Clave: glosario terminos, linux-kernel.
+ :Descripción: De la Introducción: "This glossary is intended as
+ a brief description of some of the acronyms and terms you may hear
+ during discussion of the Linux kernel".
+
+ * Título: **The Linux Kernel Module Programming Guide**
+
+ :Autor: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
+ Jim Huang.
+ :URL: https://sysprog21.github.io/lkmpg/
+ :Fecha: 2021
+ :Palabras Clave: modules, GPL book, /proc, ioctls, system calls,
+ interrupt handlers, llamadas al sistema, interrupciones.
+ :Descripción: Un muy buen libro GPL sobre el tema de la programación
+ de módulos. Muchos ejemplos. Actualmente la nueva versión está
+ siendo mantenida activamente ent https://github.com/sysprog21/lkmpg.
+
+Libros publicados
+-----------------
+
+ * Título: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization**
+
+ :Autor: Kaiwan N. Billimoria
+ :Publica: Packt Publishing Ltd
+ :Fecha: 2021
+ :Paginas: 754
+ :ISBN: 978-1789953435
+
+ * Título: **Linux Kernel Development, 3rd Edition**
+
+ :Autor: Robert Love
+ :Publica: Addison-Wesley
+ :Fecha: July, 2010
+ :Paginas: 440
+ :ISBN: 978-0672329463
+ :Notas: Libro fundacional
+
+.. _sp_ldd3_published:
+
+ * Título: **Linux Device Drivers, 3rd Edition**
+
+ :Authors: Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
+ :Publica: O'Reilly & Associates
+ :Fecha: 2005
+ :Paginas: 636
+ :ISBN: 0-596-00590-3
+ :Notas: Libro fundacional. Más información en
+ http://www.oreilly.com/catalog/linuxdrive3/
+ formato PDF, URL: https://lwn.net/Kernel/LDD3/
+
+ * Título: **The Design of the UNIX Operating System**
+
+ :Autor: Maurice J. Bach
+ :Publica: Prentice Hall
+ :Fecha: 1986
+ :Paginas: 471
+ :ISBN: 0-13-201757-1
+ :Notas: Libro fundacional
+
+Recursos varios
+---------------
+
+ * Título: **Cross-Referencing Linux**
+
+ :URL: https://elixir.bootlin.com/
+ :Palabras Clave: Browsing source code.
+ :Descripción: Otro navegador de código fuente del kernel Linux que se
+ encuentra en la web. Muchas referencias cruzadas a variables y
+ funciones. Puedes ver dónde se definen y dónde se utilizan.
+
+ * Título: **Linux Weekly News**
+
+ :URL: https://lwn.net
+ :Palabras Clave: latest kernel news, noticias del kernel Linux.
+ :Descripción: El título lo dice todo (Noticias Semanales de Linux).
+ Hay una sección fija sobre el kernel, resumiendo el trabajo de sus
+ desarrolladores, correcciones de errores, nuevas funciones y
+ versiones, producido durante la semana.
+
+ * Título: **The home page of Linux-MM**
+
+ :Autor: The Linux-MM team.
+ :URL: https://linux-mm.org/
+ :Palabras Clave: memory management, Linux-MM, mm patches, TODO, docs,
+ mailing list, administración de memoria, Linux-MM, parches mm, listas
+ de correo.
+ :Descripción: Sitio dedicado al desarrollo de la gestión de memoria
+ de Linux. Parches relacionados con la memoria, HOWTOs, enlaces,
+ desarrolladores de mm... ¡Si está interesado en el desarrollo de la
+ gestión de memoria no te lo pierdas!
+
+ * Título: **Kernel Newbies IRC Channel and Website**
+
+ :URL: https://www.kernelnewbies.org
+ :Palabras Clave: IRC, newbies, channel, asking doubts, canal, dudas,
+ novatos, preguntar.
+ :Descripción: #kernelnewbies en irc.oftc.net.
+ #kernelnewbies es una red de IRC dedicada al hacker del kernel
+ 'novato'. La audiencia se compone principalmente de personas que
+ quieren aprender sobre el kernel, trabajar en proyectos del kernel
+ o hackers profesionales del kernel que quieren ayudar a la gente
+ menos experimentada.
+ #kernelnewbies es parte de la red OFTC IRC.
+ Pruebe con irc.oftc.net como su servidor y luego haga /join
+ #kernelnewbies.
+ El sitio web kernelnewbies también alberga artículos, documentos, FAQs...
+
+ * Título: **linux-kernel mailing list archives and search engines**
+
+ :URL: http://vger.kernel.org/vger-lists.html
+ :URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html
+ :URL: http://groups.google.com/group/mlist.linux.kernel
+ :Palabras Clave: linux-kernel, archives, buscar, search, archivos.
+ :Descripción: Algunos de los archivadores de listas de correo del
+ kernel de Linux. Si usted tiene uno mejor/otro, por favor hágamelo
+ saber.
+
+-------
+
+Este documento se basaba originalmente en:
+
+ https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+
+escrito por Juan-Mariano de Goyenche
diff --git a/Documentation/translations/sp_SP/process/submitting-patches.rst b/Documentation/translations/sp_SP/process/submitting-patches.rst
new file mode 100644
index 000000000000..bf95ceb5e865
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/submitting-patches.rst
@@ -0,0 +1,894 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_submittingpatches:
+
+Envío de parches: la guía esencial para incluir su código en el kernel
+=======================================================================
+
+Para una persona o empresa que desee enviar un cambio al kernel Linux,
+el proceso puede en ocasiones resultar desalentador si no se está
+familiarizado con "el sistema". Este texto es una colección de sugerencias
+que pueden aumentar considerablemente las posibilidades de que se acepte su
+cambio.
+
+Este documento contiene una gran cantidad de sugerencias en un formato
+relativamente conciso. Para obtener información detallada sobre cómo
+funciona el proceso de desarrollo del kernel, consulte
+Documentation/process/development-process.rst. Además, lea
+Documentation/process/submit-checklist.rst para obtener una lista de
+elementos a verificar antes de enviar código. Para los parches de
+"binding" del árbol de dispositivos, lea
+Documentation/devicetree/bindings/submitting-patches.rst.
+
+Esta documentación asume que está usando ``git`` para preparar sus parches.
+Si no está familiarizado con ``git``, le recomendamos que aprenda a
+usarlo, le hará la vida como desarrollador del kernel y en general mucho
+más sencilla.
+
+Algunos subsistemas y árboles de mantenimiento cuentan con información
+adicional sobre su flujo de trabajo y expectativas, consulte
+:ref:`Documentation/process/maintainer-handbooks.rst <maintainer_handbooks_main>`.
+
+Obtenga el código fuente actual
+--------------------------------
+
+Si no tiene a mano un repositorio con el código fuente actual del kernel,
+use ``git`` para obtener uno. Querrá comenzar con el repositorio principal,
+que se puede descargar con::
+
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+
+Tenga en cuenta, sin embargo, que es posible que no desee desarrollar con
+el árbol principal directamente. La mayoría de los maintainers de
+subsistemas usan sus propios árboles de código fuente y quieren ver parches
+preparados para esos árboles. Revise el campo **T:** para el subsistema
+en el archivo MAINTAINERS para encontrar dicho árbol, o simplemente
+pregunte al maintainer si el árbol no está listado allí.
+
+.. _sp_describe_changes:
+
+Describa sus cambios
+---------------------
+
+Describa su problema. Sea su parche una corrección de un error de una
+línea o 5000 líneas para una nuevo "feature", debe haber un problema
+subyacente que le motivó a hacer ese trabajo. Convenza al revisor de que
+hay un problema que merece la pena solucionar y de que tiene sentido que
+lea más allá del primer párrafo.
+
+Describa el impacto relativo al usuario. Cosas que estropeen el kernel y
+los bloqueos son bastante convincentes, pero no todos los errores son tan
+evidentes. Incluso si se detectó un problema durante la revisión del
+código, describa el impacto que cree pueda tener en los usuarios. Tenga en
+cuenta que la mayoría de instalaciones de Linux ejecutan kernels desde
+árboles estables secundarios o árboles específicos de proveedor/producto
+que seleccionan ("cherry-pick") solo parches específicos de upstream, así
+que incluya cualquier cosa que pueda ayudar a dirigir su cambio
+aguas abajo: circunstancias que producen cierta situación, extractos de
+dmesg, descripciones del error fatal, regresiones de rendimiento, picos de
+latencia, bloqueos, etc.
+
+Cuantifique optimizaciones y beneficios/perdidas. Si asegura mejoras en
+rendimiento, consumo de memoria, huella del stack o tamaño de binario,
+incluya números que lo respalden. Pero también describa costes no obvios.
+Las optimizaciones generalmente no son gratuitas, sino un equilibrio entre
+CPU, memoria y legibilidad; o, cuando se trata de heurísticas, entre
+diferentes cargas de trabajo. Describa las desventajas esperadas de su
+optimización para que el revisor pueda comparar las perdidas con los
+beneficios.
+
+Una vez establecido el problema, describa lo que realmente está haciendo
+al respecto en detalles técnicos. Es importante describir el cambio en
+lenguaje sencillo para que el revisor verifique que el código se está
+comportando como se pretende.
+
+El maintainer le agradecerá que escriba la descripción de su parche en un
+formato que se pueda incorporar fácilmente en la gestión del código fuente
+del sistema, ``git``, como un "commit log" (registros de los commits).
+Consulte :ref:`sp_the_canonical_patch_format`.
+
+Resuelva solo un problema por parche. Si su descripción comienza a ser muy
+larga, eso es una señal de que probablemente necesite dividir su parche.
+Lea :ref:`split_changes`.
+
+Cuando envíe o vuelva a enviar un parche o una serie de parches, incluya la
+descripción completa del parche y justificación del mismo. No se limite a
+decir que esa es la versión N del parche (serie). No espere que el
+maintainer del subsistema referencie versiones de parches anteriores o use
+referencias URL para encontrar la descripción del parche y colocarla en el
+parche. Es decir, el parche (serie) y su descripción deben ser
+independientes. Esto beneficia tanto a los maintainers como a los
+revisores. Algunos revisores probablemente ni siquiera recibieran versiones
+anteriores del parche.
+
+Describa sus cambios en la forma imperativa, por ejemplo, "hacer que xyzzy
+haga frotz" en lugar de "[Este parche] hace que xyzzy haga frotz" o "[Yo]
+Cambié xyzzy para que haga frotz", como si estuviera dando órdenes al
+código fuente para cambiar su comportamiento.
+
+Si desea hacer referencia a un commit específico, no se limite a hacer
+referencia al ID SHA-1 del commit. Incluya también el resumen de una línea
+del commit, para que sea más fácil para los revisores saber de qué se
+trata.
+Ejemplo::
+
+ Commit e21d2170f36602ae2708 ("video: quitar platform_set_drvdata()
+ innecesario") eliminó innecesario platform_set_drvdata(), pero dejó la
+ variable "dev" sin usar, bórrese.
+
+También debe asegurarse de utilizar al menos los primeros doce caracteres
+del identificador SHA-1. El repositorio del kernel contiene muchos *muchos*
+objetos, por lo que las colisiones con identificaciones más cortas son una
+posibilidad real. Tenga en cuenta que, aunque no hay colisión con su
+identificación de seis caracteres ahora, esa condición puede cambiar dentro
+de cinco años.
+
+Si las discusiones relacionadas o cualquier otra información relativa al
+cambio se pueden encontrar en la web, agregue las etiquetas 'Link:' que
+apunten a estos. En caso de que su parche corrija un error, por poner un
+ejemplo, agregue una etiqueta con una URL que haga referencia al informe en
+los archivos de las listas de correo o un rastreador de errores; si el
+parche es el resultado de alguna discusión anterior de la lista de correo o
+algo documentado en la web, referencie esto.
+
+Cuando se vincule a archivos de listas de correo, preferiblemente use el
+servicio de archivador de mensajes lore.kernel.org. Para crear la URL del
+enlace, utilice el contenido del encabezado ("header") ``Message-Id`` del
+mensaje sin los corchetes angulares que lo rodean.
+Por ejemplo::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+Verifique el enlace para asegurarse de que realmente funciona y apunta al
+mensaje correspondiente.
+
+Sin embargo, intente que su explicación sea comprensible sin recursos
+externos. Además de dar una URL a un archivo o error de la lista de correo,
+resuma los puntos relevantes de la discusión que condujeron al parche tal y
+como se envió.
+
+Si su parche corrige un error en un commit específico, por ejemplo
+encontró un problema usando ``git bisect``, utilice la etiqueta 'Fixes:'
+con los primeros 12 caracteres del ID SHA-1 y el resumen de una línea. No
+divida la etiqueta en varias líneas, las etiquetas están exentas de la
+regla "ajustar a 75 columnas" para simplificar análisis de scripts. Por
+ejemplo::
+
+ Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page()
+ devuelva la cantidad de páginas que realmente liberó")
+
+Las siguientes configuraciones de ``git config`` se pueden usar para
+agregar un bonito formato y generar este estilo con los comandos
+``git log`` o ``git show``::
+
+ [core]
+ abbrev = 12
+ [pretty]
+ fixes = Fixes: %h (\"%s\")
+
+Un ejemplo de uso::
+
+ $ git log -1 --pretty=fixes 54a4f0239f2e
+ Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page() devuelva la cantidad de páginas que realmente liberó")
+
+.. _sp_split_changes:
+
+Separe sus cambios
+-------------------
+
+Separe cada **cambio lógico** en un parche separado.
+
+Por ejemplo, si sus cambios incluyen correcciones de errores y mejoras en
+el rendimiento de un controlador, separe esos cambios en dos o más parches.
+Si sus cambios incluyen una actualización de la API y una nueva controlador
+que usa esta nueva API, sepárelos en dos parches.
+
+Por otro lado, si realiza un solo cambio en numerosos archivos, agrupe esos
+cambios en un solo parche. Por lo tanto, un solo cambio lógico estará
+contenido en un solo parche.
+
+El punto a recordar es que cada parche debe realizar un cambio que puede
+ser verificado por los revisores fácilmente. Cada parche debe ser
+justificable por sus propios méritos.
+
+Si un parche depende de otro parche para que un cambio sea completo, eso
+está bien. Simplemente incluya que **"este parche depende del parche X"**
+en la descripción de su parche.
+
+Cuando divida su cambio en una serie de parches, tenga especial cuidado en
+asegurarse de que el kernel se compila y ejecuta correctamente después de
+cada parche en la serie. Los desarrolladores que usan ``git bisect``
+para rastrear un problema pueden terminar dividiendo su serie de parches en
+cualquier punto; no le agradecerán si introdujo errores a la mitad.
+
+Si no puede condensar su conjunto de parches en un conjunto más pequeño de
+parches, solo publique, más o menos 15 a la vez, y espere la revisión e
+integración.
+
+
+Revise el estilo en sus cambios
+--------------------------------
+
+Revise su parche para ver si hay violaciones de estilo básico, cuyos
+detalles pueden ser encontrados en Documentation/process/coding-style.rst.
+No hacerlo simplemente desperdicia el tiempo de los revisores y su parche
+será rechazado, probablemente sin siquiera ser leído.
+
+Una excepción importante es cuando se mueve código de un archivo a otro.
+En tal caso, en absoluto debe modificar el código movido en el mismo parche
+en que lo mueve. Esto divide claramente el acto de mover el código y sus
+cambios. Esto ayuda mucho a la revisión de la diferencias reales y permite
+que las herramientas rastreen mejor el historial del código en sí.
+
+Verifique sus parches con el verificador de estilo de parches antes de
+enviarlos (scripts/checkpatch.pl). Tenga en cuenta, sin embargo, que el
+verificador de estilo debe ser visto como una guía, no como un reemplazo
+del juicio humano. Si su código es mejor con una violación entonces
+probablemente sea mejor dejarlo estar.
+
+El verificador informa a tres niveles:
+ - ERROR: cosas que es muy probable que estén mal
+ - WARNING: Advertencia. Cosas que requieren una revisión cuidadosa
+ - CHECK: Revisar. Cosas que requieren pensarlo
+
+Debe poder justificar todas las violaciones que permanezcan en su parche.
+
+
+Seleccione los destinatarios de su parche
+------------------------------------------
+
+Siempre debe incluir en copia a los apropiados maintainers del subsistema
+en cualquier parche con código que mantengan; revise a través del archivo
+MAINTAINERS y el historial de revisión del código fuente para ver quiénes
+son esos maintainers. El script scripts/get_maintainer.pl puede ser muy
+útil en este paso (pase rutas a sus parches como argumentos para
+scripts/get_maintainer.pl). Si no puede encontrar un maintainer del
+subsistema en el que está trabajando, Andrew Morton
+(akpm@linux-foundation.org) sirve como maintainer de último recurso.
+
+Normalmente, también debe elegir al menos una lista de correo para recibir
+una copia de su conjunto de parches. linux-kernel@vger.kernel.org debe
+usarse de forma predeterminada para todos los parches, pero el volumen en
+esta lista ha hecho que muchos desarrolladores se desconecten. Busque en el
+archivo MAINTAINERS una lista específica de los subsistemas; su parche
+probablemente recibirá más atención allí. Sin embargo, no envíe spam a
+listas no relacionadas.
+
+Muchas listas relacionadas con el kernel están alojadas en vger.kernel.org;
+puedes encontrar un listado de estas en
+http://vger.kernel.org/vger-lists.html. Existen listas relacionadas con el
+kernel alojadas en otros lugares, no obstante.
+
+¡No envíe más de 15 parches a la vez a las listas de correo de vger!
+
+Linus Torvalds es el árbitro final de todos los cambios aceptados en el
+kernel de Linux. Su dirección de correo electrónico es
+<torvalds@linux-foundation.org>. Recibe muchos correos electrónicos y, en
+este momento, muy pocos parches pasan por Linus directamente, por lo que
+normalmente debe hacer todo lo posible para -evitar- enviarle un correo
+electrónico.
+
+Si tiene un parche que corrige un error de seguridad explotable, envíe ese
+parche a security@kernel.org. Para errores graves, se debe mantener un
+poco de discreción y permitir que los distribuidores entreguen el parche a
+los usuarios; en esos casos, obviamente, el parche no debe enviarse a
+ninguna lista pública. Revise también
+Documentation/admin-guide/security-bugs.rst.
+
+Los parches que corrigen un error grave en un kernel en uso deben dirigirse
+hacia los maintainers estables poniendo una línea como esta::
+
+ CC: stable@vger.kernel.org
+
+en el área de sign-off de su parche (es decir, NO un destinatario de correo
+electrónico). También debe leer
+Documentation/process/stable-kernel-rules.rst además de este documento.
+
+Si los cambios afectan las interfaces del kernel para el usuario, envíe al
+maintainer de las MAN-PAGES (como se indica en el archivo MAINTAINERS) un
+parche de páginas de manual, o al menos una notificación del cambio, para
+que alguna información se abra paso en las páginas del manual. Los cambios
+de la API del espacio de usuario también deben copiarse en
+linux-api@vger.kernel.org.
+
+
+Sin MIME, enlaces, compresión o archivos adjuntos. Solo texto plano
+--------------------------------------------------------------------
+
+Linus y otros desarrolladores del kernel deben poder leer y comentar sobre
+los cambios que está enviando. Es importante para un desarrollador kernel
+poder "citar" sus cambios, utilizando herramientas estándar de correo
+electrónico, de modo que puedan comentar sobre partes específicas de su
+código.
+
+Por este motivo, todos los parches deben enviarse por correo electrónico
+"inline". La forma más sencilla de hacerlo es con ``git send-email``, que
+es muy recomendable. Un tutorial interactivo para ``git send-email`` está
+disponible en https://git-send-email.io.
+
+Si elige no usar ``git send-email``:
+
+.. warning::
+
+ Tenga cuidado con el ajuste de palabras de su editor que corrompe su
+ parche, si elige cortar y pegar su parche.
+
+No adjunte el parche como un archivo adjunto MIME, comprimido o no. Muchas
+populares aplicaciones de correo electrónico no siempre transmiten un MIME
+archivo adjunto como texto sin formato, por lo que es imposible comentar
+en su código. Linus también necesita un poco más de tiempo para procesar un
+archivo adjunto MIME, disminuyendo la probabilidad de que se acepte su
+cambio adjunto en MIME.
+
+Excepción: si su proveedor de correo está destrozando parches, entonces
+alguien puede pedir que los vuelva a enviar usando MIME.
+
+Consulte Documentation/process/email-clients.rst para obtener sugerencias
+sobre cómo configurar su cliente de correo electrónico para que envíe sus
+parches intactos.
+
+Responda a los comentarios de revisión
+---------------------------------------
+
+Es casi seguro que su parche recibirá comentarios de los revisores sobre
+maneras en que se pueda mejorar el parche, en forma de respuesta a su
+correo electrónico. Debe responder a esos comentarios; ignorar a los
+revisores es una buena manera de ser ignorado de vuelta. Simplemente puede
+responder a sus correos electrónicos para contestar a sus comentarios.
+Revisiones a los comentarios o preguntas que no conduzcan a un cambio de
+código deben casi con certeza generar un comentario o una entrada en el
+"changelog" para que el próximo revisor entienda lo que está pasando.
+
+Asegúrese de decirles a los revisores qué cambios está haciendo y de
+agradecerles que dediquen su tiempo. La revisión del código es un proceso
+agotador y lento, y los revisores a veces se ponen de mal humor. Sin
+embargo, incluso en ese caso, responda cortésmente y aborde los problemas
+que hayan señalado. Al enviar un siguiente versión, agregue un
+``patch changelog`` (registro de cambios en los parches) a la carta de
+presentación ("cover letter") o a parches individuales explicando la
+diferencia con la presentación anterior (ver
+:ref:`sp_the_canonical_patch_format`).
+
+Consulte Documentation/process/email-clients.rst para obtener
+recomendaciones sobre clientes de correo electrónico y normas de etiqueta
+en la lista de correo.
+
+.. _sp_resend_reminders:
+
+No se desanime o impaciente
+---------------------------
+
+Después de haber entregado su cambio, sea paciente y espere. Los revisores
+son personas ocupadas y es posible que no lleguen a su parche de inmediato.
+
+Érase una vez, los parches solían desaparecer en el vacío sin comentarios,
+pero el proceso de desarrollo funciona mejor que eso ahora. Debería
+recibir comentarios dentro de una semana más o menos; si eso no sucede,
+asegúrese de que ha enviado sus parches al lugar correcto. Espere un mínimo
+de una semana antes de volver a enviar o hacer ping a los revisores,
+posiblemente más durante periodos de mucho trabajo ocupados como "merge
+windows".
+
+También está bien volver a enviar el parche o la serie de parches después
+de un par de semanas con la palabra "RESEND" (reenviar) añadida a la línea
+de asunto::
+
+ [PATCH Vx RESEND] sub/sys: Resumen condensado de parche
+
+No incluya "RESEND" cuando envíe una versión modificada de su parche o
+serie de parches: "RESEND" solo se aplica al reenvío de un parche o serie
+de parches que no hayan sido modificados de ninguna manera con respecto a
+la presentación anterior.
+
+
+Incluya PATCH en el asunto
+--------------------------
+
+Debido al alto tráfico de correo electrónico a Linus y al kernel de Linux,
+es común prefijar su línea de asunto con [PATCH]. Esto le permite a Linus
+y otros desarrolladores del kernel distinguir más fácilmente los parches de
+otras discusiones por correo electrónico.
+
+``git send-email`` lo hará automáticamente.
+
+
+Firme su trabajo: el Certificado de Origen del Desarrollador
+------------------------------------------------------------
+
+Para mejorar el seguimiento de quién hizo qué, especialmente con parches
+que pueden filtrarse hasta su destino final a través de varias capas de
+maintainers, hemos introducido un procedimiento de "sign-off" (aprobación)
+en parches que se envían por correo electrónico.
+
+La aprobación es una simple línea al final de la explicación del parche,
+que certifica que usted lo escribió o que tiene derecho a enviarlo como un
+parche de código abierto. Las reglas son bastante simples: si usted puede
+certificar lo siguiente:
+
+Certificado de Origen del Desarrollador 1.1
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Al hacer una contribución a este proyecto, certifico que:
+
+ (a) La contribución fue creada en su totalidad o en parte por mí y
+ tengo derecho a enviarlo bajo la licencia de código abierto
+ indicada en el documento; o
+
+ (b) La contribución se basa en trabajo previo que, hasta donde yo
+ soy consciente, está cubierto por una licencia de código
+ abierto apropiada y tengo el derecho bajo esa licencia de
+ presentar tal trabajo con modificaciones, ya sean creadas en su
+ totalidad o en parte por mí, bajo la misma licencia de código
+ (salvo que sea permitido presentar bajo una licencia diferente),
+ tal y como se indica en el documento; o
+
+ (c) La contribución me fue proporcionada directamente por alguna
+ otra persona que certificó (a), (b) o (c) y no he modificado
+ esto.
+
+ (d) Entiendo y acepto que este proyecto y la contribución
+ son públicos y que un registro de la contribución (incluyendo
+ toda la información personal que envío con él, incluida mi
+ firma) es mantenida indefinidamente y puede ser redistribuida
+ de manera consistente con este proyecto o la(s) licencia(s) de
+ código abierto involucradas.
+
+entonces simplemente incluya una línea que rece::
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+usando su nombre real (lamentablemente, no pseudónimos ni contribuciones
+anónimas). Esto se hará por usted automáticamente si usa ``git commit -s``.
+Las reversiones de código también deben incluir "Signed-off-by".
+``git revert -s`` hace eso por usted.
+
+Algunas personas también ponen etiquetas adicionales al final. Simplemente
+serán ignoradas por ahora, pero puede hacer esto para marcar procedimientos
+internos de su empresa o simplemente señalar algún detalle especial sobre
+la firma.
+
+Cualquier otro SoB (Signed-off-by:) después del SoB del autor es de
+personas que manipulen y transporten el parche, pero no participaron en su
+desarrollo. Las cadenas de SoB deben reflejar la ruta **real** del parche
+de cómo se propagó a los maintainers y, en última instancia, a Linus, con
+la primera entrada de SoB que señala la autoría principal de un solo autor.
+
+
+Cuándo usar Acked-by:, Cc: y Co-developed-by por:
+-------------------------------------------------
+
+La etiqueta Signed-off-by: indica que el firmante estuvo involucrado en el
+desarrollo del parche, o que él/ella se encontraba en el camino de entrega
+del parche.
+
+Si una persona no estuvo directamente involucrada en la preparación o
+administración de un parche pero desea expresar y registrar su aprobación,
+entonces puede pedir que se agregue una línea Acked-by: al registro de
+cambios del parche.
+
+Acked-by: a menudo lo usa el maintainer del código afectado cuando ese
+maintainer no contribuyó ni envió el parche.
+
+Acked-by: no es tan formal como Signed-off-by:. Es una manera de marcar que
+el "acker" ha revisado al menos ese parche y ha indicado su aceptación. Por
+los merge de parches a veces convertirán manualmente el "sí, me parece bien"
+de un acker en un Acked-by: (pero tenga en cuenta que por lo general es
+mejor pedir un acuse de recibo explícito).
+
+Acked-by: no necesariamente indica el reconocimiento de todo el parche.
+Por ejemplo, si un parche afecta a varios subsistemas y tiene un
+Acked-by: de un maintainer del subsistema, entonces esto generalmente
+indica el reconocimiento de solo la parte que afecta el código de ese
+maintainer. Buen juicio debe ejercitarse aquí. En caso de duda, la gente
+debe consultar la discusión original en los archivos de la lista de correo.
+
+Si una persona ha tenido la oportunidad de comentar un parche, pero no lo
+ha hecho, puede incluir opcionalmente una etiqueta ``Cc:`` al parche.
+Esta es la única etiqueta que se puede agregar sin una acción explícita por
+parte de la persona a la que se nombre - pero debe indicar que esta persona
+fue copiada en el parche. Esta etiqueta documenta que las partes
+potencialmente interesadas han sido incluidas en la discusión.
+
+Co-developed-by: establece que el parche fue co-creado por múltiples
+desarrolladores; se utiliza para dar atribución a los coautores (además del
+autor atribuido por la etiqueta From:) cuando varias personas trabajan en
+un solo parche. Ya que Co-developed-by: denota autoría, cada
+Co-developed-by: debe ser inmediatamente seguido de Signed-off-by: del
+coautor asociado. Se mantiene el procedimiento estándar, es decir, el orden
+de las etiquetas Signed-off-by: debe reflejar el historial cronológico del
+parche en la medida de lo posible, independientemente de si el autor se
+atribuye a través de From: o Co-developed-by:. Cabe destacar que el último
+Signed-off-by: siempre debe ser del desarrollador que envía el parche.
+
+Tenga en cuenta que la etiqueta From: es opcional cuando el autor From: es
+también la persona (y correo electrónico) enumerados en la línea From: del
+encabezado del correo electrónico.
+
+Ejemplo de un parche enviado por el From: autor::
+
+ <changelog>
+
+ Co-developed-by: Primer coautor <primer@coauthor.example.org>
+ Signed-off-by: Primer coautor <primer@coauthor.example.org>
+ Co-developed-by: Segundo coautor <segundo@coautor.ejemplo.org>
+ Signed-off-by: Segundo coautor <segundo@coautor.ejemplo.org>
+ Signed-off-by: Autor del From <from@author.example.org>
+
+Ejemplo de un parche enviado por un Co-developed-by: autor::
+
+ From: Autor del From <from@author.example.org>
+
+ <changelog>
+
+ Co-developed-by: Co-Autor aleatorio <aleatorio@coauthor.example.org>
+ Signed-off-by: Coautor aleatorio <aleatorio@coauthor.example.org>
+ Signed-off-by: Autor del From <from@author.example.org>
+ Co-developed-by: Coautor que envió <sub@coauthor.example.org>
+ Signed-off-by: Coautor que envía <sub@coauthor.example.org>
+
+Uso de Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: y Fixes:
+----------------------------------------------------------------------
+
+La etiqueta Reported-by (Reportado-por) otorga crédito a las personas que
+encuentran errores y los reportan. Por favor, tenga en cuenta que si se
+informó de un error en privado, debe pedir primero permiso antes de usar la
+etiqueta Reported-by. La etiqueta está destinada a errores; por favor no la
+use para acreditar peticiones de características.
+
+Una etiqueta Tested-by: indica que el parche se probó con éxito (en algún
+entorno) por la persona nombrada. Esta etiqueta informa a los maintainers
+de que se han realizado algunas pruebas, proporciona un medio para ubicar
+"testers" (gente que pruebe) otros parches futuros y asegura el crédito
+para los testers.
+
+Reviewed-by: en cambio, indica que el parche ha sido revisado y encontrado
+aceptable de acuerdo con la Declaración del Revisor:
+
+Declaración de Supervisión del Revisor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Al ofrecer mi etiqueta Reviewed-by:, afirmo que:
+
+(a) He llevado a cabo una revisión técnica de este parche para
+evaluar su idoneidad y preparación para su inclusión en
+el kernel principal.
+
+(b) Cualquier problema, inquietud o pregunta relacionada con el parche
+han sido comunicados al remitente. Estoy satisfecho
+con la respuesta del remitente a mis comentarios.
+
+(c) Si bien puede haber cosas que podrían mejorarse con esta
+entrega, creo que es, en este momento, (1) una
+modificación valiosa al kernel, y (2) libre de conocidas
+cuestiones que argumentarían en contra de su inclusión.
+
+(d) Si bien he revisado el parche y creo que es correcto,
+no hago (a menos que se indique explícitamente en otro lugar) ninguna
+garantía o avales de que logrará su definido
+propósito o función en cualquier situación dada.
+
+Una etiqueta Reviewed-by es una declaración de opinión de que el parche es
+una modificación apropiada al kernel sin que haya ningún problema grave
+a nivel técnico. Cualquier revisor interesado (que haya hecho el trabajo)
+puede ofrecer una etiqueta Reviewed-by para un parche. Esta etiqueta sirve
+para dar crédito a revisores e informar a los maintainers del grado de
+revisión que se ha hecho en el parche. Las etiquetas Reviewed-by, cuando
+las otorgan revisores conocidos por entender del tema y realizar
+revisiones exhaustivas, normalmente aumentan la probabilidad de que su
+parche entre en el kernel.
+
+Las etiquetas Tested-by y Reviewed-by, una vez recibidas en la lista de
+correo por el tester o revisor, deben ser incluidas por el autor de los
+parches pertinentes al enviar próximas versiones. Sin embargo, si el parche
+ha cambiado sustancialmente en la siguiente versión, es posible que estas
+etiquetas ya no sean aplicables y, por lo tanto, deben eliminarse. Por lo
+general, se debe mencionar la eliminación de las etiquetas Tested-by o
+Reviewed-by de alguien en el registro de cambios del parche (después del
+separador '---').
+
+Una etiqueta Suggested-by: indica que la idea del parche es sugerida por la
+persona nombrada y asegura el crédito a la persona por la idea. Tenga en
+cuenta que esto no debe agregarse sin el permiso del "reporter",
+especialmente si la idea no fue publicada en un foro público. Dicho esto,
+si diligentemente acreditamos a los reporters de ideas, con suerte, se
+sentirán inspirados para ayudarnos nuevamente en el futuro.
+
+Una etiqueta Fixes: indica que el parche corrige un problema en un commit
+anterior. Esto se utiliza para facilitar descubrir dónde se originó un
+error, lo que puede ayudar a revisar una corrección de errores. Esta
+etiqueta también ayuda al equipo del kernel estable a determinar qué
+versiones estables del kernel deberían recibir su corrección. Este es el
+método preferido para indicar un error corregido por el parche. Revise
+:ref:`describe_changes` para más detalles.
+
+Nota: Adjuntar una etiqueta Fixes: no subvierte las reglas estables del
+proceso del kernel ni el requisito de CC: stable@vger.kernel.org en todos
+los parches candidatos de ramas estables. Para obtener más información, lea
+Documentation/process/stable-kernel-rules.rst.
+
+.. _sp_the_canonical_patch_format:
+
+Formato de parche canónico
+---------------------------
+
+Esta sección describe cómo debe darse formato al propio parche. Tenga en
+cuenta que, si tiene sus parches almacenados en un repositorio ``git``, el
+parche con formato adecuado se puede obtener con ``git format-patch``. Las
+herramientas no pueden crear el texto necesario, sin embargo, así que lea
+las instrucciones a continuación de todos modos.
+
+La línea de asunto del parche canónico es::
+
+ Asunto: [PATCH 001/123] subsistema: frase de resumen
+
+El cuerpo del mensaje del parche canónico contiene lo siguiente:
+
+ - Una línea ``from`` que especifica el autor del parche, seguida de una
+ línea vacía (solo es necesario si la persona que envía el parche no es
+ el autor).
+
+ - El cuerpo de la explicación, línea envuelta en 75 columnas, que se
+ copiara en el registro de cambios permanente para describir este parche.
+
+ - Una línea vacía.
+
+ - Las líneas ``Signed-off-by:``, descritas anteriormente, que
+ también vaya en el registro de cambios.
+
+ - Una línea de marcador que contiene simplemente ``---``.
+
+ - Cualquier comentario adicional que no sea adecuado para el registro de
+ cambios.
+
+ - El parche real (output de ``diff``).
+
+El formato de la línea de asunto hace que sea muy fácil ordenar los correos
+electrónicos alfabéticamente por línea de asunto - prácticamente cualquier
+lector de correo electrónico permite esto, ya que debido a que el número de
+secuencia se rellena con ceros, el orden numérico y alfabético es el mismo.
+
+El ``subsistema`` en el asunto del correo electrónico debe identificar qué
+área o subsistema del kernel está siendo parcheado.
+
+La ``frase de resumen`` en el Asunto del correo electrónico debe describir
+de forma concisa el parche que contiene ese correo electrónico. La
+``frase resumen`` no debe ser un nombre de archivo. No use la mismo ``frase
+resumen`` para cada parche en una serie completa de parches (donde una
+`` serie de parches`` (patch series) es una secuencia ordenada de múltiples
+parches relacionados).
+
+Tenga en cuenta que la ``frase de resumen`` de su correo electrónico se
+convierte en un identificador global único para ese parche. Se propaga por
+hasta el registro de cambios de ``git``. La ``frase resumida`` se puede
+usar más adelante en discusiones de desarrolladores que se refieran al
+parche. La gente querrá buscar en Google la ``frase de resumen`` para leer
+la discusión al respecto del parche. También será lo único que la gente
+podrá ver rápidamente cuando, dos o tres meses después, estén pasando por
+quizás miles de parches usando herramientas como ``gitk`` o ``git log
+--oneline``.
+
+Por estas razones, el ``resumen`` no debe tener más de 70-75 caracteres, y
+debe describir tanto lo que cambia el parche como por qué el parche podría
+ser necesario. Es un reto ser tanto sucinto como descriptivo, pero eso es
+lo que un resumen bien escrito debería hacer.
+
+La ``frase de resumen`` puede estar precedida por etiquetas encerradas en
+corchetes: "Asunto: [PATCH <etiqueta>...] <frase de resumen>". Las
+etiquetas no se consideran parte de la frase de resumen, pero describen
+cómo debería ser tratado el parche. Las etiquetas comunes pueden incluir un
+descriptor de versión si las múltiples versiones del parche se han enviado
+en respuesta a comentarios (es decir, "v1, v2, v3") o "RFC" para indicar
+una solicitud de comentarios.
+
+Si hay cuatro parches en una serie de parches, los parches individuales
+pueden enumerarse así: 1/4, 2/4, 3/4, 4/4. Esto asegura que los
+desarrolladores entiendan el orden en que se deben aplicar los parches y
+que han revisado o aplicado todos los parches de la serie de parches.
+
+Aquí hay algunos buenos ejemplos de Asuntos::
+
+ Asunto: [PATCH 2/5] ext2: mejorar la escalabilidad de la búsqueda de mapas de bits
+ Asunto: [PATCH v2 27/01] x86: corregir el seguimiento de eflags
+ Asunto: [PATCH v2] sub/sys: resumen conciso del parche
+ Asunto: [PATCH v2 M/N] sub/sys: resumen conciso del parche
+
+La línea ``from`` debe ser la primera línea en el cuerpo del mensaje,
+y tiene la forma::
+
+ From: Autor del parche <autor@ejemplo.com>
+
+La línea ``From`` especifica quién será acreditado como el autor del parche
+en el registro de cambios permanente. Si falta la línea ``from``, entonces
+la línea ``From:`` del encabezado del correo electrónico se usará para
+determinar el autor del parche en el registro de cambios.
+
+La explicación estará incluida en el commit del changelog permanente, por
+lo que debería tener sentido para un lector competente que hace mucho tiempo
+ha olvidado los detalles de la discusión que podrían haber llevado a
+este parche. Incluidos los síntomas del fallo que el parche trate
+(mensajes de registro del kernel, mensajes de oops, etc.) son especialmente
+útiles para personas que podrían estar buscando en los registros de
+commits en busca de la aplicación del parche. El texto debe estar escrito
+con tal detalle que cuando se lea semanas, meses o incluso años después,
+pueda dar al lector la información necesaria y detalles para comprender el
+razonamiento de **por qué** se creó el parche.
+
+Si un parche corrige una falla de compilación, puede que no sea necesario
+incluir _todos_ los errores de compilación; pero lo suficiente como para
+que sea probable que alguien que busque el parche puede encontrarlo. Como
+en la ``frase de resumen``, es importante ser tanto sucinto como
+descriptivo.
+
+La línea marcadora ``---`` cumple el propósito esencial de marcar para
+herramientas de manejo de parches donde termina el mensaje de registro de
+cambios.
+
+Un buen uso de los comentarios adicionales después del marcador ``---`` es
+para ``diffstat``, para mostrar qué archivos han cambiado, y el número de
+líneas insertadas y eliminadas por archivo. Un ``diffstat`` es
+especialmente útil en parches más grandes. Si va a incluir un ``diffstat``
+después del marcador ``---``, utilice las opciones ``diffstat``
+``-p 1 -w 70`` para que los nombres de archivo se enumeran desde la parte
+superior del árbol de fuentes del kernel y no use demasiado espacio
+horizontal (que encaje fácilmente en 80 columnas, tal vez con alguna
+indentación). (``git`` genera diffstats apropiados por defecto).
+
+Otros comentarios relevantes solo en el momento o para el maintainer, pero
+no adecuados para el registro de cambios permanente, también debe ir aquí.
+Un buen ejemplo de tales comentarios podría ser ``registros de cambios de
+parches`` que describen qué ha cambiado entre la versión v1 y v2 del
+parche.
+
+Por favor, ponga esta información **después** de la línea ``---`` que
+separa el registro de cambios del resto del parche. La información de la
+versión no forma parte del registro de cambios que se incluye con el árbol
+git. Es información adicional para los revisores. Si se coloca encima de la
+etiquetas de commit, necesita interacción manual para eliminarlo. Si esta
+debajo de la línea de separación, se quita automáticamente al aplicar el
+parche::
+
+ <mensaje de commit>
+ ...
+ Signed-off-by: Autor <autor@correo>
+ ---
+ V2 -> V3: función auxiliar redundante eliminada
+ V1 -> V2: estilo de código limpio y comentarios de revisión abordados
+
+ ruta/al/archivo | 5+++--
+ ...
+
+Revise más detalles sobre el formato de parche adecuado en las siguientes
+referencias
+
+.. _sp_backtraces:
+
+Retrocesos en mensajes de confirmación
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Los "backtraces" (deshacer el camino) ayuda a documentar la cadena de
+llamadas que conducen a un problema. Sin embargo, no todos los rastreos son
+útiles. Por ejemplo, las tempranas cadenas de llamadas de inicio son únicas
+y obvias. Sin embargo, al copiar la salida completa de dmesg textualmente,
+incluye información que distrae, como marcas de tiempo, listas de módulos,
+registro y volcados de pila.
+
+Por lo tanto, los backtraces más útiles deben contener los datos
+relevantes de la información vertida, lo que hace que sea más fácil
+centrarse en el verdadero tema. Este es un ejemplo de un backtrace bien
+recortado::
+
+ error de acceso de MSR no verificado: WRMSR a 0xd51 (intentó escribir 0x0000000000000064)
+ en rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
+ Rastreo de llamadas:
+ mba_wrmsr
+ update_domains
+ rdtgroup_mkdir
+
+.. _sp_explicit_in_reply_to:
+
+In-Reply-To explicitos en las cabeceras
+---------------------------------------
+
+Puede ser útil agregar manualmente encabezados In-Reply-To: a un parche
+(por ejemplo, al usar ``git send-email``) para asociar el parche con una
+discusión anterior relevante, por ejemplo para vincular una corrección de
+errores al correo electrónico con el informe de errores. Sin embargo, para
+una serie de parches múltiples, generalmente es mejor evitar usar
+In-Reply-To: para vincular a versiones anteriores de la serie. De esta
+forma, varias versiones del parche no se convierten en un inmanejable
+bosque de referencias en clientes de correo electrónico. Si un enlace es
+útil, puede usar el redirector https://lore.kernel.org/ (por ejemplo, en
+el texto de la carta de introducción del correo electrónico) para vincular
+a una versión anterior de la serie de parches.
+
+
+Proporcionar información de árbol base
+--------------------------------------
+
+Cuando otros desarrolladores reciben sus parches y comienzan el proceso de
+revisión, a menudo es útil para ellos saber en qué parte del historial del
+árbol deben colocar su trabajo. Esto es particularmente útil para CI
+automatizado de procesos que intentan ejecutar una serie de pruebas para
+establecer la calidad de su envío antes de que el maintainer comience la
+revisión.
+
+Si está utilizando ``git format-patch`` para generar sus parches, puede
+incluir automáticamente la información del árbol base en su envío usando el
+parámetro ``--base``. La forma más fácil y conveniente de usar esta opción
+es con "topical branches" (ramas de temas)::
+
+ $ git checkout -t -b my-topical-branch master
+ Branch 'my-topical-branch' set up to track local branch 'master'.
+ Switched to a new branch 'my-topical-branch'
+
+ [realice sus cambios y ediciones]
+
+ $ git format-patch --base=auto --cover-letter -o outgoing/ master
+ outgoing/0000-cover-letter.patch
+ outgoing/0001-First-Commit.patch
+ outgoing/...
+
+Cuando abra ``outgoing/0000-cover-letter.patch`` para editar, tenga en
+cuenta que tendrá el tráiler ``base-commit:`` al final, que proporciona al
+revisor y a las herramientas de CI suficiente información para realizar
+correctamente ``git am`` sin preocuparse por los conflictos::
+
+ $ git checkout -b patch-review [base-commit-id]
+ Switched to a new branch 'patch-review'
+ $ git am patches.mbox
+ Applying: First Commit
+ Applying: ...
+
+Consulte ``man git-format-patch`` para obtener más información al respecto
+de esta opción.
+
+.. Note::
+
+ La función ``--base`` se introdujo en la versión 2.9.0 de git.
+
+Si no está utilizando git para dar forma a sus parches, aún puede incluir
+el mismo tráiler ``base-commit`` para indicar el hash de confirmación del
+árbol en que se basa su trabajo. Debe agregarlo en la carta de presentación
+o en el primer parche de la serie y debe colocarse ya sea bajo la línea
+``---`` o en la parte inferior de todos los demás contenido, justo antes de
+su firma del correo electrónico.
+
+
+Referencias
+-----------
+
+"The perfect patch" (tpp) por Andrew Morton.
+ <https://www.ozlabs.org/~akpm/stuff/tpp.txt>
+
+"Linux kernel patch submission format" por Jeff Garzik.
+ <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
+
+"How to piss off a kernel subsystem maintainer" por Greg Kroah-Hartman.
+ <http://www.kroah.com/log/linux/maintainer.html>
+
+ <http://www.kroah.com/log/linux/maintainer-02.html>
+
+ <http://www.kroah.com/log/linux/maintainer-03.html>
+
+ <http://www.kroah.com/log/linux/maintainer-04.html>
+
+ <http://www.kroah.com/log/linux/maintainer-05.html>
+
+ <http://www.kroah.com/log/linux/maintainer-06.html>
+
+NO!!!! Gente, no mas bombas enormes de parches a linux-kernel@vger.kernel.org!
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
+
+Kernel Documentation/process/coding-style.rst
+
+Email de Linus Torvalds sobre la forma canónica de los parches:
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
+
+"On submitting kernel patches" por Andi Kleen
+ Algunas estrategias para conseguir incluir cambios complicados o
+ controvertidos.
+
+ http://halobates.de/on-submitting-patches.pdf
diff --git a/Documentation/translations/sp_SP/wrappers/memory-barriers.rst b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst
new file mode 100644
index 000000000000..50715b7d51b9
--- /dev/null
+++ b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst
@@ -0,0 +1,19 @@
+.. SPDX-License-Identifier: GPL-2.0
+ This is a simple wrapper to bring memory-barriers.txt (Spanish
+ translation) into the RST world until such a time as that file can be
+ converted directly.
+
+====================================
+Barreras de Memoria del kernel Linux
+====================================
+
+.. raw:: latex
+
+ \footnotesize
+
+.. include:: ../memory-barriers.txt
+ :literal:
+
+.. raw:: latex
+
+ \normalsize
diff --git a/Documentation/translations/zh_CN/core-api/errseq.rst b/Documentation/translations/zh_CN/core-api/errseq.rst
new file mode 100644
index 000000000000..815fb303ea2f
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/errseq.rst
@@ -0,0 +1,145 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/errseq.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+================
+errseq_t数据类型
+================
+
+``errseq_t`` 是一种在一个地方记录错误的方法,并允许任意数量的 ``订阅者`` 判断自上
+次采样点以来是否发生了变化。
+
+最初的用例是跟踪文件同步系统调用( ``fsync``, ``fdatasync``, ``msync`` 和
+``sync_file_range`` )的错误,但它也可以用于其他情况。
+
+它被实现为一个无符号的32位值。低位被指定保存错误代码(在1和MAX_ERRNO之间)。高位
+用作计数器。这里是用原子操作而不是锁来完成的,因此可以从任何上下文中调用这些函数。
+
+请注意,如果频繁记录新错误,则存在冲突风险,因为我们用作计数器的位很少。
+
+为了缓解这种情况,错误值和计数器之间的位被用作一个标志,以判断自记录新值以来是否
+对该值进行了采样。这使我们能够避免在上次记录错误后没有人取样的情况下碰撞计数器。
+
+因此,我们得到了一个类似这样的值:
+
++--------------------------------------+------+------------------------+
+| 31..13 | 12 | 11..0 |
++--------------------------------------+------+------------------------+
+| 计数器 | 标志 | 错误值 |
++--------------------------------------+------+------------------------+
+
+总体思路是让 ``观察者`` 对errseq_t值进行采样,并将其保留为运行游标。该值稍后可用
+于判断自采样完成后是否发生了任何新错误,并原子地记录检查时的状态。这使得我们能在
+一个地方记录错误,然后有许多 ``观察者`` 可以判断自上次检查以来该值是否发生了变化。
+
+新的errseq_t应始终清零。全零的errseq_t值是从未出现错误的特殊(但常见)情况。因此,
+如果您希望知道自首次初始化以来是否曾经有过错误集,则全零值被用作 ``纪元`` 。
+
+API的使用方法
+=============
+
+让我给你们讲一个关于员工drone的故事。现在,他总体上是个好员工,但公司有点...管理
+繁重。他今天必须向77名主管汇报,明天 ``大老板`` 要从外地赶来,他肯定也会考验这个
+可怜的家伙。
+
+他们都把工作交给他去做---多到他都记不住谁交给他什么了,但这并不是什么大问题。主管
+们只想知道他什么时候完成他们迄今为止交给他的所有工作,以及自从他们上次询问以来他
+是否犯了任何错误。
+
+他可能在他们实际上并没有交给他的工作上犯了错误,但他无法在那么详细的层面上记录事
+情,他所能记得的只是他最近犯的错误。
+
+下面是我们 ``worker_drone`` 的表达式::
+
+ struct worker_drone {
+ errseq_t wd_err; /* 用来记录错误 */
+ };
+
+每天, ``worker_drone`` 都是以一张白纸开始的::
+
+ struct worker_drone wd;
+
+ wd.wd_err = (errseq_t)0;
+
+主管们进来后对当天的工作进行初步了解。他们并不关心在他们观察开始之前发生的任何事
+情::
+
+ struct supervisor {
+ errseq_t s_wd_err; /* wd_err的私有“游标” */
+ spinlock_t s_wd_err_lock; /* 保护s_wd_err */
+ }
+
+ struct supervisor su;
+
+ su.s_wd_err = errseq_sample(&wd.wd_err);
+ spin_lock_init(&su.s_wd_err_lock);
+
+现在他们开始给他布置任务。每隔几分钟,他们就要求他完成迄今为止交给他的所有工作。
+然后问他是否有犯任何错误::
+
+ spin_lock(&su.su_wd_err_lock);
+ err = errseq_check_and_advance(&wd.wd_err, &su.s_wd_err);
+ spin_unlock(&su.su_wd_err_lock);
+
+到目前为止,它只是不断返回0。
+
+现在,这家公司的老板非常吝啬,给了他不合格的设备来完成他的工作。偶尔设备会出现故
+障,导致他犯错。他重重地叹了一口气,并把它记录下来::
+
+ errseq_set(&wd.wd_err, -EIO);
+
+...然后继续工作。主管们最终会再次检查,他们在下次检查时都会发现这个错误。后续的调
+用将返回0,直到记录下另一个错误,此时将向每个调用报告一次。
+
+请注意,主管们无法知道他们犯了多少错误,只能知道自上次检查以来是否犯了一个错误,
+以及记录的最新值。
+
+偶尔,大老板会来抽查,要求员工为他做一次性的工作。他并不像主管们那样全职观察员工,
+但他确实需要知道在他的工作处理过程中是否发生了错误。
+
+他只需对员工当前的errseq_t进行采样,然后用它来判断后来是否发生了错误::
+
+ errseq_t since = errseq_sample(&wd.wd_err);
+ /* 提交一些工作,等待完成 */
+ err = errseq_check(&wd.wd_err, since);
+
+由于他只是要在那个点之后丢弃 ``since`` ,所以他不需要在这里推进它。同时他也不需要
+任何锁,因为它不能被其他人使用。
+
+序列化更新errseq_t游标
+======================
+
+请注意,errseq_t API在check_and_advance_operation期间不保护errseq_t游标。只有典型
+的错误代码是被原子化处理的。在多任务同时使用同一个errseq_t游标的情况下,对该游标
+的更新进行序列化是很重要的。
+
+如果不这样做,那么游标就有可能向后移动。在这种情况下,同一个错误可能被报告多次。
+
+因此,通常先执行errseq_check检查是否有任何变化,然后在获取锁后才执行
+errseq_check_and_advance。例如::
+
+ if (errseq_check(&wd.wd_err, READ_ONCE(su.s_wd_err)) {
+ /* su.s_wd_err被s_wd_err_lock保护 */
+ spin_lock(&su.s_wd_err_lock);
+ err = errseq_check_and_advance(&wd.wd_err, &su.s_wd_err);
+ spin_unlock(&su.s_wd_err_lock);
+ }
+
+这就避免了自上次检查以来没有任何变化的常见情况下的自旋锁。
+
+函数
+====
+
+该API在以下内核代码中:
+
+lib/errseq.c
diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst
index 37756d240b5e..922cabf7b5dd 100644
--- a/Documentation/translations/zh_CN/core-api/index.rst
+++ b/Documentation/translations/zh_CN/core-api/index.rst
@@ -48,12 +48,12 @@
circular-buffers
generic-radix-tree
packing
+ this_cpu_ops
-Todolist:
-
+=======
+Todolist:
- this_cpu_ops
timekeeping
errseq
diff --git a/Documentation/translations/zh_CN/core-api/local_ops.rst b/Documentation/translations/zh_CN/core-api/local_ops.rst
index 41e4525038e8..eb5423f60f17 100644
--- a/Documentation/translations/zh_CN/core-api/local_ops.rst
+++ b/Documentation/translations/zh_CN/core-api/local_ops.rst
@@ -185,7 +185,7 @@ UP之间没有不同的行为,在你的架构的 ``local.h`` 中包括 ``asm-g
static void __exit test_exit(void)
{
- del_timer_sync(&test_timer);
+ timer_shutdown_sync(&test_timer);
}
module_init(test_init);
diff --git a/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst b/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst
new file mode 100644
index 000000000000..bea5ee8eb8a0
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst
@@ -0,0 +1,285 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/this_cpu_ops.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+============
+this_cpu操作
+============
+
+:作者: Christoph Lameter, 2014年8月4日
+:作者: Pranith Kumar, 2014年8月2日
+
+this_cpu操作是一种优化访问与当前执行处理器相关的每CPU变量的方法。这是通过使用段寄
+存器(或专用寄存器,cpu在其中永久存储特定处理器的每CPU区域的起始)来完成的。
+
+this_cpu操作将每CPU变量的偏移量添加到处理器特定的每CPU基址上,并将该操作编码到对
+每CPU变量进行操作的指令中。
+
+这意味着在偏移量的计算和对数据的操作之间不存在原子性问题。因此,没有必要禁用抢占
+或中断来确保处理器在计算地址和数据操作之间不被改变。
+
+读取-修改-写入操作特别值得关注。通常处理器具有特殊的低延迟指令,可以在没有典型同
+步开销的情况下运行,但仍提供某种宽松的原子性保证。例如,x86可以执行RMW(读取,
+修改,写入)指令,如同inc/dec/cmpxchg,而无需锁前缀和相关的延迟损失。
+
+对没有锁前缀的变量的访问是不同步的,也不需要同步,因为我们处理的是当前执行的处理
+器所特有的每CPU数据。只有当前的处理器可以访问该变量,因此系统中的其他处理器不存在
+并发性问题。
+
+请注意,远程处理器对每CPU区域的访问是特殊情况,可能会影响通过 ``this_cpu_*`` 的本
+地RMW操作的性能和正确性(远程写操作)。
+
+this_cpu操作的主要用途是优化计数器操作。
+
+定义了以下具有隐含抢占保护的this_cpu()操作。可以使用这些操作而不用担心抢占和中断::
+
+ this_cpu_read(pcp)
+ this_cpu_write(pcp, val)
+ this_cpu_add(pcp, val)
+ this_cpu_and(pcp, val)
+ this_cpu_or(pcp, val)
+ this_cpu_add_return(pcp, val)
+ this_cpu_xchg(pcp, nval)
+ this_cpu_cmpxchg(pcp, oval, nval)
+ this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+ this_cpu_sub(pcp, val)
+ this_cpu_inc(pcp)
+ this_cpu_dec(pcp)
+ this_cpu_sub_return(pcp, val)
+ this_cpu_inc_return(pcp)
+ this_cpu_dec_return(pcp)
+
+
+this_cpu操作的内部工作
+----------------------
+
+在x86上,fs:或gs:段寄存器包含每CPU区域的基址。这样就可以简单地使用段覆盖,将每CPU
+相对地址重定位到处理器适当的每CPU区域。所以对每CPU基址的重定位是通过段寄存器前缀
+在指令中编码完成的。
+
+例如::
+
+ DEFINE_PER_CPU(int, x);
+ int z;
+
+ z = this_cpu_read(x);
+
+产生的单指令为::
+
+ mov ax, gs:[x]
+
+而不是像每CPU操作那样,先是一系列的地址计算,然后从该地址获取。在this_cpu_ops之前,
+这样的序列还需要先禁用/启用抢占功能,以防止内核在计算过程中将线程移动到不同的处理
+器上。
+
+请思考下面this_cpu操作::
+
+ this_cpu_inc(x)
+
+这将产生如下单指令(无锁前缀!)::
+
+ inc gs:[x]
+
+而不是在没有段寄存器的情况下所需要的以下操作::
+
+ int *y;
+ int cpu;
+
+ cpu = get_cpu();
+ y = per_cpu_ptr(&x, cpu);
+ (*y)++;
+ put_cpu();
+
+请注意,这些操作只能用于为特定处理器保留的每CPU数据。如果不在上下文代码中禁用抢占,
+``this_cpu_inc()`` 将仅保证每CPU的某一个计数器被正确地递增,但不能保证操作系统不
+会在this_cpu指令执行的前后直接移动该进程。一般来说,这意味着每个处理器的单个计数
+器的值是没有意义的。所有每CPU计数器的总和才是唯一有意义的值。
+
+每CPU变量的使用是出于性能的考虑。如果多个处理器同时处理相同的代码路径,可以避免缓
+存行跳转。每个处理器都有自己的每CPU变量,因此不会发生并发缓存行更新。为这种优化必
+须付出的代价是,当需要计数器的值时要将每CPU计数器相加。
+
+
+特殊的操作
+----------
+
+::
+
+ y = this_cpu_ptr(&x)
+
+使用每CPU变量的偏移量(&x!),并返回属于当前执行处理器的每CPU变量的地址。
+``this_cpu_ptr`` 避免了通用 ``get_cpu``/``put_cpu`` 序列所需的多个步骤。没有可用
+的处理器编号。相反,本地每CPU区域的偏移量只是简单地添加到每CPU偏移量上。
+
+请注意,这个操作通常是在抢占被禁用后再在代码段中使用。然后该指针用来访问临界区中
+的本地每CPU数据。当重新启用抢占时,此指针通常不再有用,因为它可能不再指向当前处理
+器的每CPU数据。
+
+每CPU变量和偏移量
+-----------------
+
+每CPU变量相对于每CPU区域的起始点是有偏移的。它们没有地址,尽管代码里看起来像有一
+样。不能直接对偏移量解引用,必须用处理器每CPU区域基指针加上偏移量,以构成有效地址。
+
+因此,在每CPU操作的上下文之外使用x或&x是无效的,这种行为通常会被当作一个空指针的
+解引用来处理。
+
+::
+
+ DEFINE_PER_CPU(int, x);
+
+在每CPU操作的上下文中,上面表达式说明x是一个每CPU变量。大多数this_cpu操作都需要一
+个cpu变量。
+
+::
+
+ int __percpu *p = &x;
+
+&x和p是每CPU变量的偏移量。 ``this_cpu_ptr()`` 使用每CPU变量的偏移量,这让它看起来
+有点奇怪。
+
+
+每CPU结构体字段的操作
+---------------------
+
+假设我们有一个每CPU结构::
+
+ struct s {
+ int n,m;
+ };
+
+ DEFINE_PER_CPU(struct s, p);
+
+
+这些字段的操作非常简单::
+
+ this_cpu_inc(p.m)
+
+ z = this_cpu_cmpxchg(p.m, 0, 1);
+
+
+如果我们有一个相对于结构体s的偏移量::
+
+ struct s __percpu *ps = &p;
+
+ this_cpu_dec(ps->m);
+
+ z = this_cpu_inc_return(ps->n);
+
+
+如果我们后面不使用 ``this_cpu ops`` 来操作字段,则指针的计算可能需要使用
+``this_cpu_ptr()``::
+
+ struct s *pp;
+
+ pp = this_cpu_ptr(&p);
+
+ pp->m--;
+
+ z = pp->n++;
+
+
+this_cpu ops的变体
+------------------
+
+this_cpu的操作是中断安全的。一些架构不支持这些每CPU的本地操作。在这种情况下,该操
+作必须被禁用中断的代码所取代,然后做那些保证是原子的操作,再重新启用中断。当然这
+样做是很昂贵的。如果有其他原因导致调度器不能改变我们正在执行的处理器,那么就没有
+理由禁用中断了。为此,我们提供了以下__this_cpu操作。
+
+这些操作不能保证并发中断或抢占。如果在中断上下文中不使用每CPU变量并且调度程序无法
+抢占,那么它们是安全的。如果在操作进行时仍有中断发生,并且中断也修改了变量,则无
+法保证RMW操作是安全的::
+
+ __this_cpu_read(pcp)
+ __this_cpu_write(pcp, val)
+ __this_cpu_add(pcp, val)
+ __this_cpu_and(pcp, val)
+ __this_cpu_or(pcp, val)
+ __this_cpu_add_return(pcp, val)
+ __this_cpu_xchg(pcp, nval)
+ __this_cpu_cmpxchg(pcp, oval, nval)
+ __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+ __this_cpu_sub(pcp, val)
+ __this_cpu_inc(pcp)
+ __this_cpu_dec(pcp)
+ __this_cpu_sub_return(pcp, val)
+ __this_cpu_inc_return(pcp)
+ __this_cpu_dec_return(pcp)
+
+
+将增加x,并且不会回退到在无法通过地址重定位和同一指令中的读取-修改-写入操作实现原
+子性的平台上禁用中断的代码。
+
+
+&this_cpu_ptr(pp)->n 对比 this_cpu_ptr(&pp->n)
+----------------------------------------------
+
+第一个操作使用偏移量并形成一个地址,然后再加上n字段的偏移量。这可能会导致编译器产
+生两条加法指令。
+
+第二个操作先加上两个偏移量,然后进行重定位。恕我直言,第二种形式看起来更干净,而
+且更容易与 ``()`` 结合。第二种形式也与 ``this_cpu_read()`` 和大家的使用方式一致。
+
+
+远程访问每CPU数据
+-----------------
+
+每CPU数据结构被设计为由一个CPU独占使用。如果您按预期使用变量,则 ``this_cpu_ops()``
+保证是 ``原子的`` ,因为没有其他CPU可以访问这些数据结构。
+
+在某些特殊情况下,您可能需要远程访问每CPU数据结构。通常情况下,进行远程读访问是安
+全的,这经常是为了统计计数器值。远程写访问可能会出现问题,因为this_cpu操作没有锁
+语义。远程写可能会干扰this_cpu RMW操作。
+
+除非绝对必要,否则强烈建议不要对每CPU数据结构进行远程写访问。请考虑使用IPI来唤醒
+远程CPU,并对其每CPU区域进行更新。
+
+要远程访问每CPU数据结构,通常使用 ``per_cpu_ptr()`` 函数::
+
+
+ DEFINE_PER_CPU(struct data, datap);
+
+ struct data *p = per_cpu_ptr(&datap, cpu);
+
+这清楚地表明,我们正准备远程访问每CPU区域。
+
+您还可以执行以下操作以将datap偏移量转换为地址::
+
+ struct data *p = this_cpu_ptr(&datap);
+
+但是,将通过this_cpu_ptr计算的指针传递给其他cpu是不寻常的,应该避免。
+
+远程访问通常只用于读取另一个cpu的每CPU数据状态。由于this_cpu操作宽松的同步要求,
+写访问可能会导致奇特的问题。
+
+下面的情况说明了写入操作的一些问题,由于两个每CPU变量共享一个缓存行,但宽松的同步
+仅应用于更新缓存行的一个进程。
+
+考虑以下示例::
+
+
+ struct test {
+ atomic_t a;
+ int b;
+ };
+
+ DEFINE_PER_CPU(struct test, onecacheline);
+
+如果一个处理器远程更新字段 ``a`` ,而本地处理器将使用this_cpu ops来更新字段 ``b`` ,
+会发生什么情况,这一点值得注意。应避免在同一缓存行内同时访问数据。此外,可能还需
+要进行代价高昂的同步。在这种情况下,通常建议使用IPI,而不是远程写入另一个处理器的
+每CPU区域。
+
+即使在远程写很少的情况下,请记住远程写将从最有可能访问它的处理器中逐出缓存行。如
+果处理器唤醒时发现每CPU区域缺少本地缓存行,其性能和唤醒时间将受到影响。
diff --git a/Documentation/translations/zh_CN/doc-guide/index.rst b/Documentation/translations/zh_CN/doc-guide/index.rst
index 5151953c196f..78c2e9a1697f 100644
--- a/Documentation/translations/zh_CN/doc-guide/index.rst
+++ b/Documentation/translations/zh_CN/doc-guide/index.rst
@@ -19,7 +19,7 @@
contributing
maintainer-profile
-.. only:: 子项目与HTML
+.. only:: subproject and html
目录
====
diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst
index ec99ef5fe990..3660a3451c86 100644
--- a/Documentation/translations/zh_CN/index.rst
+++ b/Documentation/translations/zh_CN/index.rst
@@ -71,6 +71,7 @@ TODOList:
dev-tools/index
dev-tools/testing-overview
kernel-hacking/index
+ rust/index
TODOList:
@@ -90,12 +91,12 @@ TODOList:
admin-guide/index
admin-guide/reporting-issues.rst
+ userspace-api/index
TODOList:
* 内核构建系统 <kbuild/index>
* 用户空间工具 <tools/index>
-* userspace-api/index
也可参考独立于内核文档的 `Linux 手册页 <https://www.kernel.org/doc/man-pages/>`_ 。
@@ -124,13 +125,13 @@ TODOList:
其他文档
--------
-有几份未排序的文档似乎不适合放在文档的其他部分,或者可能需要进行一些调整和/或
+有几份未分类的文档似乎不适合放在文档的其他部分,或者可能需要进行一些调整和/或
转换为reStructureText格式,也有可能太旧。
-TODOList:
-
-* staging/index
+.. toctree::
+ :maxdepth: 2
+ staging/index
索引和表格
----------
diff --git a/Documentation/translations/zh_CN/loongarch/booting.rst b/Documentation/translations/zh_CN/loongarch/booting.rst
new file mode 100644
index 000000000000..fb6440c438f0
--- /dev/null
+++ b/Documentation/translations/zh_CN/loongarch/booting.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/loongarch/booting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+====================
+启动 Linux/LoongArch
+====================
+
+:作者: 司延腾 <siyanteng@loongson.cn>
+:日期: 2022年11月18日
+
+BootLoader传递给内核的信息
+==========================
+
+LoongArch支持ACPI和FDT启动,需要传递给内核的信息包括memmap、initrd、cmdline、可
+选的ACPI/FDT表等。
+
+内核在 `kernel_entry` 入口处被传递以下参数:
+
+ - a0 = efi_boot: `efi_boot` 是一个标志,表示这个启动环境是否完全符合UEFI
+ 的要求。
+
+ - a1 = cmdline: `cmdline` 是一个指向内核命令行的指针。
+
+ - a2 = systemtable: `systemtable` 指向EFI的系统表,在这个阶段涉及的所有
+ 指针都是物理地址。
+
+Linux/LoongArch内核镜像文件头
+=============================
+
+内核镜像是EFI镜像。作为PE文件,它们有一个64字节的头部结构体,如下所示::
+
+ u32 MZ_MAGIC /* "MZ", MS-DOS 头 */
+ u32 res0 = 0 /* 保留 */
+ u64 kernel_entry /* 内核入口点 */
+ u64 _end - _text /* 内核镜像有效大小 */
+ u64 load_offset /* 加载内核镜像相对内存起始地址的偏移量 */
+ u64 res1 = 0 /* 保留 */
+ u64 res2 = 0 /* 保留 */
+ u64 res3 = 0 /* 保留 */
+ u32 LINUX_PE_MAGIC /* 魔术数 */
+ u32 pe_header - _head /* 到PE头的偏移量 */
diff --git a/Documentation/translations/zh_CN/loongarch/index.rst b/Documentation/translations/zh_CN/loongarch/index.rst
index 7d23eb78379d..0273a08342f7 100644
--- a/Documentation/translations/zh_CN/loongarch/index.rst
+++ b/Documentation/translations/zh_CN/loongarch/index.rst
@@ -14,6 +14,7 @@ LoongArch体系结构
:numbered:
introduction
+ booting
irq-chip-model
features
diff --git a/Documentation/translations/zh_CN/loongarch/introduction.rst b/Documentation/translations/zh_CN/loongarch/introduction.rst
index 128878f5bb70..470c38ae2caf 100644
--- a/Documentation/translations/zh_CN/loongarch/introduction.rst
+++ b/Documentation/translations/zh_CN/loongarch/introduction.rst
@@ -70,8 +70,8 @@ LA64中每个寄存器为64位宽。 ``$r0`` 的内容总是固定为0,而其
================= ================== =================== ==========
.. note::
- 注意:在一些遗留代码中有时可能见到 ``$v0`` 和 ``$v1`` ,它们是
- ``$a0`` 和 ``$a1`` 的别名,属于已经废弃的用法。
+ 注意:在一些遗留代码中有时可能见到 ``$fv0`` 和 ``$fv1`` ,它们是
+ ``$fa0`` 和 ``$fa1`` 的别名,属于已经废弃的用法。
向量寄存器
@@ -338,15 +338,15 @@ Loongson与LoongArch的开发者网站(软件与文档资源):
LoongArch指令集架构的文档:
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.00-CN.pdf (中文版)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (中文版)
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.00-EN.pdf (英文版)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (英文版)
LoongArch的ELF psABI文档:
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v1.00-CN.pdf (中文版)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-CN.pdf (中文版)
- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v1.00-EN.pdf (英文版)
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-EN.pdf (英文版)
Loongson与LoongArch的Linux内核源码仓库:
diff --git a/Documentation/translations/zh_CN/rust/arch-support.rst b/Documentation/translations/zh_CN/rust/arch-support.rst
new file mode 100644
index 000000000000..afbd02afec45
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/arch-support.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/arch-support.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+架构支持
+========
+
+目前,Rust编译器(``rustc``)使用LLVM进行代码生成,这限制了可以支持的目标架构。此外,对
+使用LLVM/Clang构建内核的支持也有所不同(请参见 Documentation/kbuild/llvm.rst )。这
+种支持对于使用 ``libclang`` 的 ``bindgen`` 来说是必需的。
+
+下面是目前可以工作的架构的一般总结。支持程度与 ``MAINTAINERS`` 文件中的``S`` 值相对应:
+
+============ ================ ==============================================
+架构 支持水平 限制因素
+============ ================ ==============================================
+``x86`` Maintained 只有 ``x86_64``
+============ ================ ==============================================
diff --git a/Documentation/translations/zh_CN/rust/coding-guidelines.rst b/Documentation/translations/zh_CN/rust/coding-guidelines.rst
new file mode 100644
index 000000000000..6c0bdbbc5a2a
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/coding-guidelines.rst
@@ -0,0 +1,192 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/coding-guidelines.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+编码指南
+========
+
+本文档描述了如何在内核中编写Rust代码。
+
+
+风格和格式化
+------------
+
+代码应该使用 ``rustfmt`` 进行格式化。这样一来,一个不时为内核做贡献的人就不需要再去学
+习和记忆一个样式指南了。更重要的是,审阅者和维护者不需要再花时间指出风格问题,这样就可以
+减少补丁落地所需的邮件往返。
+
+.. note:: ``rustfmt`` 不检查注释和文档的约定。因此,这些仍然需要照顾到。
+
+使用 ``rustfmt`` 的默认设置。这意味着遵循Rust的习惯性风格。例如,缩进时使用4个空格而
+不是制表符。
+
+在输入、保存或提交时告知编辑器/IDE进行格式化是很方便的。然而,如果因为某些原因需要在某
+个时候重新格式化整个内核Rust的源代码,可以运行以下程序::
+
+ make LLVM=1 rustfmt
+
+也可以检查所有的东西是否都是格式化的(否则就打印一个差异),例如对于一个CI,用::
+
+ make LLVM=1 rustfmtcheck
+
+像内核其他部分的 ``clang-format`` 一样, ``rustfmt`` 在单个文件上工作,并且不需要
+内核配置。有时,它甚至可以与破碎的代码一起工作。
+
+
+注释
+----
+
+“普通”注释(即以 ``//`` 开头,而不是 ``///`` 或 ``//!`` 开头的代码文档)的写法与文
+档注释相同,使用Markdown语法,尽管它们不会被渲染。这提高了一致性,简化了规则,并允许在
+这两种注释之间更容易地移动内容。比如说:
+
+.. code-block:: rust
+
+ // `object` is ready to be handled now.
+ f(object);
+
+此外,就像文档一样,注释在句子的开头要大写,并以句号结束(即使是单句)。这包括 ``// SAFETY:``,
+``// TODO:`` 和其他“标记”的注释,例如:
+
+.. code-block:: rust
+
+ // FIXME: The error should be handled properly.
+
+注释不应该被用于文档的目的:注释是为了实现细节,而不是为了用户。即使源文件的读者既是API
+的实现者又是用户,这种区分也是有用的。事实上,有时同时使用注释和文档是很有用的。例如,用
+于 ``TODO`` 列表或对文档本身的注释。对于后一种情况,注释可以插在中间;也就是说,离要注
+释的文档行更近。对于其他情况,注释会写在文档之后,例如:
+
+.. code-block:: rust
+
+ /// Returns a new [`Foo`].
+ ///
+ /// # Examples
+ ///
+ // TODO: Find a better example.
+ /// ```
+ /// let foo = f(42);
+ /// ```
+ // FIXME: Use fallible approach.
+ pub fn f(x: i32) -> Foo {
+ // ...
+ }
+
+一种特殊的注释是 ``// SAFETY:`` 注释。这些注释必须出现在每个 ``unsafe`` 块之前,它们
+解释了为什么该块内的代码是正确/健全的,即为什么它在任何情况下都不会触发未定义行为,例如:
+
+.. code-block:: rust
+
+ // SAFETY: `p` is valid by the safety requirements.
+ unsafe { *p = 0; }
+
+``// SAFETY:`` 注释不能与代码文档中的 ``# Safety`` 部分相混淆。 ``# Safety`` 部
+分指定了(函数)调用者或(特性)实现者需要遵守的契约。
+``// SAFETY:`` 注释显示了为什么一个(函数)调用者或(特性)实现者实际上尊重了
+``# Safety`` 部分或语言参考中的前提条件。
+
+
+代码文档
+--------
+
+Rust内核代码不像C内核代码那样被记录下来(即通过kernel-doc)。取而代之的是用于记录Rust
+代码的常用系统:rustdoc工具,它使用Markdown(一种轻量级的标记语言)。
+
+要学习Markdown,外面有很多指南。例如:
+
+https://commonmark.org/help/
+
+一个记录良好的Rust函数可能是这样的:
+
+.. code-block:: rust
+
+ /// Returns the contained [`Some`] value, consuming the `self` value,
+ /// without checking that the value is not [`None`].
+ ///
+ /// # Safety
+ ///
+ /// Calling this method on [`None`] is *[undefined behavior]*.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = Some("air");
+ /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
+ /// ```
+ pub unsafe fn unwrap_unchecked(self) -> T {
+ match self {
+ Some(val) => val,
+
+ // SAFETY: The safety contract must be upheld by the caller.
+ None => unsafe { hint::unreachable_unchecked() },
+ }
+ }
+
+这个例子展示了一些 ``rustdoc`` 的特性和内核中遵循的一些惯例:
+
+ - 第一段必须是一个简单的句子,简要地描述被记录的项目的作用。进一步的解释必须放在额
+ 外的段落中。
+
+ - 不安全的函数必须在 ``# Safety`` 部分记录其安全前提条件。
+
+ - 虽然这里没有显示,但如果一个函数可能会恐慌,那么必须在 ``# Panics`` 部分描述发
+ 生这种情况的条件。
+
+ 请注意,恐慌应该是非常少见的,只有在有充分理由的情况下才会使用。几乎在所有的情况下,
+ 都应该使用一个可失败的方法,通常是返回一个 ``Result``。
+
+ - 如果提供使用实例对读者有帮助的话,必须写在一个叫做``# Examples``的部分。
+
+ - Rust项目(函数、类型、常量……)必须有适当的链接(``rustdoc`` 会自动创建一个
+ 链接)。
+
+ - 任何 ``unsafe`` 的代码块都必须在前面加上一个 ``// SAFETY:`` 的注释,描述里面
+ 的代码为什么是正确的。
+
+ 虽然有时原因可能看起来微不足道,但写这些注释不仅是记录已经考虑到的问题的好方法,
+ 最重要的是,它提供了一种知道没有额外隐含约束的方法。
+
+要了解更多关于如何编写Rust和拓展功能的文档,请看看 ``rustdoc`` 这本书,网址是:
+
+ https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html
+
+
+命名
+----
+
+Rust内核代码遵循通常的Rust命名空间:
+
+ https://rust-lang.github.io/api-guidelines/naming.html
+
+当现有的C语言概念(如宏、函数、对象......)被包装成Rust抽象时,应该使用尽可能接近C语
+言的名称,以避免混淆,并在C语言和Rust语言之间来回切换时提高可读性。例如,C语言中的
+``pr_info`` 这样的宏在Rust中的命名是一样的。
+
+说到这里,应该调整大小写以遵循Rust的命名惯例,模块和类型引入的命名间隔不应该在项目名称
+中重复。例如,在包装常量时,如:
+
+.. code-block:: c
+
+ #define GPIO_LINE_DIRECTION_IN 0
+ #define GPIO_LINE_DIRECTION_OUT 1
+
+在Rust中的等价物可能是这样的(忽略文档)。:
+
+.. code-block:: rust
+
+ pub mod gpio {
+ pub enum LineDirection {
+ In = bindings::GPIO_LINE_DIRECTION_IN as _,
+ Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+ }
+ }
+
+也就是说, ``GPIO_LINE_DIRECTION_IN`` 的等价物将被称为 ``gpio::LineDirection::In`` 。
+特别是,它不应该被命名为 ``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN`` 。
diff --git a/Documentation/translations/zh_CN/rust/general-information.rst b/Documentation/translations/zh_CN/rust/general-information.rst
new file mode 100644
index 000000000000..6b91dfe1834a
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/general-information.rst
@@ -0,0 +1,75 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/general-information.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+
+基本信息
+========
+
+本文档包含了在内核中使用Rust支持时需要了解的有用信息。
+
+
+代码文档
+--------
+
+Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
+
+生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。它们可以在以下地址阅读
+(TODO:当在主线中时链接,与其他文档一起生成):
+
+ http://kernel.org/
+
+这些文档也可以很容易地在本地生成和阅读。这相当快(与编译代码本身的顺序相同),而且不需要特
+殊的工具或环境。这有一个额外的好处,那就是它们将根据所使用的特定内核配置进行定制。要生成它
+们,请使用 ``rustdoc`` 目标,并使用编译时使用的相同调用,例如::
+
+ make LLVM=1 rustdoc
+
+要在你的网络浏览器中本地阅读该文档,请运行如::
+
+ xdg-open rust/doc/kernel/index.html
+
+要了解如何编写文档,请看 coding-guidelines.rst 。
+
+
+额外的lints
+-----------
+
+虽然 ``rustc`` 是一个非常有用的编译器,但一些额外的lints和分析可以通过 ``clippy``
+(一个Rust linter)来实现。要启用它,请将CLIPPY=1传递到用于编译的同一调用中,例如::
+
+ make LLVM=1 CLIPPY=1
+
+请注意,Clippy可能会改变代码生成,因此在构建产品内核时不应该启用它。
+
+抽象和绑定
+----------
+
+抽象是用Rust代码包装来自C端的内核功能。
+
+为了使用来自C端的函数和类型,需要创建绑定。绑定是Rust对那些来自C端的函数和类型的声明。
+
+例如,人们可以在Rust中写一个 ``Mutex`` 抽象,它从C端包装一个 ``Mutex结构体`` ,并
+通过绑定调用其函数。
+
+抽象并不能用于所有的内核内部API和概念,但随着时间的推移,我们打算扩大覆盖范围。“Leaf”
+模块(例如,驱动程序)不应该直接使用C语言的绑定。相反,子系统应该根据需要提供尽可能安
+全的抽象。
+
+
+有条件的编译
+------------
+
+Rust代码可以访问基于内核配置的条件性编译:
+
+.. code-block:: rust
+
+ #[cfg(CONFIG_X)] // Enabled (`y` or `m`)
+ #[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`)
+ #[cfg(CONFIG_X="m")] // Enabled as a module (`m`)
+ #[cfg(not(CONFIG_X))] // Disabled
diff --git a/Documentation/translations/zh_CN/rust/index.rst b/Documentation/translations/zh_CN/rust/index.rst
new file mode 100644
index 000000000000..b01f887e7167
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/index.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+Rust
+====
+
+与内核中的Rust有关的文档。若要开始在内核中使用Rust,请阅读quick-start.rst指南。
+
+.. toctree::
+ :maxdepth: 1
+
+ quick-start
+ general-information
+ coding-guidelines
+ arch-support
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/rust/quick-start.rst b/Documentation/translations/zh_CN/rust/quick-start.rst
new file mode 100644
index 000000000000..a4b8e8a50a89
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/quick-start.rst
@@ -0,0 +1,211 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/quick-start.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+
+快速入门
+========
+
+本文介绍了如何开始使用Rust进行内核开发。
+
+
+构建依赖
+--------
+
+本节描述了如何获取构建所需的工具。
+
+其中一些依赖也许可以从Linux发行版中获得,包名可能是 ``rustc`` , ``rust-src`` ,
+``rust-bindgen`` 等。然而,在写这篇文章的时候,它们很可能还不够新,除非发行版跟踪最
+新的版本。
+
+为了方便检查是否满足要求,可以使用以下目标::
+
+ make LLVM=1 rustavailable
+
+这会触发与Kconfig用来确定是否应该启用 ``RUST_IS_AVAILABLE`` 相同的逻辑;不过,如
+果Kconfig认为不该启用,它会列出未满足的条件。
+
+
+rustc
+*****
+
+需要一个特定版本的Rust编译器。较新的版本可能会也可能不会工作,因为就目前而言,内核依赖
+于一些不稳定的Rust特性。
+
+如果使用的是 ``rustup`` ,请进入检出的源代码目录并运行::
+
+ rustup override set $(scripts/min-tool-version.sh rustc)
+
+或者从以下网址获取一个独立的安装程序或安装 ``rustup`` :
+
+ https://www.rust-lang.org
+
+
+Rust标准库源代码
+****************
+
+Rust标准库的源代码是必需的,因为构建系统会交叉编译 ``core`` 和 ``alloc`` 。
+
+如果正在使用 ``rustup`` ,请运行::
+
+ rustup component add rust-src
+
+这些组件是按工具链安装的,因此以后升级Rust编译器版本需要重新添加组件。
+
+否则,如果使用独立的安装程序,可以将Rust仓库克隆到工具链的安装文件夹中::
+
+ git clone --recurse-submodules \
+ --branch $(scripts/min-tool-version.sh rustc) \
+ https://github.com/rust-lang/rust \
+ $(rustc --print sysroot)/lib/rustlib/src/rust
+
+在这种情况下,以后升级Rust编译器版本需要手动更新这个克隆的仓库。
+
+
+libclang
+********
+
+``bindgen`` 使用 ``libclang`` (LLVM的一部分)来理解内核中的C代码,这意味着需要安
+装LLVM;同在开启 ``CC=clang`` 或 ``LLVM=1`` 时编译内核一样。
+
+Linux发行版中可能会有合适的包,所以最好先检查一下。
+
+适用于部分系统和架构的二进制文件也可到以下网址下载:
+
+ https://releases.llvm.org/download.html
+
+或者自行构建LLVM,这需要相当长的时间,但并不是一个复杂的过程:
+
+ https://llvm.org/docs/GettingStarted.html#getting-the-source-code-and-building-llvm
+
+请参阅 Documentation/kbuild/llvm.rst 了解更多信息,以及获取预构建版本和发行包
+的进一步方法。
+
+
+bindgen
+*******
+
+内核的C端绑定是在构建时使用 ``bindgen`` 工具生成的。这需要特定的版本。
+
+通过以下方式安装它(注意,这将从源码下载并构建该工具)::
+
+ cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen
+
+
+开发依赖
+--------
+
+本节解释了如何获取开发所需的工具。也就是说,在构建内核时不需要这些工具。
+
+
+rustfmt
+*******
+
+``rustfmt`` 工具被用来自动格式化所有的Rust内核代码,包括生成的C绑定(详情请见
+coding-guidelines.rst )。
+
+如果使用的是 ``rustup`` ,它的 ``默认`` 配置文件已经安装了这个工具,因此不需要做什么。
+如果使用的是其他配置文件,可以手动安装该组件::
+
+ rustup component add rustfmt
+
+独立的安装程序也带有 ``rustfmt`` 。
+
+
+clippy
+******
+
+``clippy`` 是一个Rust linter。运行它可以为Rust代码提供额外的警告。它可以通过向 ``make``
+传递 ``CLIPPY=1`` 来运行(关于细节,详见 general-information.rst )。
+
+如果正在使用 ``rustup`` ,它的 ``默认`` 配置文件已经安装了这个工具,因此不需要做什么。
+如果使用的是另一个配置文件,该组件可以被手动安装::
+
+ rustup component add clippy
+
+独立的安装程序也带有 ``clippy`` 。
+
+
+cargo
+*****
+
+``cargo`` 是Rust的本地构建系统。目前需要它来运行测试,因为它被用来构建一个自定义的标准
+库,其中包含了内核中自定义 ``alloc`` 所提供的设施。测试可以使用 ``rusttest`` Make 目标
+来运行。
+
+如果使用的是 ``rustup`` ,所有的配置文件都已经安装了该工具,因此不需要再做什么。
+
+独立的安装程序也带有 ``cargo`` 。
+
+
+rustdoc
+*******
+
+``rustdoc`` 是Rust的文档工具。它为Rust代码生成漂亮的HTML文档(详情请见 general-information.rst )。
+
+``rustdoc`` 也被用来测试文档化的Rust代码中提供的例子(称为doctests或文档测试)。
+``rusttest`` 是本功能的Make目标。
+
+如果使用的是 ``rustup`` ,所有的配置文件都已经安装了这个工具,因此不需要做什么。
+
+独立的安装程序也带有 ``rustdoc`` 。
+
+
+rust-analyzer
+*************
+
+`rust-analyzer <https://rust-analyzer.github.io/>`_ 语言服务器可以和许多编辑器
+一起使用,以实现语法高亮、补全、转到定义和其他功能。
+
+``rust-analyzer`` 需要一个配置文件, ``rust-project.json``, 它可以由 ``rust-analyzer``
+Make 目标生成。
+
+
+配置
+----
+
+Rust支持(CONFIG_RUST)需要在 ``General setup`` 菜单中启用。在其他要求得到满足的情
+况下,该选项只有在找到合适的Rust工具链时才会显示(见上文)。相应的,这将使依赖Rust的其
+他选项可见。
+
+之后,进入::
+
+ Kernel hacking
+ -> Sample kernel code
+ -> Rust samples
+
+并启用一些内置或可加载的样例模块。
+
+
+构建
+----
+
+用完整的LLVM工具链构建内核是目前支持的最佳设置。即::
+
+ make LLVM=1
+
+对于不支持完整LLVM工具链的架构,使用::
+
+ make CC=clang
+
+使用GCC对某些配置也是可行的,但目前它是非常试验性的。
+
+
+折腾
+----
+
+要想深入了解,请看 ``samples/rust/`` 下的样例源代码、 ``rust/`` 下的Rust支持代码和
+``Kernel hacking`` 下的 ``Rust hacking`` 菜单。
+
+如果使用的是GDB/Binutils,而Rust符号没有被demangled,原因是工具链还不支持Rust的新v0
+mangling方案。有几个办法可以解决:
+
+ - 安装一个较新的版本(GDB >= 10.2, Binutils >= 2.36)。
+
+ - 一些版本的GDB(例如vanilla GDB 10.1)能够使用嵌入在调试信息(``CONFIG_DEBUG_INFO``)
+ 中的pre-demangled的名字。
diff --git a/Documentation/translations/zh_CN/staging/index.rst b/Documentation/translations/zh_CN/staging/index.rst
new file mode 100644
index 000000000000..bb55c81c84a3
--- /dev/null
+++ b/Documentation/translations/zh_CN/staging/index.rst
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/staging/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+未分类文档
+==========
+
+.. toctree::
+ :maxdepth: 2
+
+ xz
+
+TODOList:
+
+* crc32
+* lzo
+* remoteproc
+* rpmsg
+* speculation
+* static-keys
+* tee
diff --git a/Documentation/translations/zh_CN/staging/xz.rst b/Documentation/translations/zh_CN/staging/xz.rst
new file mode 100644
index 000000000000..211c487bcb62
--- /dev/null
+++ b/Documentation/translations/zh_CN/staging/xz.rst
@@ -0,0 +1,100 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/staging/xz.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+===================
+Linux中的XZ数据压缩
+===================
+
+介绍
+====
+
+XZ是一种通用的数据压缩格式,其具有高压缩率和相对快的解压速度。主要的压缩算法(
+过滤器)是LZMA2。额外的过滤器可以被用来进一步提高压缩率,比如用来提高可执行数据
+压缩率的Branch/Call/Jump (BCJ)过滤器。
+
+XZ解压器在Linux中被称作XZ Embedded。它支持LZMA2过滤器和可选的BCJ过滤器,并支持
+CRC32完整性校验。你可以在XZ Embedded的主页<https://tukaani.org/xz/embedded.html>
+中找到最新版本和关于在Linux内核之外使用源码的信息。
+
+对于用户空间来说,XZ Utils提供了类似于zlib的压缩库和类似于gzip的命令行工具。
+XZ Utils可以从<https://tukaani.org/xz/>下载。
+
+内核中的XZ相关组件
+==================
+
+xz_dec模块为XZ解压器提供了单次调用(缓冲区到缓冲区)和多次调用(有状态)的
+API。xz_dec模块的用法记录在include/linux/xz.h中。
+
+xz_dec_test模块用于测试xz_dec。除非你想魔改XZ解压器,否则xz_dec_test是
+没有用的。xz_dec_test会动态分配一个字符设备主设备号,你可以从用户空间向它
+写入.xz文件,解压的输出会被丢弃。关注dmesg可以找到xz_dec_test输出的诊断信息。
+详细内容请查看xz_dec_test的源码。
+
+为了解压内核镜像、初始ram文件系统和初始ram磁盘,lib/decompress_unxz.c实现
+了一个包装函数。它的API与其他 decompress_*.c 文件相同,那些API定义在
+include/linux/decompress/generic.h中。
+
+scripts/xz_wrap.sh是一个XZ Utils中的xz命令行工具包装器。这个包装器会
+设置合适的压缩选项来压缩内核镜像。
+
+在内核的makefiles中,提供了使用$(call if_needed)的两个命令。内核镜像应该
+使用$(call if_needed,xzkern)来压缩,它会使用BCJ过滤器和一个大LZMA2字典。
+它还会附加一个四字节的包含源文件大小的预告,这会在启动代码中被用到。其他文件
+应该使用$(call if_needed,xzmisc)来压缩,它会使用1 MiB的LZMA2字典并禁用
+BCJ过滤器。
+
+关于压缩选项的说明
+==================
+
+因为XZ Embedded只支持没有完整性校验的数据流或者CRC32,请确保你在编码未来将被
+内核解码的文件时没有使用其他完整性校验方式。使用liblzma时,你需要使用LZMA_CHECK_NONE
+或LZMA_CHECK_CRC32。使用xz命令行工具时,使用--check=none或--check=crc32。
+
+除非有其他环节会验证解压数据的完整性,否则强烈使用CRC32。双重验证可能会浪费
+CPU周期。请注意头部总是会包含用于解压器验证的CRC32,你只能修改或禁用解压后数据
+的完整性校验方式。
+
+在用户中间中,LZMA2通常使用几兆字节大小的字典。解码器需要在RAM中放置字典,
+因此大字典不能被用于那些意在被内核解码的文件。1 MiB在内核中大概是可接受的最大
+字典大小(可能对初始ram文件系统也适用)。XZ Utils中的预设值可能并不适合创建
+内核文件,所以请别犹豫使用自定义设置。比如::
+
+ xz --check=crc32 --lzma2=dict=512KiB inputfile
+
+使用上面字典大小的一个例外是在单一调用模式下使用解码器。解压内核自身就是一个例
+子。在单一调用模式下,内存用量并不和字典大小有关,这种情况就是使用大字典的好地
+方:为了最大化压缩,字典至少应该和解压后的数据一样大。
+
+未来计划
+========
+
+如果有人认为有用的话,可能会考虑创建一个受限的XZ编码器。LZMA2的压缩速率比Deflate
+或LZO等要慢,即使在最快的配置选项下。所以并不清楚LZMA2编码器是否需要并入内核。
+
+有计划在解压代码中支持有限的随机访问读数据。不知道这能否在内核中有任何用,但是我
+知道这会在一些Linux内核以外的嵌入式项目中有用。
+
+.xz文件格式规范的一致性
+=======================
+
+在一些边缘情况下,为了简化事情牺牲了尽早地检测错误。因为并不会导致安全问题,实际
+上是没有关系的。但在测试代码的时候知道这一点很好,比如测试来自XZ Utils的文件。
+
+报告错误
+========
+
+请在报告错误前确认是否已经在上游修复。可以从<https://tukaani.org/xz/embedded.html>
+获取最新的源码。
+
+可以通过联系<lasse.collin@tukaani.org>或者访问Freenode上的#tukaani
+联系Larhzu。我并不经常阅读LKML或者其他内核相关的邮件列表,所以如果要告知我什么事情
+,你应该通过我的私人邮箱或者IRC联系我。
+
+请不要因为内核中XZ的实现或关于XZ Utils的问题打扰Igor Pavlov。虽然这两种实现
+包含了建立在Igor Pavlov的代码上的重要源码,但并不由他维护和提供支持。
diff --git a/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst
new file mode 100644
index 000000000000..845b932bf935
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst
@@ -0,0 +1,168 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/accelerators/ocxl.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+=====================================
+OpenCAPI (开放相干加速器处理器接口)
+=====================================
+
+*OpenCAPI: Open Coherent Accelerator Processor Interface*
+
+OpenCAPI是处理器和加速器之间的一个接口,致力于达到低延迟和高带宽。该规范
+由 `OpenCAPI Consortium <http://opencapi.org/>`_ 开发。
+
+它允许加速器(可以是FPGA、ASIC等)使用虚拟地址连贯地访问主机内存。一个OpenCAPI
+设备也可以托管它自己的内存,并可以由主机访问。
+
+OpenCAPI在Linux中称为“ocxl”,它作为“cxl”(用于powerpc的IBM CAPI接口的驱动)的
+开放、处理器无关的演进,这么命名是为了避免与ISDN CAPI子系统相混淆。
+
+
+高层视角
+========
+
+OpenCAPI定义了一个在物理链路层上实现的数据链路层(TL)和传输层(TL)。任何
+实现DL和TL的处理器或者设备都可以开始共享内存。
+
+::
+
+ +-----------+ +-------------+
+ | | | |
+ | | | Accelerated |
+ | Processor | | Function |
+ | | +--------+ | Unit | +--------+
+ | |--| Memory | | (AFU) |--| Memory |
+ | | +--------+ | | +--------+
+ +-----------+ +-------------+
+ | |
+ +-----------+ +-------------+
+ | TL | | TLX |
+ +-----------+ +-------------+
+ | |
+ +-----------+ +-------------+
+ | DL | | DLX |
+ +-----------+ +-------------+
+ | |
+ | PHY |
+ +---------------------------------------+
+
+ Processor:处理器
+ Memory:内存
+ Accelerated Function Unit:加速函数单元
+
+
+
+设备发现
+========
+
+OpenCAPI依赖一个在设备上实现的与PCI类似的配置空间。因此主机可以通过查询
+配置空间来发现AFU。
+
+OpenCAPI设备在Linux中被当作类PCI设备(有一些注意事项)。固件需要对硬件进行
+抽象,就好像它是一个PCI链路。许多已有的PCI架构被重用:在模拟标准PCI时,
+设备被扫描并且BAR(基址寄存器)被分配。像“lspci”的命令因此可以被用于查看
+哪些设备可用。
+
+配置空间定义了可以在物理适配器上可以被找到的AFU,比如它的名字、支持多少内
+存上下文、内存映射IO(MMIO)区域的大小等。
+
+
+
+MMIO
+====
+
+OpenCAPI为每个AFU定义了两个MMIO区域:
+
+* 全局MMIO区域,保存和整个AFU相关的寄存器。
+* 每个进程的MMIO区域,对于每个上下文固定大小。
+
+
+
+AFU中断
+=======
+
+OpenCAPI拥有AFU向主机进程发送中断的可能性。它通过定义在传输层的“intrp_req”
+来完成,指定一个定义中断的64位对象句柄。
+
+驱动允许一个进程分配中断并获取可以传递给AFU的64位对象句柄。
+
+
+
+字符设备
+========
+
+驱动为每个在物理设备上发现的AFU创建一个字符设备。一个物理设备可能拥有多个
+函数,一个函数可以拥有多个AFU。不过编写这篇文档之时,只对导出一个AFU的设备
+测试过。
+
+字符设备可以在 /dev/ocxl/ 中被找到,其命名为:
+/dev/ocxl/<AFU 名称>.<位置>.<索引>
+
+<AFU 名称> 是一个最长20个字符的名称,和在AFU配置空间中找到的相同。
+<位置>由驱动添加,可在系统有不止一个相同的OpenCAPI设备时帮助区分设备。
+<索引>也是为了在少见情况下帮助区分AFU,即设备携带多个同样的AFU副本时。
+
+
+
+Sysfs类
+=======
+
+添加了代表AFU的ocxl类。查看/sys/class/ocxl。布局在
+Documentation/ABI/testing/sysfs-class-ocxl 中描述。
+
+
+
+用户API
+=======
+
+打开
+----
+
+基于在配置空间中找到的AFU定义,AFU可能支持在多个内存上下文中工作,这种情况
+下相关的字符设备可以被不同进程多次打开。
+
+
+ioctl
+-----
+
+OCXL_IOCTL_ATTACH:
+
+ 附加调用进程的内存上下文到AFU,以允许AFU访问其内存。
+
+OCXL_IOCTL_IRQ_ALLOC:
+
+ 分配AFU中断,返回标识符。
+
+OCXL_IOCTL_IRQ_FREE:
+
+ 释放之前分配的AFU中断。
+
+OCXL_IOCTL_IRQ_SET_FD:
+
+ 将一个事件文件描述符和AFU中断关联,因此用户进程可以在AFU发送中断时收到通
+ 知。
+
+OCXL_IOCTL_GET_METADATA:
+
+ 从卡中获取配置信息,比如内存映射IO区域的大小、AFU版本和当前上下文的进程
+ 地址空间ID(PASID)。
+
+OCXL_IOCTL_ENABLE_P9_WAIT:
+
+ 允许AFU唤醒执行“等待”的用户空间进程。返回信息给用户空间,允许其配置AFU。
+ 注意这只在POWER9上可用。
+
+OCXL_IOCTL_GET_FEATURES:
+
+ 报告用户空间可用的影响OpenCAPI的CPU特性。
+
+
+mmap
+----
+
+一个进程可以mmap每个进程的MMIO区域来和AFU交互。
diff --git a/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst b/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst
new file mode 100644
index 000000000000..d52c7052f101
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/ebpf/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+eBPF 用户空间API
+================
+
+eBPF是一种在Linux内核中提供沙箱化运行环境的机制,它可以在不改变内核源码或加载
+内核模块的情况下扩展运行时和编写工具。eBPF程序能够被附加到各种内核子系统中,包
+括网络,跟踪和Linux安全模块(LSM)等。
+
+关于eBPF的内部内核文档,请查看 Documentation/bpf/index.rst 。
+
+.. toctree::
+ :maxdepth: 1
+
+ syscall
diff --git a/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst b/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst
new file mode 100644
index 000000000000..47e2a59ae45d
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/ebpf/syscall.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+eBPF Syscall
+------------
+
+:作者:
+ - Alexei Starovoitov <ast@kernel.org>
+ - Joe Stringer <joe@wand.net.nz>
+ - Michael Kerrisk <mtk.manpages@gmail.com>
+
+bpf syscall的主要信息可以在 `man-pages`_ 中的 `bpf(2)`_ 找到。
+
+bpf() 子命令参考
+~~~~~~~~~~~~~~~~
+
+子命令在以下内核代码中:
+
+include/uapi/linux/bpf.h
+
+.. Links:
+.. _man-pages: https://www.kernel.org/doc/man-pages/
+.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html
diff --git a/Documentation/translations/zh_CN/userspace-api/futex2.rst b/Documentation/translations/zh_CN/userspace-api/futex2.rst
new file mode 100644
index 000000000000..04f9d62db1f7
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/futex2.rst
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/futex2.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+======
+futex2
+======
+
+:作者: André Almeida <andrealmeid@collabora.com>
+
+futex,或者称为快速用户互斥锁(fast user mutex),是一组允许用户空间创建高性能同步
+机制的系统调用,比如用户空间中的互斥锁,信号量和条件变量。C标准库,如glibc,使用它作
+为实现更多高级接口的方式,如pthreads。
+
+futex2是初代futex系统调用的后续版本,旨在克服原有接口的限制。
+
+用户API
+=======
+
+``futex_waitv()``
+-----------------
+
+等待一个futex数组,可由其中任意一个唤醒::
+
+ futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes,
+ unsigned int flags, struct timespec *timeout, clockid_t clockid)
+
+ struct futex_waitv {
+ __u64 val;
+ __u64 uaddr;
+ __u32 flags;
+ __u32 __reserved;
+ };
+
+用户空间设置一个struct futex_waitv数组(最多128项),设置 ``uaddr`` 为等待的
+地址, ``val`` 为期望值, ``flags`` 为指定的类型(如private)和futex的大小。
+``__reserved`` 需要置为0,但是它可用作未来扩展。指向数组第一个元素的指针作为
+``waiters`` 传递。如果 ``waiters`` 或任何的 ``uaddr`` 地址无效,将返回 ``-EFAULT`` 。
+
+如果用户空间拥有32位的指针,那么需要做显式转换来保证高位清零。 ``uintptr_t`` 设计
+得很精巧,在32/64位的指针上都正常工作。
+
+``nr_futexes`` 指定了数组的大小。不在[1,128]区间内的值会使系统调用返回 ``-EINVAL`` 。
+
+系统调用的 ``flags`` 参数需要置0,但可用作未来扩展。
+
+对于每个 ``waiters`` 数组中的项,在 ``uaddr`` 的当前值会和 ``val`` 比较。如果
+不一致,系统调用会撤销截至目前完成的所有工作,并返回 ``-EAGAIN`` 。如果所有测试
+和验证都通过,系统调用会等待直到以下情况之一发生:
+
+- 指定的timeout超时,返回 ``-ETIMEOUT`` 。
+- 一个信号被传递给睡眠中的任务,返回 ``-ERESTARTSYS`` 。
+- 某个列表中的futex被唤醒,返回那个被唤醒的futex的索引。
+
+关于如何使用接口的例子可以在 ``tools/testing/selftests/futex/functional/futex_waitv.c``
+中找到。
+
+超时
+----
+
+``struct timespec *timeout`` 是一个指向绝对超时时间的可选参数。你需要在 ``clockid``
+参数中指定要使用的时钟类型。支持 ``CLOCK_MONOTONIC`` 和 ``CLOCK_REALTIME`` 。这个
+系统调用只接受64位的timespec结构体。
+
+futex的类型
+-----------
+
+futex既可以是私有的也可以是共享的。私有用于多个进程共享同样的内存空间,并且futex的虚拟
+地址对所有进程都是一样的。这允许在内核中进行优化。要使用私有futex,需要在futex标志中指定
+``FUTEX_PRIVATE_FLAG`` 。对于那些不在同一内存空间共享的进程,可以让同一个futex拥有不同
+的虚拟地址(例如使用基于文件的共享内存),这需要不同的内部机制来使得正确进入队列。这是默认
+的行为,而且对私有futex和共享futex都适用。
+
+futex可以是不同的大小:8,16,32或64位。目前只支持32位大小的futex,并且需要通过 ``FUTEX_32``
+标志指定。
diff --git a/Documentation/translations/zh_CN/userspace-api/index.rst b/Documentation/translations/zh_CN/userspace-api/index.rst
new file mode 100644
index 000000000000..5dc0f2e69c17
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/index.rst
@@ -0,0 +1,50 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+=========================
+Linux 内核用户空间API指南
+=========================
+
+.. _man-pages: https://www.kernel.org/doc/man-pages/
+
+尽管许多用户空间API的文档被记录在别处(特别是在 man-pages_ 项目中),
+在代码树中仍然可以找到有关用户空间的部分信息。这个手册意在成为这些信息
+聚集的地方。
+
+.. class:: toc-title
+
+ 目录
+
+.. toctree::
+ :maxdepth: 2
+
+ no_new_privs
+ seccomp_filter
+ accelerators/ocxl
+ ebpf/index
+ sysfs-platform_profile
+ futex2
+
+TODOList:
+
+* landlock
+* unshare
+* spec_ctrl
+* ioctl/index
+* iommu
+* media/index
+* netlink/index
+* vduse
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst b/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst
new file mode 100644
index 000000000000..81bd16ce3ad2
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/no_new_privs.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+============
+无新权限标志
+============
+
+execve系统调用可以给一个新启动的程序授予它的父程序本没有的权限。最明显的两个
+例子就是setuid/setgid控制程序和文件的能力。为了避免父程序也获得这些权限,内
+核和用户代码必须小心避免任何父程序可以颠覆子程序的情况。比如:
+
+ - 程序在setuid后,动态装载器处理 ``LD_*`` 环境变量的不同方式。
+
+ - 对于非特权程序,chroot是不允许的,因为这会允许 ``/etc/passwd`` 在继承
+ chroot的程序眼中被替换。
+
+ - 执行代码对ptrace有特殊处理。
+
+这些都是临时性的修复。 ``no_new_privs`` 位(从 Linux 3.5 起)是一个新的通
+用的机制来保证一个进程安全地修改其执行环境并跨execve持久化。任何任务都可以设
+置 ``no_new_privs`` 。一旦该位被设置,它会在fork、clone和execve中继承下去
+,并且不能被撤销。在 ``no_new_privs`` 被设置的情况下, ``execve()`` 将保证
+不会授予权限去做任何没有execve调用就不能做的事情。比如, setuid 和 setgid
+位不会再改变 uid 或 gid;文件能力不会被添加到授权集合中,并且Linux安全模块(
+LSM)不会在execve调用后放松限制。
+
+设置 ``no_new_privs`` 使用::
+
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+不过要小心,Linux安全模块(LSM)也可能不会在 ``no_new_privs`` 模式下收紧约束。
+(这意味着一个一般的服务启动器在执行守护进程前就去设置 ``no_new_privs`` 可能
+会干扰基于LSM的沙箱。)
+
+请注意, ``no_new_privs`` 并不能阻止不涉及 ``execve()`` 的权限变化。一个拥有
+适当权限的任务仍然可以调用 ``setuid(2)`` 并接收 SCM_RIGHTS 数据报。
+
+目前来说, ``no_new_privs`` 有两大使用场景:
+
+ - 为seccomp模式2沙箱安装的过滤器会跨execve持久化,并能够改变新执行程序的行为。
+ 非特权用户因此在 ``no_new_privs`` 被设置的情况下只允许安装这样的过滤器。
+
+ - ``no_new_privs`` 本身就能被用于减少非特权用户的攻击面。如果所有以某个 uid
+ 运行的程序都设置了 ``no_new_privs`` ,那么那个 uid 将无法通过攻击 setuid,
+ setgid 和使用文件能力的二进制来提权;它需要先攻击一些没有被设置 ``no_new_privs``
+ 位的东西。
+
+将来,其他潜在的危险的内核特性可能被非特权任务利用,即使 ``no_new_privs`` 被置位。
+原则上,当 ``no_new_privs`` 被置位时, ``unshare(2)`` 和 ``clone(2)`` 的几个选
+项将是安全的,并且 ``no_new_privs`` 加上 ``chroot`` 是可以被认为比 chroot本身危
+险性小得多的。
diff --git a/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst b/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst
new file mode 100644
index 000000000000..ede8b37c953f
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst
@@ -0,0 +1,293 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/seccomp_filter.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+==================================
+Seccomp BPF (基于过滤器的安全计算)
+==================================
+
+*Seccomp: SECure COMPuting*
+
+介绍
+====
+
+大量系统调用被暴露给每个用户空间进程,但其中又有许多系统调用在进程的整个生命
+周期中都没被使用。随着系统调用的改变和成熟,缺陷被找到并消除。允许某一部分应
+用程序仅能访问一部分系统调用是有好处的,这会缩小内核暴露给应用程序的面积。
+系统调用过滤器就是为这些应用程序而生的。
+
+Seccomp过滤提供了一种为进程指定一个处理系统调用的过滤器的方法。这个过滤器体
+现为一个伯克利包过滤器(BPF)程序,就像套接字过滤器一样,不同在于前者处理的
+数据和正在进行的系统调用有关:系统调用号和系统调用参数。这样使用一种长期与
+用户空间和直接数据打交道的语言来表达系统调用过滤成为了可能。
+
+此外,BPF让seccomp用户不再成为在系统调用干预框架(system call interposition
+frameworks)中常见的检查-使用竞态攻击(TOCTOU)的受害者。BPF程序可能无法解引
+用指针,这就限制了所有过滤器仅能直接评估系统调用参数。
+
+这不是什么
+==========
+
+系统调用过滤并不是一个沙箱。它提供了一种明确定义的机制来最小化内核暴露面。它
+旨在成为一个沙箱开发者使用的工具。除此之外,逻辑行为和信息流的策略应该结合其他
+系统加固手段或者可能由你选择的内核安全模块(LSM)来管理。易于表达的动态过滤器
+为这条路提供了更多选择(比如避免病态的大小或者选择允许 socketcall() 中的多路
+系统调用),但将其理解为更完整的沙箱解决方案是错误的。
+
+用法
+====
+
+添加了一个额外的seccomp模式,它可以使用和严格seccomp相同的 prctl(2) 调用来启用。
+如果架构有 ``CONFIG_HAVE_ARCH_SECCOMP_FILTER`` 标志,那么可以添加以下过滤器:
+
+``PR_SET_SECCOMP``:
+ 现在需要添加一个额外的参数来指定使用BPF程序的新过滤器。
+ BPF程序将在反应系统调用号、参数和其他元数据的seccomp_data结构体之上执行。
+ BPF程序必须返回允许的值之一来告知内核应该采取什么行动。
+
+ 用法::
+
+ prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog);
+
+ 'prog' 参数是一个指向 sock_fprog 结构体的指针,其中包含了过滤器程序。如
+ 果程序是无效的,该调用会返回 -1 并设置 errno 为 ``EINVAL`` 。
+
+ 如果 ``fork`` / ``clone`` 和 ``execve`` 被 @prog 所允许,任何子进程都将
+ 受到和父进程相同的过滤器和系统调用ABI的约束。
+
+ 在调用之前,进程必须调用 ``prctl(PR_SET_NO_NEW_PRIVS, 1)`` 或者在它的
+ 命名空间内以 ``CAP_SYS_ADMIN`` 权限运行。如果以上条件不满足,会返回
+ ``-EACCES`` 。这一要求保证了过滤器程序不能用于比安装过滤器的进程拥有更高
+ 权限的子进程。
+
+ 另外,如果 ``prctl(2)`` 被安装的过滤器所允许,就可以叠加额外的过滤器。这会增
+ 加评估时间,但是可以进一步降低执行进程时的攻击面。
+
+以上调用在成功时返回0,失败时返回一个非零的值。
+
+返回值
+======
+
+一个seccomp过滤器可能返回下列任意值。如果多个过滤器存在,评估一个指定系统调用的
+返回值总会使用最高优先级的值。(比如 ``SECCOMP_RET_KILL_PROCESS`` 总是被优先
+返回。)
+
+按照优先级排序,它们是:
+
+``SECCOMP_RET_KILL_PROCESS``:
+ 使得整个进程立即结束而不执行系统调用。进程的退出状态 (``status & 0x7f``) 将
+ 是 ``SIGSYS`` ,而不是 ``SIGKILL`` 。
+
+``SECCOMP_RET_KILL_THREAD``:
+ 使得线程立即结束而不执行系统调用。线程的退出状态 (``status & 0x7f``) 将是
+ 是 ``SIGSYS`` ,而不是 ``SIGKILL`` 。
+
+``SECCOMP_RET_TRAP``:
+ 使得内核向触发进程发送一个 ``SIGSYS`` 信号而不执行系统调用。
+ ``siginfo->si_call_addr`` 会展示系统调用指令的位置, ``siginfo->si_syscall``
+ 和 ``siginfo->si_arch`` 会指出试图进行的系统调用。程序计数器会和发生了系统
+ 调用的一样(即它不会指向系统调用指令)。返回值寄存器会包含一个与架构相关的值——
+ 如果恢复执行,需要将其设为合理的值。(架构依赖性是因为将其替换为 ``-ENOSYS``
+ 会导致一些有用的信息被覆盖。)
+
+ 返回值的 ``SECCOMP_RET_DATA`` 部分会作为 ``si_errno`` 传递。
+
+ 由seccomp触发的 ``SIGSYS`` 会有一个 ``SYS_SECCOMP`` 的 si_code 。
+
+``SECCOMP_RET_ERRNO``:
+ 使得返回值的低16位作为errno传递给用户空间,而不执行系统调用。
+
+``SECCOMP_RET_USER_NOTIF``:
+ 使得一个 ``struct seccomp_notif`` 消息被发送到已附加的用户空间通知文件描述
+ 符。如果没有被附加则返回 ``-ENOSYS`` 。下面会讨论如何处理用户通知。
+
+``SECCOMP_RET_TRACE``:
+ 当返回的时候,这个值会使得内核在执行系统调用前尝试去通知一个基于 ``ptrace()``
+ 的追踪器。如果没有追踪器, ``-ENOSYS`` 会返回给用户空间,并且系统调用不会执行。
+
+ 如果追踪器通过 ``ptrace(PTRACE_SETOPTIONS)`` 请求了 ``PTRACE_O_TRACESECCOMP``,
+ 那么它会收到 ``PTRACE_EVENT_SECCOMP`` 通知。BPF程序返回值的 ``SECCOMP_RET_DATA``
+ 部分会通过 ``PTRACE_GETEVENTMSG`` 提供给追踪器。
+
+ 追踪器可以通过改变系统调用号到-1来跳过系统调用。或者追踪器可以改变系统调用号到
+ 一个有效值来改变请求的系统调用。如果追踪器请求跳过系统调用,那么系统调用将返回
+ 追踪器放在返回值寄存器中的值。
+
+ 在追踪器被通知后,seccomp检查不会再次运行。(这意味着基于seccomp的沙箱必须禁止
+ ptrace的使用,甚至其他沙箱进程也不行,除非非常小心;ptrace可以通过这个机制来逃
+ 逸。)
+
+``SECCOMP_RET_LOG``:
+ 使得系统调用在被记录之后再运行。这应该被应用开发者用来检查他们的程序需要哪些
+ 系统调用,而不需要反复通过多个测试和开发周期来建立清单。
+
+ 只有在 actions_logged sysctl 字符串中出现 "log" 时,这个操作才会被记录。
+
+``SECCOMP_RET_ALLOW``:
+ 使得系统调用被执行。
+
+如果多个追踪器存在,评估系统调用的返回值将永远使用最高优先级的值。
+
+优先级只通过 ``SECCOMP_RET_ACTION`` 掩码来决定。当多个过滤器返回相同优先级的返回
+值时,只有来自最近安装的过滤器的 ``SECCOMP_RET_DATA`` 会被返回。
+
+隐患
+====
+
+最需要避免的隐患是在过滤系统调用号时却不检查架构值。因为在任何支持多个系统调用
+约定的架构上,系统调用号可能根据具体调用而不同。如果不同调用约定中的调用号有重叠,
+那么过滤器的检查可能被滥用。请总是检查架构值!
+
+例子
+====
+
+``samples/seccomp/`` 文件夹包含了x86专用和更通用的使用高层宏接口来生成BPF程序的
+例子。
+
+用户空间通知
+============
+
+``SECCOMP_RET_USER_NOTIF`` 返回值会让seccomp过滤器传递一个特定的系统调用给用户
+空间处理。这可能会对像容器管理器的程序有用,它们希望拦截特定的系统调用(如 ``mount()``,
+``finit_module()`` 等等)并改变其行为。
+
+传递 ``SECCOMP_FILTER_FLAG_NEW_LISTENER`` 参数给 ``seccomp()`` 系统调用可以取
+得通知文件描述符:
+
+.. code-block:: c
+
+ fd = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog);
+
+成功情况下会返回一个对过滤器监听的文件描述符,然后可以通过 ``SCM_RIGHTS`` 或类似
+的方式传递。需要注意的是,过滤器文件描述符针对的是一个特定的过滤器而不是特定的进程。
+所以如果这个进程后来fork了,来自两个进程的通知都会出现在同一个过滤器文件描述符中。
+对于过滤器文件描述符的读写也是同步的,所以一个过滤器文件描述符可以安全地拥有多个读者。
+
+seccomp通知文件描述符由两个结构体组成:
+
+.. code-block:: c
+
+ struct seccomp_notif_sizes {
+ __u16 seccomp_notif;
+ __u16 seccomp_notif_resp;
+ __u16 seccomp_data;
+ };
+
+ struct seccomp_notif {
+ __u64 id;
+ __u32 pid;
+ __u32 flags;
+ struct seccomp_data data;
+ };
+
+ struct seccomp_notif_resp {
+ __u64 id;
+ __s64 val;
+ __s32 error;
+ __u32 flags;
+ };
+
+``struct seccomp_notif_sizes`` 结构体可以用于确定seccomp通知中各种结构体的大小。
+``struct seccomp_data`` 的大小可能未来会改变,所以需要使用下面的代码:
+
+.. code-block:: c
+
+ struct seccomp_notif_sizes sizes;
+ seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes);
+
+来决定需要分配的多种结构体的大小。请查看 samples/seccomp/user-trap.c 中的例子。
+
+用户可以通过 ``ioctl(SECCOMP_IOCTL_NOTIF_RECV)`` (或 ``poll()``) 读取seccomp
+通知文件描述符来接收一个 ``struct seccomp_notif`` ,其中包含五个成员:结构体的
+输入长度,每个过滤器唯一的 ``id`` , 触发请求进程的 ``pid`` (如果进程的pid命名空
+间对于监听者的pid命名空间不可见的话,可能为0)。通知还包含传递给seccomp的 ``data``
+和一个过滤器标志。在调用ioctl前结构体应该被清空。
+
+之后用户空间可以根据这些信息决定做什么,并通过 ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)``
+发送一个响应,表示应该给用户空间返回什么。 ``struct seccomp_notif_resp`` 的 ``id``
+成员应该和 ``struct seccomp_notif`` 的 ``id`` 一致。
+
+用户空间也可以通过 ``ioctl(SECCOMP_IOCTL_NOTIF_ADDFD)`` 向通知进程添加文件描述
+符。 ``struct seccomp_notif_addfd`` 的 ``id`` 成员应该和 ``struct seccomp_notif``
+的 ``id`` 保持一致。 ``newfd_flags`` 标志可以被用于在通知进程的文件描述符上设置
+O_CLOEXEC 等标志。如果监督者(supervisor)向文件描述符注入一个特定的数字,可以使用
+``SECCOMP_ADDFD_FLAG_SETFD`` 标志,并设置 ``newfd`` 成员为要使用的特定数字。
+如果文件描述符已经在通知进程中打开,那它将被替换。监督者也可以添加一个文件描述符,
+并使用 ``SECCOMP_ADDFD_FLAG_SEND`` 标志原子响应,返回值将是注入的文件描述符编号。
+
+通知进程可以被抢占,导致通知被终止。这可能在尝试代表通知进程执行长时间且通常可重试
+(如挂载文件系统)的操作时导致问题。另外,在安装过滤器的时候,
+``SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV`` 可以被设置。这个标志使得当监督者收到用
+户通知时,通知进程会忽略非致命信号,直到响应被发送。在用户空间收到通知之前发出的信号
+将被正常处理。
+
+值得注意的是, ``struct seccomp_data`` 包含了系统调用寄存器参数的值,但是不包含指向
+内存的指针。进程的内存可以通过 ``ptrace()`` 或 ``/proc/pid/mem`` 由合适的特权跟踪
+访问。但是,需要注意避免之前提到的TOCTOU攻击:所有从被跟踪者内存中读到的参数都应该先
+读到追踪器的内存中,再做出策略决定。这样就可以对系统调用的参数做原子决定。
+
+Sysctls
+=======
+
+Seccomp的sysctl文件可以在 ``/proc/sys/kernel/seccomp/`` 文件夹中找到。这里有对文件
+夹中每个文件的描述:
+
+``actions_avail``:
+ 以字符串形式保存seccomp返回值(参考上文的 ``SECCOMP_RET_*`` 宏)的只读有序
+ 列表。从左往右按照最少许可返回值到最多许可返回值排序。
+
+ 这个列表代表了内核支持的seccomp返回值集合。一个用户空间程序可以使用这个列表来在
+ 程序建立时确定在 ``seccomp.h`` 中找到的动作是否和当前运行内核实际支持的动作有所
+ 不同。
+
+``actions_logged``:
+ 允许被记录的seccomp返回值(参考上文的 ``SECCOMP_RET_*`` 宏)的可读写有序列表。
+ 对文件写入不需要是有序的,但从文件读取将采用与actions_avail sysctl一致的方式排序。
+
+ ``allow`` 字符串在 ``actions_logged`` sysctl中不被接收,因为不可能记录
+ ``SECCOMP_RET_ALLOW`` 动作。尝试向sysctl写入 ``allow`` 会导致返回一个EINVAL。
+
+添加架构支持
+============
+
+请查看 ``arch/Kconfig`` 了解权威要求。总的来说如果一个架构同时支持ptrace_event和
+seccomp,那么它将可以通过较小的修改支持seccomp过滤器: ``SIGSYS`` 支持和seccomp
+返回值检查。然后必须将 ``CONFIG_HAVE_ARCH_SECCOMP_FILTER`` 添加到它的架构特定
+的Kconfig中。
+
+注意事项
+========
+
+vDSO可能导致一些系统调用完全在用户空间中运行,当你在不同机器上跑程序时可能导致回退
+到真正系统调用的意外发生。为了在x86上最小化这些意外的发生,请确保你在测试时把
+``/sys/devices/system/clocksource/clocksource0/current_clocksource`` 设置为
+``acpi_pm`` 之类的值。
+
+在x86-64上,vsyscall模拟默认开启。(vsyscalls是vDSO调用的传统变体。)目前,模拟
+vsyscalls会遵守seccomp,但是有一些奇怪情况:
+
+- ``SECCOMP_RET_TRAP`` 的返回值会设置一个指向给定vsyscall入口的 ``si_call_addr``,
+ 而不是'syscall'指令之后的地址。任何想重新开始调用的代码都需要注意 (a) ret指令
+ 已被模拟,(b) 试图恢复系统调用将再次触发标准vsyscall模拟安全检查,使得恢复系统
+ 调用在大部分情况下没有意义。
+
+- ``SECCOMP_RET_TRACE`` 的返回值将像往常一样给追踪器发出信号,但是系统调用可能不能
+ 使用orig_rax寄存器改变为另一个系统调用。可能只能改变为-1来跳过当前模拟的调用。
+ 任何其他改变都可能终止进程。追踪器看到的rip值将是系统调用的入口地址;这和正常行为
+ 不同。追踪器禁止修改rip或者rsp。(不要依赖其他改变来终止进程,它们可能正常工作。
+ 比如在一些内核中,选择一个只存在于未来内核中的系统调用将被正确模拟,返回一个
+ ``-ENOSYS`` 。)
+
+要检测这个古怪的行为,可以检查 ``addr & ~0x0C00 == 0xFFFFFFFFFF600000``。(对于
+``SECCOMP_RET_TRACE`` ,使用rip。对于 ``SECCOMP_RET_TRAP`` ,使用
+``siginfo->si_call_addr`` 。)不要检测其他条件:未来内核可能会改进vsyscall模拟,
+当前内核在vsyscall=native模式下会有不同表现,但在这些情况下, ``0xF...F600{0,4,8,C}00``
+处的指令将不是系统调用。
+
+请注意,现代系统根本不可能使用vsyscalls —— 它们是一种遗留功能,而且比标准系统调用
+慢得多。 新的代码将使用vDSO,而vDSO发出的系统调用与正常的系统调用没有区别。
diff --git a/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst b/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst
new file mode 100644
index 000000000000..7d21740db125
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst
@@ -0,0 +1,40 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/sysfs-platform_profile.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+==========================================================
+平台配置文件选择(如 /sys/firmware/acpi/platform_profile)
+==========================================================
+
+现代系统中平台性能、温度、风扇和其他硬件相关的特性通常是可以动态配置的。平台
+配置通常会根据当前的状态由一些自动机制(很可能存在于内核之外)来自动调整。
+
+这些平台自动调整机制通常能够被配置成多个平台配置文件中的一个,要么偏向节能运
+行,要么偏向性能运行。
+
+platform_profile属性的目的是提供一个通用的sysfs API来选择这些平台自动配置
+机制的配置文件。
+
+需要注意的是,这个API只能用作选择平台配置文件,用来监测所产生的性能特征并不
+是其目标。监测性能最好使用设备/供应商提供的工具,比如turbostat。
+
+具体来说,当选择高性能配置文件时,真实能达到的性能可能受制于多种因素,比如:
+其他组件的发热,房间温度,笔记本底部的自由空气流动等。让用户空间知道任何阻碍
+达到要求性能水平的局部最优条件,显然不是这个API的目标。
+
+由于数字本身并不能代表一个配置文件会调整的多个变量(功耗,发热等),这个API
+使用字符串来描述多种配置文件。为了保证用户空间能够获得一致的体验,
+sysfs-platform_profile ABI 文档定义了一个固定的配置文件名集合。驱动程序
+*必须* 将它们内置的配置文件表示映射到这个固定的集合中。
+
+如果映射时没有很好的匹配,可以添加一个新的配置文件名称。驱动希望引入的新配置
+文件名称时必须:
+
+ 1. 解释为什么无法使用已有的配置文件名称。
+ 2. 添加一个新的配置文件名称,以及预期行为的清晰描述,保存到
+ sysfs-platform_profile ABI文档中。
diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS
index 67c59cdc9959..81ea3eb29e96 100644
--- a/Documentation/usb/CREDITS
+++ b/Documentation/usb/CREDITS
@@ -1,7 +1,7 @@
Credits for the Simple Linux USB Driver:
The following people have contributed to this code (in alphabetical
-order by last name). I'm sure this list should be longer, its
+order by last name). I'm sure this list should be longer, it's
difficult to maintain, add yourself with a patch if desired.
Georg Acher <acher@informatik.tu-muenchen.de>
@@ -126,7 +126,7 @@ THANKS file in Inaky's driver):
- Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
pointing out mortal bugs and giving advice.
- - Edmund Humemberger <ed@atnet.at>, for it's great work on
+ - Edmund Humemberger <ed@atnet.at>, for his great work on
public relationships and general management stuff for the
Linux-USB effort.
@@ -136,7 +136,7 @@ THANKS file in Inaky's driver):
- Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
introductory documents (competing with Alberto's :).
- - Christian Groessler <cpg@aladdin.de>, for it's help on those
+ - Christian Groessler <cpg@aladdin.de>, for his help on those
itchy bits ... :)
- Paul MacKerras for polishing OHCI and pushing me harder for
diff --git a/Documentation/usb/functionfs.rst b/Documentation/usb/functionfs.rst
index 7fdc6d840ac5..a3054bea38f3 100644
--- a/Documentation/usb/functionfs.rst
+++ b/Documentation/usb/functionfs.rst
@@ -49,7 +49,7 @@ level it would look like this::
$ ( cd /dev/ffs-hid && hid-daemon ) &
On kernel level the gadget checks ffs_data->dev_name to identify
-whether it's FunctionFS designed for MTP ("mtp") or HID ("hid").
+whether its FunctionFS is designed for MTP ("mtp") or HID ("hid").
If no "functions" module parameters is supplied, the driver accepts
just one function with any name.
diff --git a/Documentation/usb/gadget_multi.rst b/Documentation/usb/gadget_multi.rst
index 3a22c1b2f39e..f78a51ff2324 100644
--- a/Documentation/usb/gadget_multi.rst
+++ b/Documentation/usb/gadget_multi.rst
@@ -9,7 +9,7 @@ The Multifunction Composite Gadget (or g_multi) is a composite gadget
that makes extensive use of the composite framework to provide
a... multifunction gadget.
-In it's standard configuration it provides a single USB configuration
+In its standard configuration it provides a single USB configuration
with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
USB Mass Storage functions.
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index cec780c2f497..d8cd8cd9ce25 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
-:Date: September 2022
+:Date: October 2022
The goal of Landlock is to enable to restrict ambient rights (e.g. global
filesystem access) for a set of processes. Because Landlock is a stackable
@@ -60,7 +60,8 @@ the need to be explicit about the denied-by-default access rights.
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
- LANDLOCK_ACCESS_FS_REFER,
+ LANDLOCK_ACCESS_FS_REFER |
+ LANDLOCK_ACCESS_FS_TRUNCATE,
};
Because we may not know on which kernel version an application will be
@@ -69,16 +70,28 @@ should try to protect users as much as possible whatever the kernel they are
using. To avoid binary enforcement (i.e. either all security features or
none), we can leverage a dedicated Landlock command to get the current version
of the Landlock ABI and adapt the handled accesses. Let's check if we should
-remove the ``LANDLOCK_ACCESS_FS_REFER`` access right which is only supported
-starting with the second version of the ABI.
+remove the ``LANDLOCK_ACCESS_FS_REFER`` or ``LANDLOCK_ACCESS_FS_TRUNCATE``
+access rights, which are only supported starting with the second and third
+version of the ABI.
.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
- if (abi < 2) {
+ if (abi < 0) {
+ /* Degrades gracefully if Landlock is not handled. */
+ perror("The running kernel does not enable to use Landlock");
+ return 0;
+ }
+ switch (abi) {
+ case 1:
+ /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
+ __attribute__((fallthrough));
+ case 2:
+ /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
+ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
}
This enables to create an inclusive ruleset that will contain our rules.
@@ -127,8 +140,8 @@ descriptor.
It may also be required to create rules following the same logic as explained
for the ruleset creation, by filtering access rights according to the Landlock
-ABI version. In this example, this is not required because
-``LANDLOCK_ACCESS_FS_REFER`` is not allowed by any rule.
+ABI version. In this example, this is not required because all of the requested
+``allowed_access`` rights are already available in ABI 1.
We now have a ruleset with one rule allowing read access to ``/usr`` while
denying all other handled accesses for the filesystem. The next step is to
@@ -252,6 +265,37 @@ To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target
process, a sandboxed process should have a subset of the target process rules,
which means the tracee must be in a sub-domain of the tracer.
+Truncating files
+----------------
+
+The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and
+``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and sometimes
+overlap in non-intuitive ways. It is recommended to always specify both of
+these together.
+
+A particularly surprising example is :manpage:`creat(2)`. The name suggests
+that this system call requires the rights to create and write files. However,
+it also requires the truncate right if an existing file under the same name is
+already present.
+
+It should also be noted that truncating files does not require the
+``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)`
+system call, this can also be done through :manpage:`open(2)` with the flags
+``O_RDONLY | O_TRUNC``.
+
+When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE``
+right is associated with the newly created file descriptor and will be used for
+subsequent truncation attempts using :manpage:`ftruncate(2)`. The behavior is
+similar to opening a file for reading or writing, where permissions are checked
+during :manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and
+:manpage:`write(2)` calls.
+
+As a consequence, it is possible to have multiple open file descriptors for the
+same file, where one grants the right to truncate the file and the other does
+not. It is also possible to pass such file descriptors between processes,
+keeping their Landlock properties, even when these processes do not have an
+enforced Landlock ruleset.
+
Compatibility
=============
@@ -398,6 +442,15 @@ Starting with the Landlock ABI version 2, it is now possible to securely
control renaming and linking thanks to the new ``LANDLOCK_ACCESS_FS_REFER``
access right.
+File truncation (ABI < 3)
+-------------------------
+
+File truncation could not be denied before the third Landlock ABI, so it is
+always allowed when using a kernel that only supports the first or second ABI.
+
+Starting with the Landlock ABI version 3, it is now possible to securely control
+truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right.
+
.. _kernel_support:
Kernel support
diff --git a/Documentation/userspace-api/media/Makefile b/Documentation/userspace-api/media/Makefile
index 00922aa7efde..3d8aaf5c253b 100644
--- a/Documentation/userspace-api/media/Makefile
+++ b/Documentation/userspace-api/media/Makefile
@@ -47,10 +47,11 @@ $(BUILDDIR)/lirc.h.rst: ${UAPI}/lirc.h ${PARSER} $(SRC_DIR)/lirc.h.rst.exception
# Media build rules
-.PHONY: all html epub xml latex
+.PHONY: all html texinfo epub xml latex
all: $(IMGDOT) $(BUILDDIR) ${TARGETS}
html: all
+texinfo: all
epub: all
xml: all
latex: $(IMGPDF) all
diff --git a/Documentation/userspace-api/media/cec/cec-pin-error-inj.rst b/Documentation/userspace-api/media/cec/cec-pin-error-inj.rst
index b0efce40471f..411d42a742f3 100644
--- a/Documentation/userspace-api/media/cec/cec-pin-error-inj.rst
+++ b/Documentation/userspace-api/media/cec/cec-pin-error-inj.rst
@@ -1,5 +1,7 @@
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. _cec_pin_error_inj:
+
CEC Pin Framework Error Injection
=================================
diff --git a/Documentation/userspace-api/media/drivers/aspeed-video.rst b/Documentation/userspace-api/media/drivers/aspeed-video.rst
new file mode 100644
index 000000000000..1b0cb1e3eba8
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/aspeed-video.rst
@@ -0,0 +1,65 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: <isonum.txt>
+
+ASPEED video driver
+===================
+
+ASPEED Video Engine found on AST2400/2500/2600 SoC supports high performance
+video compressions with a wide range of video quality and compression ratio
+options. The adopted compressing algorithm is a modified JPEG algorithm.
+
+There are 2 types of compressions in this IP.
+
+* JPEG JFIF standard mode: for single frame and management compression
+* ASPEED proprietary mode: for multi-frame and differential compression.
+ Support 2-pass (high quality) video compression scheme (Patent pending by
+ ASPEED). Provide visually lossless video compression quality or to reduce
+ the network average loading under intranet KVM applications.
+
+VIDIOC_S_FMT can be used to choose which format you want. V4L2_PIX_FMT_JPEG
+stands for JPEG JFIF standard mode; V4L2_PIX_FMT_AJPG stands for ASPEED
+proprietary mode.
+
+More details on the ASPEED video hardware operations can be found in
+*chapter 6.2.16 KVM Video Driver* of SDK_User_Guide which available on
+AspeedTech-BMC/openbmc/releases.
+
+The ASPEED video driver implements the following driver-specific control:
+
+``V4L2_CID_ASPEED_HQ_MODE``
+---------------------------
+ Enable/Disable ASPEED's High quality mode. This is a private control
+ that can be used to enable high quality for aspeed proprietary mode.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - ``(0)``
+ - ASPEED HQ mode is disabled.
+ * - ``(1)``
+ - ASPEED HQ mode is enabled.
+
+``V4L2_CID_ASPEED_HQ_JPEG_QUALITY``
+-----------------------------------
+ Define the quality of ASPEED's High quality mode. This is a private control
+ that can be used to decide compression quality if High quality mode enabled
+ . Higher the value, better the quality and bigger the size.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - ``(1)``
+ - minimum
+ * - ``(12)``
+ - maximum
+ * - ``(1)``
+ - step
+ * - ``(1)``
+ - default
+
+**Copyright** |copy| 2022 ASPEED Technology Inc.
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 32f82aed47d9..915dbf0f4db5 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -31,6 +31,7 @@ For more details see the file COPYING in the source distribution of Linux.
:maxdepth: 5
:numbered:
+ aspeed-video
ccs
cx2341x-uapi
dw100
@@ -38,4 +39,5 @@ For more details see the file COPYING in the source distribution of Linux.
max2175
meye-uapi
omap3isp-uapi
+ st-vgxy61
uvcvideo
diff --git a/Documentation/userspace-api/media/drivers/st-vgxy61.rst b/Documentation/userspace-api/media/drivers/st-vgxy61.rst
new file mode 100644
index 000000000000..d9e3b80e3a96
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/st-vgxy61.rst
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+ST VGXY61 camera sensor driver
+==============================
+
+The ST VGXY61 driver implements the following controls:
+
+``V4L2_CID_HDR_SENSOR_MODE``
+-------------------------------
+ Change the sensor HDR mode. A HDR picture is obtained by merging two
+ captures of the same scene using two different exposure periods.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - HDR linearize
+ - The merger outputs a long exposure capture as long as it is not
+ saturated.
+ * - HDR substraction
+ - This involves subtracting the short exposure frame from the long
+ exposure frame.
+ * - No HDR
+ - This mode is used for standard dynamic range (SDR) exposures.
diff --git a/Documentation/userspace-api/media/dvb/fe_property_parameters.rst b/Documentation/userspace-api/media/dvb/fe_property_parameters.rst
index ecd84a8790a2..1717a0565fe8 100644
--- a/Documentation/userspace-api/media/dvb/fe_property_parameters.rst
+++ b/Documentation/userspace-api/media/dvb/fe_property_parameters.rst
@@ -89,16 +89,21 @@ ATSC (version 1) 8-VSB and 16-VSB.
DMTB 4-QAM, 16-QAM, 32-QAM, 64-QAM and 4-QAM-NR.
DVB-C Annex A/C 16-QAM, 32-QAM, 64-QAM and 256-QAM.
DVB-C Annex B 64-QAM.
+DVB-C2 QPSK, 16-QAM, 64-QAM, 256-QAM, 1024-QAM and 4096-QAM.
DVB-T QPSK, 16-QAM and 64-QAM.
DVB-T2 QPSK, 16-QAM, 64-QAM and 256-QAM.
DVB-S No need to set. It supports only QPSK.
DVB-S2 QPSK, 8-PSK, 16-APSK and 32-APSK.
+DVB-S2X 8-APSK-L, 16-APSK-L, 32-APSK-L, 64-APSK and 64-APSK-L.
ISDB-T QPSK, DQPSK, 16-QAM and 64-QAM.
ISDB-S 8-PSK, QPSK and BPSK.
======================= =======================================================
.. note::
+ As DVB-S2X specifies extensions to the DVB-S2 standard, the same
+ delivery system enum value is used (SYS_DVBS2).
+
Please notice that some of the above modulation types may not be
defined currently at the Kernel. The reason is simple: no driver
needed such definition yet.
@@ -854,9 +859,10 @@ The acceptable values are defined by :c:type:`fe_guard_interval`.
#. If ``DTV_GUARD_INTERVAL`` is set the ``GUARD_INTERVAL_AUTO`` the
hardware will try to find the correct guard interval (if capable) and
will use TMCC to fill in the missing parameters.
- #. Intervals ``GUARD_INTERVAL_1_128``, ``GUARD_INTERVAL_19_128``
- and ``GUARD_INTERVAL_19_256`` are used only for DVB-T2 at
- present.
+ #. Interval ``GUARD_INTERVAL_1_64`` is used only for DVB-C2.
+ #. Interval ``GUARD_INTERVAL_1_128`` is used for both DVB-C2 and DVB_T2.
+ #. Intervals ``GUARD_INTERVAL_19_128`` and ``GUARD_INTERVAL_19_256`` are
+ used only for DVB-T2.
#. Intervals ``GUARD_INTERVAL_PN420``, ``GUARD_INTERVAL_PN595`` and
``GUARD_INTERVAL_PN945`` are used only for DMTB at the present.
On such standard, only those intervals and ``GUARD_INTERVAL_AUTO``
@@ -916,14 +922,15 @@ The acceptable values are defined by :c:type:`fe_hierarchy`.
DTV_STREAM_ID
=============
-Used on DVB-S2, DVB-T2 and ISDB-S.
+Used on DVB-C2, DVB-S2, DVB-T2 and ISDB-S.
-DVB-S2, DVB-T2 and ISDB-S support the transmission of several streams on
-a single transport stream. This property enables the digital TV driver to
-handle substream filtering, when supported by the hardware. By default,
-substream filtering is disabled.
+DVB-C2, DVB-S2, DVB-T2 and ISDB-S support the transmission of several
+streams on a single transport stream. This property enables the digital
+TV driver to handle substream filtering, when supported by the hardware.
+By default, substream filtering is disabled.
-For DVB-S2 and DVB-T2, the valid substream id range is from 0 to 255.
+For DVB-C2, DVB-S2 and DVB-T2, the valid substream id range is from 0 to
+255.
For ISDB, the valid substream id range is from 1 to 65535.
diff --git a/Documentation/userspace-api/media/frontend.h.rst.exceptions b/Documentation/userspace-api/media/frontend.h.rst.exceptions
index 6283702c08c8..8b73fee11a79 100644
--- a/Documentation/userspace-api/media/frontend.h.rst.exceptions
+++ b/Documentation/userspace-api/media/frontend.h.rst.exceptions
@@ -86,6 +86,13 @@ ignore symbol APSK_16
ignore symbol APSK_32
ignore symbol DQPSK
ignore symbol QAM_4_NR
+ignore symbol QAM_1024
+ignore symbol QAM_4096
+ignore symbol APSK_8_L
+ignore symbol APSK_16_L
+ignore symbol APSK_32_L
+ignore symbol APSK_64
+ignore symbol APSK_64_L
ignore symbol SEC_VOLTAGE_13
ignore symbol SEC_VOLTAGE_18
@@ -119,6 +126,22 @@ ignore symbol FEC_AUTO
ignore symbol FEC_3_5
ignore symbol FEC_9_10
ignore symbol FEC_2_5
+ignore symbol FEC_1_3
+ignore symbol FEC_1_4
+ignore symbol FEC_5_9
+ignore symbol FEC_7_9
+ignore symbol FEC_8_15
+ignore symbol FEC_11_15
+ignore symbol FEC_13_18
+ignore symbol FEC_9_20
+ignore symbol FEC_11_20
+ignore symbol FEC_23_36
+ignore symbol FEC_25_36
+ignore symbol FEC_13_45
+ignore symbol FEC_26_45
+ignore symbol FEC_28_45
+ignore symbol FEC_32_45
+ignore symbol FEC_77_90
ignore symbol TRANSMISSION_MODE_AUTO
ignore symbol TRANSMISSION_MODE_1K
@@ -143,6 +166,7 @@ ignore symbol GUARD_INTERVAL_19_256
ignore symbol GUARD_INTERVAL_PN420
ignore symbol GUARD_INTERVAL_PN595
ignore symbol GUARD_INTERVAL_PN945
+ignore symbol GUARD_INTERVAL_1_64
ignore symbol HIERARCHY_NONE
ignore symbol HIERARCHY_AUTO
@@ -163,6 +187,9 @@ ignore symbol ROLLOFF_35
ignore symbol ROLLOFF_20
ignore symbol ROLLOFF_25
ignore symbol ROLLOFF_AUTO
+ignore symbol ROLLOFF_15
+ignore symbol ROLLOFF_10
+ignore symbol ROLLOFF_5
ignore symbol INVERSION_ON
ignore symbol INVERSION_OFF
@@ -187,6 +214,7 @@ ignore symbol SYS_DAB
ignore symbol SYS_DSS
ignore symbol SYS_CMMB
ignore symbol SYS_DVBH
+ignore symbol SYS_DVBC2
ignore symbol ATSCMH_SCCC_BLK_SEP
ignore symbol ATSCMH_SCCC_BLK_COMB
diff --git a/Documentation/userspace-api/media/v4l/buffer.rst b/Documentation/userspace-api/media/v4l/buffer.rst
index 4638ec64db00..04dec3e570ed 100644
--- a/Documentation/userspace-api/media/v4l/buffer.rst
+++ b/Documentation/userspace-api/media/v4l/buffer.rst
@@ -187,10 +187,8 @@ struct v4l2_buffer
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 ``type`` 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 ``bytesused`` will be set to the
- size of the buffer (see the ``length`` field of this struct) by
- the driver. For multiplanar formats this field is ignored and the
+ when it refers to an output stream. For multiplanar formats this field
+ is ignored and the
``planes`` pointer is used instead.
* - __u32
- ``flags``
@@ -327,10 +325,7 @@ struct v4l2_plane
- ``bytesused``
- The number of bytes occupied by data in the plane (its payload).
Drivers must set this field when ``type`` 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
- ``bytesused`` will be set to the size of the plane (see the
- ``length`` field of this struct) by the driver.
+ stream, applications when it refers to an output stream.
.. note::
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst
index 4c5061aa9cd4..daa4f40869f8 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst
@@ -661,3 +661,11 @@ enum v4l2_scene_mode -
.. [#f1]
This control may be changed to a menu control in the future, if more
options are required.
+
+``V4L2_CID_HDR_SENSOR_MODE (menu)``
+ Change the sensor HDR mode. A HDR picture is obtained by merging two
+ captures of the same scene using two different exposure periods. HDR mode
+ describes the way these two captures are merged in the sensor.
+
+ As modes differ for each sensor, menu items are not standardized by this
+ control and are left to the programmer.
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
index 0ff68cd8cf62..73cd99828010 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
@@ -258,6 +258,23 @@ please make a proposal on the linux-media mailing list.
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video.
+ * .. _V4L2-PIX-FMT-AJPG:
+
+ - ``V4L2_PIX_FMT_AJPG``
+ - 'AJPG'
+ - ASPEED JPEG format used by the aspeed-video driver on Aspeed platforms,
+ which is generally adapted for remote KVM.
+ On each frame compression, I will compare the new frame with previous
+ one to decide which macroblock's data is changed, and only the changed
+ macroblocks will be compressed.
+
+ The implementation is based on AST2600 A3 datasheet, revision 0.9, which
+ is not publicly available. Or you can reference Video stream data format
+ – ASPEED mode compression of SDK_User_Guide which available on
+ AspeedTech-BMC/openbmc/releases.
+
+ Decoder's implementation can be found here,
+ `aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
.. raw:: latex
\normalsize
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
index 10b1feeb0b57..f1d5bb7b806d 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
@@ -273,7 +273,9 @@ of the luma plane.
.. _V4L2-PIX-FMT-NV12-16L16:
.. _V4L2-PIX-FMT-NV12-32L32:
.. _V4L2-PIX-FMT-NV12M-8L128:
+.. _V4L2-PIX-FMT-NV12-8L128:
.. _V4L2-PIX-FMT-NV12M-10BE-8L128:
+.. _V4L2-PIX-FMT-NV12-10BE-8L128:
.. _V4L2-PIX-FMT-MM21:
Tiled NV12
@@ -319,6 +321,9 @@ pixels in 2D 8x128 tiles, and stores tiles linearly in memory.
The image height must be aligned to a multiple of 128.
The layouts of the luma and chroma planes are identical.
+``V4L2_PIX_FMT_NV12_8L128`` is similar to ``V4L2_PIX_FMT_NV12M_8L128`` but stores
+two planes in one memory.
+
``V4L2_PIX_FMT_NV12M_10BE_8L128`` is similar to ``V4L2_PIX_FMT_NV12M`` but stores
10 bits pixels in 2D 8x128 tiles, and stores tiles linearly in memory.
the data is arranged in big endian order.
@@ -334,6 +339,9 @@ byte 2: Y1(bits 3-0) Y2(bits 9-6)
byte 3: Y2(bits 5-0) Y3(bits 9-8)
byte 4: Y3(bits 7-0)
+``V4L2_PIX_FMT_NV12_10BE_8L128`` is similar to ``V4L2_PIX_FMT_NV12M_10BE_8L128`` but stores
+two planes in one memory.
+
``V4L2_PIX_FMT_MM21`` store luma pixel in 16x32 tiles, and chroma pixels
in 16x16 tiles. The line stride must be aligned to a multiple of 16 and the
image height must be aligned to a multiple of 32. The number of luma and chroma
diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst
index d21d532eee15..16ef3b41932e 100644
--- a/Documentation/userspace-api/media/v4l/subdev-formats.rst
+++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst
@@ -6057,6 +6057,43 @@ the following codes.
- y\ :sub:`2`
- y\ :sub:`1`
- y\ :sub:`0`
+ * .. _MEDIA-BUS-FMT-Y16-1X16:
+
+ - MEDIA_BUS_FMT_Y16_1X16
+ - 0x202e
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ - y\ :sub:`15`
+ - y\ :sub:`14`
+ - y\ :sub:`13`
+ - y\ :sub:`12`
+ - y\ :sub:`11`
+ - y\ :sub:`10`
+ - y\ :sub:`9`
+ - y\ :sub:`8`
+ - y\ :sub:`7`
+ - y\ :sub:`6`
+ - y\ :sub:`5`
+ - y\ :sub:`4`
+ - y\ :sub:`3`
+ - y\ :sub:`2`
+ - y\ :sub:`1`
+ - y\ :sub:`0`
* .. _MEDIA-BUS-FMT-UYVY8-1X16:
- MEDIA_BUS_FMT_UYVY8_1X16
diff --git a/Documentation/virt/coco/tdx-guest.rst b/Documentation/virt/coco/tdx-guest.rst
new file mode 100644
index 000000000000..46e316db6bb4
--- /dev/null
+++ b/Documentation/virt/coco/tdx-guest.rst
@@ -0,0 +1,52 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================================================
+TDX Guest API Documentation
+===================================================================
+
+1. General description
+======================
+
+The TDX guest driver exposes IOCTL interfaces via the /dev/tdx-guest misc
+device to allow userspace to get certain TDX guest-specific details.
+
+2. API description
+==================
+
+In this section, for each supported IOCTL, the following information is
+provided along with a generic description.
+
+:Input parameters: Parameters passed to the IOCTL and related details.
+:Output: Details about output data and return value (with details about
+ the non common error values).
+
+2.1 TDX_CMD_GET_REPORT0
+-----------------------
+
+:Input parameters: struct tdx_report_req
+:Output: Upon successful execution, TDREPORT data is copied to
+ tdx_report_req.tdreport and return 0. Return -EINVAL for invalid
+ operands, -EIO on TDCALL failure or standard error number on other
+ common failures.
+
+The TDX_CMD_GET_REPORT0 IOCTL can be used by the attestation software to get
+the TDREPORT0 (a.k.a. TDREPORT subtype 0) from the TDX module using
+TDCALL[TDG.MR.REPORT].
+
+A subtype index is added at the end of this IOCTL CMD to uniquely identify the
+subtype-specific TDREPORT request. Although the subtype option is mentioned in
+the TDX Module v1.0 specification, section titled "TDG.MR.REPORT", it is not
+currently used, and it expects this value to be 0. So to keep the IOCTL
+implementation simple, the subtype option was not included as part of the input
+ABI. However, in the future, if the TDX Module supports more than one subtype,
+a new IOCTL CMD will be created to handle it. To keep the IOCTL naming
+consistent, a subtype index is added as part of the IOCTL CMD.
+
+Reference
+---------
+
+TDX reference material is collected here:
+
+https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html
+
+The driver is based on TDX module specification v1.0 and TDX GHCI specification v1.0.
diff --git a/Documentation/virt/index.rst b/Documentation/virt/index.rst
index 2f1cffa87b1b..56e003ff28ff 100644
--- a/Documentation/virt/index.rst
+++ b/Documentation/virt/index.rst
@@ -14,6 +14,7 @@ Linux Virtualization Support
ne_overview
acrn/index
coco/sev-guest
+ coco/tdx-guest
hyperv/index
.. only:: html and subproject
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index eee9f857a986..896914e3a847 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -7213,14 +7213,13 @@ veto the transition.
:Parameters: args[0] is the maximum poll time in nanoseconds
:Returns: 0 on success; -1 on error
-This capability overrides the kvm module parameter halt_poll_ns for the
-target VM.
-
-VCPU polling allows a VCPU to poll for wakeup events instead of immediately
-scheduling during guest halts. The maximum time a VCPU can spend polling is
-controlled by the kvm module parameter halt_poll_ns. This capability allows
-the maximum halt time to specified on a per-VM basis, effectively overriding
-the module parameter for the target VM.
+KVM_CAP_HALT_POLL overrides the kvm.halt_poll_ns module parameter to set the
+maximum halt-polling time for all vCPUs in the target VM. This capability can
+be invoked at any time and any number of times to dynamically change the
+maximum halt-polling time.
+
+See Documentation/virt/kvm/halt-polling.rst for more information on halt
+polling.
7.21 KVM_CAP_X86_USER_SPACE_MSR
-------------------------------
diff --git a/Documentation/virt/kvm/devices/vm.rst b/Documentation/virt/kvm/devices/vm.rst
index 0aa5b1cfd700..60acc39e0e93 100644
--- a/Documentation/virt/kvm/devices/vm.rst
+++ b/Documentation/virt/kvm/devices/vm.rst
@@ -215,6 +215,7 @@ KVM_S390_VM_TOD_EXT).
:Parameters: address of a buffer in user space to store the data (u8) to
:Returns: -EFAULT if the given address is not accessible from kernel space;
-EINVAL if setting the TOD clock extension to != 0 is not supported
+ -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
3.2. ATTRIBUTE: KVM_S390_VM_TOD_LOW
-----------------------------------
@@ -224,6 +225,7 @@ the POP (u64).
:Parameters: address of a buffer in user space to store the data (u64) to
:Returns: -EFAULT if the given address is not accessible from kernel space
+ -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
3.3. ATTRIBUTE: KVM_S390_VM_TOD_EXT
-----------------------------------
@@ -237,6 +239,7 @@ it, it is stored as 0 and not allowed to be set to a value != 0.
(kvm_s390_vm_tod_clock) to
:Returns: -EFAULT if the given address is not accessible from kernel space;
-EINVAL if setting the TOD clock extension to != 0 is not supported
+ -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
4. GROUP: KVM_S390_VM_CRYPTO
============================
diff --git a/Documentation/virt/kvm/x86/halt-polling.rst b/Documentation/virt/kvm/halt-polling.rst
index 4922e4a15f18..3fae39b1a5ba 100644
--- a/Documentation/virt/kvm/x86/halt-polling.rst
+++ b/Documentation/virt/kvm/halt-polling.rst
@@ -119,6 +119,19 @@ These module parameters can be set from the debugfs files in:
Note: that these module parameters are system wide values and are not able to
be tuned on a per vm basis.
+Any changes to these parameters will be picked up by new and existing vCPUs the
+next time they halt, with the notable exception of VMs using KVM_CAP_HALT_POLL
+(see next section).
+
+KVM_CAP_HALT_POLL
+=================
+
+KVM_CAP_HALT_POLL is a VM capability that allows userspace to override halt_poll_ns
+on a per-VM basis. VMs using KVM_CAP_HALT_POLL ignore halt_poll_ns completely (but
+still obey halt_poll_ns_grow, halt_poll_ns_grow_start, and halt_poll_ns_shrink).
+
+See Documentation/virt/kvm/api.rst for more information on this capability.
+
Further Notes
=============
diff --git a/Documentation/virt/kvm/index.rst b/Documentation/virt/kvm/index.rst
index e0a2c74e1043..ad13ec55ddfe 100644
--- a/Documentation/virt/kvm/index.rst
+++ b/Documentation/virt/kvm/index.rst
@@ -17,4 +17,5 @@ KVM
locking
vcpu-requests
+ halt-polling
review-checklist
diff --git a/Documentation/virt/kvm/x86/index.rst b/Documentation/virt/kvm/x86/index.rst
index 7ff588826b9f..9ece6b8dc817 100644
--- a/Documentation/virt/kvm/x86/index.rst
+++ b/Documentation/virt/kvm/x86/index.rst
@@ -10,7 +10,6 @@ KVM for x86 systems
amd-memory-encryption
cpuid
errata
- halt-polling
hypercalls
mmu
msr
diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst
index 894a19897005..240d084782a6 100644
--- a/Documentation/x86/boot.rst
+++ b/Documentation/x86/boot.rst
@@ -455,6 +455,7 @@ Protocol: 2.00+
11 Minimal Linux Bootloader
<http://sebastian-plotz.blogspot.de>
12 OVMF UEFI virtualization stack
+ 13 barebox
== =======================================
Please contact <hpa@zytor.com> if you need a bootloader ID value assigned.
diff --git a/Documentation/x86/tdx.rst b/Documentation/x86/tdx.rst
index b8fa4329e1a5..dc8d9fd2c3f7 100644
--- a/Documentation/x86/tdx.rst
+++ b/Documentation/x86/tdx.rst
@@ -210,6 +210,49 @@ converted to shared on boot.
For coherent DMA allocation, the DMA buffer gets converted on the
allocation. Check force_dma_unencrypted() for details.
+Attestation
+===========
+
+Attestation is used to verify the TDX guest trustworthiness to other
+entities before provisioning secrets to the guest. For example, a key
+server may want to use attestation to verify that the guest is the
+desired one before releasing the encryption keys to mount the encrypted
+rootfs or a secondary drive.
+
+The TDX module records the state of the TDX guest in various stages of
+the guest boot process using the build time measurement register (MRTD)
+and runtime measurement registers (RTMR). Measurements related to the
+guest initial configuration and firmware image are recorded in the MRTD
+register. Measurements related to initial state, kernel image, firmware
+image, command line options, initrd, ACPI tables, etc are recorded in
+RTMR registers. For more details, as an example, please refer to TDX
+Virtual Firmware design specification, section titled "TD Measurement".
+At TDX guest runtime, the attestation process is used to attest to these
+measurements.
+
+The attestation process consists of two steps: TDREPORT generation and
+Quote generation.
+
+TDX guest uses TDCALL[TDG.MR.REPORT] to get the TDREPORT (TDREPORT_STRUCT)
+from the TDX module. TDREPORT is a fixed-size data structure generated by
+the TDX module which contains guest-specific information (such as build
+and boot measurements), platform security version, and the MAC to protect
+the integrity of the TDREPORT. A user-provided 64-Byte REPORTDATA is used
+as input and included in the TDREPORT. Typically it can be some nonce
+provided by attestation service so the TDREPORT can be verified uniquely.
+More details about the TDREPORT can be found in Intel TDX Module
+specification, section titled "TDG.MR.REPORT Leaf".
+
+After getting the TDREPORT, the second step of the attestation process
+is to send it to the Quoting Enclave (QE) to generate the Quote. TDREPORT
+by design can only be verified on the local platform as the MAC key is
+bound to the platform. To support remote verification of the TDREPORT,
+TDX leverages Intel SGX Quoting Enclave to verify the TDREPORT locally
+and convert it to a remotely verifiable Quote. Method of sending TDREPORT
+to QE is implementation specific. Attestation software can choose
+whatever communication channel available (i.e. vsock or TCP/IP) to
+send the TDREPORT to QE and receive the Quote.
+
References
==========
diff --git a/MAINTAINERS b/MAINTAINERS
index 046ff06ff97f..de46dc69922a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -775,6 +775,24 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
F: drivers/media/platform/sunxi/sun4i-csi/
+ALLWINNER A31 CSI DRIVER
+M: Yong Deng <yong.deng@magewell.com>
+M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
+F: drivers/media/platform/sunxi/sun6i-csi/
+
+ALLWINNER A31 ISP DRIVER
+M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml
+F: drivers/staging/media/sunxi/sun6i-isp/
+F: drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h
+
ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER
M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
L: linux-media@vger.kernel.org
@@ -1093,6 +1111,16 @@ S: Maintained
F: Documentation/hid/amd-sfh*
F: drivers/hid/amd-sfh-hid/
+AMLOGIC DDR PMU DRIVER
+M: Jiucheng Xu <jiucheng.xu@amlogic.com>
+L: linux-amlogic@lists.infradead.org
+S: Supported
+W: http://www.amlogic.com
+F: Documentation/admin-guide/perf/meson-ddr-pmu.rst
+F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
+F: drivers/perf/amlogic/
+F: include/soc/amlogic/
+
AMPHION VPU CODEC V4L2 DRIVER
M: Ming Qian <ming.qian@nxp.com>
M: Shijie Qin <shijie.qin@nxp.com>
@@ -1685,7 +1713,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-F: Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
+F: Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER
@@ -1897,6 +1925,7 @@ T: git https://github.com/AsahiLinux/linux.git
F: Documentation/devicetree/bindings/arm/apple.yaml
F: Documentation/devicetree/bindings/arm/apple/*
F: Documentation/devicetree/bindings/clock/apple,nco.yaml
+F: Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml
F: Documentation/devicetree/bindings/dma/apple,admac.yaml
F: Documentation/devicetree/bindings/i2c/apple,i2c.yaml
F: Documentation/devicetree/bindings/interrupt-controller/apple,*
@@ -1911,6 +1940,7 @@ F: Documentation/devicetree/bindings/power/apple*
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
F: arch/arm64/boot/dts/apple/
F: drivers/clk/clk-apple-nco.c
+F: drivers/cpufreq/apple-soc-cpufreq.c
F: drivers/dma/apple-admac.c
F: drivers/i2c/busses/i2c-pasemi-core.c
F: drivers/i2c/busses/i2c-pasemi-platform.c
@@ -2197,7 +2227,7 @@ M: Wei Xu <xuwei5@hisilicon.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
W: http://www.hisilicon.com
-T: git git://github.com/hisilicon/linux-hisi.git
+T: git https://github.com/hisilicon/linux-hisi.git
F: arch/arm/boot/dts/hi3*
F: arch/arm/boot/dts/hip*
F: arch/arm/boot/dts/hisi*
@@ -2272,8 +2302,6 @@ F: drivers/clocksource/timer-ixp4xx.c
F: drivers/crypto/ixp4xx_crypto.c
F: drivers/gpio/gpio-ixp4xx.c
F: drivers/irqchip/irq-ixp4xx.c
-F: include/linux/irqchip/irq-ixp4xx.h
-F: include/linux/platform_data/timer-ixp4xx.h
ARM/INTEL KEEMBAY ARCHITECTURE
M: Paul J. Murphy <paul.j.murphy@intel.com>
@@ -2341,6 +2369,8 @@ M: Gregory Clement <gregory.clement@bootlin.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git
+F: Documentation/devicetree/bindings/arm/marvell/marvell,dove.txt
+F: Documentation/devicetree/bindings/arm/marvell/marvell,orion5x.txt
F: Documentation/devicetree/bindings/soc/dove/
F: arch/arm/boot/dts/dove*
F: arch/arm/boot/dts/orion5x*
@@ -2357,6 +2387,7 @@ M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git
+F: Documentation/devicetree/bindings/arm/marvell/
F: arch/arm/boot/dts/armada*
F: arch/arm/boot/dts/kirkwood*
F: arch/arm/configs/mvebu_*_defconfig
@@ -2620,7 +2651,7 @@ W: http://www.armlinux.org.uk/
ARM/QUALCOMM SUPPORT
M: Andy Gross <agross@kernel.org>
M: Bjorn Andersson <andersson@kernel.org>
-R: Konrad Dybcio <konrad.dybcio@somainline.org>
+R: Konrad Dybcio <konrad.dybcio@linaro.org>
L: linux-arm-msm@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
@@ -2691,7 +2722,7 @@ F: arch/arm/boot/dts/rtd*
F: arch/arm/mach-realtek/
F: arch/arm64/boot/dts/realtek/
-ARM/RENESAS ARCHITECTURE
+ARM/RISC-V/RENESAS ARCHITECTURE
M: Geert Uytterhoeven <geert+renesas@glider.be>
M: Magnus Damm <magnus.damm@gmail.com>
L: linux-renesas-soc@vger.kernel.org
@@ -2699,7 +2730,6 @@ S: Supported
Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/
C: irc://irc.libera.chat/renesas-soc
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
-F: Documentation/devicetree/bindings/arm/renesas.yaml
F: Documentation/devicetree/bindings/hwinfo/renesas,prr.yaml
F: Documentation/devicetree/bindings/soc/renesas/
F: arch/arm/boot/dts/emev2*
@@ -2713,6 +2743,7 @@ F: arch/arm/configs/shmobile_defconfig
F: arch/arm/include/debug/renesas-scif.S
F: arch/arm/mach-shmobile/
F: arch/arm64/boot/dts/renesas/
+F: arch/riscv/boot/dts/renesas/
F: drivers/soc/renesas/
F: include/linux/soc/renesas/
@@ -4809,7 +4840,7 @@ R: Jeff Layton <jlayton@kernel.org>
L: ceph-devel@vger.kernel.org
S: Supported
W: http://ceph.com/
-T: git git://github.com/ceph/ceph-client.git
+T: git https://github.com/ceph/ceph-client.git
F: include/linux/ceph/
F: include/linux/crush/
F: net/ceph/
@@ -4821,7 +4852,7 @@ R: Jeff Layton <jlayton@kernel.org>
L: ceph-devel@vger.kernel.org
S: Supported
W: http://ceph.com/
-T: git git://github.com/ceph/ceph-client.git
+T: git https://github.com/ceph/ceph-client.git
F: Documentation/filesystems/ceph.rst
F: fs/ceph/
@@ -4911,7 +4942,7 @@ F: drivers/platform/chrome/
CHROMEOS EC CODEC DRIVER
M: Cheng-Yi Chiang <cychiang@chromium.org>
-M: Tzung-Bi Shih <tzungbi@google.com>
+M: Tzung-Bi Shih <tzungbi@kernel.org>
R: Guenter Roeck <groeck@chromium.org>
L: chrome-platform@lists.linux.dev
S: Maintained
@@ -4941,6 +4972,12 @@ S: Maintained
F: drivers/platform/chrome/cros_usbpd_notify.c
F: include/linux/platform_data/cros_usbpd_notify.h
+CHROMEOS HPS DRIVER
+M: Dan Callaghan <dcallagh@chromium.org>
+R: Sami Kyöstilä <skyostil@chromium.org>
+S: Maintained
+F: drivers/platform/chrome/cros_hps_i2c.c
+
CHRONTEL CH7322 CEC DRIVER
M: Joe Tessler <jrt@google.com>
L: linux-media@vger.kernel.org
@@ -5299,7 +5336,7 @@ M: Johannes Weiner <hannes@cmpxchg.org>
M: Michal Hocko <mhocko@kernel.org>
M: Roman Gushchin <roman.gushchin@linux.dev>
M: Shakeel Butt <shakeelb@google.com>
-R: Muchun Song <songmuchun@bytedance.com>
+R: Muchun Song <muchun.song@linux.dev>
L: cgroups@vger.kernel.org
L: linux-mm@kvack.org
S: Maintained
@@ -5502,14 +5539,6 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained
F: sound/pci/cs5535audio/
-CSI DRIVERS FOR ALLWINNER V3s
-M: Yong Deng <yong.deng@magewell.com>
-L: linux-media@vger.kernel.org
-S: Maintained
-T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
-F: drivers/media/platform/sunxi/sun6i-csi/
-
CTU CAN FD DRIVER
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
M: Ondrej Ille <ondrej.ille@gmail.com>
@@ -5585,8 +5614,6 @@ F: drivers/scsi/cxgbi/cxgb3i
CXGB4 CRYPTO DRIVER (chcr)
M: Ayush Sawal <ayush.sawal@chelsio.com>
-M: Vinay Kumar Yadav <vinay.yadav@chelsio.com>
-M: Rohit Maheshwari <rohitm@chelsio.com>
L: linux-crypto@vger.kernel.org
S: Supported
W: http://www.chelsio.com
@@ -5594,8 +5621,6 @@ F: drivers/crypto/chelsio
CXGB4 INLINE CRYPTO DRIVER
M: Ayush Sawal <ayush.sawal@chelsio.com>
-M: Vinay Kumar Yadav <vinay.yadav@chelsio.com>
-M: Rohit Maheshwari <rohitm@chelsio.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.chelsio.com
@@ -5858,6 +5883,13 @@ L: Dell.Client.Kernel@dell.com
S: Maintained
F: drivers/platform/x86/dell/dell-wmi-descriptor.c
+DELL WMI DDV DRIVER
+M: Armin Wolf <W_Armin@gmx.de>
+S: Maintained
+F: Documentation/ABI/testing/debugfs-dell-wmi-ddv
+F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
+F: drivers/platform/x86/dell/dell-wmi-ddv.c
+
DELL WMI SYSMAN DRIVER
M: Divya Bharathi <divya.bharathi@dell.com>
M: Prasanth Ksr <prasanth.ksr@dell.com>
@@ -6033,11 +6065,12 @@ F: include/net/devlink.h
F: include/uapi/linux/devlink.h
F: net/core/devlink.c
-DH ELECTRONICS IMX6 DHCOM BOARD SUPPORT
+DH ELECTRONICS IMX6 DHCOM/DHCOR BOARD SUPPORT
M: Christoph Niedermaier <cniedermaier@dh-electronics.com>
L: kernel@dh-electronics.com
S: Maintained
F: arch/arm/boot/dts/imx6*-dhcom-*
+F: arch/arm/boot/dts/imx6*-dhcor-*
DH ELECTRONICS STM32MP1 DHCOM/DHCOR BOARD SUPPORT
M: Marek Vasut <marex@denx.de>
@@ -6506,6 +6539,12 @@ S: Orphan / Obsolete
F: drivers/gpu/drm/i810/
F: include/uapi/drm/i810_drm.h
+DRM DRIVER FOR JADARD JD9365DA-H3 MIPI-DSI LCD PANELS
+M: Jagan Teki <jagan@edgeble.ai>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
+F: drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
+
DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER
M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
S: Supported
@@ -6695,10 +6734,13 @@ L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/drm_aperture.c
+F: drivers/gpu/drm/tiny/ofdrm.c
F: drivers/gpu/drm/tiny/simpledrm.c
F: drivers/video/aperture.c
+F: drivers/video/nomodeset.c
F: include/drm/drm_aperture.h
F: include/linux/aperture.h
+F: include/video/nomodeset.h
DRM DRIVER FOR SIS VIDEO CARDS
S: Orphan / Obsolete
@@ -6827,6 +6869,15 @@ F: include/drm/drm*
F: include/linux/vga*
F: include/uapi/drm/drm*
+DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK
+M: Oded Gabbay <ogabbay@kernel.org>
+L: dri-devel@lists.freedesktop.org
+S: Maintained
+C: irc://irc.oftc.net/dri-devel
+T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git
+F: Documentation/accel/
+F: drivers/accel/
+
DRM DRIVERS FOR ALLWINNER A10
M: Maxime Ripard <mripard@kernel.org>
M: Chen-Yu Tsai <wens@csie.org>
@@ -7115,7 +7166,7 @@ F: drivers/gpu/drm/ttm/
F: include/drm/ttm/
DRM GPU SCHEDULER
-M: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
+M: Luben Tuikov <luben.tuikov@amd.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
@@ -7363,9 +7414,9 @@ F: drivers/edac/thunderx_edac*
EDAC-CORE
M: Borislav Petkov <bp@alien8.de>
-M: Mauro Carvalho Chehab <mchehab@kernel.org>
M: Tony Luck <tony.luck@intel.com>
R: James Morse <james.morse@arm.com>
+R: Mauro Carvalho Chehab <mchehab@kernel.org>
R: Robert Richter <rric@kernel.org>
L: linux-edac@vger.kernel.org
S: Supported
@@ -7482,8 +7533,7 @@ S: Maintained
F: drivers/edac/pnd2_edac.[ch]
EDAC-QCOM
-M: Channagoud Kadabi <ckadabi@codeaurora.org>
-M: Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
+M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-arm-msm@vger.kernel.org
L: linux-edac@vger.kernel.org
S: Maintained
@@ -8602,8 +8652,8 @@ F: include/asm-generic/
F: include/uapi/asm-generic/
GENERIC PHY FRAMEWORK
-M: Kishon Vijay Abraham I <kishon@ti.com>
M: Vinod Koul <vkoul@kernel.org>
+M: Kishon Vijay Abraham I <kishon@kernel.org>
L: linux-phy@lists.infradead.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-phy/list/
@@ -9248,7 +9298,7 @@ F: drivers/misc/hisi_hikey_usb.c
HISILICON PMU DRIVER
M: Shaokun Zhang <zhangshaokun@hisilicon.com>
-M: Qi Liu <liuqi115@huawei.com>
+M: Jonathan Cameron <jonathan.cameron@huawei.com>
S: Supported
W: http://www.hisilicon.com
F: Documentation/admin-guide/perf/hisi-pcie-pmu.rst
@@ -9341,7 +9391,7 @@ S: Maintained
F: drivers/crypto/hisilicon/trng/trng.c
HISILICON V3XX SPI NOR FLASH Controller Driver
-M: John Garry <john.garry@huawei.com>
+M: Jay Fang <f.fangjian@huawei.com>
S: Maintained
W: http://www.hisilicon.com
F: drivers/spi/spi-hisi-sfc-v3xx.c
@@ -9366,7 +9416,7 @@ F: drivers/net/wireless/intersil/hostap/
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
L: platform-driver-x86@vger.kernel.org
S: Orphan
-F: drivers/platform/x86/tc1100-wmi.c
+F: drivers/platform/x86/hp/tc1100-wmi.c
HPET: High Precision Event Timers driver
M: Clemens Ladisch <clemens@ladisch.de>
@@ -9443,7 +9493,7 @@ F: drivers/net/ethernet/huawei/hinic/
HUGETLB SUBSYSTEM
M: Mike Kravetz <mike.kravetz@oracle.com>
-M: Muchun Song <songmuchun@bytedance.com>
+M: Muchun Song <muchun.song@linux.dev>
L: linux-mm@kvack.org
S: Maintained
F: Documentation/ABI/testing/sysfs-kernel-mm-hugepages
@@ -9507,7 +9557,6 @@ F: drivers/media/i2c/hi847.c
Hyper-V/Azure CORE AND DRIVERS
M: "K. Y. Srinivasan" <kys@microsoft.com>
M: Haiyang Zhang <haiyangz@microsoft.com>
-M: Stephen Hemminger <sthemmin@microsoft.com>
M: Wei Liu <wei.liu@kernel.org>
M: Dexuan Cui <decui@microsoft.com>
L: linux-hyperv@vger.kernel.org
@@ -10027,6 +10076,11 @@ F: Documentation/hwmon/ina2xx.rst
F: drivers/hwmon/ina2xx.c
F: include/linux/platform_data/ina2xx.h
+INDEX OF FURTHER KERNEL DOCUMENTATION
+M: Carlos Bilbao <carlos.bilbao@amd.com>
+S: Maintained
+F: Documentation/process/kernel-docs.rst
+
INDUSTRY PACK SUBSYSTEM (IPACK)
M: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
M: Jens Taprogge <jens.taprogge@taprogge.org>
@@ -10056,6 +10110,7 @@ F: drivers/infiniband/
F: include/rdma/
F: include/trace/events/ib_mad.h
F: include/trace/events/ib_umad.h
+F: include/trace/misc/rdma.h
F: include/uapi/linux/if_infiniband.h
F: include/uapi/rdma/
F: samples/bpf/ibumad_kern.c
@@ -10229,6 +10284,7 @@ Q: http://patchwork.freedesktop.org/project/intel-gfx/
B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
C: irc://irc.oftc.net/intel-gfx
T: git git://anongit.freedesktop.org/drm-intel
+F: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
F: Documentation/gpu/i915.rst
F: drivers/gpu/drm/i915/
F: include/drm/i915*
@@ -10288,7 +10344,7 @@ T: git https://github.com/intel/gvt-linux.git
F: drivers/gpu/drm/i915/gvt/
INTEL HID EVENT DRIVER
-M: Alex Hung <alex.hung@canonical.com>
+M: Alex Hung <alexhung@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel/hid.c
@@ -10899,6 +10955,13 @@ F: drivers/isdn/Makefile
F: drivers/isdn/hardware/
F: drivers/isdn/mISDN/
+ISOFS FILESYSTEM
+M: Jan Kara <jack@suse.cz>
+L: linux-fsdevel@vger.kernel.org
+S: Maintained
+F: Documentation/filesystems/isofs.rst
+F: fs/isofs/
+
IT87 HARDWARE MONITORING DRIVER
M: Jean Delvare <jdelvare@suse.com>
L: linux-hwmon@vger.kernel.org
@@ -10960,9 +11023,9 @@ F: drivers/hwmon/jc42.c
JFS FILESYSTEM
M: Dave Kleikamp <shaggy@kernel.org>
L: jfs-discussion@lists.sourceforge.net
-S: Maintained
+S: Odd Fixes
W: http://jfs.sourceforge.net/
-T: git git://github.com/kleikamp/linux-shaggy.git
+T: git https://github.com/kleikamp/linux-shaggy.git
F: Documentation/admin-guide/jfs.rst
F: fs/jfs/
@@ -11036,6 +11099,7 @@ KCONFIG
M: Masahiro Yamada <masahiroy@kernel.org>
L: linux-kbuild@vger.kernel.org
S: Maintained
+Q: https://patchwork.kernel.org/project/linux-kbuild/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
F: Documentation/kbuild/kconfig*
F: scripts/Kconfig.include
@@ -11093,10 +11157,12 @@ F: fs/autofs/
KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
M: Masahiro Yamada <masahiroy@kernel.org>
-M: Michal Marek <michal.lkml@markovi.net>
+R: Nathan Chancellor <nathan@kernel.org>
R: Nick Desaulniers <ndesaulniers@google.com>
+R: Nicolas Schier <nicolas@fjasle.eu>
L: linux-kbuild@vger.kernel.org
S: Maintained
+Q: https://patchwork.kernel.org/project/linux-kbuild/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
F: Documentation/kbuild/
F: Makefile
@@ -11132,11 +11198,18 @@ L: linux-nfs@vger.kernel.org
S: Supported
W: http://nfs.sourceforge.net/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
+F: fs/exportfs/
F: fs/lockd/
F: fs/nfs_common/
F: fs/nfsd/
F: include/linux/lockd/
F: include/linux/sunrpc/
+F: include/trace/events/rpcgss.h
+F: include/trace/events/rpcrdma.h
+F: include/trace/events/sunrpc.h
+F: include/trace/misc/fs.h
+F: include/trace/misc/nfs.h
+F: include/trace/misc/sunrpc.h
F: include/uapi/linux/nfsd/
F: include/uapi/linux/sunrpc/
F: net/sunrpc/
@@ -11858,7 +11931,7 @@ M: Eric Piel <eric.piel@tremplin-utc.net>
S: Maintained
F: Documentation/misc-devices/lis3lv02d.rst
F: drivers/misc/lis3lv02d/
-F: drivers/platform/x86/hp_accel.c
+F: drivers/platform/x86/hp/hp_accel.c
LIST KUNIT TEST
M: David Gow <davidgow@google.com>
@@ -12013,6 +12086,13 @@ F: drivers/*/*loongarch*
F: Documentation/loongarch/
F: Documentation/translations/zh_CN/loongarch/
+LOONGSON-2 SOC SERIES GUTS DRIVER
+M: Yinbo Zhu <zhuyinbo@loongson.cn>
+L: loongarch@lists.linux.dev
+S: Maintained
+F: Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
+F: drivers/soc/loongson/loongson2_guts.c
+
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Sathya Prakash <sathya.prakash@broadcom.com>
M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
@@ -12090,7 +12170,7 @@ M: Alexey Kodanev <alexey.kodanev@oracle.com>
L: ltp@lists.linux.it (subscribers-only)
S: Maintained
W: http://linux-test-project.github.io/
-T: git git://github.com/linux-test-project/ltp.git
+T: git https://github.com/linux-test-project/ltp.git
LYNX 28G SERDES PHY DRIVER
M: Ioana Ciornei <ioana.ciornei@nxp.com>
@@ -12226,7 +12306,6 @@ F: arch/mips/boot/dts/img/pistachio*
MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
M: Andrew Lunn <andrew@lunn.ch>
-M: Vivien Didelot <vivien.didelot@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/marvell.txt
@@ -12726,7 +12805,7 @@ F: Documentation/admin-guide/media/imx7.rst
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
F: drivers/media/platform/nxp/imx-mipi-csis.c
-F: drivers/staging/media/imx/imx7-media-csi.c
+F: drivers/media/platform/nxp/imx7-media-csi.c
MEDIA DRIVERS FOR HELENE
M: Abylay Ospan <aospan@netup.ru>
@@ -13385,7 +13464,7 @@ MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
M: Liang Yang <liang.yang@amlogic.com>
L: linux-mtd@lists.infradead.org
S: Maintained
-F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
+F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml
F: drivers/mtd/nand/raw/meson_*
MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
@@ -13466,7 +13545,7 @@ M: Eugen Hristev <eugen.hristev@microchip.com>
L: linux-media@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
-F: drivers/media/platform/atmel/microchip-csi2dc.c
+F: drivers/media/platform/microchip/microchip-csi2dc.c
MICROCHIP ECC DRIVER
M: Tudor Ambarus <tudor.ambarus@microchip.com>
@@ -13493,8 +13572,10 @@ L: linux-media@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
F: Documentation/devicetree/bindings/media/microchip,xisc.yaml
-F: drivers/media/platform/atmel/atmel-isc*
-F: drivers/media/platform/atmel/atmel-sama*-isc*
+F: drivers/staging/media/deprecated/atmel/atmel-isc*
+F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc*
+F: drivers/media/platform/microchip/microchip-isc*
+F: drivers/media/platform/microchip/microchip-sama*-isc*
F: include/linux/atmel-isc-media.h
MICROCHIP ISI DRIVER
@@ -13627,6 +13708,12 @@ S: Supported
F: drivers/misc/atmel-ssc.c
F: include/linux/atmel-ssc.h
+MICROCHIP SOC DRIVERS
+M: Conor Dooley <conor@kernel.org>
+S: Supported
+T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
+F: drivers/soc/microchip/
+
MICROCHIP USB251XB DRIVER
M: Richard Leitner <richard.leitner@skidata.com>
L: linux-usb@vger.kernel.org
@@ -14324,7 +14411,6 @@ F: drivers/net/wireless/
NETWORKING [DSA]
M: Andrew Lunn <andrew@lunn.ch>
-M: Vivien Didelot <vivien.didelot@gmail.com>
M: Florian Fainelli <f.fainelli@gmail.com>
M: Vladimir Oltean <olteanv@gmail.com>
S: Maintained
@@ -15181,6 +15267,13 @@ S: Maintained
T: git git://linuxtv.org/media_tree.git
F: drivers/media/i2c/ov08d10.c
+OMNIVISION OV08X40 SENSOR DRIVER
+M: Jason Chen <jason.z.chen@intel.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/i2c/ov08x40.c
+
OMNIVISION OV13858 SENSOR DRIVER
M: Sakari Ailus <sakari.ailus@linux.intel.com>
L: linux-media@vger.kernel.org
@@ -15219,6 +15312,14 @@ S: Maintained
T: git git://linuxtv.org/media_tree.git
F: drivers/media/i2c/ov2740.c
+OMNIVISION OV4689 SENSOR DRIVER
+M: Mikhail Rudenko <mike.rudenko@gmail.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml
+F: drivers/media/i2c/ov5647.c
+
OMNIVISION OV5640 SENSOR DRIVER
M: Steve Longerbeam <slongerbeam@gmail.com>
L: linux-media@vger.kernel.org
@@ -15946,6 +16047,7 @@ Q: https://patchwork.kernel.org/project/linux-pci/list/
B: https://bugzilla.kernel.org
C: irc://irc.oftc.net/linux-pci
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
+F: Documentation/devicetree/bindings/pci/
F: drivers/pci/controller/
F: drivers/pci/pci-bridge-emul.c
F: drivers/pci/pci-bridge-emul.h
@@ -16052,7 +16154,7 @@ F: Documentation/devicetree/bindings/pci/microchip*
F: drivers/pci/controller/*microchip*
PCIE DRIVER FOR QUALCOMM MSM
-M: Stanimir Varbanov <svarbanov@mm-sol.com>
+M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-pci@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Maintained
@@ -16142,7 +16244,8 @@ F: include/linux/peci-cpu.h
F: include/linux/peci.h
PENSANDO ETHERNET DRIVERS
-M: Shannon Nelson <snelson@pensando.io>
+M: Shannon Nelson <shannon.nelson@amd.com>
+M: Brett Creeley <brett.creeley@amd.com>
M: drivers@pensando.io
L: netdev@vger.kernel.org
S: Supported
@@ -16373,13 +16476,6 @@ S: Supported
F: Documentation/devicetree/bindings/input/pine64,pinephone-keyboard.yaml
F: drivers/input/keyboard/pinephone-keyboard.c
-PKTCDVD DRIVER
-M: linux-block@vger.kernel.org
-S: Orphan
-F: drivers/block/pktcdvd.c
-F: include/linux/pktcdvd.h
-F: include/uapi/linux/pktcdvd.h
-
PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER
M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained
@@ -16657,10 +16753,10 @@ F: net/psample
PSTORE FILESYSTEM
M: Kees Cook <keescook@chromium.org>
-M: Anton Vorontsov <anton@enomsg.org>
-M: Colin Cross <ccross@android.com>
-M: Tony Luck <tony.luck@intel.com>
-S: Maintained
+R: Tony Luck <tony.luck@intel.com>
+R: Guilherme G. Piccoli <gpiccoli@igalia.com>
+L: linux-hardening@vger.kernel.org
+S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
F: Documentation/admin-guide/ramoops.rst
F: Documentation/admin-guide/pstore-blk.rst
@@ -16707,7 +16803,6 @@ M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: Documentation/admin-guide/media/pulse8-cec.rst
F: drivers/media/cec/usb/pulse8/
PURELIFI PLFXLC DRIVER
@@ -16802,7 +16897,7 @@ M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
M: Banajit Goswami <bgoswami@quicinc.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
-F: Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml
+F: Documentation/devicetree/bindings/soc/qcom/qcom,apr*
F: Documentation/devicetree/bindings/sound/qcom,*
F: drivers/soc/qcom/apr.c
F: include/dt-bindings/sound/qcom,wcd9335.h
@@ -17160,7 +17255,8 @@ F: Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
F: drivers/thermal/qcom/
QUALCOMM VENUS VIDEO ACCELERATOR DRIVER
-M: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+M: Stanimir Varbanov <stanimir.k.varbanov@gmail.com>
+M: Vikash Garodia <quic_vgarodia@quicinc.com>
L: linux-media@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Maintained
@@ -17225,7 +17321,7 @@ R: Dongsheng Yang <dongsheng.yang@easystack.cn>
L: ceph-devel@vger.kernel.org
S: Supported
W: http://ceph.com/
-T: git git://github.com/ceph/ceph-client.git
+T: git https://github.com/ceph/ceph-client.git
F: Documentation/ABI/testing/sysfs-bus-rbd
F: drivers/block/rbd.c
F: drivers/block/rbd_types.h
@@ -17478,10 +17574,8 @@ S: Maintained
F: drivers/net/wireless/realtek/rtw89/
REDPINE WIRELESS DRIVER
-M: Amitkumar Karwar <amitkarwar@gmail.com>
-M: Siva Rebbagondla <siva8118@gmail.com>
L: linux-wireless@vger.kernel.org
-S: Maintained
+S: Orphan
F: drivers/net/wireless/rsi/
REGISTER MAP ABSTRACTION
@@ -17726,7 +17820,7 @@ F: arch/riscv/
N: riscv
K: riscv
-RISC-V/MICROCHIP POLARFIRE SOC SUPPORT
+RISC-V MICROCHIP FPGA SUPPORT
M: Conor Dooley <conor.dooley@microchip.com>
M: Daire McNamara <daire.mcnamara@microchip.com>
L: linux-riscv@lists.infradead.org
@@ -17744,17 +17838,26 @@ F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
F: arch/riscv/boot/dts/microchip/
F: drivers/char/hw_random/mpfs-rng.c
F: drivers/clk/microchip/clk-mpfs.c
-F: drivers/i2c/busses/i2c-microchip-core.c
+F: drivers/i2c/busses/i2c-microchip-corei2c.c
F: drivers/mailbox/mailbox-mpfs.c
F: drivers/pci/controller/pcie-microchip-host.c
F: drivers/reset/reset-mpfs.c
F: drivers/rtc/rtc-mpfs.c
-F: drivers/soc/microchip/
+F: drivers/soc/microchip/mpfs-sys-controller.c
F: drivers/spi/spi-microchip-core-qspi.c
F: drivers/spi/spi-microchip-core.c
F: drivers/usb/musb/mpfs.c
F: include/soc/microchip/mpfs.h
+RISC-V MISC SOC SUPPORT
+M: Conor Dooley <conor@kernel.org>
+L: linux-riscv@lists.infradead.org
+S: Maintained
+Q: https://patchwork.kernel.org/project/linux-riscv/list/
+T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
+F: Documentation/devicetree/bindings/riscv/
+F: arch/riscv/boot/dts/
+
RNBD BLOCK DRIVERS
M: Md. Haris Iqbal <haris.iqbal@ionos.com>
M: Jack Wang <jinpu.wang@ionos.com>
@@ -17995,7 +18098,7 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/fbdev/savage/
-S390
+S390 ARCHITECTURE
M: Heiko Carstens <hca@linux.ibm.com>
M: Vasily Gorbik <gor@linux.ibm.com>
M: Alexander Gordeev <agordeev@linux.ibm.com>
@@ -18050,6 +18153,15 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/s390/net/
+S390 MM
+M: Alexander Gordeev <agordeev@linux.ibm.com>
+M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
+L: linux-s390@vger.kernel.org
+S: Supported
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
+F: arch/s390/include/asm/pgtable.h
+F: arch/s390/mm
+
S390 PCI SUBSYSTEM
M: Niklas Schnelle <schnelle@linux.ibm.com>
M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
@@ -18781,7 +18893,6 @@ M: Palmer Dabbelt <palmer@dabbelt.com>
M: Paul Walmsley <paul.walmsley@sifive.com>
L: linux-riscv@lists.infradead.org
S: Supported
-T: git https://github.com/sifive/riscv-linux.git
N: sifive
K: [^@]sifive
@@ -18800,6 +18911,13 @@ S: Maintained
F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
F: drivers/dma/sf-pdma/
+SIFIVE SOC DRIVERS
+M: Conor Dooley <conor@kernel.org>
+L: linux-riscv@lists.infradead.org
+S: Maintained
+T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
+F: drivers/soc/sifive/
+
SILEAD TOUCHSCREEN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
@@ -19188,7 +19306,7 @@ M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/i2c/imx290.txt
+F: Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
F: drivers/media/i2c/imx290.c
SONY IMX319 SENSOR DRIVER
@@ -19337,6 +19455,11 @@ W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
F: drivers/media/dvb-frontends/sp2*
+SPANISH DOCUMENTATION
+M: Carlos Bilbao <carlos.bilbao@amd.com>
+S: Maintained
+F: Documentation/translations/sp_SP/
+
SPARC + UltraSPARC (sparc/sparc64)
M: "David S. Miller" <davem@davemloft.net>
L: sparclinux@vger.kernel.org
@@ -19503,6 +19626,16 @@ S: Maintained
F: Documentation/hwmon/stpddc60.rst
F: drivers/hwmon/pmbus/stpddc60.c
+ST VGXY61 DRIVER
+M: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
+M: Sylvain Petinot <sylvain.petinot@foss.st.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml
+F: Documentation/userspace-api/media/drivers/st-vgxy61.rst
+F: drivers/media/i2c/st-vgxy61.c
+
ST VL53L0X ToF RANGER(I2C) IIO DRIVER
M: Song Qiang <songqiang1304521@gmail.com>
L: linux-iio@vger.kernel.org
@@ -19518,6 +19651,7 @@ S: Supported
F: Documentation/process/stable-kernel-rules.rst
STAGING - ATOMISP DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
M: Mauro Carvalho Chehab <mchehab@kernel.org>
R: Sakari Ailus <sakari.ailus@linux.intel.com>
L: linux-media@vger.kernel.org
@@ -19601,6 +19735,11 @@ M: Ion Badulescu <ionut@badula.org>
S: Odd Fixes
F: drivers/net/ethernet/adaptec/starfire*
+STARFIVE DEVICETREES
+M: Emil Renner Berthing <kernel@esmil.dk>
+S: Maintained
+F: arch/riscv/boot/dts/starfive/
+
STARFIVE JH7100 CLOCK DRIVERS
M: Emil Renner Berthing <kernel@esmil.dk>
S: Maintained
@@ -19973,6 +20112,7 @@ F: drivers/clk/clk-sc[mp]i.c
F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
+F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
F: drivers/reset/reset-scmi.c
F: include/linux/sc[mp]i_protocol.h
@@ -21721,6 +21861,12 @@ F: include/linux/virtio*.h
F: include/uapi/linux/virtio_*.h
F: tools/virtio/
+VISL VIRTUAL STATELESS DECODER DRIVER
+M: Daniel Almeida <daniel.almeida@collabora.com>
+L: linux-media@vger.kernel.org
+S: Supported
+F: drivers/media/test-drivers/visl
+
IFCVF VIRTIO DATA PATH ACCELERATOR
R: Zhu Lingshan <lingshan.zhu@intel.com>
F: drivers/vdpa/ifcvf/
diff --git a/Makefile b/Makefile
index ac2ec990422d..bb60045526c4 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 6
PATCHLEVEL = 1
SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION =
NAME = Hurr durr I'ma ninja sloth
# *DOCUMENTATION*
@@ -562,7 +562,7 @@ KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE
KBUILD_CFLAGS := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE \
-Werror=implicit-function-declaration -Werror=implicit-int \
- -Werror=return-type -Wno-format-security \
+ -Werror=return-type -Wno-format-security -funsigned-char \
-std=gnu11
KBUILD_CPPFLAGS := -D__KERNEL__
KBUILD_RUSTFLAGS := $(rust_common_flags) \
@@ -966,8 +966,10 @@ LDFLAGS_vmlinux += --gc-sections
endif
ifdef CONFIG_SHADOW_CALL_STACK
+ifndef CONFIG_DYNAMIC_SCS
CC_FLAGS_SCS := -fsanitize=shadow-call-stack
KBUILD_CFLAGS += $(CC_FLAGS_SCS)
+endif
export CC_FLAGS_SCS
endif
@@ -1785,7 +1787,7 @@ $(help-board-dirs): help-%:
# Documentation targets
# ---------------------------------------------------------------------------
DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \
- linkcheckdocs dochelp refcheckdocs
+ linkcheckdocs dochelp refcheckdocs texinfodocs infodocs
PHONY += $(DOC_TARGETS)
$(DOC_TARGETS):
$(Q)$(MAKE) $(build)=Documentation $@
@@ -2001,7 +2003,9 @@ clean: $(clean-dirs)
@find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
\( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '*.ko.*' \
- -o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
+ -o -name '*.dtb' -o -name '*.dtbo' \
+ -o -name '*.dtb.S' -o -name '*.dtbo.S' \
+ -o -name '*.dt.yaml' \
-o -name '*.dwo' -o -name '*.lst' \
-o -name '*.su' -o -name '*.mod' -o -name '*.usyms' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
diff --git a/arch/Kconfig b/arch/Kconfig
index 8f138e580d1a..2d0e7099eb3f 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -468,6 +468,9 @@ config ARCH_WANT_IRQS_OFF_ACTIVATE_MM
config ARCH_HAVE_NMI_SAFE_CMPXCHG
bool
+config ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
+ bool
+
config HAVE_ALIGNED_STRUCT_PAGE
bool
help
@@ -651,6 +654,13 @@ config SHADOW_CALL_STACK
reading and writing arbitrary memory may be able to locate them
and hijack control flow by modifying the stacks.
+config DYNAMIC_SCS
+ bool
+ help
+ Set by the arch code if it relies on code patching to insert the
+ shadow call stack push and pop instructions rather than on the
+ compiler.
+
config LTO
bool
help
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index 8049997fa372..e6da23f1da83 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -120,12 +120,6 @@ extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task);
#define ELF_CORE_COPY_TASK_REGS(TASK, DEST) \
dump_elf_task(*(DEST), TASK)
-/* Similar, but for the FP registers. */
-
-extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task);
-#define ELF_CORE_COPY_FPREGS(TASK, DEST) \
- dump_elf_task_fp(*(DEST), TASK)
-
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This is trivial on Alpha,
but not so on other machines. */
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index df5f317ab3fc..3557ce64ed21 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -16,7 +16,6 @@
#define current_pt_regs() \
((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
-#define signal_pt_regs current_pt_regs
#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index fdc485d7787a..082631465074 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -75,11 +75,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
/* Work to do on interrupt/exception return. */
#define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
- _TIF_NOTIFY_RESUME)
-
-/* Work to do on any return to userspace. */
-#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
- | _TIF_SYSCALL_TRACE)
+ _TIF_NOTIFY_RESUME | _TIF_NOTIFY_SIGNAL)
#define TS_UAC_NOPRINT 0x0001 /* ! Preserve the following three */
#define TS_UAC_NOFIX 0x0002 /* ! flags as they match */
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index e227f3a29a43..a6207c47f089 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -469,13 +469,16 @@ entSys:
#ifdef CONFIG_AUDITSYSCALL
lda $6, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
and $3, $6, $3
-#endif
bne $3, strace
+#else
+ blbs $3, strace /* check for SYSCALL_TRACE in disguise */
+#endif
beq $4, 1f
ldq $27, 0($5)
1: jsr $26, ($27), sys_ni_syscall
ldgp $gp, 0($26)
blt $0, $syscall_error /* the call failed */
+$ret_success:
stq $0, 0($sp)
stq $31, 72($sp) /* a3=0 => no error */
@@ -525,11 +528,6 @@ $syscall_error:
stq $1, 72($sp) /* a3 for return */
br ret_from_sys_call
-$ret_success:
- stq $0, 0($sp)
- stq $31, 72($sp) /* a3=0 => no error */
- br ret_from_sys_call
-
/*
* Do all cleanup when returning from all interrupts and system calls.
*
@@ -598,8 +596,8 @@ ret_from_straced:
/* check return.. */
blt $0, $strace_error /* the call failed */
- stq $31, 72($sp) /* a3=0 => no error */
$strace_success:
+ stq $31, 72($sp) /* a3=0 => no error */
stq $0, 0($sp) /* save return value */
DO_SWITCH_STACK
@@ -768,7 +766,7 @@ alpha_switch_to:
.align 4
.ent ret_from_fork
ret_from_fork:
- lda $26, ret_from_sys_call
+ lda $26, ret_to_user
mov $17, $16
jmp $31, schedule_tail
.end ret_from_fork
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index dbf1bc5e2ad2..65fdae9e48f3 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -333,14 +333,12 @@ dump_elf_task(elf_greg_t *dest, struct task_struct *task)
}
EXPORT_SYMBOL(dump_elf_task);
-int
-dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
- struct switch_stack *sw = (struct switch_stack *)task_pt_regs(task) - 1;
- memcpy(dest, sw->fp, 32 * 8);
+ struct switch_stack *sw = (struct switch_stack *)task_pt_regs(t) - 1;
+ memcpy(fpu, sw->fp, 32 * 8);
return 1;
}
-EXPORT_SYMBOL(dump_elf_task_fp);
/*
* Return saved PC of a blocked thread. This assumes the frame
diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c
index da7542cea0d8..2abdcd9b09e8 100644
--- a/arch/arc/kernel/ptrace.c
+++ b/arch/arc/kernel/ptrace.c
@@ -185,7 +185,7 @@ static int genregs_set(struct task_struct *target,
#define REG_IGNORE_ONE(LOC) \
if (!ret) \
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
offsetof(struct user_regs_struct, LOC), \
offsetof(struct user_regs_struct, LOC) + 4);
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 6aa7dc4db2fc..d08a3c450ce7 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -129,6 +129,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4709-tplink-archer-c9-v1.dtb \
bcm47094-asus-rt-ac88u.dtb \
bcm47094-dlink-dir-885l.dtb \
+ bcm47094-dlink-dir-890l.dtb \
bcm47094-linksys-panamera.dtb \
bcm47094-luxul-abr-4500.dtb \
bcm47094-luxul-xap-1610.dtb \
@@ -139,6 +140,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm47094-netgear-r8500.dtb \
bcm47094-phicomm-k3.dtb \
bcm53015-meraki-mr26.dtb \
+ bcm53016-dlink-dwl-8610ap.dtb \
bcm53016-meraki-mr32.dtb \
bcm94708.dtb \
bcm94709.dtb \
@@ -355,6 +357,7 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \
kirkwood-ns2mini.dtb \
kirkwood-nsa310.dtb \
kirkwood-nsa310a.dtb \
+ kirkwood-nsa310s.dtb \
kirkwood-nsa320.dtb \
kirkwood-nsa325.dtb \
kirkwood-openblocks_a6.dtb \
@@ -681,6 +684,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6s-dhcom-drc02.dtb
dtb-$(CONFIG_SOC_IMX6SL) += \
imx6sl-evk.dtb \
+ imx6sl-kobo-aura2.dtb \
imx6sl-tolino-shine2hd.dtb \
imx6sl-tolino-shine3.dtb \
imx6sl-tolino-vision5.dtb \
@@ -1029,7 +1033,9 @@ dtb-$(CONFIG_ARCH_OXNAS) += \
dtb-$(CONFIG_ARCH_QCOM) += \
qcom-apq8016-sbc.dtb \
qcom-apq8026-asus-sparrow.dtb \
+ qcom-apq8026-huawei-sturgeon.dtb \
qcom-apq8026-lg-lenok.dtb \
+ qcom-apq8026-samsung-matisse-wifi.dtb \
qcom-apq8060-dragonboard.dtb \
qcom-apq8064-cm-qs600.dtb \
qcom-apq8064-ifc6410.dtb \
@@ -1059,6 +1065,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-msm8974-sony-xperia-rhine-amami.dtb \
qcom-msm8974-sony-xperia-rhine-honami.dtb \
qcom-msm8974pro-fairphone-fp2.dtb \
+ qcom-msm8974pro-oneplus-bacon.dtb \
qcom-msm8974pro-samsung-klte.dtb \
qcom-msm8974pro-sony-xperia-shinano-castor.dtb \
qcom-mdm9615-wp8548-mangoh-green.dtb \
@@ -1214,6 +1221,7 @@ dtb-$(CONFIG_ARCH_STM32) += \
stm32mp151a-prtt1a.dtb \
stm32mp151a-prtt1c.dtb \
stm32mp151a-prtt1s.dtb \
+ stm32mp151a-dhcor-testbench.dtb \
stm32mp153c-dhcom-drc02.dtb \
stm32mp153c-dhcor-drc-compact.dtb \
stm32mp157a-avenger96.dtb \
@@ -1454,6 +1462,8 @@ dtb-$(CONFIG_ARCH_UNIPHIER) += \
uniphier-pro4-ace.dtb \
uniphier-pro4-ref.dtb \
uniphier-pro4-sanji.dtb \
+ uniphier-pro5-epcore.dtb \
+ uniphier-pro5-proex.dtb \
uniphier-pxs2-gentil.dtb \
uniphier-pxs2-vodka.dtb \
uniphier-sld8-ref.dtb
@@ -1588,6 +1598,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-asrock-e3c246d4i.dtb \
aspeed-bmc-asrock-romed8hm3.dtb \
aspeed-bmc-bytedance-g220a.dtb \
+ aspeed-bmc-delta-ahe50dc.dtb \
aspeed-bmc-facebook-bletchley.dtb \
aspeed-bmc-facebook-cloudripper.dtb \
aspeed-bmc-facebook-cmm.dtb \
@@ -1601,6 +1612,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-facebook-wedge400.dtb \
aspeed-bmc-facebook-yamp.dtb \
aspeed-bmc-facebook-yosemitev2.dtb \
+ aspeed-bmc-ibm-bonnell.dtb \
aspeed-bmc-ibm-everest.dtb \
aspeed-bmc-ibm-rainier.dtb \
aspeed-bmc-ibm-rainier-1s4u.dtb \
@@ -1612,7 +1624,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-lenovo-hr855xg2.dtb \
aspeed-bmc-microsoft-olympus.dtb \
aspeed-bmc-opp-lanyang.dtb \
- aspeed-bmc-opp-mihawk.dtb \
aspeed-bmc-opp-mowgli.dtb \
aspeed-bmc-opp-nicole.dtb \
aspeed-bmc-opp-palmetto.dtb \
diff --git a/arch/arm/boot/dts/am335x-baltos-leds.dtsi b/arch/arm/boot/dts/am335x-baltos-leds.dtsi
index 9a79f727baf6..025014657d12 100644
--- a/arch/arm/boot/dts/am335x-baltos-leds.dtsi
+++ b/arch/arm/boot/dts/am335x-baltos-leds.dtsi
@@ -17,18 +17,18 @@
compatible = "gpio-leds";
- power {
+ led-power {
label = "onrisc:red:power";
linux,default-trigger = "default-on";
gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
default-state = "on";
};
- wlan {
+ led-wlan {
label = "onrisc:blue:wlan";
gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- app {
+ led-app {
label = "onrisc:green:app";
gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
default-state = "off";
diff --git a/arch/arm/boot/dts/am335x-boneblack-hdmi.dtsi b/arch/arm/boot/dts/am335x-boneblack-hdmi.dtsi
index 7cfddada9348..486f24deb875 100644
--- a/arch/arm/boot/dts/am335x-boneblack-hdmi.dtsi
+++ b/arch/arm/boot/dts/am335x-boneblack-hdmi.dtsi
@@ -85,8 +85,13 @@
audio-ports = < TDA998x_I2S 0x03>;
ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
port@0 {
- hdmi_0: endpoint@0 {
+ reg = <0>;
+
+ hdmi_0: endpoint {
remote-endpoint = <&lcdc_0>;
};
};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 25c6ac9913d2..5beabaa5ff6a 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -126,7 +126,7 @@
backlight = <&backlight>;
port {
- panel_0: endpoint@0 {
+ panel_0: endpoint {
remote-endpoint = <&lcdc_0>;
};
};
@@ -544,7 +544,7 @@
#size-cells = <1>;
partition@0 {
label = "NAND.SPL";
- reg = <0x00000000 0x000020000>;
+ reg = <0x00000000 0x00020000>;
};
partition@1 {
label = "NAND.SPL.backup1";
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 9c458e5a95b7..5b3278c0c46a 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -191,7 +191,7 @@
backlight = <&lcd_bl>;
port {
- panel_0: endpoint@0 {
+ panel_0: endpoint {
remote-endpoint = <&lcdc_0>;
};
};
diff --git a/arch/arm/boot/dts/am335x-guardian.dts b/arch/arm/boot/dts/am335x-guardian.dts
index f6356266564c..b357364e93f9 100644
--- a/arch/arm/boot/dts/am335x-guardian.dts
+++ b/arch/arm/boot/dts/am335x-guardian.dts
@@ -103,8 +103,9 @@
};
- guardian_beeper: dmtimer-pwm@7 {
+ guardian_beeper: pwm-7 {
compatible = "ti,omap-dmtimer-pwm";
+ #pwm-cells = <3>;
ti,timers = <&timer7>;
pinctrl-names = "default";
pinctrl-0 = <&guardian_beeper_pins>;
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index cc14415a4eb9..3fddf80dcf71 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -168,7 +168,7 @@
/* MTD partition table */
partition@0 {
label = "SPL";
- reg = <0x00000000 0x000080000>;
+ reg = <0x00000000 0x00080000>;
};
partition@1 {
@@ -188,7 +188,7 @@
partition@4 {
label = "File System";
- reg = <0x00780000 0x007880000>;
+ reg = <0x00780000 0x07880000>;
};
};
};
diff --git a/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi b/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi
index 7b40ca9483ca..49e280b42442 100644
--- a/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi
+++ b/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi
@@ -16,11 +16,11 @@
/* Power supply provides a fixed 3.3V @3A */
vmmcsd_fixed: vmmcsd-regulator {
- compatible = "regulator-fixed";
- regulator-name = "vmmcsd_fixed";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
};
buttons: push_button {
diff --git a/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi b/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi
index e0364adb8393..7d00e8b20f18 100644
--- a/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi
+++ b/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi
@@ -21,11 +21,11 @@
/* Power supply provides a fixed 3.3V @3A */
vmmcsd_fixed: vmmcsd-regulator {
- compatible = "regulator-fixed";
- regulator-name = "vmmcsd_fixed";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
};
buttons: push_button {
diff --git a/arch/arm/boot/dts/am335x-myirtech-myd.dts b/arch/arm/boot/dts/am335x-myirtech-myd.dts
index 9d81d4cc6890..425ad9b81a68 100644
--- a/arch/arm/boot/dts/am335x-myirtech-myd.dts
+++ b/arch/arm/boot/dts/am335x-myirtech-myd.dts
@@ -161,8 +161,13 @@
#sound-dai-cells = <0>;
ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
port@0 {
- hdmi_0: endpoint@0 {
+ reg = <0>;
+
+ hdmi_0: endpoint {
remote-endpoint = <&lcdc_0>;
};
};
diff --git a/arch/arm/boot/dts/am335x-pcm-953.dtsi b/arch/arm/boot/dts/am335x-pcm-953.dtsi
index dae448040a97..947497413977 100644
--- a/arch/arm/boot/dts/am335x-pcm-953.dtsi
+++ b/arch/arm/boot/dts/am335x-pcm-953.dtsi
@@ -12,22 +12,20 @@
compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx";
/* Power */
- regulators {
- vcc3v3: fixedregulator@1 {
- compatible = "regulator-fixed";
- regulator-name = "vcc3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
+ vcc3v3: fixedregulator1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
- vcc1v8: fixedregulator@2 {
- compatible = "regulator-fixed";
- regulator-name = "vcc1v8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-boot-on;
- };
+ vcc1v8: fixedregulator2 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
};
/* User IO */
diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
index 8691eec33b61..a4509e9e1056 100644
--- a/arch/arm/boot/dts/am335x-pepper.dts
+++ b/arch/arm/boot/dts/am335x-pepper.dts
@@ -555,11 +555,11 @@
};
&usb0 {
- dr_mode = "host";
+ dr_mode = "host";
};
&usb1 {
- dr_mode = "host";
+ dr_mode = "host";
};
&am33xx_pinmux {
diff --git a/arch/arm/boot/dts/am335x-pocketbeagle.dts b/arch/arm/boot/dts/am335x-pocketbeagle.dts
index 5e415d8ffdd8..0ba4883cd4ef 100644
--- a/arch/arm/boot/dts/am335x-pocketbeagle.dts
+++ b/arch/arm/boot/dts/am335x-pocketbeagle.dts
@@ -23,28 +23,28 @@
compatible = "gpio-leds";
- usr0 {
+ led-usr0 {
label = "beaglebone:green:usr0";
gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
- usr1 {
+ led-usr1 {
label = "beaglebone:green:usr1";
gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc0";
default-state = "off";
};
- usr2 {
+ led-usr2 {
label = "beaglebone:green:usr2";
gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "cpu0";
default-state = "off";
};
- usr3 {
+ led-usr3 {
label = "beaglebone:green:usr3";
gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
default-state = "off";
diff --git a/arch/arm/boot/dts/am3517-evm.dts b/arch/arm/boot/dts/am3517-evm.dts
index 35b653014f2b..11618aa501fc 100644
--- a/arch/arm/boot/dts/am3517-evm.dts
+++ b/arch/arm/boot/dts/am3517-evm.dts
@@ -26,12 +26,12 @@
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vmmc_fixed: vmmc {
- compatible = "regulator-fixed";
- regulator-name = "vmmc_fixed";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
+ vmmc_fixed: vmmc {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
gpio-keys {
compatible = "gpio-keys-polled";
@@ -150,7 +150,7 @@
enable-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* gpio_182 */
};
- pwm11: dmtimer-pwm@11 {
+ pwm11: pwm-11 {
compatible = "ti,omap-dmtimer-pwm";
pinctrl-names = "default";
pinctrl-0 = <&pwm_pins>;
@@ -176,7 +176,7 @@
};
&davinci_mdio {
- status = "okay";
+ status = "okay";
};
&dss {
@@ -227,7 +227,7 @@
};
&mmc3 {
- status = "disabled";
+ status = "disabled";
};
&usbhshost {
diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi
index cb316135bc7c..823f63502e9f 100644
--- a/arch/arm/boot/dts/am3517.dtsi
+++ b/arch/arm/boot/dts/am3517.dtsi
@@ -49,13 +49,35 @@
};
ocp@68000000 {
- am35x_otg_hs: am35x_otg_hs@5c040000 {
- compatible = "ti,omap3-musb";
- ti,hwmods = "am35x_otg_hs";
- status = "disabled";
- reg = <0x5c040000 0x1000>;
- interrupts = <71>;
- interrupt-names = "mc";
+ target-module@5c040000 {
+ compatible = "ti,sysc-omap2", "ti,sysc";
+ reg = <0x5c040400 0x4>,
+ <0x5c040404 0x4>,
+ <0x5c040408 0x4>;
+ reg-names = "rev", "sysc", "syss";
+ ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP |
+ SYSC_OMAP2_SOFTRESET |
+ SYSC_OMAP2_AUTOIDLE)>;
+ ti,sysc-midle = <SYSC_IDLE_FORCE>,
+ <SYSC_IDLE_NO>,
+ <SYSC_IDLE_SMART>;
+ ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+ <SYSC_IDLE_NO>,
+ <SYSC_IDLE_SMART>;
+ ti,syss-mask = <1>;
+ clocks = <&hsotgusb_ick_am35xx>;
+ clock-names = "fck";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x5c040000 0x1000>;
+
+ am35x_otg_hs: am35x_otg_hs@0 {
+ compatible = "ti,omap3-musb";
+ status = "disabled";
+ reg = <0 0x1000>;
+ interrupts = <71>;
+ interrupt-names = "mc";
+ };
};
davinci_emac: ethernet@5c000000 {
@@ -154,7 +176,7 @@
};
/* Table Table 5-79 of the TRM shows 480ab000 is reserved */
-&usb_otg_hs {
+&usb_otg_target {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
index 123a95f87554..e46cf2a9d075 100644
--- a/arch/arm/boot/dts/am437x-idk-evm.dts
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -452,7 +452,7 @@
*/
partition@0 {
label = "QSPI.U_BOOT";
- reg = <0x00000000 0x000080000>;
+ reg = <0x00000000 0x00080000>;
};
partition@1 {
label = "QSPI.U_BOOT.backup";
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 036f3831dc26..511a02e13e2c 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -763,7 +763,7 @@
*/
partition@0 {
label = "QSPI.U_BOOT";
- reg = <0x00000000 0x000080000>;
+ reg = <0x00000000 0x00080000>;
};
partition@1 {
label = "QSPI.U_BOOT.backup";
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 27f4ce855549..9fc915a2582e 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -919,7 +919,7 @@
*/
partition@0 {
label = "QSPI.U_BOOT";
- reg = <0x00000000 0x000080000>;
+ reg = <0x00000000 0x00080000>;
};
partition@1 {
label = "QSPI.U_BOOT.backup";
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index c06eda817242..7f092a8811e8 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -542,7 +542,7 @@
*/
partition@0 {
label = "QSPI.SPL";
- reg = <0x00000000 0x000040000>;
+ reg = <0x00000000 0x00040000>;
};
partition@1 {
label = "QSPI.u-boot";
diff --git a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
index 2008c6eaaa52..561195b749eb 100644
--- a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
+++ b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
@@ -86,19 +86,19 @@
pinctrl-names = "default";
- sata-r-amber-pin {
+ led-sata-r-amber {
label = "dns327l:amber:sata-r";
gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>;
default-state = "keep";
};
- sata-l-amber-pin {
+ led-sata-l-amber {
label = "dns327l:amber:sata-l";
gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
default-state = "keep";
};
- backup-led-pin {
+ led-backup {
label = "dns327l:white:usb";
gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
default-state = "keep";
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index b0b640b7de40..079b37cf148a 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -85,11 +85,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <8192>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <8192>;
+ };
};
gpio-leds {
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index 85e2e9e27a9f..d752ac1d7b58 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -94,11 +94,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <8192>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <8192>;
+ };
};
gpio-leds {
diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index 6ba7699b69ed..be005c9f42ef 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -61,8 +61,8 @@
status = "okay";
phy-mode = "rgmii-id";
fixed-link {
- speed = <1000>;
- full-duplex;
+ speed = <1000>;
+ full-duplex;
};
};
@@ -155,18 +155,18 @@
};
port@1 {
- reg = <1>;
- label = "lan1";
+ reg = <1>;
+ label = "lan1";
};
port@2 {
- reg = <2>;
- label = "lan2";
+ reg = <2>;
+ label = "lan2";
};
port@3 {
- reg = <3>;
- label = "lan3";
+ reg = <3>;
+ label = "lan3";
};
port@5 {
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts b/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts
index 3cf70c72c5ca..9cb69999b1db 100644
--- a/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts
@@ -72,11 +72,11 @@
};
gpio-leds {
- red-sata2 {
+ led-red-sata2 {
label = "dart:red:sata2";
gpios = <&pca9554 0 GPIO_ACTIVE_LOW>;
};
- red-sata3 {
+ led-red-sata3 {
label = "dart:red:sata3";
gpios = <&pca9554 3 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
index 866b8630d407..822f10734946 100644
--- a/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
@@ -132,21 +132,21 @@
gpio-leds {
compatible = "gpio-leds";
- white-power {
+ led-white-power {
label = "dart:white:power";
gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
};
- red-power {
+ led-red-power {
label = "dart:red:power";
gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>;
};
- red-sata0 {
+ led-red-sata0 {
label = "dart:red:sata0";
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
};
- red-sata1 {
+ led-red-sata1 {
label = "dart:red:sata1";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
index 702a85af2078..124a8ba279e3 100644
--- a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
+++ b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
@@ -107,7 +107,7 @@
gpio-leds {
compatible = "gpio-leds";
- red-sata0 {
+ led-red-sata0 {
label = "cumulus:red:sata0";
gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
default-state = "off";
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
index e72b8ed4b997..f0893cc06607 100644
--- a/arch/arm/boot/dts/armada-370-synology-ds213j.dts
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -91,9 +91,9 @@
};
ethernet@70000 {
- status = "okay";
- phy = <&phy1>;
- phy-mode = "sgmii";
+ status = "okay";
+ phy = <&phy1>;
+ phy-mode = "sgmii";
};
sata@a0000 {
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 9dc928859ad3..2013a5ccecd3 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -84,7 +84,7 @@
pcie2: pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x80000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index 929deaf312a5..c310ef26d1cc 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -592,7 +592,7 @@
pcie1: pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-380.dtsi b/arch/arm/boot/dts/armada-380.dtsi
index ce1dddb2269b..e94f22b0e9b5 100644
--- a/arch/arm/boot/dts/armada-380.dtsi
+++ b/arch/arm/boot/dts/armada-380.dtsi
@@ -89,7 +89,7 @@
/* x1 port */
pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -118,7 +118,7 @@
/* x1 port */
pcie@3,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
reg = <0x1800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-385-linksys-caiman.dts b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
index a03050c97084..88b2921fed55 100644
--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
@@ -62,11 +62,11 @@
};
&gpio_leds {
- power {
+ led-power {
label = "caiman:white:power";
};
- sata {
+ led-sata {
label = "caiman:white:sata";
};
};
diff --git a/arch/arm/boot/dts/armada-385-linksys-cobra.dts b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
index e3e4877a6f49..88200f930d0d 100644
--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
@@ -62,11 +62,11 @@
};
&gpio_leds {
- power {
+ led-power {
label = "cobra:white:power";
};
- sata {
+ led-sata {
label = "cobra:white:sata";
};
};
diff --git a/arch/arm/boot/dts/armada-385-linksys-rango.dts b/arch/arm/boot/dts/armada-385-linksys-rango.dts
index 3c4af57ec2b9..4ab45f294de2 100644
--- a/arch/arm/boot/dts/armada-385-linksys-rango.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-rango.dts
@@ -54,22 +54,22 @@
};
&gpio_leds {
- power {
+ led-power {
gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
label = "rango:white:power";
};
- sata {
+ led-sata {
gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
label = "rango:white:sata";
};
- wlan_2g {
+ led-wlan_2g {
gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
label = "rango:white:wlan_2g";
};
- wlan_5g {
+ led-wlan_5g {
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
label = "rango:white:wlan_5g";
};
diff --git a/arch/arm/boot/dts/armada-385-linksys-shelby.dts b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
index 3451cd3e5dff..f1b1f22413f1 100644
--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
@@ -62,11 +62,11 @@
};
&gpio_leds {
- power {
+ led-power {
label = "shelby:white:power";
};
- sata {
+ led-sata {
label = "shelby:white:sata";
};
};
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index 116aca5e688f..85e8d966f6c1 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -71,12 +71,12 @@
pinctrl-0 = <&gpio_leds_pins>;
pinctrl-names = "default";
- power {
+ led-power {
gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
- sata {
+ led-sata {
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
default-state = "off";
linux,default-trigger = "disk-activity";
diff --git a/arch/arm/boot/dts/armada-385-synology-ds116.dts b/arch/arm/boot/dts/armada-385-synology-ds116.dts
index 2622af73c9da..ea91ff964d94 100644
--- a/arch/arm/boot/dts/armada-385-synology-ds116.dts
+++ b/arch/arm/boot/dts/armada-385-synology-ds116.dts
@@ -149,7 +149,7 @@
* sata0, and accesses to SATA disk 0 make it blink so it
* doesn't need to be declared here.
*/
- orange {
+ led-orange {
gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
label = "ds116:orange:disk";
default-state = "off";
diff --git a/arch/arm/boot/dts/armada-385-turris-omnia.dts b/arch/arm/boot/dts/armada-385-turris-omnia.dts
index 72ac807cae25..0c1f238e4c30 100644
--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts
+++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts
@@ -23,6 +23,12 @@
stdout-path = &uart0;
};
+ aliases {
+ ethernet0 = &eth0;
+ ethernet1 = &eth1;
+ ethernet2 = &eth2;
+ };
+
memory {
device_type = "memory";
reg = <0x00000000 0x40000000>; /* 1024 MB */
@@ -483,7 +489,17 @@
};
};
- /* port 6 is connected to eth0 */
+ ports@6 {
+ reg = <6>;
+ label = "cpu";
+ ethernet = <&eth0>;
+ phy-mode = "rgmii-id";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/armada-385.dtsi b/arch/arm/boot/dts/armada-385.dtsi
index 83392b92dae2..be8d607c59b2 100644
--- a/arch/arm/boot/dts/armada-385.dtsi
+++ b/arch/arm/boot/dts/armada-385.dtsi
@@ -93,7 +93,7 @@
/* x1 port */
pcie2: pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -121,7 +121,7 @@
/* x1 port */
pcie3: pcie@3,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
reg = <0x1800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -152,7 +152,7 @@
*/
pcie4: pcie@4,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+ assigned-addresses = <0x82002000 0 0x48000 0 0x2000>;
reg = <0x2000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 446861b6b17b..12933eff419f 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -304,7 +304,7 @@
};
gpio0: gpio@18100 {
- compatible = "marvell,armada-370-gpio",
+ compatible = "marvell,armadaxp-gpio",
"marvell,orion-gpio";
reg = <0x18100 0x40>, <0x181c0 0x08>;
reg-names = "gpio", "pwm";
@@ -323,7 +323,7 @@
};
gpio1: gpio@18140 {
- compatible = "marvell,armada-370-gpio",
+ compatible = "marvell,armadaxp-gpio",
"marvell,orion-gpio";
reg = <0x18140 0x40>, <0x181c8 0x08>;
reg-names = "gpio", "pwm";
diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi
index 923b035a3ab3..1e05208d9f34 100644
--- a/arch/arm/boot/dts/armada-39x.dtsi
+++ b/arch/arm/boot/dts/armada-39x.dtsi
@@ -213,7 +213,7 @@
};
gpio0: gpio@18100 {
- compatible = "marvell,orion-gpio";
+ compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio";
reg = <0x18100 0x40>;
ngpios = <32>;
gpio-controller;
@@ -227,7 +227,7 @@
};
gpio1: gpio@18140 {
- compatible = "marvell,orion-gpio";
+ compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio";
reg = <0x18140 0x40>;
ngpios = <28>;
gpio-controller;
@@ -463,7 +463,7 @@
/* x1 port */
pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -492,7 +492,7 @@
/* x1 port */
pcie@3,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
reg = <0x1800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -524,7 +524,7 @@
*/
pcie@4,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+ assigned-addresses = <0x82002000 0 0x48000 0 0x2000>;
reg = <0x2000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
index b21ffb819b1d..7a7e2066c498 100644
--- a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
+++ b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
@@ -296,6 +296,7 @@
compatible = "marvell,armada-xp-wdt";
clocks = <&coreclk 2>, <&refclk>;
clock-names = "nbclk", "fixed";
+ interrupts = <93>, <38>;
};
&cpurst {
diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 622ac40dd164..dbe8dfe236fb 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -195,7 +195,7 @@
pinctrl-0 = <&power_led_pin>;
pinctrl-names = "default";
- power {
+ led-power {
label = "mamba:white:power";
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
default-state = "on";
diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index bf9360f41e0a..5ea9d509cd30 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -107,7 +107,7 @@
pcie2: pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -135,7 +135,7 @@
pcie3: pcie@3,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+ assigned-addresses = <0x82001800 0 0x48000 0 0x2000>;
reg = <0x1800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -163,7 +163,7 @@
pcie4: pcie@4,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x4c000 0 0x2000>;
+ assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>;
reg = <0x2000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -191,7 +191,7 @@
pcie5: pcie@5,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
+ assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
reg = <0x2800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index 0714af52e607..6c6fbb9faf5a 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -122,7 +122,7 @@
pcie2: pcie@2,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -150,7 +150,7 @@
pcie3: pcie@3,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+ assigned-addresses = <0x82001800 0 0x48000 0 0x2000>;
reg = <0x1800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -178,7 +178,7 @@
pcie4: pcie@4,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x4c000 0 0x2000>;
+ assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>;
reg = <0x2000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -206,7 +206,7 @@
pcie5: pcie@5,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
+ assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
reg = <0x2800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -234,7 +234,7 @@
pcie6: pcie@6,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x84000 0 0x2000>;
+ assigned-addresses = <0x82003000 0 0x84000 0 0x2000>;
reg = <0x3000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -262,7 +262,7 @@
pcie7: pcie@7,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x88000 0 0x2000>;
+ assigned-addresses = <0x82003800 0 0x88000 0 0x2000>;
reg = <0x3800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -290,7 +290,7 @@
pcie8: pcie@8,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x8c000 0 0x2000>;
+ assigned-addresses = <0x82004000 0 0x8c000 0 0x2000>;
reg = <0x4000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
@@ -318,7 +318,7 @@
pcie9: pcie@9,0 {
device_type = "pci";
- assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
+ assigned-addresses = <0x82004800 0 0x42000 0 0x2000>;
reg = <0x4800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 8ea73587db81..31933f81144e 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -121,11 +121,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <32768>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
};
gpio-leds {
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 6c19984d668e..4297482da62f 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -260,6 +260,7 @@
compatible = "marvell,armada-xp-wdt";
clocks = <&coreclk 2>, <&refclk>;
clock-names = "nbclk", "fixed";
+ interrupts = <93>, <38>;
};
&cpurst {
diff --git a/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts b/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts
index d127cbcc7998..0a51d2e32fab 100644
--- a/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts
@@ -342,6 +342,10 @@
&i2c0 {
status = "okay";
+ ssif-bmc@10 {
+ compatible = "ssif-bmc";
+ reg = <0x10>;
+ };
};
&i2c1 {
@@ -350,6 +354,14 @@
&i2c2 {
status = "okay";
+ smpro@4f {
+ compatible = "ampere,smpro";
+ reg = <0x4f>;
+ };
+ smpro@4e {
+ compatible = "ampere,smpro";
+ reg = <0x4e>;
+ };
};
&i2c3 {
diff --git a/arch/arm/boot/dts/aspeed-bmc-ampere-mtmitchell.dts b/arch/arm/boot/dts/aspeed-bmc-ampere-mtmitchell.dts
index 606cd4be245a..4b91600eaf62 100644
--- a/arch/arm/boot/dts/aspeed-bmc-ampere-mtmitchell.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-ampere-mtmitchell.dts
@@ -445,6 +445,10 @@
&i2c11 {
status = "okay";
+ ssif-bmc@10 {
+ compatible = "ssif-bmc";
+ reg = <0x10>;
+ };
};
&i2c14 {
diff --git a/arch/arm/boot/dts/aspeed-bmc-delta-ahe50dc.dts b/arch/arm/boot/dts/aspeed-bmc-delta-ahe50dc.dts
new file mode 100644
index 000000000000..6600f7e9bf5e
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-delta-ahe50dc.dts
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+#include "aspeed-g4.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+#define EFUSE_OUTPUT(n) \
+ efuse##n { \
+ compatible = "regulator-output"; \
+ vout-supply = <&efuse##n>; \
+ }
+
+#define __stringify(x) #x
+
+#define EFUSE(hexaddr, num) \
+ efuse@##hexaddr { \
+ compatible = "lm25066"; \
+ reg = <0x##hexaddr>; \
+ shunt-resistor-micro-ohms = <675>; \
+ regulators { \
+ efuse##num: vout0 { \
+ regulator-name = __stringify(efuse##num##-reg); \
+ }; \
+ }; \
+ }
+
+/{
+ model = "Delta Power AHE-50DC";
+ compatible = "delta,ahe50dc-bmc", "aspeed,ast2400";
+
+ aliases {
+ serial4 = &uart5;
+
+ /*
+ * pca9541-arbitrated logical i2c buses are numbered as the
+ * corresponding physical bus plus 20
+ */
+ i2c20 = &i2carb0;
+ i2c21 = &i2carb1;
+ i2c22 = &i2carb2;
+ i2c23 = &i2carb3;
+ i2c24 = &i2carb4;
+ i2c26 = &i2carb6;
+ i2c27 = &i2carb7;
+ i2c28 = &i2carb8;
+ i2c32 = &i2carb12;
+ };
+
+ chosen {
+ stdout-path = &uart3;
+ bootargs = "console=ttyS2,115200n8 earlycon";
+ };
+
+ memory@40000000 {
+ reg = <0x40000000 0x10000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ heartbeat {
+ gpios = <&gpio ASPEED_GPIO(P, 0) GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ panic {
+ gpios = <&gpio ASPEED_GPIO(P, 2) GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "panic";
+ };
+ };
+
+ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>,
+ <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>, <&adc 9>;
+ };
+
+ EFUSE_OUTPUT(01);
+ EFUSE_OUTPUT(02);
+ EFUSE_OUTPUT(03);
+ EFUSE_OUTPUT(04);
+ EFUSE_OUTPUT(05);
+ EFUSE_OUTPUT(06);
+ EFUSE_OUTPUT(07);
+ EFUSE_OUTPUT(08);
+ EFUSE_OUTPUT(09);
+ EFUSE_OUTPUT(10);
+ EFUSE_OUTPUT(11);
+ EFUSE_OUTPUT(12);
+ EFUSE_OUTPUT(13);
+ EFUSE_OUTPUT(14);
+ EFUSE_OUTPUT(15);
+ EFUSE_OUTPUT(16);
+ EFUSE_OUTPUT(17);
+ EFUSE_OUTPUT(18);
+ EFUSE_OUTPUT(19);
+ EFUSE_OUTPUT(20);
+ EFUSE_OUTPUT(21);
+ EFUSE_OUTPUT(22);
+ EFUSE_OUTPUT(23);
+ EFUSE_OUTPUT(24);
+ EFUSE_OUTPUT(25);
+ EFUSE_OUTPUT(26);
+ EFUSE_OUTPUT(27);
+ EFUSE_OUTPUT(28);
+ EFUSE_OUTPUT(29);
+ EFUSE_OUTPUT(30);
+ EFUSE_OUTPUT(31);
+ EFUSE_OUTPUT(32);
+ EFUSE_OUTPUT(33);
+ EFUSE_OUTPUT(34);
+ EFUSE_OUTPUT(35);
+ EFUSE_OUTPUT(36);
+ EFUSE_OUTPUT(37);
+ EFUSE_OUTPUT(38);
+ EFUSE_OUTPUT(39);
+ EFUSE_OUTPUT(40);
+ EFUSE_OUTPUT(41);
+ EFUSE_OUTPUT(42);
+ EFUSE_OUTPUT(43);
+ EFUSE_OUTPUT(44);
+ EFUSE_OUTPUT(45);
+ EFUSE_OUTPUT(46);
+ EFUSE_OUTPUT(47);
+ EFUSE_OUTPUT(48);
+ EFUSE_OUTPUT(49);
+ EFUSE_OUTPUT(50);
+
+};
+
+&fmc {
+ status = "okay";
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "flash0";
+ spi-max-frequency = <50000000>; // 50 MHz
+#include "openbmc-flash-layout.dtsi"
+ };
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&mac1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&i2c0 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@79 {
+ compatible = "nxp,pca9541";
+ reg = <0x79>;
+
+ i2carb0: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* lm25066 efuses @ 10-17, 40-47, 50-57 */
+ EFUSE(10, 03);
+ EFUSE(11, 04);
+ EFUSE(12, 01);
+ EFUSE(13, 02);
+ EFUSE(14, 13);
+ EFUSE(15, 14);
+ EFUSE(16, 15);
+ EFUSE(17, 16);
+ EFUSE(40, 12);
+ EFUSE(41, 11);
+ EFUSE(42, 10);
+ EFUSE(43, 09);
+ EFUSE(44, 08);
+ EFUSE(45, 07);
+ EFUSE(46, 05);
+ EFUSE(47, 06);
+ EFUSE(50, 17);
+ EFUSE(51, 18);
+ EFUSE(52, 20);
+ EFUSE(53, 19);
+ EFUSE(54, 22);
+ EFUSE(55, 21);
+ EFUSE(56, 24);
+ EFUSE(57, 23);
+ };
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@72 {
+ compatible = "nxp,pca9541";
+ reg = <0x72>;
+
+ i2carb1: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&i2c2 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@73 {
+ compatible = "nxp,pca9541";
+ reg = <0x73>;
+
+ i2carb2: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&i2c3 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@74 {
+ compatible = "nxp,pca9541";
+ reg = <0x74>;
+
+ i2carb3: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&i2c4 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@7a {
+ compatible = "nxp,pca9541";
+ reg = <0x7a>;
+
+ i2carb4: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio@20 {
+ compatible = "nxp,pca9534";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ /* lm25066 efuses @ 10-17, 40-47, 50-57, 59, 5a */
+ EFUSE(10, 27);
+ EFUSE(11, 28);
+ EFUSE(12, 25);
+ EFUSE(13, 26);
+ EFUSE(14, 37);
+ EFUSE(15, 38);
+ EFUSE(16, 39);
+ EFUSE(17, 40);
+ EFUSE(40, 36);
+ EFUSE(41, 35);
+ EFUSE(42, 34);
+ EFUSE(43, 33);
+ EFUSE(44, 32);
+ EFUSE(45, 31);
+ EFUSE(46, 29);
+ EFUSE(47, 30);
+ EFUSE(50, 41);
+ EFUSE(51, 42);
+ EFUSE(52, 44);
+ EFUSE(53, 43);
+ EFUSE(54, 46);
+ EFUSE(55, 45);
+ EFUSE(56, 48);
+ EFUSE(57, 47);
+ EFUSE(59, 49);
+ EFUSE(5a, 50);
+ };
+ };
+};
+
+&i2c6 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@75 {
+ compatible = "nxp,pca9541";
+ reg = <0x75>;
+
+ i2carb6: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&i2c7 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@76 {
+ compatible = "nxp,pca9541";
+ reg = <0x76>;
+
+ i2carb7: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&i2c8 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@7c {
+ compatible = "nxp,pca9541";
+ reg = <0x7c>;
+
+ i2carb8: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fancontrol@30 {
+ compatible = "delta,ahe50dc-fan";
+ reg = <0x30>;
+ };
+
+ /* Baseboard FRU eeprom */
+ eeprom@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ };
+ };
+ };
+};
+
+&i2c12 {
+ status = "okay";
+ bus-frequency = <200000>;
+
+ pca9541@71 {
+ compatible = "nxp,pca9541";
+ reg = <0x71>;
+
+ i2carb12: i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&gpio {
+ status = "okay";
+ gpio-line-names =
+ /* A */ "", "", "", "", "", "", "", "",
+ /* B */ "", "", "", "", "", "", "", "",
+ /* C */ "RESET_PEER_N", "HEARTBEAT_OUT", "", "", "", "", "", "",
+ /* D */ "", "", "", "", "", "", "", "",
+ /* E */ "DOOM_N", "", "", "", "", "LED_PWR_BLUE", "", "",
+ /* F */ "", "", "", "", "", "", "", "",
+ /* G */ "", "", "", "", "", "", "", "",
+ /* H */ "", "", "", "", "", "", "", "",
+ /* I */ "", "", "", "", "", "", "", "",
+ /* J */ "", "", "BMC_ID", "", "", "", "", "",
+ /* K */ "", "", "", "", "", "", "", "",
+ /* L */ "", "", "", "", "", "", "", "",
+ /* M */ "", "", "", "", "", "", "", "",
+ /* N */ "", "", "", "", "", "", "", "",
+ /* O */ "", "", "", "", "", "", "", "",
+ /* P */ "LED_GREEN", "", "LED_RED", "", "", "", "", "",
+ /* Q */ "", "", "", "", "", "", "", "",
+ /* R */ "", "", "", "", "", "", "", "",
+ /* S */ "", "", "", "", "", "", "", "",
+ /* T */ "", "", "", "", "", "", "", "",
+ /* U */ "", "", "", "", "", "", "", "",
+ /* V */ "", "", "", "", "", "", "", "",
+ /* W */ "", "", "", "", "", "", "", "",
+ /* X */ "", "", "", "", "", "", "", "",
+ /* Y */ "HEARTBEAT_IN", "BOARDREV0", "BOARDREV1", "",
+ /* Z */ "", "", "", "", "", "", "", "",
+ /* AA */ "", "", "", "", "", "", "", "",
+ /* AB */ "", "", "", "";
+
+ /*
+ * I don't rightly know what this GPIO really *is*, but setting it to
+ * zero causes the fans to run at full speed, after which setting it
+ * back to one causes a power output glitch, so install a hog to keep
+ * it at one as a failsafe to ensure nothing accidentally touches it.
+ */
+ doom-guardrail {
+ gpio-hog;
+ gpios = <ASPEED_GPIO(E, 0) GPIO_ACTIVE_LOW>;
+ output-low;
+ };
+};
+
+&adc {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc0_default
+ &pinctrl_adc1_default
+ &pinctrl_adc2_default
+ &pinctrl_adc3_default
+ &pinctrl_adc4_default
+ &pinctrl_adc5_default
+ &pinctrl_adc6_default
+ &pinctrl_adc7_default
+ &pinctrl_adc8_default
+ &pinctrl_adc9_default>;
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts
index 1fc3e7cbf0d1..a619eec70633 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts
@@ -60,7 +60,7 @@
compatible = "gpio-leds";
sys_log_id {
default-state = "off";
- gpios = <&front_leds 0 GPIO_ACTIVE_HIGH>;
+ gpios = <&front_leds 0 GPIO_ACTIVE_LOW>;
};
};
@@ -191,6 +191,95 @@
gpios = <&sled6_leds 1 GPIO_ACTIVE_LOW>;
};
};
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ presence-sled1 {
+ label = "presence-sled1";
+ gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 2)>;
+ };
+ presence-sled2 {
+ label = "presence-sled2";
+ gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 3)>;
+ };
+ presence-sled3 {
+ label = "presence-sled3";
+ gpios = <&gpio0 ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 4)>;
+ };
+ presence-sled4 {
+ label = "presence-sled4";
+ gpios = <&gpio0 ASPEED_GPIO(H, 5) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 5)>;
+ };
+ presence-sled5 {
+ label = "presence-sled5";
+ gpios = <&gpio0 ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 6)>;
+ };
+ presence-sled6 {
+ label = "presence-sled6";
+ gpios = <&gpio0 ASPEED_GPIO(H, 7) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 7)>;
+ };
+ };
+
+ vbus_sled1: vbus_sled1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled1";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled1_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vbus_sled2: vbus_sled2 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled2";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled2_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vbus_sled3: vbus_sled3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled3";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled3_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vbus_sled4: vbus_sled4 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled4";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled4_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vbus_sled5: vbus_sled5 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled5";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled5_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vbus_sled6: vbus_sled6 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus_sled6";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&sled6_ioexp 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
&mac2 {
@@ -302,17 +391,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(B, 0) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled1>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -388,17 +477,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(B, 1) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled2>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -474,17 +563,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(B, 7) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled3>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -560,17 +649,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(S, 7) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled4>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -646,17 +735,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(Y, 3) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled5>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -732,17 +821,17 @@
compatible = "fcs,fusb302";
reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <ASPEED_GPIO(I, 7) IRQ_TYPE_LEVEL_LOW>;
+ vbus-supply = <&vbus_sled6>;
+
connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "dual";
- try-power-role = "sink";
- data-role = "dual";
- source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
- PDO_VAR(3000, 12000, 3000)
- PDO_PPS_APDO(3000, 11000, 3000)>;
- op-sink-microwatt = <10000000>;
+ power-role = "source";
+ data-role = "host";
+ pd-disable;
+ typec-power-opmode = "default";
};
};
@@ -863,6 +952,9 @@
};
&gpio0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpiov2_unbiased_default>;
+
gpio-line-names =
/*A0-A7*/ "","","","","","","","",
/*B0-B7*/ "FUSB302_SLED1_INT_N","FUSB302_SLED2_INT_N",
@@ -892,11 +984,11 @@
/*M0-M7*/ "ALERT_SLED1_N","ALERT_SLED2_N",
"ALERT_SLED3_N","ALERT_SLED4_N",
"ALERT_SLED5_N","ALERT_SLED6_N",
- "","",
+ "","USB_DEBUG_PWR_BTN_N",
/*N0-N7*/ "LED_POSTCODE_0","LED_POSTCODE_1",
"LED_POSTCODE_2","LED_POSTCODE_3",
"LED_POSTCODE_4","LED_POSTCODE_5",
- "LED_POSTCODE_5","LED_POSTCODE_7",
+ "LED_POSTCODE_6","LED_POSTCODE_7",
/*O0-O7*/ "","","","",
"","BOARD_ID0","BOARD_ID1","BOARD_ID2",
/*P0-P7*/ "","","","","","","","BMC_HEARTBEAT",
@@ -953,3 +1045,22 @@
&ehci0 {
status = "okay";
};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emmc_controller {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl_gpiov2_unbiased_default: gpiov2 {
+ pins = "AD14";
+ bias-disable;
+ };
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-cloudripper.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-cloudripper.dts
index 9c6271a17ae8..5cd060029ea9 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-cloudripper.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-cloudripper.dts
@@ -77,7 +77,7 @@
i2c55 = &imux55;
};
- spi_gpio: spi-gpio {
+ spi_gpio: spi {
num-chipselects = <2>;
cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>,
<&gpio0 ASPEED_GPIO(X, 1) GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-elbert.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-elbert.dts
index 8e1a1d1b282d..b5cd4c7800b0 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-elbert.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-elbert.dts
@@ -44,7 +44,7 @@
stdout-path = &uart5;
};
- spi_gpio: spi-gpio {
+ spi_gpio: spi {
num-chipselects = <1>;
cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts
index af58a73bbc49..6b319f34a9b9 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts
@@ -207,7 +207,7 @@
i2c143 = &imux143;
};
- spi_gpio: spi-gpio {
+ spi_gpio: spi {
num-chipselects = <3>;
cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>,
<0>, /* device reg=<1> does not exist */
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts
index a901c8be49b9..ed305948386f 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts
@@ -67,7 +67,7 @@
* full-duplex SPI transactions are not supported by ASPEED SPI
* Controllers.
*/
- spi_gpio: spi-gpio {
+ spi_gpio: spi {
status = "okay";
compatible = "spi-gpio";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-bonnell.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-bonnell.dts
new file mode 100644
index 000000000000..d1971ddf06a5
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-ibm-bonnell.dts
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2022 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/i2c/i2c.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+ model = "Bonnell";
+ compatible = "ibm,bonnell-bmc", "aspeed,ast2600";
+
+ aliases {
+ i2c100 = &cfam0_i2c0;
+ i2c101 = &cfam0_i2c1;
+ i2c110 = &cfam0_i2c10;
+ i2c111 = &cfam0_i2c11;
+ i2c112 = &cfam0_i2c12;
+ i2c113 = &cfam0_i2c13;
+ i2c114 = &cfam0_i2c14;
+ i2c115 = &cfam0_i2c15;
+ i2c202 = &cfam1_i2c2;
+ i2c203 = &cfam1_i2c3;
+ i2c210 = &cfam1_i2c10;
+ i2c211 = &cfam1_i2c11;
+ i2c214 = &cfam1_i2c14;
+ i2c215 = &cfam1_i2c15;
+ i2c216 = &cfam1_i2c16;
+ i2c217 = &cfam1_i2c17;
+
+ serial4 = &uart5;
+ i2c16 = &i2c11mux0chn0;
+ i2c17 = &i2c11mux0chn1;
+ i2c18 = &i2c11mux0chn2;
+ i2c19 = &i2c11mux0chn3;
+
+ spi10 = &cfam0_spi0;
+ spi11 = &cfam0_spi1;
+ spi12 = &cfam0_spi2;
+ spi13 = &cfam0_spi3;
+ spi20 = &cfam1_spi0;
+ spi21 = &cfam1_spi1;
+ spi22 = &cfam1_spi2;
+ spi23 = &cfam1_spi3;
+
+ };
+
+ chosen {
+ stdout-path = &uart5;
+ bootargs = "console=ttyS4,115200n8 earlycon";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ ramoops@b3e00000 {
+ compatible = "ramoops";
+ reg = <0xb3e00000 0x200000>; /* 16 * (4 * 0x8000) */
+ record-size = <0x8000>;
+ console-size = <0x8000>;
+ ftrace-size = <0x8000>;
+ pmsg-size = <0x8000>;
+ max-reason = <3>; /* KMSG_DUMP_EMERG */
+ };
+
+ /* LPC FW cycle bridge region requires natural alignment */
+ flash_memory: region@b4000000 {
+ no-map;
+ reg = <0xb4000000 0x04000000>; /* 64M */
+ };
+
+ /* VGA region is dictated by hardware strapping */
+ vga_memory: region@bf000000 {
+ no-map;
+ compatible = "shared-dma-pool";
+ reg = <0xbf000000 0x01000000>; /* 16M */
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ fan0 {
+ gpios = <&gpio0 ASPEED_GPIO(G, 0) GPIO_ACTIVE_LOW>;
+ };
+
+ fan1 {
+ gpios = <&gpio0 ASPEED_GPIO(G, 1) GPIO_ACTIVE_LOW>;
+ };
+
+ rear-enc-id0 {
+ gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>;
+ };
+
+ rear-enc-fault0 {
+ gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <1000>;
+
+ fan0-presence {
+ label = "fan0-presence";
+ gpios = <&gpio0 ASPEED_GPIO(F, 4) GPIO_ACTIVE_LOW>;
+ linux,code = <6>;
+ };
+
+ fan1-presence {
+ label = "fan1-presence";
+ gpios = <&gpio0 ASPEED_GPIO(F, 5) GPIO_ACTIVE_LOW>;
+ linux,code = <7>;
+ };
+ };
+
+ iio-hwmon-battery {
+ compatible = "iio-hwmon";
+ io-channels = <&adc1 7>;
+ };
+};
+
+&adc1 {
+ status = "okay";
+ aspeed,int-vref-microvolt = <2500000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default
+ &pinctrl_adc10_default &pinctrl_adc11_default
+ &pinctrl_adc12_default &pinctrl_adc13_default
+ &pinctrl_adc14_default &pinctrl_adc15_default>;
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&uhci {
+ status = "okay";
+};
+
+&gpio0 {
+ gpio-line-names =
+ /*A0-A7*/ "","","","","","","","",
+ /*B0-B7*/ "","","","","","","checkstop","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "","","","","","","","",
+ /*E0-E7*/ "","","","","","","","",
+ /*F0-F7*/ "","","rtc-battery-voltage-read-enable","reset-cause-pinhole","","","","",
+ /*G0-G7*/ "fan0","fan1","","","","","","",
+ /*H0-H7*/ "","","rear-enc-id0","rear-enc-fault0","","","","",
+ /*I0-I7*/ "","","","","","","bmc-secure-boot","",
+ /*J0-J7*/ "","","","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "","","","","","","","",
+ /*O0-O7*/ "","","","usb-power","","","","",
+ /*P0-P7*/ "","","","","","","","",
+ /*Q0-Q7*/ "cfam-reset","","regulator-standby-faulted","","","","","",
+ /*R0-R7*/ "bmc-tpm-reset","power-chassis-control","power-chassis-good","","","","","",
+ /*S0-S7*/ "presence-ps0","presence-ps1","","","power-ffs-sync-history","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","";
+
+ usb_power {
+ gpio-hog;
+ gpios = <ASPEED_GPIO(O, 3) GPIO_ACTIVE_LOW>;
+ output-high;
+ };
+};
+
+&emmc_controller {
+ status = "okay";
+};
+
+&pinctrl_emmc_default {
+ bias-disable;
+};
+
+&emmc {
+ status = "okay";
+ clk-phase-mmc-hs200 = <180>, <180>;
+};
+
+&fsim0 {
+ status = "okay";
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cfam-reset-gpios = <&gpio0 ASPEED_GPIO(Q, 0) GPIO_ACTIVE_HIGH>;
+
+ cfam@0,0 {
+ reg = <0 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <0>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ i2c@1800 {
+ compatible = "ibm,fsi-i2c-master";
+ reg = <0x1800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam0_i2c0: i2c-bus@0 {
+ reg = <0>; /* OMI01 */
+ };
+
+ cfam0_i2c1: i2c-bus@1 {
+ reg = <1>; /* OMI23 */
+ };
+
+ cfam0_i2c10: i2c-bus@a {
+ reg = <10>; /* OP3A */
+ };
+
+ cfam0_i2c11: i2c-bus@b {
+ reg = <11>; /* OP3B */
+ };
+
+ cfam0_i2c12: i2c-bus@c {
+ reg = <12>; /* OP4A */
+ };
+
+ cfam0_i2c13: i2c-bus@d {
+ reg = <13>; /* OP4B */
+ };
+
+ cfam0_i2c14: i2c-bus@e {
+ reg = <14>; /* OP5A */
+ };
+
+ cfam0_i2c15: i2c-bus@f {
+ reg = <15>; /* OP5B */
+ };
+ };
+
+ fsi2spi@1c00 {
+ compatible = "ibm,fsi2spi";
+ reg = <0x1c00 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam0_spi0: spi@0 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam0_spi1: spi@20 {
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam0_spi2: spi@40 {
+ reg = <0x40>;
+ compatible = "ibm,fsi2spi-restricted";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam0_spi3: spi@60 {
+ reg = <0x60>;
+ compatible = "ibm,fsi2spi-restricted";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ0: occ {
+ compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
+ };
+ };
+
+ fsi_hub0: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&fsi_hub0 {
+ cfam@1,0 {
+ reg = <1 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <1>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ i2c@1800 {
+ compatible = "ibm,fsi-i2c-master";
+ reg = <0x1800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam1_i2c2: i2c-bus@2 {
+ reg = <2>; /* OMI45 */
+ };
+
+ cfam1_i2c3: i2c-bus@3 {
+ reg = <3>; /* OMI67 */
+ };
+
+ cfam1_i2c10: i2c-bus@a {
+ reg = <10>; /* OP3A */
+ };
+
+ cfam1_i2c11: i2c-bus@b {
+ reg = <11>; /* OP3B */
+ };
+
+ cfam1_i2c14: i2c-bus@e {
+ reg = <14>; /* OP5A */
+ };
+
+ cfam1_i2c15: i2c-bus@f {
+ reg = <15>; /* OP5B */
+ };
+
+ cfam1_i2c16: i2c-bus@10 {
+ reg = <16>; /* OP6A */
+ };
+
+ cfam1_i2c17: i2c-bus@11 {
+ reg = <17>; /* OP6B */
+ };
+ };
+
+ fsi2spi@1c00 {
+ compatible = "ibm,fsi2spi";
+ reg = <0x1c00 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam1_spi0: spi@0 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam1_spi1: spi@20 {
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam1_spi2: spi@40 {
+ reg = <0x40>;
+ compatible = "ibm,fsi2spi-restricted";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+
+ cfam1_spi3: spi@60 {
+ reg = <0x60>;
+ compatible = "ibm,fsi2spi-restricted";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@0 {
+ at25,byte-len = <0x80000>;
+ at25,addr-mode = <4>;
+ at25,page-size = <256>;
+
+ compatible = "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ1: occ {
+ compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
+ };
+ };
+
+ fsi_hub1: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+};
+
+&ibt {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+
+ tca9554@20 {
+ compatible = "ti,tca9554";
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names = "",
+ "RUSSEL_FW_I2C_ENABLE_N",
+ "RUSSEL_OPPANEL_PRESENCE_N",
+ "BLYTH_OPPANEL_PRESENCE_N",
+ "CPU_TPM_CARD_PRESENT_N",
+ "",
+ "",
+ "DASD_BP_PRESENT_N";
+ };
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+
+ ucd90160@64 {
+ compatible = "ti,ucd90160";
+ reg = <0x64>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ power-supply@58 {
+ compatible = "ibm,cffps";
+ reg = <0x58>;
+ };
+
+ power-supply@59 {
+ compatible = "ibm,cffps";
+ reg = <0x59>;
+ };
+};
+
+&i2c4 {
+ status = "okay";
+};
+
+&i2c5 {
+ status = "okay";
+};
+
+&i2c6 {
+ status = "okay";
+};
+
+&i2c7 {
+ multi-master;
+ status = "okay";
+
+ si7021-a20@40 {
+ compatible = "silabs,si7020";
+ reg = <0x40>;
+ };
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+
+ max31785@52 {
+ compatible = "maxim,max31785a";
+ reg = <0x52>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fan0: fan@0 {
+ compatible = "pmbus-fan";
+ reg = <0>;
+ tach-pulses = <2>;
+ };
+
+ fan1: fan@1 {
+ compatible = "pmbus-fan";
+ reg = <1>;
+ tach-pulses = <2>;
+ };
+ };
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "front-sys-id0";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "front-check-log0";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@2 {
+ label = "front-enc-fault1";
+ reg = <2>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@3 {
+ label = "front-sys-pwron0";
+ reg = <3>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
+
+ ibm-panel@62 {
+ compatible = "ibm,op-panel";
+ reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>;
+ };
+
+ dps: dps310@76 {
+ compatible = "infineon,dps310";
+ reg = <0x76>;
+ #io-channel-cells = <0>;
+ };
+};
+
+&i2c8 {
+ status = "okay";
+
+ rtc@32 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names = "",
+ "APSS_RESET_N",
+ "",
+ "N_MODE_CPU_N",
+ "",
+ "",
+ "P10_DCM_PRESENT",
+ "";
+ };
+};
+
+&i2c9 {
+ status = "okay";
+
+ tmp423a@4c {
+ compatible = "ti,tmp423";
+ reg = <0x4c>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+};
+
+&i2c11 {
+ status = "okay";
+
+ tca9554@20 {
+ compatible = "ti,tca9554";
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names = "BOOT_RCVRY_TWI",
+ "BOOT_RCVRY_UART",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "PE_SWITCH_RSTB_N";
+ };
+
+ tmp435@4c {
+ compatible = "ti,tmp435";
+ reg = <0x4c>;
+ };
+
+ pca9849@75 {
+ compatible = "nxp,pca849";
+ reg = <0x75>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ i2c-mux-idle-disconnect;
+
+ i2c11mux0chn0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c11mux0chn1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ i2c11mux0chn2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ i2c11mux0chn3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+ };
+};
+
+&i2c12 {
+ status = "okay";
+
+ tpm@2e {
+ compatible = "nuvoton,npct75x";
+ reg = <0x2e>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+};
+
+&i2c13 {
+ status = "okay";
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "nvme0";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "nvme1";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@2 {
+ label = "nvme2";
+ reg = <2>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@3 {
+ label = "nvme3";
+ reg = <3>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
+};
+
+&i2c14 {
+ status = "okay";
+};
+
+&i2c15 {
+ status = "okay";
+};
+
+&vuart1 {
+ status = "okay";
+};
+
+&vuart2 {
+ status = "okay";
+};
+
+&lpc_ctrl {
+ status = "okay";
+ memory-region = <&flash_memory>;
+};
+
+&mac2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii3_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>,
+ <&syscon ASPEED_CLK_MAC3RCLK>;
+ clock-names = "MACCLK", "RCLK";
+ use-ncsi;
+};
+
+&mac3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii4_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC4CLK>,
+ <&syscon ASPEED_CLK_MAC4RCLK>;
+ clock-names = "MACCLK", "RCLK";
+ use-ncsi;
+};
+
+&wdt1 {
+ aspeed,reset-type = "none";
+ aspeed,external-signal;
+ aspeed,ext-push-pull;
+ aspeed,ext-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&wdt2 {
+ status = "okay";
+};
+
+&xdma {
+ status = "okay";
+ memory-region = <&vga_memory>;
+};
+
+&kcs2 {
+ status = "okay";
+ aspeed,lpc-io-reg = <0xca8 0xcac>;
+};
+
+&kcs3 {
+ status = "okay";
+ aspeed,lpc-io-reg = <0xca2>;
+ aspeed,lpc-interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
index a6a2bc3b855c..1448ea895be4 100644
--- a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
@@ -162,16 +162,9 @@
#size-cells = <1>;
ranges;
- /* LPC FW cycle bridge region requires natural alignment */
- flash_memory: region@b8000000 {
- no-map;
- reg = <0xb8000000 0x04000000>; /* 64M */
- };
-
- /* 48MB region from the end of flash to start of vga memory */
- ramoops@bc000000 {
+ ramoops@b3e00000 {
compatible = "ramoops";
- reg = <0xbc000000 0x200000>; /* 16 * (4 * 0x8000) */
+ reg = <0xb3e00000 0x200000>; /* 16 * (4 * 0x8000) */
record-size = <0x8000>;
console-size = <0x8000>;
ftrace-size = <0x8000>;
@@ -179,6 +172,12 @@
max-reason = <3>; /* KMSG_DUMP_EMERG */
};
+ /* LPC FW cycle bridge region requires natural alignment */
+ flash_memory: region@b4000000 {
+ no-map;
+ reg = <0xb4000000 0x04000000>; /* 64M */
+ };
+
/* VGA region is dictated by hardware strapping */
vga_memory: region@bf000000 {
no-map;
@@ -2551,6 +2550,11 @@
fsi_occ0: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -2695,6 +2699,11 @@
fsi_occ1: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -2839,6 +2848,11 @@
fsi_occ2: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -2983,6 +2997,11 @@
fsi_occ3: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -3127,6 +3146,11 @@
fsi_occ4: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -3271,6 +3295,11 @@
fsi_occ5: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -3415,6 +3444,11 @@
fsi_occ6: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -3559,6 +3593,11 @@
fsi_occ7: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
index bf59a9962379..20ef958698ec 100644
--- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
@@ -95,14 +95,9 @@
#size-cells = <1>;
ranges;
- flash_memory: region@b8000000 {
- no-map;
- reg = <0xb8000000 0x04000000>; /* 64M */
- };
-
- ramoops@bc000000 {
+ ramoops@b3e00000 {
compatible = "ramoops";
- reg = <0xbc000000 0x200000>; /* 16 * (4 * 0x8000) */
+ reg = <0xb3e00000 0x200000>; /* 16 * (4 * 0x8000) */
record-size = <0x8000>;
console-size = <0x8000>;
ftrace-size = <0x8000>;
@@ -110,6 +105,13 @@
max-reason = <3>; /* KMSG_DUMP_EMERG */
};
+ /* LPC FW cycle bridge region requires natural alignment */
+ flash_memory: region@b4000000 {
+ no-map;
+ reg = <0xb4000000 0x04000000>; /* 64M */
+ };
+
+ /* VGA region is dictated by hardware strapping */
vga_memory: region@bf000000 {
no-map;
compatible = "shared-dma-pool";
@@ -442,6 +444,11 @@
fsi_occ0: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -586,6 +593,11 @@
fsi_occ1: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -730,6 +742,11 @@
fsi_occ2: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -874,6 +891,11 @@
fsi_occ3: occ {
compatible = "ibm,p10-occ";
+
+ occ-hwmon {
+ compatible = "ibm,p10-occ-hwmon";
+ ibm,no-poll-on-init;
+ };
};
};
@@ -995,32 +1017,6 @@
reg = <0x4a>;
};
- pca9551@60 {
- compatible = "nxp,pca9551";
- reg = <0x60>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- led@0 {
- label = "cablecard0-cxp-top";
- reg = <0>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
-
- led@1 {
- label = "cablecard0-cxp-bot";
- reg = <1>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
- };
-
pca9546@70 {
compatible = "nxp,pca9546";
reg = <0x70>;
@@ -1038,6 +1034,32 @@
compatible = "atmel,24c64";
reg = <0x50>;
};
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "cablecard0-cxp-top";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "cablecard0-cxp-bot";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
};
i2c4mux0chn1: i2c@1 {
@@ -1077,58 +1099,6 @@
reg = <0x49>;
};
- pca9551@60 {
- compatible = "nxp,pca9551";
- reg = <0x60>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- led@0 {
- label = "cablecard3-cxp-top";
- reg = <0>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
-
- led@1 {
- label = "cablecard3-cxp-bot";
- reg = <1>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
- };
-
- pca9551@61 {
- compatible = "nxp,pca9551";
- reg = <0x61>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- led@0 {
- label = "cablecard4-cxp-top";
- reg = <0>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
-
- led@1 {
- label = "cablecard4-cxp-bot";
- reg = <1>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
- };
-
pca9546@70 {
compatible = "nxp,pca9546";
reg = <0x70>;
@@ -1146,6 +1116,32 @@
compatible = "atmel,24c64";
reg = <0x50>;
};
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "cablecard3-cxp-top";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "cablecard3-cxp-bot";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
};
i2c5mux0chn1: i2c@1 {
@@ -1157,6 +1153,32 @@
compatible = "atmel,24c64";
reg = <0x51>;
};
+
+ pca9551@61 {
+ compatible = "nxp,pca9551";
+ reg = <0x61>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "cablecard4-cxp-top";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "cablecard4-cxp-bot";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
};
};
};
@@ -2009,32 +2031,6 @@
reg = <0x49>;
};
- pca9551@60 {
- compatible = "nxp,pca9551";
- reg = <0x60>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- led@0 {
- label = "cablecard10-cxp-top";
- reg = <0>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
-
- led@1 {
- label = "cablecard10-cxp-bot";
- reg = <1>;
- retain-state-shutdown;
- default-state = "keep";
- type = <PCA955X_TYPE_LED>;
- };
- };
-
pca9546@70 {
compatible = "nxp,pca9546";
reg = <0x70>;
@@ -2052,6 +2048,32 @@
compatible = "atmel,24c64";
reg = <0x50>;
};
+
+ pca9551@60 {
+ compatible = "nxp,pca9551";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ led@0 {
+ label = "cablecard10-cxp-top";
+ reg = <0>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+
+ led@1 {
+ label = "cablecard10-cxp-bot";
+ reg = <1>;
+ retain-state-shutdown;
+ default-state = "keep";
+ type = <PCA955X_TYPE_LED>;
+ };
+ };
};
i2c11mux0chn1: i2c@1 {
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
deleted file mode 100644
index 48776fb663fb..000000000000
--- a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
+++ /dev/null
@@ -1,1381 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/dts-v1/;
-#include "aspeed-g5.dtsi"
-#include <dt-bindings/gpio/aspeed-gpio.h>
-#include <dt-bindings/leds/leds-pca955x.h>
-
-/ {
- model = "Mihawk BMC";
- compatible = "ibm,mihawk-bmc", "aspeed,ast2500";
-
- aliases {
- i2c215 = &bus6_mux215;
- i2c216 = &bus6_mux216;
- i2c217 = &bus6_mux217;
- i2c218 = &bus6_mux218;
- i2c219 = &bus6_mux219;
- i2c220 = &bus6_mux220;
- i2c221 = &bus6_mux221;
- i2c222 = &bus6_mux222;
- i2c223 = &bus7_mux223;
- i2c224 = &bus7_mux224;
- i2c225 = &bus7_mux225;
- i2c226 = &bus7_mux226;
- i2c227 = &bus7_mux227;
- i2c228 = &bus7_mux228;
- i2c229 = &bus7_mux229;
- i2c230 = &bus7_mux230;
- i2c231 = &bus9_mux231;
- i2c232 = &bus9_mux232;
- i2c233 = &bus9_mux233;
- i2c234 = &bus9_mux234;
- i2c235 = &bus9_mux235;
- i2c236 = &bus9_mux236;
- i2c237 = &bus9_mux237;
- i2c238 = &bus9_mux238;
- i2c239 = &bus10_mux239;
- i2c240 = &bus10_mux240;
- i2c241 = &bus10_mux241;
- i2c242 = &bus10_mux242;
- i2c243 = &bus10_mux243;
- i2c244 = &bus10_mux244;
- i2c245 = &bus10_mux245;
- i2c246 = &bus10_mux246;
- i2c247 = &bus12_mux247;
- i2c248 = &bus12_mux248;
- i2c249 = &bus12_mux249;
- i2c250 = &bus12_mux250;
- i2c251 = &bus13_mux251;
- i2c252 = &bus13_mux252;
- i2c253 = &bus13_mux253;
- i2c254 = &bus13_mux254;
- i2c255 = &bus13_mux255;
- i2c256 = &bus13_mux256;
- i2c257 = &bus13_mux257;
- i2c258 = &bus13_mux258;
- };
-
- chosen {
- stdout-path = &uart5;
- bootargs = "console=ttyS4,115200 earlycon";
- };
-
- memory@80000000 {
- reg = <0x80000000 0x20000000>;
- };
-
- reserved-memory {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- flash_memory: region@98000000 {
- no-map;
- reg = <0x98000000 0x04000000>; /* 64M */
- };
-
- gfx_memory: framebuffer {
- size = <0x01000000>;
- alignment = <0x01000000>;
- compatible = "shared-dma-pool";
- reusable;
- };
-
- video_engine_memory: jpegbuffer {
- size = <0x02000000>;
- alignment = <0x01000000>;
- compatible = "shared-dma-pool";
- reusable;
- };
- };
-
- gpio-keys {
- compatible = "gpio-keys";
-
- event-air-water {
- label = "air-water";
- gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
- linux,code = <ASPEED_GPIO(F, 6)>;
- };
-
- event-checkstop {
- label = "checkstop";
- gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
- linux,code = <ASPEED_GPIO(J, 2)>;
- };
-
- event-ps0-presence {
- label = "ps0-presence";
- gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
- linux,code = <ASPEED_GPIO(Z, 2)>;
- };
-
- event-ps1-presence {
- label = "ps1-presence";
- gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
- linux,code = <ASPEED_GPIO(Z, 0)>;
- };
-
- button-id {
- label = "id-button";
- gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
- linux,code = <ASPEED_GPIO(F, 1)>;
- };
- };
-
- gpio-keys-polled {
- compatible = "gpio-keys-polled";
- poll-interval = <1000>;
-
- event-fan0-presence {
- label = "fan0-presence";
- gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
- linux,code = <9>;
- };
-
- event-fan1-presence {
- label = "fan1-presence";
- gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
- linux,code = <10>;
- };
-
- event-fan2-presence {
- label = "fan2-presence";
- gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
- linux,code = <11>;
- };
-
- event-fan3-presence {
- label = "fan3-presence";
- gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
- linux,code = <12>;
- };
-
- event-fan4-presence {
- label = "fan4-presence";
- gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
- linux,code = <13>;
- };
-
- event-fan5-presence {
- label = "fan5-presence";
- gpios = <&pca9552 14 GPIO_ACTIVE_LOW>;
- linux,code = <14>;
- };
- };
-
- leds {
- compatible = "gpio-leds";
-
- front-fault {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
- };
-
- power-button {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>;
- };
-
- front-id {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>;
- };
-
-
- fan0 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 0 GPIO_ACTIVE_LOW>;
- };
-
- fan1 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 1 GPIO_ACTIVE_LOW>;
- };
-
- fan2 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 2 GPIO_ACTIVE_LOW>;
- };
-
- fan3 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 3 GPIO_ACTIVE_LOW>;
- };
-
- fan4 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 4 GPIO_ACTIVE_LOW>;
- };
-
- fan5 {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&pca9552 5 GPIO_ACTIVE_LOW>;
- };
- };
-
- fsi: gpio-fsi {
- compatible = "fsi-master-gpio", "fsi-master";
- #address-cells = <2>;
- #size-cells = <0>;
- no-gpio-delays;
-
- clock-gpios = <&gpio ASPEED_GPIO(E, 6) GPIO_ACTIVE_HIGH>;
- data-gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_HIGH>;
- mux-gpios = <&gpio ASPEED_GPIO(E, 5) GPIO_ACTIVE_HIGH>;
- enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
- trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
- };
- iio-hwmon-12v {
- compatible = "iio-hwmon";
- io-channels = <&adc 0>;
- };
-
- iio-hwmon-5v {
- compatible = "iio-hwmon";
- io-channels = <&adc 1>;
- };
-
- iio-hwmon-3v {
- compatible = "iio-hwmon";
- io-channels = <&adc 2>;
- };
-
- iio-hwmon-vdd0 {
- compatible = "iio-hwmon";
- io-channels = <&adc 3>;
- };
-
- iio-hwmon-vdd1 {
- compatible = "iio-hwmon";
- io-channels = <&adc 4>;
- };
-
- iio-hwmon-vcs0 {
- compatible = "iio-hwmon";
- io-channels = <&adc 5>;
- };
-
- iio-hwmon-vcs1 {
- compatible = "iio-hwmon";
- io-channels = <&adc 6>;
- };
-
- iio-hwmon-vdn0 {
- compatible = "iio-hwmon";
- io-channels = <&adc 7>;
- };
-
- iio-hwmon-vdn1 {
- compatible = "iio-hwmon";
- io-channels = <&adc 8>;
- };
-
- iio-hwmon-vio0 {
- compatible = "iio-hwmon";
- io-channels = <&adc 9>;
- };
-
- iio-hwmon-vio1 {
- compatible = "iio-hwmon";
- io-channels = <&adc 10>;
- };
-
- iio-hwmon-vddra {
- compatible = "iio-hwmon";
- io-channels = <&adc 11>;
- };
-
- iio-hwmon-battery {
- compatible = "iio-hwmon";
- io-channels = <&adc 12>;
- };
-
- iio-hwmon-vddrb {
- compatible = "iio-hwmon";
- io-channels = <&adc 13>;
- };
-
- iio-hwmon-vddrc {
- compatible = "iio-hwmon";
- io-channels = <&adc 14>;
- };
-
- iio-hwmon-vddrd {
- compatible = "iio-hwmon";
- io-channels = <&adc 15>;
- };
-};
-
-&pwm_tacho {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
- &pinctrl_pwm2_default &pinctrl_pwm3_default
- &pinctrl_pwm4_default &pinctrl_pwm5_default>;
-
- fan@0 {
- reg = <0x00>;
- aspeed,fan-tach-ch = /bits/ 8 <0x00>;
- };
-
- fan@1 {
- reg = <0x01>;
- aspeed,fan-tach-ch = /bits/ 8 <0x01>;
- };
-
- fan@2 {
- reg = <0x02>;
- aspeed,fan-tach-ch = /bits/ 8 <0x02>;
- };
-
- fan@3 {
- reg = <0x03>;
- aspeed,fan-tach-ch = /bits/ 8 <0x03>;
- };
-
- fan@4 {
- reg = <0x04>;
- aspeed,fan-tach-ch = /bits/ 8 <0x04>;
- };
-
- fan@5 {
- reg = <0x05>;
- aspeed,fan-tach-ch = /bits/ 8 <0x05>;
- };
-
- fan@6 {
- reg = <0x00>;
- aspeed,fan-tach-ch = /bits/ 8 <0x06>;
- };
-
- fan@7 {
- reg = <0x01>;
- aspeed,fan-tach-ch = /bits/ 8 <0x07>;
- };
-
- fan@8 {
- reg = <0x02>;
- aspeed,fan-tach-ch = /bits/ 8 <0x08>;
- };
-
- fan@9 {
- reg = <0x03>;
- aspeed,fan-tach-ch = /bits/ 8 <0x09>;
- };
-
- fan@10 {
- reg = <0x04>;
- aspeed,fan-tach-ch = /bits/ 8 <0x0a>;
- };
-
- fan@11 {
- reg = <0x05>;
- aspeed,fan-tach-ch = /bits/ 8 <0x0b>;
- };
-};
-
-&gpio {
- gpio-line-names =
- /*A0-A7*/ "","cfam-reset","","","","","","",
- /*B0-B7*/ "","","","","","","","",
- /*C0-C7*/ "","","","","","","","",
- /*D0-D7*/ "fsi-enable","","","","","","","",
- /*E0-E7*/ "","","","","","fsi-mux","fsi-clock","fsi-data",
- /*F0-F7*/ "","id-button","","","","","air-water","",
- /*G0-G7*/ "","","","","","","","",
- /*H0-H7*/ "","","","","","","","",
- /*I0-I7*/ "","","","","","","","",
- /*J0-J7*/ "","","checkstop","","","","","",
- /*K0-K7*/ "","","","","","","","",
- /*L0-L7*/ "","","","","","","","",
- /*M0-M7*/ "","","","","","","","",
- /*N0-N7*/ "","","","","","","","",
- /*O0-O7*/ "","","","","","","","",
- /*P0-P7*/ "","","","","","","","",
- /*Q0-Q7*/ "","","","","","","","",
- /*R0-R7*/ "","","fsi-trans","","","","","",
- /*S0-S7*/ "","","","","","","","",
- /*T0-T7*/ "","","","","","","","",
- /*U0-U7*/ "","","","","","","","",
- /*V0-V7*/ "","","","","","","","",
- /*W0-W7*/ "","","","","","","","",
- /*X0-X7*/ "","","","","","","","",
- /*Y0-Y7*/ "","","","","","","","",
- /*Z0-Z7*/ "presence-ps1","","presence-ps0","","","","","",
- /*AA0-AA7*/ "led-front-fault","power-button","led-front-id","","","","","",
- /*AB0-AB7*/ "","","","","","","","",
- /*AC0-AC7*/ "","","","","","","","";
-};
-
-&fmc {
- status = "okay";
- flash@0 {
- status = "okay";
- label = "bmc";
- m25p,fast-read;
- spi-max-frequency = <50000000>;
- partitions {
- #address-cells = < 1 >;
- #size-cells = < 1 >;
- compatible = "fixed-partitions";
- u-boot@0 {
- reg = < 0 0x60000 >;
- label = "u-boot";
- };
- u-boot-env@60000 {
- reg = < 0x60000 0x20000 >;
- label = "u-boot-env";
- };
- obmc-ubi@80000 {
- reg = < 0x80000 0x1F80000 >;
- label = "obmc-ubi";
- };
- };
- };
- flash@1 {
- status = "okay";
- label = "alt-bmc";
- m25p,fast-read;
- spi-max-frequency = <50000000>;
- partitions {
- #address-cells = < 1 >;
- #size-cells = < 1 >;
- compatible = "fixed-partitions";
- u-boot@0 {
- reg = < 0 0x60000 >;
- label = "alt-u-boot";
- };
- u-boot-env@60000 {
- reg = < 0x60000 0x20000 >;
- label = "alt-u-boot-env";
- };
- obmc-ubi@80000 {
- reg = < 0x80000 0x1F80000 >;
- label = "alt-obmc-ubi";
- };
- };
- };
-};
-
-&spi1 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_spi1_default>;
-
- flash@0 {
- status = "okay";
- label = "pnor";
- m25p,fast-read;
- spi-max-frequency = <100000000>;
- };
-};
-
-&lpc_ctrl {
- status = "okay";
- memory-region = <&flash_memory>;
- flash = <&spi1>;
-};
-
-&uart1 {
- /* Rear RS-232 connector */
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_txd1_default
- &pinctrl_rxd1_default
- &pinctrl_nrts1_default
- &pinctrl_ndtr1_default
- &pinctrl_ndsr1_default
- &pinctrl_ncts1_default
- &pinctrl_ndcd1_default
- &pinctrl_nri1_default>;
-};
-
-&uart2 {
- /* APSS */
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
-};
-
-&uart5 {
- status = "okay";
-};
-
-&mac0 {
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_rmii1_default>;
- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
- <&syscon ASPEED_CLK_MAC1RCLK>;
- clock-names = "MACCLK", "RCLK";
- use-ncsi;
-};
-
-&mac1 {
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
-};
-
-&i2c0 {
- status = "disabled";
-};
-
-&i2c1 {
- status = "disabled";
-};
-
-&i2c2 {
- status = "okay";
-
- /* SAMTEC P0 */
- /* SAMTEC P1 */
-
-};
-
-&i2c3 {
- status = "okay";
-
- /* APSS */
- /* CPLD */
-
- /* PCA9516 (repeater) ->
- * CLK Buffer 9FGS9092
- * CLK Buffer 9DBL0651BKILFT
- * CLK Buffer 9DBL0651BKILFT
- * Power Supply 0
- * Power Supply 1
- * PCA 9552 LED
- */
-
- power-supply@58 {
- compatible = "ibm,cffps1";
- reg = <0x58>;
- };
-
- power-supply@5b {
- compatible = "ibm,cffps1";
- reg = <0x5b>;
- };
-
- pca9552: pca9552@60 {
- compatible = "nxp,pca9552";
- reg = <0x60>;
- #address-cells = <1>;
- #size-cells = <0>;
- gpio-controller;
- #gpio-cells = <2>;
-
- gpio@0 {
- reg = <0>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@1 {
- reg = <1>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@2 {
- reg = <2>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@3 {
- reg = <3>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@4 {
- reg = <4>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@5 {
- reg = <5>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@6 {
- reg = <6>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@7 {
- reg = <7>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@8 {
- reg = <8>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@9 {
- reg = <9>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@10 {
- reg = <10>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@11 {
- reg = <11>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@12 {
- reg = <12>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@13 {
- reg = <13>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@14 {
- reg = <14>;
- type = <PCA955X_TYPE_GPIO>;
- };
- gpio@15 {
- reg = <15>;
- type = <PCA955X_TYPE_GPIO>;
- };
-
- };
-
-};
-
-&i2c4 {
- status = "okay";
-
- /* CP0 VDD & VCS : IR35221 */
- /* CP0 VDN : IR35221 */
- /* CP0 VIO : IR38064 */
- /* CP0 VDDR : PXM1330 */
-
- ir35221@70 {
- compatible = "infineon,ir35221";
- reg = <0x70>;
- };
-
- ir35221@72 {
- compatible = "infineon,ir35221";
- reg = <0x72>;
- };
-
-};
-
-&i2c5 {
- status = "okay";
-
- /* CP0 VDD & VCS : IR35221 */
- /* CP0 VDN : IR35221 */
- /* CP0 VIO : IR38064 */
- /* CP0 VDDR : PXM1330 */
-
- ir35221@70 {
- compatible = "infineon,ir35221";
- reg = <0x70>;
- };
-
- ir35221@72 {
- compatible = "infineon,ir35221";
- reg = <0x72>;
- };
-
-};
-
-&i2c6 {
- status = "okay";
-
- /* pca9548 -> NVMe1 to 8 */
-
- pca9548@70 {
- compatible = "nxp,pca9548";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
-
- bus7_mux223: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
- };
-
- bus7_mux224: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- };
-
- bus7_mux225: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus7_mux226: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
-
- bus7_mux227: i2c@4 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <4>;
- };
-
- bus7_mux228: i2c@5 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <5>;
- };
-
- bus7_mux229: i2c@6 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <6>;
- };
-
- bus7_mux230: i2c@7 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <7>;
- };
- };
-
-};
-
-&i2c7 {
- status = "okay";
-
- /* pca9548 -> NVMe9 to 16 */
-
- pca9548@70 {
- compatible = "nxp,pca9548";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
-
- bus6_mux215: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
- };
-
- bus6_mux216: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- };
-
- bus6_mux217: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus6_mux218: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
-
- bus6_mux219: i2c@4 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <4>;
- };
-
- bus6_mux220: i2c@5 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <5>;
- };
-
- bus6_mux221: i2c@6 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <6>;
- };
-
- bus6_mux222: i2c@7 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <7>;
- };
- };
-
-};
-
-&i2c8 {
- status = "okay";
-
- eeprom@50 {
- compatible = "atmel,24c64";
- reg = <0x50>;
- };
-};
-
-&i2c9 {
- status = "okay";
-
- /* pca9545 Riser ->
- * PCIe x8 Slot3
- * PCIe x16 slot4
- * PCIe x8 slot5
- * I2C BMC RISER PCA9554
- * BMC SCL/SDA PCA9554
- * PCA9554
- */
-
- /* pca9545 ->
- * PCIe x16 Slot1
- * PCIe x8 slot2
- * PEX8748
- */
-
- pca9545riser@70 {
- compatible = "nxp,pca9545";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
-
- i2c-mux-idle-disconnect;
- interrupt-controller;
- #interrupt-cells = <2>;
-
- bus9_mux231: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus0-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus0";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus9_mux232: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus1-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus1";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus9_mux233: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus9_mux234: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
- };
-
- pca9545@71 {
- compatible = "nxp,pca9545";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x71>;
-
- i2c-mux-idle-disconnect;
- interrupt-controller;
- #interrupt-cells = <2>;
-
- bus9_mux235: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus2-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus2";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus9_mux236: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus3-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus3";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus9_mux237: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus9_mux238: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
- };
-};
-
-&i2c10 {
- status = "okay";
-
- /* pca9545 Riser ->
- * PCIe x8 Slot8
- * PCIe x16 slot9
- * PCIe x8 slot10
- * I2C BMC RISER PCA9554
- * BMC SCL/SDA PCA9554
- * PCA9554
- */
-
- /* pca9545 ->
- * PCIe x16 Slot1
- * PCIe x8 slot2
- * PEX8748
- */
-
- pca9545riser@70 {
- compatible = "nxp,pca9545";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
-
- i2c-mux-idle-disconnect;
- interrupt-controller;
- #interrupt-cells = <2>;
-
- bus10_mux239: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus4-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus4";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus10_mux240: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus5-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus5";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus10_mux241: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus10_mux242: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
- };
-
- pca9545@71 {
- compatible = "nxp,pca9545";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x71>;
-
- i2c-mux-idle-disconnect;
- interrupt-controller;
- #interrupt-cells = <2>;
-
- bus10_mux243: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus6-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus6";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus10_mux244: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
-
- tca9554@39 {
- compatible = "ti,tca9554";
- reg = <0x39>;
- gpio-controller;
- #gpio-cells = <2>;
-
- smbus7-hog {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-high;
- line-name = "smbus7";
- };
- };
-
- tmp431@4c {
- compatible = "ti,tmp401";
- reg = <0x4c>;
- };
- };
-
- bus10_mux245: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus10_mux246: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
- };
-};
-
-&i2c11 {
- status = "okay";
-
- /* TPM */
- /* RTC RX8900CE */
- /* FPGA for power sequence */
- /* TMP275A */
- /* TMP275A */
- /* EMC1462 */
-
- tpm@57 {
- compatible = "infineon,slb9645tt";
- reg = <0x57>;
- };
-
- rtc@32 {
- compatible = "epson,rx8900";
- reg = <0x32>;
- };
-
- tmp275@48 {
- compatible = "ti,tmp275";
- reg = <0x48>;
- };
-
- tmp275@49 {
- compatible = "ti,tmp275";
- reg = <0x49>;
- };
-
- /* chip emc1462 use emc1403 driver */
- emc1403@4c {
- compatible = "smsc,emc1403";
- reg = <0x4c>;
- };
-
-};
-
-&i2c12 {
- status = "okay";
-
- /* pca9545 ->
- * SAS BP1
- * SAS BP2
- * NVMe BP
- * M.2 riser
- */
-
- pca9545@70 {
- compatible = "nxp,pca9545";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
-
- interrupt-controller;
- #interrupt-cells = <2>;
-
- bus12_mux247: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
-
- eeprom@50 {
- compatible = "atmel,24c64";
- reg = <0x50>;
- };
- };
-
- bus12_mux248: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
-
- eeprom@50 {
- compatible = "atmel,24c64";
- reg = <0x50>;
- };
- };
-
- bus12_mux249: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
-
- eeprom@50 {
- compatible = "atmel,24c64";
- reg = <0x50>;
- };
- };
-
- bus12_mux250: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
-
- tmp275@48 {
- compatible = "ti,tmp275";
- reg = <0x48>;
- };
- };
-
- };
-
-};
-
-&i2c13 {
- status = "okay";
-
- /* pca9548 ->
- * NVMe BP
- * NVMe HDD17 to 24
- */
-
- pca9548@70 {
- compatible = "nxp,pca9548";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x70>;
- bus13_mux251: i2c@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0>;
- };
-
- bus13_mux252: i2c@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- };
-
- bus13_mux253: i2c@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- };
-
- bus13_mux254: i2c@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- };
-
- bus13_mux255: i2c@4 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <4>;
- };
-
- bus13_mux256: i2c@5 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <5>;
- };
-
- bus13_mux257: i2c@6 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <6>;
- };
-
- bus13_mux258: i2c@7 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <7>;
- };
- };
-};
-
-&vuart {
- status = "okay";
-};
-
-&gfx {
- status = "okay";
- memory-region = <&gfx_memory>;
-};
-
-&adc {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_adc0_default
- &pinctrl_adc1_default
- &pinctrl_adc2_default
- &pinctrl_adc3_default
- &pinctrl_adc4_default
- &pinctrl_adc5_default
- &pinctrl_adc6_default
- &pinctrl_adc7_default
- &pinctrl_adc8_default
- &pinctrl_adc9_default
- &pinctrl_adc10_default
- &pinctrl_adc11_default
- &pinctrl_adc12_default
- &pinctrl_adc13_default
- &pinctrl_adc14_default
- &pinctrl_adc15_default>;
-};
-
-&wdt1 {
- aspeed,reset-type = "none";
- aspeed,external-signal;
- aspeed,ext-push-pull;
- aspeed,ext-active-high;
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_wdtrst1_default>;
-};
-
-&wdt2 {
- aspeed,alt-boot;
-};
-
-&ibt {
- status = "okay";
-};
-
-&vhub {
- status = "okay";
-};
-
-&video {
- status = "okay";
- memory-region = <&video_engine_memory>;
-};
-
-#include "ibm-power9-dual.dtsi"
-
diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index ebbcfe445d9c..cc2f8b785917 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -36,6 +36,10 @@
serial4 = &uart5;
serial5 = &vuart1;
serial6 = &vuart2;
+ mdio0 = &mdio0;
+ mdio1 = &mdio1;
+ mdio2 = &mdio2;
+ mdio3 = &mdio3;
};
diff --git a/arch/arm/boot/dts/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/ast2600-facebook-netbmc-common.dtsi
index 051de5bec345..31590d3186a2 100644
--- a/arch/arm/boot/dts/ast2600-facebook-netbmc-common.dtsi
+++ b/arch/arm/boot/dts/ast2600-facebook-netbmc-common.dtsi
@@ -25,7 +25,7 @@
* full-duplex SPI transactions are not supported by ASPEED SPI
* Controllers.
*/
- spi_gpio: spi-gpio {
+ spi_gpio: spi {
status = "okay";
compatible = "spi-gpio";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91-sam9x60ek.dts b/arch/arm/boot/dts/at91-sam9x60ek.dts
index 4ba52ba11dc6..d929c1ba5789 100644
--- a/arch/arm/boot/dts/at91-sam9x60ek.dts
+++ b/arch/arm/boot/dts/at91-sam9x60ek.dts
@@ -76,7 +76,6 @@
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
- status = "okay";
};
vdd_1v15: fixed-regulator-vdd_1v15 {
@@ -85,7 +84,6 @@
regulator-min-microvolt = <1150000>;
regulator-max-microvolt = <1150000>;
regulator-always-on;
- status = "okay";
};
vdd1_3v3: fixed-regulator-vdd1_3v3 {
@@ -94,7 +92,6 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
- status = "okay";
};
vdd2_3v3: regulator-fixed-vdd2_3v3 {
@@ -103,7 +100,6 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
- status = "okay";
};
};
diff --git a/arch/arm/boot/dts/at91-sama7g5ek.dts b/arch/arm/boot/dts/at91-sama7g5ek.dts
index 3b25c67795dd..aa5cc0e98bba 100644
--- a/arch/arm/boot/dts/at91-sama7g5ek.dts
+++ b/arch/arm/boot/dts/at91-sama7g5ek.dts
@@ -764,8 +764,9 @@
&sdmmc0 {
bus-width = <8>;
non-removable;
- no-1-8-v;
sdhci-caps-mask = <0x0 0x00200000>;
+ vmmc-supply = <&vdd_3v3>;
+ vqmmc-supply = <&vldo1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sdmmc0_default>;
status = "okay";
@@ -775,6 +776,8 @@
bus-width = <4>;
no-1-8-v;
sdhci-caps-mask = <0x0 0x00200000>;
+ vmmc-supply = <&vdd_3v3>;
+ vqmmc-supply = <&vdd_3v3>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sdmmc1_default>;
status = "okay";
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 7a113325abb9..6f9004ebf424 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -666,7 +666,7 @@
compatible = "atmel,at91rm9200-udc";
reg = <0xfffb0000 0x4000>;
interrupts = <11 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&pmc PMC_TYPE_PERIPHERAL 11>, <&pmc PMC_TYPE_SYSTEM 2>;
+ clocks = <&pmc PMC_TYPE_PERIPHERAL 11>, <&pmc PMC_TYPE_SYSTEM 1>;
clock-names = "pclk", "hclk";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index 60d61291f344..024af2db638e 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -39,6 +39,13 @@
};
+ usb1 {
+ pinctrl_usb1_vbus_gpio: usb1_vbus_gpio {
+ atmel,pins =
+ <AT91_PIOC 5 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>; /* PC5 GPIO */
+ };
+ };
+
mmc0_slot1 {
pinctrl_board_mmc0_slot1: mmc0_slot1-board {
atmel,pins =
@@ -84,6 +91,8 @@
};
usb1: gadget@fffa4000 {
+ pinctrl-0 = <&pinctrl_usb1_vbus_gpio>;
+ pinctrl-names = "default";
atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/axp22x.dtsi b/arch/arm/boot/dts/axp22x.dtsi
index a020c12b2884..f79650afd0a7 100644
--- a/arch/arm/boot/dts/axp22x.dtsi
+++ b/arch/arm/boot/dts/axp22x.dtsi
@@ -67,6 +67,12 @@
status = "disabled";
};
+ axp_gpio: gpio {
+ compatible = "x-powers,axp221-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
regulators {
/* Default work frequency for buck regulators */
x-powers,dcdc-freq = <3000>;
diff --git a/arch/arm/boot/dts/axp809.dtsi b/arch/arm/boot/dts/axp809.dtsi
index ab8e5f2d9246..d134d4c00bd8 100644
--- a/arch/arm/boot/dts/axp809.dtsi
+++ b/arch/arm/boot/dts/axp809.dtsi
@@ -50,4 +50,11 @@
compatible = "x-powers,axp809";
interrupt-controller;
#interrupt-cells = <1>;
+
+ axp_gpio: gpio {
+ compatible = "x-powers,axp809-gpio",
+ "x-powers,axp221-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
};
diff --git a/arch/arm/boot/dts/axp81x.dtsi b/arch/arm/boot/dts/axp81x.dtsi
index b93387b0c1c3..ebaf1c3ce8db 100644
--- a/arch/arm/boot/dts/axp81x.dtsi
+++ b/arch/arm/boot/dts/axp81x.dtsi
@@ -62,16 +62,6 @@
compatible = "x-powers,axp813-gpio";
gpio-controller;
#gpio-cells = <2>;
-
- gpio0_ldo: gpio0-ldo-pin {
- pins = "GPIO0";
- function = "ldo";
- };
-
- gpio1_ldo: gpio1-ldo-pin {
- pins = "GPIO1";
- function = "ldo";
- };
};
battery_power_supply: battery-power {
@@ -144,15 +134,11 @@
};
reg_ldo_io0: ldo-io0 {
- pinctrl-names = "default";
- pinctrl-0 = <&gpio0_ldo>;
/* Disable by default to avoid conflicts with GPIO */
status = "disabled";
};
reg_ldo_io1: ldo-io1 {
- pinctrl-names = "default";
- pinctrl-0 = <&gpio1_ldo>;
/* Disable by default to avoid conflicts with GPIO */
status = "disabled";
};
diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
index 4432412044de..d5f8823230db 100644
--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
@@ -2,6 +2,7 @@
/dts-v1/;
#include "bcm2711.dtsi"
#include "bcm2711-rpi.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-peripheral.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -14,20 +15,7 @@
stdout-path = "serial1:115200n8";
};
- leds {
- led-act {
- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
-
- sd_io_1v8_reg: sd_io_1v8_reg {
+ sd_io_1v8_reg: regulator-sd-io-1v8 {
compatible = "regulator-gpio";
regulator-name = "vdd-sd-io";
regulator-min-microvolt = <1800000>;
@@ -41,7 +29,7 @@
status = "okay";
};
- sd_vcc_reg: sd_vcc_reg {
+ sd_vcc_reg: regulator-sd-vcc {
compatible = "regulator-fixed";
regulator-name = "vcc-sd";
regulator-min-microvolt = <3300000>;
@@ -156,6 +144,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led_pwr: led-pwr {
+ label = "PWR";
+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pixelvalve0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm2711-rpi-400.dts b/arch/arm/boot/dts/bcm2711-rpi-400.dts
index c53d9eb0b802..1ab8184302db 100644
--- a/arch/arm/boot/dts/bcm2711-rpi-400.dts
+++ b/arch/arm/boot/dts/bcm2711-rpi-400.dts
@@ -11,14 +11,6 @@
stdout-path = "serial1:115200n8";
};
- leds {
- /delete-node/ led-act;
-
- led-pwr {
- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
- };
- };
-
gpio-poweroff {
compatible = "gpio-poweroff";
gpios = <&expgpio 5 GPIO_ACTIVE_HIGH>;
@@ -40,6 +32,14 @@
clock-frequency = <1950000>;
};
+&led_pwr {
+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ /delete-node/ led_act;
+};
+
&pm {
/delete-property/ system-power-controller;
};
diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4-io.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4-io.dts
index 19600b629be5..d7ba02f586d3 100644
--- a/arch/arm/boot/dts/bcm2711-rpi-cm4-io.dts
+++ b/arch/arm/boot/dts/bcm2711-rpi-cm4-io.dts
@@ -1,23 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "bcm2711-rpi-cm4.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
/ {
model = "Raspberry Pi Compute Module 4 IO Board";
-
- leds {
- led-act {
- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&ddc0 {
@@ -113,6 +101,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pixelvalve0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dtsi b/arch/arm/boot/dts/bcm2711-rpi-cm4.dtsi
index a2954d466a73..48e63ab7848c 100644
--- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dtsi
+++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dtsi
@@ -12,7 +12,7 @@
stdout-path = "serial1:115200n8";
};
- sd_io_1v8_reg: sd_io_1v8_reg {
+ sd_io_1v8_reg: regulator-sd-io-1v8 {
compatible = "regulator-gpio";
regulator-name = "vdd-sd-io";
regulator-min-microvolt = <1800000>;
@@ -26,7 +26,7 @@
status = "okay";
};
- sd_vcc_reg: sd_vcc_reg {
+ sd_vcc_reg: regulator-sd-vcc {
compatible = "regulator-fixed";
regulator-name = "vcc-sd";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi
index 941c4d16791b..097e9f252235 100644
--- a/arch/arm/boot/dts/bcm2711.dtsi
+++ b/arch/arm/boot/dts/bcm2711.dtsi
@@ -48,7 +48,7 @@
* This node is the provider for the enable-method for
* bringing up secondary cores.
*/
- local_intc: local_intc@40000000 {
+ local_intc: interrupt-controller@40000000 {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
};
@@ -536,6 +536,7 @@
*/
l2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>; // 1MiB(size)/64(line-size)=16384ways/16-way set
@@ -647,21 +648,21 @@
gpio-ranges = <&gpio 0 0 58>;
- gpclk0_gpio49: gpclk0_gpio49 {
+ gpclk0_gpio49: gpclk0-gpio49 {
pin-gpclk {
pins = "gpio49";
function = "alt1";
bias-disable;
};
};
- gpclk1_gpio50: gpclk1_gpio50 {
+ gpclk1_gpio50: gpclk1-gpio50 {
pin-gpclk {
pins = "gpio50";
function = "alt1";
bias-disable;
};
};
- gpclk2_gpio51: gpclk2_gpio51 {
+ gpclk2_gpio51: gpclk2-gpio51 {
pin-gpclk {
pins = "gpio51";
function = "alt1";
@@ -669,7 +670,7 @@
};
};
- i2c0_gpio46: i2c0_gpio46 {
+ i2c0_gpio46: i2c0-gpio46 {
pin-sda {
function = "alt0";
pins = "gpio46";
@@ -681,7 +682,7 @@
bias-disable;
};
};
- i2c1_gpio46: i2c1_gpio46 {
+ i2c1_gpio46: i2c1-gpio46 {
pin-sda {
function = "alt1";
pins = "gpio46";
@@ -693,7 +694,7 @@
bias-disable;
};
};
- i2c3_gpio2: i2c3_gpio2 {
+ i2c3_gpio2: i2c3-gpio2 {
pin-sda {
function = "alt5";
pins = "gpio2";
@@ -705,7 +706,7 @@
bias-disable;
};
};
- i2c3_gpio4: i2c3_gpio4 {
+ i2c3_gpio4: i2c3-gpio4 {
pin-sda {
function = "alt5";
pins = "gpio4";
@@ -717,7 +718,7 @@
bias-disable;
};
};
- i2c4_gpio6: i2c4_gpio6 {
+ i2c4_gpio6: i2c4-gpio6 {
pin-sda {
function = "alt5";
pins = "gpio6";
@@ -729,7 +730,7 @@
bias-disable;
};
};
- i2c4_gpio8: i2c4_gpio8 {
+ i2c4_gpio8: i2c4-gpio8 {
pin-sda {
function = "alt5";
pins = "gpio8";
@@ -741,7 +742,7 @@
bias-disable;
};
};
- i2c5_gpio10: i2c5_gpio10 {
+ i2c5_gpio10: i2c5-gpio10 {
pin-sda {
function = "alt5";
pins = "gpio10";
@@ -753,7 +754,7 @@
bias-disable;
};
};
- i2c5_gpio12: i2c5_gpio12 {
+ i2c5_gpio12: i2c5-gpio12 {
pin-sda {
function = "alt5";
pins = "gpio12";
@@ -765,7 +766,7 @@
bias-disable;
};
};
- i2c6_gpio0: i2c6_gpio0 {
+ i2c6_gpio0: i2c6-gpio0 {
pin-sda {
function = "alt5";
pins = "gpio0";
@@ -777,7 +778,7 @@
bias-disable;
};
};
- i2c6_gpio22: i2c6_gpio22 {
+ i2c6_gpio22: i2c6-gpio22 {
pin-sda {
function = "alt5";
pins = "gpio22";
@@ -789,7 +790,7 @@
bias-disable;
};
};
- i2c_slave_gpio8: i2c_slave_gpio8 {
+ i2c_slave_gpio8: i2c-slave-gpio8 {
pins-i2c-slave {
pins = "gpio8",
"gpio9",
@@ -799,7 +800,7 @@
};
};
- jtag_gpio48: jtag_gpio48 {
+ jtag_gpio48: jtag-gpio48 {
pins-jtag {
pins = "gpio48",
"gpio49",
@@ -811,7 +812,7 @@
};
};
- mii_gpio28: mii_gpio28 {
+ mii_gpio28: mii-gpio28 {
pins-mii {
pins = "gpio28",
"gpio29",
@@ -820,7 +821,7 @@
function = "alt4";
};
};
- mii_gpio36: mii_gpio36 {
+ mii_gpio36: mii-gpio36 {
pins-mii {
pins = "gpio36",
"gpio37",
@@ -830,7 +831,7 @@
};
};
- pcm_gpio50: pcm_gpio50 {
+ pcm_gpio50: pcm-gpio50 {
pins-pcm {
pins = "gpio50",
"gpio51",
@@ -840,63 +841,63 @@
};
};
- pwm0_0_gpio12: pwm0_0_gpio12 {
+ pwm0_0_gpio12: pwm0-0-gpio12 {
pin-pwm {
pins = "gpio12";
function = "alt0";
bias-disable;
};
};
- pwm0_0_gpio18: pwm0_0_gpio18 {
+ pwm0_0_gpio18: pwm0-0-gpio18 {
pin-pwm {
pins = "gpio18";
function = "alt5";
bias-disable;
};
};
- pwm1_0_gpio40: pwm1_0_gpio40 {
+ pwm1_0_gpio40: pwm1-0-gpio40 {
pin-pwm {
pins = "gpio40";
function = "alt0";
bias-disable;
};
};
- pwm0_1_gpio13: pwm0_1_gpio13 {
+ pwm0_1_gpio13: pwm0-1-gpio13 {
pin-pwm {
pins = "gpio13";
function = "alt0";
bias-disable;
};
};
- pwm0_1_gpio19: pwm0_1_gpio19 {
+ pwm0_1_gpio19: pwm0-1-gpio19 {
pin-pwm {
pins = "gpio19";
function = "alt5";
bias-disable;
};
};
- pwm1_1_gpio41: pwm1_1_gpio41 {
+ pwm1_1_gpio41: pwm1-1-gpio41 {
pin-pwm {
pins = "gpio41";
function = "alt0";
bias-disable;
};
};
- pwm0_1_gpio45: pwm0_1_gpio45 {
+ pwm0_1_gpio45: pwm0-1-gpio45 {
pin-pwm {
pins = "gpio45";
function = "alt0";
bias-disable;
};
};
- pwm0_0_gpio52: pwm0_0_gpio52 {
+ pwm0_0_gpio52: pwm0-0-gpio52 {
pin-pwm {
pins = "gpio52";
function = "alt1";
bias-disable;
};
};
- pwm0_1_gpio53: pwm0_1_gpio53 {
+ pwm0_1_gpio53: pwm0-1-gpio53 {
pin-pwm {
pins = "gpio53";
function = "alt1";
@@ -904,7 +905,7 @@
};
};
- rgmii_gpio35: rgmii_gpio35 {
+ rgmii_gpio35: rgmii-gpio35 {
pin-start-stop {
pins = "gpio35";
function = "alt4";
@@ -914,26 +915,26 @@
function = "alt4";
};
};
- rgmii_irq_gpio34: rgmii_irq_gpio34 {
+ rgmii_irq_gpio34: rgmii-irq-gpio34 {
pin-irq {
pins = "gpio34";
function = "alt5";
};
};
- rgmii_irq_gpio39: rgmii_irq_gpio39 {
+ rgmii_irq_gpio39: rgmii-irq-gpio39 {
pin-irq {
pins = "gpio39";
function = "alt4";
};
};
- rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
+ rgmii_mdio_gpio28: rgmii-mdio-gpio28 {
pins-mdio {
pins = "gpio28",
"gpio29";
function = "alt5";
};
};
- rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
+ rgmii_mdio_gpio37: rgmii-mdio-gpio37 {
pins-mdio {
pins = "gpio37",
"gpio38";
@@ -941,7 +942,7 @@
};
};
- spi0_gpio46: spi0_gpio46 {
+ spi0_gpio46: spi0-gpio46 {
pins-spi {
pins = "gpio46",
"gpio47",
@@ -950,7 +951,7 @@
function = "alt2";
};
};
- spi2_gpio46: spi2_gpio46 {
+ spi2_gpio46: spi2-gpio46 {
pins-spi {
pins = "gpio46",
"gpio47",
@@ -960,7 +961,7 @@
function = "alt5";
};
};
- spi3_gpio0: spi3_gpio0 {
+ spi3_gpio0: spi3-gpio0 {
pins-spi {
pins = "gpio0",
"gpio1",
@@ -969,7 +970,7 @@
function = "alt3";
};
};
- spi4_gpio4: spi4_gpio4 {
+ spi4_gpio4: spi4-gpio4 {
pins-spi {
pins = "gpio4",
"gpio5",
@@ -978,7 +979,7 @@
function = "alt3";
};
};
- spi5_gpio12: spi5_gpio12 {
+ spi5_gpio12: spi5-gpio12 {
pins-spi {
pins = "gpio12",
"gpio13",
@@ -987,7 +988,7 @@
function = "alt3";
};
};
- spi6_gpio18: spi6_gpio18 {
+ spi6_gpio18: spi6-gpio18 {
pins-spi {
pins = "gpio18",
"gpio19",
@@ -997,7 +998,7 @@
};
};
- uart2_gpio0: uart2_gpio0 {
+ uart2_gpio0: uart2-gpio0 {
pin-tx {
pins = "gpio0";
function = "alt4";
@@ -1009,7 +1010,7 @@
bias-pull-up;
};
};
- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
+ uart2_ctsrts_gpio2: uart2-ctsrts-gpio2 {
pin-cts {
pins = "gpio2";
function = "alt4";
@@ -1021,7 +1022,7 @@
bias-disable;
};
};
- uart3_gpio4: uart3_gpio4 {
+ uart3_gpio4: uart3-gpio4 {
pin-tx {
pins = "gpio4";
function = "alt4";
@@ -1033,7 +1034,7 @@
bias-pull-up;
};
};
- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
+ uart3_ctsrts_gpio6: uart3-ctsrts-gpio6 {
pin-cts {
pins = "gpio6";
function = "alt4";
@@ -1045,7 +1046,7 @@
bias-disable;
};
};
- uart4_gpio8: uart4_gpio8 {
+ uart4_gpio8: uart4-gpio8 {
pin-tx {
pins = "gpio8";
function = "alt4";
@@ -1057,7 +1058,7 @@
bias-pull-up;
};
};
- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
+ uart4_ctsrts_gpio10: uart4-ctsrts-gpio10 {
pin-cts {
pins = "gpio10";
function = "alt4";
@@ -1069,7 +1070,7 @@
bias-disable;
};
};
- uart5_gpio12: uart5_gpio12 {
+ uart5_gpio12: uart5-gpio12 {
pin-tx {
pins = "gpio12";
function = "alt4";
@@ -1081,7 +1082,7 @@
bias-pull-up;
};
};
- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
+ uart5_ctsrts_gpio14: uart5-ctsrts-gpio14 {
pin-cts {
pins = "gpio14";
function = "alt4";
diff --git a/arch/arm/boot/dts/bcm2835-common.dtsi b/arch/arm/boot/dts/bcm2835-common.dtsi
index a037d2bc5b11..bb7e8f7facaf 100644
--- a/arch/arm/boot/dts/bcm2835-common.dtsi
+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
@@ -152,41 +152,41 @@
};
&gpio {
- i2c_slave_gpio18: i2c_slave_gpio18 {
+ i2c_slave_gpio18: i2c-slave-gpio18 {
brcm,pins = <18 19 20 21>;
brcm,function = <BCM2835_FSEL_ALT3>;
};
- jtag_gpio4: jtag_gpio4 {
+ jtag_gpio4: jtag-gpio4 {
brcm,pins = <4 5 6 12 13>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- pwm0_gpio12: pwm0_gpio12 {
+ pwm0_gpio12: pwm0-gpio12 {
brcm,pins = <12>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- pwm0_gpio18: pwm0_gpio18 {
+ pwm0_gpio18: pwm0-gpio18 {
brcm,pins = <18>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- pwm0_gpio40: pwm0_gpio40 {
+ pwm0_gpio40: pwm0-gpio40 {
brcm,pins = <40>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- pwm1_gpio13: pwm1_gpio13 {
+ pwm1_gpio13: pwm1-gpio13 {
brcm,pins = <13>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- pwm1_gpio19: pwm1_gpio19 {
+ pwm1_gpio19: pwm1-gpio19 {
brcm,pins = <19>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- pwm1_gpio41: pwm1_gpio41 {
+ pwm1_gpio41: pwm1-gpio41 {
brcm,pins = <41>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- pwm1_gpio45: pwm1_gpio45 {
+ pwm1_gpio45: pwm1-gpio45 {
brcm,pins = <45>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
index 9b9a18bbb20a..02ce817868ba 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
/ {
@@ -12,19 +14,6 @@
device_type = "memory";
reg = <0 0x10000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&gpio {
@@ -107,6 +96,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
index f664e4fced93..3fdf60eb11dc 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
/ {
@@ -12,12 +14,6 @@
device_type = "memory";
reg = <0 0x10000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
- };
- };
};
&gpio {
@@ -102,6 +98,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
index 248feb2ed23d..9956fd06a4b6 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
@@ -13,19 +15,6 @@
device_type = "memory";
reg = <0 0x20000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&gpio {
@@ -109,6 +98,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
index f5b66d3f4ff3..4e1770afb145 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-smsc9512.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
@@ -13,12 +15,6 @@
device_type = "memory";
reg = <0 0x10000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
- };
- };
};
&gpio {
@@ -102,6 +98,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index f589bede2b11..eec1d0892d33 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-smsc9512.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
@@ -13,12 +15,6 @@
device_type = "memory";
reg = <0 0x10000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
- };
- };
};
&gpio {
@@ -96,6 +92,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
index e4e6b6abbfc1..750cd76948e3 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi
@@ -2,6 +2,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
/ {
leds {
@@ -32,6 +34,10 @@
};
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
+};
+
&sdhost {
non-removable;
vmmc-supply = <&reg_3v3>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-common.dtsi b/arch/arm/boot/dts/bcm2835-rpi-common.dtsi
index 8a55b6cded59..4e7b4a592da7 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-common.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi-common.dtsi
@@ -7,6 +7,23 @@
#include <dt-bindings/power/raspberrypi-power.h>
+&firmware {
+ firmware_clocks: clocks {
+ compatible = "raspberrypi,firmware-clocks";
+ #clock-cells = <1>;
+ };
+};
+
+&hdmi {
+ clocks = <&firmware_clocks 9>,
+ <&firmware_clocks 13>;
+ clock-names = "pixel", "hdmi";
+};
+
&v3d {
power-domains = <&power RPI_POWER_DOMAIN_V3D>;
};
+
+&vec {
+ clocks = <&firmware_clocks 15>;
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
index 596bb1ef994e..dbf825985ec0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
@@ -6,6 +6,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-otg.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -22,12 +24,6 @@
/* 8250 auxiliary UART instead of pl011 */
stdout-path = "serial1:115200n8";
};
-
- leds {
- led-act {
- gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
- };
- };
};
&bt {
@@ -110,6 +106,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
+};
+
&sdhci {
pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero.dts b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
index a65c2bca69ea..f80e65a825fd 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
@@ -6,6 +6,8 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-otg.dtsi"
/ {
@@ -16,12 +18,6 @@
device_type = "memory";
reg = <0 0x20000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
- };
- };
};
&gpio {
@@ -104,6 +100,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+};
+
&sdhost {
pinctrl-names = "default";
pinctrl-0 = <&sdhost_gpio48>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 87ddcad76083..ee9ee9d1fe65 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -1,16 +1,6 @@
#include <dt-bindings/power/raspberrypi-power.h>
/ {
- leds {
- compatible = "gpio-leds";
-
- led-act {
- label = "ACT";
- default-state = "keep";
- linux,default-trigger = "heartbeat";
- };
- };
-
soc {
firmware: firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 1c90e5a44283..15cb331febbb 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "bcm283x.dtsi"
#include "bcm2835-common.dtsi"
-#include "bcm2835-rpi-common.dtsi"
/ {
compatible = "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
index 3635502b1e0a..6068ec390081 100644
--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
@@ -2,6 +2,7 @@
/dts-v1/;
#include "bcm2836.dtsi"
#include "bcm2836-rpi.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
@@ -13,19 +14,6 @@
device_type = "memory";
reg = <0 0x40000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&gpio {
@@ -109,6 +97,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>;
diff --git a/arch/arm/boot/dts/bcm2836-rpi.dtsi b/arch/arm/boot/dts/bcm2836-rpi.dtsi
index c4c858b984c6..48b03b55ff56 100644
--- a/arch/arm/boot/dts/bcm2836-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2836-rpi.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi-common.dtsi"
&vchiq {
compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi
index 534dacfc4dd5..783fe624ba68 100644
--- a/arch/arm/boot/dts/bcm2836.dtsi
+++ b/arch/arm/boot/dts/bcm2836.dtsi
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "bcm283x.dtsi"
#include "bcm2835-common.dtsi"
-#include "bcm2835-rpi-common.dtsi"
/ {
compatible = "brcm,bcm2836";
@@ -11,7 +10,7 @@
<0x40000000 0x40000000 0x00001000>;
dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
- local_intc: local_intc@40000000 {
+ local_intc: interrupt-controller@40000000 {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
interrupt-controller;
@@ -113,6 +112,7 @@
*/
l2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts
index f7222a28903e..3548306dfbcb 100644
--- a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts
@@ -2,6 +2,7 @@
/dts-v1/;
#include "bcm2837.dtsi"
#include "bcm2836-rpi.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -18,19 +19,6 @@
device_type = "memory";
reg = <0 0x20000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&firmware {
@@ -124,6 +112,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
index ec721d323ac5..2f1800cbc522 100644
--- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
@@ -3,6 +3,7 @@
#include "bcm2837.dtsi"
#include "bcm2836-rpi.dtsi"
#include "bcm283x-rpi-lan7515.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -19,19 +20,6 @@
device_type = "memory";
reg = <0 0x40000000>;
};
-
- leds {
- led-act {
- gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
- };
-
- led-pwr {
- label = "PWR";
- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
- default-state = "keep";
- linux,default-trigger = "default-on";
- };
- };
};
&bt {
@@ -130,6 +118,19 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
+};
+
+&leds {
+ led-pwr {
+ label = "PWR";
+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+};
+
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
index fb6a417d73e7..61270340075c 100644
--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
@@ -2,6 +2,7 @@
/dts-v1/;
#include "bcm2837.dtsi"
#include "bcm2836-rpi.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -19,12 +20,6 @@
device_type = "memory";
reg = <0 0x40000000>;
};
-
- leds {
- led-act {
- gpios = <&expgpio 2 GPIO_ACTIVE_HIGH>;
- };
- };
};
&bt {
@@ -129,6 +124,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&expgpio 2 GPIO_ACTIVE_HIGH>;
+};
+
/* uart0 communicates with the BT module */
&uart0 {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi
index f57b4ca145dd..1e4e4946b6b6 100644
--- a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi
+++ b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi
@@ -9,14 +9,6 @@
reg = <0 0x40000000>;
};
- leds {
- /*
- * Since there is no upstream GPIO driver yet,
- * remove the incomplete node.
- */
- /delete-node/ led-act;
- };
-
reg_3v3: fixed-regulator {
compatible = "regulator-fixed";
regulator-name = "3V3";
diff --git a/arch/arm/boot/dts/bcm2837-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2837-rpi-zero-2-w.dts
index 4a768562985e..b9cc4594398b 100644
--- a/arch/arm/boot/dts/bcm2837-rpi-zero-2-w.dts
+++ b/arch/arm/boot/dts/bcm2837-rpi-zero-2-w.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include "bcm2837.dtsi"
#include "bcm2836-rpi.dtsi"
+#include "bcm283x-rpi-led-deprecated.dtsi"
#include "bcm283x-rpi-usb-otg.dtsi"
#include "bcm283x-rpi-wifi-bt.dtsi"
@@ -22,12 +23,6 @@
/* 8250 auxiliary UART instead of pl011 */
stdout-path = "serial1:115200n8";
};
-
- leds {
- led-act {
- gpios = <&gpio 29 GPIO_ACTIVE_LOW>;
- };
- };
};
&bt {
@@ -109,6 +104,10 @@
status = "okay";
};
+&led_act {
+ gpios = <&gpio 29 GPIO_ACTIVE_LOW>;
+};
+
&sdhci {
pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
};
diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
index 5dbdebc46259..84c08b46519d 100644
--- a/arch/arm/boot/dts/bcm2837.dtsi
+++ b/arch/arm/boot/dts/bcm2837.dtsi
@@ -1,6 +1,5 @@
#include "bcm283x.dtsi"
#include "bcm2835-common.dtsi"
-#include "bcm2835-rpi-common.dtsi"
/ {
compatible = "brcm,bcm2837";
@@ -115,6 +114,7 @@
*/
l2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>; // 512KiB(size)/64(line-size)=8192ways/16-way set
diff --git a/arch/arm/boot/dts/bcm283x-rpi-led-deprecated.dtsi b/arch/arm/boot/dts/bcm283x-rpi-led-deprecated.dtsi
new file mode 100644
index 000000000000..f83e56de1a72
--- /dev/null
+++ b/arch/arm/boot/dts/bcm283x-rpi-led-deprecated.dtsi
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+ /*
+ * This file provides the now deprecated ACT LED to the
+ * Raspberry Pi boards. Please don't include this file
+ * for new boards!
+ */
+ leds: leds {
+ compatible = "gpio-leds";
+
+ led_act: led-act {
+ label = "ACT";
+ default-state = "keep";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index d2d9c6e67f39..c9c52a19ef3b 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -135,17 +135,17 @@
* groups only make sense to switch to a
* particular function together.
*/
- dpi_gpio0: dpi_gpio0 {
+ dpi_gpio0: dpi-gpio0 {
brcm,pins = <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>;
brcm,function = <BCM2835_FSEL_ALT2>;
};
- emmc_gpio22: emmc_gpio22 {
+ emmc_gpio22: emmc-gpio22 {
brcm,pins = <22 23 24 25 26 27>;
brcm,function = <BCM2835_FSEL_ALT3>;
};
- emmc_gpio34: emmc_gpio34 {
+ emmc_gpio34: emmc-gpio34 {
brcm,pins = <34 35 36 37 38 39>;
brcm,function = <BCM2835_FSEL_ALT3>;
brcm,pull = <BCM2835_PUD_OFF
@@ -155,95 +155,95 @@
BCM2835_PUD_UP
BCM2835_PUD_UP>;
};
- emmc_gpio48: emmc_gpio48 {
+ emmc_gpio48: emmc-gpio48 {
brcm,pins = <48 49 50 51 52 53>;
brcm,function = <BCM2835_FSEL_ALT3>;
};
- gpclk0_gpio4: gpclk0_gpio4 {
+ gpclk0_gpio4: gpclk0-gpio4 {
brcm,pins = <4>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- gpclk1_gpio5: gpclk1_gpio5 {
+ gpclk1_gpio5: gpclk1-gpio5 {
brcm,pins = <5>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- gpclk1_gpio42: gpclk1_gpio42 {
+ gpclk1_gpio42: gpclk1-gpio42 {
brcm,pins = <42>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- gpclk1_gpio44: gpclk1_gpio44 {
+ gpclk1_gpio44: gpclk1-gpio44 {
brcm,pins = <44>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- gpclk2_gpio6: gpclk2_gpio6 {
+ gpclk2_gpio6: gpclk2-gpio6 {
brcm,pins = <6>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- gpclk2_gpio43: gpclk2_gpio43 {
+ gpclk2_gpio43: gpclk2-gpio43 {
brcm,pins = <43>;
brcm,function = <BCM2835_FSEL_ALT0>;
brcm,pull = <BCM2835_PUD_OFF>;
};
- i2c0_gpio0: i2c0_gpio0 {
+ i2c0_gpio0: i2c0-gpio0 {
brcm,pins = <0 1>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- i2c0_gpio28: i2c0_gpio28 {
+ i2c0_gpio28: i2c0-gpio28 {
brcm,pins = <28 29>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- i2c0_gpio44: i2c0_gpio44 {
+ i2c0_gpio44: i2c0-gpio44 {
brcm,pins = <44 45>;
brcm,function = <BCM2835_FSEL_ALT1>;
};
- i2c1_gpio2: i2c1_gpio2 {
+ i2c1_gpio2: i2c1-gpio2 {
brcm,pins = <2 3>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- i2c1_gpio44: i2c1_gpio44 {
+ i2c1_gpio44: i2c1-gpio44 {
brcm,pins = <44 45>;
brcm,function = <BCM2835_FSEL_ALT2>;
};
- jtag_gpio22: jtag_gpio22 {
+ jtag_gpio22: jtag-gpio22 {
brcm,pins = <22 23 24 25 26 27>;
brcm,function = <BCM2835_FSEL_ALT4>;
};
- pcm_gpio18: pcm_gpio18 {
+ pcm_gpio18: pcm-gpio18 {
brcm,pins = <18 19 20 21>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- pcm_gpio28: pcm_gpio28 {
+ pcm_gpio28: pcm-gpio28 {
brcm,pins = <28 29 30 31>;
brcm,function = <BCM2835_FSEL_ALT2>;
};
- sdhost_gpio48: sdhost_gpio48 {
+ sdhost_gpio48: sdhost-gpio48 {
brcm,pins = <48 49 50 51 52 53>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- spi0_gpio7: spi0_gpio7 {
+ spi0_gpio7: spi0-gpio7 {
brcm,pins = <7 8 9 10 11>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- spi0_gpio35: spi0_gpio35 {
+ spi0_gpio35: spi0-gpio35 {
brcm,pins = <35 36 37 38 39>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
- spi1_gpio16: spi1_gpio16 {
+ spi1_gpio16: spi1-gpio16 {
brcm,pins = <16 17 18 19 20 21>;
brcm,function = <BCM2835_FSEL_ALT4>;
};
- spi2_gpio40: spi2_gpio40 {
+ spi2_gpio40: spi2-gpio40 {
brcm,pins = <40 41 42 43 44 45>;
brcm,function = <BCM2835_FSEL_ALT4>;
};
- uart0_gpio14: uart0_gpio14 {
+ uart0_gpio14: uart0-gpio14 {
brcm,pins = <14 15>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
@@ -252,50 +252,50 @@
* people often run uart0 on the two pins
* without flow control.
*/
- uart0_ctsrts_gpio16: uart0_ctsrts_gpio16 {
+ uart0_ctsrts_gpio16: uart0-ctsrts-gpio16 {
brcm,pins = <16 17>;
brcm,function = <BCM2835_FSEL_ALT3>;
};
- uart0_ctsrts_gpio30: uart0_ctsrts_gpio30 {
+ uart0_ctsrts_gpio30: uart0-ctsrts-gpio30 {
brcm,pins = <30 31>;
brcm,function = <BCM2835_FSEL_ALT3>;
brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
};
- uart0_gpio32: uart0_gpio32 {
+ uart0_gpio32: uart0-gpio32 {
brcm,pins = <32 33>;
brcm,function = <BCM2835_FSEL_ALT3>;
brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
};
- uart0_gpio36: uart0_gpio36 {
+ uart0_gpio36: uart0-gpio36 {
brcm,pins = <36 37>;
brcm,function = <BCM2835_FSEL_ALT2>;
};
- uart0_ctsrts_gpio38: uart0_ctsrts_gpio38 {
+ uart0_ctsrts_gpio38: uart0-ctsrts-gpio38 {
brcm,pins = <38 39>;
brcm,function = <BCM2835_FSEL_ALT2>;
};
- uart1_gpio14: uart1_gpio14 {
+ uart1_gpio14: uart1-gpio14 {
brcm,pins = <14 15>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- uart1_ctsrts_gpio16: uart1_ctsrts_gpio16 {
+ uart1_ctsrts_gpio16: uart1-ctsrts-gpio16 {
brcm,pins = <16 17>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- uart1_gpio32: uart1_gpio32 {
+ uart1_gpio32: uart1-gpio32 {
brcm,pins = <32 33>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- uart1_ctsrts_gpio30: uart1_ctsrts_gpio30 {
+ uart1_ctsrts_gpio30: uart1-ctsrts-gpio30 {
brcm,pins = <30 31>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- uart1_gpio40: uart1_gpio40 {
+ uart1_gpio40: uart1-gpio40 {
brcm,pins = <40 41>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
- uart1_ctsrts_gpio42: uart1_ctsrts_gpio42 {
+ uart1_ctsrts_gpio42: uart1-ctsrts-gpio42 {
brcm,pins = <42 43>;
brcm,function = <BCM2835_FSEL_ALT5>;
};
diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
index 09ee3e46c0cc..c80ac16ad949 100644
--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
@@ -28,40 +28,39 @@
leds {
compatible = "gpio-leds";
- usb3 {
+ led-usb3 {
label = "bcm53xx:blue:usb3";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
};
- wan {
+ led-wan {
label = "bcm53xx:blue:wan";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
};
- lan {
+ led-lan {
label = "bcm53xx:blue:lan";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
};
- power {
+ led-power {
label = "bcm53xx:blue:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- all {
+ led-all {
label = "bcm53xx:blue:all";
gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
};
-
- usb2 {
+ led-usb2 {
label = "bcm53xx:blue:usb2";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
index 32619c6045d3..3fe17bd7b86d 100644
--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
@@ -28,24 +28,24 @@
leds {
compatible = "gpio-leds";
- usb2 {
+ led-usb2 {
label = "bcm53xx:blue:usb2";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
};
- power {
+ led-power {
label = "bcm53xx:blue:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- logo {
+ led-logo {
label = "bcm53xx:white:logo";
gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:blue:usb3";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi
index a658b9b7bcec..e583b9cbf07c 100644
--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi
@@ -37,7 +37,7 @@
leds {
compatible = "gpio-leds";
- usb {
+ led-usb {
/* label = "bcm53xx:blue:usb"; */
function = LED_FUNCTION_USB;
color = <LED_COLOR_ID_BLUE>;
@@ -48,14 +48,14 @@
linux,default-trigger = "usbport";
};
- power0 {
+ led-power0 {
/* label = "bcm53xx:red:power"; */
function = LED_FUNCTION_FAULT;
color = <LED_COLOR_ID_RED>;
gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
};
- power1 {
+ led-power1 {
/* label = "bcm53xx:white:power"; */
function = LED_FUNCTION_POWER;
color = <LED_COLOR_ID_WHITE>;
@@ -63,7 +63,7 @@
linux,default-trigger = "default-on";
};
- router0 {
+ led-router0 {
/* label = "bcm53xx:blue:router"; */
function = LED_FUNCTION_STATUS;
color = <LED_COLOR_ID_BLUE>;
@@ -71,14 +71,14 @@
linux,default-trigger = "default-on";
};
- router1 {
+ led-router1 {
/* label = "bcm53xx:amber:router"; */
function = LED_FUNCTION_STATUS;
color = <LED_COLOR_ID_AMBER>;
gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
};
- wan {
+ led-wan {
/* label = "bcm53xx:blue:wan"; */
function = LED_FUNCTION_WAN;
color = <LED_COLOR_ID_BLUE>;
@@ -86,14 +86,14 @@
linux,default-trigger = "default-on";
};
- wireless0 {
+ led-wireless0 {
/* label = "bcm53xx:blue:wireless"; */
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_BLUE>;
gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
};
- wireless1 {
+ led-wireless1 {
/* label = "bcm53xx:amber:wireless"; */
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_AMBER>;
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
index f8f53457dd43..43c698a0a7c3 100644
--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
@@ -49,7 +49,7 @@
leds {
compatible = "gpio-leds";
- usb {
+ led-usb {
label = "bcm53xx:blue:usb";
gpios = <&hc595 0 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -58,40 +58,40 @@
linux,default-trigger = "usbport";
};
- power0 {
+ led-power0 {
label = "bcm53xx:red:power";
gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
};
- power1 {
+ led-power1 {
label = "bcm53xx:white:power";
gpios = <&hc595 2 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- router0 {
+ led-router0 {
label = "bcm53xx:blue:router";
gpios = <&hc595 3 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- router1 {
+ led-router1 {
label = "bcm53xx:amber:router";
gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
};
- wan {
+ led-wan {
label = "bcm53xx:blue:wan";
gpios = <&hc595 5 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- wireless0 {
+ led-wireless0 {
label = "bcm53xx:blue:wireless";
gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
};
- wireless1 {
+ led-wireless1 {
label = "bcm53xx:amber:wireless";
gpios = <&hc595 7 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
index 14ee410183af..6de7fe204b0c 100644
--- a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
+++ b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
@@ -23,19 +23,19 @@
leds {
compatible = "gpio-leds";
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
index 600ab087f5e5..f5b75ba93512 100644
--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
@@ -42,7 +42,7 @@
leds {
compatible = "gpio-leds";
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index fd6d8d2a4456..89155caf50be 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -29,24 +29,24 @@
leds {
compatible = "gpio-leds";
- logo {
+ led-logo {
label = "bcm53xx:white:logo";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- power0 {
+ led-power0 {
label = "bcm53xx:green:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- power1 {
+ led-power1 {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- usb {
+ led-usb {
label = "bcm53xx:blue:usb";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -54,7 +54,7 @@
linux,default-trigger = "usbport";
};
- wireless {
+ led-wireless {
label = "bcm53xx:blue:wireless";
gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
index 76fc1099d47d..57d00a0b4765 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
@@ -28,29 +28,29 @@
leds {
compatible = "gpio-leds";
- logo {
+ led-logo {
label = "bcm53xx:white:logo";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- power0 {
+ led-power0 {
label = "bcm53xx:green:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
};
- power1 {
+ led-power1 {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- usb {
+ led-usb {
label = "bcm53xx:blue:usb";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
};
- wireless {
+ led-wireless {
label = "bcm53xx:blue:wireless";
gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
index 6bcdfb73cb9e..26cdeb5cc337 100644
--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
@@ -28,64 +28,64 @@
leds {
compatible = "gpio-leds";
- power-white {
+ led-power-white {
label = "bcm53xx:white:power";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- power-amber {
+ led-power-amber {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>;
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:white:usb2";
gpios = <&chipcommon 3 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port2>, <&ehci_port2>;
linux,default-trigger = "usbport";
};
- usb3-white {
+ led-usb3-white {
label = "bcm53xx:white:usb3";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
trigger-sources = <&xhci_port1>;
linux,default-trigger = "usbport";
};
- usb3-green {
+ led-usb3-green {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>;
linux,default-trigger = "usbport";
};
- wps {
+ led-wps {
label = "bcm53xx:white:wps";
gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
};
- status-red {
+ led-status-red {
label = "bcm53xx:red:status";
gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
};
- status-green {
+ led-status-green {
label = "bcm53xx:green:status";
gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
};
- status-blue {
+ led-status-blue {
label = "bcm53xx:blue:status";
gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
};
- wan-white {
+ led-wan-white {
label = "bcm53xx:white:wan";
gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
};
- wan-red {
+ led-wan-red {
label = "bcm53xx:red:wan";
gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
index ca47cc4f2ba1..3854db0118a9 100644
--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
@@ -28,30 +28,30 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "bcm53xx:blue:power";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:blue:usb2";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- wan {
+ led-wan {
label = "bcm53xx:blue:wan";
gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- lan {
+ led-lan {
label = "bcm53xx:blue:lan";
gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:blue:usb3";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
index 0edc2543e568..407319cb5c0d 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
@@ -49,40 +49,40 @@
leds {
compatible = "gpio-leds";
- power0 {
+ led-power0 {
label = "bcm53xx:green:power";
gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- power1 {
+ led-power1 {
label = "bcm53xx:red:power";
gpios = <&hc595 2 GPIO_ACTIVE_HIGH>;
};
- router0 {
+ led-router0 {
label = "bcm53xx:green:router";
gpios = <&hc595 3 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- router1 {
+ led-router1 {
label = "bcm53xx:amber:router";
gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
};
- wan {
+ led-wan {
label = "bcm53xx:green:wan";
gpios = <&hc595 5 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- wireless0 {
+ led-wireless0 {
label = "bcm53xx:green:wireless";
gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
};
- wireless1 {
+ led-wireless1 {
label = "bcm53xx:amber:wireless";
gpios = <&hc595 7 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
index 1f0998f34afd..f8622ecce6a2 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
@@ -49,45 +49,45 @@
leds {
compatible = "gpio-leds";
- usb {
+ led-usb {
label = "bcm53xx:green:usb";
gpios = <&hc595 0 GPIO_ACTIVE_HIGH>;
};
- power0 {
+ led-power0 {
label = "bcm53xx:green:power";
gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- power1 {
+ led-power1 {
label = "bcm53xx:red:power";
gpios = <&hc595 2 GPIO_ACTIVE_HIGH>;
};
- router0 {
+ led-router0 {
label = "bcm53xx:green:router";
gpios = <&hc595 3 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- router1 {
+ led-router1 {
label = "bcm53xx:amber:router";
gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
};
- wan {
+ led-wan {
label = "bcm53xx:green:wan";
gpios = <&hc595 5 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- wireless0 {
+ led-wireless0 {
label = "bcm53xx:green:wireless";
gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
};
- wireless1 {
+ led-wireless1 {
label = "bcm53xx:amber:wireless";
gpios = <&hc595 7 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts b/arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts
index c8c02377543b..76c9b30b868d 100644
--- a/arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts
+++ b/arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts
@@ -23,19 +23,19 @@
leds {
compatible = "gpio-leds";
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
diff --git a/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts b/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts
index 3b35a7af4b1c..6ef0c0788e62 100644
--- a/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts
+++ b/arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts
@@ -29,62 +29,62 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "bcm53xx:green:power";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- lan3 {
+ led-lan3 {
label = "bcm53xx:green:lan3";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- lan4 {
+ led-lan4 {
label = "bcm53xx:green:lan4";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- wan {
+ led-wan {
label = "bcm53xx:green:wan";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- lan2 {
+ led-lan2 {
label = "bcm53xx:green:lan2";
gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- usb {
+ led-usb {
label = "bcm53xx:green:usb";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port2>, <&ehci_port2>;
linux,default-trigger = "usbport";
};
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:green:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:green:5ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
};
- lan1 {
+ led-lan1 {
label = "bcm53xx:green:lan1";
gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
linux,default-trigger = "none";
diff --git a/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts b/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts
index 19a7971b5a00..b6a5886698b2 100644
--- a/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts
+++ b/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts
@@ -23,50 +23,50 @@
leds {
compatible = "gpio-leds";
- 2ghz {
+ led-2ghz {
label = "bcm53xx:green:2ghz";
gpios = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
};
- lan {
+ led-lan {
label = "bcm53xx:green:lan";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
};
- usb2-port1 {
+ led-usb2-port1 {
label = "bcm53xx:green:usb2-port1";
gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>;
linux,default-trigger = "usbport";
};
- power {
+ led-power {
label = "bcm53xx:green:power";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- wan-green {
+ led-wan-green {
label = "bcm53xx:green:wan";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
};
- wps {
+ led-wps {
label = "bcm53xx:green:wps";
gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
};
- wan-amber {
+ led-wan-amber {
label = "bcm53xx:amber:wan";
gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:green:5ghz";
gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
};
- usb2-port2 {
+ led-usb2-port2 {
label = "bcm53xx:green:usb2-port2";
gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port2>, <&ehci_port2>;
@@ -95,30 +95,15 @@
status = "okay";
partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- boot@0 {
- label = "boot";
- reg = <0x000000 0x040000>;
- read-only;
- };
+ compatible = "tplink,safeloader-partitions";
+ partitions-table-offset = <0xe50000>;
- os-image@100000 {
- label = "os-image";
- reg = <0x040000 0x200000>;
+ partition-os-image {
compatible = "brcm,trx";
};
- rootfs@240000 {
- label = "rootfs";
- reg = <0x240000 0xc00000>;
- };
-
- nvram@ff0000 {
- label = "nvram";
- reg = <0xff0000 0x010000>;
+ partition-file-system {
+ linux,rootfs;
};
};
};
diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
index f52a75c4ca09..4f44cb4df704 100644
--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
@@ -28,18 +28,18 @@
leds {
compatible = "gpio-leds";
- wps {
+ led-wps {
label = "bcm53xx:blue:wps";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
};
- power {
+ led-power {
label = "bcm53xx:blue:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- wan {
+ led-wan {
label = "bcm53xx:red:wan";
gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
index 5ff6c588e16e..b7cd2faa30ce 100644
--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
@@ -28,48 +28,48 @@
leds {
compatible = "gpio-leds";
- usb {
+ led-usb {
label = "bcm53xx:green:usb";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
};
- power-amber {
+ led-power-amber {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
};
- power-white {
+ led-power-white {
label = "bcm53xx:white:power";
gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- router-amber {
+ led-router-amber {
label = "bcm53xx:amber:router";
gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>;
};
- router-white {
+ led-router-white {
label = "bcm53xx:white:router";
gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
};
- wan-amber {
+ led-wan-amber {
label = "bcm53xx:amber:wan";
gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
};
- wan-white {
+ led-wan-white {
label = "bcm53xx:white:wan";
gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
};
- wireless-amber {
+ led-wireless-amber {
label = "bcm53xx:amber:wireless";
gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
};
- wireless-white {
+ led-wireless-white {
label = "bcm53xx:white:wireless";
gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
index de961fbb6200..24ba8f8f9bf3 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
@@ -28,43 +28,43 @@
leds {
compatible = "gpio-leds";
- power-white {
+ led-power-white {
label = "bcm53xx:white:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- power-amber {
+ led-power-amber {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:white:5ghz";
gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:white:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- wps {
+ led-wps {
label = "bcm53xx:white:wps";
gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
};
- wireless {
+ led-wireless {
label = "bcm53xx:white:wireless";
gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:white:usb3";
gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:white:usb2";
gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
index 087f7f60de18..14303ab521ea 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
@@ -39,59 +39,59 @@
leds {
compatible = "gpio-leds";
- power-white {
+ led-power-white {
label = "bcm53xx:white:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- power-amber {
+ led-power-amber {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- wan-white {
+ led-wan-white {
label = "bcm53xx:white:wan";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- wan-amber {
+ led-wan-amber {
label = "bcm53xx:amber:wan";
gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
};
- 5ghz-1 {
+ led-5ghz-1 {
label = "bcm53xx:white:5ghz-1";
gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:white:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- wireless {
+ led-wireless {
label = "bcm53xx:white:wireless";
gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
};
- wps {
+ led-wps {
label = "bcm53xx:white:wps";
gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
};
- 5ghz-2 {
+ led-5ghz-2 {
label = "bcm53xx:white:5ghz-2";
gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:white:usb3";
gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:white:usb2";
gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
index 11d1068160da..5a8b2b1567e6 100644
--- a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
+++ b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
@@ -23,27 +23,27 @@
leds {
compatible = "gpio-leds";
- lan {
+ led-lan {
label = "bcm53xx:blue:lan";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
};
- wps {
+ led-wps {
label = "bcm53xx:blue:wps";
gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>;
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:blue:usb3";
gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -51,24 +51,24 @@
linux,default-trigger = "usbport";
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:blue:usb2";
gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port2>, <&ehci_port2>;
linux,default-trigger = "usbport";
};
- wan-blue {
+ led-wan-blue {
label = "bcm53xx:blue:wan";
gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
};
- wan-amber {
+ led-wan-amber {
label = "bcm53xx:amber:wan";
gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
};
- power {
+ led-power {
label = "bcm53xx:blue:power";
gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
@@ -104,30 +104,15 @@
status = "okay";
partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- boot@0 {
- label = "boot";
- reg = <0x000000 0x040000>;
- read-only;
- };
+ compatible = "tplink,safeloader-partitions";
+ partitions-table-offset = <0xe50000>;
- os-image@100000 {
- label = "os-image";
- reg = <0x040000 0x200000>;
+ partition-os-image {
compatible = "brcm,trx";
};
- rootfs@240000 {
- label = "rootfs";
- reg = <0x240000 0xc00000>;
- };
-
- nvram@ff0000 {
- label = "nvram";
- reg = <0xff0000 0x010000>;
+ partition-file-system {
+ linux,rootfs;
};
};
};
diff --git a/arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts b/arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts
index a5fec56d11c0..a50ff686b557 100644
--- a/arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts
+++ b/arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts
@@ -33,37 +33,37 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "white:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- wan-red {
+ led-wan-red {
label = "red:wan";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
};
- lan {
+ led-lan {
label = "white:lan";
gpios = <&chipcommon 21 GPIO_ACTIVE_LOW>;
};
- usb2 {
+ led-usb2 {
label = "white:usb2";
gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
trigger-sources = <&ehci_port2>;
linux,default-trigger = "usbport";
};
- usb3 {
+ led-usb3 {
label = "white:usb3";
gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
trigger-sources = <&ehci_port1>, <&xhci_port1>;
linux,default-trigger = "usbport";
};
- wps {
+ led-wps {
label = "white:wps";
gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
index 2c38b642a8b8..555fbe41dd8f 100644
--- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
+++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
@@ -43,28 +43,28 @@
leds {
compatible = "gpio-leds";
- power-white {
+ led-power-white {
label = "bcm53xx:white:power";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- wan-white {
+ led-wan-white {
label = "bcm53xx:white:wan";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
};
- power-amber {
+ led-power-amber {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
};
- wan-amber {
+ led-wan-amber {
label = "bcm53xx:amber:wan";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- usb3-white {
+ led-usb3-white {
label = "bcm53xx:white:usb3";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -72,12 +72,12 @@
linux,default-trigger = "usbport";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:white:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:white:5ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-890l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-890l.dts
new file mode 100644
index 000000000000..d945a20b06e0
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47094-dlink-dir-890l.dts
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Device tree for D-Link DIR-890L
+ * D-Link calls this board "WRGAC36"
+ * this router has the same looks and form factor as D-Link DIR-885L.
+ *
+ * Some differences from DIR-885L include a separate USB2 port, separate LEDs
+ * for USB2 and USB3, a separate VCC supply for the USB2 slot and no
+ * router/extender switch is mounted (there is an empty mount point on the
+ * PCB) so this device is a pure router. Also the LAN ports are in the right
+ * order.
+ *
+ * Based on the device tree for DIR-885L
+ * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+ * Copyright (C) 2022 Linus Walleij
+ */
+
+/dts-v1/;
+
+#include "bcm47094.dtsi"
+#include "bcm5301x-nand-cs0-bch1.dtsi"
+
+/ {
+ compatible = "dlink,dir-890l", "brcm,bcm47094", "brcm,bcm4708";
+ model = "D-Link DIR-890L";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlycon";
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+ };
+
+ leds {
+ /*
+ * LED information is derived from the boot log which
+ * conveniently lists all the LEDs.
+ */
+ compatible = "gpio-leds";
+
+ led-power-white {
+ label = "bcm53xx:white:power";
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ led-wan-white {
+ label = "bcm53xx:white:wan";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ };
+
+ led-power-amber {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ };
+
+ led-wan-amber {
+ label = "bcm53xx:amber:wan";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ };
+
+ led-usb3-white {
+ label = "bcm53xx:white:usb3";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
+ trigger-sources = <&xhci_port1>;
+ linux,default-trigger = "usbport";
+ };
+
+ led-usb2-white {
+ label = "bcm53xx:white:usb2";
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ trigger-sources = <&ohci_port1>, <&ehci_port1>;
+ linux,default-trigger = "usbport";
+ };
+
+ led-2ghz {
+ label = "bcm53xx:white:2ghz";
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ };
+
+ led-5ghz {
+ label = "bcm53xx:white:5ghz";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ button-wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Called "factory reset" in the vendor dmesg */
+ button-restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ /*
+ * The flash memory is memory mapped at 0x1e000000-0x1fffffff
+ * 64KB blocks; total size 2MB, same that can be
+ * found attached to the spi_nor SPI controller.
+ */
+ nvram@1e1f0000 {
+ compatible = "brcm,nvram";
+ reg = <0x1e1f0000 0x00010000>;
+
+ et0macaddr: et0macaddr {
+ };
+ };
+};
+
+&gmac2 {
+ /*
+ * The NVRAM curiously does not contain a MAC address
+ * for et2 so since that is the only ethernet interface
+ * actually in use on the platform, we use this et0 MAC
+ * address for et2.
+ */
+ nvmem-cells = <&et0macaddr>;
+ nvmem-cell-names = "mac-address";
+};
+
+&spi_nor {
+ status = "okay";
+};
+
+&nandcs {
+ /* Spansion S34ML01G2, 128MB with 128KB erase blocks */
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /*
+ * This is called "nflash" in the vendor kernel with
+ * "upgrade" and "rootfs" (probably using OpenWrt
+ * splitpart). We call it "firmware" like standard tools
+ * assume. The CFE loader contains incorrect information
+ * about TRX partitions, ignore this, there are no TRX
+ * partitions: this device uses SEAMA.
+ */
+ firmware@0 {
+ label = "firmware";
+ reg = <0x00000000 0x08000000>;
+ };
+ };
+};
+
+&usb2 {
+ vcc-gpios = <&chipcommon 21 GPIO_ACTIVE_HIGH>;
+};
+
+&usb3 {
+ vcc-gpios = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
+};
+
+&usb3_phy {
+ status = "okay";
+};
+
+&srab {
+ status = "okay";
+
+ ports {
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan3";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan4";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "wan";
+ };
+
+ port@8 {
+ reg = <8>;
+ label = "cpu";
+ ethernet = <&gmac2>;
+ phy-mode = "rgmii";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
index 86c7cc0fa70e..d9a16a820e7f 100644
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -52,19 +52,19 @@
leds {
compatible = "gpio-leds";
- wps {
+ led-wps {
label = "bcm53xx:white:wps";
gpios = <&chipcommon 22 GPIO_ACTIVE_LOW>;
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:green:usb2";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port2>, <&ehci_port2>;
linux,default-trigger = "usbport";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -72,58 +72,58 @@
linux,default-trigger = "usbport";
};
- power {
+ led-power {
label = "bcm53xx:white:power";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-on";
};
- wifi-disabled {
+ led-wifi-disabled {
label = "bcm53xx:amber:wifi-disabled";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
};
- wifi-enabled {
+ led-wifi-enabled {
label = "bcm53xx:white:wifi-enabled";
gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
};
- bluebar1 {
+ led-bluebar1 {
label = "bcm53xx:white:bluebar1";
gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
};
- bluebar2 {
+ led-bluebar2 {
label = "bcm53xx:white:bluebar2";
gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
};
- bluebar3 {
+ led-bluebar3 {
label = "bcm53xx:white:bluebar3";
gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
};
- bluebar4 {
+ led-bluebar4 {
label = "bcm53xx:white:bluebar4";
gpios = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
};
- bluebar5 {
+ led-bluebar5 {
label = "bcm53xx:white:bluebar5";
gpios = <&chipcommon 19 GPIO_ACTIVE_HIGH>;
};
- bluebar6 {
+ led-bluebar6 {
label = "bcm53xx:white:bluebar6";
gpios = <&chipcommon 20 GPIO_ACTIVE_HIGH>;
};
- bluebar7 {
+ led-bluebar7 {
label = "bcm53xx:white:bluebar7";
gpios = <&chipcommon 21 GPIO_ACTIVE_HIGH>;
};
- bluebar8 {
+ led-bluebar8 {
label = "bcm53xx:white:bluebar8";
gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts b/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts
index 9ad15bcae1ca..41a0722fa64a 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts
@@ -30,13 +30,13 @@
leds {
compatible = "gpio-leds";
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts b/arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts
index ee24d3768536..c56c7e366848 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts
@@ -23,18 +23,18 @@
leds {
compatible = "gpio-leds";
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts b/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts
index 6549d07b9887..1b5c91a524ac 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts
@@ -30,13 +30,13 @@
leds {
compatible = "gpio-leds";
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 20 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 19 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
index 654fcce9fded..739063b77b1f 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
@@ -25,7 +25,7 @@
leds {
compatible = "gpio-leds";
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
index bf053a2fcc7c..7afc68d5d2c2 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
@@ -30,38 +30,38 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "bcm53xx:green:power";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- lan3 {
+ led-lan3 {
label = "bcm53xx:green:lan3";
gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
};
- lan4 {
+ led-lan4 {
label = "bcm53xx:green:lan4";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
};
- wan {
+ led-wan {
label = "bcm53xx:green:wan";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- lan1 {
+ led-lan1 {
label = "bcm53xx:green:lan1";
gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
};
- lan2 {
+ led-lan2 {
label = "bcm53xx:green:lan2";
gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -69,18 +69,18 @@
linux,default-trigger = "usbport";
};
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:green:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:green:5ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
index 78a90dd57a4e..60a2c441d5bd 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
@@ -33,13 +33,13 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "bcm53xx:green:power";
gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:green:usb3";
gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
trigger-sources = <&ohci_port1>, <&ehci_port1>,
@@ -47,18 +47,18 @@
linux,default-trigger = "usbport";
};
- status {
+ led-status {
label = "bcm53xx:green:status";
gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:green:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:green:5ghz";
gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
index f850dce37b20..76d562610654 100644
--- a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
+++ b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts
@@ -25,38 +25,38 @@
leds {
compatible = "gpio-leds";
- power0 {
+ led-power0 {
label = "bcm53xx:white:power";
gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-on";
};
- power1 {
+ led-power1 {
label = "bcm53xx:amber:power";
gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
};
- 5ghz-1 {
+ led-5ghz-1 {
label = "bcm53xx:white:5ghz-1";
gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
};
- 5ghz-2 {
+ led-5ghz-2 {
label = "bcm53xx:white:5ghz-2";
gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:white:2ghz";
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
};
- usb2 {
+ led-usb2 {
label = "bcm53xx:white:usb2";
gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
};
- usb3 {
+ led-usb3 {
label = "bcm53xx:white:usb3";
gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts b/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
index e20b6d2eb274..0734aa249b8e 100644
--- a/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
+++ b/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
@@ -23,13 +23,13 @@
leds {
compatible = "gpio-leds";
- wlan {
+ led-wlan {
label = "bcm53xx:blue:wlan";
gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-off";
};
- system {
+ led-system {
label = "bcm53xx:green:system";
gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
diff --git a/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts b/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
index 9d863570fcf3..e6fb6cbe6963 100644
--- a/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
+++ b/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
@@ -20,26 +20,26 @@
reg = <0x00000000 0x08000000>;
};
- leds {
+ leds-0 {
compatible = "gpio-leds";
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-off";
};
- system {
+ led-system {
label = "bcm53xx:green:system";
gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
};
};
- pcie0_leds {
+ leds-1 {
compatible = "gpio-leds";
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&pcie0_chipcommon 3 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "default-off";
diff --git a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts
index 55b92645b0f1..dab2e5f63a72 100644
--- a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts
+++ b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts
@@ -20,37 +20,37 @@
reg = <0x00000000 0x08000000>;
};
- leds {
+ leds-0 {
compatible = "gpio-leds";
- usb {
+ led-usb {
label = "bcm53xx:blue:usb";
gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>;
linux,default-trigger = "usbport";
};
- wps {
+ led-wps {
label = "bcm53xx:blue:wps";
gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
};
- system {
+ led-system {
label = "bcm53xx:blue:system";
gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
};
};
- pcie0_leds {
+ leds-1 {
compatible = "gpio-leds";
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&pcie0_chipcommon 3 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/bcm47622.dtsi b/arch/arm/boot/dts/bcm47622.dtsi
index 2df04528af82..f4b2db9bc4ab 100644
--- a/arch/arm/boot/dts/bcm47622.dtsi
+++ b/arch/arm/boot/dts/bcm47622.dtsi
@@ -51,6 +51,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm53016-dlink-dwl-8610ap.dts b/arch/arm/boot/dts/bcm53016-dlink-dwl-8610ap.dts
new file mode 100644
index 000000000000..c1f54391746f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm53016-dlink-dwl-8610ap.dts
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/dts-v1/;
+
+#include "bcm4709.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "D-Link DWL-8610AP";
+ compatible = "dlink,dwl-8610ap", "brcm,bcm53016", "brcm,bcm4708";
+
+ memory@0 {
+ device_type = "memory";
+ /* 512 MB RAM in 2 x Macronix D9PSH chips */
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-power {
+ function = LED_FUNCTION_POWER;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ };
+
+ led-diag {
+ /* Actually "diag" unclear what this means */
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+
+ led-wlan-2g {
+ function = LED_FUNCTION_WLAN;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ };
+
+ led-wlan-5g {
+ function = LED_FUNCTION_WLAN;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ button-reset {
+ debounce-interval = <100>;
+ wakeup-source;
+ linux,code = <KEY_RESTART>;
+ label = "reset";
+ /* This GPIO is actually stored in NVRAM, but it's not gonna change */
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ /*
+ * Flash memory at 0x1e000000-0x1fffffff
+ * Macronix 32 64KB blocks; total size 2MB, same that can be
+ * found attached to the spi_nor SPI controller.
+ */
+ nvram@1e080000 {
+ compatible = "brcm,nvram";
+ reg = <0x1e080000 0x00020000>;
+
+ et0macaddr: et0macaddr {
+ };
+
+ et1macaddr: et1macaddr {
+ };
+ };
+};
+
+&gmac0 {
+ nvmem-cells = <&et0macaddr>;
+ nvmem-cell-names = "mac-address";
+};
+
+&gmac1 {
+ nvmem-cells = <&et1macaddr>;
+ nvmem-cell-names = "mac-address";
+};
+
+&spi_nor {
+ /* Serial SPI NOR Flash MX 25L1606E */
+ status = "okay";
+};
+
+&nandcs {
+ /*
+ * Spansion S34ML01G100TFI00 128 MB NAND Flash memory
+ *
+ * This ECC is a bit unorthodox but it is what the stock firmware
+ * is using, so to be able to mount the original partitions
+ * this is necessary.
+ */
+ nand-ecc-strength = <5>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* This is named nflash1.trx in CFE */
+ trx@0 {
+ label = "firmware";
+ reg = <0x00000000 0x02800000>;
+ compatible = "brcm,trx";
+ };
+
+ /* This is named nflash1.trx2 in CFE */
+ trx2@2800000 {
+ label = "firmware2";
+ reg = <0x02800000 0x02800000>;
+ compatible = "brcm,trx";
+ };
+
+ /* This is named nflash1.rwfs in CFE */
+ free@5000000 {
+ label = "free";
+ reg = <0x05000000 0x03000000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm53016-meraki-mr32.dts b/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
index e678bc03d816..46c2c93b01d8 100644
--- a/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
+++ b/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
@@ -58,7 +58,7 @@
pwm-leds {
compatible = "pwm-leds";
- red {
+ led-0 {
/* SYS-LED 1 - Tricolor */
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_RED>;
@@ -66,7 +66,7 @@
max-brightness = <255>;
};
- green {
+ led-1 {
/* SYS-LED 1 - Tricolor */
function = LED_FUNCTION_POWER;
color = <LED_COLOR_ID_GREEN>;
@@ -74,7 +74,7 @@
max-brightness = <255>;
};
- blue {
+ led-2 {
/* SYS-LED 1 - Tricolor */
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_BLUE>;
diff --git a/arch/arm/boot/dts/bcm63148.dtsi b/arch/arm/boot/dts/bcm63148.dtsi
index df5307b6b3af..7cd55d64de71 100644
--- a/arch/arm/boot/dts/bcm63148.dtsi
+++ b/arch/arm/boot/dts/bcm63148.dtsi
@@ -35,6 +35,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm63178.dtsi b/arch/arm/boot/dts/bcm63178.dtsi
index cbd094dde6d0..043e699cbc27 100644
--- a/arch/arm/boot/dts/bcm63178.dtsi
+++ b/arch/arm/boot/dts/bcm63178.dtsi
@@ -43,6 +43,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm6756.dtsi b/arch/arm/boot/dts/bcm6756.dtsi
index ce1b59faf800..5c72219bc194 100644
--- a/arch/arm/boot/dts/bcm6756.dtsi
+++ b/arch/arm/boot/dts/bcm6756.dtsi
@@ -51,6 +51,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm6846.dtsi b/arch/arm/boot/dts/bcm6846.dtsi
index 8aa47a2583b2..81513a793815 100644
--- a/arch/arm/boot/dts/bcm6846.dtsi
+++ b/arch/arm/boot/dts/bcm6846.dtsi
@@ -35,6 +35,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm6855.dtsi b/arch/arm/boot/dts/bcm6855.dtsi
index 620f51aee1a2..5fa5feac0e29 100644
--- a/arch/arm/boot/dts/bcm6855.dtsi
+++ b/arch/arm/boot/dts/bcm6855.dtsi
@@ -43,6 +43,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm6878.dtsi b/arch/arm/boot/dts/bcm6878.dtsi
index 1e8b5fa96c25..4ec836ac4baf 100644
--- a/arch/arm/boot/dts/bcm6878.dtsi
+++ b/arch/arm/boot/dts/bcm6878.dtsi
@@ -35,6 +35,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm/boot/dts/bcm947189acdbmr.dts b/arch/arm/boot/dts/bcm947189acdbmr.dts
index 16e70a264faf..3709baa2376f 100644
--- a/arch/arm/boot/dts/bcm947189acdbmr.dts
+++ b/arch/arm/boot/dts/bcm947189acdbmr.dts
@@ -25,17 +25,17 @@
leds {
compatible = "gpio-leds";
- wps {
+ led-wps {
label = "bcm53xx:blue:wps";
gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
};
- 5ghz {
+ led-5ghz {
label = "bcm53xx:blue:5ghz";
gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
};
- 2ghz {
+ led-2ghz {
label = "bcm53xx:blue:2ghz";
gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 00a36fba2fd2..9aee3cfd3e98 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -139,7 +139,7 @@
pcie1: pcie@2 {
device_type = "pci";
status = "disabled";
- assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
+ assigned-addresses = <0x82001000 0 0x80000 0 0x2000>;
reg = <0x1000 0 0 0 0>;
clocks = <&gate_clk 5>;
marvell,pcie-port = <1>;
diff --git a/arch/arm/boot/dts/dra7-evm-common.dtsi b/arch/arm/boot/dts/dra7-evm-common.dtsi
index 68c43eb12c1a..4cdffd6db740 100644
--- a/arch/arm/boot/dts/dra7-evm-common.dtsi
+++ b/arch/arm/boot/dts/dra7-evm-common.dtsi
@@ -151,7 +151,7 @@
*/
partition@0 {
label = "QSPI.SPL";
- reg = <0x00000000 0x000010000>;
+ reg = <0x00000000 0x00010000>;
};
partition@1 {
label = "QSPI.SPL.backup1";
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 87deb6a76eff..8cbcf55a5a33 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -483,7 +483,7 @@
#size-cells = <1>;
partition@0 {
label = "NAND.SPL";
- reg = <0x00000000 0x000020000>;
+ reg = <0x00000000 0x00020000>;
};
partition@1 {
label = "NAND.SPL.backup1";
diff --git a/arch/arm/boot/dts/dra72-evm-common.dtsi b/arch/arm/boot/dts/dra72-evm-common.dtsi
index 8948e10dbeb8..c79ba671ec2b 100644
--- a/arch/arm/boot/dts/dra72-evm-common.dtsi
+++ b/arch/arm/boot/dts/dra72-evm-common.dtsi
@@ -356,7 +356,7 @@
#size-cells = <1>;
partition@0 {
label = "NAND.SPL";
- reg = <0x00000000 0x000020000>;
+ reg = <0x00000000 0x00020000>;
};
partition@1 {
label = "NAND.SPL.backup1";
@@ -490,7 +490,7 @@
*/
partition@0 {
label = "QSPI.SPL";
- reg = <0x00000000 0x000010000>;
+ reg = <0x00000000 0x00010000>;
};
partition@1 {
label = "QSPI.SPL.backup1";
diff --git a/arch/arm/boot/dts/e60k02.dtsi b/arch/arm/boot/dts/e60k02.dtsi
index 935e2359f8df..94944cc21931 100644
--- a/arch/arm/boot/dts/e60k02.dtsi
+++ b/arch/arm/boot/dts/e60k02.dtsi
@@ -104,7 +104,16 @@
clock-frequency = <100000>;
status = "okay";
- /* TODO: CYTTSP5 touch controller at 0x24 */
+ touchscreen@24 {
+ compatible = "cypress,tt21000";
+ reg = <0x24>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_cyttsp5_gpio>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+ vdd-supply = <&ldo5_reg>;
+ };
/* TODO: TPS65185 PMIC for E Ink at 0x68 */
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 326b9e0ed8d3..a2d6ee7fff08 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -485,7 +485,7 @@
};
mfc: codec@13400000 {
- compatible = "samsung,mfc-v7";
+ compatible = "samsung,exynos3250-mfc", "samsung,mfc-v7";
reg = <0x13400000 0x10000>;
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "mfc", "sclk_mfc";
diff --git a/arch/arm/boot/dts/imx6dl-colibri-aster.dts b/arch/arm/boot/dts/imx6dl-colibri-aster.dts
index 74e8a6cd8bed..a28e083f29d5 100644
--- a/arch/arm/boot/dts/imx6dl-colibri-aster.dts
+++ b/arch/arm/boot/dts/imx6dl-colibri-aster.dts
@@ -99,7 +99,6 @@
};
&usbh1 {
- vbus-supply = <&reg_usb_host_vbus>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
index 7272edd85a49..a02981d4a3fc 100644
--- a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
@@ -111,7 +111,6 @@
};
&usbh1 {
- vbus-supply = <&reg_usb_host_vbus>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6dl-colibri-iris.dts b/arch/arm/boot/dts/imx6dl-colibri-iris.dts
index cf77d894f6d7..c5797ff35b71 100644
--- a/arch/arm/boot/dts/imx6dl-colibri-iris.dts
+++ b/arch/arm/boot/dts/imx6dl-colibri-iris.dts
@@ -138,7 +138,6 @@
};
&usbh1 {
- vbus-supply = <&reg_usb_host_vbus>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6q-prti6q.dts b/arch/arm/boot/dts/imx6q-prti6q.dts
index b4605edfd2ab..d8fa83effd63 100644
--- a/arch/arm/boot/dts/imx6q-prti6q.dts
+++ b/arch/arm/boot/dts/imx6q-prti6q.dts
@@ -364,8 +364,8 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_wifi>;
interrupts-extended = <&gpio1 30 IRQ_TYPE_LEVEL_HIGH>;
- ref-clock-frequency = "38400000";
- tcxo-clock-frequency = "19200000";
+ ref-clock-frequency = <38400000>;
+ tcxo-clock-frequency = <19200000>;
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/imx6qdl-colibri.dtsi
index 023e76215064..d8f985f297e4 100644
--- a/arch/arm/boot/dts/imx6qdl-colibri.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-colibri.dtsi
@@ -24,6 +24,13 @@
status = "disabled";
};
+ extcon_usbc_det: usbc-det {
+ compatible = "linux,extcon-usb-gpio";
+ id-gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>; /* SODIMM 137 / USBC_DET */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbc_det>;
+ };
+
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
@@ -105,7 +112,7 @@
reg_usb_host_vbus: regulator-usb-host-vbus {
compatible = "regulator-fixed";
- gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; /* USBH_PEN */
+ gpio = <&gpio3 31 GPIO_ACTIVE_LOW>; /* SODIMM 129 / USBH_PEN */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_regulator_usbh_pwr>;
regulator-max-microvolt = <5000000>;
@@ -670,9 +677,16 @@
status = "disabled";
};
+/* Colibri USBH */
+&usbh1 {
+ vbus-supply = <&reg_usb_host_vbus>;
+};
+
+/* Colibri USBC */
&usbotg {
disable-over-current;
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ extcon = <0>, <&extcon_usbc_det>;
status = "disabled";
};
@@ -986,7 +1000,7 @@
pinctrl_regulator_usbh_pwr: gpioregusbhpwrgrp {
fsl,pins = <
- /* USBH_EN */
+ /* SODIMM 129 / USBH_PEN */
MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x0f058
>;
};
@@ -1055,7 +1069,7 @@
pinctrl_usbc_det: usbcdetgrp {
fsl,pins = <
- /* USBC_DET */
+ /* SODIMM 137 / USBC_DET */
MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
/* USBC_DET_OVERWRITE */
MX6QDL_PAD_RGMII_RXC__GPIO6_IO30 0x0f058
diff --git a/arch/arm/boot/dts/imx6qdl-pico.dtsi b/arch/arm/boot/dts/imx6qdl-pico.dtsi
index f7a56d6b160c..c39a9ebdaba1 100644
--- a/arch/arm/boot/dts/imx6qdl-pico.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-pico.dtsi
@@ -233,7 +233,6 @@
pinctrl-0 = <&pinctrl_ov5645>;
reg = <0x3c>;
clocks = <&clks IMX6QDL_CLK_CKO2>;
- clock-names = "xclk";
clock-frequency = <24000000>;
vdddo-supply = <&reg_1p8v>;
vdda-supply = <&reg_2p8v>;
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 22f8e2783cdf..12573e1f917c 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -14,6 +14,11 @@
stdout-path = &uart2;
};
+ aliases {
+ mmc0 = &usdhc3;
+ mmc1 = &usdhc4;
+ };
+
memory@10000000 {
device_type = "memory";
reg = <0x10000000 0x40000000>;
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
index ec6fba5ee8fd..e4f63423d8ee 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
@@ -131,7 +131,6 @@
pinctrl-0 = <&pinctrl_ov5645>;
reg = <0x3c>;
clocks = <&clks IMX6QDL_CLK_CKO2>;
- clock-names = "xclk";
clock-frequency = <24000000>;
vdddo-supply = <&reg_1p8v>;
vdda-supply = <&reg_2p8v>;
diff --git a/arch/arm/boot/dts/imx6sl-kobo-aura2.dts b/arch/arm/boot/dts/imx6sl-kobo-aura2.dts
new file mode 100644
index 000000000000..657d0f1b6115
--- /dev/null
+++ b/arch/arm/boot/dts/imx6sl-kobo-aura2.dts
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device tree for the Kobo Aura 2 ebook reader
+ *
+ * Name on mainboard is: 37NB-E60QL0+4B1
+ * Serials start with: E60QL2
+ *
+ * Copyright 2022 Andreas Kemnade
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "imx6sl.dtsi"
+
+/ {
+ model = "Kobo Aura 2";
+ compatible = "kobo,aura2", "fsl,imx6sl";
+
+ aliases {
+ mmc0 = &usdhc2;
+ mmc1 = &usdhc3;
+ };
+
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ gpio_keys: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ key-cover {
+ label = "Cover";
+ gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
+ linux,code = <SW_LID>;
+ linux,input-type = <EV_SW>;
+ wakeup-source;
+ };
+
+ key-power {
+ label = "Power";
+ gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ wakeup-source;
+ };
+ };
+
+ leds: leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_led>;
+
+ led-0 {
+ label = "koboaura2:white:on";
+ gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
+ color = <LED_COLOR_ID_WHITE>;
+ linux,default-trigger = "timer";
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x10000000>;
+ };
+
+ reg_wifi: regulator-wifi {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wifi_power>;
+ regulator-name = "SD3_SPWR";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ gpio = <&gpio4 29 GPIO_ACTIVE_LOW>;
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wifi_reset>;
+ post-power-on-delay-ms = <20>;
+ reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_sleep>;
+ status = "okay";
+
+ lm3630a: backlight@36 {
+ compatible = "ti,lm3630a";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lm3630a_bl_gpio>;
+ reg = <0x36>;
+ enable-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ led-sources = <0>;
+ label = "backlight";
+ default-brightness = <0>;
+ max-brightness = <255>;
+ };
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_sleep>;
+ clock-frequency = <100000>;
+ status = "okay";
+
+ /* eKTF2232 at 0x15 */
+ /* FP9928 at 0x48 */
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clock-frequency = <400000>;
+ status = "okay";
+
+ ricoh619: pmic@32 {
+ compatible = "ricoh,rc5t619";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ricoh_gpio>;
+ reg = <0x32>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ system-power-controller;
+
+ regulators {
+ dcdc1_reg: DCDC1 {
+ regulator-name = "DCDC1";
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <900000>;
+ regulator-suspend-min-microvolt = <900000>;
+ };
+ };
+
+ /* Core3_3V3 */
+ dcdc2_reg: DCDC2 {
+ regulator-name = "DCDC2";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <3100000>;
+ regulator-suspend-min-microvolt = <3100000>;
+ };
+ };
+
+ dcdc3_reg: DCDC3 {
+ regulator-name = "DCDC3";
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <1140000>;
+ regulator-suspend-min-microvolt = <1140000>;
+ };
+ };
+
+ /* Core4_1V2 */
+ dcdc4_reg: DCDC4 {
+ regulator-name = "DCDC4";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <1140000>;
+ regulator-suspend-min-microvolt = <1140000>;
+ };
+ };
+
+ /* Core4_1V8 */
+ dcdc5_reg: DCDC5 {
+ regulator-name = "DCDC5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <1700000>;
+ regulator-suspend-min-microvolt = <1700000>;
+ };
+ };
+
+ /* IR_3V3 */
+ ldo1_reg: LDO1 {
+ regulator-name = "LDO1";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* Core1_3V3 */
+ ldo2_reg: LDO2 {
+ regulator-name = "LDO2";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-max-microvolt = <3000000>;
+ regulator-suspend-min-microvolt = <3000000>;
+ };
+ };
+
+ /* Core5_1V2 */
+ ldo3_reg: LDO3 {
+ regulator-name = "LDO3";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "LDO4";
+ regulator-boot-on;
+ };
+
+ /* SPD_3V3 */
+ ldo5_reg: LDO5 {
+ regulator-name = "LDO5";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* DDR_0V6 */
+ ldo6_reg: LDO6 {
+ regulator-name = "LDO6";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* VDD_PWM */
+ ldo7_reg: LDO7 {
+ regulator-name = "LDO7";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* ldo_1v8 */
+ ldo8_reg: LDO8 {
+ regulator-name = "LDO8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "LDO9";
+ regulator-boot-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "LDO10";
+ regulator-boot-on;
+ };
+
+ ldortc1_reg: LDORTC1 {
+ regulator-name = "LDORTC1";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
+};
+
+&reg_vdd1p1 {
+ vin-supply = <&dcdc2_reg>;
+};
+
+&reg_vdd2p5 {
+ vin-supply = <&dcdc2_reg>;
+};
+
+&reg_arm {
+ vin-supply = <&dcdc3_reg>;
+};
+
+&reg_soc {
+ vin-supply = <&dcdc1_reg>;
+};
+
+&reg_pu {
+ vin-supply = <&dcdc1_reg>;
+};
+
+&snvs_rtc {
+ /*
+ * We are using the RTC in the PMIC, but this one is not disabled
+ * in imx6sl.dtsi.
+ */
+ status = "disabled";
+};
+
+&uart1 {
+ /* J4, through-holes */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart4 {
+ /* TP198, next to J4, SMD pads */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+ pinctrl-3 = <&pinctrl_usdhc2_sleep>;
+ non-removable;
+ status = "okay";
+
+ /* internal uSD card */
+};
+
+&usdhc3 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+ pinctrl-3 = <&pinctrl_usdhc3_sleep>;
+ vmmc-supply = <&reg_wifi>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ cap-power-off-card;
+ non-removable;
+ status = "okay";
+
+ /*
+ * RTL8189F SDIO WiFi
+ */
+};
+
+&usbotg1 {
+ disable-over-current;
+ srp-disable;
+ hnp-disable;
+ adp-disable;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_gpio_keys: gpio-keysgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD1_DAT1__GPIO5_IO08 0x17059
+ MX6SL_PAD_SD1_DAT4__GPIO5_IO12 0x17059
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001f8b1
+ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1
+ >;
+ };
+
+ pinctrl_i2c1_sleep: i2c1-sleepgrp {
+ fsl,pins = <
+ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1
+ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001f8b1
+ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1
+ >;
+ };
+
+ pinctrl_i2c2_sleep: i2c2-sleepgrp {
+ fsl,pins = <
+ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1
+ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6SL_PAD_REF_CLK_24M__I2C3_SCL 0x4001f8b1
+ MX6SL_PAD_REF_CLK_32K__I2C3_SDA 0x4001f8b1
+ >;
+ };
+
+ pinctrl_led: ledgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD1_DAT6__GPIO5_IO07 0x17059
+ >;
+ };
+
+ pinctrl_lm3630a_bl_gpio: lm3630a-bl-gpiogrp {
+ fsl,pins = <
+ MX6SL_PAD_EPDC_PWRCTRL3__GPIO2_IO10 0x10059 /* HWEN */
+ >;
+ };
+
+ pinctrl_ricoh_gpio: ricoh-gpiogrp {
+ fsl,pins = <
+ MX6SL_PAD_SD1_CLK__GPIO5_IO15 0x1b8b1 /* ricoh619 chg */
+ MX6SL_PAD_SD1_DAT0__GPIO5_IO11 0x1b8b1 /* ricoh619 irq */
+ MX6SL_PAD_KEY_COL2__GPIO3_IO28 0x1b8b1 /* ricoh619 bat_low_int */
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1
+ MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6SL_PAD_KEY_ROW6__UART4_TX_DATA 0x1b0b1
+ MX6SL_PAD_KEY_COL6__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg1: usbotg1grp {
+ fsl,pins = <
+ MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6SL_PAD_SD2_CLK__SD2_CLK 0x13059
+ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9
+ MX6SL_PAD_SD2_CLK__SD2_CLK 0x130b9
+ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
+ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
+ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
+ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9
+ MX6SL_PAD_SD2_CLK__SD2_CLK 0x130f9
+ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
+ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
+ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
+ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9
+ >;
+ };
+
+ pinctrl_usdhc2_sleep: usdhc2-sleepgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_CMD__GPIO5_IO04 0x100f9
+ MX6SL_PAD_SD2_CLK__GPIO5_IO05 0x100f9
+ MX6SL_PAD_SD2_DAT0__GPIO5_IO01 0x100f9
+ MX6SL_PAD_SD2_DAT1__GPIO4_IO30 0x100f9
+ MX6SL_PAD_SD2_DAT2__GPIO5_IO03 0x100f9
+ MX6SL_PAD_SD2_DAT3__GPIO4_IO28 0x100f9
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6SL_PAD_SD3_CMD__SD3_CMD 0x11059
+ MX6SL_PAD_SD3_CLK__SD3_CLK 0x11059
+ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x11059
+ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x11059
+ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x11059
+ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x11059
+ >;
+ };
+
+ pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9
+ MX6SL_PAD_SD3_CLK__SD3_CLK 0x170b9
+ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9
+ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9
+ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9
+ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9
+ >;
+ };
+
+ pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9
+ MX6SL_PAD_SD3_CLK__SD3_CLK 0x170f9
+ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+ >;
+ };
+
+ pinctrl_usdhc3_sleep: usdhc3-sleepgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD3_CMD__GPIO5_IO21 0x100c1
+ MX6SL_PAD_SD3_CLK__GPIO5_IO18 0x100c1
+ MX6SL_PAD_SD3_DAT0__GPIO5_IO19 0x100c1
+ MX6SL_PAD_SD3_DAT1__GPIO5_IO20 0x100c1
+ MX6SL_PAD_SD3_DAT2__GPIO5_IO16 0x100c1
+ MX6SL_PAD_SD3_DAT3__GPIO5_IO17 0x100c1
+ >;
+ };
+
+ pinctrl_wifi_power: wifi-powergrp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_DAT6__GPIO4_IO29 0x10059 /* WIFI_3V3_ON */
+ >;
+ };
+
+ pinctrl_wifi_reset: wifi-resetgrp {
+ fsl,pins = <
+ MX6SL_PAD_SD2_DAT7__GPIO5_IO00 0x10059 /* WIFI_RST */
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts b/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts
index 663ee9df79e6..da1399057634 100644
--- a/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts
+++ b/arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts
@@ -18,6 +18,21 @@
model = "Tolino Shine 2 HD";
compatible = "kobo,tolino-shine2hd", "fsl,imx6sl";
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&ec 0 50000>;
+ power-supply = <&backlight_regulator>;
+ };
+
+ backlight_regulator: regulator-backlight {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_backlight_power>;
+ regulator-name = "backlight";
+ gpio = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
chosen {
stdout-path = &uart1;
};
@@ -65,6 +80,12 @@
gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "timer";
};
+
+ led-1 {
+ label = "tolinoshine2hd:white:backlightboost";
+ gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "off";
+ };
};
memory@80000000 {
@@ -299,6 +320,12 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
+ pinctrl_backlight_power: backlight-powergrp {
+ fsl,pins = <
+ MX6SL_PAD_EPDC_PWRCTRL3__GPIO2_IO10 0x10059
+ >;
+ };
+
pinctrl_gpio_keys: gpio-keysgrp {
fsl,pins = <
MX6SL_PAD_SD1_DAT1__GPIO5_IO08 0x17059
@@ -383,7 +410,8 @@
pinctrl_led: ledgrp {
fsl,pins = <
- MX6SL_PAD_SD1_DAT2__GPIO5_IO13 0x17059
+ MX6SL_PAD_SD1_DAT2__GPIO5_IO13 0x17059
+ MX6SL_PAD_EPDC_SDCE2__GPIO1_IO29 0x17059
>;
};
diff --git a/arch/arm/boot/dts/imx6sl-tolino-shine3.dts b/arch/arm/boot/dts/imx6sl-tolino-shine3.dts
index e3f1e8d79528..db5d8509935f 100644
--- a/arch/arm/boot/dts/imx6sl-tolino-shine3.dts
+++ b/arch/arm/boot/dts/imx6sl-tolino-shine3.dts
@@ -52,6 +52,13 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
+ pinctrl_cyttsp5_gpio: cyttsp5-gpiogrp {
+ fsl,pins = <
+ MX6SL_PAD_SD1_DAT3__GPIO5_IO06 0x17059 /* TP_INT */
+ MX6SL_PAD_SD1_DAT2__GPIO5_IO13 0x10059 /* TP_RST */
+ >;
+ };
+
pinctrl_gpio_keys: gpio-keysgrp {
fsl,pins = <
MX6SL_PAD_SD1_DAT1__GPIO5_IO08 0x17059 /* PWR_SW */
diff --git a/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts b/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts
index 90b32f5eb529..c7cfe0b70f04 100644
--- a/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts
+++ b/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts
@@ -62,6 +62,13 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
+ pinctrl_cyttsp5_gpio: cyttsp5-gpiogrp {
+ fsl,pins = <
+ MX6SLL_PAD_SD1_DATA3__GPIO5_IO06 0x17059 /* TP_INT */
+ MX6SLL_PAD_SD1_DATA2__GPIO5_IO13 0x10059 /* TP_RST */
+ >;
+ };
+
pinctrl_gpio_keys: gpio-keysgrp {
fsl,pins = <
MX6SLL_PAD_SD1_DATA1__GPIO5_IO08 0x17059 /* PWR_SW */
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index abc3572d699e..80f5efd65c2f 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -1391,7 +1391,7 @@
pwm8: pwm@22b0000 {
compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm";
- reg = <0x0022b0000 0x4000>;
+ reg = <0x022b0000 0x4000>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6SX_CLK_PWM8>,
<&clks IMX6SX_CLK_PWM8>;
diff --git a/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi
index 3cddc68917a0..5168ed0ffec3 100644
--- a/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi
+++ b/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi
@@ -102,6 +102,10 @@
status = "disabled";
};
+&wdog1 {
+ fsl,suspend-in-wait;
+};
+
&iomuxc {
pinctrl_enet1: enet1grp {
fsl,pins = <
diff --git a/arch/arm/boot/dts/imx6ull-colibri-aster.dts b/arch/arm/boot/dts/imx6ull-colibri-aster.dts
index d3f2fb7c6c1e..3e0897c3a296 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-aster.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-aster.dts
@@ -15,6 +15,46 @@
"fsl,imx6ull";
};
+&ad7879_ts {
+ status = "okay";
+};
+
&atmel_mxt_ts {
status = "okay";
};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
+
+/* PWM <B> */
+&pwm5 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
+
+/* PWM <C> */
+&pwm6 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
index 9bf7111d7b00..d6da984e518d 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
@@ -12,3 +12,27 @@
model = "Toradex Colibri iMX6ULL 256/512MB on Colibri Evaluation Board V3";
compatible = "toradex,colibri-imx6ull-eval", "fsl,imx6ull";
};
+
+&ad7879_ts {
+ status = "okay";
+};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-iris-v2.dts b/arch/arm/boot/dts/imx6ull-colibri-iris-v2.dts
index afc1e0119783..f6b31118be17 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-iris-v2.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-iris-v2.dts
@@ -15,13 +15,21 @@
"fsl,imx6ull";
};
+&ad7879_ts {
+ status = "okay";
+};
+
&atmel_mxt_ts {
status = "okay";
};
+&backlight {
+ status = "okay";
+};
+
&gpio1 {
/* This turns the LVDS transceiver on */
- lvds-power-on {
+ lvds-power-on-hog {
gpio-hog;
gpios = <14 GPIO_ACTIVE_HIGH>; /* SODIMM 99 */
line-name = "LVDS_POWER_ON";
@@ -34,7 +42,7 @@
* This switches the LVDS transceiver to the single-channel
* output mode.
*/
- lvds-ch-mode {
+ lvds-ch-mode-hog {
gpio-hog;
gpios = <0 GPIO_ACTIVE_HIGH>; /* SODIMM 55 */
line-name = "LVDS_CH_MODE";
@@ -44,7 +52,7 @@
/*
* This switches the LVDS transceiver to the 24-bit RGB mode.
*/
- lvds-rgb-mode {
+ lvds-rgb-mode-hog {
gpio-hog;
gpios = <1 GPIO_ACTIVE_HIGH>; /* SODIMM 63 */
line-name = "LVDS_RGB_MODE";
@@ -56,10 +64,42 @@
/*
* This switches the LVDS transceiver to VESA color mapping mode.
*/
- lvds-color-map {
+ lvds-color-map-hog {
gpio-hog;
gpios = <3 GPIO_ACTIVE_HIGH>; /* SODIMM 95 */
line-name = "LVDS_COLOR_MAP";
output-low;
};
};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
+
+/* PWM <B> */
+&pwm5 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
+
+/* PWM <C> */
+&pwm6 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-iris.dts b/arch/arm/boot/dts/imx6ull-colibri-iris.dts
index 4fb97b0fe30b..2a0d0fc3b9d6 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-iris.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-iris.dts
@@ -15,6 +15,26 @@
"fsl,imx6ull";
};
-&atmel_mxt_ts {
+&ad7879_ts {
+ status = "okay";
+};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-iris.dtsi b/arch/arm/boot/dts/imx6ull-colibri-iris.dtsi
index 7f3b37baba88..166a0aefc869 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-iris.dtsi
+++ b/arch/arm/boot/dts/imx6ull-colibri-iris.dtsi
@@ -59,7 +59,7 @@
* in userspace.
* The same applies to uart1_tx_on.
*/
- uart25_tx_on {
+ uart25_tx_on-hog {
gpio-hog;
gpios = <15 0>;
output-high;
@@ -67,7 +67,7 @@
};
&gpio2 {
- uart1_tx_on {
+ uart1_tx_on-hog {
gpio-hog;
gpios = <7 0>;
output-high;
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi-aster.dts b/arch/arm/boot/dts/imx6ull-colibri-wifi-aster.dts
index b4f65e8c5857..c7da5b41966f 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-wifi-aster.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi-aster.dts
@@ -15,6 +15,46 @@
"fsl,imx6ull";
};
+&ad7879_ts {
+ status = "okay";
+};
+
&atmel_mxt_ts {
status = "okay";
};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
+
+/* PWM <B> */
+&pwm5 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
+
+/* PWM <C> */
+&pwm6 {
+ /* Pin already used by atmel_mxt_ts touchscreen */
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts b/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
index 1d64d1a5d8a7..917f5dbe64ba 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
@@ -12,3 +12,27 @@
model = "Toradex Colibri iMX6ULL 512MB on Colibri Evaluation Board V3";
compatible = "toradex,colibri-imx6ull-wifi-eval", "fsl,imx6ull";
};
+
+&ad7879_ts {
+ status = "okay";
+};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi-iris-v2.dts b/arch/arm/boot/dts/imx6ull-colibri-wifi-iris-v2.dts
index ce02f8a9ddd3..488da6df56fa 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-wifi-iris-v2.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi-iris-v2.dts
@@ -15,13 +15,21 @@
"fsl,imx6ull";
};
+&ad7879_ts {
+ status = "okay";
+};
+
&atmel_mxt_ts {
status = "okay";
};
+&backlight {
+ status = "okay";
+};
+
&gpio1 {
/* This turns the LVDS transceiver on */
- lvds-power-on {
+ lvds-power-on-hog {
gpio-hog;
gpios = <14 GPIO_ACTIVE_HIGH>; /* SODIMM 99 */
line-name = "LVDS_POWER_ON";
@@ -34,7 +42,7 @@
* This switches the LVDS transceiver to the single-channel
* output mode.
*/
- lvds-ch-mode {
+ lvds-ch-mode-hog {
gpio-hog;
gpios = <0 GPIO_ACTIVE_HIGH>; /* SODIMM 55 */
line-name = "LVDS_CH_MODE";
@@ -44,7 +52,7 @@
/*
* This switches the LVDS transceiver to the 24-bit RGB mode.
*/
- lvds-rgb-mode {
+ lvds-rgb-mode-hog {
gpio-hog;
gpios = <1 GPIO_ACTIVE_HIGH>; /* SODIMM 63 */
line-name = "LVDS_RGB_MODE";
@@ -56,10 +64,26 @@
/*
* This switches the LVDS transceiver to VESA color mapping mode.
*/
- lvds-color-map {
+ lvds-color-map-hog {
gpio-hog;
gpios = <3 GPIO_ACTIVE_HIGH>; /* SODIMM 95 */
line-name = "LVDS_COLOR_MAP";
output-low;
};
};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi-iris.dts b/arch/arm/boot/dts/imx6ull-colibri-wifi-iris.dts
index 5ac1aa298ce7..e63253254754 100644
--- a/arch/arm/boot/dts/imx6ull-colibri-wifi-iris.dts
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi-iris.dts
@@ -15,6 +15,26 @@
"fsl,imx6ull";
};
+&ad7879_ts {
+ status = "okay";
+};
+
&atmel_mxt_ts {
status = "okay";
};
+
+&backlight {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&lcdif {
+ status = "okay";
+};
+
+&panel_dpi {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri.dtsi b/arch/arm/boot/dts/imx6ull-colibri.dtsi
index 577a424b0e1d..336ab2e0534c 100644
--- a/arch/arm/boot/dts/imx6ull-colibri.dtsi
+++ b/arch/arm/boot/dts/imx6ull-colibri.dtsi
@@ -21,7 +21,29 @@
pinctrl-0 = <&pinctrl_gpio_bl_on>;
power-supply = <&reg_3v3>;
pwms = <&pwm4 0 5000000 1>;
- status = "okay";
+ status = "disabled";
+ };
+
+ connector {
+ compatible = "gpio-usb-b-connector", "usb-b-connector";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_snvs_usbc_det>;
+ id-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; /* SODIMM 137 / USBC_DET */
+ label = "USBC";
+ self-powered;
+ type = "micro";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ usb_dr_connector: endpoint {
+ remote-endpoint = <&usb1_drd_sw>;
+ };
+ };
+ };
};
gpio-keys {
@@ -42,7 +64,7 @@
compatible = "edt,et057090dhu";
backlight = <&backlight>;
power-supply = <&reg_3v3>;
- status = "okay";
+ status = "disabled";
port {
lcd_panel_in: endpoint {
@@ -159,7 +181,7 @@
pinctrl-1 = <&pinctrl_i2c1_gpio>;
sda-gpios = <&gpio1 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
scl-gpios = <&gpio1 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
- status = "okay";
+ status = "disabled";
/* Atmel maxtouch controller */
atmel_mxt_ts: touchscreen@4a {
@@ -202,6 +224,7 @@
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
+ status = "disabled";
};
};
@@ -209,6 +232,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
+ status = "disabled";
port {
lcdif_out: endpoint {
@@ -278,6 +302,13 @@
srp-disable;
hnp-disable;
adp-disable;
+ usb-role-switch;
+
+ port {
+ usb1_drd_sw: endpoint {
+ remote-endpoint = <&usb_dr_connector>;
+ };
+ };
};
/* Colibri USBH */
diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi
index a8c31ee65623..f8b8372b6851 100644
--- a/arch/arm/boot/dts/imx7-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -29,7 +29,6 @@
extcon_usbc_det: usbc-det {
compatible = "linux,extcon-usb-gpio";
- debounce = <25>;
id-gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>; /* SODIMM 137 / USBC_DET */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usbc_det>;
@@ -652,7 +651,7 @@
* NOTE: This pin group conflicts with pin groups pinctrl_pwm2/pinctrl_pwm3.
* Don't use them simultaneously.
*/
- pinctrl_atmel_adapter: atmelconnectorgrp {
+ pinctrl_atmel_adapter: atmeladaptergrp {
fsl,pins = <
MX7D_PAD_GPIO1_IO09__GPIO1_IO9 0x74 /* SODIMM 28 / INT */
MX7D_PAD_GPIO1_IO10__GPIO1_IO10 0x14 /* SODIMM 30 / RST */
@@ -660,7 +659,7 @@
};
/* Atmel MXT touchsceen + boards with built-in Capacitive Touch Connector */
- pinctrl_atmel_connector: atmeladaptergrp {
+ pinctrl_atmel_connector: atmelconnectorgrp {
fsl,pins = <
MX7D_PAD_EPDC_BDR0__GPIO2_IO28 0x14 /* SODIMM 106 / RST */
MX7D_PAD_EPDC_DATA15__GPIO2_IO15 0x74 /* SODIMM 107 / INT */
diff --git a/arch/arm/boot/dts/imx7d-remarkable2.dts b/arch/arm/boot/dts/imx7d-remarkable2.dts
index a2a91bfdd98e..8b2f11e85e05 100644
--- a/arch/arm/boot/dts/imx7d-remarkable2.dts
+++ b/arch/arm/boot/dts/imx7d-remarkable2.dts
@@ -22,6 +22,28 @@
reg = <0x80000000 0x40000000>;
};
+ thermal-zones {
+ epd-thermal {
+ thermal-sensors = <&sy7636a>;
+ polling-delay-passive = <30000>;
+ polling-delay = <30000>;
+
+ trips {
+ trip0 {
+ temperature = <49000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
reg_brcm: regulator-brcm {
compatible = "regulator-fixed";
regulator-name = "brcm_reg";
@@ -84,6 +106,32 @@
};
};
+&i2c4 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4>;
+ status = "okay";
+
+ sy7636a: pmic@62 {
+ compatible = "silergy,sy7636a";
+ reg = <0x62>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_epdpmic>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #thermal-sensor-cells = <0>;
+ epd-pwr-good-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>;
+
+ regulators {
+ reg_epdpmic: vcom {
+ regulator-name = "vcom";
+ regulator-boot-on;
+ };
+ };
+ };
+};
+
&snvs_pwrkey {
status = "okay";
};
@@ -177,6 +225,13 @@
>;
};
+ pinctrl_epdpmic: epdpmicgrp {
+ fsl,pins = <
+ MX7D_PAD_SAI2_RX_DATA__GPIO6_IO21 0x00000074
+ MX7D_PAD_ENET1_RGMII_TXC__GPIO7_IO11 0x00000014
+ >;
+ };
+
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f
@@ -184,6 +239,13 @@
>;
};
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX7D_PAD_I2C4_SDA__I2C4_SDA 0x4000007f
+ MX7D_PAD_I2C4_SCL__I2C4_SCL 0x4000007f
+ >;
+ };
+
pinctrl_uart1: uart1grp {
fsl,pins = <
MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79
diff --git a/arch/arm/boot/dts/kirkwood-b3.dts b/arch/arm/boot/dts/kirkwood-b3.dts
index a7636fe28501..681343c1357a 100644
--- a/arch/arm/boot/dts/kirkwood-b3.dts
+++ b/arch/arm/boot/dts/kirkwood-b3.dts
@@ -187,7 +187,7 @@
/* Wifi model has Atheros chipset on pcie port */
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-db-88f6281.dts b/arch/arm/boot/dts/kirkwood-db-88f6281.dts
index 2adb17c955aa..a9a8e6b744c7 100644
--- a/arch/arm/boot/dts/kirkwood-db-88f6281.dts
+++ b/arch/arm/boot/dts/kirkwood-db-88f6281.dts
@@ -18,7 +18,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-db-88f6282.dts b/arch/arm/boot/dts/kirkwood-db-88f6282.dts
index f84a48539917..6dc6579d4524 100644
--- a/arch/arm/boot/dts/kirkwood-db-88f6282.dts
+++ b/arch/arm/boot/dts/kirkwood-db-88f6282.dts
@@ -18,7 +18,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-dir665.dts b/arch/arm/boot/dts/kirkwood-dir665.dts
index c32300611d2c..f9f4b0143ba8 100644
--- a/arch/arm/boot/dts/kirkwood-dir665.dts
+++ b/arch/arm/boot/dts/kirkwood-dir665.dts
@@ -211,18 +211,18 @@
};
port@1 {
- reg = <1>;
- label = "lan3";
+ reg = <1>;
+ label = "lan3";
};
port@2 {
- reg = <2>;
- label = "lan2";
+ reg = <2>;
+ label = "lan2";
};
port@3 {
- reg = <3>;
- label = "lan1";
+ reg = <3>;
+ label = "lan1";
};
port@4 {
@@ -268,7 +268,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-ds112.dts b/arch/arm/boot/dts/kirkwood-ds112.dts
index f48609e95afe..3912f1b525b6 100644
--- a/arch/arm/boot/dts/kirkwood-ds112.dts
+++ b/arch/arm/boot/dts/kirkwood-ds112.dts
@@ -43,7 +43,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie1 {
diff --git a/arch/arm/boot/dts/kirkwood-ds411.dts b/arch/arm/boot/dts/kirkwood-ds411.dts
index 86907be70cf9..1d4256ef325d 100644
--- a/arch/arm/boot/dts/kirkwood-ds411.dts
+++ b/arch/arm/boot/dts/kirkwood-ds411.dts
@@ -47,7 +47,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie1 {
diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts
index 95af7aa1fdcb..aed20185fd7a 100644
--- a/arch/arm/boot/dts/kirkwood-iconnect.dts
+++ b/arch/arm/boot/dts/kirkwood-iconnect.dts
@@ -187,7 +187,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-km_common.dtsi b/arch/arm/boot/dts/kirkwood-km_common.dtsi
index 75dc83914f56..52baffe45f12 100644
--- a/arch/arm/boot/dts/kirkwood-km_common.dtsi
+++ b/arch/arm/boot/dts/kirkwood-km_common.dtsi
@@ -39,7 +39,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-l-50.dts b/arch/arm/boot/dts/kirkwood-l-50.dts
index 0d81c43a6a73..60c1e94f5dd3 100644
--- a/arch/arm/boot/dts/kirkwood-l-50.dts
+++ b/arch/arm/boot/dts/kirkwood-l-50.dts
@@ -223,18 +223,18 @@
};
port@1 {
- reg = <1>;
- label = "lan1";
+ reg = <1>;
+ label = "lan1";
};
port@2 {
- reg = <2>;
- label = "lan6";
+ reg = <2>;
+ label = "lan6";
};
port@3 {
- reg = <3>;
- label = "lan2";
+ reg = <3>;
+ label = "lan2";
};
port@4 {
@@ -282,18 +282,18 @@
};
port@1 {
- reg = <1>;
- label = "lan8";
+ reg = <1>;
+ label = "lan8";
};
port@2 {
- reg = <2>;
- label = "lan4";
+ reg = <2>;
+ label = "lan4";
};
port@3 {
- reg = <3>;
- label = "dmz";
+ reg = <3>;
+ label = "dmz";
};
switch1port5: port@5 {
diff --git a/arch/arm/boot/dts/kirkwood-laplug.dts b/arch/arm/boot/dts/kirkwood-laplug.dts
index 6158214a939a..8c2b540eaf4f 100644
--- a/arch/arm/boot/dts/kirkwood-laplug.dts
+++ b/arch/arm/boot/dts/kirkwood-laplug.dts
@@ -160,7 +160,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-linkstation.dtsi b/arch/arm/boot/dts/kirkwood-linkstation.dtsi
index 407d6d8b3a7f..b54c9980f636 100644
--- a/arch/arm/boot/dts/kirkwood-linkstation.dtsi
+++ b/arch/arm/boot/dts/kirkwood-linkstation.dtsi
@@ -156,7 +156,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-mplcec4.dts b/arch/arm/boot/dts/kirkwood-mplcec4.dts
index b80d12f6aa49..e87ea7146546 100644
--- a/arch/arm/boot/dts/kirkwood-mplcec4.dts
+++ b/arch/arm/boot/dts/kirkwood-mplcec4.dts
@@ -8,10 +8,10 @@
model = "MPL CEC4";
compatible = "mpl,cec4-10", "mpl,cec4", "marvell,kirkwood-88f6281", "marvell,kirkwood";
- memory {
- device_type = "memory";
- reg = <0x00000000 0x20000000>;
- };
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>;
+ };
chosen {
bootargs = "console=ttyS0,115200n8 earlyprintk";
@@ -66,8 +66,8 @@
};
};
- i2c@11000 {
- status = "okay";
+ i2c@11000 {
+ status = "okay";
rtc@51 {
compatible = "nxp,pcf8563";
@@ -79,7 +79,7 @@
reg = <0x57>;
};
- };
+ };
serial@12000 {
status = "okay";
@@ -208,7 +208,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
index 2e1a75348908..ced576acfb95 100644
--- a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
+++ b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
@@ -170,7 +170,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-nas2big.dts b/arch/arm/boot/dts/kirkwood-nas2big.dts
index 6a2934b7d0ce..0b0a15093146 100644
--- a/arch/arm/boot/dts/kirkwood-nas2big.dts
+++ b/arch/arm/boot/dts/kirkwood-nas2big.dts
@@ -131,7 +131,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-net2big.dts b/arch/arm/boot/dts/kirkwood-net2big.dts
index 3e3ac289e5b0..d5f6bb50ba11 100644
--- a/arch/arm/boot/dts/kirkwood-net2big.dts
+++ b/arch/arm/boot/dts/kirkwood-net2big.dts
@@ -46,11 +46,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <32768>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
};
};
diff --git a/arch/arm/boot/dts/kirkwood-net5big.dts b/arch/arm/boot/dts/kirkwood-net5big.dts
index cba8a2b6f6d9..2497ad26b5b6 100644
--- a/arch/arm/boot/dts/kirkwood-net5big.dts
+++ b/arch/arm/boot/dts/kirkwood-net5big.dts
@@ -78,11 +78,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <32768>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
};
netxbig-leds {
diff --git a/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts b/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts
index b13aee570804..6cf76430cfab 100644
--- a/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts
+++ b/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts
@@ -78,11 +78,11 @@
};
clocks {
- g762_clk: g762-oscillator {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <8192>;
- };
+ g762_clk: g762-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <8192>;
+ };
};
i2c@11000 {
@@ -266,7 +266,7 @@
/* Connected to NEC uPD720200 USB 3.0 controller */
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-nsa310.dts b/arch/arm/boot/dts/kirkwood-nsa310.dts
index 9b861c2e76c5..c1799a07816e 100644
--- a/arch/arm/boot/dts/kirkwood-nsa310.dts
+++ b/arch/arm/boot/dts/kirkwood-nsa310.dts
@@ -131,7 +131,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-nsa310s.dts b/arch/arm/boot/dts/kirkwood-nsa310s.dts
new file mode 100644
index 000000000000..49da633a1bc0
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-nsa310s.dts
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * ZyXEL NSA310S Board Description
+ * Copyright 2020-2022 Pawel Dembicki <paweldembicki@gmail.com>
+ * Copyright (c) 2015-2021, Tony Dinh <mibodhi@gmail.com>
+ * Copyright (c) 2014, Adam Baker <linux@baker-net.org.uk>
+ * Based upon the board setup file created by Peter Schildmann
+ */
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+ model = "ZyXEL NSA310S";
+ compatible = "zyxel,nsa310s", "marvell,kirkwood-88f6702", "marvell,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk";
+ stdout-path = &uart0;
+ };
+
+ gpio_poweroff {
+ compatible = "gpio-poweroff";
+ pinctrl-0 = <&pmx_pwr_off>;
+ pinctrl-names = "default";
+ gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>;
+ };
+
+ keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&pmx_buttons>;
+ pinctrl-names = "default";
+
+ power {
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+ };
+
+ copy {
+ label = "Copy Button";
+ linux,code = <KEY_COPY>;
+ gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
+ };
+
+ reset {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&pmx_leds>;
+ pinctrl-names = "default";
+
+ led-1 {
+ function = LED_FUNCTION_DISK_ERR;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-2 {
+ function = LED_FUNCTION_USB;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "usb-host";
+ };
+
+ led-3 {
+ function = LED_FUNCTION_DISK;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "ata1";
+ };
+
+ led-4 {
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-5 {
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-6 {
+ function = LED_FUNCTION_STATUS;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ led-7 {
+ function = LED_FUNCTION_STATUS;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ usb0_power: regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "USB Power";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata1_power: regulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "SATA1 Power";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+ };
+
+ thermal-zones {
+ disk-thermal {
+ polling-delay = <20000>;
+ polling-delay-passive = <2000>;
+
+ thermal-sensors = <&hdd_temp>;
+
+ trips {
+ disk_alert: disk-alert {
+ temperature = <40000>;
+ hysteresis = <5000>;
+ type = "active";
+ };
+ disk_crit: disk-crit {
+ temperature = <60000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+
+&eth0 {
+ status = "okay";
+
+ ethernet0-port@0 {
+ phy-handle = <&ethphy0>;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+
+ rtc@68 {
+ compatible = "htk,ht1382";
+ reg = <0x68>;
+ };
+};
+
+&mdio {
+ status = "okay";
+
+ ethphy0: ethernet-phy@1 {
+ reg = <1>;
+ phy-mode = "rgmii-id";
+ marvell,reg-init = <0x1 0x16 0x0 0x3>,
+ <0x1 0x10 0x0 0x1017>,
+ <0x1 0x11 0x0 0x4408>,
+ <0x1 0x16 0x0 0x0>;
+ };
+};
+
+&nand {
+ status = "okay";
+ chip-delay = <35>;
+
+ partition@0 {
+ label = "uboot";
+ reg = <0x0000000 0x00c0000>;
+ read-only;
+ };
+ partition@c0000 {
+ label = "uboot_env";
+ reg = <0x00c0000 0x0080000>;
+ };
+ partition@140000 {
+ label = "ubi";
+ reg = <0x0140000 0x7ec0000>;
+ };
+};
+
+&pciec {
+ status = "okay";
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+
+ pmx_buttons: pmx-buttons {
+ marvell,pins = "mpp24", "mpp25", "mpp26";
+ marvell,function = "gpio";
+ };
+
+ pmx_leds: pmx-leds {
+ marvell,pins = "mpp13", "mpp15", "mpp16", "mpp22", "mpp23",
+ "mpp28", "mpp29";
+ marvell,function = "gpio";
+ };
+
+ pmx_power: pmx-power {
+ marvell,pins = "mpp21", "mpp33";
+ marvell,function = "gpio";
+ };
+
+ pmx_pwr_off: pmx-pwr-off {
+ marvell,pins = "mpp27";
+ marvell,function = "gpio";
+ };
+};
+
+&rtc {
+ status = "disabled";
+};
+
+&sata {
+ status = "okay";
+ nr-ports = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdd_temp: sata-port@0 {
+ reg = <0>;
+ #thermal-sensor-cells = <0>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/kirkwood-nsa320.dts b/arch/arm/boot/dts/kirkwood-nsa320.dts
index b69b096f267b..652405e65006 100644
--- a/arch/arm/boot/dts/kirkwood-nsa320.dts
+++ b/arch/arm/boot/dts/kirkwood-nsa320.dts
@@ -211,7 +211,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-nsa325.dts b/arch/arm/boot/dts/kirkwood-nsa325.dts
index 6f8085dbb1f4..371456de34b2 100644
--- a/arch/arm/boot/dts/kirkwood-nsa325.dts
+++ b/arch/arm/boot/dts/kirkwood-nsa325.dts
@@ -224,7 +224,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi b/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi
index 8f73197f251a..ea3d36512e9f 100644
--- a/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi
+++ b/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi
@@ -150,7 +150,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-rd88f6192.dts b/arch/arm/boot/dts/kirkwood-rd88f6192.dts
index 712d6042b132..f00325ffde07 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6192.dts
+++ b/arch/arm/boot/dts/kirkwood-rd88f6192.dts
@@ -31,10 +31,10 @@
pinctrl-0 = <&pmx_usb_power>;
pinctrl-names = "default";
- pmx_usb_power: pmx-usb-power {
- marvell,pins = "mpp10";
- marvell,function = "gpo";
- };
+ pmx_usb_power: pmx-usb-power {
+ marvell,pins = "mpp10";
+ marvell,function = "gpo";
+ };
};
serial@12000 {
@@ -62,43 +62,43 @@
};
regulators {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-0 = <&pmx_usb_power>;
- pinctrl-names = "default";
-
- usb_power: regulator@0 {
- compatible = "regulator-fixed";
- reg = <0>;
- regulator-name = "USB VBUS";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- enable-active-high;
- regulator-always-on;
- regulator-boot-on;
- gpio = <&gpio0 10 GPIO_ACTIVE_HIGH>;
- };
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&pmx_usb_power>;
+ pinctrl-names = "default";
+
+ usb_power: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "USB VBUS";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio0 10 GPIO_ACTIVE_HIGH>;
+ };
};
};
&mdio {
- status = "okay";
+ status = "okay";
- ethphy0: ethernet-phy@8 {
- reg = <8>;
- };
+ ethphy0: ethernet-phy@8 {
+ reg = <8>;
+ };
};
&eth0 {
- status = "okay";
- ethernet0-port@0 {
- phy-handle = <&ethphy0>;
- };
+ status = "okay";
+ ethernet0-port@0 {
+ phy-handle = <&ethphy0>;
+ };
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts b/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
index 9d88301daf0e..72edd47e19ff 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
+++ b/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
@@ -19,7 +19,7 @@
};
&eth1 {
- status = "disabled";
+ status = "disabled";
};
&switch {
diff --git a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
index f1f8eee132e8..e21aa674945d 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
+++ b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
@@ -48,7 +48,7 @@
cd-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
/* No WP GPIO */
};
- };
+ };
};
&nand {
@@ -126,7 +126,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-rs212.dts b/arch/arm/boot/dts/kirkwood-rs212.dts
index c51cea883215..4ad412115a24 100644
--- a/arch/arm/boot/dts/kirkwood-rs212.dts
+++ b/arch/arm/boot/dts/kirkwood-rs212.dts
@@ -43,7 +43,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie1 {
diff --git a/arch/arm/boot/dts/kirkwood-synology.dtsi b/arch/arm/boot/dts/kirkwood-synology.dtsi
index 8f6c387d3a8b..9b6666020cdd 100644
--- a/arch/arm/boot/dts/kirkwood-synology.dtsi
+++ b/arch/arm/boot/dts/kirkwood-synology.dtsi
@@ -847,7 +847,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-t5325.dts b/arch/arm/boot/dts/kirkwood-t5325.dts
index fe63b3a03a72..ad093324e075 100644
--- a/arch/arm/boot/dts/kirkwood-t5325.dts
+++ b/arch/arm/boot/dts/kirkwood-t5325.dts
@@ -219,7 +219,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi
index 994cabcf4b51..1939462a5f48 100644
--- a/arch/arm/boot/dts/kirkwood-ts219.dtsi
+++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi
@@ -86,7 +86,7 @@
status = "okay";
ethphy0: ethernet-phy@X {
- /* overwrite reg property in board file */
+ /* overwrite reg property in board file */
};
};
@@ -98,7 +98,7 @@
};
&pciec {
- status = "okay";
+ status = "okay";
};
&pcie0 {
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index fca31a5d5ac7..815ef7719d13 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -24,9 +24,9 @@
};
aliases {
- gpio0 = &gpio0;
- gpio1 = &gpio1;
- i2c0 = &i2c0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ i2c0 = &i2c0;
};
mbus@f1000000 {
@@ -279,15 +279,15 @@
clocks = <&gate_clk 8>;
xor00 {
- interrupts = <5>;
- dmacap,memcpy;
- dmacap,xor;
+ interrupts = <5>;
+ dmacap,memcpy;
+ dmacap,xor;
};
xor01 {
- interrupts = <6>;
- dmacap,memcpy;
- dmacap,xor;
- dmacap,memset;
+ interrupts = <6>;
+ dmacap,memcpy;
+ dmacap,xor;
+ dmacap,memset;
};
};
@@ -299,15 +299,15 @@
clocks = <&gate_clk 16>;
xor00 {
- interrupts = <7>;
- dmacap,memcpy;
- dmacap,xor;
+ interrupts = <7>;
+ dmacap,memcpy;
+ dmacap,xor;
};
xor01 {
- interrupts = <8>;
- dmacap,memcpy;
- dmacap,xor;
- dmacap,memset;
+ interrupts = <8>;
+ dmacap,memcpy;
+ dmacap,xor;
+ dmacap,memset;
};
};
diff --git a/arch/arm/boot/dts/lan966x-pcb8290.dts b/arch/arm/boot/dts/lan966x-pcb8290.dts
index 77187f59f04d..8804e8ba5370 100644
--- a/arch/arm/boot/dts/lan966x-pcb8290.dts
+++ b/arch/arm/boot/dts/lan966x-pcb8290.dts
@@ -58,41 +58,57 @@
ext_phy0: ethernet-phy@7 {
reg = <7>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy1: ethernet-phy@8 {
reg = <8>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy2: ethernet-phy@9 {
reg = <9>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy3: ethernet-phy@10 {
reg = <10>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy4: ethernet-phy@15 {
reg = <15>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy5: ethernet-phy@16 {
reg = <16>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy6: ethernet-phy@17 {
reg = <17>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
ext_phy7: ethernet-phy@18 {
reg = <18>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
coma-mode-gpios = <&gpio 60 GPIO_OPEN_DRAIN>;
};
};
diff --git a/arch/arm/boot/dts/lan966x-pcb8291.dts b/arch/arm/boot/dts/lan966x-pcb8291.dts
index f4f054cdf2a8..3a3d76af8612 100644
--- a/arch/arm/boot/dts/lan966x-pcb8291.dts
+++ b/arch/arm/boot/dts/lan966x-pcb8291.dts
@@ -69,6 +69,12 @@
pins = "GPIO_35", "GPIO_36";
function = "can0_b";
};
+
+ sgpio_a_pins: sgpio-a-pins {
+ /* SCK, D0, D1, LD */
+ pins = "GPIO_32", "GPIO_33", "GPIO_34", "GPIO_35";
+ function = "sgpio_a";
+ };
};
&can0 {
@@ -118,6 +124,20 @@
status = "okay";
};
+&sgpio {
+ pinctrl-0 = <&sgpio_a_pins>;
+ pinctrl-names = "default";
+ microchip,sgpio-port-ranges = <0 3>, <8 11>;
+ status = "okay";
+
+ gpio@0 {
+ ngpios = <64>;
+ };
+ gpio@1 {
+ ngpios = <64>;
+ };
+};
+
&switch {
status = "okay";
};
diff --git a/arch/arm/boot/dts/lan966x.dtsi b/arch/arm/boot/dts/lan966x.dtsi
index 0bf818713422..05b73f7cf0c7 100644
--- a/arch/arm/boot/dts/lan966x.dtsi
+++ b/arch/arm/boot/dts/lan966x.dtsi
@@ -157,6 +157,11 @@
};
};
+ otp: otp@e0021000 {
+ compatible = "microchip,lan9668-otpc", "microchip,lan9662-otpc";
+ reg = <0xe0021000 0x300>;
+ };
+
flx0: flexcom@e0040000 {
compatible = "atmel,sama5d2-flexcom";
reg = <0xe0040000 0x100>;
diff --git a/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi b/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
index d3da8b1b473b..e0cbac500e17 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
+++ b/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
@@ -59,7 +59,7 @@
};
};
- pwm10: dmtimer-pwm {
+ pwm10: pwm-10 {
compatible = "ti,omap-dmtimer-pwm";
pinctrl-names = "default";
pinctrl-0 = <&pwm_pins>;
diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
index 3a5228562b0d..72b5af475d09 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
+++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -20,7 +20,7 @@
leds {
compatible = "gpio-leds";
- user0 {
+ led-user0 {
label = "user0";
gpios = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* LEDA */
linux,default-trigger = "none";
diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi
index c87066d6c995..974410918f35 100644
--- a/arch/arm/boot/dts/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/lpc32xx.dtsi
@@ -315,7 +315,7 @@
/* System Control Block */
scb {
compatible = "simple-bus";
- ranges = <0x0 0x040004000 0x00001000>;
+ ranges = <0x0 0x40004000 0x00001000>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts b/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts
index f3ddea934f1b..d2cae8c7d7a6 100644
--- a/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts
+++ b/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts
@@ -30,11 +30,11 @@
};
reg_3p3v: regulator-3p3v {
- compatible = "regulator-fixed";
- regulator-name = "3P3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
};
leds {
diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
index c7a1f3ffc48c..f7cc8fc678fa 100644
--- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
@@ -133,7 +133,7 @@
dais = <&mcbsp2_port>, <&mcbsp3_port>;
};
- pwm8: dmtimer-pwm-8 {
+ pwm8: pwm-8 {
pinctrl-names = "default";
pinctrl-0 = <&vibrator_direction_pin>;
@@ -143,7 +143,7 @@
ti,clock-source = <0x01>;
};
- pwm9: dmtimer-pwm-9 {
+ pwm9: pwm-9 {
pinctrl-names = "default";
pinctrl-0 = <&vibrator_enable_pin>;
diff --git a/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts b/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts
index d10669fcd527..9e9eba8bad5e 100644
--- a/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm730-gbs.dts
@@ -366,7 +366,7 @@
spi-max-frequency = <20000000>;
spi-rx-bus-width = <2>;
label = "bmc";
- partitions@80000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts b/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
index 491606c4f044..2a394cc15284 100644
--- a/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
@@ -142,7 +142,7 @@
reg = <0>;
spi-rx-bus-width = <2>;
- partitions@80000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nuvoton-npcm730-kudo.dts b/arch/arm/boot/dts/nuvoton-npcm730-kudo.dts
index a0c2d7652625..f7b38bee039b 100644
--- a/arch/arm/boot/dts/nuvoton-npcm730-kudo.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm730-kudo.dts
@@ -388,7 +388,7 @@
spi-max-frequency = <5000000>;
spi-rx-bus-width = <2>;
label = "bmc";
- partitions@80000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -422,7 +422,7 @@
reg = <1>;
spi-max-frequency = <5000000>;
spi-rx-bus-width = <2>;
- partitions@88000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -447,7 +447,7 @@
reg = <0>;
spi-max-frequency = <5000000>;
spi-rx-bus-width = <2>;
- partitions@A0000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
index 3dad32834e5e..f53d45fa1de8 100644
--- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
@@ -74,7 +74,7 @@
spi-rx-bus-width = <2>;
reg = <0>;
spi-max-frequency = <5000000>;
- partitions@80000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -135,7 +135,7 @@
spi-rx-bus-width = <2>;
reg = <0>;
spi-max-frequency = <5000000>;
- partitions@A0000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts
index 132e702281fc..87359ab05db3 100644
--- a/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts
@@ -107,7 +107,7 @@
reg = <0>;
spi-rx-bus-width = <2>;
- partitions@80000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -146,7 +146,7 @@
reg = <1>;
npcm,fiu-rx-bus-width = <2>;
- partitions@88000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -173,7 +173,7 @@
reg = <0>;
spi-rx-bus-width = <2>;
- partitions@A0000000 {
+ partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts b/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts
index 3ee61251a16d..b78c116cbc18 100644
--- a/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts
+++ b/arch/arm/boot/dts/nuvoton-wpcm450-supermicro-x9sci-ln4f.dts
@@ -15,6 +15,11 @@
model = "Supermicro X9SCi-LN4F BMC";
compatible = "supermicro,x9sci-ln4f-bmc", "nuvoton,wpcm450";
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ };
+
chosen {
stdout-path = "serial0:115200n8";
};
@@ -53,6 +58,33 @@
};
};
+&fiu {
+ status = "okay";
+
+ flash@0 {
+ reg = <0>;
+ compatible = "jedec,spi-nor";
+ };
+};
+
+&gpio0 {
+ gpio-line-names =
+ /* 0 */ "", "host-reset-control-n", "", "", "", "", "", "",
+ /* 8 */ "", "", "", "", "power-chassis-control-n", "", "uid-button", "";
+};
+
+&gpio1 {
+ gpio-line-names =
+ /* 0 */ "", "", "", "", "led-heartbeat", "", "", "led-uid",
+ /* 8 */ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names =
+ /* 0 */ "", "", "", "", "", "", "", "",
+ /* 8 */ "", "", "", "", "", "", "", "power-chassis-good";
+};
+
&pinctrl {
key_pins: mux-keys {
groups = "gspi", "sspi";
@@ -77,7 +109,3 @@
/* "Serial over LAN" port. Connected to ttyS2 of the host system. */
status = "okay";
};
-
-&watchdog0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/nuvoton-wpcm450.dtsi b/arch/arm/boot/dts/nuvoton-wpcm450.dtsi
index 93595850a4c3..b637241316bb 100644
--- a/arch/arm/boot/dts/nuvoton-wpcm450.dtsi
+++ b/arch/arm/boot/dts/nuvoton-wpcm450.dtsi
@@ -37,6 +37,14 @@
#clock-cells = <0>;
};
+ refclk: clock-48mhz {
+ /* 48 MHz reference oscillator */
+ compatible = "fixed-clock";
+ clock-output-names = "ref";
+ clock-frequency = <48000000>;
+ #clock-cells = <0>;
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -49,6 +57,15 @@
reg = <0xb0000000 0x200>;
};
+ clk: clock-controller@b0000200 {
+ compatible = "nuvoton,wpcm450-clk";
+ reg = <0xb0000200 0x100>;
+ clocks = <&refclk>;
+ clock-names = "ref";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
serial0: serial@b8000000 {
compatible = "nuvoton,wpcm450-uart";
reg = <0xb8000000 0x20>;
@@ -81,7 +98,6 @@
interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xb800101c 0x4>;
clocks = <&clk24m>;
- status = "disabled";
};
aic: interrupt-controller@b8002000 {
@@ -456,5 +472,21 @@
function = "hg7";
};
};
+
+ fiu: spi-controller@c8000000 {
+ compatible = "nuvoton,wpcm450-fiu";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xc8000000 0x1000>, <0xc0000000 0x4000000>;
+ reg-names = "control", "memory";
+ clocks = <&clk 0>;
+ status = "disabled";
+ };
+
+ shm: syscon@c8001000 {
+ compatible = "nuvoton,wpcm450-shm", "syscon";
+ reg = <0xc8001000 0x1000>;
+ reg-io-width = <1>;
+ };
};
};
diff --git a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
index ce6c235f68ec..3046ec572632 100644
--- a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
+++ b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
@@ -8,9 +8,9 @@
/ {
vddvario: regulator-vddvario {
- compatible = "regulator-fixed";
- regulator-name = "vddvario";
- regulator-always-on;
+ compatible = "regulator-fixed";
+ regulator-name = "vddvario";
+ regulator-always-on;
};
vdd33a: regulator-vdd33a {
diff --git a/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
index e7534fe9c53c..bc8961f3690f 100644
--- a/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
+++ b/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
@@ -12,9 +12,9 @@
/ {
vddvario: regulator-vddvario {
- compatible = "regulator-fixed";
- regulator-name = "vddvario";
- regulator-always-on;
+ compatible = "regulator-fixed";
+ regulator-name = "vddvario";
+ regulator-always-on;
};
vdd33a: regulator-vdd33a {
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 0548b391334f..47ff1ffddfc5 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -28,18 +28,18 @@
leds {
compatible = "gpio-leds";
- pmu_stat {
+ led-pmu-stat {
label = "beagleboard::pmu_stat";
gpios = <&twl_gpio 19 GPIO_ACTIVE_HIGH>; /* LEDB */
};
- heartbeat {
+ led-heartbeat {
label = "beagleboard::usr0";
gpios = <&gpio5 22 GPIO_ACTIVE_HIGH>; /* 150 -> D6 LED */
linux,default-trigger = "heartbeat";
};
- mmc {
+ led-mmc {
label = "beagleboard::usr1";
gpios = <&gpio5 21 GPIO_ACTIVE_HIGH>; /* 149 -> D7 LED */
linux,default-trigger = "mmc0";
diff --git a/arch/arm/boot/dts/omap3-cm-t3517.dts b/arch/arm/boot/dts/omap3-cm-t3517.dts
index 3b8349094baa..f25c0a84a190 100644
--- a/arch/arm/boot/dts/omap3-cm-t3517.dts
+++ b/arch/arm/boot/dts/omap3-cm-t3517.dts
@@ -11,12 +11,12 @@
model = "CompuLab CM-T3517";
compatible = "compulab,omap3-cm-t3517", "ti,am3517", "ti,omap3";
- vmmc: regulator-vmmc {
- compatible = "regulator-fixed";
- regulator-name = "vmmc";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
+ vmmc: regulator-vmmc {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
wl12xx_vmmc2: wl12xx_vmmc2 {
compatible = "regulator-fixed";
diff --git a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
index 54cd37336be7..38aa1febc33f 100644
--- a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
+++ b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
@@ -15,28 +15,28 @@
leds {
compatible = "gpio-leds";
- heartbeat {
+ led-heartbeat {
label = "devkit8000::led1";
gpios = <&gpio6 26 GPIO_ACTIVE_HIGH>; /* 186 -> LED1 */
default-state = "on";
linux,default-trigger = "heartbeat";
};
- mmc {
+ led-mmc {
label = "devkit8000::led2";
gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 -> LED2 */
default-state = "on";
linux,default-trigger = "none";
};
- usr {
+ led-usr {
label = "devkit8000::led3";
gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* 164 -> LED3 */
default-state = "on";
linux,default-trigger = "usr";
};
- pmu_stat {
+ led-pmu-stat {
label = "devkit8000::pmu_stat";
gpios = <&twl_gpio 19 GPIO_ACTIVE_HIGH>; /* LEDB */
};
diff --git a/arch/arm/boot/dts/omap3-echo.dts b/arch/arm/boot/dts/omap3-echo.dts
index 8f02ff5e7da6..06d2377d28ad 100644
--- a/arch/arm/boot/dts/omap3-echo.dts
+++ b/arch/arm/boot/dts/omap3-echo.dts
@@ -146,7 +146,7 @@
label = "q1";
reg = <0x32>;
clock-mode = /bits/ 8 <0>; /* LP55XX_CLOCK_AUTO */
- enable-gpio = <&gpio4 13 GPIO_ACTIVE_HIGH>; /* GPIO_109 */
+ enable-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>; /* GPIO_109 */
multi-led@0 {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index 28a6a9345be5..87e0ab1bbe95 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -147,7 +147,7 @@
pinctrl-0 = <&backlight_pins>;
};
- pwm11: dmtimer-pwm {
+ pwm11: pwm-11 {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer11>;
#pwm-cells = <3>;
@@ -332,7 +332,7 @@
OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
>;
- };
+ };
gps_pins: pinmux_gps_pins {
pinctrl-single,pins = <
@@ -853,8 +853,8 @@
};
&hdqw1w {
- pinctrl-names = "default";
- pinctrl-0 = <&hdq_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdq_pins>;
};
/* image signal processor within OMAP3 SoC */
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 36fc8805e0c1..85f33bbb566f 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -301,5 +301,5 @@
&vaux1 {
/* Needed for ads7846 */
- regulator-name = "vcc";
+ regulator-name = "vcc";
};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index dd7971556449..6ba2e8f81973 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -49,7 +49,7 @@
leds {
compatible = "gpio-leds";
- heartbeat {
+ led-heartbeat {
label = "debug::sleep";
gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>; /* 162 */
linux,default-trigger = "default-on";
@@ -156,7 +156,7 @@
io-channel-names = "temp", "bsi", "vbat";
};
- pwm9: dmtimer-pwm {
+ pwm9: pwm-9 {
compatible = "ti,omap-dmtimer-pwm";
#pwm-cells = <3>;
ti,timers = <&timer9>;
@@ -236,27 +236,27 @@
pinctrl-single,pins = <
/* address lines */
- OMAP3_CORE1_IOPAD(0x207a, PIN_OUTPUT | MUX_MODE0) /* gpmc_a1.gpmc_a1 */
- OMAP3_CORE1_IOPAD(0x207c, PIN_OUTPUT | MUX_MODE0) /* gpmc_a2.gpmc_a2 */
- OMAP3_CORE1_IOPAD(0x207e, PIN_OUTPUT | MUX_MODE0) /* gpmc_a3.gpmc_a3 */
+ OMAP3_CORE1_IOPAD(0x207a, PIN_OUTPUT | MUX_MODE0) /* gpmc_a1.gpmc_a1 */
+ OMAP3_CORE1_IOPAD(0x207c, PIN_OUTPUT | MUX_MODE0) /* gpmc_a2.gpmc_a2 */
+ OMAP3_CORE1_IOPAD(0x207e, PIN_OUTPUT | MUX_MODE0) /* gpmc_a3.gpmc_a3 */
/* data lines, gpmc_d0..d7 not muxable according to TRM */
- OMAP3_CORE1_IOPAD(0x209e, PIN_INPUT | MUX_MODE0) /* gpmc_d8.gpmc_d8 */
- OMAP3_CORE1_IOPAD(0x20a0, PIN_INPUT | MUX_MODE0) /* gpmc_d9.gpmc_d9 */
- OMAP3_CORE1_IOPAD(0x20a2, PIN_INPUT | MUX_MODE0) /* gpmc_d10.gpmc_d10 */
- OMAP3_CORE1_IOPAD(0x20a4, PIN_INPUT | MUX_MODE0) /* gpmc_d11.gpmc_d11 */
- OMAP3_CORE1_IOPAD(0x20a6, PIN_INPUT | MUX_MODE0) /* gpmc_d12.gpmc_d12 */
- OMAP3_CORE1_IOPAD(0x20a8, PIN_INPUT | MUX_MODE0) /* gpmc_d13.gpmc_d13 */
- OMAP3_CORE1_IOPAD(0x20aa, PIN_INPUT | MUX_MODE0) /* gpmc_d14.gpmc_d14 */
- OMAP3_CORE1_IOPAD(0x20ac, PIN_INPUT | MUX_MODE0) /* gpmc_d15.gpmc_d15 */
+ OMAP3_CORE1_IOPAD(0x209e, PIN_INPUT | MUX_MODE0) /* gpmc_d8.gpmc_d8 */
+ OMAP3_CORE1_IOPAD(0x20a0, PIN_INPUT | MUX_MODE0) /* gpmc_d9.gpmc_d9 */
+ OMAP3_CORE1_IOPAD(0x20a2, PIN_INPUT | MUX_MODE0) /* gpmc_d10.gpmc_d10 */
+ OMAP3_CORE1_IOPAD(0x20a4, PIN_INPUT | MUX_MODE0) /* gpmc_d11.gpmc_d11 */
+ OMAP3_CORE1_IOPAD(0x20a6, PIN_INPUT | MUX_MODE0) /* gpmc_d12.gpmc_d12 */
+ OMAP3_CORE1_IOPAD(0x20a8, PIN_INPUT | MUX_MODE0) /* gpmc_d13.gpmc_d13 */
+ OMAP3_CORE1_IOPAD(0x20aa, PIN_INPUT | MUX_MODE0) /* gpmc_d14.gpmc_d14 */
+ OMAP3_CORE1_IOPAD(0x20ac, PIN_INPUT | MUX_MODE0) /* gpmc_d15.gpmc_d15 */
/*
* gpmc_ncs0, gpmc_nadv_ale, gpmc_noe, gpmc_nwe, gpmc_wait0 not muxable
* according to TRM. OneNAND seems to require PIN_INPUT on clock.
*/
- OMAP3_CORE1_IOPAD(0x20b0, PIN_OUTPUT | MUX_MODE0) /* gpmc_ncs1.gpmc_ncs1 */
- OMAP3_CORE1_IOPAD(0x20be, PIN_INPUT | MUX_MODE0) /* gpmc_clk.gpmc_clk */
- >;
+ OMAP3_CORE1_IOPAD(0x20b0, PIN_OUTPUT | MUX_MODE0) /* gpmc_ncs1.gpmc_ncs1 */
+ OMAP3_CORE1_IOPAD(0x20be, PIN_INPUT | MUX_MODE0) /* gpmc_clk.gpmc_clk */
+ >;
};
i2c1_pins: pinmux_i2c1_pins {
@@ -738,12 +738,12 @@
si4713: si4713@63 {
compatible = "silabs,si4713";
- reg = <0x63>;
+ reg = <0x63>;
- interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */
- reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */
- vio-supply = <&vio>;
- vdd-supply = <&vaux1>;
+ interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */
+ reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */
+ vio-supply = <&vio>;
+ vdd-supply = <&vaux1>;
};
bq24150a: bq24150a@6b {
diff --git a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
index bb932913c9e3..a6dbbba799b2 100644
--- a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
@@ -17,19 +17,19 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- gpio148 {
+ led-gpio148 {
label = "overo:red:gpio148";
gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>; /* gpio 148 */
};
- gpio150 {
+ led-gpio150 {
label = "overo:yellow:gpio150";
gpios = <&gpio5 22 GPIO_ACTIVE_HIGH>; /* gpio 150 */
};
- gpio151 {
+ led-gpio151 {
label = "overo:blue:gpio151";
gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* gpio 151 */
};
- gpio170 {
+ led-gpio170 {
label = "overo:green:gpio170";
gpios = <&gpio6 10 GPIO_ACTIVE_HIGH>; /* gpio 170 */
};
diff --git a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
index 2d2c61d7aa86..0d0e62c00916 100644
--- a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
@@ -17,12 +17,12 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */
linux,default-trigger = "heartbeat";
};
- gpio22 {
+ led-gpio22 {
label = "overo:blue:gpio22";
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */
};
diff --git a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
index 155aec121400..5f6721326f86 100644
--- a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
@@ -17,12 +17,12 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */
linux,default-trigger = "heartbeat";
};
- gpio22 {
+ led-gpio22 {
label = "overo:blue:gpio22";
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */
};
diff --git a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
index 82a04466747a..4b66f622ac13 100644
--- a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
@@ -17,12 +17,12 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */
linux,default-trigger = "heartbeat";
};
- gpio22 {
+ led-gpio22 {
label = "overo:blue:gpio22";
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */
};
diff --git a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
index 453a55324fa1..a8f163a899f0 100644
--- a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
@@ -17,12 +17,12 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */
linux,default-trigger = "heartbeat";
};
- gpio22 {
+ led-gpio22 {
label = "overo:blue:gpio22";
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */
};
diff --git a/arch/arm/boot/dts/omap3-overo-summit-common.dtsi b/arch/arm/boot/dts/omap3-overo-summit-common.dtsi
index df7450f17ffd..ec03ca17e98b 100644
--- a/arch/arm/boot/dts/omap3-overo-summit-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-summit-common.dtsi
@@ -15,7 +15,7 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */
linux,default-trigger = "heartbeat";
diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
index 9bf4b88a4b50..5432e4e16ab5 100644
--- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
@@ -13,7 +13,7 @@
/ {
leds {
compatible = "gpio-leds";
- heartbeat {
+ led-heartbeat {
label = "overo:red:gpio21";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
linux,default-trigger = "heartbeat";
diff --git a/arch/arm/boot/dts/omap3-zoom3.dts b/arch/arm/boot/dts/omap3-zoom3.dts
index 0482676d1830..ce58b1f208e8 100644
--- a/arch/arm/boot/dts/omap3-zoom3.dts
+++ b/arch/arm/boot/dts/omap3-zoom3.dts
@@ -23,9 +23,9 @@
};
vddvario: regulator-vddvario {
- compatible = "regulator-fixed";
- regulator-name = "vddvario";
- regulator-always-on;
+ compatible = "regulator-fixed";
+ regulator-name = "vddvario";
+ regulator-always-on;
};
vdd33a: regulator-vdd33a {
@@ -84,28 +84,28 @@
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- OMAP3_CORE1_IOPAD(0x2180, PIN_INPUT | MUX_MODE0) /* uart1_cts.uart1_cts */
- OMAP3_CORE1_IOPAD(0x217e, PIN_OUTPUT | MUX_MODE0) /* uart1_rts.uart1_rts */
- OMAP3_CORE1_IOPAD(0x2182, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
- OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
+ OMAP3_CORE1_IOPAD(0x2180, PIN_INPUT | MUX_MODE0) /* uart1_cts.uart1_cts */
+ OMAP3_CORE1_IOPAD(0x217e, PIN_OUTPUT | MUX_MODE0) /* uart1_rts.uart1_rts */
+ OMAP3_CORE1_IOPAD(0x2182, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
+ OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
- OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
- OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
- OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- OMAP3_CORE1_IOPAD(0x219a, PIN_INPUT_PULLDOWN | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
- OMAP3_CORE1_IOPAD(0x219c, PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
- OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ OMAP3_CORE1_IOPAD(0x219a, PIN_INPUT_PULLDOWN | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
+ OMAP3_CORE1_IOPAD(0x219c, PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
>;
};
@@ -205,22 +205,22 @@
};
&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
};
&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart2_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
};
&uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
};
&uart4 {
- status = "disabled";
+ status = "disabled";
};
&usb_otg_hs {
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 825075ff0e34..92cd4c99dae7 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -893,15 +893,37 @@
#gpio-cells = <2>;
};
- usb_otg_hs: usb_otg_hs@480ab000 {
- compatible = "ti,omap3-musb";
- reg = <0x480ab000 0x1000>;
- interrupts = <92>, <93>;
- interrupt-names = "mc", "dma";
- ti,hwmods = "usb_otg_hs";
- multipoint = <1>;
- num-eps = <16>;
- ram-bits = <12>;
+ usb_otg_target: target-module@480ab000 {
+ compatible = "ti,sysc-omap2", "ti,sysc";
+ reg = <0x480ab400 0x4>,
+ <0x480ab404 0x4>,
+ <0x480ab408 0x4>;
+ reg-names = "rev", "sysc", "syss";
+ ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP |
+ SYSC_OMAP2_SOFTRESET |
+ SYSC_OMAP2_AUTOIDLE)>;
+ ti,sysc-midle = <SYSC_IDLE_FORCE>,
+ <SYSC_IDLE_NO>,
+ <SYSC_IDLE_SMART>;
+ ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+ <SYSC_IDLE_NO>,
+ <SYSC_IDLE_SMART>;
+ ti,syss-mask = <1>;
+ /* Clock defined in the SoC specific dtsi file */
+ clock-names = "fck";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x480ab000 0x1000>;
+
+ usb_otg_hs: usb@0 {
+ compatible = "ti,omap3-musb";
+ reg = <0 0x1000>;
+ interrupts = <92>, <93>;
+ interrupt-names = "mc", "dma";
+ multipoint = <1>;
+ num-eps = <16>;
+ ram-bits = <12>;
+ };
};
dss: dss@48050000 {
diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi
index 2eb73ae7ef3e..9dbf62797f0f 100644
--- a/arch/arm/boot/dts/omap34xx.dtsi
+++ b/arch/arm/boot/dts/omap34xx.dtsi
@@ -189,6 +189,10 @@
"ssi_ick";
};
+&usb_otg_target {
+ clocks = <&hsotgusb_ick_3430es2>;
+};
+
/include/ "omap34xx-omap36xx-clocks.dtsi"
/include/ "omap36xx-omap3430es2plus-clocks.dtsi"
/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi
index 32ac7924a130..fff9c3d34193 100644
--- a/arch/arm/boot/dts/omap36xx.dtsi
+++ b/arch/arm/boot/dts/omap36xx.dtsi
@@ -240,6 +240,10 @@
"ssi_ick";
};
+&usb_otg_target {
+ clocks = <&hsotgusb_ick_3430es2>;
+};
+
/include/ "omap34xx-omap36xx-clocks.dtsi"
/include/ "omap36xx-omap3430es2plus-clocks.dtsi"
/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap4-cpu-thermal.dtsi b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi
index 4d7eeb133dad..801b4f10350c 100644
--- a/arch/arm/boot/dts/omap4-cpu-thermal.dtsi
+++ b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi
@@ -13,20 +13,20 @@ cpu_thermal: cpu_thermal {
polling-delay = <1000>; /* milliseconds */
/* sensor ID */
- thermal-sensors = <&bandgap 0>;
+ thermal-sensors = <&bandgap 0>;
cpu_trips: trips {
- cpu_alert0: cpu_alert {
- temperature = <100000>; /* millicelsius */
- hysteresis = <2000>; /* millicelsius */
- type = "passive";
- };
- cpu_crit: cpu_crit {
- temperature = <125000>; /* millicelsius */
- hysteresis = <2000>; /* millicelsius */
- type = "critical";
- };
- };
+ cpu_alert0: cpu_alert {
+ temperature = <100000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_crit: cpu_crit {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
cpu_cooling_maps: cooling-maps {
map0 {
diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
index 518652a599bd..0269424350aa 100644
--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
+++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
@@ -49,13 +49,13 @@
&led_wkgpio_pins
>;
- heartbeat {
+ led-heartbeat {
label = "pandaboard::status1";
gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
- mmc {
+ led-mmc {
label = "pandaboard::status2";
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc0";
diff --git a/arch/arm/boot/dts/omap4-panda-es.dts b/arch/arm/boot/dts/omap4-panda-es.dts
index 7c6886cd738f..7631029e4d7a 100644
--- a/arch/arm/boot/dts/omap4-panda-es.dts
+++ b/arch/arm/boot/dts/omap4-panda-es.dts
@@ -79,10 +79,10 @@
&led_wkgpio_pins
>;
- heartbeat {
+ led-heartbeat {
gpios = <&gpio4 14 GPIO_ACTIVE_HIGH>;
};
- mmc {
+ led-mmc {
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts
index ca759b7b8a58..2d87b9fc230e 100644
--- a/arch/arm/boot/dts/omap5-cm-t54.dts
+++ b/arch/arm/boot/dts/omap5-cm-t54.dts
@@ -84,36 +84,36 @@
};
lcd0: display {
- compatible = "startek,startek-kd050c", "panel-dpi";
- label = "lcd";
-
- pinctrl-names = "default";
- pinctrl-0 = <&lcd_pins>;
-
- enable-gpios = <&gpio8 3 GPIO_ACTIVE_HIGH>;
-
- panel-timing {
- clock-frequency = <33000000>;
- hactive = <800>;
- vactive = <480>;
- hfront-porch = <40>;
- hback-porch = <40>;
- hsync-len = <43>;
- vback-porch = <29>;
- vfront-porch = <13>;
- vsync-len = <3>;
- hsync-active = <0>;
- vsync-active = <0>;
- de-active = <1>;
- pixelclk-active = <1>;
- };
-
- port {
- lcd_in: endpoint {
- remote-endpoint = <&dpi_lcd_out>;
- };
- };
- };
+ compatible = "startek,startek-kd050c", "panel-dpi";
+ label = "lcd";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_pins>;
+
+ enable-gpios = <&gpio8 3 GPIO_ACTIVE_HIGH>;
+
+ panel-timing {
+ clock-frequency = <33000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <40>;
+ hback-porch = <40>;
+ hsync-len = <43>;
+ vback-porch = <29>;
+ vfront-porch = <13>;
+ vsync-len = <3>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ };
+
+ port {
+ lcd_in: endpoint {
+ remote-endpoint = <&dpi_lcd_out>;
+ };
+ };
+ };
hdmi0: connector0 {
compatible = "hdmi-connector";
@@ -644,8 +644,8 @@
};
&usb3 {
- extcon = <&extcon_usb3>;
- vbus-supply = <&smps10_out1_reg>;
+ extcon = <&extcon_usb3>;
+ vbus-supply = <&smps10_out1_reg>;
};
&cpu0 {
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index 4fe7735c7c58..16212b912b94 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -53,6 +53,8 @@
compatible = "mrvl,mmp-timer";
reg = <0xd4014000 0x100>;
interrupts = <13>;
+ clocks = <&soc_clocks PXA168_CLK_TIMER>;
+ resets = <&soc_clocks PXA168_CLK_TIMER>;
};
uart1: serial@d4017000 {
diff --git a/arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts b/arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts
index 215613c65250..7a80e1c9f126 100644
--- a/arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts
+++ b/arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts
@@ -87,7 +87,7 @@
};
&rpm_requests {
- pm8226-regulators {
+ regulators {
compatible = "qcom,rpm-pm8226-regulators";
pm8226_s3: s3 {
diff --git a/arch/arm/boot/dts/qcom-apq8026-huawei-sturgeon.dts b/arch/arm/boot/dts/qcom-apq8026-huawei-sturgeon.dts
new file mode 100644
index 000000000000..d64096028ab1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-apq8026-huawei-sturgeon.dts
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Luca Weiss <luca@z3ntu.xyz>
+ */
+
+/dts-v1/;
+
+#include "qcom-msm8226.dtsi"
+#include "qcom-pm8226.dtsi"
+
+/delete-node/ &adsp_region;
+
+/ {
+ model = "Huawei Watch";
+ compatible = "huawei,sturgeon", "qcom,apq8026";
+ chassis-type = "watch";
+ qcom,msm-id = <199 0x20000>;
+ qcom,board-id = <8 4>;
+
+ reserved-memory {
+ sbl_region: sbl@2f00000 {
+ reg = <0x02f00000 0x100000>;
+ no-map;
+ };
+
+ external_image_region: external-image@3100000 {
+ reg = <0x3100000 0x200000>;
+ no-map;
+ };
+
+ peripheral_region: peripheral@3300000 {
+ reg = <0x3300000 0x600000>;
+ no-map;
+ };
+
+ adsp_region: adsp@3900000 {
+ reg = <0x3900000 0x1400000>;
+ no-map;
+ };
+
+ modem_region: modem@4d00000 {
+ reg = <0x4d00000 0x1b00000>;
+ no-map;
+ };
+
+ modem_efs_region: modem-efs@7f00000 {
+ reg = <0x7f00000 0x100000>;
+ no-map;
+ };
+ };
+
+ vreg_wlan: wlan-regulator {
+ compatible = "regulator-fixed";
+
+ regulator-name = "wl-reg";
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ gpio = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_regulator_default_state>;
+ };
+};
+
+&adsp {
+ status = "okay";
+};
+
+&blsp1_i2c5 {
+ clock-frequency = <384000>;
+
+ status = "okay";
+
+ touchscreen@20 {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x20>;
+
+ interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&pm8226_l19>;
+ vio-supply = <&pm8226_lvs1>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_default_state>;
+
+ syna,startup-delay-ms = <160>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rmi4-f01@1 {
+ reg = <0x1>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f12@12 {
+ reg = <0x12>;
+ syna,sensor-type = <1>;
+ };
+ };
+};
+
+&blsp1_uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&blsp1_uart4_default_state>;
+
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43430a0-bt";
+ max-speed = <3000000>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&bluetooth_default_state>;
+
+ host-wakeup-gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
+ device-wakeup-gpios = <&tlmm 63 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&tlmm 67 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8226-regulators";
+
+ pm8226_s3: s3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2200000>;
+ };
+
+ pm8226_s5: s5 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8226_l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l3: l3 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1337500>;
+ };
+
+ pm8226_l4: l4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l5: l5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l6: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l7: l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
+
+ pm8226_l8: l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l9: l9 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l10: l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l14: l14 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
+
+ pm8226_l15: l15 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ pm8226_l16: l16 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
+ };
+
+ pm8226_l17: l17 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l18: l18 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l19: l19 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8226_l20: l20 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8226_l21: l21 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l22: l22 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l23: l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l24: l24 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8226_l25: l25 {
+ regulator-min-microvolt = <1775000>;
+ regulator-max-microvolt = <2125000>;
+ };
+
+ pm8226_l26: l26 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l27: l27 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l28: l28 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_lvs1: lvs1 {};
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8226_l17>;
+ vqmmc-supply = <&pm8226_l6>;
+
+ bus-width = <8>;
+ non-removable;
+
+ status = "okay";
+};
+
+&sdhc_3 {
+ max-frequency = <100000000>;
+ non-removable;
+
+ vmmc-supply = <&vreg_wlan>;
+ vqmmc-supply = <&pm8226_l6>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+ wifi@1 {
+ compatible = "brcm,bcm43430a0-fmac", "brcm,bcm4329-fmac";
+ reg = <1>;
+
+ interrupts-extended = <&tlmm 66 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-names = "host-wake";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_hostwake_default_state>;
+ };
+};
+
+&smbb {
+ qcom,fast-charge-safe-voltage = <4370000>;
+ qcom,fast-charge-high-threshold-voltage = <4350000>;
+ qcom,minimum-input-voltage = <4350000>;
+ qcom,fast-charge-current-limit = <300000>;
+ qcom,fast-charge-safe-current = <600000>;
+ qcom,auto-recharge-threshold-voltage = <4240000>;
+};
+
+&tlmm {
+ blsp1_uart4_default_state: blsp1-uart4-default-state {
+ pins = "gpio12", "gpio13", "gpio14", "gpio15";
+ function = "blsp_uart4";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ bluetooth_default_state: bluetooth-default-state {
+ pins = "gpio63", "gpio64";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ touch_default_state: touch-default-state {
+ irq-pins {
+ pins = "gpio17";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+
+ reset-pins {
+ pins = "gpio16";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ wlan_hostwake_default_state: wlan-hostwake-default-state {
+ pins = "gpio66";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+
+ wlan_regulator_default_state: wlan-regulator-default-state {
+ pins = "gpio110";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+};
+
+&usb {
+ extcon = <&smbb>;
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usb_hs_phy {
+ extcon = <&smbb>;
+ v1p8-supply = <&pm8226_l10>;
+ v3p3-supply = <&pm8226_l20>;
+};
diff --git a/arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts b/arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts
index 193569f0ca5f..de2fb1c01b6e 100644
--- a/arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts
+++ b/arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts
@@ -13,6 +13,7 @@
/ {
model = "LG G Watch R";
compatible = "lg,lenok", "qcom,apq8026";
+ chassis-type = "watch";
qcom,board-id = <132 0x0a>;
qcom,msm-id = <199 0x20000>;
@@ -115,7 +116,7 @@
};
&rpm_requests {
- pm8226-regulators {
+ regulators {
compatible = "qcom,rpm-pm8226-regulators";
pm8226_s3: s3 {
@@ -299,8 +300,8 @@
input-enable;
};
- touch_pins: touch {
- irq {
+ touch_pins: touch-state {
+ irq-pins {
pins = "gpio17";
function = "gpio";
@@ -309,7 +310,7 @@
input-enable;
};
- reset {
+ reset-pins {
pins = "gpio16";
function = "gpio";
diff --git a/arch/arm/boot/dts/qcom-apq8026-samsung-matisse-wifi.dts b/arch/arm/boot/dts/qcom-apq8026-samsung-matisse-wifi.dts
new file mode 100644
index 000000000000..1c52337af560
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-apq8026-samsung-matisse-wifi.dts
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Matti Lehtimäki <matti.lehtimaki@gmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "qcom-msm8226.dtsi"
+#include "qcom-pm8226.dtsi"
+
+/ {
+ model = "Samsung Galaxy Tab 4 10.1";
+ compatible = "samsung,matisse-wifi", "qcom,apq8026";
+ chassis-type = "tablet";
+
+ aliases {
+ mmc0 = &sdhc_1; /* SDC1 eMMC slot */
+ mmc1 = &sdhc_2; /* SDC2 SD card slot */
+ display0 = &framebuffer0;
+ };
+
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ stdout-path = "display0";
+
+ framebuffer0: framebuffer@3200000 {
+ compatible = "simple-framebuffer";
+ reg = <0x03200000 0x800000>;
+ width = <1280>;
+ height = <800>;
+ stride = <(1280 * 3)>;
+ format = "r8g8b8";
+ };
+ };
+
+ gpio-hall-sensor {
+ compatible = "gpio-keys";
+
+ event-hall-sensor {
+ label = "Hall Effect Sensor";
+ gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ interrupts = <&tlmm 110 IRQ_TYPE_EDGE_FALLING>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ debounce-interval = <15>;
+ wakeup-source;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+
+ key-home {
+ label = "Home";
+ gpios = <&tlmm 108 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_HOMEPAGE>;
+ debounce-interval = <15>;
+ };
+
+ key-volume-down {
+ label = "Volume Down";
+ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ debounce-interval = <15>;
+ };
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&tlmm 106 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ };
+ };
+
+ reg_tsp_1p8v: regulator-tsp-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "tsp_1p8v";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ gpio = <&tlmm 31 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsp_en_default_state>;
+ };
+
+ reg_tsp_3p3v: regulator-tsp-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "tsp_3p3v";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsp_en1_default_state>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@3200000 {
+ reg = <0x03200000 0x800000>;
+ no-map;
+ };
+
+ mpss@8400000 {
+ reg = <0x08400000 0x1f00000>;
+ no-map;
+ };
+
+ mba@a300000 {
+ reg = <0x0a300000 0x100000>;
+ no-map;
+ };
+
+ reserved@cb00000 {
+ reg = <0x0cb00000 0x700000>;
+ no-map;
+ };
+
+ wcnss@d200000 {
+ reg = <0x0d200000 0x700000>;
+ no-map;
+ };
+
+ adsp@d900000 {
+ reg = <0x0d900000 0x1800000>;
+ no-map;
+ };
+
+ venus@f100000 {
+ reg = <0x0f100000 0x500000>;
+ no-map;
+ };
+
+ /delete-node/ smem@3000000;
+ smem_region: smem@fa00000 {
+ reg = <0x0fa00000 0x100000>;
+ no-map;
+ };
+
+ reserved@fb00000 {
+ reg = <0x0fb00000 0x260000>;
+ no-map;
+ };
+
+ rfsa@fd60000 {
+ reg = <0x0fd60000 0x20000>;
+ no-map;
+ };
+
+ rmtfs@fd80000 {
+ compatible = "qcom,rmtfs-mem";
+ reg = <0x0fd80000 0x180000>;
+ no-map;
+
+ qcom,client-id = <1>;
+ };
+ };
+};
+
+&blsp1_i2c2 {
+ status = "okay";
+
+ accelerometer@1d {
+ compatible = "st,lis2hh12";
+ reg = <0x1d>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <54 IRQ_TYPE_LEVEL_HIGH>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&accel_int_default_state>;
+
+ st,drdy-int-pin = <1>;
+
+ vdd-supply = <&pm8226_l19>;
+ vddio-supply = <&pm8226_lvs1>;
+ };
+};
+
+&blsp1_i2c4 {
+ status = "okay";
+
+ muic: usb-switch@25 {
+ compatible = "siliconmitus,sm5502-muic";
+ reg = <0x25>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&muic_int_default_state>;
+ };
+};
+
+&blsp1_i2c5 {
+ status = "okay";
+
+ touchscreen@4a {
+ compatible = "atmel,maxtouch";
+ reg = <0x4a>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsp_int_rst_default_state>;
+
+ reset-gpios = <&pm8226_gpios 6 GPIO_ACTIVE_LOW>;
+
+ vdd-supply = <&reg_tsp_1p8v>;
+ vdda-supply = <&reg_tsp_3p3v>;
+ };
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8226-regulators";
+
+ pm8226_s3: s3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_s5: s5 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8226_l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l3: l3 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1337500>;
+ regulator-always-on;
+ };
+
+ pm8226_l4: l4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l5: l5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l6: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ pm8226_l7: l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
+
+ pm8226_l8: l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ pm8226_l9: l9 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l10: l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l14: l14 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
+
+ pm8226_l15: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8226_l16: l16 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
+ };
+
+ pm8226_l17: l17 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-system-load = <200000>;
+ regulator-allow-set-load;
+ regulator-always-on;
+ };
+
+ pm8226_l18: l18 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l19: l19 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8226_l20: l20 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8226_l21: l21 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l22: l22 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8226_l23: l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8226_l24: l24 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8226_l25: l25 {
+ regulator-min-microvolt = <1775000>;
+ regulator-max-microvolt = <2125000>;
+ };
+
+ pm8226_l26: l26 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_l27: l27 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l28: l28 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_lvs1: lvs1 {};
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8226_l17>;
+ vqmmc-supply = <&pm8226_l6>;
+
+ bus-width = <8>;
+ non-removable;
+
+ status = "okay";
+};
+
+&sdhc_2 {
+ vmmc-supply = <&pm8226_l18>;
+ vqmmc-supply = <&pm8226_l21>;
+
+ bus-width = <4>;
+ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+
+ status = "okay";
+};
+
+&tlmm {
+ accel_int_default_state: accel-int-default-state {
+ pins = "gpio54";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ muic_int_default_state: muic-int-default-state {
+ pins = "gpio67";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ tsp_en_default_state: tsp-en-default-state {
+ pins = "gpio31";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ tsp_en1_default_state: tsp-en1-default-state {
+ pins = "gpio73";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ tsp_int_rst_default_state: tsp-int-rst-default-state {
+ pins = "gpio17";
+ function = "gpio";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+};
+
+&usb {
+ extcon = <&muic>, <&muic>;
+ status = "okay";
+};
+
+&usb_hs_phy {
+ extcon = <&muic>;
+ v1p8-supply = <&pm8226_l10>;
+ v3p3-supply = <&pm8226_l20>;
+};
diff --git a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
index 573e4dc66bb0..7a4c59e04af6 100644
--- a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
+++ b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
@@ -81,931 +81,899 @@
pinctrl-names = "default";
pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>;
};
+};
- soc {
- pinctrl@800000 {
- /* eMMC pins, all 8 data lines connected */
- dragon_sdcc1_pins: sdcc1 {
- mux {
- pins = "gpio159", "gpio160", "gpio161",
- "gpio162", "gpio163", "gpio164",
- "gpio165", "gpio166", "gpio167",
- "gpio168";
- function = "sdc1";
- };
- clk {
- pins = "gpio167"; /* SDC1 CLK */
- drive-strength = <16>;
- bias-disable;
- };
- cmd {
- pins = "gpio168"; /* SDC1 CMD */
- drive-strength = <10>;
- bias-pull-up;
- };
- data {
- /* SDC1 D0 to D7 */
- pins = "gpio159", "gpio160", "gpio161", "gpio162",
- "gpio163", "gpio164", "gpio165", "gpio166";
- drive-strength = <10>;
- bias-pull-up;
- };
- };
+&ebi2 {
+ /* The EBI2 will instantiate first, then populate its children */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ebi2_pins>;
+ status = "okay";
- /*
- * The SDCC3 pins are hardcoded (non-muxable) but need some pin
- * configuration.
- */
- dragon_sdcc3_pins: sdcc3 {
- clk {
- pins = "sdc3_clk";
- drive-strength = <8>;
- bias-disable;
- };
- cmd {
- pins = "sdc3_cmd";
- drive-strength = <8>;
- bias-pull-up;
- };
- data {
- pins = "sdc3_data";
- drive-strength = <8>;
- bias-pull-up;
- };
- };
+ /*
+ * An on-board SMSC LAN9221 chip for "debug ethernet",
+ * which is actually just an ordinary ethernet on the
+ * EBI2. This has a 25MHz chrystal next to it, so no
+ * clocking is needed.
+ */
+ ethernet@2,0 {
+ compatible = "smsc,lan9221", "smsc,lan9115";
+ reg = <2 0x0 0x100>;
+ /*
+ * The second interrupt is the PME interrupt
+ * for network wakeup, connected to the TLMM.
+ */
+ interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>,
+ <&tlmm 29 IRQ_TYPE_EDGE_RISING>;
+ reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
+ vdd33a-supply = <&dragon_veth>;
+ vddvario-supply = <&dragon_vario>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ethernet_gpios>;
+ phy-mode = "mii";
+ reg-io-width = <2>;
+ smsc,force-external-phy;
+ smsc,irq-push-pull;
+
+ /*
+ * SLOW chipselect config
+ * Delay 9 cycles (140ns@64MHz) between SMSC
+ * LAN9221 Ethernet controller reads and writes
+ * on CS2.
+ */
+ qcom,xmem-recovery-cycles = <0>;
+ qcom,xmem-write-hold-cycles = <3>;
+ qcom,xmem-write-delta-cycles = <31>;
+ qcom,xmem-read-delta-cycles = <28>;
+ qcom,xmem-write-wait-cycles = <9>;
+ qcom,xmem-read-wait-cycles = <9>;
+ };
+};
- /* Second SD card slot pins */
- dragon_sdcc5_pins: sdcc5 {
- mux {
- pins = "gpio95", "gpio96", "gpio97",
- "gpio98", "gpio99", "gpio100";
- function = "sdc5";
- };
- clk {
- pins = "gpio97"; /* SDC5 CLK */
- drive-strength = <16>;
- bias-disable;
- };
- cmd {
- pins = "gpio95"; /* SDC5 CMD */
- drive-strength = <10>;
- bias-pull-up;
- };
- data {
- /* SDC5 D0 to D3 */
- pins = "gpio96", "gpio98", "gpio99", "gpio100";
- drive-strength = <10>;
- bias-pull-up;
- };
- };
+&gsbi3 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
- dragon_gsbi3_i2c_pins: gsbi3_i2c {
- mux {
- pins = "gpio43", "gpio44";
- function = "gsbi3";
- };
- pinconf {
- pins = "gpio43", "gpio44";
- drive-strength = <8>;
- /* These have external pull-up 2.2kOhm to 1.8V */
- bias-disable;
- };
- };
+&gsbi3_i2c {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi3_i2c_pins>;
+ status = "okay";
+
+ touchscreen@24 {
+ compatible = "cypress,cy8ctma340";
+ reg = <0x24>;
+ /* Certainly we can do at least 400 kHz */
+ clock-frequency = <400000>;
+ /* IRQ on GPIO61 called /CTP_INT */
+ interrupt-parent = <&tlmm>;
+ interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
+ /*
+ * The I2C bus is using a PCA9306 level translator from L16A
+ * to L2B so these two voltages are needed and L16A is
+ * kind of the IO voltage, however L16Aisn't really fed to
+ * the TMA340, which relies entirely on L2B (PM8901 L2).
+ */
+ vcpin-supply = <&pm8058_l16>;
+ vdd-supply = <&pm8901_l2>;
+ /* GPIO58, called WAKE_CTP */
+ reset-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
+ touchscreen-size-x = <480>;
+ touchscreen-size-y = <800>;
+ active-interval-ms = <0>;
+ touch-timeout-ms = <255>;
+ lowpower-interval-ms = <10>;
+ bootloader-key = /bits/ 8 <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_tma340_gpios>;
+ };
+};
- dragon_gsbi8_i2c_pins: gsbi8_i2c {
- mux {
- pins = "gpio64", "gpio65";
- function = "gsbi8";
- };
- pinconf {
- pins = "gpio64", "gpio65";
- drive-strength = <16>;
- /* These have external pull-up 2.2kOhm to 1.8V */
- bias-disable;
- };
- };
+&gsbi8 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
- dragon_gsbi12_i2c_pins: gsbi12_i2c {
- mux {
- pins = "gpio115", "gpio116";
- function = "gsbi12";
- };
- pinconf {
- pins = "gpio115", "gpio116";
- drive-strength = <16>;
- /* These have external pull-up 4.7kOhm to 1.8V */
- bias-disable;
- };
- };
+&gsbi8_i2c {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi8_i2c_pins>;
+ status = "okay";
+
+ eeprom@52 {
+ /* A 16KiB Platform ID EEPROM on the CPU carrier board */
+ compatible = "atmel,24c128";
+ reg = <0x52>;
+ vcc-supply = <&pm8058_s3>;
+ pagesize = <64>;
+ };
+ wm8903: wm8903@1a {
+ /* This Woolfson Micro device has an unrouted interrupt line */
+ compatible = "wlf,wm8903";
+ reg = <0x1a>;
+
+ AVDD-supply = <&pm8058_l16>;
+ CPVDD-supply = <&pm8058_l16>;
+ DBVDD-supply = <&pm8058_s3>;
+ DCVDD-supply = <&pm8058_l0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ micdet-cfg = <0>;
+ micdet-delay = <100>;
+ gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+ };
+};
- /* Primary serial port uart 0 pins */
- dragon_gsbi12_serial_pins: gsbi12_serial {
- mux {
- pins = "gpio117", "gpio118";
- function = "gsbi12";
- };
- tx {
- pins = "gpio117";
- drive-strength = <8>;
- bias-disable;
- };
- rx {
- pins = "gpio118";
- drive-strength = <2>;
- bias-pull-up;
- };
- };
+&gsbi12 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
- dragon_ebi2_pins: ebi2 {
- /*
- * Pins used by EBI2 on the Dragonboard, actually only
- * CS2 is used by a real peripheral. CS0 is just
- * routed to a test point.
- */
- mux0 {
- pins =
- /* "gpio39", CS1A_N this is not good to mux */
- "gpio40", /* CS2A_N */
- "gpio134"; /* CS0_N testpoint TP29 */
- function = "ebi2cs";
- };
- mux1 {
- pins =
- /* EBI2_ADDR_7 downto EBI2_ADDR_0 address bus */
- "gpio123", "gpio124", "gpio125", "gpio126",
- "gpio127", "gpio128", "gpio129", "gpio130",
- /* EBI2_DATA_15 downto EBI2_DATA_0 data bus */
- "gpio135", "gpio136", "gpio137", "gpio138",
- "gpio139", "gpio140", "gpio141", "gpio142",
- "gpio143", "gpio144", "gpio145", "gpio146",
- "gpio147", "gpio148", "gpio149", "gpio150",
- "gpio151", /* EBI2_OE_N */
- "gpio153", /* EBI2_ADV */
- "gpio157"; /* EBI2_WE_N */
- function = "ebi2";
- };
- };
+&gsbi12_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi12_serial_pins>;
+ status = "okay";
+};
- /* Interrupt line for the KXSD9 accelerometer */
- dragon_kxsd9_gpios: kxsd9 {
- irq {
- pins = "gpio57"; /* IRQ line */
- bias-pull-up;
- };
- };
+&gsbi12_i2c {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi12_i2c_pins>;
+ status = "okay";
+
+ ak8975@c {
+ compatible = "asahi-kasei,ak8975";
+ reg = <0x0c>;
+ interrupt-parent = <&pm8058_gpio>;
+ interrupts = <33 IRQ_TYPE_EDGE_RISING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ak8975_gpios>;
+ vid-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
+ };
+ bmp085@77 {
+ compatible = "bosch,bmp085";
+ reg = <0x77>;
+ interrupt-parent = <&pm8058_gpio>;
+ interrupts = <16 IRQ_TYPE_EDGE_RISING>;
+ reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_bmp085_gpios>;
+ vddd-supply = <&pm8058_lvs0>; // 1.8V
+ vdda-supply = <&pm8058_l14>; // 2.85V
+ };
+ mpu3050@68 {
+ compatible = "invensense,mpu3050";
+ reg = <0x68>;
+ /*
+ * GPIO17 is pulled high by a 10k
+ * resistor to VLOGIC so needs to be
+ * active low/falling edge.
+ */
+ interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_mpu3050_gpios>;
+ vlogic-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
- dragon_tma340_gpios: tma340 {
- reset {
- /* RESET line, TS_ATTN, WAKE_CTP */
- pins = "gpio58";
- function = "gpio";
- drive-strength = <6>;
- bias-disable;
- };
- irq {
- pins = "gpio61"; /* IRQ line */
- function = "gpio";
- drive-strength = <2>;
- bias-pull-up;
- };
+ /*
+ * The MPU-3050 acts as a hub for the
+ * accelerometer.
+ */
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ kxsd9@18 {
+ compatible = "kionix,kxsd9";
+ reg = <0x18>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_kxsd9_gpios>;
+ iovdd-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
};
};
+ };
+};
- qcom,ssbi@500000 {
- pmic@0 {
- keypad@148 {
- linux,keymap = <
- MATRIX_KEY(0, 0, KEY_MENU)
- MATRIX_KEY(0, 2, KEY_1)
- MATRIX_KEY(0, 3, KEY_4)
- MATRIX_KEY(0, 4, KEY_7)
- MATRIX_KEY(1, 0, KEY_UP)
- MATRIX_KEY(1, 1, KEY_LEFT)
- MATRIX_KEY(1, 2, KEY_DOWN)
- MATRIX_KEY(1, 3, KEY_5)
- MATRIX_KEY(1, 3, KEY_8)
- MATRIX_KEY(2, 0, KEY_HOME)
- MATRIX_KEY(2, 1, KEY_REPLY)
- MATRIX_KEY(2, 2, KEY_2)
- MATRIX_KEY(2, 3, KEY_6)
- MATRIX_KEY(3, 0, KEY_VOLUMEUP)
- MATRIX_KEY(3, 1, KEY_RIGHT)
- MATRIX_KEY(3, 2, KEY_3)
- MATRIX_KEY(3, 3, KEY_9)
- MATRIX_KEY(3, 4, KEY_SWITCHVIDEOMODE)
- MATRIX_KEY(4, 0, KEY_VOLUMEDOWN)
- MATRIX_KEY(4, 1, KEY_BACK)
- MATRIX_KEY(4, 2, KEY_CAMERA)
- MATRIX_KEY(4, 3, KEY_KBDILLUMTOGGLE)
- >;
- keypad,num-rows = <6>;
- keypad,num-columns = <5>;
- };
-
- gpio@150 {
- dragon_ethernet_gpios: ethernet-state {
- pinconf {
- pins = "gpio7";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_bmp085_gpios: bmp085-state {
- pinconf {
- pins = "gpio16";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_mpu3050_gpios: mpu3050-state {
- pinconf {
- pins = "gpio17";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_sdcc3_gpios: sdcc3-state {
- pinconf {
- pins = "gpio22";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_sdcc5_gpios: sdcc5-state {
- pinconf {
- pins = "gpio26";
- function = "normal";
- input-enable;
- bias-pull-up;
- qcom,pull-up-strength = <PMIC_GPIO_PULL_UP_30>;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_ak8975_gpios: ak8975-state {
- pinconf {
- pins = "gpio33";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_cm3605_gpios: cm3605-state {
- /* Pin 34 connected to the proxy IRQ */
- gpio34-pins {
- pins = "gpio34";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- /* Pin 35 connected to ASET */
- gpio35-pins {
- pins = "gpio35";
- function = "normal";
- output-high;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_veth_gpios: veth-state {
- pinconf {
- pins = "gpio40";
- function = "normal";
- bias-disable;
- drive-push-pull;
- };
- };
- };
-
- mpps@50 {
- dragon_cm3605_mpps: cm3605-mpps-state {
- mpp5 {
- pins = "mpp5";
- function = "analog";
- input-enable;
- bias-high-impedance;
- /* Let's use channel 5 */
- qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH5>;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- };
-
- xoadc@197 {
- /* Reference voltage 2.2 V */
- xoadc-ref-supply = <&pm8058_l18>;
-
- /* Board-specific channels */
- mpp5@5 {
- /* Connected to AOUT of ALS sensor */
- reg = <0x00 0x05>;
- };
- mpp6@6 {
- /* Connected to test point TP43 */
- reg = <0x00 0x06>;
- };
- mpp7@7 {
- /* Connected to battery thermistor */
- reg = <0x00 0x07>;
- };
- mpp8@8 {
- /* Connected to battery ID detector */
- reg = <0x00 0x08>;
- };
- mpp9@9 {
- /* Connected to XO thermistor */
- reg = <0x00 0x09>;
- };
- };
-
- led@48 {
- /*
- * The keypad LED @0x48 is routed to
- * the sensor board where it is
- * connected to an infrared LED
- * SFH4650 (60mW, @850nm) next to the
- * ambient light and proximity sensor
- * Capella Microsystems CM3605.
- */
- compatible = "qcom,pm8058-keypad-led";
- reg = <0x48>;
- label = "pm8058:infrared:proximitysensor";
- default-state = "off";
- linux,default-trigger = "cm3605";
- };
- led@131 {
- compatible = "qcom,pm8058-led";
- reg = <0x131>;
- label = "pm8058:red";
- color = <LED_COLOR_ID_RED>;
- default-state = "off";
- };
- led@132 {
- /*
- * This is actually green too on my
- * board, but documented as yellow.
- */
- compatible = "qcom,pm8058-led";
- reg = <0x132>;
- label = "pm8058:yellow";
- color = <LED_COLOR_ID_YELLOW>;
- default-state = "off";
- linux,default-trigger = "mmc0";
- };
- led@133 {
- compatible = "qcom,pm8058-led";
- reg = <0x133>;
- label = "pm8058:green";
- function = LED_FUNCTION_HEARTBEAT;
- color = <LED_COLOR_ID_GREEN>;
- default-state = "on";
- linux,default-trigger = "heartbeat";
- };
- };
+&pm8058_gpio {
+ dragon_ethernet_gpios: ethernet-state {
+ pinconf {
+ pins = "gpio7";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_bmp085_gpios: bmp085-state {
+ pinconf {
+ pins = "gpio16";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_mpu3050_gpios: mpu3050-state {
+ pinconf {
+ pins = "gpio17";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_sdcc3_gpios: sdcc3-state {
+ pinconf {
+ pins = "gpio22";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_sdcc5_gpios: sdcc5-state {
+ pinconf {
+ pins = "gpio26";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ qcom,pull-up-strength = <PMIC_GPIO_PULL_UP_30>;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_ak8975_gpios: ak8975-state {
+ pinconf {
+ pins = "gpio33";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_cm3605_gpios: cm3605-state {
+ /* Pin 34 connected to the proxy IRQ */
+ gpio34-pins {
+ pins = "gpio34";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ /* Pin 35 connected to ASET */
+ gpio35-pins {
+ pins = "gpio35";
+ function = "normal";
+ output-high;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_veth_gpios: veth-state {
+ pinconf {
+ pins = "gpio40";
+ function = "normal";
+ bias-disable;
+ drive-push-pull;
};
+ };
+};
- gsbi@16200000 {
- qcom,mode = <GSBI_PROT_I2C>;
- status = "okay";
+&pm8058_keypad {
+ linux,keymap = <
+ MATRIX_KEY(0, 0, KEY_MENU)
+ MATRIX_KEY(0, 2, KEY_1)
+ MATRIX_KEY(0, 3, KEY_4)
+ MATRIX_KEY(0, 4, KEY_7)
+ MATRIX_KEY(1, 0, KEY_UP)
+ MATRIX_KEY(1, 1, KEY_LEFT)
+ MATRIX_KEY(1, 2, KEY_DOWN)
+ MATRIX_KEY(1, 3, KEY_5)
+ MATRIX_KEY(1, 3, KEY_8)
+ MATRIX_KEY(2, 0, KEY_HOME)
+ MATRIX_KEY(2, 1, KEY_REPLY)
+ MATRIX_KEY(2, 2, KEY_2)
+ MATRIX_KEY(2, 3, KEY_6)
+ MATRIX_KEY(3, 0, KEY_VOLUMEUP)
+ MATRIX_KEY(3, 1, KEY_RIGHT)
+ MATRIX_KEY(3, 2, KEY_3)
+ MATRIX_KEY(3, 3, KEY_9)
+ MATRIX_KEY(3, 4, KEY_SWITCHVIDEOMODE)
+ MATRIX_KEY(4, 0, KEY_VOLUMEDOWN)
+ MATRIX_KEY(4, 1, KEY_BACK)
+ MATRIX_KEY(4, 2, KEY_CAMERA)
+ MATRIX_KEY(4, 3, KEY_KBDILLUMTOGGLE)
+ >;
+ keypad,num-rows = <6>;
+ keypad,num-columns = <5>;
+};
- gsbi3_i2c: i2c@16280000 {
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi3_i2c_pins>;
- status = "okay";
-
- touchscreen@24 {
- compatible = "cypress,cy8ctma340";
- reg = <0x24>;
- /* Certainly we can do at least 400 kHz */
- clock-frequency = <400000>;
- /* IRQ on GPIO61 called /CTP_INT */
- interrupt-parent = <&tlmm>;
- interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
- /*
- * The I2C bus is using a PCA9306 level translator from L16A
- * to L2B so these two voltages are needed and L16A is
- * kind of the IO voltage, however L16Aisn't really fed to
- * the TMA340, which relies entirely on L2B (PM8901 L2).
- */
- vcpin-supply = <&pm8058_l16>;
- vdd-supply = <&pm8901_l2>;
- /* GPIO58, called WAKE_CTP */
- reset-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
- touchscreen-size-x = <480>;
- touchscreen-size-y = <800>;
- active-interval-ms = <0>;
- touch-timeout-ms = <255>;
- lowpower-interval-ms = <10>;
- bootloader-key = /bits/ 8 <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_tma340_gpios>;
- };
- };
+&pm8058_led48 {
+ /*
+ * The keypad LED @0x48 is routed to
+ * the sensor board where it is
+ * connected to an infrared LED
+ * SFH4650 (60mW, @850nm) next to the
+ * ambient light and proximity sensor
+ * Capella Microsystems CM3605.
+ */
+ label = "pm8058:infrared:proximitysensor";
+ default-state = "off";
+ linux,default-trigger = "cm3605";
+ status = "okay";
+};
+
+&pm8058_led131 {
+ label = "pm8058:red";
+ color = <LED_COLOR_ID_RED>;
+ default-state = "off";
+ status = "okay";
+};
+
+&pm8058_led132 {
+ /*
+ * This is actually green too on my
+ * board, but documented as yellow.
+ */
+ label = "pm8058:yellow";
+ color = <LED_COLOR_ID_YELLOW>;
+ default-state = "off";
+ linux,default-trigger = "mmc0";
+ status = "okay";
+};
+
+&pm8058_led133 {
+ label = "pm8058:green";
+ function = LED_FUNCTION_HEARTBEAT;
+ color = <LED_COLOR_ID_GREEN>;
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ status = "okay";
+};
+
+&pm8058_mpps {
+ dragon_cm3605_mpps: cm3605-mpps-state {
+ mpp5 {
+ pins = "mpp5";
+ function = "analog";
+ input-enable;
+ bias-high-impedance;
+ /* Let's use channel 5 */
+ qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH5>;
+ power-source = <PM8058_GPIO_S3>;
};
+ };
+};
- gsbi@19800000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
+&rpm {
+ /*
+ * Set up of the PMIC RPM regulators for this board
+ * PM8901 supplies "preliminary regulators" whatever
+ * that means
+ */
+ pm8901-regulators {
+ vdd_l0-supply = <&pm8901_s4>;
+ vdd_l1-supply = <&vph>;
+ vdd_l2-supply = <&vph>;
+ vdd_l3-supply = <&vph>;
+ vdd_l4-supply = <&vph>;
+ vdd_l5-supply = <&vph>;
+ vdd_l6-supply = <&vph>;
+ /* vdd_s0-supply, vdd_s1-supply: SAW regulators */
+ vdd_s2-supply = <&vph>;
+ vdd_s3-supply = <&vph>;
+ vdd_s4-supply = <&vph>;
+ lvs0_in-supply = <&pm8058_s3>;
+ lvs1_in-supply = <&pm8901_s4>;
+ lvs2_in-supply = <&pm8058_l0>;
+ lvs3_in-supply = <&pm8058_s2>;
+ mvs_in-supply = <&pm8058_s3>;
+
+ l0 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l2 {
+ /* TMA340 requires strictly 3.3V */
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l4 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l5 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l6 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ bias-pull-down;
+ };
- i2c@19880000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi8_i2c_pins>;
-
- eeprom@52 {
- /* A 16KiB Platform ID EEPROM on the CPU carrier board */
- compatible = "atmel,24c128";
- reg = <0x52>;
- vcc-supply = <&pm8058_s3>;
- pagesize = <64>;
- };
- wm8903: wm8903@1a {
- /* This Woolfson Micro device has an unrouted interrupt line */
- compatible = "wlf,wm8903";
- reg = <0x1a>;
-
- AVDD-supply = <&pm8058_l16>;
- CPVDD-supply = <&pm8058_l16>;
- DBVDD-supply = <&pm8058_s3>;
- DCVDD-supply = <&pm8058_l0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- micdet-cfg = <0>;
- micdet-delay = <100>;
- gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
- };
- };
+ /* s0 and s1 are SAW regulators controlled over SPM */
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s3 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s4 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
};
- gsbi@19c00000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
+ /* LVS0 thru 3 and mvs are just switches */
+ lvs0 {
+ regulator-always-on;
+ };
+ lvs1 { };
+ lvs2 { };
+ lvs3 { };
+ mvs { };
- serial@19c40000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi12_serial_pins>;
- };
+ };
- i2c@19c80000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi12_i2c_pins>;
-
- ak8975@c {
- compatible = "asahi-kasei,ak8975";
- reg = <0x0c>;
- interrupt-parent = <&pm8058_gpio>;
- interrupts = <33 IRQ_TYPE_EDGE_RISING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ak8975_gpios>;
- vid-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
- };
- bmp085@77 {
- compatible = "bosch,bmp085";
- reg = <0x77>;
- interrupt-parent = <&pm8058_gpio>;
- interrupts = <16 IRQ_TYPE_EDGE_RISING>;
- reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_bmp085_gpios>;
- vddd-supply = <&pm8058_lvs0>; // 1.8V
- vdda-supply = <&pm8058_l14>; // 2.85V
- };
- mpu3050@68 {
- compatible = "invensense,mpu3050";
- reg = <0x68>;
- /*
- * GPIO17 is pulled high by a 10k
- * resistor to VLOGIC so needs to be
- * active low/falling edge.
- */
- interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_mpu3050_gpios>;
- vlogic-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
-
- /*
- * The MPU-3050 acts as a hub for the
- * accelerometer.
- */
- i2c-gate {
- #address-cells = <1>;
- #size-cells = <0>;
-
- kxsd9@18 {
- compatible = "kionix,kxsd9";
- reg = <0x18>;
- interrupt-parent = <&tlmm>;
- interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_kxsd9_gpios>;
- iovdd-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
- };
- };
- };
- };
+ pm8058-regulators {
+ vdd_l0_l1_lvs-supply = <&pm8058_s3>;
+ vdd_l2_l11_l12-supply = <&vph>;
+ vdd_l3_l4_l5-supply = <&vph>;
+ vdd_l6_l7-supply = <&vph>;
+ vdd_l8-supply = <&vph>;
+ vdd_l9-supply = <&vph>;
+ vdd_l10-supply = <&vph>;
+ vdd_l13_l16-supply = <&pm8058_s4>;
+ vdd_l14_l15-supply = <&vph>;
+ vdd_l17_l18-supply = <&vph>;
+ vdd_l19_l20-supply = <&vph>;
+ vdd_l21-supply = <&pm8058_s3>;
+ vdd_l22-supply = <&pm8058_s3>;
+ vdd_l23_l24_l25-supply = <&pm8058_s3>;
+ vdd_s0-supply = <&vph>;
+ vdd_s1-supply = <&vph>;
+ vdd_s2-supply = <&vph>;
+ vdd_s3-supply = <&vph>;
+ vdd_s4-supply = <&vph>;
+ vdd_ncp-supply = <&vph>;
+
+ l0 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l4 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l5 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l6 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3600000>;
+ bias-pull-down;
+ };
+ l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l8 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <3050000>;
+ bias-pull-down;
+ };
+ l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l10 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l11 {
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ bias-pull-down;
+ };
+ l12 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ bias-pull-down;
+ };
+ l13 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ bias-pull-down;
+ };
+ l14 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+ l15 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+ l17 {
+ // 1.5V according to schematic
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l18 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ bias-pull-down;
+ };
+ l19 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ bias-pull-down;
+ };
+ l20 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l21 {
+ // 1.1 V according to schematic
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+ l22 {
+ // 1.2 V according to schematic
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ bias-pull-down;
+ };
+ l23 {
+ // Unused
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l24 {
+ // Unused
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l25 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
};
- external-bus@1a100000 {
- /* The EBI2 will instantiate first, then populate its children */
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ebi2_pins>;
-
- /*
- * An on-board SMSC LAN9221 chip for "debug ethernet",
- * which is actually just an ordinary ethernet on the
- * EBI2. This has a 25MHz chrystal next to it, so no
- * clocking is needed.
- */
- ethernet@2,0 {
- compatible = "smsc,lan9221", "smsc,lan9115";
- reg = <2 0x0 0x100>;
- /*
- * The second interrupt is the PME interrupt
- * for network wakeup, connected to the TLMM.
- */
- interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>,
- <&tlmm 29 IRQ_TYPE_EDGE_RISING>;
- reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
- vdd33a-supply = <&dragon_veth>;
- vddvario-supply = <&dragon_vario>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ethernet_gpios>;
- phy-mode = "mii";
- reg-io-width = <2>;
- smsc,force-external-phy;
- smsc,irq-push-pull;
-
- /*
- * SLOW chipselect config
- * Delay 9 cycles (140ns@64MHz) between SMSC
- * LAN9221 Ethernet controller reads and writes
- * on CS2.
- */
- qcom,xmem-recovery-cycles = <0>;
- qcom,xmem-write-hold-cycles = <3>;
- qcom,xmem-write-delta-cycles = <31>;
- qcom,xmem-read-delta-cycles = <28>;
- qcom,xmem-write-wait-cycles = <9>;
- qcom,xmem-read-wait-cycles = <9>;
- };
+ s0 {
+ // regulator-min-microvolt = <500000>;
+ // regulator-max-microvolt = <1325000>;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s1 {
+ // regulator-min-microvolt = <500000>;
+ // regulator-max-microvolt = <1250000>;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s2 {
+ // 1.3 V according to schematic
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ regulator-always-on;
+ bias-pull-down;
+ };
+ s4 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ qcom,switch-mode-frequency = <1600000>;
+ regulator-always-on;
+ bias-pull-down;
};
- rpm@104000 {
- /*
- * Set up of the PMIC RPM regulators for this board
- * PM8901 supplies "preliminary regulators" whatever
- * that means
- */
- pm8901-regulators {
- vdd_l0-supply = <&pm8901_s4>;
- vdd_l1-supply = <&vph>;
- vdd_l2-supply = <&vph>;
- vdd_l3-supply = <&vph>;
- vdd_l4-supply = <&vph>;
- vdd_l5-supply = <&vph>;
- vdd_l6-supply = <&vph>;
- /* vdd_s0-supply, vdd_s1-supply: SAW regulators */
- vdd_s2-supply = <&vph>;
- vdd_s3-supply = <&vph>;
- vdd_s4-supply = <&vph>;
- lvs0_in-supply = <&pm8058_s3>;
- lvs1_in-supply = <&pm8901_s4>;
- lvs2_in-supply = <&pm8058_l0>;
- lvs3_in-supply = <&pm8058_s2>;
- mvs_in-supply = <&pm8058_s3>;
-
- l0 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
- l1 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- bias-pull-down;
- };
- l2 {
- /* TMA340 requires strictly 3.3V */
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- bias-pull-down;
- };
- l3 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- bias-pull-down;
- };
- l4 {
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <2600000>;
- bias-pull-down;
- };
- l5 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- bias-pull-down;
- };
- l6 {
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- bias-pull-down;
- };
-
- /* s0 and s1 are SAW regulators controlled over SPM */
- s2 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
- s3 {
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
- s4 {
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
-
- /* LVS0 thru 3 and mvs are just switches */
- lvs0 {
- regulator-always-on;
- };
- lvs1 { };
- lvs2 { };
- lvs3 { };
- mvs { };
+ /* LVS0 and LVS1 are just switches */
+ lvs0 {
+ bias-pull-down;
+ };
+ lvs1 {
+ bias-pull-down;
+ };
- };
+ ncp {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ };
+ };
+};
- pm8058-regulators {
- vdd_l0_l1_lvs-supply = <&pm8058_s3>;
- vdd_l2_l11_l12-supply = <&vph>;
- vdd_l3_l4_l5-supply = <&vph>;
- vdd_l6_l7-supply = <&vph>;
- vdd_l8-supply = <&vph>;
- vdd_l9-supply = <&vph>;
- vdd_l10-supply = <&vph>;
- vdd_l13_l16-supply = <&pm8058_s4>;
- vdd_l14_l15-supply = <&vph>;
- vdd_l17_l18-supply = <&vph>;
- vdd_l19_l20-supply = <&vph>;
- vdd_l21-supply = <&pm8058_s3>;
- vdd_l22-supply = <&pm8058_s3>;
- vdd_l23_l24_l25-supply = <&pm8058_s3>;
- vdd_s0-supply = <&vph>;
- vdd_s1-supply = <&vph>;
- vdd_s2-supply = <&vph>;
- vdd_s3-supply = <&vph>;
- vdd_s4-supply = <&vph>;
- vdd_ncp-supply = <&vph>;
-
- l0 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
- l1 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
- l2 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2600000>;
- bias-pull-down;
- };
- l3 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
- l4 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- bias-pull-down;
- };
- l5 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- bias-pull-down;
- };
- l6 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3600000>;
- bias-pull-down;
- };
- l7 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
- l8 {
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <3050000>;
- bias-pull-down;
- };
- l9 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
- l10 {
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <2600000>;
- bias-pull-down;
- };
- l11 {
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- bias-pull-down;
- };
- l12 {
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- bias-pull-down;
- };
- l13 {
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- bias-pull-down;
- };
- l14 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- };
- l15 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- bias-pull-down;
- };
- l16 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- regulator-always-on;
- };
- l17 {
- // 1.5V according to schematic
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <2600000>;
- bias-pull-down;
- };
- l18 {
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- bias-pull-down;
- };
- l19 {
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <2500000>;
- bias-pull-down;
- };
- l20 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
- l21 {
- // 1.1 V according to schematic
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- regulator-always-on;
- };
- l22 {
- // 1.2 V according to schematic
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- bias-pull-down;
- };
- l23 {
- // Unused
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
- l24 {
- // Unused
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
- l25 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
-
- s0 {
- // regulator-min-microvolt = <500000>;
- // regulator-max-microvolt = <1325000>;
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
- s1 {
- // regulator-min-microvolt = <500000>;
- // regulator-max-microvolt = <1250000>;
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
- s2 {
- // 1.3 V according to schematic
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1400000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
- s3 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <1600000>;
- regulator-always-on;
- bias-pull-down;
- };
- s4 {
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- qcom,switch-mode-frequency = <1600000>;
- regulator-always-on;
- bias-pull-down;
- };
-
- /* LVS0 and LVS1 are just switches */
- lvs0 {
- bias-pull-down;
- };
- lvs1 {
- bias-pull-down;
- };
-
- ncp {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <1600000>;
- };
- };
+/* Internal 3.69 GiB eMMC */
+&sdcc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc1_pins>;
+ vmmc-supply = <&pm8901_l5>;
+ vqmmc-supply = <&pm8901_lvs0>;
+ status = "okay";
+};
+
+/* External micro SD card, directly connected, pulled up to 2.85 V */
+&sdcc3 {
+ /* Enable SSBI GPIO 22 as input, use for card detect */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc3_pins>, <&dragon_sdcc3_gpios>;
+ cd-gpios = <&pm8058_gpio 22 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&pm8058_l14>;
+ status = "okay";
+};
+
+/*
+ * Second external micro SD card, using two TXB104RGYR levelshifters
+ * to lift from 1.8 V to 2.85 V
+ */
+&sdcc5 {
+ /* Enable SSBI GPIO 26 as input, use for card detect */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc5_pins>, <&dragon_sdcc5_gpios>;
+ cd-gpios = <&pm8058_gpio 26 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&tlmm 106 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&pm8058_l14>;
+ vqmmc-supply = <&dragon_vio_txb>;
+ status = "okay";
+};
+
+&tlmm {
+ /* eMMC pins, all 8 data lines connected */
+ dragon_sdcc1_pins: sdcc1-state {
+ clk-pins {
+ pins = "gpio167"; /* SDC1 CLK */
+ function = "sdc1";
+ drive-strength = <16>;
+ bias-disable;
};
- amba {
- /* Internal 3.69 GiB eMMC */
- mmc@12400000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc1_pins>;
- vmmc-supply = <&pm8901_l5>;
- vqmmc-supply = <&pm8901_lvs0>;
- };
+ cmd-pins {
+ pins = "gpio168"; /* SDC1 CMD */
+ function = "sdc1";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ data-pins {
+ /* SDC1 D0 to D7 */
+ pins = "gpio159", "gpio160", "gpio161", "gpio162",
+ "gpio163", "gpio164", "gpio165", "gpio166";
+ function = "sdc1";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
- /* External micro SD card, directly connected, pulled up to 2.85 V */
- mmc@12180000 {
- status = "okay";
- /* Enable SSBI GPIO 22 as input, use for card detect */
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc3_pins>, <&dragon_sdcc3_gpios>;
- cd-gpios = <&pm8058_gpio 22 GPIO_ACTIVE_LOW>;
- wp-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
- vmmc-supply = <&pm8058_l14>;
- };
+ /*
+ * The SDCC3 pins are hardcoded (non-muxable) but need some pin
+ * configuration.
+ */
+ dragon_sdcc3_pins: sdcc3-state {
+ clk-pins {
+ pins = "sdc3_clk";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ cmd-pins {
+ pins = "sdc3_cmd";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ data-pins {
+ pins = "sdc3_data";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
- /*
- * Second external micro SD card, using two TXB104RGYR levelshifters
- * to lift from 1.8 V to 2.85 V
- */
- mmc@12200000 {
- status = "okay";
- /* Enable SSBI GPIO 26 as input, use for card detect */
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc5_pins>, <&dragon_sdcc5_gpios>;
- cd-gpios = <&pm8058_gpio 26 GPIO_ACTIVE_LOW>;
- wp-gpios = <&tlmm 106 GPIO_ACTIVE_HIGH>;
- vmmc-supply = <&pm8058_l14>;
- vqmmc-supply = <&dragon_vio_txb>;
- };
+ /* Second SD card slot pins */
+ dragon_sdcc5_pins: sdcc5-state {
+ clk-pins {
+ pins = "gpio97"; /* SDC5 CLK */
+ function = "sdc5";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ cmd-pins {
+ pins = "gpio95"; /* SDC5 CMD */
+ function = "sdc5";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ data-pins {
+ /* SDC5 D0 to D3 */
+ pins = "gpio96", "gpio98", "gpio99", "gpio100";
+ function = "sdc5";
+ drive-strength = <10>;
+ bias-pull-up;
};
};
+
+ dragon_gsbi3_i2c_pins: gsbi3-i2c-state {
+ pins = "gpio43", "gpio44";
+ function = "gsbi3";
+ drive-strength = <8>;
+ /* These have external pull-up 2.2kOhm to 1.8V */
+ bias-disable;
+ };
+
+ dragon_gsbi8_i2c_pins: gsbi8-i2c-state {
+ pins = "gpio64", "gpio65";
+ function = "gsbi8";
+ drive-strength = <16>;
+ /* These have external pull-up 2.2kOhm to 1.8V */
+ bias-disable;
+ };
+
+ dragon_gsbi12_i2c_pins: gsbi12-i2c-state {
+ pins = "gpio115", "gpio116";
+ function = "gsbi12";
+ drive-strength = <16>;
+ /* These have external pull-up 4.7kOhm to 1.8V */
+ bias-disable;
+ };
+
+ /* Primary serial port uart 0 pins */
+ dragon_gsbi12_serial_pins: gsbi12-serial-state {
+ tx-pins {
+ pins = "gpio117";
+ function = "gsbi12";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ rx-pins {
+ pins = "gpio118";
+ function = "gsbi12";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ dragon_ebi2_pins: ebi2-state {
+ /*
+ * Pins used by EBI2 on the Dragonboard, actually only
+ * CS2 is used by a real peripheral. CS0 is just
+ * routed to a test point.
+ */
+ mux0-pins {
+ pins =
+ /* "gpio39", CS1A_N this is not good to mux */
+ "gpio40", /* CS2A_N */
+ "gpio134"; /* CS0_N testpoint TP29 */
+ function = "ebi2cs";
+ };
+ mux1-pins {
+ pins =
+ /* EBI2_ADDR_7 downto EBI2_ADDR_0 address bus */
+ "gpio123", "gpio124", "gpio125", "gpio126",
+ "gpio127", "gpio128", "gpio129", "gpio130",
+ /* EBI2_DATA_15 downto EBI2_DATA_0 data bus */
+ "gpio135", "gpio136", "gpio137", "gpio138",
+ "gpio139", "gpio140", "gpio141", "gpio142",
+ "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150",
+ "gpio151", /* EBI2_OE_N */
+ "gpio153", /* EBI2_ADV */
+ "gpio157"; /* EBI2_WE_N */
+ function = "ebi2";
+ };
+ };
+
+ /* Interrupt line for the KXSD9 accelerometer */
+ dragon_kxsd9_gpios: kxsd9-state {
+ pins = "gpio57"; /* IRQ line */
+ function = "gpio";
+ bias-pull-up;
+ };
+
+ dragon_tma340_gpios: tma340-state {
+ reset-pins {
+ /* RESET line, TS_ATTN, WAKE_CTP */
+ pins = "gpio58";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ irq-pins {
+ pins = "gpio61"; /* IRQ line */
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+};
+
+&xoadc {
+ /* Reference voltage 2.2 V */
+ xoadc-ref-supply = <&pm8058_l18>;
+
+ /* Board-specific channels */
+ mpp5@5 {
+ /* Connected to AOUT of ALS sensor */
+ reg = <0x00 0x05>;
+ };
+ mpp6@6 {
+ /* Connected to test point TP43 */
+ reg = <0x00 0x06>;
+ };
+ mpp7@7 {
+ /* Connected to battery thermistor */
+ reg = <0x00 0x07>;
+ };
+ mpp8@8 {
+ /* Connected to battery ID detector */
+ reg = <0x00 0x08>;
+ };
+ mpp9@9 {
+ /* Connected to XO thermistor */
+ reg = <0x00 0x09>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
index fee278e32cb6..bf2fb0f70fe4 100644
--- a/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
@@ -6,6 +6,7 @@
/ {
model = "Asus Nexus7(flo)";
compatible = "asus,nexus7-flo", "qcom,apq8064";
+ chassis-type = "tablet";
aliases {
serial0 = &gsbi7_serial;
@@ -30,7 +31,7 @@
};
};
- ext_3p3v: regulator-fixed@1 {
+ ext_3p3v: regulator-ext-3p3v {
compatible = "regulator-fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
@@ -57,302 +58,291 @@
};
soc {
- rpm@108000 {
- regulators {
- vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
- vin_lvs1_3_6-supply = <&pm8921_s4>;
- vin_lvs4_5_7-supply = <&pm8921_s4>;
-
-
- vdd_l24-supply = <&pm8921_s1>;
- vdd_l25-supply = <&pm8921_s1>;
- vin_lvs2-supply = <&pm8921_s1>;
-
- vdd_l26-supply = <&pm8921_s7>;
- vdd_l27-supply = <&pm8921_s7>;
- vdd_l28-supply = <&pm8921_s7>;
-
- vdd_ncp-supply = <&pm8921_l6>;
-
- /* Buck SMPS */
- s1 {
- regulator-always-on;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,switch-mode-frequency = <3200000>;
- bias-pull-down;
- };
-
- /* msm otg HSUSB_VDDCX */
- s3 {
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <1150000>;
- qcom,switch-mode-frequency = <4800000>;
- };
-
- /*
- * msm_sdcc.1-sdc-vdd_io
- * tabla2x-slim-CDC_VDDA_RX
- * tabla2x-slim-CDC_VDDA_TX
- * tabla2x-slim-CDC_VDD_CP
- * tabla2x-slim-VDDIO_CDC
- */
- s4 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <3200000>;
- regulator-always-on;
- };
-
- s7 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- /* mipi_dsi.1-dsi1_pll_vdda */
- l2 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- /* msm_otg-HSUSB_3p3 */
- l3 {
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- bias-pull-down;
- };
-
- /* msm_otg-HSUSB_1p8 */
- l4 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- /* msm_sdcc.1-sdc_vdd */
- l5 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- regulator-always-on;
- bias-pull-down;
- };
-
- l6 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- };
-
- /* mipi_dsi.1-dsi1_avdd */
- l11 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- bias-pull-down;
- regulator-always-on;
- };
-
- /* pwm_power for backlight */
- l17 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- /* camera, qdsp6 */
- l23 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- /*
- * tabla2x-slim-CDC_VDDA_A_1P2V
- * tabla2x-slim-VDDD_CDC_D
- */
- l25 {
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <1250000>;
- bias-pull-down;
- };
-
- lvs1 {
- bias-pull-down;
- };
-
- lvs4 {
- bias-pull-down;
- };
-
- lvs5 {
- bias-pull-down;
- };
-
- lvs6 {
- bias-pull-down;
- };
- /*
- * mipi_dsi.1-dsi1_vddio
- * pil_riva-pll_vdd
- */
- lvs7 {
- bias-pull-down;
- };
- };
- };
+ sram@2a03f000 {
+ compatible = "qcom,apq8064-imem", "syscon", "simple-mfd";
+ reg = <0x2a03f000 0x1000>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x65c>;
- mdp@5100000 {
- status = "okay";
- ports {
- port@1 {
- mdp_dsi1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
- };
- };
+ mode-normal = <0x77665501>;
+ mode-bootloader = <0x77665500>;
+ mode-recovery = <0x77665502>;
};
};
+ };
+};
- dsi0: dsi@4700000 {
- status = "okay";
- vdda-supply = <&pm8921_l2>;/*VDD_MIPI1 to 4*/
- vdd-supply = <&pm8921_l8>;
- vddio-supply = <&pm8921_lvs7>;
- avdd-supply = <&pm8921_l11>;
-
- panel@0 {
- reg = <0>;
- compatible = "jdi,lt070me05000";
-
- vddp-supply = <&pm8921_l17>;
- iovcc-supply = <&pm8921_lvs7>;
-
- enable-gpios = <&pm8921_gpio 36 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_LOW>;
- dcdc-en-gpios = <&pm8921_gpio 23 GPIO_ACTIVE_HIGH>;
-
- port {
- panel_in: endpoint {
- remote-endpoint = <&dsi0_out>;
- };
- };
- };
- ports {
- port@0 {
- dsi0_in: endpoint {
- remote-endpoint = <&mdp_dsi1_out>;
- };
- };
-
- port@1 {
- dsi0_out: endpoint {
- remote-endpoint = <&panel_in>;
- data-lanes = <0 1 2 3>;
- };
- };
+&dsi0 {
+ vdda-supply = <&pm8921_l2>;/*VDD_MIPI1 to 4*/
+ vdd-supply = <&pm8921_l8>;
+ vddio-supply = <&pm8921_lvs7>;
+ avdd-supply = <&pm8921_l11>;
+ status = "okay";
+
+ panel@0 {
+ reg = <0>;
+ compatible = "jdi,lt070me05000";
+
+ vddp-supply = <&pm8921_l17>;
+ iovcc-supply = <&pm8921_lvs7>;
+
+ enable-gpios = <&pm8921_gpio 36 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_LOW>;
+ dcdc-en-gpios = <&pm8921_gpio 23 GPIO_ACTIVE_HIGH>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
};
};
+ };
+};
+
+&dsi0_in {
+ remote-endpoint = <&mdp_dsi1_out>;
+};
+
+&dsi0_out {
+ remote-endpoint = <&panel_in>;
+ data-lanes = <0 1 2 3>;
+};
+
+&dsi0_phy {
+ vddio-supply = <&pm8921_lvs7>;/*VDD_PLL2_1 to 7*/
+ status = "okay";
+};
+
+&gsbi1 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
+
+&gsbi1_i2c {
+ status = "okay";
+ clock-frequency = <200000>;
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "default";
+
+ eeprom@52 {
+ compatible = "atmel,24c128";
+ reg = <0x52>;
+ pagesize = <32>;
+ };
+
+ bq27541@55 {
+ compatible = "ti,bq27541";
+ reg = <0x55>;
+ };
+
+};
+
+&gsbi3 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
+
+&gsbi3_i2c {
+ clock-frequency = <200000>;
+ pinctrl-0 = <&i2c3_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ trackpad@10 {
+ compatible = "elan,ekth3500";
+ reg = <0x10>;
+ interrupt-parent = <&tlmm_pinmux>;
+ interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+&gsbi6 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
+
+&gsbi6_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi6_uart_4pins>;
+ status = "okay";
+};
- dsi-phy@4700200 {
- status = "okay";
- vddio-supply = <&pm8921_lvs7>;/*VDD_PLL2_1 to 7*/
+&gsbi7 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
+
+&gsbi7_serial {
+ status = "okay";
+};
+
+&mdp {
+ status = "okay";
+};
+
+/* eMMC */
+&sdcc1 {
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+ status = "okay";
+};
+
+&mdp_dsi1_out {
+ remote-endpoint = <&dsi0_in>;
+};
+
+&rpm {
+ regulators {
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vin_lvs2-supply = <&pm8921_s1>;
+
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
+ vdd_ncp-supply = <&pm8921_l6>;
+
+ /* Buck SMPS */
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
};
- gsbi@16200000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
- i2c@16280000 {
- status = "okay";
- clock-frequency = <200000>;
- pinctrl-0 = <&i2c3_pins>;
- pinctrl-names = "default";
-
- trackpad@10 {
- compatible = "elan,ekth3500";
- reg = <0x10>;
- interrupt-parent = <&tlmm_pinmux>;
- interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
- };
- };
+ /* msm otg HSUSB_VDDCX */
+ s3 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,switch-mode-frequency = <4800000>;
};
+ /*
+ * msm_sdcc.1-sdc-vdd_io
+ * tabla2x-slim-CDC_VDDA_RX
+ * tabla2x-slim-CDC_VDDA_TX
+ * tabla2x-slim-CDC_VDD_CP
+ * tabla2x-slim-VDDIO_CDC
+ */
+ s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <3200000>;
+ regulator-always-on;
+ };
- gsbi@12440000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
- i2c@12460000 {
- status = "okay";
- clock-frequency = <200000>;
- pinctrl-0 = <&i2c1_pins>;
- pinctrl-names = "default";
+ /* mipi_dsi.1-dsi1_pll_vdda */
+ l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
- eeprom@52 {
- compatible = "atmel,24c128";
- reg = <0x52>;
- pagesize = <32>;
- };
+ /* msm_otg-HSUSB_3p3 */
+ l3 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ bias-pull-down;
+ };
- bq27541@55 {
- compatible = "ti,bq27541";
- reg = <0x55>;
- };
+ /* msm_otg-HSUSB_1p8 */
+ l4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
- };
+ /* msm_sdcc.1-sdc_vdd */
+ l5 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-always-on;
+ bias-pull-down;
};
- gsbi@16500000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
+ l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
- serial@16540000 {
- status = "okay";
+ /* mipi_dsi.1-dsi1_avdd */
+ l11 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
- pinctrl-names = "default";
- pinctrl-0 = <&gsbi6_uart_4pins>;
- };
+ /* pwm_power for backlight */
+ l17 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
};
- gsbi@16600000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
- serial@16640000 {
- status = "okay";
- };
+ /* camera, qdsp6 */
+ l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
};
- /* OTG */
- usb@12500000 {
- status = "okay";
- dr_mode = "otg";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l4>;
- };
- };
+ /*
+ * tabla2x-slim-CDC_VDDA_A_1P2V
+ * tabla2x-slim-VDDD_CDC_D
+ */
+ l25 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ bias-pull-down;
};
- amba {
- /* eMMC */
- mmc@12400000 {
- status = "okay";
- vmmc-supply = <&pm8921_l5>;
- vqmmc-supply = <&pm8921_s4>;
- };
+ lvs1 {
+ bias-pull-down;
};
- sram@2a03f000 {
- compatible = "qcom,apq8064-imem", "syscon", "simple-mfd";
- reg = <0x2a03f000 0x1000>;
+ lvs4 {
+ bias-pull-down;
+ };
- reboot-mode {
- compatible = "syscon-reboot-mode";
- offset = <0x65c>;
+ lvs5 {
+ bias-pull-down;
+ };
- mode-normal = <0x77665501>;
- mode-bootloader = <0x77665500>;
- mode-recovery = <0x77665502>;
- };
+ lvs6 {
+ bias-pull-down;
+ };
+ /*
+ * mipi_dsi.1-dsi1_vddio
+ * pil_riva-pll_vdd
+ */
+ lvs7 {
+ bias-pull-down;
};
};
};
+
+&usb_hs1_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+};
+
+/* OTG */
+&usb1 {
+ dr_mode = "otg";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
index 529629a0a9dc..d6ecfd8addb7 100644
--- a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
@@ -15,232 +15,216 @@
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>;
- };
+ sdcc4_pwrseq: pwrseq-sdcc4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_default_gpios>;
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pm8921_gpio 43 GPIO_ACTIVE_LOW>;
};
- soc {
- pinctrl@800000 {
- card_detect: card_detect {
- mux {
- pins = "gpio26";
- function = "gpio";
- bias-disable;
- };
- };
-
- pcie_pins: pcie_pinmux {
- mux {
- pins = "gpio27";
- function = "gpio";
- };
- conf {
- pins = "gpio27";
- drive-strength = <12>;
- bias-disable;
- };
- };
- };
+ /* on board fixed 3.3v supply */
+ v3p3_fixed: regulator-v3p3 {
+ compatible = "regulator-fixed";
+ regulator-name = "PCIE V3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+};
- rpm@108000 {
- regulators {
- vin_lvs1_3_6-supply = <&pm8921_s4>;
- vin_lvs2-supply = <&pm8921_s1>;
- vin_lvs4_5_7-supply = <&pm8921_s4>;
-
- vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
- vdd_l24-supply = <&pm8921_s1>;
- vdd_l25-supply = <&pm8921_s1>;
- vdd_l26-supply = <&pm8921_s7>;
- vdd_l27-supply = <&pm8921_s7>;
- vdd_l28-supply = <&pm8921_s7>;
-
-
- /* Buck SMPS */
- s1 {
- regulator-always-on;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,switch-mode-frequency = <3200000>;
- bias-pull-down;
- };
-
- s3 {
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1400000>;
- qcom,switch-mode-frequency = <4800000>;
- };
-
- s4 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- s7 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- l3 {
- regulator-min-microvolt = <3050000>;
- regulator-max-microvolt = <3300000>;
- bias-pull-down;
- };
-
- l4 {
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- l5 {
- regulator-min-microvolt = <2750000>;
- regulator-max-microvolt = <3000000>;
- bias-pull-down;
- };
-
- l23 {
- regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <1900000>;
- bias-pull-down;
- };
-
- pm8921_lvs6: lvs6 {
- bias-pull-down;
- };
-
- };
- };
+&gsbi1 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
- gsbi@12440000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
+&gsbi1_i2c {
+ clock-frequency = <200000>;
+ status = "okay";
- i2c@12460000 {
- status = "okay";
- clock-frequency = <200000>;
+ eeprom@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <32>;
+ };
+};
+
+&gsbi7 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
- eeprom@50 {
- compatible = "atmel,24c02";
- reg = <0x50>;
- pagesize = <32>;
- };
- };
+&gsbi7_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi7_uart_2pins>;
+ status = "okay";
+};
+
+&pcie {
+ vdda-supply = <&pm8921_s3>;
+ vdda_phy-supply = <&pm8921_lvs6>;
+ vdda_refclk-supply = <&v3p3_fixed>;
+ pinctrl-0 = <&pcie_pins>;
+ pinctrl-names = "default";
+ perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&pm8921_gpio {
+ wlan_default_gpios: wlan-gpios-state {
+ pinconf {
+ pins = "gpio43";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
};
+ };
+};
+
+&rpm {
+ regulators {
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs2-supply = <&pm8921_s1>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
- gsbi@16600000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
- serial@16640000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&gsbi7_uart_2pins>;
- };
+ /* Buck SMPS */
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
};
- /* OTG */
- usb@12500000 {
- status = "okay";
- dr_mode = "otg";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l4>;
- };
- };
+ s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <4800000>;
};
- usb@12520000 {
- status = "okay";
- dr_mode = "host";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l23>;
- };
- };
+ s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <3200000>;
};
- usb@12530000 {
- status = "okay";
- dr_mode = "host";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l23>;
- };
- };
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
};
- /* on board fixed 3.3v supply */
- v3p3_fixed: v3p3 {
- compatible = "regulator-fixed";
- regulator-name = "PCIE V3P3";
- regulator-min-microvolt = <3300000>;
+ l3 {
+ regulator-min-microvolt = <3050000>;
regulator-max-microvolt = <3300000>;
- regulator-always-on;
+ bias-pull-down;
+ };
+
+ l4 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l5 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
};
- qcom,ssbi@500000 {
- pmic@0 {
- gpio@150 {
- wlan_default_gpios: wlan-gpios-state {
- pinconf {
- pins = "gpio43";
- function = "normal";
- bias-disable;
- power-source = <PM8921_GPIO_S4>;
- };
- };
- };
- };
+ l23 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ bias-pull-down;
};
- pci@1b500000 {
- status = "okay";
- vdda-supply = <&pm8921_s3>;
- vdda_phy-supply = <&pm8921_lvs6>;
- vdda_refclk-supply = <&v3p3_fixed>;
- pinctrl-0 = <&pcie_pins>;
- pinctrl-names = "default";
- perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>;
+ lvs6 {
+ bias-pull-down;
};
- amba {
- /* eMMC */
- sdcc1: mmc@12400000 {
- status = "okay";
- vmmc-supply = <&pm8921_l5>;
- vqmmc-supply = <&pm8921_s4>;
- };
-
- /* External micro SD card */
- sdcc3: mmc@12180000 {
- status = "okay";
- vmmc-supply = <&v3p3_fixed>;
- pinctrl-names = "default";
- pinctrl-0 = <&card_detect>;
- cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
- };
- /* WLAN */
- sdcc4: mmc@121c0000 {
- status = "okay";
- vmmc-supply = <&v3p3_fixed>;
- vqmmc-supply = <&v3p3_fixed>;
- mmc-pwrseq = <&sdcc4_pwrseq>;
- };
+ };
+};
+
+/* eMMC */
+&sdcc1 {
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+ status = "okay";
+};
+
+/* External micro SD card */
+&sdcc3 {
+ vmmc-supply = <&v3p3_fixed>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&card_detect>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+/* WLAN */
+&sdcc4 {
+ status = "okay";
+ vmmc-supply = <&v3p3_fixed>;
+ vqmmc-supply = <&v3p3_fixed>;
+ mmc-pwrseq = <&sdcc4_pwrseq>;
+};
+
+&tlmm_pinmux {
+ card_detect: card_detect {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ bias-disable;
+ };
+ };
+
+ pcie_pins: pcie_pinmux {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+ conf {
+ pins = "gpio27";
+ drive-strength = <12>;
+ bias-disable;
};
};
};
+
+&usb_hs1_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+};
+
+&usb_hs3_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+};
+
+&usb_hs4_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+};
+
+/* OTG */
+&usb1 {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb3 {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb4 {
+ dr_mode = "host";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index a7f90217661b..96307550523a 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -22,23 +22,12 @@
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 {
+ led-user1 {
label = "apq8064:green:user1";
color = <LED_COLOR_ID_GREEN>;
gpios = <&pm8921_gpio 18 GPIO_ACTIVE_HIGH>;
@@ -57,326 +46,314 @@
};
};
- soc {
- pinctrl@800000 {
- card_detect: card_detect {
- mux {
- pins = "gpio26";
- function = "gpio";
- bias-disable;
- };
- };
+ sdcc4_pwrseq: pwrseq-sdcc4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_default_gpios>;
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pm8921_gpio 43 GPIO_ACTIVE_LOW>;
+ };
- pcie_pins: pcie_pinmux {
- mux {
- pins = "gpio27";
- function = "gpio";
- };
- conf {
- pins = "gpio27";
- drive-strength = <12>;
- bias-disable;
- };
- };
- };
+ ext_3p3v: regulator-ext-3p3v {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "ext_3p3v";
+ regulator-type = "voltage";
+ startup-delay-us = <0>;
+ gpio = <&tlmm_pinmux 77 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+};
- rpm@108000 {
- regulators {
- vin_lvs1_3_6-supply = <&pm8921_s4>;
- vin_lvs2-supply = <&pm8921_s1>;
- vin_lvs4_5_7-supply = <&pm8921_s4>;
-
- vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
- vdd_l24-supply = <&pm8921_s1>;
- vdd_l25-supply = <&pm8921_s1>;
- vdd_l26-supply = <&pm8921_s7>;
- vdd_l27-supply = <&pm8921_s7>;
- vdd_l28-supply = <&pm8921_s7>;
-
-
- /* Buck SMPS */
- s1 {
- regulator-always-on;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,switch-mode-frequency = <3200000>;
- bias-pull-down;
- };
-
- s3 {
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1400000>;
- qcom,switch-mode-frequency = <4800000>;
- };
-
- s4 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- s7 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- l3 {
- regulator-min-microvolt = <3050000>;
- regulator-max-microvolt = <3300000>;
- bias-pull-down;
- };
-
- l4 {
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- l5 {
- regulator-min-microvolt = <2750000>;
- regulator-max-microvolt = <3000000>;
- bias-pull-down;
- };
-
- l6 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- bias-pull-down;
- };
-
- l23 {
- regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <1900000>;
- bias-pull-down;
- };
-
- lvs1 {
- bias-pull-down;
- };
-
- lvs6 {
- bias-pull-down;
- };
- };
- };
+&gsbi1 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
- ext_3p3v: regulator-fixed@1 {
- compatible = "regulator-fixed";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "ext_3p3v";
- regulator-type = "voltage";
- startup-delay-us = <0>;
- gpio = <&tlmm_pinmux 77 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- regulator-boot-on;
- };
+&gsbi1_i2c {
+ clock-frequency = <200000>;
+ status = "okay";
- gsbi3: gsbi@16200000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
- i2c@16280000 {
- status = "okay";
- };
- };
+ eeprom@52 {
+ compatible = "atmel,24c128";
+ reg = <0x52>;
+ pagesize = <32>;
+ };
+};
- gsbi@16300000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
- /* CAM I2C MIPI-CSI connector */
- i2c@16380000 {
- status = "okay";
- };
- };
+&gsbi3 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
+
+&gsbi3_i2c {
+ status = "okay";
+};
- gsbi@12440000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C>;
+&gsbi4 {
+ qcom,mode = <GSBI_PROT_I2C>;
+ status = "okay";
+};
- i2c@12460000 {
- status = "okay";
- clock-frequency = <200000>;
+/* CAM I2C MIPI-CSI connector */
+&gsbi4_i2c {
+ status = "okay";
+};
- eeprom@52 {
- compatible = "atmel,24c128";
- reg = <0x52>;
- pagesize = <32>;
- };
- };
- };
+&gsbi5 {
+ qcom,mode = <GSBI_PROT_SPI>;
+ status = "okay";
+};
- gsbi@1a200000 {
- qcom,mode = <GSBI_PROT_SPI>;
- status = "okay";
- spi4: spi@1a280000 {
- status = "okay";
- num-cs = <1>;
- cs-gpios = <&tlmm_pinmux 53 0>;
- };
- };
+&gsbi5_spi {
+ num-cs = <1>;
+ cs-gpios = <&tlmm_pinmux 53 0>;
+ status = "okay";
+};
+
+&gsbi6 {
+ qcom,mode = <GSBI_PROT_UART_W_FC>;
+ status = "okay";
+};
- gsbi@16500000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_UART_W_FC>;
+&gsbi6_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi6_uart_4pins>;
+ status = "okay";
+};
- serial@16540000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&gsbi6_uart_4pins>;
- };
+&gsbi7 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
+
+&gsbi7_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi7_uart_2pins>;
+ status = "okay";
+};
+
+&hdmi {
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+ hpd-gpios = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&hdmi_in {
+ remote-endpoint = <&mdp_dtv_out>;
+};
+
+&hdmi_out {
+ remote-endpoint = <&hdmi_con>;
+};
+
+&hdmi_phy {
+ status = "okay";
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+};
+
+&mdp {
+ status = "okay";
+};
+
+&mdp_dtv_out {
+ remote-endpoint = <&hdmi_in>;
+};
+
+&pcie {
+ status = "okay";
+ vdda-supply = <&pm8921_s3>;
+ vdda_phy-supply = <&pm8921_lvs6>;
+ vdda_refclk-supply = <&ext_3p3v>;
+ pinctrl-0 = <&pcie_pins>;
+ pinctrl-names = "default";
+ perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>;
+};
+
+&pm8921_gpio {
+ wlan_default_gpios: wlan-gpios-state {
+ pinconf {
+ pins = "gpio43";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
};
+ };
- gsbi@16600000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
- serial@16640000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&gsbi7_uart_2pins>;
- };
+ notify_led: nled-state {
+ pinconf {
+ pins = "gpio18";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
};
+ };
+};
- sata_phy0: phy@1b400000 {
- status = "okay";
+&rpm {
+ regulators {
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs2-supply = <&pm8921_s1>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
+
+ /* Buck SMPS */
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
};
- sata0: sata@29000000 {
- status = "okay";
- target-supply = <&pm8921_s4>;
+ s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <4800000>;
};
- /* OTG */
- usb@12500000 {
- status = "okay";
- dr_mode = "otg";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l4>;
- };
- };
+ s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <3200000>;
};
- usb@12520000 {
- status = "okay";
- dr_mode = "host";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l23>;
- };
- };
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
};
- usb@12530000 {
- status = "okay";
- dr_mode = "host";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l23>;
- };
- };
+ l3 {
+ regulator-min-microvolt = <3050000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
};
- pci@1b500000 {
- status = "okay";
- vdda-supply = <&pm8921_s3>;
- vdda_phy-supply = <&pm8921_lvs6>;
- vdda_refclk-supply = <&ext_3p3v>;
- pinctrl-0 = <&pcie_pins>;
- pinctrl-names = "default";
- perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>;
+ l4 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
};
- qcom,ssbi@500000 {
- pmic@0 {
- gpio@150 {
- wlan_default_gpios: wlan-gpios-state {
- pinconf {
- pins = "gpio43";
- function = "normal";
- bias-disable;
- power-source = <PM8921_GPIO_S4>;
- };
- };
-
- notify_led: nled-state {
- pinconf {
- pins = "gpio18";
- function = "normal";
- bias-disable;
- power-source = <PM8921_GPIO_S4>;
- };
- };
- };
- };
+ l5 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
};
- amba {
- /* eMMC */
- sdcc1: mmc@12400000 {
- status = "okay";
- vmmc-supply = <&pm8921_l5>;
- vqmmc-supply = <&pm8921_s4>;
- };
+ l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
- /* External micro SD card */
- sdcc3: mmc@12180000 {
- status = "okay";
- vmmc-supply = <&pm8921_l6>;
- pinctrl-names = "default";
- pinctrl-0 = <&card_detect>;
- cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
- };
- /* WLAN */
- sdcc4: mmc@121c0000 {
- status = "okay";
- vmmc-supply = <&ext_3p3v>;
- vqmmc-supply = <&pm8921_lvs1>;
- mmc-pwrseq = <&sdcc4_pwrseq>;
- };
+ l23 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ bias-pull-down;
};
- hdmi-tx@4a00000 {
- status = "okay";
+ lvs1 {
+ bias-pull-down;
+ };
- core-vdda-supply = <&pm8921_hdmi_switch>;
+ lvs6 {
+ bias-pull-down;
+ };
+ };
+};
- hpd-gpios = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
+&sata_phy0 {
+ status = "okay";
+};
- ports {
- port@0 {
- endpoint {
- remote-endpoint = <&mdp_dtv_out>;
- };
- };
+&sata0 {
+ target-supply = <&pm8921_s4>;
+ status = "okay";
+};
- port@1 {
- endpoint {
- remote-endpoint = <&hdmi_con>;
- };
- };
- };
- };
+/* eMMC */
+&sdcc1 {
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+ status = "okay";
+};
- hdmi-phy@4a00400 {
- status = "okay";
+/* External micro SD card */
+&sdcc3 {
+ vmmc-supply = <&pm8921_l6>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&card_detect>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
- core-vdda-supply = <&pm8921_hdmi_switch>;
- };
+/* WLAN */
+&sdcc4 {
+ vmmc-supply = <&ext_3p3v>;
+ vqmmc-supply = <&pm8921_lvs1>;
+ mmc-pwrseq = <&sdcc4_pwrseq>;
+ status = "okay";
+};
- mdp@5100000 {
- status = "okay";
+&tlmm_pinmux {
+ card_detect: card_detect {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ bias-disable;
+ };
+ };
- ports {
- port@3 {
- endpoint {
- remote-endpoint = <&hdmi_in>;
- };
- };
- };
+ pcie_pins: pcie_pinmux {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+ conf {
+ pins = "gpio27";
+ drive-strength = <12>;
+ bias-disable;
};
};
};
+
+&usb_hs1_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+};
+
+&usb_hs3_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+};
+
+&usb_hs4_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+};
+
+/* OTG */
+&usb1 {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb3 {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb4 {
+ dr_mode = "host";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts
index c07c5474750d..9244512b74d1 100644
--- a/arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts
@@ -8,6 +8,7 @@
/ {
model = "Sony Xperia Z";
compatible = "sony,xperia-yuga", "qcom,apq8064";
+ chassis-type = "handset";
aliases {
serial0 = &gsbi5_serial;
@@ -51,351 +52,338 @@
linux,code = <KEY_VOLUMEUP>;
};
};
+};
+
+&gsbi5 {
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ status = "okay";
+};
+
+&gsbi5_serial {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi5_uart_pin_a>;
+ status = "okay";
+};
+
+&pm8921_gpio {
+ gpio_keys_pin_a: gpio-keys-active-state {
+ pins = "gpio3", "gpio4", "gpio29", "gpio35";
+ function = "normal";
+
+ bias-pull-up;
+ drive-push-pull;
+ input-enable;
+ power-source = <2>;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+ qcom,pull-up-strength = <0>;
+ };
+};
+
+&riva {
+ pinctrl-names = "default";
+ pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>;
+ status = "okay";
+};
+
+&rpm {
+ regulators {
+ vin_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vin_lvs_1_3_6-supply = <&pm8921_s4>;
+ vin_lvs_4_5_7-supply = <&pm8921_s4>;
+ vin_ncp-supply = <&pm8921_l6>;
+ vin_lvs2-supply = <&pm8921_s4>;
+ vin_l24-supply = <&pm8921_s1>;
+ vin_l25-supply = <&pm8921_s1>;
+ vin_l27-supply = <&pm8921_s7>;
+ vin_l28-supply = <&pm8921_s7>;
+
+ /* Buck SMPS */
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
+ };
+
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+
+ s3 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,switch-mode-frequency = <4800000>;
+ bias-pull-down;
+ };
+
+ s4 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ qcom,force-mode = <QCOM_RPM_FORCE_MODE_AUTO>;
+ };
+
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ s8 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ qcom,switch-mode-frequency = <1600000>;
+ };
+
+ /* PMOS LDO */
+ l1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ bias-pull-down;
+ };
- soc {
- pinctrl@800000 {
- gsbi5_uart_pin_a: gsbi5-uart-pin-active {
- rx {
- pins = "gpio52";
- function = "gsbi5";
- drive-strength = <2>;
- bias-pull-up;
- };
-
- tx {
- pins = "gpio51";
- function = "gsbi5";
- drive-strength = <4>;
- bias-disable;
- };
- };
-
-
- sdcc3_cd_pin_a: sdcc3-cd-pin-active {
- pins = "gpio26";
- function = "gpio";
-
- drive-strength = <2>;
- bias-disable;
- };
- };
-
-
- rpm@108000 {
- regulators {
- vin_l1_l2_l12_l18-supply = <&pm8921_s4>;
- vin_lvs_1_3_6-supply = <&pm8921_s4>;
- vin_lvs_4_5_7-supply = <&pm8921_s4>;
- vin_ncp-supply = <&pm8921_l6>;
- vin_lvs2-supply = <&pm8921_s4>;
- vin_l24-supply = <&pm8921_s1>;
- vin_l25-supply = <&pm8921_s1>;
- vin_l27-supply = <&pm8921_s7>;
- vin_l28-supply = <&pm8921_s7>;
-
- /* Buck SMPS */
- s1 {
- regulator-always-on;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,switch-mode-frequency = <3200000>;
- bias-pull-down;
- };
-
- s2 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- };
-
- s3 {
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <1150000>;
- qcom,switch-mode-frequency = <4800000>;
- bias-pull-down;
- };
-
- s4 {
- regulator-always-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <1600000>;
- bias-pull-down;
- qcom,force-mode = <QCOM_RPM_FORCE_MODE_AUTO>;
- };
-
- s7 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,switch-mode-frequency = <3200000>;
- };
-
- s8 {
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- qcom,switch-mode-frequency = <1600000>;
- };
-
- /* PMOS LDO */
- l1 {
- regulator-always-on;
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- bias-pull-down;
- };
-
- l2 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
-
- l3 {
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- bias-pull-down;
- };
-
- l4 {
- regulator-always-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- l5 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- bias-pull-down;
- };
-
- l6 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- bias-pull-down;
- };
-
- l7 {
- regulator-min-microvolt = <1850000>;
- regulator-max-microvolt = <2950000>;
- bias-pull-down;
- };
-
- l8 {
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- bias-pull-down;
- };
-
- l9 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- bias-pull-down;
- };
-
- l10 {
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- bias-pull-down;
- };
-
- l11 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- bias-pull-down;
- };
-
- l12 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
-
- l14 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- l15 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- bias-pull-down;
- };
-
- l16 {
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- bias-pull-down;
- };
-
- l17 {
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- bias-pull-down;
- };
-
- l18 {
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- bias-pull-down;
- };
-
- l21 {
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- bias-pull-down;
- };
-
- l22 {
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <2600000>;
- bias-pull-down;
- };
-
- l23 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- bias-pull-down;
- };
-
- l24 {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1150000>;
- bias-pull-down;
- };
-
- l25 {
- regulator-always-on;
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <1250000>;
- bias-pull-down;
- };
-
- l27 {
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- };
-
- l28 {
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- bias-pull-down;
- };
-
- l29 {
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- bias-pull-down;
- };
-
- /* Low Voltage Switch */
- lvs1 {
- bias-pull-down;
- };
-
- lvs2 {
- bias-pull-down;
- };
-
- lvs3 {
- bias-pull-down;
- };
-
- lvs4 {
- bias-pull-down;
- };
-
- lvs5 {
- bias-pull-down;
- };
-
- lvs6 {
- bias-pull-down;
- };
-
- lvs7 {
- bias-pull-down;
- };
-
- usb-switch {};
-
- hdmi-switch {};
-
- ncp {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,switch-mode-frequency = <1600000>;
- };
- };
- };
-
- qcom,ssbi@500000 {
- pmic@0 {
- gpio@150 {
- gpio_keys_pin_a: gpio-keys-active-state {
- pins = "gpio3", "gpio4", "gpio29", "gpio35";
- function = "normal";
-
- bias-pull-up;
- drive-push-pull;
- input-enable;
- power-source = <2>;
- qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
- qcom,pull-up-strength = <0>;
- };
- };
- };
- };
-
- usb@12500000 {
- status = "okay";
- dr_mode = "otg";
- ulpi {
- phy {
- v3p3-supply = <&pm8921_l3>;
- v1p8-supply = <&pm8921_l4>;
- };
- };
+ l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
};
- gsbi@1a200000 {
- status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
+ l3 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ bias-pull-down;
+ };
+
+ l4 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l5 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l8 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ bias-pull-down;
+ };
+
+ l9 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ };
+
+ l10 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ bias-pull-down;
+ };
- serial@1a240000 {
- status = "okay";
+ l11 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ };
+
+ l12 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
- pinctrl-names = "default";
- pinctrl-0 = <&gsbi5_uart_pin_a>;
- };
+ l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
};
- amba {
- sdcc1: mmc@12400000 {
- status = "okay";
+ l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
- vmmc-supply = <&pm8921_l5>;
- vqmmc-supply = <&pm8921_s4>;
- };
+ l16 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ bias-pull-down;
+ };
- sdcc3: mmc@12180000 {
- status = "okay";
+ l17 {
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ bias-pull-down;
+ };
- vmmc-supply = <&pm8921_l6>;
- cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+ l18 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
- pinctrl-names = "default";
- pinctrl-0 = <&sdcc3_pins>, <&sdcc3_cd_pin_a>;
- };
+ l21 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ bias-pull-down;
};
- riva-pil@3204000 {
- status = "okay";
+ l22 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
- pinctrl-names = "default";
- pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>;
+ l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l24 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1150000>;
+ bias-pull-down;
+ };
+
+ l25 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ bias-pull-down;
+ };
+
+ l27 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ l28 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ bias-pull-down;
+ };
+
+ l29 {
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ bias-pull-down;
+ };
+
+ /* Low Voltage Switch */
+ lvs1 {
+ bias-pull-down;
+ };
+
+ lvs2 {
+ bias-pull-down;
+ };
+
+ lvs3 {
+ bias-pull-down;
+ };
+
+ lvs4 {
+ bias-pull-down;
+ };
+
+ lvs5 {
+ bias-pull-down;
+ };
+
+ lvs6 {
+ bias-pull-down;
+ };
+
+ lvs7 {
+ bias-pull-down;
+ };
+
+ usb-switch {};
+
+ hdmi-switch {};
+
+ ncp {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
};
};
};
+
+&sdcc1 {
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+ status = "okay";
+};
+
+&sdcc3 {
+ vmmc-supply = <&pm8921_l6>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdcc3_pins>, <&sdcc3_cd_pin_a>;
+
+ status = "okay";
+};
+
+&tlmm_pinmux {
+ gsbi5_uart_pin_a: gsbi5-uart-pin-active {
+ rx {
+ pins = "gpio52";
+ function = "gsbi5";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ tx {
+ pins = "gpio51";
+ function = "gsbi5";
+ drive-strength = <4>;
+ bias-disable;
+ };
+ };
+
+
+ sdcc3_cd_pin_a: sdcc3-cd-pin-active {
+ pins = "gpio26";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&usb_hs1_phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+};
+
+&usb1 {
+ dr_mode = "otg";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 942aa2278355..0da9623ea084 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -672,7 +672,7 @@
reg = <0x00c00000 0x1000>;
qcom,controller-type = "pmic-arbiter";
- pm8821: pmic@1 {
+ pm8821: pmic {
compatible = "qcom,pm8821";
interrupt-parent = <&tlmm_pinmux>;
interrupts = <76 IRQ_TYPE_LEVEL_LOW>;
@@ -693,12 +693,12 @@
};
};
- qcom,ssbi@500000 {
+ ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x00500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
- pmicintc: pmic@0 {
+ pmicintc: pmic {
compatible = "qcom,pm8921";
interrupt-parent = <&tlmm_pinmux>;
interrupts = <74 8>;
@@ -884,7 +884,7 @@
reg = <0x2011000 0x1000>;
};
- rpm@108000 {
+ rpm: rpm@108000 {
compatible = "qcom,rpm-apq8064";
reg = <0x108000 0x1000>;
qcom,ipc = <&l2cc 0x8 2>;
@@ -1085,15 +1085,21 @@
ports-implemented = <0x1>;
};
- /* Temporary fixed regulator */
- sdcc1bam: dma-controller@12402000{
- compatible = "qcom,bam-v1.3.0";
- reg = <0x12402000 0x8000>;
- interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&gcc SDC1_H_CLK>;
- clock-names = "bam_clk";
- #dma-cells = <1>;
- qcom,ee = <0>;
+ sdcc3: mmc@12180000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ status = "disabled";
+ reg = <0x12180000 0x2000>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <192000000>;
+ no-1-8-v;
+ dmas = <&sdcc3bam 2>, <&sdcc3bam 1>;
+ dma-names = "tx", "rx";
};
sdcc3bam: dma-controller@12182000{
@@ -1106,6 +1112,24 @@
qcom,ee = <0>;
};
+ sdcc4: mmc@121c0000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ status = "disabled";
+ reg = <0x121c0000 0x2000>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <48000000>;
+ dmas = <&sdcc4bam 2>, <&sdcc4bam 1>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdc4_gpios>;
+ };
+
sdcc4bam: dma-controller@121c2000{
compatible = "qcom,bam-v1.3.0";
reg = <0x121c2000 0x8000>;
@@ -1116,67 +1140,33 @@
qcom,ee = <0>;
};
- amba {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- sdcc1: mmc@12400000 {
- status = "disabled";
- compatible = "arm,pl18x", "arm,primecell";
- pinctrl-names = "default";
- pinctrl-0 = <&sdcc1_pins>;
- arm,primecell-periphid = <0x00051180>;
- reg = <0x12400000 0x2000>;
- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <8>;
- max-frequency = <96000000>;
- non-removable;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
- dma-names = "tx", "rx";
- };
-
- sdcc3: mmc@12180000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- status = "disabled";
- reg = <0x12180000 0x2000>;
- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <4>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <192000000>;
- no-1-8-v;
- dmas = <&sdcc3bam 2>, <&sdcc3bam 1>;
- dma-names = "tx", "rx";
- };
+ sdcc1: mmc@12400000 {
+ status = "disabled";
+ compatible = "arm,pl18x", "arm,primecell";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdcc1_pins>;
+ arm,primecell-periphid = <0x00051180>;
+ reg = <0x12400000 0x2000>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <8>;
+ max-frequency = <96000000>;
+ non-removable;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
+ dma-names = "tx", "rx";
+ };
- sdcc4: mmc@121c0000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- status = "disabled";
- reg = <0x121c0000 0x2000>;
- interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <4>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <48000000>;
- dmas = <&sdcc4bam 2>, <&sdcc4bam 1>;
- dma-names = "tx", "rx";
- pinctrl-names = "default";
- pinctrl-0 = <&sdc4_gpios>;
- };
+ sdcc1bam: dma-controller@12402000{
+ compatible = "qcom,bam-v1.3.0";
+ reg = <0x12402000 0x8000>;
+ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC1_H_CLK>;
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <0>;
};
tcsr: syscon@1a400000 {
@@ -1316,7 +1306,6 @@
<&dsi0_phy 1>;
syscon-sfpb = <&mmss_sfpb>;
phys = <&dsi0_phy>;
- phy-names = "dsi";
status = "disabled";
ports {
@@ -1338,7 +1327,7 @@
};
- dsi0_phy: dsi-phy@4700200 {
+ dsi0_phy: phy@4700200 {
compatible = "qcom,dsi-phy-28nm-8960";
#clock-cells = <1>;
#phy-cells = <0>;
@@ -1470,6 +1459,8 @@
phys = <&hdmi_phy>;
+ status = "disabled";
+
ports {
#address-cells = <1>;
#size-cells = <0>;
@@ -1488,7 +1479,7 @@
};
};
- hdmi_phy: hdmi-phy@4a00400 {
+ hdmi_phy: phy@4a00400 {
compatible = "qcom,hdmi-phy-8960";
reg = <0x4a00400 0x60>,
<0x4a00500 0x100>;
@@ -1498,6 +1489,8 @@
clocks = <&mmcc HDMI_S_AHB_CLK>;
clock-names = "slave_iface";
#phy-cells = <0>;
+
+ status = "disabled";
};
mdp: mdp@5100000 {
@@ -1552,7 +1545,7 @@
};
};
- riva: riva-pil@3204000 {
+ riva: riva-pil@3200800 {
compatible = "qcom,riva-pil";
reg = <0x03200800 0x1000>, <0x03202000 0x2000>, <0x03204000 0x100>;
@@ -1615,7 +1608,7 @@
};
etb@1a01000 {
- compatible = "coresight-etb10", "arm,primecell";
+ compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0x1a01000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
diff --git a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
index 91716298ec5e..1345df7cbd00 100644
--- a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
+++ b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
@@ -35,30 +35,8 @@
};
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs2_phy>;
- phy-select = <&tcsr 0xb000 1>;
- extcon = <&smbb>, <&usb_id>;
- vbus-supply = <&chg_otg>;
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@b {
- status = "okay";
- v3p3-supply = <&pm8941_l24>;
- v1p8-supply = <&pm8941_l6>;
- extcon = <&smbb>;
- qcom,init-seq = /bits/ 8 <0x1 0x63>;
- };
- };
-};
-
&rpm_requests {
- pm8841-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8841-regulators";
pm8841_s1: s1 {
@@ -82,7 +60,7 @@
};
};
- pm8941-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm8941-regulators";
vdd_l1_l3-supply = <&pm8941_s1>;
@@ -272,34 +250,34 @@
};
&tlmm {
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_on: sdc2-on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <10>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
- cd {
+ cd-pins {
pins = "gpio62";
function = "gpio";
drive-strength = <2>;
@@ -307,3 +285,23 @@
};
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs2_phy>;
+ phy-select = <&tcsr 0xb000 1>;
+ extcon = <&smbb>, <&usb_id>;
+ vbus-supply = <&chg_otg>;
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs2_phy {
+ status = "okay";
+ v3p3-supply = <&pm8941_l24>;
+ v1p8-supply = <&pm8941_l6>;
+ extcon = <&smbb>;
+ qcom,init-seq = /bits/ 8 <0x1 0x63>;
+};
diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index f2fb7c975af8..fe30abfff90a 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -72,7 +72,7 @@
};
L2: l2-cache {
- compatible = "qcom,arch-cache";
+ compatible = "cache";
cache-level = <2>;
qcom,saw = <&saw_l2>;
};
@@ -258,12 +258,14 @@
};
tsens: thermal-sensor@fc4a8000 {
- compatible = "qcom,msm8974-tsens";
+ compatible = "qcom,msm8974-tsens", "qcom,tsens-v0_1";
reg = <0xfc4a9000 0x1000>, /* TM */
<0xfc4a8000 0x1000>; /* SROT */
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
nvmem-cell-names = "calib", "calib_backup";
#qcom,sensors = <11>;
+ interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "uplow";
#thermal-sensor-cells = <1>;
};
timer@f9020000 {
@@ -394,7 +396,7 @@
#hwlock-cells = <1>;
};
- rpm_msg_ram: memory@fc428000 {
+ rpm_msg_ram: sram@fc428000 {
compatible = "qcom,rpm-msg-ram";
reg = <0xfc428000 0x4000>;
};
@@ -474,7 +476,7 @@
compatible = "qcom,rpm-apq8084";
qcom,smd-channels = "rpm_requests";
- pma8084-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pma8084-regulators";
pma8084_s1: s1 {};
diff --git a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts
index cf7da1ab177c..1b27edce9d4f 100644
--- a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts
+++ b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts
@@ -9,7 +9,7 @@
leds {
compatible = "gpio-leds";
- power {
+ led-power {
label = "ap120c-ac:green:power";
function = LED_FUNCTION_POWER;
color = <LED_COLOR_ID_GREEN>;
@@ -17,14 +17,14 @@
default-state = "on";
};
- wlan {
+ led-wlan {
label = "ap120c-ac:green:wlan";
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
};
- support {
+ led-support {
label = "ap120c-ac:green:support";
color = <LED_COLOR_ID_GREEN>;
gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts
index c4f89b712fd9..a707057c887d 100644
--- a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts
+++ b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts
@@ -7,7 +7,7 @@
leds {
compatible = "gpio-leds";
- status: status {
+ status: led-status {
label = "ap120c-ac:blue:status";
function = LED_FUNCTION_STATUS;
color = <LED_COLOR_ID_BLUE>;
@@ -15,7 +15,7 @@
default-state = "keep";
};
- wlan2g {
+ led-wlan2g {
label = "ap120c-ac:green:wlan2g";
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_GREEN>;
@@ -23,7 +23,7 @@
linux,default-trigger = "phy0tpt";
};
- wlan5g {
+ led-wlan5g {
label = "ap120c-ac:red:wlan5g";
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_RED>;
diff --git a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi
index af9a26fb5d4a..a5a6f3ebb274 100644
--- a/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi
@@ -6,7 +6,7 @@
/ {
model = "ALFA Network AP120C-AC";
- compatible = "alfa-network,ap120c-ac";
+ compatible = "alfa-network,ap120c-ac", "qcom,ipq4018";
keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts b/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts
index 394412619894..365fbac417fd 100644
--- a/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts
+++ b/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts
@@ -7,7 +7,7 @@
/ {
model = "8devices Jalapeno";
- compatible = "8dev,jalapeno";
+ compatible = "8dev,jalapeno", "qcom,ipq4018";
};
&tlmm {
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index b23591110bd2..acb08dcf9442 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -348,7 +348,7 @@
saw0: regulator@b089000 {
compatible = "qcom,saw2";
reg = <0x0b089000 0x1000>, <0x0b009000 0x1000>;
- regulator;
+ regulator;
};
saw1: regulator@b099000 {
diff --git a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
index 5a65cce2500c..f908889c4f95 100644
--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
+++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
@@ -5,7 +5,7 @@
/ {
model = "MikroTik RB3011UiAS-RM";
- compatible = "mikrotik,rb3011";
+ compatible = "mikrotik,rb3011", "qcom,ipq8064";
aliases {
serial0 = &gsbi7_serial;
@@ -264,8 +264,7 @@
&nand {
status = "okay";
- nandcs@0 {
- compatible = "qcom,nandcs";
+ nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
index 90c08b51680a..7e784b0995da 100644
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -513,8 +513,8 @@
gcc: clock-controller@900000 {
compatible = "qcom,gcc-ipq8064", "syscon";
- clocks = <&pxo_board>, <&cxo_board>;
- clock-names = "pxo", "cxo";
+ clocks = <&pxo_board>, <&cxo_board>, <&lcc PLL4>;
+ clock-names = "pxo", "cxo", "pll4";
reg = <0x00900000 0x4000>;
#clock-cells = <1>;
#reset-cells = <1>;
@@ -728,7 +728,6 @@
status = "disabled";
reg = <0x12180000 0x2000>;
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <8>;
@@ -748,7 +747,6 @@
arm,primecell-periphid = <0x00051180>;
reg = <0x12400000 0x2000>;
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <8>;
@@ -756,7 +754,6 @@
non-removable;
cap-sd-highspeed;
cap-mmc-highspeed;
- mmc-ddr-1_8v;
vmmc-supply = <&vsdcc_fixed>;
dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
dma-names = "tx", "rx";
diff --git a/arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts b/arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts
index 0827de5426c1..a8304769b509 100644
--- a/arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts
+++ b/arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
/*
* Device Tree Source for mangOH Green Board with WP8548 Module
*
* Copyright (C) 2016 BayLibre, SAS.
* Author : Neil Armstrong <narmstrong@baylibre.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/input/input.h>
@@ -82,8 +45,8 @@
* - 42: IOT0_GPIO1 and SD Card Detect
*/
- gpioext1_pins: gpioext1_pins {
- pins {
+ gpioext1_pins: gpioext1-state {
+ gpioext1-pins {
pins = "gpio2";
function = "gpio";
input-enable;
@@ -91,8 +54,8 @@
};
};
- sdc_cd_pins: sdc_cd_pins {
- pins {
+ sdc_cd_pins: sdc-cd-state {
+ sdc-cd-pins {
pins = "gpio42";
function = "gpio";
drive-strength = <2>;
@@ -153,7 +116,7 @@
#size-cells = <0>;
reg = <4>;
- gpioext0: gpio@3e {
+ gpioext0: pinctrl@3e {
/* GPIO Expander 0 Mapping :
* - 0: ARDUINO_RESET_Level shift
* - 1: BattChrgr_PG_N
@@ -179,7 +142,7 @@
interrupt-parent = <&gpioext1>;
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
- probe-reset;
+ semtech,probe-reset;
gpio-controller;
interrupt-controller;
@@ -191,7 +154,7 @@
#size-cells = <0>;
reg = <5>;
- gpioext1: gpio@3f {
+ gpioext1: pinctrl@3f {
/* GPIO Expander 1 Mapping :
* - 0: GPIOEXP_INT1
* - 1: Battery detect
@@ -220,7 +183,7 @@
interrupt-parent = <&msmgpio>;
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
- probe-reset;
+ semtech,probe-reset;
gpio-controller;
interrupt-controller;
@@ -232,7 +195,7 @@
#size-cells = <0>;
reg = <6>;
- gpioext2: gpio@70 {
+ gpioext2: pinctrl@70 {
/* GPIO Expander 2 Mapping :
* - 0: USB_HUB_INTn
* - 1: HUB_CONNECT
@@ -258,7 +221,7 @@
interrupt-parent = <&gpioext1>;
interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
- probe-reset;
+ semtech,probe-reset;
gpio-controller;
interrupt-controller;
diff --git a/arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi
index 49de1821ac3a..92c8003dac25 100644
--- a/arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi
+++ b/arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
/*
* Device Tree Source for Sierra Wireless WP8548 Module
*
* Copyright (C) 2016 BayLibre, SAS.
* Author : Neil Armstrong <narmstrong@baylibre.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 "qcom-mdm9615.dtsi"
@@ -59,8 +22,8 @@
pinctrl-0 = <&reset_out_pins>;
pinctrl-names = "default";
- gsbi3_pins: gsbi3_pins {
- mux {
+ gsbi3_pins: gsbi3-state {
+ gsbi3-pins {
pins = "gpio8", "gpio9", "gpio10", "gpio11";
function = "gsbi3";
drive-strength = <8>;
@@ -68,8 +31,8 @@
};
};
- gsbi4_pins: gsbi4_pins {
- mux {
+ gsbi4_pins: gsbi4-state {
+ gsbi4-pins {
pins = "gpio12", "gpio13", "gpio14", "gpio15";
function = "gsbi4";
drive-strength = <8>;
@@ -77,15 +40,15 @@
};
};
- gsbi5_i2c_pins: gsbi5_i2c_pins {
- pin16 {
+ gsbi5_i2c_pins: gsbi5-i2c-state {
+ sda-pins {
pins = "gpio16";
function = "gsbi5_i2c";
drive-strength = <8>;
bias-disable;
};
- pin17 {
+ scl-pins {
pins = "gpio17";
function = "gsbi5_i2c";
drive-strength = <2>;
@@ -93,8 +56,8 @@
};
};
- gsbi5_uart_pins: gsbi5_uart_pins {
- mux {
+ gsbi5_uart_pins: gsbi5-uart-state {
+ gsbi5-uart-pins {
pins = "gpio18", "gpio19";
function = "gsbi5_uart";
drive-strength = <8>;
@@ -102,8 +65,8 @@
};
};
- reset_out_pins: reset_out_pins {
- pins {
+ reset_out_pins: reset-out-state {
+ reset-out-pins {
pins = "gpio66";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm/boot/dts/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom-mdm9615.dtsi
index b47c86412de2..b0fe1d95d88f 100644
--- a/arch/arm/boot/dts/qcom-mdm9615.dtsi
+++ b/arch/arm/boot/dts/qcom-mdm9615.dtsi
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
/*
* Device Tree Source for Qualcomm MDM9615 SoC
*
* Copyright (C) 2016 BayLibre, SAS.
* Author : Neil Armstrong <narmstrong@baylibre.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/;
@@ -64,6 +27,7 @@
cpu0: cpu@0 {
compatible = "arm,cortex-a5";
+ reg = <0>;
device_type = "cpu";
next-level-cache = <&L2>;
};
@@ -206,7 +170,6 @@
#size-cells = <0>;
reg = <0x16280000 0x1000>;
interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
- spi-max-frequency = <24000000>;
clocks = <&gcc GSBI3_QUP_CLK>, <&gcc GSBI3_H_CLK>;
clock-names = "core", "iface";
@@ -283,7 +246,7 @@
reg = <0x500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
- pmicintc: pmic@0 {
+ pmicintc: pmic {
compatible = "qcom,pm8018", "qcom,pm8921";
interrupts = <GIC_PPI 226 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <2>;
@@ -351,51 +314,43 @@
qcom,ee = <0>;
};
- amba {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- sdcc1: mmc@12180000 {
- status = "disabled";
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- reg = <0x12180000 0x2000>;
- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <8>;
- max-frequency = <48000000>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- vmmc-supply = <&vsdcc_fixed>;
- dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
- dma-names = "tx", "rx";
- assigned-clocks = <&gcc SDC1_CLK>;
- assigned-clock-rates = <400000>;
- };
+ sdcc1: mmc@12180000 {
+ status = "disabled";
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ reg = <0x12180000 0x2000>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <8>;
+ max-frequency = <48000000>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ vmmc-supply = <&vsdcc_fixed>;
+ dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
+ dma-names = "tx", "rx";
+ assigned-clocks = <&gcc SDC1_CLK>;
+ assigned-clock-rates = <400000>;
+ };
- sdcc2: mmc@12140000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- status = "disabled";
- reg = <0x12140000 0x2000>;
- interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <4>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <48000000>;
- no-1-8-v;
- vmmc-supply = <&vsdcc_fixed>;
- dmas = <&sdcc2bam 2>, <&sdcc2bam 1>;
- dma-names = "tx", "rx";
- assigned-clocks = <&gcc SDC2_CLK>;
- assigned-clock-rates = <400000>;
- };
+ sdcc2: mmc@12140000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ status = "disabled";
+ reg = <0x12140000 0x2000>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <48000000>;
+ no-1-8-v;
+ vmmc-supply = <&vsdcc_fixed>;
+ dmas = <&sdcc2bam 2>, <&sdcc2bam 1>;
+ dma-names = "tx", "rx";
+ assigned-clocks = <&gcc SDC2_CLK>;
+ assigned-clock-rates = <400000>;
};
tcsr: syscon@1a400000 {
diff --git a/arch/arm/boot/dts/qcom-msm8226-samsung-s3ve3g.dts b/arch/arm/boot/dts/qcom-msm8226-samsung-s3ve3g.dts
index 290e1df631f0..6a082ad4418a 100644
--- a/arch/arm/boot/dts/qcom-msm8226-samsung-s3ve3g.dts
+++ b/arch/arm/boot/dts/qcom-msm8226-samsung-s3ve3g.dts
@@ -8,6 +8,7 @@
/ {
model = "Samsung Galaxy S III Neo";
compatible = "samsung,s3ve3g", "qcom,msm8226";
+ chassis-type = "handset";
aliases {
serial0 = &blsp1_uart3;
diff --git a/arch/arm/boot/dts/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom-msm8226.dtsi
index cf2d56929428..4cba25dad8d6 100644
--- a/arch/arm/boot/dts/qcom-msm8226.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8226.dtsi
@@ -7,6 +7,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8974.h>
+#include <dt-bindings/clock/qcom,mmcc-msm8974.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/power/qcom-rpmpd.h>
#include <dt-bindings/reset/qcom,gcc-msm8974.h>
@@ -298,6 +299,33 @@
#size-cells = <0>;
};
+ cci: cci@fda0c000 {
+ compatible = "qcom,msm8226-cci";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfda0c000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&mmcc CAMSS_TOP_AHB_CLK>,
+ <&mmcc CAMSS_CCI_CCI_AHB_CLK>,
+ <&mmcc CAMSS_CCI_CCI_CLK>;
+ clock-names = "camss_top_ahb",
+ "cci_ahb",
+ "cci";
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cci_default>;
+ pinctrl-1 = <&cci_sleep>;
+
+ status = "disabled";
+
+ cci_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
usb: usb@f9a55000 {
compatible = "qcom,ci-hdrc";
reg = <0xf9a55000 0x200>,
@@ -344,6 +372,14 @@
#power-domain-cells = <1>;
};
+ mmcc: clock-controller@fd8c0000 {
+ compatible = "qcom,mmcc-msm8226";
+ reg = <0xfd8c0000 0x6000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
tlmm: pinctrl@fd510000 {
compatible = "qcom,msm8226-pinctrl";
reg = <0xfd510000 0x4000>;
@@ -354,49 +390,65 @@
#interrupt-cells = <2>;
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
- blsp1_i2c1_pins: blsp1-i2c1 {
+ blsp1_i2c1_pins: blsp1-i2c1-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c2_pins: blsp1-i2c2 {
+ blsp1_i2c2_pins: blsp1-i2c2-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c3_pins: blsp1-i2c3 {
+ blsp1_i2c3_pins: blsp1-i2c3-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c4_pins: blsp1-i2c4 {
+ blsp1_i2c4_pins: blsp1-i2c4-state {
pins = "gpio14", "gpio15";
function = "blsp_i2c4";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c5_pins: blsp1-i2c5 {
+ blsp1_i2c5_pins: blsp1-i2c5-state {
pins = "gpio18", "gpio19";
function = "blsp_i2c5";
drive-strength = <2>;
bias-disable;
};
+ cci_default: cci-default-state {
+ pins = "gpio29", "gpio30";
+ function = "cci_i2c0";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cci_sleep: cci-sleep-state {
+ pins = "gpio29", "gpio30";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
sdhc1_default_state: sdhc1-default-state {
- clk {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <10>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
@@ -404,13 +456,13 @@
};
sdhc2_default_state: sdhc2-default-state {
- clk {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <10>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <10>;
bias-pull-up;
@@ -418,21 +470,21 @@
};
sdhc3_default_state: sdhc3-default-state {
- clk {
+ clk-pins {
pins = "gpio44";
function = "sdc3";
drive-strength = <8>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "gpio43";
function = "sdc3";
drive-strength = <8>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "gpio39", "gpio40", "gpio41", "gpio42";
function = "sdc3";
drive-strength = <8>;
@@ -527,7 +579,7 @@
};
};
- rpm_msg_ram: memory@fc428000 {
+ rpm_msg_ram: sram@fc428000 {
compatible = "qcom,rpm-msg-ram";
reg = <0xfc428000 0x4000>;
};
diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi
index ddce7d64ba99..86f76d0feff4 100644
--- a/arch/arm/boot/dts/qcom-msm8660.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8660.dtsi
@@ -316,7 +316,7 @@
};
};
- external-bus@1a100000 {
+ ebi2: external-bus@1a100000 {
compatible = "qcom,msm8660-ebi2";
#address-cells = <2>;
#size-cells = <1>;
@@ -333,12 +333,12 @@
status = "disabled";
};
- qcom,ssbi@500000 {
+ ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
- pm8058: pmic@0 {
+ pm8058: pmic {
compatible = "qcom,pm8058";
interrupt-parent = <&tlmm>;
interrupts = <88 8>;
@@ -379,7 +379,7 @@
pull-up;
};
- keypad@148 {
+ pm8058_keypad: keypad@148 {
compatible = "qcom,pm8058-keypad";
reg = <0x148>;
interrupt-parent = <&pm8058>;
@@ -444,6 +444,31 @@
compatible = "qcom,pm8058-vib";
reg = <0x4a>;
};
+
+ pm8058_led48: led@48 {
+ compatible = "qcom,pm8058-keypad-led";
+ reg = <0x48>;
+ status = "disabled";
+ };
+
+ pm8058_led131: led@131 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x131>;
+ status = "disabled";
+ };
+
+ pm8058_led132: led@132 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x132>;
+ status = "disabled";
+ };
+
+ pm8058_led133: led@133 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x133>;
+ status = "disabled";
+ };
+
};
};
@@ -471,7 +496,7 @@
clock-names = "pxo";
};
- pm8901-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8901-regulators";
pm8901_l0: l0 {};
@@ -495,7 +520,7 @@
pm8901_mvs: mvs {};
};
- pm8058-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm8058-regulators";
pm8058_l0: l0 {};
@@ -549,7 +574,6 @@
arm,primecell-periphid = <0x00051180>;
reg = <0x12400000 0x8000>;
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <8>;
@@ -565,7 +589,6 @@
arm,primecell-periphid = <0x00051180>;
reg = <0x12140000 0x8000>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <8>;
@@ -580,7 +603,6 @@
status = "disabled";
reg = <0x12180000 0x8000>;
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <4>;
@@ -596,7 +618,6 @@
status = "disabled";
reg = <0x121c0000 0x8000>;
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <4>;
@@ -611,7 +632,6 @@
status = "disabled";
reg = <0x12200000 0x8000>;
interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&gcc SDC5_CLK>, <&gcc SDC5_H_CLK>;
clock-names = "mclk", "apb_pclk";
bus-width = <4>;
diff --git a/arch/arm/boot/dts/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom-msm8960-cdp.dts
index 9157e3c4f48f..8fa2befa629a 100644
--- a/arch/arm/boot/dts/qcom-msm8960-cdp.dts
+++ b/arch/arm/boot/dts/qcom-msm8960-cdp.dts
@@ -18,7 +18,7 @@
regulators {
compatible = "simple-bus";
- ext_l2: gpio-regulator@91 {
+ ext_l2: gpio-regulator {
compatible = "regulator-fixed";
regulator-name = "ext_l2";
gpio = <&msmgpio 91 0>;
@@ -42,7 +42,7 @@
compatible = "micrel,ks8851";
reg = <0>;
interrupt-parent = <&msmgpio>;
- interrupts = <90 8>;
+ interrupts = <90 IRQ_TYPE_LEVEL_LOW>;
spi-max-frequency = <5400000>;
vdd-supply = <&ext_l2>;
vdd-io-supply = <&pm8921_lvs6>;
@@ -60,33 +60,32 @@
};
&msmgpio {
- spi1_default: spi1_default {
- mux {
- pins = "gpio6", "gpio7", "gpio9";
- function = "gsbi1";
- };
-
- mosi {
+ spi1_default: spi1-default-state {
+ mosi-pins {
pins = "gpio6";
+ function = "gsbi1";
drive-strength = <12>;
bias-disable;
};
- miso {
+ miso-pins {
pins = "gpio7";
+ function = "gsbi1";
drive-strength = <12>;
bias-disable;
};
- cs {
+ cs-pins {
pins = "gpio8";
+ function = "gsbi1";
drive-strength = <12>;
bias-disable;
output-low;
};
- clk {
+ clk-pins {
pins = "gpio9";
+ function = "gsbi1";
drive-strength = <12>;
bias-disable;
};
diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi
index c5740da3754c..7debf9db7cb1 100644
--- a/arch/arm/boot/dts/qcom-msm8960.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8960.dtsi
@@ -17,7 +17,7 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <1 14 0x304>;
+ interrupts = <GIC_PPI 14 0x304>;
cpu@0 {
compatible = "qcom,krait";
@@ -52,7 +52,7 @@
cpu-pmu {
compatible = "qcom,krait-pmu";
- interrupts = <1 10 0x304>;
+ interrupts = <GIC_PPI 10 0x304>;
qcom,no-pc-write;
};
@@ -105,9 +105,9 @@
timer@200a000 {
compatible = "qcom,kpss-timer",
"qcom,kpss-wdt-msm8960", "qcom,msm-timer";
- interrupts = <1 1 0x301>,
- <1 2 0x301>,
- <1 3 0x301>;
+ interrupts = <GIC_PPI 1 0x301>,
+ <GIC_PPI 2 0x301>,
+ <GIC_PPI 3 0x301>;
reg = <0x0200a000 0x100>;
clock-frequency = <27000000>,
<32768>;
@@ -119,7 +119,7 @@
gpio-controller;
gpio-ranges = <&msmgpio 0 0 152>;
#gpio-cells = <2>;
- interrupts = <0 16 0x4>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x800000 0x4000>;
@@ -247,15 +247,15 @@
};
};
- qcom,ssbi@500000 {
+ ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
- pmicintc: pmic@0 {
+ pmicintc: pmic {
compatible = "qcom,pm8921";
interrupt-parent = <&msmgpio>;
- interrupts = <104 8>;
+ interrupts = <104 IRQ_TYPE_LEVEL_LOW>;
#interrupt-cells = <2>;
interrupt-controller;
#address-cells = <1>;
@@ -265,7 +265,8 @@
compatible = "qcom,pm8921-pwrkey";
reg = <0x1c>;
interrupt-parent = <&pmicintc>;
- interrupts = <50 1>, <51 1>;
+ interrupts = <50 IRQ_TYPE_EDGE_RISING>,
+ <51 IRQ_TYPE_EDGE_RISING>;
debounce = <15625>;
pull-up;
};
@@ -274,7 +275,8 @@
compatible = "qcom,pm8921-keypad";
reg = <0x148>;
interrupt-parent = <&pmicintc>;
- interrupts = <74 1>, <75 1>;
+ interrupts = <74 IRQ_TYPE_EDGE_RISING>,
+ <75 IRQ_TYPE_EDGE_RISING>;
debounce = <15>;
scan-delay = <32>;
row-hold = <91500>;
@@ -283,7 +285,7 @@
rtc@11d {
compatible = "qcom,pm8921-rtc";
interrupt-parent = <&pmicintc>;
- interrupts = <39 1>;
+ interrupts = <39 IRQ_TYPE_EDGE_RISING>;
reg = <0x11d>;
allow-set-time;
};
@@ -297,44 +299,36 @@
clock-names = "core";
};
- amba {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- sdcc1: mmc@12400000 {
- status = "disabled";
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- reg = <0x12400000 0x8000>;
- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <8>;
- max-frequency = <96000000>;
- non-removable;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- vmmc-supply = <&vsdcc_fixed>;
- };
+ sdcc3: mmc@12180000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ status = "disabled";
+ reg = <0x12180000 0x8000>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <192000000>;
+ no-1-8-v;
+ vmmc-supply = <&vsdcc_fixed>;
+ };
- sdcc3: mmc@12180000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00051180>;
- status = "disabled";
- reg = <0x12180000 0x8000>;
- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
- clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
- clock-names = "mclk", "apb_pclk";
- bus-width = <4>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <192000000>;
- no-1-8-v;
- vmmc-supply = <&vsdcc_fixed>;
- };
+ sdcc1: mmc@12400000 {
+ status = "disabled";
+ compatible = "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00051180>;
+ reg = <0x12400000 0x8000>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+ clock-names = "mclk", "apb_pclk";
+ bus-width = <8>;
+ max-frequency = <96000000>;
+ non-removable;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ vmmc-supply = <&vsdcc_fixed>;
};
tcsr: syscon@1a400000 {
diff --git a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
index 6daceaa87802..280e63e3ebf2 100644
--- a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
@@ -9,6 +9,7 @@
/ {
model = "LGE MSM 8974 HAMMERHEAD";
compatible = "lge,hammerhead", "qcom,msm8974";
+ chassis-type = "handset";
aliases {
serial0 = &blsp1_uart1;
@@ -247,31 +248,6 @@
status = "okay";
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs1_phy>;
- phy-select = <&tcsr 0xb000 0>;
-
- extcon = <&charger>, <&usb_id>;
- vbus-supply = <&usb_otg_vbus>;
-
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@a {
- status = "okay";
-
- v1p8-supply = <&pm8941_l6>;
- v3p3-supply = <&pm8941_l24>;
-
- qcom,init-seq = /bits/ 8 <0x1 0x64>;
- };
- };
-};
-
&pm8941_gpios {
gpio_keys_pin_a: gpio-keys-active-state {
pins = "gpio2", "gpio3";
@@ -344,7 +320,7 @@
};
&rpm_requests {
- pm8841-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8841-regulators";
pm8841_s1: s1 {
@@ -368,7 +344,7 @@
};
};
- pm8941-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm8941-regulators";
vdd_l1_l3-supply = <&pm8941_s1>;
@@ -573,43 +549,43 @@
};
&tlmm {
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_on: sdc2-on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <6>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
};
- mpu6515_pin: mpu6515 {
+ mpu6515_pin: mpu6515-state {
pins = "gpio73";
function = "gpio";
bias-disable;
input-enable;
};
- touch_pin: touch {
- int {
+ touch_pin: touch-state {
+ int-pins {
pins = "gpio5";
function = "gpio";
@@ -618,7 +594,7 @@
input-enable;
};
- reset {
+ reset-pins {
pins = "gpio8";
function = "gpio";
@@ -627,27 +603,50 @@
};
};
- panel_pin: panel {
+ panel_pin: panel-state {
pins = "gpio12";
function = "mdp_vsync";
drive-strength = <2>;
bias-disable;
};
- bt_pin: bt {
- hostwake {
+ bt_pin: bt-state {
+ hostwake-pins {
pins = "gpio42";
function = "gpio";
};
- devwake {
+ devwake-pins {
pins = "gpio62";
function = "gpio";
};
- shutdown {
+ shutdown-pins {
pins = "gpio41";
function = "gpio";
};
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+
+ extcon = <&charger>, <&usb_id>;
+ vbus-supply = <&usb_otg_vbus>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pm8941_l6>;
+ v3p3-supply = <&pm8941_l24>;
+
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-amami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-amami.dts
index 68d5626bf491..9f2ab5c122d0 100644
--- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-amami.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-amami.dts
@@ -4,6 +4,7 @@
/ {
model = "Sony Xperia Z1 Compact";
compatible = "sony,xperia-amami", "qcom,msm8974";
+ chassis-type = "handset";
};
&smbb {
diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-honami.dts
index ea6a941d8f8c..9028f17e5c4a 100644
--- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-honami.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine-honami.dts
@@ -4,4 +4,5 @@
/ {
model = "Sony Xperia Z1";
compatible = "sony,xperia-honami", "qcom,msm8974";
+ chassis-type = "handset";
};
diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi
index 5a70683d9103..1b683690a1ad 100644
--- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi
@@ -132,31 +132,6 @@
/* sii8334 MHL HDMI bridge */
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs1_phy>;
- phy-select = <&tcsr 0xb000 0>;
- extcon = <&smbb>, <&usb_id>;
- vbus-supply = <&chg_otg>;
-
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@a {
- status = "okay";
-
- v1p8-supply = <&pm8941_l6>;
- v3p3-supply = <&pm8941_l24>;
-
- extcon = <&smbb>;
- qcom,init-seq = /bits/ 8 <0x1 0x64>;
- };
- };
-};
-
&pm8941_coincell {
status = "okay";
qcom,rset-ohms = <2100>;
@@ -178,7 +153,7 @@
qcom,power-source = <1>;
- rgb-led {
+ multi-led {
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_STATUS;
@@ -214,7 +189,7 @@
};
&rpm_requests {
- pm8841-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8841-regulators";
pm8841_s1: s1 {
@@ -238,7 +213,7 @@
};
};
- pm8941-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm8941-regulators";
vdd_l1_l3-supply = <&pm8941_s1>;
@@ -442,7 +417,7 @@
};
&tlmm {
- ts_int_pin: touch-int {
+ ts_int_pin: touch-int-state {
pins = "gpio61";
function = "gpio";
drive-strength = <2>;
@@ -450,34 +425,34 @@
input-enable;
};
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_on: sdc-on {
- clk {
+ sdc2_on: sdc-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <10>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
- cd {
+ cd-pins {
pins = "gpio62";
function = "gpio";
drive-strength = <2>;
@@ -485,3 +460,26 @@
};
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+ extcon = <&smbb>, <&usb_id>;
+ vbus-supply = <&chg_otg>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pm8941_l6>;
+ v3p3-supply = <&pm8941_l24>;
+
+ extcon = <&smbb>;
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 7a9be0acf3f5..8d216a3c0851 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -653,7 +653,7 @@
#size-cells = <0>;
};
- otg: usb@f9a55000 {
+ usb: usb@f9a55000 {
compatible = "qcom,ci-hdrc";
reg = <0xf9a55000 0x200>,
<0xf9a55200 0x200>;
@@ -679,7 +679,7 @@
#phy-cells = <0>;
clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
clock-names = "ref", "sleep";
- resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>;
+ resets = <&gcc GCC_USB2A_PHY_BCR>, <&usb 0>;
reset-names = "phy", "por";
status = "disabled";
};
@@ -690,7 +690,7 @@
#phy-cells = <0>;
clocks = <&xo_board>, <&gcc GCC_USB2B_PHY_SLEEP_CLK>;
clock-names = "ref", "sleep";
- resets = <&gcc GCC_USB2B_PHY_BCR>, <&otg 1>;
+ resets = <&gcc GCC_USB2B_PHY_BCR>, <&usb 1>;
reset-names = "phy", "por";
status = "disabled";
};
@@ -1056,7 +1056,7 @@
reg = <0xfc400000 0x4000>;
};
- rpm_msg_ram: memory@fc428000 {
+ rpm_msg_ram: sram@fc428000 {
compatible = "qcom,rpm-msg-ram";
reg = <0xfc428000 0x4000>;
};
@@ -1116,7 +1116,7 @@
};
tsens: thermal-sensor@fc4a9000 {
- compatible = "qcom,msm8974-tsens";
+ compatible = "qcom,msm8974-tsens", "qcom,tsens-v0_1";
reg = <0xfc4a9000 0x1000>, /* TM */
<0xfc4a8000 0x1000>; /* SROT */
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
@@ -1194,7 +1194,7 @@
resets = <&gcc GCC_MSS_RESTART>;
reset-names = "mss_restart";
- qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+ qcom,halt-regs = <&tcsr_mutex 0x1180 0x1200 0x1280>;
qcom,smem-states = <&modem_smp2p_out 0>;
qcom,smem-state-names = "stop";
@@ -1233,13 +1233,14 @@
};
};
- tcsr_mutex_block: syscon@fd484000 {
- compatible = "syscon";
+ tcsr_mutex: hwlock@fd484000 {
+ compatible = "qcom,msm8974-tcsr-mutex", "qcom,tcsr-mutex", "syscon";
reg = <0xfd484000 0x2000>;
+ #hwlock-cells = <1>;
};
tcsr: syscon@fd4a0000 {
- compatible = "syscon";
+ compatible = "qcom,tcsr-msm8974", "syscon";
reg = <0xfd4a0000 0x10000>;
};
@@ -1253,61 +1254,62 @@
#interrupt-cells = <2>;
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
- sdc1_off: sdc1-off {
- clk {
+ sdc1_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
};
- sdc2_off: sdc2-off {
- clk {
+ sdc2_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
};
- cd {
+ cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-disable;
drive-strength = <2>;
};
};
- blsp1_uart2_default: blsp1-uart2-default {
- rx {
+ blsp1_uart2_default: blsp1-uart2-default-state {
+ rx-pins {
pins = "gpio5";
function = "blsp_uart2";
drive-strength = <2>;
bias-pull-up;
};
- tx {
+ tx-pins {
pins = "gpio4";
function = "blsp_uart2";
drive-strength = <4>;
@@ -1315,15 +1317,15 @@
};
};
- blsp2_uart1_default: blsp2-uart1-default {
- tx-rts {
+ blsp2_uart1_default: blsp2-uart1-default-state {
+ tx-rts-pins {
pins = "gpio41", "gpio44";
function = "blsp_uart7";
drive-strength = <2>;
bias-disable;
};
- rx-cts {
+ rx-cts-pins {
pins = "gpio42", "gpio43";
function = "blsp_uart7";
drive-strength = <2>;
@@ -1331,22 +1333,22 @@
};
};
- blsp2_uart1_sleep: blsp2-uart1-sleep {
+ blsp2_uart1_sleep: blsp2-uart1-sleep-state {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- blsp2_uart4_default: blsp2-uart4-default {
- tx-rts {
+ blsp2_uart4_default: blsp2-uart4-default-state {
+ tx-rts-pins {
pins = "gpio53", "gpio56";
function = "blsp_uart10";
drive-strength = <2>;
bias-disable;
};
- rx-cts {
+ rx-cts-pins {
pins = "gpio54", "gpio55";
function = "blsp_uart10";
drive-strength = <2>;
@@ -1354,42 +1356,42 @@
};
};
- blsp1_i2c1_default: blsp1-i2c1-default {
+ blsp1_i2c1_default: blsp1-i2c1-default-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c1_sleep: blsp1-i2c1-sleep {
+ blsp1_i2c1_sleep: blsp1-i2c1-sleep-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c2_default: blsp1-i2c2-default {
+ blsp1_i2c2_default: blsp1-i2c2-default-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c2_sleep: blsp1-i2c2-sleep {
+ blsp1_i2c2_sleep: blsp1-i2c2-sleep-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c3_default: blsp1-i2c3-default {
+ blsp1_i2c3_default: blsp1-i2c3-default-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c3_sleep: blsp1-i2c3-sleep {
+ blsp1_i2c3_sleep: blsp1-i2c3-sleep-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
@@ -1400,14 +1402,14 @@
/* BLSP1_I2C5 info is missing */
- blsp1_i2c6_default: blsp1-i2c6-default {
+ blsp1_i2c6_default: blsp1-i2c6-default-state {
pins = "gpio29", "gpio30";
function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c6_sleep: blsp1-i2c6-sleep {
+ blsp1_i2c6_sleep: blsp1-i2c6-sleep-state {
pins = "gpio29", "gpio30";
function = "blsp_i2c6";
drive-strength = <2>;
@@ -1417,14 +1419,14 @@
/* BLSP2_I2C1 info is missing */
- blsp2_i2c2_default: blsp2-i2c2-default {
+ blsp2_i2c2_default: blsp2-i2c2-default-state {
pins = "gpio47", "gpio48";
function = "blsp_i2c8";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c2_sleep: blsp2-i2c2-sleep {
+ blsp2_i2c2_sleep: blsp2-i2c2-sleep-state {
pins = "gpio47", "gpio48";
function = "blsp_i2c8";
drive-strength = <2>;
@@ -1435,48 +1437,80 @@
/* BLSP2_I2C4 info is missing */
- blsp2_i2c5_default: blsp2-i2c5-default {
+ blsp2_i2c5_default: blsp2-i2c5-default-state {
pins = "gpio83", "gpio84";
function = "blsp_i2c11";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c5_sleep: blsp2-i2c5-sleep {
+ blsp2_i2c5_sleep: blsp2-i2c5-sleep-state {
pins = "gpio83", "gpio84";
function = "blsp_i2c11";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c6_default: blsp2-i2c6-default {
+ blsp2_i2c6_default: blsp2-i2c6-default-state {
pins = "gpio87", "gpio88";
function = "blsp_i2c12";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+ blsp2_i2c6_sleep: blsp2-i2c6-sleep-state {
pins = "gpio87", "gpio88";
function = "blsp_i2c12";
drive-strength = <2>;
bias-pull-up;
};
- spi8_default: spi8_default {
- mosi {
+ cci_default: cci-default-state {
+ cci_i2c0_default: cci-i2c0-default-pins {
+ pins = "gpio19", "gpio20";
+ function = "cci_i2c0";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cci_i2c1_default: cci-i2c1-default-pins {
+ pins = "gpio21", "gpio22";
+ function = "cci_i2c1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cci_sleep: cci-sleep-state {
+ cci_i2c0_sleep: cci-i2c0-sleep-pins {
+ pins = "gpio19", "gpio20";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cci_i2c1_sleep: cci-i2c1-sleep-pins {
+ pins = "gpio21", "gpio22";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ spi8_default: spi8_default-state {
+ mosi-pins {
pins = "gpio45";
function = "blsp_spi8";
};
- miso {
+ miso-pins {
pins = "gpio46";
function = "blsp_spi8";
};
- cs {
+ cs-pins {
pins = "gpio47";
function = "blsp_spi8";
};
- clk {
+ clk-pins {
pins = "gpio48";
function = "blsp_spi8";
};
@@ -1571,7 +1605,6 @@
"core_mmss";
phys = <&dsi0_phy>;
- phy-names = "dsi-phy";
status = "disabled";
@@ -1597,7 +1630,7 @@
};
};
- dsi0_phy: dsi-phy@fd922a00 {
+ dsi0_phy: phy@fd922a00 {
compatible = "qcom,dsi-phy-28nm-hpm";
reg = <0xfd922a00 0xd4>,
<0xfd922b00 0x280>,
@@ -1616,6 +1649,40 @@
};
};
+ cci: cci@fda0c000 {
+ compatible = "qcom,msm8974-cci";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfda0c000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&mmcc CAMSS_TOP_AHB_CLK>,
+ <&mmcc CAMSS_CCI_CCI_AHB_CLK>,
+ <&mmcc CAMSS_CCI_CCI_CLK>;
+ clock-names = "camss_top_ahb",
+ "cci_ahb",
+ "cci";
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cci_default>;
+ pinctrl-1 = <&cci_sleep>;
+
+ status = "disabled";
+
+ cci_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
gpu: adreno@fdb00000 {
compatible = "qcom,adreno-330.1", "qcom,adreno";
reg = <0xfdb00000 0x10000>;
@@ -1703,8 +1770,6 @@
qcom,ipc = <&apcs 8 8>;
qcom,smd-edge = <1>;
label = "lpass";
- #address-cells = <1>;
- #size-cells = <0>;
};
};
@@ -1719,13 +1784,6 @@
};
};
- tcsr_mutex: tcsr-mutex {
- compatible = "qcom,tcsr-mutex";
- syscon = <&tcsr_mutex_block 0 0x80>;
-
- #hwlock-cells = <1>;
- };
-
thermal-zones {
cpu0-thermal {
polling-delay-passive = <250>;
diff --git a/arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts
index ff6e0066768b..f531d2679f6c 100644
--- a/arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts
+++ b/arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts
@@ -8,7 +8,8 @@
/ {
model = "Fairphone 2";
- compatible = "fairphone,fp2", "qcom,msm8974";
+ compatible = "fairphone,fp2", "qcom,msm8974pro", "qcom,msm8974";
+ chassis-type = "handset";
aliases {
mmc0 = &sdhc_1;
@@ -85,31 +86,6 @@
};
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs1_phy>;
- phy-select = <&tcsr 0xb000 0>;
- extcon = <&smbb>, <&usb_id>;
- vbus-supply = <&chg_otg>;
-
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@a {
- status = "okay";
-
- v1p8-supply = <&pm8941_l6>;
- v3p3-supply = <&pm8941_l24>;
-
- extcon = <&smbb>;
- qcom,init-seq = /bits/ 8 <0x1 0x64>;
- };
- };
-};
-
&pm8941_gpios {
gpio_keys_pin_a: gpio-keys-active-state {
pins = "gpio1", "gpio2", "gpio5";
@@ -190,7 +166,7 @@
};
&rpm_requests {
- pm8841-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8841-regulators";
pm8841_s1: s1 {
@@ -209,7 +185,7 @@
};
};
- pm8941-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm8941-regulators";
vdd_l1_l3-supply = <&pm8941_s1>;
@@ -408,36 +384,36 @@
};
&tlmm {
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_on: sdc2-on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <10>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
};
- wcnss_pin_a: wcnss-pin-active {
- wlan {
+ wcnss_pin_a: wcnss-pin-active-state {
+ wlan-pins {
pins = "gpio36", "gpio37", "gpio38", "gpio39", "gpio40";
function = "wlan";
@@ -445,7 +421,7 @@
bias-pull-down;
};
- bt {
+ bt-pins {
pins = "gpio35", "gpio43", "gpio44";
function = "bt";
@@ -453,7 +429,7 @@
bias-pull-down;
};
- fm {
+ fm-pins {
pins = "gpio41", "gpio42";
function = "fm";
@@ -462,3 +438,26 @@
};
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+ extcon = <&smbb>, <&usb_id>;
+ vbus-supply = <&chg_otg>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pm8941_l6>;
+ v3p3-supply = <&pm8941_l24>;
+
+ extcon = <&smbb>;
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom-msm8974pro-oneplus-bacon.dts
new file mode 100644
index 000000000000..b5606623f968
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-msm8974pro-oneplus-bacon.dts
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "qcom-msm8974pro.dtsi"
+#include "qcom-pm8841.dtsi"
+#include "qcom-pm8941.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+/ {
+ model = "OnePlus One";
+ compatible = "oneplus,bacon", "qcom,msm8974pro", "qcom,msm8974";
+ chassis-type = "handset";
+ qcom,msm-id = <194 0x10000>;
+ qcom,board-id = <8 0>;
+
+ aliases {
+ serial0 = &blsp1_uart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&blsp1_i2c1 {
+ status = "okay";
+
+ fuel-gauge@55 {
+ compatible = "ti,bq27541";
+ reg = <0x55>;
+ power-supplies = <&bq24196_charger>;
+ };
+};
+
+&blsp1_i2c2 {
+ status = "okay";
+
+ rmi4-i2c-dev@20 {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x20>;
+
+ syna,startup-delay-ms = <100>;
+
+ interrupts-extended = <&tlmm 61 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&pm8941_l22>;
+ vio-supply = <&pm8941_lvs3>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_default_state>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rmi4-f01@1 {
+ reg = <0x1>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f12@12 {
+ reg = <0x12>;
+ syna,sensor-type = <1>;
+ /*
+ * Touchscreen size is 2040x1080, y-values between
+ * 1920-2040 are used for touchkey (menu, home & back).
+ * For now clip it off so we don't get touch events
+ * outside of the display area.
+ */
+ syna,clip-y-high = <1920>;
+ };
+ };
+};
+
+&blsp1_i2c6 {
+ status = "okay";
+
+ bq24196_charger: charger@6b {
+ compatible = "ti,bq24196";
+ reg = <0x6b>;
+ interrupts-extended = <&tlmm 31 IRQ_TYPE_EDGE_FALLING>;
+ omit-battery-class;
+ };
+};
+
+&blsp1_uart2 {
+ status = "okay";
+};
+
+&gcc {
+ compatible = "qcom,gcc-msm8974pro-ac";
+};
+
+&pm8941_coincell {
+ qcom,rset-ohms = <800>;
+ qcom,vset-millivolts = <3200>;
+
+ status = "okay";
+};
+
+&pronto {
+ vddmx-supply = <&pm8841_s1>;
+ vddcx-supply = <&pm8841_s2>;
+ vddpx-supply = <&pm8941_s3>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcnss_pin_a>;
+
+ status = "okay";
+
+ iris {
+ vddxo-supply = <&pm8941_l6>;
+ vddrfa-supply = <&pm8941_l11>;
+ vddpa-supply = <&pm8941_l19>;
+ vdddig-supply = <&pm8941_s3>;
+ };
+
+ smd-edge {
+ qcom,remote-pid = <4>;
+ label = "pronto";
+
+ wcnss {
+ status = "okay";
+ };
+ };
+};
+
+&remoteproc_adsp {
+ cx-supply = <&pm8841_s2>;
+
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators-0 {
+ compatible = "qcom,rpm-pm8841-regulators";
+
+ pm8841_s1: s1 {
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm8841_s2: s2 {
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-always-on;
+ };
+
+ pm8841_s3: s3 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,rpm-pm8941-regulators";
+
+ vdd_l1_l3-supply = <&pm8941_s1>;
+ vdd_l2_lvs1_2_3-supply = <&pm8941_s3>;
+ vdd_l4_l11-supply = <&pm8941_s1>;
+ vdd_l5_l7-supply = <&pm8941_s2>;
+ vdd_l6_l12_l14_l15-supply = <&pm8941_s2>;
+ vdd_l8_l16_l18_l19-supply = <&vreg_vph_pwr>;
+ vdd_l9_l10_l17_l22-supply = <&vreg_boost>;
+ vdd_l13_l20_l23_l24-supply = <&vreg_boost>;
+ vdd_l21-supply = <&vreg_boost>;
+
+ pm8941_s1: s1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ pm8941_s2: s2 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_s3: s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-system-load = <154000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-allow-set-load;
+ };
+
+ pm8941_l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ pm8941_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8941_l3: l3 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8941_l4: l4 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8941_l5: l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8941_l6: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_l7: l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_l8: l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8941_l9: l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8941_l10: l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8941_l11: l11 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8941_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-allow-set-load;
+ };
+
+ pm8941_l13: l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_l14: l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8941_l15: l15 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8941_l16: l16 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ pm8941_l17: l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8941_l18: l18 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8941_l19: l19 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <3350000>;
+ };
+
+ pm8941_l20: l20 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-system-load = <200000>;
+ regulator-allow-set-load;
+ regulator-boot-on;
+ };
+
+ pm8941_l21: l21 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_l22: l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-allow-set-load;
+ };
+
+ pm8941_l23: l23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8941_l24: l24 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+
+ regulator-boot-on;
+ };
+
+ pm8941_lvs3: lvs3 {};
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8941_l20>;
+ vqmmc-supply = <&pm8941_s3>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc1_on>;
+ pinctrl-1 = <&sdc1_off>;
+
+ status = "okay";
+};
+
+&tlmm {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ drive-strength = <4>;
+ bias-disable;
+ };
+
+ cmd-data-pins {
+ pins = "sdc1_cmd", "sdc1_data";
+ drive-strength = <4>;
+ bias-pull-up;
+ };
+ };
+
+ touch_default_state: touch-default-state {
+ int-pins {
+ pins = "gpio61";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+
+ reset-pins {
+ pins = "gpio60";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ wcnss_pin_a: wcnss-pin-active-state {
+ wlan-pins {
+ pins = "gpio36", "gpio37", "gpio38", "gpio39", "gpio40";
+ function = "wlan";
+ drive-strength = <6>;
+ bias-pull-down;
+ };
+
+ bt-pins {
+ pins = "gpio35", "gpio43", "gpio44";
+ function = "bt";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+};
+
+&usb {
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+ extcon = <&smbb>, <&usb_id>;
+ vbus-supply = <&chg_otg>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+
+ status = "okay";
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pm8941_l6>;
+ v3p3-supply = <&pm8941_l24>;
+
+ extcon = <&smbb>;
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts b/arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts
index 983e10c3d863..b9698ffb66ca 100644
--- a/arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts
+++ b/arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts
@@ -7,7 +7,8 @@
/ {
model = "Samsung Galaxy S5";
- compatible = "samsung,klte", "qcom,msm8974";
+ compatible = "samsung,klte", "qcom,msm8974pro", "qcom,msm8974";
+ chassis-type = "handset";
aliases {
serial0 = &blsp1_uart1;
@@ -375,28 +376,6 @@
status = "okay";
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs1_phy>;
- phy-select = <&tcsr 0xb000 0>;
-
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@a {
- status = "okay";
-
- v1p8-supply = <&pma8084_l6>;
- v3p3-supply = <&pma8084_l24>;
-
- qcom,init-seq = /bits/ 8 <0x1 0x64>;
- };
- };
-};
-
&pma8084_gpios {
gpio_keys_pin_a: gpio-keys-active-state {
pins = "gpio2", "gpio3", "gpio5";
@@ -470,7 +449,7 @@
};
&rpm_requests {
- pma8084-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pma8084-regulators";
pma8084_s1: s1 {
@@ -706,57 +685,57 @@
&tlmm {
/* This seems suspicious, but somebody with this device should look into it. */
- blsp2_uart2_pins_active: blsp2-uart2-pins-active {
+ blsp2_uart2_pins_active: blsp2-uart2-pins-active-state {
pins = "gpio45", "gpio46", "gpio47", "gpio48";
function = "blsp_uart8";
drive-strength = <8>;
bias-disable;
};
- blsp2_uart2_pins_sleep: blsp2-uart2-pins-sleep {
+ blsp2_uart2_pins_sleep: blsp2-uart2-pins-sleep-state {
pins = "gpio45", "gpio46", "gpio47", "gpio48";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- bt_pins: bt-pins {
- hostwake {
+ bt_pins: bt-pins-state {
+ hostwake-pins {
pins = "gpio75";
function = "gpio";
drive-strength = <16>;
input-enable;
};
- devwake {
+ devwake-pins {
pins = "gpio91";
function = "gpio";
drive-strength = <2>;
};
};
- sdc1_on: sdhc1-on {
- clk {
+ sdc1_on: sdhc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <4>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <4>;
bias-pull-up;
};
};
- sdc3_on: sdc3-on {
+ sdc3_on: sdc3-on-state {
pins = "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", "gpio40";
function = "sdc3";
drive-strength = <8>;
bias-disable;
};
- sdhc3_cd_pin: sdc3-cd-on {
+ sdhc3_cd_pin: sdc3-cd-on-state {
pins = "gpio62";
function = "gpio";
@@ -764,52 +743,72 @@
bias-disable;
};
- sdc2_on: sdhc2-on {
- clk {
+ sdc2_on: sdhc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <6>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
};
- i2c_touchkey_pins: i2c-touchkey {
+ i2c_touchkey_pins: i2c-touchkey-state {
pins = "gpio95", "gpio96";
function = "gpio";
input-enable;
bias-pull-up;
};
- i2c_led_gpioex_pins: i2c-led-gpioex {
+ i2c_led_gpioex_pins: i2c-led-gpioex-state {
pins = "gpio120", "gpio121";
function = "gpio";
input-enable;
bias-pull-down;
};
- gpioex_pin: gpioex {
+ gpioex_pin: gpioex-state {
pins = "gpio145";
function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
- wifi_pin: wifi {
+ wifi_pin: wifi-state {
pins = "gpio92";
function = "gpio";
input-enable;
bias-pull-down;
};
- panel_te_pin: panel {
+ panel_te_pin: panel-state {
pins = "gpio12";
function = "mdp_vsync";
drive-strength = <2>;
bias-disable;
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pma8084_l6>;
+ v3p3-supply = <&pma8084_l24>;
+
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts
index 3f45f5c5d37b..3b1cc39f2269 100644
--- a/arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts
+++ b/arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts
@@ -8,7 +8,8 @@
/ {
model = "Sony Xperia Z2 Tablet";
- compatible = "sony,xperia-castor", "qcom,msm8974";
+ compatible = "sony,xperia-castor", "qcom,msm8974pro", "qcom,msm8974";
+ chassis-type = "tablet";
aliases {
serial0 = &blsp1_uart2;
@@ -212,31 +213,6 @@
};
};
-&otg {
- status = "okay";
-
- phys = <&usb_hs1_phy>;
- phy-select = <&tcsr 0xb000 0>;
- extcon = <&smbb>, <&usb_id>;
- vbus-supply = <&chg_otg>;
-
- hnp-disable;
- srp-disable;
- adp-disable;
-
- ulpi {
- phy@a {
- status = "okay";
-
- v1p8-supply = <&pm8941_l6>;
- v3p3-supply = <&pm8941_l24>;
-
- extcon = <&smbb>;
- qcom,init-seq = /bits/ 8 <0x1 0x64>;
- };
- };
-};
-
&pm8941_coincell {
status = "okay";
@@ -294,7 +270,7 @@
qcom,power-source = <1>;
- rgb-led {
+ multi-led {
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_STATUS;
@@ -319,7 +295,7 @@
};
&rpm_requests {
- pm8941-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8941-regulators";
vdd_l1_l3-supply = <&pm8941_s1>;
@@ -548,41 +524,42 @@
};
&tlmm {
- lcd_backlight_en_pin_a: lcd-backlight-vddio {
+ lcd_backlight_en_pin_a: lcd-backlight-vddio-state {
pins = "gpio69";
+ function = "gpio";
drive-strength = <10>;
output-low;
bias-disable;
};
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc1_cmd", "sdc1_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_on: sdc2-on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <6>;
bias-disable;
};
- cmd-data {
+ cmd-data-pins {
pins = "sdc2_cmd", "sdc2_data";
drive-strength = <6>;
bias-pull-up;
};
- cd {
+ cd-pins {
pins = "gpio62";
function = "gpio";
drive-strength = <2>;
@@ -590,22 +567,22 @@
};
};
- sdc3_on: sdc3-on {
- clk {
+ sdc3_on: sdc3-on-state {
+ clk-pins {
pins = "gpio40";
function = "sdc3";
drive-strength = <10>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "gpio39";
function = "sdc3";
drive-strength = <10>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "gpio35", "gpio36", "gpio37", "gpio38";
function = "sdc3";
drive-strength = <10>;
@@ -613,7 +590,7 @@
};
};
- ts_int_pin: ts-int-pin {
+ ts_int_pin: ts-int-pin-state {
pins = "gpio86";
function = "gpio";
drive-strength = <2>;
@@ -621,7 +598,7 @@
input-enable;
};
- bt_host_wake_pin: bt-host-wake {
+ bt_host_wake_pin: bt-host-wake-state {
pins = "gpio95";
function = "gpio";
drive-strength = <2>;
@@ -629,10 +606,33 @@
output-low;
};
- bt_dev_wake_pin: bt-dev-wake {
+ bt_dev_wake_pin: bt-dev-wake-state {
pins = "gpio96";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
};
+
+&usb {
+ status = "okay";
+
+ phys = <&usb_hs1_phy>;
+ phy-select = <&tcsr 0xb000 0>;
+ extcon = <&smbb>, <&usb_id>;
+ vbus-supply = <&chg_otg>;
+
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+};
+
+&usb_hs1_phy {
+ status = "okay";
+
+ v1p8-supply = <&pm8941_l6>;
+ v3p3-supply = <&pm8941_l24>;
+
+ extcon = <&smbb>;
+ qcom,init-seq = /bits/ 8 <0x1 0x64>;
+};
diff --git a/arch/arm/boot/dts/qcom-pm8226.dtsi b/arch/arm/boot/dts/qcom-pm8226.dtsi
index 9b7d9d04ded6..eb36d3662464 100644
--- a/arch/arm/boot/dts/qcom-pm8226.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8226.dtsi
@@ -90,6 +90,16 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ pm8226_gpios: gpio@c000 {
+ compatible = "qcom,pm8226-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pm8226_gpios 0 0 8>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
pm8226_1: pm8226@1 {
@@ -98,7 +108,7 @@
#address-cells = <1>;
#size-cells = <0>;
- pm8226_spmi_regulators: pm8226-regulators {
+ pm8226_spmi_regulators: regulators {
compatible = "qcom,pm8226-regulators";
};
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index 9cd49deb9fa7..cd957a1e7cdf 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -27,7 +27,7 @@
bias-pull-up;
};
- usb_id: misc@900 {
+ usb_id: usb-detect@900 {
compatible = "qcom,pm8941-misc";
reg = <0x900>;
interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>;
@@ -59,7 +59,7 @@
chg_otg: otg-vbus { };
};
- pm8941_gpios: gpios@c000 {
+ pm8941_gpios: gpio@c000 {
compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
@@ -101,37 +101,44 @@
#size-cells = <0>;
#io-channel-cells = <1>;
- bat_temp {
- reg = <VADC_LR_MUX1_BAT_THERM>;
+
+ adc-chan@6 {
+ reg = <VADC_VBAT_SNS>;
};
- die_temp {
+
+ adc-chan@8 {
reg = <VADC_DIE_TEMP>;
};
- ref_625mv {
+
+ adc-chan@9 {
reg = <VADC_REF_625MV>;
};
- ref_1250v {
+
+ adc-chan@a {
reg = <VADC_REF_1250MV>;
};
- ref_gnd {
+
+ adc-chan@e {
reg = <VADC_GND_REF>;
};
- ref_vdd {
+
+ adc-chan@f {
reg = <VADC_VDD_VADC>;
};
- vbat_sns {
- reg = <VADC_VBAT_SNS>;
+
+ adc-chan@30 {
+ reg = <VADC_LR_MUX1_BAT_THERM>;
};
};
- pm8941_iadc: iadc@3600 {
+ pm8941_iadc: adc@3600 {
compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
reg = <0x3600>;
interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
qcom,external-resistor-micro-ohms = <10000>;
};
- pm8941_coincell: coincell@2800 {
+ pm8941_coincell: charger@2800 {
compatible = "qcom,pm8941-coincell";
reg = <0x2800>;
status = "disabled";
diff --git a/arch/arm/boot/dts/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom-pma8084.dtsi
index e77602e9f95c..2dd4c6aa71c9 100644
--- a/arch/arm/boot/dts/qcom-pma8084.dtsi
+++ b/arch/arm/boot/dts/qcom-pma8084.dtsi
@@ -27,7 +27,7 @@
bias-pull-up;
};
- pma8084_gpios: gpios@c000 {
+ pma8084_gpios: gpio@c000 {
compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
@@ -64,22 +64,27 @@
#size-cells = <0>;
#io-channel-cells = <1>;
- die_temp {
+ adc-chan@8 {
reg = <VADC_DIE_TEMP>;
};
- ref_625mv {
+
+ adc-chan@9 {
reg = <VADC_REF_625MV>;
};
- ref_1250v {
+
+ adc-chan@a {
reg = <VADC_REF_1250MV>;
};
- ref_buf_625mv {
+
+ adc-chan@c {
reg = <VADC_SPARE1>;
};
- ref_gnd {
+
+ adc-chan@e {
reg = <VADC_GND_REF>;
};
- ref_vdd {
+
+ adc-chan@f {
reg = <VADC_VDD_VADC>;
};
};
diff --git a/arch/arm/boot/dts/qcom-pmx65.dtsi b/arch/arm/boot/dts/qcom-pmx65.dtsi
index abf229a8b75a..1c7fdf59c1f5 100644
--- a/arch/arm/boot/dts/qcom-pmx65.dtsi
+++ b/arch/arm/boot/dts/qcom-pmx65.dtsi
@@ -20,7 +20,7 @@
#thermal-sensor-cells = <0>;
};
- pmx65_gpios: pinctrl@8800 {
+ pmx65_gpios: gpio@8800 {
compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio";
reg = <0x8800>;
gpio-controller;
diff --git a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts
index a4fa468a095f..ac8b4626ae9a 100644
--- a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts
+++ b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts
@@ -282,40 +282,25 @@
};
&tlmm {
- pcie_ep_clkreq_default: pcie_ep_clkreq_default {
- mux {
- pins = "gpio56";
- function = "pcie_clkreq";
- };
- config {
- pins = "gpio56";
- drive-strength = <2>;
- bias-disable;
- };
+ pcie_ep_clkreq_default: pcie-ep-clkreq-default-state {
+ pins = "gpio56";
+ function = "pcie_clkreq";
+ drive-strength = <2>;
+ bias-disable;
};
- pcie_ep_perst_default: pcie_ep_perst_default {
- mux {
- pins = "gpio57";
- function = "gpio";
- };
- config {
- pins = "gpio57";
- drive-strength = <2>;
- bias-pull-down;
- };
+ pcie_ep_perst_default: pcie-ep-perst-default-state {
+ pins = "gpio57";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
};
- pcie_ep_wake_default: pcie_ep_wake_default {
- mux {
- pins = "gpio53";
- function = "gpio";
- };
- config {
- pins = "gpio53";
- drive-strength = <2>;
- bias-disable;
- };
+ pcie_ep_wake_default: pcie-ep-wake-default-state {
+ pins = "gpio53";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi
index c72540223fa9..f1c0dab40992 100644
--- a/arch/arm/boot/dts/qcom-sdx55.dtsi
+++ b/arch/arm/boot/dts/qcom-sdx55.dtsi
@@ -559,6 +559,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 109>;
};
sram@1468f000 {
diff --git a/arch/arm/boot/dts/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom-sdx65.dtsi
index 4cd405db5500..b073e0c63df4 100644
--- a/arch/arm/boot/dts/qcom-sdx65.dtsi
+++ b/arch/arm/boot/dts/qcom-sdx65.dtsi
@@ -441,8 +441,8 @@
interrupt-controller;
};
- imem@1468f000 {
- compatible = "simple-mfd";
+ sram@1468f000 {
+ compatible = "qcom,sdx65-imem", "syscon", "simple-mfd";
reg = <0x1468f000 0x1000>;
ranges = <0x0 0x1468f000 0x1000>;
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/r8a7742.dtsi b/arch/arm/boot/dts/r8a7742.dtsi
index 758a1bf02fae..73be346001cb 100644
--- a/arch/arm/boot/dts/r8a7742.dtsi
+++ b/arch/arm/boot/dts/r8a7742.dtsi
@@ -1298,7 +1298,7 @@
dma-names = "rx", "tx", "rxu", "txu";
};
ssi1: ssi-1 {
- interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>,
<&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index db171e3c62f2..111a6d23159e 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -1252,7 +1252,7 @@
dma-names = "rx", "tx", "rxu", "txu";
};
ssi1: ssi-1 {
- interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>,
<&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index d8f91d9f42ae..777b672b59cc 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -1365,7 +1365,7 @@
dma-names = "rx", "tx", "rxu", "txu";
};
ssi1: ssi-1 {
- interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>,
<&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi
index 9ebe7bfaf0ed..3e0be1b58931 100644
--- a/arch/arm/boot/dts/r8a7793.dtsi
+++ b/arch/arm/boot/dts/r8a7793.dtsi
@@ -1111,7 +1111,7 @@
dma-names = "rx", "tx", "rxu", "txu";
};
ssi1: ssi-1 {
- interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>,
<&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
diff --git a/arch/arm/boot/dts/r9a06g032.dtsi b/arch/arm/boot/dts/r9a06g032.dtsi
index 563024c9a4ae..41e19c0986ce 100644
--- a/arch/arm/boot/dts/r9a06g032.dtsi
+++ b/arch/arm/boot/dts/r9a06g032.dtsi
@@ -199,7 +199,7 @@
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART3>, <&sysctrl R9A06G032_HCLK_UART3>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmamux 0 0 0 0 0 1>, <&dmamux 1 0 0 0 1 1>;
+ dmas = <&dmamux 0 0 0 0 0 1>, <&dmamux 1 0 0 0 1 1>;
dma-names = "rx", "tx";
status = "disabled";
};
@@ -212,7 +212,7 @@
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART4>, <&sysctrl R9A06G032_HCLK_UART4>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmamux 2 0 0 0 2 1>, <&dmamux 3 0 0 0 3 1>;
+ dmas = <&dmamux 2 0 0 0 2 1>, <&dmamux 3 0 0 0 3 1>;
dma-names = "rx", "tx";
status = "disabled";
};
@@ -225,7 +225,7 @@
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART5>, <&sysctrl R9A06G032_HCLK_UART5>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmamux 4 0 0 0 4 1>, <&dmamux 5 0 0 0 5 1>;
+ dmas = <&dmamux 4 0 0 0 4 1>, <&dmamux 5 0 0 0 5 1>;
dma-names = "rx", "tx";
status = "disabled";
};
@@ -238,7 +238,7 @@
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART6>, <&sysctrl R9A06G032_HCLK_UART6>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmamux 6 0 0 0 6 1>, <&dmamux 7 0 0 0 7 1>;
+ dmas = <&dmamux 6 0 0 0 6 1>, <&dmamux 7 0 0 0 7 1>;
dma-names = "rx", "tx";
status = "disabled";
};
@@ -251,7 +251,7 @@
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART7>, <&sysctrl R9A06G032_HCLK_UART7>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmamux 4 0 0 0 20 1>, <&dmamux 5 0 0 0 21 1>;
+ dmas = <&dmamux 4 0 0 0 20 1>, <&dmamux 5 0 0 0 21 1>;
dma-names = "rx", "tx";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/rk3036-evb.dts b/arch/arm/boot/dts/rk3036-evb.dts
index 9fd4d9db9f8f..becdc0b664bf 100644
--- a/arch/arm/boot/dts/rk3036-evb.dts
+++ b/arch/arm/boot/dts/rk3036-evb.dts
@@ -35,11 +35,10 @@
&i2c1 {
status = "okay";
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
};
};
diff --git a/arch/arm/boot/dts/rk3066a-mk808.dts b/arch/arm/boot/dts/rk3066a-mk808.dts
index cfa318a506eb..2db5ba706208 100644
--- a/arch/arm/boot/dts/rk3066a-mk808.dts
+++ b/arch/arm/boot/dts/rk3066a-mk808.dts
@@ -32,7 +32,7 @@
keyup-threshold-microvolt = <2500000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <0>;
diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts
index e7cf18823558..118deacd38c4 100644
--- a/arch/arm/boot/dts/rk3188-radxarock.dts
+++ b/arch/arm/boot/dts/rk3188-radxarock.dts
@@ -71,7 +71,7 @@
#sound-dai-cells = <0>;
};
- ir_recv: gpio-ir-receiver {
+ ir_recv: ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index cdd4a0bd5133..44b54af0bbf9 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -379,7 +379,7 @@
rockchip,pins = <2 RK_PD3 1 &pcfg_pull_none>;
};
- lcdc1_rgb24: ldcd1-rgb24 {
+ lcdc1_rgb24: lcdc1-rgb24 {
rockchip,pins = <2 RK_PA0 1 &pcfg_pull_none>,
<2 RK_PA1 1 &pcfg_pull_none>,
<2 RK_PA2 1 &pcfg_pull_none>,
@@ -607,7 +607,6 @@
&global_timer {
interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
- status = "disabled";
};
&local_timer {
diff --git a/arch/arm/boot/dts/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rk3288-evb-act8846.dts
index be695b8c1f67..8a635c243127 100644
--- a/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ b/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -54,7 +54,7 @@
vin-supply = <&vcc_sys>;
};
- hym8563@51 {
+ rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 399d6b9c5fd4..382d2839cf47 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -28,19 +28,19 @@
press-threshold-microvolt = <300000>;
};
- menu {
+ button-menu {
label = "Menu";
linux,code = <KEY_MENU>;
press-threshold-microvolt = <640000>;
};
- esc {
+ button-esc {
label = "Esc";
linux,code = <KEY_ESC>;
press-threshold-microvolt = <1000000>;
};
- home {
+ button-home {
label = "Home";
linux,code = <KEY_HOME>;
press-threshold-microvolt = <1300000>;
diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi
index 052afe5543e2..3836c61cfb76 100644
--- a/arch/arm/boot/dts/rk3288-firefly.dtsi
+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -233,11 +233,10 @@
vin-supply = <&vcc_sys>;
};
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
interrupt-parent = <&gpio7>;
interrupts = <RK_PA4 IRQ_TYPE_EDGE_FALLING>;
diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts
index 713f55e143c6..db1eb648e0e1 100644
--- a/arch/arm/boot/dts/rk3288-miqi.dts
+++ b/arch/arm/boot/dts/rk3288-miqi.dts
@@ -162,11 +162,10 @@
vin-supply = <&vcc_sys>;
};
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
};
diff --git a/arch/arm/boot/dts/rk3288-rock2-square.dts b/arch/arm/boot/dts/rk3288-rock2-square.dts
index 80e0f07c8e87..13cfdaa95cc7 100644
--- a/arch/arm/boot/dts/rk3288-rock2-square.dts
+++ b/arch/arm/boot/dts/rk3288-rock2-square.dts
@@ -165,11 +165,10 @@
};
&i2c0 {
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
interrupt-parent = <&gpio0>;
interrupts = <RK_PA4 IRQ_TYPE_EDGE_FALLING>;
diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi
index 0ae2bd150e37..793951655b73 100644
--- a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi
+++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi
@@ -241,7 +241,6 @@
interrupt-parent = <&gpio5>;
interrupts = <RK_PC3 IRQ_TYPE_LEVEL_LOW>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "hym8563";
pinctrl-names = "default";
pinctrl-0 = <&hym8563_int>;
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index bf285091a9eb..cb4e42ede56a 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -76,6 +76,13 @@
reg = <0x1013c200 0x20>;
interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
clocks = <&cru CORE_PERI>;
+ status = "disabled";
+ /* The clock source and the sched_clock provided by the arm_global_timer
+ * on Rockchip rk3066a/rk3188 are quite unstable because their rates
+ * depend on the CPU frequency.
+ * Keep the arm_global_timer disabled in order to have the
+ * DW_APB_TIMER (rk3066a) or ROCKCHIP_TIMER (rk3188) selected by default.
+ */
};
local_timer: local-timer@1013c600 {
diff --git a/arch/arm/boot/dts/sama7g5-pinfunc.h b/arch/arm/boot/dts/sama7g5-pinfunc.h
index 4eb30445d205..a67a156e26ab 100644
--- a/arch/arm/boot/dts/sama7g5-pinfunc.h
+++ b/arch/arm/boot/dts/sama7g5-pinfunc.h
@@ -261,7 +261,7 @@
#define PIN_PB2__FLEXCOM6_IO0 PINMUX_PIN(PIN_PB2, 2, 1)
#define PIN_PB2__ADTRG PINMUX_PIN(PIN_PB2, 3, 1)
#define PIN_PB2__A20 PINMUX_PIN(PIN_PB2, 4, 1)
-#define PIN_PB2__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB2, 6, 3)
+#define PIN_PB2__FLEXCOM11_IO1 PINMUX_PIN(PIN_PB2, 6, 3)
#define PIN_PB3 35
#define PIN_PB3__GPIO PINMUX_PIN(PIN_PB3, 0, 0)
#define PIN_PB3__RF1 PINMUX_PIN(PIN_PB3, 1, 1)
@@ -673,7 +673,7 @@
#define PIN_PD8__GPIO PINMUX_PIN(PIN_PD8, 0, 0)
#define PIN_PD8__SDMMC2_DAT3 PINMUX_PIN(PIN_PD8, 1, 1)
#define PIN_PD8__I2SMCC0_DIN0 PINMUX_PIN(PIN_PD8, 3, 1)
-#define PIN_PD8__A11_NANDCLE PINMUX_PIN(PIN_PD8, 4, 2)
+#define PIN_PD8__A22_NANDCLE PINMUX_PIN(PIN_PD8, 4, 2)
#define PIN_PD8__TIOA2 PINMUX_PIN(PIN_PD8, 5, 2)
#define PIN_PD8__FLEXCOM11_IO0 PINMUX_PIN(PIN_PD8, 6, 5)
#define PIN_PD9 105
diff --git a/arch/arm/boot/dts/sama7g5.dtsi b/arch/arm/boot/dts/sama7g5.dtsi
index 7bd8ae8e8d38..ab131762ecb5 100644
--- a/arch/arm/boot/dts/sama7g5.dtsi
+++ b/arch/arm/boot/dts/sama7g5.dtsi
@@ -9,12 +9,15 @@
*
*/
+#include <dt-bindings/iio/adc/at91-sama5d2_adc.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/at91.h>
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/nvmem/microchip,sama7g5-otpc.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
model = "Microchip SAMA7G5 family SoC";
@@ -34,6 +37,7 @@
clocks = <&pmc PMC_TYPE_CORE PMC_CPUPLL>;
clock-names = "cpu";
operating-points-v2 = <&cpu_opp_table>;
+ #cooling-cells = <2>; /* min followed by max */
};
};
@@ -72,6 +76,46 @@
};
};
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&thermal_sensor>;
+
+ trips {
+ cpu_normal: cpu-alert0 {
+ temperature = <90000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ cpu_hot: cpu-alert1 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ cpu_critical: cpu-critical {
+ temperature = <100000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_normal>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+
+ map1 {
+ trip = <&cpu_hot>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+ };
+
clocks {
slow_xtal: slow_xtal {
compatible = "fixed-clock";
@@ -108,6 +152,13 @@
ranges;
};
+ thermal_sensor: thermal-sensor {
+ compatible = "generic-adc-thermal";
+ #thermal-sensor-cells = <0>;
+ io-channels = <&adc AT91_SAMA7G5_ADC_TEMP_CHANNEL>;
+ io-channel-names = "sensor-channel";
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -153,7 +204,7 @@
};
};
- securam: securam@e0000000 {
+ securam: sram@e0000000 {
compatible = "microchip,sama7g5-securam", "atmel,sama5d2-securam", "mmio-sram";
reg = <0xe0000000 0x4000>;
clocks = <&pmc PMC_TYPE_PERIPHERAL 18>;
@@ -420,6 +471,9 @@
atmel,min-sample-rate-hz = <200000>;
atmel,max-sample-rate-hz = <20000000>;
atmel,startup-time-ms = <4>;
+ #io-channel-cells = <1>;
+ nvmem-cells = <&temperature_calib>;
+ nvmem-cell-names = "temperature_calib";
status = "disabled";
};
@@ -888,6 +942,17 @@
reg = <0xe3804000 0x1000>;
};
+ otpc: efuse@e8c00000 {
+ compatible = "microchip,sama7g5-otpc", "syscon";
+ reg = <0xe8c00000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ temperature_calib: calib@1 {
+ reg = <OTP_PKT(1) 76>;
+ };
+ };
+
gic: interrupt-controller@e8c11000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 2459f3cd7dd9..6eda6fdc101b 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -453,7 +453,6 @@
compatible = "altr,socfpga-gate-clk";
clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
clk-gate = <0xa0 8>;
- clk-phase = <0 135>;
};
sdmmc_clk_divided: sdmmc_clk_divided {
@@ -755,7 +754,7 @@
reg = <0xff800000 0x1000>;
};
- mmc: dwmmc0@ff704000 {
+ mmc: mmc@ff704000 {
compatible = "altr,socfpga-dw-mshc";
reg = <0xff704000 0x1000>;
interrupts = <0 139 4>;
@@ -765,6 +764,7 @@
clocks = <&l4_mp_clk>, <&sdmmc_clk_divided>;
clock-names = "biu", "ciu";
resets = <&rst SDMMC_RESET>;
+ altr,sysmgr-syscon = <&sysmgr 0x108 3>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
index 4370e3cbbb4b..3b2a2c9c6547 100644
--- a/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -365,7 +365,6 @@
compatible = "altr,socfpga-a10-gate-clk";
clocks = <&sdmmc_free_clk>;
clk-gate = <0xC8 5>;
- clk-phase = <0 135>;
};
qspi_clk: qspi_clk {
@@ -656,7 +655,7 @@
arm,shared-override;
};
- mmc: dwmmc0@ff808000 {
+ mmc: mmc@ff808000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "altr,socfpga-dw-mshc";
@@ -666,6 +665,7 @@
clocks = <&l4_mp_clk>, <&sdmmc_clk>;
clock-names = "biu", "ciu";
resets = <&rst SDMMC_RESET>;
+ altr,sysmgr-syscon = <&sysmgr 0x28 4>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi b/arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi
index ad7cd14de6b6..41f865c8c098 100644
--- a/arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi
@@ -73,6 +73,7 @@
cap-sd-highspeed;
broken-cd;
bus-width = <4>;
+ clk-phase-sd-hs = <0>, <135>;
};
&osc1 {
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts
index 9aa897b79544..a662df319a84 100644
--- a/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts
@@ -16,11 +16,11 @@
partition@0 {
label = "Boot and fpga data";
- reg = <0x0 0x02000000>;
+ reg = <0x0 0x02500000>;
};
partition@1c00000 {
label = "Root Filesystem - JFFS2";
- reg = <0x02000000 0x06000000>;
+ reg = <0x02500000 0x05500000>;
};
};
};
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
index 64dc0799f3d7..d3969367f4b5 100644
--- a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
@@ -12,6 +12,7 @@
cap-mmc-highspeed;
broken-cd;
bus-width = <4>;
+ clk-phase-sd-hs = <0>, <135>;
};
&eccmgr {
diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi
index 22dbf07afcff..40fecde65c54 100644
--- a/arch/arm/boot/dts/socfpga_arria5.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria5.dtsi
@@ -18,11 +18,12 @@
};
};
- mmc0: dwmmc0@ff704000 {
+ mmc0: mmc@ff704000 {
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
+ clk-phase-sd-hs = <0>, <135>;
};
sysmgr@ffd08000 {
diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts
index 7f5458d8fccc..c48385702a85 100644
--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts
@@ -29,22 +29,22 @@
leds {
compatible = "gpio-leds";
- hps0 {
+ led-hps0 {
label = "hps_led0";
gpios = <&porta 0 1>;
};
- hps1 {
+ led-hps1 {
label = "hps_led1";
gpios = <&portb 11 1>;
};
- hps2 {
+ led-hps2 {
label = "hps_led2";
gpios = <&porta 17 1>;
};
- hps3 {
+ led-hps3 {
label = "hps_led3";
gpios = <&porta 18 1>;
};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
index 319a71e41ea4..305fe207b237 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
@@ -18,11 +18,12 @@
};
};
- mmc0: dwmmc0@ff704000 {
+ mmc0: mmc@ff704000 {
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
+ clk-phase-sd-hs = <0>, <135>;
};
sysmgr@ffd08000 {
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dts b/arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dts
index c8f051fb2bf6..bedf577cb056 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dts
@@ -33,7 +33,7 @@
leds {
compatible = "gpio-leds";
- hps0 {
+ led-hps0 {
label = "hps_led0";
gpios = <&portb 24 0>;
linux,default-trigger = "heartbeat";
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi
index bd92806ffc12..3b9daddf91cd 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi
+++ b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi
@@ -18,5 +18,6 @@
&mmc0 { /* On-SoM eMMC */
bus-width = <8>;
+ clk-phase-sd-hs = <0>, <135>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
index b2241205c7a9..c7f5fa0ba0f2 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -29,22 +29,22 @@
leds {
compatible = "gpio-leds";
- hps0 {
+ led-hps0 {
label = "hps_led0";
gpios = <&portb 15 1>;
};
- hps1 {
+ led-hps1 {
label = "hps_led1";
gpios = <&portb 14 1>;
};
- hps2 {
+ led-hps2 {
label = "hps_led2";
gpios = <&portb 13 1>;
};
- hps3 {
+ led-hps3 {
label = "hps_led3";
gpios = <&portb 12 1>;
};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
index f24f17c2f5ee..e0630b0eed03 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
@@ -141,7 +141,7 @@
reg = <0x50>;
};
- i2cswitch@70 {
+ i2c-mux@70 {
compatible = "nxp,pca9548";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
index a77846f73b34..3d0d806888b7 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -29,7 +29,7 @@
};
};
- dwmmc0@ff704000 {
+ mmc@ff704000 {
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
index fd41243a0b2c..6b67c0ceaed9 100644
--- a/arch/arm/boot/dts/spear600.dtsi
+++ b/arch/arm/boot/dts/spear600.dtsi
@@ -47,7 +47,7 @@
compatible = "arm,pl110", "arm,primecell";
reg = <0xfc200000 0x1000>;
interrupt-parent = <&vic1>;
- interrupts = <12>;
+ interrupts = <13>;
status = "disabled";
};
@@ -207,6 +207,36 @@
interrupts = <6>;
status = "disabled";
};
+
+ ssp1: spi@d0100000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xd0100000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&vic0>;
+ interrupts = <26>;
+ status = "disabled";
+ };
+
+ ssp2: spi@d0180000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xd0180000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&vic0>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ ssp3: spi@d8180000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xd8180000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&vic1>;
+ interrupts = <5>;
+ status = "disabled";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index 9afe8301bd47..a42a4fd69299 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -1149,17 +1149,15 @@
compatible = "stericsson,ux500-cryp";
reg = <0xa03cb000 0x1000>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
-
- v-ape-supply = <&db8500_vape_reg>;
clocks = <&prcc_pclk 6 1>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
hash@a03c2000 {
compatible = "stericsson,ux500-hash";
reg = <0xa03c2000 0x1000>;
-
- v-ape-supply = <&db8500_vape_reg>;
clocks = <&prcc_pclk 6 2>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
};
};
diff --git a/arch/arm/boot/dts/ste-ux500-samsung-codina-tmo.dts b/arch/arm/boot/dts/ste-ux500-samsung-codina-tmo.dts
index 27a3ab7e25e1..e036393d5415 100644
--- a/arch/arm/boot/dts/ste-ux500-samsung-codina-tmo.dts
+++ b/arch/arm/boot/dts/ste-ux500-samsung-codina-tmo.dts
@@ -247,7 +247,7 @@
};
};
- spi-gpio-0 {
+ spi {
compatible = "spi-gpio";
/* Clock on GPIO220, pin SCL */
sck-gpios = <&gpio6 28 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/ste-ux500-samsung-codina.dts b/arch/arm/boot/dts/ste-ux500-samsung-codina.dts
index b88f0c07873d..1a6d24a7ccb8 100644
--- a/arch/arm/boot/dts/ste-ux500-samsung-codina.dts
+++ b/arch/arm/boot/dts/ste-ux500-samsung-codina.dts
@@ -333,7 +333,7 @@
};
};
- spi-gpio-0 {
+ spi {
compatible = "spi-gpio";
/* Clock on GPIO220, pin SCL */
sck-gpios = <&gpio6 28 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/ste-ux500-samsung-gavini.dts b/arch/arm/boot/dts/ste-ux500-samsung-gavini.dts
index 7231bc745200..5b445fa4c8c0 100644
--- a/arch/arm/boot/dts/ste-ux500-samsung-gavini.dts
+++ b/arch/arm/boot/dts/ste-ux500-samsung-gavini.dts
@@ -277,7 +277,7 @@
/*
* TODO: See if we can use the PL023 for this instead.
*/
- spi-gpio-0 {
+ spi {
compatible = "spi-gpio";
/* Clock on GPIO220, pin SCL */
sck-gpios = <&gpio6 28 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts
index 69387e8754a9..e901cb76b899 100644
--- a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts
+++ b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts
@@ -271,7 +271,7 @@
* this derivative is 3wire support, so it cannot be used to drive
* this panel interface. We have to use GPIO bit-banging instead.
*/
- spi-gpio-0 {
+ spi {
compatible = "spi-gpio";
/* Clock on GPIO220 */
sck-gpios = <&gpio6 28 GPIO_ACTIVE_HIGH>;
@@ -373,9 +373,13 @@
#address-cells = <1>;
#size-cells = <0>;
- nfc@30 {
- compatible = "nxp,pn547", "nxp,nxp-nci-i2c";
- reg = <0x30>;
+ /* This is only mounted on the GT-I9070P */
+ nfc@2b { /* 0x30? */
+ /* NXP NFC circuit PN544 C1 marked NXP 44501 */
+ compatible = "nxp,pn544-i2c";
+ /* IF0, IF1 high, gives I2C address 0x2B */
+ reg = <0x2b>;
+ clock-frequency = <400000>;
/* NFC IRQ on GPIO32 */
interrupt-parent = <&gpio1>;
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
@@ -384,7 +388,7 @@
/* GPIO88 */
enable-gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
- pinctrl-0 = <&pn547_janice_default>;
+ pinctrl-0 = <&pn544_janice_default>;
};
};
@@ -959,7 +963,7 @@
};
};
nfc {
- pn547_janice_default: pn547_janice {
+ pn544_janice_default: pn544_janice {
/* Interrupt line */
janice_cfg1 {
pins = "GPIO32_V2";
diff --git a/arch/arm/boot/dts/ste-ux500-samsung-kyle.dts b/arch/arm/boot/dts/ste-ux500-samsung-kyle.dts
index 167846df3104..45fab5283a9d 100644
--- a/arch/arm/boot/dts/ste-ux500-samsung-kyle.dts
+++ b/arch/arm/boot/dts/ste-ux500-samsung-kyle.dts
@@ -315,6 +315,21 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&u1rxtx_a_1_default &u1ctsrts_a_1_default>;
pinctrl-1 = <&u1rxtx_a_1_sleep &u1ctsrts_a_1_sleep>;
+
+ gnss {
+ /* The CSRG05TA03-ICJE-R is a SirfStarV 5t chip */
+ compatible = "csr,csrg05ta03-icje-r";
+ /* GPS_RSTN on GPIO21 */
+ reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+ /* GPS_ON_OFF on GPIO86 */
+ sirf,onoff-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
+ /* GPS_1V8 (VSMPS2) */
+ vcc-supply = <&db8500_vsmps2_reg>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&g05ta03_kyle_default>;
+ /* According to /etc/sirfgps.conf */
+ current-speed = <460800>;
+ };
};
/* Debugging console UART connected to AB8505 USB */
@@ -674,6 +689,20 @@
};
};
};
+ g05ta03 {
+ g05ta03_kyle_default: g05ta03 {
+ /* Reset line, start out de-asserted */
+ kyle_cfg1 {
+ pins = "GPIO21_AB3";
+ ste,config = <&gpio_out_hi>;
+ };
+ /* GPS_ON_OFF, start out deasserted (off) */
+ kyle_cfg2 {
+ pins = "GPIO86_C6";
+ ste,config = <&gpio_out_lo>;
+ };
+ };
+ };
};
&ab8505_gpio {
diff --git a/arch/arm/boot/dts/stih410-b2260.dts b/arch/arm/boot/dts/stih410-b2260.dts
index 26d93f26f6d0..240b62040000 100644
--- a/arch/arm/boot/dts/stih410-b2260.dts
+++ b/arch/arm/boot/dts/stih410-b2260.dts
@@ -27,26 +27,26 @@
leds {
compatible = "gpio-leds";
- user_green_1 {
+ led-user-green-1 {
label = "User_green_1";
gpios = <&pio1 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
- user_green_2 {
+ led-user-green-2 {
label = "User_green_2";
gpios = <&pio4 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- user_green_3 {
+ led-user-green-3 {
label = "User_green_3";
gpios = <&pio2 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- user_green_4 {
+ led-user-green-4 {
label = "User_green_4";
gpios = <&pio2 5 GPIO_ACTIVE_LOW>;
default-state = "off";
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
index d21bcc7c1271..53ac6c2b7b7d 100644
--- a/arch/arm/boot/dts/stih418-b2199.dts
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -26,12 +26,12 @@
leds {
compatible = "gpio-leds";
- red {
+ led-red {
label = "Front Panel LED";
gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
- green {
+ led-green {
gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
diff --git a/arch/arm/boot/dts/stih418-b2264.dts b/arch/arm/boot/dts/stih418-b2264.dts
index a99604bebf8c..34a518b037ab 100644
--- a/arch/arm/boot/dts/stih418-b2264.dts
+++ b/arch/arm/boot/dts/stih418-b2264.dts
@@ -76,7 +76,7 @@
soc {
leds {
compatible = "gpio-leds";
- green {
+ led-green {
gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index 2aa94605d3d4..920a0bad7494 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -9,12 +9,12 @@
/ {
leds {
compatible = "gpio-leds";
- red {
+ led-red {
label = "Front Panel LED";
gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
- green {
+ led-green {
gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
index 2059593da21d..28e3deb20e1e 100644
--- a/arch/arm/boot/dts/stm32h743.dtsi
+++ b/arch/arm/boot/dts/stm32h743.dtsi
@@ -375,7 +375,6 @@
arm,primecell-periphid = <0x10153180>;
reg = <0x52007000 0x1000>;
interrupts = <49>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC1_CK>;
clock-names = "apb_pclk";
resets = <&rcc STM32H7_AHB3_RESET(SDMMC1)>;
@@ -389,7 +388,6 @@
arm,primecell-periphid = <0x10153180>;
reg = <0x48022400 0x400>;
interrupts = <124>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC2_CK>;
clock-names = "apb_pclk";
resets = <&rcc STM32H7_AHB2_RESET(SDMMC2)>;
diff --git a/arch/arm/boot/dts/stm32mp13-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp13-pinctrl.dtsi
index efdd163eba30..d377d4c0bef5 100644
--- a/arch/arm/boot/dts/stm32mp13-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp13-pinctrl.dtsi
@@ -6,6 +6,13 @@
#include <dt-bindings/pinctrl/stm32-pinfunc.h>
&pinctrl {
+ adc1_usb_cc_pins_a: adc1-usb-cc-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 12, ANALOG)>, /* ADC1 in6 */
+ <STM32_PINMUX('A', 3, ANALOG)>; /* ADC1 in12 */
+ };
+ };
+
i2c1_pins_a: i2c1-0 {
pins {
pinmux = <STM32_PINMUX('D', 12, AF5)>, /* I2C1_SCL */
@@ -40,6 +47,13 @@
};
};
+ mcp23017_pins_a: mcp23017-0 {
+ pins {
+ pinmux = <STM32_PINMUX('G', 12, GPIO)>;
+ bias-pull-up;
+ };
+ };
+
sdmmc1_b4_pins_a: sdmmc1-b4-0 {
pins {
pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
@@ -165,6 +179,13 @@
};
};
+ stm32g0_intn_pins_a: stm32g0-intn-0 {
+ pins {
+ pinmux = <STM32_PINMUX('I', 2, GPIO)>;
+ bias-pull-up;
+ };
+ };
+
uart4_pins_a: uart4-0 {
pins1 {
pinmux = <STM32_PINMUX('D', 6, AF8)>; /* UART4_TX */
diff --git a/arch/arm/boot/dts/stm32mp131.dtsi b/arch/arm/boot/dts/stm32mp131.dtsi
index dd35a607073d..accc3824f7e9 100644
--- a/arch/arm/boot/dts/stm32mp131.dtsi
+++ b/arch/arm/boot/dts/stm32mp131.dtsi
@@ -77,6 +77,28 @@
always-on;
};
+ /* PWR 1v1, 1v8 and 3v3 regulators defined as fixed, waiting for SCMI */
+ reg11: reg11 {
+ compatible = "regulator-fixed";
+ regulator-name = "reg11";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ reg18: reg18 {
+ compatible = "regulator-fixed";
+ regulator-name = "reg18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ usb33: usb33 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -231,6 +253,66 @@
dma-channels = <16>;
};
+ adc_2: adc@48004000 {
+ compatible = "st,stm32mp13-adc-core";
+ reg = <0x48004000 0x400>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc ADC2>, <&rcc ADC2_K>;
+ clock-names = "bus", "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ adc2: adc@0 {
+ compatible = "st,stm32mp13-adc";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0>;
+ interrupt-parent = <&adc_2>;
+ interrupts = <0>;
+ dmas = <&dmamux1 10 0x400 0x80000001>;
+ dma-names = "rx";
+ status = "disabled";
+
+ channel@13 {
+ reg = <13>;
+ label = "vrefint";
+ };
+ channel@14 {
+ reg = <14>;
+ label = "vddcore";
+ };
+ channel@16 {
+ reg = <16>;
+ label = "vddcpu";
+ };
+ channel@17 {
+ reg = <17>;
+ label = "vddq_ddr";
+ };
+ };
+ };
+
+ usbotg_hs: usb@49000000 {
+ compatible = "st,stm32mp15-hsotg", "snps,dwc2";
+ reg = <0x49000000 0x40000>;
+ clocks = <&rcc USBO_K>;
+ clock-names = "otg";
+ resets = <&rcc USBO_R>;
+ reset-names = "dwc2";
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ g-rx-fifo-size = <512>;
+ g-np-tx-fifo-size = <32>;
+ g-tx-fifo-size = <256 16 16 16 16 16 16 16>;
+ dr_mode = "otg";
+ otg-rev = <0x200>;
+ usb33d-supply = <&usb33>;
+ status = "disabled";
+ };
+
spi4: spi@4c002000 {
compatible = "st,stm32h7-spi";
reg = <0x4c002000 0x400>;
@@ -354,7 +436,6 @@
arm,primecell-periphid = <0x20253180>;
reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC1_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC1_R>;
@@ -369,7 +450,6 @@
arm,primecell-periphid = <0x20253180>;
reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC2_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC2_R>;
@@ -379,6 +459,25 @@
status = "disabled";
};
+ usbh_ohci: usb@5800c000 {
+ compatible = "generic-ohci";
+ reg = <0x5800c000 0x1000>;
+ clocks = <&usbphyc>, <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ usbh_ehci: usb@5800d000 {
+ compatible = "generic-ehci";
+ reg = <0x5800d000 0x1000>;
+ clocks = <&usbphyc>, <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ companion = <&usbh_ohci>;
+ status = "disabled";
+ };
+
iwdg2: watchdog@5a002000 {
compatible = "st,stm32mp1-iwdg";
reg = <0x5a002000 0x400>;
@@ -387,6 +486,29 @@
status = "disabled";
};
+ usbphyc: usbphyc@5a006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "st,stm32mp1-usbphyc";
+ reg = <0x5a006000 0x1000>;
+ clocks = <&rcc USBPHY_K>;
+ resets = <&rcc USBPHY_R>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>;
+ status = "disabled";
+
+ usbphyc_port0: usb-phy@0 {
+ #phy-cells = <0>;
+ reg = <0>;
+ };
+
+ usbphyc_port1: usb-phy@1 {
+ #phy-cells = <1>;
+ reg = <1>;
+ };
+ };
+
rtc: rtc@5c004000 {
compatible = "st,stm32mp1-rtc";
reg = <0x5c004000 0x400>;
diff --git a/arch/arm/boot/dts/stm32mp133.dtsi b/arch/arm/boot/dts/stm32mp133.dtsi
index 531c263c9f46..df451c3c2a26 100644
--- a/arch/arm/boot/dts/stm32mp133.dtsi
+++ b/arch/arm/boot/dts/stm32mp133.dtsi
@@ -33,5 +33,36 @@
bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>;
status = "disabled";
};
+
+ adc_1: adc@48003000 {
+ compatible = "st,stm32mp13-adc-core";
+ reg = <0x48003000 0x400>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc ADC1>, <&rcc ADC1_K>;
+ clock-names = "bus", "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ adc1: adc@0 {
+ compatible = "st,stm32mp13-adc";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0>;
+ interrupt-parent = <&adc_1>;
+ interrupts = <0>;
+ dmas = <&dmamux1 9 0x400 0x80000001>;
+ dma-names = "rx";
+ status = "disabled";
+
+ channel@18 {
+ reg = <18>;
+ label = "vrefint";
+ };
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/stm32mp135f-dk.dts b/arch/arm/boot/dts/stm32mp135f-dk.dts
index de341d17e87d..9ff5a3eaf55b 100644
--- a/arch/arm/boot/dts/stm32mp135f-dk.dts
+++ b/arch/arm/boot/dts/stm32mp135f-dk.dts
@@ -59,6 +59,22 @@
};
};
+ v3v3_sw: v3v3-sw {
+ compatible = "regulator-fixed";
+ regulator-name = "v3v3_sw";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_adc: vdd-adc {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_adc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
vdd_sd: vdd-sd {
compatible = "regulator-fixed";
regulator-name = "vdd_sd";
@@ -66,6 +82,39 @@
regulator-max-microvolt = <2900000>;
regulator-always-on;
};
+
+ vdd_usb: vdd-usb {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_usb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+};
+
+&adc_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&adc1_usb_cc_pins_a>;
+ vdda-supply = <&vdd_adc>;
+ vref-supply = <&vdd_adc>;
+ status = "okay";
+ adc1: adc@0 {
+ status = "okay";
+ /*
+ * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in6 & in12.
+ * Use at least 5 * RC time, e.g. 5 * (Rp + Rd) * C:
+ * 5 * (5.1 + 47kOhms) * 5pF => 1.3us.
+ * Use arbitrary margin here (e.g. 5us).
+ */
+ channel@6 {
+ reg = <6>;
+ st,min-sample-time-ns = <5000>;
+ };
+ channel@12 {
+ reg = <12>;
+ st,min-sample-time-ns = <5000>;
+ };
+ };
};
&i2c1 {
@@ -79,6 +128,42 @@
/* spare dmas for other usage */
/delete-property/dmas;
/delete-property/dma-names;
+
+ mcp23017: pinctrl@21 {
+ compatible = "microchip,mcp23017";
+ reg = <0x21>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpiog>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcp23017_pins_a>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ microchip,irq-mirror;
+ };
+
+ typec@53 {
+ compatible = "st,stm32g0-typec";
+ reg = <0x53>;
+ /* Alert pin on PI2 */
+ interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpioi>;
+ /* Internal pull-up on PI2 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&stm32g0_intn_pins_a>;
+ firmware-name = "stm32g0-ucsi.mp135f-dk.fw";
+ connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+
+ port {
+ con_usb_c_g0_ep: endpoint {
+ remote-endpoint = <&usbotg_hs_ep>;
+ };
+ };
+ };
+ };
};
&i2c5 {
@@ -108,7 +193,7 @@
pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_clk_pins_a>;
pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_clk_pins_a>;
pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
- broken-cd;
+ cd-gpios = <&gpioh 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
disable-wp;
st,neg-edge;
bus-width = <4>;
@@ -128,3 +213,60 @@
pinctrl-0 = <&uart4_pins_a>;
status = "okay";
};
+
+&usbh_ehci {
+ phys = <&usbphyc_port0>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /* onboard HUB */
+ hub@1 {
+ compatible = "usb424,2514";
+ reg = <1>;
+ vdd-supply = <&v3v3_sw>;
+ };
+};
+
+&usbotg_hs {
+ phys = <&usbphyc_port1 0>;
+ phy-names = "usb2-phy";
+ usb-role-switch;
+ status = "okay";
+ port {
+ usbotg_hs_ep: endpoint {
+ remote-endpoint = <&con_usb_c_g0_ep>;
+ };
+ };
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+ st,current-boost-microamp = <1000>;
+ st,decrease-hs-slew-rate;
+ st,tune-hs-dc-level = <2>;
+ st,enable-hs-rftime-reduction;
+ st,trim-hs-current = <11>;
+ st,trim-hs-impedance = <2>;
+ st,tune-squelch-level = <1>;
+ st,enable-hs-rx-gain-eq;
+ st,no-hs-ftime-ctrl;
+ st,no-lsfs-sc;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+ st,current-boost-microamp = <1000>;
+ st,decrease-hs-slew-rate;
+ st,tune-hs-dc-level = <2>;
+ st,enable-hs-rftime-reduction;
+ st,trim-hs-current = <11>;
+ st,trim-hs-impedance = <2>;
+ st,tune-squelch-level = <1>;
+ st,enable-hs-rx-gain-eq;
+ st,no-hs-ftime-ctrl;
+ st,no-lsfs-sc;
+};
diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
index e02b3f5d44cb..5491b6c4dec2 100644
--- a/arch/arm/boot/dts/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/stm32mp151.dtsi
@@ -1118,7 +1118,6 @@
arm,primecell-periphid = <0x00253180>;
reg = <0x48004000 0x400>;
interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC3_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC3_R>;
@@ -1439,7 +1438,6 @@
arm,primecell-periphid = <0x00253180>;
reg = <0x58005000 0x1000>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC1_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC1_R>;
@@ -1454,7 +1452,6 @@
arm,primecell-periphid = <0x00253180>;
reg = <0x58007000 0x1000>;
interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC2_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC2_R>;
diff --git a/arch/arm/boot/dts/stm32mp151a-dhcor-testbench.dts b/arch/arm/boot/dts/stm32mp151a-dhcor-testbench.dts
new file mode 100644
index 000000000000..e0f828ecc2fa
--- /dev/null
+++ b/arch/arm/boot/dts/stm32mp151a-dhcor-testbench.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+/dts-v1/;
+
+#include "stm32mp151.dtsi"
+#include "stm32mp15xx-dhcor-som.dtsi"
+#include "stm32mp15xx-dhcor-testbench.dtsi"
+
+/ {
+ model = "DH electronics STM32MP151A DHCOR Testbench";
+ compatible = "dh,stm32mp151a-dhcor-testbench",
+ "dh,stm32mp151a-dhcor-som",
+ "st,stm32mp151";
+};
diff --git a/arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts b/arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts
index 2e3c9fbb4eb3..275167f26fd9 100644
--- a/arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dhcor-avenger96.dts
@@ -13,7 +13,6 @@
/dts-v1/;
#include "stm32mp157.dtsi"
-#include "stm32mp15xc.dtsi"
#include "stm32mp15xx-dhcor-som.dtsi"
#include "stm32mp15xx-dhcor-avenger96.dtsi"
diff --git a/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi b/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi
index 30156b7546ed..aef02e6421a3 100644
--- a/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi
@@ -173,7 +173,7 @@
phy-handle = <&phy0>;
st,eth-ref-clk-sel;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 050c3c27a420..a665189fe621 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -144,7 +144,7 @@
max-speed = <1000>;
phy-handle = <&phy0>;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
@@ -370,6 +370,14 @@
&usbh_ehci {
phys = <&usbphyc_port0>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /* onboard HUB */
+ hub@1 {
+ compatible = "usb424,2514";
+ reg = <1>;
+ vdd-supply = <&v3v3>;
+ };
};
&usbotg_hs {
@@ -393,6 +401,11 @@
st,tune-squelch-level = <3>;
st,tune-hs-rx-offset = <2>;
st,no-lsfs-sc;
+
+ connector {
+ compatible = "usb-a-connector";
+ vbus-supply = <&vbus_sw>;
+ };
};
&usbphyc_port1 {
diff --git a/arch/arm/boot/dts/stm32mp157c-lxa-mc1.dts b/arch/arm/boot/dts/stm32mp157c-lxa-mc1.dts
index e8d2ec41d537..cb00ce7cec8b 100644
--- a/arch/arm/boot/dts/stm32mp157c-lxa-mc1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-lxa-mc1.dts
@@ -112,7 +112,7 @@
phy-handle = <&ethphy>;
status = "okay";
- mdio0 {
+ mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/stm32mp157c-odyssey.dts b/arch/arm/boot/dts/stm32mp157c-odyssey.dts
index ed66d25b8bf3..a8b3f7a54703 100644
--- a/arch/arm/boot/dts/stm32mp157c-odyssey.dts
+++ b/arch/arm/boot/dts/stm32mp157c-odyssey.dts
@@ -41,7 +41,7 @@
assigned-clock-rates = <125000000>; /* Clock PLL4 to 750Mhz in ATF/U-Boot */
st,eth-clk-sel;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi
index 5f586f024060..4709677151aa 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi
@@ -242,7 +242,7 @@
sai2a_port: port {
sai2a_endpoint: endpoint {
remote-endpoint = <&sgtl5000_tx_endpoint>;
- format = "i2s";
+ dai-format = "i2s";
mclk-fs = <512>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <16>;
@@ -260,7 +260,7 @@
sai2b_port: port {
sai2b_endpoint: endpoint {
remote-endpoint = <&sgtl5000_rx_endpoint>;
- format = "i2s";
+ dai-format = "i2s";
mclk-fs = <512>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <16>;
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi
index 238a611192e7..002f221f1694 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi
@@ -125,7 +125,7 @@
max-speed = <100>;
phy-handle = <&phy0>;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi
index 90933077d66d..50af4a27d6be 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi
@@ -66,7 +66,6 @@
led4 {
label = "green:user3";
gpios = <&gpiog 1 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "none";
default-state = "off";
panic-indicator;
};
@@ -100,7 +99,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpios = <&gpioz 3 GPIO_ACTIVE_HIGH>;
+ gpio = <&gpioz 3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
};
@@ -151,7 +150,7 @@
max-speed = <1000>;
phy-handle = <&phy0>;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
@@ -359,7 +358,7 @@
sai2a_port: port {
sai2a_endpoint: endpoint {
remote-endpoint = <&adv7513_i2s0>;
- format = "i2s";
+ dai-format = "i2s";
mclk-fs = <256>;
};
};
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi
index 27477bb219de..c32c160f97f2 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi
@@ -78,7 +78,7 @@
max-speed = <1000>;
phy-handle = <&phy0>;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-testbench.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-testbench.dtsi
new file mode 100644
index 000000000000..5fdb74b652ac
--- /dev/null
+++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-testbench.dtsi
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+/ {
+ aliases {
+ ethernet0 = &ethernet0;
+ mmc0 = &sdmmc1;
+ mmc1 = &sdmmc2;
+ serial0 = &uart4;
+ serial1 = &uart7;
+ spi0 = &qspi;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ sd_switch: regulator-sd_switch {
+ compatible = "regulator-gpio";
+ regulator-name = "sd_switch";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2900000>;
+ regulator-type = "voltage";
+ regulator-always-on;
+
+ gpios = <&gpioi 5 GPIO_ACTIVE_HIGH>;
+ gpios-states = <0>;
+ states = <1800000 0x1>,
+ <2900000 0x0>;
+ };
+};
+
+&adc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&adc12_ain_pins_b>;
+ vdd-supply = <&vdd>;
+ vdda-supply = <&vdda>;
+ vref-supply = <&vdda>;
+ status = "okay";
+
+ adc1: adc@0 {
+ st,adc-channels = <0 1 6>;
+ st,min-sample-time-nsecs = <5000>;
+ status = "okay";
+ };
+
+ adc2: adc@100 {
+ st,adc-channels = <0 1 2>;
+ st,min-sample-time-nsecs = <5000>;
+ status = "okay";
+ };
+};
+
+&ethernet0 {
+ status = "okay";
+ pinctrl-0 = <&ethernet0_rgmii_pins_c>;
+ pinctrl-1 = <&ethernet0_rgmii_sleep_pins_c>;
+ pinctrl-names = "default", "sleep";
+ phy-mode = "rgmii";
+ max-speed = <1000>;
+ phy-handle = <&phy0>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dwmac-mdio";
+ reset-gpios = <&gpioz 2 GPIO_ACTIVE_LOW>;
+ reset-delay-us = <1000>;
+ reset-post-delay-us = <1000>;
+
+ phy0: ethernet-phy@7 {
+ reg = <7>;
+
+ rxc-skew-ps = <1500>;
+ rxdv-skew-ps = <540>;
+ rxd0-skew-ps = <420>;
+ rxd1-skew-ps = <420>;
+ rxd2-skew-ps = <420>;
+ rxd3-skew-ps = <420>;
+
+ txc-skew-ps = <1440>;
+ txen-skew-ps = <540>;
+ txd0-skew-ps = <420>;
+ txd1-skew-ps = <420>;
+ txd2-skew-ps = <420>;
+ txd3-skew-ps = <420>;
+ };
+ };
+};
+
+&sdmmc1 {
+ pinctrl-names = "default", "opendrain", "sleep";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_b>;
+ pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_b>;
+ pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_b>;
+ cd-gpios = <&gpioi 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+ disable-wp;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ vqmmc-supply = <&sd_switch>;
+ status = "okay";
+};
+
+&sdmmc2 {
+ pinctrl-names = "default", "opendrain", "sleep";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_c>;
+ pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_c>;
+ pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_c>;
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ no-sd;
+ no-sdio;
+ non-removable;
+ st,neg-edge;
+ vmmc-supply = <&v3v3>;
+ vqmmc-supply = <&v3v3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_b>;
+ /delete-property/dmas;
+ /delete-property/dma-names;
+ status = "okay";
+};
+
+&uart7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ uart-has-rtscts;
+ /delete-property/dmas;
+ /delete-property/dma-names;
+ status = "okay";
+};
+
+&usbh_ehci {
+ phys = <&usbphyc_port0>;
+ status = "okay";
+};
+
+&usbh_ohci {
+ phys = <&usbphyc_port0>;
+ status = "okay";
+};
+
+&usbotg_hs {
+ pinctrl-0 = <&usbotg_hs_pins_a>;
+ pinctrl-names = "default";
+ phy-names = "usb2-phy";
+ phys = <&usbphyc_port1 0>;
+ status = "okay";
+ vbus-supply = <&vbus_otg>;
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index 8b48d3c89a04..7798a2e17c5c 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -141,7 +141,7 @@
max-speed = <1000>;
phy-handle = <&phy0>;
- mdio0 {
+ mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
@@ -508,7 +508,7 @@
sai2a_port: port {
sai2a_endpoint: endpoint {
remote-endpoint = <&cs42l51_tx_endpoint>;
- format = "i2s";
+ dai-format = "i2s";
mclk-fs = <256>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <32>;
@@ -526,7 +526,7 @@
sai2b_port: port {
sai2b_endpoint: endpoint {
remote-endpoint = <&cs42l51_rx_endpoint>;
- format = "i2s";
+ dai-format = "i2s";
mclk-fs = <256>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <32>;
diff --git a/arch/arm/boot/dts/suniv-f1c100s.dtsi b/arch/arm/boot/dts/suniv-f1c100s.dtsi
index 0edc1724407b..9455d27e516e 100644
--- a/arch/arm/boot/dts/suniv-f1c100s.dtsi
+++ b/arch/arm/boot/dts/suniv-f1c100s.dtsi
@@ -166,6 +166,12 @@
drive-strength = <30>;
};
+ /omit-if-no-ref/
+ i2c0_pd_pins: i2c0-pd-pins {
+ pins = "PD0", "PD12";
+ function = "i2c0";
+ };
+
spi0_pc_pins: spi0-pc-pins {
pins = "PC0", "PC1", "PC2", "PC3";
function = "spi0";
@@ -177,6 +183,42 @@
};
};
+ i2c0: i2c@1c27000 {
+ compatible = "allwinner,suniv-f1c100s-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x01c27000 0x400>;
+ interrupts = <7>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@1c27400 {
+ compatible = "allwinner,suniv-f1c100s-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x01c27400 0x400>;
+ interrupts = <8>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@1c27800 {
+ compatible = "allwinner,suniv-f1c100s-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x01c27800 0x400>;
+ interrupts = <9>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
timer@1c20c00 {
compatible = "allwinner,suniv-f1c100s-timer";
reg = <0x01c20c00 0x90>;
@@ -192,6 +234,34 @@
clocks = <&osc32k>;
};
+ pwm: pwm@1c21000 {
+ compatible = "allwinner,suniv-f1c100s-pwm",
+ "allwinner,sun7i-a20-pwm";
+ reg = <0x01c21000 0x400>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ ir: ir@1c22c00 {
+ compatible = "allwinner,suniv-f1c100s-ir",
+ "allwinner,sun6i-a31-ir";
+ reg = <0x01c22c00 0x400>;
+ clocks = <&ccu CLK_BUS_IR>, <&ccu CLK_IR>;
+ clock-names = "apb", "ir";
+ resets = <&ccu RST_BUS_IR>;
+ interrupts = <6>;
+ status = "disabled";
+ };
+
+ lradc: lradc@1c23400 {
+ compatible = "allwinner,suniv-f1c100s-lradc",
+ "allwinner,sun8i-a83t-r-lradc";
+ reg = <0x01c23400 0x400>;
+ interrupts = <22>;
+ status = "disabled";
+ };
+
uart0: serial@1c25000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c25000 0x400>;
diff --git a/arch/arm/boot/dts/sunplus-sp7021.dtsi b/arch/arm/boot/dts/sunplus-sp7021.dtsi
index 7dc4ce3619c7..ae9bbe0320b8 100644
--- a/arch/arm/boot/dts/sunplus-sp7021.dtsi
+++ b/arch/arm/boot/dts/sunplus-sp7021.dtsi
@@ -211,7 +211,6 @@
interrupt-names = "dma_w", "master_risc", "slave_risc";
clocks = <&clkc CLK_SPI_COMBO_1>;
resets = <&rstc RST_SPI_COMBO_1>;
- spi-max-frequency = <25000000>;
status = "disabled";
};
@@ -225,7 +224,6 @@
interrupt-names = "dma_w", "master_risc", "slave_risc";
clocks = <&clkc CLK_SPI_COMBO_2>;
resets = <&rstc RST_SPI_COMBO_2>;
- spi-max-frequency = <25000000>;
status = "disabled";
};
@@ -239,7 +237,6 @@
interrupt-names = "dma_w", "master_risc", "slave_risc";
clocks = <&clkc CLK_SPI_COMBO_3>;
resets = <&rstc RST_SPI_COMBO_3>;
- spi-max-frequency = <25000000>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi b/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
index e899d14f38c3..1d1d127cf38f 100644
--- a/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
+++ b/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
@@ -89,13 +89,13 @@
};
reg_gmac_3v3: gmac-3v3 {
- compatible = "regulator-fixed";
- regulator-name = "gmac-3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- startup-delay-us = <100000>;
- enable-active-high;
- gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+ compatible = "regulator-fixed";
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
};
wifi_pwrseq: wifi_pwrseq {
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 09aefb4e90f8..686193bd6bd9 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -302,6 +302,8 @@
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>;
resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
status = "disabled";
};
@@ -312,6 +314,8 @@
clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>,
<&ccu CLK_USB_OHCI0>;
resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra114-asus-tf701t.dts b/arch/arm/boot/dts/tegra114-asus-tf701t.dts
index 284209b0bd96..9279d24db009 100644
--- a/arch/arm/boot/dts/tegra114-asus-tf701t.dts
+++ b/arch/arm/boot/dts/tegra114-asus-tf701t.dts
@@ -80,7 +80,7 @@
};
pinmux@70000868 {
- asus_pad_ec_default: asus-pad-ec-default {
+ asus_pad_ec_default: pinmux-asus-pad-ec-default {
ec-interrupt {
nvidia,pins = "kb_col5_pq5";
nvidia,function = "kbc";
@@ -98,7 +98,7 @@
};
};
- backlight_default: backlight-default {
+ backlight_default: pinmux-backlight-default {
backlight-enable {
nvidia,pins = "gmi_ad10_ph2";
nvidia,function = "gmi";
@@ -108,7 +108,7 @@
};
};
- codec_default: codec-default {
+ codec_default: pinmux-codec-default {
ldo1-en {
nvidia,pins = "sdmmc1_wp_n_pv3";
nvidia,function = "sdmmc1";
@@ -127,7 +127,7 @@
};
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: pinmux-gpio-keys-default {
power {
nvidia,pins = "kb_col0_pq0";
nvidia,function = "kbc";
@@ -146,7 +146,7 @@
};
};
- gpio_hall_sensor_default: gpio-hall-sensor-default {
+ gpio_hall_sensor_default: pinmux-gpio-hall-sensor-default {
ulpi_data4_po5 {
nvidia,pins = "ulpi_data4_po5";
nvidia,function = "spi2";
@@ -156,7 +156,7 @@
};
};
- hp_det_default: hp-det-default {
+ hp_det_default: pinmux-hp-det-default {
gmi_iordy_pi5 {
nvidia,pins = "kb_row7_pr7";
nvidia,function = "rsvd2";
@@ -166,7 +166,7 @@
};
};
- imu_default: imu-default {
+ imu_default: pinmux-imu-default {
kb_row3_pr3 {
nvidia,pins = "kb_row3_pr3";
nvidia,function = "rsvd3";
@@ -176,7 +176,7 @@
};
};
- pwm_default: pwm-default {
+ pwm_default: pinmux-pwm-default {
gmi_ad9_ph1 {
nvidia,pins = "gmi_ad9_ph1";
nvidia,function = "pwm1";
@@ -187,7 +187,7 @@
};
/* XXX make this something more sensible */
- pwm_sleep: pwm-sleep {
+ pwm_sleep: pinmux-pwm-sleep {
gmi_ad9_ph1 {
nvidia,pins = "gmi_ad9_ph1";
nvidia,function = "pwm1";
@@ -197,7 +197,7 @@
};
};
- sdmmc3_default: sdmmc3-default {
+ sdmmc3_default: pinmux-sdmmc3-default {
sdmmc3_clk_pa6 {
nvidia,pins = "sdmmc3_clk_pa6";
nvidia,function = "sdmmc3";
@@ -233,7 +233,7 @@
};
};
- sdmmc3_vdd_default: sdmmc3-vdd-default {
+ sdmmc3_vdd_default: pinmux-sdmmc3-vdd-default {
gmi_clk_pk1 {
nvidia,pins = "gmi_clk_pk1";
nvidia,function = "gmi";
@@ -243,7 +243,7 @@
};
};
- vdd_lcd_default: vdd-lcd-default {
+ vdd_lcd_default: pinmux-vdd-lcd-default {
sdmmc4_clk_pcc4 {
nvidia,pins = "sdmmc4_clk_pcc4";
nvidia,function = "sdmmc4";
diff --git a/arch/arm/boot/dts/tegra124-nyan-big.dts b/arch/arm/boot/dts/tegra124-nyan-big.dts
index fdc1d64dfff9..9a01dfed1379 100644
--- a/arch/arm/boot/dts/tegra124-nyan-big.dts
+++ b/arch/arm/boot/dts/tegra124-nyan-big.dts
@@ -18,6 +18,7 @@
aux-bus {
panel: panel {
compatible = "auo,b133xtn01";
+ power-supply = <&vdd_3v3_panel>;
backlight = <&backlight>;
};
};
@@ -39,7 +40,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinmux_default>;
- pinmux_default: common {
+ pinmux_default: pinmux {
clk_32k_out_pa0 {
nvidia,pins = "clk_32k_out_pa0";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
diff --git a/arch/arm/boot/dts/tegra124-nyan-blaze.dts b/arch/arm/boot/dts/tegra124-nyan-blaze.dts
index abdf4456826f..0beef1c03ff3 100644
--- a/arch/arm/boot/dts/tegra124-nyan-blaze.dts
+++ b/arch/arm/boot/dts/tegra124-nyan-blaze.dts
@@ -20,6 +20,7 @@
aux-bus {
panel: panel {
compatible = "samsung,ltn140at29-301";
+ power-supply = <&vdd_3v3_panel>;
backlight = <&backlight>;
};
};
@@ -37,7 +38,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinmux_default>;
- pinmux_default: common {
+ pinmux_default: pinmux {
clk_32k_out_pa0 {
nvidia,pins = "clk_32k_out_pa0";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts
index 8f40fcfc11b0..7e739879c00c 100644
--- a/arch/arm/boot/dts/tegra124-venice2.dts
+++ b/arch/arm/boot/dts/tegra124-venice2.dts
@@ -52,6 +52,7 @@
aux-bus {
panel: panel {
compatible = "lg,lp129qe";
+ power-supply = <&vdd_3v3_panel>;
backlight = <&backlight>;
};
};
@@ -70,7 +71,7 @@
pinctrl-names = "boot";
pinctrl-0 = <&pinmux_boot>;
- pinmux_boot: common {
+ pinmux_boot: pinmux {
dap_mclk1_pw4 {
nvidia,pins = "dap_mclk1_pw4";
nvidia,function = "extperiph1";
diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
index dac6d02a1b15..17afc2c7cb37 100644
--- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
+++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
@@ -342,7 +342,7 @@
};
};
- state_i2cmux_ddc: pinmux_i2cmux_ddc {
+ state_i2cmux_ddc: pinmux-i2cmux-ddc {
ddc {
nvidia,pins = "ddc";
nvidia,function = "i2c2";
@@ -353,7 +353,7 @@
};
};
- state_i2cmux_pta: pinmux_i2cmux_pta {
+ state_i2cmux_pta: pinmux-i2cmux-pta {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -364,7 +364,7 @@
};
};
- state_i2cmux_idle: pinmux_i2cmux_idle {
+ state_i2cmux_idle: pinmux-i2cmux-idle {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
diff --git a/arch/arm/boot/dts/tegra20-asus-tf101.dts b/arch/arm/boot/dts/tegra20-asus-tf101.dts
index bf797a1f27ea..c39ddb462ad0 100644
--- a/arch/arm/boot/dts/tegra20-asus-tf101.dts
+++ b/arch/arm/boot/dts/tegra20-asus-tf101.dts
@@ -399,7 +399,7 @@
};
};
- state_i2cmux_ddc: pinmux_i2cmux_ddc {
+ state_i2cmux_ddc: pinmux-i2cmux-ddc {
ddc {
nvidia,pins = "ddc";
nvidia,function = "i2c2";
@@ -411,7 +411,7 @@
};
};
- state_i2cmux_pta: pinmux_i2cmux_pta {
+ state_i2cmux_pta: pinmux-i2cmux-pta {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -423,7 +423,7 @@
};
};
- state_i2cmux_idle: pinmux_i2cmux_idle {
+ state_i2cmux_idle: pinmux-i2cmux-idle {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -1019,7 +1019,7 @@
};
display-panel {
- compatible = "panel-lvds";
+ compatible = "auo,b101ew05", "panel-lvds";
/* AUO B101EW05 using custom timings */
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 5b4c5ef30996..ab33ff67fdb9 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -285,7 +285,7 @@
};
};
- state_i2cmux_ddc: pinmux_i2cmux_ddc {
+ state_i2cmux_ddc: pinmux-i2cmux-ddc {
ddc {
nvidia,pins = "ddc";
nvidia,function = "i2c2";
@@ -296,7 +296,7 @@
};
};
- state_i2cmux_pta: pinmux_i2cmux_pta {
+ state_i2cmux_pta: pinmux-i2cmux-pta {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -307,7 +307,7 @@
};
};
- state_i2cmux_idle: pinmux_i2cmux_idle {
+ state_i2cmux_idle: pinmux-i2cmux-idle {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi
index 0e19bd0a847c..980272ad59a4 100644
--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi
+++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi
@@ -249,7 +249,7 @@
};
};
- state_i2cmux_ddc: pinmux_i2cmux_ddc {
+ state_i2cmux_ddc: pinmux-i2cmux-ddc {
ddc {
nvidia,pins = "ddc";
nvidia,function = "i2c2";
@@ -260,7 +260,7 @@
};
};
- state_i2cmux_pta: pinmux_i2cmux_pta {
+ state_i2cmux_pta: pinmux-i2cmux-pta {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -271,7 +271,7 @@
};
};
- state_i2cmux_idle: pinmux_i2cmux_idle {
+ state_i2cmux_idle: pinmux-i2cmux-idle {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index caa17e876e41..2d7bb442d6b6 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -284,7 +284,7 @@
};
};
- state_i2cmux_ddc: pinmux_i2cmux_ddc {
+ state_i2cmux_ddc: pinmux-i2cmux-ddc {
ddc {
nvidia,pins = "ddc";
nvidia,function = "i2c2";
@@ -295,7 +295,7 @@
};
};
- state_i2cmux_pta: pinmux_i2cmux_pta {
+ state_i2cmux_pta: pinmux-i2cmux-pta {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
@@ -306,7 +306,7 @@
};
};
- state_i2cmux_idle: pinmux_i2cmux_idle {
+ state_i2cmux_idle: pinmux-i2cmux-idle {
ddc {
nvidia,pins = "ddc";
nvidia,function = "rsvd4";
diff --git a/arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi b/arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi
index c27e70d8bf2b..08ea9cb32d0e 100644
--- a/arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi
+++ b/arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi
@@ -168,7 +168,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
/* SDMMC3 pinmux */
@@ -711,7 +711,7 @@
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
/* GPIO keys pinmux */
@@ -805,7 +805,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
vi_d10_pt2 {
@@ -937,7 +937,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_DISABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
vi_mclk_pt1 {
@@ -1509,7 +1509,6 @@
extcon-keys {
compatible = "gpio-keys";
- interrupt-parent = <&gpio>;
switch-dock-hall-sensor {
label = "Lid sensor";
@@ -1542,7 +1541,6 @@
gpio-keys {
compatible = "gpio-keys";
- interrupt-parent = <&gpio>;
key-power {
label = "Power";
diff --git a/arch/arm/boot/dts/tegra30-pegatron-chagall.dts b/arch/arm/boot/dts/tegra30-pegatron-chagall.dts
index 7c81f0205549..d9408a90653a 100644
--- a/arch/arm/boot/dts/tegra30-pegatron-chagall.dts
+++ b/arch/arm/boot/dts/tegra30-pegatron-chagall.dts
@@ -134,7 +134,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
/* SDMMC3 pinmux */
@@ -150,7 +150,6 @@
nvidia,pins = "sdmmc3_cmd_pa7",
"sdmmc3_dat3_pb4",
"sdmmc3_dat2_pb5",
- "sdmmc3_dat2_pb5",
"sdmmc3_dat1_pb6",
"sdmmc3_dat0_pb7",
"sdmmc3_dat5_pd0",
@@ -622,7 +621,7 @@
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
pu1 {
@@ -689,7 +688,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
vi_d10_pt2 {
@@ -864,7 +863,7 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_DISABLE>;
nvidia,lock = <0>;
- nvidia,ioreset = <0>;
+ nvidia,io-reset = <0>;
};
vi_mclk_pt1 {
@@ -2653,7 +2652,6 @@
extcon-keys {
compatible = "gpio-keys";
- interrupt-parent = <&gpio>;
switch-dock-insert {
label = "Chagall Dock";
@@ -2686,7 +2684,6 @@
gpio-keys {
compatible = "gpio-keys";
- interrupt-parent = <&gpio>;
key-power {
label = "Power";
diff --git a/arch/arm/boot/dts/uniphier-pro5-epcore.dts b/arch/arm/boot/dts/uniphier-pro5-epcore.dts
new file mode 100644
index 000000000000..ed759dcc3216
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-pro5-epcore.dts
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Device Tree Source for UniPhier Pro5 EP-CORE Board (Pro5-PCIe_EP-CORE)
+ *
+ * Copyright (C) 2021 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+/dts-v1/;
+#include "uniphier-pro5.dtsi"
+#include "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier Pro5 EP-CORE Board";
+ compatible = "socionext,uniphier-pro5-epcore", "socionext,uniphier-pro5";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ i2c0 = &i2c0;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+};
+
+&ethsc {
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+};
+
+&serialsc {
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+};
+
+&serial0 {
+ status = "okay";
+};
+
+&serial1 {
+ status = "okay";
+};
+
+&serial2 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&sd {
+ status = "okay";
+};
+
+&pcie_ep {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/uniphier-pro5-proex.dts b/arch/arm/boot/dts/uniphier-pro5-proex.dts
new file mode 100644
index 000000000000..2cfb84f73cc0
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-pro5-proex.dts
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Device Tree Source for UniPhier Pro5 ProEX Board
+ *
+ * Copyright (C) 2021 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+/dts-v1/;
+#include "uniphier-pro5.dtsi"
+
+/ {
+ model = "UniPhier Pro5 ProEX Board";
+ compatible = "socionext,uniphier-pro5-proex", "socionext,uniphier-pro5";
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ aliases {
+ serial1 = &serial1;
+ serial2 = &serial2;
+ i2c0 = &i2c0;
+ i2c1 = &i2c3;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+};
+
+&serial1 {
+ status = "okay";
+};
+
+&serial2 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&i2c3 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&pcie_ep {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index f434fe5cf4a1..def538ce8769 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -383,49 +383,49 @@
leds {
compatible = "gpio-leds";
- user1 {
+ led-user1 {
label = "v2m:green:user1";
gpios = <&v2m_led_gpios 0 0>;
linux,default-trigger = "heartbeat";
};
- user2 {
+ led-user2 {
label = "v2m:green:user2";
gpios = <&v2m_led_gpios 1 0>;
linux,default-trigger = "mmc0";
};
- user3 {
+ led-user3 {
label = "v2m:green:user3";
gpios = <&v2m_led_gpios 2 0>;
linux,default-trigger = "cpu0";
};
- user4 {
+ led-user4 {
label = "v2m:green:user4";
gpios = <&v2m_led_gpios 3 0>;
linux,default-trigger = "cpu1";
};
- user5 {
+ led-user5 {
label = "v2m:green:user5";
gpios = <&v2m_led_gpios 4 0>;
linux,default-trigger = "cpu2";
};
- user6 {
+ led-user6 {
label = "v2m:green:user6";
gpios = <&v2m_led_gpios 5 0>;
linux,default-trigger = "cpu3";
};
- user7 {
+ led-user7 {
label = "v2m:green:user7";
gpios = <&v2m_led_gpios 6 0>;
linux,default-trigger = "cpu4";
};
- user8 {
+ led-user8 {
label = "v2m:green:user8";
gpios = <&v2m_led_gpios 7 0>;
linux,default-trigger = "cpu5";
diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
index de79dcfd32e6..f892977da9e4 100644
--- a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
@@ -259,7 +259,7 @@
xtal-trim = /bits/ 8 <0x06>;
sleep-gpio = <&gpio0 24 GPIO_ACTIVE_HIGH>;
- reset-gpio = <&gpio6 10 GPIO_ACTIVE_HIGH>;
+ reset-gpio = <&gpio6 10 GPIO_ACTIVE_LOW>;
fsl,spi-cs-sck-delay = <180>;
fsl,spi-sck-cs-delay = <250>;
diff --git a/arch/arm/configs/clps711x_defconfig b/arch/arm/configs/clps711x_defconfig
index 92481b2a88fa..adcee238822a 100644
--- a/arch/arm/configs/clps711x_defconfig
+++ b/arch/arm/configs/clps711x_defconfig
@@ -14,7 +14,8 @@ CONFIG_ARCH_EDB7211=y
CONFIG_ARCH_P720T=y
CONFIG_AEABI=y
# CONFIG_COREDUMP is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig
index 2a2d2cb3ce2e..69341c33e0cc 100644
--- a/arch/arm/configs/collie_defconfig
+++ b/arch/arm/configs/collie_defconfig
@@ -13,7 +13,8 @@ CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1"
CONFIG_FPE_NWFPE=y
CONFIG_PM=y
# CONFIG_SWAP is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 078d61b758a9..025eb333dcaa 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -166,6 +166,7 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_TOUCHSCREEN_AD7879=y
CONFIG_TOUCHSCREEN_AD7879_I2C=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_CYTTSP5=y
CONFIG_TOUCHSCREEN_DA9052=y
CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_GOODIX=y
@@ -222,6 +223,7 @@ CONFIG_RN5T618_POWER=m
CONFIG_SENSORS_MC13783_ADC=y
CONFIG_SENSORS_GPIO_FAN=y
CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_SENSORS_SY7636A=y
CONFIG_THERMAL_STATISTICS=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_CPU_THERMAL=y
@@ -237,6 +239,7 @@ CONFIG_MFD_DA9062=y
CONFIG_MFD_DA9063=y
CONFIG_MFD_MC13XXX_SPI=y
CONFIG_MFD_MC13XXX_I2C=y
+CONFIG_MFD_SY7636A=y
CONFIG_MFD_RN5T618=y
CONFIG_MFD_STMPE=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -250,6 +253,7 @@ CONFIG_REGULATOR_MC13783=y
CONFIG_REGULATOR_MC13892=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_REGULATOR_RN5T618=y
+CONFIG_REGULATOR_SY7636A=y
CONFIG_RC_CORE=y
CONFIG_RC_DEVICES=y
CONFIG_IR_GPIO_CIR=y
@@ -397,6 +401,7 @@ CONFIG_CLK_IMX8MN=y
CONFIG_CLK_IMX8MP=y
CONFIG_CLK_IMX8MQ=y
CONFIG_SOC_IMX8M=y
+CONFIG_EXTCON_USB_GPIO=y
CONFIG_IIO=y
CONFIG_MMA8452=y
CONFIG_IMX7D_ADC=y
diff --git a/arch/arm/configs/multi_v4t_defconfig b/arch/arm/configs/multi_v4t_defconfig
index e2fd822f741a..b60000a89aff 100644
--- a/arch/arm/configs/multi_v4t_defconfig
+++ b/arch/arm/configs/multi_v4t_defconfig
@@ -25,7 +25,8 @@ CONFIG_ARM_CLPS711X_CPUIDLE=y
CONFIG_JUMP_LABEL=y
CONFIG_PARTITION_ADVANCED=y
# CONFIG_COREDUMP is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index b61b2e3d116b..ee184eb37adc 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -663,11 +663,11 @@ CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_ASPEED=m
-CONFIG_VIDEO_ATMEL_ISC=m
-CONFIG_VIDEO_ATMEL_XISC=m
CONFIG_VIDEO_ATMEL_ISI=m
-CONFIG_VIDEO_MICROCHIP_CSI2DC=m
CONFIG_VIDEO_MMP_CAMERA=m
+CONFIG_VIDEO_MICROCHIP_ISC=m
+CONFIG_VIDEO_MICROCHIP_XISC=m
+CONFIG_VIDEO_MICROCHIP_CSI2DC=m
CONFIG_VIDEO_TEGRA_VDE=m
CONFIG_VIDEO_RENESAS_CEU=m
CONFIG_VIDEO_RCAR_VIN=m
@@ -891,6 +891,8 @@ CONFIG_USB_CONFIGFS_F_UVC=y
CONFIG_USB_CONFIGFS_F_PRINTER=y
CONFIG_USB_ETH=m
CONFIG_TYPEC=m
+CONFIG_TYPEC_UCSI=m
+CONFIG_UCSI_STM32G0=m
CONFIG_TYPEC_STUSB160X=m
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=16
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index 70511fe4b3ec..246f1bba7df5 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -42,7 +42,8 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_BINFMT_MISC=y
# CONFIG_SWAP is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig
index d60cc9cc4c21..0a0f12df40b5 100644
--- a/arch/arm/configs/pxa_defconfig
+++ b/arch/arm/configs/pxa_defconfig
@@ -49,7 +49,8 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_LDM_PARTITION=y
CONFIG_CMDLINE_PARTITION=y
CONFIG_BINFMT_MISC=y
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_COMPACTION is not set
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index 7d8b6884fd00..b41716c1ec64 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -131,14 +131,19 @@ CONFIG_PINCTRL_APQ8064=y
CONFIG_PINCTRL_APQ8084=y
CONFIG_PINCTRL_IPQ4019=y
CONFIG_PINCTRL_IPQ8064=y
+CONFIG_PINCTRL_MSM8226=y
CONFIG_PINCTRL_MSM8660=y
CONFIG_PINCTRL_MSM8960=y
+CONFIG_PINCTRL_MDM9607=y
CONFIG_PINCTRL_MDM9615=y
CONFIG_PINCTRL_MSM8X74=y
+CONFIG_PINCTRL_MSM8909=y
+CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_PINCTRL_SDX55=y
+CONFIG_PINCTRL_SDX65=y
CONFIG_GPIO_SYSFS=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_MSM=y
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index 877bbe7b777e..f89fd4e0d10a 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -150,8 +150,8 @@ CONFIG_MEDIA_PLATFORM_SUPPORT=y
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_ATMEL_ISC=y
CONFIG_VIDEO_ATMEL_ISI=y
+CONFIG_VIDEO_MICROCHIP_ISC=y
CONFIG_VIDEO_MT9V032=m
CONFIG_VIDEO_OV2640=m
CONFIG_VIDEO_OV5640=m
diff --git a/arch/arm/configs/sama7_defconfig b/arch/arm/configs/sama7_defconfig
index 8f28c9d443f0..0d964c613d71 100644
--- a/arch/arm/configs/sama7_defconfig
+++ b/arch/arm/configs/sama7_defconfig
@@ -128,6 +128,10 @@ CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_AT91_RESET=y
CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC=y
# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_STATISTICS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_GENERIC_ADC_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_SAMA5D4_WATCHDOG=y
CONFIG_MFD_ATMEL_FLEXCOM=y
@@ -140,7 +144,7 @@ CONFIG_MEDIA_SUPPORT_FILTER=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_PLATFORM_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_ATMEL_XISC=y
+CONFIG_VIDEO_MICROCHIP_XISC=y
CONFIG_VIDEO_MICROCHIP_CSI2DC=y
CONFIG_VIDEO_IMX219=m
CONFIG_VIDEO_IMX274=m
@@ -196,6 +200,7 @@ CONFIG_PWM=y
CONFIG_PWM_ATMEL=y
CONFIG_MCHP_EIC=y
CONFIG_RESET_CONTROLLER=y
+CONFIG_NVMEM_MICROCHIP_OTPC=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_FANOTIFY=y
@@ -211,13 +216,13 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_LSM="N"
CONFIG_CRYPTO_AUTHENC=y
-CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CFB=y
CONFIG_CRYPTO_OFB=y
CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_DEV_ATMEL_AES=y
diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig
index 3d631b1f3cfa..3e2c2abae5ba 100644
--- a/arch/arm/configs/spear6xx_defconfig
+++ b/arch/arm/configs/spear6xx_defconfig
@@ -11,7 +11,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_BINFMT_MISC=y
CONFIG_NET=y
CONFIG_MTD=y
-CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_NAND_FSMC=y
@@ -28,23 +27,21 @@ CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_SMSC is not set
CONFIG_STMMAC_ETH=y
# CONFIG_WLAN is not set
-CONFIG_INPUT_FF_MEMLESS=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_RAW_DRIVER=y
CONFIG_I2C=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
-CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_DRM=y
+CONFIG_DRM_PL111=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig
index 3b29ae1fb750..6bd38b6f22c4 100644
--- a/arch/arm/configs/tct_hammer_defconfig
+++ b/arch/arm/configs/tct_hammer_defconfig
@@ -19,7 +19,8 @@ CONFIG_FPE_NWFPE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_SWAP is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig
index ea59e4b6bfc5..6bd9f71b71fc 100644
--- a/arch/arm/configs/xcep_defconfig
+++ b/arch/arm/configs/xcep_defconfig
@@ -26,7 +26,8 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLOCK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_NET=y
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index fe87397c3d8c..bdbc1e590891 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -17,7 +17,7 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_arch_fetch_caller_regs(regs, __ip) { \
(regs)->ARM_pc = (__ip); \
- (regs)->ARM_fp = (unsigned long) __builtin_frame_address(0); \
+ frame_pointer((regs)) = (unsigned long) __builtin_frame_address(0); \
(regs)->ARM_sp = current_stack_pointer; \
(regs)->ARM_cpsr = SVC_MODE; \
}
diff --git a/arch/arm/include/asm/pgtable-nommu.h b/arch/arm/include/asm/pgtable-nommu.h
index d16aba48fa0a..090011394477 100644
--- a/arch/arm/include/asm/pgtable-nommu.h
+++ b/arch/arm/include/asm/pgtable-nommu.h
@@ -45,12 +45,6 @@
typedef pte_t *pte_addr_t;
/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-#define ZERO_PAGE(vaddr) (virt_to_page(0))
-
-/*
* Mark the prot value as uncacheable and unbufferable.
*/
#define pgprot_noncached(prot) (prot)
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 78a532068fec..ef48a55e9af8 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -10,6 +10,15 @@
#include <linux/const.h>
#include <asm/proc-fns.h>
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern struct page *empty_zero_page;
+#define ZERO_PAGE(vaddr) (empty_zero_page)
+#endif
+
#ifndef CONFIG_MMU
#include <asm-generic/pgtable-nopud.h>
@@ -139,13 +148,6 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
*/
#ifndef __ASSEMBLY__
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern struct page *empty_zero_page;
-#define ZERO_PAGE(vaddr) (empty_zero_page)
-
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h
index 088d03161be5..0bd4979759f1 100644
--- a/arch/arm/include/asm/stackprotector.h
+++ b/arch/arm/include/asm/stackprotector.h
@@ -15,9 +15,6 @@
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H 1
-#include <linux/random.h>
-#include <linux/version.h>
-
#include <asm/thread_info.h>
extern unsigned long __stack_chk_guard;
@@ -30,11 +27,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
#ifndef CONFIG_STACKPROTECTOR_PER_TASK
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index f567032a09c0..a2e9ac763a9f 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -73,7 +73,7 @@ void machine_kexec_cleanup(struct kimage *image)
{
}
-void machine_crash_nonpanic_core(void *unused)
+static void machine_crash_nonpanic_core(void *unused)
{
struct pt_regs regs;
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index a2b31d91a1b6..f811733a8fc5 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -371,7 +371,7 @@ static unsigned long sigpage_addr(const struct mm_struct *mm,
slots = ((last - first) >> PAGE_SHIFT) + 1;
- offset = prandom_u32_max(slots);
+ offset = get_random_u32_below(slots);
addr = first + (offset << PAGE_SHIFT);
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index bfe88c6e60d5..2d8e2516906b 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -651,11 +651,9 @@ static int vfp_set(struct task_struct *target,
if (ret)
return ret;
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- user_fpregs_offset + sizeof(new_vfp.fpregs),
- user_fpscr_offset);
- if (ret)
- return ret;
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ user_fpregs_offset + sizeof(new_vfp.fpregs),
+ user_fpscr_offset);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&new_vfp.fpscr,
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index ffed4d949042..e4904faf1753 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -169,10 +169,15 @@ sr_ena_2:
cmp tmp1, #UDDRC_STAT_SELFREF_TYPE_SW
bne sr_ena_2
- /* Put DDR PHY's DLL in bypass mode for non-backup modes. */
+ /* Disable DX DLLs for non-backup modes. */
cmp r7, #AT91_PM_BACKUP
beq sr_ena_3
+ /* Do not soft reset the AC DLL. */
+ ldr tmp1, [r3, DDR3PHY_ACDLLCR]
+ bic tmp1, tmp1, DDR3PHY_ACDLLCR_DLLSRST
+ str tmp1, [r3, DDR3PHY_ACDLLCR]
+
/* Disable DX DLLs. */
ldr tmp1, [r3, #DDR3PHY_DX0DLLCR]
orr tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c
index 67ed68fbe3a5..bf2b5c6a18c6 100644
--- a/arch/arm/mach-at91/sama5.c
+++ b/arch/arm/mach-at91/sama5.c
@@ -26,7 +26,7 @@ static void sama5_l2c310_write_sec(unsigned long val, unsigned reg)
static void __init sama5_secure_cache_init(void)
{
sam_secure_init();
- if (sam_linux_is_optee_available())
+ if (IS_ENABLED(CONFIG_OUTER_CACHE) && sam_linux_is_optee_available())
outer_cache.write_sec = sama5_l2c310_write_sec;
}
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 28db97289ee8..0788c5cc7f9e 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -12,7 +12,6 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of_address.h>
-#include <linux/pinctrl/machine.h>
#include <asm/system_misc.h>
#include <asm/hardware/cache-l2x0.h>
diff --git a/arch/arm/mach-ixp4xx/ixp4xx-of.c b/arch/arm/mach-ixp4xx/ixp4xx-of.c
index f543e2adae0c..1b4d84a5b02f 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx-of.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx-of.c
@@ -2,48 +2,7 @@
/*
* IXP4xx Device Tree boot support
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-/*
- * These are the only fixed phys to virt mappings we ever need
- * we put it right after the UART mapping at 0xffc80000-0xffc81fff
- */
-#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
-#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000
-
-static struct map_desc ixp4xx_of_io_desc[] __initdata = {
- /*
- * This is needed for runtime system configuration checks,
- * such as reading if hardware so-and-so is present. This
- * could eventually be converted into a syscon once all boards
- * are converted to device tree.
- */
- {
- .virtual = IXP4XX_EXP_CFG_BASE_VIRT,
- .pfn = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_UART_8250
- /* This is needed for LL-debug/earlyprintk/debug-macro.S */
- {
- .virtual = CONFIG_DEBUG_UART_VIRT,
- .pfn = __phys_to_pfn(CONFIG_DEBUG_UART_PHYS),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#endif
-};
-
-static void __init ixp4xx_of_map_io(void)
-{
- iotable_init(ixp4xx_of_io_desc, ARRAY_SIZE(ixp4xx_of_io_desc));
-}
/*
* We handle 4 different SoC families. These compatible strings are enough
@@ -59,6 +18,5 @@ static const char *ixp4xx_of_board_compat[] = {
};
DT_MACHINE_START(IXP4XX_DT, "IXP4xx (Device Tree)")
- .map_io = ixp4xx_of_map_io,
.dt_compat = ixp4xx_of_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-keystone/Makefile b/arch/arm/mach-keystone/Makefile
index 739b38be5696..0c1d54aec60f 100644
--- a/arch/arm/mach-keystone/Makefile
+++ b/arch/arm/mach-keystone/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-obj-y := keystone.o smc.o
-
-obj-$(CONFIG_SMP) += platsmp.o
+obj-y := keystone.o
# PM domain driver for Keystone SOCs
obj-$(CONFIG_ARCH_KEYSTONE) += pm_domain.o
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
index 2c647bdf8d25..aa352c2de313 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -18,7 +18,6 @@
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-#include <asm/smp_plat.h>
#include <asm/memory.h>
#include "memory.h"
@@ -103,7 +102,6 @@ DT_MACHINE_START(KEYSTONE, "Keystone")
#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
.dma_zone_size = SZ_2G,
#endif
- .smp = smp_ops(keystone_smp_ops),
.init_machine = keystone_init,
.dt_compat = keystone_match,
.pv_fixup = keystone_pv_fixup,
diff --git a/arch/arm/mach-keystone/keystone.h b/arch/arm/mach-keystone/keystone.h
index 438e531cc007..71ff8cd2ee4a 100644
--- a/arch/arm/mach-keystone/keystone.h
+++ b/arch/arm/mach-keystone/keystone.h
@@ -8,13 +8,8 @@
#ifndef __KEYSTONE_H__
#define __KEYSTONE_H__
-#define KEYSTONE_MON_CPU_UP_IDX 0x00
-
#ifndef __ASSEMBLER__
-extern const struct smp_operations keystone_smp_ops;
-extern void secondary_startup(void);
-extern u32 keystone_cpu_smc(u32 command, u32 cpu, u32 addr);
extern int keystone_pm_runtime_init(void);
#endif /* __ASSEMBLER__ */
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
deleted file mode 100644
index 673fcf3b34b1..000000000000
--- a/arch/arm/mach-keystone/platsmp.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Keystone SOC SMP platform code
- *
- * Copyright 2013 Texas Instruments, Inc.
- * Cyril Chemparathy <cyril@ti.com>
- * Santosh Shilimkar <santosh.shillimkar@ti.com>
- *
- * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
- */
-
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-#include <linux/pgtable.h>
-
-#include <asm/smp_plat.h>
-#include <asm/prom.h>
-#include <asm/tlbflush.h>
-
-#include "keystone.h"
-
-static int keystone_smp_boot_secondary(unsigned int cpu,
- struct task_struct *idle)
-{
- unsigned long start = virt_to_idmap(&secondary_startup);
- int error;
-
- pr_debug("keystone-smp: booting cpu %d, vector %08lx\n",
- cpu, start);
-
- error = keystone_cpu_smc(KEYSTONE_MON_CPU_UP_IDX, cpu, start);
- if (error)
- pr_err("CPU %d bringup failed with %d\n", cpu, error);
-
- return error;
-}
-
-const struct smp_operations keystone_smp_ops __initconst = {
- .smp_boot_secondary = keystone_smp_boot_secondary,
-};
diff --git a/arch/arm/mach-keystone/smc.S b/arch/arm/mach-keystone/smc.S
deleted file mode 100644
index 21ef75cf5370..000000000000
--- a/arch/arm/mach-keystone/smc.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Keystone Secure APIs
- *
- * Copyright (C) 2013 Texas Instruments, Inc.
- * Santosh Shilimkar <santosh.shilimkar@ti.com>
- */
-
-#include <linux/linkage.h>
-
-/**
- * u32 keystone_cpu_smc(u32 command, u32 cpu, u32 addr)
- *
- * Low level CPU monitor API
- * @command: Monitor command.
- * @cpu: CPU Number
- * @addr: Kernel jump address for boot CPU
- *
- * Return: Non zero value on failure
- */
- .arch_extension sec
-ENTRY(keystone_cpu_smc)
- stmfd sp!, {r4-r11, lr}
- smc #0
- ldmfd sp!, {r4-r11, pc}
-ENDPROC(keystone_cpu_smc)
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 41b2e8abc9e6..708816caf859 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -43,18 +43,21 @@
static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
/*
- * FIXME: the timer needs some delay to stablize the counter capture
+ * Read the timer through the CVWR register. Delay is required after requesting
+ * a read. The CR register cannot be directly read due to metastability issues
+ * documented in the PXA168 software manual.
*/
static inline uint32_t timer_read(void)
{
- int delay = 100;
+ uint32_t val;
+ int delay = 3;
__raw_writel(1, mmp_timer_base + TMR_CVWR(1));
while (delay--)
- cpu_relax();
+ val = __raw_readl(mmp_timer_base + TMR_CVWR(1));
- return __raw_readl(mmp_timer_base + TMR_CVWR(1));
+ return val;
}
static u64 notrace mmp_read_sched_clock(void)
diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c
index 7fa1806acd65..beec22e17e89 100644
--- a/arch/arm/mach-mvebu/pm-board.c
+++ b/arch/arm/mach-mvebu/pm-board.c
@@ -8,19 +8,19 @@
*/
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include "common.h"
#define ARMADA_PIC_NR_GPIOS 3
static void __iomem *gpio_ctrl;
-static int pic_gpios[ARMADA_PIC_NR_GPIOS];
+static struct gpio_desc *pic_gpios[ARMADA_PIC_NR_GPIOS];
static int pic_raw_gpios[ARMADA_PIC_NR_GPIOS];
static void mvebu_armada_pm_enter(void __iomem *sdram_reg, u32 srcmd)
@@ -90,27 +90,17 @@ static int __init mvebu_armada_pm_init(void)
char *name;
struct of_phandle_args args;
- pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i);
- if (pic_gpios[i] < 0) {
- ret = -ENODEV;
- goto out;
- }
-
name = kasprintf(GFP_KERNEL, "pic-pin%d", i);
if (!name) {
ret = -ENOMEM;
goto out;
}
- ret = gpio_request(pic_gpios[i], name);
- if (ret < 0) {
- kfree(name);
- goto out;
- }
-
- ret = gpio_direction_output(pic_gpios[i], 0);
- if (ret < 0) {
- gpio_free(pic_gpios[i]);
+ pic_gpios[i] = fwnode_gpiod_get_index(of_fwnode_handle(np),
+ "ctrl", i, GPIOD_OUT_HIGH,
+ name);
+ ret = PTR_ERR_OR_ZERO(pic_gpios[i]);
+ if (ret) {
kfree(name);
goto out;
}
@@ -118,7 +108,7 @@ static int __init mvebu_armada_pm_init(void)
ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2,
i, &args);
if (ret < 0) {
- gpio_free(pic_gpios[i]);
+ gpiod_put(pic_gpios[i]);
kfree(name);
goto out;
}
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 25c9d184fa4c..0129b7c514d7 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -17,7 +17,6 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/sys_soc.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -393,8 +392,10 @@ static void __init mxs_machine_init(void)
root = of_find_node_by_path("/");
ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
- if (ret)
+ if (ret) {
+ kfree(soc_dev_attr);
return;
+ }
soc_dev_attr->family = "Freescale MXS Family";
soc_dev_attr->soc_id = mxs_get_soc_id();
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 5e86145db0e2..8897364e550b 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -22,7 +22,6 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/platform_data/mmc-omap.h>
#include <linux/mfd/menelaus.h>
-#include <sound/tlv320aic3x.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -567,10 +566,6 @@ struct menelaus_platform_data n8x0_menelaus_platform_data = {
.late_init = n8x0_menelaus_late_init,
};
-struct aic3x_pdata n810_aic33_data = {
- .gpio_reset = 118,
-};
-
static int __init n8x0_late_initcall(void)
{
if (!board_caps)
diff --git a/arch/arm/mach-omap2/common-board-devices.h b/arch/arm/mach-omap2/common-board-devices.h
index b23962c38fb2..69694af71475 100644
--- a/arch/arm/mach-omap2/common-board-devices.h
+++ b/arch/arm/mach-omap2/common-board-devices.h
@@ -2,12 +2,10 @@
#ifndef __OMAP_COMMON_BOARD_DEVICES__
#define __OMAP_COMMON_BOARD_DEVICES__
-#include <sound/tlv320aic3x.h>
#include <linux/mfd/menelaus.h>
void *n8x0_legacy_init(void);
extern struct menelaus_platform_data n8x0_menelaus_platform_data;
-extern struct aic3x_pdata n810_aic33_data;
#endif /* __OMAP_COMMON_BOARD_DEVICES__ */
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index b6c7d98a9eff..4d46c56db38b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -1135,65 +1135,6 @@ static struct omap_hwmod omap34xx_mcspi4 = {
.class = &omap34xx_mcspi_class,
};
-/* usbhsotg */
-static struct omap_hwmod_class_sysconfig omap3xxx_usbhsotg_sysc = {
- .rev_offs = 0x0400,
- .sysc_offs = 0x0404,
- .syss_offs = 0x0408,
- .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE|
- SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
- .sysc_fields = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class usbotg_class = {
- .name = "usbotg",
- .sysc = &omap3xxx_usbhsotg_sysc,
-};
-
-/* usb_otg_hs */
-
-static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
- .name = "usb_otg_hs",
- .main_clk = "hsotgusb_ick",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
- },
- },
- .class = &usbotg_class,
-
- /*
- * Erratum ID: i479 idle_req / idle_ack mechanism potentially
- * broken when autoidle is enabled
- * workaround is to disable the autoidle bit at module level.
- *
- * Enabling the device in any other MIDLEMODE setting but force-idle
- * causes core_pwrdm not enter idle states at least on OMAP3630.
- * Note that musb has OTG_FORCESTDBY register that controls MSTANDBY
- * signal when MIDLEMODE is set to force-idle.
- */
- .flags = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE |
- HWMOD_FORCE_MSTANDBY | HWMOD_RECONFIG_IO_CHAIN,
-};
-
-/* usb_otg_hs */
-
-static struct omap_hwmod_class am35xx_usbotg_class = {
- .name = "am35xx_usbotg",
-};
-
-static struct omap_hwmod am35xx_usbhsotg_hwmod = {
- .name = "am35x_otg_hs",
- .main_clk = "hsotgusb_fck",
- .class = &am35xx_usbotg_class,
- .flags = HWMOD_NO_IDLEST,
-};
-
/* MMC/SD/SDIO common */
static struct omap_hwmod_class_sysconfig omap34xx_mmc_sysc = {
.rev_offs = 0x1fc,
@@ -1561,22 +1502,6 @@ static struct omap_hwmod_ocp_if omap3xxx_dss__l3 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* l3_core -> usbhsotg interface */
-static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
- .master = &omap3xxx_usbhsotg_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "core_l3_ick",
- .user = OCP_USER_MPU,
-};
-
-/* l3_core -> am35xx_usbhsotg interface */
-static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
- .master = &am35xx_usbhsotg_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "hsotgusb_ick",
- .user = OCP_USER_MPU,
-};
-
/* l3_core -> sad2d interface */
static struct omap_hwmod_ocp_if omap3xxx_sad2d__l3 = {
.master = &omap3xxx_sad2d_hwmod,
@@ -1758,24 +1683,6 @@ static struct omap_hwmod_ocp_if omap36xx_l4_core__sr2 = {
.user = OCP_USER_MPU,
};
-
-/* l4_core -> usbhsotg */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__usbhsotg = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_usbhsotg_hwmod,
- .clk = "l4_ick",
- .user = OCP_USER_MPU,
-};
-
-
-/* l4_core -> usbhsotg */
-static struct omap_hwmod_ocp_if am35xx_l4_core__usbhsotg = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &am35xx_usbhsotg_hwmod,
- .clk = "hsotgusb_ick",
- .user = OCP_USER_MPU,
-};
-
/* L4_WKUP -> L4_SEC interface */
static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__l4_sec = {
.master = &omap3xxx_l4_wkup_hwmod,
@@ -2465,8 +2372,6 @@ static struct omap_hwmod_ocp_if *omap3430es1_hwmod_ocp_ifs[] __initdata = {
static struct omap_hwmod_ocp_if *omap3430es2plus_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_dss__l3,
&omap3xxx_l4_core__dss,
- &omap3xxx_usbhsotg__l3,
- &omap3xxx_l4_core__usbhsotg,
&omap3xxx_usb_host_hs__l3_main_2,
&omap3xxx_l4_core__usb_host_hs,
&omap3xxx_l4_core__usb_tll_hs,
@@ -2509,8 +2414,6 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_l4_core__dss,
&omap36xx_l4_core__sr1,
&omap36xx_l4_core__sr2,
- &omap3xxx_usbhsotg__l3,
- &omap3xxx_l4_core__usbhsotg,
&omap3xxx_l4_core__mailbox,
&omap3xxx_usb_host_hs__l3_main_2,
&omap3xxx_l4_core__usb_host_hs,
@@ -2528,8 +2431,6 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_dss__l3,
&omap3xxx_l4_core__dss,
- &am35xx_usbhsotg__l3,
- &am35xx_l4_core__usbhsotg,
&am35xx_l4_core__uart4,
&omap3xxx_usb_host_hs__l3_main_2,
&omap3xxx_l4_core__usb_host_hs,
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 5b99d602c87b..9deba798cc91 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -440,7 +440,6 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
#ifdef CONFIG_MACH_NOKIA_N8X0
OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
OF_DEV_AUXDATA("menelaus", 0x72, "1-0072", &n8x0_menelaus_platform_data),
- OF_DEV_AUXDATA("tlv320aic3x", 0x18, "2-0018", &n810_aic33_data),
#endif
#ifdef CONFIG_ARCH_OMAP3
OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu",
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 37f862f13c8d..8d64cc7edccd 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -3,7 +3,5 @@ menuconfig ARCH_RENESAS
bool "Renesas ARM SoCs"
depends on ARCH_MULTI_V7
select ARM_GIC
- select GPIOLIB
select NO_IOPORT_MAP
- select PINCTRL
select ZONE_DMA if ARM_LPAE
diff --git a/arch/arm/mach-spear/time.c b/arch/arm/mach-spear/time.c
index e979e2197f8e..5371c824786d 100644
--- a/arch/arm/mach-spear/time.c
+++ b/arch/arm/mach-spear/time.c
@@ -90,7 +90,7 @@ static void __init spear_clocksource_init(void)
200, 16, clocksource_mmio_readw_up);
}
-static inline void timer_shutdown(struct clock_event_device *evt)
+static inline void spear_timer_shutdown(struct clock_event_device *evt)
{
u16 val = readw(gpt_base + CR(CLKEVT));
@@ -101,7 +101,7 @@ static inline void timer_shutdown(struct clock_event_device *evt)
static int spear_shutdown(struct clock_event_device *evt)
{
- timer_shutdown(evt);
+ spear_timer_shutdown(evt);
return 0;
}
@@ -111,7 +111,7 @@ static int spear_set_oneshot(struct clock_event_device *evt)
u16 val;
/* stop the timer */
- timer_shutdown(evt);
+ spear_timer_shutdown(evt);
val = readw(gpt_base + CR(CLKEVT));
val |= CTRL_ONE_SHOT;
@@ -126,7 +126,7 @@ static int spear_set_periodic(struct clock_event_device *evt)
u16 val;
/* stop the timer */
- timer_shutdown(evt);
+ spear_timer_shutdown(evt);
period = clk_get_rate(gpt_clk) / HZ;
period >>= CTRL_PRESCALER16;
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index e929aaa744c0..7cc0dd8ed991 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -26,7 +26,6 @@
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
-#include "db8500-regs.h"
#include "pm_domains.h"
static int __init ux500_l2x0_unlock(void)
diff --git a/arch/arm/mach-ux500/db8500-regs.h b/arch/arm/mach-ux500/db8500-regs.h
deleted file mode 100644
index 0d47d7171d9b..000000000000
--- a/arch/arm/mach-ux500/db8500-regs.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST-Ericsson SA 2010
- */
-
-#ifndef __MACH_DB8500_REGS_H
-#define __MACH_DB8500_REGS_H
-
-/* Base address and bank offsets for ESRAM */
-#define U8500_ESRAM_BASE 0x40000000
-#define U8500_ESRAM_BANK_SIZE 0x00020000
-#define U8500_ESRAM_BANK0 U8500_ESRAM_BASE
-#define U8500_ESRAM_BANK1 (U8500_ESRAM_BASE + U8500_ESRAM_BANK_SIZE)
-#define U8500_ESRAM_BANK2 (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
-#define U8500_ESRAM_BANK3 (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
-#define U8500_ESRAM_BANK4 (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
-/*
- * on V1 DMA uses 4KB for logical parameters position is right after the 64KB
- * reserved for security
- */
-#define U8500_ESRAM_DMA_LCPA_OFFSET 0x10000
-
-#define U8500_DMA_LCPA_BASE (U8500_ESRAM_BANK0 + U8500_ESRAM_DMA_LCPA_OFFSET)
-
-/* This address fulfills the 256k alignment requirement of the lcla base */
-#define U8500_DMA_LCLA_BASE U8500_ESRAM_BANK4
-
-#define U8500_PER3_BASE 0x80000000
-#define U8500_STM_BASE 0x80100000
-#define U8500_STM_REG_BASE (U8500_STM_BASE + 0xF000)
-#define U8500_PER2_BASE 0x80110000
-#define U8500_PER1_BASE 0x80120000
-#define U8500_B2R2_BASE 0x80130000
-#define U8500_HSEM_BASE 0x80140000
-#define U8500_PER4_BASE 0x80150000
-#define U8500_TPIU_BASE 0x80190000
-#define U8500_ICN_BASE 0x81000000
-
-#define U8500_BOOT_ROM_BASE 0x90000000
-/* ASIC ID is at 0xbf4 offset within this region */
-#define U8500_ASIC_ID_BASE 0x9001D000
-
-#define U8500_PER6_BASE 0xa03c0000
-#define U8500_PER7_BASE 0xa03d0000
-#define U8500_PER5_BASE 0xa03e0000
-
-#define U8500_SVA_BASE 0xa0100000
-#define U8500_SIA_BASE 0xa0200000
-
-#define U8500_SGA_BASE 0xa0300000
-#define U8500_MCDE_BASE 0xa0350000
-#define U8500_DMA_BASE 0x801C0000 /* v1 */
-
-#define U8500_SBAG_BASE 0xa0390000
-
-#define U8500_SCU_BASE 0xa0410000
-#define U8500_GIC_CPU_BASE 0xa0410100
-#define U8500_TWD_BASE 0xa0410600
-#define U8500_GIC_DIST_BASE 0xa0411000
-#define U8500_L2CC_BASE 0xa0412000
-
-#define U8500_MODEM_I2C 0xb7e02000
-
-#define U8500_GPIO0_BASE (U8500_PER1_BASE + 0xE000)
-#define U8500_GPIO1_BASE (U8500_PER3_BASE + 0xE000)
-#define U8500_GPIO2_BASE (U8500_PER2_BASE + 0xE000)
-#define U8500_GPIO3_BASE (U8500_PER5_BASE + 0x1E000)
-
-#define U8500_UART0_BASE (U8500_PER1_BASE + 0x0000)
-#define U8500_UART1_BASE (U8500_PER1_BASE + 0x1000)
-
-/* per6 base addresses */
-#define U8500_RNG_BASE (U8500_PER6_BASE + 0x0000)
-#define U8500_HASH0_BASE (U8500_PER6_BASE + 0x1000)
-#define U8500_HASH1_BASE (U8500_PER6_BASE + 0x2000)
-#define U8500_PKA_BASE (U8500_PER6_BASE + 0x4000)
-#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x5100)
-#define U8500_MTU0_BASE (U8500_PER6_BASE + 0x6000) /* v1 */
-#define U8500_MTU1_BASE (U8500_PER6_BASE + 0x7000) /* v1 */
-#define U8500_CR_BASE (U8500_PER6_BASE + 0x8000) /* v1 */
-#define U8500_CRYP0_BASE (U8500_PER6_BASE + 0xa000)
-#define U8500_CRYP1_BASE (U8500_PER6_BASE + 0xb000)
-#define U8500_CLKRST6_BASE (U8500_PER6_BASE + 0xf000)
-
-/* per5 base addresses */
-#define U8500_USBOTG_BASE (U8500_PER5_BASE + 0x00000)
-#define U8500_CLKRST5_BASE (U8500_PER5_BASE + 0x1f000)
-
-/* per4 base addresses */
-#define U8500_BACKUPRAM0_BASE (U8500_PER4_BASE + 0x00000)
-#define U8500_BACKUPRAM1_BASE (U8500_PER4_BASE + 0x01000)
-#define U8500_RTT0_BASE (U8500_PER4_BASE + 0x02000)
-#define U8500_RTT1_BASE (U8500_PER4_BASE + 0x03000)
-#define U8500_RTC_BASE (U8500_PER4_BASE + 0x04000)
-#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
-#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
-#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
-#define U9540_DMC1_BASE (U8500_PER4_BASE + 0x0A000)
-#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
-#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
-#define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
-#define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)
-
-/* per3 base addresses */
-#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
-#define U8500_SSP0_BASE (U8500_PER3_BASE + 0x2000)
-#define U8500_SSP1_BASE (U8500_PER3_BASE + 0x3000)
-#define U8500_I2C0_BASE (U8500_PER3_BASE + 0x4000)
-#define U8500_SDI2_BASE (U8500_PER3_BASE + 0x5000)
-#define U8500_SKE_BASE (U8500_PER3_BASE + 0x6000)
-#define U8500_UART2_BASE (U8500_PER3_BASE + 0x7000)
-#define U8500_SDI5_BASE (U8500_PER3_BASE + 0x8000)
-#define U8500_CLKRST3_BASE (U8500_PER3_BASE + 0xf000)
-
-/* per2 base addresses */
-#define U8500_I2C3_BASE (U8500_PER2_BASE + 0x0000)
-#define U8500_SPI2_BASE (U8500_PER2_BASE + 0x1000)
-#define U8500_SPI1_BASE (U8500_PER2_BASE + 0x2000)
-#define U8500_PWL_BASE (U8500_PER2_BASE + 0x3000)
-#define U8500_SDI4_BASE (U8500_PER2_BASE + 0x4000)
-#define U8500_MSP2_BASE (U8500_PER2_BASE + 0x7000)
-#define U8500_SDI1_BASE (U8500_PER2_BASE + 0x8000)
-#define U8500_SDI3_BASE (U8500_PER2_BASE + 0x9000)
-#define U8500_SPI0_BASE (U8500_PER2_BASE + 0xa000)
-#define U8500_HSIR_BASE (U8500_PER2_BASE + 0xb000)
-#define U8500_HSIT_BASE (U8500_PER2_BASE + 0xc000)
-#define U8500_CLKRST2_BASE (U8500_PER2_BASE + 0xf000)
-
-/* per1 base addresses */
-#define U8500_I2C1_BASE (U8500_PER1_BASE + 0x2000)
-#define U8500_MSP0_BASE (U8500_PER1_BASE + 0x3000)
-#define U8500_MSP1_BASE (U8500_PER1_BASE + 0x4000)
-#define U8500_MSP3_BASE (U8500_PER1_BASE + 0x5000)
-#define U8500_SDI0_BASE (U8500_PER1_BASE + 0x6000)
-#define U8500_I2C2_BASE (U8500_PER1_BASE + 0x8000)
-#define U8500_SPI3_BASE (U8500_PER1_BASE + 0x9000)
-#define U8500_I2C4_BASE (U8500_PER1_BASE + 0xa000)
-#define U8500_SLIM0_BASE (U8500_PER1_BASE + 0xb000)
-#define U8500_CLKRST1_BASE (U8500_PER1_BASE + 0xf000)
-
-#define U8500_SHRM_GOP_INTERRUPT_BASE 0xB7C00040
-
-#define U8500_GPIOBANK0_BASE U8500_GPIO0_BASE
-#define U8500_GPIOBANK1_BASE (U8500_GPIO0_BASE + 0x80)
-#define U8500_GPIOBANK2_BASE U8500_GPIO1_BASE
-#define U8500_GPIOBANK3_BASE (U8500_GPIO1_BASE + 0x80)
-#define U8500_GPIOBANK4_BASE (U8500_GPIO1_BASE + 0x100)
-#define U8500_GPIOBANK5_BASE (U8500_GPIO1_BASE + 0x180)
-#define U8500_GPIOBANK6_BASE U8500_GPIO2_BASE
-#define U8500_GPIOBANK7_BASE (U8500_GPIO2_BASE + 0x80)
-#define U8500_GPIOBANK8_BASE U8500_GPIO3_BASE
-
-#define U8500_MCDE_SIZE 0x1000
-#define U8500_DSI_LINK_SIZE 0x1000
-#define U8500_DSI_LINK1_BASE (U8500_MCDE_BASE + U8500_MCDE_SIZE)
-#define U8500_DSI_LINK2_BASE (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
-#define U8500_DSI_LINK3_BASE (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
-#define U8500_DSI_LINK_COUNT 0x3
-
-/* Modem and APE physical addresses */
-#define U8500_MODEM_BASE 0xe000000
-#define U8500_APE_BASE 0x6000000
-
-/* SoC identification number information */
-#define U8500_BB_UID_BASE (U8500_BACKUPRAM1_BASE + 0xFC0)
-
-/* Offsets to specific addresses in some IP blocks for DMA */
-#define MSP_TX_RX_REG_OFFSET 0
-#define CRYP1_RX_REG_OFFSET 0x10
-#define CRYP1_TX_REG_OFFSET 0x8
-#define HASH1_TX_REG_OFFSET 0x4
-
-/*
- * Macros to get at IO space when running virtually
- * We dont map all the peripherals, let ioremap do
- * this for us. We map only very basic peripherals here.
- */
-#define U8500_IO_VIRTUAL 0xf0000000
-#define U8500_IO_PHYSICAL 0xa0000000
-/* This is where we map in the ROM to check ASIC IDs */
-#define UX500_VIRT_ROM IOMEM(0xf0000000)
-
-/* This macro is used in assembly, so no cast */
-#define IO_ADDRESS(x) \
- (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + U8500_IO_VIRTUAL)
-
-/* typesafe io address */
-#define __io_address(n) IOMEM(IO_ADDRESS(n))
-
-/* Used by some plat-nomadik code */
-#define io_p2v(n) __io_address(n)
-
-#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
-
-#endif
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 415d8ad2a3c1..656b58bd296a 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -20,8 +20,6 @@
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
-#include "db8500-regs.h"
-
/* Magic triggers in backup RAM */
#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
index ff9c375e4277..dc962d006b08 100644
--- a/arch/arm/mach-ux500/pm.c
+++ b/arch/arm/mach-ux500/pm.c
@@ -16,8 +16,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
-#include "db8500-regs.h"
-
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130)
#define PRCM_ARM_WFI_STANDBY_WFI0 0x08
@@ -124,7 +122,7 @@ bool prcmu_pending_irq(void)
}
/*
- * This function checks if the specified cpu is in in WFI. It's usage
+ * This function checks if the specified cpu is in WFI. It's usage
* makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
* function. Of course passing smp_processor_id() to this function will
* always return false...
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index d7909091cf97..c135f6e37a00 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -564,14 +564,6 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
if (mask < 0xffffffffULL)
gfp |= GFP_DMA;
- /*
- * Following is a work-around (a.k.a. hack) to prevent pages
- * with __GFP_COMP being passed to split_page() which cannot
- * handle them. The real problem is that this flag probably
- * should be 0 on ARM as it is not supported on this
- * platform; see CONFIG_HUGETLBFS.
- */
- gfp &= ~(__GFP_COMP);
args.gfp = gfp;
*handle = DMA_MAPPING_ERROR;
@@ -1093,15 +1085,6 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
return __iommu_alloc_simple(dev, size, gfp, handle,
coherent_flag, attrs);
- /*
- * Following is a work-around (a.k.a. hack) to prevent pages
- * with __GFP_COMP being passed to split_page() which cannot
- * handle them. The real problem is that this flag probably
- * should be 0 on ARM as it is not supported on this
- * platform; see CONFIG_HUGETLBFS.
- */
- gfp &= ~(__GFP_COMP);
-
pages = __iommu_alloc_buffer(dev, size, gfp, attrs, coherent_flag);
if (!pages)
return NULL;
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 46cccd6bf705..de988cba9a4b 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -105,6 +105,19 @@ static inline bool is_write_fault(unsigned int fsr)
return (fsr & FSR_WRITE) && !(fsr & FSR_CM);
}
+static inline bool is_translation_fault(unsigned int fsr)
+{
+ int fs = fsr_fs(fsr);
+#ifdef CONFIG_ARM_LPAE
+ if ((fs & FS_MMU_NOLL_MASK) == FS_TRANS_NOLL)
+ return true;
+#else
+ if (fs == FS_L1_TRANS || fs == FS_L2_TRANS)
+ return true;
+#endif
+ return false;
+}
+
static void die_kernel_fault(const char *msg, struct mm_struct *mm,
unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
@@ -140,7 +153,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
if (addr < PAGE_SIZE) {
msg = "NULL pointer dereference";
} else {
- if (kfence_handle_page_fault(addr, is_write_fault(fsr), regs))
+ if (is_translation_fault(fsr) &&
+ kfence_handle_page_fault(addr, is_write_fault(fsr), regs))
return;
msg = "paging request";
@@ -208,7 +222,7 @@ static inline bool is_permission_fault(unsigned int fsr)
{
int fs = fsr_fs(fsr);
#ifdef CONFIG_ARM_LPAE
- if ((fs & FS_PERM_NOLL_MASK) == FS_PERM_NOLL)
+ if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
return true;
#else
if (fs == FS_L1_PERM || fs == FS_L2_PERM)
diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h
index 83b5ab32d7a4..54927ba1fa6e 100644
--- a/arch/arm/mm/fault.h
+++ b/arch/arm/mm/fault.h
@@ -14,8 +14,9 @@
#ifdef CONFIG_ARM_LPAE
#define FSR_FS_AEA 17
+#define FS_TRANS_NOLL 0x4
#define FS_PERM_NOLL 0xC
-#define FS_PERM_NOLL_MASK 0x3C
+#define FS_MMU_NOLL_MASK 0x3C
static inline int fsr_fs(unsigned int fsr)
{
@@ -23,8 +24,10 @@ static inline int fsr_fs(unsigned int fsr)
}
#else
#define FSR_FS_AEA 22
-#define FS_L1_PERM 0xD
-#define FS_L2_PERM 0xF
+#define FS_L1_TRANS 0x5
+#define FS_L2_TRANS 0x7
+#define FS_L1_PERM 0xD
+#define FS_L2_PERM 0xF
static inline int fsr_fs(unsigned int fsr)
{
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index c42debaded95..c1494a4dee25 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -26,6 +26,13 @@
unsigned long vectors_base;
+/*
+ * empty_zero_page is a special page that is used for
+ * zero-initialized data and COW.
+ */
+struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
+
#ifdef CONFIG_ARM_MPU
struct mpu_rgn_info mpu_rgn_info;
#endif
@@ -148,9 +155,21 @@ void __init adjust_lowmem_bounds(void)
*/
void __init paging_init(const struct machine_desc *mdesc)
{
+ void *zero_page;
+
early_trap_init((void *)vectors_base);
mpu_setup();
+
+ /* allocate the zero page. */
+ zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+ if (!zero_page)
+ panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
+ __func__, PAGE_SIZE, PAGE_SIZE);
+
bootmem_init();
+
+ empty_zero_page = virt_to_page(zero_page);
+ flush_dcache_page(empty_zero_page);
}
/*
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 93c8ccbf2982..7d59765aef22 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -445,7 +445,7 @@ static int __init xen_guest_init(void)
return 0;
if (IS_ENABLED(CONFIG_XEN_VIRTIO))
- virtio_set_mem_acc_cb(xen_virtio_mem_acc);
+ virtio_set_mem_acc_cb(xen_virtio_restricted_mem_acc);
if (!acpi_disabled)
xen_acpi_guest_init();
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 505c8a1ccbe0..7fc3457a8891 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config ARM64
def_bool y
+ select ACPI_APMT if ACPI
select ACPI_CCA_REQUIRED if ACPI
select ACPI_GENERIC_GSI if ACPI
select ACPI_GTDT if ACPI
@@ -31,6 +32,7 @@ config ARM64
select ARCH_HAS_KCOV
select ARCH_HAS_KEEPINITRD
select ARCH_HAS_MEMBARRIER_SYNC_CORE
+ select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
select ARCH_HAS_PTE_DEVMAP
select ARCH_HAS_PTE_SPECIAL
@@ -117,6 +119,7 @@ config ARM64
select CPU_PM if (SUSPEND || CPU_IDLE)
select CRC32
select DCACHE_WORD_ACCESS
+ select DYNAMIC_FTRACE if FUNCTION_TRACER
select DMA_DIRECT_REMAP
select EDAC_SUPPORT
select FRAME_POINTER
@@ -181,8 +184,10 @@ config ARM64
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE
+ select HAVE_DYNAMIC_FTRACE_WITH_ARGS \
+ if $(cc-option,-fpatchable-function-entry=2)
select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
- if DYNAMIC_FTRACE_WITH_REGS
+ if DYNAMIC_FTRACE_WITH_ARGS
select HAVE_EFFICIENT_UNALIGNED_ACCESS
select HAVE_FAST_GUP
select HAVE_FTRACE_MCOUNT_RECORD
@@ -233,16 +238,16 @@ config ARM64
help
ARM 64-bit (AArch64) Linux support.
-config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS
+config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS
def_bool CC_IS_CLANG
# https://github.com/ClangBuiltLinux/linux/issues/1507
depends on AS_IS_GNU || (AS_IS_LLVM && (LD_IS_LLD || LD_VERSION >= 23600))
- select HAVE_DYNAMIC_FTRACE_WITH_REGS
+ select HAVE_DYNAMIC_FTRACE_WITH_ARGS
-config GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS
+config GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS
def_bool CC_IS_GCC
depends on $(cc-option,-fpatchable-function-entry=2)
- select HAVE_DYNAMIC_FTRACE_WITH_REGS
+ select HAVE_DYNAMIC_FTRACE_WITH_ARGS
config 64BIT
def_bool y
@@ -370,6 +375,9 @@ config KASAN_SHADOW_OFFSET
default 0xeffffff800000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
default 0xffffffffffffffff
+config UNWIND_TABLES
+ bool
+
source "arch/arm64/Kconfig.platforms"
menu "Kernel Features"
@@ -964,6 +972,22 @@ config ARM64_ERRATUM_2457168
If unsure, say Y.
+config ARM64_ERRATUM_2645198
+ bool "Cortex-A715: 2645198: Workaround possible [ESR|FAR]_ELx corruption"
+ default y
+ help
+ This option adds the workaround for ARM Cortex-A715 erratum 2645198.
+
+ If a Cortex-A715 cpu sees a page mapping permissions change from executable
+ to non-executable, it may corrupt the ESR_ELx and FAR_ELx registers on the
+ next instruction abort caused by permission fault.
+
+ Only user-space does executable to non-executable permission transition via
+ mprotect() system call. Workaround the problem by doing a break-before-make
+ TLB invalidation, for all changes to executable user space mappings.
+
+ If unsure, say Y.
+
config CAVIUM_ERRATUM_22375
bool "Cavium erratum 22375, 24313"
default y
@@ -1714,7 +1738,6 @@ config ARM64_LSE_ATOMICS
config ARM64_USE_LSE_ATOMICS
bool "Atomic instructions"
- depends on JUMP_LABEL
default y
help
As part of the Large System Extensions, ARMv8.1 introduces new
@@ -1816,7 +1839,7 @@ config ARM64_PTR_AUTH_KERNEL
# which is only understood by binutils starting with version 2.33.1.
depends on LD_IS_LLD || LD_VERSION >= 23301 || (CC_IS_GCC && GCC_VERSION < 90100)
depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE
- depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
+ depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_ARGS)
help
If the compiler supports the -mbranch-protection or
-msign-return-address flag (e.g. GCC 7 or later), then this option
@@ -1826,7 +1849,7 @@ config ARM64_PTR_AUTH_KERNEL
disabled with minimal loss of protection.
This feature works with FUNCTION_GRAPH_TRACER option only if
- DYNAMIC_FTRACE_WITH_REGS is enabled.
+ DYNAMIC_FTRACE_WITH_ARGS is enabled.
config CC_HAS_BRANCH_PROT_PAC_RET
# GCC 9 or later, clang 8 or later
@@ -1924,7 +1947,7 @@ config ARM64_BTI_KERNEL
depends on !CC_IS_GCC
# https://github.com/llvm/llvm-project/commit/a88c722e687e6780dcd6a58718350dc76fcc4cc9
depends on !CC_IS_CLANG || CLANG_VERSION >= 120000
- depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
+ depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_ARGS)
help
Build the kernel with Branch Target Identification annotations
and enable enforcement of this for kernel code. When this option
@@ -2157,6 +2180,15 @@ config ARCH_NR_GPIO
If unsure, leave the default value.
+config UNWIND_PATCH_PAC_INTO_SCS
+ bool "Enable shadow call stack dynamically using code patching"
+ # needs Clang with https://reviews.llvm.org/D111780 incorporated
+ depends on CC_IS_CLANG && CLANG_VERSION >= 150000
+ depends on ARM64_PTR_AUTH_KERNEL && CC_HAS_BRANCH_PROT_PAC_RET
+ depends on SHADOW_CALL_STACK
+ select UNWIND_TABLES
+ select DYNAMIC_SCS
+
endmenu # "Kernel Features"
menu "Boot options"
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 76580b932e44..d1970adf80ab 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -252,8 +252,6 @@ config ARCH_REALTEK
config ARCH_RENESAS
bool "Renesas SoC Platforms"
- select GPIOLIB
- select PINCTRL
help
This enables support for the ARMv8 based Renesas SoCs.
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 5e56d26a2239..d62bd221828f 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -45,8 +45,13 @@ KBUILD_CFLAGS += $(call cc-option,-mabi=lp64)
KBUILD_AFLAGS += $(call cc-option,-mabi=lp64)
# Avoid generating .eh_frame* sections.
+ifneq ($(CONFIG_UNWIND_TABLES),y)
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
KBUILD_AFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
+else
+KBUILD_CFLAGS += -fasynchronous-unwind-tables
+KBUILD_AFLAGS += -fasynchronous-unwind-tables
+endif
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
prepare: stack_protector_prepare
@@ -72,10 +77,16 @@ branch-prot-flags-$(CONFIG_CC_HAS_SIGN_RETURN_ADDRESS) := -msign-return-address=
# We enable additional protection for leaf functions as there is some
# narrow potential for ROP protection benefits and no substantial
# performance impact has been observed.
+PACRET-y := pac-ret+leaf
+
+# Using a shadow call stack in leaf functions is too costly, so avoid PAC there
+# as well when we may be patching PAC into SCS
+PACRET-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) := pac-ret
+
ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
-branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI) := -mbranch-protection=pac-ret+leaf+bti
+branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI) := -mbranch-protection=$(PACRET-y)+bti
else
-branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=pac-ret+leaf
+branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=$(PACRET-y)
endif
# -march=armv8.3-a enables the non-nops instructions for PAC, to avoid the
# compiler to generate them and consequently to break the single image contract
@@ -128,7 +139,7 @@ endif
CHECKFLAGS += -D__aarch64__
-ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_REGS),y)
+ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_ARGS),y)
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
CC_FLAGS_FTRACE := -fpatchable-function-entry=2
endif
diff --git a/arch/arm64/boot/dts/allwinner/axp803.dtsi b/arch/arm64/boot/dts/allwinner/axp803.dtsi
index 578ef368e2b4..a6b4b87f185d 100644
--- a/arch/arm64/boot/dts/allwinner/axp803.dtsi
+++ b/arch/arm64/boot/dts/allwinner/axp803.dtsi
@@ -25,16 +25,6 @@
compatible = "x-powers,axp803-gpio", "x-powers,axp813-gpio";
gpio-controller;
#gpio-cells = <2>;
-
- gpio0_ldo: gpio0-ldo-pin {
- pins = "GPIO0";
- function = "ldo";
- };
-
- gpio1_ldo: gpio1-ldo-pin {
- pins = "GPIO1";
- function = "ldo";
- };
};
battery_power_supply: battery-power {
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
index 620cb3ef5f6c..50ed2e9f10ed 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
@@ -406,6 +406,20 @@
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "realtek,rtl8723cs-bt";
+ device-wake-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL5 */
+ enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+ host-wake-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+ };
+};
+
&usb_otg {
dr_mode = "host";
};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 53f6660656ac..ca1d287a0a01 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -161,6 +161,7 @@
clocks = <&ccu CLK_BUS_VP9>, <&ccu CLK_VP9>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_VP9>;
+ iommus = <&iommu 5>;
};
video-codec@1c0e000 {
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts
index 02893f3ac99d..cb8600d0ea1e 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts
@@ -49,8 +49,24 @@
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
+
+ reg_usb1_vbus: regulator-usb1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb1-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&reg_vcc5v>;
+ enable-active-high;
+ gpio = <&pio 2 16 GPIO_ACTIVE_HIGH>; /* PC16 */
+ };
};
+&ehci1 {
+ status = "okay";
+};
+
+/* USB 2 & 3 are on headers only. */
+
&emac0 {
pinctrl-names = "default";
pinctrl-0 = <&ext_rgmii_pins>;
@@ -76,6 +92,10 @@
status = "okay";
};
+&ohci1 {
+ status = "okay";
+};
+
&r_rsb {
status = "okay";
@@ -211,3 +231,24 @@
pinctrl-0 = <&uart0_ph_pins>;
status = "okay";
};
+
+&usbotg {
+ /*
+ * PHY0 pins are connected to a USB-C socket, but a role switch
+ * is not implemented: both CC pins are pulled to GND.
+ * The VBUS pins power the device, so a fixed peripheral mode
+ * is the best choice.
+ * The board can be powered via GPIOs, in this case port0 *can*
+ * act as a host (with a cable/adapter ignoring CC), as VBUS is
+ * then provided by the GPIOs. Any user of this setup would
+ * need to adjust the DT accordingly: dr_mode set to "host",
+ * enabling OHCI0 and EHCI0.
+ */
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts
index 6619db34714a..07424c28b696 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts
@@ -32,6 +32,14 @@
};
};
+&ehci0 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
&ir {
status = "okay";
};
@@ -54,6 +62,14 @@
status = "okay";
};
+&ohci0 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
&r_rsb {
status = "okay";
@@ -175,3 +191,12 @@
pinctrl-0 = <&uart0_ph_pins>;
status = "okay";
};
+
+&usbotg {
+ dr_mode = "host"; /* USB A type receptable */
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index 622a1f7d1641..74aed0d232a9 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -504,6 +504,166 @@
};
};
+ usbotg: usb@5100000 {
+ compatible = "allwinner,sun50i-h616-musb",
+ "allwinner,sun8i-h3-musb";
+ reg = <0x05100000 0x0400>;
+ clocks = <&ccu CLK_BUS_OTG>;
+ resets = <&ccu RST_BUS_OTG>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ status = "disabled";
+ };
+
+ usbphy: phy@5100400 {
+ compatible = "allwinner,sun50i-h616-usb-phy";
+ reg = <0x05100400 0x24>,
+ <0x05101800 0x14>,
+ <0x05200800 0x14>,
+ <0x05310800 0x14>,
+ <0x05311800 0x14>;
+ reg-names = "phy_ctrl",
+ "pmu0",
+ "pmu1",
+ "pmu2",
+ "pmu3";
+ clocks = <&ccu CLK_USB_PHY0>,
+ <&ccu CLK_USB_PHY1>,
+ <&ccu CLK_USB_PHY2>,
+ <&ccu CLK_USB_PHY3>,
+ <&ccu CLK_BUS_EHCI2>;
+ clock-names = "usb0_phy",
+ "usb1_phy",
+ "usb2_phy",
+ "usb3_phy",
+ "pmu2_clk";
+ resets = <&ccu RST_USB_PHY0>,
+ <&ccu RST_USB_PHY1>,
+ <&ccu RST_USB_PHY2>,
+ <&ccu RST_USB_PHY3>;
+ reset-names = "usb0_reset",
+ "usb1_reset",
+ "usb2_reset",
+ "usb3_reset";
+ status = "disabled";
+ #phy-cells = <1>;
+ };
+
+ ehci0: usb@5101000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05101000 0x100>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_BUS_EHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_OHCI0>,
+ <&ccu RST_BUS_EHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@5101400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05101400 0x100>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci1: usb@5200000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05200000 0x100>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI1>,
+ <&ccu CLK_BUS_EHCI1>,
+ <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_BUS_OHCI1>,
+ <&ccu RST_BUS_EHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci1: usb@5200400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05200400 0x100>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI1>,
+ <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_BUS_OHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci2: usb@5310000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05310000 0x100>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI2>,
+ <&ccu CLK_BUS_EHCI2>,
+ <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_BUS_OHCI2>,
+ <&ccu RST_BUS_EHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci2: usb@5310400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05310400 0x100>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI2>,
+ <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_BUS_OHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci3: usb@5311000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05311000 0x100>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI3>,
+ <&ccu CLK_BUS_EHCI3>,
+ <&ccu CLK_USB_OHCI3>;
+ resets = <&ccu RST_BUS_OHCI3>,
+ <&ccu RST_BUS_EHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci3: usb@5311400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05311400 0x100>;
+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI3>,
+ <&ccu CLK_USB_OHCI3>;
+ resets = <&ccu RST_BUS_OHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
rtc: rtc@7000000 {
compatible = "allwinner,sun50i-h616-rtc";
reg = <0x07000000 0x400>;
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
index 14c220d87807..55c5e1fdddc7 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -309,6 +309,7 @@
<&clkmgr STRATIX10_SDMMC_CLK>;
clock-names = "biu", "ciu";
iommus = <&smmu 5>;
+ altr,sysmgr-syscon = <&sysmgr 0x28 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
index 48424e459f12..17752ca743e5 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
@@ -22,17 +22,17 @@
leds {
compatible = "gpio-leds";
- hps0 {
+ led-hps0 {
label = "hps_led0";
gpios = <&portb 20 GPIO_ACTIVE_HIGH>;
};
- hps1 {
+ led-hps1 {
label = "hps_led1";
gpios = <&portb 19 GPIO_ACTIVE_HIGH>;
};
- hps2 {
+ led-hps2 {
label = "hps_led2";
gpios = <&portb 21 GPIO_ACTIVE_HIGH>;
};
@@ -105,6 +105,7 @@
cap-mmc-highspeed;
broken-cd;
bus-width = <4>;
+ clk-phase-sd-hs = <0>, <135>;
};
&osc1 {
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts
index 847a7c01f5af..ede99dcc0558 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts
@@ -22,17 +22,17 @@
leds {
compatible = "gpio-leds";
- hps0 {
+ led-hps0 {
label = "hps_led0";
gpios = <&portb 20 GPIO_ACTIVE_HIGH>;
};
- hps1 {
+ led-hps1 {
label = "hps_led1";
gpios = <&portb 19 GPIO_ACTIVE_HIGH>;
};
- hps2 {
+ led-hps2 {
label = "hps_led2";
gpios = <&portb 21 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
index e213aeebb774..97b42e2100e0 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gsking-x.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking-pro.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-go-ultra.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2-plus.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb
diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
index b4000cf65a9a..d2f7cb4e5375 100644
--- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
@@ -36,6 +36,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
index 04f797b5a012..1648e67afbb6 100644
--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
@@ -105,6 +105,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
index 45947c1031c4..9dbd50820b1c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
@@ -1705,6 +1705,12 @@
};
};
+ pmu: pmu@ff638000 {
+ reg = <0x0 0xff638000 0x0 0x100>,
+ <0x0 0xff638c00 0x0 0x100>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_EDGE_RISING>;
+ };
+
aobus: bus@ff800000 {
compatible = "simple-bus";
reg = <0x0 0xff800000 0x0 0x100000>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
index fb0ab27d1f64..7677764eeee6 100644
--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
@@ -50,6 +50,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -133,3 +134,7 @@
};
};
};
+
+&pmu {
+ compatible = "amlogic,g12a-ddr-pmu";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-go-ultra.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-go-ultra.dts
new file mode 100644
index 000000000000..1e40709610c5
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-go-ultra.dts
@@ -0,0 +1,722 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Neil Armstrong <neil.armstrong@linaro.org>
+ */
+
+/dts-v1/;
+
+#include "meson-g12b-s922x.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-toacodec.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
+
+/ {
+ compatible = "hardkernel,odroid-go-ultra", "amlogic,s922x", "amlogic,g12b";
+ model = "Hardkernel ODROID-GO-Ultra";
+
+ aliases {
+ serial0 = &uart_AO;
+ rtc0 = &vrtc;
+ };
+
+ adc-joystick-left {
+ compatible = "adc-joystick";
+ io-channels = <&saradc 2>, <&saradc 3>;
+ poll-interval = <10>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axis@0 {
+ reg = <0>;
+ linux,code = <ABS_Y>;
+ abs-range = <3150 950>;
+ abs-fuzz = <32>;
+ abs-flat = <64>;
+ };
+ axis@1 {
+ reg = <1>;
+ linux,code = <ABS_X>;
+ abs-range = <700 2900>;
+ abs-fuzz = <32>;
+ abs-flat = <64>;
+ };
+ };
+
+ adc-joystick-right {
+ compatible = "adc-joystick";
+ io-channels = <&saradc 0>, <&saradc 1>;
+ poll-interval = <10>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axis@0 {
+ reg = <0>;
+ linux,code = <ABS_RY>;
+ abs-range = <3150 950>;
+ abs-fuzz = <32>;
+ abs-flat = <64>;
+ };
+ axis@1 {
+ reg = <1>;
+ linux,code = <ABS_RX>;
+ abs-range = <800 3000>;
+ abs-fuzz = <32>;
+ abs-flat = <64>;
+ };
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ codec_clk: codec-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <12288000>;
+ clock-output-names = "codec_clk";
+ #clock-cells = <0>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys-polled";
+ poll-interval = <10>;
+ pinctrl-0 = <&keypad_gpio_pins>;
+ pinctrl-names = "default";
+
+ volume-up-button {
+ label = "VOLUME-UP";
+ linux,code = <KEY_VOLUMEUP>;
+ gpios = <&gpio GPIOX_8 GPIO_ACTIVE_LOW>;
+ };
+ volume-down-button {
+ label = "VOLUME-DOWN";
+ linux,code = <KEY_VOLUMEDOWN>;
+ gpios = <&gpio GPIOX_9 GPIO_ACTIVE_LOW>;
+ };
+ dpad-up-button {
+ label = "DPAD-UP";
+ linux,code = <BTN_DPAD_UP>;
+ gpios = <&gpio GPIOX_0 GPIO_ACTIVE_LOW>;
+ };
+ dpad-down-button {
+ label = "DPAD-DOWN";
+ linux,code = <BTN_DPAD_DOWN>;
+ gpios = <&gpio GPIOX_1 GPIO_ACTIVE_LOW>;
+ };
+ dpad-left-button {
+ label = "DPAD-LEFT";
+ linux,code = <BTN_DPAD_LEFT>;
+ gpios = <&gpio GPIOX_2 GPIO_ACTIVE_LOW>;
+ };
+ dpad-right-button {
+ label = "DPAD-RIGHT";
+ linux,code = <BTN_DPAD_RIGHT>;
+ gpios = <&gpio GPIOX_3 GPIO_ACTIVE_LOW>;
+ };
+ a-button {
+ label = "A";
+ linux,code = <BTN_EAST>;
+ gpios = <&gpio GPIOX_4 GPIO_ACTIVE_LOW>;
+ };
+ b-button {
+ label = "B";
+ linux,code = <BTN_SOUTH>;
+ gpios = <&gpio GPIOX_5 GPIO_ACTIVE_LOW>;
+ };
+ y-button {
+ label = "Y";
+ linux,code = <BTN_WEST>;
+ gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+ };
+ x-button {
+ label = "X";
+ linux,code = <BTN_NORTH>;
+ gpios = <&gpio GPIOX_7 GPIO_ACTIVE_LOW>;
+ };
+ f1-button {
+ label = "F1";
+ linux,code = <BTN_TRIGGER_HAPPY1>;
+ gpios = <&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
+ };
+ f2-button {
+ label = "F2";
+ linux,code = <BTN_TRIGGER_HAPPY2>;
+ gpios = <&gpio GPIOX_10 GPIO_ACTIVE_LOW>;
+ };
+ f3-button {
+ label = "F3";
+ linux,code = <BTN_TRIGGER_HAPPY3>;
+ gpios = <&gpio GPIOX_11 GPIO_ACTIVE_LOW>;
+ };
+ f4-button {
+ label = "F4";
+ linux,code = <BTN_TRIGGER_HAPPY4>;
+ gpios = <&gpio GPIOX_12 GPIO_ACTIVE_LOW>;
+ };
+ f5-button {
+ label = "F5";
+ linux,code = <BTN_TRIGGER_HAPPY5>;
+ gpios = <&gpio GPIOX_13 GPIO_ACTIVE_LOW>;
+ };
+ f6-button {
+ label = "F6";
+ linux,code = <BTN_TRIGGER_HAPPY6>;
+ gpios = <&gpio GPIOX_16 GPIO_ACTIVE_LOW>;
+ };
+ top-left-button {
+ label = "TOP Left";
+ linux,code = <BTN_TL>;
+ gpios = <&gpio GPIOX_14 GPIO_ACTIVE_LOW>;
+ };
+ top-left2-button {
+ label = "TOP Left 2";
+ linux,code = <BTN_TL2>;
+ gpios = <&gpio GPIOX_19 GPIO_ACTIVE_LOW>;
+ };
+ top-right-button {
+ label = "TOP Right";
+ linux,code = <BTN_TR>;
+ gpios = <&gpio GPIOX_15 GPIO_ACTIVE_LOW>;
+ };
+ top-right2-button {
+ label = "TOP Right 2";
+ linux,code = <BTN_TR2>;
+ gpios = <&gpio GPIOX_18 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x40000000>;
+ };
+
+ emmc_pwrseq: emmc-pwrseq {
+ compatible = "mmc-pwrseq-emmc";
+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-blue {
+ color = <LED_COLOR_ID_BLUE>;
+ gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ vdd_sys: regulator-vdd-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_SYS";
+ regulator-min-microvolt = <3800000>;
+ regulator-max-microvolt = <3800000>;
+ regulator-always-on;
+ };
+
+ sound {
+ compatible = "amlogic,axg-sound-card";
+ model = "Odroid GO Ultra";
+ audio-widgets = "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Internal Speakers";
+ audio-aux-devs = <&tdmout_b>, <&tdmin_b>, <&speaker_amp>;
+ audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+ "TDM_B Playback", "TDMOUT_B OUT",
+ "TDMIN_B IN 1", "TDM_B Capture",
+ "TDMIN_B IN 4", "TDM_B Loopback",
+ "TODDR_A IN 1", "TDMIN_B OUT",
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Speaker Amplifier INL", "HPOL",
+ "Speaker Amplifier INR", "HPOR",
+ "Internal Speakers", "Speaker Amplifier OUTL",
+ "Internal Speakers", "Speaker Amplifier OUTR";
+
+ assigned-clocks = <&clkc CLKID_MPLL2>,
+ <&clkc CLKID_MPLL0>,
+ <&clkc CLKID_MPLL1>;
+ assigned-clock-parents = <0>, <0>, <0>;
+ assigned-clock-rates = <294912000>,
+ <270950400>,
+ <393216000>;
+
+ dai-link-0 {
+ sound-dai = <&frddr_a>;
+ };
+
+ dai-link-1 {
+ sound-dai = <&toddr_a>;
+ };
+
+ dai-link-2 {
+ sound-dai = <&tdmif_b>;
+ dai-format = "i2s";
+ dai-tdm-slot-tx-mask-0 = <1 1>;
+ mclk-fs = <256>;
+
+ codec-0 {
+ sound-dai = <&rk817>;
+ };
+ };
+ };
+
+ speaker_amp: speaker-amplifier {
+ compatible = "simple-audio-amplifier";
+ sound-name-prefix = "Speaker Amplifier";
+ VCC-supply = <&hp_5v>;
+ };
+};
+
+&arb {
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&vddcpu_b>;
+ operating-points-v2 = <&cpu_opp_table_0>;
+ clocks = <&clkc CLKID_CPU_CLK>;
+ clock-latency = <50000>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcpu_b>;
+ operating-points-v2 = <&cpu_opp_table_0>;
+ clocks = <&clkc CLKID_CPU_CLK>;
+ clock-latency = <50000>;
+};
+
+&cpu100 {
+ cpu-supply = <&vddcpu_a>;
+ operating-points-v2 = <&cpub_opp_table_1>;
+ clocks = <&clkc CLKID_CPUB_CLK>;
+ clock-latency = <50000>;
+};
+
+&cpu101 {
+ cpu-supply = <&vddcpu_a>;
+ operating-points-v2 = <&cpub_opp_table_1>;
+ clocks = <&clkc CLKID_CPUB_CLK>;
+ clock-latency = <50000>;
+};
+
+&cpu102 {
+ cpu-supply = <&vddcpu_a>;
+ operating-points-v2 = <&cpub_opp_table_1>;
+ clocks = <&clkc CLKID_CPUB_CLK>;
+ clock-latency = <50000>;
+};
+
+&cpu103 {
+ cpu-supply = <&vddcpu_a>;
+ operating-points-v2 = <&cpub_opp_table_1>;
+ clocks = <&clkc CLKID_CPUB_CLK>;
+ clock-latency = <50000>;
+};
+
+/* RK817 only supports 12.5mV steps, round up the values */
+&cpu_opp_table_0 {
+ opp-1000000000 {
+ opp-microvolt = <737500>;
+ };
+ opp-1200000000 {
+ opp-microvolt = <737500>;
+ };
+ opp-1398000000 {
+ opp-microvolt = <762500>;
+ };
+ opp-1512000000 {
+ opp-microvolt = <800000>;
+ };
+ opp-1608000000 {
+ opp-microvolt = <837500>;
+ };
+ opp-1704000000 {
+ opp-microvolt = <862500>;
+ };
+ opp-1896000000 {
+ opp-microvolt = <987500>;
+ };
+ opp-1992000000 {
+ opp-microvolt = <1012500>;
+ };
+};
+
+/* RK818 only supports 12.5mV steps, round up the values */
+&cpub_opp_table_1 {
+ opp-1000000000 {
+ opp-microvolt = <775000>;
+ };
+ opp-1200000000 {
+ opp-microvolt = <775000>;
+ };
+ opp-1398000000 {
+ opp-microvolt = <800000>;
+ };
+ opp-1512000000 {
+ opp-microvolt = <825000>;
+ };
+ opp-1608000000 {
+ opp-microvolt = <862500>;
+ };
+ opp-1704000000 {
+ opp-microvolt = <900000>;
+ };
+ opp-1800000000 {
+ opp-microvolt = <987500>;
+ };
+ opp-1908000000 {
+ opp-microvolt = <1025000>;
+ };
+};
+
+&i2c_AO {
+ status = "okay";
+ pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>;
+ pinctrl-names = "default";
+
+ rk818: pmic@1c {
+ compatible = "rockchip,rk818";
+ reg = <0x1c>;
+ interrupt-parent = <&gpio_intc>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>; /* GPIOAO_7 */
+
+ vcc1-supply = <&vdd_sys>;
+ vcc2-supply = <&vdd_sys>;
+ vcc3-supply = <&vdd_sys>;
+ vcc4-supply = <&vdd_sys>;
+ vcc6-supply = <&vdd_sys>;
+ vcc7-supply = <&vcc_2v3>;
+ vcc8-supply = <&vcc_2v3>;
+ vcc9-supply = <&vddao_3v3>;
+ boost-supply = <&vdd_sys>;
+ switch-supply = <&vdd_sys>;
+
+ regulators {
+ vddcpu_a: DCDC_REG1 {
+ regulator-name = "vddcpu_a";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <775000>;
+ regulator-max-microvolt = <1025000>;
+ regulator-ramp-delay = <6001>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <775000>;
+ };
+ };
+
+ vdd_ee: DCDC_REG2 {
+ regulator-name = "vdd_ee";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-ramp-delay = <6001>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <875000>;
+ };
+ };
+
+ vddq_1v1: DCDC_REG3 {
+ regulator-name = "vddq_1v1";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vddao_3v3: DCDC_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vddao_3v3";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ hp_5v: DCDC_BOOST {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "hp_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vddio_ao1v8: LDO_REG5 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vddio_ao1v8";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vddq_1v8: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vddq_1v8";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vddio_c: LDO_REG9 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vddio_c";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_sd: SWITCH_REG {
+ regulator-name = "vcc_sd";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ OTG_SWITCH {
+ regulator-name = "otg_switch";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&i2c3 {
+ status = "okay";
+ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
+ pinctrl-names = "default";
+
+ rk817: pmic@20 {
+ compatible = "rockchip,rk817";
+ reg = <0x20>;
+ interrupt-parent = <&gpio_intc>;
+
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>; /* GPIOAO_5 */
+
+ vcc1-supply = <&vdd_sys>;
+ vcc2-supply = <&vdd_sys>;
+ vcc3-supply = <&vdd_sys>;
+ vcc4-supply = <&vdd_sys>;
+ vcc5-supply = <&vdd_sys>;
+ vcc6-supply = <&vdd_sys>;
+ vcc7-supply = <&vdd_sys>;
+ vcc8-supply = <&vdd_sys>;
+ vcc9-supply = <&rk817_boost>;
+
+ #sound-dai-cells = <0>;
+ clocks = <&codec_clk>;
+ clock-names = "mclk";
+
+ #clock-cells = <1>;
+
+ regulators {
+ vddcpu_b: DCDC_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <737500>;
+ regulator-max-microvolt = <1012500>;
+ regulator-ramp-delay = <6001>;
+ regulator-initial-mode = <0x2>;
+ regulator-name = "vddcpu_b";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_2v3: DCDC_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <2300000>;
+ regulator-max-microvolt = <2400000>;
+ regulator-initial-mode = <0x2>;
+ regulator-name = "vcc_2v3";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ LDO_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vdd_codec";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_lcd: LDO_REG8 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_lcd";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ rk817_boost: BOOST {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5400000>;
+ regulator-name = "rk817_boost";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ usb_host: OTG_SWITCH {
+ regulator-name = "usb_host";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&clkc_audio {
+ status = "okay";
+};
+
+&eth_phy {
+ status = "disabled";
+};
+
+&frddr_a {
+ status = "okay";
+};
+
+&periphs_pinctrl {
+ keypad_gpio_pins: keypad-gpio {
+ mux {
+ groups = "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3",
+ "GPIOX_4", "GPIOX_5", "GPIOX_6", "GPIOX_7",
+ "GPIOX_8", "GPIOX_9", "GPIOX_10", "GPIOX_11",
+ "GPIOX_12", "GPIOX_13", "GPIOX_14", "GPIOX_15",
+ "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19";
+ function = "gpio_periphs";
+ bias-pull-up;
+ output-disable;
+ };
+ };
+};
+
+&saradc {
+ status = "okay";
+ vref-supply = <&vddio_ao1v8>;
+};
+
+/* SD card */
+&sd_emmc_b {
+ status = "okay";
+ pinctrl-0 = <&sdcard_c_pins>;
+ pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+ pinctrl-names = "default", "clk-gate";
+
+ bus-width = <4>;
+ cap-sd-highspeed;
+ max-frequency = <50000000>;
+ disable-wp;
+
+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vddio_c>;
+
+};
+
+/* eMMC */
+&sd_emmc_c {
+ status = "okay";
+ pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>;
+ pinctrl-1 = <&emmc_clk_gate_pins>;
+ pinctrl-names = "default", "clk-gate";
+
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ max-frequency = <200000000>;
+ disable-wp;
+
+ mmc-pwrseq = <&emmc_pwrseq>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vddio_ao1v8>;
+};
+
+
+&tdmif_b {
+ pinctrl-0 = <&tdm_b_dout0_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, <&tdm_b_din1_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>,
+ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>;
+ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_SCLK>,
+ <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
+ assigned-clock-rates = <0>, <0>;
+};
+
+&tdmin_b {
+ status = "okay";
+};
+
+&tdmout_b {
+ status = "okay";
+};
+
+&toddr_a {
+ status = "okay";
+};
+
+&uart_AO {
+ status = "okay";
+ pinctrl-0 = <&uart_ao_a_pins>;
+ pinctrl-names = "default";
+};
+
+&usb {
+ status = "okay";
+ dr_mode = "peripheral";
+};
+
+&usb2_phy0 {
+ status = "okay";
+};
+
+&usb2_phy1 {
+ status = "okay";
+ phy-supply = <&usb_host>;
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
index fd3fa82e4c33..667d2b774924 100644
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
@@ -39,6 +39,14 @@
reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
};
+ fan: gpio-fan {
+ compatible = "gpio-fan";
+ gpios = <&gpio_ao GPIOAO_10 GPIO_ACTIVE_HIGH>;
+ /* Using Dummy Speed */
+ gpio-fan,speed-map = <0 0>, <1 1>;
+ #cooling-cells = <2>;
+ };
+
leds {
compatible = "gpio-leds";
@@ -410,6 +418,40 @@
clock-latency = <50000>;
};
+&cpu_thermal {
+ trips {
+ cpu_active: cpu-active {
+ temperature = <60000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "active";
+ };
+ };
+
+ cooling-maps {
+ map {
+ trip = <&cpu_active>;
+ cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
+
+&ddr_thermal {
+ trips {
+ ddr_active: ddr-active {
+ temperature = <60000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "active";
+ };
+ };
+
+ cooling-maps {
+ map {
+ trip = <&ddr_active>;
+ cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
+
&ext_mdio {
external_phy: ethernet-phy@0 {
/* Realtek RTL8211F (0x001cc916) */
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
index ee8fcae9f9f0..75ff00fb2e4c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
@@ -105,6 +105,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
};
@@ -139,3 +140,7 @@
&mali {
dma-coherent;
};
+
+&pmu {
+ compatible = "amlogic,g12b-ddr-pmu";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 023a52005494..e3c12e0be99d 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -132,6 +132,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 7c029f552a23..923d2d8bbb9c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -427,6 +427,20 @@
};
};
+ spi_idle_high_pins: spi-idle-high-pins {
+ mux {
+ groups = "spi_sclk";
+ bias-pull-up;
+ };
+ };
+
+ spi_idle_low_pins: spi-idle-low-pins {
+ mux {
+ groups = "spi_sclk";
+ bias-pull-down;
+ };
+ };
+
spi_ss0_pins: spi-ss0 {
mux {
groups = "spi_ss0";
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
index 6ab1cc125b96..202deb4e2d63 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
@@ -140,7 +140,6 @@
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
};
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index c3ac531c4f84..04e9d0f1bde0 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -429,6 +429,20 @@
};
};
+ spi_idle_high_pins: spi-idle-high-pins {
+ mux {
+ groups = "spi_sclk";
+ bias-pull-up;
+ };
+ };
+
+ spi_idle_low_pins: spi-idle-low-pins {
+ mux {
+ groups = "spi_sclk";
+ bias-pull-down;
+ };
+ };
+
spi_ss0_pins: spi-ss0 {
mux {
groups = "spi_ss0";
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
index f43c45daf7eb..b21172ece1fa 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
@@ -270,7 +270,6 @@
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
};
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts
index b8ef3bd8b840..1703da3235ea 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts
@@ -89,7 +89,6 @@
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
wakeup-source;
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
index 80737731af3f..56ca0ba2241e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
@@ -88,6 +88,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -520,6 +521,10 @@
power-domains = <&pwrc PWRC_SM1_PCIE_ID>;
};
+&pmu {
+ compatible = "amlogic,sm1-ddr-pmu";
+};
+
&pwrc {
compatible = "amlogic,meson-sm1-pwrc";
};
diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile
index c0510c25ca6a..5a7506ff5ea3 100644
--- a/arch/arm64/boot/dts/apple/Makefile
+++ b/arch/arm64/boot/dts/apple/Makefile
@@ -4,3 +4,9 @@ dtb-$(CONFIG_ARCH_APPLE) += t8103-j293.dtb
dtb-$(CONFIG_ARCH_APPLE) += t8103-j313.dtb
dtb-$(CONFIG_ARCH_APPLE) += t8103-j456.dtb
dtb-$(CONFIG_ARCH_APPLE) += t8103-j457.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6000-j314s.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6001-j314c.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6000-j316s.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6001-j316c.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6001-j375c.dtb
+dtb-$(CONFIG_ARCH_APPLE) += t6002-j375d.dtb
diff --git a/arch/arm64/boot/dts/apple/multi-die-cpp.h b/arch/arm64/boot/dts/apple/multi-die-cpp.h
new file mode 100644
index 000000000000..39e8953bf809
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/multi-die-cpp.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR MIT
+ *
+ * C preprocessor macros for t600x multi die support.
+ */
+
+#ifndef __DTS_APPLE_MULTI_DIE_CPP_H
+#define __DTS_APPLE_MULTI_DIE_CPP_H
+
+#ifndef __stringify
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+#endif
+
+#ifndef __concat
+#define __concat_1(x, y...) x ## y
+#define __concat(x, y...) __concat_1(x, y)
+#endif
+
+#define DIE_NODE(a) __concat(a, DIE)
+#define DIE_LABEL(a) __stringify(__concat(a, DIE))
+
+#endif /* !__DTS_APPLE_MULTI_DIE_CPP_H */
diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts
new file mode 100644
index 000000000000..c9e192848fe3
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * MacBook Pro (14-inch, M1 Pro, 2021)
+ *
+ * target-type: J314s
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6000.dtsi"
+#include "t600x-j314-j316.dtsi"
+
+/ {
+ compatible = "apple,j314s", "apple,t6000", "apple,arm-platform";
+ model = "Apple MacBook Pro (14-inch, M1 Pro, 2021)";
+};
diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts
new file mode 100644
index 000000000000..ff1803ce2300
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * MacBook Pro (16-inch, M1 Pro, 2021)
+ *
+ * target-type: J316s
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6000.dtsi"
+#include "t600x-j314-j316.dtsi"
+
+/ {
+ compatible = "apple,j316s", "apple,t6000", "apple,arm-platform";
+ model = "Apple MacBook Pro (16-inch, M1 Pro, 2021)";
+};
diff --git a/arch/arm64/boot/dts/apple/t6000.dtsi b/arch/arm64/boot/dts/apple/t6000.dtsi
new file mode 100644
index 000000000000..89c3b211b116
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6000.dtsi
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple T6000 "M1 Pro" SoC
+ *
+ * Other names: H13J, "Jade Chop"
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/* This chip is just a cut down version of t6001, so include it and disable the missing parts */
+
+#include "t6001.dtsi"
+
+/ {
+ compatible = "apple,t6000", "apple,arm-platform";
+};
+
+/delete-node/ &pmgr_south;
diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts
new file mode 100644
index 000000000000..1761d15b98c1
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * MacBook Pro (14-inch, M1 Max, 2021)
+ *
+ * target-type: J314c
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6001.dtsi"
+#include "t600x-j314-j316.dtsi"
+
+/ {
+ compatible = "apple,j314c", "apple,t6001", "apple,arm-platform";
+ model = "Apple MacBook Pro (14-inch, M1 Max, 2021)";
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts
new file mode 100644
index 000000000000..750e9beeffc0
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * MacBook Pro (16-inch, M1 Max, 2021)
+ *
+ * target-type: J316c
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6001.dtsi"
+#include "t600x-j314-j316.dtsi"
+
+/ {
+ compatible = "apple,j316c", "apple,t6001", "apple,arm-platform";
+ model = "Apple MacBook Pro (16-inch, M1 Max, 2021)";
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts
new file mode 100644
index 000000000000..62ea437b58b2
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Mac Studio (M1 Max, 2022)
+ *
+ * target-type: J375c
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6001.dtsi"
+#include "t600x-j375.dtsi"
+
+/ {
+ compatible = "apple,j375c", "apple,t6001", "apple,arm-platform";
+ model = "Apple Mac Studio (M1 Max, 2022)";
+};
diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi
new file mode 100644
index 000000000000..620b17e4031f
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6001.dtsi
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple T6001 "M1 Max" SoC
+ *
+ * Other names: H13J, "Jade"
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/apple.h>
+
+#include "multi-die-cpp.h"
+
+#include "t600x-common.dtsi"
+
+/ {
+ compatible = "apple,t6001", "apple,arm-platform";
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ ranges;
+ nonposted-mmio;
+
+ // filled via templated includes at the end of the file
+ };
+};
+
+#define DIE
+#define DIE_NO 0
+
+&{/soc} {
+ #include "t600x-die0.dtsi"
+ #include "t600x-dieX.dtsi"
+ #include "t600x-nvme.dtsi"
+};
+
+#include "t600x-gpio-pins.dtsi"
+#include "t600x-pmgr.dtsi"
+
+#undef DIE
+#undef DIE_NO
+
+
+&aic {
+ affinities {
+ e-core-pmu-affinity {
+ apple,fiq-index = <AIC_CPU_PMU_E>;
+ cpus = <&cpu_e00 &cpu_e01>;
+ };
+
+ p-core-pmu-affinity {
+ apple,fiq-index = <AIC_CPU_PMU_P>;
+ cpus = <&cpu_p00 &cpu_p01 &cpu_p02 &cpu_p03
+ &cpu_p10 &cpu_p11 &cpu_p12 &cpu_p13>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts
new file mode 100644
index 000000000000..3365429bdc8b
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Mac Studio (M1 Ultra, 2022)
+ *
+ * target-type: J375d
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t6002.dtsi"
+#include "t600x-j375.dtsi"
+
+/ {
+ compatible = "apple,j375d", "apple,t6002", "apple,arm-platform";
+ model = "Apple Mac Studio (M1 Ultra, 2022)";
+};
+
+/* USB Type C */
+&i2c0 {
+ /* front-right */
+ hpm4: usb-pd@39 {
+ compatible = "apple,cd321x";
+ reg = <0x39>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ /* front-left */
+ hpm5: usb-pd@3a {
+ compatible = "apple,cd321x";
+ reg = <0x3a>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+};
+
+/* delete unused always-on power-domains on die 1 */
+
+/delete-node/ &ps_atc2_usb_aon_die1;
+/delete-node/ &ps_atc2_usb_die1;
+
+/delete-node/ &ps_atc3_usb_aon_die1;
+/delete-node/ &ps_atc3_usb_die1;
+
+/delete-node/ &ps_disp0_cpu0_die1;
+/delete-node/ &ps_disp0_fe_die1;
diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi
new file mode 100644
index 000000000000..a963a5011799
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t6002.dtsi
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple T6002 "M1 Ultra" SoC
+ *
+ * Other names: H13J, "Jade 2C"
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/apple.h>
+
+#include "multi-die-cpp.h"
+
+#include "t600x-common.dtsi"
+
+/ {
+ compatible = "apple,t6002", "apple,arm-platform";
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ cpu-map {
+ cluster3 {
+ core0 {
+ cpu = <&cpu_e10>;
+ };
+ core1 {
+ cpu = <&cpu_e11>;
+ };
+ };
+
+ cluster4 {
+ core0 {
+ cpu = <&cpu_p20>;
+ };
+ core1 {
+ cpu = <&cpu_p21>;
+ };
+ core2 {
+ cpu = <&cpu_p22>;
+ };
+ core3 {
+ cpu = <&cpu_p23>;
+ };
+ };
+
+ cluster5 {
+ core0 {
+ cpu = <&cpu_p30>;
+ };
+ core1 {
+ cpu = <&cpu_p31>;
+ };
+ core2 {
+ cpu = <&cpu_p32>;
+ };
+ core3 {
+ cpu = <&cpu_p33>;
+ };
+ };
+ };
+
+ cpu_e10: cpu@800 {
+ compatible = "apple,icestorm";
+ device_type = "cpu";
+ reg = <0x0 0x800>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_3>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
+ operating-points-v2 = <&icestorm_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e_die1>;
+ };
+
+ cpu_e11: cpu@801 {
+ compatible = "apple,icestorm";
+ device_type = "cpu";
+ reg = <0x0 0x801>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_3>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
+ operating-points-v2 = <&icestorm_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e_die1>;
+ };
+
+ cpu_p20: cpu@10900 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10900>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_4>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0_die1>;
+ };
+
+ cpu_p21: cpu@10901 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10901>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_4>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0_die1>;
+ };
+
+ cpu_p22: cpu@10902 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10902>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_4>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0_die1>;
+ };
+
+ cpu_p23: cpu@10903 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10903>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_4>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0_die1>;
+ };
+
+ cpu_p30: cpu@10a00 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10a00>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_5>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1_die1>;
+ };
+
+ cpu_p31: cpu@10a01 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10a01>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_5>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1_die1>;
+ };
+
+ cpu_p32: cpu@10a02 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10a02>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_5>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1_die1>;
+ };
+
+ cpu_p33: cpu@10a03 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10a03>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_5>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1_die1>;
+ };
+
+ l2_cache_3: l2-cache-3 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0x400000>;
+ };
+
+ l2_cache_4: l2-cache-4 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0xc00000>;
+ };
+
+ l2_cache_5: l2-cache-5 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0xc00000>;
+ };
+ };
+
+ die0: soc@200000000 {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x2 0x0 0x2 0x0 0x4 0x0>,
+ <0x5 0x80000000 0x5 0x80000000 0x1 0x80000000>,
+ <0x7 0x0 0x7 0x0 0xf 0x80000000>;
+ nonposted-mmio;
+
+ // filled via templated includes at the end of the file
+ };
+
+ die1: soc@2200000000 {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x2 0x0 0x22 0x0 0x4 0x0>,
+ <0x7 0x0 0x27 0x0 0xf 0x80000000>;
+ nonposted-mmio;
+
+ // filled via templated includes at the end of the file
+ };
+};
+
+#define DIE
+#define DIE_NO 0
+
+&die0 {
+ #include "t600x-die0.dtsi"
+ #include "t600x-dieX.dtsi"
+};
+
+#include "t600x-pmgr.dtsi"
+#include "t600x-gpio-pins.dtsi"
+
+#undef DIE
+#undef DIE_NO
+
+#define DIE _die1
+#define DIE_NO 1
+
+&die1 {
+ #include "t600x-dieX.dtsi"
+ #include "t600x-nvme.dtsi"
+};
+
+#include "t600x-pmgr.dtsi"
+
+#undef DIE
+#undef DIE_NO
+
+&aic {
+ affinities {
+ e-core-pmu-affinity {
+ apple,fiq-index = <AIC_CPU_PMU_E>;
+ cpus = <&cpu_e00 &cpu_e01
+ &cpu_e10 &cpu_e11>;
+ };
+
+ p-core-pmu-affinity {
+ apple,fiq-index = <AIC_CPU_PMU_P>;
+ cpus = <&cpu_p00 &cpu_p01 &cpu_p02 &cpu_p03
+ &cpu_p10 &cpu_p11 &cpu_p12 &cpu_p13
+ &cpu_p20 &cpu_p21 &cpu_p22 &cpu_p23
+ &cpu_p30 &cpu_p31 &cpu_p32 &cpu_p33>;
+ };
+ };
+};
+
+&ps_gfx {
+ // On t6002, the die0 GPU power domain needs both AFR power domains
+ power-domains = <&ps_afr>, <&ps_afr_die1>;
+};
diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi
new file mode 100644
index 000000000000..fa8ead699363
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Common Apple T6000 / T6001 / T6002 "M1 Pro/Max/Ultra" SoC
+ *
+ * Other names: H13J, "Jade Chop", "Jade", "Jade 2C"
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu_e00>;
+ };
+ core1 {
+ cpu = <&cpu_e01>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu_p00>;
+ };
+ core1 {
+ cpu = <&cpu_p01>;
+ };
+ core2 {
+ cpu = <&cpu_p02>;
+ };
+ core3 {
+ cpu = <&cpu_p03>;
+ };
+ };
+
+ cluster2 {
+ core0 {
+ cpu = <&cpu_p10>;
+ };
+ core1 {
+ cpu = <&cpu_p11>;
+ };
+ core2 {
+ cpu = <&cpu_p12>;
+ };
+ core3 {
+ cpu = <&cpu_p13>;
+ };
+ };
+ };
+
+ cpu_e00: cpu@0 {
+ compatible = "apple,icestorm";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
+ operating-points-v2 = <&icestorm_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ };
+
+ cpu_e01: cpu@1 {
+ compatible = "apple,icestorm";
+ device_type = "cpu";
+ reg = <0x0 0x1>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
+ operating-points-v2 = <&icestorm_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ };
+
+ cpu_p00: cpu@10100 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10100>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0>;
+ };
+
+ cpu_p01: cpu@10101 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10101>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0>;
+ };
+
+ cpu_p02: cpu@10102 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10102>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0>;
+ };
+
+ cpu_p03: cpu@10103 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10103>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p0>;
+ };
+
+ cpu_p10: cpu@10200 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10200>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_2>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1>;
+ };
+
+ cpu_p11: cpu@10201 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10201>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_2>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1>;
+ };
+
+ cpu_p12: cpu@10202 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10202>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_2>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1>;
+ };
+
+ cpu_p13: cpu@10203 {
+ compatible = "apple,firestorm";
+ device_type = "cpu";
+ reg = <0x0 0x10203>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0>; /* To be filled by loader */
+ next-level-cache = <&l2_cache_2>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ operating-points-v2 = <&firestorm_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p1>;
+ };
+
+ l2_cache_0: l2-cache-0 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0x400000>;
+ };
+
+ l2_cache_1: l2-cache-1 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0xc00000>;
+ };
+
+ l2_cache_2: l2-cache-2 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0xc00000>;
+ };
+ };
+
+ icestorm_opp: opp-table-0 {
+ compatible = "operating-points-v2";
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <7500>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <972000000>;
+ opp-level = <2>;
+ clock-latency-ns = <23000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1332000000>;
+ opp-level = <3>;
+ clock-latency-ns = <29000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1704000000>;
+ opp-level = <4>;
+ clock-latency-ns = <40000>;
+ };
+ opp05 {
+ opp-hz = /bits/ 64 <2064000000>;
+ opp-level = <5>;
+ clock-latency-ns = <50000>;
+ };
+ };
+
+ firestorm_opp: opp-table-1 {
+ compatible = "operating-points-v2";
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <8000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <828000000>;
+ opp-level = <2>;
+ clock-latency-ns = <18000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-level = <3>;
+ clock-latency-ns = <19000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1296000000>;
+ opp-level = <4>;
+ clock-latency-ns = <23000>;
+ };
+ opp05 {
+ opp-hz = /bits/ 64 <1524000000>;
+ opp-level = <5>;
+ clock-latency-ns = <24000>;
+ };
+ opp06 {
+ opp-hz = /bits/ 64 <1752000000>;
+ opp-level = <6>;
+ clock-latency-ns = <28000>;
+ };
+ opp07 {
+ opp-hz = /bits/ 64 <1980000000>;
+ opp-level = <7>;
+ clock-latency-ns = <31000>;
+ };
+ opp08 {
+ opp-hz = /bits/ 64 <2208000000>;
+ opp-level = <8>;
+ clock-latency-ns = <45000>;
+ };
+ opp09 {
+ opp-hz = /bits/ 64 <2448000000>;
+ opp-level = <9>;
+ clock-latency-ns = <49000>;
+ };
+ opp10 {
+ opp-hz = /bits/ 64 <2676000000>;
+ opp-level = <10>;
+ clock-latency-ns = <53000>;
+ };
+ opp11 {
+ opp-hz = /bits/ 64 <2904000000>;
+ opp-level = <11>;
+ clock-latency-ns = <56000>;
+ };
+ opp12 {
+ opp-hz = /bits/ 64 <3036000000>;
+ opp-level = <12>;
+ clock-latency-ns = <56000>;
+ };
+ /* Not available until CPU deep sleep is implemented
+ opp13 {
+ opp-hz = /bits/ 64 <3132000000>;
+ opp-level = <13>;
+ clock-latency-ns = <56000>;
+ turbo-mode;
+ };
+ opp14 {
+ opp-hz = /bits/ 64 <3168000000>;
+ opp-level = <14>;
+ clock-latency-ns = <56000>;
+ turbo-mode;
+ };
+ opp15 {
+ opp-hz = /bits/ 64 <3228000000>;
+ opp-level = <15>;
+ clock-latency-ns = <56000>;
+ turbo-mode;
+ };
+ */
+ };
+
+ pmu-e {
+ compatible = "apple,icestorm-pmu";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_FIQ 0 AIC_CPU_PMU_E IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ pmu-p {
+ compatible = "apple,firestorm-pmu";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_FIQ 0 AIC_CPU_PMU_P IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&aic>;
+ interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt";
+ interrupts = <AIC_FIQ 0 AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_FIQ 0 AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_FIQ 0 AIC_TMR_HV_PHYS IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_FIQ 0 AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ clkref: clock-ref {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "clkref";
+ };
+
+ /*
+ * This is a fabulated representation of the input clock
+ * to NCO since we don't know the true clock tree.
+ */
+ nco_clkref: clock-ref-nco {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-output-names = "nco_ref";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
new file mode 100644
index 000000000000..1c41954e3899
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Devices used on die 0 on the Apple T6002 "M1 Ultra" SoC and present on
+ * Apple T6000 / T6001 "M1 Pro" / "M1 Max".
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+
+ nco: clock-controller@28e03c000 {
+ compatible = "apple,t6000-nco", "apple,nco";
+ reg = <0x2 0x8e03c000 0x0 0x14000>;
+ clocks = <&nco_clkref>;
+ #clock-cells = <1>;
+ };
+
+ aic: interrupt-controller@28e100000 {
+ compatible = "apple,t6000-aic", "apple,aic2";
+ #interrupt-cells = <4>;
+ interrupt-controller;
+ reg = <0x2 0x8e100000 0x0 0xc000>,
+ <0x2 0x8e10c000 0x0 0x4>;
+ reg-names = "core", "event";
+ power-domains = <&ps_aic>;
+ };
+
+ pinctrl_smc: pinctrl@290820000 {
+ compatible = "apple,t6000-pinctrl", "apple,pinctrl";
+ reg = <0x2 0x90820000 0x0 0x4000>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_smc 0 0 30>;
+ apple,npins = <30>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 743 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 744 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 745 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 746 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 747 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 748 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 749 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wdt: watchdog@2922b0000 {
+ compatible = "apple,t6000-wdt", "apple,wdt";
+ reg = <0x2 0x922b0000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 631 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ sio_dart_0: iommu@39b004000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x3 0x9b004000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1130 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_sio_cpu>;
+ };
+
+ sio_dart_1: iommu@39b008000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x3 0x9b008000 0x0 0x8000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1130 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_sio_cpu>;
+ };
+
+ i2c0: i2c@39b040000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b040000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1119 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c0_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c0>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ };
+
+ i2c1: i2c@39b044000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b044000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1120 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c1>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@39b048000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b048000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1121 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c2>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@39b04c000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b04c000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1122 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c3_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c3>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@39b050000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b050000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1123 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c4_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c4>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@39b054000 {
+ compatible = "apple,t6000-i2c", "apple,i2c";
+ reg = <0x3 0x9b054000 0x0 0x4000>;
+ clocks = <&clkref>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1124 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-0 = <&i2c5_pins>;
+ pinctrl-names = "default";
+ power-domains = <&ps_i2c5>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ status = "disabled";
+ };
+
+ serial0: serial@39b200000 {
+ compatible = "apple,s5l-uart";
+ reg = <0x3 0x9b200000 0x0 0x1000>;
+ reg-io-width = <4>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1097 IRQ_TYPE_LEVEL_HIGH>;
+ /*
+ * TODO: figure out the clocking properly, there may
+ * be a third selectable clock.
+ */
+ clocks = <&clkref>, <&clkref>;
+ clock-names = "uart", "clk_uart_baud0";
+ power-domains = <&ps_uart0>;
+ status = "disabled";
+ };
+
+ admac: dma-controller@39b400000 {
+ compatible = "apple,t6000-admac", "apple,admac";
+ reg = <0x3 0x9b400000 0x0 0x34000>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ interrupts-extended = <0>,
+ <&aic AIC_IRQ 0 1118 IRQ_TYPE_LEVEL_HIGH>,
+ <0>,
+ <0>;
+ iommus = <&sio_dart_0 2>, <&sio_dart_1 2>;
+ power-domains = <&ps_sio_adma>;
+ resets = <&ps_audio_p>;
+ };
+
+ mca: mca@39b600000 {
+ compatible = "apple,t6000-mca", "apple,mca";
+ reg = <0x3 0x9b600000 0x0 0x10000>,
+ <0x3 0x9b500000 0x0 0x20000>;
+ clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>;
+ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>,
+ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>,
+ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>,
+ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>;
+ dma-names = "tx0a", "rx0a", "tx0b", "rx0b",
+ "tx1a", "rx1a", "tx1b", "rx1b",
+ "tx2a", "rx2a", "tx2b", "rx2b",
+ "tx3a", "rx3a", "tx3b", "rx3b";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1112 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1113 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1114 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1115 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>,
+ <&ps_mca2>, <&ps_mca3>;
+ resets = <&ps_audio_p>;
+ #sound-dai-cells = <1>;
+ };
+
+ pcie0_dart_0: iommu@581008000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x5 0x81008000 0x0 0x4000>;
+ #iommu-cells = <1>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1271 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&ps_apcie_gp_sys>;
+ };
+
+ pcie0_dart_1: iommu@582008000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x5 0x82008000 0x0 0x4000>;
+ #iommu-cells = <1>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1274 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&ps_apcie_gp_sys>;
+ };
+
+ pcie0_dart_2: iommu@583008000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x5 0x83008000 0x0 0x4000>;
+ #iommu-cells = <1>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1277 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&ps_apcie_gp_sys>;
+ };
+
+ pcie0_dart_3: iommu@584008000 {
+ compatible = "apple,t6000-dart";
+ reg = <0x5 0x84008000 0x0 0x4000>;
+ #iommu-cells = <1>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1280 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&ps_apcie_gp_sys>;
+ };
+
+ pcie0: pcie@590000000 {
+ compatible = "apple,t6000-pcie", "apple,pcie";
+ device_type = "pci";
+
+ reg = <0x5 0x90000000 0x0 0x1000000>,
+ <0x5 0x80000000 0x0 0x100000>,
+ <0x5 0x81000000 0x0 0x4000>,
+ <0x5 0x82000000 0x0 0x4000>,
+ <0x5 0x83000000 0x0 0x4000>,
+ <0x5 0x84000000 0x0 0x4000>;
+ reg-names = "config", "rc", "port0", "port1", "port2", "port3";
+
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 0 1270 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1273 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1276 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 0 1279 IRQ_TYPE_LEVEL_HIGH>;
+
+ msi-controller;
+ msi-parent = <&pcie0>;
+ msi-ranges = <&aic AIC_IRQ 0 1581 IRQ_TYPE_EDGE_RISING 32>;
+
+
+ iommu-map = <0x100 &pcie0_dart_0 1 1>,
+ <0x200 &pcie0_dart_1 1 1>,
+ <0x300 &pcie0_dart_2 1 1>,
+ <0x400 &pcie0_dart_3 1 1>;
+ iommu-map-mask = <0xff00>;
+
+ bus-range = <0 4>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x43000000 0x5 0xa0000000 0x5 0xa0000000 0x0 0x20000000>,
+ <0x02000000 0x0 0xc0000000 0x5 0xc0000000 0x0 0x40000000>;
+
+ power-domains = <&ps_apcie_gp_sys>;
+ pinctrl-0 = <&pcie_pins>;
+ pinctrl-names = "default";
+
+ port00: pci@0,0 {
+ device_type = "pci";
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ reset-gpios = <&pinctrl_ap 4 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
+ <0 0 0 2 &port00 0 0 0 1>,
+ <0 0 0 3 &port00 0 0 0 2>,
+ <0 0 0 4 &port00 0 0 0 3>;
+ };
+
+ port01: pci@1,0 {
+ device_type = "pci";
+ reg = <0x800 0x0 0x0 0x0 0x0>;
+ reset-gpios = <&pinctrl_ap 5 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &port01 0 0 0 0>,
+ <0 0 0 2 &port01 0 0 0 1>,
+ <0 0 0 3 &port01 0 0 0 2>,
+ <0 0 0 4 &port01 0 0 0 3>;
+ };
+
+ port02: pci@2,0 {
+ device_type = "pci";
+ reg = <0x1000 0x0 0x0 0x0 0x0>;
+ reset-gpios = <&pinctrl_ap 6 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &port02 0 0 0 0>,
+ <0 0 0 2 &port02 0 0 0 1>,
+ <0 0 0 3 &port02 0 0 0 2>,
+ <0 0 0 4 &port02 0 0 0 3>;
+ };
+
+ port03: pci@3,0 {
+ device_type = "pci";
+ reg = <0x1800 0x0 0x0 0x0 0x0>;
+ reset-gpios = <&pinctrl_ap 7 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &port03 0 0 0 0>,
+ <0 0 0 2 &port03 0 0 0 1>,
+ <0 0 0 3 &port03 0 0 0 2>,
+ <0 0 0 4 &port03 0 0 0 3>;
+ };
+ };
diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
new file mode 100644
index 000000000000..a32ff0c9d7b0
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Devices used on both dies on the Apple T6002 "M1 Ultra" and present on
+ * Apple T6000/T6001 "M1 Pro/Max".
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+ DIE_NODE(cpufreq_e): cpufreq@210e20000 {
+ compatible = "apple,t6000-cluster-cpufreq", "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x10e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ DIE_NODE(cpufreq_p0): cpufreq@211e20000 {
+ compatible = "apple,t6000-cluster-cpufreq", "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x11e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ DIE_NODE(cpufreq_p1): cpufreq@212e20000 {
+ compatible = "apple,t6000-cluster-cpufreq", "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x12e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ DIE_NODE(pmgr): power-management@28e080000 {
+ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x2 0x8e080000 0 0x4000>;
+ };
+
+ DIE_NODE(pmgr_east): power-management@28e580000 {
+ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x2 0x8e580000 0 0xc000>;
+ };
+
+ DIE_NODE(pmgr_south): power-management@28e680000 {
+ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x2 0x8e680000 0 0xc000>;
+ };
+
+ DIE_NODE(pinctrl_nub): pinctrl@2921f0000 {
+ compatible = "apple,t6000-pinctrl", "apple,pinctrl";
+ reg = <0x2 0x921f0000 0x0 0x4000>;
+ power-domains = <&DIE_NODE(ps_nub_gpio)>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&DIE_NODE(pinctrl_nub) 0 0 16>;
+ apple,npins = <16>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 623 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 624 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 625 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 626 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 627 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 628 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 629 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ DIE_NODE(pmgr_mini): power-management@292280000 {
+ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x2 0x92280000 0 0x4000>;
+ };
+
+ DIE_NODE(pinctrl_aop): pinctrl@293820000 {
+ compatible = "apple,t6000-pinctrl", "apple,pinctrl";
+ reg = <0x2 0x93820000 0x0 0x4000>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&DIE_NODE(pinctrl_aop) 0 0 63>;
+ apple,npins = <63>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 567 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 568 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 569 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 570 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 571 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 572 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 573 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ DIE_NODE(pinctrl_ap): pinctrl@39b028000 {
+ compatible = "apple,t6000-pinctrl", "apple,pinctrl";
+ reg = <0x3 0x9b028000 0x0 0x4000>;
+
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 427 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 428 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 429 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 430 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 431 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 432 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 433 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&clkref>;
+ power-domains = <&DIE_NODE(ps_gpio)>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&DIE_NODE(pinctrl_ap) 0 0 255>;
+ apple,npins = <255>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
diff --git a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi
new file mode 100644
index 000000000000..b31f1a7a2b3f
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * GPIO pin mappings for Apple T600x SoCs.
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&pinctrl_ap {
+ i2c0_pins: i2c0-pins {
+ pinmux = <APPLE_PINMUX(92, 1)>,
+ <APPLE_PINMUX(93, 1)>;
+ };
+
+ i2c1_pins: i2c1-pins {
+ pinmux = <APPLE_PINMUX(94, 1)>,
+ <APPLE_PINMUX(95, 1)>;
+ };
+
+ i2c2_pins: i2c2-pins {
+ pinmux = <APPLE_PINMUX(96, 1)>,
+ <APPLE_PINMUX(97, 1)>;
+ };
+
+ i2c3_pins: i2c3-pins {
+ pinmux = <APPLE_PINMUX(98, 1)>,
+ <APPLE_PINMUX(99, 1)>;
+ };
+
+ i2c4_pins: i2c4-pins {
+ pinmux = <APPLE_PINMUX(8, 1)>,
+ <APPLE_PINMUX(9, 1)>;
+ };
+
+ i2c5_pins: i2c5-pins {
+ pinmux = <APPLE_PINMUX(100, 1)>,
+ <APPLE_PINMUX(101, 1)>;
+ };
+
+ pcie_pins: pcie-pins {
+ pinmux = <APPLE_PINMUX(0, 1)>,
+ <APPLE_PINMUX(1, 1)>,
+ <APPLE_PINMUX(2, 1)>,
+ <APPLE_PINMUX(3, 1)>;
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
new file mode 100644
index 000000000000..34906d522f0a
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * MacBook Pro (14/16-inch, 2021)
+ *
+ * This file contains the parts common to J314 and J316 devices with both t6000 and t6001.
+ *
+ * target-type: J314s / J314c / J316s / J316c
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/ {
+ aliases {
+ serial0 = &serial0;
+ wifi0 = &wifi0;
+ };
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ stdout-path = "serial0";
+
+ framebuffer0: framebuffer@0 {
+ compatible = "apple,simple-framebuffer", "simple-framebuffer";
+ reg = <0 0 0 0>; /* To be filled by loader */
+ /* Format properties will be added by loader */
+ status = "disabled";
+ };
+ };
+
+ memory@10000000000 {
+ device_type = "memory";
+ reg = <0x100 0 0x2 0>; /* To be filled by loader */
+ };
+};
+
+&serial0 {
+ status = "okay";
+};
+
+/* USB Type C */
+&i2c0 {
+ hpm0: usb-pd@38 {
+ compatible = "apple,cd321x";
+ reg = <0x38>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ hpm1: usb-pd@3f {
+ compatible = "apple,cd321x";
+ reg = <0x3f>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ hpm2: usb-pd@3b {
+ compatible = "apple,cd321x";
+ reg = <0x3b>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ /* MagSafe port */
+ hpm5: usb-pd@3a {
+ compatible = "apple,cd321x";
+ reg = <0x3a>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+};
+
+&nco_clkref {
+ clock-frequency = <1068000000>;
+};
+
+/* PCIe devices */
+&port00 {
+ /* WLAN */
+ bus-range = <1 1>;
+ wifi0: wifi@0,0 {
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+ /* To be filled by the loader */
+ local-mac-address = [00 10 18 00 00 10];
+ };
+};
+
+&port01 {
+ /* SD card reader */
+ bus-range = <2 2>;
+ sdhci0: mmc@0,0 {
+ compatible = "pci17a0,9755";
+ reg = <0x20000 0x0 0x0 0x0 0x0>;
+ cd-inverted;
+ wp-inverted;
+ };
+};
+
+&pcie0_dart_2 {
+ status = "disabled";
+};
+
+&pcie0_dart_3 {
+ status = "disabled";
+};
+
+/delete-node/ &port02;
+/delete-node/ &port03;
diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi
new file mode 100644
index 000000000000..00d3a9447c89
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Mac Studio (2022)
+ *
+ * This file contains the parts common to J375 devices with both t6001 and t6002.
+ *
+ * target-type: J375c / J375d
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/ {
+ aliases {
+ serial0 = &serial0;
+ wifi0 = &wifi0;
+ };
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ stdout-path = "serial0";
+
+ framebuffer0: framebuffer@0 {
+ compatible = "apple,simple-framebuffer", "simple-framebuffer";
+ reg = <0 0 0 0>; /* To be filled by loader */
+ /* Format properties will be added by loader */
+ status = "disabled";
+ };
+ };
+
+ memory@10000000000 {
+ device_type = "memory";
+ reg = <0x100 0 0x2 0>; /* To be filled by loader */
+ };
+};
+
+&serial0 {
+ status = "okay";
+};
+
+/* USB Type C */
+&i2c0 {
+ hpm0: usb-pd@38 {
+ compatible = "apple,cd321x";
+ reg = <0x38>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ hpm1: usb-pd@3f {
+ compatible = "apple,cd321x";
+ reg = <0x3f>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ hpm2: usb-pd@3b {
+ compatible = "apple,cd321x";
+ reg = <0x3b>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+
+ hpm3: usb-pd@3c {
+ compatible = "apple,cd321x";
+ reg = <0x3c>;
+ interrupt-parent = <&pinctrl_ap>;
+ interrupts = <174 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "irq";
+ };
+};
+
+&nco_clkref {
+ clock-frequency = <1068000000>;
+};
+
+/* PCIe devices */
+&port00 {
+ /* WLAN */
+ bus-range = <1 1>;
+ wifi0: wifi@0,0 {
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+ /* To be filled by the loader */
+ local-mac-address = [00 10 18 00 00 10];
+ };
+};
+
+&port01 {
+ /* SD card reader */
+ bus-range = <2 2>;
+ sdhci0: mmc@0,0 {
+ compatible = "pci17a0,9755";
+ reg = <0x20000 0x0 0x0 0x0 0x0>;
+ cd-inverted;
+ wp-inverted;
+ };
+};
+
+&port02 {
+ /* 10 Gbit Ethernet */
+ bus-range = <3 3>;
+ ethernet0: ethernet@0,0 {
+ reg = <0x30000 0x0 0x0 0x0 0x0>;
+ /* To be filled by the loader */
+ local-mac-address = [00 10 18 00 00 00];
+ };
+};
+
+&port03 {
+ /* USB xHCI */
+ bus-range = <4 4>;
+};
diff --git a/arch/arm64/boot/dts/apple/t600x-nvme.dtsi b/arch/arm64/boot/dts/apple/t600x-nvme.dtsi
new file mode 100644
index 000000000000..7dff738d317e
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-nvme.dtsi
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * NVMe related devices for Apple T600x SoCs.
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+ DIE_NODE(ans_mbox): mbox@38f408000 {
+ compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4";
+ reg = <0x3 0x8f408000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1069 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1070 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1071 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1072 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "send-empty", "send-not-empty",
+ "recv-empty", "recv-not-empty";
+ power-domains = <&DIE_NODE(ps_ans2)>;
+ #mbox-cells = <0>;
+ };
+
+ DIE_NODE(sart): sart@393c50000 {
+ compatible = "apple,t6000-sart";
+ reg = <0x3 0x93c50000 0x0 0x10000>;
+ power-domains = <&DIE_NODE(ps_ans2)>;
+ };
+
+ DIE_NODE(nvme): nvme@393cc0000 {
+ compatible = "apple,t6000-nvme-ans2", "apple,nvme-ans2";
+ reg = <0x3 0x93cc0000 0x0 0x40000>, <0x3 0x8f400000 0x0 0x4000>;
+ reg-names = "nvme", "ans";
+ interrupt-parent = <&aic>;
+ /* The NVME interrupt is always routed to die */
+ interrupts = <AIC_IRQ 0 1613 IRQ_TYPE_LEVEL_HIGH>;
+ mboxes = <&DIE_NODE(ans_mbox)>;
+ apple,sart = <&DIE_NODE(sart)>;
+ power-domains = <&DIE_NODE(ps_ans2)>,
+ <&DIE_NODE(ps_apcie_st_sys)>,
+ <&DIE_NODE(ps_apcie_st1_sys)>;
+ power-domain-names = "ans", "apcie0", "apcie1";
+ resets = <&DIE_NODE(ps_ans2)>;
+ };
diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi
new file mode 100644
index 000000000000..0bd44753b76a
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi
@@ -0,0 +1,2012 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * PMGR Power domains for the Apple T6001 "M1 Max" SoC
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&DIE_NODE(pmgr) {
+ DIE_NODE(ps_pms_bridge): power-controller@100 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x100 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pms_bridge);
+ apple,always-on; /* Core device */
+ };
+
+ DIE_NODE(ps_aic): power-controller@108 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x108 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(aic);
+ apple,always-on; /* Core device */
+ };
+
+ DIE_NODE(ps_dwi): power-controller@110 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x110 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dwi);
+ apple,always-on; /* Core device */
+ };
+
+ DIE_NODE(ps_pms): power-controller@118 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x118 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pms);
+ apple,always-on; /* Core device */
+ };
+
+ DIE_NODE(ps_gpio): power-controller@120 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x120 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(gpio);
+ power-domains = <&DIE_NODE(ps_pms)>, <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_soc_dpe): power-controller@128 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x128 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(soc_dpe);
+ apple,always-on; /* Core device */
+ };
+
+ DIE_NODE(ps_pmgr_soc_ocla): power-controller@130 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x130 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pmgr_soc_ocla);
+ power-domains = <&DIE_NODE(ps_pms)>;
+ };
+
+ DIE_NODE(ps_pcie0_ref): power-controller@138 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x138 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pcie0_ref);
+ };
+
+ DIE_NODE(ps_pcie1_ref): power-controller@140 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x140 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pcie1_ref);
+ };
+
+ DIE_NODE(ps_apcie_st): power-controller@148 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x148 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(apcie_st);
+ power-domains = <&DIE_NODE(ps_pcie1_ref)>;
+ };
+
+ DIE_NODE(ps_apcie_gp): power-controller@150 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x150 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(apcie_gp);
+ power-domains = <&DIE_NODE(ps_pcie0_ref)>;
+ };
+
+ DIE_NODE(ps_devc0_ivdmc): power-controller@180 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x180 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(devc0_ivdmc);
+ };
+
+ DIE_NODE(ps_amcc0): power-controller@188 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x188 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc0);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_amcc2): power-controller@190 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x190 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc2);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_dcs_00): power-controller@198 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x198 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_00);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_01): power-controller@1a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_01);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_02): power-controller@1a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_02);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_03): power-controller@1b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_03);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_08): power-controller@1b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_08);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_09): power-controller@1c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_09);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_10): power-controller@1c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_10);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_11): power-controller@1d0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1d0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_11);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_afi): power-controller@1d8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1d8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afi);
+ apple,always-on; /* Apple Fabric, CPU interface is here */
+ };
+
+ DIE_NODE(ps_afc): power-controller@1e0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1e0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afc);
+ apple,always-on; /* Apple Fabric, CPU interface is here */
+ };
+
+ DIE_NODE(ps_afr): power-controller@1e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1e8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afr);
+ /* Apple Fabric, media stuff: this can power down */
+ };
+
+ DIE_NODE(ps_afnc1_ioa): power-controller@1f0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1f0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc1_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc0_ioa): power-controller@1f8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1f8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc0_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc1_ls): power-controller@200 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x200 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc1_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc1_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc0_ls): power-controller@208 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x208 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc0_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc0_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc1_lw0): power-controller@210 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x210 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc1_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc1_ls)>;
+ };
+
+ DIE_NODE(ps_afnc1_lw1): power-controller@218 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x218 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc1_lw1);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc1_ls)>;
+ };
+
+ DIE_NODE(ps_afnc1_lw2): power-controller@220 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x220 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc1_lw2);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc1_ls)>;
+ };
+
+ DIE_NODE(ps_afnc0_lw0): power-controller@228 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x228 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc0_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc0_ls)>;
+ };
+
+ DIE_NODE(ps_scodec): power-controller@230 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x230 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(scodec);
+ power-domains = <&DIE_NODE(ps_afnc1_lw0)>;
+ };
+
+ DIE_NODE(ps_atc0_common): power-controller@238 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x238 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_common);
+ power-domains = <&DIE_NODE(ps_afnc1_lw1)>;
+ };
+
+ DIE_NODE(ps_atc1_common): power-controller@240 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x240 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_common);
+ power-domains = <&DIE_NODE(ps_afnc1_lw1)>;
+ };
+
+ DIE_NODE(ps_c0_usb31drd): power-controller@248 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x248 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(c0_usb31drd);
+ power-domains = <&DIE_NODE(ps_usb)>;
+ };
+
+ DIE_NODE(ps_c1_usb31drd): power-controller@250 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x250 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(c1_usb31drd);
+ power-domains = <&DIE_NODE(ps_usb)>;
+ };
+
+ DIE_NODE(ps_dispext0_fe): power-controller@258 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x258 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext0_fe);
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_dispext1_fe): power-controller@260 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x260 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext1_fe);
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_ane_sys): power-controller@268 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x268 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ane_sys);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_avd_sys): power-controller@270 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x270 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(avd_sys);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_dispext0_cpu0): power-controller@280 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x280 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext0_cpu0);
+ power-domains = <&DIE_NODE(ps_dispext0_fe)>;
+ };
+
+ DIE_NODE(ps_dispext1_cpu0): power-controller@2a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext1_cpu0);
+ power-domains = <&DIE_NODE(ps_dispext1_fe)>;
+ };
+
+ DIE_NODE(ps_ane_sys_cpu): power-controller@2c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2c8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ane_sys_cpu);
+ power-domains = <&DIE_NODE(ps_ane_sys)>;
+ };
+
+#if DIE_NO == 0
+ /* PMP is only present on die 0 of the M1 Ultra */
+ DIE_NODE(ps_pmp): power-controller@2d8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2d8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pmp);
+ };
+#endif
+
+ DIE_NODE(ps_pms_sram): power-controller@2e0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2e0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(pms_sram);
+ };
+
+ DIE_NODE(ps_apcie_st_sys): power-controller@2e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2e8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(apcie_st_sys);
+ power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans2)>;
+ };
+
+ DIE_NODE(ps_apcie_st1_sys): power-controller@2f0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2f0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(apcie_st1_sys);
+ power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans2)>;
+ };
+
+ DIE_NODE(ps_atc2_common): power-controller@2f8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2f8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_common);
+ power-domains = <&DIE_NODE(ps_afnc1_lw1)>;
+ };
+
+ DIE_NODE(ps_atc3_common): power-controller@300 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x300 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_common);
+ power-domains = <&DIE_NODE(ps_afnc1_lw1)>;
+ };
+
+ DIE_NODE(ps_usb): power-controller@318 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x318 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(usb);
+ power-domains = <&DIE_NODE(ps_afnc1_lw2)>;
+ };
+
+ DIE_NODE(ps_apcie_gp_sys): power-controller@320 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x320 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(apcie_gp_sys);
+ power-domains = <&DIE_NODE(ps_afnc1_lw2)>, <&DIE_NODE(ps_apcie_gp)>;
+ apple,always-on; /* Breaks things if shut down */
+ };
+
+ DIE_NODE(ps_atc0_cio): power-controller@328 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x328 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_cio);
+ power-domains = <&DIE_NODE(ps_atc0_common)>;
+ };
+
+ DIE_NODE(ps_atc0_pcie): power-controller@330 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x330 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_pcie);
+ power-domains = <&DIE_NODE(ps_atc0_common)>;
+ };
+
+ DIE_NODE(ps_atc1_cio): power-controller@338 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x338 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_cio);
+ power-domains = <&DIE_NODE(ps_atc1_common)>;
+ };
+
+ DIE_NODE(ps_atc1_pcie): power-controller@340 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x340 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_pcie);
+ power-domains = <&DIE_NODE(ps_atc1_common)>;
+ };
+
+ DIE_NODE(ps_atc2_cio): power-controller@348 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x348 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_cio);
+ power-domains = <&DIE_NODE(ps_atc2_common)>;
+ };
+
+ DIE_NODE(ps_atc2_pcie): power-controller@350 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x350 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_pcie);
+ power-domains = <&DIE_NODE(ps_atc2_common)>;
+ };
+
+ DIE_NODE(ps_atc3_cio): power-controller@358 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x358 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_cio);
+ power-domains = <&DIE_NODE(ps_atc3_common)>;
+ };
+
+ DIE_NODE(ps_atc3_pcie): power-controller@360 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x360 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_pcie);
+ power-domains = <&DIE_NODE(ps_atc3_common)>;
+ };
+
+ DIE_NODE(ps_c0_usbctl): power-controller@368 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x368 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(c0_usbctl);
+ power-domains = <&DIE_NODE(ps_usb)>;
+ };
+
+ DIE_NODE(ps_c1_usbctl): power-controller@370 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x370 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(c1_usbctl);
+ power-domains = <&DIE_NODE(ps_usb)>;
+ };
+
+ DIE_NODE(ps_atc0_cio_pcie): power-controller@378 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x378 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_cio_pcie);
+ power-domains = <&DIE_NODE(ps_atc0_cio)>;
+ };
+
+ DIE_NODE(ps_atc0_cio_usb): power-controller@380 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x380 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_cio_usb);
+ power-domains = <&DIE_NODE(ps_atc0_cio)>;
+ };
+
+ DIE_NODE(ps_atc1_cio_pcie): power-controller@388 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x388 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_cio_pcie);
+ power-domains = <&DIE_NODE(ps_atc1_cio)>;
+ };
+
+ DIE_NODE(ps_atc1_cio_usb): power-controller@390 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x390 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_cio_usb);
+ power-domains = <&DIE_NODE(ps_atc1_cio)>;
+ };
+
+ DIE_NODE(ps_atc2_cio_pcie): power-controller@398 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x398 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_cio_pcie);
+ power-domains = <&DIE_NODE(ps_atc2_cio)>;
+ };
+
+ DIE_NODE(ps_atc2_cio_usb): power-controller@3a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_cio_usb);
+ power-domains = <&DIE_NODE(ps_atc2_cio)>;
+ };
+
+ DIE_NODE(ps_atc3_cio_pcie): power-controller@3a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_cio_pcie);
+ power-domains = <&DIE_NODE(ps_atc3_cio)>;
+ };
+
+ DIE_NODE(ps_atc3_cio_usb): power-controller@3b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_cio_usb);
+ power-domains = <&DIE_NODE(ps_atc3_cio)>;
+ };
+
+ DIE_NODE(ps_trace_fab): power-controller@3b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(trace_fab);
+ };
+};
+
+&DIE_NODE(pmgr_east) {
+ DIE_NODE(ps_clvr_spmi0): power-controller@100 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x100 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(clvr_spmi0);
+ apple,always-on; /* PCPU voltage regulator interface (used by SMC) */
+ };
+
+ DIE_NODE(ps_clvr_spmi1): power-controller@108 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x108 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(clvr_spmi1);
+ apple,always-on; /* GPU voltage regulator interface (used by SMC) */
+ };
+
+ DIE_NODE(ps_clvr_spmi2): power-controller@110 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x110 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(clvr_spmi2);
+ apple,always-on; /* ANE, fabric, AFR voltage regulator interface (used by SMC) */
+ };
+
+ DIE_NODE(ps_clvr_spmi3): power-controller@118 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x118 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(clvr_spmi3);
+ apple,always-on; /* Additional voltage regulator, probably used on T6001 (SMC) */
+ };
+
+ DIE_NODE(ps_clvr_spmi4): power-controller@120 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x120 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(clvr_spmi4);
+ apple,always-on; /* Additional voltage regulator, probably used on T6001 (SMC) */
+ };
+
+ DIE_NODE(ps_ispsens0): power-controller@128 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x128 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ispsens0);
+ };
+
+ DIE_NODE(ps_ispsens1): power-controller@130 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x130 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ispsens1);
+ };
+
+ DIE_NODE(ps_ispsens2): power-controller@138 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x138 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ispsens2);
+ };
+
+ DIE_NODE(ps_ispsens3): power-controller@140 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x140 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ispsens3);
+ };
+
+ DIE_NODE(ps_afnc2_ioa): power-controller@148 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x148 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc2_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc2_ls): power-controller@150 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x150 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc2_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc2_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc2_lw0): power-controller@158 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x158 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc2_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc2_ls)>;
+ };
+
+ DIE_NODE(ps_afnc2_lw1): power-controller@160 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x160 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc2_lw1);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc2_ls)>;
+ };
+
+ DIE_NODE(ps_afnc3_ioa): power-controller@168 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x168 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc3_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc3_ls): power-controller@170 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x170 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc3_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc3_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc3_lw0): power-controller@178 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x178 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc3_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc3_ls)>;
+ };
+
+ DIE_NODE(ps_sio): power-controller@180 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x180 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio);
+ power-domains = <&DIE_NODE(ps_afnc2_lw1)>;
+ };
+
+ DIE_NODE(ps_sio_cpu): power-controller@188 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x188 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio_cpu);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_fpwm0): power-controller@190 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x190 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(fpwm0);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_fpwm1): power-controller@198 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x198 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(fpwm1);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_fpwm2): power-controller@1a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(fpwm2);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c0): power-controller@1a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c0);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c1): power-controller@1b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c1);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c2): power-controller@1b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c2);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c3): power-controller@1c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c3);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c4): power-controller@1c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c4);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c5): power-controller@1d0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1d0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c5);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c6): power-controller@1d8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1d8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c6);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_i2c7): power-controller@1e0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1e0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(i2c7);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_spi_p): power-controller@1e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1e8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi_p);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_spi0): power-controller@1f0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1f0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi0);
+ power-domains = <&DIE_NODE(ps_spi_p)>;
+ };
+
+ DIE_NODE(ps_spi1): power-controller@1f8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1f8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi1);
+ power-domains = <&DIE_NODE(ps_spi_p)>;
+ };
+
+ DIE_NODE(ps_spi2): power-controller@200 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x200 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi2);
+ power-domains = <&DIE_NODE(ps_spi_p)>;
+ };
+
+ DIE_NODE(ps_spi3): power-controller@208 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x208 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi3);
+ power-domains = <&DIE_NODE(ps_spi_p)>;
+ };
+
+ DIE_NODE(ps_spi4): power-controller@210 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x210 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(spi4);
+ power-domains = <&DIE_NODE(ps_spi_p)>;
+ };
+
+ DIE_NODE(ps_sio_spmi0): power-controller@218 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x218 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio_spmi0);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_sio_spmi1): power-controller@220 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x220 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio_spmi1);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_sio_spmi2): power-controller@228 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x228 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio_spmi2);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_uart_p): power-controller@230 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x230 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart_p);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_uart_n): power-controller@238 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x238 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart_n);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart0): power-controller@240 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x240 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart0);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart1): power-controller@248 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x248 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart1);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart2): power-controller@250 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x250 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart2);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart3): power-controller@258 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x258 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart3);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart4): power-controller@260 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x260 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart4);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart6): power-controller@268 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x268 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart6);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_uart7): power-controller@270 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x270 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(uart7);
+ power-domains = <&DIE_NODE(ps_uart_p)>;
+ };
+
+ DIE_NODE(ps_audio_p): power-controller@278 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x278 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(audio_p);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_sio_adma): power-controller@280 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x280 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sio_adma);
+ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_mca0): power-controller@288 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x288 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(mca0);
+ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>;
+ };
+
+ DIE_NODE(ps_mca1): power-controller@290 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x290 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(mca1);
+ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>;
+ };
+
+ DIE_NODE(ps_mca2): power-controller@298 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x298 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(mca2);
+ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>;
+ };
+
+ DIE_NODE(ps_mca3): power-controller@2a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(mca3);
+ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>;
+ };
+
+ DIE_NODE(ps_dpa0): power-controller@2a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dpa0);
+ power-domains = <&DIE_NODE(ps_audio_p)>;
+ };
+
+ DIE_NODE(ps_dpa1): power-controller@2b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dpa1);
+ power-domains = <&DIE_NODE(ps_audio_p)>;
+ };
+
+ DIE_NODE(ps_dpa2): power-controller@2b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dpa2);
+ power-domains = <&DIE_NODE(ps_audio_p)>;
+ };
+
+ DIE_NODE(ps_dpa3): power-controller@2c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2c0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dpa3);
+ power-domains = <&DIE_NODE(ps_audio_p)>;
+ };
+
+ DIE_NODE(ps_dpa4): power-controller@2c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2c8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dpa4);
+ power-domains = <&DIE_NODE(ps_audio_p)>;
+ };
+
+ DIE_NODE(ps_aes): power-controller@2d0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2d0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(aes);
+ power-domains = <&DIE_NODE(ps_sio)>;
+ };
+
+ DIE_NODE(ps_amcc1): power-controller@2d8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2d8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc1);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_amcc3): power-controller@2e0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2e0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc3);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_dcs_04): power-controller@2e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2e8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_04);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_05): power-controller@2f0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2f0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_05);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_06): power-controller@2f8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x2f8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_06);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_07): power-controller@300 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x300 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_07);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_12): power-controller@308 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x308 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_12);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_13): power-controller@310 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x310 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_13);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_14): power-controller@318 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x318 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_14);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_15): power-controller@320 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x320 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_15);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_disp0_fe): power-controller@328 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x328 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(disp0_fe);
+ power-domains = <&DIE_NODE(ps_afnc2_lw0)>;
+ apple,always-on; /* TODO: figure out if we can enable PM here */
+ };
+
+ DIE_NODE(ps_disp0_cpu0): power-controller@350 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x350 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(disp0_cpu0);
+ power-domains = <&DIE_NODE(ps_disp0_fe)>;
+ apple,always-on; /* TODO: figure out if we can enable PM here */
+ apple,min-state = <4>;
+ };
+
+ DIE_NODE(ps_dispdfr_fe): power-controller@378 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x378 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispdfr_fe);
+ power-domains = <&DIE_NODE(ps_afnc2_lw1)>;
+ };
+
+ DIE_NODE(ps_dispdfr_be): power-controller@380 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x380 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispdfr_be);
+ power-domains = <&DIE_NODE(ps_dispdfr_fe)>;
+ };
+
+ DIE_NODE(ps_mipi_dsi): power-controller@388 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x388 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(mipi_dsi);
+ power-domains = <&DIE_NODE(ps_dispdfr_be)>;
+ };
+
+ DIE_NODE(ps_jpg): power-controller@390 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x390 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(jpg);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_msr0): power-controller@398 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x398 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(msr0);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_msr0_ase_core): power-controller@3a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(msr0_ase_core);
+ power-domains = <&DIE_NODE(ps_msr0)>;
+ };
+
+ DIE_NODE(ps_isp_sys): power-controller@3a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(isp_sys);
+ power-domains = <&DIE_NODE(ps_afnc2_lw1)>;
+ };
+
+ DIE_NODE(ps_venc_sys): power-controller@3b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_sys);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_ans2): power-controller@3b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ans2);
+ /*
+ * The ADT makes ps_apcie_st[1]_sys depend on ps_ans2 instead,
+ * but we'd rather have a single power domain for the downstream
+ * device to depend on, so use this node as the child.
+ * This makes more sense anyway (since ANS2 uses APCIE_ST).
+ */
+ power-domains = <&DIE_NODE(ps_afnc2_lw0)>;
+ };
+
+ DIE_NODE(ps_gfx): power-controller@3c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x3c0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(gfx);
+ power-domains = <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_sep): power-controller@c00 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xc00 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(sep);
+ apple,always-on; /* Locked on */
+ };
+
+ DIE_NODE(ps_venc_dma): power-controller@8000 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8000 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_dma);
+ power-domains = <&DIE_NODE(ps_venc_sys)>;
+ };
+
+ DIE_NODE(ps_venc_pipe4): power-controller@8008 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8008 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_pipe4);
+ power-domains = <&DIE_NODE(ps_venc_dma)>;
+ };
+
+ DIE_NODE(ps_venc_pipe5): power-controller@8010 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8010 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_pipe5);
+ power-domains = <&DIE_NODE(ps_venc_dma)>;
+ };
+
+ DIE_NODE(ps_venc_me0): power-controller@8018 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8018 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_me0);
+ power-domains = <&DIE_NODE(ps_venc_pipe5)>, <&DIE_NODE(ps_venc_pipe4)>;
+ };
+
+ DIE_NODE(ps_venc_me1): power-controller@8020 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8020 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc_me1);
+ power-domains = <&DIE_NODE(ps_venc_me0)>;
+ };
+};
+
+&DIE_NODE(pmgr_south) {
+ DIE_NODE(ps_amcc4): power-controller@100 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x100 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc4);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_amcc5): power-controller@108 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x108 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc5);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_amcc6): power-controller@110 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x110 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc6);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_amcc7): power-controller@118 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x118 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(amcc7);
+ apple,always-on; /* Memory controller */
+ };
+
+ DIE_NODE(ps_dcs_16): power-controller@120 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x120 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_16);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_17): power-controller@128 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x128 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_17);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_18): power-controller@130 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x130 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_18);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_19): power-controller@138 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x138 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_19);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_20): power-controller@140 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x140 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_20);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_21): power-controller@148 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x148 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_21);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_22): power-controller@150 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x150 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_22);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_23): power-controller@158 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x158 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_23);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_24): power-controller@160 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x160 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_24);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_25): power-controller@168 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x168 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_25);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_26): power-controller@170 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x170 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_26);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_27): power-controller@178 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x178 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_27);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_28): power-controller@180 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x180 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_28);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_29): power-controller@188 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x188 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_29);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_30): power-controller@190 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x190 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_30);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_dcs_31): power-controller@198 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x198 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dcs_31);
+ apple,always-on; /* LPDDR5 interface */
+ };
+
+ DIE_NODE(ps_afnc4_ioa): power-controller@1a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc4_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc4_ls): power-controller@1a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1a8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc4_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc4_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc4_lw0): power-controller@1b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc4_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc4_ls)>;
+ };
+
+ DIE_NODE(ps_afnc5_ioa): power-controller@1b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1b8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc5_ioa);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afi)>;
+ };
+
+ DIE_NODE(ps_afnc5_ls): power-controller@1c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc5_ls);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc5_ioa)>;
+ };
+
+ DIE_NODE(ps_afnc5_lw0): power-controller@1c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1c8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(afnc5_lw0);
+ apple,always-on; /* Apple Fabric */
+ power-domains = <&DIE_NODE(ps_afnc5_ls)>;
+ };
+
+ DIE_NODE(ps_dispext2_fe): power-controller@1d0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1d0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext2_fe);
+ power-domains = <&DIE_NODE(ps_afnc4_lw0)>;
+ };
+
+ DIE_NODE(ps_dispext2_cpu0): power-controller@1e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x1e8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext2_cpu0);
+ power-domains = <&DIE_NODE(ps_dispext2_fe)>;
+ };
+
+ DIE_NODE(ps_dispext3_fe): power-controller@210 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x210 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext3_fe);
+ power-domains = <&DIE_NODE(ps_afnc4_lw0)>;
+ };
+
+ DIE_NODE(ps_dispext3_cpu0): power-controller@228 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x228 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(dispext3_cpu0);
+ power-domains = <&DIE_NODE(ps_dispext3_fe)>;
+ };
+
+ DIE_NODE(ps_msr1): power-controller@250 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x250 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(msr1);
+ power-domains = <&DIE_NODE(ps_afnc5_lw0)>, <&DIE_NODE(ps_afr)>;
+ };
+
+ DIE_NODE(ps_msr1_ase_core): power-controller@258 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x258 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(msr1_ase_core);
+ power-domains = <&DIE_NODE(ps_msr1)>;
+ };
+
+ DIE_NODE(ps_venc1_sys): power-controller@260 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x260 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_sys);
+ power-domains = <&DIE_NODE(ps_afnc5_lw0)>, <&DIE_NODE(ps_afr)>;
+ };
+
+ /* Seems to be disabled on shipping hardware */
+#if 0
+ DIE_NODE(ps_ane1_sys): power-controller@268 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x268 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ane1_sys);
+ power-domains = <&DIE_NODE(ps_afnc5_lw0)>;
+ };
+
+ DIE_NODE(ps_ane1_sys_cpu): power-controller@270 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x270 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(ane1_sys_cpu);
+ power-domains = <&DIE_NODE(ps_ane1_sys)>;
+ };
+#endif
+
+ DIE_NODE(ps_venc1_dma): power-controller@8000 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8000 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_dma);
+ power-domains = <&DIE_NODE(ps_venc1_sys)>;
+ };
+
+ DIE_NODE(ps_venc1_pipe4): power-controller@8008 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8008 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_pipe4);
+ power-domains = <&DIE_NODE(ps_venc1_dma)>;
+ };
+
+ DIE_NODE(ps_venc1_pipe5): power-controller@8010 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8010 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_pipe5);
+ power-domains = <&DIE_NODE(ps_venc1_dma)>;
+ };
+
+ DIE_NODE(ps_venc1_me0): power-controller@8018 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8018 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_me0);
+ power-domains = <&DIE_NODE(ps_venc1_pipe4)>, <&DIE_NODE(ps_venc1_pipe5)>;
+ };
+
+ DIE_NODE(ps_venc1_me1): power-controller@8020 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x8020 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(venc1_me1);
+ power-domains = <&DIE_NODE(ps_venc1_me0)>;
+ };
+
+ DIE_NODE(ps_prores): power-controller@c000 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xc000 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(prores);
+ power-domains = <&DIE_NODE(ps_afnc4_lw0)>;
+ };
+};
+
+&DIE_NODE(pmgr_mini) {
+ DIE_NODE(ps_debug): power-controller@58 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x58 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(debug);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_nub_spmi0): power-controller@60 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x60 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_spmi0);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_nub_spmi1): power-controller@68 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x68 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_spmi1);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_nub_aon): power-controller@70 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x70 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_aon);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_msg): power-controller@78 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x78 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(msg);
+ };
+
+ DIE_NODE(ps_nub_gpio): power-controller@80 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x80 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_gpio);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_atc0_usb_aon): power-controller@88 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x88 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_usb_aon);
+ apple,always-on; /* Needs to stay on for dwc3 to work */
+ };
+
+ DIE_NODE(ps_atc1_usb_aon): power-controller@90 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x90 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_usb_aon);
+ apple,always-on; /* Needs to stay on for dwc3 to work */
+ };
+
+ DIE_NODE(ps_atc2_usb_aon): power-controller@98 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0x98 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_usb_aon);
+ apple,always-on; /* Needs to stay on for dwc3 to work */
+ };
+
+ DIE_NODE(ps_atc3_usb_aon): power-controller@a0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xa0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_usb_aon);
+ apple,always-on; /* Needs to stay on for dwc3 to work */
+ };
+
+ DIE_NODE(ps_gp_usb_aon): power-controller@a8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xa8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(gp_usb_aon);
+ };
+
+ DIE_NODE(ps_nub_fabric): power-controller@b0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xb0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_fabric);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_nub_sram): power-controller@b8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xb8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(nub_sram);
+ apple,always-on; /* Core AON device */
+ };
+
+ DIE_NODE(ps_debug_usb): power-controller@c0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xc0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(debug_usb);
+ apple,always-on; /* Core AON device */
+ power-domains = <&DIE_NODE(ps_debug)>;
+ };
+
+ DIE_NODE(ps_debug_auth): power-controller@c8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xc8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(debug_auth);
+ apple,always-on; /* Core AON device */
+ power-domains = <&DIE_NODE(ps_debug)>;
+ };
+
+ DIE_NODE(ps_atc0_usb): power-controller@d0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xd0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc0_usb);
+ power-domains = <&DIE_NODE(ps_atc0_usb_aon)>, <&DIE_NODE(ps_atc0_common)>;
+ };
+
+ DIE_NODE(ps_atc1_usb): power-controller@d8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xd8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc1_usb);
+ power-domains = <&DIE_NODE(ps_atc1_usb_aon)>, <&DIE_NODE(ps_atc1_common)>;
+ };
+
+ DIE_NODE(ps_atc2_usb): power-controller@e0 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xe0 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc2_usb);
+ power-domains = <&DIE_NODE(ps_atc2_usb_aon)>, <&DIE_NODE(ps_atc2_common)>;
+ };
+
+ DIE_NODE(ps_atc3_usb): power-controller@e8 {
+ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate";
+ reg = <0xe8 4>;
+ #power-domain-cells = <0>;
+ #reset-cells = <0>;
+ label = DIE_LABEL(atc3_usb);
+ power-domains = <&DIE_NODE(ps_atc3_usb_aon)>, <&DIE_NODE(ps_atc3_common)>;
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts
index 8c6bf9592510..83bb4dc32af9 100644
--- a/arch/arm64/boot/dts/apple/t8103-j456.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j456.dts
@@ -14,7 +14,7 @@
/ {
compatible = "apple,j456", "apple,t8103", "apple,arm-platform";
- model = "Apple iMac (24-inch, 4x USB-C, M1, 2020)";
+ model = "Apple iMac (24-inch, 4x USB-C, M1, 2021)";
aliases {
ethernet0 = &ethernet0;
diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts
index fe7c0aaf7d62..67e433d5f8ba 100644
--- a/arch/arm64/boot/dts/apple/t8103-j457.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j457.dts
@@ -14,7 +14,7 @@
/ {
compatible = "apple,j457", "apple,t8103", "apple,arm-platform";
- model = "Apple iMac (24-inch, 2x USB-C, M1, 2020)";
+ model = "Apple iMac (24-inch, 2x USB-C, M1, 2021)";
aliases {
ethernet0 = &ethernet0;
diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi
index 3d15b8e2a6c1..9706d26f9c64 100644
--- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi
@@ -78,3 +78,7 @@
apple,antenna-sku = "XX";
};
};
+
+&nco_clkref {
+ clock-frequency = <900000000>;
+};
diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi
index a6dbb1f485d8..9645861a858c 100644
--- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi
@@ -339,7 +339,7 @@
#power-domain-cells = <0>;
#reset-cells = <0>;
label = "sio_adma";
- power-domains = <&ps_sio>, <&ps_pms>;
+ power-domains = <&ps_sio>, <&ps_pms>, <&ps_audio_p>;
};
ps_aes: power-controller@238 {
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 51a63b29d404..9859219699f4 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -22,69 +22,279 @@
#address-cells = <2>;
#size-cells = <0>;
- cpu0: cpu@0 {
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu_e0>;
+ };
+ core1 {
+ cpu = <&cpu_e1>;
+ };
+ core2 {
+ cpu = <&cpu_e2>;
+ };
+ core3 {
+ cpu = <&cpu_e3>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu_p0>;
+ };
+ core1 {
+ cpu = <&cpu_p1>;
+ };
+ core2 {
+ cpu = <&cpu_p2>;
+ };
+ core3 {
+ cpu = <&cpu_p3>;
+ };
+ };
+ };
+
+ cpu_e0: cpu@0 {
compatible = "apple,icestorm";
device_type = "cpu";
reg = <0x0 0x0>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&ecluster_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
};
- cpu1: cpu@1 {
+ cpu_e1: cpu@1 {
compatible = "apple,icestorm";
device_type = "cpu";
reg = <0x0 0x1>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&ecluster_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
};
- cpu2: cpu@2 {
+ cpu_e2: cpu@2 {
compatible = "apple,icestorm";
device_type = "cpu";
reg = <0x0 0x2>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&ecluster_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
};
- cpu3: cpu@3 {
+ cpu_e3: cpu@3 {
compatible = "apple,icestorm";
device_type = "cpu";
reg = <0x0 0x3>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&ecluster_opp>;
+ capacity-dmips-mhz = <714>;
+ performance-domains = <&cpufreq_e>;
+ next-level-cache = <&l2_cache_0>;
+ i-cache-size = <0x20000>;
+ d-cache-size = <0x10000>;
};
- cpu4: cpu@10100 {
+ cpu_p0: cpu@10100 {
compatible = "apple,firestorm";
device_type = "cpu";
reg = <0x0 0x10100>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&pcluster_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p>;
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
};
- cpu5: cpu@10101 {
+ cpu_p1: cpu@10101 {
compatible = "apple,firestorm";
device_type = "cpu";
reg = <0x0 0x10101>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&pcluster_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p>;
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
};
- cpu6: cpu@10102 {
+ cpu_p2: cpu@10102 {
compatible = "apple,firestorm";
device_type = "cpu";
reg = <0x0 0x10102>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&pcluster_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p>;
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
};
- cpu7: cpu@10103 {
+ cpu_p3: cpu@10103 {
compatible = "apple,firestorm";
device_type = "cpu";
reg = <0x0 0x10103>;
enable-method = "spin-table";
cpu-release-addr = <0 0>; /* To be filled by loader */
+ operating-points-v2 = <&pcluster_opp>;
+ capacity-dmips-mhz = <1024>;
+ performance-domains = <&cpufreq_p>;
+ next-level-cache = <&l2_cache_1>;
+ i-cache-size = <0x30000>;
+ d-cache-size = <0x20000>;
+ };
+
+ l2_cache_0: l2-cache-0 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0x400000>;
+ };
+
+ l2_cache_1: l2-cache-1 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ cache-size = <0xc00000>;
+ };
+ };
+
+ ecluster_opp: opp-table-0 {
+ compatible = "operating-points-v2";
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <7500>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <972000000>;
+ opp-level = <2>;
+ clock-latency-ns = <22000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1332000000>;
+ opp-level = <3>;
+ clock-latency-ns = <27000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1704000000>;
+ opp-level = <4>;
+ clock-latency-ns = <33000>;
+ };
+ opp05 {
+ opp-hz = /bits/ 64 <2064000000>;
+ opp-level = <5>;
+ clock-latency-ns = <50000>;
+ };
+ };
+
+ pcluster_opp: opp-table-1 {
+ compatible = "operating-points-v2";
+
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-level = <1>;
+ clock-latency-ns = <8000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <828000000>;
+ opp-level = <2>;
+ clock-latency-ns = <19000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-level = <3>;
+ clock-latency-ns = <21000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1284000000>;
+ opp-level = <4>;
+ clock-latency-ns = <23000>;
};
+ opp05 {
+ opp-hz = /bits/ 64 <1500000000>;
+ opp-level = <5>;
+ clock-latency-ns = <24000>;
+ };
+ opp06 {
+ opp-hz = /bits/ 64 <1728000000>;
+ opp-level = <6>;
+ clock-latency-ns = <29000>;
+ };
+ opp07 {
+ opp-hz = /bits/ 64 <1956000000>;
+ opp-level = <7>;
+ clock-latency-ns = <31000>;
+ };
+ opp08 {
+ opp-hz = /bits/ 64 <2184000000>;
+ opp-level = <8>;
+ clock-latency-ns = <34000>;
+ };
+ opp09 {
+ opp-hz = /bits/ 64 <2388000000>;
+ opp-level = <9>;
+ clock-latency-ns = <36000>;
+ };
+ opp10 {
+ opp-hz = /bits/ 64 <2592000000>;
+ opp-level = <10>;
+ clock-latency-ns = <51000>;
+ };
+ opp11 {
+ opp-hz = /bits/ 64 <2772000000>;
+ opp-level = <11>;
+ clock-latency-ns = <54000>;
+ };
+ opp12 {
+ opp-hz = /bits/ 64 <2988000000>;
+ opp-level = <12>;
+ clock-latency-ns = <55000>;
+ };
+#if 0
+ /* Not available until CPU deep sleep is implemented */
+ opp13 {
+ opp-hz = /bits/ 64 <3096000000>;
+ opp-level = <13>;
+ clock-latency-ns = <55000>;
+ turbo-mode;
+ };
+ opp14 {
+ opp-hz = /bits/ 64 <3144000000>;
+ opp-level = <14>;
+ clock-latency-ns = <56000>;
+ turbo-mode;
+ };
+ opp15 {
+ opp-hz = /bits/ 64 <3204000000>;
+ opp-level = <15>;
+ clock-latency-ns = <56000>;
+ turbo-mode;
+ };
+#endif
};
timer {
@@ -116,6 +326,16 @@
clock-output-names = "clkref";
};
+ /*
+ * This is a fabulated representation of the input clock
+ * to NCO since we don't know the true clock tree.
+ */
+ nco_clkref: clock-ref-nco {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-output-names = "nco_ref";
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <2>;
@@ -124,6 +344,27 @@
ranges;
nonposted-mmio;
+ cpufreq_e: performance-controller@210e20000 {
+ compatible = "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x10e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ cpufreq_p: performance-controller@211e20000 {
+ compatible = "apple,t8103-cluster-cpufreq", "apple,cluster-cpufreq";
+ reg = <0x2 0x11e20000 0 0x1000>;
+ #performance-domain-cells = <0>;
+ };
+
+ sio_dart: iommu@235004000 {
+ compatible = "apple,t8103-dart";
+ reg = <0x2 0x35004000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 635 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_sio_cpu>;
+ };
+
i2c0: i2c@235010000 {
compatible = "apple,t8103-i2c", "apple,i2c";
reg = <0x2 0x35010000 0x0 0x4000>;
@@ -219,6 +460,61 @@
status = "disabled";
};
+ admac: dma-controller@238200000 {
+ compatible = "apple,t8103-admac", "apple,admac";
+ reg = <0x2 0x38200000 0x0 0x34000>;
+ dma-channels = <24>;
+ interrupts-extended = <0>,
+ <&aic AIC_IRQ 626 IRQ_TYPE_LEVEL_HIGH>,
+ <0>,
+ <0>;
+ #dma-cells = <1>;
+ iommus = <&sio_dart 2>;
+ power-domains = <&ps_sio_adma>;
+ resets = <&ps_audio_p>;
+ };
+
+ mca: i2s@238400000 {
+ compatible = "apple,t8103-mca", "apple,mca";
+ reg = <0x2 0x38400000 0x0 0x18000>,
+ <0x2 0x38300000 0x0 0x30000>;
+
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 619 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 620 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 621 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 622 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 623 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 624 IRQ_TYPE_LEVEL_HIGH>;
+
+ resets = <&ps_audio_p>;
+ clocks = <&nco 0>, <&nco 1>, <&nco 2>,
+ <&nco 3>, <&nco 4>, <&nco 4>;
+ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>,
+ <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>;
+ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>,
+ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>,
+ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>,
+ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>,
+ <&admac 16>, <&admac 17>, <&admac 18>, <&admac 19>,
+ <&admac 20>, <&admac 21>, <&admac 22>, <&admac 23>;
+ dma-names = "tx0a", "rx0a", "tx0b", "rx0b",
+ "tx1a", "rx1a", "tx1b", "rx1b",
+ "tx2a", "rx2a", "tx2b", "rx2b",
+ "tx3a", "rx3a", "tx3b", "rx3b",
+ "tx4a", "rx4a", "tx4b", "rx4b",
+ "tx5a", "rx5a", "tx5b", "rx5b";
+
+ #sound-dai-cells = <1>;
+ };
+
+ nco: clock-controller@23b044000 {
+ compatible = "apple,t8103-nco", "apple,nco";
+ reg = <0x2 0x3b044000 0x0 0x14000>;
+ clocks = <&nco_clkref>;
+ #clock-cells = <1>;
+ };
+
aic: interrupt-controller@23b100000 {
compatible = "apple,t8103-aic", "apple,aic";
#interrupt-cells = <3>;
@@ -229,12 +525,12 @@
affinities {
e-core-pmu-affinity {
apple,fiq-index = <AIC_CPU_PMU_E>;
- cpus = <&cpu0 &cpu1 &cpu2 &cpu3>;
+ cpus = <&cpu_e0 &cpu_e1 &cpu_e2 &cpu_e3>;
};
p-core-pmu-affinity {
apple,fiq-index = <AIC_CPU_PMU_P>;
- cpus = <&cpu4 &cpu5 &cpu6 &cpu7>;
+ cpus = <&cpu_p0 &cpu_p1 &cpu_p2 &cpu_p3>;
};
};
};
@@ -412,7 +708,7 @@
resets = <&ps_ans2>;
};
- pcie0_dart_0: dart@681008000 {
+ pcie0_dart_0: iommu@681008000 {
compatible = "apple,t8103-dart";
reg = <0x6 0x81008000 0x0 0x4000>;
#iommu-cells = <1>;
@@ -421,7 +717,7 @@
power-domains = <&ps_apcie_gp>;
};
- pcie0_dart_1: dart@682008000 {
+ pcie0_dart_1: iommu@682008000 {
compatible = "apple,t8103-dart";
reg = <0x6 0x82008000 0x0 0x4000>;
#iommu-cells = <1>;
@@ -430,7 +726,7 @@
power-domains = <&ps_apcie_gp>;
};
- pcie0_dart_2: dart@683008000 {
+ pcie0_dart_2: iommu@683008000 {
compatible = "apple,t8103-dart";
reg = <0x6 0x83008000 0x0 0x4000>;
#iommu-cells = <1>;
diff --git a/arch/arm64/boot/dts/arm/corstone1000.dtsi b/arch/arm64/boot/dts/arm/corstone1000.dtsi
index 4e46826f883a..21f1f952e985 100644
--- a/arch/arm64/boot/dts/arm/corstone1000.dtsi
+++ b/arch/arm64/boot/dts/arm/corstone1000.dtsi
@@ -53,6 +53,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-level = <2>;
cache-size = <0x80000>;
cache-line-size = <64>;
diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dtsi b/arch/arm64/boot/dts/arm/foundation-v8.dtsi
index 83e3e7e3984f..029578072d8f 100644
--- a/arch/arm64/boot/dts/arm/foundation-v8.dtsi
+++ b/arch/arm64/boot/dts/arm/foundation-v8.dtsi
@@ -58,6 +58,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -84,6 +85,11 @@
<GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
};
+ spe-pmu {
+ compatible = "arm,statistical-profiling-extension-v1";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
watchdog@2a440000 {
compatible = "arm,sbsa-gwdt";
reg = <0x0 0x2a440000 0 0x1000>,
diff --git a/arch/arm64/boot/dts/arm/fvp-base-revc.dts b/arch/arm64/boot/dts/arm/fvp-base-revc.dts
index 5f6f30c801a7..60472d65a355 100644
--- a/arch/arm64/boot/dts/arm/fvp-base-revc.dts
+++ b/arch/arm64/boot/dts/arm/fvp-base-revc.dts
@@ -47,48 +47,121 @@
compatible = "arm,armv8";
reg = <0x0 0x000>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C0_L2>;
};
cpu1: cpu@100 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C0_L2>;
};
cpu2: cpu@200 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x200>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C0_L2>;
};
cpu3: cpu@300 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x300>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C0_L2>;
};
cpu4: cpu@10000 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x10000>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C1_L2>;
};
cpu5: cpu@10100 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x10100>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C1_L2>;
};
cpu6: cpu@10200 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x10200>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C1_L2>;
};
cpu7: cpu@10300 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x10300>;
enable-method = "psci";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <64>;
+ i-cache-sets = <256>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <64>;
+ d-cache-sets = <256>;
+ next-level-cache = <&C1_L2>;
+ };
+ C0_L2: l2-cache0 {
+ compatible = "cache";
+ cache-size = <0x80000>;
+ cache-line-size = <64>;
+ cache-sets = <512>;
+ cache-level = <2>;
+ cache-unified;
+ };
+
+ C1_L2: l2-cache1 {
+ compatible = "cache";
+ cache-size = <0x80000>;
+ cache-line-size = <64>;
+ cache-sets = <512>;
+ cache-level = <2>;
+ cache-unified;
};
};
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
index 6451c62146fd..1d90eeebb37d 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -189,6 +189,7 @@
A57_L2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x200000>;
cache-line-size = <64>;
cache-sets = <2048>;
@@ -197,6 +198,7 @@
A53_L2: l2-cache1 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts
index 438cd1ff4bd0..d2ada69b0a43 100644
--- a/arch/arm64/boot/dts/arm/juno-r2.dts
+++ b/arch/arm64/boot/dts/arm/juno-r2.dts
@@ -195,6 +195,7 @@
A72_L2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x200000>;
cache-line-size = <64>;
cache-sets = <2048>;
@@ -203,6 +204,7 @@
A53_L2: l2-cache1 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index cf4a58211399..5e48a01a5b9f 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -194,6 +194,7 @@
A57_L2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x200000>;
cache-line-size = <64>;
cache-sets = <2048>;
@@ -202,6 +203,7 @@
A53_L2: l2-cache1 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
index 258991ad7cc0..ef68f5aae7dd 100644
--- a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
+++ b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
@@ -71,6 +71,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
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 5b6d9d8e934d..796cd7d02eb5 100644
--- a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
+++ b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
@@ -57,6 +57,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi
index dac9d3b4e91d..eb2a78f4e033 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi
@@ -63,6 +63,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -283,6 +284,11 @@
#address-cells = <1>;
#size-cells = <1>;
+ timer@0 {
+ compatible = "brcm,bcm63138-timer";
+ reg = <0x0 0x28>;
+ };
+
watchdog@28 {
compatible = "brcm,bcm6345-wdt";
reg = <0x28 0x8>;
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi
index 3d016c2ce675..d5bc31980f03 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi
@@ -51,6 +51,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi
index 04de96bd0a03..6f805266d3c9 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi
@@ -35,6 +35,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi
index 13629702f70b..b982249b80a2 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi
@@ -51,6 +51,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi
index c3e6197be808..a996d436e977 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi
@@ -51,6 +51,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi
index 0bce6497219f..62c530d4b103 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi
@@ -35,6 +35,7 @@
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi
index 29a880c6c858..34c7b513d363 100644
--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi
@@ -50,6 +50,7 @@
};
L2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -109,6 +110,25 @@
#size-cells = <1>;
ranges = <0x0 0x0 0xff800000 0x62000>;
+ twd: timer-mfd@400 {
+ compatible = "brcm,bcm4908-twd", "simple-mfd", "syscon";
+ reg = <0x400 0x4c>;
+ ranges = <0x0 0x400 0x4c>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ timer@0 {
+ compatible = "brcm,bcm63138-timer";
+ reg = <0x0 0x28>;
+ };
+
+ watchdog@28 {
+ compatible = "brcm,bcm6345-wdt";
+ reg = <0x28 0x8>;
+ };
+ };
+
uart0: serial@640 {
compatible = "brcm,bcm6345-uart";
reg = <0x640 0x18>;
diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts
index e34172e3117e..fbf0392b8371 100644
--- a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts
@@ -52,7 +52,7 @@
memory {
device_type = "memory";
- reg = <0x000000000 0x80000000 0x00000000 0x40000000>;
+ reg = <0x00000000 0x80000000 0x00000000 0x40000000>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2-xmc.dts b/arch/arm64/boot/dts/broadcom/northstar2/ns2-xmc.dts
index 7bf26f3e36bf..699f7742ce7f 100644
--- a/arch/arm64/boot/dts/broadcom/northstar2/ns2-xmc.dts
+++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2-xmc.dts
@@ -49,7 +49,7 @@
memory {
device_type = "memory";
- reg = <0x000000000 0x80000000 0x00000001 0x00000000>;
+ reg = <0x00000000 0x80000000 0x00000001 0x00000000>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
index fda97c47f4e9..18cdbc20f03f 100644
--- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
@@ -79,6 +79,7 @@
CLUSTER0_L2: l2-cache@0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
index 8f8c25e51194..e05901abe957 100644
--- a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
+++ b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
@@ -108,18 +108,22 @@
CLUSTER0_L2: l2-cache@0 {
compatible = "cache";
+ cache-level = <2>;
};
CLUSTER1_L2: l2-cache@100 {
compatible = "cache";
+ cache-level = <2>;
};
CLUSTER2_L2: l2-cache@200 {
compatible = "cache";
+ cache-level = <2>;
};
CLUSTER3_L2: l2-cache@300 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 3ea9edc87909..ef6f364eaa18 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -57,10 +57,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-emcon-avari.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-innocomm-wb15-evk.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-kontron-bl.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-kontron-bl-osm-s.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-mx8menlo.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-nitrogen-r2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-phg.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-phyboard-polis-rdk.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-tqma8mqml-mba8mx.dtb
dtb-$(CONFIG_ARCH_MXC) += imx8mm-var-som-symphony.dtb
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dtso
index f826392c23fa..f826392c23fa 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dtso
index b949cac03742..b949cac03742 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtso
index 1dff68d7484b..1dff68d7484b 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dtso
index 19424d349713..19424d349713 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dtso
index fb85847f778f..fb85847f778f 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtso
index 63e46fad22bd..63e46fad22bd 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtso
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
index ac1c3a7e5f7a..1b33cabb4e14 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
@@ -46,6 +46,7 @@
l2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 704f72caddd3..b9fd24cdc919 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -84,6 +84,7 @@
l2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 3d9e29824bb2..a01e3cfec77f 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -79,6 +79,7 @@
l2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
index a2cadf757148..1e5d76c4d83d 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -95,18 +95,22 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-level = <2>;
};
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-level = <2>;
};
CPU_PW20: cpu-pw20 {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi
index c3dc38188c17..c12c86915ec8 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi
@@ -95,18 +95,22 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-level = <2>;
};
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-level = <2>;
};
CPU_PW20: cpu-pw20 {
diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
index 8c76d86cb756..50c19e8405d5 100644
--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
@@ -300,6 +300,7 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -308,6 +309,7 @@
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -316,6 +318,7 @@
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -324,6 +327,7 @@
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -332,6 +336,7 @@
cluster4_l2: l2-cache4 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -340,6 +345,7 @@
cluster5_l2: l2-cache5 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -348,6 +354,7 @@
cluster6_l2: l2-cache6 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -356,6 +363,7 @@
cluster7_l2: l2-cache7 {
compatible = "cache";
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
index 10370d1a6c6d..4852760adeee 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
@@ -34,6 +34,35 @@ conn_subsys: bus@5b000000 {
clock-output-names = "conn_ipg_clk";
};
+ usbotg1: usb@5b0d0000 {
+ compatible = "fsl,imx7ulp-usb";
+ reg = <0x5b0d0000 0x200>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,usbphy = <&usbphy1>;
+ fsl,usbmisc = <&usbmisc1 0>;
+ clocks = <&usb2_lpcg 0>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
+ power-domains = <&pd IMX_SC_R_USB_0>;
+ status = "disabled";
+ };
+
+ usbmisc1: usbmisc@5b0d0200 {
+ #index-cells = <1>;
+ compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc";
+ reg = <0x5b0d0200 0x200>;
+ };
+
+ usbphy1: usbphy@5b100000 {
+ compatible = "fsl,imx7ulp-usbphy";
+ reg = <0x5b100000 0x1000>;
+ clocks = <&usb2_lpcg 1>;
+ power-domains = <&pd IMX_SC_R_USB_0_PHY>;
+ status = "disabled";
+ };
+
usdhc1: mmc@5b010000 {
interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x5b010000 0x10000>;
@@ -195,4 +224,14 @@ conn_subsys: bus@5b000000 {
"enet1_lpcg_ipg_s_clk";
power-domains = <&pd IMX_SC_R_ENET_1>;
};
+
+ usb2_lpcg: clock-controller@5b270000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5b270000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&conn_ahb_clk>, <&conn_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_6>, <IMX_LPCG_CLK_7>;
+ clock-output-names = "usboh3_ahb_clk", "usboh3_phy_ipg_clk";
+ power-domains = <&pd IMX_SC_R_USB_0_PHY>;
+ };
};
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
index d7b4229bb4a2..a943a1e2797f 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
@@ -20,6 +20,70 @@ dma_subsys: bus@5a000000 {
clock-output-names = "dma_ipg_clk";
};
+ lpspi0: spi@5a000000 {
+ compatible = "fsl,imx7ulp-spi";
+ reg = <0x5a000000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&spi0_lpcg 0>,
+ <&spi0_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_SPI_0 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <20000000>;
+ power-domains = <&pd IMX_SC_R_SPI_0>;
+ status = "disabled";
+ };
+
+ lpspi1: spi@5a010000 {
+ compatible = "fsl,imx7ulp-spi";
+ reg = <0x5a010000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&spi1_lpcg 0>,
+ <&spi1_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_SPI_1 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <60000000>;
+ power-domains = <&pd IMX_SC_R_SPI_1>;
+ status = "disabled";
+ };
+
+ lpspi2: spi@5a020000 {
+ compatible = "fsl,imx7ulp-spi";
+ reg = <0x5a020000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&spi2_lpcg 0>,
+ <&spi2_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_SPI_2 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <60000000>;
+ power-domains = <&pd IMX_SC_R_SPI_2>;
+ status = "disabled";
+ };
+
+ lpspi3: spi@5a030000 {
+ compatible = "fsl,imx7ulp-spi";
+ reg = <0x5a030000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&spi3_lpcg 0>,
+ <&spi3_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_SPI_3 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <60000000>;
+ power-domains = <&pd IMX_SC_R_SPI_3>;
+ status = "disabled";
+ };
+
lpuart0: serial@5a060000 {
reg = <0x5a060000 0x1000>;
interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
@@ -60,6 +124,54 @@ dma_subsys: bus@5a000000 {
status = "disabled";
};
+ spi0_lpcg: clock-controller@5a400000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5a400000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_SPI_0 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "spi0_lpcg_clk",
+ "spi0_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_SPI_0>;
+ };
+
+ spi1_lpcg: clock-controller@5a410000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5a410000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_SPI_1 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "spi1_lpcg_clk",
+ "spi1_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_SPI_1>;
+ };
+
+ spi2_lpcg: clock-controller@5a420000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5a420000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_SPI_2 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "spi2_lpcg_clk",
+ "spi2_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_SPI_2>;
+ };
+
+ spi3_lpcg: clock-controller@5a430000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5a430000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_SPI_3 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "spi3_lpcg_clk",
+ "spi3_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_SPI_3>;
+ };
+
uart0_lpcg: clock-controller@5a460000 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x5a460000 0x10000>;
@@ -156,6 +268,34 @@ dma_subsys: bus@5a000000 {
status = "disabled";
};
+ adc0: adc@5a880000 {
+ compatible = "nxp,imx8qxp-adc";
+ reg = <0x5a880000 0x10000>;
+ interrupts = <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&adc0_lpcg 0>,
+ <&adc0_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_ADC_0 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <24000000>;
+ power-domains = <&pd IMX_SC_R_ADC_0>;
+ status = "disabled";
+ };
+
+ adc1: adc@5a890000 {
+ compatible = "nxp,imx8qxp-adc";
+ reg = <0x5a890000 0x10000>;
+ interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ clocks = <&adc1_lpcg 0>,
+ <&adc1_lpcg 1>;
+ clock-names = "per", "ipg";
+ assigned-clocks = <&clk IMX_SC_R_ADC_1 IMX_SC_PM_CLK_PER>;
+ assigned-clock-rates = <24000000>;
+ power-domains = <&pd IMX_SC_R_ADC_1>;
+ status = "disabled";
+ };
+
i2c0_lpcg: clock-controller@5ac00000 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x5ac00000 0x10000>;
@@ -203,4 +343,28 @@ dma_subsys: bus@5a000000 {
"i2c3_lpcg_ipg_clk";
power-domains = <&pd IMX_SC_R_I2C_3>;
};
+
+ adc0_lpcg: clock-controller@5ac80000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5ac80000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_ADC_0 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "adc0_lpcg_clk",
+ "adc0_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_ADC_0>;
+ };
+
+ adc1_lpcg: clock-controller@5ac90000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5ac90000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&clk IMX_SC_R_ADC_1 IMX_SC_PM_CLK_PER>,
+ <&dma_ipg_clk>;
+ clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+ clock-output-names = "adc1_lpcg_clk",
+ "adc1_lpcg_ipg_clk";
+ power-domains = <&pd IMX_SC_R_ADC_1>;
+ };
};
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi
index 6446e6df7a9a..1f3d225e64ec 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi
@@ -11,7 +11,8 @@ lsio_subsys: bus@5d000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
- ranges = <0x5d000000 0x0 0x5d000000 0x1000000>;
+ ranges = <0x5d000000 0x0 0x5d000000 0x1000000>,
+ <0x08000000 0x0 0x08000000 0x10000000>;
lsio_mem_clk: clock-lsio-mem {
compatible = "fixed-clock";
@@ -107,6 +108,20 @@ lsio_subsys: bus@5d000000 {
power-domains = <&pd IMX_SC_R_GPIO_7>;
};
+ flexspi0: spi@5d120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nxp,imx8qxp-fspi";
+ reg = <0x5d120000 0x10000>, <0x08000000 0x10000000>;
+ reg-names = "fspi_base", "fspi_mmap";
+ interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX_SC_R_FSPI_0 IMX_SC_PM_CLK_PER>,
+ <&clk IMX_SC_R_FSPI_0 IMX_SC_PM_CLK_PER>;
+ clock-names = "fspi", "fspi_en";
+ power-domains = <&pd IMX_SC_R_FSPI_0>;
+ status = "disabled";
+ };
+
lsio_mu0: mailbox@5d1b0000 {
reg = <0x5d1b0000 0x10000>;
interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
index ca2a43e0cbf6..280a9c9d8bd9 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
@@ -90,6 +90,28 @@
enable-active-high;
off-on-delay-us = <3480>;
};
+
+ reg_vref_1v8: regulator-adc-vref {
+ compatible = "regulator-fixed";
+ regulator-name = "vref_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ mii_select: regulator-4 {
+ compatible = "regulator-fixed";
+ regulator-name = "mii-select";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&scu_gpio 6 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+};
+
+&adc0 {
+ vref-supply = <&reg_vref_1v8>;
+ status = "okay";
};
&eqos {
@@ -159,6 +181,23 @@
};
};
+&flexspi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexspi0>;
+ nxp,fspi-dll-slvdly = <4>;
+ status = "okay";
+
+ mt35xu512aba0: flash@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <133000000>;
+ spi-tx-bus-width = <8>;
+ spi-rx-bus-width = <8>;
+ };
+};
+
&i2c2 {
#address-cells = <1>;
#size-cells = <0>;
@@ -266,6 +305,40 @@
};
};
+&usbphy1 {
+ /* USB eye diagram tests result */
+ fsl,tx-d-cal = <114>;
+ status = "okay";
+};
+
+&usbotg1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg1>;
+ srp-disable;
+ hnp-disable;
+ adp-disable;
+ power-active-high;
+ disable-over-current;
+ status = "okay";
+};
+
+&usbphy2 {
+ /* USB eye diagram tests result */
+ fsl,tx-d-cal = <111>;
+ status = "okay";
+};
+
+&usbotg2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg2>;
+ srp-disable;
+ hnp-disable;
+ adp-disable;
+ power-active-high;
+ disable-over-current;
+ status = "okay";
+};
+
&usdhc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc1>;
@@ -286,6 +359,21 @@
status = "okay";
};
+&lpspi3 {
+ fsl,spi-num-chipselects = <1>;
+ fsl,spi-only-use-cs1-sel;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpspi3>;
+ pinctrl-assert-gpios = <&pca6416_1 7 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+
+ spidev0: spi@0 {
+ reg = <0>;
+ compatible = "rohm,dh2228fv";
+ spi-max-frequency = <30000000>;
+ };
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
@@ -330,6 +418,25 @@
>;
};
+ pinctrl_flexspi0: flexspi0grp {
+ fsl,pins = <
+ IMX8DXL_QSPI0A_DATA0_LSIO_QSPI0A_DATA0 0x06000021
+ IMX8DXL_QSPI0A_DATA1_LSIO_QSPI0A_DATA1 0x06000021
+ IMX8DXL_QSPI0A_DATA2_LSIO_QSPI0A_DATA2 0x06000021
+ IMX8DXL_QSPI0A_DATA3_LSIO_QSPI0A_DATA3 0x06000021
+ IMX8DXL_QSPI0A_DQS_LSIO_QSPI0A_DQS 0x06000021
+ IMX8DXL_QSPI0A_SS0_B_LSIO_QSPI0A_SS0_B 0x06000021
+ IMX8DXL_QSPI0A_SCLK_LSIO_QSPI0A_SCLK 0x06000021
+ IMX8DXL_QSPI0B_SCLK_LSIO_QSPI0B_SCLK 0x06000021
+ IMX8DXL_QSPI0B_DATA0_LSIO_QSPI0B_DATA0 0x06000021
+ IMX8DXL_QSPI0B_DATA1_LSIO_QSPI0B_DATA1 0x06000021
+ IMX8DXL_QSPI0B_DATA2_LSIO_QSPI0B_DATA2 0x06000021
+ IMX8DXL_QSPI0B_DATA3_LSIO_QSPI0B_DATA3 0x06000021
+ IMX8DXL_QSPI0B_DQS_LSIO_QSPI0B_DQS 0x06000021
+ IMX8DXL_QSPI0B_SS0_B_LSIO_QSPI0B_SS0_B 0x06000021
+ >;
+ };
+
pinctrl_fec1: fec1grp {
fsl,pins = <
IMX8DXL_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB0_PAD 0x000014a0
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
index 795d1d472fae..6881330ab4c6 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
@@ -11,6 +11,10 @@
clock-frequency = <160000000>;
};
+&adc0 {
+ interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+};
+
&i2c0 {
compatible = "fsl,imx8dxl-lpi2c", "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c";
interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
@@ -50,3 +54,19 @@
compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart";
interrupts = <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
};
+
+&lpspi0 {
+ interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&lpspi1 {
+ interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&lpspi2 {
+ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&lpspi3 {
+ interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
index 69c4849f2132..6b416fb760d5 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
@@ -140,3 +140,13 @@
compatible = "fsl,imx8dxl-usdhc", "fsl,imx8qxp-usdhc";
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
};
+
+&usbotg1 {
+ interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+ /*
+ * usbotg1 and usbotg2 share one clock
+ * scfw disable clock access and keep it always on
+ * in case other core (M4) use one of these.
+ */
+ clocks = <&clk_dummy>;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-lsio.dtsi
index 815bd987b09b..5f4f789e4a73 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-lsio.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-lsio.dtsi
@@ -3,44 +3,90 @@
* Copyright 2019~2020, 2022 NXP
*/
+&flexspi0 {
+ compatible = "nxp,imx8dxl-fspi";
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+};
+
&lsio_gpio0 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 47 13>,
+ <&iomuxc 13 61 4>,
+ <&iomuxc 19 67 4>,
+ <&iomuxc 24 72 1>;
};
&lsio_gpio1 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 4 74 5>,
+ <&iomuxc 9 80 16>;
};
&lsio_gpio2 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 1 98 2>,
+ <&iomuxc 3 101 1>,
+ <&iomuxc 5 107 8>;
};
&lsio_gpio3 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 115 4>,
+ <&iomuxc 9 121 1>,
+ <&iomuxc 10 120 1>,
+ <&iomuxc 11 123 1>,
+ <&iomuxc 12 122 1>,
+ <&iomuxc 13 125 1>,
+ <&iomuxc 14 124 1>,
+ <&iomuxc 16 126 1>,
+ <&iomuxc 17 128 1>,
+ <&iomuxc 18 131 1>,
+ <&iomuxc 19 130 1>,
+ <&iomuxc 20 133 1>,
+ <&iomuxc 21 132 1>,
+ <&iomuxc 22 129 1>,
+ <&iomuxc 23 134 1>;
};
&lsio_gpio4 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 0 3>,
+ <&iomuxc 3 4 4>,
+ <&iomuxc 7 9 12>,
+ <&iomuxc 19 22 2>,
+ <&iomuxc 21 25 2>,
+ <&iomuxc 29 29 3>;
};
&lsio_gpio5 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 32 3>,
+ <&iomuxc 3 36 6>,
+ <&iomuxc 9 43 3>;
};
&lsio_gpio6 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 53 7>,
+ <&iomuxc 8 86 10>,
+ <&iomuxc 19 107 8>;
};
&lsio_gpio7 {
compatible = "fsl,imx8dxl-gpio", "fsl,imx35-gpio";
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&iomuxc 0 0 3>,
+ <&iomuxc 3 4 4>,
+ <&iomuxc 8 22 2>,
+ <&iomuxc 10 25 2>,
+ <&iomuxc 16 44 2>;
};
&lsio_mu0 {
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl.dtsi
index 5ddbda0b4def..0c64b9194621 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8dxl.dtsi
@@ -59,6 +59,7 @@
A35_L2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -133,6 +134,12 @@
clock-names = "xtal_32KHz", "xtal_24Mhz";
};
+ scu_gpio: gpio {
+ compatible = "fsl,imx8qxp-sc-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
iomuxc: pinctrl {
compatible = "fsl,imx8dxl-iomuxc";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi
index cf07987ccc10..201325f566cb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi
@@ -47,15 +47,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts
index 778bdbe228d3..24f61db33eba 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts
@@ -46,6 +46,12 @@
clock-frequency = <25000000>;
};
+ clk_xtal32k: clk-xtal32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
panel: panel {
backlight = <&backlight>;
power-supply = <&reg_panel_vcc>;
@@ -77,12 +83,11 @@
enable-active-high;
};
- watchdog-gpio {
+ watchdog {
/* TPS3813 */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_watchdog_gpio>;
compatible = "linux,wdt-gpio";
- always-enabled;
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
hw_algo = "level";
/* Reset triggers in 2..3 seconds */
@@ -114,15 +119,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -183,8 +188,6 @@
reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
reset-assert-us = <10000>;
reset-deassert-us = <10000>;
- qca,clk-out-frequency = <125000000>;
- qca,clk-out-strength = <AR803X_STRENGTH_FULL>;
qca,keep-pll-enabled;
vddio-supply = <&vddio>;
@@ -271,6 +274,9 @@
pmic: pmic@4b {
compatible = "rohm,bd71847";
reg = <0x4b>;
+ #clock-cells = <0>;
+ clocks = <&clk_xtal32k 0>;
+ clock-output-names = "clk-32k-out";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pmic>;
interrupt-parent = <&gpio1>;
@@ -928,6 +934,10 @@
status = "disabled";
};
+&snvs_rtc {
+ clocks = <&pmic>;
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
index a2b24d4d4e3e..b68954bcc383 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
@@ -23,15 +23,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
index 7d6317d95b13..e0b604ac0da4 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
@@ -56,6 +56,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ off-on-delay-us = <20000>;
enable-active-high;
};
@@ -343,6 +344,7 @@
reg = <0x20>;
gpio-controller;
#gpio-cells = <2>;
+ vcc-supply = <&buck4_reg>;
};
};
@@ -399,6 +401,10 @@
status = "okay";
};
+&usbphynop1 {
+ wakeup-source;
+};
+
&usbotg1 {
dr_mode = "otg";
hnp-disable;
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15-evk.dts b/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15-evk.dts
new file mode 100644
index 000000000000..055faae79930
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15-evk.dts
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2018 Bang & Olufsen
+ * Copyright 2022 Pengutronix
+ */
+
+/dts-v1/;
+
+#include "imx8mm-innocomm-wb15.dtsi"
+
+/ {
+ model = "InnoComm WB15-EVK";
+ compatible = "innocomm,wb15-evk", "fsl,imx8mm";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ led-0 {
+ label = "debug";
+ gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ reg_vsd_3v3: regulator-vsd-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_reg_vsd_3v3>;
+ regulator-name = "VSD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_ethphy: regulator-eth-phy {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec_phy_reg>;
+ regulator-name = "PHY_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec>;
+ phy-mode = "rgmii-id";
+ phy-handle = <&ethphy0>;
+ fsl,magic-packet;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0x1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec_phy>;
+ reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ phy-supply = <&reg_ethphy>;
+ };
+ };
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usbotg1 {
+ dr_mode = "otg";
+ samsung,picophy-pre-emp-curr-control = <3>;
+ samsung,picophy-dc-vol-level-adjust = <7>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usbotg2 {
+ dr_mode = "host";
+ samsung,picophy-pre-emp-curr-control = <3>;
+ samsung,picophy-dc-vol-level-adjust = <7>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc2 {
+ cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&reg_vsd_3v3>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_fec: fec-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x03
+ MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x03
+ MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f
+ MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f
+ MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f
+ MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f
+ MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91
+ MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91
+ MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91
+ MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91
+ MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f
+ MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91
+ MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91
+ MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f
+ >;
+ };
+
+ pinctrl_fec_phy: fec-phy-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9 0x19
+ >;
+ };
+
+ pinctrl_fec_phy_reg: fec-phy-reg-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x16
+ >;
+ };
+
+ pinctrl_gpio_leds: led-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3 0xd6
+ >;
+ };
+
+ pinctrl_reg_vsd_3v3: reg-vsd-3v3-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x41
+ >;
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15.dtsi
new file mode 100644
index 000000000000..44e87b1568e7
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-innocomm-wb15.dtsi
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2018 Bang & Olufsen
+ */
+
+#include "imx8mm.dtsi"
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+/ {
+ reg_modem: regulator-modem {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_modem_regulator>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "epdev_on";
+ gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ reg_3v3_out: regulator-3v3-out {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3_OUT";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&cpu_alert0 {
+ temperature = <95000>;
+};
+
+&cpu_crit0 {
+ temperature = <105000>;
+};
+
+&ddrc {
+ operating-points-v2 = <&ddrc_opp_table>;
+
+ ddrc_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-25000000 {
+ opp-hz = /bits/ 64 <25000000>;
+ };
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ status = "okay";
+
+ pmic@4b {
+ compatible = "rohm,bd71847";
+ reg = <0x4b>;
+ pinctrl-0 = <&pinctrl_pmic>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+ rohm,reset-snvs-powered;
+
+ regulators {
+ buck1_reg: BUCK1 {
+ regulator-name = "buck1";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <1250>;
+ rohm,dvs-run-voltage = <850000>;
+ rohm,dvs-idle-voltage = <850000>;
+ rohm,dvs-suspend-voltage = <850000>;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "buck2";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <1250>;
+ rohm,dvs-run-voltage = <1000000>;
+ rohm,dvs-idle-voltage = <900000>;
+ };
+
+ buck3_reg: BUCK3 {
+ // buck5 in datasheet
+ regulator-name = "buck3";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ buck4_reg: BUCK4 {
+ // buck6 in datasheet
+ regulator-name = "buck4";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ buck5_reg: BUCK5 {
+ // buck7 in datasheet
+ regulator-name = "buck5";
+ regulator-min-microvolt = <1605000>;
+ regulator-max-microvolt = <1995000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ buck6_reg: BUCK6 {
+ // buck8 in datasheet
+ regulator-name = "buck6";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: LDO1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "ldo5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "ldo6";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+};
+
+&pcie_phy {
+ fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+ fsl,tx-deemph-gen1 = <0x2d>;
+ fsl,tx-deemph-gen2 = <0xf>;
+ status = "okay";
+};
+
+&pcie0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie0>;
+ reset-gpio = <&gpio5 21 GPIO_ACTIVE_LOW>;
+ clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_PHY>,
+ <&clk IMX8MM_CLK_PCIE1_AUX>;
+ clock-names = "pcie", "pcie_bus", "pcie_aux";
+ fsl,max-link-speed = <1>;
+ assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>, <&clk IMX8MM_CLK_PCIE1_CTRL>;
+ assigned-clock-rates = <10000000>, <250000000>;
+ assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>, <&clk IMX8MM_SYS_PLL2_250M>;
+ status = "okay";
+};
+
+&uart1 { /* BT */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ assigned-clocks = <&clk IMX8MM_CLK_UART1>;
+ assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4349-bt";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_modem_bt>;
+ device-wakeup-gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+ vbat-supply = <&reg_3v3_out>;
+ vddio-supply = <&reg_3v3_out>;
+ clocks = <&osc_32k>;
+ max-speed = <3000000>;
+ clock-names = "extclk";
+ };
+};
+
+&uart2 { /* console */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ bus-width = <8>;
+ no-sd;
+ no-sdio;
+ non-removable;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+ bus-width = <4>;
+};
+
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+ status = "okay";
+};
+
+&A53_0 {
+ cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+ cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+ cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+ cpu-supply = <&buck2_reg>;
+};
+
+/delete-node/ &sec_jr1; /* Job ring in use by OP-TEE */
+
+&iomuxc {
+ pinctrl_i2c1: i2c1-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3
+ >;
+ };
+
+ pinctrl_i2c1_gpio: i2c1-gpio-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
+ pinctrl_i2c2: i2c2-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3
+ >;
+ };
+
+ pinctrl_i2c2_gpio: i2c2-gpio-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
+ pinctrl_i2c3: i2c3-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA 0x400001c3
+ >;
+ };
+
+ pinctrl_i2c3_gpio: i2c3-gpio-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
+ pinctrl_pcie0: pcie0-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B 0x61
+ MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21 0x6
+ >;
+ };
+
+ pinctrl_modem_bt: modem-bt-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_NAND_CLE_GPIO3_IO5 0x19
+ MX8MM_IOMUXC_NAND_CE2_B_GPIO3_IO3 0x19
+ MX8MM_IOMUXC_NAND_CE3_B_GPIO3_IO4 0x19
+ MX8MM_IOMUXC_NAND_RE_B_GPIO3_IO15 0x19
+ MX8MM_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K 0x141
+ >;
+ };
+
+ pinctrl_modem_regulator: modem-reg-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16 0x41
+ >;
+ };
+
+ pinctrl_pmic: pmic-irq-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41
+ >;
+ };
+
+ pinctrl_uart1: uart1-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140
+ MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140
+ MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B 0x140
+ MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B 0x140
+ >;
+ };
+
+ pinctrl_uart2: uart2-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140
+ MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x40000190
+ MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d0
+ MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d0
+ MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d0
+ MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d0
+ MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d0
+ MX8MM_IOMUXC_SD1_DATA4_USDHC1_DATA4 0x1d0
+ MX8MM_IOMUXC_SD1_DATA5_USDHC1_DATA5 0x1d0
+ MX8MM_IOMUXC_SD1_DATA6_USDHC1_DATA6 0x1d0
+ MX8MM_IOMUXC_SD1_DATA7_USDHC1_DATA7 0x1d0
+ MX8MM_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x190
+ MX8MM_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0x1d0
+ >;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1-100mhz-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x40000194
+ MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d4
+ MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d4
+ MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d4
+ MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d4
+ MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d4
+ MX8MM_IOMUXC_SD1_DATA4_USDHC1_DATA4 0x1d4
+ MX8MM_IOMUXC_SD1_DATA5_USDHC1_DATA5 0x1d4
+ MX8MM_IOMUXC_SD1_DATA6_USDHC1_DATA6 0x1d4
+ MX8MM_IOMUXC_SD1_DATA7_USDHC1_DATA7 0x1d4
+ MX8MM_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x194
+ MX8MM_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0x1d4
+ >;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1-200mhz-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x40000196
+ MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d6
+ MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d6
+ MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d6
+ MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d6
+ MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d6
+ MX8MM_IOMUXC_SD1_DATA4_USDHC1_DATA4 0x1d6
+ MX8MM_IOMUXC_SD1_DATA5_USDHC1_DATA5 0x1d6
+ MX8MM_IOMUXC_SD1_DATA6_USDHC1_DATA6 0x1d6
+ MX8MM_IOMUXC_SD1_DATA7_USDHC1_DATA7 0x1d6
+ MX8MM_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x196
+ MX8MM_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0x1d6
+ >;
+ };
+
+ pinctrl_usdhc2_gpio: usdhc2-gpio-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x1d0
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0
+ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4
+ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6
+ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0
+ >;
+ };
+
+ pinctrl_wdog: wdog-grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6
+ >;
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi
index 8d10f5b41297..5172883717d1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi
@@ -47,11 +47,11 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi
index 0679728d2489..1f8326613ee9 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi
@@ -46,11 +46,11 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phg.dts b/arch/arm64/boot/dts/freescale/imx8mm-phg.dts
new file mode 100644
index 000000000000..e9447738b104
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-phg.dts
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Fabio Estevam <festevam@denx.de>
+ */
+
+/dts-v1/;
+
+#include "imx8mm-tqma8mqml.dtsi"
+
+/ {
+ model = "Cloos i.MX8MM PHG board";
+ compatible = "cloos,imx8mm-phg", "tq,imx8mm-tqma8mqml", "fsl,imx8mm";
+
+ aliases {
+ mmc0 = &usdhc3;
+ mmc1 = &usdhc2;
+ };
+
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ beeper {
+ compatible = "gpio-beeper";
+ pinctrl-0 = <&pinctrl_beeper>;
+ gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_led>;
+
+ led-0 {
+ label = "status1";
+ gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-1 {
+ label = "status2";
+ gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-2 {
+ label = "status3";
+ gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-3 {
+ label = "run";
+ gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+ };
+
+ led-4 {
+ label = "powerled";
+ gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ reg_usb_otg_vbus: regulator-usb-otg-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_otg_vbus_ctrl>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usdhc2_vmmc: regulator-vmmc {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+ regulator-name = "VSD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ startup-delay-us = <100>;
+ off-on-delay-us = <12000>;
+ };
+};
+
+&ecspi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+ phy-mode = "rgmii-id";
+ phy-handle = <&ethphy0>;
+ fsl,magic-packet;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ compatible = "ethernet-phy-ieee802.3-c22";
+ };
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&usbphynop1 {
+ power-domains = <&pgc_otg1>;
+};
+
+&usbphynop2 {
+ power-domains = <&pgc_otg2>;
+};
+
+&usbotg1 {
+ dr_mode = "host";
+ vbus-supply = <&reg_usb_otg_vbus>;
+ status = "okay";
+};
+
+&usbotg2 {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usdhc2 {
+ assigned-clocks = <&clk IMX8MM_CLK_USDHC2>;
+ assigned-clock-rates = <400000000>;
+ assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_400M>;
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ no-mmc;
+ no-sdio;
+ sd-uhs-sdr104;
+ sd-uhs-ddr50;
+ vmmc-supply = <&reg_usdhc2_vmmc>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_beeper: beepergrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO00_GPIO1_IO0 0x19
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO 0x82
+ MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI 0x82
+ MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK 0x82
+ MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19
+ >;
+ };
+
+ pinctrl_fec1: fec1grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x40000002
+ MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x40000002
+ MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x14
+ MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x14
+ MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x14
+ MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x14
+ MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x90
+ MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x90
+ MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x90
+ MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x90
+ MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x14
+ MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x90
+ MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x90
+ MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x14
+ MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x10
+ >;
+ };
+
+ pinctrl_gpio_led: gpioledgrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x19
+ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x19
+ MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x19
+ MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x19
+ MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1 0x19
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3
+ >;
+ };
+
+ pinctrl_otg_vbus_ctrl: otgvbusctrlgrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD1_DATA0_GPIO2_IO2 0x119
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140
+ MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140
+ >;
+ };
+
+ pinctrl_usdhc2_gpio: usdhc2grpgpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x1c4
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196
+ MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6
+ MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6
+ MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6
+ MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6
+ MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6
+ >;
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
index 995b44efb1b6..92616bc4f71f 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
@@ -53,15 +53,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
index 7e0aeb2db305..a0aeac619929 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
@@ -34,11 +34,25 @@
off-on-delay-us = <12000>;
};
- extcon_usbotg1: extcon-usbotg1 {
- compatible = "linux,extcon-usb-gpio";
+ connector {
+ compatible = "gpio-usb-b-connector", "usb-b-connector";
+ type = "micro";
+ label = "X19";
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb1_extcon>;
- id-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&pinctrl_usb1_connector>;
+ id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ usb_dr_connector: endpoint {
+ remote-endpoint = <&usb1_drd_sw>;
+ };
+ };
+ };
};
};
@@ -105,13 +119,19 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usbotg1>;
dr_mode = "otg";
- extcon = <&extcon_usbotg1>;
srp-disable;
hnp-disable;
adp-disable;
power-active-high;
over-current-active-low;
+ usb-role-switch;
status = "okay";
+
+ port {
+ usb1_drd_sw: endpoint {
+ remote-endpoint = <&usb_dr_connector>;
+ };
+ };
};
&usbotg2 {
@@ -231,7 +251,7 @@
<MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x84>;
};
- pinctrl_usb1_extcon: usb1-extcongrp {
+ pinctrl_usb1_connector: usb1-connectorgrp {
fsl,pins = <MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x1c0>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-var-som.dtsi
index a0bd540f27d3..ae0721b807e1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-var-som.dtsi
@@ -53,15 +53,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi
index 66a0d103c90f..9e7d38872157 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi
@@ -81,15 +81,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -119,8 +119,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -365,8 +368,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
eeprom@52 {
@@ -435,6 +441,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -442,6 +455,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_uart2: uart2grp {
fsl,pins = <
MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dtso
index 4eaf8aabcbff..4eaf8aabcbff 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-imx219.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dtso
index 3ea73a6886ff..3ea73a6886ff 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dtso
index c3cd9f2b0db3..c3cd9f2b0db3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs422.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dtso
index cc0a287226ab..cc0a287226ab 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs485.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dtso
index f3ece4b7fbbd..f3ece4b7fbbd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-imx219.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso
index 2fa635e1c1a8..2fa635e1c1a8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso
index 3e6404340d52..3e6404340d52 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso
index 2c71ab9854cb..2c71ab9854cb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
index d3ee6fc4baab..750a1f07ecb7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
@@ -248,15 +248,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -326,8 +326,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -477,8 +480,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
pmic@4b {
@@ -600,8 +606,11 @@
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
leds_gpio: gpio@20 {
@@ -673,8 +682,11 @@
&i2c4 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4_gpio>;
+ scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
@@ -852,6 +864,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -859,6 +878,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -866,6 +892,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_i2c4: i2c4grp {
fsl,pins = <
MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3
@@ -873,6 +906,13 @@
>;
};
+ pinctrl_i2c4_gpio: i2c4gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C4_SCL_GPIO5_IO20 0x400001c3
+ MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21 0x400001c3
+ >;
+ };
+
pinctrl_ksz: kszgrp {
fsl,pins = <
MX8MM_IOMUXC_SAI1_TXD6_GPIO4_IO18 0x41
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
index 31f4c735fe4f..32872b0b1aaf 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
@@ -198,15 +198,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -261,7 +261,7 @@
&gpio1 {
gpio-line-names = "", "", "", "", "", "", "", "",
- "", "", "", "", "", "m2_reset", "", "m2_wdis#",
+ "m2_pwr_en", "", "", "", "", "m2_reset", "", "m2_wdis#",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "";
};
@@ -283,7 +283,8 @@
&gpio4 {
gpio-line-names = "", "", "", "", "", "", "", "",
"", "", "", "amp_gpio3", "amp_gpio2", "", "amp_gpio1", "",
- "", "", "", "", "amp_gpio4", "app_gpio1", "", "uart1_rs485",
+ "lte_pwr#", "lte_rst", "lte_int", "",
+ "amp_gpio4", "app_gpio1", "vdd_4p0_en", "uart1_rs485",
"", "uart1_term", "uart1_half", "app_gpio2",
"mipi_gpio1", "", "", "";
};
@@ -298,8 +299,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -566,8 +570,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
accelerometer@19 {
@@ -585,16 +592,22 @@
/* off-board header */
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
/* off-board header */
&i2c4 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4_gpio>;
+ scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
@@ -738,14 +751,19 @@
pinctrl_hog: hoggrp {
fsl,pins = <
MX8MM_IOMUXC_NAND_CE0_B_GPIO3_IO1 0x40000159 /* M2_GDIS# */
+ MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x40000041 /* M2_PWR_EN */
MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RESET */
MX8MM_IOMUXC_NAND_DATA01_GPIO3_IO7 0x40000119 /* M2_OFF# */
MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x40000159 /* M2_WDIS# */
+ MX8MM_IOMUXC_SAI1_TXD6_GPIO4_IO18 0x40000041 /* LTE_INT */
+ MX8MM_IOMUXC_SAI1_TXD5_GPIO4_IO17 0x40000041 /* LTE_RST# */
+ MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16 0x40000041 /* LTE_PWR */
MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14 0x40000041 /* AMP GPIO1 */
MX8MM_IOMUXC_SAI1_TXD0_GPIO4_IO12 0x40000041 /* AMP GPIO2 */
MX8MM_IOMUXC_SAI1_TXC_GPIO4_IO11 0x40000041 /* AMP GPIO3 */
MX8MM_IOMUXC_SAI1_MCLK_GPIO4_IO20 0x40000041 /* AMP_GPIO4 */
MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x40000041 /* APP GPIO1 */
+ MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x40000041 /* VDD_4P0_EN */
MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27 0x40000041 /* APP GPIO2 */
MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8 0x40000041 /* UART2_EN# */
MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x40000041 /* MIPI_GPIO1 */
@@ -779,8 +797,6 @@
MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f
MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x19 /* RST# */
MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x19 /* IRQ# */
- MX8MM_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN 0x141
- MX8MM_IOMUXC_GPIO1_IO09_ENET1_1588_EVENT0_OUT 0x141
>;
};
@@ -797,6 +813,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -804,6 +827,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -811,6 +841,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_i2c4: i2c4grp {
fsl,pins = <
MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3
@@ -818,6 +855,13 @@
>;
};
+ pinctrl_i2c4_gpio: i2c4gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C4_SCL_GPIO5_IO20 0x400001c3
+ MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21 0x400001c3
+ >;
+ };
+
pinctrl_gpio_leds: gpioledgrp {
fsl,pins = <
MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x19
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts
index 19f6d2943d26..8ce562246a08 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts
@@ -207,15 +207,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -265,8 +265,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -397,8 +400,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
pmic@4b {
@@ -520,8 +526,11 @@
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
accelerometer@19 {
@@ -681,6 +690,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -688,6 +704,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -695,6 +718,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_gpio_leds: gpioledgrp {
fsl,pins = <
MX8MM_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5 0x19
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts
index a67771d02146..eceed9816f5d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts
@@ -266,15 +266,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -315,8 +315,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -441,8 +444,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
pmic@4b {
@@ -564,8 +570,11 @@
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
accelerometer@19 {
@@ -582,8 +591,11 @@
&i2c4 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4_gpio>;
+ scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gpioled: gpio@27 {
@@ -738,6 +750,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -745,6 +764,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -752,6 +778,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_i2c4: i2c4grp {
fsl,pins = <
MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3
@@ -759,6 +792,13 @@
>;
};
+ pinctrl_i2c4_gpio: i2c4gpiogrp {
+ fsl,pins = <
+ MX8MM_IOMUXC_I2C4_SCL_GPIO5_IO20 0x400001c3
+ MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21 0x400001c3
+ >;
+ };
+
pinctrl_pcie0: pciegrp {
fsl,pins = <
MX8MM_IOMUXC_ECSPI2_MOSI_GPIO5_IO11 0x41
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
index bcab830c6e95..0d454e0e2f7c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
@@ -3,8 +3,8 @@
* Copyright 2022 Toradex
*/
-#include "dt-bindings/phy/phy-imx8-pcie.h"
-#include "dt-bindings/pwm/pwm.h"
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
#include "imx8mm.dtsi"
/ {
@@ -183,15 +183,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -610,7 +610,7 @@
compatible = "atmel,maxtouch";
/*
* Verdin GPIO_9_DSI
- * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI83 IRQ albeit currently unused)
+ * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI84 IRQ albeit currently unused)
*/
interrupt-parent = <&gpio3>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
@@ -653,7 +653,8 @@
assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
<&clk IMX8MM_SYS_PLL2_250M>;
assigned-clock-rates = <10000000>, <250000000>;
- clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
+ clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>,
+ <&clk IMX8MM_CLK_PCIE1_AUX>,
<&clk IMX8MM_CLK_PCIE1_PHY>;
clock-names = "pcie", "pcie_aux", "pcie_bus";
pinctrl-names = "default";
@@ -664,6 +665,7 @@
&pcie_phy {
clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
+ clock-names = "ref";
fsl,clkreq-unsupported;
fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
fsl,tx-deemph-gen1 = <0x2d>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
index dabd94dc30c4..4ee89fdcf59b 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -139,6 +139,7 @@
A53_L2: l2-cache0 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
@@ -575,9 +576,10 @@
};
};
- anatop: anatop@30360000 {
- compatible = "fsl,imx8mm-anatop", "syscon";
+ anatop: clock-controller@30360000 {
+ compatible = "fsl,imx8mm-anatop";
reg = <0x30360000 0x10000>;
+ #clock-cells = <1>;
};
snvs: snvs@30370000 {
@@ -1244,10 +1246,10 @@
clocks = <&clk IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK>;
};
- gpmi: nand-controller@33002000{
+ gpmi: nand-controller@33002000 {
compatible = "fsl,imx8mm-gpmi-nand", "fsl,imx7d-gpmi-nand";
#address-cells = <1>;
- #size-cells = <1>;
+ #size-cells = <0>;
reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
reg-names = "gpmi-nand", "bch";
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi
index 1133cded9be2..8a4369d38903 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi
@@ -55,15 +55,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-800M {
+ opp-800000000 {
opp-hz = /bits/ 64 <800000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
index d8ce217c6016..5110d59b719f 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
@@ -35,15 +35,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-600M {
+ opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
index 4eb467df5ba7..4839a962a170 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
@@ -47,6 +47,7 @@
regulator-boot-on;
regulator-always-on;
regulator-ramp-delay = <3125>;
+ nxp,dvs-standby-voltage = <750000>;
};
buck2: BUCK2 {
@@ -56,8 +57,6 @@
regulator-boot-on;
regulator-always-on;
regulator-ramp-delay = <3125>;
- nxp,dvs-run-voltage = <950000>;
- nxp,dvs-standby-voltage = <850000>;
};
buck4: BUCK4{
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
index 261c36540079..8fef980c4ab2 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
@@ -36,6 +36,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ off-on-delay-us = <12000>;
enable-active-high;
};
@@ -159,8 +160,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
status = "okay";
ptn5110: tcpc@50 {
@@ -195,8 +199,11 @@
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
status = "okay";
pca6416: gpio@20 {
@@ -240,6 +247,15 @@
status = "okay";
};
+&uart1 { /* BT */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ assigned-clocks = <&clk IMX8MN_CLK_UART1>;
+ assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_80M>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
&uart2 { /* console */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
@@ -255,6 +271,10 @@
status = "okay";
};
+&usbphynop1 {
+ wakeup-source;
+};
+
&usbotg1 {
dr_mode = "otg";
hnp-disable;
@@ -369,6 +389,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2grp-gpio {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16 0x1c3
+ MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17 0x1c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -376,6 +403,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3grp-gpio {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18 0x1c3
+ MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19 0x1c3
+ >;
+ };
+
pinctrl_pmic: pmicirqgrp {
fsl,pins = <
MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141
@@ -419,6 +453,15 @@
>;
};
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140
+ MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140
+ MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B 0x140
+ MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B 0x140
+ >;
+ };
+
pinctrl_uart2: uart2grp {
fsl,pins = <
MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
index dd4302ac1de4..b9444e4a3d2d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
@@ -189,15 +189,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-750M {
+ opp-750000000 {
opp-hz = /bits/ 64 <750000000>;
};
};
@@ -256,7 +256,7 @@
&gpio1 {
gpio-line-names = "", "", "", "", "", "", "", "",
- "", "", "", "", "", "m2_reset", "", "m2_wdis#",
+ "m2_pwr_en", "", "", "", "", "m2_reset", "", "m2_wdis#",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "";
};
@@ -278,7 +278,7 @@
&gpio4 {
gpio-line-names = "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
- "", "", "", "", "", "app_gpio1", "", "uart1_rs485",
+ "", "", "", "", "", "app_gpio1", "vdd_4p0_en", "uart1_rs485",
"", "uart1_term", "uart1_half", "app_gpio2",
"mipi_gpio1", "", "", "";
};
@@ -297,8 +297,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -565,8 +568,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
accelerometer@19 {
@@ -584,16 +590,22 @@
/* off-board header */
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
/* off-board header */
&i2c4 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4_gpio>;
+ scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
@@ -689,10 +701,12 @@
pinctrl_hog: hoggrp {
fsl,pins = <
MX8MN_IOMUXC_NAND_CE0_B_GPIO3_IO1 0x40000159 /* M2_GDIS# */
+ MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x40000041 /* M2_PWR_EN */
MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RESET */
MX8MN_IOMUXC_NAND_DATA01_GPIO3_IO7 0x40000119 /* M2_OFF# */
MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x40000159 /* M2_WDIS# */
MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x40000041 /* APP GPIO1 */
+ MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22 0x40000041 /* VDD_4P0_EN */
MX8MN_IOMUXC_SAI2_MCLK_GPIO4_IO27 0x40000041 /* APP GPIO2 */
MX8MN_IOMUXC_SD1_DATA6_GPIO2_IO8 0x40000041 /* UART2_EN# */
MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x40000041 /* MIPI_GPIO1 */
@@ -726,8 +740,6 @@
MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f
MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x19 /* RST# */
MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x19 /* IRQ# */
- MX8MN_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN 0x141
- MX8MN_IOMUXC_GPIO1_IO09_ENET1_1588_EVENT0_OUT 0x141
>;
};
@@ -744,6 +756,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14 0x400001c3
+ MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15 0x400001c3
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3
@@ -751,6 +770,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16 0x400001c3
+ MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3
@@ -758,6 +784,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18 0x400001c3
+ MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_i2c4: i2c4grp {
fsl,pins = <
MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3
@@ -765,6 +798,13 @@
>;
};
+ pinctrl_i2c4_gpio: i2c4gpiogrp {
+ fsl,pins = <
+ MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20 0x400001c3
+ MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21 0x400001c3
+ >;
+ };
+
pinctrl_gpio_leds: gpioledgrp {
fsl,pins = <
MX8MN_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x19
diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index ad0b99adf691..b7d91df71cc2 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -139,6 +139,7 @@
A53_L2: l2-cache0 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
@@ -576,10 +577,10 @@
};
};
- anatop: anatop@30360000 {
- compatible = "fsl,imx8mn-anatop", "fsl,imx8mm-anatop",
- "syscon";
+ anatop: clock-controller@30360000 {
+ compatible = "fsl,imx8mn-anatop", "fsl,imx8mm-anatop";
reg = <0x30360000 0x10000>;
+ #clock-cells = <1>;
};
snvs: snvs@30370000 {
@@ -1102,7 +1103,7 @@
gpmi: nand-controller@33002000 {
compatible = "fsl,imx8mn-gpmi-nand", "fsl,imx7d-gpmi-nand";
#address-cells = <1>;
- #size-cells = <1>;
+ #size-cells = <0>;
reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
reg-names = "gpmi-nand", "bch";
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
index 0f13ee362771..6e1192e751f8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
@@ -427,6 +427,24 @@
pinctrl-0 = <&pinctrl_uart2>;
uart-has-rtscts;
status = "okay";
+
+ /*
+ * PLL3 at 320 MHz supplies UART2 root with 64 MHz clock,
+ * which with 16x oversampling yields 4 Mbdps baud base,
+ * which is exactly the maximum rate supported by muRata
+ * 2AE bluetooth UART.
+ */
+ assigned-clocks = <&clk IMX8MP_SYS_PLL3>, <&clk IMX8MP_CLK_UART2>;
+ assigned-clock-parents = <0>, <&clk IMX8MP_SYS_PLL3_OUT>;
+ assigned-clock-rates = <320000000>, <64000000>;
+
+ bluetooth {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2_bt>;
+ compatible = "cypress,cyw4373a0-bt";
+ shutdown-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+ max-speed = <4000000>;
+ };
};
&uart3 {
@@ -849,6 +867,13 @@
>;
};
+ pinctrl_uart2_bt: dhcom-uart2-bt-grp {
+ fsl,pins = <
+ /* BT_REG_EN */
+ MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x144
+ >;
+ };
+
pinctrl_uart3: dhcom-uart3-grp {
fsl,pins = <
MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX 0x49
@@ -886,8 +911,6 @@
MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0
MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0
MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0
- /* BT_REG_EN */
- MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x144
/* WL_REG_EN */
MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x144
>;
@@ -901,8 +924,6 @@
MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d4
MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d4
MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d4
- /* BT_REG_EN */
- MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x144
/* WL_REG_EN */
MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x144
>;
@@ -916,8 +937,6 @@
MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d6
MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d6
MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d6
- /* BT_REG_EN */
- MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x144
/* WL_REG_EN */
MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x144
>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index 9f1469db554d..d4c7ca16abd0 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -85,6 +85,20 @@
};
};
+&flexspi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexspi0>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <80000000>;
+ spi-tx-bus-width = <1>;
+ spi-rx-bus-width = <4>;
+ };
+};
+
&A53_0 {
cpu-supply = <&reg_arm>;
};
@@ -317,6 +331,13 @@
};
};
+&i2c2 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
&i2c3 {
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -390,10 +411,37 @@
status = "okay";
};
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>;
+ status = "okay";
+};
+
+&pwm4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm4>;
+ status = "okay";
+};
+
&snvs_pwrkey {
status = "okay";
};
+&uart1 { /* BT */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ assigned-clocks = <&clk IMX8MP_CLK_UART1>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
&uart2 {
/* console */
pinctrl-names = "default";
@@ -416,6 +464,15 @@
status = "okay";
};
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
&usdhc2 {
assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
assigned-clock-rates = <400000000>;
@@ -515,6 +572,17 @@
>;
};
+ pinctrl_flexspi0: flexspi0grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK 0x1c2
+ MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B 0x82
+ MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00 0x82
+ MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01 0x82
+ MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02 0x82
+ MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03 0x82
+ >;
+ };
+
pinctrl_gpio_led: gpioledgrp {
fsl,pins = <
MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x140
@@ -528,6 +596,13 @@
>;
};
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2
+ MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2
@@ -544,14 +619,14 @@
pinctrl_pcie0: pcie0grp {
fsl,pins = <
- MX8MP_IOMUXC_I2C4_SCL__PCIE_CLKREQ_B 0x61 /* open drain, pull up */
- MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x41
+ MX8MP_IOMUXC_I2C4_SCL__PCIE_CLKREQ_B 0x60 /* open drain, pull up */
+ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40
>;
};
pinctrl_pcie0_reg: pcie0reggrp {
fsl,pins = <
- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x41
+ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40
>;
};
@@ -567,12 +642,39 @@
>;
};
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_GPIO1_IO01__PWM1_OUT 0x116
+ >;
+ };
+
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_GPIO1_IO11__PWM2_OUT 0x116
+ >;
+ };
+
+ pinctrl_pwm4: pwm4grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_SAI5_RXFS__PWM4_OUT 0x116
+ >;
+ };
+
pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
fsl,pins = <
MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40
>;
};
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140
+ MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140
+ MX8MP_IOMUXC_UART3_RXD__UART1_DCE_CTS 0x140
+ MX8MP_IOMUXC_UART3_TXD__UART1_DCE_RTS 0x140
+ >;
+ };
+
pinctrl_uart2: uart2grp {
fsl,pins = <
MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x140
@@ -586,6 +688,15 @@
>;
};
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX 0x140
+ MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX 0x140
+ MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS 0x140
+ MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS 0x140
+ >;
+ };
+
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <
MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 7bf6f81e87b4..6357f3d96ccd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -8,6 +8,7 @@
#include <dt-bindings/leds/common.h>
#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
#include <dt-bindings/pwm/pwm.h>
#include "imx8mp-tqma8mpql.dtsi"
@@ -48,6 +49,27 @@
status = "disabled";
};
+ clk_xtal25: clk-xtal25 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+
+ fan0: pwm-fan {
+ compatible = "pwm-fan";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwmfan>;
+ fan-supply = <&reg_pwm_fan>;
+ #cooling-cells = <2>;
+ /* typical 25 kHz -> 40.000 nsec */
+ pwms = <&pwm3 0 40000 PWM_POLARITY_INVERTED>;
+ cooling-levels = <0 32 64 128 196 240>;
+ pulses-per-revolution = <2>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ status = "disabled";
+ };
+
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
@@ -108,6 +130,18 @@
status = "disabled";
};
+ reg_pwm_fan: regulator-pwm-fan {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_regpwmfan>;
+ regulator-name = "FAN_PWR";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ vin-supply = <&reg_vcc_12v0>;
+ };
+
reg_usdhc2_vmmc: regulator-usdhc2 {
compatible = "regulator-fixed";
pinctrl-names = "default";
@@ -165,6 +199,47 @@
linux,cma-default;
};
};
+
+ thermal-zones {
+ soc-thermal {
+ trips {
+ soc_active0: trip-active0 {
+ temperature = <40000>;
+ hysteresis = <5000>;
+ type = "active";
+ };
+
+ soc_active1: trip-active1 {
+ temperature = <48000>;
+ hysteresis = <3000>;
+ type = "active";
+ };
+
+ soc_active2: trip-active2 {
+ temperature = <60000>;
+ hysteresis = <10000>;
+ type = "active";
+ };
+ };
+
+ cooling-maps {
+ map1 {
+ trip = <&soc_active0>;
+ cooling-device = <&fan0 1 1>;
+ };
+
+ map2 {
+ trip = <&soc_active1>;
+ cooling-device = <&fan0 2 2>;
+ };
+
+ map3 {
+ trip = <&soc_active2>;
+ cooling-device = <&fan0 3 3>;
+ };
+ };
+ };
+ };
};
&ecspi1 {
@@ -340,9 +415,16 @@
"", "", "", "",
"", "", "", "",
"", "", "DP_IRQ", "DSI_EN",
- "HDMI_OC#", "TEMP_EVENT#", "PCIE_CLK_OE#", "",
+ "HDMI_OC#", "TEMP_EVENT#", "PCIE_REFCLK_OE#", "",
"", "", "", "FAN_PWR",
"RTC_EVENT#", "CODEC_RST#", "", "";
+
+ pcie-refclkreq-hog {
+ gpio-hog;
+ gpios = <22 0>;
+ output-high;
+ line-name = "PCIE_REFCLK_OE#";
+ };
};
&gpio5 {
@@ -377,6 +459,13 @@
pagesize = <16>;
vcc-supply = <&reg_vcc_3v3>;
};
+
+ pcieclk: clock-generator@6a {
+ compatible = "renesas,9fgv0241";
+ reg = <0x6a>;
+ clocks = <&clk_xtal25>;
+ #clock-cells = <1>;
+ };
};
&i2c4 {
@@ -407,6 +496,25 @@
interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
};
+&pcie_phy {
+ fsl,clkreq-unsupported;
+ fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
+ clocks = <&pcieclk 0>;
+ clock-names = "ref";
+ status = "okay";
+};
+
+&pcie {
+ clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
+ <&clk IMX8MP_CLK_HSIO_AXI>,
+ <&clk IMX8MP_CLK_PCIE_ROOT>;
+ clock-names = "pcie", "pcie_bus", "pcie_aux";
+ assigned-clocks = <&clk IMX8MP_CLK_PCIE_AUX>;
+ assigned-clock-rates = <10000000>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_50M>;
+ status = "okay";
+};
+
&pwm2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm2>;
@@ -461,11 +569,23 @@
status = "okay";
};
+&usb3_1 {
+ fsl,disable-port-power-control;
+ fsl,permanently-attached;
+ dr_mode = "host";
+ status = "okay";
+};
+
&usb3_phy0 {
vbus-supply = <&reg_vcc_5v0>;
status = "okay";
};
+&usb3_phy1 {
+ vbus-supply = <&reg_vcc_5v0>;
+ status = "okay";
+};
+
&usb_dwc3_0 {
/* dual role is implemented, but not a full featured OTG */
hnp-disable;
@@ -486,6 +606,31 @@
};
};
+&usb_dwc3_1 {
+ dr_mode = "host";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbhub>;
+ status = "okay";
+
+ hub_2_0: hub@1 {
+ compatible = "usb451,8142";
+ reg = <1>;
+ peer-hub = <&hub_3_0>;
+ reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
+ vdd-supply = <&reg_vcc_3v3>;
+ };
+
+ hub_3_0: hub@2 {
+ compatible = "usb451,8140";
+ reg = <2>;
+ peer-hub = <&hub_2_0>;
+ reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
+ vdd-supply = <&reg_vcc_3v3>;
+ };
+};
+
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
@@ -685,10 +830,18 @@
fsl,pins = <MX8MP_IOMUXC_I2C3_SDA__PWM3_OUT 0x14>;
};
+ pinctrl_pwmfan: pwmfangrp {
+ fsl,pins = <MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18 0x80>; /* FAN RPM */
+ };
+
pinctrl_reg12v0: reg12v0grp {
fsl,pins = <MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140>; /* VCC12V enable */
};
+ pinctrl_regpwmfan: regpwmfangrp {
+ fsl,pins = <MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27 0x80>;
+ };
+
/* X61 */
pinctrl_uart1: uart1grp {
fsl,pins = <MX8MP_IOMUXC_SD1_CLK__UART1_DCE_TX 0x140>,
@@ -720,6 +873,10 @@
fsl,pins = <MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x1c0>;
};
+ pinctrl_usbhub: usbhubgrp {
+ fsl,pins = <MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11 0x10>;
+ };
+
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x192>,
<MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d2>,
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
index 06b4c93c5876..ceeca4966fc5 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
@@ -253,8 +253,11 @@
&i2c1 {
clock-frequency = <100000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
gsc: gsc@20 {
@@ -477,8 +480,11 @@
&i2c2 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
accelerometer@19 {
@@ -556,16 +562,22 @@
/* off-board header */
&i2c3 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c3>;
+ pinctrl-1 = <&pinctrl_i2c3_gpio>;
+ scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
/* off-board header */
&i2c4 {
clock-frequency = <400000>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c4>;
+ pinctrl-1 = <&pinctrl_i2c4_gpio>;
+ scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "okay";
};
@@ -800,6 +812,13 @@
>;
};
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14 0x400001c2
+ MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15 0x400001c2
+ >;
+ };
+
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2
@@ -807,6 +826,13 @@
>;
};
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16 0x400001c3
+ MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17 0x400001c3
+ >;
+ };
+
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2
@@ -814,6 +840,13 @@
>;
};
+ pinctrl_i2c3_gpio: i2c3gpiogrp {
+ fsl,pins = <
+ MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18 0x400001c3
+ MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19 0x400001c3
+ >;
+ };
+
pinctrl_i2c4: i2c4grp {
fsl,pins = <
MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL 0x400001c2
@@ -821,6 +854,13 @@
>;
};
+ pinctrl_i2c4_gpio: i2c4gpiogrp {
+ fsl,pins = <
+ MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20 0x400001c3
+ MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21 0x400001c3
+ >;
+ };
+
pinctrl_ksz: kszgrp {
fsl,pins = <
MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x150 /* IRQ# */
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
index 4b8f86f63081..80db1ad7c230 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
@@ -116,6 +116,7 @@
/* Verdin USB_2 */
&usb3_1 {
+ fsl,permanently-attached;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
index 5dcd1de586b5..6a1890a4b5d8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
@@ -3,7 +3,8 @@
* Copyright 2022 Toradex
*/
-#include "dt-bindings/pwm/pwm.h"
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
#include "imx8mp.dtsi"
/ {
@@ -678,8 +679,8 @@
status = "disabled";
};
- lvds_ti_sn65dsi83: bridge@2c {
- compatible = "ti,sn65dsi83";
+ lvds_ti_sn65dsi84: bridge@2c {
+ compatible = "ti,sn65dsi84";
/* Verdin GPIO_9_DSI (SN65DSI84 IRQ, SODIMM 17, unused) */
/* Verdin GPIO_10_DSI (SODIMM 21) */
enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
@@ -712,7 +713,7 @@
compatible = "atmel,maxtouch";
/*
* Verdin GPIO_9_DSI
- * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI83 IRQ albeit currently unused)
+ * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI84 IRQ albeit currently unused)
*/
interrupt-parent = <&gpio4>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
@@ -806,28 +807,45 @@
};
/* Verdin USB_1 */
-&usb3_phy0 {
- vbus-supply = <&reg_usb1_vbus>;
+&usb3_0 {
+ fsl,disable-port-power-control;
+ fsl,over-current-active-low;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb_1_oc_n>;
};
&usb_dwc3_0 {
+ /* dual role only, not full featured OTG */
adp-disable;
dr_mode = "otg";
hnp-disable;
maximum-speed = "high-speed";
- over-current-active-low;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb_1_id>;
+ role-switch-default-mode = "peripheral";
srp-disable;
+ usb-role-switch;
+
+ connector {
+ compatible = "gpio-usb-b-connector", "usb-b-connector";
+ id-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+ label = "Type-C";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb_1_id>;
+ self-powered;
+ type = "micro";
+ vbus-supply = <&reg_usb1_vbus>;
+ };
};
/* Verdin USB_2 */
+&usb3_1 {
+ fsl,disable-port-power-control;
+};
+
&usb3_phy1 {
vbus-supply = <&reg_usb2_vbus>;
};
&usb_dwc3_1 {
- disable-over-current;
dr_mode = "host";
};
@@ -1045,7 +1063,6 @@
pinctrl_gpio_hog3: gpiohog3grp {
fsl,pins =
- <MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x1c4>, /* SODIMM 157 */
/* CSI_1_MCLK */
<MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15 0x1c4>; /* SODIMM 91 */
};
@@ -1220,7 +1237,7 @@
pinctrl_usb1_vbus: usb1vbusgrp {
fsl,pins =
- <MX8MP_IOMUXC_GPIO1_IO12__USB1_OTG_PWR 0x19>; /* SODIMM 155 */
+ <MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x106>; /* SODIMM 155 */
};
/* USB_1_ID */
@@ -1229,9 +1246,15 @@
<MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10 0x1c4>; /* SODIMM 161 */
};
+ /* USB_1_OC# */
+ pinctrl_usb_1_oc_n: usb1ocngrp {
+ fsl,pins =
+ <MX8MP_IOMUXC_GPIO1_IO13__USB1_OTG_OC 0x1c4>; /* SODIMM 157 */
+ };
+
pinctrl_usb2_vbus: usb2vbusgrp {
fsl,pins =
- <MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x19>; /* SODIMM 185 */
+ <MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14 0x106>; /* SODIMM 185 */
};
/* On-module Wi-Fi */
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
index bb916a0948a8..7a6e6221f421 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
@@ -123,6 +123,7 @@
A53_L2: l2-cache0 {
compatible = "cache";
+ cache-unified;
cache-level = <2>;
cache-size = <0x80000>;
cache-line-size = <64>;
@@ -441,10 +442,10 @@
};
};
- anatop: anatop@30360000 {
- compatible = "fsl,imx8mp-anatop", "fsl,imx8mm-anatop",
- "syscon";
+ anatop: clock-controller@30360000 {
+ compatible = "fsl,imx8mp-anatop", "fsl,imx8mm-anatop";
reg = <0x30360000 0x10000>;
+ #clock-cells = <1>;
};
snvs: snvs@30370000 {
@@ -631,6 +632,14 @@
reg = <IMX8MP_POWER_DOMAIN_VPU_VC8000E>;
clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>;
};
+
+ pgc_mlmix: power-domain@24 {
+ #power-domain-cells = <0>;
+ reg = <IMX8MP_POWER_DOMAIN_MLMIX>;
+ clocks = <&clk IMX8MP_CLK_ML_AXI>,
+ <&clk IMX8MP_CLK_ML_AHB>,
+ <&clk IMX8MP_CLK_NPU_ROOT>;
+ };
};
};
};
@@ -705,12 +714,15 @@
ecspi1: spi@30820000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+ compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
reg = <0x30820000 0x10000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_ECSPI1_ROOT>,
<&clk IMX8MP_CLK_ECSPI1_ROOT>;
clock-names = "ipg", "per";
+ assigned-clock-rates = <80000000>;
+ assigned-clocks = <&clk IMX8MP_CLK_ECSPI1>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>;
dma-names = "rx", "tx";
status = "disabled";
@@ -719,12 +731,15 @@
ecspi2: spi@30830000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+ compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
reg = <0x30830000 0x10000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_ECSPI2_ROOT>,
<&clk IMX8MP_CLK_ECSPI2_ROOT>;
clock-names = "ipg", "per";
+ assigned-clock-rates = <80000000>;
+ assigned-clocks = <&clk IMX8MP_CLK_ECSPI2>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>;
dma-names = "rx", "tx";
status = "disabled";
@@ -733,12 +748,15 @@
ecspi3: spi@30840000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+ compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
reg = <0x30840000 0x10000>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_ECSPI3_ROOT>,
<&clk IMX8MP_CLK_ECSPI3_ROOT>;
clock-names = "ipg", "per";
+ assigned-clock-rates = <80000000>;
+ assigned-clocks = <&clk IMX8MP_CLK_ECSPI3>;
+ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>;
dma-names = "rx", "tx";
status = "disabled";
@@ -1063,11 +1081,11 @@
noc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-200M {
+ opp-200000000 {
opp-hz = /bits/ 64 <200000000>;
};
- opp-1000M {
+ opp-1000000000 {
opp-hz = /bits/ 64 <1000000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
index 82387b9cb800..78937910f403 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
@@ -46,6 +46,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ off-on-delay-us = <20000>;
enable-active-high;
};
@@ -163,22 +164,22 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
/*
* On imx8mq B0 PLL can't be bypassed so low bus is 166M
*/
- opp-166M {
+ opp-166000000 {
opp-hz = /bits/ 64 <166935483>;
};
- opp-800M {
+ opp-800000000 {
opp-hz = /bits/ 64 <800000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
index 6445c6b90b5b..4c8904fba1c1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
@@ -7,6 +7,7 @@
#include "dt-bindings/input/input.h"
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/leds/common.h>
#include "dt-bindings/pwm/pwm.h"
#include "dt-bindings/usb/pd.h"
#include "imx8mq.dtsi"
@@ -61,14 +62,13 @@
};
leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_gpio_leds>;
+ compatible = "pwm-leds";
led1 {
- label = "LED 1";
- gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
- default-state = "off";
+ function = LED_FUNCTION_STATUS;
+ color = <LED_COLOR_ID_RED>;
+ max-brightness = <248>;
+ pwms = <&pwm2 0 50000 0>;
};
};
@@ -615,9 +615,9 @@
>;
};
- pinctrl_gpio_leds: gpioledgrp {
+ pinctrl_pwm_led: pwmledgrp {
fsl,pins = <
- MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x16
+ MX8MQ_IOMUXC_GPIO1_IO13_PWM2_OUT 0x16
>;
};
@@ -920,6 +920,12 @@
status = "okay";
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm_led>;
+ status = "okay";
+};
+
&snvs_pwrkey {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
index ae08556b2ef2..ddf0e330dc7c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
@@ -311,15 +311,15 @@
ddrc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-25M {
+ opp-25000000 {
opp-hz = /bits/ 64 <25000000>;
};
- opp-100M {
+ opp-100000000 {
opp-hz = /bits/ 64 <100000000>;
};
- opp-800M {
+ opp-800000000 {
opp-hz = /bits/ 64 <800000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi
index 802ad6e5cef6..9a95e30fb42d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi
@@ -220,12 +220,14 @@
reg = <0x53>;
pagesize = <16>;
read-only;
+ vcc-supply = <&reg_vcc3v3>;
};
eeprom0: eeprom@57 {
compatible = "atmel,24c64";
reg = <0x57>;
pagesize = <32>;
+ vcc-supply = <&reg_vcc3v3>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index 19eaa523564d..7ce99c084e54 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -179,6 +179,7 @@
A53_L2: l2-cache0 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -605,10 +606,11 @@
};
};
- anatop: syscon@30360000 {
- compatible = "fsl,imx8mq-anatop", "syscon";
+ anatop: clock-controller@30360000 {
+ compatible = "fsl,imx8mq-anatop";
reg = <0x30360000 0x10000>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #clock-cells = <1>;
};
snvs: snvs@30370000 {
@@ -1184,7 +1186,7 @@
};
csi1: csi@30a90000 {
- compatible = "fsl,imx8mq-csi", "fsl,imx7-csi";
+ compatible = "fsl,imx8mq-csi";
reg = <0x30a90000 0x10000>;
interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MQ_CLK_CSI1_ROOT>;
@@ -1236,7 +1238,7 @@
};
csi2: csi@30b80000 {
- compatible = "fsl,imx8mq-csi", "fsl,imx7-csi";
+ compatible = "fsl,imx8mq-csi";
reg = <0x30b80000 0x10000>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MQ_CLK_CSI2_ROOT>;
@@ -1356,15 +1358,15 @@
noc_opp_table: opp-table {
compatible = "operating-points-v2";
- opp-133M {
+ opp-133000000 {
opp-hz = /bits/ 64 <133333333>;
};
- opp-400M {
+ opp-400000000 {
opp-hz = /bits/ 64 <400000000>;
};
- opp-800M {
+ opp-800000000 {
opp-hz = /bits/ 64 <800000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi
index 669aa14ce9f7..b483134f84d1 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-lsio.dtsi
@@ -6,30 +6,68 @@
&lsio_gpio0 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 0 6>,
+ <&iomuxc 6 7 22>,
+ <&iomuxc 28 36 4>;
};
&lsio_gpio1 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 40 4>,
+ <&iomuxc 4 50 12>,
+ <&iomuxc 16 63 8>,
+ <&iomuxc 24 72 8>;
};
&lsio_gpio2 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 80 4>,
+ <&iomuxc 4 85 18>,
+ <&iomuxc 22 104 10>;
};
&lsio_gpio3 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 114 2>,
+ <&iomuxc 2 117 16>,
+ <&iomuxc 18 141 1>,
+ <&iomuxc 19 140 1>,
+ <&iomuxc 20 139 1>,
+ <&iomuxc 21 138 1>,
+ <&iomuxc 22 137 1>,
+ <&iomuxc 23 136 1>,
+ <&iomuxc 24 135 1>,
+ <&iomuxc 25 134 1>,
+ <&iomuxc 26 142 3>,
+ <&iomuxc 29 146 3>;
};
&lsio_gpio4 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 149 3>,
+ <&iomuxc 3 153 4>,
+ <&iomuxc 7 158 6>,
+ <&iomuxc 13 165 6>,
+ <&iomuxc 19 172 8>,
+ <&iomuxc 27 198 5>;
};
&lsio_gpio5 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 203 1>,
+ <&iomuxc 1 205 2>,
+ <&iomuxc 3 210 11>,
+ <&iomuxc 14 223 3>,
+ <&iomuxc 17 227 2>,
+ <&iomuxc 19 230 5>,
+ <&iomuxc 24 236 6>,
+ <&iomuxc 30 243 2>;
};
&lsio_gpio6 {
compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 245 10>,
+ <&iomuxc 10 256 12>;
};
&lsio_gpio7 {
diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
index c9c2b6536233..41ce8336f29e 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
@@ -136,6 +136,7 @@
A53_L2: l2-cache0 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
@@ -144,6 +145,7 @@
A72_L2: l2-cache1 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x100000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi
index a08e70fb7c7a..7c334b93db3b 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi
@@ -3,7 +3,7 @@
* Copyright 2019 Toradex
*/
-#include "dt-bindings/input/linux-event-codes.h"
+#include <dt-bindings/input/linux-event-codes.h>
/ {
aliases {
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi
index 8e2152c6eb88..8f722b1dd078 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-lsio.dtsi
@@ -6,26 +6,51 @@
&lsio_gpio0 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 1 56 12>,
+ <&iomuxc 13 69 4>,
+ <&iomuxc 19 75 4>,
+ <&iomuxc 24 80 1>,
+ <&iomuxc 25 82 7>;
};
&lsio_gpio1 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 89 9>,
+ <&iomuxc 9 99 16>,
+ <&iomuxc 25 116 7>;
};
&lsio_gpio2 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 123 1>,
+ <&iomuxc 1 126 2>,
+ <&iomuxc 3 129 1>;
};
&lsio_gpio3 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 146 4>,
+ <&iomuxc 4 151 13>,
+ <&iomuxc 17 165 8>;
};
&lsio_gpio4 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 0 3>,
+ <&iomuxc 3 4 4>,
+ <&iomuxc 7 9 6>,
+ <&iomuxc 13 16 6>,
+ <&iomuxc 19 23 2>,
+ <&iomuxc 21 26 2>,
+ <&iomuxc 23 30 6>,
+ <&iomuxc 29 37 3>;
};
&lsio_gpio5 {
compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
+ gpio-ranges = <&iomuxc 0 40 3>,
+ <&iomuxc 3 44 6>,
+ <&iomuxc 9 51 3>;
};
&lsio_gpio6 {
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
index f4ea18bb95ab..85c0b1d2bac5 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
@@ -127,6 +127,7 @@
A35_L2: l2-cache0 {
compatible = "cache";
cache-level = <2>;
+ cache-unified;
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <1024>;
diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 06ce5f19aa8a..32193a43ff49 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -51,6 +51,7 @@
A35_L2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx93-pinfunc.h b/arch/arm64/boot/dts/freescale/imx93-pinfunc.h
index 4298a145f8a9..4298a145f8a9 100755..100644
--- a/arch/arm64/boot/dts/freescale/imx93-pinfunc.h
+++ b/arch/arm64/boot/dts/freescale/imx93-pinfunc.h
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 0247866fc86b..5d79663b3b84 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -17,6 +17,10 @@
#size-cells = <2>;
aliases {
+ gpio0 = &gpio1;
+ gpio1 = &gpio2;
+ gpio2 = &gpio3;
+ gpio3 = &gpio4;
i2c0 = &lpi2c1;
i2c1 = &lpi2c2;
i2c2 = &lpi2c3;
@@ -135,6 +139,7 @@
compatible = "fsl,imx93-mu", "fsl,imx8ulp-mu";
reg = <0x44230000 0x10000>;
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_MU1_B_GATE>;
#mbox-cells = <2>;
status = "disabled";
};
@@ -145,6 +150,15 @@
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc_24m>;
clock-names = "per";
+ nxp,no-divider;
+ };
+
+ tpm2: pwm@44320000 {
+ compatible = "fsl,imx7ulp-pwm";
+ reg = <0x44320000 0x10000>;
+ clocks = <&clk IMX93_CLK_TPM2_GATE>;
+ #pwm-cells = <3>;
+ status = "disabled";
};
lpi2c1: i2c@44340000 {
@@ -270,10 +284,35 @@
compatible = "fsl,imx93-mu", "fsl,imx8ulp-mu";
reg = <0x42440000 0x10000>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_MU2_B_GATE>;
#mbox-cells = <2>;
status = "disabled";
};
+ tpm4: pwm@424f0000 {
+ compatible = "fsl,imx7ulp-pwm";
+ reg = <0x424f0000 0x10000>;
+ clocks = <&clk IMX93_CLK_TPM4_GATE>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ tpm5: pwm@42500000 {
+ compatible = "fsl,imx7ulp-pwm";
+ reg = <0x42500000 0x10000>;
+ clocks = <&clk IMX93_CLK_TPM5_GATE>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ tpm6: pwm@42510000 {
+ compatible = "fsl,imx7ulp-pwm";
+ reg = <0x42510000 0x10000>;
+ clocks = <&clk IMX93_CLK_TPM6_GATE>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
lpi2c3: i2c@42530000 {
compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
reg = <0x42530000 0x10000>;
@@ -294,6 +333,30 @@
status = "disabled";
};
+ lpspi3: spi@42550000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x42550000 0x10000>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI3_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
+ lpspi4: spi@42560000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x42560000 0x10000>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI4_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
lpuart3: serial@42570000 {
compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
reg = <0x42570000 0x1000>;
@@ -388,6 +451,54 @@
status = "disabled";
};
+ lpspi5: spi@426f0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x426f0000 0x10000>;
+ interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI5_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
+ lpspi6: spi@42700000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x42700000 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI6_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
+ lpspi7: spi@42710000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x42710000 0x10000>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI7_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
+ lpspi8: spi@42720000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
+ reg = <0x42720000 0x10000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPSPI8_GATE>,
+ <&clk IMX93_CLK_BUS_WAKEUP>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+
};
aips3: bus@42800000 {
diff --git a/arch/arm64/boot/dts/freescale/mba8mx.dtsi b/arch/arm64/boot/dts/freescale/mba8mx.dtsi
index 104bdd4e437a..daa37adeff3b 100644
--- a/arch/arm64/boot/dts/freescale/mba8mx.dtsi
+++ b/arch/arm64/boot/dts/freescale/mba8mx.dtsi
@@ -215,6 +215,7 @@
compatible = "nxp,se97b", "atmel,24c02";
reg = <0x57>;
pagesize = <16>;
+ vcc-supply = <&reg_vcc_3v3>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 824d401e7a2c..d8c82da88ca0 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -52,10 +52,12 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/s32v234.dtsi b/arch/arm64/boot/dts/freescale/s32v234.dtsi
index ba0b5305d481..3e306218d533 100644
--- a/arch/arm64/boot/dts/freescale/s32v234.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32v234.dtsi
@@ -61,10 +61,12 @@
cluster0_l2_cache: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2_cache: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
index 8343d0cedde3..a57f35eb5ef6 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
@@ -203,10 +203,12 @@
A53_L2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
A73_L2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index ae0a7cfeeb47..f6d3202b0d1a 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -186,10 +186,12 @@
CLUSTER0_L2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
CLUSTER1_L2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
index 7b2abd10d3d6..5b2b1bfd0d2a 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -211,18 +211,22 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-level = <2>;
};
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index 2f8b03b0d365..291c2ee38288 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -211,18 +211,22 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-level = <2>;
};
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
index 1a16662f8867..b8746fb959b5 100644
--- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
@@ -842,66 +842,82 @@
cluster0_l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
cluster1_l2: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
};
cluster2_l2: l2-cache2 {
compatible = "cache";
+ cache-level = <2>;
};
cluster3_l2: l2-cache3 {
compatible = "cache";
+ cache-level = <2>;
};
cluster4_l2: l2-cache4 {
compatible = "cache";
+ cache-level = <2>;
};
cluster5_l2: l2-cache5 {
compatible = "cache";
+ cache-level = <2>;
};
cluster6_l2: l2-cache6 {
compatible = "cache";
+ cache-level = <2>;
};
cluster7_l2: l2-cache7 {
compatible = "cache";
+ cache-level = <2>;
};
cluster8_l2: l2-cache8 {
compatible = "cache";
+ cache-level = <2>;
};
cluster9_l2: l2-cache9 {
compatible = "cache";
+ cache-level = <2>;
};
cluster10_l2: l2-cache10 {
compatible = "cache";
+ cache-level = <2>;
};
cluster11_l2: l2-cache11 {
compatible = "cache";
+ cache-level = <2>;
};
cluster12_l2: l2-cache12 {
compatible = "cache";
+ cache-level = <2>;
};
cluster13_l2: l2-cache13 {
compatible = "cache";
+ cache-level = <2>;
};
cluster14_l2: l2-cache14 {
compatible = "cache";
+ cache-level = <2>;
};
cluster15_l2: l2-cache15 {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
index 7bbec8aafa62..849b46dd8098 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
@@ -313,6 +313,7 @@
<&clkmgr AGILEX_SDMMC_CLK>;
clock-names = "biu", "ciu";
iommus = <&smmu 5>;
+ altr,sysmgr-syscon = <&sysmgr 0x28 4>;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts
index 26cd3c121757..07c3f8876613 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts
@@ -83,6 +83,7 @@
cap-sd-highspeed;
broken-cd;
bus-width = <4>;
+ clk-phase-sd-hs = <0>, <135>;
};
&osc1 {
diff --git a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts
index 62c66e52b656..08c088571270 100644
--- a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts
+++ b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts
@@ -74,6 +74,7 @@
cap-sd-highspeed;
broken-cd;
bus-width = <4>;
+ clk-phase-sd-hs = <0>, <135>;
};
&osc1 {
diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
index 44ed6f963b75..7308f7b6b22c 100644
--- a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
@@ -49,6 +49,7 @@
l2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index ada164d423f3..cd0988317623 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -125,9 +125,12 @@
/delete-property/ mrvl,i2c-fast-mode;
status = "okay";
+ /* MCP7940MT-I/MNY RTC */
rtc@6f {
compatible = "microchip,mcp7940x";
reg = <0x6f>;
+ interrupt-parent = <&gpiosb>;
+ interrupts = <5 0>; /* GPIO2_5 */
};
};
@@ -136,6 +139,7 @@
pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
status = "okay";
reset-gpios = <&gpiosb 3 GPIO_ACTIVE_LOW>;
+ slot-power-limit-milliwatt = <10000>;
/*
* U-Boot port for Turris Mox has a bug which always expects that "ranges" DT property
* contains exactly 2 ranges with 3 (child) address cells, 2 (parent) address cells and
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index df152c72276b..e300145ad1a6 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -35,6 +35,11 @@
reg = <0 0x4000000 0 0x200000>;
no-map;
};
+
+ tee@4400000 {
+ reg = <0 0x4400000 0 0x1000000>;
+ no-map;
+ };
};
cpus {
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
index fcab5173fe67..990f70303fe6 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
@@ -51,6 +51,7 @@
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
index 3db427122f9e..a7b8e001cc9c 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
@@ -81,6 +81,7 @@
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
+ cache-level = <2>;
};
l2_1: l2-cache1 {
@@ -88,6 +89,7 @@
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
+ cache-level = <2>;
};
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi
index 68782f161f12..7740098fd108 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi
@@ -81,6 +81,7 @@
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
+ cache-level = <2>;
};
l2_1: l2-cache1 {
@@ -88,6 +89,7 @@
cache-size = <0x80000>;
cache-line-size = <64>;
cache-sets = <512>;
+ cache-level = <2>;
};
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi b/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi
index a06a0a889c43..4e6d29ad32eb 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi
@@ -41,6 +41,11 @@
reg = <0x0 0x4000000 0x0 0x200000>;
no-map;
};
+
+ tee@4400000 {
+ reg = <0 0x4400000 0 0x1000000>;
+ no-map;
+ };
};
AP_NAME {
diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 0ec90cb3ef28..813e735c5b96 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt2712-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6755-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6779-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6795-evb.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt6795-sony-xperia-m5.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-x20-dev.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt2712-evb.dts b/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
index 9b1af9c80130..d31a194124c9 100644
--- a/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
@@ -26,14 +26,14 @@
stdout-path = "serial0:921600n8";
};
- cpus_fixed_vproc0: fixedregulator@0 {
+ cpus_fixed_vproc0: regulator-vproc-buck0 {
compatible = "regulator-fixed";
regulator-name = "vproc_buck0";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
- cpus_fixed_vproc1: fixedregulator@1 {
+ cpus_fixed_vproc1: regulator-vproc-buck1 {
compatible = "regulator-fixed";
regulator-name = "vproc_buck1";
regulator-min-microvolt = <1000000>;
@@ -50,7 +50,7 @@
id-gpio = <&pio 14 GPIO_ACTIVE_HIGH>;
};
- usb_p0_vbus: regulator@2 {
+ usb_p0_vbus: regulator-usb-p0-vbus {
compatible = "regulator-fixed";
regulator-name = "p0_vbus";
regulator-min-microvolt = <5000000>;
@@ -59,7 +59,7 @@
enable-active-high;
};
- usb_p1_vbus: regulator@3 {
+ usb_p1_vbus: regulator-usb-p1-vbus {
compatible = "regulator-fixed";
regulator-name = "p1_vbus";
regulator-min-microvolt = <5000000>;
@@ -68,7 +68,7 @@
enable-active-high;
};
- usb_p2_vbus: regulator@4 {
+ usb_p2_vbus: regulator-usb-p2-vbus {
compatible = "regulator-fixed";
regulator-name = "p2_vbus";
regulator-min-microvolt = <5000000>;
@@ -77,7 +77,7 @@
enable-active-high;
};
- usb_p3_vbus: regulator@5 {
+ usb_p3_vbus: regulator-usb-p3-vbus {
compatible = "regulator-fixed";
regulator-name = "p3_vbus";
regulator-min-microvolt = <5000000>;
diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
index e6d7453e56e0..92212cddd37e 100644
--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
@@ -160,70 +160,70 @@
#clock-cells = <0>;
};
- clk26m: oscillator@0 {
+ clk26m: oscillator-26m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
clock-output-names = "clk26m";
};
- clk32k: oscillator@1 {
+ clk32k: oscillator-32k {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "clk32k";
};
- clkfpc: oscillator@2 {
+ clkfpc: oscillator-50m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <50000000>;
clock-output-names = "clkfpc";
};
- clkaud_ext_i_0: oscillator@3 {
+ clkaud_ext_i_0: oscillator-aud0 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <6500000>;
clock-output-names = "clkaud_ext_i_0";
};
- clkaud_ext_i_1: oscillator@4 {
+ clkaud_ext_i_1: oscillator-aud1 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <196608000>;
clock-output-names = "clkaud_ext_i_1";
};
- clkaud_ext_i_2: oscillator@5 {
+ clkaud_ext_i_2: oscillator-aud2 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <180633600>;
clock-output-names = "clkaud_ext_i_2";
};
- clki2si0_mck_i: oscillator@6 {
+ clki2si0_mck_i: oscillator-i2s0 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <30000000>;
clock-output-names = "clki2si0_mck_i";
};
- clki2si1_mck_i: oscillator@7 {
+ clki2si1_mck_i: oscillator-i2s1 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <30000000>;
clock-output-names = "clki2si1_mck_i";
};
- clki2si2_mck_i: oscillator@8 {
+ clki2si2_mck_i: oscillator-i2s2 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <30000000>;
clock-output-names = "clki2si2_mck_i";
};
- clktdmin_mclk_i: oscillator@9 {
+ clktdmin_mclk_i: oscillator-mclk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <30000000>;
@@ -266,7 +266,7 @@
reg = <0 0x10005000 0 0x1000>;
};
- pio: pinctrl@10005000 {
+ pio: pinctrl@1000b000 {
compatible = "mediatek,mt2712-pinctrl";
reg = <0 0x1000b000 0 0x1000>;
mediatek,pctl-regmap = <&syscfg_pctl_a>;
@@ -766,9 +766,9 @@
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_0>,
<&pericfg CLK_PERI_MSDC50_0_HCLK_EN>,
- <&pericfg CLK_PERI_MSDC30_0_QTR_EN>,
- <&pericfg CLK_PERI_MSDC50_0_EN>;
- clock-names = "source", "hclk", "bus_clk", "source_cg";
+ <&pericfg CLK_PERI_MSDC50_0_EN>,
+ <&pericfg CLK_PERI_MSDC30_0_QTR_EN>;
+ clock-names = "source", "hclk", "source_cg", "bus_clk";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt6779.dtsi b/arch/arm64/boot/dts/mediatek/mt6779.dtsi
index 9bdf5145966c..5c579e88e749 100644
--- a/arch/arm64/boot/dts/mediatek/mt6779.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6779.dtsi
@@ -88,14 +88,14 @@
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW 0>;
};
- clk26m: oscillator@0 {
+ clk26m: oscillator-26m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
clock-output-names = "clk26m";
};
- clk32k: oscillator@1 {
+ clk32k: oscillator-32k {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
@@ -117,7 +117,7 @@
compatible = "simple-bus";
ranges;
- gic: interrupt-controller@0c000000 {
+ gic: interrupt-controller@c000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <4>;
interrupt-parent = <&gic>;
@@ -138,7 +138,7 @@
};
- sysirq: intpol-controller@0c53a650 {
+ sysirq: intpol-controller@c53a650 {
compatible = "mediatek,mt6779-sysirq",
"mediatek,mt6577-sysirq";
interrupt-controller;
@@ -160,7 +160,7 @@
};
pio: pinctrl@10005000 {
- compatible = "mediatek,mt6779-pinctrl", "syscon";
+ compatible = "mediatek,mt6779-pinctrl";
reg = <0 0x10005000 0 0x1000>,
<0 0x11c20000 0 0x1000>,
<0 0x11d10000 0 0x1000>,
diff --git a/arch/arm64/boot/dts/mediatek/mt6795-sony-xperia-m5.dts b/arch/arm64/boot/dts/mediatek/mt6795-sony-xperia-m5.dts
new file mode 100644
index 000000000000..d3415527d389
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt6795-sony-xperia-m5.dts
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Collabora Ltd
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+/dts-v1/;
+#include "mt6795.dtsi"
+
+/ {
+ model = "Sony Xperia M5";
+ compatible = "sony,xperia-m5", "mediatek,mt6795";
+ chassis-type = "handset";
+
+ aliases {
+ mmc0 = &mmc0;
+ mmc1 = &mmc1;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ memory@40000000 {
+ device_type = "memory";
+ reg = <0 0x40000000 0 0x1e800000>;
+ };
+
+ reserved_memory: reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* 128 KiB reserved for ARM Trusted Firmware (BL31) */
+ bl31_secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
+ no-map;
+ };
+
+ /* preloader and bootloader regions cannot be touched */
+ preloader-region@44800000 {
+ reg = <0 0x44800000 0 0x100000>;
+ no-map;
+ };
+
+ bootloader-region@46000000 {
+ reg = <0 0x46000000 0 0x400000>;
+ no-map;
+ };
+ };
+};
+
+&pio {
+ uart0_pins: uart0-pins {
+ pins-rx {
+ pinmux = <PINMUX_GPIO113__FUNC_URXD0>;
+ bias-pull-up;
+ input-enable;
+ };
+ pins-tx {
+ pinmux = <PINMUX_GPIO114__FUNC_UTXD0>;
+ output-high;
+ };
+ };
+
+ uart2_pins: uart2-pins {
+ pins-rx {
+ pinmux = <PINMUX_GPIO31__FUNC_URXD2>;
+ bias-pull-up;
+ input-enable;
+ };
+ pins-tx {
+ pinmux = <PINMUX_GPIO32__FUNC_UTXD2>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+};
+
+&uart2 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
index 46f0e54be766..bb575837e4ce 100644
--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
@@ -6,7 +6,9 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/mediatek,mt6795-clk.h>
#include <dt-bindings/pinctrl/mt6795-pinfunc.h>
+#include <dt-bindings/reset/mediatek,mt6795-resets.h>
/ {
compatible = "mediatek,mt6795";
@@ -192,6 +194,26 @@
compatible = "simple-bus";
ranges;
+ topckgen: syscon@10000000 {
+ compatible = "mediatek,mt6795-topckgen", "syscon";
+ reg = <0 0x10000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ infracfg: syscon@10001000 {
+ compatible = "mediatek,mt6795-infracfg", "syscon";
+ reg = <0 0x10001000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pericfg: syscon@10003000 {
+ compatible = "mediatek,mt6795-pericfg", "syscon";
+ reg = <0 0x10003000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pio: pinctrl@10005000 {
compatible = "mediatek,mt6795-pinctrl";
reg = <0 0x10005000 0 0x1000>, <0 0x1000b000 0 0x1000>;
@@ -292,7 +314,10 @@
"mediatek,mt6577-uart";
reg = <0 0x11002000 0 0x400>;
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&clk26m>;
+ clocks = <&pericfg CLK_PERI_UART0_SEL>, <&pericfg CLK_PERI_UART0>;
+ clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -301,16 +326,48 @@
"mediatek,mt6577-uart";
reg = <0 0x11003000 0 0x400>;
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&clk26m>;
+ clocks = <&pericfg CLK_PERI_UART1_SEL>, <&pericfg CLK_PERI_UART1>;
+ clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
+ apdma: dma-controller@11000380 {
+ compatible = "mediatek,mt6795-uart-dma",
+ "mediatek,mt6577-uart-dma";
+ reg = <0 0x11000380 0 0x60>,
+ <0 0x11000400 0 0x60>,
+ <0 0x11000480 0 0x60>,
+ <0 0x11000500 0 0x60>,
+ <0 0x11000580 0 0x60>,
+ <0 0x11000600 0 0x60>,
+ <0 0x11000680 0 0x60>,
+ <0 0x11000700 0 0x60>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>;
+ dma-requests = <8>;
+ clocks = <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "apdma";
+ mediatek,dma-33bits;
+ #dma-cells = <1>;
+ };
+
uart2: serial@11004000 {
compatible = "mediatek,mt6795-uart",
"mediatek,mt6577-uart";
reg = <0 0x11004000 0 0x400>;
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&clk26m>;
+ clocks = <&pericfg CLK_PERI_UART2_SEL>, <&pericfg CLK_PERI_UART2>;
+ clock-names = "baud", "bus";
+ dmas = <&apdma 4>, <&apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -319,7 +376,51 @@
"mediatek,mt6577-uart";
reg = <0 0x11005000 0 0x400>;
interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&clk26m>;
+ clocks = <&pericfg CLK_PERI_UART3_SEL>, <&pericfg CLK_PERI_UART3>;
+ clock-names = "baud", "bus";
+ dmas = <&apdma 6>, <&apdma 7>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ mmc0: mmc@11230000 {
+ compatible = "mediatek,mt6795-mmc";
+ reg = <0 0x11230000 0 0x1000>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_0>,
+ <&topckgen CLK_TOP_MSDC50_0_H_SEL>,
+ <&topckgen CLK_TOP_MSDC50_0_SEL>;
+ clock-names = "source", "hclk", "source_cg";
+ status = "disabled";
+ };
+
+ mmc1: mmc@11240000 {
+ compatible = "mediatek,mt6795-mmc";
+ reg = <0 0x11240000 0 0x1000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_1>,
+ <&topckgen CLK_TOP_AXI_SEL>;
+ clock-names = "source", "hclk";
+ status = "disabled";
+ };
+
+ mmc2: mmc@11250000 {
+ compatible = "mediatek,mt6795-mmc";
+ reg = <0 0x11250000 0 0x1000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_2>,
+ <&topckgen CLK_TOP_AXI_SEL>;
+ clock-names = "source", "hclk";
+ status = "disabled";
+ };
+
+ mmc3: mmc@11260000 {
+ compatible = "mediatek,mt6795-mmc";
+ reg = <0 0x11260000 0 0x1000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_3>,
+ <&topckgen CLK_TOP_AXI_SEL>;
+ clock-names = "source", "hclk";
status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt6797.dtsi b/arch/arm64/boot/dts/mediatek/mt6797.dtsi
index 15616231022a..c3677d77e0a4 100644
--- a/arch/arm64/boot/dts/mediatek/mt6797.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6797.dtsi
@@ -95,7 +95,7 @@
};
};
- clk26m: oscillator@0 {
+ clk26m: oscillator-26m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
index d3f9eab2b784..af3fe61e4093 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
@@ -235,7 +235,6 @@
bus-width = <4>;
max-frequency = <50000000>;
cap-sd-highspeed;
- r_smpl = <1>;
cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>;
vmmc-supply = <&reg_3p3v>;
vqmmc-supply = <&reg_3p3v>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
index 36722cabe626..b74e774c6eba 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
@@ -208,7 +208,6 @@
bus-width = <4>;
max-frequency = <50000000>;
cap-sd-highspeed;
- r_smpl = <1>;
cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>;
vmmc-supply = <&reg_3p3v>;
vqmmc-supply = <&reg_3p3v>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
index afe37b702eef..9b83925893b7 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
@@ -9,7 +9,7 @@
/ {
model = "MediaTek MT7986a RFB";
- compatible = "mediatek,mt7986a-rfb";
+ compatible = "mediatek,mt7986a-rfb", "mediatek,mt7986a";
aliases {
serial0 = &uart0;
@@ -25,6 +25,10 @@
};
};
+&crypto {
+ status = "okay";
+};
+
&eth {
status = "okay";
@@ -54,6 +58,88 @@
};
};
+&pio {
+ spi_flash_pins: spi-flash-pins {
+ mux {
+ function = "spi";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ spic_pins: spic-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_2";
+ };
+ };
+
+ uart1_pins: uart1-pins {
+ mux {
+ function = "uart";
+ groups = "uart1";
+ };
+ };
+
+ uart2_pins: uart2-pins {
+ mux {
+ function = "uart";
+ groups = "uart2";
+ };
+ };
+
+ wf_2g_5g_pins: wf-2g-5g-pins {
+ mux {
+ function = "wifi";
+ groups = "wf_2g", "wf_5g";
+ };
+ conf {
+ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+ "WF1_TOP_CLK", "WF1_TOP_DATA";
+ drive-strength = <4>;
+ };
+ };
+
+ wf_dbdc_pins: wf-dbdc-pins {
+ mux {
+ function = "wifi";
+ groups = "wf_dbdc";
+ };
+ conf {
+ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+ "WF0_TOP_CLK", "WF0_TOP_DATA";
+ drive-strength = <4>;
+ };
+ };
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+ spi_nand: spi_nand@0 {
+ compatible = "spi-nand";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spic_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+};
+
&switch {
ports {
#address-cells = <1>;
@@ -121,50 +207,3 @@
pinctrl-0 = <&wf_2g_5g_pins>;
pinctrl-1 = <&wf_dbdc_pins>;
};
-
-&pio {
- uart1_pins: uart1-pins {
- mux {
- function = "uart";
- groups = "uart1";
- };
- };
-
- uart2_pins: uart2-pins {
- mux {
- function = "uart";
- groups = "uart2";
- };
- };
-
- wf_2g_5g_pins: wf-2g-5g-pins {
- mux {
- function = "wifi";
- groups = "wf_2g", "wf_5g";
- };
- conf {
- pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
- "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
- "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
- "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
- "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
- "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
- "WF1_TOP_CLK", "WF1_TOP_DATA";
- drive-strength = <4>;
- };
- };
-
- wf_dbdc_pins: wf-dbdc-pins {
- mux {
- function = "wifi";
- groups = "wf_dbdc";
- };
- conf {
- pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
- "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
- "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
- "WF0_TOP_CLK", "WF0_TOP_DATA";
- drive-strength = <4>;
- };
- };
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index 72e0d9722e07..ed703025a7cc 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -10,11 +10,12 @@
#include <dt-bindings/reset/mt7986-resets.h>
/ {
+ compatible = "mediatek,mt7986a";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
- clk40m: oscillator@0 {
+ clk40m: oscillator-40m {
compatible = "fixed-clock";
clock-frequency = <40000000>;
#clock-cells = <0>;
@@ -112,6 +113,12 @@
#clock-cells = <1>;
};
+ wed_pcie: wed-pcie@10003000 {
+ compatible = "mediatek,mt7986-wed-pcie",
+ "syscon";
+ reg = <0 0x10003000 0 0x10>;
+ };
+
topckgen: topckgen@1001b000 {
compatible = "mediatek,mt7986-topckgen", "syscon";
reg = <0 0x1001B000 0 0x1000>;
@@ -168,7 +175,7 @@
#clock-cells = <1>;
};
- trng: trng@1020f000 {
+ trng: rng@1020f000 {
compatible = "mediatek,mt7986-rng",
"mediatek,mt7623-rng";
reg = <0 0x1020f000 0 0x100>;
@@ -177,6 +184,21 @@
status = "disabled";
};
+ crypto: crypto@10320000 {
+ compatible = "inside-secure,safexcel-eip97";
+ reg = <0 0x10320000 0 0x40000>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ring0", "ring1", "ring2", "ring3";
+ clocks = <&infracfg CLK_INFRA_EIP97_CK>;
+ clock-names = "infra_eip97_ck";
+ assigned-clocks = <&topckgen CLK_TOP_EIP_B_SEL>;
+ assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>;
+ status = "disabled";
+ };
+
uart0: serial@11002000 {
compatible = "mediatek,mt7986-uart",
"mediatek,mt6577-uart";
@@ -218,6 +240,48 @@
status = "disabled";
};
+ i2c0: i2c@11008000 {
+ compatible = "mediatek,mt7986-i2c";
+ reg = <0 0x11008000 0 0x90>,
+ <0 0x10217080 0 0x80>;
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ clock-div = <5>;
+ clocks = <&infracfg CLK_INFRA_I2C0_CK>,
+ <&infracfg CLK_INFRA_AP_DMA_CK>;
+ clock-names = "main", "dma";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi0: spi@1100a000 {
+ compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0 0x1100a000 0 0x100>;
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&topckgen CLK_TOP_MPLL_D2>,
+ <&topckgen CLK_TOP_SPI_SEL>,
+ <&infracfg CLK_INFRA_SPI0_CK>,
+ <&infracfg CLK_INFRA_SPI0_HCK_CK>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk";
+ status = "disabled";
+ };
+
+ spi1: spi@1100b000 {
+ compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0 0x1100b000 0 0x100>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&topckgen CLK_TOP_MPLL_D2>,
+ <&topckgen CLK_TOP_SPIM_MST_SEL>,
+ <&infracfg CLK_INFRA_SPI1_CK>,
+ <&infracfg CLK_INFRA_SPI1_HCK_CK>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk";
+ status = "disabled";
+ };
+
ethsys: syscon@15000000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -228,12 +292,6 @@
#reset-cells = <1>;
};
- wed_pcie: wed-pcie@10003000 {
- compatible = "mediatek,mt7986-wed-pcie",
- "syscon";
- reg = <0 0x10003000 0 0x10>;
- };
-
wed0: wed@15010000 {
compatible = "mediatek,mt7986-wed",
"syscon";
diff --git a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
index 3443013b5971..243760cd3011 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
@@ -9,7 +9,7 @@
/ {
model = "MediaTek MT7986b RFB";
- compatible = "mediatek,mt7986b-rfb";
+ compatible = "mediatek,mt7986b-rfb", "mediatek,mt7986b";
aliases {
serial0 = &uart0;
@@ -25,7 +25,7 @@
};
};
-&uart0 {
+&crypto {
status = "okay";
};
@@ -99,14 +99,21 @@
};
};
-&wifi {
- status = "okay";
- pinctrl-names = "default", "dbdc";
- pinctrl-0 = <&wf_2g_5g_pins>;
- pinctrl-1 = <&wf_dbdc_pins>;
-};
-
&pio {
+ spi_flash_pins: spi-flash-pins {
+ mux {
+ function = "spi";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ spic_pins: spic-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_2";
+ };
+ };
+
wf_2g_5g_pins: wf-2g-5g-pins {
mux {
function = "wifi";
@@ -138,3 +145,35 @@
};
};
};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+ spi_nand: spi_nand@0 {
+ compatible = "spi-nand";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spic_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&wifi {
+ status = "okay";
+ pinctrl-names = "default", "dbdc";
+ pinctrl-0 = <&wf_2g_5g_pins>;
+ pinctrl-1 = <&wf_dbdc_pins>;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
index 23923b9f8944..db5189664c29 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
@@ -5,6 +5,9 @@
*/
#include "mt7986a.dtsi"
+/ {
+ compatible = "mediatek,mt7986b";
+};
&pio {
compatible = "mediatek,mt7986b-pinctrl";
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
index b4b86bb1f1a7..7fc4c592a908 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
@@ -221,11 +221,6 @@
};
};
-&afe {
- i2s3-share = "I2S2";
- i2s0-share = "I2S5";
-};
-
&auxadc {
status = "okay";
};
@@ -378,7 +373,6 @@
mmc-pwrseq = <&wifi_pwrseq>;
bus-width = <4>;
max-frequency = <200000000>;
- drv-type = <2>;
cap-sd-highspeed;
sd-uhs-sdr50;
sd-uhs-sdr104;
diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi
index 64693c17af9e..c326aeb33a10 100644
--- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi
@@ -198,16 +198,19 @@
l2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l2_1: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l3_0: l3-cache {
compatible = "cache";
+ cache-level = <3>;
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
index 6b20376191a7..424fc89cc6f7 100644
--- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
@@ -169,16 +169,19 @@
l2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l2_1: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l3_0: l3-cache {
compatible = "cache";
+ cache-level = <3>;
};
idle-states {
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
index 9b62e161db26..560103e29017 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
@@ -120,6 +120,78 @@
};
};
+&dp_intf0 {
+ status = "okay";
+
+ port {
+ dp_intf0_out: endpoint {
+ remote-endpoint = <&edp_in>;
+ };
+ };
+};
+
+&dp_intf1 {
+ status = "okay";
+
+ port {
+ dp_intf1_out: endpoint {
+ remote-endpoint = <&dptx_in>;
+ };
+ };
+};
+
+&edp_tx {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&edptx_pins_default>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ edp_in: endpoint {
+ remote-endpoint = <&dp_intf0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ edp_out: endpoint {
+ data-lanes = <0 1 2 3>;
+ };
+ };
+ };
+};
+
+&dp_tx {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dptx_pin>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dptx_in: endpoint {
+ remote-endpoint = <&dp_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dptx_out: endpoint {
+ data-lanes = <0 1 2 3>;
+ };
+ };
+ };
+};
+
&i2c0 {
status = "okay";
@@ -479,6 +551,20 @@
};
};
+ edptx_pins_default: edptx-default-pins {
+ pins-cmd-dat {
+ pinmux = <PINMUX_GPIO7__FUNC_EDP_TX_HPD>;
+ bias-pull-up;
+ };
+ };
+
+ dptx_pin: dptx-default-pins {
+ pins-cmd-dat {
+ pinmux = <PINMUX_GPIO18__FUNC_DP_TX_HPD>;
+ bias-pull-up;
+ };
+ };
+
i2c0_pins: i2c0-default-pins {
pins-bus {
pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
index 905d1a90b406..5d31536f4c48 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
@@ -13,6 +13,7 @@
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/pinctrl/mt8195-pinfunc.h>
#include <dt-bindings/power/mt8195-power.h>
+#include <dt-bindings/reset/mt8195-resets.h>
/ {
compatible = "mediatek,mt8195";
@@ -36,7 +37,7 @@
enable-method = "psci";
performance-domains = <&performance 0>;
clock-frequency = <1701000000>;
- capacity-dmips-mhz = <578>;
+ capacity-dmips-mhz = <308>;
cpu-idle-states = <&cpu_off_l &cluster_off_l>;
next-level-cache = <&l2_0>;
#cooling-cells = <2>;
@@ -49,7 +50,7 @@
enable-method = "psci";
performance-domains = <&performance 0>;
clock-frequency = <1701000000>;
- capacity-dmips-mhz = <578>;
+ capacity-dmips-mhz = <308>;
cpu-idle-states = <&cpu_off_l &cluster_off_l>;
next-level-cache = <&l2_0>;
#cooling-cells = <2>;
@@ -62,7 +63,7 @@
enable-method = "psci";
performance-domains = <&performance 0>;
clock-frequency = <1701000000>;
- capacity-dmips-mhz = <578>;
+ capacity-dmips-mhz = <308>;
cpu-idle-states = <&cpu_off_l &cluster_off_l>;
next-level-cache = <&l2_0>;
#cooling-cells = <2>;
@@ -75,7 +76,7 @@
enable-method = "psci";
performance-domains = <&performance 0>;
clock-frequency = <1701000000>;
- capacity-dmips-mhz = <578>;
+ capacity-dmips-mhz = <308>;
cpu-idle-states = <&cpu_off_l &cluster_off_l>;
next-level-cache = <&l2_0>;
#cooling-cells = <2>;
@@ -213,16 +214,19 @@
l2_0: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l2_1: l2-cache1 {
compatible = "cache";
+ cache-level = <2>;
next-level-cache = <&l3_0>;
};
l3_0: l3-cache {
compatible = "cache";
+ cache-level = <3>;
};
};
@@ -1182,6 +1186,110 @@
status = "disabled";
};
+ pcie0: pcie@112f0000 {
+ compatible = "mediatek,mt8195-pcie",
+ "mediatek,mt8192-pcie";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ reg = <0 0x112f0000 0 0x4000>;
+ reg-names = "pcie-mac";
+ interrupts = <GIC_SPI 791 IRQ_TYPE_LEVEL_HIGH 0>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x81000000 0 0x20000000
+ 0x0 0x20000000 0 0x200000>,
+ <0x82000000 0 0x20200000
+ 0x0 0x20200000 0 0x3e00000>;
+
+ iommu-map = <0 &iommu_infra IOMMU_PORT_INFRA_PCIE0 0x2>;
+ iommu-map-mask = <0x0>;
+
+ clocks = <&infracfg_ao CLK_INFRA_AO_PCIE_PL_P_250M_P0>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_TL_26M>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_TL_96M>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_TL_32K>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_PERI_26M>,
+ <&pericfg_ao CLK_PERI_AO_PCIE_P0_MEM>;
+ clock-names = "pl_250m", "tl_26m", "tl_96m",
+ "tl_32k", "peri_26m", "peri_mem";
+ assigned-clocks = <&topckgen CLK_TOP_TL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4_D4>;
+
+ phys = <&pciephy>;
+ phy-names = "pcie-phy";
+
+ power-domains = <&spm MT8195_POWER_DOMAIN_PCIE_MAC_P0>;
+
+ resets = <&infracfg_ao MT8195_INFRA_RST2_PCIE_P0_SWRST>;
+ reset-names = "mac";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ <0 0 0 2 &pcie_intc0 1>,
+ <0 0 0 3 &pcie_intc0 2>,
+ <0 0 0 4 &pcie_intc0 3>;
+ status = "disabled";
+
+ pcie_intc0: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ pcie1: pcie@112f8000 {
+ compatible = "mediatek,mt8195-pcie",
+ "mediatek,mt8192-pcie";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ reg = <0 0x112f8000 0 0x4000>;
+ reg-names = "pcie-mac";
+ interrupts = <GIC_SPI 792 IRQ_TYPE_LEVEL_HIGH 0>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x81000000 0 0x24000000
+ 0x0 0x24000000 0 0x200000>,
+ <0x82000000 0 0x24200000
+ 0x0 0x24200000 0 0x3e00000>;
+
+ iommu-map = <0 &iommu_infra IOMMU_PORT_INFRA_PCIE1 0x2>;
+ iommu-map-mask = <0x0>;
+
+ clocks = <&infracfg_ao CLK_INFRA_AO_PCIE_PL_P_250M_P1>,
+ <&clk26m>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_TL_96M>,
+ <&clk26m>,
+ <&infracfg_ao CLK_INFRA_AO_PCIE_PERI_26M>,
+ /* Designer has connect pcie1 with peri_mem_p0 clock */
+ <&pericfg_ao CLK_PERI_AO_PCIE_P0_MEM>;
+ clock-names = "pl_250m", "tl_26m", "tl_96m",
+ "tl_32k", "peri_26m", "peri_mem";
+ assigned-clocks = <&topckgen CLK_TOP_TL_P1>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4_D4>;
+
+ phys = <&u3port1 PHY_TYPE_PCIE>;
+ phy-names = "pcie-phy";
+ power-domains = <&spm MT8195_POWER_DOMAIN_PCIE_MAC_P1>;
+
+ resets = <&infracfg_ao MT8195_INFRA_RST2_PCIE_P1_SWRST>;
+ reset-names = "mac";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+ <0 0 0 2 &pcie_intc1 1>,
+ <0 0 0 3 &pcie_intc1 2>,
+ <0 0 0 4 &pcie_intc1 3>;
+ status = "disabled";
+
+ pcie_intc1: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+
nor_flash: spi@1132c000 {
compatible = "mediatek,mt8195-nor",
"mediatek,mt8173-nor";
@@ -1241,6 +1349,37 @@
reg = <0x189 0x2>;
bits = <7 5>;
};
+ pciephy_rx_ln1: pciephy-rx-ln1@190,1 {
+ reg = <0x190 0x1>;
+ bits = <0 4>;
+ };
+ pciephy_tx_ln1_nmos: pciephy-tx-ln1-nmos@190,2 {
+ reg = <0x190 0x1>;
+ bits = <4 4>;
+ };
+ pciephy_tx_ln1_pmos: pciephy-tx-ln1-pmos@191,1 {
+ reg = <0x191 0x1>;
+ bits = <0 4>;
+ };
+ pciephy_rx_ln0: pciephy-rx-ln0@191,2 {
+ reg = <0x191 0x1>;
+ bits = <4 4>;
+ };
+ pciephy_tx_ln0_nmos: pciephy-tx-ln0-nmos@192,1 {
+ reg = <0x192 0x1>;
+ bits = <0 4>;
+ };
+ pciephy_tx_ln0_pmos: pciephy-tx-ln0-pmos@192,2 {
+ reg = <0x192 0x1>;
+ bits = <4 4>;
+ };
+ pciephy_glb_intr: pciephy-glb-intr@193 {
+ reg = <0x193 0x1>;
+ bits = <0 4>;
+ };
+ dp_calibration: dp-data@1ac {
+ reg = <0x1ac 0x10>;
+ };
};
u3phy2: t-phy@11c40000 {
@@ -1461,6 +1600,23 @@
};
};
+ pciephy: phy@11e80000 {
+ compatible = "mediatek,mt8195-pcie-phy";
+ reg = <0 0x11e80000 0 0x10000>;
+ reg-names = "sif";
+ nvmem-cells = <&pciephy_glb_intr>, <&pciephy_tx_ln0_pmos>,
+ <&pciephy_tx_ln0_nmos>, <&pciephy_rx_ln0>,
+ <&pciephy_tx_ln1_pmos>, <&pciephy_tx_ln1_nmos>,
+ <&pciephy_rx_ln1>;
+ nvmem-cell-names = "glb_intr", "tx_ln0_pmos",
+ "tx_ln0_nmos", "rx_ln0",
+ "tx_ln1_pmos", "tx_ln1_nmos",
+ "rx_ln1";
+ power-domains = <&spm MT8195_POWER_DOMAIN_PCIE_PHY>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
ufsphy: ufs-phy@11fa0000 {
compatible = "mediatek,mt8195-ufsphy", "mediatek,mt8183-ufsphy";
reg = <0 0x11fa0000 0 0xc000>;
@@ -1959,6 +2115,30 @@
power-domains = <&spm MT8195_POWER_DOMAIN_VENC>;
};
+ venc: video-codec@1a020000 {
+ compatible = "mediatek,mt8195-vcodec-enc";
+ reg = <0 0x1a020000 0 0x10000>;
+ iommus = <&iommu_vdo M4U_PORT_L19_VENC_RCPU>,
+ <&iommu_vdo M4U_PORT_L19_VENC_REC>,
+ <&iommu_vdo M4U_PORT_L19_VENC_BSDMA>,
+ <&iommu_vdo M4U_PORT_L19_VENC_SV_COMV>,
+ <&iommu_vdo M4U_PORT_L19_VENC_RD_COMV>,
+ <&iommu_vdo M4U_PORT_L19_VENC_CUR_LUMA>,
+ <&iommu_vdo M4U_PORT_L19_VENC_CUR_CHROMA>,
+ <&iommu_vdo M4U_PORT_L19_VENC_REF_LUMA>,
+ <&iommu_vdo M4U_PORT_L19_VENC_REF_CHROMA>;
+ interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH 0>;
+ mediatek,scp = <&scp>;
+ clocks = <&vencsys CLK_VENC_VENC>;
+ clock-names = "venc_sel";
+ assigned-clocks = <&topckgen CLK_TOP_VENC>;
+ assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4>;
+ power-domains = <&spm MT8195_POWER_DOMAIN_VENC>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ };
+
vencsys_core1: clock-controller@1b000000 {
compatible = "mediatek,mt8195-vencsys_core1";
reg = <0 0x1b000000 0 0x1000>;
@@ -2067,6 +2247,17 @@
mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0x4000 0x1000>;
};
+ dp_intf0: dp-intf@1c015000 {
+ compatible = "mediatek,mt8195-dp-intf";
+ reg = <0 0x1c015000 0 0x1000>;
+ interrupts = <GIC_SPI 657 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vdosys0 CLK_VDO0_DP_INTF0>,
+ <&vdosys0 CLK_VDO0_DP_INTF0_DP_INTF>,
+ <&apmixedsys CLK_APMIXED_TVDPLL1>;
+ clock-names = "engine", "pixel", "pll";
+ status = "disabled";
+ };
+
mutex: mutex@1c016000 {
compatible = "mediatek,mt8195-disp-mutex";
reg = <0 0x1c016000 0 0x1000>;
@@ -2155,5 +2346,39 @@
clock-names = "apb", "smi", "gals";
power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
};
+
+ dp_intf1: dp-intf@1c113000 {
+ compatible = "mediatek,mt8195-dp-intf";
+ reg = <0 0x1c113000 0 0x1000>;
+ interrupts = <GIC_SPI 513 IRQ_TYPE_LEVEL_HIGH 0>;
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
+ clocks = <&vdosys1 CLK_VDO1_DP_INTF0_MM>,
+ <&vdosys1 CLK_VDO1_DPINTF>,
+ <&apmixedsys CLK_APMIXED_TVDPLL2>;
+ clock-names = "engine", "pixel", "pll";
+ status = "disabled";
+ };
+
+ edp_tx: edp-tx@1c500000 {
+ compatible = "mediatek,mt8195-edp-tx";
+ reg = <0 0x1c500000 0 0x8000>;
+ nvmem-cells = <&dp_calibration>;
+ nvmem-cell-names = "dp_calibration_data";
+ power-domains = <&spm MT8195_POWER_DOMAIN_EPD_TX>;
+ interrupts = <GIC_SPI 676 IRQ_TYPE_LEVEL_HIGH 0>;
+ max-linkrate-mhz = <8100>;
+ status = "disabled";
+ };
+
+ dp_tx: dp-tx@1c600000 {
+ compatible = "mediatek,mt8195-dp-tx";
+ reg = <0 0x1c600000 0 0x8000>;
+ nvmem-cells = <&dp_calibration>;
+ nvmem-cell-names = "dp_calibration_data";
+ power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
+ interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
+ max-linkrate-mhz = <8100>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
index 8ee1529683a3..ec8dfb3d1c6d 100644
--- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
@@ -17,7 +17,7 @@
};
firmware {
- optee: optee@4fd00000 {
+ optee: optee {
compatible = "linaro,optee-tz";
method = "smc";
};
@@ -209,7 +209,7 @@
};
};
- i2c0_pins_a: i2c0@0 {
+ i2c0_pins_a: i2c0 {
pins1 {
pinmux = <MT8516_PIN_58_SDA0__FUNC_SDA0_0>,
<MT8516_PIN_59_SCL0__FUNC_SCL0_0>;
@@ -217,7 +217,7 @@
};
};
- i2c2_pins_a: i2c2@0 {
+ i2c2_pins_a: i2c2 {
pins1 {
pinmux = <MT8516_PIN_60_SDA2__FUNC_SDA2_0>,
<MT8516_PIN_61_SCL2__FUNC_SCL2_0>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts b/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
index d461da0b8049..3e8dee85d55f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
@@ -62,7 +62,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinmux_default>;
- pinmux_default: pinmux@0 {
+ pinmux_default: pinmux {
dap_mclk1_pw4 {
nvidia,pins = "dap_mclk1_pw4";
nvidia,function = "extperiph1";
diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
index 3673f79adf1a..858fc01cecb6 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -393,7 +393,6 @@
reg = <0x0 0x7000a000 0x0 0x100>;
#pwm-cells = <2>;
clocks = <&tegra_car TEGRA124_CLK_PWM>;
- clock-names = "pwm";
resets = <&tegra_car 17>;
reset-names = "pwm";
status = "disabled";
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 6602fe421ee8..b3f1494c02c1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -78,7 +78,8 @@
reg = <0x0 0x2600000 0x0 0x210000>;
resets = <&bpmp TEGRA186_RESET_GPCDMA>;
reset-names = "gpcdma";
- interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
@@ -112,6 +113,7 @@
#dma-cells = <1>;
iommus = <&smmu TEGRA186_SID_GPCDMA_0>;
dma-coherent;
+ dma-channel-mask = <0xfffffffe>;
status = "okay";
};
@@ -790,7 +792,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x3280000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM1>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM1>;
reset-names = "pwm";
status = "disabled";
@@ -801,7 +802,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x3290000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM2>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM2>;
reset-names = "pwm";
status = "disabled";
@@ -812,7 +812,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x32a0000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM3>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM3>;
reset-names = "pwm";
status = "disabled";
@@ -823,7 +822,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x32c0000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM5>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM5>;
reset-names = "pwm";
status = "disabled";
@@ -834,7 +832,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x32d0000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM6>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM6>;
reset-names = "pwm";
status = "disabled";
@@ -845,7 +842,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x32e0000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM7>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM7>;
reset-names = "pwm";
status = "disabled";
@@ -856,7 +852,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0x32f0000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM8>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM8>;
reset-names = "pwm";
status = "disabled";
@@ -1274,7 +1269,6 @@
compatible = "nvidia,tegra186-pwm";
reg = <0x0 0xc340000 0x0 0x10000>;
clocks = <&bpmp TEGRA186_CLK_PWM4>;
- clock-names = "pwm";
resets = <&bpmp TEGRA186_RESET_PWM4>;
reset-names = "pwm";
status = "disabled";
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
index b0f9393dd39c..cd272d407e01 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
@@ -23,7 +23,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200n8";
+ bootargs = "console=ttyTCU0,115200n8";
stdout-path = "serial0:115200n8";
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
index 273a1ef716b6..f212f6aced04 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
@@ -2117,8 +2117,8 @@
"usb-b-connector";
label = "micro-USB";
type = "micro";
- vbus-gpio = <&gpio TEGRA194_MAIN_GPIO(Z, 1)
- GPIO_ACTIVE_LOW>;
+ vbus-gpios = <&gpio TEGRA194_MAIN_GPIO(Z, 1)
+ GPIO_ACTIVE_LOW>;
};
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi
index 0bd66f9c620b..0751edddf7d5 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi
@@ -20,7 +20,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200n8";
+ bootargs = "console=ttyTCU0,115200n8";
stdout-path = "serial0:115200n8";
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 41f3a7e188d0..4afcbd60e144 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -86,6 +86,7 @@
interrupt-controller;
#gpio-cells = <2>;
gpio-controller;
+ gpio-ranges = <&pinmux 0 0 169>;
};
cbb-noc@2300000 {
@@ -142,7 +143,8 @@
reg = <0x2600000 0x210000>;
resets = <&bpmp TEGRA194_RESET_GPCDMA>;
reset-names = "gpcdma";
- interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
@@ -176,6 +178,7 @@
#dma-cells = <1>;
iommus = <&smmu TEGRA194_SID_GPCDMA_0>;
dma-coherent;
+ dma-channel-mask = <0xfffffffe>;
status = "okay";
};
@@ -626,12 +629,10 @@
pinmux: pinmux@2430000 {
compatible = "nvidia,tegra194-pinmux";
- reg = <0x2430000 0x17000>,
- <0xc300000 0x4000>;
-
+ reg = <0x2430000 0x17000>;
status = "okay";
- pex_rst_c5_out_state: pex_rst_c5_out {
+ pex_rst_c5_out_state: pinmux-pex-rst-c5-out {
pex_rst {
nvidia,pins = "pex_l5_rst_n_pgg1";
nvidia,schmitt = <TEGRA_PIN_DISABLE>;
@@ -642,7 +643,7 @@
};
};
- clkreq_c5_bi_dir_state: clkreq_c5_bi_dir {
+ clkreq_c5_bi_dir_state: pinmux-clkreq-c5-bi-dir {
clkreq {
nvidia,pins = "pex_l5_clkreq_n_pgg0";
nvidia,schmitt = <TEGRA_PIN_DISABLE>;
@@ -935,7 +936,6 @@
<&bpmp TEGRA194_CLK_QSPI0_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA194_RESET_QSPI0>;
- reset-names = "qspi";
status = "disabled";
};
@@ -949,7 +949,6 @@
<&bpmp TEGRA194_CLK_QSPI1_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA194_RESET_QSPI1>;
- reset-names = "qspi";
status = "disabled";
};
@@ -958,7 +957,6 @@
"nvidia,tegra186-pwm";
reg = <0x3280000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM1>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM1>;
reset-names = "pwm";
status = "disabled";
@@ -970,7 +968,6 @@
"nvidia,tegra186-pwm";
reg = <0x3290000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM2>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM2>;
reset-names = "pwm";
status = "disabled";
@@ -982,7 +979,6 @@
"nvidia,tegra186-pwm";
reg = <0x32a0000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM3>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM3>;
reset-names = "pwm";
status = "disabled";
@@ -994,7 +990,6 @@
"nvidia,tegra186-pwm";
reg = <0x32c0000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM5>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM5>;
reset-names = "pwm";
status = "disabled";
@@ -1006,7 +1001,6 @@
"nvidia,tegra186-pwm";
reg = <0x32d0000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM6>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM6>;
reset-names = "pwm";
status = "disabled";
@@ -1018,7 +1012,6 @@
"nvidia,tegra186-pwm";
reg = <0x32e0000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM7>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM7>;
reset-names = "pwm";
status = "disabled";
@@ -1030,7 +1023,6 @@
"nvidia,tegra186-pwm";
reg = <0x32f0000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM8>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM8>;
reset-names = "pwm";
status = "disabled";
@@ -1154,7 +1146,7 @@
};
hda@3510000 {
- compatible = "nvidia,tegra194-hda", "nvidia,tegra30-hda";
+ compatible = "nvidia,tegra194-hda";
reg = <0x3510000 0x10000>;
interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_HDA>,
@@ -1366,6 +1358,16 @@
status = "disabled";
};
+ hte_lic: hardware-timestamp@3aa0000 {
+ compatible = "nvidia,tegra194-gte-lic";
+ reg = <0x3aa0000 0x10000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ nvidia,int-threshold = <1>;
+ nvidia,slices = <11>;
+ #timestamp-cells = <1>;
+ status = "okay";
+ };
+
hsp_top0: hsp@3c00000 {
compatible = "nvidia,tegra194-hsp";
reg = <0x03c00000 0xa0000>;
@@ -1579,6 +1581,16 @@
#mbox-cells = <2>;
};
+ hte_aon: hardware-timestamp@c1e0000 {
+ compatible = "nvidia,tegra194-gte-aon";
+ reg = <0xc1e0000 0x10000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ nvidia,int-threshold = <1>;
+ nvidia,slices = <3>;
+ #timestamp-cells = <1>;
+ status = "okay";
+ };
+
gen2_i2c: i2c@c240000 {
compatible = "nvidia,tegra194-i2c";
reg = <0x0c240000 0x10000>;
@@ -1660,6 +1672,14 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-range = <&pinmux_aon 0 0 30>;
+ };
+
+ pinmux_aon: pinmux@c300000 {
+ compatible = "nvidia,tegra194-pinmux-aon";
+ reg = <0xc300000 0x4000>;
+
+ status = "okay";
};
pwm4: pwm@c340000 {
@@ -1667,7 +1687,6 @@
"nvidia,tegra186-pwm";
reg = <0xc340000 0x10000>;
clocks = <&bpmp TEGRA194_CLK_PWM4>;
- clock-names = "pwm";
resets = <&bpmp TEGRA194_RESET_PWM4>;
reset-names = "pwm";
status = "disabled";
@@ -1895,7 +1914,7 @@
#address-cells = <1>;
#size-cells = <1>;
- ranges = <0x15000000 0x15000000 0x01000000>;
+ ranges = <0x14800000 0x14800000 0x02800000>;
interconnects = <&mc TEGRA194_MEMORY_CLIENT_HOST1XDMAR &emc>;
interconnect-names = "dma-mem";
iommus = <&smmu TEGRA194_SID_HOST1X>;
@@ -3029,36 +3048,51 @@
};
l2c_0: l2-cache0 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <2>;
next-level-cache = <&l3c>;
};
l2c_1: l2-cache1 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <2>;
next-level-cache = <&l3c>;
};
l2c_2: l2-cache2 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <2>;
next-level-cache = <&l3c>;
};
l2c_3: l2-cache3 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <2>;
next-level-cache = <&l3c>;
};
l3c: l3-cache {
+ compatible = "cache";
+ cache-unified;
cache-size = <4194304>;
cache-line-size = <64>;
+ cache-level = <3>;
cache-sets = <4096>;
};
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
index a44c56c1e56e..dd9a17922fe5 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
@@ -1293,14 +1293,14 @@
};
};
- dvfs_pwm_active_state: dvfs_pwm_active {
+ dvfs_pwm_active_state: pinmux-dvfs-pwm-active {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
};
- dvfs_pwm_inactive_state: dvfs_pwm_inactive {
+ dvfs_pwm_inactive_state: pinmux-dvfs-pwm-inactive {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
@@ -1368,6 +1368,7 @@
#size-cells = <0>;
ethernet@1 {
+ compatible = "usb955,9ff";
reg = <1>;
};
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 37678c337a34..2041371ea7ff 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -109,14 +109,14 @@
};
pinmux@700008d4 {
- dvfs_pwm_active_state: dvfs_pwm_active {
+ dvfs_pwm_active_state: pinmux-dvfs-pwm-active {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
};
- dvfs_pwm_inactive_state: dvfs_pwm_inactive {
+ dvfs_pwm_inactive_state: pinmux-dvfs-pwm-inactive {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 724e87450605..bc0cacb20d7a 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -554,42 +554,48 @@
compatible = "nvidia,tegra210-pinmux";
reg = <0x0 0x700008d4 0x0 0x29c>, /* Pad control registers */
<0x0 0x70003000 0x0 0x294>; /* Mux registers */
- sdmmc1_3v3_drv: sdmmc1-3v3-drv {
+
+ sdmmc1_3v3_drv: pinmux-sdmmc1-3v3-drv {
sdmmc1 {
nvidia,pins = "drive_sdmmc1";
nvidia,pull-down-strength = <0x8>;
nvidia,pull-up-strength = <0x8>;
};
};
- sdmmc1_1v8_drv: sdmmc1-1v8-drv {
+
+ sdmmc1_1v8_drv: pinmux-sdmmc1-1v8-drv {
sdmmc1 {
nvidia,pins = "drive_sdmmc1";
nvidia,pull-down-strength = <0x4>;
nvidia,pull-up-strength = <0x3>;
};
};
- sdmmc2_1v8_drv: sdmmc2-1v8-drv {
+
+ sdmmc2_1v8_drv: pinmux-sdmmc2-1v8-drv {
sdmmc2 {
nvidia,pins = "drive_sdmmc2";
nvidia,pull-down-strength = <0x10>;
nvidia,pull-up-strength = <0x10>;
};
};
- sdmmc3_3v3_drv: sdmmc3-3v3-drv {
+
+ sdmmc3_3v3_drv: pinmux-sdmmc3-3v3-drv {
sdmmc3 {
nvidia,pins = "drive_sdmmc3";
nvidia,pull-down-strength = <0x8>;
nvidia,pull-up-strength = <0x8>;
};
};
- sdmmc3_1v8_drv: sdmmc3-1v8-drv {
+
+ sdmmc3_1v8_drv: pinmux-sdmmc3-1v8-drv {
sdmmc3 {
nvidia,pins = "drive_sdmmc3";
nvidia,pull-down-strength = <0x4>;
nvidia,pull-up-strength = <0x3>;
};
};
- sdmmc4_1v8_drv: sdmmc4-1v8-drv {
+
+ sdmmc4_1v8_drv: pinmux-sdmmc4-1v8-drv {
sdmmc4 {
nvidia,pins = "drive_sdmmc4";
nvidia,pull-down-strength = <0x10>;
@@ -667,7 +673,6 @@
reg = <0x0 0x7000a000 0x0 0x100>;
#pwm-cells = <2>;
clocks = <&tegra_car TEGRA210_CLK_PWM>;
- clock-names = "pwm";
resets = <&tegra_car 17>;
reset-names = "pwm";
status = "disabled";
@@ -912,35 +917,33 @@
};
};
- sdmmc1_3v3: sdmmc1-3v3 {
- pins = "sdmmc1";
- power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
- };
+ pinmux {
+ sdmmc1_3v3: sdmmc1-3v3 {
+ pins = "sdmmc1";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
+ };
- sdmmc1_1v8: sdmmc1-1v8 {
- pins = "sdmmc1";
- power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
- };
+ sdmmc1_1v8: sdmmc1-1v8 {
+ pins = "sdmmc1";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
+ };
- sdmmc3_3v3: sdmmc3-3v3 {
- pins = "sdmmc3";
- power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
- };
+ sdmmc3_3v3: sdmmc3-3v3 {
+ pins = "sdmmc3";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
+ };
- sdmmc3_1v8: sdmmc3-1v8 {
- pins = "sdmmc3";
- power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
- };
+ sdmmc3_1v8: sdmmc3-1v8 {
+ pins = "sdmmc3";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
+ };
- pex_dpd_disable: pex_en {
- pex-dpd-disable {
+ pex_dpd_disable: pex-dpd-disable {
pins = "pex-bias", "pex-clk1", "pex-clk2";
low-power-disable;
};
- };
- pex_dpd_enable: pex_dis {
- pex-dpd-enable {
+ pex_dpd_enable: pex-dpd-enable {
pins = "pex-bias", "pex-clk1", "pex-clk2";
low-power-enable;
};
@@ -1865,7 +1868,6 @@
<&tegra_car TEGRA210_CLK_QSPI_PM>;
clock-names = "qspi", "qspi_out";
resets = <&tegra_car 211>;
- reset-names = "qspi";
dmas = <&apbdma 5>, <&apbdma 5>;
dma-names = "rx", "tx";
status = "disabled";
@@ -2005,6 +2007,7 @@
L2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3701-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3701-0000.dtsi
index 9e4d72cfa69f..8b86ea9cb50c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3701-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3701-0000.dtsi
@@ -39,7 +39,6 @@
regulator-max-microvolt = <12000000>;
gpio = <&gpio TEGRA234_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>;
regulator-boot-on;
- enable-active-low;
};
bus@0 {
@@ -55,6 +54,13 @@
};
};
+ mmc@3400000 {
+ status = "okay";
+ bus-width = <4>;
+ cd-gpios = <&gpio TEGRA234_MAIN_GPIO(G, 7) GPIO_ACTIVE_LOW>;
+ disable-wp;
+ };
+
mmc@3460000 {
status = "okay";
bus-width = <8>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
index 57ab75328814..96aa2267b06d 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
@@ -2007,6 +2007,17 @@
status = "okay";
};
+ serial@31d0000 {
+ current-speed = <115200>;
+ status = "okay";
+ };
+
+ pwm@32a0000 {
+ assigned-clocks = <&bpmp TEGRA234_CLK_PWM3>;
+ assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLP_OUT0>;
+ status = "okay";
+ };
+
hda@3510000 {
nvidia,model = "NVIDIA Jetson AGX Orin HDA";
status = "okay";
@@ -2014,7 +2025,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200n8";
+ bootargs = "console=ttyTCU0,115200n8";
stdout-path = "serial0:115200n8";
};
@@ -2184,4 +2195,12 @@
phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4",
"p2u-5", "p2u-6", "p2u-7";
};
+
+ pwm-fan {
+ compatible = "pwm-fan";
+ pwms = <&pwm3 0 45334>;
+
+ cooling-levels = <0 95 178 255>;
+ #cooling-cells = <2>;
+ };
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000.dtsi
index a85993c85e45..e76894574d32 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000.dtsi
@@ -2,4 +2,18 @@
/ {
compatible = "nvidia,p3737-0000";
+
+ bus@0 {
+ pwm@3280000 {
+ status = "okay";
+ };
+
+ pwm@32c0000 {
+ status = "okay";
+ };
+
+ pwm@32f0000 {
+ status = "okay";
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index 0170bfa8a467..eaf05ee9acd1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -7,6 +7,7 @@
#include <dt-bindings/memory/tegra234-mc.h>
#include <dt-bindings/power/tegra234-powergate.h>
#include <dt-bindings/reset/tegra234-reset.h>
+#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
/ {
compatible = "nvidia,tegra234";
@@ -27,7 +28,8 @@
reg = <0x2600000 0x210000>;
resets = <&bpmp TEGRA234_RESET_GPCDMA>;
reset-names = "gpcdma";
- interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
@@ -60,6 +62,7 @@
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
#dma-cells = <1>;
iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;
+ dma-channel-mask = <0xfffffffe>;
dma-coherent;
};
@@ -564,7 +567,7 @@
#address-cells = <1>;
#size-cells = <1>;
- ranges = <0x15000000 0x15000000 0x01000000>;
+ ranges = <0x14800000 0x14800000 0x02000000>;
interconnects = <&mc TEGRA234_MEMORY_CLIENT_HOST1XDMAR &emc>;
interconnect-names = "dma-mem";
iommus = <&smmu_niso1 TEGRA234_SID_HOST1X>;
@@ -603,6 +606,42 @@
iommus = <&smmu_niso1 TEGRA234_SID_VIC>;
dma-coherent;
};
+
+ nvdec@15480000 {
+ compatible = "nvidia,tegra234-nvdec";
+ reg = <0x15480000 0x00040000>;
+ clocks = <&bpmp TEGRA234_CLK_NVDEC>,
+ <&bpmp TEGRA234_CLK_FUSE>,
+ <&bpmp TEGRA234_CLK_TSEC_PKA>;
+ clock-names = "nvdec", "fuse", "tsec_pka";
+ resets = <&bpmp TEGRA234_RESET_NVDEC>;
+ reset-names = "nvdec";
+ power-domains = <&bpmp TEGRA234_POWER_DOMAIN_NVDEC>;
+ interconnects = <&mc TEGRA234_MEMORY_CLIENT_NVDECSRD &emc>,
+ <&mc TEGRA234_MEMORY_CLIENT_NVDECSWR &emc>;
+ interconnect-names = "dma-mem", "write";
+ iommus = <&smmu_niso1 TEGRA234_SID_NVDEC>;
+ dma-coherent;
+
+ nvidia,memory-controller = <&mc>;
+
+ /*
+ * Placeholder values that firmware needs to update with the real
+ * offsets parsed from the microcode headers.
+ */
+ nvidia,bl-manifest-offset = <0>;
+ nvidia,bl-data-offset = <0>;
+ nvidia,bl-code-offset = <0>;
+ nvidia,os-manifest-offset = <0>;
+ nvidia,os-data-offset = <0>;
+ nvidia,os-code-offset = <0>;
+
+ /*
+ * Firmware needs to set this to "okay" once the above values have
+ * been updated.
+ */
+ status = "disabled";
+ };
};
gpio: gpio@2200000 {
@@ -836,6 +875,13 @@
dma-names = "rx", "tx";
};
+ uarti: serial@31d0000 {
+ compatible = "arm,sbsa-uart";
+ reg = <0x31d0000 0x10000>;
+ interrupts = <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
dp_aux_ch3_i2c: i2c@31e0000 {
compatible = "nvidia,tegra194-i2c";
reg = <0x31e0000 0x100>;
@@ -865,22 +911,79 @@
<&bpmp TEGRA234_CLK_QSPI0_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA234_RESET_QSPI0>;
- reset-names = "qspi";
status = "disabled";
};
pwm1: pwm@3280000 {
- compatible = "nvidia,tegra194-pwm",
- "nvidia,tegra186-pwm";
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
reg = <0x3280000 0x10000>;
clocks = <&bpmp TEGRA234_CLK_PWM1>;
- clock-names = "pwm";
resets = <&bpmp TEGRA234_RESET_PWM1>;
reset-names = "pwm";
status = "disabled";
#pwm-cells = <2>;
};
+ pwm2: pwm@3290000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x3290000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM2>;
+ resets = <&bpmp TEGRA234_RESET_PWM2>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
+ pwm3: pwm@32a0000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x32a0000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM3>;
+ resets = <&bpmp TEGRA234_RESET_PWM3>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
+ pwm5: pwm@32c0000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x32c0000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM5>;
+ resets = <&bpmp TEGRA234_RESET_PWM5>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
+ pwm6: pwm@32d0000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x32d0000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM6>;
+ resets = <&bpmp TEGRA234_RESET_PWM6>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
+ pwm7: pwm@32e0000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x32e0000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM7>;
+ resets = <&bpmp TEGRA234_RESET_PWM7>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
+ pwm8: pwm@32f0000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0x32f0000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM8>;
+ resets = <&bpmp TEGRA234_RESET_PWM8>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
spi@3300000 {
compatible = "nvidia,tegra234-qspi";
reg = <0x3300000 0x1000>;
@@ -891,7 +994,41 @@
<&bpmp TEGRA234_CLK_QSPI1_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA234_RESET_QSPI1>;
- reset-names = "qspi";
+ status = "disabled";
+ };
+
+ mmc@3400000 {
+ compatible = "nvidia,tegra234-sdhci", "nvidia,tegra186-sdhci";
+ reg = <0x03400000 0x20000>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bpmp TEGRA234_CLK_SDMMC1>,
+ <&bpmp TEGRA234_CLK_SDMMC_LEGACY_TM>;
+ clock-names = "sdhci", "tmclk";
+ assigned-clocks = <&bpmp TEGRA234_CLK_SDMMC1>,
+ <&bpmp TEGRA234_CLK_PLLC4_MUXED>;
+ assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLC4_MUXED>,
+ <&bpmp TEGRA234_CLK_PLLC4_VCO_DIV2>;
+ resets = <&bpmp TEGRA234_RESET_SDMMC1>;
+ reset-names = "sdhci";
+ interconnects = <&mc TEGRA234_MEMORY_CLIENT_SDMMCRA &emc>,
+ <&mc TEGRA234_MEMORY_CLIENT_SDMMCWA &emc>;
+ interconnect-names = "dma-mem", "write";
+ iommus = <&smmu_niso1 TEGRA234_SID_SDMMC1A>;
+ pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
+ pinctrl-0 = <&sdmmc1_3v3>;
+ pinctrl-1 = <&sdmmc1_1v8>;
+ nvidia,pad-autocal-pull-up-offset-3v3-timeout = <0x07>;
+ nvidia,pad-autocal-pull-down-offset-3v3-timeout = <0x07>;
+ nvidia,pad-autocal-pull-up-offset-1v8-timeout = <0x06>;
+ nvidia,pad-autocal-pull-down-offset-1v8-timeout = <0x07>;
+ nvidia,pad-autocal-pull-up-offset-sdr104 = <0x00>;
+ nvidia,pad-autocal-pull-down-offset-sdr104 = <0x00>;
+ nvidia,default-tap = <14>;
+ nvidia,default-trim = <0x8>;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ sd-uhs-sdr104;
status = "disabled";
};
@@ -925,7 +1062,7 @@
};
hda@3510000 {
- compatible = "nvidia,tegra234-hda", "nvidia,tegra30-hda";
+ compatible = "nvidia,tegra234-hda";
reg = <0x3510000 0x10000>;
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA234_CLK_AZA_BIT>,
@@ -967,6 +1104,198 @@
#mbox-cells = <2>;
};
+ p2u_hsio_0: phy@3e00000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e00000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_1: phy@3e10000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e10000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_2: phy@3e20000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e20000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_3: phy@3e30000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e30000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_4: phy@3e40000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e40000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_5: phy@3e50000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e50000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_6: phy@3e60000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e60000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_hsio_7: phy@3e70000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e70000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_0: phy@3e90000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03e90000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_1: phy@3ea0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03ea0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_2: phy@3eb0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03eb0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_3: phy@3ec0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03ec0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_4: phy@3ed0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03ed0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_5: phy@3ee0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03ee0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_6: phy@3ef0000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03ef0000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_nvhs_7: phy@3f00000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f00000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_0: phy@3f20000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f20000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_1: phy@3f30000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f30000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_2: phy@3f40000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f40000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_3: phy@3f50000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f50000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_4: phy@3f60000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f60000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_5: phy@3f70000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f70000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_6: phy@3f80000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f80000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
+ p2u_gbe_7: phy@3f90000 {
+ compatible = "nvidia,tegra234-p2u";
+ reg = <0x03f90000 0x10000>;
+ reg-names = "ctl";
+
+ #phy-cells = <0>;
+ };
+
ethernet@6800000 {
compatible = "nvidia,tegra234-mgbe";
reg = <0x06800000 0x10000>,
@@ -1259,198 +1588,6 @@
status = "okay";
};
- p2u_hsio_0: phy@3e00000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e00000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_1: phy@3e10000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e10000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_2: phy@3e20000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e20000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_3: phy@3e30000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e30000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_4: phy@3e40000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e40000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_5: phy@3e50000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e50000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_6: phy@3e60000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e60000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_hsio_7: phy@3e70000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e70000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_0: phy@3e90000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03e90000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_1: phy@3ea0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03ea0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_2: phy@3eb0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03eb0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_3: phy@3ec0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03ec0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_4: phy@3ed0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03ed0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_5: phy@3ee0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03ee0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_6: phy@3ef0000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03ef0000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_nvhs_7: phy@3f00000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f00000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_0: phy@3f20000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f20000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_1: phy@3f30000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f30000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_2: phy@3f40000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f40000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_3: phy@3f50000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f50000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_4: phy@3f60000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f60000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_5: phy@3f70000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f70000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_6: phy@3f80000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f80000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
- p2u_gbe_7: phy@3f90000 {
- compatible = "nvidia,tegra234-p2u";
- reg = <0x03f90000 0x10000>;
- reg-names = "ctl";
-
- #phy-cells = <0>;
- };
-
hsp_aon: hsp@c150000 {
compatible = "nvidia,tegra234-hsp", "nvidia,tegra194-hsp";
reg = <0x0c150000 0x90000>;
@@ -1488,7 +1625,6 @@
gen8_i2c: i2c@c250000 {
compatible = "nvidia,tegra194-i2c";
reg = <0xc250000 0x100>;
- nvidia,hw-instance-id = <0x7>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
clock-frequency = <400000>;
@@ -1530,6 +1666,16 @@
gpio-controller;
};
+ pwm4: pwm@c340000 {
+ compatible = "nvidia,tegra234-pwm", "nvidia,tegra194-pwm";
+ reg = <0xc340000 0x10000>;
+ clocks = <&bpmp TEGRA234_CLK_PWM4>;
+ resets = <&bpmp TEGRA234_RESET_PWM4>;
+ reset-names = "pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ };
+
pmc: pmc@c360000 {
compatible = "nvidia,tegra234-pmc";
reg = <0x0c360000 0x10000>,
@@ -1541,6 +1687,26 @@
#interrupt-cells = <2>;
interrupt-controller;
+
+ sdmmc1_3v3: sdmmc1-3v3 {
+ pins = "sdmmc1-hv";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
+ };
+
+ sdmmc1_1v8: sdmmc1-1v8 {
+ pins = "sdmmc1-hv";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
+ };
+
+ sdmmc3_3v3: sdmmc3-3v3 {
+ pins = "sdmmc3-hv";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_3V3>;
+ };
+
+ sdmmc3_1v8: sdmmc3-1v8 {
+ pins = "sdmmc3-hv";
+ power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
+ };
};
aon-fabric@c600000 {
@@ -1576,7 +1742,7 @@
interrupt-controller;
};
- smmu_iso: iommu@10000000{
+ smmu_iso: iommu@10000000 {
compatible = "nvidia,tegra234-smmu", "nvidia,smmu-500";
reg = <0x10000000 0x1000000>;
interrupts = <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
@@ -1879,8 +2045,9 @@
reg = <0x00 0x140a0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x2a000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x2a040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x2a080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x2a080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x35 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -1932,8 +2099,9 @@
reg = <0x00 0x140c0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x2c000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x2c040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x2c080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x2c080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x38 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -1965,7 +2133,7 @@
bus-range = <0x0 0xff>;
- ranges = <0x43000000 0x35 0x40000000 0x35 0x40000000 0x2 0xe8000000>, /* prefetchable memory (11904 MB) */
+ ranges = <0x43000000 0x35 0x40000000 0x35 0x40000000 0x2 0xc0000000>, /* prefetchable memory (11264 MB) */
<0x02000000 0x0 0x40000000 0x38 0x28000000 0x0 0x08000000>, /* non-prefetchable memory (128 MB) */
<0x01000000 0x0 0x2c100000 0x00 0x2c100000 0x0 0x00100000>; /* downstream I/O (1 MB) */
@@ -1985,8 +2153,9 @@
reg = <0x00 0x140e0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x2e000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x2e040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x2e080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x2e080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x3b 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2038,8 +2207,9 @@
reg = <0x00 0x14100000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x30000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x30040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x30080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x30080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x20 0xb0000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2091,8 +2261,9 @@
reg = <0x00 0x14120000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x32000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x32040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x32080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x32080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x20 0xf0000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2144,8 +2315,9 @@
reg = <0x00 0x14140000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x34000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x34040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x34080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x34080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x21 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2178,7 +2350,7 @@
bus-range = <0x0 0xff>;
ranges = <0x43000000 0x21 0x00000000 0x21 0x00000000 0x0 0x28000000>, /* prefetchable memory (640 MB) */
- <0x02000000 0x0 0x40000000 0x21 0xe8000000 0x0 0x08000000>, /* non-prefetchable memory (128 MB) */
+ <0x02000000 0x0 0x40000000 0x21 0x28000000 0x0 0x08000000>, /* non-prefetchable memory (128 MB) */
<0x01000000 0x0 0x34100000 0x00 0x34100000 0x0 0x00100000>; /* downstream I/O (1 MB) */
interconnects = <&mc TEGRA234_MEMORY_CLIENT_PCIE3R &emc>,
@@ -2197,8 +2369,9 @@
reg = <0x00 0x14160000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x36000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x36040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x36080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x36080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x24 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2250,8 +2423,9 @@
reg = <0x00 0x14180000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x38000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x38040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x38080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x38080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x27 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2303,8 +2477,9 @@
reg = <0x00 0x141a0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x3a000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x3a040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x3a080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x3a080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x2b 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2336,7 +2511,7 @@
bus-range = <0x0 0xff>;
- ranges = <0x43000000 0x27 0x40000000 0x27 0x40000000 0x3 0xe8000000>, /* prefetchable memory (16000 MB) */
+ ranges = <0x43000000 0x28 0x00000000 0x28 0x00000000 0x3 0x28000000>, /* prefetchable memory (12928 MB) */
<0x02000000 0x0 0x40000000 0x2b 0x28000000 0x0 0x08000000>, /* non-prefetchable memory (128 MB) */
<0x01000000 0x0 0x3a100000 0x00 0x3a100000 0x0 0x00100000>; /* downstream I/O (1 MB) */
@@ -2356,8 +2531,9 @@
reg = <0x00 0x141c0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x3c000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x3c040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x3c080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x3c080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x2e 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2409,8 +2585,9 @@
reg = <0x00 0x141e0000 0x0 0x00020000>, /* appl registers (128K) */
<0x00 0x3e000000 0x0 0x00040000>, /* configuration space (256K) */
<0x00 0x3e040000 0x0 0x00040000>, /* iATU_DMA reg space (256K) */
- <0x00 0x3e080000 0x0 0x00040000>; /* DBI reg space (256K) */
- reg-names = "appl", "config", "atu_dma", "dbi";
+ <0x00 0x3e080000 0x0 0x00040000>, /* DBI reg space (256K) */
+ <0x32 0x30000000 0x0 0x10000000>; /* ECAM (256MB) */
+ reg-names = "appl", "config", "atu_dma", "dbi", "ecam";
#address-cells = <3>;
#size-cells = <2>;
@@ -2442,7 +2619,7 @@
bus-range = <0x0 0xff>;
- ranges = <0x43000000 0x2e 0x40000000 0x2e 0x40000000 0x3 0xe8000000>, /* prefetchable memory (16000 MB) */
+ ranges = <0x43000000 0x30 0x00000000 0x30 0x00000000 0x2 0x28000000>, /* prefetchable memory (8832 MB) */
<0x02000000 0x0 0x40000000 0x32 0x28000000 0x0 0x08000000>, /* non-prefetchable memory (128 MB) */
<0x01000000 0x0 0x3e100000 0x00 0x3e100000 0x0 0x00100000>; /* downstream I/O (1 MB) */
@@ -2905,117 +3082,150 @@
};
l2c0_0: l2-cache00 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c0>;
};
l2c0_1: l2-cache01 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c0>;
};
l2c0_2: l2-cache02 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c0>;
};
l2c0_3: l2-cache03 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c0>;
};
l2c1_0: l2-cache10 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c1>;
};
l2c1_1: l2-cache11 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c1>;
};
l2c1_2: l2-cache12 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c1>;
};
l2c1_3: l2-cache13 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c1>;
};
l2c2_0: l2-cache20 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c2>;
};
l2c2_1: l2-cache21 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c2>;
};
l2c2_2: l2-cache22 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c2>;
};
l2c2_3: l2-cache23 {
+ compatible = "cache";
cache-size = <262144>;
cache-line-size = <64>;
cache-sets = <512>;
cache-unified;
+ cache-level = <2>;
next-level-cache = <&l3c2>;
};
l3c0: l3-cache0 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <3>;
};
l3c1: l3-cache1 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <3>;
};
l3c2: l3-cache2 {
+ compatible = "cache";
+ cache-unified;
cache-size = <2097152>;
cache-line-size = <64>;
cache-sets = <2048>;
+ cache-level = <3>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index d7669a7cee9f..3e79496292e7 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -21,6 +21,8 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-grandmax.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-j5.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-serranove.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-wingtech-wt88047.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8956-sony-xperia-loire-kugo.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8956-sony-xperia-loire-suzu.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8992-lg-bullhead-rev-10.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8992-lg-bullhead-rev-101.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8992-msft-lumia-octagon-talkman.dtb
@@ -33,12 +35,14 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8994-sony-xperia-kitakami-satsuki.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8994-sony-xperia-kitakami-sumire.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8994-sony-xperia-kitakami-suzuran.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8996-oneplus3.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8996-oneplus3t.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-sony-xperia-tone-dora.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-sony-xperia-tone-kagura.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-sony-xperia-tone-keyaki.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-xiaomi-gemini.dtb
-dtb-$(CONFIG_ARCH_QCOM) += msm8996-xiaomi-natrium.dtb
-dtb-$(CONFIG_ARCH_QCOM) += msm8996-xiaomi-scorpio.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8996pro-xiaomi-natrium.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8996pro-xiaomi-scorpio.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-asus-novago-tp370ql.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-fxtec-pro1.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-hp-envy-x2.dtb
@@ -49,11 +53,14 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-oneplus-dumpling.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-lilac.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-maple.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-poplar.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8998-xiaomi-sagit.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb
dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5.dtb
+dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5-vision-mezzanine.dtb
dtb-$(CONFIG_ARCH_QCOM) += sa8155p-adp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sa8295p-adp.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sa8540p-ride.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-idp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1-lte.dtb
@@ -87,6 +94,8 @@ dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel-lte-parade.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel-lte-ti.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel-parade.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel-ti.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel360-lte.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pazquel360-wifi.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1-lte.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r2.dtb
@@ -104,11 +113,14 @@ dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1-lte.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-crd.dtb
-dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-evoker-r0.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-evoker.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-evoker-lte.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-herobrine-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-villager-r0.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-villager-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-villager-r1-lte.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-zombie.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sc7280-herobrine-zombie-lte.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-idp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-idp2.dtb
dtb-$(CONFIG_ARCH_QCOM) += sc7280-crd-r3.dtb
@@ -122,25 +134,31 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-nile-voyager.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm632-fairphone-fp3.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm636-sony-xperia-ganges-mermaid.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-lavender.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sdm670-google-sargo.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r1.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r2.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r3.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c-navigation-mezzanine.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-lg-judyln.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-lg-judyp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-oneplus-enchilada.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-oneplus-fajita.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sdm845-samsung-starqltechn.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-sony-xperia-tama-akari.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-sony-xperia-tama-akatsuki.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-sony-xperia-tama-apollo.dtb
-dtb-$(CONFIG_ARCH_QCOM) += sdm845-xiaomi-beryllium.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sdm845-xiaomi-beryllium-ebbg.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sdm845-xiaomi-beryllium-tianma.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-xiaomi-polaris.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-shift-axolotl.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm850-lenovo-yoga-c630.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm850-samsung-w737.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm4250-oneplus-billie2.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm6125-sony-xperia-seine-pdx201.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm6350-sony-xperia-lena-pdx213.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm6375-sony-xperia-murray-pdx225.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm7225-fairphone-fp4.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8150-hdk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8150-microsoft-surface-duo.dtb
@@ -159,3 +177,4 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8350-sony-xperia-sagami-pdx215.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8450-hdk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8450-qrd.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx223.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx224.dtb
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
index 1b613098fb4a..ef5b39ba1238 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
@@ -718,14 +718,14 @@
"USR_LED_2_CTRL", /* GPIO 120 */
"SB_HS_ID";
- msmgpio_leds: msmgpio-leds {
+ msmgpio_leds: msmgpio-leds-state {
pins = "gpio21", "gpio120";
function = "gpio";
output-low;
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio121";
function = "gpio";
@@ -734,7 +734,7 @@
bias-pull-up;
};
- adv7533_int_active: adv533-int-active {
+ adv7533_int_active: adv533-int-active-state {
pins = "gpio31";
function = "gpio";
@@ -742,7 +742,7 @@
bias-disable;
};
- adv7533_int_suspend: adv7533-int-suspend {
+ adv7533_int_suspend: adv7533-int-suspend-state {
pins = "gpio31";
function = "gpio";
@@ -750,7 +750,7 @@
bias-disable;
};
- adv7533_switch_active: adv7533-switch-active {
+ adv7533_switch_active: adv7533-switch-active-state {
pins = "gpio32";
function = "gpio";
@@ -758,7 +758,7 @@
bias-disable;
};
- adv7533_switch_suspend: adv7533-switch-suspend {
+ adv7533_switch_suspend: adv7533-switch-suspend-state {
pins = "gpio32";
function = "gpio";
@@ -766,7 +766,7 @@
bias-disable;
};
- msm_key_volp_n_default: msm-key-volp-n-default {
+ msm_key_volp_n_default: msm-key-volp-n-default-state {
pins = "gpio107";
function = "gpio";
@@ -839,7 +839,7 @@
function = "digital";
output-low;
- power-source = <PM8916_MPP_L5>; // 1.8V
+ power-source = <PM8916_MPP_L5>; /* 1.8V */
};
pm8916_mpps_leds: pm8916-mpps-state {
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
index 5cdc7ac1a9c0..fe6c415e8229 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
@@ -422,82 +422,46 @@
"NC", /* GPIO_148 */
"NC"; /* GPIO_149 */
- sdc2_cd_on: sdc2_cd_on {
- mux {
- pins = "gpio38";
- function = "gpio";
- };
-
- config {
- pins = "gpio38";
- bias-pull-up; /* pull up */
- drive-strength = <16>; /* 16 MA */
- };
+ sdc2_cd_on: sdc2-cd-on-state {
+ pins = "gpio38";
+ function = "gpio";
+ bias-pull-up;
+ drive-strength = <16>;
};
- sdc2_cd_off: sdc2_cd_off {
- mux {
- pins = "gpio38";
- function = "gpio";
- };
-
- config {
- pins = "gpio38";
- bias-pull-up; /* pull up */
- drive-strength = <2>; /* 2 MA */
- };
+ sdc2_cd_off: sdc2-cd-off-state {
+ pins = "gpio38";
+ function = "gpio";
+ bias-pull-up;
+ drive-strength = <2>;
};
- hdmi_hpd_active: hdmi_hpd_active {
- mux {
- pins = "gpio34";
- function = "hdmi_hot";
- };
-
- config {
- pins = "gpio34";
- bias-pull-down;
- drive-strength = <16>;
- };
+ hdmi_hpd_active: hdmi-hpd-active-state {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ bias-pull-down;
+ drive-strength = <16>;
};
- hdmi_hpd_suspend: hdmi_hpd_suspend {
- mux {
- pins = "gpio34";
- function = "hdmi_hot";
- };
-
- config {
- pins = "gpio34";
- bias-pull-down;
- drive-strength = <2>;
- };
+ hdmi_hpd_suspend: hdmi-hpd-suspend-state {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ bias-pull-down;
+ drive-strength = <2>;
};
- hdmi_ddc_active: hdmi_ddc_active {
- mux {
- pins = "gpio32", "gpio33";
- function = "hdmi_ddc";
- };
-
- config {
- pins = "gpio32", "gpio33";
- drive-strength = <2>;
- bias-pull-up;
- };
+ hdmi_ddc_active: hdmi-ddc-active-state {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ drive-strength = <2>;
+ bias-pull-up;
};
- hdmi_ddc_suspend: hdmi_ddc_suspend {
- mux {
- pins = "gpio32", "gpio33";
- function = "hdmi_ddc";
- };
-
- config {
- pins = "gpio32", "gpio33";
- drive-strength = <2>;
- bias-pull-down;
- };
+ hdmi_ddc_suspend: hdmi-ddc-suspend-state {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ drive-strength = <2>;
+ bias-pull-down;
};
};
@@ -560,7 +524,7 @@
pins = "gpio5";
function = PMIC_GPIO_FUNC_NORMAL;
output-low;
- power-source = <2>; // PM8994_GPIO_S4, 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
};
};
@@ -569,7 +533,7 @@
pins = "gpio19";
function = PMIC_GPIO_FUNC_NORMAL;
output-low;
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
bias-pull-down;
};
@@ -580,7 +544,7 @@
pins = "gpio8";
function = PMIC_GPIO_FUNC_NORMAL;
output-low;
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
bias-pull-down;
};
@@ -590,7 +554,7 @@
pinconf {
pins = "gpio15";
function = "func1";
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
};
};
@@ -602,7 +566,7 @@
drive-push-pull;
bias-pull-up;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
};
};
@@ -623,7 +587,7 @@
input-enable;
bias-pull-down;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
};
};
};
@@ -679,7 +643,7 @@
input-enable;
bias-pull-down;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
- power-source = <PM8994_GPIO_S4>; // 1.8V
+ power-source = <PM8994_GPIO_S4>; /* 1.8V */
};
};
};
@@ -751,7 +715,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -963,7 +927,7 @@
};
};
- pmi8994-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
diff --git a/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts b/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts
index 92f264891d84..71e0a500599c 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts
+++ b/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts
@@ -104,65 +104,27 @@
status = "okay";
};
-&tlmm {
- sdc2_pins_default: sdc2-pins-default {
- clk {
- pins = "sdc2_clk";
- bias-disable;
- drive-strength = <16>;
- };
-
- cmd {
- pins = "sdc2_cmd";
- bias-pull-up;
- drive-strength = <10>;
- };
-
- data {
- pins = "sdc2_data";
- bias-pull-up;
- drive-strength = <10>;
- };
+&sdc2_state_on {
+ cd-pins {
+ pins = "gpio38";
+ function = "gpio";
- cd {
- pins = "gpio38";
- function = "gpio";
-
- bias-pull-up;
- drive-strength = <16>;
- };
+ bias-pull-up;
+ drive-strength = <16>;
};
+};
- sdc2_pins_sleep: sdc2-pins-sleep {
- clk {
- pins = "sdc2_clk";
- bias-disable;
- drive-strength = <2>;
- };
-
- cmd {
- pins = "sdc2_cmd";
- bias-pull-up;
- drive-strength = <2>;
- };
-
- data {
- pins = "sdc2_data";
- bias-pull-up;
- drive-strength = <2>;
- };
-
- cd {
- pins = "gpio38";
- function = "gpio";
- bias-pull-up;
- drive-strength = <2>;
- };
+&sdc2_state_off {
+ cd-pins {
+ pins = "gpio38";
+ function = "gpio";
+ bias-pull-up;
+ drive-strength = <2>;
};
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -372,10 +334,6 @@
vmmc-supply = <&vreg_l21a_2p95>;
vqmmc-supply = <&vreg_l13a_2p95>;
-
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&sdc2_pins_default>;
- pinctrl-1 = <&sdc2_pins_sleep>;
};
&ufshc {
diff --git a/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts b/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
index 1ba2eca33c7b..2aee8594b280 100644
--- a/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
+++ b/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
@@ -19,7 +19,6 @@
chosen {
stdout-path = "serial0:115200n8";
- bootargs-append = " swiotlb=1";
};
};
@@ -37,6 +36,8 @@
&blsp1_spi1 {
cs-select = <0>;
+ pinctrl-0 = <&spi_0_pins>;
+ pinctrl-names = "default";
status = "okay";
flash@0 {
@@ -49,13 +50,13 @@
};
&tlmm {
- i2c_1_pins: i2c-1-pins {
+ i2c_1_pins: i2c-1-state {
pins = "gpio42", "gpio43";
function = "blsp2_i2c";
drive-strength = <8>;
};
- spi_0_pins: spi-0-pins {
+ spi_0_pins: spi-0-state {
pins = "gpio38", "gpio39", "gpio40", "gpio41";
function = "blsp0_spi";
drive-strength = <8>;
@@ -80,9 +81,9 @@
};
&qusb_phy_1 {
- status = "ok";
+ status = "okay";
};
&usb2 {
- status = "ok";
+ status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
index a7c7ca980a71..5d453f11acd9 100644
--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
@@ -218,14 +218,14 @@
interrupt-controller;
#interrupt-cells = <2>;
- serial_3_pins: serial3-pinmux {
+ serial_3_pins: serial3-state {
pins = "gpio44", "gpio45";
function = "blsp2_uart";
drive-strength = <8>;
bias-pull-down;
};
- qpic_pins: qpic-pins {
+ qpic_pins: qpic-state {
pins = "gpio1", "gpio3", "gpio4",
"gpio5", "gpio6", "gpio7",
"gpio8", "gpio10", "gpio11",
@@ -348,7 +348,7 @@
status = "disabled";
};
- qpic_nand: nand@79b0000 {
+ qpic_nand: nand-controller@79b0000 {
compatible = "qcom,ipq6018-nand";
reg = <0x0 0x079b0000 0x0 0x10000>;
#address-cells = <1>;
@@ -406,7 +406,8 @@
pcie_phy0: phy@84200 {
reg = <0x0 0x84200 0x0 0x16c>, /* Serdes Tx */
<0x0 0x84400 0x0 0x200>, /* Serdes Rx */
- <0x0 0x84800 0x0 0x4f4>; /* PCS: Lane0, COM, PCIE */
+ <0x0 0x84800 0x0 0x1f0>, /* PCS: Lane0, COM, PCIE */
+ <0x0 0x84c00 0x0 0xf4>; /* pcs_misc */
#phy-cells = <0>;
clocks = <&gcc GCC_PCIE0_PIPE_CLK>;
@@ -511,14 +512,6 @@
clock-names = "xo";
};
- timer {
- compatible = "arm,armv8-timer";
- interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
- };
-
timer@b120000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -770,6 +763,14 @@
};
};
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
wcss: wcss-smp2p {
compatible = "qcom,smp2p";
qcom,smem = <435>, <428>;
diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
index 7143c936de61..ca3f96646b90 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
/dts-v1/;
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
*/
#include "ipq8074.dtsi"
+#include "pmp8074.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
@@ -51,12 +54,12 @@
&pcie0 {
status = "okay";
- perst-gpios = <&tlmm 61 0x1>;
+ perst-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
};
&pcie1 {
status = "okay";
- perst-gpios = <&tlmm 58 0x1>;
+ perst-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
};
&pcie_phy0 {
@@ -84,6 +87,7 @@
&sdhc_1 {
status = "okay";
+ vqmmc-supply = <&l11>;
};
&qusb_phy_0 {
diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
index 2bfcf42aeabc..cc1992ca0519 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
*/
/dts-v1/;
diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
index 7da39f1d979b..d7f0efda6b8e 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/dts-v1/;
-/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
*/
#include "ipq8074-hk10.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi b/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi
index db4b87944cdf..651a231554e0 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi
@@ -5,6 +5,7 @@
/dts-v1/;
#include "ipq8074.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
aliases {
@@ -22,7 +23,7 @@
};
&blsp1_spi1 {
- status = "ok";
+ status = "okay";
flash@0 {
#address-cells = <1>;
@@ -34,33 +35,33 @@
};
&blsp1_uart5 {
- status = "ok";
+ status = "okay";
};
&pcie0 {
- status = "ok";
- perst-gpios = <&tlmm 58 0x1>;
+ status = "okay";
+ perst-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
};
&pcie1 {
- status = "ok";
- perst-gpios = <&tlmm 61 0x1>;
+ status = "okay";
+ perst-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
};
&pcie_phy0 {
- status = "ok";
+ status = "okay";
};
&pcie_phy1 {
- status = "ok";
+ status = "okay";
};
&qpic_bam {
- status = "ok";
+ status = "okay";
};
&qpic_nand {
- status = "ok";
+ status = "okay";
nand@0 {
reg = <0>;
diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
index a47acf9bdf24..4e51d8e3df04 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
@@ -129,10 +129,10 @@
status = "disabled";
usb1_ssphy: phy@58200 {
- reg = <0x00058200 0x130>, /* Tx */
+ reg = <0x00058200 0x130>, /* Tx */
<0x00058400 0x200>, /* Rx */
- <0x00058800 0x1f8>, /* PCS */
- <0x00058600 0x044>; /* PCS misc*/
+ <0x00058800 0x1f8>, /* PCS */
+ <0x00058600 0x044>; /* PCS misc */
#phy-cells = <0>;
#clock-cells = <0>;
clocks = <&gcc GCC_USB1_PIPE_CLK>;
@@ -172,10 +172,10 @@
status = "disabled";
usb0_ssphy: phy@78200 {
- reg = <0x00078200 0x130>, /* Tx */
+ reg = <0x00078200 0x130>, /* Tx */
<0x00078400 0x200>, /* Rx */
- <0x00078800 0x1f8>, /* PCS */
- <0x00078600 0x044>; /* PCS misc*/
+ <0x00078800 0x1f8>, /* PCS */
+ <0x00078600 0x044>; /* PCS misc */
#phy-cells = <0>;
#clock-cells = <0>;
clocks = <&gcc GCC_USB0_PIPE_CLK>;
@@ -273,6 +273,16 @@
status = "disabled";
};
+ tsens: thermal-sensor@4a9000 {
+ compatible = "qcom,ipq8074-tsens";
+ reg = <0x4a9000 0x1000>, /* TM */
+ <0x4a8000 0x1000>; /* SROT */
+ interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "combined";
+ #qcom,sensors = <16>;
+ #thermal-sensor-cells = <1>;
+ };
+
cryptobam: dma-controller@704000 {
compatible = "qcom,bam-v1.7.0";
reg = <0x00704000 0x20000>;
@@ -307,35 +317,35 @@
interrupt-controller;
#interrupt-cells = <0x2>;
- serial_4_pins: serial4-pinmux {
+ serial_4_pins: serial4-state {
pins = "gpio23", "gpio24";
function = "blsp4_uart1";
drive-strength = <8>;
bias-disable;
};
- i2c_0_pins: i2c-0-pinmux {
+ i2c_0_pins: i2c-0-state {
pins = "gpio42", "gpio43";
function = "blsp1_i2c";
drive-strength = <8>;
bias-disable;
};
- spi_0_pins: spi-0-pins {
+ spi_0_pins: spi-0-state {
pins = "gpio38", "gpio39", "gpio40", "gpio41";
function = "blsp0_spi";
drive-strength = <8>;
bias-disable;
};
- hsuart_pins: hsuart-pins {
+ hsuart_pins: hsuart-state {
pins = "gpio46", "gpio47", "gpio48", "gpio49";
function = "blsp2_uart";
drive-strength = <8>;
bias-disable;
};
- qpic_pins: qpic-pins {
+ qpic_pins: qpic-state {
pins = "gpio1", "gpio3", "gpio4",
"gpio5", "gpio6", "gpio7",
"gpio8", "gpio10", "gpio11",
@@ -350,9 +360,11 @@
gcc: gcc@1800000 {
compatible = "qcom,gcc-ipq8074";
reg = <0x01800000 0x80000>;
- #clock-cells = <0x1>;
+ clocks = <&xo>, <&sleep_clk>;
+ clock-names = "xo", "sleep_clk";
+ #clock-cells = <1>;
#power-domain-cells = <1>;
- #reset-cells = <0x1>;
+ #reset-cells = <1>;
};
tcsr_mutex: hwlock@1905000 {
@@ -668,12 +680,22 @@
apcs_glb: mailbox@b111000 {
compatible = "qcom,ipq8074-apcs-apps-global";
- reg = <0x0b111000 0x6000>;
+ reg = <0x0b111000 0x1000>;
+ clocks = <&a53pll>, <&xo>;
+ clock-names = "pll", "xo";
#clock-cells = <1>;
#mbox-cells = <1>;
};
+ a53pll: clock@b116000 {
+ compatible = "qcom,ipq8074-a53pll";
+ reg = <0x0b116000 0x40>;
+ #clock-cells = <0>;
+ clocks = <&xo>;
+ clock-names = "xo";
+ };
+
timer@b120000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -865,4 +887,90 @@
<GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
+
+ thermal-zones {
+ nss-top-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 4>;
+ };
+
+ nss0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 5>;
+ };
+
+ nss1-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 6>;
+ };
+
+ wcss-phya0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 7>;
+ };
+
+ wcss-phya1-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 8>;
+ };
+
+ cpu0_thermal: cpu0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 9>;
+ };
+
+ cpu1_thermal: cpu1-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 10>;
+ };
+
+ cpu2_thermal: cpu2-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 11>;
+ };
+
+ cpu3_thermal: cpu3-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 12>;
+ };
+
+ cluster_thermal: cluster-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 13>;
+ };
+
+ wcss-phyb0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 14>;
+ };
+
+ wcss-phyb1-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 15>;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts
index 3dc9619fde6e..701a5585d77e 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts
@@ -5,6 +5,7 @@
#include "msm8916-pm8916.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
/ {
model = "Alcatel OneTouch Idol 3 (4.7)";
@@ -34,6 +35,19 @@
};
};
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_leds_default>;
+
+ led-0 {
+ gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "torch";
+ function = LED_FUNCTION_TORCH;
+ };
+ };
+
usb_id: usb-id {
compatible = "linux,extcon-usb-gpio";
id-gpio = <&msmgpio 69 GPIO_ACTIVE_HIGH>;
@@ -116,6 +130,27 @@
};
};
+&blsp_i2c6 {
+ status = "okay";
+
+ led-controller@68 {
+ compatible = "si-en,sn3190";
+ reg = <0x68>;
+ shutdown-gpios = <&msmgpio 89 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_enable_default &led_shutdown_default>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ led-max-microamp = <5000>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+ };
+};
+
&pm8916_resin {
status = "okay";
linux,code = <KEY_VOLUMEDOWN>;
@@ -260,7 +295,7 @@
};
&msmgpio {
- accel_int_default: accel-int-default {
+ accel_int_default: accel-int-default-state {
pins = "gpio31";
function = "gpio";
@@ -268,7 +303,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
@@ -276,7 +311,15 @@
bias-pull-up;
};
- gyro_int_default: gyro-int-default {
+ gpio_leds_default: gpio-leds-default-state {
+ pins = "gpio32";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ gyro_int_default: gyro-int-default-state {
pins = "gpio97", "gpio98";
function = "gpio";
@@ -284,7 +327,30 @@
bias-disable;
};
- mag_reset_default: mag-reset-default {
+ /*
+ * The OEM wired an additional GPIO to be asserted so that
+ * the si-en,sn3190 LED IC works. Since this GPIO is not
+ * part of the IC datasheet nor supported by the driver,
+ * force it asserted here.
+ */
+ led_enable_default: led-enable-default-state {
+ pins = "gpio102";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+
+ led_shutdown_default: led-shutdown-default-state {
+ pins = "gpio89";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ mag_reset_default: mag-reset-default-state {
pins = "gpio8";
function = "gpio";
@@ -292,7 +358,7 @@
bias-disable;
};
- proximity_int_default: proximity-int-default {
+ proximity_int_default: proximity-int-default-state {
pins = "gpio12";
function = "gpio";
@@ -300,7 +366,7 @@
bias-pull-up;
};
- ts_int_reset_default: ts-int-reset-default {
+ ts_int_reset_default: ts-int-reset-default-state {
pins = "gpio13", "gpio100";
function = "gpio";
@@ -308,7 +374,7 @@
bias-disable;
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio69";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts
index dd92070a1211..3618704a5330 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts
@@ -263,7 +263,7 @@
};
&msmgpio {
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107", "gpio117";
function = "gpio";
@@ -271,7 +271,7 @@
bias-pull-up;
};
- imu_default: imu-default {
+ imu_default: imu-default-state {
pins = "gpio36";
function = "gpio";
@@ -279,7 +279,7 @@
bias-disable;
};
- mag_reset_default: mag-reset-default {
+ mag_reset_default: mag-reset-default-state {
pins = "gpio112";
function = "gpio";
@@ -287,7 +287,7 @@
bias-disable;
};
- sd_vmmc_en_default: sd-vmmc-en-default {
+ sd_vmmc_en_default: sd-vmmc-en-default-state {
pins = "gpio87";
function = "gpio";
@@ -295,14 +295,16 @@
bias-disable;
};
- touchscreen_default: touchscreen-default {
- pins = "gpio13";
- function = "gpio";
+ touchscreen_default: touchscreen-default-state {
+ touch-pins {
+ pins = "gpio13";
+ function = "gpio";
- drive-strength = <2>;
- bias-pull-up;
+ drive-strength = <2>;
+ bias-pull-up;
+ };
- reset {
+ reset-pins {
pins = "gpio12";
function = "gpio";
@@ -311,7 +313,7 @@
};
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio110";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts
index 9e470c67274e..8c07eca900d3 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (C) 2021 Stephan Gerhold
+/*
+ * Copyright (C) 2021 Stephan Gerhold
+ */
/dts-v1/;
@@ -414,7 +416,7 @@
};
&msmgpio {
- accel_irq_default: accel-irq-default {
+ accel_irq_default: accel-irq-default-state {
pins = "gpio115";
function = "gpio";
@@ -422,7 +424,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
@@ -430,7 +432,7 @@
bias-pull-up;
};
- gpio_leds_default: gpio-leds-default {
+ gpio_leds_default: gpio-leds-default-state {
pins = "gpio8", "gpio9", "gpio10";
function = "gpio";
@@ -438,7 +440,7 @@
bias-disable;
};
- nfc_default: nfc-default {
+ nfc_default: nfc-default-state {
pins = "gpio2", "gpio20", "gpio21";
function = "gpio";
@@ -446,7 +448,7 @@
bias-disable;
};
- mag_reset_default: mag-reset-default {
+ mag_reset_default: mag-reset-default-state {
pins = "gpio36";
function = "gpio";
@@ -454,7 +456,7 @@
bias-disable;
};
- prox_irq_default: prox-irq-default {
+ prox_irq_default: prox-irq-default-state {
pins = "gpio113";
function = "gpio";
@@ -462,7 +464,7 @@
bias-disable;
};
- reg_lcd_en_default: reg-lcd-en-default {
+ reg_lcd_en_default: reg-lcd-en-default-state {
pins = "gpio32", "gpio97";
function = "gpio";
@@ -470,7 +472,7 @@
bias-disable;
};
- sdhc2_cd_default: sdhc2-cd-default {
+ sdhc2_cd_default: sdhc2-cd-default-state {
pins = "gpio56";
function = "gpio";
@@ -478,7 +480,7 @@
bias-disable;
};
- ts_irq_default: ts-irq-default {
+ ts_irq_default: ts-irq-default-state {
pins = "gpio13";
function = "gpio";
@@ -486,7 +488,7 @@
bias-disable;
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio117";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts
index d85e7f7c0835..d1e8cf2f50c0 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts
@@ -22,7 +22,7 @@
};
reserved-memory {
- // wcnss.mdt is not relocatable, so it must be loaded at 0x8b600000
+ /* wcnss.mdt is not relocatable, so it must be loaded at 0x8b600000 */
/delete-node/ wcnss@89300000;
wcnss_mem: wcnss@8b600000 {
@@ -204,12 +204,12 @@
rmi4-f01@1 {
reg = <0x1>;
- syna,nosleep-mode = <1>; // Allow sleeping
+ syna,nosleep-mode = <1>; /* Allow sleeping */
};
rmi4-f12@12 {
reg = <0x12>;
- syna,sensor-type = <1>; // Touchscreen
+ syna,sensor-type = <1>; /* Touchscreen */
};
};
};
@@ -367,7 +367,7 @@
};
&msmgpio {
- accel_int_default: accel-int-default {
+ accel_int_default: accel-int-default-state {
pins = "gpio116";
function = "gpio";
@@ -375,7 +375,7 @@
bias-disable;
};
- camera_flash_default: camera-flash-default {
+ camera_flash_default: camera-flash-default-state {
pins = "gpio31", "gpio32";
function = "gpio";
@@ -383,7 +383,7 @@
bias-disable;
};
- ctp_pwr_en_default: ctp-pwr-en-default {
+ ctp_pwr_en_default: ctp-pwr-en-default-state {
pins = "gpio17";
function = "gpio";
@@ -391,7 +391,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
@@ -399,7 +399,7 @@
bias-pull-up;
};
- gyro_int_default: gyro-int-default {
+ gyro_int_default: gyro-int-default-state {
pins = "gpio22", "gpio23";
function = "gpio";
@@ -407,7 +407,7 @@
bias-disable;
};
- light_int_default: light-int-default {
+ light_int_default: light-int-default-state {
pins = "gpio115";
function = "gpio";
@@ -415,7 +415,7 @@
bias-disable;
};
- magn_int_default: magn-int-default {
+ magn_int_default: magn-int-default-state {
pins = "gpio113";
function = "gpio";
@@ -423,7 +423,7 @@
bias-disable;
};
- tp_int_default: tp-int-default {
+ tp_int_default: tp-int-default-state {
pins = "gpio13";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts
index b4812f093b17..3899e11b9843 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts
@@ -234,7 +234,7 @@
};
&msmgpio {
- button_backlight_default: button-backlight-default {
+ button_backlight_default: button-backlight-default-state {
pins = "gpio17";
function = "gpio";
@@ -242,7 +242,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
@@ -250,7 +250,7 @@
bias-pull-up;
};
- mag_reset_default: mag-reset-default {
+ mag_reset_default: mag-reset-default-state {
pins = "gpio111";
function = "gpio";
@@ -258,7 +258,7 @@
bias-disable;
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio110";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
index 7dedb91b9930..33dfcf318a81 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
@@ -5,8 +5,8 @@
&msmgpio {
- blsp1_uart1_default: blsp1-uart1-default {
- // TX, RX, CTS_N, RTS_N
+ blsp1_uart1_default: blsp1-uart1-default-state {
+ /* TX, RX, CTS_N, RTS_N */
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "blsp_uart1";
@@ -14,7 +14,7 @@
bias-disable;
};
- blsp1_uart1_sleep: blsp1-uart1-sleep {
+ blsp1_uart1_sleep: blsp1-uart1-sleep-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "gpio";
@@ -22,7 +22,7 @@
bias-pull-down;
};
- blsp1_uart2_default: blsp1-uart2-default {
+ blsp1_uart2_default: blsp1-uart2-default-state {
pins = "gpio4", "gpio5";
function = "blsp_uart2";
@@ -30,7 +30,7 @@
bias-disable;
};
- blsp1_uart2_sleep: blsp1-uart2-sleep {
+ blsp1_uart2_sleep: blsp1-uart2-sleep-state {
pins = "gpio4", "gpio5";
function = "gpio";
@@ -38,14 +38,15 @@
bias-pull-down;
};
- spi1_default: spi1-default {
- pins = "gpio0", "gpio1", "gpio3";
- function = "blsp_spi1";
+ spi1_default: spi1-default-state {
+ spi-pins {
+ pins = "gpio0", "gpio1", "gpio3";
+ function = "blsp_spi1";
- drive-strength = <12>;
- bias-disable;
-
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio2";
function = "gpio";
@@ -55,7 +56,7 @@
};
};
- spi1_sleep: spi1-sleep {
+ spi1_sleep: spi1-sleep-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "gpio";
@@ -63,14 +64,15 @@
bias-pull-down;
};
- spi2_default: spi2-default {
- pins = "gpio4", "gpio5", "gpio7";
- function = "blsp_spi2";
+ spi2_default: spi2-default-state {
+ spi-pins {
+ pins = "gpio4", "gpio5", "gpio7";
+ function = "blsp_spi2";
- drive-strength = <12>;
- bias-disable;
-
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio6";
function = "gpio";
@@ -80,7 +82,7 @@
};
};
- spi2_sleep: spi2-sleep {
+ spi2_sleep: spi2-sleep-state {
pins = "gpio4", "gpio5", "gpio6", "gpio7";
function = "gpio";
@@ -88,14 +90,15 @@
bias-pull-down;
};
- spi3_default: spi3-default {
- pins = "gpio8", "gpio9", "gpio11";
- function = "blsp_spi3";
+ spi3_default: spi3-default-state {
+ spi-pins {
+ pins = "gpio8", "gpio9", "gpio11";
+ function = "blsp_spi3";
- drive-strength = <12>;
- bias-disable;
-
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio10";
function = "gpio";
@@ -105,7 +108,7 @@
};
};
- spi3_sleep: spi3-sleep {
+ spi3_sleep: spi3-sleep-state {
pins = "gpio8", "gpio9", "gpio10", "gpio11";
function = "gpio";
@@ -113,14 +116,15 @@
bias-pull-down;
};
- spi4_default: spi4-default {
- pins = "gpio12", "gpio13", "gpio15";
- function = "blsp_spi4";
-
- drive-strength = <12>;
- bias-disable;
+ spi4_default: spi4-default-state {
+ spi-pins {
+ pins = "gpio12", "gpio13", "gpio15";
+ function = "blsp_spi4";
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio14";
function = "gpio";
@@ -130,7 +134,7 @@
};
};
- spi4_sleep: spi4-sleep {
+ spi4_sleep: spi4-sleep-state {
pins = "gpio12", "gpio13", "gpio14", "gpio15";
function = "gpio";
@@ -138,14 +142,15 @@
bias-pull-down;
};
- spi5_default: spi5-default {
- pins = "gpio16", "gpio17", "gpio19";
- function = "blsp_spi5";
+ spi5_default: spi5-default-state {
+ spi-pins {
+ pins = "gpio16", "gpio17", "gpio19";
+ function = "blsp_spi5";
- drive-strength = <12>;
- bias-disable;
-
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio18";
function = "gpio";
@@ -155,7 +160,7 @@
};
};
- spi5_sleep: spi5-sleep {
+ spi5_sleep: spi5-sleep-state {
pins = "gpio16", "gpio17", "gpio18", "gpio19";
function = "gpio";
@@ -163,14 +168,15 @@
bias-pull-down;
};
- spi6_default: spi6-default {
- pins = "gpio20", "gpio21", "gpio23";
- function = "blsp_spi6";
-
- drive-strength = <12>;
- bias-disable;
+ spi6_default: spi6-default-state {
+ spi-pins {
+ pins = "gpio20", "gpio21", "gpio23";
+ function = "blsp_spi6";
- cs {
+ drive-strength = <12>;
+ bias-disable;
+ };
+ cs-pins {
pins = "gpio22";
function = "gpio";
@@ -180,7 +186,7 @@
};
};
- spi6_sleep: spi6-sleep {
+ spi6_sleep: spi6-sleep-state {
pins = "gpio20", "gpio21", "gpio22", "gpio23";
function = "gpio";
@@ -188,7 +194,7 @@
bias-pull-down;
};
- i2c1_default: i2c1-default {
+ i2c1_default: i2c1-default-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
@@ -196,7 +202,7 @@
bias-disable;
};
- i2c1_sleep: i2c1-sleep {
+ i2c1_sleep: i2c1-sleep-state {
pins = "gpio2", "gpio3";
function = "gpio";
@@ -204,7 +210,7 @@
bias-disable;
};
- i2c2_default: i2c2-default {
+ i2c2_default: i2c2-default-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
@@ -212,7 +218,7 @@
bias-disable;
};
- i2c2_sleep: i2c2-sleep {
+ i2c2_sleep: i2c2-sleep-state {
pins = "gpio6", "gpio7";
function = "gpio";
@@ -220,7 +226,7 @@
bias-disable;
};
- i2c3_default: i2c3-default {
+ i2c3_default: i2c3-default-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
@@ -228,7 +234,7 @@
bias-disable;
};
- i2c3_sleep: i2c3-sleep {
+ i2c3_sleep: i2c3-sleep-state {
pins = "gpio10", "gpio11";
function = "gpio";
@@ -236,7 +242,7 @@
bias-disable;
};
- i2c4_default: i2c4-default {
+ i2c4_default: i2c4-default-state {
pins = "gpio14", "gpio15";
function = "blsp_i2c4";
@@ -244,7 +250,7 @@
bias-disable;
};
- i2c4_sleep: i2c4-sleep {
+ i2c4_sleep: i2c4-sleep-state {
pins = "gpio14", "gpio15";
function = "gpio";
@@ -252,7 +258,7 @@
bias-disable;
};
- i2c5_default: i2c5-default {
+ i2c5_default: i2c5-default-state {
pins = "gpio18", "gpio19";
function = "blsp_i2c5";
@@ -260,7 +266,7 @@
bias-disable;
};
- i2c5_sleep: i2c5-sleep {
+ i2c5_sleep: i2c5-sleep-state {
pins = "gpio18", "gpio19";
function = "gpio";
@@ -268,7 +274,7 @@
bias-disable;
};
- i2c6_default: i2c6-default {
+ i2c6_default: i2c6-default-state {
pins = "gpio22", "gpio23";
function = "blsp_i2c6";
@@ -276,7 +282,7 @@
bias-disable;
};
- i2c6_sleep: i2c6-sleep {
+ i2c6_sleep: i2c6-sleep-state {
pins = "gpio22", "gpio23";
function = "gpio";
@@ -284,14 +290,14 @@
bias-disable;
};
- pmx-sdc1-clk {
- sdc1_clk_on: clk-on {
+ pmx-sdc1-clk-state {
+ sdc1_clk_on: clk-on-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- sdc1_clk_off: clk-off {
+ sdc1_clk_off: clk-off-pins {
pins = "sdc1_clk";
bias-disable;
@@ -299,14 +305,14 @@
};
};
- pmx-sdc1-cmd {
- sdc1_cmd_on: cmd-on {
+ pmx-sdc1-cmd-state {
+ sdc1_cmd_on: cmd-on-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <10>;
};
- sdc1_cmd_off: cmd-off {
+ sdc1_cmd_off: cmd-off-pins {
pins = "sdc1_cmd";
bias-pull-up;
@@ -314,14 +320,14 @@
};
};
- pmx-sdc1-data {
- sdc1_data_on: data-on {
+ pmx-sdc1-data-state {
+ sdc1_data_on: data-on-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- sdc1_data_off: data-off {
+ sdc1_data_off: data-off-pins {
pins = "sdc1_data";
bias-pull-up;
@@ -329,14 +335,14 @@
};
};
- pmx-sdc2-clk {
- sdc2_clk_on: clk-on {
+ pmx-sdc2-clk-state {
+ sdc2_clk_on: clk-on-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- sdc2_clk_off: clk-off {
+ sdc2_clk_off: clk-off-pins {
pins = "sdc2_clk";
bias-disable;
@@ -344,14 +350,14 @@
};
};
- pmx-sdc2-cmd {
- sdc2_cmd_on: cmd-on {
+ pmx-sdc2-cmd-state {
+ sdc2_cmd_on: cmd-on-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_cmd_off: cmd-off {
+ sdc2_cmd_off: cmd-off-pins {
pins = "sdc2_cmd";
bias-pull-up;
@@ -359,14 +365,14 @@
};
};
- pmx-sdc2-data {
- sdc2_data_on: data-on {
+ pmx-sdc2-data-state {
+ sdc2_data_on: data-on-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_data_off: data-off {
+ sdc2_data_off: data-off-pins {
pins = "sdc2_data";
bias-pull-up;
@@ -374,15 +380,15 @@
};
};
- pmx-sdc2-cd-pin {
- sdc2_cd_on: cd-on {
+ pmx-sdc2-cd-pin-state {
+ sdc2_cd_on: cd-on-pins {
pins = "gpio38";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- sdc2_cd_off: cd-off {
+ sdc2_cd_off: cd-off-pins {
pins = "gpio38";
function = "gpio";
@@ -391,8 +397,8 @@
};
};
- cdc-pdm-lines {
- cdc_pdm_lines_act: pdm-lines-on {
+ cdc-pdm-lines-state {
+ cdc_pdm_lines_act: pdm-lines-on-pins {
pins = "gpio63", "gpio64", "gpio65", "gpio66",
"gpio67", "gpio68";
function = "cdc_pdm0";
@@ -400,7 +406,7 @@
drive-strength = <8>;
bias-disable;
};
- cdc_pdm_lines_sus: pdm-lines-off {
+ cdc_pdm_lines_sus: pdm-lines-off-pins {
pins = "gpio63", "gpio64", "gpio65", "gpio66",
"gpio67", "gpio68";
function = "cdc_pdm0";
@@ -410,15 +416,15 @@
};
};
- ext-pri-tlmm-lines {
- ext_pri_tlmm_lines_act: ext-pa-on {
+ ext-pri-tlmm-lines-state {
+ ext_pri_tlmm_lines_act: ext-pa-on-pins {
pins = "gpio113", "gpio114", "gpio115", "gpio116";
function = "pri_mi2s";
drive-strength = <8>;
bias-disable;
};
- ext_pri_tlmm_lines_sus: ext-pa-off {
+ ext_pri_tlmm_lines_sus: ext-pa-off-pins {
pins = "gpio113", "gpio114", "gpio115", "gpio116";
function = "pri_mi2s";
@@ -427,15 +433,15 @@
};
};
- ext-pri-ws-line {
- ext_pri_ws_act: ext-pa-on {
+ ext-pri-ws-line-state {
+ ext_pri_ws_act: ext-pa-on-pins {
pins = "gpio110";
function = "pri_mi2s_ws";
drive-strength = <8>;
bias-disable;
};
- ext_pri_ws_sus: ext-pa-off {
+ ext_pri_ws_sus: ext-pa-off-pins {
pins = "gpio110";
function = "pri_mi2s_ws";
@@ -444,15 +450,15 @@
};
};
- ext-mclk-tlmm-lines {
- ext_mclk_tlmm_lines_act: mclk-lines-on {
+ ext-mclk-tlmm-lines-state {
+ ext_mclk_tlmm_lines_act: mclk-lines-on-pins {
pins = "gpio116";
function = "pri_mi2s";
drive-strength = <8>;
bias-disable;
};
- ext_mclk_tlmm_lines_sus: mclk-lines-off {
+ ext_mclk_tlmm_lines_sus: mclk-lines-off-pins {
pins = "gpio116";
function = "pri_mi2s";
@@ -462,15 +468,15 @@
};
/* secondary Mi2S */
- ext-sec-tlmm-lines {
- ext_sec_tlmm_lines_act: tlmm-lines-on {
+ ext-sec-tlmm-lines-state {
+ ext_sec_tlmm_lines_act: tlmm-lines-on-pins {
pins = "gpio112", "gpio117", "gpio118", "gpio119";
function = "sec_mi2s";
drive-strength = <8>;
bias-disable;
};
- ext_sec_tlmm_lines_sus: tlmm-lines-off {
+ ext_sec_tlmm_lines_sus: tlmm-lines-off-pins {
pins = "gpio112", "gpio117", "gpio118", "gpio119";
function = "sec_mi2s";
@@ -479,40 +485,38 @@
};
};
- cdc-dmic-lines {
- cdc_dmic_lines_act: dmic-lines-on {
- clk {
- pins = "gpio0";
- function = "dmic0_clk";
+ cdc_dmic_lines_act: cdc-dmic-lines-on-state {
+ clk-pins {
+ pins = "gpio0";
+ function = "dmic0_clk";
- drive-strength = <8>;
- };
- data {
- pins = "gpio1";
- function = "dmic0_data";
+ drive-strength = <8>;
+ };
+ data-pins {
+ pins = "gpio1";
+ function = "dmic0_data";
- drive-strength = <8>;
- };
+ drive-strength = <8>;
};
- cdc_dmic_lines_sus: dmic-lines-off {
- clk {
- pins = "gpio0";
- function = "dmic0_clk";
+ };
+ cdc_dmic_lines_sus: cdc-dmic-lines-off-state {
+ clk-pins {
+ pins = "gpio0";
+ function = "dmic0_clk";
- drive-strength = <2>;
- bias-disable;
- };
- data {
- pins = "gpio1";
- function = "dmic0_data";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ data-pins {
+ pins = "gpio1";
+ function = "dmic0_data";
- drive-strength = <2>;
- bias-disable;
- };
+ drive-strength = <2>;
+ bias-disable;
};
};
- wcnss_pin_a: wcnss-active {
+ wcnss_pin_a: wcnss-active-state {
pins = "gpio40", "gpio41", "gpio42", "gpio43", "gpio44";
function = "wcss_wlan";
@@ -520,7 +524,7 @@
bias-pull-up;
};
- cci0_default: cci0-default {
+ cci0_default: cci0-default-state {
pins = "gpio29", "gpio30";
function = "cci_i2c";
@@ -528,22 +532,22 @@
bias-disable;
};
- camera_front_default: camera-front-default {
- pwdn {
+ camera_front_default: camera-front-default-state {
+ pwdn-pins {
pins = "gpio33";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- rst {
+ rst-pins {
pins = "gpio28";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- mclk1 {
+ mclk1-pins {
pins = "gpio27";
function = "cam_mclk1";
@@ -552,22 +556,22 @@
};
};
- camera_rear_default: camera-rear-default {
- pwdn {
+ camera_rear_default: camera-rear-default-state {
+ pwdn-pins {
pins = "gpio34";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- rst {
+ rst-pins {
pins = "gpio35";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- mclk0 {
+ mclk0-pins {
pins = "gpio26";
function = "cam_mclk0";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi
index 539823b2c36e..8cac23b5240c 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi
@@ -47,7 +47,7 @@
};
&rpm_requests {
- smd_rpm_regulators: pm8916-regulators {
+ smd_rpm_regulators: regulators {
compatible = "qcom,rpm-pm8916-regulators";
/* pm8916_s1 is managed by rpmpd (MSM8916_VDDCX) */
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi
index 3255bd3fcb55..d600916a0e55 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi
@@ -23,6 +23,17 @@
};
};
+ clk_pwm: pwm {
+ compatible = "clk-pwm";
+ #pwm-cells = <2>;
+
+ clocks = <&gcc GCC_GP2_CLK>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&motor_pwm_default>;
+ status = "disabled";
+ };
+
gpio-keys {
compatible = "gpio-keys";
@@ -61,6 +72,24 @@
};
};
+ /*
+ * NOTE: A5 connects GPIO 76 to a reglator powering the motor
+ * driver IC but A3 connects the same signal to an ENABLE pin of
+ * the driver.
+ */
+ reg_motor_vdd: regulator-motor-vdd {
+ compatible = "regulator-fixed";
+ regulator-name = "motor_vdd";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+
+ gpio = <&msmgpio 76 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&motor_en_default>;
+ };
+
reg_vdd_tsp_a: regulator-vdd-tsp-a {
compatible = "regulator-fixed";
regulator-name = "vdd_tsp_a";
@@ -144,7 +173,7 @@
interrupt-parent = <&msmgpio>;
interrupts = <21 IRQ_TYPE_EDGE_RISING>;
- en-gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>;
+ en-gpios = <&msmgpio 20 GPIO_ACTIVE_LOW>;
wake-gpios = <&msmgpio 49 GPIO_ACTIVE_HIGH>;
clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>;
@@ -153,6 +182,16 @@
pinctrl-0 = <&nfc_default &nfc_clk_req>;
};
};
+
+ vibrator: vibrator {
+ compatible = "pwm-vibrator";
+
+ pwms = <&clk_pwm 0 100000>;
+ pwm-names = "enable";
+
+ vcc-supply = <&reg_motor_vdd>;
+ status = "disabled";
+ };
};
&blsp_i2c2 {
@@ -348,7 +387,7 @@
};
&msmgpio {
- accel_int_default: accel-int-default {
+ accel_int_default: accel-int-default-state {
pins = "gpio115";
function = "gpio";
@@ -356,7 +395,7 @@
bias-disable;
};
- fg_alert_default: fg-alert-default {
+ fg_alert_default: fg-alert-default-state {
pins = "gpio121";
function = "gpio";
@@ -364,7 +403,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107", "gpio109";
function = "gpio";
@@ -372,7 +411,7 @@
bias-pull-up;
};
- gpio_hall_sensor_default: gpio-hall-sensor-default {
+ gpio_hall_sensor_default: gpio-hall-sensor-default-state {
pins = "gpio52";
function = "gpio";
@@ -380,47 +419,60 @@
bias-disable;
};
- mdss {
- mdss_default: mdss-default {
- pins = "gpio25";
- function = "gpio";
+ mdss_default: mdss-default-state {
+ pins = "gpio25";
+ function = "gpio";
- drive-strength = <8>;
- bias-disable;
- };
- mdss_sleep: mdss-sleep {
- pins = "gpio25";
- function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ mdss_sleep: mdss-sleep-state {
+ pins = "gpio25";
+ function = "gpio";
- drive-strength = <2>;
- bias-pull-down;
- };
+ drive-strength = <2>;
+ bias-pull-down;
};
- muic_i2c_default: muic-i2c-default {
- pins = "gpio105", "gpio106";
+ motor_en_default: motor-en-default-stae {
+ pins = "gpio76";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- muic_int_default: muic-int-default {
- pins = "gpio12";
+ motor_pwm_default: motor-pwm-default-state {
+ pins = "gpio50";
+ function = "gcc_gp2_clk_a";
+ };
+
+ muic_i2c_default: muic-i2c-default-state {
+ pins = "gpio105", "gpio106";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- nfc_default: nfc-default {
- pins = "gpio20", "gpio49";
+ muic_int_default: muic-int-default-state {
+ pins = "gpio12";
function = "gpio";
drive-strength = <2>;
bias-disable;
+ };
+
+ nfc_default: nfc-default-state {
+ nfc-pins {
+ pins = "gpio20", "gpio49";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
- irq {
+ irq-pins {
pins = "gpio21";
function = "gpio";
@@ -429,7 +481,7 @@
};
};
- nfc_i2c_default: nfc-i2c-default {
+ nfc_i2c_default: nfc-i2c-default-state {
pins = "gpio0", "gpio1";
function = "gpio";
@@ -437,7 +489,7 @@
bias-disable;
};
- tkey_default: tkey-default {
+ tkey_default: tkey-default-state {
pins = "gpio98";
function = "gpio";
@@ -445,7 +497,7 @@
bias-disable;
};
- tkey_i2c_default: tkey-i2c-default {
+ tkey_i2c_default: tkey-i2c-default-state {
pins = "gpio16", "gpio17";
function = "gpio";
@@ -453,7 +505,7 @@
bias-disable;
};
- tsp_en_default: tsp-en-default {
+ tsp_en_default: tsp-en-default-state {
pins = "gpio73";
function = "gpio";
@@ -461,7 +513,7 @@
bias-disable;
};
- ts_int_default: ts-int-default {
+ ts_int_default: ts-int-default-state {
pins = "gpio13";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts
index 6db5f78ca286..c691cca2eb45 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts
@@ -81,6 +81,10 @@
};
};
+&clk_pwm {
+ status = "okay";
+};
+
&dsi0 {
panel@0 {
reg = <0>;
@@ -104,8 +108,12 @@
remote-endpoint = <&panel_in>;
};
+&vibrator {
+ status = "okay";
+};
+
&msmgpio {
- panel_vdd3_default: panel-vdd3-default {
+ panel_vdd3_default: panel-vdd3-default-state {
pins = "gpio9";
function = "gpio";
@@ -113,7 +121,7 @@
bias-disable;
};
- tkey_en_default: tkey-en-default {
+ tkey_en_default: tkey-en-default-state {
pins = "gpio86";
function = "gpio";
@@ -121,7 +129,7 @@
bias-disable;
};
- tkey_led_en_default: tkey-led-en-default {
+ tkey_led_en_default: tkey-led-en-default-state {
pins = "gpio60";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts
index 5fb8ecd0c9ca..3dd819458785 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts
@@ -50,6 +50,10 @@
};
};
+&clk_pwm {
+ status = "okay";
+};
+
&pronto {
iris {
compatible = "qcom,wcn3660b";
@@ -61,8 +65,12 @@
vdd-supply = <&reg_touch_key>;
};
+&vibrator {
+ status = "okay";
+};
+
&msmgpio {
- tkey_en_default: tkey-en-default {
+ tkey_en_default: tkey-en-default-state {
pins = "gpio97";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi
index 542010fdfb8a..c95f0b4bc61f 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi
@@ -26,19 +26,6 @@
};
};
- reg_motor_vdd: regulator-motor-vdd {
- compatible = "regulator-fixed";
- regulator-name = "motor_vdd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
-
- gpio = <&msmgpio 76 GPIO_ACTIVE_HIGH>;
- enable-active-high;
-
- pinctrl-names = "default";
- pinctrl-0 = <&motor_en_default>;
- };
-
reg_touch_key: regulator-touch-key {
compatible = "regulator-fixed";
regulator-name = "touch_key";
@@ -61,21 +48,18 @@
/delete-node/ magnetometer@12;
};
+&reg_motor_vdd {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+};
+
&touchkey {
vcc-supply = <&reg_touch_key>;
vdd-supply = <&reg_touch_key>;
};
&msmgpio {
- motor_en_default: motor-en-default {
- pins = "gpio76";
- function = "gpio";
-
- drive-strength = <2>;
- bias-disable;
- };
-
- tkey_en_default: tkey-en-default {
+ tkey_en_default: tkey-en-default-state {
pins = "gpio97";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts
index bc7134698978..a3d572d851ef 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts
@@ -46,7 +46,7 @@
};
&msmgpio {
- gpio_leds_default: gpio-led-default {
+ gpio_leds_default: gpio-led-default-state {
pins = "gpio60";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts
index eabeed18cfaa..7ac49a021563 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts
@@ -199,7 +199,7 @@
};
&msmgpio {
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107", "gpio109";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts
index bbd6bb3f4fd7..d4984b3af802 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (C) 2019 Stephan Gerhold
+/*
+ * Copyright (C) 2019 Stephan Gerhold
+ */
/dts-v1/;
@@ -422,7 +424,7 @@
};
&msmgpio {
- fg_alert_default: fg-alert-default {
+ fg_alert_default: fg-alert-default-state {
pins = "gpio121";
function = "gpio";
@@ -430,7 +432,7 @@
bias-disable;
};
- gpio_keys_default: gpio-keys-default {
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107", "gpio109";
function = "gpio";
@@ -438,7 +440,7 @@
bias-pull-up;
};
- gpio_hall_sensor_default: gpio-hall-sensor-default {
+ gpio_hall_sensor_default: gpio-hall-sensor-default-state {
pins = "gpio52";
function = "gpio";
@@ -446,7 +448,7 @@
bias-disable;
};
- imu_irq_default: imu-irq-default {
+ imu_irq_default: imu-irq-default-state {
pins = "gpio115";
function = "gpio";
@@ -454,7 +456,7 @@
bias-disable;
};
- muic_i2c_default: muic-i2c-default {
+ muic_i2c_default: muic-i2c-default-state {
pins = "gpio105", "gpio106";
function = "gpio";
@@ -462,7 +464,7 @@
bias-disable;
};
- muic_irq_default: muic-irq-default {
+ muic_irq_default: muic-irq-default-state {
pins = "gpio12";
function = "gpio";
@@ -470,14 +472,15 @@
bias-disable;
};
- nfc_default: nfc-default {
- pins = "gpio20", "gpio49";
- function = "gpio";
-
- drive-strength = <2>;
- bias-disable;
+ nfc_default: nfc-default-state {
+ nfc-pins {
+ pins = "gpio20", "gpio49";
+ function = "gpio";
- irq {
+ drive-strength = <2>;
+ bias-disable;
+ };
+ irq-pins {
pins = "gpio21";
function = "gpio";
@@ -486,7 +489,7 @@
};
};
- nfc_i2c_default: nfc-i2c-default {
+ nfc_i2c_default: nfc-i2c-default-state {
pins = "gpio0", "gpio1";
function = "gpio";
@@ -494,7 +497,7 @@
bias-disable;
};
- tkey_default: tkey-default {
+ tkey_default: tkey-default-state {
pins = "gpio98";
function = "gpio";
@@ -502,7 +505,7 @@
bias-disable;
};
- tkey_en_default: tkey-en-default {
+ tkey_en_default: tkey-en-default-state {
pins = "gpio86";
function = "gpio";
@@ -510,7 +513,7 @@
bias-disable;
};
- tkey_i2c_default: tkey-i2c-default {
+ tkey_i2c_default: tkey-i2c-default-state {
pins = "gpio16", "gpio17";
function = "gpio";
@@ -518,7 +521,7 @@
bias-disable;
};
- tkey_led_en_default: tkey-led-en-default {
+ tkey_led_en_default: tkey-led-en-default-state {
pins = "gpio60";
function = "gpio";
@@ -526,7 +529,7 @@
bias-disable;
};
- tsp_en_default: tsp-en-default {
+ tsp_en_default: tsp-en-default-state {
pins = "gpio73";
function = "gpio";
@@ -534,7 +537,7 @@
bias-disable;
};
- tsp_irq_default: tsp-irq-default {
+ tsp_irq_default: tsp-irq-default-state {
pins = "gpio13";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts
index 84a352dcf9a2..a87be1d95b14 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (C) 2020 Stephan Gerhold
+/*
+ * Copyright (C) 2020 Stephan Gerhold
+ */
/dts-v1/;
@@ -21,6 +23,20 @@
stdout-path = "serial0";
};
+ flash-led-controller {
+ compatible = "ocs,ocp8110";
+ enable-gpios = <&msmgpio 31 GPIO_ACTIVE_HIGH>;
+ flash-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_flash_default>;
+
+ flash_led: led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+ };
+
gpio-keys {
compatible = "gpio-keys";
@@ -272,7 +288,15 @@
};
&msmgpio {
- gpio_keys_default: gpio-keys-default {
+ camera_flash_default: camera-flash-default-state {
+ pins = "gpio31", "gpio32";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
@@ -280,7 +304,7 @@
bias-pull-up;
};
- imu_default: imu-default {
+ imu_default: imu-default-state {
pins = "gpio115";
function = "gpio";
@@ -288,14 +312,15 @@
bias-disable;
};
- touchscreen_default: touchscreen-default {
- pins = "gpio13";
- function = "gpio";
-
- drive-strength = <2>;
- bias-pull-up;
+ touchscreen_default: touchscreen-default-state {
+ touchscreen-pins {
+ pins = "gpio13";
+ function = "gpio";
- reset {
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ reset-pins {
pins = "gpio12";
function = "gpio";
@@ -304,7 +329,7 @@
};
};
- usb_id_default: usb-id-default {
+ usb_id_default: usb-id-default-state {
pins = "gpio110";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index a831064700ee..2ca8e977fc2a 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -1046,7 +1046,6 @@
"pixel",
"core";
phys = <&dsi_phy0>;
- phy-names = "dsi-phy";
#address-cells = <1>;
#size-cells = <0>;
@@ -1070,7 +1069,7 @@
};
};
- dsi_phy0: dsi-phy@1a98300 {
+ dsi_phy0: phy@1a98300 {
compatible = "qcom,dsi-phy-28nm-lp";
reg = <0x01a98300 0xd4>,
<0x01a98500 0x280>,
@@ -1264,21 +1263,21 @@
clock-names = "iface", "bus";
qcom,iommu-secure-id = <17>;
- // vfe:
+ /* VFE */
iommu-ctx@3000 {
compatible = "qcom,msm-iommu-v1-sec";
reg = <0x3000 0x1000>;
interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
};
- // mdp_0:
+ /* MDP_0 */
iommu-ctx@4000 {
compatible = "qcom,msm-iommu-v1-ns";
reg = <0x4000 0x1000>;
interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
};
- // venus_ns:
+ /* VENUS_NS */
iommu-ctx@5000 {
compatible = "qcom,msm-iommu-v1-sec";
reg = <0x5000 0x1000>;
@@ -1297,14 +1296,14 @@
clock-names = "iface", "bus";
qcom,iommu-secure-id = <18>;
- // gfx3d_user:
+ /* GFX3D_USER */
iommu-ctx@1000 {
compatible = "qcom,msm-iommu-v1-ns";
reg = <0x1000 0x1000>;
interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
};
- // gfx3d_priv:
+ /* GFX3D_PRIV */
iommu-ctx@2000 {
compatible = "qcom,msm-iommu-v1-ns";
reg = <0x2000 0x1000>;
@@ -1345,7 +1344,7 @@
};
mpss: remoteproc@4080000 {
- compatible = "qcom,msm8916-mss-pil", "qcom,q6v5-pil";
+ compatible = "qcom,msm8916-mss-pil";
reg = <0x04080000 0x100>,
<0x04020000 0x040>;
@@ -1438,7 +1437,7 @@
lpass: audio-controller@7708000 {
status = "disabled";
- compatible = "qcom,lpass-cpu-apq8016";
+ compatible = "qcom,apq8016-lpass-cpu";
/*
* Note: Unlike the name would suggest, the SEC_I2S_CLK
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 6b992a6d56c1..32349174c4bd 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -460,229 +460,229 @@
interrupt-controller;
#interrupt-cells = <2>;
- uart_console_active: uart-console-active-pins {
+ uart_console_active: uart-console-active-state {
pins = "gpio4", "gpio5";
function = "blsp_uart2";
drive-strength = <2>;
bias-disable;
};
- uart_console_sleep: uart-console-sleep-pins {
+ uart_console_sleep: uart-console-sleep-state {
pins = "gpio4", "gpio5";
function = "blsp_uart2";
drive-strength = <2>;
bias-pull-down;
};
- sdc1_clk_on: sdc1-clk-on-pins {
+ sdc1_clk_on: sdc1-clk-on-state {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- sdc1_clk_off: sdc1-clk-off-pins {
+ sdc1_clk_off: sdc1-clk-off-state {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- sdc1_cmd_on: sdc1-cmd-on-pins {
+ sdc1_cmd_on: sdc1-cmd-on-state {
pins = "sdc1_cmd";
bias-disable;
drive-strength = <10>;
};
- sdc1_cmd_off: sdc1-cmd-off-pins {
+ sdc1_cmd_off: sdc1-cmd-off-state {
pins = "sdc1_cmd";
bias-disable;
drive-strength = <2>;
};
- sdc1_data_on: sdc1-data-on-pins {
+ sdc1_data_on: sdc1-data-on-state {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- sdc1_data_off: sdc1-data-off-pins {
+ sdc1_data_off: sdc1-data-off-state {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- sdc1_rclk_on: sdc1-rclk-on-pins {
+ sdc1_rclk_on: sdc1-rclk-on-state {
pins = "sdc1_rclk";
bias-pull-down;
};
- sdc1_rclk_off: sdc1-rclk-off-pins {
+ sdc1_rclk_off: sdc1-rclk-off-state {
pins = "sdc1_rclk";
bias-pull-down;
};
- sdc2_clk_on: sdc2-clk-on-pins {
+ sdc2_clk_on: sdc2-clk-on-state {
pins = "sdc2_clk";
drive-strength = <16>;
bias-disable;
};
- sdc2_clk_off: sdc2-clk-off-pins {
+ sdc2_clk_off: sdc2-clk-off-state {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- sdc2_cmd_on: sdc2-cmd-on-pins {
+ sdc2_cmd_on: sdc2-cmd-on-state {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_cmd_off: sdc2-cmd-off-pins {
+ sdc2_cmd_off: sdc2-cmd-off-state {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- sdc2_data_on: sdc2-data-on-pins {
+ sdc2_data_on: sdc2-data-on-state {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_data_off: sdc2-data-off-pins {
+ sdc2_data_off: sdc2-data-off-state {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
};
- sdc2_cd_on: cd-on-pins {
+ sdc2_cd_on: cd-on-state {
pins = "gpio133";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- sdc2_cd_off: cd-off-pins {
+ sdc2_cd_off: cd-off-state {
pins = "gpio133";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- gpio_key_default: gpio-key-default-pins {
+ gpio_key_default: gpio-key-default-state {
pins = "gpio85";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- i2c_1_default: i2c-1-default-pins {
+ i2c_1_default: i2c-1-default-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- i2c_1_sleep: i2c-1-sleep-pins {
+ i2c_1_sleep: i2c-1-sleep-state {
pins = "gpio2", "gpio3";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_2_default: i2c-2-default-pins {
+ i2c_2_default: i2c-2-default-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- i2c_2_sleep: i2c-2-sleep-pins {
+ i2c_2_sleep: i2c-2-sleep-state {
pins = "gpio6", "gpio7";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_3_default: i2c-3-default-pins {
+ i2c_3_default: i2c-3-default-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
bias-disable;
};
- i2c_3_sleep: i2c-3-sleep-pins {
+ i2c_3_sleep: i2c-3-sleep-state {
pins = "gpio10", "gpio11";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_4_default: i2c-4-default-pins {
+ i2c_4_default: i2c-4-default-state {
pins = "gpio14", "gpio15";
function = "blsp_i2c4";
drive-strength = <2>;
bias-disable;
};
- i2c_4_sleep: i2c-4-sleep-pins {
+ i2c_4_sleep: i2c-4-sleep-state {
pins = "gpio14", "gpio15";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_5_default: i2c-5-default-pins {
+ i2c_5_default: i2c-5-default-state {
pins = "gpio18", "gpio19";
function = "blsp_i2c5";
drive-strength = <2>;
bias-disable;
};
- i2c_5_sleep: i2c-5-sleep-pins {
+ i2c_5_sleep: i2c-5-sleep-state {
pins = "gpio18", "gpio19";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_6_default: i2c-6-default-pins {
+ i2c_6_default: i2c-6-default-state {
pins = "gpio22", "gpio23";
function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
- i2c_6_sleep: i2c-6-sleep-pins {
+ i2c_6_sleep: i2c-6-sleep-state {
pins = "gpio22", "gpio23";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_7_default: i2c-7-default-pins {
+ i2c_7_default: i2c-7-default-state {
pins = "gpio135", "gpio136";
function = "blsp_i2c7";
drive-strength = <2>;
bias-disable;
};
- i2c_7_sleep: i2c-7-sleep-pins {
+ i2c_7_sleep: i2c-7-sleep-state {
pins = "gpio135", "gpio136";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c_8_default: i2c-8-default-pins {
+ i2c_8_default: i2c-8-default-state {
pins = "gpio98", "gpio99";
function = "blsp_i2c8";
drive-strength = <2>;
bias-disable;
};
- i2c_8_sleep: i2c-8-sleep-pins {
+ i2c_8_sleep: i2c-8-sleep-state {
pins = "gpio98", "gpio99";
function = "gpio";
drive-strength = <2>;
@@ -726,6 +726,250 @@
reg = <0x193f044 0x4>;
};
+ mdss: mdss@1a00000 {
+ compatible = "qcom,mdss";
+
+ reg = <0x1a00000 0x1000>,
+ <0x1ab0000 0x1040>;
+ reg-names = "mdss_phys",
+ "vbif_phys";
+
+ power-domains = <&gcc MDSS_GDSC>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>,
+ <&gcc GCC_MDSS_MDP_CLK>;
+ clock-names = "iface",
+ "bus",
+ "vsync",
+ "core";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ status = "disabled";
+
+ mdp: mdp@1a01000 {
+ compatible = "qcom,msm8953-mdp5", "qcom,mdp5";
+ reg = <0x1a01000 0x89000>;
+ reg-names = "mdp_phys";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ power-domains = <&gcc MDSS_GDSC>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface",
+ "bus",
+ "core",
+ "vsync";
+
+ iommus = <&apps_iommu 0x15>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mdp5_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ mdp5_intf2_out: endpoint {
+ remote-endpoint = <&dsi1_in>;
+ };
+ };
+ };
+ };
+
+ dsi0: dsi@1a94000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x1a94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ assigned-clocks = <&gcc BYTE0_CLK_SRC>,
+ <&gcc PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>,
+ <&dsi0_phy 1>;
+
+ clocks = <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_BYTE0_CLK>,
+ <&gcc GCC_MDSS_PCLK0_CLK>,
+ <&gcc GCC_MDSS_ESC0_CLK>;
+ clock-names = "mdp_core",
+ "iface",
+ "bus",
+ "byte",
+ "pixel",
+ "core";
+
+ phys = <&dsi0_phy>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&mdp5_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi0_phy: phy@1a94400 {
+ compatible = "qcom,dsi-phy-14nm-8953";
+ reg = <0x1a94400 0x100>,
+ <0x1a94500 0x300>,
+ <0x1a94800 0x188>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>, <&xo_board>;
+ clock-names = "iface", "ref";
+
+ status = "disabled";
+ };
+
+ dsi1: dsi@1a96000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x1a96000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <5>;
+
+ assigned-clocks = <&gcc BYTE1_CLK_SRC>,
+ <&gcc PCLK1_CLK_SRC>;
+ assigned-clock-parents = <&dsi1_phy 0>,
+ <&dsi1_phy 1>;
+
+ clocks = <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_BYTE1_CLK>,
+ <&gcc GCC_MDSS_PCLK1_CLK>,
+ <&gcc GCC_MDSS_ESC1_CLK>;
+ clock-names = "mdp_core",
+ "iface",
+ "bus",
+ "byte",
+ "pixel",
+ "core";
+
+ phys = <&dsi1_phy>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi1_in: endpoint {
+ remote-endpoint = <&mdp5_intf2_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi1_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi1_phy: phy@1a96400 {
+ compatible = "qcom,dsi-phy-14nm-8953";
+ reg = <0x1a96400 0x100>,
+ <0x1a96500 0x300>,
+ <0x1a96800 0x188>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>, <&xo_board>;
+ clock-names = "iface", "ref";
+
+ status = "disabled";
+ };
+ };
+
+ apps_iommu: iommu@1e00000 {
+ compatible = "qcom,msm8953-iommu", "qcom,msm-iommu-v1";
+ ranges = <0 0x1e20000 0x20000>;
+
+ clocks = <&gcc GCC_SMMU_CFG_CLK>,
+ <&gcc GCC_APSS_TCU_ASYNC_CLK>;
+ clock-names = "iface", "bus";
+
+ qcom,iommu-secure-id = <17>;
+
+ #address-cells = <1>;
+ #iommu-cells = <1>;
+ #size-cells = <1>;
+
+ /* VFE */
+ iommu-ctx@14000 {
+ compatible = "qcom,msm-iommu-v1-ns";
+ reg = <0x14000 0x1000>;
+ interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ /* MDP_0 */
+ iommu-ctx@15000 {
+ compatible = "qcom,msm-iommu-v1-ns";
+ reg = <0x15000 0x1000>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ /* VENUS_NS */
+ iommu-ctx@16000 {
+ compatible = "qcom,msm-iommu-v1-ns";
+ reg = <0x16000 0x1000>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
spmi_bus: spmi@200f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x200f000 0x1000>,
diff --git a/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-kugo.dts b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-kugo.dts
new file mode 100644
index 000000000000..3fb8e23e4330
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-kugo.dts
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2016-2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@somainline.org>
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+/dts-v1/;
+
+#include "msm8956-sony-xperia-loire.dtsi"
+
+/ {
+ model = "Sony Xperia X Compact";
+ compatible = "sony,kugo-row", "qcom,msm8956";
+ chassis-type = "handset";
+};
+
+&blsp2_i2c2 {
+ status = "okay";
+
+ /* FUSB301 USB-C Controller */
+};
+
+&blsp2_i2c4 {
+ status = "okay";
+
+ /* ST STMVL53L0 ToF @ 29 */
+ /* AMS TCS349 RGBCIR @ 72 */
+};
+
+&pm8950_l1 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-suzu.dts b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-suzu.dts
new file mode 100644
index 000000000000..87d657f6806b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire-suzu.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2016-2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@somainline.org>
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+/dts-v1/;
+
+#include "msm8956-sony-xperia-loire.dtsi"
+
+/ {
+ model = "Sony Xperia X";
+ compatible = "sony,suzu-row", "qcom,msm8956";
+ chassis-type = "handset";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire.dtsi b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire.dtsi
new file mode 100644
index 000000000000..67baced639c9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8956-sony-xperia-loire.dtsi
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2016-2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@somainline.org>
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+#include "msm8956.dtsi"
+
+#include "pm8004.dtsi"
+#include "pm8950.dtsi"
+#include "pmi8950.dtsi"
+
+/ {
+ qcom,msm-id = <266 0x10001>; /* MSM8956 v1.1 */
+ qcom,board-id = <8 0>;
+
+ aliases {
+ mmc0 = &sdhc_1; /* SDC1 eMMC slot */
+ mmc1 = &sdhc_2; /* SDC2 SD card slot */
+ mmc2 = &sdhc_3; /* SDC3 SDIO card slot */
+ serial0 = &blsp2_uart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reserved-memory {
+ cont-splash@83000000 {
+ reg = <0x0 0x83000000 0x0 0x2800000>;
+ };
+
+ ramoops@57f00000 {
+ compatible = "ramoops";
+ reg = <0 0x57f00000 0 0x100000>;
+ record-size = <0x20000>;
+ console-size = <0x40000>;
+ ftrace-size = <0x20000>;
+ pmsg-size = <0x20000>;
+ ecc-size = <16>;
+ };
+ };
+
+ usbphy_1p2: regulator-usbphy-1p2 {
+ compatible = "regulator-fixed";
+ regulator-name = "usbphy-1p2";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ vin-supply = <&vph_pwr>;
+ };
+
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+ regulator-name = "vph-pwr";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&blsp1_i2c4 {
+ status = "okay";
+
+ /* Synaptics RMI4 @ 2c */
+};
+
+&blsp2_uart2 {
+ status = "okay";
+};
+
+&gcc {
+ vdd_gfx-supply = <&pm8004_s5>;
+};
+
+&otg {
+ status = "okay";
+};
+
+&pm8004_spmi_regulators {
+ vdd_s2-supply = <&vph_pwr>;
+ vdd_s5-supply = <&vph_pwr>;
+
+ /* Cluster 1 supply */
+ pm8004_s2: s2 {
+ /* regulator-min-microvolt = <500000>; */
+ /* Set .95V to prevent unstabilities until CPR for this SoC is done */
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1165000>;
+ regulator-name = "vdd_apc1";
+ /* Set always on until the CPU PLL is done */
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ pm8004_s5: s5 {
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1165000>;
+ regulator-enable-ramp-delay = <500>;
+ regulator-name = "vdd_gfx";
+ /* Hack this on until the gpu driver is ready for it */
+ regulator-always-on;
+ };
+};
+
+&pm8950_spmi_regulators {
+ vdd_s5-supply = <&vph_pwr>;
+
+ /* Cluster 0 supply */
+ pm8950_spmi_s5: s5 {
+ /* Set .95V to prevent unstabilities until CPR for this SoC is done */
+ /* regulator-min-microvolt = <790000>; */
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1165000>;
+ regulator-name = "vdd_apc0";
+ /* Set always on until the CPU PLL is done */
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&rpm_requests {
+ pm8950_regulators: regulators {
+ compatible = "qcom,rpm-pm8950-regulators";
+
+ vdd_s1-supply = <&vph_pwr>;
+ vdd_s2-supply = <&vph_pwr>;
+ vdd_s3-supply = <&vph_pwr>;
+ vdd_s4-supply = <&vph_pwr>;
+ vdd_s6-supply = <&vph_pwr>;
+ vdd_l1_l19-supply = <&pm8950_s3>;
+ vdd_l2_l23-supply = <&pm8950_s3>;
+ vdd_l3-supply = <&pm8950_s3>;
+ vdd_l5_l6_l7_l16-supply = <&pm8950_s4>;
+ vdd_l8_l11_l12_l17_l22-supply = <&vph_pwr>;
+
+ pm8950_s1: s1 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1162500>;
+ };
+
+ pm8950_s3: s3 {
+ regulator-min-microvolt = <1325000>;
+ regulator-max-microvolt = <1325000>;
+ regulator-always-on;
+ };
+
+ pm8950_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ pm8950_l1: l1 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ pm8950_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8950_l3: l3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8950_l5: l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-system-load = <290000>;
+ regulator-allow-set-load;
+ };
+
+ pm8950_l6: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8950_l7: l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8950_l8: l8 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ regulator-system-load = <130000>;
+ regulator-allow-set-load;
+ };
+
+ pm8950_l9: l9 {
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2400000>;
+ };
+
+ pm8950_l10: l10 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2900000>;
+ };
+
+ pm8950_l11: l11 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-system-load = <60000>;
+ regulator-allow-set-load;
+ };
+
+ pm8950_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-system-load = <100000>;
+ regulator-allow-set-load;
+ };
+
+ pm8950_l13: l13 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8950_l14: l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8950_l15: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8950_l16: l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8950_l17: l17 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2900000>;
+ };
+
+ pm8950_l22: l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8950_l23: l23 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+ };
+};
+
+&sdhc_1 {
+ /* Toshiba THGBMHG8C4LBAU7 (032G34) */
+ bus-width = <8>;
+ non-removable;
+ vmmc-supply = <&pm8950_l8>;
+ vqmmc-supply = <&pm8950_l5>;
+ status = "okay";
+};
+
+&sdhc_2 {
+ bus-width = <4>;
+ cd-gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&pm8950_l11>;
+ vqmmc-supply = <&pm8950_l12>;
+ status = "okay";
+};
+
+&tlmm {
+ gpio-reserved-ranges = <0 4>;
+};
+
+&usb_hs_phy {
+ vdd-supply = <&usbphy_1p2>;
+ vdda1p8-supply = <&pm8950_l7>;
+ vdda3p3-supply = <&pm8950_l13>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8956.dtsi b/arch/arm64/boot/dts/qcom/msm8956.dtsi
new file mode 100644
index 000000000000..e432512d8716
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8956.dtsi
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2016-2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@collabora.com>
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+#include "msm8976.dtsi"
+
+&pmu {
+ interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+};
+
+/*
+ * You might be wondering.. why is it so empty out there?
+ * Well, the SoCs are almost identical.
+ */
diff --git a/arch/arm64/boot/dts/qcom/msm8976.dtsi b/arch/arm64/boot/dts/qcom/msm8976.dtsi
new file mode 100644
index 000000000000..05dcb30b0779
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8976.dtsi
@@ -0,0 +1,1198 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2016-2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@collabora.com>
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+#include <dt-bindings/clock/qcom,gcc-msm8976.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+
+/ {
+ interrupt-parent = <&intc>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen { };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x0>;
+ enable-method = "psci";
+ cpu-idle-states = <&little_cpu_sleep_0>;
+ capacity-dmips-mhz = <573>;
+ next-level-cache = <&l2_0>;
+ #cooling-cells = <2>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x1>;
+ enable-method = "psci";
+ cpu-idle-states = <&little_cpu_sleep_0>;
+ capacity-dmips-mhz = <573>;
+ next-level-cache = <&l2_0>;
+ #cooling-cells = <2>;
+ };
+
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x2>;
+ enable-method = "psci";
+ cpu-idle-states = <&little_cpu_sleep_0>;
+ capacity-dmips-mhz = <573>;
+ next-level-cache = <&l2_0>;
+ #cooling-cells = <2>;
+ };
+
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x3>;
+ enable-method = "psci";
+ cpu-idle-states = <&little_cpu_sleep_0>;
+ capacity-dmips-mhz = <573>;
+ next-level-cache = <&l2_0>;
+ #cooling-cells = <2>;
+ };
+
+ CPU4: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72";
+ reg = <0x100>;
+ enable-method = "psci";
+ cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ capacity-dmips-mhz = <1024>;
+ next-level-cache = <&l2_1>;
+ #cooling-cells = <2>;
+ };
+
+ CPU5: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72";
+ reg = <0x101>;
+ enable-method = "psci";
+ cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ capacity-dmips-mhz = <1024>;
+ next-level-cache = <&l2_1>;
+ #cooling-cells = <2>;
+ };
+
+ CPU6: cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72";
+ reg = <0x102>;
+ enable-method = "psci";
+ cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ capacity-dmips-mhz = <1024>;
+ next-level-cache = <&l2_1>;
+ #cooling-cells = <2>;
+ };
+
+ CPU7: cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72";
+ reg = <0x103>;
+ enable-method = "psci";
+ cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ capacity-dmips-mhz = <1024>;
+ next-level-cache = <&l2_1>;
+ #cooling-cells = <2>;
+ };
+
+ 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>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ little_cpu_sleep_0: cpu-sleep-0-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "little-power-collapse";
+ arm,psci-suspend-param = <0x40000003>;
+ entry-latency-us = <181>;
+ exit-latency-us = <149>;
+ min-residency-us = <703>;
+ local-timer-stop;
+ };
+
+ big_cpu_sleep_0: cpu-sleep-1-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "big-retention";
+ arm,psci-suspend-param = <0x00000002>;
+ entry-latency-us = <142>;
+ exit-latency-us = <99>;
+ min-residency-us = <242>;
+ };
+
+ big_cpu_sleep_1: cpu-sleep-1-1 {
+ compatible = "arm,idle-state";
+ idle-state-name = "big-power-collapse";
+ arm,psci-suspend-param = <0x40000003>;
+ entry-latency-us = <158>;
+ exit-latency-us = <144>;
+ min-residency-us = <863>;
+ local-timer-stop;
+ };
+ };
+
+ l2_0: l2-cache0 {
+ compatible = "cache";
+ cache-level = <2>;
+ };
+
+ l2_1: l2-cache1 {
+ compatible = "cache";
+ cache-level = <2>;
+ };
+ };
+
+ firmware {
+ scm: scm {
+ compatible = "qcom,scm-msm8976", "qcom,scm";
+ clocks = <&gcc GCC_CRYPTO_CLK>,
+ <&gcc GCC_CRYPTO_AXI_CLK>,
+ <&gcc GCC_CRYPTO_AHB_CLK>;
+ clock-names = "core", "bus", "iface";
+ #reset-cells = <1>;
+
+ qcom,dload-mode = <&tcsr 0x6100>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the size */
+ reg = <0x0 0x80000000 0x0 0x0>;
+ };
+
+ pmu: pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ext-region@85b00000 {
+ reg = <0x0 0x85b00000 0x0 0x500000>;
+ no-map;
+ };
+
+ smem@86300000 {
+ compatible = "qcom,smem";
+ reg = <0x0 0x86300000 0x0 0x100000>;
+ no-map;
+
+ hwlocks = <&tcsr_mutex 3>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ };
+
+ reserved@86400000 {
+ reg = <0x0 0x86400000 0x0 0x800000>;
+ no-map;
+ };
+
+ mpss_mem: mpss@86c00000 {
+ reg = <0x0 0x86c00000 0x0 0x5600000>;
+ no-map;
+ };
+
+ lpass_mem: lpass@8c200000 {
+ reg = <0x0 0x8c200000 0x0 0x1800000>;
+ no-map;
+ };
+
+ venus_mem: memory@8da00000 {
+ reg = <0x0 0x8da00000 0x0 0x2600000>;
+ no-map;
+ };
+
+ tz-apps@8dd00000 {
+ reg = <0x0 0x8dd00000 0x0 0x1400000>;
+ no-map;
+ };
+ };
+
+ smp2p-hexagon {
+ compatible = "qcom,smp2p";
+ interrupts = <GIC_SPI 291 IRQ_TYPE_EDGE_RISING>;
+ qcom,ipc = <&apcs 8 10>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <2>;
+ qcom,smem = <443>, <429>;
+
+ adsp_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ adsp_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-modem {
+ compatible = "qcom,smp2p";
+ interrupts = <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>;
+ qcom,ipc = <&apcs 8 13>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <1>;
+ qcom,smem = <435>, <428>;
+
+ modem_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ modem_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ interrupts = <GIC_SPI 143 IRQ_TYPE_EDGE_RISING>;
+ qcom,ipc = <&apcs 8 17>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <4>;
+ qcom,smem = <451>, <431>;
+
+ wcnss_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ wcnss_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests: rpm-requests {
+ compatible = "qcom,rpm-msm8976";
+ qcom,smd-channels = "rpm_requests";
+
+ rpmcc: clock-controller {
+ compatible = "qcom,rpmcc-msm8976", "qcom,rpmcc";
+ #clock-cells = <1>;
+ };
+
+ rpmpd: power-controller {
+ compatible = "qcom,msm8976-rpmpd";
+ #power-domain-cells = <1>;
+ operating-points-v2 = <&rpmpd_opp_table>;
+
+ rpmpd_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ rpmpd_opp_ret: opp1 {
+ opp-level = <RPM_SMD_LEVEL_RETENTION>;
+ };
+
+ rpmpd_opp_ret_plus: opp2 {
+ opp-level = <RPM_SMD_LEVEL_RETENTION_PLUS>;
+ };
+
+ rpmpd_opp_min_svs: opp3 {
+ opp-level = <RPM_SMD_LEVEL_MIN_SVS>;
+ };
+
+ rpmpd_opp_low_svs: opp4 {
+ opp-level = <RPM_SMD_LEVEL_LOW_SVS>;
+ };
+
+ rpmpd_opp_svs: opp5 {
+ opp-level = <RPM_SMD_LEVEL_SVS>;
+ };
+
+ rpmpd_opp_svs_plus: opp6 {
+ opp-level = <RPM_SMD_LEVEL_SVS_PLUS>;
+ };
+
+ rpmpd_opp_nom: opp7 {
+ opp-level = <RPM_SMD_LEVEL_NOM>;
+ };
+
+ rpmpd_opp_nom_plus: opp8 {
+ opp-level = <RPM_SMD_LEVEL_NOM_PLUS>;
+ };
+
+ rpmpd_opp_turbo: opp9 {
+ opp-level = <RPM_SMD_LEVEL_TURBO>;
+ };
+
+ rpmpd_opp_turbo_no_cpr: opp10 {
+ opp-level = <RPM_SMD_LEVEL_TURBO_NO_CPR>;
+ };
+
+ rpmpd_opp_turbo_high: opp111 {
+ opp-level = <RPM_SMD_LEVEL_TURBO_HIGH>;
+ };
+ };
+ };
+ };
+ };
+ };
+
+ smsm {
+ compatible = "qcom,smsm";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ipc-1 = <&apcs 8 12>;
+ qcom,ipc-2 = <&apcs 8 9>;
+ qcom,ipc-3 = <&apcs 8 18>;
+
+ apps_smsm: apps@0 {
+ reg = <0>;
+ #qcom,smem-state-cells = <1>;
+ };
+
+ hexagon_smsm: hexagon@1 {
+ reg = <1>;
+ interrupts = <0 290 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ wcnss_smsm: wcnss@6 {
+ reg = <6>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ soc: soc@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+
+ rng@22000 {
+ compatible = "qcom,prng";
+ reg = <0x00022000 0x140>;
+ clocks = <&gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "core";
+ };
+
+ rpm_msg_ram: sram@60000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00060000 0x8000>;
+ };
+
+ usb_hs_phy: phy@6c000 {
+ compatible = "qcom,usb-hs-28nm-femtophy";
+ reg = <0x0006c000 0x200>;
+ #phy-cells = <0>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&gcc GCC_USB_HS_PHY_CFG_AHB_CLK>,
+ <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
+ clock-names = "ref", "ahb", "sleep";
+ resets = <&gcc RST_QUSB2_PHY_BCR>,
+ <&gcc RST_USB2_HS_PHY_ONLY_BCR>;
+ reset-names = "phy", "por";
+ status = "disabled";
+ };
+
+ qfprom: qfprom@a4000 {
+ compatible = "qcom,msm8976-qfprom", "qcom,qfprom";
+ reg = <0x000a4000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ tsens_caldata: caldata@218 {
+ reg = <0x218 0x18>;
+ };
+ };
+
+ tsens: thermal-sensor@4a9000 {
+ compatible = "qcom,msm8976-tsens", "qcom,tsens-v1";
+ reg = <0x004a9000 0x1000>, /* TM */
+ <0x004a8000 0x1000>; /* SROT */
+ interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "uplow";
+ nvmem-cells = <&tsens_caldata>;
+ nvmem-cell-names = "calib";
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ tlmm: pinctrl@1000000 {
+ compatible = "qcom,msm8976-pinctrl";
+ reg = <0x01000000 0x300000>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&tlmm 0 0 145>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ spi1_default: spi0-default-state {
+ spi-pins {
+ pins = "gpio0", "gpio1", "gpio3";
+ function = "blsp_spi1";
+ drive-strength = <12>;
+ bias-disable;
+ };
+
+ cs-pins {
+ pins = "gpio2";
+ function = "blsp_spi1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ spi1_sleep: spi0-sleep-state {
+ spi-pins {
+ pins = "gpio0", "gpio1", "gpio3";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cs-pins {
+ pins = "gpio2";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_i2c2_default: blsp1-i2c2-default-state {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp1_i2c2_sleep: blsp1-i2c2-sleep-state {
+ pins = "gpio6", "gpio7";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp1_i2c4_default: blsp1-i2c4-default-state {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp1_i2c4_sleep: blsp1-i2c4-sleep-state {
+ pins = "gpio14", "gpio15";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp2_uart2_active: blsp2-uart2-active-state {
+ pins = "gpio20", "gpio21";
+ function = "blsp_uart6";
+ drive-strength = <4>;
+ bias-disable;
+ };
+
+ blsp2_uart2_sleep: blsp2-uart2-sleep-state {
+ pins = "gpio20", "gpio21";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ /* 4 (not 6!) interfaces per QUP, BLSP2 indexes are numbered (n)+4 */
+ blsp2_i2c2_default: blsp2-i2c2-default-state {
+ pins = "gpio22", "gpio23";
+ function = "blsp_i2c6";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp2_i2c2_sleep: blsp2-i2c2-sleep-state {
+ pins = "gpio22", "gpio23";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp2_i2c4_default: blsp2-i2c4-default-state {
+ pins = "gpio18", "gpio19";
+ function = "blsp_i2c8";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ blsp2_i2c4_sleep: blsp2-i2c4-sleep-state {
+ pins = "gpio18", "gpio19";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ gcc: clock-controller@1800000 {
+ compatible = "qcom,gcc-msm8976";
+ reg = <0x01800000 0x80000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+
+ assigned-clocks = <&gcc GPLL3>;
+ assigned-clock-rates = <1100000000>;
+
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&rpmcc RPM_SMD_XO_A_CLK_SRC>,
+ <0>,
+ <0>,
+ <0>,
+ <0>;
+ clock-names = "xo",
+ "xo_a",
+ "dsi0pll",
+ "dsi0pllbyte",
+ "dsi1pll",
+ "dsi1pllbyte";
+ };
+
+ tcsr_mutex: hwlock@1905000 {
+ compatible = "qcom,tcsr-mutex";
+ reg = <0x01905000 0x20000>;
+ #hwlock-cells = <1>;
+ };
+
+ tcsr: syscon@1937000 {
+ compatible = "qcom,msm8976-tcsr", "syscon";
+ reg = <0x01937000 0x30000>;
+ };
+
+ spmi_bus: spmi@200f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x0200f000 0x1000>,
+ <0x02400000 0x800000>,
+ <0x02c00000 0x800000>,
+ <0x03800000 0x200000>,
+ <0x0200a000 0x2100>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "periph_irq";
+ qcom,channel = <0>;
+ qcom,ee = <0>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ cell-index = <0>;
+ };
+
+ sdhc_1: mmc@7824000 {
+ compatible = "qcom,msm8976-sdhci", "qcom,sdhci-msm-v4";
+ reg = <0x07824900 0x500>, <0x07824000 0x800>;
+ reg-names = "hc", "core";
+
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+ <&gcc GCC_SDCC1_APPS_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "core", "xo";
+ status = "disabled";
+ };
+
+ sdhc_2: mmc@7864000 {
+ compatible = "qcom,msm8976-sdhci", "qcom,sdhci-msm-v4";
+ reg = <0x07864900 0x11c>, <0x07864000 0x800>;
+ reg-names = "hc", "core";
+
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+ <&gcc GCC_SDCC2_APPS_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "core", "xo";
+ status = "disabled";
+ };
+
+ blsp1_dma: dma-controller@7884000 {
+ compatible = "qcom,bam-v1.7.0";
+ reg = <0x07884000 0x1f000>;
+ interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <0>;
+ };
+
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x078af000 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";
+ dmas = <&blsp1_dma 0>, <&blsp1_dma 1>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ blsp1_uart2: serial@78b0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x078b0000 0x200>;
+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ dmas = <&blsp1_dma 2>, <&blsp1_dma 3>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ blsp1_spi1: spi@78b5000 {
+ compatible = "qcom,spi-qup-v2.2.1";
+ reg = <0x078b5000 0x500>;
+ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ dmas = <&blsp1_dma 4>, <&blsp1_dma 5>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&spi1_default>;
+ pinctrl-1 = <&spi1_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ blsp1_i2c2: i2c@78b6000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x078b6000 0x500>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ clock-frequency = <400000>;
+ dmas = <&blsp1_dma 6>, <&blsp1_dma 7>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp1_i2c2_default>;
+ pinctrl-1 = <&blsp1_i2c2_default>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ blsp1_i2c4: i2c@78b8000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x078b8000 0x500>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ clock-frequency = <400000>;
+ dmas = <&blsp1_dma 10>, <&blsp1_dma 11>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp1_i2c4_default>;
+ pinctrl-1 = <&blsp1_i2c4_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ otg: usb@78db000 {
+ compatible = "qcom,ci-hdrc";
+ reg = <0x078db000 0x200>,
+ <0x078db200 0x200>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_USB_HS_AHB_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>;
+ clock-names = "iface", "core";
+ assigned-clocks = <&gcc GCC_USB_HS_SYSTEM_CLK>;
+ assigned-clock-rates = <80000000>;
+ resets = <&gcc RST_USB_HS_BCR>;
+ reset-names = "core";
+ ahb-burst-config = <0>;
+ dr_mode = "peripheral";
+ phy_type = "ulpi";
+ phy-names = "usb-phy";
+ phys = <&usb_hs_phy>;
+ status = "disabled";
+ #reset-cells = <1>;
+ };
+
+ sdhc_3: mmc@7a24000 {
+ compatible = "qcom,msm8976-sdhci", "qcom,sdhci-msm-v4";
+ reg = <0x07a24900 0x11c>, <0x07a24000 0x800>;
+ reg-names = "hc", "core";
+
+ interrupts = <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC3_AHB_CLK>,
+ <&gcc GCC_SDCC3_APPS_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "core", "xo";
+
+ status = "disabled";
+ };
+
+ blsp2_dma: dma-controller@7ac4000 {
+ compatible = "qcom,bam-v1.7.0";
+ reg = <0x07ac4000 0x1f000>;
+ interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <0>;
+ };
+
+ blsp2_uart2: serial@7af0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x07af0000 0x200>;
+ interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+ dmas = <&blsp2_dma 0>, <&blsp2_dma 1>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ blsp2_i2c2: i2c@7af6000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x07af6000 0x600>;
+ interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+ clock-frequency = <400000>;
+ dmas = <&blsp2_dma 6>, <&blsp2_dma 7>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_i2c2_default>;
+ pinctrl-1 = <&blsp2_i2c2_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ blsp2_i2c4: i2c@7af8000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x07af8000 0x600>;
+ interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP2_QUP4_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+ clock-frequency = <400000>;
+ dmas = <&blsp2_dma 10>, <&blsp2_dma 11>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_i2c4_default>;
+ pinctrl-1 = <&blsp2_i2c4_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ intc: interrupt-controller@b000000 {
+ compatible = "qcom,msm-qgic2";
+ reg = <0x0b000000 0x1000>, <0x0b002000 0x1000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ apcs: mailbox@b011000 {
+ compatible = "qcom,msm8976-apcs-kpss-global", "syscon";
+ reg = <0x0b011000 0x1000>;
+ #mbox-cells = <1>;
+ };
+
+ timer@b120000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0b120000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <19200000>;
+
+ frame@b121000 {
+ reg = <0x0b121000 0x1000>, <0x0b122000 0x1000>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <0>;
+ };
+
+ frame@b123000 {
+ reg = <0x0b123000 0x1000>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <1>;
+ status = "disabled";
+ };
+
+ frame@b124000 {
+ reg = <0x0b124000 0x1000>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <2>;
+ status = "disabled";
+ };
+
+ frame@b125000 {
+ reg = <0x0b125000 0x1000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <3>;
+ status = "disabled";
+ };
+
+ frame@b126000 {
+ reg = <0x0b126000 0x1000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <4>;
+ status = "disabled";
+ };
+
+ frame@b127000 {
+ reg = <0x0b127000 0x1000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <5>;
+ status = "disabled";
+ };
+
+ frame@b128000 {
+ reg = <0x0b128000 0x1000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <6>;
+ status = "disabled";
+ };
+ };
+
+ imem: sram@8600000 {
+ compatible = "qcom,msm8976-imem", "syscon", "simple-mfd";
+ reg = <0x08600000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0 0x08600000 0x1000>;
+
+ pil-reloc@94c {
+ compatible = "qcom,pil-reloc-info";
+ reg = <0x94c 0xc8>;
+ };
+ };
+ };
+
+ thermal-zones {
+ aoss0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 0>;
+
+ trips {
+ aoss0_alert0: trip-point0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ modem-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 1>;
+ trips {
+ modem_alert0: trip-point0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ qdsp-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 2>;
+ trips {
+ qdsp_alert0: trip-point0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ cam-isp-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 3>;
+ trips {
+ cam_isp_alert0: trip-point0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ cpu4-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 4>;
+
+ trips {
+ cpu4_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ cpu4_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu4_crit: cpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu5-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 5>;
+
+ trips {
+ cpu5_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ cpu5_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu5_crit: cpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu6-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 6>;
+
+ trips {
+ cpu6_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ cpu6_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu6_crit: cpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu7-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 7>;
+
+ trips {
+ cpu7_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ cpu7_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu7_crit: cpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ big-l2-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 8>;
+
+ trips {
+ l2_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ l2_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ l2_crit: l2-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu0-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 9>;
+
+ trips {
+ cpu0_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ cpu0_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu0_crit: cpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ gpu-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&tsens 10>;
+
+ trips {
+ gpu_alert0: trip-point0 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ gpu_alert1: trip-point1 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ gpu_crit: gpu-crit {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ clock-frequency = <19200000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-10.dts b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-10.dts
index 7e6bce4af441..4159fc35571a 100644
--- a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-10.dts
+++ b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-10.dts
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) Jean Thomas <virgule@jeanthomas.me>
+/*
+ * Copyright (c) Jean Thomas <virgule@jeanthomas.me>
*/
/dts-v1/;
diff --git a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-101.dts
index e6a5ebd30e2f..ad9702dd171b 100644
--- a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-101.dts
+++ b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead-rev-101.dts
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) Jean Thomas <virgule@jeanthomas.me>
+/*
+ * Copyright (c) Jean Thomas <virgule@jeanthomas.me>
*/
/dts-v1/;
diff --git a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
index 71e373b11de9..87c90e93667f 100644
--- a/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015, LGE Inc. All rights reserved.
+/*
+ * Copyright (c) 2015, LGE Inc. All rights reserved.
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
* Copyright (c) 2021, Petr Vorel <petr.vorel@gmail.com>
*/
@@ -58,7 +59,7 @@
};
&rpm_requests {
- pm8994_regulators: pm8994-regulators {
+ pm8994_regulators: regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_l1-supply = <&pm8994_s1>;
@@ -236,9 +237,11 @@
};
pm8994_l26: l26 {
- /* TODO: value from downstream
- regulator-min-microvolt = <987500>;
- fails to apply */
+ /*
+ * TODO: value from downstream
+ * regulator-min-microvolt = <987500>;
+ * fails to apply
+ */
};
pm8994_l27: l27 {
@@ -252,19 +255,19 @@
};
pm8994_l29: l29 {
- /* TODO: Unsupported voltage range.
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- qcom,init-voltage = <2800000>;
- */
+ /*
+ * TODO: Unsupported voltage range.
+ * regulator-min-microvolt = <2800000>;
+ * regulator-max-microvolt = <2800000>;
+ */
};
pm8994_l30: l30 {
- /* TODO: get this verified
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,init-voltage = <1800000>;
- */
+ /*
+ * TODO: get this verified
+ * regulator-min-microvolt = <1800000>;
+ * regulator-max-microvolt = <1800000>;
+ */
};
pm8994_l31: l31 {
@@ -273,15 +276,15 @@
};
pm8994_l32: l32 {
- /* TODO: get this verified
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,init-voltage = <1800000>;
- */
+ /*
+ * TODO: get this verified
+ * regulator-min-microvolt = <1800000>;
+ * regulator-max-microvolt = <1800000>;
+ */
};
};
- pmi8994_regulators: pmi8994-regulators {
+ pmi8994_regulators: regulators-1 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
diff --git a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
index c4e87d0aec42..b242c272d2af 100644
--- a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
+++ b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
@@ -153,7 +153,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_l1-supply = <&pm8994_s7>;
@@ -363,7 +363,7 @@
pm8994_lvs2: lvs2 {};
};
- pmi8994_regulators: pmi8994-regulators {
+ pmi8994_regulators: regulators-1 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
vdd_bst_byp-supply = <&vph_pwr>;
diff --git a/arch/arm64/boot/dts/qcom/msm8992.dtsi b/arch/arm64/boot/dts/qcom/msm8992.dtsi
index 750643763a76..10adb4986ef1 100644
--- a/arch/arm64/boot/dts/qcom/msm8992.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8992.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*/
#include "msm8994.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts
index dbfbb77e9ff5..85abff0e9b3f 100644
--- a/arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts
+++ b/arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015, Huawei Inc. All rights reserved.
+/*
+ * Copyright (c) 2015, Huawei Inc. All rights reserved.
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, Petr Vorel <petr.vorel@gmail.com>
*/
diff --git a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi
index f9d8bd09e074..9b67f0d3820c 100644
--- a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi
@@ -551,7 +551,7 @@
&rpm_requests {
/* These values were taken from the original firmware ACPI tables */
- pm8994_regulators: pm8994-regulators {
+ pm8994_regulators: regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -835,7 +835,7 @@
vreg_lvs2a_1p8: lvs2 { };
};
- pmi8994_regulators: pmi8994-regulators {
+ pmi8994_regulators: regulators-1 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -881,28 +881,28 @@
};
&tlmm {
- grip_default: grip-default {
+ grip_default: grip-default-state {
pins = "gpio39";
function = "gpio";
drive-strength = <6>;
bias-pull-down;
};
- grip_sleep: grip-sleep {
+ grip_sleep: grip-sleep-state {
pins = "gpio39";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- hall_front_default: hall-front-default {
+ hall_front_default: hall-front-default-state {
pins = "gpio42";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- hall_back_default: hall-back-default {
+ hall_back_default: hall-back-default-state {
pins = "gpio75";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi b/arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi
index ff60b7004d26..f3d153c34918 100644
--- a/arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi
@@ -186,7 +186,7 @@
&rpm_requests {
/* PMI8994 should probe first, because pmi8994_bby supplies some of PM8994's regulators */
- pmi8994_regulators: pmi8994-regulators {
+ pmi8994_regulators: regulators-0 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -205,7 +205,7 @@
};
};
- pm8994_regulators: pm8994-regulators {
+ pm8994_regulators: regulators-1 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s3-supply = <&vph_pwr>;
@@ -477,15 +477,17 @@
};
&tlmm {
- ts_int_active: ts-int-active {
+ ts_int_active: ts-int-active-state {
pins = "gpio42";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
input-enable;
};
- ts_reset_active: ts-reset-active {
+ ts_reset_active: ts-reset-active-state {
pins = "gpio109";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
output-low;
diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi
index ded5b7ceeaf9..9ff9d35496d2 100644
--- a/arch/arm64/boot/dts/qcom/msm8994.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -553,7 +554,6 @@
clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>,
<&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
- spi-max-frequency = <19200000>;
dmas = <&blsp1_dma 12>, <&blsp1_dma 13>;
dma-names = "tx", "rx";
pinctrl-names = "default", "sleep";
@@ -691,7 +691,6 @@
clocks = <&gcc GCC_BLSP2_QUP4_SPI_APPS_CLK>,
<&gcc GCC_BLSP2_AHB_CLK>;
clock-names = "core", "iface";
- spi-max-frequency = <19200000>;
dmas = <&blsp2_dma 18>, <&blsp2_dma 19>;
dma-names = "tx", "rx";
pinctrl-names = "default", "sleep";
@@ -773,254 +772,256 @@
interrupt-controller;
#interrupt-cells = <2>;
- blsp1_uart2_default: blsp1-uart2-default {
- function = "blsp_uart2";
+ blsp1_uart2_default: blsp1-uart2-default-state {
pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
drive-strength = <16>;
bias-disable;
};
- blsp1_uart2_sleep: blsp1-uart2-sleep {
- function = "gpio";
+ blsp1_uart2_sleep: blsp1-uart2-sleep-state {
pins = "gpio4", "gpio5";
+ function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- blsp2_uart2_default: blsp2-uart2-default {
+ blsp2_uart2_default: blsp2-uart2-default-state {
+ pins = "gpio45", "gpio46", "gpio47", "gpio48";
function = "blsp_uart8";
- pins = "gpio45", "gpio46",
- "gpio47", "gpio48";
drive-strength = <16>;
bias-disable;
};
- blsp2_uart2_sleep: blsp2-uart2-sleep {
+ blsp2_uart2_sleep: blsp2-uart2-sleep-state {
+ pins = "gpio45", "gpio46", "gpio47", "gpio48";
function = "gpio";
- pins = "gpio45", "gpio46",
- "gpio47", "gpio48";
drive-strength = <2>;
bias-disable;
};
- i2c1_default: i2c1-default {
- function = "blsp_i2c1";
+ i2c1_default: i2c1-default-state {
pins = "gpio2", "gpio3";
+ function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- i2c1_sleep: i2c1-sleep {
- function = "gpio";
+ i2c1_sleep: i2c1-sleep-state {
pins = "gpio2", "gpio3";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c2_default: i2c2-default {
- function = "blsp_i2c2";
+ i2c2_default: i2c2-default-state {
pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- i2c2_sleep: i2c2-sleep {
- function = "gpio";
+ i2c2_sleep: i2c2-sleep-state {
pins = "gpio6", "gpio7";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c4_default: i2c4-default {
- function = "blsp_i2c4";
+ i2c4_default: i2c4-default-state {
pins = "gpio19", "gpio20";
+ function = "blsp_i2c4";
drive-strength = <2>;
bias-disable;
};
- i2c4_sleep: i2c4-sleep {
- function = "gpio";
+ i2c4_sleep: i2c4-sleep-state {
pins = "gpio19", "gpio20";
+ function = "gpio";
drive-strength = <2>;
bias-pull-down;
input-enable;
};
- i2c5_default: i2c5-default {
- function = "blsp_i2c5";
+ i2c5_default: i2c5-default-state {
pins = "gpio23", "gpio24";
+ function = "blsp_i2c5";
drive-strength = <2>;
bias-disable;
};
- i2c5_sleep: i2c5-sleep {
- function = "gpio";
+ i2c5_sleep: i2c5-sleep-state {
pins = "gpio23", "gpio24";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c6_default: i2c6-default {
- function = "blsp_i2c6";
+ i2c6_default: i2c6-default-state {
pins = "gpio28", "gpio27";
+ function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
- i2c6_sleep: i2c6-sleep {
- function = "gpio";
+ i2c6_sleep: i2c6-sleep-state {
pins = "gpio28", "gpio27";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c7_default: i2c7-default {
- function = "blsp_i2c7";
+ i2c7_default: i2c7-default-state {
pins = "gpio44", "gpio43";
+ function = "blsp_i2c7";
drive-strength = <2>;
bias-disable;
};
- i2c7_sleep: i2c7-sleep {
- function = "gpio";
+ i2c7_sleep: i2c7-sleep-state {
pins = "gpio44", "gpio43";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp2_spi10_default: blsp2-spi10-default {
- default {
- function = "blsp_spi10";
+ blsp2_spi10_default: blsp2-spi10-default-state {
+ default-pins {
pins = "gpio53", "gpio54", "gpio55";
+ function = "blsp_spi10";
drive-strength = <10>;
bias-pull-down;
};
- cs {
+
+ cs-pins {
+ pins = "gpio67";
function = "gpio";
- pins = "gpio55";
drive-strength = <2>;
bias-disable;
};
};
- blsp2_spi10_sleep: blsp2-spi10-sleep {
+ blsp2_spi10_sleep: blsp2-spi10-sleep-state {
pins = "gpio53", "gpio54", "gpio55";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- i2c11_default: i2c11-default {
- function = "blsp_i2c11";
+ i2c11_default: i2c11-default-state {
pins = "gpio83", "gpio84";
+ function = "blsp_i2c11";
drive-strength = <2>;
bias-disable;
};
- i2c11_sleep: i2c11-sleep {
- function = "gpio";
+ i2c11_sleep: i2c11-sleep-state {
pins = "gpio83", "gpio84";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp1_spi1_default: blsp1-spi1-default {
- default {
- function = "blsp_spi1";
+ blsp1_spi1_default: blsp1-spi1-default-state {
+ default-pins {
pins = "gpio0", "gpio1", "gpio3";
+ function = "blsp_spi1";
drive-strength = <10>;
bias-pull-down;
};
- cs {
- function = "gpio";
+
+ cs-pins {
pins = "gpio8";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
};
- blsp1_spi1_sleep: blsp1-spi1-sleep {
+ blsp1_spi1_sleep: blsp1-spi1-sleep-state {
pins = "gpio0", "gpio1", "gpio3";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- sdc1_clk_on: clk-on {
+ sdc1_clk_on: clk-on-state {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- sdc1_clk_off: clk-off {
+ sdc1_clk_off: clk-off-state {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- sdc1_cmd_on: cmd-on {
+ sdc1_cmd_on: cmd-on-state {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <8>;
};
- sdc1_cmd_off: cmd-off {
+ sdc1_cmd_off: cmd-off-state {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- sdc1_data_on: data-on {
+ sdc1_data_on: data-on-state {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <8>;
};
- sdc1_data_off: data-off {
+ sdc1_data_off: data-off-state {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- sdc1_rclk_on: rclk-on {
+ sdc1_rclk_on: rclk-on-state {
pins = "sdc1_rclk";
bias-pull-down;
};
- sdc1_rclk_off: rclk-off {
+ sdc1_rclk_off: rclk-off-state {
pins = "sdc1_rclk";
bias-pull-down;
};
- sdc2_clk_on: sdc2-clk-on {
+ sdc2_clk_on: sdc2-clk-on-state {
pins = "sdc2_clk";
bias-disable;
drive-strength = <10>;
};
- sdc2_clk_off: sdc2-clk-off {
+ sdc2_clk_off: sdc2-clk-off-state {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- sdc2_cmd_on: sdc2-cmd-on {
+ sdc2_cmd_on: sdc2-cmd-on-state {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_cmd_off: sdc2-cmd-off {
+ sdc2_cmd_off: sdc2-cmd-off-state {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- sdc2_data_on: sdc2-data-on {
+ sdc2_data_on: sdc2-data-on-state {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
- sdc2_data_off: sdc2-data-off {
+ sdc2_data_off: sdc2-data-off-state {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/msm8996-oneplus-common.dtsi
new file mode 100644
index 000000000000..20f5c103c63b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8996-oneplus-common.dtsi
@@ -0,0 +1,787 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Harry Austen <hpausten@protonmail.com>
+ */
+
+#include "msm8996.dtsi"
+#include "pm8994.dtsi"
+#include "pmi8994.dtsi"
+#include "pmi8996.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
+#include <dt-bindings/sound/qcom,wcd9335.h>
+
+/ {
+ aliases {
+ serial0 = &blsp1_uart2;
+ serial1 = &blsp2_uart2;
+ };
+
+ battery: battery {
+ compatible = "simple-battery";
+
+ constant-charge-current-max-microamp = <3000000>;
+ voltage-min-design-microvolt = <3400000>;
+ };
+
+ chosen {
+ stdout-path = "serial1:115200n8";
+ };
+
+ clocks {
+ div1_mclk: div1-clk {
+ compatible = "gpio-gate-clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&audio_mclk>;
+ #clock-cells = <0>;
+ clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
+ enable-gpios = <&pm8994_gpios 15 GPIO_ACTIVE_HIGH>;
+ };
+
+ divclk4: div4-clk {
+ compatible = "fixed-clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&divclk4_pin_a>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "divclk4";
+ };
+ };
+
+ reserved-memory {
+ ramoops@ac000000 {
+ compatible = "ramoops";
+ reg = <0 0xac000000 0 0x200000>;
+ record-size = <0x20000>;
+ console-size = <0x100000>;
+ pmsg-size = <0x80000>;
+ };
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ wlan_en: wlan-en-regulator {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_en_gpios>;
+ regulator-name = "wlan-en-regulator";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ gpio = <&pm8994_gpios 8 GPIO_ACTIVE_HIGH>;
+
+ /* WLAN card specific delay */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+};
+
+&adsp_pil {
+ status = "okay";
+};
+
+&blsp1_i2c3 {
+ status = "okay";
+
+ tfa9890_amp: audio-codec@36 {
+ compatible = "nxp,tfa9890";
+ reg = <0x36>;
+ #sound-dai-cells = <0>;
+ };
+};
+
+&blsp1_i2c6 {
+ status = "okay";
+
+ bq27541: fuel-gauge@55 {
+ compatible = "ti,bq27541";
+ reg = <0x55>;
+ };
+};
+
+&blsp1_uart2 {
+ label = "BT-UART";
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "qcom,qca6174-bt";
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_en_gpios>;
+ enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>;
+ clocks = <&divclk4>;
+ };
+};
+
+&blsp2_i2c1 {
+ status = "okay";
+};
+
+&blsp2_i2c6 {
+ status = "okay";
+
+ synaptics_rmi4_i2c: touchscreen@20 {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts-extended = <&tlmm 125 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&touch_default>;
+ pinctrl-1 = <&touch_suspend>;
+ vdd-supply = <&vreg_l22a_3p0>;
+ vio-supply = <&vreg_s4a_1p8>;
+ syna,reset-delay-ms = <200>;
+ syna,startup-delay-ms = <200>;
+
+ rmi4-f01@1 {
+ reg = <0x1>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f12@12 {
+ reg = <0x12>;
+ syna,sensor-type = <1>;
+ touchscreen-x-mm = <68>;
+ touchscreen-y-mm = <122>;
+ };
+ };
+};
+
+&blsp2_uart2 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_uart2_2pins_default>;
+ pinctrl-1 = <&blsp2_uart2_2pins_sleep>;
+ status = "okay";
+};
+
+&camss {
+ vdda-supply = <&vreg_l2a_1p25>;
+};
+
+&dsi0 {
+ vdda-supply = <&vreg_l2a_1p25>;
+ vcca-supply = <&vreg_l22a_3p0>;
+ status = "okay";
+};
+
+&dsi0_out {
+ data-lanes = <0 1 2 3>;
+};
+
+&dsi0_phy {
+ vdda-supply = <&vreg_l2a_1p25>;
+ vcca-supply = <&vreg_l28a_0p925>;
+ status = "okay";
+};
+
+&gpu {
+ status = "okay";
+};
+
+&hsusb_phy1 {
+ vdd-supply = <&vreg_l28a_0p925>;
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+ status = "okay";
+};
+
+&hsusb_phy2 {
+ vdd-supply = <&vreg_l28a_0p925>;
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+ status = "okay";
+};
+
+&mdp {
+ status = "okay";
+};
+
+&mdss {
+ status = "okay";
+};
+
+&mmcc {
+ vdd-gfx-supply = <&vdd_gfx>;
+};
+
+&mss_pil {
+ pll-supply = <&vreg_l12a_1p8>;
+ status = "okay";
+};
+
+&pcie0 {
+ perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
+ vddpe-3v3-supply = <&wlan_en>;
+ vdda-supply = <&vreg_l28a_0p925>;
+ status = "okay";
+};
+
+&pcie_phy {
+ vdda-phy-supply = <&vreg_l28a_0p925>;
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ status = "okay";
+};
+
+&pm8994_gpios {
+ bt_en_gpios: bt-en-gpios-state {
+ pins = "gpio19";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ power-source = <PM8994_GPIO_S4>;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
+ bias-pull-down;
+ };
+
+ wlan_en_gpios: wlan-en-gpios-state {
+ pins = "gpio8";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ power-source = <PM8994_GPIO_S4>;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
+ bias-pull-down;
+ };
+
+ audio_mclk: divclk1-state {
+ pins = "gpio15";
+ function = PMIC_GPIO_FUNC_FUNC1;
+ power-source = <PM8994_GPIO_S4>;
+ };
+
+ divclk4_pin_a: divclk4-state {
+ pins = "gpio18";
+ function = PMIC_GPIO_FUNC_FUNC2;
+ bias-disable;
+ power-source = <PM8994_GPIO_S4>;
+ };
+};
+
+&pm8994_spmi_regulators {
+ qcom,saw-reg = <&saw3>;
+
+ s9 {
+ qcom,saw-slave;
+ };
+
+ s10 {
+ qcom,saw-slave;
+ };
+
+ s11 {
+ qcom,saw-leader;
+ regulator-min-microvolt = <1140000>;
+ regulator-max-microvolt = <1140000>;
+ regulator-max-step-microvolt = <150000>;
+ regulator-always-on;
+ };
+};
+
+&pmi8994_spmi_regulators {
+ vdd_gfx: s2 {
+ regulator-name = "vdd-gfx";
+ regulator-min-microvolt = <980000>;
+ regulator-max-microvolt = <1230000>;
+ };
+};
+
+&q6asmdai {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai@0 {
+ reg = <0>;
+ };
+
+ dai@1 {
+ reg = <1>;
+ };
+
+ dai@2 {
+ reg = <2>;
+ };
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8994-regulators";
+
+ vreg_s3a_1p3: s3 {
+ regulator-name = "vreg_s3a_1p3";
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ vreg_s4a_1p8: s4 {
+ regulator-name = "vreg_s4a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vreg_s5a_2p15: s5 {
+ regulator-name = "vreg_s5a_2p15";
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ };
+
+ vreg_s7a_0p8: s7 {
+ regulator-name = "vreg_s7a_0p8";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ };
+
+ vreg_l1a_1p0: l1 {
+ regulator-name = "vreg_l1a_1p0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ vreg_l2a_1p25: l2 {
+ regulator-name = "vreg_l2a_1p25";
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l3a_1p1: l3 {
+ regulator-name = "vreg_l3a_1p1";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ vreg_l4a_1p225: l4 {
+ regulator-name = "vreg_l4a_1p225";
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ vreg_l6a_1p2: l6 {
+ regulator-name = "vreg_l6a_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vreg_l7a_1p8: l7 {
+ regulator-name = "vreg_l7a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l9a_1p8: l9 {
+ regulator-name = "vreg_l9a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l10a_1p8: l10 {
+ regulator-name = "vreg_l10a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l11a_1p15: l11 {
+ regulator-name = "vreg_l11a_1p15";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ vreg_l12a_1p8: l12 {
+ regulator-name = "vreg_l12a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l13a_2p95: l13 {
+ regulator-name = "vreg_l13a_2p95";
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ vreg_l16a_2p7: l16 {
+ regulator-name = "vreg_l16a_2p7";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ vreg_l17a_2p6: l17 {
+ regulator-name = "vreg_l17a_2p6";
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ };
+
+ vreg_l18a_3p3: l18 {
+ regulator-name = "vreg_l18a_3p3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vreg_l19a_3p0: l19 {
+ regulator-name = "vreg_l19a_3p0";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ vreg_l20a_2p95: l20 {
+ regulator-name = "vreg_l20a_2p95";
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l21a_2p95: l21 {
+ regulator-name = "vreg_l21a_2p95";
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-allow-set-load;
+ regulator-system-load = <200000>;
+ };
+
+ vreg_l22a_3p0: l22 {
+ regulator-name = "vreg_l22a_3p0";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vreg_l23a_2p8: l23 {
+ regulator-name = "vreg_l23a_2p8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ vreg_l24a_3p075: l24 {
+ regulator-name = "vreg_l24a_3p075";
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ vreg_l25a_1p2: l25 {
+ regulator-name = "vreg_l25a_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-allow-set-load;
+ regulator-always-on;
+ };
+
+ vreg_l27a_1p2: l27 {
+ regulator-name = "vreg_l27a_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vreg_l28a_0p925: l28 {
+ regulator-name = "vreg_l28a_0p925";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <925000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l29a_2p8: l29 {
+ regulator-name = "vreg_l29a_2p8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ vreg_l30a_1p8: l30 {
+ regulator-name = "vreg_l30a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l32a_1p8: l32 {
+ regulator-name = "vreg_l32a_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+};
+
+&slpi_pil {
+ status = "okay";
+};
+
+&sound {
+ compatible = "qcom,apq8096-sndcard";
+ model = "OnePlus3";
+ audio-routing = "RX_BIAS", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC4", "MIC BIAS1",
+ "MIC BIAS1", "Primary Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Noise Mic";
+
+ mm1-dai-link {
+ link-name = "MultiMedia1";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
+ };
+ };
+
+ mm2-dai-link {
+ link-name = "MultiMedia2";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>;
+ };
+ };
+
+ mm3-dai-link {
+ link-name = "MultiMedia3";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>;
+ };
+ };
+
+ mm4-dai-link {
+ link-name = "MultiMedia4";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA4>;
+ };
+ };
+
+ mm5-dai-link {
+ link-name = "MultiMedia5";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA5>;
+ };
+ };
+
+ mm6-dai-link {
+ link-name = "MultiMedia6";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA6>;
+ };
+ };
+
+ mm7-dai-link {
+ link-name = "MultiMedia7";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA7>;
+ };
+ };
+
+ mm8-dai-link {
+ link-name = "MultiMedia8";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA8>;
+ };
+ };
+
+ mm9-dai-link {
+ link-name = "MultiMedia9";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA9>;
+ };
+ };
+
+ mm10-dai-link {
+ link-name = "MultiMedia10";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA10>;
+ };
+ };
+
+ mm11-dai-link {
+ link-name = "MultiMedia11";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA11>;
+ };
+ };
+
+ mm12-dai-link {
+ link-name = "MultiMedia12";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA12>;
+ };
+ };
+
+ mm13-dai-link {
+ link-name = "MultiMedia13";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA13>;
+ };
+ };
+
+ mm14-dai-link {
+ link-name = "MultiMedia14";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA14>;
+ };
+ };
+
+ mm15-dai-link {
+ link-name = "MultiMedia15";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA15>;
+ };
+ };
+
+ mm16-dai-link {
+ link-name = "MultiMedia16";
+
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA16>;
+ };
+ };
+
+ slim-dai-link {
+ link-name = "SLIM Playback";
+
+ cpu {
+ sound-dai = <&q6afedai SLIMBUS_6_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&wcd9335 AIF4_PB>;
+ };
+ };
+
+ slimcap-dai-link {
+ link-name = "SLIM Capture";
+
+ cpu {
+ sound-dai = <&q6afedai SLIMBUS_0_TX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&wcd9335 AIF1_CAP>;
+ };
+ };
+
+ speaker-dai-link {
+ link-name = "Speaker";
+
+ cpu {
+ sound-dai = <&q6afedai QUATERNARY_MI2S_RX>;
+ };
+
+ codec {
+ sound-dai = <&tfa9890_amp>;
+ };
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <81 4>;
+
+ mdss_dsi_active: mdss-dsi-active-state {
+ pins = "gpio8";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ mdss_dsi_suspend: mdss-dsi-suspend-state {
+ pins = "gpio8";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ mdss_te_active: mdss-te-active-state {
+ pins = "gpio10";
+ function = "mdp_vsync";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ mdss_te_suspend: mdss-te-suspend-state {
+ pins = "gpio10";
+ function = "mdp_vsync";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ touch_default: touch-default-state {
+ pins = "gpio89", "gpio125", "gpio49";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+
+ touch_suspend: touch-suspend-state {
+ pins = "gpio89", "gpio125", "gpio49";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&ufsphy {
+ vdda-phy-supply = <&vreg_l28a_0p925>;
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ vddp-ref-clk-supply = <&vreg_l25a_1p2>;
+
+ status = "okay";
+};
+
+&ufshc {
+ vcc-supply = <&vreg_l20a_2p95>;
+ vccq-supply = <&vreg_l25a_1p2>;
+ vccq2-supply = <&vreg_s4a_1p8>;
+
+ vcc-max-microamp = <600000>;
+ vccq-max-microamp = <450000>;
+ vccq2-max-microamp = <450000>;
+
+ status = "okay";
+};
+
+&usb3 {
+ status = "okay";
+};
+
+&usb3_dwc3 {
+ phys = <&hsusb_phy1>;
+ phy-names = "usb2-phy";
+
+ maximum-speed = "high-speed";
+};
+
+&venus {
+ status = "okay";
+};
+
+&wcd9335 {
+ clock-names = "mclk", "slimbus";
+ clocks = <&div1_mclk>,
+ <&rpmcc RPM_SMD_BB_CLK1>;
+
+ vdd-buck-supply = <&vreg_s4a_1p8>;
+ vdd-buck-sido-supply = <&vreg_s4a_1p8>;
+ vdd-tx-supply = <&vreg_s4a_1p8>;
+ vdd-rx-supply = <&vreg_s4a_1p8>;
+ vdd-io-supply = <&vreg_s4a_1p8>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-oneplus3.dts b/arch/arm64/boot/dts/qcom/msm8996-oneplus3.dts
new file mode 100644
index 000000000000..1bdc1b134305
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8996-oneplus3.dts
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Harry Austen <hpausten@protonmail.com>
+ */
+
+/dts-v1/;
+
+#include "msm8996-oneplus-common.dtsi"
+
+/ {
+ model = "OnePlus 3";
+ compatible = "oneplus,oneplus3", "qcom,msm8996";
+ chassis-type = "handset";
+ qcom,board-id = <8 0 15801 15>, <8 0 15801 16>;
+ qcom,msm-id = <246 0x30001>;
+};
+
+&adsp_pil {
+ firmware-name = "qcom/msm8996/oneplus3/adsp.mbn";
+};
+
+&battery {
+ charge-full-design-microamp-hours = <3000000>;
+ voltage-max-design-microvolt = <4350000>;
+};
+
+&gpu {
+ zap-shader {
+ firmware-name = "qcom/msm8996/oneplus3/a530_zap.mbn";
+ };
+};
+
+&mss_pil {
+ firmware-name = "qcom/msm8996/oneplus3/mba.mbn",
+ "qcom/msm8996/oneplus3/modem.mbn";
+};
+
+&slpi_pil {
+ firmware-name = "qcom/msm8996/oneplus3/slpi.mbn";
+};
+
+&venus {
+ firmware-name = "qcom/msm8996/oneplus3/venus.mbn";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-oneplus3t.dts b/arch/arm64/boot/dts/qcom/msm8996-oneplus3t.dts
new file mode 100644
index 000000000000..34f837dd0c12
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8996-oneplus3t.dts
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Harry Austen <hpausten@protonmail.com>
+ */
+
+/dts-v1/;
+
+#include "msm8996-oneplus-common.dtsi"
+
+/ {
+ model = "OnePlus 3T";
+ compatible = "oneplus,oneplus3t", "qcom,msm8996";
+ chassis-type = "handset";
+ qcom,board-id = <8 0 15811 26>,
+ <8 0 15811 27>,
+ <8 0 15811 28>;
+};
+
+&adsp_pil {
+ firmware-name = "qcom/msm8996/oneplus3t/adsp.mbn";
+};
+
+&battery {
+ charge-full-design-microamp-hours = <3400000>;
+ voltage-max-design-microvolt = <4400000>;
+};
+
+&gpu {
+ zap-shader {
+ firmware-name = "qcom/msm8996/oneplus3t/a530_zap.mbn";
+ };
+};
+
+&mss_pil {
+ firmware-name = "qcom/msm8996/oneplus3t/mba.mbn",
+ "qcom/msm8996/oneplus3t/modem.mbn";
+};
+
+&slpi_pil {
+ firmware-name = "qcom/msm8996/oneplus3t/slpi.mbn";
+};
+
+&venus {
+ firmware-name = "qcom/msm8996/oneplus3t/venus.mbn";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi b/arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi
index ca7c8d2e1d3d..dec361b93cce 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi
@@ -629,7 +629,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -847,28 +847,28 @@
pinctrl-0 = <&sw_service_gpio>;
pinctrl-names = "default";
- disp_reset_n_gpio: disp-reset-n {
+ disp_reset_n_gpio: disp-reset-n-state {
pins = "gpio8";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- mdp_vsync_p_gpio: mdp-vsync-p {
+ mdp_vsync_p_gpio: mdp-vsync-p-state {
pins = "gpio10";
function = "mdp_vsync";
drive-strength = <2>;
bias-disable;
};
- sw_service_gpio: sw-service-gpio {
+ sw_service_gpio: sw-service-gpio-state {
pins = "gpio16";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- usb_detect: usb-detect {
+ usb_detect: usb-detect-state {
pins = "gpio25";
function = "gpio";
drive-strength = <2>;
@@ -876,7 +876,7 @@
output-high;
};
- uim_detect_en: uim-detect-en {
+ uim_detect_en: uim-detect-en-state {
pins = "gpio29";
function = "gpio";
drive-strength = <2>;
@@ -884,14 +884,14 @@
output-high;
};
- tray_det_pin: tray-det {
+ tray_det_pin: tray-det-state {
pins = "gpio40";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- tp_vddio_en: tp-vddio-en {
+ tp_vddio_en: tp-vddio-en-state {
pins = "gpio50";
function = "gpio";
drive-strength = <2>;
@@ -899,7 +899,7 @@
output-high;
};
- lcd_vddio_en: lcd-vddio-en {
+ lcd_vddio_en: lcd-vddio-en-state {
pins = "gpio51";
function = "gpio";
drive-strength = <2>;
@@ -907,15 +907,14 @@
output-low;
};
- wl_host_wake: wl-host-wake {
+ wl_host_wake: wl-host-wake-state {
pins = "gpio79";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
- input-high;
};
- wl_reg_on: wl-reg-on {
+ wl_reg_on: wl-reg-on-state {
pins = "gpio84";
function = "gpio";
drive-strength = <2>;
@@ -923,20 +922,20 @@
output-low;
};
- ts_reset_n: ts-rst-n {
+ ts_reset_n: ts-rst-n-state {
pins = "gpio89";
function = "gpio";
drive-strength = <2>;
};
- touch_int_n: touch-int-n {
+ touch_int_n: touch-int-n-state {
pins = "gpio125";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- touch_int_sleep: touch-int-sleep {
+ touch_int_sleep: touch-int-sleep-state {
pins = "gpio125";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi
index 77819186086a..5b47b8de69da 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi
@@ -3,9 +3,6 @@
* Copyright (c) 2020, Yassine Oudjana <y.oudjana@protonmail.com>
*/
-/dts-v1/;
-
-#include "msm8996.dtsi"
#include "pm8994.dtsi"
#include "pmi8994.dtsi"
#include <dt-bindings/input/input.h>
@@ -413,7 +410,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -598,7 +595,7 @@
};
};
- pmi8994-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8994-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -694,35 +691,35 @@
};
&tlmm {
- mdss_dsi_default: mdss_dsi_default {
+ mdss_dsi_default: mdss-dsi-default-state {
pins = "gpio8";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
- mdss_dsi_sleep: mdss_dsi_sleep {
+ mdss_dsi_sleep: mdss-dsi-sleep-state {
pins = "gpio8";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- mdss_te_default: mdss_te_default {
+ mdss_te_default: mdss-te-default-state {
pins = "gpio10";
function = "mdp_vsync";
drive-strength = <2>;
bias-pull-down;
};
- mdss_te_sleep: mdss_te_sleep {
+ mdss_te_sleep: mdss-te-sleep-state {
pins = "gpio10";
function = "mdp_vsync";
drive-strength = <2>;
bias-pull-down;
};
- nfc_default: nfc_default {
+ nfc_default: nfc-default-state {
pins = "gpio12", "gpio21";
function = "gpio";
drive-strength = <16>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
index 4e5264f4116a..d8734913482f 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
+++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
@@ -5,6 +5,7 @@
/dts-v1/;
+#include "msm8996.dtsi"
#include "msm8996-xiaomi-common.dtsi"
#include <dt-bindings/sound/qcom,q6afe.h>
#include <dt-bindings/sound/qcom,q6asm.h>
@@ -219,7 +220,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
vreg_l17a_2p8: l17 {
regulator-name = "vreg_l17a_2p8";
regulator-min-microvolt = <2500000>;
@@ -445,28 +446,28 @@
"RFFE1_DATA", /* GPIO_148 */
"RFFE1_CLK"; /* GPIO_149 */
- touchscreen_default: touchscreen_default {
+ touchscreen_default: touchscreen-default-state {
pins = "gpio89", "gpio125";
function = "gpio";
drive-strength = <10>;
bias-pull-up;
};
- touchscreen_sleep: touchscreen_sleep {
+ touchscreen_sleep: touchscreen-sleep-state {
pins = "gpio89", "gpio125";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- vibrator_default: vibrator_default {
+ vibrator_default: vibrator-default-state {
pins = "gpio93";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
- vibrator_sleep: vibrator_sleep {
+ vibrator_sleep: vibrator-sleep-state {
pins = "gpio93";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index c0a2baffa49d..d31464204f69 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -144,82 +145,92 @@
/* Nominal fmax for now */
opp-307200000 {
opp-hz = /bits/ 64 <307200000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-422400000 {
opp-hz = /bits/ 64 <422400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-480000000 {
opp-hz = /bits/ 64 <480000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-556800000 {
opp-hz = /bits/ 64 <556800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-652800000 {
opp-hz = /bits/ 64 <652800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-729600000 {
opp-hz = /bits/ 64 <729600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-844800000 {
opp-hz = /bits/ 64 <844800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-960000000 {
opp-hz = /bits/ 64 <960000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1036800000 {
opp-hz = /bits/ 64 <1036800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1113600000 {
opp-hz = /bits/ 64 <1113600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1190400000 {
opp-hz = /bits/ 64 <1190400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1228800000 {
opp-hz = /bits/ 64 <1228800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1324800000 {
opp-hz = /bits/ 64 <1324800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xd>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1363200000 {
+ opp-hz = /bits/ 64 <1363200000>;
+ opp-supported-hw = <0x2>;
clock-latency-ns = <200000>;
};
opp-1401600000 {
opp-hz = /bits/ 64 <1401600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xd>;
clock-latency-ns = <200000>;
};
opp-1478400000 {
opp-hz = /bits/ 64 <1478400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x9>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1497600000 {
+ opp-hz = /bits/ 64 <1497600000>;
+ opp-supported-hw = <0x04>;
clock-latency-ns = <200000>;
};
opp-1593600000 {
opp-hz = /bits/ 64 <1593600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x9>;
clock-latency-ns = <200000>;
};
};
@@ -232,127 +243,137 @@
/* Nominal fmax for now */
opp-307200000 {
opp-hz = /bits/ 64 <307200000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-403200000 {
opp-hz = /bits/ 64 <403200000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-480000000 {
opp-hz = /bits/ 64 <480000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-556800000 {
opp-hz = /bits/ 64 <556800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-652800000 {
opp-hz = /bits/ 64 <652800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-729600000 {
opp-hz = /bits/ 64 <729600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-806400000 {
opp-hz = /bits/ 64 <806400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-883200000 {
opp-hz = /bits/ 64 <883200000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-940800000 {
opp-hz = /bits/ 64 <940800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1036800000 {
opp-hz = /bits/ 64 <1036800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1113600000 {
opp-hz = /bits/ 64 <1113600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1190400000 {
opp-hz = /bits/ 64 <1190400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1248000000 {
opp-hz = /bits/ 64 <1248000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1324800000 {
opp-hz = /bits/ 64 <1324800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1401600000 {
opp-hz = /bits/ 64 <1401600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1478400000 {
opp-hz = /bits/ 64 <1478400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1555200000 {
opp-hz = /bits/ 64 <1555200000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1632000000 {
opp-hz = /bits/ 64 <1632000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1708800000 {
opp-hz = /bits/ 64 <1708800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
clock-latency-ns = <200000>;
};
opp-1785600000 {
opp-hz = /bits/ 64 <1785600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0xf>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1804800000 {
+ opp-hz = /bits/ 64 <1804800000>;
+ opp-supported-hw = <0xe>;
clock-latency-ns = <200000>;
};
opp-1824000000 {
opp-hz = /bits/ 64 <1824000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1900800000 {
+ opp-hz = /bits/ 64 <1900800000>;
+ opp-supported-hw = <0x4>;
clock-latency-ns = <200000>;
};
opp-1920000000 {
opp-hz = /bits/ 64 <1920000000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
};
opp-1996800000 {
opp-hz = /bits/ 64 <1996800000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
};
opp-2073600000 {
opp-hz = /bits/ 64 <2073600000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
};
opp-2150400000 {
opp-hz = /bits/ 64 <2150400000>;
- opp-supported-hw = <0x77>;
+ opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
};
};
@@ -860,9 +881,9 @@
<&gcc GPLL0>,
<&dsi0_phy 1>,
<&dsi0_phy 0>,
- <0>,
- <0>,
- <0>;
+ <&dsi1_phy 1>,
+ <&dsi1_phy 0>,
+ <&hdmi_phy>;
clock-names = "xo",
"gcc_mmss_noc_cfg_ahb_clk",
"gpll0",
@@ -993,7 +1014,6 @@
assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
phys = <&dsi0_phy>;
- phy-names = "dsi";
status = "disabled";
#address-cells = <1>;
@@ -1018,7 +1038,7 @@
};
};
- dsi0_phy: dsi-phy@994400 {
+ dsi0_phy: phy@994400 {
compatible = "qcom,dsi-phy-14nm";
reg = <0x00994400 0x100>,
<0x00994500 0x300>,
@@ -1061,7 +1081,6 @@
assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
phys = <&dsi1_phy>;
- phy-names = "dsi";
status = "disabled";
#address-cells = <1>;
@@ -1086,7 +1105,7 @@
};
};
- dsi1_phy: dsi-phy@996400 {
+ dsi1_phy: phy@996400 {
compatible = "qcom,dsi-phy-14nm";
reg = <0x00996400 0x100>,
<0x00996500 0x300>,
@@ -1145,7 +1164,7 @@
};
};
- hdmi_phy: hdmi-phy@9a0600 {
+ hdmi_phy: phy@9a0600 {
#phy-cells = <0>;
compatible = "qcom,hdmi-phy-8996";
reg = <0x009a0600 0x1c4>,
@@ -1213,17 +1232,17 @@
compatible = "operating-points-v2";
/*
- * 624Mhz and 560Mhz are only available on speed
- * bin (1 << 0). All the rest are available on
- * all bins of the hardware
+ * 624Mhz is only available on speed bins 0 and 3.
+ * 560Mhz is only available on speed bins 0, 2 and 3.
+ * All the rest are available on all bins of the hardware.
*/
opp-624000000 {
opp-hz = /bits/ 64 <624000000>;
- opp-supported-hw = <0x01>;
+ opp-supported-hw = <0x09>;
};
opp-560000000 {
opp-hz = /bits/ 64 <560000000>;
- opp-supported-hw = <0x01>;
+ opp-supported-hw = <0x0d>;
};
opp-510000000 {
opp-hz = /bits/ 64 <510000000>;
@@ -1262,15 +1281,15 @@
interrupt-controller;
#interrupt-cells = <2>;
- blsp1_spi1_default: blsp1-spi1-default {
- spi {
+ blsp1_spi1_default: blsp1-spi1-default-state {
+ spi-pins {
pins = "gpio0", "gpio1", "gpio3";
function = "blsp_spi1";
drive-strength = <12>;
bias-disable;
};
- cs {
+ cs-pins {
pins = "gpio2";
function = "gpio";
drive-strength = <16>;
@@ -1279,42 +1298,56 @@
};
};
- blsp1_spi1_sleep: blsp1-spi1-sleep {
+ blsp1_spi1_sleep: blsp1-spi1-sleep-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- blsp2_uart2_2pins_default: blsp2-uart1-2pins {
+ blsp2_uart2_2pins_default: blsp2-uart2-2pins-state {
pins = "gpio4", "gpio5";
function = "blsp_uart8";
drive-strength = <16>;
bias-disable;
};
- blsp2_uart2_2pins_sleep: blsp2-uart1-2pins-sleep {
+ blsp2_uart2_2pins_sleep: blsp2-uart2-2pins-sleep-state {
pins = "gpio4", "gpio5";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c2_default: blsp2-i2c2 {
+ blsp2_i2c2_default: blsp2-i2c2-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c8";
drive-strength = <16>;
bias-disable;
};
- blsp2_i2c2_sleep: blsp2-i2c2-sleep {
+ blsp2_i2c2_sleep: blsp2-i2c2-sleep-state {
pins = "gpio6", "gpio7";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- cci0_default: cci0-default {
+ blsp1_i2c6_default: blsp1-i2c6-state {
+ pins = "gpio27", "gpio28";
+ function = "blsp_i2c6";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ blsp1_i2c6_sleep: blsp1-i2c6-sleep-state {
+ pins = "gpio27", "gpio28";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ cci0_default: cci0-default-state {
pins = "gpio17", "gpio18";
function = "cci_i2c";
drive-strength = <16>;
@@ -1322,22 +1355,22 @@
};
camera0_state_on:
- camera_rear_default: camera-rear-default {
- camera0_mclk: mclk0 {
+ camera_rear_default: camera-rear-default-state {
+ camera0_mclk: mclk0-pins {
pins = "gpio13";
function = "cam_mclk";
drive-strength = <16>;
bias-disable;
};
- camera0_rst: rst {
+ camera0_rst: rst-pins {
pins = "gpio25";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- camera0_pwdn: pwdn {
+ camera0_pwdn: pwdn-pins {
pins = "gpio26";
function = "gpio";
drive-strength = <16>;
@@ -1345,7 +1378,7 @@
};
};
- cci1_default: cci1-default {
+ cci1_default: cci1-default-state {
pins = "gpio19", "gpio20";
function = "cci_i2c";
drive-strength = <16>;
@@ -1353,22 +1386,22 @@
};
camera1_state_on:
- camera_board_default: camera-board-default {
- mclk1 {
+ camera_board_default: camera-board-default-state {
+ mclk1-pins {
pins = "gpio14";
function = "cam_mclk";
drive-strength = <16>;
bias-disable;
};
- pwdn {
+ pwdn-pins {
pins = "gpio98";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- rst {
+ rst-pins {
pins = "gpio104";
function = "gpio";
drive-strength = <16>;
@@ -1377,22 +1410,22 @@
};
camera2_state_on:
- camera_front_default: camera-front-default {
- camera2_mclk: mclk2 {
+ camera_front_default: camera-front-default-state {
+ camera2_mclk: mclk2-pins {
pins = "gpio15";
function = "cam_mclk";
drive-strength = <16>;
bias-disable;
};
- camera2_rst: rst {
+ camera2_rst: rst-pins {
pins = "gpio23";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- pwdn {
+ pwdn-pins {
pins = "gpio133";
function = "gpio";
drive-strength = <16>;
@@ -1400,22 +1433,22 @@
};
};
- pcie0_state_on: pcie0-state-on {
- perst {
+ pcie0_state_on: pcie0-state-on-state {
+ perst-pins {
pins = "gpio35";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio36";
function = "pci_e0";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio37";
function = "gpio";
drive-strength = <2>;
@@ -1423,22 +1456,22 @@
};
};
- pcie0_state_off: pcie0-state-off {
- perst {
+ pcie0_state_off: pcie0-state-off-state {
+ perst-pins {
pins = "gpio35";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio36";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- wake {
+ wake-pins {
pins = "gpio37";
function = "gpio";
drive-strength = <2>;
@@ -1446,63 +1479,63 @@
};
};
- blsp1_uart2_default: blsp1-uart2-default {
+ blsp1_uart2_default: blsp1-uart2-default-state {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "blsp_uart2";
drive-strength = <16>;
bias-disable;
};
- blsp1_uart2_sleep: blsp1-uart2-sleep {
+ blsp1_uart2_sleep: blsp1-uart2-sleep-state {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c3_default: blsp1-i2c2-default {
+ blsp1_i2c3_default: blsp1-i2c3-default-state {
pins = "gpio47", "gpio48";
function = "blsp_i2c3";
drive-strength = <16>;
bias-disable;
};
- blsp1_i2c3_sleep: blsp1-i2c2-sleep {
+ blsp1_i2c3_sleep: blsp1-i2c3-sleep-state {
pins = "gpio47", "gpio48";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp2_uart3_4pins_default: blsp2-uart2-4pins {
+ blsp2_uart3_4pins_default: blsp2-uart3-4pins-state {
pins = "gpio49", "gpio50", "gpio51", "gpio52";
function = "blsp_uart9";
drive-strength = <16>;
bias-disable;
};
- blsp2_uart3_4pins_sleep: blsp2-uart2-4pins-sleep {
+ blsp2_uart3_4pins_sleep: blsp2-uart3-4pins-sleep-state {
pins = "gpio49", "gpio50", "gpio51", "gpio52";
function = "blsp_uart9";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c3_default: blsp2-i2c3 {
+ blsp2_i2c3_default: blsp2-i2c3-state-state {
pins = "gpio51", "gpio52";
function = "blsp_i2c9";
drive-strength = <16>;
bias-disable;
};
- blsp2_i2c3_sleep: blsp2-i2c3-sleep {
+ blsp2_i2c3_sleep: blsp2-i2c3-sleep-state {
pins = "gpio51", "gpio52";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- wcd_intr_default: wcd-intr-default{
+ wcd_intr_default: wcd-intr-default-state {
pins = "gpio54";
function = "gpio";
drive-strength = <2>;
@@ -1510,21 +1543,21 @@
input-enable;
};
- blsp2_i2c1_default: blsp2-i2c1 {
+ blsp2_i2c1_default: blsp2-i2c1-state {
pins = "gpio55", "gpio56";
function = "blsp_i2c7";
drive-strength = <16>;
bias-disable;
};
- blsp2_i2c1_sleep: blsp2-i2c0-sleep {
+ blsp2_i2c1_sleep: blsp2-i2c1-sleep-state {
pins = "gpio55", "gpio56";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c5_default: blsp2-i2c5 {
+ blsp2_i2c5_default: blsp2-i2c5-state {
pins = "gpio60", "gpio61";
function = "blsp_i2c11";
drive-strength = <2>;
@@ -1533,7 +1566,7 @@
/* Sleep state for BLSP2_I2C5 is missing.. */
- cdc_reset_active: cdc-reset-active {
+ cdc_reset_active: cdc-reset-active-state {
pins = "gpio64";
function = "gpio";
drive-strength = <16>;
@@ -1541,7 +1574,7 @@
output-high;
};
- cdc_reset_sleep: cdc-reset-sleep {
+ cdc_reset_sleep: cdc-reset-sleep-state {
pins = "gpio64";
function = "gpio";
drive-strength = <16>;
@@ -1549,15 +1582,15 @@
output-low;
};
- blsp2_spi6_default: blsp2-spi5-default {
- spi {
+ blsp2_spi6_default: blsp2-spi6-default-state {
+ spi-pins {
pins = "gpio85", "gpio86", "gpio88";
function = "blsp_spi12";
drive-strength = <12>;
bias-disable;
};
- cs {
+ cs-pins {
pins = "gpio87";
function = "gpio";
drive-strength = <16>;
@@ -1566,43 +1599,43 @@
};
};
- blsp2_spi6_sleep: blsp2-spi5-sleep {
+ blsp2_spi6_sleep: blsp2-spi6-sleep-state {
pins = "gpio85", "gpio86", "gpio87", "gpio88";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- blsp2_i2c6_default: blsp2-i2c6 {
+ blsp2_i2c6_default: blsp2-i2c6-state {
pins = "gpio87", "gpio88";
function = "blsp_i2c12";
drive-strength = <16>;
bias-disable;
};
- blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+ blsp2_i2c6_sleep: blsp2-i2c6-sleep-state {
pins = "gpio87", "gpio88";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- pcie1_state_on: pcie1-state-on {
- perst {
+ pcie1_state_on: pcie1-on-state {
+ perst-pins {
pins = "gpio130";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio131";
function = "pci_e1";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio132";
function = "gpio";
drive-strength = <2>;
@@ -1610,16 +1643,16 @@
};
};
- pcie1_state_off: pcie1-state-off {
+ pcie1_state_off: pcie1-off-state {
/* Perst is missing? */
- clkreq {
+ clkreq-pins {
pins = "gpio131";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- wake {
+ wake-pins {
pins = "gpio132";
function = "gpio";
drive-strength = <2>;
@@ -1627,22 +1660,22 @@
};
};
- pcie2_state_on: pcie2-state-on {
- perst {
+ pcie2_state_on: pcie2-on-state {
+ perst-pins {
pins = "gpio114";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio115";
function = "pci_e2";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio116";
function = "gpio";
drive-strength = <2>;
@@ -1650,16 +1683,16 @@
};
};
- pcie2_state_off: pcie2-state-off {
+ pcie2_state_off: pcie2-off-state {
/* Perst is missing? */
- clkreq {
+ clkreq-pins {
pins = "gpio115";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- wake {
+ wake-pins {
pins = "gpio116";
function = "gpio";
drive-strength = <2>;
@@ -1667,90 +1700,90 @@
};
};
- sdc1_state_on: sdc1-state-on {
- clk {
+ sdc1_state_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc1_state_off: sdc1-state-off {
- clk {
+ sdc1_state_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc2_state_on: sdc2-clk-on {
- clk {
+ sdc2_state_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
};
- sdc2_state_off: sdc2-clk-off {
- clk {
+ sdc2_state_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
@@ -1995,10 +2028,6 @@
lanes-per-direction = <1>;
#reset-cells = <1>;
status = "disabled";
-
- ufs_variant {
- compatible = "qcom,ufs_variant";
- };
};
ufsphy: phy@627000 {
@@ -2205,9 +2234,9 @@
<GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
- clocks = <&mmcc GPU_AHB_CLK>,
- <&gcc GCC_MMSS_BIMC_GFX_CLK>;
- clock-names = "iface", "bus";
+ clocks = <&gcc GCC_MMSS_BIMC_GFX_CLK>,
+ <&mmcc GPU_AHB_CLK>;
+ clock-names = "bus", "iface";
power-domains = <&mmcc GPU_GDSC>;
};
@@ -2272,9 +2301,9 @@
<GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
- clocks = <&mmcc SMMU_MDP_AHB_CLK>,
- <&mmcc SMMU_MDP_AXI_CLK>;
- clock-names = "iface", "bus";
+ clocks = <&mmcc SMMU_MDP_AXI_CLK>,
+ <&mmcc SMMU_MDP_AHB_CLK>;
+ clock-names = "bus", "iface";
power-domains = <&mmcc MDSS_GDSC>;
};
@@ -2292,9 +2321,9 @@
<GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&mmcc MMAGIC_VIDEO_GDSC>;
- clocks = <&mmcc SMMU_VIDEO_AHB_CLK>,
- <&mmcc SMMU_VIDEO_AXI_CLK>;
- clock-names = "iface", "bus";
+ clocks = <&mmcc SMMU_VIDEO_AXI_CLK>,
+ <&mmcc SMMU_VIDEO_AHB_CLK>;
+ clock-names = "bus", "iface";
#iommu-cells = <1>;
status = "okay";
};
@@ -2308,10 +2337,9 @@
<GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&mmcc MMAGIC_CAMSS_GDSC>;
- clocks = <&mmcc SMMU_VFE_AHB_CLK>,
- <&mmcc SMMU_VFE_AXI_CLK>;
- clock-names = "iface",
- "bus";
+ clocks = <&mmcc SMMU_VFE_AXI_CLK>,
+ <&mmcc SMMU_VFE_AHB_CLK>;
+ clock-names = "bus", "iface";
#iommu-cells = <1>;
};
@@ -2336,9 +2364,9 @@
<GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>,
- <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
- clock-names = "iface", "bus";
+ clocks = <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>,
+ <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>;
+ clock-names = "bus", "iface";
};
slpi_pil: remoteproc@1c00000 {
@@ -3127,6 +3155,23 @@
status = "disabled";
};
+ blsp1_i2c6: i2c@757a000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x757a000 0x1000>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>,
+ <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp1_i2c6_default>;
+ pinctrl-1 = <&blsp1_i2c6_sleep>;
+ dmas = <&blsp1_dma 22>, <&blsp1_dma 23>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
blsp2_dma: dma-controller@7584000 {
compatible = "qcom,bam-v1.7.0";
reg = <0x07584000 0x2b000>;
@@ -3309,27 +3354,25 @@
qcom,num-ees = <2>;
};
- slim_msm: slim@91c0000 {
+ slim_msm: slim-ngd@91c0000 {
compatible = "qcom,slim-ngd-v1.5.0";
reg = <0x091c0000 0x2C000>;
- reg-names = "ctrl";
interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&slimbam 3>, <&slimbam 4>,
- <&slimbam 5>, <&slimbam 6>;
- dma-names = "rx", "tx", "tx2", "rx2";
+ dmas = <&slimbam 3>, <&slimbam 4>;
+ dma-names = "rx", "tx";
#address-cells = <1>;
#size-cells = <0>;
- ngd@1 {
+ slim@1 {
reg = <1>;
- #address-cells = <1>;
- #size-cells = <1>;
+ #address-cells = <2>;
+ #size-cells = <0>;
- tasha_ifd: tas-ifd {
+ tasha_ifd: tas-ifd@0,0 {
compatible = "slim217,1a0";
reg = <0 0>;
};
- wcd9335: codec@1{
+ wcd9335: codec@1,0 {
pinctrl-0 = <&cdc_reset_active &wcd_intr_default>;
pinctrl-names = "default";
@@ -3342,7 +3385,7 @@
interrupt-names = "intr1", "intr2";
interrupt-controller;
#interrupt-cells = <1>;
- reset-gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 64 GPIO_ACTIVE_LOW>;
slim-ifc-dev = <&tasha_ifd>;
@@ -3393,12 +3436,12 @@
#address-cells = <1>;
#size-cells = <0>;
- q6core {
+ service@3 {
reg = <APR_SVC_ADSP_CORE>;
compatible = "qcom,q6core";
};
- q6afe: q6afe {
+ q6afe: service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
q6afedai: dais {
@@ -3406,13 +3449,13 @@
#address-cells = <1>;
#size-cells = <0>;
#sound-dai-cells = <1>;
- hdmi@1 {
+ dai@1 {
reg = <1>;
};
};
};
- q6asm: q6asm {
+ q6asm: service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
q6asmdai: dais {
@@ -3424,7 +3467,7 @@
};
};
- q6adm: q6adm {
+ q6adm: service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
q6routing: routing {
@@ -3504,7 +3547,7 @@
};
saw3: syscon@9a10000 {
- compatible = "qcom,tcsr-msm8996", "syscon";
+ compatible = "syscon";
reg = <0x09a10000 0x1000>;
};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts b/arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-natrium.dts
index ff4673ee9e81..d18d0b0eda95 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts
+++ b/arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-natrium.dts
@@ -5,6 +5,7 @@
/dts-v1/;
+#include "msm8996pro.dtsi"
#include "msm8996-xiaomi-common.dtsi"
#include "pmi8996.dtsi"
#include <dt-bindings/sound/qcom,q6afe.h>
@@ -12,7 +13,7 @@
/ {
model = "Xiaomi Mi 5s Plus";
- compatible = "xiaomi,natrium", "qcom,msm8996";
+ compatible = "xiaomi,natrium", "qcom,msm8996pro", "qcom,msm8996";
chassis-type = "handset";
qcom,msm-id = <305 0x10000>;
qcom,board-id = <47 0>;
@@ -164,7 +165,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
vreg_l3a_0p875: l3 {
regulator-name = "vreg_l3a_0p875";
regulator-min-microvolt = <850000>;
@@ -398,14 +399,14 @@
"RFFE1_DATA", /* GPIO_148 */
"RFFE1_CLK"; /* GPIO_149 */
- touchscreen_default: touchscreen-default {
+ touchscreen_default: touchscreen-default-state {
pins = "gpio89", "gpio125";
function = "gpio";
drive-strength = <10>;
bias-pull-up;
};
- touchscreen_sleep: touchscreen-sleep {
+ touchscreen_sleep: touchscreen-sleep-state {
pins = "gpio89", "gpio125";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-scorpio.dts b/arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-scorpio.dts
index 79be5fb1295b..5e3b9130e9c2 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-scorpio.dts
+++ b/arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-scorpio.dts
@@ -5,6 +5,7 @@
/dts-v1/;
+#include "msm8996pro.dtsi"
#include "msm8996-xiaomi-common.dtsi"
#include "pmi8996.dtsi"
#include <dt-bindings/sound/qcom,q6afe.h>
@@ -13,7 +14,7 @@
/ {
model = "Xiaomi Mi Note 2";
- compatible = "xiaomi,scorpio", "qcom,msm8996";
+ compatible = "xiaomi,scorpio", "qcom,msm8996pro", "qcom,msm8996";
chassis-type = "handset";
qcom,msm-id = <305 0x10000>;
qcom,board-id = <34 0>;
@@ -216,7 +217,7 @@
};
&rpm_requests {
- pm8994-regulators {
+ regulators-0 {
vreg_l3a_0p875: l3 {
regulator-name = "vreg_l3a_0p875";
regulator-min-microvolt = <850000>;
@@ -468,28 +469,28 @@
"RFFE1_DATA", /* GPIO_148 */
"RFFE1_CLK"; /* GPIO_149 */
- touchkey_default: touchkey_default {
+ touchkey_default: touchkey-default-state {
pins = "gpio77";
function = "gpio";
drive-strength = <16>;
bias-pull-up;
};
- touchkey_sleep: touchkey_sleep {
+ touchkey_sleep: touchkey-sleep-state {
pins = "gpio77";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
- touchscreen_default: touchscreen_default {
+ touchscreen_default: touchscreen-default-state {
pins = "gpio75", "gpio125";
function = "gpio";
drive-strength = <10>;
bias-pull-up;
};
- touchscreen_sleep: touchscreen_sleep {
+ touchscreen_sleep: touchscreen-sleep-state {
pins = "gpio75", "gpio125";
function = "gpio";
drive-strength = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996pro.dtsi b/arch/arm64/boot/dts/qcom/msm8996pro.dtsi
new file mode 100644
index 000000000000..a679a9c0cf99
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8996pro.dtsi
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include "msm8996.dtsi"
+
+/ {
+ /delete-node/ opp-table-cluster0;
+ /delete-node/ opp-table-cluster1;
+
+ /*
+ * On MSM8996 Pro the cpufreq driver shifts speed bins into the high
+ * nibble of supported hw, so speed bin 0 becomes 0x10, speed bin 1
+ * becomes 0x20, speed 2 becomes 0x40.
+ */
+
+ cluster0_opp: opp-table-cluster0 {
+ compatible = "operating-points-v2-kryo-cpu";
+ nvmem-cells = <&speedbin_efuse>;
+ opp-shared;
+
+ opp-307200000 {
+ opp-hz = /bits/ 64 <307200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-460800000 {
+ opp-hz = /bits/ 64 <460800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-537600000 {
+ opp-hz = /bits/ 64 <537600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-691200000 {
+ opp-hz = /bits/ 64 <691200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-768000000 {
+ opp-hz = /bits/ 64 <768000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-844800000 {
+ opp-hz = /bits/ 64 <844800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-902400000 {
+ opp-hz = /bits/ 64 <902400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-979200000 {
+ opp-hz = /bits/ 64 <979200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1056000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1132800000 {
+ opp-hz = /bits/ 64 <1132800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1209600000 {
+ opp-hz = /bits/ 64 <1209600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1286400000 {
+ opp-hz = /bits/ 64 <1286400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1363200000 {
+ opp-hz = /bits/ 64 <1363200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1440000000 {
+ opp-hz = /bits/ 64 <1440000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1516800000 {
+ opp-hz = /bits/ 64 <1516800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1593600000 {
+ opp-hz = /bits/ 64 <1593600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1996800000 {
+ opp-hz = /bits/ 64 <1996800000>;
+ opp-supported-hw = <0x20>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2188800000 {
+ opp-hz = /bits/ 64 <2188800000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ };
+
+ cluster1_opp: opp-table-cluster1 {
+ compatible = "operating-points-v2-kryo-cpu";
+ nvmem-cells = <&speedbin_efuse>;
+ opp-shared;
+
+ opp-307200000 {
+ opp-hz = /bits/ 64 <307200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-460800000 {
+ opp-hz = /bits/ 64 <460800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-537600000 {
+ opp-hz = /bits/ 64 <537600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-691200000 {
+ opp-hz = /bits/ 64 <691200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-748800000 {
+ opp-hz = /bits/ 64 <748800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-825600000 {
+ opp-hz = /bits/ 64 <825600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-902400000 {
+ opp-hz = /bits/ 64 <902400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-979200000 {
+ opp-hz = /bits/ 64 <979200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1056000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1132800000 {
+ opp-hz = /bits/ 64 <1132800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1209600000 {
+ opp-hz = /bits/ 64 <1209600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1286400000 {
+ opp-hz = /bits/ 64 <1286400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1363200000 {
+ opp-hz = /bits/ 64 <1363200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1440000000 {
+ opp-hz = /bits/ 64 <1440000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1516800000 {
+ opp-hz = /bits/ 64 <1516800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1593600000 {
+ opp-hz = /bits/ 64 <1593600000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1670400000 {
+ opp-hz = /bits/ 64 <1670400000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1747200000 {
+ opp-hz = /bits/ 64 <1747200000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1824000000 {
+ opp-hz = /bits/ 64 <1824000000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1900800000 {
+ opp-hz = /bits/ 64 <1900800000>;
+ opp-supported-hw = <0x70>;
+ clock-latency-ns = <200000>;
+ };
+ opp-1977600000 {
+ opp-hz = /bits/ 64 <1977600000>;
+ opp-supported-hw = <0x30>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2054400000 {
+ opp-hz = /bits/ 64 <2054400000>;
+ opp-supported-hw = <0x30>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2150400000 {
+ opp-hz = /bits/ 64 <2150400000>;
+ opp-supported-hw = <0x30>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2246400000 {
+ opp-hz = /bits/ 64 <2246400000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ opp-2342400000 {
+ opp-hz = /bits/ 64 <2342400000>;
+ opp-supported-hw = <0x10>;
+ clock-latency-ns = <200000>;
+ };
+ };
+};
+
+&gpu_opp_table {
+ /*
+ * Unlike CPU opp tables, the GPU driver does not shift speed bins.
+ *
+ * 652.8 Mhz is available on speed bin 0 only.
+ * 624 Mhz and 560 Mhz are available on speed bins 0 and 1.
+ * All the rest are available on all bins of the hardware (like on
+ * plain 8996).
+ */
+
+ opp-652800000 {
+ opp-hz = /bits/ 64 <652800000>;
+ opp-supported-hw = <0x01>;
+ };
+ opp-624000000 {
+ opp-hz = /bits/ 64 <624000000>;
+ opp-supported-hw = <0x03>;
+ };
+ opp-560000000 {
+ opp-hz = /bits/ 64 <560000000>;
+ opp-supported-hw = <0x03>;
+ };
+ /* The rest is inherited from msm8996 */
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
index 7928b8197474..3b7172aa4037 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
@@ -35,7 +35,7 @@
};
&blsp1_uart3_on {
- rx {
+ rx-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 45 (RX). This is needed to
@@ -46,7 +46,7 @@
bias-pull-up;
};
- cts {
+ cts-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
@@ -137,7 +137,7 @@
};
&rpm_requests {
- pm8998-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -357,8 +357,9 @@
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
- touchpad: touchpad-pin {
+ touchpad: touchpad-pin-state {
pins = "gpio123";
+ function = "gpio";
bias-pull-up;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts b/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
index 429ba57e20f7..310f7a2df1e8 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
+++ b/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
@@ -216,7 +216,7 @@
};
&blsp1_uart3_on {
- rx {
+ rx-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 45 (RX). This is needed to
@@ -227,7 +227,7 @@
bias-pull-up;
};
- cts {
+ cts-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
@@ -310,15 +310,11 @@
};
&funnel4 {
- // FIXME: Figure out why clock late_initcall crashes the board with
- // this enabled.
- // status = "okay";
+ /* FIXME: Figure out why clock late_initcall crashes the board with this enabled. */
};
&funnel5 {
- // FIXME: Figure out why clock late_initcall crashes the board with
- // this enabled.
- // status = "okay";
+ /* FIXME: Figure out why clock late_initcall crashes the board with this enabled. */
};
&pcie0 {
@@ -390,7 +386,7 @@
};
&rpm_requests {
- pm8998-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -588,7 +584,7 @@
};
- pmi8998-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8998-regulators";
vdd_bob-supply = <&vph_pwr>;
@@ -615,14 +611,14 @@
&tlmm {
gpio-reserved-ranges = <0 4>;
- mdp_vsync_n: mdp-vsync-n {
+ mdp_vsync_n: mdp-vsync-n-state {
pins = "gpio10";
function = "mdp_vsync_a";
bias-pull-down;
drive-strength = <2>;
};
- gpio_kb_pins_extra: gpio-kb-pins-extra {
+ gpio_kb_pins_extra: gpio-kb-pins-extra-state {
pins = "gpio21", "gpio32", "gpio33", "gpio114",
"gpio128", "gpio129";
function = "gpio";
@@ -630,21 +626,21 @@
bias-pull-up;
};
- ts_vio_default: ts-vio-def {
+ ts_vio_default: ts-vio-def-state {
pins = "gpio81";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- ts_rst_n: ts-rst-n {
+ ts_rst_n: ts-rst-n-state {
pins = "gpio89";
function = "gpio";
bias-pull-up;
drive-strength = <8>;
};
- hall_sensor1_default: hall-sensor1-def {
+ hall_sensor1_default: hall-sensor1-def-state {
pins = "gpio124";
function = "gpio";
bias-disable;
@@ -652,7 +648,7 @@
input-enable;
};
- ts_int_n: ts-int-n {
+ ts_int_n: ts-int-n-state {
pins = "gpio125";
function = "gpio";
bias-disable;
diff --git a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
index cf81c33a9d7e..a105143bee4a 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
+++ b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
@@ -28,8 +28,8 @@
};
&remoteproc_mss {
- firmware-name = "qcom/LENOVO/81F1/qcdsp1v28998.mbn",
- "qcom/LENOVO/81F1/qcdsp28998.mbn";
+ firmware-name = "qcom/msm8998/LENOVO/81F1/qcdsp1v28998.mbn",
+ "qcom/msm8998/LENOVO/81F1/qcdsp28998.mbn";
};
&sdhc2 {
diff --git a/arch/arm64/boot/dts/qcom/msm8998-mtp.dts b/arch/arm64/boot/dts/qcom/msm8998-mtp.dts
index a3ca58100aee..453a1c9e9808 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8998-mtp.dts
@@ -46,7 +46,7 @@
};
&blsp1_uart3_on {
- rx {
+ rx-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 45 (RX). This is needed to
@@ -57,7 +57,7 @@
bias-pull-up;
};
- cts {
+ cts-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
@@ -124,15 +124,11 @@
};
&funnel4 {
- // FIXME: Figure out why clock late_initcall crashes the board with
- // this enabled.
- // status = "okay";
+ /* FIXME: Figure out why clock late_initcall crashes the board with this enabled. */
};
&funnel5 {
- // FIXME: Figure out why clock late_initcall crashes the board with
- // this enabled.
- // status = "okay";
+ /* FIXME: Figure out why clock late_initcall crashes the board with this enabled. */
};
&pcie0 {
@@ -168,7 +164,7 @@
};
&rpm_requests {
- pm8998-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -366,7 +362,7 @@
};
- pmi8998-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8998-regulators";
vdd_bob-supply = <&vph_pwr>;
diff --git a/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts b/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts
index ef2a88a64d32..9fb1fb9b8529 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts
+++ b/arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts
@@ -22,7 +22,7 @@
pinctrl-names = "default";
pinctrl-0 = <&button_backlight_default>;
- button-backlight {
+ led-keypad-backlight {
gpios = <&pmi8998_gpio 5 GPIO_ACTIVE_HIGH>;
color = <LED_COLOR_ID_WHITE>;
function = LED_FUNCTION_KBD_BACKLIGHT;
@@ -33,11 +33,9 @@
&pmi8998_gpio {
button_backlight_default: button-backlight-state {
- pinconf {
- pins = "gpio5";
- function = "normal";
- bias-pull-down;
- qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
- };
+ pins = "gpio5";
+ function = "gpio";
+ bias-pull-down;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi
index 62bda23791bb..7d4a67d07501 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi
@@ -233,7 +233,7 @@
};
&blsp1_uart3_on {
- rx {
+ rx-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 46 (RX). This is needed to
@@ -244,7 +244,7 @@
bias-pull-up;
};
- cts {
+ cts-pins {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
@@ -279,6 +279,10 @@
};
};
+&pmi8998_rradc {
+ status = "okay";
+};
+
&qusb2phy {
status = "okay";
@@ -288,7 +292,7 @@
};
&rpm_requests {
- pm8998-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -477,7 +481,7 @@
vreg_lvs2a_1p8: lvs2 { };
};
- pmi8998-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8998-regulators";
vdd_bob-supply = <&vph_pwr>;
@@ -492,7 +496,7 @@
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
- hall_sensor_default: hall-sensor-default {
+ hall_sensor_default: hall-sensor-default-state {
pins = "gpio124";
function = "gpio";
drive-strength = <2>;
@@ -500,28 +504,28 @@
input-enable;
};
- ts_int_active: ts-int-active {
+ ts_int_active: ts-int-active-state {
pins = "gpio125";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
- ts_reset_active: ts-reset-active {
+ ts_reset_active: ts-reset-active-state {
pins = "gpio89";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
- nfc_int_active: nfc-int-active {
+ nfc_int_active: nfc-int-active-state {
pins = "gpio92";
function = "gpio";
drive-strength = <6>;
bias-pull-up;
};
- nfc_enable_active: nfc-enable-active {
+ nfc_enable_active: nfc-enable-active-state {
pins = "gpio12", "gpio116";
function = "gpio";
drive-strength = <6>;
diff --git a/arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi b/arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi
index d08639082247..5da87baa2b23 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi
@@ -375,7 +375,7 @@
};
&rpm_requests {
- pm8998-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -410,135 +410,166 @@
regulator-min-microvolt = <1352000>;
regulator-max-microvolt = <1352000>;
};
+
vreg_s4a_1p8: s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-system-load = <100000>;
regulator-allow-set-load;
};
+
vreg_s5a_2p04: s5 {
regulator-min-microvolt = <1904000>;
regulator-max-microvolt = <2032000>;
};
+
vreg_s7a_1p025: s7 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1028000>;
};
+
vreg_l1a_0p875: l1 {
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
regulator-system-load = <73400>;
regulator-allow-set-load;
};
+
vreg_l2a_1p2: l2 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-system-load = <12560>;
regulator-allow-set-load;
};
+
vreg_l3a_1p0: l3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
+
vreg_l5a_0p8: l5 {
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <800000>;
};
+
vreg_l6a_1p8: l6 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
vreg_l7a_1p8: l7 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
vreg_l8a_1p2: l8 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
+
vreg_l9a_1p8: l9 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
+
vreg_l10a_1p8: l10 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
+
vreg_l11a_1p0: l11 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
+
vreg_l12a_1p8: l12 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
vreg_l13a_2p95: l13 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
};
+
vreg_l14a_1p85: l14 {
regulator-min-microvolt = <1848000>;
regulator-max-microvolt = <1856000>;
regulator-system-load = <32000>;
regulator-allow-set-load;
};
+
vreg_l15a_1p8: l15 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
vreg_l16a_2p7: l16 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
+
vreg_l17a_1p3: l17 {
regulator-min-microvolt = <1304000>;
regulator-max-microvolt = <1304000>;
};
- vreg_l18a_2p85: l18 {};
+
+ vreg_l18a_2p85: l18 { };
+
vreg_l19a_2p7: l19 {
regulator-min-microvolt = <2696000>;
regulator-max-microvolt = <2704000>;
};
+
vreg_l20a_2p95: l20 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-system-load = <10000>;
regulator-allow-set-load;
};
+
vreg_l21a_2p95: l21 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-system-load = <800000>;
regulator-allow-set-load;
};
+
vreg_l22a_2p85: l22 { };
+
vreg_l23a_3p3: l23 {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3312000>;
};
+
vreg_l24a_3p075: l24 {
regulator-min-microvolt = <3088000>;
regulator-max-microvolt = <3088000>;
};
+
vreg_l25a_3p3: l25 {
regulator-min-microvolt = <3104000>;
regulator-max-microvolt = <3312000>;
};
+
vreg_l26a_1p2: l26 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-allow-set-load;
};
+
vreg_l28_3p0: l28 {
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
+
vreg_lvs1a_1p8: lvs1 { };
+
vreg_lvs2a_1p8: lvs2 { };
};
- pmi8998-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pmi8998-regulators";
vdd_bob-supply = <&vph_pwr>;
@@ -565,14 +596,14 @@
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
- mdp_vsync_n: mdp-vsync-n {
+ mdp_vsync_n: mdp-vsync-n-state {
pins = "gpio10";
function = "mdp_vsync_a";
drive-strength = <2>;
bias-pull-down;
};
- nfc_ven: nfc-ven {
+ nfc_ven: nfc-ven-state {
pins = "gpio12";
function = "gpio";
bias-disable;
@@ -580,42 +611,42 @@
output-low;
};
- msm_mclk0_default: msm-mclk0-active {
+ msm_mclk0_default: msm-mclk0-active-state {
pins = "gpio13";
function = "cam_mclk";
drive-strength = <2>;
bias-disable;
};
- msm_mclk1_default: msm-mclk1-active {
+ msm_mclk1_default: msm-mclk1-active-state {
pins = "gpio14";
function = "cam_mclk";
drive-strength = <2>;
bias-disable;
};
- cci0_default: cci0-default {
+ cci0_default: cci0-default-state {
pins = "gpio18", "gpio19";
function = "cci_i2c";
bias-disable;
drive-strength = <2>;
};
- cci1_default: cci1-default {
+ cci1_default: cci1-default-state {
pins = "gpio19", "gpio20";
function = "cci_i2c";
bias-disable;
drive-strength = <2>;
};
- cam0_vdig_default: cam0-vdig-default {
+ cam0_vdig_default: cam0-vdig-default-state {
pins = "gpio21";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- tof_int: tof-int {
+ tof_int: tof-int-state {
pins = "gpio22";
function = "gpio";
bias-pull-up;
@@ -623,28 +654,28 @@
input-enable;
};
- cam1_vdig_default: cam1-vdig-default {
+ cam1_vdig_default: cam1-vdig-default-state {
pins = "gpio25";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- usb_extcon_active: usb-extcon-active {
+ usb_extcon_active: usb-extcon-active-state {
pins = "gpio38";
function = "gpio";
bias-disable;
drive-strength = <16>;
};
- tof_reset: tof-reset {
+ tof_reset: tof-reset-state {
pins = "gpio27";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- hall_sensor0_default: acc-cover-open {
+ hall_sensor0_default: acc-cover-open-state {
pins = "gpio124";
function = "gpio";
bias-disable;
@@ -652,14 +683,14 @@
input-enable;
};
- ts_int_n: ts-int-n {
+ ts_int_n: ts-int-n-state {
pins = "gpio125";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
- usb_vbus_active: usb-vbus-active {
+ usb_vbus_active: usb-vbus-active-state {
pins = "gpio128";
function = "gpio";
bias-disable;
@@ -667,7 +698,7 @@
output-low;
};
- ts_vddio_en: ts-vddio-en-default {
+ ts_vddio_en: ts-vddio-en-default-state {
pins = "gpio133";
function = "gpio";
bias-disable;
diff --git a/arch/arm64/boot/dts/qcom/msm8998-xiaomi-sagit.dts b/arch/arm64/boot/dts/qcom/msm8998-xiaomi-sagit.dts
new file mode 100644
index 000000000000..b1aac7311ef9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8998-xiaomi-sagit.dts
@@ -0,0 +1,711 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Xiaomi Mi 6 (sagit) device tree source based on msm8998-mtp.dtsi
+ *
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Degdag Mohamed <degdagmohamed@gmail.com>
+ * Copyright (c) 2022, Dzmitry Sankouski <dsankouski@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "msm8998.dtsi"
+#include "pm8005.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+/*
+ * Delete following upstream (msm8998.dtsi) reserved
+ * memory mappings which are different in this device.
+ */
+/delete-node/ &adsp_mem;
+/delete-node/ &mpss_mem;
+/delete-node/ &venus_mem;
+/delete-node/ &mba_mem;
+/delete-node/ &slpi_mem;
+/delete-node/ &ipa_fw_mem;
+/delete-node/ &ipa_gsi_mem;
+/delete-node/ &gpu_mem;
+/delete-node/ &wlan_msa_mem;
+
+/ {
+ model = "Xiaomi Mi 6";
+ compatible = "xiaomi,sagit", "qcom,msm8998";
+ chassis-type = "handset";
+ /* Required for bootloader to select correct board */
+ qcom,board-id = <30 0>;
+
+ reserved-memory {
+ /*
+ * Xiaomi's ADSP firmware requires 30 MiB in total, so increase the adsp_mem
+ * region by 4 MiB to account for this while relocating the other now
+ * conflicting memory nodes accordingly.
+ */
+ adsp_mem: memory@8b200000 {
+ reg = <0x0 0x8b200000 0x0 0x1e00000>;
+ no-map;
+ };
+
+ mpss_mem: memory@8d000000 {
+ reg = <0x0 0x8d000000 0x0 0x7000000>;
+ no-map;
+ };
+
+ venus_mem: memory@94000000 {
+ reg = <0x0 0x94000000 0x0 0x500000>;
+ no-map;
+ };
+
+ mba_mem: memory@94500000 {
+ reg = <0x0 0x94500000 0x0 0x200000>;
+ no-map;
+ };
+
+ slpi_mem: memory@94700000 {
+ reg = <0x0 0x94700000 0x0 0xf00000>;
+ no-map;
+ };
+
+ ipa_fw_mem: memory@95600000 {
+ reg = <0x0 0x95600000 0x0 0x10000>;
+ no-map;
+ };
+
+ ipa_gsi_mem: memory@95610000 {
+ reg = <0x0 0x95610000 0x0 0x5000>;
+ no-map;
+ };
+
+ gpu_mem: memory@95615000 {
+ reg = <0x0 0x95615000 0x0 0x100000>;
+ no-map;
+ };
+
+ wlan_msa_mem: memory@95715000 {
+ reg = <0x0 0x95715000 0x0 0x100000>;
+ no-map;
+ };
+
+ /* Bootloader display framebuffer region */
+ cont_splash_mem: memory@9d400000 {
+ reg = <0x0 0x9d400000 0x0 0x2400000>;
+ no-map;
+ };
+
+ /* For getting crash logs using Android downstream kernels */
+ ramoops@ac000000 {
+ compatible = "ramoops";
+ reg = <0x0 0xac000000 0x0 0x200000>;
+ console-size = <0x80000>;
+ pmsg-size = <0x40000>;
+ record-size = <0x8000>;
+ ftrace-size = <0x20000>;
+ };
+
+ /*
+ * The following memory regions on downstream are "dynamically allocated"
+ * but given the same addresses every time. Hard code them as these addresses
+ * are where the Xiaomi signed firmware expects them to be.
+ */
+ ipa_fws_region: memory@f7800000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0xf7800000 0x0 0x5000>;
+ no-map;
+ };
+
+ zap_shader_region: memory@f7900000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0xf7900000 0x0 0x2000>;
+ no-map;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ label = "Volume buttons";
+ autorepeat;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&vol_up_key_default>;
+
+ key-vol-up {
+ label = "Volume up";
+ gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ wakeup-source;
+ };
+ };
+
+ gpio-hall-sensor {
+ compatible = "gpio-keys";
+ label = "Hall effect sensor";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hall_sensor_default_state>;
+
+ event-hall-sensor {
+ label = "Hall Effect Sensor";
+ gpios = <&tlmm 124 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ linux,can-disable;
+ wakeup-source;
+ };
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ disp_vddts_vreg: disp-vddts-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "disp-vddts-regulator";
+ gpio = <&tlmm 50 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+};
+
+&blsp1_i2c5 {
+ pinctrl-names = "default", "sleep";
+ status = "okay";
+
+ touchscreen@20 {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <125 IRQ_TYPE_EDGE_FALLING>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&ts_active_state>;
+ pinctrl-1 = <&ts_int_suspend_state &ts_reset_suspend_state>;
+
+ vdd-supply = <&disp_vddts_vreg>;
+ vio-supply = <&vreg_l6a_1p8>;
+
+ syna,reset-delay-ms = <20>;
+ syna,startup-delay-ms = <20>;
+
+ rmi4-f01@1 {
+ reg = <0x01>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f12@12 {
+ reg = <0x12>;
+ touchscreen-x-mm = <64>;
+ touchscreen-y-mm = <114>;
+ syna,sensor-type = <1>;
+ syna,rezero-wait-ms = <20>;
+ };
+
+ rmi4-f1a@1a {
+ reg = <0x1a>;
+ syna,codes = <KEY_BACK KEY_APPSELECT>;
+ };
+ };
+};
+
+&blsp1_i2c5_sleep {
+ /delete-property/ bias-pull-up;
+ bias-disable;
+};
+
+&blsp1_uart3 {
+ status = "okay";
+
+ bluetooth {
+ compatible = "qcom,wcn3990-bt";
+
+ vddio-supply = <&vreg_s4a_1p8>;
+ vddxo-supply = <&vreg_l7a_1p8>;
+ vddrf-supply = <&vreg_l17a_1p3>;
+ vddch0-supply = <&vreg_l25a_3p3>;
+ max-speed = <3200000>;
+ };
+};
+
+&blsp1_uart3_on {
+ rx-pins {
+ /delete-property/ bias-disable;
+ /*
+ * Configure a pull-up on 46 (RX). This is needed to
+ * avoid garbage data when the TX pin of the Bluetooth
+ * module is in tri-state (module powered off or not
+ * driving the signal yet).
+ */
+ bias-pull-up;
+ };
+
+ cts-pins {
+ /delete-property/ bias-disable;
+ /*
+ * Configure a pull-down on 47 (CTS) to match the pull
+ * of the Bluetooth module.
+ */
+ bias-pull-down;
+ };
+};
+
+&blsp2_uart1 {
+ status = "okay";
+};
+
+&pm8005_regulators {
+ compatible = "qcom,pm8005-regulators";
+
+ vdd_s1-supply = <&vph_pwr>;
+
+ pm8005_s1: s1 { /* VDD_GFX supply */
+ regulator-min-microvolt = <524000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-enable-ramp-delay = <500>;
+
+ /* hack until we rig up the gpu consumer */
+ regulator-always-on;
+ };
+};
+
+&pm8998_gpio {
+ vol_up_key_default: vol-up-key-default-state {
+ pins = "gpio6";
+ function = "normal";
+ bias-pull-up;
+ input-enable;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+ };
+
+ audio_mclk_pin: audio-mclk-pin-active-state {
+ pins = "gpio13";
+ function = "func2";
+ power-source = <0>;
+ };
+};
+
+&qusb2phy {
+ vdd-supply = <&vreg_l1a_0p875>;
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators-0 {
+ compatible = "qcom,rpm-pm8998-regulators";
+
+ vdd_s1-supply = <&vph_pwr>;
+ vdd_s2-supply = <&vph_pwr>;
+ vdd_s3-supply = <&vph_pwr>;
+ vdd_s4-supply = <&vph_pwr>;
+ vdd_s5-supply = <&vph_pwr>;
+ vdd_s6-supply = <&vph_pwr>;
+ vdd_s7-supply = <&vph_pwr>;
+ vdd_s8-supply = <&vph_pwr>;
+ vdd_s9-supply = <&vph_pwr>;
+ vdd_s10-supply = <&vph_pwr>;
+ vdd_s11-supply = <&vph_pwr>;
+ vdd_s12-supply = <&vph_pwr>;
+ vdd_s13-supply = <&vph_pwr>;
+ vdd_l1_l27-supply = <&vreg_s7a_1p025>;
+ vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
+ vdd_l3_l11-supply = <&vreg_s7a_1p025>;
+ vdd_l4_l5-supply = <&vreg_s7a_1p025>;
+ vdd_l6-supply = <&vreg_s5a_2p04>;
+ vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
+ vdd_l9-supply = <&vreg_bob>;
+ vdd_l10_l23_l25-supply = <&vreg_bob>;
+ vdd_l13_l19_l21-supply = <&vreg_bob>;
+ vdd_l16_l28-supply = <&vreg_bob>;
+ vdd_l18_l22-supply = <&vreg_bob>;
+ vdd_l20_l24-supply = <&vreg_bob>;
+ vdd_l26-supply = <&vreg_s3a_1p35>;
+ vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
+
+ vreg_s3a_1p35: s3 {
+ regulator-min-microvolt = <1352000>;
+ regulator-max-microvolt = <1352000>;
+ };
+
+ vreg_s4a_1p8: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_s5a_2p04: s5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ vreg_s7a_1p025: s7 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1028000>;
+ };
+
+ vreg_l1a_0p875: l1 {
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ };
+
+ vreg_l2a_1p2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vreg_l3a_1p0: l3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ vreg_l5a_0p8: l5 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ };
+
+ vreg_l6a_1p8: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l7a_1p8: l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l8a_1p2: l8 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vreg_l9a_1p8: l9 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ vreg_l10a_1p8: l10 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ vreg_l11a_1p0: l11 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ vreg_l12a_1p8: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l13a_2p95: l13 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ vreg_l14a_1p8: l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l15a_1p8: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_l16a_2p7: l16 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ };
+
+ vreg_l17a_1p3: l17 {
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ vreg_l18a_2p7: l18 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ };
+
+ vreg_l19a_3p0: l19 {
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ };
+
+ vreg_l20a_2p95: l20 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l21a_2p95: l21 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-system-load = <800000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l22a_2p85: l22 {
+ regulator-min-microvolt = <2864000>;
+ regulator-max-microvolt = <2864000>;
+ };
+
+ vreg_l23a_3p3: l23 {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ };
+
+ vreg_l24a_3p075: l24 {
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3088000>;
+ };
+
+ vreg_l25a_3p3: l25 {
+ regulator-min-microvolt = <3104000>;
+ regulator-max-microvolt = <3312000>;
+ };
+
+ vreg_l26a_1p2: l26 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l28_3p0: l28 {
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ };
+
+ vreg_lvs1a_1p8: lvs1 { };
+
+ vreg_lvs2a_1p8: lvs2 { };
+ };
+
+ regulators-1 {
+ compatible = "qcom,rpm-pmi8998-regulators";
+
+ vdd_bob-supply = <&vph_pwr>;
+
+ vreg_bob: bob {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ };
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <0 4>, <81 4>;
+
+ cci1_default_state: cci1-default-state {
+ pins = "gpio19", "gpio20";
+ function = "cci_i2c";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ cdc_reset_n_state: cdc-reset-n-state {
+ pins = "gpio64";
+ function = "gpio";
+ bias-pull-down;
+ drive-strength = <16>;
+ output-high;
+ };
+
+ hall_sensor_default_state: hall-sensor-default-state {
+ pins = "gpio124";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+
+ mdss_dsi_active_state: mdss-dsi-active-state {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ mdss_dsi_suspend_state: mdss-dsi-suspend-state {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ mdss_te_active_state: mdss-te-active-state {
+ pins = "gpio10";
+ function = "mdp_vsync_a";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ mdss_te_suspend_state: mdss-te-suspend-state {
+ pins = "gpio10";
+ function = "mdp_vsync_a";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ msm_mclk0_active_state: msm-mclk0-active-state {
+ pins = "gpio13";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ msm_mclk0_suspend_state: msm-mclk0-suspend-state {
+ pins = "gpio13";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ msm_mclk1_active_state: msm-mclk1-active-state {
+ pins = "gpio14";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ msm_mclk1_suspend_state: msm-mclk1-suspend-state {
+ pins = "gpio14";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ nfc_int_active_state: nfc-int-active-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ nfc_int_suspend_state: nfc-int-suspend-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ nfc_enable_active_state: nfc-enable-active-state {
+ pins = "gpio12", "gpio116";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ nfc_enable_suspend_state: nfc-enable-suspend-state {
+ pins = "gpio12", "gpio116";
+ function = "gpio";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ ts_active_state: ts-active-state {
+ pins = "gpio89", "gpio125";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-pull-up;
+ input-enable;
+ };
+
+ ts_int_suspend_state: ts-int-suspend-state {
+ pins = "gpio125";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ ts_reset_suspend_state: ts-reset-suspend-state {
+ pins = "gpio89";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ wcd_int_n_state: wcd-int-n-state {
+ pins = "gpio54";
+ function = "gpio";
+ bias-pull-down;
+ drive-strength = <2>;
+ input-enable;
+ };
+
+ wsa_leftspk_pwr_n_state: wsa-leftspk-pwr-n-state {
+ pins = "gpio65";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ output-low;
+ };
+
+ wsa_rightspk_pwr_n_state: wsa-rightspk-pwr-n-state {
+ pins = "gpio66";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ output-low;
+ };
+};
+
+&pm8998_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+ status = "okay";
+};
+
+&ufshc {
+ vcc-supply = <&vreg_l20a_2p95>;
+ vccq-supply = <&vreg_l26a_1p2>;
+ vccq2-supply = <&vreg_s4a_1p8>;
+ vcc-max-microamp = <750000>;
+ vccq-max-microamp = <560000>;
+ vccq2-max-microamp = <750000>;
+ status = "okay";
+};
+
+&ufsphy {
+ vdda-phy-supply = <&vreg_l1a_0p875>;
+ vdda-pll-supply = <&vreg_l2a_1p2>;
+ vddp-ref-clk-supply = <&vreg_l26a_1p2>;
+ status = "okay";
+};
+
+&usb3 {
+ /* Disable USB3 clock requirement as the device only supports USB2 */
+ qcom,select-utmi-as-pipe-clk;
+ status = "okay";
+};
+
+&usb3_dwc3 {
+ /* Drop the unused USB 3 PHY */
+ phys = <&qusb2phy>;
+ phy-names = "usb2-phy";
+
+ /* Fastest mode for USB 2 */
+ maximum-speed = "high-speed";
+
+ /* Force to peripheral until we can switch modes */
+ dr_mode = "peripheral";
+};
+
+&wifi {
+ vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+ vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+ vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+ vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
index f05f16ac5cc1..539382dab0ad 100644
--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
@@ -900,7 +900,7 @@
};
pcie0: pci@1c00000 {
- compatible = "qcom,pcie-msm8996";
+ compatible = "qcom,pcie-msm8998", "qcom,pcie-msm8996";
reg = <0x01c00000 0x2000>,
<0x1b000000 0xf1d>,
<0x1b000f20 0xa8>,
@@ -929,11 +929,11 @@
<0 0 0 4 &intc 0 0 139 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
- <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
- <&gcc GCC_PCIE_0_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
- <&gcc GCC_PCIE_0_AUX_CLK>;
- clock-names = "pipe", "bus_master", "bus_slave", "cfg", "aux";
+ <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_0_SLV_AXI_CLK>;
+ clock-names = "pipe", "aux", "cfg", "bus_master", "bus_slave";
power-domains = <&gcc PCIE_0_GDSC>;
iommu-map = <0x100 &anoc1_smmu 0x1480 1>;
@@ -1056,81 +1056,82 @@
compatible = "qcom,msm8998-pinctrl";
reg = <0x03400000 0xc00000>;
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&tlmm 0 0 150>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
- sdc2_on: sdc2-on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <16>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
drive-strength = <10>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "sdc2_data";
drive-strength = <10>;
bias-pull-up;
};
};
- sdc2_off: sdc2-off {
- clk {
+ sdc2_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <2>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
drive-strength = <2>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "sdc2_data";
drive-strength = <2>;
bias-pull-up;
};
};
- sdc2_cd: sdc2-cd {
+ sdc2_cd: sdc2-cd-state {
pins = "gpio95";
function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
- blsp1_uart3_on: blsp1-uart3-on {
- tx {
+ blsp1_uart3_on: blsp1-uart3-on-state {
+ tx-pins {
pins = "gpio45";
function = "blsp_uart3_a";
drive-strength = <2>;
bias-disable;
};
- rx {
+ rx-pins {
pins = "gpio46";
function = "blsp_uart3_a";
drive-strength = <2>;
bias-disable;
};
- cts {
+ cts-pins {
pins = "gpio47";
function = "blsp_uart3_a";
drive-strength = <2>;
bias-disable;
};
- rfr {
+ rfr-pins {
pins = "gpio48";
function = "blsp_uart3_a";
drive-strength = <2>;
@@ -1138,168 +1139,168 @@
};
};
- blsp1_i2c1_default: blsp1-i2c1-default {
+ blsp1_i2c1_default: blsp1-i2c1-default-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c1_sleep: blsp1-i2c1-sleep {
+ blsp1_i2c1_sleep: blsp1-i2c1-sleep-state-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c2_default: blsp1-i2c2-default {
+ blsp1_i2c2_default: blsp1-i2c2-default-state {
pins = "gpio32", "gpio33";
function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c2_sleep: blsp1-i2c2-sleep {
+ blsp1_i2c2_sleep: blsp1-i2c2-sleep-state-state {
pins = "gpio32", "gpio33";
function = "blsp_i2c2";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c3_default: blsp1-i2c3-default {
+ blsp1_i2c3_default: blsp1-i2c3-default-state {
pins = "gpio47", "gpio48";
function = "blsp_i2c3";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c3_sleep: blsp1-i2c3-sleep {
+ blsp1_i2c3_sleep: blsp1-i2c3-sleep-state {
pins = "gpio47", "gpio48";
function = "blsp_i2c3";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c4_default: blsp1-i2c4-default {
+ blsp1_i2c4_default: blsp1-i2c4-default-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c4";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c4_sleep: blsp1-i2c4-sleep {
+ blsp1_i2c4_sleep: blsp1-i2c4-sleep-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c4";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c5_default: blsp1-i2c5-default {
+ blsp1_i2c5_default: blsp1-i2c5-default-state {
pins = "gpio87", "gpio88";
function = "blsp_i2c5";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c5_sleep: blsp1-i2c5-sleep {
+ blsp1_i2c5_sleep: blsp1-i2c5-sleep-state {
pins = "gpio87", "gpio88";
function = "blsp_i2c5";
drive-strength = <2>;
bias-pull-up;
};
- blsp1_i2c6_default: blsp1-i2c6-default {
+ blsp1_i2c6_default: blsp1-i2c6-default-state {
pins = "gpio43", "gpio44";
function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
- blsp1_i2c6_sleep: blsp1-i2c6-sleep {
+ blsp1_i2c6_sleep: blsp1-i2c6-sleep-state {
pins = "gpio43", "gpio44";
function = "blsp_i2c6";
drive-strength = <2>;
bias-pull-up;
};
/* 6 interfaces per QUP, BLSP2 indexes are numbered (n)+6 */
- blsp2_i2c1_default: blsp2-i2c1-default {
+ blsp2_i2c1_default: blsp2-i2c1-default-state {
pins = "gpio55", "gpio56";
function = "blsp_i2c7";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c1_sleep: blsp2-i2c1-sleep {
+ blsp2_i2c1_sleep: blsp2-i2c1-sleep-state {
pins = "gpio55", "gpio56";
function = "blsp_i2c7";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c2_default: blsp2-i2c2-default {
+ blsp2_i2c2_default: blsp2-i2c2-default-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c8";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c2_sleep: blsp2-i2c2-sleep {
+ blsp2_i2c2_sleep: blsp2-i2c2-sleep-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c8";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c3_default: blsp2-i2c3-default {
+ blsp2_i2c3_default: blsp2-i2c3-default-state {
pins = "gpio51", "gpio52";
function = "blsp_i2c9";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c3_sleep: blsp2-i2c3-sleep {
+ blsp2_i2c3_sleep: blsp2-i2c3-sleep-state {
pins = "gpio51", "gpio52";
function = "blsp_i2c9";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c4_default: blsp2-i2c4-default {
+ blsp2_i2c4_default: blsp2-i2c4-default-state {
pins = "gpio67", "gpio68";
function = "blsp_i2c10";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c4_sleep: blsp2-i2c4-sleep {
+ blsp2_i2c4_sleep: blsp2-i2c4-sleep-state {
pins = "gpio67", "gpio68";
function = "blsp_i2c10";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c5_default: blsp2-i2c5-default {
+ blsp2_i2c5_default: blsp2-i2c5-default-state {
pins = "gpio60", "gpio61";
function = "blsp_i2c11";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c5_sleep: blsp2-i2c5-sleep {
+ blsp2_i2c5_sleep: blsp2-i2c5-sleep-state {
pins = "gpio60", "gpio61";
function = "blsp_i2c11";
drive-strength = <2>;
bias-pull-up;
};
- blsp2_i2c6_default: blsp2-i2c6-default {
+ blsp2_i2c6_default: blsp2-i2c6-default-state {
pins = "gpio83", "gpio84";
function = "blsp_i2c12";
drive-strength = <2>;
bias-disable;
};
- blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+ blsp2_i2c6_sleep: blsp2-i2c6-sleep-state {
pins = "gpio83", "gpio84";
function = "blsp_i2c12";
drive-strength = <2>;
@@ -1903,7 +1904,7 @@
cpu = <&CPU4>;
- port{
+ port {
etm4_out: endpoint {
remote-endpoint = <&apss_funnel_in4>;
};
@@ -1920,7 +1921,7 @@
cpu = <&CPU5>;
- port{
+ port {
etm5_out: endpoint {
remote-endpoint = <&apss_funnel_in5>;
};
@@ -1937,7 +1938,7 @@
cpu = <&CPU6>;
- port{
+ port {
etm6_out: endpoint {
remote-endpoint = <&apss_funnel_in6>;
};
@@ -1954,7 +1955,7 @@
cpu = <&CPU7>;
- port{
+ port {
etm7_out: endpoint {
remote-endpoint = <&apss_funnel_in7>;
};
diff --git a/arch/arm64/boot/dts/qcom/pm6125.dtsi b/arch/arm64/boot/dts/qcom/pm6125.dtsi
new file mode 100644
index 000000000000..1c8ccda26ffb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm6125.dtsi
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ thermal-zones {
+ pm6125-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+
+ thermal-sensors = <&pm6125_temp>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+&spmi_bus {
+ pmic@0 {
+ compatible = "qcom,pm6125", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm6125_pon: pon@800 {
+ compatible = "qcom,pm8998-pon";
+ reg = <0x800>;
+ mode-bootloader = <0x2>;
+ mode-recovery = <0x1>;
+
+ pon_pwrkey: pwrkey {
+ compatible = "qcom,pm8941-pwrkey";
+ interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ linux,code = <KEY_POWER>;
+ bias-pull-up;
+ status = "disabled";
+ };
+
+ pon_resin: resin {
+ compatible = "qcom,pm8941-resin";
+ interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ bias-pull-up;
+ status = "disabled";
+ };
+ };
+
+ pm6125_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+ io-channels = <&pm6125_adc ADC5_DIE_TEMP>;
+ io-channel-names = "thermal";
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm6125_adc: adc@3100 {
+ compatible = "qcom,spmi-adc5";
+ reg = <0x3100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #io-channel-cells = <1>;
+
+ ref-gnd@0 {
+ reg = <ADC5_REF_GND>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vref-1p25@1 {
+ reg = <ADC5_1P25VREF>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ die-temp@6 {
+ reg = <ADC5_DIE_TEMP>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vph-pwr@83 {
+ reg = <ADC5_VPH_PWR>;
+ qcom,pre-scaling = <1 3>;
+ };
+
+ vcoin@85 {
+ reg = <ADC5_VCOIN>;
+ qcom,pre-scaling = <1 3>;
+ };
+
+ xo-therm@4c {
+ reg = <ADC5_XO_THERM_100K_PU>;
+ qcom,pre-scaling = <1 1>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+ };
+
+ pm6125_adc_tm: adc-tm@3500 {
+ compatible = "qcom,spmi-adc-tm5";
+ reg = <0x3500>;
+ interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #thermal-sensor-cells = <1>;
+ status = "disabled";
+ };
+
+ pm6125_rtc: rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000>, <0x6100>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
+ };
+
+ pm6125_gpio: gpio@c000 {
+ compatible = "qcom,pm6125-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm6125_gpio 0 0 9>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pmic@1 {
+ compatible = "qcom,pm6125", "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi
index 8a4972e6a24c..3d91fb405ca2 100644
--- a/arch/arm64/boot/dts/qcom/pm6150.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
-// Copyright (c) 2019, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/input/linux-event-codes.h>
@@ -86,7 +88,7 @@
status = "disabled";
};
- pm6150_gpio: gpios@c000 {
+ pm6150_gpio: gpio@c000 {
compatible = "qcom,pm6150-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi
index f02c223ef448..90aac61ad264 100644
--- a/arch/arm64/boot/dts/qcom/pm6150l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi
@@ -1,10 +1,43 @@
// SPDX-License-Identifier: BSD-3-Clause
-// Copyright (c) 2019, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
+/ {
+ thermal-zones {
+ pm6150l-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+
+ thermal-sensors = <&pm6150l_temp>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
&spmi_bus {
pm6150l_lsid4: pmic@4 {
compatible = "qcom,pm6150l", "qcom,spmi-pmic";
@@ -12,6 +45,13 @@
#address-cells = <1>;
#size-cells = <0>;
+ pm6150l_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400>;
+ interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
pm6150l_adc: adc@3100 {
compatible = "qcom,spmi-adc5";
reg = <0x3100>;
@@ -55,7 +95,7 @@
status = "disabled";
};
- pm6150l_gpio: gpios@c000 {
+ pm6150l_gpio: gpio@c000 {
compatible = "qcom,pm6150l-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm6350.dtsi b/arch/arm64/boot/dts/qcom/pm6350.dtsi
index ecf9b9919182..3a2a841e83f1 100644
--- a/arch/arm64/boot/dts/qcom/pm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm6350.dtsi
@@ -3,8 +3,40 @@
* Copyright (c) 2021, Luca Weiss <luca@z3ntu.xyz>
*/
+#include <dt-bindings/input/input.h>
#include <dt-bindings/spmi/spmi.h>
+/ {
+ thermal-zones {
+ pm6350-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+
+ thermal-sensors = <&pm6350_temp>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
&spmi_bus {
pmic@0 {
compatible = "qcom,pm6350", "qcom,spmi-pmic";
@@ -35,7 +67,14 @@
};
};
- pm6350_gpios: gpios@c000 {
+ pm6350_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm6350_gpios: gpio@c000 {
compatible = "qcom,pm6350-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index e1622b16c08b..fc0eccaccdf6 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -163,14 +163,14 @@
qcom,pre-scaling = <1 3>;
};
- vcoin: vcoin@83 {
+ vcoin: vcoin@85 {
reg = <ADC5_VCOIN>;
qcom,decimation = <1024>;
qcom,pre-scaling = <1 3>;
};
};
- pm660_gpios: gpios@c000 {
+ pm660_gpios: gpio@c000 {
compatible = "qcom,pm660-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 8aa0a5078772..f9b3864bd3b9 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -48,7 +48,7 @@
#thermal-sensor-cells = <0>;
};
- pm660l_gpios: gpios@c000 {
+ pm660l_gpios: gpio@c000 {
compatible = "qcom,pm660l-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm7325.dtsi b/arch/arm64/boot/dts/qcom/pm7325.dtsi
index e7f64a9ddc9c..d1c5476af5ee 100644
--- a/arch/arm64/boot/dts/qcom/pm7325.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm7325.dtsi
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
-// Copyright (c) 2021, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
@@ -18,7 +20,7 @@
#thermal-sensor-cells = <0>;
};
- pm7325_gpios: gpios@8800 {
+ pm7325_gpios: gpio@8800 {
compatible = "qcom,pm7325-gpio", "qcom,spmi-gpio";
reg = <0x8800>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi
index 50fb6c753bf8..8d4b081b4e9d 100644
--- a/arch/arm64/boot/dts/qcom/pm8005.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi
@@ -11,7 +11,7 @@
#address-cells = <1>;
#size-cells = <0>;
- pm8005_gpio: gpios@c000 {
+ pm8005_gpio: gpio@c000 {
compatible = "qcom,pm8005-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi
index cdded791d96e..66752cc063d6 100644
--- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi
@@ -53,7 +53,7 @@
status = "disabled";
};
- pm8150b_vbus: dcdc@1100 {
+ pm8150b_vbus: usb-vbus-regulator@1100 {
compatible = "qcom,pm8150b-vbus-reg";
status = "disabled";
reg = <0x1100>;
diff --git a/arch/arm64/boot/dts/qcom/pm8450a.dtsi b/arch/arm64/boot/dts/qcom/pm8450a.dtsi
new file mode 100644
index 000000000000..34fc72896761
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8450a.dtsi
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+
+&spmi_bus {
+ pm8450a: pmic@0 {
+ compatible = "qcom,pm8150", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8450a_gpios: gpio@c000 {
+ compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm8450a_gpios 0 0 10>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pm8450c: pmic@4 {
+ compatible = "qcom,pm8150", "qcom,spmi-pmic";
+ reg = <0x4 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8450c_gpios: gpio@c000 {
+ compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm8450c_gpios 0 0 10>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pm8450e: pmic@8 {
+ compatible = "qcom,pm8150", "qcom,spmi-pmic";
+ reg = <0x8 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8450e_gpios: gpio@c000 {
+ compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm8450e_gpios 0 0 10>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pm8450g: pmic@c {
+ compatible = "qcom,pm8150", "qcom,spmi-pmic";
+ reg = <0xc SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8450g_gpios: gpio@c000 {
+ compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm8450g_gpios 0 0 10>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
index 606c2a6d1f0f..08f9ca006e72 100644
--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -107,7 +107,7 @@
#interrupt-cells = <2>;
};
- pm8916_gpios: gpios@c000 {
+ pm8916_gpios: gpio@c000 {
compatible = "qcom,pm8916-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm8950.dtsi b/arch/arm64/boot/dts/qcom/pm8950.dtsi
new file mode 100644
index 000000000000..07c3896bd36f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8950.dtsi
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@somainline.org>
+ * Copyright (c) 2022, Marijn Suijten <marijn.suijten@somainline.org>
+ */
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#include <dt-bindings/spmi/spmi.h>
+
+&spmi_bus {
+ pmic@0 {
+ compatible = "qcom,pm8950", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pon@800 {
+ compatible = "qcom,pm8916-pon";
+ reg = <0x0800>;
+ mode-bootloader = <0x2>;
+ mode-recovery = <0x1>;
+
+ pwrkey {
+ compatible = "qcom,pm8941-pwrkey";
+ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ bias-pull-up;
+ linux,code = <KEY_POWER>;
+ };
+ };
+
+ pm8950_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400>;
+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ io-channels = <&pm8950_vadc VADC_DIE_TEMP>;
+ io-channel-names = "thermal";
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm8950_vadc: adc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ vcoin@5 {
+ reg = <VADC_VCOIN>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vph-pwr@7 {
+ reg = <VADC_VSYS>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ die-temp@8 {
+ reg = <VADC_DIE_TEMP>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ ref-625mv@9 {
+ reg = <VADC_REF_625MV>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ ref-1250mv@a {
+ reg = <VADC_REF_1250MV>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ ref-buf-625mv@c {
+ reg = <VADC_SPARE1>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ ref-gnd@e {
+ reg = <VADC_GND_REF>;
+ };
+
+ ref-vdd@f {
+ reg = <VADC_VDD_VADC>;
+ };
+
+ pa-therm1@11 {
+ reg = <VADC_P_MUX2_1_1>;
+ qcom,pre-scaling = <1 1>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+
+ case-therm@13 {
+ reg = <VADC_P_MUX4_1_1>;
+ qcom,pre-scaling = <1 1>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+
+ xo-therm@32 {
+ reg = <VADC_LR_MUX3_XO_THERM>;
+ qcom,pre-scaling = <1 1>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+
+ pa-therm0@36 {
+ reg = <VADC_LR_MUX7_HW_ID>;
+ qcom,pre-scaling = <1 1>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+
+ xo-therm-buf@3c {
+ reg = <VADC_LR_MUX3_BUF_XO_THERM>;
+ qcom,pre-scaling = <1 1>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ };
+ };
+
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+ };
+
+ pm8950_mpps: mpps@a000 {
+ compatible = "qcom,pm8950-mpp", "qcom,spmi-mpp";
+ reg = <0xa000>;
+ gpio-controller;
+ gpio-ranges = <&pm8950_mpps 0 0 4>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pm8950_gpio: gpio@c000 {
+ compatible = "qcom,pm8950-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pm8950_gpio 0 0 8>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pmic@1 {
+ compatible = "qcom,pm8950", "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8950_spmi_regulators: regulators {
+ compatible = "qcom,pm8950-regulators";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8994.dtsi b/arch/arm64/boot/dts/qcom/pm8994.dtsi
index e92e5ac414d3..672094c8ca58 100644
--- a/arch/arm64/boot/dts/qcom/pm8994.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8994.dtsi
@@ -108,7 +108,7 @@
};
};
- pm8994_gpios: gpios@c000 {
+ pm8994_gpios: gpio@c000 {
compatible = "qcom,pm8994-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index d09f2954b6f9..6a5854333b2b 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -52,6 +52,14 @@
bias-pull-up;
linux,code = <KEY_POWER>;
};
+
+ pm8998_resin: resin {
+ compatible = "qcom,pm8941-resin";
+ interrupts = <GIC_SPI 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ bias-pull-up;
+ status = "disabled";
+ };
};
pm8998_temp: temp-alarm@2400 {
@@ -63,7 +71,7 @@
#thermal-sensor-cells = <0>;
};
- pm8998_coincell: coincell@2800 {
+ pm8998_coincell: charger@2800 {
compatible = "qcom,pm8941-coincell";
reg = <0x2800>;
@@ -101,7 +109,7 @@
interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
};
- pm8998_gpio: gpios@c000 {
+ pm8998_gpio: gpio@c000 {
compatible = "qcom,pm8998-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
new file mode 100644
index 000000000000..32d27e2187e3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019, AngeloGioacchino Del Regno <kholk11@gmail.com>
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+&spmi_bus {
+ pmic@2 {
+ compatible = "qcom,pmi8950", "qcom,spmi-pmic";
+ reg = <0x2 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmi8950_vadc: adc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100>;
+ interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ adc-chan@0 {
+ reg = <VADC_USBIN>;
+ qcom,pre-scaling = <1 4>;
+ label = "usbin";
+ };
+
+ adc-chan@1 {
+ reg = <VADC_DCIN>;
+ qcom,pre-scaling = <1 4>;
+ label = "dcin";
+ };
+
+ adc-chan@2 {
+ reg = <VADC_VCHG_SNS>;
+ qcom,pre-scaling = <1 1>;
+ label = "vchg_sns";
+ };
+
+ adc-chan@9 {
+ reg = <VADC_REF_625MV>;
+ qcom,pre-scaling = <1 1>;
+ label = "ref_625mv";
+ };
+
+ adc-chan@a {
+ reg = <VADC_REF_1250MV>;
+ qcom,pre-scaling = <1 1>;
+ label = "ref_1250v";
+ };
+
+ adc-chan@d {
+ reg = <VADC_SPARE2>;
+ qcom,pre-scaling = <1 1>;
+ label = "chg_temp";
+ };
+ };
+
+ pmi8950_mpps: mpps@a000 {
+ compatible = "qcom,pmi8950-mpp", "qcom,spmi-mpp";
+ reg = <0xa000>;
+ gpio-controller;
+ gpio-ranges = <&pmi8950_mpps 0 0 4>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pmi8950_gpio: gpio@c000 {
+ compatible = "qcom,pmi8950-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ gpio-ranges = <&pmi8950_gpio 0 0 2>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pmic@3 {
+ compatible = "qcom,pmi8950", "qcom,spmi-pmic";
+ reg = <0x3 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmi8950_wled: leds@d800 {
+ compatible = "qcom,pmi8950-wled";
+ reg = <0xd800>, <0xd900>;
+ interrupts = <0x3 0xd8 0x02 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "short";
+ label = "backlight";
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
index 542c215dde10..a0af91698d49 100644
--- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
@@ -10,7 +10,7 @@
#address-cells = <1>;
#size-cells = <0>;
- pmi8994_gpios: gpios@c000 {
+ pmi8994_gpios: gpio@c000 {
compatible = "qcom,pmi8994-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 3852a012bb0f..cd1caeae8281 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -9,7 +9,7 @@
#address-cells = <1>;
#size-cells = <0>;
- pmi8998_gpio: gpios@c000 {
+ pmi8998_gpio: gpio@c000 {
compatible = "qcom,pmi8998-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
@@ -18,6 +18,14 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ pmi8998_rradc: adc@4500 {
+ compatible = "qcom,pmi8998-rradc";
+ reg = <0x4500>;
+ #io-channel-cells = <1>;
+
+ status = "disabled";
+ };
};
pmi8998_lsid1: pmic@3 {
diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi
index a7ec9d11946d..32f5e6af8c11 100644
--- a/arch/arm64/boot/dts/qcom/pmk8350.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi
@@ -8,27 +8,33 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
+/* (Sadly) this PMIC can be configured to be at different SIDs */
+#ifndef PMK8350_SID
+ #define PMK8350_SID 0
+#endif
+
&spmi_bus {
- pmk8350: pmic@0 {
+ pmk8350: pmic@PMK8350_SID {
compatible = "qcom,pmk8350", "qcom,spmi-pmic";
- reg = <0x0 SPMI_USID>;
+ reg = <PMK8350_SID SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
pmk8350_pon: pon@1300 {
compatible = "qcom,pm8998-pon";
- reg = <0x1300>;
+ reg = <0x1300>, <0x800>;
+ reg-names = "hlos", "pbs";
pon_pwrkey: pwrkey {
compatible = "qcom,pmk8350-pwrkey";
- interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_BOTH>;
+ interrupts = <PMK8350_SID 0x13 0x7 IRQ_TYPE_EDGE_BOTH>;
linux,code = <KEY_POWER>;
status = "disabled";
};
pon_resin: resin {
compatible = "qcom,pmk8350-resin";
- interrupts = <0x0 0x13 0x6 IRQ_TYPE_EDGE_BOTH>;
+ interrupts = <PMK8350_SID 0x13 0x6 IRQ_TYPE_EDGE_BOTH>;
status = "disabled";
};
};
@@ -38,14 +44,14 @@
reg = <0x3100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <PMK8350_SID 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
#io-channel-cells = <1>;
};
pmk8350_adc_tm: adc-tm@3400 {
compatible = "qcom,adc-tm7";
reg = <0x3400>;
- interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <PMK8350_SID 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
#thermal-sensor-cells = <1>;
@@ -56,7 +62,7 @@
compatible = "qcom,pmk8350-rtc";
reg = <0x6100>, <0x6200>;
reg-names = "rtc", "alarm";
- interrupts = <0x0 0x62 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <PMK8350_SID 0x62 0x1 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/pmp8074.dtsi b/arch/arm64/boot/dts/qcom/pmp8074.dtsi
new file mode 100644
index 000000000000..ceb2e6358b3d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pmp8074.dtsi
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+
+&spmi_bus {
+ pmic@0 {
+ compatible = "qcom,pmp8074", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmp8074_adc: adc@3100 {
+ compatible = "qcom,spmi-adc-rev2";
+ reg = <0x3100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ ref-gnd@0 {
+ reg = <ADC5_REF_GND>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vref-1p25@1 {
+ reg = <ADC5_1P25VREF>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vref-vadc@2 {
+ reg = <ADC5_VREF_VADC>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ pmic_die: die-temp@6 {
+ reg = <ADC5_DIE_TEMP>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ xo_therm: xo-temp@76 {
+ reg = <ADC5_XO_THERM_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ pa_therm1: thermistor1@77 {
+ reg = <ADC5_AMUX_THM1_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ pa_therm2: thermistor2@78 {
+ reg = <ADC5_AMUX_THM2_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ pa_therm3: thermistor3@79 {
+ reg = <ADC5_AMUX_THM3_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ vph-pwr@131 {
+ reg = <ADC5_VPH_PWR>;
+ qcom,pre-scaling = <1 3>;
+ };
+ };
+
+ pmp8074_rtc: rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+ allow-set-time;
+ status = "disabled";
+ };
+
+ pmp8074_gpios: gpio@c000 {
+ compatible = "qcom,pmp8074-gpio", "qcom,spmi-gpio";
+ reg = <0xc000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pmp8074_gpios 0 0 12>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pmic@1 {
+ compatible = "qcom,pmp8074", "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+
+ regulators {
+ compatible = "qcom,pmp8074-regulators";
+
+ s3: s3 {
+ regulator-name = "vdd_s3";
+ regulator-min-microvolt = <592000>;
+ regulator-max-microvolt = <1064000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ s4: s4 {
+ regulator-name = "vdd_s4";
+ regulator-min-microvolt = <712000>;
+ regulator-max-microvolt = <992000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l11: l11 {
+ regulator-name = "l11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pms405.dtsi b/arch/arm64/boot/dts/qcom/pms405.dtsi
index 634b0681d04c..ffe9e33808d0 100644
--- a/arch/arm64/boot/dts/qcom/pms405.dtsi
+++ b/arch/arm64/boot/dts/qcom/pms405.dtsi
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
#include <dt-bindings/spmi/spmi.h>
#include <dt-bindings/input/linux-event-codes.h>
diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts b/arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts
index 937eb4555ffe..fc29b194cd34 100644
--- a/arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts
+++ b/arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
/dts-v1/;
diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts b/arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts
index 08d5d51221cf..59702ba24f35 100644
--- a/arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts
+++ b/arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
/dts-v1/;
@@ -37,54 +39,54 @@
};
&tlmm {
- ethernet_defaults: ethernet-defaults {
- int {
+ ethernet_defaults: ethernet-defaults-state {
+ int-pins {
pins = "gpio61";
function = "rgmii_int";
bias-disable;
drive-strength = <2>;
};
- mdc {
+ mdc-pins {
pins = "gpio76";
function = "rgmii_mdc";
bias-pull-up;
};
- mdio {
+ mdio-pins {
pins = "gpio75";
function = "rgmii_mdio";
bias-pull-up;
};
- tx {
+ tx-pins {
pins = "gpio67", "gpio66", "gpio65", "gpio64";
function = "rgmii_tx";
bias-pull-up;
drive-strength = <16>;
};
- rx {
+ rx-pins {
pins = "gpio73", "gpio72", "gpio71", "gpio70";
function = "rgmii_rx";
bias-disable;
drive-strength = <2>;
};
- tx-ctl {
+ tx-ctl-pins {
pins = "gpio68";
function = "rgmii_ctl";
bias-pull-up;
drive-strength = <16>;
};
- rx-ctl {
+ rx-ctl-pins {
pins = "gpio74";
function = "rgmii_ctl";
bias-disable;
drive-strength = <2>;
};
- tx-ck {
+ tx-ck-pins {
pins = "gpio63";
function = "rgmii_ck";
bias-pull-up;
drive-strength = <16>;
};
- rx-ck {
+ rx-ck-pins {
pins = "gpio69";
function = "rgmii_ck";
bias-disable;
diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
index 1678ef0f8684..04c82d1624eb 100644
--- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
#include <dt-bindings/gpio/gpio.h>
#include "qcs404.dtsi"
@@ -125,7 +127,7 @@
};
&rpm_requests {
- pms405-regulators {
+ regulators {
compatible = "qcom,rpm-pms405-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -229,7 +231,7 @@
};
&tlmm {
- perst_state: perst {
+ perst_state: perst-state {
pins = "gpio43";
function = "gpio";
@@ -238,68 +240,63 @@
output-low;
};
- sdc1_on: sdc1-on {
- clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc1_off: sdc1-off {
- clk {
+ sdc1_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- usb3_id_pin: usb3-id-pin {
- pinmux {
- pins = "gpio116";
- function = "gpio";
- };
+ usb3_id_pin: usb3-id-state {
+ pins = "gpio116";
+ function = "gpio";
- pinconf {
- pins = "gpio116";
- drive-strength = <2>;
- bias-pull-up;
- input-enable;
- };
+ drive-strength = <2>;
+ bias-pull-up;
+ input-enable;
};
};
@@ -366,31 +363,28 @@
/* PINCTRL - additions to nodes defined in qcs404.dtsi */
&blsp1_uart2_default {
- rx {
+ rx-pins {
drive-strength = <2>;
bias-disable;
};
- tx {
+ tx-pins {
drive-strength = <2>;
bias-disable;
};
};
&blsp1_uart3_default {
- cts {
- pins = "gpio84";
+ cts-pins {
bias-disable;
};
- rts-tx {
- pins = "gpio85", "gpio82";
+ rts-tx-pins {
drive-strength = <2>;
bias-disable;
};
- rx {
- pins = "gpio83";
+ rx-pins {
bias-pull-up;
};
};
diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
index 80f2d05595fa..a5324eecb50a 100644
--- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-qcs404.h>
@@ -593,118 +595,130 @@
interrupt-controller;
#interrupt-cells = <2>;
- blsp1_i2c0_default: blsp1-i2c0-default {
+ blsp1_i2c0_default: blsp1-i2c0-default-state {
pins = "gpio32", "gpio33";
function = "blsp_i2c0";
};
- blsp1_i2c1_default: blsp1-i2c1-default {
+ blsp1_i2c1_default: blsp1-i2c1-default-state {
pins = "gpio24", "gpio25";
function = "blsp_i2c1";
};
- blsp1_i2c2_default: blsp1-i2c2-default {
- sda {
+ blsp1_i2c2_default: blsp1-i2c2-default-state {
+ sda-pins {
pins = "gpio19";
function = "blsp_i2c_sda_a2";
};
- scl {
+ scl-pins {
pins = "gpio20";
function = "blsp_i2c_scl_a2";
};
};
- blsp1_i2c3_default: blsp1-i2c3-default {
+ blsp1_i2c3_default: blsp1-i2c3-default-state {
pins = "gpio84", "gpio85";
function = "blsp_i2c3";
};
- blsp1_i2c4_default: blsp1-i2c4-default {
+ blsp1_i2c4_default: blsp1-i2c4-default-state {
pins = "gpio117", "gpio118";
function = "blsp_i2c4";
};
- blsp1_uart0_default: blsp1-uart0-default {
+ blsp1_uart0_default: blsp1-uart0-default-state {
pins = "gpio30", "gpio31", "gpio32", "gpio33";
function = "blsp_uart0";
};
- blsp1_uart1_default: blsp1-uart1-default {
+ blsp1_uart1_default: blsp1-uart1-default-state {
pins = "gpio22", "gpio23";
function = "blsp_uart1";
};
- blsp1_uart2_default: blsp1-uart2-default {
- rx {
+ blsp1_uart2_default: blsp1-uart2-default-state {
+ rx-pins {
pins = "gpio18";
function = "blsp_uart_rx_a2";
};
- tx {
+ tx-pins {
pins = "gpio17";
function = "blsp_uart_tx_a2";
};
};
- blsp1_uart3_default: blsp1-uart3-default {
- pins = "gpio82", "gpio83", "gpio84", "gpio85";
- function = "blsp_uart3";
+ blsp1_uart3_default: blsp1-uart3-default-state {
+ cts-pins {
+ pins = "gpio84";
+ function = "blsp_uart3";
+ };
+
+ rts-tx-pins {
+ pins = "gpio85", "gpio82";
+ function = "blsp_uart3";
+ };
+
+ rx-pins {
+ pins = "gpio83";
+ function = "blsp_uart3";
+ };
};
- blsp2_i2c0_default: blsp2-i2c0-default {
+ blsp2_i2c0_default: blsp2-i2c0-default-state {
pins = "gpio28", "gpio29";
function = "blsp_i2c5";
};
- blsp1_spi0_default: blsp1-spi0-default {
+ blsp1_spi0_default: blsp1-spi0-default-state {
pins = "gpio30", "gpio31", "gpio32", "gpio33";
function = "blsp_spi0";
};
- blsp1_spi1_default: blsp1-spi1-default {
- mosi {
+ blsp1_spi1_default: blsp1-spi1-default-state {
+ mosi-pins {
pins = "gpio22";
function = "blsp_spi_mosi_a1";
};
- miso {
+ miso-pins {
pins = "gpio23";
function = "blsp_spi_miso_a1";
};
- cs_n {
+ cs-n-pins {
pins = "gpio24";
function = "blsp_spi_cs_n_a1";
};
- clk {
+ clk-pins {
pins = "gpio25";
function = "blsp_spi_clk_a1";
};
};
- blsp1_spi2_default: blsp1-spi2-default {
+ blsp1_spi2_default: blsp1-spi2-default-state {
pins = "gpio17", "gpio18", "gpio19", "gpio20";
function = "blsp_spi2";
};
- blsp1_spi3_default: blsp1-spi3-default {
+ blsp1_spi3_default: blsp1-spi3-default-state {
pins = "gpio82", "gpio83", "gpio84", "gpio85";
function = "blsp_spi3";
};
- blsp1_spi4_default: blsp1-spi4-default {
+ blsp1_spi4_default: blsp1-spi4-default-state {
pins = "gpio37", "gpio38", "gpio117", "gpio118";
function = "blsp_spi4";
};
- blsp2_spi0_default: blsp2-spi0-default {
+ blsp2_spi0_default: blsp2-spi0-default-state {
pins = "gpio26", "gpio27", "gpio28", "gpio29";
function = "blsp_spi5";
};
- blsp2_uart0_default: blsp2-uart0-default {
+ blsp2_uart0_default: blsp2-uart0-default-state {
pins = "gpio26", "gpio27", "gpio28", "gpio29";
function = "blsp_uart5";
};
diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts
new file mode 100644
index 000000000000..bb149e577914
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ */
+
+/dts-v1/;
+
+#include "qrb5165-rb5.dts"
+
+&camcc {
+ status = "okay";
+};
+
+&camss {
+ vdda-phy-supply = <&vreg_l5a_0p88>;
+ vdda-pll-supply = <&vreg_l9a_1p2>;
+ status = "okay";
+
+ ports {
+ /* The port index denotes CSIPHY id i.e. csiphy2 */
+ port@2 {
+ csiphy2_ep: endpoint {
+ clock-lanes = <7>;
+ data-lanes = <0 1 2 3>;
+ remote-endpoint = <&imx577_ep>;
+ };
+ };
+ };
+};
+
+&cci1 {
+ status = "okay";
+};
+
+&cci1_i2c0 {
+ camera@1a {
+ compatible = "sony,imx577";
+ reg = <0x1a>;
+
+ reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default", "suspend";
+ pinctrl-0 = <&cam2_default>;
+ pinctrl-1 = <&cam2_suspend>;
+
+ clocks = <&camcc CAM_CC_MCLK2_CLK>;
+ assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>;
+ assigned-clock-rates = <24000000>;
+
+ dovdd-supply = <&vreg_l7f_1p8>;
+ avdd-supply = <&vdc_5v>;
+ dvdd-supply = <&vdc_5v>;
+
+ port {
+ imx577_ep: endpoint {
+ clock-lanes = <1>;
+ link-frequencies = /bits/ 64 <600000000>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csiphy2_ep>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
index bf8077a1cf9a..8c64cb060e21 100644
--- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
+++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
@@ -867,7 +867,7 @@
};
&q6afedai {
- qi2s@16 {
+ dai@16 {
reg = <PRIMARY_MI2S_RX>;
qcom,sd-lines = <0 1 2 3>;
};
@@ -875,7 +875,7 @@
/* TERT I2S Uses 1 I2S SD Lines for audio on LT9611 HDMI Bridge */
&q6afedai {
- qi2s@20 {
+ dai@20 {
reg = <TERTIARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
@@ -904,7 +904,7 @@
cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>;
bus-width = <4>;
no-sdio;
- no-emmc;
+ no-mmc;
};
&sound {
@@ -1007,7 +1007,7 @@
};
&swr0 {
- left_spkr: wsa8810-left{
+ left_spkr: speaker@0,3 {
compatible = "sdw10217211000";
reg = <0 3>;
powerdown-gpios = <&tlmm 130 GPIO_ACTIVE_HIGH>;
@@ -1016,7 +1016,7 @@
#sound-dai-cells = <0>;
};
- right_spkr: wsa8810-right{
+ right_spkr: speaker@0,4 {
compatible = "sdw10217211000";
reg = <0 4>;
powerdown-gpios = <&tlmm 130 GPIO_ACTIVE_HIGH>;
@@ -1210,33 +1210,33 @@
"HST_WLAN_UART_TX",
"HST_WLAN_UART_RX";
- lt9611_irq_pin: lt9611-irq {
+ lt9611_irq_pin: lt9611-irq-state {
pins = "gpio63";
function = "gpio";
bias-disable;
};
- sdc2_default_state: sdc2-default {
- clk {
+ sdc2_default_state: sdc2-default-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
};
- sdc2_card_det_n: sd-card-det-n {
+ sdc2_card_det_n: sd-card-det-n-state {
pins = "gpio77";
function = "gpio";
bias-pull-up;
diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts
index 87ab0e1ecd16..f41dcc379dce 100644
--- a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts
+++ b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts
@@ -43,7 +43,6 @@
regulator-always-on;
regulator-boot-on;
- regulator-allow-set-load;
vin-supply = <&vreg_3p3>;
};
@@ -137,6 +136,8 @@
regulator-max-microvolt = <880000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7a_1p8: ldo7 {
@@ -152,6 +153,8 @@
regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l11a_0p8: ldo11 {
@@ -258,6 +261,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7c_1p8: ldo7 {
@@ -273,6 +278,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l10c_3p3: ldo10 {
@@ -386,7 +393,7 @@
vmmc-supply = <&vreg_l17a_2p96>; /* Card power line */
bus-width = <4>;
no-sdio;
- no-emmc;
+ no-mmc;
};
&uart2 {
@@ -477,26 +484,26 @@
&tlmm {
gpio-reserved-ranges = <0 4>;
- sdc2_on: sdc2_on {
- clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable; /* No pull */
drive-strength = <16>; /* 16 MA */
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up; /* pull up */
drive-strength = <16>; /* 16 MA */
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up; /* pull up */
drive-strength = <16>; /* 16 MA */
};
- sd-cd {
+ sd-cd-pins {
pins = "gpio96";
function = "gpio";
bias-pull-up; /* pull up */
@@ -504,26 +511,26 @@
};
};
- sdc2_off: sdc2_off {
- clk {
+ sdc2_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable; /* No pull */
drive-strength = <2>; /* 2 MA */
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up; /* pull up */
drive-strength = <2>; /* 2 MA */
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up; /* pull up */
drive-strength = <2>; /* 2 MA */
};
- sd-cd {
+ sd-cd-pins {
pins = "gpio96";
function = "gpio";
bias-pull-up; /* pull up */
@@ -531,66 +538,62 @@
};
};
- usb2phy_ac_en1_default: usb2phy_ac_en1_default {
- mux {
- pins = "gpio113";
- function = "usb2phy_ac";
- bias-disable;
- drive-strength = <2>;
- };
+ usb2phy_ac_en1_default: usb2phy-ac-en1-default-state {
+ pins = "gpio113";
+ function = "usb2phy_ac";
+ bias-disable;
+ drive-strength = <2>;
};
- usb2phy_ac_en2_default: usb2phy_ac_en2_default {
- mux {
- pins = "gpio123";
- function = "usb2phy_ac";
- bias-disable;
- drive-strength = <2>;
- };
+ usb2phy_ac_en2_default: usb2phy-ac-en2-default-state {
+ pins = "gpio123";
+ function = "usb2phy_ac";
+ bias-disable;
+ drive-strength = <2>;
};
- ethernet_defaults: ethernet-defaults {
- mdc {
+ ethernet_defaults: ethernet-defaults-state {
+ mdc-pins {
pins = "gpio7";
function = "rgmii";
bias-pull-up;
};
- mdio {
+ mdio-pins {
pins = "gpio59";
function = "rgmii";
bias-pull-up;
};
- rgmii-rx {
+ rgmii-rx-pins {
pins = "gpio117", "gpio118", "gpio119", "gpio120", "gpio115", "gpio116";
function = "rgmii";
bias-disable;
drive-strength = <2>;
};
- rgmii-tx {
+ rgmii-tx-pins {
pins = "gpio122", "gpio4", "gpio5", "gpio6", "gpio114", "gpio121";
function = "rgmii";
bias-pull-up;
drive-strength = <16>;
};
- phy-intr {
+ phy-intr-pins {
pins = "gpio124";
function = "emac_phy";
bias-disable;
drive-strength = <8>;
};
- pps {
+ pps-pins {
pins = "gpio81";
function = "emac_pps";
bias-disable;
drive-strength = <8>;
};
- phy-reset {
+ phy-reset-pins {
pins = "gpio79";
function = "gpio";
bias-pull-up;
diff --git a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
index b608b82dff03..84cb6f3eeb56 100644
--- a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
+++ b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
@@ -57,6 +57,13 @@
regulator-max-microvolt = <3072000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
};
+
+ vreg_l11a: ldo11 {
+ regulator-name = "vreg_l11a";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
};
pmm8540-c-regulators {
@@ -83,6 +90,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l4c: ldo4 {
@@ -98,6 +107,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7c: ldo7 {
@@ -113,6 +124,8 @@
regulator-max-microvolt = <2504000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l17c: ldo17 {
@@ -121,6 +134,8 @@
regulator-max-microvolt = <2504000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
};
@@ -151,6 +166,76 @@
};
};
+&pcie2a {
+ perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie2a_default>;
+
+ status = "okay";
+};
+
+&pcie2a_phy {
+ vdda-phy-supply = <&vreg_l11a>;
+ vdda-pll-supply = <&vreg_l3a>;
+
+ status = "okay";
+};
+
+&pcie3a {
+ num-lanes = <2>;
+
+ perst-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 56 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie3a_default>;
+
+ status = "okay";
+};
+
+&pcie3a_phy {
+ vdda-phy-supply = <&vreg_l11a>;
+ vdda-pll-supply = <&vreg_l3a>;
+
+ status = "okay";
+};
+
+&pcie3b {
+ perst-gpios = <&tlmm 153 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 130 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie3b_default>;
+
+ status = "okay";
+};
+
+&pcie3b_phy {
+ vdda-phy-supply = <&vreg_l11a>;
+ vdda-pll-supply = <&vreg_l3a>;
+
+ status = "okay";
+};
+
+&pcie4 {
+ perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie4_default>;
+
+ status = "okay";
+};
+
+&pcie4_phy {
+ vdda-phy-supply = <&vreg_l11a>;
+ vdda-pll-supply = <&vreg_l3a>;
+
+ status = "okay";
+};
+
&qup2 {
status = "okay";
};
@@ -182,6 +267,14 @@
#address-cells = <1>;
#size-cells = <0>;
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+ wakeup-source;
+ };
+
pm8450a_gpios: gpio@c000 {
compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
@@ -380,3 +473,97 @@
};
/* PINCTRL */
+
+&tlmm {
+ pcie2a_default: pcie2a-default-state {
+ clkreq-n-pins {
+ pins = "gpio142";
+ function = "pcie2a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio143";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio145";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie3a_default: pcie3a-default-state {
+ clkreq-n-pins {
+ pins = "gpio150";
+ function = "pcie3a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio151";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio56";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie3b_default: pcie3b-default-state {
+ clkreq-n-pins {
+ pins = "gpio152";
+ function = "pcie3b_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio153";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio130";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie4_default: pcie4-default-state {
+ clkreq-n-pins {
+ pins = "gpio140";
+ function = "pcie4_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio141";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio139";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sa8540p-ride.dts b/arch/arm64/boot/dts/qcom/sa8540p-ride.dts
new file mode 100644
index 000000000000..6c547f1b13dc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sa8540p-ride.dts
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "sa8540p.dtsi"
+#include "pm8450a.dtsi"
+
+/ {
+ model = "Qualcomm SA8540P Ride";
+ compatible = "qcom,sa8540p-ride", "qcom,sa8540p";
+
+ aliases {
+ serial0 = &qup2_uart17;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm8150-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vreg_l3a: ldo3 {
+ regulator-name = "vreg_l3a";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1208000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l5a: ldo5 {
+ regulator-name = "vreg_l5a";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7a: ldo7 {
+ regulator-name = "vreg_l7a";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l11a: ldo11 {
+ regulator-name = "vreg_l11a";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l13a: ldo13 {
+ regulator-name = "vreg_l13a";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8150-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vreg_l1c: ldo1 {
+ regulator-name = "vreg_l1c";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2c: ldo2 {
+ regulator-name = "vreg_l2c";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4c: ldo4 {
+ regulator-name = "vreg_l4c";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1208000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6c: ldo6 {
+ regulator-name = "vreg_l6c";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ vreg_l7c: ldo7 {
+ regulator-name = "vreg_l7c";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17c: ldo17 {
+ regulator-name = "vreg_l17c";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <2504000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+ };
+
+ regulators-2 {
+ compatible = "qcom,pm8150-rpmh-regulators";
+ qcom,pmic-id = "g";
+
+ vreg_l3g: ldo3 {
+ regulator-name = "vreg_l3g";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7g: ldo7 {
+ regulator-name = "vreg_l7g";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8g: ldo8 {
+ regulator-name = "vreg_l8g";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+};
+
+&pcie3a {
+ ranges = <0x01000000 0x0 0x40200000 0x0 0x40200000 0x0 0x100000>,
+ <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x20000000>,
+ <0x03000000 0x6 0x00000000 0x6 0x00000000 0x2 0x00000000>;
+
+ perst-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 56 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie3a_default>;
+
+ status = "okay";
+};
+
+&pcie3a_phy {
+ vdda-phy-supply = <&vreg_l11a>;
+ vdda-pll-supply = <&vreg_l3a>;
+
+ status = "okay";
+};
+
+&qup2 {
+ status = "okay";
+};
+
+&qup2_uart17 {
+ compatible = "qcom,geni-debug-uart";
+ status = "okay";
+};
+
+&remoteproc_nsp0 {
+ firmware-name = "qcom/sa8540p/cdsp.mbn";
+ status = "okay";
+};
+
+&remoteproc_nsp1 {
+ firmware-name = "qcom/sa8540p/cdsp1.mbn";
+ status = "okay";
+};
+
+&tlmm {
+ pcie3a_default: pcie3a-default-state {
+ perst-pins {
+ pins = "gpio151";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ clkreq-pins {
+ pins = "gpio150";
+ function = "pcie3a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ wake-pins {
+ pins = "gpio56";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+};
+
+&ufs_mem_hc {
+ reset-gpios = <&tlmm 228 GPIO_ACTIVE_LOW>;
+
+ vcc-supply = <&vreg_l17c>;
+ vccq-supply = <&vreg_l6c>;
+
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ vdda-phy-supply = <&vreg_l8g>;
+ vdda-pll-supply = <&vreg_l3g>;
+
+ status = "okay";
+};
+
+&usb_0 {
+ status = "okay";
+};
+
+&usb_0_dwc3 {
+ dr_mode = "peripheral";
+};
+
+&usb_0_hsphy {
+ vdda-pll-supply = <&vreg_l5a>;
+ vdda18-supply = <&vreg_l7a>;
+ vdda33-supply = <&vreg_l13a>;
+
+ status = "okay";
+};
+
+&usb_0_qmpphy {
+ vdda-phy-supply = <&vreg_l3a>;
+ vdda-pll-supply = <&vreg_l5a>;
+
+ status = "okay";
+};
+
+&usb_2_hsphy0 {
+ vdda-pll-supply = <&vreg_l5a>;
+ vdda18-supply = <&vreg_l7g>;
+ vdda33-supply = <&vreg_l13a>;
+
+ status = "okay";
+};
+
+&usb_2_qmpphy0 {
+ vdda-phy-supply = <&vreg_l3a>;
+ vdda-pll-supply = <&vreg_l5a>;
+
+ status = "okay";
+};
+
+&xo_board_clk {
+ clock-frequency = <38400000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sa8540p.dtsi b/arch/arm64/boot/dts/qcom/sa8540p.dtsi
index 8ea2886fbab2..a88452c20d05 100644
--- a/arch/arm64/boot/dts/qcom/sa8540p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8540p.dtsi
@@ -14,59 +14,81 @@
compatible = "operating-points-v2";
opp-shared;
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ opp-peak-kBps = <(300000 * 32)>;
+ };
opp-403200000 {
opp-hz = /bits/ 64 <403200000>;
+ opp-peak-kBps = <(384000 * 32)>;
};
opp-499200000 {
opp-hz = /bits/ 64 <499200000>;
+ opp-peak-kBps = <(480000 * 32)>;
};
opp-595200000 {
opp-hz = /bits/ 64 <595200000>;
+ opp-peak-kBps = <(576000 * 32)>;
};
opp-710400000 {
opp-hz = /bits/ 64 <710400000>;
+ opp-peak-kBps = <(672000 * 32)>;
};
opp-806400000 {
opp-hz = /bits/ 64 <806400000>;
+ opp-peak-kBps = <(768000 * 32)>;
};
opp-902400000 {
opp-hz = /bits/ 64 <902400000>;
+ opp-peak-kBps = <(864000 * 32)>;
};
opp-1017600000 {
opp-hz = /bits/ 64 <1017600000>;
+ opp-peak-kBps = <(960000 * 32)>;
};
opp-1113600000 {
opp-hz = /bits/ 64 <1113600000>;
+ opp-peak-kBps = <(1075200 * 32)>;
};
opp-1209600000 {
opp-hz = /bits/ 64 <1209600000>;
+ opp-peak-kBps = <(1171200 * 32)>;
};
opp-1324800000 {
opp-hz = /bits/ 64 <1324800000>;
+ opp-peak-kBps = <(1286400 * 32)>;
};
opp-1440000000 {
opp-hz = /bits/ 64 <1440000000>;
+ opp-peak-kBps = <(1382400 * 32)>;
};
opp-1555200000 {
opp-hz = /bits/ 64 <1555200000>;
+ opp-peak-kBps = <(1497600 * 32)>;
};
opp-1670400000 {
opp-hz = /bits/ 64 <1670400000>;
+ opp-peak-kBps = <(1593600 * 32)>;
};
opp-1785600000 {
opp-hz = /bits/ 64 <1785600000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-1881600000 {
opp-hz = /bits/ 64 <1881600000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2016000000 {
opp-hz = /bits/ 64 <2016000000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2131200000 {
opp-hz = /bits/ 64 <2131200000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2246400000 {
opp-hz = /bits/ 64 <2246400000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
};
@@ -76,58 +98,134 @@
opp-825600000 {
opp-hz = /bits/ 64 <825600000>;
+ opp-peak-kBps = <(300000 * 32)>;
};
opp-940800000 {
opp-hz = /bits/ 64 <940800000>;
+ opp-peak-kBps = <(864000 * 32)>;
};
opp-1056000000 {
opp-hz = /bits/ 64 <1056000000>;
+ opp-peak-kBps = <(960000 * 32)>;
};
opp-1171200000 {
opp-hz = /bits/ 64 <1171200000>;
+ opp-peak-kBps = <(1171200 * 32)>;
};
opp-1286400000 {
opp-hz = /bits/ 64 <1286400000>;
+ opp-peak-kBps = <(1286400 * 32)>;
};
opp-1401600000 {
opp-hz = /bits/ 64 <1401600000>;
+ opp-peak-kBps = <(1382400 * 32)>;
};
opp-1516800000 {
opp-hz = /bits/ 64 <1516800000>;
+ opp-peak-kBps = <(1497600 * 32)>;
};
opp-1632000000 {
opp-hz = /bits/ 64 <1632000000>;
+ opp-peak-kBps = <(1593600 * 32)>;
};
opp-1747200000 {
opp-hz = /bits/ 64 <1747200000>;
+ opp-peak-kBps = <(1593600 * 32)>;
};
opp-1862400000 {
opp-hz = /bits/ 64 <1862400000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-1977600000 {
opp-hz = /bits/ 64 <1977600000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2073600000 {
opp-hz = /bits/ 64 <2073600000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2169600000 {
opp-hz = /bits/ 64 <2169600000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2284800000 {
opp-hz = /bits/ 64 <2284800000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2380800000 {
opp-hz = /bits/ 64 <2380800000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2496000000 {
opp-hz = /bits/ 64 <2496000000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
opp-2592000000 {
opp-hz = /bits/ 64 <2592000000>;
+ opp-peak-kBps = <(1708800 * 32)>;
};
};
};
+&pcie2a {
+ compatible = "qcom,pcie-sa8540p";
+
+ linux,pci-domain = <0>;
+
+ interrupts = <GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi";
+};
+
+&pcie2b {
+ compatible = "qcom,pcie-sa8540p";
+
+ linux,pci-domain = <1>;
+
+ interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi";
+};
+
+&pcie3a {
+ compatible = "qcom,pcie-sa8540p";
+ reg = <0x0 0x01c10000 0x0 0x3000>,
+ <0x0 0x40000000 0x0 0xf1d>,
+ <0x0 0x40000f20 0x0 0xa8>,
+ <0x0 0x40001000 0x0 0x1000>,
+ <0x0 0x40100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+
+ ranges = <0x01000000 0x0 0x40200000 0x0 0x40200000 0x0 0x100000>,
+ <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1d00000>;
+
+ linux,pci-domain = <2>;
+
+ interrupts = <GIC_SPI 567 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi";
+
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 541 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 542 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 543 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 544 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&pcie3b {
+ compatible = "qcom,pcie-sa8540p";
+
+ linux,pci-domain = <3>;
+
+ interrupts = <GIC_SPI 565 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi";
+};
+
+&pcie4 {
+ compatible = "qcom,pcie-sa8540p";
+
+ linux,pci-domain = <4>;
+
+ interrupts = <GIC_SPI 518 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi";
+};
+
&rpmhpd {
compatible = "qcom,sa8540p-rpmhpd";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-idp.dts b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
index 9dee131b1e24..70fd9ff8dfa2 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-idp.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
@@ -481,287 +481,261 @@
};
&qspi_clk {
- pinconf {
- pins = "gpio63";
- bias-disable;
- };
+ bias-disable;
};
&qspi_cs0 {
- pinconf {
- pins = "gpio68";
- bias-disable;
- };
+ bias-disable;
};
&qspi_data01 {
- pinconf {
- pins = "gpio64", "gpio65";
-
- /* High-Z when no transfers; nice to park the lines */
- bias-pull-up;
- };
+ /* High-Z when no transfers; nice to park the lines */
+ bias-pull-up;
};
&qup_i2c2_default {
- pinconf {
- pins = "gpio15", "gpio16";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c4_default {
- pinconf {
- pins = "gpio115", "gpio116";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c7_default {
- pinconf {
- pins = "gpio6", "gpio7";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c9_default {
- pinconf {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
-&qup_uart3_default {
- pinconf-cts {
- /*
- * Configure a pull-down on CTS to match the pull of
- * the Bluetooth module.
- */
- pins = "gpio38";
- bias-pull-down;
- };
+&qup_uart3_cts {
+ /*
+ * Configure a pull-down on CTS to match the pull of
+ * the Bluetooth module.
+ */
+ bias-pull-down;
+};
- pinconf-rts {
- /* We'll drive RTS, so no pull */
- pins = "gpio39";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_uart3_rts {
+ /* We'll drive RTS, so no pull */
+ drive-strength = <2>;
+ bias-disable;
+};
- pinconf-tx {
- /* We'll drive TX, so no pull */
- pins = "gpio40";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_uart3_tx {
+ /* We'll drive TX, so no pull */
+ drive-strength = <2>;
+ bias-disable;
+};
- pinconf-rx {
- /*
- * Configure a pull-up on RX. This is needed to avoid
- * garbage data when the TX pin of the Bluetooth module is
- * in tri-state (module powered off or not driving the
- * signal yet).
- */
- pins = "gpio41";
- bias-pull-up;
- };
+&qup_uart3_rx {
+ /*
+ * Configure a pull-up on RX. This is needed to avoid
+ * garbage data when the TX pin of the Bluetooth module is
+ * in tri-state (module powered off or not driving the
+ * signal yet).
+ */
+ bias-pull-up;
};
-&qup_uart8_default {
- pinconf-tx {
- pins = "gpio44";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_uart8_tx {
+ drive-strength = <2>;
+ bias-disable;
+};
- pinconf-rx {
- pins = "gpio45";
- drive-strength = <2>;
- bias-pull-up;
- };
+&qup_uart8_rx {
+ drive-strength = <2>;
+ bias-pull-up;
};
-&qup_spi0_default {
- pinconf {
- pins = "gpio34", "gpio35", "gpio36", "gpio37";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_spi0_spi {
+ drive-strength = <2>;
+ bias-disable;
};
-&qup_spi6_default {
- pinconf {
- pins = "gpio59", "gpio60", "gpio61", "gpio62";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_spi0_cs {
+ drive-strength = <2>;
+ bias-disable;
};
-&qup_spi10_default {
- pinconf {
- pins = "gpio86", "gpio87", "gpio88", "gpio89";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_spi6_spi {
+ drive-strength = <2>;
+ bias-disable;
};
-&tlmm {
- qup_uart3_sleep: qup-uart3-sleep {
- pinmux {
- pins = "gpio38", "gpio39",
- "gpio40", "gpio41";
- function = "gpio";
- };
+&qup_spi6_cs {
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_spi10_spi {
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_spi10_cs {
+ drive-strength = <2>;
+ bias-disable;
+};
- pinconf-cts {
+&tlmm {
+ qup_uart3_sleep: qup-uart3-sleep-state {
+ cts-pins {
/*
* Configure a pull-down on CTS to match the pull of
* the Bluetooth module.
*/
pins = "gpio38";
+ function = "gpio";
bias-pull-down;
};
- pinconf-rts {
+ rts-pins {
/*
* Configure pull-down on RTS. As RTS is active low
* signal, pull it low to indicate the BT SoC that it
* can wakeup the system anytime from suspend state by
* pulling RX low (by sending wakeup bytes).
*/
- pins = "gpio39";
- bias-pull-down;
+ pins = "gpio39";
+ function = "gpio";
+ bias-pull-down;
};
- pinconf-tx {
+ tx-pins {
/*
* Configure pull-up on TX when it isn't actively driven
* to prevent BT SoC from receiving garbage during sleep.
*/
pins = "gpio40";
+ function = "gpio";
bias-pull-up;
};
- pinconf-rx {
+ rx-pins {
/*
* Configure a pull-up on RX. This is needed to avoid
* garbage data when the TX pin of the Bluetooth module
* is floating which may cause spurious wakeups.
*/
pins = "gpio41";
+ function = "gpio";
bias-pull-up;
};
};
- sdc1_on: sdc1-on {
- pinconf-clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc1_off: sdc1-off {
- pinconf-clk {
+ sdc1_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc2_on: sdc2-on {
- pinconf-clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-sd-cd {
+ sd-cd-pins {
pins = "gpio69";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
- sdc2_off: sdc2-off {
- pinconf-clk {
+ sdc2_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-sd-cd {
+ sd-cd-pins {
pins = "gpio69";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
index 7ee407f7b6bb..8b8ea8af165d 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
@@ -181,23 +181,15 @@ ap_ts_pen_1v8: &i2c4 {
/* PINCTRL - modifications to sc7180-trogdor.dtsi */
&en_pp3300_dx_edp {
- pinmux {
- pins = "gpio67";
- };
-
- pinconf {
- pins = "gpio67";
- };
+ pins = "gpio67";
};
&ts_reset_l {
- pinconf {
- /*
- * We want reset state by default and it will be up to the
- * driver to disable this when it's ready.
- */
- output-low;
- };
+ /*
+ * We want reset state by default and it will be up to the
+ * driver to disable this when it's ready.
+ */
+ output-low;
};
/* PINCTRL - board-specific pinctrl */
@@ -327,16 +319,10 @@ ap_ts_pen_1v8: &i2c4 {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- dmic_clk_en: dmic_clk_en {
- pinmux {
- pins = "gpio83";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio83";
- drive-strength = <8>;
- bias-pull-up;
- };
+ dmic_clk_en: dmic-clk-en-state {
+ pins = "gpio83";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
index 1bd6c7dcd9e9..d3cf64c16dcd 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
@@ -10,22 +10,22 @@
/ {
/* BOARD-SPECIFIC TOP LEVEL NODES */
- max98360a_1: max98360a_1 {
+ max98360a_1: amplifier-1 {
compatible = "maxim,max98360a";
#sound-dai-cells = <0>;
};
- max98360a_2: max98360a_2 {
+ max98360a_2: amplifier-2 {
compatible = "maxim,max98360a";
#sound-dai-cells = <0>;
};
- max98360a_3: max98360a_3 {
+ max98360a_3: amplifier-3 {
compatible = "maxim,max98360a";
#sound-dai-cells = <0>;
};
- pp3300_touch: pp3300-touch {
+ pp3300_touch: pp3300-touch-regulator {
compatible = "regulator-fixed";
regulator-name = "pp3300_touch";
@@ -180,30 +180,19 @@ ap_ts_pen_1v8: &i2c4 {
/* PINCTRL - modifications to sc7180-trogdor.dtsi */
&en_pp3300_dx_edp {
- pinmux {
- pins = "gpio67";
- };
-
- pinconf {
- pins = "gpio67";
- };
+ pins = "gpio67";
};
-&sec_mi2s_active{
- pinmux {
- pins = "gpio49", "gpio50", "gpio51", "gpio52";
- function = "mi2s_1";
- };
+&sec_mi2s_active {
+ pins = "gpio49", "gpio50", "gpio51", "gpio52";
};
&ts_reset_l {
- pinconf {
- /*
- * We want reset state by default and it will be up to the
- * driver to disable this when it's ready.
- */
- output-low;
- };
+ /*
+ * We want reset state by default and it will be up to the
+ * driver to disable this when it's ready.
+ */
+ output-low;
};
/* PINCTRL - board-specific pinctrl */
@@ -333,16 +322,10 @@ ap_ts_pen_1v8: &i2c4 {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- en_pp3300_touch: en-pp3300-touch {
- pinmux {
- pins = "gpio87";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio87";
- drive-strength = <2>;
- bias-disable;
- };
+ en_pp3300_touch: en-pp3300-touch-state {
+ pins = "gpio87";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts
index 1a62e8d435ab..3abd6222fe46 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts
@@ -29,16 +29,10 @@
};
&tlmm {
- en_fp_rails: en-fp-rails {
- pinmux {
- pins = "gpio74";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio74";
- drive-strength = <2>;
- bias-disable;
- };
+ en_fp_rails: en-fp-rails-state {
+ pins = "gpio74";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi
index 74f0e07ea5cf..315ac5eb5f78 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi
@@ -11,6 +11,7 @@
&alc5682 {
compatible = "realtek,rt5682s";
+ /delete-property/ VBAT-supply;
realtek,dmic1-clk-pin = <2>;
realtek,dmic-clk-rate-hz = <2048000>;
};
@@ -87,13 +88,7 @@ ap_ts_pen_1v8: &i2c4 {
/* PINCTRL - modifications to sc7180-trogdor.dtsi */
&en_pp3300_dx_edp {
- pinmux {
- pins = "gpio67";
- };
-
- pinconf {
- pins = "gpio67";
- };
+ pins = "gpio67";
};
/* PINCTRL - board-specific pinctrl */
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
index 002663d752da..269007d73162 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
@@ -75,21 +75,13 @@ ap_ts_pen_1v8: &i2c4 {
/* PINCTRL - modifications to sc7180-trogdor.dtsi */
&trackpad_int_1v8_odl {
- pinmux {
- pins = "gpio58";
- };
-
- pinconf {
- pins = "gpio58";
- };
+ pins = "gpio58";
};
&ts_reset_l {
- pinconf {
- /* This pin is not connected on -rev0, pull up to park. */
- /delete-property/bias-disable;
- bias-pull-up;
- };
+ /* This pin is not connected on -rev0, pull up to park. */
+ /delete-property/bias-disable;
+ bias-pull-up;
};
/* PINCTRL - board-specific pinctrl */
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi
index 7bc8402c018e..f4c1f3813664 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi
@@ -24,30 +24,13 @@
/* PINCTRL - modifications to sc7180-trogdor-mrbland.dtsi */
&avdd_lcd_en {
- pinmux {
- pins = "gpio80";
- };
-
- pinconf {
- pins = "gpio80";
- };
+ pins = "gpio80";
};
&mipi_1800_en {
- pinmux {
- pins = "gpio81";
- };
-
- pinconf {
- pins = "gpio81";
- };
+ pins = "gpio81";
};
-&vdd_reset_1800 {
- pinmux {
- pins = "gpio76";
- };
- pinconf {
- pins = "gpio76";
- };
+&vdd_reset_1800 {
+ pins = "gpio76";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi
index 97cba7f8064f..ed12ee35f06b 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi
@@ -13,7 +13,7 @@
/delete-node/ &usb_c1;
/ {
- avdd_lcd: avdd-lcd {
+ avdd_lcd: avdd-lcd-regulator {
compatible = "regulator-fixed";
regulator-name = "avdd_lcd";
@@ -25,7 +25,7 @@
vin-supply = <&pp5000_a>;
};
- avee_lcd: avee-lcd {
+ avee_lcd: avee-lcd-regulator {
compatible = "regulator-fixed";
regulator-name = "avee_lcd";
@@ -37,7 +37,7 @@
vin-supply = <&pp5000_a>;
};
- v1p8_mipi: v1p8-mipi {
+ v1p8_mipi: v1p8-mipi-regulator {
compatible = "regulator-fixed";
regulator-name = "v1p8_mipi";
@@ -160,13 +160,7 @@ pp3300_disp_on: &pp3300_dx_edp {
*/
tp_en: &en_pp3300_dx_edp {
- pinmux {
- pins = "gpio85";
- };
-
- pinconf {
- pins = "gpio85";
- };
+ pins = "gpio85";
};
/* PINCTRL - board-specific pinctrl */
@@ -296,55 +290,31 @@ tp_en: &en_pp3300_dx_edp {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- avdd_lcd_en: avdd-lcd-en {
- pinmux {
- pins = "gpio88";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio88";
- drive-strength = <2>;
- bias-disable;
- };
+ avdd_lcd_en: avdd-lcd-en-state {
+ pins = "gpio88";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- avee_lcd_en: avee-lcd-en {
- pinmux {
- pins = "gpio21";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio21";
- drive-strength = <2>;
- bias-disable;
- };
+ avee_lcd_en: avee-lcd-en-state {
+ pins = "gpio21";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- mipi_1800_en: mipi-1800-en {
- pinmux {
- pins = "gpio86";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio86";
- drive-strength = <2>;
- bias-disable;
- };
+ mipi_1800_en: mipi-1800-en-state {
+ pins = "gpio86";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- vdd_reset_1800: vdd-reset-1800 {
- pinmux {
- pins = "gpio87";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio87";
- drive-strength = <2>;
- bias-disable;
- };
+ vdd_reset_1800: vdd-reset-1800-state {
+ pins = "gpio87";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-parade-ps8640.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-parade-ps8640.dtsi
index 6a84fba178d6..ebd6765e2afa 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-parade-ps8640.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-parade-ps8640.dtsi
@@ -8,7 +8,7 @@
#include <dt-bindings/gpio/gpio.h>
/ {
- pp3300_brij_ps8640: pp3300-brij-ps8640 {
+ pp3300_brij_ps8640: pp3300-brij-ps8640-regulator {
compatible = "regulator-fixed";
status = "okay";
regulator-name = "pp3300_brij_ps8640";
@@ -83,29 +83,17 @@ edp_brij_i2c: &i2c2 {
};
&tlmm {
- edp_brij_ps8640_rst: edp-brij-ps8640-rst {
- pinmux {
- pins = "gpio11";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio11";
- drive-strength = <2>;
- bias-disable;
- };
+ edp_brij_ps8640_rst: edp-brij-ps8640-rst-state {
+ pins = "gpio11";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- en_pp3300_edp_brij_ps8640: en-pp3300-edp-brij-ps8640 {
- pinmux {
- pins = "gpio32";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio32";
- drive-strength = <2>;
- bias-disable;
- };
+ en_pp3300_edp_brij_ps8640: en-pp3300-edp-brij-ps8640-state {
+ pins = "gpio32";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi
index 56d787785fd5..d06cc4ea3375 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi
@@ -84,13 +84,7 @@
};
&en_pp3300_dx_edp {
- pinmux {
- pins = "gpio67";
- };
-
- pinconf {
- pins = "gpio67";
- };
+ pins = "gpio67";
};
/* PINCTRL - board-specific pinctrl */
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-lte.dts
new file mode 100644
index 000000000000..021bcafcf815
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-lte.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-parade-ps8640.dtsi"
+#include "sc7180-trogdor-pazquel360.dtsi"
+#include "sc7180-trogdor-lte-sku.dtsi"
+
+/ {
+ model = "Google Pazquel (Parade,LTE)";
+ compatible = "google,pazquel-sku22", "google,pazquel-sku20", "qcom,sc7180";
+};
+
+&ap_sar_sensor_i2c {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-wifi.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-wifi.dts
new file mode 100644
index 000000000000..defd84c5354a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360-wifi.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-parade-ps8640.dtsi"
+#include "sc7180-trogdor-pazquel360.dtsi"
+
+/ {
+ model = "Google Pazquel (Parade,WIFI-only)";
+ compatible = "google,pazquel-sku21", "qcom,sc7180";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360.dtsi
new file mode 100644
index 000000000000..5702325d0c7b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel360.dtsi
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/* This file must be included after sc7180-trogdor.dtsi */
+#include "sc7180-trogdor-pazquel.dtsi"
+
+&alc5682 {
+ compatible = "realtek,rt5682s";
+ realtek,dmic1-clk-pin = <2>;
+ realtek,dmic-clk-rate-hz = <2048000>;
+};
+
+&keyboard_controller {
+ function-row-physmap = <
+ MATRIX_KEY(0x00, 0x02, 0) /* T1 */
+ MATRIX_KEY(0x03, 0x02, 0) /* T2 */
+ MATRIX_KEY(0x02, 0x02, 0) /* T3 */
+ MATRIX_KEY(0x01, 0x02, 0) /* T4 */
+ MATRIX_KEY(0x03, 0x04, 0) /* T5 */
+ MATRIX_KEY(0x02, 0x04, 0) /* T6 */
+ MATRIX_KEY(0x01, 0x04, 0) /* T7 */
+ MATRIX_KEY(0x02, 0x09, 0) /* T8 */
+ MATRIX_KEY(0x01, 0x09, 0) /* T9 */
+ MATRIX_KEY(0x00, 0x04, 0) /* T10 */
+ MATRIX_KEY(0x03, 0x09, 0) /* T11 */
+ >;
+ linux,keymap = <
+ MATRIX_KEY(0x00, 0x02, KEY_BACK)
+ MATRIX_KEY(0x03, 0x02, KEY_REFRESH)
+ MATRIX_KEY(0x02, 0x02, KEY_ZOOM)
+ MATRIX_KEY(0x01, 0x02, KEY_SCALE)
+ MATRIX_KEY(0x03, 0x04, KEY_SYSRQ)
+ MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN)
+ MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP)
+ MATRIX_KEY(0x02, 0x09, KEY_MUTE)
+ MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN)
+ MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP)
+ MATRIX_KEY(0x03, 0x09, KEY_SLEEP)
+ CROS_STD_MAIN_KEYMAP
+ >;
+};
+
+&sound {
+ compatible = "google,sc7180-trogdor";
+ model = "sc7180-rt5682s-max98357a-1mic";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
index a7582fb547ee..6c5287bd27d6 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
@@ -312,15 +312,9 @@ ap_ts_pen_1v8: &i2c4 {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- dmic_sel: dmic-sel {
- pinmux {
- pins = "gpio86";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio86";
- bias-pull-down;
- };
+ dmic_sel: dmic-sel-state {
+ pins = "gpio86";
+ function = "gpio";
+ bias-pull-down;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi
index 695b04fe7221..cb41ccdaccfd 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi
@@ -13,7 +13,7 @@
/delete-node/ &usb_c1;
/ {
- ppvar_lcd: ppvar-lcd {
+ ppvar_lcd: ppvar-lcd-regulator {
compatible = "regulator-fixed";
regulator-name = "ppvar_lcd";
@@ -25,7 +25,7 @@
vin-supply = <&pp5000_a>;
};
- v1p8_disp: v1p8-disp {
+ v1p8_disp: v1p8-disp-regulator {
compatible = "regulator-fixed";
regulator-name = "v1p8_disp";
@@ -147,13 +147,7 @@ pp3300_disp_on: &pp3300_dx_edp {
*/
tp_en: &en_pp3300_dx_edp {
- pinmux {
- pins = "gpio67";
- };
-
- pinconf {
- pins = "gpio67";
- };
+ pins = "gpio67";
};
/* PINCTRL - board-specific pinctrl */
@@ -283,42 +277,24 @@ tp_en: &en_pp3300_dx_edp {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- lcd_rst: lcd-rst {
- pinmux {
- pins = "gpio87";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio87";
- drive-strength = <2>;
- bias-disable;
- };
+ lcd_rst: lcd-rst-state {
+ pins = "gpio87";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- ppvar_lcd_en: ppvar-lcd-en {
- pinmux {
- pins = "gpio88";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio88";
- drive-strength = <2>;
- bias-disable;
- };
+ ppvar_lcd_en: ppvar-lcd-en-state {
+ pins = "gpio88";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- pp1800_disp_on: pp1800-disp-on {
- pinmux {
- pins = "gpio86";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio86";
- drive-strength = <2>;
- bias-disable;
- };
+ pp1800_disp_on: pp1800-disp-on-state {
+ pins = "gpio86";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts
index bc097d1b1b23..671b3691f1bb 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts
@@ -63,13 +63,7 @@ ap_ts_pen_1v8: &i2c4 {
/* PINCTRL - modifications to sc7180-trogdor.dtsi */
&trackpad_int_1v8_odl {
- pinmux {
- pins = "gpio58";
- };
-
- pinconf {
- pins = "gpio58";
- };
+ pins = "gpio58";
};
/* PINCTRL - board-specific pinctrl */
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-ti-sn65dsi86.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-ti-sn65dsi86.dtsi
index f869e6a343c1..65333709e529 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-ti-sn65dsi86.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-ti-sn65dsi86.dtsi
@@ -76,16 +76,10 @@ edp_brij_i2c: &i2c2 {
};
&tlmm {
- edp_brij_irq: edp-brij-irq {
- pinmux {
- pins = "gpio11";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio11";
- drive-strength = <2>;
- bias-pull-down;
- };
+ edp_brij_irq: edp-brij-irq-state {
+ pins = "gpio11";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi
index db29e0cba29d..7f272c6e95f6 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi
@@ -24,30 +24,13 @@
/* PINCTRL - modifications to sc7180-trogdor-wormdingler.dtsi */
&avdd_lcd_en {
- pinmux {
- pins = "gpio80";
- };
-
- pinconf {
- pins = "gpio80";
- };
+ pins = "gpio80";
};
&mipi_1800_en {
- pinmux {
- pins = "gpio81";
- };
-
- pinconf {
- pins = "gpio81";
- };
+ pins = "gpio81";
};
-&vdd_reset_1800 {
- pinmux {
- pins = "gpio76";
- };
- pinconf {
- pins = "gpio76";
- };
+&vdd_reset_1800 {
+ pins = "gpio76";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts
index aa605885c371..6225ab8329c3 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts
@@ -19,6 +19,7 @@
&alc5682 {
compatible = "realtek,rt5682s";
+ /delete-property/ VBAT-supply;
realtek,dmic1-clk-pin = <2>;
realtek,dmic-clk-rate-hz = <2048000>;
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts
index 7116c44c8d85..b40b068dad6a 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts
@@ -19,6 +19,7 @@
&alc5682 {
compatible = "realtek,rt5682s";
+ /delete-property/ VBAT-supply;
realtek,dmic1-clk-pin = <2>;
realtek,dmic-clk-rate-hz = <2048000>;
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi
index 6312108e8b3e..9832e752da35 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi
@@ -10,7 +10,7 @@
#include "sc7180-trogdor.dtsi"
/ {
- avdd_lcd: avdd-lcd {
+ avdd_lcd: avdd-lcd-regulator {
compatible = "regulator-fixed";
regulator-name = "avdd_lcd";
@@ -22,7 +22,7 @@
vin-supply = <&pp5000_a>;
};
- avee_lcd: avee-lcd {
+ avee_lcd: avee-lcd-regulator {
compatible = "regulator-fixed";
regulator-name = "avee_lcd";
@@ -35,7 +35,7 @@
};
pp1800_ts:
- v1p8_mipi: v1p8-mipi {
+ v1p8_mipi: v1p8-mipi-regulator {
compatible = "regulator-fixed";
regulator-name = "v1p8_mipi";
@@ -222,13 +222,7 @@ pp3300_disp_on: &pp3300_dx_edp {
*/
tp_en: &en_pp3300_dx_edp {
- pinmux {
- pins = "gpio85";
- };
-
- pinconf {
- pins = "gpio85";
- };
+ pins = "gpio85";
};
/* PINCTRL - board-specific pinctrl */
@@ -358,55 +352,31 @@ tp_en: &en_pp3300_dx_edp {
"DP_HOT_PLUG_DET",
"EC_IN_RW_ODL";
- avdd_lcd_en: avdd-lcd-en {
- pinmux {
- pins = "gpio88";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio88";
- drive-strength = <2>;
- bias-disable;
- };
+ avdd_lcd_en: avdd-lcd-en-state {
+ pins = "gpio88";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- avee_lcd_en: avee-lcd-en {
- pinmux {
- pins = "gpio21";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio21";
- drive-strength = <2>;
- bias-disable;
- };
+ avee_lcd_en: avee-lcd-en-state {
+ pins = "gpio21";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- mipi_1800_en: mipi-1800-en {
- pinmux {
- pins = "gpio86";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio86";
- drive-strength = <2>;
- bias-disable;
- };
+ mipi_1800_en: mipi-1800-en-state {
+ pins = "gpio86";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- vdd_reset_1800: vdd-reset-1800 {
- pinmux {
- pins = "gpio87";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio87";
- drive-strength = <2>;
- bias-disable;
- };
+ vdd_reset_1800: vdd-reset-1800-state {
+ pins = "gpio87";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
index eae22e6e97c1..f1defb94d670 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
@@ -354,7 +354,7 @@
pwmleds {
compatible = "pwm-leds";
- keyboard_backlight: keyboard-backlight {
+ keyboard_backlight: led-0 {
status = "disabled";
label = "cros_ec::kbd_backlight";
function = LED_FUNCTION_KBD_BACKLIGHT;
@@ -768,6 +768,8 @@ hp_i2c: &i2c9 {
interrupts = <28 IRQ_TYPE_EDGE_BOTH>;
AVDD-supply = <&pp1800_alc5682>;
+ DBVDD-supply = <&pp1800_alc5682>;
+ LDO1-IN-supply = <&pp1800_alc5682>;
MICVDD-supply = <&pp3300_codec>;
VBAT-supply = <&pp3300_audio>;
@@ -880,27 +882,30 @@ hp_i2c: &i2c9 {
};
&spi0 {
- pinctrl-0 = <&qup_spi0_cs_gpio_init_high>, <&qup_spi0_cs_gpio>;
+ pinctrl-0 = <&qup_spi0_spi>, <&qup_spi0_cs_gpio>;
cs-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
};
&spi6 {
- pinctrl-0 = <&qup_spi6_cs_gpio_init_high>, <&qup_spi6_cs_gpio>;
+ pinctrl-0 = <&qup_spi6_spi>, <&qup_spi6_cs_gpio>;
cs-gpios = <&tlmm 62 GPIO_ACTIVE_LOW>;
};
ap_spi_fp: &spi10 {
- pinctrl-0 = <&qup_spi10_cs_gpio_init_high>, <&qup_spi10_cs_gpio>;
+ pinctrl-0 = <&qup_spi10_spi>, <&qup_spi10_cs_gpio>;
cs-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>;
cros_ec_fp: ec@0 {
- compatible = "google,cros-ec-spi";
+ compatible = "google,cros-ec-fp", "google,cros-ec-spi";
reg = <0>;
interrupt-parent = <&tlmm>;
interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
- pinctrl-0 = <&fp_to_ap_irq_l>;
+ pinctrl-0 = <&fp_to_ap_irq_l>, <&fp_rst_l>, <&fpmcu_boot0>;
+ boot0-gpios = <&tlmm 10 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 22 GPIO_ACTIVE_LOW>;
spi-max-frequency = <3000000>;
+ vdd-supply = <&pp3300_fp_tp>;
};
};
@@ -997,175 +1002,141 @@ ap_spi_fp: &spi10 {
/* PINCTRL - additions to nodes defined in sc7180.dtsi */
&dp_hot_plug_det {
- pinconf {
- pins = "gpio117";
- bias-disable;
- };
+ bias-disable;
};
&pri_mi2s_active {
- pinconf {
- pins = "gpio53", "gpio54", "gpio55", "gpio56";
- drive-strength = <2>;
- bias-pull-down;
- };
+ drive-strength = <2>;
+ bias-pull-down;
};
&pri_mi2s_mclk_active {
- pinconf {
- pins = "gpio57";
- drive-strength = <2>;
- bias-pull-down;
- };
+ drive-strength = <2>;
+ bias-pull-down;
};
&qspi_cs0 {
- pinconf {
- pins = "gpio68";
- bias-disable;
- };
+ bias-disable;
};
&qspi_clk {
- pinconf {
- pins = "gpio63";
- drive-strength = <8>;
- bias-disable;
- };
+ drive-strength = <8>;
+ bias-disable;
};
&qspi_data01 {
- pinconf {
- pins = "gpio64", "gpio65";
-
- /* High-Z when no transfers; nice to park the lines */
- bias-pull-up;
- };
+ /* High-Z when no transfers; nice to park the lines */
+ bias-pull-up;
};
&qup_i2c2_default {
- pinconf {
- pins = "gpio15", "gpio16";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c4_default {
- pinconf {
- pins = "gpio115", "gpio116";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c5_default {
- pinconf {
- pins = "gpio25", "gpio26";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c7_default {
- pinconf {
- pins = "gpio6", "gpio7";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
&qup_i2c9_default {
- pinconf {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
+ drive-strength = <2>;
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
+};
+
+&qup_spi0_spi {
+ drive-strength = <2>;
+ bias-disable;
};
&qup_spi0_cs_gpio {
- pinconf {
- pins = "gpio34", "gpio35", "gpio36", "gpio37";
- drive-strength = <2>;
- bias-disable;
- };
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_spi6_spi {
+ drive-strength = <2>;
+ bias-disable;
};
&qup_spi6_cs_gpio {
- pinconf {
- pins = "gpio59", "gpio60", "gpio61", "gpio62";
- drive-strength = <2>;
- bias-disable;
- };
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_spi10_spi {
+ drive-strength = <2>;
+ bias-disable;
};
&qup_spi10_cs_gpio {
- pinconf {
- pins = "gpio86", "gpio87", "gpio88", "gpio89";
- drive-strength = <2>;
- bias-disable;
- };
+ drive-strength = <2>;
+ bias-disable;
};
-&qup_uart3_default {
- pinconf-cts {
- /*
- * Configure a pull-down on CTS to match the pull of
- * the Bluetooth module.
- */
- pins = "gpio38";
- bias-pull-down;
- };
+&qup_uart3_cts {
+ /*
+ * Configure a pull-down on CTS to match the pull of
+ * the Bluetooth module.
+ */
+ bias-pull-down;
+};
- pinconf-rts-tx {
- /* We'll drive RTS and TX, so no pull */
- pins = "gpio39", "gpio40";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_uart3_rts {
+ /* We'll drive RTS, so no pull */
+ drive-strength = <2>;
+ bias-disable;
+};
- pinconf-rx {
- /*
- * Configure a pull-up on RX. This is needed to avoid
- * garbage data when the TX pin of the Bluetooth module is
- * in tri-state (module powered off or not driving the
- * signal yet).
- */
- pins = "gpio41";
- bias-pull-up;
- };
+&qup_uart3_tx {
+ /* We'll drive TX, so no pull */
+ drive-strength = <2>;
+ bias-disable;
};
-&qup_uart8_default {
- pinconf-tx {
- pins = "gpio44";
- drive-strength = <2>;
- bias-disable;
- };
+&qup_uart3_rx {
+ /*
+ * Configure a pull-up on RX. This is needed to avoid
+ * garbage data when the TX pin of the Bluetooth module is
+ * in tri-state (module powered off or not driving the
+ * signal yet).
+ */
+ bias-pull-up;
+};
- pinconf-rx {
- pins = "gpio45";
- drive-strength = <2>;
- bias-pull-up;
- };
+&qup_uart8_tx {
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_uart8_rx {
+ drive-strength = <2>;
+ bias-pull-up;
};
&sec_mi2s_active {
- pinconf {
- pins = "gpio49", "gpio50", "gpio51";
- drive-strength = <2>;
- bias-pull-down;
- };
+ drive-strength = <2>;
+ bias-pull-down;
};
/* PINCTRL - board-specific pinctrl */
@@ -1196,468 +1167,337 @@ ap_spi_fp: &spi10 {
pinctrl-names = "default";
pinctrl-0 = <&bios_flash_wp_l>, <&ap_suspend_l_neuter>;
- amp_en: amp-en {
- pinmux {
- pins = "gpio23";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio23";
- bias-pull-down;
- };
+ amp_en: amp-en-state {
+ pins = "gpio23";
+ function = "gpio";
+ bias-pull-down;
};
- ap_ec_int_l: ap-ec-int-l {
- pinmux {
- pins = "gpio94";
- function = "gpio";
- input-enable;
- };
-
- pinconf {
- pins = "gpio94";
- bias-pull-up;
- };
+ ap_ec_int_l: ap-ec-int-l-state {
+ pins = "gpio94";
+ function = "gpio";
+ input-enable;
+ bias-pull-up;
};
- ap_edp_bklten: ap-edp-bklten {
- pinmux {
- pins = "gpio12";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio12";
- drive-strength = <2>;
- bias-disable;
+ ap_edp_bklten: ap-edp-bklten-state {
+ pins = "gpio12";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
- /* Force backlight to be disabled to match state at boot. */
- output-low;
- };
+ /* Force backlight to be disabled to match state at boot. */
+ output-low;
};
- ap_suspend_l_neuter: ap-suspend-l-neuter {
- pinmux {
- pins = "gpio27";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio27";
- bias-disable;
- };
+ ap_suspend_l_neuter: ap-suspend-l-neuter-state {
+ pins = "gpio27";
+ function = "gpio";
+ bias-disable;
};
- bios_flash_wp_l: bios-flash-wp-l {
- pinmux {
- pins = "gpio66";
- function = "gpio";
- input-enable;
- };
-
- pinconf {
- pins = "gpio66";
- bias-disable;
- };
+ bios_flash_wp_l: bios-flash-wp-l-state {
+ pins = "gpio66";
+ function = "gpio";
+ input-enable;
+ bias-disable;
};
- edp_brij_en: edp-brij-en {
- pinmux {
- pins = "gpio104";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio104";
- drive-strength = <2>;
- bias-disable;
- };
+ edp_brij_en: edp-brij-en-state {
+ pins = "gpio104";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- en_pp3300_codec: en-pp3300-codec {
- pinmux {
- pins = "gpio83";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio83";
- drive-strength = <2>;
- bias-disable;
- };
+ en_pp3300_codec: en-pp3300-codec-state {
+ pins = "gpio83";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- en_pp3300_dx_edp: en-pp3300-dx-edp {
- pinmux {
- pins = "gpio30";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio30";
- drive-strength = <2>;
- bias-disable;
- };
+ en_pp3300_dx_edp: en-pp3300-dx-edp-state {
+ pins = "gpio30";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- en_pp3300_hub: en-pp3300-hub {
- pinmux {
- pins = "gpio84";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio84";
- drive-strength = <2>;
- bias-disable;
- };
+ en_pp3300_hub: en-pp3300-hub-state {
+ pins = "gpio84";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
};
- fp_to_ap_irq_l: fp-to-ap-irq-l {
- pinmux {
- pins = "gpio4";
- function = "gpio";
- input-enable;
- };
-
- pinconf {
- pins = "gpio4";
-
- /* Has external pullup */
- bias-disable;
- };
+ fp_rst_l: fp-rst-l-state {
+ pins = "gpio22";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
};
- h1_ap_int_odl: h1-ap-int-odl {
- pinmux {
- pins = "gpio42";
- function = "gpio";
- input-enable;
- };
+ fp_to_ap_irq_l: fp-to-ap-irq-l-state {
+ pins = "gpio4";
+ function = "gpio";
+ input-enable;
- pinconf {
- pins = "gpio42";
- bias-pull-up;
- };
+ /* Has external pullup */
+ bias-disable;
};
- hp_irq: hp-irq {
- pinmux {
- pins = "gpio28";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio28";
- bias-pull-up;
- };
+ fpmcu_boot0: fpmcu-boot0-state {
+ pins = "gpio10";
+ function = "gpio";
+ bias-disable;
};
- pen_irq_l: pen-irq-l {
- pinmux {
- pins = "gpio21";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio21";
-
- /* Has external pullup */
- bias-disable;
- };
+ h1_ap_int_odl: h1-ap-int-odl-state {
+ pins = "gpio42";
+ function = "gpio";
+ input-enable;
+ bias-pull-up;
};
- pen_pdct_l: pen-pdct-l {
- pinmux {
- pins = "gpio52";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio52";
-
- /* Has external pullup */
- bias-disable;
- };
+ hp_irq: hp-irq-state {
+ pins = "gpio28";
+ function = "gpio";
+ bias-pull-up;
};
- pen_rst_odl: pen-rst-odl {
- pinmux {
- pins = "gpio18";
- function = "gpio";
- };
+ pen_irq_l: pen-irq-l-state {
+ pins = "gpio21";
+ function = "gpio";
- pinconf {
- pins = "gpio18";
- bias-disable;
- drive-strength = <2>;
-
- /*
- * The pen driver doesn't currently support
- * driving this reset line. By specifying
- * output-high here we're relying on the fact
- * that this pin has a default pulldown at boot
- * (which makes sure the pen was in reset if it
- * was powered) and then we set it high here to
- * take it out of reset. Better would be if the
- * pen driver could control this and we could
- * remove "output-high" here.
- */
- output-high; /* TODO: Remove this? */
- };
+ /* Has external pullup */
+ bias-disable;
};
- p_sensor_int_l: p-sensor-int-l {
- pinmux {
- pins = "gpio24";
- function = "gpio";
- input-enable;
- };
+ pen_pdct_l: pen-pdct-l-state-state {
+ pins = "gpio52";
+ function = "gpio";
- pinconf {
- pins = "gpio24";
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
- qup_spi0_cs_gpio_init_high: qup-spi0-cs-gpio-init-high {
- pinconf {
- pins = "gpio37";
- output-high;
- };
- };
+ pen_rst_odl: pen-rst-odl-state {
+ pins = "gpio18";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
- qup_spi6_cs_gpio_init_high: qup-spi6-cs-gpio-init-high {
- pinconf {
- pins = "gpio62";
- output-high;
- };
+ /*
+ * The pen driver doesn't currently support
+ * driving this reset line. By specifying
+ * output-high here we're relying on the fact
+ * that this pin has a default pulldown at boot
+ * (which makes sure the pen was in reset if it
+ * was powered) and then we set it high here to
+ * take it out of reset. Better would be if the
+ * pen driver could control this and we could
+ * remove "output-high" here.
+ */
+ output-high; /* TODO: Remove this? */
};
- qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high {
- pinconf {
- pins = "gpio89";
- output-high;
- };
- };
+ p_sensor_int_l: p-sensor-int-l-state {
+ pins = "gpio24";
+ function = "gpio";
+ input-enable;
- qup_uart3_sleep: qup-uart3-sleep {
- pinmux {
- pins = "gpio38", "gpio39",
- "gpio40", "gpio41";
- function = "gpio";
- };
+ /* Has external pullup */
+ bias-disable;
+ };
- pinconf-cts {
+ qup_uart3_sleep: qup-uart3-sleep-state {
+ cts-pins {
/*
* Configure a pull-down on CTS to match the pull of
* the Bluetooth module.
*/
pins = "gpio38";
+ function = "gpio";
bias-pull-down;
};
- pinconf-rts {
+ rts-pins {
/*
* Configure pull-down on RTS. As RTS is active low
* signal, pull it low to indicate the BT SoC that it
* can wakeup the system anytime from suspend state by
* pulling RX low (by sending wakeup bytes).
*/
- pins = "gpio39";
- bias-pull-down;
+ pins = "gpio39";
+ function = "gpio";
+ bias-pull-down;
};
- pinconf-tx {
+ tx-pins {
/*
* Configure pull-up on TX when it isn't actively driven
* to prevent BT SoC from receiving garbage during sleep.
*/
pins = "gpio40";
+ function = "gpio";
bias-pull-up;
};
- pinconf-rx {
+ rx-pins {
/*
* Configure a pull-up on RX. This is needed to avoid
* garbage data when the TX pin of the Bluetooth module
* is floating which may cause spurious wakeups.
*/
pins = "gpio41";
+ function = "gpio";
bias-pull-up;
};
};
/* Named trackpad_int_1v8_odl on earlier revision schematics */
trackpad_int_1v8_odl:
- tp_int_odl: tp-int-odl {
- pinmux {
- pins = "gpio0";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio0";
+ tp_int_odl: tp-int-odl-state {
+ pins = "gpio0";
+ function = "gpio";
- /* Has external pullup */
- bias-disable;
- };
+ /* Has external pullup */
+ bias-disable;
};
- ts_int_l: ts-int-l {
- pinmux {
- pins = "gpio9";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio9";
- bias-pull-up;
- };
+ ts_int_l: ts-int-l-state {
+ pins = "gpio9";
+ function = "gpio";
+ bias-pull-up;
};
- ts_reset_l: ts-reset-l {
- pinmux {
- pins = "gpio8";
- function = "gpio";
- };
-
- pinconf {
- pins = "gpio8";
- bias-disable;
- drive-strength = <2>;
- };
+ ts_reset_l: ts-reset-l-state {
+ pins = "gpio8";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
};
- sdc1_on: sdc1-on {
- pinconf-clk {
+ sdc1_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <16>;
};
- pinconf-data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <16>;
};
- pinconf-rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc1_off: sdc1-off {
- pinconf-clk {
+ sdc1_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc2_on: sdc2-on {
- pinconf-clk {
+ sdc2_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
- pinconf-sd-cd {
+ sd-cd-pins {
pins = "gpio69";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
- sdc2_off: sdc2-off {
- pinconf-clk {
+ sdc2_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- pinconf-cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
};
- pinconf-sd-cd {
+ sd-cd-pins {
pins = "gpio69";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
- uf_cam_en: uf-cam-en {
- pinmux {
- pins = "gpio6";
- function = "gpio";
- };
+ uf_cam_en: uf-cam-en-state {
+ pins = "gpio6";
+ function = "gpio";
+ drive-strength = <2>;
- pinconf {
- pins = "gpio6";
- drive-strength = <2>;
- /* External pull down */
- bias-disable;
- };
+ /* External pull down */
+ bias-disable;
};
- wf_cam_en: wf-cam-en {
- pinmux {
- pins = "gpio7";
- function = "gpio";
- };
+ wf_cam_en: wf-cam-en-state {
+ pins = "gpio7";
+ function = "gpio";
+ drive-strength = <2>;
- pinconf {
- pins = "gpio7";
- drive-strength = <2>;
- /* External pull down */
- bias-disable;
- };
+ /* External pull down */
+ bias-disable;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi
index 58976a1ba06b..f71cf21a8dd8 100644
--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
@@ -662,6 +662,7 @@
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
+ power-domains = <&rpmhpd SC7180_CX>;
};
qfprom: efuse@784000 {
@@ -795,7 +796,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi0_default>;
+ pinctrl-0 = <&qup_spi0_spi>, <&qup_spi0_cs>;
interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -849,7 +850,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi1_default>;
+ pinctrl-0 = <&qup_spi1_spi>, <&qup_spi1_cs>;
interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -939,7 +940,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi3_default>;
+ pinctrl-0 = <&qup_spi3_spi>, <&qup_spi3_cs>;
interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1029,7 +1030,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi5_default>;
+ pinctrl-0 = <&qup_spi5_spi>, <&qup_spi5_cs>;
interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1096,7 +1097,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi6_default>;
+ pinctrl-0 = <&qup_spi6_spi>, <&qup_spi6_cs>;
interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1186,7 +1187,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi8_default>;
+ pinctrl-0 = <&qup_spi8_spi>, <&qup_spi8_cs>;
interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1276,7 +1277,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi10_default>;
+ pinctrl-0 = <&qup_spi10_spi>, <&qup_spi10_cs>;
interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1330,7 +1331,7 @@
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>;
pinctrl-names = "default";
- pinctrl-0 = <&qup_spi11_default>;
+ pinctrl-0 = <&qup_spi11_spi>, <&qup_spi11_cs>;
interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -1486,410 +1487,443 @@
gpio-ranges = <&tlmm 0 0 120>;
wakeup-parent = <&pdc>;
- dp_hot_plug_det: dp-hot-plug-det {
- pinmux {
- pins = "gpio117";
- function = "dp_hot";
- };
+ dp_hot_plug_det: dp-hot-plug-det-state {
+ pins = "gpio117";
+ function = "dp_hot";
};
- qspi_clk: qspi-clk {
- pinmux {
- pins = "gpio63";
- function = "qspi_clk";
- };
+ qspi_clk: qspi-clk-state {
+ pins = "gpio63";
+ function = "qspi_clk";
};
- qspi_cs0: qspi-cs0 {
- pinmux {
- pins = "gpio68";
- function = "qspi_cs";
- };
+ qspi_cs0: qspi-cs0-state {
+ pins = "gpio68";
+ function = "qspi_cs";
};
- qspi_cs1: qspi-cs1 {
- pinmux {
- pins = "gpio72";
- function = "qspi_cs";
- };
+ qspi_cs1: qspi-cs1-state {
+ pins = "gpio72";
+ function = "qspi_cs";
};
- qspi_data01: qspi-data01 {
- pinmux-data {
- pins = "gpio64", "gpio65";
- function = "qspi_data";
- };
+ qspi_data01: qspi-data01-state {
+ pins = "gpio64", "gpio65";
+ function = "qspi_data";
};
- qspi_data12: qspi-data12 {
- pinmux-data {
- pins = "gpio66", "gpio67";
- function = "qspi_data";
- };
+ qspi_data12: qspi-data12-state {
+ pins = "gpio66", "gpio67";
+ function = "qspi_data";
};
- qup_i2c0_default: qup-i2c0-default {
- pinmux {
- pins = "gpio34", "gpio35";
- function = "qup00";
- };
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio34", "gpio35";
+ function = "qup00";
};
- qup_i2c1_default: qup-i2c1-default {
- pinmux {
- pins = "gpio0", "gpio1";
- function = "qup01";
- };
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup01";
};
- qup_i2c2_default: qup-i2c2-default {
- pinmux {
- pins = "gpio15", "gpio16";
- function = "qup02_i2c";
- };
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio15", "gpio16";
+ function = "qup02_i2c";
};
- qup_i2c3_default: qup-i2c3-default {
- pinmux {
- pins = "gpio38", "gpio39";
- function = "qup03";
- };
+ qup_i2c3_default: qup-i2c3-default-state {
+ pins = "gpio38", "gpio39";
+ function = "qup03";
};
- qup_i2c4_default: qup-i2c4-default {
- pinmux {
- pins = "gpio115", "gpio116";
- function = "qup04_i2c";
- };
+ qup_i2c4_default: qup-i2c4-default-state {
+ pins = "gpio115", "gpio116";
+ function = "qup04_i2c";
};
- qup_i2c5_default: qup-i2c5-default {
- pinmux {
- pins = "gpio25", "gpio26";
- function = "qup05";
- };
+ qup_i2c5_default: qup-i2c5-default-state {
+ pins = "gpio25", "gpio26";
+ function = "qup05";
};
- qup_i2c6_default: qup-i2c6-default {
- pinmux {
- pins = "gpio59", "gpio60";
- function = "qup10";
- };
+ qup_i2c6_default: qup-i2c6-default-state {
+ pins = "gpio59", "gpio60";
+ function = "qup10";
};
- qup_i2c7_default: qup-i2c7-default {
- pinmux {
- pins = "gpio6", "gpio7";
- function = "qup11_i2c";
- };
+ qup_i2c7_default: qup-i2c7-default-state {
+ pins = "gpio6", "gpio7";
+ function = "qup11_i2c";
};
- qup_i2c8_default: qup-i2c8-default {
- pinmux {
- pins = "gpio42", "gpio43";
- function = "qup12";
- };
+ qup_i2c8_default: qup-i2c8-default-state {
+ pins = "gpio42", "gpio43";
+ function = "qup12";
};
- qup_i2c9_default: qup-i2c9-default {
- pinmux {
- pins = "gpio46", "gpio47";
- function = "qup13_i2c";
- };
+ qup_i2c9_default: qup-i2c9-default-state {
+ pins = "gpio46", "gpio47";
+ function = "qup13_i2c";
};
- qup_i2c10_default: qup-i2c10-default {
- pinmux {
- pins = "gpio86", "gpio87";
- function = "qup14";
- };
+ qup_i2c10_default: qup-i2c10-default-state {
+ pins = "gpio86", "gpio87";
+ function = "qup14";
};
- qup_i2c11_default: qup-i2c11-default {
- pinmux {
- pins = "gpio53", "gpio54";
- function = "qup15";
- };
+ qup_i2c11_default: qup-i2c11-default-state {
+ pins = "gpio53", "gpio54";
+ function = "qup15";
+ };
+
+ qup_spi0_spi: qup-spi0-spi-state {
+ pins = "gpio34", "gpio35", "gpio36";
+ function = "qup00";
+ };
+
+ qup_spi0_cs: qup-spi0-cs-state {
+ pins = "gpio37";
+ function = "qup00";
+ };
+
+ qup_spi0_cs_gpio: qup-spi0-cs-gpio-state {
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ qup_spi1_spi: qup-spi1-spi-state {
+ pins = "gpio0", "gpio1", "gpio2";
+ function = "qup01";
+ };
+
+ qup_spi1_cs: qup-spi1-cs-state {
+ pins = "gpio3";
+ function = "qup01";
+ };
+
+ qup_spi1_cs_gpio: qup-spi1-cs-gpio-state {
+ pins = "gpio3";
+ function = "gpio";
+ };
+
+ qup_spi3_spi: qup-spi3-spi-state {
+ pins = "gpio38", "gpio39", "gpio40";
+ function = "qup03";
+ };
+
+ qup_spi3_cs: qup-spi3-cs-state {
+ pins = "gpio41";
+ function = "qup03";
};
- qup_spi0_default: qup-spi0-default {
- pinmux {
- pins = "gpio34", "gpio35",
- "gpio36", "gpio37";
+ qup_spi3_cs_gpio: qup-spi3-cs-gpio-state {
+ pins = "gpio41";
+ function = "gpio";
+ };
+
+ qup_spi5_spi: qup-spi5-spi-state {
+ pins = "gpio25", "gpio26", "gpio27";
+ function = "qup05";
+ };
+
+ qup_spi5_cs: qup-spi5-cs-state {
+ pins = "gpio28";
+ function = "qup05";
+ };
+
+ qup_spi5_cs_gpio: qup-spi5-cs-gpio-state {
+ pins = "gpio28";
+ function = "gpio";
+ };
+
+ qup_spi6_spi: qup-spi6-spi-state {
+ pins = "gpio59", "gpio60", "gpio61";
+ function = "qup10";
+ };
+
+ qup_spi6_cs: qup-spi6-cs-state {
+ pins = "gpio62";
+ function = "qup10";
+ };
+
+ qup_spi6_cs_gpio: qup-spi6-cs-gpio-state {
+ pins = "gpio62";
+ function = "gpio";
+ };
+
+ qup_spi8_spi: qup-spi8-spi-state {
+ pins = "gpio42", "gpio43", "gpio44";
+ function = "qup12";
+ };
+
+ qup_spi8_cs: qup-spi8-cs-state {
+ pins = "gpio45";
+ function = "qup12";
+ };
+
+ qup_spi8_cs_gpio: qup-spi8-cs-gpio-state {
+ pins = "gpio45";
+ function = "gpio";
+ };
+
+ qup_spi10_spi: qup-spi10-spi-state {
+ pins = "gpio86", "gpio87", "gpio88";
+ function = "qup14";
+ };
+
+ qup_spi10_cs: qup-spi10-cs-state {
+ pins = "gpio89";
+ function = "qup14";
+ };
+
+ qup_spi10_cs_gpio: qup-spi10-cs-gpio-state {
+ pins = "gpio89";
+ function = "gpio";
+ };
+
+ qup_spi11_spi: qup-spi11-spi-state {
+ pins = "gpio53", "gpio54", "gpio55";
+ function = "qup15";
+ };
+
+ qup_spi11_cs: qup-spi11-cs-state {
+ pins = "gpio56";
+ function = "qup15";
+ };
+
+ qup_spi11_cs_gpio: qup-spi11-cs-gpio-state {
+ pins = "gpio56";
+ function = "gpio";
+ };
+
+ qup_uart0_default: qup-uart0-default-state {
+ qup_uart0_cts: cts-pins {
+ pins = "gpio34";
function = "qup00";
};
- };
- qup_spi0_cs_gpio: qup-spi0-cs-gpio {
- pinmux {
- pins = "gpio34", "gpio35",
- "gpio36";
+ qup_uart0_rts: rts-pins {
+ pins = "gpio35";
function = "qup00";
};
- pinmux-cs {
+ qup_uart0_tx: tx-pins {
+ pins = "gpio36";
+ function = "qup00";
+ };
+
+ qup_uart0_rx: rx-pins {
pins = "gpio37";
- function = "gpio";
+ function = "qup00";
};
};
- qup_spi1_default: qup-spi1-default {
- pinmux {
- pins = "gpio0", "gpio1",
- "gpio2", "gpio3";
+ qup_uart1_default: qup-uart1-default-state {
+ qup_uart1_cts: cts-pins {
+ pins = "gpio0";
function = "qup01";
};
- };
- qup_spi1_cs_gpio: qup-spi1-cs-gpio {
- pinmux {
- pins = "gpio0", "gpio1",
- "gpio2";
+ qup_uart1_rts: rts-pins {
+ pins = "gpio1";
function = "qup01";
};
- pinmux-cs {
- pins = "gpio3";
- function = "gpio";
+ qup_uart1_tx: tx-pins {
+ pins = "gpio2";
+ function = "qup01";
};
- };
- qup_spi3_default: qup-spi3-default {
- pinmux {
- pins = "gpio38", "gpio39",
- "gpio40", "gpio41";
- function = "qup03";
+ qup_uart1_rx: rx-pins {
+ pins = "gpio3";
+ function = "qup01";
};
};
- qup_spi3_cs_gpio: qup-spi3-cs-gpio {
- pinmux {
- pins = "gpio38", "gpio39",
- "gpio40";
- function = "qup03";
+ qup_uart2_default: qup-uart2-default-state {
+ qup_uart2_tx: tx-pins {
+ pins = "gpio15";
+ function = "qup02_uart";
};
- pinmux-cs {
- pins = "gpio41";
- function = "gpio";
+ qup_uart2_rx: rx-pins {
+ pins = "gpio16";
+ function = "qup02_uart";
};
};
- qup_spi5_default: qup-spi5-default {
- pinmux {
- pins = "gpio25", "gpio26",
- "gpio27", "gpio28";
- function = "qup05";
+ qup_uart3_default: qup-uart3-default-state {
+ qup_uart3_cts: cts-pins {
+ pins = "gpio38";
+ function = "qup03";
};
- };
- qup_spi5_cs_gpio: qup-spi5-cs-gpio {
- pinmux {
- pins = "gpio25", "gpio26",
- "gpio27";
- function = "qup05";
+ qup_uart3_rts: rts-pins {
+ pins = "gpio39";
+ function = "qup03";
};
- pinmux-cs {
- pins = "gpio28";
- function = "gpio";
+ qup_uart3_tx: tx-pins {
+ pins = "gpio40";
+ function = "qup03";
};
- };
- qup_spi6_default: qup-spi6-default {
- pinmux {
- pins = "gpio59", "gpio60",
- "gpio61", "gpio62";
- function = "qup10";
+ qup_uart3_rx: rx-pins {
+ pins = "gpio41";
+ function = "qup03";
};
};
- qup_spi6_cs_gpio: qup-spi6-cs-gpio {
- pinmux {
- pins = "gpio59", "gpio60",
- "gpio61";
- function = "qup10";
+ qup_uart4_default: qup-uart4-default-state {
+ qup_uart4_tx: tx-pins {
+ pins = "gpio115";
+ function = "qup04_uart";
};
- pinmux-cs {
- pins = "gpio62";
- function = "gpio";
+ qup_uart4_rx: rx-pins {
+ pins = "gpio116";
+ function = "qup04_uart";
};
};
- qup_spi8_default: qup-spi8-default {
- pinmux {
- pins = "gpio42", "gpio43",
- "gpio44", "gpio45";
- function = "qup12";
+ qup_uart5_default: qup-uart5-default-state {
+ qup_uart5_cts: cts-pins {
+ pins = "gpio25";
+ function = "qup05";
};
- };
- qup_spi8_cs_gpio: qup-spi8-cs-gpio {
- pinmux {
- pins = "gpio42", "gpio43",
- "gpio44";
- function = "qup12";
+ qup_uart5_rts: rts-pins {
+ pins = "gpio26";
+ function = "qup05";
};
- pinmux-cs {
- pins = "gpio45";
- function = "gpio";
+ qup_uart5_tx: tx-pins {
+ pins = "gpio27";
+ function = "qup05";
};
- };
- qup_spi10_default: qup-spi10-default {
- pinmux {
- pins = "gpio86", "gpio87",
- "gpio88", "gpio89";
- function = "qup14";
+ qup_uart5_rx: rx-pins {
+ pins = "gpio28";
+ function = "qup05";
};
};
- qup_spi10_cs_gpio: qup-spi10-cs-gpio {
- pinmux {
- pins = "gpio86", "gpio87",
- "gpio88";
- function = "qup14";
+ qup_uart6_default: qup-uart6-default-state {
+ qup_uart6_cts: cts-pins {
+ pins = "gpio59";
+ function = "qup10";
};
- pinmux-cs {
- pins = "gpio89";
- function = "gpio";
+ qup_uart6_rts: rts-pins {
+ pins = "gpio60";
+ function = "qup10";
};
- };
- qup_spi11_default: qup-spi11-default {
- pinmux {
- pins = "gpio53", "gpio54",
- "gpio55", "gpio56";
- function = "qup15";
+ qup_uart6_tx: tx-pins {
+ pins = "gpio61";
+ function = "qup10";
+ };
+
+ qup_uart6_rx: rx-pins {
+ pins = "gpio62";
+ function = "qup10";
};
};
- qup_spi11_cs_gpio: qup-spi11-cs-gpio {
- pinmux {
- pins = "gpio53", "gpio54",
- "gpio55";
- function = "qup15";
+ qup_uart7_default: qup-uart7-default-state {
+ qup_uart7_tx: tx-pins {
+ pins = "gpio6";
+ function = "qup11_uart";
};
- pinmux-cs {
- pins = "gpio56";
- function = "gpio";
+ qup_uart7_rx: rx-pins {
+ pins = "gpio7";
+ function = "qup11_uart";
};
};
- qup_uart0_default: qup-uart0-default {
- pinmux {
- pins = "gpio34", "gpio35",
- "gpio36", "gpio37";
- function = "qup00";
+ qup_uart8_default: qup-uart8-default-state {
+ qup_uart8_tx: tx-pins {
+ pins = "gpio44";
+ function = "qup12";
};
- };
- qup_uart1_default: qup-uart1-default {
- pinmux {
- pins = "gpio0", "gpio1",
- "gpio2", "gpio3";
- function = "qup01";
+ qup_uart8_rx: rx-pins {
+ pins = "gpio45";
+ function = "qup12";
};
};
- qup_uart2_default: qup-uart2-default {
- pinmux {
- pins = "gpio15", "gpio16";
- function = "qup02_uart";
+ qup_uart9_default: qup-uart9-default-state {
+ qup_uart9_tx: tx-pins {
+ pins = "gpio46";
+ function = "qup13_uart";
};
- };
- qup_uart3_default: qup-uart3-default {
- pinmux {
- pins = "gpio38", "gpio39",
- "gpio40", "gpio41";
- function = "qup03";
+ qup_uart9_rx: rx-pins {
+ pins = "gpio47";
+ function = "qup13_uart";
};
};
- qup_uart4_default: qup-uart4-default {
- pinmux {
- pins = "gpio115", "gpio116";
- function = "qup04_uart";
+ qup_uart10_default: qup-uart10-default-state {
+ qup_uart10_cts: cts-pins {
+ pins = "gpio86";
+ function = "qup14";
};
- };
- qup_uart5_default: qup-uart5-default {
- pinmux {
- pins = "gpio25", "gpio26",
- "gpio27", "gpio28";
- function = "qup05";
+ qup_uart10_rts: rts-pins {
+ pins = "gpio87";
+ function = "qup14";
};
- };
- qup_uart6_default: qup-uart6-default {
- pinmux {
- pins = "gpio59", "gpio60",
- "gpio61", "gpio62";
- function = "qup10";
+ qup_uart10_tx: tx-pins {
+ pins = "gpio88";
+ function = "qup14";
};
- };
- qup_uart7_default: qup-uart7-default {
- pinmux {
- pins = "gpio6", "gpio7";
- function = "qup11_uart";
+ qup_uart10_rx: rx-pins {
+ pins = "gpio89";
+ function = "qup14";
};
};
- qup_uart8_default: qup-uart8-default {
- pinmux {
- pins = "gpio44", "gpio45";
- function = "qup12";
+ qup_uart11_default: qup-uart11-default-state {
+ qup_uart11_cts: cts-pins {
+ pins = "gpio53";
+ function = "qup15";
};
- };
- qup_uart9_default: qup-uart9-default {
- pinmux {
- pins = "gpio46", "gpio47";
- function = "qup13_uart";
+ qup_uart11_rts: rts-pins {
+ pins = "gpio54";
+ function = "qup15";
};
- };
- qup_uart10_default: qup-uart10-default {
- pinmux {
- pins = "gpio86", "gpio87",
- "gpio88", "gpio89";
- function = "qup14";
+ qup_uart11_tx: tx-pins {
+ pins = "gpio55";
+ function = "qup15";
};
- };
- qup_uart11_default: qup-uart11-default {
- pinmux {
- pins = "gpio53", "gpio54",
- "gpio55", "gpio56";
+ qup_uart11_rx: rx-pins {
+ pins = "gpio56";
function = "qup15";
};
};
- sec_mi2s_active: sec-mi2s-active {
- pinmux {
- pins = "gpio49", "gpio50", "gpio51";
- function = "mi2s_1";
- };
+ sec_mi2s_active: sec-mi2s-active-state {
+ pins = "gpio49", "gpio50", "gpio51";
+ function = "mi2s_1";
};
- pri_mi2s_active: pri-mi2s-active {
- pinmux {
- pins = "gpio53", "gpio54", "gpio55", "gpio56";
- function = "mi2s_0";
- };
+ pri_mi2s_active: pri-mi2s-active-state {
+ pins = "gpio53", "gpio54", "gpio55", "gpio56";
+ function = "mi2s_0";
};
- pri_mi2s_mclk_active: pri-mi2s-mclk-active {
- pinmux {
- pins = "gpio57";
- function = "lpass_ext";
- };
+ pri_mi2s_mclk_active: pri-mi2s-mclk-active-state {
+ pins = "gpio57";
+ function = "lpass_ext";
};
};
@@ -2775,6 +2809,7 @@
"dm_hs_phy_irq", "dp_hs_phy_irq";
power-domains = <&gcc USB30_PRIM_GDSC>;
+ required-opps = <&rpmhpd_opp_nom>;
resets = <&gcc GCC_USB30_PRIM_BCR>;
@@ -2782,6 +2817,8 @@
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3 0>;
interconnect-names = "usb-ddr", "apps-usb";
+ wakeup-source;
+
usb_1_dwc3: usb@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xe000>;
@@ -3012,7 +3049,6 @@
power-domains = <&rpmhpd SC7180_CX>;
phys = <&dsi_phy>;
- phy-names = "dsi";
#address-cells = <1>;
#size-cells = <0>;
@@ -3057,7 +3093,7 @@
};
};
- dsi_phy: dsi-phy@ae94400 {
+ dsi_phy: phy@ae94400 {
compatible = "qcom,dsi-phy-10nm";
reg = <0 0x0ae94400 0 0x200>,
<0 0x0ae94600 0 0x280>,
@@ -3522,7 +3558,7 @@
};
osm_l3: interconnect@18321000 {
- compatible = "qcom,sc7180-osm-l3";
+ compatible = "qcom,sc7180-osm-l3", "qcom,osm-l3";
reg = <0 0x18321000 0 0x1400>;
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi
index 25f31c81b2b7..16fb20369c01 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi
@@ -39,20 +39,10 @@
no-map;
};
- mpss_mem: memory@8b800000 {
- reg = <0x0 0x8b800000 0x0 0xf600000>;
- no-map;
- };
-
wpss_mem: memory@9ae00000 {
reg = <0x0 0x9ae00000 0x0 0x1900000>;
no-map;
};
-
- mba_mem: memory@9c700000 {
- reg = <0x0 0x9c700000 0x0 0x200000>;
- no-map;
- };
};
};
@@ -88,11 +78,6 @@
firmware-name = "ath11k/WCN6750/hw1.0/wpss.mdt";
};
-/* Increase the size from 2.5MB to 8MB */
-&rmtfs_mem {
- reg = <0x0 0x9c900000 0x0 0x800000>;
-};
-
&wifi {
status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/sc7280-crd-r3.dts b/arch/arm64/boot/dts/qcom/sc7280-crd-r3.dts
index dddb505e220b..1185141f348e 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-crd-r3.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-crd-r3.dts
@@ -118,25 +118,25 @@ ap_ts_pen_1v8: &i2c13 {
};
&tlmm {
- tp_int_odl: tp-int-odl {
+ tp_int_odl: tp-int-odl-state {
pins = "gpio7";
function = "gpio";
bias-disable;
};
- ts_int_l: ts-int-l {
+ ts_int_l: ts-int-l-state {
pins = "gpio55";
function = "gpio";
bias-pull-up;
};
- ts_reset_l: ts-reset-l {
+ ts_reset_l: ts-reset-l-state {
pins = "gpio54";
function = "gpio";
bias-disable;
};
- us_euro_hs_sel: us-euro-hs-sel {
+ us_euro_hs_sel: us-euro-hs-sel-state {
pins = "gpio81";
function = "gpio";
bias-pull-down;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682-3mic.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682-3mic.dtsi
new file mode 100644
index 000000000000..1ca11a14104d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682-3mic.dtsi
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ *
+ * This file defines the common audio settings for the child boards
+ * using rt5682 codec and having 3 dmics connected to sc7280.
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/ {
+ /* BOARD-SPECIFIC TOP LEVEL NODES */
+ sound: sound {
+ compatible = "google,sc7280-herobrine";
+ model = "sc7280-rt5682-max98360a-3mic";
+
+ audio-routing = "VA DMIC0", "vdd-micb",
+ "VA DMIC1", "vdd-micb",
+ "VA DMIC2", "vdd-micb",
+ "VA DMIC3", "vdd-micb",
+
+ "Headphone Jack", "HPOL",
+ "Headphone Jack", "HPOR";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai-link@0 {
+ link-name = "MAX98360";
+ reg = <0>;
+
+ cpu {
+ sound-dai = <&lpass_cpu MI2S_SECONDARY>;
+ };
+
+ codec {
+ sound-dai = <&max98360a>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "DisplayPort";
+ reg = <1>;
+
+ cpu {
+ sound-dai = <&lpass_cpu LPASS_DP_RX>;
+ };
+
+ codec {
+ sound-dai = <&mdss_dp>;
+ };
+ };
+
+ dai-link@2 {
+ link-name = "ALC5682";
+ reg = <2>;
+
+ cpu {
+ sound-dai = <&lpass_cpu MI2S_PRIMARY>;
+ };
+
+ codec {
+ sound-dai = <&alc5682 0 /* aif1 */>;
+ };
+ };
+
+ dai-link@4 {
+ link-name = "DMIC";
+ reg = <4>;
+
+ cpu {
+ sound-dai = <&lpass_cpu LPASS_CDC_DMA_VA_TX0>;
+ };
+
+ codec {
+ sound-dai = <&lpass_va_macro 0>;
+ };
+ };
+ };
+};
+
+hp_i2c: &i2c2 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ alc5682: codec@1a {
+ compatible = "realtek,rt5682s";
+ reg = <0x1a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_irq>;
+
+ #sound-dai-cells = <1>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <101 IRQ_TYPE_EDGE_BOTH>;
+
+ AVDD-supply = <&pp1800_alc5682>;
+ MICVDD-supply = <&pp3300_codec>;
+
+ realtek,dmic1-data-pin = <1>;
+ realtek,dmic1-clk-pin = <2>;
+ realtek,jd-src = <1>;
+ realtek,dmic-clk-rate-hz = <2048000>;
+ };
+};
+
+&lpass_cpu {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mi2s0_data0>, <&mi2s0_data1>, <&mi2s0_mclk>, <&mi2s0_sclk>, <&mi2s0_ws>,
+ <&mi2s1_data0>, <&mi2s1_sclk>, <&mi2s1_ws>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+ dai-link@0 {
+ reg = <MI2S_PRIMARY>;
+ qcom,playback-sd-lines = <1>;
+ qcom,capture-sd-lines = <0>;
+ };
+
+ dai-link@1 {
+ reg = <MI2S_SECONDARY>;
+ qcom,playback-sd-lines = <0>;
+ };
+
+ dai-link@5 {
+ reg = <LPASS_DP_RX>;
+ };
+
+ dai-link@25 {
+ reg = <LPASS_CDC_DMA_VA_TX0>;
+ };
+};
+
+&lpass_va_macro {
+ vdd-micb-supply = <&pp1800_l2c>;
+ pinctrl-0 = <&lpass_dmic01_clk>, <&lpass_dmic01_data>, <&lpass_dmic23_clk>,
+ <&lpass_dmic23_data>;
+
+ status = "okay";
+};
+
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+&lpass_dmic01_clk {
+ drive-strength = <8>;
+ bias-disable;
+};
+
+&lpass_dmic01_data {
+ bias-pull-down;
+};
+
+&lpass_dmic23_clk {
+ drive-strength = <8>;
+ bias-disable;
+};
+
+&lpass_dmic23_data {
+ bias-pull-down;
+};
+
+&mi2s0_data0 {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_data1 {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_mclk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_sclk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_ws {
+ drive-strength = <6>;
+ bias-disable;
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682.dtsi
new file mode 100644
index 000000000000..af685bc35e10
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-rt5682.dtsi
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ *
+ * This file defines the common audio settings for the child boards
+ * using rt5682 codec.
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/ {
+ /* BOARD-SPECIFIC TOP LEVEL NODES */
+ sound: sound {
+ compatible = "google,sc7280-herobrine";
+ model = "sc7280-rt5682-max98360a-1mic";
+
+ audio-routing = "Headphone Jack", "HPOL",
+ "Headphone Jack", "HPOR";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai-link@0 {
+ link-name = "MAX98360";
+ reg = <0>;
+
+ cpu {
+ sound-dai = <&lpass_cpu MI2S_SECONDARY>;
+ };
+
+ codec {
+ sound-dai = <&max98360a>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "ALC5682";
+ reg = <1>;
+
+ cpu {
+ sound-dai = <&lpass_cpu MI2S_PRIMARY>;
+ };
+
+ codec {
+ sound-dai = <&alc5682 0 /* aif1 */>;
+ };
+ };
+ };
+};
+
+hp_i2c: &i2c2 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ alc5682: codec@1a {
+ compatible = "realtek,rt5682s";
+ reg = <0x1a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_irq>;
+
+ #sound-dai-cells = <1>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <101 IRQ_TYPE_EDGE_BOTH>;
+
+ AVDD-supply = <&pp1800_alc5682>;
+ MICVDD-supply = <&pp3300_codec>;
+
+ realtek,dmic1-data-pin = <1>;
+ realtek,dmic1-clk-pin = <2>;
+ realtek,jd-src = <1>;
+ realtek,dmic-clk-rate-hz = <2048000>;
+ };
+};
+
+&lpass_cpu {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mi2s0_data0>, <&mi2s0_data1>, <&mi2s0_mclk>, <&mi2s0_sclk>, <&mi2s0_ws>,
+ <&mi2s1_data0>, <&mi2s1_sclk>, <&mi2s1_ws>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+ dai-link@0 {
+ reg = <MI2S_PRIMARY>;
+ qcom,playback-sd-lines = <1>;
+ qcom,capture-sd-lines = <0>;
+ };
+
+ dai-link@1 {
+ reg = <MI2S_SECONDARY>;
+ qcom,playback-sd-lines = <0>;
+ };
+};
+
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+&mi2s0_data0 {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_data1 {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_mclk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_sclk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s0_ws {
+ drive-strength = <6>;
+ bias-disable;
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi
index c72e53aaf997..ae2552094cda 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi
@@ -167,10 +167,6 @@
bias-disable;
};
-&lpass_dmic01_clk_sleep {
- drive-strength = <2>;
-};
-
&lpass_dmic01_data {
bias-pull-down;
};
@@ -180,10 +176,6 @@
bias-disable;
};
-&lpass_dmic23_clk_sleep {
- drive-strength = <2>;
-};
-
&lpass_dmic23_data {
bias-pull-down;
};
@@ -194,30 +186,18 @@
bias-disable;
};
-&lpass_rx_swr_clk_sleep {
- bias-pull-down;
-};
-
&lpass_rx_swr_data {
drive-strength = <2>;
slew-rate = <1>;
bias-bus-hold;
};
-&lpass_rx_swr_data_sleep {
- bias-pull-down;
-};
-
&lpass_tx_swr_clk {
drive-strength = <2>;
slew-rate = <1>;
bias-disable;
};
-&lpass_tx_swr_clk_sleep {
- bias-pull-down;
-};
-
&lpass_tx_swr_data {
drive-strength = <2>;
slew-rate = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts
index f0f26af1e421..4e0b013e25f4 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts
@@ -372,5 +372,6 @@ ap_ts_pen_1v8: &i2c13 {
"", /* 170 */
"MOS_BLE_UART_TX",
"MOS_BLE_UART_RX",
+ "",
"";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-lte.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-lte.dts
new file mode 100644
index 000000000000..14f20e705869
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-lte.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Evoker board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7280-herobrine-evoker.dtsi"
+#include "sc7280-herobrine-lte-sku.dtsi"
+
+/ {
+ model = "Google Evoker with LTE";
+ compatible = "google,evoker-sku512", "qcom,sc7280";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dts
new file mode 100644
index 000000000000..4f781fe25c9c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Evoker board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7280-herobrine-evoker.dtsi"
+#include "sc7280-herobrine-wifi-sku.dtsi"
+
+/ {
+ model = "Google Evoker";
+ compatible = "google,evoker", "qcom,sc7280";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-r0.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dtsi
index ccbe50b6249a..3d639c70a06e 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker-r0.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-evoker.dtsi
@@ -5,14 +5,8 @@
* Copyright 2022 Google LLC.
*/
-/dts-v1/;
-
#include "sc7280-herobrine.dtsi"
-
-/ {
- model = "Google Evoker";
- compatible = "google,evoker", "qcom,sc7280";
-};
+#include "sc7280-herobrine-audio-rt5682-3mic.dtsi"
/*
* ADDITIONS TO FIXED REGULATORS DEFINED IN PARENT DEVICE TREE FILES
@@ -30,16 +24,15 @@ ap_tp_i2c: &i2c0 {
status = "okay";
clock-frequency = <400000>;
- trackpad: trackpad@2c {
- compatible = "hid-over-i2c";
- reg = <0x2c>;
+ trackpad: trackpad@15 {
+ compatible = "elan,ekth3000";
+ reg = <0x15>;
pinctrl-names = "default";
pinctrl-0 = <&tp_int_odl>;
interrupt-parent = <&tlmm>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
- hid-descr-addr = <0x20>;
vcc-supply = <&pp3300_z1>;
wakeup-source;
@@ -50,9 +43,9 @@ ts_i2c: &i2c13 {
status = "okay";
clock-frequency = <400000>;
- ap_ts: touchscreen@10 {
- compatible = "elan,ekth6915";
- reg = <0x10>;
+ ap_ts: touchscreen@5d {
+ compatible = "goodix,gt7986u", "goodix,gt7375p";
+ reg = <0x5d>;
pinctrl-names = "default";
pinctrl-0 = <&ts_int_conn>, <&ts_rst_conn>;
@@ -61,7 +54,7 @@ ts_i2c: &i2c13 {
reset-gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
- vcc33-supply = <&ts_avdd>;
+ vdd-supply = <&ts_avdd>;
};
};
@@ -328,6 +321,5 @@ ts_i2c: &i2c13 {
"MOS_BLE_UART_TX",
"MOS_BLE_UART_RX",
"",
- "",
"";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts
index c1a671968725..b04888a98203 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts
@@ -8,6 +8,7 @@
/dts-v1/;
#include "sc7280-herobrine.dtsi"
+#include "sc7280-herobrine-audio-rt5682.dtsi"
#include "sc7280-herobrine-lte-sku.dtsi"
/ {
@@ -47,10 +48,6 @@
/* ADDITIONS TO NODES DEFINED IN PARENT DEVICE TREE FILES */
-&ap_spi_fp {
- status = "okay";
-};
-
/*
* Although the trackpad is really part of the herobrine baseboard, we'll
* put the actual definition in the board device tree since different boards
@@ -358,6 +355,5 @@ ts_i2c: &i2c13 {
"MOS_BLE_UART_TX",
"MOS_BLE_UART_RX",
"",
- "",
"";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
index a92eeccd2b2a..ad66e5e9db4e 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi
@@ -6,6 +6,20 @@
*/
/* Modem setup is different on Chrome setups than typical Qualcomm setup */
+/ {
+ reserved-memory {
+ mpss_mem: memory@8b800000 {
+ reg = <0x0 0x8b800000 0x0 0xf600000>;
+ no-map;
+ };
+
+ mba_mem: memory@9c700000 {
+ reg = <0x0 0x9c700000 0x0 0x200000>;
+ no-map;
+ };
+ };
+};
+
&remoteproc_mpss {
compatible = "qcom,sc7280-mss-pil";
iommus = <&apps_smmu 0x124 0x0>, <&apps_smmu 0x488 0x7>;
@@ -15,3 +29,8 @@
"qcom/sc7280-herobrine/modem/qdsp6sw.mbn";
status = "okay";
};
+
+/* Increase the size from 2.5MB to 8MB */
+&rmtfs_mem {
+ reg = <0x0 0x9c900000 0x0 0x800000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1-lte.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1-lte.dts
index f1017809e5da..d71cc4bbc4b3 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1-lte.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1-lte.dts
@@ -5,7 +5,9 @@
* Copyright 2022 Google LLC.
*/
-#include "sc7280-herobrine-villager-r1.dts"
+/dts-v1/;
+
+#include "sc7280-herobrine-villager-r1.dtsi"
#include "sc7280-herobrine-lte-sku.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dts
index cfc648726930..edb52f12f0ea 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dts
@@ -7,37 +7,10 @@
/dts-v1/;
-#include "sc7280-herobrine-villager.dtsi"
-#include "sc7280-herobrine-audio-wcd9385.dtsi"
+#include "sc7280-herobrine-villager-r1.dtsi"
+#include "sc7280-herobrine-wifi-sku.dtsi"
/ {
model = "Google Villager (rev1+)";
compatible = "google,villager", "qcom,sc7280";
};
-
-&lpass_va_macro {
- vdd-micb-supply = <&pp1800_l2c>;
-};
-
-&sound {
- audio-routing =
- "IN1_HPHL", "HPHL_OUT",
- "IN2_HPHR", "HPHR_OUT",
- "AMIC1", "MIC BIAS1",
- "AMIC2", "MIC BIAS2",
- "VA DMIC0", "vdd-micb",
- "VA DMIC1", "vdd-micb",
- "VA DMIC2", "vdd-micb",
- "VA DMIC3", "vdd-micb",
- "TX SWR_ADC0", "ADC1_OUTPUT",
- "TX SWR_ADC1", "ADC2_OUTPUT",
- "TX SWR_ADC2", "ADC3_OUTPUT",
- "TX SWR_DMIC0", "DMIC1_OUTPUT",
- "TX SWR_DMIC1", "DMIC2_OUTPUT",
- "TX SWR_DMIC2", "DMIC3_OUTPUT",
- "TX SWR_DMIC3", "DMIC4_OUTPUT",
- "TX SWR_DMIC4", "DMIC5_OUTPUT",
- "TX SWR_DMIC5", "DMIC6_OUTPUT",
- "TX SWR_DMIC6", "DMIC7_OUTPUT",
- "TX SWR_DMIC7", "DMIC8_OUTPUT";
-};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dtsi
new file mode 100644
index 000000000000..b25df5a99161
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r1.dtsi
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Villager board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "sc7280-herobrine-villager.dtsi"
+#include "sc7280-herobrine-audio-wcd9385.dtsi"
+
+&lpass_va_macro {
+ vdd-micb-supply = <&pp1800_l2c>;
+};
+
+&sound {
+ audio-routing =
+ "IN1_HPHL", "HPHL_OUT",
+ "IN2_HPHR", "HPHR_OUT",
+ "AMIC1", "MIC BIAS1",
+ "AMIC2", "MIC BIAS2",
+ "VA DMIC0", "vdd-micb",
+ "VA DMIC1", "vdd-micb",
+ "VA DMIC2", "vdd-micb",
+ "VA DMIC3", "vdd-micb",
+ "TX SWR_ADC0", "ADC1_OUTPUT",
+ "TX SWR_ADC1", "ADC2_OUTPUT",
+ "TX SWR_ADC2", "ADC3_OUTPUT",
+ "TX SWR_DMIC0", "DMIC1_OUTPUT",
+ "TX SWR_DMIC1", "DMIC2_OUTPUT",
+ "TX SWR_DMIC2", "DMIC3_OUTPUT",
+ "TX SWR_DMIC3", "DMIC4_OUTPUT",
+ "TX SWR_DMIC4", "DMIC5_OUTPUT",
+ "TX SWR_DMIC5", "DMIC6_OUTPUT",
+ "TX SWR_DMIC6", "DMIC7_OUTPUT",
+ "TX SWR_DMIC7", "DMIC8_OUTPUT";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager.dtsi
index 4566722bf4dd..17553e0fd6fd 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-villager.dtsi
@@ -78,16 +78,6 @@ ts_i2c: &i2c13 {
status = "okay";
};
-/* For nvme */
-&pcie1 {
- status = "okay";
-};
-
-/* For nvme */
-&pcie1_phy {
- status = "okay";
-};
-
&pwmleds {
status = "okay";
};
@@ -321,6 +311,5 @@ ts_i2c: &i2c13 {
"MOS_BLE_UART_TX",
"MOS_BLE_UART_RX",
"",
- "",
"";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi
new file mode 100644
index 000000000000..2febd6126d4c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Google Herobrine dts fragment for WIFI SKUs
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+/* WIFI SKUs save 256M by not having modem/mba/rmtfs memory regions defined. */
+
+/delete-node/ &remoteproc_mpss;
+/delete-node/ &rmtfs_mem;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie-lte.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie-lte.dts
new file mode 100644
index 000000000000..c9fe64529555
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie-lte.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Zombie board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7280-herobrine-zombie.dtsi"
+#include "sc7280-herobrine-lte-sku.dtsi"
+
+/ {
+ model = "Google Zombie with LTE";
+ compatible = "google,zombie-sku512", "qcom,sc7280";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dts b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dts
new file mode 100644
index 000000000000..0246c12b2f40
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Zombie board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7280-herobrine-zombie.dtsi"
+#include "sc7280-herobrine-wifi-sku.dtsi"
+
+/ {
+ model = "Google Zombie";
+ compatible = "google,zombie", "qcom,sc7280";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dtsi
new file mode 100644
index 000000000000..7fc0b6bfc0d6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-zombie.dtsi
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Zombie board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+#include "sc7280-herobrine.dtsi"
+#include "sc7280-herobrine-audio-rt5682.dtsi"
+
+/*
+ * ADDITIONS TO FIXED REGULATORS DEFINED IN PARENT DEVICE TREE FILES
+ *
+ * Sort order matches the order in the parent files (parents before children).
+ */
+
+&pp3300_codec {
+ status = "okay";
+};
+
+/* ADDITIONS TO NODES DEFINED IN PARENT DEVICE TREE FILES */
+
+ap_tp_i2c: &i2c0 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ trackpad: trackpad@15 {
+ compatible = "hid-over-i2c";
+ reg = <0x15>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tp_int_odl>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+
+ hid-descr-addr = <0x01>;
+ vdd-supply = <&pp3300_z1>;
+
+ wakeup-source;
+ };
+};
+
+&ap_sar_sensor_i2c {
+ status = "okay";
+};
+
+&ap_sar_sensor0 {
+ status = "okay";
+};
+
+&ap_sar_sensor1 {
+ status = "okay";
+};
+
+&mdss_edp {
+ status = "okay";
+};
+
+&mdss_edp_phy {
+ status = "okay";
+};
+
+/* For nvme */
+&pcie1 {
+ status = "okay";
+};
+
+/* For nvme */
+&pcie1_phy {
+ status = "okay";
+};
+
+&pm8350c_pwm_backlight{
+ /* Set the PWM period to 200 microseconds (5kHz duty cycle) */
+ pwms = <&pm8350c_pwm 3 200000>;
+};
+
+&pwmleds {
+ status = "okay";
+};
+
+/* For eMMC */
+&sdhc_1 {
+ status = "okay";
+};
+
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+&ts_rst_conn {
+ bias-disable;
+};
+
+/* PINCTRL - BOARD-SPECIFIC */
+
+/*
+ * Methodology for gpio-line-names:
+ * - If a pin goes to herobrine board and is named it gets that name.
+ * - If a pin goes to herobrine board and is not named, it gets no name.
+ * - If a pin is totally internal to Qcard then it gets Qcard name.
+ * - If a pin is not hooked up on Qcard, it gets no name.
+ */
+
+&pm8350c_gpios {
+ gpio-line-names = "FLASH_STROBE_1", /* 1 */
+ "AP_SUSPEND",
+ "PM8008_1_RST_N",
+ "",
+ "",
+ "",
+ "PMIC_EDP_BL_EN",
+ "PMIC_EDP_BL_PWM",
+ "";
+};
+
+&tlmm {
+ gpio-line-names = "AP_TP_I2C_SDA", /* 0 */
+ "AP_TP_I2C_SCL",
+ "SSD_RST_L",
+ "PE_WAKE_ODL",
+ "AP_SAR_SDA",
+ "AP_SAR_SCL",
+ "PRB_SC_GPIO_6",
+ "TP_INT_ODL",
+ "HP_I2C_SDA",
+ "HP_I2C_SCL",
+
+ "GNSS_L1_EN", /* 10 */
+ "GNSS_L5_EN",
+ "SPI_AP_MOSI",
+ "SPI_AP_MISO",
+ "SPI_AP_CLK",
+ "SPI_AP_CS0_L",
+ /*
+ * AP_FLASH_WP is crossystem ABI. Schematics
+ * call it BIOS_FLASH_WP_OD.
+ */
+ "AP_FLASH_WP",
+ "",
+ "AP_EC_INT_L",
+ "",
+
+ "UF_CAM_RST_L", /* 20 */
+ "WF_CAM_RST_L",
+ "UART_AP_TX_DBG_RX",
+ "UART_DBG_TX_AP_RX",
+ "",
+ "PM8008_IRQ_1",
+ "HOST2WLAN_SOL",
+ "WLAN2HOST_SOL",
+ "MOS_BT_UART_CTS",
+ "MOS_BT_UART_RFR",
+
+ "MOS_BT_UART_TX", /* 30 */
+ "MOS_BT_UART_RX",
+ "PRB_SC_GPIO_32",
+ "HUB_RST_L",
+ "",
+ "",
+ "AP_SPI_FP_MISO",
+ "AP_SPI_FP_MOSI",
+ "AP_SPI_FP_CLK",
+ "AP_SPI_FP_CS_L",
+
+ "AP_EC_SPI_MISO", /* 40 */
+ "AP_EC_SPI_MOSI",
+ "AP_EC_SPI_CLK",
+ "AP_EC_SPI_CS_L",
+ "LCM_RST_L",
+ "EARLY_EUD_N",
+ "",
+ "DP_HOT_PLUG_DET",
+ "IO_BRD_MLB_ID0",
+ "IO_BRD_MLB_ID1",
+
+ "IO_BRD_MLB_ID2", /* 50 */
+ "SSD_EN",
+ "TS_I2C_SDA_CONN",
+ "TS_I2C_CLK_CONN",
+ "TS_RST_CONN",
+ "TS_INT_CONN",
+ "AP_I2C_TPM_SDA",
+ "AP_I2C_TPM_SCL",
+ "PRB_SC_GPIO_58",
+ "PRB_SC_GPIO_59",
+
+ "EDP_HOT_PLUG_DET_N", /* 60 */
+ "FP_TO_AP_IRQ_L",
+ "",
+ "AMP_EN",
+ "CAM0_MCLK_GPIO_64",
+ "CAM1_MCLK_GPIO_65",
+ "WF_CAM_MCLK",
+ "PRB_SC_GPIO_67",
+ "FPMCU_BOOT0",
+ "UF_CAM_SDA",
+
+ "UF_CAM_SCL", /* 70 */
+ "",
+ "",
+ "WF_CAM_SDA",
+ "WF_CAM_SCL",
+ "",
+ "",
+ "EN_FP_RAILS",
+ "FP_RST_L",
+ "PCIE1_CLKREQ_ODL",
+
+ "EN_PP3300_DX_EDP", /* 80 */
+ "US_EURO_HS_SEL",
+ "FORCED_USB_BOOT",
+ "WCD_RESET_N",
+ "MOS_WLAN_EN",
+ "MOS_BT_EN",
+ "MOS_SW_CTRL",
+ "MOS_PCIE0_RST",
+ "MOS_PCIE0_CLKREQ_N",
+ "MOS_PCIE0_WAKE_N",
+
+ "MOS_LAA_AS_EN", /* 90 */
+ "SD_CD_ODL",
+ "",
+ "",
+ "MOS_BT_WLAN_SLIMBUS_CLK",
+ "MOS_BT_WLAN_SLIMBUS_DAT0",
+ "HP_MCLK",
+ "HP_BCLK",
+ "HP_DOUT",
+ "HP_DIN",
+
+ "HP_LRCLK", /* 100 */
+ "HP_IRQ",
+ "",
+ "",
+ "GSC_AP_INT_ODL",
+ "EN_PP3300_CODEC",
+ "AMP_BCLK",
+ "AMP_DIN",
+ "AMP_LRCLK",
+ "UIM1_DATA_GPIO_109",
+
+ "UIM1_CLK_GPIO_110", /* 110 */
+ "UIM1_RESET_GPIO_111",
+ "PRB_SC_GPIO_112",
+ "UIM0_DATA",
+ "UIM0_CLK",
+ "UIM0_RST",
+ "UIM0_PRESENT_ODL",
+ "SDM_RFFE0_CLK",
+ "SDM_RFFE0_DATA",
+ "WF_CAM_EN",
+
+ "FASTBOOT_SEL_0", /* 120 */
+ "SC_GPIO_121",
+ "FASTBOOT_SEL_1",
+ "SC_GPIO_123",
+ "FASTBOOT_SEL_2",
+ "SM_RFFE4_CLK_GRFC_8",
+ "SM_RFFE4_DATA_GRFC_9",
+ "WLAN_COEX_UART1_RX",
+ "WLAN_COEX_UART1_TX",
+ "PRB_SC_GPIO_129",
+
+ "LCM_ID0", /* 130 */
+ "LCM_ID1",
+ "",
+ "SDR_QLINK_REQ",
+ "SDR_QLINK_EN",
+ "QLINK0_WMSS_RESET_N",
+ "SMR526_QLINK1_REQ",
+ "SMR526_QLINK1_EN",
+ "SMR526_QLINK1_WMSS_RESET_N",
+ "PRB_SC_GPIO_139",
+
+ "SAR1_IRQ_ODL", /* 140 */
+ "SAR0_IRQ_ODL",
+ "PRB_SC_GPIO_142",
+ "",
+ "WCD_SWR_TX_CLK",
+ "WCD_SWR_TX_DATA0",
+ "WCD_SWR_TX_DATA1",
+ "WCD_SWR_RX_CLK",
+ "WCD_SWR_RX_DATA0",
+ "WCD_SWR_RX_DATA1",
+
+ "DMIC01_CLK", /* 150 */
+ "DMIC01_DATA",
+ "DMIC23_CLK",
+ "DMIC23_DATA",
+ "",
+ "",
+ "EC_IN_RW_ODL",
+ "HUB_EN",
+ "WCD_SWR_TX_DATA2",
+ "",
+
+ "", /* 160 */
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+
+ "", /* 170 */
+ "MOS_BLE_UART_TX",
+ "MOS_BLE_UART_RX",
+ "",
+ "";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
index c11e37160f34..27f479ff9d80 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
@@ -307,7 +307,7 @@
pwmleds: pwmleds {
compatible = "pwm-leds";
status = "disabled";
- keyboard_backlight: keyboard-backlight {
+ keyboard_backlight: led-0 {
label = "cros_ec::kbd_backlight";
function = LED_FUNCTION_KBD_BACKLIGHT;
pwms = <&cros_ec_pwm 0>;
@@ -503,13 +503,16 @@ ap_spi_fp: &spi9 {
cs-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
cros_ec_fp: ec@0 {
- compatible = "google,cros-ec-spi";
+ compatible = "google,cros-ec-fp", "google,cros-ec-spi";
reg = <0>;
interrupt-parent = <&tlmm>;
interrupts = <61 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&fp_to_ap_irq_l>, <&fp_rst_l>, <&fpmcu_boot0>;
+ boot0-gpios = <&tlmm 68 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>;
spi-max-frequency = <3000000>;
+ vdd-supply = <&pp3300_fp_mcu>;
};
};
@@ -627,6 +630,13 @@ ap_ec_spi: &spi10 {
&usb_1_hsphy {
status = "okay";
+
+ qcom,hs-rise-fall-time-bp = <0>;
+ qcom,squelch-detector-bp = <(-2090)>;
+ qcom,hs-disconnect-bp = <1743>;
+ qcom,hs-amplitude-bp = <1780>;
+ qcom,hs-crossover-voltage-microvolt = <(-31000)>;
+ qcom,hs-output-impedance-micro-ohms = <2600000>;
};
&usb_1_qmpphy {
@@ -639,6 +649,21 @@ ap_ec_spi: &spi10 {
bias-disable;
};
+&mi2s1_data0 {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s1_sclk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&mi2s1_ws {
+ drive-strength = <6>;
+ bias-disable;
+};
+
&pcie1_clkreq_n {
bias-pull-up;
drive-strength = <2>;
@@ -744,27 +769,27 @@ ap_ec_spi: &spi10 {
pinctrl-names = "default";
pinctrl-0 = <&bios_flash_wp_od>;
- amp_en: amp-en-pins {
+ amp_en: amp-en-state {
pins = "gpio63";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- ap_ec_int_l: ap-ec-int-l-pins {
+ ap_ec_int_l: ap-ec-int-l-state {
pins = "gpio18";
function = "gpio";
bias-pull-up;
};
- bios_flash_wp_od: bios-flash-wp-od-pins {
+ bios_flash_wp_od: bios-flash-wp-od-state {
pins = "gpio16";
function = "gpio";
/* Has external pull */
bias-disable;
};
- en_fp_rails: en-fp-rails-pins {
+ en_fp_rails: en-fp-rails-state {
pins = "gpio77";
function = "gpio";
bias-disable;
@@ -772,60 +797,60 @@ ap_ec_spi: &spi10 {
output-high;
};
- en_pp3300_codec: en-pp3300-codec-pins {
+ en_pp3300_codec: en-pp3300-codec-state {
pins = "gpio105";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- en_pp3300_dx_edp: en-pp3300-dx-edp-pins {
+ en_pp3300_dx_edp: en-pp3300-dx-edp-state {
pins = "gpio80";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- fp_rst_l: fp-rst-l-pins {
+ fp_rst_l: fp-rst-l-state {
pins = "gpio78";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- fp_to_ap_irq_l: fp-to-ap-irq-l-pins {
+ fp_to_ap_irq_l: fp-to-ap-irq-l-state {
pins = "gpio61";
function = "gpio";
/* Has external pullup */
bias-disable;
};
- fpmcu_boot0: fpmcu-boot0-pins {
+ fpmcu_boot0: fpmcu-boot0-state {
pins = "gpio68";
function = "gpio";
bias-disable;
};
- gsc_ap_int_odl: gsc-ap-int-odl-pins {
+ gsc_ap_int_odl: gsc-ap-int-odl-state {
pins = "gpio104";
function = "gpio";
bias-pull-up;
};
- hp_irq: hp-irq-pins {
+ hp_irq: hp-irq-state {
pins = "gpio101";
function = "gpio";
bias-pull-up;
};
- hub_en: hub-en-pins {
+ hub_en: hub-en-state {
pins = "gpio157";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- pe_wake_odl: pe-wake-odl-pins {
+ pe_wake_odl: pe-wake-odl-state {
pins = "gpio3";
function = "gpio";
/* Has external pull */
@@ -834,45 +859,45 @@ ap_ec_spi: &spi10 {
};
/* For ap_spi_fp */
- qup_spi9_cs_gpio_init_high: qup-spi9-cs-gpio-init-high-pins {
+ qup_spi9_cs_gpio_init_high: qup-spi9-cs-gpio-init-high-state {
pins = "gpio39";
function = "gpio";
output-high;
};
/* For ap_ec_spi */
- qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high-pins {
+ qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high-state {
pins = "gpio43";
function = "gpio";
output-high;
};
- sar0_irq_odl: sar0-irq-odl-pins {
+ sar0_irq_odl: sar0-irq-odl-state {
pins = "gpio141";
function = "gpio";
bias-pull-up;
};
- sar1_irq_odl: sar1-irq-odl-pins {
+ sar1_irq_odl: sar1-irq-odl-state {
pins = "gpio140";
function = "gpio";
bias-pull-up;
};
- sd_cd_odl: sd-cd-odl-pins {
+ sd_cd_odl: sd-cd-odl-state {
pins = "gpio91";
function = "gpio";
bias-pull-up;
};
- ssd_en: ssd-en-pins {
+ ssd_en: ssd-en-state {
pins = "gpio51";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- ssd_rst_l: ssd-rst-l-pins {
+ ssd_rst_l: ssd-rst-l-state {
pins = "gpio2";
function = "gpio";
bias-disable;
@@ -880,14 +905,14 @@ ap_ec_spi: &spi10 {
output-low;
};
- tp_int_odl: tp-int-odl-pins {
+ tp_int_odl: tp-int-odl-state {
pins = "gpio7";
function = "gpio";
/* Has external pullup */
bias-disable;
};
- wf_cam_en: wf-cam-en-pins {
+ wf_cam_en: wf-cam-en-state {
pins = "gpio119";
function = "gpio";
/* Has external pulldown */
diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi
index 7f5143e9bb80..3cfeb118d379 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi
@@ -79,27 +79,29 @@ ap_h1_spi: &spi14 {
};
&tlmm {
- ap_ec_int_l: ap-ec-int-l-pins {
+ ap_ec_int_l: ap-ec-int-l-state {
pins = "gpio18";
function = "gpio";
input-enable;
bias-pull-up;
};
- h1_ap_int_odl: h1-ap-int-odl-pins {
+ h1_ap_int_odl: h1-ap-int-odl-state {
pins = "gpio104";
function = "gpio";
input-enable;
bias-pull-up;
};
- qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high-pins {
+ qup_spi10_cs_gpio_init_high: qup-spi10-cs-gpio-init-high-state {
pins = "gpio43";
+ function = "gpio";
output-high;
};
- qup_spi14_cs_gpio_init_high: qup-spi14-cs-gpio-init-high-pins {
+ qup_spi14_cs_gpio_init_high: qup-spi14-cs-gpio-init-high-state {
pins = "gpio59";
+ function = "gpio";
output-high;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dts b/arch/arm64/boot/dts/qcom/sc7280-idp.dts
index 7559164cdda0..ba64316b4427 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-idp.dts
+++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dts
@@ -10,7 +10,6 @@
#include <dt-bindings/iio/qcom,spmi-adc7-pmr735a.h>
#include "sc7280-idp.dtsi"
#include "pmr735a.dtsi"
-#include "sc7280-herobrine-lte-sku.dtsi"
/ {
model = "Qualcomm Technologies, Inc. sc7280 IDP SKU1 platform";
@@ -61,11 +60,6 @@
vddio-supply = <&vreg_l19b_1p8>;
};
-&ipa {
- status = "okay";
- modem-init;
-};
-
&pmk8350_rtc {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
index cd432a2856a7..f7efb9966afd 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
@@ -13,6 +13,7 @@
#include "pmk8350.dtsi"
#include "sc7280-chrome-common.dtsi"
+#include "sc7280-herobrine-lte-sku.dtsi"
/ {
aliases {
@@ -34,7 +35,7 @@
pinctrl-0 = <&wcd_reset_n>;
pinctrl-1 = <&wcd_reset_n_sleep>;
- reset-gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 83 GPIO_ACTIVE_LOW>;
qcom,rx-device = <&wcd_rx>;
qcom,tx-device = <&wcd_tx>;
@@ -522,6 +523,12 @@
vdda-pll-supply = <&vreg_l10c_0p8>;
vdda33-supply = <&vreg_l2b_3p0>;
vdda18-supply = <&vreg_l1c_1p8>;
+ qcom,hs-rise-fall-time-bp = <0>;
+ qcom,squelch-detector-bp = <(-2090)>;
+ qcom,hs-disconnect-bp = <1743>;
+ qcom,hs-amplitude-bp = <1780>;
+ qcom,hs-crossover-voltage-microvolt = <(-31000)>;
+ qcom,hs-output-impedance-micro-ohms = <2600000>;
};
&usb_1_qmpphy {
@@ -569,10 +576,6 @@
bias-disable;
};
-&lpass_dmic01_clk_sleep {
- drive-strength = <2>;
-};
-
&lpass_dmic01_data {
bias-pull-down;
};
@@ -582,10 +585,6 @@
bias-disable;
};
-&lpass_dmic23_clk_sleep {
- drive-strength = <2>;
-};
-
&lpass_dmic23_data {
bias-pull-down;
};
@@ -596,30 +595,18 @@
bias-disable;
};
-&lpass_rx_swr_clk_sleep {
- bias-pull-down;
-};
-
&lpass_rx_swr_data {
drive-strength = <2>;
slew-rate = <1>;
bias-bus-hold;
};
-&lpass_rx_swr_data_sleep {
- bias-pull-down;
-};
-
&lpass_tx_swr_clk {
drive-strength = <2>;
slew-rate = <1>;
bias-disable;
};
-&lpass_tx_swr_clk_sleep {
- bias-pull-down;
-};
-
&lpass_tx_swr_data {
drive-strength = <2>;
slew-rate = <1>;
@@ -747,24 +734,24 @@
};
&tlmm {
- amp_en: amp-en {
+ amp_en: amp-en-state {
pins = "gpio63";
bias-pull-down;
drive-strength = <2>;
};
- bt_en: bt-en-pins {
+ bt_en: bt-en-state {
pins = "gpio85";
function = "gpio";
output-low;
bias-disable;
};
- nvme_pwren: nvme-pwren-pins {
+ nvme_pwren: nvme-pwren-state {
function = "gpio";
};
- pcie1_reset_n: pcie1-reset-n-pins {
+ pcie1_reset_n: pcie1-reset-n-state {
pins = "gpio2";
function = "gpio";
@@ -773,7 +760,7 @@
bias-disable;
};
- pcie1_wake_n: pcie1-wake-n-pins {
+ pcie1_wake_n: pcie1-wake-n-state {
pins = "gpio3";
function = "gpio";
@@ -781,7 +768,7 @@
bias-pull-up;
};
- qup_uart7_sleep_cts: qup-uart7-sleep-cts-pins {
+ qup_uart7_sleep_cts: qup-uart7-sleep-cts-state {
pins = "gpio28";
function = "gpio";
/*
@@ -794,7 +781,7 @@
bias-bus-hold;
};
- qup_uart7_sleep_rts: qup-uart7-sleep-rts-pins {
+ qup_uart7_sleep_rts: qup-uart7-sleep-rts-state {
pins = "gpio29";
function = "gpio";
/*
@@ -806,7 +793,7 @@
bias-pull-down;
};
- qup_uart7_sleep_tx: qup-uart7-sleep-tx-pins {
+ qup_uart7_sleep_tx: qup-uart7-sleep-tx-state {
pins = "gpio30";
function = "gpio";
/*
@@ -816,7 +803,7 @@
bias-pull-up;
};
- qup_uart7_sleep_rx: qup-uart7-sleep-rx-pins {
+ qup_uart7_sleep_rx: qup-uart7-sleep-rx-state {
pins = "gpio31";
function = "gpio";
/*
@@ -827,25 +814,25 @@
bias-pull-up;
};
- sd_cd: sd-cd-pins {
+ sd_cd: sd-cd-state {
pins = "gpio91";
function = "gpio";
bias-pull-up;
};
- sw_ctrl: sw-ctrl-pins {
+ sw_ctrl: sw-ctrl-state {
pins = "gpio86";
function = "gpio";
bias-pull-down;
};
- wcd_reset_n: wcd-reset-n {
+ wcd_reset_n: wcd-reset-n-state {
pins = "gpio83";
function = "gpio";
drive-strength = <8>;
};
- wcd_reset_n_sleep: wcd-reset-n-sleep {
+ wcd_reset_n_sleep: wcd-reset-n-sleep-state {
pins = "gpio83";
function = "gpio";
drive-strength = <8>;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi b/arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi
index 4b8c676b0bb1..df49564ae6dc 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi
@@ -37,7 +37,7 @@
pinctrl-0 = <&wcd_reset_n>, <&us_euro_hs_sel>;
pinctrl-1 = <&wcd_reset_n_sleep>, <&us_euro_hs_sel>;
- reset-gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 83 GPIO_ACTIVE_LOW>;
us-euro-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>;
qcom,rx-device = <&wcd_rx>;
@@ -595,7 +595,7 @@ mos_bt_uart: &uart7 {
};
&tlmm {
- mos_bt_en: mos-bt-en-pins {
+ mos_bt_en: mos-bt-en-state {
pins = "gpio85";
function = "gpio";
drive-strength = <2>;
@@ -603,7 +603,7 @@ mos_bt_uart: &uart7 {
};
/* For mos_bt_uart */
- qup_uart7_sleep_cts: qup-uart7-sleep-cts-pins {
+ qup_uart7_sleep_cts: qup-uart7-sleep-cts-state {
pins = "gpio28";
function = "gpio";
/*
@@ -617,7 +617,7 @@ mos_bt_uart: &uart7 {
};
/* For mos_bt_uart */
- qup_uart7_sleep_rts: qup-uart7-sleep-rts-pins {
+ qup_uart7_sleep_rts: qup-uart7-sleep-rts-state {
pins = "gpio29";
function = "gpio";
/*
@@ -630,7 +630,7 @@ mos_bt_uart: &uart7 {
};
/* For mos_bt_uart */
- qup_uart7_sleep_rx: qup-uart7-sleep-rx-pins {
+ qup_uart7_sleep_rx: qup-uart7-sleep-rx-state {
pins = "gpio31";
function = "gpio";
/*
@@ -642,7 +642,7 @@ mos_bt_uart: &uart7 {
};
/* For mos_bt_uart */
- qup_uart7_sleep_tx: qup-uart7-sleep-tx-pins {
+ qup_uart7_sleep_tx: qup-uart7-sleep-tx-state {
pins = "gpio30";
function = "gpio";
/*
@@ -652,32 +652,32 @@ mos_bt_uart: &uart7 {
bias-pull-up;
};
- ts_int_conn: ts-int-conn-pins {
+ ts_int_conn: ts-int-conn-state {
pins = "gpio55";
function = "gpio";
bias-pull-up;
};
- ts_rst_conn: ts-rst-conn-pins {
+ ts_rst_conn: ts-rst-conn-state {
pins = "gpio54";
function = "gpio";
drive-strength = <2>;
};
- us_euro_hs_sel: us-euro-hs-sel {
+ us_euro_hs_sel: us-euro-hs-sel-state {
pins = "gpio81";
function = "gpio";
bias-pull-down;
drive-strength = <2>;
};
- wcd_reset_n: wcd-reset-n {
+ wcd_reset_n: wcd-reset-n-state {
pins = "gpio83";
function = "gpio";
drive-strength = <8>;
};
- wcd_reset_n_sleep: wcd-reset-n-sleep {
+ wcd_reset_n_sleep: wcd-reset-n-sleep-state {
pins = "gpio83";
function = "gpio";
drive-strength = <8>;
diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
index 212580316d3e..0adf13399e64 100644
--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
@@ -752,6 +752,17 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ wlan_smp2p_out: wlan-ap-to-wpss {
+ qcom,entry-name = "wlan";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ wlan_smp2p_in: wlan-wpss-to-ap {
+ qcom,entry-name = "wlan";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
pmu {
@@ -920,7 +931,7 @@
gpi_dma0: dma-controller@900000 {
#dma-cells = <3>;
- compatible = "qcom,sc7280-gpi-dma";
+ compatible = "qcom,sc7280-gpi-dma", "qcom,sm6350-gpi-dma";
reg = <0 0x00900000 0 0x60000>;
interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
@@ -967,6 +978,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
<&gpi_dma0 1 0 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1025,6 +1038,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>,
<&gpi_dma0 1 1 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1083,6 +1098,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>,
<&gpi_dma0 1 2 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1141,6 +1158,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>,
<&gpi_dma0 1 3 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1199,6 +1218,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>,
<&gpi_dma0 1 4 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1257,6 +1278,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>,
<&gpi_dma0 1 5 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1315,6 +1338,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>,
<&gpi_dma0 1 6 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1373,6 +1398,8 @@
<&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>,
<&gpi_dma0 1 7 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1419,7 +1446,7 @@
gpi_dma1: dma-controller@a00000 {
#dma-cells = <3>;
- compatible = "qcom,sc7280-gpi-dma";
+ compatible = "qcom,sc7280-gpi-dma", "qcom,sm6350-gpi-dma";
reg = <0 0x00a00000 0 0x60000>;
interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
@@ -1466,6 +1493,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>,
<&gpi_dma1 1 0 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1524,6 +1553,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>,
<&gpi_dma1 1 1 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1582,6 +1613,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>,
<&gpi_dma1 1 2 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1640,6 +1673,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>,
<&gpi_dma1 1 3 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1698,6 +1733,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>,
<&gpi_dma1 1 4 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1756,6 +1793,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>,
<&gpi_dma1 1 5 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1814,6 +1853,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>,
<&gpi_dma1 1 6 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -1872,6 +1913,8 @@
<&aggre2_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>;
interconnect-names = "qup-core", "qup-config",
"qup-memory";
+ power-domains = <&rpmhpd SC7280_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>,
<&gpi_dma1 1 7 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
@@ -2004,6 +2047,8 @@
qcom,rproc = <&remoteproc_wpss>;
memory-region = <&wlan_fw_mem>, <&wlan_ce_mem>;
status = "disabled";
+ qcom,smem-states = <&wlan_smp2p_out 0>;
+ qcom,smem-state-names = "wlan-smp2p-out";
};
pcie1: pci@1c08000 {
@@ -2285,7 +2330,6 @@
qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff>;
qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff>;
qcom,ports-lane-control = /bits/ 8 <0x00 0x01 0x00>;
- qcom,port-offset = <1>;
#sound-dai-cells = <1>;
#address-cells = <2>;
@@ -2296,7 +2340,8 @@
lpass_audiocc: clock-controller@3300000 {
compatible = "qcom,sc7280-lpassaudiocc";
- reg = <0 0x03300000 0 0x30000>;
+ reg = <0 0x03300000 0 0x30000>,
+ <0 0x032a9000 0 0x1000>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&lpass_aon LPASS_AON_CC_MAIN_RCG_CLK_SRC>;
clock-names = "bi_tcxo", "lpass_aon_cc_main_rcg_clk_src";
@@ -2433,84 +2478,42 @@
#gpio-cells = <2>;
gpio-ranges = <&lpass_tlmm 0 0 15>;
- #clock-cells = <1>;
-
- lpass_dmic01_clk: dmic01-clk {
- pins = "gpio6";
- function = "dmic1_clk";
- };
-
- lpass_dmic01_clk_sleep: dmic01-clk-sleep {
+ lpass_dmic01_clk: dmic01-clk-state {
pins = "gpio6";
function = "dmic1_clk";
};
- lpass_dmic01_data: dmic01-data {
+ lpass_dmic01_data: dmic01-data-state {
pins = "gpio7";
function = "dmic1_data";
};
- lpass_dmic01_data_sleep: dmic01-data-sleep {
- pins = "gpio7";
- function = "dmic1_data";
- };
-
- lpass_dmic23_clk: dmic23-clk {
- pins = "gpio8";
- function = "dmic2_clk";
- };
-
- lpass_dmic23_clk_sleep: dmic23-clk-sleep {
+ lpass_dmic23_clk: dmic23-clk-state {
pins = "gpio8";
function = "dmic2_clk";
};
- lpass_dmic23_data: dmic23-data {
+ lpass_dmic23_data: dmic23-data-state {
pins = "gpio9";
function = "dmic2_data";
};
- lpass_dmic23_data_sleep: dmic23-data-sleep {
- pins = "gpio9";
- function = "dmic2_data";
- };
-
- lpass_rx_swr_clk: rx-swr-clk {
+ lpass_rx_swr_clk: rx-swr-clk-state {
pins = "gpio3";
function = "swr_rx_clk";
};
- lpass_rx_swr_clk_sleep: rx-swr-clk-sleep {
- pins = "gpio3";
- function = "swr_rx_clk";
- };
-
- lpass_rx_swr_data: rx-swr-data {
+ lpass_rx_swr_data: rx-swr-data-state {
pins = "gpio4", "gpio5";
function = "swr_rx_data";
};
- lpass_rx_swr_data_sleep: rx-swr-data-sleep {
- pins = "gpio4", "gpio5";
- function = "swr_rx_data";
- };
-
- lpass_tx_swr_clk: tx-swr-clk {
- pins = "gpio0";
- function = "swr_tx_clk";
- };
-
- lpass_tx_swr_clk_sleep: tx-swr-clk-sleep {
+ lpass_tx_swr_clk: tx-swr-clk-state {
pins = "gpio0";
function = "swr_tx_clk";
};
- lpass_tx_swr_data: tx-swr-data {
- pins = "gpio1", "gpio2", "gpio14";
- function = "swr_tx_data";
- };
-
- lpass_tx_swr_data_sleep: tx-swr-data-sleep {
+ lpass_tx_swr_data: tx-swr-data-state {
pins = "gpio1", "gpio2", "gpio14";
function = "swr_tx_data";
};
@@ -3923,11 +3926,13 @@
"iface",
"bus";
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&mdss_dsi_phy 0>, <&mdss_dsi_phy 1>;
+
operating-points-v2 = <&dsi_opp_table>;
power-domains = <&rpmhpd SC7280_CX>;
phys = <&mdss_dsi_phy>;
- phy-names = "dsi";
#address-cells = <1>;
#size-cells = <0>;
@@ -4258,791 +4263,791 @@
gpio-ranges = <&tlmm 0 0 175>;
wakeup-parent = <&pdc>;
- dp_hot_plug_det: dp-hot-plug-det-pins {
+ dp_hot_plug_det: dp-hot-plug-det-state {
pins = "gpio47";
function = "dp_hot";
};
- edp_hot_plug_det: edp-hot-plug-det-pins {
+ edp_hot_plug_det: edp-hot-plug-det-state {
pins = "gpio60";
function = "edp_hot";
};
- mi2s0_data0: mi2s0-data0-pins {
+ mi2s0_data0: mi2s0-data0-state {
pins = "gpio98";
function = "mi2s0_data0";
};
- mi2s0_data1: mi2s0-data1-pins {
+ mi2s0_data1: mi2s0-data1-state {
pins = "gpio99";
function = "mi2s0_data1";
};
- mi2s0_mclk: mi2s0-mclk-pins {
+ mi2s0_mclk: mi2s0-mclk-state {
pins = "gpio96";
function = "pri_mi2s";
};
- mi2s0_sclk: mi2s0-sclk-pins {
+ mi2s0_sclk: mi2s0-sclk-state {
pins = "gpio97";
function = "mi2s0_sck";
};
- mi2s0_ws: mi2s0-ws-pins {
+ mi2s0_ws: mi2s0-ws-state {
pins = "gpio100";
function = "mi2s0_ws";
};
- mi2s1_data0: mi2s1-data0-pins {
+ mi2s1_data0: mi2s1-data0-state {
pins = "gpio107";
function = "mi2s1_data0";
};
- mi2s1_sclk: mi2s1-sclk-pins {
+ mi2s1_sclk: mi2s1-sclk-state {
pins = "gpio106";
function = "mi2s1_sck";
};
- mi2s1_ws: mi2s1-ws-pins {
+ mi2s1_ws: mi2s1-ws-state {
pins = "gpio108";
function = "mi2s1_ws";
};
- pcie1_clkreq_n: pcie1-clkreq-n-pins {
+ pcie1_clkreq_n: pcie1-clkreq-n-state {
pins = "gpio79";
function = "pcie1_clkreqn";
};
- qspi_clk: qspi-clk-pins {
+ qspi_clk: qspi-clk-state {
pins = "gpio14";
function = "qspi_clk";
};
- qspi_cs0: qspi-cs0-pins {
+ qspi_cs0: qspi-cs0-state {
pins = "gpio15";
function = "qspi_cs";
};
- qspi_cs1: qspi-cs1-pins {
+ qspi_cs1: qspi-cs1-state {
pins = "gpio19";
function = "qspi_cs";
};
- qspi_data01: qspi-data01-pins {
+ qspi_data01: qspi-data01-state {
pins = "gpio12", "gpio13";
function = "qspi_data";
};
- qspi_data12: qspi-data12-pins {
+ qspi_data12: qspi-data12-state {
pins = "gpio16", "gpio17";
function = "qspi_data";
};
- qup_i2c0_data_clk: qup-i2c0-data-clk-pins {
+ qup_i2c0_data_clk: qup-i2c0-data-clk-state {
pins = "gpio0", "gpio1";
function = "qup00";
};
- qup_i2c1_data_clk: qup-i2c1-data-clk-pins {
+ qup_i2c1_data_clk: qup-i2c1-data-clk-state {
pins = "gpio4", "gpio5";
function = "qup01";
};
- qup_i2c2_data_clk: qup-i2c2-data-clk-pins {
+ qup_i2c2_data_clk: qup-i2c2-data-clk-state {
pins = "gpio8", "gpio9";
function = "qup02";
};
- qup_i2c3_data_clk: qup-i2c3-data-clk-pins {
+ qup_i2c3_data_clk: qup-i2c3-data-clk-state {
pins = "gpio12", "gpio13";
function = "qup03";
};
- qup_i2c4_data_clk: qup-i2c4-data-clk-pins {
+ qup_i2c4_data_clk: qup-i2c4-data-clk-state {
pins = "gpio16", "gpio17";
function = "qup04";
};
- qup_i2c5_data_clk: qup-i2c5-data-clk-pins {
+ qup_i2c5_data_clk: qup-i2c5-data-clk-state {
pins = "gpio20", "gpio21";
function = "qup05";
};
- qup_i2c6_data_clk: qup-i2c6-data-clk-pins {
+ qup_i2c6_data_clk: qup-i2c6-data-clk-state {
pins = "gpio24", "gpio25";
function = "qup06";
};
- qup_i2c7_data_clk: qup-i2c7-data-clk-pins {
+ qup_i2c7_data_clk: qup-i2c7-data-clk-state {
pins = "gpio28", "gpio29";
function = "qup07";
};
- qup_i2c8_data_clk: qup-i2c8-data-clk-pins {
+ qup_i2c8_data_clk: qup-i2c8-data-clk-state {
pins = "gpio32", "gpio33";
function = "qup10";
};
- qup_i2c9_data_clk: qup-i2c9-data-clk-pins {
+ qup_i2c9_data_clk: qup-i2c9-data-clk-state {
pins = "gpio36", "gpio37";
function = "qup11";
};
- qup_i2c10_data_clk: qup-i2c10-data-clk-pins {
+ qup_i2c10_data_clk: qup-i2c10-data-clk-state {
pins = "gpio40", "gpio41";
function = "qup12";
};
- qup_i2c11_data_clk: qup-i2c11-data-clk-pins {
+ qup_i2c11_data_clk: qup-i2c11-data-clk-state {
pins = "gpio44", "gpio45";
function = "qup13";
};
- qup_i2c12_data_clk: qup-i2c12-data-clk-pins {
+ qup_i2c12_data_clk: qup-i2c12-data-clk-state {
pins = "gpio48", "gpio49";
function = "qup14";
};
- qup_i2c13_data_clk: qup-i2c13-data-clk-pins {
+ qup_i2c13_data_clk: qup-i2c13-data-clk-state {
pins = "gpio52", "gpio53";
function = "qup15";
};
- qup_i2c14_data_clk: qup-i2c14-data-clk-pins {
+ qup_i2c14_data_clk: qup-i2c14-data-clk-state {
pins = "gpio56", "gpio57";
function = "qup16";
};
- qup_i2c15_data_clk: qup-i2c15-data-clk-pins {
+ qup_i2c15_data_clk: qup-i2c15-data-clk-state {
pins = "gpio60", "gpio61";
function = "qup17";
};
- qup_spi0_data_clk: qup-spi0-data-clk-pins {
+ qup_spi0_data_clk: qup-spi0-data-clk-state {
pins = "gpio0", "gpio1", "gpio2";
function = "qup00";
};
- qup_spi0_cs: qup-spi0-cs-pins {
+ qup_spi0_cs: qup-spi0-cs-state {
pins = "gpio3";
function = "qup00";
};
- qup_spi0_cs_gpio: qup-spi0-cs-gpio-pins {
+ qup_spi0_cs_gpio: qup-spi0-cs-gpio-state {
pins = "gpio3";
function = "gpio";
};
- qup_spi1_data_clk: qup-spi1-data-clk-pins {
+ qup_spi1_data_clk: qup-spi1-data-clk-state {
pins = "gpio4", "gpio5", "gpio6";
function = "qup01";
};
- qup_spi1_cs: qup-spi1-cs-pins {
+ qup_spi1_cs: qup-spi1-cs-state {
pins = "gpio7";
function = "qup01";
};
- qup_spi1_cs_gpio: qup-spi1-cs-gpio-pins {
+ qup_spi1_cs_gpio: qup-spi1-cs-gpio-state {
pins = "gpio7";
function = "gpio";
};
- qup_spi2_data_clk: qup-spi2-data-clk-pins {
+ qup_spi2_data_clk: qup-spi2-data-clk-state {
pins = "gpio8", "gpio9", "gpio10";
function = "qup02";
};
- qup_spi2_cs: qup-spi2-cs-pins {
+ qup_spi2_cs: qup-spi2-cs-state {
pins = "gpio11";
function = "qup02";
};
- qup_spi2_cs_gpio: qup-spi2-cs-gpio-pins {
+ qup_spi2_cs_gpio: qup-spi2-cs-gpio-state {
pins = "gpio11";
function = "gpio";
};
- qup_spi3_data_clk: qup-spi3-data-clk-pins {
+ qup_spi3_data_clk: qup-spi3-data-clk-state {
pins = "gpio12", "gpio13", "gpio14";
function = "qup03";
};
- qup_spi3_cs: qup-spi3-cs-pins {
+ qup_spi3_cs: qup-spi3-cs-state {
pins = "gpio15";
function = "qup03";
};
- qup_spi3_cs_gpio: qup-spi3-cs-gpio-pins {
+ qup_spi3_cs_gpio: qup-spi3-cs-gpio-state {
pins = "gpio15";
function = "gpio";
};
- qup_spi4_data_clk: qup-spi4-data-clk-pins {
+ qup_spi4_data_clk: qup-spi4-data-clk-state {
pins = "gpio16", "gpio17", "gpio18";
function = "qup04";
};
- qup_spi4_cs: qup-spi4-cs-pins {
+ qup_spi4_cs: qup-spi4-cs-state {
pins = "gpio19";
function = "qup04";
};
- qup_spi4_cs_gpio: qup-spi4-cs-gpio-pins {
+ qup_spi4_cs_gpio: qup-spi4-cs-gpio-state {
pins = "gpio19";
function = "gpio";
};
- qup_spi5_data_clk: qup-spi5-data-clk-pins {
+ qup_spi5_data_clk: qup-spi5-data-clk-state {
pins = "gpio20", "gpio21", "gpio22";
function = "qup05";
};
- qup_spi5_cs: qup-spi5-cs-pins {
+ qup_spi5_cs: qup-spi5-cs-state {
pins = "gpio23";
function = "qup05";
};
- qup_spi5_cs_gpio: qup-spi5-cs-gpio-pins {
+ qup_spi5_cs_gpio: qup-spi5-cs-gpio-state {
pins = "gpio23";
function = "gpio";
};
- qup_spi6_data_clk: qup-spi6-data-clk-pins {
+ qup_spi6_data_clk: qup-spi6-data-clk-state {
pins = "gpio24", "gpio25", "gpio26";
function = "qup06";
};
- qup_spi6_cs: qup-spi6-cs-pins {
+ qup_spi6_cs: qup-spi6-cs-state {
pins = "gpio27";
function = "qup06";
};
- qup_spi6_cs_gpio: qup-spi6-cs-gpio-pins {
+ qup_spi6_cs_gpio: qup-spi6-cs-gpio-state {
pins = "gpio27";
function = "gpio";
};
- qup_spi7_data_clk: qup-spi7-data-clk-pins {
+ qup_spi7_data_clk: qup-spi7-data-clk-state {
pins = "gpio28", "gpio29", "gpio30";
function = "qup07";
};
- qup_spi7_cs: qup-spi7-cs-pins {
+ qup_spi7_cs: qup-spi7-cs-state {
pins = "gpio31";
function = "qup07";
};
- qup_spi7_cs_gpio: qup-spi7-cs-gpio-pins {
+ qup_spi7_cs_gpio: qup-spi7-cs-gpio-state {
pins = "gpio31";
function = "gpio";
};
- qup_spi8_data_clk: qup-spi8-data-clk-pins {
+ qup_spi8_data_clk: qup-spi8-data-clk-state {
pins = "gpio32", "gpio33", "gpio34";
function = "qup10";
};
- qup_spi8_cs: qup-spi8-cs-pins {
+ qup_spi8_cs: qup-spi8-cs-state {
pins = "gpio35";
function = "qup10";
};
- qup_spi8_cs_gpio: qup-spi8-cs-gpio-pins {
+ qup_spi8_cs_gpio: qup-spi8-cs-gpio-state {
pins = "gpio35";
function = "gpio";
};
- qup_spi9_data_clk: qup-spi9-data-clk-pins {
+ qup_spi9_data_clk: qup-spi9-data-clk-state {
pins = "gpio36", "gpio37", "gpio38";
function = "qup11";
};
- qup_spi9_cs: qup-spi9-cs-pins {
+ qup_spi9_cs: qup-spi9-cs-state {
pins = "gpio39";
function = "qup11";
};
- qup_spi9_cs_gpio: qup-spi9-cs-gpio-pins {
+ qup_spi9_cs_gpio: qup-spi9-cs-gpio-state {
pins = "gpio39";
function = "gpio";
};
- qup_spi10_data_clk: qup-spi10-data-clk-pins {
+ qup_spi10_data_clk: qup-spi10-data-clk-state {
pins = "gpio40", "gpio41", "gpio42";
function = "qup12";
};
- qup_spi10_cs: qup-spi10-cs-pins {
+ qup_spi10_cs: qup-spi10-cs-state {
pins = "gpio43";
function = "qup12";
};
- qup_spi10_cs_gpio: qup-spi10-cs-gpio-pins {
+ qup_spi10_cs_gpio: qup-spi10-cs-gpio-state {
pins = "gpio43";
function = "gpio";
};
- qup_spi11_data_clk: qup-spi11-data-clk-pins {
+ qup_spi11_data_clk: qup-spi11-data-clk-state {
pins = "gpio44", "gpio45", "gpio46";
function = "qup13";
};
- qup_spi11_cs: qup-spi11-cs-pins {
+ qup_spi11_cs: qup-spi11-cs-state {
pins = "gpio47";
function = "qup13";
};
- qup_spi11_cs_gpio: qup-spi11-cs-gpio-pins {
+ qup_spi11_cs_gpio: qup-spi11-cs-gpio-state {
pins = "gpio47";
function = "gpio";
};
- qup_spi12_data_clk: qup-spi12-data-clk-pins {
+ qup_spi12_data_clk: qup-spi12-data-clk-state {
pins = "gpio48", "gpio49", "gpio50";
function = "qup14";
};
- qup_spi12_cs: qup-spi12-cs-pins {
+ qup_spi12_cs: qup-spi12-cs-state {
pins = "gpio51";
function = "qup14";
};
- qup_spi12_cs_gpio: qup-spi12-cs-gpio-pins {
+ qup_spi12_cs_gpio: qup-spi12-cs-gpio-state {
pins = "gpio51";
function = "gpio";
};
- qup_spi13_data_clk: qup-spi13-data-clk-pins {
+ qup_spi13_data_clk: qup-spi13-data-clk-state {
pins = "gpio52", "gpio53", "gpio54";
function = "qup15";
};
- qup_spi13_cs: qup-spi13-cs-pins {
+ qup_spi13_cs: qup-spi13-cs-state {
pins = "gpio55";
function = "qup15";
};
- qup_spi13_cs_gpio: qup-spi13-cs-gpio-pins {
+ qup_spi13_cs_gpio: qup-spi13-cs-gpio-state {
pins = "gpio55";
function = "gpio";
};
- qup_spi14_data_clk: qup-spi14-data-clk-pins {
+ qup_spi14_data_clk: qup-spi14-data-clk-state {
pins = "gpio56", "gpio57", "gpio58";
function = "qup16";
};
- qup_spi14_cs: qup-spi14-cs-pins {
+ qup_spi14_cs: qup-spi14-cs-state {
pins = "gpio59";
function = "qup16";
};
- qup_spi14_cs_gpio: qup-spi14-cs-gpio-pins {
+ qup_spi14_cs_gpio: qup-spi14-cs-gpio-state {
pins = "gpio59";
function = "gpio";
};
- qup_spi15_data_clk: qup-spi15-data-clk-pins {
+ qup_spi15_data_clk: qup-spi15-data-clk-state {
pins = "gpio60", "gpio61", "gpio62";
function = "qup17";
};
- qup_spi15_cs: qup-spi15-cs-pins {
+ qup_spi15_cs: qup-spi15-cs-state {
pins = "gpio63";
function = "qup17";
};
- qup_spi15_cs_gpio: qup-spi15-cs-gpio-pins {
+ qup_spi15_cs_gpio: qup-spi15-cs-gpio-state {
pins = "gpio63";
function = "gpio";
};
- qup_uart0_cts: qup-uart0-cts-pins {
+ qup_uart0_cts: qup-uart0-cts-state {
pins = "gpio0";
function = "qup00";
};
- qup_uart0_rts: qup-uart0-rts-pins {
+ qup_uart0_rts: qup-uart0-rts-state {
pins = "gpio1";
function = "qup00";
};
- qup_uart0_tx: qup-uart0-tx-pins {
+ qup_uart0_tx: qup-uart0-tx-state {
pins = "gpio2";
function = "qup00";
};
- qup_uart0_rx: qup-uart0-rx-pins {
+ qup_uart0_rx: qup-uart0-rx-state {
pins = "gpio3";
function = "qup00";
};
- qup_uart1_cts: qup-uart1-cts-pins {
+ qup_uart1_cts: qup-uart1-cts-state {
pins = "gpio4";
function = "qup01";
};
- qup_uart1_rts: qup-uart1-rts-pins {
+ qup_uart1_rts: qup-uart1-rts-state {
pins = "gpio5";
function = "qup01";
};
- qup_uart1_tx: qup-uart1-tx-pins {
+ qup_uart1_tx: qup-uart1-tx-state {
pins = "gpio6";
function = "qup01";
};
- qup_uart1_rx: qup-uart1-rx-pins {
+ qup_uart1_rx: qup-uart1-rx-state {
pins = "gpio7";
function = "qup01";
};
- qup_uart2_cts: qup-uart2-cts-pins {
+ qup_uart2_cts: qup-uart2-cts-state {
pins = "gpio8";
function = "qup02";
};
- qup_uart2_rts: qup-uart2-rts-pins {
+ qup_uart2_rts: qup-uart2-rts-state {
pins = "gpio9";
function = "qup02";
};
- qup_uart2_tx: qup-uart2-tx-pins {
+ qup_uart2_tx: qup-uart2-tx-state {
pins = "gpio10";
function = "qup02";
};
- qup_uart2_rx: qup-uart2-rx-pins {
+ qup_uart2_rx: qup-uart2-rx-state {
pins = "gpio11";
function = "qup02";
};
- qup_uart3_cts: qup-uart3-cts-pins {
+ qup_uart3_cts: qup-uart3-cts-state {
pins = "gpio12";
function = "qup03";
};
- qup_uart3_rts: qup-uart3-rts-pins {
+ qup_uart3_rts: qup-uart3-rts-state {
pins = "gpio13";
function = "qup03";
};
- qup_uart3_tx: qup-uart3-tx-pins {
+ qup_uart3_tx: qup-uart3-tx-state {
pins = "gpio14";
function = "qup03";
};
- qup_uart3_rx: qup-uart3-rx-pins {
+ qup_uart3_rx: qup-uart3-rx-state {
pins = "gpio15";
function = "qup03";
};
- qup_uart4_cts: qup-uart4-cts-pins {
+ qup_uart4_cts: qup-uart4-cts-state {
pins = "gpio16";
function = "qup04";
};
- qup_uart4_rts: qup-uart4-rts-pins {
+ qup_uart4_rts: qup-uart4-rts-state {
pins = "gpio17";
function = "qup04";
};
- qup_uart4_tx: qup-uart4-tx-pins {
+ qup_uart4_tx: qup-uart4-tx-state {
pins = "gpio18";
function = "qup04";
};
- qup_uart4_rx: qup-uart4-rx-pins {
+ qup_uart4_rx: qup-uart4-rx-state {
pins = "gpio19";
function = "qup04";
};
- qup_uart5_cts: qup-uart5-cts-pins {
+ qup_uart5_cts: qup-uart5-cts-state {
pins = "gpio20";
function = "qup05";
};
- qup_uart5_rts: qup-uart5-rts-pins {
+ qup_uart5_rts: qup-uart5-rts-state {
pins = "gpio21";
function = "qup05";
};
- qup_uart5_tx: qup-uart5-tx-pins {
+ qup_uart5_tx: qup-uart5-tx-state {
pins = "gpio22";
function = "qup05";
};
- qup_uart5_rx: qup-uart5-rx-pins {
+ qup_uart5_rx: qup-uart5-rx-state {
pins = "gpio23";
function = "qup05";
};
- qup_uart6_cts: qup-uart6-cts-pins {
+ qup_uart6_cts: qup-uart6-cts-state {
pins = "gpio24";
function = "qup06";
};
- qup_uart6_rts: qup-uart6-rts-pins {
+ qup_uart6_rts: qup-uart6-rts-state {
pins = "gpio25";
function = "qup06";
};
- qup_uart6_tx: qup-uart6-tx-pins {
+ qup_uart6_tx: qup-uart6-tx-state {
pins = "gpio26";
function = "qup06";
};
- qup_uart6_rx: qup-uart6-rx-pins {
+ qup_uart6_rx: qup-uart6-rx-state {
pins = "gpio27";
function = "qup06";
};
- qup_uart7_cts: qup-uart7-cts-pins {
+ qup_uart7_cts: qup-uart7-cts-state {
pins = "gpio28";
function = "qup07";
};
- qup_uart7_rts: qup-uart7-rts-pins {
+ qup_uart7_rts: qup-uart7-rts-state {
pins = "gpio29";
function = "qup07";
};
- qup_uart7_tx: qup-uart7-tx-pins {
+ qup_uart7_tx: qup-uart7-tx-state {
pins = "gpio30";
function = "qup07";
};
- qup_uart7_rx: qup-uart7-rx-pins {
+ qup_uart7_rx: qup-uart7-rx-state {
pins = "gpio31";
function = "qup07";
};
- qup_uart8_cts: qup-uart8-cts-pins {
+ qup_uart8_cts: qup-uart8-cts-state {
pins = "gpio32";
function = "qup10";
};
- qup_uart8_rts: qup-uart8-rts-pins {
+ qup_uart8_rts: qup-uart8-rts-state {
pins = "gpio33";
function = "qup10";
};
- qup_uart8_tx: qup-uart8-tx-pins {
+ qup_uart8_tx: qup-uart8-tx-state {
pins = "gpio34";
function = "qup10";
};
- qup_uart8_rx: qup-uart8-rx-pins {
+ qup_uart8_rx: qup-uart8-rx-state {
pins = "gpio35";
function = "qup10";
};
- qup_uart9_cts: qup-uart9-cts-pins {
+ qup_uart9_cts: qup-uart9-cts-state {
pins = "gpio36";
function = "qup11";
};
- qup_uart9_rts: qup-uart9-rts-pins {
+ qup_uart9_rts: qup-uart9-rts-state {
pins = "gpio37";
function = "qup11";
};
- qup_uart9_tx: qup-uart9-tx-pins {
+ qup_uart9_tx: qup-uart9-tx-state {
pins = "gpio38";
function = "qup11";
};
- qup_uart9_rx: qup-uart9-rx-pins {
+ qup_uart9_rx: qup-uart9-rx-state {
pins = "gpio39";
function = "qup11";
};
- qup_uart10_cts: qup-uart10-cts-pins {
+ qup_uart10_cts: qup-uart10-cts-state {
pins = "gpio40";
function = "qup12";
};
- qup_uart10_rts: qup-uart10-rts-pins {
+ qup_uart10_rts: qup-uart10-rts-state {
pins = "gpio41";
function = "qup12";
};
- qup_uart10_tx: qup-uart10-tx-pins {
+ qup_uart10_tx: qup-uart10-tx-state {
pins = "gpio42";
function = "qup12";
};
- qup_uart10_rx: qup-uart10-rx-pins {
+ qup_uart10_rx: qup-uart10-rx-state {
pins = "gpio43";
function = "qup12";
};
- qup_uart11_cts: qup-uart11-cts-pins {
+ qup_uart11_cts: qup-uart11-cts-state {
pins = "gpio44";
function = "qup13";
};
- qup_uart11_rts: qup-uart11-rts-pins {
+ qup_uart11_rts: qup-uart11-rts-state {
pins = "gpio45";
function = "qup13";
};
- qup_uart11_tx: qup-uart11-tx-pins {
+ qup_uart11_tx: qup-uart11-tx-state {
pins = "gpio46";
function = "qup13";
};
- qup_uart11_rx: qup-uart11-rx-pins {
+ qup_uart11_rx: qup-uart11-rx-state {
pins = "gpio47";
function = "qup13";
};
- qup_uart12_cts: qup-uart12-cts-pins {
+ qup_uart12_cts: qup-uart12-cts-state {
pins = "gpio48";
function = "qup14";
};
- qup_uart12_rts: qup-uart12-rts-pins {
+ qup_uart12_rts: qup-uart12-rts-state {
pins = "gpio49";
function = "qup14";
};
- qup_uart12_tx: qup-uart12-tx-pins {
+ qup_uart12_tx: qup-uart12-tx-state {
pins = "gpio50";
function = "qup14";
};
- qup_uart12_rx: qup-uart12-rx-pins {
+ qup_uart12_rx: qup-uart12-rx-state {
pins = "gpio51";
function = "qup14";
};
- qup_uart13_cts: qup-uart13-cts-pins {
+ qup_uart13_cts: qup-uart13-cts-state {
pins = "gpio52";
function = "qup15";
};
- qup_uart13_rts: qup-uart13-rts-pins {
+ qup_uart13_rts: qup-uart13-rts-state {
pins = "gpio53";
function = "qup15";
};
- qup_uart13_tx: qup-uart13-tx-pins {
+ qup_uart13_tx: qup-uart13-tx-state {
pins = "gpio54";
function = "qup15";
};
- qup_uart13_rx: qup-uart13-rx-pins {
+ qup_uart13_rx: qup-uart13-rx-state {
pins = "gpio55";
function = "qup15";
};
- qup_uart14_cts: qup-uart14-cts-pins {
+ qup_uart14_cts: qup-uart14-cts-state {
pins = "gpio56";
function = "qup16";
};
- qup_uart14_rts: qup-uart14-rts-pins {
+ qup_uart14_rts: qup-uart14-rts-state {
pins = "gpio57";
function = "qup16";
};
- qup_uart14_tx: qup-uart14-tx-pins {
+ qup_uart14_tx: qup-uart14-tx-state {
pins = "gpio58";
function = "qup16";
};
- qup_uart14_rx: qup-uart14-rx-pins {
+ qup_uart14_rx: qup-uart14-rx-state {
pins = "gpio59";
function = "qup16";
};
- qup_uart15_cts: qup-uart15-cts-pins {
+ qup_uart15_cts: qup-uart15-cts-state {
pins = "gpio60";
function = "qup17";
};
- qup_uart15_rts: qup-uart15-rts-pins {
+ qup_uart15_rts: qup-uart15-rts-state {
pins = "gpio61";
function = "qup17";
};
- qup_uart15_tx: qup-uart15-tx-pins {
+ qup_uart15_tx: qup-uart15-tx-state {
pins = "gpio62";
function = "qup17";
};
- qup_uart15_rx: qup-uart15-rx-pins {
+ qup_uart15_rx: qup-uart15-rx-state {
pins = "gpio63";
function = "qup17";
};
- sdc1_clk: sdc1-clk-pins {
+ sdc1_clk: sdc1-clk-state {
pins = "sdc1_clk";
};
- sdc1_cmd: sdc1-cmd-pins {
+ sdc1_cmd: sdc1-cmd-state {
pins = "sdc1_cmd";
};
- sdc1_data: sdc1-data-pins {
+ sdc1_data: sdc1-data-state {
pins = "sdc1_data";
};
- sdc1_rclk: sdc1-rclk-pins {
+ sdc1_rclk: sdc1-rclk-state {
pins = "sdc1_rclk";
};
- sdc1_clk_sleep: sdc1-clk-sleep-pins {
+ sdc1_clk_sleep: sdc1-clk-sleep-state {
pins = "sdc1_clk";
drive-strength = <2>;
bias-bus-hold;
};
- sdc1_cmd_sleep: sdc1-cmd-sleep-pins {
+ sdc1_cmd_sleep: sdc1-cmd-sleep-state {
pins = "sdc1_cmd";
drive-strength = <2>;
bias-bus-hold;
};
- sdc1_data_sleep: sdc1-data-sleep-pins {
+ sdc1_data_sleep: sdc1-data-sleep-state {
pins = "sdc1_data";
drive-strength = <2>;
bias-bus-hold;
};
- sdc1_rclk_sleep: sdc1-rclk-sleep-pins {
+ sdc1_rclk_sleep: sdc1-rclk-sleep-state {
pins = "sdc1_rclk";
drive-strength = <2>;
bias-bus-hold;
};
- sdc2_clk: sdc2-clk-pins {
+ sdc2_clk: sdc2-clk-state {
pins = "sdc2_clk";
};
- sdc2_cmd: sdc2-cmd-pins {
+ sdc2_cmd: sdc2-cmd-state {
pins = "sdc2_cmd";
};
- sdc2_data: sdc2-data-pins {
+ sdc2_data: sdc2-data-state {
pins = "sdc2_data";
};
- sdc2_clk_sleep: sdc2-clk-sleep-pins {
+ sdc2_clk_sleep: sdc2-clk-sleep-state {
pins = "sdc2_clk";
drive-strength = <2>;
bias-bus-hold;
};
- sdc2_cmd_sleep: sdc2-cmd-sleep-pins {
+ sdc2_cmd_sleep: sdc2-cmd-sleep-state {
pins = "sdc2_cmd";
drive-strength = <2>;
bias-bus-hold;
};
- sdc2_data_sleep: sdc2-data-sleep-pins {
+ sdc2_data_sleep: sdc2-data-sleep-state {
pins = "sdc2_data";
drive-strength = <2>;
bias-bus-hold;
@@ -5313,7 +5318,7 @@
};
epss_l3: interconnect@18590000 {
- compatible = "qcom,sc7280-epss-l3";
+ compatible = "qcom,sc7280-epss-l3", "qcom,epss-l3";
reg = <0 0x18590000 0 0x1000>;
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>;
clock-names = "xo", "alternate";
@@ -5321,7 +5326,7 @@
};
cpufreq_hw: cpufreq@18591000 {
- compatible = "qcom,cpufreq-epss";
+ compatible = "qcom,sc7280-cpufreq-epss", "qcom,cpufreq-epss";
reg = <0 0x18591000 0 0x1000>,
<0 0x18592000 0 0x1000>,
<0 0x18593000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
index fea7d8273ccd..551768f97729 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
@@ -37,7 +37,7 @@
vreg_edp_bl: regulator-edp-bl {
compatible = "regulator-fixed";
- regulator-name = "VREG_EDP_BL";
+ regulator-name = "VBL9";
regulator-min-microvolt = <3600000>;
regulator-max-microvolt = <3600000>;
@@ -50,10 +50,24 @@
regulator-boot-on;
};
+ vreg_nvme: regulator-nvme {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC3_SSD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 135 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&nvme_reg_en>;
+ };
+
vreg_misc_3p3: regulator-misc-3p3 {
compatible = "regulator-fixed";
- regulator-name = "VREG_MISC_3P3";
+ regulator-name = "VCC3B";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
@@ -66,6 +80,38 @@
regulator-boot-on;
regulator-always-on;
};
+
+ vreg_wlan: regulator-wlan {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC_WLAN_3R9";
+ regulator-min-microvolt = <3900000>;
+ regulator-max-microvolt = <3900000>;
+
+ gpio = <&pmr735a_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hastings_reg_en>;
+
+ regulator-boot-on;
+ };
+
+ vreg_wwan: regulator-wwan {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC3B_WAN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&pmc8280_2_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wwan_sw_en>;
+
+ regulator-boot-on;
+ };
};
&apps_rsc {
@@ -124,6 +170,8 @@
regulator-max-microvolt = <2504000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l13c: ldo13 {
@@ -146,6 +194,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l4d: ldo4 {
@@ -178,6 +228,63 @@
};
};
+&pcie2a {
+ perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_nvme>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie2a_default>;
+
+ status = "okay";
+};
+
+&pcie2a_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
+&pcie3a {
+ perst-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_wwan>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie3a_default>;
+
+ status = "okay";
+};
+
+&pcie3a_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
+&pcie4 {
+ perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_wlan>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie4_default>;
+
+ status = "okay";
+};
+
+&pcie4_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
&pmc8280c_lpg {
status = "okay";
};
@@ -363,6 +470,13 @@
};
};
+&pmc8280_2_gpios {
+ wwan_sw_en: wwan-sw-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
+
&pmc8280c_gpios {
edp_bl_pwm: edp-bl-pwm-state {
pins = "gpio8";
@@ -370,29 +484,112 @@
};
};
+&pmr735a_gpios {
+ hastings_reg_en: hastings-reg-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
+
&tlmm {
gpio-reserved-ranges = <74 6>, <83 4>, <125 2>, <128 2>, <154 7>;
kybd_default: kybd-default-state {
- disable {
+ disable-pins {
pins = "gpio102";
function = "gpio";
output-low;
};
- int-n {
+ int-n-pins {
pins = "gpio104";
function = "gpio";
bias-disable;
};
- reset {
+ reset-pins {
pins = "gpio105";
function = "gpio";
bias-disable;
};
};
+ nvme_reg_en: nvme-reg-en-state {
+ pins = "gpio135";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ pcie2a_default: pcie2a-default-state {
+ clkreq-n-pins {
+ pins = "gpio142";
+ function = "pcie2a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio143";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio145";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie3a_default: pcie3a-default-state {
+ clkreq-n-pins {
+ pins = "gpio150";
+ function = "pcie3a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio151";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio148";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie4_default: pcie4-default-state {
+ clkreq-n-pins {
+ pins = "gpio140";
+ function = "pcie4_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio141";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio139";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
qup0_i2c4_default: qup0-i2c4-default-state {
pins = "gpio171", "gpio172";
function = "qup4";
@@ -410,7 +607,7 @@
};
tpad_default: tpad-default-state {
- int-n {
+ int-n-pins {
pins = "gpio182";
function = "gpio";
bias-disable;
@@ -418,13 +615,13 @@
};
ts0_default: ts0-default-state {
- int-n {
+ int-n-pins {
pins = "gpio175";
function = "gpio";
bias-disable;
};
- reset-n {
+ reset-n-pins {
pins = "gpio99";
function = "gpio";
output-high;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
index b2b744bb8a53..568c6be1ceaa 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
@@ -7,6 +7,11 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pmr735a.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include "sc8280xp.dtsi"
@@ -26,6 +31,67 @@
pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>;
};
+ thermal-zones {
+ skin-temp-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmk8280_adc_tm 5>;
+
+ trips {
+ skin_temp_alert0: trip-point0 {
+ temperature = <55000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+
+ skin_temp_alert1: trip-point1 {
+ temperature = <58000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+
+ skin-temp-crit {
+ temperature = <73000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&skin_temp_alert0>;
+ cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+
+ map1 {
+ trip = <&skin_temp_alert1>;
+ cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hall_int_n_default>;
+
+ switch-lid {
+ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ wakeup-source;
+ wakeup-event-action = <EV_ACT_DEASSERTED>;
+ };
+ };
+
vreg_edp_bl: regulator-edp-bl {
compatible = "regulator-fixed";
@@ -58,6 +124,54 @@
regulator-boot-on;
regulator-always-on;
};
+
+ vreg_nvme: regulator-nvme {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC3_SSD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 135 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&nvme_reg_en>;
+
+ regulator-boot-on;
+ };
+
+ vreg_wlan: regulator-wlan {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC_WLAN_3R9";
+ regulator-min-microvolt = <3900000>;
+ regulator-max-microvolt = <3900000>;
+
+ gpio = <&pmr735a_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hastings_reg_en>;
+
+ regulator-boot-on;
+ };
+
+ vreg_wwan: regulator-wwan {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VCC3B_WAN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&pmc8280_2_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wwan_sw_en>;
+
+ regulator-boot-on;
+ };
};
&apps_rsc {
@@ -95,7 +209,7 @@
regulator-max-microvolt = <880000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-boot-on;
- regulator-always-on; // FIXME: VDD_A_EDP_0_0P9
+ regulator-always-on; /* FIXME: VDD_A_EDP_0_0P9 */
};
};
@@ -145,6 +259,13 @@
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
};
+ vreg_l6d: ldo6 {
+ regulator-name = "vreg_l6d";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
vreg_l7d: ldo7 {
regulator-name = "vreg_l7d";
regulator-min-microvolt = <3072000>;
@@ -161,14 +282,221 @@
};
};
+&pcie2a {
+ perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_nvme>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie2a_default>;
+
+ status = "okay";
+};
+
+&pcie2a_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
+&pcie3a {
+ perst-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_wwan>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie3a_default>;
+
+ status = "okay";
+};
+
+&pcie3a_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
+&pcie4 {
+ perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>;
+
+ vddpe-3v3-supply = <&vreg_wlan>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie4_default>;
+
+ status = "okay";
+};
+
+&pcie4_phy {
+ vdda-phy-supply = <&vreg_l6d>;
+ vdda-pll-supply = <&vreg_l4d>;
+
+ status = "okay";
+};
+
&pmc8280c_lpg {
status = "okay";
};
+&pmk8280_adc_tm {
+ status = "okay";
+
+ sys-therm@0 {
+ reg = <0>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM1_100K_PU(1)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@1 {
+ reg = <1>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM2_100K_PU(1)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@2 {
+ reg = <2>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM3_100K_PU(1)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@3 {
+ reg = <3>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@4 {
+ reg = <4>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM1_100K_PU(3)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@5 {
+ reg = <5>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM2_100K_PU(3)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@6 {
+ reg = <6>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM3_100K_PU(3)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@7 {
+ reg = <7>;
+ io-channels = <&pmk8280_vadc PM8350_ADC7_AMUX_THM4_100K_PU(3)>;
+ qcom,hw-settle-time-us = <200>;
+ qcom,avg-samples = <2>;
+ qcom,ratiometric;
+ };
+};
+
&pmk8280_pon_pwrkey {
status = "okay";
};
+&pmk8280_pon_resin {
+ status = "okay";
+};
+
+&pmk8280_vadc {
+ status = "okay";
+
+ pmic-die-temp@3 {
+ reg = <PMK8350_ADC7_DIE_TEMP>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ xo-therm@44 {
+ reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ pmic-die-temp@103 {
+ reg = <PM8350_ADC7_DIE_TEMP(1)>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ sys-therm@144 {
+ reg = <PM8350_ADC7_AMUX_THM1_100K_PU(1)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@145 {
+ reg = <PM8350_ADC7_AMUX_THM2_100K_PU(1)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@146 {
+ reg = <PM8350_ADC7_AMUX_THM3_100K_PU(1)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@147 {
+ reg = <PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ pmic-die-temp@303 {
+ reg = <PM8350_ADC7_DIE_TEMP(3)>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ sys-therm@344 {
+ reg = <PM8350_ADC7_AMUX_THM1_100K_PU(3)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@345 {
+ reg = <PM8350_ADC7_AMUX_THM2_100K_PU(3)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@346 {
+ reg = <PM8350_ADC7_AMUX_THM3_100K_PU(3)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ sys-therm@347 {
+ reg = <PM8350_ADC7_AMUX_THM4_100K_PU(3)>;
+ qcom,hw-settle-time = <200>;
+ qcom,ratiometric;
+ };
+
+ pmic-die-temp@403 {
+ reg = <PMR735A_ADC7_DIE_TEMP>;
+ qcom,pre-scaling = <1 1>;
+ };
+};
+
&qup0 {
status = "okay";
};
@@ -339,6 +667,13 @@
};
};
+&pmc8280_2_gpios {
+ wwan_sw_en: wwan-sw-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
+
&pmc8280c_gpios {
edp_bl_pwm: edp-bl-pwm-state {
pins = "gpio8";
@@ -346,29 +681,119 @@
};
};
+&pmr735a_gpios {
+ hastings_reg_en: hastings-reg-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
+
&tlmm {
gpio-reserved-ranges = <70 2>, <74 6>, <83 4>, <125 2>, <128 2>, <154 7>;
+ hall_int_n_default: hall-int-n-state {
+ pins = "gpio107";
+ function = "gpio";
+ input-enable;
+ bias-disable;
+ };
+
kybd_default: kybd-default-state {
- disable {
+ disable-pins {
pins = "gpio102";
function = "gpio";
output-low;
};
- int-n {
+ int-n-pins {
pins = "gpio104";
function = "gpio";
bias-disable;
};
- reset {
+ reset-pins {
pins = "gpio105";
function = "gpio";
bias-disable;
};
};
+ nvme_reg_en: nvme-reg-en-state {
+ pins = "gpio135";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ pcie2a_default: pcie2a-default-state {
+ clkreq-n-pins {
+ pins = "gpio142";
+ function = "pcie2a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio143";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio145";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie3a_default: pcie3a-default-state {
+ clkreq-n-pins {
+ pins = "gpio150";
+ function = "pcie3a_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio151";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio148";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie4_default: pcie4-default-state {
+ clkreq-n-pins {
+ pins = "gpio140";
+ function = "pcie4_clkreq";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio141";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ wake-n-pins {
+ pins = "gpio139";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
qup0_i2c4_default: qup0-i2c4-default-state {
pins = "gpio171", "gpio172";
function = "qup4";
@@ -384,7 +809,7 @@
};
tpad_default: tpad-default-state {
- int-n {
+ int-n-pins {
pins = "gpio182";
function = "gpio";
bias-disable;
@@ -392,13 +817,13 @@
};
ts0_default: ts0-default-state {
- int-n {
+ int-n-pins {
pins = "gpio175";
function = "gpio";
bias-disable;
};
- reset-n {
+ reset-n-pins {
pins = "gpio99";
function = "gpio";
output-high;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi
index 24836b6b9bbc..f2c0b71b5d8e 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi
@@ -7,6 +7,50 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
+/ {
+ thermal-zones {
+ pm8280_1_thermal: pm8280-1-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8280_1_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+
+ pm8280_2_thermal: pm8280-2-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8280_2_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
&spmi_bus {
pmk8280: pmic@0 {
compatible = "qcom,pmk8350", "qcom,spmi-pmic";
@@ -24,6 +68,32 @@
linux,code = <KEY_POWER>;
status = "disabled";
};
+
+ pmk8280_pon_resin: resin {
+ compatible = "qcom,pmk8350-resin";
+ interrupts = <0x0 0x13 0x6 IRQ_TYPE_EDGE_BOTH>;
+ status = "disabled";
+ };
+ };
+
+ pmk8280_vadc: adc@3100 {
+ compatible = "qcom,spmi-adc7";
+ reg = <0x3100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ status = "disabled";
+ };
+
+ pmk8280_adc_tm: adc-tm@3400 {
+ compatible = "qcom,spmi-adc-tm5-gen2";
+ reg = <0x3400>;
+ interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #thermal-sensor-cells = <1>;
+ status = "disabled";
};
};
@@ -33,6 +103,13 @@
#address-cells = <1>;
#size-cells = <0>;
+ pm8280_1_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
pmc8280_1_gpios: gpio@8800 {
compatible = "qcom,pm8350-gpio", "qcom,spmi-gpio";
reg = <0x8800>;
@@ -78,6 +155,13 @@
#address-cells = <1>;
#size-cells = <0>;
+ pm8280_2_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0x2 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
pmc8280_2_gpios: gpio@8800 {
compatible = "qcom,pm8350-gpio", "qcom,spmi-gpio";
reg = <0x8800>;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
index c32bcded2aef..109c9d2b684d 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
@@ -6,6 +6,7 @@
#include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interconnect/qcom,osm-l3.h>
#include <dt-bindings/interconnect/qcom,sc8280xp.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/qcom-ipcc.h>
@@ -38,66 +39,87 @@
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
+ opp-peak-kBps = <(300000 * 32)>;
};
opp-403200000 {
opp-hz = /bits/ 64 <403200000>;
+ opp-peak-kBps = <(384000 * 32)>;
};
opp-499200000 {
opp-hz = /bits/ 64 <499200000>;
+ opp-peak-kBps = <(480000 * 32)>;
};
opp-595200000 {
opp-hz = /bits/ 64 <595200000>;
+ opp-peak-kBps = <(576000 * 32)>;
};
opp-691200000 {
opp-hz = /bits/ 64 <691200000>;
+ opp-peak-kBps = <(672000 * 32)>;
};
opp-806400000 {
opp-hz = /bits/ 64 <806400000>;
+ opp-peak-kBps = <(768000 * 32)>;
};
opp-902400000 {
opp-hz = /bits/ 64 <902400000>;
+ opp-peak-kBps = <(864000 * 32)>;
};
opp-1017600000 {
opp-hz = /bits/ 64 <1017600000>;
+ opp-peak-kBps = <(960000 * 32)>;
};
opp-1113600000 {
opp-hz = /bits/ 64 <1113600000>;
+ opp-peak-kBps = <(1075200 * 32)>;
};
opp-1209600000 {
opp-hz = /bits/ 64 <1209600000>;
+ opp-peak-kBps = <(1171200 * 32)>;
};
opp-1324800000 {
opp-hz = /bits/ 64 <1324800000>;
+ opp-peak-kBps = <(1267200 * 32)>;
};
opp-1440000000 {
opp-hz = /bits/ 64 <1440000000>;
+ opp-peak-kBps = <(1363200 * 32)>;
};
opp-1555200000 {
opp-hz = /bits/ 64 <1555200000>;
+ opp-peak-kBps = <(1536000 * 32)>;
};
opp-1670400000 {
opp-hz = /bits/ 64 <1670400000>;
+ opp-peak-kBps = <(1612800 * 32)>;
};
opp-1785600000 {
opp-hz = /bits/ 64 <1785600000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-1881600000 {
opp-hz = /bits/ 64 <1881600000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-1996800000 {
opp-hz = /bits/ 64 <1996800000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2112000000 {
opp-hz = /bits/ 64 <2112000000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2227200000 {
opp-hz = /bits/ 64 <2227200000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2342400000 {
opp-hz = /bits/ 64 <2342400000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2438400000 {
opp-hz = /bits/ 64 <2438400000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
};
@@ -107,66 +129,87 @@
opp-825600000 {
opp-hz = /bits/ 64 <825600000>;
+ opp-peak-kBps = <(768000 * 32)>;
};
opp-940800000 {
opp-hz = /bits/ 64 <940800000>;
+ opp-peak-kBps = <(864000 * 32)>;
};
opp-1056000000 {
opp-hz = /bits/ 64 <1056000000>;
+ opp-peak-kBps = <(960000 * 32)>;
};
opp-1171200000 {
opp-hz = /bits/ 64 <1171200000>;
+ opp-peak-kBps = <(1171200 * 32)>;
};
opp-1286400000 {
opp-hz = /bits/ 64 <1286400000>;
+ opp-peak-kBps = <(1267200 * 32)>;
};
opp-1401600000 {
opp-hz = /bits/ 64 <1401600000>;
+ opp-peak-kBps = <(1363200 * 32)>;
};
opp-1516800000 {
opp-hz = /bits/ 64 <1516800000>;
+ opp-peak-kBps = <(1459200 * 32)>;
};
opp-1632000000 {
opp-hz = /bits/ 64 <1632000000>;
+ opp-peak-kBps = <(1612800 * 32)>;
};
opp-1747200000 {
opp-hz = /bits/ 64 <1747200000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-1862400000 {
opp-hz = /bits/ 64 <1862400000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-1977600000 {
opp-hz = /bits/ 64 <1977600000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2073600000 {
opp-hz = /bits/ 64 <2073600000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2169600000 {
opp-hz = /bits/ 64 <2169600000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2284800000 {
opp-hz = /bits/ 64 <2284800000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2400000000 {
opp-hz = /bits/ 64 <2400000000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2496000000 {
opp-hz = /bits/ 64 <2496000000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2592000000 {
opp-hz = /bits/ 64 <2592000000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2688000000 {
opp-hz = /bits/ 64 <2688000000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2803200000 {
opp-hz = /bits/ 64 <2803200000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2899200000 {
opp-hz = /bits/ 64 <2899200000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
opp-2995200000 {
opp-hz = /bits/ 64 <2995200000>;
+ opp-peak-kBps = <(1689600 * 32)>;
};
};
@@ -185,6 +228,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_0: l2-cache {
compatible = "cache";
@@ -206,6 +250,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_100: l2-cache {
compatible = "cache";
@@ -224,6 +269,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_200: l2-cache {
compatible = "cache";
@@ -242,6 +288,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_300: l2-cache {
compatible = "cache";
@@ -260,6 +307,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
operating-points-v2 = <&cpu4_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_400: l2-cache {
compatible = "cache";
@@ -278,6 +326,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
operating-points-v2 = <&cpu4_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_500: l2-cache {
compatible = "cache";
@@ -296,6 +345,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
operating-points-v2 = <&cpu4_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_600: l2-cache {
compatible = "cache";
@@ -314,6 +364,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
operating-points-v2 = <&cpu4_opp_table>;
+ interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
#cooling-cells = <2>;
L2_700: l2-cache {
compatible = "cache";
@@ -729,11 +780,11 @@
<0>,
<0>,
<0>,
- <0>,
- <0>,
- <0>,
- <0>,
- <0>,
+ <&pcie2a_phy>,
+ <&pcie2b_phy>,
+ <&pcie3a_phy>,
+ <&pcie3b_phy>,
+ <&pcie4_phy>,
<0>,
<0>;
power-domains = <&rpmhpd SC8280XP_CX>;
@@ -839,12 +890,505 @@
status = "disabled";
};
+ pcie4: pcie@1c00000 {
+ device_type = "pci";
+ compatible = "qcom,pcie-sc8280xp";
+ reg = <0x0 0x01c00000 0x0 0x3000>,
+ <0x0 0x30000000 0x0 0xf1d>,
+ <0x0 0x30000f20 0x0 0xa8>,
+ <0x0 0x30001000 0x0 0x1000>,
+ <0x0 0x30100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x30200000 0x0 0x30200000 0x0 0x100000>,
+ <0x02000000 0x0 0x30300000 0x0 0x30300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
+
+ dma-coherent;
+
+ linux,pci-domain = <6>;
+ num-lanes = <1>;
+
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi0", "msi1", "msi2", "msi3";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
+ <&gcc GCC_PCIE_4_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_4_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_4_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_4_SLV_Q2A_AXI_CLK>,
+ <&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>,
+ <&gcc GCC_CNOC_PCIE4_QX_CLK>;
+ clock-names = "aux",
+ "cfg",
+ "bus_master",
+ "bus_slave",
+ "slave_q2a",
+ "ddrss_sf_tbu",
+ "noc_aggr_4",
+ "noc_aggr_south_sf",
+ "cnoc_qx";
+
+ assigned-clocks = <&gcc GCC_PCIE_4_AUX_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ interconnects = <&aggre2_noc MASTER_PCIE_4 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_4 0>;
+ interconnect-names = "pcie-mem", "cpu-pcie";
+
+ resets = <&gcc GCC_PCIE_4_BCR>;
+ reset-names = "pci";
+
+ power-domains = <&gcc PCIE_4_GDSC>;
+
+ phys = <&pcie4_phy>;
+ phy-names = "pciephy";
+
+ status = "disabled";
+ };
+
+ pcie4_phy: phy@1c06000 {
+ compatible = "qcom,sc8280xp-qmp-gen3x1-pcie-phy";
+ reg = <0x0 0x01c06000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
+ <&gcc GCC_PCIE_4_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_4_CLKREF_CLK>,
+ <&gcc GCC_PCIE4_PHY_RCHNG_CLK>,
+ <&gcc GCC_PCIE_4_PIPE_CLK>,
+ <&gcc GCC_PCIE_4_PIPEDIV2_CLK>;
+ clock-names = "aux", "cfg_ahb", "ref", "rchng",
+ "pipe", "pipediv2";
+
+ assigned-clocks = <&gcc GCC_PCIE4_PHY_RCHNG_CLK>;
+ assigned-clock-rates = <100000000>;
+
+ power-domains = <&gcc PCIE_4_GDSC>;
+
+ resets = <&gcc GCC_PCIE_4_PHY_BCR>;
+ reset-names = "phy";
+
+ #clock-cells = <0>;
+ clock-output-names = "pcie_4_pipe_clk";
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
+ pcie3b: pcie@1c08000 {
+ device_type = "pci";
+ compatible = "qcom,pcie-sc8280xp";
+ reg = <0x0 0x01c08000 0x0 0x3000>,
+ <0x0 0x32000000 0x0 0xf1d>,
+ <0x0 0x32000f20 0x0 0xa8>,
+ <0x0 0x32001000 0x0 0x1000>,
+ <0x0 0x32100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x32200000 0x0 0x32200000 0x0 0x100000>,
+ <0x02000000 0x0 0x32300000 0x0 0x32300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
+
+ dma-coherent;
+
+ linux,pci-domain = <5>;
+ num-lanes = <2>;
+
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi0", "msi1", "msi2", "msi3";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 526 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 527 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 528 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 529 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_PCIE_3B_AUX_CLK>,
+ <&gcc GCC_PCIE_3B_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_3B_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_3B_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_3B_SLV_Q2A_AXI_CLK>,
+ <&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>;
+ clock-names = "aux",
+ "cfg",
+ "bus_master",
+ "bus_slave",
+ "slave_q2a",
+ "ddrss_sf_tbu",
+ "noc_aggr_4",
+ "noc_aggr_south_sf";
+
+ assigned-clocks = <&gcc GCC_PCIE_3B_AUX_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ interconnects = <&aggre2_noc MASTER_PCIE_3B 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_3B 0>;
+ interconnect-names = "pcie-mem", "cpu-pcie";
+
+ resets = <&gcc GCC_PCIE_3B_BCR>;
+ reset-names = "pci";
+
+ power-domains = <&gcc PCIE_3B_GDSC>;
+
+ phys = <&pcie3b_phy>;
+ phy-names = "pciephy";
+
+ status = "disabled";
+ };
+
+ pcie3b_phy: phy@1c0e000 {
+ compatible = "qcom,sc8280xp-qmp-gen3x2-pcie-phy";
+ reg = <0x0 0x01c0e000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_PCIE_3B_AUX_CLK>,
+ <&gcc GCC_PCIE_3B_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_3A3B_CLKREF_CLK>,
+ <&gcc GCC_PCIE3B_PHY_RCHNG_CLK>,
+ <&gcc GCC_PCIE_3B_PIPE_CLK>,
+ <&gcc GCC_PCIE_3B_PIPEDIV2_CLK>;
+ clock-names = "aux", "cfg_ahb", "ref", "rchng",
+ "pipe", "pipediv2";
+
+ assigned-clocks = <&gcc GCC_PCIE3B_PHY_RCHNG_CLK>;
+ assigned-clock-rates = <100000000>;
+
+ power-domains = <&gcc PCIE_3B_GDSC>;
+
+ resets = <&gcc GCC_PCIE_3B_PHY_BCR>;
+ reset-names = "phy";
+
+ #clock-cells = <0>;
+ clock-output-names = "pcie_3b_pipe_clk";
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
+ pcie3a: pcie@1c10000 {
+ device_type = "pci";
+ compatible = "qcom,pcie-sc8280xp";
+ reg = <0x0 0x01c10000 0x0 0x3000>,
+ <0x0 0x34000000 0x0 0xf1d>,
+ <0x0 0x34000f20 0x0 0xa8>,
+ <0x0 0x34001000 0x0 0x1000>,
+ <0x0 0x34100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x34200000 0x0 0x34200000 0x0 0x100000>,
+ <0x02000000 0x0 0x34300000 0x0 0x34300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
+
+ dma-coherent;
+
+ linux,pci-domain = <4>;
+ num-lanes = <4>;
+
+ interrupts = <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi0", "msi1", "msi2", "msi3";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 499 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 542 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 543 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 544 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_PCIE_3A_AUX_CLK>,
+ <&gcc GCC_PCIE_3A_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_3A_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_3A_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_3A_SLV_Q2A_AXI_CLK>,
+ <&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>;
+ clock-names = "aux",
+ "cfg",
+ "bus_master",
+ "bus_slave",
+ "slave_q2a",
+ "ddrss_sf_tbu",
+ "noc_aggr_4",
+ "noc_aggr_south_sf";
+
+ assigned-clocks = <&gcc GCC_PCIE_3A_AUX_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ interconnects = <&aggre2_noc MASTER_PCIE_3A 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_3A 0>;
+ interconnect-names = "pcie-mem", "cpu-pcie";
+
+ resets = <&gcc GCC_PCIE_3A_BCR>;
+ reset-names = "pci";
+
+ power-domains = <&gcc PCIE_3A_GDSC>;
+
+ phys = <&pcie3a_phy>;
+ phy-names = "pciephy";
+
+ status = "disabled";
+ };
+
+ pcie3a_phy: phy@1c14000 {
+ compatible = "qcom,sc8280xp-qmp-gen3x4-pcie-phy";
+ reg = <0x0 0x01c14000 0x0 0x2000>,
+ <0x0 0x01c16000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_PCIE_3A_AUX_CLK>,
+ <&gcc GCC_PCIE_3A_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_3A3B_CLKREF_CLK>,
+ <&gcc GCC_PCIE3A_PHY_RCHNG_CLK>,
+ <&gcc GCC_PCIE_3A_PIPE_CLK>,
+ <&gcc GCC_PCIE_3A_PIPEDIV2_CLK>;
+ clock-names = "aux", "cfg_ahb", "ref", "rchng",
+ "pipe", "pipediv2";
+
+ assigned-clocks = <&gcc GCC_PCIE3A_PHY_RCHNG_CLK>;
+ assigned-clock-rates = <100000000>;
+
+ power-domains = <&gcc PCIE_3A_GDSC>;
+
+ resets = <&gcc GCC_PCIE_3A_PHY_BCR>;
+ reset-names = "phy";
+
+ qcom,4ln-config-sel = <&tcsr 0xa044 1>;
+
+ #clock-cells = <0>;
+ clock-output-names = "pcie_3a_pipe_clk";
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
+ pcie2b: pcie@1c18000 {
+ device_type = "pci";
+ compatible = "qcom,pcie-sc8280xp";
+ reg = <0x0 0x01c18000 0x0 0x3000>,
+ <0x0 0x38000000 0x0 0xf1d>,
+ <0x0 0x38000f20 0x0 0xa8>,
+ <0x0 0x38001000 0x0 0x1000>,
+ <0x0 0x38100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x38200000 0x0 0x38200000 0x0 0x100000>,
+ <0x02000000 0x0 0x38300000 0x0 0x38300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
+
+ dma-coherent;
+
+ linux,pci-domain = <3>;
+ num-lanes = <2>;
+
+ interrupts = <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi0", "msi1", "msi2", "msi3";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_PCIE_2B_AUX_CLK>,
+ <&gcc GCC_PCIE_2B_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_2B_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_2B_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_2B_SLV_Q2A_AXI_CLK>,
+ <&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>;
+ clock-names = "aux",
+ "cfg",
+ "bus_master",
+ "bus_slave",
+ "slave_q2a",
+ "ddrss_sf_tbu",
+ "noc_aggr_4",
+ "noc_aggr_south_sf";
+
+ assigned-clocks = <&gcc GCC_PCIE_2B_AUX_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ interconnects = <&aggre2_noc MASTER_PCIE_2B 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_2B 0>;
+ interconnect-names = "pcie-mem", "cpu-pcie";
+
+ resets = <&gcc GCC_PCIE_2B_BCR>;
+ reset-names = "pci";
+
+ power-domains = <&gcc PCIE_2B_GDSC>;
+
+ phys = <&pcie2b_phy>;
+ phy-names = "pciephy";
+
+ status = "disabled";
+ };
+
+ pcie2b_phy: phy@1c1e000 {
+ compatible = "qcom,sc8280xp-qmp-gen3x2-pcie-phy";
+ reg = <0x0 0x01c1e000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_PCIE_2B_AUX_CLK>,
+ <&gcc GCC_PCIE_2B_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_2A2B_CLKREF_CLK>,
+ <&gcc GCC_PCIE2B_PHY_RCHNG_CLK>,
+ <&gcc GCC_PCIE_2B_PIPE_CLK>,
+ <&gcc GCC_PCIE_2B_PIPEDIV2_CLK>;
+ clock-names = "aux", "cfg_ahb", "ref", "rchng",
+ "pipe", "pipediv2";
+
+ assigned-clocks = <&gcc GCC_PCIE2B_PHY_RCHNG_CLK>;
+ assigned-clock-rates = <100000000>;
+
+ power-domains = <&gcc PCIE_2B_GDSC>;
+
+ resets = <&gcc GCC_PCIE_2B_PHY_BCR>;
+ reset-names = "phy";
+
+ #clock-cells = <0>;
+ clock-output-names = "pcie_2b_pipe_clk";
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
+ pcie2a: pcie@1c20000 {
+ device_type = "pci";
+ compatible = "qcom,pcie-sc8280xp";
+ reg = <0x0 0x01c20000 0x0 0x3000>,
+ <0x0 0x3c000000 0x0 0xf1d>,
+ <0x0 0x3c000f20 0x0 0xa8>,
+ <0x0 0x3c001000 0x0 0x1000>,
+ <0x0 0x3c100000 0x0 0x100000>;
+ reg-names = "parf", "dbi", "elbi", "atu", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x3c200000 0x0 0x3c200000 0x0 0x100000>,
+ <0x02000000 0x0 0x3c300000 0x0 0x3c300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
+
+ dma-coherent;
+
+ linux,pci-domain = <2>;
+ num-lanes = <4>;
+
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 523 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 524 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 525 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi0", "msi1", "msi2", "msi3";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 530 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 531 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 532 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 533 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_PCIE_2A_AUX_CLK>,
+ <&gcc GCC_PCIE_2A_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_2A_MSTR_AXI_CLK>,
+ <&gcc GCC_PCIE_2A_SLV_AXI_CLK>,
+ <&gcc GCC_PCIE_2A_SLV_Q2A_AXI_CLK>,
+ <&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
+ <&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>;
+ clock-names = "aux",
+ "cfg",
+ "bus_master",
+ "bus_slave",
+ "slave_q2a",
+ "ddrss_sf_tbu",
+ "noc_aggr_4",
+ "noc_aggr_south_sf";
+
+ assigned-clocks = <&gcc GCC_PCIE_2A_AUX_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ interconnects = <&aggre2_noc MASTER_PCIE_2A 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_2A 0>;
+ interconnect-names = "pcie-mem", "cpu-pcie";
+
+ resets = <&gcc GCC_PCIE_2A_BCR>;
+ reset-names = "pci";
+
+ power-domains = <&gcc PCIE_2A_GDSC>;
+
+ phys = <&pcie2a_phy>;
+ phy-names = "pciephy";
+
+ status = "disabled";
+ };
+
+ pcie2a_phy: phy@1c24000 {
+ compatible = "qcom,sc8280xp-qmp-gen3x4-pcie-phy";
+ reg = <0x0 0x01c24000 0x0 0x2000>,
+ <0x0 0x01c26000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_PCIE_2A_AUX_CLK>,
+ <&gcc GCC_PCIE_2A_CFG_AHB_CLK>,
+ <&gcc GCC_PCIE_2A2B_CLKREF_CLK>,
+ <&gcc GCC_PCIE2A_PHY_RCHNG_CLK>,
+ <&gcc GCC_PCIE_2A_PIPE_CLK>,
+ <&gcc GCC_PCIE_2A_PIPEDIV2_CLK>;
+ clock-names = "aux", "cfg_ahb", "ref", "rchng",
+ "pipe", "pipediv2";
+
+ assigned-clocks = <&gcc GCC_PCIE2A_PHY_RCHNG_CLK>;
+ assigned-clock-rates = <100000000>;
+
+ power-domains = <&gcc PCIE_2A_GDSC>;
+
+ resets = <&gcc GCC_PCIE_2A_PHY_BCR>;
+ reset-names = "phy";
+
+ qcom,4ln-config-sel = <&tcsr 0xa044 0>;
+
+ #clock-cells = <0>;
+ clock-output-names = "pcie_2a_pipe_clk";
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
ufs_mem_hc: ufs@1d84000 {
compatible = "qcom,sc8280xp-ufshc", "qcom,ufshc",
"jedec,ufs-2.0";
reg = <0 0x01d84000 0 0x3000>;
interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
- phys = <&ufs_mem_phy_lanes>;
+ phys = <&ufs_mem_phy>;
phy-names = "ufsphy";
lanes-per-direction = <2>;
#reset-cells = <1>;
@@ -855,12 +1399,13 @@
required-opps = <&rpmhpd_opp_nom>;
iommus = <&apps_smmu 0xe0 0x0>;
+ dma-coherent;
clocks = <&gcc GCC_UFS_PHY_AXI_CLK>,
<&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>,
<&gcc GCC_UFS_PHY_AHB_CLK>,
<&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_UFS_REF_CLKREF_CLK>,
<&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
@@ -885,27 +1430,20 @@
ufs_mem_phy: phy@1d87000 {
compatible = "qcom,sc8280xp-qmp-ufs-phy";
- reg = <0 0x01d87000 0 0xe10>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
- clock-names = "ref",
- "ref_aux";
- clocks = <&rpmhcc RPMH_CXO_CLK>,
+ reg = <0 0x01d87000 0 0x1000>;
+
+ clocks = <&gcc GCC_UFS_CARD_CLKREF_CLK>,
<&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+ clock-names = "ref", "ref_aux";
+
+ power-domains = <&gcc UFS_PHY_GDSC>;
resets = <&ufs_mem_hc 0>;
reset-names = "ufsphy";
- status = "disabled";
- ufs_mem_phy_lanes: phy@1d87400 {
- reg = <0 0x01d87400 0 0x108>,
- <0 0x01d87600 0 0x1e0>,
- <0 0x01d87c00 0 0x1dc>,
- <0 0x01d87800 0 0x108>,
- <0 0x01d87a00 0 0x1e0>;
- #phy-cells = <0>;
- };
+ #phy-cells = <0>;
+
+ status = "disabled";
};
ufs_card_hc: ufs@1da4000 {
@@ -913,7 +1451,7 @@
"jedec,ufs-2.0";
reg = <0 0x01da4000 0 0x3000>;
interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
- phys = <&ufs_card_phy_lanes>;
+ phys = <&ufs_card_phy>;
phy-names = "ufsphy";
lanes-per-direction = <2>;
#reset-cells = <1>;
@@ -923,12 +1461,13 @@
power-domains = <&gcc UFS_CARD_GDSC>;
iommus = <&apps_smmu 0x4a0 0x0>;
+ dma-coherent;
clocks = <&gcc GCC_UFS_CARD_AXI_CLK>,
<&gcc GCC_AGGRE_UFS_CARD_AXI_CLK>,
<&gcc GCC_UFS_CARD_AHB_CLK>,
<&gcc GCC_UFS_CARD_UNIPRO_CORE_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_UFS_REF_CLKREF_CLK>,
<&gcc GCC_UFS_CARD_TX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_CARD_RX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_CARD_RX_SYMBOL_1_CLK>;
@@ -953,28 +1492,20 @@
ufs_card_phy: phy@1da7000 {
compatible = "qcom,sc8280xp-qmp-ufs-phy";
- reg = <0 0x01da7000 0 0xe10>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
- clock-names = "ref",
- "ref_aux";
+ reg = <0 0x01da7000 0 0x1000>;
+
clocks = <&gcc GCC_UFS_1_CARD_CLKREF_CLK>,
<&gcc GCC_UFS_CARD_PHY_AUX_CLK>;
+ clock-names = "ref", "ref_aux";
+
+ power-domains = <&gcc UFS_CARD_GDSC>;
resets = <&ufs_card_hc 0>;
reset-names = "ufsphy";
- status = "disabled";
+ #phy-cells = <0>;
- ufs_card_phy_lanes: phy@1da7400 {
- reg = <0 0x01da7400 0 0x108>,
- <0 0x01da7600 0 0x1e0>,
- <0 0x01da7c00 0 0x1dc>,
- <0 0x01da7800 0 0x108>,
- <0 0x01da7a00 0 0x1e0>;
- #phy-cells = <0>;
- };
+ status = "disabled";
};
tcsr_mutex: hwlock@1f40000 {
@@ -983,6 +1514,11 @@
#hwlock-cells = <1>;
};
+ tcsr: syscon@1fc0000 {
+ compatible = "qcom,sc8280xp-tcsr", "syscon";
+ reg = <0x0 0x01fc0000 0x0 0x30000>;
+ };
+
usb_0_hsphy: phy@88e5000 {
compatible = "qcom,sc8280xp-usb-hs-phy",
"qcom,usb-snps-hs-5nm-phy";
@@ -1048,70 +1584,52 @@
status = "disabled";
};
- usb_2_qmpphy0: phy-wrapper@88ef000 {
+ usb_2_qmpphy0: phy@88ef000 {
compatible = "qcom,sc8280xp-qmp-usb3-uni-phy";
- reg = <0 0x088ef000 0 0x1c8>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
+ reg = <0 0x088ef000 0 0x2000>;
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP0_CLKREF_CLK>,
- <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>;
- clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+ <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
+ <&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
+ clock-names = "aux", "ref", "com_aux", "pipe";
resets = <&gcc GCC_USB3_UNIPHY_MP0_BCR>,
<&gcc GCC_USB3UNIPHY_PHY_MP0_BCR>;
- reset-names = "phy", "common";
+ reset-names = "phy", "phy_phy";
power-domains = <&gcc USB30_MP_GDSC>;
- status = "disabled";
+ #clock-cells = <0>;
+ clock-output-names = "usb2_phy0_pipe_clk";
- usb_2_ssphy0: phy@88efe00 {
- reg = <0 0x088efe00 0 0x160>,
- <0 0x088f0000 0 0x1ec>,
- <0 0x088ef200 0 0x1f0>;
- #phy-cells = <0>;
- #clock-cells = <0>;
- clocks = <&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
- clock-names = "pipe0";
- clock-output-names = "usb2_phy0_pipe_clk";
- };
+ #phy-cells = <0>;
+
+ status = "disabled";
};
- usb_2_qmpphy1: phy-wrapper@88f1000 {
+ usb_2_qmpphy1: phy@88f1000 {
compatible = "qcom,sc8280xp-qmp-usb3-uni-phy";
- reg = <0 0x088f1000 0 0x1c8>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
+ reg = <0 0x088f1000 0 0x2000>;
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP1_CLKREF_CLK>,
- <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>;
- clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+ <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
+ <&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
+ clock-names = "aux", "ref", "com_aux", "pipe";
resets = <&gcc GCC_USB3_UNIPHY_MP1_BCR>,
<&gcc GCC_USB3UNIPHY_PHY_MP1_BCR>;
- reset-names = "phy", "common";
+ reset-names = "phy", "phy_phy";
power-domains = <&gcc USB30_MP_GDSC>;
- status = "disabled";
+ #clock-cells = <0>;
+ clock-output-names = "usb2_phy1_pipe_clk";
- usb_2_ssphy1: phy@88f1e00 {
- reg = <0 0x088f1e00 0 0x160>,
- <0 0x088f2000 0 0x1ec>,
- <0 0x088f1200 0 0x1f0>;
- #phy-cells = <0>;
- #clock-cells = <0>;
- clocks = <&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
- clock-names = "pipe0";
- clock-output-names = "usb2_phy1_pipe_clk";
- };
+ #phy-cells = <0>;
+
+ status = "disabled";
};
remoteproc_adsp: remoteproc@3000000 {
@@ -1181,26 +1699,16 @@
usb_0_ssphy: usb3-phy@88eb400 {
reg = <0 0x088eb400 0 0x100>,
<0 0x088eb600 0 0x3ec>,
- <0 0x088ec400 0 0x1f0>,
+ <0 0x088ec400 0 0x364>,
<0 0x088eba00 0 0x100>,
<0 0x088ebc00 0 0x3ec>,
- <0 0x088ec700 0 0x64>;
+ <0 0x088ec200 0 0x18>;
#phy-cells = <0>;
#clock-cells = <0>;
clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
clock-names = "pipe0";
clock-output-names = "usb0_phy_pipe_clk_src";
};
-
- usb_0_dpphy: dp-phy@88ed200 {
- reg = <0 0x088ed200 0 0x200>,
- <0 0x088ed400 0 0x200>,
- <0 0x088eda00 0 0x200>,
- <0 0x088ea600 0 0x200>,
- <0 0x088ea800 0 0x200>;
- #clock-cells = <1>;
- #phy-cells = <0>;
- };
};
usb_1_hsphy: phy@8902000 {
@@ -1242,8 +1750,8 @@
usb_1_ssphy: usb3-phy@8903400 {
reg = <0 0x08903400 0 0x100>,
- <0 0x08903c00 0 0x3ec>,
- <0 0x08904400 0 0x1f0>,
+ <0 0x08903600 0 0x3ec>,
+ <0 0x08904400 0 0x364>,
<0 0x08903a00 0 0x100>,
<0 0x08903c00 0 0x3ec>,
<0 0x08904200 0 0x18>;
@@ -1253,15 +1761,96 @@
clock-names = "pipe0";
clock-output-names = "usb1_phy_pipe_clk_src";
};
+ };
- usb_1_dpphy: dp-phy@8904200 {
- reg = <0 0x08904200 0 0x200>,
- <0 0x08904400 0 0x200>,
- <0 0x08904a00 0 0x200>,
- <0 0x08904600 0 0x200>,
- <0 0x08904800 0 0x200>;
- #clock-cells = <1>;
- #phy-cells = <0>;
+ pmu@9091000 {
+ compatible = "qcom,sc8280xp-llcc-bwmon", "qcom,sc7280-llcc-bwmon";
+ reg = <0 0x9091000 0 0x1000>;
+
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+
+ interconnects = <&mc_virt MASTER_LLCC 3 &mc_virt SLAVE_EBI1 3>;
+
+ operating-points-v2 = <&llcc_bwmon_opp_table>;
+
+ llcc_bwmon_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-0 {
+ opp-peak-kBps = <762000>;
+ };
+ opp-1 {
+ opp-peak-kBps = <1720000>;
+ };
+ opp-2 {
+ opp-peak-kBps = <2086000>;
+ };
+ opp-3 {
+ opp-peak-kBps = <2597000>;
+ };
+ opp-4 {
+ opp-peak-kBps = <2929000>;
+ };
+ opp-5 {
+ opp-peak-kBps = <3879000>;
+ };
+ opp-6 {
+ opp-peak-kBps = <5161000>;
+ };
+ opp-7 {
+ opp-peak-kBps = <5931000>;
+ };
+ opp-8 {
+ opp-peak-kBps = <6515000>;
+ };
+ opp-9 {
+ opp-peak-kBps = <7980000>;
+ };
+ opp-10 {
+ opp-peak-kBps = <8136000>;
+ };
+ opp-11 {
+ opp-peak-kBps = <10437000>;
+ };
+ opp-12 {
+ opp-peak-kBps = <12191000>;
+ };
+ };
+ };
+
+ pmu@90b6400 {
+ compatible = "qcom,sc8280xp-cpu-bwmon", "qcom,msm8998-bwmon";
+ reg = <0 0x090b6400 0 0x600>;
+
+ interrupts = <GIC_SPI 581 IRQ_TYPE_LEVEL_HIGH>;
+
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &gem_noc SLAVE_LLCC 3>;
+ operating-points-v2 = <&cpu_bwmon_opp_table>;
+
+ cpu_bwmon_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-0 {
+ opp-peak-kBps = <2288000>;
+ };
+ opp-1 {
+ opp-peak-kBps = <4577000>;
+ };
+ opp-2 {
+ opp-peak-kBps = <7110000>;
+ };
+ opp-3 {
+ opp-peak-kBps = <9155000>;
+ };
+ opp-4 {
+ opp-peak-kBps = <12298000>;
+ };
+ opp-5 {
+ opp-peak-kBps = <14236000>;
+ };
+ opp-6 {
+ opp-peak-kBps = <15258001>;
+ };
};
};
@@ -1476,6 +2065,11 @@
#clock-cells = <0>;
};
+ sram@c3f0000 {
+ compatible = "qcom,rpmh-stats";
+ reg = <0 0x0c3f0000 0 0x400>;
+ };
+
spmi_bus: spmi@c440000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0 0x0c440000 0 0x1100>,
@@ -1806,6 +2400,16 @@
};
};
+ epss_l3: interconnect@18590000 {
+ compatible = "qcom,sc8280xp-epss-l3", "qcom,epss-l3";
+ reg = <0 0x18590000 0 0x1000>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>;
+ clock-names = "xo", "alternate";
+
+ #interconnect-cells = <1>;
+ };
+
cpufreq_hw: cpufreq@18591000 {
compatible = "qcom,sc8280xp-cpufreq-epss", "qcom,cpufreq-epss";
reg = <0 0x18591000 0 0x1000>,
diff --git a/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts b/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts
index 28050bc5f081..7c81918eee66 100644
--- a/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts
+++ b/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts
@@ -99,7 +99,7 @@
};
&adsp_pil {
- firmware-name = "qcom/ifc6560/adsp.mbn";
+ firmware-name = "qcom/sda660/adsp.mbn";
};
&blsp_i2c6 {
@@ -231,7 +231,7 @@
};
&rpm_requests {
- pm660-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm660-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -313,7 +313,7 @@
};
};
- pm660l-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm660l-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -401,16 +401,18 @@
};
&sdc2_state_on {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
&sdc2_state_off {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-disable;
drive-strength = <2>;
};
@@ -436,7 +438,7 @@
cd-gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
no-sdio;
- no-emmc;
+ no-mmc;
};
&tlmm {
diff --git a/arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi b/arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi
index 09c07800793a..3d2b08d551d0 100644
--- a/arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi
@@ -155,7 +155,7 @@
};
&adsp_pil {
- firmware-name = "adsp.mdt";
+ firmware-name = "qcom/sdm630/Sony/nile/adsp.mdt";
};
&blsp_i2c1 {
@@ -260,7 +260,7 @@
};
&rpm_requests {
- pm660l-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm660l-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -394,7 +394,7 @@
};
};
- pm660-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm660-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -577,16 +577,18 @@
};
&sdc2_state_on {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
&sdc2_state_off {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-disable;
drive-strength = <2>;
};
@@ -615,33 +617,35 @@
&tlmm {
gpio-reserved-ranges = <8 4>;
- ts_int_active: ts-int-active {
+ ts_int_active: ts-int-active-state {
pins = "gpio45";
+ function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
- ts_lcd_id_active: ts-lcd-id-active {
+ ts_lcd_id_active: ts-lcd-id-active-state {
pins = "gpio56";
+ function = "gpio";
drive-strength = <8>;
bias-disable;
};
- imx300_vana_default: imx300-vana-default {
+ imx300_vana_default: imx300-vana-default-state {
pins = "gpio50";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- imx219_vana_default: imx219-vana-default {
+ imx219_vana_default: imx219-vana-default-state {
pins = "gpio51";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
- cam_vdig_default: cam-vdig-default {
+ cam_vdig_default: cam-vdig-default-state {
pins = "gpio52";
function = "gpio";
bias-disable;
diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi
index b51b85f583e5..13e6a4fbba27 100644
--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi
@@ -721,33 +721,36 @@
interrupt-controller;
#interrupt-cells = <2>;
- blsp1_uart1_default: blsp1-uart1-default {
+ blsp1_uart1_default: blsp1-uart1-default-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ function = "blsp_uart1";
drive-strength = <2>;
bias-disable;
};
- blsp1_uart1_sleep: blsp1-uart1-sleep {
+ blsp1_uart1_sleep: blsp1-uart1-sleep-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
- blsp1_uart2_default: blsp1-uart2-default {
+ blsp1_uart2_default: blsp1-uart2-default-state {
pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
drive-strength = <2>;
bias-disable;
};
- blsp2_uart1_default: blsp2-uart1-active {
- tx-rts {
+ blsp2_uart1_default: blsp2-uart1-active-state {
+ tx-rts-pins {
pins = "gpio16", "gpio19";
function = "blsp_uart5";
drive-strength = <2>;
bias-disable;
};
- rx {
+ rx-pins {
/*
* Avoid garbage data while BT module
* is powered off or not driving signal
@@ -758,7 +761,7 @@
bias-pull-up;
};
- cts {
+ cts-pins {
/* Match the pull of the BT module */
pins = "gpio18";
function = "blsp_uart5";
@@ -767,244 +770,232 @@
};
};
- blsp2_uart1_sleep: blsp2-uart1-sleep {
- tx {
+ blsp2_uart1_sleep: blsp2-uart1-sleep-state {
+ tx-pins {
pins = "gpio16";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
- rx-cts-rts {
+ rx-cts-rts-pins {
pins = "gpio17", "gpio18", "gpio19";
function = "gpio";
drive-strength = <2>;
- bias-no-pull;
+ bias-disable;
};
};
- i2c1_default: i2c1-default {
+ i2c1_default: i2c1-default-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-disable;
};
- i2c1_sleep: i2c1-sleep {
+ i2c1_sleep: i2c1-sleep-state {
pins = "gpio2", "gpio3";
function = "blsp_i2c1";
drive-strength = <2>;
bias-pull-up;
};
- i2c2_default: i2c2-default {
+ i2c2_default: i2c2-default-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-disable;
};
- i2c2_sleep: i2c2-sleep {
+ i2c2_sleep: i2c2-sleep-state {
pins = "gpio6", "gpio7";
function = "blsp_i2c2";
drive-strength = <2>;
bias-pull-up;
};
- i2c3_default: i2c3-default {
+ i2c3_default: i2c3-default-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
bias-disable;
};
- i2c3_sleep: i2c3-sleep {
+ i2c3_sleep: i2c3-sleep-state {
pins = "gpio10", "gpio11";
function = "blsp_i2c3";
drive-strength = <2>;
bias-pull-up;
};
- i2c4_default: i2c4-default {
+ i2c4_default: i2c4-default-state {
pins = "gpio14", "gpio15";
function = "blsp_i2c4";
drive-strength = <2>;
bias-disable;
};
- i2c4_sleep: i2c4-sleep {
+ i2c4_sleep: i2c4-sleep-state {
pins = "gpio14", "gpio15";
function = "blsp_i2c4";
drive-strength = <2>;
bias-pull-up;
};
- i2c5_default: i2c5-default {
+ i2c5_default: i2c5-default-state {
pins = "gpio18", "gpio19";
function = "blsp_i2c5";
drive-strength = <2>;
bias-disable;
};
- i2c5_sleep: i2c5-sleep {
+ i2c5_sleep: i2c5-sleep-state {
pins = "gpio18", "gpio19";
function = "blsp_i2c5";
drive-strength = <2>;
bias-pull-up;
};
- i2c6_default: i2c6-default {
+ i2c6_default: i2c6-default-state {
pins = "gpio22", "gpio23";
function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
- i2c6_sleep: i2c6-sleep {
+ i2c6_sleep: i2c6-sleep-state {
pins = "gpio22", "gpio23";
function = "blsp_i2c6";
drive-strength = <2>;
bias-pull-up;
};
- i2c7_default: i2c7-default {
+ i2c7_default: i2c7-default-state {
pins = "gpio26", "gpio27";
function = "blsp_i2c7";
drive-strength = <2>;
bias-disable;
};
- i2c7_sleep: i2c7-sleep {
+ i2c7_sleep: i2c7-sleep-state {
pins = "gpio26", "gpio27";
function = "blsp_i2c7";
drive-strength = <2>;
bias-pull-up;
};
- i2c8_default: i2c8-default {
+ i2c8_default: i2c8-default-state {
pins = "gpio30", "gpio31";
- function = "blsp_i2c8";
+ function = "blsp_i2c8_a";
drive-strength = <2>;
bias-disable;
};
- i2c8_sleep: i2c8-sleep {
+ i2c8_sleep: i2c8-sleep-state {
pins = "gpio30", "gpio31";
- function = "blsp_i2c8";
+ function = "blsp_i2c8_a";
drive-strength = <2>;
bias-pull-up;
};
- cci0_default: cci0_default {
- pinmux {
- pins = "gpio36","gpio37";
- function = "cci_i2c";
- };
-
- pinconf {
- pins = "gpio36","gpio37";
- bias-pull-up;
- drive-strength = <2>;
- };
+ cci0_default: cci0-default-state {
+ pins = "gpio36","gpio37";
+ function = "cci_i2c";
+ bias-pull-up;
+ drive-strength = <2>;
};
- cci1_default: cci1_default {
- pinmux {
- pins = "gpio38","gpio39";
- function = "cci_i2c";
- };
-
- pinconf {
- pins = "gpio38","gpio39";
- bias-pull-up;
- drive-strength = <2>;
- };
+ cci1_default: cci1-default-state {
+ pins = "gpio38","gpio39";
+ function = "cci_i2c";
+ bias-pull-up;
+ drive-strength = <2>;
};
- sdc1_state_on: sdc1-on {
- clk {
+ sdc1_state_on: sdc1-on-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <10>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc1_state_off: sdc1-off {
- clk {
+ sdc1_state_off: sdc1-off-state {
+ clk-pins {
pins = "sdc1_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc1_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc1_data";
bias-pull-up;
drive-strength = <2>;
};
- rclk {
+ rclk-pins {
pins = "sdc1_rclk";
bias-pull-down;
};
};
- sdc2_state_on: sdc2-on {
- clk {
+ sdc2_state_on: sdc2-on-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <16>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <10>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <10>;
};
};
- sdc2_state_off: sdc2-off {
- clk {
+ sdc2_state_off: sdc2-off-state {
+ clk-pins {
pins = "sdc2_clk";
bias-disable;
drive-strength = <2>;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
bias-pull-up;
drive-strength = <2>;
};
- data {
+ data-pins {
pins = "sdc2_data";
bias-pull-up;
drive-strength = <2>;
@@ -1616,7 +1607,6 @@
"core";
phys = <&dsi0_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -1639,7 +1629,7 @@
};
};
- dsi0_phy: dsi-phy@c994400 {
+ dsi0_phy: phy@c994400 {
compatible = "qcom,dsi-phy-14nm-660";
reg = <0x0c994400 0x100>,
<0x0c994500 0x300>,
@@ -2224,12 +2214,12 @@
#address-cells = <1>;
#size-cells = <0>;
- q6core {
+ service@3 {
reg = <APR_SVC_ADSP_CORE>;
compatible = "qcom,q6core";
};
- q6afe: apr-service@4 {
+ q6afe: service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
q6afedai: dais {
@@ -2240,7 +2230,7 @@
};
};
- q6asm: apr-service@7 {
+ q6asm: service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
q6asmdai: dais {
@@ -2252,7 +2242,7 @@
};
};
- q6adm: apr-service@8 {
+ q6adm: service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
q6routing: routing {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts
index 891e314bc782..3fb513cad0a9 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts
@@ -49,6 +49,20 @@
vdda-phy-dpdm-supply = <&pm8953_l13>;
};
+&i2c_3 {
+ status = "okay";
+
+ touchscreen@48 {
+ compatible = "himax,hx83112b";
+ reg = <0x48>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 IRQ_TYPE_LEVEL_LOW>;
+ touchscreen-size-x = <1080>;
+ touchscreen-size-y = <2160>;
+ reset-gpios = <&tlmm 64 GPIO_ACTIVE_LOW>;
+ };
+};
+
&pm8953_resin {
status = "okay";
linux,code = <KEY_VOLUMEDOWN>;
@@ -69,7 +83,7 @@
};
&rpm_requests {
- pm8953-regulators {
+ regulators {
compatible = "qcom,rpm-pm8953-regulators";
vdd_l1-supply = <&pm8953_s3>;
diff --git a/arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts b/arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts
index 58f687fc49e0..9702e5f59a1d 100644
--- a/arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts
+++ b/arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts
@@ -19,7 +19,7 @@
};
&sdc2_state_on {
- clk {
+ clk-pins {
drive-strength = <14>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts
index a3559f6e34a5..8fb2d1788742 100644
--- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts
+++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts
@@ -111,7 +111,7 @@
};
&rpm_requests {
- pm660l-regulators {
+ regulators-0 {
compatible = "qcom,rpm-pm660l-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -206,7 +206,7 @@
};
};
- pm660-regulators {
+ regulators-1 {
compatible = "qcom,rpm-pm660-regulators";
vdd_s1-supply = <&vph_pwr>;
@@ -372,16 +372,18 @@
};
&sdc2_state_on {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-pull-up;
drive-strength = <2>;
};
};
&sdc2_state_off {
- sd-cd {
+ sd-cd-pins {
pins = "gpio54";
+ function = "gpio";
bias-disable;
drive-strength = <2>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm660.dtsi b/arch/arm64/boot/dts/qcom/sdm660.dtsi
index 43220af1b685..d52123cb5cd3 100644
--- a/arch/arm64/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm660.dtsi
@@ -190,7 +190,6 @@
"core";
phys = <&dsi1_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -213,7 +212,7 @@
};
};
- dsi1_phy: dsi-phy@c996400 {
+ dsi1_phy: phy@c996400 {
compatible = "qcom,dsi-phy-14nm-660";
reg = <0x0c996400 0x100>,
<0x0c996500 0x300>,
diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts
new file mode 100644
index 000000000000..cf2ae540db12
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device tree for Google Pixel 3a, adapted from google-blueline device tree,
+ * xiaomi-lavender device tree, and oneplus-common device tree.
+ *
+ * Copyright (c) 2022, Richard Acayan. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+#include "sdm670.dtsi"
+#include "pm660.dtsi"
+#include "pm660l.dtsi"
+
+/delete-node/ &mpss_region;
+/delete-node/ &venus_mem;
+/delete-node/ &wlan_msa_mem;
+/delete-node/ &cdsp_mem;
+/delete-node/ &mba_region;
+/delete-node/ &adsp_mem;
+/delete-node/ &ipa_fw_mem;
+/delete-node/ &ipa_gsi_mem;
+/delete-node/ &gpu_mem;
+
+/ {
+ model = "Google Pixel 3a";
+ compatible = "google,sargo", "qcom,sdm670";
+
+ aliases { };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ framebuffer@9c000000 {
+ compatible = "simple-framebuffer";
+ reg = <0 0x9c000000 0 (1080 * 2220 * 4)>;
+ width = <1080>;
+ height = <2220>;
+ stride = <(1080 * 4)>;
+ format = "a8r8g8b8";
+ };
+ };
+
+ clocks {
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32764>;
+ };
+
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <38400000>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&vol_up_pin>;
+
+ key-vol-up {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ mpss_region: mpss@8b000000 {
+ reg = <0 0x8b000000 0 0x9800000>;
+ no-map;
+ };
+
+ venus_mem: venus@94800000 {
+ reg = <0 0x94800000 0 0x500000>;
+ no-map;
+ };
+
+ wlan_msa_mem: wlan-msa@94d00000 {
+ reg = <0 0x94d00000 0 0x100000>;
+ no-map;
+ };
+
+ cdsp_mem: cdsp@94e00000 {
+ reg = <0 0x94e00000 0 0x800000>;
+ no-map;
+ };
+
+ mba_region: mba@95600000 {
+ reg = <0 0x95600000 0 0x200000>;
+ no-map;
+ };
+
+ adsp_mem: adsp@95800000 {
+ reg = <0 0x95800000 0 0x2200000>;
+ no-map;
+ };
+
+ ipa_fw_mem: ipa-fw@97a00000 {
+ reg = <0 0x97a00000 0 0x10000>;
+ no-map;
+ };
+
+ ipa_gsi_mem: ipa-gsi@97a10000 {
+ reg = <0 0x97a10000 0 0x5000>;
+ no-map;
+ };
+
+ gpu_mem: gpu@97a15000 {
+ reg = <0 0x97a15000 0 0x2000>;
+ no-map;
+ };
+
+ framebuffer-region@9c000000 {
+ reg = <0 0x9c000000 0 0x2400000>;
+ no-map;
+ };
+
+ /* Also includes ramoops regions */
+ debug_info_mem: debug-info@a1800000 {
+ reg = <0 0xa1800000 0 0x411000>;
+ no-map;
+ };
+ };
+
+ /*
+ * The touchscreen regulator seems to be controlled somehow by a gpio.
+ * Model it as a fixed regulator and keep it on. Without schematics we
+ * don't know how this is actually wired up...
+ */
+ ts_1p8_supply: ts-1p8-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "ts_1p8_supply";
+
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ gpio = <&pm660_gpios 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /*
+ * Supply map from xiaomi-lavender specifies this as the supply for
+ * ldob1, ldob9, ldob10, ldoa2, and ldoa3, while downstream specifies
+ * this as a power domain. Set this as a fixed regulator with the same
+ * voltage as lavender until display is needed to avoid unneccessarily
+ * using a deprecated binding (regulator-fixed-domain).
+ */
+ vreg_s2b_1p05: vreg-s2b-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_s2b";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm660-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+
+ vdd-l1-l6-l7-supply = <&vreg_s6a_0p87>;
+ vdd-l2-l3-supply = <&vreg_s2b_1p05>;
+ vdd-l5-supply = <&vreg_s2b_1p05>;
+ vdd-l8-l9-l10-l11-l12-l13-l14-supply = <&vreg_s4a_2p04>;
+ vdd-l15-l16-l17-l18-l19-supply = <&vreg_bob>;
+
+ /*
+ * S1A (FTAPC0), S2A (FTAPC1), S3A (HFAPC1) are managed
+ * by the Core Power Reduction hardened (CPRh) and the
+ * Operating State Manager (OSM) HW automatically.
+ */
+
+ vreg_s4a_2p04: smps4 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2040000>;
+ regulator-enable-ramp-delay = <200>;
+ };
+
+ vreg_s6a_0p87: smps6 {
+ regulator-min-microvolt = <1224000>;
+ regulator-max-microvolt = <1352000>;
+ regulator-enable-ramp-delay = <150>;
+ };
+
+ /* LDOs */
+ vreg_l1a_1p225: ldo1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l2a_1p0: ldo2 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l3a_1p0: ldo3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l5a_0p848: ldo5 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l6a_1p3: ldo6 {
+ regulator-min-microvolt = <1248000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l7a_1p2: ldo7 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l8a_1p8: ldo8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l9a_1p8: ldo9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l10a_1p8: ldo10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l11a_1p8: ldo11 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l12a_1p8: ldo12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l13a_1p8: ldo13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l14a_1p8: ldo14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l15a_1p8: ldo15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l16a_2p7: ldo16 {
+ regulator-min-microvolt = <2696000>;
+ regulator-max-microvolt = <2696000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l17a_1p8: ldo17 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l19a_3p3: ldo19 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3312000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm660l-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+
+ vdd-l1-l9-l10-supply = <&vreg_s2b_1p05>;
+ vdd-l2-supply = <&vreg_bob>;
+ vdd-l3-l5-l7-l8-supply = <&vreg_bob>;
+ vdd-l4-l6-supply = <&vreg_bob>;
+ vdd-bob-supply = <&vph_pwr>;
+
+ /* LDOs */
+ vreg_l1b_0p925: ldo1 {
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <900000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l2b_2p95: ldo2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l3b_3p0: ldo3 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l4b_2p95: ldo4 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l5b_2p95: ldo5 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l6b_3p3: ldo6 {
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l7b_3p125: ldo7 {
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ vreg_l8b_3p3: ldo8 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3312000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ /*
+ * Downstream specifies a fixed voltage of 3.312 V, but the
+ * PMIC4 BOB ranges don't support that. Widen the range a
+ * little to avoid adding a new BOB regulator type.
+ */
+ vreg_bob: bob {
+ regulator-min-microvolt = <3296000>;
+ regulator-max-microvolt = <3328000>;
+ regulator-enable-ramp-delay = <500>;
+ };
+ };
+
+};
+
+&gcc {
+ protected-clocks = <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+ <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+};
+
+&gpi_dma1 {
+ status = "okay";
+};
+
+&i2c9 {
+ clock-frequency = <100000>;
+ status = "okay";
+
+ synaptics-rmi4-i2c@20 {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x20>;
+ interrupts-extended = <&tlmm 125 IRQ_TYPE_EDGE_FALLING>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&touchscreen_default>;
+
+ vio-supply = <&ts_1p8_supply>;
+
+ syna,reset-delay-ms = <200>;
+ syna,startup-delay-ms = <200>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rmi4-f01@1 {
+ reg = <0x01>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f12@12 {
+ reg = <0x12>;
+ touchscreen-x-mm = <62>;
+ touchscreen-y-mm = <127>;
+ syna,sensor-type = <1>;
+ };
+ };
+};
+
+&pm660l_gpios {
+ vol_up_pin: vol-up-state {
+ pins = "gpio7";
+ function = "normal";
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+ input-enable;
+ bias-pull-up;
+ };
+};
+
+&pon_pwrkey {
+ status = "okay";
+};
+
+&pon_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&sdhc_1 {
+ supports-cqe;
+ mmc-hs200-1_8v;
+ mmc-hs400-1_8v;
+ mmc-ddr-1_8v;
+
+ qcom,ddr-config = <0xc3040873>;
+
+ vmmc-supply = <&vreg_l4b_2p95>;
+ vqmmc-supply = <&vreg_l8a_1p8>;
+
+ status = "okay";
+};
+
+&tlmm {
+ gpio-reserved-ranges = <0 4>, <81 4>;
+
+ touchscreen_default: ts-default-state {
+ ts-reset-pins {
+ pins = "gpio99";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ output-high;
+ };
+
+ ts-irq-pins {
+ pins = "gpio125";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ ts-switch-pins {
+ pins = "gpio135";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+};
+
+&usb_1_hsphy {
+ vdd-supply = <&vreg_l1b_0p925>;
+ vdda-pll-supply = <&vreg_l10a_1p8>;
+ vdda-phy-dpdm-supply = <&vreg_l7b_3p125>;
+
+ status = "okay";
+};
+
+&usb_1 {
+ qcom,select-utmi-as-pipe-clk;
+ status = "okay";
+};
+
+&usb_1_dwc3 {
+ /* Only peripheral works for now */
+ dr_mode = "peripheral";
+
+ /* Do not assume that sdm670.dtsi will never support USB 3.0 */
+ phys = <&usb_1_hsphy>;
+ phy-names = "usb2-phy";
+ maximum-speed = "high-speed";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
new file mode 100644
index 000000000000..47363fde64ac
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -0,0 +1,1160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SDM670 SoC device tree source, adapted from SDM845 SoC device tree
+ *
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Richard Acayan. All rights reserved.
+ */
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/dma/qcom-gpi.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy-qcom-qusb2.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+#include <dt-bindings/soc/qcom,rpmh-rsc.h>
+
+/ {
+ interrupt-parent = <&intc>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases { };
+
+ chosen { };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD0>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_0>;
+ L2_0: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ L3_0: l3-cache {
+ compatible = "cache";
+ };
+ };
+ };
+
+ CPU1: cpu@100 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD1>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_100>;
+ L2_100: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU2: cpu@200 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD2>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_200>;
+ L2_200: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU3: cpu@300 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD3>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_300>;
+ L2_300: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU4: cpu@400 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x400>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD4>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_400>;
+ L2_400: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU5: cpu@500 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x500>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD5>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_500>;
+ L2_500: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU6: cpu@600 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x600>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD6>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_600>;
+ L2_600: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU7: cpu@700 {
+ device_type = "cpu";
+ compatible = "qcom,kryo360";
+ reg = <0x0 0x700>;
+ enable-method = "psci";
+ power-domains = <&CPU_PD7>;
+ power-domain-names = "psci";
+ next-level-cache = <&L2_700>;
+ L2_700: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+
+ core1 {
+ cpu = <&CPU1>;
+ };
+
+ core2 {
+ cpu = <&CPU2>;
+ };
+
+ core3 {
+ cpu = <&CPU3>;
+ };
+
+ core4 {
+ cpu = <&CPU4>;
+ };
+
+ core5 {
+ cpu = <&CPU5>;
+ };
+
+ core6 {
+ cpu = <&CPU6>;
+ };
+
+ core7 {
+ cpu = <&CPU7>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "little-rail-power-collapse";
+ arm,psci-suspend-param = <0x40000004>;
+ entry-latency-us = <702>;
+ exit-latency-us = <915>;
+ min-residency-us = <1617>;
+ local-timer-stop;
+ };
+
+ BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "big-rail-power-collapse";
+ arm,psci-suspend-param = <0x40000004>;
+ entry-latency-us = <526>;
+ exit-latency-us = <1854>;
+ min-residency-us = <2380>;
+ local-timer-stop;
+ };
+ };
+
+ domain-idle-states {
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "domain-idle-state";
+ arm,psci-suspend-param = <0x4100c244>;
+ entry-latency-us = <3263>;
+ exit-latency-us = <6562>;
+ min-residency-us = <9825>;
+ };
+ };
+ };
+
+ firmware {
+ scm {
+ compatible = "qcom,scm-sdm670", "qcom,scm";
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the size */
+ reg = <0x0 0x80000000 0x0 0x0>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+
+ CPU_PD0: power-domain-cpu0 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD1: power-domain-cpu1 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD2: power-domain-cpu2 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD3: power-domain-cpu3 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD4: power-domain-cpu4 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD5: power-domain-cpu5 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD6: power-domain-cpu6 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&BIG_CPU_SLEEP_0>;
+ };
+
+ CPU_PD7: power-domain-cpu7 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&BIG_CPU_SLEEP_0>;
+ };
+
+ CLUSTER_PD: power-domain-cluster {
+ #power-domain-cells = <0>;
+ domain-idle-states = <&CLUSTER_SLEEP_0>;
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ hyp_mem: hyp-mem@85700000 {
+ reg = <0 0x85700000 0 0x600000>;
+ no-map;
+ };
+
+ xbl_mem: xbl-mem@85e00000 {
+ reg = <0 0x85e00000 0 0x100000>;
+ no-map;
+ };
+
+ aop_mem: aop-mem@85fc0000 {
+ reg = <0 0x85fc0000 0 0x20000>;
+ no-map;
+ };
+
+ aop_cmd_db_mem: aop-cmd-db-mem@85fe0000 {
+ compatible = "qcom,cmd-db";
+ reg = <0 0x85fe0000 0 0x20000>;
+ no-map;
+ };
+
+ camera_mem: camera-mem@8ab00000 {
+ reg = <0 0x8ab00000 0 0x500000>;
+ no-map;
+ };
+
+ mpss_region: mpss@8b000000 {
+ reg = <0 0x8b000000 0 0x7e00000>;
+ no-map;
+ };
+
+ venus_mem: venus@92e00000 {
+ reg = <0 0x92e00000 0 0x500000>;
+ no-map;
+ };
+
+ wlan_msa_mem: wlan-msa@93300000 {
+ reg = <0 0x93300000 0 0x100000>;
+ no-map;
+ };
+
+ cdsp_mem: cdsp@93400000 {
+ reg = <0 0x93400000 0 0x800000>;
+ no-map;
+ };
+
+ mba_region: mba@93c00000 {
+ reg = <0 0x93c00000 0 0x200000>;
+ no-map;
+ };
+
+ adsp_mem: adsp@93e00000 {
+ reg = <0 0x93e00000 0 0x1e00000>;
+ no-map;
+ };
+
+ ipa_fw_mem: ipa-fw@95c00000 {
+ reg = <0 0x95c00000 0 0x10000>;
+ no-map;
+ };
+
+ ipa_gsi_mem: ipa-gsi@95c10000 {
+ reg = <0 0x95c10000 0 0x5000>;
+ no-map;
+ };
+
+ gpu_mem: gpu@95c15000 {
+ reg = <0 0x95c15000 0 0x2000>;
+ no-map;
+ };
+
+ spss_mem: spss@97b00000 {
+ reg = <0 0x97b00000 0 0x100000>;
+ no-map;
+ };
+
+ qseecom_mem: qseecom@9e400000 {
+ reg = <0 0x9e400000 0 0x1400000>;
+ no-map;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 3 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ soc: soc@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0 0 0 0 0x10 0>;
+ dma-ranges = <0 0 0 0 0x10 0>;
+ compatible = "simple-bus";
+
+ gcc: clock-controller@100000 {
+ compatible = "qcom,gcc-sdm670";
+ reg = <0 0x00100000 0 0x1f0000>;
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&rpmhcc RPMH_CXO_CLK_A>,
+ <&sleep_clk>;
+ clock-names = "bi_tcxo",
+ "bi_tcxo_ao",
+ "sleep_clk";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+ sdhc_1: mmc@7c4000 {
+ compatible = "qcom,sdm670-sdhci", "qcom,sdhci-msm-v5";
+ reg = <0 0x007c4000 0 0x1000>,
+ <0 0x007c5000 0 0x1000>,
+ <0 0x007c8000 0 0x8000>;
+ reg-names = "hc", "cqhci", "ice";
+
+ interrupts = <GIC_SPI 641 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 644 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+ <&gcc GCC_SDCC1_APPS_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_SDCC1_ICE_CORE_CLK>,
+ <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>;
+ clock-names = "iface", "core", "xo", "ice", "bus";
+
+ iommus = <&apps_smmu 0x140 0xf>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc1_state_on>;
+ pinctrl-1 = <&sdc1_state_off>;
+ power-domains = <&rpmhpd SDM670_CX>;
+
+ bus-width = <8>;
+ non-removable;
+
+ status = "disabled";
+ };
+
+ gpi_dma0: dma-controller@800000 {
+ #dma-cells = <3>;
+ compatible = "qcom,sdm670-gpi-dma", "qcom,sdm845-gpi-dma";
+ reg = <0 0x00800000 0 0x60000>;
+ interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <13>;
+ dma-channel-mask = <0xfa>;
+ iommus = <&apps_smmu 0x16 0x0>;
+ status = "disabled";
+ };
+
+ qupv3_id_0: geniqup@8c0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0 0x008c0000 0 0x6000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ iommus = <&apps_smmu 0x3 0x0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ i2c0: i2c@880000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00880000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c0_default>;
+ interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 0 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c1: i2c@884000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00884000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c1_default>;
+ interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 1 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c2: i2c@888000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00888000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c2_default>;
+ interrupts = <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 2 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c3: i2c@88c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x0088c000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c3_default>;
+ interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 3 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c4: i2c@890000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00890000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c4_default>;
+ interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 4 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c5: i2c@894000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00894000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c5_default>;
+ interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 5 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c6: i2c@898000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00898000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c6_default>;
+ interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 6 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c7: i2c@89c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x0089c000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c7_default>;
+ interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 7 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+ };
+
+ gpi_dma1: dma-controller@a00000 {
+ #dma-cells = <3>;
+ compatible = "qcom,sdm670-gpi-dma", "qcom,sdm845-gpi-dma";
+ reg = <0 0x00a00000 0 0x60000>;
+ interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <13>;
+ dma-channel-mask = <0xfa>;
+ iommus = <&apps_smmu 0x6d6 0x0>;
+ status = "disabled";
+ };
+
+ qupv3_id_1: geniqup@ac0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0 0x00ac0000 0 0x6000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ iommus = <&apps_smmu 0x6c3 0x0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ i2c8: i2c@a80000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a80000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c8_default>;
+ interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 0 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c9: i2c@a84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a84000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c9_default>;
+ interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 1 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c10: i2c@a88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a88000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c10_default>;
+ interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 2 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c11: i2c@a8c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a8c000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c11_default>;
+ interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 3 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c12: i2c@a90000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a90000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c12_default>;
+ interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 4 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c13: i2c@a94000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a94000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c13_default>;
+ interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 5 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c14: i2c@a98000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a98000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c14_default>;
+ interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 6 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c15: i2c@a9c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0 0x00a9c000 0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c15_default>;
+ interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&rpmhpd SDM670_CX>;
+ dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 7 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+ };
+
+ tlmm: pinctrl@3400000 {
+ compatible = "qcom,sdm670-tlmm";
+ reg = <0 0x03400000 0 0xc00000>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 151>;
+
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup0";
+ };
+
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio17", "gpio18";
+ function = "qup1";
+ };
+
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio27", "gpio28";
+ function = "qup2";
+ };
+
+ qup_i2c3_default: qup-i2c3-default-state {
+ pins = "gpio41", "gpio42";
+ function = "qup3";
+ };
+
+ qup_i2c4_default: qup-i2c4-default-state {
+ pins = "gpio89", "gpio90";
+ function = "qup4";
+ };
+
+ qup_i2c5_default: qup-i2c5-default-state {
+ pins = "gpio85", "gpio86";
+ function = "qup5";
+ };
+
+ qup_i2c6_default: qup-i2c6-default-state {
+ pins = "gpio45", "gpio46";
+ function = "qup6";
+ };
+
+ qup_i2c7_default: qup-i2c7-default-state {
+ pins = "gpio93", "gpio94";
+ function = "qup7";
+ };
+
+ qup_i2c8_default: qup-i2c8-default-state {
+ pins = "gpio65", "gpio66";
+ function = "qup8";
+ };
+
+ qup_i2c9_default: qup-i2c9-default-state {
+ pins = "gpio6", "gpio7";
+ function = "qup9";
+ };
+
+ qup_i2c10_default: qup-i2c10-default-state {
+ pins = "gpio55", "gpio56";
+ function = "qup10";
+ };
+
+ qup_i2c11_default: qup-i2c11-default-state {
+ pins = "gpio31", "gpio32";
+ function = "qup11";
+ };
+
+ qup_i2c12_default: qup-i2c12-default-state {
+ pins = "gpio49", "gpio50";
+ function = "qup12";
+ };
+
+ qup_i2c13_default: qup-i2c13-default-state {
+ pins = "gpio105", "gpio106";
+ function = "qup13";
+ };
+
+ qup_i2c14_default: qup-i2c14-default-state {
+ pins = "gpio33", "gpio34";
+ function = "qup14";
+ };
+
+ qup_i2c15_default: qup-i2c15-default-state {
+ pins = "gpio81", "gpio82";
+ function = "qup15";
+ };
+
+ sdc1_state_on: sdc1-on-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ bias-disable;
+ drive-strength = <16>;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-pull-down;
+ };
+ };
+
+ sdc1_state_off: sdc1-off-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-pull-down;
+ };
+ };
+ };
+
+ usb_1_hsphy: phy@88e2000 {
+ compatible = "qcom,sdm670-qusb2-phy", "qcom,qusb2-v2-phy";
+ reg = <0 0x088e2000 0 0x400>;
+ #phy-cells = <0>;
+
+ clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "cfg_ahb", "ref";
+
+ resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+
+ status = "disabled";
+ };
+
+ usb_1: usb@a6f8800 {
+ compatible = "qcom,sdm670-dwc3", "qcom,dwc3";
+ reg = <0 0x0a6f8800 0 0x400>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ dma-ranges;
+
+ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>,
+ <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_SLEEP_CLK>,
+ <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>;
+ clock-names = "cfg_noc",
+ "core",
+ "iface",
+ "sleep",
+ "mock_utmi";
+
+ assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <150000000>;
+
+ interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 488 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 489 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq",
+ "dm_hs_phy_irq", "dp_hs_phy_irq";
+
+ power-domains = <&gcc USB30_PRIM_GDSC>;
+
+ resets = <&gcc GCC_USB30_PRIM_BCR>;
+
+ status = "disabled";
+
+ usb_1_dwc3: usb@a600000 {
+ compatible = "snps,dwc3";
+ reg = <0 0x0a600000 0 0xcd00>;
+ interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+ iommus = <&apps_smmu 0x740 0>;
+ snps,dis_u2_susphy_quirk;
+ snps,dis_enblslpm_quirk;
+ phys = <&usb_1_hsphy>;
+ phy-names = "usb2-phy";
+ };
+ };
+
+ spmi_bus: spmi@c440000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0 0x0c440000 0 0x1100>,
+ <0 0x0c600000 0 0x2000000>,
+ <0 0x0e600000 0 0x100000>,
+ <0 0x0e700000 0 0xa0000>,
+ <0 0x0c40a000 0 0x26000>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 481 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
+
+ apps_smmu: iommu@15000000 {
+ compatible = "qcom,sdm670-smmu-500", "qcom,smmu-500", "arm,mmu-500";
+ reg = <0 0x15000000 0 0x80000>;
+ #iommu-cells = <2>;
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ apps_rsc: rsc@179c0000 {
+ compatible = "qcom,rpmh-rsc";
+ reg = <0 0x179c0000 0 0x10000>,
+ <0 0x179d0000 0 0x10000>,
+ <0 0x179e0000 0 0x10000>;
+ reg-names = "drv-0", "drv-1", "drv-2";
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ label = "apps_rsc";
+ qcom,tcs-offset = <0xd00>;
+ qcom,drv-id = <2>;
+ qcom,tcs-config = <ACTIVE_TCS 2>,
+ <SLEEP_TCS 3>,
+ <WAKE_TCS 3>,
+ <CONTROL_TCS 1>;
+
+ apps_bcm_voter: bcm-voter {
+ compatible = "qcom,bcm-voter";
+ };
+
+ rpmhcc: clock-controller {
+ compatible = "qcom,sdm670-rpmh-clk";
+ #clock-cells = <1>;
+ clock-names = "xo";
+ clocks = <&xo_board>;
+ };
+
+ rpmhpd: power-controller {
+ compatible = "qcom,sdm670-rpmhpd";
+ #power-domain-cells = <1>;
+ operating-points-v2 = <&rpmhpd_opp_table>;
+
+ rpmhpd_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ rpmhpd_opp_ret: opp1 {
+ opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
+ };
+
+ rpmhpd_opp_min_svs: opp2 {
+ opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ };
+
+ rpmhpd_opp_low_svs: opp3 {
+ opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+ };
+
+ rpmhpd_opp_svs: opp4 {
+ opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+ };
+
+ rpmhpd_opp_svs_l1: opp5 {
+ opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+ };
+
+ rpmhpd_opp_nom: opp6 {
+ opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+ };
+
+ rpmhpd_opp_nom_l1: opp7 {
+ opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
+ };
+
+ rpmhpd_opp_nom_l2: opp8 {
+ opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
+ };
+
+ rpmhpd_opp_turbo: opp9 {
+ opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
+ };
+
+ rpmhpd_opp_turbo_l1: opp10 {
+ opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
+ };
+ };
+ };
+ };
+
+ intc: interrupt-controller@17a00000 {
+ compatible = "arm,gic-v3";
+ reg = <0 0x17a00000 0 0x10000>, /* GICD */
+ <0 0x17a60000 0 0x100000>; /* GICR * 8 */
+ interrupt-controller;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <3>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
index b5eb8f7eca1d..ca676e04687b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
@@ -16,7 +16,7 @@
/ {
aliases {
bluetooth0 = &bluetooth;
- hsuart0 = &uart6;
+ serial1 = &uart6;
serial0 = &uart9;
wifi0 = &wifi;
};
@@ -860,6 +860,8 @@ ap_ts_i2c: &i2c14 {
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth: wcn3990-bt {
compatible = "qcom,wcn3990-bt";
vddio-supply = <&src_pp1800_s4a>;
@@ -1079,41 +1081,6 @@ ap_ts_i2c: &i2c14 {
};
};
-&qup_uart6_default {
- /* Change pinmux to all 4 pins since CTS and RTS are connected */
- pinmux {
- pins = "gpio45", "gpio46",
- "gpio47", "gpio48";
- };
-
- pinconf-cts {
- /*
- * Configure a pull-down on 45 (CTS) to match the pull of
- * the Bluetooth module.
- */
- pins = "gpio45";
- bias-pull-down;
- };
-
- pinconf-rts-tx {
- /* We'll drive 46 (RTS) and 47 (TX), so no pull */
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
- bias-disable;
- };
-
- pinconf-rx {
- /*
- * Configure a pull-up on 48 (RX). This is needed to avoid
- * garbage data when the TX pin of the Bluetooth module is
- * in tri-state (module powered off or not driving the
- * signal yet).
- */
- pins = "gpio48";
- bias-pull-up;
- };
-};
-
&qup_uart9_default {
pinconf-tx {
pins = "gpio4";
@@ -1341,7 +1308,7 @@ ap_ts_i2c: &i2c14 {
};
pen_rst_l: pen-rst-l {
- pinmux {
+ pinmux {
pins = "gpio23";
function = "gpio";
};
@@ -1408,7 +1375,7 @@ ap_ts_i2c: &i2c14 {
};
ts_int_l: ts-int-l {
- pinmux {
+ pinmux {
pins = "gpio125";
function = "gpio";
};
@@ -1420,7 +1387,7 @@ ap_ts_i2c: &i2c14 {
};
ts_reset_l: ts-reset-l {
- pinmux {
+ pinmux {
pins = "gpio118";
function = "gpio";
};
@@ -1436,7 +1403,7 @@ ap_ts_i2c: &i2c14 {
config {
pins = "gpio126";
function = "gpio";
- bias-no-pull;
+ bias-disable;
drive-strength = <2>;
output-low;
};
@@ -1446,7 +1413,7 @@ ap_ts_i2c: &i2c14 {
config {
pins = "gpio126";
function = "gpio";
- bias-no-pull;
+ bias-disable;
drive-strength = <2>;
output-high;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts
new file mode 100644
index 000000000000..a21caa6f3fa2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ */
+
+/dts-v1/;
+
+#include "sdm845-db845c.dts"
+
+&camss {
+ vdda-phy-supply = <&vreg_l1a_0p875>;
+ vdda-pll-supply = <&vreg_l26a_1p2>;
+
+ status = "okay";
+
+ ports {
+ port@0 {
+ csiphy0_ep: endpoint {
+ data-lanes = <0 1 2 3>;
+ remote-endpoint = <&ov8856_ep>;
+ };
+ };
+ };
+};
+
+&cci {
+ status = "okay";
+};
+
+&cci_i2c0 {
+ camera@10 {
+ compatible = "ovti,ov8856";
+ reg = <0x10>;
+
+ /* CAM0_RST_N */
+ reset-gpios = <&tlmm 9 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cam0_default>;
+
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "xvclk";
+ clock-frequency = <19200000>;
+
+ /*
+ * The &vreg_s4a_1p8 trace is powered on as a,
+ * so it is represented by a fixed regulator.
+ *
+ * The 2.8V vdda-supply and 1.2V vddd-supply regulators
+ * both have to be enabled through the power management
+ * gpios.
+ */
+ dovdd-supply = <&vreg_lvs1a_1p8>;
+ avdd-supply = <&cam0_avdd_2v8>;
+ dvdd-supply = <&cam0_dvdd_1v2>;
+
+ port {
+ ov8856_ep: endpoint {
+ link-frequencies = /bits/ 64
+ <360000000 180000000>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csiphy0_ep>;
+ };
+ };
+ };
+};
+
+&cci_i2c1 {
+ camera@60 {
+ compatible = "ovti,ov7251";
+
+ /* I2C address as per ov7251.txt linux documentation */
+ reg = <0x60>;
+
+ /* CAM3_RST_N */
+ enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cam3_default>;
+
+ clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+ clock-names = "xclk";
+ clock-frequency = <24000000>;
+
+ /*
+ * The &vreg_s4a_1p8 trace always powered on.
+ *
+ * The 2.8V vdda-supply regulator is enabled when the
+ * vreg_s4a_1p8 trace is pulled high.
+ * It too is represented by a fixed regulator.
+ *
+ * No 1.2V vddd-supply regulator is used.
+ */
+ vdddo-supply = <&vreg_lvs1a_1p8>;
+ vdda-supply = <&cam3_avdd_2v8>;
+
+ status = "disabled";
+
+ port {
+ ov7251_ep: endpoint {
+ data-lanes = <0 1>;
+/* remote-endpoint = <&csiphy3_ep>; */
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
index 132417e2d11e..f41c6d600ea8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -22,7 +22,7 @@
aliases {
serial0 = &uart9;
- hsuart0 = &uart6;
+ serial1 = &uart6;
};
chosen {
@@ -120,9 +120,11 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- // TODO: make it possible to drive same GPIO from two clients
- // gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
- // enable-active-high;
+ /*
+ * TODO: make it possible to drive same GPIO from two clients
+ * gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+ * enable-active-high;
+ */
};
pcie0_1p05v: pcie-0-1p05v-regulator {
@@ -133,9 +135,11 @@
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
- // TODO: make it possible to drive same GPIO from two clients
- // gpio = <&tlmm 90 GPIO_ACTIVE_HIGH>;
- // enable-active-high;
+ /*
+ * TODO: make it possible to drive same GPIO from two clients
+ * gpio = <&tlmm 90 GPIO_ACTIVE_HIGH>;
+ * enable-active-high;
+ */
};
cam0_dvdd_1v2: reg_cam0_dvdd_1v2 {
@@ -195,9 +199,11 @@
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <500000>;
- // TODO: make it possible to drive same GPIO from two clients
- // gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
- // enable-active-high;
+ /*
+ * TODO: make it possible to drive same GPIO from two clients
+ * gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+ * enable-active-high;
+ */
};
vbat: vbat-regulator {
@@ -649,9 +655,13 @@
};
};
+&pmi8998_rradc {
+ status = "okay";
+};
+
/* QUAT I2S Uses 4 I2S SD Lines for audio on LT9611 HDMI Bridge */
&q6afedai {
- qi2s@22 {
+ dai@22 {
reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0 1 2 3>;
};
@@ -986,6 +996,8 @@
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth {
compatible = "qcom,wcn3990-bt";
@@ -1076,7 +1088,7 @@
status = "okay";
};
-&wcd9340{
+&wcd9340 {
pinctrl-0 = <&wcd_intr_default>;
pinctrl-names = "default";
clock-names = "extclk";
@@ -1089,7 +1101,7 @@
vdd-io-supply = <&vreg_s4a_1p8>;
swm: swm@c85 {
- left_spkr: wsa8810-left{
+ left_spkr: speaker@0,1 {
compatible = "sdw10217201000";
reg = <0 1>;
powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>;
@@ -1098,7 +1110,7 @@
#sound-dai-cells = <0>;
};
- right_spkr: wsa8810-right{
+ right_spkr: speaker@0,2 {
compatible = "sdw10217201000";
powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>;
reg = <0 2>;
@@ -1123,10 +1135,13 @@
/* PINCTRL - additions to nodes defined in sdm845.dtsi */
&qup_spi2_default {
- drive-strength = <16>;
+ pinconf {
+ pins = "gpio27", "gpio28", "gpio29", "gpio30";
+ drive-strength = <16>;
+ };
};
-&qup_uart3_default{
+&qup_uart3_default {
pinmux {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "qup3";
@@ -1141,29 +1156,6 @@
};
};
-&qup_uart6_default {
- pinmux {
- pins = "gpio45", "gpio46", "gpio47", "gpio48";
- function = "qup6";
- };
-
- cts {
- pins = "gpio45";
- bias-disable;
- };
-
- rts-tx {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
- bias-disable;
- };
-
- rx {
- pins = "gpio48";
- bias-pull-up;
- };
-};
-
&qup_uart9_default {
pinconf-tx {
pins = "gpio4";
@@ -1182,105 +1174,6 @@
};
-&cci {
- status = "okay";
-};
-
-&camss {
- vdda-phy-supply = <&vreg_l1a_0p875>;
- vdda-pll-supply = <&vreg_l26a_1p2>;
-
- status = "ok";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 {
- reg = <0>;
- csiphy0_ep: endpoint {
- data-lanes = <0 1 2 3>;
- remote-endpoint = <&ov8856_ep>;
- };
- };
- };
-};
-
-&cci_i2c0 {
- camera@10 {
- compatible = "ovti,ov8856";
- reg = <0x10>;
-
- // CAM0_RST_N
- reset-gpios = <&tlmm 9 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&cam0_default>;
-
- clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
- clock-names = "xvclk";
- clock-frequency = <19200000>;
-
- /* The &vreg_s4a_1p8 trace is powered on as a,
- * so it is represented by a fixed regulator.
- *
- * The 2.8V vdda-supply and 1.2V vddd-supply regulators
- * both have to be enabled through the power management
- * gpios.
- */
- dovdd-supply = <&vreg_lvs1a_1p8>;
- avdd-supply = <&cam0_avdd_2v8>;
- dvdd-supply = <&cam0_dvdd_1v2>;
-
- status = "ok";
-
- port {
- ov8856_ep: endpoint {
- link-frequencies = /bits/ 64
- <360000000 180000000>;
- data-lanes = <1 2 3 4>;
- remote-endpoint = <&csiphy0_ep>;
- };
- };
- };
-};
-
-&cci_i2c1 {
- camera@60 {
- compatible = "ovti,ov7251";
-
- // I2C address as per ov7251.txt linux documentation
- reg = <0x60>;
-
- // CAM3_RST_N
- enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&cam3_default>;
-
- clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
- clock-names = "xclk";
- clock-frequency = <24000000>;
-
- /* The &vreg_s4a_1p8 trace always powered on.
- *
- * The 2.8V vdda-supply regulator is enabled when the
- * vreg_s4a_1p8 trace is pulled high.
- * It too is represented by a fixed regulator.
- *
- * No 1.2V vddd-supply regulator is used.
- */
- vdddo-supply = <&vreg_lvs1a_1p8>;
- vdda-supply = <&cam3_avdd_2v8>;
-
- status = "disable";
-
- port {
- ov7251_ep: endpoint {
- data-lanes = <0 1>;
-// remote-endpoint = <&csiphy3_ep>;
- };
- };
- };
-};
-
/* PINCTRL - additions to nodes defined in sdm845.dtsi */
&qup_spi0_default {
config {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi
index 20f275f8694d..1eb423e4be24 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi
@@ -604,7 +604,7 @@
};
&pm8998_gpio {
- vol_up_pin_a: vol-up-active-pins {
+ vol_up_pin_a: vol-up-active-state {
pins = "gpio6";
function = "normal";
input-enable;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
index 392461c29e76..42cf4dd5ea28 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
@@ -19,7 +19,7 @@
/ {
aliases {
serial0 = &uart9;
- hsuart0 = &uart6;
+ serial1 = &uart6;
};
chosen {
@@ -50,7 +50,8 @@
};
reserved-memory {
- /* The rmtfs_mem needs to be guarded due to "XPU limitations"
+ /*
+ * The rmtfs_mem needs to be guarded due to "XPU limitations"
* it is otherwise possible for an allocation adjacent to the
* rmtfs_mem region to trigger an XPU violation, causing a crash.
*/
@@ -433,7 +434,7 @@
status = "okay";
};
-/* Modem/wifi*/
+/* Modem/wifi */
&mss_pil {
status = "okay";
firmware-name = "qcom/sdm845/oneplus6/mba.mbn", "qcom/sdm845/oneplus6/modem.mbn";
@@ -461,6 +462,10 @@
};
};
+&pmi8998_rradc {
+ status = "okay";
+};
+
&qupv3_id_1 {
status = "okay";
};
@@ -500,35 +505,11 @@
};
};
-/*
- * Prevent garbage data on bluetooth UART lines
- */
-&qup_uart6_default {
- pinmux {
- pins = "gpio45", "gpio46", "gpio47", "gpio48";
- function = "qup6";
- };
-
- cts {
- pins = "gpio45";
- bias-pull-down;
- };
-
- rts-tx {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
- bias-disable;
- };
-
- rx {
- pins = "gpio48";
- bias-pull-up;
- };
-};
-
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth {
compatible = "qcom,wcn3990-bt";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts
new file mode 100644
index 000000000000..e742c27fe91f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SDM845 Samsung S9 (SM-G9600) (starqltechn / star2qltechn) common device tree source
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include "sdm845.dtsi"
+
+/ {
+ chassis-type = "handset";
+ model = "Samsung Galaxy S9 SM-G9600";
+ compatible = "samsung,starqltechn", "qcom,sdm845";
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ framebuffer: framebuffer@9d400000 {
+ compatible = "simple-framebuffer";
+ reg = <0 0x9d400000 0 (2960 * 1440 * 4)>;//2400000
+ width = <1440>;
+ height = <2960>;
+ stride = <(1440 * 4)>;
+ format = "a8r8g8b8";
+ };
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ };
+
+ /*
+ * Apparently RPMh does not provide support for PM8998 S4 because it
+ * is always-on; model it as a fixed regulator.
+ */
+ vreg_s4a_1p8: pm8998-smps4 {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_s4a_1p8";
+
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+
+ vin-supply = <&vph_pwr>;
+ };
+
+ reserved-memory {
+ memory@9d400000 {
+ reg = <0x0 0x9d400000 0x0 0x02400000>;
+ no-map;
+ };
+
+ memory@a1300000 {
+ compatible = "ramoops";
+ reg = <0x0 0xa1300000 0x0 0x100000>;
+ record-size = <0x40000>;
+ console-size = <0x40000>;
+ ftrace-size = <0x40000>;
+ pmsg-size = <0x40000>;
+ };
+ };
+};
+
+
+&apps_rsc {
+ pm8998-rpmh-regulators {
+ compatible = "qcom,pm8998-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+ vdd-s11-supply = <&vph_pwr>;
+ vdd-s12-supply = <&vph_pwr>;
+ vdd-s13-supply = <&vph_pwr>;
+ vdd-l1-l27-supply = <&vreg_s7a_1p025>;
+ vdd-l2-l8-l17-supply = <&vreg_s3a_1p35>;
+ vdd-l3-l11-supply = <&vreg_s7a_1p025>;
+ vdd-l4-l5-supply = <&vreg_s7a_1p025>;
+ vdd-l6-supply = <&vph_pwr>;
+ vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p04>;
+ vdd-l26-supply = <&vreg_s3a_1p35>;
+ vin-lvs-1-2-supply = <&vreg_s4a_1p8>;
+
+ vreg_s2a_1p125: smps2 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ vreg_s3a_1p35: smps3 {
+ regulator-min-microvolt = <1352000>;
+ regulator-max-microvolt = <1352000>;
+ };
+
+ vreg_s5a_2p04: smps5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ vreg_s7a_1p025: smps7 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1028000>;
+ };
+
+ vdd_qusb_hs0:
+ vdda_hp_pcie_core:
+ vdda_mipi_csi0_0p9:
+ vdda_mipi_csi1_0p9:
+ vdda_mipi_csi2_0p9:
+ vdda_mipi_dsi0_pll:
+ vdda_mipi_dsi1_pll:
+ vdda_qlink_lv:
+ vdda_qlink_lv_ck:
+ vdda_qrefs_0p875:
+ vdda_pcie_core:
+ vdda_pll_cc_ebi01:
+ vdda_pll_cc_ebi23:
+ vdda_sp_sensor:
+ vdda_ufs1_core:
+ vdda_ufs2_core:
+ vdda_usb1_ss_core:
+ vdda_usb2_ss_core:
+ vreg_l1a_0p875: ldo1 {
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vddpx_10:
+ vreg_l2a_1p2: ldo2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-always-on;
+ };
+
+ vreg_l3a_1p0: ldo3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vdd_wcss_cx:
+ vdd_wcss_mx:
+ vdda_wcss_pll:
+ vreg_l5a_0p8: ldo5 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vddpx_13:
+ vreg_l6a_1p8: ldo6 {
+ regulator-min-microvolt = <1856000>;
+ regulator-max-microvolt = <1856000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7a_1p8: ldo7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8a_1p2: ldo8 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1248000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9a_1p8: ldo9 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <2928000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l10a_1p8: ldo10 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <2928000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l11a_1p0: ldo11 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1048000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vdd_qfprom:
+ vdd_qfprom_sp:
+ vdda_apc1_cs_1p8:
+ vdda_gfx_cs_1p8:
+ vdda_qrefs_1p8:
+ vdda_qusb_hs0_1p8:
+ vddpx_11:
+ vreg_l12a_1p8: ldo12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vddpx_2:
+ vreg_l13a_2p95: ldo13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l14a_1p88: ldo14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l15a_1p8: ldo15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l16a_2p7: ldo16 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17a_1p3: ldo17 {
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l18a_2p7: ldo18 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l19a_3p0: ldo19 {
+ regulator-min-microvolt = <2856000>;
+ regulator-max-microvolt = <3104000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l20a_2p95: ldo20 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l21a_2p95: ldo21 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l22a_2p85: ldo22 {
+ regulator-min-microvolt = <2864000>;
+ regulator-max-microvolt = <3312000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l23a_3p3: ldo23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3312000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vdda_qusb_hs0_3p1:
+ vreg_l24a_3p075: ldo24 {
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3088000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l25a_3p3: ldo25 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3312000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vdda_hp_pcie_1p2:
+ vdda_hv_ebi0:
+ vdda_hv_ebi1:
+ vdda_hv_ebi2:
+ vdda_hv_ebi3:
+ vdda_mipi_csi_1p25:
+ vdda_mipi_dsi0_1p2:
+ vdda_mipi_dsi1_1p2:
+ vdda_pcie_1p2:
+ vdda_ufs1_1p2:
+ vdda_ufs2_1p2:
+ vdda_usb1_ss_1p2:
+ vdda_usb2_ss_1p2:
+ vreg_l26a_1p2: ldo26 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l28a_3p0: ldo28 {
+ regulator-min-microvolt = <2856000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_lvs1a_1p8: lvs1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_lvs2a_1p8: lvs2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+
+ pm8005-rpmh-regulators {
+ compatible = "qcom,pm8005-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+
+ vreg_s3c_0p6: smps3 {
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <600000>;
+ };
+ };
+};
+
+&gcc {
+ protected-clocks = <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+ <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+ <GCC_LPASS_Q6_AXI_CLK>,
+ <GCC_LPASS_SWAY_CLK>;
+};
+
+&i2c10 {
+ clock-frequency = <400000>;
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&uart9 {
+ status = "okay";
+};
+
+&ufs_mem_hc {
+ reset-gpios = <&tlmm 150 GPIO_ACTIVE_LOW>;
+ vcc-supply = <&vreg_l20a_2p95>;
+ vcc-max-microamp = <600000>;
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ vdda-phy-supply = <&vdda_ufs1_core>;
+ vdda-pll-supply = <&vdda_ufs1_1p2>;
+ status = "okay";
+};
+
+&sdhc_2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdc2_clk_state &sdc2_cmd_state &sdc2_data_state &sd_card_det_n_state>;
+ cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&vreg_l21a_2p95>;
+ vqmmc-supply = <&vddpx_2>;
+ status = "okay";
+};
+
+&usb_1 {
+ status = "okay";
+};
+
+&usb_1_dwc3 {
+ /* Until we have Type C hooked up we'll force this as peripheral. */
+ dr_mode = "peripheral";
+};
+
+&usb_1_hsphy {
+ vdd-supply = <&vdda_usb1_ss_core>;
+ vdda-pll-supply = <&vdda_qusb_hs0_1p8>;
+ vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>;
+
+ qcom,imp-res-offset-value = <8>;
+ qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_21_6_MA>;
+ qcom,preemphasis-level = <QUSB2_V2_PREEMPHASIS_5_PERCENT>;
+ qcom,preemphasis-width = <QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT>;
+ status = "okay";
+};
+
+&usb_1_qmpphy {
+ vdda-phy-supply = <&vdda_usb1_ss_1p2>;
+ vdda-pll-supply = <&vdda_usb1_ss_core>;
+ status = "okay";
+};
+
+&wifi {
+ vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+ vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+ vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+ vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+ status = "okay";
+};
+
+&tlmm {
+ gpio-reserved-ranges = <0 4>, <27 4>, <81 4>, <85 4>;
+
+ sdc2_clk_state: sdc2-clk-state {
+ pins = "sdc2_clk";
+ bias-disable;
+
+ /*
+ * It seems that mmc_test reports errors if drive
+ * strength is not 16 on clk, cmd, and data pins.
+ */
+ drive-strength = <16>;
+ };
+
+ sdc2_cmd_state: sdc2-cmd-state {
+ pins = "sdc2_cmd";
+ bias-pull-up;
+ drive-strength = <16>;
+ };
+
+ sdc2_data_state: sdc2-data-state {
+ pins = "sdc2_data";
+ bias-pull-up;
+ drive-strength = <16>;
+ };
+
+ sd_card_det_n_state: sd-card-det-n-state {
+ pins = "gpio126";
+ function = "gpio";
+ bias-pull-up;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
index 83261c9bb4f2..bb77ccfdc68c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
@@ -23,6 +23,7 @@
aliases {
display0 = &framebuffer0;
serial0 = &uart9;
+ serial1 = &uart6;
};
chosen {
@@ -693,9 +694,17 @@
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth {
compatible = "qcom,wcn3990-bt";
+ /*
+ * This path is relative to the qca/
+ * subdir under lib/firmware.
+ */
+ firmware-name = "axolotl/crnv21.bin";
+
vddio-supply = <&vreg_s4a_1p8>;
vddxo-supply = <&vreg_l7a_1p8>;
vddrf-supply = <&vreg_l17a_1p3>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi
index 51ee42e3c995..87dd0fc36747 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi
@@ -376,7 +376,7 @@
pinctrl-names = "default";
bus-width = <4>;
no-sdio;
- no-emmc;
+ no-mmc;
};
&tlmm {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
index 0f470cf1ed1c..eb6b2b676eca 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
@@ -26,8 +26,6 @@
/delete-node/ &rmtfs_mem;
/ {
- model = "Xiaomi Pocophone F1";
- compatible = "xiaomi,beryllium", "qcom,sdm845";
chassis-type = "handset";
/* required for bootloader to select correct board */
@@ -35,7 +33,7 @@
qcom,msm-id = <321 0x20001>;
aliases {
- hsuart0 = &uart6;
+ serial1 = &uart6;
};
gpio-keys {
@@ -221,8 +219,7 @@
status = "okay";
vdda-supply = <&vreg_l26a_1p2>;
- panel@0 {
- compatible = "tianma,fhd-video";
+ display_panel: panel@0 {
reg = <0>;
vddio-supply = <&vreg_l14a_1p8>;
vddpos-supply = <&lab>;
@@ -234,8 +231,10 @@
backlight = <&pmi8998_wled>;
reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;
+ status = "disabled";
+
port {
- tianma_nt36672a_in_0: endpoint {
+ panel_in_0: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
@@ -243,7 +242,7 @@
};
&dsi0_out {
- remote-endpoint = <&tianma_nt36672a_in_0>;
+ remote-endpoint = <&panel_in_0>;
data-lanes = <0 1 2 3>;
};
@@ -336,9 +335,13 @@
};
};
+&pmi8998_rradc {
+ status = "okay";
+};
+
/* QUAT I2S Uses 1 I2S SD Line for audio on TAS2559/60 amplifiers */
&q6afedai {
- qi2s@22 {
+ dai@22 {
reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
@@ -481,6 +484,8 @@
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth {
compatible = "qcom,wcn3990-bt";
@@ -567,28 +572,3 @@
vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
vdd-3.3-ch1-supply = <&vreg_l23a_3p3>;
};
-
-/* PINCTRL - additions to nodes defined in sdm845.dtsi */
-
-&qup_uart6_default {
- pinmux {
- pins = "gpio45", "gpio46", "gpio47", "gpio48";
- function = "qup6";
- };
-
- cts {
- pins = "gpio45";
- bias-disable;
- };
-
- rts-tx {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
- bias-disable;
- };
-
- rx {
- pins = "gpio48";
- bias-pull-up;
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts
new file mode 100644
index 000000000000..76931ebad065
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+#include "sdm845-xiaomi-beryllium-common.dtsi"
+
+/ {
+ model = "Xiaomi Pocophone F1 (EBBG)";
+ compatible = "xiaomi,beryllium-ebbg", "qcom,sdm845";
+};
+
+&display_panel {
+ compatible = "ebbg,ft8719";
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-tianma.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-tianma.dts
new file mode 100644
index 000000000000..8e176111e599
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-tianma.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+#include "sdm845-xiaomi-beryllium-common.dtsi"
+
+/ {
+ model = "Xiaomi Pocophone F1 (Tianma)";
+ compatible = "xiaomi,beryllium", "qcom,sdm845";
+};
+
+&display_panel {
+ compatible = "tianma,fhd-video";
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts
index afc17e4d403f..38ba809a95cd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts
@@ -456,9 +456,6 @@
&i2c14 {
clock-frequency = <400000>;
- dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>,
- <&gpi_dma1 1 6 QCOM_GPI_I2C>;
- dma-names = "tx", "rx";
status = "okay";
touchscreen@20 {
@@ -544,8 +541,8 @@
};
&q6afedai {
- qi2s@22 {
- reg = <22>;
+ dai@22 {
+ reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
};
@@ -628,7 +625,7 @@
};
wcd_intr_default: wcd-intr-default {
- pins = "goui54";
+ pins = "gpio54";
function = "gpio";
input-enable;
bias-pull-down;
@@ -639,6 +636,8 @@
&uart6 {
status = "okay";
+ pinctrl-0 = <&qup_uart6_4pin>;
+
bluetooth {
compatible = "qcom,wcn3990-bt";
@@ -735,28 +734,3 @@
qcom,snoc-host-cap-skip-quirk;
status = "okay";
};
-
-/* PINCTRL - additions to nodes defined in sdm845.dtsi */
-
-&qup_uart6_default {
- pinmux {
- pins = "gpio45", "gpio46", "gpio47", "gpio48";
- function = "qup6";
- };
-
- cts {
- pins = "gpio45";
- bias-disable;
- };
-
- rts-tx {
- pins = "gpio46", "gpio47";
- drive-strength = <2>;
- bias-disable;
- };
-
- rx {
- pins = "gpio48";
- bias-pull-up;
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index d761da47220d..65032b94b46d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -767,13 +767,13 @@
#size-cells = <0>;
qcom,intents = <512 20>;
- apr-service@3 {
+ service@3 {
reg = <APR_SVC_ADSP_CORE>;
compatible = "qcom,q6core";
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
- q6afe: apr-service@4 {
+ q6afe: service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -785,7 +785,7 @@
};
};
- q6asm: apr-service@7 {
+ q6asm: service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -798,7 +798,7 @@
};
};
- q6adm: apr-service@8 {
+ q6adm: service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -3008,6 +3008,28 @@
};
};
+ qup_uart6_4pin: qup-uart6-4pin-state {
+
+ cts-pins {
+ pins = "gpio45";
+ function = "qup6";
+ bias-pull-down;
+ };
+
+ rts-tx-pins {
+ pins = "gpio46", "gpio47";
+ function = "qup6";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ rx-pins {
+ pins = "gpio48";
+ function = "qup6";
+ bias-pull-up;
+ };
+ };
+
qup_uart7_default: qup-uart7-default {
pinmux {
pins = "gpio95", "gpio96";
@@ -3823,33 +3845,29 @@
status = "disabled";
};
- slim: slim@171c0000 {
+ slim: slim-ngd@171c0000 {
compatible = "qcom,slim-ngd-v2.1.0";
reg = <0 0x171c0000 0 0x2c000>;
interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
- qcom,apps-ch-pipes = <0x780000>;
- qcom,ea-pc = <0x270>;
- status = "okay";
- dmas = <&slimbam 3>, <&slimbam 4>,
- <&slimbam 5>, <&slimbam 6>;
- dma-names = "rx", "tx", "tx2", "rx2";
+ dmas = <&slimbam 3>, <&slimbam 4>;
+ dma-names = "rx", "tx";
iommus = <&apps_smmu 0x1806 0x0>;
#address-cells = <1>;
#size-cells = <0>;
- ngd@1 {
+ slim@1 {
reg = <1>;
#address-cells = <2>;
#size-cells = <0>;
- wcd9340_ifd: ifd@0{
+ wcd9340_ifd: ifd@0,0 {
compatible = "slim217,250";
reg = <0 0>;
};
- wcd9340: codec@1{
+ wcd9340: codec@1,0 {
compatible = "slim217,250";
reg = <1 0>;
slim-ifc-dev = <&wcd9340_ifd>;
@@ -3959,9 +3977,10 @@
};
usb_1_qmpphy: phy@88e9000 {
- compatible = "qcom,sdm845-qmp-usb3-phy";
+ compatible = "qcom,sdm845-qmp-usb3-dp-phy";
reg = <0 0x088e9000 0 0x18c>,
- <0 0x088e8000 0 0x10>;
+ <0 0x088e8000 0 0x38>,
+ <0 0x088ea000 0 0x40>;
status = "disabled";
#address-cells = <2>;
#size-cells = <2>;
@@ -3973,11 +3992,11 @@
<&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>;
clock-names = "aux", "cfg_ahb", "ref", "com_aux";
- resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>,
- <&gcc GCC_USB3_PHY_PRIM_BCR>;
+ resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
+ <&gcc GCC_USB3_DP_PHY_PRIM_BCR>;
reset-names = "phy", "common";
- usb_1_ssphy: phy@88e9200 {
+ usb_1_ssphy: usb3-phy@88e9200 {
reg = <0 0x088e9200 0 0x128>,
<0 0x088e9400 0 0x200>,
<0 0x088e9c00 0 0x218>,
@@ -3990,6 +4009,16 @@
clock-names = "pipe0";
clock-output-names = "usb3_phy_pipe_clk_src";
};
+
+ dp_phy: dp-phy@88ea200 {
+ reg = <0 0x088ea200 0 0x200>,
+ <0 0x088ea400 0 0x200>,
+ <0 0x088eaa00 0 0x200>,
+ <0 0x088ea600 0 0x200>,
+ <0 0x088ea800 0 0x200>;
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+ };
};
usb_2_qmpphy: phy@88eb000 {
@@ -4339,6 +4368,22 @@
ports {
#address-cells = <1>;
#size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+
+ port@1 {
+ reg = <1>;
+ };
+
+ port@2 {
+ reg = <2>;
+ };
+
+ port@3 {
+ reg = <3>;
+ };
};
};
@@ -4483,13 +4528,20 @@
port@0 {
reg = <0>;
- dpu_intf1_out: endpoint {
- remote-endpoint = <&dsi0_in>;
+ dpu_intf0_out: endpoint {
+ remote-endpoint = <&dp_in>;
};
};
port@1 {
reg = <1>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
dpu_intf2_out: endpoint {
remote-endpoint = <&dsi1_in>;
};
@@ -4521,6 +4573,77 @@
};
};
+ mdss_dp: displayport-controller@ae90000 {
+ status = "disabled";
+ compatible = "qcom,sdm845-dp";
+
+ reg = <0 0xae90000 0 0x200>,
+ <0 0xae90200 0 0x200>,
+ <0 0xae90400 0 0x600>,
+ <0 0xae90a00 0 0x600>,
+ <0 0xae91000 0 0x600>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <12>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>;
+ clock-names = "core_iface", "core_aux", "ctrl_link",
+ "ctrl_link_iface", "stream_pixel";
+ #clock-cells = <1>;
+ assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
+ assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>;
+ phys = <&dp_phy>;
+ phy-names = "dp";
+
+ operating-points-v2 = <&dp_opp_table>;
+ power-domains = <&rpmhpd SDM845_CX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ dp_in: endpoint {
+ remote-endpoint = <&dpu_intf0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dp_out: endpoint { };
+ };
+ };
+
+ dp_opp_table: dp-opp-table {
+ compatible = "operating-points-v2";
+
+ opp-162000000 {
+ opp-hz = /bits/ 64 <162000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-270000000 {
+ opp-hz = /bits/ 64 <270000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-540000000 {
+ opp-hz = /bits/ 64 <540000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
+ };
+
dsi0: dsi@ae94000 {
compatible = "qcom,mdss-dsi-ctrl";
reg = <0 0x0ae94000 0 0x400>;
@@ -4548,7 +4671,6 @@
power-domains = <&rpmhpd SDM845_CX>;
phys = <&dsi0_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -4574,7 +4696,7 @@
};
};
- dsi0_phy: dsi-phy@ae94400 {
+ dsi0_phy: phy@ae94400 {
compatible = "qcom,dsi-phy-10nm";
reg = <0 0x0ae94400 0 0x200>,
<0 0x0ae94600 0 0x280>,
@@ -4620,7 +4742,6 @@
power-domains = <&rpmhpd SDM845_CX>;
phys = <&dsi1_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -4646,7 +4767,7 @@
};
};
- dsi1_phy: dsi-phy@ae96400 {
+ dsi1_phy: phy@ae96400 {
compatible = "qcom,dsi-phy-10nm";
reg = <0 0x0ae96400 0 0x200>,
<0 0x0ae96600 0 0x280>,
@@ -4812,8 +4933,8 @@
<&dsi0_phy 1>,
<&dsi1_phy 0>,
<&dsi1_phy 1>,
- <0>,
- <0>;
+ <&dp_phy 0>,
+ <&dp_phy 1>;
clock-names = "bi_tcxo",
"gcc_disp_gpll0_clk_src",
"gcc_disp_gpll0_div_clk_src",
@@ -5197,7 +5318,7 @@
};
osm_l3: interconnect@17d41000 {
- compatible = "qcom,sdm845-osm-l3";
+ compatible = "qcom,sdm845-osm-l3", "qcom,osm-l3";
reg = <0 0x17d41000 0 0x1400>;
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
index be59a8ba9c1f..f32b7445f7c9 100644
--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
@@ -487,8 +487,10 @@
};
&qup_i2c12_default {
- drive-strength = <2>;
- bias-disable;
+ pinmux {
+ drive-strength = <2>;
+ bias-disable;
+ };
};
&qup_uart6_default {
@@ -783,7 +785,7 @@
qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
swm: swm@c85 {
- left_spkr: wsa8810-left{
+ left_spkr: speaker@0,3 {
compatible = "sdw10217211000";
reg = <0 3>;
powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>;
@@ -792,7 +794,7 @@
#sound-dai-cells = <0>;
};
- right_spkr: wsa8810-right{
+ right_spkr: speaker@0,4 {
compatible = "sdw10217211000";
powerdown-gpios = <&wcdgpio 2 GPIO_ACTIVE_HIGH>;
reg = <0 4>;
diff --git a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts
index f954fe5cb61a..daca1e0ad62a 100644
--- a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts
+++ b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts
@@ -43,7 +43,7 @@
#size-cells = <2>;
ranges;
- // Firmware initialized the display at 1280p instead of 1440p
+ /* Firmware initialized the display at 1280p instead of 1440p */
framebuffer0: framebuffer@80400000 {
compatible = "simple-framebuffer";
reg = <0 0x80400000 0 (1920 * 1280 * 4)>;
@@ -124,7 +124,7 @@
};
&adsp_pas {
- firmware-name = "qcom/samsung/w737/qcadsp850.mbn";
+ firmware-name = "qcom/sdm850/samsung/w737/qcadsp850.mbn";
status = "okay";
};
@@ -336,7 +336,7 @@
};
&cdsp_pas {
- firmware-name = "qcom/samsung/w737/qccdsp850.mbn";
+ firmware-name = "qcom/sdm850/samsung/w737/qccdsp850.mbn";
status = "okay";
};
@@ -385,7 +385,7 @@
&ipa {
status = "okay";
memory-region = <&ipa_fw_mem>;
- firmware-name = "qcom/samsung/w737/ipa_fws.elf";
+ firmware-name = "qcom/sdm850/samsung/w737/ipa_fws.elf";
};
/* No idea why it causes an SError when enabled */
@@ -395,7 +395,7 @@
&mss_pil {
status = "okay";
- firmware-name = "qcom/samsung/w737/qcdsp1v2850.mbn", "qcom/samsung/w737/qcdsp2850.mbn";
+ firmware-name = "qcom/sdm850/samsung/w737/qcdsp1v2850.mbn", "qcom/sdm850/samsung/w737/qcdsp2850.mbn";
};
&qup_i2c10_default {
@@ -415,8 +415,10 @@
};
&qup_i2c12_default {
- drive-strength = <2>;
- bias-disable;
+ pinmux {
+ drive-strength = <2>;
+ bias-disable;
+ };
};
&qup_uart6_default {
@@ -574,7 +576,7 @@
};
pen_rst_l: pen-rst-l {
- pinmux {
+ pinmux {
pins = "gpio21";
function = "gpio";
};
@@ -696,7 +698,7 @@
&venus {
status = "okay";
- firmware-name = "qcom/samsung/w737/qcvss850.mbn";
+ firmware-name = "qcom/sdm850/samsung/w737/qcvss850.mbn";
};
&wcd9340{
@@ -715,7 +717,7 @@
qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
swm: swm@c85 {
- left_spkr: wsa8810-left{
+ left_spkr: speaker@0,3 {
compatible = "sdw10217211000";
reg = <0 3>;
powerdown-gpios = <&wcdgpio 1 GPIO_ACTIVE_HIGH>;
@@ -724,7 +726,7 @@
#sound-dai-cells = <0>;
};
- right_spkr: wsa8810-right{
+ right_spkr: speaker@0,4 {
compatible = "sdw10217211000";
powerdown-gpios = <&wcdgpio 2 GPIO_ACTIVE_HIGH>;
reg = <0 4>;
diff --git a/arch/arm64/boot/dts/qcom/sm4250-oneplus-billie2.dts b/arch/arm64/boot/dts/qcom/sm4250-oneplus-billie2.dts
new file mode 100644
index 000000000000..a3f1c7c41fd7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm4250-oneplus-billie2.dts
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021, Iskren Chernev <iskren.chernev@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "sm4250.dtsi"
+
+/ {
+ model = "OnePlus Nord N100";
+ compatible = "oneplus,billie2", "qcom,sm4250";
+
+ /* required for bootloader to select correct board */
+ qcom,msm-id = <0x1a1 0x10000 0x1bc 0x10000>;
+ qcom,board-id = <0x1000b 0x00>;
+
+ aliases {
+ };
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ stdout-path = "framebuffer0";
+
+ framebuffer0: framebuffer@9d400000 {
+ compatible = "simple-framebuffer";
+ reg = <0 0x5c000000 0 (1600 * 720 * 4)>;
+ width = <720>;
+ height = <1600>;
+ stride = <(720 * 4)>;
+ format = "a8r8g8b8";
+ };
+ };
+};
+
+&reserved_memory {
+ bootloader_log_mem: memory@5fff7000 {
+ reg = <0x0 0x5fff7000 0x0 0x8000>;
+ no-map;
+ };
+
+ ramoops@cbe00000 {
+ compatible = "ramoops";
+ reg = <0x0 0xcbe00000 0x0 0x400000>;
+ record-size = <0x40000>;
+ pmsg-size = <0x200000>;
+ console-size = <0x40000>;
+ ftrace-size = <0x40000>;
+ };
+
+ param_mem: memory@cc200000 {
+ reg = <0x0 0xcc200000 0x0 0x100000>;
+ no-map;
+ };
+
+ mtp_mem: memory@cc300000 {
+ reg = <0x00 0xcc300000 0x00 0xb00000>;
+ no-map;
+ };
+};
+
+&rpm_requests {
+ regulators-0 {
+ compatible = "qcom,rpm-pm6125-regulators";
+
+ vreg_s6a: s6 {
+ regulator-min-microvolt = <320000>;
+ regulator-max-microvolt = <1456000>;
+ };
+
+ vreg_s7a: s7 {
+ regulator-min-microvolt = <1280000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ vreg_s8a: s8 {
+ regulator-min-microvolt = <1064000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ vreg_l1a: l1 {
+ regulator-min-microvolt = <952000>;
+ regulator-max-microvolt = <1152000>;
+ };
+
+ vreg_l4a: l4 {
+ regulator-min-microvolt = <488000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ vreg_l5a: l5 {
+ regulator-min-microvolt = <1648000>;
+ regulator-max-microvolt = <3056000>;
+ };
+
+ vreg_l6a: l6 {
+ regulator-min-microvolt = <576000>;
+ regulator-max-microvolt = <656000>;
+ };
+
+ vreg_l7a: l7 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ vreg_l8a: l8 {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <728000>;
+ };
+
+ vreg_l9a: l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ };
+
+ vreg_l10a: l10 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <1904000>;
+ };
+
+ vreg_l11a: l11 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <1952000>;
+ };
+
+ vreg_l12a: l12 {
+ regulator-min-microvolt = <1624000>;
+ regulator-max-microvolt = <1984000>;
+ };
+
+ vreg_l13a: l13 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <1952000>;
+ };
+
+ vreg_l14a: l14 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <1904000>;
+ };
+
+ vreg_l15a: l15 {
+ regulator-min-microvolt = <2920000>;
+ regulator-max-microvolt = <3232000>;
+ };
+
+ vreg_l16a: l16 {
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <1904000>;
+ };
+
+ vreg_l17a: l17 {
+ regulator-min-microvolt = <1152000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ vreg_l18a: l18 {
+ regulator-min-microvolt = <1104000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ vreg_l19a: l19 {
+ regulator-min-microvolt = <1624000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ vreg_l20a: l20 {
+ regulator-min-microvolt = <1624000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ vreg_l21a: l21 {
+ regulator-min-microvolt = <2400000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ vreg_l22a: l22 {
+ regulator-min-microvolt = <2952000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ vreg_l23a: l23 {
+ regulator-min-microvolt = <3296000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ vreg_l24a: l24 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <3544000>;
+ };
+ };
+};
+
+&sleep_clk {
+ clock-frequency = <32764>;
+};
+
+&sdhc_2 {
+ vmmc-supply = <&vreg_l22a>;
+ vqmmc-supply = <&vreg_l5a>;
+
+ cd-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>;
+
+ status = "okay";
+};
+
+&tlmm {
+ gpio-reserved-ranges = <14 4>;
+};
+
+&ufs_mem_hc {
+ vcc-supply = <&vreg_l24a>;
+ vcc-max-microamp = <600000>;
+ vccq2-supply = <&vreg_l11a>;
+ vccq2-max-microamp = <600000>;
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ vdda-phy-supply = <&vreg_l4a>;
+ vdda-pll-supply = <&vreg_l12a>;
+ vddp-ref-clk-supply = <&vreg_l18a>;
+ status = "okay";
+};
+
+&usb_1 {
+ status = "okay";
+};
+
+&usb_1_hsphy {
+ vdd-supply = <&vreg_l4a>;
+ vdda-pll-supply = <&vreg_l12a>;
+ vdda-phy-dpdm-supply = <&vreg_l15a>;
+ status = "okay";
+};
+
+&xo_board {
+ clock-frequency = <19200000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sm4250.dtsi b/arch/arm64/boot/dts/qcom/sm4250.dtsi
new file mode 100644
index 000000000000..c5add8f44fc0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm4250.dtsi
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021, Iskren Chernev <iskren.chernev@gmail.com>
+ */
+
+#include "sm6115.dtsi"
+
+&CPU0 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU1 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU2 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU3 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU4 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU5 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU6 {
+ compatible = "qcom,kryo240";
+};
+
+&CPU7 {
+ compatible = "qcom,kryo240";
+};
diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi
new file mode 100644
index 000000000000..572bf04adf90
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi
@@ -0,0 +1,1425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021, Iskren Chernev <iskren.chernev@gmail.com>
+ */
+
+#include <dt-bindings/clock/qcom,gcc-sm6115.h>
+#include <dt-bindings/clock/qcom,sm6115-dispcc.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/dma/qcom-gpi.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+
+/ {
+ interrupt-parent = <&intc>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen { };
+
+ clocks {
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x0>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ enable-method = "psci";
+ next-level-cache = <&L2_0>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ L2_0: l2-cache {
+ compatible = "cache";
+ cache-level = <2>;
+ };
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x1>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ enable-method = "psci";
+ next-level-cache = <&L2_0>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ };
+
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x2>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ enable-method = "psci";
+ next-level-cache = <&L2_0>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ };
+
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x3>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ enable-method = "psci";
+ next-level-cache = <&L2_0>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ };
+
+ CPU4: cpu@100 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ capacity-dmips-mhz = <1638>;
+ dynamic-power-coefficient = <282>;
+ next-level-cache = <&L2_1>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ L2_1: l2-cache {
+ compatible = "cache";
+ cache-level = <2>;
+ };
+ };
+
+ CPU5: cpu@101 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x101>;
+ capacity-dmips-mhz = <1638>;
+ dynamic-power-coefficient = <282>;
+ enable-method = "psci";
+ next-level-cache = <&L2_1>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ };
+
+ CPU6: cpu@102 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x102>;
+ capacity-dmips-mhz = <1638>;
+ dynamic-power-coefficient = <282>;
+ enable-method = "psci";
+ next-level-cache = <&L2_1>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ };
+
+ CPU7: cpu@103 {
+ device_type = "cpu";
+ compatible = "qcom,kryo260";
+ reg = <0x0 0x103>;
+ capacity-dmips-mhz = <1638>;
+ dynamic-power-coefficient = <282>;
+ enable-method = "psci";
+ next-level-cache = <&L2_1>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ };
+
+ 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>;
+ };
+ };
+ };
+ };
+
+ firmware {
+ scm: scm {
+ compatible = "qcom,scm-sm6115", "qcom,scm";
+ #reset-cells = <1>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the size */
+ reg = <0 0x80000000 0 0>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ reserved_memory: reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ hyp_mem: memory@45700000 {
+ reg = <0x0 0x45700000 0x0 0x600000>;
+ no-map;
+ };
+
+ xbl_aop_mem: memory@45e00000 {
+ reg = <0x0 0x45e00000 0x0 0x140000>;
+ no-map;
+ };
+
+ sec_apps_mem: memory@45fff000 {
+ reg = <0x0 0x45fff000 0x0 0x1000>;
+ no-map;
+ };
+
+ smem_mem: memory@46000000 {
+ compatible = "qcom,smem";
+ reg = <0x0 0x46000000 0x0 0x200000>;
+ no-map;
+
+ hwlocks = <&tcsr_mutex 3>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ };
+
+ cdsp_sec_mem: memory@46200000 {
+ reg = <0x0 0x46200000 0x0 0x1e00000>;
+ no-map;
+ };
+
+ pil_modem_mem: memory@4ab00000 {
+ reg = <0x0 0x4ab00000 0x0 0x6900000>;
+ no-map;
+ };
+
+ pil_video_mem: memory@51400000 {
+ reg = <0x0 0x51400000 0x0 0x500000>;
+ no-map;
+ };
+
+ wlan_msa_mem: memory@51900000 {
+ reg = <0x0 0x51900000 0x0 0x100000>;
+ no-map;
+ };
+
+ pil_cdsp_mem: memory@51a00000 {
+ reg = <0x0 0x51a00000 0x0 0x1e00000>;
+ no-map;
+ };
+
+ pil_adsp_mem: memory@53800000 {
+ reg = <0x0 0x53800000 0x0 0x2800000>;
+ no-map;
+ };
+
+ pil_ipa_fw_mem: memory@56100000 {
+ reg = <0x0 0x56100000 0x0 0x10000>;
+ no-map;
+ };
+
+ pil_ipa_gsi_mem: memory@56110000 {
+ reg = <0x0 0x56110000 0x0 0x5000>;
+ no-map;
+ };
+
+ pil_gpu_mem: memory@56115000 {
+ reg = <0x0 0x56115000 0x0 0x2000>;
+ no-map;
+ };
+
+ cont_splash_memory: memory@5c000000 {
+ reg = <0x0 0x5c000000 0x0 0x00f00000>;
+ no-map;
+ };
+
+ dfps_data_memory: memory@5cf00000 {
+ reg = <0x0 0x5cf00000 0x0 0x0100000>;
+ no-map;
+ };
+
+ removed_mem: memory@60000000 {
+ reg = <0x0 0x60000000 0x0 0x3900000>;
+ no-map;
+ };
+ };
+
+ rpm-glink {
+ compatible = "qcom,glink-rpm";
+
+ interrupts = <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ mboxes = <&apcs_glb 0>;
+
+ rpm_requests: rpm-requests {
+ compatible = "qcom,rpm-sm6115";
+ qcom,glink-channels = "rpm_requests";
+
+ rpmcc: clock-controller {
+ compatible = "qcom,rpmcc-sm6115", "qcom,rpmcc";
+ #clock-cells = <1>;
+ };
+
+ rpmpd: power-controller {
+ compatible = "qcom,sm6115-rpmpd";
+ #power-domain-cells = <1>;
+ operating-points-v2 = <&rpmpd_opp_table>;
+
+ rpmpd_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ rpmpd_opp_min_svs: opp1 {
+ opp-level = <RPM_SMD_LEVEL_MIN_SVS>;
+ };
+
+ rpmpd_opp_low_svs: opp2 {
+ opp-level = <RPM_SMD_LEVEL_LOW_SVS>;
+ };
+
+ rpmpd_opp_svs: opp3 {
+ opp-level = <RPM_SMD_LEVEL_SVS>;
+ };
+
+ rpmpd_opp_svs_plus: opp4 {
+ opp-level = <RPM_SMD_LEVEL_SVS_PLUS>;
+ };
+
+ rpmpd_opp_nom: opp5 {
+ opp-level = <RPM_SMD_LEVEL_NOM>;
+ };
+
+ rpmpd_opp_nom_plus: opp6 {
+ opp-level = <RPM_SMD_LEVEL_NOM_PLUS>;
+ };
+
+ rpmpd_opp_turbo: opp7 {
+ opp-level = <RPM_SMD_LEVEL_TURBO>;
+ };
+
+ rpmpd_opp_turbo_plus: opp8 {
+ opp-level = <RPM_SMD_LEVEL_TURBO_NO_CPR>;
+ };
+ };
+ };
+ };
+ };
+
+ soc: soc@0 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+
+ tcsr_mutex: hwlock@340000 {
+ compatible = "qcom,tcsr-mutex";
+ reg = <0x00340000 0x20000>;
+ #hwlock-cells = <1>;
+ };
+
+ tlmm: pinctrl@500000 {
+ compatible = "qcom,sm6115-tlmm";
+ reg = <0x00500000 0x400000>, <0x00900000 0x400000>, <0x00d00000 0x400000>;
+ reg-names = "west", "south", "east";
+ interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ gpio-ranges = <&tlmm 0 0 121>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup0";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio4", "gpio5";
+ function = "qup1";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio6", "gpio7";
+ function = "qup2";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c3_default: qup-i2c3-default-state {
+ pins = "gpio8", "gpio9";
+ function = "qup3";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c4_default: qup-i2c4-default-state {
+ pins = "gpio12", "gpio13";
+ function = "qup4";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c5_default: qup-i2c5-default-state {
+ pins = "gpio14", "gpio15";
+ function = "qup5";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi0_default: qup-spi0-default-state {
+ pins = "gpio0", "gpio1","gpio2", "gpio3";
+ function = "qup0";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi1_default: qup-spi1-default-state {
+ pins = "gpio4", "gpio5", "gpio69", "gpio70";
+ function = "qup1";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi2_default: qup-spi2-default-state {
+ pins = "gpio6", "gpio7", "gpio71", "gpio80";
+ function = "qup2";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi3_default: qup-spi3-default-state {
+ pins = "gpio8", "gpio9", "gpio10", "gpio11";
+ function = "qup3";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi4_default: qup-spi4-default-state {
+ pins = "gpio12", "gpio13", "gpio96", "gpio97";
+ function = "qup4";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi5_default: qup-spi5-default-state {
+ pins = "gpio14", "gpio15", "gpio16", "gpio17";
+ function = "qup5";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ sdc1_state_on: sdc1-on-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ bias-disable;
+ drive-strength = <16>;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-pull-down;
+ };
+ };
+
+ sdc1_state_off: sdc1-off-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-pull-down;
+ };
+ };
+
+ sdc2_state_on: sdc2-on-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ bias-disable;
+ drive-strength = <16>;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ bias-pull-up;
+ drive-strength = <10>;
+ };
+
+ sd-cd-pins {
+ pins = "gpio88";
+ function = "gpio";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+ };
+
+ sdc2_state_off: sdc2-off-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ sd-cd-pins {
+ pins = "gpio88";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ };
+ };
+ };
+
+ gcc: clock-controller@1400000 {
+ compatible = "qcom,gcc-sm6115";
+ reg = <0x01400000 0x1f0000>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&sleep_clk>;
+ clock-names = "bi_tcxo", "sleep_clk";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+ usb_1_hsphy: phy@1613000 {
+ compatible = "qcom,sm6115-qusb2-phy";
+ reg = <0x01613000 0x180>;
+ #phy-cells = <0>;
+
+ clocks = <&gcc GCC_AHB2PHY_USB_CLK>, <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "cfg_ahb", "ref";
+
+ resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+ nvmem-cells = <&qusb2_hstx_trim>;
+
+ status = "disabled";
+ };
+
+ qfprom@1b40000 {
+ compatible = "qcom,sm6115-qfprom", "qcom,qfprom";
+ reg = <0x01b40000 0x7000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qusb2_hstx_trim: hstx-trim@25b {
+ reg = <0x25b 0x1>;
+ bits = <1 4>;
+ };
+ };
+
+ rng: rng@1b53000 {
+ compatible = "qcom,prng-ee";
+ reg = <0x01b53000 0x1000>;
+ clocks = <&gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "core";
+ };
+
+ spmi_bus: spmi@1c40000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x01c40000 0x1100>,
+ <0x01e00000 0x2000000>,
+ <0x03e00000 0x100000>,
+ <0x03f00000 0xa0000>,
+ <0x01c0a000 0x26000>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
+
+ tsens0: thermal-sensor@4410000 {
+ compatible = "qcom,sm6115-tsens", "qcom,tsens-v2";
+ reg = <0x04411000 0x1ff>, /* TM */
+ <0x04410000 0x8>; /* SROT */
+ #qcom,sensors = <16>;
+ interrupts = <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "uplow", "critical";
+ #thermal-sensor-cells = <1>;
+ };
+
+ rpm_msg_ram: sram@45f0000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x045f0000 0x7000>;
+ };
+
+ sram@4690000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x04690000 0x10000>;
+ };
+
+ sdhc_1: mmc@4744000 {
+ compatible = "qcom,sm6115-sdhci", "qcom,sdhci-msm-v5";
+ reg = <0x04744000 0x1000>, <0x04745000 0x1000>, <0x04748000 0x8000>;
+ reg-names = "hc", "cqhci", "ice";
+
+ interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+ <&gcc GCC_SDCC1_APPS_CLK>,
+ <&xo_board>,
+ <&gcc GCC_SDCC1_ICE_CORE_CLK>;
+ clock-names = "iface", "core", "xo", "ice";
+
+ pinctrl-0 = <&sdc1_state_on>;
+ pinctrl-1 = <&sdc1_state_off>;
+ pinctrl-names = "default", "sleep";
+
+ bus-width = <8>;
+ status = "disabled";
+ };
+
+ sdhc_2: mmc@4784000 {
+ compatible = "qcom,sm6115-sdhci", "qcom,sdhci-msm-v5";
+ reg = <0x04784000 0x1000>;
+ reg-names = "hc";
+
+ interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC2_AHB_CLK>, <&gcc GCC_SDCC2_APPS_CLK>, <&xo_board>;
+ clock-names = "iface", "core", "xo";
+
+ pinctrl-0 = <&sdc2_state_on>;
+ pinctrl-1 = <&sdc2_state_off>;
+ pinctrl-names = "default", "sleep";
+
+ power-domains = <&rpmpd SM6115_VDDCX>;
+ operating-points-v2 = <&sdhc2_opp_table>;
+ iommus = <&apps_smmu 0x00a0 0x0>;
+ resets = <&gcc GCC_SDCC2_BCR>;
+
+ bus-width = <4>;
+ qcom,dll-config = <0x0007642c>;
+ qcom,ddr-config = <0x80040868>;
+ status = "disabled";
+
+ sdhc2_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-202000000 {
+ opp-hz = /bits/ 64 <202000000>;
+ required-opps = <&rpmpd_opp_nom>;
+ };
+ };
+ };
+
+ ufs_mem_hc: ufs@4804000 {
+ compatible = "qcom,sm6115-ufshc", "qcom,ufshc", "jedec,ufs-2.0";
+ reg = <0x04804000 0x3000>, <0x04810000 0x8000>;
+ interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&ufs_mem_phy_lanes>;
+ phy-names = "ufsphy";
+ lanes-per-direction = <1>;
+ #reset-cells = <1>;
+ resets = <&gcc GCC_UFS_PHY_BCR>;
+ reset-names = "rst";
+
+ power-domains = <&gcc GCC_UFS_PHY_GDSC>;
+ iommus = <&apps_smmu 0x100 0>;
+
+ clocks = <&gcc GCC_UFS_PHY_AXI_CLK>,
+ <&gcc GCC_SYS_NOC_UFS_PHY_AXI_CLK>,
+ <&gcc GCC_UFS_PHY_AHB_CLK>,
+ <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
+ <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
+ <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
+ clock-names = "core_clk",
+ "bus_aggr_clk",
+ "iface_clk",
+ "core_clk_unipro",
+ "ref_clk",
+ "tx_lane0_sync_clk",
+ "rx_lane0_sync_clk",
+ "ice_core_clk";
+
+ freq-table-hz = <50000000 200000000>,
+ <0 0>,
+ <0 0>,
+ <37500000 150000000>,
+ <75000000 300000000>,
+ <0 0>,
+ <0 0>,
+ <0 0>;
+
+ status = "disabled";
+ };
+
+ ufs_mem_phy: phy@4807000 {
+ compatible = "qcom,sm6115-qmp-ufs-phy";
+ reg = <0x04807000 0x1c4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ clocks = <&gcc GCC_UFS_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+ clock-names = "ref", "ref_aux";
+
+ resets = <&ufs_mem_hc 0>;
+ reset-names = "ufsphy";
+ status = "disabled";
+
+ ufs_mem_phy_lanes: phy@4807400 {
+ reg = <0x4807400 0x098>,
+ <0x4807600 0x130>,
+ <0x4807c00 0x16c>;
+ #phy-cells = <0>;
+ };
+ };
+
+ gpi_dma0: dma-controller@4a00000 {
+ compatible = "qcom,sm6115-gpi-dma", "qcom,sm6350-gpi-dma";
+ reg = <0x04a00000 0x60000>;
+ interrupts = <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <10>;
+ dma-channel-mask = <0xf>;
+ iommus = <&apps_smmu 0xf6 0x0>;
+ #dma-cells = <3>;
+ status = "disabled";
+ };
+
+ qupv3_id_0: geniqup@4ac0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0x04ac0000 0x2000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ iommus = <&apps_smmu 0xe3 0x0>;
+ ranges;
+ status = "disabled";
+
+ i2c0: i2c@4a80000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a80000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c0_default>;
+ interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 0 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi0: spi@4a80000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a80000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi0_default>;
+ interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 0 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@4a84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a84000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c1_default>;
+ interrupts = <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 1 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@4a84000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a84000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi1_default>;
+ interrupts = <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 1 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@4a88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a88000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c2_default>;
+ interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 2 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi2: spi@4a88000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a88000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi2_default>;
+ interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 2 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@4a8c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a8c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c3_default>;
+ interrupts = <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 3 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi3: spi@4a8c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a8c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi3_default>;
+ interrupts = <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 3 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@4a90000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a90000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c4_default>;
+ interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 4 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi4: spi@4a90000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a90000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi4_default>;
+ interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 4 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@4a94000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x04a94000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c5_default>;
+ interrupts = <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 5 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi5: spi@4a94000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x04a94000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi5_default>;
+ interrupts = <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 5 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ usb_1: usb@4ef8800 {
+ compatible = "qcom,sm6115-dwc3", "qcom,dwc3";
+ reg = <0x04ef8800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>,
+ <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_SLEEP_CLK>,
+ <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB3_PRIM_CLKREF_CLK>;
+ clock-names = "cfg_noc", "core", "iface", "sleep", "mock_utmi", "xo";
+
+ assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <66666667>;
+
+ interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq";
+
+ resets = <&gcc GCC_USB30_PRIM_BCR>;
+ power-domains = <&gcc GCC_USB30_PRIM_GDSC>;
+ qcom,select-utmi-as-pipe-clk;
+ status = "disabled";
+
+ usb_1_dwc3: usb@4e00000 {
+ compatible = "snps,dwc3";
+ reg = <0x04e00000 0xcd00>;
+ interrupts = <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb_1_hsphy>;
+ phy-names = "usb2-phy";
+ iommus = <&apps_smmu 0x120 0x0>;
+ snps,dis_u2_susphy_quirk;
+ snps,dis_enblslpm_quirk;
+ snps,has-lpm-erratum;
+ snps,hird-threshold = /bits/ 8 <0x10>;
+ snps,usb3_lpm_capable;
+ maximum-speed = "high-speed";
+ dr_mode = "peripheral";
+ };
+ };
+
+ mdss: display-subsystem@5e00000 {
+ compatible = "qcom,sm6115-mdss";
+ reg = <0x05e00000 0x1000>;
+ reg-names = "mdss";
+
+ power-domains = <&dispcc MDSS_GDSC>;
+
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+
+ interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ iommus = <&apps_smmu 0x420 0x2>,
+ <&apps_smmu 0x421 0x0>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ status = "disabled";
+
+ mdp: display-controller@5e01000 {
+ compatible = "qcom,sm6115-dpu";
+ reg = <0x05e01000 0x8f000>,
+ <0x05eb0000 0x2008>;
+ reg-names = "mdp", "vbif";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "bus",
+ "iface",
+ "core",
+ "lut",
+ "rot",
+ "vsync";
+
+ operating-points-v2 = <&mdp_opp_table>;
+ power-domains = <&rpmpd SM6115_VDDCX>;
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+
+ mdp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-19200000 {
+ opp-hz = /bits/ 64 <19200000>;
+ required-opps = <&rpmpd_opp_min_svs>;
+ };
+
+ opp-192000000 {
+ opp-hz = /bits/ 64 <192000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-256000000 {
+ opp-hz = /bits/ 64 <256000000>;
+ required-opps = <&rpmpd_opp_svs>;
+ };
+
+ opp-307200000 {
+ opp-hz = /bits/ 64 <307200000>;
+ required-opps = <&rpmpd_opp_svs_plus>;
+ };
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ required-opps = <&rpmpd_opp_nom>;
+ };
+ };
+ };
+
+ dsi0: dsi@5e94000 {
+ compatible = "qcom,dsi-ctrl-6g-qcm2290";
+ reg = <0x05e94000 0x400>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
+
+ operating-points-v2 = <&dsi_opp_table>;
+ power-domains = <&rpmpd SM6115_VDDCX>;
+ phys = <&dsi0_phy>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+
+ dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-19200000 {
+ opp-hz = /bits/ 64 <19200000>;
+ required-opps = <&rpmpd_opp_min_svs>;
+ };
+
+ opp-164000000 {
+ opp-hz = /bits/ 64 <164000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmpd_opp_svs>;
+ };
+ };
+ };
+
+ dsi0_phy: phy@5e94400 {
+ compatible = "qcom,dsi-phy-14nm-2290";
+ reg = <0x05e94400 0x100>,
+ <0x05e94500 0x300>,
+ <0x05e94800 0x188>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "ref";
+
+ status = "disabled";
+ };
+ };
+
+ dispcc: clock-controller@5f00000 {
+ compatible = "qcom,sm6115-dispcc";
+ reg = <0x05f00000 0x20000>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&sleep_clk>,
+ <&dsi0_phy 0>,
+ <&dsi0_phy 1>,
+ <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+ apps_smmu: iommu@c600000 {
+ compatible = "qcom,sm6115-smmu-500", "qcom,smmu-500", "arm,mmu-500";
+ reg = <0x0c600000 0x80000>;
+ #iommu-cells = <2>;
+ #global-interrupts = <1>;
+
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wifi: wifi@c800000 {
+ compatible = "qcom,wcn3990-wifi";
+ reg = <0x0c800000 0x800000>;
+ reg-names = "membase";
+ memory-region = <&wlan_msa_mem>;
+ interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>;
+ iommus = <&apps_smmu 0x1a0 0x1>;
+ qcom,msa-fixed-perm;
+ status = "disabled";
+ };
+
+ apcs_glb: mailbox@f111000 {
+ compatible = "qcom,sm6115-apcs-hmss-global";
+ reg = <0x0f111000 0x1000>;
+
+ #mbox-cells = <1>;
+ };
+
+ timer@f120000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0f120000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <19200000>;
+
+ frame@f121000 {
+ reg = <0x0f121000 0x1000>, <0x0f122000 0x1000>;
+ frame-number = <0>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ frame@f123000 {
+ reg = <0x0f123000 0x1000>;
+ frame-number = <1>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ frame@f124000 {
+ reg = <0x0f124000 0x1000>;
+ frame-number = <2>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ frame@f125000 {
+ reg = <0x0f125000 0x1000>;
+ frame-number = <3>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ frame@f126000 {
+ reg = <0x0f126000 0x1000>;
+ frame-number = <4>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ frame@f127000 {
+ reg = <0x0f127000 0x1000>;
+ frame-number = <5>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ frame@f128000 {
+ reg = <0x0f128000 0x1000>;
+ frame-number = <6>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
+
+ intc: interrupt-controller@f200000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0f200000 0x10000>, <0x0f300000 0x100000>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #redistributor-regions = <1>;
+ redistributor-stride = <0x0 0x20000>;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ cpufreq_hw: cpufreq@f521000 {
+ compatible = "qcom,cpufreq-hw";
+ reg = <0x0f521000 0x1000>, <0x0f523000 0x1000>;
+
+ reg-names = "freq-domain0", "freq-domain1";
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gcc GPLL0>;
+ clock-names = "xo", "alternate";
+
+ #freq-domain-cells = <1>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 0 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts b/arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts
index 6a8b88cc4385..0de6c5b7f742 100644
--- a/arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts
+++ b/arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts
@@ -6,9 +6,10 @@
/dts-v1/;
#include "sm6125.dtsi"
+#include "pm6125.dtsi"
#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
/ {
/* required for bootloader to select correct board */
@@ -80,15 +81,175 @@
no-map;
};
};
+
+ thermal-zones {
+ rf-pa0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm6125_adc_tm 0>;
+
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+ };
+
+ quiet-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <5000>;
+ thermal-sensors = <&pm6125_adc_tm 1>;
+
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+ };
+
+ xo-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm6125_adc_tm 2>;
+
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+ };
+
+ rf-pa1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm6125_adc_tm 3>;
+
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+ };
+ };
};
&hsusb_phy1 {
status = "okay";
};
+&pm6125_adc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_flash_therm &emmc_ufs_therm &rf_pa1_therm>;
+
+ rf-pa0-therm@4d {
+ reg = <ADC5_AMUX_THM1_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ quiet-therm@4e {
+ reg = <ADC5_AMUX_THM2_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ camera-flash-therm@52 {
+ reg = <ADC5_GPIO1_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ emmc-ufs-therm@54 {
+ reg = <ADC5_GPIO3_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+
+ rf-pa1-therm@55 {
+ reg = <ADC5_GPIO4_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time = <200>;
+ qcom,pre-scaling = <1 1>;
+ };
+};
+
+&pm6125_adc_tm {
+ status = "okay";
+
+ rf-pa0-therm@0 {
+ reg = <0>;
+ io-channels = <&pm6125_adc ADC5_AMUX_THM1_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time-us = <200>;
+ };
+
+ quiet-therm@1 {
+ reg = <1>;
+ io-channels = <&pm6125_adc ADC5_AMUX_THM2_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time-us = <200>;
+ };
+
+ xo-therm@2 {
+ reg = <2>;
+ io-channels = <&pm6125_adc ADC5_XO_THERM_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time-us = <200>;
+ };
+
+ rf-pa1-therm@3 {
+ reg = <3>;
+ io-channels = <&pm6125_adc ADC5_GPIO4_100K_PU>;
+ qcom,ratiometric;
+ qcom,hw-settle-time-us = <200>;
+ };
+};
+
+&pm6125_gpio {
+ camera_flash_therm: camera-flash-therm-state {
+ pins = "gpio3";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ bias-high-impedance;
+ };
+
+ emmc_ufs_therm: emmc-ufs-therm-state {
+ pins = "gpio6";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ bias-high-impedance;
+ };
+
+ rf_pa1_therm: rf-pa1-therm-state {
+ pins = "gpio7";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ bias-high-impedance;
+ };
+};
+
+&pon_pwrkey {
+ status = "okay";
+};
+
+&pon_resin {
+ status = "okay";
+ linux,code = <KEY_VOLUMEUP>;
+};
+
&sdc2_off_state {
sd-cd-pins {
pins = "gpio98";
+ function = "gpio";
drive-strength = <2>;
bias-disable;
};
@@ -97,6 +258,7 @@
&sdc2_on_state {
sd-cd-pins {
pins = "gpio98";
+ function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi
index 1fe3fa3ad877..7e25a4f85594 100644
--- a/arch/arm64/boot/dts/qcom/sm6125.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi
@@ -407,13 +407,13 @@
};
sdc2_on_state: sdc2-on-state {
- clk {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <16>;
bias-disable;
};
- cmd-pins-pins {
+ cmd-pins {
pins = "sdc2_cmd";
drive-strength = <10>;
bias-pull-up;
@@ -458,7 +458,7 @@
sdhc_1: mmc@4744000 {
compatible = "qcom,sm6125-sdhci", "qcom,sdhci-msm-v5";
reg = <0x04744000 0x1000>, <0x04745000 0x1000>;
- reg-names = "hc", "core";
+ reg-names = "hc", "cqhci";
interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
@@ -476,6 +476,8 @@
bus-width = <8>;
non-removable;
+ supports-cqe;
+
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sm6350-sony-xperia-lena-pdx213.dts b/arch/arm64/boot/dts/qcom/sm6350-sony-xperia-lena-pdx213.dts
index 36911b9a5c04..94f77d376662 100644
--- a/arch/arm64/boot/dts/qcom/sm6350-sony-xperia-lena-pdx213.dts
+++ b/arch/arm64/boot/dts/qcom/sm6350-sony-xperia-lena-pdx213.dts
@@ -4,7 +4,10 @@
*/
/dts-v1/;
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include "sm6350.dtsi"
+#include "pm6350.dtsi"
/ {
model = "Sony Xperia 10 III";
@@ -28,16 +31,348 @@
clocks = <&gcc GCC_DISP_AXI_CLK>;
};
};
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_keys_state>;
+
+ key-volume-down {
+ label = "volume_down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ touch_en_vreg: touch-en-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "touch_en_vreg";
+ gpio = <&tlmm 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ vin-supply = <&pm6350_l6>;
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm6350-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ pm6350_s1: smps1 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_s2: smps2 {
+ regulator-min-microvolt = <1503000>;
+ regulator-max-microvolt = <2048000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l2: ldo2 {
+ regulator-min-microvolt = <1503000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l3: ldo3 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l4: ldo4 {
+ regulator-min-microvolt = <352000>;
+ regulator-max-microvolt = <801000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l5: ldo5 {
+ regulator-min-microvolt = <1503000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l6: ldo6 {
+ regulator-min-microvolt = <1710000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l7: ldo7 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l8: ldo8 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l9: ldo9 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3401000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l11: ldo11 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l12: ldo12 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l13: ldo13 {
+ regulator-min-microvolt = <570000>;
+ regulator-max-microvolt = <650000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l14: ldo14 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l15: ldo15 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1305000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l16: ldo16 {
+ regulator-min-microvolt = <830000>;
+ regulator-max-microvolt = <921000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l18: ldo18 {
+ regulator-min-microvolt = <788000>;
+ regulator-max-microvolt = <1049000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l19: ldo19 {
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1305000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l20: ldo20 {
+ regulator-min-microvolt = <530000>;
+ regulator-max-microvolt = <801000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l21: ldo21 {
+ regulator-min-microvolt = <751000>;
+ regulator-max-microvolt = <825000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6350_l22: ldo22 {
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1305000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm6150l-rpmh-regulators";
+ qcom,pmic-id = "e";
+
+ pm6150l_s8: smps8 {
+ regulator-min-microvolt = <313000>;
+ regulator-max-microvolt = <1395000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l1: ldo1 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l2: ldo2 {
+ regulator-min-microvolt = <1170000>;
+ regulator-max-microvolt = <1305000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l3: ldo3 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1299000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l4: ldo4 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l5: ldo5 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l6: ldo6 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+
+ };
+
+ pm6150l_l7: ldo7 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l8: ldo8 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l9: ldo9 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+
+ };
+
+ pm6150l_l10: ldo10 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3401000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_l11: ldo11 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3401000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm6150l_bob: bob {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <5492000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ regulator-allow-bypass;
+ };
+ };
+};
+
+&gpi_dma0 {
+ status = "okay";
+};
+
+&gpi_dma1 {
+ status = "okay";
+};
+
+&i2c8 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ touchscreen@48 {
+ compatible = "samsung,s6sy761";
+ reg = <0x48>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <22 0x2008>;
+ vdd-supply = <&pm6350_l11>;
+ avdd-supply = <&touch_en_vreg>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_int_default &ts_active>;
+ };
+};
+
+&pm6350_gpios {
+ gpio_keys_state: gpio-keys-state {
+ key-volume-down-pins {
+ pins = "gpio2";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ power-source = <0>;
+ bias-disable;
+ input-enable;
+ };
+ };
+};
+
+&pm6350_resin {
+ linux,code = <KEY_VOLUMEUP>;
+ status = "okay";
+};
+
+&qupv3_id_0 {
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&sdc2_off_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&sdc2_on_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
};
&sdhc_2 {
status = "okay";
+ vmmc-supply = <&pm6150l_l9>;
+ vqmmc-supply = <&pm6150l_l6>;
+
cd-gpios = <&tlmm 94 GPIO_ACTIVE_HIGH>;
};
&tlmm {
gpio-reserved-ranges = <13 4>, <45 2>, <56 2>;
+
+ ts_active: ts-active-state {
+ pins = "gpio21";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+
+ ts_int_default: ts-int-default-state {
+ pins = "gpio22";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
};
&usb_1 {
diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index c39de7d3ace0..43324bf291c3 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -485,11 +485,13 @@
interrupts = <GIC_SPI 641 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 644 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "hc_irq", "pwr_irq";
+ iommus = <&apps_smmu 0x60 0x0>;
clocks = <&gcc GCC_SDCC1_AHB_CLK>,
<&gcc GCC_SDCC1_APPS_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "core", "xo";
+ resets = <&gcc GCC_SDCC1_BCR>;
qcom,dll-config = <0x000f642c>;
qcom,ddr-config = <0x80040868>;
power-domains = <&rpmhpd SM6350_CX>;
@@ -1063,15 +1065,21 @@
interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "hc_irq", "pwr_irq";
+ iommus = <&apps_smmu 0x560 0x0>;
clocks = <&gcc GCC_SDCC2_AHB_CLK>,
<&gcc GCC_SDCC2_APPS_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "core", "xo";
+ resets = <&gcc GCC_SDCC2_BCR>;
interconnects = <&aggre2_noc MASTER_SDCC_2 0 &clk_virt SLAVE_EBI_CH0 0>,
<&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_SDCC_2 0>;
interconnect-names = "sdhc-ddr", "cpu-sdhc";
+ pinctrl-0 = <&sdc2_on_state>;
+ pinctrl-1 = <&sdc2_off_state>;
+ pinctrl-names = "default", "sleep";
+
qcom,dll-config = <0x0007642c>;
qcom,ddr-config = <0x80040868>;
power-domains = <&rpmhpd SM6350_CX>;
@@ -1148,15 +1156,11 @@
dp_phy: dp-phy@88ea200 {
reg = <0 0x088ea200 0 0x200>,
<0 0x088ea400 0 0x200>,
- <0 0x088eac00 0 0x400>,
+ <0 0x088eaa00 0 0x200>,
<0 0x088ea600 0 0x200>,
- <0 0x088ea800 0 0x200>,
- <0 0x088eaa00 0 0x100>;
+ <0 0x088ea800 0 0x200>;
#phy-cells = <0>;
#clock-cells = <1>;
- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
- clock-names = "pipe0";
- clock-output-names = "usb3_phy_pipe_clk_src";
};
};
@@ -1314,6 +1318,46 @@
#interrupt-cells = <2>;
gpio-ranges = <&tlmm 0 0 157>;
+ sdc2_off_state: sdc2-off-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ sdc2_on_state: sdc2-on-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
+
qup_uart9_default: qup-uart9-default-state {
pins = "gpio25", "gpio26";
function = "qup13_f2";
diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts
new file mode 100644
index 000000000000..b691c3834b6b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+/dts-v1/;
+
+/* PMK8350 is configured to use SID6 instead of 0 */
+#define PMK8350_SID 6
+
+#include <dt-bindings/gpio/gpio.h>
+#include "sm6375.dtsi"
+#include "pm6125.dtsi"
+#include "pmk8350.dtsi"
+#include "pmr735a.dtsi"
+
+/* PM6125 PON is used and we can't have duplicate labels */
+/delete-node/ &pmk8350_pon;
+
+/ {
+ model = "Sony Xperia 10 IV";
+ compatible = "sony,pdx225", "qcom,sm6375";
+ chassis-type = "handset";
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ framebuffer: framebuffer@85200000 {
+ compatible = "simple-framebuffer";
+ reg = <0 0x85200000 0 0xc00000>;
+
+ width = <1080>;
+ height = <2520>;
+ stride = <(1080 * 4)>;
+ format = "a8r8g8b8";
+ /*
+ * That's (going to be) a lot of clocks, but it's necessary due
+ * to unused clk cleanup & no panel driver yet
+ */
+ clocks = <&gcc GCC_DISP_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&gcc GCC_DISP_THROTTLE_CORE_CLK>,
+ <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>;
+ };
+ };
+
+ reserved-memory {
+ cont_splash_mem: memory@85200000 {
+ reg = <0 0x85200000 0 0xc00000>;
+ no-map;
+ };
+
+ ramoops@ffc40000 {
+ compatible = "ramoops";
+ reg = <0 0xffc40000 0 0xb0000>;
+ record-size = <0x10000>;
+ console-size = <0x60000>;
+ ftrace-size = <0x10000>;
+ pmsg-size = <0x20000>;
+ ecc-size = <16>;
+ };
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&sdc2_off_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&sdc2_on_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+};
+
+&sdhc_2 {
+ status = "okay";
+
+ vmmc-supply = <&pm6125_l22>;
+ vqmmc-supply = <&pm6125_l5>;
+
+ cd-gpios = <&tlmm 94 GPIO_ACTIVE_HIGH>;
+};
+
+&gpi_dma0 {
+ status = "okay";
+};
+
+&gpi_dma1 {
+ status = "okay";
+};
+
+&i2c8 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ touchscreen@48 {
+ compatible = "samsung,s6sy761";
+ reg = <0x48>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <22 0x2008>;
+
+ vdd-supply = <&pm6125_l13>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_int_default &ts_avdd_default>;
+ };
+};
+
+&pmk8350_adc_tm {
+ status = "okay";
+};
+
+&pmk8350_rtc {
+ status = "okay";
+};
+
+&pon_pwrkey {
+ status = "okay";
+};
+
+&pon_resin {
+ linux,code = <KEY_VOLUMEUP>;
+ status = "okay";
+};
+
+&qupv3_id_0 {
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/Sony/murray/adsp.mbn";
+ status = "okay";
+};
+
+&remoteproc_cdsp {
+ firmware-name = "qcom/Sony/murray/cdsp.mbn";
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators-0 {
+ compatible = "qcom,rpm-pm6125-regulators";
+
+ pm6125_s5: s5 {
+ regulator-min-microvolt = <382000>;
+ regulator-max-microvolt = <1120000>;
+ };
+
+ pm6125_s6: s6 {
+ regulator-min-microvolt = <320000>;
+ regulator-max-microvolt = <1374000>;
+ };
+
+ pm6125_s7: s7 {
+ regulator-min-microvolt = <1574000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ /*
+ * S8 is VDD_GFX
+ * L1 is VDD_LPI_CX
+ */
+
+ pm6125_l2: l2 {
+ regulator-min-microvolt = <1170000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm6125_l3: l3 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm6125_l4: l4 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm6125_l5: l5 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-allow-set-load;
+ };
+
+ pm6125_l6: l6 {
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm6125_l7: l7 {
+ regulator-min-microvolt = <720000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm6125_l8: l8 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm6125_l9: l9 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <2000000>;
+ };
+
+ pm6125_l10: l10 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ };
+
+ pm6125_l11: l11 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ };
+
+ pm6125_l12: l12 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <2000000>;
+ };
+
+ pm6125_l13: l13 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <1980000>;
+ };
+
+ pm6125_l14: l14 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ };
+
+ pm6125_l15: l15 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ pm6125_l16: l16 {
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ };
+
+ /* L17 is VDD_LPI_MX */
+
+ pm6125_l18: l18 {
+ regulator-min-microvolt = <830000>;
+ regulator-max-microvolt = <920000>;
+ };
+
+ pm6125_l19: l19 {
+ regulator-min-microvolt = <1624000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ pm6125_l20: l20 {
+ regulator-min-microvolt = <1624000>;
+ regulator-max-microvolt = <3304000>;
+ };
+
+ pm6125_l21: l21 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3400000>;
+ };
+
+ pm6125_l22: l22 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-allow-set-load;
+ };
+
+ pm6125_l23: l23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3400000>;
+ };
+
+ pm6125_l24: l24 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <3544000>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,rpm-pmr735a-regulators";
+
+ /*
+ * S1 is VDD_MX
+ * S2 is VDD_CX
+ */
+
+ pmr735a_l1: l1 {
+ regulator-min-microvolt = <570000>;
+ regulator-max-microvolt = <650000>;
+ };
+
+ pmr735a_l2: l2 {
+ regulator-min-microvolt = <352000>;
+ regulator-max-microvolt = <796000>;
+ };
+
+ pmr735a_l3: l3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pmr735a_l4: l4 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <2000000>;
+ };
+
+ pmr735a_l5: l5 {
+ regulator-min-microvolt = <751000>;
+ regulator-max-microvolt = <824000>;
+ };
+
+ pmr735a_l6: l6 {
+ regulator-min-microvolt = <504000>;
+ regulator-max-microvolt = <868000>;
+ };
+
+ pmr735a_l7: l7 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ };
+ };
+};
+
+&sdc2_off_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&sdc2_on_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+};
+
+&sdhc_2 {
+ status = "okay";
+
+ vmmc-supply = <&pm6125_l22>;
+ vqmmc-supply = <&pm6125_l5>;
+
+ cd-gpios = <&tlmm 94 GPIO_ACTIVE_HIGH>;
+};
+
+&tlmm {
+ gpio-reserved-ranges = <13 4>;
+
+ ts_int_default: ts-int-default-state {
+ pins = "gpio22";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+
+ ts_avdd_default: ts-avdd-default-state {
+ pins = "gpio59";
+ function = "gpio";
+ drive-strength = <8>;
+ output-high;
+ };
+};
+
+&usb_1 {
+ status = "okay";
+};
+
+&usb_1_dwc3 {
+ dr_mode = "peripheral";
+};
+
+&usb_1_hsphy {
+ status = "okay";
+};
+
+&xo_board_clk {
+ clock-frequency = <19200000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi
new file mode 100644
index 000000000000..12cf5dbe5bd6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi
@@ -0,0 +1,1396 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/clock/qcom,sm6375-gcc.h>
+#include <dt-bindings/dma/qcom-gpi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mailbox/qcom-ipcc.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+
+/ {
+ interrupt-parent = <&intc>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen { };
+
+ clocks {
+ xo_board_clk: xo-board-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ next-level-cache = <&L2_0>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD0>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_0: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ L3_0: l3-cache {
+ compatible = "cache";
+ };
+ };
+ };
+
+ CPU1: cpu@100 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ next-level-cache = <&L2_100>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD1>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_100: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU2: cpu@200 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ next-level-cache = <&L2_200>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD2>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_200: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU3: cpu@300 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ next-level-cache = <&L2_300>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD3>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_300: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU4: cpu@400 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x400>;
+ enable-method = "psci";
+ next-level-cache = <&L2_400>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD4>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_400: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU5: cpu@500 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x500>;
+ enable-method = "psci";
+ next-level-cache = <&L2_500>;
+ qcom,freq-domain = <&cpufreq_hw 0>;
+ power-domains = <&CPU_PD5>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_500: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+
+ };
+
+ CPU6: cpu@600 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x600>;
+ enable-method = "psci";
+ next-level-cache = <&L2_600>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ power-domains = <&CPU_PD6>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_600: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ CPU7: cpu@700 {
+ device_type = "cpu";
+ compatible = "qcom,kryo660";
+ reg = <0x0 0x700>;
+ enable-method = "psci";
+ next-level-cache = <&L2_700>;
+ qcom,freq-domain = <&cpufreq_hw 1>;
+ power-domains = <&CPU_PD7>;
+ power-domain-names = "psci";
+ #cooling-cells = <2>;
+ L2_700: l2-cache {
+ compatible = "cache";
+ next-level-cache = <&L3_0>;
+ };
+ };
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+
+ core1 {
+ cpu = <&CPU1>;
+ };
+
+ core2 {
+ cpu = <&CPU2>;
+ };
+
+ core3 {
+ cpu = <&CPU3>;
+ };
+
+ core4 {
+ cpu = <&CPU4>;
+ };
+
+ core5 {
+ cpu = <&CPU5>;
+ };
+
+ core6 {
+ cpu = <&CPU6>;
+ };
+
+ core7 {
+ cpu = <&CPU7>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "silver-rail-power-collapse";
+ arm,psci-suspend-param = <0x40000004>;
+ entry-latency-us = <702>;
+ exit-latency-us = <915>;
+ min-residency-us = <4001>;
+ local-timer-stop;
+ };
+
+ BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+ compatible = "arm,idle-state";
+ idle-state-name = "gold-rail-power-collapse";
+ arm,psci-suspend-param = <0x40000004>;
+ entry-latency-us = <526>;
+ exit-latency-us = <1854>;
+ min-residency-us = <5555>;
+ local-timer-stop;
+ };
+ };
+
+ domain-idle-states {
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "domain-idle-state";
+ idle-state-name = "cluster-power-collapse";
+ arm,psci-suspend-param = <0x41000044>;
+ entry-latency-us = <2752>;
+ exit-latency-us = <3048>;
+ min-residency-us = <6118>;
+ local-timer-stop;
+ };
+ };
+ };
+
+ firmware {
+ scm {
+ compatible = "qcom,scm-sm6375", "qcom,scm";
+ clocks = <&rpmcc RPM_SMD_CE1_CLK>;
+ clock-names = "core";
+ #reset-cells = <1>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the size */
+ reg = <0x0 0x80000000 0x0 0x0>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+
+ CPU_PD0: cpu0 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD1: cpu1 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD2: cpu2 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD3: cpu3 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD4: cpu4 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD5: cpu5 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+ };
+
+ CPU_PD6: cpu6 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&BIG_CPU_SLEEP_0>;
+ };
+
+ CPU_PD7: cpu7 {
+ #power-domain-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ domain-idle-states = <&BIG_CPU_SLEEP_0>;
+ };
+
+ CLUSTER_PD: cpu-cluster0 {
+ #power-domain-cells = <0>;
+ domain-idle-states = <&CLUSTER_SLEEP_0>;
+ };
+ };
+
+ qup_opp_table: opp-table-qup {
+ compatible = "operating-points-v2";
+
+ opp-75000000 {
+ opp-hz = /bits/ 64 <75000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ required-opps = <&rpmpd_opp_svs>;
+ };
+
+ opp-128000000 {
+ opp-hz = /bits/ 64 <128000000>;
+ required-opps = <&rpmpd_opp_nom>;
+ };
+ };
+
+ reserved_memory: reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ hyp_mem: hypervisor@80000000 {
+ reg = <0 0x80000000 0 0x600000>;
+ no-map;
+ };
+
+ xbl_aop_mem: xbl-aop@80700000 {
+ reg = <0 0x80700000 0 0x100000>;
+ no-map;
+ };
+
+ reserved_xbl_uefi: xbl-uefi-res@80880000 {
+ reg = <0 0x80880000 0 0x14000>;
+ no-map;
+ };
+
+ smem_mem: smem@80900000 {
+ compatible = "qcom,smem";
+ reg = <0 0x80900000 0 0x200000>;
+ hwlocks = <&tcsr_mutex 3>;
+ no-map;
+ };
+
+ fw_mem: fw@80b00000 {
+ reg = <0 0x80b00000 0 0x100000>;
+ no-map;
+ };
+
+ cdsp_secure_heap_mem: cdsp-sec-heap@80c00000 {
+ reg = <0 0x80c00000 0 0x1e00000>;
+ no-map;
+ };
+
+ dfps_data_mem: dpfs-data@85e00000 {
+ reg = <0 0x85e00000 0 0x100000>;
+ no-map;
+ };
+
+ pil_wlan_mem: pil-wlan@86500000 {
+ reg = <0 0x86500000 0 0x200000>;
+ no-map;
+ };
+
+ pil_adsp_mem: pil-adsp@86700000 {
+ reg = <0 0x86700000 0 0x2000000>;
+ no-map;
+ };
+
+ pil_cdsp_mem: pil-cdsp@88700000 {
+ reg = <0 0x88700000 0 0x1e00000>;
+ no-map;
+ };
+
+ pil_video_mem: pil-video@8a500000 {
+ reg = <0 0x8a500000 0 0x500000>;
+ no-map;
+ };
+
+ pil_ipa_fw_mem: pil-ipa-fw@8aa00000 {
+ reg = <0 0x8aa00000 0 0x10000>;
+ no-map;
+ };
+
+ pil_ipa_gsi_mem: pil-ipa-gsi@8aa10000 {
+ reg = <0 0x8aa10000 0 0xa000>;
+ no-map;
+ };
+
+ pil_gpu_micro_code_mem: pil-gpu-ucode@8aa1a000 {
+ reg = <0 0x8aa1a000 0 0x2000>;
+ no-map;
+ };
+
+ pil_mpss_wlan_mem: pil-mpss-wlan@8b800000 {
+ reg = <0 0x8b800000 0 0x10000000>;
+ no-map;
+ };
+
+ removed_mem: removed@c0000000 {
+ reg = <0 0xc0000000 0 0x5100000>;
+ no-map;
+ };
+
+ debug_mem: debug@ffb00000 {
+ reg = <0 0xffb00000 0 0xc0000>;
+ no-map;
+ };
+
+ last_log_mem: lastlog@ffbc0000 {
+ reg = <0 0xffbc0000 0 0x80000>;
+ no-map;
+ };
+
+ cmdline_region: cmdline@ffd00000 {
+ reg = <0 0xffd00000 0 0x1000>;
+ no-map;
+ };
+ };
+
+ rpm-glink {
+ compatible = "qcom,glink-rpm";
+ interrupts-extended = <&ipcc IPCC_CLIENT_AOP
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+ rpm_requests: rpm-requests {
+ compatible = "qcom,rpm-sm6375";
+ qcom,glink-channels = "rpm_requests";
+
+ rpmcc: clock-controller {
+ compatible = "qcom,rpmcc-sm6375", "qcom,rpmcc";
+ clocks = <&xo_board_clk>;
+ clock-names = "xo";
+ #clock-cells = <1>;
+ };
+
+ rpmpd: power-controller {
+ compatible = "qcom,sm6375-rpmpd";
+ #power-domain-cells = <1>;
+ operating-points-v2 = <&rpmpd_opp_table>;
+
+ rpmpd_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ rpmpd_opp_ret: opp1 {
+ opp-level = <RPM_SMD_LEVEL_RETENTION>;
+ };
+
+ rpmpd_opp_min_svs: opp2 {
+ opp-level = <RPM_SMD_LEVEL_MIN_SVS>;
+ };
+
+ rpmpd_opp_low_svs: opp3 {
+ opp-level = <RPM_SMD_LEVEL_LOW_SVS>;
+ };
+
+ rpmpd_opp_svs: opp4 {
+ opp-level = <RPM_SMD_LEVEL_SVS>;
+ };
+
+ rpmpd_opp_svs_plus: opp5 {
+ opp-level = <RPM_SMD_LEVEL_SVS_PLUS>;
+ };
+
+ rpmpd_opp_nom: opp6 {
+ opp-level = <RPM_SMD_LEVEL_NOM>;
+ };
+
+ rpmpd_opp_nom_plus: opp7 {
+ opp-level = <RPM_SMD_LEVEL_NOM_PLUS>;
+ };
+
+ rpmpd_opp_turbo: opp8 {
+ opp-level = <RPM_SMD_LEVEL_TURBO>;
+ };
+
+ rpmpd_opp_turbo_no_cpr: opp9 {
+ opp-level = <RPM_SMD_LEVEL_TURBO_NO_CPR>;
+ };
+ };
+ };
+ };
+ };
+
+ smp2p-adsp {
+ compatible = "qcom,smp2p";
+ qcom,smem = <443>, <429>;
+ interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
+ IPCC_MPROC_SIGNAL_SMP2P
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_LPASS
+ IPCC_MPROC_SIGNAL_SMP2P>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <2>;
+
+ smp2p_adsp_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ smp2p_adsp_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-cdsp {
+ compatible = "qcom,smp2p";
+ qcom,smem = <94>, <432>;
+ interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
+ IPCC_MPROC_SIGNAL_SMP2P
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_CDSP
+ IPCC_MPROC_SIGNAL_SMP2P>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <5>;
+
+ smp2p_cdsp_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ smp2p_cdsp_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ soc: soc@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0 0 0 0 0x10 0>;
+ dma-ranges = <0 0 0 0 0x10 0>;
+ compatible = "simple-bus";
+
+ ipcc: mailbox@208000 {
+ compatible = "qcom,sm6375-ipcc", "qcom,ipcc";
+ reg = <0 0x00208000 0 0x1000>;
+ interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #mbox-cells = <2>;
+ };
+
+ tcsr_mutex: hwlock@340000 {
+ compatible = "qcom,tcsr-mutex";
+ reg = <0x0 0x00340000 0x0 0x40000>;
+ #hwlock-cells = <1>;
+ };
+
+ tlmm: pinctrl@500000 {
+ compatible = "qcom,sm6375-tlmm";
+ reg = <0 0x00500000 0 0x800000>;
+ interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&tlmm 0 0 157>;
+ /* TODO: Hook up MPM as wakeup-parent when it's there */
+ interrupt-controller;
+ gpio-controller;
+ #interrupt-cells = <2>;
+ #gpio-cells = <2>;
+
+ sdc2_off_state: sdc2-off-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ sdc2_on_state: sdc2-on-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
+
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup00";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio61", "gpio62";
+ function = "qup01";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio45", "gpio46";
+ function = "qup02";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c8_default: qup-i2c8-default-state {
+ pins = "gpio19", "gpio20";
+ /* TLMM, GCC and vendor DT all have different indices.. */
+ function = "qup12";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_i2c10_default: qup-i2c10-default-state {
+ pins = "gpio4", "gpio5";
+ function = "qup10";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ qup_spi0_default: qup-spi0-default-state {
+ pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ function = "qup00";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ gcc: clock-controller@1400000 {
+ compatible = "qcom,sm6375-gcc";
+ reg = <0 0x01400000 0 0x1f0000>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&rpmcc RPM_SMD_XO_A_CLK_SRC>,
+ <&sleep_clk>;
+ #power-domain-cells = <1>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ usb_1_hsphy: phy@162b000 {
+ compatible = "qcom,sm6375-usb-hs-phy", "qcom,usb-snps-hs-7nm-phy";
+ reg = <0 0x0162b000 0 0x400>;
+
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "ref";
+ resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+
+ spmi_bus: spmi@1c40000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0 0x01c40000 0 0x1100>,
+ <0 0x01e00000 0 0x2000000>,
+ <0 0x03e00000 0 0x100000>,
+ <0 0x03f00000 0 0xa0000>,
+ <0 0x01c0a000 0 0x26000>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
+
+ rpm_msg_ram: sram@45f0000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0 0x045f0000 0 0x7000>;
+ };
+
+ sdhc_2: mmc@4784000 {
+ compatible = "qcom,sm6375-sdhci", "qcom,sdhci-msm-v5";
+ reg = <0 0x04784000 0 0x1000>;
+
+ interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+ <&gcc GCC_SDCC2_APPS_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface", "core", "xo";
+ resets = <&gcc GCC_SDCC2_BCR>;
+ iommus = <&apps_smmu 0x40 0x0>;
+
+ pinctrl-0 = <&sdc2_on_state>;
+ pinctrl-1 = <&sdc2_off_state>;
+ pinctrl-names = "default", "sleep";
+
+ qcom,dll-config = <0x0007642c>;
+ qcom,ddr-config = <0x80040868>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&sdhc2_opp_table>;
+ bus-width = <4>;
+
+ status = "disabled";
+
+ sdhc2_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-202000000 {
+ opp-hz = /bits/ 64 <202000000>;
+ required-opps = <&rpmpd_opp_svs_plus>;
+ };
+ };
+ };
+
+ gpi_dma0: dma-controller@4a00000 {
+ compatible = "qcom,sm6375-gpi-dma", "qcom,sm6350-gpi-dma";
+ reg = <0 0x04a00000 0 0x60000>;
+ interrupts = <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <10>;
+ dma-channel-mask = <0x1f>;
+ iommus = <&apps_smmu 0x16 0x0>;
+ #dma-cells = <3>;
+ status = "disabled";
+ };
+
+ qupv3_id_0: geniqup@4ac0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0x0 0x04ac0000 0x0 0x2000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ iommus = <&apps_smmu 0x3 0x0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ i2c0: i2c@4a80000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04a80000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c0_default>;
+ dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 0 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi0: spi@4a80000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04a80000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_spi0_default>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 0 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@4a84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04a84000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ interrupts = <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c1_default>;
+ dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 1 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@4a84000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04a84000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ interrupts = <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 1 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@4a88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04a88000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c2_default>;
+ dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>,
+ <&gpi_dma0 1 2 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi2: spi@4a88000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04a88000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>,
+ <&gpi_dma0 1 2 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ /*
+ * As per GCC, QUP3/4/5/11 also exist, but are not even defined downstream.
+ * There is a comment in the included DTSI of another SoC saying that they
+ * are not "bolled out" (probably meaning not routed to solder balls)
+ * TLMM driver however, suggests there are as many as 15 QUPs in total!
+ * Most of which don't even have pin configurations for.. Sad stuff!
+ */
+ };
+
+ gpi_dma1: dma-controller@4c00000 {
+ compatible = "qcom,sm6375-gpi-dma", "qcom,sm6350-gpi-dma";
+ reg = <0 0x04c00000 0 0x60000>;
+ interrupts = <GIC_SPI 497 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 498 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 499 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 500 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 501 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 502 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 503 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 504 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 505 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <10>;
+ dma-channel-mask = <0x1f>;
+ iommus = <&apps_smmu 0xd6 0x0>;
+ #dma-cells = <3>;
+ status = "disabled";
+ };
+
+ qupv3_id_1: geniqup@4cc0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0x0 0x04cc0000 0x0 0x2000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ iommus = <&apps_smmu 0xc3 0x0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ i2c6: i2c@4c80000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04c80000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
+ interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 0 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi6: spi@4c80000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04c80000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
+ interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>,
+ <&gpi_dma1 1 0 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c7: i2c@4c84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04c84000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ interrupts = <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 1 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi7: spi@4c84000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04c84000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ interrupts = <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>,
+ <&gpi_dma1 1 1 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c8: i2c@4c88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04c88000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
+ interrupts = <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c8_default>;
+ dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 2 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi8: spi@4c88000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04c88000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
+ interrupts = <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>,
+ <&gpi_dma1 1 2 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c9: i2c@4c8c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04c8c000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>;
+ interrupts = <GIC_SPI 510 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 3 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi9: spi@4c8c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04c8c000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>;
+ interrupts = <GIC_SPI 510 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>,
+ <&gpi_dma1 1 3 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c10: i2c@4c90000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x04c90000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
+ interrupts = <GIC_SPI 511 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&qup_i2c10_default>;
+ dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>,
+ <&gpi_dma1 1 4 QCOM_GPI_I2C>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi10: spi@4c90000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x04c90000 0x0 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
+ interrupts = <GIC_SPI 511 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&rpmpd SM6375_VDDCX>;
+ operating-points-v2 = <&qup_opp_table>;
+ dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>,
+ <&gpi_dma1 1 4 QCOM_GPI_SPI>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ usb_1: usb@4ef8800 {
+ compatible = "qcom,sm6375-dwc3", "qcom,dwc3";
+ reg = <0 0x04ef8800 0 0x400>;
+
+ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>,
+ <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_SLEEP_CLK>,
+ <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB3_PRIM_CLKREF_CLK>;
+ clock-names = "cfg_noc",
+ "core",
+ "iface",
+ "sleep",
+ "mock_utmi",
+ "xo";
+
+ assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <133333333>;
+
+ interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hs_phy_irq",
+ "ss_phy_irq",
+ "dm_hs_phy_irq",
+ "dp_hs_phy_irq";
+
+ power-domains = <&gcc USB30_PRIM_GDSC>;
+
+ resets = <&gcc GCC_USB30_PRIM_BCR>;
+
+ /*
+ * This property is there to allow USB2 to work, as
+ * USB3 is not implemented yet - (re)move it when
+ * proper support is in place.
+ */
+ qcom,select-utmi-as-pipe-clk;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ status = "disabled";
+
+ usb_1_dwc3: usb@4e00000 {
+ compatible = "snps,dwc3";
+ reg = <0 0x04e00000 0 0xcd00>;
+ interrupts = <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>;
+ maximum-speed = "high-speed";
+ phys = <&usb_1_hsphy>;
+ phy-names = "usb2-phy";
+ iommus = <&apps_smmu 0xe0 0x0>;
+
+ /* Yes, this impl *does* have an unfunny number of quirks.. */
+ snps,hird-threshold = /bits/ 8 <0x10>;
+ snps,usb2-gadget-lpm-disable;
+ snps,dis_u2_susphy_quirk;
+ snps,is-utmi-l1-suspend;
+ snps,dis-u1-entry-quirk;
+ snps,dis-u2-entry-quirk;
+ snps,usb3_lpm_capable;
+ snps,has-lpm-erratum;
+ tx-fifo-resize;
+ };
+ };
+
+ remoteproc_adsp: remoteproc@a400000 {
+ compatible = "qcom,sm6375-adsp-pas";
+ reg = <0 0x0a400000 0 0x100>;
+
+ interrupts-extended = <&intc GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+ <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "xo";
+
+ power-domains = <&rpmpd SM6375_VDD_LPI_CX>,
+ <&rpmpd SM6375_VDD_LPI_MX>;
+ power-domain-names = "lcx", "lmx";
+
+ memory-region = <&pil_adsp_mem>;
+
+ qcom,smem-states = <&smp2p_adsp_out 0>;
+ qcom,smem-state-names = "stop";
+
+ status = "disabled";
+
+ glink-edge {
+ interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_LPASS
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+ label = "lpass";
+ qcom,remote-pid = <2>;
+ };
+ };
+
+ remoteproc_cdsp: remoteproc@b000000 {
+ compatible = "qcom,sm6375-cdsp-pas";
+ reg = <0x0 0x0b000000 0x0 0x100000>;
+
+ interrupts-extended = <&intc GIC_SPI 265 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_cdsp_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "xo";
+
+ power-domains = <&rpmpd SM6375_VDDCX>;
+
+ memory-region = <&pil_cdsp_mem>;
+
+ qcom,smem-states = <&smp2p_cdsp_out 0>;
+ qcom,smem-state-names = "stop";
+
+ status = "disabled";
+
+ glink-edge {
+ interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_CDSP
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
+ label = "cdsp";
+ qcom,remote-pid = <5>;
+ };
+ };
+
+ apps_smmu: iommu@c600000 {
+ compatible = "qcom,sm6375-smmu-500", "arm,mmu-500";
+ reg = <0 0x0c600000 0 0x100000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+
+ power-domains = <&gcc HLOS1_VOTE_MM_SNOC_MMU_TBU_RT_GDSC>,
+ <&gcc HLOS1_VOTE_MM_SNOC_MMU_TBU_NRT_GDSC>,
+ <&gcc HLOS1_VOTE_TURING_MMU_TBU0_GDSC>;
+ #global-interrupts = <1>;
+ #iommu-cells = <2>;
+ };
+
+ intc: interrupt-controller@f200000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0x0f200000 0x0 0x10000>, /* GICD */
+ <0x0 0x0f240000 0x0 0x100000>; /* GICR * 8 */
+ interrupts = <GIC_PPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ #redistributor-regions = <1>;
+ #interrupt-cells = <3>;
+ redistributor-stride = <0 0x20000>;
+ interrupt-controller;
+ };
+
+ timer@f420000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0 0x0f420000 0 0x1000>;
+ ranges = <0 0 0 0x20000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ frame@f421000 {
+ reg = <0x0f421000 0x1000>, <0x0f422000 0x1000>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <0>;
+ };
+
+ frame@f423000 {
+ reg = <0x0f243000 0x1000>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <1>;
+ status = "disabled";
+ };
+
+ frame@f425000 {
+ reg = <0x0f425000 0x1000>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <2>;
+ status = "disabled";
+ };
+
+ frame@f427000 {
+ reg = <0x0f427000 0x1000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <3>;
+ status = "disabled";
+ };
+
+ frame@f429000 {
+ reg = <0x0f429000 0x1000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <4>;
+ status = "disabled";
+ };
+
+ frame@f42b000 {
+ reg = <0x0f42b000 0x1000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <5>;
+ status = "disabled";
+ };
+
+ frame@f42d000 {
+ reg = <0x0f42d000 0x1000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ frame-number = <6>;
+ status = "disabled";
+ };
+ };
+
+ cpufreq_hw: cpufreq@fd91000 {
+ compatible = "qcom,sm6375-cpufreq-epss", "qcom,cpufreq-epss";
+ reg = <0 0x0fd91000 0 0x1000>, <0 0x0fd92000 0 0x1000>;
+ reg-names = "freq-domain0", "freq-domain1";
+
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gcc GPLL0>;
+ clock-names = "xo", "alternate";
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "dcvsh-irq-0", "dcvsh-irq-1";
+ #freq-domain-cells = <1>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 0 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
index 30c94fd4fe61..c456e9594ea5 100644
--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
+++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
@@ -279,8 +279,11 @@
vreg_l6e: ldo6 {
regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <3544000>;
+ regulator-max-microvolt = <2950000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7e: ldo7 {
@@ -297,8 +300,11 @@
vreg_l9e: ldo9 {
regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <3544000>;
+ regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l10e: ldo10 {
@@ -424,6 +430,33 @@
status = "okay";
};
+&sdc2_off_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&sdc2_on_state {
+ sd-cd-pins {
+ pins = "gpio94";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+};
+
+&sdhc_2 {
+ vmmc-supply = <&vreg_l9e>;
+ vqmmc-supply = <&vreg_l6e>;
+
+ cd-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
+
+ status = "okay";
+};
+
&tlmm {
gpio-reserved-ranges = <13 4>, <56 2>;
};
diff --git a/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts b/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts
index bb278ecac3fa..5397fba9417b 100644
--- a/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts
+++ b/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts
@@ -475,7 +475,7 @@
&tlmm {
gpio-reserved-ranges = <126 4>;
- da7280_intr_default: da7280-intr-default {
+ da7280_intr_default: da7280-intr-default-state {
pins = "gpio42";
function = "gpio";
bias-pull-up;
diff --git a/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi
index 014fe3a31548..c958a8b16730 100644
--- a/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi
@@ -348,6 +348,8 @@
regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7c_3p0: ldo7 {
@@ -367,6 +369,8 @@
regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l10c_3p3: ldo10 {
diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi
index cef8c4f4f0ff..a0c57fb798d3 100644
--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi
@@ -887,7 +887,7 @@
};
gpi_dma0: dma-controller@800000 {
- compatible = "qcom,sm8150-gpi-dma";
+ compatible = "qcom,sm8150-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0x800000 0 0x60000>;
interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
@@ -1222,7 +1222,7 @@
};
gpi_dma1: dma-controller@a00000 {
- compatible = "qcom,sm8150-gpi-dma";
+ compatible = "qcom,sm8150-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0xa00000 0 0x60000>;
interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
@@ -1471,7 +1471,7 @@
};
gpi_dma2: dma-controller@c00000 {
- compatible = "qcom,sm8150-gpi-dma";
+ compatible = "qcom,sm8150-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0xc00000 0 0x60000>;
interrupts = <GIC_SPI 588 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>,
@@ -2032,11 +2032,11 @@
status = "disabled";
ufs_mem_phy_lanes: phy@1d87400 {
- reg = <0 0x01d87400 0 0x108>,
- <0 0x01d87600 0 0x1e0>,
- <0 0x01d87c00 0 0x1dc>,
- <0 0x01d87800 0 0x108>,
- <0 0x01d87a00 0 0x1e0>;
+ reg = <0 0x01d87400 0 0x16c>,
+ <0 0x01d87600 0 0x200>,
+ <0 0x01d87c00 0 0x200>,
+ <0 0x01d87800 0 0x16c>,
+ <0 0x01d87a00 0 0x200>;
#phy-cells = <0>;
};
};
@@ -2074,8 +2074,8 @@
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
- power-domains = <&rpmhpd 3>,
- <&rpmhpd 2>;
+ power-domains = <&rpmhpd SM8150_LCX>,
+ <&rpmhpd SM8150_LMX>;
power-domain-names = "lcx", "lmx";
memory-region = <&slpi_mem>;
@@ -2276,422 +2276,302 @@
#interrupt-cells = <2>;
wakeup-parent = <&pdc>;
- qup_i2c0_default: qup-i2c0-default {
- mux {
- pins = "gpio0", "gpio1";
- function = "qup0";
- };
-
- config {
- pins = "gpio0", "gpio1";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup0";
+ drive-strength = <0x02>;
+ bias-disable;
};
- qup_spi0_default: qup-spi0-default {
+ qup_spi0_default: qup-spi0-default-state {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "qup0";
drive-strength = <6>;
bias-disable;
};
- qup_i2c1_default: qup-i2c1-default {
- mux {
- pins = "gpio114", "gpio115";
- function = "qup1";
- };
-
- config {
- pins = "gpio114", "gpio115";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio114", "gpio115";
+ function = "qup1";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi1_default: qup-spi1-default {
+ qup_spi1_default: qup-spi1-default-state {
pins = "gpio114", "gpio115", "gpio116", "gpio117";
function = "qup1";
drive-strength = <6>;
bias-disable;
};
- qup_i2c2_default: qup-i2c2-default {
- mux {
- pins = "gpio126", "gpio127";
- function = "qup2";
- };
-
- config {
- pins = "gpio126", "gpio127";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio126", "gpio127";
+ function = "qup2";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi2_default: qup-spi2-default {
+ qup_spi2_default: qup-spi2-default-state {
pins = "gpio126", "gpio127", "gpio128", "gpio129";
function = "qup2";
drive-strength = <6>;
bias-disable;
};
- qup_i2c3_default: qup-i2c3-default {
- mux {
- pins = "gpio144", "gpio145";
- function = "qup3";
- };
-
- config {
- pins = "gpio144", "gpio145";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c3_default: qup-i2c3-default-state {
+ pins = "gpio144", "gpio145";
+ function = "qup3";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi3_default: qup-spi3-default {
+ qup_spi3_default: qup-spi3-default-state {
pins = "gpio144", "gpio145", "gpio146", "gpio147";
function = "qup3";
drive-strength = <6>;
bias-disable;
};
- qup_i2c4_default: qup-i2c4-default {
- mux {
- pins = "gpio51", "gpio52";
- function = "qup4";
- };
-
- config {
- pins = "gpio51", "gpio52";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c4_default: qup-i2c4-default-state {
+ pins = "gpio51", "gpio52";
+ function = "qup4";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi4_default: qup-spi4-default {
+ qup_spi4_default: qup-spi4-default-state {
pins = "gpio51", "gpio52", "gpio53", "gpio54";
function = "qup4";
drive-strength = <6>;
bias-disable;
};
- qup_i2c5_default: qup-i2c5-default {
- mux {
- pins = "gpio121", "gpio122";
- function = "qup5";
- };
-
- config {
- pins = "gpio121", "gpio122";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c5_default: qup-i2c5-default-state {
+ pins = "gpio121", "gpio122";
+ function = "qup5";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi5_default: qup-spi5-default {
+ qup_spi5_default: qup-spi5-default-state {
pins = "gpio119", "gpio120", "gpio121", "gpio122";
function = "qup5";
drive-strength = <6>;
bias-disable;
};
- qup_i2c6_default: qup-i2c6-default {
- mux {
- pins = "gpio6", "gpio7";
- function = "qup6";
- };
-
- config {
- pins = "gpio6", "gpio7";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c6_default: qup-i2c6-default-state {
+ pins = "gpio6", "gpio7";
+ function = "qup6";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi6_default: qup-spi6_default {
+ qup_spi6_default: qup-spi6_default-state {
pins = "gpio4", "gpio5", "gpio6", "gpio7";
function = "qup6";
drive-strength = <6>;
bias-disable;
};
- qup_i2c7_default: qup-i2c7-default {
- mux {
- pins = "gpio98", "gpio99";
- function = "qup7";
- };
-
- config {
- pins = "gpio98", "gpio99";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c7_default: qup-i2c7-default-state {
+ pins = "gpio98", "gpio99";
+ function = "qup7";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi7_default: qup-spi7_default {
+ qup_spi7_default: qup-spi7_default-state {
pins = "gpio98", "gpio99", "gpio100", "gpio101";
function = "qup7";
drive-strength = <6>;
bias-disable;
};
- qup_i2c8_default: qup-i2c8-default {
- mux {
- pins = "gpio88", "gpio89";
- function = "qup8";
- };
-
- config {
- pins = "gpio88", "gpio89";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c8_default: qup-i2c8-default-state {
+ pins = "gpio88", "gpio89";
+ function = "qup8";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi8_default: qup-spi8-default {
+ qup_spi8_default: qup-spi8-default-state {
pins = "gpio88", "gpio89", "gpio90", "gpio91";
function = "qup8";
drive-strength = <6>;
bias-disable;
};
- qup_i2c9_default: qup-i2c9-default {
- mux {
- pins = "gpio39", "gpio40";
- function = "qup9";
- };
-
- config {
- pins = "gpio39", "gpio40";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c9_default: qup-i2c9-default-state {
+ pins = "gpio39", "gpio40";
+ function = "qup9";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi9_default: qup-spi9-default {
+ qup_spi9_default: qup-spi9-default-state {
pins = "gpio39", "gpio40", "gpio41", "gpio42";
function = "qup9";
drive-strength = <6>;
bias-disable;
};
- qup_i2c10_default: qup-i2c10-default {
- mux {
- pins = "gpio9", "gpio10";
- function = "qup10";
- };
-
- config {
- pins = "gpio9", "gpio10";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c10_default: qup-i2c10-default-state {
+ pins = "gpio9", "gpio10";
+ function = "qup10";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi10_default: qup-spi10-default {
+ qup_spi10_default: qup-spi10-default-state {
pins = "gpio9", "gpio10", "gpio11", "gpio12";
function = "qup10";
drive-strength = <6>;
bias-disable;
};
- qup_i2c11_default: qup-i2c11-default {
- mux {
- pins = "gpio94", "gpio95";
- function = "qup11";
- };
-
- config {
- pins = "gpio94", "gpio95";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c11_default: qup-i2c11-default-state {
+ pins = "gpio94", "gpio95";
+ function = "qup11";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi11_default: qup-spi11-default {
+ qup_spi11_default: qup-spi11-default-state {
pins = "gpio92", "gpio93", "gpio94", "gpio95";
function = "qup11";
drive-strength = <6>;
bias-disable;
};
- qup_i2c12_default: qup-i2c12-default {
- mux {
- pins = "gpio83", "gpio84";
- function = "qup12";
- };
-
- config {
- pins = "gpio83", "gpio84";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c12_default: qup-i2c12-default-state {
+ pins = "gpio83", "gpio84";
+ function = "qup12";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi12_default: qup-spi12-default {
+ qup_spi12_default: qup-spi12-default-state {
pins = "gpio83", "gpio84", "gpio85", "gpio86";
function = "qup12";
drive-strength = <6>;
bias-disable;
};
- qup_i2c13_default: qup-i2c13-default {
- mux {
- pins = "gpio43", "gpio44";
- function = "qup13";
- };
-
- config {
- pins = "gpio43", "gpio44";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c13_default: qup-i2c13-default-state {
+ pins = "gpio43", "gpio44";
+ function = "qup13";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi13_default: qup-spi13-default {
+ qup_spi13_default: qup-spi13-default-state {
pins = "gpio43", "gpio44", "gpio45", "gpio46";
function = "qup13";
drive-strength = <6>;
bias-disable;
};
- qup_i2c14_default: qup-i2c14-default {
- mux {
- pins = "gpio47", "gpio48";
- function = "qup14";
- };
-
- config {
- pins = "gpio47", "gpio48";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c14_default: qup-i2c14-default-state {
+ pins = "gpio47", "gpio48";
+ function = "qup14";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi14_default: qup-spi14-default {
+ qup_spi14_default: qup-spi14-default-state {
pins = "gpio47", "gpio48", "gpio49", "gpio50";
function = "qup14";
drive-strength = <6>;
bias-disable;
};
- qup_i2c15_default: qup-i2c15-default {
- mux {
- pins = "gpio27", "gpio28";
- function = "qup15";
- };
-
- config {
- pins = "gpio27", "gpio28";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c15_default: qup-i2c15-default-state {
+ pins = "gpio27", "gpio28";
+ function = "qup15";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi15_default: qup-spi15-default {
+ qup_spi15_default: qup-spi15-default-state {
pins = "gpio27", "gpio28", "gpio29", "gpio30";
function = "qup15";
drive-strength = <6>;
bias-disable;
};
- qup_i2c16_default: qup-i2c16-default {
- mux {
- pins = "gpio86", "gpio85";
- function = "qup16";
- };
-
- config {
- pins = "gpio86", "gpio85";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c16_default: qup-i2c16-default-state {
+ pins = "gpio86", "gpio85";
+ function = "qup16";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi16_default: qup-spi16-default {
+ qup_spi16_default: qup-spi16-default-state {
pins = "gpio83", "gpio84", "gpio85", "gpio86";
function = "qup16";
drive-strength = <6>;
bias-disable;
};
- qup_i2c17_default: qup-i2c17-default {
- mux {
- pins = "gpio55", "gpio56";
- function = "qup17";
- };
-
- config {
- pins = "gpio55", "gpio56";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c17_default: qup-i2c17-default-state {
+ pins = "gpio55", "gpio56";
+ function = "qup17";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi17_default: qup-spi17-default {
+ qup_spi17_default: qup-spi17-default-state {
pins = "gpio55", "gpio56", "gpio57", "gpio58";
function = "qup17";
drive-strength = <6>;
bias-disable;
};
- qup_i2c18_default: qup-i2c18-default {
- mux {
- pins = "gpio23", "gpio24";
- function = "qup18";
- };
-
- config {
- pins = "gpio23", "gpio24";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c18_default: qup-i2c18-default-state {
+ pins = "gpio23", "gpio24";
+ function = "qup18";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi18_default: qup-spi18-default {
+ qup_spi18_default: qup-spi18-default-state {
pins = "gpio23", "gpio24", "gpio25", "gpio26";
function = "qup18";
drive-strength = <6>;
bias-disable;
};
- qup_i2c19_default: qup-i2c19-default {
- mux {
- pins = "gpio57", "gpio58";
- function = "qup19";
- };
-
- config {
- pins = "gpio57", "gpio58";
- drive-strength = <0x02>;
- bias-disable;
- };
+ qup_i2c19_default: qup-i2c19-default-state {
+ pins = "gpio57", "gpio58";
+ function = "qup19";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi19_default: qup-spi19-default {
+ qup_spi19_default: qup-spi19-default-state {
pins = "gpio55", "gpio56", "gpio57", "gpio58";
function = "qup19";
drive-strength = <6>;
bias-disable;
};
- pcie0_default_state: pcie0-default {
- perst {
+ pcie0_default_state: pcie0-default-state {
+ perst-pins {
pins = "gpio35";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio36";
function = "pci_e0";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio37";
function = "gpio";
drive-strength = <2>;
@@ -2699,22 +2579,22 @@
};
};
- pcie1_default_state: pcie1-default {
- perst {
+ pcie1_default_state: pcie1-default-state {
+ perst-pins {
pins = "gpio102";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio103";
function = "pci_e1";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio104";
function = "gpio";
drive-strength = <2>;
@@ -2739,8 +2619,8 @@
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
- power-domains = <&rpmhpd 7>,
- <&rpmhpd 0>;
+ power-domains = <&rpmhpd SM8150_CX>,
+ <&rpmhpd SM8150_MSS>;
power-domain-names = "cx", "mss";
memory-region = <&mpss_mem>;
@@ -3366,7 +3246,7 @@
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
- power-domains = <&rpmhpd 7>;
+ power-domains = <&rpmhpd SM8150_CX>;
memory-region = <&cdsp_mem>;
@@ -3867,7 +3747,7 @@
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
- power-domains = <&rpmhpd 7>;
+ power-domains = <&rpmhpd SM8150_CX>;
memory-region = <&adsp_mem>;
@@ -4010,6 +3890,7 @@
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 1>;
+ power-domains = <&CLUSTER_PD>;
rpmhcc: clock-controller {
compatible = "qcom,sm8150-rpmh-clk";
@@ -4078,7 +3959,7 @@
};
osm_l3: interconnect@18321000 {
- compatible = "qcom,sm8150-osm-l3";
+ compatible = "qcom,sm8150-osm-l3", "qcom,osm-l3";
reg = <0 0x18321000 0 0x1400>;
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
diff --git a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts
index a102aa5efa32..3ed8c84e25b8 100644
--- a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts
@@ -635,7 +635,7 @@
wcd938x: codec {
compatible = "qcom,wcd9380-codec";
#sound-dai-cells = <1>;
- reset-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
vdd-buck-supply = <&vreg_s4a_1p8>;
vdd-rxtx-supply = <&vreg_s4a_1p8>;
vdd-io-supply = <&vreg_s4a_1p8>;
@@ -757,7 +757,7 @@
};
&swr0 {
- left_spkr: wsa8810-right@0,3{
+ left_spkr: speaker@0,3 {
compatible = "sdw10217211000";
reg = <0 3>;
powerdown-gpios = <&tlmm 26 GPIO_ACTIVE_HIGH>;
@@ -766,7 +766,7 @@
#sound-dai-cells = <0>;
};
- right_spkr: wsa8810-left@0,4{
+ right_spkr: speaker@0,4 {
compatible = "sdw10217211000";
reg = <0 4>;
powerdown-gpios = <&tlmm 127 GPIO_ACTIVE_HIGH>;
@@ -799,31 +799,19 @@
&tlmm {
gpio-reserved-ranges = <28 4>, <40 4>;
- wcd938x_reset_default: wcd938x_reset_default {
- mux {
- pins = "gpio32";
- function = "gpio";
- };
-
- config {
- pins = "gpio32";
- drive-strength = <16>;
- output-high;
- };
+ wcd938x_reset_default: wcd938x-reset-default-state {
+ pins = "gpio32";
+ function = "gpio";
+ drive-strength = <16>;
+ output-high;
};
- wcd938x_reset_sleep: wcd938x_reset_sleep {
- mux {
- pins = "gpio32";
- function = "gpio";
- };
-
- config {
- pins = "gpio32";
- drive-strength = <16>;
- bias-disable;
- output-low;
- };
+ wcd938x_reset_sleep: wcd938x-reset-sleep-state {
+ pins = "gpio32";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi
index 549e0a2aa9fe..09a31f707639 100644
--- a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi
@@ -317,6 +317,8 @@
regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7c_2p85: ldo7 {
@@ -339,6 +341,8 @@
regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l10c_3p3: ldo10 {
@@ -434,7 +438,16 @@
status = "okay";
clock-frequency = <400000>;
- /* NXP PN553 NFC @ 28 */
+ nfc@28 {
+ compatible = "nxp,nxp-nci-i2c";
+ reg = <0x28>;
+
+ interrupt-parent = <&tlmm>;
+ interrupts = <111 IRQ_TYPE_EDGE_RISING>;
+
+ enable-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>;
+ firmware-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ };
};
&i2c2 {
@@ -572,7 +585,7 @@
vqmmc-supply = <&vreg_l6c_2p9>;
bus-width = <4>;
no-sdio;
- no-emmc;
+ no-mmc;
};
&slpi {
@@ -582,49 +595,49 @@
&tlmm {
gpio-reserved-ranges = <40 4>, <52 4>;
- sdc2_default_state: sdc2-default {
- clk {
+ sdc2_default_state: sdc2-default-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <16>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
drive-strength = <16>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "sdc2_data";
drive-strength = <16>;
bias-pull-up;
};
};
- mdm2ap_default: mdm2ap-default {
+ mdm2ap_default: mdm2ap-default-state {
pins = "gpio1", "gpio3";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
- ts_int_default: ts-int-default {
+ ts_int_default: ts-int-default-state {
pins = "gpio39";
function = "gpio";
drive-strength = <2>;
- bias-disabled;
+ bias-disable;
input-enable;
};
- ap2mdm_default: ap2mdm-default {
+ ap2mdm_default: ap2mdm-default-state {
pins = "gpio56", "gpio57";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
- sdc2_card_det_n: sd-card-det-n {
+ sdc2_card_det_n: sd-card-det-n-state {
pins = "gpio77";
function = "gpio";
bias-pull-up;
diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
index a5b62cadb129..dab5579946f3 100644
--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
@@ -334,6 +334,7 @@
exit-latency-us = <6562>;
min-residency-us = <9987>;
local-timer-stop;
+ status = "disabled";
};
};
};
@@ -936,7 +937,7 @@
};
gpi_dma2: dma-controller@800000 {
- compatible = "qcom,sm8250-gpi-dma";
+ compatible = "qcom,sm8250-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0x00800000 0 0x70000>;
interrupts = <GIC_SPI 588 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>,
@@ -1187,7 +1188,7 @@
};
gpi_dma0: dma-controller@900000 {
- compatible = "qcom,sm8250-gpi-dma";
+ compatible = "qcom,sm8250-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0x00900000 0 0x70000>;
interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
@@ -1505,7 +1506,7 @@
};
gpi_dma1: dma-controller@a00000 {
- compatible = "qcom,sm8250-gpi-dma";
+ compatible = "qcom,sm8250-gpi-dma", "qcom,sdm845-gpi-dma";
reg = <0 0x00a00000 0 0x70000>;
interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
@@ -2179,11 +2180,11 @@
status = "disabled";
ufs_mem_phy_lanes: phy@1d87400 {
- reg = <0 0x01d87400 0 0x108>,
- <0 0x01d87600 0 0x1e0>,
- <0 0x01d87c00 0 0x1dc>,
- <0 0x01d87800 0 0x108>,
- <0 0x01d87a00 0 0x1e0>;
+ reg = <0 0x01d87400 0 0x16c>,
+ <0 0x01d87600 0 0x200>,
+ <0 0x01d87c00 0 0x200>,
+ <0 0x01d87800 0 0x16c>,
+ <0 0x01d87a00 0 0x200>;
#phy-cells = <0>;
};
};
@@ -2360,7 +2361,6 @@
qcom,ports-word-length = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
qcom,ports-block-group-count = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
qcom,ports-lane-control = /bits/ 8 <0xFF 0x00 0x01 0x00 0x01>;
- qcom,port-offset = <1>;
#sound-dai-cells = <1>;
#address-cells = <2>;
#size-cells = <0>;
@@ -2388,8 +2388,8 @@
<&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
clock-names = "core", "audio";
- wsa_swr_active: wsa-swr-active-pins {
- clk {
+ wsa_swr_active: wsa-swr-active-state {
+ clk-pins {
pins = "gpio10";
function = "wsa_swr_clk";
drive-strength = <2>;
@@ -2397,7 +2397,7 @@
bias-disable;
};
- data {
+ data-pins {
pins = "gpio11";
function = "wsa_swr_data";
drive-strength = <2>;
@@ -2407,8 +2407,8 @@
};
};
- wsa_swr_sleep: wsa-swr-sleep-pins {
- clk {
+ wsa_swr_sleep: wsa-swr-sleep-state {
+ clk-pins {
pins = "gpio10";
function = "wsa_swr_clk";
drive-strength = <2>;
@@ -2416,7 +2416,7 @@
bias-pull-down;
};
- data {
+ data-pins {
pins = "gpio11";
function = "wsa_swr_data";
drive-strength = <2>;
@@ -2426,14 +2426,14 @@
};
};
- dmic01_active: dmic01-active-pins {
- clk {
+ dmic01_active: dmic01-active-state {
+ clk-pins {
pins = "gpio6";
function = "dmic1_clk";
drive-strength = <8>;
output-high;
};
- data {
+ data-pins {
pins = "gpio7";
function = "dmic1_data";
drive-strength = <8>;
@@ -2441,8 +2441,8 @@
};
};
- dmic01_sleep: dmic01-sleep-pins {
- clk {
+ dmic01_sleep: dmic01-sleep-state {
+ clk-pins {
pins = "gpio6";
function = "dmic1_clk";
drive-strength = <2>;
@@ -2450,17 +2450,17 @@
output-low;
};
- data {
+ data-pins {
pins = "gpio7";
function = "dmic1_data";
drive-strength = <2>;
- pull-down;
+ bias-pull-down;
input-enable;
};
};
- rx_swr_active: rx_swr-active-pins {
- clk {
+ rx_swr_active: rx-swr-active-state {
+ clk-pins {
pins = "gpio3";
function = "swr_rx_clk";
drive-strength = <2>;
@@ -2468,7 +2468,7 @@
bias-disable;
};
- data {
+ data-pins {
pins = "gpio4", "gpio5";
function = "swr_rx_data";
drive-strength = <2>;
@@ -2477,8 +2477,8 @@
};
};
- tx_swr_active: tx_swr-active-pins {
- clk {
+ tx_swr_active: tx-swr-active-state {
+ clk-pins {
pins = "gpio0";
function = "swr_tx_clk";
drive-strength = <2>;
@@ -2486,7 +2486,7 @@
bias-disable;
};
- data {
+ data-pins {
pins = "gpio1", "gpio2";
function = "swr_tx_data";
drive-strength = <2>;
@@ -2495,8 +2495,8 @@
};
};
- tx_swr_sleep: tx_swr-sleep-pins {
- clk {
+ tx_swr_sleep: tx-swr-sleep-state {
+ clk-pins {
pins = "gpio0";
function = "swr_tx_clk";
drive-strength = <2>;
@@ -2504,7 +2504,7 @@
bias-pull-down;
};
- data1 {
+ data1-pins {
pins = "gpio1";
function = "swr_tx_data";
drive-strength = <2>;
@@ -2512,7 +2512,7 @@
bias-bus-hold;
};
- data2 {
+ data2-pins {
pins = "gpio2";
function = "swr_tx_data";
drive-strength = <2>;
@@ -2729,6 +2729,503 @@
};
};
+ stm@6002000 {
+ compatible = "arm,coresight-stm", "arm,primecell";
+ reg = <0 0x06002000 0 0x1000>, <0 0x16280000 0 0x180000>;
+ reg-names = "stm-base", "stm-stimulus-base";
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ stm_out: endpoint {
+ remote-endpoint = <&funnel0_in7>;
+ };
+ };
+ };
+ };
+
+ funnel@6041000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ reg = <0 0x06041000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ funnel_in0_out_funnel_merg: endpoint {
+ remote-endpoint = <&funnel_merg_in_funnel_in0>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@7 {
+ reg = <7>;
+ funnel0_in7: endpoint {
+ remote-endpoint = <&stm_out>;
+ };
+ };
+ };
+ };
+
+ funnel@6042000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ reg = <0 0x06042000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_in1_out_funnel_merg: endpoint {
+ remote-endpoint = <&funnel_merg_in_funnel_in1>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@4 {
+ reg = <4>;
+ funnel_in1_in_funnel_apss_merg: endpoint {
+ remote-endpoint = <&funnel_apss_merg_out_funnel_in1>;
+ };
+ };
+ };
+ };
+
+ funnel@6045000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ reg = <0 0x06045000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ funnel_merg_out_funnel_swao: endpoint {
+ remote-endpoint = <&funnel_swao_in_funnel_merg>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_merg_in_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_out_funnel_merg>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ funnel_merg_in_funnel_in1: endpoint {
+ remote-endpoint = <&funnel_in1_out_funnel_merg>;
+ };
+ };
+ };
+ };
+
+ replicator@6046000 {
+ compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
+ reg = <0 0x06046000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ replicator_out: endpoint {
+ remote-endpoint = <&etr_in>;
+ };
+ };
+ };
+
+ in-ports {
+ port {
+ replicator_cx_in_swao_out: endpoint {
+ remote-endpoint = <&replicator_swao_out_cx_in>;
+ };
+ };
+ };
+ };
+
+ etr@6048000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0 0x06048000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,scatter-gather;
+
+ in-ports {
+ port {
+ etr_in: endpoint {
+ remote-endpoint = <&replicator_out>;
+ };
+ };
+ };
+ };
+
+ funnel@6b04000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ arm,primecell-periphid = <0x000bb908>;
+
+ reg = <0 0x06b04000 0 0x1000>;
+ reg-names = "funnel-base";
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ funnel_swao_out_etf: endpoint {
+ remote-endpoint = <&etf_in_funnel_swao_out>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@7 {
+ reg = <7>;
+ funnel_swao_in_funnel_merg: endpoint {
+ remote-endpoint= <&funnel_merg_out_funnel_swao>;
+ };
+ };
+ };
+
+ };
+
+ etf@6b05000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0 0x06b05000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ etf_out: endpoint {
+ remote-endpoint = <&replicator_in>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ etf_in_funnel_swao_out: endpoint {
+ remote-endpoint = <&funnel_swao_out_etf>;
+ };
+ };
+ };
+ };
+
+ replicator@6b06000 {
+ compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
+ reg = <0 0x06b06000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ replicator_swao_out_cx_in: endpoint {
+ remote-endpoint = <&replicator_cx_in_swao_out>;
+ };
+ };
+ };
+
+ in-ports {
+ port {
+ replicator_in: endpoint {
+ remote-endpoint = <&etf_out>;
+ };
+ };
+ };
+ };
+
+ etm@7040000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07040000 0 0x1000>;
+
+ cpu = <&CPU0>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm0_out: endpoint {
+ remote-endpoint = <&apss_funnel_in0>;
+ };
+ };
+ };
+ };
+
+ etm@7140000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07140000 0 0x1000>;
+
+ cpu = <&CPU1>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm1_out: endpoint {
+ remote-endpoint = <&apss_funnel_in1>;
+ };
+ };
+ };
+ };
+
+ etm@7240000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07240000 0 0x1000>;
+
+ cpu = <&CPU2>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm2_out: endpoint {
+ remote-endpoint = <&apss_funnel_in2>;
+ };
+ };
+ };
+ };
+
+ etm@7340000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07340000 0 0x1000>;
+
+ cpu = <&CPU3>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm3_out: endpoint {
+ remote-endpoint = <&apss_funnel_in3>;
+ };
+ };
+ };
+ };
+
+ etm@7440000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07440000 0 0x1000>;
+
+ cpu = <&CPU4>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm4_out: endpoint {
+ remote-endpoint = <&apss_funnel_in4>;
+ };
+ };
+ };
+ };
+
+ etm@7540000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07540000 0 0x1000>;
+
+ cpu = <&CPU5>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm5_out: endpoint {
+ remote-endpoint = <&apss_funnel_in5>;
+ };
+ };
+ };
+ };
+
+ etm@7640000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07640000 0 0x1000>;
+
+ cpu = <&CPU6>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm6_out: endpoint {
+ remote-endpoint = <&apss_funnel_in6>;
+ };
+ };
+ };
+ };
+
+ etm@7740000 {
+ compatible = "arm,coresight-etm4x", "arm,primecell";
+ reg = <0 0x07740000 0 0x1000>;
+
+ cpu = <&CPU7>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ arm,coresight-loses-context-with-cpu;
+
+ out-ports {
+ port {
+ etm7_out: endpoint {
+ remote-endpoint = <&apss_funnel_in7>;
+ };
+ };
+ };
+ };
+
+ funnel@7800000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ reg = <0 0x07800000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ port {
+ funnel_apss_out_funnel_apss_merg: endpoint {
+ remote-endpoint = <&funnel_apss_merg_in_funnel_apss>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ apss_funnel_in0: endpoint {
+ remote-endpoint = <&etm0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ apss_funnel_in1: endpoint {
+ remote-endpoint = <&etm1_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ apss_funnel_in2: endpoint {
+ remote-endpoint = <&etm2_out>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ apss_funnel_in3: endpoint {
+ remote-endpoint = <&etm3_out>;
+ };
+ };
+
+ port@4 {
+ reg = <4>;
+ apss_funnel_in4: endpoint {
+ remote-endpoint = <&etm4_out>;
+ };
+ };
+
+ port@5 {
+ reg = <5>;
+ apss_funnel_in5: endpoint {
+ remote-endpoint = <&etm5_out>;
+ };
+ };
+
+ port@6 {
+ reg = <6>;
+ apss_funnel_in6: endpoint {
+ remote-endpoint = <&etm6_out>;
+ };
+ };
+
+ port@7 {
+ reg = <7>;
+ apss_funnel_in7: endpoint {
+ remote-endpoint = <&etm7_out>;
+ };
+ };
+ };
+ };
+
+ funnel@7810000 {
+ compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+ reg = <0 0x07810000 0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ out-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port {
+ funnel_apss_merg_out_funnel_in1: endpoint {
+ remote-endpoint = <&funnel_in1_in_funnel_apss_merg>;
+ };
+ };
+ };
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss_merg_in_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_out_funnel_apss_merg>;
+ };
+ };
+ };
+ };
+
cdsp: remoteproc@8300000 {
compatible = "qcom,sm8250-cdsp-pas";
reg = <0 0x08300000 0 0x10000>;
@@ -2891,15 +3388,11 @@
dp_phy: dp-phy@88ea200 {
reg = <0 0x088ea200 0 0x200>,
<0 0x088ea400 0 0x200>,
- <0 0x088eac00 0 0x400>,
+ <0 0x088eaa00 0 0x200>,
<0 0x088ea600 0 0x200>,
- <0 0x088ea800 0 0x200>,
- <0 0x088eaa00 0 0x100>;
+ <0 0x088ea800 0 0x200>;
#phy-cells = <0>;
#clock-cells = <1>;
- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
- clock-names = "pipe0";
- clock-output-names = "usb3_phy_pipe_clk_src";
};
};
@@ -3415,6 +3908,35 @@
"cam_hf_0_mnoc",
"cam_sf_0_mnoc",
"cam_sf_icp_mnoc";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+
+ port@1 {
+ reg = <1>;
+ };
+
+ port@2 {
+ reg = <2>;
+ };
+
+ port@3 {
+ reg = <3>;
+ };
+
+ port@4 {
+ reg = <4>;
+ };
+
+ port@5 {
+ reg = <5>;
+ };
+ };
};
camcc: clock-controller@ad00000 {
@@ -3555,7 +4077,6 @@
power-domains = <&rpmhpd SM8250_MMCX>;
phys = <&dsi0_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -3600,7 +4121,7 @@
};
};
- dsi0_phy: dsi-phy@ae94400 {
+ dsi0_phy: phy@ae94400 {
compatible = "qcom,dsi-phy-7nm";
reg = <0 0x0ae94400 0 0x200>,
<0 0x0ae94600 0 0x280>,
@@ -3647,7 +4168,6 @@
power-domains = <&rpmhpd SM8250_MMCX>;
phys = <&dsi1_phy>;
- phy-names = "dsi";
status = "disabled";
@@ -3673,7 +4193,7 @@
};
};
- dsi1_phy: dsi-phy@ae96400 {
+ dsi1_phy: phy@ae96400 {
compatible = "qcom,dsi-phy-7nm";
reg = <0 0x0ae96400 0 0x200>,
<0 0x0ae96600 0 0x280>,
@@ -3798,8 +4318,41 @@
gpio-ranges = <&tlmm 0 0 181>;
wakeup-parent = <&pdc>;
- cci0_default: cci0-default {
- cci0_i2c0_default: cci0-i2c0-default {
+ cam2_default: cam2-default-state {
+ rst-pins {
+ pins = "gpio78";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ mclk-pins {
+ pins = "gpio96";
+ function = "cam_mclk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ cam2_suspend: cam2-suspend-state {
+ rst-pins {
+ pins = "gpio78";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+
+ mclk-pins {
+ pins = "gpio96";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cci0_default: cci0-default-state {
+ cci0_i2c0_default: cci0-i2c0-default-pins {
/* SDA, SCL */
pins = "gpio101", "gpio102";
function = "cci_i2c";
@@ -3808,7 +4361,7 @@
drive-strength = <2>; /* 2 mA */
};
- cci0_i2c1_default: cci0-i2c1-default {
+ cci0_i2c1_default: cci0-i2c1-default-pins {
/* SDA, SCL */
pins = "gpio103", "gpio104";
function = "cci_i2c";
@@ -3818,8 +4371,8 @@
};
};
- cci0_sleep: cci0-sleep {
- cci0_i2c0_sleep: cci0-i2c0-sleep {
+ cci0_sleep: cci0-sleep-state {
+ cci0_i2c0_sleep: cci0-i2c0-sleep-pins {
/* SDA, SCL */
pins = "gpio101", "gpio102";
function = "cci_i2c";
@@ -3828,7 +4381,7 @@
bias-pull-down;
};
- cci0_i2c1_sleep: cci0-i2c1-sleep {
+ cci0_i2c1_sleep: cci0-i2c1-sleep-pins {
/* SDA, SCL */
pins = "gpio103", "gpio104";
function = "cci_i2c";
@@ -3838,8 +4391,8 @@
};
};
- cci1_default: cci1-default {
- cci1_i2c0_default: cci1-i2c0-default {
+ cci1_default: cci1-default-state {
+ cci1_i2c0_default: cci1-i2c0-default-pins {
/* SDA, SCL */
pins = "gpio105","gpio106";
function = "cci_i2c";
@@ -3848,7 +4401,7 @@
drive-strength = <2>; /* 2 mA */
};
- cci1_i2c1_default: cci1-i2c1-default {
+ cci1_i2c1_default: cci1-i2c1-default-pins {
/* SDA, SCL */
pins = "gpio107","gpio108";
function = "cci_i2c";
@@ -3858,8 +4411,8 @@
};
};
- cci1_sleep: cci1-sleep {
- cci1_i2c0_sleep: cci1-i2c0-sleep {
+ cci1_sleep: cci1-sleep-state {
+ cci1_i2c0_sleep: cci1-i2c0-sleep-pins {
/* SDA, SCL */
pins = "gpio105","gpio106";
function = "cci_i2c";
@@ -3868,7 +4421,7 @@
drive-strength = <2>; /* 2 mA */
};
- cci1_i2c1_sleep: cci1-i2c1-sleep {
+ cci1_i2c1_sleep: cci1-i2c1-sleep-pins {
/* SDA, SCL */
pins = "gpio107","gpio108";
function = "cci_i2c";
@@ -3878,22 +4431,22 @@
};
};
- pri_mi2s_active: pri-mi2s-active {
- sclk {
+ pri_mi2s_active: pri-mi2s-active-state {
+ sclk-pins {
pins = "gpio138";
function = "mi2s0_sck";
drive-strength = <8>;
bias-disable;
};
- ws {
+ ws-pins {
pins = "gpio141";
function = "mi2s0_ws";
drive-strength = <8>;
output-high;
};
- data0 {
+ data0-pins {
pins = "gpio139";
function = "mi2s0_data0";
drive-strength = <8>;
@@ -3901,7 +4454,7 @@
output-high;
};
- data1 {
+ data1-pins {
pins = "gpio140";
function = "mi2s0_data1";
drive-strength = <8>;
@@ -3909,632 +4462,500 @@
};
};
- qup_i2c0_default: qup-i2c0-default {
- mux {
- pins = "gpio28", "gpio29";
- function = "qup0";
- };
-
- config {
- pins = "gpio28", "gpio29";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c0_default: qup-i2c0-default-state {
+ pins = "gpio28", "gpio29";
+ function = "qup0";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c1_default: qup-i2c1-default {
- pinmux {
- pins = "gpio4", "gpio5";
- function = "qup1";
- };
-
- config {
- pins = "gpio4", "gpio5";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c1_default: qup-i2c1-default-state {
+ pins = "gpio4", "gpio5";
+ function = "qup1";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c2_default: qup-i2c2-default {
- mux {
- pins = "gpio115", "gpio116";
- function = "qup2";
- };
-
- config {
- pins = "gpio115", "gpio116";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c2_default: qup-i2c2-default-state {
+ pins = "gpio115", "gpio116";
+ function = "qup2";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c3_default: qup-i2c3-default {
- mux {
- pins = "gpio119", "gpio120";
- function = "qup3";
- };
-
- config {
- pins = "gpio119", "gpio120";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c3_default: qup-i2c3-default-state {
+ pins = "gpio119", "gpio120";
+ function = "qup3";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c4_default: qup-i2c4-default {
- mux {
- pins = "gpio8", "gpio9";
- function = "qup4";
- };
-
- config {
- pins = "gpio8", "gpio9";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c4_default: qup-i2c4-default-state {
+ pins = "gpio8", "gpio9";
+ function = "qup4";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c5_default: qup-i2c5-default {
- mux {
- pins = "gpio12", "gpio13";
- function = "qup5";
- };
-
- config {
- pins = "gpio12", "gpio13";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c5_default: qup-i2c5-default-state {
+ pins = "gpio12", "gpio13";
+ function = "qup5";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c6_default: qup-i2c6-default {
- mux {
- pins = "gpio16", "gpio17";
- function = "qup6";
- };
-
- config {
- pins = "gpio16", "gpio17";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c6_default: qup-i2c6-default-state {
+ pins = "gpio16", "gpio17";
+ function = "qup6";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c7_default: qup-i2c7-default {
- mux {
- pins = "gpio20", "gpio21";
- function = "qup7";
- };
-
- config {
- pins = "gpio20", "gpio21";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c7_default: qup-i2c7-default-state {
+ pins = "gpio20", "gpio21";
+ function = "qup7";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c8_default: qup-i2c8-default {
- mux {
- pins = "gpio24", "gpio25";
- function = "qup8";
- };
-
- config {
- pins = "gpio24", "gpio25";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c8_default: qup-i2c8-default-state {
+ pins = "gpio24", "gpio25";
+ function = "qup8";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c9_default: qup-i2c9-default {
- mux {
- pins = "gpio125", "gpio126";
- function = "qup9";
- };
-
- config {
- pins = "gpio125", "gpio126";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c9_default: qup-i2c9-default-state {
+ pins = "gpio125", "gpio126";
+ function = "qup9";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c10_default: qup-i2c10-default {
- mux {
- pins = "gpio129", "gpio130";
- function = "qup10";
- };
-
- config {
- pins = "gpio129", "gpio130";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c10_default: qup-i2c10-default-state {
+ pins = "gpio129", "gpio130";
+ function = "qup10";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c11_default: qup-i2c11-default {
- mux {
- pins = "gpio60", "gpio61";
- function = "qup11";
- };
-
- config {
- pins = "gpio60", "gpio61";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c11_default: qup-i2c11-default-state {
+ pins = "gpio60", "gpio61";
+ function = "qup11";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c12_default: qup-i2c12-default {
- mux {
- pins = "gpio32", "gpio33";
- function = "qup12";
- };
-
- config {
- pins = "gpio32", "gpio33";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c12_default: qup-i2c12-default-state {
+ pins = "gpio32", "gpio33";
+ function = "qup12";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c13_default: qup-i2c13-default {
- mux {
- pins = "gpio36", "gpio37";
- function = "qup13";
- };
-
- config {
- pins = "gpio36", "gpio37";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c13_default: qup-i2c13-default-state {
+ pins = "gpio36", "gpio37";
+ function = "qup13";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c14_default: qup-i2c14-default {
- mux {
- pins = "gpio40", "gpio41";
- function = "qup14";
- };
-
- config {
- pins = "gpio40", "gpio41";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c14_default: qup-i2c14-default-state {
+ pins = "gpio40", "gpio41";
+ function = "qup14";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c15_default: qup-i2c15-default {
- mux {
- pins = "gpio44", "gpio45";
- function = "qup15";
- };
-
- config {
- pins = "gpio44", "gpio45";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c15_default: qup-i2c15-default-state {
+ pins = "gpio44", "gpio45";
+ function = "qup15";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c16_default: qup-i2c16-default {
- mux {
- pins = "gpio48", "gpio49";
- function = "qup16";
- };
-
- config {
- pins = "gpio48", "gpio49";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c16_default: qup-i2c16-default-state {
+ pins = "gpio48", "gpio49";
+ function = "qup16";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c17_default: qup-i2c17-default {
- mux {
- pins = "gpio52", "gpio53";
- function = "qup17";
- };
-
- config {
- pins = "gpio52", "gpio53";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c17_default: qup-i2c17-default-state {
+ pins = "gpio52", "gpio53";
+ function = "qup17";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c18_default: qup-i2c18-default {
- mux {
- pins = "gpio56", "gpio57";
- function = "qup18";
- };
-
- config {
- pins = "gpio56", "gpio57";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c18_default: qup-i2c18-default-state {
+ pins = "gpio56", "gpio57";
+ function = "qup18";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_i2c19_default: qup-i2c19-default {
- mux {
- pins = "gpio0", "gpio1";
- function = "qup19";
- };
-
- config {
- pins = "gpio0", "gpio1";
- drive-strength = <2>;
- bias-disable;
- };
+ qup_i2c19_default: qup-i2c19-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup19";
+ drive-strength = <2>;
+ bias-disable;
};
- qup_spi0_cs: qup-spi0-cs {
+ qup_spi0_cs: qup-spi0-cs-state {
pins = "gpio31";
function = "qup0";
};
- qup_spi0_cs_gpio: qup-spi0-cs-gpio {
+ qup_spi0_cs_gpio: qup-spi0-cs-gpio-state {
pins = "gpio31";
function = "gpio";
};
- qup_spi0_data_clk: qup-spi0-data-clk {
+ qup_spi0_data_clk: qup-spi0-data-clk-state {
pins = "gpio28", "gpio29",
"gpio30";
function = "qup0";
};
- qup_spi1_cs: qup-spi1-cs {
+ qup_spi1_cs: qup-spi1-cs-state {
pins = "gpio7";
function = "qup1";
};
- qup_spi1_cs_gpio: qup-spi1-cs-gpio {
+ qup_spi1_cs_gpio: qup-spi1-cs-gpio-state {
pins = "gpio7";
function = "gpio";
};
- qup_spi1_data_clk: qup-spi1-data-clk {
+ qup_spi1_data_clk: qup-spi1-data-clk-state {
pins = "gpio4", "gpio5",
"gpio6";
function = "qup1";
};
- qup_spi2_cs: qup-spi2-cs {
+ qup_spi2_cs: qup-spi2-cs-state {
pins = "gpio118";
function = "qup2";
};
- qup_spi2_cs_gpio: qup-spi2-cs-gpio {
+ qup_spi2_cs_gpio: qup-spi2-cs-gpio-state {
pins = "gpio118";
function = "gpio";
};
- qup_spi2_data_clk: qup-spi2-data-clk {
+ qup_spi2_data_clk: qup-spi2-data-clk-state {
pins = "gpio115", "gpio116",
"gpio117";
function = "qup2";
};
- qup_spi3_cs: qup-spi3-cs {
+ qup_spi3_cs: qup-spi3-cs-state {
pins = "gpio122";
function = "qup3";
};
- qup_spi3_cs_gpio: qup-spi3-cs-gpio {
+ qup_spi3_cs_gpio: qup-spi3-cs-gpio-state {
pins = "gpio122";
function = "gpio";
};
- qup_spi3_data_clk: qup-spi3-data-clk {
+ qup_spi3_data_clk: qup-spi3-data-clk-state {
pins = "gpio119", "gpio120",
"gpio121";
function = "qup3";
};
- qup_spi4_cs: qup-spi4-cs {
+ qup_spi4_cs: qup-spi4-cs-state {
pins = "gpio11";
function = "qup4";
};
- qup_spi4_cs_gpio: qup-spi4-cs-gpio {
+ qup_spi4_cs_gpio: qup-spi4-cs-gpio-state {
pins = "gpio11";
function = "gpio";
};
- qup_spi4_data_clk: qup-spi4-data-clk {
+ qup_spi4_data_clk: qup-spi4-data-clk-state {
pins = "gpio8", "gpio9",
"gpio10";
function = "qup4";
};
- qup_spi5_cs: qup-spi5-cs {
+ qup_spi5_cs: qup-spi5-cs-state {
pins = "gpio15";
function = "qup5";
};
- qup_spi5_cs_gpio: qup-spi5-cs-gpio {
+ qup_spi5_cs_gpio: qup-spi5-cs-gpio-state {
pins = "gpio15";
function = "gpio";
};
- qup_spi5_data_clk: qup-spi5-data-clk {
+ qup_spi5_data_clk: qup-spi5-data-clk-state {
pins = "gpio12", "gpio13",
"gpio14";
function = "qup5";
};
- qup_spi6_cs: qup-spi6-cs {
+ qup_spi6_cs: qup-spi6-cs-state {
pins = "gpio19";
function = "qup6";
};
- qup_spi6_cs_gpio: qup-spi6-cs-gpio {
+ qup_spi6_cs_gpio: qup-spi6-cs-gpio-state {
pins = "gpio19";
function = "gpio";
};
- qup_spi6_data_clk: qup-spi6-data-clk {
+ qup_spi6_data_clk: qup-spi6-data-clk-state {
pins = "gpio16", "gpio17",
"gpio18";
function = "qup6";
};
- qup_spi7_cs: qup-spi7-cs {
+ qup_spi7_cs: qup-spi7-cs-state {
pins = "gpio23";
function = "qup7";
};
- qup_spi7_cs_gpio: qup-spi7-cs-gpio {
+ qup_spi7_cs_gpio: qup-spi7-cs-gpio-state {
pins = "gpio23";
function = "gpio";
};
- qup_spi7_data_clk: qup-spi7-data-clk {
+ qup_spi7_data_clk: qup-spi7-data-clk-state {
pins = "gpio20", "gpio21",
"gpio22";
function = "qup7";
};
- qup_spi8_cs: qup-spi8-cs {
+ qup_spi8_cs: qup-spi8-cs-state {
pins = "gpio27";
function = "qup8";
};
- qup_spi8_cs_gpio: qup-spi8-cs-gpio {
+ qup_spi8_cs_gpio: qup-spi8-cs-gpio-state {
pins = "gpio27";
function = "gpio";
};
- qup_spi8_data_clk: qup-spi8-data-clk {
+ qup_spi8_data_clk: qup-spi8-data-clk-state {
pins = "gpio24", "gpio25",
"gpio26";
function = "qup8";
};
- qup_spi9_cs: qup-spi9-cs {
+ qup_spi9_cs: qup-spi9-cs-state {
pins = "gpio128";
function = "qup9";
};
- qup_spi9_cs_gpio: qup-spi9-cs-gpio {
+ qup_spi9_cs_gpio: qup-spi9-cs-gpio-state {
pins = "gpio128";
function = "gpio";
};
- qup_spi9_data_clk: qup-spi9-data-clk {
+ qup_spi9_data_clk: qup-spi9-data-clk-state {
pins = "gpio125", "gpio126",
"gpio127";
function = "qup9";
};
- qup_spi10_cs: qup-spi10-cs {
+ qup_spi10_cs: qup-spi10-cs-state {
pins = "gpio132";
function = "qup10";
};
- qup_spi10_cs_gpio: qup-spi10-cs-gpio {
+ qup_spi10_cs_gpio: qup-spi10-cs-gpio-state {
pins = "gpio132";
function = "gpio";
};
- qup_spi10_data_clk: qup-spi10-data-clk {
+ qup_spi10_data_clk: qup-spi10-data-clk-state {
pins = "gpio129", "gpio130",
"gpio131";
function = "qup10";
};
- qup_spi11_cs: qup-spi11-cs {
+ qup_spi11_cs: qup-spi11-cs-state {
pins = "gpio63";
function = "qup11";
};
- qup_spi11_cs_gpio: qup-spi11-cs-gpio {
+ qup_spi11_cs_gpio: qup-spi11-cs-gpio-state {
pins = "gpio63";
function = "gpio";
};
- qup_spi11_data_clk: qup-spi11-data-clk {
+ qup_spi11_data_clk: qup-spi11-data-clk-state {
pins = "gpio60", "gpio61",
"gpio62";
function = "qup11";
};
- qup_spi12_cs: qup-spi12-cs {
+ qup_spi12_cs: qup-spi12-cs-state {
pins = "gpio35";
function = "qup12";
};
- qup_spi12_cs_gpio: qup-spi12-cs-gpio {
+ qup_spi12_cs_gpio: qup-spi12-cs-gpio-state {
pins = "gpio35";
function = "gpio";
};
- qup_spi12_data_clk: qup-spi12-data-clk {
+ qup_spi12_data_clk: qup-spi12-data-clk-state {
pins = "gpio32", "gpio33",
"gpio34";
function = "qup12";
};
- qup_spi13_cs: qup-spi13-cs {
+ qup_spi13_cs: qup-spi13-cs-state {
pins = "gpio39";
function = "qup13";
};
- qup_spi13_cs_gpio: qup-spi13-cs-gpio {
+ qup_spi13_cs_gpio: qup-spi13-cs-gpio-state {
pins = "gpio39";
function = "gpio";
};
- qup_spi13_data_clk: qup-spi13-data-clk {
+ qup_spi13_data_clk: qup-spi13-data-clk-state {
pins = "gpio36", "gpio37",
"gpio38";
function = "qup13";
};
- qup_spi14_cs: qup-spi14-cs {
+ qup_spi14_cs: qup-spi14-cs-state {
pins = "gpio43";
function = "qup14";
};
- qup_spi14_cs_gpio: qup-spi14-cs-gpio {
+ qup_spi14_cs_gpio: qup-spi14-cs-gpio-state {
pins = "gpio43";
function = "gpio";
};
- qup_spi14_data_clk: qup-spi14-data-clk {
+ qup_spi14_data_clk: qup-spi14-data-clk-state {
pins = "gpio40", "gpio41",
"gpio42";
function = "qup14";
};
- qup_spi15_cs: qup-spi15-cs {
+ qup_spi15_cs: qup-spi15-cs-state {
pins = "gpio47";
function = "qup15";
};
- qup_spi15_cs_gpio: qup-spi15-cs-gpio {
+ qup_spi15_cs_gpio: qup-spi15-cs-gpio-state {
pins = "gpio47";
function = "gpio";
};
- qup_spi15_data_clk: qup-spi15-data-clk {
+ qup_spi15_data_clk: qup-spi15-data-clk-state {
pins = "gpio44", "gpio45",
"gpio46";
function = "qup15";
};
- qup_spi16_cs: qup-spi16-cs {
+ qup_spi16_cs: qup-spi16-cs-state {
pins = "gpio51";
function = "qup16";
};
- qup_spi16_cs_gpio: qup-spi16-cs-gpio {
+ qup_spi16_cs_gpio: qup-spi16-cs-gpio-state {
pins = "gpio51";
function = "gpio";
};
- qup_spi16_data_clk: qup-spi16-data-clk {
+ qup_spi16_data_clk: qup-spi16-data-clk-state {
pins = "gpio48", "gpio49",
"gpio50";
function = "qup16";
};
- qup_spi17_cs: qup-spi17-cs {
+ qup_spi17_cs: qup-spi17-cs-state {
pins = "gpio55";
function = "qup17";
};
- qup_spi17_cs_gpio: qup-spi17-cs-gpio {
+ qup_spi17_cs_gpio: qup-spi17-cs-gpio-state {
pins = "gpio55";
function = "gpio";
};
- qup_spi17_data_clk: qup-spi17-data-clk {
+ qup_spi17_data_clk: qup-spi17-data-clk-state {
pins = "gpio52", "gpio53",
"gpio54";
function = "qup17";
};
- qup_spi18_cs: qup-spi18-cs {
+ qup_spi18_cs: qup-spi18-cs-state {
pins = "gpio59";
function = "qup18";
};
- qup_spi18_cs_gpio: qup-spi18-cs-gpio {
+ qup_spi18_cs_gpio: qup-spi18-cs-gpio-state {
pins = "gpio59";
function = "gpio";
};
- qup_spi18_data_clk: qup-spi18-data-clk {
+ qup_spi18_data_clk: qup-spi18-data-clk-state {
pins = "gpio56", "gpio57",
"gpio58";
function = "qup18";
};
- qup_spi19_cs: qup-spi19-cs {
+ qup_spi19_cs: qup-spi19-cs-state {
pins = "gpio3";
function = "qup19";
};
- qup_spi19_cs_gpio: qup-spi19-cs-gpio {
+ qup_spi19_cs_gpio: qup-spi19-cs-gpio-state {
pins = "gpio3";
function = "gpio";
};
- qup_spi19_data_clk: qup-spi19-data-clk {
+ qup_spi19_data_clk: qup-spi19-data-clk-state {
pins = "gpio0", "gpio1",
"gpio2";
function = "qup19";
};
- qup_uart2_default: qup-uart2-default {
- mux {
- pins = "gpio117", "gpio118";
- function = "qup2";
- };
+ qup_uart2_default: qup-uart2-default-state {
+ pins = "gpio117", "gpio118";
+ function = "qup2";
};
- qup_uart6_default: qup-uart6-default {
- mux {
- pins = "gpio16", "gpio17",
- "gpio18", "gpio19";
- function = "qup6";
- };
+ qup_uart6_default: qup-uart6-default-state {
+ pins = "gpio16", "gpio17", "gpio18", "gpio19";
+ function = "qup6";
};
- qup_uart12_default: qup-uart12-default {
- mux {
- pins = "gpio34", "gpio35";
- function = "qup12";
- };
+ qup_uart12_default: qup-uart12-default-state {
+ pins = "gpio34", "gpio35";
+ function = "qup12";
};
- qup_uart17_default: qup-uart17-default {
- mux {
- pins = "gpio52", "gpio53",
- "gpio54", "gpio55";
- function = "qup17";
- };
+ qup_uart17_default: qup-uart17-default-state {
+ pins = "gpio52", "gpio53", "gpio54", "gpio55";
+ function = "qup17";
};
- qup_uart18_default: qup-uart18-default {
- mux {
- pins = "gpio58", "gpio59";
- function = "qup18";
- };
+ qup_uart18_default: qup-uart18-default-state {
+ pins = "gpio58", "gpio59";
+ function = "qup18";
};
- tert_mi2s_active: tert-mi2s-active {
- sck {
+ tert_mi2s_active: tert-mi2s-active-state {
+ sck-pins {
pins = "gpio133";
function = "mi2s2_sck";
drive-strength = <8>;
bias-disable;
};
- data0 {
+ data0-pins {
pins = "gpio134";
function = "mi2s2_data0";
drive-strength = <8>;
@@ -4542,7 +4963,7 @@
output-high;
};
- ws {
+ ws-pins {
pins = "gpio135";
function = "mi2s2_ws";
drive-strength = <8>;
@@ -4550,42 +4971,42 @@
};
};
- sdc2_sleep_state: sdc2-sleep {
- clk {
+ sdc2_sleep_state: sdc2-sleep-state {
+ clk-pins {
pins = "sdc2_clk";
drive-strength = <2>;
bias-disable;
};
- cmd {
+ cmd-pins {
pins = "sdc2_cmd";
drive-strength = <2>;
bias-pull-up;
};
- data {
+ data-pins {
pins = "sdc2_data";
drive-strength = <2>;
bias-pull-up;
};
};
- pcie0_default_state: pcie0-default {
- perst {
+ pcie0_default_state: pcie0-default-state {
+ perst-pins {
pins = "gpio79";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio80";
function = "pci_e0";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio81";
function = "gpio";
drive-strength = <2>;
@@ -4593,22 +5014,22 @@
};
};
- pcie1_default_state: pcie1-default {
- perst {
+ pcie1_default_state: pcie1-default-state {
+ perst-pins {
pins = "gpio82";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio83";
function = "pci_e1";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio84";
function = "gpio";
drive-strength = <2>;
@@ -4616,22 +5037,22 @@
};
};
- pcie2_default_state: pcie2-default {
- perst {
+ pcie2_default_state: pcie2-default-state {
+ perst-pins {
pins = "gpio85";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
- clkreq {
+ clkreq-pins {
pins = "gpio86";
function = "pci_e2";
drive-strength = <2>;
bias-pull-up;
};
- wake {
+ wake-pins {
pins = "gpio87";
function = "gpio";
drive-strength = <2>;
@@ -4790,13 +5211,13 @@
#address-cells = <1>;
#size-cells = <0>;
- apr-service@3 {
+ service@3 {
reg = <APR_SVC_ADSP_CORE>;
compatible = "qcom,q6core";
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
- q6afe: apr-service@4 {
+ q6afe: service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -4807,13 +5228,13 @@
#sound-dai-cells = <1>;
};
- q6afecc: cc {
+ q6afecc: clock-controller {
compatible = "qcom,q6afe-clocks";
#clock-cells = <2>;
};
};
- q6asm: apr-service@7 {
+ q6asm: service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -4826,7 +5247,7 @@
};
};
- q6adm: apr-service@8 {
+ q6adm: service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
@@ -4955,6 +5376,7 @@
qcom,drv-id = <2>;
qcom,tcs-config = <ACTIVE_TCS 2>, <SLEEP_TCS 3>,
<WAKE_TCS 3>, <CONTROL_TCS 1>;
+ power-domains = <&CLUSTER_PD>;
rpmhcc: clock-controller {
compatible = "qcom,sm8250-rpmh-clk";
@@ -5019,7 +5441,7 @@
};
epss_l3: interconnect@18590000 {
- compatible = "qcom,sm8250-epss-l3";
+ compatible = "qcom,sm8250-epss-l3", "qcom,epss-l3";
reg = <0 0x18590000 0 0x1000>;
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
diff --git a/arch/arm64/boot/dts/qcom/sm8350-hdk.dts b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts
index 0fcf5bd88fc7..26a608144886 100644
--- a/arch/arm64/boot/dts/qcom/sm8350-hdk.dts
+++ b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts
@@ -107,6 +107,8 @@
regulator-max-microvolt = <888000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l6b_1p2: ldo6 {
@@ -115,6 +117,8 @@
regulator-max-microvolt = <1208000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l7b_2p96: ldo7 {
@@ -123,6 +127,8 @@
regulator-max-microvolt = <2504000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
vreg_l9b_1p2: ldo9 {
@@ -131,6 +137,8 @@
regulator-max-microvolt = <1200000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami-pdx215.dts b/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami-pdx215.dts
index d21bbeb603a6..c74c973a69d2 100644
--- a/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami-pdx215.dts
+++ b/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami-pdx215.dts
@@ -11,3 +11,209 @@
model = "Sony Xperia 1 III";
compatible = "sony,pdx215-generic", "qcom,sm8350";
};
+
+&tlmm {
+ gpio-line-names = "APPS_I2C_0_SDA", /* GPIO_0 */
+ "APPS_I2C_0_SCL",
+ "UWIDEC_PWR_EN",
+ "HAP_RST_N",
+ "WLC_I2C_SDA",
+ "WLC_I2C_SCL",
+ "PM8008_1_RESET_N",
+ "WLC_INT_N",
+ "OIS_TELE_I2C_SDA",
+ "OIS_TELE_I2C_SCL",
+ "PM8350_OPTION", /* GPIO_10 */
+ "NC",
+ "APPS_I2C_1_SDA",
+ "APPS_I2C_1_SCL",
+ "NC",
+ "NC",
+ "CAM1_RESET_N",
+ "LEO_CAM0_RESET_N",
+ "DEBUG_UART_TX",
+ "DEBUG_UART_RX",
+ "TS_I2C_SDA", /* GPIO_20 */
+ "TS_I2C_SCL",
+ "TS_RESET_N",
+ "TS_INT_N",
+ "DISP_RESET_N",
+ "SW_SERVICE",
+ "DISP_ERR_FG",
+ "TX_GTR_THRES_IN",
+ "NC",
+ "NC",
+ "NC", /* GPIO_30 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "SPK_AMP_INT_N",
+ "SPK_AMP_RESET_N",
+ "FP_INT_N",
+ "FP_RESET_N",
+ "NC", /* GPIO_40 */
+ "NC",
+ "DEBUG_GPIO0",
+ "FORCE_USB_BOOT",
+ "FP_SPI_MISO",
+ "FP_SPI_MOSI",
+ "FP_SPI_CLK",
+ "FP_SPI_CS_N",
+ "SPK_AMP_I2C_SDA",
+ "SPK_AMP_I2C_SCL",
+ "NC", /* GPIO_50 */
+ "HAP_INT_N",
+ "CAMSENSOR_I2C_SDA",
+ "CAMSENSOR_I2C_SCL",
+ "SBU_SW_OE",
+ "SBU_SW_SEL",
+ "NFC_ESE_SPI_MISO",
+ "NFC_ESE_SPI_MOSI",
+ "NFC_ESE_SPI_CLK",
+ "NFC_ESE_SPI_CS",
+ "NFC_I2C_SDA", /* GPIO_60 */
+ "NFC_I2C_SCL",
+ "NFC_EN",
+ "NFC_CLK_REQ",
+ "HST_WLAN_EN",
+ "HST_BT_EN",
+ "HW_ID_0",
+ "HW_ID_1",
+ "HST_BT_UART_CTS",
+ "HST_BT_UART_RFR",
+ "HST_BT_UART_TX", /* GPIO_70 */
+ "HST_BT_UART_RX",
+ "HAP_I2C_SDA",
+ "HAP_I2C_SCL",
+ "RF_LCD_ID_EN",
+ "RF_ID_EXTENSION",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HALL_INT_N", /* GPIO_80 */
+ "USB_CC_DIR",
+ "DISP_VSYNC",
+ "NC",
+ "NC",
+ "CAM_SOF_TELE",
+ "NFC_DWL_REQ",
+ "NFC_IRQ",
+ "WCD_RST_N",
+ "ALS_PROX_INT_N",
+ "NC", /* GPIO_90 */
+ "NC",
+ "TRAY_DET",
+ "UDON_SWITCH_SEL",
+ "PCIE0_RESET_N",
+ "PCIE0_CLK_REQ_N",
+ "PCIE0_WAKE_N",
+ "CAM_SOF",
+ "RF_ID_EXTENSION_2",
+ "RGBC_IR_INT",
+ "CAM_MCLK0", /* GPIO_100 */
+ "CAM_MCLK1",
+ "CAM_MCLK2",
+ "CAM_MCLK3",
+ "CAM_MCLK4",
+ "NC",
+ "CAM2_RESET_N",
+ "CCI_I2C0_SDA",
+ "CCI_I2C0_SCL",
+ "CCI_I2C1_SDA",
+ "CCI_I2C1_SCL", /* GPIO_110 */
+ "CCI_I2C2_SDA",
+ "CCI_I2C2_SCL",
+ "CCI_I2C3_SDA",
+ "CCI_I2C3_SCL",
+ "NC",
+ "PM8008_1_IRQ",
+ "CAM3_RESET_N",
+ "IMU1_INT",
+ "EXT_VD0_XVS",
+ "NC", /* GPIO_120 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HAP_I2S_CLK",
+ "HAP_I2S_DOUT",
+ "HAP_TRG1",
+ "HAP_I2S_SYNC",
+ "HST_BT_WLAN_SLIMBUS_CLK",
+ "HST_BT_WLAN_SLIMBUS_DAT0", /* GPIO_130 */
+ "NC",
+ "UIM2_DETECT_EN",
+ "UIM2_DATA",
+ "UIM2_CLK",
+ "UIM2_RESET",
+ "UIM2_PRESENT",
+ "UIM1_DATA",
+ "UIM1_CLK",
+ "UIM1_RESET",
+ "TRAY_DET", /* GPIO_140 */
+ "SM_RFFE0_CLK",
+ "SM_RFFE0_DATA",
+ "SM_RFFE1_CLK",
+ "SM_RFFE1_DATA",
+ "SM_MSS_GRFC4",
+ "SM_MSS_GRFC5",
+ "SM_MSS_GRFC6",
+ "SM_MSS_GRFC7",
+ "SM_RFFE4_CLK",
+ "SM_RFFE4_DATA", /* GPIO_150 */
+ "WLAN_COEX_UART1_RX",
+ "WLAN_COEX_UART1_TX",
+ "HST_SW_CTRL",
+ "DISP_VDDR_EN",
+ "NC",
+ "NC",
+ "PA_INDICATOR_OR",
+ "TOF_RST_N",
+ "QLINK0_REQ",
+ "QLINK0_EN", /* GPIO_160 */
+ "QLINK0_WMSS_RESET_N",
+ "QLINK1_REQ",
+ "QLINK1_EN",
+ "QLINK1_WMSS_RESET_N",
+ "PM8008_2_IRQ",
+ "TELEC_PWR_EN",
+ "PM8008_2_RESET_N",
+ "WCD_SWR_TX_CLK",
+ "WCD_SWR_TX_DATA0",
+ "WCD_SWR_TX_DATA1", /* GPIO_170 */
+ "WCD_SWR_RX_CLK",
+ "WCD_SWR_RX_DATA0",
+ "WCD_SWR_RX_DATA1",
+ "SM_DMIC1_CLK",
+ "SM_DMIC1_DATA",
+ "SM_DMIC2_CLK",
+ "SM_DMIC2_DATA",
+ "SPK_AMP_I2S_CLK",
+ "SPK_AMP_I2S_WS",
+ "SPK_AMP_I2S_ASP_DIN", /* GPIO_180 */
+ "SPK_AMP_I2S_ASP_DOUT",
+ "WCD_SWR_TX_DATA2",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "IMU_SPI_MISO",
+ "IMU_SPI_MOSI",
+ "IMU_SPI_CLK",
+ "IMU_SPI_CS_N", /* GPIO_190 */
+ "MAG_I2C_SDA",
+ "MAG_I2C_SCL",
+ "SENSOR_I2C_SDA",
+ "SENSOR_I2C_SCL",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HST_BLE_UART_TX",
+ "HST_BLE_UART_RX", /* GPIO_200 */
+ "HST_WLAN_UART_TX",
+ "HST_WLAN_UART_RX";
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi b/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi
index b3c9952ac173..1f2d660f8f86 100644
--- a/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi
@@ -3,6 +3,7 @@
* Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
*/
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include "sm8350.dtsi"
#include "pm8350.dtsi"
#include "pm8350b.dtsi"
@@ -73,16 +74,366 @@
no-map;
};
};
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
};
&adsp {
status = "okay";
- firmware-name = "qcom/adsp.mbn";
+ firmware-name = "qcom/sm8350/Sony/sagami/adsp.mbn";
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm8350-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+ vdd-s11-supply = <&vph_pwr>;
+ vdd-s12-supply = <&vph_pwr>;
+
+ vdd-l1-l4-supply = <&pm8350_s11>;
+ vdd-l2-l7-supply = <&vreg_bob>;
+ vdd-l3-l5-supply = <&vreg_bob>;
+ vdd-l6-l9-l10-supply = <&pm8350_s11>;
+
+ /*
+ * ARC regulators:
+ * S5 - mx.lvl
+ * S6 - gfx.lvl
+ * S9 - mxc.lvl
+ */
+
+ pm8350_s10: smps10 {
+ regulator-name = "pm8350_s10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_s11: smps11 {
+ regulator-name = "pm8350_s11";
+ regulator-min-microvolt = <752000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_s12: smps12 {
+ regulator-name = "pm8350_s12";
+ regulator-min-microvolt = <1224000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l1: ldo1 {
+ regulator-name = "pm8350_l1";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l2: ldo2 {
+ regulator-name = "pm8350_l2";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l3: ldo3 {
+ regulator-name = "pm8350_l3";
+ regulator-min-microvolt = <904000>;
+ regulator-max-microvolt = <904000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ /* L4 - lmx.lvl (ARC) */
+
+ pm8350_l5: ldo5 {
+ regulator-name = "pm8350_l5";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <888000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ pm8350_l6: ldo6 {
+ regulator-name = "pm8350_l6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1208000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ pm8350_l7: ldo7 {
+ regulator-name = "pm8350_l7";
+ regulator-min-microvolt = <2400000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ /* L8 - lcx.lvl (ARC) */
+
+ pm8350_l9: ldo9 {
+ regulator-name = "pm8350_l9";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8350c-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+
+ vdd-l1-l12-supply = <&pm8350c_s1>;
+ vdd-l2-l8-supply = <&pm8350c_s1>;
+ vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>;
+ vdd-l6-l9-l11-supply = <&vreg_bob>;
+ vdd-l10-supply = <&pm8350_s12>;
+
+ vdd-bob-supply = <&vph_pwr>;
+
+ pm8350c_s1: smps1 {
+ regulator-name = "pm8350c_s1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1952000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ /* S2 - ebi.lvl (ARC) */
+
+ pm8350c_s3: smps3 {
+ regulator-name = "pm8350c_s3";
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <704000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ /*
+ * ARC regulators:
+ * S4 - mss.lvl
+ * S6 - cx.lvl
+ * S8 - mmcx.lvl
+ */
+
+ pm8350c_s10: smps10 {
+ regulator-name = "pm8350c_s10";
+ regulator-min-microvolt = <1048000>;
+ regulator-max-microvolt = <1128000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l1: ldo1 {
+ regulator-name = "pm8350c_l1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l2: ldo2 {
+ regulator-name = "pm8350c_l2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l3: ldo3 {
+ regulator-name = "pm8350c_l3";
+ regulator-min-microvolt = <3304000>;
+ regulator-max-microvolt = <3304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l4: ldo4 {
+ regulator-name = "pm8350c_l4";
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l5: ldo5 {
+ regulator-name = "pm8350c_l5";
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l6: ldo6 {
+ regulator-name = "pm8350c_l6";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l7: ldo7 {
+ regulator-name = "pm8350c_l7";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l8: ldo8 {
+ regulator-name = "pm8350c_l8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l9: ldo9 {
+ regulator-name = "pm8350c_l9";
+ regulator-min-microvolt = <2960000>;
+ /* Originally max = 3008000 but SDHCI expects 2960000 */
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l10: ldo10 {
+ regulator-name = "pm8350c_l10";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l11: ldo11 {
+ regulator-name = "pm8350c_l11";
+ regulator-min-microvolt = <2400000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l12: ldo12 {
+ regulator-name = "pm8350c_l12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l13: ldo13 {
+ regulator-name = "pm8350c_l13";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_bob: bob {
+ regulator-name = "vreg_bob";
+ regulator-min-microvolt = <3400000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ };
+ };
+
+ /* TODO: Add pm8350b (just one ldo) once the driver part is in */
+
+ regulators-2 {
+ compatible = "qcom,pmr735a-rpmh-regulators";
+ qcom,pmic-id = "e";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+
+ vdd-l1-l2-supply = <&pmr735a_s2>;
+ vdd-l3-supply = <&pmr735a_s1>;
+ vdd-l4-supply = <&pm8350c_s1>;
+ vdd-l5-l6-supply = <&pm8350c_s1>;
+ vdd-l7-bob-supply = <&vreg_bob>;
+
+ pmr735a_s1: smps1 {
+ regulator-name = "pmr735a_s1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1280000>;
+ };
+
+ pmr735a_s2: smps2 {
+ regulator-name = "pmr735a_s2";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <976000>;
+ };
+
+ pmr735a_s3: smps3 {
+ regulator-name = "pmr735a_s3";
+ regulator-min-microvolt = <2208000>;
+ regulator-max-microvolt = <2352000>;
+ };
+
+ pmr735a_l1: ldo1 {
+ regulator-name = "pmr735a_l1";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <912000>;
+ };
+
+ pmr735a_l2: ldo2 {
+ regulator-name = "pmr735a_l2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pmr735a_l3: ldo3 {
+ regulator-name = "pmr735a_l3";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pmr735a_l4: ldo4 {
+ regulator-name = "pmr735a_l4";
+ regulator-min-microvolt = <1776000>;
+ regulator-max-microvolt = <1872000>;
+ };
+
+ pmr735a_l5: ldo5 {
+ regulator-name = "pmr735a_l5";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ };
+
+ pmr735a_l6: ldo6 {
+ regulator-name = "pmr735a_l6";
+ regulator-min-microvolt = <480000>;
+ regulator-max-microvolt = <904000>;
+ };
+
+ pmr735a_l7: ldo7 {
+ regulator-name = "pmr735a_l7";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+ };
};
&cdsp {
status = "okay";
- firmware-name = "qcom/cdsp.mbn";
+ firmware-name = "qcom/sm8350/Sony/sagami/cdsp.mbn";
};
&i2c1 {
@@ -175,12 +526,12 @@
&ipa {
status = "okay";
memory-region = <&pil_ipa_fw_mem>;
- firmware-name = "qcom/ipa_fws.mbn";
+ firmware-name = "qcom/sm8350/Sony/sagami/ipa_fws.mbn";
};
&mpss {
status = "okay";
- firmware-name = "qcom/modem.mbn";
+ firmware-name = "qcom/sm8350/Sony/sagami/modem.mbn";
};
&pmk8350_rtc {
@@ -208,9 +559,21 @@
status = "okay";
};
+&sdhc_2 {
+ cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_default_state &sdc2_card_det_active>;
+ pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_sleep>;
+ vmmc-supply = <&pm8350c_l9>;
+ vqmmc-supply = <&pm8350c_l6>;
+ no-sdio;
+ no-mmc;
+ status = "okay";
+};
+
&slpi {
status = "okay";
- firmware-name = "qcom/slpi.mbn";
+ firmware-name = "qcom/sm8350/Sony/sagami/slpi.mbn";
};
&spi14 {
@@ -221,6 +584,209 @@
&tlmm {
gpio-reserved-ranges = <44 4>;
+ gpio-line-names = "APPS_I2C_0_SDA", /* GPIO_0 */
+ "APPS_I2C_0_SCL",
+ "UWIDEC_PWR_EN",
+ "HAP_RST_N",
+ "NC",
+ "NC",
+ "PM8008_1_RESET_N",
+ "NC",
+ "OIS_TELE_I2C_SDA",
+ "OIS_TELE_I2C_SCL",
+ "PM8350_OPTION", /* GPIO_10 */
+ "NC",
+ "APPS_I2C_1_SDA",
+ "APPS_I2C_1_SCL",
+ "NC",
+ "NC",
+ "CAM1_RESET_N",
+ "LEO_CAM0_RESET_N",
+ "DEBUG_UART_TX",
+ "DEBUG_UART_RX",
+ "TS_I2C_SDA", /* GPIO_20 */
+ "TS_I2C_SCL",
+ "TS_RESET_N",
+ "TS_INT_N",
+ "DISP_RESET_N",
+ "SW_SERVICE",
+ "DISP_ERR_FG",
+ "TX_GTR_THRES_IN",
+ "NC",
+ "NC",
+ "NC", /* GPIO_30 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "SPK_AMP_INT_N",
+ "SPK_AMP_RESET_N",
+ "FP_INT_N",
+ "FP_RESET_N",
+ "NC", /* GPIO_40 */
+ "NC",
+ "DEBUG_GPIO0",
+ "FORCE_USB_BOOT",
+ "FP_SPI_MISO",
+ "FP_SPI_MOSI",
+ "FP_SPI_CLK",
+ "FP_SPI_CS_N",
+ "SPK_AMP_I2C_SDA",
+ "SPK_AMP_I2C_SCL",
+ "NC", /* GPIO_50 */
+ "HAP_INT_N",
+ "CAMSENSOR_I2C_SDA",
+ "CAMSENSOR_I2C_SCL",
+ "SBU_SW_OE",
+ "SBU_SW_SEL",
+ "NFC_ESE_SPI_MISO",
+ "NFC_ESE_SPI_MOSI",
+ "NFC_ESE_SPI_CLK",
+ "NFC_ESE_SPI_CS",
+ "NFC_I2C_SDA", /* GPIO_60 */
+ "NFC_I2C_SCL",
+ "NFC_EN",
+ "NFC_CLK_REQ",
+ "HST_WLAN_EN",
+ "HST_BT_EN",
+ "HW_ID_0",
+ "HW_ID_1",
+ "HST_BT_UART_CTS",
+ "HST_BT_UART_RFR",
+ "HST_BT_UART_TX", /* GPIO_70 */
+ "HST_BT_UART_RX",
+ "HAP_I2C_SDA",
+ "HAP_I2C_SCL",
+ "RF_LCD_ID_EN",
+ "RF_ID_EXTENSION",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HALL_INT_N", /* GPIO_80 */
+ "USB_CC_DIR",
+ "DISP_VSYNC",
+ "NC",
+ "NC",
+ "CAM_SOF_TELE",
+ "NFC_DWL_REQ",
+ "NFC_IRQ",
+ "WCD_RST_N",
+ "ALS_PROX_INT_N",
+ "NC", /* GPIO_90 */
+ "NC",
+ "TRAY_DET",
+ "UDON_SWITCH_SEL",
+ "PCIE0_RESET_N",
+ "PCIE0_CLK_REQ_N",
+ "PCIE0_WAKE_N",
+ "CAM_SOF",
+ "RF_ID_EXTENSION_2",
+ "RGBC_IR_INT",
+ "CAM_MCLK0", /* GPIO_100 */
+ "CAM_MCLK1",
+ "CAM_MCLK2",
+ "CAM_MCLK3",
+ "NC",
+ "NC",
+ "CAM2_RESET_N",
+ "CCI_I2C0_SDA",
+ "CCI_I2C0_SCL",
+ "CCI_I2C1_SDA",
+ "CCI_I2C1_SCL", /* GPIO_110 */
+ "CCI_I2C2_SDA",
+ "CCI_I2C2_SCL",
+ "CCI_I2C3_SDA",
+ "CCI_I2C3_SCL",
+ "NC",
+ "PM8008_1_IRQ",
+ "CAM3_RESET_N",
+ "IMU1_INT",
+ "EXT_VD0_XVS",
+ "NC", /* GPIO_120 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HAP_I2S_CLK",
+ "HAP_I2S_DOUT",
+ "HAP_TRG1",
+ "HAP_I2S_SYNC",
+ "HST_BT_WLAN_SLIMBUS_CLK",
+ "HST_BT_WLAN_SLIMBUS_DAT0", /* GPIO_130 */
+ "NC",
+ "UIM2_DETECT_EN",
+ "UIM2_DATA",
+ "UIM2_CLK",
+ "UIM2_RESET",
+ "UIM2_PRESENT",
+ "UIM1_DATA",
+ "UIM1_CLK",
+ "UIM1_RESET",
+ "TRAY_DET", /* GPIO_140 */
+ "SM_RFFE0_CLK",
+ "SM_RFFE0_DATA",
+ "SM_RFFE1_CLK",
+ "SM_RFFE1_DATA",
+ "SM_MSS_GRFC4",
+ "SM_MSS_GRFC5",
+ "SM_MSS_GRFC6",
+ "SM_MSS_GRFC7",
+ "SM_RFFE4_CLK",
+ "SM_RFFE4_DATA", /* GPIO_150 */
+ "WLAN_COEX_UART1_RX",
+ "WLAN_COEX_UART1_TX",
+ "HST_SW_CTRL",
+ "DISP_VDDR_EN",
+ "NC",
+ "NC",
+ "PA_INDICATOR_OR",
+ "NC",
+ "QLINK0_REQ",
+ "QLINK0_EN", /* GPIO_160 */
+ "QLINK0_WMSS_RESET_N",
+ "NC",
+ "NC",
+ "NC",
+ "PM8008_2_IRQ",
+ "TELEC_PWR_EN",
+ "PM8008_2_RESET_N",
+ "WCD_SWR_TX_CLK",
+ "WCD_SWR_TX_DATA0",
+ "WCD_SWR_TX_DATA1", /* GPIO_170 */
+ "WCD_SWR_RX_CLK",
+ "WCD_SWR_RX_DATA0",
+ "WCD_SWR_RX_DATA1",
+ "SM_DMIC1_CLK",
+ "SM_DMIC1_DATA",
+ "SM_DMIC2_CLK",
+ "SM_DMIC2_DATA",
+ "SPK_AMP_I2S_CLK",
+ "SPK_AMP_I2S_WS",
+ "SPK_AMP_I2S_ASP_DIN", /* GPIO_180 */
+ "SPK_AMP_I2S_ASP_DOUT",
+ "WCD_SWR_TX_DATA2",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "IMU_SPI_MISO",
+ "IMU_SPI_MOSI",
+ "IMU_SPI_CLK",
+ "IMU_SPI_CS_N", /* GPIO_190 */
+ "MAG_I2C_SDA",
+ "MAG_I2C_SCL",
+ "SENSOR_I2C_SDA",
+ "SENSOR_I2C_SCL",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "HST_BLE_UART_TX",
+ "HST_BLE_UART_RX", /* GPIO_200 */
+ "HST_WLAN_UART_TX",
+ "HST_WLAN_UART_RX";
ts_int_default: ts-int-default-state {
pins = "gpio23";
@@ -229,31 +795,45 @@
bias-disable;
input-enable;
};
+
+ sdc2_card_det_active: sd-card-det-active-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ sdc2_card_det_sleep: sd-card-det-sleep-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
};
/* BIG WARNING! DO NOT TOUCH UFS, YOUR DEVICE WILL DIE! */
&ufs_mem_hc { status = "disabled"; };
&ufs_mem_phy { status = "disabled"; };
-/* TODO: Make USB3 work (perhaps needs regulators for higher-current operation?) */
&usb_1 {
status = "okay";
-
- qcom,select-utmi-as-pipe-clk;
};
&usb_1_dwc3 {
dr_mode = "peripheral";
-
- maximum-speed = "high-speed";
- phys = <&usb_1_hsphy>;
- phy-names = "usb2-phy";
};
&usb_1_hsphy {
status = "okay";
+
+ vdda-pll-supply = <&pm8350_l5>;
+ vdda18-supply = <&pm8350c_l1>;
+ vdda33-supply = <&pm8350_l2>;
};
&usb_1_qmpphy {
status = "okay";
+
+ vdda-phy-supply = <&pm8350_l6>;
+ vdda-pll-supply = <&pm8350_l1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi
index a86d9ea93b9d..245dce24ec59 100644
--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi
@@ -678,7 +678,7 @@
};
gpi_dma2: dma-controller@800000 {
- compatible = "qcom,sm8350-gpi-dma";
+ compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma";
reg = <0 0x00800000 0 0x60000>;
interrupts = <GIC_SPI 588 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>,
@@ -904,7 +904,7 @@
};
gpi_dma0: dma-controller@900000 {
- compatible = "qcom,sm8350-gpi-dma";
+ compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma";
reg = <0 0x09800000 0 0x60000>;
interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
@@ -1209,7 +1209,7 @@
};
gpi_dma1: dma-controller@a00000 {
- compatible = "qcom,sm8350-gpi-dma";
+ compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma";
reg = <0 0x00a00000 0 0x60000>;
interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
@@ -1761,6 +1761,46 @@
gpio-ranges = <&tlmm 0 0 204>;
wakeup-parent = <&pdc>;
+ sdc2_default_state: sdc2-default-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+ };
+
+ sdc2_sleep_state: sdc2-sleep-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
qup_uart3_default_state: qup-uart3-default-state {
rx-pins {
pins = "gpio18";
@@ -2004,6 +2044,7 @@
qcom,drv-id = <2>;
qcom,tcs-config = <ACTIVE_TCS 2>, <SLEEP_TCS 3>,
<WAKE_TCS 3>, <CONTROL_TCS 0>;
+ power-domains = <&CLUSTER_PD>;
rpmhcc: clock-controller {
compatible = "qcom,sm8350-rpmh-clk";
@@ -2142,11 +2183,11 @@
status = "disabled";
ufs_mem_phy_lanes: phy@1d87400 {
- reg = <0 0x01d87400 0 0x108>,
- <0 0x01d87600 0 0x1e0>,
- <0 0x01d87c00 0 0x1dc>,
- <0 0x01d87800 0 0x108>,
- <0 0x01d87a00 0 0x1e0>;
+ reg = <0 0x01d87400 0 0x188>,
+ <0 0x01d87600 0 0x200>,
+ <0 0x01d87c00 0 0x200>,
+ <0 0x01d87800 0 0x188>,
+ <0 0x01d87a00 0 0x200>;
#phy-cells = <0>;
};
};
@@ -2221,7 +2262,7 @@
cdsp: remoteproc@98900000 {
compatible = "qcom,sm8350-cdsp-pas";
- reg = <0 0x098900000 0 0x1400000>;
+ reg = <0 0x98900000 0 0x1400000>;
interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>,
<&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>,
@@ -2328,6 +2369,45 @@
};
};
+ sdhc_2: sdhci@8804000 {
+ compatible = "qcom,sm8350-sdhci", "qcom,sdhci-msm-v5";
+ reg = <0 0x08804000 0 0x1000>;
+
+ interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+ <&gcc GCC_SDCC2_APPS_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "core", "xo";
+ resets = <&gcc GCC_SDCC2_BCR>;
+ interconnects = <&aggre2_noc MASTER_SDCC_2 0 &mc_virt SLAVE_EBI1 0>,
+ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_SDCC_2 0>;
+ interconnect-names = "sdhc-ddr","cpu-sdhc";
+ iommus = <&apps_smmu 0x4a0 0x0>;
+ power-domains = <&rpmhpd SM8350_CX>;
+ operating-points-v2 = <&sdhc2_opp_table>;
+ bus-width = <4>;
+ dma-coherent;
+
+ status = "disabled";
+
+ sdhc2_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-202000000 {
+ opp-hz = /bits/ 64 <202000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
usb_1_hsphy: phy@88e3000 {
compatible = "qcom,sm8350-usb-hs-phy",
"qcom,usb-snps-hs-7nm-phy";
diff --git a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts
index 38ccd44620d0..4de3e1f1c39c 100644
--- a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts
+++ b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "sm8450.dtsi"
/ {
@@ -394,8 +395,181 @@
status = "okay";
};
+&sdhc_2 {
+ cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>;
+ pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_n>;
+ vmmc-supply = <&vreg_l9c_2p96>;
+ vqmmc-supply = <&vreg_l6c_1p8>;
+ no-sdio;
+ no-mmc;
+ status = "okay";
+};
+
+&soc {
+ wcd938x: codec {
+ compatible = "qcom,wcd9380-codec";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_default>;
+
+ qcom,micbias1-microvolt = <1800000>;
+ qcom,micbias2-microvolt = <1800000>;
+ qcom,micbias3-microvolt = <1800000>;
+ qcom,micbias4-microvolt = <1800000>;
+ qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>;
+ qcom,mbhc-headset-vthreshold-microvolt = <1700000>;
+ qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
+ qcom,rx-device = <&wcd_rx>;
+ qcom,tx-device = <&wcd_tx>;
+
+ reset-gpios = <&tlmm 43 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <1>;
+
+ vdd-buck-supply = <&vreg_s10b_1p8>;
+ vdd-rxtx-supply = <&vreg_s10b_1p8>;
+ vdd-io-supply = <&vreg_s10b_1p8>;
+ vdd-mic-bias-supply = <&vreg_bob>;
+ };
+};
+
+&sound {
+ compatible = "qcom,sm8450-sndcard";
+ model = "SM8450-HDK";
+ audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT",
+ "SpkrRight IN", "WSA_SPK2 OUT",
+ "IN1_HPHL", "HPHL_OUT",
+ "IN2_HPHR", "HPHR_OUT",
+ "AMIC2", "MIC BIAS2",
+ "VA DMIC0", "MIC BIAS1",
+ "VA DMIC1", "MIC BIAS1",
+ "VA DMIC2", "MIC BIAS3",
+ "TX DMIC0", "MIC BIAS1",
+ "TX DMIC1", "MIC BIAS2",
+ "TX DMIC2", "MIC BIAS3",
+ "TX SWR_ADC1", "ADC2_OUTPUT";
+
+ wcd-playback-dai-link {
+ link-name = "WCD Playback";
+
+ cpu {
+ sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
+ };
+
+ codec {
+ sound-dai = <&wcd938x 0>, <&swr1 0>, <&rxmacro 0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ wcd-capture-dai-link {
+ link-name = "WCD Capture";
+
+ cpu {
+ sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+ };
+
+ codec {
+ sound-dai = <&wcd938x 1>, <&swr2 0>, <&txmacro 0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ wsa-dai-link {
+ link-name = "WSA Playback";
+
+ cpu {
+ sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+ };
+
+ codec {
+ sound-dai = <&left_spkr>, <&right_spkr>, <&swr0 0>, <&wsamacro 0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ va-dai-link {
+ link-name = "VA Capture";
+
+ cpu {
+ sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+ };
+
+ codec {
+ sound-dai = <&vamacro 0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+};
+
+&swr0 {
+ left_spkr: speaker@0,1 {
+ compatible = "sdw10217020200";
+ reg = <0 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ powerdown-gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrLeft";
+ #thermal-sensor-cells = <0>;
+ vdd-supply = <&vreg_s10b_1p8>;
+ };
+
+ right_spkr: speaker@0,2 {
+ compatible = "sdw10217020200";
+ reg = <0 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ powerdown-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrRight";
+ #thermal-sensor-cells = <0>;
+ vdd-supply = <&vreg_s10b_1p8>;
+ };
+};
+
+&swr1 {
+ status = "okay";
+
+ wcd_rx: codec@0,4 {
+ compatible = "sdw20217010d00";
+ reg = <0 4>;
+ qcom,rx-port-mapping = <1 2 3 4 5>;
+ };
+};
+
+&swr2 {
+ status = "okay";
+
+ wcd_tx: codec@0,3 {
+ compatible = "sdw20217010d00";
+ reg = <0 3>;
+ qcom,tx-port-mapping = <1 1 2 3>;
+ };
+};
+
&tlmm {
gpio-reserved-ranges = <28 4>, <36 4>;
+
+ sdc2_card_det_n: sd-card-det-n-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
};
&uart7 {
@@ -442,3 +616,34 @@
vdda-phy-supply = <&vreg_l6b_1p2>;
vdda-pll-supply = <&vreg_l1b_0p91>;
};
+
+&vamacro {
+ pinctrl-0 = <&dmic01_default>, <&dmic02_default>;
+ pinctrl-names = "default";
+ vdd-micb-supply = <&vreg_s10b_1p8>;
+ qcom,dmic-sample-rate = <600000>;
+};
+
+&tlmm {
+ spkr_1_sd_n_active: spkr-1-sd-n-active-state {
+ pins = "gpio1";
+ function = "gpio";
+ drive-strength = <4>;
+ bias-disable;
+ output-low;
+ };
+
+ spkr_2_sd_n_active: spkr-2-sd-n-active-state {
+ pins = "gpio89";
+ function = "gpio";
+ drive-strength = <4>;
+ bias-disable;
+ output-low;
+ };
+
+ wcd_default: wcd-default-state {
+ pins = "gpio43";
+ function = "gpio";
+ bias-disable;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts
index e58fc7399799..ee62514fff68 100644
--- a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts
@@ -388,6 +388,18 @@
firmware-name = "qcom/sm8450/slpi.mbn";
};
+&sdhc_2 {
+ cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>;
+ pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_n>;
+ vmmc-supply = <&vreg_l9c_2p96>;
+ vqmmc-supply = <&vreg_l6c_1p8>;
+ no-sdio;
+ no-mmc;
+ status = "okay";
+};
+
&spi4 {
status = "okay";
};
@@ -402,6 +414,13 @@
&tlmm {
gpio-reserved-ranges = <28 4>, <36 4>;
+
+ sdc2_card_det_n: sd-card-det-n-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
};
&uart7 {
diff --git a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts
index d68765eb6d4f..b83500316a81 100644
--- a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts
+++ b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx223.dts
@@ -1,634 +1,227 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Linaro Limited
*/
/dts-v1/;
-#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
-#include "sm8450.dtsi"
-
-/delete-node/ &adsp_mem;
-/delete-node/ &rmtfs_mem;
-/delete-node/ &video_mem;
+#include "sm8450-sony-xperia-nagara.dtsi"
/ {
model = "Sony Xperia 1 IV";
compatible = "sony,pdx223", "qcom,sm8450";
- chassis-type = "handset";
-
- aliases {
- serial0 = &uart7;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
- reserved-memory {
- adsp_mem: memory@85700000 {
- reg = <0x0 0x85700000 0x0 0x2800000>;
- no-map;
- };
-
- video_mem: memory@9fd00000 {
- reg = <0x0 0x9fd00000 0x0 0x700000>;
- no-map;
- };
-
- rmtfs_mem: memory@f3300000 {
- compatible = "qcom,rmtfs-mem";
- reg = <0x0 0xf3300000 0x0 0x280000>;
- no-map;
-
- qcom,client-id = <1>;
- qcom,vmid = <15>;
- };
-
- ramoops@ffc00000 {
- compatible = "ramoops";
- reg = <0 0xffc00000 0 0x200000>;
- console-size = <0x40000>;
- record-size = <0x1000>;
- ecc-size = <16>;
- no-map;
- };
- };
-
- /* Sadly, the voltages for these GPIO regulators are unknown. */
- imx650_vana_vreg: imx650-vana-regulator {
- compatible = "regulator-fixed";
- regulator-name = "imx650_vana_vreg";
- gpio = <&tlmm 23 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
- vph_pwr: vph-pwr-regulator {
- compatible = "regulator-fixed";
- regulator-name = "vph_pwr";
- regulator-min-microvolt = <3700000>;
- regulator-max-microvolt = <3700000>;
-
- regulator-always-on;
- regulator-boot-on;
- };
-};
-
-&apps_rsc {
- pm8350-rpmh-regulators {
- compatible = "qcom,pm8350-rpmh-regulators";
- qcom,pmic-id = "b";
-
- vdd-s1-supply = <&vph_pwr>;
- vdd-s2-supply = <&vph_pwr>;
- vdd-s3-supply = <&vph_pwr>;
- vdd-s4-supply = <&vph_pwr>;
- vdd-s5-supply = <&vph_pwr>;
- vdd-s6-supply = <&vph_pwr>;
- vdd-s7-supply = <&vph_pwr>;
- vdd-s8-supply = <&vph_pwr>;
- vdd-s9-supply = <&vph_pwr>;
- vdd-s10-supply = <&vph_pwr>;
- vdd-s11-supply = <&vph_pwr>;
- vdd-s12-supply = <&vph_pwr>;
-
- vdd-l1-l4-supply = <&pm8350_s11>;
- vdd-l2-l7-supply = <&vreg_bob>;
- vdd-l3-l5-supply = <&vreg_bob>;
- vdd-l6-l9-l10-supply = <&pm8350_s12>;
-
- /*
- * ARC regulators:
- * s5 - gfx.lvl
- * l8 - lcx.lvl
- */
-
- pm8350_s10: smps10 {
- regulator-name = "pm8350_s10";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm8350_s11: smps11 {
- regulator-name = "pm8350_s11";
- regulator-min-microvolt = <848000>;
- regulator-max-microvolt = <1104000>;
- };
-
- pm8350_s12: smps12 {
- regulator-name = "pm8350_s12";
- regulator-min-microvolt = <1224000>;
- regulator-max-microvolt = <1400000>;
- };
-
- pm8350_l1: ldo1 {
- regulator-name = "pm8350_l1";
- regulator-min-microvolt = <912000>;
- regulator-max-microvolt = <920000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l2: ldo2 {
- regulator-name = "pm8350_l2";
- regulator-min-microvolt = <3072000>;
- regulator-max-microvolt = <3072000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l3: ldo3 {
- regulator-name = "pm8350_l3";
- regulator-min-microvolt = <904000>;
- regulator-max-microvolt = <904000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l5: ldo5 {
- regulator-name = "pm8350_l5";
- regulator-min-microvolt = <880000>;
- regulator-max-microvolt = <912000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l6: ldo6 {
- regulator-name = "pm8350_l6";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l7: ldo7 {
- regulator-name = "pm8350_l7";
- regulator-min-microvolt = <2504000>;
- regulator-max-microvolt = <2504000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350_l9: ldo9 {
- regulator-name = "pm8350_l9";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
- };
-
- pm8350c-rpmh-regulators {
- compatible = "qcom,pm8350c-rpmh-regulators";
- qcom,pmic-id = "c";
-
- vdd-s1-supply = <&vph_pwr>;
- vdd-s2-supply = <&vph_pwr>;
- vdd-s3-supply = <&vph_pwr>;
- vdd-s4-supply = <&vph_pwr>;
- vdd-s5-supply = <&vph_pwr>;
- vdd-s6-supply = <&vph_pwr>;
- vdd-s7-supply = <&vph_pwr>;
- vdd-s8-supply = <&vph_pwr>;
- vdd-s9-supply = <&vph_pwr>;
- vdd-s10-supply = <&vph_pwr>;
-
- vdd-l1-l12-supply = <&vreg_bob>;
- vdd-l2-l8-supply = <&vreg_bob>;
- vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>;
- vdd-l6-l9-l11-supply = <&vreg_bob>;
- vdd-l10-supply = <&pm8350_s12>;
-
- vdd-bob-supply = <&vph_pwr>;
-
- /*
- * ARC regulators:
- * s2 - mxc.lvl
- * s4 - mss.lvl
- * s6 - cx.lvl
- */
-
- pm8350c_s1: smps1 {
- regulator-name = "pm8350c_s1";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2024000>;
- };
-
- pm8350c_s10: smps10 {
- regulator-name = "pm8350c_s10";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1100000>;
- };
-
- vreg_bob: bob {
- regulator-name = "vreg_bob";
- regulator-min-microvolt = <3400000>;
- regulator-max-microvolt = <3960000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
- };
-
- pm8350c_l1: ldo1 {
- regulator-name = "pm8350c_l1";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l2: ldo2 {
- regulator-name = "pm8350c_l2";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l3: ldo3 {
- regulator-name = "pm8350c_l3";
- regulator-min-microvolt = <3296000>;
- regulator-max-microvolt = <3304000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l4: ldo4 {
- regulator-name = "pm8350c_l4";
- regulator-min-microvolt = <1704000>;
- regulator-max-microvolt = <3000000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l5: ldo5 {
- regulator-name = "pm8350c_l5";
- regulator-min-microvolt = <1704000>;
- regulator-max-microvolt = <3000000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l6: ldo6 {
- regulator-name = "pm8350c_l6";
- regulator-min-microvolt = <2960000>;
- /* Originally max = 3008000 but SDHCI expects 2960000 */
- regulator-max-microvolt = <2960000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l7: ldo7 {
- regulator-name = "pm8350c_l7";
- regulator-min-microvolt = <3008000>;
- regulator-max-microvolt = <3008000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l8: ldo8 {
- regulator-name = "pm8350c_l8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l9: ldo9 {
- regulator-name = "pm8350c_l9";
- regulator-min-microvolt = <2960000>;
- /* Originally max = 3008000 but SDHCI expects 2960000 */
- regulator-max-microvolt = <2960000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l10: ldo10 {
- regulator-name = "pm8350c_l10";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l12: ldo12 {
- regulator-name = "pm8350c_l12";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1968000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8350c_l13: ldo13 {
- regulator-name = "pm8350c_l13";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
- };
-
- pm8450-rpmh-regulators {
- compatible = "qcom,pm8450-rpmh-regulators";
- qcom,pmic-id = "h";
-
- vdd-s1-supply = <&vph_pwr>;
- vdd-s2-supply = <&vph_pwr>;
- vdd-s3-supply = <&vph_pwr>;
- vdd-s4-supply = <&vph_pwr>;
- vdd-s5-supply = <&vph_pwr>;
- vdd-s6-supply = <&vph_pwr>;
-
- vdd-l2-supply = <&vreg_bob>;
- vdd-l3-supply = <&vreg_bob>;
- vdd-l4-supply = <&vreg_bob>;
-
- /*
- * ARC regulators:
- * S2 - ebi.lvl
- * S4 - mmcx.lvl
- * S6 - mx.lvl
- * L1 - lmx.lvl
- */
-
- pm8450_s3: smps3 {
- regulator-name = "pm8450_s3";
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <600000>;
- };
-
- pm8450_l2: ldo2 {
- regulator-name = "pm8450_l2";
- regulator-min-microvolt = <880000>;
- regulator-max-microvolt = <912000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
-
- pm8450_l3: ldo3 {
- regulator-name = "pm8450_l3";
- regulator-min-microvolt = <912000>;
- regulator-max-microvolt = <912000>;
- regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- };
- };
-
- pmr735a-rpmh-regulators {
- compatible = "qcom,pmr735a-rpmh-regulators";
- qcom,pmic-id = "e";
-
- vdd-s1-supply = <&vph_pwr>;
- vdd-s2-supply = <&vph_pwr>;
- vdd-s3-supply = <&vph_pwr>;
-
- vdd-l1-l2-supply = <&pmr735a_s2>;
- vdd-l3-supply = <&pmr735a_s1>;
- vdd-l4-supply = <&pm8350c_s1>;
- vdd-l5-l6-supply = <&pm8350c_s1>;
- vdd-l7-bob-supply = <&vreg_bob>;
-
- pmr735a_s1: smps1 {
- regulator-name = "pmr735a_s1";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1296000>;
- };
-
- pmr735a_s2: smps2 {
- regulator-name = "pmr735a_s2";
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <1040000>;
- };
-
- pmr735a_s3: smps3 {
- regulator-name = "pmr735a_s3";
- regulator-min-microvolt = <435000>;
- regulator-max-microvolt = <2352000>;
- };
-
- pmr735a_l1: ldo1 {
- regulator-name = "pmr735a_l1";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <800000>;
- };
-
- pmr735a_l2: ldo2 {
- regulator-name = "pmr735a_l2";
- regulator-min-microvolt = <480000>;
- regulator-max-microvolt = <912000>;
- };
-
- pmr735a_l3: ldo3 {
- regulator-name = "pmr735a_l3";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- pmr735a_l4: ldo4 {
- regulator-name = "pmr735a_l4";
- regulator-min-microvolt = <1776000>;
- regulator-max-microvolt = <1776000>;
- };
-
- pmr735a_l5: ldo5 {
- regulator-name = "pmr735a_l5";
- regulator-min-microvolt = <880000>;
- regulator-max-microvolt = <880000>;
- };
-
- pmr735a_l6: ldo6 {
- regulator-name = "pmr735a_l6";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- pmr735a_l7: ldo7 {
- regulator-name = "pmr735a_l7";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
- };
-};
-
-&gpi_dma0 {
- status = "okay";
-};
-
-&gpi_dma1 {
- status = "okay";
-};
-
-&gpi_dma2 {
- status = "okay";
-};
-
-/* I2C4 is used, it hosts a Samsung touchscreen, but GPI DMA is broken.. */
-
-&i2c5 {
- clock-frequency = <400000>;
- status = "okay";
-
- /* Dialog SLG51000 CMIC @ 75 */
-};
-
-&i2c9 {
- clock-frequency = <400000>;
- status = "okay";
-
- /* NXP SN1X0 NFC @ 28 */
-};
-
-&i2c13 {
- clock-frequency = <400000>;
- status = "okay";
-
- /* Richwave RTC6226 FM Radio Receiver @ 64 */
-};
-
-&i2c14 {
- clock-frequency = <1000000>;
- status = "okay";
-
- cs35l41_l: speaker-amp@40 {
- compatible = "cirrus,cs35l41";
- reg = <0x40>;
- interrupt-parent = <&tlmm>;
- interrupts = <182 IRQ_TYPE_LEVEL_LOW>;
- reset-gpios = <&tlmm 183 GPIO_ACTIVE_HIGH>;
- cirrus,boost-peak-milliamp = <4000>;
- cirrus,boost-ind-nanohenry = <1000>;
- cirrus,boost-cap-microfarad = <15>;
- cirrus,gpio2-src-select = <2>;
- cirrus,gpio2-output-enable;
- cirrus,asp-sdout-hiz = <3>;
- #sound-dai-cells = <1>;
- };
-
- cs35l41_r: speaker-amp@41 {
- compatible = "cirrus,cs35l41";
- reg = <0x41>;
- interrupt-parent = <&tlmm>;
- interrupts = <182 IRQ_TYPE_LEVEL_LOW>;
- reset-gpios = <&tlmm 183 GPIO_ACTIVE_HIGH>;
- cirrus,boost-peak-milliamp = <4000>;
- cirrus,boost-ind-nanohenry = <1000>;
- cirrus,boost-cap-microfarad = <15>;
- cirrus,gpio2-src-select = <2>;
- cirrus,gpio2-output-enable;
- cirrus,asp-sdout-hiz = <3>;
- #sound-dai-cells = <1>;
- };
-};
-
-&i2c15 {
- clock-frequency = <400000>;
- status = "okay";
-
- /* AMS TCS3490 RGB+IR color sensor @ 72 */
-};
-
-&i2c19 {
- clock-frequency = <1000000>;
- status = "okay";
-
- /* Cirrus Logic CS40L25A boosted haptics driver @ 40 */
-};
-
-&pcie0 {
- max-link-speed = <2>;
- status = "okay";
-};
-
-&pcie0_phy {
- vdda-phy-supply = <&pm8350_l5>;
- vdda-pll-supply = <&pm8350_l6>;
- status = "okay";
-};
-
-&remoteproc_adsp {
- firmware-name = "qcom/adsp.mbn";
- status = "okay";
-};
-
-&remoteproc_cdsp {
- firmware-name = "qcom/cdsp.mbn";
- status = "okay";
-};
-
-&remoteproc_slpi {
- firmware-name = "qcom/slpi.mbn";
- status = "okay";
-};
-
-&qupv3_id_0 {
- status = "okay";
-};
-
-&qupv3_id_1 {
- status = "okay";
-};
-
-&qupv3_id_2 {
- status = "okay";
-};
-
-&sdhc_2 {
- cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>;
- pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_n>;
- vmmc-supply = <&pm8350c_l9>;
- vqmmc-supply = <&pm8350c_l6>;
- /* Forbid SDR104/SDR50 - broken hw! */
- sdhci-caps-mask = <0x3 0x0>;
- no-sdio;
- no-mmc;
- status = "okay";
-};
-
-&spi10 {
- status = "okay";
-
- /* NXP SN1X0 NFC Secure Element @ 0 */
};
&tlmm {
- gpio-reserved-ranges = <28 4>;
-
- sdc2_default_state: sdc2-default-state {
- clk-pins {
- pins = "sdc2_clk";
- drive-strength = <16>;
- bias-disable;
- };
-
- cmd-pins {
- pins = "sdc2_cmd";
- drive-strength = <16>;
- bias-pull-up;
- };
-
- data-pins {
- pins = "sdc2_data";
- drive-strength = <16>;
- bias-pull-up;
- };
- };
-
- ts_int_default: ts-int-default-state {
- pins = "gpio23";
- function = "gpio";
- drive-strength = <2>;
- bias-disable;
- input-enable;
- };
-
- sdc2_card_det_n: sd-card-det-n-state {
- pins = "gpio92";
- function = "gpio";
- drive-strength = <2>;
- bias-pull-up;
- };
-};
-
-&uart7 {
- status = "okay";
-};
-
-&usb_1 {
- status = "okay";
-};
-
-&usb_1_dwc3 {
- dr_mode = "peripheral";
-};
-
-&usb_1_hsphy {
- vdda-pll-supply = <&pm8350_l5>;
- vdda18-supply = <&pm8350c_l1>;
- vdda33-supply = <&pm8350_l2>;
- status = "okay";
-};
-
-&usb_1_qmpphy {
- vdda-phy-supply = <&pm8350_l6>;
- vdda-pll-supply = <&pm8350_l1>;
- status = "okay";
+ gpio-line-names = "NC", /* GPIO_0 */
+ "NC",
+ "NC",
+ "NC",
+ "WLC_I2C_SDA",
+ "WLC_I2C_SCL",
+ "NC",
+ "PM8010_1_RESET_N",
+ "WLC_INT_N",
+ "NC",
+ "NC", /* GPIO_10 */
+ "PM8010_2_RESET_N",
+ "DISP_ERR_FG",
+ "HALL_INT_N",
+ "ALS_PROX_INT_N",
+ "IMU1_INT",
+ "TS_I2C_SDA",
+ "TS_I2C_SCL",
+ "DISP_RESET_N",
+ "DISP_VDDR_EN",
+ "TS_RESET_N", /* GPIO_20 */
+ "TS_INT_N",
+ "NC",
+ "TELEC_PWR_EN",
+ "CAM1_RESET_N",
+ "LEO_CAM0_RESET_N",
+ "DEBUG_UART_TX",
+ "DEBUG_UART_RX",
+ "FP_SPI_MISO",
+ "FP_SPI_MOSI",
+ "FP_SPI_CLK", /* GPIO_30 */
+ "FP_SPI_CS_N",
+ "NFC_I2C_SDA",
+ "NFC_I2C_SCL",
+ "NFC_EN",
+ "NFC_CLK_REQ",
+ "NFC_ESE_SPI_MISO",
+ "NFC_ESE_SPI_MOSI",
+ "NFC_ESE_SPI_CLK",
+ "NFC_ESE_SPI_CS",
+ "FP_INT_N", /* GPIO_40 */
+ "NC",
+ "FP_RESET_N",
+ "WCD_RST_N",
+ "NC",
+ "NFC_DWL_REQ",
+ "NFC_IRQ",
+ "FORCE_USB_BOOT",
+ "APPS_I2C_1_SDA",
+ "APPS_I2C_1_SCL",
+ "SBU_SW_OE", /* GPIO_50 */
+ "SBU_SW_SEL",
+ "SPK_AMP_I2C_SDA",
+ "SPK_AMP_I2C_SCL",
+ "NC",
+ "NC",
+ "CAMSENSOR_I2C_SDA",
+ "CAMSENSOR_I2C_SCL",
+ "GNSS_ELNA_EN0",
+ "NC",
+ "NC", /* GPIO_60 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "RGBC_IR_INT",
+ "NC",
+ "NC",
+ "NC",
+ "NC", /* GPIO_70 */
+ "NC",
+ "HAP_I2C_SDA",
+ "HAP_I2C_SCL",
+ "HAP_RST_N",
+ "HAP_INT_N",
+ "HST_BT_UART_CTS",
+ "HST_BT_UART_RFR",
+ "HST_BT_UART_TX",
+ "HST_BT_UART_RX",
+ "HST_WLAN_EN", /* GPIO_80 */
+ "HST_BT_EN",
+ "HST_SW_CTRL",
+ "NC",
+ "NC",
+ "NC",
+ "DISP_VSYNC",
+ "NC",
+ "NC",
+ "HW_ID_0",
+ "HW_ID_1", /* GPIO_90 */
+ "USB_CC_DIR",
+ "TRAY_DET",
+ "SW_SERVICE",
+ "PCIE0_RESET_N",
+ "PCIE0_CLK_REQ_N",
+ "PCIE0_WAKE_N",
+ "OIS_ENABLE_WIDE",
+ "DEBUG_GPIO0",
+ "NC",
+ "CAM_MCLK0", /* GPIO_100 */
+ "CAM_MCLK1",
+ "CAM_MCLK2",
+ "CAM_MCLK3",
+ "NC",
+ "NC",
+ "TOF_RST_N",
+ "CAM_SOF",
+ "NC",
+ "AFEXPTMG_TELE",
+ "CCI_I2C0_SDA", /* GPIO_110 */
+ "CCI_I2C0_SCL",
+ "CCI_I2C1_SDA",
+ "CCI_I2C1_SCL",
+ "CCI_I2C2_SDA",
+ "CCI_I2C2_SCL",
+ "NC",
+ "CAM2_RESET_N",
+ "NC",
+ "EXT_VD0_XVS",
+ "CAM3_RESET_N", /* GPIO_120 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "RF_ID_EXTENSION_2",
+ "HAP_I2S_CLK",
+ "HAP_I2S_DOUT",
+ "HAP_TRG1",
+ "HAP_I2S_SYNC",
+ "UIM1_DATA", /* GPIO_130 */
+ "UIM1_CLK",
+ "UIM1_RESET",
+ "TRAY_DET",
+ "UIM2_DATA",
+ "UIM2_CLK",
+ "UIM2_RESET",
+ "UIM2_PRESENT",
+ "SM_RFFE0_CLK",
+ "SM_RFFE0_DATA",
+ "SM_RFFE1_CLK", /* GPIO_140 */
+ "SM_RFFE1_DATA",
+ "SM_MSS_GRFC4",
+ "HST_AS_EN",
+ "LAA_RX_EN",
+ "NC",
+ "SM_RFFE4_CLK",
+ "SM_RFFE4_DATA",
+ "WLAN_COEX_UART1_RX",
+ "WLAN_COEX_UART1_TX",
+ "RF_LCD_ID_EN", /* GPIO_150 */
+ "RF_ID_EXTENSION",
+ "SM_MSS_GRFC12",
+ "NFC_COLD_RST",
+ "NC",
+ "NC",
+ "SDR1_QLINK0_REQ",
+ "SDR1_QLINK0_EN",
+ "SDR1_QLINK0_WMSS_RESET_N",
+ "QLINK1_REQ",
+ "QLINK1_EN", /* GPIO_160 */
+ "QLINK1_WMSS_RESET_N",
+ "SDR2_QLINK2_REQ",
+ "SDR2_QLINK2_EN",
+ "SDR2_QLINK2_WMSS_RESET_N",
+ "WCD_SWR_TX_CLK",
+ "WCD_SWR_TX_DATA0",
+ "WCD_SWR_TX_DATA1",
+ "WCD_SWR_RX_CLK",
+ "WCD_SWR_RX_DATA0",
+ "WCD_SWR_RX_DATA1", /* GPIO_170 */
+ "SM_DMIC1_CLK",
+ "SM_DMIC1_DATA",
+ "SM_DMIC2_CLK",
+ "SM_DMIC2_DATA",
+ "SPK_AMP_I2S_CLK",
+ "SPK_AMP_I2S_WS",
+ "NC",
+ "NC",
+ "WCD_SWR_TX_DATA2",
+ "SPK_AMP_I2S_ASP_DIN", /* GPIO_180 */
+ "SPK_AMP_I2S_ASP_DOUT",
+ "SPK_AMP_INT_N",
+ "SPK_AMP_RESET_N",
+ "HST_BT_WLAN_SLIMBUS_CLK",
+ "HST_BT_WLAN_SLIMBUS_DAT0",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "MAG_I2C_SDA", /* GPIO_190 */
+ "MAG_I2C_SCL",
+ "IMU_SPI_MISO",
+ "IMU_SPI_MOSI",
+ "IMU_SPI_CLK",
+ "IMU_SPI_CS_N",
+ "SENSOR_I2C_SDA",
+ "SENSOR_I2C_SCL",
+ "OIS_TELE_I2C_SDA",
+ "OIS_TELE_I2C_SCL",
+ "NC", /* GPIO_200 */
+ "OIS_ENABLE_TELE",
+ "HST_BLE_UART_TX",
+ "HST_BLE_UART_RX",
+ "HSTP_CLK_CFG_SEL",
+ "NC",
+ "APPS_I2C_0_SDA",
+ "APPS_I2C_0_SCL",
+ "CCI_I2C3_SDA",
+ "CCI_I2C3_SCL";
};
diff --git a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx224.dts b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx224.dts
new file mode 100644
index 000000000000..13c2fc4bccfc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara-pdx224.dts
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+/dts-v1/;
+
+#include "sm8450-sony-xperia-nagara.dtsi"
+
+/ {
+ model = "Sony Xperia 5 IV";
+ compatible = "sony,pdx224", "qcom,sm8450";
+
+ imx563_vdig_vreg: imx563-vdig-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "imx563_vdig_vreg";
+ gpio = <&tlmm 22 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&tlmm {
+ gpio-line-names = "TELE_SPI_MISO", /* GPIO_0 */
+ "TELE_SPI_MOSI", /* SONY says NC, but it only makes sense this way.. */
+ "TELE_SPI_CLK",
+ "TELE_SPI_CS_N",
+ "WLC_I2C_SDA",
+ "WLC_I2C_SCL",
+ "NC",
+ "PM8010_1_RESET_N",
+ "WLC_INT_N",
+ "NC",
+ "NC", /* GPIO_10 */
+ "NC",
+ "DISP_ERR_FG",
+ "HALL_INT_N",
+ "ALS_PROX_INT_N",
+ "IMU1_INT",
+ "TS_I2C_SDA",
+ "TS_I2C_SCL",
+ "DISP_RESET_N",
+ "DISP_VDDR_EN",
+ "TS_RESET_N", /* GPIO_20 */
+ "TS_INT_N",
+ "UWIDEC_PWR_EN",
+ "TELEC_PWR_EN",
+ "CAM1_RESET_N",
+ "LEO_CAM0_RESET_N",
+ "DEBUG_UART_TX",
+ "DEBUG_UART_RX",
+ "FP_SPI_MISO",
+ "FP_SPI_MOSI",
+ "FP_SPI_CLK", /* GPIO_30 */
+ "FP_SPI_CS_N",
+ "NFC_I2C_SDA",
+ "NFC_I2C_SCL",
+ "NFC_EN",
+ "NFC_CLK_REQ",
+ "NFC_ESE_SPI_MISO",
+ "NFC_ESE_SPI_MOSI",
+ "NFC_ESE_SPI_CLK",
+ "NFC_ESE_SPI_CS",
+ "FP_INT_N", /* GPIO_40 */
+ "NC",
+ "FP_RESET_N",
+ "WCD_RST_N",
+ "NC",
+ "NFC_DWL_REQ",
+ "NFC_IRQ",
+ "FORCE_USB_BOOT",
+ "APPS_I2C_1_SDA",
+ "APPS_I2C_1_SCL",
+ "SBU_SW_OE", /* GPIO_50 */
+ "SBU_SW_SEL",
+ "SPK_AMP_I2C_SDA",
+ "SPK_AMP_I2C_SCL",
+ "NC",
+ "NC",
+ "CAMSENSOR_I2C_SDA",
+ "CAMSENSOR_I2C_SCL",
+ "GNSS_ELNA_EN0",
+ "NC",
+ "NC", /* GPIO_60 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "RGBC_IR_INT",
+ "NC",
+ "NC",
+ "NC",
+ "NC", /* GPIO_70 */
+ "NC",
+ "HAP_I2C_SDA",
+ "HAP_I2C_SCL",
+ "HAP_RST_N",
+ "HAP_INT_N",
+ "HST_BT_UART_CTS",
+ "HST_BT_UART_RFR",
+ "HST_BT_UART_TX",
+ "HST_BT_UART_RX",
+ "HST_WLAN_EN", /* GPIO_80 */
+ "HST_BT_EN",
+ "HST_SW_CTRL",
+ "NC",
+ "NC",
+ "NC",
+ "DISP_VSYNC",
+ "NC",
+ "NC",
+ "HW_ID_0",
+ "HW_ID_1", /* GPIO_90 */
+ "USB_CC_DIR",
+ "TRAY_DET",
+ "SW_SERVICE",
+ "PCIE0_RESET_N",
+ "PCIE0_CLK_REQ_N",
+ "PCIE0_WAKE_N",
+ "OIS_ENABLE_WIDE",
+ "DEBUG_GPIO0",
+ "NC",
+ "CAM_MCLK0", /* GPIO_100 */
+ "CAM_MCLK1",
+ "CAM_MCLK2",
+ "CAM_MCLK3",
+ "NC",
+ "NC",
+ "NC", /* SONY didn't rename this, but there's no ToF so it's likely NC */
+ "CAM_SOF",
+ "NC",
+ "AFEXPTMG_TELE",
+ "CCI_I2C0_SDA", /* GPIO_110 */
+ "CCI_I2C0_SCL",
+ "CCI_I2C1_SDA",
+ "CCI_I2C1_SCL",
+ "CCI_I2C2_SDA",
+ "CCI_I2C2_SCL",
+ "NC",
+ "CAM2_RESET_N",
+ "NC",
+ "EXT_VD0_XVS",
+ "CAM3_RESET_N", /* GPIO_120 */
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "RF_ID_EXTENSION_2",
+ "HAP_I2S_CLK",
+ "HAP_I2S_DOUT",
+ "HAP_TRG1",
+ "HAP_I2S_SYNC",
+ "UIM1_DATA", /* GPIO_130 */
+ "UIM1_CLK",
+ "UIM1_RESET",
+ "TRAY_DET",
+ "UIM2_DATA",
+ "UIM2_CLK",
+ "UIM2_RESET",
+ "UIM2_PRESENT",
+ "SM_RFFE0_CLK",
+ "SM_RFFE0_DATA",
+ "SM_RFFE1_CLK", /* GPIO_140 */
+ "SM_RFFE1_DATA",
+ "SM_MSS_GRFC4",
+ "HST_AS_EN",
+ "LAA_RX_EN",
+ "NC",
+ "SM_RFFE4_CLK",
+ "SM_RFFE4_DATA",
+ "WLAN_COEX_UART1_RX",
+ "WLAN_COEX_UART1_TX",
+ "RF_LCD_ID_EN", /* GPIO_150 */
+ "RF_ID_EXTENSION",
+ "SM_MSS_GRFC12",
+ "NFC_COLD_RST",
+ "NC",
+ "NC",
+ "SDR1_QLINK0_REQ",
+ "SDR1_QLINK0_EN",
+ "SDR1_QLINK0_WMSS_RESET_N",
+ "NC",
+ "NC", /* GPIO_160 */
+ "NC",
+ "SDR2_QLINK2_REQ",
+ "SDR2_QLINK2_EN",
+ "SDR2_QLINK2_WMSS_RESET_N",
+ "WCD_SWR_TX_CLK",
+ "WCD_SWR_TX_DATA0",
+ "WCD_SWR_TX_DATA1",
+ "WCD_SWR_RX_CLK",
+ "WCD_SWR_RX_DATA0",
+ "WCD_SWR_RX_DATA1", /* GPIO_170 */
+ "SM_DMIC1_CLK",
+ "SM_DMIC1_DATA",
+ "SM_DMIC2_CLK",
+ "SM_DMIC2_DATA",
+ "SPK_AMP_I2S_CLK",
+ "SPK_AMP_I2S_WS",
+ "NC",
+ "NC",
+ "WCD_SWR_TX_DATA2",
+ "SPK_AMP_I2S_ASP_DIN", /* GPIO_180 */
+ "SPK_AMP_I2S_ASP_DOUT",
+ "SPK_AMP_INT_N",
+ "SPK_AMP_RESET_N",
+ "HST_BT_WLAN_SLIMBUS_CLK",
+ "HST_BT_WLAN_SLIMBUS_DAT0",
+ "NC",
+ "NC",
+ "NC",
+ "NC",
+ "MAG_I2C_SDA", /* GPIO_190 */
+ "MAG_I2C_SCL",
+ "IMU_SPI_MISO",
+ "IMU_SPI_MOSI",
+ "IMU_SPI_CLK",
+ "IMU_SPI_CS_N",
+ "SENSOR_I2C_SDA",
+ "SENSOR_I2C_SCL",
+ "OIS_TELE_I2C_SDA",
+ "OIS_TELE_I2C_SCL",
+ "NC", /* GPIO_200 */
+ "OIS_ENABLE_TELE",
+ "HST_BLE_UART_TX",
+ "HST_BLE_UART_RX",
+ "HSTP_CLK_CFG_SEL",
+ "NC",
+ "APPS_I2C_0_SDA",
+ "APPS_I2C_0_SCL",
+ "CCI_I2C3_SDA",
+ "CCI_I2C3_SCL";
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi
new file mode 100644
index 000000000000..38256226d229
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi
@@ -0,0 +1,631 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include "sm8450.dtsi"
+
+/delete-node/ &adsp_mem;
+/delete-node/ &rmtfs_mem;
+/delete-node/ &video_mem;
+
+/ {
+ chassis-type = "handset";
+
+ aliases {
+ serial0 = &uart7;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reserved-memory {
+ adsp_mem: memory@85700000 {
+ reg = <0x0 0x85700000 0x0 0x2800000>;
+ no-map;
+ };
+
+ video_mem: memory@9fd00000 {
+ reg = <0x0 0x9fd00000 0x0 0x700000>;
+ no-map;
+ };
+
+ rmtfs_mem: memory@f3300000 {
+ compatible = "qcom,rmtfs-mem";
+ reg = <0x0 0xf3300000 0x0 0x280000>;
+ no-map;
+
+ qcom,client-id = <1>;
+ qcom,vmid = <15>;
+ };
+
+ ramoops@ffc00000 {
+ compatible = "ramoops";
+ reg = <0 0xffc00000 0 0x200000>;
+ console-size = <0x40000>;
+ record-size = <0x1000>;
+ ecc-size = <16>;
+ no-map;
+ };
+ };
+
+ /* Sadly, the voltages for these GPIO regulators are unknown. */
+ imx650_vana_vreg: imx650-vana-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "imx650_vana_vreg";
+ gpio = <&tlmm 23 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&apps_rsc {
+ pm8350-rpmh-regulators {
+ compatible = "qcom,pm8350-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+ vdd-s11-supply = <&vph_pwr>;
+ vdd-s12-supply = <&vph_pwr>;
+
+ vdd-l1-l4-supply = <&pm8350_s11>;
+ vdd-l2-l7-supply = <&vreg_bob>;
+ vdd-l3-l5-supply = <&vreg_bob>;
+ vdd-l6-l9-l10-supply = <&pm8350_s12>;
+
+ /*
+ * ARC regulators:
+ * s5 - gfx.lvl
+ * l8 - lcx.lvl
+ */
+
+ pm8350_s10: smps10 {
+ regulator-name = "pm8350_s10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8350_s11: smps11 {
+ regulator-name = "pm8350_s11";
+ regulator-min-microvolt = <848000>;
+ regulator-max-microvolt = <1104000>;
+ };
+
+ pm8350_s12: smps12 {
+ regulator-name = "pm8350_s12";
+ regulator-min-microvolt = <1224000>;
+ regulator-max-microvolt = <1400000>;
+ };
+
+ pm8350_l1: ldo1 {
+ regulator-name = "pm8350_l1";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l2: ldo2 {
+ regulator-name = "pm8350_l2";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l3: ldo3 {
+ regulator-name = "pm8350_l3";
+ regulator-min-microvolt = <904000>;
+ regulator-max-microvolt = <904000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l5: ldo5 {
+ regulator-name = "pm8350_l5";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l6: ldo6 {
+ regulator-name = "pm8350_l6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l7: ldo7 {
+ regulator-name = "pm8350_l7";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <2504000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350_l9: ldo9 {
+ regulator-name = "pm8350_l9";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ pm8350c-rpmh-regulators {
+ compatible = "qcom,pm8350c-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+
+ vdd-l1-l12-supply = <&vreg_bob>;
+ vdd-l2-l8-supply = <&vreg_bob>;
+ vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>;
+ vdd-l6-l9-l11-supply = <&vreg_bob>;
+ vdd-l10-supply = <&pm8350_s12>;
+
+ vdd-bob-supply = <&vph_pwr>;
+
+ /*
+ * ARC regulators:
+ * s2 - mxc.lvl
+ * s4 - mss.lvl
+ * s6 - cx.lvl
+ */
+
+ pm8350c_s1: smps1 {
+ regulator-name = "pm8350c_s1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2024000>;
+ };
+
+ pm8350c_s10: smps10 {
+ regulator-name = "pm8350c_s10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ vreg_bob: bob {
+ regulator-name = "vreg_bob";
+ regulator-min-microvolt = <3400000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ };
+
+ pm8350c_l1: ldo1 {
+ regulator-name = "pm8350c_l1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l2: ldo2 {
+ regulator-name = "pm8350c_l2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l3: ldo3 {
+ regulator-name = "pm8350c_l3";
+ regulator-min-microvolt = <3296000>;
+ regulator-max-microvolt = <3304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l4: ldo4 {
+ regulator-name = "pm8350c_l4";
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l5: ldo5 {
+ regulator-name = "pm8350c_l5";
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l6: ldo6 {
+ regulator-name = "pm8350c_l6";
+ regulator-min-microvolt = <2960000>;
+ /* Originally max = 3008000 but SDHCI expects 2960000 */
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l7: ldo7 {
+ regulator-name = "pm8350c_l7";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l8: ldo8 {
+ regulator-name = "pm8350c_l8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l9: ldo9 {
+ regulator-name = "pm8350c_l9";
+ regulator-min-microvolt = <2960000>;
+ /* Originally max = 3008000 but SDHCI expects 2960000 */
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l10: ldo10 {
+ regulator-name = "pm8350c_l10";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l12: ldo12 {
+ regulator-name = "pm8350c_l12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1968000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8350c_l13: ldo13 {
+ regulator-name = "pm8350c_l13";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ pm8450-rpmh-regulators {
+ compatible = "qcom,pm8450-rpmh-regulators";
+ qcom,pmic-id = "h";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+
+ vdd-l2-supply = <&vreg_bob>;
+ vdd-l3-supply = <&vreg_bob>;
+ vdd-l4-supply = <&vreg_bob>;
+
+ /*
+ * ARC regulators:
+ * S2 - ebi.lvl
+ * S4 - mmcx.lvl
+ * S6 - mx.lvl
+ * L1 - lmx.lvl
+ */
+
+ pm8450_s3: smps3 {
+ regulator-name = "pm8450_s3";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <600000>;
+ };
+
+ pm8450_l2: ldo2 {
+ regulator-name = "pm8450_l2";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ pm8450_l3: ldo3 {
+ regulator-name = "pm8450_l3";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ pmr735a-rpmh-regulators {
+ compatible = "qcom,pmr735a-rpmh-regulators";
+ qcom,pmic-id = "e";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+
+ vdd-l1-l2-supply = <&pmr735a_s2>;
+ vdd-l3-supply = <&pmr735a_s1>;
+ vdd-l4-supply = <&pm8350c_s1>;
+ vdd-l5-l6-supply = <&pm8350c_s1>;
+ vdd-l7-bob-supply = <&vreg_bob>;
+
+ pmr735a_s1: smps1 {
+ regulator-name = "pmr735a_s1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1296000>;
+ };
+
+ pmr735a_s2: smps2 {
+ regulator-name = "pmr735a_s2";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1040000>;
+ };
+
+ pmr735a_s3: smps3 {
+ regulator-name = "pmr735a_s3";
+ regulator-min-microvolt = <435000>;
+ regulator-max-microvolt = <2352000>;
+ };
+
+ pmr735a_l1: ldo1 {
+ regulator-name = "pmr735a_l1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ };
+
+ pmr735a_l2: ldo2 {
+ regulator-name = "pmr735a_l2";
+ regulator-min-microvolt = <480000>;
+ regulator-max-microvolt = <912000>;
+ };
+
+ pmr735a_l3: ldo3 {
+ regulator-name = "pmr735a_l3";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pmr735a_l4: ldo4 {
+ regulator-name = "pmr735a_l4";
+ regulator-min-microvolt = <1776000>;
+ regulator-max-microvolt = <1776000>;
+ };
+
+ pmr735a_l5: ldo5 {
+ regulator-name = "pmr735a_l5";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ };
+
+ pmr735a_l6: ldo6 {
+ regulator-name = "pmr735a_l6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pmr735a_l7: ldo7 {
+ regulator-name = "pmr735a_l7";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+ };
+};
+
+&gpi_dma0 {
+ status = "okay";
+};
+
+&gpi_dma1 {
+ status = "okay";
+};
+
+&gpi_dma2 {
+ status = "okay";
+};
+
+&i2c4 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ touchscreen@48 {
+ compatible = "samsung,s6sy761";
+ reg = <0x48>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <21 0x2008>;
+ vdd-supply = <&pm8350c_l2>;
+ avdd-supply = <&pm8350c_l3>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_reset_default &ts_int_default>;
+ };
+};
+
+&i2c5 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ /* Dialog SLG51000 CMIC @ 75 */
+};
+
+&i2c9 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ /* NXP SN1X0 NFC @ 28 */
+};
+
+&i2c13 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ /* Richwave RTC6226 FM Radio Receiver @ 64 */
+};
+
+&i2c14 {
+ clock-frequency = <1000000>;
+ status = "okay";
+
+ cs35l41_l: speaker-amp@40 {
+ compatible = "cirrus,cs35l41";
+ reg = <0x40>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <182 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&tlmm 183 GPIO_ACTIVE_HIGH>;
+ cirrus,boost-peak-milliamp = <4000>;
+ cirrus,boost-ind-nanohenry = <1000>;
+ cirrus,boost-cap-microfarad = <15>;
+ cirrus,gpio2-src-select = <2>;
+ cirrus,gpio2-output-enable;
+ cirrus,asp-sdout-hiz = <3>;
+ #sound-dai-cells = <1>;
+ };
+
+ cs35l41_r: speaker-amp@41 {
+ compatible = "cirrus,cs35l41";
+ reg = <0x41>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <182 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&tlmm 183 GPIO_ACTIVE_HIGH>;
+ cirrus,boost-peak-milliamp = <4000>;
+ cirrus,boost-ind-nanohenry = <1000>;
+ cirrus,boost-cap-microfarad = <15>;
+ cirrus,gpio2-src-select = <2>;
+ cirrus,gpio2-output-enable;
+ cirrus,asp-sdout-hiz = <3>;
+ #sound-dai-cells = <1>;
+ };
+};
+
+&i2c15 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ /* AMS TCS3490 RGB+IR color sensor @ 72 */
+};
+
+&i2c19 {
+ clock-frequency = <1000000>;
+ status = "okay";
+
+ /* Cirrus Logic CS40L25A boosted haptics driver @ 40 */
+};
+
+&pcie0 {
+ max-link-speed = <2>;
+ status = "okay";
+};
+
+&pcie0_phy {
+ vdda-phy-supply = <&pm8350_l5>;
+ vdda-pll-supply = <&pm8350_l6>;
+ status = "okay";
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/sm8350/Sony/nagara/adsp.mbn";
+ status = "okay";
+};
+
+&remoteproc_cdsp {
+ firmware-name = "qcom/sm8350/Sony/nagara/cdsp.mbn";
+ status = "okay";
+};
+
+&remoteproc_slpi {
+ firmware-name = "qcom/sm8350/Sony/nagara/slpi.mbn";
+ status = "okay";
+};
+
+&qupv3_id_0 {
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&qupv3_id_2 {
+ status = "okay";
+};
+
+&sdhc_2 {
+ cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>;
+ pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_n>;
+ vmmc-supply = <&pm8350c_l9>;
+ vqmmc-supply = <&pm8350c_l6>;
+ no-sdio;
+ no-mmc;
+ status = "okay";
+};
+
+&spi10 {
+ status = "okay";
+
+ /* NXP SN1X0 NFC Secure Element @ 0 */
+};
+
+&tlmm {
+ gpio-reserved-ranges = <28 4>;
+
+ ts_reset_default: ts-reset-default-state {
+ pins = "gpio20";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+
+ ts_int_default: ts-int-default-state {
+ pins = "gpio21";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+
+ sdc2_card_det_n: sd-card-det-n-state {
+ pins = "gpio92";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+};
+
+&uart7 {
+ status = "okay";
+};
+
+&usb_1 {
+ status = "okay";
+};
+
+&usb_1_dwc3 {
+ dr_mode = "peripheral";
+};
+
+&usb_1_hsphy {
+ vdda-pll-supply = <&pm8350_l5>;
+ vdda18-supply = <&pm8350c_l1>;
+ vdda33-supply = <&pm8350_l2>;
+ status = "okay";
+};
+
+&usb_1_qmpphy {
+ vdda-phy-supply = <&pm8350_l6>;
+ vdda-pll-supply = <&pm8350_l1>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index d32f08df743d..570475040d95 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -7,12 +7,15 @@
#include <dt-bindings/clock/qcom,gcc-sm8450.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,sm8450-camcc.h>
+#include <dt-bindings/clock/qcom,sm8450-dispcc.h>
#include <dt-bindings/dma/qcom-gpi.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/mailbox/qcom-ipcc.h>
#include <dt-bindings/power/qcom-rpmpd.h>
#include <dt-bindings/interconnect/qcom,sm8450.h>
+#include <dt-bindings/soc/qcom,gpr.h>
#include <dt-bindings/soc/qcom,rpmh-rsc.h>
+#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include <dt-bindings/thermal/thermal.h>
/ {
@@ -51,6 +54,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 0>;
L2_0: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -70,6 +74,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 0>;
L2_100: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -86,6 +91,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 0>;
L2_200: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -102,6 +108,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 0>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 0>;
L2_300: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -118,6 +125,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 1>;
L2_400: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -134,6 +142,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 1>;
L2_500: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -151,6 +160,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 1>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 1>;
L2_600: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -167,6 +177,7 @@
power-domain-names = "psci";
qcom,freq-domain = <&cpufreq_hw 2>;
#cooling-cells = <2>;
+ clocks = <&cpufreq_hw 2>;
L2_700: l2-cache {
compatible = "cache";
next-level-cache = <&L3_0>;
@@ -730,7 +741,7 @@
};
gpi_dma2: dma-controller@800000 {
- compatible = "qcom,sm8450-gpi-dma";
+ compatible = "qcom,sm8450-gpi-dma", "qcom,sm6350-gpi-dma";
#dma-cells = <3>;
reg = <0 0x800000 0 0x60000>;
interrupts = <GIC_SPI 588 IRQ_TYPE_LEVEL_HIGH>,
@@ -791,7 +802,6 @@
interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi15_data_clk>, <&qup_spi15_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -831,7 +841,6 @@
interrupts = <GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi16_data_clk>, <&qup_spi16_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -871,7 +880,6 @@
interrupts = <GIC_SPI 584 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi17_data_clk>, <&qup_spi17_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -911,7 +919,6 @@
interrupts = <GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi18_data_clk>, <&qup_spi18_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -951,7 +958,6 @@
interrupts = <GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi19_data_clk>, <&qup_spi19_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -1004,7 +1010,6 @@
interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi20_data_clk>, <&qup_spi20_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -1044,7 +1049,6 @@
interrupts = <GIC_SPI 579 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&qup_spi21_data_clk>, <&qup_spi21_cs>;
- spi-max-frequency = <50000000>;
interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
<&system_noc MASTER_A2NOC_SNOC 0 &gem_noc SLAVE_LLCC 0>;
interconnect-names = "qup-core", "qup-config";
@@ -1058,7 +1062,7 @@
};
gpi_dma0: dma-controller@900000 {
- compatible = "qcom,sm8450-gpi-dma";
+ compatible = "qcom,sm8450-gpi-dma", "qcom,sm6350-gpi-dma";
#dma-cells = <3>;
reg = <0 0x900000 0 0x60000>;
interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
@@ -1394,7 +1398,7 @@
};
gpi_dma1: dma-controller@a00000 {
- compatible = "qcom,sm8450-gpi-dma";
+ compatible = "qcom,sm8450-gpi-dma", "qcom,sm6350-gpi-dma";
#dma-cells = <3>;
reg = <0 0xa00000 0 0x60000>;
interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
@@ -2095,9 +2099,212 @@
};
};
+ wsa2macro: codec@31e0000 {
+ compatible = "qcom,sm8450-lpass-wsa-macro";
+ reg = <0 0x031e0000 0 0x1000>;
+ clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&vamacro>;
+ clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+ assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ assigned-clock-rates = <19200000>, <19200000>;
+
+ #clock-cells = <0>;
+ clock-output-names = "wsa2-mclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wsa2_swr_active>;
+ #sound-dai-cells = <1>;
+ };
+
+ /* WSA2 */
+ swr4: soundwire-controller@31f0000 {
+ compatible = "qcom,soundwire-v1.7.0";
+ reg = <0 0x031f0000 0 0x2000>;
+ interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&wsa2macro>;
+ clock-names = "iface";
+
+ qcom,din-ports = <2>;
+ qcom,dout-ports = <6>;
+
+ qcom,ports-sinterval-low = /bits/ 8 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x0f 0x0f>;
+ qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0c 0x06 0x12 0x0d 0x07 0x0a>;
+ qcom,ports-offset2 = /bits/ 8 <0xff 0x00 0x1f 0xff 0x00 0x1f 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0x01 0xff 0xff 0x01 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ };
+
+ rxmacro: codec@3200000 {
+ compatible = "qcom,sm8450-lpass-rx-macro";
+ reg = <0 0x3200000 0 0x1000>;
+ clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&vamacro>;
+ clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+
+ assigned-clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ assigned-clock-rates = <19200000>, <19200000>;
+
+ #clock-cells = <0>;
+ clock-output-names = "mclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rx_swr_active>;
+ #sound-dai-cells = <1>;
+ };
+
+ swr1: soundwire-controller@3210000 {
+ compatible = "qcom,soundwire-v1.7.0";
+ reg = <0 0x3210000 0 0x2000>;
+ interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rxmacro>;
+ clock-names = "iface";
+ label = "RX";
+ qcom,din-ports = <0>;
+ qcom,dout-ports = <5>;
+
+ qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1f 0x1f 0x07 0x00>;
+ qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00>;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00>;
+ qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ };
+
+ txmacro: codec@3220000 {
+ compatible = "qcom,sm8450-lpass-tx-macro";
+ reg = <0 0x3220000 0 0x1000>;
+ clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&vamacro>;
+ clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+ assigned-clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ assigned-clock-rates = <19200000>, <19200000>;
+
+ #clock-cells = <0>;
+ clock-output-names = "mclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&tx_swr_active>;
+ #sound-dai-cells = <1>;
+ };
+
+ wsamacro: codec@3240000 {
+ compatible = "qcom,sm8450-lpass-wsa-macro";
+ reg = <0 0x03240000 0 0x1000>;
+ clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&vamacro>;
+ clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+
+ assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ assigned-clock-rates = <19200000>, <19200000>;
+
+ #clock-cells = <0>;
+ clock-output-names = "mclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wsa_swr_active>;
+ #sound-dai-cells = <1>;
+ };
+
+ /* WSA */
+ swr0: soundwire-controller@3250000 {
+ compatible = "qcom,soundwire-v1.7.0";
+ reg = <0 0x03250000 0 0x2000>;
+ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&wsamacro>;
+ clock-names = "iface";
+
+ qcom,din-ports = <2>;
+ qcom,dout-ports = <6>;
+
+ qcom,ports-sinterval-low = /bits/ 8 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x0f 0x0f>;
+ qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0c 0x06 0x12 0x0d 0x07 0x0a>;
+ qcom,ports-offset2 = /bits/ 8 <0xff 0x00 0x1f 0xff 0x00 0x1f 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0x01 0xff 0xff 0x01 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ };
+
+ swr2: soundwire-controller@33b0000 {
+ compatible = "qcom,soundwire-v1.7.0";
+ reg = <0 0x33b0000 0 0x2000>;
+ interrupts-extended = <&intc GIC_SPI 496 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 520 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "core", "wake";
+
+ clocks = <&vamacro>;
+ clock-names = "iface";
+ label = "TX";
+
+ qcom,din-ports = <4>;
+ qcom,dout-ports = <0>;
+ qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>;
+ qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x01 0x01>;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>;
+ qcom,ports-lane-control = /bits/ 8 <0x01 0x02 0x00 0x00>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ };
+
+ vamacro: codec@33f0000 {
+ compatible = "qcom,sm8450-lpass-va-macro";
+ reg = <0 0x033f0000 0 0x1000>;
+ clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ clock-names = "mclk", "macro", "dcodec", "npl";
+ assigned-clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ assigned-clock-rates = <19200000>;
+
+ #clock-cells = <0>;
+ clock-output-names = "fsgen";
+ #sound-dai-cells = <1>;
+ };
+
remoteproc_adsp: remoteproc@30000000 {
compatible = "qcom,sm8450-adsp-pas";
- reg = <0 0x030000000 0 0x100>;
+ reg = <0 0x30000000 0 0x100>;
interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
<&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
@@ -2133,6 +2340,45 @@
label = "lpass";
qcom,remote-pid = <2>;
+ gpr {
+ compatible = "qcom,gpr";
+ qcom,glink-channels = "adsp_apps";
+ qcom,domain = <GPR_DOMAIN_ID_ADSP>;
+ qcom,intents = <512 20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ q6apm: service@1 {
+ compatible = "qcom,q6apm";
+ reg = <GPR_APM_MODULE_IID>;
+ #sound-dai-cells = <0>;
+ qcom,protection-domain = "avs/audio",
+ "msm/adsp/audio_pd";
+
+ q6apmdai: dais {
+ compatible = "qcom,q6apm-dais";
+ iommus = <&apps_smmu 0x1801 0x0>;
+ };
+
+ q6apmbedai: bedais {
+ compatible = "qcom,q6apm-lpass-dais";
+ #sound-dai-cells = <1>;
+ };
+ };
+
+ q6prm: service@2 {
+ compatible = "qcom,q6prm";
+ reg = <GPR_PRM_MODULE_IID>;
+ qcom,protection-domain = "avs/audio",
+ "msm/adsp/audio_pd";
+
+ q6prmcc: clock-controller {
+ compatible = "qcom,q6prm-lpass-clocks";
+ #clock-cells = <2>;
+ };
+ };
+ };
+
fastrpc {
compatible = "qcom,fastrpc";
qcom,glink-channels = "fastrpcglink-apps-dsp";
@@ -2163,7 +2409,7 @@
remoteproc_cdsp: remoteproc@32300000 {
compatible = "qcom,sm8450-cdsp-pas";
- reg = <0 0x032300000 0 0x1400000>;
+ reg = <0 0x32300000 0 0x1400000>;
interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>,
<&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>,
@@ -2283,8 +2529,8 @@
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
- power-domains = <&rpmhpd 0>,
- <&rpmhpd 12>;
+ power-domains = <&rpmhpd SM8450_CX>,
+ <&rpmhpd SM8450_MSS>;
power-domain-names = "cx", "mss";
memory-region = <&mpss_mem>;
@@ -2307,6 +2553,84 @@
};
};
+ cci0: cci@ac15000 {
+ compatible = "qcom,sm8450-cci";
+ reg = <0 0xac15000 0 0x1000>;
+ interrupts = <GIC_SPI 460 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc TITAN_TOP_GDSC>;
+
+ clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&camcc CAM_CC_CPAS_AHB_CLK>,
+ <&camcc CAM_CC_CCI_0_CLK>,
+ <&camcc CAM_CC_CCI_0_CLK_SRC>;
+ clock-names = "camnoc_axi",
+ "slow_ahb_src",
+ "cpas_ahb",
+ "cci",
+ "cci_src";
+ pinctrl-0 = <&cci0_default &cci1_default>;
+ pinctrl-1 = <&cci0_sleep &cci1_sleep>;
+ pinctrl-names = "default", "sleep";
+
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci0_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci0_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ cci1: cci@ac16000 {
+ compatible = "qcom,sm8450-cci";
+ reg = <0 0xac16000 0 0x1000>;
+ interrupts = <GIC_SPI 271 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc TITAN_TOP_GDSC>;
+
+ clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&camcc CAM_CC_CPAS_AHB_CLK>,
+ <&camcc CAM_CC_CCI_1_CLK>,
+ <&camcc CAM_CC_CCI_1_CLK_SRC>;
+ clock-names = "camnoc_axi",
+ "slow_ahb_src",
+ "cpas_ahb",
+ "cci",
+ "cci_src";
+ pinctrl-0 = <&cci2_default &cci3_default>;
+ pinctrl-1 = <&cci2_sleep &cci3_sleep>;
+ pinctrl-names = "default", "sleep";
+
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci1_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci1_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
camcc: clock-controller@ade0000 {
compatible = "qcom,sm8450-camcc";
reg = <0 0x0ade0000 0 0x20000>;
@@ -2322,6 +2646,33 @@
status = "disabled";
};
+ dispcc: clock-controller@af00000 {
+ compatible = "qcom,sm8450-dispcc";
+ reg = <0 0x0af00000 0 0x20000>;
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&rpmhcc RPMH_CXO_CLK_A>,
+ <&gcc GCC_DISP_AHB_CLK>,
+ <&sleep_clk>,
+ <0>, /* dsi0 */
+ <0>,
+ <0>, /* dsi1 */
+ <0>,
+ <0>, /* dp0 */
+ <0>,
+ <0>, /* dp1 */
+ <0>,
+ <0>, /* dp2 */
+ <0>,
+ <0>, /* dp3 */
+ <0>;
+ power-domains = <&rpmhpd SM8450_MMCX>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ status = "disabled";
+ };
+
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8450-pdc", "qcom,pdc";
reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
@@ -2384,6 +2735,26 @@
gpio-ranges = <&tlmm 0 0 211>;
wakeup-parent = <&pdc>;
+ sdc2_default_state: sdc2-default-state {
+ clk-pins {
+ pins = "sdc2_clk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc2_cmd";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc2_data";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+ };
+
sdc2_sleep_state: sdc2-sleep-state {
clk-pins {
pins = "sdc2_clk";
@@ -2404,6 +2775,70 @@
};
};
+ cci0_default: cci0-default-state {
+ /* SDA, SCL */
+ pins = "gpio110", "gpio111";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ cci0_sleep: cci0-sleep-state {
+ /* SDA, SCL */
+ pins = "gpio110", "gpio111";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci1_default: cci1-default-state {
+ /* SDA, SCL */
+ pins = "gpio112", "gpio113";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ cci1_sleep: cci1-sleep-state {
+ /* SDA, SCL */
+ pins = "gpio112", "gpio113";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci2_default: cci2-default-state {
+ /* SDA, SCL */
+ pins = "gpio114", "gpio115";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ cci2_sleep: cci2-sleep-state {
+ /* SDA, SCL */
+ pins = "gpio114", "gpio115";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci3_default: cci3-default-state {
+ /* SDA, SCL */
+ pins = "gpio208", "gpio209";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ cci3_sleep: cci3-sleep-state {
+ /* SDA, SCL */
+ pins = "gpio208", "gpio209";
+ function = "cci_i2c";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
pcie0_default_state: pcie0-default-state {
perst-pins {
pins = "gpio94";
@@ -2800,6 +3235,123 @@
};
+ lpass_tlmm: pinctrl@3440000{
+ compatible = "qcom,sm8450-lpass-lpi-pinctrl";
+ reg = <0 0x3440000 0x0 0x20000>,
+ <0 0x34d0000 0x0 0x10000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&lpass_tlmm 0 0 23>;
+
+ clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ clock-names = "core", "audio";
+
+ tx_swr_active: tx-swr-active-state {
+ clk-pins {
+ pins = "gpio0";
+ function = "swr_tx_clk";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-disable;
+ };
+
+ data-pins {
+ pins = "gpio1", "gpio2", "gpio14";
+ function = "swr_tx_data";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-bus-hold;
+ };
+ };
+
+ rx_swr_active: rx-swr-active-state {
+ clk-pins {
+ pins = "gpio3";
+ function = "swr_rx_clk";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-disable;
+ };
+
+ data-pins {
+ pins = "gpio4", "gpio5";
+ function = "swr_rx_data";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-bus-hold;
+ };
+ };
+
+ dmic01_default: dmic01-default-state {
+ clk-pins {
+ pins = "gpio6";
+ function = "dmic1_clk";
+ drive-strength = <8>;
+ output-high;
+ };
+
+ data-pins {
+ pins = "gpio7";
+ function = "dmic1_data";
+ drive-strength = <8>;
+ input-enable;
+ };
+ };
+
+ dmic02_default: dmic02-default-state {
+ clk-pins {
+ pins = "gpio8";
+ function = "dmic2_clk";
+ drive-strength = <8>;
+ output-high;
+ };
+
+ data-pins {
+ pins = "gpio9";
+ function = "dmic2_data";
+ drive-strength = <8>;
+ input-enable;
+ };
+ };
+
+ wsa_swr_active: wsa-swr-active-state {
+ clk-pins {
+ pins = "gpio10";
+ function = "wsa_swr_clk";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-disable;
+ };
+
+ data-pins {
+ pins = "gpio11";
+ function = "wsa_swr_data";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-bus-hold;
+ };
+ };
+
+ wsa2_swr_active: wsa2-swr-active-state {
+ clk-pins {
+ pins = "gpio15";
+ function = "wsa2_swr_clk";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-disable;
+ };
+
+ data-pins {
+ pins = "gpio16";
+ function = "wsa2_swr_data";
+ drive-strength = <2>;
+ slew-rate = <1>;
+ bias-bus-hold;
+ };
+ };
+ };
+
apps_smmu: iommu@15000000 {
compatible = "qcom,sm8450-smmu-500", "arm,mmu-500";
reg = <0 0x15000000 0 0x100000>;
@@ -2999,6 +3551,7 @@
qcom,drv-id = <2>;
qcom,tcs-config = <ACTIVE_TCS 3>, <SLEEP_TCS 2>,
<WAKE_TCS 2>, <CONTROL_TCS 0>;
+ power-domains = <&CLUSTER_PD>;
apps_bcm_voter: bcm-voter {
compatible = "qcom,bcm-voter";
@@ -3075,6 +3628,7 @@
<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "dcvsh-irq-0", "dcvsh-irq-1", "dcvsh-irq-2";
#freq-domain-cells = <1>;
+ #clock-cells = <1>;
};
gem_noc: interconnect@19100000 {
@@ -3161,16 +3715,16 @@
status = "disabled";
ufs_mem_phy_lanes: phy@1d87400 {
- reg = <0 0x01d87400 0 0x108>,
- <0 0x01d87600 0 0x1e0>,
- <0 0x01d87c00 0 0x1dc>,
- <0 0x01d87800 0 0x108>,
- <0 0x01d87a00 0 0x1e0>;
+ reg = <0 0x01d87400 0 0x188>,
+ <0 0x01d87600 0 0x200>,
+ <0 0x01d87c00 0 0x200>,
+ <0 0x01d87800 0 0x188>,
+ <0 0x01d87a00 0 0x200>;
#phy-cells = <0>;
};
};
- sdhc_2: sdhci@8804000 {
+ sdhc_2: mmc@8804000 {
compatible = "qcom,sm8450-sdhci", "qcom,sdhci-msm-v5";
reg = <0 0x08804000 0 0x1000>;
@@ -3192,6 +3746,9 @@
bus-width = <4>;
dma-coherent;
+ /* Forbid SDR104/SDR50 - broken hw! */
+ sdhci-caps-mask = <0x3 0x0>;
+
status = "disabled";
sdhc2_opp_table: opp-table {
@@ -3274,6 +3831,9 @@
};
};
+ sound: sound {
+ };
+
thermal-zones {
aoss0-thermal {
polling-delay-passive = <0>;
diff --git a/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi b/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
index 7ce986f0a06f..7cb5c958aece 100644
--- a/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
+++ b/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
@@ -65,7 +65,6 @@
ov5645: ov5645@3c {
compatible = "ovti,ov5645";
reg = <0x3c>;
- clock-names = "xclk";
clocks = <&osc25250_clk>;
clock-frequency = <24000000>;
vdddo-supply = <&ov5645_vdddo_1v8>;
diff --git a/arch/arm64/boot/dts/renesas/condor-common.dtsi b/arch/arm64/boot/dts/renesas/condor-common.dtsi
index dfbe35bf46e0..7c34d14dcd7e 100644
--- a/arch/arm64/boot/dts/renesas/condor-common.dtsi
+++ b/arch/arm64/boot/dts/renesas/condor-common.dtsi
@@ -21,6 +21,7 @@
chosen {
stdout-path = "serial0:115200n8";
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
};
d1_8v: regulator-2 {
diff --git a/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts b/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dtso
index 258f8668ca36..258f8668ca36 100644
--- a/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts
+++ b/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dtso
diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi
index ed9400f903c9..41fbb9998cf8 100644
--- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi
@@ -656,7 +656,7 @@
avb0: ethernet@e6800000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6800000 0 0x800>;
interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
@@ -704,7 +704,7 @@
avb1: ethernet@e6810000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6810000 0 0x800>;
interrupts = <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
@@ -752,7 +752,7 @@
avb2: ethernet@e6820000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6820000 0 0x1000>;
interrupts = <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
@@ -800,7 +800,7 @@
avb3: ethernet@e6830000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6830000 0 0x1000>;
interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
@@ -848,7 +848,7 @@
avb4: ethernet@e6840000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6840000 0 0x1000>;
interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>,
@@ -896,7 +896,7 @@
avb5: ethernet@e6850000 {
compatible = "renesas,etheravb-r8a779a0",
- "renesas,etheravb-rcar-gen3";
+ "renesas,etheravb-rcar-gen4";
reg = <0 0xe6850000 0 0x1000>;
interrupts = <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>,
@@ -1019,7 +1019,7 @@
msiof0: spi@e6e90000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6e90000 0 0x0064>;
interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 618>;
@@ -1034,7 +1034,7 @@
msiof1: spi@e6ea0000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6ea0000 0 0x0064>;
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 619>;
@@ -1049,7 +1049,7 @@
msiof2: spi@e6c00000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6c00000 0 0x0064>;
interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 620>;
@@ -1064,7 +1064,7 @@
msiof3: spi@e6c10000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6c10000 0 0x0064>;
interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 621>;
@@ -1079,7 +1079,7 @@
msiof4: spi@e6c20000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6c20000 0 0x0064>;
interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 622>;
@@ -1094,7 +1094,7 @@
msiof5: spi@e6c28000 {
compatible = "renesas,msiof-r8a779a0",
- "renesas,rcar-gen3-msiof";
+ "renesas,rcar-gen4-msiof";
reg = <0 0xe6c28000 0 0x0064>;
interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 623>;
diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi
index a45df1041705..045d70535519 100644
--- a/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi
@@ -12,13 +12,13 @@
compatible = "renesas,spider-cpu", "renesas,r8a779f0";
aliases {
- serial0 = &scif3;
+ serial0 = &hscif0;
serial1 = &scif0;
};
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
- stdout-path = "serial0:115200n8";
+ stdout-path = "serial0:1843200n8";
};
memory@48000000 {
@@ -59,6 +59,14 @@
clock-frequency = <32768>;
};
+&hscif0 {
+ pinctrl-0 = <&hscif0_pins>;
+ pinctrl-names = "default";
+
+ uart-has-rtscts;
+ status = "okay";
+};
+
&i2c4 {
pinctrl-0 = <&i2c4_pins>;
pinctrl-names = "default";
@@ -99,6 +107,11 @@
pinctrl-0 = <&scif_clk_pins>;
pinctrl-names = "default";
+ hscif0_pins: hscif0 {
+ groups = "hscif0_data", "hscif0_ctrl";
+ function = "hscif0";
+ };
+
i2c4_pins: i2c4 {
groups = "i2c4";
function = "i2c4";
@@ -115,11 +128,6 @@
function = "scif0";
};
- scif3_pins: scif3 {
- groups = "scif3_data", "scif3_ctrl";
- function = "scif3";
- };
-
scif_clk_pins: scif_clk {
groups = "scif_clk";
function = "scif_clk";
@@ -139,14 +147,6 @@
status = "okay";
};
-&scif3 {
- pinctrl-0 = <&scif3_pins>;
- pinctrl-names = "default";
-
- uart-has-rtscts;
- status = "okay";
-};
-
&scif_clk {
clock-frequency = <24000000>;
};
diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi
index 15e8d1ebf575..33c1015e9ab3 100644
--- a/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi
@@ -5,6 +5,10 @@
* Copyright (C) 2021 Renesas Electronics Corp.
*/
+&eth_serdes {
+ status = "okay";
+};
+
&i2c4 {
eeprom@52 {
compatible = "rohm,br24g01", "atmel,24c01";
@@ -13,3 +17,89 @@
pagesize = <8>;
};
};
+
+&pfc {
+ tsn0_pins: tsn0 {
+ groups = "tsn0_mdio_b", "tsn0_link_b";
+ function = "tsn0";
+ power-source = <1800>;
+ };
+
+ tsn1_pins: tsn1 {
+ groups = "tsn1_mdio_b", "tsn1_link_b";
+ function = "tsn1";
+ power-source = <1800>;
+ };
+
+ tsn2_pins: tsn2 {
+ groups = "tsn2_mdio_b", "tsn2_link_b";
+ function = "tsn2";
+ power-source = <1800>;
+ };
+};
+
+&rswitch {
+ pinctrl-0 = <&tsn0_pins>, <&tsn1_pins>, <&tsn2_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ phy-handle = <&u101>;
+ phy-mode = "sgmii";
+ phys = <&eth_serdes 0>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ u101: ethernet-phy@1 {
+ reg = <1>;
+ compatible = "ethernet-phy-ieee802.3-c45";
+ interrupt-parent = <&gpio3>;
+ interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
+ };
+ port@1 {
+ reg = <1>;
+ phy-handle = <&u201>;
+ phy-mode = "sgmii";
+ phys = <&eth_serdes 1>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ u201: ethernet-phy@2 {
+ reg = <2>;
+ compatible = "ethernet-phy-ieee802.3-c45";
+ interrupt-parent = <&gpio3>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
+ };
+ port@2 {
+ reg = <2>;
+ phy-handle = <&u301>;
+ phy-mode = "sgmii";
+ phys = <&eth_serdes 2>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ u301: ethernet-phy@3 {
+ reg = <3>;
+ compatible = "ethernet-phy-ieee802.3-c45";
+ interrupt-parent = <&gpio3>;
+ interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
index c2f152bcf10e..67a4f2d4480d 100644
--- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
@@ -469,6 +469,16 @@
status = "disabled";
};
+ eth_serdes: phy@e6444000 {
+ compatible = "renesas,r8a779f0-ether-serdes";
+ reg = <0 0xe6444000 0 0x2800>;
+ clocks = <&cpg CPG_MOD 1506>;
+ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+ resets = <&cpg 1506>;
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
i2c0: i2c@e6500000 {
compatible = "renesas,i2c-r8a779f0",
"renesas,rcar-gen4-i2c";
@@ -577,7 +587,7 @@
reg = <0 0xe6540000 0 0x60>;
interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 514>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x31>, <&dmac0 0x30>,
@@ -594,7 +604,7 @@
reg = <0 0xe6550000 0 0x60>;
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 515>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x33>, <&dmac0 0x32>,
@@ -611,7 +621,7 @@
reg = <0 0xe6560000 0 0x60>;
interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 516>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x35>, <&dmac0 0x34>,
@@ -628,7 +638,7 @@
reg = <0 0xe66a0000 0 0x60>;
interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 517>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x37>, <&dmac0 0x36>,
@@ -651,13 +661,113 @@
status = "disabled";
};
+ rswitch: ethernet@e6880000 {
+ compatible = "renesas,r8a779f0-ether-switch";
+ reg = <0 0xe6880000 0 0x20000>, <0 0xe68c0000 0 0x20000>;
+ reg-names = "base", "secure_base";
+ interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 292 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mfwd_error", "race_error",
+ "coma_error", "gwca0_error",
+ "gwca1_error", "etha0_error",
+ "etha1_error", "etha2_error",
+ "gptp0_status", "gptp1_status",
+ "mfwd_status", "race_status",
+ "coma_status", "gwca0_status",
+ "gwca1_status", "etha0_status",
+ "etha1_status", "etha2_status",
+ "rmac0_status", "rmac1_status",
+ "rmac2_status",
+ "gwca0_rxtx0", "gwca0_rxtx1",
+ "gwca0_rxtx2", "gwca0_rxtx3",
+ "gwca0_rxtx4", "gwca0_rxtx5",
+ "gwca0_rxtx6", "gwca0_rxtx7",
+ "gwca1_rxtx0", "gwca1_rxtx1",
+ "gwca1_rxtx2", "gwca1_rxtx3",
+ "gwca1_rxtx4", "gwca1_rxtx5",
+ "gwca1_rxtx6", "gwca1_rxtx7",
+ "gwca0_rxts0", "gwca0_rxts1",
+ "gwca1_rxts0", "gwca1_rxts1",
+ "rmac0_mdio", "rmac1_mdio",
+ "rmac2_mdio",
+ "rmac0_phy", "rmac1_phy",
+ "rmac2_phy";
+ clocks = <&cpg CPG_MOD 1505>;
+ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+ resets = <&cpg 1505>;
+ status = "disabled";
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ phys = <&eth_serdes 0>;
+ };
+ port@1 {
+ reg = <1>;
+ phys = <&eth_serdes 1>;
+ };
+ port@2 {
+ reg = <2>;
+ phys = <&eth_serdes 2>;
+ };
+ };
+ };
+
scif0: serial@e6e60000 {
compatible = "renesas,scif-r8a779f0",
"renesas,rcar-gen4-scif", "renesas,scif";
reg = <0 0xe6e60000 0 64>;
interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 702>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x51>, <&dmac0 0x50>,
@@ -674,7 +784,7 @@
reg = <0 0xe6e68000 0 64>;
interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 703>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x53>, <&dmac0 0x52>,
@@ -691,7 +801,7 @@
reg = <0 0xe6c50000 0 64>;
interrupts = <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 704>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x57>, <&dmac0 0x56>,
@@ -708,7 +818,7 @@
reg = <0 0xe6c40000 0 64>;
interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 705>,
- <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+ <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x59>, <&dmac0 0x58>,
diff --git a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
index 895f0bd9f754..c10740aee9f6 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
@@ -96,6 +96,24 @@
device_type = "memory";
reg = <0x6 0x00000000 0x1 0x00000000>;
};
+
+ reg_1p8v: regulator-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
};
&avb0 {
@@ -135,6 +153,17 @@
status = "okay";
clock-frequency = <400000>;
+ io_expander_a: gpio@20 {
+ compatible = "onnn,pca9654";
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
eeprom@50 {
compatible = "rohm,br24g01", "atmel,24c01";
label = "cpu-board";
@@ -143,6 +172,23 @@
};
};
+&mmc0 {
+ pinctrl-0 = <&mmc_pins>;
+ pinctrl-1 = <&mmc_pins>;
+ pinctrl-names = "default", "state_uhs";
+
+ vmmc-supply = <&reg_3p3v>;
+ vqmmc-supply = <&reg_1p8v>;
+ mmc-hs200-1_8v;
+ mmc-hs400-1_8v;
+ bus-width = <8>;
+ no-sd;
+ no-sdio;
+ non-removable;
+ full-pwr-cycle-in-suspend;
+ status = "okay";
+};
+
&pfc {
pinctrl-0 = <&scif_clk_pins>;
pinctrl-names = "default";
@@ -180,17 +226,56 @@
bias-pull-up;
};
+ mmc_pins: mmc {
+ groups = "mmc_data8", "mmc_ctrl", "mmc_ds";
+ function = "mmc";
+ power-source = <1800>;
+ };
+
+ qspi0_pins: qspi0 {
+ groups = "qspi0_ctrl", "qspi0_data4";
+ function = "qspi0";
+ };
+
scif_clk_pins: scif_clk {
groups = "scif_clk";
function = "scif_clk";
};
};
-&scif_clk {
- clock-frequency = <24000000>;
+&rpc {
+ pinctrl-0 = <&qspi0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ flash@0 {
+ compatible = "spansion,s25fs512s", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <40000000>;
+ spi-rx-bus-width = <4>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ boot@0 {
+ reg = <0x0 0x1200000>;
+ read-only;
+ };
+ user@1200000 {
+ reg = <0x1200000 0x2e00000>;
+ };
+ };
+ };
};
&rwdt {
timeout-sec = <60>;
status = "okay";
};
+
+&scif_clk {
+ clock-frequency = <24000000>;
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
index d70f0600ae5a..45d8d927ad26 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
@@ -14,18 +14,138 @@
#address-cells = <2>;
#size-cells = <2>;
+ cluster0_opp: opp-table-0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-500000000 {
+ opp-hz = /bits/ 64 <500000000>;
+ opp-microvolt = <825000>;
+ clock-latency-ns = <500000>;
+ };
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <825000>;
+ clock-latency-ns = <500000>;
+ };
+ opp-1500000000 {
+ opp-hz = /bits/ 64 <1500000000>;
+ opp-microvolt = <825000>;
+ clock-latency-ns = <500000>;
+ };
+ opp-1700000000 {
+ opp-hz = /bits/ 64 <1700000000>;
+ opp-microvolt = <825000>;
+ clock-latency-ns = <500000>;
+ opp-suspend;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&a76_0>;
+ };
+ core1 {
+ cpu = <&a76_1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&a76_2>;
+ };
+ core1 {
+ cpu = <&a76_3>;
+ };
+ };
+ };
+
a76_0: cpu@0 {
compatible = "arm,cortex-a76";
reg = <0>;
device_type = "cpu";
power-domains = <&sysc R8A779G0_PD_A1E0D0C0>;
+ next-level-cache = <&L3_CA76_0>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
+ clocks = <&cpg CPG_CORE R8A779G0_CLK_Z0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ a76_1: cpu@100 {
+ compatible = "arm,cortex-a76";
+ reg = <0x100>;
+ device_type = "cpu";
+ power-domains = <&sysc R8A779G0_PD_A1E0D0C1>;
+ next-level-cache = <&L3_CA76_0>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
+ clocks = <&cpg CPG_CORE R8A779G0_CLK_Z0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ a76_2: cpu@10000 {
+ compatible = "arm,cortex-a76";
+ reg = <0x10000>;
+ device_type = "cpu";
+ power-domains = <&sysc R8A779G0_PD_A1E0D1C0>;
+ next-level-cache = <&L3_CA76_1>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
+ clocks = <&cpg CPG_CORE R8A779G0_CLK_Z0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ a76_3: cpu@10100 {
+ compatible = "arm,cortex-a76";
+ reg = <0x10100>;
+ device_type = "cpu";
+ power-domains = <&sysc R8A779G0_PD_A1E0D1C1>;
+ next-level-cache = <&L3_CA76_1>;
+ enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
+ clocks = <&cpg CPG_CORE R8A779G0_CLK_Z0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <400>;
+ exit-latency-us = <500>;
+ min-residency-us = <4000>;
+ };
+ };
+
+ L3_CA76_0: cache-controller-0 {
+ compatible = "cache";
+ power-domains = <&sysc R8A779G0_PD_A2E0D0>;
+ cache-unified;
+ cache-level = <3>;
+ };
+
+ L3_CA76_1: cache-controller-1 {
+ compatible = "cache";
+ power-domains = <&sysc R8A779G0_PD_A2E0D1>;
+ cache-unified;
+ cache-level = <3>;
};
};
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
+ method = "smc";
+ };
+
extal_clk: extal {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -214,6 +334,76 @@
#interrupt-cells = <2>;
};
+ cmt0: timer@e60f0000 {
+ compatible = "renesas,r8a779g0-cmt0",
+ "renesas,rcar-gen4-cmt0";
+ reg = <0 0xe60f0000 0 0x1004>;
+ interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 910>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 910>;
+ status = "disabled";
+ };
+
+ cmt1: timer@e6130000 {
+ compatible = "renesas,r8a779g0-cmt1",
+ "renesas,rcar-gen4-cmt1";
+ reg = <0 0xe6130000 0 0x1004>;
+ interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 911>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 911>;
+ status = "disabled";
+ };
+
+ cmt2: timer@e6140000 {
+ compatible = "renesas,r8a779g0-cmt1",
+ "renesas,rcar-gen4-cmt1";
+ reg = <0 0xe6140000 0 0x1004>;
+ interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 912>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 912>;
+ status = "disabled";
+ };
+
+ cmt3: timer@e6148000 {
+ compatible = "renesas,r8a779g0-cmt1",
+ "renesas,rcar-gen4-cmt1";
+ reg = <0 0xe6148000 0 0x1004>;
+ interrupts = <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 913>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 913>;
+ status = "disabled";
+ };
+
cpg: clock-controller@e6150000 {
compatible = "renesas,r8a779g0-cpg-mssr";
reg = <0 0xe6150000 0 0x4000>;
@@ -235,12 +425,96 @@
#power-domain-cells = <1>;
};
+ intc_ex: interrupt-controller@e61c0000 {
+ compatible = "renesas,intc-ex-r8a779g0", "renesas,irqc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0 0xe61c0000 0 0x200>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 611>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 611>;
+ };
+
+ tmu0: timer@e61e0000 {
+ compatible = "renesas,tmu-r8a779g0", "renesas,tmu";
+ reg = <0 0xe61e0000 0 0x30>;
+ interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 713>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 713>;
+ status = "disabled";
+ };
+
+ tmu1: timer@e6fc0000 {
+ compatible = "renesas,tmu-r8a779g0", "renesas,tmu";
+ reg = <0 0xe6fc0000 0 0x30>;
+ interrupts = <GIC_SPI 292 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 714>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 714>;
+ status = "disabled";
+ };
+
+ tmu2: timer@e6fd0000 {
+ compatible = "renesas,tmu-r8a779g0", "renesas,tmu";
+ reg = <0 0xe6fd0000 0 0x30>;
+ interrupts = <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 715>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 715>;
+ status = "disabled";
+ };
+
+ tmu3: timer@e6fe0000 {
+ compatible = "renesas,tmu-r8a779g0", "renesas,tmu";
+ reg = <0 0xe6fe0000 0 0x30>;
+ interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 716>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 716>;
+ status = "disabled";
+ };
+
+ tmu4: timer@ffc00000 {
+ compatible = "renesas,tmu-r8a779g0", "renesas,tmu";
+ reg = <0 0xffc00000 0 0x30>;
+ interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 717>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 717>;
+ status = "disabled";
+ };
+
i2c0: i2c@e6500000 {
compatible = "renesas,i2c-r8a779g0",
"renesas,rcar-gen4-i2c";
reg = <0 0xe6500000 0 0x40>;
interrupts = <GIC_SPI 610 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 518>;
+ dmas = <&dmac0 0x91>, <&dmac0 0x90>,
+ <&dmac1 0x91>, <&dmac1 0x90>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 518>;
i2c-scl-internal-delay-ns = <110>;
@@ -255,6 +529,9 @@
reg = <0 0xe6508000 0 0x40>;
interrupts = <GIC_SPI 611 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 519>;
+ dmas = <&dmac0 0x93>, <&dmac0 0x92>,
+ <&dmac1 0x93>, <&dmac1 0x92>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 519>;
i2c-scl-internal-delay-ns = <110>;
@@ -269,6 +546,9 @@
reg = <0 0xe6510000 0 0x40>;
interrupts = <GIC_SPI 612 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 520>;
+ dmas = <&dmac0 0x95>, <&dmac0 0x94>,
+ <&dmac1 0x95>, <&dmac1 0x94>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 520>;
i2c-scl-internal-delay-ns = <110>;
@@ -283,6 +563,9 @@
reg = <0 0xe66d0000 0 0x40>;
interrupts = <GIC_SPI 613 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 521>;
+ dmas = <&dmac0 0x97>, <&dmac0 0x96>,
+ <&dmac1 0x97>, <&dmac1 0x96>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 521>;
i2c-scl-internal-delay-ns = <110>;
@@ -297,6 +580,9 @@
reg = <0 0xe66d8000 0 0x40>;
interrupts = <GIC_SPI 614 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 522>;
+ dma-names = "tx", "rx", "tx", "rx";
+ dmas = <&dmac0 0x99>, <&dmac0 0x98>,
+ <&dmac1 0x99>, <&dmac1 0x98>;
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 522>;
i2c-scl-internal-delay-ns = <110>;
@@ -311,6 +597,9 @@
reg = <0 0xe66e0000 0 0x40>;
interrupts = <GIC_SPI 615 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 523>;
+ dmas = <&dmac0 0x9b>, <&dmac0 0x9a>,
+ <&dmac1 0x9b>, <&dmac1 0x9a>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 523>;
i2c-scl-internal-delay-ns = <110>;
@@ -321,19 +610,72 @@
hscif0: serial@e6540000 {
compatible = "renesas,hscif-r8a779g0",
- "renesas,rcar-gen4-hscif",
- "renesas,hscif";
- reg = <0 0xe6540000 0 96>;
+ "renesas,rcar-gen4-hscif", "renesas,hscif";
+ reg = <0 0xe6540000 0 0x60>;
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 514>,
- <&cpg CPG_CORE R8A779G0_CLK_S0D3_PER>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x31>, <&dmac0 0x30>,
+ <&dmac1 0x31>, <&dmac1 0x30>;
+ dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
resets = <&cpg 514>;
status = "disabled";
};
+ hscif1: serial@e6550000 {
+ compatible = "renesas,hscif-r8a779g0",
+ "renesas,rcar-gen4-hscif", "renesas,hscif";
+ reg = <0 0xe6550000 0 0x60>;
+ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 515>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x33>, <&dmac0 0x32>,
+ <&dmac1 0x33>, <&dmac1 0x32>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 515>;
+ status = "disabled";
+ };
+
+ hscif2: serial@e6560000 {
+ compatible = "renesas,hscif-r8a779g0",
+ "renesas,rcar-gen4-hscif", "renesas,hscif";
+ reg = <0 0xe6560000 0 0x60>;
+ interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 516>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x35>, <&dmac0 0x34>,
+ <&dmac1 0x35>, <&dmac1 0x34>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 516>;
+ status = "disabled";
+ };
+
+ hscif3: serial@e66a0000 {
+ compatible = "renesas,hscif-r8a779g0",
+ "renesas,rcar-gen4-hscif", "renesas,hscif";
+ reg = <0 0xe66a0000 0 0x60>;
+ interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 517>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x37>, <&dmac0 0x36>,
+ <&dmac1 0x37>, <&dmac1 0x36>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 517>;
+ status = "disabled";
+ };
+
avb0: ethernet@e6800000 {
compatible = "renesas,etheravb-r8a779g0",
"renesas,etheravb-rcar-gen4";
@@ -475,6 +817,381 @@
status = "disabled";
};
+ pwm0: pwm@e6e30000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e30000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm1: pwm@e6e31000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e31000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm2: pwm@e6e32000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e32000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm3: pwm@e6e33000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e33000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm4: pwm@e6e34000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e34000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm5: pwm@e6e35000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e35000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm6: pwm@e6e36000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e36000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm7: pwm@e6e37000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e37000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm8: pwm@e6e38000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e38000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ pwm9: pwm@e6e39000 {
+ compatible = "renesas,pwm-r8a779g0", "renesas,pwm-rcar";
+ reg = <0 0xe6e39000 0 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cpg CPG_MOD 628>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 628>;
+ status = "disabled";
+ };
+
+ scif0: serial@e6e60000 {
+ compatible = "renesas,scif-r8a779g0",
+ "renesas,rcar-gen4-scif", "renesas,scif";
+ reg = <0 0xe6e60000 0 64>;
+ interrupts = <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 702>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x51>, <&dmac0 0x50>,
+ <&dmac1 0x51>, <&dmac1 0x50>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 702>;
+ status = "disabled";
+ };
+
+ scif1: serial@e6e68000 {
+ compatible = "renesas,scif-r8a779g0",
+ "renesas,rcar-gen4-scif", "renesas,scif";
+ reg = <0 0xe6e68000 0 64>;
+ interrupts = <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 703>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x53>, <&dmac0 0x52>,
+ <&dmac1 0x53>, <&dmac1 0x52>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 703>;
+ status = "disabled";
+ };
+
+ scif3: serial@e6c50000 {
+ compatible = "renesas,scif-r8a779g0",
+ "renesas,rcar-gen4-scif", "renesas,scif";
+ reg = <0 0xe6c50000 0 64>;
+ interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 704>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x57>, <&dmac0 0x56>,
+ <&dmac1 0x57>, <&dmac1 0x56>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 704>;
+ status = "disabled";
+ };
+
+ scif4: serial@e6c40000 {
+ compatible = "renesas,scif-r8a779g0",
+ "renesas,rcar-gen4-scif", "renesas,scif";
+ reg = <0 0xe6c40000 0 64>;
+ interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 705>,
+ <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
+ <&scif_clk>;
+ clock-names = "fck", "brg_int", "scif_clk";
+ dmas = <&dmac0 0x59>, <&dmac0 0x58>,
+ <&dmac1 0x59>, <&dmac1 0x58>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 705>;
+ status = "disabled";
+ };
+
+ tpu: pwm@e6e80000 {
+ compatible = "renesas,tpu-r8a779g0", "renesas,tpu";
+ reg = <0 0xe6e80000 0 0x148>;
+ interrupts = <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 718>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 718>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ msiof0: spi@e6e90000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6e90000 0 0x0064>;
+ interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 618>;
+ dmas = <&dmac0 0x41>, <&dmac0 0x40>,
+ <&dmac1 0x41>, <&dmac1 0x40>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 618>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof1: spi@e6ea0000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6ea0000 0 0x0064>;
+ interrupts = <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 619>;
+ dmas = <&dmac0 0x43>, <&dmac0 0x42>,
+ <&dmac1 0x43>, <&dmac1 0x42>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 619>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof2: spi@e6c00000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6c00000 0 0x0064>;
+ interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 620>;
+ dmas = <&dmac0 0x45>, <&dmac0 0x44>,
+ <&dmac1 0x45>, <&dmac1 0x44>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 620>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof3: spi@e6c10000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6c10000 0 0x0064>;
+ interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 621>;
+ dmas = <&dmac0 0x47>, <&dmac0 0x46>,
+ <&dmac1 0x47>, <&dmac1 0x46>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 621>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof4: spi@e6c20000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6c20000 0 0x0064>;
+ interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 622>;
+ dmas = <&dmac0 0x49>, <&dmac0 0x48>,
+ <&dmac1 0x49>, <&dmac1 0x48>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 622>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof5: spi@e6c28000 {
+ compatible = "renesas,msiof-r8a779g0",
+ "renesas,rcar-gen4-msiof";
+ reg = <0 0xe6c28000 0 0x0064>;
+ interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 623>;
+ dmas = <&dmac0 0x4b>, <&dmac0 0x4a>,
+ <&dmac1 0x4b>, <&dmac1 0x4a>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 623>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ dmac0: dma-controller@e7350000 {
+ compatible = "renesas,dmac-r8a779g0",
+ "renesas,rcar-gen4-dmac";
+ reg = <0 0xe7350000 0 0x1000>,
+ <0 0xe7300000 0 0x10000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3", "ch4",
+ "ch5", "ch6", "ch7", "ch8", "ch9",
+ "ch10", "ch11", "ch12", "ch13",
+ "ch14", "ch15";
+ clocks = <&cpg CPG_MOD 709>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 709>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
+
+ dmac1: dma-controller@e7351000 {
+ compatible = "renesas,dmac-r8a779g0",
+ "renesas,rcar-gen4-dmac";
+ reg = <0 0xe7351000 0 0x1000>,
+ <0 0xe7310000 0 0x10000>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3", "ch4",
+ "ch5", "ch6", "ch7", "ch8", "ch9",
+ "ch10", "ch11", "ch12", "ch13",
+ "ch14", "ch15";
+ clocks = <&cpg CPG_MOD 710>;
+ clock-names = "fck";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 710>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
+
+ mmc0: mmc@ee140000 {
+ compatible = "renesas,sdhi-r8a779g0",
+ "renesas,rcar-gen4-sdhi";
+ reg = <0 0xee140000 0 0x2000>;
+ interrupts = <GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 706>,
+ <&cpg CPG_CORE R8A779G0_CLK_SD0H>;
+ clock-names = "core", "clkh";
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 706>;
+ max-frequency = <200000000>;
+ status = "disabled";
+ };
+
+ rpc: spi@ee200000 {
+ compatible = "renesas,r8a779g0-rpc-if",
+ "renesas,rcar-gen4-rpc-if";
+ reg = <0 0xee200000 0 0x200>,
+ <0 0x08000000 0 0x04000000>,
+ <0 0xee208000 0 0x100>;
+ reg-names = "regs", "dirmap", "wbuf";
+ interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 629>;
+ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+ resets = <&cpg 629>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@f1000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
@@ -483,7 +1200,7 @@
reg = <0x0 0xf1000000 0 0x20000>,
<0x0 0xf1060000 0 0x110000>;
interrupts = <GIC_PPI 9
- (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
prr: chipid@fff00044 {
@@ -494,9 +1211,9 @@
timer {
compatible = "arm,armv8-timer";
- interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
+ interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
};
diff --git a/arch/arm64/boot/dts/renesas/r9a07g043.dtsi b/arch/arm64/boot/dts/renesas/r9a07g043.dtsi
index 689aa4ba416b..3f7d451b1199 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g043.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g043.dtsi
@@ -1,11 +1,10 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/*
- * Device Tree Source for the RZ/G2UL SoC
+ * Device Tree Source for the RZ/Five and RZ/G2UL SoCs
*
* Copyright (C) 2022 Renesas Electronics Corp.
*/
-#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/r9a07g043-cpg.h>
/ {
@@ -69,36 +68,8 @@
};
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu0: cpu@0 {
- compatible = "arm,cortex-a55";
- reg = <0>;
- device_type = "cpu";
- #cooling-cells = <2>;
- next-level-cache = <&L3_CA55>;
- enable-method = "psci";
- clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
- operating-points-v2 = <&cluster0_opp>;
- };
-
- L3_CA55: cache-controller-0 {
- compatible = "cache";
- cache-unified;
- cache-size = <0x40000>;
- };
- };
-
- psci {
- compatible = "arm,psci-1.0", "arm,psci-0.2";
- method = "smc";
- };
-
soc: soc {
compatible = "simple-bus";
- interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
@@ -107,10 +78,10 @@
compatible = "renesas,r9a07g043-ssi",
"renesas,rz-ssi";
reg = <0 0x10049c00 0 0x400>;
- interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 328 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 329 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(326) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(327) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(328) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(329) IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx", "dma_rt";
clocks = <&cpg CPG_MOD R9A07G043_SSI0_PCLK2>,
<&cpg CPG_MOD R9A07G043_SSI0_PCLK_SFR>,
@@ -128,10 +99,10 @@
compatible = "renesas,r9a07g043-ssi",
"renesas,rz-ssi";
reg = <0 0x1004a000 0 0x400>;
- interrupts = <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 331 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 332 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 333 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(330) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(331) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(332) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(333) IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx", "dma_rt";
clocks = <&cpg CPG_MOD R9A07G043_SSI1_PCLK2>,
<&cpg CPG_MOD R9A07G043_SSI1_PCLK_SFR>,
@@ -149,10 +120,10 @@
compatible = "renesas,r9a07g043-ssi",
"renesas,rz-ssi";
reg = <0 0x1004a400 0 0x400>;
- interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 335 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 336 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 337 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(334) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(335) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(336) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(337) IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx", "dma_rt";
clocks = <&cpg CPG_MOD R9A07G043_SSI2_PCLK2>,
<&cpg CPG_MOD R9A07G043_SSI2_PCLK_SFR>,
@@ -170,10 +141,10 @@
compatible = "renesas,r9a07g043-ssi",
"renesas,rz-ssi";
reg = <0 0x1004a800 0 0x400>;
- interrupts = <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 339 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 341 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(338) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(339) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(340) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(341) IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx", "dma_rt";
clocks = <&cpg CPG_MOD R9A07G043_SSI3_PCLK2>,
<&cpg CPG_MOD R9A07G043_SSI3_PCLK_SFR>,
@@ -190,9 +161,9 @@
spi0: spi@1004ac00 {
compatible = "renesas,r9a07g043-rspi", "renesas,rspi-rz";
reg = <0 0x1004ac00 0 0x400>;
- interrupts = <GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 413 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 414 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(415) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(413) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(414) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
clocks = <&cpg CPG_MOD R9A07G043_RSPI0_CLKB>;
resets = <&cpg R9A07G043_RSPI0_RST>;
@@ -208,9 +179,9 @@
spi1: spi@1004b000 {
compatible = "renesas,r9a07g043-rspi", "renesas,rspi-rz";
reg = <0 0x1004b000 0 0x400>;
- interrupts = <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(418) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(416) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(417) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
clocks = <&cpg CPG_MOD R9A07G043_RSPI1_CLKB>;
resets = <&cpg R9A07G043_RSPI1_RST>;
@@ -226,9 +197,9 @@
spi2: spi@1004b400 {
compatible = "renesas,r9a07g043-rspi", "renesas,rspi-rz";
reg = <0 0x1004b400 0 0x400>;
- interrupts = <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(421) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(419) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(420) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
clocks = <&cpg CPG_MOD R9A07G043_RSPI2_CLKB>;
resets = <&cpg R9A07G043_RSPI2_RST>;
@@ -245,12 +216,12 @@
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004b800 0 0x400>;
- interrupts = <GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 383 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(380) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(382) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(383) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(381) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(384) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(384) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
@@ -264,12 +235,12 @@
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004bc00 0 0x400>;
- interrupts = <GIC_SPI 385 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 387 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 388 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 386 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(385) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(387) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(388) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(386) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(389) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(389) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF1_CLK_PCK>;
@@ -283,12 +254,12 @@
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004c000 0 0x400>;
- interrupts = <GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 391 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(390) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(392) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(393) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(391) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(394) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(394) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF2_CLK_PCK>;
@@ -302,12 +273,12 @@
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004c400 0 0x400>;
- interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(395) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(397) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(398) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(396) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(399) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(399) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF3_CLK_PCK>;
@@ -321,12 +292,12 @@
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004c800 0 0x400>;
- interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(400) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(402) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(403) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(401) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(404) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(404) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF4_CLK_PCK>;
@@ -339,10 +310,10 @@
sci0: serial@1004d000 {
compatible = "renesas,r9a07g043-sci", "renesas,sci";
reg = <0 0x1004d000 0 0x400>;
- interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 406 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 407 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(405) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(406) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(407) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(408) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCI0_CLKP>;
clock-names = "fck";
@@ -354,10 +325,10 @@
sci1: serial@1004d400 {
compatible = "renesas,r9a07g043-sci", "renesas,sci";
reg = <0 0x1004d400 0 0x400>;
- interrupts = <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 412 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(409) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(410) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(411) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(412) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCI1_CLKP>;
clock-names = "fck";
@@ -369,14 +340,14 @@
canfd: can@10050000 {
compatible = "renesas,r9a07g043-canfd", "renesas,rzg2l-canfd";
reg = <0 0x10050000 0 0x8000>;
- interrupts = <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(426) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(427) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(422) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(424) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(428) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(423) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(425) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(429) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "g_err", "g_recc",
"ch0_err", "ch0_rec", "ch0_trx",
"ch1_err", "ch1_rec", "ch1_trx";
@@ -405,14 +376,14 @@
#size-cells = <0>;
compatible = "renesas,riic-r9a07g043", "renesas,riic-rz";
reg = <0 0x10058000 0 0x400>;
- interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 348 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 349 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(350) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(348) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(349) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(352) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(353) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(351) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(354) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(355) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tei", "ri", "ti", "spi", "sti",
"naki", "ali", "tmoi";
clocks = <&cpg CPG_MOD R9A07G043_I2C0_PCLK>;
@@ -427,14 +398,14 @@
#size-cells = <0>;
compatible = "renesas,riic-r9a07g043", "renesas,riic-rz";
reg = <0 0x10058400 0 0x400>;
- interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 356 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 357 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(358) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(356) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(357) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(360) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(361) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(359) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(362) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(363) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tei", "ri", "ti", "spi", "sti",
"naki", "ali", "tmoi";
clocks = <&cpg CPG_MOD R9A07G043_I2C1_PCLK>;
@@ -449,14 +420,14 @@
#size-cells = <0>;
compatible = "renesas,riic-r9a07g043", "renesas,riic-rz";
reg = <0 0x10058800 0 0x400>;
- interrupts = <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(366) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(364) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(365) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(368) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(369) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(367) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(370) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(371) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tei", "ri", "ti", "spi", "sti",
"naki", "ali", "tmoi";
clocks = <&cpg CPG_MOD R9A07G043_I2C2_PCLK>;
@@ -471,14 +442,14 @@
#size-cells = <0>;
compatible = "renesas,riic-r9a07g043", "renesas,riic-rz";
reg = <0 0x10058c00 0 0x400>;
- interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 372 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 373 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(374) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(372) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(373) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(376) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(377) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(375) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(378) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(379) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tei", "ri", "ti", "spi", "sti",
"naki", "ali", "tmoi";
clocks = <&cpg CPG_MOD R9A07G043_I2C3_PCLK>;
@@ -491,7 +462,7 @@
adc: adc@10059000 {
compatible = "renesas,r9a07g043-adc", "renesas,rzg2l-adc";
reg = <0 0x10059000 0 0x400>;
- interrupts = <GIC_SPI 347 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(347) IRQ_TYPE_EDGE_RISING>;
clocks = <&cpg CPG_MOD R9A07G043_ADC_ADCLK>,
<&cpg CPG_MOD R9A07G043_ADC_PCLK>;
clock-names = "adclk", "pclk";
@@ -551,12 +522,6 @@
sysc: system-controller@11020000 {
compatible = "renesas,r9a07g043-sysc";
reg = <0 0x11020000 0 0x10000>;
- interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "lpm_int", "ca55stbydone_int",
- "cm33stbyr_int", "ca55_deny";
status = "disabled";
};
@@ -578,23 +543,23 @@
"renesas,rz-dmac";
reg = <0 0x11820000 0 0x10000>,
<0 0x11830000 0 0x10000>;
- interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 125 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 126 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 127 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 130 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 131 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 132 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 133 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 134 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 135 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 136 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 137 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 138 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 139 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 140 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(141) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(125) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(126) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(127) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(128) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(129) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(130) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(131) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(132) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(133) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(134) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(135) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(136) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(137) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(138) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(139) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(140) IRQ_TYPE_EDGE_RISING>;
interrupt-names = "error",
"ch0", "ch1", "ch2", "ch3",
"ch4", "ch5", "ch6", "ch7",
@@ -609,22 +574,12 @@
dma-channels = <16>;
};
- gic: interrupt-controller@11900000 {
- compatible = "arm,gic-v3";
- #interrupt-cells = <3>;
- #address-cells = <0>;
- interrupt-controller;
- reg = <0x0 0x11900000 0 0x40000>,
- <0x0 0x11940000 0 0x60000>;
- interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
- };
-
sdhi0: mmc@11c00000 {
compatible = "renesas,sdhi-r9a07g043",
"renesas,rcar-gen3-sdhi";
reg = <0x0 0x11c00000 0 0x10000>;
- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(104) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(105) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_SDHI0_IMCLK>,
<&cpg CPG_MOD R9A07G043_SDHI0_CLK_HS>,
<&cpg CPG_MOD R9A07G043_SDHI0_IMCLK2>,
@@ -639,8 +594,8 @@
compatible = "renesas,sdhi-r9a07g043",
"renesas,rcar-gen3-sdhi";
reg = <0x0 0x11c10000 0 0x10000>;
- interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(106) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(107) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_SDHI1_IMCLK>,
<&cpg CPG_MOD R9A07G043_SDHI1_CLK_HS>,
<&cpg CPG_MOD R9A07G043_SDHI1_IMCLK2>,
@@ -655,9 +610,9 @@
compatible = "renesas,r9a07g043-gbeth",
"renesas,rzg2l-gbeth";
reg = <0 0x11c20000 0 0x10000>;
- interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(84) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(85) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(86) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "mux", "fil", "arp_ns";
phy-mode = "rgmii";
clocks = <&cpg CPG_MOD R9A07G043_ETH0_CLK_AXI>,
@@ -675,9 +630,9 @@
compatible = "renesas,r9a07g043-gbeth",
"renesas,rzg2l-gbeth";
reg = <0 0x11c30000 0 0x10000>;
- interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(87) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(88) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(89) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "mux", "fil", "arp_ns";
phy-mode = "rgmii";
clocks = <&cpg CPG_MOD R9A07G043_ETH1_CLK_AXI>,
@@ -705,7 +660,7 @@
ohci0: usb@11c50000 {
compatible = "generic-ohci";
reg = <0 0x11c50000 0 0x100>;
- interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(91) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H0_HCLK>;
resets = <&phyrst 0>,
@@ -719,7 +674,7 @@
ohci1: usb@11c70000 {
compatible = "generic-ohci";
reg = <0 0x11c70000 0 0x100>;
- interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(96) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H1_HCLK>;
resets = <&phyrst 1>,
@@ -733,7 +688,7 @@
ehci0: usb@11c50100 {
compatible = "generic-ehci";
reg = <0 0x11c50100 0 0x100>;
- interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(92) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H0_HCLK>;
resets = <&phyrst 0>,
@@ -748,7 +703,7 @@
ehci1: usb@11c70100 {
compatible = "generic-ehci";
reg = <0 0x11c70100 0 0x100>;
- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(97) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H1_HCLK>;
resets = <&phyrst 1>,
@@ -764,7 +719,7 @@
compatible = "renesas,usb2-phy-r9a07g043",
"renesas,rzg2l-usb2-phy";
reg = <0 0x11c50200 0 0x700>;
- interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(94) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H0_HCLK>;
resets = <&phyrst 0>;
@@ -777,7 +732,7 @@
compatible = "renesas,usb2-phy-r9a07g043",
"renesas,rzg2l-usb2-phy";
reg = <0 0x11c70200 0 0x700>;
- interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(99) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2H1_HCLK>;
resets = <&phyrst 1>;
@@ -790,10 +745,10 @@
compatible = "renesas,usbhs-r9a07g043",
"renesas,rza2-usbhs";
reg = <0 0x11c60000 0 0x10000>;
- interrupts = <GIC_SPI 100 IRQ_TYPE_EDGE_RISING>,
- <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_EDGE_RISING>,
+ <SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(102) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(103) IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A07G043_USB_PCLK>,
<&cpg CPG_MOD R9A07G043_USB_U2P_EXR_CPUCLK>;
resets = <&phyrst 0>,
@@ -812,34 +767,19 @@
clocks = <&cpg CPG_MOD R9A07G043_WDT0_PCLK>,
<&cpg CPG_MOD R9A07G043_WDT0_CLK>;
clock-names = "pclk", "oscclk";
- interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <SOC_PERIPHERAL_IRQ(49) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(50) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "wdt", "perrout";
resets = <&cpg R9A07G043_WDT0_PRESETN>;
power-domains = <&cpg>;
status = "disabled";
};
- wdt2: watchdog@12800400 {
- compatible = "renesas,r9a07g043-wdt",
- "renesas,rzg2l-wdt";
- reg = <0 0x12800400 0 0x400>;
- clocks = <&cpg CPG_MOD R9A07G043_WDT2_PCLK>,
- <&cpg CPG_MOD R9A07G043_WDT2_CLK>;
- clock-names = "pclk", "oscclk";
- interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "wdt", "perrout";
- resets = <&cpg R9A07G043_WDT2_PRESETN>;
- power-domains = <&cpg>;
- status = "disabled";
- };
-
ostm0: timer@12801000 {
compatible = "renesas,r9a07g043-ostm",
"renesas,ostm";
reg = <0x0 0x12801000 0x0 0x400>;
- interrupts = <GIC_SPI 46 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(46) IRQ_TYPE_EDGE_RISING>;
clocks = <&cpg CPG_MOD R9A07G043_OSTM0_PCLK>;
resets = <&cpg R9A07G043_OSTM0_PRESETZ>;
power-domains = <&cpg>;
@@ -850,7 +790,7 @@
compatible = "renesas,r9a07g043-ostm",
"renesas,ostm";
reg = <0x0 0x12801400 0x0 0x400>;
- interrupts = <GIC_SPI 47 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(47) IRQ_TYPE_EDGE_RISING>;
clocks = <&cpg CPG_MOD R9A07G043_OSTM1_PCLK>;
resets = <&cpg R9A07G043_OSTM1_PRESETZ>;
power-domains = <&cpg>;
@@ -861,7 +801,7 @@
compatible = "renesas,r9a07g043-ostm",
"renesas,ostm";
reg = <0x0 0x12801800 0x0 0x400>;
- interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <SOC_PERIPHERAL_IRQ(48) IRQ_TYPE_EDGE_RISING>;
clocks = <&cpg CPG_MOD R9A07G043_OSTM2_PCLK>;
resets = <&cpg R9A07G043_OSTM2_PRESETZ>;
power-domains = <&cpg>;
@@ -899,12 +839,4 @@
};
};
};
-
- timer {
- compatible = "arm,armv8-timer";
- interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
- <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
- };
};
diff --git a/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi
new file mode 100644
index 000000000000..6af5f3bca2d1
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the RZ/G2UL SoC
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define SOC_PERIPHERAL_IRQ(nr) GIC_SPI nr
+
+#include "r9a07g043.dtsi"
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a55";
+ reg = <0>;
+ device_type = "cpu";
+ #cooling-cells = <2>;
+ next-level-cache = <&L3_CA55>;
+ enable-method = "psci";
+ clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ L3_CA55: cache-controller-0 {
+ compatible = "cache";
+ cache-unified;
+ cache-size = <0x40000>;
+ cache-level = <3>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+ <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+};
+
+&soc {
+ interrupt-parent = <&gic>;
+
+ gic: interrupt-controller@11900000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x0 0x11900000 0 0x40000>,
+ <0x0 0x11940000 0 0x60000>;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&sysc {
+ interrupts = <SOC_PERIPHERAL_IRQ(42) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(43) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(44) IRQ_TYPE_LEVEL_HIGH>,
+ <SOC_PERIPHERAL_IRQ(45) IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "lpm_int", "ca55stbydone_int",
+ "cm33stbyr_int", "ca55_deny";
+};
diff --git a/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts b/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts
index 059885a01ede..01483b4302c2 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts
+++ b/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts
@@ -17,7 +17,7 @@
#define SW_SW0_DEV_SEL 1
#define SW_ET0_EN_N 1
-#include "r9a07g043.dtsi"
+#include "r9a07g043u.dtsi"
#include "rzg2ul-smarc-som.dtsi"
#include "rzg2ul-smarc.dtsi"
diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
index 2283d4fb8736..487536696d90 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
@@ -109,6 +109,7 @@
compatible = "cache";
cache-unified;
cache-size = <0x40000>;
+ cache-level = <3>;
};
};
@@ -644,7 +645,6 @@
reg = <0 0x11030000 0 0x10000>;
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <2>;
#interrupt-cells = <2>;
interrupt-parent = <&irqc>;
interrupt-controller;
@@ -994,21 +994,6 @@
status = "disabled";
};
- wdt2: watchdog@12800400 {
- compatible = "renesas,r9a07g044-wdt",
- "renesas,rzg2l-wdt";
- reg = <0 0x12800400 0 0x400>;
- clocks = <&cpg CPG_MOD R9A07G044_WDT2_PCLK>,
- <&cpg CPG_MOD R9A07G044_WDT2_CLK>;
- clock-names = "pclk", "oscclk";
- interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "wdt", "perrout";
- resets = <&cpg R9A07G044_WDT2_PRESETN>;
- power-domains = <&cpg>;
- status = "disabled";
- };
-
ostm0: timer@12801000 {
compatible = "renesas,r9a07g044-ostm",
"renesas,ostm";
diff --git a/arch/arm64/boot/dts/renesas/r9a07g044c2-smarc.dts b/arch/arm64/boot/dts/renesas/r9a07g044c2-smarc.dts
index fc34058002e2..f67a6f125d9c 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g044c2-smarc.dts
+++ b/arch/arm64/boot/dts/renesas/r9a07g044c2-smarc.dts
@@ -6,7 +6,37 @@
*/
/dts-v1/;
+
+/*
+ * DIP-Switch SW1 setting on SoM
+ * 1 : High; 0: Low
+ * SW1-2 : SW_SD0_DEV_SEL (1: eMMC; 0: uSD)
+ * SW1-3 : SW_SCIF_CAN (1: CAN1; 0: SCIF1)
+ * SW1-4 : SW_RSPI_CAN (1: CAN1; 0: RSPI1)
+ * SW1-5 : SW_I2S0_I2S1 (1: I2S2 (HDMI audio); 0: I2S0)
+ * Please change below macros according to SW1 setting
+ */
+
+#define SW_SD0_DEV_SEL 1
+
+#define SW_SCIF_CAN 0
+#if (SW_SCIF_CAN)
+/* Due to HW routing, SW_RSPI_CAN is always 0 when SW_SCIF_CAN is set to 1 */
+#define SW_RSPI_CAN 0
+#else
+/* Please set SW_RSPI_CAN. Default value is 1 */
+#define SW_RSPI_CAN 1
+#endif
+
+#if (SW_SCIF_CAN && SW_RSPI_CAN)
+#error "Can not set 1 to both SW_SCIF_CAN and SW_RSPI_CAN due to HW routing"
+#endif
+
+/* comment the #define statement to disable SCIF1 (SER0) on PMOD1 (CN7) */
+#define PMOD1_SER0 1
+
#include "r9a07g044c2.dtsi"
+#include "rzg2lc-smarc-som.dtsi"
#include "rzg2lc-smarc.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi
index 358d4c34465f..304ade54425b 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi
@@ -109,6 +109,7 @@
compatible = "cache";
cache-unified;
cache-size = <0x40000>;
+ cache-level = <3>;
};
};
@@ -650,7 +651,6 @@
reg = <0 0x11030000 0 0x10000>;
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <2>;
#interrupt-cells = <2>;
interrupt-parent = <&irqc>;
interrupt-controller;
@@ -1000,21 +1000,6 @@
status = "disabled";
};
- wdt2: watchdog@12800400 {
- compatible = "renesas,r9a07g054-wdt",
- "renesas,rzg2l-wdt";
- reg = <0 0x12800400 0 0x400>;
- clocks = <&cpg CPG_MOD R9A07G054_WDT2_PCLK>,
- <&cpg CPG_MOD R9A07G054_WDT2_CLK>;
- clock-names = "pclk", "oscclk";
- interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "wdt", "perrout";
- resets = <&cpg R9A07G054_WDT2_PRESETN>;
- power-domains = <&cpg>;
- status = "disabled";
- };
-
ostm0: timer@12801000 {
compatible = "renesas,r9a07g054-ostm",
"renesas,ostm";
diff --git a/arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts b/arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts
index 5c15d73d059f..11e1d51c7c0e 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts
+++ b/arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts
@@ -83,3 +83,7 @@
&uart0 {
status = "okay";
};
+
+&wdt0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi
index fb1a97202c38..0373ec409d54 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi
@@ -37,8 +37,15 @@
compatible = "arm,cortex-a53";
reg = <0>;
device_type = "cpu";
+ next-level-cache = <&L2_CA53>;
clocks = <&cpg CPG_MOD R9A09G011_CA53_CLK>;
};
+
+ L2_CA53: cache-controller-0 {
+ compatible = "cache";
+ cache-unified;
+ cache-level = <2>;
+ };
};
soc: soc {
@@ -48,7 +55,7 @@
#size-cells = <2>;
ranges;
- gic: interrupt-controller@82000000 {
+ gic: interrupt-controller@82010000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;
#address-cells = <0>;
@@ -123,10 +130,15 @@
#power-domain-cells = <0>;
};
+ sys: system-controller@a3f03000 {
+ compatible = "renesas,r9a09g011-sys";
+ reg = <0 0xa3f03000 0 0x400>;
+ };
+
i2c0: i2c@a4030000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,i2c-r9a09g011", "renesas,rzv2m-i2c";
+ compatible = "renesas,r9a09g011-i2c", "renesas,rzv2m-i2c";
reg = <0 0xa4030000 0 0x80>;
interrupts = <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 236 IRQ_TYPE_EDGE_RISING>;
@@ -140,7 +152,7 @@
i2c2: i2c@a4030100 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,i2c-r9a09g011", "renesas,rzv2m-i2c";
+ compatible = "renesas,r9a09g011-i2c", "renesas,rzv2m-i2c";
reg = <0 0xa4030100 0 0x80>;
interrupts = <GIC_SPI 234 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 238 IRQ_TYPE_EDGE_RISING>;
@@ -161,6 +173,19 @@
status = "disabled";
};
+ wdt0: watchdog@a4050000 {
+ compatible = "renesas,r9a09g011-wdt",
+ "renesas,rzv2m-wdt";
+ reg = <0 0xa4050000 0 0x80>;
+ clocks = <&cpg CPG_MOD R9A09G011_WDT0_PCLK>,
+ <&cpg CPG_MOD R9A09G011_WDT0_CLK>;
+ clock-names = "pclk", "oscclk";
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&cpg R9A09G011_WDT0_PRESETN>;
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
pinctrl: pinctrl@b6250000 {
compatible = "renesas,r9a09g011-pinctrl";
reg = <0 0xb6250000 0 0x800>;
diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi
index c4faff092380..fbbb4f03440b 100644
--- a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi
@@ -351,8 +351,3 @@
status = "okay";
timeout-sec = <60>;
};
-
-&wdt2 {
- status = "okay";
- timeout-sec = <60>;
-};
diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi
index 78e6e2376b01..8a0d56872de7 100644
--- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi
@@ -276,8 +276,3 @@
status = "okay";
timeout-sec = <60>;
};
-
-&wdt2 {
- status = "okay";
- timeout-sec = <60>;
-};
diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi
index 6be25a8a28db..b6bd27196d88 100644
--- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi
@@ -8,37 +8,9 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rzg2l-pinctrl.h>
-/*
- * DIP-Switch SW1 setting on SoM
- * 1 : High; 0: Low
- * SW1-2 : SW_SD0_DEV_SEL (1: eMMC; 0: uSD)
- * SW1-3 : SW_SCIF_CAN (1: CAN1; 0: SCIF1)
- * SW1-4 : SW_RSPI_CAN (1: CAN1; 0: RSPI1)
- * SW1-5 : SW_I2S0_I2S1 (1: I2S2 (HDMI audio); 0: I2S0)
- * Please change below macros according to SW1 setting
- */
-
-#define SW_SD0_DEV_SEL 1
-
-#define SW_SCIF_CAN 0
-#if (SW_SCIF_CAN)
-/* Due to HW routing, SW_RSPI_CAN is always 0 when SW_SCIF_CAN is set to 1 */
-#define SW_RSPI_CAN 0
-#else
-/* Please set SW_RSPI_CAN. Default value is 1 */
-#define SW_RSPI_CAN 1
-#endif
-
-#if (SW_SCIF_CAN && SW_RSPI_CAN)
-#error "Can not set 1 to both SW_SCIF_CAN and SW_RSPI_CAN due to HW routing"
-#endif
-
-#include "rzg2lc-smarc-som.dtsi"
#include "rzg2lc-smarc-pinfunction.dtsi"
#include "rz-smarc-common.dtsi"
-/* comment the #define statement to disable SCIF1 (SER0) on PMOD1 (CN7) */
-#define PMOD1_SER0 1
/ {
aliases {
diff --git a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-pinfunction.dtsi b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-pinfunction.dtsi
index bd8bc858c28c..58923dc83faa 100644
--- a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-pinfunction.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-pinfunction.dtsi
@@ -99,6 +99,13 @@
input-enable;
};
+ spi1_pins: spi1 {
+ pinmux = <RZG2L_PORT_PINMUX(4, 0, 2)>, /* CK */
+ <RZG2L_PORT_PINMUX(4, 1, 2)>, /* MOSI */
+ <RZG2L_PORT_PINMUX(4, 2, 2)>, /* MISO */
+ <RZG2L_PORT_PINMUX(4, 3, 2)>; /* SSL */
+ };
+
ssi1_pins: ssi1 {
pinmux = <RZG2L_PORT_PINMUX(3, 0, 2)>, /* BCK */
<RZG2L_PORT_PINMUX(3, 1, 2)>, /* RCK */
diff --git a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi
index 2a0feb53f0dc..931efc07d6fb 100644
--- a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi
@@ -221,13 +221,6 @@
pinmux = <RZG2L_PORT_PINMUX(0, 0, 1)>; /* SD0_CD */
};
};
-
- spi1_pins: rspi1 {
- pinmux = <RZG2L_PORT_PINMUX(4, 0, 2)>, /* CK */
- <RZG2L_PORT_PINMUX(4, 1, 2)>, /* MOSI */
- <RZG2L_PORT_PINMUX(4, 2, 2)>, /* MISO */
- <RZG2L_PORT_PINMUX(4, 3, 2)>; /* SSL */
- };
};
#if (SW_SW0_DEV_SEL)
diff --git a/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts b/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dtso
index c83a30adc6ad..c83a30adc6ad 100644
--- a/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts
+++ b/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dtso
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 8c15593c0ca4..0a76a2ebb5f6 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -3,11 +3,15 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-ctouch2.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-ctouch2-of10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-edimm2.2.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-ringneck-haikou.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-rock-pi-s.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3318-a95x-z2.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-anbernic-rg351m.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2-v11.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go3.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-nanopi-r2s.dtb
@@ -62,13 +66,19 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353p.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353v.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353vs.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg503.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.1.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.2.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-a.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-b.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-roc-pc.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-soquartz-blade.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-soquartz-cm4.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-soquartz-model-a.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-box-demo.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-bpi-r2-pro.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-v10.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-odroid-m1.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-rock-3a.dtb
diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts
index 07008d84434c..c1bbd555f5f5 100644
--- a/arch/arm64/boot/dts/rockchip/px30-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts
@@ -30,31 +30,31 @@
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
- esc-key {
+ button-esc {
label = "esc";
linux,code = <KEY_ESC>;
press-threshold-microvolt = <1310000>;
};
- home-key {
+ button-home {
label = "home";
linux,code = <KEY_HOME>;
press-threshold-microvolt = <624000>;
};
- menu-key {
+ button-menu {
label = "menu";
linux,code = <KEY_MENU>;
press-threshold-microvolt = <987000>;
};
- vol-down-key {
+ button-down {
label = "volume down";
linux,code = <KEY_VOLUMEDOWN>;
press-threshold-microvolt = <300000>;
};
- vol-up-key {
+ button-up {
label = "volume up";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <17000>;
diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts
new file mode 100644
index 000000000000..08a3ad3e7ae9
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Theobroma Systems Design und Consulting GmbH
+ */
+
+/dts-v1/;
+#include "px30-ringneck.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+ model = "Theobroma Systems PX30-uQ7 SoM on Haikou devkit";
+ compatible = "tsd,px30-ringneck-haikou", "rockchip,px30";
+
+ aliases {
+ mmc2 = &sdmmc;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&haikou_keys_pin>;
+ pinctrl-names = "default";
+
+ button-batlow-n {
+ label = "BATLOW#";
+ linux,code = <KEY_BATTERY>;
+ gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+ };
+
+ button-slp-btn-n {
+ label = "SLP_BTN#";
+ linux,code = <KEY_SLEEP>;
+ gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_LOW>;
+ };
+
+ button-wake-n {
+ label = "WAKE#";
+ linux,code = <KEY_WAKEUP>;
+ gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
+ wakeup-source;
+ };
+
+ switch-lid-btn-n {
+ label = "LID_BTN#";
+ linux,code = <SW_LID>;
+ linux,input-type = <EV_SW>;
+ gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ pinctrl-0 = <&module_led_pin>, <&sd_card_led_pin>;
+
+ sd_card_led: led-1 {
+ gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc2";
+ function = LED_FUNCTION_SD;
+ color = <LED_COLOR_ID_BLUE>;
+ };
+ };
+
+ i2s0-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "Haikou,I2S-codec";
+ simple-audio-card,mclk-fs = <512>;
+
+ simple-audio-card,codec {
+ clocks = <&sgtl5000_clk>;
+ sound-dai = <&sgtl5000>;
+ };
+
+ simple-audio-card,cpu {
+ bitclock-master;
+ frame-master;
+ sound-dai = <&i2s0_8ch>;
+ };
+ };
+
+ sgtl5000_clk: sgtl5000-oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
+
+ dc_12v: dc-12v-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "dc_12v";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ };
+
+ vcc3v3_baseboard: vcc3v3-baseboard-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_baseboard";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_baseboard: vcc5v0-baseboard-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_baseboard";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vdda_codec: vdda-codec-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vdda_codec";
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc5v0_baseboard>;
+ };
+
+ vddd_codec: vddd-codec-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vddd_codec";
+ regulator-boot-on;
+ regulator-min-microvolt = <1600000>;
+ regulator-max-microvolt = <1600000>;
+ vin-supply = <&vcc5v0_baseboard>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&sgtl5000_clk>;
+ #sound-dai-cells = <0>;
+ VDDA-supply = <&vdda_codec>;
+ VDDIO-supply = <&vcc3v3_baseboard>;
+ VDDD-supply = <&vddd_codec>;
+ };
+};
+
+&i2c3 {
+ eeprom@50 {
+ reg = <0x50>;
+ compatible = "atmel,24c01";
+ pagesize = <8>;
+ size = <128>;
+ vcc-supply = <&vcc3v3_baseboard>;
+ };
+};
+
+&i2s0_8ch {
+ status = "okay";
+};
+
+&gmac {
+ status = "okay";
+};
+
+&pinctrl {
+ haikou {
+ haikou_keys_pin: haikou-keys-pin {
+ rockchip,pins =
+ /* WAKE# */
+ <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+ /* SLP_BTN# */
+ <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+ /* LID_BTN */
+ <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ /* BATLOW# */
+ <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ /* BIOS_DISABLE# */
+ <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ leds {
+ sd_card_led_pin: sd-card-led-pin {
+ rockchip,pins =
+ <3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&sdmmc {
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ vmmc-supply = <&vcc3v3_baseboard>;
+ status = "okay";
+};
+
+&spi1 {
+ status = "okay";
+};
+
+&u2phy_otg {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart5 {
+ pinctrl-0 = <&uart5_xfer>;
+ status = "okay";
+};
+
+&usb20_otg {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
new file mode 100644
index 000000000000..12397755830b
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Theobroma Systems Design und Consulting GmbH
+ */
+
+/dts-v1/;
+#include "px30.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+ aliases {
+ mmc0 = &emmc;
+ mmc1 = &sdio;
+ rtc0 = &rtc_twi;
+ rtc1 = &rk809;
+ };
+
+ emmc_pwrseq: emmc-pwrseq {
+ compatible = "mmc-pwrseq-emmc";
+ pinctrl-0 = <&emmc_reset>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&module_led_pin>;
+ status = "okay";
+
+ module_led: led-0 {
+ gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_HEARTBEAT;
+ linux,default-trigger = "heartbeat";
+ color = <LED_COLOR_ID_AMBER>;
+ };
+ };
+
+ vcc5v0_sys: vccsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu1 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ mmc-hs200-1_8v;
+ supports-emmc;
+ mmc-pwrseq = <&emmc_pwrseq>;
+ non-removable;
+ vmmc-supply = <&vcc_3v3>;
+ vqmmc-supply = <&vcc_emmc>;
+
+ status = "okay";
+};
+
+/* On-module TI DP83825I PHY but no connector, enable in carrierboard */
+&gmac {
+ snps,reset-gpio = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 50000 50000>;
+ phy-supply = <&vcc_3v3>;
+ clock_in_out = "output";
+};
+
+&gpio2 {
+ /*
+ * The Qseven BIOS_DISABLE signal on the PX30-µQ7 keeps the on-module
+ * eMMC powered-down initially (in fact it keeps the reset signal
+ * asserted). BIOS_DISABLE_OVERRIDE pin allows to re-enable eMMC after
+ * the SPL has been booted from SD Card.
+ */
+ bios-disable-override-hog {
+ gpios = <RK_PB5 GPIO_ACTIVE_LOW>;
+ output-high;
+ line-name = "bios_disable_override";
+ gpio-hog;
+ };
+
+ /*
+ * The BIOS_DISABLE hog is a feedback pin for the actual status of the
+ * signal, ignoring the BIOS_DISABLE_OVERRIDE logic. This usually
+ * represents the state of a switch on the baseboard.
+ */
+ bios-disable-n-hog {
+ gpios = <RK_PC2 GPIO_ACTIVE_LOW>;
+ line-name = "bios_disable";
+ input;
+ gpio-hog;
+ };
+};
+
+&gpu {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ rk809: pmic@20 {
+ compatible = "rockchip,rk809";
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-0 = <&pmic_int>;
+ pinctrl-names = "default";
+ #clock-cells = <0>;
+ clock-output-names = "xin32k";
+ rockchip,system-power-controller;
+ wakeup-source;
+
+ vcc1-supply = <&vcc5v0_sys>;
+ vcc2-supply = <&vcc5v0_sys>;
+ vcc3-supply = <&vcc5v0_sys>;
+ vcc4-supply = <&vcc5v0_sys>;
+ vcc5-supply = <&vcc_3v3>;
+ vcc6-supply = <&vcc_3v3>;
+ vcc7-supply = <&vcc_3v3>;
+ vcc9-supply = <&vcc5v0_sys>;
+
+ regulators {
+ vdd_log: DCDC_REG1 {
+ regulator-name = "vdd_log";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <950000>;
+ };
+ };
+
+ vdd_arm: DCDC_REG2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <950000>;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-name = "vcc_ddr";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_3v0_1v8: vcc_emmc: DCDC_REG4 {
+ regulator-name = "vcc_3v0_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3000000>;
+ };
+ };
+
+ vcc_3v3: DCDC_REG5 {
+ regulator-name = "vcc_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_1v8: LDO_REG2 {
+ regulator-name = "vcc_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc_1v0: LDO_REG3 {
+ regulator-name = "vcc_1v0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_lcd: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vcc_lcd";
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_1v8_lcd: LDO_REG8 {
+ regulator-name = "vcc_1v8_lcd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcca_1v8: LDO_REG9 {
+ regulator-name = "vcca_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "okay";
+
+ /* SE05x is limited to Fast Mode */
+ clock-frequency = <400000>;
+
+ fan: fan@18 {
+ compatible = "ti,amc6821";
+ reg = <0x18>;
+ #cooling-cells = <2>;
+ };
+
+ rtc_twi: rtc@6f {
+ compatible = "isil,isl1208";
+ reg = <0x6f>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+};
+
+&i2s0_8ch {
+ rockchip,trcm-sync-tx-only;
+
+ pinctrl-0 = <&i2s0_8ch_sclktx &i2s0_8ch_lrcktx
+ &i2s0_8ch_sdo0 &i2s0_8ch_sdi0>;
+};
+
+&io_domains {
+ vccio1-supply = <&vcc_3v3>;
+ vccio2-supply = <&vccio_sd>;
+ vccio3-supply = <&vcc_3v3>;
+ vccio4-supply = <&vcc_3v3>;
+ vccio5-supply = <&vcc_3v3>;
+ vccio6-supply = <&vcc_emmc>;
+ vccio-oscgpi-supply = <&vcc_3v3>;
+
+ status = "okay";
+};
+
+&pinctrl {
+ emmc {
+ emmc_reset: emmc-reset {
+ rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ leds {
+ module_led_pin: module-led-pin {
+ rockchip,pins = <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ pmic_int: pmic-int {
+ rockchip,pins =
+ <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+};
+
+&saradc {
+ vref-supply = <&vcc_1v8>;
+ status = "okay";
+};
+
+&sdmmc {
+ vqmmc-supply = <&vccio_sd>;
+};
+
+&tsadc {
+ status = "okay";
+};
+
+&u2phy {
+ status = "okay";
+};
+
+&u2phy_host {
+ status = "okay";
+};
+
+/* Mule UCAN */
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-evb.dts b/arch/arm64/boot/dts/rockchip/rk3308-evb.dts
index 9fe9b0d11003..184b84fdde07 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3308-evb.dts
@@ -23,7 +23,7 @@
poll-interval = <100>;
keyup-threshold-microvolt = <1800000>;
- func-key {
+ button-func {
linux,code = <KEY_FN>;
label = "function";
press-threshold-microvolt = <18000>;
@@ -37,31 +37,31 @@
poll-interval = <100>;
keyup-threshold-microvolt = <1800000>;
- esc-key {
+ button-esc {
linux,code = <KEY_MICMUTE>;
label = "micmute";
press-threshold-microvolt = <1130000>;
};
- home-key {
+ button-home {
linux,code = <KEY_MODE>;
label = "mode";
press-threshold-microvolt = <901000>;
};
- menu-key {
+ button-menu {
linux,code = <KEY_PLAY>;
label = "play";
press-threshold-microvolt = <624000>;
};
- vol-down-key {
+ button-down {
linux,code = <KEY_VOLUMEDOWN>;
label = "volume down";
press-threshold-microvolt = <300000>;
};
- vol-up-key {
+ button-up {
linux,code = <KEY_VOLUMEUP>;
label = "volume up";
press-threshold-microvolt = <18000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
index ea6820902ede..7ea48167747c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
@@ -19,7 +19,7 @@
stdout-path = "serial2:1500000n8";
};
- ir_rx {
+ ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 2dfa67f1cd67..dd228a256a32 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -96,6 +96,7 @@
l2: l2-cache {
compatible = "cache";
+ cache-level = <2>;
};
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts
index 43c928ac98f0..1deef53a4c94 100644
--- a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts
@@ -25,7 +25,7 @@
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <17000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts
new file mode 100644
index 000000000000..61b31688b469
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Hardkernel Co., Ltd
+ * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2022 Maya Matuszczyk <maccraft123mc@gmail.com>
+ */
+
+/dts-v1/;
+#include "rk3326-odroid-go.dtsi"
+
+/ {
+ model = "Anbernic RG351M";
+ compatible = "anbernic,rg351m", "rockchip,rk3326";
+
+ vibrator {
+ compatible = "pwm-vibrator";
+ pwms = <&pwm0 0 1000000 0>;
+ pwm-names = "enable";
+ };
+};
+
+/delete-node/ &builtin_gamepad;
+/delete-node/ &vcc_host; /* conflicts with pwm vibration motor */
+
+&internal_display {
+ compatible = "elida,kd35t133";
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+/delete-node/ &rk817_charger;
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi
new file mode 100644
index 000000000000..fbc6bfbaa5c1
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Hardkernel Co., Ltd
+ * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2022 Maya Matuszczyk <maccraft123mc@gmail.com>
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3326.dtsi"
+
+/ {
+ aliases {
+ mmc0 = &sdmmc;
+ };
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ power-supply = <&vcc_bl>;
+ pwms = <&pwm1 0 25000 0>;
+ };
+
+ builtin_gamepad: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&btn_pins>;
+
+ button-sw1 {
+ gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_LOW>;
+ label = "DPAD-UP";
+ linux,code = <BTN_DPAD_UP>;
+ };
+ button-sw2 {
+ gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_LOW>;
+ label = "DPAD-DOWN";
+ linux,code = <BTN_DPAD_DOWN>;
+ };
+ button-sw3 {
+ gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
+ label = "DPAD-LEFT";
+ linux,code = <BTN_DPAD_LEFT>;
+ };
+ button-sw4 {
+ gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_LOW>;
+ label = "DPAD-RIGHT";
+ linux,code = <BTN_DPAD_RIGHT>;
+ };
+ button-sw5 {
+ gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
+ label = "BTN-A";
+ linux,code = <BTN_EAST>;
+ };
+ button-sw6 {
+ gpios = <&gpio1 RK_PA5 GPIO_ACTIVE_LOW>;
+ label = "BTN-B";
+ linux,code = <BTN_SOUTH>;
+ };
+ button-sw7 {
+ gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>;
+ label = "BTN-Y";
+ linux,code = <BTN_WEST>;
+ };
+ button-sw8 {
+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_LOW>;
+ label = "BTN-X";
+ linux,code = <BTN_NORTH>;
+ };
+ btn_f1: button-sw9 {
+ gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_LOW>;
+ label = "F1";
+ linux,code = <BTN_TRIGGER_HAPPY1>;
+ };
+ btn_f2: button-sw10 {
+ gpios = <&gpio2 RK_PA1 GPIO_ACTIVE_LOW>;
+ label = "F2";
+ linux,code = <BTN_TRIGGER_HAPPY2>;
+ };
+ btn_f3: button-sw11 {
+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
+ label = "F3";
+ linux,code = <BTN_TRIGGER_HAPPY3>;
+ };
+ btn_f4: button-sw12 {
+ gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_LOW>;
+ label = "F4";
+ linux,code = <BTN_TRIGGER_HAPPY4>;
+ };
+ btn_f5: button-sw13 {
+ gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_LOW>;
+ label = "F5";
+ linux,code = <BTN_TRIGGER_HAPPY5>;
+ };
+ btn_f6: button-sw14 {
+ gpios = <&gpio2 RK_PA5 GPIO_ACTIVE_LOW>;
+ label = "F6";
+ linux,code = <BTN_TRIGGER_HAPPY6>;
+ };
+ button-sw15 {
+ gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>;
+ label = "TOP-LEFT";
+ linux,code = <BTN_TL>;
+ };
+ button-sw16 {
+ gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
+ label = "TOP-RIGHT";
+ linux,code = <BTN_TR>;
+ };
+ };
+
+ leds: gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&blue_led_pin>;
+
+ blue_led: led-0 {
+ label = "blue:heartbeat";
+ gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ rk817-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Analog";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Speaker";
+ simple-audio-card,routing =
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Speaker", "SPKO";
+
+ simple-audio-card,codec {
+ sound-dai = <&rk817>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_2ch>;
+ };
+ };
+
+ vccsys: vccsys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v8_sys";
+ regulator-always-on;
+ regulator-min-microvolt = <3800000>;
+ regulator-max-microvolt = <3800000>;
+ };
+
+ vcc_host: vcc_host {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_host";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ gpio = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&usb_midu>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu1 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+ cpu-supply = <&vdd_arm>;
+};
+
+&cru {
+ assigned-clocks = <&cru PLL_NPLL>,
+ <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>,
+ <&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>,
+ <&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>,
+ <&cru PLL_CPLL>;
+
+ assigned-clock-rates = <1188000000>,
+ <200000000>, <200000000>,
+ <150000000>, <150000000>,
+ <100000000>, <200000000>,
+ <17000000>;
+};
+
+&display_subsystem {
+ status = "okay";
+};
+
+&dsi {
+ status = "okay";
+
+ ports {
+ mipi_out: port@1 {
+ reg = <1>;
+
+ mipi_out_panel: endpoint {
+ remote-endpoint = <&mipi_in_panel>;
+ };
+ };
+ };
+
+ internal_display: panel@0 {
+ reg = <0>;
+ backlight = <&backlight>;
+ iovcc-supply = <&vcc_lcd>;
+ reset-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+ rotation = <270>;
+ vdd-supply = <&vcc_lcd>;
+
+ port {
+ mipi_in_panel: endpoint {
+ remote-endpoint = <&mipi_out_panel>;
+ };
+ };
+ };
+};
+
+&dsi_dphy {
+ status = "okay";
+};
+
+&gpu {
+ mali-supply = <&vdd_logic>;
+ status = "okay";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ i2c-scl-falling-time-ns = <16>;
+ i2c-scl-rising-time-ns = <280>;
+ status = "okay";
+
+ rk817: pmic@20 {
+ compatible = "rockchip,rk817";
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
+ clock-output-names = "rk808-clkout1", "xin32k";
+ clock-names = "mclk";
+ clocks = <&cru SCLK_I2S1_OUT>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int>, <&i2s1_2ch_mclk>;
+ wakeup-source;
+ #clock-cells = <1>;
+ #sound-dai-cells = <0>;
+
+ vcc1-supply = <&vccsys>;
+ vcc2-supply = <&vccsys>;
+ vcc3-supply = <&vccsys>;
+ vcc4-supply = <&vccsys>;
+ vcc5-supply = <&vccsys>;
+ vcc6-supply = <&vccsys>;
+ vcc7-supply = <&vccsys>;
+ vcc8-supply = <&vccsys>;
+
+ regulators {
+ vdd_logic: DCDC_REG1 {
+ regulator-name = "vdd_logic";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-ramp-delay = <6001>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <950000>;
+ };
+ };
+
+ vdd_arm: DCDC_REG2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <950000>;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-name = "vcc_ddr";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_3v3: DCDC_REG4 {
+ regulator-name = "vcc_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_1v8: LDO_REG2 {
+ regulator-name = "vcc_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vdd_1v0: LDO_REG3 {
+ regulator-name = "vdd_1v0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc3v3_pmu: LDO_REG4 {
+ regulator-name = "vcc3v3_pmu";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_sd: LDO_REG6 {
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_bl: LDO_REG7 {
+ regulator-name = "vcc_bl";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_lcd: LDO_REG8 {
+ regulator-name = "vcc_lcd";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <2800000>;
+ };
+ };
+
+ LDO_REG9 {
+ /* unused */
+ };
+
+ usb_midu: BOOST {
+ regulator-name = "usb_midu";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+
+ rk817_charger: charger {
+ rockchip,resistor-sense-micro-ohms = <10000>;
+ rockchip,sleep-enter-current-microamp = <300000>;
+ rockchip,sleep-filter-current-microamp = <100000>;
+ };
+
+ rk817_codec: codec {
+ rockchip,mic-in-differential;
+ };
+ };
+};
+
+/* EXT Header(P2): 7(SCL:GPIO0.C2), 8(SDA:GPIO0.C3) */
+&i2c1 {
+ clock-frequency = <400000>;
+ status = "okay";
+};
+
+/* I2S 1 Channel Used */
+&i2s1_2ch {
+ status = "okay";
+};
+
+&io_domains {
+ vccio1-supply = <&vcc_3v3>;
+ vccio2-supply = <&vccio_sd>;
+ vccio3-supply = <&vcc_3v3>;
+ vccio4-supply = <&vcc_3v3>;
+ vccio5-supply = <&vcc_3v3>;
+ vccio6-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
+&pmu_io_domains {
+ pmuio1-supply = <&vcc3v3_pmu>;
+ pmuio2-supply = <&vcc3v3_pmu>;
+ status = "okay";
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&saradc {
+ vref-supply = <&vcc_1v8>;
+ status = "okay";
+};
+
+&sdmmc {
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>; /*[> CD GPIO <]*/
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&sfc {
+ pinctrl-0 = <&sfc_clk &sfc_cs0 &sfc_bus2>;
+ pinctrl-names = "default";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <108000000>;
+ spi-rx-bus-width = <2>;
+ spi-tx-bus-width = <1>;
+ };
+};
+
+&tsadc {
+ status = "okay";
+};
+
+&u2phy {
+ status = "okay";
+
+ u2phy_host: host-port {
+ status = "okay";
+ };
+
+ u2phy_otg: otg-port {
+ status = "disabled";
+ };
+};
+
+&usb20_otg {
+ status = "okay";
+};
+
+/* EXT Header(P2): 2(RXD:GPIO1.C0),3(TXD:.C1),4(CTS:.C2),5(RTS:.C3) */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_xfer &uart1_cts>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2m1_xfer>;
+ status = "okay";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&pinctrl {
+ btns {
+ btn_pins: btn-pins {
+ rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ headphone {
+ hp_det: hp-det {
+ rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ leds {
+ blue_led_pin: blue-led-pin {
+ rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ dc_det: dc-det {
+ rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ pmic_int: pmic-int {
+ rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ soc_slppin_gpio: soc_slppin_gpio {
+ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>;
+ };
+
+ soc_slppin_rst: soc_slppin_rst {
+ rockchip,pins = <0 RK_PA4 2 &pcfg_pull_none>;
+ };
+
+ soc_slppin_slp: soc_slppin_slp {
+ rockchip,pins = <0 RK_PA4 1 &pcfg_pull_none>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2-v11.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2-v11.dts
new file mode 100644
index 000000000000..139c898e590e
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2-v11.dts
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Hardkernel Co., Ltd
+ * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2022 Maya Matuszczyk <maccraft123mc@gmail.com>
+ */
+
+/dts-v1/;
+#include "rk3326-odroid-go.dtsi"
+
+/ {
+ model = "ODROID-GO Advance Black Edition";
+ compatible = "hardkernel,rk3326-odroid-go2-v11", "rockchip,rk3326";
+
+ aliases {
+ mmc1 = &sdio;
+ };
+
+ analog_sticks: adc-joystick {
+ compatible = "adc-joystick";
+ io-channels = <&saradc 1>,
+ <&saradc 2>;
+ poll-interval = <60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axis@0 {
+ reg = <0>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <172 772>;
+ linux,code = <ABS_X>;
+ };
+
+ axis@1 {
+ reg = <1>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <278 815>;
+ linux,code = <ABS_Y>;
+ };
+ };
+
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <3000000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <180000>;
+ voltage-max-design-microvolt = <4100000>;
+ voltage-min-design-microvolt = <3500000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4046950 100>, <4001920 95>, <3967900 90>, <3919950 85>,
+ <3888450 80>, <3861850 75>, <3831540 70>, <3799130 65>,
+ <3768190 60>, <3745650 55>, <3726610 50>, <3711630 45>,
+ <3696720 40>, <3685660 35>, <3674950 30>, <3663050 25>,
+ <3649470 20>, <3635260 15>, <3616920 10>, <3592440 5>,
+ <3574170 0>;
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_pwrseq_pins>;
+ reset-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&builtin_gamepad {
+ button-sw20 {
+ gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+ label = "TOP-LEFT 2";
+ linux,code = <BTN_TL2>;
+ };
+ button-sw21 {
+ gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+ label = "TOP-RIGHT 2";
+ linux,code = <BTN_TR2>;
+ };
+};
+
+&internal_display {
+ compatible = "elida,kd35t133";
+};
+
+&rk817 {
+ regulators {
+ vcc_wifi: LDO_REG9 {
+ regulator-name = "vcc_wifi";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+ };
+};
+
+&rk817_charger {
+ monitored-battery = <&battery>;
+};
+
+&sdio {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ disable-wp;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ non-removable;
+ vmmc-supply = <&vcc_wifi>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ esp8089: wifi@1 {
+ compatible = "esp,esp8089";
+ reg = <1>;
+ };
+};
+
+&pinctrl {
+ btns {
+ btn_pins: btn-pins {
+ rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ wifi {
+ wifi_pwrseq_pins: wifi-pwrseq-pins {
+ rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB6 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
index 72899a714310..4702183b673c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
@@ -2,30 +2,21 @@
/*
* Copyright (c) 2019 Hardkernel Co., Ltd
* Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2022 Maya Matuszczyk <maccraft123mc@gmail.com>
*/
/dts-v1/;
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/rockchip.h>
-#include "rk3326.dtsi"
+#include "rk3326-odroid-go.dtsi"
/ {
model = "ODROID-GO Advance";
compatible = "hardkernel,rk3326-odroid-go2", "rockchip,rk3326";
- aliases {
- mmc0 = &sdmmc;
- };
-
- chosen {
- stdout-path = "serial2:115200n8";
- };
-
- adc-joystick {
+ analog_sticks: adc-joystick {
compatible = "adc-joystick";
io-channels = <&saradc 1>,
<&saradc 2>;
+ poll-interval = <60>;
#address-cells = <1>;
#size-cells = <0>;
@@ -46,12 +37,6 @@
};
};
- backlight: backlight {
- compatible = "pwm-backlight";
- power-supply = <&vcc_bl>;
- pwms = <&pwm1 0 25000 0>;
- };
-
battery: battery {
compatible = "simple-battery";
charge-full-design-microamp-hours = <3000000>;
@@ -63,606 +48,19 @@
voltage-min-design-microvolt = <3500000>;
ocv-capacity-celsius = <20>;
- ocv-capacity-table-0 = <4046950 100>, <4001920 95>, <3967900 90>, <3919950 85>,
+ ocv-capacity-table-0 = <4046950 100>, <4001920 95>, <3967900 90>, <3919950 85>,
<3888450 80>, <3861850 75>, <3831540 70>, <3799130 65>,
<3768190 60>, <3745650 55>, <3726610 50>, <3711630 45>,
<3696720 40>, <3685660 35>, <3674950 30>, <3663050 25>,
<3649470 20>, <3635260 15>, <3616920 10>, <3592440 5>,
<3574170 0>;
};
-
- gpio-keys {
- compatible = "gpio-keys";
- pinctrl-names = "default";
- pinctrl-0 = <&btn_pins>;
-
- /*
- * *** ODROIDGO2-Advance Switch layout ***
- * |------------------------------------------------|
- * | sw15 sw16 |
- * |------------------------------------------------|
- * | sw1 |-------------------| sw8 |
- * | sw3 sw4 | | sw7 sw5 |
- * | sw2 | LCD Display | sw6 |
- * | | | |
- * | |-------------------| |
- * | sw9 sw10 sw11 sw12 sw13 sw14 |
- * |------------------------------------------------|
- */
-
- button-sw1 {
- gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_LOW>;
- label = "DPAD-UP";
- linux,code = <BTN_DPAD_UP>;
- };
- button-sw2 {
- gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_LOW>;
- label = "DPAD-DOWN";
- linux,code = <BTN_DPAD_DOWN>;
- };
- button-sw3 {
- gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
- label = "DPAD-LEFT";
- linux,code = <BTN_DPAD_LEFT>;
- };
- button-sw4 {
- gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_LOW>;
- label = "DPAD-RIGHT";
- linux,code = <BTN_DPAD_RIGHT>;
- };
- button-sw5 {
- gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
- label = "BTN-A";
- linux,code = <BTN_EAST>;
- };
- button-sw6 {
- gpios = <&gpio1 RK_PA5 GPIO_ACTIVE_LOW>;
- label = "BTN-B";
- linux,code = <BTN_SOUTH>;
- };
- button-sw7 {
- gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>;
- label = "BTN-Y";
- linux,code = <BTN_WEST>;
- };
- button-sw8 {
- gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_LOW>;
- label = "BTN-X";
- linux,code = <BTN_NORTH>;
- };
- button-sw9 {
- gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_LOW>;
- label = "F1";
- linux,code = <BTN_TRIGGER_HAPPY1>;
- };
- button-sw10 {
- gpios = <&gpio2 RK_PA1 GPIO_ACTIVE_LOW>;
- label = "F2";
- linux,code = <BTN_TRIGGER_HAPPY2>;
- };
- button-sw11 {
- gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
- label = "F3";
- linux,code = <BTN_TRIGGER_HAPPY3>;
- };
- button-sw12 {
- gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_LOW>;
- label = "F4";
- linux,code = <BTN_TRIGGER_HAPPY4>;
- };
- button-sw13 {
- gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_LOW>;
- label = "F5";
- linux,code = <BTN_TRIGGER_HAPPY5>;
- };
- button-sw14 {
- gpios = <&gpio2 RK_PA5 GPIO_ACTIVE_LOW>;
- label = "F6";
- linux,code = <BTN_TRIGGER_HAPPY6>;
- };
- button-sw15 {
- gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>;
- label = "TOP-LEFT";
- linux,code = <BTN_TL>;
- };
- button-sw16 {
- gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
- label = "TOP-RIGHT";
- linux,code = <BTN_TR>;
- };
- };
-
- leds: gpio-leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&blue_led_pin>;
-
- blue_led: led-0 {
- label = "blue:heartbeat";
- gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "heartbeat";
- };
- };
-
- rk817-sound {
- compatible = "simple-audio-card";
- simple-audio-card,name = "Analog";
- simple-audio-card,format = "i2s";
- simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
- simple-audio-card,mclk-fs = <256>;
- simple-audio-card,widgets =
- "Microphone", "Mic Jack",
- "Headphone", "Headphones",
- "Speaker", "Speaker";
- simple-audio-card,routing =
- "MICL", "Mic Jack",
- "Headphones", "HPOL",
- "Headphones", "HPOR",
- "Speaker", "SPKO";
-
- simple-audio-card,codec {
- sound-dai = <&rk817>;
- };
-
- simple-audio-card,cpu {
- sound-dai = <&i2s1_2ch>;
- };
- };
-
- vccsys: vccsys {
- compatible = "regulator-fixed";
- regulator-name = "vcc3v8_sys";
- regulator-always-on;
- regulator-min-microvolt = <3800000>;
- regulator-max-microvolt = <3800000>;
- };
-
- vcc_host: vcc_host {
- compatible = "regulator-fixed";
- regulator-name = "vcc_host";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
-
- gpio = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&usb_midu>;
- };
-};
-
-&cpu0 {
- cpu-supply = <&vdd_arm>;
-};
-
-&cpu1 {
- cpu-supply = <&vdd_arm>;
-};
-
-&cpu2 {
- cpu-supply = <&vdd_arm>;
-};
-
-&cpu3 {
- cpu-supply = <&vdd_arm>;
-};
-
-&cru {
- assigned-clocks = <&cru PLL_NPLL>,
- <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>,
- <&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>,
- <&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>,
- <&cru PLL_CPLL>;
-
- assigned-clock-rates = <1188000000>,
- <200000000>, <200000000>,
- <150000000>, <150000000>,
- <100000000>, <200000000>,
- <17000000>;
};
-&display_subsystem {
- status = "okay";
+&internal_display {
+ compatible = "elida,kd35t133";
};
-&dsi {
- status = "okay";
-
- ports {
- mipi_out: port@1 {
- reg = <1>;
-
- mipi_out_panel: endpoint {
- remote-endpoint = <&mipi_in_panel>;
- };
- };
- };
-
- panel@0 {
- compatible = "elida,kd35t133";
- reg = <0>;
- backlight = <&backlight>;
- iovcc-supply = <&vcc_lcd>;
- reset-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
- rotation = <270>;
- vdd-supply = <&vcc_lcd>;
-
- port {
- mipi_in_panel: endpoint {
- remote-endpoint = <&mipi_out_panel>;
- };
- };
- };
-};
-
-&dsi_dphy {
- status = "okay";
-};
-
-&gpu {
- mali-supply = <&vdd_logic>;
- status = "okay";
-};
-
-&i2c0 {
- clock-frequency = <400000>;
- i2c-scl-falling-time-ns = <16>;
- i2c-scl-rising-time-ns = <280>;
- status = "okay";
-
- rk817: pmic@20 {
- compatible = "rockchip,rk817";
- reg = <0x20>;
- interrupt-parent = <&gpio0>;
- interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
- clock-output-names = "rk808-clkout1", "xin32k";
- clock-names = "mclk";
- clocks = <&cru SCLK_I2S1_OUT>;
- pinctrl-names = "default";
- pinctrl-0 = <&pmic_int>, <&i2s1_2ch_mclk>;
- wakeup-source;
- #clock-cells = <1>;
- #sound-dai-cells = <0>;
-
- vcc1-supply = <&vccsys>;
- vcc2-supply = <&vccsys>;
- vcc3-supply = <&vccsys>;
- vcc4-supply = <&vccsys>;
- vcc5-supply = <&vccsys>;
- vcc6-supply = <&vccsys>;
- vcc7-supply = <&vccsys>;
- vcc8-supply = <&vccsys>;
-
- regulators {
- vdd_logic: DCDC_REG1 {
- regulator-name = "vdd_logic";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1150000>;
- regulator-ramp-delay = <6001>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <950000>;
- };
- };
-
- vdd_arm: DCDC_REG2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-ramp-delay = <6001>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <950000>;
- };
- };
-
- vcc_ddr: DCDC_REG3 {
- regulator-name = "vcc_ddr";
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- vcc_3v3: DCDC_REG4 {
- regulator-name = "vcc_3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <3300000>;
- };
- };
-
- vcc_1v8: LDO_REG2 {
- regulator-name = "vcc_1v8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <1800000>;
- };
- };
-
- vdd_1v0: LDO_REG3 {
- regulator-name = "vdd_1v0";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <1000000>;
- };
- };
-
- vcc3v3_pmu: LDO_REG4 {
- regulator-name = "vcc3v3_pmu";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <3300000>;
- };
- };
-
- vccio_sd: LDO_REG5 {
- regulator-name = "vccio_sd";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <3300000>;
- };
- };
-
- vcc_sd: LDO_REG6 {
- regulator-name = "vcc_sd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
-
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <3300000>;
- };
- };
-
- vcc_bl: LDO_REG7 {
- regulator-name = "vcc_bl";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <3300000>;
- };
- };
-
- vcc_lcd: LDO_REG8 {
- regulator-name = "vcc_lcd";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <2800000>;
- };
- };
-
- vcc_cam: LDO_REG9 {
- regulator-name = "vcc_cam";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <3000000>;
- };
- };
-
- usb_midu: BOOST {
- regulator-name = "usb_midu";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5400000>;
- regulator-always-on;
- regulator-boot-on;
- };
- };
-
- rk817_charger: charger {
- monitored-battery = <&battery>;
- rockchip,resistor-sense-micro-ohms = <10000>;
- rockchip,sleep-enter-current-microamp = <300000>;
- rockchip,sleep-filter-current-microamp = <100000>;
- };
-
- rk817_codec: codec {
- rockchip,mic-in-differential;
- };
- };
-};
-
-/* EXT Header(P2): 7(SCL:GPIO0.C2), 8(SDA:GPIO0.C3) */
-&i2c1 {
- clock-frequency = <400000>;
- status = "okay";
-};
-
-/* I2S 1 Channel Used */
-&i2s1_2ch {
- status = "okay";
-};
-
-&io_domains {
- vccio1-supply = <&vcc_3v3>;
- vccio2-supply = <&vccio_sd>;
- vccio3-supply = <&vcc_3v3>;
- vccio4-supply = <&vcc_3v3>;
- vccio5-supply = <&vcc_3v3>;
- vccio6-supply = <&vcc_3v3>;
- status = "okay";
-};
-
-&pmu_io_domains {
- pmuio1-supply = <&vcc3v3_pmu>;
- pmuio2-supply = <&vcc3v3_pmu>;
- status = "okay";
-};
-
-&pwm1 {
- status = "okay";
-};
-
-&saradc {
- vref-supply = <&vcc_1v8>;
- status = "okay";
-};
-
-&sdmmc {
- cap-sd-highspeed;
- card-detect-delay = <200>;
- cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>; /*[> CD GPIO <]*/
- sd-uhs-sdr12;
- sd-uhs-sdr25;
- sd-uhs-sdr50;
- sd-uhs-sdr104;
- vmmc-supply = <&vcc_sd>;
- vqmmc-supply = <&vccio_sd>;
- status = "okay";
-};
-
-&sfc {
- pinctrl-0 = <&sfc_clk &sfc_cs0 &sfc_bus2>;
- pinctrl-names = "default";
- #address-cells = <1>;
- #size-cells = <0>;
- status = "okay";
-
- flash@0 {
- compatible = "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <108000000>;
- spi-rx-bus-width = <2>;
- spi-tx-bus-width = <1>;
- };
-};
-
-&tsadc {
- status = "okay";
-};
-
-&u2phy {
- status = "okay";
-
- u2phy_host: host-port {
- status = "okay";
- };
-
- u2phy_otg: otg-port {
- status = "disabled";
- };
-};
-
-&usb20_otg {
- status = "okay";
-};
-
-/* EXT Header(P2): 2(RXD:GPIO1.C0),3(TXD:.C1),4(CTS:.C2),5(RTS:.C3) */
-&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_xfer &uart1_cts>;
- status = "okay";
-};
-
-&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart2m1_xfer>;
- status = "okay";
-};
-
-&vopb {
- status = "okay";
-};
-
-&vopb_mmu {
- status = "okay";
-};
-
-&pinctrl {
- btns {
- btn_pins: btn-pins {
- rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
- <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
- <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
- };
- };
-
- headphone {
- hp_det: hp-det {
- rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>;
- };
- };
-
- leds {
- blue_led_pin: blue-led-pin {
- rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
- pmic {
- dc_det: dc-det {
- rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- pmic_int: pmic-int {
- rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
- };
-
- soc_slppin_gpio: soc_slppin_gpio {
- rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>;
- };
-
- soc_slppin_rst: soc_slppin_rst {
- rockchip,pins = <0 RK_PA4 2 &pcfg_pull_none>;
- };
-
- soc_slppin_slp: soc_slppin_slp {
- rockchip,pins = <0 RK_PA4 1 &pcfg_pull_none>;
- };
- };
+&rk817_charger {
+ monitored-battery = <&battery>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts
new file mode 100644
index 000000000000..842efbaf1a6a
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Hardkernel Co., Ltd
+ * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2022 Maya Matuszczyk <maccraft123mc@gmail.com>
+ */
+
+/dts-v1/;
+#include "rk3326-odroid-go.dtsi"
+
+/ {
+ model = "ODROID-GO Super";
+ compatible = "hardkernel,rk3326-odroid-go3", "rockchip,rk3326";
+
+ joystick_mux_controller: mux-controller {
+ compatible = "gpio-mux";
+ pinctrl = <&mux_en_pins>;
+ #mux-control-cells = <0>;
+
+ mux-gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>,
+ <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+ };
+
+ joystick_mux: adc-mux {
+ compatible = "io-channel-mux";
+ io-channels = <&saradc 1>;
+ io-channel-names = "parent";
+ #io-channel-cells = <1>;
+
+ mux-controls = <&joystick_mux_controller>;
+ channels = "0", "1", "2", "3";
+ };
+
+ analog_sticks: adc-joystick {
+ compatible = "adc-joystick";
+ io-channels = <&joystick_mux 0>,
+ <&joystick_mux 1>,
+ <&joystick_mux 2>,
+ <&joystick_mux 3>;
+ poll-interval = <60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axis@0 {
+ reg = <0>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <180 800>;
+ linux,code = <ABS_X>;
+ };
+
+ axis@1 {
+ reg = <1>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <180 800>;
+ linux,code = <ABS_RX>;
+ };
+
+ axis@2 {
+ reg = <2>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <180 800>;
+ linux,code = <ABS_Y>;
+ };
+
+ axis@3 {
+ reg = <3>;
+ abs-flat = <10>;
+ abs-fuzz = <10>;
+ abs-range = <180 800>;
+ linux,code = <ABS_RY>;
+ };
+ };
+
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <4000000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <180000>;
+ voltage-max-design-microvolt = <4100000>;
+ voltage-min-design-microvolt = <3500000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4046950 100>, <4001920 95>, <3967900 90>, <3919950 85>,
+ <3888450 80>, <3861850 75>, <3831540 70>, <3799130 65>,
+ <3768190 60>, <3745650 55>, <3726610 50>, <3711630 45>,
+ <3696720 40>, <3685660 35>, <3674950 30>, <3663050 25>,
+ <3649470 20>, <3635260 15>, <3616920 10>, <3592440 5>,
+ <3574170 0>;
+ };
+
+ gpio-keys-vol {
+ compatible = "gpio-keys";
+ autorepeat;
+ pinctrl-0 = <&btn_pins_vol>;
+ pinctrl-names = "default";
+
+ button-vol-down {
+ gpios = <&gpio2 RK_PA1 GPIO_ACTIVE_LOW>;
+ label = "VOLUMEDOWN";
+ linux,code = <KEY_VOLUMEDOWN>;
+ };
+
+ button-volume-up {
+ gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_LOW>;
+ label = "VOLUMEUP";
+ linux,code = <KEY_VOLUMEUP>;
+ };
+ };
+};
+
+/* f1 and f2 conflict with volume buttons */
+/delete-node/ &btn_f1;
+/delete-node/ &btn_f2;
+
+&builtin_gamepad {
+ button-sw19 {
+ gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+ label = "SELECT";
+ linux,code = <BTN_SELECT>;
+ };
+ /* note that TR2 and TL2 are swapped */
+ button-sw20 {
+ gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+ label = "TOP-RIGHT 2";
+ linux,code = <BTN_TR2>;
+ };
+ button-sw21 {
+ gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+ label = "TOP-LEFT 2";
+ linux,code = <BTN_TL2>;
+ };
+ button-sw22 {
+ gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+ label = "START";
+ linux,code = <BTN_START>;
+ };
+};
+
+&internal_display {
+ status = "disabled";
+};
+
+&rk817_charger {
+ monitored-battery = <&battery>;
+};
+
+&pinctrl {
+ btns {
+ btn_pins: btn-pins {
+ rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+ <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ btn_pins_vol: btn-pins-vol {
+ rockchip,pins = <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
+ <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ joystick {
+ mux_en_pins: mux-pins {
+ rockchip,pins = <3 RK_PB5 RK_FUNC_GPIO &pcfg_output_low>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 49ae15708a0b..6d7a7bf72ac7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -102,6 +102,7 @@
l2: l2-cache0 {
compatible = "cache";
+ cache-level = <2>;
};
};
@@ -1025,6 +1026,17 @@
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ crypto: crypto@ff060000 {
+ compatible = "rockchip,rk3328-crypto";
+ reg = <0x0 0xff060000 0x0 0x4000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_CRYPTO_MST>, <&cru HCLK_CRYPTO_SLV>,
+ <&cru SCLK_CRYPTO>;
+ clock-names = "hclk_master", "hclk_slave", "sclk";
+ resets = <&cru SRST_CRYPTO>;
+ reset-names = "crypto-rst";
+ };
+
pinctrl: pinctrl {
compatible = "rockchip,rk3328-pinctrl";
rockchip,grf = <&grf>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
index 7f5bba0c6001..81d1064fdb21 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
@@ -208,11 +208,10 @@
vin-supply = <&vcc_sys>;
};
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
/* rtc_int is not connected */
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
index 38d757c00548..5589f3db6b36 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
@@ -192,11 +192,10 @@
vin-supply = <&vcc_sys>;
};
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
/* rtc_int is not connected */
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
index ed3348b558f8..a47d9f758611 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
@@ -734,10 +734,6 @@ camera: &i2c7 {
};
/* PINCTRL OVERRIDES */
-&ec_ap_int_l {
- rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
-};
-
&ap_fw_wp {
rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
index 2a332763c35c..9d9297bc5f04 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
@@ -123,7 +123,7 @@
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "Recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <18000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
index 452728b82e42..3bf8f959e42c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
@@ -39,7 +39,7 @@
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "Recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <18000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts
index 72182c58cc46..65cb21837b0c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts
@@ -19,7 +19,7 @@
keyup-threshold-microvolt = <1500000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "Recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <18000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
index 278123b4f911..b6e082f1f6d9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
@@ -167,6 +167,7 @@
};
&emmc_phy {
+ rockchip,enable-strobe-pulldown;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
index 9e2e246e0bab..dba4d03bfc2b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
@@ -52,13 +52,13 @@
press-threshold-microvolt = <300000>;
};
- back {
+ button-back {
label = "Back";
linux,code = <KEY_BACK>;
press-threshold-microvolt = <985000>;
};
- menu {
+ button-menu {
label = "Menu";
linux,code = <KEY_MENU>;
press-threshold-microvolt = <1314000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 2e058c315025..04403a76238b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -81,6 +81,27 @@
regulator-max-microvolt = <1800000>;
vin-supply = <&vcc3v3_sys>;
};
+
+ wifi_pwrseq: sdio-wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk818 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable_h_pin>;
+ /*
+ * Wait between power-on and SDIO access for CYP43455
+ * POR circuit.
+ */
+ post-power-on-delay-ms = <110>;
+ /*
+ * Wait between consecutive toggles for CYP43455 CBUCK
+ * regulator discharge.
+ */
+ power-off-delay-us = <10000>;
+
+ /* WL_REG_ON on module */
+ reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+ };
};
&cpu_l0 {
@@ -360,11 +381,45 @@
};
};
+ sdio-pwrseq {
+ wifi_enable_h_pin: wifi-enable-h-pin {
+ rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
sound {
vcc1v8_codec_en: vcc1v8-codec-en {
rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>;
};
};
+
+ wireless-bluetooth {
+ bt_wake_pin: bt-wake-pin {
+ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_host_wake_pin: bt-host-wake-pin {
+ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_reset_pin: bt-reset-pin {
+ rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&sdio0 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ disable-wp;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+ sd-uhs-sdr104;
+ status = "okay";
};
&sdmmc {
@@ -393,6 +448,27 @@
status = "okay";
};
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4345c5";
+ clocks = <&rk818 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+ max-speed = <1500000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_pin &bt_wake_pin &bt_reset_pin>;
+ shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+ vbat-supply = <&vcc3v3_sys>;
+ vddio-supply = <&vcc_1v8>;
+ };
+};
+
&uart2 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
index 04c752f49be9..115c14c0a3c6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
@@ -207,7 +207,7 @@
cap-sd-highspeed;
cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
disable-wp;
- max-frequency = <150000000>;
+ max-frequency = <40000000>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
vmmc-supply = <&vcc3v3_baseboard>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
index 5a2661ae0131..7ba1c28f70a9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
@@ -98,13 +98,12 @@
};
&i2c0 {
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PA5 IRQ_TYPE_EDGE_FALLING>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "xin32k";
pinctrl-names = "default";
pinctrl-0 = <&hym8563_int>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi
index 2f4b1b2e3ac7..bbf1e3f24585 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi
@@ -41,7 +41,7 @@
keyup-threshold-microvolt = <1500000>;
poll-interval = <100>;
- recovery {
+ button-recovery {
label = "Recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <18000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts
index f9884902f874..309c35d7fca8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts
@@ -601,6 +601,12 @@
status = "okay";
};
+&tsadc {
+ rockchip,hw-tshut-mode = <1>;
+ rockchip,hw-tshut-polarity = <1>;
+ status = "okay";
+};
+
&u2phy0 {
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
index 645ced6617a6..1f76d3501bda 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
@@ -509,7 +509,6 @@
&i2s1 {
rockchip,playback-channels = <2>;
rockchip,capture-channels = <2>;
- status = "okay";
};
&i2s2 {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
index 94e39ed63397..c920ddf44baf 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
@@ -128,6 +128,8 @@
};
&hdmi {
+ avdd-0v9-supply = <&vcca0v9_hdmi>;
+ avdd-1v8-supply = <&vcca1v8_hdmi>;
ddc-i2c-bus = <&i2c3>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_cec>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
index 13927e7d0724..dbec2b7173a0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
@@ -33,13 +33,13 @@
press-threshold-microvolt = <300000>;
};
- back {
+ button-back {
label = "Back";
linux,code = <KEY_BACK>;
press-threshold-microvolt = <985000>;
};
- menu {
+ button-menu {
label = "Menu";
linux,code = <KEY_MENU>;
press-threshold-microvolt = <1314000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 92c2207e686c..4391aea25984 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -582,6 +582,26 @@
status = "disabled";
};
+ crypto0: crypto@ff8b0000 {
+ compatible = "rockchip,rk3399-crypto";
+ reg = <0x0 0xff8b0000 0x0 0x4000>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru HCLK_M_CRYPTO0>, <&cru HCLK_S_CRYPTO0>, <&cru SCLK_CRYPTO0>;
+ clock-names = "hclk_master", "hclk_slave", "sclk";
+ resets = <&cru SRST_CRYPTO0>, <&cru SRST_CRYPTO0_S>, <&cru SRST_CRYPTO0_M>;
+ reset-names = "master", "lave", "crypto";
+ };
+
+ crypto1: crypto@ff8b8000 {
+ compatible = "rockchip,rk3399-crypto";
+ reg = <0x0 0xff8b8000 0x0 0x4000>;
+ interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru HCLK_M_CRYPTO1>, <&cru HCLK_S_CRYPTO1>, <&cru SCLK_CRYPTO1>;
+ clock-names = "hclk_master", "hclk_slave", "sclk";
+ resets = <&cru SRST_CRYPTO1>, <&cru SRST_CRYPTO1_S>, <&cru SRST_CRYPTO1_M>;
+ reset-names = "master", "slave", "crypto";
+ };
+
i2c1: i2c@ff110000 {
compatible = "rockchip,rk3399-i2c";
reg = <0x0 0xff110000 0x0 0x1000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi
index 935b8c68a71d..bf9eb0405b62 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi
@@ -297,11 +297,10 @@
clock-frequency = <400000>;
status = "okay";
- hym8563: hym8563@51 {
+ hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "hym8563";
pinctrl-names = "default";
pinctrl-0 = <&hym8563_int>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
index 7a20e2d6876a..63cff402f3a8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
@@ -5,7 +5,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/linux-event-codes.h>
#include <dt-bindings/pinctrl/rockchip.h>
-#include "rk3566-anbernic-rgxx3.dtsi"
+#include "rk3566-anbernic-rg353x.dtsi"
/ {
model = "RG353P";
@@ -18,26 +18,66 @@
mmc3 = &sdmmc2;
};
- backlight: backlight {
- compatible = "pwm-backlight";
- power-supply = <&vcc_sys>;
- pwms = <&pwm4 0 25000 0>;
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <3472000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <117000>;
+ voltage-max-design-microvolt = <4172000>;
+ voltage-min-design-microvolt = <3400000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4172000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
+ <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
+ <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
+ <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
+ <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
+ <3400000 0>;
};
-};
-&gpio_keys_control {
- button-a {
- gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
- label = "EAST";
- linux,code = <BTN_EAST>;
+ /* Channels reversed for both headphones and speakers. */
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rk817_ext";
+ simple-audio-card,aux-devs = <&spk_amp>;
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Internal Speakers";
+ simple-audio-card,routing =
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Internal Speakers", "Speaker Amp OUTL",
+ "Internal Speakers", "Speaker Amp OUTR",
+ "Speaker Amp INL", "HPOL",
+ "Speaker Amp INR", "HPOR";
+ simple-audio-card,pin-switches = "Internal Speakers";
+
+ simple-audio-card,codec {
+ sound-dai = <&rk817>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
};
- button-left {
- gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>;
- label = "DPAD-LEFT";
- linux,code = <BTN_DPAD_LEFT>;
+ spk_amp: audio-amplifier {
+ compatible = "simple-audio-amplifier";
+ enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&spk_amp_enable_h>;
+ pinctrl-names = "default";
+ sound-name-prefix = "Speaker Amp";
};
+};
+&gpio_keys_control {
button-r1 {
gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
label = "TR";
@@ -49,27 +89,6 @@
label = "TR2";
linux,code = <BTN_TR2>;
};
-
- button-right {
- gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
- label = "DPAD-RIGHT";
- linux,code = <BTN_DPAD_RIGHT>;
- };
-
- button-y {
- gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
- label = "WEST";
- linux,code = <BTN_WEST>;
- };
-};
-
-&i2c0 {
- /* This hardware is physically present but unused. */
- power-monitor@62 {
- compatible = "cellwise,cw2015";
- reg = <0x62>;
- status = "disabled";
- };
};
&i2c2 {
@@ -78,8 +97,22 @@
status = "okay";
};
-&pwm4 {
- status = "okay";
+&pinctrl {
+ audio-amplifier {
+ spk_amp_enable_h: spk-amp-enable-h {
+ rockchip,pins =
+ <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&rk817 {
+ rk817_charger: charger {
+ monitored-battery = <&battery>;
+ rockchip,resistor-sense-micro-ohms = <10000>;
+ rockchip,sleep-enter-current-microamp = <300000>;
+ rockchip,sleep-filter-current-microamp = <100000>;
+ };
};
&sdhci {
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts
new file mode 100644
index 000000000000..885234a023e1
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rg353x.dtsi"
+
+/ {
+ model = "RG353V";
+ compatible = "anbernic,rg353v", "rockchip,rk3566";
+
+ aliases {
+ mmc0 = &sdhci;
+ mmc1 = &sdmmc0;
+ mmc2 = &sdmmc1;
+ mmc3 = &sdmmc2;
+ };
+
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <3151000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <117000>;
+ voltage-max-design-microvolt = <4172000>;
+ voltage-min-design-microvolt = <3400000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4172000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
+ <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
+ <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
+ <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
+ <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
+ <3400000 0>;
+ };
+
+ /* Channels reversed for headphones. */
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rk817_int";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Internal Speakers";
+ simple-audio-card,routing =
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Internal Speakers", "SPKO";
+
+ simple-audio-card,codec {
+ sound-dai = <&rk817>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+ };
+};
+
+&gpio_keys_control {
+ button-r1 {
+ gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+ label = "TR";
+ linux,code = <BTN_TR>;
+ };
+
+ button-r2 {
+ gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+ label = "TR2";
+ linux,code = <BTN_TR2>;
+ };
+};
+
+&i2c2 {
+ pintctrl-names = "default";
+ pinctrl-0 = <&i2c2m1_xfer>;
+ status = "okay";
+};
+
+&pinctrl {
+ touch {
+ touch_rst: touch-rst {
+ rockchip,pins =
+ <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+};
+
+&rk817 {
+ rk817_charger: charger {
+ monitored-battery = <&battery>;
+ rockchip,resistor-sense-micro-ohms = <10000>;
+ rockchip,sleep-enter-current-microamp = <300000>;
+ rockchip,sleep-filter-current-microamp = <100000>;
+ };
+};
+
+&sdhci {
+ pinctrl-0 = <&emmc_bus8>, <&emmc_clk>, <&emmc_cmd>, <&emmc_datastrobe>, <&emmc_rstnout>;
+ pinctrl-names = "default";
+ bus-width = <8>;
+ mmc-hs200-1_8v;
+ non-removable;
+ vmmc-supply = <&vcc_3v3>;
+ vqmmc-supply = <&vcc_1v8>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts
new file mode 100644
index 000000000000..a7dc462fe21f
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rg353x.dtsi"
+
+/ {
+ model = "RG353VS";
+ compatible = "anbernic,rg353vs", "rockchip,rk3566";
+
+ aliases {
+ mmc0 = &sdmmc0;
+ mmc1 = &sdmmc1;
+ mmc2 = &sdmmc2;
+ };
+
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <3151000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <117000>;
+ voltage-max-design-microvolt = <4172000>;
+ voltage-min-design-microvolt = <3400000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4172000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
+ <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
+ <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
+ <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
+ <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
+ <3400000 0>;
+ };
+
+ /* Channels reversed for headphones. */
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rk817_int";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Internal Speakers";
+ simple-audio-card,routing =
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Internal Speakers", "SPKO";
+
+ simple-audio-card,codec {
+ sound-dai = <&rk817>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+ };
+};
+
+&gpio_keys_control {
+ button-r1 {
+ gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+ label = "TR";
+ linux,code = <BTN_TR>;
+ };
+
+ button-r2 {
+ gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+ label = "TR2";
+ linux,code = <BTN_TR2>;
+ };
+};
+
+&rk817 {
+ rk817_charger: charger {
+ monitored-battery = <&battery>;
+ rockchip,resistor-sense-micro-ohms = <10000>;
+ rockchip,sleep-enter-current-microamp = <300000>;
+ rockchip,sleep-filter-current-microamp = <100000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353x.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353x.dtsi
new file mode 100644
index 000000000000..65a80d1f6d91
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353x.dtsi
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rgxx3.dtsi"
+
+/ {
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ power-supply = <&vcc_sys>;
+ pwms = <&pwm4 0 25000 0>;
+ };
+};
+
+&cru {
+ assigned-clocks = <&cru PLL_GPLL>, <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
+ assigned-clock-rates = <1200000000>, <200000000>, <241500000>;
+};
+
+&gpio_keys_control {
+ button-a {
+ gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+ label = "EAST";
+ linux,code = <BTN_EAST>;
+ };
+
+ button-left {
+ gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>;
+ label = "DPAD-LEFT";
+ linux,code = <BTN_DPAD_LEFT>;
+ };
+
+ button-right {
+ gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
+ label = "DPAD-RIGHT";
+ linux,code = <BTN_DPAD_RIGHT>;
+ };
+
+ button-y {
+ gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+ label = "WEST";
+ linux,code = <BTN_WEST>;
+ };
+};
+
+&i2c0 {
+ /* This hardware is physically present but unused. */
+ power-monitor@62 {
+ compatible = "cellwise,cw2015";
+ reg = <0x62>;
+ status = "disabled";
+ };
+};
+
+&pwm4 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts
index 3dc01549a5b4..5dafcc86296b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts
@@ -17,6 +17,25 @@
mmc2 = &sdmmc2;
};
+ battery: battery {
+ compatible = "simple-battery";
+ charge-full-design-microamp-hours = <3472000>;
+ charge-term-current-microamp = <300000>;
+ constant-charge-current-max-microamp = <2000000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <117000>;
+ voltage-max-design-microvolt = <4172000>;
+ voltage-min-design-microvolt = <3400000>;
+
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 = <4172000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
+ <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
+ <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
+ <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
+ <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
+ <3400000 0>;
+ };
+
gpio_spi: spi {
compatible = "spi-gpio";
pinctrl-names = "default";
@@ -29,6 +48,50 @@
cs-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
num-chipselects = <0>;
};
+
+ /* Channels reversed for both headphones and speakers. */
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rk817_ext";
+ simple-audio-card,aux-devs = <&spk_amp>;
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Headphone", "Headphones",
+ "Speaker", "Internal Speakers";
+ simple-audio-card,routing =
+ "MICL", "Mic Jack",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Internal Speakers", "Speaker Amp OUTL",
+ "Internal Speakers", "Speaker Amp OUTR",
+ "Speaker Amp INL", "HPOL",
+ "Speaker Amp INR", "HPOR";
+ simple-audio-card,pin-switches = "Internal Speakers";
+
+ simple-audio-card,codec {
+ sound-dai = <&rk817>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+ };
+
+ spk_amp: audio-amplifier {
+ compatible = "simple-audio-amplifier";
+ enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&spk_amp_enable_h>;
+ pinctrl-names = "default";
+ sound-name-prefix = "Speaker Amp";
+ };
+};
+
+&cru {
+ assigned-clocks = <&cru PLL_GPLL>, <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
+ assigned-clock-rates = <1200000000>, <200000000>, <500000000>;
};
&gpio_keys_control {
@@ -76,6 +139,13 @@
};
&pinctrl {
+ audio-amplifier {
+ spk_amp_enable_h: spk-amp-enable-h {
+ rockchip,pins =
+ <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
gpio-spi {
spi_pins: spi-pins {
rockchip,pins =
@@ -85,3 +155,12 @@
};
};
};
+
+&rk817 {
+ rk817_charger: charger {
+ monitored-battery = <&battery>;
+ rockchip,resistor-sense-micro-ohms = <10000>;
+ rockchip,sleep-enter-current-microamp = <300000>;
+ rockchip,sleep-filter-current-microamp = <100000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi
index 2b455143b86d..41262a69d33e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi
@@ -22,6 +22,7 @@
<&adc_mux 3>;
pinctrl-0 = <&joy_mux_en>;
pinctrl-names = "default";
+ poll-interval = <60>;
#address-cells = <1>;
#size-cells = <0>;
@@ -217,37 +218,6 @@
};
};
- /* Channels reversed for both headphones and speakers. */
- sound {
- compatible = "simple-audio-card";
- simple-audio-card,name = "anbernic_rk817";
- simple-audio-card,aux-devs = <&spk_amp>;
- simple-audio-card,format = "i2s";
- simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
- simple-audio-card,mclk-fs = <256>;
- simple-audio-card,widgets =
- "Microphone", "Mic Jack",
- "Headphone", "Headphones",
- "Speaker", "Internal Speakers";
- simple-audio-card,routing =
- "MICL", "Mic Jack",
- "Headphones", "HPOL",
- "Headphones", "HPOR",
- "Internal Speakers", "Speaker Amp OUTL",
- "Internal Speakers", "Speaker Amp OUTR",
- "Speaker Amp INL", "HPOL",
- "Speaker Amp INR", "HPOR";
- simple-audio-card,pin-switches = "Internal Speakers";
-
- simple-audio-card,codec {
- sound-dai = <&rk817>;
- };
-
- simple-audio-card,cpu {
- sound-dai = <&i2s1_8ch>;
- };
- };
-
sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&rk817 1>;
@@ -258,14 +228,6 @@
reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_LOW>;
};
- spk_amp: audio-amplifier {
- compatible = "simple-audio-amplifier";
- enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
- pinctrl-0 = <&spk_amp_enable_h>;
- pinctrl-names = "default";
- sound-name-prefix = "Speaker Amp";
- };
-
vcc3v3_lcd0_n: regulator-vcc3v3-lcd0 {
compatible = "regulator-fixed";
gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
@@ -607,13 +569,6 @@
};
&pinctrl {
- audio-amplifier {
- spk_amp_enable_h: spk-amp-enable-h {
- rockchip,pins =
- <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
gpio-btns {
btn_pins_ctrl: btn-pins-ctrl {
rockchip,pins =
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
new file mode 100644
index 000000000000..4c7f9abd594f
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/*
+ * Author: Piotr Oniszczuk piotr.oniszczuk@gmail.com
+ * Based on Quartz64 DT by: Peter Geis pgwipeout@gmail.com
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include "rk3566.dtsi"
+
+/ {
+ model = "Rockchip RK3566 BOX DEMO Board";
+ compatible = "rockchip,rk3566-box-demo", "rockchip,rk3566";
+
+ aliases {
+ ethernet0 = &gmac1;
+ mmc0 = &sdmmc0;
+ mmc1 = &sdmmc1;
+ mmc2 = &sdhci;
+ };
+
+ chosen: chosen {
+ stdout-path = "serial2:1500000n8";
+ };
+
+ gmac1_clkin: external-gmac1-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "gmac1_clkin";
+ #clock-cells = <0>;
+ };
+
+ hdmi-con {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio4 RK_PC3 GPIO_ACTIVE_LOW>;
+ pinctrl-0 = <&ir_int>;
+ linux,rc-map-name = "rc-beelink-gs1";
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_work: led-0 {
+ gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_HEARTBEAT;
+ color = <LED_COLOR_ID_BLUE>;
+ linux,default-trigger = "heartbeat";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_work_en>;
+ };
+ };
+
+ sdio_pwrseq: sdio-pwrseq {
+ status = "okay";
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&pmucru CLK_RTC_32K>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable_h &wifi_32k>;
+ reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;
+ };
+
+ spdif_dit: spdif-dit {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ spdif_sound: spdif-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SPDIF";
+
+ simple-audio-card,cpu {
+ sound-dai = <&spdif>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&spdif_dit>;
+ };
+ };
+
+ vcc12v0_dcin: regulator-vcc12v0-dcin {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc12v0_dcin";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ };
+
+ vcc5v0_sys: regulator-vcc5v0-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc12v0_dcin>;
+ };
+
+ vcc3v3_sys: regulator-vcc3v3-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc12v0_dcin>;
+ };
+
+ vcc_3v3: regulator-vcc-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_3v3";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc5v0_usb_host: regulator-vcc5v0-usb-host {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb_host_en>;
+ regulator-name = "vcc5v0_usb_host";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcc5v0_usb2_otg: regulator-vcc5v0-usb2-otg {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb2_otg_en>;
+ regulator-name = "vcc5v0_usb_otg";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcca_1v8: regulator-vcca-1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcca_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vdda_0v9: regulator-vdda-0v9 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdda_0v9";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vdd_fixed: regulator-vdd-fixed {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_fixed";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <950000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vdd_cpu: regulator-vdd-cpu {
+ compatible = "pwm-regulator";
+ pwms = <&pwm0 0 5000 1>;
+ regulator-name = "vdd_cpu";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-settling-time-up-us = <250>;
+ pwm-supply = <&vcc5v0_sys>;
+ };
+
+ vdd_logic: regulator-vdd-logic {
+ compatible = "pwm-regulator";
+ pwms = <&pwm1 0 5000 1>;
+ regulator-name = "vdd_logic";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-settling-time-up-us = <250>;
+ pwm-supply = <&vcc5v0_sys>;
+ };
+};
+
+&combphy1 {
+ status = "okay";
+};
+
+&combphy2 {
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu1 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu2 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu3 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&gmac1 {
+ assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>;
+ assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&gmac1_clkin>;
+ phy-mode = "rgmii";
+ clock_in_out = "input";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac1m1_miim
+ &gmac1m1_tx_bus2
+ &gmac1m1_rx_bus2
+ &gmac1m1_rgmii_clk
+ &gmac1m1_rgmii_bus
+ &gmac1m1_clkinout>;
+ snps,reset-gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>;
+ snps,reset-active-low;
+ /* Reset time is 20ms, 100ms for rtl8211f */
+ snps,reset-delays-us = <0 20000 100000>;
+
+ tx_delay = <0x4f>;
+ rx_delay = <0x2d>;
+ phy-handle = <&rgmii_phy1>;
+ status = "okay";
+};
+
+&mdio1 {
+ rgmii_phy1: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0x1>;
+ };
+};
+
+&hdmi {
+ assigned-clocks = <&cru CLK_HDMI_CEC>;
+ assigned-clock-rates = <32768>;
+ avdd-0v9-supply = <&vdda_0v9>;
+ avdd-1v8-supply = <&vcca_1v8>;
+ status = "okay";
+};
+
+&hdmi_in {
+ hdmi_in_vp0: endpoint {
+ remote-endpoint = <&vp0_out_hdmi>;
+ };
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&hdmi_sound {
+ status = "okay";
+};
+
+&gpu {
+ status = "okay";
+};
+
+&i2s0_8ch {
+ status = "okay";
+};
+
+&i2s1_8ch {
+ rockchip,trcm-sync-tx-only;
+ status = "okay";
+};
+
+&pinctrl {
+ bt {
+ bt_enable_h: bt-enable-h {
+ rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_host_wake_l: bt-host-wake-l {
+ rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ bt_wake_l: bt-wake-l {
+ rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdio-pwrseq {
+ wifi_enable_h: wifi-enable-h {
+ rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wifi_32k: wifi-32k {
+ rockchip,pins = <0 RK_PB0 2 &pcfg_pull_none>;
+ };
+ };
+
+ usb {
+ vcc5v0_usb_host_en: vcc5v0_usb_host_en {
+ rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ vcc5v0_usb2_otg_en: vcc5v0_usb2_otg_en {
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ };
+
+ ir {
+ ir_int: ir-int {
+ rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ led {
+ led_work_en: led_work_en {
+ rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&sdhci {
+ bus-width = <8>;
+ mmc-hs200-1_8v;
+ non-removable;
+ status = "okay";
+};
+
+&sdmmc0 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
+ vmmc-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
+&sdmmc1 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ disable-wp;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>;
+ vmmc-supply = <&vcc_3v3>;
+ vqmmc-supply = <&vcca_1v8>;
+ status = "okay";
+};
+
+&spdif {
+ status = "okay";
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1m1_cs0 &spi1m1_pins>;
+};
+
+&tsadc {
+ /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-mode = <1>;
+ /* tshut polarity 0:LOW 1:HIGH */
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn>;
+ status = "okay";
+ uart-has-rtscts;
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&pmucru CLK_RTC_32K>;
+ clock-names = "ext_clock";
+ device-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+ host-wake-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
+ vbat-supply = <&vcc3v3_sys>;
+ vddio-supply = <&vcca_1v8>;
+ };
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&vop {
+ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+ assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+ status = "okay";
+};
+
+&vop_mmu {
+ status = "okay";
+};
+
+&vp0 {
+ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
+ reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+ remote-endpoint = <&hdmi_in_vp0>;
+ };
+};
+
+&vpu {
+ status = "okay";
+};
+
+&vdpu_mmu {
+ status = "okay";
+};
+
+&usb2phy0_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy0_otg {
+ vbus-supply = <&vcc5v0_usb2_otg>;
+ status = "okay";
+};
+
+&usb2phy1_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy1_otg {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy1 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&usb_host1_xhci {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
index 0d45868132b9..8d61f824c12d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
@@ -23,7 +23,7 @@
io-channel-names = "buttons";
keyup-threshold-microvolt = <1750000>;
- recovery {
+ button-recovery {
label = "recovery";
linux,code = <KEY_VENDOR>;
press-threshold-microvolt = <0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index a05460b92415..25a8c781f4e7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -740,7 +740,7 @@
&uart1 {
pinctrl-names = "default";
- pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn>;
+ pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn &uart1m0_rtsn>;
status = "okay";
uart-has-rtscts;
@@ -748,13 +748,14 @@
compatible = "brcm,bcm43438-bt";
clocks = <&rk817 1>;
clock-names = "lpo";
- device-wakeup-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
- host-wakeup-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+ device-wakeup-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
vbat-supply = <&vcc_sys>;
vddio-supply = <&vcca1v8_pmu>;
+ max-speed = <3000000>;
};
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
index 77b179cd20e7..b276eb0810c7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
@@ -246,7 +246,7 @@
compatible = "rockchip,rk809";
reg = <0x20>;
interrupt-parent = <&gpio0>;
- interrupts = <RK_PA7 IRQ_TYPE_LEVEL_LOW>;
+ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_LOW>;
assigned-clocks = <&cru I2S1_MCLKOUT_TX>;
assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>;
clock-names = "mclk";
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts
index dba648c2f57e..61c7a3ad7387 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts
@@ -82,6 +82,18 @@
vin-supply = <&usb_5v>;
};
+ vcc3v3_pcie: vcc3v3-pcie-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_enable_h>;
+ regulator-name = "vcc3v3_pcie";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
vcc3v3_sys: vcc3v3-sys-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc3v3_sys";
@@ -122,6 +134,10 @@
status = "okay";
};
+&combphy2 {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&vdd_cpu>;
};
@@ -142,7 +158,7 @@
assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>;
assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>, <&gmac1_clkin>;
clock_in_out = "input";
- phy-mode = "rgmii-id";
+ phy-mode = "rgmii";
phy-supply = <&vcc_3v3>;
pinctrl-names = "default";
pinctrl-0 = <&gmac1m0_miim
@@ -432,11 +448,7 @@
&i2c3 {
pinctrl-names = "default";
- pinctrl-0 = <&i2c3m1_xfer>;
- status = "okay";
-};
-
-&i2c5 {
+ pinctrl-0 = <&i2c3m0_xfer>;
status = "okay";
};
@@ -447,6 +459,14 @@
};
};
+&pcie2x1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_reset_h>;
+ reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
+ vpcie3v3-supply = <&vcc3v3_pcie>;
+ status = "okay";
+};
+
&pinctrl {
bt {
bt_enable_h: bt-enable-h {
@@ -468,6 +488,16 @@
};
};
+ pcie {
+ pcie_enable_h: pcie-enable-h {
+ rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ pcie_reset_h: pcie-reset-h {
+ rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
pmic {
pmic_int: pmic_int {
rockchip,pins =
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts
new file mode 100644
index 000000000000..4e49bebf548b
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+#include "rk3566-soquartz.dtsi"
+
+/ {
+ model = "PINE64 RK3566 SOQuartz on Blade carrier board";
+ compatible = "pine64,soquartz-blade", "pine64,soquartz", "rockchip,rk3566";
+
+ /* labeled VCC3V0_SD in schematic to not conflict with PMIC regulator */
+ vcc3v0_sd: vcc3v0-sd-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v0_sd";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ /* labeled VCC_SSD in schematic */
+ vcc3v3_pcie_p: vcc3v3-pcie-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_pcie_p";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vbus>;
+ };
+
+ vcc5v_dcin: vcc5v-dcin-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v_dcin";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+};
+
+&combphy2 {
+ phy-supply = <&vcc3v3_sys>;
+ status = "okay";
+};
+
+&gmac1 {
+ status = "okay";
+};
+
+/*
+ * i2c1 is exposed on CM1 / Module1A
+ * pin 80 - SCL0 - i2c1_scl_m0, pullup to vcc3v3_pmu
+ * pin 82 - SDA0 - i2c1_sda_m0, pullup to vcc3v3_pmu
+ */
+&i2c1 {
+ status = "okay";
+
+};
+
+/*
+ * i2c2 is exposed on CM1 / Module1A - to PI40
+ * pin 56 - GPIO3 - i2c2_scl_m1, pullup to vcc_3v3, shared with i2s1_8ch
+ * pin 58 - GPIO2 - i2c2_sda_m1, pullup to vcc_3v3
+ */
+&i2c2 {
+ status = "disabled";
+};
+
+/*
+ * i2c3 is exposed on CM1 / Module1A - to PI40
+ * pin 35 - ID_SC(GPIO28) - i2c3_scl_m0, pullup to vcc_3v3
+ * pin 36 - ID_SD(GPIO27) - i2c3_sda_m0, pullup to vcc_3v3
+ */
+&i2c3 {
+ status = "disabled";
+};
+
+/*
+ * i2c4 is exposed on CM2 / Module1B - to PI40
+ * pin 45 - GPIO24 - i2c4_scl_m1
+ * pin 47 - GPIO23 - i2c4_sda_m1
+ */
+&i2c4 {
+ status = "disabled";
+};
+
+/*
+ * i2s1_8ch is exposed on CM1 / Module1A - to PI40
+ * pin 24 - GPIO26 - i2s1_sdi1_m1
+ * pin 25 - GPIO21 - i2s1_sdo0_m1
+ * pin 26 - GPIO19 - i2s1_lrck_tx_m1
+ * pin 27 - GPIO20 - i2s1_sdi0_m1
+ * pin 29 - GPIO16 - i2s1_sdi3_m1
+ * pin 30 - GPIO6 - i2s1_sdi2_m1
+ * pin 40 - GPIO9 - i2s1_sdo1_m1, shared with spi3
+ * pin 41 - GPIO25 - i2s1_sdo2_m1
+ * pin 49 - GPIO18 - i2s1_sclk_tx_m1
+ * pin 50 - GPIO17 - i2s1_mclk_m1
+ * pin 56 - GPIO3 - i2s1_sdo3_m1, shared with i2c2
+ */
+&i2s1_8ch {
+ status = "disabled";
+};
+
+&led_diy {
+ color = <LED_COLOR_ID_RED>;
+ function = LED_FUNCTION_DISK_ACTIVITY;
+ linux,default-trigger = "disk-activity";
+ status = "okay";
+};
+
+&led_work {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_STATUS;
+ linux,default-trigger = "heartbeat";
+ status = "okay";
+};
+
+&pcie2x1 {
+ vpcie3v3-supply = <&vcc3v3_pcie_p>;
+ status = "okay";
+};
+
+&rgmii_phy1 {
+ status = "okay";
+};
+
+/*
+ * saradc is exposed on CM1 / Module1A - to J2
+ * pin 94 - AIN1 - saradc_vin3
+ * pin 96 - AIN0 - saradc_vin2
+ */
+&saradc {
+ status = "disabled";
+};
+
+&sdmmc0 {
+ vmmc-supply = <&vcc3v0_sd>;
+ status = "okay";
+};
+
+/*
+ * spi3 is exposed on CM1 / Module1A - to PI40
+ * pin 37 - GPIO7 - spi3_cs1_m0
+ * pin 38 - GPIO11 - spi3_clk_m0
+ * pin 39 - GPIO8 - spi3_cs0_m0
+ * pin 40 - GPIO9 - spi3_miso_m0, shared with i2s1_8ch
+ * pin 44 - GPIO10 - spi3_mosi_m0
+ */
+&spi3 {
+ status = "disabled";
+};
+
+/*
+ * uart2 is exposed on CM1 / Module1A - to PI40
+ * pin 51 - GPIO15 - uart2_rx_m0
+ * pin 55 - GPIO14 - uart2_tx_m0
+ */
+&uart2 {
+ status = "okay";
+};
+
+/*
+ * uart7 is exposed on CM1 / Module1A - to PI40
+ * pin 46 - GPIO22 - uart7_tx_m2
+ * pin 47 - GPIO23 - uart7_rx_m2
+ */
+&uart7 {
+ status = "okay";
+};
+
+&usb2phy0 {
+ status = "okay";
+};
+
+&usb2phy0_otg {
+ phy-supply = <&vbus>;
+ status = "okay";
+};
+
+&usb_host0_xhci {
+ status = "okay";
+};
+
+&vbus {
+ vin-supply = <&vcc5v_dcin>;
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts
index e00568a6be5c..263ce40770dd 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts
@@ -30,6 +30,12 @@
};
};
+/* phy for pcie */
+&combphy2 {
+ phy-supply = <&vcc3v3_sys>;
+ status = "okay";
+};
+
&gmac1 {
status = "okay";
};
@@ -105,6 +111,11 @@
status = "okay";
};
+&pcie2x1 {
+ vpcie3v3-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
&rgmii_phy1 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts
new file mode 100644
index 000000000000..2208dbfb7f0a
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include "rk3566-soquartz.dtsi"
+
+/ {
+ model = "PINE64 RK3566 SOQuartz on Model A carrier board";
+ compatible = "pine64,soquartz-model-a", "pine64,soquartz", "rockchip,rk3566";
+
+ /* labeled DCIN_12V in schematic */
+ vcc12v_dcin: vcc12v-dcin-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc12v_dcin";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ };
+
+ vcc5v0_usb: vcc5v0-usb-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_usb";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc12v_dcin>;
+ };
+
+ /*
+ * Labelled VCC3V0_SD in schematic to not conflict with PMIC
+ * regulator, it's 3.3v in actuality
+ */
+ vcc3v0_sd: vcc3v0-sd-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v0_sd";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc3v3_pcie: vcc3v3-pcie-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_pcie";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc12v_dcin>;
+ };
+
+ vcc12v_pcie: vcc12v-pcie-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc12v_pcie";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ vin-supply = <&vcc12v_dcin>;
+ };
+};
+
+/* phy for pcie */
+&combphy2 {
+ phy-supply = <&vcc3v3_sys>;
+ status = "okay";
+};
+
+&gmac1 {
+ status = "okay";
+};
+
+/*
+ * i2c1 is exposed on CM1 / Module1A
+ * pin 80 - SCL0 - i2c1_scl_m0, pullup to vcc3v3_pmu
+ * pin 82 - SDA0 - i2c1_sda_m0, pullup to vcc3v3_pmu
+ */
+&i2c1 {
+ status = "okay";
+
+ /*
+ * the rtc interrupt is tied to PMIC_PWRON,
+ * it will force reset the board if triggered.
+ */
+ pcf85063: rtc@51 {
+ compatible = "nxp,pcf85063";
+ reg = <0x51>;
+ };
+};
+
+/*
+ * i2c2 is exposed on CM1 / Module1A - to PI40
+ * pin 56 - GPIO3 - i2c2_scl_m1, pullup to vcc_3v3, shared with i2s1_8ch
+ * pin 58 - GPIO2 - i2c2_sda_m1, pullup to vcc_3v3
+ */
+&i2c2 {
+ status = "disabled";
+};
+
+/*
+ * i2c3 is exposed on CM1 / Module1A - to PI40
+ * pin 35 - ID_SC(GPIO28) - i2c3_scl_m0, pullup to vcc_3v3
+ * pin 36 - ID_SD(GPIO27) - i2c3_sda_m0, pullup to vcc_3v3
+ */
+&i2c3 {
+ status = "disabled";
+};
+
+/*
+ * i2c4 is exposed on CM2 / Module1B - to PI40
+ * pin 45 - GPIO24 - i2c4_scl_m1
+ * pin 47 - GPIO23 - i2c4_sda_m1
+ */
+&i2c4 {
+ status = "disabled";
+};
+
+/*
+ * i2s1_8ch is exposed on CM1 / Module1A - to PI40
+ * pin 24 - GPIO26 - i2s1_sdi1_m1
+ * pin 25 - GPIO21 - i2s1_sdo0_m1
+ * pin 26 - GPIO19 - i2s1_lrck_tx_m1
+ * pin 27 - GPIO20 - i2s1_sdi0_m1
+ * pin 29 - GPIO16 - i2s1_sdi3_m1
+ * pin 30 - GPIO6 - i2s1_sdi2_m1
+ * pin 40 - GPIO9 - i2s1_sdo1_m1, shared with spi3
+ * pin 41 - GPIO25 - i2s1_sdo2_m1
+ * pin 49 - GPIO18 - i2s1_sclk_tx_m1
+ * pin 50 - GPIO17 - i2s1_mclk_m1
+ * pin 56 - GPIO3 - i2s1_sdo3_m1, shared with i2c2
+ */
+&i2s1_8ch {
+ status = "disabled";
+};
+
+&led_diy {
+ status = "okay";
+};
+
+&led_work {
+ status = "okay";
+};
+
+&pcie2x1 {
+ vpcie3v3-supply = <&vcc3v3_pcie>;
+ status = "okay";
+};
+
+&rgmii_phy1 {
+ status = "okay";
+};
+
+&rgmii_phy1 {
+ status = "okay";
+};
+
+/*
+ * saradc is exposed on CM1 / Module1A - to J2
+ * pin 94 - AIN1 - saradc_vin3
+ * pin 96 - AIN0 - saradc_vin2
+ */
+&saradc {
+ status = "disabled";
+};
+
+/*
+ * vmmc-supply is vcc3v3_sd on v1.0 and vcc3v0_sd on v1.1+
+ * the soquartz SoM has SDMMC_PWR (CM1 pin 75) hardwired to vcc3v3_sys,
+ * so we use vcc3v3_sd here to ensure the regulator is enabled on older boards.
+ */
+&sdmmc0 {
+ vmmc-supply = <&vcc3v3_sd>;
+ status = "okay";
+};
+
+/*
+ * spi3 is exposed on CM1 / Module1A - to PI40
+ * pin 37 - GPIO7 - spi3_cs1_m0
+ * pin 38 - GPIO11 - spi3_clk_m0
+ * pin 39 - GPIO8 - spi3_cs0_m0
+ * pin 40 - GPIO9 - spi3_miso_m0, shared with i2s1_8ch
+ * pin 44 - GPIO10 - spi3_mosi_m0
+ */
+&spi3 {
+ status = "disabled";
+};
+
+/*
+ * uart2 is exposed on CM1 / Module1A - to PI40
+ * pin 51 - GPIO15 - uart2_rx_m0
+ * pin 55 - GPIO14 - uart2_tx_m0
+ */
+&uart2 {
+ status = "okay";
+};
+
+/*
+ * uart7 is exposed on CM1 / Module1A - to PI40
+ * pin 46 - GPIO22 - uart7_tx_m2
+ * pin 47 - GPIO23 - uart7_rx_m2
+ */
+&uart7 {
+ status = "okay";
+};
+
+&usb2phy0 {
+ status = "okay";
+};
+
+&usb2phy0_otg {
+ phy-supply = <&vcc5v0_usb>;
+ status = "okay";
+};
+
+&usb_host0_xhci {
+ status = "okay";
+};
+
+&vbus {
+ vin-supply = <&vcc5v0_usb>;
+};
+
+&vcc3v3_sd {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi
index 5bcd4be32964..ce7165d7f1a1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi
@@ -4,6 +4,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
#include "rk3566.dtsi"
/ {
@@ -28,6 +29,17 @@
#clock-cells = <0>;
};
+ hdmi-con {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
leds {
compatible = "gpio-leds";
@@ -143,6 +155,33 @@
status = "disabled";
};
+&gpu {
+ mali-supply = <&vdd_gpu>;
+ status = "okay";
+};
+
+&hdmi {
+ avdd-0v9-supply = <&vdda0v9_image>;
+ avdd-1v8-supply = <&vcca1v8_image>;
+ status = "okay";
+};
+
+&hdmi_in {
+ hdmi_in_vp0: endpoint {
+ remote-endpoint = <&vp0_out_hdmi>;
+ };
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&hdmi_sound {
+ status = "okay";
+};
+
&i2c0 {
status = "okay";
@@ -411,6 +450,10 @@
status = "disabled";
};
+&i2s0_8ch {
+ status = "okay";
+};
+
/*
* i2s1_8ch is exposed on CM1 / Module1A
* pin 24 - i2s1_sdi1_m1
@@ -444,6 +487,12 @@
};
};
+&pcie2x1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_reset_h>;
+ reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
+};
+
&pinctrl {
bt {
bt_enable_h: bt-enable-h {
@@ -469,6 +518,15 @@
};
};
+ pcie {
+ pcie_clkreq_h: pcie-clkreq-h {
+ rockchip,pins = <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ pcie_reset_h: pcie-reset-h {
+ rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
pmic {
pmic_int_l: pmic-int-l {
rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -614,3 +672,20 @@
&usb_host0_xhci {
status = "disabled";
};
+
+&vop {
+ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+ assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+ status = "okay";
+};
+
+&vop_mmu {
+ status = "okay";
+};
+
+&vp0 {
+ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
+ reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+ remote-endpoint = <&hdmi_in_vp0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
index c282f6e79960..26d7fda275ed 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
@@ -500,7 +500,6 @@
interrupt-parent = <&gpio0>;
interrupts = <RK_PD3 IRQ_TYPE_EDGE_FALLING>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "rtcic_32kout";
pinctrl-names = "default";
pinctrl-0 = <&hym8563_int>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts
new file mode 100644
index 000000000000..59ecf868dbd0
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts
@@ -0,0 +1,744 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Hardkernel Co., Ltd.
+ *
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include "rk3568.dtsi"
+
+/ {
+ model = "Hardkernel ODROID-M1";
+ compatible = "rockchip,rk3568-odroid-m1", "rockchip,rk3568";
+
+ aliases {
+ ethernet0 = &gmac0;
+ i2c0 = &i2c3;
+ i2c3 = &i2c0;
+ mmc0 = &sdhci;
+ mmc1 = &sdmmc0;
+ serial0 = &uart1;
+ serial1 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial2:1500000n8";
+ };
+
+ dc_12v: dc-12v-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "dc_12v";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ };
+
+ hdmi-con {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_receiver_pin>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_power: led-0 {
+ gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_POWER;
+ color = <LED_COLOR_ID_RED>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_power_pin>;
+ };
+ led_work: led-1 {
+ gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_HEARTBEAT;
+ color = <LED_COLOR_ID_BLUE>;
+ linux,default-trigger = "heartbeat";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_work_pin>;
+ };
+ };
+
+ rk809-sound {
+ compatible = "simple-audio-card";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_det_pin>;
+ simple-audio-card,name = "Analog RK817";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Headphone", "Headphones",
+ "Speaker", "Speaker";
+ simple-audio-card,routing =
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
+ "Speaker", "SPKO";
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&rk809>;
+ };
+ };
+
+ vcc3v3_pcie: vcc3v3-pcie-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_pcie";
+ enable-active-high;
+ gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc3v3_pcie_en_pin>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <5000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc3v3_sys: vcc3v3-sys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_sys: vcc5v0-sys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_usb_host: vcc5v0-usb-host-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_usb_host";
+ enable-active-high;
+ gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb_host_en_pin>;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcc5v0_usb_otg: vcc5v0-usb-otg-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_usb_otg";
+ enable-active-high;
+ gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb_otg_en_pin>;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+};
+
+&combphy0 {
+ /* Used for USB3 */
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&combphy1 {
+ /* Used for USB3 */
+ phy-supply = <&vcc5v0_usb_otg>;
+ status = "okay";
+};
+
+&combphy2 {
+ /* used for SATA */
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu1 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu2 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu3 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&gmac0 {
+ assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
+ assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>;
+ assigned-clock-rates = <0>, <125000000>;
+ clock_in_out = "output";
+ phy-handle = <&rgmii_phy0>;
+ phy-mode = "rgmii";
+ phy-supply = <&vcc3v3_sys>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac0_miim
+ &gmac0_tx_bus2
+ &gmac0_rx_bus2
+ &gmac0_rgmii_clk
+ &gmac0_rgmii_bus>;
+ status = "okay";
+
+ tx_delay = <0x4f>;
+ rx_delay = <0x2d>;
+};
+
+&gpu {
+ mali-supply = <&vdd_gpu>;
+ status = "okay";
+};
+
+&hdmi {
+ avdd-0v9-supply = <&vdda0v9_image>;
+ avdd-1v8-supply = <&vcca1v8_image>;
+ status = "okay";
+};
+
+&hdmi_in {
+ hdmi_in_vp0: endpoint {
+ remote-endpoint = <&vp0_out_hdmi>;
+ };
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&hdmi_sound {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ vdd_cpu: regulator@1c {
+ compatible = "tcs,tcs4525";
+ reg = <0x1c>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-name = "vdd_cpu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-ramp-delay = <2300>;
+ vin-supply = <&vcc3v3_sys>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ rk809: pmic@20 {
+ compatible = "rockchip,rk809";
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_LOW>;
+ assigned-clocks = <&cru I2S1_MCLKOUT_TX>;
+ assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>;
+ #clock-cells = <1>;
+ clock-names = "mclk";
+ clocks = <&cru I2S1_MCLKOUT_TX>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l>, <&i2s1m0_mclk>;
+ rockchip,system-power-controller;
+ #sound-dai-cells = <0>;
+ vcc1-supply = <&vcc3v3_sys>;
+ vcc2-supply = <&vcc3v3_sys>;
+ vcc3-supply = <&vcc3v3_sys>;
+ vcc4-supply = <&vcc3v3_sys>;
+ vcc5-supply = <&vcc3v3_sys>;
+ vcc6-supply = <&vcc3v3_sys>;
+ vcc7-supply = <&vcc3v3_sys>;
+ vcc8-supply = <&vcc3v3_sys>;
+ vcc9-supply = <&vcc3v3_sys>;
+ wakeup-source;
+
+ regulators {
+ vdd_logic: DCDC_REG1 {
+ regulator-name = "vdd_logic";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-init-microvolt = <900000>;
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: DCDC_REG2 {
+ regulator-name = "vdd_gpu";
+ regulator-always-on;
+ regulator-init-microvolt = <900000>;
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-name = "vcc_ddr";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-initial-mode = <0x2>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vdd_npu: DCDC_REG4 {
+ regulator-name = "vdd_npu";
+ regulator-init-microvolt = <900000>;
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_1v8: DCDC_REG5 {
+ regulator-name = "vcc_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda0v9_image: LDO_REG1 {
+ regulator-name = "vdda0v9_image";
+ regulator-always-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda_0v9: LDO_REG2 {
+ regulator-name = "vdda_0v9";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda0v9_pmu: LDO_REG3 {
+ regulator-name = "vdda0v9_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <900000>;
+ };
+ };
+
+ vccio_acodec: LDO_REG4 {
+ regulator-name = "vccio_acodec";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc3v3_pmu: LDO_REG6 {
+ regulator-name = "vcc3v3_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcca_1v8: LDO_REG7 {
+ regulator-name = "vcca_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcca1v8_pmu: LDO_REG8 {
+ regulator-name = "vcca1v8_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcca1v8_image: LDO_REG9 {
+ regulator-name = "vcca1v8_image";
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_3v3: SWITCH_REG1 {
+ regulator-name = "vcc_3v3";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc3v3_sd: SWITCH_REG2 {
+ regulator-name = "vcc3v3_sd";
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&i2s0_8ch {
+ status = "okay";
+};
+
+&i2s1_8ch {
+ rockchip,trcm-sync-tx-only;
+ status = "okay";
+};
+
+&mdio0 {
+ rgmii_phy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0x0>;
+ reset-assert-us = <20000>;
+ reset-deassert-us = <100000>;
+ reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&pcie30phy {
+ status = "okay";
+};
+
+&pcie3x2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_reset_pin>;
+ reset-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_HIGH>;
+ vpcie3v3-supply = <&vcc3v3_pcie>;
+ status = "okay";
+};
+
+&pinctrl {
+ fspi {
+ fspi_dual_io_pins: fspi-dual-io-pins {
+ rockchip,pins =
+ /* fspi_clk */
+ <1 RK_PD0 1 &pcfg_pull_none>,
+ /* fspi_cs0n */
+ <1 RK_PD3 1 &pcfg_pull_none>,
+ /* fspi_d0 */
+ <1 RK_PD1 1 &pcfg_pull_none>,
+ /* fspi_d1 */
+ <1 RK_PD2 1 &pcfg_pull_none>;
+ };
+ };
+
+ ir-receiver {
+ ir_receiver_pin: ir-receiver-pin {
+ /* external pullup to VCC3V3_SYS */
+ rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ leds {
+ led_power_pin: led-power-pin {
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ led_work_pin: led-work-pin {
+ rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pcie {
+ pcie_reset_pin: pcie-reset-pin {
+ rockchip,pins = <2 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ vcc3v3_pcie_en_pin: vcc3v3-pcie-en-pin {
+ rockchip,pins = <4 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ pmic_int_l: pmic-int-l {
+ rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ rk809 {
+ hp_det_pin: hp-det-pin {
+ rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb {
+ vcc5v0_usb_host_en_pin: vcc5v0-usb-host-en-pin {
+ rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ vcc5v0_usb_otg_en_pin: vcc5v0-usb-dr-en-pin {
+ rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pmu_io_domains {
+ pmuio1-supply = <&vcc3v3_pmu>;
+ pmuio2-supply = <&vcc3v3_pmu>;
+ vccio1-supply = <&vccio_acodec>;
+ vccio2-supply = <&vcc_1v8>;
+ vccio3-supply = <&vccio_sd>;
+ vccio4-supply = <&vcc_1v8>;
+ vccio5-supply = <&vcc_3v3>;
+ vccio6-supply = <&vcc_3v3>;
+ vccio7-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
+&saradc {
+ vref-supply = <&vcca_1v8>;
+ status = "okay";
+};
+
+&sata2 {
+ status = "okay";
+};
+
+&sdhci {
+ bus-width = <8>;
+ max-frequency = <200000000>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe &emmc_rstnout>;
+ vmmc-supply = <&vcc_3v3>;
+ vqmmc-supply = <&vcc_1v8>;
+ status = "okay";
+};
+
+&sdmmc0 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
+ sd-uhs-sdr50;
+ vmmc-supply = <&vcc3v3_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&sfc {
+ /* Dual I/O mode as the D2 pin conflicts with the eMMC */
+ pinctrl-0 = <&fspi_dual_io_pins>;
+ pinctrl-names = "default";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <100000000>;
+ spi-rx-bus-width = <2>;
+ spi-tx-bus-width = <1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "SPL";
+ reg = <0x0 0xe0000>;
+ };
+ partition@e0000 {
+ label = "U-Boot Env";
+ reg = <0xe0000 0x20000>;
+ };
+ partition@100000 {
+ label = "U-Boot";
+ reg = <0x100000 0x200000>;
+ };
+ partition@300000 {
+ label = "splash";
+ reg = <0x300000 0x100000>;
+ };
+ partition@400000 {
+ label = "Filesystem";
+ reg = <0x400000 0xc00000>;
+ };
+ };
+ };
+};
+
+&tsadc {
+ rockchip,hw-tshut-mode = <1>;
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host0_xhci {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&usb_host1_xhci {
+ status = "okay";
+};
+
+&usb2phy0 {
+ status = "okay";
+};
+
+&usb2phy0_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy0_otg {
+ phy-supply = <&vcc5v0_usb_otg>;
+ status = "okay";
+};
+
+&usb2phy1 {
+ status = "okay";
+};
+
+&usb2phy1_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy1_otg {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&vop {
+ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+ assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+ status = "okay";
+};
+
+&vop_mmu {
+ status = "okay";
+};
+
+&vp0 {
+ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
+ reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+ remote-endpoint = <&hdmi_in_vp0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
index fb87a168fe96..a1c5fdf7d68f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
@@ -32,6 +32,13 @@
};
};
+ gmac1_clkin: external-gmac1-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "gmac1_clkin";
+ #clock-cells = <0>;
+ };
+
leds {
compatible = "gpio-leds";
@@ -60,13 +67,55 @@
};
};
- vcc12v_dcin: vcc12v-dcin {
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk809 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable>;
+ post-power-on-delay-ms = <100>;
+ power-off-delay-us = <5000000>;
+ reset-gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>;
+ };
+
+ vcc12v_dcin: vcc12v-dcin-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc12v_dcin";
regulator-always-on;
regulator-boot-on;
};
+ pcie30_avdd0v9: pcie30-avdd0v9-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie30_avdd0v9";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ pcie30_avdd1v8: pcie30-avdd1v8-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie30_avdd1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ /* pi6c pcie clock generator */
+ vcc3v3_pi6c_03: vcc3v3-pi6c-03-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_pi6c_03";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
vcc3v3_pcie: vcc3v3-pcie-regulator {
compatible = "regulator-fixed";
enable-active-high;
@@ -79,7 +128,7 @@
vin-supply = <&vcc5v0_sys>;
};
- vcc3v3_sys: vcc3v3-sys {
+ vcc3v3_sys: vcc3v3-sys-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc3v3_sys";
regulator-always-on;
@@ -89,7 +138,7 @@
vin-supply = <&vcc12v_dcin>;
};
- vcc5v0_sys: vcc5v0-sys {
+ vcc5v0_sys: vcc5v0-sys-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_sys";
regulator-always-on;
@@ -99,7 +148,7 @@
vin-supply = <&vcc12v_dcin>;
};
- vcc5v0_usb: vcc5v0-usb {
+ vcc5v0_usb: vcc5v0-usb-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_usb";
regulator-always-on;
@@ -109,7 +158,7 @@
vin-supply = <&vcc12v_dcin>;
};
- vcc5v0_usb_host: vcc5v0-usb-host {
+ vcc5v0_usb_host: vcc5v0-usb-host-regulator {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
@@ -144,7 +193,7 @@
vin-supply = <&vcc5v0_usb>;
};
- vcc_cam: vcc-cam {
+ vcc_cam: vcc-cam-regulator {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;
@@ -160,7 +209,7 @@
};
};
- vcc_mipi: vcc-mipi {
+ vcc_mipi: vcc-mipi-regulator {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>;
@@ -207,16 +256,17 @@
&gmac1 {
assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>;
- assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>;
- assigned-clock-rates = <0>, <125000000>;
- clock_in_out = "output";
+ assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&gmac1_clkin>;
+ clock_in_out = "input";
phy-handle = <&rgmii_phy1>;
phy-mode = "rgmii-id";
+ phy-supply = <&vcc_3v3>;
pinctrl-names = "default";
pinctrl-0 = <&gmac1m1_miim
&gmac1m1_tx_bus2
&gmac1m1_rx_bus2
&gmac1m1_rgmii_clk
+ &gmac1m1_clkinout
&gmac1m1_rgmii_bus>;
status = "okay";
};
@@ -509,7 +559,6 @@
interrupt-parent = <&gpio0>;
interrupts = <RK_PD3 IRQ_TYPE_LEVEL_LOW>;
#clock-cells = <0>;
- clock-frequency = <32768>;
clock-output-names = "rtcic_32kout";
pinctrl-names = "default";
pinctrl-0 = <&hym8563_int>;
@@ -526,6 +575,11 @@
status = "okay";
};
+&i2s2_2ch {
+ rockchip,trcm-sync-tx-only;
+ status = "okay";
+};
+
&mdio1 {
rgmii_phy1: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
@@ -546,6 +600,19 @@
status = "okay";
};
+&pcie30phy {
+ phy-supply = <&vcc3v3_pi6c_03>;
+ status = "okay";
+};
+
+&pcie3x2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie30x2m1_pins>;
+ reset-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_HIGH>;
+ vpcie3v3-supply = <&vcc3v3_pcie>;
+ status = "okay";
+};
+
&pinctrl {
cam {
vcc_cam_en: vcc_cam_en {
@@ -605,6 +672,26 @@
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
+
+ bt {
+ bt_enable: bt-enable {
+ rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_host_wake: bt-host-wake {
+ rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ bt_wake: bt-wake {
+ rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdio-pwrseq {
+ wifi_enable: wifi-enable {
+ rockchip,pins = <3 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
};
&pmu_io_domains {
@@ -649,12 +736,50 @@
status = "okay";
};
+&sdmmc2 {
+ supports-sdio;
+ bus-width = <4>;
+ disable-wp;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2m0_bus4 &sdmmc2m0_cmd &sdmmc2m0_clk>;
+ sd-uhs-sdr104;
+ vmmc-supply = <&vcc3v3_sys>;
+ vqmmc-supply = <&vcc_1v8>;
+ status = "okay";
+};
+
&tsadc {
rockchip,hw-tshut-mode = <1>;
rockchip,hw-tshut-polarity = <0>;
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn &uart1m0_rtsn>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rk809 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake &bt_wake &bt_enable>;
+ vbat-supply = <&vcc3v3_sys>;
+ vddio-supply = <&vcc_1v8>;
+ /* vddio comes from regulator on module, use IO bank voltage instead */
+ };
+};
+
&uart2 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 164708f1eb67..5706c3e24f0a 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -1049,20 +1049,6 @@
status = "disabled";
};
- spdif: spdif@fe460000 {
- compatible = "rockchip,rk3568-spdif";
- reg = <0x0 0xfe460000 0x0 0x1000>;
- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
- clock-names = "mclk", "hclk";
- clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>;
- dmas = <&dmac1 1>;
- dma-names = "tx";
- pinctrl-names = "default";
- pinctrl-0 = <&spdifm0_tx>;
- #sound-dai-cells = <0>;
- status = "disabled";
- };
-
i2s0_8ch: i2s@fe400000 {
compatible = "rockchip,rk3568-i2s-tdm";
reg = <0x0 0xfe400000 0x0 0x1000>;
@@ -1105,6 +1091,28 @@
status = "disabled";
};
+ i2s2_2ch: i2s@fe420000 {
+ compatible = "rockchip,rk3568-i2s-tdm";
+ reg = <0x0 0xfe420000 0x0 0x1000>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ assigned-clocks = <&cru CLK_I2S2_2CH_SRC>;
+ assigned-clock-rates = <1188000000>;
+ clocks = <&cru MCLK_I2S2_2CH>, <&cru MCLK_I2S2_2CH>, <&cru HCLK_I2S2_2CH>;
+ clock-names = "mclk_tx", "mclk_rx", "hclk";
+ dmas = <&dmac1 4>, <&dmac1 5>;
+ dma-names = "tx", "rx";
+ resets = <&cru SRST_M_I2S2_2CH>;
+ reset-names = "m";
+ rockchip,grf = <&grf>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s2m0_sclktx
+ &i2s2m0_lrcktx
+ &i2s2m0_sdi
+ &i2s2m0_sdo>;
+ #sound-dai-cells = <0>;
+ status = "disabled";
+ };
+
i2s3_2ch: i2s@fe430000 {
compatible = "rockchip,rk3568-i2s-tdm";
reg = <0x0 0xfe430000 0x0 0x1000>;
@@ -1142,6 +1150,20 @@
status = "disabled";
};
+ spdif: spdif@fe460000 {
+ compatible = "rockchip,rk3568-spdif";
+ reg = <0x0 0xfe460000 0x0 0x1000>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "mclk", "hclk";
+ clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>;
+ dmas = <&dmac1 1>;
+ dma-names = "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdifm0_tx>;
+ #sound-dai-cells = <0>;
+ status = "disabled";
+ };
+
dmac0: dma-controller@fe530000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xfe530000 0x0 0x4000>;
diff --git a/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi b/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
index d0abb9aa0e9e..e3852c946352 100644
--- a/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
@@ -55,14 +55,14 @@
samsung,pins = "gpf5-0";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_NONE>;
- samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
ufs_refclk_out: ufs-refclk-out-pins {
samsung,pins = "gpf5-1";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_NONE>;
- samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
};
@@ -239,105 +239,105 @@
samsung,pins = "gpb6-1";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
pwm1_out: pwm1-out-pins {
samsung,pins = "gpb6-5";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c0_bus: hs-i2c0-bus-pins {
samsung,pins = "gpb0-0", "gpb0-1";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c1_bus: hs-i2c1-bus-pins {
samsung,pins = "gpb0-2", "gpb0-3";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c2_bus: hs-i2c2-bus-pins {
samsung,pins = "gpb0-4", "gpb0-5";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c3_bus: hs-i2c3-bus-pins {
samsung,pins = "gpb0-6", "gpb0-7";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c4_bus: hs-i2c4-bus-pins {
samsung,pins = "gpb1-0", "gpb1-1";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c5_bus: hs-i2c5-bus-pins {
samsung,pins = "gpb1-2", "gpb1-3";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c6_bus: hs-i2c6-bus-pins {
samsung,pins = "gpb1-4", "gpb1-5";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
hs_i2c7_bus: hs-i2c7-bus-pins {
samsung,pins = "gpb1-6", "gpb1-7";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
uart0_data: uart0-data-pins {
samsung,pins = "gpb7-0", "gpb7-1";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_NONE>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
uart1_data: uart1-data-pins {
samsung,pins = "gpb7-4", "gpb7-5";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_NONE>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
spi0_bus: spi0-bus-pins {
samsung,pins = "gpb4-0", "gpb4-2", "gpb4-3";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
spi1_bus: spi1-bus-pins {
samsung,pins = "gpb4-4", "gpb4-6", "gpb4-7";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
spi2_bus: spi2-bus-pins {
samsung,pins = "gpb5-0", "gpb5-2", "gpb5-3";
samsung,pin-function = <FSD_PIN_FUNC_2>;
samsung,pin-pud = <FSD_PIN_PULL_UP>;
- samsung,pin-drv = <FSD_PIN_DRV_LV1>;
+ samsung,pin-drv = <FSD_PIN_DRV_LV4>;
};
};
diff --git a/arch/arm64/boot/dts/tesla/fsd-pinctrl.h b/arch/arm64/boot/dts/tesla/fsd-pinctrl.h
index 6ffbda362493..c397d02208a0 100644
--- a/arch/arm64/boot/dts/tesla/fsd-pinctrl.h
+++ b/arch/arm64/boot/dts/tesla/fsd-pinctrl.h
@@ -16,9 +16,9 @@
#define FSD_PIN_PULL_UP 3
#define FSD_PIN_DRV_LV1 0
-#define FSD_PIN_DRV_LV2 2
-#define FSD_PIN_DRV_LV3 1
-#define FSD_PIN_DRV_LV4 3
+#define FSD_PIN_DRV_LV2 1
+#define FSD_PIN_DRV_LV4 2
+#define FSD_PIN_DRV_LV6 3
#define FSD_PIN_FUNC_INPUT 0
#define FSD_PIN_FUNC_OUTPUT 1
diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 4555a5be2257..cf7c509538a4 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic-pg2.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-pg2.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-beagleboneai64.dtb
dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board.dtb
dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb
diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
index 03660476364f..072903649d6e 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
@@ -192,6 +192,102 @@
pinctrl-single,function-mask = <0xffffffff>;
};
+ main_timer0: timer@2400000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2400000 0x00 0x400>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 36 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 36 2>;
+ assigned-clock-parents = <&k3_clks 36 3>;
+ power-domains = <&k3_pds 36 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer1: timer@2410000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2410000 0x00 0x400>;
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 37 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 37 2>;
+ assigned-clock-parents = <&k3_clks 37 3>;
+ power-domains = <&k3_pds 37 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer2: timer@2420000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2420000 0x00 0x400>;
+ interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 38 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 38 2>;
+ assigned-clock-parents = <&k3_clks 38 3>;
+ power-domains = <&k3_pds 38 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer3: timer@2430000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2430000 0x00 0x400>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 39 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 39 2>;
+ assigned-clock-parents = <&k3_clks 39 3>;
+ power-domains = <&k3_pds 39 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer4: timer@2440000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2440000 0x00 0x400>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 40 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 40 2>;
+ assigned-clock-parents = <&k3_clks 40 3>;
+ power-domains = <&k3_pds 40 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer5: timer@2450000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2450000 0x00 0x400>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 41 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 41 2>;
+ assigned-clock-parents = <&k3_clks 41 3>;
+ power-domains = <&k3_pds 41 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer6: timer@2460000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2460000 0x00 0x400>;
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 42 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 42 2>;
+ assigned-clock-parents = <&k3_clks 42 3>;
+ power-domains = <&k3_pds 42 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer7: timer@2470000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2470000 0x00 0x400>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 43 2>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 43 2>;
+ assigned-clock-parents = <&k3_clks 43 3>;
+ power-domains = <&k3_pds 43 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
main_uart0: serial@2800000 {
compatible = "ti,am64-uart", "ti,am654-uart";
reg = <0x00 0x02800000 0x00 0x100>;
@@ -199,6 +295,7 @@
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 146 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -208,6 +305,7 @@
power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 152 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -217,6 +315,7 @@
power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 153 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart3: serial@2830000 {
@@ -226,6 +325,7 @@
power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 154 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart4: serial@2840000 {
@@ -235,6 +335,7 @@
power-domains = <&k3_pds 155 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 155 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart5: serial@2850000 {
@@ -244,6 +345,7 @@
power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 156 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart6: serial@2860000 {
@@ -253,6 +355,7 @@
power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 158 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_i2c0: i2c@20000000 {
@@ -264,6 +367,7 @@
power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 102 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c1: i2c@20010000 {
@@ -275,6 +379,7 @@
power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 103 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c2: i2c@20020000 {
@@ -286,6 +391,7 @@
power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 104 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c3: i2c@20030000 {
@@ -297,6 +403,7 @@
power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 105 2>;
clock-names = "fck";
+ status = "disabled";
};
main_spi0: spi@20100000 {
@@ -307,6 +414,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 172 0>;
+ status = "disabled";
};
main_spi1: spi@20110000 {
@@ -317,6 +425,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 173 0>;
+ status = "disabled";
};
main_spi2: spi@20120000 {
@@ -327,6 +436,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 174 0>;
+ status = "disabled";
};
main_gpio_intr: interrupt-controller@a00000 {
@@ -393,6 +503,7 @@
ti,otap-del-sel-mmc-hs = <0x0>;
ti,otap-del-sel-ddr52 = <0x9>;
ti,otap-del-sel-hs200 = <0x6>;
+ status = "disabled";
};
sdhci1: mmc@fa00000 {
@@ -416,6 +527,7 @@
ti,itap-del-sel-sdr25 = <0x0>;
ti,clkbuf-sel = <0x7>;
bus-width = <4>;
+ status = "disabled";
};
sdhci2: mmc@fa20000 {
@@ -438,6 +550,7 @@
ti,itap-del-sel-sdr12 = <0x0>;
ti,itap-del-sel-sdr25 = <0x0>;
ti,clkbuf-sel = <0x7>;
+ status = "disabled";
};
fss: bus@fc00000 {
@@ -462,6 +575,7 @@
power-domains = <&k3_pds 75 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
};
@@ -520,6 +634,7 @@
clocks = <&k3_clks 13 0>;
clock-names = "fck";
bus_freq = <1000000>;
+ status = "disabled";
};
cpts@3d000 {
@@ -557,6 +672,7 @@
power-domains = <&k3_pds 51 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 51 0>;
clock-names = "fck";
+ status = "disabled";
};
ecap1: pwm@23110000 {
@@ -566,6 +682,7 @@
power-domains = <&k3_pds 52 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 52 0>;
clock-names = "fck";
+ status = "disabled";
};
ecap2: pwm@23120000 {
@@ -575,6 +692,7 @@
power-domains = <&k3_pds 53 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 53 0>;
clock-names = "fck";
+ status = "disabled";
};
main_mcan0: can@20701000 {
@@ -589,6 +707,7 @@
<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
epwm0: pwm@23000000 {
@@ -598,6 +717,7 @@
power-domains = <&k3_pds 86 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 0>, <&k3_clks 86 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm1: pwm@23010000 {
@@ -607,6 +727,7 @@
power-domains = <&k3_pds 87 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 1>, <&k3_clks 87 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm2: pwm@23020000 {
@@ -616,5 +737,6 @@
power-domains = <&k3_pds 88 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 2>, <&k3_clks 88 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi
index f56c803560f2..a427231527c3 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi
@@ -14,6 +14,51 @@
pinctrl-single,function-mask = <0xffffffff>;
};
+ /*
+ * The MCU domain timer interrupts are routed only to the ESM module,
+ * and not currently available for Linux. The MCU domain timers are
+ * of limited use without interrupts, and likely reserved by the ESM.
+ */
+ mcu_timer0: timer@4800000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x4800000 0x00 0x400>;
+ clocks = <&k3_clks 35 2>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer1: timer@4810000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x4810000 0x00 0x400>;
+ clocks = <&k3_clks 48 2>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 48 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer2: timer@4820000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x4820000 0x00 0x400>;
+ clocks = <&k3_clks 49 2>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 49 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer3: timer@4830000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x4830000 0x00 0x400>;
+ clocks = <&k3_clks 50 2>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 50 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
mcu_uart0: serial@4a00000 {
compatible = "ti,am64-uart", "ti,am654-uart";
reg = <0x00 0x04a00000 0x00 0x100>;
@@ -21,6 +66,7 @@
power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 149 0>;
clock-names = "fclk";
+ status = "disabled";
};
mcu_i2c0: i2c@4900000 {
@@ -32,6 +78,7 @@
power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 106 2>;
clock-names = "fck";
+ status = "disabled";
};
mcu_spi0: spi@4b00000 {
@@ -42,6 +89,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 147 0>;
+ status = "disabled";
};
mcu_spi1: spi@4b10000 {
@@ -52,6 +100,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 148 0>;
+ status = "disabled";
};
mcu_gpio_intr: interrupt-controller@4210000 {
diff --git a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi
index 4090134676cf..38dced6b4fef 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi
@@ -26,16 +26,18 @@
power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 114 0>;
clock-names = "fclk";
+ status = "disabled";
};
wkup_i2c0: i2c@2b200000 {
compatible = "ti,am64-i2c", "ti,omap4-i2c";
- reg = <0x00 0x02b200000 0x00 0x100>;
+ reg = <0x00 0x2b200000 0x00 0x100>;
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 107 4>;
clock-names = "fck";
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-am625-sk.dts b/arch/arm64/boot/dts/ti/k3-am625-sk.dts
index 93a5f0817efc..4f179b146cab 100644
--- a/arch/arm64/boot/dts/ti/k3-am625-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am625-sk.dts
@@ -31,6 +31,15 @@
bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000";
};
+ opp-table {
+ /* Add 1.4GHz OPP for am625-sk board. Requires VDD_CORE to be at 0.85V */
+ opp-1400000000 {
+ opp-hz = /bits/ 64 <1400000000>;
+ opp-supported-hw = <0x01 0x0004>;
+ clock-latency-ns = <6000000>;
+ };
+ };
+
memory@80000000 {
device_type = "memory";
/* 2G RAM */
@@ -282,11 +291,8 @@
status = "reserved";
};
-&mcu_uart0 {
- status = "disabled";
-};
-
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
};
@@ -296,41 +302,15 @@
status = "reserved";
};
-&main_uart2 {
- status = "disabled";
-};
-
-&main_uart3 {
- status = "disabled";
-};
-
-&main_uart4 {
- status = "disabled";
-};
-
-&main_uart5 {
- status = "disabled";
-};
-
-&main_uart6 {
- status = "disabled";
-};
-
-&mcu_i2c0 {
- status = "disabled";
-};
-
-&wkup_i2c0 {
- status = "disabled";
-};
-
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
};
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
@@ -363,15 +343,8 @@
};
};
-&main_i2c2 {
- status = "disabled";
-};
-
-&main_i2c3 {
- status = "disabled";
-};
-
&sdhci0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_mmc0_pins_default>;
ti,driver-strength-ohm = <50>;
@@ -380,6 +353,7 @@
&sdhci1 {
/* SD/MMC */
+ status = "okay";
vmmc-supply = <&vdd_mmc1>;
vqmmc-supply = <&vdd_sd_dv>;
pinctrl-names = "default";
@@ -390,8 +364,7 @@
&cpsw3g {
pinctrl-names = "default";
- pinctrl-0 = <&main_mdio1_pins_default
- &main_rgmii1_pins_default
+ pinctrl-0 = <&main_rgmii1_pins_default
&main_rgmii2_pins_default>;
};
@@ -406,6 +379,10 @@
};
&cpsw3g_mdio {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_mdio1_pins_default>;
+
cpsw3g_phy0: ethernet-phy@0 {
reg = <0>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
@@ -429,6 +406,7 @@
};
&ospi0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&ospi0_pins_default>;
@@ -486,31 +464,3 @@
};
};
};
-
-&ecap0 {
- status = "disabled";
-};
-
-&ecap1 {
- status = "disabled";
-};
-
-&ecap2 {
- status = "disabled";
-};
-
-&main_mcan0 {
- status = "disabled";
-};
-
-&epwm0 {
- status = "disabled";
-};
-
-&epwm1 {
- status = "disabled";
-};
-
-&epwm2 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am625.dtsi b/arch/arm64/boot/dts/ti/k3-am625.dtsi
index 887f31c23fef..cea2cc7de5dd 100644
--- a/arch/arm64/boot/dts/ti/k3-am625.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am625.dtsi
@@ -48,6 +48,8 @@
d-cache-line-size = <64>;
d-cache-sets = <128>;
next-level-cache = <&L2_0>;
+ operating-points-v2 = <&a53_opp_table>;
+ clocks = <&k3_clks 135 0>;
};
cpu1: cpu@1 {
@@ -62,6 +64,8 @@
d-cache-line-size = <64>;
d-cache-sets = <128>;
next-level-cache = <&L2_0>;
+ operating-points-v2 = <&a53_opp_table>;
+ clocks = <&k3_clks 136 0>;
};
cpu2: cpu@2 {
@@ -76,6 +80,8 @@
d-cache-line-size = <64>;
d-cache-sets = <128>;
next-level-cache = <&L2_0>;
+ operating-points-v2 = <&a53_opp_table>;
+ clocks = <&k3_clks 137 0>;
};
cpu3: cpu@3 {
@@ -90,6 +96,51 @@
d-cache-line-size = <64>;
d-cache-sets = <128>;
next-level-cache = <&L2_0>;
+ operating-points-v2 = <&a53_opp_table>;
+ clocks = <&k3_clks 138 0>;
+ };
+ };
+
+ a53_opp_table: opp-table {
+ compatible = "operating-points-v2-ti-cpu";
+ opp-shared;
+ syscon = <&wkup_conf>;
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ opp-supported-hw = <0x01 0x0007>;
+ clock-latency-ns = <6000000>;
+ };
+
+ opp-400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-supported-hw = <0x01 0x0007>;
+ clock-latency-ns = <6000000>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-supported-hw = <0x01 0x0007>;
+ clock-latency-ns = <6000000>;
+ };
+
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-supported-hw = <0x01 0x0007>;
+ clock-latency-ns = <6000000>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-supported-hw = <0x01 0x0006>;
+ clock-latency-ns = <6000000>;
+ };
+
+ opp-1250000000 {
+ opp-hz = /bits/ 64 <1250000000>;
+ opp-supported-hw = <0x01 0x0004>;
+ clock-latency-ns = <6000000>;
+ opp-suspend;
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi
index 99afac40e8d4..81d984414fd4 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi
@@ -31,7 +31,7 @@
wkup_i2c0: i2c@2b200000 {
compatible = "ti,am64-i2c", "ti,omap4-i2c";
- reg = <0x00 0x02b200000 0x00 0x100>;
+ reg = <0x00 0x2b200000 0x00 0x100>;
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
index d6aa23681bbe..5e8036f32d79 100644
--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
@@ -237,6 +237,7 @@
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 146 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -248,6 +249,7 @@
power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 152 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -259,6 +261,7 @@
power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 153 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart3: serial@2830000 {
@@ -270,6 +273,7 @@
power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 154 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart4: serial@2840000 {
@@ -281,6 +285,7 @@
power-domains = <&k3_pds 155 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 155 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart5: serial@2850000 {
@@ -292,6 +297,7 @@
power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 156 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart6: serial@2860000 {
@@ -303,6 +309,7 @@
power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 158 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_i2c0: i2c@20000000 {
@@ -314,6 +321,7 @@
power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 102 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c1: i2c@20010000 {
@@ -325,6 +333,7 @@
power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 103 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c2: i2c@20020000 {
@@ -336,6 +345,7 @@
power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 104 2>;
clock-names = "fck";
+ status = "disabled";
};
main_i2c3: i2c@20030000 {
@@ -347,6 +357,7 @@
power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 105 2>;
clock-names = "fck";
+ status = "disabled";
};
main_spi0: spi@20100000 {
@@ -359,6 +370,7 @@
clocks = <&k3_clks 141 0>;
dmas = <&main_pktdma 0xc300 0>, <&main_pktdma 0x4300 0>;
dma-names = "tx0", "rx0";
+ status = "disabled";
};
main_spi1: spi@20110000 {
@@ -369,6 +381,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 142 0>;
+ status = "disabled";
};
main_spi2: spi@20120000 {
@@ -379,6 +392,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 143 0>;
+ status = "disabled";
};
main_spi3: spi@20130000 {
@@ -389,6 +403,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 144 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 144 0>;
+ status = "disabled";
};
main_spi4: spi@20140000 {
@@ -399,6 +414,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 145 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 145 0>;
+ status = "disabled";
};
main_gpio_intr: interrupt-controller@a00000 {
@@ -536,6 +552,7 @@
clocks = <&k3_clks 13 0>;
clock-names = "fck";
bus_freq = <1000000>;
+ status = "disabled";
};
cpts@3d000 {
@@ -612,7 +629,7 @@
assigned-clocks = <&k3_clks 0 0>;
assigned-clock-parents = <&k3_clks 0 3>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
adc {
#io-channel-cells = <1>;
@@ -855,6 +872,7 @@
ranges = <0x01000000 0x00 0x68001000 0x00 0x68001000 0x00 0x0010000>,
<0x02000000 0x00 0x68011000 0x00 0x68011000 0x00 0x7fef000>;
dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x00000010 0x0>;
+ status = "disabled";
};
pcie0_ep: pcie-ep@f102000 {
@@ -873,6 +891,7 @@
clocks = <&k3_clks 114 0>;
clock-names = "fck";
max-functions = /bits/ 8 <1>;
+ status = "disabled";
};
epwm0: pwm@23000000 {
@@ -882,6 +901,7 @@
power-domains = <&k3_pds 86 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 0>, <&k3_clks 86 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm1: pwm@23010000 {
@@ -891,6 +911,7 @@
power-domains = <&k3_pds 87 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 1>, <&k3_clks 87 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm2: pwm@23020000 {
@@ -900,6 +921,7 @@
power-domains = <&k3_pds 88 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 2>, <&k3_clks 88 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm3: pwm@23030000 {
@@ -909,6 +931,7 @@
power-domains = <&k3_pds 89 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 3>, <&k3_clks 89 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm4: pwm@23040000 {
@@ -918,6 +941,7 @@
power-domains = <&k3_pds 90 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 4>, <&k3_clks 90 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm5: pwm@23050000 {
@@ -927,6 +951,7 @@
power-domains = <&k3_pds 91 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 5>, <&k3_clks 91 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm6: pwm@23060000 {
@@ -936,6 +961,7 @@
power-domains = <&k3_pds 92 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 6>, <&k3_clks 92 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm7: pwm@23070000 {
@@ -945,6 +971,7 @@
power-domains = <&k3_pds 93 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 7>, <&k3_clks 93 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
epwm8: pwm@23080000 {
@@ -954,6 +981,7 @@
power-domains = <&k3_pds 94 TI_SCI_PD_EXCLUSIVE>;
clocks = <&epwm_tbclk 8>, <&k3_clks 94 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ecap0: pwm@23100000 {
@@ -963,6 +991,7 @@
power-domains = <&k3_pds 51 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 51 0>;
clock-names = "fck";
+ status = "disabled";
};
ecap1: pwm@23110000 {
@@ -972,6 +1001,7 @@
power-domains = <&k3_pds 52 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 52 0>;
clock-names = "fck";
+ status = "disabled";
};
ecap2: pwm@23120000 {
@@ -981,6 +1011,7 @@
power-domains = <&k3_pds 53 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 53 0>;
clock-names = "fck";
+ status = "disabled";
};
main_rti0: watchdog@e000000 {
@@ -1138,6 +1169,7 @@
#address-cells = <1>;
#size-cells = <0>;
bus_freq = <1000000>;
+ status = "disabled";
};
};
@@ -1278,6 +1310,7 @@
clocks = <&k3_clks 82 0>;
clock-names = "fck";
bus_freq = <1000000>;
+ status = "disabled";
};
};
@@ -1293,6 +1326,7 @@
<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan1: can@20711000 {
@@ -1307,6 +1341,7 @@
<GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
crypto: crypto@40900000 {
@@ -1324,7 +1359,6 @@
compatible = "inside-secure,safexcel-eip76";
reg = <0x00 0x40910000 0x00 0x7d>;
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&k3_clks 133 1>;
status = "disabled"; /* Used by OP-TEE */
};
};
@@ -1334,8 +1368,8 @@
power-domains = <&k3_pds 80 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 80 0>;
clock-names = "fck";
- reg = <0x00 0x03b000000 0x00 0x400>,
- <0x00 0x050000000 0x00 0x8000000>;
+ reg = <0x00 0x3b000000 0x00 0x400>,
+ <0x00 0x50000000 0x00 0x8000000>;
reg-names = "cfg", "data";
interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
gpmc,num-cs = <3>;
@@ -1346,6 +1380,7 @@
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
+ status = "disabled";
};
elm0: ecc@25010000 {
@@ -1355,5 +1390,6 @@
power-domains = <&k3_pds 54 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 54 0>;
clock-names = "fck";
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi
index 02d4285acbb8..38ddf0b3b8a0 100644
--- a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi
@@ -14,6 +14,7 @@
power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 149 0>;
clock-names = "fclk";
+ status = "disabled";
};
mcu_uart1: serial@4a10000 {
@@ -24,6 +25,7 @@
power-domains = <&k3_pds 160 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 160 0>;
clock-names = "fclk";
+ status = "disabled";
};
mcu_i2c0: i2c@4900000 {
@@ -35,6 +37,7 @@
power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 106 2>;
clock-names = "fck";
+ status = "disabled";
};
mcu_i2c1: i2c@4910000 {
@@ -46,6 +49,7 @@
power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 107 2>;
clock-names = "fck";
+ status = "disabled";
};
mcu_spi0: spi@4b00000 {
@@ -56,6 +60,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 147 0>;
+ status = "disabled";
};
mcu_spi1: spi@4b10000 {
@@ -66,6 +71,7 @@
#size-cells = <0>;
power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 148 0>;
+ status = "disabled";
};
mcu_gpio_intr: interrupt-controller@4210000 {
diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts
index 5cf913860f80..39feea78a084 100644
--- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts
@@ -325,6 +325,7 @@
};
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
};
@@ -334,35 +335,8 @@
status = "reserved";
};
-&main_uart2 {
- status = "disabled";
-};
-
-&main_uart3 {
- status = "disabled";
-};
-
-&main_uart4 {
- status = "disabled";
-};
-
-&main_uart5 {
- status = "disabled";
-};
-
-&main_uart6 {
- status = "disabled";
-};
-
-&mcu_uart0 {
- status = "disabled";
-};
-
-&mcu_uart1 {
- status = "disabled";
-};
-
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
@@ -405,23 +379,8 @@
status = "reserved";
};
-&mcu_i2c0 {
- status = "disabled";
-};
-
-&mcu_i2c1 {
- status = "disabled";
-};
-
-&mcu_spi0 {
- status = "disabled";
-};
-
-&mcu_spi1 {
- status = "disabled";
-};
-
&main_spi0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_spi0_pins_default>;
ti,pindir-d0-out-d1-in;
@@ -466,8 +425,7 @@
&cpsw3g {
pinctrl-names = "default";
- pinctrl-0 = <&mdio1_pins_default
- &rgmii1_pins_default
+ pinctrl-0 = <&rgmii1_pins_default
&rgmii2_pins_default>;
};
@@ -482,6 +440,10 @@
};
&cpsw3g_mdio {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mdio1_pins_default>;
+
cpsw3g_phy0: ethernet-phy@0 {
reg = <0>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
@@ -594,6 +556,7 @@
};
&pcie0_rc {
+ status = "okay";
reset-gpios = <&exp1 5 GPIO_ACTIVE_HIGH>;
phys = <&serdes0_pcie_link>;
phy-names = "pcie-phy";
@@ -604,83 +567,25 @@
phys = <&serdes0_pcie_link>;
phy-names = "pcie-phy";
num-lanes = <1>;
- status = "disabled";
};
&ecap0 {
+ status = "okay";
/* PWM is available on Pin 1 of header J12 */
pinctrl-names = "default";
pinctrl-0 = <&main_ecap0_pins_default>;
};
-&ecap1 {
- status = "disabled";
-};
-
-&ecap2 {
- status = "disabled";
-};
-
-&epwm0 {
- status = "disabled";
-};
-
-&epwm1 {
- status = "disabled";
-};
-
-&epwm2 {
- status = "disabled";
-};
-
-&epwm3 {
- status = "disabled";
-};
-
-&epwm4 {
- status = "disabled";
-};
-
-&epwm5 {
- status = "disabled";
-};
-
-&epwm6 {
- status = "disabled";
-};
-
-&epwm7 {
- status = "disabled";
-};
-
-&epwm8 {
- status = "disabled";
-};
-
-&icssg0_mdio {
- status = "disabled";
-};
-
-&icssg1_mdio {
- status = "disabled";
-};
-
&main_mcan0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_mcan0_pins_default>;
phys = <&transceiver1>;
};
&main_mcan1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_mcan1_pins_default>;
phys = <&transceiver2>;
};
-
-&gpmc0 {
- status = "disabled";
-};
-
-&elm0 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts
index 738d0cf6c40a..2e2d40da360a 100644
--- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts
@@ -338,15 +338,8 @@
};
};
-&mcu_uart0 {
- status = "disabled";
-};
-
-&mcu_uart1 {
- status = "disabled";
-};
-
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
};
@@ -356,35 +349,8 @@
status = "reserved";
};
-&main_uart2 {
- status = "disabled";
-};
-
-&main_uart3 {
- status = "disabled";
-};
-
-&main_uart4 {
- status = "disabled";
-};
-
-&main_uart5 {
- status = "disabled";
-};
-
-&main_uart6 {
- status = "disabled";
-};
-
-&mcu_i2c0 {
- status = "disabled";
-};
-
-&mcu_i2c1 {
- status = "disabled";
-};
-
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
@@ -409,18 +375,6 @@
};
};
-&main_i2c3 {
- status = "disabled";
-};
-
-&mcu_spi0 {
- status = "disabled";
-};
-
-&mcu_spi1 {
- status = "disabled";
-};
-
/* mcu_gpio0 is reserved for mcu firmware usage */
&mcu_gpio0 {
status = "reserved";
@@ -485,8 +439,7 @@
&cpsw3g {
pinctrl-names = "default";
- pinctrl-0 = <&mdio1_pins_default
- &rgmii1_pins_default
+ pinctrl-0 = <&rgmii1_pins_default
&rgmii2_pins_default>;
};
@@ -501,6 +454,10 @@
};
&cpsw3g_mdio {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mdio1_pins_default>;
+
cpsw3g_phy0: ethernet-phy@0 {
reg = <0>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
@@ -603,92 +560,9 @@
<&main_r5fss1_core1_memory_region>;
};
-&pcie0_rc {
- status = "disabled";
-};
-
-&pcie0_ep {
- status = "disabled";
-};
-
&ecap0 {
+ status = "okay";
/* PWM is available on Pin 1 of header J3 */
pinctrl-names = "default";
pinctrl-0 = <&main_ecap0_pins_default>;
};
-
-&ecap1 {
- status = "disabled";
-};
-
-&ecap2 {
- status = "disabled";
-};
-
-&epwm0 {
- status = "disabled";
-};
-
-&epwm1 {
- status = "disabled";
-};
-
-&epwm2 {
- status = "disabled";
-};
-
-&epwm3 {
- status = "disabled";
-};
-
-&epwm4 {
- /*
- * EPWM4_A, EPWM4_B is available on Pin 32 and 33 on J4 (RPi hat)
- * But RPi Hat will be used for other use cases, so marking epwm4 as disabled.
- */
- status = "disabled";
-};
-
-&epwm5 {
- /*
- * EPWM5_A, EPWM5_B is available on Pin 29 and 31 on J4 (RPi hat)
- * But RPi Hat will be used for other use cases, so marking epwm5 as disabled.
- */
- status = "disabled";
-};
-
-&epwm6 {
- status = "disabled";
-};
-
-&epwm7 {
- status = "disabled";
-};
-
-&epwm8 {
- status = "disabled";
-};
-
-&icssg0_mdio {
- status = "disabled";
-};
-
-&icssg1_mdio {
- status = "disabled";
-};
-
-&main_mcan0 {
- status = "disabled";
-};
-
-&main_mcan1 {
- status = "disabled";
-};
-
-&gpmc0 {
- status = "disabled";
-};
-
-&elm0 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
index 32b797237581..3cced26b520a 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
@@ -360,15 +360,13 @@
};
&main_uart1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart1_pins_default>;
};
-&main_uart2 {
- status = "disabled";
-};
-
&mcu_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&arduino_uart_pins_default>;
};
@@ -413,12 +411,14 @@
};
&wkup_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&wkup_i2c0_pins_default>;
clock-frequency = <400000>;
};
&mcu_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -478,6 +478,7 @@
};
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -495,18 +496,21 @@
};
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
};
&main_i2c2 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c2_pins_default>;
clock-frequency = <400000>;
};
&main_i2c3 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c3_pins_default>;
clock-frequency = <400000>;
@@ -546,6 +550,7 @@
};
&ecap0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&ecap0_pins_default>;
};
@@ -570,6 +575,7 @@
};
&mcu_spi0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_spi0_pins_default>;
@@ -626,15 +632,8 @@
};
};
-&pcie0_rc {
- status = "disabled";
-};
-
-&pcie0_ep {
- status = "disabled";
-};
-
&pcie1_rc {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&minipcie_pins_default>;
@@ -644,19 +643,8 @@
reset-gpios = <&wkup_gpio0 27 GPIO_ACTIVE_HIGH>;
};
-&m_can0 {
- status = "disabled";
-};
-
-&m_can1 {
- status = "disabled";
-};
-
-&pcie1_ep {
- status = "disabled";
-};
-
&mailbox0_cluster0 {
+ status = "okay";
interrupts = <436>;
mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
@@ -666,6 +654,7 @@
};
&mailbox0_cluster1 {
+ status = "okay";
interrupts = <432>;
mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
@@ -674,46 +663,6 @@
};
};
-&mailbox0_cluster2 {
- status = "disabled";
-};
-
-&mailbox0_cluster3 {
- status = "disabled";
-};
-
-&mailbox0_cluster4 {
- status = "disabled";
-};
-
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
&mcu_r5fss0_core0 {
memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
<&mcu_r5fss0_core0_memory_region>;
@@ -725,27 +674,3 @@
<&mcu_r5fss0_core1_memory_region>;
mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>;
};
-
-&icssg0_mdio {
- status = "disabled";
-};
-
-&icssg1_mdio {
- status = "disabled";
-};
-
-&icssg2_mdio {
- status = "disabled";
-};
-
-&mcasp0 {
- status = "disabled";
-};
-
-&mcasp1 {
- status = "disabled";
-};
-
-&mcasp2 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
index 4005a73cfea9..1adba2f2c153 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
@@ -91,6 +91,7 @@
clock-frequency = <48000000>;
current-speed = <115200>;
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -99,6 +100,7 @@
interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <48000000>;
power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -107,6 +109,7 @@
interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <48000000>;
power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
crypto: crypto@4e00000 {
@@ -120,17 +123,33 @@
dmas = <&main_udmap 0xc001>, <&main_udmap 0x4002>,
<&main_udmap 0x4003>;
dma-names = "tx", "rx1", "rx2";
- dma-coherent;
rng: rng@4e10000 {
compatible = "inside-secure,safexcel-eip76";
reg = <0x0 0x4e10000 0x0 0x7d>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&k3_clks 136 1>;
status = "disabled"; /* Used by OP-TEE */
};
};
+ /* TIMERIO pad input CTRLMMR_TIMER*_CTRL registers */
+ main_timerio_input: pinctrl@104200 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x104200 0x0 0x30>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0x0000001ff>;
+ };
+
+ /* TIMERIO pad output CTCTRLMMR_TIMERIO*_CTRL registers */
+ main_timerio_output: pinctrl@104280 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x104280 0x0 0x20>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0x0000000f>;
+ };
+
main_pmx0: pinctrl@11c000 {
compatible = "pinctrl-single";
reg = <0x0 0x11c000 0x0 0x2e4>;
@@ -156,6 +175,7 @@
clock-names = "fck";
clocks = <&k3_clks 110 1>;
power-domains = <&k3_pds 110 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c1: i2c@2010000 {
@@ -167,6 +187,7 @@
clock-names = "fck";
clocks = <&k3_clks 111 1>;
power-domains = <&k3_pds 111 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c2: i2c@2020000 {
@@ -178,6 +199,7 @@
clock-names = "fck";
clocks = <&k3_clks 112 1>;
power-domains = <&k3_pds 112 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c3: i2c@2030000 {
@@ -189,6 +211,7 @@
clock-names = "fck";
clocks = <&k3_clks 113 1>;
power-domains = <&k3_pds 113 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
ecap0: pwm@3100000 {
@@ -198,6 +221,7 @@
power-domains = <&k3_pds 39 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 39 0>;
clock-names = "fck";
+ status = "disabled";
};
main_spi0: spi@2100000 {
@@ -210,6 +234,7 @@
#size-cells = <0>;
dmas = <&main_udmap 0xc500>, <&main_udmap 0x4500>;
dma-names = "tx0", "rx0";
+ status = "disabled";
};
main_spi1: spi@2110000 {
@@ -222,6 +247,7 @@
#size-cells = <0>;
assigned-clocks = <&k3_clks 137 1>;
assigned-clock-rates = <48000000>;
+ status = "disabled";
};
main_spi2: spi@2120000 {
@@ -232,6 +258,7 @@
power-domains = <&k3_pds 139 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
main_spi3: spi@2130000 {
@@ -242,6 +269,7 @@
power-domains = <&k3_pds 140 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
main_spi4: spi@2140000 {
@@ -252,6 +280,151 @@
power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
+ };
+
+ main_timer0: timer@2400000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2400000 0x00 0x400>;
+ interrupts = <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 23 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 23 0>;
+ assigned-clock-parents = <&k3_clks 23 1>;
+ power-domains = <&k3_pds 23 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer1: timer@2410000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2410000 0x00 0x400>;
+ interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 24 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 24 0>;
+ assigned-clock-parents = <&k3_clks 24 1>;
+ power-domains = <&k3_pds 24 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer2: timer@2420000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2420000 0x00 0x400>;
+ interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 27 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 27 0>;
+ assigned-clock-parents = <&k3_clks 27 1>;
+ power-domains = <&k3_pds 27 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer3: timer@2430000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2430000 0x00 0x400>;
+ interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 28 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 28 0>;
+ assigned-clock-parents = <&k3_clks 28 1>;
+ power-domains = <&k3_pds 28 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer4: timer@2440000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2440000 0x00 0x400>;
+ interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 29 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 29 0>;
+ assigned-clock-parents = <&k3_clks 29 1>;
+ power-domains = <&k3_pds 29 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer5: timer@2450000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2450000 0x00 0x400>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 30 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 30 0>;
+ assigned-clock-parents = <&k3_clks 30 1>;
+ power-domains = <&k3_pds 30 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer6: timer@2460000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2460000 0x00 0x400>;
+ interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 31 0>;
+ assigned-clocks = <&k3_clks 31 0>;
+ assigned-clock-parents = <&k3_clks 31 1>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 31 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer7: timer@2470000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2470000 0x00 0x400>;
+ interrupts = <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 32 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 32 0>;
+ assigned-clock-parents = <&k3_clks 32 1>;
+ power-domains = <&k3_pds 32 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer8: timer@2480000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2480000 0x00 0x400>;
+ interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 33 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 33 0>;
+ assigned-clock-parents = <&k3_clks 33 1>;
+ power-domains = <&k3_pds 33 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer9: timer@2490000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x2490000 0x00 0x400>;
+ interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 34 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 34 0>;
+ assigned-clock-parents = <&k3_clks 34 1>;
+ power-domains = <&k3_pds 34 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer10: timer@24a0000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x24a0000 0x00 0x400>;
+ interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 25 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 25 0>;
+ assigned-clock-parents = <&k3_clks 25 1>;
+ power-domains = <&k3_pds 25 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ };
+
+ main_timer11: timer@24b0000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x24b0000 0x00 0x400>;
+ interrupts = <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&k3_clks 26 0>;
+ clock-names = "fck";
+ assigned-clocks = <&k3_clks 26 0>;
+ assigned-clock-parents = <&k3_clks 26 1>;
+ power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
};
sdhci0: mmc@4f80000 {
@@ -342,7 +515,7 @@
dss_oldi_io_ctrl: dss-oldi-io-ctrl@41e0 {
compatible = "syscon";
- reg = <0x0000041e0 0x14>;
+ reg = <0x000041e0 0x14>;
};
ehrpwm_tbclk: clock@4140 {
@@ -501,6 +674,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster1: mailbox@31f81000 {
@@ -510,6 +684,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster2: mailbox@31f82000 {
@@ -519,6 +694,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster3: mailbox@31f83000 {
@@ -528,6 +704,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster4: mailbox@31f84000 {
@@ -537,6 +714,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster5: mailbox@31f85000 {
@@ -546,6 +724,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster6: mailbox@31f86000 {
@@ -555,6 +734,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster7: mailbox@31f87000 {
@@ -564,6 +744,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster8: mailbox@31f88000 {
@@ -573,6 +754,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster9: mailbox@31f89000 {
@@ -582,6 +764,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster10: mailbox@31f8a000 {
@@ -591,6 +774,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
mailbox0_cluster11: mailbox@31f8b000 {
@@ -600,6 +784,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&intr_main_navss>;
+ status = "disabled";
};
ringacc: ringacc@3c000000 {
@@ -707,6 +892,7 @@
interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
msi-map = <0x0 &gic_its 0x0 0x10000>;
device_type = "pci";
+ status = "disabled";
};
pcie0_ep: pcie-ep@5500000 {
@@ -720,6 +906,7 @@
max-link-speed = <2>;
dma-coherent;
interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
};
pcie1_rc: pcie@5600000 {
@@ -740,6 +927,7 @@
interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>;
msi-map = <0x0 &gic_its 0x10000 0x10000>;
device_type = "pci";
+ status = "disabled";
};
pcie1_ep: pcie-ep@5600000 {
@@ -753,6 +941,7 @@
max-link-speed = <2>;
dma-coherent;
interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
};
mcasp0: mcasp@2b00000 {
@@ -770,6 +959,7 @@
clocks = <&k3_clks 104 0>;
clock-names = "fck";
power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp1: mcasp@2b10000 {
@@ -787,6 +977,7 @@
clocks = <&k3_clks 105 0>;
clock-names = "fck";
power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp2: mcasp@2b20000 {
@@ -804,6 +995,7 @@
clocks = <&k3_clks 106 0>;
clock-names = "fck";
power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
cal: cal@6f03000 {
@@ -874,6 +1066,7 @@
power-domains = <&k3_pds 40 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 0>, <&k3_clks 40 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ehrpwm1: pwm@3010000 {
@@ -883,6 +1076,7 @@
power-domains = <&k3_pds 41 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 1>, <&k3_clks 41 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ehrpwm2: pwm@3020000 {
@@ -892,6 +1086,7 @@
power-domains = <&k3_pds 42 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 2>, <&k3_clks 42 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ehrpwm3: pwm@3030000 {
@@ -901,6 +1096,7 @@
power-domains = <&k3_pds 43 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 3>, <&k3_clks 43 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ehrpwm4: pwm@3040000 {
@@ -910,6 +1106,7 @@
power-domains = <&k3_pds 44 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 4>, <&k3_clks 44 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
ehrpwm5: pwm@3050000 {
@@ -919,6 +1116,7 @@
power-domains = <&k3_pds 45 TI_SCI_PD_EXCLUSIVE>;
clocks = <&ehrpwm_tbclk 5>, <&k3_clks 45 0>;
clock-names = "tbclk", "fck";
+ status = "disabled";
};
icssg0: icssg@b000000 {
@@ -1059,6 +1257,7 @@
#address-cells = <1>;
#size-cells = <0>;
bus_freq = <1000000>;
+ status = "disabled";
};
};
@@ -1200,6 +1399,7 @@
#address-cells = <1>;
#size-cells = <0>;
bus_freq = <1000000>;
+ status = "disabled";
};
};
@@ -1341,6 +1541,7 @@
#address-cells = <1>;
#size-cells = <0>;
bus_freq = <1000000>;
+ status = "disabled";
};
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
index 8d592bf41d6f..5dfa31840e9c 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
@@ -20,13 +20,32 @@
};
};
+ /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */
+ mcu_timerio_input: pinctrl@40f04200 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x40f04200 0x0 0x10>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0x00000101>;
+ };
+
+ /* MCU_TIMERIO pad output CTRLMMR_MCU_TIMERIO*_CTRL registers */
+ mcu_timerio_output: pinctrl@40f04280 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x40f04280 0x0 0x8>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0x00000003>;
+ };
+
mcu_uart0: serial@40a00000 {
compatible = "ti,am654-uart";
- reg = <0x00 0x40a00000 0x00 0x100>;
- interrupts = <GIC_SPI 565 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <96000000>;
- current-speed = <115200>;
- power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
+ reg = <0x00 0x40a00000 0x00 0x100>;
+ interrupts = <GIC_SPI 565 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <96000000>;
+ current-speed = <115200>;
+ power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_ram: sram@41c00000 {
@@ -46,6 +65,7 @@
clock-names = "fck";
clocks = <&k3_clks 114 1>;
power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_spi0: spi@40300000 {
@@ -56,6 +76,7 @@
power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
mcu_spi1: spi@40310000 {
@@ -66,6 +87,7 @@
power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
mcu_spi2: spi@40320000 {
@@ -76,6 +98,7 @@
power-domains = <&k3_pds 144 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
tscadc0: tscadc@40200000 {
@@ -85,7 +108,7 @@
clocks = <&k3_clks 0 2>;
assigned-clocks = <&k3_clks 0 2>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
dmas = <&mcu_udmap 0x7100>,
<&mcu_udmap 0x7101 >;
dma-names = "fifo0", "fifo1";
@@ -103,7 +126,7 @@
clocks = <&k3_clks 1 2>;
assigned-clocks = <&k3_clks 1 2>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
dmas = <&mcu_udmap 0x7102>,
<&mcu_udmap 0x7103>;
dma-names = "fifo0", "fifo1";
@@ -114,6 +137,51 @@
};
};
+ /*
+ * The MCU domain timer interrupts are routed only to the ESM module,
+ * and not currently available for Linux. The MCU domain timers are
+ * of limited use without interrupts, and likely reserved by the ESM.
+ */
+ mcu_timer0: timer@40400000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x40400000 0x00 0x400>;
+ clocks = <&k3_clks 35 0>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer1: timer@40410000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x40410000 0x00 0x400>;
+ clocks = <&k3_clks 36 0>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 36 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer2: timer@40420000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x40420000 0x00 0x400>;
+ clocks = <&k3_clks 37 0>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 37 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
+ mcu_timer3: timer@40430000 {
+ compatible = "ti,am654-timer";
+ reg = <0x00 0x40430000 0x00 0x400>;
+ clocks = <&k3_clks 38 0>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 38 TI_SCI_PD_EXCLUSIVE>;
+ ti,timer-pwm;
+ status = "reserved";
+ };
+
mcu_navss: bus@28380000 {
compatible = "simple-mfd";
#address-cells = <2>;
@@ -172,6 +240,7 @@
<GIC_SPI 545 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
m_can1: mcan@40568000 {
@@ -187,6 +256,7 @@
<GIC_SPI 548 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
fss: fss@47000000 {
@@ -273,6 +343,7 @@
clocks = <&k3_clks 5 10>;
clock-names = "fck";
bus_freq = <1000000>;
+ status = "disabled";
};
cpts@3d000 {
diff --git a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
index fa11d7142006..fd2b998ebddc 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
@@ -54,6 +54,7 @@
clock-frequency = <48000000>;
current-speed = <115200>;
power-domains = <&k3_pds 150 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
wkup_i2c0: i2c@42120000 {
@@ -65,6 +66,7 @@
clock-names = "fck";
clocks = <&k3_clks 115 1>;
power-domains = <&k3_pds 115 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
intr_wkup_gpio: interrupt-controller@42200000 {
diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi
index 4a9bf7d7c07d..cd43fd11a5c2 100644
--- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi
@@ -50,6 +50,7 @@
};
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
};
diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
index 5850582dd4ed..592ab2b54cb3 100644
--- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
@@ -271,13 +271,20 @@
status = "reserved";
};
+&mcu_uart0 {
+ status = "okay";
+ /* Default pinmux */
+};
+
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
};
&wkup_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&wkup_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -296,7 +303,13 @@
};
};
+&mcu_i2c0 {
+ status = "okay";
+ /* Default pinmux */
+};
+
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -310,23 +323,27 @@
};
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
};
&main_i2c2 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c2_pins_default>;
clock-frequency = <400000>;
};
&ecap0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&ecap0_pins_default>;
};
&main_spi0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_spi0_pins_default>;
#address-cells = <1>;
@@ -398,31 +415,8 @@
status = "disabled";
};
-&pcie0_rc {
- status = "disabled";
-};
-
-&pcie0_ep {
- status = "disabled";
-};
-
-&pcie1_rc {
- status = "disabled";
-};
-
-&pcie1_ep {
- status = "disabled";
-};
-
-&m_can0 {
- status = "disabled";
-};
-
-&m_can1 {
- status = "disabled";
-};
-
&mailbox0_cluster0 {
+ status = "okay";
interrupts = <436>;
mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
@@ -432,6 +426,7 @@
};
&mailbox0_cluster1 {
+ status = "okay";
interrupts = <432>;
mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
@@ -440,46 +435,6 @@
};
};
-&mailbox0_cluster2 {
- status = "disabled";
-};
-
-&mailbox0_cluster3 {
- status = "disabled";
-};
-
-&mailbox0_cluster4 {
- status = "disabled";
-};
-
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
&mcu_r5fss0_core0 {
memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
<&mcu_r5fss0_core0_memory_region>;
@@ -512,10 +467,14 @@
&mcu_cpsw {
pinctrl-names = "default";
- pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>;
+ pinctrl-0 = <&mcu_cpsw_pins_default>;
};
&davinci_mdio {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcu_mdio_pins_default>;
+
phy0: ethernet-phy@0 {
reg = <0>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
@@ -528,30 +487,6 @@
phy-handle = <&phy0>;
};
-&mcasp0 {
- status = "disabled";
-};
-
-&mcasp1 {
- status = "disabled";
-};
-
-&mcasp2 {
- status = "disabled";
-};
-
&dss {
status = "disabled";
};
-
-&icssg0_mdio {
- status = "disabled";
-};
-
-&icssg1_mdio {
- status = "disabled";
-};
-
-&icssg2_mdio {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi
index d25e8b26187f..0f67e1ec0fb8 100644
--- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi
@@ -50,7 +50,3 @@
ti,driver-strength-ohm = <50>;
disable-wp;
};
-
-&main_uart0 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts
index 7e8552fd2b6a..6240856e4863 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts
@@ -154,51 +154,27 @@
status = "reserved";
};
+&mcu_uart0 {
+ status = "okay";
+ /* Default pinmux */
+};
+
&main_uart0 {
+ status = "okay";
/* Shared with ATF on this platform */
power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
};
+&main_uart1 {
+ status = "okay";
+ /* Default pinmux */
+};
+
&main_uart2 {
/* MAIN UART 2 is used by R5F firmware */
status = "reserved";
};
-&main_uart3 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart4 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart5 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart6 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart7 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart8 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart9 {
- /* UART not brought out */
- status = "disabled";
-};
-
&main_gpio2 {
status = "disabled";
};
@@ -234,6 +210,7 @@
};
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -261,6 +238,7 @@
* The i2c1 of the CPB (as it is labeled) is not connected to j7200.
*/
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
index 80a57916bcb3..138381f43ce4 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
@@ -142,6 +142,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster1: mailbox@31f81000 {
@@ -151,6 +152,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster2: mailbox@31f82000 {
@@ -160,6 +162,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster3: mailbox@31f83000 {
@@ -169,6 +172,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster4: mailbox@31f84000 {
@@ -178,6 +182,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster5: mailbox@31f85000 {
@@ -187,6 +192,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster6: mailbox@31f86000 {
@@ -196,6 +202,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster7: mailbox@31f87000 {
@@ -205,6 +212,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster8: mailbox@31f88000 {
@@ -214,6 +222,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster9: mailbox@31f89000 {
@@ -223,6 +232,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster10: mailbox@31f8a000 {
@@ -232,6 +242,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster11: mailbox@31f8b000 {
@@ -241,6 +252,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
main_ringacc: ringacc@3c000000 {
@@ -319,6 +331,7 @@
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 146 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -330,6 +343,7 @@
power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 278 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -341,6 +355,7 @@
power-domains = <&k3_pds 279 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 279 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart3: serial@2830000 {
@@ -352,6 +367,7 @@
power-domains = <&k3_pds 280 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 280 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart4: serial@2840000 {
@@ -363,6 +379,7 @@
power-domains = <&k3_pds 281 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 281 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart5: serial@2850000 {
@@ -374,6 +391,7 @@
power-domains = <&k3_pds 282 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 282 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart6: serial@2860000 {
@@ -385,6 +403,7 @@
power-domains = <&k3_pds 283 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 283 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart7: serial@2870000 {
@@ -396,6 +415,7 @@
power-domains = <&k3_pds 284 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 284 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart8: serial@2880000 {
@@ -407,6 +427,7 @@
power-domains = <&k3_pds 285 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 285 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart9: serial@2890000 {
@@ -418,6 +439,7 @@
power-domains = <&k3_pds 286 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 286 2>;
clock-names = "fclk";
+ status = "disabled";
};
main_i2c0: i2c@2000000 {
@@ -429,6 +451,7 @@
clock-names = "fck";
clocks = <&k3_clks 187 1>;
power-domains = <&k3_pds 187 TI_SCI_PD_SHARED>;
+ status = "disabled";
};
main_i2c1: i2c@2010000 {
@@ -440,6 +463,7 @@
clock-names = "fck";
clocks = <&k3_clks 188 1>;
power-domains = <&k3_pds 188 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c2: i2c@2020000 {
@@ -451,6 +475,7 @@
clock-names = "fck";
clocks = <&k3_clks 189 1>;
power-domains = <&k3_pds 189 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c3: i2c@2030000 {
@@ -462,6 +487,7 @@
clock-names = "fck";
clocks = <&k3_clks 190 1>;
power-domains = <&k3_pds 190 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c4: i2c@2040000 {
@@ -473,6 +499,7 @@
clock-names = "fck";
clocks = <&k3_clks 191 1>;
power-domains = <&k3_pds 191 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c5: i2c@2050000 {
@@ -484,6 +511,7 @@
clock-names = "fck";
clocks = <&k3_clks 192 1>;
power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c6: i2c@2060000 {
@@ -495,6 +523,7 @@
clock-names = "fck";
clocks = <&k3_clks 193 1>;
power-domains = <&k3_pds 193 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_sdhci0: mmc@4f80000 {
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
index e5be78a58682..fe669deba489 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
@@ -79,6 +79,7 @@
power-domains = <&k3_pds 287 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 287 2>;
clock-names = "fclk";
+ status = "disabled";
};
mcu_uart0: serial@40a00000 {
@@ -90,6 +91,7 @@
power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 149 2>;
clock-names = "fclk";
+ status = "disabled";
};
wkup_gpio_intr: interrupt-controller@42200000 {
@@ -249,6 +251,7 @@
clock-names = "fck";
clocks = <&k3_clks 194 1>;
power-domains = <&k3_pds 194 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_i2c1: i2c@40b10000 {
@@ -260,6 +263,7 @@
clock-names = "fck";
clocks = <&k3_clks 195 1>;
power-domains = <&k3_pds 195 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
wkup_i2c0: i2c@42120000 {
@@ -271,6 +275,7 @@
clock-names = "fck";
clocks = <&k3_clks 197 1>;
power-domains = <&k3_pds 197 TI_SCI_PD_SHARED>;
+ status = "disabled";
};
fss: syscon@47000000 {
@@ -325,7 +330,7 @@
clocks = <&k3_clks 0 1>;
assigned-clocks = <&k3_clks 0 3>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
dmas = <&main_udmap 0x7400>,
<&main_udmap 0x7401>;
dma-names = "fifo0", "fifo1";
@@ -386,7 +391,6 @@
dmas = <&mcu_udmap 0xf501>, <&mcu_udmap 0x7502>,
<&mcu_udmap 0x7503>;
dma-names = "tx", "rx1", "rx2";
- dma-coherent;
rng: rng@40910000 {
compatible = "inside-secure,safexcel-eip76";
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
index 2d615c3e9fa1..fa44ed4c17d5 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
@@ -144,6 +144,7 @@
};
&mailbox0_cluster0 {
+ status = "okay";
interrupts = <436>;
mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
@@ -158,6 +159,7 @@
};
&mailbox0_cluster1 {
+ status = "okay";
interrupts = <432>;
mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
@@ -171,46 +173,6 @@
};
};
-&mailbox0_cluster2 {
- status = "disabled";
-};
-
-&mailbox0_cluster3 {
- status = "disabled";
-};
-
-&mailbox0_cluster4 {
- status = "disabled";
-};
-
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
&mcu_r5fss0_core0 {
mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts
new file mode 100644
index 000000000000..37c24b077b6a
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts
@@ -0,0 +1,1055 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * https://beagleboard.org/ai-64
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022 Jason Kridner, BeagleBoard.org Foundation
+ * Copyright (C) 2022 Robert Nelson, BeagleBoard.org Foundation
+ */
+
+/dts-v1/;
+
+#include "k3-j721e.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/phy/phy-cadence.h>
+
+/ {
+ compatible = "beagle,j721e-beagleboneai64", "ti,j721e";
+ model = "BeagleBoard.org BeagleBone AI-64";
+
+ aliases {
+ serial2 = &main_uart0;
+ mmc0 = &main_sdhci0;
+ mmc1 = &main_sdhci1;
+ i2c0 = &wkup_i2c0;
+ i2c1 = &main_i2c6;
+ i2c2 = &main_i2c2;
+ i2c3 = &main_i2c4;
+ };
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* 4G RAM */
+ reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
+ <0x00000008 0x80000000 0x00000000 0x80000000>;
+ };
+
+ reserved_memory: reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ secure_ddr: optee@9e800000 {
+ reg = <0x00 0x9e800000 0x00 0x01800000>;
+ no-map;
+ };
+
+ mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa0000000 0x00 0x100000>;
+ no-map;
+ };
+
+ mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa0100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa1000000 0x00 0x100000>;
+ no-map;
+ };
+
+ mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa1100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa2000000 0x00 0x100000>;
+ no-map;
+ };
+
+ main_r5fss0_core0_memory_region: r5f-memory@a2100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa2100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa3000000 0x00 0x100000>;
+ no-map;
+ };
+
+ main_r5fss0_core1_memory_region: r5f-memory@a3100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa3100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa4000000 0x00 0x100000>;
+ no-map;
+ };
+
+ main_r5fss1_core0_memory_region: r5f-memory@a4100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa4100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa5000000 0x00 0x100000>;
+ no-map;
+ };
+
+ main_r5fss1_core1_memory_region: r5f-memory@a5100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa5100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ c66_1_dma_memory_region: c66-dma-memory@a6000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa6000000 0x00 0x100000>;
+ no-map;
+ };
+
+ c66_0_memory_region: c66-memory@a6100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa6100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ c66_0_dma_memory_region: c66-dma-memory@a7000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa7000000 0x00 0x100000>;
+ no-map;
+ };
+
+ c66_1_memory_region: c66-memory@a7100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa7100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ c71_0_dma_memory_region: c71-dma-memory@a8000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa8000000 0x00 0x100000>;
+ no-map;
+ };
+
+ c71_0_memory_region: c71-memory@a8100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0xa8100000 0x00 0xf00000>;
+ no-map;
+ };
+
+ rtos_ipc_memory_region: ipc-memories@aa000000 {
+ reg = <0x00 0xaa000000 0x00 0x01c00000>;
+ alignment = <0x1000>;
+ no-map;
+ };
+ };
+
+ gpio_keys: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sw_pwr_pins_default>;
+
+ button-1 {
+ label = "BOOT";
+ linux,code = <BTN_0>;
+ gpios = <&wkup_gpio0 0 GPIO_ACTIVE_LOW>;
+ };
+
+ button-2 {
+ label = "POWER";
+ linux,code = <KEY_POWER>;
+ gpios = <&wkup_gpio0 4 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_default>;
+
+ led-0 {
+ gpios = <&main_gpio0 96 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_HEARTBEAT;
+ linux,default-trigger = "heartbeat";
+ };
+
+ led-1 {
+ gpios = <&main_gpio0 95 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_DISK_ACTIVITY;
+ linux,default-trigger = "mmc0";
+ };
+
+ led-2 {
+ gpios = <&main_gpio0 97 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_CPU;
+ linux,default-trigger = "cpu";
+ };
+
+ led-3 {
+ gpios = <&main_gpio0 110 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_DISK_ACTIVITY;
+ linux,default-trigger = "mmc1";
+ };
+
+ led-4 {
+ gpios = <&main_gpio0 109 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_WLAN;
+ default-state = "off";
+ };
+ };
+
+ evm_12v0: regulator-0 {
+ /* main supply */
+ compatible = "regulator-fixed";
+ regulator-name = "evm_12v0";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vsys_3v3: regulator-1 {
+ /* Output of LMS140 */
+ compatible = "regulator-fixed";
+ regulator-name = "vsys_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&evm_12v0>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vsys_5v0: regulator-2 {
+ /* Output of LM5140 */
+ compatible = "regulator-fixed";
+ regulator-name = "vsys_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&evm_12v0>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vdd_mmc1: regulator-3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_pwr_en_pins_default>;
+ regulator-name = "vdd_mmc1";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ enable-active-high;
+ vin-supply = <&vsys_3v3>;
+ gpio = <&main_gpio0 82 GPIO_ACTIVE_HIGH>;
+ };
+
+ vdd_sd_dv_alt: regulator-4 {
+ compatible = "regulator-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&vdd_sd_dv_alt_pins_default>;
+ regulator-name = "tlv71033";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ vin-supply = <&vsys_5v0>;
+ gpios = <&main_gpio0 117 GPIO_ACTIVE_HIGH>;
+ states = <1800000 0x0>,
+ <3300000 0x1>;
+ };
+
+ dp_pwr_3v3: regulator-5 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp0_3v3_en_pins_default>;
+ regulator-name = "dp-pwr";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&main_gpio0 49 GPIO_ACTIVE_HIGH>; /* DP0_PWR_SW_EN */
+ enable-active-high;
+ };
+
+ dp0: connector {
+ compatible = "dp-connector";
+ label = "DP0";
+ type = "full-size";
+ dp-pwr-supply = <&dp_pwr_3v3>;
+
+ port {
+ dp_connector_in: endpoint {
+ remote-endpoint = <&dp0_out>;
+ };
+ };
+ };
+};
+
+&main_pmx0 {
+ led_pins_default: led-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x184, PIN_INPUT, 7) /* (T23) RGMII5_RD0.GPIO0_96 */
+ J721E_IOPAD(0x180, PIN_INPUT, 7) /* (R23) RGMII5_RD1.GPIO0_95 */
+ J721E_IOPAD(0x188, PIN_INPUT, 7) /* (Y28) RGMII6_TX_CTL.GPIO0_97 */
+ J721E_IOPAD(0x1bc, PIN_INPUT, 7) /* (V24) MDIO0_MDC.GPIO0_110 */
+ J721E_IOPAD(0x1b8, PIN_INPUT, 7) /* (V26) MDIO0_MDIO.GPIO0_109 */
+ >;
+ };
+
+ main_mmc1_pins_default: main-mmc1-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x254, PIN_INPUT, 0) /* (R29) MMC1_CMD */
+ J721E_IOPAD(0x250, PIN_INPUT, 0) /* (P25) MMC1_CLK */
+ J721E_IOPAD(0x2ac, PIN_INPUT, 0) /* (P25) MMC1_CLKLB */
+ J721E_IOPAD(0x24c, PIN_INPUT, 0) /* (R24) MMC1_DAT0 */
+ J721E_IOPAD(0x248, PIN_INPUT, 0) /* (P24) MMC1_DAT1 */
+ J721E_IOPAD(0x244, PIN_INPUT, 0) /* (R25) MMC1_DAT2 */
+ J721E_IOPAD(0x240, PIN_INPUT, 0) /* (R26) MMC1_DAT3 */
+ J721E_IOPAD(0x258, PIN_INPUT, 0) /* (P23) MMC1_SDCD */
+ >;
+ };
+
+ main_uart0_pins_default: main-uart0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x1e8, PIN_INPUT, 0) /* (AB2) UART0_RXD */
+ J721E_IOPAD(0x1ec, PIN_OUTPUT, 0) /* (AB3) UART0_TXD */
+ >;
+ };
+
+ sd_pwr_en_pins_default: sd-pwr-en-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x14c, PIN_INPUT, 7) /* (AA29) PRG0_PRU1_GPO19.GPIO0_82 */
+ >;
+ };
+
+ vdd_sd_dv_alt_pins_default: vdd-sd-dv-alt-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x1d8, PIN_INPUT, 7) /* (W4) SPI1_CS1.GPIO0_117 */
+ >;
+ };
+
+ main_usbss0_pins_default: main-usbss0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x210, PIN_INPUT, 7) /* (W3) MCAN1_RX.GPIO1_3 - USBC_DIR */
+ >;
+ };
+
+ main_usbss1_pins_default: main-usbss1-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x290, INPUT_DISABLE, 1) /* (U6) USB0_DRVVBUS.USB1_DRVVBUS */
+ >;
+ };
+
+ dp0_3v3_en_pins_default:dp0-3v3-en-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0xc8, PIN_INPUT, 7) /* (AE26) PRG0_PRU0_GPO6.GPIO0_49 */
+ >;
+ };
+
+ dp0_pins_default: dp0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x1c4, PIN_INPUT, 5) /* (Y4) SPI0_CS1.DP0_HPD */
+ >;
+ };
+
+ main_i2c0_pins_default: main-i2c0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x220, PIN_INPUT_PULLUP, 0) /* (AC5) I2C0_SCL */
+ J721E_IOPAD(0x224, PIN_INPUT_PULLUP, 0) /* (AA5) I2C0_SDA */
+ >;
+ };
+
+ main_i2c1_pins_default: main-i2c1-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x228, PIN_INPUT_PULLUP, 0) /* (Y6) I2C1_SCL */
+ J721E_IOPAD(0x22c, PIN_INPUT_PULLUP, 0) /* (AA6) I2C1_SDA */
+ >;
+ };
+
+ main_i2c2_pins_default: main-i2c2-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x208, PIN_INPUT_PULLUP, 4) /* (W5) MCAN0_RX.I2C2_SCL */
+ J721E_IOPAD(0x20c, PIN_INPUT_PULLUP, 4) /* (W6) MCAN0_TX.I2C2_SDA */
+ J721E_IOPAD(0x138, PIN_INPUT, 7) /* (AE25) PRG0_PRU1_GPO14.GPIO0_77 */
+ J721E_IOPAD(0x13c, PIN_INPUT, 7) /* (AF29) PRG0_PRU1_GPO15.GPIO0_78 */
+ >;
+ };
+
+ main_i2c3_pins_default: main-i2c3-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x270, PIN_INPUT_PULLUP, 4) /* (T26) MMC2_CLK.I2C3_SCL */
+ J721E_IOPAD(0x274, PIN_INPUT_PULLUP, 4) /* (T25) MMC2_CMD.I2C3_SDA */
+ >;
+ };
+
+ main_i2c4_pins_default: main-i2c4-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x1e0, PIN_INPUT_PULLUP, 2) /* (Y5) SPI1_D0.I2C4_SCL */
+ J721E_IOPAD(0x1dc, PIN_INPUT_PULLUP, 2) /* (Y1) SPI1_CLK.I2C4_SDA */
+ J721E_IOPAD(0x30, PIN_INPUT, 7) /* (AF24) PRG1_PRU0_GPO11.GPIO0_12 */
+ J721E_IOPAD(0x34, PIN_INPUT, 7) /* (AJ24) PRG1_PRU0_GPO12.GPIO0_13 */
+ >;
+ };
+
+ main_i2c5_pins_default: main-i2c5-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x150, PIN_INPUT_PULLUP, 2) /* (Y26) PRG0_MDIO0_MDIO.I2C5_SCL */
+ J721E_IOPAD(0x154, PIN_INPUT_PULLUP, 2) /* (AA27) PRG0_MDIO0_MDC.I2C5_SDA */
+ >;
+ };
+
+ main_i2c6_pins_default: main-i2c6-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x1d0, PIN_INPUT_PULLUP, 2) /* (AA3) SPI0_D1.I2C6_SCL */
+ J721E_IOPAD(0x1e4, PIN_INPUT_PULLUP, 2) /* (Y2) SPI1_D1.I2C6_SDA */
+ J721E_IOPAD(0x74, PIN_INPUT, 7) /* (AC21) PRG1_PRU1_GPO7.GPIO0_28 */
+ J721E_IOPAD(0xa4, PIN_INPUT, 7) /* (AH22) PRG1_PRU1_GPO19.GPIO0_40 */
+ >;
+ };
+
+ csi0_gpio_pins_default: csi0-gpio-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x19c, PIN_INPUT_PULLDOWN, 7) /* (W27) RGMII6_TD0.GPIO0_102 */
+ J721E_IOPAD(0x1a0, PIN_INPUT_PULLDOWN, 7) /* (W29) RGMII6_TXC.GPIO0_103 */
+ >;
+ };
+
+ csi1_gpio_pins_default: csi1-gpio-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x198, PIN_INPUT_PULLDOWN, 7) /* (V25) RGMII6_TD1.GPIO0_101 */
+ J721E_IOPAD(0x1b0, PIN_INPUT_PULLDOWN, 7) /* (W24) RGMII6_RD1.GPIO0_107 */
+ >;
+ };
+
+ pcie1_rst_pins_default: pcie1-rst-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x5c, PIN_INPUT, 7) /* (AG23) PRG1_PRU1_GPO1.GPIO0_22 */
+ >;
+ };
+};
+
+&wkup_pmx0 {
+ eeprom_wp_pins_default: eeprom-wp-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0xc4, PIN_OUTPUT_PULLUP, 7) /* (G24) WKUP_GPIO0_5 */
+ >;
+ };
+
+ mcu_adc0_pins_default: mcu-adc0-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x130, PIN_INPUT, 0) /* (K25) MCU_ADC0_AIN0 */
+ J721E_WKUP_IOPAD(0x134, PIN_INPUT, 0) /* (K26) MCU_ADC0_AIN1 */
+ J721E_WKUP_IOPAD(0x138, PIN_INPUT, 0) /* (K28) MCU_ADC0_AIN2 */
+ J721E_WKUP_IOPAD(0x13c, PIN_INPUT, 0) /* (L28) MCU_ADC0_AIN3 */
+ J721E_WKUP_IOPAD(0x140, PIN_INPUT, 0) /* (K24) MCU_ADC0_AIN4 */
+ J721E_WKUP_IOPAD(0x144, PIN_INPUT, 0) /* (K27) MCU_ADC0_AIN5 */
+ J721E_WKUP_IOPAD(0x148, PIN_INPUT, 0) /* (K29) MCU_ADC0_AIN6 */
+ >;
+ };
+
+ mcu_adc1_pins_default: mcu-adc1-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x150, PIN_INPUT, 0) /* (N23) MCU_ADC1_AIN0 */
+ >;
+ };
+
+ mikro_bus_pins_default: mikro-bus-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x108, PIN_INPUT, 7) /* SDAPULLEN (E26) PMIC_POWER_EN0.WKUP_GPIO0_66 */
+ J721E_WKUP_IOPAD(0xd4, PIN_INPUT, 7) /* SDA (G26) WKUP_GPIO0_9.MCU_I2C1_SDA */
+ J721E_WKUP_IOPAD(0xf4, PIN_INPUT, 7) /* SDA (D25) MCU_I3C0_SDA.WKUP_GPIO0_61 */
+ J721E_WKUP_IOPAD(0xd0, PIN_INPUT, 7) /* SCL (G27) WKUP_GPIO0_8.MCU_I2C1_SCL */
+ J721E_WKUP_IOPAD(0xf0, PIN_INPUT, 7) /* SCL (D26) MCU_I3C0_SCL.WKUP_GPIO0_60 */
+
+ J721E_WKUP_IOPAD(0xb8, PIN_INPUT, 7) /* MOSI (F28) WKUP_GPIO0_2.MCU_SPI1_D1 */
+ J721E_WKUP_IOPAD(0xb4, PIN_INPUT, 7) /* MISO (F25) WKUP_GPIO0_1.MCU_SPI1_D0 */
+ J721E_WKUP_IOPAD(0xb0, PIN_INPUT, 7) /* CLK (F26) WKUP_GPIO0_0.MCU_SPI1_CLK */
+ J721E_WKUP_IOPAD(0xbc, PIN_INPUT, 7) /* CS (F27) WKUP_GPIO0_3.MCU_SPI1_CS0 */
+
+ J721E_WKUP_IOPAD(0x44, PIN_INPUT, 7) /* RX (G22) MCU_OSPI1_D1.WKUP_GPIO0_33 */
+ J721E_WKUP_IOPAD(0x48, PIN_INPUT, 7) /* TX (D23) MCU_OSPI1_D2.WKUP_GPIO0_34 */
+
+ J721E_WKUP_IOPAD(0x4c, PIN_INPUT, 7) /* INT (C23) MCU_OSPI1_D3.WKUP_GPIO0_35 */
+ J721E_WKUP_IOPAD(0x54, PIN_INPUT, 7) /* RST (E22) MCU_OSPI1_CSn1.WKUP_GPIO0_37 */
+ J721E_WKUP_IOPAD(0xdc, PIN_INPUT, 7) /* PWM (H27) WKUP_GPIO0_11 */
+ J721E_WKUP_IOPAD(0xac, PIN_INPUT, 7) /* AN (C29) MCU_MCAN0_RX.WKUP_GPIO0_59 */
+ >;
+ };
+
+ mcu_cpsw_pins_default: mcu-cpsw-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x84, PIN_INPUT, 0) /* (B24) MCU_RGMII1_RD0 */
+ J721E_WKUP_IOPAD(0x80, PIN_INPUT, 0) /* (A24) MCU_RGMII1_RD1 */
+ J721E_WKUP_IOPAD(0x7c, PIN_INPUT, 0) /* (D24) MCU_RGMII1_RD2 */
+ J721E_WKUP_IOPAD(0x78, PIN_INPUT, 0) /* (A25) MCU_RGMII1_RD3 */
+ J721E_WKUP_IOPAD(0x74, PIN_INPUT, 0) /* (C24) MCU_RGMII1_RXC */
+ J721E_WKUP_IOPAD(0x5c, PIN_INPUT, 0) /* (C25) MCU_RGMII1_RX_CTL */
+ J721E_WKUP_IOPAD(0x6c, PIN_OUTPUT, 0) /* (B25) MCU_RGMII1_TD0 */
+ J721E_WKUP_IOPAD(0x68, PIN_OUTPUT, 0) /* (A26) MCU_RGMII1_TD1 */
+ J721E_WKUP_IOPAD(0x64, PIN_OUTPUT, 0) /* (A27) MCU_RGMII1_TD2 */
+ J721E_WKUP_IOPAD(0x60, PIN_OUTPUT, 0) /* (A28) MCU_RGMII1_TD3 */
+ J721E_WKUP_IOPAD(0x70, PIN_OUTPUT, 0) /* (B26) MCU_RGMII1_TXC */
+ J721E_WKUP_IOPAD(0x58, PIN_OUTPUT, 0) /* (B27) MCU_RGMII1_TX_CTL */
+ >;
+ };
+
+ mcu_mdio_pins_default: mcu-mdio1-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x8c, PIN_OUTPUT, 0) /* (F23) MCU_MDIO0_MDC */
+ J721E_WKUP_IOPAD(0x88, PIN_INPUT, 0) /* (E23) MCU_MDIO0_MDIO */
+ >;
+ };
+
+ sw_pwr_pins_default: sw-pwr-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0xc0, PIN_INPUT, 7) /* (G25) WKUP_GPIO0_4 */
+ >;
+ };
+
+ wkup_i2c0_pins_default: wkup-i2c0-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0xf8, PIN_INPUT_PULLUP, 0) /* (J25) WKUP_I2C0_SCL */
+ J721E_WKUP_IOPAD(0xfc, PIN_INPUT_PULLUP, 0) /* (H24) WKUP_I2C0_SDA */
+ >;
+ };
+
+ mcu_usbss1_pins_default: mcu-usbss1-pins-default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x3c, PIN_OUTPUT_PULLUP, 5) /* (A23) MCU_OSPI1_LBCLKO.WKUP_GPIO0_30 */
+ >;
+ };
+};
+
+&wkup_uart0 {
+ /* Wakeup UART is used by TIFS firmware. */
+ status = "reserved";
+};
+
+&main_uart0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_uart0_pins_default>;
+ /* Shared with ATF on this platform */
+ power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
+};
+
+&main_sdhci0 {
+ /* eMMC */
+ non-removable;
+ ti,driver-strength-ohm = <50>;
+ disable-wp;
+};
+
+&main_sdhci1 {
+ /* SD Card */
+ vmmc-supply = <&vdd_mmc1>;
+ vqmmc-supply = <&vdd_sd_dv_alt>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_mmc1_pins_default>;
+ ti,driver-strength-ohm = <50>;
+ disable-wp;
+};
+
+&main_sdhci2 {
+ /* Unused */
+ status = "disabled";
+};
+
+&ospi0 {
+ /* Unused */
+ status = "disabled";
+};
+
+&ospi1 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c0_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&main_i2c1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c1_pins_default &csi1_gpio_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&main_i2c2 {
+ /* BBB Header: P9.19 and P9.20 */
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c2_pins_default>;
+ clock-frequency = <100000>;
+};
+
+&main_i2c3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c3_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&main_i2c4 {
+ /* BBB Header: P9.24 and P9.26 */
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c4_pins_default>;
+ clock-frequency = <100000>;
+};
+
+&main_i2c5 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c5_pins_default &csi0_gpio_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&main_i2c6 {
+ /* BBB Header: P9.17 and P9.18 */
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c6_pins_default>;
+ clock-frequency = <100000>;
+ status = "okay";
+};
+
+&wkup_i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wkup_i2c0_pins_default &eeprom_wp_pins_default>;
+ clock-frequency = <400000>;
+
+ eeprom@50 {
+ compatible = "atmel,24c04";
+ reg = <0x50>;
+ };
+};
+
+&main_gpio2 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_gpio3 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_gpio4 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_gpio5 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_gpio6 {
+ /* Unused */
+ status = "disabled";
+};
+
+&main_gpio7 {
+ /* Unused */
+ status = "disabled";
+};
+
+&wkup_gpio0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcu_adc0_pins_default &mcu_adc1_pins_default &mikro_bus_pins_default>;
+};
+
+&wkup_gpio1 {
+ /* Unused */
+ status = "disabled";
+};
+
+&usb_serdes_mux {
+ idle-states = <1>, <1>; /* USB0 to SERDES3, USB1 to SERDES2 */
+};
+
+&serdes_ln_ctrl {
+ idle-states = <J721E_SERDES0_LANE0_IP4_UNUSED>, <J721E_SERDES0_LANE1_IP4_UNUSED>,
+ <J721E_SERDES1_LANE0_PCIE1_LANE0>, <J721E_SERDES1_LANE1_PCIE1_LANE1>,
+ <J721E_SERDES2_LANE0_IP1_UNUSED>, <J721E_SERDES2_LANE1_USB3_1>,
+ <J721E_SERDES3_LANE0_USB3_0_SWAP>, <J721E_SERDES3_LANE1_USB3_0>,
+ <J721E_SERDES4_LANE0_EDP_LANE0>, <J721E_SERDES4_LANE1_EDP_LANE1>,
+ <J721E_SERDES4_LANE2_EDP_LANE2>, <J721E_SERDES4_LANE3_EDP_LANE3>;
+};
+
+&serdes_wiz3 {
+ typec-dir-gpios = <&main_gpio1 3 GPIO_ACTIVE_LOW>;
+ typec-dir-debounce-ms = <700>; /* TUSB321, tCCB_DEFAULT 133 ms */
+};
+
+&serdes3 {
+ serdes3_usb_link: phy@0 {
+ reg = <0>;
+ cdns,num-lanes = <2>;
+ #phy-cells = <0>;
+ cdns,phy-type = <PHY_TYPE_USB3>;
+ resets = <&serdes_wiz3 1>, <&serdes_wiz3 2>;
+ };
+};
+
+&serdes4 {
+ torrent_phy_dp: phy@0 {
+ reg = <0>;
+ resets = <&serdes_wiz4 1>;
+ cdns,phy-type = <PHY_TYPE_DP>;
+ cdns,num-lanes = <4>;
+ cdns,max-bit-rate = <5400>;
+ #phy-cells = <0>;
+ };
+};
+
+&mhdp {
+ phys = <&torrent_phy_dp>;
+ phy-names = "dpphy";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp0_pins_default>;
+};
+
+&usbss0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_usbss0_pins_default>;
+ ti,vbus-divider;
+};
+
+&usb0 {
+ dr_mode = "peripheral";
+ maximum-speed = "super-speed";
+ phys = <&serdes3_usb_link>;
+ phy-names = "cdns3,usb3-phy";
+};
+
+&serdes2 {
+ serdes2_usb_link: phy@1 {
+ reg = <1>;
+ cdns,num-lanes = <1>;
+ #phy-cells = <0>;
+ cdns,phy-type = <PHY_TYPE_USB3>;
+ resets = <&serdes_wiz2 2>;
+ };
+};
+
+&usbss1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_usbss1_pins_default &mcu_usbss1_pins_default>;
+ ti,vbus-divider;
+};
+
+&usb1 {
+ dr_mode = "host";
+ maximum-speed = "super-speed";
+ phys = <&serdes2_usb_link>;
+ phy-names = "cdns3,usb3-phy";
+};
+
+&tscadc0 {
+ /* BBB Header: P9.39, P9.40, P9.37, P9.38, P9.33, P9.36, P9.35 */
+ adc {
+ ti,adc-channels = <0 1 2 3 4 5 6>;
+ };
+};
+
+&tscadc1 {
+ /* MCU mikroBUS Header J10.1 - MCU_ADC1_AIN0 */
+ adc {
+ ti,adc-channels = <0>;
+ };
+};
+
+&mcu_cpsw {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcu_cpsw_pins_default>;
+};
+
+&davinci_mdio {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcu_mdio_pins_default>;
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+ };
+};
+
+&cpsw_port1 {
+ phy-mode = "rgmii-rxid";
+ phy-handle = <&phy0>;
+};
+
+&dss {
+ /*
+ * These clock assignments are chosen to enable the following outputs:
+ *
+ * VP0 - DisplayPort SST
+ * VP1 - DPI0
+ * VP2 - DSI
+ * VP3 - DPI1
+ */
+
+ assigned-clocks = <&k3_clks 152 1>, /* VP 1 pixel clock */
+ <&k3_clks 152 4>, /* VP 2 pixel clock */
+ <&k3_clks 152 9>, /* VP 3 pixel clock */
+ <&k3_clks 152 13>; /* VP 4 pixel clock */
+ assigned-clock-parents = <&k3_clks 152 2>, /* PLL16_HSDIV0 */
+ <&k3_clks 152 6>, /* PLL19_HSDIV0 */
+ <&k3_clks 152 11>, /* PLL18_HSDIV0 */
+ <&k3_clks 152 18>; /* PLL23_HSDIV0 */
+};
+
+&dss_ports {
+ port {
+ dpi0_out: endpoint {
+ remote-endpoint = <&dp0_in>;
+ };
+ };
+};
+
+&dp0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dp0_in: endpoint {
+ remote-endpoint = <&dpi0_out>;
+ };
+ };
+
+ port@4 {
+ reg = <4>;
+ dp0_out: endpoint {
+ remote-endpoint = <&dp_connector_in>;
+ };
+ };
+};
+
+&serdes0 {
+ serdes0_pcie_link: phy@0 {
+ reg = <0>;
+ cdns,num-lanes = <1>;
+ #phy-cells = <0>;
+ cdns,phy-type = <PHY_TYPE_PCIE>;
+ resets = <&serdes_wiz0 1>;
+ };
+};
+
+&serdes1 {
+ serdes1_pcie_link: phy@0 {
+ reg = <0>;
+ cdns,num-lanes = <2>;
+ #phy-cells = <0>;
+ cdns,phy-type = <PHY_TYPE_PCIE>;
+ resets = <&serdes_wiz1 1>, <&serdes_wiz1 2>;
+ };
+};
+
+&pcie0_rc {
+ /* Unused */
+ status = "disabled";
+};
+
+&pcie1_rc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie1_rst_pins_default>;
+ phys = <&serdes1_pcie_link>;
+ phy-names = "pcie-phy";
+ num-lanes = <2>;
+ max-link-speed = <3>;
+ reset-gpios = <&main_gpio0 22 GPIO_ACTIVE_HIGH>;
+};
+
+&pcie2_rc {
+ /* Unused */
+ status = "disabled";
+};
+
+&pcie0_ep {
+ status = "disabled";
+ phys = <&serdes0_pcie_link>;
+ phy-names = "pcie-phy";
+ num-lanes = <1>;
+};
+
+&pcie1_ep {
+ status = "disabled";
+ phys = <&serdes1_pcie_link>;
+ phy-names = "pcie-phy";
+ num-lanes = <2>;
+};
+
+&pcie2_ep {
+ /* Unused */
+ status = "disabled";
+};
+
+&pcie3_rc {
+ /* Unused */
+ status = "disabled";
+};
+
+&pcie3_ep {
+ /* Unused */
+ status = "disabled";
+};
+
+&icssg0_mdio {
+ /* Unused */
+ status = "disabled";
+};
+
+&icssg1_mdio {
+ /* Unused */
+ status = "disabled";
+};
+
+&ufs_wrapper {
+ status = "disabled";
+};
+
+&mailbox0_cluster0 {
+ interrupts = <436>;
+
+ mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
+ ti,mbox-rx = <0 0 0>;
+ ti,mbox-tx = <1 0 0>;
+ };
+
+ mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
+ ti,mbox-rx = <2 0 0>;
+ ti,mbox-tx = <3 0 0>;
+ };
+};
+
+&mailbox0_cluster1 {
+ interrupts = <432>;
+
+ mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
+ ti,mbox-rx = <0 0 0>;
+ ti,mbox-tx = <1 0 0>;
+ };
+
+ mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 {
+ ti,mbox-rx = <2 0 0>;
+ ti,mbox-tx = <3 0 0>;
+ };
+};
+
+&mailbox0_cluster2 {
+ interrupts = <428>;
+
+ mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
+ ti,mbox-rx = <0 0 0>;
+ ti,mbox-tx = <1 0 0>;
+ };
+
+ mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 {
+ ti,mbox-rx = <2 0 0>;
+ ti,mbox-tx = <3 0 0>;
+ };
+};
+
+&mailbox0_cluster3 {
+ interrupts = <424>;
+
+ mbox_c66_0: mbox-c66-0 {
+ ti,mbox-rx = <0 0 0>;
+ ti,mbox-tx = <1 0 0>;
+ };
+
+ mbox_c66_1: mbox-c66-1 {
+ ti,mbox-rx = <2 0 0>;
+ ti,mbox-tx = <3 0 0>;
+ };
+};
+
+&mailbox0_cluster4 {
+ interrupts = <420>;
+
+ mbox_c71_0: mbox-c71-0 {
+ ti,mbox-rx = <0 0 0>;
+ ti,mbox-tx = <1 0 0>;
+ };
+};
+
+&mcu_r5fss0_core0 {
+ mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
+ memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
+ <&mcu_r5fss0_core0_memory_region>;
+};
+
+&mcu_r5fss0_core1 {
+ mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
+ memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
+ <&mcu_r5fss0_core1_memory_region>;
+};
+
+&main_r5fss0_core0 {
+ mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
+ memory-region = <&main_r5fss0_core0_dma_memory_region>,
+ <&main_r5fss0_core0_memory_region>;
+};
+
+&main_r5fss0_core1 {
+ mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
+ memory-region = <&main_r5fss0_core1_dma_memory_region>,
+ <&main_r5fss0_core1_memory_region>;
+};
+
+&main_r5fss1_core0 {
+ mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
+ memory-region = <&main_r5fss1_core0_dma_memory_region>,
+ <&main_r5fss1_core0_memory_region>;
+};
+
+&main_r5fss1_core1 {
+ mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
+ memory-region = <&main_r5fss1_core1_dma_memory_region>,
+ <&main_r5fss1_core1_memory_region>;
+};
+
+&c66_0 {
+ mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
+ memory-region = <&c66_0_dma_memory_region>,
+ <&c66_0_memory_region>;
+};
+
+&c66_1 {
+ mboxes = <&mailbox0_cluster3 &mbox_c66_1>;
+ memory-region = <&c66_1_dma_memory_region>,
+ <&c66_1_memory_region>;
+};
+
+&c71_0 {
+ mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
+ memory-region = <&c71_0_dma_memory_region>,
+ <&c71_0_memory_region>;
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
index b1691ac3442d..7db0603125aa 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
@@ -96,7 +96,7 @@
<3300000 0x1>;
};
- sound0: sound@0 {
+ sound0: sound-0 {
compatible = "ti,j721e-cpb-audio";
model = "j721e-cpb";
@@ -370,38 +370,30 @@
status = "reserved";
};
-&main_uart0 {
- power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
-};
-
-&main_uart3 {
- /* UART not brought out */
- status = "disabled";
+&mcu_uart0 {
+ status = "okay";
+ /* Default pinmux */
};
-&main_uart5 {
- /* UART not brought out */
- status = "disabled";
+&main_uart0 {
+ status = "okay";
+ /* Shared with ATF on this platform */
+ power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
};
-&main_uart6 {
- /* UART not brought out */
- status = "disabled";
+&main_uart1 {
+ status = "okay";
+ /* Default pinmux */
};
-&main_uart7 {
- /* UART not brought out */
- status = "disabled";
+&main_uart2 {
+ status = "okay";
+ /* Default pinmux */
};
-&main_uart8 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart9 {
- /* UART not brought out */
- status = "disabled";
+&main_uart4 {
+ status = "okay";
+ /* Default pinmux */
};
&main_gpio2 {
@@ -537,6 +529,7 @@
};
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -573,6 +566,7 @@
};
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
clock-frequency = <400000>;
@@ -598,6 +592,7 @@
};
&main_i2c3 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c3_pins_default>;
clock-frequency = <400000>;
@@ -636,6 +631,7 @@
};
&main_i2c6 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c6_pins_default>;
clock-frequency = <400000>;
@@ -713,47 +709,8 @@
};
};
-&mcasp0 {
- status = "disabled";
-};
-
-&mcasp1 {
- status = "disabled";
-};
-
-&mcasp2 {
- status = "disabled";
-};
-
-&mcasp3 {
- status = "disabled";
-};
-
-&mcasp4 {
- status = "disabled";
-};
-
-&mcasp5 {
- status = "disabled";
-};
-
-&mcasp6 {
- status = "disabled";
-};
-
-&mcasp7 {
- status = "disabled";
-};
-
-&mcasp8 {
- status = "disabled";
-};
-
-&mcasp9 {
- status = "disabled";
-};
-
&mcasp10 {
+ status = "okay";
#sound-dai-cells = <0>;
pinctrl-names = "default";
@@ -771,10 +728,6 @@
rx-num-evt = <0>;
};
-&mcasp11 {
- status = "disabled";
-};
-
&cmn_refclk1 {
clock-frequency = <100000000>;
};
@@ -925,73 +878,29 @@
};
&mcu_mcan0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_mcan0_pins_default>;
phys = <&transceiver1>;
};
&mcu_mcan1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_mcan1_pins_default>;
phys = <&transceiver2>;
};
&main_mcan0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_mcan0_pins_default>;
phys = <&transceiver3>;
};
-&main_mcan1 {
- status = "disabled";
-};
-
&main_mcan2 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_mcan2_pins_default>;
phys = <&transceiver4>;
};
-
-&main_mcan3 {
- status = "disabled";
-};
-
-&main_mcan4 {
- status = "disabled";
-};
-
-&main_mcan5 {
- status = "disabled";
-};
-
-&main_mcan6 {
- status = "disabled";
-};
-
-&main_mcan7 {
- status = "disabled";
-};
-
-&main_mcan8 {
- status = "disabled";
-};
-
-&main_mcan9 {
- status = "disabled";
-};
-
-&main_mcan10 {
- status = "disabled";
-};
-
-&main_mcan11 {
- status = "disabled";
-};
-
-&main_mcan12 {
- status = "disabled";
-};
-
-&main_mcan13 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
index 917c9dc99efa..c935622f0102 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
@@ -66,7 +66,73 @@
#mux-control-cells = <1>;
mux-reg-masks = <0x4000 0x8000000>, /* USB0 to SERDES0/3 mux */
<0x4010 0x8000000>; /* USB1 to SERDES1/2 mux */
- };
+ };
+
+ ehrpwm_tbclk: clock-controller@4140 {
+ compatible = "ti,am654-ehrpwm-tbclk", "syscon";
+ reg = <0x4140 0x18>;
+ #clock-cells = <1>;
+ };
+ };
+
+ main_ehrpwm0: pwm@3000000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3000000 0x00 0x100>;
+ power-domains = <&k3_pds 83 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 0>, <&k3_clks 83 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
+ };
+
+ main_ehrpwm1: pwm@3010000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3010000 0x00 0x100>;
+ power-domains = <&k3_pds 84 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 1>, <&k3_clks 84 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
+ };
+
+ main_ehrpwm2: pwm@3020000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3020000 0x00 0x100>;
+ power-domains = <&k3_pds 85 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 2>, <&k3_clks 85 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
+ };
+
+ main_ehrpwm3: pwm@3030000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3030000 0x00 0x100>;
+ power-domains = <&k3_pds 86 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 3>, <&k3_clks 86 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
+ };
+
+ main_ehrpwm4: pwm@3040000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3040000 0x00 0x100>;
+ power-domains = <&k3_pds 87 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 4>, <&k3_clks 87 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
+ };
+
+ main_ehrpwm5: pwm@3050000 {
+ compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x00 0x3050000 0x00 0x100>;
+ power-domains = <&k3_pds 88 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&ehrpwm_tbclk 5>, <&k3_clks 88 0>;
+ clock-names = "tbclk", "fck";
+ status = "disabled";
};
gic500: interrupt-controller@1800000 {
@@ -176,6 +242,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster1: mailbox@31f81000 {
@@ -185,6 +252,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster2: mailbox@31f82000 {
@@ -194,6 +262,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster3: mailbox@31f83000 {
@@ -203,6 +272,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster4: mailbox@31f84000 {
@@ -212,6 +282,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster5: mailbox@31f85000 {
@@ -221,6 +292,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster6: mailbox@31f86000 {
@@ -230,6 +302,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster7: mailbox@31f87000 {
@@ -239,6 +312,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster8: mailbox@31f88000 {
@@ -248,6 +322,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster9: mailbox@31f89000 {
@@ -257,6 +332,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster10: mailbox@31f8a000 {
@@ -266,6 +342,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster11: mailbox@31f8b000 {
@@ -275,6 +352,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
main_ringacc: ringacc@3c000000 {
@@ -337,13 +415,11 @@
dmas = <&main_udmap 0xc000>, <&main_udmap 0x4000>,
<&main_udmap 0x4001>;
dma-names = "tx", "rx1", "rx2";
- dma-coherent;
rng: rng@4e10000 {
compatible = "inside-secure,safexcel-eip76";
reg = <0x0 0x4e10000 0x0 0x7d>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&k3_clks 264 2>;
};
};
@@ -840,6 +916,7 @@
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 146 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -851,6 +928,7 @@
power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 278 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -862,6 +940,7 @@
power-domains = <&k3_pds 279 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 279 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart3: serial@2830000 {
@@ -873,6 +952,7 @@
power-domains = <&k3_pds 280 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 280 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart4: serial@2840000 {
@@ -884,6 +964,7 @@
power-domains = <&k3_pds 281 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 281 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart5: serial@2850000 {
@@ -895,6 +976,7 @@
power-domains = <&k3_pds 282 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 282 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart6: serial@2860000 {
@@ -906,6 +988,7 @@
power-domains = <&k3_pds 283 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 283 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart7: serial@2870000 {
@@ -917,6 +1000,7 @@
power-domains = <&k3_pds 284 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 284 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart8: serial@2880000 {
@@ -928,6 +1012,7 @@
power-domains = <&k3_pds 285 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 285 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_uart9: serial@2890000 {
@@ -939,6 +1024,7 @@
power-domains = <&k3_pds 286 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 286 0>;
clock-names = "fclk";
+ status = "disabled";
};
main_gpio0: gpio@600000 {
@@ -1219,6 +1305,7 @@
clock-names = "fck";
clocks = <&k3_clks 187 0>;
power-domains = <&k3_pds 187 TI_SCI_PD_SHARED>;
+ status = "disabled";
};
main_i2c1: i2c@2010000 {
@@ -1230,6 +1317,7 @@
clock-names = "fck";
clocks = <&k3_clks 188 0>;
power-domains = <&k3_pds 188 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c2: i2c@2020000 {
@@ -1241,6 +1329,7 @@
clock-names = "fck";
clocks = <&k3_clks 189 0>;
power-domains = <&k3_pds 189 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c3: i2c@2030000 {
@@ -1252,6 +1341,7 @@
clock-names = "fck";
clocks = <&k3_clks 190 0>;
power-domains = <&k3_pds 190 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c4: i2c@2040000 {
@@ -1263,6 +1353,7 @@
clock-names = "fck";
clocks = <&k3_clks 191 0>;
power-domains = <&k3_pds 191 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c5: i2c@2050000 {
@@ -1274,6 +1365,7 @@
clock-names = "fck";
clocks = <&k3_clks 192 0>;
power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c6: i2c@2060000 {
@@ -1285,6 +1377,7 @@
clock-names = "fck";
clocks = <&k3_clks 193 0>;
power-domains = <&k3_pds 193 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
ufs_wrapper: ufs-wrapper@4e80000 {
@@ -1408,6 +1501,7 @@
clocks = <&k3_clks 174 1>;
clock-names = "fck";
power-domains = <&k3_pds 174 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp1: mcasp@2b10000 {
@@ -1425,6 +1519,7 @@
clocks = <&k3_clks 175 1>;
clock-names = "fck";
power-domains = <&k3_pds 175 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp2: mcasp@2b20000 {
@@ -1442,6 +1537,7 @@
clocks = <&k3_clks 176 1>;
clock-names = "fck";
power-domains = <&k3_pds 176 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp3: mcasp@2b30000 {
@@ -1459,6 +1555,7 @@
clocks = <&k3_clks 177 1>;
clock-names = "fck";
power-domains = <&k3_pds 177 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp4: mcasp@2b40000 {
@@ -1476,6 +1573,7 @@
clocks = <&k3_clks 178 1>;
clock-names = "fck";
power-domains = <&k3_pds 178 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp5: mcasp@2b50000 {
@@ -1493,6 +1591,7 @@
clocks = <&k3_clks 179 1>;
clock-names = "fck";
power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp6: mcasp@2b60000 {
@@ -1510,6 +1609,7 @@
clocks = <&k3_clks 180 1>;
clock-names = "fck";
power-domains = <&k3_pds 180 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp7: mcasp@2b70000 {
@@ -1527,6 +1627,7 @@
clocks = <&k3_clks 181 1>;
clock-names = "fck";
power-domains = <&k3_pds 181 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp8: mcasp@2b80000 {
@@ -1544,6 +1645,7 @@
clocks = <&k3_clks 182 1>;
clock-names = "fck";
power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp9: mcasp@2b90000 {
@@ -1561,6 +1663,7 @@
clocks = <&k3_clks 183 1>;
clock-names = "fck";
power-domains = <&k3_pds 183 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp10: mcasp@2ba0000 {
@@ -1578,6 +1681,7 @@
clocks = <&k3_clks 184 1>;
clock-names = "fck";
power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcasp11: mcasp@2bb0000 {
@@ -1595,6 +1699,7 @@
clocks = <&k3_clks 185 1>;
clock-names = "fck";
power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
watchdog0: watchdog@2200000 {
@@ -2027,6 +2132,7 @@
<GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan1: can@2711000 {
@@ -2041,6 +2147,7 @@
<GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan2: can@2721000 {
@@ -2055,6 +2162,7 @@
<GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan3: can@2731000 {
@@ -2069,6 +2177,7 @@
<GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan4: can@2741000 {
@@ -2083,6 +2192,7 @@
<GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan5: can@2751000 {
@@ -2097,6 +2207,7 @@
<GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan6: can@2761000 {
@@ -2111,6 +2222,7 @@
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan7: can@2771000 {
@@ -2125,6 +2237,7 @@
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan8: can@2781000 {
@@ -2139,6 +2252,7 @@
<GIC_SPI 577 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan9: can@2791000 {
@@ -2153,6 +2267,7 @@
<GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan10: can@27a1000 {
@@ -2167,6 +2282,7 @@
<GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan11: can@27b1000 {
@@ -2181,6 +2297,7 @@
<GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan12: can@27c1000 {
@@ -2195,6 +2312,7 @@
<GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan13: can@27d1000 {
@@ -2209,5 +2327,6 @@
<GIC_SPI 592 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
index df08724bbf1c..8ac78034d5d6 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
@@ -79,6 +79,7 @@
power-domains = <&k3_pds 287 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 287 0>;
clock-names = "fclk";
+ status = "disabled";
};
mcu_uart0: serial@40a00000 {
@@ -90,6 +91,7 @@
power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 149 0>;
clock-names = "fclk";
+ status = "disabled";
};
wkup_gpio_intr: interrupt-controller@42200000 {
@@ -145,6 +147,7 @@
clock-names = "fck";
clocks = <&k3_clks 194 0>;
power-domains = <&k3_pds 194 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_i2c1: i2c@40b10000 {
@@ -156,6 +159,7 @@
clock-names = "fck";
clocks = <&k3_clks 195 0>;
power-domains = <&k3_pds 195 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
wkup_i2c0: i2c@42120000 {
@@ -167,6 +171,7 @@
clock-names = "fck";
clocks = <&k3_clks 197 0>;
power-domains = <&k3_pds 197 TI_SCI_PD_SHARED>;
+ status = "disabled";
};
fss: fss@47000000 {
@@ -216,7 +221,7 @@
clocks = <&k3_clks 0 1>;
assigned-clocks = <&k3_clks 0 3>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
dmas = <&main_udmap 0x7400>,
<&main_udmap 0x7401>;
dma-names = "fifo0", "fifo1";
@@ -235,7 +240,7 @@
clocks = <&k3_clks 1 1>;
assigned-clocks = <&k3_clks 1 3>;
assigned-clock-rates = <60000000>;
- clock-names = "adc_tsc_fck";
+ clock-names = "fck";
dmas = <&main_udmap 0x7402>,
<&main_udmap 0x7403>;
dma-names = "fifo0", "fifo1";
@@ -403,6 +408,7 @@
<GIC_SPI 833 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
mcu_mcan1: can@40568000 {
@@ -417,5 +423,6 @@
<GIC_SPI 836 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
index 80358cba6954..4640d280c85c 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
@@ -400,6 +400,47 @@
J721E_IOPAD(0x124, PIN_INPUT, 7) /* (Y24) PRG0_PRU1_GPO9.GPIO0_72 */
>;
};
+
+ main_i2c5_pins_default: main-i2c5-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x150, PIN_INPUT_PULLUP, 2) /* (Y26) PRG0_MDIO0_MDIO.I2C5_SCL */
+ J721E_IOPAD(0x154, PIN_INPUT_PULLUP, 2) /* (AA27) PRG0_MDIO0_MDC.I2C5_SDA */
+ >;
+ };
+
+ rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x01C, PIN_INPUT, 7) /* (AD22) PRG1_PRU0_GPO6.GPIO0_7 */
+ J721E_IOPAD(0x120, PIN_INPUT, 7) /* (AA28) PRG0_PRU1_GPO8.GPIO0_71 */
+ J721E_IOPAD(0x14C, PIN_INPUT, 7) /* (AA29) PRG0_PRU1_GPO19.GPIO0_82 */
+ J721E_IOPAD(0x02C, PIN_INPUT, 7) /* (AD21) PRG1_PRU0_GPO10.GPIO0_11 */
+ J721E_IOPAD(0x198, PIN_INPUT, 7) /* (V25) RGMII6_TD1.GPIO0_101 */
+ J721E_IOPAD(0x1B0, PIN_INPUT, 7) /* (W24) RGMII6_RD1.GPIO0_107 */
+ J721E_IOPAD(0x1A0, PIN_INPUT, 7) /* (W29) RGMII6_TXC.GPIO0_103 */
+ J721E_IOPAD(0x008, PIN_INPUT, 7) /* (AG22) PRG1_PRU0_GPO1.GPIO0_2 */
+ J721E_IOPAD(0x1D0, PIN_INPUT, 7) /* (AA3) SPI0_D1.GPIO0_115 */
+ J721E_IOPAD(0x11C, PIN_INPUT, 7) /* (AA24) PRG0_PRU1_GPO7.GPIO0_70 */
+ J721E_IOPAD(0x148, PIN_INPUT, 7) /* (AA26) PRG0_PRU1_GPO18.GPIO0_81 */
+ J721E_IOPAD(0x004, PIN_INPUT, 7) /* (AC23) PRG1_PRU0_GPO0.GPIO0_1 */
+ J721E_IOPAD(0x014, PIN_INPUT, 7) /* (AH23) PRG1_PRU0_GPO4.GPIO0_5 */
+ J721E_IOPAD(0x020, PIN_INPUT, 7) /* (AE20) PRG1_PRU0_GPO7.GPIO0_8 */
+ J721E_IOPAD(0x19C, PIN_INPUT, 7) /* (W27) RGMII6_TD0.GPIO0_102 */
+ J721E_IOPAD(0x1B4, PIN_INPUT, 7) /* (W25) RGMII6_RD0.GPIO0_108 */
+ J721E_IOPAD(0x188, PIN_INPUT, 7) /* (Y28) RGMII6_TX_CTL.GPIO0_97 */
+ J721E_IOPAD(0x00C, PIN_INPUT, 7) /* (AF22) PRG1_PRU0_GPO2.GPIO0_3 */
+ J721E_IOPAD(0x010, PIN_INPUT, 7) /* (AJ23) PRG1_PRU0_GPO3.GPIO0_4 */
+ J721E_IOPAD(0x178, PIN_INPUT, 7) /* (U27) RGMII5_RD3.GPIO0_93 */
+ J721E_IOPAD(0x17C, PIN_INPUT, 7) /* (U24) RGMII5_RD2.GPIO0_94 */
+ J721E_IOPAD(0x190, PIN_INPUT, 7) /* (W23) RGMII6_TD3.GPIO0_99 */
+ J721E_IOPAD(0x18C, PIN_INPUT, 7) /* (V23) RGMII6_RX_CTL.GPIO0_98 */
+ >;
+ };
+
+ rpi_header_gpio1_pins_default: rpi-header-gpio1-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x234, PIN_INPUT, 7) /* (U3) EXT_REFCLK1.GPIO1_12 */
+ >;
+ };
};
&wkup_pmx0 {
@@ -475,46 +516,22 @@
status = "reserved";
};
+&mcu_uart0 {
+ status = "okay";
+ /* Default pinmux */
+};
+
&main_uart0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart0_pins_default>;
/* Shared with ATF on this platform */
power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
};
-&main_uart2 {
- /* Brought out on RPi header */
- status = "disabled";
-};
-
-&main_uart3 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart5 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart6 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart7 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart8 {
- /* UART not brought out */
- status = "disabled";
-};
-
-&main_uart9 {
- /* Brought out on M.2 E Key */
- status = "disabled";
+&main_uart1 {
+ status = "okay";
+ /* Default pinmux */
};
&main_sdhci0 {
@@ -561,6 +578,7 @@
};
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -588,18 +606,15 @@
};
&main_i2c1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c1_pins_default>;
/* i2c1 is used for DVI DDC, so we need to use 100kHz */
clock-frequency = <100000>;
};
-&main_i2c2 {
- /* Unused */
- status = "disabled";
-};
-
&main_i2c3 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c3_pins_default>;
clock-frequency = <400000>;
@@ -626,19 +641,22 @@
};
};
-&main_i2c4 {
- /* Unused */
- status = "disabled";
-};
-
&main_i2c5 {
/* Brought out on RPi Header */
- status = "disabled";
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c5_pins_default>;
+ clock-frequency = <400000>;
};
-&main_i2c6 {
- /* Unused */
- status = "disabled";
+&main_gpio0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rpi_header_gpio0_pins_default>;
+};
+
+&main_gpio1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rpi_header_gpio1_pins_default>;
};
&main_gpio2 {
@@ -837,66 +855,6 @@
};
};
-&mcasp0 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp1 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp2 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp3 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp4 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp5 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp6 {
- /* Brought out on RPi header */
- status = "disabled";
-};
-
-&mcasp7 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp8 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp9 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp10 {
- /* Unused */
- status = "disabled";
-};
-
-&mcasp11 {
- /* Brought out on M.2 E Key */
- status = "disabled";
-};
-
&serdes0 {
serdes0_pcie_link: phy@0 {
reg = <0>;
@@ -984,6 +942,7 @@
};
&mailbox0_cluster0 {
+ status = "okay";
interrupts = <436>;
mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
@@ -998,6 +957,7 @@
};
&mailbox0_cluster1 {
+ status = "okay";
interrupts = <432>;
mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
@@ -1012,6 +972,7 @@
};
&mailbox0_cluster2 {
+ status = "okay";
interrupts = <428>;
mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
@@ -1026,6 +987,7 @@
};
&mailbox0_cluster3 {
+ status = "okay";
interrupts = <424>;
mbox_c66_0: mbox-c66-0 {
@@ -1040,6 +1002,7 @@
};
&mailbox0_cluster4 {
+ status = "okay";
interrupts = <420>;
mbox_c71_0: mbox-c71-0 {
@@ -1048,34 +1011,6 @@
};
};
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
&mcu_r5fss0_core0 {
mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
index e36335232cf8..e289d5b44356 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
@@ -186,6 +186,7 @@
};
&mailbox0_cluster0 {
+ status = "okay";
interrupts = <436>;
mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
@@ -200,6 +201,7 @@
};
&mailbox0_cluster1 {
+ status = "okay";
interrupts = <432>;
mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
@@ -214,6 +216,7 @@
};
&mailbox0_cluster2 {
+ status = "okay";
interrupts = <428>;
mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
@@ -228,6 +231,7 @@
};
&mailbox0_cluster3 {
+ status = "okay";
interrupts = <424>;
mbox_c66_0: mbox-c66-0 {
@@ -242,6 +246,7 @@
};
&mailbox0_cluster4 {
+ status = "okay";
interrupts = <420>;
mbox_c71_0: mbox-c71-0 {
@@ -250,34 +255,6 @@
};
};
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
&mcu_r5fss0_core0 {
mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
index b210cc07c539..a7aa6cf08acd 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
@@ -219,49 +219,19 @@
status = "reserved";
};
-&main_uart0 {
- status = "disabled";
-};
-
-&main_uart1 {
- status = "disabled";
-};
-
-&main_uart2 {
- status = "disabled";
-};
-
-&main_uart3 {
- status = "disabled";
-};
-
-&main_uart4 {
- status = "disabled";
-};
-
-&main_uart5 {
- status = "disabled";
-};
-
-&main_uart6 {
- status = "disabled";
-};
-
-&main_uart7 {
- status = "disabled";
+&mcu_uart0 {
+ status = "okay";
+ /* Default pinmux */
};
&main_uart8 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_uart8_pins_default>;
/* Shared with TFA on this platform */
power-domains = <&k3_pds 357 TI_SCI_PD_SHARED>;
};
-&main_uart9 {
- status = "disabled";
-};
-
&main_i2c0 {
clock-frequency = <400000>;
@@ -291,30 +261,6 @@
};
};
-&main_i2c1 {
- status = "disabled";
-};
-
-&main_i2c2 {
- status = "disabled";
-};
-
-&main_i2c3 {
- status = "disabled";
-};
-
-&main_i2c4 {
- status = "disabled";
-};
-
-&main_i2c5 {
- status = "disabled";
-};
-
-&main_i2c6 {
- status = "disabled";
-};
-
&main_sdhci0 {
/* eMMC */
non-removable;
@@ -351,81 +297,15 @@
};
&mcu_mcan0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_mcan0_pins_default>;
phys = <&transceiver1>;
};
&mcu_mcan1 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcu_mcan1_pins_default>;
phys = <&transceiver2>;
};
-
-&main_mcan0 {
- status = "disabled";
-};
-
-&main_mcan1 {
- status = "disabled";
-};
-
-&main_mcan2 {
- status = "disabled";
-};
-
-&main_mcan3 {
- status = "disabled";
-};
-
-&main_mcan4 {
- status = "disabled";
-};
-
-&main_mcan5 {
- status = "disabled";
-};
-
-&main_mcan6 {
- status = "disabled";
-};
-
-&main_mcan7 {
- status = "disabled";
-};
-
-&main_mcan8 {
- status = "disabled";
-};
-
-&main_mcan9 {
- status = "disabled";
-};
-
-&main_mcan10 {
- status = "disabled";
-};
-
-&main_mcan11 {
- status = "disabled";
-};
-
-&main_mcan12 {
- status = "disabled";
-};
-
-&main_mcan13 {
- status = "disabled";
-};
-
-&main_mcan14 {
- status = "disabled";
-};
-
-&main_mcan15 {
- status = "disabled";
-};
-
-&main_mcan17 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
index 34e7d577ae13..8915132efcc1 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
@@ -60,7 +60,7 @@
#interrupt-cells = <1>;
ti,sci = <&sms>;
ti,sci-dev-id = <148>;
- ti,interrupt-ranges = <8 360 56>;
+ ti,interrupt-ranges = <8 392 56>;
};
main_pmx0: pinctrl@11c000 {
@@ -72,6 +72,25 @@
pinctrl-single,function-mask = <0xffffffff>;
};
+ main_crypto: crypto@4e00000 {
+ compatible = "ti,j721e-sa2ul";
+ reg = <0x00 0x04e00000 0x00 0x1200>;
+ power-domains = <&k3_pds 297 TI_SCI_PD_EXCLUSIVE>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x00 0x04e00000 0x00 0x04e00000 0x00 0x30000>;
+
+ dmas = <&main_udmap 0xca40>, <&main_udmap 0x4a40>,
+ <&main_udmap 0x4a41>;
+ dma-names = "tx", "rx1", "rx2";
+
+ rng: rng@4e10000 {
+ compatible = "inside-secure,safexcel-eip76";
+ reg = <0x00 0x04e10000 0x00 0x7d>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
main_uart0: serial@2800000 {
compatible = "ti,j721e-uart", "ti,am654-uart";
reg = <0x00 0x02800000 0x00 0x200>;
@@ -80,6 +99,7 @@
clocks = <&k3_clks 146 3>;
clock-names = "fclk";
power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart1: serial@2810000 {
@@ -90,6 +110,7 @@
clocks = <&k3_clks 350 3>;
clock-names = "fclk";
power-domains = <&k3_pds 350 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart2: serial@2820000 {
@@ -100,6 +121,7 @@
clocks = <&k3_clks 351 3>;
clock-names = "fclk";
power-domains = <&k3_pds 351 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart3: serial@2830000 {
@@ -110,6 +132,7 @@
clocks = <&k3_clks 352 3>;
clock-names = "fclk";
power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart4: serial@2840000 {
@@ -120,6 +143,7 @@
clocks = <&k3_clks 353 3>;
clock-names = "fclk";
power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart5: serial@2850000 {
@@ -130,6 +154,7 @@
clocks = <&k3_clks 354 3>;
clock-names = "fclk";
power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart6: serial@2860000 {
@@ -140,6 +165,7 @@
clocks = <&k3_clks 355 3>;
clock-names = "fclk";
power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart7: serial@2870000 {
@@ -150,6 +176,7 @@
clocks = <&k3_clks 356 3>;
clock-names = "fclk";
power-domains = <&k3_pds 356 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart8: serial@2880000 {
@@ -160,6 +187,7 @@
clocks = <&k3_clks 357 3>;
clock-names = "fclk";
power-domains = <&k3_pds 357 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_uart9: serial@2890000 {
@@ -170,6 +198,7 @@
clocks = <&k3_clks 358 3>;
clock-names = "fclk";
power-domains = <&k3_pds 358 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_gpio0: gpio@600000 {
@@ -256,6 +285,7 @@
clocks = <&k3_clks 215 1>;
clock-names = "fck";
power-domains = <&k3_pds 215 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c2: i2c@2020000 {
@@ -267,6 +297,7 @@
clocks = <&k3_clks 216 1>;
clock-names = "fck";
power-domains = <&k3_pds 216 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c3: i2c@2030000 {
@@ -278,6 +309,7 @@
clocks = <&k3_clks 217 1>;
clock-names = "fck";
power-domains = <&k3_pds 217 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c4: i2c@2040000 {
@@ -289,6 +321,7 @@
clocks = <&k3_clks 218 1>;
clock-names = "fck";
power-domains = <&k3_pds 218 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c5: i2c@2050000 {
@@ -300,6 +333,7 @@
clocks = <&k3_clks 219 1>;
clock-names = "fck";
power-domains = <&k3_pds 219 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_i2c6: i2c@2060000 {
@@ -311,6 +345,7 @@
clocks = <&k3_clks 220 1>;
clock-names = "fck";
power-domains = <&k3_pds 220 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
main_sdhci0: mmc@4f80000 {
@@ -428,6 +463,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster1: mailbox@31f81000 {
@@ -437,6 +473,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster2: mailbox@31f82000 {
@@ -446,6 +483,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster3: mailbox@31f83000 {
@@ -455,6 +493,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster4: mailbox@31f84000 {
@@ -464,6 +503,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster5: mailbox@31f85000 {
@@ -473,6 +513,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster6: mailbox@31f86000 {
@@ -482,6 +523,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster7: mailbox@31f87000 {
@@ -491,6 +533,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster8: mailbox@31f88000 {
@@ -500,6 +543,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster9: mailbox@31f89000 {
@@ -509,6 +553,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster10: mailbox@31f8a000 {
@@ -518,6 +563,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox0_cluster11: mailbox@31f8b000 {
@@ -527,6 +573,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster0: mailbox@31f90000 {
@@ -536,6 +583,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster1: mailbox@31f91000 {
@@ -545,6 +593,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster2: mailbox@31f92000 {
@@ -554,6 +603,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster3: mailbox@31f93000 {
@@ -563,6 +613,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster4: mailbox@31f94000 {
@@ -572,6 +623,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster5: mailbox@31f95000 {
@@ -581,6 +633,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster6: mailbox@31f96000 {
@@ -590,6 +643,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster7: mailbox@31f97000 {
@@ -599,6 +653,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster8: mailbox@31f98000 {
@@ -608,6 +663,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster9: mailbox@31f99000 {
@@ -617,6 +673,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster10: mailbox@31f9a000 {
@@ -626,6 +683,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
mailbox1_cluster11: mailbox@31f9b000 {
@@ -635,6 +693,7 @@
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <16>;
interrupt-parent = <&main_navss_intr>;
+ status = "disabled";
};
main_ringacc: ringacc@3c000000 {
@@ -698,6 +757,7 @@
<GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan1: can@2711000 {
@@ -712,6 +772,7 @@
<GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan2: can@2721000 {
@@ -726,6 +787,7 @@
<GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan3: can@2731000 {
@@ -740,6 +802,7 @@
<GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan4: can@2741000 {
@@ -754,6 +817,7 @@
<GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan5: can@2751000 {
@@ -768,6 +832,7 @@
<GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan6: can@2761000 {
@@ -782,6 +847,7 @@
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan7: can@2771000 {
@@ -796,6 +862,7 @@
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan8: can@2781000 {
@@ -810,6 +877,7 @@
<GIC_SPI 577 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan9: can@2791000 {
@@ -824,6 +892,7 @@
<GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan10: can@27a1000 {
@@ -838,6 +907,7 @@
<GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan11: can@27b1000 {
@@ -852,6 +922,7 @@
<GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan12: can@27c1000 {
@@ -866,6 +937,7 @@
<GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan13: can@27d1000 {
@@ -880,6 +952,7 @@
<GIC_SPI 592 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan14: can@2681000 {
@@ -894,6 +967,7 @@
<GIC_SPI 595 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan15: can@2691000 {
@@ -908,6 +982,7 @@
<GIC_SPI 598 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan16: can@26a1000 {
@@ -922,6 +997,7 @@
<GIC_SPI 785 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
main_mcan17: can@26b1000 {
@@ -936,5 +1012,6 @@
<GIC_SPI 788 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
index 4d1bfabd1313..0af242aa9816 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
@@ -65,7 +65,7 @@
#interrupt-cells = <1>;
ti,sci = <&sms>;
ti,sci-dev-id = <125>;
- ti,interrupt-ranges = <16 928 16>;
+ ti,interrupt-ranges = <16 960 16>;
};
mcu_conf: syscon@40f00000 {
@@ -91,6 +91,7 @@
clocks = <&k3_clks 359 3>;
clock-names = "fclk";
power-domains = <&k3_pds 359 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_uart0: serial@40a00000 {
@@ -101,6 +102,7 @@
clocks = <&k3_clks 149 3>;
clock-names = "fclk";
power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
wkup_gpio0: gpio@42110000 {
@@ -144,6 +146,7 @@
clocks = <&k3_clks 223 1>;
clock-names = "fck";
power-domains = <&k3_pds 223 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_i2c0: i2c@40b00000 {
@@ -155,6 +158,7 @@
clocks = <&k3_clks 221 1>;
clock-names = "fck";
power-domains = <&k3_pds 221 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_i2c1: i2c@40b10000 {
@@ -166,6 +170,7 @@
clocks = <&k3_clks 222 1>;
clock-names = "fck";
power-domains = <&k3_pds 222 TI_SCI_PD_EXCLUSIVE>;
+ status = "disabled";
};
mcu_mcan0: can@40528000 {
@@ -180,6 +185,7 @@
<GIC_SPI 833 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
mcu_mcan1: can@40568000 {
@@ -194,6 +200,7 @@
<GIC_SPI 836 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "int0", "int1";
bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+ status = "disabled";
};
mcu_navss: bus@28380000{
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
index 76f0ceacb6d4..6930efff8a5a 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
@@ -56,6 +56,7 @@
};
&main_i2c0 {
+ status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&main_i2c0_pins_default>;
clock-frequency = <400000>;
@@ -73,103 +74,8 @@
};
&main_mcan16 {
+ status = "okay";
pinctrl-0 = <&main_mcan16_pins_default>;
pinctrl-names = "default";
phys = <&transceiver0>;
};
-
-&mailbox0_cluster0 {
- status = "disabled";
-};
-
-&mailbox0_cluster1 {
- status = "disabled";
-};
-
-&mailbox0_cluster2 {
- status = "disabled";
-};
-
-&mailbox0_cluster3 {
- status = "disabled";
-};
-
-&mailbox0_cluster4 {
- status = "disabled";
-};
-
-&mailbox0_cluster5 {
- status = "disabled";
-};
-
-&mailbox0_cluster6 {
- status = "disabled";
-};
-
-&mailbox0_cluster7 {
- status = "disabled";
-};
-
-&mailbox0_cluster8 {
- status = "disabled";
-};
-
-&mailbox0_cluster9 {
- status = "disabled";
-};
-
-&mailbox0_cluster10 {
- status = "disabled";
-};
-
-&mailbox0_cluster11 {
- status = "disabled";
-};
-
-&mailbox1_cluster0 {
- status = "disabled";
-};
-
-&mailbox1_cluster1 {
- status = "disabled";
-};
-
-&mailbox1_cluster2 {
- status = "disabled";
-};
-
-&mailbox1_cluster3 {
- status = "disabled";
-};
-
-&mailbox1_cluster4 {
- status = "disabled";
-};
-
-&mailbox1_cluster5 {
- status = "disabled";
-};
-
-&mailbox1_cluster6 {
- status = "disabled";
-};
-
-&mailbox1_cluster7 {
- status = "disabled";
-};
-
-&mailbox1_cluster8 {
- status = "disabled";
-};
-
-&mailbox1_cluster9 {
- status = "disabled";
-};
-
-&mailbox1_cluster10 {
- status = "disabled";
-};
-
-&mailbox1_cluster11 {
- status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
index e2dd72fe33ce..24a252317150 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
@@ -150,6 +150,18 @@
#clock-cells = <0>;
clock-frequency = <114285000>;
};
+
+ dpcon {
+ compatible = "dp-connector";
+ label = "P11";
+ type = "full-size";
+
+ port {
+ dpcon_in: endpoint {
+ remote-endpoint = <&dpsub_dp_out>;
+ };
+ };
+ };
};
&can1 {
@@ -1015,4 +1027,12 @@
phy-names = "dp-phy0", "dp-phy1";
phys = <&psgtr 1 PHY_TYPE_DP 0 3>,
<&psgtr 0 PHY_TYPE_DP 1 3>;
+
+ ports {
+ port@5 {
+ dpsub_dp_out: endpoint {
+ remote-endpoint = <&dpcon_in>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
index a549265e55f6..307c76cd8544 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -930,6 +930,30 @@
<&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO1>,
<&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO2>,
<&zynqmp_dpdma ZYNQMP_DPDMA_GRAPHICS>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+ port@1 {
+ reg = <1>;
+ };
+ port@2 {
+ reg = <2>;
+ };
+ port@3 {
+ reg = <3>;
+ };
+ port@4 {
+ reg = <4>;
+ };
+ port@5 {
+ reg = <5>;
+ };
+ };
};
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0b6af3348e79..851e8f9be06d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -357,6 +357,7 @@ CONFIG_RMNET=m
CONFIG_R8169=m
CONFIG_SH_ETH=y
CONFIG_RAVB=y
+CONFIG_RENESAS_ETHER_SWITCH=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
CONFIG_SNI_AVE=y
@@ -369,7 +370,7 @@ CONFIG_MESON_GXL_PHY=m
CONFIG_AQUANTIA_PHY=y
CONFIG_BCM54140_PHY=m
CONFIG_MARVELL_PHY=m
-CONFIG_MARVELL_10G_PHY=m
+CONFIG_MARVELL_10G_PHY=y
CONFIG_MICREL_PHY=y
CONFIG_MICROSEMI_PHY=y
CONFIG_AT803X_PHY=y
@@ -392,6 +393,7 @@ CONFIG_USB_NET_PLUSB=m
CONFIG_USB_NET_MCS7830=m
CONFIG_ATH10K=m
CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K_SDIO=m
CONFIG_ATH10K_SNOC=m
CONFIG_WCN36XX=m
CONFIG_ATH11K=m
@@ -412,6 +414,7 @@ CONFIG_KEYBOARD_CROS_EC=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=m
CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_ELAN=m
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PM8941_PWRKEY=y
@@ -462,6 +465,10 @@ CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_TCG_TPM=y
+CONFIG_TCG_TIS=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_TCG_TIS_SPI_CR50=y
+CONFIG_TCG_TIS_I2C_CR50=m
CONFIG_TCG_TIS_I2C_INFINEON=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
@@ -505,6 +512,7 @@ CONFIG_SPI_IMX=m
CONFIG_SPI_FSL_DSPI=y
CONFIG_SPI_MESON_SPICC=m
CONFIG_SPI_MESON_SPIFC=m
+CONFIG_SPI_MT65XX=y
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
CONFIG_SPI_ROCKCHIP=y
@@ -538,9 +546,12 @@ CONFIG_PINCTRL_MSM=y
CONFIG_PINCTRL_IPQ8074=y
CONFIG_PINCTRL_IPQ6018=y
CONFIG_PINCTRL_MSM8916=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8976=y
CONFIG_PINCTRL_MSM8994=y
CONFIG_PINCTRL_MSM8996=y
CONFIG_PINCTRL_MSM8998=y
+CONFIG_PINCTRL_QCM2290=y
CONFIG_PINCTRL_QCS404=y
CONFIG_PINCTRL_QDF2XXX=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
@@ -549,6 +560,7 @@ CONFIG_PINCTRL_SC7280=y
CONFIG_PINCTRL_SC8180X=y
CONFIG_PINCTRL_SC8280XP=y
CONFIG_PINCTRL_SDM845=y
+CONFIG_PINCTRL_SM6115=y
CONFIG_PINCTRL_SM8150=y
CONFIG_PINCTRL_SM8250=y
CONFIG_PINCTRL_SM8350=y
@@ -614,6 +626,7 @@ CONFIG_BRCMSTB_THERMAL=m
CONFIG_EXYNOS_THERMAL=y
CONFIG_TEGRA_SOCTHERM=m
CONFIG_TEGRA_BPMP_THERMAL=m
+CONFIG_GENERIC_ADC_THERMAL=m
CONFIG_QCOM_TSENS=y
CONFIG_QCOM_SPMI_ADC_TM5=m
CONFIG_QCOM_SPMI_TEMP_ALARM=m
@@ -698,6 +711,7 @@ CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SDR_PLATFORM_DRIVERS=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MEDIATEK_JPEG=m
CONFIG_VIDEO_QCOM_CAMSS=m
CONFIG_VIDEO_QCOM_VENUS=m
CONFIG_VIDEO_RCAR_ISP=m
@@ -759,7 +773,9 @@ CONFIG_DRM_PARADE_PS8640=m
CONFIG_DRM_SII902X=m
CONFIG_DRM_SIMPLE_BRIDGE=m
CONFIG_DRM_THINE_THC63LVD1024=m
+CONFIG_DRM_TI_TFP410=m
CONFIG_DRM_TI_SN65DSI86=m
+CONFIG_DRM_ANALOGIX_ANX7625=m
CONFIG_DRM_I2C_ADV7511=m
CONFIG_DRM_I2C_ADV7511_AUDIO=y
CONFIG_DRM_CDNS_MHDP8546=m
@@ -789,6 +805,7 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=y
+CONFIG_SND_ALOOP=m
CONFIG_SND_HDA_TEGRA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_SOC=y
@@ -801,6 +818,9 @@ CONFIG_SND_SOC_IMX_SGTL5000=m
CONFIG_SND_SOC_IMX_SPDIF=m
CONFIG_SND_SOC_FSL_ASOC_CARD=m
CONFIG_SND_SOC_IMX_AUDMIX=m
+CONFIG_SND_SOC_MT8183=m
+CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=m
+CONFIG_SND_SOC_MT8183_DA7219_MAX98357A=m
CONFIG_SND_MESON_AXG_SOUND_CARD=m
CONFIG_SND_MESON_GX_SOUND_CARD=m
CONFIG_SND_SOC_QCOM=m
@@ -843,9 +863,11 @@ CONFIG_SND_SOC_GTM601=m
CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m
CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m
CONFIG_SND_SOC_PCM3168A_I2C=m
+CONFIG_SND_SOC_RT5640=m
CONFIG_SND_SOC_RT5659=m
CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m
CONFIG_SND_SOC_SIMPLE_MUX=m
+CONFIG_SND_SOC_TAS2552=m
CONFIG_SND_SOC_TAS571X=m
CONFIG_SND_SOC_TLV320AIC32X4_I2C=m
CONFIG_SND_SOC_WCD9335=m
@@ -1003,6 +1025,7 @@ CONFIG_RTC_DRV_SNVS=m
CONFIG_RTC_DRV_IMX_SC=m
CONFIG_RTC_DRV_MT6397=m
CONFIG_RTC_DRV_XGENE=y
+CONFIG_TEGRA186_TIMER=y
CONFIG_DMADEVICES=y
CONFIG_DMA_BCM2835=y
CONFIG_DMA_SUN6I=m
@@ -1049,6 +1072,7 @@ CONFIG_COMMON_CLK_CS2000_CP=y
CONFIG_COMMON_CLK_FSL_SAI=y
CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_COMMON_CLK_PWM=y
+CONFIG_COMMON_CLK_RS9_PCIE=y
CONFIG_COMMON_CLK_VC5=y
CONFIG_COMMON_CLK_NPCM8XX=y
CONFIG_COMMON_CLK_BD718XX=m
@@ -1083,6 +1107,7 @@ CONFIG_SDM_GPUCC_845=y
CONFIG_SDM_VIDEOCC_845=y
CONFIG_SDM_DISPCC_845=y
CONFIG_SM_DISPCC_8250=y
+CONFIG_SM_GCC_6115=y
CONFIG_SM_GCC_8350=y
CONFIG_SM_GCC_8450=y
CONFIG_SM_GPUCC_8150=y
@@ -1107,6 +1132,7 @@ CONFIG_ARM_SMMU_V3=y
CONFIG_MTK_IOMMU=y
CONFIG_QCOM_IOMMU=y
CONFIG_REMOTEPROC=y
+CONFIG_MTK_SCP=m
CONFIG_QCOM_Q6V5_ADSP=m
CONFIG_QCOM_Q6V5_MSS=m
CONFIG_QCOM_Q6V5_PAS=m
@@ -1124,8 +1150,10 @@ CONFIG_RASPBERRYPI_POWER=y
CONFIG_FSL_DPAA=y
CONFIG_FSL_MC_DPIO=y
CONFIG_FSL_RCPM=y
+CONFIG_MTK_CMDQ=m
CONFIG_MTK_DEVAPC=m
CONFIG_MTK_PMIC_WRAP=y
+CONFIG_MTK_SVS=m
CONFIG_QCOM_AOSS_QMP=y
CONFIG_QCOM_COMMAND_DB=y
CONFIG_QCOM_CPR=y
@@ -1176,6 +1204,7 @@ CONFIG_ARCH_TEGRA_234_SOC=y
CONFIG_TI_SCI_PM_DOMAINS=y
CONFIG_ARM_IMX_BUS_DEVFREQ=m
CONFIG_ARM_IMX8M_DDRC_DEVFREQ=m
+CONFIG_ARM_MEDIATEK_CCI_DEVFREQ=m
CONFIG_EXTCON_PTN5150=m
CONFIG_EXTCON_USB_GPIO=y
CONFIG_EXTCON_USBC_CROS_EC=y
@@ -1183,6 +1212,7 @@ CONFIG_RENESAS_RPCIF=m
CONFIG_IIO=y
CONFIG_EXYNOS_ADC=y
CONFIG_MAX9611=m
+CONFIG_MEDIATEK_MT6577_AUXADC=m
CONFIG_QCOM_SPMI_VADC=m
CONFIG_QCOM_SPMI_ADC5=m
CONFIG_ROCKCHIP_SARADC=m
@@ -1239,6 +1269,7 @@ CONFIG_PHY_QCOM_USB_HS=m
CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m
CONFIG_PHY_QCOM_USB_HS_28NM=m
CONFIG_PHY_QCOM_USB_SS=m
+CONFIG_PHY_R8A779F0_ETHERNET_SERDES=y
CONFIG_PHY_RCAR_GEN3_PCIE=y
CONFIG_PHY_RCAR_GEN3_USB2=y
CONFIG_PHY_RCAR_GEN3_USB3=m
@@ -1270,6 +1301,7 @@ CONFIG_NVMEM_IMX_OCOTP_SCU=y
CONFIG_NVMEM_MTK_EFUSE=y
CONFIG_NVMEM_QCOM_QFPROM=y
CONFIG_NVMEM_ROCKCHIP_EFUSE=y
+CONFIG_NVMEM_SNVS_LPGPR=y
CONFIG_NVMEM_SUNXI_SID=y
CONFIG_NVMEM_UNIPHIER_EFUSE=y
CONFIG_NVMEM_MESON_EFUSE=m
@@ -1293,12 +1325,13 @@ CONFIG_INTERCONNECT_IMX=m
CONFIG_INTERCONNECT_IMX8MM=m
CONFIG_INTERCONNECT_IMX8MN=m
CONFIG_INTERCONNECT_IMX8MQ=m
+CONFIG_INTERCONNECT_IMX8MP=m
CONFIG_INTERCONNECT_QCOM=y
CONFIG_INTERCONNECT_QCOM_MSM8916=m
CONFIG_INTERCONNECT_QCOM_MSM8996=m
CONFIG_INTERCONNECT_QCOM_OSM_L3=m
CONFIG_INTERCONNECT_QCOM_QCS404=m
-CONFIG_INTERCONNECT_QCOM_SC7180=m
+CONFIG_INTERCONNECT_QCOM_SC7180=y
CONFIG_INTERCONNECT_QCOM_SC7280=y
CONFIG_INTERCONNECT_QCOM_SC8180X=y
CONFIG_INTERCONNECT_QCOM_SC8280XP=y
@@ -1306,7 +1339,10 @@ CONFIG_INTERCONNECT_QCOM_SDM845=y
CONFIG_INTERCONNECT_QCOM_SM8150=m
CONFIG_INTERCONNECT_QCOM_SM8250=m
CONFIG_INTERCONNECT_QCOM_SM8350=m
-CONFIG_INTERCONNECT_QCOM_SM8450=m
+CONFIG_INTERCONNECT_QCOM_SM8450=y
+CONFIG_HTE=y
+CONFIG_HTE_TEGRA194=y
+CONFIG_HTE_TEGRA194_TEST=m
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
@@ -1341,6 +1377,7 @@ CONFIG_CRYPTO_USER_API_RNG=m
CONFIG_CRYPTO_DEV_SUN8I_CE=m
CONFIG_CRYPTO_DEV_FSL_CAAM=m
CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=m
+CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCOM_RNG=m
CONFIG_CRYPTO_DEV_CCREE=m
CONFIG_CRYPTO_DEV_HISI_SEC2=m
diff --git a/arch/arm64/include/asm/alternative-macros.h b/arch/arm64/include/asm/alternative-macros.h
index 3622e9f4fb44..bdf1f6bcd010 100644
--- a/arch/arm64/include/asm/alternative-macros.h
+++ b/arch/arm64/include/asm/alternative-macros.h
@@ -224,7 +224,7 @@ alternative_endif
#include <linux/types.h>
static __always_inline bool
-alternative_has_feature_likely(unsigned long feature)
+alternative_has_feature_likely(const unsigned long feature)
{
compiletime_assert(feature < ARM64_NCAPS,
"feature must be < ARM64_NCAPS");
@@ -242,7 +242,7 @@ l_no:
}
static __always_inline bool
-alternative_has_feature_unlikely(unsigned long feature)
+alternative_has_feature_unlikely(const unsigned long feature)
{
compiletime_assert(feature < ARM64_NCAPS,
"feature must be < ARM64_NCAPS");
diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h
index 109e2a4454be..2f5f3da34782 100644
--- a/arch/arm64/include/asm/archrandom.h
+++ b/arch/arm64/include/asm/archrandom.h
@@ -5,6 +5,7 @@
#include <linux/arm-smccc.h>
#include <linux/bug.h>
#include <linux/kernel.h>
+#include <linux/irqflags.h>
#include <asm/cpufeature.h>
#define ARM_SMCCC_TRNG_MIN_VERSION 0x10000UL
@@ -58,6 +59,13 @@ static inline bool __arm64_rndrrs(unsigned long *v)
return ok;
}
+static __always_inline bool __cpu_has_rng(void)
+{
+ if (unlikely(!system_capabilities_finalized() && !preemptible()))
+ return this_cpu_has_cap(ARM64_HAS_RNG);
+ return cpus_have_const_cap(ARM64_HAS_RNG);
+}
+
static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
{
/*
@@ -66,7 +74,7 @@ static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t
* cpufeature code and with potential scheduling between CPUs
* with and without the feature.
*/
- if (max_longs && cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
+ if (max_longs && __cpu_has_rng() && __arm64_rndr(v))
return 1;
return 0;
}
@@ -108,7 +116,7 @@ static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, s
* reseeded after each invocation. This is not a 100% fit but good
* enough to implement this API if no other entropy source exists.
*/
- if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndrrs(v))
+ if (__cpu_has_rng() && __arm64_rndrrs(v))
return 1;
return 0;
@@ -121,40 +129,4 @@ static inline bool __init __early_cpu_has_rndr(void)
return (ftr >> ID_AA64ISAR0_EL1_RNDR_SHIFT) & 0xf;
}
-static inline size_t __init __must_check
-arch_get_random_seed_longs_early(unsigned long *v, size_t max_longs)
-{
- WARN_ON(system_state != SYSTEM_BOOTING);
-
- if (!max_longs)
- return 0;
-
- if (smccc_trng_available) {
- struct arm_smccc_res res;
-
- max_longs = min_t(size_t, 3, max_longs);
- arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, max_longs * 64, &res);
- if ((int)res.a0 >= 0) {
- switch (max_longs) {
- case 3:
- *v++ = res.a1;
- fallthrough;
- case 2:
- *v++ = res.a2;
- fallthrough;
- case 1:
- *v++ = res.a3;
- break;
- }
- return max_longs;
- }
- }
-
- if (__early_cpu_has_rndr() && __arm64_rndr(v))
- return 1;
-
- return 0;
-}
-#define arch_get_random_seed_longs_early arch_get_random_seed_longs_early
-
#endif /* _ASM_ARCHRANDOM_H */
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index e5957a53be39..376a980f2bad 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -34,11 +34,6 @@
wx\n .req w\n
.endr
- .macro save_and_disable_daif, flags
- mrs \flags, daif
- msr daifset, #0xf
- .endm
-
.macro disable_daif
msr daifset, #0xf
.endm
@@ -47,15 +42,6 @@
msr daifclr, #0xf
.endm
- .macro restore_daif, flags:req
- msr daif, \flags
- .endm
-
- /* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */
- .macro enable_da
- msr daifclr, #(8 | 4)
- .endm
-
/*
* Save/restore interrupts.
*/
@@ -620,17 +606,6 @@ alternative_endif
.endm
/*
- * Perform the reverse of offset_ttbr1.
- * bic is used as it can cover the immediate value and, in future, won't need
- * to be nop'ed out when dealing with 52-bit kernel VAs.
- */
- .macro restore_ttbr1, ttbr
-#ifdef CONFIG_ARM64_VA_BITS_52
- bic \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
-#endif
- .endm
-
-/*
* Arrange a physical address in a TTBR register, taking care of 52-bit
* addresses.
*
@@ -660,12 +635,10 @@ alternative_endif
.endm
.macro pte_to_phys, phys, pte
-#ifdef CONFIG_ARM64_PA_BITS_52
- ubfiz \phys, \pte, #(48 - 16 - 12), #16
- bfxil \phys, \pte, #16, #32
- lsl \phys, \phys, #16
-#else
and \phys, \pte, #PTE_ADDR_MASK
+#ifdef CONFIG_ARM64_PA_BITS_52
+ orr \phys, \phys, \phys, lsl #PTE_ADDR_HIGH_SHIFT
+ and \phys, \phys, GENMASK_ULL(PHYS_MASK_SHIFT - 1, PAGE_SHIFT)
#endif
.endm
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index f73f11b55042..03d1c9d7af82 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -832,7 +832,8 @@ static inline bool system_supports_tlb_range(void)
cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
}
-extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
+int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
+bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
{
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index abc418650fec..4e8b66c74ea2 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -41,7 +41,7 @@
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
#define MIDR_CPU_MODEL(imp, partnum) \
- (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \
+ ((_AT(u32, imp) << MIDR_IMPLEMENTOR_SHIFT) | \
(0xf << MIDR_ARCHITECTURE_SHIFT) | \
((partnum) << MIDR_PARTNUM_SHIFT))
@@ -80,6 +80,7 @@
#define ARM_CPU_PART_CORTEX_X1 0xD44
#define ARM_CPU_PART_CORTEX_A510 0xD46
#define ARM_CPU_PART_CORTEX_A710 0xD47
+#define ARM_CPU_PART_CORTEX_A715 0xD4D
#define ARM_CPU_PART_CORTEX_X2 0xD48
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
@@ -142,6 +143,7 @@
#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
+#define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715)
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index d6cf535d8352..439e2bc5d5d8 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -14,16 +14,8 @@
#ifdef CONFIG_EFI
extern void efi_init(void);
-
-bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg);
#else
#define efi_init()
-
-static inline
-bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
-{
- return false;
-}
#endif
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h
index 19713d0f013b..92963f98afec 100644
--- a/arch/arm64/include/asm/exception.h
+++ b/arch/arm64/include/asm/exception.h
@@ -58,7 +58,8 @@ asmlinkage void call_on_irq_stack(struct pt_regs *regs,
asmlinkage void asm_exit_to_user_mode(struct pt_regs *regs);
void do_mem_abort(unsigned long far, unsigned long esr, struct pt_regs *regs);
-void do_undefinstr(struct pt_regs *regs, unsigned long esr);
+void do_el0_undef(struct pt_regs *regs, unsigned long esr);
+void do_el1_undef(struct pt_regs *regs, unsigned long esr);
void do_el0_bti(struct pt_regs *regs);
void do_el1_bti(struct pt_regs *regs, unsigned long esr);
void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr,
@@ -67,10 +68,10 @@ void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs);
void do_sve_acc(unsigned long esr, struct pt_regs *regs);
void do_sme_acc(unsigned long esr, struct pt_regs *regs);
void do_fpsimd_exc(unsigned long esr, struct pt_regs *regs);
-void do_sysinstr(unsigned long esr, struct pt_regs *regs);
+void do_el0_sys(unsigned long esr, struct pt_regs *regs);
void do_sp_pc_abort(unsigned long addr, unsigned long esr, struct pt_regs *regs);
void bad_el0_sync(struct pt_regs *regs, int reason, unsigned long esr);
-void do_cp15instr(unsigned long esr, struct pt_regs *regs);
+void do_el0_cp15(unsigned long esr, struct pt_regs *regs);
int do_compat_alignment_fixup(unsigned long addr, struct pt_regs *regs);
void do_el0_svc(struct pt_regs *regs);
void do_el0_svc_compat(struct pt_regs *regs);
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 6f86b7ab6c28..e6fa1e2982c8 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -56,11 +56,20 @@ extern void fpsimd_signal_preserve_current_state(void);
extern void fpsimd_preserve_current_state(void);
extern void fpsimd_restore_current_state(void);
extern void fpsimd_update_current_state(struct user_fpsimd_state const *state);
+extern void fpsimd_kvm_prepare(void);
+
+struct cpu_fp_state {
+ struct user_fpsimd_state *st;
+ void *sve_state;
+ void *za_state;
+ u64 *svcr;
+ unsigned int sve_vl;
+ unsigned int sme_vl;
+ enum fp_type *fp_type;
+ enum fp_type to_save;
+};
-extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
- void *sve_state, unsigned int sve_vl,
- void *za_state, unsigned int sme_vl,
- u64 *svcr);
+extern void fpsimd_bind_state_to_cpu(struct cpu_fp_state *fp_state);
extern void fpsimd_flush_task_state(struct task_struct *target);
extern void fpsimd_save_and_flush_cpu_state(void);
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 329dbbd4d50b..5664729800ae 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -23,7 +23,7 @@
*/
#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
#define ARCH_SUPPORTS_FTRACE_OPS 1
#else
#define MCOUNT_ADDR ((unsigned long)_mcount)
@@ -33,8 +33,7 @@
#define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
#define FTRACE_PLT_IDX 0
-#define FTRACE_REGS_PLT_IDX 1
-#define NR_FTRACE_PLTS 2
+#define NR_FTRACE_PLTS 1
/*
* Currently, gcc tends to save the link register after the local variables
@@ -69,7 +68,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
* Adjust addr to point at the BL in the callsite.
* See ftrace_init_nop() for the callsite sequence.
*/
- if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
+ if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
return addr + AARCH64_INSN_SIZE;
/*
* addr is the address of the mcount call instruction.
@@ -78,10 +77,71 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
return addr;
}
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
struct dyn_ftrace;
struct ftrace_ops;
-struct ftrace_regs;
+
+#define arch_ftrace_get_regs(regs) NULL
+
+struct ftrace_regs {
+ /* x0 - x8 */
+ unsigned long regs[9];
+ unsigned long __unused;
+
+ unsigned long fp;
+ unsigned long lr;
+
+ unsigned long sp;
+ unsigned long pc;
+};
+
+static __always_inline unsigned long
+ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs)
+{
+ return fregs->pc;
+}
+
+static __always_inline void
+ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+ unsigned long pc)
+{
+ fregs->pc = pc;
+}
+
+static __always_inline unsigned long
+ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
+{
+ return fregs->sp;
+}
+
+static __always_inline unsigned long
+ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n)
+{
+ if (n < 8)
+ return fregs->regs[n];
+ return 0;
+}
+
+static __always_inline unsigned long
+ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
+{
+ return fregs->regs[0];
+}
+
+static __always_inline void
+ftrace_regs_set_return_value(struct ftrace_regs *fregs,
+ unsigned long ret)
+{
+ fregs->regs[0] = ret;
+}
+
+static __always_inline void
+ftrace_override_function_with_return(struct ftrace_regs *fregs)
+{
+ fregs->pc = fregs->lr;
+}
+
+int ftrace_regs_query_register_offset(const char *name);
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
#define ftrace_init_nop ftrace_init_nop
diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
index d20f5da2d76f..6a4a1ab8eb23 100644
--- a/arch/arm64/include/asm/hugetlb.h
+++ b/arch/arm64/include/asm/hugetlb.h
@@ -49,6 +49,15 @@ extern pte_t huge_ptep_get(pte_t *ptep);
void __init arm64_hugetlb_cma_reserve(void);
+#define huge_ptep_modify_prot_start huge_ptep_modify_prot_start
+extern pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep);
+
+#define huge_ptep_modify_prot_commit huge_ptep_modify_prot_commit
+extern void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t old_pte, pte_t new_pte);
+
#include <asm-generic/hugetlb.h>
#endif /* __ASM_HUGETLB_H */
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 298b386d3ebe..06dd12c514e6 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -120,6 +120,9 @@
#define KERNEL_HWCAP_WFXT __khwcap2_feature(WFXT)
#define KERNEL_HWCAP_EBF16 __khwcap2_feature(EBF16)
#define KERNEL_HWCAP_SVE_EBF16 __khwcap2_feature(SVE_EBF16)
+#define KERNEL_HWCAP_CSSC __khwcap2_feature(CSSC)
+#define KERNEL_HWCAP_RPRFM __khwcap2_feature(RPRFM)
+#define KERNEL_HWCAP_SVE2P1 __khwcap2_feature(SVE2P1)
/*
* This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 834bff720582..aaf1f52fbf3e 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -13,31 +13,6 @@
#include <asm/insn-def.h>
#ifndef __ASSEMBLY__
-/*
- * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
- * Section C3.1 "A64 instruction index by encoding":
- * AArch64 main encoding table
- * Bit position
- * 28 27 26 25 Encoding Group
- * 0 0 - - Unallocated
- * 1 0 0 - Data processing, immediate
- * 1 0 1 - Branch, exception generation and system instructions
- * - 1 - 0 Loads and stores
- * - 1 0 1 Data processing - register
- * 0 1 1 1 Data processing - SIMD and floating point
- * 1 1 1 1 Data processing - SIMD and floating point
- * "-" means "don't care"
- */
-enum aarch64_insn_encoding_class {
- AARCH64_INSN_CLS_UNKNOWN, /* UNALLOCATED */
- AARCH64_INSN_CLS_SVE, /* SVE instructions */
- AARCH64_INSN_CLS_DP_IMM, /* Data processing - immediate */
- AARCH64_INSN_CLS_DP_REG, /* Data processing - register */
- AARCH64_INSN_CLS_DP_FPSIMD, /* Data processing - SIMD and FP */
- AARCH64_INSN_CLS_LDST, /* Loads and stores */
- AARCH64_INSN_CLS_BR_SYS, /* Branch, exception generation and
- * system instructions */
-};
enum aarch64_insn_hint_cr_op {
AARCH64_INSN_HINT_NOP = 0x0 << 5,
@@ -326,6 +301,23 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
return (val); \
}
+/*
+ * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
+ * Section C3.1 "A64 instruction index by encoding":
+ * AArch64 main encoding table
+ * Bit position
+ * 28 27 26 25 Encoding Group
+ * 0 0 - - Unallocated
+ * 1 0 0 - Data processing, immediate
+ * 1 0 1 - Branch, exception generation and system instructions
+ * - 1 - 0 Loads and stores
+ * - 1 0 1 Data processing - register
+ * 0 1 1 1 Data processing - SIMD and floating point
+ * 1 1 1 1 Data processing - SIMD and floating point
+ * "-" means "don't care"
+ */
+__AARCH64_INSN_FUNCS(class_branch_sys, 0x1c000000, 0x14000000)
+
__AARCH64_INSN_FUNCS(adr, 0x9F000000, 0x10000000)
__AARCH64_INSN_FUNCS(adrp, 0x9F000000, 0x90000000)
__AARCH64_INSN_FUNCS(prfm, 0x3FC00000, 0x39800000)
@@ -431,58 +423,122 @@ __AARCH64_INSN_FUNCS(pssbb, 0xFFFFFFFF, 0xD503349F)
#undef __AARCH64_INSN_FUNCS
-bool aarch64_insn_is_steppable_hint(u32 insn);
-bool aarch64_insn_is_branch_imm(u32 insn);
+static __always_inline bool aarch64_insn_is_steppable_hint(u32 insn)
+{
+ if (!aarch64_insn_is_hint(insn))
+ return false;
+
+ switch (insn & 0xFE0) {
+ case AARCH64_INSN_HINT_XPACLRI:
+ case AARCH64_INSN_HINT_PACIA_1716:
+ case AARCH64_INSN_HINT_PACIB_1716:
+ case AARCH64_INSN_HINT_PACIAZ:
+ case AARCH64_INSN_HINT_PACIASP:
+ case AARCH64_INSN_HINT_PACIBZ:
+ case AARCH64_INSN_HINT_PACIBSP:
+ case AARCH64_INSN_HINT_BTI:
+ case AARCH64_INSN_HINT_BTIC:
+ case AARCH64_INSN_HINT_BTIJ:
+ case AARCH64_INSN_HINT_BTIJC:
+ case AARCH64_INSN_HINT_NOP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static __always_inline bool aarch64_insn_is_branch(u32 insn)
+{
+ /* b, bl, cb*, tb*, ret*, b.cond, br*, blr* */
+
+ return aarch64_insn_is_b(insn) ||
+ aarch64_insn_is_bl(insn) ||
+ aarch64_insn_is_cbz(insn) ||
+ aarch64_insn_is_cbnz(insn) ||
+ aarch64_insn_is_tbz(insn) ||
+ aarch64_insn_is_tbnz(insn) ||
+ aarch64_insn_is_ret(insn) ||
+ aarch64_insn_is_ret_auth(insn) ||
+ aarch64_insn_is_br(insn) ||
+ aarch64_insn_is_br_auth(insn) ||
+ aarch64_insn_is_blr(insn) ||
+ aarch64_insn_is_blr_auth(insn) ||
+ aarch64_insn_is_bcond(insn);
+}
-static inline bool aarch64_insn_is_adr_adrp(u32 insn)
+static __always_inline bool aarch64_insn_is_branch_imm(u32 insn)
{
- return aarch64_insn_is_adr(insn) || aarch64_insn_is_adrp(insn);
+ return aarch64_insn_is_b(insn) ||
+ aarch64_insn_is_bl(insn) ||
+ aarch64_insn_is_tbz(insn) ||
+ aarch64_insn_is_tbnz(insn) ||
+ aarch64_insn_is_cbz(insn) ||
+ aarch64_insn_is_cbnz(insn) ||
+ aarch64_insn_is_bcond(insn);
}
-static inline bool aarch64_insn_is_dsb(u32 insn)
+static __always_inline bool aarch64_insn_is_adr_adrp(u32 insn)
{
- return aarch64_insn_is_dsb_base(insn) || aarch64_insn_is_dsb_nxs(insn);
+ return aarch64_insn_is_adr(insn) ||
+ aarch64_insn_is_adrp(insn);
}
-static inline bool aarch64_insn_is_barrier(u32 insn)
+static __always_inline bool aarch64_insn_is_dsb(u32 insn)
{
- return aarch64_insn_is_dmb(insn) || aarch64_insn_is_dsb(insn) ||
- aarch64_insn_is_isb(insn) || aarch64_insn_is_sb(insn) ||
- aarch64_insn_is_clrex(insn) || aarch64_insn_is_ssbb(insn) ||
+ return aarch64_insn_is_dsb_base(insn) ||
+ aarch64_insn_is_dsb_nxs(insn);
+}
+
+static __always_inline bool aarch64_insn_is_barrier(u32 insn)
+{
+ return aarch64_insn_is_dmb(insn) ||
+ aarch64_insn_is_dsb(insn) ||
+ aarch64_insn_is_isb(insn) ||
+ aarch64_insn_is_sb(insn) ||
+ aarch64_insn_is_clrex(insn) ||
+ aarch64_insn_is_ssbb(insn) ||
aarch64_insn_is_pssbb(insn);
}
-static inline bool aarch64_insn_is_store_single(u32 insn)
+static __always_inline bool aarch64_insn_is_store_single(u32 insn)
{
return aarch64_insn_is_store_imm(insn) ||
aarch64_insn_is_store_pre(insn) ||
aarch64_insn_is_store_post(insn);
}
-static inline bool aarch64_insn_is_store_pair(u32 insn)
+static __always_inline bool aarch64_insn_is_store_pair(u32 insn)
{
return aarch64_insn_is_stp(insn) ||
aarch64_insn_is_stp_pre(insn) ||
aarch64_insn_is_stp_post(insn);
}
-static inline bool aarch64_insn_is_load_single(u32 insn)
+static __always_inline bool aarch64_insn_is_load_single(u32 insn)
{
return aarch64_insn_is_load_imm(insn) ||
aarch64_insn_is_load_pre(insn) ||
aarch64_insn_is_load_post(insn);
}
-static inline bool aarch64_insn_is_load_pair(u32 insn)
+static __always_inline bool aarch64_insn_is_load_pair(u32 insn)
{
return aarch64_insn_is_ldp(insn) ||
aarch64_insn_is_ldp_pre(insn) ||
aarch64_insn_is_ldp_post(insn);
}
+static __always_inline bool aarch64_insn_uses_literal(u32 insn)
+{
+ /* ldr/ldrsw (literal), prfm */
+
+ return aarch64_insn_is_ldr_lit(insn) ||
+ aarch64_insn_is_ldrsw_lit(insn) ||
+ aarch64_insn_is_adr_adrp(insn) ||
+ aarch64_insn_is_prfm_lit(insn);
+}
+
enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
-bool aarch64_insn_uses_literal(u32 insn);
-bool aarch64_insn_is_branch(u32 insn);
u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn);
u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
u32 insn, u64 imm);
@@ -496,8 +552,18 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
enum aarch64_insn_branch_type type);
u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
enum aarch64_insn_condition cond);
-u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_cr_op op);
-u32 aarch64_insn_gen_nop(void);
+
+static __always_inline u32
+aarch64_insn_gen_hint(enum aarch64_insn_hint_cr_op op)
+{
+ return aarch64_insn_get_hint_value() | op;
+}
+
+static __always_inline u32 aarch64_insn_gen_nop(void)
+{
+ return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP);
+}
+
u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
enum aarch64_insn_branch_type type);
u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
@@ -580,10 +646,6 @@ u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant,
enum aarch64_insn_register Rn,
enum aarch64_insn_register Rd,
u8 lsb);
-u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
- enum aarch64_insn_prfm_type type,
- enum aarch64_insn_prfm_target target,
- enum aarch64_insn_prfm_policy policy);
#ifdef CONFIG_ARM64_LSE_ATOMICS
u32 aarch64_insn_gen_atomic_ld_op(enum aarch64_insn_register result,
enum aarch64_insn_register address,
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h
index cea441b6aa5d..48ddc0f45d22 100644
--- a/arch/arm64/include/asm/jump_label.h
+++ b/arch/arm64/include/asm/jump_label.h
@@ -15,8 +15,8 @@
#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE
-static __always_inline bool arch_static_branch(struct static_key *key,
- bool branch)
+static __always_inline bool arch_static_branch(struct static_key * const key,
+ const bool branch)
{
asm_volatile_goto(
"1: nop \n\t"
@@ -32,8 +32,8 @@ l_yes:
return true;
}
-static __always_inline bool arch_static_branch_jump(struct static_key *key,
- bool branch)
+static __always_inline bool arch_static_branch_jump(struct static_key * const key,
+ const bool branch)
{
asm_volatile_goto(
"1: b %l[l_yes] \n\t"
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
index 32d14f481f0c..fcd14197756f 100644
--- a/arch/arm64/include/asm/kernel-pgtable.h
+++ b/arch/arm64/include/asm/kernel-pgtable.h
@@ -18,11 +18,6 @@
* with 4K (section size = 2M) but not with 16K (section size = 32M) or
* 64K (section size = 512M).
*/
-#ifdef CONFIG_ARM64_4K_PAGES
-#define ARM64_KERNEL_USES_PMD_MAPS 1
-#else
-#define ARM64_KERNEL_USES_PMD_MAPS 0
-#endif
/*
* The idmap and swapper page tables need some space reserved in the kernel
@@ -34,7 +29,7 @@
* VA range, so pages required to map highest possible PA are reserved in all
* cases.
*/
-#if ARM64_KERNEL_USES_PMD_MAPS
+#ifdef CONFIG_ARM64_4K_PAGES
#define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS - 1)
#else
#define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS)
@@ -96,7 +91,7 @@
#define INIT_IDMAP_DIR_PAGES EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE, 1)
/* Initial memory map size */
-#if ARM64_KERNEL_USES_PMD_MAPS
+#ifdef CONFIG_ARM64_4K_PAGES
#define SWAPPER_BLOCK_SHIFT PMD_SHIFT
#define SWAPPER_BLOCK_SIZE PMD_SIZE
#define SWAPPER_TABLE_SHIFT PUD_SHIFT
@@ -112,7 +107,7 @@
#define SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
-#if ARM64_KERNEL_USES_PMD_MAPS
+#ifdef CONFIG_ARM64_4K_PAGES
#define SWAPPER_RW_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
#define SWAPPER_RX_MMUFLAGS (SWAPPER_RW_MMUFLAGS | PMD_SECT_RDONLY)
#else
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 45e2136322ba..fd34ab155d0b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -306,8 +306,18 @@ struct vcpu_reset_state {
struct kvm_vcpu_arch {
struct kvm_cpu_context ctxt;
- /* Guest floating point state */
+ /*
+ * Guest floating point state
+ *
+ * The architecture has two main floating point extensions,
+ * the original FPSIMD and SVE. These have overlapping
+ * register views, with the FPSIMD V registers occupying the
+ * low 128 bits of the SVE Z registers. When the core
+ * floating point code saves the register state of a task it
+ * records which view it saved in fp_type.
+ */
void *sve_state;
+ enum fp_type fp_type;
unsigned int sve_max_vl;
u64 svcr;
diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h
index c503db8e73b0..f99d74826a7e 100644
--- a/arch/arm64/include/asm/lse.h
+++ b/arch/arm64/include/asm/lse.h
@@ -10,7 +10,6 @@
#include <linux/compiler_types.h>
#include <linux/export.h>
-#include <linux/jump_label.h>
#include <linux/stringify.h>
#include <asm/alternative.h>
#include <asm/alternative-macros.h>
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index d3f8b5df0c1f..72dbd6400549 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -18,6 +18,7 @@
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
+#include <asm/daifflags.h>
#include <asm/proc-fns.h>
#include <asm-generic/mm_hooks.h>
#include <asm/cputype.h>
@@ -152,6 +153,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
typedef void (ttbr_replace_func)(phys_addr_t);
extern ttbr_replace_func idmap_cpu_replace_ttbr1;
ttbr_replace_func *replace_phys;
+ unsigned long daif;
/* phys_to_ttbr() zeros lower 2 bits of ttbr with 52-bit PA */
phys_addr_t ttbr1 = phys_to_ttbr(virt_to_phys(pgdp));
@@ -171,7 +173,15 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
__cpu_install_idmap(idmap);
+
+ /*
+ * We really don't want to take *any* exceptions while TTBR1 is
+ * in the process of being replaced so mask everything.
+ */
+ daif = local_daif_save();
replace_phys(ttbr1);
+ local_daif_restore(daif);
+
cpu_uninstall_idmap();
}
diff --git a/arch/arm64/include/asm/module.lds.h b/arch/arm64/include/asm/module.lds.h
index 094701ec5500..dbba4b7559aa 100644
--- a/arch/arm64/include/asm/module.lds.h
+++ b/arch/arm64/include/asm/module.lds.h
@@ -17,4 +17,12 @@ SECTIONS {
*/
.text.hot : { *(.text.hot) }
#endif
+
+#ifdef CONFIG_UNWIND_TABLES
+ /*
+ * Currently, we only use unwind info at module load time, so we can
+ * put it into the .init allocation.
+ */
+ .init.eh_frame : { *(.eh_frame) }
+#endif
}
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 5ab8d163198f..f658aafc47df 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -159,6 +159,7 @@
#ifdef CONFIG_ARM64_PA_BITS_52
#define PTE_ADDR_HIGH (_AT(pteval_t, 0xf) << 12)
#define PTE_ADDR_MASK (PTE_ADDR_LOW | PTE_ADDR_HIGH)
+#define PTE_ADDR_HIGH_SHIFT 36
#else
#define PTE_ADDR_MASK PTE_ADDR_LOW
#endif
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 71a1af42f0e8..c36d56dbf940 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -77,11 +77,11 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
static inline phys_addr_t __pte_to_phys(pte_t pte)
{
return (pte_val(pte) & PTE_ADDR_LOW) |
- ((pte_val(pte) & PTE_ADDR_HIGH) << 36);
+ ((pte_val(pte) & PTE_ADDR_HIGH) << PTE_ADDR_HIGH_SHIFT);
}
static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
{
- return (phys | (phys >> 36)) & PTE_ADDR_MASK;
+ return (phys | (phys >> PTE_ADDR_HIGH_SHIFT)) & PTE_ADDR_MASK;
}
#else
#define __pte_to_phys(pte) (pte_val(pte) & PTE_ADDR_MASK)
@@ -609,7 +609,6 @@ extern pgd_t init_pg_dir[PTRS_PER_PGD];
extern pgd_t init_pg_end[];
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
-extern pgd_t idmap_pg_end[];
extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
extern pgd_t reserved_pg_dir[PTRS_PER_PGD];
@@ -863,12 +862,12 @@ static inline bool pte_user_accessible_page(pte_t pte)
static inline bool pmd_user_accessible_page(pmd_t pmd)
{
- return pmd_present(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
+ return pmd_leaf(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
}
static inline bool pud_user_accessible_page(pud_t pud)
{
- return pud_present(pud) && pud_user(pud);
+ return pud_leaf(pud) && pud_user(pud);
}
#endif
@@ -1096,6 +1095,15 @@ static inline bool pud_sect_supported(void)
}
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+#define ptep_modify_prot_start ptep_modify_prot_start
+extern pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep);
+
+#define ptep_modify_prot_commit ptep_modify_prot_commit
+extern void ptep_modify_prot_commit(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t old_pte, pte_t new_pte);
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_PGTABLE_H */
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 445aa3af3b76..d51b32a69309 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -122,6 +122,12 @@ enum vec_type {
ARM64_VEC_MAX,
};
+enum fp_type {
+ FP_STATE_CURRENT, /* Save based on current task state. */
+ FP_STATE_FPSIMD,
+ FP_STATE_SVE,
+};
+
struct cpu_context {
unsigned long x19;
unsigned long x20;
@@ -152,6 +158,7 @@ struct thread_struct {
struct user_fpsimd_state fpsimd_state;
} uw;
+ enum fp_type fp_type; /* registers FPSIMD or SVE? */
unsigned int fpsimd_cpu;
void *sve_state; /* SVE registers, if any */
void *za_state; /* ZA register, if any */
@@ -308,13 +315,13 @@ static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
}
#endif
-static inline bool is_ttbr0_addr(unsigned long addr)
+static __always_inline bool is_ttbr0_addr(unsigned long addr)
{
/* entry assembly clears tags for TTBR0 addrs */
return addr < TASK_SIZE;
}
-static inline bool is_ttbr1_addr(unsigned long addr)
+static __always_inline bool is_ttbr1_addr(unsigned long addr)
{
/* TTBR1 addresses may have a tag if KASAN_SW_TAGS is in use */
return arch_kasan_reset_tag(addr) >= PAGE_OFFSET;
@@ -396,18 +403,5 @@ long get_tagged_addr_ctrl(struct task_struct *task);
#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current)
#endif
-/*
- * For CONFIG_GCC_PLUGIN_STACKLEAK
- *
- * These need to be macros because otherwise we get stuck in a nightmare
- * of header definitions for the use of task_stack_page.
- */
-
-/*
- * The top of the current task's task stack
- */
-#define current_top_of_stack() ((unsigned long)current->stack + THREAD_SIZE)
-#define on_thread_stack() (on_task_stack(current, current_stack_pointer, 1))
-
#endif /* __ASSEMBLY__ */
#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/include/asm/scs.h b/arch/arm64/include/asm/scs.h
index 8297bccf0784..ff7da1268a52 100644
--- a/arch/arm64/include/asm/scs.h
+++ b/arch/arm64/include/asm/scs.h
@@ -5,6 +5,7 @@
#ifdef __ASSEMBLY__
#include <asm/asm-offsets.h>
+#include <asm/sysreg.h>
#ifdef CONFIG_SHADOW_CALL_STACK
scs_sp .req x18
@@ -24,6 +25,54 @@
.endm
#endif /* CONFIG_SHADOW_CALL_STACK */
+
+#else
+
+#include <linux/scs.h>
+#include <asm/cpufeature.h>
+
+#ifdef CONFIG_UNWIND_PATCH_PAC_INTO_SCS
+static inline bool should_patch_pac_into_scs(void)
+{
+ u64 reg;
+
+ /*
+ * We only enable the shadow call stack dynamically if we are running
+ * on a system that does not implement PAC or BTI. PAC and SCS provide
+ * roughly the same level of protection, and BTI relies on the PACIASP
+ * instructions serving as landing pads, preventing us from patching
+ * those instructions into something else.
+ */
+ reg = read_sysreg_s(SYS_ID_AA64ISAR1_EL1);
+ if (SYS_FIELD_GET(ID_AA64ISAR1_EL1, APA, reg) |
+ SYS_FIELD_GET(ID_AA64ISAR1_EL1, API, reg))
+ return false;
+
+ reg = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
+ if (SYS_FIELD_GET(ID_AA64ISAR2_EL1, APA3, reg))
+ return false;
+
+ if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
+ reg = read_sysreg_s(SYS_ID_AA64PFR1_EL1);
+ if (reg & (0xf << ID_AA64PFR1_EL1_BT_SHIFT))
+ return false;
+ }
+ return true;
+}
+
+static inline void dynamic_scs_init(void)
+{
+ if (should_patch_pac_into_scs()) {
+ pr_info("Enabling dynamic shadow call stack\n");
+ static_branch_enable(&dynamic_scs_enabled);
+ }
+}
+#else
+static inline void dynamic_scs_init(void) {}
+#endif
+
+int scs_patch(const u8 eh_frame[], int size);
+
#endif /* __ASSEMBLY __ */
#endif /* _ASM_SCS_H */
diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h
index aa3d3607d5c8..db7b371b367c 100644
--- a/arch/arm64/include/asm/spectre.h
+++ b/arch/arm64/include/asm/spectre.h
@@ -26,6 +26,7 @@ enum mitigation_state {
SPECTRE_VULNERABLE,
};
+struct pt_regs;
struct task_struct;
/*
@@ -98,5 +99,6 @@ enum mitigation_state arm64_get_spectre_bhb_state(void);
bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
u8 spectre_bhb_loop_affected(int scope);
void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
+bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_SPECTRE_H */
diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h
index 33f1bb453150..ae3ad80f51fe 100644
--- a/arch/arm64/include/asm/stackprotector.h
+++ b/arch/arm64/include/asm/stackprotector.h
@@ -13,8 +13,6 @@
#ifndef __ASM_STACKPROTECTOR_H
#define __ASM_STACKPROTECTOR_H
-#include <linux/random.h>
-#include <linux/version.h>
#include <asm/pointer_auth.h>
extern unsigned long __stack_chk_guard;
@@ -28,12 +26,7 @@ extern unsigned long __stack_chk_guard;
static __always_inline void boot_init_stack_canary(void)
{
#if defined(CONFIG_STACKPROTECTOR)
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
- canary &= CANARY_MASK;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK))
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
index 5a0edb064ea4..4e5354beafb0 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -57,6 +57,8 @@ static inline bool on_task_stack(const struct task_struct *tsk,
return stackinfo_on_stack(&info, sp, size);
}
+#define on_thread_stack() (on_task_stack(current, current_stack_pointer, 1))
+
#ifdef CONFIG_VMAP_STACK
DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
diff --git a/arch/arm64/include/asm/syscall_wrapper.h b/arch/arm64/include/asm/syscall_wrapper.h
index b383b4802a7b..d30217c21eff 100644
--- a/arch/arm64/include/asm/syscall_wrapper.h
+++ b/arch/arm64/include/asm/syscall_wrapper.h
@@ -8,7 +8,7 @@
#ifndef __ASM_SYSCALL_WRAPPER_H
#define __ASM_SYSCALL_WRAPPER_H
-struct pt_regs;
+#include <asm/ptrace.h>
#define SC_ARM64_REGS_TO_ARGS(x, ...) \
__MAP(x,__SC_ARGS \
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 7d301700d1a9..1312fb48f18b 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -90,20 +90,24 @@
*/
#define pstate_field(op1, op2) ((op1) << Op1_shift | (op2) << Op2_shift)
#define PSTATE_Imm_shift CRm_shift
+#define SET_PSTATE(x, r) __emit_inst(0xd500401f | PSTATE_ ## r | ((!!x) << PSTATE_Imm_shift))
#define PSTATE_PAN pstate_field(0, 4)
#define PSTATE_UAO pstate_field(0, 3)
#define PSTATE_SSBS pstate_field(3, 1)
+#define PSTATE_DIT pstate_field(3, 2)
#define PSTATE_TCO pstate_field(3, 4)
-#define SET_PSTATE_PAN(x) __emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift))
-#define SET_PSTATE_UAO(x) __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift))
-#define SET_PSTATE_SSBS(x) __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift))
-#define SET_PSTATE_TCO(x) __emit_inst(0xd500401f | PSTATE_TCO | ((!!x) << PSTATE_Imm_shift))
+#define SET_PSTATE_PAN(x) SET_PSTATE((x), PAN)
+#define SET_PSTATE_UAO(x) SET_PSTATE((x), UAO)
+#define SET_PSTATE_SSBS(x) SET_PSTATE((x), SSBS)
+#define SET_PSTATE_DIT(x) SET_PSTATE((x), DIT)
+#define SET_PSTATE_TCO(x) SET_PSTATE((x), TCO)
#define set_pstate_pan(x) asm volatile(SET_PSTATE_PAN(x))
#define set_pstate_uao(x) asm volatile(SET_PSTATE_UAO(x))
#define set_pstate_ssbs(x) asm volatile(SET_PSTATE_SSBS(x))
+#define set_pstate_dit(x) asm volatile(SET_PSTATE_DIT(x))
#define __SYS_BARRIER_INSN(CRm, op2, Rt) \
__emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f))
@@ -165,31 +169,6 @@
#define SYS_MPIDR_EL1 sys_reg(3, 0, 0, 0, 5)
#define SYS_REVIDR_EL1 sys_reg(3, 0, 0, 0, 6)
-#define SYS_ID_PFR0_EL1 sys_reg(3, 0, 0, 1, 0)
-#define SYS_ID_PFR1_EL1 sys_reg(3, 0, 0, 1, 1)
-#define SYS_ID_PFR2_EL1 sys_reg(3, 0, 0, 3, 4)
-#define SYS_ID_DFR0_EL1 sys_reg(3, 0, 0, 1, 2)
-#define SYS_ID_DFR1_EL1 sys_reg(3, 0, 0, 3, 5)
-#define SYS_ID_AFR0_EL1 sys_reg(3, 0, 0, 1, 3)
-#define SYS_ID_MMFR0_EL1 sys_reg(3, 0, 0, 1, 4)
-#define SYS_ID_MMFR1_EL1 sys_reg(3, 0, 0, 1, 5)
-#define SYS_ID_MMFR2_EL1 sys_reg(3, 0, 0, 1, 6)
-#define SYS_ID_MMFR3_EL1 sys_reg(3, 0, 0, 1, 7)
-#define SYS_ID_MMFR4_EL1 sys_reg(3, 0, 0, 2, 6)
-#define SYS_ID_MMFR5_EL1 sys_reg(3, 0, 0, 3, 6)
-
-#define SYS_ID_ISAR0_EL1 sys_reg(3, 0, 0, 2, 0)
-#define SYS_ID_ISAR1_EL1 sys_reg(3, 0, 0, 2, 1)
-#define SYS_ID_ISAR2_EL1 sys_reg(3, 0, 0, 2, 2)
-#define SYS_ID_ISAR3_EL1 sys_reg(3, 0, 0, 2, 3)
-#define SYS_ID_ISAR4_EL1 sys_reg(3, 0, 0, 2, 4)
-#define SYS_ID_ISAR5_EL1 sys_reg(3, 0, 0, 2, 5)
-#define SYS_ID_ISAR6_EL1 sys_reg(3, 0, 0, 2, 7)
-
-#define SYS_MVFR0_EL1 sys_reg(3, 0, 0, 3, 0)
-#define SYS_MVFR1_EL1 sys_reg(3, 0, 0, 3, 1)
-#define SYS_MVFR2_EL1 sys_reg(3, 0, 0, 3, 2)
-
#define SYS_ACTLR_EL1 sys_reg(3, 0, 1, 0, 1)
#define SYS_RGSR_EL1 sys_reg(3, 0, 1, 0, 5)
#define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6)
@@ -692,112 +671,6 @@
#define ID_AA64MMFR0_EL1_PARANGE_MAX ID_AA64MMFR0_EL1_PARANGE_48
#endif
-#define ID_DFR0_PERFMON_SHIFT 24
-
-#define ID_DFR0_PERFMON_8_0 0x3
-#define ID_DFR0_PERFMON_8_1 0x4
-#define ID_DFR0_PERFMON_8_4 0x5
-#define ID_DFR0_PERFMON_8_5 0x6
-
-#define ID_ISAR4_SWP_FRAC_SHIFT 28
-#define ID_ISAR4_PSR_M_SHIFT 24
-#define ID_ISAR4_SYNCH_PRIM_FRAC_SHIFT 20
-#define ID_ISAR4_BARRIER_SHIFT 16
-#define ID_ISAR4_SMC_SHIFT 12
-#define ID_ISAR4_WRITEBACK_SHIFT 8
-#define ID_ISAR4_WITHSHIFTS_SHIFT 4
-#define ID_ISAR4_UNPRIV_SHIFT 0
-
-#define ID_DFR1_MTPMU_SHIFT 0
-
-#define ID_ISAR0_DIVIDE_SHIFT 24
-#define ID_ISAR0_DEBUG_SHIFT 20
-#define ID_ISAR0_COPROC_SHIFT 16
-#define ID_ISAR0_CMPBRANCH_SHIFT 12
-#define ID_ISAR0_BITFIELD_SHIFT 8
-#define ID_ISAR0_BITCOUNT_SHIFT 4
-#define ID_ISAR0_SWAP_SHIFT 0
-
-#define ID_ISAR5_RDM_SHIFT 24
-#define ID_ISAR5_CRC32_SHIFT 16
-#define ID_ISAR5_SHA2_SHIFT 12
-#define ID_ISAR5_SHA1_SHIFT 8
-#define ID_ISAR5_AES_SHIFT 4
-#define ID_ISAR5_SEVL_SHIFT 0
-
-#define ID_ISAR6_I8MM_SHIFT 24
-#define ID_ISAR6_BF16_SHIFT 20
-#define ID_ISAR6_SPECRES_SHIFT 16
-#define ID_ISAR6_SB_SHIFT 12
-#define ID_ISAR6_FHM_SHIFT 8
-#define ID_ISAR6_DP_SHIFT 4
-#define ID_ISAR6_JSCVT_SHIFT 0
-
-#define ID_MMFR0_INNERSHR_SHIFT 28
-#define ID_MMFR0_FCSE_SHIFT 24
-#define ID_MMFR0_AUXREG_SHIFT 20
-#define ID_MMFR0_TCM_SHIFT 16
-#define ID_MMFR0_SHARELVL_SHIFT 12
-#define ID_MMFR0_OUTERSHR_SHIFT 8
-#define ID_MMFR0_PMSA_SHIFT 4
-#define ID_MMFR0_VMSA_SHIFT 0
-
-#define ID_MMFR4_EVT_SHIFT 28
-#define ID_MMFR4_CCIDX_SHIFT 24
-#define ID_MMFR4_LSM_SHIFT 20
-#define ID_MMFR4_HPDS_SHIFT 16
-#define ID_MMFR4_CNP_SHIFT 12
-#define ID_MMFR4_XNX_SHIFT 8
-#define ID_MMFR4_AC2_SHIFT 4
-#define ID_MMFR4_SPECSEI_SHIFT 0
-
-#define ID_MMFR5_ETS_SHIFT 0
-
-#define ID_PFR0_DIT_SHIFT 24
-#define ID_PFR0_CSV2_SHIFT 16
-#define ID_PFR0_STATE3_SHIFT 12
-#define ID_PFR0_STATE2_SHIFT 8
-#define ID_PFR0_STATE1_SHIFT 4
-#define ID_PFR0_STATE0_SHIFT 0
-
-#define ID_DFR0_PERFMON_SHIFT 24
-#define ID_DFR0_MPROFDBG_SHIFT 20
-#define ID_DFR0_MMAPTRC_SHIFT 16
-#define ID_DFR0_COPTRC_SHIFT 12
-#define ID_DFR0_MMAPDBG_SHIFT 8
-#define ID_DFR0_COPSDBG_SHIFT 4
-#define ID_DFR0_COPDBG_SHIFT 0
-
-#define ID_PFR2_SSBS_SHIFT 4
-#define ID_PFR2_CSV3_SHIFT 0
-
-#define MVFR0_FPROUND_SHIFT 28
-#define MVFR0_FPSHVEC_SHIFT 24
-#define MVFR0_FPSQRT_SHIFT 20
-#define MVFR0_FPDIVIDE_SHIFT 16
-#define MVFR0_FPTRAP_SHIFT 12
-#define MVFR0_FPDP_SHIFT 8
-#define MVFR0_FPSP_SHIFT 4
-#define MVFR0_SIMD_SHIFT 0
-
-#define MVFR1_SIMDFMAC_SHIFT 28
-#define MVFR1_FPHP_SHIFT 24
-#define MVFR1_SIMDHP_SHIFT 20
-#define MVFR1_SIMDSP_SHIFT 16
-#define MVFR1_SIMDINT_SHIFT 12
-#define MVFR1_SIMDLS_SHIFT 8
-#define MVFR1_FPDNAN_SHIFT 4
-#define MVFR1_FPFTZ_SHIFT 0
-
-#define ID_PFR1_GIC_SHIFT 28
-#define ID_PFR1_VIRT_FRAC_SHIFT 24
-#define ID_PFR1_SEC_FRAC_SHIFT 20
-#define ID_PFR1_GENTIMER_SHIFT 16
-#define ID_PFR1_VIRTUALIZATION_SHIFT 12
-#define ID_PFR1_MPROGMOD_SHIFT 8
-#define ID_PFR1_SECURITY_SHIFT 4
-#define ID_PFR1_PROGMOD_SHIFT 0
-
#if defined(CONFIG_ARM64_4K_PAGES)
#define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN4_SHIFT
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN
@@ -815,9 +688,6 @@
#define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN64_2_SHIFT
#endif
-#define MVFR2_FPMISC_SHIFT 4
-#define MVFR2_SIMDMISC_SHIFT 0
-
#define CPACR_EL1_FPEN_EL1EN (BIT(20)) /* enable EL1 access */
#define CPACR_EL1_FPEN_EL0EN (BIT(21)) /* enable EL0 access, if EL1EN set */
@@ -851,10 +721,6 @@
#define SYS_RGSR_EL1_SEED_SHIFT 8
#define SYS_RGSR_EL1_SEED_MASK 0xffffUL
-/* GMID_EL1 field definitions */
-#define GMID_EL1_BS_SHIFT 0
-#define GMID_EL1_BS_SIZE 4
-
/* TFSR{,E0}_EL1 bit definitions */
#define SYS_TFSR_EL1_TF0_SHIFT 0
#define SYS_TFSR_EL1_TF1_SHIFT 1
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 6e5826470bea..1f361e2da516 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -13,17 +13,16 @@
struct pt_regs;
-struct undef_hook {
- struct list_head node;
- u32 instr_mask;
- u32 instr_val;
- u64 pstate_mask;
- u64 pstate_val;
- int (*fn)(struct pt_regs *regs, u32 instr);
-};
+#ifdef CONFIG_ARMV8_DEPRECATED
+bool try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn);
+#else
+static inline bool
+try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn)
+{
+ return false;
+}
+#endif /* CONFIG_ARMV8_DEPRECATED */
-void register_undef_hook(struct undef_hook *hook);
-void unregister_undef_hook(struct undef_hook *hook);
void force_signal_inject(int signal, int code, unsigned long address, unsigned long err);
void arm64_notify_segfault(unsigned long addr);
void arm64_force_sig_fault(int signo, int code, unsigned long far, const char *str);
diff --git a/arch/arm64/include/asm/uprobes.h b/arch/arm64/include/asm/uprobes.h
index 315eef654e39..ba4bff5ca674 100644
--- a/arch/arm64/include/asm/uprobes.h
+++ b/arch/arm64/include/asm/uprobes.h
@@ -12,7 +12,7 @@
#define MAX_UINSN_BYTES AARCH64_INSN_SIZE
-#define UPROBE_SWBP_INSN BRK64_OPCODE_UPROBES
+#define UPROBE_SWBP_INSN cpu_to_le32(BRK64_OPCODE_UPROBES)
#define UPROBE_SWBP_INSN_SIZE AARCH64_INSN_SIZE
#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 9b245da6f507..b713d30544f1 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -93,5 +93,8 @@
#define HWCAP2_WFXT (1UL << 31)
#define HWCAP2_EBF16 (1UL << 32)
#define HWCAP2_SVE_EBF16 (1UL << 33)
+#define HWCAP2_CSSC (1UL << 34)
+#define HWCAP2_RPRFM (1UL << 35)
+#define HWCAP2_SVE2P1 (1UL << 36)
#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index 4aaf31e3bf16..9525041e4a14 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -62,6 +62,10 @@ struct sigcontext {
* context. Such structures must be placed after the rt_sigframe on the stack
* and be 16-byte aligned. The last structure must be a dummy one with the
* magic and size set to 0.
+ *
+ * Note that the values allocated for use as magic should be chosen to
+ * be meaningful in ASCII to aid manual parsing, ZA doesn't follow this
+ * convention due to oversight but it should be observed for future additions.
*/
struct _aarch64_ctx {
__u32 magic;
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2f361a883d8c..8dd925f4a4c6 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -80,6 +80,8 @@ obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o
obj-$(CONFIG_ARM64_MTE) += mte.o
obj-y += vdso-wrap.o
obj-$(CONFIG_COMPAT_VDSO) += vdso32-wrap.o
+obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) += patch-scs.o
+CFLAGS_patch-scs.o += -mbranch-protection=none
# Force dependency (vdso*-wrap.S includes vdso.so through incbin)
$(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index a5a256e3f9fe..378453faa87e 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "ACPI: " fmt
#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
#include <linux/cpumask.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
@@ -411,3 +412,108 @@ void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
{
memblock_mark_nomap(addr, size);
}
+
+#ifdef CONFIG_ACPI_FFH
+/*
+ * Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
+ * specified in https://developer.arm.com/docs/den0048/latest
+ */
+struct acpi_ffh_data {
+ struct acpi_ffh_info info;
+ void (*invoke_ffh_fn)(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 *args,
+ struct arm_smccc_quirk *res);
+ void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
+ struct arm_smccc_1_2_regs *res);
+};
+
+int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
+{
+ enum arm_smccc_conduit conduit;
+ struct acpi_ffh_data *ffh_ctxt;
+
+ ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
+ if (!ffh_ctxt)
+ return -ENOMEM;
+
+ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
+ return -EOPNOTSUPP;
+
+ conduit = arm_smccc_1_1_get_conduit();
+ if (conduit == SMCCC_CONDUIT_NONE) {
+ pr_err("%s: invalid SMCCC conduit\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if (conduit == SMCCC_CONDUIT_SMC) {
+ ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
+ ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
+ } else {
+ ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
+ ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
+ }
+
+ memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
+
+ *region_ctxt = ffh_ctxt;
+ return AE_OK;
+}
+
+static bool acpi_ffh_smccc_owner_allowed(u32 fid)
+{
+ int owner = ARM_SMCCC_OWNER_NUM(fid);
+
+ if (owner == ARM_SMCCC_OWNER_STANDARD ||
+ owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
+ return true;
+
+ return false;
+}
+
+int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
+{
+ int ret = 0;
+ struct acpi_ffh_data *ffh_ctxt = region_context;
+
+ if (ffh_ctxt->info.offset == 0) {
+ /* SMC/HVC 32bit call */
+ struct arm_smccc_res res;
+ u32 a[8] = { 0 }, *ptr = (u32 *)value;
+
+ if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
+ !acpi_ffh_smccc_owner_allowed(*ptr) ||
+ ffh_ctxt->info.length > 32) {
+ ret = AE_ERROR;
+ } else {
+ int idx, len = ffh_ctxt->info.length >> 2;
+
+ for (idx = 0; idx < len; idx++)
+ a[idx] = *(ptr + idx);
+
+ ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
+ a[5], a[6], a[7], &res, NULL);
+ memcpy(value, &res, sizeof(res));
+ }
+
+ } else if (ffh_ctxt->info.offset == 1) {
+ /* SMC/HVC 64bit call */
+ struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
+
+ if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
+ !acpi_ffh_smccc_owner_allowed(r->a0) ||
+ ffh_ctxt->info.length > sizeof(*r)) {
+ ret = AE_ERROR;
+ } else {
+ ffh_ctxt->invoke_ffh64_fn(r, r);
+ memcpy(value, r, ffh_ctxt->info.length);
+ }
+ } else {
+ ret = AE_ERROR;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_ACPI_FFH */
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 91263d09ea65..d32d4ed5519b 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -196,7 +196,7 @@ static void __apply_alternatives(const struct alt_region *region,
}
}
-void apply_alternatives_vdso(void)
+static void __init apply_alternatives_vdso(void)
{
struct alt_region region;
const struct elf64_hdr *hdr;
@@ -220,7 +220,7 @@ void apply_alternatives_vdso(void)
__apply_alternatives(&region, false, &all_capabilities[0]);
}
-static const struct alt_region kernel_alternatives = {
+static const struct alt_region kernel_alternatives __initconst = {
.begin = (struct alt_instr *)__alt_instructions,
.end = (struct alt_instr *)__alt_instructions_end,
};
@@ -229,7 +229,7 @@ static const struct alt_region kernel_alternatives = {
* We might be patching the stop_machine state machine, so implement a
* really simple polling protocol here.
*/
-static int __apply_alternatives_multi_stop(void *unused)
+static int __init __apply_alternatives_multi_stop(void *unused)
{
/* We always have a CPU 0 at this point (__init) */
if (smp_processor_id()) {
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index fb0e7c7b2e20..8a9052cf3013 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -17,7 +17,6 @@
#include <asm/sysreg.h>
#include <asm/system_misc.h>
#include <asm/traps.h>
-#include <asm/kprobes.h>
#define CREATE_TRACE_POINTS
#include "trace-events-emulation.h"
@@ -39,226 +38,46 @@ enum insn_emulation_mode {
enum legacy_insn_status {
INSN_DEPRECATED,
INSN_OBSOLETE,
-};
-
-struct insn_emulation_ops {
- const char *name;
- enum legacy_insn_status status;
- struct undef_hook *hooks;
- int (*set_hw_mode)(bool enable);
+ INSN_UNAVAILABLE,
};
struct insn_emulation {
- struct list_head node;
- struct insn_emulation_ops *ops;
+ const char *name;
+ enum legacy_insn_status status;
+ bool (*try_emulate)(struct pt_regs *regs,
+ u32 insn);
+ int (*set_hw_mode)(bool enable);
+
int current_mode;
int min;
int max;
-};
-
-static LIST_HEAD(insn_emulation);
-static int nr_insn_emulated __initdata;
-static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
-static DEFINE_MUTEX(insn_emulation_mutex);
-
-static void register_emulation_hooks(struct insn_emulation_ops *ops)
-{
- struct undef_hook *hook;
-
- BUG_ON(!ops->hooks);
-
- for (hook = ops->hooks; hook->instr_mask; hook++)
- register_undef_hook(hook);
-
- pr_notice("Registered %s emulation handler\n", ops->name);
-}
-
-static void remove_emulation_hooks(struct insn_emulation_ops *ops)
-{
- struct undef_hook *hook;
-
- BUG_ON(!ops->hooks);
-
- for (hook = ops->hooks; hook->instr_mask; hook++)
- unregister_undef_hook(hook);
-
- pr_notice("Removed %s emulation handler\n", ops->name);
-}
-
-static void enable_insn_hw_mode(void *data)
-{
- struct insn_emulation *insn = (struct insn_emulation *)data;
- if (insn->ops->set_hw_mode)
- insn->ops->set_hw_mode(true);
-}
-
-static void disable_insn_hw_mode(void *data)
-{
- struct insn_emulation *insn = (struct insn_emulation *)data;
- if (insn->ops->set_hw_mode)
- insn->ops->set_hw_mode(false);
-}
-
-/* Run set_hw_mode(mode) on all active CPUs */
-static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
-{
- if (!insn->ops->set_hw_mode)
- return -EINVAL;
- if (enable)
- on_each_cpu(enable_insn_hw_mode, (void *)insn, true);
- else
- on_each_cpu(disable_insn_hw_mode, (void *)insn, true);
- return 0;
-}
-
-/*
- * Run set_hw_mode for all insns on a starting CPU.
- * Returns:
- * 0 - If all the hooks ran successfully.
- * -EINVAL - At least one hook is not supported by the CPU.
- */
-static int run_all_insn_set_hw_mode(unsigned int cpu)
-{
- int rc = 0;
- unsigned long flags;
- struct insn_emulation *insn;
-
- raw_spin_lock_irqsave(&insn_emulation_lock, flags);
- list_for_each_entry(insn, &insn_emulation, node) {
- bool enable = (insn->current_mode == INSN_HW);
- if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) {
- pr_warn("CPU[%u] cannot support the emulation of %s",
- cpu, insn->ops->name);
- rc = -EINVAL;
- }
- }
- raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
- return rc;
-}
-
-static int update_insn_emulation_mode(struct insn_emulation *insn,
- enum insn_emulation_mode prev)
-{
- int ret = 0;
-
- switch (prev) {
- case INSN_UNDEF: /* Nothing to be done */
- break;
- case INSN_EMULATE:
- remove_emulation_hooks(insn->ops);
- break;
- case INSN_HW:
- if (!run_all_cpu_set_hw_mode(insn, false))
- pr_notice("Disabled %s support\n", insn->ops->name);
- break;
- }
-
- switch (insn->current_mode) {
- case INSN_UNDEF:
- break;
- case INSN_EMULATE:
- register_emulation_hooks(insn->ops);
- break;
- case INSN_HW:
- ret = run_all_cpu_set_hw_mode(insn, true);
- if (!ret)
- pr_notice("Enabled %s support\n", insn->ops->name);
- break;
- }
- return ret;
-}
-
-static void __init register_insn_emulation(struct insn_emulation_ops *ops)
-{
- unsigned long flags;
- struct insn_emulation *insn;
-
- insn = kzalloc(sizeof(*insn), GFP_KERNEL);
- if (!insn)
- return;
-
- insn->ops = ops;
- insn->min = INSN_UNDEF;
-
- switch (ops->status) {
- case INSN_DEPRECATED:
- insn->current_mode = INSN_EMULATE;
- /* Disable the HW mode if it was turned on at early boot time */
- run_all_cpu_set_hw_mode(insn, false);
- insn->max = INSN_HW;
- break;
- case INSN_OBSOLETE:
- insn->current_mode = INSN_UNDEF;
- insn->max = INSN_EMULATE;
- break;
- }
-
- raw_spin_lock_irqsave(&insn_emulation_lock, flags);
- list_add(&insn->node, &insn_emulation);
- nr_insn_emulated++;
- raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
-
- /* Register any handlers if required */
- update_insn_emulation_mode(insn, INSN_UNDEF);
-}
-
-static int emulation_proc_handler(struct ctl_table *table, int write,
- void *buffer, size_t *lenp,
- loff_t *ppos)
-{
- int ret = 0;
- struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
- enum insn_emulation_mode prev_mode = insn->current_mode;
-
- mutex_lock(&insn_emulation_mutex);
- ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+ /*
+ * sysctl for this emulation + a sentinal entry.
+ */
+ struct ctl_table sysctl[2];
+};
- if (ret || !write || prev_mode == insn->current_mode)
- goto ret;
+#define ARM_OPCODE_CONDTEST_FAIL 0
+#define ARM_OPCODE_CONDTEST_PASS 1
+#define ARM_OPCODE_CONDTEST_UNCOND 2
- ret = update_insn_emulation_mode(insn, prev_mode);
- if (ret) {
- /* Mode change failed, revert to previous mode. */
- insn->current_mode = prev_mode;
- update_insn_emulation_mode(insn, INSN_UNDEF);
- }
-ret:
- mutex_unlock(&insn_emulation_mutex);
- return ret;
-}
+#define ARM_OPCODE_CONDITION_UNCOND 0xf
-static void __init register_insn_emulation_sysctl(void)
+static unsigned int __maybe_unused aarch32_check_condition(u32 opcode, u32 psr)
{
- unsigned long flags;
- int i = 0;
- struct insn_emulation *insn;
- struct ctl_table *insns_sysctl, *sysctl;
-
- insns_sysctl = kcalloc(nr_insn_emulated + 1, sizeof(*sysctl),
- GFP_KERNEL);
- if (!insns_sysctl)
- return;
-
- raw_spin_lock_irqsave(&insn_emulation_lock, flags);
- list_for_each_entry(insn, &insn_emulation, node) {
- sysctl = &insns_sysctl[i];
-
- sysctl->mode = 0644;
- sysctl->maxlen = sizeof(int);
+ u32 cc_bits = opcode >> 28;
- sysctl->procname = insn->ops->name;
- sysctl->data = &insn->current_mode;
- sysctl->extra1 = &insn->min;
- sysctl->extra2 = &insn->max;
- sysctl->proc_handler = emulation_proc_handler;
- i++;
+ if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
+ if ((*aarch32_opcode_cond_checks[cc_bits])(psr))
+ return ARM_OPCODE_CONDTEST_PASS;
+ else
+ return ARM_OPCODE_CONDTEST_FAIL;
}
- raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
-
- register_sysctl("abi", insns_sysctl);
+ return ARM_OPCODE_CONDTEST_UNCOND;
}
+#ifdef CONFIG_SWP_EMULATION
/*
* Implement emulation of the SWP/SWPB instructions using load-exclusive and
* store-exclusive.
@@ -339,25 +158,6 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
return res;
}
-#define ARM_OPCODE_CONDTEST_FAIL 0
-#define ARM_OPCODE_CONDTEST_PASS 1
-#define ARM_OPCODE_CONDTEST_UNCOND 2
-
-#define ARM_OPCODE_CONDITION_UNCOND 0xf
-
-static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr)
-{
- u32 cc_bits = opcode >> 28;
-
- if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
- if ((*aarch32_opcode_cond_checks[cc_bits])(psr))
- return ARM_OPCODE_CONDTEST_PASS;
- else
- return ARM_OPCODE_CONDTEST_FAIL;
- }
- return ARM_OPCODE_CONDTEST_UNCOND;
-}
-
/*
* swp_handler logs the id of calling process, dissects the instruction, sanity
* checks the memory location, calls emulate_swpX for the actual operation and
@@ -430,28 +230,27 @@ fault:
return 0;
}
-/*
- * Only emulate SWP/SWPB executed in ARM state/User mode.
- * The kernel must be SWP free and SWP{B} does not exist in Thumb.
- */
-static struct undef_hook swp_hooks[] = {
- {
- .instr_mask = 0x0fb00ff0,
- .instr_val = 0x01000090,
- .pstate_mask = PSR_AA32_MODE_MASK,
- .pstate_val = PSR_AA32_MODE_USR,
- .fn = swp_handler
- },
- { }
-};
+static bool try_emulate_swp(struct pt_regs *regs, u32 insn)
+{
+ /* SWP{B} only exists in ARM state and does not exist in Thumb */
+ if (!compat_user_mode(regs) || compat_thumb_mode(regs))
+ return false;
-static struct insn_emulation_ops swp_ops = {
+ if ((insn & 0x0fb00ff0) != 0x01000090)
+ return false;
+
+ return swp_handler(regs, insn) == 0;
+}
+
+static struct insn_emulation insn_swp = {
.name = "swp",
.status = INSN_OBSOLETE,
- .hooks = swp_hooks,
+ .try_emulate = try_emulate_swp,
.set_hw_mode = NULL,
};
+#endif /* CONFIG_SWP_EMULATION */
+#ifdef CONFIG_CP15_BARRIER_EMULATION
static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
{
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
@@ -514,31 +313,29 @@ static int cp15_barrier_set_hw_mode(bool enable)
return 0;
}
-static struct undef_hook cp15_barrier_hooks[] = {
- {
- .instr_mask = 0x0fff0fdf,
- .instr_val = 0x0e070f9a,
- .pstate_mask = PSR_AA32_MODE_MASK,
- .pstate_val = PSR_AA32_MODE_USR,
- .fn = cp15barrier_handler,
- },
- {
- .instr_mask = 0x0fff0fff,
- .instr_val = 0x0e070f95,
- .pstate_mask = PSR_AA32_MODE_MASK,
- .pstate_val = PSR_AA32_MODE_USR,
- .fn = cp15barrier_handler,
- },
- { }
-};
+static bool try_emulate_cp15_barrier(struct pt_regs *regs, u32 insn)
+{
+ if (!compat_user_mode(regs) || compat_thumb_mode(regs))
+ return false;
+
+ if ((insn & 0x0fff0fdf) == 0x0e070f9a)
+ return cp15barrier_handler(regs, insn) == 0;
+
+ if ((insn & 0x0fff0fff) == 0x0e070f95)
+ return cp15barrier_handler(regs, insn) == 0;
-static struct insn_emulation_ops cp15_barrier_ops = {
+ return false;
+}
+
+static struct insn_emulation insn_cp15_barrier = {
.name = "cp15_barrier",
.status = INSN_DEPRECATED,
- .hooks = cp15_barrier_hooks,
+ .try_emulate = try_emulate_cp15_barrier,
.set_hw_mode = cp15_barrier_set_hw_mode,
};
+#endif /* CONFIG_CP15_BARRIER_EMULATION */
+#ifdef CONFIG_SETEND_EMULATION
static int setend_set_hw_mode(bool enable)
{
if (!cpu_supports_mixed_endian_el0())
@@ -586,31 +383,218 @@ static int t16_setend_handler(struct pt_regs *regs, u32 instr)
return rc;
}
-static struct undef_hook setend_hooks[] = {
- {
- .instr_mask = 0xfffffdff,
- .instr_val = 0xf1010000,
- .pstate_mask = PSR_AA32_MODE_MASK,
- .pstate_val = PSR_AA32_MODE_USR,
- .fn = a32_setend_handler,
- },
- {
- /* Thumb mode */
- .instr_mask = 0xfffffff7,
- .instr_val = 0x0000b650,
- .pstate_mask = (PSR_AA32_T_BIT | PSR_AA32_MODE_MASK),
- .pstate_val = (PSR_AA32_T_BIT | PSR_AA32_MODE_USR),
- .fn = t16_setend_handler,
- },
- {}
-};
+static bool try_emulate_setend(struct pt_regs *regs, u32 insn)
+{
+ if (compat_thumb_mode(regs) &&
+ (insn & 0xfffffff7) == 0x0000b650)
+ return t16_setend_handler(regs, insn) == 0;
+
+ if (compat_user_mode(regs) &&
+ (insn & 0xfffffdff) == 0xf1010000)
+ return a32_setend_handler(regs, insn) == 0;
-static struct insn_emulation_ops setend_ops = {
+ return false;
+}
+
+static struct insn_emulation insn_setend = {
.name = "setend",
.status = INSN_DEPRECATED,
- .hooks = setend_hooks,
+ .try_emulate = try_emulate_setend,
.set_hw_mode = setend_set_hw_mode,
};
+#endif /* CONFIG_SETEND_EMULATION */
+
+static struct insn_emulation *insn_emulations[] = {
+#ifdef CONFIG_SWP_EMULATION
+ &insn_swp,
+#endif
+#ifdef CONFIG_CP15_BARRIER_EMULATION
+ &insn_cp15_barrier,
+#endif
+#ifdef CONFIG_SETEND_EMULATION
+ &insn_setend,
+#endif
+};
+
+static DEFINE_MUTEX(insn_emulation_mutex);
+
+static void enable_insn_hw_mode(void *data)
+{
+ struct insn_emulation *insn = (struct insn_emulation *)data;
+ if (insn->set_hw_mode)
+ insn->set_hw_mode(true);
+}
+
+static void disable_insn_hw_mode(void *data)
+{
+ struct insn_emulation *insn = (struct insn_emulation *)data;
+ if (insn->set_hw_mode)
+ insn->set_hw_mode(false);
+}
+
+/* Run set_hw_mode(mode) on all active CPUs */
+static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
+{
+ if (!insn->set_hw_mode)
+ return -EINVAL;
+ if (enable)
+ on_each_cpu(enable_insn_hw_mode, (void *)insn, true);
+ else
+ on_each_cpu(disable_insn_hw_mode, (void *)insn, true);
+ return 0;
+}
+
+/*
+ * Run set_hw_mode for all insns on a starting CPU.
+ * Returns:
+ * 0 - If all the hooks ran successfully.
+ * -EINVAL - At least one hook is not supported by the CPU.
+ */
+static int run_all_insn_set_hw_mode(unsigned int cpu)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ /*
+ * Disable IRQs to serialize against an IPI from
+ * run_all_cpu_set_hw_mode(), ensuring the HW is programmed to the most
+ * recent enablement state if the two race with one another.
+ */
+ local_irq_save(flags);
+ for (int i = 0; i < ARRAY_SIZE(insn_emulations); i++) {
+ struct insn_emulation *insn = insn_emulations[i];
+ bool enable = READ_ONCE(insn->current_mode) == INSN_HW;
+ if (insn->set_hw_mode && insn->set_hw_mode(enable)) {
+ pr_warn("CPU[%u] cannot support the emulation of %s",
+ cpu, insn->name);
+ rc = -EINVAL;
+ }
+ }
+ local_irq_restore(flags);
+
+ return rc;
+}
+
+static int update_insn_emulation_mode(struct insn_emulation *insn,
+ enum insn_emulation_mode prev)
+{
+ int ret = 0;
+
+ switch (prev) {
+ case INSN_UNDEF: /* Nothing to be done */
+ break;
+ case INSN_EMULATE:
+ break;
+ case INSN_HW:
+ if (!run_all_cpu_set_hw_mode(insn, false))
+ pr_notice("Disabled %s support\n", insn->name);
+ break;
+ }
+
+ switch (insn->current_mode) {
+ case INSN_UNDEF:
+ break;
+ case INSN_EMULATE:
+ break;
+ case INSN_HW:
+ ret = run_all_cpu_set_hw_mode(insn, true);
+ if (!ret)
+ pr_notice("Enabled %s support\n", insn->name);
+ break;
+ }
+
+ return ret;
+}
+
+static int emulation_proc_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int ret = 0;
+ struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
+ enum insn_emulation_mode prev_mode = insn->current_mode;
+
+ mutex_lock(&insn_emulation_mutex);
+ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+ if (ret || !write || prev_mode == insn->current_mode)
+ goto ret;
+
+ ret = update_insn_emulation_mode(insn, prev_mode);
+ if (ret) {
+ /* Mode change failed, revert to previous mode. */
+ WRITE_ONCE(insn->current_mode, prev_mode);
+ update_insn_emulation_mode(insn, INSN_UNDEF);
+ }
+ret:
+ mutex_unlock(&insn_emulation_mutex);
+ return ret;
+}
+
+static void __init register_insn_emulation(struct insn_emulation *insn)
+{
+ struct ctl_table *sysctl;
+
+ insn->min = INSN_UNDEF;
+
+ switch (insn->status) {
+ case INSN_DEPRECATED:
+ insn->current_mode = INSN_EMULATE;
+ /* Disable the HW mode if it was turned on at early boot time */
+ run_all_cpu_set_hw_mode(insn, false);
+ insn->max = INSN_HW;
+ break;
+ case INSN_OBSOLETE:
+ insn->current_mode = INSN_UNDEF;
+ insn->max = INSN_EMULATE;
+ break;
+ case INSN_UNAVAILABLE:
+ insn->current_mode = INSN_UNDEF;
+ insn->max = INSN_UNDEF;
+ break;
+ }
+
+ /* Program the HW if required */
+ update_insn_emulation_mode(insn, INSN_UNDEF);
+
+ if (insn->status != INSN_UNAVAILABLE) {
+ sysctl = &insn->sysctl[0];
+
+ sysctl->mode = 0644;
+ sysctl->maxlen = sizeof(int);
+
+ sysctl->procname = insn->name;
+ sysctl->data = &insn->current_mode;
+ sysctl->extra1 = &insn->min;
+ sysctl->extra2 = &insn->max;
+ sysctl->proc_handler = emulation_proc_handler;
+
+ register_sysctl("abi", sysctl);
+ }
+}
+
+bool try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn)
+{
+ for (int i = 0; i < ARRAY_SIZE(insn_emulations); i++) {
+ struct insn_emulation *ie = insn_emulations[i];
+
+ if (ie->status == INSN_UNAVAILABLE)
+ continue;
+
+ /*
+ * A trap may race with the mode being changed
+ * INSN_EMULATE<->INSN_HW. Try to emulate the instruction to
+ * avoid a spurious UNDEF.
+ */
+ if (READ_ONCE(ie->current_mode) == INSN_UNDEF)
+ continue;
+
+ if (ie->try_emulate(regs, insn))
+ return true;
+ }
+
+ return false;
+}
/*
* Invoked as core_initcall, which guarantees that the instruction
@@ -618,24 +602,25 @@ static struct insn_emulation_ops setend_ops = {
*/
static int __init armv8_deprecated_init(void)
{
- if (IS_ENABLED(CONFIG_SWP_EMULATION))
- register_insn_emulation(&swp_ops);
+#ifdef CONFIG_SETEND_EMULATION
+ if (!system_supports_mixed_endian_el0()) {
+ insn_setend.status = INSN_UNAVAILABLE;
+ pr_info("setend instruction emulation is not supported on this system\n");
+ }
- if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
- register_insn_emulation(&cp15_barrier_ops);
+#endif
+ for (int i = 0; i < ARRAY_SIZE(insn_emulations); i++) {
+ struct insn_emulation *ie = insn_emulations[i];
- if (IS_ENABLED(CONFIG_SETEND_EMULATION)) {
- if (system_supports_mixed_endian_el0())
- register_insn_emulation(&setend_ops);
- else
- pr_info("setend instruction emulation is not supported on this system\n");
+ if (ie->status == INSN_UNAVAILABLE)
+ continue;
+
+ register_insn_emulation(ie);
}
cpuhp_setup_state_nocalls(CPUHP_AP_ARM64_ISNDEP_STARTING,
"arm64/isndep:starting",
run_all_insn_set_hw_mode, NULL);
- register_insn_emulation_sysctl();
-
return 0;
}
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 1197e7679882..2234624536d9 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -82,6 +82,19 @@ int main(void)
DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe));
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
BLANK();
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
+ DEFINE(FREGS_X0, offsetof(struct ftrace_regs, regs[0]));
+ DEFINE(FREGS_X2, offsetof(struct ftrace_regs, regs[2]));
+ DEFINE(FREGS_X4, offsetof(struct ftrace_regs, regs[4]));
+ DEFINE(FREGS_X6, offsetof(struct ftrace_regs, regs[6]));
+ DEFINE(FREGS_X8, offsetof(struct ftrace_regs, regs[8]));
+ DEFINE(FREGS_FP, offsetof(struct ftrace_regs, fp));
+ DEFINE(FREGS_LR, offsetof(struct ftrace_regs, lr));
+ DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp));
+ DEFINE(FREGS_PC, offsetof(struct ftrace_regs, pc));
+ DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs));
+ BLANK();
+#endif
#ifdef CONFIG_COMPAT
DEFINE(COMPAT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_sigframe, uc.uc_mcontext.arm_r0));
DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_rt_sigframe, sig.uc.uc_mcontext.arm_r0));
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 89ac00084f38..307faa2b4395 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -661,6 +661,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
CAP_MIDR_RANGE_LIST(trbe_write_out_of_range_cpus),
},
#endif
+#ifdef CONFIG_ARM64_ERRATUM_2645198
+ {
+ .desc = "ARM erratum 2645198",
+ .capability = ARM64_WORKAROUND_2645198,
+ ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A715)
+ },
+#endif
#ifdef CONFIG_ARM64_ERRATUM_2077057
{
.desc = "ARM erratum 2077057",
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index b3f37e2209ad..7e76e1fda2a1 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -212,6 +212,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
};
static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_CSSC_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_RPRFM_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_EL1_BC_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
FTR_STRICT, FTR_EXACT, ID_AA64ISAR2_EL1_APA3_SHIFT, 4, 0),
@@ -402,14 +404,14 @@ struct arm64_ftr_reg arm64_ftr_reg_ctrel0 = {
};
static const struct arm64_ftr_bits ftr_id_mmfr0[] = {
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_INNERSHR_SHIFT, 4, 0xf),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_FCSE_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_MMFR0_AUXREG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_TCM_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_SHARELVL_SHIFT, 4, 0),
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_OUTERSHR_SHIFT, 4, 0xf),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_PMSA_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_VMSA_SHIFT, 4, 0),
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_InnerShr_SHIFT, 4, 0xf),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_FCSE_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_AuxReg_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_TCM_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_ShareLvl_SHIFT, 4, 0),
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_OuterShr_SHIFT, 4, 0xf),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_PMSA_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR0_EL1_VMSA_SHIFT, 4, 0),
ARM64_FTR_END,
};
@@ -429,32 +431,32 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
};
static const struct arm64_ftr_bits ftr_mvfr0[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPROUND_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPSHVEC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPSQRT_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPDIVIDE_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPTRAP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPDP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_FPSP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_SIMD_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPRound_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPShVec_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPSqrt_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPDivide_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPTrap_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPDP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_FPSP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR0_EL1_SIMDReg_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_mvfr1[] = {
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_SIMDFMAC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_FPHP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_SIMDHP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_SIMDSP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_SIMDINT_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_SIMDLS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_FPDNAN_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_FPFTZ_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDFMAC_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_FPHP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDHP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDSP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDInt_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDLS_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_FPDNaN_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_FPFtZ_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_mvfr2[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR2_FPMISC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR2_SIMDMISC_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR2_EL1_FPMisc_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR2_EL1_SIMDMisc_SHIFT, 4, 0),
ARM64_FTR_END,
};
@@ -470,34 +472,34 @@ static const struct arm64_ftr_bits ftr_gmid[] = {
};
static const struct arm64_ftr_bits ftr_id_isar0[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_DIVIDE_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_DEBUG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_COPROC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_CMPBRANCH_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_BITFIELD_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_BITCOUNT_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_SWAP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_Divide_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_Debug_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_Coproc_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_CmpBranch_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_BitField_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_BitCount_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_EL1_Swap_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_isar5[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_RDM_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_CRC32_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_SHA2_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_SHA1_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_AES_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_SEVL_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_RDM_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_CRC32_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_SHA2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_SHA1_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_AES_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR5_EL1_SEVL_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_mmfr4[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EVT_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_CCIDX_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_LSM_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_HPDS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_CNP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_XNX_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_AC2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_EVT_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_CCIDX_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_LSM_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_HPDS_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_CnP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_XNX_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR4_EL1_AC2_SHIFT, 4, 0),
/*
* SpecSEI = 1 indicates that the PE might generate an SError on an
@@ -505,80 +507,80 @@ static const struct arm64_ftr_bits ftr_id_mmfr4[] = {
* SError might be generated than it will not be. Hence it has been
* classified as FTR_HIGHER_SAFE.
*/
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_MMFR4_SPECSEI_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_MMFR4_EL1_SpecSEI_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_isar4[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_SWP_FRAC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_PSR_M_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_SYNCH_PRIM_FRAC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_BARRIER_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_SMC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_WRITEBACK_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_WITHSHIFTS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_UNPRIV_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_SWP_frac_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_PSR_M_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_SynchPrim_frac_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_Barrier_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_SMC_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_Writeback_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_WithShifts_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR4_EL1_Unpriv_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_mmfr5[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR5_ETS_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_MMFR5_EL1_ETS_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_isar6[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_I8MM_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_BF16_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_SPECRES_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_SB_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_FHM_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_DP_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_JSCVT_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_I8MM_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_BF16_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_SPECRES_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_SB_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_FHM_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_DP_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_JSCVT_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_pfr0[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_DIT_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR0_CSV2_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_STATE3_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_STATE2_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_STATE1_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_STATE0_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_DIT_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_CSV2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_State3_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_State2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_State1_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR0_EL1_State0_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_pfr1[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_GIC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_VIRT_FRAC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_SEC_FRAC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_GENTIMER_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_VIRTUALIZATION_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_MPROGMOD_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_SECURITY_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_PROGMOD_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_GIC_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_Virt_frac_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_Sec_frac_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_GenTimer_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_Virtualization_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_MProgMod_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_Security_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR1_EL1_ProgMod_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_pfr2[] = {
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_SSBS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_CSV3_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_EL1_SSBS_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_EL1_CSV3_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_dfr0[] = {
/* [31:28] TraceFilt */
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_PERFMON_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MPROFDBG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MMAPTRC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_COPTRC_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MMAPDBG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_COPSDBG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_COPDBG_SHIFT, 4, 0),
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapDbg_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopSDbg_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopDbg_SHIFT, 4, 0),
ARM64_FTR_END,
};
static const struct arm64_ftr_bits ftr_id_dfr1[] = {
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR1_MTPMU_SHIFT, 4, 0),
+ S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR1_EL1_MTPMU_SHIFT, 4, 0),
ARM64_FTR_END,
};
@@ -1119,12 +1121,12 @@ static int update_32bit_cpu_features(int cpu, struct cpuinfo_32bit *info,
* EL1-dependent register fields to avoid spurious sanity check fails.
*/
if (!id_aa64pfr0_32bit_el1(pfr0)) {
- relax_cpu_ftr_reg(SYS_ID_ISAR4_EL1, ID_ISAR4_SMC_SHIFT);
- relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_VIRT_FRAC_SHIFT);
- relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_SEC_FRAC_SHIFT);
- relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_VIRTUALIZATION_SHIFT);
- relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_SECURITY_SHIFT);
- relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_PROGMOD_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_ISAR4_EL1, ID_ISAR4_EL1_SMC_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_EL1_Virt_frac_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_EL1_Sec_frac_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_EL1_Virtualization_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_EL1_Security_SHIFT);
+ relax_cpu_ftr_reg(SYS_ID_PFR1_EL1, ID_PFR1_EL1_ProgMod_SHIFT);
}
taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu,
@@ -2101,6 +2103,11 @@ static void cpu_trap_el0_impdef(const struct arm64_cpu_capabilities *__unused)
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_TIDCP);
}
+static void cpu_enable_dit(const struct arm64_cpu_capabilities *__unused)
+{
+ set_pstate_dit(1);
+}
+
/* Internal helper functions to match cpu capability type */
static bool
cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -2664,6 +2671,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.matches = has_cpuid_feature,
.cpu_enable = cpu_trap_el0_impdef,
},
+ {
+ .desc = "Data independent timing control (DIT)",
+ .capability = ARM64_HAS_DIT,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .sys_reg = SYS_ID_AA64PFR0_EL1,
+ .sign = FTR_UNSIGNED,
+ .field_pos = ID_AA64PFR0_EL1_DIT_SHIFT,
+ .field_width = 4,
+ .min_field_value = ID_AA64PFR0_EL1_DIT_IMP,
+ .matches = has_cpuid_feature,
+ .cpu_enable = cpu_enable_dit,
+ },
{},
};
@@ -2772,6 +2791,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_EL1_AT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_USCAT),
#ifdef CONFIG_ARM64_SVE
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_SVE_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR0_EL1_SVE_IMP, CAP_HWCAP, KERNEL_HWCAP_SVE),
+ HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_SVEver_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_SVEver_SVE2p1, CAP_HWCAP, KERNEL_HWCAP_SVE2P1),
HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_SVEver_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_SVEver_SVE2, CAP_HWCAP, KERNEL_HWCAP_SVE2),
HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_AES_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEAES),
HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_AES_PMULL128, CAP_HWCAP, KERNEL_HWCAP_SVEPMULL),
@@ -2798,6 +2818,8 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
#endif /* CONFIG_ARM64_MTE */
HWCAP_CAP(SYS_ID_AA64MMFR0_EL1, ID_AA64MMFR0_EL1_ECV_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ECV),
HWCAP_CAP(SYS_ID_AA64MMFR1_EL1, ID_AA64MMFR1_EL1_AFP_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_AFP),
+ HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_CSSC_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_CSSC_IMP, CAP_HWCAP, KERNEL_HWCAP_CSSC),
+ HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_RPRFM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_RPRFM_IMP, CAP_HWCAP, KERNEL_HWCAP_RPRFM),
HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_RPRES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_RPRES),
HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_WFxT_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_WFxT_IMP, CAP_HWCAP, KERNEL_HWCAP_WFXT),
#ifdef CONFIG_ARM64_SME
@@ -2829,24 +2851,24 @@ static bool compat_has_neon(const struct arm64_cpu_capabilities *cap, int scope)
else
mvfr1 = read_sysreg_s(SYS_MVFR1_EL1);
- return cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDSP_SHIFT) &&
- cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDINT_SHIFT) &&
- cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDLS_SHIFT);
+ return cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_EL1_SIMDSP_SHIFT) &&
+ cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_EL1_SIMDInt_SHIFT) &&
+ cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_EL1_SIMDLS_SHIFT);
}
#endif
static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = {
#ifdef CONFIG_COMPAT
HWCAP_CAP_MATCH(compat_has_neon, CAP_COMPAT_HWCAP, COMPAT_HWCAP_NEON),
- HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_SIMDFMAC_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv4),
+ HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_EL1_SIMDFMAC_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv4),
/* Arm v8 mandates MVFR0.FPDP == {0, 2}. So, piggy back on this for the presence of VFP support */
- HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFP),
- HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv3),
- HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
- HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
- HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
- HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
- HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
+ HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_EL1_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFP),
+ HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_EL1_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv3),
+ HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_AES_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
+ HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_AES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
+ HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_SHA1_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
+ HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_SHA2_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
+ HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_CRC32_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
#endif
{},
};
@@ -3435,35 +3457,22 @@ int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt)
return rc;
}
-static int emulate_mrs(struct pt_regs *regs, u32 insn)
+bool try_emulate_mrs(struct pt_regs *regs, u32 insn)
{
u32 sys_reg, rt;
+ if (compat_user_mode(regs) || !aarch64_insn_is_mrs(insn))
+ return false;
+
/*
* sys_reg values are defined as used in mrs/msr instruction.
* shift the imm value to get the encoding.
*/
sys_reg = (u32)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_16, insn) << 5;
rt = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RT, insn);
- return do_emulate_mrs(regs, sys_reg, rt);
+ return do_emulate_mrs(regs, sys_reg, rt) == 0;
}
-static struct undef_hook mrs_hook = {
- .instr_mask = 0xffff0000,
- .instr_val = 0xd5380000,
- .pstate_mask = PSR_AA32_MODE_MASK,
- .pstate_val = PSR_MODE_EL0t,
- .fn = emulate_mrs,
-};
-
-static int __init enable_mrs_emulation(void)
-{
- register_undef_hook(&mrs_hook);
- return 0;
-}
-
-core_initcall(enable_mrs_emulation);
-
enum mitigation_state arm64_get_meltdown_state(void)
{
if (__meltdown_safe)
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 28d4f442b0bc..379695262b77 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -116,6 +116,9 @@ static const char *const hwcap_str[] = {
[KERNEL_HWCAP_WFXT] = "wfxt",
[KERNEL_HWCAP_EBF16] = "ebf16",
[KERNEL_HWCAP_SVE_EBF16] = "sveebf16",
+ [KERNEL_HWCAP_CSSC] = "cssc",
+ [KERNEL_HWCAP_RPRFM] = "rprfm",
+ [KERNEL_HWCAP_SVE2P1] = "sve2p1",
};
#ifdef CONFIG_COMPAT
diff --git a/arch/arm64/kernel/efi-rt-wrapper.S b/arch/arm64/kernel/efi-rt-wrapper.S
index 67babd5f04c2..75691a2641c1 100644
--- a/arch/arm64/kernel/efi-rt-wrapper.S
+++ b/arch/arm64/kernel/efi-rt-wrapper.S
@@ -6,7 +6,7 @@
#include <linux/linkage.h>
SYM_FUNC_START(__efi_rt_asm_wrapper)
- stp x29, x30, [sp, #-112]!
+ stp x29, x30, [sp, #-32]!
mov x29, sp
/*
@@ -17,20 +17,6 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
stp x1, x18, [sp, #16]
/*
- * Preserve all callee saved registers and record the stack pointer
- * value in a per-CPU variable so we can recover from synchronous
- * exceptions occurring while running the firmware routines.
- */
- stp x19, x20, [sp, #32]
- stp x21, x22, [sp, #48]
- stp x23, x24, [sp, #64]
- stp x25, x26, [sp, #80]
- stp x27, x28, [sp, #96]
-
- adr_this_cpu x8, __efi_rt_asm_recover_sp, x9
- str x29, [x8]
-
- /*
* We are lucky enough that no EFI runtime services take more than
* 5 arguments, so all are passed in registers rather than via the
* stack.
@@ -45,7 +31,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
ldp x1, x2, [sp, #16]
cmp x2, x18
- ldp x29, x30, [sp], #112
+ ldp x29, x30, [sp], #32
b.ne 0f
ret
0:
@@ -59,18 +45,3 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
mov x18, x2
b efi_handle_corrupted_x18 // tail call
SYM_FUNC_END(__efi_rt_asm_wrapper)
-
-SYM_FUNC_START(__efi_rt_asm_recover)
- ldr_this_cpu x8, __efi_rt_asm_recover_sp, x9
- mov sp, x8
-
- ldp x0, x18, [sp, #16]
- ldp x19, x20, [sp, #32]
- ldp x21, x22, [sp, #48]
- ldp x23, x24, [sp, #64]
- ldp x25, x26, [sp, #80]
- ldp x27, x28, [sp, #96]
- ldp x29, x30, [sp], #112
-
- b efi_handle_runtime_exception
-SYM_FUNC_END(__efi_rt_asm_recover)
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index 8d36e66a6e64..a908a37f0367 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -9,10 +9,17 @@
#include <linux/efi.h>
#include <linux/init.h>
-#include <linux/percpu.h>
#include <asm/efi.h>
+static bool region_is_misaligned(const efi_memory_desc_t *md)
+{
+ if (PAGE_SIZE == EFI_PAGE_SIZE)
+ return false;
+ return !PAGE_ALIGNED(md->phys_addr) ||
+ !PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT);
+}
+
/*
* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
* executable, everything else can be mapped with the XN bits
@@ -26,14 +33,22 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md)
if (type == EFI_MEMORY_MAPPED_IO)
return PROT_DEVICE_nGnRE;
- if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr),
- "UEFI Runtime regions are not aligned to 64 KB -- buggy firmware?"))
+ if (region_is_misaligned(md)) {
+ static bool __initdata code_is_misaligned;
+
/*
- * If the region is not aligned to the page size of the OS, we
- * can not use strict permissions, since that would also affect
- * the mapping attributes of the adjacent regions.
+ * Regions that are not aligned to the OS page size cannot be
+ * mapped with strict permissions, as those might interfere
+ * with the permissions that are needed by the adjacent
+ * region's mapping. However, if we haven't encountered any
+ * misaligned runtime code regions so far, we can safely use
+ * non-executable permissions for non-code regions.
*/
- return pgprot_val(PAGE_KERNEL_EXEC);
+ code_is_misaligned |= (type == EFI_RUNTIME_SERVICES_CODE);
+
+ return code_is_misaligned ? pgprot_val(PAGE_KERNEL_EXEC)
+ : pgprot_val(PAGE_KERNEL);
+ }
/* R-- */
if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
@@ -64,19 +79,16 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE ||
md->type == EFI_RUNTIME_SERVICES_DATA);
- if (!PAGE_ALIGNED(md->phys_addr) ||
- !PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT)) {
- /*
- * If the end address of this region is not aligned to page
- * size, the mapping is rounded up, and may end up sharing a
- * page frame with the next UEFI memory region. If we create
- * a block entry now, we may need to split it again when mapping
- * the next region, and support for that is going to be removed
- * from the MMU routines. So avoid block mappings altogether in
- * that case.
- */
+ /*
+ * If this region is not aligned to the page size used by the OS, the
+ * mapping will be rounded outwards, and may end up sharing a page
+ * frame with an adjacent runtime memory region. Given that the page
+ * table descriptor covering the shared page will be rewritten when the
+ * adjacent region gets mapped, we must avoid block mappings here so we
+ * don't have to worry about splitting them when that happens.
+ */
+ if (region_is_misaligned(md))
page_mappings_only = true;
- }
create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
md->num_pages << EFI_PAGE_SHIFT,
@@ -103,6 +115,9 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
md->type != EFI_RUNTIME_SERVICES_DATA);
+ if (region_is_misaligned(md))
+ return 0;
+
/*
* Calling apply_to_page_range() is only safe on regions that are
* guaranteed to be mapped down to pages. Since we are only called
@@ -129,28 +144,3 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)
pr_err_ratelimited(FW_BUG "register x18 corrupted by EFI %s\n", f);
return s;
}
-
-asmlinkage DEFINE_PER_CPU(u64, __efi_rt_asm_recover_sp);
-
-asmlinkage efi_status_t __efi_rt_asm_recover(void);
-
-asmlinkage efi_status_t efi_handle_runtime_exception(const char *f)
-{
- pr_err(FW_BUG "Synchronous exception occurred in EFI runtime service %s()\n", f);
- clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
- return EFI_ABORTED;
-}
-
-bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
-{
- /* Check whether the exception occurred while running the firmware */
- if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
- return false;
-
- pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
- add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
- dump_stack();
-
- regs->pc = (u64)__efi_rt_asm_recover;
- return true;
-}
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 27369fa1c032..cce1167199e3 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -30,7 +30,7 @@
/*
* Handle IRQ/context state management when entering from kernel mode.
* Before this function is called it is not safe to call regular kernel code,
- * intrumentable code, or any code which may trigger an exception.
+ * instrumentable code, or any code which may trigger an exception.
*
* This is intended to match the logic in irqentry_enter(), handling the kernel
* mode transitions only.
@@ -63,7 +63,7 @@ static void noinstr enter_from_kernel_mode(struct pt_regs *regs)
/*
* Handle IRQ/context state management when exiting to kernel mode.
* After this function returns it is not safe to call regular kernel code,
- * intrumentable code, or any code which may trigger an exception.
+ * instrumentable code, or any code which may trigger an exception.
*
* This is intended to match the logic in irqentry_exit(), handling the kernel
* mode transitions only, and with preemption handled elsewhere.
@@ -97,7 +97,7 @@ static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
/*
* Handle IRQ/context state management when entering from user mode.
* Before this function is called it is not safe to call regular kernel code,
- * intrumentable code, or any code which may trigger an exception.
+ * instrumentable code, or any code which may trigger an exception.
*/
static __always_inline void __enter_from_user_mode(void)
{
@@ -116,7 +116,7 @@ static __always_inline void enter_from_user_mode(struct pt_regs *regs)
/*
* Handle IRQ/context state management when exiting to user mode.
* After this function returns it is not safe to call regular kernel code,
- * intrumentable code, or any code which may trigger an exception.
+ * instrumentable code, or any code which may trigger an exception.
*/
static __always_inline void __exit_to_user_mode(void)
{
@@ -152,7 +152,7 @@ asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs)
/*
* Handle IRQ/context state management when entering an NMI from user/kernel
* mode. Before this function is called it is not safe to call regular kernel
- * code, intrumentable code, or any code which may trigger an exception.
+ * code, instrumentable code, or any code which may trigger an exception.
*/
static void noinstr arm64_enter_nmi(struct pt_regs *regs)
{
@@ -170,7 +170,7 @@ static void noinstr arm64_enter_nmi(struct pt_regs *regs)
/*
* Handle IRQ/context state management when exiting an NMI from user/kernel
* mode. After this function returns it is not safe to call regular kernel
- * code, intrumentable code, or any code which may trigger an exception.
+ * code, instrumentable code, or any code which may trigger an exception.
*/
static void noinstr arm64_exit_nmi(struct pt_regs *regs)
{
@@ -192,7 +192,7 @@ static void noinstr arm64_exit_nmi(struct pt_regs *regs)
/*
* Handle IRQ/context state management when entering a debug exception from
* kernel mode. Before this function is called it is not safe to call regular
- * kernel code, intrumentable code, or any code which may trigger an exception.
+ * kernel code, instrumentable code, or any code which may trigger an exception.
*/
static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
{
@@ -207,7 +207,7 @@ static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
/*
* Handle IRQ/context state management when exiting a debug exception from
* kernel mode. After this function returns it is not safe to call regular
- * kernel code, intrumentable code, or any code which may trigger an exception.
+ * kernel code, instrumentable code, or any code which may trigger an exception.
*/
static void noinstr arm64_exit_el1_dbg(struct pt_regs *regs)
{
@@ -384,7 +384,7 @@ static void noinstr el1_undef(struct pt_regs *regs, unsigned long esr)
{
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
- do_undefinstr(regs, esr);
+ do_el1_undef(regs, esr);
local_daif_mask();
exit_to_kernel_mode(regs);
}
@@ -570,7 +570,7 @@ static void noinstr el0_sys(struct pt_regs *regs, unsigned long esr)
{
enter_from_user_mode(regs);
local_daif_restore(DAIF_PROCCTX);
- do_sysinstr(esr, regs);
+ do_el0_sys(esr, regs);
exit_to_user_mode(regs);
}
@@ -599,7 +599,7 @@ static void noinstr el0_undef(struct pt_regs *regs, unsigned long esr)
{
enter_from_user_mode(regs);
local_daif_restore(DAIF_PROCCTX);
- do_undefinstr(regs, esr);
+ do_el0_undef(regs, esr);
exit_to_user_mode(regs);
}
@@ -762,7 +762,7 @@ static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr)
{
enter_from_user_mode(regs);
local_daif_restore(DAIF_PROCCTX);
- do_cp15instr(esr, regs);
+ do_el0_cp15(esr, regs);
exit_to_user_mode(regs);
}
diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
index 795344ab4ec4..3b625f76ffba 100644
--- a/arch/arm64/kernel/entry-ftrace.S
+++ b/arch/arm64/kernel/entry-ftrace.S
@@ -13,83 +13,58 @@
#include <asm/ftrace.h>
#include <asm/insn.h>
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
/*
* Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before
* the regular function prologue. For an enabled callsite, ftrace_init_nop() and
* ftrace_make_call() have patched those NOPs to:
*
* MOV X9, LR
- * BL <entry>
- *
- * ... where <entry> is either ftrace_caller or ftrace_regs_caller.
+ * BL ftrace_caller
*
* Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are
* live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to
* clobber.
*
- * We save the callsite's context into a pt_regs before invoking any ftrace
- * callbacks. So that we can get a sensible backtrace, we create a stack record
- * for the callsite and the ftrace entry assembly. This is not sufficient for
- * reliable stacktrace: until we create the callsite stack record, its caller
- * is missing from the LR and existing chain of frame records.
+ * We save the callsite's context into a struct ftrace_regs before invoking any
+ * ftrace callbacks. So that we can get a sensible backtrace, we create frame
+ * records for the callsite and the ftrace entry assembly. This is not
+ * sufficient for reliable stacktrace: until we create the callsite stack
+ * record, its caller is missing from the LR and existing chain of frame
+ * records.
*/
- .macro ftrace_regs_entry, allregs=0
- /* Make room for pt_regs, plus a callee frame */
- sub sp, sp, #(PT_REGS_SIZE + 16)
-
- /* Save function arguments (and x9 for simplicity) */
- stp x0, x1, [sp, #S_X0]
- stp x2, x3, [sp, #S_X2]
- stp x4, x5, [sp, #S_X4]
- stp x6, x7, [sp, #S_X6]
- stp x8, x9, [sp, #S_X8]
-
- /* Optionally save the callee-saved registers, always save the FP */
- .if \allregs == 1
- stp x10, x11, [sp, #S_X10]
- stp x12, x13, [sp, #S_X12]
- stp x14, x15, [sp, #S_X14]
- stp x16, x17, [sp, #S_X16]
- stp x18, x19, [sp, #S_X18]
- stp x20, x21, [sp, #S_X20]
- stp x22, x23, [sp, #S_X22]
- stp x24, x25, [sp, #S_X24]
- stp x26, x27, [sp, #S_X26]
- stp x28, x29, [sp, #S_X28]
- .else
- str x29, [sp, #S_FP]
- .endif
-
- /* Save the callsite's SP and LR */
- add x10, sp, #(PT_REGS_SIZE + 16)
- stp x9, x10, [sp, #S_LR]
+SYM_CODE_START(ftrace_caller)
+ bti c
- /* Save the PC after the ftrace callsite */
- str x30, [sp, #S_PC]
+ /* Save original SP */
+ mov x10, sp
- /* Create a frame record for the callsite above pt_regs */
- stp x29, x9, [sp, #PT_REGS_SIZE]
- add x29, sp, #PT_REGS_SIZE
+ /* Make room for ftrace regs, plus two frame records */
+ sub sp, sp, #(FREGS_SIZE + 32)
- /* Create our frame record within pt_regs. */
- stp x29, x30, [sp, #S_STACKFRAME]
- add x29, sp, #S_STACKFRAME
- .endm
+ /* Save function arguments */
+ stp x0, x1, [sp, #FREGS_X0]
+ stp x2, x3, [sp, #FREGS_X2]
+ stp x4, x5, [sp, #FREGS_X4]
+ stp x6, x7, [sp, #FREGS_X6]
+ str x8, [sp, #FREGS_X8]
-SYM_CODE_START(ftrace_regs_caller)
- bti c
- ftrace_regs_entry 1
- b ftrace_common
-SYM_CODE_END(ftrace_regs_caller)
+ /* Save the callsite's FP, LR, SP */
+ str x29, [sp, #FREGS_FP]
+ str x9, [sp, #FREGS_LR]
+ str x10, [sp, #FREGS_SP]
-SYM_CODE_START(ftrace_caller)
- bti c
- ftrace_regs_entry 0
- b ftrace_common
-SYM_CODE_END(ftrace_caller)
+ /* Save the PC after the ftrace callsite */
+ str x30, [sp, #FREGS_PC]
+
+ /* Create a frame record for the callsite above the ftrace regs */
+ stp x29, x9, [sp, #FREGS_SIZE + 16]
+ add x29, sp, #FREGS_SIZE + 16
+
+ /* Create our frame record above the ftrace regs */
+ stp x29, x30, [sp, #FREGS_SIZE]
+ add x29, sp, #FREGS_SIZE
-SYM_CODE_START(ftrace_common)
sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn)
mov x1, x9 // parent_ip (callsite's LR)
ldr_l x2, function_trace_op // op
@@ -104,24 +79,24 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
* to restore x0-x8, x29, and x30.
*/
/* Restore function arguments */
- ldp x0, x1, [sp]
- ldp x2, x3, [sp, #S_X2]
- ldp x4, x5, [sp, #S_X4]
- ldp x6, x7, [sp, #S_X6]
- ldr x8, [sp, #S_X8]
+ ldp x0, x1, [sp, #FREGS_X0]
+ ldp x2, x3, [sp, #FREGS_X2]
+ ldp x4, x5, [sp, #FREGS_X4]
+ ldp x6, x7, [sp, #FREGS_X6]
+ ldr x8, [sp, #FREGS_X8]
/* Restore the callsite's FP, LR, PC */
- ldr x29, [sp, #S_FP]
- ldr x30, [sp, #S_LR]
- ldr x9, [sp, #S_PC]
+ ldr x29, [sp, #FREGS_FP]
+ ldr x30, [sp, #FREGS_LR]
+ ldr x9, [sp, #FREGS_PC]
/* Restore the callsite's SP */
- add sp, sp, #PT_REGS_SIZE + 16
+ add sp, sp, #FREGS_SIZE + 32
ret x9
-SYM_CODE_END(ftrace_common)
+SYM_CODE_END(ftrace_caller)
-#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
/*
* Gcc with -pg will put the following code in the beginning of each function:
@@ -195,44 +170,6 @@ SYM_CODE_END(ftrace_common)
add \reg, \reg, #8
.endm
-#ifndef CONFIG_DYNAMIC_FTRACE
-/*
- * void _mcount(unsigned long return_address)
- * @return_address: return address to instrumented function
- *
- * This function makes calls, if enabled, to:
- * - tracer function to probe instrumented function's entry,
- * - ftrace_graph_caller to set up an exit hook
- */
-SYM_FUNC_START(_mcount)
- mcount_enter
-
- ldr_l x2, ftrace_trace_function
- adr x0, ftrace_stub
- cmp x0, x2 // if (ftrace_trace_function
- b.eq skip_ftrace_call // != ftrace_stub) {
-
- mcount_get_pc x0 // function's pc
- mcount_get_lr x1 // function's lr (= parent's pc)
- blr x2 // (*ftrace_trace_function)(pc, lr);
-
-skip_ftrace_call: // }
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- ldr_l x2, ftrace_graph_return
- cmp x0, x2 // if ((ftrace_graph_return
- b.ne ftrace_graph_caller // != ftrace_stub)
-
- ldr_l x2, ftrace_graph_entry // || (ftrace_graph_entry
- adr_l x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub))
- cmp x0, x2
- b.ne ftrace_graph_caller // ftrace_graph_caller();
-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
- mcount_exit
-SYM_FUNC_END(_mcount)
-EXPORT_SYMBOL(_mcount)
-NOKPROBE(_mcount)
-
-#else /* CONFIG_DYNAMIC_FTRACE */
/*
* _mcount() is used to build the kernel with -pg option, but all the branch
* instructions to _mcount() are replaced to NOP initially at kernel start up,
@@ -272,7 +209,6 @@ SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();
mcount_exit
SYM_FUNC_END(ftrace_caller)
-#endif /* CONFIG_DYNAMIC_FTRACE */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/*
@@ -293,17 +229,17 @@ SYM_FUNC_START(ftrace_graph_caller)
mcount_exit
SYM_FUNC_END(ftrace_graph_caller)
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
SYM_TYPED_FUNC_START(ftrace_stub)
ret
SYM_FUNC_END(ftrace_stub)
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
SYM_TYPED_FUNC_START(ftrace_stub_graph)
ret
SYM_FUNC_END(ftrace_stub_graph)
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/*
* void return_to_handler(void)
*
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index e28137d64b76..11cb99c4d298 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -197,6 +197,9 @@ alternative_cb_end
.endm
.macro kernel_entry, el, regsize = 64
+ .if \el == 0
+ alternative_insn nop, SET_PSTATE_DIT(1), ARM64_HAS_DIT
+ .endif
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
.endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 23834d96d1e7..dcc81e7200d4 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -118,16 +118,8 @@
* returned from the 2nd syscall yet, TIF_FOREIGN_FPSTATE is still set so
* whatever is in the FPSIMD registers is not saved to memory, but discarded.
*/
-struct fpsimd_last_state_struct {
- struct user_fpsimd_state *st;
- void *sve_state;
- void *za_state;
- u64 *svcr;
- unsigned int sve_vl;
- unsigned int sme_vl;
-};
-static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
+static DEFINE_PER_CPU(struct cpu_fp_state, fpsimd_last_state);
__ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {
#ifdef CONFIG_ARM64_SVE
@@ -330,15 +322,6 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
* The task can execute SVE instructions while in userspace without
* trapping to the kernel.
*
- * When stored, Z0-Z31 (incorporating Vn in bits[127:0] or the
- * corresponding Zn), P0-P15 and FFR are encoded in
- * task->thread.sve_state, formatted appropriately for vector
- * length task->thread.sve_vl or, if SVCR.SM is set,
- * task->thread.sme_vl.
- *
- * task->thread.sve_state must point to a valid buffer at least
- * sve_state_size(task) bytes in size.
- *
* During any syscall, the kernel may optionally clear TIF_SVE and
* discard the vector state except for the FPSIMD subset.
*
@@ -348,7 +331,15 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
* do_sve_acc() to be called, which does some preparation and then
* sets TIF_SVE.
*
- * When stored, FPSIMD registers V0-V31 are encoded in
+ * During any syscall, the kernel may optionally clear TIF_SVE and
+ * discard the vector state except for the FPSIMD subset.
+ *
+ * The data will be stored in one of two formats:
+ *
+ * * FPSIMD only - FP_STATE_FPSIMD:
+ *
+ * When the FPSIMD only state stored task->thread.fp_type is set to
+ * FP_STATE_FPSIMD, the FPSIMD registers V0-V31 are encoded in
* task->thread.uw.fpsimd_state; bits [max : 128] for each of Z0-Z31 are
* logically zero but not stored anywhere; P0-P15 and FFR are not
* stored and have unspecified values from userspace's point of
@@ -356,7 +347,23 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
* but userspace is discouraged from relying on this.
*
* task->thread.sve_state does not need to be non-NULL, valid or any
- * particular size: it must not be dereferenced.
+ * particular size: it must not be dereferenced and any data stored
+ * there should be considered stale and not referenced.
+ *
+ * * SVE state - FP_STATE_SVE:
+ *
+ * When the full SVE state is stored task->thread.fp_type is set to
+ * FP_STATE_SVE and Z0-Z31 (incorporating Vn in bits[127:0] or the
+ * corresponding Zn), P0-P15 and FFR are encoded in in
+ * task->thread.sve_state, formatted appropriately for vector
+ * length task->thread.sve_vl or, if SVCR.SM is set,
+ * task->thread.sme_vl. The storage for the vector registers in
+ * task->thread.uw.fpsimd_state should be ignored.
+ *
+ * task->thread.sve_state must point to a valid buffer at least
+ * sve_state_size(task) bytes in size. The data stored in
+ * task->thread.uw.fpsimd_state.vregs should be considered stale
+ * and not referenced.
*
* * FPSR and FPCR are always stored in task->thread.uw.fpsimd_state
* irrespective of whether TIF_SVE is clear or set, since these are
@@ -378,11 +385,37 @@ static void task_fpsimd_load(void)
WARN_ON(!system_supports_fpsimd());
WARN_ON(!have_cpu_fpsimd_context());
- /* Check if we should restore SVE first */
- if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
- sve_set_vq(sve_vq_from_vl(task_get_sve_vl(current)) - 1);
- restore_sve_regs = true;
- restore_ffr = true;
+ if (system_supports_sve()) {
+ switch (current->thread.fp_type) {
+ case FP_STATE_FPSIMD:
+ /* Stop tracking SVE for this task until next use. */
+ if (test_and_clear_thread_flag(TIF_SVE))
+ sve_user_disable();
+ break;
+ case FP_STATE_SVE:
+ if (!thread_sm_enabled(&current->thread) &&
+ !WARN_ON_ONCE(!test_and_set_thread_flag(TIF_SVE)))
+ sve_user_enable();
+
+ if (test_thread_flag(TIF_SVE))
+ sve_set_vq(sve_vq_from_vl(task_get_sve_vl(current)) - 1);
+
+ restore_sve_regs = true;
+ restore_ffr = true;
+ break;
+ default:
+ /*
+ * This indicates either a bug in
+ * fpsimd_save() or memory corruption, we
+ * should always record an explicit format
+ * when we save. We always at least have the
+ * memory allocated for FPSMID registers so
+ * try that and hope for the best.
+ */
+ WARN_ON_ONCE(1);
+ clear_thread_flag(TIF_SVE);
+ break;
+ }
}
/* Restore SME, override SVE register configuration if needed */
@@ -398,18 +431,19 @@ static void task_fpsimd_load(void)
if (thread_za_enabled(&current->thread))
za_load_state(current->thread.za_state);
- if (thread_sm_enabled(&current->thread)) {
- restore_sve_regs = true;
+ if (thread_sm_enabled(&current->thread))
restore_ffr = system_supports_fa64();
- }
}
- if (restore_sve_regs)
+ if (restore_sve_regs) {
+ WARN_ON_ONCE(current->thread.fp_type != FP_STATE_SVE);
sve_load_state(sve_pffr(&current->thread),
&current->thread.uw.fpsimd_state.fpsr,
restore_ffr);
- else
+ } else {
+ WARN_ON_ONCE(current->thread.fp_type != FP_STATE_FPSIMD);
fpsimd_load_state(&current->thread.uw.fpsimd_state);
+ }
}
/*
@@ -419,12 +453,12 @@ static void task_fpsimd_load(void)
* last, if KVM is involved this may be the guest VM context rather
* than the host thread for the VM pointed to by current. This means
* that we must always reference the state storage via last rather
- * than via current, other than the TIF_ flags which KVM will
- * carefully maintain for us.
+ * than via current, if we are saving KVM state then it will have
+ * ensured that the type of registers to save is set in last->to_save.
*/
static void fpsimd_save(void)
{
- struct fpsimd_last_state_struct const *last =
+ struct cpu_fp_state const *last =
this_cpu_ptr(&fpsimd_last_state);
/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
bool save_sve_regs = false;
@@ -437,7 +471,14 @@ static void fpsimd_save(void)
if (test_thread_flag(TIF_FOREIGN_FPSTATE))
return;
- if (test_thread_flag(TIF_SVE)) {
+ /*
+ * If a task is in a syscall the ABI allows us to only
+ * preserve the state shared with FPSIMD so don't bother
+ * saving the full SVE state in that case.
+ */
+ if ((last->to_save == FP_STATE_CURRENT && test_thread_flag(TIF_SVE) &&
+ !in_syscall(current_pt_regs())) ||
+ last->to_save == FP_STATE_SVE) {
save_sve_regs = true;
save_ffr = true;
vl = last->sve_vl;
@@ -474,8 +515,10 @@ static void fpsimd_save(void)
sve_save_state((char *)last->sve_state +
sve_ffr_offset(vl),
&last->st->fpsr, save_ffr);
+ *last->fp_type = FP_STATE_SVE;
} else {
fpsimd_save_state(last->st);
+ *last->fp_type = FP_STATE_FPSIMD;
}
}
@@ -768,8 +811,7 @@ void fpsimd_sync_to_sve(struct task_struct *task)
*/
void sve_sync_to_fpsimd(struct task_struct *task)
{
- if (test_tsk_thread_flag(task, TIF_SVE) ||
- thread_sm_enabled(&task->thread))
+ if (task->thread.fp_type == FP_STATE_SVE)
sve_to_fpsimd(task);
}
@@ -848,8 +890,10 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type,
fpsimd_flush_task_state(task);
if (test_and_clear_tsk_thread_flag(task, TIF_SVE) ||
- thread_sm_enabled(&task->thread))
+ thread_sm_enabled(&task->thread)) {
sve_to_fpsimd(task);
+ task->thread.fp_type = FP_STATE_FPSIMD;
+ }
if (system_supports_sme() && type == ARM64_VEC_SME) {
task->thread.svcr &= ~(SVCR_SM_MASK |
@@ -1368,6 +1412,7 @@ static void sve_init_regs(void)
fpsimd_bind_task_to_cpu();
} else {
fpsimd_to_sve(current);
+ current->thread.fp_type = FP_STATE_SVE;
}
}
@@ -1596,6 +1641,8 @@ void fpsimd_flush_thread(void)
current->thread.svcr = 0;
}
+ current->thread.fp_type = FP_STATE_FPSIMD;
+
put_cpu_fpsimd_context();
kfree(sve_state);
kfree(za_state);
@@ -1628,14 +1675,38 @@ void fpsimd_signal_preserve_current_state(void)
}
/*
+ * Called by KVM when entering the guest.
+ */
+void fpsimd_kvm_prepare(void)
+{
+ if (!system_supports_sve())
+ return;
+
+ /*
+ * KVM does not save host SVE state since we can only enter
+ * the guest from a syscall so the ABI means that only the
+ * non-saved SVE state needs to be saved. If we have left
+ * SVE enabled for performance reasons then update the task
+ * state to be FPSIMD only.
+ */
+ get_cpu_fpsimd_context();
+
+ if (test_and_clear_thread_flag(TIF_SVE)) {
+ sve_to_fpsimd(current);
+ current->thread.fp_type = FP_STATE_FPSIMD;
+ }
+
+ put_cpu_fpsimd_context();
+}
+
+/*
* Associate current's FPSIMD context with this cpu
* The caller must have ownership of the cpu FPSIMD context before calling
* this function.
*/
static void fpsimd_bind_task_to_cpu(void)
{
- struct fpsimd_last_state_struct *last =
- this_cpu_ptr(&fpsimd_last_state);
+ struct cpu_fp_state *last = this_cpu_ptr(&fpsimd_last_state);
WARN_ON(!system_supports_fpsimd());
last->st = &current->thread.uw.fpsimd_state;
@@ -1644,6 +1715,8 @@ static void fpsimd_bind_task_to_cpu(void)
last->sve_vl = task_get_sve_vl(current);
last->sme_vl = task_get_sme_vl(current);
last->svcr = &current->thread.svcr;
+ last->fp_type = &current->thread.fp_type;
+ last->to_save = FP_STATE_CURRENT;
current->thread.fpsimd_cpu = smp_processor_id();
/*
@@ -1665,22 +1738,14 @@ static void fpsimd_bind_task_to_cpu(void)
}
}
-void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
- unsigned int sve_vl, void *za_state,
- unsigned int sme_vl, u64 *svcr)
+void fpsimd_bind_state_to_cpu(struct cpu_fp_state *state)
{
- struct fpsimd_last_state_struct *last =
- this_cpu_ptr(&fpsimd_last_state);
+ struct cpu_fp_state *last = this_cpu_ptr(&fpsimd_last_state);
WARN_ON(!system_supports_fpsimd());
WARN_ON(!in_softirq() && !irqs_disabled());
- last->st = st;
- last->svcr = svcr;
- last->sve_state = sve_state;
- last->za_state = za_state;
- last->sve_vl = sve_vl;
- last->sme_vl = sme_vl;
+ *last = *state;
}
/*
@@ -1838,7 +1903,7 @@ void kernel_neon_begin(void)
/* Invalidate any task state remaining in the fpsimd regs: */
fpsimd_flush_cpu_state();
}
-EXPORT_SYMBOL(kernel_neon_begin);
+EXPORT_SYMBOL_GPL(kernel_neon_begin);
/*
* kernel_neon_end(): give the CPU FPSIMD registers back to the current task
@@ -1856,7 +1921,7 @@ void kernel_neon_end(void)
put_cpu_fpsimd_context();
}
-EXPORT_SYMBOL(kernel_neon_end);
+EXPORT_SYMBOL_GPL(kernel_neon_end);
#ifdef CONFIG_EFI
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index 8745175f4a75..b30b955a8921 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -17,7 +17,49 @@
#include <asm/insn.h>
#include <asm/patching.h>
-#ifdef CONFIG_DYNAMIC_FTRACE
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
+struct fregs_offset {
+ const char *name;
+ int offset;
+};
+
+#define FREGS_OFFSET(n, field) \
+{ \
+ .name = n, \
+ .offset = offsetof(struct ftrace_regs, field), \
+}
+
+static const struct fregs_offset fregs_offsets[] = {
+ FREGS_OFFSET("x0", regs[0]),
+ FREGS_OFFSET("x1", regs[1]),
+ FREGS_OFFSET("x2", regs[2]),
+ FREGS_OFFSET("x3", regs[3]),
+ FREGS_OFFSET("x4", regs[4]),
+ FREGS_OFFSET("x5", regs[5]),
+ FREGS_OFFSET("x6", regs[6]),
+ FREGS_OFFSET("x7", regs[7]),
+ FREGS_OFFSET("x8", regs[8]),
+
+ FREGS_OFFSET("x29", fp),
+ FREGS_OFFSET("x30", lr),
+ FREGS_OFFSET("lr", lr),
+
+ FREGS_OFFSET("sp", sp),
+ FREGS_OFFSET("pc", pc),
+};
+
+int ftrace_regs_query_register_offset(const char *name)
+{
+ for (int i = 0; i < ARRAY_SIZE(fregs_offsets); i++) {
+ const struct fregs_offset *roff = &fregs_offsets[i];
+ if (!strcmp(roff->name, name))
+ return roff->offset;
+ }
+
+ return -EINVAL;
+}
+#endif
+
/*
* Replace a single instruction, which may be a branch or NOP.
* If @validate == true, a replaced instruction is checked against 'old'.
@@ -70,9 +112,6 @@ static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
if (addr == FTRACE_ADDR)
return &plt[FTRACE_PLT_IDX];
- if (addr == FTRACE_REGS_ADDR &&
- IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
- return &plt[FTRACE_REGS_PLT_IDX];
#endif
return NULL;
}
@@ -154,25 +193,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return ftrace_modify_code(pc, old, new, true);
}
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
-int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
- unsigned long addr)
-{
- unsigned long pc = rec->ip;
- u32 old, new;
-
- if (!ftrace_find_callable_addr(rec, NULL, &old_addr))
- return -EINVAL;
- if (!ftrace_find_callable_addr(rec, NULL, &addr))
- return -EINVAL;
-
- old = aarch64_insn_gen_branch_imm(pc, old_addr,
- AARCH64_INSN_BRANCH_LINK);
- new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
-
- return ftrace_modify_code(pc, old, new, true);
-}
-
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
/*
* The compiler has inserted two NOPs before the regular function prologue.
* All instrumented functions follow the AAPCS, so x0-x8 and x19-x30 are live,
@@ -228,7 +249,7 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
*
* Note: 'mod' is only set at module load time.
*/
- if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) &&
+ if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) &&
IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && mod) {
return aarch64_insn_patch_text_nosync((void *)pc, new);
}
@@ -246,7 +267,6 @@ void arch_ftrace_update_code(int command)
command |= FTRACE_MAY_SLEEP;
ftrace_modify_all_code(command);
}
-#endif /* CONFIG_DYNAMIC_FTRACE */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/*
@@ -277,21 +297,11 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
}
}
-#ifdef CONFIG_DYNAMIC_FTRACE
-
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct ftrace_regs *fregs)
{
- /*
- * When DYNAMIC_FTRACE_WITH_REGS is selected, `fregs` can never be NULL
- * and arch_ftrace_get_regs(fregs) will always give a non-NULL pt_regs
- * in which we can safely modify the LR.
- */
- struct pt_regs *regs = arch_ftrace_get_regs(fregs);
- unsigned long *parent = (unsigned long *)&procedure_link_pointer(regs);
-
- prepare_ftrace_return(ip, parent, frame_pointer(regs));
+ prepare_ftrace_return(ip, &fregs->lr, fregs->fp);
}
#else
/*
@@ -323,6 +333,5 @@ int ftrace_disable_ftrace_graph_caller(void)
{
return ftrace_modify_graph_caller(false);
}
-#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
-#endif /* CONFIG_DYNAMIC_FTRACE */
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 2196aad7b55b..952e17bd1c0b 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -462,6 +462,9 @@ SYM_FUNC_START_LOCAL(__primary_switched)
bl early_fdt_map // Try mapping the FDT early
mov x0, x20 // pass the full boot status
bl init_feature_override // Parse cpu feature overrides
+#ifdef CONFIG_UNWIND_PATCH_PAC_INTO_SCS
+ bl scs_patch_vmlinux
+#endif
mov x0, x20
bl finalise_el2 // Prefer VHE if possible
ldp x29, x30, [sp], #16
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 38dbd3828f13..6ad5c6ef5329 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -10,20 +10,21 @@
* Copyright (C) 2012 ARM Ltd.
*/
-#include <linux/irq.h>
-#include <linux/memory.h>
-#include <linux/smp.h>
#include <linux/hardirq.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/kprobes.h>
+#include <linux/memory.h>
#include <linux/scs.h>
#include <linux/seq_file.h>
+#include <linux/smp.h>
#include <linux/vmalloc.h>
#include <asm/daifflags.h>
#include <asm/exception.h>
-#include <asm/vmap_stack.h>
#include <asm/softirq_stack.h>
+#include <asm/stacktrace.h>
+#include <asm/vmap_stack.h>
/* Only access this in an NMI enter/exit */
DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts);
@@ -41,7 +42,7 @@ static void init_irq_scs(void)
{
int cpu;
- if (!IS_ENABLED(CONFIG_SHADOW_CALL_STACK))
+ if (!scs_is_enabled())
return;
for_each_possible_cpu(cpu)
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 76b41e4ca9fa..5af4975caeb5 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -15,9 +15,11 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/moduleloader.h>
+#include <linux/scs.h>
#include <linux/vmalloc.h>
#include <asm/alternative.h>
#include <asm/insn.h>
+#include <asm/scs.h>
#include <asm/sections.h>
void *module_alloc(unsigned long size)
@@ -497,9 +499,6 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
__init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
- if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
- __init_plt(&plts[FTRACE_REGS_PLT_IDX], FTRACE_REGS_ADDR);
-
mod->arch.ftrace_trampolines = plts;
#endif
return 0;
@@ -514,5 +513,11 @@ int module_finalize(const Elf_Ehdr *hdr,
if (s)
apply_alternatives_module((void *)s->sh_addr, s->sh_size);
+ if (scs_is_dynamic()) {
+ s = find_section(hdr, sechdrs, ".init.eh_frame");
+ if (s)
+ scs_patch((void *)s->sh_addr, s->sh_size);
+ }
+
return module_init_ftrace_plt(hdr, sechdrs, me);
}
diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c
index 57c7c211f8c7..aa718d6a9274 100644
--- a/arch/arm64/kernel/paravirt.c
+++ b/arch/arm64/kernel/paravirt.c
@@ -141,10 +141,6 @@ static bool __init has_pv_steal_clock(void)
{
struct arm_smccc_res res;
- /* To detect the presence of PV time support we require SMCCC 1.1+ */
- if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE)
- return false;
-
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_HV_PV_TIME_FEATURES, &res);
diff --git a/arch/arm64/kernel/patch-scs.c b/arch/arm64/kernel/patch-scs.c
new file mode 100644
index 000000000000..1b3da02d5b74
--- /dev/null
+++ b/arch/arm64/kernel/patch-scs.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 - Google LLC
+ * Author: Ard Biesheuvel <ardb@google.com>
+ */
+
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+#include <asm/scs.h>
+
+//
+// This minimal DWARF CFI parser is partially based on the code in
+// arch/arc/kernel/unwind.c, and on the document below:
+// https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+//
+
+#define DW_CFA_nop 0x00
+#define DW_CFA_set_loc 0x01
+#define DW_CFA_advance_loc1 0x02
+#define DW_CFA_advance_loc2 0x03
+#define DW_CFA_advance_loc4 0x04
+#define DW_CFA_offset_extended 0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined 0x07
+#define DW_CFA_same_value 0x08
+#define DW_CFA_register 0x09
+#define DW_CFA_remember_state 0x0a
+#define DW_CFA_restore_state 0x0b
+#define DW_CFA_def_cfa 0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset 0x0e
+#define DW_CFA_def_cfa_expression 0x0f
+#define DW_CFA_expression 0x10
+#define DW_CFA_offset_extended_sf 0x11
+#define DW_CFA_def_cfa_sf 0x12
+#define DW_CFA_def_cfa_offset_sf 0x13
+#define DW_CFA_val_offset 0x14
+#define DW_CFA_val_offset_sf 0x15
+#define DW_CFA_val_expression 0x16
+#define DW_CFA_lo_user 0x1c
+#define DW_CFA_negate_ra_state 0x2d
+#define DW_CFA_GNU_args_size 0x2e
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+#define DW_CFA_hi_user 0x3f
+
+extern const u8 __eh_frame_start[], __eh_frame_end[];
+
+enum {
+ PACIASP = 0xd503233f,
+ AUTIASP = 0xd50323bf,
+ SCS_PUSH = 0xf800865e,
+ SCS_POP = 0xf85f8e5e,
+};
+
+static void __always_inline scs_patch_loc(u64 loc)
+{
+ u32 insn = le32_to_cpup((void *)loc);
+
+ switch (insn) {
+ case PACIASP:
+ *(u32 *)loc = cpu_to_le32(SCS_PUSH);
+ break;
+ case AUTIASP:
+ *(u32 *)loc = cpu_to_le32(SCS_POP);
+ break;
+ default:
+ /*
+ * While the DW_CFA_negate_ra_state directive is guaranteed to
+ * appear right after a PACIASP/AUTIASP instruction, it may
+ * also appear after a DW_CFA_restore_state directive that
+ * restores a state that is only partially accurate, and is
+ * followed by DW_CFA_negate_ra_state directive to toggle the
+ * PAC bit again. So we permit other instructions here, and ignore
+ * them.
+ */
+ return;
+ }
+ dcache_clean_pou(loc, loc + sizeof(u32));
+}
+
+/*
+ * Skip one uleb128/sleb128 encoded quantity from the opcode stream. All bytes
+ * except the last one have bit #7 set.
+ */
+static int __always_inline skip_xleb128(const u8 **opcode, int size)
+{
+ u8 c;
+
+ do {
+ c = *(*opcode)++;
+ size--;
+ } while (c & BIT(7));
+
+ return size;
+}
+
+struct eh_frame {
+ /*
+ * The size of this frame if 0 < size < U32_MAX, 0 terminates the list.
+ */
+ u32 size;
+
+ /*
+ * The first frame is a Common Information Entry (CIE) frame, followed
+ * by one or more Frame Description Entry (FDE) frames. In the former
+ * case, this field is 0, otherwise it is the negated offset relative
+ * to the associated CIE frame.
+ */
+ u32 cie_id_or_pointer;
+
+ union {
+ struct { // CIE
+ u8 version;
+ u8 augmentation_string[];
+ };
+
+ struct { // FDE
+ s32 initial_loc;
+ s32 range;
+ u8 opcodes[];
+ };
+ };
+};
+
+static int noinstr scs_handle_fde_frame(const struct eh_frame *frame,
+ bool fde_has_augmentation_data,
+ int code_alignment_factor)
+{
+ int size = frame->size - offsetof(struct eh_frame, opcodes) + 4;
+ u64 loc = (u64)offset_to_ptr(&frame->initial_loc);
+ const u8 *opcode = frame->opcodes;
+
+ if (fde_has_augmentation_data) {
+ int l;
+
+ // assume single byte uleb128_t
+ if (WARN_ON(*opcode & BIT(7)))
+ return -ENOEXEC;
+
+ l = *opcode++;
+ opcode += l;
+ size -= l + 1;
+ }
+
+ /*
+ * Starting from 'loc', apply the CFA opcodes that advance the location
+ * pointer, and identify the locations of the PAC instructions.
+ */
+ while (size-- > 0) {
+ switch (*opcode++) {
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ break;
+
+ case DW_CFA_advance_loc1:
+ loc += *opcode++ * code_alignment_factor;
+ size--;
+ break;
+
+ case DW_CFA_advance_loc2:
+ loc += *opcode++ * code_alignment_factor;
+ loc += (*opcode++ << 8) * code_alignment_factor;
+ size -= 2;
+ break;
+
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended:
+ size = skip_xleb128(&opcode, size);
+ fallthrough;
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_def_cfa_offset_sf:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_same_value:
+ case DW_CFA_restore_extended:
+ case 0x80 ... 0xbf:
+ size = skip_xleb128(&opcode, size);
+ break;
+
+ case DW_CFA_negate_ra_state:
+ scs_patch_loc(loc - 4);
+ break;
+
+ case 0x40 ... 0x7f:
+ // advance loc
+ loc += (opcode[-1] & 0x3f) * code_alignment_factor;
+ break;
+
+ case 0xc0 ... 0xff:
+ break;
+
+ default:
+ pr_err("unhandled opcode: %02x in FDE frame %lx\n", opcode[-1], (uintptr_t)frame);
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int noinstr scs_patch(const u8 eh_frame[], int size)
+{
+ const u8 *p = eh_frame;
+
+ while (size > 4) {
+ const struct eh_frame *frame = (const void *)p;
+ bool fde_has_augmentation_data = true;
+ int code_alignment_factor = 1;
+ int ret;
+
+ if (frame->size == 0 ||
+ frame->size == U32_MAX ||
+ frame->size > size)
+ break;
+
+ if (frame->cie_id_or_pointer == 0) {
+ const u8 *p = frame->augmentation_string;
+
+ /* a 'z' in the augmentation string must come first */
+ fde_has_augmentation_data = *p == 'z';
+
+ /*
+ * The code alignment factor is a uleb128 encoded field
+ * but given that the only sensible values are 1 or 4,
+ * there is no point in decoding the whole thing.
+ */
+ p += strlen(p) + 1;
+ if (!WARN_ON(*p & BIT(7)))
+ code_alignment_factor = *p;
+ } else {
+ ret = scs_handle_fde_frame(frame,
+ fde_has_augmentation_data,
+ code_alignment_factor);
+ if (ret)
+ return ret;
+ }
+
+ p += sizeof(frame->size) + frame->size;
+ size -= sizeof(frame->size) + frame->size;
+ }
+ return 0;
+}
+
+asmlinkage void __init scs_patch_vmlinux(void)
+{
+ if (!should_patch_pac_into_scs())
+ return;
+
+ WARN_ON(scs_patch(__eh_frame_start, __eh_frame_end - __eh_frame_start));
+ icache_inval_all_pou();
+ isb();
+}
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 7b0643fe2f13..a5193f2146a6 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -806,10 +806,14 @@ static void armv8pmu_disable_event(struct perf_event *event)
static void armv8pmu_start(struct arm_pmu *cpu_pmu)
{
- struct perf_event_context *task_ctx =
- this_cpu_ptr(cpu_pmu->pmu.pmu_cpu_context)->task_ctx;
+ struct perf_event_context *ctx;
+ int nr_user = 0;
- if (sysctl_perf_user_access && task_ctx && task_ctx->nr_user)
+ ctx = perf_cpu_task_ctx();
+ if (ctx)
+ nr_user = ctx->nr_user;
+
+ if (sysctl_perf_user_access && nr_user)
armv8pmu_enable_user_access(cpu_pmu);
else
armv8pmu_disable_user_access();
@@ -1019,10 +1023,10 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
return 0;
}
-static int armv8pmu_filter_match(struct perf_event *event)
+static bool armv8pmu_filter(struct pmu *pmu, int cpu)
{
- unsigned long evtype = event->hw.config_base & ARMV8_PMU_EVTYPE_EVENT;
- return evtype != ARMV8_PMUV3_PERFCTR_CHAIN;
+ struct arm_pmu *armpmu = to_arm_pmu(pmu);
+ return !cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus);
}
static void armv8pmu_reset(void *info)
@@ -1146,7 +1150,8 @@ static void __armv8pmu_probe_pmu(void *info)
dfr0 = read_sysreg(id_aa64dfr0_el1);
pmuver = cpuid_feature_extract_unsigned_field(dfr0,
ID_AA64DFR0_EL1_PMUVer_SHIFT);
- if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF || pmuver == 0)
+ if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF ||
+ pmuver == ID_AA64DFR0_EL1_PMUVer_NI)
return;
cpu_pmu->pmuver = pmuver;
@@ -1253,7 +1258,7 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
cpu_pmu->stop = armv8pmu_stop;
cpu_pmu->reset = armv8pmu_reset;
cpu_pmu->set_event_filter = armv8pmu_set_event_filter;
- cpu_pmu->filter_match = armv8pmu_filter_match;
+ cpu_pmu->filter = armv8pmu_filter;
cpu_pmu->pmu.event_idx = armv8pmu_user_event_idx;
diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile
index 839291430cb3..4c0ea3cd4ea4 100644
--- a/arch/arm64/kernel/pi/Makefile
+++ b/arch/arm64/kernel/pi/Makefile
@@ -7,6 +7,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
-I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \
-include $(srctree)/include/linux/hidden.h \
-D__DISABLE_EXPORTS -ffreestanding -D__NO_FORTIFY \
+ -fno-asynchronous-unwind-tables -fno-unwind-tables \
$(call cc-option,-fno-addrsig)
# remove SCS flags from all objects in this directory
diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c
index 104101f633b1..968d5fffe233 100644
--- a/arch/arm64/kernel/probes/decode-insn.c
+++ b/arch/arm64/kernel/probes/decode-insn.c
@@ -24,7 +24,7 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn)
* currently safe. Lastly, MSR instructions can do any number of nasty
* things we can't handle during single-stepping.
*/
- if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
+ if (aarch64_insn_is_class_branch_sys(insn)) {
if (aarch64_insn_is_branch(insn) ||
aarch64_insn_is_msr_imm(insn) ||
aarch64_insn_is_msr_reg(insn) ||
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index c9e4d0720285..f35d059a9a36 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -294,19 +294,12 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
}
break;
- case KPROBE_HIT_ACTIVE:
- case KPROBE_HIT_SSDONE:
- /*
- * In case the user-specified fault handler returned
- * zero, try to fix up.
- */
- if (fixup_exception(regs))
- return 1;
}
return 0;
}
-static void __kprobes kprobe_handler(struct pt_regs *regs)
+static int __kprobes
+kprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr)
{
struct kprobe *p, *cur_kprobe;
struct kprobe_ctlblk *kcb;
@@ -316,39 +309,44 @@ static void __kprobes kprobe_handler(struct pt_regs *regs)
cur_kprobe = kprobe_running();
p = get_kprobe((kprobe_opcode_t *) addr);
+ if (WARN_ON_ONCE(!p)) {
+ /*
+ * Something went wrong. This BRK used an immediate reserved
+ * for kprobes, but we couldn't find any corresponding probe.
+ */
+ return DBG_HOOK_ERROR;
+ }
- if (p) {
- if (cur_kprobe) {
- if (reenter_kprobe(p, regs, kcb))
- return;
- } else {
- /* Probe hit */
- set_current_kprobe(p);
- kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-
- /*
- * If we have no pre-handler or it returned 0, we
- * continue with normal processing. If we have a
- * pre-handler and it returned non-zero, it will
- * modify the execution path and no need to single
- * stepping. Let's just reset current kprobe and exit.
- */
- if (!p->pre_handler || !p->pre_handler(p, regs)) {
- setup_singlestep(p, regs, kcb, 0);
- } else
- reset_current_kprobe();
- }
+ if (cur_kprobe) {
+ /* Hit a kprobe inside another kprobe */
+ if (!reenter_kprobe(p, regs, kcb))
+ return DBG_HOOK_ERROR;
+ } else {
+ /* Probe hit */
+ set_current_kprobe(p);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+ /*
+ * If we have no pre-handler or it returned 0, we
+ * continue with normal processing. If we have a
+ * pre-handler and it returned non-zero, it will
+ * modify the execution path and not need to single-step
+ * Let's just reset current kprobe and exit.
+ */
+ if (!p->pre_handler || !p->pre_handler(p, regs))
+ setup_singlestep(p, regs, kcb, 0);
+ else
+ reset_current_kprobe();
}
- /*
- * The breakpoint instruction was removed right
- * after we hit it. Another cpu has removed
- * either a probepoint or a debugger breakpoint
- * at this address. In either case, no further
- * handling of this interrupt is appropriate.
- * Return back to original instruction, and continue.
- */
+
+ return DBG_HOOK_HANDLED;
}
+static struct break_hook kprobes_break_hook = {
+ .imm = KPROBES_BRK_IMM,
+ .fn = kprobe_breakpoint_handler,
+};
+
static int __kprobes
kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned long esr)
{
@@ -373,18 +371,6 @@ static struct break_hook kprobes_break_ss_hook = {
.fn = kprobe_breakpoint_ss_handler,
};
-static int __kprobes
-kprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr)
-{
- kprobe_handler(regs);
- return DBG_HOOK_HANDLED;
-}
-
-static struct break_hook kprobes_break_hook = {
- .imm = KPROBES_BRK_IMM,
- .fn = kprobe_breakpoint_handler,
-};
-
/*
* Provide a blacklist of symbols identifying ranges which cannot be kprobed.
* This blacklist is exposed to userspace via debugfs (kprobes/blacklist).
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 044a7d7f1f6a..269ac1c25ae2 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -331,6 +331,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
clear_tsk_thread_flag(dst, TIF_SME);
}
+ dst->thread.fp_type = FP_STATE_FPSIMD;
+
/* clear any pending asynchronous tag fault raised by the parent */
clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
@@ -591,7 +593,7 @@ unsigned long __get_wchan(struct task_struct *p)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(PAGE_SIZE);
+ sp -= get_random_u32_below(PAGE_SIZE);
return sp & ~0xf;
}
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
index bfce41c2a53b..fca9cc6f5581 100644
--- a/arch/arm64/kernel/proton-pack.c
+++ b/arch/arm64/kernel/proton-pack.c
@@ -521,10 +521,13 @@ bool has_spectre_v4(const struct arm64_cpu_capabilities *cap, int scope)
return state != SPECTRE_UNAFFECTED;
}
-static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr)
+bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr)
{
- if (user_mode(regs))
- return 1;
+ const u32 instr_mask = ~(1U << PSTATE_Imm_shift);
+ const u32 instr_val = 0xd500401f | PSTATE_SSBS;
+
+ if ((instr & instr_mask) != instr_val)
+ return false;
if (instr & BIT(PSTATE_Imm_shift))
regs->pstate |= PSR_SSBS_BIT;
@@ -532,19 +535,11 @@ static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr)
regs->pstate &= ~PSR_SSBS_BIT;
arm64_skip_faulting_instruction(regs, 4);
- return 0;
+ return true;
}
-static struct undef_hook ssbs_emulation_hook = {
- .instr_mask = ~(1U << PSTATE_Imm_shift),
- .instr_val = 0xd500401f | PSTATE_SSBS,
- .fn = ssbs_emulation_handler,
-};
-
static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
{
- static bool undef_hook_registered = false;
- static DEFINE_RAW_SPINLOCK(hook_lock);
enum mitigation_state state;
/*
@@ -555,13 +550,6 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
if (state != SPECTRE_MITIGATED || !this_cpu_has_cap(ARM64_SSBS))
return state;
- raw_spin_lock(&hook_lock);
- if (!undef_hook_registered) {
- register_undef_hook(&ssbs_emulation_hook);
- undef_hook_registered = true;
- }
- raw_spin_unlock(&hook_lock);
-
if (spectre_v4_mitigations_off()) {
sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
set_pstate_ssbs(1);
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index c2fb5755bbec..2686ab157601 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -514,9 +514,7 @@ static int hw_break_set(struct task_struct *target,
/* Resource info and pad */
offset = offsetof(struct user_hwdebug_state, dbg_regs);
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
- if (ret)
- return ret;
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
/* (address, ctrl) registers */
limit = regset->n * regset->size;
@@ -543,11 +541,8 @@ static int hw_break_set(struct task_struct *target,
return ret;
offset += PTRACE_HBP_CTRL_SZ;
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- offset,
- offset + PTRACE_HBP_PAD_SZ);
- if (ret)
- return ret;
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ offset, offset + PTRACE_HBP_PAD_SZ);
offset += PTRACE_HBP_PAD_SZ;
idx++;
}
@@ -907,8 +902,7 @@ static int sve_set_common(struct task_struct *target,
ret = __fpr_set(target, regset, pos, count, kbuf, ubuf,
SVE_PT_FPSIMD_OFFSET);
clear_tsk_thread_flag(target, TIF_SVE);
- if (type == ARM64_VEC_SME)
- fpsimd_force_sync_to_sve(target);
+ target->thread.fp_type = FP_STATE_FPSIMD;
goto out;
}
@@ -931,6 +925,7 @@ static int sve_set_common(struct task_struct *target,
if (!target->thread.sve_state) {
ret = -ENOMEM;
clear_tsk_thread_flag(target, TIF_SVE);
+ target->thread.fp_type = FP_STATE_FPSIMD;
goto out;
}
@@ -942,6 +937,7 @@ static int sve_set_common(struct task_struct *target,
*/
fpsimd_sync_to_sve(target);
set_tsk_thread_flag(target, TIF_SVE);
+ target->thread.fp_type = FP_STATE_SVE;
BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
start = SVE_PT_SVE_OFFSET;
@@ -954,10 +950,7 @@ static int sve_set_common(struct task_struct *target,
start = end;
end = SVE_PT_SVE_FPSR_OFFSET(vq);
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- start, end);
- if (ret)
- goto out;
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, start, end);
/*
* Copy fpsr, and fpcr which must follow contiguously in
diff --git a/arch/arm64/kernel/sdei.c b/arch/arm64/kernel/sdei.c
index d56e170e1ca7..830be01af32d 100644
--- a/arch/arm64/kernel/sdei.c
+++ b/arch/arm64/kernel/sdei.c
@@ -144,7 +144,7 @@ static int init_sdei_scs(void)
int cpu;
int err = 0;
- if (!IS_ENABLED(CONFIG_SHADOW_CALL_STACK))
+ if (!scs_is_enabled())
return 0;
for_each_possible_cpu(cpu) {
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index fea3223704b6..12cfe9d0d3fa 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -30,6 +30,7 @@
#include <linux/efi.h>
#include <linux/psci.h>
#include <linux/sched/task.h>
+#include <linux/scs.h>
#include <linux/mm.h>
#include <asm/acpi.h>
@@ -42,6 +43,7 @@
#include <asm/cpu_ops.h>
#include <asm/kasan.h>
#include <asm/numa.h>
+#include <asm/scs.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/smp_plat.h>
@@ -312,6 +314,8 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
jump_label_init();
parse_early_param();
+ dynamic_scs_init();
+
/*
* Unmask asynchronous aborts and fiq after bringing up possible
* earlycon. (Report possible System Errors once we can report this
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 9ad911f1647c..e0d09bf5b01b 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -207,6 +207,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
__get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
clear_thread_flag(TIF_SVE);
+ current->thread.fp_type = FP_STATE_FPSIMD;
/* load the hardware registers from the fpsimd_state structure */
if (!err)
@@ -292,6 +293,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
if (sve.head.size <= sizeof(*user->sve)) {
clear_thread_flag(TIF_SVE);
current->thread.svcr &= ~SVCR_SM_MASK;
+ current->thread.fp_type = FP_STATE_FPSIMD;
goto fpsimd_only;
}
@@ -327,6 +329,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
current->thread.svcr |= SVCR_SM_MASK;
else
set_thread_flag(TIF_SVE);
+ current->thread.fp_type = FP_STATE_SVE;
fpsimd_only:
/* copy the FP and status/control registers */
@@ -932,9 +935,11 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
* FPSIMD register state - flush the saved FPSIMD
* register state in case it gets loaded.
*/
- if (current->thread.svcr & SVCR_SM_MASK)
+ if (current->thread.svcr & SVCR_SM_MASK) {
memset(&current->thread.uw.fpsimd_state, 0,
sizeof(current->thread.uw.fpsimd_state));
+ current->thread.fp_type = FP_STATE_FPSIMD;
+ }
current->thread.svcr &= ~(SVCR_ZA_MASK |
SVCR_SM_MASK);
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index 634279b3b03d..117e2c180f3c 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -23,8 +23,8 @@
*
* The regs must be on a stack currently owned by the calling task.
*/
-static inline void unwind_init_from_regs(struct unwind_state *state,
- struct pt_regs *regs)
+static __always_inline void unwind_init_from_regs(struct unwind_state *state,
+ struct pt_regs *regs)
{
unwind_init_common(state, current);
@@ -58,8 +58,8 @@ static __always_inline void unwind_init_from_caller(struct unwind_state *state)
* duration of the unwind, or the unwind will be bogus. It is never valid to
* call this for the current task.
*/
-static inline void unwind_init_from_task(struct unwind_state *state,
- struct task_struct *task)
+static __always_inline void unwind_init_from_task(struct unwind_state *state,
+ struct task_struct *task)
{
unwind_init_common(state, task);
@@ -186,7 +186,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
: stackinfo_get_unknown(); \
})
-noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
+noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
void *cookie, struct task_struct *task,
struct pt_regs *regs)
{
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 8b02d310838f..e7163f31f716 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -60,6 +60,8 @@ void notrace __cpu_suspend_exit(void)
* PSTATE was not saved over suspend/resume, re-enable any detected
* features that might not have been set correctly.
*/
+ if (cpus_have_const_cap(ARM64_HAS_DIT))
+ set_pstate_dit(1);
__uaccess_enable_hw_pan();
/*
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index d72e8f23422d..a5de47e3df2b 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -183,21 +183,12 @@ static inline void fp_user_discard(void)
if (!system_supports_sve())
return;
- /*
- * If SME is not active then disable SVE, the registers will
- * be cleared when userspace next attempts to access them and
- * we do not need to track the SVE register state until then.
- */
- clear_thread_flag(TIF_SVE);
+ if (test_thread_flag(TIF_SVE)) {
+ unsigned int sve_vq_minus_one;
- /*
- * task_fpsimd_load() won't be called to update CPACR_EL1 in
- * ret_to_user unless TIF_FOREIGN_FPSTATE is still set, which only
- * happens if a context switch or kernel_neon_begin() or context
- * modification (sigreturn, ptrace) intervenes.
- * So, ensure that CPACR_EL1 is already correct for the fast-path case.
- */
- sve_user_disable();
+ sve_vq_minus_one = sve_vq_from_vl(task_get_sve_vl(current)) - 1;
+ sve_flush_live(true, sve_vq_minus_one);
+ }
}
void do_el0_svc(struct pt_regs *regs)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 23d281ed7621..4c0caa589e12 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -373,51 +373,22 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
regs->pstate &= ~PSR_BTYPE_MASK;
}
-static LIST_HEAD(undef_hook);
-static DEFINE_RAW_SPINLOCK(undef_lock);
-
-void register_undef_hook(struct undef_hook *hook)
+static int user_insn_read(struct pt_regs *regs, u32 *insnp)
{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&undef_lock, flags);
- list_add(&hook->node, &undef_hook);
- raw_spin_unlock_irqrestore(&undef_lock, flags);
-}
-
-void unregister_undef_hook(struct undef_hook *hook)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&undef_lock, flags);
- list_del(&hook->node);
- raw_spin_unlock_irqrestore(&undef_lock, flags);
-}
-
-static int call_undef_hook(struct pt_regs *regs)
-{
- struct undef_hook *hook;
- unsigned long flags;
u32 instr;
- int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
unsigned long pc = instruction_pointer(regs);
- if (!user_mode(regs)) {
- __le32 instr_le;
- if (get_kernel_nofault(instr_le, (__le32 *)pc))
- goto exit;
- instr = le32_to_cpu(instr_le);
- } else if (compat_thumb_mode(regs)) {
+ if (compat_thumb_mode(regs)) {
/* 16-bit Thumb instruction */
__le16 instr_le;
if (get_user(instr_le, (__le16 __user *)pc))
- goto exit;
+ return -EFAULT;
instr = le16_to_cpu(instr_le);
if (aarch32_insn_is_wide(instr)) {
u32 instr2;
if (get_user(instr_le, (__le16 __user *)(pc + 2)))
- goto exit;
+ return -EFAULT;
instr2 = le16_to_cpu(instr_le);
instr = (instr << 16) | instr2;
}
@@ -425,19 +396,12 @@ static int call_undef_hook(struct pt_regs *regs)
/* 32-bit ARM instruction */
__le32 instr_le;
if (get_user(instr_le, (__le32 __user *)pc))
- goto exit;
+ return -EFAULT;
instr = le32_to_cpu(instr_le);
}
- raw_spin_lock_irqsave(&undef_lock, flags);
- list_for_each_entry(hook, &undef_hook, node)
- if ((instr & hook->instr_mask) == hook->instr_val &&
- (regs->pstate & hook->pstate_mask) == hook->pstate_val)
- fn = hook->fn;
-
- raw_spin_unlock_irqrestore(&undef_lock, flags);
-exit:
- return fn ? fn(regs, instr) : 1;
+ *insnp = instr;
+ return 0;
}
void force_signal_inject(int signal, int code, unsigned long address, unsigned long err)
@@ -486,21 +450,40 @@ void arm64_notify_segfault(unsigned long addr)
force_signal_inject(SIGSEGV, code, addr, 0);
}
-void do_undefinstr(struct pt_regs *regs, unsigned long esr)
+void do_el0_undef(struct pt_regs *regs, unsigned long esr)
{
+ u32 insn;
+
/* check for AArch32 breakpoint instructions */
if (!aarch32_break_handler(regs))
return;
- if (call_undef_hook(regs) == 0)
+ if (user_insn_read(regs, &insn))
+ goto out_err;
+
+ if (try_emulate_mrs(regs, insn))
return;
- if (!user_mode(regs))
- die("Oops - Undefined instruction", regs, esr);
+ if (try_emulate_armv8_deprecated(regs, insn))
+ return;
+out_err:
force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
}
-NOKPROBE_SYMBOL(do_undefinstr);
+
+void do_el1_undef(struct pt_regs *regs, unsigned long esr)
+{
+ u32 insn;
+
+ if (aarch64_insn_read((void *)regs->pc, &insn))
+ goto out_err;
+
+ if (try_emulate_el1_ssbs(regs, insn))
+ return;
+
+out_err:
+ die("Oops - Undefined instruction", regs, esr);
+}
void do_el0_bti(struct pt_regs *regs)
{
@@ -511,7 +494,6 @@ void do_el1_bti(struct pt_regs *regs, unsigned long esr)
{
die("Oops - BTI", regs, esr);
}
-NOKPROBE_SYMBOL(do_el1_bti);
void do_el0_fpac(struct pt_regs *regs, unsigned long esr)
{
@@ -526,7 +508,6 @@ void do_el1_fpac(struct pt_regs *regs, unsigned long esr)
*/
die("Oops - FPAC", regs, esr);
}
-NOKPROBE_SYMBOL(do_el1_fpac)
#define __user_cache_maint(insn, address, res) \
if (address >= TASK_SIZE_MAX) { \
@@ -748,7 +729,7 @@ static const struct sys64_hook cp15_64_hooks[] = {
{},
};
-void do_cp15instr(unsigned long esr, struct pt_regs *regs)
+void do_el0_cp15(unsigned long esr, struct pt_regs *regs)
{
const struct sys64_hook *hook, *hook_base;
@@ -769,7 +750,7 @@ void do_cp15instr(unsigned long esr, struct pt_regs *regs)
hook_base = cp15_64_hooks;
break;
default:
- do_undefinstr(regs, esr);
+ do_el0_undef(regs, esr);
return;
}
@@ -784,12 +765,11 @@ void do_cp15instr(unsigned long esr, struct pt_regs *regs)
* EL0. Fall back to our usual undefined instruction handler
* so that we handle these consistently.
*/
- do_undefinstr(regs, esr);
+ do_el0_undef(regs, esr);
}
-NOKPROBE_SYMBOL(do_cp15instr);
#endif
-void do_sysinstr(unsigned long esr, struct pt_regs *regs)
+void do_el0_sys(unsigned long esr, struct pt_regs *regs)
{
const struct sys64_hook *hook;
@@ -804,9 +784,8 @@ void do_sysinstr(unsigned long esr, struct pt_regs *regs)
* back to our usual undefined instruction handler so that we handle
* these consistently.
*/
- do_undefinstr(regs, esr);
+ do_el0_undef(regs, esr);
}
-NOKPROBE_SYMBOL(do_sysinstr);
static const char *esr_class_str[] = {
[0 ... ESR_ELx_EC_MAX] = "UNRECOGNIZED EC",
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 99ae81ab91a7..e59a32aa0c49 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -151,28 +151,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm);
return 0;
}
-
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- if (likely(vma->vm_mm == current->mm))
- return current->nsproxy->time_ns->vvar_page;
-
- /*
- * VM_PFNMAP | VM_IO protect .fault() handler from being called
- * through interfaces like /proc/$pid/mem or
- * process_vm_{readv,writev}() as long as there's no .access()
- * in special_mapping_vmops.
- * For more details check_vma_flags() and __access_remote_vm()
- */
- WARN(1, "vvar_page accessed remotely");
-
- return NULL;
-}
-#else
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- return NULL;
-}
#endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 45131e354e27..4c13dafc98b8 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -121,6 +121,17 @@ jiffies = jiffies_64;
#define TRAMP_TEXT
#endif
+#ifdef CONFIG_UNWIND_TABLES
+#define UNWIND_DATA_SECTIONS \
+ .eh_frame : { \
+ __eh_frame_start = .; \
+ *(.eh_frame) \
+ __eh_frame_end = .; \
+ }
+#else
+#define UNWIND_DATA_SECTIONS
+#endif
+
/*
* The size of the PE/COFF section that covers the kernel image, which
* runs from _stext to _edata, must be a round multiple of the PE/COFF
@@ -231,6 +242,8 @@ SECTIONS
__alt_instructions_end = .;
}
+ UNWIND_DATA_SECTIONS
+
. = ALIGN(SEGMENT_ALIGN);
__inittext_end = .;
__initdata_begin = .;
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index ec8e4494873d..02dd7e9ebd39 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -75,11 +75,12 @@ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
{
BUG_ON(!current->mm);
- BUG_ON(test_thread_flag(TIF_SVE));
if (!system_supports_fpsimd())
return;
+ fpsimd_kvm_prepare();
+
vcpu->arch.fp_state = FP_STATE_HOST_OWNED;
vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
@@ -129,20 +130,31 @@ void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu)
*/
void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
{
+ struct cpu_fp_state fp_state;
+
WARN_ON_ONCE(!irqs_disabled());
if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) {
+
/*
* Currently we do not support SME guests so SVCR is
* always 0 and we just need a variable to point to.
*/
- fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.fp_regs,
- vcpu->arch.sve_state,
- vcpu->arch.sve_max_vl,
- NULL, 0, &vcpu->arch.svcr);
+ fp_state.st = &vcpu->arch.ctxt.fp_regs;
+ fp_state.sve_state = vcpu->arch.sve_state;
+ fp_state.sve_vl = vcpu->arch.sve_max_vl;
+ fp_state.za_state = NULL;
+ fp_state.svcr = &vcpu->arch.svcr;
+ fp_state.fp_type = &vcpu->arch.fp_type;
+
+ if (vcpu_has_sve(vcpu))
+ fp_state.to_save = FP_STATE_SVE;
+ else
+ fp_state.to_save = FP_STATE_FPSIMD;
+
+ fpsimd_bind_state_to_cpu(&fp_state);
clear_thread_flag(TIF_FOREIGN_FPSTATE);
- update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
}
}
@@ -199,7 +211,5 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
sysreg_clear_set(CPACR_EL1, CPACR_EL1_ZEN_EL0EN, 0);
}
- update_thread_flag(TIF_SVE, 0);
-
local_irq_restore(flags);
}
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index be0a2bc3e20d..530347cdebe3 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -96,6 +96,7 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_CFI)
# when profile optimization is applied. gen-hyprel does not support SHT_REL and
# causes a build failure. Remove profile optimization flags.
KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%, $(KBUILD_CFLAGS))
+KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
# KVM nVHE code is run at a different exception code with a different map, so
# compiler instrumentation that inserts callbacks or checks into the code may
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f4a7c5abcbca..608e4f25161d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1121,8 +1121,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r
case SYS_ID_DFR0_EL1:
/* Limit guests to PMUv3 for ARMv8.4 */
val = cpuid_feature_cap_perfmon_field(val,
- ID_DFR0_PERFMON_SHIFT,
- kvm_vcpu_has_pmu(vcpu) ? ID_DFR0_PERFMON_8_4 : 0);
+ ID_DFR0_EL1_PerfMon_SHIFT,
+ kvm_vcpu_has_pmu(vcpu) ? ID_DFR0_EL1_PerfMon_PMUv3p4 : 0);
break;
}
diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c
index 49e972beeac7..924934cb85ee 100644
--- a/arch/arm64/lib/insn.c
+++ b/arch/arm64/lib/insn.c
@@ -20,91 +20,6 @@
#define AARCH64_INSN_N_BIT BIT(22)
#define AARCH64_INSN_LSL_12 BIT(22)
-static const int aarch64_insn_encoding_class[] = {
- AARCH64_INSN_CLS_UNKNOWN,
- AARCH64_INSN_CLS_UNKNOWN,
- AARCH64_INSN_CLS_SVE,
- AARCH64_INSN_CLS_UNKNOWN,
- AARCH64_INSN_CLS_LDST,
- AARCH64_INSN_CLS_DP_REG,
- AARCH64_INSN_CLS_LDST,
- AARCH64_INSN_CLS_DP_FPSIMD,
- AARCH64_INSN_CLS_DP_IMM,
- AARCH64_INSN_CLS_DP_IMM,
- AARCH64_INSN_CLS_BR_SYS,
- AARCH64_INSN_CLS_BR_SYS,
- AARCH64_INSN_CLS_LDST,
- AARCH64_INSN_CLS_DP_REG,
- AARCH64_INSN_CLS_LDST,
- AARCH64_INSN_CLS_DP_FPSIMD,
-};
-
-enum aarch64_insn_encoding_class __kprobes aarch64_get_insn_class(u32 insn)
-{
- return aarch64_insn_encoding_class[(insn >> 25) & 0xf];
-}
-
-bool __kprobes aarch64_insn_is_steppable_hint(u32 insn)
-{
- if (!aarch64_insn_is_hint(insn))
- return false;
-
- switch (insn & 0xFE0) {
- case AARCH64_INSN_HINT_XPACLRI:
- case AARCH64_INSN_HINT_PACIA_1716:
- case AARCH64_INSN_HINT_PACIB_1716:
- case AARCH64_INSN_HINT_PACIAZ:
- case AARCH64_INSN_HINT_PACIASP:
- case AARCH64_INSN_HINT_PACIBZ:
- case AARCH64_INSN_HINT_PACIBSP:
- case AARCH64_INSN_HINT_BTI:
- case AARCH64_INSN_HINT_BTIC:
- case AARCH64_INSN_HINT_BTIJ:
- case AARCH64_INSN_HINT_BTIJC:
- case AARCH64_INSN_HINT_NOP:
- return true;
- default:
- return false;
- }
-}
-
-bool aarch64_insn_is_branch_imm(u32 insn)
-{
- return (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn) ||
- aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn) ||
- aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
- aarch64_insn_is_bcond(insn));
-}
-
-bool __kprobes aarch64_insn_uses_literal(u32 insn)
-{
- /* ldr/ldrsw (literal), prfm */
-
- return aarch64_insn_is_ldr_lit(insn) ||
- aarch64_insn_is_ldrsw_lit(insn) ||
- aarch64_insn_is_adr_adrp(insn) ||
- aarch64_insn_is_prfm_lit(insn);
-}
-
-bool __kprobes aarch64_insn_is_branch(u32 insn)
-{
- /* b, bl, cb*, tb*, ret*, b.cond, br*, blr* */
-
- return aarch64_insn_is_b(insn) ||
- aarch64_insn_is_bl(insn) ||
- aarch64_insn_is_cbz(insn) ||
- aarch64_insn_is_cbnz(insn) ||
- aarch64_insn_is_tbz(insn) ||
- aarch64_insn_is_tbnz(insn) ||
- aarch64_insn_is_ret(insn) ||
- aarch64_insn_is_ret_auth(insn) ||
- aarch64_insn_is_br(insn) ||
- aarch64_insn_is_br_auth(insn) ||
- aarch64_insn_is_blr(insn) ||
- aarch64_insn_is_blr_auth(insn) ||
- aarch64_insn_is_bcond(insn);
-}
-
static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
u32 *maskp, int *shiftp)
{
@@ -435,16 +350,6 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
offset >> 2);
}
-u32 __kprobes aarch64_insn_gen_hint(enum aarch64_insn_hint_cr_op op)
-{
- return aarch64_insn_get_hint_value() | op;
-}
-
-u32 __kprobes aarch64_insn_gen_nop(void)
-{
- return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP);
-}
-
u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
enum aarch64_insn_branch_type type)
{
@@ -816,76 +721,6 @@ u32 aarch64_insn_gen_cas(enum aarch64_insn_register result,
}
#endif
-static u32 aarch64_insn_encode_prfm_imm(enum aarch64_insn_prfm_type type,
- enum aarch64_insn_prfm_target target,
- enum aarch64_insn_prfm_policy policy,
- u32 insn)
-{
- u32 imm_type = 0, imm_target = 0, imm_policy = 0;
-
- switch (type) {
- case AARCH64_INSN_PRFM_TYPE_PLD:
- break;
- case AARCH64_INSN_PRFM_TYPE_PLI:
- imm_type = BIT(0);
- break;
- case AARCH64_INSN_PRFM_TYPE_PST:
- imm_type = BIT(1);
- break;
- default:
- pr_err("%s: unknown prfm type encoding %d\n", __func__, type);
- return AARCH64_BREAK_FAULT;
- }
-
- switch (target) {
- case AARCH64_INSN_PRFM_TARGET_L1:
- break;
- case AARCH64_INSN_PRFM_TARGET_L2:
- imm_target = BIT(0);
- break;
- case AARCH64_INSN_PRFM_TARGET_L3:
- imm_target = BIT(1);
- break;
- default:
- pr_err("%s: unknown prfm target encoding %d\n", __func__, target);
- return AARCH64_BREAK_FAULT;
- }
-
- switch (policy) {
- case AARCH64_INSN_PRFM_POLICY_KEEP:
- break;
- case AARCH64_INSN_PRFM_POLICY_STRM:
- imm_policy = BIT(0);
- break;
- default:
- pr_err("%s: unknown prfm policy encoding %d\n", __func__, policy);
- return AARCH64_BREAK_FAULT;
- }
-
- /* In this case, imm5 is encoded into Rt field. */
- insn &= ~GENMASK(4, 0);
- insn |= imm_policy | (imm_target << 1) | (imm_type << 3);
-
- return insn;
-}
-
-u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
- enum aarch64_insn_prfm_type type,
- enum aarch64_insn_prfm_target target,
- enum aarch64_insn_prfm_policy policy)
-{
- u32 insn = aarch64_insn_get_prfm_value();
-
- insn = aarch64_insn_encode_ldst_size(AARCH64_INSN_SIZE_64, insn);
-
- insn = aarch64_insn_encode_prfm_imm(type, target, policy, insn);
-
- insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
- base);
-
- return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, 0);
-}
-
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
enum aarch64_insn_register src,
int imm, enum aarch64_insn_variant variant,
diff --git a/arch/arm64/lib/mte.S b/arch/arm64/lib/mte.S
index 1b7c93ae7e63..5018ac03b6bf 100644
--- a/arch/arm64/lib/mte.S
+++ b/arch/arm64/lib/mte.S
@@ -18,7 +18,7 @@
*/
.macro multitag_transfer_size, reg, tmp
mrs_s \reg, SYS_GMID_EL1
- ubfx \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_SIZE
+ ubfx \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_WIDTH
mov \tmp, #4
lsl \reg, \tmp, \reg
.endm
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 3cb101e8cb29..5240f6acad64 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -36,7 +36,22 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
{
unsigned long start = (unsigned long)page_address(page);
- dcache_clean_poc(start, start + size);
+ /*
+ * The architecture only requires a clean to the PoC here in order to
+ * meet the requirements of the DMA API. However, some vendors (i.e.
+ * Qualcomm) abuse the DMA API for transferring buffers from the
+ * non-secure to the secure world, resetting the system if a non-secure
+ * access shows up after the buffer has been transferred:
+ *
+ * https://lore.kernel.org/r/20221114110329.68413-1-manivannan.sadhasivam@linaro.org
+ *
+ * Using clean+invalidate appears to make this issue less likely, but
+ * the drivers themselves still need fixing as the CPU could issue a
+ * speculative read from the buffer via the linear mapping irrespective
+ * of the cache maintenance we use. Once the drivers are fixed, we can
+ * relax this to a clean operation.
+ */
+ dcache_clean_inval_poc(start, start + size);
}
#ifdef CONFIG_IOMMU_DMA
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 3e9cf9826417..74f76514a48d 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -30,7 +30,6 @@
#include <asm/bug.h>
#include <asm/cmpxchg.h>
#include <asm/cpufeature.h>
-#include <asm/efi.h>
#include <asm/exception.h>
#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
@@ -354,6 +353,11 @@ static bool is_el1_mte_sync_tag_check_fault(unsigned long esr)
return false;
}
+static bool is_translation_fault(unsigned long esr)
+{
+ return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
+}
+
static void __do_kernel_fault(unsigned long addr, unsigned long esr,
struct pt_regs *regs)
{
@@ -386,15 +390,13 @@ static void __do_kernel_fault(unsigned long addr, unsigned long esr,
} else if (addr < PAGE_SIZE) {
msg = "NULL pointer dereference";
} else {
- if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs))
+ if (is_translation_fault(esr) &&
+ kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs))
return;
msg = "paging request";
}
- if (efi_runtime_fixup_exception(regs, msg))
- return;
-
die_kernel_fault(msg, addr, esr, regs);
}
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 35e9a468d13e..cd8d96e1fa1a 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -559,3 +559,24 @@ bool __init arch_hugetlb_valid_size(unsigned long size)
{
return __hugetlb_valid_size(size);
}
+
+pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+ if (IS_ENABLED(CONFIG_ARM64_WORKAROUND_2645198) &&
+ cpus_have_const_cap(ARM64_WORKAROUND_2645198)) {
+ /*
+ * Break-before-make (BBM) is required for all user space mappings
+ * when the permission changes from executable to non-executable
+ * in cases where cpu is affected with errata #2645198.
+ */
+ if (pte_user_exec(READ_ONCE(*ptep)))
+ return huge_ptep_clear_flush(vma, addr, ptep);
+ }
+ return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+}
+
+void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
+ pte_t old_pte, pte_t pte)
+{
+ set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+}
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 4b4651ee47f2..58a0bb2c17f1 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -96,6 +96,8 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
#define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit
#define CRASH_ADDR_HIGH_MAX (PHYS_MASK + 1)
+#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
+
static int __init reserve_crashkernel_low(unsigned long long low_size)
{
unsigned long long low_base;
@@ -130,6 +132,7 @@ static void __init reserve_crashkernel(void)
unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
char *cmdline = boot_command_line;
int ret;
+ bool fixed_base = false;
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
@@ -147,7 +150,9 @@ static void __init reserve_crashkernel(void)
* is not allowed.
*/
ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
- if (ret && (ret != -ENOENT))
+ if (ret == -ENOENT)
+ crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
+ else if (ret)
return;
crash_max = CRASH_ADDR_HIGH_MAX;
@@ -159,18 +164,32 @@ static void __init reserve_crashkernel(void)
crash_size = PAGE_ALIGN(crash_size);
/* User specifies base address explicitly. */
- if (crash_base)
+ if (crash_base) {
+ fixed_base = true;
crash_max = crash_base + crash_size;
+ }
+retry:
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
crash_base, crash_max);
if (!crash_base) {
+ /*
+ * If the first attempt was for low memory, fall back to
+ * high memory, the minimum required low memory will be
+ * reserved later.
+ */
+ if (!fixed_base && (crash_max == CRASH_ADDR_LOW_MAX)) {
+ crash_max = CRASH_ADDR_HIGH_MAX;
+ crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
+ goto retry;
+ }
+
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
crash_size);
return;
}
- if ((crash_base >= CRASH_ADDR_LOW_MAX) &&
+ if ((crash_base > CRASH_ADDR_LOW_MAX - crash_low_size) &&
crash_low_size && reserve_crashkernel_low(crash_low_size)) {
memblock_phys_free(crash_base, crash_size);
return;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9a7c38965154..2368e4daa23d 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1196,7 +1196,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
WARN_ON((start < VMEMMAP_START) || (end > VMEMMAP_END));
- if (!ARM64_KERNEL_USES_PMD_MAPS)
+ if (!IS_ENABLED(CONFIG_ARM64_4K_PAGES))
return vmemmap_populate_basepages(start, end, node, altmap);
do {
@@ -1702,3 +1702,24 @@ static int __init prevent_bootmem_remove_init(void)
}
early_initcall(prevent_bootmem_remove_init);
#endif
+
+pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+ if (IS_ENABLED(CONFIG_ARM64_WORKAROUND_2645198) &&
+ cpus_have_const_cap(ARM64_WORKAROUND_2645198)) {
+ /*
+ * Break-before-make (BBM) is required for all user space mappings
+ * when the permission changes from executable to non-executable
+ * in cases where cpu is affected with errata #2645198.
+ */
+ if (pte_user_exec(READ_ONCE(*ptep)))
+ return ptep_clear_flush(vma, addr, ptep);
+ }
+ return ptep_get_and_clear(vma->vm_mm, addr, ptep);
+}
+
+void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
+ pte_t old_pte, pte_t pte)
+{
+ set_pte_at(vma->vm_mm, addr, ptep, pte);
+}
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index d107c3d434e2..5922178d7a06 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -26,7 +26,7 @@ bool can_set_direct_map(void)
* mapped at page granularity, so that it is possible to
* protect/unprotect single pages.
*/
- return rodata_full || debug_pagealloc_enabled() ||
+ return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() ||
IS_ENABLED(CONFIG_KFENCE);
}
@@ -102,7 +102,8 @@ static int change_memory_common(unsigned long addr, int numpages,
* If we are manipulating read-only permissions, apply the same
* change to the linear mapping of the pages that back this VM area.
*/
- if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
+ if (rodata_enabled &&
+ rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
pgprot_val(clear_mask) == PTE_RDONLY)) {
for (i = 0; i < area->nr_pages; i++) {
__change_memory_common((u64)page_address(area->pages[i]),
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index b9ecbbae1e1a..066fa60b93d2 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -189,16 +189,12 @@ SYM_FUNC_END(cpu_do_resume)
* called by anything else. It can only be executed from a TTBR0 mapping.
*/
SYM_TYPED_FUNC_START(idmap_cpu_replace_ttbr1)
- save_and_disable_daif flags=x2
-
__idmap_cpu_set_reserved_ttbr1 x1, x3
offset_ttbr1 x0, x3
msr ttbr1_el1, x0
isb
- restore_daif x2
-
ret
SYM_FUNC_END(idmap_cpu_replace_ttbr1)
.popsection
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index f1c0347ec31a..dfeb2c51e257 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -20,6 +20,7 @@ HAS_CNP
HAS_CRC32
HAS_DCPODP
HAS_DCPOP
+HAS_DIT
HAS_E0PD
HAS_ECV
HAS_EPAN
@@ -70,6 +71,7 @@ WORKAROUND_2038923
WORKAROUND_2064142
WORKAROUND_2077057
WORKAROUND_2457168
+WORKAROUND_2645198
WORKAROUND_2658417
WORKAROUND_TRBE_OVERWRITE_FILL_MODE
WORKAROUND_TSB_FLUSH_FAILURE
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk
index db461921d256..c350164a3955 100755
--- a/arch/arm64/tools/gen-sysreg.awk
+++ b/arch/arm64/tools/gen-sysreg.awk
@@ -33,7 +33,7 @@ function expect_fields(nf) {
# Print a CPP macro definition, padded with spaces so that the macro bodies
# line up in a column
function define(name, val) {
- printf "%-48s%s\n", "#define " name, val
+ printf "%-56s%s\n", "#define " name, val
}
# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 384757a7eda9..184e58fd5631 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -46,6 +46,760 @@
# feature that introduces them (eg, FEAT_LS64_ACCDATA introduces enumeration
# item ACCDATA) though it may be more taseful to do something else.
+Sysreg ID_PFR0_EL1 3 0 0 1 0
+Res0 63:32
+Enum 31:28 RAS
+ 0b0000 NI
+ 0b0001 RAS
+ 0b0010 RASv1p1
+EndEnum
+Enum 27:24 DIT
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 AMU
+ 0b0000 NI
+ 0b0001 AMUv1
+ 0b0010 AMUv1p1
+EndEnum
+Enum 19:16 CSV2
+ 0b0000 UNDISCLOSED
+ 0b0001 IMP
+ 0b0010 CSV2p1
+EndEnum
+Enum 15:12 State3
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 State2
+ 0b0000 NI
+ 0b0001 NO_CV
+ 0b0010 CV
+EndEnum
+Enum 7:4 State1
+ 0b0000 NI
+ 0b0001 THUMB
+ 0b0010 THUMB2
+EndEnum
+Enum 3:0 State0
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_PFR1_EL1 3 0 0 1 1
+Res0 63:32
+Enum 31:28 GIC
+ 0b0000 NI
+ 0b0001 GICv3
+ 0b0010 GICv4p1
+EndEnum
+Enum 27:24 Virt_frac
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 Sec_frac
+ 0b0000 NI
+ 0b0001 WALK_DISABLE
+ 0b0010 SECURE_MEMORY
+EndEnum
+Enum 19:16 GenTimer
+ 0b0000 NI
+ 0b0001 IMP
+ 0b0010 ECV
+EndEnum
+Enum 15:12 Virtualization
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 MProgMod
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 Security
+ 0b0000 NI
+ 0b0001 EL3
+ 0b0001 NSACR_RFR
+EndEnum
+Enum 3:0 ProgMod
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_DFR0_EL1 3 0 0 1 2
+Res0 63:32
+Enum 31:28 TraceFilt
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 PerfMon
+ 0b0000 NI
+ 0b0001 PMUv1
+ 0b0010 PMUv2
+ 0b0011 PMUv3
+ 0b0100 PMUv3p1
+ 0b0101 PMUv3p4
+ 0b0110 PMUv3p5
+ 0b0111 PMUv3p7
+ 0b1000 PMUv3p8
+ 0b1111 IMPDEF
+EndEnum
+Enum 23:20 MProfDbg
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 MMapTrc
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 CopTrc
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 MMapDbg
+ 0b0000 NI
+ 0b0100 Armv7
+ 0b0101 Armv7p1
+EndEnum
+Field 7:4 CopSDbg
+Enum 3:0 CopDbg
+ 0b0000 NI
+ 0b0010 Armv6
+ 0b0011 Armv6p1
+ 0b0100 Armv7
+ 0b0101 Armv7p1
+ 0b0110 Armv8
+ 0b0111 VHE
+ 0b1000 Debugv8p2
+ 0b1001 Debugv8p4
+ 0b1010 Debugv8p8
+EndEnum
+EndSysreg
+
+Sysreg ID_AFR0_EL1 3 0 0 1 3
+Res0 63:16
+Field 15:12 IMPDEF3
+Field 11:8 IMPDEF2
+Field 7:4 IMPDEF1
+Field 3:0 IMPDEF0
+EndSysreg
+
+Sysreg ID_MMFR0_EL1 3 0 0 1 4
+Res0 63:32
+Enum 31:28 InnerShr
+ 0b0000 NC
+ 0b0001 HW
+ 0b1111 IGNORED
+EndEnum
+Enum 27:24 FCSE
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 AuxReg
+ 0b0000 NI
+ 0b0001 ACTLR
+ 0b0010 AIFSR
+EndEnum
+Enum 19:16 TCM
+ 0b0000 NI
+ 0b0001 IMPDEF
+ 0b0010 TCM
+ 0b0011 TCM_DMA
+EndEnum
+Enum 15:12 ShareLvl
+ 0b0000 ONE
+ 0b0001 TWO
+EndEnum
+Enum 11:8 OuterShr
+ 0b0000 NC
+ 0b0001 HW
+ 0b1111 IGNORED
+EndEnum
+Enum 7:4 PMSA
+ 0b0000 NI
+ 0b0001 IMPDEF
+ 0b0010 PMSAv6
+ 0b0011 PMSAv7
+EndEnum
+Enum 3:0 VMSA
+ 0b0000 NI
+ 0b0001 IMPDEF
+ 0b0010 VMSAv6
+ 0b0011 VMSAv7
+ 0b0100 VMSAv7_PXN
+ 0b0101 VMSAv7_LONG
+EndEnum
+EndSysreg
+
+Sysreg ID_MMFR1_EL1 3 0 0 1 5
+Res0 63:32
+Enum 31:28 BPred
+ 0b0000 NI
+ 0b0001 BP_SW_MANGED
+ 0b0010 BP_ASID_AWARE
+ 0b0011 BP_NOSNOOP
+ 0b0100 BP_INVISIBLE
+EndEnum
+Enum 27:24 L1TstCln
+ 0b0000 NI
+ 0b0001 NOINVALIDATE
+ 0b0010 INVALIDATE
+EndEnum
+Enum 23:20 L1Uni
+ 0b0000 NI
+ 0b0001 INVALIDATE
+ 0b0010 CLEAN_AND_INVALIDATE
+EndEnum
+Enum 19:16 L1Hvd
+ 0b0000 NI
+ 0b0001 INVALIDATE_ISIDE_ONLY
+ 0b0010 INVALIDATE
+ 0b0011 CLEAN_AND_INVALIDATE
+EndEnum
+Enum 15:12 L1UniSW
+ 0b0000 NI
+ 0b0001 CLEAN
+ 0b0010 CLEAN_AND_INVALIDATE
+ 0b0011 INVALIDATE
+EndEnum
+Enum 11:8 L1HvdSW
+ 0b0000 NI
+ 0b0001 CLEAN_AND_INVALIDATE
+ 0b0010 INVALIDATE_DSIDE_ONLY
+ 0b0011 INVALIDATE
+EndEnum
+Enum 7:4 L1UniVA
+ 0b0000 NI
+ 0b0001 CLEAN_AND_INVALIDATE
+ 0b0010 INVALIDATE_BP
+EndEnum
+Enum 3:0 L1HvdVA
+ 0b0000 NI
+ 0b0001 CLEAN_AND_INVALIDATE
+ 0b0010 INVALIDATE_BP
+EndEnum
+EndSysreg
+
+Sysreg ID_MMFR2_EL1 3 0 0 1 6
+Res0 63:32
+Enum 31:28 HWAccFlg
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 WFIStall
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 MemBarr
+ 0b0000 NI
+ 0b0001 DSB_ONLY
+ 0b0010 IMP
+EndEnum
+Enum 19:16 UniTLB
+ 0b0000 NI
+ 0b0001 BY_VA
+ 0b0010 BY_MATCH_ASID
+ 0b0011 BY_ALL_ASID
+ 0b0100 OTHER_TLBS
+ 0b0101 BROADCAST
+ 0b0110 BY_IPA
+EndEnum
+Enum 15:12 HvdTLB
+ 0b0000 NI
+EndEnum
+Enum 11:8 L1HvdRng
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 L1HvdBG
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 L1HvdFG
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_MMFR3_EL1 3 0 0 1 7
+Res0 63:32
+Enum 31:28 Supersec
+ 0b0000 IMP
+ 0b1111 NI
+EndEnum
+Enum 27:24 CMemSz
+ 0b0000 4GB
+ 0b0001 64GB
+ 0b0010 1TB
+EndEnum
+Enum 23:20 CohWalk
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 PAN
+ 0b0000 NI
+ 0b0001 PAN
+ 0b0010 PAN2
+EndEnum
+Enum 15:12 MaintBcst
+ 0b0000 NI
+ 0b0001 NO_TLB
+ 0b0010 ALL
+EndEnum
+Enum 11:8 BPMaint
+ 0b0000 NI
+ 0b0001 ALL
+ 0b0010 BY_VA
+EndEnum
+Enum 7:4 CMaintSW
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 CMaintVA
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR0_EL1 3 0 0 2 0
+Res0 63:28
+Enum 27:24 Divide
+ 0b0000 NI
+ 0b0001 xDIV_T32
+ 0b0010 xDIV_A32
+EndEnum
+Enum 23:20 Debug
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 Coproc
+ 0b0000 NI
+ 0b0001 MRC
+ 0b0010 MRC2
+ 0b0011 MRRC
+ 0b0100 MRRC2
+EndEnum
+Enum 15:12 CmpBranch
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 BitField
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 BitCount
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 Swap
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR1_EL1 3 0 0 2 1
+Res0 63:32
+Enum 31:28 Jazelle
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 Interwork
+ 0b0000 NI
+ 0b0001 BX
+ 0b0010 BLX
+ 0b0011 A32_BX
+EndEnum
+Enum 23:20 Immediate
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 IfThen
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 Extend
+ 0b0000 NI
+ 0b0001 SXTB
+ 0b0010 SXTB16
+EndEnum
+Enum 11:8 Except_AR
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 Except
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 Endian
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR2_EL1 3 0 0 2 2
+Res0 63:32
+Enum 31:28 Reversal
+ 0b0000 NI
+ 0b0001 REV
+ 0b0010 RBIT
+EndEnum
+Enum 27:24 PSR_AR
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 MultU
+ 0b0000 NI
+ 0b0001 UMULL
+ 0b0010 UMAAL
+EndEnum
+Enum 19:16 MultS
+ 0b0000 NI
+ 0b0001 SMULL
+ 0b0010 SMLABB
+ 0b0011 SMLAD
+EndEnum
+Enum 15:12 Mult
+ 0b0000 NI
+ 0b0001 MLA
+ 0b0010 MLS
+EndEnum
+Enum 11:8 MultiAccessInt
+ 0b0000 NI
+ 0b0001 RESTARTABLE
+ 0b0010 CONTINUABLE
+EndEnum
+Enum 7:4 MemHint
+ 0b0000 NI
+ 0b0001 PLD
+ 0b0010 PLD2
+ 0b0011 PLI
+ 0b0100 PLDW
+EndEnum
+Enum 3:0 LoadStore
+ 0b0000 NI
+ 0b0001 DOUBLE
+ 0b0010 ACQUIRE
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR3_EL1 3 0 0 2 3
+Res0 63:32
+Enum 31:28 T32EE
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 TrueNOP
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 T32Copy
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 TabBranch
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 SynchPrim
+ 0b0000 NI
+ 0b0001 EXCLUSIVE
+ 0b0010 DOUBLE
+EndEnum
+Enum 11:8 SVC
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 SIMD
+ 0b0000 NI
+ 0b0001 SSAT
+ 0b0011 PKHBT
+EndEnum
+Enum 3:0 Saturate
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR4_EL1 3 0 0 2 4
+Res0 63:32
+Enum 31:28 SWP_frac
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 PSR_M
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 SynchPrim_frac
+ 0b0000 NI
+ 0b0011 IMP
+EndEnum
+Enum 19:16 Barrier
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 SMC
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 Writeback
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 WithShifts
+ 0b0000 NI
+ 0b0001 LSL3
+ 0b0011 LS
+ 0b0100 REG
+EndEnum
+Enum 3:0 Unpriv
+ 0b0000 NI
+ 0b0001 REG_BYTE
+ 0b0010 SIGNED_HALFWORD
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR5_EL1 3 0 0 2 5
+Res0 63:32
+Enum 31:28 VCMA
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 RDM
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Res0 23:20
+Enum 19:16 CRC32
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 SHA2
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 SHA1
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 AES
+ 0b0000 NI
+ 0b0001 IMP
+ 0b0010 VMULL
+EndEnum
+Enum 3:0 SEVL
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_ISAR6_EL1 3 0 0 2 7
+Res0 63:28
+Enum 27:24 I8MM
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 BF16
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 SPECRES
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 SB
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 FHM
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 DP
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 JSCVT
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_MMFR4_EL1 3 0 0 2 6
+Res0 63:32
+Enum 31:28 EVT
+ 0b0000 NI
+ 0b0001 NO_TLBIS
+ 0b0010 TLBIS
+EndEnum
+Enum 27:24 CCIDX
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 LSM
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 HPDS
+ 0b0000 NI
+ 0b0001 AA32HPD
+ 0b0010 HPDS2
+EndEnum
+Enum 15:12 CnP
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 XNX
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 AC2
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 SpecSEI
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg MVFR0_EL1 3 0 0 3 0
+Res0 63:32
+Enum 31:28 FPRound
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 FPShVec
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 23:20 FPSqrt
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 19:16 FPDivide
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 FPTrap
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 FPDP
+ 0b0000 NI
+ 0b0001 VFPv2
+ 0b0001 VFPv3
+EndEnum
+Enum 7:4 FPSP
+ 0b0000 NI
+ 0b0001 VFPv2
+ 0b0001 VFPv3
+EndEnum
+Enum 3:0 SIMDReg
+ 0b0000 NI
+ 0b0001 IMP_16x64
+ 0b0001 IMP_32x64
+EndEnum
+EndSysreg
+
+Sysreg MVFR1_EL1 3 0 0 3 1
+Res0 63:32
+Enum 31:28 SIMDFMAC
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 27:24 FPHP
+ 0b0000 NI
+ 0b0001 FPHP
+ 0b0010 FPHP_CONV
+ 0b0011 FP16
+EndEnum
+Enum 23:20 SIMDHP
+ 0b0000 NI
+ 0b0001 SIMDHP
+ 0b0001 SIMDHP_FLOAT
+EndEnum
+Enum 19:16 SIMDSP
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 15:12 SIMDInt
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 11:8 SIMDLS
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 7:4 FPDNaN
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 FPFtZ
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg MVFR2_EL1 3 0 0 3 2
+Res0 63:8
+Enum 7:4 FPMisc
+ 0b0000 NI
+ 0b0001 FP
+ 0b0010 FP_DIRECTED_ROUNDING
+ 0b0011 FP_ROUNDING
+ 0b0100 FP_MAX_MIN
+EndEnum
+Enum 3:0 SIMDMisc
+ 0b0000 NI
+ 0b0001 SIMD_DIRECTED_ROUNDING
+ 0b0010 SIMD_ROUNDING
+ 0b0011 SIMD_MAX_MIN
+EndEnum
+EndSysreg
+
+Sysreg ID_PFR2_EL1 3 0 0 3 4
+Res0 63:12
+Enum 11:8 RAS_frac
+ 0b0000 NI
+ 0b0001 RASv1p1
+EndEnum
+Enum 7:4 SSBS
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 CSV3
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
+Sysreg ID_DFR1_EL1 3 0 0 3 5
+Res0 63:8
+Enum 7:4 HPMN0
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 MTPMU
+ 0b0000 IMPDEF
+ 0b0001 IMP
+ 0b1111 NI
+EndEnum
+EndSysreg
+
+Sysreg ID_MMFR5_EL1 3 0 0 3 6
+Res0 63:8
+Enum 7:4 nTLBPA
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 3:0 ETS
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+EndSysreg
+
Sysreg ID_AA64PFR0_EL1 3 0 0 4 0
Enum 63:60 CSV3
0b0000 NI
@@ -210,6 +964,7 @@ EndEnum
Enum 3:0 SVEver
0b0000 IMP
0b0001 SVE2
+ 0b0010 SVE2p1
EndEnum
EndSysreg
@@ -484,7 +1239,16 @@ EndEnum
EndSysreg
Sysreg ID_AA64ISAR2_EL1 3 0 0 6 2
-Res0 63:28
+Res0 63:56
+Enum 55:52 CSSC
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Enum 51:48 RPRFM
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Res0 47:28
Enum 27:24 PAC_frac
0b0000 NI
0b0001 IMP
diff --git a/arch/csky/include/asm/stackprotector.h b/arch/csky/include/asm/stackprotector.h
index d7cd4e51edd9..d23747447166 100644
--- a/arch/csky/include/asm/stackprotector.h
+++ b/arch/csky/include/asm/stackprotector.h
@@ -2,9 +2,6 @@
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H 1
-#include <linux/random.h>
-#include <linux/version.h>
-
extern unsigned long __stack_chk_guard;
/*
@@ -15,12 +12,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
- canary &= CANARY_MASK;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/arch/csky/kernel/process.c b/arch/csky/kernel/process.c
index eedddb155669..2b0ed515a88e 100644
--- a/arch/csky/kernel/process.c
+++ b/arch/csky/kernel/process.c
@@ -9,6 +9,7 @@
#include <linux/kallsyms.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>
+#include <linux/elfcore.h>
#include <asm/elf.h>
#include <abi/reg_ops.h>
@@ -69,12 +70,11 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
}
/* Fill in the fpu structure for a core dump. */
-int dump_fpu(struct pt_regs *regs, struct user_fp *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
memcpy(fpu, &current->thread.user_fp, sizeof(*fpu));
return 1;
}
-EXPORT_SYMBOL(dump_fpu);
int dump_task_regs(struct task_struct *tsk, elf_gregset_t *pr_regs)
{
diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c
index 8975f9b4cedf..125f19995b76 100644
--- a/arch/hexagon/kernel/ptrace.c
+++ b/arch/hexagon/kernel/ptrace.c
@@ -115,10 +115,9 @@ static int genregs_set(struct task_struct *target,
/* Ignore the rest, if needed */
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- offsetof(struct user_regs_struct, pad1), -1);
-
- if (ret)
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ offsetof(struct user_regs_struct, pad1), -1);
+ else
return ret;
/*
diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c
index 684667ade525..901df49461a0 100644
--- a/arch/ia64/hp/common/aml_nfw.c
+++ b/arch/ia64/hp/common/aml_nfw.c
@@ -187,9 +187,9 @@ static int aml_nfw_add(struct acpi_device *device)
return aml_nfw_add_global_handler();
}
-static int aml_nfw_remove(struct acpi_device *device)
+static void aml_nfw_remove(struct acpi_device *device)
{
- return aml_nfw_remove_global_handler();
+ aml_nfw_remove_global_handler();
}
static const struct acpi_device_id aml_nfw_ids[] = {
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index ce66dfc0e719..83a492c8d298 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -23,10 +23,6 @@
#include <asm/unaligned.h>
#include <asm/early_ioremap.h>
-/* We don't use IO slowdowns on the ia64, but.. */
-#define __SLOW_DOWN_IO do { } while (0)
-#define SLOW_DOWN_IO do { } while (0)
-
#define __IA64_UNCACHED_OFFSET RGN_BASE(RGN_UNCACHED)
/*
diff --git a/arch/ia64/include/asm/kprobes.h b/arch/ia64/include/asm/kprobes.h
index c5cf5e4fb338..9e956768946c 100644
--- a/arch/ia64/include/asm/kprobes.h
+++ b/arch/ia64/include/asm/kprobes.h
@@ -110,8 +110,6 @@ extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
-extern void invalidate_stacked_regs(void);
-extern void flush_register_stack(void);
extern void arch_remove_kprobe(struct kprobe *p);
#endif /* CONFIG_KPROBES */
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index ab8aeb34d1d9..4c41912c550f 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1481,12 +1481,10 @@ static void do_gpregs_set(struct unw_frame_info *info, void *arg)
return;
/* Skip r0 */
if (dst->pos < ELF_GR_OFFSET(1)) {
- dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
- &dst->u.set.kbuf,
- &dst->u.set.ubuf,
- 0, ELF_GR_OFFSET(1));
- if (dst->ret)
- return;
+ user_regset_copyin_ignore(&dst->pos, &dst->count,
+ &dst->u.set.kbuf, &dst->u.set.ubuf,
+ 0, ELF_GR_OFFSET(1));
+ dst->ret = 0;
}
while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
@@ -1560,11 +1558,11 @@ static void do_fpregs_set(struct unw_frame_info *info, void *arg)
/* Skip pos 0 and 1 */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
- dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
- &dst->u.set.kbuf,
- &dst->u.set.ubuf,
- 0, ELF_FP_OFFSET(2));
- if (dst->count == 0 || dst->ret)
+ user_regset_copyin_ignore(&dst->pos, &dst->count,
+ &dst->u.set.kbuf, &dst->u.set.ubuf,
+ 0, ELF_FP_OFFSET(2));
+ dst->ret = 0;
+ if (dst->count == 0)
return;
}
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 215bf3f8cb20..f6a502e8f02c 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -140,7 +140,7 @@ asmlinkage unsigned long
sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff)
{
addr = ksys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
- if (!IS_ERR((void *) addr))
+ if (!IS_ERR_VALUE(addr))
force_successful_syscall_return();
return addr;
}
@@ -152,7 +152,7 @@ sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, int fd, lo
return -EINVAL;
addr = ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
- if (!IS_ERR((void *) addr))
+ if (!IS_ERR_VALUE(addr))
force_successful_syscall_return();
return addr;
}
@@ -162,7 +162,7 @@ ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, u
unsigned long new_addr)
{
addr = sys_mremap(addr, old_len, new_len, flags, new_addr);
- if (!IS_ERR((void *) addr))
+ if (!IS_ERR_VALUE(addr))
force_successful_syscall_return();
return addr;
}
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 903096bd87f8..386adde2feff 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -10,6 +10,7 @@ config LOONGARCH
select ARCH_ENABLE_MEMORY_HOTPLUG
select ARCH_ENABLE_MEMORY_HOTREMOVE
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
+ select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_INLINE_READ_LOCK if !PREEMPTION
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index f4cb54d5afd6..01b57b726322 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -97,7 +97,7 @@ KBUILD_LDFLAGS += -m $(ld-emul)
ifdef CONFIG_LOONGARCH
CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
- egrep -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \
+ grep -E -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \
sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g')
endif
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index 17162f494b9b..825c2519b9d1 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -31,148 +31,6 @@ static inline bool acpi_has_cpu_in_madt(void)
extern struct list_head acpi_wakeup_device_list;
-/*
- * Temporary definitions until the core ACPICA code gets updated (see
- * 1656837932-18257-1-git-send-email-lvjianmin@loongson.cn and its
- * follow-ups for the "rationale").
- *
- * Once the "legal reasons" are cleared and that the code is merged,
- * this can be dropped entierely.
- */
-#if (ACPI_CA_VERSION == 0x20220331 && !defined(LOONGARCH_ACPICA_EXT))
-
-#define LOONGARCH_ACPICA_EXT 1
-
-#define ACPI_MADT_TYPE_CORE_PIC 17
-#define ACPI_MADT_TYPE_LIO_PIC 18
-#define ACPI_MADT_TYPE_HT_PIC 19
-#define ACPI_MADT_TYPE_EIO_PIC 20
-#define ACPI_MADT_TYPE_MSI_PIC 21
-#define ACPI_MADT_TYPE_BIO_PIC 22
-#define ACPI_MADT_TYPE_LPC_PIC 23
-
-/* Values for Version field above */
-
-enum acpi_madt_core_pic_version {
- ACPI_MADT_CORE_PIC_VERSION_NONE = 0,
- ACPI_MADT_CORE_PIC_VERSION_V1 = 1,
- ACPI_MADT_CORE_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_lio_pic_version {
- ACPI_MADT_LIO_PIC_VERSION_NONE = 0,
- ACPI_MADT_LIO_PIC_VERSION_V1 = 1,
- ACPI_MADT_LIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_eio_pic_version {
- ACPI_MADT_EIO_PIC_VERSION_NONE = 0,
- ACPI_MADT_EIO_PIC_VERSION_V1 = 1,
- ACPI_MADT_EIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_ht_pic_version {
- ACPI_MADT_HT_PIC_VERSION_NONE = 0,
- ACPI_MADT_HT_PIC_VERSION_V1 = 1,
- ACPI_MADT_HT_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_bio_pic_version {
- ACPI_MADT_BIO_PIC_VERSION_NONE = 0,
- ACPI_MADT_BIO_PIC_VERSION_V1 = 1,
- ACPI_MADT_BIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_msi_pic_version {
- ACPI_MADT_MSI_PIC_VERSION_NONE = 0,
- ACPI_MADT_MSI_PIC_VERSION_V1 = 1,
- ACPI_MADT_MSI_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-enum acpi_madt_lpc_pic_version {
- ACPI_MADT_LPC_PIC_VERSION_NONE = 0,
- ACPI_MADT_LPC_PIC_VERSION_V1 = 1,
- ACPI_MADT_LPC_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-#pragma pack(1)
-
-/* Core Interrupt Controller */
-
-struct acpi_madt_core_pic {
- struct acpi_subtable_header header;
- u8 version;
- u32 processor_id;
- u32 core_id;
- u32 flags;
-};
-
-/* Legacy I/O Interrupt Controller */
-
-struct acpi_madt_lio_pic {
- struct acpi_subtable_header header;
- u8 version;
- u64 address;
- u16 size;
- u8 cascade[2];
- u32 cascade_map[2];
-};
-
-/* Extend I/O Interrupt Controller */
-
-struct acpi_madt_eio_pic {
- struct acpi_subtable_header header;
- u8 version;
- u8 cascade;
- u8 node;
- u64 node_map;
-};
-
-/* HT Interrupt Controller */
-
-struct acpi_madt_ht_pic {
- struct acpi_subtable_header header;
- u8 version;
- u64 address;
- u16 size;
- u8 cascade[8];
-};
-
-/* Bridge I/O Interrupt Controller */
-
-struct acpi_madt_bio_pic {
- struct acpi_subtable_header header;
- u8 version;
- u64 address;
- u16 size;
- u16 id;
- u16 gsi_base;
-};
-
-/* MSI Interrupt Controller */
-
-struct acpi_madt_msi_pic {
- struct acpi_subtable_header header;
- u8 version;
- u64 msg_address;
- u32 start;
- u32 count;
-};
-
-/* LPC Interrupt Controller */
-
-struct acpi_madt_lpc_pic {
- struct acpi_subtable_header header;
- u8 version;
- u64 address;
- u16 size;
- u8 cascade;
-};
-
-#pragma pack()
-
-#endif
-
#endif /* !CONFIG_ACPI */
#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index d06d4542b634..a115e8999c69 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -93,7 +93,7 @@ int liointc_acpi_init(struct irq_domain *parent,
int eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc);
-struct irq_domain *htvec_acpi_init(struct irq_domain *parent,
+int htvec_acpi_init(struct irq_domain *parent,
struct acpi_madt_ht_pic *acpi_htvec);
int pch_lpc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lpc_pic *acpi_pchlpc);
@@ -117,7 +117,7 @@ extern struct fwnode_handle *liointc_handle;
extern struct fwnode_handle *pch_lpc_handle;
extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
-extern irqreturn_t loongson3_ipi_interrupt(int irq, void *dev);
+extern irqreturn_t loongson_ipi_interrupt(int irq, void *dev);
#include <asm-generic/irq.h>
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index 946704bee599..79d5bfd913e0 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -349,13 +349,17 @@ static inline pte_t pte_mkclean(pte_t pte)
static inline pte_t pte_mkdirty(pte_t pte)
{
- pte_val(pte) |= (_PAGE_DIRTY | _PAGE_MODIFIED);
+ pte_val(pte) |= _PAGE_MODIFIED;
+ if (pte_val(pte) & _PAGE_WRITE)
+ pte_val(pte) |= _PAGE_DIRTY;
return pte;
}
static inline pte_t pte_mkwrite(pte_t pte)
{
- pte_val(pte) |= (_PAGE_WRITE | _PAGE_DIRTY);
+ pte_val(pte) |= _PAGE_WRITE;
+ if (pte_val(pte) & _PAGE_MODIFIED)
+ pte_val(pte) |= _PAGE_DIRTY;
return pte;
}
@@ -455,7 +459,9 @@ static inline int pmd_write(pmd_t pmd)
static inline pmd_t pmd_mkwrite(pmd_t pmd)
{
- pmd_val(pmd) |= (_PAGE_WRITE | _PAGE_DIRTY);
+ pmd_val(pmd) |= _PAGE_WRITE;
+ if (pmd_val(pmd) & _PAGE_MODIFIED)
+ pmd_val(pmd) |= _PAGE_DIRTY;
return pmd;
}
@@ -478,10 +484,13 @@ static inline pmd_t pmd_mkclean(pmd_t pmd)
static inline pmd_t pmd_mkdirty(pmd_t pmd)
{
- pmd_val(pmd) |= (_PAGE_DIRTY | _PAGE_MODIFIED);
+ pmd_val(pmd) |= _PAGE_MODIFIED;
+ if (pmd_val(pmd) & _PAGE_WRITE)
+ pmd_val(pmd) |= _PAGE_DIRTY;
return pmd;
}
+#define pmd_young pmd_young
static inline int pmd_young(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_ACCESSED);
diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
index 71189b28bfb2..d82687390b4a 100644
--- a/arch/loongarch/include/asm/smp.h
+++ b/arch/loongarch/include/asm/smp.h
@@ -19,21 +19,21 @@ extern cpumask_t cpu_sibling_map[];
extern cpumask_t cpu_core_map[];
extern cpumask_t cpu_foreign_map[];
-void loongson3_smp_setup(void);
-void loongson3_prepare_cpus(unsigned int max_cpus);
-void loongson3_boot_secondary(int cpu, struct task_struct *idle);
-void loongson3_init_secondary(void);
-void loongson3_smp_finish(void);
-void loongson3_send_ipi_single(int cpu, unsigned int action);
-void loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action);
+void loongson_smp_setup(void);
+void loongson_prepare_cpus(unsigned int max_cpus);
+void loongson_boot_secondary(int cpu, struct task_struct *idle);
+void loongson_init_secondary(void);
+void loongson_smp_finish(void);
+void loongson_send_ipi_single(int cpu, unsigned int action);
+void loongson_send_ipi_mask(const struct cpumask *mask, unsigned int action);
#ifdef CONFIG_HOTPLUG_CPU
-int loongson3_cpu_disable(void);
-void loongson3_cpu_die(unsigned int cpu);
+int loongson_cpu_disable(void);
+void loongson_cpu_die(unsigned int cpu);
#endif
static inline void plat_smp_setup(void)
{
- loongson3_smp_setup();
+ loongson_smp_setup();
}
static inline int raw_smp_processor_id(void)
@@ -78,35 +78,25 @@ extern void calculate_cpu_foreign_map(void);
*/
extern void show_ipi_list(struct seq_file *p, int prec);
-/*
- * This function sends a 'reschedule' IPI to another CPU.
- * it goes straight through and wastes no time serializing
- * anything. Worst case is that we lose a reschedule ...
- */
-static inline void smp_send_reschedule(int cpu)
-{
- loongson3_send_ipi_single(cpu, SMP_RESCHEDULE);
-}
-
static inline void arch_send_call_function_single_ipi(int cpu)
{
- loongson3_send_ipi_single(cpu, SMP_CALL_FUNCTION);
+ loongson_send_ipi_single(cpu, SMP_CALL_FUNCTION);
}
static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
- loongson3_send_ipi_mask(mask, SMP_CALL_FUNCTION);
+ loongson_send_ipi_mask(mask, SMP_CALL_FUNCTION);
}
#ifdef CONFIG_HOTPLUG_CPU
static inline int __cpu_disable(void)
{
- return loongson3_cpu_disable();
+ return loongson_cpu_disable();
}
static inline void __cpu_die(unsigned int cpu)
{
- loongson3_cpu_die(cpu);
+ loongson_cpu_die(cpu);
}
extern void play_dead(void);
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index 335398482038..8319cc409009 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -56,23 +56,6 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
return ioremap_cache(phys, size);
}
-void __init acpi_boot_table_init(void)
-{
- /*
- * If acpi_disabled, bail out
- */
- if (acpi_disabled)
- return;
-
- /*
- * Initialize the ACPI boot-time table parser.
- */
- if (acpi_table_init()) {
- disable_acpi();
- return;
- }
-}
-
#ifdef CONFIG_SMP
static int set_processor_mask(u32 id, u32 flags)
{
@@ -156,13 +139,21 @@ static void __init acpi_process_madt(void)
loongson_sysconf.nr_cpus = num_processors;
}
-int __init acpi_boot_init(void)
+void __init acpi_boot_table_init(void)
{
/*
* If acpi_disabled, bail out
*/
if (acpi_disabled)
- return -1;
+ return;
+
+ /*
+ * Initialize the ACPI boot-time table parser.
+ */
+ if (acpi_table_init()) {
+ disable_acpi();
+ return;
+ }
loongson_sysconf.boot_cpu_id = read_csr_cpuid();
@@ -173,8 +164,6 @@ int __init acpi_boot_init(void)
/* Do not enable ACPI SPCR console by default */
acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
-
- return 0;
}
#ifdef CONFIG_ACPI_NUMA
diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c
index 1ba19c76563e..0524bf1169b7 100644
--- a/arch/loongarch/kernel/irq.c
+++ b/arch/loongarch/kernel/irq.c
@@ -117,7 +117,7 @@ void __init init_IRQ(void)
if (ipi_irq < 0)
panic("IPI IRQ mapping failed\n");
irq_set_percpu_devid(ipi_irq);
- r = request_percpu_irq(ipi_irq, loongson3_ipi_interrupt, "IPI", &ipi_dummy_dev);
+ r = request_percpu_irq(ipi_irq, loongson_ipi_interrupt, "IPI", &ipi_dummy_dev);
if (r < 0)
panic("IPI IRQ request failed\n");
#endif
diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
index 2526b68f1c0f..d61c9f465b95 100644
--- a/arch/loongarch/kernel/process.c
+++ b/arch/loongarch/kernel/process.c
@@ -152,7 +152,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
childregs->csr_crmd = p->thread.csr_crmd;
childregs->csr_prmd = p->thread.csr_prmd;
childregs->csr_ecfg = p->thread.csr_ecfg;
- return 0;
+ goto out;
}
/* user thread */
@@ -171,14 +171,15 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
*/
childregs->csr_euen = 0;
+ if (clone_flags & CLONE_SETTLS)
+ childregs->regs[2] = tls;
+
+out:
clear_tsk_thread_flag(p, TIF_USEDFPU);
clear_tsk_thread_flag(p, TIF_USEDSIMD);
clear_tsk_thread_flag(p, TIF_LSX_CTX_LIVE);
clear_tsk_thread_flag(p, TIF_LASX_CTX_LIVE);
- if (clone_flags & CLONE_SETTLS)
- childregs->regs[2] = tls;
-
return 0;
}
@@ -293,7 +294,7 @@ unsigned long stack_top(void)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(PAGE_SIZE);
+ sp -= get_random_u32_below(PAGE_SIZE);
return sp & STACK_ALIGN;
}
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 1eb63fa9bc81..ae436def7ee9 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -257,7 +257,6 @@ void __init platform_init(void)
#ifdef CONFIG_ACPI
acpi_gbl_use_default_register_widths = false;
acpi_boot_table_init();
- acpi_boot_init();
#endif
#ifdef CONFIG_NUMA
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 781a4d4bdddc..14508d429ffa 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -136,12 +136,12 @@ static void ipi_write_action(int cpu, u32 action)
}
}
-void loongson3_send_ipi_single(int cpu, unsigned int action)
+void loongson_send_ipi_single(int cpu, unsigned int action)
{
ipi_write_action(cpu_logical_map(cpu), (u32)action);
}
-void loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+void loongson_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
@@ -149,7 +149,18 @@ void loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
ipi_write_action(cpu_logical_map(i), (u32)action);
}
-irqreturn_t loongson3_ipi_interrupt(int irq, void *dev)
+/*
+ * This function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+void smp_send_reschedule(int cpu)
+{
+ loongson_send_ipi_single(cpu, SMP_RESCHEDULE);
+}
+EXPORT_SYMBOL_GPL(smp_send_reschedule);
+
+irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
{
unsigned int action;
unsigned int cpu = smp_processor_id();
@@ -169,7 +180,7 @@ irqreturn_t loongson3_ipi_interrupt(int irq, void *dev)
return IRQ_HANDLED;
}
-void __init loongson3_smp_setup(void)
+void __init loongson_smp_setup(void)
{
cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package;
cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
@@ -178,7 +189,7 @@ void __init loongson3_smp_setup(void)
pr_info("Detected %i available CPU(s)\n", loongson_sysconf.nr_cpus);
}
-void __init loongson3_prepare_cpus(unsigned int max_cpus)
+void __init loongson_prepare_cpus(unsigned int max_cpus)
{
int i = 0;
@@ -193,7 +204,7 @@ void __init loongson3_prepare_cpus(unsigned int max_cpus)
/*
* Setup the PC, SP, and TP of a secondary processor and start it running!
*/
-void loongson3_boot_secondary(int cpu, struct task_struct *idle)
+void loongson_boot_secondary(int cpu, struct task_struct *idle)
{
unsigned long entry;
@@ -205,13 +216,13 @@ void loongson3_boot_secondary(int cpu, struct task_struct *idle)
csr_mail_send(entry, cpu_logical_map(cpu), 0);
- loongson3_send_ipi_single(cpu, SMP_BOOT_CPU);
+ loongson_send_ipi_single(cpu, SMP_BOOT_CPU);
}
/*
* SMP init and finish on secondary CPUs
*/
-void loongson3_init_secondary(void)
+void loongson_init_secondary(void)
{
unsigned int cpu = smp_processor_id();
unsigned int imask = ECFGF_IP0 | ECFGF_IP1 | ECFGF_IP2 |
@@ -231,7 +242,7 @@ void loongson3_init_secondary(void)
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
}
-void loongson3_smp_finish(void)
+void loongson_smp_finish(void)
{
local_irq_enable();
iocsr_write64(0, LOONGARCH_IOCSR_MBUF0);
@@ -240,7 +251,7 @@ void loongson3_smp_finish(void)
#ifdef CONFIG_HOTPLUG_CPU
-int loongson3_cpu_disable(void)
+int loongson_cpu_disable(void)
{
unsigned long flags;
unsigned int cpu = smp_processor_id();
@@ -262,7 +273,7 @@ int loongson3_cpu_disable(void)
return 0;
}
-void loongson3_cpu_die(unsigned int cpu)
+void loongson_cpu_die(unsigned int cpu)
{
while (per_cpu(cpu_state, cpu) != CPU_DEAD)
cpu_relax();
@@ -300,19 +311,19 @@ void play_dead(void)
*/
#ifdef CONFIG_PM
-static int loongson3_ipi_suspend(void)
+static int loongson_ipi_suspend(void)
{
return 0;
}
-static void loongson3_ipi_resume(void)
+static void loongson_ipi_resume(void)
{
iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN);
}
-static struct syscore_ops loongson3_ipi_syscore_ops = {
- .resume = loongson3_ipi_resume,
- .suspend = loongson3_ipi_suspend,
+static struct syscore_ops loongson_ipi_syscore_ops = {
+ .resume = loongson_ipi_resume,
+ .suspend = loongson_ipi_suspend,
};
/*
@@ -321,7 +332,7 @@ static struct syscore_ops loongson3_ipi_syscore_ops = {
*/
static int __init ipi_pm_init(void)
{
- register_syscore_ops(&loongson3_ipi_syscore_ops);
+ register_syscore_ops(&loongson_ipi_syscore_ops);
return 0;
}
@@ -425,7 +436,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{
init_new_context(current, &init_mm);
current_thread_info()->cpu = 0;
- loongson3_prepare_cpus(max_cpus);
+ loongson_prepare_cpus(max_cpus);
set_cpu_sibling_map(0);
set_cpu_core_map(0);
calculate_cpu_foreign_map();
@@ -436,7 +447,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
- loongson3_boot_secondary(cpu, tidle);
+ loongson_boot_secondary(cpu, tidle);
/* Wait for CPU to start and be ready to sync counters */
if (!wait_for_completion_timeout(&cpu_starting,
@@ -465,7 +476,7 @@ asmlinkage void start_secondary(void)
cpu_probe();
constant_clockevent_init();
- loongson3_init_secondary();
+ loongson_init_secondary();
set_cpu_sibling_map(cpu);
set_cpu_core_map(cpu);
@@ -487,11 +498,11 @@ asmlinkage void start_secondary(void)
complete(&cpu_running);
/*
- * irq will be enabled in loongson3_smp_finish(), enabling it too
+ * irq will be enabled in loongson_smp_finish(), enabling it too
* early is dangerous.
*/
WARN_ON_ONCE(!irqs_disabled());
- loongson3_smp_finish();
+ loongson_smp_finish();
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
}
diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c
index b206d9159205..4571c3c87cd4 100644
--- a/arch/loongarch/kernel/unwind_prologue.c
+++ b/arch/loongarch/kernel/unwind_prologue.c
@@ -43,7 +43,8 @@ static bool unwind_by_prologue(struct unwind_state *state)
{
struct stack_info *info = &state->stack_info;
union loongarch_instruction *ip, *ip_end;
- unsigned long frame_size = 0, frame_ra = -1;
+ long frame_ra = -1;
+ unsigned long frame_size = 0;
unsigned long size, offset, pc = state->pc;
if (state->sp >= info->end || state->sp < info->begin)
diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c
index 8c9826062652..eaebd2e0f725 100644
--- a/arch/loongarch/kernel/vdso.c
+++ b/arch/loongarch/kernel/vdso.c
@@ -78,7 +78,7 @@ static unsigned long vdso_base(void)
unsigned long base = STACK_TOP;
if (current->flags & PF_RANDOMIZE) {
- base += prandom_u32_max(VDSO_RANDOMIZE_SIZE);
+ base += get_random_u32_below(VDSO_RANDOMIZE_SIZE);
base = PAGE_ALIGN(base);
}
diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
index d8ee8fbc8c67..58781c6e4191 100644
--- a/arch/loongarch/mm/tlbex.S
+++ b/arch/loongarch/mm/tlbex.S
@@ -10,6 +10,8 @@
#include <asm/regdef.h>
#include <asm/stackframe.h>
+#define INVTLB_ADDR_GFALSE_AND_ASID 5
+
#define PTRS_PER_PGD_BITS (PAGE_SHIFT - 3)
#define PTRS_PER_PUD_BITS (PAGE_SHIFT - 3)
#define PTRS_PER_PMD_BITS (PAGE_SHIFT - 3)
@@ -136,13 +138,10 @@ tlb_huge_update_load:
ori t0, ra, _PAGE_VALID
st.d t0, t1, 0
#endif
- tlbsrch
- addu16i.d t1, zero, -(CSR_TLBIDX_EHINV >> 16)
- addi.d ra, t1, 0
- csrxchg ra, t1, LOONGARCH_CSR_TLBIDX
- tlbwr
-
- csrxchg zero, t1, LOONGARCH_CSR_TLBIDX
+ csrrd ra, LOONGARCH_CSR_ASID
+ csrrd t1, LOONGARCH_CSR_BADV
+ andi ra, ra, CSR_ASID_ASID
+ invtlb INVTLB_ADDR_GFALSE_AND_ASID, ra, t1
/*
* A huge PTE describes an area the size of the
@@ -287,13 +286,11 @@ tlb_huge_update_store:
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
st.d t0, t1, 0
#endif
- tlbsrch
- addu16i.d t1, zero, -(CSR_TLBIDX_EHINV >> 16)
- addi.d ra, t1, 0
- csrxchg ra, t1, LOONGARCH_CSR_TLBIDX
- tlbwr
+ csrrd ra, LOONGARCH_CSR_ASID
+ csrrd t1, LOONGARCH_CSR_BADV
+ andi ra, ra, CSR_ASID_ASID
+ invtlb INVTLB_ADDR_GFALSE_AND_ASID, ra, t1
- csrxchg zero, t1, LOONGARCH_CSR_TLBIDX
/*
* A huge PTE describes an area the size of the
* configured huge page size. This is twice the
@@ -436,6 +433,11 @@ tlb_huge_update_modify:
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
st.d t0, t1, 0
#endif
+ csrrd ra, LOONGARCH_CSR_ASID
+ csrrd t1, LOONGARCH_CSR_BADV
+ andi ra, ra, CSR_ASID_ASID
+ invtlb INVTLB_ADDR_GFALSE_AND_ASID, ra, t1
+
/*
* A huge PTE describes an area the size of the
* configured huge page size. This is twice the
@@ -466,7 +468,7 @@ tlb_huge_update_modify:
addu16i.d t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
- tlbwr
+ tlbfill
/* Reset default page size */
addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index e2038d9499e4..7b49fe6f7cb3 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -562,29 +562,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -593,11 +574,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index ddd201259e43..656a06d97d4c 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -519,29 +519,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -550,11 +531,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index d9f783707387..8972b822875d 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -539,29 +539,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -570,11 +551,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 68957c6bcff1..7b86e1277a1a 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -511,29 +511,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -542,11 +523,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 825c6a02fa9d..d0d5c0a9aee6 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -521,29 +521,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -552,11 +533,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 17f64c562bf1..ac1d0c86b6ff 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -541,29 +541,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -572,11 +553,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index f5f4c572b694..c5f7603c9830 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -627,29 +627,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -658,11 +639,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index b4a0bbef7e39..26f5b59e3bc0 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -510,29 +510,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -541,11 +522,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index c6a6d5926793..3045c7f0bde3 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -511,29 +511,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -542,11 +523,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 49c9c89f0caf..f2a486be651b 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -528,29 +528,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -559,11 +540,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index 9b44eeb9c07f..8a7db7be10c0 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -510,29 +510,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -541,11 +522,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index d2ffb0a65b44..7ed49ee0b9e0 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -509,29 +509,10 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_TI=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
@@ -540,11 +521,30 @@ CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 557d60867f98..6fdc13610565 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -49,7 +49,7 @@ static void nfcon_write(struct console *con, const char *str,
static struct tty_driver *nfcon_device(struct console *con, int *index)
{
*index = 0;
- return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL;
+ return console_is_registered(con) ? nfcon_tty_driver : NULL;
}
static struct console nf_console = {
@@ -107,6 +107,11 @@ static int __init nf_debug_setup(char *arg)
stderr_id = nf_get_id("NF_STDERR");
if (stderr_id) {
+ /*
+ * The console will be enabled when debug=nfcon is specified
+ * as a kernel parameter. Since this is a non-standard way
+ * of enabling consoles, it must be explicitly enabled.
+ */
nf_console.flags |= CON_ENABLED;
register_console(&nf_console);
}
@@ -151,7 +156,7 @@ static int __init nfcon_init(void)
nfcon_tty_driver = driver;
- if (!(nf_console.flags & CON_ENABLED))
+ if (!console_is_registered(&nf_console))
register_console(&nf_console);
return 0;
diff --git a/arch/m68k/include/asm/mac_via.h b/arch/m68k/include/asm/mac_via.h
index 1149251ea58d..a9ef1e9ba6c4 100644
--- a/arch/m68k/include/asm/mac_via.h
+++ b/arch/m68k/include/asm/mac_via.h
@@ -267,14 +267,6 @@ extern void via1_irq(struct irq_desc *desc);
extern void via1_set_head(int);
extern int via2_scsi_drq_pending(void);
-static inline int rbv_set_video_bpp(int bpp)
-{
- char val = (bpp==1)?0:(bpp==2)?1:(bpp==4)?2:(bpp==8)?3:-1;
- if (!rbv_present || val<0) return -1;
- via2[rMonP] = (via2[rMonP] & ~RBV_DEPTH) | val;
- return 0;
-}
-
#endif /* __ASSEMBLY__ */
#endif /* _ASM_MAC_VIA_H_ */
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 2cb4a61bcfac..e06ce147c0b7 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -32,6 +32,7 @@
#include <linux/rcupdate.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/elfcore.h>
#include <asm/traps.h>
#include <asm/machdep.h>
@@ -213,7 +214,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
}
/* Fill in the fpu structure for a core dump. */
-int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
if (FPU_IS_EMU) {
int i;
@@ -262,7 +263,6 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
return 1;
}
-EXPORT_SYMBOL(dump_fpu);
unsigned long __get_wchan(struct task_struct *p)
{
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 4fab34791758..c7cb29f0ff01 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -126,7 +126,7 @@ static void via_rtc_send(__u8 data)
reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
- /* The bits of the byte go in in MSB order */
+ /* The bits of the byte go into the RTC in MSB order */
for (i = 0 ; i < 8 ; i++) {
bit = data & 0x80? 1 : 0;
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 4ebb56d6d959..cc88af6fa7a4 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -215,11 +215,3 @@ config MB_MANAGER
Say N here unless you know what you are doing.
endmenu
-
-menu "Bus Options"
-
-config PCI_XILINX
- bool "Xilinx PCI host bridge support"
- depends on PCI
-
-endmenu
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index 3f8a86c4336a..02e6be9c5b0d 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -67,12 +67,12 @@ linux.bin.ub linux.bin.gz: linux.bin
linux.bin: vmlinux
linux.bin linux.bin.gz linux.bin.ub:
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
- @echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
+ @echo 'Kernel: $(boot)/$@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
PHONY += simpleImage.$(DTB)
simpleImage.$(DTB): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(addprefix $(boot)/$@., ub unstrip strip)
- @echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
+ @echo 'Kernel: $(boot)/$@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
define archhelp
echo '* linux.bin - Create raw binary'
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index 8150daf04a76..756feb9369a6 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -19,7 +19,6 @@ CONFIG_HZ_100=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE_FORCE=y
CONFIG_HIGHMEM=y
-CONFIG_PCI_XILINX=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 171b40a2d905..be5f504bead4 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -25,75 +25,17 @@ static inline int pcibios_vaddr_is_ioport(void __iomem *address)
*/
struct pci_controller {
struct pci_bus *bus;
- char is_dynamic;
- struct device_node *dn;
struct list_head list_node;
- struct device *parent;
-
- int first_busno;
- int last_busno;
-
- int self_busno;
void __iomem *io_base_virt;
- resource_size_t io_base_phys;
-
- resource_size_t pci_io_size;
-
- /* Some machines (PReP) have a non 1:1 mapping of
- * the PCI memory space in the CPU bus space
- */
- resource_size_t pci_mem_offset;
-
- /* Some machines have a special region to forward the ISA
- * "memory" cycles such as VGA memory regions. Left to 0
- * if unsupported
- */
- resource_size_t isa_mem_phys;
- resource_size_t isa_mem_size;
-
- struct pci_ops *ops;
- unsigned int __iomem *cfg_addr;
- void __iomem *cfg_data;
-
- /*
- * Used for variants of PCI indirect handling and possible quirks:
- * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
- * EXT_REG - provides access to PCI-e extended registers
- * SURPRESS_PRIMARY_BUS - we suppress the setting of PCI_PRIMARY_BUS
- * on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS
- * to determine which bus number to match on when generating type0
- * config cycles
- * NO_PCIE_LINK - the Freescale PCI-e controllers have issues with
- * hanging if we don't have link and try to do config cycles to
- * anything but the PHB. Only allow talking to the PHB if this is
- * set.
- * BIG_ENDIAN - cfg_addr is a big endian register
- * BROKEN_MRM - the 440EPx/GRx chips have an errata that causes hangs
- * on the PLB4. Effectively disable MRM commands by setting this.
- */
-#define INDIRECT_TYPE_SET_CFG_TYPE 0x00000001
-#define INDIRECT_TYPE_EXT_REG 0x00000002
-#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS 0x00000004
-#define INDIRECT_TYPE_NO_PCIE_LINK 0x00000008
-#define INDIRECT_TYPE_BIG_ENDIAN 0x00000010
-#define INDIRECT_TYPE_BROKEN_MRM 0x00000020
- u32 indirect_type;
/* Currently, we limit ourselves to 1 IO range and 3 mem
* ranges since the common pci_bus structure can't handle more
*/
struct resource io_resource;
- struct resource mem_resources[3];
- int global_number; /* PCI domain number */
};
#ifdef CONFIG_PCI
-static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
-{
- return bus->sysdata;
-}
-
static inline int isa_vaddr_is_ioport(void __iomem *address)
{
/* No specific ISA handling on ppc32 at this stage, it
@@ -103,39 +45,5 @@ static inline int isa_vaddr_is_ioport(void __iomem *address)
}
#endif /* CONFIG_PCI */
-/* These are used for config access before all the PCI probing
- has been done. */
-extern int early_read_config_byte(struct pci_controller *hose, int bus,
- int dev_fn, int where, u8 *val);
-extern int early_read_config_word(struct pci_controller *hose, int bus,
- int dev_fn, int where, u16 *val);
-extern int early_read_config_dword(struct pci_controller *hose, int bus,
- int dev_fn, int where, u32 *val);
-extern int early_write_config_byte(struct pci_controller *hose, int bus,
- int dev_fn, int where, u8 val);
-extern int early_write_config_word(struct pci_controller *hose, int bus,
- int dev_fn, int where, u16 val);
-extern int early_write_config_dword(struct pci_controller *hose, int bus,
- int dev_fn, int where, u32 val);
-
-extern int early_find_capability(struct pci_controller *hose, int bus,
- int dev_fn, int cap);
-
-extern void setup_indirect_pci(struct pci_controller *hose,
- resource_size_t cfg_addr,
- resource_size_t cfg_data, u32 flags);
-
-/* Get the PCI host controller for an OF device */
-extern struct pci_controller *pci_find_hose_for_OF_device(
- struct device_node *node);
-
-/* Fill up host controller resources from the OF node */
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev, int primary);
-
-/* Allocate & free a PCI host bridge structure */
-extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
-extern void pcibios_free_controller(struct pci_controller *phb);
-
#endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index d90528064604..91f1f71c266a 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -21,15 +21,6 @@
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0x10000000
-/* Values for the `which' argument to sys_pciconfig_iobase syscall. */
-#define IOBASE_BRIDGE_NUMBER 0
-#define IOBASE_MEMORY 1
-#define IOBASE_IO 2
-#define IOBASE_ISA_IO 3
-#define IOBASE_ISA_MEM 4
-
-#define pcibios_scan_all_fns(a, b) 0
-
/*
* Set this to 1 if you want the kernel to re-assign all PCI
* bus numbers (don't do that on ppc64 yet !)
@@ -41,33 +32,13 @@ extern int pci_domain_nr(struct pci_bus *bus);
/* Decide whether to display the domain number in /proc */
extern int pci_proc_domain(struct pci_bus *bus);
-struct vm_area_struct;
-
/* Tell PCI code what kind of PCI resource mappings we support */
#define HAVE_PCI_MMAP 1
#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
-#define arch_can_pci_mmap_io() 1
-
-extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
- size_t count);
-extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
- size_t count);
-extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state);
-
-#define HAVE_PCI_LEGACY 1
-
-extern void pcibios_resource_survey(void);
struct file;
-/* This part of code was originally in xilinx-pci.h */
-#ifdef CONFIG_PCI_XILINX
-extern void __init xilinx_pci_init(void);
-#else
static inline void __init xilinx_pci_init(void) { return; }
-#endif
#endif /* __KERNEL__ */
#endif /* __ASM_MICROBLAZE_PCI_H */
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 3c6241bcaea8..1f802aab2b96 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -133,7 +133,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
/*
* Set up a thread for executing a new program
*/
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
return 0; /* MicroBlaze has no separate FPU registers */
}
diff --git a/arch/microblaze/pci/Makefile b/arch/microblaze/pci/Makefile
index 0251c20e1d62..f8267d20e067 100644
--- a/arch/microblaze/pci/Makefile
+++ b/arch/microblaze/pci/Makefile
@@ -3,5 +3,4 @@
# Makefile
#
-obj-$(CONFIG_PCI) += pci-common.o indirect_pci.o iomap.o
-obj-$(CONFIG_PCI_XILINX) += xilinx_pci.o
+obj-$(CONFIG_PCI) += iomap.o
diff --git a/arch/microblaze/pci/indirect_pci.c b/arch/microblaze/pci/indirect_pci.c
deleted file mode 100644
index 1caf7d3e0eef..000000000000
--- a/arch/microblaze/pci/indirect_pci.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Support for indirect PCI bridges.
- *
- * Copyright (C) 1998 Gabriel Paubert.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <asm/pci-bridge.h>
-
-static int
-indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 *val)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- volatile void __iomem *cfg_data;
- u8 cfg_type = 0;
- u32 bus_no, reg;
-
- if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
- if (bus->number != hose->first_busno)
- return PCIBIOS_DEVICE_NOT_FOUND;
- if (devfn != 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
- if (bus->number != hose->first_busno)
- cfg_type = 1;
-
- bus_no = (bus->number == hose->first_busno) ?
- hose->self_busno : bus->number;
-
- if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
- reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
- else
- reg = offset & 0xfc; /* Only 3 bits for function */
-
- if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
- out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
- (devfn << 8) | reg | cfg_type));
- else
- out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
- (devfn << 8) | reg | cfg_type));
-
- /*
- * Note: the caller has already checked that offset is
- * suitably aligned and that len is 1, 2 or 4.
- */
- cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */
- switch (len) {
- case 1:
- *val = in_8(cfg_data);
- break;
- case 2:
- *val = in_le16(cfg_data);
- break;
- default:
- *val = in_le32(cfg_data);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 val)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- volatile void __iomem *cfg_data;
- u8 cfg_type = 0;
- u32 bus_no, reg;
-
- if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
- if (bus->number != hose->first_busno)
- return PCIBIOS_DEVICE_NOT_FOUND;
- if (devfn != 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
- if (bus->number != hose->first_busno)
- cfg_type = 1;
-
- bus_no = (bus->number == hose->first_busno) ?
- hose->self_busno : bus->number;
-
- if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
- reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
- else
- reg = offset & 0xfc;
-
- if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
- out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
- (devfn << 8) | reg | cfg_type));
- else
- out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
- (devfn << 8) | reg | cfg_type));
-
- /* suppress setting of PCI_PRIMARY_BUS */
- if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
- if ((offset == PCI_PRIMARY_BUS) &&
- (bus->number == hose->first_busno))
- val &= 0xffffff00;
-
- /* Workaround for PCI_28 Errata in 440EPx/GRx */
- if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) &&
- offset == PCI_CACHE_LINE_SIZE) {
- val = 0;
- }
-
- /*
- * Note: the caller has already checked that offset is
- * suitably aligned and that len is 1, 2 or 4.
- */
- cfg_data = hose->cfg_data + (offset & 3);
- switch (len) {
- case 1:
- out_8(cfg_data, val);
- break;
- case 2:
- out_le16(cfg_data, val);
- break;
- default:
- out_le32(cfg_data, val);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops indirect_pci_ops = {
- .read = indirect_read_config,
- .write = indirect_write_config,
-};
-
-void __init
-setup_indirect_pci(struct pci_controller *hose,
- resource_size_t cfg_addr,
- resource_size_t cfg_data, u32 flags)
-{
- resource_size_t base = cfg_addr & PAGE_MASK;
- void __iomem *mbase;
-
- mbase = ioremap(base, PAGE_SIZE);
- hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
- if ((cfg_data & PAGE_MASK) != base)
- mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
- hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
- hose->ops = &indirect_pci_ops;
- hose->indirect_type = flags;
-}
diff --git a/arch/microblaze/pci/iomap.c b/arch/microblaze/pci/iomap.c
index bde74af4c1cd..b2ee8ace9b6e 100644
--- a/arch/microblaze/pci/iomap.c
+++ b/arch/microblaze/pci/iomap.c
@@ -11,6 +11,42 @@
#include <linux/io.h>
#include <asm/pci-bridge.h>
+static DEFINE_SPINLOCK(hose_spinlock);
+LIST_HEAD(hose_list);
+
+unsigned long isa_io_base;
+EXPORT_SYMBOL(isa_io_base);
+
+static resource_size_t pcibios_io_size(const struct pci_controller *hose)
+{
+ return resource_size(&hose->io_resource);
+}
+
+int pcibios_vaddr_is_ioport(void __iomem *address)
+{
+ int ret = 0;
+ struct pci_controller *hose;
+ resource_size_t size;
+
+ spin_lock(&hose_spinlock);
+ list_for_each_entry(hose, &hose_list, list_node) {
+ size = pcibios_io_size(hose);
+ if (address >= hose->io_base_virt &&
+ address < (hose->io_base_virt + size)) {
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&hose_spinlock);
+ return ret;
+}
+
+/* Display the domain number in /proc */
+int pci_proc_domain(struct pci_bus *bus)
+{
+ return pci_domain_nr(bus);
+}
+
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
if (isa_vaddr_is_ioport(addr))
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
deleted file mode 100644
index 33bab7eec731..000000000000
--- a/arch/microblaze/pci/pci-common.c
+++ /dev/null
@@ -1,1067 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Contains common pci routines for ALL ppc platform
- * (based on pci_32.c and pci_64.c)
- *
- * Port for PPC64 David Engebretsen, IBM Corp.
- * Contains common pci routines for ppc64 platform, pSeries and iSeries brands.
- *
- * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
- * Rework, based on alpha PCI code.
- *
- * Common pmac/prep/chrp pci routines. -- Cort
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/memblock.h>
-#include <linux/mm.h>
-#include <linux/shmem_fs.h>
-#include <linux/list.h>
-#include <linux/syscalls.h>
-#include <linux/irq.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_pci.h>
-#include <linux/export.h>
-
-#include <asm/processor.h>
-#include <linux/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/byteorder.h>
-
-static DEFINE_SPINLOCK(hose_spinlock);
-LIST_HEAD(hose_list);
-
-/* XXX kill that some day ... */
-static int global_phb_number; /* Global phb counter */
-
-/* ISA Memory physical address */
-resource_size_t isa_mem_base;
-
-unsigned long isa_io_base;
-EXPORT_SYMBOL(isa_io_base);
-
-static int pci_bus_count;
-
-struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
-{
- struct pci_controller *phb;
-
- phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
- if (!phb)
- return NULL;
- spin_lock(&hose_spinlock);
- phb->global_number = global_phb_number++;
- list_add_tail(&phb->list_node, &hose_list);
- spin_unlock(&hose_spinlock);
- phb->dn = dev;
- phb->is_dynamic = mem_init_done;
- return phb;
-}
-
-void pcibios_free_controller(struct pci_controller *phb)
-{
- spin_lock(&hose_spinlock);
- list_del(&phb->list_node);
- spin_unlock(&hose_spinlock);
-
- if (phb->is_dynamic)
- kfree(phb);
-}
-
-static resource_size_t pcibios_io_size(const struct pci_controller *hose)
-{
- return resource_size(&hose->io_resource);
-}
-
-int pcibios_vaddr_is_ioport(void __iomem *address)
-{
- int ret = 0;
- struct pci_controller *hose;
- resource_size_t size;
-
- spin_lock(&hose_spinlock);
- list_for_each_entry(hose, &hose_list, list_node) {
- size = pcibios_io_size(hose);
- if (address >= hose->io_base_virt &&
- address < (hose->io_base_virt + size)) {
- ret = 1;
- break;
- }
- }
- spin_unlock(&hose_spinlock);
- return ret;
-}
-
-unsigned long pci_address_to_pio(phys_addr_t address)
-{
- struct pci_controller *hose;
- resource_size_t size;
- unsigned long ret = ~0;
-
- spin_lock(&hose_spinlock);
- list_for_each_entry(hose, &hose_list, list_node) {
- size = pcibios_io_size(hose);
- if (address >= hose->io_base_phys &&
- address < (hose->io_base_phys + size)) {
- unsigned long base =
- (unsigned long)hose->io_base_virt - _IO_BASE;
- ret = base + (address - hose->io_base_phys);
- break;
- }
- }
- spin_unlock(&hose_spinlock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(pci_address_to_pio);
-
-/* This routine is meant to be used early during boot, when the
- * PCI bus numbers have not yet been assigned, and you need to
- * issue PCI config cycles to an OF device.
- * It could also be used to "fix" RTAS config cycles if you want
- * to set pci_assign_all_buses to 1 and still use RTAS for PCI
- * config cycles.
- */
-struct pci_controller *pci_find_hose_for_OF_device(struct device_node *node)
-{
- while (node) {
- struct pci_controller *hose, *tmp;
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- if (hose->dn == node)
- return hose;
- node = node->parent;
- }
- return NULL;
-}
-
-void pcibios_set_master(struct pci_dev *dev)
-{
- /* No special bus mastering setup handling */
-}
-
-/*
- * Platform support for /proc/bus/pci/X/Y mmap()s.
- */
-
-int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
-{
- struct pci_controller *hose = pci_bus_to_host(pdev->bus);
- resource_size_t ioaddr = pci_resource_start(pdev, bar);
-
- if (!hose)
- return -EINVAL; /* should never happen */
-
- /* Convert to an offset within this PCI controller */
- ioaddr -= (unsigned long)hose->io_base_virt - _IO_BASE;
-
- vma->vm_pgoff += (ioaddr + hose->io_base_phys) >> PAGE_SHIFT;
- return 0;
-}
-
-/* This provides legacy IO read access on a bus */
-int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
-{
- unsigned long offset;
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct resource *rp = &hose->io_resource;
- void __iomem *addr;
-
- /* Check if port can be supported by that bus. We only check
- * the ranges of the PHB though, not the bus itself as the rules
- * for forwarding legacy cycles down bridges are not our problem
- * here. So if the host bridge supports it, we do it.
- */
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- offset += port;
-
- if (!(rp->flags & IORESOURCE_IO))
- return -ENXIO;
- if (offset < rp->start || (offset + size) > rp->end)
- return -ENXIO;
- addr = hose->io_base_virt + port;
-
- switch (size) {
- case 1:
- *((u8 *)val) = in_8(addr);
- return 1;
- case 2:
- if (port & 1)
- return -EINVAL;
- *((u16 *)val) = in_le16(addr);
- return 2;
- case 4:
- if (port & 3)
- return -EINVAL;
- *((u32 *)val) = in_le32(addr);
- return 4;
- }
- return -EINVAL;
-}
-
-/* This provides legacy IO write access on a bus */
-int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
-{
- unsigned long offset;
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct resource *rp = &hose->io_resource;
- void __iomem *addr;
-
- /* Check if port can be supported by that bus. We only check
- * the ranges of the PHB though, not the bus itself as the rules
- * for forwarding legacy cycles down bridges are not our problem
- * here. So if the host bridge supports it, we do it.
- */
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- offset += port;
-
- if (!(rp->flags & IORESOURCE_IO))
- return -ENXIO;
- if (offset < rp->start || (offset + size) > rp->end)
- return -ENXIO;
- addr = hose->io_base_virt + port;
-
- /* WARNING: The generic code is idiotic. It gets passed a pointer
- * to what can be a 1, 2 or 4 byte quantity and always reads that
- * as a u32, which means that we have to correct the location of
- * the data read within those 32 bits for size 1 and 2
- */
- switch (size) {
- case 1:
- out_8(addr, val >> 24);
- return 1;
- case 2:
- if (port & 1)
- return -EINVAL;
- out_le16(addr, val >> 16);
- return 2;
- case 4:
- if (port & 3)
- return -EINVAL;
- out_le32(addr, val);
- return 4;
- }
- return -EINVAL;
-}
-
-/* This provides legacy IO or memory mmap access on a bus */
-int pci_mmap_legacy_page_range(struct pci_bus *bus,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- resource_size_t offset =
- ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
- resource_size_t size = vma->vm_end - vma->vm_start;
- struct resource *rp;
-
- pr_debug("pci_mmap_legacy_page_range(%04x:%02x, %s @%llx..%llx)\n",
- pci_domain_nr(bus), bus->number,
- mmap_state == pci_mmap_mem ? "MEM" : "IO",
- (unsigned long long)offset,
- (unsigned long long)(offset + size - 1));
-
- if (mmap_state == pci_mmap_mem) {
- /* Hack alert !
- *
- * Because X is lame and can fail starting if it gets an error
- * trying to mmap legacy_mem (instead of just moving on without
- * legacy memory access) we fake it here by giving it anonymous
- * memory, effectively behaving just like /dev/zero
- */
- if ((offset + size) > hose->isa_mem_size) {
- pr_debug("Process %s (pid:%d) mapped non-existing PCI",
- current->comm, current->pid);
- pr_debug("legacy memory for 0%04x:%02x\n",
- pci_domain_nr(bus), bus->number);
- if (vma->vm_flags & VM_SHARED)
- return shmem_zero_setup(vma);
- return 0;
- }
- offset += hose->isa_mem_phys;
- } else {
- unsigned long io_offset = (unsigned long)hose->io_base_virt -
- _IO_BASE;
- unsigned long roffset = offset + io_offset;
- rp = &hose->io_resource;
- if (!(rp->flags & IORESOURCE_IO))
- return -ENXIO;
- if (roffset < rp->start || (roffset + size) > rp->end)
- return -ENXIO;
- offset += hose->io_base_phys;
- }
- pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset);
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-}
-
-void pci_resource_to_user(const struct pci_dev *dev, int bar,
- const struct resource *rsrc,
- resource_size_t *start, resource_size_t *end)
-{
- struct pci_bus_region region;
-
- if (rsrc->flags & IORESOURCE_IO) {
- pcibios_resource_to_bus(dev->bus, &region,
- (struct resource *) rsrc);
- *start = region.start;
- *end = region.end;
- return;
- }
-
- /* We pass a CPU physical address to userland for MMIO instead of a
- * BAR value because X is lame and expects to be able to use that
- * to pass to /dev/mem!
- *
- * That means we may have 64-bit values where some apps only expect
- * 32 (like X itself since it thinks only Sparc has 64-bit MMIO).
- */
- *start = rsrc->start;
- *end = rsrc->end;
-}
-
-/**
- * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
- * @hose: newly allocated pci_controller to be setup
- * @dev: device node of the host bridge
- * @primary: set if primary bus (32 bits only, soon to be deprecated)
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping of a pci controller based on its
- * content.
- *
- * Life would be boring if it wasn't for a few issues that we have to deal
- * with here:
- *
- * - We can only cope with one IO space range and up to 3 Memory space
- * ranges. However, some machines (thanks Apple !) tend to split their
- * space into lots of small contiguous ranges. So we have to coalesce.
- *
- * - We can only cope with all memory ranges having the same offset
- * between CPU addresses and PCI addresses. Unfortunately, some bridges
- * are setup for a large 1:1 mapping along with a small "window" which
- * maps PCI address 0 to some arbitrary high address of the CPU space in
- * order to give access to the ISA memory hole.
- * The way out of here that I've chosen for now is to always set the
- * offset based on the first resource found, then override it if we
- * have a different offset and the previous was set by an ISA hole.
- *
- * - Some busses have IO space not starting at 0, which causes trouble with
- * the way we do our IO resource renumbering. The code somewhat deals with
- * it for 64 bits but I would expect problems on 32 bits.
- *
- * - Some 32 bits platforms such as 4xx can have physical space larger than
- * 32 bits so we need to use 64 bits values for the parsing
- */
-void pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev, int primary)
-{
- int memno = 0, isa_hole = -1;
- unsigned long long isa_mb = 0;
- struct resource *res;
- struct of_pci_range range;
- struct of_pci_range_parser parser;
-
- pr_info("PCI host bridge %pOF %s ranges:\n",
- dev, primary ? "(primary)" : "");
-
- /* Check for ranges property */
- if (of_pci_range_parser_init(&parser, dev))
- return;
-
- pr_debug("Parsing ranges property...\n");
- for_each_of_pci_range(&parser, &range) {
- /* Read next ranges element */
-
- /* If we failed translation or got a zero-sized region
- * (some FW try to feed us with non sensical zero sized regions
- * such as power3 which look like some kind of attempt
- * at exposing the VGA memory hole)
- */
- if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
- continue;
-
- /* Act based on address space type */
- res = NULL;
- switch (range.flags & IORESOURCE_TYPE_BITS) {
- case IORESOURCE_IO:
- pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
- range.cpu_addr, range.cpu_addr + range.size - 1,
- range.pci_addr);
-
- /* We support only one IO range */
- if (hose->pci_io_size) {
- pr_info(" \\--> Skipped (too many) !\n");
- continue;
- }
- /* On 32 bits, limit I/O space to 16MB */
- if (range.size > 0x01000000)
- range.size = 0x01000000;
-
- /* 32 bits needs to map IOs here */
- hose->io_base_virt = ioremap(range.cpu_addr,
- range.size);
-
- /* Expect trouble if pci_addr is not 0 */
- if (primary)
- isa_io_base =
- (unsigned long)hose->io_base_virt;
- /* pci_io_size and io_base_phys always represent IO
- * space starting at 0 so we factor in pci_addr
- */
- hose->pci_io_size = range.pci_addr + range.size;
- hose->io_base_phys = range.cpu_addr - range.pci_addr;
-
- /* Build resource */
- res = &hose->io_resource;
- range.cpu_addr = range.pci_addr;
-
- break;
- case IORESOURCE_MEM:
- pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
- range.cpu_addr, range.cpu_addr + range.size - 1,
- range.pci_addr,
- (range.flags & IORESOURCE_PREFETCH) ?
- "Prefetch" : "");
-
- /* We support only 3 memory ranges */
- if (memno >= 3) {
- pr_info(" \\--> Skipped (too many) !\n");
- continue;
- }
- /* Handles ISA memory hole space here */
- if (range.pci_addr == 0) {
- isa_mb = range.cpu_addr;
- isa_hole = memno;
- if (primary || isa_mem_base == 0)
- isa_mem_base = range.cpu_addr;
- hose->isa_mem_phys = range.cpu_addr;
- hose->isa_mem_size = range.size;
- }
-
- /* We get the PCI/Mem offset from the first range or
- * the, current one if the offset came from an ISA
- * hole. If they don't match, bugger.
- */
- if (memno == 0 ||
- (isa_hole >= 0 && range.pci_addr != 0 &&
- hose->pci_mem_offset == isa_mb))
- hose->pci_mem_offset = range.cpu_addr -
- range.pci_addr;
- else if (range.pci_addr != 0 &&
- hose->pci_mem_offset != range.cpu_addr -
- range.pci_addr) {
- pr_info(" \\--> Skipped (offset mismatch) !\n");
- continue;
- }
-
- /* Build resource */
- res = &hose->mem_resources[memno++];
- break;
- }
- if (res != NULL) {
- res->name = dev->full_name;
- res->flags = range.flags;
- res->start = range.cpu_addr;
- res->end = range.cpu_addr + range.size - 1;
- res->parent = res->child = res->sibling = NULL;
- }
- }
-
- /* If there's an ISA hole and the pci_mem_offset is -not- matching
- * the ISA hole offset, then we need to remove the ISA hole from
- * the resource list for that brige
- */
- if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
- unsigned int next = isa_hole + 1;
- pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
- if (next < memno)
- memmove(&hose->mem_resources[isa_hole],
- &hose->mem_resources[next],
- sizeof(struct resource) * (memno - next));
- hose->mem_resources[--memno].flags = 0;
- }
-}
-
-/* Display the domain number in /proc */
-int pci_proc_domain(struct pci_bus *bus)
-{
- return pci_domain_nr(bus);
-}
-
-/* This header fixup will do the resource fixup for all devices as they are
- * probed, but not for bridge ranges
- */
-static void pcibios_fixup_resources(struct pci_dev *dev)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- int i;
-
- if (!hose) {
- pr_err("No host bridge for PCI dev %s !\n",
- pci_name(dev));
- return;
- }
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- struct resource *res = dev->resource + i;
- if (!res->flags)
- continue;
- if (res->start == 0) {
- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]",
- pci_name(dev), i,
- (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned int)res->flags);
- pr_debug("is unassigned\n");
- res->end -= res->start;
- res->start = 0;
- res->flags |= IORESOURCE_UNSET;
- continue;
- }
-
- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
- pci_name(dev), i,
- (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned int)res->flags);
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
-
-int pcibios_device_add(struct pci_dev *dev)
-{
- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
-
- return 0;
-}
-
-/*
- * Reparent resource children of pr that conflict with res
- * under res, and make res replace those children.
- */
-static int __init reparent_resources(struct resource *parent,
- struct resource *res)
-{
- struct resource *p, **pp;
- struct resource **firstpp = NULL;
-
- for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
- if (p->end < res->start)
- continue;
- if (res->end < p->start)
- break;
- if (p->start < res->start || p->end > res->end)
- return -1; /* not completely contained */
- if (firstpp == NULL)
- firstpp = pp;
- }
- if (firstpp == NULL)
- return -1; /* didn't find any conflicting entries? */
- res->parent = parent;
- res->child = *firstpp;
- res->sibling = *pp;
- *firstpp = res;
- *pp = NULL;
- for (p = res->child; p != NULL; p = p->sibling) {
- p->parent = res;
- pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n",
- p->name,
- (unsigned long long)p->start,
- (unsigned long long)p->end, res->name);
- }
- return 0;
-}
-
-/*
- * Handle resources of PCI devices. If the world were perfect, we could
- * just allocate all the resource regions and do nothing more. It isn't.
- * On the other hand, we cannot just re-allocate all devices, as it would
- * require us to know lots of host bridge internals. So we attempt to
- * keep as much of the original configuration as possible, but tweak it
- * when it's found to be wrong.
- *
- * Known BIOS problems we have to work around:
- * - I/O or memory regions not configured
- * - regions configured, but not enabled in the command register
- * - bogus I/O addresses above 64K used
- * - expansion ROMs left enabled (this may sound harmless, but given
- * the fact the PCI specs explicitly allow address decoders to be
- * shared between expansion ROMs and other resource regions, it's
- * at least dangerous)
- *
- * Our solution:
- * (1) Allocate resources for all buses behind PCI-to-PCI bridges.
- * This gives us fixed barriers on where we can allocate.
- * (2) Allocate resources for all enabled devices. If there is
- * a collision, just mark the resource as unallocated. Also
- * disable expansion ROMs during this step.
- * (3) Try to allocate resources for disabled devices. If the
- * resources were assigned correctly, everything goes well,
- * if they weren't, they won't disturb allocation of other
- * resources.
- * (4) Assign new addresses to resources which were either
- * not configured at all or misconfigured. If explicitly
- * requested by the user, configure expansion ROM address
- * as well.
- */
-
-static void pcibios_allocate_bus_resources(struct pci_bus *bus)
-{
- struct pci_bus *b;
- int i;
- struct resource *res, *pr;
-
- pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
- pci_domain_nr(bus), bus->number);
-
- pci_bus_for_each_resource(bus, res, i) {
- if (!res || !res->flags
- || res->start > res->end || res->parent)
- continue;
- if (bus->parent == NULL)
- pr = (res->flags & IORESOURCE_IO) ?
- &ioport_resource : &iomem_resource;
- else {
- /* Don't bother with non-root busses when
- * re-assigning all resources. We clear the
- * resource flags as if they were colliding
- * and as such ensure proper re-allocation
- * later.
- */
- pr = pci_find_parent_resource(bus->self, res);
- if (pr == res) {
- /* this happens when the generic PCI
- * code (wrongly) decides that this
- * bridge is transparent -- paulus
- */
- continue;
- }
- }
-
- pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx ",
- bus->self ? pci_name(bus->self) : "PHB",
- bus->number, i,
- (unsigned long long)res->start,
- (unsigned long long)res->end);
- pr_debug("[0x%x], parent %p (%s)\n",
- (unsigned int)res->flags,
- pr, (pr && pr->name) ? pr->name : "nil");
-
- if (pr && !(pr->flags & IORESOURCE_UNSET)) {
- struct pci_dev *dev = bus->self;
-
- if (request_resource(pr, res) == 0)
- continue;
- /*
- * Must be a conflict with an existing entry.
- * Move that entry (or entries) under the
- * bridge resource and try again.
- */
- if (reparent_resources(pr, res) == 0)
- continue;
-
- if (dev && i < PCI_BRIDGE_RESOURCE_NUM &&
- pci_claim_bridge_resource(dev,
- i + PCI_BRIDGE_RESOURCES) == 0)
- continue;
-
- }
- pr_warn("PCI: Cannot allocate resource region ");
- pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number);
- res->start = res->end = 0;
- res->flags = 0;
- }
-
- list_for_each_entry(b, &bus->children, node)
- pcibios_allocate_bus_resources(b);
-}
-
-static inline void alloc_resource(struct pci_dev *dev, int idx)
-{
- struct resource *pr, *r = &dev->resource[idx];
-
- pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
- pci_name(dev), idx,
- (unsigned long long)r->start,
- (unsigned long long)r->end,
- (unsigned int)r->flags);
-
- pr = pci_find_parent_resource(dev, r);
- if (!pr || (pr->flags & IORESOURCE_UNSET) ||
- request_resource(pr, r) < 0) {
- pr_warn("PCI: Cannot allocate resource region %d ", idx);
- pr_cont("of device %s, will remap\n", pci_name(dev));
- if (pr)
- pr_debug("PCI: parent is %p: %016llx-%016llx [%x]\n",
- pr,
- (unsigned long long)pr->start,
- (unsigned long long)pr->end,
- (unsigned int)pr->flags);
- /* We'll assign a new address later */
- r->flags |= IORESOURCE_UNSET;
- r->end -= r->start;
- r->start = 0;
- }
-}
-
-static void __init pcibios_allocate_resources(int pass)
-{
- struct pci_dev *dev = NULL;
- int idx, disabled;
- u16 command;
- struct resource *r;
-
- for_each_pci_dev(dev) {
- pci_read_config_word(dev, PCI_COMMAND, &command);
- for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
- r = &dev->resource[idx];
- if (r->parent) /* Already allocated */
- continue;
- if (!r->flags || (r->flags & IORESOURCE_UNSET))
- continue; /* Not assigned at all */
- /* We only allocate ROMs on pass 1 just in case they
- * have been screwed up by firmware
- */
- if (idx == PCI_ROM_RESOURCE)
- disabled = 1;
- if (r->flags & IORESOURCE_IO)
- disabled = !(command & PCI_COMMAND_IO);
- else
- disabled = !(command & PCI_COMMAND_MEMORY);
- if (pass == disabled)
- alloc_resource(dev, idx);
- }
- if (pass)
- continue;
- r = &dev->resource[PCI_ROM_RESOURCE];
- if (r->flags) {
- /* Turn the ROM off, leave the resource region,
- * but keep it unregistered.
- */
- u32 reg;
- pci_read_config_dword(dev, dev->rom_base_reg, &reg);
- if (reg & PCI_ROM_ADDRESS_ENABLE) {
- pr_debug("PCI: Switching off ROM of %s\n",
- pci_name(dev));
- r->flags &= ~IORESOURCE_ROM_ENABLE;
- pci_write_config_dword(dev, dev->rom_base_reg,
- reg & ~PCI_ROM_ADDRESS_ENABLE);
- }
- }
- }
-}
-
-static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- resource_size_t offset;
- struct resource *res, *pres;
- int i;
-
- pr_debug("Reserving legacy ranges for domain %04x\n",
- pci_domain_nr(bus));
-
- /* Check for IO */
- if (!(hose->io_resource.flags & IORESOURCE_IO))
- goto no_io;
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
- BUG_ON(res == NULL);
- res->name = "Legacy IO";
- res->flags = IORESOURCE_IO;
- res->start = offset;
- res->end = (offset + 0xfff) & 0xfffffffful;
- pr_debug("Candidate legacy IO: %pR\n", res);
- if (request_resource(&hose->io_resource, res)) {
- pr_debug("PCI %04x:%02x Cannot reserve Legacy IO %pR\n",
- pci_domain_nr(bus), bus->number, res);
- kfree(res);
- }
-
- no_io:
- /* Check for memory */
- offset = hose->pci_mem_offset;
- pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
- for (i = 0; i < 3; i++) {
- pres = &hose->mem_resources[i];
- if (!(pres->flags & IORESOURCE_MEM))
- continue;
- pr_debug("hose mem res: %pR\n", pres);
- if ((pres->start - offset) <= 0xa0000 &&
- (pres->end - offset) >= 0xbffff)
- break;
- }
- if (i >= 3)
- return;
- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
- BUG_ON(res == NULL);
- res->name = "Legacy VGA memory";
- res->flags = IORESOURCE_MEM;
- res->start = 0xa0000 + offset;
- res->end = 0xbffff + offset;
- pr_debug("Candidate VGA memory: %pR\n", res);
- if (request_resource(pres, res)) {
- pr_debug("PCI %04x:%02x Cannot reserve VGA memory %pR\n",
- pci_domain_nr(bus), bus->number, res);
- kfree(res);
- }
-}
-
-void __init pcibios_resource_survey(void)
-{
- struct pci_bus *b;
-
- /* Allocate and assign resources. If we re-assign everything, then
- * we skip the allocate phase
- */
- list_for_each_entry(b, &pci_root_buses, node)
- pcibios_allocate_bus_resources(b);
-
- pcibios_allocate_resources(0);
- pcibios_allocate_resources(1);
-
- /* Before we start assigning unassigned resource, we try to reserve
- * the low IO area and the VGA memory area if they intersect the
- * bus available resources to avoid allocating things on top of them
- */
- list_for_each_entry(b, &pci_root_buses, node)
- pcibios_reserve_legacy_regions(b);
-
- /* Now proceed to assigning things that were left unassigned */
- pr_debug("PCI: Assigning unassigned resources...\n");
- pci_assign_unassigned_resources();
-}
-
-static void pcibios_setup_phb_resources(struct pci_controller *hose,
- struct list_head *resources)
-{
- unsigned long io_offset;
- struct resource *res;
- int i;
-
- /* Hookup PHB IO resource */
- res = &hose->io_resource;
-
- /* Fixup IO space offset */
- io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
- res->start = (res->start + io_offset) & 0xffffffffu;
- res->end = (res->end + io_offset) & 0xffffffffu;
-
- if (!res->flags) {
- pr_warn("PCI: I/O resource not set for host ");
- pr_cont("bridge %pOF (domain %d)\n",
- hose->dn, hose->global_number);
- /* Workaround for lack of IO resource only on 32-bit */
- res->start = (unsigned long)hose->io_base_virt - isa_io_base;
- res->end = res->start + IO_SPACE_LIMIT;
- res->flags = IORESOURCE_IO;
- }
- pci_add_resource_offset(resources, res,
- (__force resource_size_t)(hose->io_base_virt - _IO_BASE));
-
- pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
- (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned long)res->flags);
-
- /* Hookup PHB Memory resources */
- for (i = 0; i < 3; ++i) {
- res = &hose->mem_resources[i];
- if (!res->flags) {
- if (i > 0)
- continue;
- pr_err("PCI: Memory resource 0 not set for ");
- pr_cont("host bridge %pOF (domain %d)\n",
- hose->dn, hose->global_number);
-
- /* Workaround for lack of MEM resource only on 32-bit */
- res->start = hose->pci_mem_offset;
- res->end = (resource_size_t)-1LL;
- res->flags = IORESOURCE_MEM;
-
- }
- pci_add_resource_offset(resources, res, hose->pci_mem_offset);
-
- pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
- i, (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned long)res->flags);
- }
-
- pr_debug("PCI: PHB MEM offset = %016llx\n",
- (unsigned long long)hose->pci_mem_offset);
- pr_debug("PCI: PHB IO offset = %08lx\n",
- (unsigned long)hose->io_base_virt - _IO_BASE);
-}
-
-static void pcibios_scan_phb(struct pci_controller *hose)
-{
- LIST_HEAD(resources);
- struct pci_bus *bus;
- struct device_node *node = hose->dn;
-
- pr_debug("PCI: Scanning PHB %pOF\n", node);
-
- pcibios_setup_phb_resources(hose, &resources);
-
- bus = pci_scan_root_bus(hose->parent, hose->first_busno,
- hose->ops, hose, &resources);
- if (bus == NULL) {
- pr_err("Failed to create bus for PCI domain %04x\n",
- hose->global_number);
- pci_free_resource_list(&resources);
- return;
- }
- bus->busn_res.start = hose->first_busno;
- hose->bus = bus;
-
- hose->last_busno = bus->busn_res.end;
-}
-
-static int __init pcibios_init(void)
-{
- struct pci_controller *hose, *tmp;
- int next_busno = 0;
-
- pr_info("PCI: Probing PCI hardware\n");
-
- /* Scan all of the recorded PCI controllers. */
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- hose->last_busno = 0xff;
- pcibios_scan_phb(hose);
- if (next_busno <= hose->last_busno)
- next_busno = hose->last_busno + 1;
- }
- pci_bus_count = next_busno;
-
- /* Call common code to handle resource allocation */
- pcibios_resource_survey();
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- if (hose->bus)
- pci_bus_add_devices(hose->bus);
- }
-
- return 0;
-}
-
-subsys_initcall(pcibios_init);
-
-static struct pci_controller *pci_bus_to_hose(int bus)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- if (bus >= hose->first_busno && bus <= hose->last_busno)
- return hose;
- return NULL;
-}
-
-/* Provide information on locations of various I/O regions in physical
- * memory. Do this on a per-card basis so that we choose the right
- * root bridge.
- * Note that the returned IO or memory base is a physical address
- */
-
-long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
-{
- struct pci_controller *hose;
- long result = -EOPNOTSUPP;
-
- hose = pci_bus_to_hose(bus);
- if (!hose)
- return -ENODEV;
-
- switch (which) {
- case IOBASE_BRIDGE_NUMBER:
- return (long)hose->first_busno;
- case IOBASE_MEMORY:
- return (long)hose->pci_mem_offset;
- case IOBASE_IO:
- return (long)hose->io_base_phys;
- case IOBASE_ISA_IO:
- return (long)isa_io_base;
- case IOBASE_ISA_MEM:
- return (long)isa_mem_base;
- }
-
- return result;
-}
-
-/*
- * Null PCI config access functions, for the case when we can't
- * find a hose.
- */
-#define NULL_PCI_OP(rw, size, type) \
-static int \
-null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \
-{ \
- return PCIBIOS_DEVICE_NOT_FOUND; \
-}
-
-static int
-null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 *val)
-{
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static int
-null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 val)
-{
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static struct pci_ops null_pci_ops = {
- .read = null_read_config,
- .write = null_write_config,
-};
-
-/*
- * These functions are used early on before PCI scanning is done
- * and all of the pci_dev and pci_bus structures have been created.
- */
-static struct pci_bus *
-fake_pci_bus(struct pci_controller *hose, int busnr)
-{
- static struct pci_bus bus;
-
- if (!hose)
- pr_err("Can't find hose for PCI bus %d!\n", busnr);
-
- bus.number = busnr;
- bus.sysdata = hose;
- bus.ops = hose ? hose->ops : &null_pci_ops;
- return &bus;
-}
-
-#define EARLY_PCI_OP(rw, size, type) \
-int early_##rw##_config_##size(struct pci_controller *hose, int bus, \
- int devfn, int offset, type value) \
-{ \
- return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus), \
- devfn, offset, value); \
-}
-
-EARLY_PCI_OP(read, byte, u8 *)
-EARLY_PCI_OP(read, word, u16 *)
-EARLY_PCI_OP(read, dword, u32 *)
-EARLY_PCI_OP(write, byte, u8)
-EARLY_PCI_OP(write, word, u16)
-EARLY_PCI_OP(write, dword, u32)
-
-int early_find_capability(struct pci_controller *hose, int bus, int devfn,
- int cap)
-{
- return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
-}
diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c
deleted file mode 100644
index f4cb86fffcee..000000000000
--- a/arch/microblaze/pci/xilinx_pci.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * PCI support for Xilinx plbv46_pci soft-core which can be used on
- * Xilinx Virtex ML410 / ML510 boards.
- *
- * Copyright 2009 Roderick Colenbrander
- * Copyright 2009 Secret Lab Technologies Ltd.
- *
- * The pci bridge fixup code was copied from ppc4xx_pci.c and was written
- * by Benjamin Herrenschmidt.
- * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM 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.
- */
-
-#include <linux/ioport.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-
-#define XPLB_PCI_ADDR 0x10c
-#define XPLB_PCI_DATA 0x110
-#define XPLB_PCI_BUS 0x114
-
-#define PCI_HOST_ENABLE_CMD (PCI_COMMAND_SERR | PCI_COMMAND_PARITY | \
- PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)
-
-static const struct of_device_id xilinx_pci_match[] = {
- { .compatible = "xlnx,plbv46-pci-1.03.a", },
- {}
-};
-
-/**
- * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration.
- */
-static void xilinx_pci_fixup_bridge(struct pci_dev *dev)
-{
- struct pci_controller *hose;
- int i;
-
- if (dev->devfn || dev->bus->self)
- return;
-
- hose = pci_bus_to_host(dev->bus);
- if (!hose)
- return;
-
- if (!of_match_node(xilinx_pci_match, hose->dn))
- return;
-
- /* Hide the PCI host BARs from the kernel as their content doesn't
- * fit well in the resource management
- */
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- dev->resource[i].flags = 0;
- }
-
- dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n",
- pci_name(dev));
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge);
-
-#ifdef DEBUG
-/**
- * xilinx_pci_exclude_device - Don't do config access for non-root bus
- *
- * This is a hack. Config access to any bus other than bus 0 does not
- * currently work on the ML510 so we prevent it here.
- */
-static int
-xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn)
-{
- return (bus != 0);
-}
-
-/**
- * xilinx_early_pci_scan - List pci config space for available devices
- *
- * List pci devices in very early phase.
- */
-static void __init xilinx_early_pci_scan(struct pci_controller *hose)
-{
- u32 bus = 0;
- u32 val, dev, func, offset;
-
- /* Currently we have only 2 device connected - up-to 32 devices */
- for (dev = 0; dev < 2; dev++) {
- /* List only first function number - up-to 8 functions */
- for (func = 0; func < 1; func++) {
- pr_info("%02x:%02x:%02x", bus, dev, func);
- /* read the first 64 standardized bytes */
- /* Up-to 192 bytes can be list of capabilities */
- for (offset = 0; offset < 64; offset += 4) {
- early_read_config_dword(hose, bus,
- PCI_DEVFN(dev, func), offset, &val);
- if (offset == 0 && val == 0xFFFFFFFF) {
- pr_cont("\nABSENT");
- break;
- }
- if (!(offset % 0x10))
- pr_cont("\n%04x: ", offset);
-
- pr_cont("%08x ", val);
- }
- pr_info("\n");
- }
- }
-}
-#else
-static void __init xilinx_early_pci_scan(struct pci_controller *hose)
-{
-}
-#endif
-
-/**
- * xilinx_pci_init - Find and register a Xilinx PCI host bridge
- */
-void __init xilinx_pci_init(void)
-{
- struct pci_controller *hose;
- struct resource r;
- void __iomem *pci_reg;
- struct device_node *pci_node;
-
- pci_node = of_find_matching_node(NULL, xilinx_pci_match);
- if (!pci_node)
- return;
-
- if (of_address_to_resource(pci_node, 0, &r)) {
- pr_err("xilinx-pci: cannot resolve base address\n");
- return;
- }
-
- hose = pcibios_alloc_controller(pci_node);
- if (!hose) {
- pr_err("xilinx-pci: pcibios_alloc_controller() failed\n");
- return;
- }
-
- /* Setup config space */
- setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR,
- r.start + XPLB_PCI_DATA,
- INDIRECT_TYPE_SET_CFG_TYPE);
-
- /* According to the xilinx plbv46_pci documentation the soft-core starts
- * a self-init when the bus master enable bit is set. Without this bit
- * set the pci bus can't be scanned.
- */
- early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD);
-
- /* Set the max latency timer to 255 */
- early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff);
-
- /* Set the max bus number to 255, and bus/subbus no's to 0 */
- pci_reg = of_iomap(pci_node, 0);
- WARN_ON(!pci_reg);
- out_be32(pci_reg + XPLB_PCI_BUS, 0x000000ff);
- iounmap(pci_reg);
-
- /* Register the host bridge with the linux kernel! */
- pci_process_bridge_OF_ranges(hose, pci_node,
- INDIRECT_TYPE_SET_CFG_TYPE);
-
- pr_info("xilinx-pci: Registered PCI host bridge\n");
- xilinx_early_pci_scan(hose);
-}
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index b296e33f8e33..490dea07d4e0 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -318,7 +318,7 @@ KBUILD_LDFLAGS += -m $(ld-emul)
ifdef CONFIG_MIPS
CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
- egrep -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \
+ grep -E -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \
sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g')
endif
diff --git a/arch/mips/alchemy/common/gpiolib.c b/arch/mips/alchemy/common/gpiolib.c
index a17d7a8909c4..1b16daaa86ae 100644
--- a/arch/mips/alchemy/common/gpiolib.c
+++ b/arch/mips/alchemy/common/gpiolib.c
@@ -31,7 +31,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <asm/mach-au1x00/gpio-au1000.h>
#include <asm/mach-au1x00/gpio-au1300.h>
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
index 6e6756e8fa0a..86a6e2590866 100644
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -361,6 +361,8 @@ static struct clk clk_periph = {
*/
int clk_enable(struct clk *clk)
{
+ if (!clk)
+ return 0;
mutex_lock(&clocks_mutex);
clk_enable_unlocked(clk);
mutex_unlock(&clocks_mutex);
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
index 5b38a802e101..c5dd415254d3 100644
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -9,6 +9,7 @@
#define DISABLE_BRANCH_PROFILING
+#define __NO_FORTIFY
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/arch/mips/boot/dts/brcm/bcm63268.dtsi b/arch/mips/boot/dts/brcm/bcm63268.dtsi
index 8926417a8fbc..c663efce91cf 100644
--- a/arch/mips/boot/dts/brcm/bcm63268.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm63268.dtsi
@@ -110,6 +110,11 @@
reg = <0x10000080 0x30>;
ranges = <0x0 0x10000080 0x30>;
+ timer@0 {
+ compatible = "brcm,bcm6345-timer";
+ reg = <0x0 0x1c>;
+ };
+
wdt: watchdog@1c {
compatible = "brcm,bcm7038-wdt";
reg = <0x1c 0xc>;
diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi
index 8c001b944c8b..cfdf9804e126 100644
--- a/arch/mips/boot/dts/brcm/bcm7435.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi
@@ -422,6 +422,7 @@
reg = <0x41c800 0x600>, <0x41d000 0x100>;
interrupt-parent = <&hif_l2_intc>;
interrupts = <24>, <4>;
+ interrupt-names = "nand_ctlrdy", "flash_dma_done";
status = "disabled";
};
diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 37c46720c719..f38c39572a9e 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -438,7 +438,7 @@
ingenic,nemc-tAW = <50>;
ingenic,nemc-tSTRV = <100>;
- reset-gpios = <&gpf 12 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpf 12 GPIO_ACTIVE_LOW>;
vcc-supply = <&eth0_power>;
interrupt-parent = <&gpe>;
diff --git a/arch/mips/boot/dts/mscc/jaguar2_pcb110.dts b/arch/mips/boot/dts/mscc/jaguar2_pcb110.dts
index 0ea7bc5b5746..1813f4e32e55 100644
--- a/arch/mips/boot/dts/mscc/jaguar2_pcb110.dts
+++ b/arch/mips/boot/dts/mscc/jaguar2_pcb110.dts
@@ -208,7 +208,7 @@
};
&i2c0 {
- pca9545@70 {
+ i2c-mux@70 {
compatible = "nxp,pca9545";
reg = <0x70>;
#address-cells = <1>;
@@ -236,7 +236,7 @@
reg = <3>;
};
};
- pca9545@71 {
+ i2c-mux@71 {
compatible = "nxp,pca9545";
reg = <0x71>;
#address-cells = <1>;
diff --git a/arch/mips/boot/dts/qca/ar9331.dtsi b/arch/mips/boot/dts/qca/ar9331.dtsi
index c4102b280b47..768ac0f869b1 100644
--- a/arch/mips/boot/dts/qca/ar9331.dtsi
+++ b/arch/mips/boot/dts/qca/ar9331.dtsi
@@ -176,7 +176,6 @@
switch_port0: port@0 {
reg = <0x0>;
- label = "cpu";
ethernet = <&eth1>;
phy-mode = "gmii";
diff --git a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts
index 7515555388ae..e31417569e09 100644
--- a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts
+++ b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts
@@ -113,13 +113,13 @@
&gmac1 {
status = "okay";
+ phy-mode = "rgmii-rxid";
phy-handle = <&ethphy5>;
};
&mdio {
ethphy5: ethernet-phy@5 {
reg = <5>;
- phy-mode = "rgmii-rxid";
};
};
diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi
index f3f4c1f26e01..aec85c779359 100644
--- a/arch/mips/boot/dts/ralink/mt7621.dtsi
+++ b/arch/mips/boot/dts/ralink/mt7621.dtsi
@@ -357,36 +357,35 @@
port@0 {
status = "disabled";
reg = <0>;
- label = "lan0";
+ label = "swp0";
};
port@1 {
status = "disabled";
reg = <1>;
- label = "lan1";
+ label = "swp1";
};
port@2 {
status = "disabled";
reg = <2>;
- label = "lan2";
+ label = "swp2";
};
port@3 {
status = "disabled";
reg = <3>;
- label = "lan3";
+ label = "swp3";
};
port@4 {
status = "disabled";
reg = <4>;
- label = "lan4";
+ label = "swp4";
};
port@6 {
reg = <6>;
- label = "cpu";
ethernet = <&gmac0>;
phy-mode = "trgmii";
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
index 306cee07ce3f..334bf8e577e5 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
@@ -780,9 +780,8 @@ int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr,
if (addr_allocated >= 0) {
named_block_desc_ptr->base_addr = addr_allocated;
named_block_desc_ptr->size = size;
- strncpy(named_block_desc_ptr->name, name,
+ strscpy(named_block_desc_ptr->name, name,
cvmx_bootmem_desc->named_block_name_len);
- named_block_desc_ptr->name[cvmx_bootmem_desc->named_block_name_len - 1] = 0;
}
if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
index d09d0769f549..0fd9ac76eb74 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
@@ -211,7 +211,7 @@ union cvmx_helper_link_info __cvmx_helper_board_link_get(int ipd_port)
{
union cvmx_helper_link_info result;
- WARN(!octeon_is_simulation(),
+ WARN_ONCE(!octeon_is_simulation(),
"Using deprecated link status - please update your DT");
/* Unless we fix it later, all links are defaulted to down */
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c
index 6f49fd9be1f3..9abfc4bf9bd8 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-helper.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -1096,7 +1096,7 @@ union cvmx_helper_link_info cvmx_helper_link_get(int ipd_port)
if (index == 0)
result = __cvmx_helper_rgmii_link_get(ipd_port);
else {
- WARN(1, "Using deprecated link status - please update your DT");
+ WARN_ONCE(1, "Using deprecated link status - please update your DT");
result.s.full_duplex = 1;
result.s.link_up = 1;
result.s.speed = 1000;
diff --git a/arch/mips/include/asm/asm-prototypes.h b/arch/mips/include/asm/asm-prototypes.h
index f901ed043c71..8e8fc38b0941 100644
--- a/arch/mips/include/asm/asm-prototypes.h
+++ b/arch/mips/include/asm/asm-prototypes.h
@@ -6,3 +6,6 @@
#include <linux/uaccess.h>
#include <asm/ftrace.h>
#include <asm/mmu_context.h>
+
+extern void clear_page_cpu(void *page);
+extern void copy_page_cpu(void *to, void *from);
diff --git a/arch/mips/include/asm/fw/fw.h b/arch/mips/include/asm/fw/fw.h
index d0ef8b4892bb..d0494ce4b337 100644
--- a/arch/mips/include/asm/fw/fw.h
+++ b/arch/mips/include/asm/fw/fw.h
@@ -26,6 +26,6 @@ extern char *fw_getcmdline(void);
extern void fw_meminit(void);
extern char *fw_getenv(char *name);
extern unsigned long fw_getenvl(char *name);
-extern void fw_init_early_console(char port);
+extern void fw_init_early_console(void);
#endif /* __ASM_FW_H_ */
diff --git a/arch/mips/include/asm/mach-ralink/mt7621.h b/arch/mips/include/asm/mach-ralink/mt7621.h
index 6bbf082dd149..79d5bb0e06d6 100644
--- a/arch/mips/include/asm/mach-ralink/mt7621.h
+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
@@ -7,10 +7,12 @@
#ifndef _MT7621_REGS_H_
#define _MT7621_REGS_H_
+#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x)))
+
#define MT7621_PALMBUS_BASE 0x1C000000
#define MT7621_PALMBUS_SIZE 0x03FFFFFF
-#define MT7621_SYSC_BASE 0x1E000000
+#define MT7621_SYSC_BASE IOMEM(0x1E000000)
#define SYSC_REG_CHIP_NAME0 0x00
#define SYSC_REG_CHIP_NAME1 0x04
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 6caec386ad2f..4678627673df 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -622,6 +622,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
return pmd;
}
+#define pmd_young pmd_young
static inline int pmd_young(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_ACCESSED);
diff --git a/arch/mips/include/asm/stackprotector.h b/arch/mips/include/asm/stackprotector.h
index 68d4be9e1254..518c192ad982 100644
--- a/arch/mips/include/asm/stackprotector.h
+++ b/arch/mips/include/asm/stackprotector.h
@@ -15,9 +15,6 @@
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H 1
-#include <linux/random.h>
-#include <linux/version.h>
-
extern unsigned long __stack_chk_guard;
/*
@@ -28,11 +25,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c
index 71a882c8c6eb..f7978d50a2ba 100644
--- a/arch/mips/kernel/jump_label.c
+++ b/arch/mips/kernel/jump_label.c
@@ -56,7 +56,7 @@ void arch_jump_label_transform(struct jump_entry *e,
* The branch offset must fit in the instruction's 26
* bit field.
*/
- WARN_ON((offset >= BIT(25)) ||
+ WARN_ON((offset >= (long)BIT(25)) ||
(offset < -(long)BIT(25)));
insn.j_format.opcode = bc6_op;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index bbe9ce471791..093dbbd6b843 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -711,7 +711,7 @@ unsigned long mips_stack_top(void)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(PAGE_SIZE);
+ sp -= get_random_u32_below(PAGE_SIZE);
return sp & ALMASK;
}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 567aec4abac0..d9df543f7e2c 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -531,10 +531,11 @@ static int fpr_set(struct task_struct *target,
ptrace_setfcr31(target, fcr31);
}
- if (count > 0)
- err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- fir_pos,
- fir_pos + sizeof(u32));
+ if (count > 0) {
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ fir_pos, fir_pos + sizeof(u32));
+ return 0;
+ }
return err;
}
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
index cfde14b48fd8..f5b2ef979b43 100644
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -145,8 +145,7 @@ LEAF(kexec_smp_wait)
* kexec_args[0..3] are used to prepare register values.
*/
-kexec_args:
- EXPORT(kexec_args)
+EXPORT(kexec_args)
arg0: PTR_WD 0x0
arg1: PTR_WD 0x0
arg2: PTR_WD 0x0
@@ -159,8 +158,7 @@ arg3: PTR_WD 0x0
* their registers a0-a3. secondary_kexec_args[0..3] are used
* to prepare register values.
*/
-secondary_kexec_args:
- EXPORT(secondary_kexec_args)
+EXPORT(secondary_kexec_args)
s_arg0: PTR_WD 0x0
s_arg1: PTR_WD 0x0
s_arg2: PTR_WD 0x0
@@ -171,19 +169,16 @@ kexec_flag:
#endif
-kexec_start_address:
- EXPORT(kexec_start_address)
+EXPORT(kexec_start_address)
PTR_WD 0x0
.size kexec_start_address, PTRSIZE
-kexec_indirection_page:
- EXPORT(kexec_indirection_page)
+EXPORT(kexec_indirection_page)
PTR_WD 0
.size kexec_indirection_page, PTRSIZE
relocate_new_kernel_end:
-relocate_new_kernel_size:
- EXPORT(relocate_new_kernel_size)
+EXPORT(relocate_new_kernel_size)
PTR_WD relocate_new_kernel_end - relocate_new_kernel
.size relocate_new_kernel_size, PTRSIZE
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index 5fd9bf1d596c..f6d40e43f108 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -79,7 +79,7 @@ static unsigned long vdso_base(void)
}
if (current->flags & PF_RANDOMIZE) {
- base += prandom_u32_max(VDSO_RANDOMIZE_SIZE);
+ base += get_random_u32_below(VDSO_RANDOMIZE_SIZE);
base = PAGE_ALIGN(base);
}
diff --git a/arch/mips/kernel/vpe-cmp.c b/arch/mips/kernel/vpe-cmp.c
index e673603e11e5..92140edb3ce3 100644
--- a/arch/mips/kernel/vpe-cmp.c
+++ b/arch/mips/kernel/vpe-cmp.c
@@ -75,7 +75,6 @@ ATTRIBUTE_GROUPS(vpe);
static void vpe_device_release(struct device *cd)
{
- kfree(cd);
}
static struct class vpe_class = {
@@ -157,6 +156,7 @@ out_dev:
device_del(&vpe_device);
out_class:
+ put_device(&vpe_device);
class_unregister(&vpe_class);
out_chrdev:
@@ -169,7 +169,7 @@ void __exit vpe_module_exit(void)
{
struct vpe *v, *n;
- device_del(&vpe_device);
+ device_unregister(&vpe_device);
class_unregister(&vpe_class);
unregister_chrdev(major, VPE_MODULE_NAME);
diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c
index bad6b0891b2b..84a82b551ec3 100644
--- a/arch/mips/kernel/vpe-mt.c
+++ b/arch/mips/kernel/vpe-mt.c
@@ -313,7 +313,6 @@ ATTRIBUTE_GROUPS(vpe);
static void vpe_device_release(struct device *cd)
{
- kfree(cd);
}
static struct class vpe_class = {
@@ -497,6 +496,7 @@ out_dev:
device_del(&vpe_device);
out_class:
+ put_device(&vpe_device);
class_unregister(&vpe_class);
out_chrdev:
@@ -509,7 +509,7 @@ void __exit vpe_module_exit(void)
{
struct vpe *v, *n;
- device_del(&vpe_device);
+ device_unregister(&vpe_device);
class_unregister(&vpe_class);
unregister_chrdev(major, VPE_MODULE_NAME);
diff --git a/arch/mips/loongson64/reset.c b/arch/mips/loongson64/reset.c
index 758d5d26aaaa..e420800043b0 100644
--- a/arch/mips/loongson64/reset.c
+++ b/arch/mips/loongson64/reset.c
@@ -16,6 +16,7 @@
#include <asm/bootinfo.h>
#include <asm/idle.h>
#include <asm/reboot.h>
+#include <asm/bug.h>
#include <loongson.h>
#include <boot_param.h>
@@ -159,8 +160,17 @@ static int __init mips_reboot_setup(void)
#ifdef CONFIG_KEXEC
kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
+ if (WARN_ON(!kexec_argv))
+ return -ENOMEM;
+
kdump_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
+ if (WARN_ON(!kdump_argv))
+ return -ENOMEM;
+
kexec_envp = kmalloc(KEXEC_ENVP_SIZE, GFP_KERNEL);
+ if (WARN_ON(!kexec_envp))
+ return -ENOMEM;
+
fw_arg1 = KEXEC_ARGV_ADDR;
memcpy(kexec_envp, (void *)fw_arg2, KEXEC_ENVP_SIZE);
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c
index e07ae098bdd8..d59888aaed81 100644
--- a/arch/mips/pci/pci-rt3883.c
+++ b/arch/mips/pci/pci-rt3883.c
@@ -404,7 +404,6 @@ static int rt3883_pci_probe(struct platform_device *pdev)
struct rt3883_pci_controller *rpc;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct resource *res;
struct device_node *child;
u32 val;
int err;
@@ -414,8 +413,7 @@ static int rt3883_pci_probe(struct platform_device *pdev)
if (!rpc)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rpc->base = devm_ioremap_resource(dev, res);
+ rpc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rpc->base))
return PTR_ERR(rpc->base);
diff --git a/arch/mips/pic32/pic32mzda/early_console.c b/arch/mips/pic32/pic32mzda/early_console.c
index 25372e62783b..3cd1b408fa1c 100644
--- a/arch/mips/pic32/pic32mzda/early_console.c
+++ b/arch/mips/pic32/pic32mzda/early_console.c
@@ -27,7 +27,7 @@
#define U_BRG(x) (UART_BASE(x) + 0x40)
static void __iomem *uart_base;
-static char console_port = -1;
+static int console_port = -1;
static int __init configure_uart_pins(int port)
{
@@ -47,7 +47,7 @@ static int __init configure_uart_pins(int port)
return 0;
}
-static void __init configure_uart(char port, int baud)
+static void __init configure_uart(int port, int baud)
{
u32 pbclk;
@@ -60,7 +60,7 @@ static void __init configure_uart(char port, int baud)
uart_base + PIC32_SET(U_STA(port)));
}
-static void __init setup_early_console(char port, int baud)
+static void __init setup_early_console(int port, int baud)
{
if (configure_uart_pins(port))
return;
@@ -130,16 +130,15 @@ _out:
return baud;
}
-void __init fw_init_early_console(char port)
+void __init fw_init_early_console(void)
{
char *arch_cmdline = pic32_getcmdline();
- int baud = -1;
+ int baud, port;
uart_base = ioremap(PIC32_BASE_UART, 0xc00);
baud = get_baud_from_cmdline(arch_cmdline);
- if (port == -1)
- port = get_port_from_cmdline(arch_cmdline);
+ port = get_port_from_cmdline(arch_cmdline);
if (port == -1)
port = EARLY_CONSOLE_PORT;
diff --git a/arch/mips/pic32/pic32mzda/init.c b/arch/mips/pic32/pic32mzda/init.c
index 08c46cf122d7..53b227a9074c 100644
--- a/arch/mips/pic32/pic32mzda/init.c
+++ b/arch/mips/pic32/pic32mzda/init.c
@@ -47,7 +47,7 @@ void __init plat_mem_setup(void)
strscpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
#ifdef CONFIG_EARLY_PRINTK
- fw_init_early_console(-1);
+ fw_init_early_console();
#endif
pic32_config_init();
}
diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c
index fb0565bc34fd..bbf5811afbf2 100644
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -25,6 +25,7 @@
#define MT7621_MEM_TEST_PATTERN 0xaa5555aa
static u32 detect_magic __initdata;
+static struct ralink_soc_info *soc_info_ptr;
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
@@ -97,41 +98,83 @@ void __init ralink_of_remap(void)
panic("Failed to remap core resources");
}
-static void soc_dev_init(struct ralink_soc_info *soc_info, u32 rev)
+static unsigned int __init mt7621_get_soc_name0(void)
+{
+ return __raw_readl(MT7621_SYSC_BASE + SYSC_REG_CHIP_NAME0);
+}
+
+static unsigned int __init mt7621_get_soc_name1(void)
+{
+ return __raw_readl(MT7621_SYSC_BASE + SYSC_REG_CHIP_NAME1);
+}
+
+static bool __init mt7621_soc_valid(void)
+{
+ if (mt7621_get_soc_name0() == MT7621_CHIP_NAME0 &&
+ mt7621_get_soc_name1() == MT7621_CHIP_NAME1)
+ return true;
+ else
+ return false;
+}
+
+static const char __init *mt7621_get_soc_id(void)
+{
+ if (mt7621_soc_valid())
+ return "MT7621";
+ else
+ return "invalid";
+}
+
+static unsigned int __init mt7621_get_soc_rev(void)
+{
+ return __raw_readl(MT7621_SYSC_BASE + SYSC_REG_CHIP_REV);
+}
+
+static unsigned int __init mt7621_get_soc_ver(void)
+{
+ return (mt7621_get_soc_rev() >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK;
+}
+
+static unsigned int __init mt7621_get_soc_eco(void)
+{
+ return (mt7621_get_soc_rev() & CHIP_REV_ECO_MASK);
+}
+
+static const char __init *mt7621_get_soc_revision(void)
+{
+ if (mt7621_get_soc_rev() == 1 && mt7621_get_soc_eco() == 1)
+ return "E2";
+ else
+ return "E1";
+}
+
+static int __init mt7621_soc_dev_init(void)
{
struct soc_device *soc_dev;
struct soc_device_attribute *soc_dev_attr;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
- return;
+ return -ENOMEM;
soc_dev_attr->soc_id = "mt7621";
soc_dev_attr->family = "Ralink";
+ soc_dev_attr->revision = mt7621_get_soc_revision();
- if (((rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK) == 1 &&
- (rev & CHIP_REV_ECO_MASK) == 1)
- soc_dev_attr->revision = "E2";
- else
- soc_dev_attr->revision = "E1";
-
- soc_dev_attr->data = soc_info;
+ soc_dev_attr->data = soc_info_ptr;
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr);
- return;
+ return PTR_ERR(soc_dev);
}
+
+ return 0;
}
+device_initcall(mt7621_soc_dev_init);
void __init prom_soc_init(struct ralink_soc_info *soc_info)
{
- void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
- unsigned char *name = NULL;
- u32 n0;
- u32 n1;
- u32 rev;
-
/* Early detection of CMP support */
mips_cm_probe();
mips_cpc_probe();
@@ -154,27 +197,23 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info)
__sync();
}
- n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0);
- n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1);
-
- if (n0 == MT7621_CHIP_NAME0 && n1 == MT7621_CHIP_NAME1) {
- name = "MT7621";
+ if (mt7621_soc_valid())
soc_info->compatible = "mediatek,mt7621-soc";
- } else {
- panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1);
- }
+ else
+ panic("mt7621: unknown SoC, n0:%08x n1:%08x\n",
+ mt7621_get_soc_name0(),
+ mt7621_get_soc_name1());
ralink_soc = MT762X_SOC_MT7621AT;
- rev = __raw_readl(sysc + SYSC_REG_CHIP_REV);
snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
"MediaTek %s ver:%u eco:%u",
- name,
- (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
- (rev & CHIP_REV_ECO_MASK));
+ mt7621_get_soc_id(),
+ mt7621_get_soc_ver(),
+ mt7621_get_soc_eco());
soc_info->mem_detect = mt7621_memory_detect;
- soc_dev_init(soc_info, rev);
+ soc_info_ptr = soc_info;
if (!register_cps_smp_ops())
return;
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
index f72658b3a53f..1f7d5c6c10b0 100644
--- a/arch/mips/vdso/Makefile
+++ b/arch/mips/vdso/Makefile
@@ -71,7 +71,7 @@ KCOV_INSTRUMENT := n
# Check that we don't have PIC 'jalr t9' calls left
quiet_cmd_vdso_mips_check = VDSOCHK $@
- cmd_vdso_mips_check = if $(OBJDUMP) --disassemble $@ | egrep -h "jalr.*t9" > /dev/null; \
+ cmd_vdso_mips_check = if $(OBJDUMP) --disassemble $@ | grep -E -h "jalr.*t9" > /dev/null; \
then (echo >&2 "$@: PIC 'jalr t9' calls are not supported"; \
rm -f $@; /bin/false); fi
diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile
index 8c3ad76602f3..29c11a06b750 100644
--- a/arch/nios2/boot/Makefile
+++ b/arch/nios2/boot/Makefile
@@ -20,7 +20,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
-$(obj)/vmImage: $(obj)/vmlinux.gz
+$(obj)/vmImage: $(obj)/vmlinux.gz FORCE
$(call if_changed,uimage)
@$(kecho) 'Kernel: $@ is ready'
diff --git a/arch/nios2/kernel/ptrace.c b/arch/nios2/kernel/ptrace.c
index cd62f310778b..9221c15972e6 100644
--- a/arch/nios2/kernel/ptrace.c
+++ b/arch/nios2/kernel/ptrace.c
@@ -54,7 +54,7 @@ static int genregs_set(struct task_struct *target,
#define REG_IGNORE_RANGE(START, END) \
if (!ret) \
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
START * 4, (END * 4) + 4);
#define REG_IN_ONE(PTR, LOC) \
@@ -80,8 +80,8 @@ static int genregs_set(struct task_struct *target,
REG_IN_ONE(&regs->ra, PTR_RA);
REG_IN_ONE(&regs->ea, PTR_PC); /* use ea for PC */
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- PTR_STATUS * 4, -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ PTR_STATUS * 4, -1);
return ret;
}
diff --git a/arch/openrisc/configs/or1ksim_defconfig b/arch/openrisc/configs/or1ksim_defconfig
index 6e1e004047c7..0116e465238f 100644
--- a/arch/openrisc/configs/or1ksim_defconfig
+++ b/arch/openrisc/configs/or1ksim_defconfig
@@ -10,7 +10,8 @@ CONFIG_EXPERT=y
# CONFIG_AIO is not set
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_MODULES=y
# CONFIG_BLOCK is not set
CONFIG_OPENRISC_BUILTIN_DTB="or1ksim"
diff --git a/arch/openrisc/configs/simple_smp_defconfig b/arch/openrisc/configs/simple_smp_defconfig
index ff49d868e040..b990cb6c9309 100644
--- a/arch/openrisc/configs/simple_smp_defconfig
+++ b/arch/openrisc/configs/simple_smp_defconfig
@@ -16,7 +16,8 @@ CONFIG_EXPERT=y
# CONFIG_AIO is not set
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_MODULES=y
# CONFIG_BLOCK is not set
CONFIG_OPENRISC_BUILTIN_DTB="simple_smp"
diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c
index b971740fc2aa..85ace93fc251 100644
--- a/arch/openrisc/kernel/ptrace.c
+++ b/arch/openrisc/kernel/ptrace.c
@@ -66,10 +66,9 @@ static int genregs_set(struct task_struct *target,
int ret;
/* ignore r0 */
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
/* r1 - r31 */
- if (!ret)
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
regs->gpr+1, 4, 4*32);
/* PC */
if (!ret)
@@ -80,8 +79,7 @@ static int genregs_set(struct task_struct *target,
* the Supervision register
*/
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 4*33, -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 4*33, -1);
return ret;
}
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 96ef6a6b66e5..69c62933e952 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -424,8 +424,9 @@ static int fpr_set(struct task_struct *target,
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- ELF_NFPREG * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NFPREG * sizeof(reg), -1);
+ return 0;
}
#define RI(reg) (offsetof(struct user_regs_struct,reg) / sizeof(long))
@@ -543,8 +544,9 @@ static int gpr_set(struct task_struct *target,
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- ELF_NGREG * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NGREG * sizeof(reg), -1);
+ return 0;
}
static const struct user_regset native_regsets[] = {
@@ -606,8 +608,9 @@ static int gpr32_set(struct task_struct *target,
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- ELF_NGREG * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NGREG * sizeof(reg), -1);
+ return 0;
}
/*
diff --git a/arch/parisc/kernel/vdso.c b/arch/parisc/kernel/vdso.c
index 47e5960a2f96..c5cbfce7a84c 100644
--- a/arch/parisc/kernel/vdso.c
+++ b/arch/parisc/kernel/vdso.c
@@ -75,7 +75,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
map_base = mm->mmap_base;
if (current->flags & PF_RANDOMIZE)
- map_base -= prandom_u32_max(0x20) * PAGE_SIZE;
+ map_base -= get_random_u32_below(0x20) * PAGE_SIZE;
vdso_text_start = get_unmapped_area(NULL, map_base, vdso_text_len, 0, 0);
diff --git a/arch/powerpc/configs/microwatt_defconfig b/arch/powerpc/configs/microwatt_defconfig
index ea2dbd778aad..18d4fe4108cb 100644
--- a/arch/powerpc/configs/microwatt_defconfig
+++ b/arch/powerpc/configs/microwatt_defconfig
@@ -68,7 +68,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_NVRAM is not set
-CONFIG_RANDOM_TRUST_CPU=y
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_BITBANG=y
diff --git a/arch/powerpc/crypto/crc-vpmsum_test.c b/arch/powerpc/crypto/crc-vpmsum_test.c
index 273c527868db..c61a874a3a5c 100644
--- a/arch/powerpc/crypto/crc-vpmsum_test.c
+++ b/arch/powerpc/crypto/crc-vpmsum_test.c
@@ -77,8 +77,8 @@ static int __init crc_test_init(void)
pr_info("crc-vpmsum_test begins, %lu iterations\n", iterations);
for (i=0; i<iterations; i++) {
- size_t offset = prandom_u32_max(16);
- size_t len = prandom_u32_max(MAX_CRC_LENGTH);
+ size_t offset = get_random_u32_below(16);
+ size_t len = get_random_u32_below(MAX_CRC_LENGTH);
if (len <= offset)
continue;
diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
index 3cee7115441b..259b9dd5fe1c 100644
--- a/arch/powerpc/include/asm/ftrace.h
+++ b/arch/powerpc/include/asm/ftrace.h
@@ -37,12 +37,32 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *
return fregs->regs.msr ? &fregs->regs : NULL;
}
-static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *fregs,
- unsigned long ip)
+static __always_inline void
+ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+ unsigned long ip)
{
regs_set_return_ip(&fregs->regs, ip);
}
+static __always_inline unsigned long
+ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs)
+{
+ return instruction_pointer(&fregs->regs);
+}
+
+#define ftrace_regs_get_argument(fregs, n) \
+ regs_get_kernel_argument(&(fregs)->regs, n)
+#define ftrace_regs_get_stack_pointer(fregs) \
+ kernel_stack_pointer(&(fregs)->regs)
+#define ftrace_regs_return_value(fregs) \
+ regs_return_value(&(fregs)->regs)
+#define ftrace_regs_set_return_value(fregs, ret) \
+ regs_set_return_value(&(fregs)->regs, ret)
+#define ftrace_override_function_with_return(fregs) \
+ override_function_with_return(&(fregs)->regs)
+#define ftrace_regs_query_register_offset(name) \
+ regs_query_register_offset(name)
+
struct ftrace_ops;
#define ftrace_graph_func ftrace_graph_func
diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
index 4745bb9998bd..6d8492b6e2b8 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -602,6 +602,7 @@ ____##func(struct pt_regs *regs)
/* kernel/traps.c */
DECLARE_INTERRUPT_HANDLER_NMI(system_reset_exception);
#ifdef CONFIG_PPC_BOOK3S_64
+DECLARE_INTERRUPT_HANDLER_RAW(machine_check_early_boot);
DECLARE_INTERRUPT_HANDLER_ASYNC(machine_check_exception_async);
#endif
DECLARE_INTERRUPT_HANDLER_NMI(machine_check_exception);
diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h
index 1c8460e23583..283c34647856 100644
--- a/arch/powerpc/include/asm/stackprotector.h
+++ b/arch/powerpc/include/asm/stackprotector.h
@@ -7,8 +7,6 @@
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H
-#include <linux/random.h>
-#include <linux/version.h>
#include <asm/reg.h>
#include <asm/current.h>
#include <asm/paca.h>
@@ -21,13 +19,7 @@
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- canary = get_random_canary();
- canary ^= mftb();
- canary ^= LINUX_VERSION_CODE;
- canary &= CANARY_MASK;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 67da147fe34d..fcf604370c66 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -2303,6 +2303,6 @@ void notrace __ppc64_runlatch_off(void)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(PAGE_SIZE);
+ sp -= get_random_u32_below(PAGE_SIZE);
return sp & ~0xf;
}
diff --git a/arch/powerpc/kernel/ptrace/ptrace-tm.c b/arch/powerpc/kernel/ptrace/ptrace-tm.c
index 44045363a903..210ea834e603 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-tm.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-tm.c
@@ -170,9 +170,9 @@ int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
(PT_MAX_PUT_REG + 1) * sizeof(reg));
if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_MAX_PUT_REG + 1) * sizeof(reg),
- PT_TRAP * sizeof(reg));
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_MAX_PUT_REG + 1) * sizeof(reg),
+ PT_TRAP * sizeof(reg));
if (!ret && count > 0) {
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
@@ -183,8 +183,8 @@ int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
}
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_TRAP + 1) * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
return ret;
}
diff --git a/arch/powerpc/kernel/ptrace/ptrace-view.c b/arch/powerpc/kernel/ptrace/ptrace-view.c
index 076d867412c7..2087a785f05f 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-view.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-view.c
@@ -267,9 +267,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
(PT_MAX_PUT_REG + 1) * sizeof(reg));
if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_MAX_PUT_REG + 1) * sizeof(reg),
- PT_TRAP * sizeof(reg));
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_MAX_PUT_REG + 1) * sizeof(reg),
+ PT_TRAP * sizeof(reg));
if (!ret && count > 0) {
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
@@ -280,8 +280,8 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
}
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_TRAP + 1) * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
return ret;
}
@@ -706,8 +706,9 @@ int gpr32_set_common(struct task_struct *target,
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_TRAP + 1) * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
+ return 0;
Efault:
user_read_access_end();
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 4abc01949702..507f8228f983 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -129,28 +129,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
return 0;
}
-
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- if (likely(vma->vm_mm == current->mm))
- return current->nsproxy->time_ns->vvar_page;
-
- /*
- * VM_PFNMAP | VM_IO protect .fault() handler from being called
- * through interfaces like /proc/$pid/mem or
- * process_vm_{readv,writev}() as long as there's no .access()
- * in special_mapping_vmops.
- * For more details check_vma_flags() and __access_remote_vm()
- */
- WARN(1, "vvar_page accessed remotely");
-
- return NULL;
-}
-#else
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- return NULL;
-}
#endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7786e3ac7611..8c3862b4c259 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -142,7 +142,7 @@ SECTIONS
#endif
.data.rel.ro : AT(ADDR(.data.rel.ro) - LOAD_OFFSET) {
- *(.data.rel.ro*)
+ *(.data.rel.ro .data.rel.ro.*)
}
.branch_lt : AT(ADDR(.branch_lt) - LOAD_OFFSET) {
diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index 349a781cea0b..60e12b716d3c 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -35,7 +35,7 @@ struct umem_info {
/* usable memory ranges to look up */
unsigned int nr_ranges;
- const struct crash_mem_range *ranges;
+ const struct range *ranges;
};
const struct kexec_file_ops * const kexec_file_loaders[] = {
diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index 563e9989a5bf..5fc53a5fcfdf 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -33,7 +33,7 @@
static inline unsigned int get_max_nr_ranges(size_t size)
{
return ((size - sizeof(struct crash_mem)) /
- sizeof(struct crash_mem_range));
+ sizeof(struct range));
}
/**
@@ -51,7 +51,7 @@ static inline size_t get_mem_rngs_size(struct crash_mem *mem_rngs)
return 0;
size = (sizeof(struct crash_mem) +
- (mem_rngs->max_nr_ranges * sizeof(struct crash_mem_range)));
+ (mem_rngs->max_nr_ranges * sizeof(struct range)));
/*
* Memory is allocated in size multiple of MEM_RANGE_CHUNK_SZ.
@@ -98,7 +98,7 @@ static int __add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
*/
static void __merge_memory_ranges(struct crash_mem *mem_rngs)
{
- struct crash_mem_range *ranges;
+ struct range *ranges;
int i, idx;
if (!mem_rngs)
@@ -123,7 +123,7 @@ static void __merge_memory_ranges(struct crash_mem *mem_rngs)
/* cmp_func_t callback to sort ranges with sort() */
static int rngcmp(const void *_x, const void *_y)
{
- const struct crash_mem_range *x = _x, *y = _y;
+ const struct range *x = _x, *y = _y;
if (x->start > y->start)
return 1;
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 43f1c76d48ce..a379b0ce19ff 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -113,23 +113,19 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
{
int i;
- /* First arg comes in as a 32 bits pointer. */
- EMIT(PPC_RAW_MR(bpf_to_ppc(BPF_REG_1), _R3));
- EMIT(PPC_RAW_LI(bpf_to_ppc(BPF_REG_1) - 1, 0));
+ /* Initialize tail_call_cnt, to be skipped if we do tail calls. */
+ EMIT(PPC_RAW_LI(_R4, 0));
+
+#define BPF_TAILCALL_PROLOGUE_SIZE 4
+
EMIT(PPC_RAW_STWU(_R1, _R1, -BPF_PPC_STACKFRAME(ctx)));
- /*
- * Initialize tail_call_cnt in stack frame if we do tail calls.
- * Otherwise, put in NOPs so that it can be skipped when we are
- * invoked through a tail call.
- */
if (ctx->seen & SEEN_TAILCALL)
- EMIT(PPC_RAW_STW(bpf_to_ppc(BPF_REG_1) - 1, _R1,
- bpf_jit_stack_offsetof(ctx, BPF_PPC_TC)));
- else
- EMIT(PPC_RAW_NOP());
+ EMIT(PPC_RAW_STW(_R4, _R1, bpf_jit_stack_offsetof(ctx, BPF_PPC_TC)));
-#define BPF_TAILCALL_PROLOGUE_SIZE 16
+ /* First arg comes in as a 32 bits pointer. */
+ EMIT(PPC_RAW_MR(bpf_to_ppc(BPF_REG_1), _R3));
+ EMIT(PPC_RAW_LI(bpf_to_ppc(BPF_REG_1) - 1, 0));
/*
* We need a stack frame, but we don't necessarily need to
@@ -170,24 +166,24 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx
for (i = BPF_PPC_NVR_MIN; i <= 31; i++)
if (bpf_is_seen_register(ctx, i))
EMIT(PPC_RAW_LWZ(i, _R1, bpf_jit_stack_offsetof(ctx, i)));
-}
-
-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
-{
- EMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_0)));
-
- bpf_jit_emit_common_epilogue(image, ctx);
-
- /* Tear down our stack frame */
if (ctx->seen & SEEN_FUNC)
EMIT(PPC_RAW_LWZ(_R0, _R1, BPF_PPC_STACKFRAME(ctx) + PPC_LR_STKOFF));
+ /* Tear down our stack frame */
EMIT(PPC_RAW_ADDI(_R1, _R1, BPF_PPC_STACKFRAME(ctx)));
if (ctx->seen & SEEN_FUNC)
EMIT(PPC_RAW_MTLR(_R0));
+}
+
+void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+{
+ EMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_0)));
+
+ bpf_jit_emit_common_epilogue(image, ctx);
+
EMIT(PPC_RAW_BLR());
}
@@ -244,7 +240,6 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
EMIT(PPC_RAW_RLWINM(_R3, b2p_index, 2, 0, 29));
EMIT(PPC_RAW_ADD(_R3, _R3, b2p_bpf_array));
EMIT(PPC_RAW_LWZ(_R3, _R3, offsetof(struct bpf_array, ptrs)));
- EMIT(PPC_RAW_STW(_R0, _R1, bpf_jit_stack_offsetof(ctx, BPF_PPC_TC)));
/*
* if (prog == NULL)
@@ -255,19 +250,14 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* goto *(prog->bpf_func + prologue_size); */
EMIT(PPC_RAW_LWZ(_R3, _R3, offsetof(struct bpf_prog, bpf_func)));
-
- if (ctx->seen & SEEN_FUNC)
- EMIT(PPC_RAW_LWZ(_R0, _R1, BPF_PPC_STACKFRAME(ctx) + PPC_LR_STKOFF));
-
EMIT(PPC_RAW_ADDIC(_R3, _R3, BPF_TAILCALL_PROLOGUE_SIZE));
-
- if (ctx->seen & SEEN_FUNC)
- EMIT(PPC_RAW_MTLR(_R0));
-
EMIT(PPC_RAW_MTCTR(_R3));
EMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_1)));
+ /* Put tail_call_cnt in r4 */
+ EMIT(PPC_RAW_MR(_R4, _R0));
+
/* tear restore NVRs, ... */
bpf_jit_emit_common_epilogue(image, ctx);
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 942aa830e110..bf318dd9b709 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -132,7 +132,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw)
static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
-static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {}
+static void power_pmu_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in) {}
static inline void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) {}
static void pmao_restore_workaround(bool ebb) { }
#endif /* CONFIG_PPC32 */
@@ -424,7 +424,7 @@ static void power_pmu_bhrb_enable(struct perf_event *event)
cpuhw->bhrb_context = event->ctx;
}
cpuhw->bhrb_users++;
- perf_sched_cb_inc(event->ctx->pmu);
+ perf_sched_cb_inc(event->pmu);
}
static void power_pmu_bhrb_disable(struct perf_event *event)
@@ -436,7 +436,7 @@ static void power_pmu_bhrb_disable(struct perf_event *event)
WARN_ON_ONCE(!cpuhw->bhrb_users);
cpuhw->bhrb_users--;
- perf_sched_cb_dec(event->ctx->pmu);
+ perf_sched_cb_dec(event->pmu);
if (!cpuhw->disabled && !cpuhw->bhrb_users) {
/* BHRB cannot be turned off when other
@@ -451,7 +451,7 @@ static void power_pmu_bhrb_disable(struct perf_event *event)
/* Called from ctxsw to prevent one process's branch entries to
* mingle with the other process's entries during context switch.
*/
-static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
+static void power_pmu_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
if (!ppmu->bhrb_nr)
return;
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index a3a71d37cb9a..3f05507e444d 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -447,21 +447,18 @@ static void pseries_msi_ops_msi_free(struct irq_domain *domain,
* RTAS can not disable one MSI at a time. It's all or nothing. Do it
* at the end after all IRQs have been freed.
*/
-static void pseries_msi_domain_free_irqs(struct irq_domain *domain,
- struct device *dev)
+static void pseries_msi_post_free(struct irq_domain *domain, struct device *dev)
{
if (WARN_ON_ONCE(!dev_is_pci(dev)))
return;
- __msi_domain_free_irqs(domain, dev);
-
rtas_disable_msi(to_pci_dev(dev));
}
static struct msi_domain_ops pseries_pci_msi_domain_ops = {
.msi_prepare = pseries_msi_ops_prepare,
.msi_free = pseries_msi_ops_msi_free,
- .domain_free_irqs = pseries_msi_domain_free_irqs,
+ .msi_post_free = pseries_msi_post_free,
};
static void pseries_msi_shutdown(struct irq_data *d)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index fa78595a6089..593cf09264d8 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -317,9 +317,9 @@ config SMP
config NR_CPUS
int "Maximum number of CPUs (2-512)"
depends on SMP
- range 2 512 if !SBI_V01
- range 2 32 if SBI_V01 && 32BIT
- range 2 64 if SBI_V01 && 64BIT
+ range 2 512 if !RISCV_SBI_V01
+ range 2 32 if RISCV_SBI_V01 && 32BIT
+ range 2 64 if RISCV_SBI_V01 && 64BIT
default "32" if 32BIT
default "64" if 64BIT
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 69774bb362d6..75fb0390d6bd 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -7,6 +7,11 @@ config SOC_MICROCHIP_POLARFIRE
help
This enables support for Microchip PolarFire SoC platforms.
+config ARCH_RENESAS
+ bool "Renesas RISC-V SoCs"
+ help
+ This enables support for the RISC-V based Renesas SoCs.
+
config SOC_SIFIVE
bool "SiFive SoCs"
select SERIAL_SIFIVE if TTY
diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
index ff174996cdfd..b0ff5fbabb0c 100644
--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -3,5 +3,6 @@ subdir-y += sifive
subdir-y += starfive
subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
subdir-y += microchip
+subdir-y += renesas
obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi
index 24b1cfb9a73e..1069134f2e12 100644
--- a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi
@@ -9,8 +9,8 @@
compatible = "microchip,corepwm-rtl-v4";
reg = <0x0 0x40000000 0x0 0xF0>;
microchip,sync-update-mask = /bits/ 32 <0>;
- #pwm-cells = <2>;
- clocks = <&fabric_clk3>;
+ #pwm-cells = <3>;
+ clocks = <&ccc_nw CLK_CCC_PLL0_OUT3>;
status = "disabled";
};
@@ -19,25 +19,13 @@
reg = <0x0 0x40000200 0x0 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&fabric_clk3>;
+ clocks = <&ccc_nw CLK_CCC_PLL0_OUT3>;
interrupt-parent = <&plic>;
interrupts = <122>;
clock-frequency = <100000>;
status = "disabled";
};
- fabric_clk3: fabric-clk3 {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <50000000>;
- };
-
- fabric_clk1: fabric-clk1 {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <125000000>;
- };
-
pcie: pcie@3000000000 {
compatible = "microchip,pcie-host-1.0";
#address-cells = <0x3>;
@@ -54,7 +42,7 @@
<0 0 0 3 &pcie_intc 2>,
<0 0 0 4 &pcie_intc 3>;
interrupt-map-mask = <0 0 0 7>;
- clocks = <&fabric_clk1>, <&fabric_clk3>;
+ clocks = <&ccc_nw CLK_CCC_PLL0_OUT1>, <&ccc_nw CLK_CCC_PLL0_OUT3>;
clock-names = "fic1", "fic3";
ranges = <0x3000000 0x0 0x8000000 0x30 0x8000000 0x0 0x80000000>;
dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x1 0x00000000>;
@@ -67,4 +55,17 @@
interrupt-controller;
};
};
+
+ refclk_ccc: cccrefclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+};
+
+&ccc_nw {
+ clocks = <&refclk_ccc>, <&refclk_ccc>, <&refclk_ccc>, <&refclk_ccc>,
+ <&refclk_ccc>, <&refclk_ccc>;
+ clock-names = "pll0_ref0", "pll0_ref1", "pll1_ref0", "pll1_ref1",
+ "dll0_ref", "dll1_ref";
+ status = "okay";
};
diff --git a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts
index ec7b7c2a3ce2..90b261114763 100644
--- a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts
+++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts
@@ -5,6 +5,8 @@
#include "mpfs.dtsi"
#include "mpfs-icicle-kit-fabric.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
/* Clock frequency (in Hz) of the rtcclk */
#define RTCCLK_FREQ 1000000
@@ -31,13 +33,41 @@
timebase-frequency = <RTCCLK_FREQ>;
};
+ leds {
+ compatible = "gpio-leds";
+
+ led-1 {
+ gpios = <&gpio2 16 GPIO_ACTIVE_HIGH>;
+ color = <LED_COLOR_ID_RED>;
+ label = "led1";
+ };
+
+ led-2 {
+ gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+ color = <LED_COLOR_ID_RED>;
+ label = "led2";
+ };
+
+ led-3 {
+ gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>;
+ color = <LED_COLOR_ID_AMBER>;
+ label = "led3";
+ };
+
+ led-4 {
+ gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ color = <LED_COLOR_ID_AMBER>;
+ label = "led4";
+ };
+ };
+
ddrc_cache_lo: memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x40000000>;
status = "okay";
};
- ddrc_cache_hi: memory@1000000000 {
+ ddrc_cache_hi: memory@1040000000 {
device_type = "memory";
reg = <0x10 0x40000000 0x0 0x40000000>;
status = "okay";
@@ -149,6 +179,10 @@
clock-frequency = <125000000>;
};
+&refclk_ccc {
+ clock-frequency = <50000000>;
+};
+
&rtc {
status = "okay";
};
diff --git a/arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi
index 7b9ee13b6a3a..8230f06ddf48 100644
--- a/arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi
@@ -30,8 +30,8 @@
<0 0 0 3 &pcie_intc 2>,
<0 0 0 4 &pcie_intc 3>;
interrupt-map-mask = <0 0 0 7>;
- clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
- clock-names = "fic0", "fic1", "fic3";
+ clocks = <&fabric_clk1>, <&fabric_clk3>;
+ clock-names = "fic0", "fic3";
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
msi-parent = <&pcie>;
msi-controller;
diff --git a/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi
index 67303bc0e451..9a56de7b91d6 100644
--- a/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi
@@ -30,8 +30,8 @@
<0 0 0 3 &pcie_intc 2>,
<0 0 0 4 &pcie_intc 3>;
interrupt-map-mask = <0 0 0 7>;
- clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
- clock-names = "fic0", "fic1", "fic3";
+ clocks = <&fabric_clk1>, <&fabric_clk3>;
+ clock-names = "fic0", "fic3";
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
msi-parent = <&pcie>;
msi-controller;
diff --git a/arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi
index 8545baf4d129..39a77df489ab 100644
--- a/arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi
@@ -13,33 +13,4 @@
#clock-cells = <0>;
clock-frequency = <125000000>;
};
-
- pcie: pcie@2000000000 {
- compatible = "microchip,pcie-host-1.0";
- #address-cells = <0x3>;
- #interrupt-cells = <0x1>;
- #size-cells = <0x2>;
- device_type = "pci";
- reg = <0x20 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
- reg-names = "cfg", "apb";
- bus-range = <0x0 0x7f>;
- interrupt-parent = <&plic>;
- interrupts = <119>;
- interrupt-map = <0 0 0 1 &pcie_intc 0>,
- <0 0 0 2 &pcie_intc 1>,
- <0 0 0 3 &pcie_intc 2>,
- <0 0 0 4 &pcie_intc 3>;
- interrupt-map-mask = <0 0 0 7>;
- clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
- clock-names = "fic0", "fic1", "fic3";
- ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
- msi-parent = <&pcie>;
- msi-controller;
- status = "disabled";
- pcie_intc: interrupt-controller {
- #address-cells = <0>;
- #interrupt-cells = <1>;
- interrupt-controller;
- };
- };
};
diff --git a/arch/riscv/boot/dts/microchip/mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi
index 8f463399a568..0a9bb84af438 100644
--- a/arch/riscv/boot/dts/microchip/mpfs.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi
@@ -236,6 +236,38 @@
#clock-cells = <1>;
};
+ ccc_se: clock-controller@38010000 {
+ compatible = "microchip,mpfs-ccc";
+ reg = <0x0 0x38010000 0x0 0x1000>, <0x0 0x38020000 0x0 0x1000>,
+ <0x0 0x39010000 0x0 0x1000>, <0x0 0x39020000 0x0 0x1000>;
+ #clock-cells = <1>;
+ status = "disabled";
+ };
+
+ ccc_ne: clock-controller@38040000 {
+ compatible = "microchip,mpfs-ccc";
+ reg = <0x0 0x38040000 0x0 0x1000>, <0x0 0x38080000 0x0 0x1000>,
+ <0x0 0x39040000 0x0 0x1000>, <0x0 0x39080000 0x0 0x1000>;
+ #clock-cells = <1>;
+ status = "disabled";
+ };
+
+ ccc_nw: clock-controller@38100000 {
+ compatible = "microchip,mpfs-ccc";
+ reg = <0x0 0x38100000 0x0 0x1000>, <0x0 0x38200000 0x0 0x1000>,
+ <0x0 0x39100000 0x0 0x1000>, <0x0 0x39200000 0x0 0x1000>;
+ #clock-cells = <1>;
+ status = "disabled";
+ };
+
+ ccc_sw: clock-controller@38400000 {
+ compatible = "microchip,mpfs-ccc";
+ reg = <0x0 0x38400000 0x0 0x1000>, <0x0 0x38800000 0x0 0x1000>,
+ <0x0 0x39400000 0x0 0x1000>, <0x0 0x39800000 0x0 0x1000>;
+ #clock-cells = <1>;
+ status = "disabled";
+ };
+
mmuart0: serial@20000000 {
compatible = "ns16550a";
reg = <0x0 0x20000000 0x0 0x400>;
diff --git a/arch/riscv/boot/dts/renesas/Makefile b/arch/riscv/boot/dts/renesas/Makefile
new file mode 100644
index 000000000000..2d3f5751a649
--- /dev/null
+++ b/arch/riscv/boot/dts/renesas/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043f01-smarc.dtb
diff --git a/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi
new file mode 100644
index 000000000000..6ec1c6f9a403
--- /dev/null
+++ b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the RZ/Five SoC
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr) (nr + 32)
+
+#include <arm64/renesas/r9a07g043.dtsi>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ timebase-frequency = <12000000>;
+
+ cpu0: cpu@0 {
+ compatible = "andestech,ax45mp", "riscv";
+ device_type = "cpu";
+ #cooling-cells = <2>;
+ reg = <0x0>;
+ status = "okay";
+ riscv,isa = "rv64imafdc";
+ mmu-type = "riscv,sv39";
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <0x40>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <0x40>;
+ clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
+ operating-points-v2 = <&cluster0_opp>;
+
+ cpu0_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ };
+};
+
+&soc {
+ interrupt-parent = <&plic>;
+
+ plic: interrupt-controller@12c00000 {
+ compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
+ #interrupt-cells = <2>;
+ #address-cells = <0>;
+ riscv,ndev = <511>;
+ interrupt-controller;
+ reg = <0x0 0x12c00000 0 0x400000>;
+ clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
+ interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
+ };
+};
diff --git a/arch/riscv/boot/dts/renesas/r9a07g043f01-smarc.dts b/arch/riscv/boot/dts/renesas/r9a07g043f01-smarc.dts
new file mode 100644
index 000000000000..2aa8515451d3
--- /dev/null
+++ b/arch/riscv/boot/dts/renesas/r9a07g043f01-smarc.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the RZ/Five SMARC EVK
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+
+/*
+ * DIP-Switch SW1 setting
+ * 1 : High; 0: Low
+ * SW1-2 : SW_SD0_DEV_SEL (0: uSD; 1: eMMC)
+ * SW1-3 : SW_ET0_EN_N (0: ETHER0; 1: CAN0, CAN1, SSI1, RSPI1)
+ * Please change below macros according to SW1 setting on the SoM
+ */
+#define SW_SW0_DEV_SEL 1
+#define SW_ET0_EN_N 1
+
+#include "r9a07g043f.dtsi"
+#include "rzfive-smarc-som.dtsi"
+#include "rzfive-smarc.dtsi"
+
+/ {
+ model = "Renesas SMARC EVK based on r9a07g043f01";
+ compatible = "renesas,smarc-evk", "renesas,r9a07g043f01", "renesas,r9a07g043";
+};
diff --git a/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi b/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi
new file mode 100644
index 000000000000..2b7672bc4b52
--- /dev/null
+++ b/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the RZ/Five SMARC EVK SOM
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <arm64/renesas/rzg2ul-smarc-som.dtsi>
+
+/ {
+ aliases {
+ /delete-property/ ethernet0;
+ /delete-property/ ethernet1;
+ };
+
+ chosen {
+ bootargs = "ignore_loglevel";
+ };
+};
+
+&dmac {
+ status = "disabled";
+};
+
+&eth0 {
+ status = "disabled";
+};
+
+&eth1 {
+ status = "disabled";
+};
+
+&ostm1 {
+ status = "disabled";
+};
+
+&ostm2 {
+ status = "disabled";
+};
+
+&sdhi0 {
+ status = "disabled";
+};
+
+&wdt0 {
+ status = "disabled";
+};
diff --git a/arch/riscv/boot/dts/renesas/rzfive-smarc.dtsi b/arch/riscv/boot/dts/renesas/rzfive-smarc.dtsi
new file mode 100644
index 000000000000..c07a487c4e5a
--- /dev/null
+++ b/arch/riscv/boot/dts/renesas/rzfive-smarc.dtsi
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the RZ/Five SMARC EVK carrier board
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <arm64/renesas/rzg2ul-smarc.dtsi>
+
+&ehci0 {
+ status = "disabled";
+};
+
+&ehci1 {
+ status = "disabled";
+};
+
+&hsusb {
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "disabled";
+};
+
+&ohci1 {
+ status = "disabled";
+};
+
+&phyrst {
+ status = "disabled";
+};
+
+&sdhi1 {
+ status = "disabled";
+};
+
+&snd_rzg2l {
+ status = "disabled";
+};
+
+&spi1 {
+ status = "disabled";
+};
+
+&ssi1 {
+ status = "disabled";
+};
+
+&usb0_vbus_otg {
+ status = "disabled";
+};
+
+&usb2_phy0 {
+ status = "disabled";
+};
+
+&usb2_phy1 {
+ status = "disabled";
+};
+
+&vccq_sdhi1 {
+ status = "disabled";
+};
diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index ced0d4e47938..900a50526d77 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -3,6 +3,8 @@
#include "fu540-c000.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pwm/pwm.h>
/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
#define RTCCLK_FREQ 1000000
@@ -42,6 +44,42 @@
compatible = "gpio-restart";
gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
};
+
+ led-controller {
+ compatible = "pwm-leds";
+
+ led-d1 {
+ pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
+ active-low;
+ color = <LED_COLOR_ID_GREEN>;
+ max-brightness = <255>;
+ label = "d1";
+ };
+
+ led-d2 {
+ pwms = <&pwm0 1 7812500 PWM_POLARITY_INVERTED>;
+ active-low;
+ color = <LED_COLOR_ID_GREEN>;
+ max-brightness = <255>;
+ label = "d2";
+ };
+
+ led-d3 {
+ pwms = <&pwm0 2 7812500 PWM_POLARITY_INVERTED>;
+ active-low;
+ color = <LED_COLOR_ID_GREEN>;
+ max-brightness = <255>;
+ label = "d3";
+ };
+
+ led-d4 {
+ pwms = <&pwm0 3 7812500 PWM_POLARITY_INVERTED>;
+ active-low;
+ color = <LED_COLOR_ID_GREEN>;
+ max-brightness = <255>;
+ label = "d4";
+ };
+ };
};
&uart0 {
diff --git a/arch/riscv/boot/dts/starfive/Makefile b/arch/riscv/boot/dts/starfive/Makefile
index 0ea1bc15ab30..039c143cba33 100644
--- a/arch/riscv/boot/dts/starfive/Makefile
+++ b/arch/riscv/boot/dts/starfive/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_SOC_STARFIVE) += jh7100-beaglev-starlight.dtb
+dtb-$(CONFIG_SOC_STARFIVE) += jh7100-beaglev-starlight.dtb jh7100-starfive-visionfive-v1.dtb
diff --git a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
index f7a230110512..7cda3a89020a 100644
--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
+++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
@@ -5,160 +5,9 @@
*/
/dts-v1/;
-#include "jh7100.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/leds/common.h>
-#include <dt-bindings/pinctrl/pinctrl-starfive-jh7100.h>
+#include "jh7100-common.dtsi"
/ {
model = "BeagleV Starlight Beta";
compatible = "beagle,beaglev-starlight-jh7100-r0", "starfive,jh7100";
-
- aliases {
- serial0 = &uart3;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
- cpus {
- timebase-frequency = <6250000>;
- };
-
- memory@80000000 {
- device_type = "memory";
- reg = <0x0 0x80000000 0x2 0x0>;
- };
-
- leds {
- compatible = "gpio-leds";
-
- led-ack {
- gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
- color = <LED_COLOR_ID_GREEN>;
- function = LED_FUNCTION_HEARTBEAT;
- linux,default-trigger = "heartbeat";
- label = "ack";
- };
- };
-};
-
-&gpio {
- i2c0_pins: i2c0-0 {
- i2c-pins {
- pinmux = <GPIOMUX(62, GPO_LOW,
- GPO_I2C0_PAD_SCK_OEN,
- GPI_I2C0_PAD_SCK_IN)>,
- <GPIOMUX(61, GPO_LOW,
- GPO_I2C0_PAD_SDA_OEN,
- GPI_I2C0_PAD_SDA_IN)>;
- bias-disable; /* external pull-up */
- input-enable;
- input-schmitt-enable;
- };
- };
-
- i2c1_pins: i2c1-0 {
- i2c-pins {
- pinmux = <GPIOMUX(47, GPO_LOW,
- GPO_I2C1_PAD_SCK_OEN,
- GPI_I2C1_PAD_SCK_IN)>,
- <GPIOMUX(48, GPO_LOW,
- GPO_I2C1_PAD_SDA_OEN,
- GPI_I2C1_PAD_SDA_IN)>;
- bias-pull-up;
- input-enable;
- input-schmitt-enable;
- };
- };
-
- i2c2_pins: i2c2-0 {
- i2c-pins {
- pinmux = <GPIOMUX(60, GPO_LOW,
- GPO_I2C2_PAD_SCK_OEN,
- GPI_I2C2_PAD_SCK_IN)>,
- <GPIOMUX(59, GPO_LOW,
- GPO_I2C2_PAD_SDA_OEN,
- GPI_I2C2_PAD_SDA_IN)>;
- bias-disable; /* external pull-up */
- input-enable;
- input-schmitt-enable;
- };
- };
-
- uart3_pins: uart3-0 {
- rx-pins {
- pinmux = <GPIOMUX(13, GPO_LOW, GPO_DISABLE,
- GPI_UART3_PAD_SIN)>;
- bias-pull-up;
- drive-strength = <14>;
- input-enable;
- input-schmitt-enable;
- slew-rate = <0>;
- };
- tx-pins {
- pinmux = <GPIOMUX(14, GPO_UART3_PAD_SOUT,
- GPO_ENABLE, GPI_NONE)>;
- bias-disable;
- drive-strength = <35>;
- input-disable;
- input-schmitt-disable;
- slew-rate = <0>;
- };
- };
-};
-
-&i2c0 {
- clock-frequency = <100000>;
- i2c-sda-hold-time-ns = <300>;
- i2c-sda-falling-time-ns = <500>;
- i2c-scl-falling-time-ns = <500>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins>;
- status = "okay";
-
- pmic@5e {
- compatible = "ti,tps65086";
- reg = <0x5e>;
- gpio-controller;
- #gpio-cells = <2>;
-
- regulators {
- };
- };
-};
-
-&i2c1 {
- clock-frequency = <400000>;
- i2c-sda-hold-time-ns = <300>;
- i2c-sda-falling-time-ns = <100>;
- i2c-scl-falling-time-ns = <100>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins>;
- status = "okay";
-};
-
-&i2c2 {
- clock-frequency = <100000>;
- i2c-sda-hold-time-ns = <300>;
- i2c-sda-falling-time-ns = <500>;
- i2c-scl-falling-time-ns = <500>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins>;
- status = "okay";
-};
-
-&osc_sys {
- clock-frequency = <25000000>;
-};
-
-&osc_aud {
- clock-frequency = <27000000>;
-};
-
-&uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
- status = "okay";
};
diff --git a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
new file mode 100644
index 000000000000..b93ce351a90f
--- /dev/null
+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
+ */
+
+/dts-v1/;
+#include "jh7100.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/pinctrl-starfive-jh7100.h>
+
+/ {
+ aliases {
+ serial0 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ cpus {
+ timebase-frequency = <6250000>;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x2 0x0>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-ack {
+ gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_HEARTBEAT;
+ linux,default-trigger = "heartbeat";
+ label = "ack";
+ };
+ };
+};
+
+&gpio {
+ i2c0_pins: i2c0-0 {
+ i2c-pins {
+ pinmux = <GPIOMUX(62, GPO_LOW,
+ GPO_I2C0_PAD_SCK_OEN,
+ GPI_I2C0_PAD_SCK_IN)>,
+ <GPIOMUX(61, GPO_LOW,
+ GPO_I2C0_PAD_SDA_OEN,
+ GPI_I2C0_PAD_SDA_IN)>;
+ bias-disable; /* external pull-up */
+ input-enable;
+ input-schmitt-enable;
+ };
+ };
+
+ i2c1_pins: i2c1-0 {
+ i2c-pins {
+ pinmux = <GPIOMUX(47, GPO_LOW,
+ GPO_I2C1_PAD_SCK_OEN,
+ GPI_I2C1_PAD_SCK_IN)>,
+ <GPIOMUX(48, GPO_LOW,
+ GPO_I2C1_PAD_SDA_OEN,
+ GPI_I2C1_PAD_SDA_IN)>;
+ bias-pull-up;
+ input-enable;
+ input-schmitt-enable;
+ };
+ };
+
+ i2c2_pins: i2c2-0 {
+ i2c-pins {
+ pinmux = <GPIOMUX(60, GPO_LOW,
+ GPO_I2C2_PAD_SCK_OEN,
+ GPI_I2C2_PAD_SCK_IN)>,
+ <GPIOMUX(59, GPO_LOW,
+ GPO_I2C2_PAD_SDA_OEN,
+ GPI_I2C2_PAD_SDA_IN)>;
+ bias-disable; /* external pull-up */
+ input-enable;
+ input-schmitt-enable;
+ };
+ };
+
+ uart3_pins: uart3-0 {
+ rx-pins {
+ pinmux = <GPIOMUX(13, GPO_LOW, GPO_DISABLE,
+ GPI_UART3_PAD_SIN)>;
+ bias-pull-up;
+ drive-strength = <14>;
+ input-enable;
+ input-schmitt-enable;
+ slew-rate = <0>;
+ };
+ tx-pins {
+ pinmux = <GPIOMUX(14, GPO_UART3_PAD_SOUT,
+ GPO_ENABLE, GPI_NONE)>;
+ bias-disable;
+ drive-strength = <35>;
+ input-disable;
+ input-schmitt-disable;
+ slew-rate = <0>;
+ };
+ };
+};
+
+&i2c0 {
+ clock-frequency = <100000>;
+ i2c-sda-hold-time-ns = <300>;
+ i2c-sda-falling-time-ns = <500>;
+ i2c-scl-falling-time-ns = <500>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "okay";
+
+ pmic@5e {
+ compatible = "ti,tps65086";
+ reg = <0x5e>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ regulators {
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+ i2c-sda-hold-time-ns = <300>;
+ i2c-sda-falling-time-ns = <100>;
+ i2c-scl-falling-time-ns = <100>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ i2c-sda-hold-time-ns = <300>;
+ i2c-sda-falling-time-ns = <500>;
+ i2c-scl-falling-time-ns = <500>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "okay";
+};
+
+&osc_sys {
+ clock-frequency = <25000000>;
+};
+
+&osc_aud {
+ clock-frequency = <27000000>;
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ status = "okay";
+};
diff --git a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
new file mode 100644
index 000000000000..e82af72f1aaf
--- /dev/null
+++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
+ */
+
+/dts-v1/;
+#include "jh7100-common.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "StarFive VisionFive V1";
+ compatible = "starfive,visionfive-v1", "starfive,jh7100";
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpio 63 GPIO_ACTIVE_HIGH>;
+ priority = <224>;
+ };
+};
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 05fd5fcf24f9..f7f32448f160 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -26,6 +26,7 @@ CONFIG_EXPERT=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_PROFILING=y
CONFIG_SOC_MICROCHIP_POLARFIRE=y
+CONFIG_ARCH_RENESAS=y
CONFIG_SOC_SIFIVE=y
CONFIG_SOC_STARFIVE=y
CONFIG_SOC_VIRT=y
@@ -123,6 +124,7 @@ CONFIG_INPUT_MOUSEDEV=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_SH_SCI=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
@@ -159,6 +161,7 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_RPMSG_CHAR=y
CONFIG_RPMSG_CTRL=y
CONFIG_RPMSG_VIRTIO=y
+CONFIG_ARCH_R9A07G043=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
index 96fe8def644c..79b3ccd58ff0 100644
--- a/arch/riscv/configs/nommu_k210_defconfig
+++ b/arch/riscv/configs/nommu_k210_defconfig
@@ -25,7 +25,8 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_CANAAN=y
CONFIG_NONPORTABLE=y
diff --git a/arch/riscv/configs/nommu_k210_sdcard_defconfig b/arch/riscv/configs/nommu_k210_sdcard_defconfig
index 379740654373..6b80bb13b8ed 100644
--- a/arch/riscv/configs/nommu_k210_sdcard_defconfig
+++ b/arch/riscv/configs/nommu_k210_sdcard_defconfig
@@ -17,7 +17,8 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_CANAAN=y
CONFIG_NONPORTABLE=y
diff --git a/arch/riscv/configs/nommu_virt_defconfig b/arch/riscv/configs/nommu_virt_defconfig
index 1a56eda5ce46..4cf0f297091e 100644
--- a/arch/riscv/configs/nommu_virt_defconfig
+++ b/arch/riscv/configs/nommu_virt_defconfig
@@ -22,7 +22,8 @@ CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_VIRT=y
CONFIG_NONPORTABLE=y
diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h
index 1b471ff73178..816e753de636 100644
--- a/arch/riscv/include/asm/asm.h
+++ b/arch/riscv/include/asm/asm.h
@@ -23,6 +23,7 @@
#define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw)
#define REG_SC __REG_SEL(sc.d, sc.w)
+#define REG_AMOSWAP_AQ __REG_SEL(amoswap.d.aq, amoswap.w.aq)
#define REG_ASM __REG_SEL(.dword, .word)
#define SZREG __REG_SEL(8, 4)
#define LGREG __REG_SEL(3, 2)
diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h
index f74879a8f1ea..e229d7be4b66 100644
--- a/arch/riscv/include/asm/efi.h
+++ b/arch/riscv/include/asm/efi.h
@@ -10,6 +10,7 @@
#include <asm/mmu_context.h>
#include <asm/ptrace.h>
#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
#ifdef CONFIG_EFI
extern void efi_init(void);
@@ -20,7 +21,10 @@ extern void efi_init(void);
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
-#define arch_efi_call_virt_setup() efi_virtmap_load()
+#define arch_efi_call_virt_setup() ({ \
+ sync_kernel_mappings(efi_mm.pgd); \
+ efi_virtmap_load(); \
+ })
#define arch_efi_call_virt_teardown() efi_virtmap_unload()
#define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
index 947f23d7b6af..59dc12b5b7e8 100644
--- a/arch/riscv/include/asm/pgalloc.h
+++ b/arch/riscv/include/asm/pgalloc.h
@@ -127,6 +127,13 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
#define __p4d_free_tlb(tlb, p4d, addr) p4d_free((tlb)->mm, p4d)
#endif /* __PAGETABLE_PMD_FOLDED */
+static inline void sync_kernel_mappings(pgd_t *pgd)
+{
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ init_mm.pgd + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *pgd;
@@ -135,9 +142,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
if (likely(pgd != NULL)) {
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
/* Copy kernel mappings */
- memcpy(pgd + USER_PTRS_PER_PGD,
- init_mm.pgd + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ sync_kernel_mappings(pgd);
}
return pgd;
}
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 7ec936910a96..92ec2d9d7273 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -600,6 +600,7 @@ static inline int pmd_dirty(pmd_t pmd)
return pte_dirty(pmd_pte(pmd));
}
+#define pmd_young pmd_young
static inline int pmd_young(pmd_t pmd)
{
return pte_young(pmd_pte(pmd));
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index d3443be7eedc..3831b638ecab 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -50,6 +50,9 @@ void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);
/* Clear IPI for current CPU */
void riscv_clear_ipi(void);
+/* Check other CPUs stop or not */
+bool smp_crash_stop_failed(void);
+
/* Secondary hart entry */
asmlinkage void smp_callin(void);
diff --git a/arch/riscv/include/asm/stackprotector.h b/arch/riscv/include/asm/stackprotector.h
index 09093af46565..43895b90fe3f 100644
--- a/arch/riscv/include/asm/stackprotector.h
+++ b/arch/riscv/include/asm/stackprotector.h
@@ -3,9 +3,6 @@
#ifndef _ASM_RISCV_STACKPROTECTOR_H
#define _ASM_RISCV_STACKPROTECTOR_H
-#include <linux/random.h>
-#include <linux/version.h>
-
extern unsigned long __stack_chk_guard;
/*
@@ -16,12 +13,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
- canary &= CANARY_MASK;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK))
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index b9eda3fcbd6d..186abd146eaf 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -404,6 +404,19 @@ handle_syscall_trace_exit:
#ifdef CONFIG_VMAP_STACK
handle_kernel_stack_overflow:
+ /*
+ * Takes the psuedo-spinlock for the shadow stack, in case multiple
+ * harts are concurrently overflowing their kernel stacks. We could
+ * store any value here, but since we're overflowing the kernel stack
+ * already we only have SP to use as a scratch register. So we just
+ * swap in the address of the spinlock, as that's definately non-zero.
+ *
+ * Pairs with a store_release in handle_bad_stack().
+ */
+1: la sp, spin_shadow_stack
+ REG_AMOSWAP_AQ sp, sp, (sp)
+ bnez sp, 1b
+
la sp, shadow_stack
addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index ee79e6839b86..2d139b724bc8 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -15,6 +15,8 @@
#include <linux/compiler.h> /* For unreachable() */
#include <linux/cpu.h> /* For cpu_down() */
#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
/*
* kexec_image_info - Print received image details
@@ -138,20 +140,35 @@ void machine_shutdown(void)
#endif
}
-/* Override the weak function in kernel/panic.c */
-void crash_smp_send_stop(void)
+static void machine_kexec_mask_interrupts(void)
{
- static int cpus_stopped;
+ unsigned int i;
+ struct irq_desc *desc;
- /*
- * This function can be called twice in panic path, but obviously
- * we execute this only once.
- */
- if (cpus_stopped)
- return;
+ for_each_irq_desc(i, desc) {
+ struct irq_chip *chip;
+ int ret;
+
+ chip = irq_desc_get_chip(desc);
+ if (!chip)
+ continue;
+
+ /*
+ * First try to remove the active state. If this
+ * fails, try to EOI the interrupt.
+ */
+ ret = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false);
+
+ if (ret && irqd_irq_inprogress(&desc->irq_data) &&
+ chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
- smp_send_stop();
- cpus_stopped = 1;
+ if (chip->irq_mask)
+ chip->irq_mask(&desc->irq_data);
+
+ if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
+ chip->irq_disable(&desc->irq_data);
+ }
}
/*
@@ -169,6 +186,8 @@ machine_crash_shutdown(struct pt_regs *regs)
crash_smp_send_stop();
crash_save_cpu(regs, smp_processor_id());
+ machine_kexec_mask_interrupts();
+
pr_info("Starting crashdump kernel...\n");
}
@@ -195,6 +214,11 @@ machine_kexec(struct kimage *image)
void *control_code_buffer = page_address(image->control_code_page);
riscv_kexec_method kexec_method = NULL;
+#ifdef CONFIG_SMP
+ WARN(smp_crash_stop_failed(),
+ "Some CPUs may be stale, kdump will be unreliable.\n");
+#endif
+
if (image->type != KEXEC_TYPE_CRASH)
kexec_method = control_code_buffer;
else
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b0c63e8e867e..8955f2432c2d 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -164,6 +164,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
unsigned long tls = args->tls;
struct pt_regs *childregs = task_pt_regs(p);
+ memset(&p->thread.s, 0, sizeof(p->thread.s));
+
/* p->thread holds context to be restored by __switch_to() */
if (unlikely(args->fn)) {
/* Kernel thread */
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index ad76bb59b059..86acd690d529 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -283,6 +283,7 @@ void __init setup_arch(char **cmdline_p)
else
pr_err("No DTB found in kernel mappings\n");
#endif
+ early_init_fdt_scan_reserved_mem();
misc_mem_init();
init_resources();
@@ -321,10 +322,11 @@ subsys_initcall(topology_init);
void free_initmem(void)
{
- if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
- set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end),
- IS_ENABLED(CONFIG_64BIT) ?
- set_memory_rw : set_memory_rw_nx);
+ if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) {
+ set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), set_memory_rw_nx);
+ if (IS_ENABLED(CONFIG_64BIT))
+ set_kernel_memory(__init_begin, __init_end, set_memory_nx);
+ }
free_initmem_default(POISON_FREE_INITMEM);
}
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
index 760a64518c58..8c3b59f1f9b8 100644
--- a/arch/riscv/kernel/smp.c
+++ b/arch/riscv/kernel/smp.c
@@ -12,6 +12,7 @@
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/kexec.h>
#include <linux/profile.h>
#include <linux/smp.h>
#include <linux/sched.h>
@@ -22,11 +23,13 @@
#include <asm/sbi.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
+#include <asm/cpu_ops.h>
enum ipi_message_type {
IPI_RESCHEDULE,
IPI_CALL_FUNC,
IPI_CPU_STOP,
+ IPI_CPU_CRASH_STOP,
IPI_IRQ_WORK,
IPI_TIMER,
IPI_MAX
@@ -71,6 +74,32 @@ static void ipi_stop(void)
wait_for_interrupt();
}
+#ifdef CONFIG_KEXEC_CORE
+static atomic_t waiting_for_crash_ipi = ATOMIC_INIT(0);
+
+static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
+{
+ crash_save_cpu(regs, cpu);
+
+ atomic_dec(&waiting_for_crash_ipi);
+
+ local_irq_disable();
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpu_has_hotplug(cpu))
+ cpu_ops[cpu]->cpu_stop();
+#endif
+
+ for(;;)
+ wait_for_interrupt();
+}
+#else
+static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
+{
+ unreachable();
+}
+#endif
+
static const struct riscv_ipi_ops *ipi_ops __ro_after_init;
void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
@@ -124,8 +153,9 @@ void arch_irq_work_raise(void)
void handle_IPI(struct pt_regs *regs)
{
- unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
- unsigned long *stats = ipi_data[smp_processor_id()].stats;
+ unsigned int cpu = smp_processor_id();
+ unsigned long *pending_ipis = &ipi_data[cpu].bits;
+ unsigned long *stats = ipi_data[cpu].stats;
riscv_clear_ipi();
@@ -154,6 +184,10 @@ void handle_IPI(struct pt_regs *regs)
ipi_stop();
}
+ if (ops & (1 << IPI_CPU_CRASH_STOP)) {
+ ipi_cpu_crash_stop(cpu, get_irq_regs());
+ }
+
if (ops & (1 << IPI_IRQ_WORK)) {
stats[IPI_IRQ_WORK]++;
irq_work_run();
@@ -176,6 +210,7 @@ static const char * const ipi_names[] = {
[IPI_RESCHEDULE] = "Rescheduling interrupts",
[IPI_CALL_FUNC] = "Function call interrupts",
[IPI_CPU_STOP] = "CPU stop interrupts",
+ [IPI_CPU_CRASH_STOP] = "CPU stop (for crash dump) interrupts",
[IPI_IRQ_WORK] = "IRQ work interrupts",
[IPI_TIMER] = "Timer broadcast interrupts",
};
@@ -235,6 +270,64 @@ void smp_send_stop(void)
cpumask_pr_args(cpu_online_mask));
}
+#ifdef CONFIG_KEXEC_CORE
+/*
+ * The number of CPUs online, not counting this CPU (which may not be
+ * fully online and so not counted in num_online_cpus()).
+ */
+static inline unsigned int num_other_online_cpus(void)
+{
+ unsigned int this_cpu_online = cpu_online(smp_processor_id());
+
+ return num_online_cpus() - this_cpu_online;
+}
+
+void crash_smp_send_stop(void)
+{
+ static int cpus_stopped;
+ cpumask_t mask;
+ unsigned long timeout;
+
+ /*
+ * This function can be called twice in panic path, but obviously
+ * we execute this only once.
+ */
+ if (cpus_stopped)
+ return;
+
+ cpus_stopped = 1;
+
+ /*
+ * If this cpu is the only one alive at this point in time, online or
+ * not, there are no stop messages to be sent around, so just back out.
+ */
+ if (num_other_online_cpus() == 0)
+ return;
+
+ cpumask_copy(&mask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+
+ atomic_set(&waiting_for_crash_ipi, num_other_online_cpus());
+
+ pr_crit("SMP: stopping secondary CPUs\n");
+ send_ipi_mask(&mask, IPI_CPU_CRASH_STOP);
+
+ /* Wait up to one second for other CPUs to stop */
+ timeout = USEC_PER_SEC;
+ while ((atomic_read(&waiting_for_crash_ipi) > 0) && timeout--)
+ udelay(1);
+
+ if (atomic_read(&waiting_for_crash_ipi) > 0)
+ pr_warn("SMP: failed to stop secondary CPUs %*pbl\n",
+ cpumask_pr_args(&mask));
+}
+
+bool smp_crash_stop_failed(void)
+{
+ return (atomic_read(&waiting_for_crash_ipi) > 0);
+}
+#endif
+
void smp_send_reschedule(int cpu)
{
send_ipi_single(cpu, IPI_RESCHEDULE);
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index f3e96d60a2ff..7abd8e4c4df6 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -221,11 +221,29 @@ asmlinkage unsigned long get_overflow_stack(void)
OVERFLOW_STACK_SIZE;
}
+/*
+ * A pseudo spinlock to protect the shadow stack from being used by multiple
+ * harts concurrently. This isn't a real spinlock because the lock side must
+ * be taken without a valid stack and only a single register, it's only taken
+ * while in the process of panicing anyway so the performance and error
+ * checking a proper spinlock gives us doesn't matter.
+ */
+unsigned long spin_shadow_stack;
+
asmlinkage void handle_bad_stack(struct pt_regs *regs)
{
unsigned long tsk_stk = (unsigned long)current->stack;
unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
+ /*
+ * We're done with the shadow stack by this point, as we're on the
+ * overflow stack. Tell any other concurrent overflowing harts that
+ * they can proceed with panicing by releasing the pseudo-spinlock.
+ *
+ * This pairs with an amoswap.aq in handle_kernel_stack_overflow.
+ */
+ smp_store_release(&spin_shadow_stack, 0);
+
console_verbose();
pr_emerg("Insufficient stack space to handle exception!\n");
diff --git a/arch/riscv/kernel/vdso.c b/arch/riscv/kernel/vdso.c
index 123d05255fcf..e410275918ac 100644
--- a/arch/riscv/kernel/vdso.c
+++ b/arch/riscv/kernel/vdso.c
@@ -137,28 +137,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm);
return 0;
}
-
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- if (likely(vma->vm_mm == current->mm))
- return current->nsproxy->time_ns->vvar_page;
-
- /*
- * VM_PFNMAP | VM_IO protect .fault() handler from being called
- * through interfaces like /proc/$pid/mem or
- * process_vm_{readv,writev}() as long as there's no .access()
- * in special_mapping_vmops.
- * For more details check_vma_flags() and __access_remote_vm()
- */
- WARN(1, "vvar_page accessed remotely");
-
- return NULL;
-}
-#else
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- return NULL;
-}
#endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile
index f2e065671e4d..06e6b27f3bcc 100644
--- a/arch/riscv/kernel/vdso/Makefile
+++ b/arch/riscv/kernel/vdso/Makefile
@@ -17,6 +17,7 @@ vdso-syms += flush_icache
obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o
ccflags-y := -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y)
@@ -28,9 +29,12 @@ obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
obj-y += vdso.o
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+ifneq ($(filter vgettimeofday, $(vdso-syms)),)
+CPPFLAGS_vdso.lds += -DHAS_VGETTIMEOFDAY
+endif
# Disable -pg to prevent insert call site
-CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os
+CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE)
# Disable profiling and instrumentation for VDSO code
GCOV_PROFILE := n
diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S
index 01d94aae5bf5..150b1a572e61 100644
--- a/arch/riscv/kernel/vdso/vdso.lds.S
+++ b/arch/riscv/kernel/vdso/vdso.lds.S
@@ -68,9 +68,11 @@ VERSION
LINUX_4.15 {
global:
__vdso_rt_sigreturn;
+#ifdef HAS_VGETTIMEOFDAY
__vdso_gettimeofday;
__vdso_clock_gettime;
__vdso_clock_getres;
+#endif
__vdso_getcpu;
__vdso_flush_icache;
local: *;
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index b56a0a75533f..50a1b6edd491 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -262,7 +262,6 @@ static void __init setup_bootmem(void)
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
}
- early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(dma32_phys_limit);
if (IS_ENABLED(CONFIG_64BIT))
hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 318fce77601d..7fd08755a1f9 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -26,6 +26,10 @@ config GENERIC_BUG
config GENERIC_BUG_RELATIVE_POINTERS
def_bool y
+config GENERIC_CSUM
+ bool
+ default y if KASAN
+
config GENERIC_LOCKBREAK
def_bool y if PREEMPTION
@@ -73,6 +77,7 @@ config S390
select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_KCOV
select ARCH_HAS_MEM_ENCRYPT
+ select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_SCALED_CPUTIME
select ARCH_HAS_SET_MEMORY
@@ -121,6 +126,7 @@ config S390
select ARCH_WANTS_NO_INSTR
select ARCH_WANT_DEFAULT_BPF_JIT
select ARCH_WANT_IPC_PARSE_VERSION
+ select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
select BUILDTIME_TABLE_SORT
select CLONE_BACKWARDS2
select DMA_OPS if PCI
@@ -196,6 +202,7 @@ config S390
select HAVE_RSEQ
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
+ select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING
@@ -207,6 +214,7 @@ config S390
select MMU_GATHER_MERGE_VMAS
select MODULES_USE_ELF_RELA
select NEED_DMA_MAP_STATE if PCI
+ select NEED_PER_CPU_EMBED_FIRST_CHUNK
select NEED_SG_DMA_LENGTH if PCI
select OLD_SIGACTION
select OLD_SIGSUSPEND3
@@ -568,8 +576,7 @@ config EXPOLINE_FULL
endchoice
config RELOCATABLE
- bool "Build a relocatable kernel"
- default y
+ def_bool y
help
This builds a kernel image that retains relocation information
so it can be loaded at an arbitrary address.
@@ -578,10 +585,11 @@ config RELOCATABLE
bootup process.
The relocations make the kernel image about 15% larger (compressed
10%), but are discarded at runtime.
+ Note: this option exists only for documentation purposes, please do
+ not remove it.
config RANDOMIZE_BASE
bool "Randomize the address of the kernel image (KASLR)"
- depends on RELOCATABLE
default y
help
In support of Kernel Address Space Layout Randomization (KASLR),
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index de6d8b2ea4d8..b3235ab0ace8 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -14,10 +14,8 @@ KBUILD_AFLAGS_MODULE += -fPIC
KBUILD_CFLAGS_MODULE += -fPIC
KBUILD_AFLAGS += -m64
KBUILD_CFLAGS += -m64
-ifeq ($(CONFIG_RELOCATABLE),y)
KBUILD_CFLAGS += -fPIE
LDFLAGS_vmlinux := -pie
-endif
aflags_dwarf := -Wa,-gdwarf-2
KBUILD_AFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -D__ASSEMBLY__
ifndef CONFIG_AS_IS_LLVM
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index d74a4c7d5df6..c0fd29133f27 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -26,8 +26,6 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/workqueue.h>
-#include <linux/suspend.h>
-#include <linux/platform_device.h>
#include <asm/appldata.h>
#include <asm/vtimer.h>
#include <linux/uaccess.h>
@@ -44,8 +42,6 @@
#define TOD_MICRO 0x01000 /* nr. of TOD clock units
for 1 microsecond */
-static struct platform_device *appldata_pdev;
-
/*
* /proc entries (sysctl)
*/
@@ -88,7 +84,6 @@ static struct vtimer_list appldata_timer;
static DEFINE_SPINLOCK(appldata_timer_lock);
static int appldata_interval = APPLDATA_CPU_INTERVAL;
static int appldata_timer_active;
-static int appldata_timer_suspended = 0;
/*
* Work queue
@@ -412,88 +407,6 @@ void appldata_unregister_ops(struct appldata_ops *ops)
/********************** module-ops management <END> **************************/
-/**************************** suspend / resume *******************************/
-static int appldata_freeze(struct device *dev)
-{
- struct appldata_ops *ops;
- int rc;
- struct list_head *lh;
-
- spin_lock(&appldata_timer_lock);
- if (appldata_timer_active) {
- __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
- appldata_timer_suspended = 1;
- }
- spin_unlock(&appldata_timer_lock);
-
- mutex_lock(&appldata_ops_mutex);
- list_for_each(lh, &appldata_ops_list) {
- ops = list_entry(lh, struct appldata_ops, list);
- if (ops->active == 1) {
- rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
- (unsigned long) ops->data, ops->size,
- ops->mod_lvl);
- if (rc != 0)
- pr_err("Stopping the data collection for %s "
- "failed with rc=%d\n", ops->name, rc);
- }
- }
- mutex_unlock(&appldata_ops_mutex);
- return 0;
-}
-
-static int appldata_restore(struct device *dev)
-{
- struct appldata_ops *ops;
- int rc;
- struct list_head *lh;
-
- spin_lock(&appldata_timer_lock);
- if (appldata_timer_suspended) {
- __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
- appldata_timer_suspended = 0;
- }
- spin_unlock(&appldata_timer_lock);
-
- mutex_lock(&appldata_ops_mutex);
- list_for_each(lh, &appldata_ops_list) {
- ops = list_entry(lh, struct appldata_ops, list);
- if (ops->active == 1) {
- ops->callback(ops->data); // init record
- rc = appldata_diag(ops->record_nr,
- APPLDATA_START_INTERVAL_REC,
- (unsigned long) ops->data, ops->size,
- ops->mod_lvl);
- if (rc != 0) {
- pr_err("Starting the data collection for %s "
- "failed with rc=%d\n", ops->name, rc);
- }
- }
- }
- mutex_unlock(&appldata_ops_mutex);
- return 0;
-}
-
-static int appldata_thaw(struct device *dev)
-{
- return appldata_restore(dev);
-}
-
-static const struct dev_pm_ops appldata_pm_ops = {
- .freeze = appldata_freeze,
- .thaw = appldata_thaw,
- .restore = appldata_restore,
-};
-
-static struct platform_driver appldata_pdrv = {
- .driver = {
- .name = "appldata",
- .pm = &appldata_pm_ops,
- },
-};
-/************************* suspend / resume <END> ****************************/
-
-
/******************************* init / exit *********************************/
/*
@@ -503,36 +416,14 @@ static struct platform_driver appldata_pdrv = {
*/
static int __init appldata_init(void)
{
- int rc;
-
init_virt_timer(&appldata_timer);
appldata_timer.function = appldata_timer_function;
appldata_timer.data = (unsigned long) &appldata_work;
-
- rc = platform_driver_register(&appldata_pdrv);
- if (rc)
- return rc;
-
- appldata_pdev = platform_device_register_simple("appldata", -1, NULL,
- 0);
- if (IS_ERR(appldata_pdev)) {
- rc = PTR_ERR(appldata_pdev);
- goto out_driver;
- }
appldata_wq = alloc_ordered_workqueue("appldata", 0);
- if (!appldata_wq) {
- rc = -ENOMEM;
- goto out_device;
- }
-
+ if (!appldata_wq)
+ return -ENOMEM;
appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
return 0;
-
-out_device:
- platform_device_unregister(appldata_pdev);
-out_driver:
- platform_driver_unregister(&appldata_pdrv);
- return rc;
}
__initcall(appldata_init);
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 883357a211a3..d52c3e2e16bc 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -37,9 +37,8 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o
obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
-obj-y += version.o pgm_check_info.o ctype.o ipl_data.o
+obj-y += version.o pgm_check_info.o ctype.o ipl_data.o machine_kexec_reloc.o
obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) += uv.o
-obj-$(CONFIG_RELOCATABLE) += machine_kexec_reloc.o
obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
obj-y += $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o
obj-$(CONFIG_KERNEL_ZSTD) += clz_ctz.o
diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c
index ca78d6162245..c1f8f7999fed 100644
--- a/arch/s390/boot/ipl_parm.c
+++ b/arch/s390/boot/ipl_parm.c
@@ -77,6 +77,9 @@ bool is_ipl_block_dump(void)
if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
return true;
+ if (ipl_block.pb0_hdr.pbt == IPL_PBT_ECKD &&
+ ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
+ return true;
return false;
}
@@ -108,6 +111,11 @@ static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
scp_data_len = ipb->nvme.scp_data_len;
scp_data = ipb->nvme.scp_data;
break;
+ case IPL_PBT_ECKD:
+ scp_data_len = ipb->eckd.scp_data_len;
+ scp_data = ipb->eckd.scp_data;
+ break;
+
default:
goto out;
}
@@ -153,6 +161,7 @@ static void append_ipl_block_parm(void)
break;
case IPL_PBT_FCP:
case IPL_PBT_NVME:
+ case IPL_PBT_ECKD:
rc = ipl_block_get_ascii_scpdata(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 6e7f01ca53e6..47ca3264c023 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -291,8 +291,7 @@ void startup_kernel(void)
clear_bss_section();
copy_bootdata();
- if (IS_ENABLED(CONFIG_RELOCATABLE))
- handle_relocs(__kaslr_offset);
+ handle_relocs(__kaslr_offset);
if (__kaslr_offset) {
/*
diff --git a/arch/s390/configs/btf.config b/arch/s390/configs/btf.config
new file mode 100644
index 000000000000..39227b4511af
--- /dev/null
+++ b/arch/s390/configs/btf.config
@@ -0,0 +1 @@
+CONFIG_DEBUG_INFO_BTF=y
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 2a827002934b..a7b4e1d82758 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -573,8 +573,6 @@ CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_HANGCHECK_TIMER=m
CONFIG_TN3270_FS=y
-# CONFIG_RANDOM_TRUST_CPU is not set
-# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
CONFIG_PPS=m
# CONFIG_PTP_1588_CLOCK is not set
# CONFIG_HWMON is not set
@@ -723,52 +721,42 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_SEQIV=y
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_CRC32=m
-CONFIG_CRYPTO_CRC32_S390=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA512_S390=m
-CONFIG_CRYPTO_SHA1_S390=m
-CONFIG_CRYPTO_SHA256_S390=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SHA3_256_S390=m
-CONFIG_CRYPTO_SHA3_512_S390=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_GHASH_S390=m
CONFIG_CRYPTO_AES_TI=m
-CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_DES_S390=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
CONFIG_CRYPTO_LZ4HC=m
@@ -779,6 +767,16 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_USER_API_RNG=m
CONFIG_CRYPTO_USER_API_AEAD=m
CONFIG_CRYPTO_STATS=y
+CONFIG_CRYPTO_CRC32_S390=y
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
+CONFIG_CRYPTO_GHASH_S390=m
+CONFIG_CRYPTO_AES_S390=m
+CONFIG_CRYPTO_DES_S390=m
+CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_ZCRYPT=m
CONFIG_PKEY=m
CONFIG_CRYPTO_PAES_S390=m
@@ -797,7 +795,6 @@ CONFIG_CMA_SIZE_MBYTES=0
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO_DWARF4=y
-CONFIG_DEBUG_INFO_BTF=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HEADERS_INSTALL=y
CONFIG_DEBUG_SECTION_MISMATCH=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index fb780e80e4c8..2bc2d0fe5774 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -563,8 +563,6 @@ CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_HANGCHECK_TIMER=m
CONFIG_TN3270_FS=y
-# CONFIG_RANDOM_TRUST_CPU is not set
-# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# CONFIG_PTP_1588_CLOCK is not set
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
@@ -707,53 +705,43 @@ CONFIG_CRYPTO_ECDSA=m
CONFIG_CRYPTO_ECRDSA=m
CONFIG_CRYPTO_SM2=m
CONFIG_CRYPTO_CURVE25519=m
-CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_AEGIS128=m
-CONFIG_CRYPTO_SEQIV=y
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_ADIANTUM=m
-CONFIG_CRYPTO_HCTR2=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_CRC32=m
-CONFIG_CRYPTO_CRC32_S390=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_SHA512_S390=m
-CONFIG_CRYPTO_SHA1_S390=m
-CONFIG_CRYPTO_SHA256_S390=m
-CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SHA3_256_S390=m
-CONFIG_CRYPTO_SHA3_512_S390=m
-CONFIG_CRYPTO_SM3_GENERIC=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_GHASH_S390=m
CONFIG_CRYPTO_AES_TI=m
-CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_DES_S390=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_ARIA=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SM4_GENERIC=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
CONFIG_CRYPTO_LZ4HC=m
@@ -764,6 +752,16 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_USER_API_RNG=m
CONFIG_CRYPTO_USER_API_AEAD=m
CONFIG_CRYPTO_STATS=y
+CONFIG_CRYPTO_CRC32_S390=y
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
+CONFIG_CRYPTO_GHASH_S390=m
+CONFIG_CRYPTO_AES_S390=m
+CONFIG_CRYPTO_DES_S390=m
+CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_ZCRYPT=m
CONFIG_PKEY=m
CONFIG_CRYPTO_PAES_S390=m
@@ -781,7 +779,6 @@ CONFIG_CMA_SIZE_MBYTES=0
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO_DWARF4=y
-CONFIG_DEBUG_INFO_BTF=y
CONFIG_GDB_SCRIPTS=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/s390/configs/kasan.config b/arch/s390/configs/kasan.config
new file mode 100644
index 000000000000..700a8b25c3ff
--- /dev/null
+++ b/arch/s390/configs/kasan.config
@@ -0,0 +1,3 @@
+CONFIG_KASAN=y
+CONFIG_KASAN_INLINE=y
+CONFIG_KASAN_VMALLOC=y
diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig
index a5576b8d4081..ae14ab0b864d 100644
--- a/arch/s390/configs/zfcpdump_defconfig
+++ b/arch/s390/configs/zfcpdump_defconfig
@@ -58,7 +58,6 @@ CONFIG_ZFCP=y
# CONFIG_VMCP is not set
# CONFIG_MONWRITER is not set
# CONFIG_S390_VMUR is not set
-# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# CONFIG_HID is not set
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set
@@ -74,7 +73,6 @@ CONFIG_PRINTK_TIME=y
# CONFIG_SYMBOLIC_ERRNAME is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO_DWARF4=y
-CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_FS=y
CONFIG_PANIC_ON_OOPS=y
# CONFIG_SCHED_DEBUG is not set
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 6511d15ace45..c3be533c4cd3 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -68,14 +68,6 @@ static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
}
-static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
-{
- if (type == DIAG204_INFO_SIMPLE)
- return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
- else /* DIAG204_INFO_EXT */
- return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
-}
-
/* Partition header */
static inline int part_hdr__size(enum diag204_format type)
diff --git a/arch/s390/include/asm/bugs.h b/arch/s390/include/asm/bugs.h
deleted file mode 100644
index aa42a179be33..000000000000
--- a/arch/s390/include/asm/bugs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * S390 version
- * Copyright IBM Corp. 1999
- * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Derived from "include/asm-i386/bugs.h"
- * Copyright (C) 1994 Linus Torvalds
- */
-
-/*
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- * void check_bugs(void);
- */
-
-static inline void check_bugs(void)
-{
- /* s390 has no bugs ... */
-}
diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h
index cdd19d326345..d977a3a2f619 100644
--- a/arch/s390/include/asm/checksum.h
+++ b/arch/s390/include/asm/checksum.h
@@ -12,6 +12,12 @@
#ifndef _S390_CHECKSUM_H
#define _S390_CHECKSUM_H
+#ifdef CONFIG_GENERIC_CSUM
+
+#include <asm-generic/checksum.h>
+
+#else /* CONFIG_GENERIC_CSUM */
+
#include <linux/uaccess.h>
#include <linux/in6.h>
@@ -129,4 +135,5 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
return csum_fold((__force __wsum)(sum >> 32));
}
+#endif /* CONFIG_GENERIC_CSUM */
#endif /* _S390_CHECKSUM_H */
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index 6f80ec9c04be..e5c5cb1207e2 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -54,12 +54,33 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *
return NULL;
}
-static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *fregs,
- unsigned long ip)
+static __always_inline unsigned long
+ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs)
+{
+ return fregs->regs.psw.addr;
+}
+
+static __always_inline void
+ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+ unsigned long ip)
{
fregs->regs.psw.addr = ip;
}
+#define ftrace_regs_get_argument(fregs, n) \
+ regs_get_kernel_argument(&(fregs)->regs, n)
+#define ftrace_regs_get_stack_pointer(fregs) \
+ kernel_stack_pointer(&(fregs)->regs)
+#define ftrace_regs_return_value(fregs) \
+ regs_return_value(&(fregs)->regs)
+#define ftrace_regs_set_return_value(fregs, ret) \
+ regs_set_return_value(&(fregs)->regs, ret)
+#define ftrace_override_function_with_return(fregs) \
+ override_function_with_return(&(fregs)->regs)
+#define ftrace_regs_query_register_offset(name) \
+ regs_query_register_offset(name)
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
/*
* When an ftrace registered caller is tracing a function that is
* also set by a register_ftrace_direct() call, it needs to be
@@ -67,10 +88,12 @@ static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *f
* place the direct caller in the ORIG_GPR2 part of pt_regs. This
* tells the ftrace_caller that there's a direct caller.
*/
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
+static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
{
+ struct pt_regs *regs = &fregs->regs;
regs->orig_gpr2 = addr;
}
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
/*
* Even though the system call numbers are identical for s390/s390x a
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index a405b6bb89fb..b0d00032479d 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -22,6 +22,7 @@ struct ipl_parameter_block {
struct ipl_pb0_common common;
struct ipl_pb0_fcp fcp;
struct ipl_pb0_ccw ccw;
+ struct ipl_pb0_eckd eckd;
struct ipl_pb0_nvme nvme;
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
};
@@ -41,6 +42,10 @@ struct ipl_parameter_block {
sizeof(struct ipl_pb0_ccw))
#define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
+#define IPL_BP_ECKD_LEN (sizeof(struct ipl_pl_hdr) + \
+ sizeof(struct ipl_pb0_eckd))
+#define IPL_BP0_ECKD_LEN (sizeof(struct ipl_pb0_eckd))
+
#define IPL_MAX_SUPPORTED_VERSION (0)
#define IPL_RB_CERT_UNKNOWN ((unsigned short)-1)
@@ -68,6 +73,8 @@ enum ipl_type {
IPL_TYPE_NSS = 16,
IPL_TYPE_NVME = 32,
IPL_TYPE_NVME_DUMP = 64,
+ IPL_TYPE_ECKD = 128,
+ IPL_TYPE_ECKD_DUMP = 256,
};
struct ipl_info
@@ -79,6 +86,9 @@ struct ipl_info
} ccw;
struct {
struct ccw_dev_id dev_id;
+ } eckd;
+ struct {
+ struct ccw_dev_id dev_id;
u64 wwpn;
u64 lun;
} fcp;
@@ -99,6 +109,7 @@ extern void set_os_info_reipl_block(void);
static inline bool is_ipl_type_dump(void)
{
return (ipl_info.type == IPL_TYPE_FCP_DUMP) ||
+ (ipl_info.type == IPL_TYPE_ECKD_DUMP) ||
(ipl_info.type == IPL_TYPE_NVME_DUMP);
}
diff --git a/arch/s390/include/asm/pai.h b/arch/s390/include/asm/pai.h
index 1a8a6b15d121..7d1888e3dee6 100644
--- a/arch/s390/include/asm/pai.h
+++ b/arch/s390/include/asm/pai.h
@@ -75,4 +75,10 @@ static __always_inline void pai_kernel_exit(struct pt_regs *regs)
WRITE_ONCE(S390_lowcore.ccd, S390_lowcore.ccd & ~PAI_CRYPTO_KERNEL_OFFSET);
}
+enum paievt_mode {
+ PAI_MODE_NONE,
+ PAI_MODE_SAMPLING,
+ PAI_MODE_COUNTING,
+};
+
#endif
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index f1cb9391190d..11e901286414 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -763,6 +763,7 @@ static inline int pmd_dirty(pmd_t pmd)
return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0;
}
+#define pmd_young pmd_young
static inline int pmd_young(pmd_t pmd)
{
return (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0;
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 87be3e855bf7..c907f747d2a0 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -199,7 +199,16 @@ unsigned long __get_wchan(struct task_struct *p);
/* Has task runtime instrumentation enabled ? */
#define is_ri_task(tsk) (!!(tsk)->thread.ri_cb)
-register unsigned long current_stack_pointer asm("r15");
+/* avoid using global register due to gcc bug in versions < 8.4 */
+#define current_stack_pointer (__current_stack_pointer())
+
+static __always_inline unsigned long __current_stack_pointer(void)
+{
+ unsigned long sp;
+
+ asm volatile("lgr %0,15" : "=d" (sp));
+ return sp;
+}
static __always_inline unsigned short stap(void)
{
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 9d4c7f71e070..dac7da88f61f 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -87,6 +87,7 @@ struct sclp_info {
unsigned char has_gisaf : 1;
unsigned char has_diag318 : 1;
unsigned char has_sipl : 1;
+ unsigned char has_sipl_eckd : 1;
unsigned char has_dirq : 1;
unsigned char has_iplcc : 1;
unsigned char has_zpci_lsi : 1;
@@ -131,6 +132,7 @@ void sclp_early_get_ipl_info(struct sclp_ipl_info *info);
void sclp_early_detect(void);
void sclp_early_printk(const char *s);
void __sclp_early_printk(const char *s, unsigned int len);
+void sclp_emergency_printk(const char *s);
int sclp_early_get_memsize(unsigned long *mem);
int sclp_early_get_hsa_size(unsigned long *hsa_size);
diff --git a/arch/s390/include/asm/serial.h b/arch/s390/include/asm/serial.h
deleted file mode 100644
index aaf85a69061c..000000000000
--- a/arch/s390/include/asm/serial.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_S390_SERIAL_H
-#define _ASM_S390_SERIAL_H
-
-#define BASE_BAUD 0
-
-#endif /* _ASM_S390_SERIAL_H */
diff --git a/arch/s390/include/asm/shmparam.h b/arch/s390/include/asm/shmparam.h
deleted file mode 100644
index e75d45649c54..000000000000
--- a/arch/s390/include/asm/shmparam.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * S390 version
- *
- * Derived from "include/asm-i386/shmparam.h"
- */
-#ifndef _ASM_S390_SHMPARAM_H
-#define _ASM_S390_SHMPARAM_H
-
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
-
-#endif /* _ASM_S390_SHMPARAM_H */
diff --git a/arch/s390/include/asm/vga.h b/arch/s390/include/asm/vga.h
deleted file mode 100644
index 605dc46bac5e..000000000000
--- a/arch/s390/include/asm/vga.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_S390_VGA_H
-#define _ASM_S390_VGA_H
-
-/* Avoid compile errors due to missing asm/vga.h */
-
-#endif /* _ASM_S390_VGA_H */
diff --git a/arch/s390/include/asm/vx-insn-asm.h b/arch/s390/include/asm/vx-insn-asm.h
new file mode 100644
index 000000000000..360f8b36d962
--- /dev/null
+++ b/arch/s390/include/asm/vx-insn-asm.h
@@ -0,0 +1,681 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for Vector Instructions
+ *
+ * Assembler macros to generate .byte/.word code for particular
+ * vector instructions that are supported by recent binutils (>= 2.26) only.
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+
+#ifndef __ASM_S390_VX_INSN_INTERNAL_H
+#define __ASM_S390_VX_INSN_INTERNAL_H
+
+#ifndef __ASM_S390_VX_INSN_H
+#error only <asm/vx-insn.h> can be included directly
+#endif
+
+#ifdef __ASSEMBLY__
+
+/* Macros to generate vector instruction byte code */
+
+/* GR_NUM - Retrieve general-purpose register number
+ *
+ * @opd: Operand to store register number
+ * @r64: String designation register in the format "%rN"
+ */
+.macro GR_NUM opd gr
+ \opd = 255
+ .ifc \gr,%r0
+ \opd = 0
+ .endif
+ .ifc \gr,%r1
+ \opd = 1
+ .endif
+ .ifc \gr,%r2
+ \opd = 2
+ .endif
+ .ifc \gr,%r3
+ \opd = 3
+ .endif
+ .ifc \gr,%r4
+ \opd = 4
+ .endif
+ .ifc \gr,%r5
+ \opd = 5
+ .endif
+ .ifc \gr,%r6
+ \opd = 6
+ .endif
+ .ifc \gr,%r7
+ \opd = 7
+ .endif
+ .ifc \gr,%r8
+ \opd = 8
+ .endif
+ .ifc \gr,%r9
+ \opd = 9
+ .endif
+ .ifc \gr,%r10
+ \opd = 10
+ .endif
+ .ifc \gr,%r11
+ \opd = 11
+ .endif
+ .ifc \gr,%r12
+ \opd = 12
+ .endif
+ .ifc \gr,%r13
+ \opd = 13
+ .endif
+ .ifc \gr,%r14
+ \opd = 14
+ .endif
+ .ifc \gr,%r15
+ \opd = 15
+ .endif
+ .if \opd == 255
+ \opd = \gr
+ .endif
+.endm
+
+/* VX_NUM - Retrieve vector register number
+ *
+ * @opd: Operand to store register number
+ * @vxr: String designation register in the format "%vN"
+ *
+ * The vector register number is used for as input number to the
+ * instruction and, as well as, to compute the RXB field of the
+ * instruction.
+ */
+.macro VX_NUM opd vxr
+ \opd = 255
+ .ifc \vxr,%v0
+ \opd = 0
+ .endif
+ .ifc \vxr,%v1
+ \opd = 1
+ .endif
+ .ifc \vxr,%v2
+ \opd = 2
+ .endif
+ .ifc \vxr,%v3
+ \opd = 3
+ .endif
+ .ifc \vxr,%v4
+ \opd = 4
+ .endif
+ .ifc \vxr,%v5
+ \opd = 5
+ .endif
+ .ifc \vxr,%v6
+ \opd = 6
+ .endif
+ .ifc \vxr,%v7
+ \opd = 7
+ .endif
+ .ifc \vxr,%v8
+ \opd = 8
+ .endif
+ .ifc \vxr,%v9
+ \opd = 9
+ .endif
+ .ifc \vxr,%v10
+ \opd = 10
+ .endif
+ .ifc \vxr,%v11
+ \opd = 11
+ .endif
+ .ifc \vxr,%v12
+ \opd = 12
+ .endif
+ .ifc \vxr,%v13
+ \opd = 13
+ .endif
+ .ifc \vxr,%v14
+ \opd = 14
+ .endif
+ .ifc \vxr,%v15
+ \opd = 15
+ .endif
+ .ifc \vxr,%v16
+ \opd = 16
+ .endif
+ .ifc \vxr,%v17
+ \opd = 17
+ .endif
+ .ifc \vxr,%v18
+ \opd = 18
+ .endif
+ .ifc \vxr,%v19
+ \opd = 19
+ .endif
+ .ifc \vxr,%v20
+ \opd = 20
+ .endif
+ .ifc \vxr,%v21
+ \opd = 21
+ .endif
+ .ifc \vxr,%v22
+ \opd = 22
+ .endif
+ .ifc \vxr,%v23
+ \opd = 23
+ .endif
+ .ifc \vxr,%v24
+ \opd = 24
+ .endif
+ .ifc \vxr,%v25
+ \opd = 25
+ .endif
+ .ifc \vxr,%v26
+ \opd = 26
+ .endif
+ .ifc \vxr,%v27
+ \opd = 27
+ .endif
+ .ifc \vxr,%v28
+ \opd = 28
+ .endif
+ .ifc \vxr,%v29
+ \opd = 29
+ .endif
+ .ifc \vxr,%v30
+ \opd = 30
+ .endif
+ .ifc \vxr,%v31
+ \opd = 31
+ .endif
+ .if \opd == 255
+ \opd = \vxr
+ .endif
+.endm
+
+/* RXB - Compute most significant bit used vector registers
+ *
+ * @rxb: Operand to store computed RXB value
+ * @v1: First vector register designated operand
+ * @v2: Second vector register designated operand
+ * @v3: Third vector register designated operand
+ * @v4: Fourth vector register designated operand
+ */
+.macro RXB rxb v1 v2=0 v3=0 v4=0
+ \rxb = 0
+ .if \v1 & 0x10
+ \rxb = \rxb | 0x08
+ .endif
+ .if \v2 & 0x10
+ \rxb = \rxb | 0x04
+ .endif
+ .if \v3 & 0x10
+ \rxb = \rxb | 0x02
+ .endif
+ .if \v4 & 0x10
+ \rxb = \rxb | 0x01
+ .endif
+.endm
+
+/* MRXB - Generate Element Size Control and RXB value
+ *
+ * @m: Element size control
+ * @v1: First vector register designated operand (for RXB)
+ * @v2: Second vector register designated operand (for RXB)
+ * @v3: Third vector register designated operand (for RXB)
+ * @v4: Fourth vector register designated operand (for RXB)
+ */
+.macro MRXB m v1 v2=0 v3=0 v4=0
+ rxb = 0
+ RXB rxb, \v1, \v2, \v3, \v4
+ .byte (\m << 4) | rxb
+.endm
+
+/* MRXBOPC - Generate Element Size Control, RXB, and final Opcode fields
+ *
+ * @m: Element size control
+ * @opc: Opcode
+ * @v1: First vector register designated operand (for RXB)
+ * @v2: Second vector register designated operand (for RXB)
+ * @v3: Third vector register designated operand (for RXB)
+ * @v4: Fourth vector register designated operand (for RXB)
+ */
+.macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
+ MRXB \m, \v1, \v2, \v3, \v4
+ .byte \opc
+.endm
+
+/* Vector support instructions */
+
+/* VECTOR GENERATE BYTE MASK */
+.macro VGBM vr imm2
+ VX_NUM v1, \vr
+ .word (0xE700 | ((v1&15) << 4))
+ .word \imm2
+ MRXBOPC 0, 0x44, v1
+.endm
+.macro VZERO vxr
+ VGBM \vxr, 0
+.endm
+.macro VONE vxr
+ VGBM \vxr, 0xFFFF
+.endm
+
+/* VECTOR LOAD VR ELEMENT FROM GR */
+.macro VLVG v, gr, disp, m
+ VX_NUM v1, \v
+ GR_NUM b2, "%r0"
+ GR_NUM r3, \gr
+ .word 0xE700 | ((v1&15) << 4) | r3
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \m, 0x22, v1
+.endm
+.macro VLVGB v, gr, index, base
+ VLVG \v, \gr, \index, \base, 0
+.endm
+.macro VLVGH v, gr, index
+ VLVG \v, \gr, \index, 1
+.endm
+.macro VLVGF v, gr, index
+ VLVG \v, \gr, \index, 2
+.endm
+.macro VLVGG v, gr, index
+ VLVG \v, \gr, \index, 3
+.endm
+
+/* VECTOR LOAD REGISTER */
+.macro VLR v1, v2
+ VX_NUM v1, \v1
+ VX_NUM v2, \v2
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word 0
+ MRXBOPC 0, 0x56, v1, v2
+.endm
+
+/* VECTOR LOAD */
+.macro VL v, disp, index="%r0", base
+ VX_NUM v1, \v
+ GR_NUM x2, \index
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | x2
+ .word (b2 << 12) | (\disp)
+ MRXBOPC 0, 0x06, v1
+.endm
+
+/* VECTOR LOAD ELEMENT */
+.macro VLEx vr1, disp, index="%r0", base, m3, opc
+ VX_NUM v1, \vr1
+ GR_NUM x2, \index
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | x2
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \m3, \opc, v1
+.endm
+.macro VLEB vr1, disp, index="%r0", base, m3
+ VLEx \vr1, \disp, \index, \base, \m3, 0x00
+.endm
+.macro VLEH vr1, disp, index="%r0", base, m3
+ VLEx \vr1, \disp, \index, \base, \m3, 0x01
+.endm
+.macro VLEF vr1, disp, index="%r0", base, m3
+ VLEx \vr1, \disp, \index, \base, \m3, 0x03
+.endm
+.macro VLEG vr1, disp, index="%r0", base, m3
+ VLEx \vr1, \disp, \index, \base, \m3, 0x02
+.endm
+
+/* VECTOR LOAD ELEMENT IMMEDIATE */
+.macro VLEIx vr1, imm2, m3, opc
+ VX_NUM v1, \vr1
+ .word 0xE700 | ((v1&15) << 4)
+ .word \imm2
+ MRXBOPC \m3, \opc, v1
+.endm
+.macro VLEIB vr1, imm2, index
+ VLEIx \vr1, \imm2, \index, 0x40
+.endm
+.macro VLEIH vr1, imm2, index
+ VLEIx \vr1, \imm2, \index, 0x41
+.endm
+.macro VLEIF vr1, imm2, index
+ VLEIx \vr1, \imm2, \index, 0x43
+.endm
+.macro VLEIG vr1, imm2, index
+ VLEIx \vr1, \imm2, \index, 0x42
+.endm
+
+/* VECTOR LOAD GR FROM VR ELEMENT */
+.macro VLGV gr, vr, disp, base="%r0", m
+ GR_NUM r1, \gr
+ GR_NUM b2, \base
+ VX_NUM v3, \vr
+ .word 0xE700 | (r1 << 4) | (v3&15)
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \m, 0x21, v3
+.endm
+.macro VLGVB gr, vr, disp, base="%r0"
+ VLGV \gr, \vr, \disp, \base, 0
+.endm
+.macro VLGVH gr, vr, disp, base="%r0"
+ VLGV \gr, \vr, \disp, \base, 1
+.endm
+.macro VLGVF gr, vr, disp, base="%r0"
+ VLGV \gr, \vr, \disp, \base, 2
+.endm
+.macro VLGVG gr, vr, disp, base="%r0"
+ VLGV \gr, \vr, \disp, \base, 3
+.endm
+
+/* VECTOR LOAD MULTIPLE */
+.macro VLM vfrom, vto, disp, base, hint=3
+ VX_NUM v1, \vfrom
+ VX_NUM v3, \vto
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | (v3&15)
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \hint, 0x36, v1, v3
+.endm
+
+/* VECTOR STORE */
+.macro VST vr1, disp, index="%r0", base
+ VX_NUM v1, \vr1
+ GR_NUM x2, \index
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | (x2&15)
+ .word (b2 << 12) | (\disp)
+ MRXBOPC 0, 0x0E, v1
+.endm
+
+/* VECTOR STORE MULTIPLE */
+.macro VSTM vfrom, vto, disp, base, hint=3
+ VX_NUM v1, \vfrom
+ VX_NUM v3, \vto
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | (v3&15)
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \hint, 0x3E, v1, v3
+.endm
+
+/* VECTOR PERMUTE */
+.macro VPERM vr1, vr2, vr3, vr4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ VX_NUM v4, \vr4
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC (v4&15), 0x8C, v1, v2, v3, v4
+.endm
+
+/* VECTOR UNPACK LOGICAL LOW */
+.macro VUPLL vr1, vr2, m3
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word 0x0000
+ MRXBOPC \m3, 0xD4, v1, v2
+.endm
+.macro VUPLLB vr1, vr2
+ VUPLL \vr1, \vr2, 0
+.endm
+.macro VUPLLH vr1, vr2
+ VUPLL \vr1, \vr2, 1
+.endm
+.macro VUPLLF vr1, vr2
+ VUPLL \vr1, \vr2, 2
+.endm
+
+/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
+.macro VPDI vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0x84, v1, v2, v3
+.endm
+
+/* VECTOR REPLICATE */
+.macro VREP vr1, vr3, imm2, m4
+ VX_NUM v1, \vr1
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v3&15)
+ .word \imm2
+ MRXBOPC \m4, 0x4D, v1, v3
+.endm
+.macro VREPB vr1, vr3, imm2
+ VREP \vr1, \vr3, \imm2, 0
+.endm
+.macro VREPH vr1, vr3, imm2
+ VREP \vr1, \vr3, \imm2, 1
+.endm
+.macro VREPF vr1, vr3, imm2
+ VREP \vr1, \vr3, \imm2, 2
+.endm
+.macro VREPG vr1, vr3, imm2
+ VREP \vr1, \vr3, \imm2, 3
+.endm
+
+/* VECTOR MERGE HIGH */
+.macro VMRH vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0x61, v1, v2, v3
+.endm
+.macro VMRHB vr1, vr2, vr3
+ VMRH \vr1, \vr2, \vr3, 0
+.endm
+.macro VMRHH vr1, vr2, vr3
+ VMRH \vr1, \vr2, \vr3, 1
+.endm
+.macro VMRHF vr1, vr2, vr3
+ VMRH \vr1, \vr2, \vr3, 2
+.endm
+.macro VMRHG vr1, vr2, vr3
+ VMRH \vr1, \vr2, \vr3, 3
+.endm
+
+/* VECTOR MERGE LOW */
+.macro VMRL vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0x60, v1, v2, v3
+.endm
+.macro VMRLB vr1, vr2, vr3
+ VMRL \vr1, \vr2, \vr3, 0
+.endm
+.macro VMRLH vr1, vr2, vr3
+ VMRL \vr1, \vr2, \vr3, 1
+.endm
+.macro VMRLF vr1, vr2, vr3
+ VMRL \vr1, \vr2, \vr3, 2
+.endm
+.macro VMRLG vr1, vr2, vr3
+ VMRL \vr1, \vr2, \vr3, 3
+.endm
+
+
+/* Vector integer instructions */
+
+/* VECTOR AND */
+.macro VN vr1, vr2, vr3
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC 0, 0x68, v1, v2, v3
+.endm
+
+/* VECTOR EXCLUSIVE OR */
+.macro VX vr1, vr2, vr3
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC 0, 0x6D, v1, v2, v3
+.endm
+
+/* VECTOR GALOIS FIELD MULTIPLY SUM */
+.macro VGFM vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0xB4, v1, v2, v3
+.endm
+.macro VGFMB vr1, vr2, vr3
+ VGFM \vr1, \vr2, \vr3, 0
+.endm
+.macro VGFMH vr1, vr2, vr3
+ VGFM \vr1, \vr2, \vr3, 1
+.endm
+.macro VGFMF vr1, vr2, vr3
+ VGFM \vr1, \vr2, \vr3, 2
+.endm
+.macro VGFMG vr1, vr2, vr3
+ VGFM \vr1, \vr2, \vr3, 3
+.endm
+
+/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
+.macro VGFMA vr1, vr2, vr3, vr4, m5
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ VX_NUM v4, \vr4
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12) | (\m5 << 8)
+ MRXBOPC (v4&15), 0xBC, v1, v2, v3, v4
+.endm
+.macro VGFMAB vr1, vr2, vr3, vr4
+ VGFMA \vr1, \vr2, \vr3, \vr4, 0
+.endm
+.macro VGFMAH vr1, vr2, vr3, vr4
+ VGFMA \vr1, \vr2, \vr3, \vr4, 1
+.endm
+.macro VGFMAF vr1, vr2, vr3, vr4
+ VGFMA \vr1, \vr2, \vr3, \vr4, 2
+.endm
+.macro VGFMAG vr1, vr2, vr3, vr4
+ VGFMA \vr1, \vr2, \vr3, \vr4, 3
+.endm
+
+/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
+.macro VSRLB vr1, vr2, vr3
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC 0, 0x7D, v1, v2, v3
+.endm
+
+/* VECTOR REPLICATE IMMEDIATE */
+.macro VREPI vr1, imm2, m3
+ VX_NUM v1, \vr1
+ .word 0xE700 | ((v1&15) << 4)
+ .word \imm2
+ MRXBOPC \m3, 0x45, v1
+.endm
+.macro VREPIB vr1, imm2
+ VREPI \vr1, \imm2, 0
+.endm
+.macro VREPIH vr1, imm2
+ VREPI \vr1, \imm2, 1
+.endm
+.macro VREPIF vr1, imm2
+ VREPI \vr1, \imm2, 2
+.endm
+.macro VREPIG vr1, imm2
+ VREP \vr1, \imm2, 3
+.endm
+
+/* VECTOR ADD */
+.macro VA vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0xF3, v1, v2, v3
+.endm
+.macro VAB vr1, vr2, vr3
+ VA \vr1, \vr2, \vr3, 0
+.endm
+.macro VAH vr1, vr2, vr3
+ VA \vr1, \vr2, \vr3, 1
+.endm
+.macro VAF vr1, vr2, vr3
+ VA \vr1, \vr2, \vr3, 2
+.endm
+.macro VAG vr1, vr2, vr3
+ VA \vr1, \vr2, \vr3, 3
+.endm
+.macro VAQ vr1, vr2, vr3
+ VA \vr1, \vr2, \vr3, 4
+.endm
+
+/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
+.macro VESRAV vr1, vr2, vr3, m4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12)
+ MRXBOPC \m4, 0x7A, v1, v2, v3
+.endm
+
+.macro VESRAVB vr1, vr2, vr3
+ VESRAV \vr1, \vr2, \vr3, 0
+.endm
+.macro VESRAVH vr1, vr2, vr3
+ VESRAV \vr1, \vr2, \vr3, 1
+.endm
+.macro VESRAVF vr1, vr2, vr3
+ VESRAV \vr1, \vr2, \vr3, 2
+.endm
+.macro VESRAVG vr1, vr2, vr3
+ VESRAV \vr1, \vr2, \vr3, 3
+.endm
+
+/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
+.macro VERLL vr1, vr3, disp, base="%r0", m4
+ VX_NUM v1, \vr1
+ VX_NUM v3, \vr3
+ GR_NUM b2, \base
+ .word 0xE700 | ((v1&15) << 4) | (v3&15)
+ .word (b2 << 12) | (\disp)
+ MRXBOPC \m4, 0x33, v1, v3
+.endm
+.macro VERLLB vr1, vr3, disp, base="%r0"
+ VERLL \vr1, \vr3, \disp, \base, 0
+.endm
+.macro VERLLH vr1, vr3, disp, base="%r0"
+ VERLL \vr1, \vr3, \disp, \base, 1
+.endm
+.macro VERLLF vr1, vr3, disp, base="%r0"
+ VERLL \vr1, \vr3, \disp, \base, 2
+.endm
+.macro VERLLG vr1, vr3, disp, base="%r0"
+ VERLL \vr1, \vr3, \disp, \base, 3
+.endm
+
+/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
+.macro VSLDB vr1, vr2, vr3, imm4
+ VX_NUM v1, \vr1
+ VX_NUM v2, \vr2
+ VX_NUM v3, \vr3
+ .word 0xE700 | ((v1&15) << 4) | (v2&15)
+ .word ((v3&15) << 12) | (\imm4)
+ MRXBOPC 0, 0x77, v1, v2, v3
+.endm
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_S390_VX_INSN_INTERNAL_H */
diff --git a/arch/s390/include/asm/vx-insn.h b/arch/s390/include/asm/vx-insn.h
index 95480ed9149e..8c188f1c6d27 100644
--- a/arch/s390/include/asm/vx-insn.h
+++ b/arch/s390/include/asm/vx-insn.h
@@ -2,677 +2,18 @@
/*
* Support for Vector Instructions
*
- * Assembler macros to generate .byte/.word code for particular
- * vector instructions that are supported by recent binutils (>= 2.26) only.
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ * This wrapper header file allows to use the vector instruction macros in
+ * both assembler files as well as in inline assemblies in C files.
*/
#ifndef __ASM_S390_VX_INSN_H
#define __ASM_S390_VX_INSN_H
-#ifdef __ASSEMBLY__
-
-
-/* Macros to generate vector instruction byte code */
-
-/* GR_NUM - Retrieve general-purpose register number
- *
- * @opd: Operand to store register number
- * @r64: String designation register in the format "%rN"
- */
-.macro GR_NUM opd gr
- \opd = 255
- .ifc \gr,%r0
- \opd = 0
- .endif
- .ifc \gr,%r1
- \opd = 1
- .endif
- .ifc \gr,%r2
- \opd = 2
- .endif
- .ifc \gr,%r3
- \opd = 3
- .endif
- .ifc \gr,%r4
- \opd = 4
- .endif
- .ifc \gr,%r5
- \opd = 5
- .endif
- .ifc \gr,%r6
- \opd = 6
- .endif
- .ifc \gr,%r7
- \opd = 7
- .endif
- .ifc \gr,%r8
- \opd = 8
- .endif
- .ifc \gr,%r9
- \opd = 9
- .endif
- .ifc \gr,%r10
- \opd = 10
- .endif
- .ifc \gr,%r11
- \opd = 11
- .endif
- .ifc \gr,%r12
- \opd = 12
- .endif
- .ifc \gr,%r13
- \opd = 13
- .endif
- .ifc \gr,%r14
- \opd = 14
- .endif
- .ifc \gr,%r15
- \opd = 15
- .endif
- .if \opd == 255
- \opd = \gr
- .endif
-.endm
-
-/* VX_NUM - Retrieve vector register number
- *
- * @opd: Operand to store register number
- * @vxr: String designation register in the format "%vN"
- *
- * The vector register number is used for as input number to the
- * instruction and, as well as, to compute the RXB field of the
- * instruction.
- */
-.macro VX_NUM opd vxr
- \opd = 255
- .ifc \vxr,%v0
- \opd = 0
- .endif
- .ifc \vxr,%v1
- \opd = 1
- .endif
- .ifc \vxr,%v2
- \opd = 2
- .endif
- .ifc \vxr,%v3
- \opd = 3
- .endif
- .ifc \vxr,%v4
- \opd = 4
- .endif
- .ifc \vxr,%v5
- \opd = 5
- .endif
- .ifc \vxr,%v6
- \opd = 6
- .endif
- .ifc \vxr,%v7
- \opd = 7
- .endif
- .ifc \vxr,%v8
- \opd = 8
- .endif
- .ifc \vxr,%v9
- \opd = 9
- .endif
- .ifc \vxr,%v10
- \opd = 10
- .endif
- .ifc \vxr,%v11
- \opd = 11
- .endif
- .ifc \vxr,%v12
- \opd = 12
- .endif
- .ifc \vxr,%v13
- \opd = 13
- .endif
- .ifc \vxr,%v14
- \opd = 14
- .endif
- .ifc \vxr,%v15
- \opd = 15
- .endif
- .ifc \vxr,%v16
- \opd = 16
- .endif
- .ifc \vxr,%v17
- \opd = 17
- .endif
- .ifc \vxr,%v18
- \opd = 18
- .endif
- .ifc \vxr,%v19
- \opd = 19
- .endif
- .ifc \vxr,%v20
- \opd = 20
- .endif
- .ifc \vxr,%v21
- \opd = 21
- .endif
- .ifc \vxr,%v22
- \opd = 22
- .endif
- .ifc \vxr,%v23
- \opd = 23
- .endif
- .ifc \vxr,%v24
- \opd = 24
- .endif
- .ifc \vxr,%v25
- \opd = 25
- .endif
- .ifc \vxr,%v26
- \opd = 26
- .endif
- .ifc \vxr,%v27
- \opd = 27
- .endif
- .ifc \vxr,%v28
- \opd = 28
- .endif
- .ifc \vxr,%v29
- \opd = 29
- .endif
- .ifc \vxr,%v30
- \opd = 30
- .endif
- .ifc \vxr,%v31
- \opd = 31
- .endif
- .if \opd == 255
- \opd = \vxr
- .endif
-.endm
-
-/* RXB - Compute most significant bit used vector registers
- *
- * @rxb: Operand to store computed RXB value
- * @v1: First vector register designated operand
- * @v2: Second vector register designated operand
- * @v3: Third vector register designated operand
- * @v4: Fourth vector register designated operand
- */
-.macro RXB rxb v1 v2=0 v3=0 v4=0
- \rxb = 0
- .if \v1 & 0x10
- \rxb = \rxb | 0x08
- .endif
- .if \v2 & 0x10
- \rxb = \rxb | 0x04
- .endif
- .if \v3 & 0x10
- \rxb = \rxb | 0x02
- .endif
- .if \v4 & 0x10
- \rxb = \rxb | 0x01
- .endif
-.endm
-
-/* MRXB - Generate Element Size Control and RXB value
- *
- * @m: Element size control
- * @v1: First vector register designated operand (for RXB)
- * @v2: Second vector register designated operand (for RXB)
- * @v3: Third vector register designated operand (for RXB)
- * @v4: Fourth vector register designated operand (for RXB)
- */
-.macro MRXB m v1 v2=0 v3=0 v4=0
- rxb = 0
- RXB rxb, \v1, \v2, \v3, \v4
- .byte (\m << 4) | rxb
-.endm
-
-/* MRXBOPC - Generate Element Size Control, RXB, and final Opcode fields
- *
- * @m: Element size control
- * @opc: Opcode
- * @v1: First vector register designated operand (for RXB)
- * @v2: Second vector register designated operand (for RXB)
- * @v3: Third vector register designated operand (for RXB)
- * @v4: Fourth vector register designated operand (for RXB)
- */
-.macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
- MRXB \m, \v1, \v2, \v3, \v4
- .byte \opc
-.endm
-
-/* Vector support instructions */
-
-/* VECTOR GENERATE BYTE MASK */
-.macro VGBM vr imm2
- VX_NUM v1, \vr
- .word (0xE700 | ((v1&15) << 4))
- .word \imm2
- MRXBOPC 0, 0x44, v1
-.endm
-.macro VZERO vxr
- VGBM \vxr, 0
-.endm
-.macro VONE vxr
- VGBM \vxr, 0xFFFF
-.endm
-
-/* VECTOR LOAD VR ELEMENT FROM GR */
-.macro VLVG v, gr, disp, m
- VX_NUM v1, \v
- GR_NUM b2, "%r0"
- GR_NUM r3, \gr
- .word 0xE700 | ((v1&15) << 4) | r3
- .word (b2 << 12) | (\disp)
- MRXBOPC \m, 0x22, v1
-.endm
-.macro VLVGB v, gr, index, base
- VLVG \v, \gr, \index, \base, 0
-.endm
-.macro VLVGH v, gr, index
- VLVG \v, \gr, \index, 1
-.endm
-.macro VLVGF v, gr, index
- VLVG \v, \gr, \index, 2
-.endm
-.macro VLVGG v, gr, index
- VLVG \v, \gr, \index, 3
-.endm
-
-/* VECTOR LOAD REGISTER */
-.macro VLR v1, v2
- VX_NUM v1, \v1
- VX_NUM v2, \v2
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word 0
- MRXBOPC 0, 0x56, v1, v2
-.endm
-
-/* VECTOR LOAD */
-.macro VL v, disp, index="%r0", base
- VX_NUM v1, \v
- GR_NUM x2, \index
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | x2
- .word (b2 << 12) | (\disp)
- MRXBOPC 0, 0x06, v1
-.endm
-
-/* VECTOR LOAD ELEMENT */
-.macro VLEx vr1, disp, index="%r0", base, m3, opc
- VX_NUM v1, \vr1
- GR_NUM x2, \index
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | x2
- .word (b2 << 12) | (\disp)
- MRXBOPC \m3, \opc, v1
-.endm
-.macro VLEB vr1, disp, index="%r0", base, m3
- VLEx \vr1, \disp, \index, \base, \m3, 0x00
-.endm
-.macro VLEH vr1, disp, index="%r0", base, m3
- VLEx \vr1, \disp, \index, \base, \m3, 0x01
-.endm
-.macro VLEF vr1, disp, index="%r0", base, m3
- VLEx \vr1, \disp, \index, \base, \m3, 0x03
-.endm
-.macro VLEG vr1, disp, index="%r0", base, m3
- VLEx \vr1, \disp, \index, \base, \m3, 0x02
-.endm
-
-/* VECTOR LOAD ELEMENT IMMEDIATE */
-.macro VLEIx vr1, imm2, m3, opc
- VX_NUM v1, \vr1
- .word 0xE700 | ((v1&15) << 4)
- .word \imm2
- MRXBOPC \m3, \opc, v1
-.endm
-.macro VLEIB vr1, imm2, index
- VLEIx \vr1, \imm2, \index, 0x40
-.endm
-.macro VLEIH vr1, imm2, index
- VLEIx \vr1, \imm2, \index, 0x41
-.endm
-.macro VLEIF vr1, imm2, index
- VLEIx \vr1, \imm2, \index, 0x43
-.endm
-.macro VLEIG vr1, imm2, index
- VLEIx \vr1, \imm2, \index, 0x42
-.endm
-
-/* VECTOR LOAD GR FROM VR ELEMENT */
-.macro VLGV gr, vr, disp, base="%r0", m
- GR_NUM r1, \gr
- GR_NUM b2, \base
- VX_NUM v3, \vr
- .word 0xE700 | (r1 << 4) | (v3&15)
- .word (b2 << 12) | (\disp)
- MRXBOPC \m, 0x21, v3
-.endm
-.macro VLGVB gr, vr, disp, base="%r0"
- VLGV \gr, \vr, \disp, \base, 0
-.endm
-.macro VLGVH gr, vr, disp, base="%r0"
- VLGV \gr, \vr, \disp, \base, 1
-.endm
-.macro VLGVF gr, vr, disp, base="%r0"
- VLGV \gr, \vr, \disp, \base, 2
-.endm
-.macro VLGVG gr, vr, disp, base="%r0"
- VLGV \gr, \vr, \disp, \base, 3
-.endm
-
-/* VECTOR LOAD MULTIPLE */
-.macro VLM vfrom, vto, disp, base, hint=3
- VX_NUM v1, \vfrom
- VX_NUM v3, \vto
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | (v3&15)
- .word (b2 << 12) | (\disp)
- MRXBOPC \hint, 0x36, v1, v3
-.endm
-
-/* VECTOR STORE */
-.macro VST vr1, disp, index="%r0", base
- VX_NUM v1, \vr1
- GR_NUM x2, \index
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | (x2&15)
- .word (b2 << 12) | (\disp)
- MRXBOPC 0, 0x0E, v1
-.endm
-
-/* VECTOR STORE MULTIPLE */
-.macro VSTM vfrom, vto, disp, base, hint=3
- VX_NUM v1, \vfrom
- VX_NUM v3, \vto
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | (v3&15)
- .word (b2 << 12) | (\disp)
- MRXBOPC \hint, 0x3E, v1, v3
-.endm
-
-/* VECTOR PERMUTE */
-.macro VPERM vr1, vr2, vr3, vr4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- VX_NUM v4, \vr4
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC (v4&15), 0x8C, v1, v2, v3, v4
-.endm
-
-/* VECTOR UNPACK LOGICAL LOW */
-.macro VUPLL vr1, vr2, m3
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word 0x0000
- MRXBOPC \m3, 0xD4, v1, v2
-.endm
-.macro VUPLLB vr1, vr2
- VUPLL \vr1, \vr2, 0
-.endm
-.macro VUPLLH vr1, vr2
- VUPLL \vr1, \vr2, 1
-.endm
-.macro VUPLLF vr1, vr2
- VUPLL \vr1, \vr2, 2
-.endm
-
-/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
-.macro VPDI vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0x84, v1, v2, v3
-.endm
-
-/* VECTOR REPLICATE */
-.macro VREP vr1, vr3, imm2, m4
- VX_NUM v1, \vr1
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v3&15)
- .word \imm2
- MRXBOPC \m4, 0x4D, v1, v3
-.endm
-.macro VREPB vr1, vr3, imm2
- VREP \vr1, \vr3, \imm2, 0
-.endm
-.macro VREPH vr1, vr3, imm2
- VREP \vr1, \vr3, \imm2, 1
-.endm
-.macro VREPF vr1, vr3, imm2
- VREP \vr1, \vr3, \imm2, 2
-.endm
-.macro VREPG vr1, vr3, imm2
- VREP \vr1, \vr3, \imm2, 3
-.endm
-
-/* VECTOR MERGE HIGH */
-.macro VMRH vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0x61, v1, v2, v3
-.endm
-.macro VMRHB vr1, vr2, vr3
- VMRH \vr1, \vr2, \vr3, 0
-.endm
-.macro VMRHH vr1, vr2, vr3
- VMRH \vr1, \vr2, \vr3, 1
-.endm
-.macro VMRHF vr1, vr2, vr3
- VMRH \vr1, \vr2, \vr3, 2
-.endm
-.macro VMRHG vr1, vr2, vr3
- VMRH \vr1, \vr2, \vr3, 3
-.endm
-
-/* VECTOR MERGE LOW */
-.macro VMRL vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0x60, v1, v2, v3
-.endm
-.macro VMRLB vr1, vr2, vr3
- VMRL \vr1, \vr2, \vr3, 0
-.endm
-.macro VMRLH vr1, vr2, vr3
- VMRL \vr1, \vr2, \vr3, 1
-.endm
-.macro VMRLF vr1, vr2, vr3
- VMRL \vr1, \vr2, \vr3, 2
-.endm
-.macro VMRLG vr1, vr2, vr3
- VMRL \vr1, \vr2, \vr3, 3
-.endm
-
-
-/* Vector integer instructions */
-
-/* VECTOR AND */
-.macro VN vr1, vr2, vr3
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC 0, 0x68, v1, v2, v3
-.endm
-
-/* VECTOR EXCLUSIVE OR */
-.macro VX vr1, vr2, vr3
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC 0, 0x6D, v1, v2, v3
-.endm
-
-/* VECTOR GALOIS FIELD MULTIPLY SUM */
-.macro VGFM vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0xB4, v1, v2, v3
-.endm
-.macro VGFMB vr1, vr2, vr3
- VGFM \vr1, \vr2, \vr3, 0
-.endm
-.macro VGFMH vr1, vr2, vr3
- VGFM \vr1, \vr2, \vr3, 1
-.endm
-.macro VGFMF vr1, vr2, vr3
- VGFM \vr1, \vr2, \vr3, 2
-.endm
-.macro VGFMG vr1, vr2, vr3
- VGFM \vr1, \vr2, \vr3, 3
-.endm
-
-/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
-.macro VGFMA vr1, vr2, vr3, vr4, m5
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- VX_NUM v4, \vr4
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12) | (\m5 << 8)
- MRXBOPC (v4&15), 0xBC, v1, v2, v3, v4
-.endm
-.macro VGFMAB vr1, vr2, vr3, vr4
- VGFMA \vr1, \vr2, \vr3, \vr4, 0
-.endm
-.macro VGFMAH vr1, vr2, vr3, vr4
- VGFMA \vr1, \vr2, \vr3, \vr4, 1
-.endm
-.macro VGFMAF vr1, vr2, vr3, vr4
- VGFMA \vr1, \vr2, \vr3, \vr4, 2
-.endm
-.macro VGFMAG vr1, vr2, vr3, vr4
- VGFMA \vr1, \vr2, \vr3, \vr4, 3
-.endm
-
-/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
-.macro VSRLB vr1, vr2, vr3
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC 0, 0x7D, v1, v2, v3
-.endm
-
-/* VECTOR REPLICATE IMMEDIATE */
-.macro VREPI vr1, imm2, m3
- VX_NUM v1, \vr1
- .word 0xE700 | ((v1&15) << 4)
- .word \imm2
- MRXBOPC \m3, 0x45, v1
-.endm
-.macro VREPIB vr1, imm2
- VREPI \vr1, \imm2, 0
-.endm
-.macro VREPIH vr1, imm2
- VREPI \vr1, \imm2, 1
-.endm
-.macro VREPIF vr1, imm2
- VREPI \vr1, \imm2, 2
-.endm
-.macro VREPIG vr1, imm2
- VREP \vr1, \imm2, 3
-.endm
-
-/* VECTOR ADD */
-.macro VA vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0xF3, v1, v2, v3
-.endm
-.macro VAB vr1, vr2, vr3
- VA \vr1, \vr2, \vr3, 0
-.endm
-.macro VAH vr1, vr2, vr3
- VA \vr1, \vr2, \vr3, 1
-.endm
-.macro VAF vr1, vr2, vr3
- VA \vr1, \vr2, \vr3, 2
-.endm
-.macro VAG vr1, vr2, vr3
- VA \vr1, \vr2, \vr3, 3
-.endm
-.macro VAQ vr1, vr2, vr3
- VA \vr1, \vr2, \vr3, 4
-.endm
-
-/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
-.macro VESRAV vr1, vr2, vr3, m4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12)
- MRXBOPC \m4, 0x7A, v1, v2, v3
-.endm
-
-.macro VESRAVB vr1, vr2, vr3
- VESRAV \vr1, \vr2, \vr3, 0
-.endm
-.macro VESRAVH vr1, vr2, vr3
- VESRAV \vr1, \vr2, \vr3, 1
-.endm
-.macro VESRAVF vr1, vr2, vr3
- VESRAV \vr1, \vr2, \vr3, 2
-.endm
-.macro VESRAVG vr1, vr2, vr3
- VESRAV \vr1, \vr2, \vr3, 3
-.endm
+#include <asm/vx-insn-asm.h>
-/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
-.macro VERLL vr1, vr3, disp, base="%r0", m4
- VX_NUM v1, \vr1
- VX_NUM v3, \vr3
- GR_NUM b2, \base
- .word 0xE700 | ((v1&15) << 4) | (v3&15)
- .word (b2 << 12) | (\disp)
- MRXBOPC \m4, 0x33, v1, v3
-.endm
-.macro VERLLB vr1, vr3, disp, base="%r0"
- VERLL \vr1, \vr3, \disp, \base, 0
-.endm
-.macro VERLLH vr1, vr3, disp, base="%r0"
- VERLL \vr1, \vr3, \disp, \base, 1
-.endm
-.macro VERLLF vr1, vr3, disp, base="%r0"
- VERLL \vr1, \vr3, \disp, \base, 2
-.endm
-.macro VERLLG vr1, vr3, disp, base="%r0"
- VERLL \vr1, \vr3, \disp, \base, 3
-.endm
+#ifndef __ASSEMBLY__
-/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
-.macro VSLDB vr1, vr2, vr3, imm4
- VX_NUM v1, \vr1
- VX_NUM v2, \vr2
- VX_NUM v3, \vr3
- .word 0xE700 | ((v1&15) << 4) | (v2&15)
- .word ((v3&15) << 12) | (\imm4)
- MRXBOPC 0, 0x77, v1, v2, v3
-.endm
+asm(".include \"asm/vx-insn-asm.h\"\n");
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLY__ */
#endif /* __ASM_S390_VX_INSN_H */
diff --git a/arch/s390/include/uapi/asm/ipl.h b/arch/s390/include/uapi/asm/ipl.h
index d1ecd5d722a0..2cd28af50dd4 100644
--- a/arch/s390/include/uapi/asm/ipl.h
+++ b/arch/s390/include/uapi/asm/ipl.h
@@ -27,6 +27,7 @@ enum ipl_pbt {
IPL_PBT_FCP = 0,
IPL_PBT_SCP_DATA = 1,
IPL_PBT_CCW = 2,
+ IPL_PBT_ECKD = 3,
IPL_PBT_NVME = 4,
};
@@ -111,6 +112,34 @@ struct ipl_pb0_ccw {
__u8 reserved5[8];
} __packed;
+/* IPL Parameter Block 0 for ECKD */
+struct ipl_pb0_eckd {
+ __u32 len;
+ __u8 pbt;
+ __u8 reserved1[3];
+ __u32 reserved2[78];
+ __u8 opt;
+ __u8 reserved4[4];
+ __u8 reserved5:5;
+ __u8 ssid:3;
+ __u16 devno;
+ __u32 reserved6[5];
+ __u32 bootprog;
+ __u8 reserved7[12];
+ struct {
+ __u16 cyl;
+ __u8 head;
+ __u8 record;
+ __u32 reserved;
+ } br_chr __packed;
+ __u32 scp_data_len;
+ __u8 reserved8[260];
+ __u8 scp_data[];
+} __packed;
+
+#define IPL_PB0_ECKD_OPT_IPL 0x10
+#define IPL_PB0_ECKD_OPT_DUMP 0x20
+
#define IPL_PB0_CCW_VM_FLAG_NSS 0x80
#define IPL_PB0_CCW_VM_FLAG_VP 0x40
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index dd74fe664ed1..c13b1455ec8c 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -46,7 +46,7 @@ struct save_area {
u64 fprs[16];
u32 fpc;
u32 prefix;
- u64 todpreg;
+ u32 todpreg;
u64 timer;
u64 todcmp;
u64 vxrs_low[16];
@@ -153,7 +153,7 @@ int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
kvec.iov_base = dst;
kvec.iov_len = count;
- iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
if (copy_oldmem_iter(&iter, src, count) < count)
return -EFAULT;
return 0;
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index d7a82066a638..b376f0377a2c 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -92,7 +92,7 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
char *out_buf, const char *in_buf);
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
- char *out_buf, debug_sprintf_entry_t *curr_event);
+ char *out_buf, const char *inbuf);
static void debug_areas_swap(debug_info_t *a, debug_info_t *b);
static void debug_events_append(debug_info_t *dest, debug_info_t *src);
@@ -139,7 +139,7 @@ struct debug_view debug_sprintf_view = {
"sprintf",
NULL,
&debug_dflt_header_fn,
- (debug_format_proc_t *)&debug_sprintf_format_fn,
+ &debug_sprintf_format_fn,
NULL,
NULL
};
@@ -1532,8 +1532,9 @@ EXPORT_SYMBOL(debug_dflt_header_fn);
#define DEBUG_SPRINTF_MAX_ARGS 10
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
- char *out_buf, debug_sprintf_entry_t *curr_event)
+ char *out_buf, const char *inbuf)
{
+ debug_sprintf_entry_t *curr_event = (debug_sprintf_entry_t *)inbuf;
int num_longs, num_used_args = 0, i, rc = 0;
int index[DEBUG_SPRINTF_MAX_ARGS];
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index d2a1f2f4f5b8..e0d11f3adfcc 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -122,24 +122,6 @@ _LPP_OFFSET = __LC_LPP
"jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", 82
.endm
- /*
- * The CHKSTG macro jumps to the provided label in case the
- * machine check interruption code reports one of unrecoverable
- * storage errors:
- * - Storage error uncorrected
- * - Storage key error uncorrected
- * - Storage degradation with Failing-storage-address validity
- */
- .macro CHKSTG errlabel
- TSTMSK __LC_MCCK_CODE,(MCCK_CODE_STG_ERROR|MCCK_CODE_STG_KEY_ERROR)
- jnz \errlabel
- TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_DEGRAD
- jz .Loklabel\@
- TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_FAIL_ADDR
- jnz \errlabel
-.Loklabel\@:
- .endm
-
#if IS_ENABLED(CONFIG_KVM)
/*
* The OUTSIDE macro jumps to the provided label in case the value
@@ -546,26 +528,18 @@ ENTRY(mcck_int_handler)
3: TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_MWP_VALID
jno .Lmcck_panic
tmhh %r8,0x0001 # interrupting from user ?
- jnz 6f
+ jnz .Lmcck_user
TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
jno .Lmcck_panic
#if IS_ENABLED(CONFIG_KVM)
- OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f
+ OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack
OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f
oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
- j 5f
-4: CHKSTG .Lmcck_panic
-5: larl %r14,.Lstosm_tmp
- stosm 0(%r14),0x04 # turn dat on, keep irqs off
- BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
+4: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
SIEEXIT
j .Lmcck_stack
#endif
-6: CHKSTG .Lmcck_panic
- larl %r14,.Lstosm_tmp
- stosm 0(%r14),0x04 # turn dat on, keep irqs off
- tmhh %r8,0x0001 # interrupting from user ?
- jz .Lmcck_stack
+.Lmcck_user:
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
.Lmcck_stack:
lg %r15,__LC_MCCK_STACK
diff --git a/arch/s390/kernel/fpu.c b/arch/s390/kernel/fpu.c
index d864c9a325e2..4666b29ac8a1 100644
--- a/arch/s390/kernel/fpu.c
+++ b/arch/s390/kernel/fpu.c
@@ -10,8 +10,7 @@
#include <linux/sched.h>
#include <asm/fpu/types.h>
#include <asm/fpu/api.h>
-
-asm(".include \"asm/vx-insn.h\"\n");
+#include <asm/vx-insn.h>
void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
{
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 325cbf69ebbd..fbd646dbf440 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/kstrtox.h>
#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/ctype.h>
@@ -39,6 +40,8 @@
#define IPL_UNKNOWN_STR "unknown"
#define IPL_CCW_STR "ccw"
+#define IPL_ECKD_STR "eckd"
+#define IPL_ECKD_DUMP_STR "eckd_dump"
#define IPL_FCP_STR "fcp"
#define IPL_FCP_DUMP_STR "fcp_dump"
#define IPL_NVME_STR "nvme"
@@ -46,6 +49,7 @@
#define IPL_NSS_STR "nss"
#define DUMP_CCW_STR "ccw"
+#define DUMP_ECKD_STR "eckd"
#define DUMP_FCP_STR "fcp"
#define DUMP_NVME_STR "nvme"
#define DUMP_NONE_STR "none"
@@ -92,6 +96,10 @@ static char *ipl_type_str(enum ipl_type type)
switch (type) {
case IPL_TYPE_CCW:
return IPL_CCW_STR;
+ case IPL_TYPE_ECKD:
+ return IPL_ECKD_STR;
+ case IPL_TYPE_ECKD_DUMP:
+ return IPL_ECKD_DUMP_STR;
case IPL_TYPE_FCP:
return IPL_FCP_STR;
case IPL_TYPE_FCP_DUMP:
@@ -113,6 +121,7 @@ enum dump_type {
DUMP_TYPE_CCW = 2,
DUMP_TYPE_FCP = 4,
DUMP_TYPE_NVME = 8,
+ DUMP_TYPE_ECKD = 16,
};
static char *dump_type_str(enum dump_type type)
@@ -122,6 +131,8 @@ static char *dump_type_str(enum dump_type type)
return DUMP_NONE_STR;
case DUMP_TYPE_CCW:
return DUMP_CCW_STR;
+ case DUMP_TYPE_ECKD:
+ return DUMP_ECKD_STR;
case DUMP_TYPE_FCP:
return DUMP_FCP_STR;
case DUMP_TYPE_NVME:
@@ -147,6 +158,7 @@ static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
static struct ipl_parameter_block *reipl_block_fcp;
static struct ipl_parameter_block *reipl_block_nvme;
static struct ipl_parameter_block *reipl_block_ccw;
+static struct ipl_parameter_block *reipl_block_eckd;
static struct ipl_parameter_block *reipl_block_nss;
static struct ipl_parameter_block *reipl_block_actual;
@@ -155,12 +167,14 @@ static enum dump_type dump_type = DUMP_TYPE_NONE;
static struct ipl_parameter_block *dump_block_fcp;
static struct ipl_parameter_block *dump_block_nvme;
static struct ipl_parameter_block *dump_block_ccw;
+static struct ipl_parameter_block *dump_block_eckd;
static struct sclp_ipl_info sclp_ipl_info;
static bool reipl_nvme_clear;
static bool reipl_fcp_clear;
static bool reipl_ccw_clear;
+static bool reipl_eckd_clear;
static inline int __diag308(unsigned long subcode, void *addr)
{
@@ -218,14 +232,14 @@ 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), \
+ __ATTR(_name, 0644, \
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 = \
- __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL)
+ __ATTR(_name, 0444, sys_##_prefix##_##_name##_show, NULL)
#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \
@@ -240,7 +254,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
return len; \
} \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
- __ATTR(_name,(S_IRUGO | S_IWUSR), \
+ __ATTR(_name, 0644, \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store)
@@ -255,7 +269,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
return len; \
} \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
- __ATTR(_name,(S_IRUGO | S_IWUSR), \
+ __ATTR(_name, 0644, \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store)
@@ -281,6 +295,11 @@ static __init enum ipl_type get_ipl_type(void)
return IPL_TYPE_NVME_DUMP;
else
return IPL_TYPE_NVME;
+ case IPL_PBT_ECKD:
+ if (ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
+ return IPL_TYPE_ECKD_DUMP;
+ else
+ return IPL_TYPE_ECKD;
}
return IPL_TYPE_UNKNOWN;
}
@@ -325,7 +344,7 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj,
}
static struct kobj_attribute sys_ipl_vm_parm_attr =
- __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
+ __ATTR(parm, 0444, ipl_vm_parm_show, NULL);
static ssize_t sys_ipl_device_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
@@ -334,6 +353,10 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
case IPL_TYPE_CCW:
return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
ipl_block.ccw.devno);
+ case IPL_TYPE_ECKD:
+ case IPL_TYPE_ECKD_DUMP:
+ return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid,
+ ipl_block.eckd.devno);
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
@@ -346,7 +369,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
}
static struct kobj_attribute sys_ipl_device_attr =
- __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
+ __ATTR(device, 0444, sys_ipl_device_show, NULL);
static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
@@ -356,7 +379,7 @@ static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
ipl_block.hdr.len);
}
static struct bin_attribute ipl_parameter_attr =
- __BIN_ATTR(binary_parameter, S_IRUGO, ipl_parameter_read, NULL,
+ __BIN_ATTR(binary_parameter, 0444, ipl_parameter_read, NULL,
PAGE_SIZE);
static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
@@ -379,11 +402,24 @@ static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
return memory_read_from_buffer(buf, count, &off, scp_data, size);
}
+static ssize_t ipl_eckd_scp_data_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ unsigned int size = ipl_block.eckd.scp_data_len;
+ void *scp_data = &ipl_block.eckd.scp_data;
+
+ return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
static struct bin_attribute ipl_scp_data_attr =
- __BIN_ATTR(scp_data, S_IRUGO, ipl_scp_data_read, NULL, PAGE_SIZE);
+ __BIN_ATTR(scp_data, 0444, ipl_scp_data_read, NULL, PAGE_SIZE);
static struct bin_attribute ipl_nvme_scp_data_attr =
- __BIN_ATTR(scp_data, S_IRUGO, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
+ __BIN_ATTR(scp_data, 0444, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
+
+static struct bin_attribute ipl_eckd_scp_data_attr =
+ __BIN_ATTR(scp_data, 0444, ipl_eckd_scp_data_read, NULL, PAGE_SIZE);
static struct bin_attribute *ipl_fcp_bin_attrs[] = {
&ipl_parameter_attr,
@@ -397,6 +433,12 @@ static struct bin_attribute *ipl_nvme_bin_attrs[] = {
NULL,
};
+static struct bin_attribute *ipl_eckd_bin_attrs[] = {
+ &ipl_parameter_attr,
+ &ipl_eckd_scp_data_attr,
+ NULL,
+};
+
/* FCP ipl device attributes */
DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
@@ -418,6 +460,84 @@ DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
(unsigned long long)ipl_block.nvme.br_lba);
+/* ECKD ipl device attributes */
+DEFINE_IPL_ATTR_RO(ipl_eckd, bootprog, "%lld\n",
+ (unsigned long long)ipl_block.eckd.bootprog);
+
+#define IPL_ATTR_BR_CHR_SHOW_FN(_name, _ipb) \
+static ssize_t eckd_##_name##_br_chr_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *buf) \
+{ \
+ struct ipl_pb0_eckd *ipb = &(_ipb); \
+ \
+ if (!ipb->br_chr.cyl && \
+ !ipb->br_chr.head && \
+ !ipb->br_chr.record) \
+ return sprintf(buf, "auto\n"); \
+ \
+ return sprintf(buf, "0x%x,0x%x,0x%x\n", \
+ ipb->br_chr.cyl, \
+ ipb->br_chr.head, \
+ ipb->br_chr.record); \
+}
+
+#define IPL_ATTR_BR_CHR_STORE_FN(_name, _ipb) \
+static ssize_t eckd_##_name##_br_chr_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ struct ipl_pb0_eckd *ipb = &(_ipb); \
+ unsigned long args[3] = { 0 }; \
+ char *p, *p1, *tmp = NULL; \
+ int i, rc; \
+ \
+ if (!strncmp(buf, "auto", 4)) \
+ goto out; \
+ \
+ tmp = kstrdup(buf, GFP_KERNEL); \
+ p = tmp; \
+ for (i = 0; i < 3; i++) { \
+ p1 = strsep(&p, ", "); \
+ if (!p1) { \
+ rc = -EINVAL; \
+ goto err; \
+ } \
+ rc = kstrtoul(p1, 0, args + i); \
+ if (rc) \
+ goto err; \
+ } \
+ \
+ rc = -EINVAL; \
+ if (i != 3) \
+ goto err; \
+ \
+ if ((args[0] || args[1]) && !args[2]) \
+ goto err; \
+ \
+ if (args[0] > UINT_MAX || args[1] > 255 || args[2] > 255) \
+ goto err; \
+ \
+out: \
+ ipb->br_chr.cyl = args[0]; \
+ ipb->br_chr.head = args[1]; \
+ ipb->br_chr.record = args[2]; \
+ rc = len; \
+err: \
+ kfree(tmp); \
+ return rc; \
+}
+
+IPL_ATTR_BR_CHR_SHOW_FN(ipl, ipl_block.eckd);
+static struct kobj_attribute sys_ipl_eckd_br_chr_attr =
+ __ATTR(br_chr, 0644, eckd_ipl_br_chr_show, NULL);
+
+IPL_ATTR_BR_CHR_SHOW_FN(reipl, reipl_block_eckd->eckd);
+IPL_ATTR_BR_CHR_STORE_FN(reipl, reipl_block_eckd->eckd);
+
+static struct kobj_attribute sys_reipl_eckd_br_chr_attr =
+ __ATTR(br_chr, 0644, eckd_reipl_br_chr_show, eckd_reipl_br_chr_store);
+
static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
@@ -469,6 +589,20 @@ static struct attribute_group ipl_nvme_attr_group = {
.bin_attrs = ipl_nvme_bin_attrs,
};
+static struct attribute *ipl_eckd_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ &sys_ipl_eckd_bootprog_attr.attr,
+ &sys_ipl_eckd_br_chr_attr.attr,
+ &sys_ipl_device_attr.attr,
+ &sys_ipl_secure_attr.attr,
+ &sys_ipl_has_secure_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_eckd_attr_group = {
+ .attrs = ipl_eckd_attrs,
+ .bin_attrs = ipl_eckd_bin_attrs,
+};
/* CCW ipl device attributes */
@@ -541,6 +675,9 @@ static int __init ipl_init(void)
rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_ccw_attr_group_lpar);
break;
+ case IPL_TYPE_ECKD:
+ rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group);
+ break;
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
@@ -642,11 +779,11 @@ static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nss_vmparm_attr =
- __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
- reipl_nss_vmparm_store);
+ __ATTR(parm, 0644, reipl_nss_vmparm_show,
+ reipl_nss_vmparm_store);
static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
- __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
- reipl_ccw_vmparm_store);
+ __ATTR(parm, 0644, reipl_ccw_vmparm_show,
+ reipl_ccw_vmparm_store);
/* FCP reipl device attributes */
@@ -686,7 +823,7 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
return count;
}
static struct bin_attribute sys_reipl_fcp_scp_data_attr =
- __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
+ __BIN_ATTR(scp_data, 0644, reipl_fcp_scpdata_read,
reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_fcp_bin_attrs[] = {
@@ -766,8 +903,8 @@ static ssize_t reipl_fcp_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
- __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
- reipl_fcp_loadparm_store);
+ __ATTR(loadparm, 0644, reipl_fcp_loadparm_show,
+ reipl_fcp_loadparm_store);
static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
@@ -779,7 +916,7 @@ static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
- if (strtobool(buf, &reipl_fcp_clear) < 0)
+ if (kstrtobool(buf, &reipl_fcp_clear) < 0)
return -EINVAL;
return len;
}
@@ -840,7 +977,7 @@ static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
}
static struct bin_attribute sys_reipl_nvme_scp_data_attr =
- __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_nvme_scpdata_read,
+ __BIN_ATTR(scp_data, 0644, reipl_nvme_scpdata_read,
reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_nvme_bin_attrs[] = {
@@ -872,8 +1009,8 @@ static ssize_t reipl_nvme_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nvme_loadparm_attr =
- __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nvme_loadparm_show,
- reipl_nvme_loadparm_store);
+ __ATTR(loadparm, 0644, reipl_nvme_loadparm_show,
+ reipl_nvme_loadparm_store);
static struct attribute *reipl_nvme_attrs[] = {
&sys_reipl_nvme_fid_attr.attr,
@@ -899,7 +1036,7 @@ static ssize_t reipl_nvme_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
- if (strtobool(buf, &reipl_nvme_clear) < 0)
+ if (kstrtobool(buf, &reipl_nvme_clear) < 0)
return -EINVAL;
return len;
}
@@ -939,8 +1076,8 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
- __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
- reipl_ccw_loadparm_store);
+ __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
+ reipl_ccw_loadparm_store);
static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
@@ -952,7 +1089,7 @@ static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
- if (strtobool(buf, &reipl_ccw_clear) < 0)
+ if (kstrtobool(buf, &reipl_ccw_clear) < 0)
return -EINVAL;
return len;
}
@@ -985,6 +1122,85 @@ static struct attribute_group reipl_ccw_attr_group_lpar = {
.attrs = reipl_ccw_attrs_lpar,
};
+/* ECKD reipl device attributes */
+
+static ssize_t reipl_eckd_scpdata_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ size_t size = reipl_block_eckd->eckd.scp_data_len;
+ void *scp_data = reipl_block_eckd->eckd.scp_data;
+
+ return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
+static ssize_t reipl_eckd_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;
+
+ if (off)
+ return -EINVAL;
+
+ memcpy(reipl_block_eckd->eckd.scp_data, buf, count);
+ if (scpdata_len % 8) {
+ padding = 8 - (scpdata_len % 8);
+ memset(reipl_block_eckd->eckd.scp_data + scpdata_len,
+ 0, padding);
+ scpdata_len += padding;
+ }
+
+ reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN + scpdata_len;
+ reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN + scpdata_len;
+ reipl_block_eckd->eckd.scp_data_len = scpdata_len;
+
+ return count;
+}
+
+static struct bin_attribute sys_reipl_eckd_scp_data_attr =
+ __BIN_ATTR(scp_data, 0644, reipl_eckd_scpdata_read,
+ reipl_eckd_scpdata_write, DIAG308_SCPDATA_SIZE);
+
+static struct bin_attribute *reipl_eckd_bin_attrs[] = {
+ &sys_reipl_eckd_scp_data_attr,
+ NULL,
+};
+
+DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd);
+DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
+ reipl_block_eckd->eckd.bootprog);
+
+static struct attribute *reipl_eckd_attrs[] = {
+ &sys_reipl_eckd_device_attr.attr,
+ &sys_reipl_eckd_bootprog_attr.attr,
+ &sys_reipl_eckd_br_chr_attr.attr,
+ NULL,
+};
+
+static struct attribute_group reipl_eckd_attr_group = {
+ .attrs = reipl_eckd_attrs,
+ .bin_attrs = reipl_eckd_bin_attrs
+};
+
+static ssize_t reipl_eckd_clear_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%u\n", reipl_eckd_clear);
+}
+
+static ssize_t reipl_eckd_clear_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (strtobool(buf, &reipl_eckd_clear) < 0)
+ return -EINVAL;
+ return len;
+}
+
+static struct kobj_attribute sys_reipl_eckd_clear_attr =
+ __ATTR(clear, 0644, reipl_eckd_clear_show, reipl_eckd_clear_store);
/* NSS reipl device attributes */
static void reipl_get_ascii_nss_name(char *dst,
@@ -1032,12 +1248,12 @@ static ssize_t reipl_nss_name_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nss_name_attr =
- __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
- reipl_nss_name_store);
+ __ATTR(name, 0644, reipl_nss_name_show,
+ reipl_nss_name_store);
static struct kobj_attribute sys_reipl_nss_loadparm_attr =
- __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
- reipl_nss_loadparm_store);
+ __ATTR(loadparm, 0644, reipl_nss_loadparm_show,
+ reipl_nss_loadparm_store);
static struct attribute *reipl_nss_attrs[] = {
&sys_reipl_nss_name_attr.attr,
@@ -1068,6 +1284,9 @@ static int reipl_set_type(enum ipl_type type)
case IPL_TYPE_CCW:
reipl_block_actual = reipl_block_ccw;
break;
+ case IPL_TYPE_ECKD:
+ reipl_block_actual = reipl_block_eckd;
+ break;
case IPL_TYPE_FCP:
reipl_block_actual = reipl_block_fcp;
break;
@@ -1098,6 +1317,8 @@ static ssize_t reipl_type_store(struct kobject *kobj,
if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_CCW);
+ else if (strncmp(buf, IPL_ECKD_STR, strlen(IPL_ECKD_STR)) == 0)
+ rc = reipl_set_type(IPL_TYPE_ECKD);
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_FCP);
else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
@@ -1113,6 +1334,7 @@ static struct kobj_attribute reipl_type_attr =
static struct kset *reipl_kset;
static struct kset *reipl_fcp_kset;
static struct kset *reipl_nvme_kset;
+static struct kset *reipl_eckd_kset;
static void __reipl_run(void *unused)
{
@@ -1124,6 +1346,13 @@ static void __reipl_run(void *unused)
else
diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
break;
+ case IPL_TYPE_ECKD:
+ diag308(DIAG308_SET, reipl_block_eckd);
+ if (reipl_eckd_clear)
+ diag308(DIAG308_LOAD_CLEAR, NULL);
+ else
+ diag308(DIAG308_LOAD_NORMAL, NULL);
+ break;
case IPL_TYPE_FCP:
diag308(DIAG308_SET, reipl_block_fcp);
if (reipl_fcp_clear)
@@ -1147,6 +1376,7 @@ static void __reipl_run(void *unused)
break;
case IPL_TYPE_FCP_DUMP:
case IPL_TYPE_NVME_DUMP:
+ case IPL_TYPE_ECKD_DUMP:
break;
}
disabled_wait();
@@ -1344,6 +1574,58 @@ out1:
return rc;
}
+static int __init reipl_eckd_init(void)
+{
+ int rc;
+
+ if (!sclp.has_sipl_eckd)
+ return 0;
+
+ reipl_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!reipl_block_eckd)
+ return -ENOMEM;
+
+ /* sysfs: create kset for mixing attr group and bin attrs */
+ reipl_eckd_kset = kset_create_and_add(IPL_ECKD_STR, NULL,
+ &reipl_kset->kobj);
+ if (!reipl_eckd_kset) {
+ free_page((unsigned long)reipl_block_eckd);
+ return -ENOMEM;
+ }
+
+ rc = sysfs_create_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
+ if (rc)
+ goto out1;
+
+ if (test_facility(141)) {
+ rc = sysfs_create_file(&reipl_eckd_kset->kobj,
+ &sys_reipl_eckd_clear_attr.attr);
+ if (rc)
+ goto out2;
+ } else {
+ reipl_eckd_clear = true;
+ }
+
+ if (ipl_info.type == IPL_TYPE_ECKD) {
+ memcpy(reipl_block_eckd, &ipl_block, sizeof(ipl_block));
+ } else {
+ reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
+ reipl_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
+ reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
+ reipl_block_eckd->eckd.pbt = IPL_PBT_ECKD;
+ reipl_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_IPL;
+ }
+ reipl_capabilities |= IPL_TYPE_ECKD;
+ return 0;
+
+out2:
+ sysfs_remove_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
+out1:
+ kset_unregister(reipl_eckd_kset);
+ free_page((unsigned long)reipl_block_eckd);
+ return rc;
+}
+
static int __init reipl_type_init(void)
{
enum ipl_type reipl_type = ipl_info.type;
@@ -1365,6 +1647,9 @@ static int __init reipl_type_init(void)
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
memcpy(reipl_block_ccw, reipl_block, size);
reipl_type = IPL_TYPE_CCW;
+ } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_ECKD) {
+ memcpy(reipl_block_eckd, reipl_block, size);
+ reipl_type = IPL_TYPE_ECKD;
}
out:
return reipl_set_type(reipl_type);
@@ -1385,6 +1670,9 @@ static int __init reipl_init(void)
rc = reipl_ccw_init();
if (rc)
return rc;
+ rc = reipl_eckd_init();
+ if (rc)
+ return rc;
rc = reipl_fcp_init();
if (rc)
return rc;
@@ -1457,6 +1745,29 @@ static struct attribute_group dump_nvme_attr_group = {
.attrs = dump_nvme_attrs,
};
+/* ECKD dump device attributes */
+DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd);
+DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
+ dump_block_eckd->eckd.bootprog);
+
+IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd);
+IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);
+
+static struct kobj_attribute sys_dump_eckd_br_chr_attr =
+ __ATTR(br_chr, 0644, eckd_dump_br_chr_show, eckd_dump_br_chr_store);
+
+static struct attribute *dump_eckd_attrs[] = {
+ &sys_dump_eckd_device_attr.attr,
+ &sys_dump_eckd_bootprog_attr.attr,
+ &sys_dump_eckd_br_chr_attr.attr,
+ NULL,
+};
+
+static struct attribute_group dump_eckd_attr_group = {
+ .name = IPL_ECKD_STR,
+ .attrs = dump_eckd_attrs,
+};
+
/* CCW dump device attributes */
DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
@@ -1496,6 +1807,8 @@ static ssize_t dump_type_store(struct kobject *kobj,
rc = dump_set_type(DUMP_TYPE_NONE);
else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
rc = dump_set_type(DUMP_TYPE_CCW);
+ else if (strncmp(buf, DUMP_ECKD_STR, strlen(DUMP_ECKD_STR)) == 0)
+ rc = dump_set_type(DUMP_TYPE_ECKD);
else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
rc = dump_set_type(DUMP_TYPE_FCP);
else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
@@ -1524,6 +1837,9 @@ static void __dump_run(void *unused)
case DUMP_TYPE_CCW:
diag308_dump(dump_block_ccw);
break;
+ case DUMP_TYPE_ECKD:
+ diag308_dump(dump_block_eckd);
+ break;
case DUMP_TYPE_FCP:
diag308_dump(dump_block_fcp);
break;
@@ -1609,6 +1925,29 @@ static int __init dump_nvme_init(void)
return 0;
}
+static int __init dump_eckd_init(void)
+{
+ int rc;
+
+ if (!sclp_ipl_info.has_dump || !sclp.has_sipl_eckd)
+ return 0; /* LDIPL DUMP is not installed */
+ dump_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!dump_block_eckd)
+ return -ENOMEM;
+ rc = sysfs_create_group(&dump_kset->kobj, &dump_eckd_attr_group);
+ if (rc) {
+ free_page((unsigned long)dump_block_eckd);
+ return rc;
+ }
+ dump_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
+ dump_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
+ dump_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
+ dump_block_eckd->eckd.pbt = IPL_PBT_ECKD;
+ dump_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_DUMP;
+ dump_capabilities |= DUMP_TYPE_ECKD;
+ return 0;
+}
+
static int __init dump_init(void)
{
int rc;
@@ -1624,6 +1963,9 @@ static int __init dump_init(void)
rc = dump_ccw_init();
if (rc)
return rc;
+ rc = dump_eckd_init();
+ if (rc)
+ return rc;
rc = dump_fcp_init();
if (rc)
return rc;
@@ -2057,6 +2399,11 @@ void __init setup_ipl(void)
ipl_info.data.ccw.dev_id.ssid = ipl_block.ccw.ssid;
ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
break;
+ case IPL_TYPE_ECKD:
+ case IPL_TYPE_ECKD_DUMP:
+ ipl_info.data.eckd.dev_id.ssid = ipl_block.eckd.ssid;
+ ipl_info.data.eckd.dev_id.devno = ipl_block.eckd.devno;
+ break;
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
ipl_info.data.fcp.dev_id.ssid = 0;
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 0032bdbe8e3f..401f9c933ff9 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -24,6 +24,7 @@
#include <asm/set_memory.h>
#include <asm/sections.h>
#include <asm/dis.h>
+#include "kprobes.h"
#include "entry.h"
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
@@ -31,8 +32,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
struct kretprobe_blackpoint kretprobe_blacklist[] = { };
-DEFINE_INSN_CACHE_OPS(s390_insn);
-
static int insn_page_in_use;
void *alloc_insn_page(void)
diff --git a/arch/s390/kernel/kprobes.h b/arch/s390/kernel/kprobes.h
new file mode 100644
index 000000000000..dc3ed5098ee7
--- /dev/null
+++ b/arch/s390/kernel/kprobes.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef _ARCH_S390_KPROBES_H
+#define _ARCH_S390_KPROBES_H
+
+#include <linux/kprobes.h>
+
+DEFINE_INSN_CACHE_OPS(s390_insn);
+
+#endif
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 31cb9b00a36b..5dbf274719a9 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -19,7 +19,7 @@
#include <linux/time.h>
#include <linux/module.h>
#include <linux/sched/signal.h>
-
+#include <linux/kvm_host.h>
#include <linux/export.h>
#include <asm/lowcore.h>
#include <asm/smp.h>
@@ -31,8 +31,7 @@
#include <asm/ctl_reg.h>
#include <asm/asm-offsets.h>
#include <asm/pai.h>
-
-#include <linux/kvm_host.h>
+#include <asm/vx-insn.h>
struct mcck_struct {
unsigned int kill_task : 1;
@@ -43,21 +42,12 @@ struct mcck_struct {
};
static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
-static struct kmem_cache *mcesa_cache;
-static unsigned long mcesa_origin_lc;
static inline int nmi_needs_mcesa(void)
{
return MACHINE_HAS_VX || MACHINE_HAS_GS;
}
-static inline unsigned long nmi_get_mcesa_size(void)
-{
- if (MACHINE_HAS_GS)
- return MCESA_MAX_SIZE;
- return MCESA_MIN_SIZE;
-}
-
/*
* The initial machine check extended save area for the boot CPU.
* It will be replaced on the boot CPU reinit with an allocated
@@ -75,36 +65,23 @@ void __init nmi_alloc_mcesa_early(u64 *mcesad)
*mcesad |= ilog2(MCESA_MAX_SIZE);
}
-static void __init nmi_alloc_cache(void)
+int nmi_alloc_mcesa(u64 *mcesad)
{
unsigned long size;
-
- if (!nmi_needs_mcesa())
- return;
- size = nmi_get_mcesa_size();
- if (size > MCESA_MIN_SIZE)
- mcesa_origin_lc = ilog2(size);
- /* create slab cache for the machine-check-extended-save-areas */
- mcesa_cache = kmem_cache_create("nmi_save_areas", size, size, 0, NULL);
- if (!mcesa_cache)
- panic("Couldn't create nmi save area cache");
-}
-
-int __ref nmi_alloc_mcesa(u64 *mcesad)
-{
- unsigned long origin;
+ void *origin;
*mcesad = 0;
if (!nmi_needs_mcesa())
return 0;
- if (!mcesa_cache)
- nmi_alloc_cache();
- origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL);
+ size = MACHINE_HAS_GS ? MCESA_MAX_SIZE : MCESA_MIN_SIZE;
+ origin = kmalloc(size, GFP_KERNEL);
if (!origin)
return -ENOMEM;
/* The pointer is stored with mcesa_bits ORed in */
- kmemleak_not_leak((void *) origin);
- *mcesad = __pa(origin) | mcesa_origin_lc;
+ kmemleak_not_leak(origin);
+ *mcesad = __pa(origin);
+ if (MACHINE_HAS_GS)
+ *mcesad |= ilog2(MCESA_MAX_SIZE);
return 0;
}
@@ -112,12 +89,64 @@ void nmi_free_mcesa(u64 *mcesad)
{
if (!nmi_needs_mcesa())
return;
- kmem_cache_free(mcesa_cache, __va(*mcesad & MCESA_ORIGIN_MASK));
+ kfree(__va(*mcesad & MCESA_ORIGIN_MASK));
+}
+
+static __always_inline char *nmi_puts(char *dest, const char *src)
+{
+ while (*src)
+ *dest++ = *src++;
+ *dest = 0;
+ return dest;
+}
+
+static __always_inline char *u64_to_hex(char *dest, u64 val)
+{
+ int i, num;
+
+ for (i = 1; i <= 16; i++) {
+ num = (val >> (64 - 4 * i)) & 0xf;
+ if (num >= 10)
+ *dest++ = 'A' + num - 10;
+ else
+ *dest++ = '0' + num;
+ }
+ *dest = 0;
+ return dest;
}
static notrace void s390_handle_damage(void)
{
+ union ctlreg0 cr0, cr0_new;
+ char message[100];
+ psw_t psw_save;
+ char *ptr;
+
smp_emergency_stop();
+ diag_amode31_ops.diag308_reset();
+ ptr = nmi_puts(message, "System stopped due to unrecoverable machine check, code: 0x");
+ u64_to_hex(ptr, S390_lowcore.mcck_interruption_code);
+
+ /*
+ * Disable low address protection and make machine check new PSW a
+ * disabled wait PSW. Any additional machine check cannot be handled.
+ */
+ __ctl_store(cr0.val, 0, 0);
+ cr0_new = cr0;
+ cr0_new.lap = 0;
+ __ctl_load(cr0_new.val, 0, 0);
+ psw_save = S390_lowcore.mcck_new_psw;
+ psw_bits(S390_lowcore.mcck_new_psw).io = 0;
+ psw_bits(S390_lowcore.mcck_new_psw).ext = 0;
+ psw_bits(S390_lowcore.mcck_new_psw).wait = 1;
+ sclp_emergency_printk(message);
+
+ /*
+ * Restore machine check new PSW and control register 0 to original
+ * values. This makes possible system dump analysis easier.
+ */
+ S390_lowcore.mcck_new_psw = psw_save;
+ __ctl_load(cr0.val, 0, 0);
disabled_wait();
while (1);
}
@@ -181,10 +210,10 @@ void noinstr s390_handle_mcck(struct pt_regs *regs)
trace_hardirqs_on();
}
/*
- * returns 0 if all required registers are available
+ * returns 0 if register contents could be validated
* returns 1 otherwise
*/
-static int notrace s390_validate_registers(union mci mci, int umode)
+static int notrace s390_validate_registers(union mci mci)
{
struct mcesa *mcesa;
void *fpt_save_area;
@@ -195,45 +224,15 @@ static int notrace s390_validate_registers(union mci mci, int umode)
kill_task = 0;
zero = 0;
- if (!mci.gr) {
- /*
- * General purpose registers couldn't be restored and have
- * unknown contents. Stop system or terminate process.
- */
- if (!umode)
- s390_handle_damage();
+ if (!mci.gr || !mci.fp)
kill_task = 1;
- }
- if (!mci.fp) {
- /*
- * Floating point registers can't be restored. If the
- * kernel currently uses floating point registers the
- * system is stopped. If the process has its floating
- * pointer registers loaded it is terminated.
- */
- if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7)
- s390_handle_damage();
- if (!test_cpu_flag(CIF_FPU))
- kill_task = 1;
- }
fpt_save_area = &S390_lowcore.floating_pt_save_area;
if (!mci.fc) {
- /*
- * Floating point control register can't be restored.
- * If the kernel currently uses the floating pointer
- * registers and needs the FPC register the system is
- * stopped. If the process has its floating pointer
- * registers loaded it is terminated. Otherwise the
- * FPC is just validated.
- */
- if (S390_lowcore.fpu_flags & KERNEL_FPC)
- s390_handle_damage();
+ kill_task = 1;
asm volatile(
" lfpc %0\n"
:
: "Q" (zero));
- if (!test_cpu_flag(CIF_FPU))
- kill_task = 1;
} else {
asm volatile(
" lfpc %0\n"
@@ -275,26 +274,15 @@ static int notrace s390_validate_registers(union mci mci, int umode)
* appropriate actions. The host vector or FPU values have been
* saved by KVM and will be restored by KVM.
*/
- if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST)) {
- /*
- * Vector registers can't be restored. If the kernel
- * currently uses vector registers the system is
- * stopped. If the process has its vector registers
- * loaded it is terminated. Otherwise just validate
- * the registers.
- */
- if (S390_lowcore.fpu_flags & KERNEL_VXR)
- s390_handle_damage();
- if (!test_cpu_flag(CIF_FPU))
- kill_task = 1;
- }
+ if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST))
+ kill_task = 1;
cr0.val = S390_lowcore.cregs_save_area[0];
cr0.afp = cr0.vx = 1;
__ctl_load(cr0.val, 0, 0);
asm volatile(
" la 1,%0\n"
- " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
- " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
+ " VLM 0,15,0,1\n"
+ " VLM 16,31,256,1\n"
:
: "Q" (*(struct vx_array *)mcesa->vector_save_area)
: "1");
@@ -306,13 +294,8 @@ static int notrace s390_validate_registers(union mci mci, int umode)
:
: "a" (&S390_lowcore.access_regs_save_area)
: "memory");
- if (!mci.ar) {
- /*
- * Access registers have unknown contents.
- * Terminating task.
- */
+ if (!mci.ar)
kill_task = 1;
- }
/* Validate guarded storage registers */
cr2.val = S390_lowcore.cregs_save_area[2];
if (cr2.gse) {
@@ -451,7 +434,9 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage();
}
}
- if (s390_validate_registers(mci, user_mode(regs))) {
+ if (s390_validate_registers(mci)) {
+ if (!user_mode(regs))
+ s390_handle_damage();
/*
* Couldn't restore all register contents for the
* user space process -> mark task for termination.
@@ -480,7 +465,21 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
mcck->stp_queue |= stp_island_check();
mcck_pending = 1;
}
-
+ /*
+ * Reinject storage related machine checks into the guest if they
+ * happen when the guest is running.
+ */
+ if (!test_cpu_flag(CIF_MCCK_GUEST)) {
+ /* Storage error uncorrected */
+ if (mci.se)
+ s390_handle_damage();
+ /* Storage key-error uncorrected */
+ if (mci.ke)
+ s390_handle_damage();
+ /* Storage degradation */
+ if (mci.ds && mci.fa)
+ s390_handle_damage();
+ }
if (mci.cp) {
/* Channel report word pending */
mcck->channel_report = 1;
diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c
index 6826e2a69a21..985e243a2ed8 100644
--- a/arch/s390/kernel/perf_pai_crypto.c
+++ b/arch/s390/kernel/perf_pai_crypto.c
@@ -35,9 +35,9 @@ struct pai_userdata {
struct paicrypt_map {
unsigned long *page; /* Page for CPU to store counters */
struct pai_userdata *save; /* Page to store no-zero counters */
- unsigned int users; /* # of PAI crypto users */
- unsigned int sampler; /* # of PAI crypto samplers */
- unsigned int counter; /* # of PAI crypto counters */
+ unsigned int active_events; /* # of PAI crypto users */
+ unsigned int refcnt; /* Reference count mapped buffers */
+ enum paievt_mode mode; /* Type of event */
struct perf_event *event; /* Perf event for sampling */
};
@@ -56,15 +56,11 @@ static void paicrypt_event_destroy(struct perf_event *event)
cpump->event = NULL;
static_branch_dec(&pai_key);
mutex_lock(&pai_reserve_mutex);
- if (event->attr.sample_period)
- cpump->sampler -= 1;
- else
- cpump->counter -= 1;
- debug_sprintf_event(cfm_dbg, 5, "%s event %#llx cpu %d"
- " sampler %d counter %d\n", __func__,
- event->attr.config, event->cpu, cpump->sampler,
- cpump->counter);
- if (!cpump->counter && !cpump->sampler) {
+ debug_sprintf_event(cfm_dbg, 5, "%s event %#llx cpu %d users %d"
+ " mode %d refcnt %d\n", __func__,
+ event->attr.config, event->cpu,
+ cpump->active_events, cpump->mode, cpump->refcnt);
+ if (!--cpump->refcnt) {
debug_sprintf_event(cfm_dbg, 4, "%s page %#lx save %p\n",
__func__, (unsigned long)cpump->page,
cpump->save);
@@ -72,6 +68,7 @@ static void paicrypt_event_destroy(struct perf_event *event)
cpump->page = NULL;
kvfree(cpump->save);
cpump->save = NULL;
+ cpump->mode = PAI_MODE_NONE;
}
mutex_unlock(&pai_reserve_mutex);
}
@@ -136,17 +133,14 @@ static u64 paicrypt_getall(struct perf_event *event)
*/
static int paicrypt_busy(struct perf_event_attr *a, struct paicrypt_map *cpump)
{
- unsigned int *use_ptr;
int rc = 0;
mutex_lock(&pai_reserve_mutex);
if (a->sample_period) { /* Sampling requested */
- use_ptr = &cpump->sampler;
- if (cpump->counter || cpump->sampler)
+ if (cpump->mode != PAI_MODE_NONE)
rc = -EBUSY; /* ... sampling/counting active */
} else { /* Counting requested */
- use_ptr = &cpump->counter;
- if (cpump->sampler)
+ if (cpump->mode == PAI_MODE_SAMPLING)
rc = -EBUSY; /* ... and sampling active */
}
if (rc)
@@ -172,12 +166,16 @@ static int paicrypt_busy(struct perf_event_attr *a, struct paicrypt_map *cpump)
rc = 0;
unlock:
- /* If rc is non-zero, do not increment counter/sampler. */
- if (!rc)
- *use_ptr += 1;
- debug_sprintf_event(cfm_dbg, 5, "%s sample_period %#llx sampler %d"
- " counter %d page %#lx save %p rc %d\n", __func__,
- a->sample_period, cpump->sampler, cpump->counter,
+ /* If rc is non-zero, do not set mode and reference count */
+ if (!rc) {
+ cpump->refcnt++;
+ cpump->mode = a->sample_period ? PAI_MODE_SAMPLING
+ : PAI_MODE_COUNTING;
+ }
+ debug_sprintf_event(cfm_dbg, 5, "%s sample_period %#llx users %d"
+ " mode %d refcnt %d page %#lx save %p rc %d\n",
+ __func__, a->sample_period, cpump->active_events,
+ cpump->mode, cpump->refcnt,
(unsigned long)cpump->page, cpump->save, rc);
mutex_unlock(&pai_reserve_mutex);
return rc;
@@ -262,7 +260,7 @@ static int paicrypt_add(struct perf_event *event, int flags)
struct paicrypt_map *cpump = this_cpu_ptr(&paicrypt_map);
unsigned long ccd;
- if (cpump->users++ == 0) {
+ if (++cpump->active_events == 1) {
ccd = virt_to_phys(cpump->page) | PAI_CRYPTO_KERNEL_OFFSET;
WRITE_ONCE(S390_lowcore.ccd, ccd);
__ctl_set_bit(0, 50);
@@ -293,7 +291,7 @@ static void paicrypt_del(struct perf_event *event, int flags)
if (!event->attr.sample_period)
/* Only counting needs to read counter */
paicrypt_stop(event, PERF_EF_UPDATE);
- if (cpump->users-- == 1) {
+ if (--cpump->active_events == 0) {
__ctl_clear_bit(0, 50);
WRITE_ONCE(S390_lowcore.ccd, 0);
}
@@ -379,7 +377,7 @@ static int paicrypt_push_sample(void)
/* Called on schedule-in and schedule-out. No access to event structure,
* but for sampling only event CRYPTO_ALL is allowed.
*/
-static void paicrypt_sched_task(struct perf_event_context *ctx, bool sched_in)
+static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
/* We started with a clean page on event installation. So read out
* results on schedule_out and if page was dirty, clear values.
diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c
index 74b53c531e0c..1138f57baae3 100644
--- a/arch/s390/kernel/perf_pai_ext.c
+++ b/arch/s390/kernel/perf_pai_ext.c
@@ -28,12 +28,6 @@
static debug_info_t *paiext_dbg;
static unsigned int paiext_cnt; /* Extracted with QPACI instruction */
-enum paiext_mode {
- PAI_MODE_NONE,
- PAI_MODE_SAMPLING,
- PAI_MODE_COUNTER,
-};
-
struct pai_userdata {
u16 num;
u64 value;
@@ -54,7 +48,7 @@ struct paiext_cb { /* PAI extension 1 control block */
struct paiext_map {
unsigned long *area; /* Area for CPU to store counters */
struct pai_userdata *save; /* Area to store non-zero counters */
- enum paiext_mode mode; /* Type of event */
+ enum paievt_mode mode; /* Type of event */
unsigned int active_events; /* # of PAI Extension users */
unsigned int refcnt;
struct perf_event *event; /* Perf event for sampling */
@@ -192,14 +186,14 @@ static int paiext_alloc(struct perf_event_attr *a, struct perf_event *event)
goto unlock;
}
cpump->mode = a->sample_period ? PAI_MODE_SAMPLING
- : PAI_MODE_COUNTER;
+ : PAI_MODE_COUNTING;
} else {
/* Multiple invocation, check whats active.
* Supported are multiple counter events or only one sampling
* event concurrently at any one time.
*/
if (cpump->mode == PAI_MODE_SAMPLING ||
- (cpump->mode == PAI_MODE_COUNTER && a->sample_period)) {
+ (cpump->mode == PAI_MODE_COUNTING && a->sample_period)) {
rc = -EBUSY;
goto unlock;
}
@@ -472,7 +466,7 @@ static int paiext_push_sample(void)
/* Called on schedule-in and schedule-out. No access to event structure,
* but for sampling only event NNPA_ALL is allowed.
*/
-static void paiext_sched_task(struct perf_event_context *ctx, bool sched_in)
+static void paiext_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
/* We started with a clean page on event installation. So read out
* results on schedule_out and if page was dirty, clear values.
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 42af4b3aa02b..3f5d2db0b854 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -224,7 +224,7 @@ unsigned long __get_wchan(struct task_struct *p)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(PAGE_SIZE);
+ sp -= get_random_u32_below(PAGE_SIZE);
return sp & ~0xf;
}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index ab19ddb09d65..2094f575c532 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -437,7 +437,7 @@ static void __init setup_lowcore_dat_off(void)
lc->svc_new_psw.addr = (unsigned long) system_call;
lc->program_new_psw.mask = int_psw_mask | PSW_MASK_MCHECK;
lc->program_new_psw.addr = (unsigned long) pgm_check_handler;
- lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+ lc->mcck_new_psw.mask = int_psw_mask;
lc->mcck_new_psw.addr = (unsigned long) mcck_int_handler;
lc->io_new_psw.mask = int_psw_mask | PSW_MASK_MCHECK;
lc->io_new_psw.addr = (unsigned long) io_int_handler;
@@ -512,6 +512,7 @@ static void __init setup_lowcore_dat_on(void)
S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.svc_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.program_new_psw.mask |= PSW_MASK_DAT;
+ S390_lowcore.mcck_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT;
__ctl_set_bit(0, 28);
__ctl_store(S390_lowcore.cregs_save_area, 0, 15);
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 3105ca5bd470..ff7bf4432229 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -44,21 +44,6 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page)
return (struct vdso_data *)(vvar_page);
}
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- if (likely(vma->vm_mm == current->mm))
- return current->nsproxy->time_ns->vvar_page;
- /*
- * VM_PFNMAP | VM_IO protect .fault() handler from being called
- * through interfaces like /proc/$pid/mem or
- * process_vm_{readv,writev}() as long as there's no .access()
- * in special_mapping_vmops().
- * For more details check_vma_flags() and __access_remote_vm()
- */
- WARN(1, "vvar_page accessed remotely");
- return NULL;
-}
-
/*
* The VVAR page layout depends on whether a task belongs to the root or
* non-root time namespace. Whenever a task changes its namespace, the VVAR
@@ -84,11 +69,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm);
return 0;
}
-#else
-static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- return NULL;
-}
#endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
@@ -227,7 +207,7 @@ static unsigned long vdso_addr(unsigned long start, unsigned long len)
end -= len;
if (end > start) {
- offset = prandom_u32_max(((end - start) >> PAGE_SHIFT) + 1);
+ offset = get_random_u32_below(((end - start) >> PAGE_SHIFT) + 1);
addr = start + (offset << PAGE_SHIFT);
} else {
addr = start;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 45d4b8182b07..bc491a73815c 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -1207,6 +1207,8 @@ static int kvm_s390_vm_get_migration(struct kvm *kvm,
return 0;
}
+static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
+
static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
{
struct kvm_s390_vm_tod_clock gtod;
@@ -1216,7 +1218,7 @@ static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
return -EINVAL;
- kvm_s390_set_tod_clock(kvm, &gtod);
+ __kvm_s390_set_tod_clock(kvm, &gtod);
VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
gtod.epoch_idx, gtod.tod);
@@ -1247,7 +1249,7 @@ static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
sizeof(gtod.tod)))
return -EFAULT;
- kvm_s390_set_tod_clock(kvm, &gtod);
+ __kvm_s390_set_tod_clock(kvm, &gtod);
VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
return 0;
}
@@ -1259,6 +1261,16 @@ static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
if (attr->flags)
return -EINVAL;
+ mutex_lock(&kvm->lock);
+ /*
+ * For protected guests, the TOD is managed by the ultravisor, so trying
+ * to change it will never bring the expected results.
+ */
+ if (kvm_s390_pv_is_protected(kvm)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
switch (attr->attr) {
case KVM_S390_VM_TOD_EXT:
ret = kvm_s390_set_tod_ext(kvm, attr);
@@ -1273,6 +1285,9 @@ static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
ret = -ENXIO;
break;
}
+
+out_unlock:
+ mutex_unlock(&kvm->lock);
return ret;
}
@@ -4377,13 +4392,6 @@ static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_t
preempt_enable();
}
-void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
-{
- mutex_lock(&kvm->lock);
- __kvm_s390_set_tod_clock(kvm, gtod);
- mutex_unlock(&kvm->lock);
-}
-
int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
{
if (!mutex_trylock(&kvm->lock))
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index f6fd668f887e..4755492dfabc 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -363,7 +363,6 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
-void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index c50c1645c0ae..ded1af2ddae9 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -126,7 +126,7 @@ int kvm_s390_pci_aen_init(u8 nisc)
return -EPERM;
mutex_lock(&aift->aift_lock);
- aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
+ aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev *),
GFP_KERNEL);
if (!aift->kzdev) {
rc = -ENOMEM;
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 94138f8f0c1c..ace2541ababd 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -546,8 +546,10 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
scb_s->eca |= scb_o->eca & ECA_CEI;
/* Epoch Extension */
- if (test_kvm_facility(vcpu->kvm, 139))
+ if (test_kvm_facility(vcpu->kvm, 139)) {
scb_s->ecd |= scb_o->ecd & ECD_MEF;
+ scb_s->epdx = scb_o->epdx;
+ }
/* etoken */
if (test_kvm_facility(vcpu->kvm, 156))
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 97d66a3e60fb..1a25d456d865 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -31,6 +31,7 @@
#include <linux/cma.h>
#include <linux/gfp.h>
#include <linux/dma-direct.h>
+#include <linux/percpu.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/pgalloc.h>
@@ -207,9 +208,6 @@ void free_initmem(void)
__set_memory((unsigned long)_sinittext,
(unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT,
SET_MEMORY_RW | SET_MEMORY_NX);
- free_reserved_area(sclp_early_sccb,
- sclp_early_sccb + EXT_SCCB_READ_SCP,
- POISON_FREE_INITMEM, "unused early sccb");
free_initmem_default(POISON_FREE_INITMEM);
}
@@ -222,6 +220,41 @@ unsigned long memory_block_size_bytes(void)
return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm);
}
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+
+static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
+{
+ return LOCAL_DISTANCE;
+}
+
+static int __init pcpu_cpu_to_node(int cpu)
+{
+ return 0;
+}
+
+void __init setup_per_cpu_areas(void)
+{
+ unsigned long delta;
+ unsigned int cpu;
+ int rc;
+
+ /*
+ * Always reserve area for module percpu variables. That's
+ * what the legacy allocator did.
+ */
+ rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
+ PERCPU_DYNAMIC_RESERVE, PAGE_SIZE,
+ pcpu_cpu_distance,
+ pcpu_cpu_to_node);
+ if (rc < 0)
+ panic("Failed to initialize percpu areas.");
+
+ delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+ for_each_possible_cpu(cpu)
+ __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
+}
+
#ifdef CONFIG_MEMORY_HOTPLUG
#ifdef CONFIG_CMA
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 1571cdcb0c50..4824d1cd33d8 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -128,7 +128,7 @@ int memcpy_real(void *dest, unsigned long src, size_t count)
kvec.iov_base = dest;
kvec.iov_len = count;
- iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
if (memcpy_real_iter(&iter, src, count) < count)
return -EFAULT;
return 0;
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
index d5ea09d78938..1e2ea706aa22 100644
--- a/arch/s390/mm/page-states.c
+++ b/arch/s390/mm/page-states.c
@@ -58,17 +58,6 @@ void __init cmma_init(void)
cmma_flag = 2;
}
-static inline unsigned char get_page_state(struct page *page)
-{
- unsigned char state;
-
- asm volatile(" .insn rrf,0xb9ab0000,%0,%1,%2,0"
- : "=&d" (state)
- : "a" (page_to_phys(page)),
- "i" (ESSA_GET_STATE));
- return state & 0x3f;
-}
-
static inline void set_page_unused(struct page *page, int order)
{
int i, rc;
diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c
index a2b42a63a53b..4ab0cf829999 100644
--- a/arch/s390/pci/pci_irq.c
+++ b/arch/s390/pci/pci_irq.c
@@ -132,7 +132,7 @@ static int zpci_clear_irq(struct zpci_dev *zdev)
static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest,
bool force)
{
- struct msi_desc *entry = irq_get_msi_desc(data->irq);
+ struct msi_desc *entry = irq_data_get_msi_desc(data);
struct msi_msg msg = entry->msg;
int cpu_addr = smp_cpu_get_cpu_address(cpumask_first(dest));
diff --git a/arch/sh/configs/rsk7201_defconfig b/arch/sh/configs/rsk7201_defconfig
index 619c18699459..376e95fa77bc 100644
--- a/arch/sh/configs/rsk7201_defconfig
+++ b/arch/sh/configs/rsk7201_defconfig
@@ -10,7 +10,8 @@ CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_AIO is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/sh/configs/rsk7203_defconfig b/arch/sh/configs/rsk7203_defconfig
index d00fafc021e1..1d5fd67a3949 100644
--- a/arch/sh/configs/rsk7203_defconfig
+++ b/arch/sh/configs/rsk7203_defconfig
@@ -11,7 +11,8 @@ CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig
index 122216123e63..78e0e7be57ee 100644
--- a/arch/sh/configs/se7206_defconfig
+++ b/arch/sh/configs/se7206_defconfig
@@ -21,7 +21,8 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_ELF_CORE is not set
# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/sh/configs/shmin_defconfig b/arch/sh/configs/shmin_defconfig
index c0b6f40d01cc..e078b193a78a 100644
--- a/arch/sh/configs/shmin_defconfig
+++ b/arch/sh/configs/shmin_defconfig
@@ -9,7 +9,8 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_SHMEM is not set
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_CPU_SUBTYPE_SH7706=y
CONFIG_MEMORY_START=0x0c000000
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
index 32ec6eb1eabc..aa353dff7f19 100644
--- a/arch/sh/configs/shx3_defconfig
+++ b/arch/sh/configs/shx3_defconfig
@@ -20,7 +20,8 @@ CONFIG_USER_NS=y
CONFIG_PID_NS=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_KALLSYMS_ALL=y
-CONFIG_SLOB=y
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
CONFIG_PROFILING=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
diff --git a/arch/sh/include/asm/stackprotector.h b/arch/sh/include/asm/stackprotector.h
index 35616841d0a1..665dafac376f 100644
--- a/arch/sh/include/asm/stackprotector.h
+++ b/arch/sh/include/asm/stackprotector.h
@@ -2,9 +2,6 @@
#ifndef __ASM_SH_STACKPROTECTOR_H
#define __ASM_SH_STACKPROTECTOR_H
-#include <linux/random.h>
-#include <linux/version.h>
-
extern unsigned long __stack_chk_guard;
/*
@@ -15,12 +12,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
- canary &= CANARY_MASK;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index d417988d9770..36f50ad81e83 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -157,8 +157,8 @@ static int genregs_set(struct task_struct *target,
offsetof(struct pt_regs, pc),
sizeof(struct pt_regs));
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- sizeof(struct pt_regs), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ sizeof(struct pt_regs), -1);
return ret;
}
@@ -229,8 +229,8 @@ static int dspregs_set(struct task_struct *target,
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs,
0, sizeof(struct pt_dspregs));
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- sizeof(struct pt_dspregs), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ sizeof(struct pt_dspregs), -1);
return ret;
}
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index a779418ceba9..3bc9736bddb1 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -693,6 +693,7 @@ static inline unsigned long pmd_dirty(pmd_t pmd)
return pte_dirty(pte);
}
+#define pmd_young pmd_young
static inline unsigned long pmd_young(pmd_t pmd)
{
pte_t pte = __pte(pmd_val(pmd));
diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
index e7db48acb838..c273ccebea46 100644
--- a/arch/sparc/kernel/ptrace_32.c
+++ b/arch/sparc/kernel/ptrace_32.c
@@ -158,8 +158,9 @@ static int genregs32_set(struct task_struct *target,
35 * sizeof(u32), 36 * sizeof(u32));
if (ret || !count)
return ret;
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 36 * sizeof(u32), 38 * sizeof(u32));
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 36 * sizeof(u32),
+ 38 * sizeof(u32));
+ return 0;
}
static int fpregs32_get(struct task_struct *target,
@@ -203,8 +204,8 @@ static int fpregs32_set(struct task_struct *target,
33 * sizeof(u32),
34 * sizeof(u32));
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 34 * sizeof(u32), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 34 * sizeof(u32), -1);
return ret;
}
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index 86a7eb5c27ba..4deba5b6eddb 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -332,8 +332,8 @@ static int genregs64_set(struct task_struct *target,
}
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 36 * sizeof(u64), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 36 * sizeof(u64), -1);
return ret;
}
@@ -406,8 +406,8 @@ static int fpregs64_set(struct task_struct *target,
task_thread_info(target)->fpsaved[0] = fprs;
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 35 * sizeof(u64), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 35 * sizeof(u64), -1);
return ret;
}
@@ -473,10 +473,8 @@ static int setregs64_set(struct task_struct *target,
15 * sizeof(u64));
if (ret)
return ret;
- ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 15 * sizeof(u64), 16 * sizeof(u64));
- if (ret)
- return ret;
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 15 * sizeof(u64), 16 * sizeof(u64));
/* TSTATE */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&tstate,
@@ -670,8 +668,9 @@ finish:
pos *= sizeof(reg);
count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 38 * sizeof(reg), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 38 * sizeof(reg), -1);
+ return 0;
}
static int fpregs32_get(struct task_struct *target,
@@ -737,8 +736,8 @@ static int fpregs32_set(struct task_struct *target,
task_thread_info(target)->fpsaved[0] = fprs;
if (!ret)
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- 34 * sizeof(u32), -1);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ 34 * sizeof(u32), -1);
return ret;
}
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c
index ae9a86cb6f3d..136c78f28f8b 100644
--- a/arch/sparc/vdso/vma.c
+++ b/arch/sparc/vdso/vma.c
@@ -354,7 +354,7 @@ static unsigned long vdso_addr(unsigned long start, unsigned int len)
unsigned int offset;
/* This loses some more bits than a modulo, but is cheaper */
- offset = prandom_u32_max(PTRS_PER_PTE);
+ offset = get_random_u32_below(PTRS_PER_PTE);
return start + (offset << PAGE_SHIFT);
}
diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig
index 5903e2b598aa..a4f0a19fbe14 100644
--- a/arch/um/drivers/Kconfig
+++ b/arch/um/drivers/Kconfig
@@ -381,7 +381,6 @@ config UML_PCI_OVER_VIRTIO
select UML_IOMEM_EMULATION
select UML_DMA_EMULATION
select PCI_MSI
- select PCI_MSI_IRQ_DOMAIN
select PCI_LOCKLESS_CONFIG
config UML_PCI_OVER_VIRTIO_DEVICE_ID
diff --git a/arch/um/include/asm/pci.h b/arch/um/include/asm/pci.h
index 34fe4921b5fa..238d2e7faff8 100644
--- a/arch/um/include/asm/pci.h
+++ b/arch/um/include/asm/pci.h
@@ -7,7 +7,7 @@
/* Generic PCI */
#include <asm-generic/pci.h>
-#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+#ifdef CONFIG_PCI_MSI
/*
* This is a bit of an annoying hack, and it assumes we only have
* the virt-pci (if anything). Which is true, but still.
diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c
index 0224fcb36e22..427dd5a61a38 100644
--- a/arch/um/kernel/kmsg_dump.c
+++ b/arch/um/kernel/kmsg_dump.c
@@ -16,20 +16,26 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
struct console *con;
unsigned long flags;
size_t len = 0;
+ int cookie;
- /* only dump kmsg when no console is available */
- if (!console_trylock())
- return;
+ /*
+ * If no consoles are available to output crash information, dump
+ * the kmsg buffer to stdout.
+ */
- for_each_console(con) {
- if(strcmp(con->name, "tty") == 0 &&
- (con->flags & (CON_ENABLED | CON_CONSDEV)) != 0) {
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(con) {
+ /*
+ * The ttynull console and disabled consoles are ignored
+ * since they cannot output. All other consoles are
+ * expected to output the crash information.
+ */
+ if (strcmp(con->name, "ttynull") != 0 &&
+ (console_srcu_read_flags(con) & CON_ENABLED)) {
break;
}
}
-
- console_unlock();
-
+ console_srcu_read_unlock(cookie);
if (con)
return;
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 010bc422a09d..47830ade35ed 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -33,6 +33,7 @@
#include <skas.h>
#include <registers.h>
#include <linux/time-internal.h>
+#include <linux/elfcore.h>
/*
* This is a per-cpu array. A processor only modifies its entry and it only
@@ -356,7 +357,7 @@ int singlestepping(void * t)
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(8192);
+ sp -= get_random_u32_below(8192);
return sp & ~0xf;
}
#endif
@@ -393,7 +394,7 @@ unsigned long __get_wchan(struct task_struct *p)
return 0;
}
-int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
int cpu = current_thread_info()->cpu;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 67745ceab0db..276b3baf1c50 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -69,6 +69,7 @@ config X86
select ARCH_ENABLE_THP_MIGRATION if X86_64 && TRANSPARENT_HUGEPAGE
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_CACHE_LINE_SIZE
+ select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE if !X86_PAE
@@ -81,6 +82,7 @@ config X86
select ARCH_HAS_KCOV if X86_64
select ARCH_HAS_MEM_ENCRYPT
select ARCH_HAS_MEMBARRIER_SYNC_CORE
+ select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
select ARCH_HAS_PMEM_API if X86_64
select ARCH_HAS_PTE_DEVMAP if X86_64
@@ -462,8 +464,8 @@ config X86_X2APIC
Some Intel systems circa 2022 and later are locked into x2APIC mode
and can not fall back to the legacy APIC modes if SGX or TDX are
- enabled in the BIOS. They will be unable to boot without enabling
- this option.
+ enabled in the BIOS. They will boot with very reduced functionality
+ without enabling this option.
If you don't know what to do here, say N.
@@ -1109,7 +1111,6 @@ config X86_LOCAL_APIC
def_bool y
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
select IRQ_DOMAIN_HIERARCHY
- select PCI_MSI_IRQ_DOMAIN if PCI_MSI
config X86_IO_APIC
def_bool y
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 9860ca5979f8..9e38ffaadb5d 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -83,7 +83,7 @@ cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
- @$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
+ @$(kecho) 'Kernel: $@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
index e476bcbd9b42..454757fbdfe5 100644
--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -668,7 +668,7 @@ static bool process_mem_region(struct mem_vector *region,
}
}
#endif
- return 0;
+ return false;
}
#ifdef CONFIG_EFI
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index 8a3fff9128bb..1c8541ae3b3a 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -350,7 +350,7 @@ static int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
}
/**
- * kstrtoul - convert a string to an unsigned long
+ * boot_kstrtoul - convert a string to an unsigned long
* @s: The start of the string. The string must be null-terminated, and may also
* include a single newline before its terminating null. The first character
* may also be a plus sign, but not a minus sign.
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index b8998cf0508a..cfd4c95b9f04 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -5,6 +5,8 @@
#define pr_fmt(fmt) "tdx: " fmt
#include <linux/cpufeature.h>
+#include <linux/export.h>
+#include <linux/io.h>
#include <asm/coco.h>
#include <asm/tdx.h>
#include <asm/vmx.h>
@@ -15,6 +17,7 @@
/* TDX module Call Leaf IDs */
#define TDX_GET_INFO 1
#define TDX_GET_VEINFO 3
+#define TDX_GET_REPORT 4
#define TDX_ACCEPT_PAGE 6
/* TDX hypercall Leaf IDs */
@@ -36,6 +39,12 @@
#define ATTR_SEPT_VE_DISABLE BIT(28)
+/* TDX Module call error codes */
+#define TDCALL_RETURN_CODE(a) ((a) >> 32)
+#define TDCALL_INVALID_OPERAND 0xc0000100
+
+#define TDREPORT_SUBTYPE_0 0
+
/*
* Wrapper for standard use of __tdx_hypercall with no output aside from
* return code.
@@ -100,6 +109,37 @@ static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
panic("TDCALL %lld failed (Buggy TDX module!)\n", fn);
}
+/**
+ * tdx_mcall_get_report0() - Wrapper to get TDREPORT0 (a.k.a. TDREPORT
+ * subtype 0) using TDG.MR.REPORT TDCALL.
+ * @reportdata: Address of the input buffer which contains user-defined
+ * REPORTDATA to be included into TDREPORT.
+ * @tdreport: Address of the output buffer to store TDREPORT.
+ *
+ * Refer to section titled "TDG.MR.REPORT leaf" in the TDX Module
+ * v1.0 specification for more information on TDG.MR.REPORT TDCALL.
+ * It is used in the TDX guest driver module to get the TDREPORT0.
+ *
+ * Return 0 on success, -EINVAL for invalid operands, or -EIO on
+ * other TDCALL failures.
+ */
+int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport)
+{
+ u64 ret;
+
+ ret = __tdx_module_call(TDX_GET_REPORT, virt_to_phys(tdreport),
+ virt_to_phys(reportdata), TDREPORT_SUBTYPE_0,
+ 0, NULL);
+ if (ret) {
+ if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)
+ return -EINVAL;
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tdx_mcall_get_report0);
+
static void tdx_parse_tdinfo(u64 *cc_mask)
{
struct tdx_module_output out;
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index 4dd19819053a..59b93901660d 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -61,7 +61,7 @@ SYM_CODE_START(entry_SYSENTER_compat)
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
/* Construct struct pt_regs on stack */
- pushq $__USER32_DS /* pt_regs->ss */
+ pushq $__USER_DS /* pt_regs->ss */
pushq $0 /* pt_regs->sp = 0 (placeholder) */
/*
@@ -197,7 +197,7 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL)
ANNOTATE_NOENDBR
/* Construct struct pt_regs on stack */
- pushq $__USER32_DS /* pt_regs->ss */
+ pushq $__USER_DS /* pt_regs->ss */
pushq %r8 /* pt_regs->sp */
pushq %r11 /* pt_regs->flags */
pushq $__USER32_CS /* pt_regs->cs */
diff --git a/arch/x86/entry/vdso/vdso.lds.S b/arch/x86/entry/vdso/vdso.lds.S
index 4bf48462fca7..e8c60ae7a7c8 100644
--- a/arch/x86/entry/vdso/vdso.lds.S
+++ b/arch/x86/entry/vdso/vdso.lds.S
@@ -27,7 +27,9 @@ VERSION {
__vdso_time;
clock_getres;
__vdso_clock_getres;
+#ifdef CONFIG_X86_SGX
__vdso_sgx_enter_enclave;
+#endif
local: *;
};
}
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 311eae30e089..b8f3f9b9e53c 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -98,24 +98,6 @@ static int vdso_mremap(const struct vm_special_mapping *sm,
}
#ifdef CONFIG_TIME_NS
-static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- if (likely(vma->vm_mm == current->mm))
- return current->nsproxy->time_ns->vvar_page;
-
- /*
- * VM_PFNMAP | VM_IO protect .fault() handler from being called
- * through interfaces like /proc/$pid/mem or
- * process_vm_{readv,writev}() as long as there's no .access()
- * in special_mapping_vmops().
- * For more details check_vma_flags() and __access_remote_vm()
- */
-
- WARN(1, "vvar_page accessed remotely");
-
- return NULL;
-}
-
/*
* The vvar page layout depends on whether a task belongs to the root or
* non-root time namespace. Whenever a task changes its namespace, the VVAR
@@ -140,11 +122,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
return 0;
}
-#else
-static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
- return NULL;
-}
#endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
@@ -210,11 +187,10 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
pgprot_decrypted(vma->vm_page_prot));
}
} else if (sym_offset == image->sym_hvclock_page) {
- struct ms_hyperv_tsc_page *tsc_pg = hv_get_tsc_page();
+ pfn = hv_get_tsc_pfn();
- if (tsc_pg && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
- return vmf_insert_pfn(vma, vmf->address,
- virt_to_phys(tsc_pg) >> PAGE_SHIFT);
+ if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
+ return vmf_insert_pfn(vma, vmf->address, pfn);
} else if (sym_offset == image->sym_timens_page) {
struct page *timens_page = find_timens_vvar_page(vma);
@@ -327,7 +303,7 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
end -= len;
if (end > start) {
- offset = prandom_u32_max(((end - start) >> PAGE_SHIFT) + 1);
+ offset = get_random_u32_below(((end - start) >> PAGE_SHIFT) + 1);
addr = start + (offset << PAGE_SHIFT);
} else {
addr = start;
diff --git a/arch/x86/events/amd/brs.c b/arch/x86/events/amd/brs.c
index f1bff153d945..58461fa18b6f 100644
--- a/arch/x86/events/amd/brs.c
+++ b/arch/x86/events/amd/brs.c
@@ -384,7 +384,7 @@ static void amd_brs_poison_buffer(void)
* On ctxswin, sched_in = true, called after the PMU has started
* On ctxswout, sched_in = false, called before the PMU is stopped
*/
-void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in)
+void amd_pmu_brs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c
index 8b70237c33f7..d6f3703e4119 100644
--- a/arch/x86/events/amd/core.c
+++ b/arch/x86/events/amd/core.c
@@ -861,8 +861,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
pmu_enabled = cpuc->enabled;
cpuc->enabled = 0;
- /* stop everything (includes BRS) */
- amd_pmu_disable_all();
+ amd_brs_disable_all();
/* Drain BRS is in use (could be inactive) */
if (cpuc->lbr_users)
@@ -873,7 +872,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
cpuc->enabled = pmu_enabled;
if (pmu_enabled)
- amd_pmu_enable_all(0);
+ amd_brs_enable_all();
return amd_pmu_adjust_nmi_window(handled);
}
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
index 4cb710efbdd9..da3f5ebac4e1 100644
--- a/arch/x86/events/amd/ibs.c
+++ b/arch/x86/events/amd/ibs.c
@@ -631,7 +631,7 @@ static const struct attribute_group *op_attr_update[] = {
static struct perf_ibs perf_ibs_fetch = {
.pmu = {
- .task_ctx_nr = perf_invalid_context,
+ .task_ctx_nr = perf_hw_context,
.event_init = perf_ibs_init,
.add = perf_ibs_add,
@@ -655,7 +655,7 @@ static struct perf_ibs perf_ibs_fetch = {
static struct perf_ibs perf_ibs_op = {
.pmu = {
- .task_ctx_nr = perf_invalid_context,
+ .task_ctx_nr = perf_hw_context,
.event_init = perf_ibs_init,
.add = perf_ibs_add,
diff --git a/arch/x86/events/amd/lbr.c b/arch/x86/events/amd/lbr.c
index 38a75216c12c..eb31f850841a 100644
--- a/arch/x86/events/amd/lbr.c
+++ b/arch/x86/events/amd/lbr.c
@@ -352,7 +352,7 @@ void amd_pmu_lbr_add(struct perf_event *event)
cpuc->br_sel = reg->reg;
}
- perf_sched_cb_inc(event->ctx->pmu);
+ perf_sched_cb_inc(event->pmu);
if (!cpuc->lbr_users++ && !event->total_time_running)
amd_pmu_lbr_reset();
@@ -370,10 +370,10 @@ void amd_pmu_lbr_del(struct perf_event *event)
cpuc->lbr_users--;
WARN_ON_ONCE(cpuc->lbr_users < 0);
- perf_sched_cb_dec(event->ctx->pmu);
+ perf_sched_cb_dec(event->pmu);
}
-void amd_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
+void amd_pmu_lbr_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c
index d568afc705d2..83f15fe411b3 100644
--- a/arch/x86/events/amd/uncore.c
+++ b/arch/x86/events/amd/uncore.c
@@ -553,6 +553,7 @@ static void uncore_clean_online(void)
hlist_for_each_entry_safe(uncore, n, &uncore_unused_list, node) {
hlist_del(&uncore->node);
+ kfree(uncore->events);
kfree(uncore);
}
}
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index b30b8bbcd1e2..85a63a41c471 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -90,6 +90,8 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_swap_task_ctx, *x86_pmu.swap_task_ctx);
DEFINE_STATIC_CALL_NULL(x86_pmu_drain_pebs, *x86_pmu.drain_pebs);
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases);
+DEFINE_STATIC_CALL_NULL(x86_pmu_filter, *x86_pmu.filter);
+
/*
* This one is magic, it will get called even when PMU init fails (because
* there is no PMU), in which case it should simply return NULL.
@@ -2031,6 +2033,7 @@ static void x86_pmu_static_call_update(void)
static_call_update(x86_pmu_pebs_aliases, x86_pmu.pebs_aliases);
static_call_update(x86_pmu_guest_get_msrs, x86_pmu.guest_get_msrs);
+ static_call_update(x86_pmu_filter, x86_pmu.filter);
}
static void _x86_pmu_read(struct perf_event *event)
@@ -2052,23 +2055,6 @@ void x86_pmu_show_pmu_cap(int num_counters, int num_counters_fixed,
pr_info("... event mask: %016Lx\n", intel_ctrl);
}
-/*
- * The generic code is not hybrid friendly. The hybrid_pmu->pmu
- * of the first registered PMU is unconditionally assigned to
- * each possible cpuctx->ctx.pmu.
- * Update the correct hybrid PMU to the cpuctx->ctx.pmu.
- */
-void x86_pmu_update_cpu_context(struct pmu *pmu, int cpu)
-{
- struct perf_cpu_context *cpuctx;
-
- if (!pmu->pmu_cpu_context)
- return;
-
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
- cpuctx->ctx.pmu = pmu;
-}
-
static int __init init_hw_perf_events(void)
{
struct x86_pmu_quirk *quirk;
@@ -2175,13 +2161,9 @@ static int __init init_hw_perf_events(void)
if (err)
goto out2;
} else {
- u8 cpu_type = get_this_hybrid_cpu_type();
struct x86_hybrid_pmu *hybrid_pmu;
int i, j;
- if (!cpu_type && x86_pmu.get_hybrid_cpu_type)
- cpu_type = x86_pmu.get_hybrid_cpu_type();
-
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
hybrid_pmu = &x86_pmu.hybrid_pmu[i];
@@ -2195,9 +2177,6 @@ static int __init init_hw_perf_events(void)
(hybrid_pmu->cpu_type == hybrid_big) ? PERF_TYPE_RAW : -1);
if (err)
break;
-
- if (cpu_type == hybrid_pmu->cpu_type)
- x86_pmu_update_cpu_context(&hybrid_pmu->pmu, raw_smp_processor_id());
}
if (i < x86_pmu.num_hybrid_pmus) {
@@ -2646,15 +2625,15 @@ static const struct attribute_group *x86_pmu_attr_groups[] = {
NULL,
};
-static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
+static void x86_pmu_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
- static_call_cond(x86_pmu_sched_task)(ctx, sched_in);
+ static_call_cond(x86_pmu_sched_task)(pmu_ctx, sched_in);
}
-static void x86_pmu_swap_task_ctx(struct perf_event_context *prev,
- struct perf_event_context *next)
+static void x86_pmu_swap_task_ctx(struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc)
{
- static_call_cond(x86_pmu_swap_task_ctx)(prev, next);
+ static_call_cond(x86_pmu_swap_task_ctx)(prev_epc, next_epc);
}
void perf_check_microcode(void)
@@ -2689,12 +2668,13 @@ static int x86_pmu_aux_output_match(struct perf_event *event)
return 0;
}
-static int x86_pmu_filter_match(struct perf_event *event)
+static bool x86_pmu_filter(struct pmu *pmu, int cpu)
{
- if (x86_pmu.filter_match)
- return x86_pmu.filter_match(event);
+ bool ret = false;
- return 1;
+ static_call_cond(x86_pmu_filter)(pmu, cpu, &ret);
+
+ return ret;
}
static struct pmu pmu = {
@@ -2725,7 +2705,7 @@ static struct pmu pmu = {
.aux_output_match = x86_pmu_aux_output_match,
- .filter_match = x86_pmu_filter_match,
+ .filter = x86_pmu_filter,
};
void arch_perf_update_userpage(struct perf_event *event,
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 1b92bf05fd65..dfd2c124cdf8 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -4536,8 +4536,6 @@ end:
cpumask_set_cpu(cpu, &pmu->supported_cpus);
cpuc->pmu = &pmu->pmu;
- x86_pmu_update_cpu_context(&pmu->pmu, cpu);
-
return true;
}
@@ -4671,17 +4669,17 @@ static void intel_pmu_cpu_dead(int cpu)
cpumask_clear_cpu(cpu, &hybrid_pmu(cpuc->pmu)->supported_cpus);
}
-static void intel_pmu_sched_task(struct perf_event_context *ctx,
+static void intel_pmu_sched_task(struct perf_event_pmu_context *pmu_ctx,
bool sched_in)
{
- intel_pmu_pebs_sched_task(ctx, sched_in);
- intel_pmu_lbr_sched_task(ctx, sched_in);
+ intel_pmu_pebs_sched_task(pmu_ctx, sched_in);
+ intel_pmu_lbr_sched_task(pmu_ctx, sched_in);
}
-static void intel_pmu_swap_task_ctx(struct perf_event_context *prev,
- struct perf_event_context *next)
+static void intel_pmu_swap_task_ctx(struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc)
{
- intel_pmu_lbr_swap_task_ctx(prev, next);
+ intel_pmu_lbr_swap_task_ctx(prev_epc, next_epc);
}
static int intel_pmu_check_period(struct perf_event *event, u64 value)
@@ -4705,12 +4703,11 @@ static int intel_pmu_aux_output_match(struct perf_event *event)
return is_intel_pt_event(event);
}
-static int intel_pmu_filter_match(struct perf_event *event)
+static void intel_pmu_filter(struct pmu *pmu, int cpu, bool *ret)
{
- struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
- unsigned int cpu = smp_processor_id();
+ struct x86_hybrid_pmu *hpmu = hybrid_pmu(pmu);
- return cpumask_test_cpu(cpu, &pmu->supported_cpus);
+ *ret = !cpumask_test_cpu(cpu, &hpmu->supported_cpus);
}
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
@@ -6413,7 +6410,7 @@ __init int intel_pmu_init(void)
static_call_update(intel_pmu_set_topdown_event_period,
&adl_set_topdown_event_period);
- x86_pmu.filter_match = intel_pmu_filter_match;
+ x86_pmu.filter = intel_pmu_filter;
x86_pmu.get_event_constraints = adl_get_event_constraints;
x86_pmu.hw_config = adl_hw_config;
x86_pmu.limit_period = spr_limit_period;
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 446d2833efa7..88e58b6ee73c 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -1069,7 +1069,7 @@ static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc)
return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs);
}
-void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
+void intel_pmu_pebs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -1177,7 +1177,7 @@ static void
pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc,
struct perf_event *event, bool add)
{
- struct pmu *pmu = event->ctx->pmu;
+ struct pmu *pmu = event->pmu;
/*
* Make sure we get updated with the first PEBS
* event. It will trigger also during removal, but
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index 8259d725054d..017baba56b01 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -515,21 +515,21 @@ static void __intel_pmu_lbr_save(void *ctx)
cpuc->last_log_id = ++task_context_opt(ctx)->log_id;
}
-void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
- struct perf_event_context *next)
+void intel_pmu_lbr_swap_task_ctx(struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc)
{
void *prev_ctx_data, *next_ctx_data;
- swap(prev->task_ctx_data, next->task_ctx_data);
+ swap(prev_epc->task_ctx_data, next_epc->task_ctx_data);
/*
- * Architecture specific synchronization makes sense in
- * case both prev->task_ctx_data and next->task_ctx_data
+ * Architecture specific synchronization makes sense in case
+ * both prev_epc->task_ctx_data and next_epc->task_ctx_data
* pointers are allocated.
*/
- prev_ctx_data = next->task_ctx_data;
- next_ctx_data = prev->task_ctx_data;
+ prev_ctx_data = next_epc->task_ctx_data;
+ next_ctx_data = prev_epc->task_ctx_data;
if (!prev_ctx_data || !next_ctx_data)
return;
@@ -538,7 +538,7 @@ void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
task_context_opt(next_ctx_data)->lbr_callstack_users);
}
-void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
+void intel_pmu_lbr_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
void *task_ctx;
@@ -551,7 +551,7 @@ void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
* the task was scheduled out, restore the stack. Otherwise flush
* the LBR stack.
*/
- task_ctx = ctx ? ctx->task_ctx_data : NULL;
+ task_ctx = pmu_ctx ? pmu_ctx->task_ctx_data : NULL;
if (task_ctx) {
if (sched_in)
__intel_pmu_lbr_restore(task_ctx);
@@ -587,8 +587,8 @@ void intel_pmu_lbr_add(struct perf_event *event)
cpuc->br_sel = event->hw.branch_reg.reg;
- if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data)
- task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users++;
+ if (branch_user_callstack(cpuc->br_sel) && event->pmu_ctx->task_ctx_data)
+ task_context_opt(event->pmu_ctx->task_ctx_data)->lbr_callstack_users++;
/*
* Request pmu::sched_task() callback, which will fire inside the
@@ -611,7 +611,7 @@ void intel_pmu_lbr_add(struct perf_event *event)
*/
if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0)
cpuc->lbr_pebs_users++;
- perf_sched_cb_inc(event->ctx->pmu);
+ perf_sched_cb_inc(event->pmu);
if (!cpuc->lbr_users++ && !event->total_time_running)
intel_pmu_lbr_reset();
}
@@ -664,8 +664,8 @@ void intel_pmu_lbr_del(struct perf_event *event)
return;
if (branch_user_callstack(cpuc->br_sel) &&
- event->ctx->task_ctx_data)
- task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users--;
+ event->pmu_ctx->task_ctx_data)
+ task_context_opt(event->pmu_ctx->task_ctx_data)->lbr_callstack_users--;
if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT)
cpuc->lbr_select = 0;
@@ -675,7 +675,7 @@ void intel_pmu_lbr_del(struct perf_event *event)
cpuc->lbr_users--;
WARN_ON_ONCE(cpuc->lbr_users < 0);
WARN_ON_ONCE(cpuc->lbr_pebs_users < 0);
- perf_sched_cb_dec(event->ctx->pmu);
+ perf_sched_cb_dec(event->pmu);
}
static inline bool vlbr_exclude_host(void)
diff --git a/arch/x86/events/intel/p4.c b/arch/x86/events/intel/p4.c
index 03bbcc2fa2ff..35936188db01 100644
--- a/arch/x86/events/intel/p4.c
+++ b/arch/x86/events/intel/p4.c
@@ -24,7 +24,7 @@ struct p4_event_bind {
unsigned int escr_msr[2]; /* ESCR MSR for this event */
unsigned int escr_emask; /* valid ESCR EventMask bits */
unsigned int shared; /* event is shared across threads */
- char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on absence */
+ signed char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on absence */
};
struct p4_pebs_bind {
diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c
index 82ef87e9a897..42a55794004a 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -1263,6 +1263,15 @@ static int pt_buffer_try_single(struct pt_buffer *buf, int nr_pages)
if (1 << order != nr_pages)
goto out;
+ /*
+ * Some processors cannot always support single range for more than
+ * 4KB - refer errata TGL052, ADL037 and RPL017. Future processors might
+ * also be affected, so for now rather than trying to keep track of
+ * which ones, just disable it for all.
+ */
+ if (nr_pages > 1)
+ goto out;
+
buf->single = true;
buf->nr_pages = nr_pages;
ret = 0;
diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h
index 2adeaf4de4df..e278e2e7c051 100644
--- a/arch/x86/events/intel/uncore.h
+++ b/arch/x86/events/intel/uncore.h
@@ -2,6 +2,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <asm/apicdef.h>
+#include <asm/intel-family.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/perf_event.h>
@@ -88,12 +89,12 @@ struct intel_uncore_type {
* to identify which platform component each PMON block of that type is
* supposed to monitor.
*/
- struct intel_uncore_topology *topology;
+ struct intel_uncore_topology **topology;
/*
* Optional callbacks for managing mapping of Uncore units to PMONs
*/
int (*get_topology)(struct intel_uncore_type *type);
- int (*set_mapping)(struct intel_uncore_type *type);
+ void (*set_mapping)(struct intel_uncore_type *type);
void (*cleanup_mapping)(struct intel_uncore_type *type);
};
@@ -178,11 +179,26 @@ struct freerunning_counters {
unsigned *box_offsets;
};
-struct intel_uncore_topology {
- u64 configuration;
+struct uncore_iio_topology {
+ int pci_bus_no;
int segment;
};
+struct uncore_upi_topology {
+ int die_to;
+ int pmu_idx_to;
+ int enabled;
+};
+
+struct intel_uncore_topology {
+ int pmu_idx;
+ union {
+ void *untyped;
+ struct uncore_iio_topology *iio;
+ struct uncore_upi_topology *upi;
+ };
+};
+
struct pci2phy_map {
struct list_head list;
int segment;
diff --git a/arch/x86/events/intel/uncore_snb.c b/arch/x86/events/intel/uncore_snb.c
index 1ef4f7861e2e..1f4869227efb 100644
--- a/arch/x86/events/intel/uncore_snb.c
+++ b/arch/x86/events/intel/uncore_snb.c
@@ -1338,6 +1338,7 @@ static void __uncore_imc_init_box(struct intel_uncore_box *box,
/* MCHBAR is disabled */
if (!(mch_bar & BIT(0))) {
pr_warn("perf uncore: MCHBAR is disabled. Failed to map IMC free-running counters.\n");
+ pci_dev_put(pdev);
return;
}
mch_bar &= ~BIT(0);
@@ -1352,6 +1353,8 @@ static void __uncore_imc_init_box(struct intel_uncore_box *box,
box->io_addr = ioremap(addr, type->mmio_map_size);
if (!box->io_addr)
pr_warn("perf uncore: Failed to ioremap for %s.\n", type->name);
+
+ pci_dev_put(pdev);
}
static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index ed869443efb2..44c2f879f708 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -445,6 +445,7 @@
#define ICX_UPI_PCI_PMON_CTR0 0x320
#define ICX_UPI_PCI_PMON_BOX_CTL 0x318
#define ICX_UPI_CTL_UMASK_EXT 0xffffff
+#define ICX_UBOX_DID 0x3450
/* ICX M3UPI*/
#define ICX_M3UPI_PCI_PMON_CTL0 0xd8
@@ -457,6 +458,7 @@
/* SPR */
#define SPR_RAW_EVENT_MASK_EXT 0xffffff
+#define SPR_UBOX_DID 0x3250
/* SPR CHA */
#define SPR_CHA_PMON_CTL_TID_EN (1 << 16)
@@ -1372,6 +1374,28 @@ static struct pci_driver snbep_uncore_pci_driver = {
#define NODE_ID_MASK 0x7
+/* Each three bits from 0 to 23 of GIDNIDMAP register correspond Node ID. */
+#define GIDNIDMAP(config, id) (((config) >> (3 * (id))) & 0x7)
+
+static int upi_nodeid_groupid(struct pci_dev *ubox_dev, int nodeid_loc, int idmap_loc,
+ int *nodeid, int *groupid)
+{
+ int ret;
+
+ /* get the Node ID of the local register */
+ ret = pci_read_config_dword(ubox_dev, nodeid_loc, nodeid);
+ if (ret)
+ goto err;
+
+ *nodeid = *nodeid & NODE_ID_MASK;
+ /* get the Node ID mapping */
+ ret = pci_read_config_dword(ubox_dev, idmap_loc, groupid);
+ if (ret)
+ goto err;
+err:
+ return ret;
+}
+
/*
* build pci bus to socket mapping
*/
@@ -1397,13 +1421,8 @@ static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool
* the topology.
*/
if (nr_node_ids <= 8) {
- /* get the Node ID of the local register */
- err = pci_read_config_dword(ubox_dev, nodeid_loc, &config);
- if (err)
- break;
- nodeid = config & NODE_ID_MASK;
- /* get the Node ID mapping */
- err = pci_read_config_dword(ubox_dev, idmap_loc, &config);
+ err = upi_nodeid_groupid(ubox_dev, nodeid_loc, idmap_loc,
+ &nodeid, &config);
if (err)
break;
@@ -1421,7 +1440,7 @@ static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool
* to a particular node.
*/
for (i = 0; i < 8; i++) {
- if (nodeid == ((config >> (3 * i)) & 0x7)) {
+ if (nodeid == GIDNIDMAP(config, i)) {
if (topology_max_die_per_package() > 1)
die_id = i;
else
@@ -2891,6 +2910,7 @@ static bool hswep_has_limit_sbox(unsigned int device)
return false;
pci_read_config_dword(dev, HSWEP_PCU_CAPID4_OFFET, &capid4);
+ pci_dev_put(dev);
if (!hswep_get_chop(capid4))
return true;
@@ -3699,10 +3719,16 @@ static struct intel_uncore_ops skx_uncore_iio_ops = {
.read_counter = uncore_msr_read_counter,
};
-static inline u8 skx_iio_stack(struct intel_uncore_pmu *pmu, int die)
+static struct intel_uncore_topology *pmu_topology(struct intel_uncore_pmu *pmu, int die)
{
- return pmu->type->topology[die].configuration >>
- (pmu->pmu_idx * BUS_NUM_STRIDE);
+ int idx;
+
+ for (idx = 0; idx < pmu->type->num_boxes; idx++) {
+ if (pmu->type->topology[die][idx].pmu_idx == pmu->pmu_idx)
+ return &pmu->type->topology[die][idx];
+ }
+
+ return NULL;
}
static umode_t
@@ -3710,8 +3736,9 @@ pmu_iio_mapping_visible(struct kobject *kobj, struct attribute *attr,
int die, int zero_bus_pmu)
{
struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(kobj_to_dev(kobj));
+ struct intel_uncore_topology *pmut = pmu_topology(pmu, die);
- return (!skx_iio_stack(pmu, die) && pmu->pmu_idx != zero_bus_pmu) ? 0 : attr->mode;
+ return (pmut && !pmut->iio->pci_bus_no && pmu->pmu_idx != zero_bus_pmu) ? 0 : attr->mode;
}
static umode_t
@@ -3727,9 +3754,10 @@ static ssize_t skx_iio_mapping_show(struct device *dev,
struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(dev);
struct dev_ext_attribute *ea = to_dev_ext_attribute(attr);
long die = (long)ea->var;
+ struct intel_uncore_topology *pmut = pmu_topology(pmu, die);
- return sprintf(buf, "%04x:%02x\n", pmu->type->topology[die].segment,
- skx_iio_stack(pmu, die));
+ return sprintf(buf, "%04x:%02x\n", pmut ? pmut->iio->segment : 0,
+ pmut ? pmut->iio->pci_bus_no : 0);
}
static int skx_msr_cpu_bus_read(int cpu, u64 *topology)
@@ -3764,18 +3792,79 @@ static int die_to_cpu(int die)
return res;
}
-static int skx_iio_get_topology(struct intel_uncore_type *type)
+enum {
+ IIO_TOPOLOGY_TYPE,
+ UPI_TOPOLOGY_TYPE,
+ TOPOLOGY_MAX
+};
+
+static const size_t topology_size[TOPOLOGY_MAX] = {
+ sizeof(*((struct intel_uncore_topology *)NULL)->iio),
+ sizeof(*((struct intel_uncore_topology *)NULL)->upi)
+};
+
+static int pmu_alloc_topology(struct intel_uncore_type *type, int topology_type)
{
- int die, ret = -EPERM;
+ int die, idx;
+ struct intel_uncore_topology **topology;
+
+ if (!type->num_boxes)
+ return -EPERM;
- type->topology = kcalloc(uncore_max_dies(), sizeof(*type->topology),
- GFP_KERNEL);
- if (!type->topology)
- return -ENOMEM;
+ topology = kcalloc(uncore_max_dies(), sizeof(*topology), GFP_KERNEL);
+ if (!topology)
+ goto err;
for (die = 0; die < uncore_max_dies(); die++) {
- ret = skx_msr_cpu_bus_read(die_to_cpu(die),
- &type->topology[die].configuration);
+ topology[die] = kcalloc(type->num_boxes, sizeof(**topology), GFP_KERNEL);
+ if (!topology[die])
+ goto clear;
+ for (idx = 0; idx < type->num_boxes; idx++) {
+ topology[die][idx].untyped = kcalloc(type->num_boxes,
+ topology_size[topology_type],
+ GFP_KERNEL);
+ if (!topology[die][idx].untyped)
+ goto clear;
+ }
+ }
+
+ type->topology = topology;
+
+ return 0;
+clear:
+ for (; die >= 0; die--) {
+ for (idx = 0; idx < type->num_boxes; idx++)
+ kfree(topology[die][idx].untyped);
+ kfree(topology[die]);
+ }
+ kfree(topology);
+err:
+ return -ENOMEM;
+}
+
+static void pmu_free_topology(struct intel_uncore_type *type)
+{
+ int die, idx;
+
+ if (type->topology) {
+ for (die = 0; die < uncore_max_dies(); die++) {
+ for (idx = 0; idx < type->num_boxes; idx++)
+ kfree(type->topology[die][idx].untyped);
+ kfree(type->topology[die]);
+ }
+ kfree(type->topology);
+ type->topology = NULL;
+ }
+}
+
+static int skx_pmu_get_topology(struct intel_uncore_type *type,
+ int (*topology_cb)(struct intel_uncore_type*, int, int, u64))
+{
+ int die, ret = -EPERM;
+ u64 cpu_bus_msr;
+
+ for (die = 0; die < uncore_max_dies(); die++) {
+ ret = skx_msr_cpu_bus_read(die_to_cpu(die), &cpu_bus_msr);
if (ret)
break;
@@ -3783,15 +3872,33 @@ static int skx_iio_get_topology(struct intel_uncore_type *type)
if (ret < 0)
break;
- type->topology[die].segment = ret;
+ ret = topology_cb(type, ret, die, cpu_bus_msr);
+ if (ret)
+ break;
}
- if (ret < 0) {
- kfree(type->topology);
- type->topology = NULL;
+ return ret;
+}
+
+static int skx_iio_topology_cb(struct intel_uncore_type *type, int segment,
+ int die, u64 cpu_bus_msr)
+{
+ int idx;
+ struct intel_uncore_topology *t;
+
+ for (idx = 0; idx < type->num_boxes; idx++) {
+ t = &type->topology[die][idx];
+ t->pmu_idx = idx;
+ t->iio->segment = segment;
+ t->iio->pci_bus_no = (cpu_bus_msr >> (idx * BUS_NUM_STRIDE)) & 0xff;
}
- return ret;
+ return 0;
+}
+
+static int skx_iio_get_topology(struct intel_uncore_type *type)
+{
+ return skx_pmu_get_topology(type, skx_iio_topology_cb);
}
static struct attribute_group skx_iio_mapping_group = {
@@ -3803,8 +3910,25 @@ static const struct attribute_group *skx_iio_attr_update[] = {
NULL,
};
-static int
-pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
+static void pmu_clear_mapping_attr(const struct attribute_group **groups,
+ struct attribute_group *ag)
+{
+ int i;
+
+ for (i = 0; groups[i]; i++) {
+ if (groups[i] == ag) {
+ for (i++; groups[i]; i++)
+ groups[i - 1] = groups[i];
+ groups[i - 1] = NULL;
+ break;
+ }
+ }
+}
+
+static void
+pmu_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag,
+ ssize_t (*show)(struct device*, struct device_attribute*, char*),
+ int topology_type)
{
char buf[64];
int ret;
@@ -3812,11 +3936,13 @@ pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
struct attribute **attrs = NULL;
struct dev_ext_attribute *eas = NULL;
- ret = type->get_topology(type);
+ ret = pmu_alloc_topology(type, topology_type);
if (ret < 0)
goto clear_attr_update;
- ret = -ENOMEM;
+ ret = type->get_topology(type);
+ if (ret < 0)
+ goto clear_topology;
/* One more for NULL. */
attrs = kcalloc((uncore_max_dies() + 1), sizeof(*attrs), GFP_KERNEL);
@@ -3828,20 +3954,20 @@ pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
goto clear_attrs;
for (die = 0; die < uncore_max_dies(); die++) {
- sprintf(buf, "die%ld", die);
+ snprintf(buf, sizeof(buf), "die%ld", die);
sysfs_attr_init(&eas[die].attr.attr);
eas[die].attr.attr.name = kstrdup(buf, GFP_KERNEL);
if (!eas[die].attr.attr.name)
goto err;
eas[die].attr.attr.mode = 0444;
- eas[die].attr.show = skx_iio_mapping_show;
+ eas[die].attr.show = show;
eas[die].attr.store = NULL;
eas[die].var = (void *)die;
attrs[die] = &eas[die].attr.attr;
}
ag->attrs = attrs;
- return 0;
+ return;
err:
for (; die >= 0; die--)
kfree(eas[die].attr.attr.name);
@@ -3849,14 +3975,13 @@ err:
clear_attrs:
kfree(attrs);
clear_topology:
- kfree(type->topology);
+ pmu_free_topology(type);
clear_attr_update:
- type->attr_update = NULL;
- return ret;
+ pmu_clear_mapping_attr(type->attr_update, ag);
}
static void
-pmu_iio_cleanup_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
+pmu_cleanup_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
{
struct attribute **attr = ag->attrs;
@@ -3868,17 +3993,23 @@ pmu_iio_cleanup_mapping(struct intel_uncore_type *type, struct attribute_group *
kfree(attr_to_ext_attr(*ag->attrs));
kfree(ag->attrs);
ag->attrs = NULL;
- kfree(type->topology);
+ pmu_free_topology(type);
+}
+
+static void
+pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
+{
+ pmu_set_mapping(type, ag, skx_iio_mapping_show, IIO_TOPOLOGY_TYPE);
}
-static int skx_iio_set_mapping(struct intel_uncore_type *type)
+static void skx_iio_set_mapping(struct intel_uncore_type *type)
{
- return pmu_iio_set_mapping(type, &skx_iio_mapping_group);
+ pmu_iio_set_mapping(type, &skx_iio_mapping_group);
}
static void skx_iio_cleanup_mapping(struct intel_uncore_type *type)
{
- pmu_iio_cleanup_mapping(type, &skx_iio_mapping_group);
+ pmu_cleanup_mapping(type, &skx_iio_mapping_group);
}
static struct intel_uncore_type skx_uncore_iio = {
@@ -4139,6 +4270,132 @@ static struct intel_uncore_ops skx_upi_uncore_pci_ops = {
.read_counter = snbep_uncore_pci_read_counter,
};
+static umode_t
+skx_upi_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
+{
+ struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(kobj_to_dev(kobj));
+
+ return pmu->type->topology[die][pmu->pmu_idx].upi->enabled ? attr->mode : 0;
+}
+
+static ssize_t skx_upi_mapping_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(dev);
+ struct dev_ext_attribute *ea = to_dev_ext_attribute(attr);
+ long die = (long)ea->var;
+ struct uncore_upi_topology *upi = pmu->type->topology[die][pmu->pmu_idx].upi;
+
+ return sysfs_emit(buf, "upi_%d,die_%d\n", upi->pmu_idx_to, upi->die_to);
+}
+
+#define SKX_UPI_REG_DID 0x2058
+#define SKX_UPI_REGS_ADDR_DEVICE_LINK0 0x0e
+#define SKX_UPI_REGS_ADDR_FUNCTION 0x00
+
+/*
+ * UPI Link Parameter 0
+ * | Bit | Default | Description
+ * | 19:16 | 0h | base_nodeid - The NodeID of the sending socket.
+ * | 12:8 | 00h | sending_port - The processor die port number of the sending port.
+ */
+#define SKX_KTILP0_OFFSET 0x94
+
+/*
+ * UPI Pcode Status. This register is used by PCode to store the link training status.
+ * | Bit | Default | Description
+ * | 4 | 0h | ll_status_valid — Bit indicates the valid training status
+ * logged from PCode to the BIOS.
+ */
+#define SKX_KTIPCSTS_OFFSET 0x120
+
+static int upi_fill_topology(struct pci_dev *dev, struct intel_uncore_topology *tp,
+ int pmu_idx)
+{
+ int ret;
+ u32 upi_conf;
+ struct uncore_upi_topology *upi = tp->upi;
+
+ tp->pmu_idx = pmu_idx;
+ ret = pci_read_config_dword(dev, SKX_KTIPCSTS_OFFSET, &upi_conf);
+ if (ret) {
+ ret = pcibios_err_to_errno(ret);
+ goto err;
+ }
+ upi->enabled = (upi_conf >> 4) & 1;
+ if (upi->enabled) {
+ ret = pci_read_config_dword(dev, SKX_KTILP0_OFFSET,
+ &upi_conf);
+ if (ret) {
+ ret = pcibios_err_to_errno(ret);
+ goto err;
+ }
+ upi->die_to = (upi_conf >> 16) & 0xf;
+ upi->pmu_idx_to = (upi_conf >> 8) & 0x1f;
+ }
+err:
+ return ret;
+}
+
+static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
+ int die, u64 cpu_bus_msr)
+{
+ int idx, ret;
+ struct intel_uncore_topology *upi;
+ unsigned int devfn;
+ struct pci_dev *dev = NULL;
+ u8 bus = cpu_bus_msr >> (3 * BUS_NUM_STRIDE);
+
+ for (idx = 0; idx < type->num_boxes; idx++) {
+ upi = &type->topology[die][idx];
+ devfn = PCI_DEVFN(SKX_UPI_REGS_ADDR_DEVICE_LINK0 + idx,
+ SKX_UPI_REGS_ADDR_FUNCTION);
+ dev = pci_get_domain_bus_and_slot(segment, bus, devfn);
+ if (dev) {
+ ret = upi_fill_topology(dev, upi, idx);
+ if (ret)
+ break;
+ }
+ }
+
+ pci_dev_put(dev);
+ return ret;
+}
+
+static int skx_upi_get_topology(struct intel_uncore_type *type)
+{
+ /* CPX case is not supported */
+ if (boot_cpu_data.x86_stepping == 11)
+ return -EPERM;
+
+ return skx_pmu_get_topology(type, skx_upi_topology_cb);
+}
+
+static struct attribute_group skx_upi_mapping_group = {
+ .is_visible = skx_upi_mapping_visible,
+};
+
+static const struct attribute_group *skx_upi_attr_update[] = {
+ &skx_upi_mapping_group,
+ NULL
+};
+
+static void
+pmu_upi_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
+{
+ pmu_set_mapping(type, ag, skx_upi_mapping_show, UPI_TOPOLOGY_TYPE);
+}
+
+static void skx_upi_set_mapping(struct intel_uncore_type *type)
+{
+ pmu_upi_set_mapping(type, &skx_upi_mapping_group);
+}
+
+static void skx_upi_cleanup_mapping(struct intel_uncore_type *type)
+{
+ pmu_cleanup_mapping(type, &skx_upi_mapping_group);
+}
+
static struct intel_uncore_type skx_uncore_upi = {
.name = "upi",
.num_counters = 4,
@@ -4151,6 +4408,10 @@ static struct intel_uncore_type skx_uncore_upi = {
.box_ctl = SKX_UPI_PCI_PMON_BOX_CTL,
.ops = &skx_upi_uncore_pci_ops,
.format_group = &skx_upi_uncore_format_group,
+ .attr_update = skx_upi_attr_update,
+ .get_topology = skx_upi_get_topology,
+ .set_mapping = skx_upi_set_mapping,
+ .cleanup_mapping = skx_upi_cleanup_mapping,
};
static void skx_m2m_uncore_pci_init_box(struct intel_uncore_box *box)
@@ -4461,11 +4722,6 @@ static int sad_cfg_iio_topology(struct intel_uncore_type *type, u8 *sad_pmon_map
int die, stack_id, ret = -EPERM;
struct pci_dev *dev = NULL;
- type->topology = kcalloc(uncore_max_dies(), sizeof(*type->topology),
- GFP_KERNEL);
- if (!type->topology)
- return -ENOMEM;
-
while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, SNR_ICX_MESH2IIO_MMAP_DID, dev))) {
ret = pci_read_config_dword(dev, SNR_ICX_SAD_CONTROL_CFG, &sad_cfg);
if (ret) {
@@ -4483,14 +4739,12 @@ static int sad_cfg_iio_topology(struct intel_uncore_type *type, u8 *sad_pmon_map
/* Convert stack id from SAD_CONTROL to PMON notation. */
stack_id = sad_pmon_mapping[stack_id];
- ((u8 *)&(type->topology[die].configuration))[stack_id] = dev->bus->number;
- type->topology[die].segment = pci_domain_nr(dev->bus);
+ type->topology[die][stack_id].iio->segment = pci_domain_nr(dev->bus);
+ type->topology[die][stack_id].pmu_idx = stack_id;
+ type->topology[die][stack_id].iio->pci_bus_no = dev->bus->number;
}
- if (ret) {
- kfree(type->topology);
- type->topology = NULL;
- }
+ pci_dev_put(dev);
return ret;
}
@@ -4519,14 +4773,14 @@ static int snr_iio_get_topology(struct intel_uncore_type *type)
return sad_cfg_iio_topology(type, snr_sad_pmon_mapping);
}
-static int snr_iio_set_mapping(struct intel_uncore_type *type)
+static void snr_iio_set_mapping(struct intel_uncore_type *type)
{
- return pmu_iio_set_mapping(type, &snr_iio_mapping_group);
+ pmu_iio_set_mapping(type, &snr_iio_mapping_group);
}
static void snr_iio_cleanup_mapping(struct intel_uncore_type *type)
{
- pmu_iio_cleanup_mapping(type, &snr_iio_mapping_group);
+ pmu_cleanup_mapping(type, &snr_iio_mapping_group);
}
static struct event_constraint snr_uncore_iio_constraints[] = {
@@ -4857,6 +5111,8 @@ static int snr_uncore_mmio_map(struct intel_uncore_box *box,
addr += box_ctl;
+ pci_dev_put(pdev);
+
box->io_addr = ioremap(addr, type->mmio_map_size);
if (!box->io_addr) {
pr_warn("perf uncore: Failed to ioremap for %s.\n", type->name);
@@ -5137,14 +5393,19 @@ static int icx_iio_get_topology(struct intel_uncore_type *type)
return sad_cfg_iio_topology(type, icx_sad_pmon_mapping);
}
-static int icx_iio_set_mapping(struct intel_uncore_type *type)
+static void icx_iio_set_mapping(struct intel_uncore_type *type)
{
- return pmu_iio_set_mapping(type, &icx_iio_mapping_group);
+ /* Detect ICX-D system. This case is not supported */
+ if (boot_cpu_data.x86_model == INTEL_FAM6_ICELAKE_D) {
+ pmu_clear_mapping_attr(type->attr_update, &icx_iio_mapping_group);
+ return;
+ }
+ pmu_iio_set_mapping(type, &icx_iio_mapping_group);
}
static void icx_iio_cleanup_mapping(struct intel_uncore_type *type)
{
- pmu_iio_cleanup_mapping(type, &icx_iio_mapping_group);
+ pmu_cleanup_mapping(type, &icx_iio_mapping_group);
}
static struct intel_uncore_type icx_uncore_iio = {
@@ -5337,6 +5598,76 @@ static const struct attribute_group icx_upi_uncore_format_group = {
.attrs = icx_upi_uncore_formats_attr,
};
+#define ICX_UPI_REGS_ADDR_DEVICE_LINK0 0x02
+#define ICX_UPI_REGS_ADDR_FUNCTION 0x01
+
+static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, int dev_link0)
+{
+ struct pci_dev *ubox = NULL;
+ struct pci_dev *dev = NULL;
+ u32 nid, gid;
+ int i, idx, ret = -EPERM;
+ struct intel_uncore_topology *upi;
+ unsigned int devfn;
+
+ /* GIDNIDMAP method supports machines which have less than 8 sockets. */
+ if (uncore_max_dies() > 8)
+ goto err;
+
+ while ((ubox = pci_get_device(PCI_VENDOR_ID_INTEL, ubox_did, ubox))) {
+ ret = upi_nodeid_groupid(ubox, SKX_CPUNODEID, SKX_GIDNIDMAP, &nid, &gid);
+ if (ret) {
+ ret = pcibios_err_to_errno(ret);
+ break;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (nid != GIDNIDMAP(gid, i))
+ continue;
+ for (idx = 0; idx < type->num_boxes; idx++) {
+ upi = &type->topology[nid][idx];
+ devfn = PCI_DEVFN(dev_link0 + idx, ICX_UPI_REGS_ADDR_FUNCTION);
+ dev = pci_get_domain_bus_and_slot(pci_domain_nr(ubox->bus),
+ ubox->bus->number,
+ devfn);
+ if (dev) {
+ ret = upi_fill_topology(dev, upi, idx);
+ if (ret)
+ goto err;
+ }
+ }
+ }
+ }
+err:
+ pci_dev_put(ubox);
+ pci_dev_put(dev);
+ return ret;
+}
+
+static int icx_upi_get_topology(struct intel_uncore_type *type)
+{
+ return discover_upi_topology(type, ICX_UBOX_DID, ICX_UPI_REGS_ADDR_DEVICE_LINK0);
+}
+
+static struct attribute_group icx_upi_mapping_group = {
+ .is_visible = skx_upi_mapping_visible,
+};
+
+static const struct attribute_group *icx_upi_attr_update[] = {
+ &icx_upi_mapping_group,
+ NULL
+};
+
+static void icx_upi_set_mapping(struct intel_uncore_type *type)
+{
+ pmu_upi_set_mapping(type, &icx_upi_mapping_group);
+}
+
+static void icx_upi_cleanup_mapping(struct intel_uncore_type *type)
+{
+ pmu_cleanup_mapping(type, &icx_upi_mapping_group);
+}
+
static struct intel_uncore_type icx_uncore_upi = {
.name = "upi",
.num_counters = 4,
@@ -5349,6 +5680,10 @@ static struct intel_uncore_type icx_uncore_upi = {
.box_ctl = ICX_UPI_PCI_PMON_BOX_CTL,
.ops = &skx_upi_uncore_pci_ops,
.format_group = &icx_upi_uncore_format_group,
+ .attr_update = icx_upi_attr_update,
+ .get_topology = icx_upi_get_topology,
+ .set_mapping = icx_upi_set_mapping,
+ .cleanup_mapping = icx_upi_cleanup_mapping,
};
static struct event_constraint icx_uncore_m3upi_constraints[] = {
@@ -5780,9 +6115,43 @@ static struct intel_uncore_type spr_uncore_m2m = {
.name = "m2m",
};
+static struct attribute_group spr_upi_mapping_group = {
+ .is_visible = skx_upi_mapping_visible,
+};
+
+static const struct attribute_group *spr_upi_attr_update[] = {
+ &uncore_alias_group,
+ &spr_upi_mapping_group,
+ NULL
+};
+
+#define SPR_UPI_REGS_ADDR_DEVICE_LINK0 0x01
+
+static void spr_upi_set_mapping(struct intel_uncore_type *type)
+{
+ pmu_upi_set_mapping(type, &spr_upi_mapping_group);
+}
+
+static void spr_upi_cleanup_mapping(struct intel_uncore_type *type)
+{
+ pmu_cleanup_mapping(type, &spr_upi_mapping_group);
+}
+
+static int spr_upi_get_topology(struct intel_uncore_type *type)
+{
+ return discover_upi_topology(type, SPR_UBOX_DID, SPR_UPI_REGS_ADDR_DEVICE_LINK0);
+}
+
static struct intel_uncore_type spr_uncore_upi = {
- SPR_UNCORE_PCI_COMMON_FORMAT(),
+ .event_mask = SNBEP_PMON_RAW_EVENT_MASK,
+ .event_mask_ext = SPR_RAW_EVENT_MASK_EXT,
+ .format_group = &spr_uncore_raw_format_group,
+ .ops = &spr_uncore_pci_ops,
.name = "upi",
+ .attr_update = spr_upi_attr_update,
+ .get_topology = spr_upi_get_topology,
+ .set_mapping = spr_upi_set_mapping,
+ .cleanup_mapping = spr_upi_cleanup_mapping,
};
static struct intel_uncore_type spr_uncore_m3upi = {
@@ -5986,6 +6355,12 @@ static void uncore_type_customized_copy(struct intel_uncore_type *to_type,
to_type->format_group = from_type->format_group;
if (from_type->attr_update)
to_type->attr_update = from_type->attr_update;
+ if (from_type->set_mapping)
+ to_type->set_mapping = from_type->set_mapping;
+ if (from_type->get_topology)
+ to_type->get_topology = from_type->get_topology;
+ if (from_type->cleanup_mapping)
+ to_type->cleanup_mapping = from_type->cleanup_mapping;
}
static struct intel_uncore_type **
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 332d2e6d8ae4..0e849f28a5c1 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -811,7 +811,7 @@ struct x86_pmu {
void (*cpu_dead)(int cpu);
void (*check_microcode)(void);
- void (*sched_task)(struct perf_event_context *ctx,
+ void (*sched_task)(struct perf_event_pmu_context *pmu_ctx,
bool sched_in);
/*
@@ -894,12 +894,12 @@ struct x86_pmu {
int num_topdown_events;
/*
- * perf task context (i.e. struct perf_event_context::task_ctx_data)
+ * perf task context (i.e. struct perf_event_pmu_context::task_ctx_data)
* switch helper to bridge calls from perf/core to perf/x86.
* See struct pmu::swap_task_ctx() usage for examples;
*/
- void (*swap_task_ctx)(struct perf_event_context *prev,
- struct perf_event_context *next);
+ void (*swap_task_ctx)(struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc);
/*
* AMD bits
@@ -925,7 +925,7 @@ struct x86_pmu {
int (*aux_output_match) (struct perf_event *event);
- int (*filter_match)(struct perf_event *event);
+ void (*filter)(struct pmu *pmu, int cpu, bool *ret);
/*
* Hybrid support
*
@@ -1180,8 +1180,6 @@ int x86_pmu_handle_irq(struct pt_regs *regs);
void x86_pmu_show_pmu_cap(int num_counters, int num_counters_fixed,
u64 intel_ctrl);
-void x86_pmu_update_cpu_context(struct pmu *pmu, int cpu);
-
extern struct event_constraint emptyconstraint;
extern struct event_constraint unconstrained;
@@ -1306,7 +1304,7 @@ void amd_pmu_lbr_reset(void);
void amd_pmu_lbr_read(void);
void amd_pmu_lbr_add(struct perf_event *event);
void amd_pmu_lbr_del(struct perf_event *event);
-void amd_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
+void amd_pmu_lbr_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in);
void amd_pmu_lbr_enable_all(void);
void amd_pmu_lbr_disable_all(void);
int amd_pmu_lbr_hw_config(struct perf_event *event);
@@ -1322,7 +1320,6 @@ void amd_brs_enable_all(void);
void amd_brs_disable_all(void);
void amd_brs_drain(void);
void amd_brs_lopwr_init(void);
-void amd_brs_disable_all(void);
int amd_brs_hw_config(struct perf_event *event);
void amd_brs_reset(void);
@@ -1330,7 +1327,7 @@ static inline void amd_pmu_brs_add(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
- perf_sched_cb_inc(event->ctx->pmu);
+ perf_sched_cb_inc(event->pmu);
cpuc->lbr_users++;
/*
* No need to reset BRS because it is reset
@@ -1345,10 +1342,10 @@ static inline void amd_pmu_brs_del(struct perf_event *event)
cpuc->lbr_users--;
WARN_ON_ONCE(cpuc->lbr_users < 0);
- perf_sched_cb_dec(event->ctx->pmu);
+ perf_sched_cb_dec(event->pmu);
}
-void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in);
+void amd_pmu_brs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in);
#else
static inline int amd_brs_init(void)
{
@@ -1373,7 +1370,7 @@ static inline void amd_pmu_brs_del(struct perf_event *event)
{
}
-static inline void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in)
+static inline void amd_pmu_brs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in)
{
}
@@ -1533,7 +1530,7 @@ void intel_pmu_pebs_enable_all(void);
void intel_pmu_pebs_disable_all(void);
-void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in);
+void intel_pmu_pebs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in);
void intel_pmu_auto_reload_read(struct perf_event *event);
@@ -1541,10 +1538,10 @@ void intel_pmu_store_pebs_lbrs(struct lbr_entry *lbr);
void intel_ds_init(void);
-void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
- struct perf_event_context *next);
+void intel_pmu_lbr_swap_task_ctx(struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc);
-void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
+void intel_pmu_lbr_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in);
u64 lbr_from_signext_quirk_wr(u64 val);
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index 29774126e931..41ef036ebb7b 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -77,7 +77,7 @@ static int hyperv_init_ghcb(void)
static int hv_cpu_init(unsigned int cpu)
{
union hv_vp_assist_msr_contents msr = { 0 };
- struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
+ struct hv_vp_assist_page **hvp = &hv_vp_assist_page[cpu];
int ret;
ret = hv_common_cpu_init(cpu);
@@ -87,34 +87,32 @@ static int hv_cpu_init(unsigned int cpu)
if (!hv_vp_assist_page)
return 0;
- if (!*hvp) {
- if (hv_root_partition) {
- /*
- * For root partition we get the hypervisor provided VP assist
- * page, instead of allocating a new page.
- */
- rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
- *hvp = memremap(msr.pfn <<
- HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
- PAGE_SIZE, MEMREMAP_WB);
- } else {
- /*
- * The VP assist page is an "overlay" page (see Hyper-V TLFS's
- * Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
- * out to make sure we always write the EOI MSR in
- * hv_apic_eoi_write() *after* the EOI optimization is disabled
- * in hv_cpu_die(), otherwise a CPU may not be stopped in the
- * case of CPU offlining and the VM will hang.
- */
+ if (hv_root_partition) {
+ /*
+ * For root partition we get the hypervisor provided VP assist
+ * page, instead of allocating a new page.
+ */
+ rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
+ *hvp = memremap(msr.pfn << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
+ PAGE_SIZE, MEMREMAP_WB);
+ } else {
+ /*
+ * The VP assist page is an "overlay" page (see Hyper-V TLFS's
+ * Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
+ * out to make sure we always write the EOI MSR in
+ * hv_apic_eoi_write() *after* the EOI optimization is disabled
+ * in hv_cpu_die(), otherwise a CPU may not be stopped in the
+ * case of CPU offlining and the VM will hang.
+ */
+ if (!*hvp)
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO);
- if (*hvp)
- msr.pfn = vmalloc_to_pfn(*hvp);
- }
- WARN_ON(!(*hvp));
- if (*hvp) {
- msr.enable = 1;
- wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
- }
+ if (*hvp)
+ msr.pfn = vmalloc_to_pfn(*hvp);
+
+ }
+ if (!WARN_ON(!(*hvp))) {
+ msr.enable = 1;
+ wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
}
return hyperv_init_ghcb();
@@ -444,7 +442,7 @@ void __init hyperv_init(void)
if (hv_root_partition) {
struct page *pg;
- void *src, *dst;
+ void *src;
/*
* For the root partition, the hypervisor will set up its
@@ -459,13 +457,13 @@ void __init hyperv_init(void)
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
pg = vmalloc_to_page(hv_hypercall_pg);
- dst = kmap_local_page(pg);
src = memremap(hypercall_msr.guest_physical_address << PAGE_SHIFT, PAGE_SIZE,
MEMREMAP_WB);
- BUG_ON(!(src && dst));
- memcpy(dst, src, HV_HYP_PAGE_SIZE);
+ BUG_ON(!src);
+ memcpy_to_page(pg, 0, src, HV_HYP_PAGE_SIZE);
memunmap(src);
- kunmap_local(dst);
+
+ hv_remap_tsc_clocksource();
} else {
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@@ -537,8 +535,7 @@ common_free:
void hyperv_cleanup(void)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
-
- unregister_syscore_ops(&hv_syscore_ops);
+ union hv_reference_tsc_msr tsc_msr;
/* Reset our OS id */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
@@ -552,12 +549,14 @@ void hyperv_cleanup(void)
hv_hypercall_pg = NULL;
/* Reset the hypercall page */
- hypercall_msr.as_uint64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ hypercall_msr.as_uint64 = hv_get_register(HV_X64_MSR_HYPERCALL);
+ hypercall_msr.enable = 0;
+ hv_set_register(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
/* Reset the TSC page */
- hypercall_msr.as_uint64 = 0;
- wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
+ tsc_msr.as_uint64 = hv_get_register(HV_X64_MSR_REFERENCE_TSC);
+ tsc_msr.enable = 0;
+ hv_set_register(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
}
void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile
index e481056698de..333556a86b2a 100644
--- a/arch/x86/ia32/Makefile
+++ b/arch/x86/ia32/Makefile
@@ -3,7 +3,5 @@
# Makefile for the ia32 kernel emulation subsystem.
#
-obj-$(CONFIG_IA32_EMULATION) := ia32_signal.o
-
audit-class-$(CONFIG_AUDIT) := audit.o
obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 3415321c8240..3216da7074ba 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -249,7 +249,6 @@ static inline u64 native_x2apic_icr_read(void)
extern int x2apic_mode;
extern int x2apic_phys;
extern void __init x2apic_set_max_apicid(u32 apicid);
-extern void __init check_x2apic(void);
extern void x2apic_setup(void);
static inline int x2apic_enabled(void)
{
@@ -258,13 +257,13 @@ static inline int x2apic_enabled(void)
#define x2apic_supported() (boot_cpu_has(X86_FEATURE_X2APIC))
#else /* !CONFIG_X86_X2APIC */
-static inline void check_x2apic(void) { }
static inline void x2apic_setup(void) { }
static inline int x2apic_enabled(void) { return 0; }
#define x2apic_mode (0)
#define x2apic_supported() (0)
#endif /* !CONFIG_X86_X2APIC */
+extern void __init check_x2apic(void);
struct irq_data;
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index b71f4f2ecdd5..c9f4730bb113 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -304,6 +304,10 @@
#define X86_FEATURE_UNRET (11*32+15) /* "" AMD BTB untrain return */
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* "" Use IBPB during runtime firmware calls */
#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
+#define X86_FEATURE_SGX_EDECCSSA (11*32+18) /* "" SGX EDECCSSA user leaf function */
+
+
+#define X86_FEATURE_MSR_TSX_CTRL (11*32+20) /* "" MSR IA32_TSX_CTRL (Intel) implemented */
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index cb0ff1055ab1..18fd06f7936a 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -152,10 +152,6 @@ do { \
(elf_check_arch_ia32(x) || \
(IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
-#if __USER32_DS != __USER_DS
-# error "The following code assumes __USER32_DS == __USER_DS"
-#endif
-
static inline void elf_common_init(struct thread_struct *t,
struct pt_regs *regs, const u16 ds)
{
@@ -226,7 +222,6 @@ do { \
/* I'm not sure if we can use '-' here */
#define ELF_PLATFORM ("x86_64")
extern void set_personality_64bit(void);
-extern unsigned int sysctl_vsyscall32;
extern int force_personality32;
#endif /* !CONFIG_X86_32 */
diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
index e1c9df9102a5..611fa41711af 100644
--- a/arch/x86/include/asm/fpu/signal.h
+++ b/arch/x86/include/asm/fpu/signal.h
@@ -13,16 +13,9 @@
#ifdef CONFIG_X86_64
# include <uapi/asm/sigcontext.h>
# include <asm/user32.h>
-struct ksignal;
-int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs);
-int ia32_setup_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs);
#else
# define user_i387_ia32_struct user_i387_struct
# define user32_fxsr_struct user_fxsr_struct
-# define ia32_setup_frame __setup_frame
-# define ia32_setup_rt_frame __setup_rt_frame
#endif
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 908d99b127d3..5061ac98ffa1 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -34,19 +34,6 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
return addr;
}
-/*
- * When a ftrace registered caller is tracing a function that is
- * also set by a register_ftrace_direct() call, it needs to be
- * differentiated in the ftrace_caller trampoline. To do this, we
- * place the direct caller in the ORIG_AX part of pt_regs. This
- * tells the ftrace_caller that there's a direct caller.
- */
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
-{
- /* Emulate a call */
- regs->orig_ax = addr;
-}
-
#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
struct ftrace_regs {
struct pt_regs regs;
@@ -61,9 +48,25 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs)
return &fregs->regs;
}
-#define ftrace_instruction_pointer_set(fregs, _ip) \
+#define ftrace_regs_set_instruction_pointer(fregs, _ip) \
do { (fregs)->regs.ip = (_ip); } while (0)
+#define ftrace_regs_get_instruction_pointer(fregs) \
+ ((fregs)->regs.ip)
+
+#define ftrace_regs_get_argument(fregs, n) \
+ regs_get_kernel_argument(&(fregs)->regs, n)
+#define ftrace_regs_get_stack_pointer(fregs) \
+ kernel_stack_pointer(&(fregs)->regs)
+#define ftrace_regs_return_value(fregs) \
+ regs_return_value(&(fregs)->regs)
+#define ftrace_regs_set_return_value(fregs, ret) \
+ regs_set_return_value(&(fregs)->regs, ret)
+#define ftrace_override_function_with_return(fregs) \
+ override_function_with_return(&(fregs)->regs)
+#define ftrace_regs_query_register_offset(name) \
+ regs_query_register_offset(name)
+
struct ftrace_ops;
#define ftrace_graph_func ftrace_graph_func
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
@@ -72,6 +75,24 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
#define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR
#endif
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+/*
+ * When a ftrace registered caller is tracing a function that is
+ * also set by a register_ftrace_direct() call, it needs to be
+ * differentiated in the ftrace_caller trampoline. To do this, we
+ * place the direct caller in the ORIG_AX part of pt_regs. This
+ * tells the ftrace_caller that there's a direct caller.
+ */
+static inline void
+__arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
+{
+ /* Emulate a call */
+ regs->orig_ax = addr;
+}
+#define arch_ftrace_set_direct_caller(fregs, addr) \
+ __arch_ftrace_set_direct_caller(&(fregs)->regs, addr)
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
#ifdef CONFIG_DYNAMIC_FTRACE
struct dyn_arch_ftrace {
diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h
index 3089ec352743..6d9368ea3701 100644
--- a/arch/x86/include/asm/hyperv-tlfs.h
+++ b/arch/x86/include/asm/hyperv-tlfs.h
@@ -374,11 +374,20 @@ struct hv_nested_enlightenments_control {
struct hv_vp_assist_page {
__u32 apic_assist;
__u32 reserved1;
- __u64 vtl_control[3];
+ __u32 vtl_entry_reason;
+ __u32 vtl_reserved;
+ __u64 vtl_ret_x64rax;
+ __u64 vtl_ret_x64rcx;
struct hv_nested_enlightenments_control nested_control;
__u8 enlighten_vmentry;
__u8 reserved2[7];
__u64 current_nested_vmcs;
+ __u8 synthetic_time_unhalted_timer_expired;
+ __u8 reserved3[7];
+ __u8 virtualization_fault_information[40];
+ __u8 reserved4[8];
+ __u8 intercept_message[256];
+ __u8 vtl_ret_actions[256];
} __packed;
struct hv_enlightened_vmcs {
diff --git a/arch/x86/include/asm/hyperv_timer.h b/arch/x86/include/asm/hyperv_timer.h
new file mode 100644
index 000000000000..388fa81b8f38
--- /dev/null
+++ b/arch/x86/include/asm/hyperv_timer.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_HYPERV_TIMER_H
+#define _ASM_X86_HYPERV_TIMER_H
+
+#include <asm/msr.h>
+
+#define hv_get_raw_timer() rdtsc_ordered()
+
+#endif
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 7cc49432187f..7a2ed154a5e1 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -44,10 +44,6 @@ extern int irq_remapping_reenable(int);
extern int irq_remap_enable_fault_handling(void);
extern void panic_if_irq_remap(const char *msg);
-/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
-extern struct irq_domain *
-arch_create_remap_msi_irq_domain(struct irq_domain *par, const char *n, int id);
-
/* Get parent irqdomain for interrupt remapping irqdomain */
static inline struct irq_domain *arch_get_ir_parent_domain(void)
{
diff --git a/arch/x86/include/asm/irqdomain.h b/arch/x86/include/asm/irqdomain.h
index 125c23b7bad3..30c325c235c0 100644
--- a/arch/x86/include/asm/irqdomain.h
+++ b/arch/x86/include/asm/irqdomain.h
@@ -7,9 +7,7 @@
#ifdef CONFIG_X86_LOCAL_APIC
enum {
- /* Allocate contiguous CPU vectors */
- X86_IRQ_ALLOC_CONTIGUOUS_VECTORS = 0x1,
- X86_IRQ_ALLOC_LEGACY = 0x2,
+ X86_IRQ_ALLOC_LEGACY = 0x1,
};
extern int x86_fwspec_is_ioapic(struct irq_fwspec *fwspec);
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7551b6f9c31c..f05ebaa26f0f 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -501,7 +501,12 @@ struct kvm_pmc {
bool intr;
};
+/* More counters may conflict with other existing Architectural MSRs */
+#define KVM_INTEL_PMC_MAX_GENERIC 8
+#define MSR_ARCH_PERFMON_PERFCTR_MAX (MSR_ARCH_PERFMON_PERFCTR0 + KVM_INTEL_PMC_MAX_GENERIC - 1)
+#define MSR_ARCH_PERFMON_EVENTSEL_MAX (MSR_ARCH_PERFMON_EVENTSEL0 + KVM_INTEL_PMC_MAX_GENERIC - 1)
#define KVM_PMC_MAX_FIXED 3
+#define KVM_AMD_PMC_MAX_GENERIC 6
struct kvm_pmu {
unsigned nr_arch_gp_counters;
unsigned nr_arch_fixed_counters;
@@ -516,7 +521,7 @@ struct kvm_pmu {
u64 reserved_bits;
u64 raw_event_mask;
u8 version;
- struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
+ struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC];
struct kvm_pmc fixed_counters[KVM_PMC_MAX_FIXED];
struct irq_work irq_work;
DECLARE_BITMAP(reprogram_pmi, X86_PMC_IDX_MAX);
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index 61f0c206bff0..6d502f3efb0f 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -19,8 +19,6 @@ typedef int (*hyperv_fill_flush_list_func)(
struct hv_guest_mapping_flush_list *flush,
void *data);
-#define hv_get_raw_timer() rdtsc_ordered()
-
void hyperv_vector_handler(struct pt_regs *regs);
#if IS_ENABLED(CONFIG_HYPERV)
diff --git a/arch/x86/include/asm/msi.h b/arch/x86/include/asm/msi.h
index d71c7e8b738d..935c6d470341 100644
--- a/arch/x86/include/asm/msi.h
+++ b/arch/x86/include/asm/msi.h
@@ -62,4 +62,10 @@ typedef struct x86_msi_addr_hi {
struct msi_msg;
u32 x86_msi_msg_get_destid(struct msi_msg *msg, bool extid);
+#define X86_VECTOR_MSI_FLAGS_SUPPORTED \
+ (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX | MSI_FLAG_PCI_MSIX_ALLOC_DYN)
+
+#define X86_VECTOR_MSI_FLAGS_REQUIRED \
+ (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS)
+
#endif /* _ASM_X86_MSI_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 10ac52705892..6bcd5d2dd718 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -4,12 +4,7 @@
#include <linux/bits.h>
-/*
- * CPU model specific register (MSR) numbers.
- *
- * Do not add new entries to this file unless the definitions are shared
- * between multiple compilation units.
- */
+/* CPU model specific register (MSR) numbers. */
/* x86-64 specific MSRs */
#define MSR_EFER 0xc0000080 /* extended feature register */
@@ -535,6 +530,11 @@
#define MSR_AMD64_CPUID_FN_1 0xc0011004
#define MSR_AMD64_LS_CFG 0xc0011020
#define MSR_AMD64_DC_CFG 0xc0011022
+
+#define MSR_AMD64_DE_CFG 0xc0011029
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
+
#define MSR_AMD64_BU_CFG2 0xc001102a
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
@@ -640,9 +640,6 @@
#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL
#define FAM10H_MMIO_CONF_BASE_SHIFT 20
#define MSR_FAM10H_NODE_ID 0xc001100c
-#define MSR_F10H_DECFG 0xc0011029
-#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1
-#define MSR_F10H_DECFG_LFENCE_SERIALIZE BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT)
/* K8 MSRs */
#define MSR_K8_TOP_MEM1 0xc001001a
@@ -1050,6 +1047,20 @@
#define VMX_BASIC_MEM_TYPE_WB 6LLU
#define VMX_BASIC_INOUT 0x0040000000000000LLU
+/* Resctrl MSRs: */
+/* - Intel: */
+#define MSR_IA32_L3_QOS_CFG 0xc81
+#define MSR_IA32_L2_QOS_CFG 0xc82
+#define MSR_IA32_QM_EVTSEL 0xc8d
+#define MSR_IA32_QM_CTR 0xc8e
+#define MSR_IA32_PQR_ASSOC 0xc8f
+#define MSR_IA32_L3_CBM_BASE 0xc90
+#define MSR_IA32_L2_CBM_BASE 0xd10
+#define MSR_IA32_MBA_THRTL_BASE 0xd50
+
+/* - AMD: */
+#define MSR_IA32_MBA_BW_BASE 0xc0000200
+
/* MSR_IA32_VMX_MISC bits */
#define MSR_IA32_VMX_MISC_INTEL_PT (1ULL << 14)
#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29)
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index c936ce9f0c47..dfdb103ae4f6 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -321,7 +321,7 @@ static inline void indirect_branch_prediction_barrier(void)
/* The Intel SPEC CTRL MSR base value cache */
extern u64 x86_spec_ctrl_base;
DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
-extern void write_spec_ctrl_current(u64 val, bool force);
+extern void update_spec_ctrl_cond(u64 val);
extern u64 spec_ctrl_current(void);
/*
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 736793d65bcb..b40c462b4af3 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -21,7 +21,7 @@ struct pci_sysdata {
#ifdef CONFIG_X86_64
void *iommu; /* IOMMU private data */
#endif
-#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+#ifdef CONFIG_PCI_MSI
void *fwnode; /* IRQ domain for MSI assignment */
#endif
#if IS_ENABLED(CONFIG_VMD)
@@ -52,7 +52,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
}
#endif
-#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+#ifdef CONFIG_PCI_MSI
static inline void *_pci_root_bus_fwnode(struct pci_bus *bus)
{
return to_pci_sysdata(bus)->fwnode;
@@ -92,6 +92,7 @@ void pcibios_scan_root(int bus);
struct irq_routing_table *pcibios_get_irq_routing_table(void);
int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
+bool pci_dev_has_default_msi_parent_domain(struct pci_dev *dev);
#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() pat_enabled()
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5059799bebe3..286a71810f9e 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -139,6 +139,7 @@ static inline int pmd_dirty(pmd_t pmd)
return pmd_flags(pmd) & _PAGE_DIRTY;
}
+#define pmd_young pmd_young
static inline int pmd_young(pmd_t pmd)
{
return pmd_flags(pmd) & _PAGE_ACCESSED;
@@ -1438,6 +1439,14 @@ static inline bool arch_has_hw_pte_young(void)
return true;
}
+#ifdef CONFIG_XEN_PV
+#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young
+static inline bool arch_has_hw_nonleaf_pmd_young(void)
+{
+ return !cpu_feature_enabled(X86_FEATURE_XENPV);
+}
+#endif
+
#ifdef CONFIG_PAGE_TABLE_CHECK
static inline bool pte_user_accessible_page(pte_t pte)
{
diff --git a/arch/x86/include/asm/qspinlock_paravirt.h b/arch/x86/include/asm/qspinlock_paravirt.h
index 60ece592b220..dbb38a6b4dfb 100644
--- a/arch/x86/include/asm/qspinlock_paravirt.h
+++ b/arch/x86/include/asm/qspinlock_paravirt.h
@@ -37,7 +37,7 @@ __PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath, ".spinlock.text");
* rsi = lockval (second argument)
* rdx = internal variable (set to 0)
*/
-asm (".pushsection .spinlock.text;"
+asm (".pushsection .spinlock.text, \"ax\";"
".globl " PV_UNLOCK ";"
".type " PV_UNLOCK ", @function;"
".align 4,0x90;"
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index d24b04ebf950..52788f79786f 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -7,8 +7,6 @@
#include <linux/sched.h>
#include <linux/jump_label.h>
-#define IA32_PQR_ASSOC 0x0c8f
-
/**
* struct resctrl_pqr_state - State cache for the PQR MSR
* @cur_rmid: The cached Resource Monitoring ID
@@ -16,8 +14,8 @@
* @default_rmid: The user assigned Resource Monitoring ID
* @default_closid: The user assigned cached Class Of Service ID
*
- * The upper 32 bits of IA32_PQR_ASSOC contain closid and the
- * lower 10 bits rmid. The update to IA32_PQR_ASSOC always
+ * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
+ * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
* contains both parts, so we need to cache them. This also
* stores the user configured per cpu CLOSID and RMID.
*
@@ -77,7 +75,7 @@ static void __resctrl_sched_in(void)
if (closid != state->cur_closid || rmid != state->cur_rmid) {
state->cur_closid = closid;
state->cur_rmid = rmid;
- wrmsr(IA32_PQR_ASSOC, rmid, closid);
+ wrmsr(MSR_IA32_PQR_ASSOC, rmid, closid);
}
}
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 2e7890dd58a4..c390a672d560 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -135,6 +135,7 @@
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
+#define __USER32_CS __USER_CS
#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS*8)
/* segment for calling fn: */
@@ -210,7 +211,6 @@
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
#define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS*8 + 3)
#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
-#define __USER32_DS __USER_DS
#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
#define __CPUNODE_SEG (GDT_ENTRY_CPUNODE*8 + 3)
diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h
index eae20fa52b93..6a0069761508 100644
--- a/arch/x86/include/asm/sgx.h
+++ b/arch/x86/include/asm/sgx.h
@@ -115,17 +115,36 @@ enum sgx_miscselect {
* %SGX_ATTR_EINITTOKENKEY: Allow to use token signing key that is used to
* sign cryptographic tokens that can be passed to
* EINIT as an authorization to run an enclave.
+ * %SGX_ATTR_ASYNC_EXIT_NOTIFY: Allow enclaves to be notified after an
+ * asynchronous exit has occurred.
*/
enum sgx_attribute {
- SGX_ATTR_INIT = BIT(0),
- SGX_ATTR_DEBUG = BIT(1),
- SGX_ATTR_MODE64BIT = BIT(2),
- SGX_ATTR_PROVISIONKEY = BIT(4),
- SGX_ATTR_EINITTOKENKEY = BIT(5),
- SGX_ATTR_KSS = BIT(7),
+ SGX_ATTR_INIT = BIT(0),
+ SGX_ATTR_DEBUG = BIT(1),
+ SGX_ATTR_MODE64BIT = BIT(2),
+ /* BIT(3) is reserved */
+ SGX_ATTR_PROVISIONKEY = BIT(4),
+ SGX_ATTR_EINITTOKENKEY = BIT(5),
+ /* BIT(6) is for CET */
+ SGX_ATTR_KSS = BIT(7),
+ /* BIT(8) is reserved */
+ /* BIT(9) is reserved */
+ SGX_ATTR_ASYNC_EXIT_NOTIFY = BIT(10),
};
-#define SGX_ATTR_RESERVED_MASK (BIT_ULL(3) | BIT_ULL(6) | GENMASK_ULL(63, 8))
+#define SGX_ATTR_RESERVED_MASK (BIT_ULL(3) | \
+ BIT_ULL(6) | \
+ BIT_ULL(8) | \
+ BIT_ULL(9) | \
+ GENMASK_ULL(63, 11))
+
+#define SGX_ATTR_UNPRIV_MASK (SGX_ATTR_DEBUG | \
+ SGX_ATTR_MODE64BIT | \
+ SGX_ATTR_KSS | \
+ SGX_ATTR_ASYNC_EXIT_NOTIFY)
+
+#define SGX_ATTR_PRIV_MASK (SGX_ATTR_PROVISIONKEY | \
+ SGX_ATTR_EINITTOKENKEY)
/**
* struct sgx_secs - SGX Enclave Control Structure (SECS)
diff --git a/arch/x86/include/asm/sighandling.h b/arch/x86/include/asm/sighandling.h
index 65e667279e0f..e770c4fc47f4 100644
--- a/arch/x86/include/asm/sighandling.h
+++ b/arch/x86/include/asm/sighandling.h
@@ -15,4 +15,13 @@
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+void __user *
+get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
+ void __user **fpstate);
+
+int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs);
+int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
+int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
+int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
+
#endif /* _ASM_X86_SIGHANDLING_H */
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 2dfb5fea13af..4a4043ca6493 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -28,11 +28,6 @@ typedef struct {
#define SA_IA32_ABI 0x02000000u
#define SA_X32_ABI 0x01000000u
-#ifndef CONFIG_COMPAT
-#define compat_sigset_t compat_sigset_t
-typedef sigset_t compat_sigset_t;
-#endif
-
#endif /* __ASSEMBLY__ */
#include <uapi/asm/signal.h>
#ifndef __ASSEMBLY__
diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h
index 5393babc0598..cb0386fc4dc3 100644
--- a/arch/x86/include/asm/spec-ctrl.h
+++ b/arch/x86/include/asm/spec-ctrl.h
@@ -13,7 +13,7 @@
* Takes the guest view of SPEC_CTRL MSR as a parameter and also
* the guest's version of VIRT_SPEC_CTRL, if emulated.
*/
-extern void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool guest);
+extern void x86_virt_spec_ctrl(u64 guest_virt_spec_ctrl, bool guest);
/**
* x86_spec_ctrl_set_guest - Set speculation control registers for the guest
@@ -24,9 +24,9 @@ extern void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bo
* Avoids writing to the MSR if the content/bits are the same
*/
static inline
-void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl)
+void x86_spec_ctrl_set_guest(u64 guest_virt_spec_ctrl)
{
- x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, true);
+ x86_virt_spec_ctrl(guest_virt_spec_ctrl, true);
}
/**
@@ -38,9 +38,9 @@ void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl)
* Avoids writing to the MSR if the content/bits are the same
*/
static inline
-void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl)
+void x86_spec_ctrl_restore_host(u64 guest_virt_spec_ctrl)
{
- x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, false);
+ x86_virt_spec_ctrl(guest_virt_spec_ctrl, false);
}
/* AMD specific Speculative Store Bypass MSR data */
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index 24a8d6c4fb18..00473a650f51 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -34,7 +34,6 @@
#include <asm/percpu.h>
#include <asm/desc.h>
-#include <linux/random.h>
#include <linux/sched.h>
/*
@@ -50,22 +49,11 @@
*/
static __always_inline void boot_init_stack_canary(void)
{
- u64 canary;
- u64 tsc;
+ unsigned long canary = get_random_canary();
#ifdef CONFIG_X86_64
BUILD_BUG_ON(offsetof(struct fixed_percpu_data, stack_canary) != 40);
#endif
- /*
- * We both use the random pool and the current TSC as a source
- * of randomness. The TSC only matters for very early init,
- * there it already has some randomness on most systems. Later
- * on during the bootup the random pool has true entropy too.
- */
- get_random_bytes(&canary, sizeof(canary));
- tsc = rdtsc();
- canary += tsc + (tsc << 32UL);
- canary &= CANARY_MASK;
current->stack_canary = canary;
#ifdef CONFIG_X86_64
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 020c81a7c729..28d889c9aa16 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -67,6 +67,8 @@ void tdx_safe_halt(void);
bool tdx_early_handle_ve(struct pt_regs *regs);
+int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
+
#else
static inline void tdx_early_init(void) { };
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index f901658d9f7c..cceaafdd2d84 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -44,7 +44,7 @@ obj-y += head_$(BITS).o
obj-y += head$(BITS).o
obj-y += ebda.o
obj-y += platform-quirks.o
-obj-y += process_$(BITS).o signal.o
+obj-y += process_$(BITS).o signal.o signal_$(BITS).o
obj-$(CONFIG_COMPAT) += signal_compat.o
obj-y += traps.o idt.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y += time.o ioport.o dumpstack.o nmi.o
@@ -54,7 +54,7 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_IRQ_WORK) += irq_work.o
obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += sys_ia32.o
-obj-$(CONFIG_IA32_EMULATION) += sys_ia32.o
+obj-$(CONFIG_IA32_EMULATION) += sys_ia32.o signal_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o
obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
obj-$(CONFIG_SYSFS) += ksysfs.o
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 5cadcea035e0..a9bea860e22a 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -624,7 +624,7 @@ void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end)
#else
-void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end) { }
+void __init_or_module apply_ibt_endbr(s32 *start, s32 *end) { }
#endif /* CONFIG_X86_KERNEL_IBT */
@@ -1608,7 +1608,7 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
default:
BUG_ON(len != insn.length);
- };
+ }
switch (tp->opcode) {
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index c6876d3ea4b1..20d9a604da7c 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1931,16 +1931,19 @@ void __init check_x2apic(void)
}
}
#else /* CONFIG_X86_X2APIC */
-static int __init validate_x2apic(void)
+void __init check_x2apic(void)
{
if (!apic_is_x2apic_enabled())
- return 0;
+ return;
/*
- * Checkme: Can we simply turn off x2apic here instead of panic?
+ * Checkme: Can we simply turn off x2APIC here instead of disabling the APIC?
*/
- panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n");
+ pr_err("Kernel does not support x2APIC, please recompile with CONFIG_X86_X2APIC.\n");
+ pr_err("Disabling APIC, expect reduced performance and functionality.\n");
+
+ disable_apic = 1;
+ setup_clear_cpu_cap(X86_FEATURE_APIC);
}
-early_initcall(validate_x2apic);
static inline void try_to_enable_x2apic(int remap_mode) { }
static inline void __x2apic_enable(void) { }
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 7517eb05bdc1..35d5b8fb18ef 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -142,70 +142,139 @@ msi_set_affinity(struct irq_data *irqd, const struct cpumask *mask, bool force)
return ret;
}
-/*
- * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI or MSI-X Capability Structure.
+/**
+ * pci_dev_has_default_msi_parent_domain - Check whether the device has the default
+ * MSI parent domain associated
+ * @dev: Pointer to the PCI device
*/
-static struct irq_chip pci_msi_controller = {
- .name = "PCI-MSI",
- .irq_unmask = pci_msi_unmask_irq,
- .irq_mask = pci_msi_mask_irq,
- .irq_ack = irq_chip_ack_parent,
- .irq_retrigger = irq_chip_retrigger_hierarchy,
- .irq_set_affinity = msi_set_affinity,
- .flags = IRQCHIP_SKIP_SET_WAKE |
- IRQCHIP_AFFINITY_PRE_STARTUP,
-};
+bool pci_dev_has_default_msi_parent_domain(struct pci_dev *dev)
+{
+ struct irq_domain *domain = dev_get_msi_domain(&dev->dev);
-int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
- msi_alloc_info_t *arg)
+ if (!domain)
+ domain = dev_get_msi_domain(&dev->bus->dev);
+ if (!domain)
+ return false;
+
+ return domain == x86_vector_domain;
+}
+
+/**
+ * x86_msi_prepare - Setup of msi_alloc_info_t for allocations
+ * @domain: The domain for which this setup happens
+ * @dev: The device for which interrupts are allocated
+ * @nvec: The number of vectors to allocate
+ * @alloc: The allocation info structure to initialize
+ *
+ * This function is to be used for all types of MSI domains above the x86
+ * vector domain and any intermediates. It is always invoked from the
+ * top level interrupt domain. The domain specific allocation
+ * functionality is determined via the @domain's bus token which allows to
+ * map the X86 specific allocation type.
+ */
+static int x86_msi_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *alloc)
{
- init_irq_alloc_info(arg, NULL);
- if (to_pci_dev(dev)->msix_enabled) {
- arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSIX;
- } else {
- arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSI;
- arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
+ struct msi_domain_info *info = domain->host_data;
+
+ init_irq_alloc_info(alloc, NULL);
+
+ switch (info->bus_token) {
+ case DOMAIN_BUS_PCI_DEVICE_MSI:
+ alloc->type = X86_IRQ_ALLOC_TYPE_PCI_MSI;
+ return 0;
+ case DOMAIN_BUS_PCI_DEVICE_MSIX:
+ case DOMAIN_BUS_PCI_DEVICE_IMS:
+ alloc->type = X86_IRQ_ALLOC_TYPE_PCI_MSIX;
+ return 0;
+ default:
+ return -EINVAL;
}
-
- return 0;
}
-EXPORT_SYMBOL_GPL(pci_msi_prepare);
-static struct msi_domain_ops pci_msi_domain_ops = {
- .msi_prepare = pci_msi_prepare,
-};
+/**
+ * x86_init_dev_msi_info - Domain info setup for MSI domains
+ * @dev: The device for which the domain should be created
+ * @domain: The (root) domain providing this callback
+ * @real_parent: The real parent domain of the to initialize domain
+ * @info: The domain info for the to initialize domain
+ *
+ * This function is to be used for all types of MSI domains above the x86
+ * vector domain and any intermediates. The domain specific functionality
+ * is determined via the @real_parent.
+ */
+static bool x86_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+ struct irq_domain *real_parent, struct msi_domain_info *info)
+{
+ const struct msi_parent_ops *pops = real_parent->msi_parent_ops;
+
+ /* MSI parent domain specific settings */
+ switch (real_parent->bus_token) {
+ case DOMAIN_BUS_ANY:
+ /* Only the vector domain can have the ANY token */
+ if (WARN_ON_ONCE(domain != real_parent))
+ return false;
+ info->chip->irq_set_affinity = msi_set_affinity;
+ /* See msi_set_affinity() for the gory details */
+ info->flags |= MSI_FLAG_NOMASK_QUIRK;
+ break;
+ case DOMAIN_BUS_DMAR:
+ case DOMAIN_BUS_AMDVI:
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return false;
+ }
+
+ /* Is the target supported? */
+ switch(info->bus_token) {
+ case DOMAIN_BUS_PCI_DEVICE_MSI:
+ case DOMAIN_BUS_PCI_DEVICE_MSIX:
+ break;
+ case DOMAIN_BUS_PCI_DEVICE_IMS:
+ if (!(pops->supported_flags & MSI_FLAG_PCI_IMS))
+ return false;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return false;
+ }
+
+ /*
+ * Mask out the domain specific MSI feature flags which are not
+ * supported by the real parent.
+ */
+ info->flags &= pops->supported_flags;
+ /* Enforce the required flags */
+ info->flags |= X86_VECTOR_MSI_FLAGS_REQUIRED;
+
+ /* This is always invoked from the top level MSI domain! */
+ info->ops->msi_prepare = x86_msi_prepare;
+
+ info->chip->irq_ack = irq_chip_ack_parent;
+ info->chip->irq_retrigger = irq_chip_retrigger_hierarchy;
+ info->chip->flags |= IRQCHIP_SKIP_SET_WAKE |
+ IRQCHIP_AFFINITY_PRE_STARTUP;
-static struct msi_domain_info pci_msi_domain_info = {
- .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_PCI_MSIX,
- .ops = &pci_msi_domain_ops,
- .chip = &pci_msi_controller,
- .handler = handle_edge_irq,
- .handler_name = "edge",
+ info->handler = handle_edge_irq;
+ info->handler_name = "edge";
+
+ return true;
+}
+
+static const struct msi_parent_ops x86_vector_msi_parent_ops = {
+ .supported_flags = X86_VECTOR_MSI_FLAGS_SUPPORTED,
+ .init_dev_msi_info = x86_init_dev_msi_info,
};
struct irq_domain * __init native_create_pci_msi_domain(void)
{
- struct fwnode_handle *fn;
- struct irq_domain *d;
-
if (disable_apic)
return NULL;
- fn = irq_domain_alloc_named_fwnode("PCI-MSI");
- if (!fn)
- return NULL;
-
- d = pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
- x86_vector_domain);
- if (!d) {
- irq_domain_free_fwnode(fn);
- pr_warn("Failed to initialize PCI-MSI irqdomain.\n");
- } else {
- d->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK;
- }
- return d;
+ x86_vector_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+ x86_vector_domain->msi_parent_ops = &x86_vector_msi_parent_ops;
+ return x86_vector_domain;
}
void __init x86_create_pci_msi_domain(void)
@@ -213,41 +282,19 @@ void __init x86_create_pci_msi_domain(void)
x86_pci_msi_default_domain = x86_init.irqs.create_pci_msi_domain();
}
-#ifdef CONFIG_IRQ_REMAP
-static struct irq_chip pci_msi_ir_controller = {
- .name = "IR-PCI-MSI",
- .irq_unmask = pci_msi_unmask_irq,
- .irq_mask = pci_msi_mask_irq,
- .irq_ack = irq_chip_ack_parent,
- .irq_retrigger = irq_chip_retrigger_hierarchy,
- .flags = IRQCHIP_SKIP_SET_WAKE |
- IRQCHIP_AFFINITY_PRE_STARTUP,
-};
-
-static struct msi_domain_info pci_msi_ir_domain_info = {
- .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
- .ops = &pci_msi_domain_ops,
- .chip = &pci_msi_ir_controller,
- .handler = handle_edge_irq,
- .handler_name = "edge",
-};
-
-struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
- const char *name, int id)
+/* Keep around for hyperV */
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+ msi_alloc_info_t *arg)
{
- struct fwnode_handle *fn;
- struct irq_domain *d;
+ init_irq_alloc_info(arg, NULL);
- fn = irq_domain_alloc_named_id_fwnode(name, id);
- if (!fn)
- return NULL;
- d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
- if (!d)
- irq_domain_free_fwnode(fn);
- return d;
+ if (to_pci_dev(dev)->msix_enabled)
+ arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSIX;
+ else
+ arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSI;
+ return 0;
}
-#endif
+EXPORT_SYMBOL_GPL(pci_msi_prepare);
#ifdef CONFIG_DMAR_TABLE
/*
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 3e6f6b448f6a..c1efebd27e6c 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -539,10 +539,6 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
if (disable_apic)
return -ENXIO;
- /* Currently vector allocator can't guarantee contiguous allocations */
- if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
- return -ENOSYS;
-
/*
* Catch any attempt to touch the cascade interrupt on a PIC
* equipped system.
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index cb50589a7102..437308004ef2 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -19,7 +19,6 @@
#include <asm/suspend.h>
#include <asm/tlbflush.h>
#include <asm/tdx.h>
-#include "../kvm/vmx/vmx.h"
#ifdef CONFIG_XEN
#include <xen/interface/xen.h>
@@ -108,9 +107,4 @@ static void __used common(void)
OFFSET(TSS_sp0, tss_struct, x86_tss.sp0);
OFFSET(TSS_sp1, tss_struct, x86_tss.sp1);
OFFSET(TSS_sp2, tss_struct, x86_tss.sp2);
-
- if (IS_ENABLED(CONFIG_KVM_INTEL)) {
- BLANK();
- OFFSET(VMX_spec_ctrl, vcpu_vmx, spec_ctrl);
- }
}
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 860b60273df3..c75d75b9f11a 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -770,8 +770,6 @@ static void init_amd_gh(struct cpuinfo_x86 *c)
set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
}
-#define MSR_AMD64_DE_CFG 0xC0011029
-
static void init_amd_ln(struct cpuinfo_x86 *c)
{
/*
@@ -965,8 +963,8 @@ static void init_amd(struct cpuinfo_x86 *c)
* msr_set_bit() uses the safe accessors, too, even if the MSR
* is not present.
*/
- msr_set_bit(MSR_F10H_DECFG,
- MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
+ msr_set_bit(MSR_AMD64_DE_CFG,
+ MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT);
/* A serializing LFENCE stops RDTSC speculation */
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index da7c361f47e0..6daf84229548 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -60,11 +60,18 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
static DEFINE_MUTEX(spec_ctrl_mutex);
+/* Update SPEC_CTRL MSR and its cached copy unconditionally */
+static void update_spec_ctrl(u64 val)
+{
+ this_cpu_write(x86_spec_ctrl_current, val);
+ wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
/*
* Keep track of the SPEC_CTRL MSR value for the current task, which may differ
* from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
*/
-void write_spec_ctrl_current(u64 val, bool force)
+void update_spec_ctrl_cond(u64 val)
{
if (this_cpu_read(x86_spec_ctrl_current) == val)
return;
@@ -75,7 +82,7 @@ void write_spec_ctrl_current(u64 val, bool force)
* When KERNEL_IBRS this MSR is written on return-to-user, unless
* forced the update can be delayed until that time.
*/
- if (force || !cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+ if (!cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
wrmsrl(MSR_IA32_SPEC_CTRL, val);
}
@@ -196,22 +203,15 @@ void __init check_bugs(void)
}
/*
- * NOTE: This function is *only* called for SVM. VMX spec_ctrl handling is
- * done in vmenter.S.
+ * NOTE: This function is *only* called for SVM, since Intel uses
+ * MSR_IA32_SPEC_CTRL for SSBD.
*/
void
-x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
+x86_virt_spec_ctrl(u64 guest_virt_spec_ctrl, bool setguest)
{
- u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
+ u64 guestval, hostval;
struct thread_info *ti = current_thread_info();
- if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
- if (hostval != guestval) {
- msrval = setguest ? guestval : hostval;
- wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
- }
- }
-
/*
* If SSBD is not handled in MSR_SPEC_CTRL on AMD, update
* MSR_AMD64_L2_CFG or MSR_VIRT_SPEC_CTRL if supported.
@@ -1335,7 +1335,7 @@ static void __init spec_ctrl_disable_kernel_rrsba(void)
if (ia32_cap & ARCH_CAP_RRSBA) {
x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S;
- write_spec_ctrl_current(x86_spec_ctrl_base, true);
+ update_spec_ctrl(x86_spec_ctrl_base);
}
}
@@ -1457,7 +1457,7 @@ static void __init spectre_v2_select_mitigation(void)
if (spectre_v2_in_ibrs_mode(mode)) {
x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
- write_spec_ctrl_current(x86_spec_ctrl_base, true);
+ update_spec_ctrl(x86_spec_ctrl_base);
}
switch (mode) {
@@ -1571,7 +1571,7 @@ static void __init spectre_v2_select_mitigation(void)
static void update_stibp_msr(void * __unused)
{
u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
- write_spec_ctrl_current(val, true);
+ update_spec_ctrl(val);
}
/* Update x86_spec_ctrl_base in case SMT state changed. */
@@ -1804,7 +1804,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
x86_amd_ssb_disable();
} else {
x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
- write_spec_ctrl_current(x86_spec_ctrl_base, true);
+ update_spec_ctrl(x86_spec_ctrl_base);
}
}
@@ -2055,7 +2055,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
void x86_spec_ctrl_setup_ap(void)
{
if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
- write_spec_ctrl_current(x86_spec_ctrl_base, true);
+ update_spec_ctrl(x86_spec_ctrl_base);
if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
x86_amd_ssb_disable();
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 3e508f239098..3f66dd03c091 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -22,9 +22,9 @@
#include <linux/io.h>
#include <linux/syscore_ops.h>
#include <linux/pgtable.h>
+#include <linux/stackprotector.h>
#include <asm/cmdline.h>
-#include <asm/stackprotector.h>
#include <asm/perf_event.h>
#include <asm/mmu_context.h>
#include <asm/doublefault.h>
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index c881bcafba7d..d95221117129 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -75,6 +75,7 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_SGX_LC, X86_FEATURE_SGX },
{ X86_FEATURE_SGX1, X86_FEATURE_SGX },
{ X86_FEATURE_SGX2, X86_FEATURE_SGX1 },
+ { X86_FEATURE_SGX_EDECCSSA, X86_FEATURE_SGX1 },
{ X86_FEATURE_XFD, X86_FEATURE_XSAVES },
{ X86_FEATURE_XFD, X86_FEATURE_XGETBV1 },
{ X86_FEATURE_AMX_TILE, X86_FEATURE_XFD },
diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c
index 21fd425088fe..c393b8773ace 100644
--- a/arch/x86/kernel/cpu/hygon.c
+++ b/arch/x86/kernel/cpu/hygon.c
@@ -326,8 +326,8 @@ static void init_hygon(struct cpuinfo_x86 *c)
* msr_set_bit() uses the safe accessors, too, even if the MSR
* is not present.
*/
- msr_set_bit(MSR_F10H_DECFG,
- MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
+ msr_set_bit(MSR_AMD64_DE_CFG,
+ MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT);
/* A serializing LFENCE stops RDTSC speculation */
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 2d7ea5480ec3..427899650483 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -1034,8 +1034,32 @@ static const struct {
static struct ratelimit_state bld_ratelimit;
+static unsigned int sysctl_sld_mitigate = 1;
static DEFINE_SEMAPHORE(buslock_sem);
+#ifdef CONFIG_PROC_SYSCTL
+static struct ctl_table sld_sysctls[] = {
+ {
+ .procname = "split_lock_mitigate",
+ .data = &sysctl_sld_mitigate,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_douintvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+ {}
+};
+
+static int __init sld_mitigate_sysctl_init(void)
+{
+ register_sysctl_init("kernel", sld_sysctls);
+ return 0;
+}
+
+late_initcall(sld_mitigate_sysctl_init);
+#endif
+
static inline bool match_option(const char *arg, int arglen, const char *opt)
{
int len = strlen(opt), ratelimit;
@@ -1146,12 +1170,20 @@ static void split_lock_init(void)
split_lock_verify_msr(sld_state != sld_off);
}
-static void __split_lock_reenable(struct work_struct *work)
+static void __split_lock_reenable_unlock(struct work_struct *work)
{
sld_update_msr(true);
up(&buslock_sem);
}
+static DECLARE_DELAYED_WORK(sl_reenable_unlock, __split_lock_reenable_unlock);
+
+static void __split_lock_reenable(struct work_struct *work)
+{
+ sld_update_msr(true);
+}
+static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable);
+
/*
* If a CPU goes offline with pending delayed work to re-enable split lock
* detection then the delayed work will be executed on some other CPU. That
@@ -1169,10 +1201,9 @@ static int splitlock_cpu_offline(unsigned int cpu)
return 0;
}
-static DECLARE_DELAYED_WORK(split_lock_reenable, __split_lock_reenable);
-
static void split_lock_warn(unsigned long ip)
{
+ struct delayed_work *work;
int cpu;
if (!current->reported_split_lock)
@@ -1180,14 +1211,26 @@ static void split_lock_warn(unsigned long ip)
current->comm, current->pid, ip);
current->reported_split_lock = 1;
- /* misery factor #1, sleep 10ms before trying to execute split lock */
- if (msleep_interruptible(10) > 0)
- return;
- /* Misery factor #2, only allow one buslocked disabled core at a time */
- if (down_interruptible(&buslock_sem) == -EINTR)
- return;
+ if (sysctl_sld_mitigate) {
+ /*
+ * misery factor #1:
+ * sleep 10ms before trying to execute split lock.
+ */
+ if (msleep_interruptible(10) > 0)
+ return;
+ /*
+ * Misery factor #2:
+ * only allow one buslocked disabled core at a time.
+ */
+ if (down_interruptible(&buslock_sem) == -EINTR)
+ return;
+ work = &sl_reenable_unlock;
+ } else {
+ work = &sl_reenable;
+ }
+
cpu = get_cpu();
- schedule_delayed_work_on(cpu, &split_lock_reenable, 2);
+ schedule_delayed_work_on(cpu, work, 2);
/* Disable split lock detection on this CPU to make progress */
sld_update_msr(false);
diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c
index 1c87501e0fa3..10fb5b5c9efa 100644
--- a/arch/x86/kernel/cpu/mce/amd.c
+++ b/arch/x86/kernel/cpu/mce/amd.c
@@ -788,6 +788,24 @@ _log_error_bank(unsigned int bank, u32 msr_stat, u32 msr_addr, u64 misc)
return status & MCI_STATUS_DEFERRED;
}
+static bool _log_error_deferred(unsigned int bank, u32 misc)
+{
+ if (!_log_error_bank(bank, mca_msr_reg(bank, MCA_STATUS),
+ mca_msr_reg(bank, MCA_ADDR), misc))
+ return false;
+
+ /*
+ * Non-SMCA systems don't have MCA_DESTAT/MCA_DEADDR registers.
+ * Return true here to avoid accessing these registers.
+ */
+ if (!mce_flags.smca)
+ return true;
+
+ /* Clear MCA_DESTAT if the deferred error was logged from MCA_STATUS. */
+ wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(bank), 0);
+ return true;
+}
+
/*
* We have three scenarios for checking for Deferred errors:
*
@@ -799,19 +817,8 @@ _log_error_bank(unsigned int bank, u32 msr_stat, u32 msr_addr, u64 misc)
*/
static void log_error_deferred(unsigned int bank)
{
- bool defrd;
-
- defrd = _log_error_bank(bank, mca_msr_reg(bank, MCA_STATUS),
- mca_msr_reg(bank, MCA_ADDR), 0);
-
- if (!mce_flags.smca)
- return;
-
- /* Clear MCA_DESTAT if we logged the deferred error from MCA_STATUS. */
- if (defrd) {
- wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(bank), 0);
+ if (_log_error_deferred(bank, 0))
return;
- }
/*
* Only deferred errors are logged in MCA_DE{STAT,ADDR} so just check
@@ -832,7 +839,7 @@ static void amd_deferred_error_interrupt(void)
static void log_error_thresholding(unsigned int bank, u64 misc)
{
- _log_error_bank(bank, mca_msr_reg(bank, MCA_STATUS), mca_msr_reg(bank, MCA_ADDR), misc);
+ _log_error_deferred(bank, misc);
}
static void log_and_reset_block(struct threshold_block *block)
diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c
index 00483d1c27e4..c4477162c07d 100644
--- a/arch/x86/kernel/cpu/mce/severity.c
+++ b/arch/x86/kernel/cpu/mce/severity.c
@@ -203,6 +203,11 @@ static struct severity {
BITSET(MCI_STATUS_OVER|MCI_STATUS_UC)
),
MCESEV(
+ PANIC, "Uncorrected in kernel",
+ BITSET(MCI_STATUS_UC),
+ KERNEL
+ ),
+ MCESEV(
UC, "Uncorrected",
BITSET(MCI_STATUS_UC)
),
@@ -391,9 +396,6 @@ static noinstr int mce_severity_intel(struct mce *m, struct pt_regs *regs, char
*msg = s->msg;
s->covered = 1;
- if (s->sev >= MCE_UC_SEVERITY && ctx == IN_KERNEL)
- return MCE_PANIC_SEVERITY;
-
return s->sev;
}
}
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 1fcbd671f1df..fdd2c4a754ce 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -908,7 +908,7 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device,
kvec.iov_base = (void *)firmware->data;
kvec.iov_len = firmware->size;
- iov_iter_kvec(&iter, WRITE, &kvec, 1, firmware->size);
+ iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size);
ret = generic_load_microcode(cpu, &iter);
release_firmware(firmware);
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 831613959a92..46668e255421 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -475,6 +475,12 @@ static bool __init ms_hyperv_x2apic_available(void)
* (logically) generates MSIs directly to the system APIC irq domain.
* There is no HPET, and PCI MSI/MSI-X interrupts are remapped by the
* pci-hyperv host bridge.
+ *
+ * Note: for a Hyper-V root partition, this will always return false.
+ * The hypervisor doesn't expose these HYPERV_CPUID_VIRT_STACK_* cpuids by
+ * default, they are implemented as intercepts by the Windows Hyper-V stack.
+ * Even a nested root partition (L2 root) will not get them because the
+ * nested (L1) hypervisor filters them out.
*/
static bool __init ms_hyperv_msi_ext_dest_id(void)
{
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 3266ea36667c..c98e52ff5f20 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -575,7 +575,7 @@ static void clear_closid_rmid(int cpu)
state->default_rmid = 0;
state->cur_closid = 0;
state->cur_rmid = 0;
- wrmsr(IA32_PQR_ASSOC, 0, 0);
+ wrmsr(MSR_IA32_PQR_ASSOC, 0, 0);
}
static int resctrl_online_cpu(unsigned int cpu)
@@ -828,7 +828,6 @@ static __init void rdt_init_res_defs_intel(void)
if (r->rid == RDT_RESOURCE_L3 ||
r->rid == RDT_RESOURCE_L2) {
r->cache.arch_has_sparse_bitmaps = false;
- r->cache.arch_has_empty_bitmaps = false;
r->cache.arch_has_per_cpu_cfg = false;
r->cache.min_cbm_bits = 1;
} else if (r->rid == RDT_RESOURCE_MBA) {
@@ -849,7 +848,6 @@ static __init void rdt_init_res_defs_amd(void)
if (r->rid == RDT_RESOURCE_L3 ||
r->rid == RDT_RESOURCE_L2) {
r->cache.arch_has_sparse_bitmaps = true;
- r->cache.arch_has_empty_bitmaps = true;
r->cache.arch_has_per_cpu_cfg = true;
r->cache.min_cbm_bits = 0;
} else if (r->rid == RDT_RESOURCE_MBA) {
diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
index 1dafbdc5ac31..1df0e3262bca 100644
--- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
+++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
@@ -105,8 +105,7 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
return false;
}
- if ((!r->cache.arch_has_empty_bitmaps && val == 0) ||
- val > r->default_ctrl) {
+ if ((r->cache.min_cbm_bits > 0 && val == 0) || val > r->default_ctrl) {
rdt_last_cmd_puts("Mask out of range\n");
return false;
}
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index 5f7128686cfd..5ebd28e6aa0c 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -8,16 +8,6 @@
#include <linux/fs_context.h>
#include <linux/jump_label.h>
-#define MSR_IA32_L3_QOS_CFG 0xc81
-#define MSR_IA32_L2_QOS_CFG 0xc82
-#define MSR_IA32_L3_CBM_BASE 0xc90
-#define MSR_IA32_L2_CBM_BASE 0xd10
-#define MSR_IA32_MBA_THRTL_BASE 0xd50
-#define MSR_IA32_MBA_BW_BASE 0xc0000200
-
-#define MSR_IA32_QM_CTR 0x0c8e
-#define MSR_IA32_QM_EVTSEL 0x0c8d
-
#define L3_QOS_CDP_ENABLE 0x01ULL
#define L2_QOS_CDP_ENABLE 0x01ULL
diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
index d961ae3ed96e..ba8d0763b36b 100644
--- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
+++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
@@ -477,7 +477,7 @@ static int pseudo_lock_fn(void *_rdtgrp)
* pseudo-locked followed by reading of kernel memory to load it
* into the cache.
*/
- __wrmsr(IA32_PQR_ASSOC, rmid_p, rdtgrp->closid);
+ __wrmsr(MSR_IA32_PQR_ASSOC, rmid_p, rdtgrp->closid);
/*
* Cache was flushed earlier. Now access kernel memory to read it
* into cache region associated with just activated plr->closid.
@@ -513,7 +513,7 @@ static int pseudo_lock_fn(void *_rdtgrp)
* Critical section end: restore closid with capacity bitmask that
* does not overlap with pseudo-locked region.
*/
- __wrmsr(IA32_PQR_ASSOC, rmid_p, closid_p);
+ __wrmsr(MSR_IA32_PQR_ASSOC, rmid_p, closid_p);
/* Re-enable the hardware prefetcher(s) */
wrmsrl(MSR_MISC_FEATURE_CONTROL, saved_msr);
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index fc01f81f6e2a..f53944fb8f7f 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -40,6 +40,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 },
{ X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 },
{ X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 },
+ { X86_FEATURE_SGX_EDECCSSA, CPUID_EAX, 11, 0x00000012, 0 },
{ X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 },
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 },
diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index 1ec20807de1e..68f8b18d2278 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -160,8 +160,8 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page,
return ret;
pginfo.addr = encl_page->desc & PAGE_MASK;
- pginfo.contents = (unsigned long)kmap_atomic(b.contents);
- pcmd_page = kmap_atomic(b.pcmd);
+ pginfo.contents = (unsigned long)kmap_local_page(b.contents);
+ pcmd_page = kmap_local_page(b.pcmd);
pginfo.metadata = (unsigned long)pcmd_page + b.pcmd_offset;
if (secs_page)
@@ -187,8 +187,8 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page,
*/
pcmd_page_empty = !memchr_inv(pcmd_page, 0, PAGE_SIZE);
- kunmap_atomic(pcmd_page);
- kunmap_atomic((void *)(unsigned long)pginfo.contents);
+ kunmap_local(pcmd_page);
+ kunmap_local((void *)(unsigned long)pginfo.contents);
get_page(b.pcmd);
sgx_encl_put_backing(&b);
@@ -197,10 +197,10 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page,
if (pcmd_page_empty && !reclaimer_writing_to_pcmd(encl, pcmd_first_page)) {
sgx_encl_truncate_backing_page(encl, PFN_DOWN(page_pcmd_off));
- pcmd_page = kmap_atomic(b.pcmd);
+ pcmd_page = kmap_local_page(b.pcmd);
if (memchr_inv(pcmd_page, 0, PAGE_SIZE))
pr_warn("PCMD page not empty after truncate.\n");
- kunmap_atomic(pcmd_page);
+ kunmap_local(pcmd_page);
}
put_page(b.pcmd);
@@ -680,11 +680,15 @@ const struct vm_operations_struct sgx_vm_ops = {
void sgx_encl_release(struct kref *ref)
{
struct sgx_encl *encl = container_of(ref, struct sgx_encl, refcount);
+ unsigned long max_page_index = PFN_DOWN(encl->base + encl->size - 1);
struct sgx_va_page *va_page;
struct sgx_encl_page *entry;
- unsigned long index;
+ unsigned long count = 0;
+
+ XA_STATE(xas, &encl->page_array, PFN_DOWN(encl->base));
- xa_for_each(&encl->page_array, index, entry) {
+ xas_lock(&xas);
+ xas_for_each(&xas, entry, max_page_index) {
if (entry->epc_page) {
/*
* The page and its radix tree entry cannot be freed
@@ -699,9 +703,20 @@ void sgx_encl_release(struct kref *ref)
}
kfree(entry);
- /* Invoke scheduler to prevent soft lockups. */
- cond_resched();
+ /*
+ * Invoke scheduler on every XA_CHECK_SCHED iteration
+ * to prevent soft lockups.
+ */
+ if (!(++count % XA_CHECK_SCHED)) {
+ xas_pause(&xas);
+ xas_unlock(&xas);
+
+ cond_resched();
+
+ xas_lock(&xas);
+ }
}
+ xas_unlock(&xas);
xa_destroy(&encl->page_array);
diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index ebe79d60619f..21ca0a831b70 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -111,7 +111,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
encl->base = secs->base;
encl->size = secs->size;
encl->attributes = secs->attributes;
- encl->attributes_mask = SGX_ATTR_DEBUG | SGX_ATTR_MODE64BIT | SGX_ATTR_KSS;
+ encl->attributes_mask = SGX_ATTR_UNPRIV_MASK;
/* Set only after completion, as encl->lock has not been taken. */
set_bit(SGX_ENCL_CREATED, &encl->flags);
@@ -221,11 +221,11 @@ static int __sgx_encl_add_page(struct sgx_encl *encl,
pginfo.secs = (unsigned long)sgx_get_epc_virt_addr(encl->secs.epc_page);
pginfo.addr = encl_page->desc & PAGE_MASK;
pginfo.metadata = (unsigned long)secinfo;
- pginfo.contents = (unsigned long)kmap_atomic(src_page);
+ pginfo.contents = (unsigned long)kmap_local_page(src_page);
ret = __eadd(&pginfo, sgx_get_epc_virt_addr(epc_page));
- kunmap_atomic((void *)pginfo.contents);
+ kunmap_local((void *)pginfo.contents);
put_page(src_page);
return ret ? -EIO : 0;
@@ -356,6 +356,9 @@ static int sgx_validate_offset_length(struct sgx_encl *encl,
if (!length || !IS_ALIGNED(length, PAGE_SIZE))
return -EINVAL;
+ if (offset + length < offset)
+ return -EINVAL;
+
if (offset + length - PAGE_SIZE >= encl->size)
return -EINVAL;
diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
index 0aad028f04d4..e5a37b6e9aa5 100644
--- a/arch/x86/kernel/cpu/sgx/main.c
+++ b/arch/x86/kernel/cpu/sgx/main.c
@@ -165,17 +165,17 @@ static int __sgx_encl_ewb(struct sgx_epc_page *epc_page, void *va_slot,
pginfo.addr = 0;
pginfo.secs = 0;
- pginfo.contents = (unsigned long)kmap_atomic(backing->contents);
- pginfo.metadata = (unsigned long)kmap_atomic(backing->pcmd) +
+ pginfo.contents = (unsigned long)kmap_local_page(backing->contents);
+ pginfo.metadata = (unsigned long)kmap_local_page(backing->pcmd) +
backing->pcmd_offset;
ret = __ewb(&pginfo, sgx_get_epc_virt_addr(epc_page), va_slot);
set_page_dirty(backing->pcmd);
set_page_dirty(backing->contents);
- kunmap_atomic((void *)(unsigned long)(pginfo.metadata -
+ kunmap_local((void *)(unsigned long)(pginfo.metadata -
backing->pcmd_offset));
- kunmap_atomic((void *)(unsigned long)pginfo.contents);
+ kunmap_local((void *)(unsigned long)pginfo.contents);
return ret;
}
diff --git a/arch/x86/kernel/cpu/tsx.c b/arch/x86/kernel/cpu/tsx.c
index ec7bbac3a9f2..8009c8346d8f 100644
--- a/arch/x86/kernel/cpu/tsx.c
+++ b/arch/x86/kernel/cpu/tsx.c
@@ -58,24 +58,6 @@ static void tsx_enable(void)
wrmsrl(MSR_IA32_TSX_CTRL, tsx);
}
-static bool tsx_ctrl_is_supported(void)
-{
- u64 ia32_cap = x86_read_arch_cap_msr();
-
- /*
- * TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
- * MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
- *
- * TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
- * microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
- * bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
- * MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
- * tsx= cmdline requests will do nothing on CPUs without
- * MSR_IA32_TSX_CTRL support.
- */
- return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
-}
-
static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
{
if (boot_cpu_has_bug(X86_BUG_TAA))
@@ -135,7 +117,7 @@ static void tsx_clear_cpuid(void)
rdmsrl(MSR_TSX_FORCE_ABORT, msr);
msr |= MSR_TFA_TSX_CPUID_CLEAR;
wrmsrl(MSR_TSX_FORCE_ABORT, msr);
- } else if (tsx_ctrl_is_supported()) {
+ } else if (cpu_feature_enabled(X86_FEATURE_MSR_TSX_CTRL)) {
rdmsrl(MSR_IA32_TSX_CTRL, msr);
msr |= TSX_CTRL_CPUID_CLEAR;
wrmsrl(MSR_IA32_TSX_CTRL, msr);
@@ -158,7 +140,8 @@ static void tsx_dev_mode_disable(void)
u64 mcu_opt_ctrl;
/* Check if RTM_ALLOW exists */
- if (!boot_cpu_has_bug(X86_BUG_TAA) || !tsx_ctrl_is_supported() ||
+ if (!boot_cpu_has_bug(X86_BUG_TAA) ||
+ !cpu_feature_enabled(X86_FEATURE_MSR_TSX_CTRL) ||
!cpu_feature_enabled(X86_FEATURE_SRBDS_CTRL))
return;
@@ -191,7 +174,20 @@ void __init tsx_init(void)
return;
}
- if (!tsx_ctrl_is_supported()) {
+ /*
+ * TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
+ * MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
+ *
+ * TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
+ * microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
+ * bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
+ * MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
+ * tsx= cmdline requests will do nothing on CPUs without
+ * MSR_IA32_TSX_CTRL support.
+ */
+ if (x86_read_arch_cap_msr() & ARCH_CAP_TSX_CTRL_MSR) {
+ setup_force_cpu_cap(X86_FEATURE_MSR_TSX_CTRL);
+ } else {
tsx_ctrl_state = TSX_CTRL_NOT_SUPPORTED;
return;
}
diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c
index e75bc2f217ff..32d710f7eb84 100644
--- a/arch/x86/kernel/crash_dump_64.c
+++ b/arch/x86/kernel/crash_dump_64.c
@@ -57,7 +57,7 @@ ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
struct kvec kvec = { .iov_base = buf, .iov_len = count };
struct iov_iter iter;
- iov_iter_kvec(&iter, READ, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
return read_from_oldmem(&iter, count, ppos,
cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT));
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 5cd51f25f446..28da5dd83fc0 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -31,11 +31,6 @@ char __initdata cmd_line[COMMAND_LINE_SIZE];
int __initdata of_ioapic;
-void __init early_init_dt_add_memory_arch(u64 base, u64 size)
-{
- BUG();
-}
-
void __init add_dtb(u64 data)
{
initial_dtb = data + offsetof(struct setup_data, data);
@@ -167,7 +162,14 @@ static void __init dtb_lapic_setup(void)
return;
}
smp_found_config = 1;
- pic_mode = 1;
+ if (of_property_read_bool(dn, "intel,virtual-wire-mode")) {
+ pr_info("Virtual Wire compatibility mode.\n");
+ pic_mode = 0;
+ } else {
+ pr_info("IMCR and PIC compatibility mode.\n");
+ pic_mode = 1;
+ }
+
register_lapic_address(lapic_addr);
}
@@ -248,7 +250,7 @@ static void __init dtb_add_ioapic(struct device_node *dn)
ret = of_address_to_resource(dn, 0, &r);
if (ret) {
- printk(KERN_ERR "Can't obtain address from device node %pOF.\n", dn);
+ pr_err("Can't obtain address from device node %pOF.\n", dn);
return;
}
mp_register_ioapic(++ioapic_id, r.start, gsi_top, &cfg);
@@ -265,7 +267,7 @@ static void __init dtb_ioapic_setup(void)
of_ioapic = 1;
return;
}
- printk(KERN_ERR "Error: No information about IO-APIC in OF.\n");
+ pr_err("Error: No information about IO-APIC in OF.\n");
}
#else
static void __init dtb_ioapic_setup(void) {}
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
index 9417d5aa7305..16f9814c9be0 100644
--- a/arch/x86/kernel/espfix_64.c
+++ b/arch/x86/kernel/espfix_64.c
@@ -94,17 +94,7 @@ static inline unsigned long espfix_base_addr(unsigned int cpu)
static void init_espfix_random(void)
{
- unsigned long rand;
-
- /*
- * This is run before the entropy pools are initialized,
- * but this is hopefully better than nothing.
- */
- if (!arch_get_random_longs(&rand, 1)) {
- /* The constant is an arbitrary large prime */
- rand = rdtsc();
- rand *= 0xc345c6b72fd16123UL;
- }
+ unsigned long rand = get_random_long();
slot_random = rand % ESPFIX_STACKS_PER_PAGE;
page_random = (rand / ESPFIX_STACKS_PER_PAGE)
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 3b28c5b25e12..9baa89a8877d 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -391,8 +391,6 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
{
struct fpstate *kstate = gfpu->fpstate;
const union fpregs_state *ustate = buf;
- struct pkru_state *xpkru;
- int ret;
if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) {
if (ustate->xsave.header.xfeatures & ~XFEATURE_MASK_FPSSE)
@@ -406,16 +404,15 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
if (ustate->xsave.header.xfeatures & ~xcr0)
return -EINVAL;
- ret = copy_uabi_from_kernel_to_xstate(kstate, ustate);
- if (ret)
- return ret;
+ /*
+ * Nullify @vpkru to preserve its current value if PKRU's bit isn't set
+ * in the header. KVM's odd ABI is to leave PKRU untouched in this
+ * case (all other components are eventually re-initialized).
+ */
+ if (!(ustate->xsave.header.xfeatures & XFEATURE_MASK_PKRU))
+ vpkru = NULL;
- /* Retrieve PKRU if not in init state */
- if (kstate->regs.xsave.header.xfeatures & XFEATURE_MASK_PKRU) {
- xpkru = get_xsave_addr(&kstate->regs.xsave, XFEATURE_PKRU);
- *vpkru = xpkru->pkru;
- }
- return 0;
+ return copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
}
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
#endif /* CONFIG_KVM */
@@ -605,9 +602,9 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal)
if (test_thread_flag(TIF_NEED_FPU_LOAD))
fpregs_restore_userregs();
save_fpregs_to_fpstate(dst_fpu);
+ fpregs_unlock();
if (!(clone_flags & CLONE_THREAD))
fpu_inherit_perms(dst_fpu);
- fpregs_unlock();
/*
* Children never inherit PASID state.
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index 8946f89761cc..851eb13edc01 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -133,9 +133,6 @@ static void __init fpu__init_system_generic(void)
fpu__init_system_mxcsr();
}
-/* 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'.
*
@@ -143,8 +140,8 @@ static void __init fpu__init_system_generic(void)
* because that's how C aligns structs.
*/
#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
- BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
- TYPE_ALIGN(TYPE)))
+ BUILD_BUG_ON(sizeof(TYPE) != \
+ ALIGN(offsetofend(TYPE, MEMBER), _Alignof(TYPE)))
/*
* We append the 'struct fpu' to the task_struct:
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index 75ffaef8c299..6d056b68f4ed 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -167,7 +167,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
}
fpu_force_restore(fpu);
- ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf);
+ ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf, &target->thread.pkru);
out:
vfree(tmpbuf);
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index 91d4b6de58ab..558076dbde5b 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -396,7 +396,7 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx,
fpregs = &fpu->fpstate->regs;
if (use_xsave() && !fx_only) {
- if (copy_sigframe_from_user_to_xstate(fpu->fpstate, buf_fx))
+ if (copy_sigframe_from_user_to_xstate(tsk, buf_fx))
return false;
} else {
if (__copy_from_user(&fpregs->fxsave, buf_fx,
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 59e543b95a3c..714166cc25f2 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -440,8 +440,8 @@ static void __init __xstate_dump_leaves(void)
}
}
-#define XSTATE_WARN_ON(x) do { \
- if (WARN_ONCE(x, "XSAVE consistency problem, dumping leaves")) { \
+#define XSTATE_WARN_ON(x, fmt, ...) do { \
+ if (WARN_ONCE(x, "XSAVE consistency problem: " fmt, ##__VA_ARGS__)) { \
__xstate_dump_leaves(); \
} \
} while (0)
@@ -554,8 +554,7 @@ static bool __init check_xstate_against_struct(int nr)
(nr >= XFEATURE_MAX) ||
(nr == XFEATURE_PT_UNIMPLEMENTED_SO_FAR) ||
((nr >= XFEATURE_RSRVD_COMP_11) && (nr <= XFEATURE_RSRVD_COMP_16))) {
- WARN_ONCE(1, "no structure for xstate: %d\n", nr);
- XSTATE_WARN_ON(1);
+ XSTATE_WARN_ON(1, "No structure for xstate: %d\n", nr);
return false;
}
return true;
@@ -598,12 +597,13 @@ static bool __init paranoid_xstate_size_valid(unsigned int kernel_size)
* XSAVES.
*/
if (!xsaves && xfeature_is_supervisor(i)) {
- XSTATE_WARN_ON(1);
+ XSTATE_WARN_ON(1, "Got supervisor feature %d, but XSAVES not advertised\n", i);
return false;
}
}
size = xstate_calculate_size(fpu_kernel_cfg.max_features, compacted);
- XSTATE_WARN_ON(size != kernel_size);
+ XSTATE_WARN_ON(size != kernel_size,
+ "size %u != kernel_size %u\n", size, kernel_size);
return size == kernel_size;
}
@@ -1200,8 +1200,36 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
}
+/**
+ * copy_uabi_to_xstate - Copy a UABI format buffer to the kernel xstate
+ * @fpstate: The fpstate buffer to copy to
+ * @kbuf: The UABI format buffer, if it comes from the kernel
+ * @ubuf: The UABI format buffer, if it comes from userspace
+ * @pkru: The location to write the PKRU value to
+ *
+ * Converts from the UABI format into the kernel internal hardware
+ * dependent format.
+ *
+ * This function ultimately has three different callers with distinct PKRU
+ * behavior.
+ * 1. When called from sigreturn the PKRU register will be restored from
+ * @fpstate via an XRSTOR. Correctly copying the UABI format buffer to
+ * @fpstate is sufficient to cover this case, but the caller will also
+ * pass a pointer to the thread_struct's pkru field in @pkru and updating
+ * it is harmless.
+ * 2. When called from ptrace the PKRU register will be restored from the
+ * thread_struct's pkru field. A pointer to that is passed in @pkru.
+ * The kernel will restore it manually, so the XRSTOR behavior that resets
+ * the PKRU register to the hardware init value (0) if the corresponding
+ * xfeatures bit is not set is emulated here.
+ * 3. When called from KVM the PKRU register will be restored from the vcpu's
+ * pkru field. A pointer to that is passed in @pkru. KVM hasn't used
+ * XRSTOR and hasn't had the PKRU resetting behavior described above. To
+ * preserve that KVM behavior, it passes NULL for @pkru if the xfeatures
+ * bit is not set.
+ */
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
- const void __user *ubuf)
+ const void __user *ubuf, u32 *pkru)
{
struct xregs_state *xsave = &fpstate->regs.xsave;
unsigned int offset, size;
@@ -1250,6 +1278,20 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
}
}
+ if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
+ struct pkru_state *xpkru;
+
+ xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
+ *pkru = xpkru->pkru;
+ } else {
+ /*
+ * KVM may pass NULL here to indicate that it does not need
+ * PKRU updated.
+ */
+ if (pkru)
+ *pkru = 0;
+ }
+
/*
* The state that came in from userspace was user-state only.
* Mask all the user states out of 'xfeatures':
@@ -1268,9 +1310,9 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
* Convert from a ptrace standard-format kernel buffer to kernel XSAVE[S]
* format and copy to the target thread. Used by ptrace and KVM.
*/
-int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf)
+int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru)
{
- return copy_uabi_to_xstate(fpstate, kbuf, NULL);
+ return copy_uabi_to_xstate(fpstate, kbuf, NULL, pkru);
}
/*
@@ -1278,10 +1320,10 @@ int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf)
* XSAVE[S] format and copy to the target thread. This is called from the
* sigreturn() and rt_sigreturn() system calls.
*/
-int copy_sigframe_from_user_to_xstate(struct fpstate *fpstate,
+int copy_sigframe_from_user_to_xstate(struct task_struct *tsk,
const void __user *ubuf)
{
- return copy_uabi_to_xstate(fpstate, NULL, ubuf);
+ return copy_uabi_to_xstate(tsk->thread.fpu.fpstate, NULL, ubuf, &tsk->thread.pkru);
}
static bool validate_independent_components(u64 mask)
diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h
index 5ad47031383b..a4ecb04d8d64 100644
--- a/arch/x86/kernel/fpu/xstate.h
+++ b/arch/x86/kernel/fpu/xstate.h
@@ -46,8 +46,8 @@ extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
u32 pkru_val, enum xstate_copy_mode copy_mode);
extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
enum xstate_copy_mode mode);
-extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf);
-extern int copy_sigframe_from_user_to_xstate(struct fpstate *fpstate, const void __user *ubuf);
+extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru);
+extern int copy_sigframe_from_user_to_xstate(struct task_struct *tsk, const void __user *ubuf);
extern void fpu__init_cpu_xstate(void);
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 9b7acc9c7874..67c8ed99144b 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -261,16 +261,6 @@ SYM_FUNC_START(startup_32_smp)
addl $__PAGE_OFFSET, %esp
/*
- * start system 32-bit setup. We need to re-do some of the things done
- * in 16-bit mode for the "real" operations.
- */
- movl setup_once_ref,%eax
- andl %eax,%eax
- jz 1f # Did we do this already?
- call *%eax
-1:
-
-/*
* Check if it is 486
*/
movb $4,X86 # at least 486
@@ -331,18 +321,7 @@ SYM_FUNC_END(startup_32_smp)
#include "verify_cpu.S"
-/*
- * setup_once
- *
- * The setup work we only want to run on the BSP.
- *
- * Warning: %esi is live across this function.
- */
__INIT
-setup_once:
- andl $0,setup_once_ref /* Once is enough, thanks */
- RET
-
SYM_FUNC_START(early_idt_handler_array)
# 36(%esp) %eflags
# 32(%esp) %cs
@@ -458,7 +437,6 @@ SYM_DATA(early_recursion_flag, .long 0)
__REFDATA
.align 4
SYM_DATA(initial_code, .long i386_start_kernel)
-SYM_DATA(setup_once_ref, .long setup_once)
#ifdef CONFIG_PAGE_TABLE_ISOLATION
#define PGD_ALIGN (2 * PAGE_SIZE)
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index 15aefa3f3e18..3aa5304200c5 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -407,7 +407,7 @@ struct legacy_pic null_legacy_pic = {
.make_irq = legacy_pic_uint_noop,
};
-struct legacy_pic default_legacy_pic = {
+static struct legacy_pic default_legacy_pic = {
.nr_legacy_irqs = NR_IRQS_LEGACY,
.chip = &i8259A_chip,
.mask = mask_8259A_irq,
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index c032edcd3d95..d85a6980e263 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -53,7 +53,7 @@ static unsigned long int get_module_load_offset(void)
*/
if (module_load_offset == 0)
module_load_offset =
- (prandom_u32_max(1024) + 1) * PAGE_SIZE;
+ get_random_u32_inclusive(1, 1024) * PAGE_SIZE;
mutex_unlock(&module_kaslr_mutex);
}
return module_load_offset;
@@ -251,14 +251,12 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
+ const Elf_Shdr *s, *alt = NULL, *locks = NULL,
*para = NULL, *orc = NULL, *orc_ip = NULL,
*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL;
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
- if (!strcmp(".text", secstrings + s->sh_name))
- text = s;
if (!strcmp(".altinstructions", secstrings + s->sh_name))
alt = s;
if (!strcmp(".smp_locks", secstrings + s->sh_name))
@@ -302,12 +300,13 @@ int module_finalize(const Elf_Ehdr *hdr,
void *iseg = (void *)ibt_endbr->sh_addr;
apply_ibt_endbr(iseg, iseg + ibt_endbr->sh_size);
}
- if (locks && text) {
+ if (locks) {
void *lseg = (void *)locks->sh_addr;
- void *tseg = (void *)text->sh_addr;
+ void *text = me->core_layout.base;
+ void *text_end = text + me->core_layout.text_size;
alternatives_smp_module_add(me, me->name,
lseg, lseg + locks->sh_size,
- tseg, tseg + text->sh_size);
+ text, text_end);
}
if (orc && orc_ip)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index c21b7347a26d..40d156a31676 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -600,7 +600,7 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
}
if (updmsr)
- write_spec_ctrl_current(msr, false);
+ update_spec_ctrl_cond(msr);
}
static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
@@ -965,7 +965,7 @@ early_param("idle", idle_setup);
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
- sp -= prandom_u32_max(8192);
+ sp -= get_random_u32_below(8192);
return sp & ~0xf;
}
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 37c12fb92906..dfaa270a7cc9 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -44,16 +44,35 @@
#include "tls.h"
-enum x86_regset {
- REGSET_GENERAL,
- REGSET_FP,
- REGSET_XFP,
- REGSET_IOPERM64 = REGSET_XFP,
- REGSET_XSTATE,
- REGSET_TLS,
- REGSET_IOPERM32,
+enum x86_regset_32 {
+ REGSET32_GENERAL,
+ REGSET32_FP,
+ REGSET32_XFP,
+ REGSET32_XSTATE,
+ REGSET32_TLS,
+ REGSET32_IOPERM,
};
+enum x86_regset_64 {
+ REGSET64_GENERAL,
+ REGSET64_FP,
+ REGSET64_IOPERM,
+ REGSET64_XSTATE,
+};
+
+#define REGSET_GENERAL \
+({ \
+ BUILD_BUG_ON((int)REGSET32_GENERAL != (int)REGSET64_GENERAL); \
+ REGSET32_GENERAL; \
+})
+
+#define REGSET_FP \
+({ \
+ BUILD_BUG_ON((int)REGSET32_FP != (int)REGSET64_FP); \
+ REGSET32_FP; \
+})
+
+
struct pt_regs_offset {
const char *name;
int offset;
@@ -788,13 +807,13 @@ long arch_ptrace(struct task_struct *child, long request,
#ifdef CONFIG_X86_32
case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */
return copy_regset_to_user(child, &user_x86_32_view,
- REGSET_XFP,
+ REGSET32_XFP,
0, sizeof(struct user_fxsr_struct),
datap) ? -EIO : 0;
case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
return copy_regset_from_user(child, &user_x86_32_view,
- REGSET_XFP,
+ REGSET32_XFP,
0, sizeof(struct user_fxsr_struct),
datap) ? -EIO : 0;
#endif
@@ -1086,13 +1105,13 @@ static long ia32_arch_ptrace(struct task_struct *child, compat_long_t request,
case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */
return copy_regset_to_user(child, &user_x86_32_view,
- REGSET_XFP, 0,
+ REGSET32_XFP, 0,
sizeof(struct user32_fxsr_struct),
datap);
case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
return copy_regset_from_user(child, &user_x86_32_view,
- REGSET_XFP, 0,
+ REGSET32_XFP, 0,
sizeof(struct user32_fxsr_struct),
datap);
@@ -1215,29 +1234,38 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
#ifdef CONFIG_X86_64
static struct user_regset x86_64_regsets[] __ro_after_init = {
- [REGSET_GENERAL] = {
- .core_note_type = NT_PRSTATUS,
- .n = sizeof(struct user_regs_struct) / sizeof(long),
- .size = sizeof(long), .align = sizeof(long),
- .regset_get = genregs_get, .set = genregs_set
+ [REGSET64_GENERAL] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = sizeof(struct user_regs_struct) / sizeof(long),
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .regset_get = genregs_get,
+ .set = genregs_set
},
- [REGSET_FP] = {
- .core_note_type = NT_PRFPREG,
- .n = sizeof(struct fxregs_state) / sizeof(long),
- .size = sizeof(long), .align = sizeof(long),
- .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
+ [REGSET64_FP] = {
+ .core_note_type = NT_PRFPREG,
+ .n = sizeof(struct fxregs_state) / sizeof(long),
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .active = regset_xregset_fpregs_active,
+ .regset_get = xfpregs_get,
+ .set = xfpregs_set
},
- [REGSET_XSTATE] = {
- .core_note_type = NT_X86_XSTATE,
- .size = sizeof(u64), .align = sizeof(u64),
- .active = xstateregs_active, .regset_get = xstateregs_get,
- .set = xstateregs_set
+ [REGSET64_XSTATE] = {
+ .core_note_type = NT_X86_XSTATE,
+ .size = sizeof(u64),
+ .align = sizeof(u64),
+ .active = xstateregs_active,
+ .regset_get = xstateregs_get,
+ .set = xstateregs_set
},
- [REGSET_IOPERM64] = {
- .core_note_type = NT_386_IOPERM,
- .n = IO_BITMAP_LONGS,
- .size = sizeof(long), .align = sizeof(long),
- .active = ioperm_active, .regset_get = ioperm_get
+ [REGSET64_IOPERM] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_LONGS,
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .active = ioperm_active,
+ .regset_get = ioperm_get
},
};
@@ -1256,43 +1284,57 @@ static const struct user_regset_view user_x86_64_view = {
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static struct user_regset x86_32_regsets[] __ro_after_init = {
- [REGSET_GENERAL] = {
- .core_note_type = NT_PRSTATUS,
- .n = sizeof(struct user_regs_struct32) / sizeof(u32),
- .size = sizeof(u32), .align = sizeof(u32),
- .regset_get = genregs32_get, .set = genregs32_set
+ [REGSET32_GENERAL] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = sizeof(struct user_regs_struct32) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .regset_get = genregs32_get,
+ .set = genregs32_set
},
- [REGSET_FP] = {
- .core_note_type = NT_PRFPREG,
- .n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
- .size = sizeof(u32), .align = sizeof(u32),
- .active = regset_fpregs_active, .regset_get = fpregs_get, .set = fpregs_set
+ [REGSET32_FP] = {
+ .core_note_type = NT_PRFPREG,
+ .n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .active = regset_fpregs_active,
+ .regset_get = fpregs_get,
+ .set = fpregs_set
},
- [REGSET_XFP] = {
- .core_note_type = NT_PRXFPREG,
- .n = sizeof(struct fxregs_state) / sizeof(u32),
- .size = sizeof(u32), .align = sizeof(u32),
- .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
+ [REGSET32_XFP] = {
+ .core_note_type = NT_PRXFPREG,
+ .n = sizeof(struct fxregs_state) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .active = regset_xregset_fpregs_active,
+ .regset_get = xfpregs_get,
+ .set = xfpregs_set
},
- [REGSET_XSTATE] = {
- .core_note_type = NT_X86_XSTATE,
- .size = sizeof(u64), .align = sizeof(u64),
- .active = xstateregs_active, .regset_get = xstateregs_get,
- .set = xstateregs_set
+ [REGSET32_XSTATE] = {
+ .core_note_type = NT_X86_XSTATE,
+ .size = sizeof(u64),
+ .align = sizeof(u64),
+ .active = xstateregs_active,
+ .regset_get = xstateregs_get,
+ .set = xstateregs_set
},
- [REGSET_TLS] = {
- .core_note_type = NT_386_TLS,
- .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN,
- .size = sizeof(struct user_desc),
- .align = sizeof(struct user_desc),
- .active = regset_tls_active,
- .regset_get = regset_tls_get, .set = regset_tls_set
+ [REGSET32_TLS] = {
+ .core_note_type = NT_386_TLS,
+ .n = GDT_ENTRY_TLS_ENTRIES,
+ .bias = GDT_ENTRY_TLS_MIN,
+ .size = sizeof(struct user_desc),
+ .align = sizeof(struct user_desc),
+ .active = regset_tls_active,
+ .regset_get = regset_tls_get,
+ .set = regset_tls_set
},
- [REGSET_IOPERM32] = {
- .core_note_type = NT_386_IOPERM,
- .n = IO_BITMAP_BYTES / sizeof(u32),
- .size = sizeof(u32), .align = sizeof(u32),
- .active = ioperm_active, .regset_get = ioperm_get
+ [REGSET32_IOPERM] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_BYTES / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .active = ioperm_active,
+ .regset_get = ioperm_get
},
};
@@ -1311,10 +1353,10 @@ u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
{
#ifdef CONFIG_X86_64
- x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64);
+ x86_64_regsets[REGSET64_XSTATE].n = size / sizeof(u64);
#endif
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
- x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64);
+ x86_32_regsets[REGSET32_XSTATE].n = size / sizeof(u64);
#endif
xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask;
}
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 49325caa7307..b26123c90b4f 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -11,6 +11,7 @@
#include <linux/smp.h>
#include <linux/topology.h>
#include <linux/pfn.h>
+#include <linux/stackprotector.h>
#include <asm/sections.h>
#include <asm/processor.h>
#include <asm/desc.h>
@@ -21,7 +22,6 @@
#include <asm/proto.h>
#include <asm/cpumask.h>
#include <asm/cpu.h>
-#include <asm/stackprotector.h>
DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
EXPORT_PER_CPU_SYMBOL(cpu_number);
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 9c7265b524c7..1504eb8d25aa 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -37,180 +37,27 @@
#include <asm/sighandling.h>
#include <asm/vm86.h>
-#ifdef CONFIG_X86_64
-#include <linux/compat.h>
-#include <asm/proto.h>
-#include <asm/ia32_unistd.h>
-#include <asm/fpu/xstate.h>
-#endif /* CONFIG_X86_64 */
-
#include <asm/syscall.h>
#include <asm/sigframe.h>
#include <asm/signal.h>
-#ifdef CONFIG_X86_64
-/*
- * If regs->ss will cause an IRET fault, change it. Otherwise leave it
- * alone. Using this generally makes no sense unless
- * user_64bit_mode(regs) would return true.
- */
-static void force_valid_ss(struct pt_regs *regs)
+static inline int is_ia32_compat_frame(struct ksignal *ksig)
{
- u32 ar;
- asm volatile ("lar %[old_ss], %[ar]\n\t"
- "jz 1f\n\t" /* If invalid: */
- "xorl %[ar], %[ar]\n\t" /* set ar = 0 */
- "1:"
- : [ar] "=r" (ar)
- : [old_ss] "rm" ((u16)regs->ss));
-
- /*
- * For a valid 64-bit user context, we need DPL 3, type
- * read-write data or read-write exp-down data, and S and P
- * set. We can't use VERW because VERW doesn't check the
- * P bit.
- */
- ar &= AR_DPL_MASK | AR_S | AR_P | AR_TYPE_MASK;
- if (ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA) &&
- ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN))
- regs->ss = __USER_DS;
+ return IS_ENABLED(CONFIG_IA32_EMULATION) &&
+ ksig->ka.sa.sa_flags & SA_IA32_ABI;
}
-# define CONTEXT_COPY_SIZE offsetof(struct sigcontext, reserved1)
-#else
-# define CONTEXT_COPY_SIZE sizeof(struct sigcontext)
-#endif
-static bool restore_sigcontext(struct pt_regs *regs,
- struct sigcontext __user *usc,
- unsigned long uc_flags)
+static inline int is_ia32_frame(struct ksignal *ksig)
{
- struct sigcontext sc;
-
- /* Always make any pending restarted system calls return -EINTR */
- current->restart_block.fn = do_no_restart_syscall;
-
- if (copy_from_user(&sc, usc, CONTEXT_COPY_SIZE))
- return false;
-
-#ifdef CONFIG_X86_32
- loadsegment(gs, sc.gs);
- regs->fs = sc.fs;
- regs->es = sc.es;
- regs->ds = sc.ds;
-#endif /* CONFIG_X86_32 */
-
- regs->bx = sc.bx;
- regs->cx = sc.cx;
- regs->dx = sc.dx;
- regs->si = sc.si;
- regs->di = sc.di;
- regs->bp = sc.bp;
- regs->ax = sc.ax;
- regs->sp = sc.sp;
- regs->ip = sc.ip;
-
-#ifdef CONFIG_X86_64
- regs->r8 = sc.r8;
- regs->r9 = sc.r9;
- regs->r10 = sc.r10;
- regs->r11 = sc.r11;
- regs->r12 = sc.r12;
- regs->r13 = sc.r13;
- regs->r14 = sc.r14;
- regs->r15 = sc.r15;
-#endif /* CONFIG_X86_64 */
-
- /* Get CS/SS and force CPL3 */
- regs->cs = sc.cs | 0x03;
- regs->ss = sc.ss | 0x03;
-
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
- /* disable syscall checks */
- regs->orig_ax = -1;
-
-#ifdef CONFIG_X86_64
- /*
- * Fix up SS if needed for the benefit of old DOSEMU and
- * CRIU.
- */
- if (unlikely(!(uc_flags & UC_STRICT_RESTORE_SS) && user_64bit_mode(regs)))
- force_valid_ss(regs);
-#endif
-
- return fpu__restore_sig((void __user *)sc.fpstate,
- IS_ENABLED(CONFIG_X86_32));
+ return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig);
}
-static __always_inline int
-__unsafe_setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
- struct pt_regs *regs, unsigned long mask)
+static inline int is_x32_frame(struct ksignal *ksig)
{
-#ifdef CONFIG_X86_32
- unsigned int gs;
- savesegment(gs, gs);
-
- unsafe_put_user(gs, (unsigned int __user *)&sc->gs, Efault);
- unsafe_put_user(regs->fs, (unsigned int __user *)&sc->fs, Efault);
- unsafe_put_user(regs->es, (unsigned int __user *)&sc->es, Efault);
- unsafe_put_user(regs->ds, (unsigned int __user *)&sc->ds, Efault);
-#endif /* CONFIG_X86_32 */
-
- unsafe_put_user(regs->di, &sc->di, Efault);
- unsafe_put_user(regs->si, &sc->si, Efault);
- unsafe_put_user(regs->bp, &sc->bp, Efault);
- unsafe_put_user(regs->sp, &sc->sp, Efault);
- unsafe_put_user(regs->bx, &sc->bx, Efault);
- unsafe_put_user(regs->dx, &sc->dx, Efault);
- unsafe_put_user(regs->cx, &sc->cx, Efault);
- unsafe_put_user(regs->ax, &sc->ax, Efault);
-#ifdef CONFIG_X86_64
- unsafe_put_user(regs->r8, &sc->r8, Efault);
- unsafe_put_user(regs->r9, &sc->r9, Efault);
- unsafe_put_user(regs->r10, &sc->r10, Efault);
- unsafe_put_user(regs->r11, &sc->r11, Efault);
- unsafe_put_user(regs->r12, &sc->r12, Efault);
- unsafe_put_user(regs->r13, &sc->r13, Efault);
- unsafe_put_user(regs->r14, &sc->r14, Efault);
- unsafe_put_user(regs->r15, &sc->r15, Efault);
-#endif /* CONFIG_X86_64 */
-
- unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault);
- unsafe_put_user(current->thread.error_code, &sc->err, Efault);
- unsafe_put_user(regs->ip, &sc->ip, Efault);
-#ifdef CONFIG_X86_32
- unsafe_put_user(regs->cs, (unsigned int __user *)&sc->cs, Efault);
- unsafe_put_user(regs->flags, &sc->flags, Efault);
- unsafe_put_user(regs->sp, &sc->sp_at_signal, Efault);
- unsafe_put_user(regs->ss, (unsigned int __user *)&sc->ss, Efault);
-#else /* !CONFIG_X86_32 */
- unsafe_put_user(regs->flags, &sc->flags, Efault);
- unsafe_put_user(regs->cs, &sc->cs, Efault);
- unsafe_put_user(0, &sc->gs, Efault);
- unsafe_put_user(0, &sc->fs, Efault);
- unsafe_put_user(regs->ss, &sc->ss, Efault);
-#endif /* CONFIG_X86_32 */
-
- unsafe_put_user(fpstate, (unsigned long __user *)&sc->fpstate, Efault);
-
- /* non-iBCS2 extensions.. */
- unsafe_put_user(mask, &sc->oldmask, Efault);
- unsafe_put_user(current->thread.cr2, &sc->cr2, Efault);
- return 0;
-Efault:
- return -EFAULT;
+ return IS_ENABLED(CONFIG_X86_X32_ABI) &&
+ ksig->ka.sa.sa_flags & SA_X32_ABI;
}
-#define unsafe_put_sigcontext(sc, fp, regs, set, label) \
-do { \
- if (__unsafe_setup_sigcontext(sc, fp, regs, set->sig[0])) \
- goto label; \
-} while(0);
-
-#define unsafe_put_sigmask(set, frame, label) \
- unsafe_put_user(*(__u64 *)(set), \
- (__u64 __user *)&(frame)->uc.uc_sigmask, \
- label)
-
/*
* Set up a signal frame.
*/
@@ -223,24 +70,12 @@ do { \
/*
* Determine which stack to use..
*/
-static unsigned long align_sigframe(unsigned long sp)
-{
-#ifdef CONFIG_X86_32
- /*
- * Align the stack pointer according to the i386 ABI,
- * i.e. so that on function entry ((sp + 4) & 15) == 0.
- */
- sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4;
-#else /* !CONFIG_X86_32 */
- sp = round_down(sp, FRAME_ALIGNMENT) - 8;
-#endif
- return sp;
-}
-
-static void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
+void __user *
+get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
void __user **fpstate)
{
+ struct k_sigaction *ka = &ksig->ka;
+ int ia32_frame = is_ia32_frame(ksig);
/* Default to using normal stack */
bool nested_altstack = on_sig_stack(regs->sp);
bool entering_altstack = false;
@@ -249,7 +84,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
unsigned long buf_fx = 0;
/* redzone */
- if (IS_ENABLED(CONFIG_X86_64))
+ if (!ia32_frame)
sp -= 128;
/* This is the X/Open sanctioned signal stack switching. */
@@ -263,7 +98,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
sp = current->sas_ss_sp + current->sas_ss_size;
entering_altstack = true;
}
- } else if (IS_ENABLED(CONFIG_X86_32) &&
+ } else if (ia32_frame &&
!nested_altstack &&
regs->ss != __USER_DS &&
!(ka->sa.sa_flags & SA_RESTORER) &&
@@ -273,11 +108,19 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
entering_altstack = true;
}
- sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32),
- &buf_fx, &math_size);
+ sp = fpu__alloc_mathframe(sp, ia32_frame, &buf_fx, &math_size);
*fpstate = (void __user *)sp;
- sp = align_sigframe(sp - frame_size);
+ sp -= frame_size;
+
+ if (ia32_frame)
+ /*
+ * Align the stack pointer according to the i386 ABI,
+ * i.e. so that on function entry ((sp + 4) & 15) == 0.
+ */
+ sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4;
+ else
+ sp = round_down(sp, FRAME_ALIGNMENT) - 8;
/*
* If we are on the alternate signal stack and would overflow it, don't.
@@ -300,391 +143,6 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
return (void __user *)sp;
}
-#ifdef CONFIG_X86_32
-static const struct {
- u16 poplmovl;
- u32 val;
- u16 int80;
-} __attribute__((packed)) retcode = {
- 0xb858, /* popl %eax; movl $..., %eax */
- __NR_sigreturn,
- 0x80cd, /* int $0x80 */
-};
-
-static const struct {
- u8 movl;
- u32 val;
- u16 int80;
- u8 pad;
-} __attribute__((packed)) rt_retcode = {
- 0xb8, /* movl $..., %eax */
- __NR_rt_sigreturn,
- 0x80cd, /* int $0x80 */
- 0
-};
-
-static int
-__setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
- struct pt_regs *regs)
-{
- struct sigframe __user *frame;
- void __user *restorer;
- void __user *fp = NULL;
-
- frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
-
- if (!user_access_begin(frame, sizeof(*frame)))
- return -EFAULT;
-
- unsafe_put_user(sig, &frame->sig, Efault);
- unsafe_put_sigcontext(&frame->sc, fp, regs, set, Efault);
- unsafe_put_user(set->sig[1], &frame->extramask[0], Efault);
- if (current->mm->context.vdso)
- restorer = current->mm->context.vdso +
- vdso_image_32.sym___kernel_sigreturn;
- else
- restorer = &frame->retcode;
- if (ksig->ka.sa.sa_flags & SA_RESTORER)
- restorer = ksig->ka.sa.sa_restorer;
-
- /* Set up to return from userspace. */
- unsafe_put_user(restorer, &frame->pretcode, Efault);
-
- /*
- * This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80
- *
- * WE DO NOT USE IT ANY MORE! It's only left here for historical
- * reasons and because gdb uses it as a signature to notice
- * signal handler stack frames.
- */
- unsafe_put_user(*((u64 *)&retcode), (u64 *)frame->retcode, Efault);
- user_access_end();
-
- /* Set up registers for signal handler */
- regs->sp = (unsigned long)frame;
- regs->ip = (unsigned long)ksig->ka.sa.sa_handler;
- regs->ax = (unsigned long)sig;
- regs->dx = 0;
- regs->cx = 0;
-
- regs->ds = __USER_DS;
- regs->es = __USER_DS;
- regs->ss = __USER_DS;
- regs->cs = __USER_CS;
-
- return 0;
-
-Efault:
- user_access_end();
- return -EFAULT;
-}
-
-static int __setup_rt_frame(int sig, struct ksignal *ksig,
- sigset_t *set, struct pt_regs *regs)
-{
- struct rt_sigframe __user *frame;
- void __user *restorer;
- void __user *fp = NULL;
-
- frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
-
- if (!user_access_begin(frame, sizeof(*frame)))
- return -EFAULT;
-
- unsafe_put_user(sig, &frame->sig, Efault);
- unsafe_put_user(&frame->info, &frame->pinfo, Efault);
- unsafe_put_user(&frame->uc, &frame->puc, Efault);
-
- /* Create the ucontext. */
- if (static_cpu_has(X86_FEATURE_XSAVE))
- unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
- else
- unsafe_put_user(0, &frame->uc.uc_flags, Efault);
- unsafe_put_user(0, &frame->uc.uc_link, Efault);
- unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
-
- /* Set up to return from userspace. */
- restorer = current->mm->context.vdso +
- vdso_image_32.sym___kernel_rt_sigreturn;
- if (ksig->ka.sa.sa_flags & SA_RESTORER)
- restorer = ksig->ka.sa.sa_restorer;
- unsafe_put_user(restorer, &frame->pretcode, Efault);
-
- /*
- * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
- *
- * WE DO NOT USE IT ANY MORE! It's only left here for historical
- * reasons and because gdb uses it as a signature to notice
- * signal handler stack frames.
- */
- unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault);
- unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
- unsafe_put_sigmask(set, frame, Efault);
- user_access_end();
-
- if (copy_siginfo_to_user(&frame->info, &ksig->info))
- return -EFAULT;
-
- /* Set up registers for signal handler */
- regs->sp = (unsigned long)frame;
- regs->ip = (unsigned long)ksig->ka.sa.sa_handler;
- regs->ax = (unsigned long)sig;
- regs->dx = (unsigned long)&frame->info;
- regs->cx = (unsigned long)&frame->uc;
-
- regs->ds = __USER_DS;
- regs->es = __USER_DS;
- regs->ss = __USER_DS;
- regs->cs = __USER_CS;
-
- return 0;
-Efault:
- user_access_end();
- return -EFAULT;
-}
-#else /* !CONFIG_X86_32 */
-static unsigned long frame_uc_flags(struct pt_regs *regs)
-{
- unsigned long flags;
-
- if (boot_cpu_has(X86_FEATURE_XSAVE))
- flags = UC_FP_XSTATE | UC_SIGCONTEXT_SS;
- else
- flags = UC_SIGCONTEXT_SS;
-
- if (likely(user_64bit_mode(regs)))
- flags |= UC_STRICT_RESTORE_SS;
-
- return flags;
-}
-
-static int __setup_rt_frame(int sig, struct ksignal *ksig,
- sigset_t *set, struct pt_regs *regs)
-{
- struct rt_sigframe __user *frame;
- void __user *fp = NULL;
- unsigned long uc_flags;
-
- /* x86-64 should always use SA_RESTORER. */
- if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
- return -EFAULT;
-
- frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
- uc_flags = frame_uc_flags(regs);
-
- if (!user_access_begin(frame, sizeof(*frame)))
- return -EFAULT;
-
- /* Create the ucontext. */
- unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
- unsafe_put_user(0, &frame->uc.uc_link, Efault);
- unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
- unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
- unsafe_put_sigmask(set, frame, Efault);
- user_access_end();
-
- if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
- if (copy_siginfo_to_user(&frame->info, &ksig->info))
- return -EFAULT;
- }
-
- /* Set up registers for signal handler */
- regs->di = sig;
- /* In case the signal handler was declared without prototypes */
- regs->ax = 0;
-
- /* This also works for non SA_SIGINFO handlers because they expect the
- next argument after the signal number on the stack. */
- regs->si = (unsigned long)&frame->info;
- regs->dx = (unsigned long)&frame->uc;
- regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
-
- regs->sp = (unsigned long)frame;
-
- /*
- * Set up the CS and SS registers to run signal handlers in
- * 64-bit mode, even if the handler happens to be interrupting
- * 32-bit or 16-bit code.
- *
- * SS is subtle. In 64-bit mode, we don't need any particular
- * SS descriptor, but we do need SS to be valid. It's possible
- * that the old SS is entirely bogus -- this can happen if the
- * signal we're trying to deliver is #GP or #SS caused by a bad
- * SS value. We also have a compatibility issue here: DOSEMU
- * relies on the contents of the SS register indicating the
- * SS value at the time of the signal, even though that code in
- * DOSEMU predates sigreturn's ability to restore SS. (DOSEMU
- * avoids relying on sigreturn to restore SS; instead it uses
- * a trampoline.) So we do our best: if the old SS was valid,
- * we keep it. Otherwise we replace it.
- */
- regs->cs = __USER_CS;
-
- if (unlikely(regs->ss != __USER_DS))
- force_valid_ss(regs);
-
- return 0;
-
-Efault:
- user_access_end();
- return -EFAULT;
-}
-#endif /* CONFIG_X86_32 */
-
-#ifdef CONFIG_X86_X32_ABI
-static int x32_copy_siginfo_to_user(struct compat_siginfo __user *to,
- const struct kernel_siginfo *from)
-{
- struct compat_siginfo new;
-
- copy_siginfo_to_external32(&new, from);
- if (from->si_signo == SIGCHLD) {
- new._sifields._sigchld_x32._utime = from->si_utime;
- new._sifields._sigchld_x32._stime = from->si_stime;
- }
- if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
- return -EFAULT;
- return 0;
-}
-
-int copy_siginfo_to_user32(struct compat_siginfo __user *to,
- const struct kernel_siginfo *from)
-{
- if (in_x32_syscall())
- return x32_copy_siginfo_to_user(to, from);
- return __copy_siginfo_to_user32(to, from);
-}
-#endif /* CONFIG_X86_X32_ABI */
-
-static int x32_setup_rt_frame(struct ksignal *ksig,
- compat_sigset_t *set,
- struct pt_regs *regs)
-{
-#ifdef CONFIG_X86_X32_ABI
- struct rt_sigframe_x32 __user *frame;
- unsigned long uc_flags;
- void __user *restorer;
- void __user *fp = NULL;
-
- if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
- return -EFAULT;
-
- frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
-
- uc_flags = frame_uc_flags(regs);
-
- if (!user_access_begin(frame, sizeof(*frame)))
- return -EFAULT;
-
- /* Create the ucontext. */
- unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
- unsafe_put_user(0, &frame->uc.uc_link, Efault);
- unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
- unsafe_put_user(0, &frame->uc.uc__pad0, Efault);
- restorer = ksig->ka.sa.sa_restorer;
- unsafe_put_user(restorer, (unsigned long __user *)&frame->pretcode, Efault);
- unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
- unsafe_put_sigmask(set, frame, Efault);
- user_access_end();
-
- if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
- if (x32_copy_siginfo_to_user(&frame->info, &ksig->info))
- return -EFAULT;
- }
-
- /* Set up registers for signal handler */
- regs->sp = (unsigned long) frame;
- regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
-
- /* We use the x32 calling convention here... */
- regs->di = ksig->sig;
- regs->si = (unsigned long) &frame->info;
- regs->dx = (unsigned long) &frame->uc;
-
- loadsegment(ds, __USER_DS);
- loadsegment(es, __USER_DS);
-
- regs->cs = __USER_CS;
- regs->ss = __USER_DS;
-#endif /* CONFIG_X86_X32_ABI */
-
- return 0;
-#ifdef CONFIG_X86_X32_ABI
-Efault:
- user_access_end();
- return -EFAULT;
-#endif
-}
-
-/*
- * Do a signal return; undo the signal stack.
- */
-#ifdef CONFIG_X86_32
-SYSCALL_DEFINE0(sigreturn)
-{
- struct pt_regs *regs = current_pt_regs();
- struct sigframe __user *frame;
- sigset_t set;
-
- frame = (struct sigframe __user *)(regs->sp - 8);
-
- if (!access_ok(frame, sizeof(*frame)))
- goto badframe;
- if (__get_user(set.sig[0], &frame->sc.oldmask) ||
- __get_user(set.sig[1], &frame->extramask[0]))
- goto badframe;
-
- set_current_blocked(&set);
-
- /*
- * x86_32 has no uc_flags bits relevant to restore_sigcontext.
- * Save a few cycles by skipping the __get_user.
- */
- if (!restore_sigcontext(regs, &frame->sc, 0))
- goto badframe;
- return regs->ax;
-
-badframe:
- signal_fault(regs, frame, "sigreturn");
-
- return 0;
-}
-#endif /* CONFIG_X86_32 */
-
-SYSCALL_DEFINE0(rt_sigreturn)
-{
- struct pt_regs *regs = current_pt_regs();
- struct rt_sigframe __user *frame;
- sigset_t set;
- unsigned long uc_flags;
-
- frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
- if (!access_ok(frame, sizeof(*frame)))
- goto badframe;
- if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask))
- goto badframe;
- if (__get_user(uc_flags, &frame->uc.uc_flags))
- goto badframe;
-
- set_current_blocked(&set);
-
- if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
- goto badframe;
-
- if (restore_altstack(&frame->uc.uc_stack))
- goto badframe;
-
- return regs->ax;
-
-badframe:
- signal_fault(regs, frame, "rt_sigreturn");
- return 0;
-}
-
/*
* There are four different struct types for signal frame: sigframe_ia32,
* rt_sigframe_ia32, rt_sigframe_x32, and rt_sigframe. Use the worst case
@@ -743,43 +201,22 @@ unsigned long get_sigframe_size(void)
return max_frame_size;
}
-static inline int is_ia32_compat_frame(struct ksignal *ksig)
-{
- return IS_ENABLED(CONFIG_IA32_EMULATION) &&
- ksig->ka.sa.sa_flags & SA_IA32_ABI;
-}
-
-static inline int is_ia32_frame(struct ksignal *ksig)
-{
- return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig);
-}
-
-static inline int is_x32_frame(struct ksignal *ksig)
-{
- return IS_ENABLED(CONFIG_X86_X32_ABI) &&
- ksig->ka.sa.sa_flags & SA_X32_ABI;
-}
-
static int
setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
- int usig = ksig->sig;
- sigset_t *set = sigmask_to_save();
- compat_sigset_t *cset = (compat_sigset_t *) set;
-
/* Perform fixup for the pre-signal frame. */
rseq_signal_deliver(ksig, regs);
/* Set up the stack frame */
if (is_ia32_frame(ksig)) {
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
- return ia32_setup_rt_frame(usig, ksig, cset, regs);
+ return ia32_setup_rt_frame(ksig, regs);
else
- return ia32_setup_frame(usig, ksig, cset, regs);
+ return ia32_setup_frame(ksig, regs);
} else if (is_x32_frame(ksig)) {
- return x32_setup_rt_frame(ksig, cset, regs);
+ return x32_setup_rt_frame(ksig, regs);
} else {
- return __setup_rt_frame(ksig->sig, ksig, set, regs);
+ return x64_setup_rt_frame(ksig, regs);
}
}
@@ -969,36 +406,3 @@ bool sigaltstack_size_valid(size_t ss_size)
return true;
}
#endif /* CONFIG_DYNAMIC_SIGFRAME */
-
-#ifdef CONFIG_X86_X32_ABI
-COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
-{
- struct pt_regs *regs = current_pt_regs();
- struct rt_sigframe_x32 __user *frame;
- sigset_t set;
- unsigned long uc_flags;
-
- frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
-
- if (!access_ok(frame, sizeof(*frame)))
- goto badframe;
- if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask))
- goto badframe;
- if (__get_user(uc_flags, &frame->uc.uc_flags))
- goto badframe;
-
- set_current_blocked(&set);
-
- if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
- goto badframe;
-
- if (compat_restore_altstack(&frame->uc.uc_stack))
- goto badframe;
-
- return regs->ax;
-
-badframe:
- signal_fault(regs, frame, "x32 rt_sigreturn");
- return 0;
-}
-#endif
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/kernel/signal_32.c
index c9c3859322fa..2553136cf39b 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/kernel/signal_32.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * linux/arch/x86_64/ia32/ia32_signal.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
@@ -26,7 +24,6 @@
#include <linux/uaccess.h>
#include <asm/fpu/signal.h>
#include <asm/ptrace.h>
-#include <asm/ia32_unistd.h>
#include <asm/user32.h>
#include <uapi/asm/sigcontext.h>
#include <asm/proto.h>
@@ -35,6 +32,9 @@
#include <asm/sighandling.h>
#include <asm/smap.h>
+#ifdef CONFIG_IA32_EMULATION
+#include <asm/ia32_unistd.h>
+
static inline void reload_segments(struct sigcontext_32 *sc)
{
unsigned int cur;
@@ -53,6 +53,21 @@ static inline void reload_segments(struct sigcontext_32 *sc)
loadsegment(es, sc->es | 0x03);
}
+#define sigset32_t compat_sigset_t
+#define restore_altstack32 compat_restore_altstack
+#define unsafe_save_altstack32 unsafe_compat_save_altstack
+
+#else
+
+#define sigset32_t sigset_t
+#define __NR_ia32_sigreturn __NR_sigreturn
+#define __NR_ia32_rt_sigreturn __NR_rt_sigreturn
+#define restore_altstack32 restore_altstack
+#define unsafe_save_altstack32 unsafe_save_altstack
+#define __copy_siginfo_to_user32 copy_siginfo_to_user
+
+#endif
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -86,6 +101,7 @@ static bool ia32_restore_sigcontext(struct pt_regs *regs,
/* disable syscall checks */
regs->orig_ax = -1;
+#ifdef CONFIG_IA32_EMULATION
/*
* Reload fs and gs if they have changed in the signal
* handler. This does not handle long fs/gs base changes in
@@ -93,10 +109,17 @@ static bool ia32_restore_sigcontext(struct pt_regs *regs,
* normal case.
*/
reload_segments(&sc);
+#else
+ loadsegment(gs, sc.gs);
+ regs->fs = sc.fs;
+ regs->es = sc.es;
+ regs->ds = sc.ds;
+#endif
+
return fpu__restore_sig(compat_ptr(sc.fpstate), 1);
}
-COMPAT_SYSCALL_DEFINE0(sigreturn)
+SYSCALL32_DEFINE0(sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
@@ -119,7 +142,7 @@ badframe:
return 0;
}
-COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
+SYSCALL32_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct rt_sigframe_ia32 __user *frame;
@@ -129,7 +152,7 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
if (!access_ok(frame, sizeof(*frame)))
goto badframe;
- if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask))
+ if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask))
goto badframe;
set_current_blocked(&set);
@@ -137,7 +160,7 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
if (!ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (compat_restore_altstack(&frame->uc.uc_stack))
+ if (restore_altstack32(&frame->uc.uc_stack))
goto badframe;
return regs->ax;
@@ -159,9 +182,15 @@ __unsafe_setup_sigcontext32(struct sigcontext_32 __user *sc,
struct pt_regs *regs, unsigned int mask)
{
unsafe_put_user(get_user_seg(gs), (unsigned int __user *)&sc->gs, Efault);
+#ifdef CONFIG_IA32_EMULATION
unsafe_put_user(get_user_seg(fs), (unsigned int __user *)&sc->fs, Efault);
unsafe_put_user(get_user_seg(ds), (unsigned int __user *)&sc->ds, Efault);
unsafe_put_user(get_user_seg(es), (unsigned int __user *)&sc->es, Efault);
+#else
+ unsafe_put_user(regs->fs, (unsigned int __user *)&sc->fs, Efault);
+ unsafe_put_user(regs->es, (unsigned int __user *)&sc->es, Efault);
+ unsafe_put_user(regs->ds, (unsigned int __user *)&sc->ds, Efault);
+#endif
unsafe_put_user(regs->di, &sc->di, Efault);
unsafe_put_user(regs->si, &sc->si, Efault);
@@ -196,43 +225,9 @@ do { \
goto label; \
} while(0)
-/*
- * Determine which stack to use..
- */
-static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
- size_t frame_size,
- void __user **fpstate)
-{
- unsigned long sp, fx_aligned, math_size;
-
- /* Default to using normal stack */
- sp = regs->sp;
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (ksig->ka.sa.sa_flags & SA_ONSTACK)
- sp = sigsp(sp, ksig);
- /* This is the legacy signal stack switching. */
- else if (regs->ss != __USER32_DS &&
- !(ksig->ka.sa.sa_flags & SA_RESTORER) &&
- ksig->ka.sa.sa_restorer)
- sp = (unsigned long) ksig->ka.sa.sa_restorer;
-
- sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size);
- *fpstate = (struct _fpstate_32 __user *) sp;
- if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)fx_aligned,
- math_size))
- return (void __user *) -1L;
-
- sp -= frame_size;
- /* Align the stack pointer according to the i386 ABI,
- * i.e. so that on function entry ((sp + 4) & 15) == 0. */
- sp = ((sp + 4) & -16ul) - 4;
- return (void __user *) sp;
-}
-
-int ia32_setup_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs)
+int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs)
{
+ sigset32_t *set = (sigset32_t *) sigmask_to_save();
struct sigframe_ia32 __user *frame;
void __user *restorer;
void __user *fp = NULL;
@@ -264,7 +259,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
- unsafe_put_user(sig, &frame->sig, Efault);
+ unsafe_put_user(ksig->sig, &frame->sig, Efault);
unsafe_put_sigcontext32(&frame->sc, fp, regs, set, Efault);
unsafe_put_user(set->sig[1], &frame->extramask[0], Efault);
unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault);
@@ -280,15 +275,20 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
/* Make -mregparm=3 work */
- regs->ax = sig;
+ regs->ax = ksig->sig;
regs->dx = 0;
regs->cx = 0;
- loadsegment(ds, __USER32_DS);
- loadsegment(es, __USER32_DS);
+#ifdef CONFIG_IA32_EMULATION
+ loadsegment(ds, __USER_DS);
+ loadsegment(es, __USER_DS);
+#else
+ regs->ds = __USER_DS;
+ regs->es = __USER_DS;
+#endif
regs->cs = __USER32_CS;
- regs->ss = __USER32_DS;
+ regs->ss = __USER_DS;
return 0;
Efault:
@@ -296,9 +296,9 @@ Efault:
return -EFAULT;
}
-int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs)
+int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
+ sigset32_t *set = (sigset32_t *) sigmask_to_save();
struct rt_sigframe_ia32 __user *frame;
void __user *restorer;
void __user *fp = NULL;
@@ -321,7 +321,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
- unsafe_put_user(sig, &frame->sig, Efault);
+ unsafe_put_user(ksig->sig, &frame->sig, Efault);
unsafe_put_user(ptr_to_compat(&frame->info), &frame->pinfo, Efault);
unsafe_put_user(ptr_to_compat(&frame->uc), &frame->puc, Efault);
@@ -331,7 +331,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
else
unsafe_put_user(0, &frame->uc.uc_flags, Efault);
unsafe_put_user(0, &frame->uc.uc_link, Efault);
- unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
+ unsafe_save_altstack32(&frame->uc.uc_stack, regs->sp, Efault);
if (ksig->ka.sa.sa_flags & SA_RESTORER)
restorer = ksig->ka.sa.sa_restorer;
@@ -357,15 +357,20 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
/* Make -mregparm=3 work */
- regs->ax = sig;
+ regs->ax = ksig->sig;
regs->dx = (unsigned long) &frame->info;
regs->cx = (unsigned long) &frame->uc;
- loadsegment(ds, __USER32_DS);
- loadsegment(es, __USER32_DS);
+#ifdef CONFIG_IA32_EMULATION
+ loadsegment(ds, __USER_DS);
+ loadsegment(es, __USER_DS);
+#else
+ regs->ds = __USER_DS;
+ regs->es = __USER_DS;
+#endif
regs->cs = __USER32_CS;
- regs->ss = __USER32_DS;
+ regs->ss = __USER_DS;
return 0;
Efault:
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
new file mode 100644
index 000000000000..ff9c55064223
--- /dev/null
+++ b/arch/x86/kernel/signal_64.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+
+#include <asm/ucontext.h>
+#include <asm/fpu/signal.h>
+#include <asm/sighandling.h>
+
+#include <asm/syscall.h>
+#include <asm/sigframe.h>
+#include <asm/signal.h>
+
+/*
+ * If regs->ss will cause an IRET fault, change it. Otherwise leave it
+ * alone. Using this generally makes no sense unless
+ * user_64bit_mode(regs) would return true.
+ */
+static void force_valid_ss(struct pt_regs *regs)
+{
+ u32 ar;
+ asm volatile ("lar %[old_ss], %[ar]\n\t"
+ "jz 1f\n\t" /* If invalid: */
+ "xorl %[ar], %[ar]\n\t" /* set ar = 0 */
+ "1:"
+ : [ar] "=r" (ar)
+ : [old_ss] "rm" ((u16)regs->ss));
+
+ /*
+ * For a valid 64-bit user context, we need DPL 3, type
+ * read-write data or read-write exp-down data, and S and P
+ * set. We can't use VERW because VERW doesn't check the
+ * P bit.
+ */
+ ar &= AR_DPL_MASK | AR_S | AR_P | AR_TYPE_MASK;
+ if (ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA) &&
+ ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN))
+ regs->ss = __USER_DS;
+}
+
+static bool restore_sigcontext(struct pt_regs *regs,
+ struct sigcontext __user *usc,
+ unsigned long uc_flags)
+{
+ struct sigcontext sc;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current->restart_block.fn = do_no_restart_syscall;
+
+ if (copy_from_user(&sc, usc, offsetof(struct sigcontext, reserved1)))
+ return false;
+
+ regs->bx = sc.bx;
+ regs->cx = sc.cx;
+ regs->dx = sc.dx;
+ regs->si = sc.si;
+ regs->di = sc.di;
+ regs->bp = sc.bp;
+ regs->ax = sc.ax;
+ regs->sp = sc.sp;
+ regs->ip = sc.ip;
+ regs->r8 = sc.r8;
+ regs->r9 = sc.r9;
+ regs->r10 = sc.r10;
+ regs->r11 = sc.r11;
+ regs->r12 = sc.r12;
+ regs->r13 = sc.r13;
+ regs->r14 = sc.r14;
+ regs->r15 = sc.r15;
+
+ /* Get CS/SS and force CPL3 */
+ regs->cs = sc.cs | 0x03;
+ regs->ss = sc.ss | 0x03;
+
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
+ /* disable syscall checks */
+ regs->orig_ax = -1;
+
+ /*
+ * Fix up SS if needed for the benefit of old DOSEMU and
+ * CRIU.
+ */
+ if (unlikely(!(uc_flags & UC_STRICT_RESTORE_SS) && user_64bit_mode(regs)))
+ force_valid_ss(regs);
+
+ return fpu__restore_sig((void __user *)sc.fpstate, 0);
+}
+
+static __always_inline int
+__unsafe_setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
+ struct pt_regs *regs, unsigned long mask)
+{
+ unsafe_put_user(regs->di, &sc->di, Efault);
+ unsafe_put_user(regs->si, &sc->si, Efault);
+ unsafe_put_user(regs->bp, &sc->bp, Efault);
+ unsafe_put_user(regs->sp, &sc->sp, Efault);
+ unsafe_put_user(regs->bx, &sc->bx, Efault);
+ unsafe_put_user(regs->dx, &sc->dx, Efault);
+ unsafe_put_user(regs->cx, &sc->cx, Efault);
+ unsafe_put_user(regs->ax, &sc->ax, Efault);
+ unsafe_put_user(regs->r8, &sc->r8, Efault);
+ unsafe_put_user(regs->r9, &sc->r9, Efault);
+ unsafe_put_user(regs->r10, &sc->r10, Efault);
+ unsafe_put_user(regs->r11, &sc->r11, Efault);
+ unsafe_put_user(regs->r12, &sc->r12, Efault);
+ unsafe_put_user(regs->r13, &sc->r13, Efault);
+ unsafe_put_user(regs->r14, &sc->r14, Efault);
+ unsafe_put_user(regs->r15, &sc->r15, Efault);
+
+ unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault);
+ unsafe_put_user(current->thread.error_code, &sc->err, Efault);
+ unsafe_put_user(regs->ip, &sc->ip, Efault);
+ unsafe_put_user(regs->flags, &sc->flags, Efault);
+ unsafe_put_user(regs->cs, &sc->cs, Efault);
+ unsafe_put_user(0, &sc->gs, Efault);
+ unsafe_put_user(0, &sc->fs, Efault);
+ unsafe_put_user(regs->ss, &sc->ss, Efault);
+
+ unsafe_put_user(fpstate, (unsigned long __user *)&sc->fpstate, Efault);
+
+ /* non-iBCS2 extensions.. */
+ unsafe_put_user(mask, &sc->oldmask, Efault);
+ unsafe_put_user(current->thread.cr2, &sc->cr2, Efault);
+ return 0;
+Efault:
+ return -EFAULT;
+}
+
+#define unsafe_put_sigcontext(sc, fp, regs, set, label) \
+do { \
+ if (__unsafe_setup_sigcontext(sc, fp, regs, set->sig[0])) \
+ goto label; \
+} while(0);
+
+#define unsafe_put_sigmask(set, frame, label) \
+ unsafe_put_user(*(__u64 *)(set), \
+ (__u64 __user *)&(frame)->uc.uc_sigmask, \
+ label)
+
+static unsigned long frame_uc_flags(struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ if (boot_cpu_has(X86_FEATURE_XSAVE))
+ flags = UC_FP_XSTATE | UC_SIGCONTEXT_SS;
+ else
+ flags = UC_SIGCONTEXT_SS;
+
+ if (likely(user_64bit_mode(regs)))
+ flags |= UC_STRICT_RESTORE_SS;
+
+ return flags;
+}
+
+int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
+{
+ sigset_t *set = sigmask_to_save();
+ struct rt_sigframe __user *frame;
+ void __user *fp = NULL;
+ unsigned long uc_flags;
+
+ /* x86-64 should always use SA_RESTORER. */
+ if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
+ return -EFAULT;
+
+ frame = get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp);
+ uc_flags = frame_uc_flags(regs);
+
+ if (!user_access_begin(frame, sizeof(*frame)))
+ return -EFAULT;
+
+ /* Create the ucontext. */
+ unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
+ unsafe_put_user(0, &frame->uc.uc_link, Efault);
+ unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
+ unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
+ unsafe_put_sigmask(set, frame, Efault);
+ user_access_end();
+
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ if (copy_siginfo_to_user(&frame->info, &ksig->info))
+ return -EFAULT;
+ }
+
+ /* Set up registers for signal handler */
+ regs->di = ksig->sig;
+ /* In case the signal handler was declared without prototypes */
+ regs->ax = 0;
+
+ /* This also works for non SA_SIGINFO handlers because they expect the
+ next argument after the signal number on the stack. */
+ regs->si = (unsigned long)&frame->info;
+ regs->dx = (unsigned long)&frame->uc;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
+
+ regs->sp = (unsigned long)frame;
+
+ /*
+ * Set up the CS and SS registers to run signal handlers in
+ * 64-bit mode, even if the handler happens to be interrupting
+ * 32-bit or 16-bit code.
+ *
+ * SS is subtle. In 64-bit mode, we don't need any particular
+ * SS descriptor, but we do need SS to be valid. It's possible
+ * that the old SS is entirely bogus -- this can happen if the
+ * signal we're trying to deliver is #GP or #SS caused by a bad
+ * SS value. We also have a compatibility issue here: DOSEMU
+ * relies on the contents of the SS register indicating the
+ * SS value at the time of the signal, even though that code in
+ * DOSEMU predates sigreturn's ability to restore SS. (DOSEMU
+ * avoids relying on sigreturn to restore SS; instead it uses
+ * a trampoline.) So we do our best: if the old SS was valid,
+ * we keep it. Otherwise we replace it.
+ */
+ regs->cs = __USER_CS;
+
+ if (unlikely(regs->ss != __USER_DS))
+ force_valid_ss(regs);
+
+ return 0;
+
+Efault:
+ user_access_end();
+ return -EFAULT;
+}
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+SYSCALL_DEFINE0(rt_sigreturn)
+{
+ struct pt_regs *regs = current_pt_regs();
+ struct rt_sigframe __user *frame;
+ sigset_t set;
+ unsigned long uc_flags;
+
+ frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
+ if (!access_ok(frame, sizeof(*frame)))
+ goto badframe;
+ if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask))
+ goto badframe;
+ if (__get_user(uc_flags, &frame->uc.uc_flags))
+ goto badframe;
+
+ set_current_blocked(&set);
+
+ if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
+ goto badframe;
+
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+ return regs->ax;
+
+badframe:
+ signal_fault(regs, frame, "rt_sigreturn");
+ return 0;
+}
+
+#ifdef CONFIG_X86_X32_ABI
+static int x32_copy_siginfo_to_user(struct compat_siginfo __user *to,
+ const struct kernel_siginfo *from)
+{
+ struct compat_siginfo new;
+
+ copy_siginfo_to_external32(&new, from);
+ if (from->si_signo == SIGCHLD) {
+ new._sifields._sigchld_x32._utime = from->si_utime;
+ new._sifields._sigchld_x32._stime = from->si_stime;
+ }
+ if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+ return 0;
+}
+
+int copy_siginfo_to_user32(struct compat_siginfo __user *to,
+ const struct kernel_siginfo *from)
+{
+ if (in_x32_syscall())
+ return x32_copy_siginfo_to_user(to, from);
+ return __copy_siginfo_to_user32(to, from);
+}
+
+int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
+{
+ compat_sigset_t *set = (compat_sigset_t *) sigmask_to_save();
+ struct rt_sigframe_x32 __user *frame;
+ unsigned long uc_flags;
+ void __user *restorer;
+ void __user *fp = NULL;
+
+ if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
+ return -EFAULT;
+
+ frame = get_sigframe(ksig, regs, sizeof(*frame), &fp);
+
+ uc_flags = frame_uc_flags(regs);
+
+ if (!user_access_begin(frame, sizeof(*frame)))
+ return -EFAULT;
+
+ /* Create the ucontext. */
+ unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
+ unsafe_put_user(0, &frame->uc.uc_link, Efault);
+ unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
+ unsafe_put_user(0, &frame->uc.uc__pad0, Efault);
+ restorer = ksig->ka.sa.sa_restorer;
+ unsafe_put_user(restorer, (unsigned long __user *)&frame->pretcode, Efault);
+ unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
+ unsafe_put_sigmask(set, frame, Efault);
+ user_access_end();
+
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ if (x32_copy_siginfo_to_user(&frame->info, &ksig->info))
+ return -EFAULT;
+ }
+
+ /* Set up registers for signal handler */
+ regs->sp = (unsigned long) frame;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
+
+ /* We use the x32 calling convention here... */
+ regs->di = ksig->sig;
+ regs->si = (unsigned long) &frame->info;
+ regs->dx = (unsigned long) &frame->uc;
+
+ loadsegment(ds, __USER_DS);
+ loadsegment(es, __USER_DS);
+
+ regs->cs = __USER_CS;
+ regs->ss = __USER_DS;
+
+ return 0;
+
+Efault:
+ user_access_end();
+ return -EFAULT;
+}
+
+COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
+{
+ struct pt_regs *regs = current_pt_regs();
+ struct rt_sigframe_x32 __user *frame;
+ sigset_t set;
+ unsigned long uc_flags;
+
+ frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
+
+ if (!access_ok(frame, sizeof(*frame)))
+ goto badframe;
+ if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask))
+ goto badframe;
+ if (__get_user(uc_flags, &frame->uc.uc_flags))
+ goto badframe;
+
+ set_current_blocked(&set);
+
+ if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
+ goto badframe;
+
+ if (compat_restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+ return regs->ax;
+
+badframe:
+ signal_fault(regs, frame, "x32 rt_sigreturn");
+ return 0;
+}
+#endif /* CONFIG_X86_X32_ABI */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 3f3ea0287f69..5a742b6ec46d 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -56,6 +56,7 @@
#include <linux/numa.h>
#include <linux/pgtable.h>
#include <linux/overflow.h>
+#include <linux/stackprotector.h>
#include <asm/acpi.h>
#include <asm/desc.h>
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 178015a820f0..d1e1679f32cf 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -15,6 +15,7 @@
#include <linux/context_tracking.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
+#include <linux/kmsan.h>
#include <linux/spinlock.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
@@ -67,13 +68,13 @@
#ifdef CONFIG_X86_64
#include <asm/x86_init.h>
-#include <asm/proto.h>
#else
#include <asm/processor-flags.h>
#include <asm/setup.h>
-#include <asm/proto.h>
#endif
+#include <asm/proto.h>
+
DECLARE_BITMAP(system_vectors, NR_VECTORS);
static inline void cond_local_irq_enable(struct pt_regs *regs)
@@ -301,6 +302,12 @@ static noinstr bool handle_bug(struct pt_regs *regs)
{
bool handled = false;
+ /*
+ * Normally @regs are unpoisoned by irqentry_enter(), but handle_bug()
+ * is a rare case that uses @regs without passing them to
+ * irqentry_enter().
+ */
+ kmsan_unpoison_entry_regs(regs);
if (!is_valid_bugaddr(regs->ip))
return handled;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index cafacb2e58cc..a78e73da4a74 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -51,7 +51,7 @@ int tsc_clocksource_reliable;
static u32 art_to_tsc_numerator;
static u32 art_to_tsc_denominator;
static u64 art_to_tsc_offset;
-struct clocksource *art_related_clocksource;
+static struct clocksource *art_related_clocksource;
struct cyc2ns {
struct cyc2ns_data data[2]; /* 0 + 2*16 = 32 */
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index b63cf8f7745e..6c07f6daaa22 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -722,8 +722,9 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
switch (opc1) {
case 0xeb: /* jmp 8 */
case 0xe9: /* jmp 32 */
- case 0x90: /* prefix* + nop; same as jmp with .offs = 0 */
break;
+ case 0x90: /* prefix* + nop; same as jmp with .offs = 0 */
+ goto setup;
case 0xe8: /* call relative */
branch_clear_offset(auprobe, insn);
@@ -753,6 +754,7 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
return -ENOTSUPP;
}
+setup:
auprobe->branch.opc1 = opc1;
auprobe->branch.ilen = insn->length;
auprobe->branch.offs = insn->immediate.value;
diff --git a/arch/x86/kvm/.gitignore b/arch/x86/kvm/.gitignore
new file mode 100644
index 000000000000..615d6ff35c00
--- /dev/null
+++ b/arch/x86/kvm/.gitignore
@@ -0,0 +1,2 @@
+/kvm-asm-offsets.s
+/kvm-asm-offsets.h
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 30f244b64523..f453a0f96e24 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -34,3 +34,15 @@ endif
obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
obj-$(CONFIG_KVM_AMD) += kvm-amd.o
+
+AFLAGS_svm/vmenter.o := -iquote $(obj)
+$(obj)/svm/vmenter.o: $(obj)/kvm-asm-offsets.h
+
+AFLAGS_vmx/vmenter.o := -iquote $(obj)
+$(obj)/vmx/vmenter.o: $(obj)/kvm-asm-offsets.h
+
+$(obj)/kvm-asm-offsets.h: $(obj)/kvm-asm-offsets.s FORCE
+ $(call filechk,offsets,__KVM_ASM_OFFSETS_H__)
+
+targets += kvm-asm-offsets.s
+clean-files += kvm-asm-offsets.h
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 62bc7a01cecc..c92c49a0b35b 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -665,7 +665,7 @@ void kvm_set_cpu_caps(void)
);
kvm_cpu_cap_init_scattered(CPUID_12_EAX,
- SF(SGX1) | SF(SGX2)
+ SF(SGX1) | SF(SGX2) | SF(SGX_EDECCSSA)
);
kvm_cpu_cap_mask(CPUID_8000_0001_ECX,
@@ -1047,9 +1047,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
* userspace. ATTRIBUTES.XFRM is not adjusted as userspace is
* expected to derive it from supported XCR0.
*/
- entry->eax &= SGX_ATTR_DEBUG | SGX_ATTR_MODE64BIT |
- SGX_ATTR_PROVISIONKEY | SGX_ATTR_EINITTOKENKEY |
- SGX_ATTR_KSS;
+ entry->eax &= SGX_ATTR_PRIV_MASK | SGX_ATTR_UNPRIV_MASK;
entry->ebx &= 0;
break;
/* Intel PT */
diff --git a/arch/x86/kvm/kvm-asm-offsets.c b/arch/x86/kvm/kvm-asm-offsets.c
new file mode 100644
index 000000000000..24a710d37323
--- /dev/null
+++ b/arch/x86/kvm/kvm-asm-offsets.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+#define COMPILE_OFFSETS
+
+#include <linux/kbuild.h>
+#include "vmx/vmx.h"
+#include "svm/svm.h"
+
+static void __used common(void)
+{
+ if (IS_ENABLED(CONFIG_KVM_AMD)) {
+ BLANK();
+ OFFSET(SVM_vcpu_arch_regs, vcpu_svm, vcpu.arch.regs);
+ OFFSET(SVM_current_vmcb, vcpu_svm, current_vmcb);
+ OFFSET(SVM_spec_ctrl, vcpu_svm, spec_ctrl);
+ OFFSET(SVM_vmcb01, vcpu_svm, vmcb01);
+ OFFSET(KVM_VMCB_pa, kvm_vmcb_info, pa);
+ OFFSET(SD_save_area_pa, svm_cpu_data, save_area_pa);
+ }
+
+ if (IS_ENABLED(CONFIG_KVM_INTEL)) {
+ BLANK();
+ OFFSET(VMX_spec_ctrl, vcpu_vmx, spec_ctrl);
+ }
+}
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 6f81539061d6..b6f96d47e596 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -2443,6 +2443,7 @@ static bool __kvm_mmu_prepare_zap_page(struct kvm *kvm,
{
bool list_unstable, zapped_root = false;
+ lockdep_assert_held_write(&kvm->mmu_lock);
trace_kvm_mmu_prepare_zap_page(sp);
++kvm->stat.mmu_shadow_zapped;
*nr_zapped = mmu_zap_unsync_children(kvm, sp, invalid_list);
@@ -4262,14 +4263,14 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
if (is_page_fault_stale(vcpu, fault, mmu_seq))
goto out_unlock;
- r = make_mmu_pages_available(vcpu);
- if (r)
- goto out_unlock;
-
- if (is_tdp_mmu_fault)
+ if (is_tdp_mmu_fault) {
r = kvm_tdp_mmu_map(vcpu, fault);
- else
+ } else {
+ r = make_mmu_pages_available(vcpu);
+ if (r)
+ goto out_unlock;
r = __direct_map(vcpu, fault);
+ }
out_unlock:
if (is_tdp_mmu_fault)
@@ -6056,7 +6057,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
write_lock(&kvm->mmu_lock);
- kvm_mmu_invalidate_begin(kvm, gfn_start, gfn_end);
+ kvm_mmu_invalidate_begin(kvm, 0, -1ul);
flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end);
@@ -6070,7 +6071,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
kvm_flush_remote_tlbs_with_address(kvm, gfn_start,
gfn_end - gfn_start);
- kvm_mmu_invalidate_end(kvm, gfn_start, gfn_end);
+ kvm_mmu_invalidate_end(kvm, 0, -1ul);
write_unlock(&kvm->mmu_lock);
}
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index d9b9a0f0db17..de1fd7369736 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -56,7 +56,7 @@ static const struct x86_cpu_id vmx_icl_pebs_cpu[] = {
* code. Each pmc, stored in kvm_pmc.idx field, is unique across
* all perf counters (both gp and fixed). The mapping relationship
* between pmc and perf counters is as the following:
- * * Intel: [0 .. INTEL_PMC_MAX_GENERIC-1] <=> gp counters
+ * * Intel: [0 .. KVM_INTEL_PMC_MAX_GENERIC-1] <=> gp counters
* [INTEL_PMC_IDX_FIXED .. INTEL_PMC_IDX_FIXED + 2] <=> fixed
* * AMD: [0 .. AMD64_NUM_COUNTERS-1] and, for families 15H
* and later, [0 .. AMD64_NUM_COUNTERS_CORE-1] <=> gp counters
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index a19d473d0184..4e5b8444f161 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -23,6 +23,7 @@ enum kvm_only_cpuid_leafs {
/* Intel-defined SGX sub-features, CPUID level 0x12 (EAX). */
#define KVM_X86_FEATURE_SGX1 KVM_X86_FEATURE(CPUID_12_EAX, 0)
#define KVM_X86_FEATURE_SGX2 KVM_X86_FEATURE(CPUID_12_EAX, 1)
+#define KVM_X86_FEATURE_SGX_EDECCSSA KVM_X86_FEATURE(CPUID_12_EAX, 11)
struct cpuid_reg {
u32 function;
@@ -78,6 +79,8 @@ static __always_inline u32 __feature_translate(int x86_feature)
return KVM_X86_FEATURE_SGX1;
else if (x86_feature == X86_FEATURE_SGX2)
return KVM_X86_FEATURE_SGX2;
+ else if (x86_feature == X86_FEATURE_SGX_EDECCSSA)
+ return KVM_X86_FEATURE_SGX_EDECCSSA;
return x86_feature;
}
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 4c620999d230..995bc0f90759 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1091,6 +1091,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
static void nested_svm_triple_fault(struct kvm_vcpu *vcpu)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_SHUTDOWN))
+ return;
+
+ kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
nested_svm_simple_vmexit(to_svm(vcpu), SVM_EXIT_SHUTDOWN);
}
@@ -1125,6 +1131,9 @@ void svm_free_nested(struct vcpu_svm *svm)
if (!svm->nested.initialized)
return;
+ if (WARN_ON_ONCE(svm->vmcb != svm->vmcb01.ptr))
+ svm_switch_vmcb(svm, &svm->vmcb01);
+
svm_vcpu_free_msrpm(svm->nested.msrpm);
svm->nested.msrpm = NULL;
@@ -1143,9 +1152,6 @@ void svm_free_nested(struct vcpu_svm *svm)
svm->nested.initialized = false;
}
-/*
- * Forcibly leave nested mode in order to be able to reset the VCPU later on.
- */
void svm_leave_nested(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index b68956299fa8..9d65cd095691 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -192,9 +192,10 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu)
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
int i;
- BUILD_BUG_ON(AMD64_NUM_COUNTERS_CORE > INTEL_PMC_MAX_GENERIC);
+ BUILD_BUG_ON(KVM_AMD_PMC_MAX_GENERIC > AMD64_NUM_COUNTERS_CORE);
+ BUILD_BUG_ON(KVM_AMD_PMC_MAX_GENERIC > INTEL_PMC_MAX_GENERIC);
- for (i = 0; i < AMD64_NUM_COUNTERS_CORE ; i++) {
+ for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC ; i++) {
pmu->gp_counters[i].type = KVM_PMC_GP;
pmu->gp_counters[i].vcpu = vcpu;
pmu->gp_counters[i].idx = i;
@@ -207,7 +208,7 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
int i;
- for (i = 0; i < AMD64_NUM_COUNTERS_CORE; i++) {
+ for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC; i++) {
struct kvm_pmc *pmc = &pmu->gp_counters[i];
pmc_stop_counter(pmc);
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 28064060413a..efaaef2b7ae1 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -196,7 +196,7 @@ static void sev_asid_free(struct kvm_sev_info *sev)
__set_bit(sev->asid, sev_reclaim_asid_bitmap);
for_each_possible_cpu(cpu) {
- sd = per_cpu(svm_data, cpu);
+ sd = per_cpu_ptr(&svm_data, cpu);
sd->sev_vmcbs[sev->asid] = NULL;
}
@@ -605,7 +605,7 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm)
save->dr6 = svm->vcpu.arch.dr6;
pr_debug("Virtual Machine Save Area (VMSA):\n");
- print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false);
+ print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false);
return 0;
}
@@ -2600,7 +2600,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
void pre_sev_run(struct vcpu_svm *svm, int cpu)
{
- struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
int asid = sev_get_asid(svm->vcpu.kvm);
/* Assign the asid allocated with this SEV guest */
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 58f0077d9357..ce362e88a567 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -245,7 +245,7 @@ struct kvm_ldttss_desc {
u32 zero1;
} __attribute__((packed));
-DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+DEFINE_PER_CPU(struct svm_cpu_data, svm_data);
/*
* Only MSR_TSC_AUX is switched via the user return hook. EFER is switched via
@@ -346,12 +346,6 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
return 0;
}
-static int is_external_interrupt(u32 info)
-{
- info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
- return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
-}
-
static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -581,12 +575,7 @@ static int svm_hardware_enable(void)
pr_err("%s: err EOPNOTSUPP on %d\n", __func__, me);
return -EINVAL;
}
- sd = per_cpu(svm_data, me);
- if (!sd) {
- pr_err("%s: svm_data is NULL on %d\n", __func__, me);
- return -EINVAL;
- }
-
+ sd = per_cpu_ptr(&svm_data, me);
sd->asid_generation = 1;
sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
sd->next_asid = sd->max_asid + 1;
@@ -597,7 +586,7 @@ static int svm_hardware_enable(void)
wrmsrl(MSR_EFER, efer | EFER_SVME);
- wrmsrl(MSR_VM_HSAVE_PA, __sme_page_pa(sd->save_area));
+ wrmsrl(MSR_VM_HSAVE_PA, sd->save_area_pa);
if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) {
/*
@@ -646,42 +635,37 @@ static int svm_hardware_enable(void)
static void svm_cpu_uninit(int cpu)
{
- struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
- if (!sd)
+ if (!sd->save_area)
return;
- per_cpu(svm_data, cpu) = NULL;
kfree(sd->sev_vmcbs);
__free_page(sd->save_area);
- kfree(sd);
+ sd->save_area_pa = 0;
+ sd->save_area = NULL;
}
static int svm_cpu_init(int cpu)
{
- struct svm_cpu_data *sd;
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
int ret = -ENOMEM;
- sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
- if (!sd)
- return ret;
- sd->cpu = cpu;
+ memset(sd, 0, sizeof(struct svm_cpu_data));
sd->save_area = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!sd->save_area)
- goto free_cpu_data;
+ return ret;
ret = sev_cpu_init(sd);
if (ret)
goto free_save_area;
- per_cpu(svm_data, cpu) = sd;
-
+ sd->save_area_pa = __sme_page_pa(sd->save_area);
return 0;
free_save_area:
__free_page(sd->save_area);
-free_cpu_data:
- kfree(sd);
+ sd->save_area = NULL;
return ret;
}
@@ -730,6 +714,15 @@ static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
u32 offset;
u32 *msrpm;
+ /*
+ * For non-nested case:
+ * If the L01 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ *
+ * For nested case:
+ * If the L02 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ */
msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
to_svm(vcpu)->msrpm;
@@ -1425,7 +1418,7 @@ static void svm_clear_current_vmcb(struct vmcb *vmcb)
int i;
for_each_online_cpu(i)
- cmpxchg(&per_cpu(svm_data, i)->current_vmcb, vmcb, NULL);
+ cmpxchg(per_cpu_ptr(&svm_data.current_vmcb, i), vmcb, NULL);
}
static void svm_vcpu_free(struct kvm_vcpu *vcpu)
@@ -1439,6 +1432,7 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
*/
svm_clear_current_vmcb(svm->vmcb);
+ svm_leave_nested(vcpu);
svm_free_nested(svm);
sev_free_vcpu(vcpu);
@@ -1450,7 +1444,7 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu);
if (sev_es_guest(vcpu->kvm))
sev_es_unmap_ghcb(svm);
@@ -1462,7 +1456,7 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
* Save additional host state that will be restored on VMEXIT (sev-es)
* or subsequent vmload of host save area.
*/
- vmsave(__sme_page_pa(sd->save_area));
+ vmsave(sd->save_area_pa);
if (sev_es_guest(vcpu->kvm)) {
struct sev_es_save_area *hostsa;
hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400);
@@ -1487,7 +1481,7 @@ static void svm_prepare_host_switch(struct kvm_vcpu *vcpu)
static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
if (sd->current_vmcb != svm->vmcb) {
sd->current_vmcb = svm->vmcb;
@@ -2710,9 +2704,9 @@ static int svm_get_msr_feature(struct kvm_msr_entry *msr)
msr->data = 0;
switch (msr->index) {
- case MSR_F10H_DECFG:
- if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
- msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE;
+ case MSR_AMD64_DE_CFG:
+ if (cpu_feature_enabled(X86_FEATURE_LFENCE_RDTSC))
+ msr->data |= MSR_AMD64_DE_CFG_LFENCE_SERIALIZE;
break;
case MSR_IA32_PERF_CAPABILITIES:
return 0;
@@ -2813,7 +2807,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
msr_info->data = 0x1E;
}
break;
- case MSR_F10H_DECFG:
+ case MSR_AMD64_DE_CFG:
msr_info->data = svm->msr_decfg;
break;
default:
@@ -3042,7 +3036,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
case MSR_VM_IGNNE:
vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
break;
- case MSR_F10H_DECFG: {
+ case MSR_AMD64_DE_CFG: {
struct kvm_msr_entry msr_entry;
msr_entry.index = msr->index;
@@ -3426,15 +3420,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
return 0;
}
- if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
- exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
- exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
- exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
- printk(KERN_ERR "%s: unexpected exit_int_info 0x%x "
- "exit_code 0x%x\n",
- __func__, svm->vmcb->control.exit_int_info,
- exit_code);
-
if (exit_fastpath != EXIT_FASTPATH_NONE)
return 1;
@@ -3443,7 +3428,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
static void reload_tss(struct kvm_vcpu *vcpu)
{
- struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu);
sd->tss_desc->type = 9; /* available 32/64-bit TSS */
load_TR_desc();
@@ -3451,7 +3436,7 @@ static void reload_tss(struct kvm_vcpu *vcpu)
static void pre_svm_run(struct kvm_vcpu *vcpu)
{
- struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);
+ struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu);
struct vcpu_svm *svm = to_svm(vcpu);
/*
@@ -3911,30 +3896,16 @@ static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
return EXIT_FASTPATH_NONE;
}
-static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_intercepted)
{
struct vcpu_svm *svm = to_svm(vcpu);
- unsigned long vmcb_pa = svm->current_vmcb->pa;
guest_state_enter_irqoff();
- if (sev_es_guest(vcpu->kvm)) {
- __svm_sev_es_vcpu_run(vmcb_pa);
- } else {
- struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);
-
- /*
- * Use a single vmcb (vmcb01 because it's always valid) for
- * context switching guest state via VMLOAD/VMSAVE, that way
- * the state doesn't need to be copied between vmcb01 and
- * vmcb02 when switching vmcbs for nested virtualization.
- */
- vmload(svm->vmcb01.pa);
- __svm_vcpu_run(vmcb_pa, (unsigned long *)&vcpu->arch.regs);
- vmsave(svm->vmcb01.pa);
-
- vmload(__sme_page_pa(sd->save_area));
- }
+ if (sev_es_guest(vcpu->kvm))
+ __svm_sev_es_vcpu_run(svm, spec_ctrl_intercepted);
+ else
+ __svm_vcpu_run(svm, spec_ctrl_intercepted);
guest_state_exit_irqoff();
}
@@ -3942,6 +3913,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ bool spec_ctrl_intercepted = msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL);
trace_kvm_entry(vcpu);
@@ -3998,34 +3970,15 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
* being speculatively taken.
*/
if (!static_cpu_has(X86_FEATURE_V_SPEC_CTRL))
- x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl);
-
- svm_vcpu_enter_exit(vcpu);
+ x86_spec_ctrl_set_guest(svm->virt_spec_ctrl);
- /*
- * We do not use IBRS in the kernel. If this vCPU has used the
- * SPEC_CTRL MSR it may have left it on; save the value and
- * turn it off. This is much more efficient than blindly adding
- * it to the atomic save/restore list. Especially as the former
- * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
- *
- * For non-nested case:
- * If the L01 MSR bitmap does not intercept the MSR, then we need to
- * save it.
- *
- * For nested case:
- * If the L02 MSR bitmap does not intercept the MSR, then we need to
- * save it.
- */
- if (!static_cpu_has(X86_FEATURE_V_SPEC_CTRL) &&
- unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)))
- svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
+ svm_vcpu_enter_exit(vcpu, spec_ctrl_intercepted);
if (!sev_es_guest(vcpu->kvm))
reload_tss(vcpu);
if (!static_cpu_has(X86_FEATURE_V_SPEC_CTRL))
- x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl);
+ x86_spec_ctrl_restore_host(svm->virt_spec_ctrl);
if (!sev_es_guest(vcpu->kvm)) {
vcpu->arch.cr2 = svm->vmcb->save.cr2;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 6a7686bf6900..199a2ecef1ce 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -209,7 +209,6 @@ struct vcpu_svm {
struct vmcb *vmcb;
struct kvm_vmcb_info vmcb01;
struct kvm_vmcb_info *current_vmcb;
- struct svm_cpu_data *svm_data;
u32 asid;
u32 sysenter_esp_hi;
u32 sysenter_eip_hi;
@@ -281,8 +280,6 @@ struct vcpu_svm {
};
struct svm_cpu_data {
- int cpu;
-
u64 asid_generation;
u32 max_asid;
u32 next_asid;
@@ -290,13 +287,15 @@ struct svm_cpu_data {
struct kvm_ldttss_desc *tss_desc;
struct page *save_area;
+ unsigned long save_area_pa;
+
struct vmcb *current_vmcb;
/* index = sev_asid, value = vmcb pointer */
struct vmcb **sev_vmcbs;
};
-DECLARE_PER_CPU(struct svm_cpu_data *, svm_data);
+DECLARE_PER_CPU(struct svm_cpu_data, svm_data);
void recalc_intercepts(struct vcpu_svm *svm);
@@ -683,7 +682,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm);
/* vmenter.S */
-void __svm_sev_es_vcpu_run(unsigned long vmcb_pa);
-void __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs);
+void __svm_sev_es_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted);
+void __svm_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted);
#endif
diff --git a/arch/x86/kvm/svm/svm_ops.h b/arch/x86/kvm/svm/svm_ops.h
index 9430d6437c9f..36c8af87a707 100644
--- a/arch/x86/kvm/svm/svm_ops.h
+++ b/arch/x86/kvm/svm/svm_ops.h
@@ -61,9 +61,4 @@ static __always_inline void vmsave(unsigned long pa)
svm_asm1(vmsave, "a" (pa), "memory");
}
-static __always_inline void vmload(unsigned long pa)
-{
- svm_asm1(vmload, "a" (pa), "memory");
-}
-
#endif /* __KVM_X86_SVM_OPS_H */
diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S
index 723f8534986c..34367dc203f2 100644
--- a/arch/x86/kvm/svm/vmenter.S
+++ b/arch/x86/kvm/svm/vmenter.S
@@ -4,35 +4,97 @@
#include <asm/bitsperlong.h>
#include <asm/kvm_vcpu_regs.h>
#include <asm/nospec-branch.h>
+#include "kvm-asm-offsets.h"
#define WORD_SIZE (BITS_PER_LONG / 8)
/* Intentionally omit RAX as it's context switched by hardware */
-#define VCPU_RCX __VCPU_REGS_RCX * WORD_SIZE
-#define VCPU_RDX __VCPU_REGS_RDX * WORD_SIZE
-#define VCPU_RBX __VCPU_REGS_RBX * WORD_SIZE
+#define VCPU_RCX (SVM_vcpu_arch_regs + __VCPU_REGS_RCX * WORD_SIZE)
+#define VCPU_RDX (SVM_vcpu_arch_regs + __VCPU_REGS_RDX * WORD_SIZE)
+#define VCPU_RBX (SVM_vcpu_arch_regs + __VCPU_REGS_RBX * WORD_SIZE)
/* Intentionally omit RSP as it's context switched by hardware */
-#define VCPU_RBP __VCPU_REGS_RBP * WORD_SIZE
-#define VCPU_RSI __VCPU_REGS_RSI * WORD_SIZE
-#define VCPU_RDI __VCPU_REGS_RDI * WORD_SIZE
+#define VCPU_RBP (SVM_vcpu_arch_regs + __VCPU_REGS_RBP * WORD_SIZE)
+#define VCPU_RSI (SVM_vcpu_arch_regs + __VCPU_REGS_RSI * WORD_SIZE)
+#define VCPU_RDI (SVM_vcpu_arch_regs + __VCPU_REGS_RDI * WORD_SIZE)
#ifdef CONFIG_X86_64
-#define VCPU_R8 __VCPU_REGS_R8 * WORD_SIZE
-#define VCPU_R9 __VCPU_REGS_R9 * WORD_SIZE
-#define VCPU_R10 __VCPU_REGS_R10 * WORD_SIZE
-#define VCPU_R11 __VCPU_REGS_R11 * WORD_SIZE
-#define VCPU_R12 __VCPU_REGS_R12 * WORD_SIZE
-#define VCPU_R13 __VCPU_REGS_R13 * WORD_SIZE
-#define VCPU_R14 __VCPU_REGS_R14 * WORD_SIZE
-#define VCPU_R15 __VCPU_REGS_R15 * WORD_SIZE
+#define VCPU_R8 (SVM_vcpu_arch_regs + __VCPU_REGS_R8 * WORD_SIZE)
+#define VCPU_R9 (SVM_vcpu_arch_regs + __VCPU_REGS_R9 * WORD_SIZE)
+#define VCPU_R10 (SVM_vcpu_arch_regs + __VCPU_REGS_R10 * WORD_SIZE)
+#define VCPU_R11 (SVM_vcpu_arch_regs + __VCPU_REGS_R11 * WORD_SIZE)
+#define VCPU_R12 (SVM_vcpu_arch_regs + __VCPU_REGS_R12 * WORD_SIZE)
+#define VCPU_R13 (SVM_vcpu_arch_regs + __VCPU_REGS_R13 * WORD_SIZE)
+#define VCPU_R14 (SVM_vcpu_arch_regs + __VCPU_REGS_R14 * WORD_SIZE)
+#define VCPU_R15 (SVM_vcpu_arch_regs + __VCPU_REGS_R15 * WORD_SIZE)
#endif
+#define SVM_vmcb01_pa (SVM_vmcb01 + KVM_VMCB_pa)
+
.section .noinstr.text, "ax"
+.macro RESTORE_GUEST_SPEC_CTRL
+ /* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */
+ ALTERNATIVE_2 "", \
+ "jmp 800f", X86_FEATURE_MSR_SPEC_CTRL, \
+ "", X86_FEATURE_V_SPEC_CTRL
+801:
+.endm
+.macro RESTORE_GUEST_SPEC_CTRL_BODY
+800:
+ /*
+ * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the
+ * host's, write the MSR. This is kept out-of-line so that the common
+ * case does not have to jump.
+ *
+ * IMPORTANT: To avoid RSB underflow attacks and any other nastiness,
+ * there must not be any returns or indirect branches between this code
+ * and vmentry.
+ */
+ movl SVM_spec_ctrl(%_ASM_DI), %eax
+ cmp PER_CPU_VAR(x86_spec_ctrl_current), %eax
+ je 801b
+ mov $MSR_IA32_SPEC_CTRL, %ecx
+ xor %edx, %edx
+ wrmsr
+ jmp 801b
+.endm
+
+.macro RESTORE_HOST_SPEC_CTRL
+ /* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */
+ ALTERNATIVE_2 "", \
+ "jmp 900f", X86_FEATURE_MSR_SPEC_CTRL, \
+ "", X86_FEATURE_V_SPEC_CTRL
+901:
+.endm
+.macro RESTORE_HOST_SPEC_CTRL_BODY
+900:
+ /* Same for after vmexit. */
+ mov $MSR_IA32_SPEC_CTRL, %ecx
+
+ /*
+ * Load the value that the guest had written into MSR_IA32_SPEC_CTRL,
+ * if it was not intercepted during guest execution.
+ */
+ cmpb $0, (%_ASM_SP)
+ jnz 998f
+ rdmsr
+ movl %eax, SVM_spec_ctrl(%_ASM_DI)
+998:
+
+ /* Now restore the host value of the MSR if different from the guest's. */
+ movl PER_CPU_VAR(x86_spec_ctrl_current), %eax
+ cmp SVM_spec_ctrl(%_ASM_DI), %eax
+ je 901b
+ xor %edx, %edx
+ wrmsr
+ jmp 901b
+.endm
+
+
/**
* __svm_vcpu_run - Run a vCPU via a transition to SVM guest mode
- * @vmcb_pa: unsigned long
- * @regs: unsigned long * (to guest registers)
+ * @svm: struct vcpu_svm *
+ * @spec_ctrl_intercepted: bool
*/
SYM_FUNC_START(__svm_vcpu_run)
push %_ASM_BP
@@ -47,49 +109,71 @@ SYM_FUNC_START(__svm_vcpu_run)
#endif
push %_ASM_BX
- /* Save @regs. */
+ /*
+ * Save variables needed after vmexit on the stack, in inverse
+ * order compared to when they are needed.
+ */
+
+ /* Accessed directly from the stack in RESTORE_HOST_SPEC_CTRL. */
push %_ASM_ARG2
- /* Save @vmcb. */
+ /* Needed to restore access to percpu variables. */
+ __ASM_SIZE(push) PER_CPU_VAR(svm_data + SD_save_area_pa)
+
+ /* Finally save @svm. */
push %_ASM_ARG1
- /* Move @regs to RAX. */
- mov %_ASM_ARG2, %_ASM_AX
+.ifnc _ASM_ARG1, _ASM_DI
+ /*
+ * Stash @svm in RDI early. On 32-bit, arguments are in RAX, RCX
+ * and RDX which are clobbered by RESTORE_GUEST_SPEC_CTRL.
+ */
+ mov %_ASM_ARG1, %_ASM_DI
+.endif
+
+ /* Clobbers RAX, RCX, RDX. */
+ RESTORE_GUEST_SPEC_CTRL
+
+ /*
+ * Use a single vmcb (vmcb01 because it's always valid) for
+ * context switching guest state via VMLOAD/VMSAVE, that way
+ * the state doesn't need to be copied between vmcb01 and
+ * vmcb02 when switching vmcbs for nested virtualization.
+ */
+ mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX
+1: vmload %_ASM_AX
+2:
+
+ /* Get svm->current_vmcb->pa into RAX. */
+ mov SVM_current_vmcb(%_ASM_DI), %_ASM_AX
+ mov KVM_VMCB_pa(%_ASM_AX), %_ASM_AX
/* Load guest registers. */
- mov VCPU_RCX(%_ASM_AX), %_ASM_CX
- mov VCPU_RDX(%_ASM_AX), %_ASM_DX
- mov VCPU_RBX(%_ASM_AX), %_ASM_BX
- mov VCPU_RBP(%_ASM_AX), %_ASM_BP
- mov VCPU_RSI(%_ASM_AX), %_ASM_SI
- mov VCPU_RDI(%_ASM_AX), %_ASM_DI
+ mov VCPU_RCX(%_ASM_DI), %_ASM_CX
+ mov VCPU_RDX(%_ASM_DI), %_ASM_DX
+ mov VCPU_RBX(%_ASM_DI), %_ASM_BX
+ mov VCPU_RBP(%_ASM_DI), %_ASM_BP
+ mov VCPU_RSI(%_ASM_DI), %_ASM_SI
#ifdef CONFIG_X86_64
- mov VCPU_R8 (%_ASM_AX), %r8
- mov VCPU_R9 (%_ASM_AX), %r9
- mov VCPU_R10(%_ASM_AX), %r10
- mov VCPU_R11(%_ASM_AX), %r11
- mov VCPU_R12(%_ASM_AX), %r12
- mov VCPU_R13(%_ASM_AX), %r13
- mov VCPU_R14(%_ASM_AX), %r14
- mov VCPU_R15(%_ASM_AX), %r15
+ mov VCPU_R8 (%_ASM_DI), %r8
+ mov VCPU_R9 (%_ASM_DI), %r9
+ mov VCPU_R10(%_ASM_DI), %r10
+ mov VCPU_R11(%_ASM_DI), %r11
+ mov VCPU_R12(%_ASM_DI), %r12
+ mov VCPU_R13(%_ASM_DI), %r13
+ mov VCPU_R14(%_ASM_DI), %r14
+ mov VCPU_R15(%_ASM_DI), %r15
#endif
-
- /* "POP" @vmcb to RAX. */
- pop %_ASM_AX
+ mov VCPU_RDI(%_ASM_DI), %_ASM_DI
/* Enter guest mode */
sti
-1: vmrun %_ASM_AX
-
-2: cli
-
-#ifdef CONFIG_RETPOLINE
- /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
- FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
-#endif
+3: vmrun %_ASM_AX
+4:
+ cli
- /* "POP" @regs to RAX. */
+ /* Pop @svm to RAX while it's the only available register. */
pop %_ASM_AX
/* Save all guest registers. */
@@ -110,6 +194,26 @@ SYM_FUNC_START(__svm_vcpu_run)
mov %r15, VCPU_R15(%_ASM_AX)
#endif
+ /* @svm can stay in RDI from now on. */
+ mov %_ASM_AX, %_ASM_DI
+
+ mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX
+5: vmsave %_ASM_AX
+6:
+
+ /* Restores GSBASE among other things, allowing access to percpu data. */
+ pop %_ASM_AX
+7: vmload %_ASM_AX
+8:
+
+#ifdef CONFIG_RETPOLINE
+ /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
+ FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
+#endif
+
+ /* Clobbers RAX, RCX, RDX. */
+ RESTORE_HOST_SPEC_CTRL
+
/*
* Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
* untrained as soon as we exit the VM and are back to the
@@ -145,6 +249,9 @@ SYM_FUNC_START(__svm_vcpu_run)
xor %r15d, %r15d
#endif
+ /* "Pop" @spec_ctrl_intercepted. */
+ pop %_ASM_BX
+
pop %_ASM_BX
#ifdef CONFIG_X86_64
@@ -159,17 +266,33 @@ SYM_FUNC_START(__svm_vcpu_run)
pop %_ASM_BP
RET
-3: cmpb $0, kvm_rebooting
+ RESTORE_GUEST_SPEC_CTRL_BODY
+ RESTORE_HOST_SPEC_CTRL_BODY
+
+10: cmpb $0, kvm_rebooting
jne 2b
ud2
+30: cmpb $0, kvm_rebooting
+ jne 4b
+ ud2
+50: cmpb $0, kvm_rebooting
+ jne 6b
+ ud2
+70: cmpb $0, kvm_rebooting
+ jne 8b
+ ud2
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE(1b, 10b)
+ _ASM_EXTABLE(3b, 30b)
+ _ASM_EXTABLE(5b, 50b)
+ _ASM_EXTABLE(7b, 70b)
SYM_FUNC_END(__svm_vcpu_run)
/**
* __svm_sev_es_vcpu_run - Run a SEV-ES vCPU via a transition to SVM guest mode
- * @vmcb_pa: unsigned long
+ * @svm: struct vcpu_svm *
+ * @spec_ctrl_intercepted: bool
*/
SYM_FUNC_START(__svm_sev_es_vcpu_run)
push %_ASM_BP
@@ -184,8 +307,31 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
#endif
push %_ASM_BX
- /* Move @vmcb to RAX. */
- mov %_ASM_ARG1, %_ASM_AX
+ /*
+ * Save variables needed after vmexit on the stack, in inverse
+ * order compared to when they are needed.
+ */
+
+ /* Accessed directly from the stack in RESTORE_HOST_SPEC_CTRL. */
+ push %_ASM_ARG2
+
+ /* Save @svm. */
+ push %_ASM_ARG1
+
+.ifnc _ASM_ARG1, _ASM_DI
+ /*
+ * Stash @svm in RDI early. On 32-bit, arguments are in RAX, RCX
+ * and RDX which are clobbered by RESTORE_GUEST_SPEC_CTRL.
+ */
+ mov %_ASM_ARG1, %_ASM_DI
+.endif
+
+ /* Clobbers RAX, RCX, RDX. */
+ RESTORE_GUEST_SPEC_CTRL
+
+ /* Get svm->current_vmcb->pa into RAX. */
+ mov SVM_current_vmcb(%_ASM_DI), %_ASM_AX
+ mov KVM_VMCB_pa(%_ASM_AX), %_ASM_AX
/* Enter guest mode */
sti
@@ -194,11 +340,17 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
2: cli
+ /* Pop @svm to RDI, guest registers have been saved already. */
+ pop %_ASM_DI
+
#ifdef CONFIG_RETPOLINE
/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
#endif
+ /* Clobbers RAX, RCX, RDX. */
+ RESTORE_HOST_SPEC_CTRL
+
/*
* Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
* untrained as soon as we exit the VM and are back to the
@@ -208,6 +360,9 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
*/
UNTRAIN_RET
+ /* "Pop" @spec_ctrl_intercepted. */
+ pop %_ASM_BX
+
pop %_ASM_BX
#ifdef CONFIG_X86_64
@@ -222,6 +377,9 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
pop %_ASM_BP
RET
+ RESTORE_GUEST_SPEC_CTRL_BODY
+ RESTORE_HOST_SPEC_CTRL_BODY
+
3: cmpb $0, kvm_rebooting
jne 2b
ud2
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 0c62352dda6a..5b0d4859e4b7 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4854,6 +4854,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
static void nested_vmx_triple_fault(struct kvm_vcpu *vcpu)
{
+ kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
nested_vmx_vmexit(vcpu, EXIT_REASON_TRIPLE_FAULT, 0, 0);
}
@@ -6440,9 +6441,6 @@ out:
return kvm_state.size;
}
-/*
- * Forcibly leave nested mode in order to be able to reset the VCPU later on.
- */
void vmx_leave_nested(struct kvm_vcpu *vcpu)
{
if (is_guest_mode(vcpu)) {
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 25b70a85bef5..10b33da9bd05 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -617,7 +617,7 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
- for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+ for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) {
pmu->gp_counters[i].type = KVM_PMC_GP;
pmu->gp_counters[i].vcpu = vcpu;
pmu->gp_counters[i].idx = i;
@@ -643,7 +643,7 @@ static void intel_pmu_reset(struct kvm_vcpu *vcpu)
struct kvm_pmc *pmc = NULL;
int i;
- for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+ for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) {
pmc = &pmu->gp_counters[i];
pmc_stop_counter(pmc);
diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S
index 8477d8bdd69c..0b5db4de4d09 100644
--- a/arch/x86/kvm/vmx/vmenter.S
+++ b/arch/x86/kvm/vmx/vmenter.S
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/asm.h>
-#include <asm/asm-offsets.h>
#include <asm/bitsperlong.h>
#include <asm/kvm_vcpu_regs.h>
#include <asm/nospec-branch.h>
#include <asm/percpu.h>
#include <asm/segment.h>
+#include "kvm-asm-offsets.h"
#include "run_flags.h"
#define WORD_SIZE (BITS_PER_LONG / 8)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5f5eb577d583..69227f77b201 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -628,6 +628,12 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vecto
ex->payload = payload;
}
+/* Forcibly leave the nested mode in cases like a vCPU reset */
+static void kvm_leave_nested(struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops.nested_ops->leave_nested(vcpu);
+}
+
static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
unsigned nr, bool has_error, u32 error_code,
bool has_payload, unsigned long payload, bool reinject)
@@ -1438,32 +1444,27 @@ static const u32 msrs_to_save_all[] = {
MSR_ARCH_PERFMON_FIXED_CTR0 + 2,
MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_STATUS,
MSR_CORE_PERF_GLOBAL_CTRL, MSR_CORE_PERF_GLOBAL_OVF_CTRL,
+ MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_PEBS_DATA_CFG,
+
+ /* This part of MSRs should match KVM_INTEL_PMC_MAX_GENERIC. */
MSR_ARCH_PERFMON_PERFCTR0, MSR_ARCH_PERFMON_PERFCTR1,
MSR_ARCH_PERFMON_PERFCTR0 + 2, MSR_ARCH_PERFMON_PERFCTR0 + 3,
MSR_ARCH_PERFMON_PERFCTR0 + 4, MSR_ARCH_PERFMON_PERFCTR0 + 5,
MSR_ARCH_PERFMON_PERFCTR0 + 6, MSR_ARCH_PERFMON_PERFCTR0 + 7,
- MSR_ARCH_PERFMON_PERFCTR0 + 8, MSR_ARCH_PERFMON_PERFCTR0 + 9,
- MSR_ARCH_PERFMON_PERFCTR0 + 10, MSR_ARCH_PERFMON_PERFCTR0 + 11,
- MSR_ARCH_PERFMON_PERFCTR0 + 12, MSR_ARCH_PERFMON_PERFCTR0 + 13,
- MSR_ARCH_PERFMON_PERFCTR0 + 14, MSR_ARCH_PERFMON_PERFCTR0 + 15,
- MSR_ARCH_PERFMON_PERFCTR0 + 16, MSR_ARCH_PERFMON_PERFCTR0 + 17,
MSR_ARCH_PERFMON_EVENTSEL0, MSR_ARCH_PERFMON_EVENTSEL1,
MSR_ARCH_PERFMON_EVENTSEL0 + 2, MSR_ARCH_PERFMON_EVENTSEL0 + 3,
MSR_ARCH_PERFMON_EVENTSEL0 + 4, MSR_ARCH_PERFMON_EVENTSEL0 + 5,
MSR_ARCH_PERFMON_EVENTSEL0 + 6, MSR_ARCH_PERFMON_EVENTSEL0 + 7,
- MSR_ARCH_PERFMON_EVENTSEL0 + 8, MSR_ARCH_PERFMON_EVENTSEL0 + 9,
- MSR_ARCH_PERFMON_EVENTSEL0 + 10, MSR_ARCH_PERFMON_EVENTSEL0 + 11,
- MSR_ARCH_PERFMON_EVENTSEL0 + 12, MSR_ARCH_PERFMON_EVENTSEL0 + 13,
- MSR_ARCH_PERFMON_EVENTSEL0 + 14, MSR_ARCH_PERFMON_EVENTSEL0 + 15,
- MSR_ARCH_PERFMON_EVENTSEL0 + 16, MSR_ARCH_PERFMON_EVENTSEL0 + 17,
- MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_PEBS_DATA_CFG,
MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3,
MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3,
+
+ /* This part of MSRs should match KVM_AMD_PMC_MAX_GENERIC. */
MSR_F15H_PERF_CTL0, MSR_F15H_PERF_CTL1, MSR_F15H_PERF_CTL2,
MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
+
MSR_IA32_XFD, MSR_IA32_XFD_ERR,
};
@@ -1562,7 +1563,7 @@ static const u32 msr_based_features_all[] = {
MSR_IA32_VMX_EPT_VPID_CAP,
MSR_IA32_VMX_VMFUNC,
- MSR_F10H_DECFG,
+ MSR_AMD64_DE_CFG,
MSR_IA32_UCODE_REV,
MSR_IA32_ARCH_CAPABILITIES,
MSR_IA32_PERF_CAPABILITIES,
@@ -5200,7 +5201,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
- kvm_x86_ops.nested_ops->leave_nested(vcpu);
+ kvm_leave_nested(vcpu);
kvm_smm_changed(vcpu, events->smi.smm);
}
@@ -7041,14 +7042,14 @@ static void kvm_init_msr_list(void)
intel_pt_validate_hw_cap(PT_CAP_num_address_ranges) * 2)
continue;
break;
- case MSR_ARCH_PERFMON_PERFCTR0 ... MSR_ARCH_PERFMON_PERFCTR0 + 17:
+ case MSR_ARCH_PERFMON_PERFCTR0 ... MSR_ARCH_PERFMON_PERFCTR_MAX:
if (msrs_to_save_all[i] - MSR_ARCH_PERFMON_PERFCTR0 >=
- min(INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp))
+ min(KVM_INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp))
continue;
break;
- case MSR_ARCH_PERFMON_EVENTSEL0 ... MSR_ARCH_PERFMON_EVENTSEL0 + 17:
+ case MSR_ARCH_PERFMON_EVENTSEL0 ... MSR_ARCH_PERFMON_EVENTSEL_MAX:
if (msrs_to_save_all[i] - MSR_ARCH_PERFMON_EVENTSEL0 >=
- min(INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp))
+ min(KVM_INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp))
continue;
break;
case MSR_IA32_XFD:
@@ -9810,7 +9811,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
int kvm_check_nested_events(struct kvm_vcpu *vcpu)
{
- if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
+ if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
kvm_x86_ops.nested_ops->triple_fault(vcpu);
return 1;
}
@@ -10565,10 +10566,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 0;
goto out;
}
- if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
- if (is_guest_mode(vcpu)) {
+ if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
+ if (is_guest_mode(vcpu))
kvm_x86_ops.nested_ops->triple_fault(vcpu);
- } else {
+
+ if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
vcpu->mmio_needed = 0;
r = 0;
@@ -12002,8 +12004,18 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
WARN_ON_ONCE(!init_event &&
(old_cr0 || kvm_read_cr3(vcpu) || kvm_read_cr4(vcpu)));
+ /*
+ * SVM doesn't unconditionally VM-Exit on INIT and SHUTDOWN, thus it's
+ * possible to INIT the vCPU while L2 is active. Force the vCPU back
+ * into L1 as EFER.SVME is cleared on INIT (along with all other EFER
+ * bits), i.e. virtualization is disabled.
+ */
+ if (is_guest_mode(vcpu))
+ kvm_leave_nested(vcpu);
+
kvm_lapic_reset(vcpu, init_event);
+ WARN_ON_ONCE(is_guest_mode(vcpu) || is_smm(vcpu));
vcpu->arch.hflags = 0;
vcpu->arch.smi_pending = 0;
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 2dae413bd62a..f3098c0e386a 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -954,6 +954,14 @@ static int kvm_xen_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
return kvm_xen_hypercall_set_result(vcpu, run->xen.u.hcall.result);
}
+static inline int max_evtchn_port(struct kvm *kvm)
+{
+ if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
+ return EVTCHN_2L_NR_CHANNELS;
+ else
+ return COMPAT_EVTCHN_2L_NR_CHANNELS;
+}
+
static bool wait_pending_event(struct kvm_vcpu *vcpu, int nr_ports,
evtchn_port_t *ports)
{
@@ -1042,6 +1050,10 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode,
*r = -EFAULT;
goto out;
}
+ if (ports[i] >= max_evtchn_port(vcpu->kvm)) {
+ *r = -EINVAL;
+ goto out;
+ }
}
if (sched_poll.nr_ports == 1)
@@ -1215,6 +1227,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
bool longmode;
u64 input, params[6], r = -ENOSYS;
bool handled = false;
+ u8 cpl;
input = (u64)kvm_register_read(vcpu, VCPU_REGS_RAX);
@@ -1242,9 +1255,17 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
params[5] = (u64)kvm_r9_read(vcpu);
}
#endif
+ cpl = static_call(kvm_x86_get_cpl)(vcpu);
trace_kvm_xen_hypercall(input, params[0], params[1], params[2],
params[3], params[4], params[5]);
+ /*
+ * Only allow hypercall acceleration for CPL0. The rare hypercalls that
+ * are permitted in guest userspace can be handled by the VMM.
+ */
+ if (unlikely(cpl > 0))
+ goto handle_in_userspace;
+
switch (input) {
case __HYPERVISOR_xen_version:
if (params[0] == XENVER_version && vcpu->kvm->arch.xen.xen_version) {
@@ -1279,10 +1300,11 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
if (handled)
return kvm_xen_hypercall_set_result(vcpu, r);
+handle_in_userspace:
vcpu->run->exit_reason = KVM_EXIT_XEN;
vcpu->run->xen.type = KVM_EXIT_XEN_HCALL;
vcpu->run->xen.u.hcall.longmode = longmode;
- vcpu->run->xen.u.hcall.cpl = static_call(kvm_x86_get_cpl)(vcpu);
+ vcpu->run->xen.u.hcall.cpl = cpl;
vcpu->run->xen.u.hcall.input = input;
vcpu->run->xen.u.hcall.params[0] = params[0];
vcpu->run->xen.u.hcall.params[1] = params[1];
@@ -1297,14 +1319,6 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
return 0;
}
-static inline int max_evtchn_port(struct kvm *kvm)
-{
- if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
- return EVTCHN_2L_NR_CHANNELS;
- else
- return COMPAT_EVTCHN_2L_NR_CHANNELS;
-}
-
static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port)
{
int poll_evtchn = vcpu->arch.xen.poll_evtchn;
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
index f1bb18617156..24b48af27417 100644
--- a/arch/x86/lib/usercopy.c
+++ b/arch/x86/lib/usercopy.c
@@ -6,6 +6,7 @@
#include <linux/uaccess.h>
#include <linux/export.h>
+#include <linux/instrumented.h>
#include <asm/tlbflush.h>
@@ -44,7 +45,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
* called from other contexts.
*/
pagefault_disable();
+ instrument_copy_from_user_before(to, from, n);
ret = raw_copy_from_user(to, from, n);
+ instrument_copy_from_user_after(to, from, n, ret);
pagefault_enable();
return ret;
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index 6b3033845c6d..5804bbae4f01 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -37,8 +37,12 @@ int pmd_huge(pmd_t pmd)
*/
int pud_huge(pud_t pud)
{
+#if CONFIG_PGTABLE_LEVELS > 2
return !pud_none(pud) &&
(pud_val(pud) & (_PAGE_PRESENT|_PAGE_PSE)) != _PAGE_PRESENT;
+#else
+ return 0;
+#endif
}
#ifdef CONFIG_HUGETLB_PAGE
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 78c5bc654cff..6453fbaedb08 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -217,9 +217,15 @@ __ioremap_caller(resource_size_t phys_addr, unsigned long size,
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
- phys_addr &= PHYSICAL_PAGE_MASK;
+ phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr+1) - phys_addr;
+ /*
+ * Mask out any bits not part of the actual physical
+ * address, like memory encryption bits.
+ */
+ phys_addr &= PHYSICAL_PAGE_MASK;
+
retval = memtype_reserve(phys_addr, (u64)phys_addr + size,
pcm, &new_pcm);
if (retval) {
diff --git a/arch/x86/mm/pat/cpa-test.c b/arch/x86/mm/pat/cpa-test.c
index 423b21e80929..3d2f7f0a6ed1 100644
--- a/arch/x86/mm/pat/cpa-test.c
+++ b/arch/x86/mm/pat/cpa-test.c
@@ -136,10 +136,10 @@ static int pageattr_test(void)
failed += print_split(&sa);
for (i = 0; i < NTEST; i++) {
- unsigned long pfn = prandom_u32_max(max_pfn_mapped);
+ unsigned long pfn = get_random_u32_below(max_pfn_mapped);
addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
- len[i] = prandom_u32_max(NPAGES);
+ len[i] = get_random_u32_below(NPAGES);
len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1);
if (len[i] == 0)
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 2e5a045731de..ef34ba21aa92 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/cc_platform.h>
#include <linux/set_memory.h>
+#include <linux/memregion.h>
#include <asm/e820/api.h>
#include <asm/processor.h>
@@ -330,6 +331,23 @@ void arch_invalidate_pmem(void *addr, size_t size)
EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
#endif
+#ifdef CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
+bool cpu_cache_has_invalidate_memregion(void)
+{
+ return !cpu_feature_enabled(X86_FEATURE_HYPERVISOR);
+}
+EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, DEVMEM);
+
+int cpu_cache_invalidate_memregion(int res_desc)
+{
+ if (WARN_ON_ONCE(!cpu_cache_has_invalidate_memregion()))
+ return -ENXIO;
+ wbinvd_on_all_cpus();
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cpu_cache_invalidate_memregion, DEVMEM);
+#endif
+
static void __cpa_flush_all(void *arg)
{
unsigned long cache = (unsigned long)arg;
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 00127abd89ee..99620428ad78 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -11,7 +11,6 @@
#include <linux/bpf.h>
#include <linux/memory.h>
#include <linux/sort.h>
-#include <linux/init.h>
#include <asm/extable.h>
#include <asm/set_memory.h>
#include <asm/nospec-branch.h>
@@ -389,18 +388,6 @@ out:
return ret;
}
-int __init bpf_arch_init_dispatcher_early(void *ip)
-{
- const u8 *nop_insn = x86_nops[5];
-
- if (is_endbr(*(u32 *)ip))
- ip += ENDBR_INSN_SIZE;
-
- if (memcmp(ip, nop_insn, X86_PATCH_SIZE))
- text_poke_early(ip, nop_insn, X86_PATCH_SIZE);
- return 0;
-}
-
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
void *old_addr, void *new_addr)
{
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index 994a229cb79f..68244a3422d1 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -183,13 +183,12 @@ err_sysfs:
return r;
}
-static int xo15_sci_remove(struct acpi_device *device)
+static void xo15_sci_remove(struct acpi_device *device)
{
acpi_disable_gpe(NULL, xo15_sci_gpe);
acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
cancel_work_sync(&sci_work);
sysfs_remove_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index bb176c72891c..93ae33248f42 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -513,15 +513,23 @@ static int pm_cpu_check(const struct x86_cpu_id *c)
static void pm_save_spec_msr(void)
{
- u32 spec_msr_id[] = {
- MSR_IA32_SPEC_CTRL,
- MSR_IA32_TSX_CTRL,
- MSR_TSX_FORCE_ABORT,
- MSR_IA32_MCU_OPT_CTRL,
- MSR_AMD64_LS_CFG,
+ struct msr_enumeration {
+ u32 msr_no;
+ u32 feature;
+ } msr_enum[] = {
+ { MSR_IA32_SPEC_CTRL, X86_FEATURE_MSR_SPEC_CTRL },
+ { MSR_IA32_TSX_CTRL, X86_FEATURE_MSR_TSX_CTRL },
+ { MSR_TSX_FORCE_ABORT, X86_FEATURE_TSX_FORCE_ABORT },
+ { MSR_IA32_MCU_OPT_CTRL, X86_FEATURE_SRBDS_CTRL },
+ { MSR_AMD64_LS_CFG, X86_FEATURE_LS_CFG_SSBD },
+ { MSR_AMD64_DE_CFG, X86_FEATURE_LFENCE_RDTSC },
};
+ int i;
- msr_build_context(spec_msr_id, ARRAY_SIZE(spec_msr_id));
+ for (i = 0; i < ARRAY_SIZE(msr_enum); i++) {
+ if (boot_cpu_has(msr_enum[i].feature))
+ msr_build_context(&msr_enum[i].msr_no, 1);
+ }
}
static int pm_check_save_msr(void)
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index dcaf3b38a9e0..6523eb7c3bd1 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -201,10 +201,6 @@ typedef struct user_i387_struct elf_fpregset_t;
struct task_struct;
-extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
-
-#define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
-
#define ELF_EXEC_PAGESIZE 4096
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index f82857e48815..1a2ba31635a5 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -23,6 +23,7 @@
#include <linux/start_kernel.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
+#include <linux/kstrtox.h>
#include <linux/memblock.h>
#include <linux/export.h>
#include <linux/mm.h>
@@ -32,6 +33,7 @@
#include <linux/edd.h>
#include <linux/reboot.h>
#include <linux/virtio_anchor.h>
+#include <linux/stackprotector.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -64,7 +66,6 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/reboot.h>
-#include <asm/stackprotector.h>
#include <asm/hypervisor.h>
#include <asm/mach_traps.h>
#include <asm/mwait.h>
@@ -113,7 +114,7 @@ static __read_mostly bool xen_msr_safe = IS_ENABLED(CONFIG_XEN_PV_MSR_SAFE);
static int __init parse_xen_msr_safe(char *str)
{
if (str)
- return strtobool(str, &xen_msr_safe);
+ return kstrtobool(str, &xen_msr_safe);
return -EINVAL;
}
early_param("xen_msr_safe", parse_xen_msr_safe);
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 4f4309500559..8db26f10fb1d 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/kstrtox.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/memblock.h>
@@ -85,7 +86,7 @@ static void __init xen_parse_512gb(void)
arg = strstr(xen_start_info->cmd_line, "xen_512gb_limit=");
if (!arg)
val = true;
- else if (strtobool(arg + strlen("xen_512gb_limit="), &val))
+ else if (kstrtobool(arg + strlen("xen_512gb_limit="), &val))
return;
xen_512gb_limit = val;
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index c3e1f9a7d43a..4b0d6fff88de 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -32,30 +32,30 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
void xen_smp_intr_free(unsigned int cpu)
{
+ kfree(per_cpu(xen_resched_irq, cpu).name);
+ per_cpu(xen_resched_irq, cpu).name = NULL;
if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
per_cpu(xen_resched_irq, cpu).irq = -1;
- kfree(per_cpu(xen_resched_irq, cpu).name);
- per_cpu(xen_resched_irq, cpu).name = NULL;
}
+ kfree(per_cpu(xen_callfunc_irq, cpu).name);
+ per_cpu(xen_callfunc_irq, cpu).name = NULL;
if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
per_cpu(xen_callfunc_irq, cpu).irq = -1;
- kfree(per_cpu(xen_callfunc_irq, cpu).name);
- per_cpu(xen_callfunc_irq, cpu).name = NULL;
}
+ kfree(per_cpu(xen_debug_irq, cpu).name);
+ per_cpu(xen_debug_irq, cpu).name = NULL;
if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
per_cpu(xen_debug_irq, cpu).irq = -1;
- kfree(per_cpu(xen_debug_irq, cpu).name);
- per_cpu(xen_debug_irq, cpu).name = NULL;
}
+ kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
+ per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
NULL);
per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
- kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
- per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
}
}
@@ -65,6 +65,7 @@ int xen_smp_intr_init(unsigned int cpu)
char *resched_name, *callfunc_name, *debug_name;
resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+ per_cpu(xen_resched_irq, cpu).name = resched_name;
rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
cpu,
xen_reschedule_interrupt,
@@ -74,9 +75,9 @@ int xen_smp_intr_init(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_resched_irq, cpu).irq = rc;
- per_cpu(xen_resched_irq, cpu).name = resched_name;
callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+ per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
cpu,
xen_call_function_interrupt,
@@ -86,10 +87,10 @@ int xen_smp_intr_init(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_callfunc_irq, cpu).irq = rc;
- per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
if (!xen_fifo_events) {
debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
+ per_cpu(xen_debug_irq, cpu).name = debug_name;
rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu,
xen_debug_interrupt,
IRQF_PERCPU | IRQF_NOBALANCING,
@@ -97,10 +98,10 @@ int xen_smp_intr_init(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_debug_irq, cpu).irq = rc;
- per_cpu(xen_debug_irq, cpu).name = debug_name;
}
callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
+ per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
cpu,
xen_call_function_single_interrupt,
@@ -110,7 +111,6 @@ int xen_smp_intr_init(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
- per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
return 0;
diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c
index 480be82e9b7b..6175f2c5c822 100644
--- a/arch/x86/xen/smp_pv.c
+++ b/arch/x86/xen/smp_pv.c
@@ -97,18 +97,18 @@ asmlinkage __visible void cpu_bringup_and_idle(void)
void xen_smp_intr_free_pv(unsigned int cpu)
{
+ kfree(per_cpu(xen_irq_work, cpu).name);
+ per_cpu(xen_irq_work, cpu).name = NULL;
if (per_cpu(xen_irq_work, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
per_cpu(xen_irq_work, cpu).irq = -1;
- kfree(per_cpu(xen_irq_work, cpu).name);
- per_cpu(xen_irq_work, cpu).name = NULL;
}
+ kfree(per_cpu(xen_pmu_irq, cpu).name);
+ per_cpu(xen_pmu_irq, cpu).name = NULL;
if (per_cpu(xen_pmu_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_pmu_irq, cpu).irq, NULL);
per_cpu(xen_pmu_irq, cpu).irq = -1;
- kfree(per_cpu(xen_pmu_irq, cpu).name);
- per_cpu(xen_pmu_irq, cpu).name = NULL;
}
}
@@ -118,6 +118,7 @@ int xen_smp_intr_init_pv(unsigned int cpu)
char *callfunc_name, *pmu_name;
callfunc_name = kasprintf(GFP_KERNEL, "irqwork%d", cpu);
+ per_cpu(xen_irq_work, cpu).name = callfunc_name;
rc = bind_ipi_to_irqhandler(XEN_IRQ_WORK_VECTOR,
cpu,
xen_irq_work_interrupt,
@@ -127,10 +128,10 @@ int xen_smp_intr_init_pv(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_irq_work, cpu).irq = rc;
- per_cpu(xen_irq_work, cpu).name = callfunc_name;
if (is_xen_pmu) {
pmu_name = kasprintf(GFP_KERNEL, "pmu%d", cpu);
+ per_cpu(xen_pmu_irq, cpu).name = pmu_name;
rc = bind_virq_to_irqhandler(VIRQ_XENPMU, cpu,
xen_pmu_irq_handler,
IRQF_PERCPU|IRQF_NOBALANCING,
@@ -138,7 +139,6 @@ int xen_smp_intr_init_pv(unsigned int cpu)
if (rc < 0)
goto fail;
per_cpu(xen_pmu_irq, cpu).irq = rc;
- per_cpu(xen_pmu_irq, cpu).name = pmu_name;
}
return 0;
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 043c73dfd2c9..5c6fc16e4b92 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -75,6 +75,7 @@ void xen_init_lock_cpu(int cpu)
cpu, per_cpu(lock_kicker_irq, cpu));
name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+ per_cpu(irq_name, cpu) = name;
irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
cpu,
dummy_handler,
@@ -85,7 +86,6 @@ void xen_init_lock_cpu(int cpu)
if (irq >= 0) {
disable_irq(irq); /* make sure it's never delivered */
per_cpu(lock_kicker_irq, cpu) = irq;
- per_cpu(irq_name, cpu) = name;
}
printk("cpu %d spinlock event irq %d\n", cpu, irq);
@@ -98,6 +98,8 @@ void xen_uninit_lock_cpu(int cpu)
if (!xen_pvspin)
return;
+ kfree(per_cpu(irq_name, cpu));
+ per_cpu(irq_name, cpu) = NULL;
/*
* When booting the kernel with 'mitigations=auto,nosmt', the secondary
* CPUs are not activated, and lock_kicker_irq is not initialized.
@@ -108,8 +110,6 @@ void xen_uninit_lock_cpu(int cpu)
unbind_from_irqhandler(irq, NULL);
per_cpu(lock_kicker_irq, cpu) = -1;
- kfree(per_cpu(irq_name, cpu));
- per_cpu(irq_name, cpu) = NULL;
}
PV_CALLEE_SAVE_REGS_THUNK(xen_vcpu_stolen);
diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S
index 6b4fdf6b9542..4a184f6e4e4d 100644
--- a/arch/x86/xen/xen-asm.S
+++ b/arch/x86/xen/xen-asm.S
@@ -262,10 +262,10 @@ SYM_CODE_START(xen_entry_SYSCALL_compat)
/*
* Neither Xen nor the kernel really knows what the old SS and
- * CS were. The kernel expects __USER32_DS and __USER32_CS, so
+ * CS were. The kernel expects __USER_DS and __USER32_CS, so
* report those values even though Xen will guess its own values.
*/
- movq $__USER32_DS, 4*8(%rsp)
+ movq $__USER_DS, 4*8(%rsp)
movq $__USER32_CS, 1*8(%rsp)
jmp entry_SYSCALL_compat_after_hwframe
@@ -284,10 +284,10 @@ SYM_CODE_START(xen_entry_SYSENTER_compat)
/*
* Neither Xen nor the kernel really knows what the old SS and
- * CS were. The kernel expects __USER32_DS and __USER32_CS, so
+ * CS were. The kernel expects __USER_DS and __USER32_CS, so
* report those values even though Xen will guess its own values.
*/
- movq $__USER32_DS, 4*8(%rsp)
+ movq $__USER_DS, 4*8(%rsp)
movq $__USER32_CS, 1*8(%rsp)
jmp entry_SYSENTER_compat_after_hwframe
diff --git a/arch/xtensa/include/asm/stackprotector.h b/arch/xtensa/include/asm/stackprotector.h
index e368f94fd2af..dd10279a2378 100644
--- a/arch/xtensa/include/asm/stackprotector.h
+++ b/arch/xtensa/include/asm/stackprotector.h
@@ -14,9 +14,6 @@
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H 1
-#include <linux/random.h>
-#include <linux/version.h>
-
extern unsigned long __stack_chk_guard;
/*
@@ -27,11 +24,7 @@ extern unsigned long __stack_chk_guard;
*/
static __always_inline void boot_init_stack_canary(void)
{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= LINUX_VERSION_CODE;
+ unsigned long canary = get_random_canary();
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/block/bdev.c b/block/bdev.c
index d699ecdb3260..edc110d90df4 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -224,7 +224,7 @@ int fsync_bdev(struct block_device *bdev)
EXPORT_SYMBOL(fsync_bdev);
/**
- * freeze_bdev -- lock a filesystem and force it into a consistent state
+ * freeze_bdev - lock a filesystem and force it into a consistent state
* @bdev: blockdevice to lock
*
* If a superblock is found on this device, we take the s_umount semaphore
@@ -268,7 +268,7 @@ done:
EXPORT_SYMBOL(freeze_bdev);
/**
- * thaw_bdev -- unlock filesystem
+ * thaw_bdev - unlock filesystem
* @bdev: blockdevice to unlock
*
* Unlocks the filesystem and marks it writeable again after freeze_bdev().
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index 144bca006463..627476bc6495 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -224,7 +224,7 @@ void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq,
{
blkg_rwstat_add(&bfqg->stats.queued, opf, 1);
bfqg_stats_end_empty_time(&bfqg->stats);
- if (!(bfqq == ((struct bfq_data *)bfqg->bfqd)->in_service_queue))
+ if (!(bfqq == bfqg->bfqd->in_service_queue))
bfqg_stats_set_start_group_wait_time(bfqg, bfqq_group(bfqq));
}
@@ -552,6 +552,7 @@ static void bfq_pd_init(struct blkg_policy_data *pd)
*/
bfqg->bfqd = bfqd;
bfqg->active_entities = 0;
+ bfqg->num_queues_with_pending_reqs = 0;
bfqg->online = true;
bfqg->rq_pos_tree = RB_ROOT;
}
@@ -610,6 +611,10 @@ struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio)
struct bfq_group *bfqg;
while (blkg) {
+ if (!blkg->online) {
+ blkg = blkg->parent;
+ continue;
+ }
bfqg = blkg_to_bfqg(blkg);
if (bfqg->online) {
bio_associate_blkg_from_css(bio, &blkg->blkcg->css);
@@ -641,6 +646,7 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
{
struct bfq_entity *entity = &bfqq->entity;
struct bfq_group *old_parent = bfqq_group(bfqq);
+ bool has_pending_reqs = false;
/*
* No point to move bfqq to the same group, which can happen when
@@ -661,6 +667,11 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
*/
bfqq->ref++;
+ if (entity->in_groups_with_pending_reqs) {
+ has_pending_reqs = true;
+ bfq_del_bfqq_in_groups_with_pending_reqs(bfqq);
+ }
+
/* If bfqq is empty, then bfq_bfqq_expire also invokes
* bfq_del_bfqq_busy, thereby removing bfqq and its entity
* from data structures related to current group. Otherwise we
@@ -688,6 +699,9 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
/* pin down bfqg and its associated blkg */
bfqg_and_blkg_get(bfqg);
+ if (has_pending_reqs)
+ bfq_add_bfqq_in_groups_with_pending_reqs(bfqq);
+
if (bfq_bfqq_busy(bfqq)) {
if (unlikely(!bfqd->nonrot_with_queueing))
bfq_pos_tree_add_move(bfqd, bfqq);
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 7ea427817f7f..a72304c728fc 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -820,7 +820,7 @@ bfq_pos_tree_add_move(struct bfq_data *bfqd, struct bfq_queue *bfqq)
* much easier to maintain the needed state:
* 1) all active queues have the same weight,
* 2) all active queues belong to the same I/O-priority class,
- * 3) there are no active groups.
+ * 3) there is at most one active group.
* In particular, the last condition is always true if hierarchical
* support or the cgroups interface are not enabled, thus no state
* needs to be maintained in this case.
@@ -852,7 +852,7 @@ static bool bfq_asymmetric_scenario(struct bfq_data *bfqd,
return varied_queue_weights || multiple_classes_busy
#ifdef CONFIG_BFQ_GROUP_IOSCHED
- || bfqd->num_groups_with_pending_reqs > 0
+ || bfqd->num_groups_with_pending_reqs > 1
#endif
;
}
@@ -870,9 +870,9 @@ static bool bfq_asymmetric_scenario(struct bfq_data *bfqd,
* In most scenarios, the rate at which nodes are created/destroyed
* should be low too.
*/
-void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq,
- struct rb_root_cached *root)
+void bfq_weights_tree_add(struct bfq_queue *bfqq)
{
+ struct rb_root_cached *root = &bfqq->bfqd->queue_weights_tree;
struct bfq_entity *entity = &bfqq->entity;
struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
bool leftmost = true;
@@ -944,13 +944,14 @@ inc_counter:
* See the comments to the function bfq_weights_tree_add() for considerations
* about overhead.
*/
-void __bfq_weights_tree_remove(struct bfq_data *bfqd,
- struct bfq_queue *bfqq,
- struct rb_root_cached *root)
+void bfq_weights_tree_remove(struct bfq_queue *bfqq)
{
+ struct rb_root_cached *root;
+
if (!bfqq->weight_counter)
return;
+ root = &bfqq->bfqd->queue_weights_tree;
bfqq->weight_counter->num_active--;
if (bfqq->weight_counter->num_active > 0)
goto reset_entity_pointer;
@@ -964,59 +965,6 @@ reset_entity_pointer:
}
/*
- * Invoke __bfq_weights_tree_remove on bfqq and decrement the number
- * of active groups for each queue's inactive parent entity.
- */
-void bfq_weights_tree_remove(struct bfq_data *bfqd,
- struct bfq_queue *bfqq)
-{
- struct bfq_entity *entity = bfqq->entity.parent;
-
- for_each_entity(entity) {
- struct bfq_sched_data *sd = entity->my_sched_data;
-
- if (sd->next_in_service || sd->in_service_entity) {
- /*
- * entity is still active, because either
- * next_in_service or in_service_entity is not
- * NULL (see the comments on the definition of
- * next_in_service for details on why
- * in_service_entity must be checked too).
- *
- * As a consequence, its parent entities are
- * active as well, and thus this loop must
- * stop here.
- */
- break;
- }
-
- /*
- * The decrement of num_groups_with_pending_reqs is
- * not performed immediately upon the deactivation of
- * entity, but it is delayed to when it also happens
- * that the first leaf descendant bfqq of entity gets
- * all its pending requests completed. The following
- * instructions perform this delayed decrement, if
- * needed. See the comments on
- * num_groups_with_pending_reqs for details.
- */
- if (entity->in_groups_with_pending_reqs) {
- entity->in_groups_with_pending_reqs = false;
- bfqd->num_groups_with_pending_reqs--;
- }
- }
-
- /*
- * Next function is invoked last, because it causes bfqq to be
- * freed if the following holds: bfqq is not in service and
- * has no dispatched request. DO NOT use bfqq after the next
- * function invocation.
- */
- __bfq_weights_tree_remove(bfqd, bfqq,
- &bfqd->queue_weights_tree);
-}
-
-/*
* Return expired entry, or NULL to just start from scratch in rbtree.
*/
static struct request *bfq_check_fifo(struct bfq_queue *bfqq,
@@ -2135,7 +2083,9 @@ static void bfq_check_waker(struct bfq_data *bfqd, struct bfq_queue *bfqq,
if (!bfqd->last_completed_rq_bfqq ||
bfqd->last_completed_rq_bfqq == bfqq ||
bfq_bfqq_has_short_ttime(bfqq) ||
- now_ns - bfqd->last_completion >= 4 * NSEC_PER_MSEC)
+ now_ns - bfqd->last_completion >= 4 * NSEC_PER_MSEC ||
+ bfqd->last_completed_rq_bfqq == &bfqd->oom_bfqq ||
+ bfqq == &bfqd->oom_bfqq)
return;
/*
@@ -2373,22 +2323,6 @@ static sector_t get_sdist(sector_t last_pos, struct request *rq)
return 0;
}
-#if 0 /* Still not clear if we can do without next two functions */
-static void bfq_activate_request(struct request_queue *q, struct request *rq)
-{
- struct bfq_data *bfqd = q->elevator->elevator_data;
-
- bfqd->rq_in_driver++;
-}
-
-static void bfq_deactivate_request(struct request_queue *q, struct request *rq)
-{
- struct bfq_data *bfqd = q->elevator->elevator_data;
-
- bfqd->rq_in_driver--;
-}
-#endif
-
static void bfq_remove_request(struct request_queue *q,
struct request *rq)
{
@@ -6261,7 +6195,8 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
*/
bfqq->budget_timeout = jiffies;
- bfq_weights_tree_remove(bfqd, bfqq);
+ bfq_del_bfqq_in_groups_with_pending_reqs(bfqq);
+ bfq_weights_tree_remove(bfqq);
}
now_ns = ktime_get_ns();
@@ -6784,6 +6719,12 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
bfqq = bfq_get_bfqq_handle_split(bfqd, bic, bio,
true, is_sync,
NULL);
+ if (unlikely(bfqq == &bfqd->oom_bfqq))
+ bfqq_already_existing = true;
+ } else
+ bfqq_already_existing = true;
+
+ if (!bfqq_already_existing) {
bfqq->waker_bfqq = old_bfqq->waker_bfqq;
bfqq->tentative_waker_bfqq = NULL;
@@ -6797,8 +6738,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
if (bfqq->waker_bfqq)
hlist_add_head(&bfqq->woken_list_node,
&bfqq->waker_bfqq->woken_list);
- } else
- bfqq_already_existing = true;
+ }
}
}
@@ -7045,6 +6985,7 @@ static void bfq_exit_queue(struct elevator_queue *e)
#endif
blk_stat_disable_accounting(bfqd->queue);
+ clear_bit(ELEVATOR_FLAG_DISABLE_WBT, &e->flags);
wbt_enable_default(bfqd->queue);
kfree(bfqd);
@@ -7190,6 +7131,7 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_type *e)
/* We dispatch from request queue wide instead of hw queue */
blk_queue_flag_set(QUEUE_FLAG_SQ_SCHED, q);
+ set_bit(ELEVATOR_FLAG_DISABLE_WBT, &eq->flags);
wbt_disable_default(q);
blk_stat_enable_accounting(q);
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h
index 71f721670ab6..9fa89577322d 100644
--- a/block/bfq-iosched.h
+++ b/block/bfq-iosched.h
@@ -492,27 +492,27 @@ struct bfq_data {
struct rb_root_cached queue_weights_tree;
/*
- * Number of groups with at least one descendant process that
+ * Number of groups with at least one process that
* has at least one request waiting for completion. Note that
* this accounts for also requests already dispatched, but not
* yet completed. Therefore this number of groups may differ
* (be larger) than the number of active groups, as a group is
* considered active only if its corresponding entity has
- * descendant queues with at least one request queued. This
+ * queues with at least one request queued. This
* number is used to decide whether a scenario is symmetric.
* For a detailed explanation see comments on the computation
* of the variable asymmetric_scenario in the function
* bfq_better_to_idle().
*
* However, it is hard to compute this number exactly, for
- * groups with multiple descendant processes. Consider a group
- * that is inactive, i.e., that has no descendant process with
+ * groups with multiple processes. Consider a group
+ * that is inactive, i.e., that has no process with
* pending I/O inside BFQ queues. Then suppose that
* num_groups_with_pending_reqs is still accounting for this
- * group, because the group has descendant processes with some
+ * group, because the group has processes with some
* I/O request still in flight. num_groups_with_pending_reqs
* should be decremented when the in-flight request of the
- * last descendant process is finally completed (assuming that
+ * last process is finally completed (assuming that
* nothing else has changed for the group in the meantime, in
* terms of composition of the group and active/inactive state of child
* groups and processes). To accomplish this, an additional
@@ -521,7 +521,7 @@ struct bfq_data {
* we resort to the following tradeoff between simplicity and
* accuracy: for an inactive group that is still counted in
* num_groups_with_pending_reqs, we decrement
- * num_groups_with_pending_reqs when the first descendant
+ * num_groups_with_pending_reqs when the first
* process of the group remains with no request waiting for
* completion.
*
@@ -529,12 +529,12 @@ struct bfq_data {
* carefulness: to avoid multiple decrements, we flag a group,
* more precisely an entity representing a group, as still
* counted in num_groups_with_pending_reqs when it becomes
- * inactive. Then, when the first descendant queue of the
+ * inactive. Then, when the first queue of the
* entity remains with no request waiting for completion,
* num_groups_with_pending_reqs is decremented, and this flag
* is reset. After this flag is reset for the entity,
* num_groups_with_pending_reqs won't be decremented any
- * longer in case a new descendant queue of the entity remains
+ * longer in case a new queue of the entity remains
* with no request waiting for completion.
*/
unsigned int num_groups_with_pending_reqs;
@@ -931,7 +931,7 @@ struct bfq_group {
struct bfq_entity entity;
struct bfq_sched_data sched_data;
- void *bfqd;
+ struct bfq_data *bfqd;
struct bfq_queue *async_bfqq[2][IOPRIO_NR_LEVELS];
struct bfq_queue *async_idle_bfqq;
@@ -939,6 +939,7 @@ struct bfq_group {
struct bfq_entity *my_entity;
int active_entities;
+ int num_queues_with_pending_reqs;
struct rb_root rq_pos_tree;
@@ -968,13 +969,8 @@ struct bfq_queue *bic_to_bfqq(struct bfq_io_cq *bic, bool is_sync);
void bic_set_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq, bool is_sync);
struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic);
void bfq_pos_tree_add_move(struct bfq_data *bfqd, struct bfq_queue *bfqq);
-void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq,
- struct rb_root_cached *root);
-void __bfq_weights_tree_remove(struct bfq_data *bfqd,
- struct bfq_queue *bfqq,
- struct rb_root_cached *root);
-void bfq_weights_tree_remove(struct bfq_data *bfqd,
- struct bfq_queue *bfqq);
+void bfq_weights_tree_add(struct bfq_queue *bfqq);
+void bfq_weights_tree_remove(struct bfq_queue *bfqq);
void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
bool compensate, enum bfqq_expiration reason);
void bfq_put_queue(struct bfq_queue *bfqq);
@@ -1078,6 +1074,8 @@ void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
bool expiration);
void bfq_del_bfqq_busy(struct bfq_queue *bfqq, bool expiration);
void bfq_add_bfqq_busy(struct bfq_queue *bfqq);
+void bfq_add_bfqq_in_groups_with_pending_reqs(struct bfq_queue *bfqq);
+void bfq_del_bfqq_in_groups_with_pending_reqs(struct bfq_queue *bfqq);
/* --------------- end of interface of B-WF2Q+ ---------------- */
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 8fc3da4c23bb..b02b53658ed4 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -218,6 +218,24 @@ static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
return false;
}
+static void bfq_inc_active_entities(struct bfq_entity *entity)
+{
+ struct bfq_sched_data *sd = entity->sched_data;
+ struct bfq_group *bfqg = container_of(sd, struct bfq_group, sched_data);
+
+ if (bfqg != bfqg->bfqd->root_group)
+ bfqg->active_entities++;
+}
+
+static void bfq_dec_active_entities(struct bfq_entity *entity)
+{
+ struct bfq_sched_data *sd = entity->sched_data;
+ struct bfq_group *bfqg = container_of(sd, struct bfq_group, sched_data);
+
+ if (bfqg != bfqg->bfqd->root_group)
+ bfqg->active_entities--;
+}
+
#else /* CONFIG_BFQ_GROUP_IOSCHED */
static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
@@ -230,6 +248,14 @@ static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
return true;
}
+static void bfq_inc_active_entities(struct bfq_entity *entity)
+{
+}
+
+static void bfq_dec_active_entities(struct bfq_entity *entity)
+{
+}
+
#endif /* CONFIG_BFQ_GROUP_IOSCHED */
/*
@@ -456,11 +482,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
{
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
struct rb_node *node = &entity->rb_node;
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- struct bfq_sched_data *sd = NULL;
- struct bfq_group *bfqg = NULL;
- struct bfq_data *bfqd = NULL;
-#endif
bfq_insert(&st->active, entity);
@@ -471,17 +492,10 @@ static void bfq_active_insert(struct bfq_service_tree *st,
bfq_update_active_tree(node);
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- sd = entity->sched_data;
- bfqg = container_of(sd, struct bfq_group, sched_data);
- bfqd = (struct bfq_data *)bfqg->bfqd;
-#endif
if (bfqq)
list_add(&bfqq->bfqq_list, &bfqq->bfqd->active_list);
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- if (bfqg != bfqd->root_group)
- bfqg->active_entities++;
-#endif
+
+ bfq_inc_active_entities(entity);
}
/**
@@ -558,29 +572,16 @@ static void bfq_active_extract(struct bfq_service_tree *st,
{
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
struct rb_node *node;
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- struct bfq_sched_data *sd = NULL;
- struct bfq_group *bfqg = NULL;
- struct bfq_data *bfqd = NULL;
-#endif
node = bfq_find_deepest(&entity->rb_node);
bfq_extract(&st->active, entity);
if (node)
bfq_update_active_tree(node);
-
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- sd = entity->sched_data;
- bfqg = container_of(sd, struct bfq_group, sched_data);
- bfqd = (struct bfq_data *)bfqg->bfqd;
-#endif
if (bfqq)
list_del(&bfqq->bfqq_list);
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- if (bfqg != bfqd->root_group)
- bfqg->active_entities--;
-#endif
+
+ bfq_dec_active_entities(entity);
}
/**
@@ -706,22 +707,6 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
if (entity->prio_changed) {
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
unsigned int prev_weight, new_weight;
- struct bfq_data *bfqd = NULL;
- struct rb_root_cached *root;
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- struct bfq_sched_data *sd;
- struct bfq_group *bfqg;
-#endif
-
- if (bfqq)
- bfqd = bfqq->bfqd;
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- else {
- sd = entity->my_sched_data;
- bfqg = container_of(sd, struct bfq_group, sched_data);
- bfqd = (struct bfq_data *)bfqg->bfqd;
- }
-#endif
/* Matches the smp_wmb() in bfq_group_set_weight. */
smp_rmb();
@@ -770,19 +755,15 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
* queue, remove the entity from its old weight counter (if
* there is a counter associated with the entity).
*/
- if (prev_weight != new_weight && bfqq) {
- root = &bfqd->queue_weights_tree;
- __bfq_weights_tree_remove(bfqd, bfqq, root);
- }
+ if (prev_weight != new_weight && bfqq)
+ bfq_weights_tree_remove(bfqq);
entity->weight = new_weight;
/*
* Add the entity, if it is not a weight-raised queue,
* to the counter associated with its new weight.
*/
- if (prev_weight != new_weight && bfqq && bfqq->wr_coeff == 1) {
- /* If we get here, root has been initialized. */
- bfq_weights_tree_add(bfqd, bfqq, root);
- }
+ if (prev_weight != new_weight && bfqq && bfqq->wr_coeff == 1)
+ bfq_weights_tree_add(bfqq);
new_st->wsum += entity->weight;
@@ -984,19 +965,6 @@ static void __bfq_activate_entity(struct bfq_entity *entity,
entity->on_st_or_in_serv = true;
}
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
- if (!bfq_entity_to_bfqq(entity)) { /* bfq_group */
- struct bfq_group *bfqg =
- container_of(entity, struct bfq_group, entity);
- struct bfq_data *bfqd = bfqg->bfqd;
-
- if (!entity->in_groups_with_pending_reqs) {
- entity->in_groups_with_pending_reqs = true;
- bfqd->num_groups_with_pending_reqs++;
- }
- }
-#endif
-
bfq_update_fin_time_enqueue(entity, st, backshifted);
}
@@ -1082,12 +1050,12 @@ static void __bfq_requeue_entity(struct bfq_entity *entity)
}
static void __bfq_activate_requeue_entity(struct bfq_entity *entity,
- struct bfq_sched_data *sd,
bool non_blocking_wait_rq)
{
struct bfq_service_tree *st = bfq_entity_service_tree(entity);
- if (sd->in_service_entity == entity || entity->tree == &st->active)
+ if (entity->sched_data->in_service_entity == entity ||
+ entity->tree == &st->active)
/*
* in service or already queued on the active tree,
* requeue or reposition
@@ -1119,14 +1087,10 @@ static void bfq_activate_requeue_entity(struct bfq_entity *entity,
bool non_blocking_wait_rq,
bool requeue, bool expiration)
{
- struct bfq_sched_data *sd;
-
for_each_entity(entity) {
- sd = entity->sched_data;
- __bfq_activate_requeue_entity(entity, sd, non_blocking_wait_rq);
-
- if (!bfq_update_next_in_service(sd, entity, expiration) &&
- !requeue)
+ __bfq_activate_requeue_entity(entity, non_blocking_wait_rq);
+ if (!bfq_update_next_in_service(entity->sched_data, entity,
+ expiration) && !requeue)
break;
}
}
@@ -1646,6 +1610,32 @@ void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
bfqq == bfqd->in_service_queue, expiration);
}
+void bfq_add_bfqq_in_groups_with_pending_reqs(struct bfq_queue *bfqq)
+{
+ struct bfq_entity *entity = &bfqq->entity;
+
+ if (!entity->in_groups_with_pending_reqs) {
+ entity->in_groups_with_pending_reqs = true;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+ if (!(bfqq_group(bfqq)->num_queues_with_pending_reqs++))
+ bfqq->bfqd->num_groups_with_pending_reqs++;
+#endif
+ }
+}
+
+void bfq_del_bfqq_in_groups_with_pending_reqs(struct bfq_queue *bfqq)
+{
+ struct bfq_entity *entity = &bfqq->entity;
+
+ if (entity->in_groups_with_pending_reqs) {
+ entity->in_groups_with_pending_reqs = false;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+ if (!(--bfqq_group(bfqq)->num_queues_with_pending_reqs))
+ bfqq->bfqd->num_groups_with_pending_reqs--;
+#endif
+ }
+}
+
/*
* Called when the bfqq no longer has requests pending, remove it from
* the service tree. As a special case, it can be invoked during an
@@ -1668,8 +1658,14 @@ void bfq_del_bfqq_busy(struct bfq_queue *bfqq, bool expiration)
bfq_deactivate_bfqq(bfqd, bfqq, true, expiration);
- if (!bfqq->dispatched)
- bfq_weights_tree_remove(bfqd, bfqq);
+ if (!bfqq->dispatched) {
+ bfq_del_bfqq_in_groups_with_pending_reqs(bfqq);
+ /*
+ * Next function is invoked last, because it causes bfqq to be
+ * freed. DO NOT use bfqq after the next function invocation.
+ */
+ bfq_weights_tree_remove(bfqq);
+ }
}
/*
@@ -1686,10 +1682,11 @@ void bfq_add_bfqq_busy(struct bfq_queue *bfqq)
bfq_mark_bfqq_busy(bfqq);
bfqd->busy_queues[bfqq->ioprio_class - 1]++;
- if (!bfqq->dispatched)
+ if (!bfqq->dispatched) {
+ bfq_add_bfqq_in_groups_with_pending_reqs(bfqq);
if (bfqq->wr_coeff == 1)
- bfq_weights_tree_add(bfqd, bfqq,
- &bfqd->queue_weights_tree);
+ bfq_weights_tree_add(bfqq);
+ }
if (bfqq->wr_coeff > 1)
bfqd->wr_busy_queues++;
diff --git a/block/bio.c b/block/bio.c
index 57c2f327225b..5f96fcae3f75 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -25,9 +25,15 @@
#include "blk-rq-qos.h"
#include "blk-cgroup.h"
+#define ALLOC_CACHE_THRESHOLD 16
+#define ALLOC_CACHE_SLACK 64
+#define ALLOC_CACHE_MAX 256
+
struct bio_alloc_cache {
struct bio *free_list;
+ struct bio *free_list_irq;
unsigned int nr;
+ unsigned int nr_irq;
};
static struct biovec_slab {
@@ -408,6 +414,22 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
queue_work(bs->rescue_workqueue, &bs->rescue_work);
}
+static void bio_alloc_irq_cache_splice(struct bio_alloc_cache *cache)
+{
+ unsigned long flags;
+
+ /* cache->free_list must be empty */
+ if (WARN_ON_ONCE(cache->free_list))
+ return;
+
+ local_irq_save(flags);
+ cache->free_list = cache->free_list_irq;
+ cache->free_list_irq = NULL;
+ cache->nr += cache->nr_irq;
+ cache->nr_irq = 0;
+ local_irq_restore(flags);
+}
+
static struct bio *bio_alloc_percpu_cache(struct block_device *bdev,
unsigned short nr_vecs, blk_opf_t opf, gfp_t gfp,
struct bio_set *bs)
@@ -417,8 +439,12 @@ static struct bio *bio_alloc_percpu_cache(struct block_device *bdev,
cache = per_cpu_ptr(bs->cache, get_cpu());
if (!cache->free_list) {
- put_cpu();
- return NULL;
+ if (READ_ONCE(cache->nr_irq) >= ALLOC_CACHE_THRESHOLD)
+ bio_alloc_irq_cache_splice(cache);
+ if (!cache->free_list) {
+ put_cpu();
+ return NULL;
+ }
}
bio = cache->free_list;
cache->free_list = bio->bi_next;
@@ -462,9 +488,6 @@ static struct bio *bio_alloc_percpu_cache(struct block_device *bdev,
* submit_bio_noacct() should be avoided - instead, use bio_set's front_pad
* for per bio allocations.
*
- * If REQ_ALLOC_CACHE is set, the final put of the bio MUST be done from process
- * context, not hard/soft IRQ.
- *
* Returns: Pointer to new bio on success, NULL on failure.
*/
struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
@@ -526,6 +549,8 @@ struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
}
if (unlikely(!p))
return NULL;
+ if (!mempool_is_saturated(&bs->bio_pool))
+ opf &= ~REQ_ALLOC_CACHE;
bio = p + bs->front_pad;
if (nr_vecs > BIO_INLINE_VECS) {
@@ -676,11 +701,8 @@ void guard_bio_eod(struct bio *bio)
bio_truncate(bio, maxsector << 9);
}
-#define ALLOC_CACHE_MAX 512
-#define ALLOC_CACHE_SLACK 64
-
-static void bio_alloc_cache_prune(struct bio_alloc_cache *cache,
- unsigned int nr)
+static int __bio_alloc_cache_prune(struct bio_alloc_cache *cache,
+ unsigned int nr)
{
unsigned int i = 0;
struct bio *bio;
@@ -692,6 +714,17 @@ static void bio_alloc_cache_prune(struct bio_alloc_cache *cache,
if (++i == nr)
break;
}
+ return i;
+}
+
+static void bio_alloc_cache_prune(struct bio_alloc_cache *cache,
+ unsigned int nr)
+{
+ nr -= __bio_alloc_cache_prune(cache, nr);
+ if (!READ_ONCE(cache->free_list)) {
+ bio_alloc_irq_cache_splice(cache);
+ __bio_alloc_cache_prune(cache, nr);
+ }
}
static int bio_cpu_dead(unsigned int cpu, struct hlist_node *node)
@@ -725,6 +758,35 @@ static void bio_alloc_cache_destroy(struct bio_set *bs)
bs->cache = NULL;
}
+static inline void bio_put_percpu_cache(struct bio *bio)
+{
+ struct bio_alloc_cache *cache;
+
+ cache = per_cpu_ptr(bio->bi_pool->cache, get_cpu());
+ if (READ_ONCE(cache->nr_irq) + cache->nr > ALLOC_CACHE_MAX) {
+ put_cpu();
+ bio_free(bio);
+ return;
+ }
+
+ bio_uninit(bio);
+
+ if ((bio->bi_opf & REQ_POLLED) && !WARN_ON_ONCE(in_interrupt())) {
+ bio->bi_next = cache->free_list;
+ cache->free_list = bio;
+ cache->nr++;
+ } else {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ bio->bi_next = cache->free_list_irq;
+ cache->free_list_irq = bio;
+ cache->nr_irq++;
+ local_irq_restore(flags);
+ }
+ put_cpu();
+}
+
/**
* bio_put - release a reference to a bio
* @bio: bio to release reference to
@@ -740,20 +802,10 @@ void bio_put(struct bio *bio)
if (!atomic_dec_and_test(&bio->__bi_cnt))
return;
}
-
- if ((bio->bi_opf & REQ_ALLOC_CACHE) && !WARN_ON_ONCE(in_interrupt())) {
- struct bio_alloc_cache *cache;
-
- bio_uninit(bio);
- cache = per_cpu_ptr(bio->bi_pool->cache, get_cpu());
- bio->bi_next = cache->free_list;
- cache->free_list = bio;
- if (++cache->nr > ALLOC_CACHE_MAX + ALLOC_CACHE_SLACK)
- bio_alloc_cache_prune(cache, ALLOC_CACHE_SLACK);
- put_cpu();
- } else {
+ if (bio->bi_opf & REQ_ALLOC_CACHE)
+ bio_put_percpu_cache(bio);
+ else
bio_free(bio);
- }
}
EXPORT_SYMBOL(bio_put);
@@ -863,6 +915,8 @@ static inline bool page_is_mergeable(const struct bio_vec *bv,
return false;
if (xen_domain() && !xen_biovec_phys_mergeable(bv, page))
return false;
+ if (!zone_device_pages_have_same_pgmap(bv->bv_page, page))
+ return false;
*same_page = ((vec_end_addr & PAGE_MASK) == page_addr);
if (*same_page)
@@ -1195,6 +1249,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
struct page **pages = (struct page **)bv;
+ unsigned int gup_flags = 0;
ssize_t size, left;
unsigned len, i = 0;
size_t offset, trim;
@@ -1208,6 +1263,9 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);
+ if (bio->bi_bdev && blk_queue_pci_p2pdma(bio->bi_bdev->bd_disk->queue))
+ gup_flags |= FOLL_PCI_P2PDMA;
+
/*
* Each segment in the iov is required to be a block size multiple.
* However, we may not be able to get the entire segment if it spans
@@ -1215,8 +1273,9 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
* result to ensure the bio's total size is correct. The remainder of
* the iov data will be picked up in the next bio iteration.
*/
- size = iov_iter_get_pages2(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
- nr_pages, &offset);
+ size = iov_iter_get_pages(iter, pages,
+ UINT_MAX - bio->bi_iter.bi_size,
+ nr_pages, &offset, gup_flags);
if (unlikely(size <= 0))
return size ? size : -EFAULT;
@@ -1342,27 +1401,6 @@ void __bio_advance(struct bio *bio, unsigned bytes)
}
EXPORT_SYMBOL(__bio_advance);
-void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
- struct bio *src, struct bvec_iter *src_iter)
-{
- while (src_iter->bi_size && dst_iter->bi_size) {
- struct bio_vec src_bv = bio_iter_iovec(src, *src_iter);
- struct bio_vec dst_bv = bio_iter_iovec(dst, *dst_iter);
- unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len);
- void *src_buf = bvec_kmap_local(&src_bv);
- void *dst_buf = bvec_kmap_local(&dst_bv);
-
- memcpy(dst_buf, src_buf, bytes);
-
- kunmap_local(dst_buf);
- kunmap_local(src_buf);
-
- bio_advance_iter_single(src, src_iter, bytes);
- bio_advance_iter_single(dst, dst_iter, bytes);
- }
-}
-EXPORT_SYMBOL(bio_copy_data_iter);
-
/**
* bio_copy_data - copy contents of data buffers from one bio to another
* @src: source bio
@@ -1376,7 +1414,21 @@ void bio_copy_data(struct bio *dst, struct bio *src)
struct bvec_iter src_iter = src->bi_iter;
struct bvec_iter dst_iter = dst->bi_iter;
- bio_copy_data_iter(dst, &dst_iter, src, &src_iter);
+ while (src_iter.bi_size && dst_iter.bi_size) {
+ struct bio_vec src_bv = bio_iter_iovec(src, src_iter);
+ struct bio_vec dst_bv = bio_iter_iovec(dst, dst_iter);
+ unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len);
+ void *src_buf = bvec_kmap_local(&src_bv);
+ void *dst_buf = bvec_kmap_local(&dst_bv);
+
+ memcpy(dst_buf, src_buf, bytes);
+
+ kunmap_local(dst_buf);
+ kunmap_local(src_buf);
+
+ bio_advance_iter_single(src, &src_iter, bytes);
+ bio_advance_iter_single(dst, &dst_iter, bytes);
+ }
}
EXPORT_SYMBOL(bio_copy_data);
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 6a5c849ee061..50ac0dce95b8 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -59,6 +59,37 @@ static struct workqueue_struct *blkcg_punt_bio_wq;
#define BLKG_DESTROY_BATCH_SIZE 64
+/*
+ * Lockless lists for tracking IO stats update
+ *
+ * New IO stats are stored in the percpu iostat_cpu within blkcg_gq (blkg).
+ * There are multiple blkg's (one for each block device) attached to each
+ * blkcg. The rstat code keeps track of which cpu has IO stats updated,
+ * but it doesn't know which blkg has the updated stats. If there are many
+ * block devices in a system, the cost of iterating all the blkg's to flush
+ * out the IO stats can be high. To reduce such overhead, a set of percpu
+ * lockless lists (lhead) per blkcg are used to track the set of recently
+ * updated iostat_cpu's since the last flush. An iostat_cpu will be put
+ * onto the lockless list on the update side [blk_cgroup_bio_start()] if
+ * not there yet and then removed when being flushed [blkcg_rstat_flush()].
+ * References to blkg are gotten and then put back in the process to
+ * protect against blkg removal.
+ *
+ * Return: 0 if successful or -ENOMEM if allocation fails.
+ */
+static int init_blkcg_llists(struct blkcg *blkcg)
+{
+ int cpu;
+
+ blkcg->lhead = alloc_percpu_gfp(struct llist_head, GFP_KERNEL);
+ if (!blkcg->lhead)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu)
+ init_llist_head(per_cpu_ptr(blkcg->lhead, cpu));
+ return 0;
+}
+
/**
* blkcg_css - find the current css
*
@@ -236,8 +267,10 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk,
blkg->blkcg = blkcg;
u64_stats_init(&blkg->iostat.sync);
- for_each_possible_cpu(cpu)
+ for_each_possible_cpu(cpu) {
u64_stats_init(&per_cpu_ptr(blkg->iostat_cpu, cpu)->sync);
+ per_cpu_ptr(blkg->iostat_cpu, cpu)->blkg = blkg;
+ }
for (i = 0; i < BLKCG_MAX_POLS; i++) {
struct blkcg_policy *pol = blkcg_policy[i];
@@ -577,7 +610,7 @@ EXPORT_SYMBOL_GPL(blkcg_print_blkgs);
* @pd: policy private data of interest
* @v: value to print
*
- * Print @v to @sf for the device assocaited with @pd.
+ * Print @v to @sf for the device associated with @pd.
*/
u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v)
{
@@ -765,7 +798,7 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep);
/**
* blkg_conf_finish - finish up per-blkg config update
- * @ctx: blkg_conf_ctx intiailized by blkg_conf_prep()
+ * @ctx: blkg_conf_ctx initialized by blkg_conf_prep()
*
* Finish up after per-blkg config update. This function must be paired
* with blkg_conf_prep().
@@ -827,7 +860,9 @@ static void blkcg_iostat_update(struct blkcg_gq *blkg, struct blkg_iostat *cur,
static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
{
struct blkcg *blkcg = css_to_blkcg(css);
- struct blkcg_gq *blkg;
+ struct llist_head *lhead = per_cpu_ptr(blkcg->lhead, cpu);
+ struct llist_node *lnode;
+ struct blkg_iostat_set *bisc, *next_bisc;
/* Root-level stats are sourced from system-wide IO stats */
if (!cgroup_parent(css->cgroup))
@@ -835,12 +870,21 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
rcu_read_lock();
- hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
+ lnode = llist_del_all(lhead);
+ if (!lnode)
+ goto out;
+
+ /*
+ * Iterate only the iostat_cpu's queued in the lockless list.
+ */
+ llist_for_each_entry_safe(bisc, next_bisc, lnode, lnode) {
+ struct blkcg_gq *blkg = bisc->blkg;
struct blkcg_gq *parent = blkg->parent;
- struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu);
struct blkg_iostat cur;
unsigned int seq;
+ WRITE_ONCE(bisc->lqueued, false);
+
/* fetch the current per-cpu values */
do {
seq = u64_stats_fetch_begin(&bisc->sync);
@@ -853,8 +897,10 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
if (parent && parent->parent)
blkcg_iostat_update(parent, &blkg->iostat.cur,
&blkg->iostat.last);
+ percpu_ref_put(&blkg->refcnt);
}
+out:
rcu_read_unlock();
}
@@ -1132,6 +1178,7 @@ static void blkcg_css_free(struct cgroup_subsys_state *css)
mutex_unlock(&blkcg_pol_mutex);
+ free_percpu(blkcg->lhead);
kfree(blkcg);
}
@@ -1139,7 +1186,6 @@ static struct cgroup_subsys_state *
blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
{
struct blkcg *blkcg;
- struct cgroup_subsys_state *ret;
int i;
mutex_lock(&blkcg_pol_mutex);
@@ -1148,12 +1194,13 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
blkcg = &blkcg_root;
} else {
blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
- if (!blkcg) {
- ret = ERR_PTR(-ENOMEM);
+ if (!blkcg)
goto unlock;
- }
}
+ if (init_blkcg_llists(blkcg))
+ goto free_blkcg;
+
for (i = 0; i < BLKCG_MAX_POLS ; i++) {
struct blkcg_policy *pol = blkcg_policy[i];
struct blkcg_policy_data *cpd;
@@ -1168,10 +1215,9 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
continue;
cpd = pol->cpd_alloc_fn(GFP_KERNEL);
- if (!cpd) {
- ret = ERR_PTR(-ENOMEM);
+ if (!cpd)
goto free_pd_blkcg;
- }
+
blkcg->cpd[i] = cpd;
cpd->blkcg = blkcg;
cpd->plid = i;
@@ -1195,12 +1241,13 @@ free_pd_blkcg:
for (i--; i >= 0; i--)
if (blkcg->cpd[i])
blkcg_policy[i]->cpd_free_fn(blkcg->cpd[i]);
-
+ free_percpu(blkcg->lhead);
+free_blkcg:
if (blkcg != &blkcg_root)
kfree(blkcg);
unlock:
mutex_unlock(&blkcg_pol_mutex);
- return ret;
+ return ERR_PTR(-ENOMEM);
}
static int blkcg_css_online(struct cgroup_subsys_state *css)
@@ -1213,7 +1260,7 @@ static int blkcg_css_online(struct cgroup_subsys_state *css)
* parent so that offline always happens towards the root.
*/
if (parent)
- blkcg_pin_online(css);
+ blkcg_pin_online(&parent->css);
return 0;
}
@@ -1784,7 +1831,7 @@ out:
/**
* blkcg_schedule_throttle - this task needs to check for throttling
- * @gendisk: disk to throttle
+ * @disk: disk to throttle
* @use_memdelay: do we charge this to memory delay for PSI
*
* This is called by the IO controller when we know there's delay accumulated
@@ -1943,6 +1990,7 @@ static int blk_cgroup_io_type(struct bio *bio)
void blk_cgroup_bio_start(struct bio *bio)
{
+ struct blkcg *blkcg = bio->bi_blkg->blkcg;
int rwd = blk_cgroup_io_type(bio), cpu;
struct blkg_iostat_set *bis;
unsigned long flags;
@@ -1961,9 +2009,21 @@ void blk_cgroup_bio_start(struct bio *bio)
}
bis->cur.ios[rwd]++;
+ /*
+ * If the iostat_cpu isn't in a lockless list, put it into the
+ * list to indicate that a stat update is pending.
+ */
+ if (!READ_ONCE(bis->lqueued)) {
+ struct llist_head *lhead = this_cpu_ptr(blkcg->lhead);
+
+ llist_add(&bis->lnode, lhead);
+ WRITE_ONCE(bis->lqueued, true);
+ percpu_ref_get(&bis->blkg->refcnt);
+ }
+
u64_stats_update_end_irqrestore(&bis->sync, flags);
if (cgroup_subsys_on_dfl(io_cgrp_subsys))
- cgroup_rstat_updated(bio->bi_blkg->blkcg->css.cgroup, cpu);
+ cgroup_rstat_updated(blkcg->css.cgroup, cpu);
put_cpu();
}
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index aa2b286bc825..1e94e404eaa8 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -18,6 +18,7 @@
#include <linux/cgroup.h>
#include <linux/kthread.h>
#include <linux/blk-mq.h>
+#include <linux/llist.h>
struct blkcg_gq;
struct blkg_policy_data;
@@ -43,6 +44,9 @@ struct blkg_iostat {
struct blkg_iostat_set {
struct u64_stats_sync sync;
+ struct blkcg_gq *blkg;
+ struct llist_node lnode;
+ int lqueued; /* queued in llist */
struct blkg_iostat cur;
struct blkg_iostat last;
};
@@ -97,6 +101,12 @@ struct blkcg {
struct blkcg_policy_data *cpd[BLKCG_MAX_POLS];
struct list_head all_blkcgs_node;
+
+ /*
+ * List of updated percpu blkg_iostat_set's since the last flush.
+ */
+ struct llist_head __percpu *lhead;
+
#ifdef CONFIG_BLK_CGROUP_FC_APPID
char fc_app_id[FC_APPID_LEN];
#endif
diff --git a/block/blk-core.c b/block/blk-core.c
index 17667159482e..3866b6c4cd88 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -59,13 +59,12 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_split);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_insert);
-DEFINE_IDA(blk_queue_ida);
+static DEFINE_IDA(blk_queue_ida);
/*
* For queue allocation
*/
-struct kmem_cache *blk_requestq_cachep;
-struct kmem_cache *blk_requestq_srcu_cachep;
+static struct kmem_cache *blk_requestq_cachep;
/*
* Controlling structure to kblockd
@@ -253,19 +252,44 @@ void blk_clear_pm_only(struct request_queue *q)
}
EXPORT_SYMBOL_GPL(blk_clear_pm_only);
+static void blk_free_queue_rcu(struct rcu_head *rcu_head)
+{
+ kmem_cache_free(blk_requestq_cachep,
+ container_of(rcu_head, struct request_queue, rcu_head));
+}
+
+static void blk_free_queue(struct request_queue *q)
+{
+ percpu_ref_exit(&q->q_usage_counter);
+
+ if (q->poll_stat)
+ blk_stat_remove_callback(q, q->poll_cb);
+ blk_stat_free_callback(q->poll_cb);
+
+ blk_free_queue_stats(q->stats);
+ kfree(q->poll_stat);
+
+ if (queue_is_mq(q))
+ blk_mq_release(q);
+
+ ida_free(&blk_queue_ida, q->id);
+ call_rcu(&q->rcu_head, blk_free_queue_rcu);
+}
+
/**
* blk_put_queue - decrement the request_queue refcount
* @q: the request_queue structure to decrement the refcount for
*
- * Decrements the refcount of the request_queue kobject. When this reaches 0
- * we'll have blk_release_queue() called.
+ * Decrements the refcount of the request_queue and free it when the refcount
+ * reaches 0.
*
- * Context: Any context, but the last reference must not be dropped from
- * atomic context.
+ * Context: Can sleep.
*/
void blk_put_queue(struct request_queue *q)
{
- kobject_put(&q->kobj);
+ might_sleep();
+ if (refcount_dec_and_test(&q->refs))
+ blk_free_queue(q);
}
EXPORT_SYMBOL(blk_put_queue);
@@ -373,26 +397,20 @@ static void blk_timeout_work(struct work_struct *work)
{
}
-struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu)
+struct request_queue *blk_alloc_queue(int node_id)
{
struct request_queue *q;
- q = kmem_cache_alloc_node(blk_get_queue_kmem_cache(alloc_srcu),
- GFP_KERNEL | __GFP_ZERO, node_id);
+ q = kmem_cache_alloc_node(blk_requestq_cachep, GFP_KERNEL | __GFP_ZERO,
+ node_id);
if (!q)
return NULL;
- if (alloc_srcu) {
- blk_queue_flag_set(QUEUE_FLAG_HAS_SRCU, q);
- if (init_srcu_struct(q->srcu) != 0)
- goto fail_q;
- }
-
q->last_merge = NULL;
q->id = ida_alloc(&blk_queue_ida, GFP_KERNEL);
if (q->id < 0)
- goto fail_srcu;
+ goto fail_q;
q->stats = blk_alloc_queue_stats();
if (!q->stats)
@@ -406,8 +424,7 @@ struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu)
INIT_WORK(&q->timeout_work, blk_timeout_work);
INIT_LIST_HEAD(&q->icq_list);
- kobject_init(&q->kobj, &blk_queue_ktype);
-
+ refcount_set(&q->refs, 1);
mutex_init(&q->debugfs_mutex);
mutex_init(&q->sysfs_lock);
mutex_init(&q->sysfs_dir_lock);
@@ -425,7 +442,6 @@ struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu)
PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
goto fail_stats;
- blk_queue_dma_alignment(q, 511);
blk_set_default_limits(&q->limits);
q->nr_requests = BLKDEV_DEFAULT_RQ;
@@ -435,11 +451,8 @@ fail_stats:
blk_free_queue_stats(q->stats);
fail_id:
ida_free(&blk_queue_ida, q->id);
-fail_srcu:
- if (alloc_srcu)
- cleanup_srcu_struct(q->srcu);
fail_q:
- kmem_cache_free(blk_get_queue_kmem_cache(alloc_srcu), q);
+ kmem_cache_free(blk_requestq_cachep, q);
return NULL;
}
@@ -455,7 +468,7 @@ bool blk_get_queue(struct request_queue *q)
{
if (unlikely(blk_queue_dying(q)))
return false;
- kobject_get(&q->kobj);
+ refcount_inc(&q->refs);
return true;
}
EXPORT_SYMBOL(blk_get_queue);
@@ -946,18 +959,6 @@ unsigned long bdev_start_io_acct(struct block_device *bdev,
EXPORT_SYMBOL(bdev_start_io_acct);
/**
- * bio_start_io_acct_time - start I/O accounting for bio based drivers
- * @bio: bio to start account for
- * @start_time: start time that should be passed back to bio_end_io_acct().
- */
-void bio_start_io_acct_time(struct bio *bio, unsigned long start_time)
-{
- bdev_start_io_acct(bio->bi_bdev, bio_sectors(bio),
- bio_op(bio), start_time);
-}
-EXPORT_SYMBOL_GPL(bio_start_io_acct_time);
-
-/**
* bio_start_io_acct - start I/O accounting for bio based drivers
* @bio: bio to start account for
*
@@ -1184,9 +1185,6 @@ int __init blk_dev_init(void)
sizeof_field(struct request, cmd_flags));
BUILD_BUG_ON(REQ_OP_BITS + REQ_FLAG_BITS > 8 *
sizeof_field(struct bio, bi_opf));
- BUILD_BUG_ON(ALIGN(offsetof(struct request_queue, srcu),
- __alignof__(struct request_queue)) !=
- sizeof(struct request_queue));
/* used for unplugging and affects IO latency/throughput - HIGHPRI */
kblockd_workqueue = alloc_workqueue("kblockd",
@@ -1197,10 +1195,6 @@ int __init blk_dev_init(void)
blk_requestq_cachep = kmem_cache_create("request_queue",
sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
- blk_requestq_srcu_cachep = kmem_cache_create("request_queue_srcu",
- sizeof(struct request_queue) +
- sizeof(struct srcu_struct), 0, SLAB_PANIC, NULL);
-
blk_debugfs_root = debugfs_create_dir("block", NULL);
return 0;
diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h
index e6818ffaddbf..a8cdaf26851e 100644
--- a/block/blk-crypto-internal.h
+++ b/block/blk-crypto-internal.h
@@ -21,9 +21,9 @@ extern const struct blk_crypto_mode blk_crypto_modes[];
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
-int blk_crypto_sysfs_register(struct request_queue *q);
+int blk_crypto_sysfs_register(struct gendisk *disk);
-void blk_crypto_sysfs_unregister(struct request_queue *q);
+void blk_crypto_sysfs_unregister(struct gendisk *disk);
void bio_crypt_dun_increment(u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
unsigned int inc);
@@ -65,14 +65,28 @@ static inline bool blk_crypto_rq_is_encrypted(struct request *rq)
return rq->crypt_ctx;
}
+blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile,
+ const struct blk_crypto_key *key,
+ struct blk_crypto_keyslot **slot_ptr);
+
+void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot);
+
+int __blk_crypto_evict_key(struct blk_crypto_profile *profile,
+ const struct blk_crypto_key *key);
+
+bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,
+ const struct blk_crypto_config *cfg);
+
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
-static inline int blk_crypto_sysfs_register(struct request_queue *q)
+static inline int blk_crypto_sysfs_register(struct gendisk *disk)
{
return 0;
}
-static inline void blk_crypto_sysfs_unregister(struct request_queue *q) { }
+static inline void blk_crypto_sysfs_unregister(struct gendisk *disk)
+{
+}
static inline bool bio_crypt_rq_ctx_compatible(struct request *rq,
struct bio *bio)
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 96c511967386..0307fb0d95d3 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -32,6 +32,7 @@
#include <linux/wait.h>
#include <linux/blkdev.h>
#include <linux/blk-integrity.h>
+#include "blk-crypto-internal.h"
struct blk_crypto_keyslot {
atomic_t slot_refs;
diff --git a/block/blk-crypto-sysfs.c b/block/blk-crypto-sysfs.c
index fd93bd2f33b7..55268edc0625 100644
--- a/block/blk-crypto-sysfs.c
+++ b/block/blk-crypto-sysfs.c
@@ -126,8 +126,9 @@ static struct kobj_type blk_crypto_ktype = {
* If the request_queue has a blk_crypto_profile, create the "crypto"
* subdirectory in sysfs (/sys/block/$disk/queue/crypto/).
*/
-int blk_crypto_sysfs_register(struct request_queue *q)
+int blk_crypto_sysfs_register(struct gendisk *disk)
{
+ struct request_queue *q = disk->queue;
struct blk_crypto_kobj *obj;
int err;
@@ -139,8 +140,8 @@ int blk_crypto_sysfs_register(struct request_queue *q)
return -ENOMEM;
obj->profile = q->crypto_profile;
- err = kobject_init_and_add(&obj->kobj, &blk_crypto_ktype, &q->kobj,
- "crypto");
+ err = kobject_init_and_add(&obj->kobj, &blk_crypto_ktype,
+ &disk->queue_kobj, "crypto");
if (err) {
kobject_put(&obj->kobj);
return err;
@@ -149,9 +150,9 @@ int blk_crypto_sysfs_register(struct request_queue *q)
return 0;
}
-void blk_crypto_sysfs_unregister(struct request_queue *q)
+void blk_crypto_sysfs_unregister(struct gendisk *disk)
{
- kobject_put(q->crypto_kobject);
+ kobject_put(disk->queue->crypto_kobject);
}
static int __init blk_crypto_sysfs_init(void)
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index a496aaef85ba..45378586151f 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -36,6 +36,12 @@ const struct blk_crypto_mode blk_crypto_modes[] = {
.keysize = 32,
.ivsize = 32,
},
+ [BLK_ENCRYPTION_MODE_SM4_XTS] = {
+ .name = "SM4-XTS",
+ .cipher_str = "xts(sm4)",
+ .keysize = 32,
+ .ivsize = 16,
+ },
};
/*
@@ -267,7 +273,6 @@ bool __blk_crypto_bio_prep(struct bio **bio_ptr)
{
struct bio *bio = *bio_ptr;
const struct blk_crypto_key *bc_key = bio->bi_crypt_context->bc_key;
- struct blk_crypto_profile *profile;
/* Error if bio has no data. */
if (WARN_ON_ONCE(!bio_has_data(bio))) {
@@ -284,10 +289,9 @@ bool __blk_crypto_bio_prep(struct bio **bio_ptr)
* Success if device supports the encryption context, or if we succeeded
* in falling back to the crypto API.
*/
- profile = bdev_get_queue(bio->bi_bdev)->crypto_profile;
- if (__blk_crypto_cfg_supported(profile, &bc_key->crypto_cfg))
+ if (blk_crypto_config_supported_natively(bio->bi_bdev,
+ &bc_key->crypto_cfg))
return true;
-
if (blk_crypto_fallback_bio_prep(bio_ptr))
return true;
fail:
@@ -352,22 +356,29 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key, const u8 *raw_key,
return 0;
}
+bool blk_crypto_config_supported_natively(struct block_device *bdev,
+ const struct blk_crypto_config *cfg)
+{
+ return __blk_crypto_cfg_supported(bdev_get_queue(bdev)->crypto_profile,
+ cfg);
+}
+
/*
* Check if bios with @cfg can be en/decrypted by blk-crypto (i.e. either the
- * request queue it's submitted to supports inline crypto, or the
+ * block_device it's submitted to supports inline crypto, or the
* blk-crypto-fallback is enabled and supports the cfg).
*/
-bool blk_crypto_config_supported(struct request_queue *q,
+bool blk_crypto_config_supported(struct block_device *bdev,
const struct blk_crypto_config *cfg)
{
return IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) ||
- __blk_crypto_cfg_supported(q->crypto_profile, cfg);
+ blk_crypto_config_supported_natively(bdev, cfg);
}
/**
* blk_crypto_start_using_key() - Start using a blk_crypto_key on a device
+ * @bdev: block device to operate on
* @key: A key to use on the device
- * @q: the request queue for the device
*
* Upper layers must call this function to ensure that either the hardware
* supports the key's crypto settings, or the crypto API fallback has transforms
@@ -379,10 +390,10 @@ bool blk_crypto_config_supported(struct request_queue *q,
* blk-crypto-fallback is either disabled or the needed algorithm
* is disabled in the crypto API; or another -errno code.
*/
-int blk_crypto_start_using_key(const struct blk_crypto_key *key,
- struct request_queue *q)
+int blk_crypto_start_using_key(struct block_device *bdev,
+ const struct blk_crypto_key *key)
{
- if (__blk_crypto_cfg_supported(q->crypto_profile, &key->crypto_cfg))
+ if (blk_crypto_config_supported_natively(bdev, &key->crypto_cfg))
return 0;
return blk_crypto_fallback_start_using_mode(key->crypto_cfg.crypto_mode);
}
@@ -390,7 +401,7 @@ int blk_crypto_start_using_key(const struct blk_crypto_key *key,
/**
* blk_crypto_evict_key() - Evict a key from any inline encryption hardware
* it may have been programmed into
- * @q: The request queue who's associated inline encryption hardware this key
+ * @bdev: The block_device who's associated inline encryption hardware this key
* might have been programmed into
* @key: The key to evict
*
@@ -400,14 +411,16 @@ int blk_crypto_start_using_key(const struct blk_crypto_key *key,
*
* Return: 0 on success or if the key wasn't in any keyslot; -errno on error.
*/
-int blk_crypto_evict_key(struct request_queue *q,
+int blk_crypto_evict_key(struct block_device *bdev,
const struct blk_crypto_key *key)
{
- if (__blk_crypto_cfg_supported(q->crypto_profile, &key->crypto_cfg))
+ struct request_queue *q = bdev_get_queue(bdev);
+
+ if (blk_crypto_config_supported_natively(bdev, &key->crypto_cfg))
return __blk_crypto_evict_key(q->crypto_profile, key);
/*
- * If the request_queue didn't support the key, then blk-crypto-fallback
+ * If the block_device didn't support the key, then blk-crypto-fallback
* may have been used, so try to evict the key from blk-crypto-fallback.
*/
return blk_crypto_fallback_evict_key(key);
diff --git a/block/blk-ia-ranges.c b/block/blk-ia-ranges.c
index 2bd1d311033b..2141931ddd37 100644
--- a/block/blk-ia-ranges.c
+++ b/block/blk-ia-ranges.c
@@ -123,7 +123,8 @@ int disk_register_independent_access_ranges(struct gendisk *disk)
*/
WARN_ON(iars->sysfs_registered);
ret = kobject_init_and_add(&iars->kobj, &blk_ia_ranges_ktype,
- &q->kobj, "%s", "independent_access_ranges");
+ &disk->queue_kobj, "%s",
+ "independent_access_ranges");
if (ret) {
disk->ia_ranges = NULL;
kobject_put(&iars->kobj);
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 495396425bad..d1bdc12deaa7 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -111,7 +111,7 @@
* busy signal.
*
* As devices can have deep queues and be unfair in how the queued commands
- * are executed, soley depending on rq wait may not result in satisfactory
+ * are executed, solely depending on rq wait may not result in satisfactory
* control quality. For a better control quality, completion latency QoS
* parameters can be configured so that the device is considered saturated
* if N'th percentile completion latency rises above the set point.
@@ -556,7 +556,6 @@ struct ioc_now {
u64 now_ns;
u64 now;
u64 vnow;
- u64 vrate;
};
struct iocg_wait {
@@ -906,8 +905,10 @@ static bool ioc_refresh_params(struct ioc *ioc, bool force)
if (idx == ioc->autop_idx && !force)
return false;
- if (idx != ioc->autop_idx)
+ if (idx != ioc->autop_idx) {
atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC);
+ ioc->vtime_base_rate = VTIME_PER_USEC;
+ }
ioc->autop_idx = idx;
ioc->autop_too_fast_at = 0;
@@ -975,7 +976,7 @@ static void ioc_adjust_base_vrate(struct ioc *ioc, u32 rq_wait_pct,
if (!ioc->busy_level || (ioc->busy_level < 0 && nr_lagging)) {
if (ioc->busy_level != prev_busy_level || nr_lagging)
- trace_iocost_ioc_vrate_adj(ioc, atomic64_read(&ioc->vtime_rate),
+ trace_iocost_ioc_vrate_adj(ioc, vrate,
missed_ppm, rq_wait_pct,
nr_lagging, nr_shortages);
@@ -1018,10 +1019,11 @@ static void ioc_adjust_base_vrate(struct ioc *ioc, u32 rq_wait_pct,
static void ioc_now(struct ioc *ioc, struct ioc_now *now)
{
unsigned seq;
+ u64 vrate;
now->now_ns = ktime_get();
now->now = ktime_to_us(now->now_ns);
- now->vrate = atomic64_read(&ioc->vtime_rate);
+ vrate = atomic64_read(&ioc->vtime_rate);
/*
* The current vtime is
@@ -1034,7 +1036,7 @@ static void ioc_now(struct ioc *ioc, struct ioc_now *now)
do {
seq = read_seqcount_begin(&ioc->period_seqcount);
now->vnow = ioc->period_at_vtime +
- (now->now - ioc->period_at) * now->vrate;
+ (now->now - ioc->period_at) * vrate;
} while (read_seqcount_retry(&ioc->period_seqcount, seq));
}
@@ -2203,8 +2205,8 @@ static void ioc_timer_fn(struct timer_list *timer)
LIST_HEAD(surpluses);
int nr_debtors, nr_shortages = 0, nr_lagging = 0;
u64 usage_us_sum = 0;
- u32 ppm_rthr = MILLION - ioc->params.qos[QOS_RPPM];
- u32 ppm_wthr = MILLION - ioc->params.qos[QOS_WPPM];
+ u32 ppm_rthr;
+ u32 ppm_wthr;
u32 missed_ppm[2], rq_wait_pct;
u64 period_vtime;
int prev_busy_level;
@@ -2215,6 +2217,8 @@ static void ioc_timer_fn(struct timer_list *timer)
/* take care of active iocgs */
spin_lock_irq(&ioc->lock);
+ ppm_rthr = MILLION - ioc->params.qos[QOS_RPPM];
+ ppm_wthr = MILLION - ioc->params.qos[QOS_WPPM];
ioc_now(ioc, &now);
period_vtime = now.vnow - ioc->period_at_vtime;
@@ -2878,7 +2882,7 @@ static int blk_iocost_init(struct gendisk *disk)
spin_unlock_irq(&ioc->lock);
/*
- * rqos must be added before activation to allow iocg_pd_init() to
+ * rqos must be added before activation to allow ioc_pd_init() to
* lookup the ioc from q. This means that the rqos methods may get
* called before policy activation completion, can't assume that the
* target bio has an iocg associated and need to test for NULL iocg.
@@ -3187,11 +3191,13 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
ioc = q_to_ioc(disk->queue);
}
+ blk_mq_freeze_queue(disk->queue);
+ blk_mq_quiesce_queue(disk->queue);
+
spin_lock_irq(&ioc->lock);
memcpy(qos, ioc->params.qos, sizeof(qos));
enable = ioc->enabled;
user = ioc->user_qos_params;
- spin_unlock_irq(&ioc->lock);
while ((p = strsep(&input, " \t\n"))) {
substring_t args[MAX_OPT_ARGS];
@@ -3258,15 +3264,15 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
if (qos[QOS_MIN] > qos[QOS_MAX])
goto einval;
- spin_lock_irq(&ioc->lock);
-
if (enable) {
blk_stat_enable_accounting(disk->queue);
blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
ioc->enabled = true;
+ wbt_disable_default(disk->queue);
} else {
blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
ioc->enabled = false;
+ wbt_enable_default(disk->queue);
}
if (user) {
@@ -3279,9 +3285,17 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
ioc_refresh_params(ioc, true);
spin_unlock_irq(&ioc->lock);
+ blk_mq_unquiesce_queue(disk->queue);
+ blk_mq_unfreeze_queue(disk->queue);
+
blkdev_put_no_open(bdev);
return nbytes;
einval:
+ spin_unlock_irq(&ioc->lock);
+
+ blk_mq_unquiesce_queue(disk->queue);
+ blk_mq_unfreeze_queue(disk->queue);
+
ret = -EINVAL;
err:
blkdev_put_no_open(bdev);
@@ -3336,6 +3350,7 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
size_t nbytes, loff_t off)
{
struct block_device *bdev;
+ struct request_queue *q;
struct ioc *ioc;
u64 u[NR_I_LCOEFS];
bool user;
@@ -3346,18 +3361,21 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
if (IS_ERR(bdev))
return PTR_ERR(bdev);
- ioc = q_to_ioc(bdev_get_queue(bdev));
+ q = bdev_get_queue(bdev);
+ ioc = q_to_ioc(q);
if (!ioc) {
ret = blk_iocost_init(bdev->bd_disk);
if (ret)
goto err;
- ioc = q_to_ioc(bdev_get_queue(bdev));
+ ioc = q_to_ioc(q);
}
+ blk_mq_freeze_queue(q);
+ blk_mq_quiesce_queue(q);
+
spin_lock_irq(&ioc->lock);
memcpy(u, ioc->params.i_lcoefs, sizeof(u));
user = ioc->user_cost_model;
- spin_unlock_irq(&ioc->lock);
while ((p = strsep(&input, " \t\n"))) {
substring_t args[MAX_OPT_ARGS];
@@ -3394,7 +3412,6 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
user = true;
}
- spin_lock_irq(&ioc->lock);
if (user) {
memcpy(ioc->params.i_lcoefs, u, sizeof(u));
ioc->user_cost_model = true;
@@ -3404,10 +3421,18 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
ioc_refresh_params(ioc, true);
spin_unlock_irq(&ioc->lock);
+ blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
+
blkdev_put_no_open(bdev);
return nbytes;
einval:
+ spin_unlock_irq(&ioc->lock);
+
+ blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
+
ret = -EINVAL;
err:
blkdev_put_no_open(bdev);
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index 571fa95aafe9..778a0057193e 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -141,7 +141,7 @@ struct iolatency_grp {
struct latency_stat __percpu *stats;
struct latency_stat cur_stat;
struct blk_iolatency *blkiolat;
- struct rq_depth rq_depth;
+ unsigned int max_depth;
struct rq_wait rq_wait;
atomic64_t window_start;
atomic_t scale_cookie;
@@ -280,7 +280,7 @@ static void iolat_cleanup_cb(struct rq_wait *rqw, void *private_data)
static bool iolat_acquire_inflight(struct rq_wait *rqw, void *private_data)
{
struct iolatency_grp *iolat = private_data;
- return rq_wait_inc_below(rqw, iolat->rq_depth.max_depth);
+ return rq_wait_inc_below(rqw, iolat->max_depth);
}
static void __blkcg_iolatency_throttle(struct rq_qos *rqos,
@@ -364,15 +364,17 @@ static void scale_cookie_change(struct blk_iolatency *blkiolat,
}
/*
- * Change the queue depth of the iolatency_grp. We add/subtract 1/16th of the
+ * Change the queue depth of the iolatency_grp. We add 1/16th of the
* queue depth at a time so we don't get wild swings and hopefully dial in to
- * fairer distribution of the overall queue depth.
+ * fairer distribution of the overall queue depth. We halve the queue depth
+ * at a time so we can scale down queue depth quickly from default unlimited
+ * to target.
*/
static void scale_change(struct iolatency_grp *iolat, bool up)
{
unsigned long qd = iolat->blkiolat->rqos.q->nr_requests;
unsigned long scale = scale_amount(qd, up);
- unsigned long old = iolat->rq_depth.max_depth;
+ unsigned long old = iolat->max_depth;
if (old > qd)
old = qd;
@@ -384,12 +386,12 @@ static void scale_change(struct iolatency_grp *iolat, bool up)
if (old < qd) {
old += scale;
old = min(old, qd);
- iolat->rq_depth.max_depth = old;
+ iolat->max_depth = old;
wake_up_all(&iolat->rq_wait.wait);
}
} else {
old >>= 1;
- iolat->rq_depth.max_depth = max(old, 1UL);
+ iolat->max_depth = max(old, 1UL);
}
}
@@ -403,9 +405,6 @@ static void check_scale_change(struct iolatency_grp *iolat)
u64 scale_lat;
int direction = 0;
- if (lat_to_blkg(iolat)->parent == NULL)
- return;
-
parent = blkg_to_lat(lat_to_blkg(iolat)->parent);
if (!parent)
return;
@@ -445,7 +444,7 @@ static void check_scale_change(struct iolatency_grp *iolat)
}
/* We're as low as we can go. */
- if (iolat->rq_depth.max_depth == 1 && direction < 0) {
+ if (iolat->max_depth == 1 && direction < 0) {
blkcg_use_delay(lat_to_blkg(iolat));
return;
}
@@ -453,7 +452,7 @@ static void check_scale_change(struct iolatency_grp *iolat)
/* We're back to the default cookie, unthrottle all the things. */
if (cur_cookie == DEFAULT_SCALE_COOKIE) {
blkcg_clear_delay(lat_to_blkg(iolat));
- iolat->rq_depth.max_depth = UINT_MAX;
+ iolat->max_depth = UINT_MAX;
wake_up_all(&iolat->rq_wait.wait);
return;
}
@@ -508,7 +507,7 @@ static void iolatency_record_time(struct iolatency_grp *iolat,
* We don't want to count issue_as_root bio's in the cgroups latency
* statistics as it could skew the numbers downwards.
*/
- if (unlikely(issue_as_root && iolat->rq_depth.max_depth != UINT_MAX)) {
+ if (unlikely(issue_as_root && iolat->max_depth != UINT_MAX)) {
u64 sub = iolat->min_lat_nsec;
if (req_time < sub)
blkcg_add_delay(lat_to_blkg(iolat), now, sub - req_time);
@@ -920,7 +919,7 @@ static void iolatency_ssd_stat(struct iolatency_grp *iolat, struct seq_file *s)
}
preempt_enable();
- if (iolat->rq_depth.max_depth == UINT_MAX)
+ if (iolat->max_depth == UINT_MAX)
seq_printf(s, " missed=%llu total=%llu depth=max",
(unsigned long long)stat.ps.missed,
(unsigned long long)stat.ps.total);
@@ -928,7 +927,7 @@ static void iolatency_ssd_stat(struct iolatency_grp *iolat, struct seq_file *s)
seq_printf(s, " missed=%llu total=%llu depth=%u",
(unsigned long long)stat.ps.missed,
(unsigned long long)stat.ps.total,
- iolat->rq_depth.max_depth);
+ iolat->max_depth);
}
static void iolatency_pd_stat(struct blkg_policy_data *pd, struct seq_file *s)
@@ -945,12 +944,12 @@ static void iolatency_pd_stat(struct blkg_policy_data *pd, struct seq_file *s)
avg_lat = div64_u64(iolat->lat_avg, NSEC_PER_USEC);
cur_win = div64_u64(iolat->cur_win_nsec, NSEC_PER_MSEC);
- if (iolat->rq_depth.max_depth == UINT_MAX)
+ if (iolat->max_depth == UINT_MAX)
seq_printf(s, " depth=max avg_lat=%llu win=%llu",
avg_lat, cur_win);
else
seq_printf(s, " depth=%u avg_lat=%llu win=%llu",
- iolat->rq_depth.max_depth, avg_lat, cur_win);
+ iolat->max_depth, avg_lat, cur_win);
}
static struct blkg_policy_data *iolatency_pd_alloc(gfp_t gfp,
@@ -994,9 +993,7 @@ static void iolatency_pd_init(struct blkg_policy_data *pd)
latency_stat_init(iolat, &iolat->cur_stat);
rq_wait_init(&iolat->rq_wait);
spin_lock_init(&iolat->child_lat.lock);
- iolat->rq_depth.queue_depth = blkg->q->nr_requests;
- iolat->rq_depth.max_depth = UINT_MAX;
- iolat->rq_depth.default_depth = iolat->rq_depth.queue_depth;
+ iolat->max_depth = UINT_MAX;
iolat->blkiolat = blkiolat;
iolat->cur_win_nsec = 100 * NSEC_PER_MSEC;
atomic64_set(&iolat->window_start, now);
diff --git a/block/blk-map.c b/block/blk-map.c
index 34735626b00f..19940c978c73 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -267,6 +267,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
{
unsigned int max_sectors = queue_max_hw_sectors(rq->q);
unsigned int nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS);
+ unsigned int gup_flags = 0;
struct bio *bio;
int ret;
int j;
@@ -278,6 +279,9 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
if (bio == NULL)
return -ENOMEM;
+ if (blk_queue_pci_p2pdma(rq->q))
+ gup_flags |= FOLL_PCI_P2PDMA;
+
while (iov_iter_count(iter)) {
struct page **pages, *stack_pages[UIO_FASTIOV];
ssize_t bytes;
@@ -286,11 +290,11 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
if (nr_vecs <= ARRAY_SIZE(stack_pages)) {
pages = stack_pages;
- bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
- nr_vecs, &offs);
+ bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
+ nr_vecs, &offs, gup_flags);
} else {
- bytes = iov_iter_get_pages_alloc2(iter, &pages,
- LONG_MAX, &offs);
+ bytes = iov_iter_get_pages_alloc(iter, &pages,
+ LONG_MAX, &offs, gup_flags);
}
if (unlikely(bytes <= 0)) {
ret = bytes ? bytes : -EFAULT;
@@ -555,7 +559,7 @@ static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
size_t nr_iter = iov_iter_count(iter);
size_t nr_segs = iter->nr_segs;
struct bio_vec *bvecs, *bvprvp = NULL;
- struct queue_limits *lim = &q->limits;
+ const struct queue_limits *lim = &q->limits;
unsigned int nsegs = 0, bytes = 0;
struct bio *bio;
size_t i;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index ff04e9290715..35a8f75cc45d 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -100,13 +100,14 @@ static inline bool req_gap_front_merge(struct request *req, struct bio *bio)
* is defined as 'unsigned int', meantime it has to be aligned to with the
* logical block size, which is the minimum accepted unit by hardware.
*/
-static unsigned int bio_allowed_max_sectors(struct queue_limits *lim)
+static unsigned int bio_allowed_max_sectors(const struct queue_limits *lim)
{
return round_down(UINT_MAX, lim->logical_block_size) >> SECTOR_SHIFT;
}
-static struct bio *bio_split_discard(struct bio *bio, struct queue_limits *lim,
- unsigned *nsegs, struct bio_set *bs)
+static struct bio *bio_split_discard(struct bio *bio,
+ const struct queue_limits *lim,
+ unsigned *nsegs, struct bio_set *bs)
{
unsigned int max_discard_sectors, granularity;
sector_t tmp;
@@ -146,7 +147,8 @@ static struct bio *bio_split_discard(struct bio *bio, struct queue_limits *lim,
}
static struct bio *bio_split_write_zeroes(struct bio *bio,
- struct queue_limits *lim, unsigned *nsegs, struct bio_set *bs)
+ const struct queue_limits *lim,
+ unsigned *nsegs, struct bio_set *bs)
{
*nsegs = 0;
if (!lim->max_write_zeroes_sectors)
@@ -165,7 +167,7 @@ static struct bio *bio_split_write_zeroes(struct bio *bio,
* aligned to a physical block boundary.
*/
static inline unsigned get_max_io_size(struct bio *bio,
- struct queue_limits *lim)
+ const struct queue_limits *lim)
{
unsigned pbs = lim->physical_block_size >> SECTOR_SHIFT;
unsigned lbs = lim->logical_block_size >> SECTOR_SHIFT;
@@ -184,7 +186,15 @@ static inline unsigned get_max_io_size(struct bio *bio,
return max_sectors & ~(lbs - 1);
}
-static inline unsigned get_max_segment_size(struct queue_limits *lim,
+/**
+ * get_max_segment_size() - maximum number of bytes to add as a single segment
+ * @lim: Request queue limits.
+ * @start_page: See below.
+ * @offset: Offset from @start_page where to add a segment.
+ *
+ * Returns the maximum number of bytes that can be added as a single segment.
+ */
+static inline unsigned get_max_segment_size(const struct queue_limits *lim,
struct page *start_page, unsigned long offset)
{
unsigned long mask = lim->seg_boundary_mask;
@@ -192,11 +202,10 @@ static inline unsigned get_max_segment_size(struct queue_limits *lim,
offset = mask & (page_to_phys(start_page) + offset);
/*
- * overflow may be triggered in case of zero page physical address
- * on 32bit arch, use queue's max segment size when that happens.
+ * Prevent an overflow if mask = ULONG_MAX and offset = 0 by adding 1
+ * after having calculated the minimum.
*/
- return min_not_zero(mask - offset + 1,
- (unsigned long)lim->max_segment_size);
+ return min(mask - offset, (unsigned long)lim->max_segment_size - 1) + 1;
}
/**
@@ -219,9 +228,9 @@ static inline unsigned get_max_segment_size(struct queue_limits *lim,
* *@nsegs segments and *@sectors sectors would make that bio unacceptable for
* the block driver.
*/
-static bool bvec_split_segs(struct queue_limits *lim, const struct bio_vec *bv,
- unsigned *nsegs, unsigned *bytes, unsigned max_segs,
- unsigned max_bytes)
+static bool bvec_split_segs(const struct queue_limits *lim,
+ const struct bio_vec *bv, unsigned *nsegs, unsigned *bytes,
+ unsigned max_segs, unsigned max_bytes)
{
unsigned max_len = min(max_bytes, UINT_MAX) - *bytes;
unsigned len = min(bv->bv_len, max_len);
@@ -267,7 +276,7 @@ static bool bvec_split_segs(struct queue_limits *lim, const struct bio_vec *bv,
* responsible for ensuring that @bs is only destroyed after processing of the
* split bio has finished.
*/
-static struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
+static struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim,
unsigned *segs, struct bio_set *bs, unsigned max_bytes)
{
struct bio_vec bv, bvprv, *bvprvp = NULL;
@@ -331,8 +340,9 @@ split:
* The split bio is allocated from @q->bio_split, which is provided by the
* block layer.
*/
-struct bio *__bio_split_to_limits(struct bio *bio, struct queue_limits *lim,
- unsigned int *nr_segs)
+struct bio *__bio_split_to_limits(struct bio *bio,
+ const struct queue_limits *lim,
+ unsigned int *nr_segs)
{
struct bio_set *bs = &bio->bi_bdev->bd_disk->bio_split;
struct bio *split;
@@ -377,7 +387,7 @@ struct bio *__bio_split_to_limits(struct bio *bio, struct queue_limits *lim,
*/
struct bio *bio_split_to_limits(struct bio *bio)
{
- struct queue_limits *lim = &bdev_get_queue(bio->bi_bdev)->limits;
+ const struct queue_limits *lim = &bdev_get_queue(bio->bi_bdev)->limits;
unsigned int nr_segs;
if (bio_may_exceed_limits(bio, lim))
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index a4f7c101b53b..23d1a90fec42 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -555,6 +555,7 @@ static int blk_mq_init_sched_shared_tags(struct request_queue *queue)
return 0;
}
+/* caller must have a reference to @e, will grab another one if successful */
int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
{
unsigned int flags = q->tag_set->flags;
@@ -563,13 +564,6 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
unsigned long i;
int ret;
- if (!e) {
- blk_queue_flag_clear(QUEUE_FLAG_SQ_SCHED, q);
- q->elevator = NULL;
- q->nr_requests = q->tag_set->queue_depth;
- return 0;
- }
-
/*
* Default to double of smaller one between hw queue_depth and 128,
* since we don't split into sync/async like the old code did.
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c
index 93997d297d42..4515288fbe35 100644
--- a/block/blk-mq-sysfs.c
+++ b/block/blk-mq-sysfs.c
@@ -185,7 +185,7 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
{
struct request_queue *q = hctx->queue;
struct blk_mq_ctx *ctx;
- int i, ret;
+ int i, j, ret;
if (!hctx->nr_ctx)
return 0;
@@ -197,9 +197,16 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
hctx_for_each_ctx(hctx, ctx, i) {
ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu);
if (ret)
- break;
+ goto out;
}
+ return 0;
+out:
+ hctx_for_each_ctx(hctx, ctx, j) {
+ if (j < i)
+ kobject_del(&ctx->kobj);
+ }
+ kobject_del(&hctx->kobj);
return ret;
}
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 6a789cda68a5..c5cf0dbca1db 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -254,15 +254,17 @@ EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue_nowait);
/**
* blk_mq_wait_quiesce_done() - wait until in-progress quiesce is done
- * @q: request queue.
+ * @set: tag_set to wait on
*
* Note: it is driver's responsibility for making sure that quiesce has
- * been started.
+ * been started on or more of the request_queues of the tag_set. This
+ * function only waits for the quiesce on those request_queues that had
+ * the quiesce flag set using blk_mq_quiesce_queue_nowait.
*/
-void blk_mq_wait_quiesce_done(struct request_queue *q)
+void blk_mq_wait_quiesce_done(struct blk_mq_tag_set *set)
{
- if (blk_queue_has_srcu(q))
- synchronize_srcu(q->srcu);
+ if (set->flags & BLK_MQ_F_BLOCKING)
+ synchronize_srcu(set->srcu);
else
synchronize_rcu();
}
@@ -280,7 +282,9 @@ EXPORT_SYMBOL_GPL(blk_mq_wait_quiesce_done);
void blk_mq_quiesce_queue(struct request_queue *q)
{
blk_mq_quiesce_queue_nowait(q);
- blk_mq_wait_quiesce_done(q);
+ /* nothing to wait for non-mq queues */
+ if (queue_is_mq(q))
+ blk_mq_wait_quiesce_done(q->tag_set);
}
EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue);
@@ -311,6 +315,33 @@ void blk_mq_unquiesce_queue(struct request_queue *q)
}
EXPORT_SYMBOL_GPL(blk_mq_unquiesce_queue);
+void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set)
+{
+ struct request_queue *q;
+
+ mutex_lock(&set->tag_list_lock);
+ list_for_each_entry(q, &set->tag_list, tag_set_list) {
+ if (!blk_queue_skip_tagset_quiesce(q))
+ blk_mq_quiesce_queue_nowait(q);
+ }
+ blk_mq_wait_quiesce_done(set);
+ mutex_unlock(&set->tag_list_lock);
+}
+EXPORT_SYMBOL_GPL(blk_mq_quiesce_tagset);
+
+void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set)
+{
+ struct request_queue *q;
+
+ mutex_lock(&set->tag_list_lock);
+ list_for_each_entry(q, &set->tag_list, tag_set_list) {
+ if (!blk_queue_skip_tagset_quiesce(q))
+ blk_mq_unquiesce_queue(q);
+ }
+ mutex_unlock(&set->tag_list_lock);
+}
+EXPORT_SYMBOL_GPL(blk_mq_unquiesce_tagset);
+
void blk_mq_wake_waiters(struct request_queue *q)
{
struct blk_mq_hw_ctx *hctx;
@@ -544,25 +575,26 @@ static struct request *blk_mq_alloc_cached_request(struct request_queue *q,
if (!plug)
return NULL;
+
if (rq_list_empty(plug->cached_rq)) {
if (plug->nr_ios == 1)
return NULL;
rq = blk_mq_rq_cache_fill(q, plug, opf, flags);
- if (rq)
- goto got_it;
- return NULL;
- }
- rq = rq_list_peek(&plug->cached_rq);
- if (!rq || rq->q != q)
- return NULL;
+ if (!rq)
+ return NULL;
+ } else {
+ rq = rq_list_peek(&plug->cached_rq);
+ if (!rq || rq->q != q)
+ return NULL;
- if (blk_mq_get_hctx_type(opf) != rq->mq_hctx->type)
- return NULL;
- if (op_is_flush(rq->cmd_flags) != op_is_flush(opf))
- return NULL;
+ if (blk_mq_get_hctx_type(opf) != rq->mq_hctx->type)
+ return NULL;
+ if (op_is_flush(rq->cmd_flags) != op_is_flush(opf))
+ return NULL;
+
+ plug->cached_rq = rq_list_next(rq);
+ }
- plug->cached_rq = rq_list_next(rq);
-got_it:
rq->cmd_flags = opf;
INIT_LIST_HEAD(&rq->queuelist);
return rq;
@@ -1529,7 +1561,13 @@ static void blk_mq_rq_timed_out(struct request *req)
blk_add_timer(req);
}
-static bool blk_mq_req_expired(struct request *rq, unsigned long *next)
+struct blk_expired_data {
+ bool has_timedout_rq;
+ unsigned long next;
+ unsigned long timeout_start;
+};
+
+static bool blk_mq_req_expired(struct request *rq, struct blk_expired_data *expired)
{
unsigned long deadline;
@@ -1539,13 +1577,13 @@ static bool blk_mq_req_expired(struct request *rq, unsigned long *next)
return false;
deadline = READ_ONCE(rq->deadline);
- if (time_after_eq(jiffies, deadline))
+ if (time_after_eq(expired->timeout_start, deadline))
return true;
- if (*next == 0)
- *next = deadline;
- else if (time_after(*next, deadline))
- *next = deadline;
+ if (expired->next == 0)
+ expired->next = deadline;
+ else if (time_after(expired->next, deadline))
+ expired->next = deadline;
return false;
}
@@ -1561,7 +1599,7 @@ void blk_mq_put_rq_ref(struct request *rq)
static bool blk_mq_check_expired(struct request *rq, void *priv)
{
- unsigned long *next = priv;
+ struct blk_expired_data *expired = priv;
/*
* blk_mq_queue_tag_busy_iter() has locked the request, so it cannot
@@ -1570,7 +1608,18 @@ static bool blk_mq_check_expired(struct request *rq, void *priv)
* it was completed and reallocated as a new request after returning
* from blk_mq_check_expired().
*/
- if (blk_mq_req_expired(rq, next))
+ if (blk_mq_req_expired(rq, expired)) {
+ expired->has_timedout_rq = true;
+ return false;
+ }
+ return true;
+}
+
+static bool blk_mq_handle_expired(struct request *rq, void *priv)
+{
+ struct blk_expired_data *expired = priv;
+
+ if (blk_mq_req_expired(rq, expired))
blk_mq_rq_timed_out(rq);
return true;
}
@@ -1579,7 +1628,9 @@ static void blk_mq_timeout_work(struct work_struct *work)
{
struct request_queue *q =
container_of(work, struct request_queue, timeout_work);
- unsigned long next = 0;
+ struct blk_expired_data expired = {
+ .timeout_start = jiffies,
+ };
struct blk_mq_hw_ctx *hctx;
unsigned long i;
@@ -1599,10 +1650,23 @@ static void blk_mq_timeout_work(struct work_struct *work)
if (!percpu_ref_tryget(&q->q_usage_counter))
return;
- blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &next);
+ /* check if there is any timed-out request */
+ blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &expired);
+ if (expired.has_timedout_rq) {
+ /*
+ * Before walking tags, we must ensure any submit started
+ * before the current time has finished. Since the submit
+ * uses srcu or rcu, wait for a synchronization point to
+ * ensure all running submits have finished
+ */
+ blk_mq_wait_quiesce_done(q->tag_set);
- if (next != 0) {
- mod_timer(&q->timeout, next);
+ expired.next = 0;
+ blk_mq_queue_tag_busy_iter(q, blk_mq_handle_expired, &expired);
+ }
+
+ if (expired.next != 0) {
+ mod_timer(&q->timeout, expired.next);
} else {
/*
* Request timeouts are handled as a forward rolling timer. If
@@ -3248,21 +3312,22 @@ static struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
tags->rqs = kcalloc_node(nr_tags, sizeof(struct request *),
GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
node);
- if (!tags->rqs) {
- blk_mq_free_tags(tags);
- return NULL;
- }
+ if (!tags->rqs)
+ goto err_free_tags;
tags->static_rqs = kcalloc_node(nr_tags, sizeof(struct request *),
GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
node);
- if (!tags->static_rqs) {
- kfree(tags->rqs);
- blk_mq_free_tags(tags);
- return NULL;
- }
+ if (!tags->static_rqs)
+ goto err_free_rqs;
return tags;
+
+err_free_rqs:
+ kfree(tags->rqs);
+err_free_tags:
+ blk_mq_free_tags(tags);
+ return NULL;
}
static int blk_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
@@ -3975,7 +4040,7 @@ static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
struct request_queue *q;
int ret;
- q = blk_alloc_queue(set->numa_node, set->flags & BLK_MQ_F_BLOCKING);
+ q = blk_alloc_queue(set->numa_node);
if (!q)
return ERR_PTR(-ENOMEM);
q->queuedata = queuedata;
@@ -4011,14 +4076,11 @@ void blk_mq_destroy_queue(struct request_queue *q)
blk_queue_flag_set(QUEUE_FLAG_DYING, q);
blk_queue_start_drain(q);
- blk_freeze_queue(q);
+ blk_mq_freeze_queue_wait(q);
blk_sync_queue(q);
blk_mq_cancel_work_sync(q);
blk_mq_exit_queue(q);
-
- /* @q is and will stay empty, shutdown and put */
- blk_put_queue(q);
}
EXPORT_SYMBOL(blk_mq_destroy_queue);
@@ -4035,6 +4097,7 @@ struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
disk = __alloc_disk_node(q, set->numa_node, lkclass);
if (!disk) {
blk_mq_destroy_queue(q);
+ blk_put_queue(q);
return ERR_PTR(-ENOMEM);
}
set_bit(GD_OWNS_QUEUE, &disk->state);
@@ -4045,9 +4108,14 @@ EXPORT_SYMBOL(__blk_mq_alloc_disk);
struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
struct lock_class_key *lkclass)
{
+ struct gendisk *disk;
+
if (!blk_get_queue(q))
return NULL;
- return __alloc_disk_node(q, NUMA_NO_NODE, lkclass);
+ disk = __alloc_disk_node(q, NUMA_NO_NODE, lkclass);
+ if (!disk)
+ blk_put_queue(q);
+ return disk;
}
EXPORT_SYMBOL(blk_mq_alloc_disk_for_queue);
@@ -4142,9 +4210,6 @@ static void blk_mq_update_poll_flag(struct request_queue *q)
int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
struct request_queue *q)
{
- WARN_ON_ONCE(blk_queue_has_srcu(q) !=
- !!(set->flags & BLK_MQ_F_BLOCKING));
-
/* mark the queue as mq asap */
q->mq_ops = set->ops;
@@ -4320,12 +4385,12 @@ static void blk_mq_update_queue_map(struct blk_mq_tag_set *set)
}
static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
- int cur_nr_hw_queues, int new_nr_hw_queues)
+ int new_nr_hw_queues)
{
struct blk_mq_tags **new_tags;
- if (cur_nr_hw_queues >= new_nr_hw_queues)
- return 0;
+ if (set->nr_hw_queues >= new_nr_hw_queues)
+ goto done;
new_tags = kcalloc_node(new_nr_hw_queues, sizeof(struct blk_mq_tags *),
GFP_KERNEL, set->numa_node);
@@ -4333,21 +4398,15 @@ static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
return -ENOMEM;
if (set->tags)
- memcpy(new_tags, set->tags, cur_nr_hw_queues *
+ memcpy(new_tags, set->tags, set->nr_hw_queues *
sizeof(*set->tags));
kfree(set->tags);
set->tags = new_tags;
+done:
set->nr_hw_queues = new_nr_hw_queues;
-
return 0;
}
-static int blk_mq_alloc_tag_set_tags(struct blk_mq_tag_set *set,
- int new_nr_hw_queues)
-{
- return blk_mq_realloc_tag_set_tags(set, 0, new_nr_hw_queues);
-}
-
/*
* Alloc a tag set to be associated with one or more request queues.
* May fail with EINVAL for various error conditions. May adjust the
@@ -4401,10 +4460,22 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
if (set->nr_maps == 1 && set->nr_hw_queues > nr_cpu_ids)
set->nr_hw_queues = nr_cpu_ids;
- if (blk_mq_alloc_tag_set_tags(set, set->nr_hw_queues) < 0)
- return -ENOMEM;
+ if (set->flags & BLK_MQ_F_BLOCKING) {
+ set->srcu = kmalloc(sizeof(*set->srcu), GFP_KERNEL);
+ if (!set->srcu)
+ return -ENOMEM;
+ ret = init_srcu_struct(set->srcu);
+ if (ret)
+ goto out_free_srcu;
+ }
ret = -ENOMEM;
+ set->tags = kcalloc_node(set->nr_hw_queues,
+ sizeof(struct blk_mq_tags *), GFP_KERNEL,
+ set->numa_node);
+ if (!set->tags)
+ goto out_cleanup_srcu;
+
for (i = 0; i < set->nr_maps; i++) {
set->map[i].mq_map = kcalloc_node(nr_cpu_ids,
sizeof(set->map[i].mq_map[0]),
@@ -4432,6 +4503,12 @@ out_free_mq_map:
}
kfree(set->tags);
set->tags = NULL;
+out_cleanup_srcu:
+ if (set->flags & BLK_MQ_F_BLOCKING)
+ cleanup_srcu_struct(set->srcu);
+out_free_srcu:
+ if (set->flags & BLK_MQ_F_BLOCKING)
+ kfree(set->srcu);
return ret;
}
EXPORT_SYMBOL(blk_mq_alloc_tag_set);
@@ -4471,6 +4548,10 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
kfree(set->tags);
set->tags = NULL;
+ if (set->flags & BLK_MQ_F_BLOCKING) {
+ cleanup_srcu_struct(set->srcu);
+ kfree(set->srcu);
+ }
}
EXPORT_SYMBOL(blk_mq_free_tag_set);
@@ -4559,17 +4640,10 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
INIT_LIST_HEAD(&qe->node);
qe->q = q;
qe->type = q->elevator->type;
+ /* keep a reference to the elevator module as we'll switch back */
+ __elevator_get(qe->type);
list_add(&qe->node, head);
-
- /*
- * After elevator_switch, the previous elevator_queue will be
- * released by elevator_release. The reference of the io scheduler
- * module get by elevator_get will also be put. So we need to get
- * a reference of the io scheduler module here to prevent it to be
- * removed.
- */
- __module_get(qe->type->elevator_owner);
- elevator_switch(q, NULL);
+ elevator_disable(q);
mutex_unlock(&q->sysfs_lock);
return true;
@@ -4602,6 +4676,8 @@ static void blk_mq_elv_switch_back(struct list_head *head,
mutex_lock(&q->sysfs_lock);
elevator_switch(q, t);
+ /* drop the reference acquired in blk_mq_elv_switch_none */
+ elevator_put(t);
mutex_unlock(&q->sysfs_lock);
}
@@ -4638,11 +4714,9 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
}
prev_nr_hw_queues = set->nr_hw_queues;
- if (blk_mq_realloc_tag_set_tags(set, set->nr_hw_queues, nr_hw_queues) <
- 0)
+ if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0)
goto reregister;
- set->nr_hw_queues = nr_hw_queues;
fallback:
blk_mq_update_queue_map(set);
list_for_each_entry(q, &set->tag_list, tag_set_list) {
@@ -4862,15 +4936,13 @@ EXPORT_SYMBOL(blk_mq_rq_cpu);
void blk_mq_cancel_work_sync(struct request_queue *q)
{
- if (queue_is_mq(q)) {
- struct blk_mq_hw_ctx *hctx;
- unsigned long i;
+ struct blk_mq_hw_ctx *hctx;
+ unsigned long i;
- cancel_delayed_work_sync(&q->requeue_work);
+ cancel_delayed_work_sync(&q->requeue_work);
- queue_for_each_hw_ctx(q, hctx, i)
- cancel_delayed_work_sync(&hctx->run_work);
- }
+ queue_for_each_hw_ctx(q, hctx, i)
+ cancel_delayed_work_sync(&hctx->run_work);
}
static int __init blk_mq_init(void)
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 0b2870839cdd..ef59fee62780 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -377,17 +377,17 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
/* run the code block in @dispatch_ops with rcu/srcu read lock held */
#define __blk_mq_run_dispatch_ops(q, check_sleep, dispatch_ops) \
do { \
- if (!blk_queue_has_srcu(q)) { \
- rcu_read_lock(); \
- (dispatch_ops); \
- rcu_read_unlock(); \
- } else { \
+ if ((q)->tag_set->flags & BLK_MQ_F_BLOCKING) { \
int srcu_idx; \
\
might_sleep_if(check_sleep); \
- srcu_idx = srcu_read_lock((q)->srcu); \
+ srcu_idx = srcu_read_lock((q)->tag_set->srcu); \
(dispatch_ops); \
- srcu_read_unlock((q)->srcu, srcu_idx); \
+ srcu_read_unlock((q)->tag_set->srcu, srcu_idx); \
+ } else { \
+ rcu_read_lock(); \
+ (dispatch_ops); \
+ rcu_read_unlock(); \
} \
} while (0)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 8bb9eef5310e..0477c4d527fe 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -57,8 +57,8 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->misaligned = 0;
lim->zoned = BLK_ZONED_NONE;
lim->zone_write_granularity = 0;
+ lim->dma_alignment = 511;
}
-EXPORT_SYMBOL(blk_set_default_limits);
/**
* blk_set_stacking_limits - set default limits for stacking devices
@@ -481,7 +481,7 @@ void blk_queue_io_opt(struct request_queue *q, unsigned int opt)
}
EXPORT_SYMBOL(blk_queue_io_opt);
-static int queue_limit_alignment_offset(struct queue_limits *lim,
+static int queue_limit_alignment_offset(const struct queue_limits *lim,
sector_t sector)
{
unsigned int granularity = max(lim->physical_block_size, lim->io_min);
@@ -491,8 +491,8 @@ static int queue_limit_alignment_offset(struct queue_limits *lim,
return (granularity + lim->alignment_offset - alignment) % granularity;
}
-static unsigned int queue_limit_discard_alignment(struct queue_limits *lim,
- sector_t sector)
+static unsigned int queue_limit_discard_alignment(
+ const struct queue_limits *lim, sector_t sector)
{
unsigned int alignment, granularity, offset;
@@ -600,6 +600,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->io_min = max(t->io_min, b->io_min);
t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
+ t->dma_alignment = max(t->dma_alignment, b->dma_alignment);
/* Set non-power-of-2 compatible chunk_sectors boundary */
if (b->chunk_sectors)
@@ -773,7 +774,7 @@ EXPORT_SYMBOL(blk_queue_virt_boundary);
**/
void blk_queue_dma_alignment(struct request_queue *q, int mask)
{
- q->dma_alignment = mask;
+ q->limits.dma_alignment = mask;
}
EXPORT_SYMBOL(blk_queue_dma_alignment);
@@ -795,8 +796,8 @@ void blk_queue_update_dma_alignment(struct request_queue *q, int mask)
{
BUG_ON(mask > PAGE_SIZE);
- if (mask > q->dma_alignment)
- q->dma_alignment = mask;
+ if (mask > q->limits.dma_alignment)
+ q->limits.dma_alignment = mask;
}
EXPORT_SYMBOL(blk_queue_update_dma_alignment);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index e71b3b43927c..93d9e9c9a6ea 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -470,6 +470,9 @@ static ssize_t queue_wb_lat_show(struct request_queue *q, char *page)
if (!wbt_rq_qos(q))
return -EINVAL;
+ if (wbt_disabled(q))
+ return sprintf(page, "0\n");
+
return sprintf(page, "%llu\n", div_u64(wbt_get_min_lat(q), 1000));
}
@@ -680,8 +683,8 @@ static struct attribute *queue_attrs[] = {
static umode_t queue_attr_visible(struct kobject *kobj, struct attribute *attr,
int n)
{
- struct request_queue *q =
- container_of(kobj, struct request_queue, kobj);
+ struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+ struct request_queue *q = disk->queue;
if (attr == &queue_io_timeout_entry.attr &&
(!q->mq_ops || !q->mq_ops->timeout))
@@ -707,8 +710,8 @@ static ssize_t
queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
struct queue_sysfs_entry *entry = to_queue(attr);
- struct request_queue *q =
- container_of(kobj, struct request_queue, kobj);
+ struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+ struct request_queue *q = disk->queue;
ssize_t res;
if (!entry->show)
@@ -724,68 +727,19 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
const char *page, size_t length)
{
struct queue_sysfs_entry *entry = to_queue(attr);
- struct request_queue *q;
+ struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+ struct request_queue *q = disk->queue;
ssize_t res;
if (!entry->store)
return -EIO;
- q = container_of(kobj, struct request_queue, kobj);
mutex_lock(&q->sysfs_lock);
res = entry->store(q, page, length);
mutex_unlock(&q->sysfs_lock);
return res;
}
-static void blk_free_queue_rcu(struct rcu_head *rcu_head)
-{
- struct request_queue *q = container_of(rcu_head, struct request_queue,
- rcu_head);
-
- kmem_cache_free(blk_get_queue_kmem_cache(blk_queue_has_srcu(q)), q);
-}
-
-/**
- * blk_release_queue - releases all allocated resources of the request_queue
- * @kobj: pointer to a kobject, whose container is a request_queue
- *
- * This function releases all allocated resources of the request queue.
- *
- * The struct request_queue refcount is incremented with blk_get_queue() and
- * decremented with blk_put_queue(). Once the refcount reaches 0 this function
- * is called.
- *
- * Drivers exist which depend on the release of the request_queue to be
- * synchronous, it should not be deferred.
- *
- * Context: can sleep
- */
-static void blk_release_queue(struct kobject *kobj)
-{
- struct request_queue *q =
- container_of(kobj, struct request_queue, kobj);
-
- might_sleep();
-
- percpu_ref_exit(&q->q_usage_counter);
-
- if (q->poll_stat)
- blk_stat_remove_callback(q, q->poll_cb);
- blk_stat_free_callback(q->poll_cb);
-
- blk_free_queue_stats(q->stats);
- kfree(q->poll_stat);
-
- if (queue_is_mq(q))
- blk_mq_release(q);
-
- if (blk_queue_has_srcu(q))
- cleanup_srcu_struct(q->srcu);
-
- ida_free(&blk_queue_ida, q->id);
- call_rcu(&q->rcu_head, blk_free_queue_rcu);
-}
-
static const struct sysfs_ops queue_sysfs_ops = {
.show = queue_attr_show,
.store = queue_attr_store,
@@ -796,12 +750,30 @@ static const struct attribute_group *blk_queue_attr_groups[] = {
NULL
};
-struct kobj_type blk_queue_ktype = {
+static void blk_queue_release(struct kobject *kobj)
+{
+ /* nothing to do here, all data is associated with the parent gendisk */
+}
+
+static struct kobj_type blk_queue_ktype = {
.default_groups = blk_queue_attr_groups,
.sysfs_ops = &queue_sysfs_ops,
- .release = blk_release_queue,
+ .release = blk_queue_release,
};
+static void blk_debugfs_remove(struct gendisk *disk)
+{
+ struct request_queue *q = disk->queue;
+
+ mutex_lock(&q->debugfs_mutex);
+ blk_trace_shutdown(q);
+ debugfs_remove_recursive(q->debugfs_dir);
+ q->debugfs_dir = NULL;
+ q->sched_debugfs_dir = NULL;
+ q->rqos_debugfs_dir = NULL;
+ mutex_unlock(&q->debugfs_mutex);
+}
+
/**
* blk_register_queue - register a block layer queue with sysfs
* @disk: Disk of which the request queue should be registered with sysfs.
@@ -812,47 +784,47 @@ int blk_register_queue(struct gendisk *disk)
int ret;
mutex_lock(&q->sysfs_dir_lock);
-
- ret = kobject_add(&q->kobj, &disk_to_dev(disk)->kobj, "queue");
+ kobject_init(&disk->queue_kobj, &blk_queue_ktype);
+ ret = kobject_add(&disk->queue_kobj, &disk_to_dev(disk)->kobj, "queue");
if (ret < 0)
- goto unlock;
+ goto out_put_queue_kobj;
- if (queue_is_mq(q))
- blk_mq_sysfs_register(disk);
+ if (queue_is_mq(q)) {
+ ret = blk_mq_sysfs_register(disk);
+ if (ret)
+ goto out_put_queue_kobj;
+ }
mutex_lock(&q->sysfs_lock);
mutex_lock(&q->debugfs_mutex);
- q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
- blk_debugfs_root);
+ q->debugfs_dir = debugfs_create_dir(disk->disk_name, blk_debugfs_root);
if (queue_is_mq(q))
blk_mq_debugfs_register(q);
mutex_unlock(&q->debugfs_mutex);
ret = disk_register_independent_access_ranges(disk);
if (ret)
- goto put_dev;
+ goto out_debugfs_remove;
if (q->elevator) {
ret = elv_register_queue(q, false);
if (ret)
- goto put_dev;
+ goto out_unregister_ia_ranges;
}
- ret = blk_crypto_sysfs_register(q);
+ ret = blk_crypto_sysfs_register(disk);
if (ret)
- goto put_dev;
+ goto out_elv_unregister;
blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
wbt_enable_default(q);
blk_throtl_register(disk);
/* Now everything is ready and send out KOBJ_ADD uevent */
- kobject_uevent(&q->kobj, KOBJ_ADD);
+ kobject_uevent(&disk->queue_kobj, KOBJ_ADD);
if (q->elevator)
kobject_uevent(&q->elevator->kobj, KOBJ_ADD);
mutex_unlock(&q->sysfs_lock);
-
-unlock:
mutex_unlock(&q->sysfs_dir_lock);
/*
@@ -871,13 +843,16 @@ unlock:
return ret;
-put_dev:
+out_elv_unregister:
elv_unregister_queue(q);
+out_unregister_ia_ranges:
disk_unregister_independent_access_ranges(disk);
+out_debugfs_remove:
+ blk_debugfs_remove(disk);
mutex_unlock(&q->sysfs_lock);
+out_put_queue_kobj:
+ kobject_put(&disk->queue_kobj);
mutex_unlock(&q->sysfs_dir_lock);
- kobject_del(&q->kobj);
-
return ret;
}
@@ -915,7 +890,7 @@ void blk_unregister_queue(struct gendisk *disk)
*/
if (queue_is_mq(q))
blk_mq_sysfs_unregister(disk);
- blk_crypto_sysfs_unregister(q);
+ blk_crypto_sysfs_unregister(disk);
mutex_lock(&q->sysfs_lock);
elv_unregister_queue(q);
@@ -923,15 +898,9 @@ void blk_unregister_queue(struct gendisk *disk)
mutex_unlock(&q->sysfs_lock);
/* Now that we've deleted all child objects, we can delete the queue. */
- kobject_uevent(&q->kobj, KOBJ_REMOVE);
- kobject_del(&q->kobj);
+ kobject_uevent(&disk->queue_kobj, KOBJ_REMOVE);
+ kobject_del(&disk->queue_kobj);
mutex_unlock(&q->sysfs_dir_lock);
- mutex_lock(&q->debugfs_mutex);
- blk_trace_shutdown(q);
- debugfs_remove_recursive(q->debugfs_dir);
- q->debugfs_dir = NULL;
- q->sched_debugfs_dir = NULL;
- q->rqos_debugfs_dir = NULL;
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_remove(disk);
}
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 847721dc2b2b..6fb5a2f9e1ee 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -129,7 +129,7 @@ static struct throtl_data *sq_to_td(struct throtl_service_queue *sq)
/*
* cgroup's limit in LIMIT_MAX is scaled if low limit is set. This scale is to
* make the IO dispatch more smooth.
- * Scale up: linearly scale up according to lapsed time since upgrade. For
+ * Scale up: linearly scale up according to elapsed time since upgrade. For
* every throtl_slice, the limit scales up 1/2 .low limit till the
* limit hits .max limit
* Scale down: exponentially scale down if a cgroup doesn't hit its .low limit
@@ -395,8 +395,9 @@ static void throtl_pd_init(struct blkg_policy_data *pd)
* If on the default hierarchy, we switch to properly hierarchical
* behavior where limits on a given throtl_grp are applied to the
* whole subtree rather than just the group itself. e.g. If 16M
- * read_bps limit is set on the root group, the whole system can't
- * exceed 16M for the device.
+ * read_bps limit is set on a parent group, summary bps of
+ * parent group and its subtree groups can't exceed 16M for the
+ * device.
*
* If not on the default hierarchy, the broken flat hierarchy
* behavior is retained where all throtl_grps are treated as if
@@ -644,7 +645,7 @@ static inline void throtl_start_new_slice_with_credit(struct throtl_grp *tg,
* that bandwidth. Do try to make use of that bandwidth while giving
* credit.
*/
- if (time_after_eq(start, tg->slice_start[rw]))
+ if (time_after(start, tg->slice_start[rw]))
tg->slice_start[rw] = start;
tg->slice_end[rw] = jiffies + tg->td->throtl_slice;
@@ -821,17 +822,15 @@ static void tg_update_carryover(struct throtl_grp *tg)
tg->carryover_ios[READ], tg->carryover_ios[WRITE]);
}
-static bool tg_within_iops_limit(struct throtl_grp *tg, struct bio *bio,
- u32 iops_limit, unsigned long *wait)
+static unsigned long tg_within_iops_limit(struct throtl_grp *tg, struct bio *bio,
+ u32 iops_limit)
{
bool rw = bio_data_dir(bio);
unsigned int io_allowed;
unsigned long jiffy_elapsed, jiffy_wait, jiffy_elapsed_rnd;
if (iops_limit == UINT_MAX) {
- if (wait)
- *wait = 0;
- return true;
+ return 0;
}
jiffy_elapsed = jiffies - tg->slice_start[rw];
@@ -841,21 +840,16 @@ static bool tg_within_iops_limit(struct throtl_grp *tg, struct bio *bio,
io_allowed = calculate_io_allowed(iops_limit, jiffy_elapsed_rnd) +
tg->carryover_ios[rw];
if (tg->io_disp[rw] + 1 <= io_allowed) {
- if (wait)
- *wait = 0;
- return true;
+ return 0;
}
/* Calc approx time to dispatch */
jiffy_wait = jiffy_elapsed_rnd - jiffy_elapsed;
-
- if (wait)
- *wait = jiffy_wait;
- return false;
+ return jiffy_wait;
}
-static bool tg_within_bps_limit(struct throtl_grp *tg, struct bio *bio,
- u64 bps_limit, unsigned long *wait)
+static unsigned long tg_within_bps_limit(struct throtl_grp *tg, struct bio *bio,
+ u64 bps_limit)
{
bool rw = bio_data_dir(bio);
u64 bytes_allowed, extra_bytes;
@@ -864,9 +858,7 @@ static bool tg_within_bps_limit(struct throtl_grp *tg, struct bio *bio,
/* no need to throttle if this bio's bytes have been accounted */
if (bps_limit == U64_MAX || bio_flagged(bio, BIO_BPS_THROTTLED)) {
- if (wait)
- *wait = 0;
- return true;
+ return 0;
}
jiffy_elapsed = jiffy_elapsed_rnd = jiffies - tg->slice_start[rw];
@@ -879,9 +871,7 @@ static bool tg_within_bps_limit(struct throtl_grp *tg, struct bio *bio,
bytes_allowed = calculate_bytes_allowed(bps_limit, jiffy_elapsed_rnd) +
tg->carryover_bytes[rw];
if (tg->bytes_disp[rw] + bio_size <= bytes_allowed) {
- if (wait)
- *wait = 0;
- return true;
+ return 0;
}
/* Calc approx time to dispatch */
@@ -896,9 +886,7 @@ static bool tg_within_bps_limit(struct throtl_grp *tg, struct bio *bio,
* up we did. Add that time also.
*/
jiffy_wait = jiffy_wait + (jiffy_elapsed_rnd - jiffy_elapsed);
- if (wait)
- *wait = jiffy_wait;
- return false;
+ return jiffy_wait;
}
/*
@@ -946,8 +934,9 @@ static bool tg_may_dispatch(struct throtl_grp *tg, struct bio *bio,
jiffies + tg->td->throtl_slice);
}
- if (tg_within_bps_limit(tg, bio, bps_limit, &bps_wait) &&
- tg_within_iops_limit(tg, bio, iops_limit, &iops_wait)) {
+ bps_wait = tg_within_bps_limit(tg, bio, bps_limit);
+ iops_wait = tg_within_iops_limit(tg, bio, iops_limit);
+ if (bps_wait + iops_wait == 0) {
if (wait)
*wait = 0;
return true;
@@ -1066,7 +1055,6 @@ static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
sq->nr_queued[rw]--;
throtl_charge_bio(tg, bio);
- bio_set_flag(bio, BIO_BPS_THROTTLED);
/*
* If our parent is another tg, we just need to transfer @bio to
@@ -1079,6 +1067,7 @@ static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
throtl_add_bio_tg(bio, &tg->qnode_on_parent[rw], parent_tg);
start_parent_slice_with_credit(tg, parent_tg, rw);
} else {
+ bio_set_flag(bio, BIO_BPS_THROTTLED);
throtl_qnode_add_bio(bio, &tg->qnode_on_parent[rw],
&parent_sq->queued[rw]);
BUG_ON(tg->td->nr_queued[rw] <= 0);
@@ -1737,7 +1726,18 @@ void blk_throtl_cancel_bios(struct gendisk *disk)
* Set the flag to make sure throtl_pending_timer_fn() won't
* stop until all throttled bios are dispatched.
*/
- blkg_to_tg(blkg)->flags |= THROTL_TG_CANCELING;
+ tg->flags |= THROTL_TG_CANCELING;
+
+ /*
+ * Do not dispatch cgroup without THROTL_TG_PENDING or cgroup
+ * will be inserted to service queue without THROTL_TG_PENDING
+ * set in tg_update_disptime below. Then IO dispatched from
+ * child in tg_dispatch_one_bio will trigger double insertion
+ * and corrupt the tree.
+ */
+ if (!(tg->flags & THROTL_TG_PENDING))
+ continue;
+
/*
* Update disptime after setting the above flag to make sure
* throtl_select_dispatch() won't exit without dispatching.
@@ -1762,7 +1762,6 @@ static unsigned long __tg_last_low_overflow_time(struct throtl_grp *tg)
return min(rtime, wtime);
}
-/* tg should not be an intermediate node */
static unsigned long tg_last_low_overflow_time(struct throtl_grp *tg)
{
struct throtl_service_queue *parent_sq;
@@ -1816,24 +1815,29 @@ static bool throtl_tg_is_idle(struct throtl_grp *tg)
return ret;
}
-static bool throtl_tg_can_upgrade(struct throtl_grp *tg)
+static bool throtl_low_limit_reached(struct throtl_grp *tg, int rw)
{
struct throtl_service_queue *sq = &tg->service_queue;
- bool read_limit, write_limit;
+ bool limit = tg->bps[rw][LIMIT_LOW] || tg->iops[rw][LIMIT_LOW];
/*
- * if cgroup reaches low limit (if low limit is 0, the cgroup always
- * reaches), it's ok to upgrade to next limit
+ * if low limit is zero, low limit is always reached.
+ * if low limit is non-zero, we can check if there is any request
+ * is queued to determine if low limit is reached as we throttle
+ * request according to limit.
*/
- read_limit = tg->bps[READ][LIMIT_LOW] || tg->iops[READ][LIMIT_LOW];
- write_limit = tg->bps[WRITE][LIMIT_LOW] || tg->iops[WRITE][LIMIT_LOW];
- if (!read_limit && !write_limit)
- return true;
- if (read_limit && sq->nr_queued[READ] &&
- (!write_limit || sq->nr_queued[WRITE]))
- return true;
- if (write_limit && sq->nr_queued[WRITE] &&
- (!read_limit || sq->nr_queued[READ]))
+ return !limit || sq->nr_queued[rw];
+}
+
+static bool throtl_tg_can_upgrade(struct throtl_grp *tg)
+{
+ /*
+ * cgroup reaches low limit when low limit of READ and WRITE are
+ * both reached, it's ok to upgrade to next limit if cgroup reaches
+ * low limit
+ */
+ if (throtl_low_limit_reached(tg, READ) &&
+ throtl_low_limit_reached(tg, WRITE))
return true;
if (time_after_eq(jiffies,
@@ -1951,8 +1955,7 @@ static bool throtl_tg_can_downgrade(struct throtl_grp *tg)
* If cgroup is below low limit, consider downgrade and throttle other
* cgroups
*/
- if (time_after_eq(now, td->low_upgrade_time + td->throtl_slice) &&
- time_after_eq(now, tg_last_low_overflow_time(tg) +
+ if (time_after_eq(now, tg_last_low_overflow_time(tg) +
td->throtl_slice) &&
(!throtl_tg_is_idle(tg) ||
!list_empty(&tg_to_blkg(tg)->blkcg->css.children)))
@@ -1962,6 +1965,11 @@ static bool throtl_tg_can_downgrade(struct throtl_grp *tg)
static bool throtl_hierarchy_can_downgrade(struct throtl_grp *tg)
{
+ struct throtl_data *td = tg->td;
+
+ if (time_before(jiffies, td->low_upgrade_time + td->throtl_slice))
+ return false;
+
while (true) {
if (!throtl_tg_can_downgrade(tg))
return false;
diff --git a/block/blk-wbt.c b/block/blk-wbt.c
index c293e08b301f..68a774d7a7c9 100644
--- a/block/blk-wbt.c
+++ b/block/blk-wbt.c
@@ -27,6 +27,7 @@
#include "blk-wbt.h"
#include "blk-rq-qos.h"
+#include "elevator.h"
#define CREATE_TRACE_POINTS
#include <trace/events/wbt.h>
@@ -422,6 +423,14 @@ static void wbt_update_limits(struct rq_wb *rwb)
rwb_wake_all(rwb);
}
+bool wbt_disabled(struct request_queue *q)
+{
+ struct rq_qos *rqos = wbt_rq_qos(q);
+
+ return !rqos || RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT ||
+ RQWB(rqos)->enable_state == WBT_STATE_OFF_MANUAL;
+}
+
u64 wbt_get_min_lat(struct request_queue *q)
{
struct rq_qos *rqos = wbt_rq_qos(q);
@@ -435,8 +444,13 @@ void wbt_set_min_lat(struct request_queue *q, u64 val)
struct rq_qos *rqos = wbt_rq_qos(q);
if (!rqos)
return;
+
RQWB(rqos)->min_lat_nsec = val;
- RQWB(rqos)->enable_state = WBT_STATE_ON_MANUAL;
+ if (val)
+ RQWB(rqos)->enable_state = WBT_STATE_ON_MANUAL;
+ else
+ RQWB(rqos)->enable_state = WBT_STATE_OFF_MANUAL;
+
wbt_update_limits(RQWB(rqos));
}
@@ -638,11 +652,15 @@ void wbt_set_write_cache(struct request_queue *q, bool write_cache_on)
*/
void wbt_enable_default(struct request_queue *q)
{
- struct rq_qos *rqos = wbt_rq_qos(q);
+ struct rq_qos *rqos;
+ bool disable_flag = q->elevator &&
+ test_bit(ELEVATOR_FLAG_DISABLE_WBT, &q->elevator->flags);
/* Throttling already enabled? */
+ rqos = wbt_rq_qos(q);
if (rqos) {
- if (RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT)
+ if (!disable_flag &&
+ RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT)
RQWB(rqos)->enable_state = WBT_STATE_ON_DEFAULT;
return;
}
@@ -651,7 +669,7 @@ void wbt_enable_default(struct request_queue *q)
if (!blk_queue_registered(q))
return;
- if (queue_is_mq(q) && IS_ENABLED(CONFIG_BLK_WBT_MQ))
+ if (queue_is_mq(q) && !disable_flag)
wbt_init(q);
}
EXPORT_SYMBOL_GPL(wbt_enable_default);
diff --git a/block/blk-wbt.h b/block/blk-wbt.h
index 7e44eccc676d..e3ea6e7e2900 100644
--- a/block/blk-wbt.h
+++ b/block/blk-wbt.h
@@ -28,13 +28,15 @@ enum {
};
/*
- * Enable states. Either off, or on by default (done at init time),
- * or on through manual setup in sysfs.
+ * If current state is WBT_STATE_ON/OFF_DEFAULT, it can be covered to any other
+ * state, if current state is WBT_STATE_ON/OFF_MANUAL, it can only be covered
+ * to WBT_STATE_OFF/ON_MANUAL.
*/
enum {
- WBT_STATE_ON_DEFAULT = 1,
- WBT_STATE_ON_MANUAL = 2,
- WBT_STATE_OFF_DEFAULT
+ WBT_STATE_ON_DEFAULT = 1, /* on by default */
+ WBT_STATE_ON_MANUAL = 2, /* on manually by sysfs */
+ WBT_STATE_OFF_DEFAULT = 3, /* off by default */
+ WBT_STATE_OFF_MANUAL = 4, /* off manually by sysfs */
};
struct rq_wb {
@@ -94,6 +96,7 @@ void wbt_enable_default(struct request_queue *);
u64 wbt_get_min_lat(struct request_queue *q);
void wbt_set_min_lat(struct request_queue *q, u64 val);
+bool wbt_disabled(struct request_queue *);
void wbt_set_write_cache(struct request_queue *, bool);
@@ -125,6 +128,10 @@ static inline u64 wbt_default_latency_nsec(struct request_queue *q)
{
return 0;
}
+static inline bool wbt_disabled(struct request_queue *q)
+{
+ return true;
+}
#endif /* CONFIG_BLK_WBT */
diff --git a/block/blk.h b/block/blk.h
index d6ea0d1a6db0..4c3b3325219a 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -26,11 +26,6 @@ struct blk_flush_queue {
spinlock_t mq_flush_lock;
};
-extern struct kmem_cache *blk_requestq_cachep;
-extern struct kmem_cache *blk_requestq_srcu_cachep;
-extern struct kobj_type blk_queue_ktype;
-extern struct ida blk_queue_ida;
-
bool is_flush_rq(struct request *req);
struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
@@ -104,7 +99,7 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
return true;
}
-static inline bool __bvec_gap_to_prev(struct queue_limits *lim,
+static inline bool __bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{
return (offset & lim->virt_boundary_mask) ||
@@ -115,7 +110,7 @@ static inline bool __bvec_gap_to_prev(struct queue_limits *lim,
* Check if adding a bio_vec after bprv with offset would create a gap in
* the SG list. Most drivers don't care about this, but some do.
*/
-static inline bool bvec_gap_to_prev(struct queue_limits *lim,
+static inline bool bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{
if (!lim->virt_boundary_mask)
@@ -278,6 +273,7 @@ bool blk_bio_list_merge(struct request_queue *q, struct list_head *list,
void blk_insert_flush(struct request *rq);
int elevator_switch(struct request_queue *q, struct elevator_type *new_e);
+void elevator_disable(struct request_queue *q);
void elevator_exit(struct request_queue *q);
int elv_register_queue(struct request_queue *q, bool uevent);
void elv_unregister_queue(struct request_queue *q);
@@ -297,7 +293,7 @@ ssize_t part_timeout_store(struct device *, struct device_attribute *,
const char *, size_t);
static inline bool bio_may_exceed_limits(struct bio *bio,
- struct queue_limits *lim)
+ const struct queue_limits *lim)
{
switch (bio_op(bio)) {
case REQ_OP_DISCARD:
@@ -320,8 +316,9 @@ static inline bool bio_may_exceed_limits(struct bio *bio,
bio->bi_io_vec->bv_len + bio->bi_io_vec->bv_offset > PAGE_SIZE;
}
-struct bio *__bio_split_to_limits(struct bio *bio, struct queue_limits *lim,
- unsigned int *nr_segs);
+struct bio *__bio_split_to_limits(struct bio *bio,
+ const struct queue_limits *lim,
+ unsigned int *nr_segs);
int ll_back_merge_fn(struct request *req, struct bio *bio,
unsigned int nr_segs);
bool blk_attempt_req_merge(struct request_queue *q, struct request *rq,
@@ -331,6 +328,7 @@ void blk_rq_set_mixed_merge(struct request *rq);
bool blk_rq_merge_ok(struct request *rq, struct bio *bio);
enum elv_merge blk_try_merge(struct request *rq, struct bio *bio);
+void blk_set_default_limits(struct queue_limits *lim);
int blk_dev_init(void);
/*
@@ -427,15 +425,9 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
struct page *page, unsigned int len, unsigned int offset,
unsigned int max_sectors, bool *same_page);
-static inline struct kmem_cache *blk_get_queue_kmem_cache(bool srcu)
-{
- if (srcu)
- return blk_requestq_srcu_cachep;
- return blk_requestq_cachep;
-}
-struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu);
+struct request_queue *blk_alloc_queue(int node_id);
-int disk_scan_partitions(struct gendisk *disk, fmode_t mode);
+int disk_scan_partitions(struct gendisk *disk, fmode_t mode, void *owner);
int disk_alloc_events(struct gendisk *disk);
void disk_add_events(struct gendisk *disk);
diff --git a/block/bsg-lib.c b/block/bsg-lib.c
index d6f5dcdce748..435c32373cd6 100644
--- a/block/bsg-lib.c
+++ b/block/bsg-lib.c
@@ -325,6 +325,7 @@ void bsg_remove_queue(struct request_queue *q)
bsg_unregister_queue(bset->bd);
blk_mq_destroy_queue(q);
+ blk_put_queue(q);
blk_mq_free_tag_set(&bset->tag_set);
kfree(bset);
}
@@ -400,6 +401,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
return q;
out_cleanup_queue:
blk_mq_destroy_queue(q);
+ blk_put_queue(q);
out_queue:
blk_mq_free_tag_set(set);
out_tag_set:
diff --git a/block/bsg.c b/block/bsg.c
index 2ab1351eb082..8eba57b9bb46 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -175,8 +175,10 @@ static void bsg_device_release(struct device *dev)
void bsg_unregister_queue(struct bsg_device *bd)
{
- if (bd->queue->kobj.sd)
- sysfs_remove_link(&bd->queue->kobj, "bsg");
+ struct gendisk *disk = bd->queue->disk;
+
+ if (disk && disk->queue_kobj.sd)
+ sysfs_remove_link(&disk->queue_kobj, "bsg");
cdev_device_del(&bd->cdev, &bd->device);
put_device(&bd->device);
}
@@ -216,8 +218,9 @@ struct bsg_device *bsg_register_queue(struct request_queue *q,
if (ret)
goto out_put_device;
- if (q->kobj.sd) {
- ret = sysfs_create_link(&q->kobj, &bd->device.kobj, "bsg");
+ if (q->disk && q->disk->queue_kobj.sd) {
+ ret = sysfs_create_link(&q->disk->queue_kobj, &bd->device.kobj,
+ "bsg");
if (ret)
goto out_device_del;
}
diff --git a/block/elevator.c b/block/elevator.c
index bd71f0fc4e4b..adee58e48e2d 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -57,7 +57,7 @@ static LIST_HEAD(elv_list);
* Query io scheduler to see if the current process issuing bio may be
* merged with rq.
*/
-static int elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio)
+static bool elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio)
{
struct request_queue *q = rq->q;
struct elevator_queue *e = q->elevator;
@@ -65,7 +65,7 @@ static int elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio)
if (e->type->ops.allow_merge)
return e->type->ops.allow_merge(q, rq, bio);
- return 1;
+ return true;
}
/*
@@ -83,78 +83,45 @@ bool elv_bio_merge_ok(struct request *rq, struct bio *bio)
}
EXPORT_SYMBOL(elv_bio_merge_ok);
-static inline bool elv_support_features(unsigned int elv_features,
- unsigned int required_features)
+static inline bool elv_support_features(struct request_queue *q,
+ const struct elevator_type *e)
{
- return (required_features & elv_features) == required_features;
+ return (q->required_elevator_features & e->elevator_features) ==
+ q->required_elevator_features;
}
/**
- * elevator_match - Test an elevator name and features
+ * elevator_match - Check whether @e's name or alias matches @name
* @e: Scheduler to test
* @name: Elevator name to test
- * @required_features: Features that the elevator must provide
*
- * Return true if the elevator @e name matches @name and if @e provides all
- * the features specified by @required_features.
+ * Return true if the elevator @e's name or alias matches @name.
*/
-static bool elevator_match(const struct elevator_type *e, const char *name,
- unsigned int required_features)
+static bool elevator_match(const struct elevator_type *e, const char *name)
{
- if (!elv_support_features(e->elevator_features, required_features))
- return false;
- if (!strcmp(e->elevator_name, name))
- return true;
- if (e->elevator_alias && !strcmp(e->elevator_alias, name))
- return true;
-
- return false;
+ return !strcmp(e->elevator_name, name) ||
+ (e->elevator_alias && !strcmp(e->elevator_alias, name));
}
-/**
- * elevator_find - Find an elevator
- * @name: Name of the elevator to find
- * @required_features: Features that the elevator must provide
- *
- * Return the first registered scheduler with name @name and supporting the
- * features @required_features and NULL otherwise.
- */
-static struct elevator_type *elevator_find(const char *name,
- unsigned int required_features)
+static struct elevator_type *__elevator_find(const char *name)
{
struct elevator_type *e;
- list_for_each_entry(e, &elv_list, list) {
- if (elevator_match(e, name, required_features))
+ list_for_each_entry(e, &elv_list, list)
+ if (elevator_match(e, name))
return e;
- }
-
return NULL;
}
-static void elevator_put(struct elevator_type *e)
-{
- module_put(e->elevator_owner);
-}
-
-static struct elevator_type *elevator_get(struct request_queue *q,
- const char *name, bool try_loading)
+static struct elevator_type *elevator_find_get(struct request_queue *q,
+ const char *name)
{
struct elevator_type *e;
spin_lock(&elv_list_lock);
-
- e = elevator_find(name, q->required_elevator_features);
- if (!e && try_loading) {
- spin_unlock(&elv_list_lock);
- request_module("%s-iosched", name);
- spin_lock(&elv_list_lock);
- e = elevator_find(name, q->required_elevator_features);
- }
-
- if (e && !try_module_get(e->elevator_owner))
+ e = __elevator_find(name);
+ if (e && (!elv_support_features(q, e) || !elevator_tryget(e)))
e = NULL;
-
spin_unlock(&elv_list_lock);
return e;
}
@@ -170,6 +137,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q,
if (unlikely(!eq))
return NULL;
+ __elevator_get(e);
eq->type = e;
kobject_init(&eq->kobj, &elv_ktype);
mutex_init(&eq->sysfs_lock);
@@ -499,7 +467,7 @@ int elv_register_queue(struct request_queue *q, bool uevent)
lockdep_assert_held(&q->sysfs_lock);
- error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
+ error = kobject_add(&e->kobj, &q->disk->queue_kobj, "iosched");
if (!error) {
struct elv_fs_entry *attr = e->type->elevator_attrs;
if (attr) {
@@ -512,7 +480,7 @@ int elv_register_queue(struct request_queue *q, bool uevent)
if (uevent)
kobject_uevent(&e->kobj, KOBJ_ADD);
- e->registered = 1;
+ set_bit(ELEVATOR_FLAG_REGISTERED, &e->flags);
}
return error;
}
@@ -523,13 +491,9 @@ void elv_unregister_queue(struct request_queue *q)
lockdep_assert_held(&q->sysfs_lock);
- if (e && e->registered) {
- struct elevator_queue *e = q->elevator;
-
+ if (e && test_and_clear_bit(ELEVATOR_FLAG_REGISTERED, &e->flags)) {
kobject_uevent(&e->kobj, KOBJ_REMOVE);
kobject_del(&e->kobj);
-
- e->registered = 0;
}
}
@@ -555,7 +519,7 @@ int elv_register(struct elevator_type *e)
/* register, don't allow duplicate names */
spin_lock(&elv_list_lock);
- if (elevator_find(e->elevator_name, 0)) {
+ if (__elevator_find(e->elevator_name)) {
spin_unlock(&elv_list_lock);
kmem_cache_destroy(e->icq_cache);
return -EBUSY;
@@ -588,39 +552,6 @@ void elv_unregister(struct elevator_type *e)
}
EXPORT_SYMBOL_GPL(elv_unregister);
-static int elevator_switch_mq(struct request_queue *q,
- struct elevator_type *new_e)
-{
- int ret;
-
- lockdep_assert_held(&q->sysfs_lock);
-
- if (q->elevator) {
- elv_unregister_queue(q);
- elevator_exit(q);
- }
-
- ret = blk_mq_init_sched(q, new_e);
- if (ret)
- goto out;
-
- if (new_e) {
- ret = elv_register_queue(q, true);
- if (ret) {
- elevator_exit(q);
- goto out;
- }
- }
-
- if (new_e)
- blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name);
- else
- blk_add_trace_msg(q, "elv switch: none");
-
-out:
- return ret;
-}
-
static inline bool elv_support_iosched(struct request_queue *q)
{
if (!queue_is_mq(q) ||
@@ -642,7 +573,7 @@ static struct elevator_type *elevator_get_default(struct request_queue *q)
!blk_mq_is_shared_tags(q->tag_set->flags))
return NULL;
- return elevator_get(q, "mq-deadline", false);
+ return elevator_find_get(q, "mq-deadline");
}
/*
@@ -656,14 +587,13 @@ static struct elevator_type *elevator_get_by_features(struct request_queue *q)
spin_lock(&elv_list_lock);
list_for_each_entry(e, &elv_list, list) {
- if (elv_support_features(e->elevator_features,
- q->required_elevator_features)) {
+ if (elv_support_features(q, e)) {
found = e;
break;
}
}
- if (found && !try_module_get(found->elevator_owner))
+ if (found && !elevator_tryget(found))
found = NULL;
spin_unlock(&elv_list_lock);
@@ -713,115 +643,147 @@ void elevator_init_mq(struct request_queue *q)
if (err) {
pr_warn("\"%s\" elevator initialization failed, "
"falling back to \"none\"\n", e->elevator_name);
- elevator_put(e);
}
+
+ elevator_put(e);
}
/*
- * switch to new_e io scheduler. be careful not to introduce deadlocks -
- * we don't free the old io scheduler, before we have allocated what we
- * need for the new one. this way we have a chance of going back to the old
- * one, if the new one fails init for some reason.
+ * Switch to new_e io scheduler.
+ *
+ * If switching fails, we are most likely running out of memory and not able
+ * to restore the old io scheduler, so leaving the io scheduler being none.
*/
int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
{
- int err;
+ int ret;
lockdep_assert_held(&q->sysfs_lock);
blk_mq_freeze_queue(q);
blk_mq_quiesce_queue(q);
- err = elevator_switch_mq(q, new_e);
+ if (q->elevator) {
+ elv_unregister_queue(q);
+ elevator_exit(q);
+ }
+
+ ret = blk_mq_init_sched(q, new_e);
+ if (ret)
+ goto out_unfreeze;
+
+ ret = elv_register_queue(q, true);
+ if (ret) {
+ elevator_exit(q);
+ goto out_unfreeze;
+ }
+ blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name);
+out_unfreeze:
blk_mq_unquiesce_queue(q);
blk_mq_unfreeze_queue(q);
- return err;
+ if (ret) {
+ pr_warn("elv: switch to \"%s\" failed, falling back to \"none\"\n",
+ new_e->elevator_name);
+ }
+
+ return ret;
+}
+
+void elevator_disable(struct request_queue *q)
+{
+ lockdep_assert_held(&q->sysfs_lock);
+
+ blk_mq_freeze_queue(q);
+ blk_mq_quiesce_queue(q);
+
+ elv_unregister_queue(q);
+ elevator_exit(q);
+ blk_queue_flag_clear(QUEUE_FLAG_SQ_SCHED, q);
+ q->elevator = NULL;
+ q->nr_requests = q->tag_set->queue_depth;
+ blk_add_trace_msg(q, "elv switch: none");
+
+ blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
}
/*
* Switch this queue to the given IO scheduler.
*/
-static int __elevator_change(struct request_queue *q, const char *name)
+static int elevator_change(struct request_queue *q, const char *elevator_name)
{
- char elevator_name[ELV_NAME_MAX];
struct elevator_type *e;
+ int ret;
/* Make sure queue is not in the middle of being removed */
if (!blk_queue_registered(q))
return -ENOENT;
- /*
- * Special case for mq, turn off scheduling
- */
- if (!strncmp(name, "none", 4)) {
- if (!q->elevator)
- return 0;
- return elevator_switch(q, NULL);
+ if (!strncmp(elevator_name, "none", 4)) {
+ if (q->elevator)
+ elevator_disable(q);
+ return 0;
}
- strlcpy(elevator_name, name, sizeof(elevator_name));
- e = elevator_get(q, strstrip(elevator_name), true);
- if (!e)
- return -EINVAL;
-
- if (q->elevator &&
- elevator_match(q->elevator->type, elevator_name, 0)) {
- elevator_put(e);
+ if (q->elevator && elevator_match(q->elevator->type, elevator_name))
return 0;
- }
- return elevator_switch(q, e);
+ e = elevator_find_get(q, elevator_name);
+ if (!e) {
+ request_module("%s-iosched", elevator_name);
+ e = elevator_find_get(q, elevator_name);
+ if (!e)
+ return -EINVAL;
+ }
+ ret = elevator_switch(q, e);
+ elevator_put(e);
+ return ret;
}
-ssize_t elv_iosched_store(struct request_queue *q, const char *name,
+ssize_t elv_iosched_store(struct request_queue *q, const char *buf,
size_t count)
{
+ char elevator_name[ELV_NAME_MAX];
int ret;
if (!elv_support_iosched(q))
return count;
- ret = __elevator_change(q, name);
+ strlcpy(elevator_name, buf, sizeof(elevator_name));
+ ret = elevator_change(q, strstrip(elevator_name));
if (!ret)
return count;
-
return ret;
}
ssize_t elv_iosched_show(struct request_queue *q, char *name)
{
- struct elevator_queue *e = q->elevator;
- struct elevator_type *elv = NULL;
- struct elevator_type *__e;
+ struct elevator_queue *eq = q->elevator;
+ struct elevator_type *cur = NULL, *e;
int len = 0;
- if (!queue_is_mq(q))
+ if (!elv_support_iosched(q))
return sprintf(name, "none\n");
- if (!q->elevator)
+ if (!q->elevator) {
len += sprintf(name+len, "[none] ");
- else
- elv = e->type;
+ } else {
+ len += sprintf(name+len, "none ");
+ cur = eq->type;
+ }
spin_lock(&elv_list_lock);
- list_for_each_entry(__e, &elv_list, list) {
- if (elv && elevator_match(elv, __e->elevator_name, 0)) {
- len += sprintf(name+len, "[%s] ", elv->elevator_name);
- continue;
- }
- if (elv_support_iosched(q) &&
- elevator_match(__e, __e->elevator_name,
- q->required_elevator_features))
- len += sprintf(name+len, "%s ", __e->elevator_name);
+ list_for_each_entry(e, &elv_list, list) {
+ if (e == cur)
+ len += sprintf(name+len, "[%s] ", e->elevator_name);
+ else if (elv_support_features(q, e))
+ len += sprintf(name+len, "%s ", e->elevator_name);
}
spin_unlock(&elv_list_lock);
- if (q->elevator)
- len += sprintf(name+len, "none");
-
- len += sprintf(len+name, "\n");
+ len += sprintf(name+len, "\n");
return len;
}
diff --git a/block/elevator.h b/block/elevator.h
index 3f0593b3bf9d..774a8f6b99e6 100644
--- a/block/elevator.h
+++ b/block/elevator.h
@@ -84,6 +84,21 @@ struct elevator_type
struct list_head list;
};
+static inline bool elevator_tryget(struct elevator_type *e)
+{
+ return try_module_get(e->elevator_owner);
+}
+
+static inline void __elevator_get(struct elevator_type *e)
+{
+ __module_get(e->elevator_owner);
+}
+
+static inline void elevator_put(struct elevator_type *e)
+{
+ module_put(e->elevator_owner);
+}
+
#define ELV_HASH_BITS 6
void elv_rqhash_del(struct request_queue *q, struct request *rq);
@@ -100,10 +115,13 @@ struct elevator_queue
void *elevator_data;
struct kobject kobj;
struct mutex sysfs_lock;
- unsigned int registered:1;
+ unsigned long flags;
DECLARE_HASHTABLE(hash, ELV_HASH_BITS);
};
+#define ELEVATOR_FLAG_REGISTERED 0
+#define ELEVATOR_FLAG_DISABLE_WBT 1
+
/*
* block elevator interface
*/
diff --git a/block/fops.c b/block/fops.c
index b90742595317..50d245e8c913 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -405,12 +405,6 @@ static int blkdev_write_end(struct file *file, struct address_space *mapping,
return ret;
}
-static int blkdev_writepages(struct address_space *mapping,
- struct writeback_control *wbc)
-{
- return generic_writepages(mapping, wbc);
-}
-
const struct address_space_operations def_blk_aops = {
.dirty_folio = block_dirty_folio,
.invalidate_folio = block_invalidate_folio,
@@ -419,7 +413,6 @@ const struct address_space_operations def_blk_aops = {
.writepage = blkdev_writepage,
.write_begin = blkdev_write_begin,
.write_end = blkdev_write_end,
- .writepages = blkdev_writepages,
.direct_IO = blkdev_direct_IO,
.migrate_folio = buffer_migrate_folio_norefs,
.is_dirty_writeback = buffer_check_dirty_writeback,
diff --git a/block/genhd.c b/block/genhd.c
index 0f9769db2de8..08f76135a637 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -356,7 +356,7 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action)
}
EXPORT_SYMBOL_GPL(disk_uevent);
-int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
+int disk_scan_partitions(struct gendisk *disk, fmode_t mode, void *owner)
{
struct block_device *bdev;
@@ -366,6 +366,9 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
return -EINVAL;
if (disk->open_partitions)
return -EBUSY;
+ /* Someone else has bdev exclusively open? */
+ if (disk->part0->bd_holder && disk->part0->bd_holder != owner)
+ return -EBUSY;
set_bit(GD_NEED_PART_SCAN, &disk->state);
bdev = blkdev_get_by_dev(disk_devt(disk), mode, NULL);
@@ -479,10 +482,6 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
goto out_put_holder_dir;
}
- ret = bd_register_pending_holders(disk);
- if (ret < 0)
- goto out_put_slave_dir;
-
ret = blk_register_queue(disk);
if (ret)
goto out_put_slave_dir;
@@ -500,7 +499,7 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
bdev_add(disk->part0, ddev->devt);
if (get_capacity(disk))
- disk_scan_partitions(disk, FMODE_READ);
+ disk_scan_partitions(disk, FMODE_READ, NULL);
/*
* Announce the disk and partitions after all partitions are
@@ -530,6 +529,7 @@ out_unregister_queue:
rq_qos_exit(disk->queue);
out_put_slave_dir:
kobject_put(disk->slave_dir);
+ disk->slave_dir = NULL;
out_put_holder_dir:
kobject_put(disk->part0->bd_holder_dir);
out_del_integrity:
@@ -560,6 +560,11 @@ void blk_mark_disk_dead(struct gendisk *disk)
{
set_bit(GD_DEAD, &disk->state);
blk_queue_start_drain(disk->queue);
+
+ /*
+ * Stop buffered writers from dirtying pages that can't be written out.
+ */
+ set_capacity_and_notify(disk, 0);
}
EXPORT_SYMBOL_GPL(blk_mark_disk_dead);
@@ -629,6 +634,7 @@ void del_gendisk(struct gendisk *disk)
kobject_put(disk->part0->bd_holder_dir);
kobject_put(disk->slave_dir);
+ disk->slave_dir = NULL;
part_stat_set_all(disk->part0, 0);
disk->part0->bd_stamp = 0;
@@ -643,7 +649,9 @@ void del_gendisk(struct gendisk *disk)
blk_sync_queue(q);
blk_flush_integrity();
- blk_mq_cancel_work_sync(q);
+
+ if (queue_is_mq(q))
+ blk_mq_cancel_work_sync(q);
blk_mq_quiesce_queue(q);
if (q->elevator) {
@@ -1193,21 +1201,10 @@ struct class block_class = {
.dev_uevent = block_uevent,
};
-static char *block_devnode(struct device *dev, umode_t *mode,
- kuid_t *uid, kgid_t *gid)
-{
- struct gendisk *disk = dev_to_disk(dev);
-
- if (disk->fops->devnode)
- return disk->fops->devnode(disk, mode);
- return NULL;
-}
-
const struct device_type disk_type = {
.name = "disk",
.groups = disk_attr_groups,
.release = disk_release,
- .devnode = block_devnode,
};
#ifdef CONFIG_PROC_FS
@@ -1412,7 +1409,7 @@ struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass)
struct request_queue *q;
struct gendisk *disk;
- q = blk_alloc_queue(node, false);
+ q = blk_alloc_queue(node);
if (!q)
return NULL;
diff --git a/block/holder.c b/block/holder.c
index 5283bc804cc1..37d18c13d958 100644
--- a/block/holder.c
+++ b/block/holder.c
@@ -4,7 +4,7 @@
struct bd_holder_disk {
struct list_head list;
- struct block_device *bdev;
+ struct kobject *holder_dir;
int refcnt;
};
@@ -14,7 +14,7 @@ static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
struct bd_holder_disk *holder;
list_for_each_entry(holder, &disk->slave_bdevs, list)
- if (holder->bdev == bdev)
+ if (holder->holder_dir == bdev->bd_holder_dir)
return holder;
return NULL;
}
@@ -29,19 +29,6 @@ static void del_symlink(struct kobject *from, struct kobject *to)
sysfs_remove_link(from, kobject_name(to));
}
-static int __link_disk_holder(struct block_device *bdev, struct gendisk *disk)
-{
- int ret;
-
- ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
- if (ret)
- return ret;
- ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
- if (ret)
- del_symlink(disk->slave_dir, bdev_kobj(bdev));
- return ret;
-}
-
/**
* bd_link_disk_holder - create symlinks between holding disk and slave bdev
* @bdev: the claimed slave bdev
@@ -75,12 +62,30 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
struct bd_holder_disk *holder;
int ret = 0;
- mutex_lock(&disk->open_mutex);
+ if (WARN_ON_ONCE(!disk->slave_dir))
+ return -EINVAL;
+
+ if (bdev->bd_disk == disk)
+ return -EINVAL;
+
+ /*
+ * del_gendisk drops the initial reference to bd_holder_dir, so we
+ * need to keep our own here to allow for cleanup past that point.
+ */
+ mutex_lock(&bdev->bd_disk->open_mutex);
+ if (!disk_live(bdev->bd_disk)) {
+ mutex_unlock(&bdev->bd_disk->open_mutex);
+ return -ENODEV;
+ }
+ kobject_get(bdev->bd_holder_dir);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
+ mutex_lock(&disk->open_mutex);
WARN_ON_ONCE(!bdev->bd_holder);
holder = bd_find_holder_disk(bdev, disk);
if (holder) {
+ kobject_put(bdev->bd_holder_dir);
holder->refcnt++;
goto out_unlock;
}
@@ -92,36 +97,32 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
}
INIT_LIST_HEAD(&holder->list);
- holder->bdev = bdev;
holder->refcnt = 1;
- if (disk->slave_dir) {
- ret = __link_disk_holder(bdev, disk);
- if (ret) {
- kfree(holder);
- goto out_unlock;
- }
- }
+ holder->holder_dir = bdev->bd_holder_dir;
+ ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
+ if (ret)
+ goto out_free_holder;
+ ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
+ if (ret)
+ goto out_del_symlink;
list_add(&holder->list, &disk->slave_bdevs);
- /*
- * del_gendisk drops the initial reference to bd_holder_dir, so we need
- * to keep our own here to allow for cleanup past that point.
- */
- kobject_get(bdev->bd_holder_dir);
+ mutex_unlock(&disk->open_mutex);
+ return 0;
+
+out_del_symlink:
+ del_symlink(disk->slave_dir, bdev_kobj(bdev));
+out_free_holder:
+ kfree(holder);
out_unlock:
mutex_unlock(&disk->open_mutex);
+ if (ret)
+ kobject_put(bdev->bd_holder_dir);
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
-static void __unlink_disk_holder(struct block_device *bdev,
- struct gendisk *disk)
-{
- del_symlink(disk->slave_dir, bdev_kobj(bdev));
- del_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
-}
-
/**
* bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
* @bdev: the calimed slave bdev
@@ -136,36 +137,18 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
+ if (WARN_ON_ONCE(!disk->slave_dir))
+ return;
+
mutex_lock(&disk->open_mutex);
holder = bd_find_holder_disk(bdev, disk);
if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
- if (disk->slave_dir)
- __unlink_disk_holder(bdev, disk);
- kobject_put(bdev->bd_holder_dir);
+ del_symlink(disk->slave_dir, bdev_kobj(bdev));
+ del_symlink(holder->holder_dir, &disk_to_dev(disk)->kobj);
+ kobject_put(holder->holder_dir);
list_del_init(&holder->list);
kfree(holder);
}
mutex_unlock(&disk->open_mutex);
}
EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
-
-int bd_register_pending_holders(struct gendisk *disk)
-{
- struct bd_holder_disk *holder;
- int ret;
-
- mutex_lock(&disk->open_mutex);
- list_for_each_entry(holder, &disk->slave_bdevs, list) {
- ret = __link_disk_holder(holder->bdev, disk);
- if (ret)
- goto out_undo;
- }
- mutex_unlock(&disk->open_mutex);
- return 0;
-
-out_undo:
- list_for_each_entry_continue_reverse(holder, &disk->slave_bdevs, list)
- __unlink_disk_holder(holder->bdev, disk);
- mutex_unlock(&disk->open_mutex);
- return ret;
-}
diff --git a/block/ioctl.c b/block/ioctl.c
index 60121e89052b..96617512982e 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -467,9 +467,10 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
* user space. Note the separate arg/argp parameters that are needed
* to deal with the compat_ptr() conversion.
*/
-static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned cmd, unsigned long arg, void __user *argp)
+static int blkdev_common_ioctl(struct file *file, fmode_t mode, unsigned cmd,
+ unsigned long arg, void __user *argp)
{
+ struct block_device *bdev = I_BDEV(file->f_mapping->host);
unsigned int max_sectors;
switch (cmd) {
@@ -527,7 +528,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
return -EACCES;
if (bdev_is_partition(bdev))
return -EINVAL;
- return disk_scan_partitions(bdev->bd_disk, mode & ~FMODE_EXCL);
+ return disk_scan_partitions(bdev->bd_disk, mode & ~FMODE_EXCL,
+ file);
case BLKTRACESTART:
case BLKTRACESTOP:
case BLKTRACETEARDOWN:
@@ -605,7 +607,7 @@ long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
- ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
+ ret = blkdev_common_ioctl(file, mode, cmd, arg, argp);
if (ret != -ENOIOCTLCMD)
return ret;
@@ -674,7 +676,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
- ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
+ ret = blkdev_common_ioctl(file, mode, cmd, arg, argp);
if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
diff --git a/block/mq-deadline.c b/block/mq-deadline.c
index 5639921dfa92..f10c2a0d18d4 100644
--- a/block/mq-deadline.c
+++ b/block/mq-deadline.c
@@ -131,6 +131,20 @@ static u8 dd_rq_ioclass(struct request *rq)
}
/*
+ * get the request before `rq' in sector-sorted order
+ */
+static inline struct request *
+deadline_earlier_request(struct request *rq)
+{
+ struct rb_node *node = rb_prev(&rq->rb_node);
+
+ if (node)
+ return rb_entry_rq(node);
+
+ return NULL;
+}
+
+/*
* get the request after `rq' in sector-sorted order
*/
static inline struct request *
@@ -278,6 +292,39 @@ static inline int deadline_check_fifo(struct dd_per_prio *per_prio,
}
/*
+ * Check if rq has a sequential request preceding it.
+ */
+static bool deadline_is_seq_write(struct deadline_data *dd, struct request *rq)
+{
+ struct request *prev = deadline_earlier_request(rq);
+
+ if (!prev)
+ return false;
+
+ return blk_rq_pos(prev) + blk_rq_sectors(prev) == blk_rq_pos(rq);
+}
+
+/*
+ * Skip all write requests that are sequential from @rq, even if we cross
+ * a zone boundary.
+ */
+static struct request *deadline_skip_seq_writes(struct deadline_data *dd,
+ struct request *rq)
+{
+ sector_t pos = blk_rq_pos(rq);
+ sector_t skipped_sectors = 0;
+
+ while (rq) {
+ if (blk_rq_pos(rq) != pos + skipped_sectors)
+ break;
+ skipped_sectors += blk_rq_sectors(rq);
+ rq = deadline_latter_request(rq);
+ }
+
+ return rq;
+}
+
+/*
* For the specified data direction, return the next request to
* dispatch using arrival ordered lists.
*/
@@ -297,11 +344,16 @@ deadline_fifo_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
/*
* Look for a write request that can be dispatched, that is one with
- * an unlocked target zone.
+ * an unlocked target zone. For some HDDs, breaking a sequential
+ * write stream can lead to lower throughput, so make sure to preserve
+ * sequential write streams, even if that stream crosses into the next
+ * zones and these zones are unlocked.
*/
spin_lock_irqsave(&dd->zone_lock, flags);
list_for_each_entry(rq, &per_prio->fifo_list[DD_WRITE], queuelist) {
- if (blk_req_can_dispatch_to_zone(rq))
+ if (blk_req_can_dispatch_to_zone(rq) &&
+ (blk_queue_nonrot(rq->q) ||
+ !deadline_is_seq_write(dd, rq)))
goto out;
}
rq = NULL;
@@ -331,13 +383,19 @@ deadline_next_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
/*
* Look for a write request that can be dispatched, that is one with
- * an unlocked target zone.
+ * an unlocked target zone. For some HDDs, breaking a sequential
+ * write stream can lead to lower throughput, so make sure to preserve
+ * sequential write streams, even if that stream crosses into the next
+ * zones and these zones are unlocked.
*/
spin_lock_irqsave(&dd->zone_lock, flags);
while (rq) {
if (blk_req_can_dispatch_to_zone(rq))
break;
- rq = deadline_latter_request(rq);
+ if (blk_queue_nonrot(rq->q))
+ rq = deadline_latter_request(rq);
+ else
+ rq = deadline_skip_seq_writes(dd, rq);
}
spin_unlock_irqrestore(&dd->zone_lock, flags);
@@ -789,6 +847,18 @@ static void dd_prepare_request(struct request *rq)
rq->elv.priv[0] = NULL;
}
+static bool dd_has_write_work(struct blk_mq_hw_ctx *hctx)
+{
+ struct deadline_data *dd = hctx->queue->elevator->elevator_data;
+ enum dd_prio p;
+
+ for (p = 0; p <= DD_PRIO_MAX; p++)
+ if (!list_empty_careful(&dd->per_prio[p].fifo_list[DD_WRITE]))
+ return true;
+
+ return false;
+}
+
/*
* Callback from inside blk_mq_free_request().
*
@@ -828,9 +898,10 @@ static void dd_finish_request(struct request *rq)
spin_lock_irqsave(&dd->zone_lock, flags);
blk_req_zone_write_unlock(rq);
- if (!list_empty(&per_prio->fifo_list[DD_WRITE]))
- blk_mq_sched_mark_restart_hctx(rq->mq_hctx);
spin_unlock_irqrestore(&dd->zone_lock, flags);
+
+ if (dd_has_write_work(rq->mq_hctx))
+ blk_mq_sched_mark_restart_hctx(rq->mq_hctx);
}
}
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 2c5327a0543a..463873f61e01 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -87,8 +87,8 @@ struct opal_dev {
u64 lowest_lba;
size_t pos;
- u8 cmd[IO_BUFFER_LENGTH];
- u8 resp[IO_BUFFER_LENGTH];
+ u8 *cmd;
+ u8 *resp;
struct parsed_resp parsed;
size_t prev_d_len;
@@ -2175,6 +2175,8 @@ void free_opal_dev(struct opal_dev *dev)
return;
clean_opal_dev(dev);
+ kfree(dev->resp);
+ kfree(dev->cmd);
kfree(dev);
}
EXPORT_SYMBOL(free_opal_dev);
@@ -2187,6 +2189,18 @@ struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
if (!dev)
return NULL;
+ /*
+ * Presumably DMA-able buffers must be cache-aligned. Kmalloc makes
+ * sure the allocated buffer is DMA-safe in that regard.
+ */
+ dev->cmd = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
+ if (!dev->cmd)
+ goto err_free_dev;
+
+ dev->resp = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
+ if (!dev->resp)
+ goto err_free_cmd;
+
INIT_LIST_HEAD(&dev->unlk_lst);
mutex_init(&dev->dev_lock);
dev->flags = 0;
@@ -2194,11 +2208,21 @@ struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
dev->send_recv = send_recv;
if (check_opal_support(dev) != 0) {
pr_debug("Opal is not supported on this device\n");
- kfree(dev);
- return NULL;
+ goto err_free_resp;
}
return dev;
+
+err_free_resp:
+ kfree(dev->resp);
+
+err_free_cmd:
+ kfree(dev->cmd);
+
+err_free_dev:
+ kfree(dev);
+
+ return NULL;
}
EXPORT_SYMBOL(init_opal_dev);
@@ -2437,6 +2461,44 @@ static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
}
+static void opal_lock_check_for_saved_key(struct opal_dev *dev,
+ struct opal_lock_unlock *lk_unlk)
+{
+ struct opal_suspend_data *iter;
+
+ if (lk_unlk->l_state != OPAL_LK ||
+ lk_unlk->session.opal_key.key_len > 0)
+ return;
+
+ /*
+ * Usually when closing a crypto device (eg: dm-crypt with LUKS) the
+ * volume key is not required, as it requires root privileges anyway,
+ * and root can deny access to a disk in many ways regardless.
+ * Requiring the volume key to lock the device is a peculiarity of the
+ * OPAL specification. Given we might already have saved the key if
+ * the user requested it via the 'IOC_OPAL_SAVE' ioctl, we can use
+ * that key to lock the device if no key was provided here, the
+ * locking range matches and the appropriate flag was passed with
+ * 'IOC_OPAL_SAVE'.
+ * This allows integrating OPAL with tools and libraries that are used
+ * to the common behaviour and do not ask for the volume key when
+ * closing a device.
+ */
+ setup_opal_dev(dev);
+ list_for_each_entry(iter, &dev->unlk_lst, node) {
+ if ((iter->unlk.flags & OPAL_SAVE_FOR_LOCK) &&
+ iter->lr == lk_unlk->session.opal_key.lr &&
+ iter->unlk.session.opal_key.key_len > 0) {
+ lk_unlk->session.opal_key.key_len =
+ iter->unlk.session.opal_key.key_len;
+ memcpy(lk_unlk->session.opal_key.key,
+ iter->unlk.session.opal_key.key,
+ iter->unlk.session.opal_key.key_len);
+ break;
+ }
+ }
+}
+
static int opal_lock_unlock(struct opal_dev *dev,
struct opal_lock_unlock *lk_unlk)
{
@@ -2446,6 +2508,7 @@ static int opal_lock_unlock(struct opal_dev *dev,
return -EINVAL;
mutex_lock(&dev->dev_lock);
+ opal_lock_check_for_saved_key(dev, lk_unlk);
ret = __opal_lock_unlock(dev, lk_unlk);
mutex_unlock(&dev->dev_lock);
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 3285e3af43e1..e75728f87ce5 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -253,7 +253,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req)
ps_end = ctx->key_size - req->src_len - 2;
req_ctx->in_buf[0] = 0x02;
for (i = 1; i < ps_end; i++)
- req_ctx->in_buf[i] = 1 + prandom_u32_max(255);
+ req_ctx->in_buf[i] = get_random_u32_inclusive(1, 255);
req_ctx->in_buf[ps_end] = 0x00;
pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf,
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index bcd059caa1c8..589189c9fced 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -766,7 +766,7 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls,
struct iov_iter input;
int err;
- iov_iter_kvec(&input, WRITE, inputs, nr_inputs, src_total_len);
+ iov_iter_kvec(&input, ITER_SOURCE, inputs, nr_inputs, src_total_len);
err = build_test_sglist(&tsgls->src, cfg->src_divs, alignmask,
cfg->inplace_mode != OUT_OF_PLACE ?
max(dst_total_len, src_total_len) :
@@ -855,9 +855,9 @@ static int prepare_keybuf(const u8 *key, unsigned int ksize,
/* Generate a random length in range [0, max_len], but prefer smaller values */
static unsigned int generate_random_length(unsigned int max_len)
{
- unsigned int len = prandom_u32_max(max_len + 1);
+ unsigned int len = get_random_u32_below(max_len + 1);
- switch (prandom_u32_max(4)) {
+ switch (get_random_u32_below(4)) {
case 0:
return len % 64;
case 1:
@@ -874,14 +874,14 @@ static void flip_random_bit(u8 *buf, size_t size)
{
size_t bitpos;
- bitpos = prandom_u32_max(size * 8);
+ bitpos = get_random_u32_below(size * 8);
buf[bitpos / 8] ^= 1 << (bitpos % 8);
}
/* Flip a random byte in the given nonempty data buffer */
static void flip_random_byte(u8 *buf, size_t size)
{
- buf[prandom_u32_max(size)] ^= 0xff;
+ buf[get_random_u32_below(size)] ^= 0xff;
}
/* Sometimes make some random changes to the given nonempty data buffer */
@@ -891,15 +891,15 @@ static void mutate_buffer(u8 *buf, size_t size)
size_t i;
/* Sometimes flip some bits */
- if (prandom_u32_max(4) == 0) {
- num_flips = min_t(size_t, 1 << prandom_u32_max(8), size * 8);
+ if (get_random_u32_below(4) == 0) {
+ num_flips = min_t(size_t, 1 << get_random_u32_below(8), size * 8);
for (i = 0; i < num_flips; i++)
flip_random_bit(buf, size);
}
/* Sometimes flip some bytes */
- if (prandom_u32_max(4) == 0) {
- num_flips = min_t(size_t, 1 << prandom_u32_max(8), size);
+ if (get_random_u32_below(4) == 0) {
+ num_flips = min_t(size_t, 1 << get_random_u32_below(8), size);
for (i = 0; i < num_flips; i++)
flip_random_byte(buf, size);
}
@@ -915,11 +915,11 @@ static void generate_random_bytes(u8 *buf, size_t count)
if (count == 0)
return;
- switch (prandom_u32_max(8)) { /* Choose a generation strategy */
+ switch (get_random_u32_below(8)) { /* Choose a generation strategy */
case 0:
case 1:
/* All the same byte, plus optional mutations */
- switch (prandom_u32_max(4)) {
+ switch (get_random_u32_below(4)) {
case 0:
b = 0x00;
break;
@@ -959,24 +959,24 @@ static char *generate_random_sgl_divisions(struct test_sg_division *divs,
unsigned int this_len;
const char *flushtype_str;
- if (div == &divs[max_divs - 1] || prandom_u32_max(2) == 0)
+ if (div == &divs[max_divs - 1] || get_random_u32_below(2) == 0)
this_len = remaining;
else
- this_len = 1 + prandom_u32_max(remaining);
+ this_len = get_random_u32_inclusive(1, remaining);
div->proportion_of_total = this_len;
- if (prandom_u32_max(4) == 0)
- div->offset = (PAGE_SIZE - 128) + prandom_u32_max(128);
- else if (prandom_u32_max(2) == 0)
- div->offset = prandom_u32_max(32);
+ if (get_random_u32_below(4) == 0)
+ div->offset = get_random_u32_inclusive(PAGE_SIZE - 128, PAGE_SIZE - 1);
+ else if (get_random_u32_below(2) == 0)
+ div->offset = get_random_u32_below(32);
else
- div->offset = prandom_u32_max(PAGE_SIZE);
- if (prandom_u32_max(8) == 0)
+ div->offset = get_random_u32_below(PAGE_SIZE);
+ if (get_random_u32_below(8) == 0)
div->offset_relative_to_alignmask = true;
div->flush_type = FLUSH_TYPE_NONE;
if (gen_flushes) {
- switch (prandom_u32_max(4)) {
+ switch (get_random_u32_below(4)) {
case 0:
div->flush_type = FLUSH_TYPE_REIMPORT;
break;
@@ -988,7 +988,7 @@ static char *generate_random_sgl_divisions(struct test_sg_division *divs,
if (div->flush_type != FLUSH_TYPE_NONE &&
!(req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) &&
- prandom_u32_max(2) == 0)
+ get_random_u32_below(2) == 0)
div->nosimd = true;
switch (div->flush_type) {
@@ -1035,7 +1035,7 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
p += scnprintf(p, end - p, "random:");
- switch (prandom_u32_max(4)) {
+ switch (get_random_u32_below(4)) {
case 0:
case 1:
cfg->inplace_mode = OUT_OF_PLACE;
@@ -1050,12 +1050,12 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
break;
}
- if (prandom_u32_max(2) == 0) {
+ if (get_random_u32_below(2) == 0) {
cfg->req_flags |= CRYPTO_TFM_REQ_MAY_SLEEP;
p += scnprintf(p, end - p, " may_sleep");
}
- switch (prandom_u32_max(4)) {
+ switch (get_random_u32_below(4)) {
case 0:
cfg->finalization_type = FINALIZATION_TYPE_FINAL;
p += scnprintf(p, end - p, " use_final");
@@ -1071,7 +1071,7 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
}
if (!(cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) &&
- prandom_u32_max(2) == 0) {
+ get_random_u32_below(2) == 0) {
cfg->nosimd = true;
p += scnprintf(p, end - p, " nosimd");
}
@@ -1084,7 +1084,7 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
cfg->req_flags);
p += scnprintf(p, end - p, "]");
- if (cfg->inplace_mode == OUT_OF_PLACE && prandom_u32_max(2) == 0) {
+ if (cfg->inplace_mode == OUT_OF_PLACE && get_random_u32_below(2) == 0) {
p += scnprintf(p, end - p, " dst_divs=[");
p = generate_random_sgl_divisions(cfg->dst_divs,
ARRAY_SIZE(cfg->dst_divs),
@@ -1093,13 +1093,13 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
p += scnprintf(p, end - p, "]");
}
- if (prandom_u32_max(2) == 0) {
- cfg->iv_offset = 1 + prandom_u32_max(MAX_ALGAPI_ALIGNMASK);
+ if (get_random_u32_below(2) == 0) {
+ cfg->iv_offset = get_random_u32_inclusive(1, MAX_ALGAPI_ALIGNMASK);
p += scnprintf(p, end - p, " iv_offset=%u", cfg->iv_offset);
}
- if (prandom_u32_max(2) == 0) {
- cfg->key_offset = 1 + prandom_u32_max(MAX_ALGAPI_ALIGNMASK);
+ if (get_random_u32_below(2) == 0) {
+ cfg->key_offset = get_random_u32_inclusive(1, MAX_ALGAPI_ALIGNMASK);
p += scnprintf(p, end - p, " key_offset=%u", cfg->key_offset);
}
@@ -1180,7 +1180,7 @@ static int build_hash_sglist(struct test_sglist *tsgl,
kv.iov_base = (void *)vec->plaintext;
kv.iov_len = vec->psize;
- iov_iter_kvec(&input, WRITE, &kv, 1, vec->psize);
+ iov_iter_kvec(&input, ITER_SOURCE, &kv, 1, vec->psize);
return build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
&input, divs);
}
@@ -1652,8 +1652,8 @@ static void generate_random_hash_testvec(struct shash_desc *desc,
vec->ksize = 0;
if (maxkeysize) {
vec->ksize = maxkeysize;
- if (prandom_u32_max(4) == 0)
- vec->ksize = 1 + prandom_u32_max(maxkeysize);
+ if (get_random_u32_below(4) == 0)
+ vec->ksize = get_random_u32_inclusive(1, maxkeysize);
generate_random_bytes((u8 *)vec->key, vec->ksize);
vec->setkey_error = crypto_shash_setkey(desc->tfm, vec->key,
@@ -2218,13 +2218,13 @@ static void mutate_aead_message(struct aead_testvec *vec, bool aad_iv,
const unsigned int aad_tail_size = aad_iv ? ivsize : 0;
const unsigned int authsize = vec->clen - vec->plen;
- if (prandom_u32_max(2) == 0 && vec->alen > aad_tail_size) {
+ if (get_random_u32_below(2) == 0 && vec->alen > aad_tail_size) {
/* Mutate the AAD */
flip_random_bit((u8 *)vec->assoc, vec->alen - aad_tail_size);
- if (prandom_u32_max(2) == 0)
+ if (get_random_u32_below(2) == 0)
return;
}
- if (prandom_u32_max(2) == 0) {
+ if (get_random_u32_below(2) == 0) {
/* Mutate auth tag (assuming it's at the end of ciphertext) */
flip_random_bit((u8 *)vec->ctext + vec->plen, authsize);
} else {
@@ -2249,7 +2249,7 @@ static void generate_aead_message(struct aead_request *req,
const unsigned int ivsize = crypto_aead_ivsize(tfm);
const unsigned int authsize = vec->clen - vec->plen;
const bool inauthentic = (authsize >= MIN_COLLISION_FREE_AUTHSIZE) &&
- (prefer_inauthentic || prandom_u32_max(4) == 0);
+ (prefer_inauthentic || get_random_u32_below(4) == 0);
/* Generate the AAD. */
generate_random_bytes((u8 *)vec->assoc, vec->alen);
@@ -2257,7 +2257,7 @@ static void generate_aead_message(struct aead_request *req,
/* Avoid implementation-defined behavior. */
memcpy((u8 *)vec->assoc + vec->alen - ivsize, vec->iv, ivsize);
- if (inauthentic && prandom_u32_max(2) == 0) {
+ if (inauthentic && get_random_u32_below(2) == 0) {
/* Generate a random ciphertext. */
generate_random_bytes((u8 *)vec->ctext, vec->clen);
} else {
@@ -2321,8 +2321,8 @@ static void generate_random_aead_testvec(struct aead_request *req,
/* Key: length in [0, maxkeysize], but usually choose maxkeysize */
vec->klen = maxkeysize;
- if (prandom_u32_max(4) == 0)
- vec->klen = prandom_u32_max(maxkeysize + 1);
+ if (get_random_u32_below(4) == 0)
+ vec->klen = get_random_u32_below(maxkeysize + 1);
generate_random_bytes((u8 *)vec->key, vec->klen);
vec->setkey_error = crypto_aead_setkey(tfm, vec->key, vec->klen);
@@ -2331,8 +2331,8 @@ static void generate_random_aead_testvec(struct aead_request *req,
/* Tag length: in [0, maxauthsize], but usually choose maxauthsize */
authsize = maxauthsize;
- if (prandom_u32_max(4) == 0)
- authsize = prandom_u32_max(maxauthsize + 1);
+ if (get_random_u32_below(4) == 0)
+ authsize = get_random_u32_below(maxauthsize + 1);
if (prefer_inauthentic && authsize < MIN_COLLISION_FREE_AUTHSIZE)
authsize = MIN_COLLISION_FREE_AUTHSIZE;
if (WARN_ON(authsize > maxdatasize))
@@ -2342,7 +2342,7 @@ static void generate_random_aead_testvec(struct aead_request *req,
/* AAD, plaintext, and ciphertext lengths */
total_len = generate_random_length(maxdatasize);
- if (prandom_u32_max(4) == 0)
+ if (get_random_u32_below(4) == 0)
vec->alen = 0;
else
vec->alen = generate_random_length(total_len);
@@ -2958,8 +2958,8 @@ static void generate_random_cipher_testvec(struct skcipher_request *req,
/* Key: length in [0, maxkeysize], but usually choose maxkeysize */
vec->klen = maxkeysize;
- if (prandom_u32_max(4) == 0)
- vec->klen = prandom_u32_max(maxkeysize + 1);
+ if (get_random_u32_below(4) == 0)
+ vec->klen = get_random_u32_below(maxkeysize + 1);
generate_random_bytes((u8 *)vec->key, vec->klen);
vec->setkey_error = crypto_skcipher_setkey(tfm, vec->key, vec->klen);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 19ee995bd0ae..968bd0a6fd78 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -99,6 +99,8 @@ source "drivers/media/Kconfig"
source "drivers/video/Kconfig"
+source "drivers/accel/Kconfig"
+
source "sound/Kconfig"
source "drivers/hid/Kconfig"
diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig
new file mode 100644
index 000000000000..c9ce849b2984
--- /dev/null
+++ b/drivers/accel/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Compute Acceleration device configuration
+#
+# This framework provides support for compute acceleration devices, such
+# as, but not limited to, Machine-Learning and Deep-Learning acceleration
+# devices
+#
+menuconfig DRM_ACCEL
+ bool "Compute Acceleration Framework"
+ depends on DRM
+ help
+ Framework for device drivers of compute acceleration devices, such
+ as, but not limited to, Machine-Learning and Deep-Learning
+ acceleration devices.
+ If you say Y here, you need to select the module that's right for
+ your acceleration device from the list below.
+ This framework is integrated with the DRM subsystem as compute
+ accelerators and GPUs share a lot in common and can use almost the
+ same infrastructure code.
+ Having said that, acceleration devices will have a different
+ major number than GPUs, and will be exposed to user-space using
+ different device files, called accel/accel* (in /dev, sysfs
+ and debugfs).
diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c
new file mode 100644
index 000000000000..a5ee84a4017a
--- /dev/null
+++ b/drivers/accel/drm_accel.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2022 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+
+#include <drm/drm_accel.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_print.h>
+
+static DEFINE_SPINLOCK(accel_minor_lock);
+static struct idr accel_minors_idr;
+
+static struct dentry *accel_debugfs_root;
+static struct class *accel_class;
+
+static struct device_type accel_sysfs_device_minor = {
+ .name = "accel_minor"
+};
+
+static char *accel_devnode(struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "accel/%s", dev_name(dev));
+}
+
+static int accel_sysfs_init(void)
+{
+ accel_class = class_create(THIS_MODULE, "accel");
+ if (IS_ERR(accel_class))
+ return PTR_ERR(accel_class);
+
+ accel_class->devnode = accel_devnode;
+
+ return 0;
+}
+
+static void accel_sysfs_destroy(void)
+{
+ if (IS_ERR_OR_NULL(accel_class))
+ return;
+ class_destroy(accel_class);
+ accel_class = NULL;
+}
+
+static int accel_name_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_minor *minor = node->minor;
+ struct drm_device *dev = minor->dev;
+ struct drm_master *master;
+
+ mutex_lock(&dev->master_mutex);
+ master = dev->master;
+ seq_printf(m, "%s", dev->driver->name);
+ if (dev->dev)
+ seq_printf(m, " dev=%s", dev_name(dev->dev));
+ if (master && master->unique)
+ seq_printf(m, " master=%s", master->unique);
+ if (dev->unique)
+ seq_printf(m, " unique=%s", dev->unique);
+ seq_puts(m, "\n");
+ mutex_unlock(&dev->master_mutex);
+
+ return 0;
+}
+
+static const struct drm_info_list accel_debugfs_list[] = {
+ {"name", accel_name_info, 0}
+};
+#define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list)
+
+/**
+ * accel_debugfs_init() - Initialize debugfs for accel minor
+ * @minor: Pointer to the drm_minor instance.
+ * @minor_id: The minor's id
+ *
+ * This function initializes the drm minor's debugfs members and creates
+ * a root directory for the minor in debugfs. It also creates common files
+ * for accelerators and calls the driver's debugfs init callback.
+ */
+void accel_debugfs_init(struct drm_minor *minor, int minor_id)
+{
+ struct drm_device *dev = minor->dev;
+ char name[64];
+
+ INIT_LIST_HEAD(&minor->debugfs_list);
+ mutex_init(&minor->debugfs_lock);
+ sprintf(name, "%d", minor_id);
+ minor->debugfs_root = debugfs_create_dir(name, accel_debugfs_root);
+
+ drm_debugfs_create_files(accel_debugfs_list, ACCEL_DEBUGFS_ENTRIES,
+ minor->debugfs_root, minor);
+
+ if (dev->driver->debugfs_init)
+ dev->driver->debugfs_init(minor);
+}
+
+/**
+ * accel_set_device_instance_params() - Set some device parameters for accel device
+ * @kdev: Pointer to the device instance.
+ * @index: The minor's index
+ *
+ * This function creates the dev_t of the device using the accel major and
+ * the device's minor number. In addition, it sets the class and type of the
+ * device instance to the accel sysfs class and device type, respectively.
+ */
+void accel_set_device_instance_params(struct device *kdev, int index)
+{
+ kdev->devt = MKDEV(ACCEL_MAJOR, index);
+ kdev->class = accel_class;
+ kdev->type = &accel_sysfs_device_minor;
+}
+
+/**
+ * accel_minor_alloc() - Allocates a new accel minor
+ *
+ * This function access the accel minors idr and allocates from it
+ * a new id to represent a new accel minor
+ *
+ * Return: A new id on success or error code in case idr_alloc failed
+ */
+int accel_minor_alloc(void)
+{
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&accel_minor_lock, flags);
+ r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT);
+ spin_unlock_irqrestore(&accel_minor_lock, flags);
+
+ return r;
+}
+
+/**
+ * accel_minor_remove() - Remove an accel minor
+ * @index: The minor id to remove.
+ *
+ * This function access the accel minors idr and removes from
+ * it the member with the id that is passed to this function.
+ */
+void accel_minor_remove(int index)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&accel_minor_lock, flags);
+ idr_remove(&accel_minors_idr, index);
+ spin_unlock_irqrestore(&accel_minor_lock, flags);
+}
+
+/**
+ * accel_minor_replace() - Replace minor pointer in accel minors idr.
+ * @minor: Pointer to the new minor.
+ * @index: The minor id to replace.
+ *
+ * This function access the accel minors idr structure and replaces the pointer
+ * that is associated with an existing id. Because the minor pointer can be
+ * NULL, we need to explicitly pass the index.
+ *
+ * Return: 0 for success, negative value for error
+ */
+void accel_minor_replace(struct drm_minor *minor, int index)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&accel_minor_lock, flags);
+ idr_replace(&accel_minors_idr, minor, index);
+ spin_unlock_irqrestore(&accel_minor_lock, flags);
+}
+
+/*
+ * Looks up the given minor-ID and returns the respective DRM-minor object. The
+ * refence-count of the underlying device is increased so you must release this
+ * object with accel_minor_release().
+ *
+ * The object can be only a drm_minor that represents an accel device.
+ *
+ * As long as you hold this minor, it is guaranteed that the object and the
+ * minor->dev pointer will stay valid! However, the device may get unplugged and
+ * unregistered while you hold the minor.
+ */
+static struct drm_minor *accel_minor_acquire(unsigned int minor_id)
+{
+ struct drm_minor *minor;
+ unsigned long flags;
+
+ spin_lock_irqsave(&accel_minor_lock, flags);
+ minor = idr_find(&accel_minors_idr, minor_id);
+ if (minor)
+ drm_dev_get(minor->dev);
+ spin_unlock_irqrestore(&accel_minor_lock, flags);
+
+ if (!minor) {
+ return ERR_PTR(-ENODEV);
+ } else if (drm_dev_is_unplugged(minor->dev)) {
+ drm_dev_put(minor->dev);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return minor;
+}
+
+static void accel_minor_release(struct drm_minor *minor)
+{
+ drm_dev_put(minor->dev);
+}
+
+/**
+ * accel_open - open method for ACCEL file
+ * @inode: device inode
+ * @filp: file pointer.
+ *
+ * This function must be used by drivers as their &file_operations.open method.
+ * It looks up the correct ACCEL device and instantiates all the per-file
+ * resources for it. It also calls the &drm_driver.open driver callback.
+ *
+ * Return: 0 on success or negative errno value on failure.
+ */
+int accel_open(struct inode *inode, struct file *filp)
+{
+ struct drm_device *dev;
+ struct drm_minor *minor;
+ int retcode;
+
+ minor = accel_minor_acquire(iminor(inode));
+ if (IS_ERR(minor))
+ return PTR_ERR(minor);
+
+ dev = minor->dev;
+
+ atomic_fetch_inc(&dev->open_count);
+
+ /* share address_space across all char-devs of a single device */
+ filp->f_mapping = dev->anon_inode->i_mapping;
+
+ retcode = drm_open_helper(filp, minor);
+ if (retcode)
+ goto err_undo;
+
+ return 0;
+
+err_undo:
+ atomic_dec(&dev->open_count);
+ accel_minor_release(minor);
+ return retcode;
+}
+EXPORT_SYMBOL_GPL(accel_open);
+
+static int accel_stub_open(struct inode *inode, struct file *filp)
+{
+ const struct file_operations *new_fops;
+ struct drm_minor *minor;
+ int err;
+
+ minor = accel_minor_acquire(iminor(inode));
+ if (IS_ERR(minor))
+ return PTR_ERR(minor);
+
+ new_fops = fops_get(minor->dev->driver->fops);
+ if (!new_fops) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ replace_fops(filp, new_fops);
+ if (filp->f_op->open)
+ err = filp->f_op->open(inode, filp);
+ else
+ err = 0;
+
+out:
+ accel_minor_release(minor);
+
+ return err;
+}
+
+static const struct file_operations accel_stub_fops = {
+ .owner = THIS_MODULE,
+ .open = accel_stub_open,
+ .llseek = noop_llseek,
+};
+
+void accel_core_exit(void)
+{
+ unregister_chrdev(ACCEL_MAJOR, "accel");
+ debugfs_remove(accel_debugfs_root);
+ accel_sysfs_destroy();
+ idr_destroy(&accel_minors_idr);
+}
+
+int __init accel_core_init(void)
+{
+ int ret;
+
+ idr_init(&accel_minors_idr);
+
+ ret = accel_sysfs_init();
+ if (ret < 0) {
+ DRM_ERROR("Cannot create ACCEL class: %d\n", ret);
+ goto error;
+ }
+
+ accel_debugfs_root = debugfs_create_dir("accel", NULL);
+
+ ret = register_chrdev(ACCEL_MAJOR, "accel", &accel_stub_fops);
+ if (ret < 0)
+ DRM_ERROR("Cannot register ACCEL major: %d\n", ret);
+
+error:
+ /*
+ * Any cleanup due to errors will be done in drm_core_exit() that
+ * will call accel_core_exit()
+ */
+ return ret;
+}
diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c
index f52265293482..73db0cb44fc7 100644
--- a/drivers/accessibility/speakup/main.c
+++ b/drivers/accessibility/speakup/main.c
@@ -1778,7 +1778,7 @@ static void speakup_con_update(struct vc_data *vc)
{
unsigned long flags;
- if (!speakup_console[vc->vc_num] || spk_parked)
+ if (!speakup_console[vc->vc_num] || spk_parked || !synth)
return;
if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
/* Speakup output, discard */
diff --git a/drivers/accessibility/speakup/utils.h b/drivers/accessibility/speakup/utils.h
index 4bf2ee8ac246..4ce9a12f7664 100644
--- a/drivers/accessibility/speakup/utils.h
+++ b/drivers/accessibility/speakup/utils.h
@@ -54,7 +54,7 @@ static inline int oops(const char *msg, const char *info)
static inline struct st_key *hash_name(char *name)
{
- u_char *pn = (u_char *)name;
+ unsigned char *pn = (unsigned char *)name;
int hash = 0;
while (*pn) {
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 473241b5193f..ccbeab9500ec 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -90,7 +90,7 @@ config ACPI_SPCR_TABLE
config ACPI_FPDT
bool "ACPI Firmware Performance Data Table (FPDT) support"
- depends on X86_64
+ depends on X86_64 || ARM64
help
Enable support for the Firmware Performance Data Table (FPDT).
This table provides information on the timing of the system
@@ -564,6 +564,16 @@ config ACPI_PCC
Enable this feature if you want to set up and install the PCC Address
Space handler to handle PCC OpRegion in the firmware.
+config ACPI_FFH
+ bool "ACPI FFH Address Space"
+ default n
+ help
+ The FFH(Fixed Function Hardware) Address Space also referred as FFH
+ Operation Region allows to define platform specific opregion.
+
+ Enable this feature if you want to set up and install the FFH Address
+ Space handler to handle FFH OpRegion in the firmware.
+
source "drivers/acpi/pmic/Kconfig"
config ACPI_VIOT
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 0002eecbf870..feb36c0b9446 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -68,6 +68,7 @@ acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o
acpi-$(CONFIG_ACPI_PRMT) += prmt.o
acpi-$(CONFIG_ACPI_PCC) += acpi_pcc.o
+acpi-$(CONFIG_ACPI_FFH) += acpi_ffh.o
# Address translation
acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index bb9fe7984b1a..1ace70b831cd 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -33,7 +33,7 @@ MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
static int acpi_ac_add(struct acpi_device *device);
-static int acpi_ac_remove(struct acpi_device *device);
+static void acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id ac_device_ids[] = {
@@ -288,12 +288,12 @@ static int acpi_ac_resume(struct device *dev)
#define acpi_ac_resume NULL
#endif
-static int acpi_ac_remove(struct acpi_device *device)
+static void acpi_ac_remove(struct acpi_device *device)
{
struct acpi_ac *ac = NULL;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
ac = acpi_driver_data(device);
@@ -301,8 +301,6 @@ static int acpi_ac_remove(struct acpi_device *device)
unregister_acpi_notifier(&ac->battery_nb);
kfree(ac);
-
- return 0;
}
static int __init acpi_ac_init(void)
diff --git a/drivers/acpi/acpi_ffh.c b/drivers/acpi/acpi_ffh.c
new file mode 100644
index 000000000000..19aff808bbb8
--- /dev/null
+++ b/drivers/acpi/acpi_ffh.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Author: Sudeep Holla <sudeep.holla@arm.com>
+ * Copyright 2022 Arm Limited
+ */
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/completion.h>
+#include <linux/idr.h>
+#include <linux/io.h>
+
+#include <linux/arm-smccc.h>
+
+static struct acpi_ffh_info ffh_ctx;
+
+int __weak acpi_ffh_address_space_arch_setup(void *handler_ctxt,
+ void **region_ctxt)
+{
+ return -EOPNOTSUPP;
+}
+
+int __weak acpi_ffh_address_space_arch_handler(acpi_integer *value,
+ void *region_context)
+{
+ return -EOPNOTSUPP;
+}
+
+static acpi_status
+acpi_ffh_address_space_setup(acpi_handle region_handle, u32 function,
+ void *handler_context, void **region_context)
+{
+ return acpi_ffh_address_space_arch_setup(handler_context,
+ region_context);
+}
+
+static acpi_status
+acpi_ffh_address_space_handler(u32 function, acpi_physical_address addr,
+ u32 bits, acpi_integer *value,
+ void *handler_context, void *region_context)
+{
+ return acpi_ffh_address_space_arch_handler(value, region_context);
+}
+
+void __init acpi_init_ffh(void)
+{
+ acpi_status status;
+
+ status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_FIXED_HARDWARE,
+ &acpi_ffh_address_space_handler,
+ &acpi_ffh_address_space_setup,
+ &ffh_ctx);
+ if (ACPI_FAILURE(status))
+ pr_alert("OperationRegion handler could not be installed\n");
+}
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index ec0e22a1e25d..02f1a1b1143c 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -287,7 +287,7 @@ static ssize_t rrtime_store(struct device *dev,
static ssize_t rrtime_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%d\n", round_robin_time);
+ return sysfs_emit(buf, "%d\n", round_robin_time);
}
static DEVICE_ATTR_RW(rrtime);
@@ -309,7 +309,7 @@ static ssize_t idlepct_store(struct device *dev,
static ssize_t idlepct_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%d\n", idle_pct);
+ return sysfs_emit(buf, "%d\n", idle_pct);
}
static DEVICE_ATTR_RW(idlepct);
@@ -449,7 +449,7 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}
-static int acpi_pad_remove(struct acpi_device *device)
+static void acpi_pad_remove(struct acpi_device *device)
{
mutex_lock(&isolated_cpus_lock);
acpi_pad_idle_cpus(0);
@@ -458,7 +458,6 @@ static int acpi_pad_remove(struct acpi_device *device)
acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify);
acpi_pad_remove_sysfs(device);
- return 0;
}
static const struct acpi_device_id pad_device_ids[] = {
diff --git a/drivers/acpi/acpi_pcc.c b/drivers/acpi/acpi_pcc.c
index 3e252be047b8..07a034a53aca 100644
--- a/drivers/acpi/acpi_pcc.c
+++ b/drivers/acpi/acpi_pcc.c
@@ -53,6 +53,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
struct pcc_data *data;
struct acpi_pcc_info *ctx = handler_context;
struct pcc_mbox_chan *pcc_chan;
+ static acpi_status ret;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -69,23 +70,35 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
if (IS_ERR(data->pcc_chan)) {
pr_err("Failed to find PCC channel for subspace %d\n",
ctx->subspace_id);
- kfree(data);
- return AE_NOT_FOUND;
+ ret = AE_NOT_FOUND;
+ goto err_free_data;
}
pcc_chan = data->pcc_chan;
+ if (!pcc_chan->mchan->mbox->txdone_irq) {
+ pr_err("This channel-%d does not support interrupt.\n",
+ ctx->subspace_id);
+ ret = AE_SUPPORT;
+ goto err_free_channel;
+ }
data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
pcc_chan->shmem_size);
if (!data->pcc_comm_addr) {
pr_err("Failed to ioremap PCC comm region mem for %d\n",
ctx->subspace_id);
- pcc_mbox_free_channel(data->pcc_chan);
- kfree(data);
- return AE_NO_MEMORY;
+ ret = AE_NO_MEMORY;
+ goto err_free_channel;
}
*region_context = data;
return AE_OK;
+
+err_free_channel:
+ pcc_mbox_free_channel(data->pcc_chan);
+err_free_data:
+ kfree(data);
+
+ return ret;
}
static acpi_status
@@ -106,19 +119,17 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
if (ret < 0)
return AE_ERROR;
- if (data->pcc_chan->mchan->mbox->txdone_irq) {
- /*
- * pcc_chan->latency is just a Nominal value. In reality the remote
- * processor could be much slower to reply. So add an arbitrary
- * amount of wait on top of Nominal.
- */
- usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
- ret = wait_for_completion_timeout(&data->done,
- usecs_to_jiffies(usecs_lat));
- if (ret == 0) {
- pr_err("PCC command executed timeout!\n");
- return AE_TIME;
- }
+ /*
+ * pcc_chan->latency is just a Nominal value. In reality the remote
+ * processor could be much slower to reply. So add an arbitrary
+ * amount of wait on top of Nominal.
+ */
+ usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
+ ret = wait_for_completion_timeout(&data->done,
+ usecs_to_jiffies(usecs_lat));
+ if (ret == 0) {
+ pr_err("PCC command executed timeout!\n");
+ return AE_TIME;
}
mbox_chan_txdone(data->pcc_chan->mchan, ret);
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 32953646caeb..30d8fd03fec7 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -86,7 +86,7 @@ static DEFINE_MUTEX(register_count_mutex);
static DEFINE_MUTEX(video_list_lock);
static LIST_HEAD(video_bus_head);
static int acpi_video_bus_add(struct acpi_device *device);
-static int acpi_video_bus_remove(struct acpi_device *device);
+static void acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
static void acpi_video_bus_register_backlight_work(struct work_struct *ignored);
static DECLARE_DELAYED_WORK(video_bus_register_backlight_work,
@@ -2067,13 +2067,13 @@ err_free_video:
return error;
}
-static int acpi_video_bus_remove(struct acpi_device *device)
+static void acpi_video_bus_remove(struct acpi_device *device)
{
struct acpi_video_bus *video = NULL;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
video = acpi_driver_data(device);
@@ -2087,8 +2087,6 @@ static int acpi_video_bus_remove(struct acpi_device *device)
kfree(video->attached_array);
kfree(video);
-
- return 0;
}
static void acpi_video_bus_register_backlight_work(struct work_struct *ignored)
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 59700433a96e..9e0d95d76fff 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -155,6 +155,7 @@ acpi-y += \
utalloc.o \
utascii.o \
utbuffer.o \
+ utcksum.o \
utcopy.o \
utexcep.o \
utdebug.o \
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 088d6a7d052c..777457a58340 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -24,6 +24,7 @@ ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT);
ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header);
+ACPI_INIT_GLOBAL(char *, acpi_gbl_CDAT, NULL);
ACPI_INIT_GLOBAL(u32, acpi_gbl_dsdt_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_facs_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX);
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index f8d7bfd737df..1c29325e4c7f 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -124,11 +124,6 @@ void
acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header *header);
-u8 acpi_tb_checksum(u8 *buffer, u32 length);
-
-acpi_status
-acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
-
void acpi_tb_check_dsdt_header(void);
struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index);
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 6e6270f96bfb..71175b664f49 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -159,6 +159,19 @@ u8 acpi_ut_valid_name_char(char character, u32 position);
void acpi_ut_check_and_repair_ascii(u8 *name, char *repaired_name, u32 count);
/*
+ * utcksum - Checksum utilities
+ */
+u8 acpi_ut_generate_checksum(void *table, u32 length, u8 original_checksum);
+
+u8 acpi_ut_checksum(u8 *buffer, u32 length);
+
+acpi_status
+acpi_ut_verify_cdat_checksum(struct acpi_table_cdat *cdat_table, u32 length);
+
+acpi_status
+acpi_ut_verify_checksum(struct acpi_table_header *table, u32 length);
+
+/*
* utnonansi - Non-ANSI C library functions
*/
void acpi_ut_strupr(char *src_string);
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index ae2e768830bf..9332bc688713 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -517,7 +517,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
if (!info) {
status = AE_NO_MEMORY;
- goto cleanup;
+ goto pop_walk_state;
}
info->parameters = &this_walk_state->operands[0];
@@ -529,7 +529,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
ACPI_FREE(info);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+ goto pop_walk_state;
}
next_walk_state->method_nesting_depth =
@@ -575,6 +575,12 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(status);
+pop_walk_state:
+
+ /* On error, pop the walk state to be deleted from thread */
+
+ acpi_ds_pop_walk_state(thread);
+
cleanup:
/* On error, we must terminate the method properly */
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index df596d46dd97..82d1728b9bc6 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -142,6 +142,9 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
status =
acpi_write_bit_register(acpi_gbl_fixed_event_info
[i].enable_register_id,
+ (i ==
+ ACPI_EVENT_PCIE_WAKE) ?
+ ACPI_ENABLE_EVENT :
ACPI_DISABLE_EVENT);
if (ACPI_FAILURE(status)) {
return (status);
@@ -185,6 +188,11 @@ u32 acpi_ev_fixed_event_detect(void)
return (int_status);
}
+ if (fixed_enable & ACPI_BITMASK_PCIEXP_WAKE_DISABLE)
+ fixed_enable &= ~ACPI_BITMASK_PCIEXP_WAKE_DISABLE;
+ else
+ fixed_enable |= ACPI_BITMASK_PCIEXP_WAKE_DISABLE;
+
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
"Fixed Event Block: Enable %08X Status %08X\n",
fixed_enable, fixed_status));
@@ -250,6 +258,9 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
if (!acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
enable_register_id,
+ (event ==
+ ACPI_EVENT_PCIE_WAKE) ?
+ ACPI_ENABLE_EVENT :
ACPI_DISABLE_EVENT);
ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index b96b3a7e78e5..d035092799eb 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -172,6 +172,15 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
ctx->subspace_id = (u8)region_obj->region.address;
}
+ if (region_obj->region.space_id ==
+ ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ struct acpi_ffh_info *ctx =
+ handler_desc->address_space.context;
+
+ ctx->length = region_obj->region.length;
+ ctx->offset = region_obj->region.address;
+ }
+
/*
* We must exit the interpreter because the region setup will
* potentially execute control methods (for example, the _REG method
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index d7d74ef87b18..e82faabdf907 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -295,8 +295,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
target));
}
if (target->common.type != ACPI_TYPE_INTEGER) {
- ACPI_EXCEPTION((AE_INFO, AE_TYPE,
- "Type not integer: %X\n", target->common.type));
+ ACPI_ERROR((AE_INFO, "Type not integer: %X",
+ target->common.type));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 2b89a496de65..657f4002f9dc 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -141,7 +141,9 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
|| obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_IPMI
|| obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_PLATFORM_RT)) {
+ ACPI_ADR_SPACE_PLATFORM_RT
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_FIXED_HARDWARE)) {
/* SMBus, GSBus, IPMI serial */
@@ -305,7 +307,9 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
|| obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_IPMI
|| obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_PLATFORM_RT)) {
+ ACPI_ADR_SPACE_PLATFORM_RT
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_FIXED_HARDWARE)) {
/* SMBus, GSBus, IPMI serial */
diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c
index 4da20d7845df..fd63f2042514 100644
--- a/drivers/acpi/acpica/exserial.c
+++ b/drivers/acpi/acpica/exserial.c
@@ -323,6 +323,12 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
function = ACPI_WRITE;
break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+
+ buffer_length = ACPI_FFH_INPUT_BUFFER_SIZE;
+ function = ACPI_WRITE;
+ break;
+
default:
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
}
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index bd936476dda9..37b3f641feaa 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -311,6 +311,20 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state)
[ACPI_EVENT_SLEEP_BUTTON].
status_register_id, ACPI_CLEAR_STATUS);
+ /* Enable pcie wake event if support */
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_PCI_EXPRESS_WAKE)) {
+ (void)
+ acpi_write_bit_register(acpi_gbl_fixed_event_info
+ [ACPI_EVENT_PCIE_WAKE].
+ enable_register_id,
+ ACPI_DISABLE_EVENT);
+ (void)
+ acpi_write_bit_register(acpi_gbl_fixed_event_info
+ [ACPI_EVENT_PCIE_WAKE].
+ status_register_id,
+ ACPI_CLEAR_STATUS);
+ }
+
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c
index a7642b34ce48..1f7677e0dbbe 100644
--- a/drivers/acpi/acpica/tbdata.c
+++ b/drivers/acpi/acpica/tbdata.c
@@ -522,7 +522,7 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc,
/* Verify the checksum */
status =
- acpi_tb_verify_checksum(table_desc->pointer,
+ acpi_ut_verify_checksum(table_desc->pointer,
table_desc->length);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 31d7ea84a360..f04dc6051320 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -298,7 +298,7 @@ void acpi_tb_parse_fadt(void)
* Validate the FADT checksum before we copy the table. Ignore
* checksum error as we want to try to get the DSDT and FACS.
*/
- (void)acpi_tb_verify_checksum(table, length);
+ (void)acpi_ut_verify_checksum(table, length);
/* Create a local copy of the FADT in common ACPI 2.0+ format */
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
index 595547db28c0..f07aa9b46f3f 100644
--- a/drivers/acpi/acpica/tbprint.c
+++ b/drivers/acpi/acpica/tbprint.c
@@ -10,6 +10,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "actables.h"
+#include "acutils.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbprint")
@@ -39,7 +40,7 @@ static void acpi_tb_fix_string(char *string, acpi_size length)
{
while (length && *string) {
- if (!isprint((int)*string)) {
+ if (!isprint((int)(u8)*string)) {
*string = '?';
}
@@ -135,77 +136,3 @@ acpi_tb_print_table_header(acpi_physical_address address,
local_header.asl_compiler_revision));
}
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_validate_checksum
- *
- * PARAMETERS: table - ACPI table to verify
- * length - Length of entire table
- *
- * RETURN: Status
- *
- * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
- * exception on bad checksum.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
-{
- u8 checksum;
-
- /*
- * FACS/S3PT:
- * They are the odd tables, have no standard ACPI header and no checksum
- */
-
- if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_S3PT) ||
- ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_FACS)) {
- return (AE_OK);
- }
-
- /* Compute the checksum on the table */
-
- checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
-
- /* Checksum ok? (should be zero) */
-
- if (checksum) {
- ACPI_BIOS_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
- "should be 0x%2.2X",
- table->signature, table->checksum,
- (u8)(table->checksum - checksum)));
-
-#if (ACPI_CHECKSUM_ABORT)
- return (AE_BAD_CHECKSUM);
-#endif
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_checksum
- *
- * PARAMETERS: buffer - Pointer to memory region to be checked
- * length - Length of this memory region
- *
- * RETURN: Checksum (u8)
- *
- * DESCRIPTION: Calculates circular checksum of memory region.
- *
- ******************************************************************************/
-
-u8 acpi_tb_checksum(u8 *buffer, u32 length)
-{
- u8 sum = 0;
- u8 *end = buffer + length;
-
- while (buffer < end) {
- sum = (u8)(sum + *(buffer++));
- }
-
- return (sum);
-}
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 633a823be65f..17ad9c227d42 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -299,7 +299,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
/* Validate the root table checksum */
- status = acpi_tb_verify_checksum(table, length);
+ status = acpi_ut_verify_checksum(table, length);
if (ACPI_FAILURE(status)) {
acpi_os_unmap_memory(table, length);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 3d09e3f6bd43..53afd75bbc06 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -74,14 +74,14 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
/* Check the standard checksum */
- if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ if (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
- (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+ (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
@@ -114,6 +114,7 @@ acpi_find_root_pointer(acpi_physical_address *table_address)
u8 *table_ptr;
u8 *mem_rover;
u32 physical_address;
+ u32 ebda_window_size;
ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
@@ -139,26 +140,37 @@ acpi_find_root_pointer(acpi_physical_address *table_address)
/* EBDA present? */
- if (physical_address > 0x400) {
+ /*
+ * Check that the EBDA pointer from memory is sane and does not point
+ * above valid low memory
+ */
+ if (physical_address > 0x400 && physical_address < 0xA0000) {
+ /*
+ * Calculate the scan window size
+ * The EBDA is not guaranteed to be larger than a ki_b and in case
+ * that it is smaller, the scanning function would leave the low
+ * memory and continue to the VGA range.
+ */
+ ebda_window_size = ACPI_MIN(ACPI_EBDA_WINDOW_SIZE,
+ 0xA0000 - physical_address);
+
/*
- * 1b) Search EBDA paragraphs (EBDA is required to be a
- * minimum of 1K length)
+ * 1b) Search EBDA paragraphs
*/
table_ptr = acpi_os_map_memory((acpi_physical_address)
physical_address,
- ACPI_EBDA_WINDOW_SIZE);
+ ebda_window_size);
if (!table_ptr) {
ACPI_ERROR((AE_INFO,
"Could not map memory at 0x%8.8X for length %u",
- physical_address, ACPI_EBDA_WINDOW_SIZE));
+ physical_address, ebda_window_size));
return_ACPI_STATUS(AE_NO_MEMORY);
}
mem_rover =
- acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_EBDA_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
+ acpi_tb_scan_memory_for_rsdp(table_ptr, ebda_window_size);
+ acpi_os_unmap_memory(table_ptr, ebda_window_size);
if (mem_rover) {
diff --git a/drivers/acpi/acpica/utcksum.c b/drivers/acpi/acpica/utcksum.c
new file mode 100644
index 000000000000..c166e4c05ab6
--- /dev/null
+++ b/drivers/acpi/acpica/utcksum.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: utcksum - Support generating table checksums
+ *
+ * Copyright (C) 2000 - 2022, Intel Corp.
+ *
+ *****************************************************************************/
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acutils.h"
+
+/* This module used for application-level code only */
+
+#define _COMPONENT ACPI_CA_DISASSEMBLER
+ACPI_MODULE_NAME("utcksum")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_verify_checksum
+ *
+ * PARAMETERS: table - ACPI table to verify
+ * length - Length of entire table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ * exception on bad checksum.
+ * Note: We don't have to check for a CDAT here, since CDAT is
+ * not in the RSDT/XSDT, and the CDAT table is never installed
+ * via ACPICA.
+ *
+ ******************************************************************************/
+acpi_status acpi_ut_verify_checksum(struct acpi_table_header *table, u32 length)
+{
+ u8 checksum;
+
+ /*
+ * FACS/S3PT:
+ * They are the odd tables, have no standard ACPI header and no checksum
+ */
+ if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_S3PT) ||
+ ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_FACS)) {
+ return (AE_OK);
+ }
+
+ /* Compute the checksum on the table */
+
+ length = table->length;
+ checksum =
+ acpi_ut_generate_checksum(ACPI_CAST_PTR(u8, table), length,
+ table->checksum);
+
+ /* Computed checksum matches table? */
+
+ if (checksum != table->checksum) {
+ ACPI_BIOS_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
+ "should be 0x%2.2X",
+ table->signature, table->checksum,
+ table->checksum - checksum));
+
+#if (ACPI_CHECKSUM_ABORT)
+ return (AE_BAD_CHECKSUM);
+#endif
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_verify_cdat_checksum
+ *
+ * PARAMETERS: table - CDAT ACPI table to verify
+ * length - Length of entire table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Verifies that the CDAT table checksums to zero. Optionally
+ * returns an exception on bad checksum.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_verify_cdat_checksum(struct acpi_table_cdat *cdat_table, u32 length)
+{
+ u8 checksum;
+
+ /* Compute the checksum on the table */
+
+ checksum = acpi_ut_generate_checksum(ACPI_CAST_PTR(u8, cdat_table),
+ cdat_table->length,
+ cdat_table->checksum);
+
+ /* Computed checksum matches table? */
+
+ if (checksum != cdat_table->checksum) {
+ ACPI_BIOS_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
+ "should be 0x%2.2X",
+ acpi_gbl_CDAT, cdat_table->checksum,
+ checksum));
+
+#if (ACPI_CHECKSUM_ABORT)
+ return (AE_BAD_CHECKSUM);
+#endif
+ }
+
+ cdat_table->checksum = checksum;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_generate_checksum
+ *
+ * PARAMETERS: table - Pointer to table to be checksummed
+ * length - Length of the table
+ * original_checksum - Value of the checksum field
+ *
+ * RETURN: 8 bit checksum of buffer
+ *
+ * DESCRIPTION: Computes an 8 bit checksum of the table.
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_generate_checksum(void *table, u32 length, u8 original_checksum)
+{
+ u8 checksum;
+
+ /* Sum the entire table as-is */
+
+ checksum = acpi_ut_checksum((u8 *)table, length);
+
+ /* Subtract off the existing checksum value in the table */
+
+ checksum = (u8)(checksum - original_checksum);
+
+ /* Compute and return the final checksum */
+
+ checksum = (u8)(0 - checksum);
+ return (checksum);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_checksum
+ *
+ * PARAMETERS: buffer - Pointer to memory region to be checked
+ * length - Length of this memory region
+ *
+ * RETURN: Checksum (u8)
+ *
+ * DESCRIPTION: Calculates circular checksum of memory region.
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_checksum(u8 *buffer, u32 length)
+{
+ u8 sum = 0;
+ u8 *end = buffer + length;
+
+ while (buffer < end) {
+ sum = (u8)(sum + *(buffer++));
+ }
+
+ return (sum);
+}
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 400b9e15a709..63c17f420fb8 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -916,13 +916,6 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj,
status = acpi_ut_walk_package_tree(source_obj, dest_obj,
acpi_ut_copy_ielement_to_ielement,
walk_state);
- if (ACPI_FAILURE(status)) {
-
- /* On failure, delete the destination package object */
-
- acpi_ut_remove_reference(dest_obj);
- }
-
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index cda6e16dddf7..53afa5edb6ec 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -186,6 +186,10 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] =
ACPI_BITREG_RT_CLOCK_ENABLE,
ACPI_BITMASK_RT_CLOCK_STATUS,
ACPI_BITMASK_RT_CLOCK_ENABLE},
+ /* ACPI_EVENT_PCIE_WAKE */ {ACPI_BITREG_PCIEXP_WAKE_STATUS,
+ ACPI_BITREG_PCIEXP_WAKE_DISABLE,
+ ACPI_BITMASK_PCIEXP_WAKE_STATUS,
+ ACPI_BITMASK_PCIEXP_WAKE_DISABLE},
};
#endif /* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index c39b5483045d..aae71b8c55d2 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -145,7 +145,7 @@ void acpi_ut_repair_name(char *name)
return;
}
- ACPI_COPY_NAMESEG(&original_name, name);
+ ACPI_COPY_NAMESEG(&original_name, &name[0]);
/* Check each character in the name */
@@ -156,10 +156,10 @@ void acpi_ut_repair_name(char *name)
/*
* Replace a bad character with something printable, yet technically
- * still invalid. This prevents any collisions with existing "good"
+ * "odd". This prevents any collisions with existing "good"
* names in the namespace.
*/
- name[i] = '*';
+ name[i] = '_';
found_bad_char = TRUE;
}
@@ -169,8 +169,8 @@ void acpi_ut_repair_name(char *name)
if (!acpi_gbl_enable_interpreter_slack) {
ACPI_WARNING((AE_INFO,
- "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
- original_name, name));
+ "Invalid character(s) in name (0x%.8X) %p, repaired: [%4.4s]",
+ original_name, name, &name[0]));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 9b52482b4ed5..c7c26872f4ce 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -25,9 +25,9 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/kref.h>
-#include <linux/rculist.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>
+#include <acpi/apei.h>
#include <asm/unaligned.h>
#include "apei-internal.h"
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 6b583373c58a..ab86b2f4e719 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -358,6 +358,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
*/
if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
struct apei_resources addr_resources;
+
apei_resources_init(&addr_resources);
trigger_param_region = einj_get_trigger_parameter_region(
trigger_tab, param1, param2);
@@ -432,11 +433,11 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
}
v5param->flags = vendor_flags;
} else if (flags) {
- v5param->flags = flags;
- v5param->memory_address = param1;
- v5param->memory_address_range = param2;
- v5param->apicid = param3;
- v5param->pcie_sbdf = param4;
+ v5param->flags = flags;
+ v5param->memory_address = param1;
+ v5param->memory_address_range = param2;
+ v5param->apicid = param3;
+ v5param->pcie_sbdf = param4;
} else {
switch (type) {
case ACPI_EINJ_PROCESSOR_CORRECTABLE:
@@ -466,6 +467,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
return rc;
if (einj_param) {
struct einj_parameter *v4param = einj_param;
+
v4param->param1 = param1;
v4param->param2 = param2;
}
@@ -569,6 +571,20 @@ static u64 error_param2;
static u64 error_param3;
static u64 error_param4;
static struct dentry *einj_debug_dir;
+static const char * const einj_error_type_string[] = {
+ "0x00000001\tProcessor Correctable\n",
+ "0x00000002\tProcessor Uncorrectable non-fatal\n",
+ "0x00000004\tProcessor Uncorrectable fatal\n",
+ "0x00000008\tMemory Correctable\n",
+ "0x00000010\tMemory Uncorrectable non-fatal\n",
+ "0x00000020\tMemory Uncorrectable fatal\n",
+ "0x00000040\tPCI Express Correctable\n",
+ "0x00000080\tPCI Express Uncorrectable non-fatal\n",
+ "0x00000100\tPCI Express Uncorrectable fatal\n",
+ "0x00000200\tPlatform Correctable\n",
+ "0x00000400\tPlatform Uncorrectable non-fatal\n",
+ "0x00000800\tPlatform Uncorrectable fatal\n",
+};
static int available_error_type_show(struct seq_file *m, void *v)
{
@@ -578,30 +594,9 @@ static int available_error_type_show(struct seq_file *m, void *v)
rc = einj_get_available_error_type(&available_error_type);
if (rc)
return rc;
- if (available_error_type & 0x0001)
- seq_printf(m, "0x00000001\tProcessor Correctable\n");
- if (available_error_type & 0x0002)
- seq_printf(m, "0x00000002\tProcessor Uncorrectable non-fatal\n");
- if (available_error_type & 0x0004)
- seq_printf(m, "0x00000004\tProcessor Uncorrectable fatal\n");
- if (available_error_type & 0x0008)
- seq_printf(m, "0x00000008\tMemory Correctable\n");
- if (available_error_type & 0x0010)
- seq_printf(m, "0x00000010\tMemory Uncorrectable non-fatal\n");
- if (available_error_type & 0x0020)
- seq_printf(m, "0x00000020\tMemory Uncorrectable fatal\n");
- if (available_error_type & 0x0040)
- seq_printf(m, "0x00000040\tPCI Express Correctable\n");
- if (available_error_type & 0x0080)
- seq_printf(m, "0x00000080\tPCI Express Uncorrectable non-fatal\n");
- if (available_error_type & 0x0100)
- seq_printf(m, "0x00000100\tPCI Express Uncorrectable fatal\n");
- if (available_error_type & 0x0200)
- seq_printf(m, "0x00000200\tPlatform Correctable\n");
- if (available_error_type & 0x0400)
- seq_printf(m, "0x00000400\tPlatform Uncorrectable non-fatal\n");
- if (available_error_type & 0x0800)
- seq_printf(m, "0x00000800\tPlatform Uncorrectable fatal\n");
+ for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++)
+ if (available_error_type & BIT(pos))
+ seq_puts(m, einj_error_type_string[pos]);
return 0;
}
@@ -689,8 +684,7 @@ static int __init einj_init(void)
if (status == AE_NOT_FOUND) {
pr_warn("EINJ table not found.\n");
return -ENODEV;
- }
- else if (ACPI_FAILURE(status)) {
+ } else if (ACPI_FAILURE(status)) {
pr_err("Failed to get EINJ table: %s\n",
acpi_format_exception(status));
return -EINVAL;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 9952f3a792ba..066dc1f5c235 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -94,6 +94,8 @@
#define FIX_APEI_GHES_SDEI_CRITICAL __end_of_fixed_addresses
#endif
+static ATOMIC_NOTIFIER_HEAD(ghes_report_chain);
+
static inline bool is_hest_type_generic_v2(struct ghes *ghes)
{
return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
@@ -108,6 +110,13 @@ bool ghes_disable;
module_param_named(disable, ghes_disable, bool, 0);
/*
+ * "ghes.edac_force_enable" forcibly enables ghes_edac and skips the platform
+ * check.
+ */
+static bool ghes_edac_force_enable;
+module_param_named(edac_force_enable, ghes_edac_force_enable, bool, 0);
+
+/*
* All error sources notified with HED (Hardware Error Device) share a
* single notifier callback, so they need to be linked and checked one
* by one. This holds true for NMI too.
@@ -119,6 +128,13 @@ static LIST_HEAD(ghes_hed);
static DEFINE_MUTEX(ghes_list_mutex);
/*
+ * A list of GHES devices which are given to the corresponding EDAC driver
+ * ghes_edac for further use.
+ */
+static LIST_HEAD(ghes_devs);
+static DEFINE_MUTEX(ghes_devs_mutex);
+
+/*
* Because the memory area used to transfer hardware error information
* from BIOS to Linux can be determined only in NMI, IRQ or timer
* handler, but general ioremap can not be used in atomic context, so
@@ -138,7 +154,7 @@ struct ghes_vendor_record_entry {
static struct gen_pool *ghes_estatus_pool;
static unsigned long ghes_estatus_pool_size_request;
-static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
+static struct ghes_estatus_cache __rcu *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
static atomic_t ghes_estatus_cache_alloced;
static int ghes_panic_timeout __read_mostly = 30;
@@ -645,7 +661,7 @@ static bool ghes_do_proc(struct ghes *ghes,
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
- ghes_edac_report_mem_error(sev, mem_err);
+ atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
arch_apei_report_mem_error(sev, mem_err);
queued = ghes_handle_memory_failure(gdata, sev);
@@ -773,48 +789,42 @@ static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
return cache;
}
-static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache)
+static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
{
+ struct ghes_estatus_cache *cache;
u32 len;
+ cache = container_of(head, struct ghes_estatus_cache, rcu);
len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
len = GHES_ESTATUS_CACHE_LEN(len);
gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len);
atomic_dec(&ghes_estatus_cache_alloced);
}
-static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
+static void
+ghes_estatus_cache_add(struct acpi_hest_generic *generic,
+ struct acpi_hest_generic_status *estatus)
{
- struct ghes_estatus_cache *cache;
-
- cache = container_of(head, struct ghes_estatus_cache, rcu);
- ghes_estatus_cache_free(cache);
-}
-
-static void ghes_estatus_cache_add(
- struct acpi_hest_generic *generic,
- struct acpi_hest_generic_status *estatus)
-{
- int i, slot = -1, count;
unsigned long long now, duration, period, max_period = 0;
- struct ghes_estatus_cache *cache, *slot_cache = NULL, *new_cache;
+ struct ghes_estatus_cache *cache, *new_cache;
+ struct ghes_estatus_cache __rcu *victim;
+ int i, slot = -1, count;
new_cache = ghes_estatus_cache_alloc(generic, estatus);
- if (new_cache == NULL)
+ if (!new_cache)
return;
+
rcu_read_lock();
now = sched_clock();
for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
cache = rcu_dereference(ghes_estatus_caches[i]);
if (cache == NULL) {
slot = i;
- slot_cache = NULL;
break;
}
duration = now - cache->time_in;
if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) {
slot = i;
- slot_cache = cache;
break;
}
count = atomic_read(&cache->count);
@@ -823,18 +833,30 @@ static void ghes_estatus_cache_add(
if (period > max_period) {
max_period = period;
slot = i;
- slot_cache = cache;
}
}
- /* new_cache must be put into array after its contents are written */
- smp_wmb();
- if (slot != -1 && cmpxchg(ghes_estatus_caches + slot,
- slot_cache, new_cache) == slot_cache) {
- if (slot_cache)
- call_rcu(&slot_cache->rcu, ghes_estatus_cache_rcu_free);
- } else
- ghes_estatus_cache_free(new_cache);
rcu_read_unlock();
+
+ if (slot != -1) {
+ /*
+ * Use release semantics to ensure that ghes_estatus_cached()
+ * running on another CPU will see the updated cache fields if
+ * it can see the new value of the pointer.
+ */
+ victim = xchg_release(&ghes_estatus_caches[slot],
+ RCU_INITIALIZER(new_cache));
+
+ /*
+ * At this point, victim may point to a cached item different
+ * from the one based on which we selected the slot. Instead of
+ * going to the loop again to pick another slot, let's just
+ * drop the other item anyway: this may cause a false cache
+ * miss later on, but that won't cause any problems.
+ */
+ if (victim)
+ call_rcu(&unrcu_pointer(victim)->rcu,
+ ghes_estatus_cache_rcu_free);
+ }
}
static void __ghes_panic(struct ghes *ghes,
@@ -1376,7 +1398,11 @@ static int ghes_probe(struct platform_device *ghes_dev)
platform_set_drvdata(ghes_dev, ghes);
- ghes_edac_register(ghes, &ghes_dev->dev);
+ ghes->dev = &ghes_dev->dev;
+
+ mutex_lock(&ghes_devs_mutex);
+ list_add_tail(&ghes->elist, &ghes_devs);
+ mutex_unlock(&ghes_devs_mutex);
/* Handle any pending errors right away */
spin_lock_irqsave(&ghes_notify_lock_irq, flags);
@@ -1440,12 +1466,12 @@ static int ghes_remove(struct platform_device *ghes_dev)
ghes_fini(ghes);
- ghes_edac_unregister(ghes);
+ mutex_lock(&ghes_devs_mutex);
+ list_del(&ghes->elist);
+ mutex_unlock(&ghes_devs_mutex);
kfree(ghes);
- platform_set_drvdata(ghes_dev, NULL);
-
return 0;
}
@@ -1497,3 +1523,41 @@ void __init acpi_ghes_init(void)
else
pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n");
}
+
+/*
+ * Known x86 systems that prefer GHES error reporting:
+ */
+static struct acpi_platform_list plat_list[] = {
+ {"HPE ", "Server ", 0, ACPI_SIG_FADT, all_versions},
+ { } /* End */
+};
+
+struct list_head *ghes_get_devices(void)
+{
+ int idx = -1;
+
+ if (IS_ENABLED(CONFIG_X86)) {
+ idx = acpi_match_platform_list(plat_list);
+ if (idx < 0) {
+ if (!ghes_edac_force_enable)
+ return NULL;
+
+ pr_warn_once("Force-loading ghes_edac on an unsupported platform. You're on your own!\n");
+ }
+ }
+
+ return &ghes_devs;
+}
+EXPORT_SYMBOL_GPL(ghes_get_devices);
+
+void ghes_register_report_chain(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&ghes_report_chain, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_register_report_chain);
+
+void ghes_unregister_report_chain(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&ghes_report_chain, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_unregister_report_chain);
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index d4a72835f328..b3ed6212244c 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -18,3 +18,6 @@ config ACPI_AGDI
reset command.
If set, the kernel parses AGDI table and listens for the command.
+
+config ACPI_APMT
+ bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 7b9e4045659d..e21a9e84e394 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_ACPI_AGDI) += agdi.o
obj-$(CONFIG_ACPI_IORT) += iort.o
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
+obj-$(CONFIG_ACPI_APMT) += apmt.o
obj-y += dma.o
diff --git a/drivers/acpi/arm64/apmt.c b/drivers/acpi/arm64/apmt.c
new file mode 100644
index 000000000000..8cab69fa5d59
--- /dev/null
+++ b/drivers/acpi/arm64/apmt.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM APMT table support.
+ * Design document number: ARM DEN0117.
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
+ *
+ */
+
+#define pr_fmt(fmt) "ACPI: APMT: " fmt
+
+#include <linux/acpi.h>
+#include <linux/acpi_apmt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#define DEV_NAME "arm-cs-arch-pmu"
+
+/* There can be up to 3 resources: page 0 and 1 address, and interrupt. */
+#define DEV_MAX_RESOURCE_COUNT 3
+
+/* Root pointer to the mapped APMT table */
+static struct acpi_table_header *apmt_table;
+
+static int __init apmt_init_resources(struct resource *res,
+ struct acpi_apmt_node *node)
+{
+ int irq, trigger;
+ int num_res = 0;
+
+ res[num_res].start = node->base_address0;
+ res[num_res].end = node->base_address0 + SZ_4K - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+
+ num_res++;
+
+ res[num_res].start = node->base_address1;
+ res[num_res].end = node->base_address1 + SZ_4K - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+
+ num_res++;
+
+ if (node->ovflw_irq != 0) {
+ trigger = (node->ovflw_irq_flags & ACPI_APMT_OVFLW_IRQ_FLAGS_MODE);
+ trigger = (trigger == ACPI_APMT_OVFLW_IRQ_FLAGS_MODE_LEVEL) ?
+ ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+ irq = acpi_register_gsi(NULL, node->ovflw_irq, trigger,
+ ACPI_ACTIVE_HIGH);
+
+ if (irq <= 0) {
+ pr_warn("APMT could not register gsi hwirq %d\n", irq);
+ return num_res;
+ }
+
+ res[num_res].start = irq;
+ res[num_res].end = irq;
+ res[num_res].flags = IORESOURCE_IRQ;
+
+ num_res++;
+ }
+
+ return num_res;
+}
+
+/**
+ * apmt_add_platform_device() - Allocate a platform device for APMT node
+ * @node: Pointer to device ACPI APMT node
+ * @fwnode: fwnode associated with the APMT node
+ *
+ * Returns: 0 on success, <0 failure
+ */
+static int __init apmt_add_platform_device(struct acpi_apmt_node *node,
+ struct fwnode_handle *fwnode)
+{
+ struct platform_device *pdev;
+ int ret, count;
+ struct resource res[DEV_MAX_RESOURCE_COUNT];
+
+ pdev = platform_device_alloc(DEV_NAME, PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return -ENOMEM;
+
+ memset(res, 0, sizeof(res));
+
+ count = apmt_init_resources(res, node);
+
+ ret = platform_device_add_resources(pdev, res, count);
+ if (ret)
+ goto dev_put;
+
+ /*
+ * Add a copy of APMT node pointer to platform_data to be used to
+ * retrieve APMT data information.
+ */
+ ret = platform_device_add_data(pdev, &node, sizeof(node));
+ if (ret)
+ goto dev_put;
+
+ pdev->dev.fwnode = fwnode;
+
+ ret = platform_device_add(pdev);
+
+ if (ret)
+ goto dev_put;
+
+ return 0;
+
+dev_put:
+ platform_device_put(pdev);
+
+ return ret;
+}
+
+static int __init apmt_init_platform_devices(void)
+{
+ struct acpi_apmt_node *apmt_node;
+ struct acpi_table_apmt *apmt;
+ struct fwnode_handle *fwnode;
+ u64 offset, end;
+ int ret;
+
+ /*
+ * apmt_table and apmt both point to the start of APMT table, but
+ * have different struct types
+ */
+ apmt = (struct acpi_table_apmt *)apmt_table;
+ offset = sizeof(*apmt);
+ end = apmt->header.length;
+
+ while (offset < end) {
+ apmt_node = ACPI_ADD_PTR(struct acpi_apmt_node, apmt,
+ offset);
+
+ fwnode = acpi_alloc_fwnode_static();
+ if (!fwnode)
+ return -ENOMEM;
+
+ ret = apmt_add_platform_device(apmt_node, fwnode);
+ if (ret) {
+ acpi_free_fwnode_static(fwnode);
+ return ret;
+ }
+
+ offset += apmt_node->length;
+ }
+
+ return 0;
+}
+
+void __init acpi_apmt_init(void)
+{
+ acpi_status status;
+ int ret;
+
+ /**
+ * APMT table nodes will be used at runtime after the apmt init,
+ * so we don't need to call acpi_put_table() to release
+ * the APMT table mapping.
+ */
+ status = acpi_get_table(ACPI_SIG_APMT, 0, &apmt_table);
+
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ const char *msg = acpi_format_exception(status);
+
+ pr_err("Failed to get APMT table, %s\n", msg);
+ }
+
+ return;
+ }
+
+ ret = apmt_init_platform_devices();
+ if (ret) {
+ pr_err("Failed to initialize APMT platform devices, ret: %d\n", ret);
+ acpi_put_table(apmt_table);
+ }
+}
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 8059baf4ef27..38fb84974f35 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -402,6 +402,10 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
return NULL;
}
+#ifndef ACPI_IORT_SMMU_V3_DEVICEID_VALID
+#define ACPI_IORT_SMMU_V3_DEVICEID_VALID (1 << 4)
+#endif
+
static int iort_get_id_mapping_index(struct acpi_iort_node *node)
{
struct acpi_iort_smmu_v3 *smmu;
@@ -418,12 +422,16 @@ static int iort_get_id_mapping_index(struct acpi_iort_node *node)
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
/*
- * ID mapping index is only ignored if all interrupts are
- * GSIV based
+ * Until IORT E.e (node rev. 5), the ID mapping index was
+ * defined to be valid unless all interrupts are GSIV-based.
*/
- if (smmu->event_gsiv && smmu->pri_gsiv && smmu->gerr_gsiv
- && smmu->sync_gsiv)
+ if (node->revision < 5) {
+ if (smmu->event_gsiv && smmu->pri_gsiv &&
+ smmu->gerr_gsiv && smmu->sync_gsiv)
+ return -EINVAL;
+ } else if (!(smmu->flags & ACPI_IORT_SMMU_V3_DEVICEID_VALID)) {
return -EINVAL;
+ }
if (smmu->id_mapping_index >= node->mapping_count) {
pr_err(FW_BUG "[node %p type %d] ID mapping index overflows valid mappings\n",
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 306513fec1e1..f4badcdde76e 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -696,7 +696,8 @@ static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock)
if (lock)
mutex_lock(&hook_mutex);
list_for_each_entry(battery, &acpi_battery_list, list) {
- hook->remove_battery(battery->bat);
+ if (!hook->remove_battery(battery->bat, hook))
+ power_supply_changed(battery->bat);
}
list_del(&hook->list);
if (lock)
@@ -724,7 +725,7 @@ void battery_hook_register(struct acpi_battery_hook *hook)
* its attributes.
*/
list_for_each_entry(battery, &acpi_battery_list, list) {
- if (hook->add_battery(battery->bat)) {
+ if (hook->add_battery(battery->bat, hook)) {
/*
* If a add-battery returns non-zero,
* the registration of the extension has failed,
@@ -735,6 +736,8 @@ void battery_hook_register(struct acpi_battery_hook *hook)
__battery_hook_unregister(hook, 0);
goto end;
}
+
+ power_supply_changed(battery->bat);
}
pr_info("new extension: %s\n", hook->name);
end:
@@ -762,7 +765,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery)
* during the battery module initialization.
*/
list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
- if (hook_node->add_battery(battery->bat)) {
+ if (hook_node->add_battery(battery->bat, hook_node)) {
/*
* The notification of the extensions has failed, to
* prevent further errors we will unload the extension.
@@ -785,7 +788,7 @@ static void battery_hook_remove_battery(struct acpi_battery *battery)
* custom attributes from the battery.
*/
list_for_each_entry(hook, &battery_hook_list, list) {
- hook->remove_battery(battery->bat);
+ hook->remove_battery(battery->bat, hook);
}
/* Then, just remove the battery from the list */
list_del(&battery->list);
@@ -1208,12 +1211,12 @@ fail:
return result;
}
-static int acpi_battery_remove(struct acpi_device *device)
+static void acpi_battery_remove(struct acpi_device *device)
{
struct acpi_battery *battery = NULL;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
device_init_wakeup(&device->dev, 0);
battery = acpi_driver_data(device);
unregister_pm_notifier(&battery->pm_nb);
@@ -1221,7 +1224,6 @@ static int acpi_battery_remove(struct acpi_device *device)
mutex_destroy(&battery->lock);
mutex_destroy(&battery->sysfs_lock);
kfree(battery);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d466c8195314..0c05ccde1f7a 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -27,6 +27,7 @@
#include <linux/dmi.h>
#endif
#include <linux/acpi_agdi.h>
+#include <linux/acpi_apmt.h>
#include <linux/acpi_iort.h>
#include <linux/acpi_viot.h>
#include <linux/pci.h>
@@ -323,6 +324,8 @@ static void acpi_bus_osc_negotiate_platform_control(void)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
if (IS_ENABLED(CONFIG_ACPI_PRMT))
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PRM_SUPPORT;
+ if (IS_ENABLED(CONFIG_ACPI_FFH))
+ capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_FFH_OPR_SUPPORT;
#ifdef CONFIG_ARM64
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT;
@@ -1408,6 +1411,7 @@ static int __init acpi_init(void)
disable_acpi();
return result;
}
+ acpi_init_ffh();
pci_mmcfg_late_init();
acpi_iort_init();
@@ -1423,6 +1427,7 @@ static int __init acpi_init(void)
acpi_setup_sb_notify_handler();
acpi_viot_init();
acpi_agdi_init();
+ acpi_apmt_init();
return 0;
}
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1f9b9a4c38c7..475e1eddfa3b 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -125,7 +125,7 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
};
static int acpi_button_add(struct acpi_device *device);
-static int acpi_button_remove(struct acpi_device *device);
+static void acpi_button_remove(struct acpi_device *device);
static void acpi_button_notify(struct acpi_device *device, u32 event);
#ifdef CONFIG_PM_SLEEP
@@ -580,14 +580,13 @@ static int acpi_button_add(struct acpi_device *device)
return error;
}
-static int acpi_button_remove(struct acpi_device *device)
+static void acpi_button_remove(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
acpi_button_remove_fs(device);
input_unregister_device(button->input);
kfree(button);
- return 0;
}
static int param_set_lid_init_state(const char *val,
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 093675b1a1ff..0f17b1c32718 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -148,7 +148,7 @@ __ATTR(_name, 0444, show_##_name, NULL)
if (ret) \
return ret; \
\
- return scnprintf(buf, PAGE_SIZE, "%llu\n", \
+ return sysfs_emit(buf, "%llu\n", \
(u64)st_name.member_name); \
} \
define_one_cppc_ro(member_name)
@@ -174,7 +174,7 @@ static ssize_t show_feedback_ctrs(struct kobject *kobj,
if (ret)
return ret;
- return scnprintf(buf, PAGE_SIZE, "ref:%llu del:%llu\n",
+ return sysfs_emit(buf, "ref:%llu del:%llu\n",
fb_ctrs.reference, fb_ctrs.delivered);
}
define_one_cppc_ro(feedback_ctrs);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 9b42628cf21b..2520fb998ce6 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1663,12 +1663,12 @@ err:
return ret;
}
-static int acpi_ec_remove(struct acpi_device *device)
+static void acpi_ec_remove(struct acpi_device *device)
{
struct acpi_ec *ec;
if (!device)
- return -EINVAL;
+ return;
ec = acpi_driver_data(device);
release_region(ec->data_addr, 1);
@@ -1678,7 +1678,6 @@ static int acpi_ec_remove(struct acpi_device *device)
ec_remove_handlers(ec);
acpi_ec_free(ec);
}
- return 0;
}
static acpi_status
@@ -1877,6 +1876,16 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = {
},
{
/*
+ * HP Pavilion Gaming Laptop 15-cx0041ur
+ */
+ .callback = ec_honor_dsdt_gpe,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 15-cx0041ur"),
+ },
+ },
+ {
+ /*
* Samsung hardware
* https://bugzilla.kernel.org/show_bug.cgi?id=44161
*/
diff --git a/drivers/acpi/fan_attr.c b/drivers/acpi/fan_attr.c
index f15157d40713..f4f6e2381f1d 100644
--- a/drivers/acpi/fan_attr.c
+++ b/drivers/acpi/fan_attr.c
@@ -27,24 +27,24 @@ static ssize_t show_state(struct device *dev, struct device_attribute *attr, cha
count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ count += sysfs_emit_at(buf, count, "not-defined:");
else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point);
+ count += sysfs_emit_at(buf, count, "%lld:", fps->trip_point);
if (fps->speed == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ count += sysfs_emit_at(buf, count, "not-defined:");
else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed);
+ count += sysfs_emit_at(buf, count, "%lld:", fps->speed);
if (fps->noise_level == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ count += sysfs_emit_at(buf, count, "not-defined:");
else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100);
+ count += sysfs_emit_at(buf, count, "%lld:", fps->noise_level * 100);
if (fps->power == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined\n");
+ count += sysfs_emit_at(buf, count, "not-defined\n");
else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld\n", fps->power);
+ count += sysfs_emit_at(buf, count, "%lld\n", fps->power);
return count;
}
diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c
index 52a0b303b70a..9dccbae9e8ea 100644
--- a/drivers/acpi/fan_core.c
+++ b/drivers/acpi/fan_core.c
@@ -236,6 +236,7 @@ static int acpi_fan_get_fif(struct acpi_device *device)
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Invalid _FIF element\n");
status = -EINVAL;
+ goto err;
}
fan->fif.revision = fields[0];
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index 60a2939cde6c..78d44e3fe129 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -56,10 +56,9 @@ static int acpi_hed_add(struct acpi_device *device)
return 0;
}
-static int acpi_hed_remove(struct acpi_device *device)
+static void acpi_hed_remove(struct acpi_device *device)
{
hed_handle = NULL;
- return 0;
}
static struct acpi_driver acpi_hed_driver = {
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index 1cc4647f78b8..c2c786eb95ab 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -94,6 +94,7 @@ EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
/**
* acpi_get_irq_source_fwhandle() - Retrieve fwhandle from IRQ resource source.
* @source: acpi_resource_source to use for the lookup.
+ * @gsi: GSI IRQ number
*
* Description:
* Retrieve the fwhandle of the device referenced by the given IRQ resource
@@ -297,8 +298,8 @@ EXPORT_SYMBOL_GPL(acpi_irq_get);
/**
* acpi_set_irq_model - Setup the GSI irqdomain information
* @model: the value assigned to acpi_irq_model
- * @fwnode: the irq_domain identifier for mapping and looking up
- * GSI interrupts
+ * @fn: a dispatcher function that will return the domain fwnode
+ * for a given GSI
*/
void __init acpi_set_irq_model(enum acpi_irq_model_id model,
struct fwnode_handle *(*fn)(u32))
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index ae5f4acf2675..f1cc5ec6a3b6 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -3371,10 +3371,9 @@ static int acpi_nfit_add(struct acpi_device *adev)
return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
}
-static int acpi_nfit_remove(struct acpi_device *adev)
+static void acpi_nfit_remove(struct acpi_device *adev)
{
/* see acpi_nfit_unregister */
- return 0;
}
static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c
index 8dd792a55730..3902759abcba 100644
--- a/drivers/acpi/nfit/intel.c
+++ b/drivers/acpi/nfit/intel.c
@@ -3,6 +3,7 @@
#include <linux/libnvdimm.h>
#include <linux/ndctl.h>
#include <linux/acpi.h>
+#include <linux/memregion.h>
#include <asm/smp.h>
#include "intel.h"
#include "nfit.h"
@@ -190,8 +191,6 @@ static int intel_security_change_key(struct nvdimm *nvdimm,
}
}
-static void nvdimm_invalidate_cache(void);
-
static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
const struct nvdimm_key_data *key_data)
{
@@ -227,9 +226,6 @@ static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
return -EIO;
}
- /* DIMM unlocked, invalidate all CPU caches before we read it */
- nvdimm_invalidate_cache();
-
return 0;
}
@@ -297,8 +293,6 @@ static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
if (!test_bit(cmd, &nfit_mem->dsm_mask))
return -ENOTTY;
- /* flush all cache before we erase DIMM */
- nvdimm_invalidate_cache();
memcpy(nd_cmd.cmd.passphrase, key->data,
sizeof(nd_cmd.cmd.passphrase));
rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
@@ -317,8 +311,6 @@ static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
return -ENXIO;
}
- /* DIMM erased, invalidate all CPU caches before we read it */
- nvdimm_invalidate_cache();
return 0;
}
@@ -354,8 +346,6 @@ static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
return -ENXIO;
}
- /* flush all cache before we make the nvdimms available */
- nvdimm_invalidate_cache();
return 0;
}
@@ -380,8 +370,6 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask))
return -ENOTTY;
- /* flush all cache before we erase DIMM */
- nvdimm_invalidate_cache();
memcpy(nd_cmd.cmd.passphrase, nkey->data,
sizeof(nd_cmd.cmd.passphrase));
rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
@@ -401,22 +389,6 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
}
}
-/*
- * TODO: define a cross arch wbinvd equivalent when/if
- * NVDIMM_FAMILY_INTEL command support arrives on another arch.
- */
-#ifdef CONFIG_X86
-static void nvdimm_invalidate_cache(void)
-{
- wbinvd_on_all_cpus();
-}
-#else
-static void nvdimm_invalidate_cache(void)
-{
- WARN_ON_ONCE("cache invalidation required after unlock\n");
-}
-#endif
-
static const struct nvdimm_security_ops __intel_security_ops = {
.get_flags = intel_security_flags,
.freeze = intel_security_freeze,
diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c
index 23f49a2f4d14..6cceca64a6bc 100644
--- a/drivers/acpi/numa/hmat.c
+++ b/drivers/acpi/numa/hmat.c
@@ -562,17 +562,26 @@ static int initiator_cmp(void *priv, const struct list_head *a,
{
struct memory_initiator *ia;
struct memory_initiator *ib;
- unsigned long *p_nodes = priv;
ia = list_entry(a, struct memory_initiator, node);
ib = list_entry(b, struct memory_initiator, node);
- set_bit(ia->processor_pxm, p_nodes);
- set_bit(ib->processor_pxm, p_nodes);
-
return ia->processor_pxm - ib->processor_pxm;
}
+static int initiators_to_nodemask(unsigned long *p_nodes)
+{
+ struct memory_initiator *initiator;
+
+ if (list_empty(&initiators))
+ return -ENXIO;
+
+ list_for_each_entry(initiator, &initiators, node)
+ set_bit(initiator->processor_pxm, p_nodes);
+
+ return 0;
+}
+
static void hmat_register_target_initiators(struct memory_target *target)
{
static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);
@@ -609,7 +618,10 @@ static void hmat_register_target_initiators(struct memory_target *target)
* initiators.
*/
bitmap_zero(p_nodes, MAX_NUMNODES);
- list_sort(p_nodes, &initiators, initiator_cmp);
+ list_sort(NULL, &initiators, initiator_cmp);
+ if (initiators_to_nodemask(p_nodes) < 0)
+ return;
+
if (!access0done) {
for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) {
loc = localities_types[i];
@@ -643,8 +655,9 @@ static void hmat_register_target_initiators(struct memory_target *target)
/* Access 1 ignores Generic Initiators */
bitmap_zero(p_nodes, MAX_NUMNODES);
- list_sort(p_nodes, &initiators, initiator_cmp);
- best = 0;
+ if (initiators_to_nodemask(p_nodes) < 0)
+ return;
+
for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) {
loc = localities_types[i];
if (!loc)
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 08e15774fb9f..ff30ceca2203 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -387,13 +387,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
u8 pin;
int triggering = ACPI_LEVEL_SENSITIVE;
/*
- * On ARM systems with the GIC interrupt model, level interrupts
+ * On ARM systems with the GIC interrupt model, or LoongArch
+ * systems with the LPIC interrupt model, level interrupts
* are always polarity high by specification; PCI legacy
* IRQs lines are inverted before reaching the interrupt
* controller and must therefore be considered active high
* as default.
*/
- int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
+ int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ||
+ acpi_irq_model == ACPI_IRQ_MODEL_LPIC ?
ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
char *link = NULL;
char link_desc[16];
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4e3db20e9cbb..b3c202d2a433 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -493,6 +493,7 @@ static u32 calculate_cxl_support(void)
u32 support;
support = OSC_CXL_2_0_PORT_DEV_REG_ACCESS_SUPPORT;
+ support |= OSC_CXL_1_1_PORT_REG_ACCESS_SUPPORT;
if (pci_aer_available())
support |= OSC_CXL_PROTOCOL_ERR_REPORTING_SUPPORT;
if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
diff --git a/drivers/acpi/pfr_telemetry.c b/drivers/acpi/pfr_telemetry.c
index 9abf350bd7a5..27fb6cdad75f 100644
--- a/drivers/acpi/pfr_telemetry.c
+++ b/drivers/acpi/pfr_telemetry.c
@@ -144,7 +144,7 @@ static int get_pfrt_log_data_info(struct pfrt_log_data_info *data_info,
ret = 0;
free_acpi_buffer:
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
@@ -180,7 +180,7 @@ static int set_pfrt_log_level(int level, struct pfrt_log_device *pfrt_log_dev)
ret = -EBUSY;
}
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
@@ -218,7 +218,7 @@ static int get_pfrt_log_level(struct pfrt_log_device *pfrt_log_dev)
ret = obj->integer.value;
free_acpi_buffer:
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
diff --git a/drivers/acpi/pfr_update.c b/drivers/acpi/pfr_update.c
index 6bb0b778b5da..98267f163e2b 100644
--- a/drivers/acpi/pfr_update.c
+++ b/drivers/acpi/pfr_update.c
@@ -178,7 +178,7 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
ret = 0;
free_acpi_buffer:
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
@@ -224,7 +224,7 @@ static int query_buffer(struct pfru_com_buf_info *info,
ret = 0;
free_acpi_buffer:
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
@@ -385,7 +385,7 @@ static int start_update(int action, struct pfru_device *pfru_dev)
ret = 0;
free_acpi_buffer:
- kfree(out_obj);
+ ACPI_FREE(out_obj);
return ret;
}
@@ -455,7 +455,7 @@ static ssize_t pfru_write(struct file *file, const char __user *buf,
iov.iov_base = (void __user *)buf;
iov.iov_len = len;
- iov_iter_init(&iter, WRITE, &iov, 1, len);
+ iov_iter_init(&iter, ITER_SOURCE, &iov, 1, len);
/* map the communication buffer */
phy_addr = (phys_addr_t)((buf_info.addr_hi << 32) | buf_info.addr_lo);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index f2588aba8421..23507d29f000 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -967,7 +967,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
if (acpi_power_get_state(resource, &state_dummy))
__acpi_power_on(resource);
- pr_info("%s [%s]\n", acpi_device_name(device), acpi_device_bid(device));
+ acpi_handle_info(handle, "New power resource\n");
result = acpi_tie_acpi_dev(device);
if (result)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index acfabfe07c4f..7bf882fcd64b 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -324,7 +324,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* the erratum), but this is known to disrupt certain ISA
* devices thus we take the conservative approach.
*/
- else if (errata.piix4.fdma) {
+ if (errata.piix4.fdma) {
acpi_handle_debug(pr->handle,
"C3 not supported on PIIX4 with Type-F DMA\n");
return;
@@ -384,8 +384,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* handle BM_RLD is to set it and leave it set.
*/
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
-
- return;
}
static int acpi_cst_latency_cmp(const void *a, const void *b)
@@ -459,7 +457,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
lapic_timer_propagate_broadcast(pr);
- return (working);
+ return working;
}
static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
@@ -1134,6 +1132,9 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
status = acpi_get_parent(handle, &pr_ahandle);
while (ACPI_SUCCESS(status)) {
d = acpi_fetch_acpi_dev(pr_ahandle);
+ if (!d)
+ break;
+
handle = pr_ahandle;
if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 757a98f6d7a2..970f04a958cd 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -142,6 +142,7 @@ int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
pr = per_cpu(processors, cpu);
if (!pr || !pr->performance || !pr->performance->state_count)
return -ENODEV;
+
*limit = pr->performance->states[pr->performance_platform_limit].
core_frequency * 1000;
return 0;
@@ -201,8 +202,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
}
pct = (union acpi_object *)buffer.pointer;
- if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
- || (pct->package.count != 2)) {
+ if (!pct || pct->type != ACPI_TYPE_PACKAGE || pct->package.count != 2) {
pr_err("Invalid _PCT data\n");
result = -EFAULT;
goto end;
@@ -214,9 +214,8 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
obj = pct->package.elements[0];
- if ((obj.type != ACPI_TYPE_BUFFER)
- || (obj.buffer.length < sizeof(struct acpi_pct_register))
- || (obj.buffer.pointer == NULL)) {
+ if (!obj.buffer.pointer || obj.type != ACPI_TYPE_BUFFER ||
+ obj.buffer.length < sizeof(struct acpi_pct_register)) {
pr_err("Invalid _PCT data (control_register)\n");
result = -EFAULT;
goto end;
@@ -230,9 +229,8 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
obj = pct->package.elements[1];
- if ((obj.type != ACPI_TYPE_BUFFER)
- || (obj.buffer.length < sizeof(struct acpi_pct_register))
- || (obj.buffer.pointer == NULL)) {
+ if (!obj.buffer.pointer || obj.type != ACPI_TYPE_BUFFER ||
+ obj.buffer.length < sizeof(struct acpi_pct_register)) {
pr_err("Invalid _PCT data (status_register)\n");
result = -EFAULT;
goto end;
@@ -260,8 +258,8 @@ static void amd_fixup_frequency(struct acpi_processor_px *px, int i)
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return;
- if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
- || boot_cpu_data.x86 == 0x11) {
+ if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) ||
+ boot_cpu_data.x86 == 0x11) {
rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi);
/*
* MSR C001_0064+:
@@ -300,7 +298,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
}
pss = buffer.pointer;
- if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
+ if (!pss || pss->type != ACPI_TYPE_PACKAGE) {
pr_err("Invalid _PSS data\n");
result = -EFAULT;
goto end;
@@ -353,8 +351,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
* Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
*/
if (!px->core_frequency ||
- ((u32)(px->core_frequency * 1000) !=
- (px->core_frequency * 1000))) {
+ (u32)(px->core_frequency * 1000) != px->core_frequency * 1000) {
pr_err(FW_BUG
"Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz\n",
pr->id, px->core_frequency);
@@ -456,7 +453,7 @@ int acpi_processor_pstate_control(void)
int acpi_processor_notify_smm(struct module *calling_module)
{
static int is_done;
- int result;
+ int result = 0;
if (!acpi_processor_cpufreq_init)
return -EBUSY;
@@ -464,42 +461,41 @@ int acpi_processor_notify_smm(struct module *calling_module)
if (!try_module_get(calling_module))
return -EINVAL;
- /* is_done is set to negative if an error occurred,
- * and to postitive if _no_ error occurred, but SMM
- * was already notified. This avoids double notification
- * which might lead to unexpected results...
+ /*
+ * is_done is set to negative if an error occurs and to 1 if no error
+ * occurrs, but SMM has been notified already. This avoids repeated
+ * notification which might lead to unexpected results.
*/
- if (is_done > 0) {
- module_put(calling_module);
- return 0;
- } else if (is_done < 0) {
- module_put(calling_module);
- return is_done;
- }
+ if (is_done != 0) {
+ if (is_done < 0)
+ result = is_done;
- is_done = -EIO;
+ goto out_put;
+ }
result = acpi_processor_pstate_control();
- if (!result) {
- pr_debug("No SMI port or pstate_control\n");
- module_put(calling_module);
- return 0;
- }
- if (result < 0) {
- module_put(calling_module);
- return result;
+ if (result <= 0) {
+ if (result) {
+ is_done = result;
+ } else {
+ pr_debug("No SMI port or pstate_control\n");
+ is_done = 1;
+ }
+ goto out_put;
}
- /* Success. If there's no _PPC, we need to fear nothing, so
- * we can allow the cpufreq driver to be rmmod'ed. */
is_done = 1;
+ /*
+ * Success. If there _PPC, unloading the cpufreq driver would be risky,
+ * so disallow it in that case.
+ */
+ if (acpi_processor_ppc_in_use)
+ return 0;
- if (!acpi_processor_ppc_in_use)
- module_put(calling_module);
-
- return 0;
+out_put:
+ module_put(calling_module);
+ return result;
}
-
EXPORT_SYMBOL(acpi_processor_notify_smm);
int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
@@ -517,7 +513,7 @@ int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
}
psd = buffer.pointer;
- if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
+ if (!psd || psd->type != ACPI_TYPE_PACKAGE) {
pr_err("Invalid _PSD data\n");
result = -EFAULT;
goto end;
@@ -532,8 +528,7 @@ int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
state.length = sizeof(struct acpi_psd_package);
state.pointer = pdomain;
- status = acpi_extract_package(&(psd->package.elements[0]),
- &format, &state);
+ status = acpi_extract_package(&(psd->package.elements[0]), &format, &state);
if (ACPI_FAILURE(status)) {
pr_err("Invalid _PSD data\n");
result = -EFAULT;
@@ -716,9 +711,8 @@ err_out:
}
EXPORT_SYMBOL(acpi_processor_preregister_performance);
-int
-acpi_processor_register_performance(struct acpi_processor_performance
- *performance, unsigned int cpu)
+int acpi_processor_register_performance(struct acpi_processor_performance
+ *performance, unsigned int cpu)
{
struct acpi_processor *pr;
@@ -751,7 +745,6 @@ acpi_processor_register_performance(struct acpi_processor_performance
mutex_unlock(&performance_mutex);
return 0;
}
-
EXPORT_SYMBOL(acpi_processor_register_performance);
void acpi_processor_unregister_performance(unsigned int cpu)
@@ -761,18 +754,15 @@ void acpi_processor_unregister_performance(unsigned int cpu)
mutex_lock(&performance_mutex);
pr = per_cpu(processors, cpu);
- if (!pr) {
- mutex_unlock(&performance_mutex);
- return;
- }
+ if (!pr)
+ goto unlock;
if (pr->performance)
kfree(pr->performance->states);
+
pr->performance = NULL;
+unlock:
mutex_unlock(&performance_mutex);
-
- return;
}
-
EXPORT_SYMBOL(acpi_processor_unregister_performance);
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index a822fe410dda..00d045e5f524 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -50,7 +50,7 @@ static int __acpi_processor_set_throttling(struct acpi_processor *pr,
static int acpi_processor_update_tsd_coord(void)
{
- int count, count_target;
+ int count_target;
int retval = 0;
unsigned int i, j;
cpumask_var_t covered_cpus;
@@ -107,7 +107,6 @@ static int acpi_processor_update_tsd_coord(void)
/* Validate the Domain info */
count_target = pdomain->num_processors;
- count = 1;
for_each_possible_cpu(j) {
if (i == j)
@@ -140,7 +139,6 @@ static int acpi_processor_update_tsd_coord(void)
cpumask_set_cpu(j, covered_cpus);
cpumask_set_cpu(j, pthrottling->shared_cpu_map);
- count++;
}
for_each_possible_cpu(j) {
if (i == j)
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index e6a01a8df1b8..e90752d4f488 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -96,7 +96,7 @@ struct acpi_sbs {
#define to_acpi_sbs(x) power_supply_get_drvdata(x)
-static int acpi_sbs_remove(struct acpi_device *device);
+static void acpi_sbs_remove(struct acpi_device *device);
static int acpi_battery_get_state(struct acpi_battery *battery);
static inline int battery_scale(int log)
@@ -664,16 +664,16 @@ end:
return result;
}
-static int acpi_sbs_remove(struct acpi_device *device)
+static void acpi_sbs_remove(struct acpi_device *device)
{
struct acpi_sbs *sbs;
int id;
if (!device)
- return -EINVAL;
+ return;
sbs = acpi_driver_data(device);
if (!sbs)
- return -EINVAL;
+ return;
mutex_lock(&sbs->lock);
acpi_smbus_unregister_callback(sbs->hc);
for (id = 0; id < MAX_SBS_BAT; ++id)
@@ -682,7 +682,6 @@ static int acpi_sbs_remove(struct acpi_device *device)
mutex_unlock(&sbs->lock);
mutex_destroy(&sbs->lock);
kfree(sbs);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 340e0b61587e..16f2daaa2c45 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -30,7 +30,7 @@ struct acpi_smb_hc {
};
static int acpi_smbus_hc_add(struct acpi_device *device);
-static int acpi_smbus_hc_remove(struct acpi_device *device);
+static void acpi_smbus_hc_remove(struct acpi_device *device);
static const struct acpi_device_id sbs_device_ids[] = {
{"ACPI0001", 0},
@@ -280,19 +280,18 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
-static int acpi_smbus_hc_remove(struct acpi_device *device)
+static void acpi_smbus_hc_remove(struct acpi_device *device)
{
struct acpi_smb_hc *hc;
if (!device)
- return -EINVAL;
+ return;
hc = acpi_driver_data(device);
acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
acpi_os_wait_events_complete();
kfree(hc);
device->driver_data = NULL;
- return 0;
}
module_acpi_driver(acpi_smb_hc_driver);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index b47e93a24a9a..274344434282 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -30,7 +30,7 @@ extern struct acpi_device *acpi_root;
#define ACPI_BUS_HID "LNXSYBUS"
#define ACPI_BUS_DEVICE_NAME "System Bus"
-#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page)
+#define INVALID_ACPI_HANDLE ((acpi_handle)ZERO_PAGE(0))
static const char *dummy_hid = "device";
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index cc2fe0618178..7db3b530279b 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -9,6 +9,7 @@
#include <linux/bitmap.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/moduleparam.h>
#include "internal.h"
@@ -197,7 +198,7 @@ static int param_set_trace_method_name(const char *val,
static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp)
{
- return scnprintf(buffer, PAGE_SIZE, "%s\n", acpi_gbl_trace_method_name);
+ return sysfs_emit(buffer, "%s\n", acpi_gbl_trace_method_name);
}
static const struct kernel_param_ops param_ops_trace_method = {
@@ -992,7 +993,7 @@ static ssize_t force_remove_store(struct kobject *kobj,
bool val;
int ret;
- ret = strtobool(buf, &val);
+ ret = kstrtobool(buf, &val);
if (ret < 0)
return ret;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 47ec11d4c68e..5fbc32b802d0 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -210,6 +210,16 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
break;
+ case ACPI_MADT_TYPE_CORE_PIC:
+ {
+ struct acpi_madt_core_pic *p = (struct acpi_madt_core_pic *)header;
+
+ pr_debug("CORE PIC (processor_id[0x%02x] core_id[0x%02x] %s)\n",
+ p->processor_id, p->core_id,
+ (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+ }
+ break;
+
default:
pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
header->type);
@@ -838,12 +848,11 @@ acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
/*
* acpi_locate_initial_tables()
*
- * find RSDP, find and checksum SDT/XSDT.
- * checksum all tables, print SDT/XSDT
+ * Get the RSDP, then find and checksum all the ACPI tables.
*
- * result: sdt_entry[] is initialized
+ * result: initial_tables[] is initialized, and points to
+ * a list of ACPI tables.
*/
-
int __init acpi_locate_initial_tables(void)
{
acpi_status status;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 40b07057983e..0b4b844f9d4c 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -74,7 +74,7 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static struct workqueue_struct *acpi_thermal_pm_queue;
static int acpi_thermal_add(struct acpi_device *device);
-static int acpi_thermal_remove(struct acpi_device *device);
+static void acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id thermal_device_ids[] = {
@@ -291,7 +291,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
"Found critical threshold [%lu]\n",
tz->trips.critical.temperature);
}
- if (tz->trips.critical.flags.valid == 1) {
+ if (tz->trips.critical.flags.valid) {
if (crt == -1) {
tz->trips.critical.flags.valid = 0;
} else if (crt > 0) {
@@ -1059,19 +1059,18 @@ end:
return result;
}
-static int acpi_thermal_remove(struct acpi_device *device)
+static void acpi_thermal_remove(struct acpi_device *device)
{
struct acpi_thermal *tz;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
flush_workqueue(acpi_thermal_pm_queue);
tz = acpi_driver_data(device);
acpi_thermal_unregister_thermal_zone(tz);
kfree(tz);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/acpi/tiny-power-button.c b/drivers/acpi/tiny-power-button.c
index a19f0e4e69f7..598f548b21f3 100644
--- a/drivers/acpi/tiny-power-button.c
+++ b/drivers/acpi/tiny-power-button.c
@@ -19,11 +19,15 @@ static const struct acpi_device_id tiny_power_button_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids);
-static int acpi_noop_add_remove(struct acpi_device *device)
+static int acpi_noop_add(struct acpi_device *device)
{
return 0;
}
+static void acpi_noop_remove(struct acpi_device *device)
+{
+}
+
static void acpi_tiny_power_button_notify(struct acpi_device *device, u32 event)
{
kill_cad_pid(power_signal, 1);
@@ -34,8 +38,8 @@ static struct acpi_driver acpi_tiny_power_button_driver = {
.class = "tiny-power-button",
.ids = tiny_power_button_device_ids,
.ops = {
- .add = acpi_noop_add_remove,
- .remove = acpi_noop_add_remove,
+ .add = acpi_noop_add,
+ .remove = acpi_noop_remove,
.notify = acpi_tiny_power_button_notify,
},
};
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 9cd8797d12bb..a934bbc9dd37 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -132,6 +132,10 @@ static int video_detect_force_none(const struct dmi_system_id *d)
}
static const struct dmi_system_id video_detect_dmi_table[] = {
+ /*
+ * Models which should use the vendor backlight interface,
+ * because of broken ACPI video backlight control.
+ */
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */
.callback = video_detect_force_vendor,
@@ -166,6 +170,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ /* https://bugs.launchpad.net/bugs/1000146 */
.callback = video_detect_force_vendor,
/* Asus X101CH */
.matches = {
@@ -190,6 +195,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ /* https://bugs.launchpad.net/bugs/1000146 */
.callback = video_detect_force_vendor,
/* Asus 1015CX */
.matches = {
@@ -199,14 +205,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
{
.callback = video_detect_force_vendor,
- /* GIGABYTE GB-BXBT-2807 */
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
- DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
- },
- },
- {
- .callback = video_detect_force_vendor,
/* Samsung N150/N210/N220 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
@@ -234,18 +232,23 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
{
.callback = video_detect_force_vendor,
- /* Sony VPCEH3U1E */
+ /* Xiaomi Mi Pad 2 */
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
},
},
+
+ /*
+ * Models which should use the vendor backlight interface,
+ * because of broken native backlight control.
+ */
{
.callback = video_detect_force_vendor,
- /* Xiaomi Mi Pad 2 */
+ /* Sony Vaio PCG-FRV35 */
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"),
},
},
@@ -400,8 +403,8 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
},
},
- /* https://bugs.launchpad.net/bugs/1894667 */
{
+ /* https://bugs.launchpad.net/bugs/1894667 */
.callback = video_detect_force_video,
/* HP 635 Notebook */
.matches = {
@@ -609,6 +612,23 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "N250P"),
},
},
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=202401 */
+ .callback = video_detect_force_native,
+ /* Sony Vaio VPCEH3U1E */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
+ },
+ },
+ {
+ .callback = video_detect_force_native,
+ /* Sony Vaio VPCY11S1E */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VPCY11S1E"),
+ },
+ },
/*
* These Toshibas have a broken acpi-video interface for brightness
@@ -646,6 +666,20 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
/*
+ * Models which have nvidia-ec-wmi support, but should not use it.
+ * Note this indicates a likely firmware bug on these models and should
+ * be revisited if/when Linux gets support for dynamic mux mode.
+ */
+ {
+ .callback = video_detect_force_native,
+ /* Dell G15 5515 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
+ },
+ },
+
+ /*
* Desktops which falsely report a backlight and which our heuristics
* for this do not catch.
*/
@@ -659,6 +693,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
{
.callback = video_detect_force_none,
+ /* GIGABYTE GB-BXBT-2807 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
+ },
+ },
+ {
+ .callback = video_detect_force_none,
/* MSI MS-7721 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
@@ -670,7 +712,17 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
static bool google_cros_ec_present(void)
{
- return acpi_dev_found("GOOG0004");
+ return acpi_dev_found("GOOG0004") || acpi_dev_found("GOOG000C");
+}
+
+/*
+ * Windows 8 and newer no longer use the ACPI video interface, so it often
+ * does not work. So on win8+ systems prefer native brightness control.
+ * Chromebooks should always prefer native backlight control.
+ */
+static bool prefer_native_over_acpi_video(void)
+{
+ return acpi_osi_is_win8() || google_cros_ec_present();
}
/*
@@ -718,31 +770,16 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
if (apple_gmux_present())
return acpi_backlight_apple_gmux;
- /* On systems with ACPI video use either native or ACPI video. */
- if (video_caps & ACPI_VIDEO_BACKLIGHT) {
- /*
- * Windows 8 and newer no longer use the ACPI video interface,
- * so it often does not work. If the ACPI tables are written
- * for win8 and native brightness ctl is available, use that.
- *
- * The native check deliberately is inside the if acpi-video
- * block on older devices without acpi-video support native
- * is usually not the best choice.
- */
- if (acpi_osi_is_win8() && native_available)
- return acpi_backlight_native;
- else
- return acpi_backlight_video;
- }
+ /* Use ACPI video if available, except when native should be preferred. */
+ if ((video_caps & ACPI_VIDEO_BACKLIGHT) &&
+ !(native_available && prefer_native_over_acpi_video()))
+ return acpi_backlight_video;
- /*
- * Chromebooks that don't have backlight handle in ACPI table
- * are supposed to use native backlight if it's available.
- */
- if (google_cros_ec_present() && native_available)
+ /* Use native if available */
+ if (native_available)
return acpi_backlight_native;
- /* No ACPI video (old hw), use vendor specific fw methods. */
+ /* No ACPI video/native (old hw), use vendor specific fw methods. */
return acpi_backlight_vendor;
}
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index d7d3f1669d4c..4e816bb402f6 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -308,7 +308,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
},
{
- /* Lenovo Yoga Tablet 1050F/L */
+ /* Lenovo Yoga Tablet 2 1050F/L */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
@@ -320,6 +320,27 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
},
{
+ /* Lenovo Yoga Tab 3 Pro X90F */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
+ .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
+ ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
+ },
+ {
+ /* Medion Lifetab S10346 */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+ /* Way too generic, also match on BIOS data */
+ DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"),
+ },
+ .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
+ ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
+ },
+ {
/* Nextbook Ares 8 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
@@ -348,6 +369,7 @@ static const struct acpi_device_id i2c_acpi_known_good_ids[] = {
{ "10EC5640", 0 }, /* RealTek ALC5640 audio codec */
{ "INT33F4", 0 }, /* X-Powers AXP288 PMIC */
{ "INT33FD", 0 }, /* Intel Crystal Cove PMIC */
+ { "INT34D3", 0 }, /* Intel Whiskey Cove PMIC */
{ "NPCE69A", 0 }, /* Asus Transformer keyboard dock */
{}
};
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 1c39cfce32fa..4ad42b0f75cd 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -739,6 +739,12 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
const char *failure_string;
struct binder_buffer *buffer;
+ if (unlikely(vma->vm_mm != alloc->mm)) {
+ ret = -EINVAL;
+ failure_string = "invalid vma->vm_mm";
+ goto err_invalid_mm;
+ }
+
mutex_lock(&binder_alloc_mmap_lock);
if (alloc->buffer_size) {
ret = -EBUSY;
@@ -785,6 +791,7 @@ err_alloc_pages_failed:
alloc->buffer_size = 0;
err_already_mapped:
mutex_unlock(&binder_alloc_mmap_lock);
+err_invalid_mm:
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
"%s: %d %lx-%lx %s failed %d\n", __func__,
alloc->pid, vma->vm_start, vma->vm_end,
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 36833a862998..eceaec33af65 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -295,7 +295,7 @@ config SATA_FSL
config SATA_GEMINI
tristate "Gemini SATA bridge support"
- depends on ARCH_GEMINI || (OF && COMPILE_TEST)
+ depends on ARCH_GEMINI || COMPILE_TEST
select SATA_HOST
default ARCH_GEMINI
help
@@ -609,16 +609,6 @@ config PATA_ATP867X
If unsure, say N.
-config PATA_BK3710
- tristate "Palmchip BK3710 PATA support"
- depends on ARCH_DAVINCI || COMPILE_TEST
- select PATA_TIMINGS
- help
- This option enables support for the integrated IDE controller on
- the TI DaVinci SoC.
-
- If unsure, say N.
-
config PATA_CMD64X
tristate "CMD64x PATA support"
depends on PCI
@@ -696,7 +686,6 @@ config PATA_EP93XX
config PATA_FTIDE010
tristate "Faraday Technology FTIDE010 PATA support"
- depends on OF
depends on ARM || COMPILE_TEST
depends on SATA_GEMINI
help
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 34623365d9a6..d2e36d367274 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -54,7 +54,6 @@ obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o
-obj-$(CONFIG_PATA_BK3710) += pata_bk3710.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 639de2d75d63..0cfd0ec6229b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -26,7 +26,6 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/gfp.h>
-#include <linux/msi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 7add8e79912b..ff8e6ae1c636 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -24,6 +24,7 @@
#include <linux/libata.h>
#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
+#include <linux/bits.h>
/* Enclosure Management Control */
#define EM_CTRL_MSG_TYPE 0x000f0000
@@ -53,12 +54,12 @@ enum {
AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ +
AHCI_CMD_TBL_AR_SZ +
(AHCI_RX_FIS_SZ * 16),
- AHCI_IRQ_ON_SG = (1 << 31),
- AHCI_CMD_ATAPI = (1 << 5),
- AHCI_CMD_WRITE = (1 << 6),
- AHCI_CMD_PREFETCH = (1 << 7),
- AHCI_CMD_RESET = (1 << 8),
- AHCI_CMD_CLR_BUSY = (1 << 10),
+ AHCI_IRQ_ON_SG = BIT(31),
+ AHCI_CMD_ATAPI = BIT(5),
+ AHCI_CMD_WRITE = BIT(6),
+ AHCI_CMD_PREFETCH = BIT(7),
+ AHCI_CMD_RESET = BIT(8),
+ AHCI_CMD_CLR_BUSY = BIT(10),
RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
@@ -76,37 +77,37 @@ enum {
HOST_CAP2 = 0x24, /* host capabilities, extended */
/* HOST_CTL bits */
- HOST_RESET = (1 << 0), /* reset controller; self-clear */
- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
- HOST_MRSM = (1 << 2), /* MSI Revert to Single Message */
- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
+ HOST_RESET = BIT(0), /* reset controller; self-clear */
+ HOST_IRQ_EN = BIT(1), /* global IRQ enable */
+ HOST_MRSM = BIT(2), /* MSI Revert to Single Message */
+ HOST_AHCI_EN = BIT(31), /* AHCI enabled */
/* HOST_CAP bits */
- HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
- HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
- HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
- HOST_CAP_PART = (1 << 13), /* Partial state capable */
- HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
- HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
- HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
- HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
- HOST_CAP_CLO = (1 << 24), /* Command List Override support */
- HOST_CAP_LED = (1 << 25), /* Supports activity LED */
- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
- HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
- HOST_CAP_SNTF = (1 << 29), /* SNotification register */
- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+ HOST_CAP_SXS = BIT(5), /* Supports External SATA */
+ HOST_CAP_EMS = BIT(6), /* Enclosure Management support */
+ HOST_CAP_CCC = BIT(7), /* Command Completion Coalescing */
+ HOST_CAP_PART = BIT(13), /* Partial state capable */
+ HOST_CAP_SSC = BIT(14), /* Slumber state capable */
+ HOST_CAP_PIO_MULTI = BIT(15), /* PIO multiple DRQ support */
+ HOST_CAP_FBS = BIT(16), /* FIS-based switching support */
+ HOST_CAP_PMP = BIT(17), /* Port Multiplier support */
+ HOST_CAP_ONLY = BIT(18), /* Supports AHCI mode only */
+ HOST_CAP_CLO = BIT(24), /* Command List Override support */
+ HOST_CAP_LED = BIT(25), /* Supports activity LED */
+ HOST_CAP_ALPM = BIT(26), /* Aggressive Link PM support */
+ HOST_CAP_SSS = BIT(27), /* Staggered Spin-up */
+ HOST_CAP_MPS = BIT(28), /* Mechanical presence switch */
+ HOST_CAP_SNTF = BIT(29), /* SNotification register */
+ HOST_CAP_NCQ = BIT(30), /* Native Command Queueing */
+ HOST_CAP_64 = BIT(31), /* PCI DAC (64-bit DMA) support */
/* HOST_CAP2 bits */
- HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
- HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
- HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
- HOST_CAP2_SDS = (1 << 3), /* Support device sleep */
- HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */
- HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */
+ HOST_CAP2_BOH = BIT(0), /* BIOS/OS handoff supported */
+ HOST_CAP2_NVMHCI = BIT(1), /* NVMHCI supported */
+ HOST_CAP2_APST = BIT(2), /* Automatic partial to slumber */
+ HOST_CAP2_SDS = BIT(3), /* Support device sleep */
+ HOST_CAP2_SADM = BIT(4), /* Support aggressive DevSlp */
+ HOST_CAP2_DESO = BIT(5), /* DevSlp from slumber only */
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
@@ -128,24 +129,24 @@ enum {
PORT_DEVSLP = 0x44, /* device sleep */
/* PORT_IRQ_{STAT,MASK} bits */
- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
-
- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
- PORT_IRQ_DMPS = (1 << 7), /* mechanical presence status */
- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
+ PORT_IRQ_COLD_PRES = BIT(31), /* cold presence detect */
+ PORT_IRQ_TF_ERR = BIT(30), /* task file error */
+ PORT_IRQ_HBUS_ERR = BIT(29), /* host bus fatal error */
+ PORT_IRQ_HBUS_DATA_ERR = BIT(28), /* host bus data error */
+ PORT_IRQ_IF_ERR = BIT(27), /* interface fatal error */
+ PORT_IRQ_IF_NONFATAL = BIT(26), /* interface non-fatal error */
+ PORT_IRQ_OVERFLOW = BIT(24), /* xfer exhausted available S/G */
+ PORT_IRQ_BAD_PMP = BIT(23), /* incorrect port multiplier */
+
+ PORT_IRQ_PHYRDY = BIT(22), /* PhyRdy changed */
+ PORT_IRQ_DMPS = BIT(7), /* mechanical presence status */
+ PORT_IRQ_CONNECT = BIT(6), /* port connect change status */
+ PORT_IRQ_SG_DONE = BIT(5), /* descriptor processed */
+ PORT_IRQ_UNK_FIS = BIT(4), /* unknown FIS rx'd */
+ PORT_IRQ_SDB_FIS = BIT(3), /* Set Device Bits FIS rx'd */
+ PORT_IRQ_DMAS_FIS = BIT(2), /* DMA Setup FIS rx'd */
+ PORT_IRQ_PIOS_FIS = BIT(1), /* PIO Setup FIS rx'd */
+ PORT_IRQ_D2H_REG_FIS = BIT(0), /* D2H Register FIS rx'd */
PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
PORT_IRQ_IF_ERR |
@@ -161,27 +162,27 @@ enum {
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
/* PORT_CMD bits */
- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
- PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
- PORT_CMD_ESP = (1 << 21), /* External Sata Port */
- PORT_CMD_CPD = (1 << 20), /* Cold Presence Detection */
- PORT_CMD_MPSP = (1 << 19), /* Mechanical Presence Switch */
- PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */
- PORT_CMD_PMP = (1 << 17), /* PMP attached */
- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
- PORT_CMD_CLO = (1 << 3), /* Command list override */
- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
-
- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ PORT_CMD_ASP = BIT(27), /* Aggressive Slumber/Partial */
+ PORT_CMD_ALPE = BIT(26), /* Aggressive Link PM enable */
+ PORT_CMD_ATAPI = BIT(24), /* Device is ATAPI */
+ PORT_CMD_FBSCP = BIT(22), /* FBS Capable Port */
+ PORT_CMD_ESP = BIT(21), /* External Sata Port */
+ PORT_CMD_CPD = BIT(20), /* Cold Presence Detection */
+ PORT_CMD_MPSP = BIT(19), /* Mechanical Presence Switch */
+ PORT_CMD_HPCP = BIT(18), /* HotPlug Capable Port */
+ PORT_CMD_PMP = BIT(17), /* PMP attached */
+ PORT_CMD_LIST_ON = BIT(15), /* cmd list DMA engine running */
+ PORT_CMD_FIS_ON = BIT(14), /* FIS DMA engine running */
+ PORT_CMD_FIS_RX = BIT(4), /* Enable FIS receive DMA engine */
+ PORT_CMD_CLO = BIT(3), /* Command list override */
+ PORT_CMD_POWER_ON = BIT(2), /* Power up device */
+ PORT_CMD_SPIN_UP = BIT(1), /* Spin up device */
+ PORT_CMD_START = BIT(0), /* Enable port DMA engine */
+
+ PORT_CMD_ICC_MASK = (0xfu << 28), /* i/f ICC state mask */
+ PORT_CMD_ICC_ACTIVE = (0x1u << 28), /* Put i/f in active state */
+ PORT_CMD_ICC_PARTIAL = (0x2u << 28), /* Put i/f in partial state */
+ PORT_CMD_ICC_SLUMBER = (0x6u << 28), /* Put i/f in slumber state */
/* PORT_CMD capabilities mask */
PORT_CMD_CAP = PORT_CMD_HPCP | PORT_CMD_MPSP |
@@ -192,9 +193,9 @@ enum {
PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */
PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */
- PORT_FBS_SDE = (1 << 2), /* FBS single device error */
- PORT_FBS_DEC = (1 << 1), /* FBS device error clear */
- PORT_FBS_EN = (1 << 0), /* Enable FBS */
+ PORT_FBS_SDE = BIT(2), /* FBS single device error */
+ PORT_FBS_DEC = BIT(1), /* FBS device error clear */
+ PORT_FBS_EN = BIT(0), /* Enable FBS */
/* PORT_DEVSLP bits */
PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */
@@ -202,50 +203,50 @@ enum {
PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */
PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */
PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */
- PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */
- PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */
+ PORT_DEVSLP_DSP = BIT(1), /* DevSlp present */
+ PORT_DEVSLP_ADSE = BIT(0), /* Aggressive DevSlp enable */
/* hpriv->flags bits */
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
- AHCI_HFLAG_NO_NCQ = (1 << 0),
- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
- AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
- AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
- AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as
- link offline */
- AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */
- AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */
- AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */
- AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
- port start (wait until
- error-handling stage) */
- AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
- AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
+ AHCI_HFLAG_NO_NCQ = BIT(0),
+ AHCI_HFLAG_IGN_IRQ_IF_ERR = BIT(1), /* ignore IRQ_IF_ERR */
+ AHCI_HFLAG_IGN_SERR_INTERNAL = BIT(2), /* ignore SERR_INTERNAL */
+ AHCI_HFLAG_32BIT_ONLY = BIT(3), /* force 32bit */
+ AHCI_HFLAG_MV_PATA = BIT(4), /* PATA port */
+ AHCI_HFLAG_NO_MSI = BIT(5), /* no PCI MSI */
+ AHCI_HFLAG_NO_PMP = BIT(6), /* no PMP */
+ AHCI_HFLAG_SECT255 = BIT(8), /* max 255 sectors */
+ AHCI_HFLAG_YES_NCQ = BIT(9), /* force NCQ cap on */
+ AHCI_HFLAG_NO_SUSPEND = BIT(10), /* don't suspend */
+ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = BIT(11), /* treat SRST timeout as
+ link offline */
+ AHCI_HFLAG_NO_SNTF = BIT(12), /* no sntf */
+ AHCI_HFLAG_NO_FPDMA_AA = BIT(13), /* no FPDMA AA */
+ AHCI_HFLAG_YES_FBS = BIT(14), /* force FBS cap on */
+ AHCI_HFLAG_DELAY_ENGINE = BIT(15), /* do not start engine on
+ port start (wait until
+ error-handling stage) */
+ AHCI_HFLAG_NO_DEVSLP = BIT(17), /* no device sleep */
+ AHCI_HFLAG_NO_FBS = BIT(18), /* no FBS */
#ifdef CONFIG_PCI_MSI
- AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */
+ AHCI_HFLAG_MULTI_MSI = BIT(20), /* per-port MSI(-X) */
#else
/* compile out MSI infrastructure */
AHCI_HFLAG_MULTI_MSI = 0,
#endif
- AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
- AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */
- AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read
- only registers */
- AHCI_HFLAG_USE_LPM_POLICY = (1 << 25), /* chipset that should use
- SATA_MOBILE_LPM_POLICY
- as default lpm_policy */
- AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during
- suspend/resume */
- AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */
+ AHCI_HFLAG_WAKE_BEFORE_STOP = BIT(22), /* wake before DMA stop */
+ AHCI_HFLAG_YES_ALPM = BIT(23), /* force ALPM cap on */
+ AHCI_HFLAG_NO_WRITE_TO_RO = BIT(24), /* don't write to read
+ only registers */
+ AHCI_HFLAG_USE_LPM_POLICY = BIT(25), /* chipset that should use
+ SATA_MOBILE_LPM_POLICY
+ as default lpm_policy */
+ AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during
+ suspend/resume */
+ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */
/* ap->flags bits */
@@ -261,22 +262,22 @@ enum {
EM_MAX_RETRY = 5,
/* em_ctl bits */
- EM_CTL_RST = (1 << 9), /* Reset */
- EM_CTL_TM = (1 << 8), /* Transmit Message */
- EM_CTL_MR = (1 << 0), /* Message Received */
- EM_CTL_ALHD = (1 << 26), /* Activity LED */
- EM_CTL_XMT = (1 << 25), /* Transmit Only */
- EM_CTL_SMB = (1 << 24), /* Single Message Buffer */
- EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */
- EM_CTL_SES = (1 << 18), /* SES-2 messages supported */
- EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */
- EM_CTL_LED = (1 << 16), /* LED messages supported */
+ EM_CTL_RST = BIT(9), /* Reset */
+ EM_CTL_TM = BIT(8), /* Transmit Message */
+ EM_CTL_MR = BIT(0), /* Message Received */
+ EM_CTL_ALHD = BIT(26), /* Activity LED */
+ EM_CTL_XMT = BIT(25), /* Transmit Only */
+ EM_CTL_SMB = BIT(24), /* Single Message Buffer */
+ EM_CTL_SGPIO = BIT(19), /* SGPIO messages supported */
+ EM_CTL_SES = BIT(18), /* SES-2 messages supported */
+ EM_CTL_SAFTE = BIT(17), /* SAF-TE messages supported */
+ EM_CTL_LED = BIT(16), /* LED messages supported */
/* em message type */
- EM_MSG_TYPE_LED = (1 << 0), /* LED */
- EM_MSG_TYPE_SAFTE = (1 << 1), /* SAF-TE */
- EM_MSG_TYPE_SES2 = (1 << 2), /* SES-2 */
- EM_MSG_TYPE_SGPIO = (1 << 3), /* SGPIO */
+ EM_MSG_TYPE_LED = BIT(0), /* LED */
+ EM_MSG_TYPE_SAFTE = BIT(1), /* SAF-TE */
+ EM_MSG_TYPE_SES2 = BIT(2), /* SES-2 */
+ EM_MSG_TYPE_SGPIO = BIT(3), /* SGPIO */
};
struct ahci_cmd_hdr {
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 954386a2b500..29acc35bf4a6 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -2071,6 +2071,20 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
!(qc->flags & ATA_QCFLAG_FAILED)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15];
+
+ /*
+ * For NCQ commands, we never get a D2H FIS, so reading the D2H Register
+ * FIS area of the Received FIS Structure (which contains a copy of the
+ * last D2H FIS received) will contain an outdated status code.
+ * For NCQ commands, we instead get a SDB FIS, so read the SDB FIS area
+ * instead. However, the SDB FIS does not contain the LBA, so we can't
+ * use the ata_tf_from_fis() helper.
+ */
+ } else if (ata_is_ncq(qc->tf.protocol)) {
+ const u8 *fis = rx_fis + RX_FIS_SDB;
+
+ qc->result_tf.status = fis[2];
+ qc->result_tf.error = fis[3];
} else
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
@@ -2106,7 +2120,7 @@ void ahci_error_handler(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
- if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ if (!ata_port_is_frozen(ap)) {
/* restart engine */
hpriv->stop_engine(ap);
hpriv->start_engine(ap);
@@ -2297,7 +2311,7 @@ static void ahci_pmp_attach(struct ata_port *ap)
* Note that during initialization, the port is marked as
* frozen since the irq handler is not yet registered.
*/
- if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!ata_port_is_frozen(ap))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
@@ -2316,7 +2330,7 @@ static void ahci_pmp_detach(struct ata_port *ap)
pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
/* see comment above in ahci_pmp_attach() */
- if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!ata_port_is_frozen(ap))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index ddf17e2d266c..b9e336bacf17 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -109,7 +109,7 @@ struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con
int i;
for (i = 0; i < hpriv->n_clks; i++) {
- if (!strcmp(hpriv->clks[i].id, con_id))
+ if (hpriv->clks[i].id && !strcmp(hpriv->clks[i].id, con_id))
return hpriv->clks[i].clk;
}
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 61b4ccf88bf1..d36e71f475ab 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -992,7 +992,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
acpi_err:
/* ignore evaluation failure if we can continue safely */
- if (rc == -EINVAL && !nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN))
+ if (rc == -EINVAL && !nr_executed && !ata_port_is_frozen(ap))
return 0;
/* fail and let EH retry once more for unknown IO errors */
@@ -1007,7 +1007,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
/* We can safely continue if no _GTF command has been executed
* and port is not frozen.
*/
- if (!nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!nr_executed && !ata_port_is_frozen(ap))
return 0;
return rc;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d3ce5c383f3a..884ae73b11ea 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1489,7 +1489,7 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
- if (ap->pflags & ATA_PFLAG_FROZEN) {
+ if (ata_port_is_frozen(ap)) {
spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
@@ -2000,7 +2000,8 @@ retry:
if (err_mask) {
if (dma) {
dev->horkage |= ATA_HORKAGE_NO_DMA_LOG;
- goto retry;
+ if (!ata_port_is_frozen(dev->link->ap))
+ goto retry;
}
ata_dev_err(dev,
"Read log 0x%02x page 0x%02x failed, Emask 0x%x\n",
@@ -4721,7 +4722,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
return;
}
- WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
+ WARN_ON_ONCE(ata_port_is_frozen(ap));
/* read result TF if requested */
if (qc->flags & ATA_QCFLAG_RESULT_TF)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 08e11bc312c2..34303ce67c14 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1406,7 +1406,7 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc)
struct ata_taskfile tf;
unsigned int err_mask;
- if (qc->ap->pflags & ATA_PFLAG_FROZEN) {
+ if (ata_port_is_frozen(qc->ap)) {
ata_dev_warn(dev, "sense data available but port frozen\n");
return;
}
@@ -1428,8 +1428,10 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc)
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
/* Ignore err_mask; ATA_ERR might be set */
if (tf.status & ATA_SENSE) {
- ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) {
+ ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ }
} else {
ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
tf.status, err_mask);
@@ -1574,11 +1576,17 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
}
switch (qc->dev->class) {
+ case ATA_DEV_ATA:
case ATA_DEV_ZAC:
- if (stat & ATA_SENSE)
+ /*
+ * Fetch the sense data explicitly if:
+ * -It was a non-NCQ command that failed, or
+ * -It was a NCQ command that failed, but the sense data
+ * was not included in the NCQ command error log
+ * (i.e. NCQ autosense is not supported by the device).
+ */
+ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) && (stat & ATA_SENSE))
ata_eh_request_sense(qc);
- fallthrough;
- case ATA_DEV_ATA:
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
if (err & (ATA_UNC | ATA_AMNF))
@@ -1588,7 +1596,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
break;
case ATA_DEV_ATAPI:
- if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
+ if (!ata_port_is_frozen(qc->ap)) {
tmp = atapi_eh_request_sense(qc->dev,
qc->scsicmd->sense_buffer,
qc->result_tf.error >> 4);
@@ -1947,6 +1955,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
ata_qc_for_each_raw(ap, qc, tag) {
if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ qc->flags & ATA_QCFLAG_RETRY ||
ata_dev_phys_link(qc->dev) != link)
continue;
@@ -1995,7 +2004,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
ehc->i.flags |= ATA_EHI_QUIET;
/* enforce default EH actions */
- if (ap->pflags & ATA_PFLAG_FROZEN ||
+ if (ata_port_is_frozen(ap) ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
ehc->i.action |= ATA_EH_RESET;
else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) ||
@@ -2238,7 +2247,7 @@ static void ata_eh_link_report(struct ata_link *link)
return;
frozen = "";
- if (ap->pflags & ATA_PFLAG_FROZEN)
+ if (ata_port_is_frozen(ap))
frozen = " frozen";
if (ap->eh_tries < ATA_EH_MAX_TRIES)
@@ -2559,8 +2568,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (reset && !(ehc->i.action & ATA_EH_RESET)) {
ata_for_each_dev(dev, link, ALL)
classes[dev->devno] = ATA_DEV_NONE;
- if ((ap->pflags & ATA_PFLAG_FROZEN) &&
- ata_is_host_link(link))
+ if (ata_port_is_frozen(ap) && ata_is_host_link(link))
ata_eh_thaw_port(ap);
rc = 0;
goto out;
@@ -2718,7 +2726,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
spin_unlock_irqrestore(link->ap->lock, flags);
- if (ap->pflags & ATA_PFLAG_FROZEN)
+ if (ata_port_is_frozen(ap))
ata_eh_thaw_port(ap);
/*
@@ -3225,7 +3233,7 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
if (err_mask & AC_ERR_DEV) {
qc->err_mask |= AC_ERR_DEV;
qc->result_tf = tf;
- if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!ata_port_is_frozen(ap))
rc = 0;
}
}
@@ -3402,7 +3410,7 @@ static int ata_eh_skip_recovery(struct ata_link *link)
return 1;
/* thaw frozen port and recover failed devices */
- if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link))
+ if (ata_port_is_frozen(ap) || ata_link_nr_enabled(link))
return 0;
/* reset at least once if reset is requested */
@@ -3757,7 +3765,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (dev)
ata_eh_handle_dev_fail(dev, rc);
- if (ap->pflags & ATA_PFLAG_FROZEN) {
+ if (ata_port_is_frozen(ap)) {
/* PMP reset requires working host port.
* Can't retry if it's frozen.
*/
@@ -3931,7 +3939,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
if (rc == 0)
ap->pflags |= ATA_PFLAG_SUSPENDED;
- else if (ap->pflags & ATA_PFLAG_FROZEN)
+ else if (ata_port_is_frozen(ap))
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index b6806d41a8c5..18ef14e749a0 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -1392,7 +1392,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
- if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
+ if (ata_id_has_ncq_autosense(dev->id) && (tf->status & ATA_SENSE))
tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
@@ -1420,7 +1420,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
int tag, rc;
/* if frozen, we can't do much */
- if (ap->pflags & ATA_PFLAG_FROZEN)
+ if (ata_port_is_frozen(ap))
return;
/* is it NCQ device error? */
@@ -1456,17 +1456,51 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
- if (dev->class == ATA_DEV_ZAC &&
- ((qc->result_tf.status & ATA_SENSE) || qc->result_tf.auxiliary)) {
+
+ /*
+ * If the device supports NCQ autosense, ata_eh_read_log_10h() will have
+ * stored the sense data in qc->result_tf.auxiliary.
+ */
+ if (qc->result_tf.auxiliary) {
char sense_key, asc, ascq;
sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
asc = (qc->result_tf.auxiliary >> 8) & 0xff;
ascq = qc->result_tf.auxiliary & 0xff;
- ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
- ata_scsi_set_sense_information(dev, qc->scsicmd,
- &qc->result_tf);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ if (ata_scsi_sense_is_valid(sense_key, asc, ascq)) {
+ ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc,
+ ascq);
+ ata_scsi_set_sense_information(dev, qc->scsicmd,
+ &qc->result_tf);
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ }
+ }
+
+ ata_qc_for_each_raw(ap, qc, tag) {
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ ata_dev_phys_link(qc->dev) != link)
+ continue;
+
+ /* Skip the single QC which caused the NCQ error. */
+ if (qc->err_mask)
+ continue;
+
+ /*
+ * For SATA, the STATUS and ERROR fields are shared for all NCQ
+ * commands that were completed with the same SDB FIS.
+ * Therefore, we have to clear the ATA_ERR bit for all QCs
+ * except the one that caused the NCQ error.
+ */
+ qc->result_tf.status &= ~ATA_ERR;
+ qc->result_tf.error = 0;
+
+ /*
+ * If we get a NCQ error, that means that a single command was
+ * aborted. All other failed commands for our link should be
+ * retried and has no business of going though further scrutiny
+ * by ata_eh_link_autopsy().
+ */
+ qc->flags |= ATA_QCFLAG_RETRY;
}
ehc->i.err_mask &= ~AC_ERR_DEV;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e2ebb0b065e2..cbb3a7a50816 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -188,6 +188,22 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
ata_scsi_park_show, ata_scsi_park_store);
EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
+bool ata_scsi_sense_is_valid(u8 sk, u8 asc, u8 ascq)
+{
+ /*
+ * If sk == NO_SENSE, and asc + ascq == NO ADDITIONAL SENSE INFORMATION,
+ * then there is no sense data to add.
+ */
+ if (sk == 0 && asc == 0 && ascq == 0)
+ return false;
+
+ /* If sk > COMPLETED, sense data is bogus. */
+ if (sk > COMPLETED)
+ return false;
+
+ return true;
+}
+
void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd,
u8 sk, u8 asc, u8 ascq)
{
@@ -642,7 +658,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
struct ata_queued_cmd *qc;
int tag;
- if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
+ if (unlikely(ata_port_is_frozen(ap)))
goto fail;
if (ap->flags & ATA_FLAG_SAS_HOST) {
@@ -3264,6 +3280,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
case REPORT_LUNS:
case REQUEST_SENSE:
case SYNCHRONIZE_CACHE:
+ case SYNCHRONIZE_CACHE_16:
case REZERO_UNIT:
case SEEK_6:
case SEEK_10:
@@ -3922,6 +3939,7 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
return ata_scsi_write_same_xlat;
case SYNCHRONIZE_CACHE:
+ case SYNCHRONIZE_CACHE_16:
if (ata_try_flush_cache(dev))
return ata_scsi_flush_xlat;
break;
@@ -3962,9 +3980,19 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev)
{
+ struct ata_port *ap = dev->link->ap;
u8 scsi_op = scmd->cmnd[0];
ata_xlat_func_t xlat_func;
+ /*
+ * scsi_queue_rq() will defer commands if scsi_host_in_recovery().
+ * However, this check is done without holding the ap->lock (a libata
+ * specific lock), so we can have received an error irq since then,
+ * therefore we must check if EH is pending, while holding ap->lock.
+ */
+ if (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS))
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
if (unlikely(!scmd->cmd_len))
goto bad_cdb_len;
@@ -4145,6 +4173,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
* turning this into a no-op.
*/
case SYNCHRONIZE_CACHE:
+ case SYNCHRONIZE_CACHE_16:
fallthrough;
/* no-op's, complete with success */
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 7916e369e15e..153f49e00713 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -184,62 +184,6 @@ void ata_sff_dma_pause(struct ata_port *ap)
}
EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
-/**
- * ata_sff_busy_sleep - sleep until BSY clears, or timeout
- * @ap: port containing status register to be polled
- * @tmout_pat: impatience timeout in msecs
- * @tmout: overall timeout in msecs
- *
- * Sleep until ATA Status register bit BSY clears,
- * or a timeout occurs.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_sff_busy_sleep(struct ata_port *ap,
- unsigned long tmout_pat, unsigned long tmout)
-{
- unsigned long timer_start, timeout;
- u8 status;
-
- status = ata_sff_busy_wait(ap, ATA_BUSY, 300);
- timer_start = jiffies;
- timeout = ata_deadline(timer_start, tmout_pat);
- while (status != 0xff && (status & ATA_BUSY) &&
- time_before(jiffies, timeout)) {
- ata_msleep(ap, 50);
- status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
- }
-
- if (status != 0xff && (status & ATA_BUSY))
- ata_port_warn(ap,
- "port is slow to respond, please be patient (Status 0x%x)\n",
- status);
-
- timeout = ata_deadline(timer_start, tmout);
- while (status != 0xff && (status & ATA_BUSY) &&
- time_before(jiffies, timeout)) {
- ata_msleep(ap, 50);
- status = ap->ops->sff_check_status(ap);
- }
-
- if (status == 0xff)
- return -ENODEV;
-
- if (status & ATA_BUSY) {
- ata_port_err(ap,
- "port failed to respond (%lu secs, Status 0x%x)\n",
- DIV_ROUND_UP(tmout, 1000), status);
- return -EBUSY;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
-
static int ata_sff_check_ready(struct ata_link *link)
{
u8 status = link->ap->ops->sff_check_status(link->ap);
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index a7e9a75410a3..e4fb9d1b9b39 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -301,7 +301,9 @@ int ata_tport_add(struct device *parent,
pm_runtime_enable(dev);
pm_runtime_forbid(dev);
- transport_add_device(dev);
+ error = transport_add_device(dev);
+ if (error)
+ goto tport_transport_add_err;
transport_configure_device(dev);
error = ata_tlink_add(&ap->link);
@@ -312,12 +314,12 @@ int ata_tport_add(struct device *parent,
tport_link_err:
transport_remove_device(dev);
+ tport_transport_add_err:
device_del(dev);
tport_err:
transport_destroy_device(dev);
put_device(dev);
- ata_host_put(ap->host);
return error;
}
@@ -456,7 +458,9 @@ int ata_tlink_add(struct ata_link *link)
goto tlink_err;
}
- transport_add_device(dev);
+ error = transport_add_device(dev);
+ if (error)
+ goto tlink_transport_err;
transport_configure_device(dev);
ata_for_each_dev(ata_dev, link, ALL) {
@@ -471,6 +475,7 @@ int ata_tlink_add(struct ata_link *link)
ata_tdev_delete(ata_dev);
}
transport_remove_device(dev);
+ tlink_transport_err:
device_del(dev);
tlink_err:
transport_destroy_device(dev);
@@ -708,7 +713,13 @@ static int ata_tdev_add(struct ata_device *ata_dev)
return error;
}
- transport_add_device(dev);
+ error = transport_add_device(dev);
+ if (error) {
+ device_del(dev);
+ ata_tdev_free(ata_dev);
+ return error;
+ }
+
transport_configure_device(dev);
return 0;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 2c5c8273af01..2cd6124a01e8 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -114,6 +114,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern bool ata_scsi_sense_is_valid(u8 sk, u8 asc, u8 ascq);
extern void ata_scsi_set_sense(struct ata_device *dev,
struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
extern void ata_scsi_set_sense_information(struct ata_device *dev,
diff --git a/drivers/ata/pata_bk3710.c b/drivers/ata/pata_bk3710.c
deleted file mode 100644
index fad95cfecced..000000000000
--- a/drivers/ata/pata_bk3710.c
+++ /dev/null
@@ -1,380 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/*
- * Palmchip BK3710 PATA controller driver
- *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Based on palm_bk3710.c:
- *
- * Copyright (C) 2006 Texas Instruments.
- * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- */
-
-#include <linux/ata.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/libata.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/types.h>
-
-#define DRV_NAME "pata_bk3710"
-
-#define BK3710_TF_OFFSET 0x1F0
-#define BK3710_CTL_OFFSET 0x3F6
-
-#define BK3710_BMISP 0x02
-#define BK3710_IDETIMP 0x40
-#define BK3710_UDMACTL 0x48
-#define BK3710_MISCCTL 0x50
-#define BK3710_REGSTB 0x54
-#define BK3710_REGRCVR 0x58
-#define BK3710_DATSTB 0x5C
-#define BK3710_DATRCVR 0x60
-#define BK3710_DMASTB 0x64
-#define BK3710_DMARCVR 0x68
-#define BK3710_UDMASTB 0x6C
-#define BK3710_UDMATRP 0x70
-#define BK3710_UDMAENV 0x74
-#define BK3710_IORDYTMP 0x78
-
-static struct scsi_host_template pata_bk3710_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
-};
-
-static unsigned int ideclk_period; /* in nanoseconds */
-
-struct pata_bk3710_udmatiming {
- unsigned int rptime; /* tRP -- Ready to pause time (nsec) */
- unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */
- /* tENV is always a minimum of 20 nsec */
-};
-
-static const struct pata_bk3710_udmatiming pata_bk3710_udmatimings[6] = {
- { 160, 240 / 2 }, /* UDMA Mode 0 */
- { 125, 160 / 2 }, /* UDMA Mode 1 */
- { 100, 120 / 2 }, /* UDMA Mode 2 */
- { 100, 90 / 2 }, /* UDMA Mode 3 */
- { 100, 60 / 2 }, /* UDMA Mode 4 */
- { 85, 40 / 2 }, /* UDMA Mode 5 */
-};
-
-static void pata_bk3710_setudmamode(void __iomem *base, unsigned int dev,
- unsigned int mode)
-{
- u32 val32;
- u16 val16;
- u8 tenv, trp, t0;
-
- /* DMA Data Setup */
- t0 = DIV_ROUND_UP(pata_bk3710_udmatimings[mode].cycletime,
- ideclk_period) - 1;
- tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
- trp = DIV_ROUND_UP(pata_bk3710_udmatimings[mode].rptime,
- ideclk_period) - 1;
-
- /* udmastb Ultra DMA Access Strobe Width */
- val32 = ioread32(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
- val32 |= t0 << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_UDMASTB);
-
- /* udmatrp Ultra DMA Ready to Pause Time */
- val32 = ioread32(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
- val32 |= trp << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_UDMATRP);
-
- /* udmaenv Ultra DMA envelop Time */
- val32 = ioread32(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
- val32 |= tenv << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_UDMAENV);
-
- /* Enable UDMA for Device */
- val16 = ioread16(base + BK3710_UDMACTL) | (1 << dev);
- iowrite16(val16, base + BK3710_UDMACTL);
-}
-
-static void pata_bk3710_setmwdmamode(void __iomem *base, unsigned int dev,
- unsigned short min_cycle,
- unsigned int mode)
-{
- const struct ata_timing *t;
- int cycletime;
- u32 val32;
- u16 val16;
- u8 td, tkw, t0;
-
- t = ata_timing_find_mode(mode);
- cycletime = max_t(int, t->cycle, min_cycle);
-
- /* DMA Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ideclk_period);
- td = DIV_ROUND_UP(t->active, ideclk_period);
- tkw = t0 - td - 1;
- td--;
-
- val32 = ioread32(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
- val32 |= td << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_DMASTB);
-
- val32 = ioread32(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= tkw << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_DMARCVR);
-
- /* Disable UDMA for Device */
- val16 = ioread16(base + BK3710_UDMACTL) & ~(1 << dev);
- iowrite16(val16, base + BK3710_UDMACTL);
-}
-
-static void pata_bk3710_set_dmamode(struct ata_port *ap,
- struct ata_device *adev)
-{
- void __iomem *base = (void __iomem *)ap->ioaddr.bmdma_addr;
- int is_slave = adev->devno;
- const u8 xferspeed = adev->dma_mode;
-
- if (xferspeed >= XFER_UDMA_0)
- pata_bk3710_setudmamode(base, is_slave,
- xferspeed - XFER_UDMA_0);
- else
- pata_bk3710_setmwdmamode(base, is_slave,
- adev->id[ATA_ID_EIDE_DMA_MIN],
- xferspeed);
-}
-
-static void pata_bk3710_setpiomode(void __iomem *base, struct ata_device *pair,
- unsigned int dev, unsigned int cycletime,
- unsigned int mode)
-{
- const struct ata_timing *t;
- u32 val32;
- u8 t2, t2i, t0;
-
- t = ata_timing_find_mode(XFER_PIO_0 + mode);
-
- /* PIO Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ideclk_period);
- t2 = DIV_ROUND_UP(t->active, ideclk_period);
-
- t2i = t0 - t2 - 1;
- t2--;
-
- val32 = ioread32(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
- val32 |= t2 << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_DATSTB);
-
- val32 = ioread32(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= t2i << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_DATRCVR);
-
- /* FIXME: this is broken also in the old driver */
- if (pair) {
- u8 mode2 = pair->pio_mode - XFER_PIO_0;
-
- if (mode2 < mode)
- mode = mode2;
- }
-
- /* TASKFILE Setup */
- t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
- t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
-
- t2i = t0 - t2 - 1;
- t2--;
-
- val32 = ioread32(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
- val32 |= t2 << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_REGSTB);
-
- val32 = ioread32(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= t2i << (dev ? 8 : 0);
- iowrite32(val32, base + BK3710_REGRCVR);
-}
-
-static void pata_bk3710_set_piomode(struct ata_port *ap,
- struct ata_device *adev)
-{
- void __iomem *base = (void __iomem *)ap->ioaddr.bmdma_addr;
- struct ata_device *pair = ata_dev_pair(adev);
- const struct ata_timing *t = ata_timing_find_mode(adev->pio_mode);
- const u16 *id = adev->id;
- unsigned int cycle_time = 0;
- int is_slave = adev->devno;
- const u8 pio = adev->pio_mode - XFER_PIO_0;
-
- if (id[ATA_ID_FIELD_VALID] & 2) {
- if (ata_id_has_iordy(id))
- cycle_time = id[ATA_ID_EIDE_PIO_IORDY];
- else
- cycle_time = id[ATA_ID_EIDE_PIO];
-
- /* conservative "downgrade" for all pre-ATA2 drives */
- if (pio < 3 && cycle_time < t->cycle)
- cycle_time = 0; /* use standard timing */
- }
-
- if (!cycle_time)
- cycle_time = t->cycle;
-
- pata_bk3710_setpiomode(base, pair, is_slave, cycle_time, pio);
-}
-
-static void pata_bk3710_chipinit(void __iomem *base)
-{
- /*
- * REVISIT: the ATA reset signal needs to be managed through a
- * GPIO, which means it should come from platform_data. Until
- * we get and use such information, we have to trust that things
- * have been reset before we get here.
- */
-
- /*
- * Program the IDETIMP Register Value based on the following assumptions
- *
- * (ATA_IDETIMP_IDEEN , ENABLE ) |
- * (ATA_IDETIMP_PREPOST1 , DISABLE) |
- * (ATA_IDETIMP_PREPOST0 , DISABLE) |
- *
- * DM6446 silicon rev 2.1 and earlier have no observed net benefit
- * from enabling prefetch/postwrite.
- */
- iowrite16(BIT(15), base + BK3710_IDETIMP);
-
- /*
- * UDMACTL Ultra-ATA DMA Control
- * (ATA_UDMACTL_UDMAP1 , 0 ) |
- * (ATA_UDMACTL_UDMAP0 , 0 )
- *
- */
- iowrite16(0, base + BK3710_UDMACTL);
-
- /*
- * MISCCTL Miscellaneous Conrol Register
- * (ATA_MISCCTL_HWNHLD1P , 1 cycle)
- * (ATA_MISCCTL_HWNHLD0P , 1 cycle)
- * (ATA_MISCCTL_TIMORIDE , 1)
- */
- iowrite32(0x001, base + BK3710_MISCCTL);
-
- /*
- * IORDYTMP IORDY Timer for Primary Register
- * (ATA_IORDYTMP_IORDYTMP , DISABLE)
- */
- iowrite32(0, base + BK3710_IORDYTMP);
-
- /*
- * Configure BMISP Register
- * (ATA_BMISP_DMAEN1 , DISABLE ) |
- * (ATA_BMISP_DMAEN0 , DISABLE ) |
- * (ATA_BMISP_IORDYINT , CLEAR) |
- * (ATA_BMISP_INTRSTAT , CLEAR) |
- * (ATA_BMISP_DMAERROR , CLEAR)
- */
- iowrite16(0xE, base + BK3710_BMISP);
-
- pata_bk3710_setpiomode(base, NULL, 0, 600, 0);
- pata_bk3710_setpiomode(base, NULL, 1, 600, 0);
-}
-
-static struct ata_port_operations pata_bk3710_ports_ops = {
- .inherits = &ata_bmdma_port_ops,
- .cable_detect = ata_cable_80wire,
-
- .set_piomode = pata_bk3710_set_piomode,
- .set_dmamode = pata_bk3710_set_dmamode,
-};
-
-static int __init pata_bk3710_probe(struct platform_device *pdev)
-{
- struct clk *clk;
- struct resource *mem;
- struct ata_host *host;
- struct ata_port *ap;
- void __iomem *base;
- unsigned long rate;
- int irq;
-
- clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk))
- return -ENODEV;
-
- clk_enable(clk);
- rate = clk_get_rate(clk);
- if (!rate)
- return -EINVAL;
-
- /* NOTE: round *down* to meet minimum timings; we count in clocks */
- ideclk_period = 1000000000UL / rate;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- pr_err(DRV_NAME ": failed to get IRQ resource\n");
- return irq;
- }
-
- base = devm_ioremap_resource(&pdev->dev, mem);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- /* configure the Palmchip controller */
- pata_bk3710_chipinit(base);
-
- /* allocate host */
- host = ata_host_alloc(&pdev->dev, 1);
- if (!host)
- return -ENOMEM;
- ap = host->ports[0];
-
- ap->ops = &pata_bk3710_ports_ops;
- ap->pio_mask = ATA_PIO4;
- ap->mwdma_mask = ATA_MWDMA2;
- ap->udma_mask = rate < 100000000 ? ATA_UDMA4 : ATA_UDMA5;
- ap->flags |= ATA_FLAG_SLAVE_POSS;
-
- ap->ioaddr.data_addr = base + BK3710_TF_OFFSET;
- ap->ioaddr.error_addr = base + BK3710_TF_OFFSET + 1;
- ap->ioaddr.feature_addr = base + BK3710_TF_OFFSET + 1;
- ap->ioaddr.nsect_addr = base + BK3710_TF_OFFSET + 2;
- ap->ioaddr.lbal_addr = base + BK3710_TF_OFFSET + 3;
- ap->ioaddr.lbam_addr = base + BK3710_TF_OFFSET + 4;
- ap->ioaddr.lbah_addr = base + BK3710_TF_OFFSET + 5;
- ap->ioaddr.device_addr = base + BK3710_TF_OFFSET + 6;
- ap->ioaddr.status_addr = base + BK3710_TF_OFFSET + 7;
- ap->ioaddr.command_addr = base + BK3710_TF_OFFSET + 7;
-
- ap->ioaddr.altstatus_addr = base + BK3710_CTL_OFFSET;
- ap->ioaddr.ctl_addr = base + BK3710_CTL_OFFSET;
-
- ap->ioaddr.bmdma_addr = base;
-
- ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
- (unsigned long)base + BK3710_TF_OFFSET,
- (unsigned long)base + BK3710_CTL_OFFSET);
-
- /* activate */
- return ata_host_activate(host, irq, ata_sff_interrupt, 0,
- &pata_bk3710_sht);
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:palm_bk3710");
-
-static struct platform_driver pata_bk3710_driver = {
- .driver = {
- .name = "palm_bk3710",
- },
-};
-
-static int __init pata_bk3710_init(void)
-{
- return platform_driver_probe(&pata_bk3710_driver, pata_bk3710_probe);
-}
-
-module_init(pata_bk3710_init);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 6c75a22db12b..47845d920075 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -931,8 +931,7 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
goto err_rel_gpio;
}
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ide_base = devm_ioremap_resource(&pdev->dev, mem_res);
+ ide_base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
if (IS_ERR(ide_base)) {
err = PTR_ERR(ide_base);
goto err_rel_gpio;
diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c
index 0117df0fe3c5..88924b5daa1a 100644
--- a/drivers/ata/pata_ftide010.c
+++ b/drivers/ata/pata_ftide010.c
@@ -560,7 +560,7 @@ static const struct of_device_id pata_ftide010_of_match[] = {
static struct platform_driver pata_ftide010_driver = {
.driver = {
.name = DRV_NAME,
- .of_match_table = of_match_ptr(pata_ftide010_of_match),
+ .of_match_table = pata_ftide010_of_match,
},
.probe = pata_ftide010_probe,
.remove = pata_ftide010_remove,
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 6559b606736d..3ebd6522a1fd 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -731,7 +731,7 @@ static int mpc52xx_ata_probe(struct platform_device *op)
udma_mask = ATA_UDMA2 & ((1 << (*prop + 1)) - 1);
ata_irq = irq_of_parse_and_map(op->dev.of_node, 0);
- if (ata_irq == NO_IRQ) {
+ if (!ata_irq) {
dev_err(&op->dev, "error mapping irq\n");
return -EINVAL;
}
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index e3263e961045..21d77633a98f 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -42,10 +42,6 @@
#define sata_dwc_writel(a, v) writel_relaxed(v, a)
#define sata_dwc_readl(a) readl_relaxed(a)
-#ifndef NO_IRQ
-#define NO_IRQ 0
-#endif
-
#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length */
enum {
@@ -242,7 +238,7 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev,
/* Get SATA DMA interrupt number */
hsdev->dma->irq = irq_of_parse_and_map(np, 1);
- if (hsdev->dma->irq == NO_IRQ) {
+ if (!hsdev->dma->irq) {
dev_err(dev, "no SATA DMA irq\n");
return -ENODEV;
}
@@ -472,7 +468,7 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
struct ata_queued_cmd *qc;
unsigned long flags;
u8 status, tag;
- int handled, num_processed, port = 0;
+ int handled, port = 0;
uint intpr, sactive, sactive2, tag_mask;
struct sata_dwc_device_port *hsdevp;
hsdev->sactive_issued = 0;
@@ -618,9 +614,7 @@ DRVSTILLBUSY:
dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
tag = 0;
- num_processed = 0;
while (tag_mask) {
- num_processed++;
while (!(tag_mask & 0x00000001)) {
tag++;
tag_mask <<= 1;
@@ -1180,7 +1174,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
/* Get SATA interrupt number */
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(dev, "no SATA DMA irq\n");
return -ENODEV;
}
diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c
index b729e9919bb0..c42cc9bbbc4e 100644
--- a/drivers/ata/sata_gemini.c
+++ b/drivers/ata/sata_gemini.c
@@ -421,7 +421,7 @@ static const struct of_device_id gemini_sata_of_match[] = {
static struct platform_driver gemini_sata_driver = {
.driver = {
.name = DRV_NAME,
- .of_match_table = of_match_ptr(gemini_sata_of_match),
+ .of_match_table = gemini_sata_of_match,
},
.probe = gemini_sata_probe,
.remove = gemini_sata_remove,
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 7f14d0d31057..9b2d289e89e1 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -2185,7 +2185,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
if (!fis)
return;
- if (ap->pflags & ATA_PFLAG_FROZEN)
+ if (ata_port_is_frozen(ap))
return;
if (fis & NV_SWNCQ_IRQ_HOTPLUG) {
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index b8465fef2ed2..9cd7d8b71361 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -817,7 +817,7 @@ static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
static void pdc_error_handler(struct ata_port *ap)
{
- if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!ata_port_is_frozen(ap))
pdc_reset_port(ap);
ata_sff_error_handler(ap);
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 6ceec59cb291..ab70cbc78f96 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -855,7 +855,7 @@ static int pdc_softreset(struct ata_link *link, unsigned int *class,
static void pdc_error_handler(struct ata_port *ap)
{
- if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ if (!ata_port_is_frozen(ap))
pdc_reset_port(ap);
ata_sff_error_handler(ap);
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 83217d243c25..3079bfe53d04 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_REGMAP) += regmap/
obj-$(CONFIG_SOC_BUS) += soc.o
obj-$(CONFIG_PINCTRL) += pinctrl.o
obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
-obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
+obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o
obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o
obj-$(CONFIG_ACPI) += physical_location.o
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 12b044151298..5883e7634a2b 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -213,7 +213,7 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
if (err)
return err;
- err = msi_domain_alloc_irqs(dev->msi.domain, dev, nvec);
+ err = msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
if (err)
platform_msi_free_priv_data(dev);
@@ -227,7 +227,7 @@ EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);
*/
void platform_msi_domain_free_irqs(struct device *dev)
{
- msi_domain_free_irqs(dev->msi.domain, dev);
+ msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
platform_msi_free_priv_data(dev);
}
EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);
@@ -325,7 +325,7 @@ void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int vir
msi_lock_descs(data->dev);
irq_domain_free_irqs_common(domain, virq, nr_irqs);
- msi_free_msi_descs_range(data->dev, MSI_DESC_ALL, virq, virq + nr_irqs - 1);
+ msi_free_msi_descs_range(data->dev, virq, virq + nr_irqs - 1);
msi_unlock_descs(data->dev);
}
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 6471b559230e..967bcf9d415e 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -494,6 +494,31 @@ void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup);
+/**
+ * dev_pm_genpd_get_next_hrtimer - Return the next_hrtimer for the genpd
+ * @dev: A device that is attached to the genpd.
+ *
+ * This routine should typically be called for a device, at the point of when a
+ * GENPD_NOTIFY_PRE_OFF notification has been sent for it.
+ *
+ * Returns the aggregated value of the genpd's next hrtimer or KTIME_MAX if no
+ * valid value have been set.
+ */
+ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
+{
+ struct generic_pm_domain *genpd;
+
+ genpd = dev_to_genpd_safe(dev);
+ if (!genpd)
+ return KTIME_MAX;
+
+ if (genpd->gd)
+ return genpd->gd->next_hrtimer;
+
+ return KTIME_MAX;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
+
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@@ -939,8 +964,8 @@ static int genpd_runtime_suspend(struct device *dev)
return 0;
genpd_lock(genpd);
- gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
+ gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_unlock(genpd);
return 0;
@@ -978,9 +1003,8 @@ static int genpd_runtime_resume(struct device *dev)
goto out;
genpd_lock(genpd);
+ genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
ret = genpd_power_on(genpd, 0);
- if (!ret)
- genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
genpd_unlock(genpd);
if (ret)
@@ -1018,8 +1042,8 @@ err_stop:
err_poweroff:
if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
genpd_lock(genpd);
- gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
+ gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_unlock(genpd);
}
@@ -1189,12 +1213,15 @@ static int genpd_prepare(struct device *dev)
* genpd_finish_suspend - Completion of suspend or hibernation of device in an
* I/O pm domain.
* @dev: Device to suspend.
- * @poweroff: Specifies if this is a poweroff_noirq or suspend_noirq callback.
+ * @suspend_noirq: Generic suspend_noirq callback.
+ * @resume_noirq: Generic resume_noirq callback.
*
* Stop the device and remove power from the domain if all devices in it have
* been stopped.
*/
-static int genpd_finish_suspend(struct device *dev, bool poweroff)
+static int genpd_finish_suspend(struct device *dev,
+ int (*suspend_noirq)(struct device *dev),
+ int (*resume_noirq)(struct device *dev))
{
struct generic_pm_domain *genpd;
int ret = 0;
@@ -1203,10 +1230,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
if (IS_ERR(genpd))
return -EINVAL;
- if (poweroff)
- ret = pm_generic_poweroff_noirq(dev);
- else
- ret = pm_generic_suspend_noirq(dev);
+ ret = suspend_noirq(dev);
if (ret)
return ret;
@@ -1217,10 +1241,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
!pm_runtime_status_suspended(dev)) {
ret = genpd_stop_dev(genpd, dev);
if (ret) {
- if (poweroff)
- pm_generic_restore_noirq(dev);
- else
- pm_generic_resume_noirq(dev);
+ resume_noirq(dev);
return ret;
}
}
@@ -1244,16 +1265,20 @@ static int genpd_suspend_noirq(struct device *dev)
{
dev_dbg(dev, "%s()\n", __func__);
- return genpd_finish_suspend(dev, false);
+ return genpd_finish_suspend(dev,
+ pm_generic_suspend_noirq,
+ pm_generic_resume_noirq);
}
/**
- * genpd_resume_noirq - Start of resume of device in an I/O PM domain.
+ * genpd_finish_resume - Completion of resume of device in an I/O PM domain.
* @dev: Device to resume.
+ * @resume_noirq: Generic resume_noirq callback.
*
* Restore power to the device's PM domain, if necessary, and start the device.
*/
-static int genpd_resume_noirq(struct device *dev)
+static int genpd_finish_resume(struct device *dev,
+ int (*resume_noirq)(struct device *dev))
{
struct generic_pm_domain *genpd;
int ret;
@@ -1265,7 +1290,7 @@ static int genpd_resume_noirq(struct device *dev)
return -EINVAL;
if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd))
- return pm_generic_resume_noirq(dev);
+ return resume_noirq(dev);
genpd_lock(genpd);
genpd_sync_power_on(genpd, true, 0);
@@ -1283,6 +1308,19 @@ static int genpd_resume_noirq(struct device *dev)
}
/**
+ * genpd_resume_noirq - Start of resume of device in an I/O PM domain.
+ * @dev: Device to resume.
+ *
+ * Restore power to the device's PM domain, if necessary, and start the device.
+ */
+static int genpd_resume_noirq(struct device *dev)
+{
+ dev_dbg(dev, "%s()\n", __func__);
+
+ return genpd_finish_resume(dev, pm_generic_resume_noirq);
+}
+
+/**
* genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
* @dev: Device to freeze.
*
@@ -1293,24 +1331,11 @@ static int genpd_resume_noirq(struct device *dev)
*/
static int genpd_freeze_noirq(struct device *dev)
{
- const struct generic_pm_domain *genpd;
- int ret = 0;
-
dev_dbg(dev, "%s()\n", __func__);
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- ret = pm_generic_freeze_noirq(dev);
- if (ret)
- return ret;
-
- if (genpd->dev_ops.stop && genpd->dev_ops.start &&
- !pm_runtime_status_suspended(dev))
- ret = genpd_stop_dev(genpd, dev);
-
- return ret;
+ return genpd_finish_suspend(dev,
+ pm_generic_freeze_noirq,
+ pm_generic_thaw_noirq);
}
/**
@@ -1322,23 +1347,9 @@ static int genpd_freeze_noirq(struct device *dev)
*/
static int genpd_thaw_noirq(struct device *dev)
{
- const struct generic_pm_domain *genpd;
- int ret = 0;
-
dev_dbg(dev, "%s()\n", __func__);
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- if (genpd->dev_ops.stop && genpd->dev_ops.start &&
- !pm_runtime_status_suspended(dev)) {
- ret = genpd_start_dev(genpd, dev);
- if (ret)
- return ret;
- }
-
- return pm_generic_thaw_noirq(dev);
+ return genpd_finish_resume(dev, pm_generic_thaw_noirq);
}
/**
@@ -1353,7 +1364,9 @@ static int genpd_poweroff_noirq(struct device *dev)
{
dev_dbg(dev, "%s()\n", __func__);
- return genpd_finish_suspend(dev, true);
+ return genpd_finish_suspend(dev,
+ pm_generic_poweroff_noirq,
+ pm_generic_restore_noirq);
}
/**
@@ -1365,40 +1378,9 @@ static int genpd_poweroff_noirq(struct device *dev)
*/
static int genpd_restore_noirq(struct device *dev)
{
- struct generic_pm_domain *genpd;
- int ret = 0;
-
dev_dbg(dev, "%s()\n", __func__);
- genpd = dev_to_genpd(dev);
- if (IS_ERR(genpd))
- return -EINVAL;
-
- /*
- * At this point suspended_count == 0 means we are being run for the
- * first time for the given domain in the present cycle.
- */
- genpd_lock(genpd);
- if (genpd->suspended_count++ == 0) {
- /*
- * The boot kernel might put the domain into arbitrary state,
- * so make it appear as powered off to genpd_sync_power_on(),
- * so that it tries to power it on in case it was really off.
- */
- genpd->status = GENPD_STATE_OFF;
- }
-
- genpd_sync_power_on(genpd, true, 0);
- genpd_unlock(genpd);
-
- if (genpd->dev_ops.stop && genpd->dev_ops.start &&
- !pm_runtime_status_suspended(dev)) {
- ret = genpd_start_dev(genpd, dev);
- if (ret)
- return ret;
- }
-
- return pm_generic_restore_noirq(dev);
+ return genpd_finish_resume(dev, pm_generic_restore_noirq);
}
/**
@@ -1994,6 +1976,7 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
gd->max_off_time_ns = -1;
gd->max_off_time_changed = true;
gd->next_wakeup = KTIME_MAX;
+ gd->next_hrtimer = KTIME_MAX;
}
/* Use only one "off" state if there were no states declared */
@@ -2749,17 +2732,6 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
dev->pm_domain->detach = genpd_dev_pm_detach;
dev->pm_domain->sync = genpd_dev_pm_sync;
- if (power_on) {
- genpd_lock(pd);
- ret = genpd_power_on(pd, 0);
- genpd_unlock(pd);
- }
-
- if (ret) {
- genpd_remove_device(pd, dev);
- return -EPROBE_DEFER;
- }
-
/* Set the default performance state */
pstate = of_get_required_opp_performance_state(dev->of_node, index);
if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) {
@@ -2771,6 +2743,24 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
goto err;
dev_gpd_data(dev)->default_pstate = pstate;
}
+
+ if (power_on) {
+ genpd_lock(pd);
+ ret = genpd_power_on(pd, 0);
+ genpd_unlock(pd);
+ }
+
+ if (ret) {
+ /* Drop the default performance state */
+ if (dev_gpd_data(dev)->default_pstate) {
+ dev_pm_genpd_set_performance_state(dev, 0);
+ dev_gpd_data(dev)->default_pstate = 0;
+ }
+
+ genpd_remove_device(pd, dev);
+ return -EPROBE_DEFER;
+ }
+
return 1;
err:
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 282a3a135827..cc2c3a5a6d35 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -375,6 +375,9 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if (idle_duration_ns <= 0)
return false;
+ /* Store the next domain_wakeup to allow consumers to use it. */
+ genpd->gd->next_hrtimer = domain_wakeup;
+
/*
* Find the deepest idle state that has its residency value satisfied
* and by also taking into account the power off latency for the state.
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b52049098d4e..50e726b6c2cf 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -243,8 +243,7 @@ void pm_runtime_set_memalloc_noio(struct device *dev, bool enable)
* flag was set by any one of the descendants.
*/
if (!dev || (!enable &&
- device_for_each_child(dev, NULL,
- dev_memalloc_noio)))
+ device_for_each_child(dev, NULL, dev_memalloc_noio)))
break;
}
mutex_unlock(&dev_hotplug_mutex);
@@ -265,15 +264,13 @@ static int rpm_check_suspend_allowed(struct device *dev)
retval = -EACCES;
else if (atomic_read(&dev->power.usage_count))
retval = -EAGAIN;
- else if (!dev->power.ignore_children &&
- atomic_read(&dev->power.child_count))
+ else if (!dev->power.ignore_children && atomic_read(&dev->power.child_count))
retval = -EBUSY;
/* Pending resume requests take precedence over suspends. */
- else if ((dev->power.deferred_resume
- && dev->power.runtime_status == RPM_SUSPENDING)
- || (dev->power.request_pending
- && dev->power.request == RPM_REQ_RESUME))
+ else if ((dev->power.deferred_resume &&
+ dev->power.runtime_status == RPM_SUSPENDING) ||
+ (dev->power.request_pending && dev->power.request == RPM_REQ_RESUME))
retval = -EAGAIN;
else if (__dev_pm_qos_resume_latency(dev) == 0)
retval = -EPERM;
@@ -404,9 +401,9 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
*
* Do that if resume fails too.
*/
- if (use_links
- && ((dev->power.runtime_status == RPM_SUSPENDING && !retval)
- || (dev->power.runtime_status == RPM_RESUMING && retval))) {
+ if (use_links &&
+ ((dev->power.runtime_status == RPM_SUSPENDING && !retval) ||
+ (dev->power.runtime_status == RPM_RESUMING && retval))) {
idx = device_links_read_lock();
__rpm_put_suppliers(dev, false);
@@ -422,6 +419,38 @@ fail:
}
/**
+ * rpm_callback - Run a given runtime PM callback for a given device.
+ * @cb: Runtime PM callback to run.
+ * @dev: Device to run the callback for.
+ */
+static int rpm_callback(int (*cb)(struct device *), struct device *dev)
+{
+ int retval;
+
+ if (dev->power.memalloc_noio) {
+ unsigned int noio_flag;
+
+ /*
+ * Deadlock might be caused if memory allocation with
+ * GFP_KERNEL happens inside runtime_suspend and
+ * runtime_resume callbacks of one block device's
+ * ancestor or the block device itself. Network
+ * device might be thought as part of iSCSI block
+ * device, so network device and its ancestor should
+ * be marked as memalloc_noio too.
+ */
+ noio_flag = memalloc_noio_save();
+ retval = __rpm_callback(cb, dev);
+ memalloc_noio_restore(noio_flag);
+ } else {
+ retval = __rpm_callback(cb, dev);
+ }
+
+ dev->power.runtime_error = retval;
+ return retval != -EACCES ? retval : -EIO;
+}
+
+/**
* rpm_idle - Notify device bus type if the device can be suspended.
* @dev: Device to notify the bus type about.
* @rpmflags: Flag bits.
@@ -459,6 +488,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
/* Act as though RPM_NOWAIT is always set. */
else if (dev->power.idle_notification)
retval = -EINPROGRESS;
+
if (retval)
goto out;
@@ -484,7 +514,17 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- retval = __rpm_callback(callback, dev);
+ if (dev->power.irq_safe)
+ spin_unlock(&dev->power.lock);
+ else
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = callback(dev);
+
+ if (dev->power.irq_safe)
+ spin_lock(&dev->power.lock);
+ else
+ spin_lock_irq(&dev->power.lock);
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
@@ -495,38 +535,6 @@ static int rpm_idle(struct device *dev, int rpmflags)
}
/**
- * rpm_callback - Run a given runtime PM callback for a given device.
- * @cb: Runtime PM callback to run.
- * @dev: Device to run the callback for.
- */
-static int rpm_callback(int (*cb)(struct device *), struct device *dev)
-{
- int retval;
-
- if (dev->power.memalloc_noio) {
- unsigned int noio_flag;
-
- /*
- * Deadlock might be caused if memory allocation with
- * GFP_KERNEL happens inside runtime_suspend and
- * runtime_resume callbacks of one block device's
- * ancestor or the block device itself. Network
- * device might be thought as part of iSCSI block
- * device, so network device and its ancestor should
- * be marked as memalloc_noio too.
- */
- noio_flag = memalloc_noio_save();
- retval = __rpm_callback(cb, dev);
- memalloc_noio_restore(noio_flag);
- } else {
- retval = __rpm_callback(cb, dev);
- }
-
- dev->power.runtime_error = retval;
- return retval != -EACCES ? retval : -EIO;
-}
-
-/**
* rpm_suspend - Carry out runtime suspend of given device.
* @dev: Device to suspend.
* @rpmflags: Flag bits.
@@ -564,12 +572,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)
/* Synchronous suspends are not allowed in the RPM_RESUMING state. */
if (dev->power.runtime_status == RPM_RESUMING && !(rpmflags & RPM_ASYNC))
retval = -EAGAIN;
+
if (retval)
goto out;
/* If the autosuspend_delay time hasn't expired yet, reschedule. */
- if ((rpmflags & RPM_AUTO)
- && dev->power.runtime_status != RPM_SUSPENDING) {
+ if ((rpmflags & RPM_AUTO) && dev->power.runtime_status != RPM_SUSPENDING) {
u64 expires = pm_runtime_autosuspend_expiration(dev);
if (expires != 0) {
@@ -584,7 +592,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
* rest.
*/
if (!(dev->power.timer_expires &&
- dev->power.timer_expires <= expires)) {
+ dev->power.timer_expires <= expires)) {
/*
* We add a slack of 25% to gather wakeups
* without sacrificing the granularity.
@@ -594,9 +602,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
dev->power.timer_expires = expires;
hrtimer_start_range_ns(&dev->power.suspend_timer,
- ns_to_ktime(expires),
- slack,
- HRTIMER_MODE_ABS);
+ ns_to_ktime(expires),
+ slack,
+ HRTIMER_MODE_ABS);
}
dev->power.timer_autosuspends = 1;
goto out;
@@ -787,8 +795,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
goto out;
}
- if (dev->power.runtime_status == RPM_RESUMING
- || dev->power.runtime_status == RPM_SUSPENDING) {
+ if (dev->power.runtime_status == RPM_RESUMING ||
+ dev->power.runtime_status == RPM_SUSPENDING) {
DEFINE_WAIT(wait);
if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
@@ -815,8 +823,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
- if (dev->power.runtime_status != RPM_RESUMING
- && dev->power.runtime_status != RPM_SUSPENDING)
+ if (dev->power.runtime_status != RPM_RESUMING &&
+ dev->power.runtime_status != RPM_SUSPENDING)
break;
spin_unlock_irq(&dev->power.lock);
@@ -836,9 +844,9 @@ static int rpm_resume(struct device *dev, int rpmflags)
*/
if (dev->power.no_callbacks && !parent && dev->parent) {
spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
- if (dev->parent->power.disable_depth > 0
- || dev->parent->power.ignore_children
- || dev->parent->power.runtime_status == RPM_ACTIVE) {
+ if (dev->parent->power.disable_depth > 0 ||
+ dev->parent->power.ignore_children ||
+ dev->parent->power.runtime_status == RPM_ACTIVE) {
atomic_inc(&dev->parent->power.child_count);
spin_unlock(&dev->parent->power.lock);
retval = 1;
@@ -867,6 +875,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
parent = dev->parent;
if (dev->power.irq_safe)
goto skip_parent;
+
spin_unlock(&dev->power.lock);
pm_runtime_get_noresume(parent);
@@ -876,8 +885,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
* Resume the parent if it has runtime PM enabled and not been
* set to ignore its children.
*/
- if (!parent->power.disable_depth
- && !parent->power.ignore_children) {
+ if (!parent->power.disable_depth &&
+ !parent->power.ignore_children) {
rpm_resume(parent, 0);
if (parent->power.runtime_status != RPM_ACTIVE)
retval = -EBUSY;
@@ -887,6 +896,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
spin_lock(&dev->power.lock);
if (retval)
goto out;
+
goto repeat;
}
skip_parent:
@@ -1291,9 +1301,9 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
* not active, has runtime PM enabled and the
* 'power.ignore_children' flag unset.
*/
- if (!parent->power.disable_depth
- && !parent->power.ignore_children
- && parent->power.runtime_status != RPM_ACTIVE) {
+ if (!parent->power.disable_depth &&
+ !parent->power.ignore_children &&
+ parent->power.runtime_status != RPM_ACTIVE) {
dev_err(dev, "runtime PM trying to activate child device %s but parent (%s) is not active\n",
dev_name(dev),
dev_name(parent));
@@ -1358,9 +1368,9 @@ static void __pm_runtime_barrier(struct device *dev)
dev->power.request_pending = false;
}
- if (dev->power.runtime_status == RPM_SUSPENDING
- || dev->power.runtime_status == RPM_RESUMING
- || dev->power.idle_notification) {
+ if (dev->power.runtime_status == RPM_SUSPENDING ||
+ dev->power.runtime_status == RPM_RESUMING ||
+ dev->power.idle_notification) {
DEFINE_WAIT(wait);
/* Suspend, wake-up or idle notification in progress. */
@@ -1445,8 +1455,8 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
* means there probably is some I/O to process and disabling runtime PM
* shouldn't prevent the device from processing the I/O.
*/
- if (check_resume && dev->power.request_pending
- && dev->power.request == RPM_REQ_RESUME) {
+ if (check_resume && dev->power.request_pending &&
+ dev->power.request == RPM_REQ_RESUME) {
/*
* Prevent suspends and idle notifications from being carried
* out after we have woken up the device.
@@ -1606,6 +1616,7 @@ void pm_runtime_irq_safe(struct device *dev)
{
if (dev->parent)
pm_runtime_get_sync(dev->parent);
+
spin_lock_irq(&dev->power.lock);
dev->power.irq_safe = 1;
spin_unlock_irq(&dev->power.lock);
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 159bac6c5046..cd4bb642b9de 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,7 +4,7 @@
# subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO)
+ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
select IRQ_DOMAIN if REGMAP_IRQ
select MDIO_BUS if REGMAP_MDIO
bool
@@ -65,3 +65,7 @@ config REGMAP_I3C
config REGMAP_SPI_AVMM
tristate
depends on SPI
+
+config REGMAP_FSI
+ tristate
+ depends on FSI
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 11facb32a027..6990de7ca9a9 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
+obj-$(CONFIG_REGMAP_FSI) += regmap-fsi.o
diff --git a/drivers/base/regmap/regmap-fsi.c b/drivers/base/regmap/regmap-fsi.c
new file mode 100644
index 000000000000..3d2f3cb31d5e
--- /dev/null
+++ b/drivers/base/regmap/regmap-fsi.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Register map access API - FSI support
+//
+// Copyright 2022 IBM Corp
+//
+// Author: Eddie James <eajames@linux.ibm.com>
+
+#include <linux/fsi.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "internal.h"
+
+static int regmap_fsi32_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ u32 v;
+ int ret;
+
+ ret = fsi_slave_read(context, reg, &v, sizeof(v));
+ if (ret)
+ return ret;
+
+ *val = v;
+ return 0;
+}
+
+static int regmap_fsi32_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ u32 v = val;
+
+ return fsi_slave_write(context, reg, &v, sizeof(v));
+}
+
+static const struct regmap_bus regmap_fsi32 = {
+ .reg_write = regmap_fsi32_reg_write,
+ .reg_read = regmap_fsi32_reg_read,
+};
+
+static int regmap_fsi32le_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ __be32 v;
+ int ret;
+
+ ret = fsi_slave_read(context, reg, &v, sizeof(v));
+ if (ret)
+ return ret;
+
+ *val = be32_to_cpu(v);
+ return 0;
+}
+
+static int regmap_fsi32le_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ __be32 v = cpu_to_be32(val);
+
+ return fsi_slave_write(context, reg, &v, sizeof(v));
+}
+
+static const struct regmap_bus regmap_fsi32le = {
+ .reg_write = regmap_fsi32le_reg_write,
+ .reg_read = regmap_fsi32le_reg_read,
+};
+
+static int regmap_fsi16_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ u16 v;
+ int ret;
+
+ ret = fsi_slave_read(context, reg, &v, sizeof(v));
+ if (ret)
+ return ret;
+
+ *val = v;
+ return 0;
+}
+
+static int regmap_fsi16_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ u16 v;
+
+ if (val > 0xffff)
+ return -EINVAL;
+
+ v = val;
+ return fsi_slave_write(context, reg, &v, sizeof(v));
+}
+
+static const struct regmap_bus regmap_fsi16 = {
+ .reg_write = regmap_fsi16_reg_write,
+ .reg_read = regmap_fsi16_reg_read,
+};
+
+static int regmap_fsi16le_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ __be16 v;
+ int ret;
+
+ ret = fsi_slave_read(context, reg, &v, sizeof(v));
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(v);
+ return 0;
+}
+
+static int regmap_fsi16le_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ __be16 v;
+
+ if (val > 0xffff)
+ return -EINVAL;
+
+ v = cpu_to_be16(val);
+ return fsi_slave_write(context, reg, &v, sizeof(v));
+}
+
+static const struct regmap_bus regmap_fsi16le = {
+ .reg_write = regmap_fsi16le_reg_write,
+ .reg_read = regmap_fsi16le_reg_read,
+};
+
+static int regmap_fsi8_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ u8 v;
+ int ret;
+
+ ret = fsi_slave_read(context, reg, &v, sizeof(v));
+ if (ret)
+ return ret;
+
+ *val = v;
+ return 0;
+}
+
+static int regmap_fsi8_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ u8 v;
+
+ if (val > 0xff)
+ return -EINVAL;
+
+ v = val;
+ return fsi_slave_write(context, reg, &v, sizeof(v));
+}
+
+static const struct regmap_bus regmap_fsi8 = {
+ .reg_write = regmap_fsi8_reg_write,
+ .reg_read = regmap_fsi8_reg_read,
+};
+
+static const struct regmap_bus *regmap_get_fsi_bus(struct fsi_device *fsi_dev,
+ const struct regmap_config *config)
+{
+ const struct regmap_bus *bus = NULL;
+
+ if (config->reg_bits == 8 || config->reg_bits == 16 || config->reg_bits == 32) {
+ switch (config->val_bits) {
+ case 8:
+ bus = &regmap_fsi8;
+ break;
+ case 16:
+ switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
+ case REGMAP_ENDIAN_LITTLE:
+#ifdef __LITTLE_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ bus = &regmap_fsi16le;
+ break;
+ case REGMAP_ENDIAN_DEFAULT:
+ case REGMAP_ENDIAN_BIG:
+#ifdef __BIG_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ bus = &regmap_fsi16;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 32:
+ switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
+ case REGMAP_ENDIAN_LITTLE:
+#ifdef __LITTLE_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ bus = &regmap_fsi32le;
+ break;
+ case REGMAP_ENDIAN_DEFAULT:
+ case REGMAP_ENDIAN_BIG:
+#ifdef __BIG_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ bus = &regmap_fsi32;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ return bus ?: ERR_PTR(-EOPNOTSUPP);
+}
+
+struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev, const struct regmap_config *config,
+ struct lock_class_key *lock_key, const char *lock_name)
+{
+ const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
+
+ if (IS_ERR(bus))
+ return ERR_CAST(bus);
+
+ return __regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__regmap_init_fsi);
+
+struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key, const char *lock_name)
+{
+ const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
+
+ if (IS_ERR(bus))
+ return ERR_CAST(bus);
+
+ return __devm_regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 4ef9488d05cd..a8f185430a07 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -115,12 +115,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
*/
for (i = 0; i < d->chip->num_regs; i++) {
if (d->mask_base) {
- reg = d->get_irq_reg(d, d->mask_base, i);
- ret = regmap_update_bits(d->map, reg,
- d->mask_buf_def[i], d->mask_buf[i]);
- if (ret)
- dev_err(d->map->dev, "Failed to sync masks in %x\n",
- reg);
+ if (d->chip->handle_mask_sync)
+ d->chip->handle_mask_sync(d->map, i,
+ d->mask_buf_def[i],
+ d->mask_buf[i],
+ d->chip->irq_drv_data);
+ else {
+ reg = d->get_irq_reg(d, d->mask_base, i);
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i],
+ d->mask_buf[i]);
+ if (ret)
+ dev_err(d->map->dev, "Failed to sync masks in %x\n",
+ reg);
+ }
}
if (d->unmask_base) {
@@ -722,6 +730,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
int i;
int ret = -ENOMEM;
int num_type_reg;
+ int num_regs;
u32 reg;
if (chip->num_regs <= 0)
@@ -796,14 +805,20 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
goto err_alloc;
}
- num_type_reg = chip->type_in_mask ? chip->num_regs : chip->num_type_reg;
- if (num_type_reg) {
- d->type_buf_def = kcalloc(num_type_reg,
+ /*
+ * Use num_config_regs if defined, otherwise fall back to num_type_reg
+ * to maintain backward compatibility.
+ */
+ num_type_reg = chip->num_config_regs ? chip->num_config_regs
+ : chip->num_type_reg;
+ num_regs = chip->type_in_mask ? chip->num_regs : num_type_reg;
+ if (num_regs) {
+ d->type_buf_def = kcalloc(num_regs,
sizeof(*d->type_buf_def), GFP_KERNEL);
if (!d->type_buf_def)
goto err_alloc;
- d->type_buf = kcalloc(num_type_reg, sizeof(*d->type_buf),
+ d->type_buf = kcalloc(num_regs, sizeof(*d->type_buf),
GFP_KERNEL);
if (!d->type_buf)
goto err_alloc;
@@ -917,13 +932,23 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
d->mask_buf[i] = d->mask_buf_def[i];
if (d->mask_base) {
- reg = d->get_irq_reg(d, d->mask_base, i);
- ret = regmap_update_bits(d->map, reg,
- d->mask_buf_def[i], d->mask_buf[i]);
- if (ret) {
- dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
- reg, ret);
- goto err_alloc;
+ if (chip->handle_mask_sync) {
+ ret = chip->handle_mask_sync(d->map, i,
+ d->mask_buf_def[i],
+ d->mask_buf[i],
+ chip->irq_drv_data);
+ if (ret)
+ goto err_alloc;
+ } else {
+ reg = d->get_irq_reg(d, d->mask_base, i);
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i],
+ d->mask_buf[i]);
+ if (ret) {
+ dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+ reg, ret);
+ goto err_alloc;
+ }
}
}
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c6d6d53e8cd3..d12d669157f2 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -3486,6 +3486,19 @@ int regmap_get_reg_stride(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+/**
+ * regmap_might_sleep() - Returns whether a regmap access might sleep.
+ *
+ * @map: Register map to operate on.
+ *
+ * Returns true if an access to the register might sleep, else false.
+ */
+bool regmap_might_sleep(struct regmap *map)
+{
+ return map->can_sleep;
+}
+EXPORT_SYMBOL_GPL(regmap_might_sleep);
+
int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val)
{
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a41145d52de9..a2184b428493 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -285,49 +285,6 @@ config BLK_DEV_RAM_SIZE
The default value is 4096 kilobytes. Only change this if you know
what you are doing.
-config CDROM_PKTCDVD
- tristate "Packet writing on CD/DVD media (DEPRECATED)"
- depends on !UML
- depends on SCSI
- select CDROM
- help
- Note: This driver is deprecated and will be removed from the
- kernel in the near future!
-
- If you have a CDROM/DVD drive that supports packet writing, say
- Y to include support. It should work with any MMC/Mt Fuji
- compliant ATAPI or SCSI drive, which is just about any newer
- DVD/CD writer.
-
- Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs
- is possible.
- DVD-RW disks must be in restricted overwrite mode.
-
- See the file <file:Documentation/cdrom/packet-writing.rst>
- for further information on the use of this driver.
-
- To compile this driver as a module, choose M here: the
- module will be called pktcdvd.
-
-config CDROM_PKTCDVD_BUFFERS
- int "Free buffers for data gathering"
- depends on CDROM_PKTCDVD
- default "8"
- help
- This controls the maximum number of active concurrent packets. More
- concurrent packets can increase write performance, but also require
- more memory. Each concurrent packet will require approximately 64Kb
- of non-swappable kernel memory, memory which will be allocated when
- a disc is opened for writing.
-
-config CDROM_PKTCDVD_WCACHE
- bool "Enable write caching"
- depends on CDROM_PKTCDVD
- help
- If enabled, write caching will be set for the CD-R/W device. For now
- this option is dangerous unless the CD-RW media is known good, as we
- don't do deferred write error handling yet.
-
config ATA_OVER_ETH
tristate "ATA over Ethernet support"
depends on NET
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 101612cba303..962ee65d8ca3 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_N64CART) += n64cart.o
obj-$(CONFIG_BLK_DEV_RAM) += brd.o
obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
-obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
obj-$(CONFIG_SUNVDC) += sunvdc.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
index cbacddc55a1d..6fb4e38fca88 100644
--- a/drivers/block/drbd/Kconfig
+++ b/drivers/block/drbd/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
#
# DRBD device driver configuration
#
diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
index 8bd534697d1b..c93e462130ff 100644
--- a/drivers/block/drbd/Makefile
+++ b/drivers/block/drbd/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
drbd-y := drbd_bitmap.o drbd_proc.o
drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o
drbd-y += drbd_main.o drbd_strings.o drbd_nl.o
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index e27478ae579c..429255876800 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_actlog.c
@@ -868,9 +868,9 @@ int __drbd_change_sync(struct drbd_device *device, sector_t sector, int size,
nr_sectors = get_capacity(device->vdisk);
esector = sector + (size >> 9) - 1;
- if (!expect(sector < nr_sectors))
+ if (!expect(device, sector < nr_sectors))
goto out;
- if (!expect(esector < nr_sectors))
+ if (!expect(device, esector < nr_sectors))
esector = nr_sectors - 1;
lbnr = BM_SECT_TO_BIT(nr_sectors-1);
@@ -1143,7 +1143,7 @@ void drbd_rs_complete_io(struct drbd_device *device, sector_t sector)
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (!bm_ext) {
spin_unlock_irqrestore(&device->al_lock, flags);
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "drbd_rs_complete_io() called, but extent not found\n");
return;
}
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 7d9db33363de..289876ffbc31 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_bitmap.c
@@ -113,7 +113,7 @@ struct drbd_bitmap {
static void __bm_print_lock_info(struct drbd_device *device, const char *func)
{
struct drbd_bitmap *b = device->bitmap;
- if (!__ratelimit(&drbd_ratelimit_state))
+ if (!drbd_ratelimit())
return;
drbd_err(device, "FIXME %s[%d] in %s, bitmap locked for '%s' by %s[%d]\n",
current->comm, task_pid_nr(current),
@@ -448,7 +448,7 @@ int drbd_bm_init(struct drbd_device *device)
sector_t drbd_bm_capacity(struct drbd_device *device)
{
- if (!expect(device->bitmap))
+ if (!expect(device, device->bitmap))
return 0;
return device->bitmap->bm_dev_capacity;
}
@@ -457,7 +457,7 @@ sector_t drbd_bm_capacity(struct drbd_device *device)
*/
void drbd_bm_cleanup(struct drbd_device *device)
{
- if (!expect(device->bitmap))
+ if (!expect(device, device->bitmap))
return;
bm_free_pages(device->bitmap->bm_pages, device->bitmap->bm_number_of_pages);
bm_vk_free(device->bitmap->bm_pages);
@@ -636,7 +636,7 @@ int drbd_bm_resize(struct drbd_device *device, sector_t capacity, int set_new_bi
int err = 0;
bool growing;
- if (!expect(b))
+ if (!expect(device, b))
return -ENOMEM;
drbd_bm_lock(device, "resize", BM_LOCKED_MASK);
@@ -757,9 +757,9 @@ unsigned long _drbd_bm_total_weight(struct drbd_device *device)
unsigned long s;
unsigned long flags;
- if (!expect(b))
+ if (!expect(device, b))
return 0;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 0;
spin_lock_irqsave(&b->bm_lock, flags);
@@ -783,9 +783,9 @@ unsigned long drbd_bm_total_weight(struct drbd_device *device)
size_t drbd_bm_words(struct drbd_device *device)
{
struct drbd_bitmap *b = device->bitmap;
- if (!expect(b))
+ if (!expect(device, b))
return 0;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 0;
return b->bm_words;
@@ -794,7 +794,7 @@ size_t drbd_bm_words(struct drbd_device *device)
unsigned long drbd_bm_bits(struct drbd_device *device)
{
struct drbd_bitmap *b = device->bitmap;
- if (!expect(b))
+ if (!expect(device, b))
return 0;
return b->bm_bits;
@@ -816,9 +816,9 @@ void drbd_bm_merge_lel(struct drbd_device *device, size_t offset, size_t number,
end = offset + number;
- if (!expect(b))
+ if (!expect(device, b))
return;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return;
if (number == 0)
return;
@@ -863,9 +863,9 @@ void drbd_bm_get_lel(struct drbd_device *device, size_t offset, size_t number,
end = offset + number;
- if (!expect(b))
+ if (!expect(device, b))
return;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return;
spin_lock_irq(&b->bm_lock);
@@ -894,9 +894,9 @@ void drbd_bm_get_lel(struct drbd_device *device, size_t offset, size_t number,
void drbd_bm_set_all(struct drbd_device *device)
{
struct drbd_bitmap *b = device->bitmap;
- if (!expect(b))
+ if (!expect(device, b))
return;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return;
spin_lock_irq(&b->bm_lock);
@@ -910,9 +910,9 @@ void drbd_bm_set_all(struct drbd_device *device)
void drbd_bm_clear_all(struct drbd_device *device)
{
struct drbd_bitmap *b = device->bitmap;
- if (!expect(b))
+ if (!expect(device, b))
return;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return;
spin_lock_irq(&b->bm_lock);
@@ -952,7 +952,7 @@ static void drbd_bm_endio(struct bio *bio)
bm_set_page_io_err(b->bm_pages[idx]);
/* Not identical to on disk version of it.
* Is BM_PAGE_IO_ERROR enough? */
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "IO ERROR %d on bitmap page idx %u\n",
bio->bi_status, idx);
} else {
@@ -1013,7 +1013,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho
else
len = PAGE_SIZE;
} else {
- if (__ratelimit(&drbd_ratelimit_state)) {
+ if (drbd_ratelimit()) {
drbd_err(device, "Invalid offset during on-disk bitmap access: "
"page idx %u, sector %llu\n", page_nr, on_disk_sector);
}
@@ -1332,9 +1332,9 @@ static unsigned long bm_find_next(struct drbd_device *device,
struct drbd_bitmap *b = device->bitmap;
unsigned long i = DRBD_END_OF_BITMAP;
- if (!expect(b))
+ if (!expect(device, b))
return i;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return i;
spin_lock_irq(&b->bm_lock);
@@ -1436,9 +1436,9 @@ static int bm_change_bits_to(struct drbd_device *device, const unsigned long s,
struct drbd_bitmap *b = device->bitmap;
int c = 0;
- if (!expect(b))
+ if (!expect(device, b))
return 1;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 0;
spin_lock_irqsave(&b->bm_lock, flags);
@@ -1582,9 +1582,9 @@ int drbd_bm_test_bit(struct drbd_device *device, const unsigned long bitnr)
unsigned long *p_addr;
int i;
- if (!expect(b))
+ if (!expect(device, b))
return 0;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 0;
spin_lock_irqsave(&b->bm_lock, flags);
@@ -1619,9 +1619,9 @@ int drbd_bm_count_bits(struct drbd_device *device, const unsigned long s, const
* robust in case we screwed up elsewhere, in that case pretend there
* was one dirty bit in the requested area, so we won't try to do a
* local read there (no bitmap probably implies no disk) */
- if (!expect(b))
+ if (!expect(device, b))
return 1;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 1;
spin_lock_irqsave(&b->bm_lock, flags);
@@ -1635,7 +1635,7 @@ int drbd_bm_count_bits(struct drbd_device *device, const unsigned long s, const
bm_unmap(p_addr);
p_addr = bm_map_pidx(b, idx);
}
- if (expect(bitnr < b->bm_bits))
+ if (expect(device, bitnr < b->bm_bits))
c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr));
else
drbd_err(device, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
@@ -1668,9 +1668,9 @@ int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr)
unsigned long flags;
unsigned long *p_addr, *bm;
- if (!expect(b))
+ if (!expect(device, b))
return 0;
- if (!expect(b->bm_pages))
+ if (!expect(device, b->bm_pages))
return 0;
spin_lock_irqsave(&b->bm_lock, flags);
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
index b3b9cd5628fd..a72c096aa5b1 100644
--- a/drivers/block/drbd/drbd_debugfs.c
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "drbd debugfs: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/block/drbd/drbd_debugfs.h b/drivers/block/drbd/drbd_debugfs.h
index 58e31cef0844..ee3d66eb40c6 100644
--- a/drivers/block/drbd/drbd_debugfs.h
+++ b/drivers/block/drbd/drbd_debugfs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/debugfs.h>
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 4d661282ff41..ae713338aa46 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
drbd_int.h
@@ -37,6 +37,7 @@
#include "drbd_strings.h"
#include "drbd_state.h"
#include "drbd_protocol.h"
+#include "drbd_polymorph_printk.h"
#ifdef __CHECKER__
# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr")))
@@ -75,71 +76,6 @@ extern int drbd_proc_details;
struct drbd_device;
struct drbd_connection;
-#define __drbd_printk_device(level, device, fmt, args...) \
- dev_printk(level, disk_to_dev((device)->vdisk), fmt, ## args)
-#define __drbd_printk_peer_device(level, peer_device, fmt, args...) \
- dev_printk(level, disk_to_dev((peer_device)->device->vdisk), fmt, ## args)
-#define __drbd_printk_resource(level, resource, fmt, args...) \
- printk(level "drbd %s: " fmt, (resource)->name, ## args)
-#define __drbd_printk_connection(level, connection, fmt, args...) \
- printk(level "drbd %s: " fmt, (connection)->resource->name, ## args)
-
-void drbd_printk_with_wrong_object_type(void);
-
-#define __drbd_printk_if_same_type(obj, type, func, level, fmt, args...) \
- (__builtin_types_compatible_p(typeof(obj), type) || \
- __builtin_types_compatible_p(typeof(obj), const type)), \
- func(level, (const type)(obj), fmt, ## args)
-
-#define drbd_printk(level, obj, fmt, args...) \
- __builtin_choose_expr( \
- __drbd_printk_if_same_type(obj, struct drbd_device *, \
- __drbd_printk_device, level, fmt, ## args), \
- __builtin_choose_expr( \
- __drbd_printk_if_same_type(obj, struct drbd_resource *, \
- __drbd_printk_resource, level, fmt, ## args), \
- __builtin_choose_expr( \
- __drbd_printk_if_same_type(obj, struct drbd_connection *, \
- __drbd_printk_connection, level, fmt, ## args), \
- __builtin_choose_expr( \
- __drbd_printk_if_same_type(obj, struct drbd_peer_device *, \
- __drbd_printk_peer_device, level, fmt, ## args), \
- drbd_printk_with_wrong_object_type()))))
-
-#define drbd_dbg(obj, fmt, args...) \
- drbd_printk(KERN_DEBUG, obj, fmt, ## args)
-#define drbd_alert(obj, fmt, args...) \
- drbd_printk(KERN_ALERT, obj, fmt, ## args)
-#define drbd_err(obj, fmt, args...) \
- drbd_printk(KERN_ERR, obj, fmt, ## args)
-#define drbd_warn(obj, fmt, args...) \
- drbd_printk(KERN_WARNING, obj, fmt, ## args)
-#define drbd_info(obj, fmt, args...) \
- drbd_printk(KERN_INFO, obj, fmt, ## args)
-#define drbd_emerg(obj, fmt, args...) \
- drbd_printk(KERN_EMERG, obj, fmt, ## args)
-
-#define dynamic_drbd_dbg(device, fmt, args...) \
- dynamic_dev_dbg(disk_to_dev(device->vdisk), fmt, ## args)
-
-#define D_ASSERT(device, exp) do { \
- if (!(exp)) \
- drbd_err(device, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__); \
- } while (0)
-
-/**
- * expect - Make an assertion
- *
- * Unlike the assert macro, this macro returns a boolean result.
- */
-#define expect(exp) ({ \
- bool _bool = (exp); \
- if (!_bool) \
- drbd_err(device, "ASSERTION %s FAILED in %s\n", \
- #exp, __func__); \
- _bool; \
- })
-
/* Defines to control fault insertion */
enum {
DRBD_FAULT_MD_WR = 0, /* meta data write */
@@ -395,6 +331,7 @@ struct drbd_peer_request {
struct drbd_peer_device *peer_device;
struct drbd_epoch *epoch; /* for writes */
struct page *pages;
+ blk_opf_t opf;
atomic_t pending_bios;
struct drbd_interval i;
/* see comments on ee flag bits below */
@@ -406,6 +343,10 @@ struct drbd_peer_request {
};
};
+/* Equivalent to bio_op and req_op. */
+#define peer_req_op(peer_req) \
+ ((peer_req)->opf & REQ_OP_MASK)
+
/* ee flag bits.
* While corresponding bios are in flight, the only modification will be
* set_bit WAS_ERROR, which has to be atomic.
@@ -1545,8 +1486,7 @@ extern void drbd_send_acks_wf(struct work_struct *ws);
extern bool drbd_rs_c_min_rate_throttle(struct drbd_device *device);
extern bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector,
bool throttle_if_app_is_waiting);
-extern int drbd_submit_peer_request(struct drbd_device *,
- struct drbd_peer_request *, blk_opf_t, int);
+extern int drbd_submit_peer_request(struct drbd_peer_request *peer_req);
extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
sector_t, unsigned int,
@@ -1718,7 +1658,7 @@ static inline void __drbd_chk_io_error_(struct drbd_device *device,
switch (ep) {
case EP_PASS_ON: /* FIXME would this be better named "Ignore"? */
if (df == DRBD_READ_ERROR || df == DRBD_WRITE_ERROR) {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Local IO failed in %s.\n", where);
if (device->state.disk > D_INCONSISTENT)
_drbd_set_state(_NS(device, disk, D_INCONSISTENT), CS_HARD, NULL);
diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c
index f07b4378388b..5024ffd6143d 100644
--- a/drivers/block/drbd/drbd_interval.c
+++ b/drivers/block/drbd/drbd_interval.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
#include <asm/bug.h>
#include <linux/rbtree_augmented.h>
#include "drbd_interval.h"
diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h
index b8c2dee5edc8..366489b72fe9 100644
--- a/drivers/block/drbd/drbd_interval.h
+++ b/drivers/block/drbd/drbd_interval.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRBD_INTERVAL_H
#define __DRBD_INTERVAL_H
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index f3e4db16fd07..2f16e1bfb6e7 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd.c
@@ -1259,7 +1259,7 @@ static int _drbd_send_bitmap(struct drbd_device *device)
struct bm_xfer_ctx c;
int err;
- if (!expect(device->bitmap))
+ if (!expect(device, device->bitmap))
return false;
if (get_ldev(device)) {
@@ -1816,7 +1816,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock,
/* THINK if (signal_pending) return ... ? */
- iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size);
if (sock == connection->data.socket) {
rcu_read_lock();
@@ -2217,7 +2217,8 @@ void drbd_destroy_device(struct kref *kref)
kref_put(&peer_device->connection->kref, drbd_destroy_connection);
kfree(peer_device);
}
- memset(device, 0xfd, sizeof(*device));
+ if (device->submit.wq)
+ destroy_workqueue(device->submit.wq);
kfree(device);
kref_put(&resource->kref, drbd_destroy_resource);
}
@@ -2249,9 +2250,9 @@ static void do_retry(struct work_struct *ws)
bool expected;
expected =
- expect(atomic_read(&req->completion_ref) == 0) &&
- expect(req->rq_state & RQ_POSTPONED) &&
- expect((req->rq_state & RQ_LOCAL_PENDING) == 0 ||
+ expect(device, atomic_read(&req->completion_ref) == 0) &&
+ expect(device, req->rq_state & RQ_POSTPONED) &&
+ expect(device, (req->rq_state & RQ_LOCAL_PENDING) == 0 ||
(req->rq_state & RQ_LOCAL_ABORTED) != 0);
if (!expected)
@@ -2309,7 +2310,6 @@ void drbd_destroy_resource(struct kref *kref)
idr_destroy(&resource->devices);
free_cpumask_var(resource->cpu_mask);
kfree(resource->name);
- memset(resource, 0xf2, sizeof(*resource));
kfree(resource);
}
@@ -2650,7 +2650,6 @@ void drbd_destroy_connection(struct kref *kref)
drbd_free_socket(&connection->data);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
- memset(connection, 0xfc, sizeof(*connection));
kfree(connection);
kref_put(&resource->kref, drbd_destroy_resource);
}
@@ -2672,7 +2671,7 @@ static int init_submitter(struct drbd_device *device)
enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor)
{
struct drbd_resource *resource = adm_ctx->resource;
- struct drbd_connection *connection;
+ struct drbd_connection *connection, *n;
struct drbd_device *device;
struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk;
@@ -2774,7 +2773,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
err = add_disk(disk);
if (err)
- goto out_idr_remove_from_resource;
+ goto out_destroy_workqueue;
/* inherit the connection state */
device->state.conn = first_connection(resource)->cstate;
@@ -2788,8 +2787,10 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
drbd_debugfs_device_add(device);
return NO_ERROR;
+out_destroy_workqueue:
+ destroy_workqueue(device->submit.wq);
out_idr_remove_from_resource:
- for_each_connection(connection, resource) {
+ for_each_connection_safe(connection, n, resource) {
peer_device = idr_remove(&connection->peer_devices, vnr);
if (peer_device)
kref_put(&connection->kref, drbd_destroy_connection);
@@ -3766,7 +3767,7 @@ _drbd_insert_fault(struct drbd_device *device, unsigned int type)
if (ret) {
drbd_fault_count++;
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_warn(device, "***Simulating %s failure\n",
_drbd_fault_str(type));
}
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 864c98e74875..60757ac31701 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_nl.c
@@ -1210,6 +1210,7 @@ static void decide_on_discard_support(struct drbd_device *device,
struct drbd_connection *connection =
first_peer_device(device)->connection;
struct request_queue *q = device->rq_queue;
+ unsigned int max_discard_sectors;
if (bdev && !bdev_max_discard_sectors(bdev->backing_bdev))
goto not_supported;
@@ -1230,15 +1231,14 @@ static void decide_on_discard_support(struct drbd_device *device,
* topology on all peers.
*/
blk_queue_discard_granularity(q, 512);
- q->limits.max_discard_sectors = drbd_max_discard_sectors(connection);
- q->limits.max_write_zeroes_sectors =
- drbd_max_discard_sectors(connection);
+ max_discard_sectors = drbd_max_discard_sectors(connection);
+ blk_queue_max_discard_sectors(q, max_discard_sectors);
+ blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
return;
not_supported:
blk_queue_discard_granularity(q, 0);
- q->limits.max_discard_sectors = 0;
- q->limits.max_write_zeroes_sectors = 0;
+ blk_queue_max_discard_sectors(q, 0);
}
static void fixup_write_zeroes(struct drbd_device *device, struct request_queue *q)
@@ -1256,6 +1256,18 @@ static void fixup_write_zeroes(struct drbd_device *device, struct request_queue
q->limits.max_write_zeroes_sectors = 0;
}
+static void fixup_discard_support(struct drbd_device *device, struct request_queue *q)
+{
+ unsigned int max_discard = device->rq_queue->limits.max_discard_sectors;
+ unsigned int discard_granularity =
+ device->rq_queue->limits.discard_granularity >> SECTOR_SHIFT;
+
+ if (discard_granularity > max_discard) {
+ blk_queue_discard_granularity(q, 0);
+ blk_queue_max_discard_sectors(q, 0);
+ }
+}
+
static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backing_dev *bdev,
unsigned int max_bio_size, struct o_qlim *o)
{
@@ -1288,6 +1300,7 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi
disk_update_readahead(device->vdisk);
}
fixup_write_zeroes(device, q);
+ fixup_discard_support(device, q);
}
void drbd_reconsider_queue_parameters(struct drbd_device *device, struct drbd_backing_dev *bdev, struct o_qlim *o)
@@ -1530,7 +1543,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
goto fail_unlock;
}
- if (!expect(new_disk_conf->resync_rate >= 1))
+ if (!expect(device, new_disk_conf->resync_rate >= 1))
new_disk_conf->resync_rate = 1;
sanitize_disk_conf(device, new_disk_conf, device->ldev);
diff --git a/drivers/block/drbd/drbd_nla.c b/drivers/block/drbd/drbd_nla.c
index 6a09b0b98018..df0d241d3f6a 100644
--- a/drivers/block/drbd/drbd_nla.c
+++ b/drivers/block/drbd/drbd_nla.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/kernel.h>
#include <net/netlink.h>
#include <linux/drbd_genl_api.h>
diff --git a/drivers/block/drbd/drbd_nla.h b/drivers/block/drbd/drbd_nla.h
index f5eaffb6474e..d3555df0d353 100644
--- a/drivers/block/drbd/drbd_nla.h
+++ b/drivers/block/drbd/drbd_nla.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRBD_NLA_H
#define __DRBD_NLA_H
diff --git a/drivers/block/drbd/drbd_polymorph_printk.h b/drivers/block/drbd/drbd_polymorph_printk.h
new file mode 100644
index 000000000000..8e0082d139ba
--- /dev/null
+++ b/drivers/block/drbd/drbd_polymorph_printk.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef DRBD_POLYMORPH_PRINTK_H
+#define DRBD_POLYMORPH_PRINTK_H
+
+#if !defined(CONFIG_DYNAMIC_DEBUG)
+#undef DEFINE_DYNAMIC_DEBUG_METADATA
+#undef __dynamic_pr_debug
+#undef DYNAMIC_DEBUG_BRANCH
+#define DEFINE_DYNAMIC_DEBUG_METADATA(D, F) const char *D = F; ((void)D)
+#define __dynamic_pr_debug(D, F, args...) do { (void)(D); if (0) printk(F, ## args); } while (0)
+#define DYNAMIC_DEBUG_BRANCH(D) false
+#endif
+
+
+#define __drbd_printk_drbd_device_prep(device) \
+ const struct drbd_device *__d = (device); \
+ const struct drbd_resource *__r = __d->resource
+#define __drbd_printk_drbd_device_fmt(fmt) "drbd %s/%u drbd%u: " fmt
+#define __drbd_printk_drbd_device_args() __r->name, __d->vnr, __d->minor
+#define __drbd_printk_drbd_device_unprep()
+
+#define __drbd_printk_drbd_peer_device_prep(peer_device) \
+ const struct drbd_device *__d; \
+ const struct drbd_resource *__r; \
+ __d = (peer_device)->device; \
+ __r = __d->resource
+#define __drbd_printk_drbd_peer_device_fmt(fmt) \
+ "drbd %s/%u drbd%u: " fmt
+#define __drbd_printk_drbd_peer_device_args() \
+ __r->name, __d->vnr, __d->minor
+#define __drbd_printk_drbd_peer_device_unprep()
+
+#define __drbd_printk_drbd_resource_prep(resource) \
+ const struct drbd_resource *__r = resource
+#define __drbd_printk_drbd_resource_fmt(fmt) "drbd %s: " fmt
+#define __drbd_printk_drbd_resource_args() __r->name
+#define __drbd_printk_drbd_resource_unprep(resource)
+
+#define __drbd_printk_drbd_connection_prep(connection) \
+ const struct drbd_connection *__c = (connection); \
+ const struct drbd_resource *__r = __c->resource
+#define __drbd_printk_drbd_connection_fmt(fmt) \
+ "drbd %s: " fmt
+#define __drbd_printk_drbd_connection_args() \
+ __r->name
+#define __drbd_printk_drbd_connection_unprep()
+
+void drbd_printk_with_wrong_object_type(void);
+void drbd_dyn_dbg_with_wrong_object_type(void);
+
+#define __drbd_printk_choose_cond(obj, struct_name) \
+ (__builtin_types_compatible_p(typeof(obj), struct struct_name *) || \
+ __builtin_types_compatible_p(typeof(obj), const struct struct_name *))
+#define __drbd_printk_if_same_type(obj, struct_name, level, fmt, args...) \
+ __drbd_printk_choose_cond(obj, struct_name), \
+({ \
+ __drbd_printk_ ## struct_name ## _prep((const struct struct_name *)(obj)); \
+ printk(level __drbd_printk_ ## struct_name ## _fmt(fmt), \
+ __drbd_printk_ ## struct_name ## _args(), ## args); \
+ __drbd_printk_ ## struct_name ## _unprep(); \
+})
+
+#define drbd_printk(level, obj, fmt, args...) \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, drbd_device, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, drbd_resource, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, drbd_connection, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, drbd_peer_device, level, fmt, ## args), \
+ drbd_printk_with_wrong_object_type()))))
+
+#define __drbd_dyn_dbg_if_same_type(obj, struct_name, fmt, args...) \
+ __drbd_printk_choose_cond(obj, struct_name), \
+({ \
+ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
+ if (DYNAMIC_DEBUG_BRANCH(descriptor)) { \
+ __drbd_printk_ ## struct_name ## _prep((const struct struct_name *)(obj)); \
+ __dynamic_pr_debug(&descriptor, __drbd_printk_ ## struct_name ## _fmt(fmt), \
+ __drbd_printk_ ## struct_name ## _args(), ## args); \
+ __drbd_printk_ ## struct_name ## _unprep(); \
+ } \
+})
+
+#define dynamic_drbd_dbg(obj, fmt, args...) \
+ __builtin_choose_expr( \
+ __drbd_dyn_dbg_if_same_type(obj, drbd_device, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_dyn_dbg_if_same_type(obj, drbd_resource, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_dyn_dbg_if_same_type(obj, drbd_connection, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_dyn_dbg_if_same_type(obj, drbd_peer_device, fmt, ## args), \
+ drbd_dyn_dbg_with_wrong_object_type()))))
+
+#define drbd_emerg(device, fmt, args...) \
+ drbd_printk(KERN_EMERG, device, fmt, ## args)
+#define drbd_alert(device, fmt, args...) \
+ drbd_printk(KERN_ALERT, device, fmt, ## args)
+#define drbd_crit(device, fmt, args...) \
+ drbd_printk(KERN_CRIT, device, fmt, ## args)
+#define drbd_err(device, fmt, args...) \
+ drbd_printk(KERN_ERR, device, fmt, ## args)
+#define drbd_warn(device, fmt, args...) \
+ drbd_printk(KERN_WARNING, device, fmt, ## args)
+#define drbd_notice(device, fmt, args...) \
+ drbd_printk(KERN_NOTICE, device, fmt, ## args)
+#define drbd_info(device, fmt, args...) \
+ drbd_printk(KERN_INFO, device, fmt, ## args)
+
+
+#define drbd_ratelimit() \
+({ \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ DEFAULT_RATELIMIT_INTERVAL, \
+ DEFAULT_RATELIMIT_BURST); \
+ __ratelimit(&_rs); \
+})
+
+#define D_ASSERT(x, exp) \
+ do { \
+ if (!(exp)) \
+ drbd_err(x, "ASSERTION %s FAILED in %s\n", \
+ #exp, __func__); \
+ } while (0)
+
+/**
+ * expect - Make an assertion
+ *
+ * Unlike the assert macro, this macro returns a boolean result.
+ */
+#define expect(x, exp) ({ \
+ bool _bool = (exp); \
+ if (!_bool && drbd_ratelimit()) \
+ drbd_err(x, "ASSERTION %s FAILED in %s\n", \
+ #exp, __func__); \
+ _bool; \
+ })
+
+#endif
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index 3c0193de2498..2227fb0db1ce 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_proc.c
diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h
index a882b65ab5d2..56bbca9d7700 100644
--- a/drivers/block/drbd/drbd_protocol.h
+++ b/drivers/block/drbd/drbd_protocol.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRBD_PROTOCOL_H
#define __DRBD_PROTOCOL_H
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index ee69d50ba4fd..0e58a3187345 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_receiver.c
@@ -413,7 +413,7 @@ void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *
drbd_free_pages(device, peer_req->pages, is_net);
D_ASSERT(device, atomic_read(&peer_req->pending_bios) == 0);
D_ASSERT(device, drbd_interval_empty(&peer_req->i));
- if (!expect(!(peer_req->flags & EE_CALL_AL_COMPLETE_IO))) {
+ if (!expect(device, !(peer_req->flags & EE_CALL_AL_COMPLETE_IO))) {
peer_req->flags &= ~EE_CALL_AL_COMPLETE_IO;
drbd_al_complete_io(device, &peer_req->i);
}
@@ -507,7 +507,7 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag
struct msghdr msg = {
.msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
};
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
return sock_recvmsg(sock, &msg, msg.msg_flags);
}
@@ -781,7 +781,7 @@ static struct socket *drbd_wait_for_connect(struct drbd_connection *connection,
timeo = connect_int * HZ;
/* 28.5% random jitter */
- timeo += prandom_u32_max(2) ? timeo / 7 : -timeo / 7;
+ timeo += get_random_u32_below(2) ? timeo / 7 : -timeo / 7;
err = wait_for_completion_interruptible_timeout(&ad->door_bell, timeo);
if (err <= 0)
@@ -1004,7 +1004,7 @@ retry:
drbd_warn(connection, "Error receiving initial packet\n");
sock_release(s);
randomize:
- if (prandom_u32_max(2))
+ if (get_random_u32_below(2))
goto retry;
}
}
@@ -1603,9 +1603,19 @@ static void drbd_issue_peer_discard_or_zero_out(struct drbd_device *device, stru
drbd_endio_write_sec_final(peer_req);
}
+static int peer_request_fault_type(struct drbd_peer_request *peer_req)
+{
+ if (peer_req_op(peer_req) == REQ_OP_READ) {
+ return peer_req->flags & EE_APPLICATION ?
+ DRBD_FAULT_DT_RD : DRBD_FAULT_RS_RD;
+ } else {
+ return peer_req->flags & EE_APPLICATION ?
+ DRBD_FAULT_DT_WR : DRBD_FAULT_RS_WR;
+ }
+}
+
/**
* drbd_submit_peer_request()
- * @device: DRBD device.
* @peer_req: peer request
*
* May spread the pages to multiple bios,
@@ -1619,10 +1629,9 @@ static void drbd_issue_peer_discard_or_zero_out(struct drbd_device *device, stru
* on certain Xen deployments.
*/
/* TODO allocate from our own bio_set. */
-int drbd_submit_peer_request(struct drbd_device *device,
- struct drbd_peer_request *peer_req,
- const blk_opf_t opf, const int fault_type)
+int drbd_submit_peer_request(struct drbd_peer_request *peer_req)
{
+ struct drbd_device *device = peer_req->peer_device->device;
struct bio *bios = NULL;
struct bio *bio;
struct page *page = peer_req->pages;
@@ -1667,7 +1676,18 @@ int drbd_submit_peer_request(struct drbd_device *device,
* generated bio, but a bio allocated on behalf of the peer.
*/
next_bio:
- bio = bio_alloc(device->ldev->backing_bdev, nr_pages, opf, GFP_NOIO);
+ /* _DISCARD, _WRITE_ZEROES handled above.
+ * REQ_OP_FLUSH (empty flush) not expected,
+ * should have been mapped to a "drbd protocol barrier".
+ * REQ_OP_SECURE_ERASE: I don't see how we could ever support that.
+ */
+ if (!(peer_req_op(peer_req) == REQ_OP_WRITE ||
+ peer_req_op(peer_req) == REQ_OP_READ)) {
+ drbd_err(device, "Invalid bio op received: 0x%x\n", peer_req->opf);
+ return -EINVAL;
+ }
+
+ bio = bio_alloc(device->ldev->backing_bdev, nr_pages, peer_req->opf, GFP_NOIO);
/* > peer_req->i.sector, unless this is the first bio */
bio->bi_iter.bi_sector = sector;
bio->bi_private = peer_req;
@@ -1697,7 +1717,7 @@ next_bio:
bios = bios->bi_next;
bio->bi_next = NULL;
- drbd_submit_bio_noacct(device, fault_type, bio);
+ drbd_submit_bio_noacct(device, peer_request_fault_type(peer_req), bio);
} while (bios);
return 0;
}
@@ -1853,21 +1873,21 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
/* assume request_size == data_size, but special case trim. */
ds = data_size;
if (trim) {
- if (!expect(data_size == 0))
+ if (!expect(peer_device, data_size == 0))
return NULL;
ds = be32_to_cpu(trim->size);
} else if (zeroes) {
- if (!expect(data_size == 0))
+ if (!expect(peer_device, data_size == 0))
return NULL;
ds = be32_to_cpu(zeroes->size);
}
- if (!expect(IS_ALIGNED(ds, 512)))
+ if (!expect(peer_device, IS_ALIGNED(ds, 512)))
return NULL;
if (trim || zeroes) {
- if (!expect(ds <= (DRBD_MAX_BBIO_SECTORS << 9)))
+ if (!expect(peer_device, ds <= (DRBD_MAX_BBIO_SECTORS << 9)))
return NULL;
- } else if (!expect(ds <= DRBD_MAX_BIO_SIZE))
+ } else if (!expect(peer_device, ds <= DRBD_MAX_BIO_SIZE))
return NULL;
/* even though we trust out peer,
@@ -2051,6 +2071,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto
* respective _drbd_clear_done_ee */
peer_req->w.cb = e_end_resync_block;
+ peer_req->opf = REQ_OP_WRITE;
peer_req->submit_jif = jiffies;
spin_lock_irq(&device->resource->req_lock);
@@ -2058,8 +2079,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto
spin_unlock_irq(&device->resource->req_lock);
atomic_add(pi->size >> 9, &device->rs_sect_ev);
- if (drbd_submit_peer_request(device, peer_req, REQ_OP_WRITE,
- DRBD_FAULT_RS_WR) == 0)
+ if (drbd_submit_peer_request(peer_req) == 0)
return 0;
/* don't care for the reason here */
@@ -2145,7 +2165,7 @@ static int receive_RSDataReply(struct drbd_connection *connection, struct packet
* or in drbd_peer_request_endio. */
err = recv_resync_read(peer_device, sector, pi);
} else {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Can not write resync data to local disk.\n");
err = drbd_drain_block(peer_device, pi->size);
@@ -2375,16 +2395,6 @@ static int wait_for_and_update_peer_seq(struct drbd_peer_device *peer_device, co
return ret;
}
-/* see also bio_flags_to_wire()
- * DRBD_REQ_*, because we need to semantically map the flags to data packet
- * flags and back. We may replicate to other kernel versions. */
-static blk_opf_t wire_flags_to_bio_flags(u32 dpf)
-{
- return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
- (dpf & DP_FUA ? REQ_FUA : 0) |
- (dpf & DP_FLUSH ? REQ_PREFLUSH : 0);
-}
-
static enum req_op wire_flags_to_bio_op(u32 dpf)
{
if (dpf & DP_ZEROES)
@@ -2395,6 +2405,15 @@ static enum req_op wire_flags_to_bio_op(u32 dpf)
return REQ_OP_WRITE;
}
+/* see also bio_flags_to_wire() */
+static blk_opf_t wire_flags_to_bio(struct drbd_connection *connection, u32 dpf)
+{
+ return wire_flags_to_bio_op(dpf) |
+ (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
+ (dpf & DP_FUA ? REQ_FUA : 0) |
+ (dpf & DP_FLUSH ? REQ_PREFLUSH : 0);
+}
+
static void fail_postponed_requests(struct drbd_device *device, sector_t sector,
unsigned int size)
{
@@ -2538,8 +2557,6 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
struct drbd_peer_request *peer_req;
struct p_data *p = pi->data;
u32 peer_seq = be32_to_cpu(p->seq_num);
- enum req_op op;
- blk_opf_t op_flags;
u32 dp_flags;
int err, tp;
@@ -2578,11 +2595,10 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
peer_req->flags |= EE_APPLICATION;
dp_flags = be32_to_cpu(p->dp_flags);
- op = wire_flags_to_bio_op(dp_flags);
- op_flags = wire_flags_to_bio_flags(dp_flags);
+ peer_req->opf = wire_flags_to_bio(connection, dp_flags);
if (pi->cmd == P_TRIM) {
D_ASSERT(peer_device, peer_req->i.size > 0);
- D_ASSERT(peer_device, op == REQ_OP_DISCARD);
+ D_ASSERT(peer_device, peer_req_op(peer_req) == REQ_OP_DISCARD);
D_ASSERT(peer_device, peer_req->pages == NULL);
/* need to play safe: an older DRBD sender
* may mean zero-out while sending P_TRIM. */
@@ -2590,7 +2606,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
peer_req->flags |= EE_ZEROOUT;
} else if (pi->cmd == P_ZEROES) {
D_ASSERT(peer_device, peer_req->i.size > 0);
- D_ASSERT(peer_device, op == REQ_OP_WRITE_ZEROES);
+ D_ASSERT(peer_device, peer_req_op(peer_req) == REQ_OP_WRITE_ZEROES);
D_ASSERT(peer_device, peer_req->pages == NULL);
/* Do (not) pass down BLKDEV_ZERO_NOUNMAP? */
if (dp_flags & DP_DISCARD)
@@ -2677,8 +2693,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
peer_req->flags |= EE_CALL_AL_COMPLETE_IO;
}
- err = drbd_submit_peer_request(device, peer_req, op | op_flags,
- DRBD_FAULT_DT_WR);
+ err = drbd_submit_peer_request(peer_req);
if (!err)
return 0;
@@ -2789,7 +2804,6 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
struct drbd_peer_request *peer_req;
struct digest_info *di = NULL;
int size, verb;
- unsigned int fault_type;
struct p_block_req *p = pi->data;
peer_device = conn_peer_device(connection, pi->vnr);
@@ -2832,7 +2846,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
default:
BUG();
}
- if (verb && __ratelimit(&drbd_ratelimit_state))
+ if (verb && drbd_ratelimit())
drbd_err(device, "Can not satisfy peer's read request, "
"no local data.\n");
@@ -2849,11 +2863,11 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
put_ldev(device);
return -ENOMEM;
}
+ peer_req->opf = REQ_OP_READ;
switch (pi->cmd) {
case P_DATA_REQUEST:
peer_req->w.cb = w_e_end_data_req;
- fault_type = DRBD_FAULT_DT_RD;
/* application IO, don't drbd_rs_begin_io */
peer_req->flags |= EE_APPLICATION;
goto submit;
@@ -2867,14 +2881,12 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
fallthrough;
case P_RS_DATA_REQUEST:
peer_req->w.cb = w_e_end_rsdata_req;
- fault_type = DRBD_FAULT_RS_RD;
/* used in the sector offset progress display */
device->bm_resync_fo = BM_SECT_TO_BIT(sector);
break;
case P_OV_REPLY:
case P_CSUM_RS_REQUEST:
- fault_type = DRBD_FAULT_RS_RD;
di = kmalloc(sizeof(*di) + pi->size, GFP_NOIO);
if (!di)
goto out_free_e;
@@ -2923,7 +2935,6 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
(unsigned long long)sector);
}
peer_req->w.cb = w_e_end_ov_req;
- fault_type = DRBD_FAULT_RS_RD;
break;
default:
@@ -2975,8 +2986,7 @@ submit_for_resync:
submit:
update_receiver_timing_details(connection, drbd_submit_peer_request);
inc_unacked(device);
- if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ,
- fault_type) == 0)
+ if (drbd_submit_peer_request(peer_req) == 0)
return 0;
/* don't care for the reason here */
@@ -4947,7 +4957,6 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
if (get_ldev(device)) {
struct drbd_peer_request *peer_req;
- const enum req_op op = REQ_OP_WRITE_ZEROES;
peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER, sector,
size, 0, GFP_NOIO);
@@ -4957,6 +4966,7 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
}
peer_req->w.cb = e_end_resync_block;
+ peer_req->opf = REQ_OP_DISCARD;
peer_req->submit_jif = jiffies;
peer_req->flags |= EE_TRIM;
@@ -4965,8 +4975,7 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
spin_unlock_irq(&device->resource->req_lock);
atomic_add(pi->size >> 9, &device->rs_sect_ev);
- err = drbd_submit_peer_request(device, peer_req, op,
- DRBD_FAULT_RS_WR);
+ err = drbd_submit_peer_request(peer_req);
if (err) {
spin_lock_irq(&device->resource->req_lock);
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 7f9bcc82fc9c..eb14ec8ec04c 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_req.c
@@ -144,7 +144,7 @@ void drbd_req_destroy(struct kref *kref)
if (get_ldev_if_state(device, D_FAILED)) {
drbd_al_complete_io(device, &req->i);
put_ldev(device);
- } else if (__ratelimit(&drbd_ratelimit_state)) {
+ } else if (drbd_ratelimit()) {
drbd_warn(device, "Should have called drbd_al_complete_io(, %llu, %u), "
"but my Disk seems to have failed :(\n",
(unsigned long long) req->i.sector, req->i.size);
@@ -518,7 +518,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req)
{
- if (!__ratelimit(&drbd_ratelimit_state))
+ if (!drbd_ratelimit())
return;
drbd_warn(device, "local %s IO error sector %llu+%u on %pg\n",
@@ -1402,7 +1402,7 @@ static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request
submit_private_bio = true;
} else if (no_remote) {
nodata:
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "IO ERROR: neither local nor remote data, sector %llu+%u\n",
(unsigned long long)req->i.sector, req->i.size >> 9);
/* A write may have been queued for send_oos, however.
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 6237fa1dcb0e..b4017b5c3fbc 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
drbd_req.h
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 3f7bf9f2d874..75d13ea0024f 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_state.c
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h
index f87371e55e68..cbaeb8018dbf 100644
--- a/drivers/block/drbd/drbd_state.h
+++ b/drivers/block/drbd/drbd_state.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef DRBD_STATE_H
#define DRBD_STATE_H
diff --git a/drivers/block/drbd/drbd_state_change.h b/drivers/block/drbd/drbd_state_change.h
index d5b0479bc9a6..9d78d8e3912e 100644
--- a/drivers/block/drbd/drbd_state_change.h
+++ b/drivers/block/drbd/drbd_state_change.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef DRBD_STATE_CHANGE_H
#define DRBD_STATE_CHANGE_H
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
index fc01307607ea..0a06f744b096 100644
--- a/drivers/block/drbd/drbd_strings.c
+++ b/drivers/block/drbd/drbd_strings.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd.h
diff --git a/drivers/block/drbd/drbd_strings.h b/drivers/block/drbd/drbd_strings.h
index 87b94a27358a..0201f6590f6a 100644
--- a/drivers/block/drbd/drbd_strings.h
+++ b/drivers/block/drbd/drbd_strings.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRBD_STRINGS_H
#define __DRBD_STRINGS_H
diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h
index 01e3babc5277..1ee81e3c2152 100644
--- a/drivers/block/drbd/drbd_vli.h
+++ b/drivers/block/drbd/drbd_vli.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
-*- linux-c -*-
drbd_receiver.c
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 0bb1a900c2d5..f46738040d6b 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
drbd_worker.c
@@ -176,7 +176,7 @@ void drbd_peer_request_endio(struct bio *bio)
bool is_discard = bio_op(bio) == REQ_OP_WRITE_ZEROES ||
bio_op(bio) == REQ_OP_DISCARD;
- if (bio->bi_status && __ratelimit(&drbd_ratelimit_state))
+ if (bio->bi_status && drbd_ratelimit())
drbd_warn(device, "%s: error=%d s=%llus\n",
is_write ? (is_discard ? "discard" : "write")
: "read", bio->bi_status,
@@ -240,7 +240,7 @@ void drbd_request_endio(struct bio *bio)
* though we still will complain noisily about it.
*/
if (unlikely(req->rq_state & RQ_LOCAL_ABORTED)) {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
if (!bio->bi_status)
@@ -400,13 +400,13 @@ static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector,
goto defer;
peer_req->w.cb = w_e_send_csum;
+ peer_req->opf = REQ_OP_READ;
spin_lock_irq(&device->resource->req_lock);
list_add_tail(&peer_req->w.list, &device->read_ee);
spin_unlock_irq(&device->resource->req_lock);
atomic_add(size >> 9, &device->rs_sect_ev);
- if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ,
- DRBD_FAULT_RS_RD) == 0)
+ if (drbd_submit_peer_request(peer_req) == 0)
return 0;
/* If it failed because of ENOMEM, retry should help. If it failed
@@ -1062,7 +1062,7 @@ int w_e_end_data_req(struct drbd_work *w, int cancel)
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
err = drbd_send_block(peer_device, P_DATA_REPLY, peer_req);
} else {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Sending NegDReply. sector=%llus.\n",
(unsigned long long)peer_req->i.sector);
@@ -1135,13 +1135,13 @@ int w_e_end_rsdata_req(struct drbd_work *w, int cancel)
else
err = drbd_send_block(peer_device, P_RS_DATA_REPLY, peer_req);
} else {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Not sending RSDataReply, "
"partner DISKLESS!\n");
err = 0;
}
} else {
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Sending NegRSDReply. sector %llus.\n",
(unsigned long long)peer_req->i.sector);
@@ -1212,7 +1212,7 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
}
} else {
err = drbd_send_ack(peer_device, P_NEG_RS_DREPLY, peer_req);
- if (__ratelimit(&drbd_ratelimit_state))
+ if (drbd_ratelimit())
drbd_err(device, "Sending NegDReply. I guess it gets messy.\n");
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index ccad3d7b3ddd..487840e3564d 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4593,8 +4593,10 @@ static int __init do_floppy_init(void)
goto out_put_disk;
err = floppy_alloc_disk(drive, 0);
- if (err)
+ if (err) {
+ blk_mq_free_tag_set(&tag_sets[drive]);
goto out_put_disk;
+ }
timer_setup(&motor_off_timer[drive], motor_off_callback, 0);
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ad92192c7d61..1f8f3b87bdfa 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -243,7 +243,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
struct iov_iter i;
ssize_t bw;
- iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
+ iov_iter_bvec(&i, ITER_SOURCE, bvec, 1, bvec->bv_len);
file_start_write(file);
bw = vfs_iter_write(file, &i, ppos, 0);
@@ -286,7 +286,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq,
ssize_t len;
rq_for_each_segment(bvec, rq, iter) {
- iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&i, ITER_DEST, &bvec, 1, bvec.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0)
return len;
@@ -392,7 +392,7 @@ static void lo_rw_aio_complete(struct kiocb *iocb, long ret)
}
static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
- loff_t pos, bool rw)
+ loff_t pos, int rw)
{
struct iov_iter iter;
struct req_iterator rq_iter;
@@ -448,7 +448,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
cmd->iocb.ki_flags = IOCB_DIRECT;
cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0);
- if (rw == WRITE)
+ if (rw == ITER_SOURCE)
ret = call_write_iter(file, &cmd->iocb, &iter);
else
ret = call_read_iter(file, &cmd->iocb, &iter);
@@ -490,12 +490,12 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq)
return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE);
case REQ_OP_WRITE:
if (cmd->use_aio)
- return lo_rw_aio(lo, cmd, pos, WRITE);
+ return lo_rw_aio(lo, cmd, pos, ITER_SOURCE);
else
return lo_write_simple(lo, rq, pos);
case REQ_OP_READ:
if (cmd->use_aio)
- return lo_rw_aio(lo, cmd, pos, READ);
+ return lo_rw_aio(lo, cmd, pos, ITER_DEST);
else
return lo_read_simple(lo, rq, pos);
default:
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 5cffd96ef2d7..e379ccc63c52 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -563,7 +563,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
u32 nbd_cmd_flags = 0;
int sent = nsock->sent, skip = 0;
- iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
+ iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
type = req_to_nbd_cmd_type(req);
if (type == U32_MAX)
@@ -649,7 +649,7 @@ send_pages:
dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
req, bvec.bv_len);
- iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&from, ITER_SOURCE, &bvec, 1, bvec.bv_len);
if (skip) {
if (skip >= iov_iter_count(&from)) {
skip -= iov_iter_count(&from);
@@ -701,7 +701,7 @@ static int nbd_read_reply(struct nbd_device *nbd, int index,
int result;
reply->magic = 0;
- iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply));
+ iov_iter_kvec(&to, ITER_DEST, &iov, 1, sizeof(*reply));
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result < 0) {
if (!nbd_disconnected(nbd->config))
@@ -790,7 +790,7 @@ static struct nbd_cmd *nbd_handle_reply(struct nbd_device *nbd, int index,
struct iov_iter to;
rq_for_each_segment(bvec, req, iter) {
- iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&to, ITER_DEST, &bvec, 1, bvec.bv_len);
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result < 0) {
dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
@@ -1267,7 +1267,7 @@ static void send_disconnects(struct nbd_device *nbd)
for (i = 0; i < config->num_connections; i++) {
struct nbd_sock *nsock = config->socks[i];
- iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
+ iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
mutex_lock(&nsock->tx_lock);
ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
if (ret < 0)
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index 1f154f92f4c2..7d28e3aa406c 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -523,6 +523,24 @@ out:
}
CONFIGFS_ATTR(nullb_device_, badblocks);
+static ssize_t nullb_device_zone_readonly_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nullb_device *dev = to_nullb_device(item);
+
+ return zone_cond_store(dev, page, count, BLK_ZONE_COND_READONLY);
+}
+CONFIGFS_ATTR_WO(nullb_device_, zone_readonly);
+
+static ssize_t nullb_device_zone_offline_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nullb_device *dev = to_nullb_device(item);
+
+ return zone_cond_store(dev, page, count, BLK_ZONE_COND_OFFLINE);
+}
+CONFIGFS_ATTR_WO(nullb_device_, zone_offline);
+
static struct configfs_attribute *nullb_device_attrs[] = {
&nullb_device_attr_size,
&nullb_device_attr_completion_nsec,
@@ -549,6 +567,8 @@ static struct configfs_attribute *nullb_device_attrs[] = {
&nullb_device_attr_zone_nr_conv,
&nullb_device_attr_zone_max_open,
&nullb_device_attr_zone_max_active,
+ &nullb_device_attr_zone_readonly,
+ &nullb_device_attr_zone_offline,
&nullb_device_attr_virt_boundary,
&nullb_device_attr_no_sched,
&nullb_device_attr_shared_tag_bitmap,
@@ -614,7 +634,7 @@ static ssize_t memb_group_features_show(struct config_item *item, char *page)
"poll_queues,power,queue_mode,shared_tag_bitmap,size,"
"submit_queues,use_per_node_hctx,virt_boundary,zoned,"
"zone_capacity,zone_max_active,zone_max_open,"
- "zone_nr_conv,zone_size\n");
+ "zone_nr_conv,zone_offline,zone_readonly,zone_size\n");
}
CONFIGFS_ATTR_RO(memb_group_, features);
diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
index 94ff68052b1e..eb5972c50be8 100644
--- a/drivers/block/null_blk/null_blk.h
+++ b/drivers/block/null_blk/null_blk.h
@@ -151,6 +151,8 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
sector_t sector, sector_t nr_sectors);
size_t null_zone_valid_read_len(struct nullb *nullb,
sector_t sector, unsigned int len);
+ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
+ size_t count, enum blk_zone_cond cond);
#else
static inline int null_init_zoned_dev(struct nullb_device *dev,
struct request_queue *q)
@@ -174,6 +176,12 @@ static inline size_t null_zone_valid_read_len(struct nullb *nullb,
{
return len;
}
+static inline ssize_t zone_cond_store(struct nullb_device *dev,
+ const char *page, size_t count,
+ enum blk_zone_cond cond)
+{
+ return -EOPNOTSUPP;
+}
#define null_report_zones NULL
#endif /* CONFIG_BLK_DEV_ZONED */
#endif /* __NULL_BLK_H */
diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
index 55a69e48ef8b..635ce0648133 100644
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -384,8 +384,10 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
null_lock_zone(dev, zone);
- if (zone->cond == BLK_ZONE_COND_FULL) {
- /* Cannot write to a full zone */
+ if (zone->cond == BLK_ZONE_COND_FULL ||
+ zone->cond == BLK_ZONE_COND_READONLY ||
+ zone->cond == BLK_ZONE_COND_OFFLINE) {
+ /* Cannot write to the zone */
ret = BLK_STS_IOERR;
goto unlock;
}
@@ -613,7 +615,9 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
for (i = dev->zone_nr_conv; i < dev->nr_zones; i++) {
zone = &dev->zones[i];
null_lock_zone(dev, zone);
- if (zone->cond != BLK_ZONE_COND_EMPTY) {
+ if (zone->cond != BLK_ZONE_COND_EMPTY &&
+ zone->cond != BLK_ZONE_COND_READONLY &&
+ zone->cond != BLK_ZONE_COND_OFFLINE) {
null_reset_zone(dev, zone);
trace_nullb_zone_op(cmd, i, zone->cond);
}
@@ -627,6 +631,12 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
null_lock_zone(dev, zone);
+ if (zone->cond == BLK_ZONE_COND_READONLY ||
+ zone->cond == BLK_ZONE_COND_OFFLINE) {
+ ret = BLK_STS_IOERR;
+ goto unlock;
+ }
+
switch (op) {
case REQ_OP_ZONE_RESET:
ret = null_reset_zone(dev, zone);
@@ -648,6 +658,7 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
if (ret == BLK_STS_OK)
trace_nullb_zone_op(cmd, zone_no, zone->cond);
+unlock:
null_unlock_zone(dev, zone);
return ret;
@@ -674,6 +685,8 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
default:
dev = cmd->nq->dev;
zone = &dev->zones[null_zone_no(dev, sector)];
+ if (zone->cond == BLK_ZONE_COND_OFFLINE)
+ return BLK_STS_IOERR;
null_lock_zone(dev, zone);
sts = null_process_cmd(cmd, op, sector, nr_sectors);
@@ -681,3 +694,79 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
return sts;
}
}
+
+/*
+ * Set a zone in the read-only or offline condition.
+ */
+static void null_set_zone_cond(struct nullb_device *dev,
+ struct nullb_zone *zone, enum blk_zone_cond cond)
+{
+ if (WARN_ON_ONCE(cond != BLK_ZONE_COND_READONLY &&
+ cond != BLK_ZONE_COND_OFFLINE))
+ return;
+
+ null_lock_zone(dev, zone);
+
+ /*
+ * If the read-only condition is requested again to zones already in
+ * read-only condition, restore back normal empty condition. Do the same
+ * if the offline condition is requested for offline zones. Otherwise,
+ * set the specified zone condition to the zones. Finish the zones
+ * beforehand to free up zone resources.
+ */
+ if (zone->cond == cond) {
+ zone->cond = BLK_ZONE_COND_EMPTY;
+ zone->wp = zone->start;
+ if (dev->memory_backed)
+ null_handle_discard(dev, zone->start, zone->len);
+ } else {
+ if (zone->cond != BLK_ZONE_COND_READONLY &&
+ zone->cond != BLK_ZONE_COND_OFFLINE)
+ null_finish_zone(dev, zone);
+ zone->cond = cond;
+ zone->wp = (sector_t)-1;
+ }
+
+ null_unlock_zone(dev, zone);
+}
+
+/*
+ * Identify a zone from the sector written to configfs file. Then set zone
+ * condition to the zone.
+ */
+ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
+ size_t count, enum blk_zone_cond cond)
+{
+ unsigned long long sector;
+ unsigned int zone_no;
+ int ret;
+
+ if (!dev->zoned) {
+ pr_err("null_blk device is not zoned\n");
+ return -EINVAL;
+ }
+
+ if (!dev->zones) {
+ pr_err("null_blk device is not yet powered\n");
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(page, 0, &sector);
+ if (ret < 0)
+ return ret;
+
+ zone_no = null_zone_no(dev, sector);
+ if (zone_no >= dev->nr_zones) {
+ pr_err("Sector out of range\n");
+ return -EINVAL;
+ }
+
+ if (dev->zones[zone_no].type == BLK_ZONE_TYPE_CONVENTIONAL) {
+ pr_err("Can not change condition of conventional zones\n");
+ return -EINVAL;
+ }
+
+ null_set_zone_cond(dev, &dev->zones[zone_no], cond);
+
+ return count;
+}
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
deleted file mode 100644
index 4cea3b08087e..000000000000
--- a/drivers/block/pktcdvd.c
+++ /dev/null
@@ -1,2944 +0,0 @@
-/*
- * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
- * Copyright (C) 2006 Thomas Maier <balagi@justmail.de>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and
- * DVD-RAM devices.
- *
- * Theory of operation:
- *
- * At the lowest level, there is the standard driver for the CD/DVD device,
- * such as drivers/scsi/sr.c. This driver can handle read and write requests,
- * but it doesn't know anything about the special restrictions that apply to
- * packet writing. One restriction is that write requests must be aligned to
- * packet boundaries on the physical media, and the size of a write request
- * must be equal to the packet size. Another restriction is that a
- * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read
- * command, if the previous command was a write.
- *
- * The purpose of the packet writing driver is to hide these restrictions from
- * higher layers, such as file systems, and present a block device that can be
- * randomly read and written using 2kB-sized blocks.
- *
- * The lowest layer in the packet writing driver is the packet I/O scheduler.
- * Its data is defined by the struct packet_iosched and includes two bio
- * queues with pending read and write requests. These queues are processed
- * by the pkt_iosched_process_queue() function. The write requests in this
- * queue are already properly aligned and sized. This layer is responsible for
- * issuing the flush cache commands and scheduling the I/O in a good order.
- *
- * The next layer transforms unaligned write requests to aligned writes. This
- * transformation requires reading missing pieces of data from the underlying
- * block device, assembling the pieces to full packets and queuing them to the
- * packet I/O scheduler.
- *
- * At the top layer there is a custom ->submit_bio function that forwards
- * read requests directly to the iosched queue and puts write requests in the
- * unaligned write queue. A kernel thread performs the necessary read
- * gathering to convert the unaligned writes to aligned writes and then feeds
- * them to the packet I/O scheduler.
- *
- *************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/pktcdvd.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/kthread.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/file.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/miscdevice.h>
-#include <linux/freezer.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/backing-dev.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_ioctl.h>
-#include <scsi/scsi.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/nospec.h>
-#include <linux/uaccess.h>
-
-#define DRIVER_NAME "pktcdvd"
-
-#define pkt_err(pd, fmt, ...) \
- pr_err("%s: " fmt, pd->name, ##__VA_ARGS__)
-#define pkt_notice(pd, fmt, ...) \
- pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__)
-#define pkt_info(pd, fmt, ...) \
- pr_info("%s: " fmt, pd->name, ##__VA_ARGS__)
-
-#define pkt_dbg(level, pd, fmt, ...) \
-do { \
- if (level == 2 && PACKET_DEBUG >= 2) \
- pr_notice("%s: %s():" fmt, \
- pd->name, __func__, ##__VA_ARGS__); \
- else if (level == 1 && PACKET_DEBUG >= 1) \
- pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__); \
-} while (0)
-
-#define MAX_SPEED 0xffff
-
-static DEFINE_MUTEX(pktcdvd_mutex);
-static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
-static struct proc_dir_entry *pkt_proc;
-static int pktdev_major;
-static int write_congestion_on = PKT_WRITE_CONGESTION_ON;
-static int write_congestion_off = PKT_WRITE_CONGESTION_OFF;
-static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
-static mempool_t psd_pool;
-static struct bio_set pkt_bio_set;
-
-static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
-static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */
-
-/* forward declaration */
-static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
-static int pkt_remove_dev(dev_t pkt_dev);
-static int pkt_seq_show(struct seq_file *m, void *p);
-
-static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd)
-{
- return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1);
-}
-
-/**********************************************************
- * sysfs interface for pktcdvd
- * by (C) 2006 Thomas Maier <balagi@justmail.de>
-
- /sys/class/pktcdvd/pktcdvd[0-7]/
- stat/reset
- stat/packets_started
- stat/packets_finished
- stat/kb_written
- stat/kb_read
- stat/kb_read_gather
- write_queue/size
- write_queue/congestion_off
- write_queue/congestion_on
- **********************************************************/
-
-static ssize_t packets_started_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%lu\n", pd->stats.pkt_started);
-}
-static DEVICE_ATTR_RO(packets_started);
-
-static ssize_t packets_finished_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%lu\n", pd->stats.pkt_ended);
-}
-static DEVICE_ATTR_RO(packets_finished);
-
-static ssize_t kb_written_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%lu\n", pd->stats.secs_w >> 1);
-}
-static DEVICE_ATTR_RO(kb_written);
-
-static ssize_t kb_read_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%lu\n", pd->stats.secs_r >> 1);
-}
-static DEVICE_ATTR_RO(kb_read);
-
-static ssize_t kb_read_gather_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%lu\n", pd->stats.secs_rg >> 1);
-}
-static DEVICE_ATTR_RO(kb_read_gather);
-
-static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
-
- if (len > 0) {
- pd->stats.pkt_started = 0;
- pd->stats.pkt_ended = 0;
- pd->stats.secs_w = 0;
- pd->stats.secs_rg = 0;
- pd->stats.secs_r = 0;
- }
- return len;
-}
-static DEVICE_ATTR_WO(reset);
-
-static struct attribute *pkt_stat_attrs[] = {
- &dev_attr_packets_finished.attr,
- &dev_attr_packets_started.attr,
- &dev_attr_kb_read.attr,
- &dev_attr_kb_written.attr,
- &dev_attr_kb_read_gather.attr,
- &dev_attr_reset.attr,
- NULL,
-};
-
-static const struct attribute_group pkt_stat_group = {
- .name = "stat",
- .attrs = pkt_stat_attrs,
-};
-
-static ssize_t size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
- int n;
-
- spin_lock(&pd->lock);
- n = sysfs_emit(buf, "%d\n", pd->bio_queue_size);
- spin_unlock(&pd->lock);
- return n;
-}
-static DEVICE_ATTR_RO(size);
-
-static void init_write_congestion_marks(int* lo, int* hi)
-{
- if (*hi > 0) {
- *hi = max(*hi, 500);
- *hi = min(*hi, 1000000);
- if (*lo <= 0)
- *lo = *hi - 100;
- else {
- *lo = min(*lo, *hi - 100);
- *lo = max(*lo, 100);
- }
- } else {
- *hi = -1;
- *lo = -1;
- }
-}
-
-static ssize_t congestion_off_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
- int n;
-
- spin_lock(&pd->lock);
- n = sysfs_emit(buf, "%d\n", pd->write_congestion_off);
- spin_unlock(&pd->lock);
- return n;
-}
-
-static ssize_t congestion_off_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
- int val;
-
- if (sscanf(buf, "%d", &val) == 1) {
- spin_lock(&pd->lock);
- pd->write_congestion_off = val;
- init_write_congestion_marks(&pd->write_congestion_off,
- &pd->write_congestion_on);
- spin_unlock(&pd->lock);
- }
- return len;
-}
-static DEVICE_ATTR_RW(congestion_off);
-
-static ssize_t congestion_on_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
- int n;
-
- spin_lock(&pd->lock);
- n = sysfs_emit(buf, "%d\n", pd->write_congestion_on);
- spin_unlock(&pd->lock);
- return n;
-}
-
-static ssize_t congestion_on_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct pktcdvd_device *pd = dev_get_drvdata(dev);
- int val;
-
- if (sscanf(buf, "%d", &val) == 1) {
- spin_lock(&pd->lock);
- pd->write_congestion_on = val;
- init_write_congestion_marks(&pd->write_congestion_off,
- &pd->write_congestion_on);
- spin_unlock(&pd->lock);
- }
- return len;
-}
-static DEVICE_ATTR_RW(congestion_on);
-
-static struct attribute *pkt_wq_attrs[] = {
- &dev_attr_congestion_on.attr,
- &dev_attr_congestion_off.attr,
- &dev_attr_size.attr,
- NULL,
-};
-
-static const struct attribute_group pkt_wq_group = {
- .name = "write_queue",
- .attrs = pkt_wq_attrs,
-};
-
-static const struct attribute_group *pkt_groups[] = {
- &pkt_stat_group,
- &pkt_wq_group,
- NULL,
-};
-
-static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
-{
- if (class_pktcdvd) {
- pd->dev = device_create_with_groups(class_pktcdvd, NULL,
- MKDEV(0, 0), pd, pkt_groups,
- "%s", pd->name);
- if (IS_ERR(pd->dev))
- pd->dev = NULL;
- }
-}
-
-static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
-{
- if (class_pktcdvd)
- device_unregister(pd->dev);
-}
-
-
-/********************************************************************
- /sys/class/pktcdvd/
- add map block device
- remove unmap packet dev
- device_map show mappings
- *******************************************************************/
-
-static void class_pktcdvd_release(struct class *cls)
-{
- kfree(cls);
-}
-
-static ssize_t device_map_show(struct class *c, struct class_attribute *attr,
- char *data)
-{
- int n = 0;
- int idx;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- for (idx = 0; idx < MAX_WRITERS; idx++) {
- struct pktcdvd_device *pd = pkt_devs[idx];
- if (!pd)
- continue;
- n += sprintf(data+n, "%s %u:%u %u:%u\n",
- pd->name,
- MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev),
- MAJOR(pd->bdev->bd_dev),
- MINOR(pd->bdev->bd_dev));
- }
- mutex_unlock(&ctl_mutex);
- return n;
-}
-static CLASS_ATTR_RO(device_map);
-
-static ssize_t add_store(struct class *c, struct class_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned int major, minor;
-
- if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
- /* pkt_setup_dev() expects caller to hold reference to self */
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
- pkt_setup_dev(MKDEV(major, minor), NULL);
-
- module_put(THIS_MODULE);
-
- return count;
- }
-
- return -EINVAL;
-}
-static CLASS_ATTR_WO(add);
-
-static ssize_t remove_store(struct class *c, struct class_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned int major, minor;
- if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
- pkt_remove_dev(MKDEV(major, minor));
- return count;
- }
- return -EINVAL;
-}
-static CLASS_ATTR_WO(remove);
-
-static struct attribute *class_pktcdvd_attrs[] = {
- &class_attr_add.attr,
- &class_attr_remove.attr,
- &class_attr_device_map.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(class_pktcdvd);
-
-static int pkt_sysfs_init(void)
-{
- int ret = 0;
-
- /*
- * create control files in sysfs
- * /sys/class/pktcdvd/...
- */
- class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL);
- if (!class_pktcdvd)
- return -ENOMEM;
- class_pktcdvd->name = DRIVER_NAME;
- class_pktcdvd->owner = THIS_MODULE;
- class_pktcdvd->class_release = class_pktcdvd_release;
- class_pktcdvd->class_groups = class_pktcdvd_groups;
- ret = class_register(class_pktcdvd);
- if (ret) {
- kfree(class_pktcdvd);
- class_pktcdvd = NULL;
- pr_err("failed to create class pktcdvd\n");
- return ret;
- }
- return 0;
-}
-
-static void pkt_sysfs_cleanup(void)
-{
- if (class_pktcdvd)
- class_destroy(class_pktcdvd);
- class_pktcdvd = NULL;
-}
-
-/********************************************************************
- entries in debugfs
-
- /sys/kernel/debug/pktcdvd[0-7]/
- info
-
- *******************************************************************/
-
-static int pkt_debugfs_seq_show(struct seq_file *m, void *p)
-{
- return pkt_seq_show(m, p);
-}
-
-static int pkt_debugfs_fops_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pkt_debugfs_seq_show, inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
- .open = pkt_debugfs_fops_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static void pkt_debugfs_dev_new(struct pktcdvd_device *pd)
-{
- if (!pkt_debugfs_root)
- return;
- pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root);
- if (!pd->dfs_d_root)
- return;
-
- pd->dfs_f_info = debugfs_create_file("info", 0444,
- pd->dfs_d_root, pd, &debug_fops);
-}
-
-static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd)
-{
- if (!pkt_debugfs_root)
- return;
- debugfs_remove(pd->dfs_f_info);
- debugfs_remove(pd->dfs_d_root);
- pd->dfs_f_info = NULL;
- pd->dfs_d_root = NULL;
-}
-
-static void pkt_debugfs_init(void)
-{
- pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL);
-}
-
-static void pkt_debugfs_cleanup(void)
-{
- debugfs_remove(pkt_debugfs_root);
- pkt_debugfs_root = NULL;
-}
-
-/* ----------------------------------------------------------*/
-
-
-static void pkt_bio_finished(struct pktcdvd_device *pd)
-{
- BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
- if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
- pkt_dbg(2, pd, "queue empty\n");
- atomic_set(&pd->iosched.attention, 1);
- wake_up(&pd->wqueue);
- }
-}
-
-/*
- * Allocate a packet_data struct
- */
-static struct packet_data *pkt_alloc_packet_data(int frames)
-{
- int i;
- struct packet_data *pkt;
-
- pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
- if (!pkt)
- goto no_pkt;
-
- pkt->frames = frames;
- pkt->w_bio = bio_kmalloc(frames, GFP_KERNEL);
- if (!pkt->w_bio)
- goto no_bio;
-
- for (i = 0; i < frames / FRAMES_PER_PAGE; i++) {
- pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO);
- if (!pkt->pages[i])
- goto no_page;
- }
-
- spin_lock_init(&pkt->lock);
- bio_list_init(&pkt->orig_bios);
-
- for (i = 0; i < frames; i++) {
- pkt->r_bios[i] = bio_kmalloc(1, GFP_KERNEL);
- if (!pkt->r_bios[i])
- goto no_rd_bio;
- }
-
- return pkt;
-
-no_rd_bio:
- for (i = 0; i < frames; i++)
- kfree(pkt->r_bios[i]);
-no_page:
- for (i = 0; i < frames / FRAMES_PER_PAGE; i++)
- if (pkt->pages[i])
- __free_page(pkt->pages[i]);
- kfree(pkt->w_bio);
-no_bio:
- kfree(pkt);
-no_pkt:
- return NULL;
-}
-
-/*
- * Free a packet_data struct
- */
-static void pkt_free_packet_data(struct packet_data *pkt)
-{
- int i;
-
- for (i = 0; i < pkt->frames; i++)
- kfree(pkt->r_bios[i]);
- for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++)
- __free_page(pkt->pages[i]);
- kfree(pkt->w_bio);
- kfree(pkt);
-}
-
-static void pkt_shrink_pktlist(struct pktcdvd_device *pd)
-{
- struct packet_data *pkt, *next;
-
- BUG_ON(!list_empty(&pd->cdrw.pkt_active_list));
-
- list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) {
- pkt_free_packet_data(pkt);
- }
- INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
-}
-
-static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)
-{
- struct packet_data *pkt;
-
- BUG_ON(!list_empty(&pd->cdrw.pkt_free_list));
-
- while (nr_packets > 0) {
- pkt = pkt_alloc_packet_data(pd->settings.size >> 2);
- if (!pkt) {
- pkt_shrink_pktlist(pd);
- return 0;
- }
- pkt->id = nr_packets;
- pkt->pd = pd;
- list_add(&pkt->list, &pd->cdrw.pkt_free_list);
- nr_packets--;
- }
- return 1;
-}
-
-static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
-{
- struct rb_node *n = rb_next(&node->rb_node);
- if (!n)
- return NULL;
- return rb_entry(n, struct pkt_rb_node, rb_node);
-}
-
-static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
-{
- rb_erase(&node->rb_node, &pd->bio_queue);
- mempool_free(node, &pd->rb_pool);
- pd->bio_queue_size--;
- BUG_ON(pd->bio_queue_size < 0);
-}
-
-/*
- * Find the first node in the pd->bio_queue rb tree with a starting sector >= s.
- */
-static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s)
-{
- struct rb_node *n = pd->bio_queue.rb_node;
- struct rb_node *next;
- struct pkt_rb_node *tmp;
-
- if (!n) {
- BUG_ON(pd->bio_queue_size > 0);
- return NULL;
- }
-
- for (;;) {
- tmp = rb_entry(n, struct pkt_rb_node, rb_node);
- if (s <= tmp->bio->bi_iter.bi_sector)
- next = n->rb_left;
- else
- next = n->rb_right;
- if (!next)
- break;
- n = next;
- }
-
- if (s > tmp->bio->bi_iter.bi_sector) {
- tmp = pkt_rbtree_next(tmp);
- if (!tmp)
- return NULL;
- }
- BUG_ON(s > tmp->bio->bi_iter.bi_sector);
- return tmp;
-}
-
-/*
- * Insert a node into the pd->bio_queue rb tree.
- */
-static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *node)
-{
- struct rb_node **p = &pd->bio_queue.rb_node;
- struct rb_node *parent = NULL;
- sector_t s = node->bio->bi_iter.bi_sector;
- struct pkt_rb_node *tmp;
-
- while (*p) {
- parent = *p;
- tmp = rb_entry(parent, struct pkt_rb_node, rb_node);
- if (s < tmp->bio->bi_iter.bi_sector)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
- rb_link_node(&node->rb_node, parent, p);
- rb_insert_color(&node->rb_node, &pd->bio_queue);
- pd->bio_queue_size++;
-}
-
-/*
- * Send a packet_command to the underlying block device and
- * wait for completion.
- */
-static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
-{
- struct request_queue *q = bdev_get_queue(pd->bdev);
- struct scsi_cmnd *scmd;
- struct request *rq;
- int ret = 0;
-
- rq = scsi_alloc_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
- REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
- scmd = blk_mq_rq_to_pdu(rq);
-
- if (cgc->buflen) {
- ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen,
- GFP_NOIO);
- if (ret)
- goto out;
- }
-
- scmd->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
- memcpy(scmd->cmnd, cgc->cmd, CDROM_PACKET_SIZE);
-
- rq->timeout = 60*HZ;
- if (cgc->quiet)
- rq->rq_flags |= RQF_QUIET;
-
- blk_execute_rq(rq, false);
- if (scmd->result)
- ret = -EIO;
-out:
- blk_mq_free_request(rq);
- return ret;
-}
-
-static const char *sense_key_string(__u8 index)
-{
- static const char * const info[] = {
- "No sense", "Recovered error", "Not ready",
- "Medium error", "Hardware error", "Illegal request",
- "Unit attention", "Data protect", "Blank check",
- };
-
- return index < ARRAY_SIZE(info) ? info[index] : "INVALID";
-}
-
-/*
- * A generic sense dump / resolve mechanism should be implemented across
- * all ATAPI + SCSI devices.
- */
-static void pkt_dump_sense(struct pktcdvd_device *pd,
- struct packet_command *cgc)
-{
- struct scsi_sense_hdr *sshdr = cgc->sshdr;
-
- if (sshdr)
- pkt_err(pd, "%*ph - sense %02x.%02x.%02x (%s)\n",
- CDROM_PACKET_SIZE, cgc->cmd,
- sshdr->sense_key, sshdr->asc, sshdr->ascq,
- sense_key_string(sshdr->sense_key));
- else
- pkt_err(pd, "%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd);
-}
-
-/*
- * flush the drive cache to media
- */
-static int pkt_flush_cache(struct pktcdvd_device *pd)
-{
- struct packet_command cgc;
-
- init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
- cgc.cmd[0] = GPCMD_FLUSH_CACHE;
- cgc.quiet = 1;
-
- /*
- * the IMMED bit -- we default to not setting it, although that
- * would allow a much faster close, this is safer
- */
-#if 0
- cgc.cmd[1] = 1 << 1;
-#endif
- return pkt_generic_packet(pd, &cgc);
-}
-
-/*
- * speed is given as the normal factor, e.g. 4 for 4x
- */
-static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
- unsigned write_speed, unsigned read_speed)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- int ret;
-
- init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
- cgc.sshdr = &sshdr;
- cgc.cmd[0] = GPCMD_SET_SPEED;
- cgc.cmd[2] = (read_speed >> 8) & 0xff;
- cgc.cmd[3] = read_speed & 0xff;
- cgc.cmd[4] = (write_speed >> 8) & 0xff;
- cgc.cmd[5] = write_speed & 0xff;
-
- ret = pkt_generic_packet(pd, &cgc);
- if (ret)
- pkt_dump_sense(pd, &cgc);
-
- return ret;
-}
-
-/*
- * Queue a bio for processing by the low-level CD device. Must be called
- * from process context.
- */
-static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
-{
- spin_lock(&pd->iosched.lock);
- if (bio_data_dir(bio) == READ)
- bio_list_add(&pd->iosched.read_queue, bio);
- else
- bio_list_add(&pd->iosched.write_queue, bio);
- spin_unlock(&pd->iosched.lock);
-
- atomic_set(&pd->iosched.attention, 1);
- wake_up(&pd->wqueue);
-}
-
-/*
- * Process the queued read/write requests. This function handles special
- * requirements for CDRW drives:
- * - A cache flush command must be inserted before a read request if the
- * previous request was a write.
- * - Switching between reading and writing is slow, so don't do it more often
- * than necessary.
- * - Optimize for throughput at the expense of latency. This means that streaming
- * writes will never be interrupted by a read, but if the drive has to seek
- * before the next write, switch to reading instead if there are any pending
- * read requests.
- * - Set the read speed according to current usage pattern. When only reading
- * from the device, it's best to use the highest possible read speed, but
- * when switching often between reading and writing, it's better to have the
- * same read and write speeds.
- */
-static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
-{
-
- if (atomic_read(&pd->iosched.attention) == 0)
- return;
- atomic_set(&pd->iosched.attention, 0);
-
- for (;;) {
- struct bio *bio;
- int reads_queued, writes_queued;
-
- spin_lock(&pd->iosched.lock);
- reads_queued = !bio_list_empty(&pd->iosched.read_queue);
- writes_queued = !bio_list_empty(&pd->iosched.write_queue);
- spin_unlock(&pd->iosched.lock);
-
- if (!reads_queued && !writes_queued)
- break;
-
- if (pd->iosched.writing) {
- int need_write_seek = 1;
- spin_lock(&pd->iosched.lock);
- bio = bio_list_peek(&pd->iosched.write_queue);
- spin_unlock(&pd->iosched.lock);
- if (bio && (bio->bi_iter.bi_sector ==
- pd->iosched.last_write))
- need_write_seek = 0;
- if (need_write_seek && reads_queued) {
- if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- pkt_dbg(2, pd, "write, waiting\n");
- break;
- }
- pkt_flush_cache(pd);
- pd->iosched.writing = 0;
- }
- } else {
- if (!reads_queued && writes_queued) {
- if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- pkt_dbg(2, pd, "read, waiting\n");
- break;
- }
- pd->iosched.writing = 1;
- }
- }
-
- spin_lock(&pd->iosched.lock);
- if (pd->iosched.writing)
- bio = bio_list_pop(&pd->iosched.write_queue);
- else
- bio = bio_list_pop(&pd->iosched.read_queue);
- spin_unlock(&pd->iosched.lock);
-
- if (!bio)
- continue;
-
- if (bio_data_dir(bio) == READ)
- pd->iosched.successive_reads +=
- bio->bi_iter.bi_size >> 10;
- else {
- pd->iosched.successive_reads = 0;
- pd->iosched.last_write = bio_end_sector(bio);
- }
- if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) {
- if (pd->read_speed == pd->write_speed) {
- pd->read_speed = MAX_SPEED;
- pkt_set_speed(pd, pd->write_speed, pd->read_speed);
- }
- } else {
- if (pd->read_speed != pd->write_speed) {
- pd->read_speed = pd->write_speed;
- pkt_set_speed(pd, pd->write_speed, pd->read_speed);
- }
- }
-
- atomic_inc(&pd->cdrw.pending_bios);
- submit_bio_noacct(bio);
- }
-}
-
-/*
- * Special care is needed if the underlying block device has a small
- * max_phys_segments value.
- */
-static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
-{
- if ((pd->settings.size << 9) / CD_FRAMESIZE
- <= queue_max_segments(q)) {
- /*
- * The cdrom device can handle one segment/frame
- */
- clear_bit(PACKET_MERGE_SEGS, &pd->flags);
- return 0;
- } else if ((pd->settings.size << 9) / PAGE_SIZE
- <= queue_max_segments(q)) {
- /*
- * We can handle this case at the expense of some extra memory
- * copies during write operations
- */
- set_bit(PACKET_MERGE_SEGS, &pd->flags);
- return 0;
- } else {
- pkt_err(pd, "cdrom max_phys_segments too small\n");
- return -EIO;
- }
-}
-
-static void pkt_end_io_read(struct bio *bio)
-{
- struct packet_data *pkt = bio->bi_private;
- struct pktcdvd_device *pd = pkt->pd;
- BUG_ON(!pd);
-
- pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n",
- bio, (unsigned long long)pkt->sector,
- (unsigned long long)bio->bi_iter.bi_sector, bio->bi_status);
-
- if (bio->bi_status)
- atomic_inc(&pkt->io_errors);
- bio_uninit(bio);
- if (atomic_dec_and_test(&pkt->io_wait)) {
- atomic_inc(&pkt->run_sm);
- wake_up(&pd->wqueue);
- }
- pkt_bio_finished(pd);
-}
-
-static void pkt_end_io_packet_write(struct bio *bio)
-{
- struct packet_data *pkt = bio->bi_private;
- struct pktcdvd_device *pd = pkt->pd;
- BUG_ON(!pd);
-
- pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, bio->bi_status);
-
- pd->stats.pkt_ended++;
-
- bio_uninit(bio);
- pkt_bio_finished(pd);
- atomic_dec(&pkt->io_wait);
- atomic_inc(&pkt->run_sm);
- wake_up(&pd->wqueue);
-}
-
-/*
- * Schedule reads for the holes in a packet
- */
-static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
-{
- int frames_read = 0;
- struct bio *bio;
- int f;
- char written[PACKET_MAX_SIZE];
-
- BUG_ON(bio_list_empty(&pkt->orig_bios));
-
- atomic_set(&pkt->io_wait, 0);
- atomic_set(&pkt->io_errors, 0);
-
- /*
- * Figure out which frames we need to read before we can write.
- */
- memset(written, 0, sizeof(written));
- spin_lock(&pkt->lock);
- bio_list_for_each(bio, &pkt->orig_bios) {
- int first_frame = (bio->bi_iter.bi_sector - pkt->sector) /
- (CD_FRAMESIZE >> 9);
- int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE;
- pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
- BUG_ON(first_frame < 0);
- BUG_ON(first_frame + num_frames > pkt->frames);
- for (f = first_frame; f < first_frame + num_frames; f++)
- written[f] = 1;
- }
- spin_unlock(&pkt->lock);
-
- if (pkt->cache_valid) {
- pkt_dbg(2, pd, "zone %llx cached\n",
- (unsigned long long)pkt->sector);
- goto out_account;
- }
-
- /*
- * Schedule reads for missing parts of the packet.
- */
- for (f = 0; f < pkt->frames; f++) {
- int p, offset;
-
- if (written[f])
- continue;
-
- bio = pkt->r_bios[f];
- bio_init(bio, pd->bdev, bio->bi_inline_vecs, 1, REQ_OP_READ);
- bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
- bio->bi_end_io = pkt_end_io_read;
- bio->bi_private = pkt;
-
- p = (f * CD_FRAMESIZE) / PAGE_SIZE;
- offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
- pkt_dbg(2, pd, "Adding frame %d, page:%p offs:%d\n",
- f, pkt->pages[p], offset);
- if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset))
- BUG();
-
- atomic_inc(&pkt->io_wait);
- pkt_queue_bio(pd, bio);
- frames_read++;
- }
-
-out_account:
- pkt_dbg(2, pd, "need %d frames for zone %llx\n",
- frames_read, (unsigned long long)pkt->sector);
- pd->stats.pkt_started++;
- pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
-}
-
-/*
- * Find a packet matching zone, or the least recently used packet if
- * there is no match.
- */
-static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone)
-{
- struct packet_data *pkt;
-
- list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) {
- if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) {
- list_del_init(&pkt->list);
- if (pkt->sector != zone)
- pkt->cache_valid = 0;
- return pkt;
- }
- }
- BUG();
- return NULL;
-}
-
-static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
-{
- if (pkt->cache_valid) {
- list_add(&pkt->list, &pd->cdrw.pkt_free_list);
- } else {
- list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list);
- }
-}
-
-static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state)
-{
-#if PACKET_DEBUG > 1
- static const char *state_name[] = {
- "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED"
- };
- enum packet_data_state old_state = pkt->state;
- pkt_dbg(2, pd, "pkt %2d : s=%6llx %s -> %s\n",
- pkt->id, (unsigned long long)pkt->sector,
- state_name[old_state], state_name[state]);
-#endif
- pkt->state = state;
-}
-
-/*
- * Scan the work queue to see if we can start a new packet.
- * returns non-zero if any work was done.
- */
-static int pkt_handle_queue(struct pktcdvd_device *pd)
-{
- struct packet_data *pkt, *p;
- struct bio *bio = NULL;
- sector_t zone = 0; /* Suppress gcc warning */
- struct pkt_rb_node *node, *first_node;
- struct rb_node *n;
-
- atomic_set(&pd->scan_queue, 0);
-
- if (list_empty(&pd->cdrw.pkt_free_list)) {
- pkt_dbg(2, pd, "no pkt\n");
- return 0;
- }
-
- /*
- * Try to find a zone we are not already working on.
- */
- spin_lock(&pd->lock);
- first_node = pkt_rbtree_find(pd, pd->current_sector);
- if (!first_node) {
- n = rb_first(&pd->bio_queue);
- if (n)
- first_node = rb_entry(n, struct pkt_rb_node, rb_node);
- }
- node = first_node;
- while (node) {
- bio = node->bio;
- zone = get_zone(bio->bi_iter.bi_sector, pd);
- list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
- if (p->sector == zone) {
- bio = NULL;
- goto try_next_bio;
- }
- }
- break;
-try_next_bio:
- node = pkt_rbtree_next(node);
- if (!node) {
- n = rb_first(&pd->bio_queue);
- if (n)
- node = rb_entry(n, struct pkt_rb_node, rb_node);
- }
- if (node == first_node)
- node = NULL;
- }
- spin_unlock(&pd->lock);
- if (!bio) {
- pkt_dbg(2, pd, "no bio\n");
- return 0;
- }
-
- pkt = pkt_get_packet_data(pd, zone);
-
- pd->current_sector = zone + pd->settings.size;
- pkt->sector = zone;
- BUG_ON(pkt->frames != pd->settings.size >> 2);
- pkt->write_size = 0;
-
- /*
- * Scan work queue for bios in the same zone and link them
- * to this packet.
- */
- spin_lock(&pd->lock);
- pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone);
- while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
- bio = node->bio;
- pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long)
- get_zone(bio->bi_iter.bi_sector, pd));
- if (get_zone(bio->bi_iter.bi_sector, pd) != zone)
- break;
- pkt_rbtree_erase(pd, node);
- spin_lock(&pkt->lock);
- bio_list_add(&pkt->orig_bios, bio);
- pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE;
- spin_unlock(&pkt->lock);
- }
- /* check write congestion marks, and if bio_queue_size is
- * below, wake up any waiters
- */
- if (pd->congested &&
- pd->bio_queue_size <= pd->write_congestion_off) {
- pd->congested = false;
- wake_up_var(&pd->congested);
- }
- spin_unlock(&pd->lock);
-
- pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
- pkt_set_state(pkt, PACKET_WAITING_STATE);
- atomic_set(&pkt->run_sm, 1);
-
- spin_lock(&pd->cdrw.active_list_lock);
- list_add(&pkt->list, &pd->cdrw.pkt_active_list);
- spin_unlock(&pd->cdrw.active_list_lock);
-
- return 1;
-}
-
-/**
- * bio_list_copy_data - copy contents of data buffers from one chain of bios to
- * another
- * @src: source bio list
- * @dst: destination bio list
- *
- * Stops when it reaches the end of either the @src list or @dst list - that is,
- * copies min(src->bi_size, dst->bi_size) bytes (or the equivalent for lists of
- * bios).
- */
-static void bio_list_copy_data(struct bio *dst, struct bio *src)
-{
- struct bvec_iter src_iter = src->bi_iter;
- struct bvec_iter dst_iter = dst->bi_iter;
-
- while (1) {
- if (!src_iter.bi_size) {
- src = src->bi_next;
- if (!src)
- break;
-
- src_iter = src->bi_iter;
- }
-
- if (!dst_iter.bi_size) {
- dst = dst->bi_next;
- if (!dst)
- break;
-
- dst_iter = dst->bi_iter;
- }
-
- bio_copy_data_iter(dst, &dst_iter, src, &src_iter);
- }
-}
-
-/*
- * Assemble a bio to write one packet and queue the bio for processing
- * by the underlying block device.
- */
-static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
-{
- int f;
-
- bio_init(pkt->w_bio, pd->bdev, pkt->w_bio->bi_inline_vecs, pkt->frames,
- REQ_OP_WRITE);
- pkt->w_bio->bi_iter.bi_sector = pkt->sector;
- pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
- pkt->w_bio->bi_private = pkt;
-
- /* XXX: locking? */
- for (f = 0; f < pkt->frames; f++) {
- struct page *page = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE];
- unsigned offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
-
- if (!bio_add_page(pkt->w_bio, page, CD_FRAMESIZE, offset))
- BUG();
- }
- pkt_dbg(2, pd, "vcnt=%d\n", pkt->w_bio->bi_vcnt);
-
- /*
- * Fill-in bvec with data from orig_bios.
- */
- spin_lock(&pkt->lock);
- bio_list_copy_data(pkt->w_bio, pkt->orig_bios.head);
-
- pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE);
- spin_unlock(&pkt->lock);
-
- pkt_dbg(2, pd, "Writing %d frames for zone %llx\n",
- pkt->write_size, (unsigned long long)pkt->sector);
-
- if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames))
- pkt->cache_valid = 1;
- else
- pkt->cache_valid = 0;
-
- /* Start the write request */
- atomic_set(&pkt->io_wait, 1);
- pkt_queue_bio(pd, pkt->w_bio);
-}
-
-static void pkt_finish_packet(struct packet_data *pkt, blk_status_t status)
-{
- struct bio *bio;
-
- if (status)
- pkt->cache_valid = 0;
-
- /* Finish all bios corresponding to this packet */
- while ((bio = bio_list_pop(&pkt->orig_bios))) {
- bio->bi_status = status;
- bio_endio(bio);
- }
-}
-
-static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
-{
- pkt_dbg(2, pd, "pkt %d\n", pkt->id);
-
- for (;;) {
- switch (pkt->state) {
- case PACKET_WAITING_STATE:
- if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0))
- return;
-
- pkt->sleep_time = 0;
- pkt_gather_data(pd, pkt);
- pkt_set_state(pkt, PACKET_READ_WAIT_STATE);
- break;
-
- case PACKET_READ_WAIT_STATE:
- if (atomic_read(&pkt->io_wait) > 0)
- return;
-
- if (atomic_read(&pkt->io_errors) > 0) {
- pkt_set_state(pkt, PACKET_RECOVERY_STATE);
- } else {
- pkt_start_write(pd, pkt);
- }
- break;
-
- case PACKET_WRITE_WAIT_STATE:
- if (atomic_read(&pkt->io_wait) > 0)
- return;
-
- if (!pkt->w_bio->bi_status) {
- pkt_set_state(pkt, PACKET_FINISHED_STATE);
- } else {
- pkt_set_state(pkt, PACKET_RECOVERY_STATE);
- }
- break;
-
- case PACKET_RECOVERY_STATE:
- pkt_dbg(2, pd, "No recovery possible\n");
- pkt_set_state(pkt, PACKET_FINISHED_STATE);
- break;
-
- case PACKET_FINISHED_STATE:
- pkt_finish_packet(pkt, pkt->w_bio->bi_status);
- return;
-
- default:
- BUG();
- break;
- }
- }
-}
-
-static void pkt_handle_packets(struct pktcdvd_device *pd)
-{
- struct packet_data *pkt, *next;
-
- /*
- * Run state machine for active packets
- */
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- if (atomic_read(&pkt->run_sm) > 0) {
- atomic_set(&pkt->run_sm, 0);
- pkt_run_state_machine(pd, pkt);
- }
- }
-
- /*
- * Move no longer active packets to the free list
- */
- spin_lock(&pd->cdrw.active_list_lock);
- list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) {
- if (pkt->state == PACKET_FINISHED_STATE) {
- list_del(&pkt->list);
- pkt_put_packet_data(pd, pkt);
- pkt_set_state(pkt, PACKET_IDLE_STATE);
- atomic_set(&pd->scan_queue, 1);
- }
- }
- spin_unlock(&pd->cdrw.active_list_lock);
-}
-
-static void pkt_count_states(struct pktcdvd_device *pd, int *states)
-{
- struct packet_data *pkt;
- int i;
-
- for (i = 0; i < PACKET_NUM_STATES; i++)
- states[i] = 0;
-
- spin_lock(&pd->cdrw.active_list_lock);
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- states[pkt->state]++;
- }
- spin_unlock(&pd->cdrw.active_list_lock);
-}
-
-/*
- * kcdrwd is woken up when writes have been queued for one of our
- * registered devices
- */
-static int kcdrwd(void *foobar)
-{
- struct pktcdvd_device *pd = foobar;
- struct packet_data *pkt;
- long min_sleep_time, residue;
-
- set_user_nice(current, MIN_NICE);
- set_freezable();
-
- for (;;) {
- DECLARE_WAITQUEUE(wait, current);
-
- /*
- * Wait until there is something to do
- */
- add_wait_queue(&pd->wqueue, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* Check if we need to run pkt_handle_queue */
- if (atomic_read(&pd->scan_queue) > 0)
- goto work_to_do;
-
- /* Check if we need to run the state machine for some packet */
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- if (atomic_read(&pkt->run_sm) > 0)
- goto work_to_do;
- }
-
- /* Check if we need to process the iosched queues */
- if (atomic_read(&pd->iosched.attention) != 0)
- goto work_to_do;
-
- /* Otherwise, go to sleep */
- if (PACKET_DEBUG > 1) {
- int states[PACKET_NUM_STATES];
- pkt_count_states(pd, states);
- pkt_dbg(2, pd, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
- states[0], states[1], states[2],
- states[3], states[4], states[5]);
- }
-
- min_sleep_time = MAX_SCHEDULE_TIMEOUT;
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- if (pkt->sleep_time && pkt->sleep_time < min_sleep_time)
- min_sleep_time = pkt->sleep_time;
- }
-
- pkt_dbg(2, pd, "sleeping\n");
- residue = schedule_timeout(min_sleep_time);
- pkt_dbg(2, pd, "wake up\n");
-
- /* make swsusp happy with our thread */
- try_to_freeze();
-
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- if (!pkt->sleep_time)
- continue;
- pkt->sleep_time -= min_sleep_time - residue;
- if (pkt->sleep_time <= 0) {
- pkt->sleep_time = 0;
- atomic_inc(&pkt->run_sm);
- }
- }
-
- if (kthread_should_stop())
- break;
- }
-work_to_do:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&pd->wqueue, &wait);
-
- if (kthread_should_stop())
- break;
-
- /*
- * if pkt_handle_queue returns true, we can queue
- * another request.
- */
- while (pkt_handle_queue(pd))
- ;
-
- /*
- * Handle packet state machine
- */
- pkt_handle_packets(pd);
-
- /*
- * Handle iosched queues
- */
- pkt_iosched_process_queue(pd);
- }
-
- return 0;
-}
-
-static void pkt_print_settings(struct pktcdvd_device *pd)
-{
- pkt_info(pd, "%s packets, %u blocks, Mode-%c disc\n",
- pd->settings.fp ? "Fixed" : "Variable",
- pd->settings.size >> 2,
- pd->settings.block_mode == 8 ? '1' : '2');
-}
-
-static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control)
-{
- memset(cgc->cmd, 0, sizeof(cgc->cmd));
-
- cgc->cmd[0] = GPCMD_MODE_SENSE_10;
- cgc->cmd[2] = page_code | (page_control << 6);
- cgc->cmd[7] = cgc->buflen >> 8;
- cgc->cmd[8] = cgc->buflen & 0xff;
- cgc->data_direction = CGC_DATA_READ;
- return pkt_generic_packet(pd, cgc);
-}
-
-static int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc)
-{
- memset(cgc->cmd, 0, sizeof(cgc->cmd));
- memset(cgc->buffer, 0, 2);
- cgc->cmd[0] = GPCMD_MODE_SELECT_10;
- cgc->cmd[1] = 0x10; /* PF */
- cgc->cmd[7] = cgc->buflen >> 8;
- cgc->cmd[8] = cgc->buflen & 0xff;
- cgc->data_direction = CGC_DATA_WRITE;
- return pkt_generic_packet(pd, cgc);
-}
-
-static int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di)
-{
- struct packet_command cgc;
- int ret;
-
- /* set up command and get the disc info */
- init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
- cgc.cmd[0] = GPCMD_READ_DISC_INFO;
- cgc.cmd[8] = cgc.buflen = 2;
- cgc.quiet = 1;
-
- ret = pkt_generic_packet(pd, &cgc);
- if (ret)
- return ret;
-
- /* not all drives have the same disc_info length, so requeue
- * packet with the length the drive tells us it can supply
- */
- cgc.buflen = be16_to_cpu(di->disc_information_length) +
- sizeof(di->disc_information_length);
-
- if (cgc.buflen > sizeof(disc_information))
- cgc.buflen = sizeof(disc_information);
-
- cgc.cmd[8] = cgc.buflen;
- return pkt_generic_packet(pd, &cgc);
-}
-
-static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti)
-{
- struct packet_command cgc;
- int ret;
-
- init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
- cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
- cgc.cmd[1] = type & 3;
- cgc.cmd[4] = (track & 0xff00) >> 8;
- cgc.cmd[5] = track & 0xff;
- cgc.cmd[8] = 8;
- cgc.quiet = 1;
-
- ret = pkt_generic_packet(pd, &cgc);
- if (ret)
- return ret;
-
- cgc.buflen = be16_to_cpu(ti->track_information_length) +
- sizeof(ti->track_information_length);
-
- if (cgc.buflen > sizeof(track_information))
- cgc.buflen = sizeof(track_information);
-
- cgc.cmd[8] = cgc.buflen;
- return pkt_generic_packet(pd, &cgc);
-}
-
-static noinline_for_stack int pkt_get_last_written(struct pktcdvd_device *pd,
- long *last_written)
-{
- disc_information di;
- track_information ti;
- __u32 last_track;
- int ret;
-
- ret = pkt_get_disc_info(pd, &di);
- if (ret)
- return ret;
-
- last_track = (di.last_track_msb << 8) | di.last_track_lsb;
- ret = pkt_get_track_info(pd, last_track, 1, &ti);
- if (ret)
- return ret;
-
- /* if this track is blank, try the previous. */
- if (ti.blank) {
- last_track--;
- ret = pkt_get_track_info(pd, last_track, 1, &ti);
- if (ret)
- return ret;
- }
-
- /* if last recorded field is valid, return it. */
- if (ti.lra_v) {
- *last_written = be32_to_cpu(ti.last_rec_address);
- } else {
- /* make it up instead */
- *last_written = be32_to_cpu(ti.track_start) +
- be32_to_cpu(ti.track_size);
- if (ti.free_blocks)
- *last_written -= (be32_to_cpu(ti.free_blocks) + 7);
- }
- return 0;
-}
-
-/*
- * write mode select package based on pd->settings
- */
-static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- write_param_page *wp;
- char buffer[128];
- int ret, size;
-
- /* doesn't apply to DVD+RW or DVD-RAM */
- if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12))
- return 0;
-
- memset(buffer, 0, sizeof(buffer));
- init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
- cgc.sshdr = &sshdr;
- ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
-
- size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff));
- pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff);
- if (size > sizeof(buffer))
- size = sizeof(buffer);
-
- /*
- * now get it all
- */
- init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ);
- cgc.sshdr = &sshdr;
- ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
-
- /*
- * write page is offset header + block descriptor length
- */
- wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset];
-
- wp->fp = pd->settings.fp;
- wp->track_mode = pd->settings.track_mode;
- wp->write_type = pd->settings.write_type;
- wp->data_block_type = pd->settings.block_mode;
-
- wp->multi_session = 0;
-
-#ifdef PACKET_USE_LS
- wp->link_size = 7;
- wp->ls_v = 1;
-#endif
-
- if (wp->data_block_type == PACKET_BLOCK_MODE1) {
- wp->session_format = 0;
- wp->subhdr2 = 0x20;
- } else if (wp->data_block_type == PACKET_BLOCK_MODE2) {
- wp->session_format = 0x20;
- wp->subhdr2 = 8;
-#if 0
- wp->mcn[0] = 0x80;
- memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1);
-#endif
- } else {
- /*
- * paranoia
- */
- pkt_err(pd, "write mode wrong %d\n", wp->data_block_type);
- return 1;
- }
- wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
-
- cgc.buflen = cgc.cmd[8] = size;
- ret = pkt_mode_select(pd, &cgc);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
-
- pkt_print_settings(pd);
- return 0;
-}
-
-/*
- * 1 -- we can write to this track, 0 -- we can't
- */
-static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
-{
- switch (pd->mmc3_profile) {
- case 0x1a: /* DVD+RW */
- case 0x12: /* DVD-RAM */
- /* The track is always writable on DVD+RW/DVD-RAM */
- return 1;
- default:
- break;
- }
-
- if (!ti->packet || !ti->fp)
- return 0;
-
- /*
- * "good" settings as per Mt Fuji.
- */
- if (ti->rt == 0 && ti->blank == 0)
- return 1;
-
- if (ti->rt == 0 && ti->blank == 1)
- return 1;
-
- if (ti->rt == 1 && ti->blank == 0)
- return 1;
-
- pkt_err(pd, "bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
- return 0;
-}
-
-/*
- * 1 -- we can write to this disc, 0 -- we can't
- */
-static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
-{
- switch (pd->mmc3_profile) {
- case 0x0a: /* CD-RW */
- case 0xffff: /* MMC3 not supported */
- break;
- case 0x1a: /* DVD+RW */
- case 0x13: /* DVD-RW */
- case 0x12: /* DVD-RAM */
- return 1;
- default:
- pkt_dbg(2, pd, "Wrong disc profile (%x)\n",
- pd->mmc3_profile);
- return 0;
- }
-
- /*
- * for disc type 0xff we should probably reserve a new track.
- * but i'm not sure, should we leave this to user apps? probably.
- */
- if (di->disc_type == 0xff) {
- pkt_notice(pd, "unknown disc - no track?\n");
- return 0;
- }
-
- if (di->disc_type != 0x20 && di->disc_type != 0) {
- pkt_err(pd, "wrong disc type (%x)\n", di->disc_type);
- return 0;
- }
-
- if (di->erasable == 0) {
- pkt_notice(pd, "disc not erasable\n");
- return 0;
- }
-
- if (di->border_status == PACKET_SESSION_RESERVED) {
- pkt_err(pd, "can't write to last track (reserved)\n");
- return 0;
- }
-
- return 1;
-}
-
-static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
-{
- struct packet_command cgc;
- unsigned char buf[12];
- disc_information di;
- track_information ti;
- int ret, track;
-
- init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
- cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
- cgc.cmd[8] = 8;
- ret = pkt_generic_packet(pd, &cgc);
- pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7];
-
- memset(&di, 0, sizeof(disc_information));
- memset(&ti, 0, sizeof(track_information));
-
- ret = pkt_get_disc_info(pd, &di);
- if (ret) {
- pkt_err(pd, "failed get_disc\n");
- return ret;
- }
-
- if (!pkt_writable_disc(pd, &di))
- return -EROFS;
-
- pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
-
- track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
- ret = pkt_get_track_info(pd, track, 1, &ti);
- if (ret) {
- pkt_err(pd, "failed get_track\n");
- return ret;
- }
-
- if (!pkt_writable_track(pd, &ti)) {
- pkt_err(pd, "can't write to this track\n");
- return -EROFS;
- }
-
- /*
- * we keep packet size in 512 byte units, makes it easier to
- * deal with request calculations.
- */
- pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
- if (pd->settings.size == 0) {
- pkt_notice(pd, "detected zero packet size!\n");
- return -ENXIO;
- }
- if (pd->settings.size > PACKET_MAX_SECTORS) {
- pkt_err(pd, "packet size is too big\n");
- return -EROFS;
- }
- pd->settings.fp = ti.fp;
- pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
-
- if (ti.nwa_v) {
- pd->nwa = be32_to_cpu(ti.next_writable);
- set_bit(PACKET_NWA_VALID, &pd->flags);
- }
-
- /*
- * in theory we could use lra on -RW media as well and just zero
- * blocks that haven't been written yet, but in practice that
- * is just a no-go. we'll use that for -R, naturally.
- */
- if (ti.lra_v) {
- pd->lra = be32_to_cpu(ti.last_rec_address);
- set_bit(PACKET_LRA_VALID, &pd->flags);
- } else {
- pd->lra = 0xffffffff;
- set_bit(PACKET_LRA_VALID, &pd->flags);
- }
-
- /*
- * fine for now
- */
- pd->settings.link_loss = 7;
- pd->settings.write_type = 0; /* packet */
- pd->settings.track_mode = ti.track_mode;
-
- /*
- * mode1 or mode2 disc
- */
- switch (ti.data_mode) {
- case PACKET_MODE1:
- pd->settings.block_mode = PACKET_BLOCK_MODE1;
- break;
- case PACKET_MODE2:
- pd->settings.block_mode = PACKET_BLOCK_MODE2;
- break;
- default:
- pkt_err(pd, "unknown data mode\n");
- return -EROFS;
- }
- return 0;
-}
-
-/*
- * enable/disable write caching on drive
- */
-static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd,
- int set)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- unsigned char buf[64];
- int ret;
-
- init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
- cgc.sshdr = &sshdr;
- cgc.buflen = pd->mode_offset + 12;
-
- /*
- * caching mode page might not be there, so quiet this command
- */
- cgc.quiet = 1;
-
- ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0);
- if (ret)
- return ret;
-
- buf[pd->mode_offset + 10] |= (!!set << 2);
-
- cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
- ret = pkt_mode_select(pd, &cgc);
- if (ret) {
- pkt_err(pd, "write caching control failed\n");
- pkt_dump_sense(pd, &cgc);
- } else if (!ret && set)
- pkt_notice(pd, "enabled write caching\n");
- return ret;
-}
-
-static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag)
-{
- struct packet_command cgc;
-
- init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
- cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
- cgc.cmd[4] = lockflag ? 1 : 0;
- return pkt_generic_packet(pd, &cgc);
-}
-
-/*
- * Returns drive maximum write speed
- */
-static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd,
- unsigned *write_speed)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- unsigned char buf[256+18];
- unsigned char *cap_buf;
- int ret, offset;
-
- cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];
- init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);
- cgc.sshdr = &sshdr;
-
- ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- if (ret) {
- cgc.buflen = pd->mode_offset + cap_buf[1] + 2 +
- sizeof(struct mode_page_header);
- ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
- }
-
- offset = 20; /* Obsoleted field, used by older drives */
- if (cap_buf[1] >= 28)
- offset = 28; /* Current write speed selected */
- if (cap_buf[1] >= 30) {
- /* If the drive reports at least one "Logical Unit Write
- * Speed Performance Descriptor Block", use the information
- * in the first block. (contains the highest speed)
- */
- int num_spdb = (cap_buf[30] << 8) + cap_buf[31];
- if (num_spdb > 0)
- offset = 34;
- }
-
- *write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1];
- return 0;
-}
-
-/* These tables from cdrecord - I don't have orange book */
-/* standard speed CD-RW (1-4x) */
-static char clv_to_speed[16] = {
- /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
- 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-/* high speed CD-RW (-10x) */
-static char hs_clv_to_speed[16] = {
- /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
- 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-/* ultra high speed CD-RW */
-static char us_clv_to_speed[16] = {
- /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
- 0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0
-};
-
-/*
- * reads the maximum media speed from ATIP
- */
-static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
- unsigned *speed)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- unsigned char buf[64];
- unsigned int size, st, sp;
- int ret;
-
- init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ);
- cgc.sshdr = &sshdr;
- cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
- cgc.cmd[1] = 2;
- cgc.cmd[2] = 4; /* READ ATIP */
- cgc.cmd[8] = 2;
- ret = pkt_generic_packet(pd, &cgc);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
- size = ((unsigned int) buf[0]<<8) + buf[1] + 2;
- if (size > sizeof(buf))
- size = sizeof(buf);
-
- init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
- cgc.sshdr = &sshdr;
- cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
- cgc.cmd[1] = 2;
- cgc.cmd[2] = 4;
- cgc.cmd[8] = size;
- ret = pkt_generic_packet(pd, &cgc);
- if (ret) {
- pkt_dump_sense(pd, &cgc);
- return ret;
- }
-
- if (!(buf[6] & 0x40)) {
- pkt_notice(pd, "disc type is not CD-RW\n");
- return 1;
- }
- if (!(buf[6] & 0x4)) {
- pkt_notice(pd, "A1 values on media are not valid, maybe not CDRW?\n");
- return 1;
- }
-
- st = (buf[6] >> 3) & 0x7; /* disc sub-type */
-
- sp = buf[16] & 0xf; /* max speed from ATIP A1 field */
-
- /* Info from cdrecord */
- switch (st) {
- case 0: /* standard speed */
- *speed = clv_to_speed[sp];
- break;
- case 1: /* high speed */
- *speed = hs_clv_to_speed[sp];
- break;
- case 2: /* ultra high speed */
- *speed = us_clv_to_speed[sp];
- break;
- default:
- pkt_notice(pd, "unknown disc sub-type %d\n", st);
- return 1;
- }
- if (*speed) {
- pkt_info(pd, "maximum media speed: %d\n", *speed);
- return 0;
- } else {
- pkt_notice(pd, "unknown speed %d for sub-type %d\n", sp, st);
- return 1;
- }
-}
-
-static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd)
-{
- struct packet_command cgc;
- struct scsi_sense_hdr sshdr;
- int ret;
-
- pkt_dbg(2, pd, "Performing OPC\n");
-
- init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
- cgc.sshdr = &sshdr;
- cgc.timeout = 60*HZ;
- cgc.cmd[0] = GPCMD_SEND_OPC;
- cgc.cmd[1] = 1;
- ret = pkt_generic_packet(pd, &cgc);
- if (ret)
- pkt_dump_sense(pd, &cgc);
- return ret;
-}
-
-static int pkt_open_write(struct pktcdvd_device *pd)
-{
- int ret;
- unsigned int write_speed, media_write_speed, read_speed;
-
- ret = pkt_probe_settings(pd);
- if (ret) {
- pkt_dbg(2, pd, "failed probe\n");
- return ret;
- }
-
- ret = pkt_set_write_settings(pd);
- if (ret) {
- pkt_dbg(1, pd, "failed saving write settings\n");
- return -EIO;
- }
-
- pkt_write_caching(pd, USE_WCACHING);
-
- ret = pkt_get_max_speed(pd, &write_speed);
- if (ret)
- write_speed = 16 * 177;
- switch (pd->mmc3_profile) {
- case 0x13: /* DVD-RW */
- case 0x1a: /* DVD+RW */
- case 0x12: /* DVD-RAM */
- pkt_dbg(1, pd, "write speed %ukB/s\n", write_speed);
- break;
- default:
- ret = pkt_media_speed(pd, &media_write_speed);
- if (ret)
- media_write_speed = 16;
- write_speed = min(write_speed, media_write_speed * 177);
- pkt_dbg(1, pd, "write speed %ux\n", write_speed / 176);
- break;
- }
- read_speed = write_speed;
-
- ret = pkt_set_speed(pd, write_speed, read_speed);
- if (ret) {
- pkt_dbg(1, pd, "couldn't set write speed\n");
- return -EIO;
- }
- pd->write_speed = write_speed;
- pd->read_speed = read_speed;
-
- ret = pkt_perform_opc(pd);
- if (ret) {
- pkt_dbg(1, pd, "Optimum Power Calibration failed\n");
- }
-
- return 0;
-}
-
-/*
- * called at open time.
- */
-static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
-{
- int ret;
- long lba;
- struct request_queue *q;
- struct block_device *bdev;
-
- /*
- * We need to re-open the cdrom device without O_NONBLOCK to be able
- * to read/write from/to it. It is already opened in O_NONBLOCK mode
- * so open should not fail.
- */
- bdev = blkdev_get_by_dev(pd->bdev->bd_dev, FMODE_READ | FMODE_EXCL, pd);
- if (IS_ERR(bdev)) {
- ret = PTR_ERR(bdev);
- goto out;
- }
-
- ret = pkt_get_last_written(pd, &lba);
- if (ret) {
- pkt_err(pd, "pkt_get_last_written failed\n");
- goto out_putdev;
- }
-
- set_capacity(pd->disk, lba << 2);
- set_capacity_and_notify(pd->bdev->bd_disk, lba << 2);
-
- q = bdev_get_queue(pd->bdev);
- if (write) {
- ret = pkt_open_write(pd);
- if (ret)
- goto out_putdev;
- /*
- * Some CDRW drives can not handle writes larger than one packet,
- * even if the size is a multiple of the packet size.
- */
- blk_queue_max_hw_sectors(q, pd->settings.size);
- set_bit(PACKET_WRITABLE, &pd->flags);
- } else {
- pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
- clear_bit(PACKET_WRITABLE, &pd->flags);
- }
-
- ret = pkt_set_segment_merging(pd, q);
- if (ret)
- goto out_putdev;
-
- if (write) {
- if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
- pkt_err(pd, "not enough memory for buffers\n");
- ret = -ENOMEM;
- goto out_putdev;
- }
- pkt_info(pd, "%lukB available on disc\n", lba << 1);
- }
-
- return 0;
-
-out_putdev:
- blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
-out:
- return ret;
-}
-
-/*
- * called when the device is closed. makes sure that the device flushes
- * the internal cache before we close.
- */
-static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
-{
- if (flush && pkt_flush_cache(pd))
- pkt_dbg(1, pd, "not flushing cache\n");
-
- pkt_lock_door(pd, 0);
-
- pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
- blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
-
- pkt_shrink_pktlist(pd);
-}
-
-static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor)
-{
- if (dev_minor >= MAX_WRITERS)
- return NULL;
-
- dev_minor = array_index_nospec(dev_minor, MAX_WRITERS);
- return pkt_devs[dev_minor];
-}
-
-static int pkt_open(struct block_device *bdev, fmode_t mode)
-{
- struct pktcdvd_device *pd = NULL;
- int ret;
-
- mutex_lock(&pktcdvd_mutex);
- mutex_lock(&ctl_mutex);
- pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
- if (!pd) {
- ret = -ENODEV;
- goto out;
- }
- BUG_ON(pd->refcnt < 0);
-
- pd->refcnt++;
- if (pd->refcnt > 1) {
- if ((mode & FMODE_WRITE) &&
- !test_bit(PACKET_WRITABLE, &pd->flags)) {
- ret = -EBUSY;
- goto out_dec;
- }
- } else {
- ret = pkt_open_dev(pd, mode & FMODE_WRITE);
- if (ret)
- goto out_dec;
- /*
- * needed here as well, since ext2 (among others) may change
- * the blocksize at mount time
- */
- set_blocksize(bdev, CD_FRAMESIZE);
- }
-
- mutex_unlock(&ctl_mutex);
- mutex_unlock(&pktcdvd_mutex);
- return 0;
-
-out_dec:
- pd->refcnt--;
-out:
- mutex_unlock(&ctl_mutex);
- mutex_unlock(&pktcdvd_mutex);
- return ret;
-}
-
-static void pkt_close(struct gendisk *disk, fmode_t mode)
-{
- struct pktcdvd_device *pd = disk->private_data;
-
- mutex_lock(&pktcdvd_mutex);
- mutex_lock(&ctl_mutex);
- pd->refcnt--;
- BUG_ON(pd->refcnt < 0);
- if (pd->refcnt == 0) {
- int flush = test_bit(PACKET_WRITABLE, &pd->flags);
- pkt_release_dev(pd, flush);
- }
- mutex_unlock(&ctl_mutex);
- mutex_unlock(&pktcdvd_mutex);
-}
-
-
-static void pkt_end_io_read_cloned(struct bio *bio)
-{
- struct packet_stacked_data *psd = bio->bi_private;
- struct pktcdvd_device *pd = psd->pd;
-
- psd->bio->bi_status = bio->bi_status;
- bio_put(bio);
- bio_endio(psd->bio);
- mempool_free(psd, &psd_pool);
- pkt_bio_finished(pd);
-}
-
-static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio)
-{
- struct bio *cloned_bio =
- bio_alloc_clone(pd->bdev, bio, GFP_NOIO, &pkt_bio_set);
- struct packet_stacked_data *psd = mempool_alloc(&psd_pool, GFP_NOIO);
-
- psd->pd = pd;
- psd->bio = bio;
- cloned_bio->bi_private = psd;
- cloned_bio->bi_end_io = pkt_end_io_read_cloned;
- pd->stats.secs_r += bio_sectors(bio);
- pkt_queue_bio(pd, cloned_bio);
-}
-
-static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
-{
- struct pktcdvd_device *pd = q->queuedata;
- sector_t zone;
- struct packet_data *pkt;
- int was_empty, blocked_bio;
- struct pkt_rb_node *node;
-
- zone = get_zone(bio->bi_iter.bi_sector, pd);
-
- /*
- * If we find a matching packet in state WAITING or READ_WAIT, we can
- * just append this bio to that packet.
- */
- spin_lock(&pd->cdrw.active_list_lock);
- blocked_bio = 0;
- list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
- if (pkt->sector == zone) {
- spin_lock(&pkt->lock);
- if ((pkt->state == PACKET_WAITING_STATE) ||
- (pkt->state == PACKET_READ_WAIT_STATE)) {
- bio_list_add(&pkt->orig_bios, bio);
- pkt->write_size +=
- bio->bi_iter.bi_size / CD_FRAMESIZE;
- if ((pkt->write_size >= pkt->frames) &&
- (pkt->state == PACKET_WAITING_STATE)) {
- atomic_inc(&pkt->run_sm);
- wake_up(&pd->wqueue);
- }
- spin_unlock(&pkt->lock);
- spin_unlock(&pd->cdrw.active_list_lock);
- return;
- } else {
- blocked_bio = 1;
- }
- spin_unlock(&pkt->lock);
- }
- }
- spin_unlock(&pd->cdrw.active_list_lock);
-
- /*
- * Test if there is enough room left in the bio work queue
- * (queue size >= congestion on mark).
- * If not, wait till the work queue size is below the congestion off mark.
- */
- spin_lock(&pd->lock);
- if (pd->write_congestion_on > 0
- && pd->bio_queue_size >= pd->write_congestion_on) {
- struct wait_bit_queue_entry wqe;
-
- init_wait_var_entry(&wqe, &pd->congested, 0);
- for (;;) {
- prepare_to_wait_event(__var_waitqueue(&pd->congested),
- &wqe.wq_entry,
- TASK_UNINTERRUPTIBLE);
- if (pd->bio_queue_size <= pd->write_congestion_off)
- break;
- pd->congested = true;
- spin_unlock(&pd->lock);
- schedule();
- spin_lock(&pd->lock);
- }
- }
- spin_unlock(&pd->lock);
-
- /*
- * No matching packet found. Store the bio in the work queue.
- */
- node = mempool_alloc(&pd->rb_pool, GFP_NOIO);
- node->bio = bio;
- spin_lock(&pd->lock);
- BUG_ON(pd->bio_queue_size < 0);
- was_empty = (pd->bio_queue_size == 0);
- pkt_rbtree_insert(pd, node);
- spin_unlock(&pd->lock);
-
- /*
- * Wake up the worker thread.
- */
- atomic_set(&pd->scan_queue, 1);
- if (was_empty) {
- /* This wake_up is required for correct operation */
- wake_up(&pd->wqueue);
- } else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) {
- /*
- * This wake up is not required for correct operation,
- * but improves performance in some cases.
- */
- wake_up(&pd->wqueue);
- }
-}
-
-static void pkt_submit_bio(struct bio *bio)
-{
- struct pktcdvd_device *pd = bio->bi_bdev->bd_disk->queue->queuedata;
- struct bio *split;
-
- bio = bio_split_to_limits(bio);
-
- pkt_dbg(2, pd, "start = %6llx stop = %6llx\n",
- (unsigned long long)bio->bi_iter.bi_sector,
- (unsigned long long)bio_end_sector(bio));
-
- /*
- * Clone READ bios so we can have our own bi_end_io callback.
- */
- if (bio_data_dir(bio) == READ) {
- pkt_make_request_read(pd, bio);
- return;
- }
-
- if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
- pkt_notice(pd, "WRITE for ro device (%llu)\n",
- (unsigned long long)bio->bi_iter.bi_sector);
- goto end_io;
- }
-
- if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) {
- pkt_err(pd, "wrong bio size\n");
- goto end_io;
- }
-
- do {
- sector_t zone = get_zone(bio->bi_iter.bi_sector, pd);
- sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd);
-
- if (last_zone != zone) {
- BUG_ON(last_zone != zone + pd->settings.size);
-
- split = bio_split(bio, last_zone -
- bio->bi_iter.bi_sector,
- GFP_NOIO, &pkt_bio_set);
- bio_chain(split, bio);
- } else {
- split = bio;
- }
-
- pkt_make_request_write(bio->bi_bdev->bd_disk->queue, split);
- } while (split != bio);
-
- return;
-end_io:
- bio_io_error(bio);
-}
-
-static void pkt_init_queue(struct pktcdvd_device *pd)
-{
- struct request_queue *q = pd->disk->queue;
-
- blk_queue_logical_block_size(q, CD_FRAMESIZE);
- blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
- q->queuedata = pd;
-}
-
-static int pkt_seq_show(struct seq_file *m, void *p)
-{
- struct pktcdvd_device *pd = m->private;
- char *msg;
- int states[PACKET_NUM_STATES];
-
- seq_printf(m, "Writer %s mapped to %pg:\n", pd->name, pd->bdev);
-
- seq_printf(m, "\nSettings:\n");
- seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2);
-
- if (pd->settings.write_type == 0)
- msg = "Packet";
- else
- msg = "Unknown";
- seq_printf(m, "\twrite type:\t\t%s\n", msg);
-
- seq_printf(m, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable");
- seq_printf(m, "\tlink loss:\t\t%d\n", pd->settings.link_loss);
-
- seq_printf(m, "\ttrack mode:\t\t%d\n", pd->settings.track_mode);
-
- if (pd->settings.block_mode == PACKET_BLOCK_MODE1)
- msg = "Mode 1";
- else if (pd->settings.block_mode == PACKET_BLOCK_MODE2)
- msg = "Mode 2";
- else
- msg = "Unknown";
- seq_printf(m, "\tblock mode:\t\t%s\n", msg);
-
- seq_printf(m, "\nStatistics:\n");
- seq_printf(m, "\tpackets started:\t%lu\n", pd->stats.pkt_started);
- seq_printf(m, "\tpackets ended:\t\t%lu\n", pd->stats.pkt_ended);
- seq_printf(m, "\twritten:\t\t%lukB\n", pd->stats.secs_w >> 1);
- seq_printf(m, "\tread gather:\t\t%lukB\n", pd->stats.secs_rg >> 1);
- seq_printf(m, "\tread:\t\t\t%lukB\n", pd->stats.secs_r >> 1);
-
- seq_printf(m, "\nMisc:\n");
- seq_printf(m, "\treference count:\t%d\n", pd->refcnt);
- seq_printf(m, "\tflags:\t\t\t0x%lx\n", pd->flags);
- seq_printf(m, "\tread speed:\t\t%ukB/s\n", pd->read_speed);
- seq_printf(m, "\twrite speed:\t\t%ukB/s\n", pd->write_speed);
- seq_printf(m, "\tstart offset:\t\t%lu\n", pd->offset);
- seq_printf(m, "\tmode page offset:\t%u\n", pd->mode_offset);
-
- seq_printf(m, "\nQueue state:\n");
- seq_printf(m, "\tbios queued:\t\t%d\n", pd->bio_queue_size);
- seq_printf(m, "\tbios pending:\t\t%d\n", atomic_read(&pd->cdrw.pending_bios));
- seq_printf(m, "\tcurrent sector:\t\t0x%llx\n", (unsigned long long)pd->current_sector);
-
- pkt_count_states(pd, states);
- seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
- states[0], states[1], states[2], states[3], states[4], states[5]);
-
- seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n",
- pd->write_congestion_off,
- pd->write_congestion_on);
- return 0;
-}
-
-static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
-{
- int i;
- struct block_device *bdev;
- struct scsi_device *sdev;
-
- if (pd->pkt_dev == dev) {
- pkt_err(pd, "recursive setup not allowed\n");
- return -EBUSY;
- }
- for (i = 0; i < MAX_WRITERS; i++) {
- struct pktcdvd_device *pd2 = pkt_devs[i];
- if (!pd2)
- continue;
- if (pd2->bdev->bd_dev == dev) {
- pkt_err(pd, "%pg already setup\n", pd2->bdev);
- return -EBUSY;
- }
- if (pd2->pkt_dev == dev) {
- pkt_err(pd, "can't chain pktcdvd devices\n");
- return -EBUSY;
- }
- }
-
- bdev = blkdev_get_by_dev(dev, FMODE_READ | FMODE_NDELAY, NULL);
- if (IS_ERR(bdev))
- return PTR_ERR(bdev);
- sdev = scsi_device_from_queue(bdev->bd_disk->queue);
- if (!sdev) {
- blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
- return -EINVAL;
- }
- put_device(&sdev->sdev_gendev);
-
- /* This is safe, since we have a reference from open(). */
- __module_get(THIS_MODULE);
-
- pd->bdev = bdev;
- set_blocksize(bdev, CD_FRAMESIZE);
-
- pkt_init_queue(pd);
-
- atomic_set(&pd->cdrw.pending_bios, 0);
- pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
- if (IS_ERR(pd->cdrw.thread)) {
- pkt_err(pd, "can't start kernel thread\n");
- goto out_mem;
- }
-
- proc_create_single_data(pd->name, 0, pkt_proc, pkt_seq_show, pd);
- pkt_dbg(1, pd, "writer mapped to %pg\n", bdev);
- return 0;
-
-out_mem:
- blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
- /* This is safe: open() is still holding a reference. */
- module_put(THIS_MODULE);
- return -ENOMEM;
-}
-
-static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
-{
- struct pktcdvd_device *pd = bdev->bd_disk->private_data;
- int ret;
-
- pkt_dbg(2, pd, "cmd %x, dev %d:%d\n",
- cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-
- mutex_lock(&pktcdvd_mutex);
- switch (cmd) {
- case CDROMEJECT:
- /*
- * The door gets locked when the device is opened, so we
- * have to unlock it or else the eject command fails.
- */
- if (pd->refcnt == 1)
- pkt_lock_door(pd, 0);
- fallthrough;
- /*
- * forward selected CDROM ioctls to CD-ROM, for UDF
- */
- case CDROMMULTISESSION:
- case CDROMREADTOCENTRY:
- case CDROM_LAST_WRITTEN:
- case CDROM_SEND_PACKET:
- case SCSI_IOCTL_SEND_COMMAND:
- if (!bdev->bd_disk->fops->ioctl)
- ret = -ENOTTY;
- else
- ret = bdev->bd_disk->fops->ioctl(bdev, mode, cmd, arg);
- break;
- default:
- pkt_dbg(2, pd, "Unknown ioctl (%x)\n", cmd);
- ret = -ENOTTY;
- }
- mutex_unlock(&pktcdvd_mutex);
-
- return ret;
-}
-
-static unsigned int pkt_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct pktcdvd_device *pd = disk->private_data;
- struct gendisk *attached_disk;
-
- if (!pd)
- return 0;
- if (!pd->bdev)
- return 0;
- attached_disk = pd->bdev->bd_disk;
- if (!attached_disk || !attached_disk->fops->check_events)
- return 0;
- return attached_disk->fops->check_events(attached_disk, clearing);
-}
-
-static char *pkt_devnode(struct gendisk *disk, umode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "pktcdvd/%s", disk->disk_name);
-}
-
-static const struct block_device_operations pktcdvd_ops = {
- .owner = THIS_MODULE,
- .submit_bio = pkt_submit_bio,
- .open = pkt_open,
- .release = pkt_close,
- .ioctl = pkt_ioctl,
- .compat_ioctl = blkdev_compat_ptr_ioctl,
- .check_events = pkt_check_events,
- .devnode = pkt_devnode,
-};
-
-/*
- * Set up mapping from pktcdvd device to CD-ROM device.
- */
-static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
-{
- int idx;
- int ret = -ENOMEM;
- struct pktcdvd_device *pd;
- struct gendisk *disk;
-
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- for (idx = 0; idx < MAX_WRITERS; idx++)
- if (!pkt_devs[idx])
- break;
- if (idx == MAX_WRITERS) {
- pr_err("max %d writers supported\n", MAX_WRITERS);
- ret = -EBUSY;
- goto out_mutex;
- }
-
- pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
- if (!pd)
- goto out_mutex;
-
- ret = mempool_init_kmalloc_pool(&pd->rb_pool, PKT_RB_POOL_SIZE,
- sizeof(struct pkt_rb_node));
- if (ret)
- goto out_mem;
-
- INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
- INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
- spin_lock_init(&pd->cdrw.active_list_lock);
-
- spin_lock_init(&pd->lock);
- spin_lock_init(&pd->iosched.lock);
- bio_list_init(&pd->iosched.read_queue);
- bio_list_init(&pd->iosched.write_queue);
- sprintf(pd->name, DRIVER_NAME"%d", idx);
- init_waitqueue_head(&pd->wqueue);
- pd->bio_queue = RB_ROOT;
-
- pd->write_congestion_on = write_congestion_on;
- pd->write_congestion_off = write_congestion_off;
-
- ret = -ENOMEM;
- disk = blk_alloc_disk(NUMA_NO_NODE);
- if (!disk)
- goto out_mem;
- pd->disk = disk;
- disk->major = pktdev_major;
- disk->first_minor = idx;
- disk->minors = 1;
- disk->fops = &pktcdvd_ops;
- disk->flags = GENHD_FL_REMOVABLE | GENHD_FL_NO_PART;
- strcpy(disk->disk_name, pd->name);
- disk->private_data = pd;
-
- pd->pkt_dev = MKDEV(pktdev_major, idx);
- ret = pkt_new_dev(pd, dev);
- if (ret)
- goto out_mem2;
-
- /* inherit events of the host device */
- disk->events = pd->bdev->bd_disk->events;
-
- ret = add_disk(disk);
- if (ret)
- goto out_mem2;
-
- pkt_sysfs_dev_new(pd);
- pkt_debugfs_dev_new(pd);
-
- pkt_devs[idx] = pd;
- if (pkt_dev)
- *pkt_dev = pd->pkt_dev;
-
- mutex_unlock(&ctl_mutex);
- return 0;
-
-out_mem2:
- put_disk(disk);
-out_mem:
- mempool_exit(&pd->rb_pool);
- kfree(pd);
-out_mutex:
- mutex_unlock(&ctl_mutex);
- pr_err("setup of pktcdvd device failed\n");
- return ret;
-}
-
-/*
- * Tear down mapping from pktcdvd device to CD-ROM device.
- */
-static int pkt_remove_dev(dev_t pkt_dev)
-{
- struct pktcdvd_device *pd;
- int idx;
- int ret = 0;
-
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- for (idx = 0; idx < MAX_WRITERS; idx++) {
- pd = pkt_devs[idx];
- if (pd && (pd->pkt_dev == pkt_dev))
- break;
- }
- if (idx == MAX_WRITERS) {
- pr_debug("dev not setup\n");
- ret = -ENXIO;
- goto out;
- }
-
- if (pd->refcnt > 0) {
- ret = -EBUSY;
- goto out;
- }
- if (!IS_ERR(pd->cdrw.thread))
- kthread_stop(pd->cdrw.thread);
-
- pkt_devs[idx] = NULL;
-
- pkt_debugfs_dev_remove(pd);
- pkt_sysfs_dev_remove(pd);
-
- blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY);
-
- remove_proc_entry(pd->name, pkt_proc);
- pkt_dbg(1, pd, "writer unmapped\n");
-
- del_gendisk(pd->disk);
- put_disk(pd->disk);
-
- mempool_exit(&pd->rb_pool);
- kfree(pd);
-
- /* This is safe: open() is still holding a reference. */
- module_put(THIS_MODULE);
-
-out:
- mutex_unlock(&ctl_mutex);
- return ret;
-}
-
-static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
-{
- struct pktcdvd_device *pd;
-
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
- if (pd) {
- ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
- ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
- } else {
- ctrl_cmd->dev = 0;
- ctrl_cmd->pkt_dev = 0;
- }
- ctrl_cmd->num_devices = MAX_WRITERS;
-
- mutex_unlock(&ctl_mutex);
-}
-
-static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
- struct pkt_ctrl_command ctrl_cmd;
- int ret = 0;
- dev_t pkt_dev = 0;
-
- if (cmd != PACKET_CTRL_CMD)
- return -ENOTTY;
-
- if (copy_from_user(&ctrl_cmd, argp, sizeof(struct pkt_ctrl_command)))
- return -EFAULT;
-
- switch (ctrl_cmd.command) {
- case PKT_CTRL_CMD_SETUP:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
- ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
- break;
- case PKT_CTRL_CMD_TEARDOWN:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
- break;
- case PKT_CTRL_CMD_STATUS:
- pkt_get_status(&ctrl_cmd);
- break;
- default:
- return -ENOTTY;
- }
-
- if (copy_to_user(argp, &ctrl_cmd, sizeof(struct pkt_ctrl_command)))
- return -EFAULT;
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static long pkt_ctl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- return pkt_ctl_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
-}
-#endif
-
-static const struct file_operations pkt_ctl_fops = {
- .open = nonseekable_open,
- .unlocked_ioctl = pkt_ctl_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = pkt_ctl_compat_ioctl,
-#endif
- .owner = THIS_MODULE,
- .llseek = no_llseek,
-};
-
-static struct miscdevice pkt_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DRIVER_NAME,
- .nodename = "pktcdvd/control",
- .fops = &pkt_ctl_fops
-};
-
-static int __init pkt_init(void)
-{
- int ret;
-
- mutex_init(&ctl_mutex);
-
- ret = mempool_init_kmalloc_pool(&psd_pool, PSD_POOL_SIZE,
- sizeof(struct packet_stacked_data));
- if (ret)
- return ret;
- ret = bioset_init(&pkt_bio_set, BIO_POOL_SIZE, 0, 0);
- if (ret) {
- mempool_exit(&psd_pool);
- return ret;
- }
-
- ret = register_blkdev(pktdev_major, DRIVER_NAME);
- if (ret < 0) {
- pr_err("unable to register block device\n");
- goto out2;
- }
- if (!pktdev_major)
- pktdev_major = ret;
-
- ret = pkt_sysfs_init();
- if (ret)
- goto out;
-
- pkt_debugfs_init();
-
- ret = misc_register(&pkt_misc);
- if (ret) {
- pr_err("unable to register misc device\n");
- goto out_misc;
- }
-
- pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL);
-
- return 0;
-
-out_misc:
- pkt_debugfs_cleanup();
- pkt_sysfs_cleanup();
-out:
- unregister_blkdev(pktdev_major, DRIVER_NAME);
-out2:
- mempool_exit(&psd_pool);
- bioset_exit(&pkt_bio_set);
- return ret;
-}
-
-static void __exit pkt_exit(void)
-{
- remove_proc_entry("driver/"DRIVER_NAME, NULL);
- misc_deregister(&pkt_misc);
-
- pkt_debugfs_cleanup();
- pkt_sysfs_cleanup();
-
- unregister_blkdev(pktdev_major, DRIVER_NAME);
- mempool_exit(&psd_pool);
- bioset_exit(&pkt_bio_set);
-}
-
-MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives");
-MODULE_AUTHOR("Jens Axboe <axboe@suse.de>");
-MODULE_LICENSE("GPL");
-
-module_init(pkt_init);
-module_exit(pkt_exit);
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index f96cb01e9604..e9de9d846b73 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -57,10 +57,8 @@
#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD)
struct ublk_rq_data {
- union {
- struct callback_head work;
- struct llist_node node;
- };
+ struct llist_node node;
+ struct callback_head work;
};
struct ublk_uring_cmd_pdu {
@@ -766,15 +764,31 @@ static inline void __ublk_rq_task_work(struct request *req)
ubq_complete_io_cmd(io, UBLK_IO_RES_OK);
}
+static inline void ublk_forward_io_cmds(struct ublk_queue *ubq)
+{
+ struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
+ struct ublk_rq_data *data, *tmp;
+
+ io_cmds = llist_reverse_order(io_cmds);
+ llist_for_each_entry_safe(data, tmp, io_cmds, node)
+ __ublk_rq_task_work(blk_mq_rq_from_pdu(data));
+}
+
+static inline void ublk_abort_io_cmds(struct ublk_queue *ubq)
+{
+ struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
+ struct ublk_rq_data *data, *tmp;
+
+ llist_for_each_entry_safe(data, tmp, io_cmds, node)
+ __ublk_abort_rq(ubq, blk_mq_rq_from_pdu(data));
+}
+
static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd)
{
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
struct ublk_queue *ubq = pdu->ubq;
- struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
- struct ublk_rq_data *data;
- llist_for_each_entry(data, io_cmds, node)
- __ublk_rq_task_work(blk_mq_rq_from_pdu(data));
+ ublk_forward_io_cmds(ubq);
}
static void ublk_rq_task_work_fn(struct callback_head *work)
@@ -782,14 +796,20 @@ static void ublk_rq_task_work_fn(struct callback_head *work)
struct ublk_rq_data *data = container_of(work,
struct ublk_rq_data, work);
struct request *req = blk_mq_rq_from_pdu(data);
+ struct ublk_queue *ubq = req->mq_hctx->driver_data;
- __ublk_rq_task_work(req);
+ ublk_forward_io_cmds(ubq);
}
-static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
+static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
{
- struct ublk_io *io = &ubq->ios[rq->tag];
+ struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
+ struct ublk_io *io;
+ if (!llist_add(&data->node, &ubq->io_cmds))
+ return;
+
+ io = &ubq->ios[rq->tag];
/*
* If the check pass, we know that this is a re-issued request aborted
* previously in monitor_work because the ubq_daemon(cmd's task) is
@@ -803,11 +823,11 @@ static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
* guarantees that here is a re-issued request aborted previously.
*/
if (unlikely(io->flags & UBLK_IO_FLAG_ABORTED)) {
- struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
- struct ublk_rq_data *data;
-
- llist_for_each_entry(data, io_cmds, node)
- __ublk_abort_rq(ubq, blk_mq_rq_from_pdu(data));
+ ublk_abort_io_cmds(ubq);
+ } else if (ublk_can_use_task_work(ubq)) {
+ if (task_work_add(ubq->ubq_daemon, &data->work,
+ TWA_SIGNAL_NO_IPI))
+ ublk_abort_io_cmds(ubq);
} else {
struct io_uring_cmd *cmd = io->cmd;
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
@@ -817,23 +837,6 @@ static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
}
}
-static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq,
- bool last)
-{
- struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
-
- if (ublk_can_use_task_work(ubq)) {
- enum task_work_notify_mode notify_mode = last ?
- TWA_SIGNAL_NO_IPI : TWA_NONE;
-
- if (task_work_add(ubq->ubq_daemon, &data->work, notify_mode))
- __ublk_abort_rq(ubq, rq);
- } else {
- if (llist_add(&data->node, &ubq->io_cmds))
- ublk_submit_cmd(ubq, rq);
- }
-}
-
static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
@@ -865,19 +868,11 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_STS_OK;
}
- ublk_queue_cmd(ubq, rq, bd->last);
+ ublk_queue_cmd(ubq, rq);
return BLK_STS_OK;
}
-static void ublk_commit_rqs(struct blk_mq_hw_ctx *hctx)
-{
- struct ublk_queue *ubq = hctx->driver_data;
-
- if (ublk_can_use_task_work(ubq))
- __set_notify_signal(ubq->ubq_daemon);
-}
-
static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
unsigned int hctx_idx)
{
@@ -899,7 +894,6 @@ static int ublk_init_rq(struct blk_mq_tag_set *set, struct request *req,
static const struct blk_mq_ops ublk_mq_ops = {
.queue_rq = ublk_queue_rq,
- .commit_rqs = ublk_commit_rqs,
.init_hctx = ublk_init_hctx,
.init_request = ublk_init_rq,
};
@@ -1197,7 +1191,7 @@ static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id,
struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
struct request *req = blk_mq_tag_to_rq(ub->tag_set.tags[q_id], tag);
- ublk_queue_cmd(ubq, req, true);
+ ublk_queue_cmd(ubq, req);
}
static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 19da5defd734..68bd2f7961b3 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -512,7 +512,7 @@ static void virtblk_free_disk(struct gendisk *disk)
{
struct virtio_blk *vblk = disk->private_data;
- ida_simple_remove(&vd_index_ida, vblk->index);
+ ida_free(&vd_index_ida, vblk->index);
mutex_destroy(&vblk->vdev_mutex);
kfree(vblk);
}
@@ -902,8 +902,8 @@ static int virtblk_probe(struct virtio_device *vdev)
return -EINVAL;
}
- err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS),
- GFP_KERNEL);
+ err = ida_alloc_range(&vd_index_ida, 0,
+ minor_to_index(1 << MINORBITS) - 1, GFP_KERNEL);
if (err < 0)
goto out;
index = err;
@@ -1163,7 +1163,7 @@ out_free_vq:
out_free_vblk:
kfree(vblk);
out_free_index:
- ida_simple_remove(&vd_index_ida, index);
+ ida_free(&vd_index_ida, index);
out:
return err;
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 35b9bcad9db9..b28489290323 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2129,7 +2129,6 @@ static void blkfront_closing(struct blkfront_info *info)
if (info->rq && info->gd) {
blk_mq_stop_hw_queues(info->rq);
blk_mark_disk_dead(info->gd);
- set_capacity(info->gd, 0);
}
for_each_rinfo(info, rinfo, i) {
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 271963805a38..f05018988a17 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2056,6 +2056,11 @@ static int btusb_setup_csr(struct hci_dev *hdev)
rp = (struct hci_rp_read_local_version *)skb->data;
+ bt_dev_info(hdev, "CSR: Setting up dongle with HCI ver=%u rev=%04x; LMP ver=%u subver=%04x; manufacturer=%u",
+ le16_to_cpu(rp->hci_ver), le16_to_cpu(rp->hci_rev),
+ le16_to_cpu(rp->lmp_ver), le16_to_cpu(rp->lmp_subver),
+ le16_to_cpu(rp->manufacturer));
+
/* Detect a wide host of Chinese controllers that aren't CSR.
*
* Known fake bcdDevices: 0x0100, 0x0134, 0x1915, 0x2520, 0x7558, 0x8891
@@ -2118,6 +2123,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
* without these the controller will lock up.
*/
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
+ set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks);
set_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks);
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 8df11016fd51..ba8be8e1bebd 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -696,9 +696,15 @@ static int qca_close(struct hci_uart *hu)
skb_queue_purge(&qca->tx_wait_q);
skb_queue_purge(&qca->txq);
skb_queue_purge(&qca->rx_memdump_q);
+ /*
+ * Shut the timers down so they can't be rearmed when
+ * destroy_workqueue() drains pending work which in turn might try
+ * to arm a timer. After shutdown rearm attempts are silently
+ * ignored by the timer core code.
+ */
+ timer_shutdown_sync(&qca->tx_idle_timer);
+ timer_shutdown_sync(&qca->wake_retrans_timer);
destroy_workqueue(qca->workqueue);
- del_timer_sync(&qca->tx_idle_timer);
- del_timer_sync(&qca->wake_retrans_timer);
qca->hu = NULL;
kfree_skb(qca->rx_skb);
diff --git a/drivers/bus/fsl-mc/Kconfig b/drivers/bus/fsl-mc/Kconfig
index b1fd55901c50..9492342e7d13 100644
--- a/drivers/bus/fsl-mc/Kconfig
+++ b/drivers/bus/fsl-mc/Kconfig
@@ -8,7 +8,7 @@
config FSL_MC_BUS
bool "QorIQ DPAA2 fsl-mc bus driver"
depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC)))
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
help
Driver to enable the bus infrastructure for the QorIQ DPAA2
architecture. The fsl-mc bus driver handles discovery of
diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c
index 5e70f9775a0e..4c84be378bf2 100644
--- a/drivers/bus/fsl-mc/dprc-driver.c
+++ b/drivers/bus/fsl-mc/dprc-driver.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/msi.h>
#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 6143dbf31f31..774f307844b4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/limits.h>
#include <linux/bitops.h>
-#include <linux/msi.h>
#include <linux/dma-mapping.h>
#include <linux/acpi.h>
#include <linux/iommu.h>
diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c
index 0cfe859a4ac4..f3f8af9426c9 100644
--- a/drivers/bus/fsl-mc/fsl-mc-msi.c
+++ b/drivers/bus/fsl-mc/fsl-mc-msi.c
@@ -213,21 +213,8 @@ struct irq_domain *fsl_mc_find_msi_domain(struct device *dev)
int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count)
{
- struct irq_domain *msi_domain;
- int error;
-
- msi_domain = dev_get_msi_domain(dev);
- if (!msi_domain)
- return -EINVAL;
-
- error = msi_setup_device_data(dev);
- if (error)
- return error;
+ int error = msi_setup_device_data(dev);
- msi_lock_descs(dev);
- if (msi_first_desc(dev, MSI_DESC_ALL))
- error = -EINVAL;
- msi_unlock_descs(dev);
if (error)
return error;
@@ -235,7 +222,7 @@ int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count)
* NOTE: Calling this function will trigger the invocation of the
* its_fsl_mc_msi_prepare() callback
*/
- error = msi_domain_alloc_irqs(msi_domain, dev, irq_count);
+ error = msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, irq_count - 1);
if (error)
dev_err(dev, "Failed to allocate IRQs\n");
@@ -244,11 +231,5 @@ int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count)
void fsl_mc_msi_domain_free_irqs(struct device *dev)
{
- struct irq_domain *msi_domain;
-
- msi_domain = dev_get_msi_domain(dev);
- if (!msi_domain)
- return;
-
- msi_domain_free_irqs(msi_domain, dev);
+ msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
}
diff --git a/drivers/bus/intel-ixp4xx-eb.c b/drivers/bus/intel-ixp4xx-eb.c
index a4388440aca7..91db001eb69a 100644
--- a/drivers/bus/intel-ixp4xx-eb.c
+++ b/drivers/bus/intel-ixp4xx-eb.c
@@ -49,7 +49,7 @@
#define IXP4XX_EXP_SIZE_SHIFT 10
#define IXP4XX_EXP_CNFG_0 BIT(9) /* Always zero */
#define IXP43X_EXP_SYNC_INTEL BIT(8) /* Only on IXP43x */
-#define IXP43X_EXP_EXP_CHIP BIT(7) /* Only on IXP43x */
+#define IXP43X_EXP_EXP_CHIP BIT(7) /* Only on IXP43x, dangerous to touch on IXP42x */
#define IXP4XX_EXP_BYTE_RD16 BIT(6)
#define IXP4XX_EXP_HRDY_POL BIT(5) /* Only on IXP42x */
#define IXP4XX_EXP_MUX_EN BIT(4)
@@ -57,8 +57,6 @@
#define IXP4XX_EXP_WORD BIT(2) /* Always zero */
#define IXP4XX_EXP_WR_EN BIT(1)
#define IXP4XX_EXP_BYTE_EN BIT(0)
-#define IXP42X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(8)|BIT(7)|IXP4XX_EXP_WORD)
-#define IXP43X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(5)|IXP4XX_EXP_WORD)
#define IXP4XX_EXP_CNFG0 0x20
#define IXP4XX_EXP_CNFG0_MEM_MAP BIT(31)
@@ -252,10 +250,9 @@ static void ixp4xx_exp_setup_chipselect(struct ixp4xx_eb *eb,
cs_cfg |= val << IXP4XX_EXP_CYC_TYPE_SHIFT;
}
- if (eb->is_42x)
- cs_cfg &= ~IXP42X_RESERVED;
if (eb->is_43x) {
- cs_cfg &= ~IXP43X_RESERVED;
+ /* Should always be zero */
+ cs_cfg &= ~IXP4XX_EXP_WORD;
/*
* This bit for Intel strata flash is currently unused, but let's
* report it if we find one.
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 01fd10a399b6..2e139e76de4c 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -129,7 +129,7 @@ enum mhi_pm_state {
#define PRIMARY_CMD_RING 0
#define MHI_DEV_WAKE_DB 127
#define MHI_MAX_MTU 0xffff
-#define MHI_RANDOM_U32_NONZERO(bmsk) (prandom_u32_max(bmsk) + 1)
+#define MHI_RANDOM_U32_NONZERO(bmsk) (get_random_u32_inclusive(1, bmsk))
enum mhi_er_type {
MHI_ER_TYPE_INVALID = 0x0,
diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c
index 4cd2e127946e..3aa91aed3bf7 100644
--- a/drivers/bus/sunxi-rsb.c
+++ b/drivers/bus/sunxi-rsb.c
@@ -267,6 +267,9 @@ EXPORT_SYMBOL_GPL(sunxi_rsb_driver_register);
/* common code that starts a transfer */
static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
{
+ u32 int_mask, status;
+ bool timeout;
+
if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) {
dev_dbg(rsb->dev, "RSB transfer still in progress\n");
return -EBUSY;
@@ -274,13 +277,23 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
reinit_completion(&rsb->complete);
- writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
- rsb->regs + RSB_INTE);
+ int_mask = RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER;
+ writel(int_mask, 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))) {
+ if (irqs_disabled()) {
+ timeout = readl_poll_timeout_atomic(rsb->regs + RSB_INTS,
+ status, (status & int_mask),
+ 10, 100000);
+ writel(status, rsb->regs + RSB_INTS);
+ } else {
+ timeout = !wait_for_completion_io_timeout(&rsb->complete,
+ msecs_to_jiffies(100));
+ status = rsb->status;
+ }
+
+ if (timeout) {
dev_dbg(rsb->dev, "RSB timeout\n");
/* abort the transfer */
@@ -292,18 +305,18 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
return -ETIMEDOUT;
}
- if (rsb->status & RSB_INTS_LOAD_BSY) {
+ if (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) {
+ if (status & RSB_INTS_TRANS_ERR) {
+ if (status & RSB_INTS_TRANS_ERR_ACK) {
dev_dbg(rsb->dev, "RSB slave nack\n");
return -EINVAL;
}
- if (rsb->status & RSB_INTS_TRANS_ERR_DATA) {
+ if (status & RSB_INTS_TRANS_ERR_DATA) {
dev_dbg(rsb->dev, "RSB transfer data error\n");
return -EIO;
}
@@ -812,14 +825,6 @@ static int sunxi_rsb_remove(struct platform_device *pdev)
return 0;
}
-static void sunxi_rsb_shutdown(struct platform_device *pdev)
-{
- struct sunxi_rsb *rsb = platform_get_drvdata(pdev);
-
- pm_runtime_disable(&pdev->dev);
- sunxi_rsb_hw_exit(rsb);
-}
-
static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = {
SET_RUNTIME_PM_OPS(sunxi_rsb_runtime_suspend,
sunxi_rsb_runtime_resume, NULL)
@@ -835,7 +840,6 @@ MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table);
static struct platform_driver sunxi_rsb_driver = {
.probe = sunxi_rsb_probe,
.remove = sunxi_rsb_remove,
- .shutdown = sunxi_rsb_shutdown,
.driver = {
.name = RSB_CTRL_NAME,
.of_match_table = sunxi_rsb_of_match_table,
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 9a7d12332fad..6afae9897843 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -1610,6 +1610,12 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+ SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000033,
+ 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
+ SYSC_MODULE_QUIRK_OTG),
+ SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000040,
+ 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
+ SYSC_MODULE_QUIRK_OTG),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
SYSC_MODULE_QUIRK_OTG),
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 0f378d29dab0..30fe9848dac1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -423,40 +423,4 @@ config ADI
and SSM (Silicon Secured Memory). Intended consumers of this
driver include crash and makedumpfile.
-config RANDOM_TRUST_CPU
- bool "Initialize RNG using CPU RNG instructions"
- default y
- help
- Initialize the RNG using random numbers supplied by the CPU's
- RNG instructions (e.g. RDRAND), if supported and available. These
- random numbers are never used directly, but are rather hashed into
- the main input pool, and this happens regardless of whether or not
- this option is enabled. Instead, this option controls whether the
- they are credited and hence can initialize the RNG. Additionally,
- other sources of randomness are always used, regardless of this
- setting. Enabling this implies trusting that the CPU can supply high
- quality and non-backdoored random numbers.
-
- Say Y here unless you have reason to mistrust your CPU or believe
- its RNG facilities may be faulty. This may also be configured at
- boot time with "random.trust_cpu=on/off".
-
-config RANDOM_TRUST_BOOTLOADER
- bool "Initialize RNG using bootloader-supplied seed"
- default y
- help
- Initialize the RNG using a seed supplied by the bootloader or boot
- environment (e.g. EFI or a bootloader-generated device tree). This
- seed is not used directly, but is rather hashed into the main input
- pool, and this happens regardless of whether or not this option is
- enabled. Instead, this option controls whether the seed is credited
- and hence can initialize the RNG. Additionally, other sources of
- randomness are always used, regardless of this setting. Enabling
- this implies trusting that the bootloader can supply high quality and
- non-backdoored seeds.
-
- Say Y here unless you have reason to mistrust your bootloader or
- believe its RNG facilities may be faulty. This may also be configured
- at boot time with "random.trust_bootloader=on/off".
-
endmenu
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index cc002b0c2f0c..63a0a8e4505d 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -69,8 +69,10 @@ static void add_early_randomness(struct hwrng *rng)
mutex_lock(&reading_mutex);
bytes_read = rng_get_data(rng, rng_fillbuf, 32, 0);
mutex_unlock(&reading_mutex);
- if (bytes_read > 0)
- add_device_randomness(rng_fillbuf, bytes_read);
+ if (bytes_read > 0) {
+ size_t entropy = bytes_read * 8 * rng->quality / 1024;
+ add_hwgenerator_randomness(rng_fillbuf, bytes_read, entropy, false);
+ }
}
static inline void cleanup_rng(struct kref *kref)
@@ -528,7 +530,7 @@ static int hwrng_fillfn(void *unused)
/* Outside lock, sure, but y'know: randomness. */
add_hwgenerator_randomness((void *)rng_fillbuf, rc,
- entropy >> 10);
+ entropy >> 10, true);
}
hwrng_fill = NULL;
return 0;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 69754155300e..5885ed574c6a 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -53,6 +53,7 @@
#include <linux/uaccess.h>
#include <linux/suspend.h>
#include <linux/siphash.h>
+#include <linux/sched/isolation.h>
#include <crypto/chacha.h>
#include <crypto/blake2s.h>
#include <asm/processor.h>
@@ -84,6 +85,7 @@ static DEFINE_STATIC_KEY_FALSE(crng_is_ready);
/* Various types of waiters for crng_init->CRNG_READY transition. */
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
static struct fasync_struct *fasync;
+static ATOMIC_NOTIFIER_HEAD(random_ready_notifier);
/* Control how we warn userspace. */
static struct ratelimit_state urandom_warning =
@@ -120,7 +122,7 @@ static void try_to_generate_entropy(void);
* Wait for the input pool to be seeded and thus guaranteed to supply
* cryptographically secure random numbers. This applies to: the /dev/urandom
* device, the get_random_bytes function, and the get_random_{u8,u16,u32,u64,
- * int,long} family of functions. Using any of these functions without first
+ * long} family of functions. Using any of these functions without first
* calling this function forfeits the guarantee of security.
*
* Returns: 0 if the input pool has been seeded.
@@ -140,6 +142,26 @@ int wait_for_random_bytes(void)
}
EXPORT_SYMBOL(wait_for_random_bytes);
+/*
+ * Add a callback function that will be invoked when the crng is initialised,
+ * or immediately if it already has been. Only use this is you are absolutely
+ * sure it is required. Most users should instead be able to test
+ * `rng_is_initialized()` on demand, or make use of `get_random_bytes_wait()`.
+ */
+int __cold execute_with_initialized_rng(struct notifier_block *nb)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&random_ready_notifier.lock, flags);
+ if (crng_ready())
+ nb->notifier_call(nb, 0, NULL);
+ else
+ ret = raw_notifier_chain_register((struct raw_notifier_head *)&random_ready_notifier.head, nb);
+ spin_unlock_irqrestore(&random_ready_notifier.lock, flags);
+ return ret;
+}
+
#define warn_unseeded_randomness() \
if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
@@ -160,6 +182,9 @@ EXPORT_SYMBOL(wait_for_random_bytes);
* u8 get_random_u8()
* u16 get_random_u16()
* u32 get_random_u32()
+ * u32 get_random_u32_below(u32 ceil)
+ * u32 get_random_u32_above(u32 floor)
+ * u32 get_random_u32_inclusive(u32 floor, u32 ceil)
* u64 get_random_u64()
* unsigned long get_random_long()
*
@@ -179,7 +204,6 @@ enum {
static struct {
u8 key[CHACHA_KEY_SIZE] __aligned(__alignof__(long));
- unsigned long birth;
unsigned long generation;
spinlock_t lock;
} base_crng = {
@@ -197,16 +221,41 @@ static DEFINE_PER_CPU(struct crng, crngs) = {
.lock = INIT_LOCAL_LOCK(crngs.lock),
};
+/*
+ * Return the interval until the next reseeding, which is normally
+ * CRNG_RESEED_INTERVAL, but during early boot, it is at an interval
+ * proportional to the uptime.
+ */
+static unsigned int crng_reseed_interval(void)
+{
+ static bool early_boot = true;
+
+ if (unlikely(READ_ONCE(early_boot))) {
+ time64_t uptime = ktime_get_seconds();
+ if (uptime >= CRNG_RESEED_INTERVAL / HZ * 2)
+ WRITE_ONCE(early_boot, false);
+ else
+ return max_t(unsigned int, CRNG_RESEED_START_INTERVAL,
+ (unsigned int)uptime / 2 * HZ);
+ }
+ return CRNG_RESEED_INTERVAL;
+}
+
/* Used by crng_reseed() and crng_make_state() to extract a new seed from the input pool. */
static void extract_entropy(void *buf, size_t len);
/* This extracts a new crng key from the input pool. */
-static void crng_reseed(void)
+static void crng_reseed(struct work_struct *work)
{
+ static DECLARE_DELAYED_WORK(next_reseed, crng_reseed);
unsigned long flags;
unsigned long next_gen;
u8 key[CHACHA_KEY_SIZE];
+ /* Immediately schedule the next reseeding, so that it fires sooner rather than later. */
+ if (likely(system_unbound_wq))
+ queue_delayed_work(system_unbound_wq, &next_reseed, crng_reseed_interval());
+
extract_entropy(key, sizeof(key));
/*
@@ -221,7 +270,6 @@ static void crng_reseed(void)
if (next_gen == ULONG_MAX)
++next_gen;
WRITE_ONCE(base_crng.generation, next_gen);
- WRITE_ONCE(base_crng.birth, jiffies);
if (!static_branch_likely(&crng_is_ready))
crng_init = CRNG_READY;
spin_unlock_irqrestore(&base_crng.lock, flags);
@@ -261,26 +309,6 @@ static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE],
}
/*
- * Return the interval until the next reseeding, which is normally
- * CRNG_RESEED_INTERVAL, but during early boot, it is at an interval
- * proportional to the uptime.
- */
-static unsigned int crng_reseed_interval(void)
-{
- static bool early_boot = true;
-
- if (unlikely(READ_ONCE(early_boot))) {
- time64_t uptime = ktime_get_seconds();
- if (uptime >= CRNG_RESEED_INTERVAL / HZ * 2)
- WRITE_ONCE(early_boot, false);
- else
- return max_t(unsigned int, CRNG_RESEED_START_INTERVAL,
- (unsigned int)uptime / 2 * HZ);
- }
- return CRNG_RESEED_INTERVAL;
-}
-
-/*
* This function returns a ChaCha state that you may use for generating
* random data. It also returns up to 32 bytes on its own of random data
* that may be used; random_data_len may not be greater than 32.
@@ -315,13 +343,6 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS],
return;
}
- /*
- * If the base_crng is old enough, we reseed, which in turn bumps the
- * generation counter that we check below.
- */
- if (unlikely(time_is_before_jiffies(READ_ONCE(base_crng.birth) + crng_reseed_interval())))
- crng_reseed();
-
local_lock_irqsave(&crngs.lock, flags);
crng = raw_cpu_ptr(&crngs);
@@ -383,11 +404,11 @@ static void _get_random_bytes(void *buf, size_t len)
}
/*
- * This function is the exported kernel interface. It returns some number of
- * good random numbers, suitable for key generation, seeding TCP sequence
- * numbers, etc. In order to ensure that the randomness returned by this
- * function is okay, the function wait_for_random_bytes() should be called and
- * return 0 at least once at any point prior.
+ * This returns random bytes in arbitrary quantities. The quality of the
+ * random bytes is good as /dev/urandom. In order to ensure that the
+ * randomness provided by this function is okay, the function
+ * wait_for_random_bytes() should be called and return 0 at least once
+ * at any point prior.
*/
void get_random_bytes(void *buf, size_t len)
{
@@ -510,6 +531,41 @@ DEFINE_BATCHED_ENTROPY(u16)
DEFINE_BATCHED_ENTROPY(u32)
DEFINE_BATCHED_ENTROPY(u64)
+u32 __get_random_u32_below(u32 ceil)
+{
+ /*
+ * This is the slow path for variable ceil. It is still fast, most of
+ * the time, by doing traditional reciprocal multiplication and
+ * opportunistically comparing the lower half to ceil itself, before
+ * falling back to computing a larger bound, and then rejecting samples
+ * whose lower half would indicate a range indivisible by ceil. The use
+ * of `-ceil % ceil` is analogous to `2^32 % ceil`, but is computable
+ * in 32-bits.
+ */
+ u32 rand = get_random_u32();
+ u64 mult;
+
+ /*
+ * This function is technically undefined for ceil == 0, and in fact
+ * for the non-underscored constant version in the header, we build bug
+ * on that. But for the non-constant case, it's convenient to have that
+ * evaluate to being a straight call to get_random_u32(), so that
+ * get_random_u32_inclusive() can work over its whole range without
+ * undefined behavior.
+ */
+ if (unlikely(!ceil))
+ return rand;
+
+ mult = (u64)ceil * rand;
+ if (unlikely((u32)mult < ceil)) {
+ u32 bound = -ceil % ceil;
+ while (unlikely((u32)mult < bound))
+ mult = (u64)ceil * get_random_u32();
+ }
+ return mult >> 32;
+}
+EXPORT_SYMBOL(__get_random_u32_below);
+
#ifdef CONFIG_SMP
/*
* This function is called when the CPU is coming up, with entry
@@ -660,9 +716,10 @@ static void __cold _credit_init_bits(size_t bits)
} while (!try_cmpxchg(&input_pool.init_bits, &orig, new));
if (orig < POOL_READY_BITS && new >= POOL_READY_BITS) {
- crng_reseed(); /* Sets crng_init to CRNG_READY under base_crng.lock. */
+ crng_reseed(NULL); /* Sets crng_init to CRNG_READY under base_crng.lock. */
if (static_key_initialized)
execute_in_process_context(crng_set_ready, &set_ready);
+ atomic_notifier_call_chain(&random_ready_notifier, 0, NULL);
wake_up_interruptible(&crng_init_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
pr_notice("crng init done\n");
@@ -689,7 +746,7 @@ static void __cold _credit_init_bits(size_t bits)
* the above entropy accumulation routines:
*
* void add_device_randomness(const void *buf, size_t len);
- * void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
+ * void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy, bool sleep_after);
* void add_bootloader_randomness(const void *buf, size_t len);
* void add_vmfork_randomness(const void *unique_vm_id, size_t len);
* void add_interrupt_randomness(int irq);
@@ -710,7 +767,7 @@ static void __cold _credit_init_bits(size_t bits)
*
* add_bootloader_randomness() is called by bootloader drivers, such as EFI
* and device tree, and credits its input depending on whether or not the
- * configuration option CONFIG_RANDOM_TRUST_BOOTLOADER is set.
+ * command line option 'random.trust_bootloader'.
*
* add_vmfork_randomness() adds a unique (but not necessarily secret) ID
* representing the current instance of a VM to the pool, without crediting,
@@ -736,8 +793,8 @@ static void __cold _credit_init_bits(size_t bits)
*
**********************************************************************/
-static bool trust_cpu __initdata = IS_ENABLED(CONFIG_RANDOM_TRUST_CPU);
-static bool trust_bootloader __initdata = IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER);
+static bool trust_cpu __initdata = true;
+static bool trust_bootloader __initdata = true;
static int __init parse_trust_cpu(char *arg)
{
return kstrtobool(arg, &trust_cpu);
@@ -768,7 +825,7 @@ static int random_pm_notification(struct notifier_block *nb, unsigned long actio
if (crng_ready() && (action == PM_RESTORE_PREPARE ||
(action == PM_POST_SUSPEND && !IS_ENABLED(CONFIG_PM_AUTOSLEEP) &&
!IS_ENABLED(CONFIG_PM_USERSPACE_AUTOSLEEP)))) {
- crng_reseed();
+ crng_reseed(NULL);
pr_notice("crng reseeded on system resumption\n");
}
return 0;
@@ -791,13 +848,13 @@ void __init random_init_early(const char *command_line)
#endif
for (i = 0, arch_bits = sizeof(entropy) * 8; i < ARRAY_SIZE(entropy);) {
- longs = arch_get_random_seed_longs_early(entropy, ARRAY_SIZE(entropy) - i);
+ longs = arch_get_random_seed_longs(entropy, ARRAY_SIZE(entropy) - i);
if (longs) {
_mix_pool_bytes(entropy, sizeof(*entropy) * longs);
i += longs;
continue;
}
- longs = arch_get_random_longs_early(entropy, ARRAY_SIZE(entropy) - i);
+ longs = arch_get_random_longs(entropy, ARRAY_SIZE(entropy) - i);
if (longs) {
_mix_pool_bytes(entropy, sizeof(*entropy) * longs);
i += longs;
@@ -812,7 +869,7 @@ void __init random_init_early(const char *command_line)
/* Reseed if already seeded by earlier phases. */
if (crng_ready())
- crng_reseed();
+ crng_reseed(NULL);
else if (trust_cpu)
_credit_init_bits(arch_bits);
}
@@ -840,7 +897,7 @@ void __init random_init(void)
/* Reseed if already seeded by earlier phases. */
if (crng_ready())
- crng_reseed();
+ crng_reseed(NULL);
WARN_ON(register_pm_notifier(&pm_notifier));
@@ -869,11 +926,11 @@ void add_device_randomness(const void *buf, size_t len)
EXPORT_SYMBOL(add_device_randomness);
/*
- * Interface for in-kernel drivers of true hardware RNGs.
- * Those devices may produce endless random bits and will be throttled
- * when our pool is full.
+ * Interface for in-kernel drivers of true hardware RNGs. Those devices
+ * may produce endless random bits, so this function will sleep for
+ * some amount of time after, if the sleep_after parameter is true.
*/
-void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
+void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy, bool sleep_after)
{
mix_pool_bytes(buf, len);
credit_init_bits(entropy);
@@ -882,14 +939,14 @@ void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
* Throttle writing to once every reseed interval, unless we're not yet
* initialized or no entropy is credited.
*/
- if (!kthread_should_stop() && (crng_ready() || !entropy))
+ if (sleep_after && !kthread_should_stop() && (crng_ready() || !entropy))
schedule_timeout_interruptible(crng_reseed_interval());
}
EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
/*
- * Handle random seed passed by bootloader, and credit it if
- * CONFIG_RANDOM_TRUST_BOOTLOADER is set.
+ * Handle random seed passed by bootloader, and credit it depending
+ * on the command line option 'random.trust_bootloader'.
*/
void __init add_bootloader_randomness(const void *buf, size_t len)
{
@@ -910,7 +967,7 @@ void __cold add_vmfork_randomness(const void *unique_vm_id, size_t len)
{
add_device_randomness(unique_vm_id, len);
if (crng_ready()) {
- crng_reseed();
+ crng_reseed(NULL);
pr_notice("crng reseeded due to virtual machine fork\n");
}
blocking_notifier_call_chain(&vmfork_chain, 0, NULL);
@@ -1176,66 +1233,102 @@ void __cold rand_initialize_disk(struct gendisk *disk)
struct entropy_timer_state {
unsigned long entropy;
struct timer_list timer;
- unsigned int samples, samples_per_bit;
+ atomic_t samples;
+ unsigned int samples_per_bit;
};
/*
- * Each time the timer fires, we expect that we got an unpredictable
- * jump in the cycle counter. Even if the timer is running on another
- * CPU, the timer activity will be touching the stack of the CPU that is
- * generating entropy..
+ * Each time the timer fires, we expect that we got an unpredictable jump in
+ * the cycle counter. Even if the timer is running on another CPU, the timer
+ * activity will be touching the stack of the CPU that is generating entropy.
*
- * Note that we don't re-arm the timer in the timer itself - we are
- * happy to be scheduled away, since that just makes the load more
- * complex, but we do not want the timer to keep ticking unless the
- * entropy loop is running.
+ * Note that we don't re-arm the timer in the timer itself - we are happy to be
+ * scheduled away, since that just makes the load more complex, but we do not
+ * want the timer to keep ticking unless the entropy loop is running.
*
* So the re-arming always happens in the entropy loop itself.
*/
static void __cold entropy_timer(struct timer_list *timer)
{
struct entropy_timer_state *state = container_of(timer, struct entropy_timer_state, timer);
+ unsigned long entropy = random_get_entropy();
- if (++state->samples == state->samples_per_bit) {
+ mix_pool_bytes(&entropy, sizeof(entropy));
+ if (atomic_inc_return(&state->samples) % state->samples_per_bit == 0)
credit_init_bits(1);
- state->samples = 0;
- }
}
/*
- * If we have an actual cycle counter, see if we can
- * generate enough entropy with timing noise
+ * If we have an actual cycle counter, see if we can generate enough entropy
+ * with timing noise.
*/
static void __cold try_to_generate_entropy(void)
{
enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = HZ / 15 };
- struct entropy_timer_state stack;
+ u8 stack_bytes[sizeof(struct entropy_timer_state) + SMP_CACHE_BYTES - 1];
+ struct entropy_timer_state *stack = PTR_ALIGN((void *)stack_bytes, SMP_CACHE_BYTES);
unsigned int i, num_different = 0;
unsigned long last = random_get_entropy();
+ int cpu = -1;
for (i = 0; i < NUM_TRIAL_SAMPLES - 1; ++i) {
- stack.entropy = random_get_entropy();
- if (stack.entropy != last)
+ stack->entropy = random_get_entropy();
+ if (stack->entropy != last)
++num_different;
- last = stack.entropy;
+ last = stack->entropy;
}
- stack.samples_per_bit = DIV_ROUND_UP(NUM_TRIAL_SAMPLES, num_different + 1);
- if (stack.samples_per_bit > MAX_SAMPLES_PER_BIT)
+ stack->samples_per_bit = DIV_ROUND_UP(NUM_TRIAL_SAMPLES, num_different + 1);
+ if (stack->samples_per_bit > MAX_SAMPLES_PER_BIT)
return;
- stack.samples = 0;
- timer_setup_on_stack(&stack.timer, entropy_timer, 0);
+ atomic_set(&stack->samples, 0);
+ timer_setup_on_stack(&stack->timer, entropy_timer, 0);
while (!crng_ready() && !signal_pending(current)) {
- if (!timer_pending(&stack.timer))
- mod_timer(&stack.timer, jiffies);
- mix_pool_bytes(&stack.entropy, sizeof(stack.entropy));
+ /*
+ * Check !timer_pending() and then ensure that any previous callback has finished
+ * executing by checking try_to_del_timer_sync(), before queueing the next one.
+ */
+ if (!timer_pending(&stack->timer) && try_to_del_timer_sync(&stack->timer) >= 0) {
+ struct cpumask timer_cpus;
+ unsigned int num_cpus;
+
+ /*
+ * Preemption must be disabled here, both to read the current CPU number
+ * and to avoid scheduling a timer on a dead CPU.
+ */
+ preempt_disable();
+
+ /* Only schedule callbacks on timer CPUs that are online. */
+ cpumask_and(&timer_cpus, housekeeping_cpumask(HK_TYPE_TIMER), cpu_online_mask);
+ num_cpus = cpumask_weight(&timer_cpus);
+ /* In very bizarre case of misconfiguration, fallback to all online. */
+ if (unlikely(num_cpus == 0)) {
+ timer_cpus = *cpu_online_mask;
+ num_cpus = cpumask_weight(&timer_cpus);
+ }
+
+ /* Basic CPU round-robin, which avoids the current CPU. */
+ do {
+ cpu = cpumask_next(cpu, &timer_cpus);
+ if (cpu == nr_cpumask_bits)
+ cpu = cpumask_first(&timer_cpus);
+ } while (cpu == smp_processor_id() && num_cpus > 1);
+
+ /* Expiring the timer at `jiffies` means it's the next tick. */
+ stack->timer.expires = jiffies;
+
+ add_timer_on(&stack->timer, cpu);
+
+ preempt_enable();
+ }
+ mix_pool_bytes(&stack->entropy, sizeof(stack->entropy));
schedule();
- stack.entropy = random_get_entropy();
+ stack->entropy = random_get_entropy();
}
+ mix_pool_bytes(&stack->entropy, sizeof(stack->entropy));
- del_timer_sync(&stack.timer);
- destroy_timer_on_stack(&stack.timer);
- mix_pool_bytes(&stack.entropy, sizeof(stack.entropy));
+ del_timer_sync(&stack->timer);
+ destroy_timer_on_stack(&stack->timer);
}
@@ -1291,7 +1384,7 @@ SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags
return ret;
}
- ret = import_single_range(READ, ubuf, len, &iov, &iter);
+ ret = import_single_range(ITER_DEST, ubuf, len, &iov, &iter);
if (unlikely(ret))
return ret;
return get_random_bytes_user(&iter);
@@ -1409,7 +1502,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return -EINVAL;
if (get_user(len, p++))
return -EFAULT;
- ret = import_single_range(WRITE, p, len, &iov, &iter);
+ ret = import_single_range(ITER_SOURCE, p, len, &iov, &iter);
if (unlikely(ret))
return ret;
ret = write_pool_user(&iter);
@@ -1432,7 +1525,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return -EPERM;
if (!crng_ready())
return -ENODATA;
- crng_reseed();
+ crng_reseed(NULL);
return 0;
default:
return -EINVAL;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 27e301a6bb7a..9211531689b2 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1123,10 +1123,9 @@ static int sonypi_acpi_add(struct acpi_device *device)
return 0;
}
-static int sonypi_acpi_remove(struct acpi_device *device)
+static void sonypi_acpi_remove(struct acpi_device *device)
{
sonypi_acpi_device = NULL;
- return 0;
}
static const struct acpi_device_id sonypi_device_ids[] = {
diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c
index 1b18ce5ebab1..0913d3eb8d51 100644
--- a/drivers/char/tpm/eventlog/acpi.c
+++ b/drivers/char/tpm/eventlog/acpi.c
@@ -90,16 +90,21 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
return -ENODEV;
if (tbl->header.length <
- sizeof(*tbl) + sizeof(struct acpi_tpm2_phy))
+ sizeof(*tbl) + sizeof(struct acpi_tpm2_phy)) {
+ acpi_put_table((struct acpi_table_header *)tbl);
return -ENODEV;
+ }
tpm2_phy = (void *)tbl + sizeof(*tbl);
len = tpm2_phy->log_area_minimum_length;
start = tpm2_phy->log_area_start_address;
- if (!start || !len)
+ if (!start || !len) {
+ acpi_put_table((struct acpi_table_header *)tbl);
return -ENODEV;
+ }
+ acpi_put_table((struct acpi_table_header *)tbl);
format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
} else {
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
@@ -120,8 +125,10 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
break;
}
+ acpi_put_table((struct acpi_table_header *)buff);
format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
}
+
if (!len) {
dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__);
return -EIO;
@@ -156,5 +163,4 @@ err:
kfree(log->bios_event_log);
log->bios_event_log = NULL;
return ret;
-
}
diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c
index a3aa411389e7..8156bb2af78c 100644
--- a/drivers/char/tpm/st33zp24/i2c.c
+++ b/drivers/char/tpm/st33zp24/i2c.c
@@ -6,13 +6,9 @@
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/tpm.h>
-#include <linux/platform_data/st33zp24.h>
#include "../tpm.h"
#include "st33zp24.h"
@@ -22,7 +18,6 @@
struct st33zp24_i2c_phy {
struct i2c_client *client;
u8 buf[ST33ZP24_BUFSIZE + 1];
- int io_lpcpd;
};
/*
@@ -99,115 +94,6 @@ static const struct st33zp24_phy_ops i2c_phy_ops = {
.recv = st33zp24_i2c_recv,
};
-static const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false };
-
-static const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = {
- { "lpcpd-gpios", &lpcpd_gpios, 1 },
- {},
-};
-
-static int st33zp24_i2c_acpi_request_resources(struct i2c_client *client)
-{
- struct tpm_chip *chip = i2c_get_clientdata(client);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_i2c_phy *phy = tpm_dev->phy_id;
- struct gpio_desc *gpiod_lpcpd;
- struct device *dev = &client->dev;
- int ret;
-
- ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios);
- if (ret)
- return ret;
-
- /* Get LPCPD GPIO from ACPI */
- gpiod_lpcpd = devm_gpiod_get(dev, "lpcpd", GPIOD_OUT_HIGH);
- if (IS_ERR(gpiod_lpcpd)) {
- dev_err(&client->dev,
- "Failed to retrieve lpcpd-gpios from acpi.\n");
- phy->io_lpcpd = -1;
- /*
- * lpcpd pin is not specified. This is not an issue as
- * power management can be also managed by TPM specific
- * commands. So leave with a success status code.
- */
- return 0;
- }
-
- phy->io_lpcpd = desc_to_gpio(gpiod_lpcpd);
-
- return 0;
-}
-
-static int st33zp24_i2c_of_request_resources(struct i2c_client *client)
-{
- struct tpm_chip *chip = i2c_get_clientdata(client);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_i2c_phy *phy = tpm_dev->phy_id;
- struct device_node *pp;
- int gpio;
- int ret;
-
- pp = client->dev.of_node;
- if (!pp) {
- dev_err(&client->dev, "No platform data\n");
- return -ENODEV;
- }
-
- /* Get GPIO from device tree */
- gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
- if (gpio < 0) {
- dev_err(&client->dev,
- "Failed to retrieve lpcpd-gpios from dts.\n");
- phy->io_lpcpd = -1;
- /*
- * lpcpd pin is not specified. This is not an issue as
- * power management can be also managed by TPM specific
- * commands. So leave with a success status code.
- */
- return 0;
- }
- /* GPIO request and configuration */
- ret = devm_gpio_request_one(&client->dev, gpio,
- GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
- if (ret) {
- dev_err(&client->dev, "Failed to request lpcpd pin\n");
- return -ENODEV;
- }
- phy->io_lpcpd = gpio;
-
- return 0;
-}
-
-static int st33zp24_i2c_request_resources(struct i2c_client *client)
-{
- struct tpm_chip *chip = i2c_get_clientdata(client);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_i2c_phy *phy = tpm_dev->phy_id;
- struct st33zp24_platform_data *pdata;
- int ret;
-
- pdata = client->dev.platform_data;
- if (!pdata) {
- dev_err(&client->dev, "No platform data\n");
- return -ENODEV;
- }
-
- /* store for late use */
- phy->io_lpcpd = pdata->io_lpcpd;
-
- if (gpio_is_valid(pdata->io_lpcpd)) {
- ret = devm_gpio_request_one(&client->dev,
- pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
- "TPM IO_LPCPD");
- if (ret) {
- dev_err(&client->dev, "Failed to request lpcpd pin\n");
- return ret;
- }
- }
-
- return 0;
-}
-
/*
* st33zp24_i2c_probe initialize the TPM device
* @param: client, the i2c_client description (TPM I2C description).
@@ -218,16 +104,8 @@ static int st33zp24_i2c_request_resources(struct i2c_client *client)
static int st33zp24_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int ret;
- struct st33zp24_platform_data *pdata;
struct st33zp24_i2c_phy *phy;
- if (!client) {
- pr_info("%s: i2c client is NULL. Device not accessible.\n",
- __func__);
- return -ENODEV;
- }
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_info(&client->dev, "client not i2c capable\n");
return -ENODEV;
@@ -240,23 +118,7 @@ static int st33zp24_i2c_probe(struct i2c_client *client,
phy->client = client;
- pdata = client->dev.platform_data;
- if (!pdata && client->dev.of_node) {
- ret = st33zp24_i2c_of_request_resources(client);
- if (ret)
- return ret;
- } else if (pdata) {
- ret = st33zp24_i2c_request_resources(client);
- if (ret)
- return ret;
- } else if (ACPI_HANDLE(&client->dev)) {
- ret = st33zp24_i2c_acpi_request_resources(client);
- if (ret)
- return ret;
- }
-
- return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq,
- phy->io_lpcpd);
+ return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq);
}
/*
diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c
index 22d184884694..2154059f0235 100644
--- a/drivers/char/tpm/st33zp24/spi.c
+++ b/drivers/char/tpm/st33zp24/spi.c
@@ -6,13 +6,9 @@
#include <linux/module.h>
#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/tpm.h>
-#include <linux/platform_data/st33zp24.h>
#include "../tpm.h"
#include "st33zp24.h"
@@ -61,7 +57,6 @@ struct st33zp24_spi_phy {
u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE];
u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE];
- int io_lpcpd;
int latency;
};
@@ -218,115 +213,6 @@ static const struct st33zp24_phy_ops spi_phy_ops = {
.recv = st33zp24_spi_recv,
};
-static const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false };
-
-static const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = {
- { "lpcpd-gpios", &lpcpd_gpios, 1 },
- {},
-};
-
-static int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev)
-{
- struct tpm_chip *chip = spi_get_drvdata(spi_dev);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_spi_phy *phy = tpm_dev->phy_id;
- struct gpio_desc *gpiod_lpcpd;
- struct device *dev = &spi_dev->dev;
- int ret;
-
- ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios);
- if (ret)
- return ret;
-
- /* Get LPCPD GPIO from ACPI */
- gpiod_lpcpd = devm_gpiod_get(dev, "lpcpd", GPIOD_OUT_HIGH);
- if (IS_ERR(gpiod_lpcpd)) {
- dev_err(dev, "Failed to retrieve lpcpd-gpios from acpi.\n");
- phy->io_lpcpd = -1;
- /*
- * lpcpd pin is not specified. This is not an issue as
- * power management can be also managed by TPM specific
- * commands. So leave with a success status code.
- */
- return 0;
- }
-
- phy->io_lpcpd = desc_to_gpio(gpiod_lpcpd);
-
- return 0;
-}
-
-static int st33zp24_spi_of_request_resources(struct spi_device *spi_dev)
-{
- struct tpm_chip *chip = spi_get_drvdata(spi_dev);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_spi_phy *phy = tpm_dev->phy_id;
- struct device_node *pp;
- int gpio;
- int ret;
-
- pp = spi_dev->dev.of_node;
- if (!pp) {
- dev_err(&spi_dev->dev, "No platform data\n");
- return -ENODEV;
- }
-
- /* Get GPIO from device tree */
- gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
- if (gpio < 0) {
- dev_err(&spi_dev->dev,
- "Failed to retrieve lpcpd-gpios from dts.\n");
- phy->io_lpcpd = -1;
- /*
- * lpcpd pin is not specified. This is not an issue as
- * power management can be also managed by TPM specific
- * commands. So leave with a success status code.
- */
- return 0;
- }
- /* GPIO request and configuration */
- ret = devm_gpio_request_one(&spi_dev->dev, gpio,
- GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
- if (ret) {
- dev_err(&spi_dev->dev, "Failed to request lpcpd pin\n");
- return -ENODEV;
- }
- phy->io_lpcpd = gpio;
-
- return 0;
-}
-
-static int st33zp24_spi_request_resources(struct spi_device *dev)
-{
- struct tpm_chip *chip = spi_get_drvdata(dev);
- struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
- struct st33zp24_spi_phy *phy = tpm_dev->phy_id;
- struct st33zp24_platform_data *pdata;
- int ret;
-
- pdata = dev->dev.platform_data;
- if (!pdata) {
- dev_err(&dev->dev, "No platform data\n");
- return -ENODEV;
- }
-
- /* store for late use */
- phy->io_lpcpd = pdata->io_lpcpd;
-
- if (gpio_is_valid(pdata->io_lpcpd)) {
- ret = devm_gpio_request_one(&dev->dev,
- pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
- "TPM IO_LPCPD");
- if (ret) {
- dev_err(&dev->dev, "%s : reset gpio_request failed\n",
- __FILE__);
- return ret;
- }
- }
-
- return 0;
-}
-
/*
* st33zp24_spi_probe initialize the TPM device
* @param: dev, the spi_device description (TPM SPI description).
@@ -335,17 +221,8 @@ static int st33zp24_spi_request_resources(struct spi_device *dev)
*/
static int st33zp24_spi_probe(struct spi_device *dev)
{
- int ret;
- struct st33zp24_platform_data *pdata;
struct st33zp24_spi_phy *phy;
- /* Check SPI platform functionnalities */
- if (!dev) {
- pr_info("%s: dev is NULL. Device is not accessible.\n",
- __func__);
- return -ENODEV;
- }
-
phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),
GFP_KERNEL);
if (!phy)
@@ -353,27 +230,11 @@ static int st33zp24_spi_probe(struct spi_device *dev)
phy->spi_device = dev;
- pdata = dev->dev.platform_data;
- if (!pdata && dev->dev.of_node) {
- ret = st33zp24_spi_of_request_resources(dev);
- if (ret)
- return ret;
- } else if (pdata) {
- ret = st33zp24_spi_request_resources(dev);
- if (ret)
- return ret;
- } else if (ACPI_HANDLE(&dev->dev)) {
- ret = st33zp24_spi_acpi_request_resources(dev);
- if (ret)
- return ret;
- }
-
phy->latency = st33zp24_spi_evaluate_latency(phy);
if (phy->latency <= 0)
return -ENODEV;
- return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq,
- phy->io_lpcpd);
+ return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq);
}
/*
@@ -411,7 +272,7 @@ static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,
static struct spi_driver st33zp24_spi_driver = {
.driver = {
- .name = TPM_ST33_SPI,
+ .name = "st33zp24-spi",
.pm = &st33zp24_spi_ops,
.of_match_table = of_match_ptr(of_st33zp24_spi_match),
.acpi_match_table = ACPI_PTR(st33zp24_spi_acpi_match),
diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c
index 15b393e92c8e..a5b554cd4778 100644
--- a/drivers/char/tpm/st33zp24/st33zp24.c
+++ b/drivers/char/tpm/st33zp24/st33zp24.c
@@ -4,6 +4,7 @@
* Copyright (C) 2009 - 2016 STMicroelectronics
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -12,7 +13,7 @@
#include <linux/freezer.h>
#include <linux/string.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/io.h>
@@ -432,11 +433,18 @@ static const struct tpm_class_ops st33zp24_tpm = {
.req_canceled = st33zp24_req_canceled,
};
+static const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = {
+ { "lpcpd-gpios", &lpcpd_gpios, 1 },
+ { },
+};
+
/*
* initialize the TPM device
*/
int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
- struct device *dev, int irq, int io_lpcpd)
+ struct device *dev, int irq)
{
int ret;
u8 intmask = 0;
@@ -463,6 +471,25 @@ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
tpm_dev->locality = LOCALITY0;
+ if (ACPI_COMPANION(dev)) {
+ ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Get LPCPD GPIO. If lpcpd pin is not specified. This is not an
+ * issue as power management can be also managed by TPM specific
+ * commands.
+ */
+ tpm_dev->io_lpcpd = devm_gpiod_get_optional(dev, "lpcpd",
+ GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(tpm_dev->io_lpcpd);
+ if (ret) {
+ dev_err(dev, "failed to request lpcpd gpio: %d\n", ret);
+ return ret;
+ }
+
if (irq) {
/* INTERRUPT Setup */
init_waitqueue_head(&tpm_dev->read_queue);
@@ -525,8 +552,8 @@ int st33zp24_pm_suspend(struct device *dev)
int ret = 0;
- if (gpio_is_valid(tpm_dev->io_lpcpd))
- gpio_set_value(tpm_dev->io_lpcpd, 0);
+ if (tpm_dev->io_lpcpd)
+ gpiod_set_value_cansleep(tpm_dev->io_lpcpd, 0);
else
ret = tpm_pm_suspend(dev);
@@ -540,8 +567,8 @@ int st33zp24_pm_resume(struct device *dev)
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
int ret = 0;
- if (gpio_is_valid(tpm_dev->io_lpcpd)) {
- gpio_set_value(tpm_dev->io_lpcpd, 1);
+ if (tpm_dev->io_lpcpd) {
+ gpiod_set_value_cansleep(tpm_dev->io_lpcpd, 1);
ret = wait_for_stat(chip,
TPM_STS_VALID, chip->timeout_b,
&tpm_dev->read_queue, false);
diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h
index b387a476c555..5acc85f711e6 100644
--- a/drivers/char/tpm/st33zp24/st33zp24.h
+++ b/drivers/char/tpm/st33zp24/st33zp24.h
@@ -7,6 +7,9 @@
#ifndef __LOCAL_ST33ZP24_H__
#define __LOCAL_ST33ZP24_H__
+#define TPM_ST33_I2C "st33zp24-i2c"
+#define TPM_ST33_SPI "st33zp24-spi"
+
#define TPM_WRITE_DIRECTION 0x80
#define ST33ZP24_BUFSIZE 2048
@@ -17,7 +20,7 @@ struct st33zp24_dev {
int locality;
int irq;
u32 intrs;
- int io_lpcpd;
+ struct gpio_desc *io_lpcpd;
wait_queue_head_t read_queue;
};
@@ -33,6 +36,6 @@ int st33zp24_pm_resume(struct device *dev);
#endif
int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
- struct device *dev, int irq, int io_lpcpd);
+ struct device *dev, int irq);
void st33zp24_remove(struct tpm_chip *chip);
#endif /* __LOCAL_ST33ZP24_H__ */
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 783d65fc71f0..741d8f3e8fb3 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -373,6 +373,11 @@ out:
}
EXPORT_SYMBOL_GPL(tpm_chip_alloc);
+static void tpm_put_device(void *dev)
+{
+ put_device(dev);
+}
+
/**
* tpmm_chip_alloc() - allocate a new struct tpm_chip instance
* @pdev: parent device to which the chip is associated
@@ -391,7 +396,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *pdev,
return chip;
rc = devm_add_action_or_reset(pdev,
- (void (*)(void *)) put_device,
+ tpm_put_device,
&chip->dev);
if (rc)
return ERR_PTR(rc);
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index dc4c0a0a5129..30b4c288c1bb 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -155,7 +155,7 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
out:
if (!priv->response_length) {
*off = 0;
- del_singleshot_timer_sync(&priv->user_read_timer);
+ del_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work);
}
mutex_unlock(&priv->buffer_mutex);
@@ -262,7 +262,7 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait)
void tpm_common_release(struct file *file, struct file_priv *priv)
{
flush_work(&priv->async_work);
- del_singleshot_timer_sync(&priv->user_read_timer);
+ del_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work);
file->private_data = NULL;
priv->response_length = 0;
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 1621ce818705..d69905233aff 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -401,13 +401,14 @@ int tpm_pm_suspend(struct device *dev)
!pm_suspend_via_firmware())
goto suspended;
- if (!tpm_chip_start(chip)) {
+ rc = tpm_try_get_ops(chip);
+ if (!rc) {
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_STATE);
else
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
- tpm_chip_stop(chip);
+ tpm_put_ops(chip);
}
suspended:
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 18606651d1aa..7e9da671a0e8 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -252,7 +252,7 @@ static int __crb_relinquish_locality(struct device *dev,
iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl);
if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, mask, value,
TPM2_TIMEOUT_C)) {
- dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
+ dev_warn(dev, "TPM_LOC_STATE_x.Relinquish timed out\n");
return -ETIME;
}
@@ -676,12 +676,16 @@ static int crb_acpi_add(struct acpi_device *device)
/* Should the FIFO driver handle this? */
sm = buf->start_method;
- if (sm == ACPI_TPM2_MEMORY_MAPPED)
- return -ENODEV;
+ if (sm == ACPI_TPM2_MEMORY_MAPPED) {
+ rc = -ENODEV;
+ goto out;
+ }
priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ if (!priv) {
+ rc = -ENOMEM;
+ goto out;
+ }
if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
@@ -689,7 +693,8 @@ static int crb_acpi_add(struct acpi_device *device)
FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
buf->header.length,
ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
priv->smc_func_id = crb_smc->smc_func_id;
@@ -700,27 +705,31 @@ static int crb_acpi_add(struct acpi_device *device)
rc = crb_map_io(device, priv, buf);
if (rc)
- return rc;
+ goto out;
chip = tpmm_chip_alloc(dev, &tpm_crb);
- if (IS_ERR(chip))
- return PTR_ERR(chip);
+ if (IS_ERR(chip)) {
+ rc = PTR_ERR(chip);
+ goto out;
+ }
dev_set_drvdata(&chip->dev, priv);
chip->acpi_dev_handle = device->handle;
chip->flags = TPM_CHIP_FLAG_TPM2;
- return tpm_chip_register(chip);
+ rc = tpm_chip_register(chip);
+
+out:
+ acpi_put_table((struct acpi_table_header *)buf);
+ return rc;
}
-static int crb_acpi_remove(struct acpi_device *device)
+static void crb_acpi_remove(struct acpi_device *device)
{
struct device *dev = &device->dev;
struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_chip_unregister(chip);
-
- return 0;
}
static const struct dev_pm_ops crb_pm = {
diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c
index 5c233423c56f..deff23bb54bf 100644
--- a/drivers/char/tpm/tpm_ftpm_tee.c
+++ b/drivers/char/tpm/tpm_ftpm_tee.c
@@ -397,7 +397,13 @@ static int __init ftpm_mod_init(void)
if (rc)
return rc;
- return driver_register(&ftpm_tee_driver.driver);
+ rc = driver_register(&ftpm_tee_driver.driver);
+ if (rc) {
+ platform_driver_unregister(&ftpm_tee_plat_driver);
+ return rc;
+ }
+
+ return 0;
}
static void __exit ftpm_mod_exit(void)
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index bcff6429e0b4..ed5dabd3c72d 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -125,6 +125,7 @@ static int check_acpi_tpm2(struct device *dev)
const struct acpi_device_id *aid = acpi_match_device(tpm_acpi_tbl, dev);
struct acpi_table_tpm2 *tbl;
acpi_status st;
+ int ret = 0;
if (!aid || aid->driver_data != DEVICE_IS_TPM2)
return 0;
@@ -132,8 +133,7 @@ static int check_acpi_tpm2(struct device *dev)
/* If the ACPI TPM2 signature is matched then a global ACPI_SIG_TPM2
* table is mandatory
*/
- st =
- acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
+ st = acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
return -EINVAL;
@@ -141,9 +141,10 @@ static int check_acpi_tpm2(struct device *dev)
/* The tpm2_crb driver handles this device */
if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
- return -ENODEV;
+ ret = -ENODEV;
- return 0;
+ acpi_put_table((struct acpi_table_header *)tbl);
+ return ret;
}
#else
static int check_acpi_tpm2(struct device *dev)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 757623bacfd5..3f98e587b3e8 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -682,15 +682,19 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- switch (priv->manufacturer_id) {
- case TPM_VID_WINBOND:
- return ((status == TPM_STS_VALID) ||
- (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
- case TPM_VID_STM:
- return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
- default:
- return (status == TPM_STS_COMMAND_READY);
+ if (!test_bit(TPM_TIS_DEFAULT_CANCELLATION, &priv->flags)) {
+ switch (priv->manufacturer_id) {
+ case TPM_VID_WINBOND:
+ return ((status == TPM_STS_VALID) ||
+ (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
+ case TPM_VID_STM:
+ return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
+ default:
+ break;
+ }
}
+
+ return status == TPM_STS_COMMAND_READY;
}
static irqreturn_t tis_int_handler(int dummy, void *dev_id)
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 66a5a13cd1df..b68479e0de10 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -86,6 +86,7 @@ enum tis_defaults {
enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = BIT(0),
TPM_TIS_INVALID_STATUS = BIT(1),
+ TPM_TIS_DEFAULT_CANCELLATION = BIT(2),
};
struct tpm_tis_data {
diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c
index 0692510dfcab..f3a7251c8e38 100644
--- a/drivers/char/tpm/tpm_tis_i2c.c
+++ b/drivers/char/tpm/tpm_tis_i2c.c
@@ -49,7 +49,7 @@
/* Masks with bits that must be read zero */
#define TPM_ACCESS_READ_ZERO 0x48
-#define TPM_INT_ENABLE_ZERO 0x7FFFFF6
+#define TPM_INT_ENABLE_ZERO 0x7FFFFF60
#define TPM_STS_READ_ZERO 0x23
#define TPM_INTF_CAPABILITY_ZERO 0x0FFFF000
#define TPM_I2C_INTERFACE_CAPABILITY_ZERO 0x80000000
@@ -329,6 +329,7 @@ static int tpm_tis_i2c_probe(struct i2c_client *dev,
if (!phy->io_buf)
return -ENOMEM;
+ set_bit(TPM_TIS_DEFAULT_CANCELLATION, &phy->priv.flags);
phy->i2c_client = dev;
/* must precede all communication with the tpm */
diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c
index b174f727a8ef..16870943a13e 100644
--- a/drivers/clk/at91/at91rm9200.c
+++ b/drivers/clk/at91/at91rm9200.c
@@ -40,7 +40,7 @@ static const struct clk_pll_characteristics rm9200_pll_characteristics = {
};
static const struct sck at91rm9200_systemck[] = {
- { .n = "udpck", .p = "usbck", .id = 2 },
+ { .n = "udpck", .p = "usbck", .id = 1 },
{ .n = "uhpck", .p = "usbck", .id = 4 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
index 679f4649a7ef..ce2f93479736 100644
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -18,25 +18,6 @@
#include <soc/bcm2835/raspberrypi-firmware.h>
-enum rpi_firmware_clk_id {
- RPI_FIRMWARE_EMMC_CLK_ID = 1,
- RPI_FIRMWARE_UART_CLK_ID,
- RPI_FIRMWARE_ARM_CLK_ID,
- RPI_FIRMWARE_CORE_CLK_ID,
- RPI_FIRMWARE_V3D_CLK_ID,
- RPI_FIRMWARE_H264_CLK_ID,
- RPI_FIRMWARE_ISP_CLK_ID,
- RPI_FIRMWARE_SDRAM_CLK_ID,
- RPI_FIRMWARE_PIXEL_CLK_ID,
- RPI_FIRMWARE_PWM_CLK_ID,
- RPI_FIRMWARE_HEVC_CLK_ID,
- RPI_FIRMWARE_EMMC2_CLK_ID,
- RPI_FIRMWARE_M2MC_CLK_ID,
- RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
- RPI_FIRMWARE_VEC_CLK_ID,
- RPI_FIRMWARE_NUM_CLK_ID,
-};
-
static char *rpi_firmware_clk_names[] = {
[RPI_FIRMWARE_EMMC_CLK_ID] = "emmc",
[RPI_FIRMWARE_UART_CLK_ID] = "uart",
diff --git a/drivers/clk/qcom/gcc-sc8280xp.c b/drivers/clk/qcom/gcc-sc8280xp.c
index a18ed88f3b82..b3198784e1c3 100644
--- a/drivers/clk/qcom/gcc-sc8280xp.c
+++ b/drivers/clk/qcom/gcc-sc8280xp.c
@@ -5364,6 +5364,8 @@ static struct clk_branch gcc_ufs_1_card_clkref_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "gcc_ufs_1_card_clkref_clk",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
.ops = &clk_branch2_ops,
},
},
@@ -5432,6 +5434,8 @@ static struct clk_branch gcc_ufs_card_clkref_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "gcc_ufs_card_clkref_clk",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
.ops = &clk_branch2_ops,
},
},
@@ -5848,6 +5852,8 @@ static struct clk_branch gcc_ufs_ref_clkref_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "gcc_ufs_ref_clkref_clk",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
.ops = &clk_branch2_ops,
},
},
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 7cf5e130e92f..0f21a8a767ac 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset-controller.h>
@@ -56,22 +55,6 @@ enum gdsc_status {
GDSC_ON
};
-static int gdsc_pm_runtime_get(struct gdsc *sc)
-{
- if (!sc->dev)
- return 0;
-
- return pm_runtime_resume_and_get(sc->dev);
-}
-
-static int gdsc_pm_runtime_put(struct gdsc *sc)
-{
- if (!sc->dev)
- return 0;
-
- return pm_runtime_put_sync(sc->dev);
-}
-
/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
{
@@ -271,8 +254,9 @@ static void gdsc_retain_ff_on(struct gdsc *sc)
regmap_update_bits(sc->regmap, sc->gdscr, mask, mask);
}
-static int _gdsc_enable(struct gdsc *sc)
+static int gdsc_enable(struct generic_pm_domain *domain)
{
+ struct gdsc *sc = domain_to_gdsc(domain);
int ret;
if (sc->pwrsts == PWRSTS_ON)
@@ -328,22 +312,11 @@ static int _gdsc_enable(struct gdsc *sc)
return 0;
}
-static int gdsc_enable(struct generic_pm_domain *domain)
+static int gdsc_disable(struct generic_pm_domain *domain)
{
struct gdsc *sc = domain_to_gdsc(domain);
int ret;
- ret = gdsc_pm_runtime_get(sc);
- if (ret)
- return ret;
-
- return _gdsc_enable(sc);
-}
-
-static int _gdsc_disable(struct gdsc *sc)
-{
- int ret;
-
if (sc->pwrsts == PWRSTS_ON)
return gdsc_assert_reset(sc);
@@ -388,18 +361,6 @@ static int _gdsc_disable(struct gdsc *sc)
return 0;
}
-static int gdsc_disable(struct generic_pm_domain *domain)
-{
- struct gdsc *sc = domain_to_gdsc(domain);
- int ret;
-
- ret = _gdsc_disable(sc);
-
- gdsc_pm_runtime_put(sc);
-
- return ret;
-}
-
static int gdsc_init(struct gdsc *sc)
{
u32 mask, val;
@@ -447,11 +408,6 @@ static int gdsc_init(struct gdsc *sc)
return ret;
}
- /* ...and the power-domain */
- ret = gdsc_pm_runtime_get(sc);
- if (ret)
- goto err_disable_supply;
-
/*
* Votable GDSCs can be ON due to Vote from other masters.
* If a Votable GDSC is ON, make sure we have a Vote.
@@ -459,14 +415,14 @@ static int gdsc_init(struct gdsc *sc)
if (sc->flags & VOTABLE) {
ret = gdsc_update_collapse_bit(sc, false);
if (ret)
- goto err_put_rpm;
+ goto err_disable_supply;
}
/* Turn on HW trigger mode if supported */
if (sc->flags & HW_CTRL) {
ret = gdsc_hwctrl(sc, true);
if (ret < 0)
- goto err_put_rpm;
+ goto err_disable_supply;
}
/*
@@ -496,13 +452,10 @@ static int gdsc_init(struct gdsc *sc)
ret = pm_genpd_init(&sc->pd, NULL, !on);
if (ret)
- goto err_put_rpm;
+ goto err_disable_supply;
return 0;
-err_put_rpm:
- if (on)
- gdsc_pm_runtime_put(sc);
err_disable_supply:
if (on && sc->rsupply)
regulator_disable(sc->rsupply);
@@ -541,8 +494,6 @@ int gdsc_register(struct gdsc_desc *desc,
for (i = 0; i < num; i++) {
if (!scs[i])
continue;
- if (pm_runtime_enabled(dev))
- scs[i]->dev = dev;
scs[i]->regmap = regmap;
scs[i]->rcdev = rcdev;
ret = gdsc_init(scs[i]);
diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index 981a12c8502d..803512688336 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -30,7 +30,6 @@ struct reset_controller_dev;
* @resets: ids of resets associated with this gdsc
* @reset_count: number of @resets
* @rcdev: reset controller
- * @dev: the device holding the GDSC, used for pm_runtime calls
*/
struct gdsc {
struct generic_pm_domain pd;
@@ -74,7 +73,6 @@ struct gdsc {
const char *supply;
struct regulator *rsupply;
- struct device *dev;
};
struct gdsc_desc {
diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c
index 273f77d54dab..e6d6cbf8c4e6 100644
--- a/drivers/clk/samsung/clk-exynos-clkout.c
+++ b/drivers/clk/samsung/clk-exynos-clkout.c
@@ -81,17 +81,19 @@ MODULE_DEVICE_TABLE(of, exynos_clkout_ids);
static int exynos_clkout_match_parent_dev(struct device *dev, u32 *mux_mask)
{
const struct exynos_clkout_variant *variant;
+ const struct of_device_id *match;
if (!dev->parent) {
dev_err(dev, "not instantiated from MFD\n");
return -EINVAL;
}
- variant = of_device_get_match_data(dev->parent);
- if (!variant) {
+ match = of_match_device(exynos_clkout_ids, dev->parent);
+ if (!match) {
dev_err(dev, "cannot match parent device\n");
return -EINVAL;
}
+ variant = match->data;
*mux_mask = variant->mux_mask;
diff --git a/drivers/clk/samsung/clk-exynos7885.c b/drivers/clk/samsung/clk-exynos7885.c
index 62ce6814f141..0d2a950ed184 100644
--- a/drivers/clk/samsung/clk-exynos7885.c
+++ b/drivers/clk/samsung/clk-exynos7885.c
@@ -231,7 +231,7 @@ static const struct samsung_div_clock top_div_clks[] __initconst = {
CLK_CON_DIV_PLL_SHARED0_DIV2, 0, 1),
DIV(CLK_DOUT_SHARED0_DIV3, "dout_shared0_div3", "fout_shared0_pll",
CLK_CON_DIV_PLL_SHARED0_DIV3, 0, 2),
- DIV(CLK_DOUT_SHARED0_DIV4, "dout_shared0_div4", "fout_shared0_pll",
+ DIV(CLK_DOUT_SHARED0_DIV4, "dout_shared0_div4", "dout_shared0_div2",
CLK_CON_DIV_PLL_SHARED0_DIV4, 0, 1),
DIV(CLK_DOUT_SHARED0_DIV5, "dout_shared0_div5", "fout_shared0_pll",
CLK_CON_DIV_PLL_SHARED0_DIV5, 0, 3),
@@ -239,7 +239,7 @@ static const struct samsung_div_clock top_div_clks[] __initconst = {
CLK_CON_DIV_PLL_SHARED1_DIV2, 0, 1),
DIV(CLK_DOUT_SHARED1_DIV3, "dout_shared1_div3", "fout_shared1_pll",
CLK_CON_DIV_PLL_SHARED1_DIV3, 0, 2),
- DIV(CLK_DOUT_SHARED1_DIV4, "dout_shared1_div4", "fout_shared1_pll",
+ DIV(CLK_DOUT_SHARED1_DIV4, "dout_shared1_div4", "dout_shared1_div2",
CLK_CON_DIV_PLL_SHARED1_DIV4, 0, 1),
/* CORE */
diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c
index d82a71f10c2c..0ecdffaa6b16 100644
--- a/drivers/clk/tegra/clk-bpmp.c
+++ b/drivers/clk/tegra/clk-bpmp.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2016-2020 NVIDIA Corporation
+ * Copyright (C) 2016-2022 NVIDIA Corporation
*/
#include <linux/clk-provider.h>
@@ -310,6 +310,23 @@ static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
.set_rate = tegra_bpmp_clk_set_rate,
};
+static const struct clk_ops tegra_bpmp_clk_mux_read_only_ops = {
+ .get_parent = tegra_bpmp_clk_get_parent,
+ .recalc_rate = tegra_bpmp_clk_recalc_rate,
+};
+
+static const struct clk_ops tegra_bpmp_clk_read_only_ops = {
+ .recalc_rate = tegra_bpmp_clk_recalc_rate,
+};
+
+static const struct clk_ops tegra_bpmp_clk_gate_mux_read_only_ops = {
+ .prepare = tegra_bpmp_clk_prepare,
+ .unprepare = tegra_bpmp_clk_unprepare,
+ .is_prepared = tegra_bpmp_clk_is_prepared,
+ .recalc_rate = tegra_bpmp_clk_recalc_rate,
+ .get_parent = tegra_bpmp_clk_get_parent,
+};
+
static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
{
struct cmd_clk_get_max_clk_id_response response;
@@ -510,8 +527,22 @@ tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
memset(&init, 0, sizeof(init));
init.name = info->name;
clk->hw.init = &init;
-
- if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
+ if (info->flags & BPMP_CLK_STATE_CHANGE_DENIED) {
+ if ((info->flags & BPMP_CLK_RATE_PARENT_CHANGE_DENIED) == 0) {
+ dev_WARN(bpmp->dev,
+ "Firmware bug! Inconsistent permission bits for clock %s. State and parent/rate changes disabled.",
+ init.name);
+ }
+ if (info->flags & TEGRA_BPMP_CLK_HAS_MUX)
+ init.ops = &tegra_bpmp_clk_mux_read_only_ops;
+ else
+ init.ops = &tegra_bpmp_clk_read_only_ops;
+ } else if (info->flags & BPMP_CLK_RATE_PARENT_CHANGE_DENIED) {
+ if (info->flags & TEGRA_BPMP_CLK_HAS_MUX)
+ init.ops = &tegra_bpmp_clk_gate_mux_read_only_ops;
+ else
+ init.ops = &tegra_bpmp_clk_gate_ops;
+ } else if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
init.ops = &tegra_bpmp_clk_mux_rate_ops;
else
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index a7ff77550e17..e09d4427f604 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -18,6 +18,7 @@
#include <linux/clocksource.h>
#include <linux/clocksource_ids.h>
#include <linux/interrupt.h>
+#include <linux/kstrtox.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/io.h>
@@ -97,7 +98,7 @@ static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EV
static int __init early_evtstrm_cfg(char *buf)
{
- return strtobool(buf, &evtstrm_enable);
+ return kstrtobool(buf, &evtstrm_enable);
}
early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
@@ -687,8 +688,8 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id)
return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt);
}
-static __always_inline int timer_shutdown(const int access,
- struct clock_event_device *clk)
+static __always_inline int arch_timer_shutdown(const int access,
+ struct clock_event_device *clk)
{
unsigned long ctrl;
@@ -701,22 +702,22 @@ static __always_inline int timer_shutdown(const int access,
static int arch_timer_shutdown_virt(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
}
static int arch_timer_shutdown_phys(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
}
static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
}
static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
}
static __always_inline void set_next_event(const int access, unsigned long evt,
@@ -806,6 +807,9 @@ static u64 __arch_timer_check_delta(void)
/*
* XGene-1 implements CVAL in terms of TVAL, meaning
* that the maximum timer range is 32bit. Shame on them.
+ *
+ * Note that TVAL is signed, thus has only 31 of its
+ * 32 bits to express magnitude.
*/
MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM,
APM_CPU_PART_POTENZA)),
@@ -813,8 +817,8 @@ static u64 __arch_timer_check_delta(void)
};
if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) {
- pr_warn_once("Broken CNTx_CVAL_EL1, limiting width to 32bits");
- return CLOCKSOURCE_MASK(32);
+ pr_warn_once("Broken CNTx_CVAL_EL1, using 31 bit TVAL instead.\n");
+ return CLOCKSOURCE_MASK(31);
}
#endif
return CLOCKSOURCE_MASK(arch_counter_get_width());
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index bb47610bbd1c..c0cef92b12b8 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/acpi.h>
+#include <linux/hyperv.h>
#include <clocksource/hyperv_timer.h>
#include <asm/hyperv-tlfs.h>
#include <asm/mshyperv.h>
@@ -366,9 +367,18 @@ static union {
u8 reserved[PAGE_SIZE];
} tsc_pg __aligned(PAGE_SIZE);
+static struct ms_hyperv_tsc_page *tsc_page = &tsc_pg.page;
+static unsigned long tsc_pfn;
+
+unsigned long hv_get_tsc_pfn(void)
+{
+ return tsc_pfn;
+}
+EXPORT_SYMBOL_GPL(hv_get_tsc_pfn);
+
struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
{
- return &tsc_pg.page;
+ return tsc_page;
}
EXPORT_SYMBOL_GPL(hv_get_tsc_page);
@@ -395,25 +405,24 @@ static u64 notrace read_hv_sched_clock_tsc(void)
static void suspend_hv_clock_tsc(struct clocksource *arg)
{
- u64 tsc_msr;
+ union hv_reference_tsc_msr tsc_msr;
/* Disable the TSC page */
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= ~BIT_ULL(0);
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ tsc_msr.enable = 0;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
}
static void resume_hv_clock_tsc(struct clocksource *arg)
{
- phys_addr_t phys_addr = virt_to_phys(&tsc_pg);
- u64 tsc_msr;
+ union hv_reference_tsc_msr tsc_msr;
/* Re-enable the TSC page */
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= GENMASK_ULL(11, 0);
- tsc_msr |= BIT_ULL(0) | (u64)phys_addr;
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ tsc_msr.enable = 1;
+ tsc_msr.pfn = tsc_pfn;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
}
#ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK
@@ -495,15 +504,11 @@ static __always_inline void hv_setup_sched_clock(void *sched_clock) {}
static bool __init hv_init_tsc_clocksource(void)
{
- u64 tsc_msr;
- phys_addr_t phys_addr;
+ union hv_reference_tsc_msr tsc_msr;
if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
return false;
- if (hv_root_partition)
- return false;
-
/*
* If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly
* handles frequency and offset changes due to live migration,
@@ -521,19 +526,31 @@ static bool __init hv_init_tsc_clocksource(void)
}
hv_read_reference_counter = read_hv_clock_tsc;
- phys_addr = virt_to_phys(hv_get_tsc_page());
/*
- * The Hyper-V TLFS specifies to preserve the value of reserved
- * bits in registers. So read the existing value, preserve the
- * low order 12 bits, and add in the guest physical address
- * (which already has at least the low 12 bits set to zero since
- * it is page aligned). Also set the "enable" bit, which is bit 0.
+ * TSC page mapping works differently in root compared to guest.
+ * - In guest partition the guest PFN has to be passed to the
+ * hypervisor.
+ * - In root partition it's other way around: it has to map the PFN
+ * provided by the hypervisor.
+ * But it can't be mapped right here as it's too early and MMU isn't
+ * ready yet. So, we only set the enable bit here and will remap the
+ * page later in hv_remap_tsc_clocksource().
+ *
+ * It worth mentioning, that TSC clocksource read function
+ * (read_hv_clock_tsc) has a MSR-based fallback mechanism, used when
+ * TSC page is zeroed (which is the case until the PFN is remapped) and
+ * thus TSC clocksource will work even without the real TSC page
+ * mapped.
*/
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= GENMASK_ULL(11, 0);
- tsc_msr = tsc_msr | 0x1 | (u64)phys_addr;
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ if (hv_root_partition)
+ tsc_pfn = tsc_msr.pfn;
+ else
+ tsc_pfn = HVPFN_DOWN(virt_to_phys(tsc_page));
+ tsc_msr.enable = 1;
+ tsc_msr.pfn = tsc_pfn;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
@@ -565,3 +582,20 @@ void __init hv_init_clocksource(void)
hv_sched_clock_offset = hv_read_reference_counter();
hv_setup_sched_clock(read_hv_sched_clock_msr);
}
+
+void __init hv_remap_tsc_clocksource(void)
+{
+ if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
+ return;
+
+ if (!hv_root_partition) {
+ WARN(1, "%s: attempt to remap TSC page in guest partition\n",
+ __func__);
+ return;
+ }
+
+ tsc_page = memremap(tsc_pfn << HV_HYP_PAGE_SHIFT, sizeof(tsc_pg),
+ MEMREMAP_WB);
+ if (!tsc_page)
+ pr_err("Failed to remap Hyper-V TSC page.\n");
+}
diff --git a/drivers/clocksource/ingenic-ost.c b/drivers/clocksource/ingenic-ost.c
index 06d25754e606..9f7c280a1336 100644
--- a/drivers/clocksource/ingenic-ost.c
+++ b/drivers/clocksource/ingenic-ost.c
@@ -141,7 +141,7 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused ingenic_ost_suspend(struct device *dev)
+static int ingenic_ost_suspend(struct device *dev)
{
struct ingenic_ost *ost = dev_get_drvdata(dev);
@@ -150,14 +150,14 @@ static int __maybe_unused ingenic_ost_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ingenic_ost_resume(struct device *dev)
+static int ingenic_ost_resume(struct device *dev)
{
struct ingenic_ost *ost = dev_get_drvdata(dev);
return clk_enable(ost->clk);
}
-static const struct dev_pm_ops __maybe_unused ingenic_ost_pm_ops = {
+static const struct dev_pm_ops ingenic_ost_pm_ops = {
/* _noirq: We want the OST clock to be gated last / ungated first */
.suspend_noirq = ingenic_ost_suspend,
.resume_noirq = ingenic_ost_resume,
@@ -181,9 +181,7 @@ static const struct of_device_id ingenic_ost_of_match[] = {
static struct platform_driver ingenic_ost_driver = {
.driver = {
.name = "ingenic-ost",
-#ifdef CONFIG_PM_SUSPEND
- .pm = &ingenic_ost_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&ingenic_ost_pm_ops),
.of_match_table = ingenic_ost_of_match,
},
};
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 64dcb082d4cf..7b952aa52c0b 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -116,6 +117,7 @@ struct sh_cmt_device {
void __iomem *mapbase;
struct clk *clk;
unsigned long rate;
+ unsigned int reg_delay;
raw_spinlock_t lock; /* Protect the shared start/stop register */
@@ -247,10 +249,17 @@ static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value)
{
- if (ch->iostart)
- ch->cmt->info->write_control(ch->iostart, 0, value);
- else
- ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
+ u32 old_value = sh_cmt_read_cmstr(ch);
+
+ if (value != old_value) {
+ if (ch->iostart) {
+ ch->cmt->info->write_control(ch->iostart, 0, value);
+ udelay(ch->cmt->reg_delay);
+ } else {
+ ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
+ udelay(ch->cmt->reg_delay);
+ }
+ }
}
static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
@@ -260,7 +269,12 @@ static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value)
{
- ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
+ u32 old_value = sh_cmt_read_cmcsr(ch);
+
+ if (value != old_value) {
+ ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
+ udelay(ch->cmt->reg_delay);
+ }
}
static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
@@ -268,14 +282,33 @@ static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
return ch->cmt->info->read_count(ch->ioctrl, CMCNT);
}
-static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
+static inline int sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
{
+ /* Tests showed that we need to wait 3 clocks here */
+ unsigned int cmcnt_delay = DIV_ROUND_UP(3 * ch->cmt->reg_delay, 2);
+ u32 reg;
+
+ if (ch->cmt->info->model > SH_CMT_16BIT) {
+ int ret = read_poll_timeout_atomic(sh_cmt_read_cmcsr, reg,
+ !(reg & SH_CMT32_CMCSR_WRFLG),
+ 1, cmcnt_delay, false, ch);
+ if (ret < 0)
+ return ret;
+ }
+
ch->cmt->info->write_count(ch->ioctrl, CMCNT, value);
+ udelay(cmcnt_delay);
+ return 0;
}
static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value)
{
- ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
+ u32 old_value = ch->cmt->info->read_count(ch->ioctrl, CMCOR);
+
+ if (value != old_value) {
+ ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
+ udelay(ch->cmt->reg_delay);
+ }
}
static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped)
@@ -319,7 +352,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
static int sh_cmt_enable(struct sh_cmt_channel *ch)
{
- int k, ret;
+ int ret;
dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
@@ -347,26 +380,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
}
sh_cmt_write_cmcor(ch, 0xffffffff);
- sh_cmt_write_cmcnt(ch, 0);
-
- /*
- * According to the sh73a0 user's manual, as CMCNT can be operated
- * only by the RCLK (Pseudo 32 kHz), there's one restriction on
- * modifying CMCNT register; two RCLK cycles are necessary before
- * this register is either read or any modification of the value
- * it holds is reflected in the LSI's actual operation.
- *
- * While at it, we're supposed to clear out the CMCNT as of this
- * moment, so make sure it's processed properly here. This will
- * take RCLKx2 at maximum.
- */
- for (k = 0; k < 100; k++) {
- if (!sh_cmt_read_cmcnt(ch))
- break;
- udelay(1);
- }
+ ret = sh_cmt_write_cmcnt(ch, 0);
- if (sh_cmt_read_cmcnt(ch)) {
+ if (ret || sh_cmt_read_cmcnt(ch)) {
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
ch->index);
ret = -ETIMEDOUT;
@@ -995,8 +1011,8 @@ MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
{
- unsigned int mask;
- unsigned int i;
+ unsigned int mask, i;
+ unsigned long rate;
int ret;
cmt->pdev = pdev;
@@ -1032,10 +1048,16 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
if (ret < 0)
goto err_clk_unprepare;
- if (cmt->info->width == 16)
- cmt->rate = clk_get_rate(cmt->clk) / 512;
- else
- cmt->rate = clk_get_rate(cmt->clk) / 8;
+ rate = clk_get_rate(cmt->clk);
+ if (!rate) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ /* We shall wait 2 input clks after register writes */
+ if (cmt->info->model >= SH_CMT_48BIT)
+ cmt->reg_delay = DIV_ROUND_UP(2UL * USEC_PER_SEC, rate);
+ cmt->rate = rate / (cmt->info->width == 16 ? 512 : 8);
/* Map the memory resource(s). */
ret = sh_cmt_map_memory(cmt);
diff --git a/drivers/clocksource/timer-npcm7xx.c b/drivers/clocksource/timer-npcm7xx.c
index a00520cbb660..9af30af5f989 100644
--- a/drivers/clocksource/timer-npcm7xx.c
+++ b/drivers/clocksource/timer-npcm7xx.c
@@ -188,6 +188,7 @@ static void __init npcm7xx_clocksource_init(void)
static int __init npcm7xx_timer_init(struct device_node *np)
{
+ struct clk *clk;
int ret;
ret = timer_of_init(np, &npcm7xx_to);
@@ -199,6 +200,15 @@ static int __init npcm7xx_timer_init(struct device_node *np)
npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
(NPCM7XX_Tx_MIN_PRESCALE + 1);
+ /* Enable the clock for timer1, if it exists */
+ clk = of_clk_get(np, 1);
+ if (clk) {
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+ else
+ pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk);
+ }
+
npcm7xx_clocksource_init();
npcm7xx_clockevents_init();
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
index 969a552da8d2..a0d66fabf073 100644
--- a/drivers/clocksource/timer-riscv.c
+++ b/drivers/clocksource/timer-riscv.c
@@ -51,7 +51,7 @@ static int riscv_clock_next_event(unsigned long delta,
static unsigned int riscv_clock_event_irq;
static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
.name = "riscv_timer_clockevent",
- .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 100,
.set_next_event = riscv_clock_next_event,
};
diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c
index e6a87f4af2b5..cd1916c05325 100644
--- a/drivers/clocksource/timer-sp804.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -155,14 +155,14 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static inline void timer_shutdown(struct clock_event_device *evt)
+static inline void evt_timer_shutdown(struct clock_event_device *evt)
{
writel(0, common_clkevt->ctrl);
}
static int sp804_shutdown(struct clock_event_device *evt)
{
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
return 0;
}
@@ -171,7 +171,7 @@ static int sp804_set_periodic(struct clock_event_device *evt)
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
writel(common_clkevt->reload, common_clkevt->load);
writel(ctrl, common_clkevt->ctrl);
return 0;
diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
index 2737407ff069..632523c1232f 100644
--- a/drivers/clocksource/timer-ti-dm-systimer.c
+++ b/drivers/clocksource/timer-ti-dm-systimer.c
@@ -345,8 +345,10 @@ static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
return error;
r = clk_get_rate(clock);
- if (!r)
+ if (!r) {
+ clk_disable_unprepare(clock);
return -ENODEV;
+ }
if (is_ick)
t->ick = clock;
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index cad29ded3a48..b24b903a8822 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -633,6 +633,8 @@ static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *n
static int omap_dm_timer_free(struct omap_dm_timer *cookie)
{
struct dmtimer *timer;
+ struct device *dev;
+ int rc;
timer = to_dmtimer(cookie);
if (unlikely(!timer))
@@ -640,10 +642,21 @@ static int omap_dm_timer_free(struct omap_dm_timer *cookie)
WARN_ON(!timer->reserved);
timer->reserved = 0;
+
+ dev = &timer->pdev->dev;
+ rc = pm_runtime_resume_and_get(dev);
+ if (rc)
+ return rc;
+
+ /* Clear timer configuration */
+ dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
+
+ pm_runtime_put_sync(dev);
+
return 0;
}
-int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
+static int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
{
struct dmtimer *timer = to_dmtimer(cookie);
if (timer)
@@ -1135,6 +1148,10 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
goto err_disable;
}
__omap_dm_timer_init_regs(timer);
+
+ /* Clear timer configuration */
+ dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
+
pm_runtime_put(dev);
}
@@ -1258,7 +1275,7 @@ static struct platform_driver omap_dm_timer_driver = {
.remove = omap_dm_timer_remove,
.driver = {
.name = "omap_timer",
- .of_match_table = of_match_ptr(omap_timer_match),
+ .of_match_table = omap_timer_match,
.pm = &omap_dm_timer_pm_ops,
},
};
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 82e5de1f6f8c..0a0352d8fa45 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -41,6 +41,15 @@ config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
To compile this driver as a module, choose M here: the
module will be called sun50i-cpufreq-nvmem.
+config ARM_APPLE_SOC_CPUFREQ
+ tristate "Apple Silicon SoC CPUFreq support"
+ depends on ARCH_APPLE || (COMPILE_TEST && 64BIT)
+ select PM_OPP
+ default ARCH_APPLE
+ help
+ This adds the CPUFreq driver for Apple Silicon machines
+ (e.g. Apple M1).
+
config ARM_ARMADA_37XX_CPUFREQ
tristate "Armada 37xx CPUFreq support"
depends on ARCH_MVEBU && CPUFREQ_DT
@@ -340,8 +349,8 @@ config ARM_TEGRA194_CPUFREQ
config ARM_TI_CPUFREQ
bool "Texas Instruments CPUFreq support"
- depends on ARCH_OMAP2PLUS
- default ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || ARCH_K3
+ default y
help
This driver enables valid OPPs on the running platform based on
values contained within the SoC in use. Enable this in order to
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 310779b07daf..00476e94db90 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -35,7 +35,7 @@ config X86_PCC_CPUFREQ
If in doubt, say N.
config X86_AMD_PSTATE
- tristate "AMD Processor P-State driver"
+ bool "AMD Processor P-State driver"
depends on X86 && ACPI
select ACPI_PROCESSOR
select ACPI_CPPC_LIB if X86_64
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 49b98c62c5af..32a7029e25ed 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
##################################################################################
# ARM SoC drivers
+obj-$(CONFIG_ARM_APPLE_SOC_CPUFREQ) += apple-soc-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ) += armada-8k-cpufreq.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 1bb2b90ebb21..78adfb2ffff6 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -19,6 +19,7 @@
#include <linux/compiler.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/string_helpers.h>
#include <linux/acpi.h>
#include <linux/io.h>
@@ -135,8 +136,8 @@ static int set_boost(struct cpufreq_policy *policy, int val)
{
on_each_cpu_mask(policy->cpus, boost_set_msr_each,
(void *)(long)val, 1);
- pr_debug("CPU %*pbl: Core Boosting %sabled.\n",
- cpumask_pr_args(policy->cpus), val ? "en" : "dis");
+ pr_debug("CPU %*pbl: Core Boosting %s.\n",
+ cpumask_pr_args(policy->cpus), str_enabled_disabled(val));
return 0;
}
@@ -535,15 +536,6 @@ static void free_acpi_perf_data(void)
free_percpu(acpi_perf_data);
}
-static int cpufreq_boost_online(unsigned int cpu)
-{
- /*
- * On the CPU_UP path we simply keep the boost-disable flag
- * in sync with the current global state.
- */
- return boost_set_msr(acpi_cpufreq_driver.boost_enabled);
-}
-
static int cpufreq_boost_down_prep(unsigned int cpu)
{
/*
@@ -897,6 +889,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (perf->states[0].core_frequency * 1000 != freq_table[0].frequency)
pr_warn(FW_WARN "P-state 0 is not max freq\n");
+ if (acpi_cpufreq_driver.set_boost)
+ set_boost(policy, acpi_cpufreq_driver.boost_enabled);
+
return result;
err_unreg:
@@ -916,6 +911,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
pr_debug("%s\n", __func__);
+ cpufreq_boost_down_prep(policy->cpu);
policy->fast_switch_possible = false;
policy->driver_data = NULL;
acpi_processor_unregister_performance(data->acpi_perf_cpu);
@@ -958,12 +954,8 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.attr = acpi_cpufreq_attr,
};
-static enum cpuhp_state acpi_cpufreq_online;
-
static void __init acpi_cpufreq_boost_init(void)
{
- int ret;
-
if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA))) {
pr_debug("Boost capabilities not present in the processor\n");
return;
@@ -971,24 +963,6 @@ static void __init acpi_cpufreq_boost_init(void)
acpi_cpufreq_driver.set_boost = set_boost;
acpi_cpufreq_driver.boost_enabled = boost_state(0);
-
- /*
- * This calls the online callback on all online cpu and forces all
- * MSRs to the same value.
- */
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpufreq/acpi:online",
- cpufreq_boost_online, cpufreq_boost_down_prep);
- if (ret < 0) {
- pr_err("acpi_cpufreq: failed to register hotplug callbacks\n");
- return;
- }
- acpi_cpufreq_online = ret;
-}
-
-static void acpi_cpufreq_boost_exit(void)
-{
- if (acpi_cpufreq_online > 0)
- cpuhp_remove_state_nocalls(acpi_cpufreq_online);
}
static int __init acpi_cpufreq_init(void)
@@ -1032,7 +1006,6 @@ static int __init acpi_cpufreq_init(void)
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret) {
free_acpi_perf_data();
- acpi_cpufreq_boost_exit();
}
return ret;
}
@@ -1041,8 +1014,6 @@ static void __exit acpi_cpufreq_exit(void)
{
pr_debug("%s\n", __func__);
- acpi_cpufreq_boost_exit();
-
cpufreq_unregister_driver(&acpi_cpufreq_driver);
free_acpi_perf_data();
diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
index e4a5b4d90f83..7f3fe2048981 100644
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-1.0-or-later
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD Processor P-state Frequency Driver Unit Test
*
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index ace7d50cf2ac..204e39006dda 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -59,12 +59,8 @@
* we disable it by default to go acpi-cpufreq on these processors and add a
* module parameter to be able to enable it manually for debugging.
*/
-static bool shared_mem = false;
-module_param(shared_mem, bool, 0444);
-MODULE_PARM_DESC(shared_mem,
- "enable amd-pstate on processors with shared memory solution (false = disabled (default), true = enabled)");
-
static struct cpufreq_driver amd_pstate_driver;
+static int cppc_load __initdata;
static inline int pstate_enable(bool enable)
{
@@ -424,12 +420,22 @@ static void amd_pstate_boost_init(struct amd_cpudata *cpudata)
amd_pstate_driver.boost_enabled = true;
}
+static void amd_perf_ctl_reset(unsigned int cpu)
+{
+ wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0);
+}
+
static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
{
int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
struct device *dev;
struct amd_cpudata *cpudata;
+ /*
+ * Resetting PERF_CTL_MSR will put the CPU in P0 frequency,
+ * which is ideal for initialization process.
+ */
+ amd_perf_ctl_reset(policy->cpu);
dev = get_cpu_device(policy->cpu);
if (!dev)
return -ENODEV;
@@ -616,6 +622,15 @@ static int __init amd_pstate_init(void)
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return -ENODEV;
+ /*
+ * by default the pstate driver is disabled to load
+ * enable the amd_pstate passive mode driver explicitly
+ * with amd_pstate=passive in kernel command line
+ */
+ if (!cppc_load) {
+ pr_debug("driver load is disabled, boot with amd_pstate=passive to enable this\n");
+ return -ENODEV;
+ }
if (!acpi_cpc_valid()) {
pr_warn_once("the _CPC object is not present in SBIOS or ACPI disabled\n");
@@ -630,13 +645,11 @@ static int __init amd_pstate_init(void)
if (boot_cpu_has(X86_FEATURE_CPPC)) {
pr_debug("AMD CPPC MSR based functionality is supported\n");
amd_pstate_driver.adjust_perf = amd_pstate_adjust_perf;
- } else if (shared_mem) {
+ } else {
+ pr_debug("AMD CPPC shared memory based functionality is supported\n");
static_call_update(amd_pstate_enable, cppc_enable);
static_call_update(amd_pstate_init_perf, cppc_init_perf);
static_call_update(amd_pstate_update_perf, cppc_update_perf);
- } else {
- pr_info("This processor supports shared memory solution, you can enable it with amd_pstate.shared_mem=1\n");
- return -ENODEV;
}
/* enable amd pstate feature */
@@ -653,16 +666,22 @@ static int __init amd_pstate_init(void)
return ret;
}
+device_initcall(amd_pstate_init);
-static void __exit amd_pstate_exit(void)
+static int __init amd_pstate_param(char *str)
{
- cpufreq_unregister_driver(&amd_pstate_driver);
+ if (!str)
+ return -EINVAL;
- amd_pstate_enable(false);
-}
+ if (!strcmp(str, "disable")) {
+ cppc_load = 0;
+ pr_info("driver is explicitly disabled\n");
+ } else if (!strcmp(str, "passive"))
+ cppc_load = 1;
-module_init(amd_pstate_init);
-module_exit(amd_pstate_exit);
+ return 0;
+}
+early_param("amd_pstate", amd_pstate_param);
MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c
index 6448e03bcf48..59b19b9975e8 100644
--- a/drivers/cpufreq/amd_freq_sensitivity.c
+++ b/drivers/cpufreq/amd_freq_sensitivity.c
@@ -125,6 +125,8 @@ static int __init amd_freq_sensitivity_init(void)
if (!pcidev) {
if (!boot_cpu_has(X86_FEATURE_PROC_FEEDBACK))
return -ENODEV;
+ } else {
+ pci_dev_put(pcidev);
}
if (rdmsrl_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val))
diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c
new file mode 100644
index 000000000000..d1801281cdd9
--- /dev/null
+++ b/drivers/cpufreq/apple-soc-cpufreq.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Apple SoC CPU cluster performance state driver
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * Based on scpi-cpufreq.c
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+#define APPLE_DVFS_CMD 0x20
+#define APPLE_DVFS_CMD_BUSY BIT(31)
+#define APPLE_DVFS_CMD_SET BIT(25)
+#define APPLE_DVFS_CMD_PS2 GENMASK(16, 12)
+#define APPLE_DVFS_CMD_PS1 GENMASK(4, 0)
+
+/* Same timebase as CPU counter (24MHz) */
+#define APPLE_DVFS_LAST_CHG_TIME 0x38
+
+/*
+ * Apple ran out of bits and had to shift this in T8112...
+ */
+#define APPLE_DVFS_STATUS 0x50
+#define APPLE_DVFS_STATUS_CUR_PS_T8103 GENMASK(7, 4)
+#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103 4
+#define APPLE_DVFS_STATUS_TGT_PS_T8103 GENMASK(3, 0)
+#define APPLE_DVFS_STATUS_CUR_PS_T8112 GENMASK(9, 5)
+#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112 5
+#define APPLE_DVFS_STATUS_TGT_PS_T8112 GENMASK(4, 0)
+
+/*
+ * Div is +1, base clock is 12MHz on existing SoCs.
+ * For documentation purposes. We use the OPP table to
+ * get the frequency.
+ */
+#define APPLE_DVFS_PLL_STATUS 0xc0
+#define APPLE_DVFS_PLL_FACTOR 0xc8
+#define APPLE_DVFS_PLL_FACTOR_MULT GENMASK(31, 16)
+#define APPLE_DVFS_PLL_FACTOR_DIV GENMASK(15, 0)
+
+#define APPLE_DVFS_TRANSITION_TIMEOUT 100
+
+struct apple_soc_cpufreq_info {
+ u64 max_pstate;
+ u64 cur_pstate_mask;
+ u64 cur_pstate_shift;
+};
+
+struct apple_cpu_priv {
+ struct device *cpu_dev;
+ void __iomem *reg_base;
+ const struct apple_soc_cpufreq_info *info;
+};
+
+static struct cpufreq_driver apple_soc_cpufreq_driver;
+
+static const struct apple_soc_cpufreq_info soc_t8103_info = {
+ .max_pstate = 15,
+ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8103,
+ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103,
+};
+
+static const struct apple_soc_cpufreq_info soc_t8112_info = {
+ .max_pstate = 31,
+ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8112,
+ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112,
+};
+
+static const struct apple_soc_cpufreq_info soc_default_info = {
+ .max_pstate = 15,
+ .cur_pstate_mask = 0, /* fallback */
+};
+
+static const struct of_device_id apple_soc_cpufreq_of_match[] = {
+ {
+ .compatible = "apple,t8103-cluster-cpufreq",
+ .data = &soc_t8103_info,
+ },
+ {
+ .compatible = "apple,t8112-cluster-cpufreq",
+ .data = &soc_t8112_info,
+ },
+ {
+ .compatible = "apple,cluster-cpufreq",
+ .data = &soc_default_info,
+ },
+ {}
+};
+
+static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
+ struct apple_cpu_priv *priv = policy->driver_data;
+ struct cpufreq_frequency_table *p;
+ unsigned int pstate;
+
+ if (priv->info->cur_pstate_mask) {
+ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS);
+
+ pstate = (reg & priv->info->cur_pstate_mask) >> priv->info->cur_pstate_shift;
+ } else {
+ /*
+ * For the fallback case we might not know the layout of DVFS_STATUS,
+ * so just use the command register value (which ignores boost limitations).
+ */
+ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_CMD);
+
+ pstate = FIELD_GET(APPLE_DVFS_CMD_PS1, reg);
+ }
+
+ cpufreq_for_each_valid_entry(p, policy->freq_table)
+ if (p->driver_data == pstate)
+ return p->frequency;
+
+ dev_err(priv->cpu_dev, "could not find frequency for pstate %d\n",
+ pstate);
+ return 0;
+}
+
+static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy,
+ unsigned int index)
+{
+ struct apple_cpu_priv *priv = policy->driver_data;
+ unsigned int pstate = policy->freq_table[index].driver_data;
+ u64 reg;
+
+ /* Fallback for newer SoCs */
+ if (index > priv->info->max_pstate)
+ index = priv->info->max_pstate;
+
+ if (readq_poll_timeout_atomic(priv->reg_base + APPLE_DVFS_CMD, reg,
+ !(reg & APPLE_DVFS_CMD_BUSY), 2,
+ APPLE_DVFS_TRANSITION_TIMEOUT)) {
+ return -EIO;
+ }
+
+ reg &= ~(APPLE_DVFS_CMD_PS1 | APPLE_DVFS_CMD_PS2);
+ reg |= FIELD_PREP(APPLE_DVFS_CMD_PS1, pstate);
+ reg |= FIELD_PREP(APPLE_DVFS_CMD_PS2, pstate);
+ reg |= APPLE_DVFS_CMD_SET;
+
+ writeq_relaxed(reg, priv->reg_base + APPLE_DVFS_CMD);
+
+ return 0;
+}
+
+static unsigned int apple_soc_cpufreq_fast_switch(struct cpufreq_policy *policy,
+ unsigned int target_freq)
+{
+ if (apple_soc_cpufreq_set_target(policy, policy->cached_resolved_idx) < 0)
+ return 0;
+
+ return policy->freq_table[policy->cached_resolved_idx].frequency;
+}
+
+static int apple_soc_cpufreq_find_cluster(struct cpufreq_policy *policy,
+ void __iomem **reg_base,
+ const struct apple_soc_cpufreq_info **info)
+{
+ struct of_phandle_args args;
+ const struct of_device_id *match;
+ int ret = 0;
+
+ ret = of_perf_domain_get_sharing_cpumask(policy->cpu, "performance-domains",
+ "#performance-domain-cells",
+ policy->cpus, &args);
+ if (ret < 0)
+ return ret;
+
+ match = of_match_node(apple_soc_cpufreq_of_match, args.np);
+ of_node_put(args.np);
+ if (!match)
+ return -ENODEV;
+
+ *info = match->data;
+
+ *reg_base = of_iomap(args.np, 0);
+ if (IS_ERR(*reg_base))
+ return PTR_ERR(*reg_base);
+
+ return 0;
+}
+
+static struct freq_attr *apple_soc_cpufreq_hw_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL, /* Filled in below if boost is enabled */
+ NULL,
+};
+
+static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int ret, i;
+ unsigned int transition_latency;
+ void __iomem *reg_base;
+ struct device *cpu_dev;
+ struct apple_cpu_priv *priv;
+ const struct apple_soc_cpufreq_info *info;
+ struct cpufreq_frequency_table *freq_table;
+
+ cpu_dev = get_cpu_device(policy->cpu);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu%d device\n", policy->cpu);
+ return -ENODEV;
+ }
+
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "%s: failed to add OPP table: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = apple_soc_cpufreq_find_cluster(policy, &reg_base, &info);
+ if (ret) {
+ dev_err(cpu_dev, "%s: failed to get cluster info: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
+ if (ret) {
+ dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret);
+ goto out_iounmap;
+ }
+
+ ret = dev_pm_opp_get_opp_count(cpu_dev);
+ if (ret <= 0) {
+ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
+ ret = -EPROBE_DEFER;
+ goto out_free_opp;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out_free_opp;
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto out_free_priv;
+ }
+
+ /* Get OPP levels (p-state indexes) and stash them in driver_data */
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ unsigned long rate = freq_table[i].frequency * 1000 + 999;
+ struct dev_pm_opp *opp = dev_pm_opp_find_freq_floor(cpu_dev, &rate);
+
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ goto out_free_cpufreq_table;
+ }
+ freq_table[i].driver_data = dev_pm_opp_get_level(opp);
+ dev_pm_opp_put(opp);
+ }
+
+ priv->cpu_dev = cpu_dev;
+ priv->reg_base = reg_base;
+ priv->info = info;
+ policy->driver_data = priv;
+ policy->freq_table = freq_table;
+
+ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
+ if (!transition_latency)
+ transition_latency = CPUFREQ_ETERNAL;
+
+ policy->cpuinfo.transition_latency = transition_latency;
+ policy->dvfs_possible_from_any_cpu = true;
+ policy->fast_switch_possible = true;
+
+ if (policy_has_boost_freq(policy)) {
+ ret = cpufreq_enable_boost_support();
+ if (ret) {
+ dev_warn(cpu_dev, "failed to enable boost: %d\n", ret);
+ } else {
+ apple_soc_cpufreq_hw_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
+ apple_soc_cpufreq_driver.boost_enabled = true;
+ }
+ }
+
+ return 0;
+
+out_free_cpufreq_table:
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_free_priv:
+ kfree(priv);
+out_free_opp:
+ dev_pm_opp_remove_all_dynamic(cpu_dev);
+out_iounmap:
+ iounmap(reg_base);
+ return ret;
+}
+
+static int apple_soc_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ struct apple_cpu_priv *priv = policy->driver_data;
+
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
+ iounmap(priv->reg_base);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct cpufreq_driver apple_soc_cpufreq_driver = {
+ .name = "apple-cpufreq",
+ .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
+ CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_IS_COOLING_DEV,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .attr = cpufreq_generic_attr,
+ .get = apple_soc_cpufreq_get_rate,
+ .init = apple_soc_cpufreq_init,
+ .exit = apple_soc_cpufreq_exit,
+ .target_index = apple_soc_cpufreq_set_target,
+ .fast_switch = apple_soc_cpufreq_fast_switch,
+ .register_em = cpufreq_register_em_with_opp,
+ .attr = apple_soc_cpufreq_hw_attr,
+};
+
+static int __init apple_soc_cpufreq_module_init(void)
+{
+ if (!of_machine_is_compatible("apple,arm-platform"))
+ return -ENODEV;
+
+ return cpufreq_register_driver(&apple_soc_cpufreq_driver);
+}
+module_init(apple_soc_cpufreq_module_init);
+
+static void __exit apple_soc_cpufreq_module_exit(void)
+{
+ cpufreq_unregister_driver(&apple_soc_cpufreq_driver);
+}
+module_exit(apple_soc_cpufreq_module_exit);
+
+MODULE_DEVICE_TABLE(of, apple_soc_cpufreq_of_match);
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_DESCRIPTION("Apple SoC CPU cluster DVFS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 6ac3800db450..8ab672883043 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -103,6 +103,8 @@ static const struct of_device_id allowlist[] __initconst = {
static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "allwinner,sun50i-h6", },
+ { .compatible = "apple,arm-platform", },
+
{ .compatible = "arm,vexpress", },
{ .compatible = "calxeda,highbank", },
@@ -160,6 +162,7 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "ti,am43", },
{ .compatible = "ti,dra7", },
{ .compatible = "ti,omap3", },
+ { .compatible = "ti,am625", },
{ .compatible = "qcom,ipq8064", },
{ .compatible = "qcom,apq8064", },
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 69b3d61852ac..7e56a42750ea 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1207,6 +1207,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
goto err_free_rcpumask;
+ init_completion(&policy->kobj_unregister);
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
cpufreq_global_kobject, "policy%u", cpu);
if (ret) {
@@ -1245,7 +1246,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
init_rwsem(&policy->rwsem);
spin_lock_init(&policy->transition_lock);
init_waitqueue_head(&policy->transition_wait);
- init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
policy->cpu = cpu;
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 1570d6f3e75d..55c7ffd37d1c 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -128,25 +128,23 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
ssize_t len = 0;
int i, j, count;
- len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
- len += scnprintf(buf + len, PAGE_SIZE - len, " : ");
+ len += sysfs_emit_at(buf, len, " From : To\n");
+ len += sysfs_emit_at(buf, len, " : ");
for (i = 0; i < stats->state_num; i++) {
if (len >= PAGE_SIZE)
break;
- len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
- stats->freq_table[i]);
+ len += sysfs_emit_at(buf, len, "%9u ", stats->freq_table[i]);
}
if (len >= PAGE_SIZE)
return PAGE_SIZE;
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+ len += sysfs_emit_at(buf, len, "\n");
for (i = 0; i < stats->state_num; i++) {
if (len >= PAGE_SIZE)
break;
- len += scnprintf(buf + len, PAGE_SIZE - len, "%9u: ",
- stats->freq_table[i]);
+ len += sysfs_emit_at(buf, len, "%9u: ", stats->freq_table[i]);
for (j = 0; j < stats->state_num; j++) {
if (len >= PAGE_SIZE)
@@ -157,11 +155,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
else
count = stats->trans_table[i * stats->max_state + j];
- len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", count);
+ len += sysfs_emit_at(buf, len, "%9u ", count);
}
if (len >= PAGE_SIZE)
break;
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+ len += sysfs_emit_at(buf, len, "\n");
}
if (len >= PAGE_SIZE) {
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 6ff73c30769f..fd73d6d2b808 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -298,6 +298,7 @@ static int hwp_active __read_mostly;
static int hwp_mode_bdw __read_mostly;
static bool per_cpu_limits __read_mostly;
static bool hwp_boost __read_mostly;
+static bool hwp_forced __read_mostly;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
@@ -1679,12 +1680,12 @@ static void intel_pstate_update_epp_defaults(struct cpudata *cpudata)
return;
/*
- * If powerup EPP is something other than chipset default 0x80 and
- * - is more performance oriented than 0x80 (default balance_perf EPP)
+ * If the EPP is set by firmware, which means that firmware enabled HWP
+ * - Is equal or less than 0x80 (default balance_perf EPP)
* - But less performance oriented than performance EPP
* then use this as new balance_perf EPP.
*/
- if (cpudata->epp_default < HWP_EPP_BALANCE_PERFORMANCE &&
+ if (hwp_forced && cpudata->epp_default <= HWP_EPP_BALANCE_PERFORMANCE &&
cpudata->epp_default > HWP_EPP_PERFORMANCE) {
epp_values[EPP_INDEX_BALANCE_PERFORMANCE] = cpudata->epp_default;
return;
@@ -2378,6 +2379,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
X86_MATCH(COMETLAKE, core_funcs),
X86_MATCH(ICELAKE_X, core_funcs),
X86_MATCH(TIGERLAKE, core_funcs),
+ X86_MATCH(SAPPHIRERAPIDS_X, core_funcs),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -3384,7 +3386,7 @@ static int __init intel_pstate_init(void)
id = x86_match_cpu(hwp_support_ids);
if (id) {
- bool hwp_forced = intel_pstate_hwp_is_enabled();
+ hwp_forced = intel_pstate_hwp_is_enabled();
if (hwp_forced)
pr_info("HWP enabled by BIOS\n");
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 3e000e1a75c6..4c57c6725c13 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -407,10 +407,10 @@ static int guess_fsb(int mult)
{
int speed = cpu_khz / 1000;
int i;
- int speeds[] = { 666, 1000, 1333, 2000 };
+ static const int speeds[] = { 666, 1000, 1333, 2000 };
int f_max, f_min;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ARRAY_SIZE(speeds); i++) {
f_max = ((speeds[i] * mult) + 50) / 100;
f_max += (ROUNDING / 2);
f_min = f_max - ROUNDING;
diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c
index f0e0a35c7f21..f80339779084 100644
--- a/drivers/cpufreq/mediatek-cpufreq-hw.c
+++ b/drivers/cpufreq/mediatek-cpufreq-hw.c
@@ -160,6 +160,7 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
struct mtk_cpufreq_data *data;
struct device *dev = &pdev->dev;
struct resource *res;
+ struct of_phandle_args args;
void __iomem *base;
int ret, i;
int index;
@@ -168,11 +169,14 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
if (!data)
return -ENOMEM;
- index = of_perf_domain_get_sharing_cpumask(policy->cpu, "performance-domains",
- "#performance-domain-cells",
- policy->cpus);
- if (index < 0)
- return index;
+ ret = of_perf_domain_get_sharing_cpumask(policy->cpu, "performance-domains",
+ "#performance-domain-cells",
+ policy->cpus, &args);
+ if (ret < 0)
+ return ret;
+
+ index = args.args[0];
+ of_node_put(args.np);
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
if (!res) {
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index 833589bc95e4..340fed35e45d 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -4,6 +4,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
#include <linux/cpufreq.h>
#include <linux/init.h>
#include <linux/interconnect.h>
@@ -43,7 +44,6 @@ struct qcom_cpufreq_soc_data {
struct qcom_cpufreq_data {
void __iomem *base;
struct resource *res;
- const struct qcom_cpufreq_soc_data *soc_data;
/*
* Mutex to synchronize between de-init sequence and re-starting LMh
@@ -55,12 +55,18 @@ struct qcom_cpufreq_data {
bool cancel_throttle;
struct delayed_work throttle_work;
struct cpufreq_policy *policy;
+ struct clk_hw cpu_clk;
bool per_core_dcvs;
struct freq_qos_request throttle_freq_req;
};
+static struct {
+ struct qcom_cpufreq_data *data;
+ const struct qcom_cpufreq_soc_data *soc_data;
+} qcom_cpufreq;
+
static unsigned long cpu_hw_rate, xo_rate;
static bool icc_scaling_enabled;
@@ -109,7 +115,7 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
unsigned int index)
{
struct qcom_cpufreq_data *data = policy->driver_data;
- const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
+ const struct qcom_cpufreq_soc_data *soc_data = qcom_cpufreq.soc_data;
unsigned long freq = policy->freq_table[index].frequency;
unsigned int i;
@@ -125,9 +131,37 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
return 0;
}
+static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
+{
+ unsigned int lval;
+
+ if (qcom_cpufreq.soc_data->reg_current_vote)
+ lval = readl_relaxed(data->base + qcom_cpufreq.soc_data->reg_current_vote) & 0x3ff;
+ else
+ lval = readl_relaxed(data->base + qcom_cpufreq.soc_data->reg_domain_state) & 0xff;
+
+ return lval * xo_rate;
+}
+
+/* Get the current frequency of the CPU (after throttling) */
static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
{
struct qcom_cpufreq_data *data;
+ struct cpufreq_policy *policy;
+
+ policy = cpufreq_cpu_get_raw(cpu);
+ if (!policy)
+ return 0;
+
+ data = policy->driver_data;
+
+ return qcom_lmh_get_throttle_freq(data) / HZ_PER_KHZ;
+}
+
+/* Get the frequency requested by the cpufreq core for the CPU */
+static unsigned int qcom_cpufreq_get_freq(unsigned int cpu)
+{
+ struct qcom_cpufreq_data *data;
const struct qcom_cpufreq_soc_data *soc_data;
struct cpufreq_policy *policy;
unsigned int index;
@@ -137,7 +171,7 @@ static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
return 0;
data = policy->driver_data;
- soc_data = data->soc_data;
+ soc_data = qcom_cpufreq.soc_data;
index = readl_relaxed(data->base + soc_data->reg_perf_state);
index = min(index, LUT_MAX_ENTRIES - 1);
@@ -149,7 +183,7 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct qcom_cpufreq_data *data = policy->driver_data;
- const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
+ const struct qcom_cpufreq_soc_data *soc_data = qcom_cpufreq.soc_data;
unsigned int index;
unsigned int i;
@@ -173,7 +207,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
unsigned long rate;
int ret;
struct qcom_cpufreq_data *drv_data = policy->driver_data;
- const struct qcom_cpufreq_soc_data *soc_data = drv_data->soc_data;
+ const struct qcom_cpufreq_soc_data *soc_data = qcom_cpufreq.soc_data;
table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
if (!table)
@@ -193,6 +227,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
}
} else if (ret != -ENODEV) {
dev_err(cpu_dev, "Invalid opp table in device tree\n");
+ kfree(table);
return ret;
} else {
policy->fast_switch_possible = true;
@@ -286,18 +321,6 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
}
}
-static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
-{
- unsigned int lval;
-
- if (data->soc_data->reg_current_vote)
- lval = readl_relaxed(data->base + data->soc_data->reg_current_vote) & 0x3ff;
- else
- lval = readl_relaxed(data->base + data->soc_data->reg_domain_state) & 0xff;
-
- return lval * xo_rate;
-}
-
static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
{
struct cpufreq_policy *policy = data->policy;
@@ -341,7 +364,7 @@ static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
* If h/w throttled frequency is higher than what cpufreq has requested
* for, then stop polling and switch back to interrupt mechanism.
*/
- if (throttled_freq >= qcom_cpufreq_hw_get(cpu))
+ if (throttled_freq >= qcom_cpufreq_get_freq(cpu))
enable_irq(data->throttle_irq);
else
mod_delayed_work(system_highpri_wq, &data->throttle_work,
@@ -367,9 +390,9 @@ static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data)
disable_irq_nosync(c_data->throttle_irq);
schedule_delayed_work(&c_data->throttle_work, 0);
- if (c_data->soc_data->reg_intr_clr)
+ if (qcom_cpufreq.soc_data->reg_intr_clr)
writel_relaxed(GT_IRQ_STATUS,
- c_data->base + c_data->soc_data->reg_intr_clr);
+ c_data->base + qcom_cpufreq.soc_data->reg_intr_clr);
return IRQ_HANDLED;
}
@@ -503,8 +526,6 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
struct of_phandle_args args;
struct device_node *cpu_np;
struct device *cpu_dev;
- struct resource *res;
- void __iomem *base;
struct qcom_cpufreq_data *data;
int ret, index;
@@ -526,51 +547,18 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
return ret;
index = args.args[0];
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- if (!res) {
- dev_err(dev, "failed to get mem resource %d\n", index);
- return -ENODEV;
- }
-
- if (!request_mem_region(res->start, resource_size(res), res->name)) {
- dev_err(dev, "failed to request resource %pR\n", res);
- return -EBUSY;
- }
-
- base = ioremap(res->start, resource_size(res));
- if (!base) {
- dev_err(dev, "failed to map resource %pR\n", res);
- ret = -ENOMEM;
- goto release_region;
- }
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto unmap_base;
- }
-
- data->soc_data = of_device_get_match_data(&pdev->dev);
- data->base = base;
- data->res = res;
+ data = &qcom_cpufreq.data[index];
/* HW should be in enabled state to proceed */
- if (!(readl_relaxed(base + data->soc_data->reg_enable) & 0x1)) {
+ if (!(readl_relaxed(data->base + qcom_cpufreq.soc_data->reg_enable) & 0x1)) {
dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index);
- ret = -ENODEV;
- goto error;
+ return -ENODEV;
}
- if (readl_relaxed(base + data->soc_data->reg_dcvs_ctrl) & 0x1)
+ if (readl_relaxed(data->base + qcom_cpufreq.soc_data->reg_dcvs_ctrl) & 0x1)
data->per_core_dcvs = true;
qcom_get_related_cpus(index, policy->cpus);
- if (cpumask_empty(policy->cpus)) {
- dev_err(dev, "Domain-%d failed to get related CPUs\n", index);
- ret = -ENOENT;
- goto error;
- }
policy->driver_data = data;
policy->dvfs_possible_from_any_cpu = true;
@@ -578,14 +566,13 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy);
if (ret) {
dev_err(dev, "Domain-%d failed to read LUT\n", index);
- goto error;
+ return ret;
}
ret = dev_pm_opp_get_opp_count(cpu_dev);
if (ret <= 0) {
dev_err(cpu_dev, "Failed to add OPPs\n");
- ret = -ENODEV;
- goto error;
+ return -ENODEV;
}
if (policy_has_boost_freq(policy)) {
@@ -594,18 +581,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
dev_warn(cpu_dev, "failed to enable boost: %d\n", ret);
}
- ret = qcom_cpufreq_hw_lmh_init(policy, index);
- if (ret)
- goto error;
-
- return 0;
-error:
- kfree(data);
-unmap_base:
- iounmap(base);
-release_region:
- release_mem_region(res->start, resource_size(res));
- return ret;
+ return qcom_cpufreq_hw_lmh_init(policy, index);
}
static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
@@ -658,20 +634,33 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
.ready = qcom_cpufreq_ready,
};
+static unsigned long qcom_cpufreq_hw_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct qcom_cpufreq_data *data = container_of(hw, struct qcom_cpufreq_data, cpu_clk);
+
+ return qcom_lmh_get_throttle_freq(data);
+}
+
+static const struct clk_ops qcom_cpufreq_hw_clk_ops = {
+ .recalc_rate = qcom_cpufreq_hw_recalc_rate,
+};
+
static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
{
+ struct clk_hw_onecell_data *clk_data;
+ struct device *dev = &pdev->dev;
struct device *cpu_dev;
struct clk *clk;
- int ret;
+ int ret, i, num_domains;
- clk = clk_get(&pdev->dev, "xo");
+ clk = clk_get(dev, "xo");
if (IS_ERR(clk))
return PTR_ERR(clk);
xo_rate = clk_get_rate(clk);
clk_put(clk);
- clk = clk_get(&pdev->dev, "alternate");
+ clk = clk_get(dev, "alternate");
if (IS_ERR(clk))
return PTR_ERR(clk);
@@ -689,11 +678,70 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* Allocate qcom_cpufreq_data based on the available frequency domains in DT */
+ num_domains = of_property_count_elems_of_size(dev->of_node, "reg", sizeof(u32) * 4);
+ if (num_domains <= 0)
+ return num_domains;
+
+ qcom_cpufreq.data = devm_kzalloc(dev, sizeof(struct qcom_cpufreq_data) * num_domains,
+ GFP_KERNEL);
+ if (!qcom_cpufreq.data)
+ return -ENOMEM;
+
+ qcom_cpufreq.soc_data = of_device_get_match_data(dev);
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_domains), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = num_domains;
+
+ for (i = 0; i < num_domains; i++) {
+ struct qcom_cpufreq_data *data = &qcom_cpufreq.data[i];
+ struct clk_init_data clk_init = {};
+ struct resource *res;
+ void __iomem *base;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, i, &res);
+ if (IS_ERR(base)) {
+ dev_err(dev, "Failed to map resource %pR\n", res);
+ return PTR_ERR(base);
+ }
+
+ data->base = base;
+ data->res = res;
+
+ /* Register CPU clock for each frequency domain */
+ clk_init.name = kasprintf(GFP_KERNEL, "qcom_cpufreq%d", i);
+ if (!clk_init.name)
+ return -ENOMEM;
+
+ clk_init.flags = CLK_GET_RATE_NOCACHE;
+ clk_init.ops = &qcom_cpufreq_hw_clk_ops;
+ data->cpu_clk.init = &clk_init;
+
+ ret = devm_clk_hw_register(dev, &data->cpu_clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register clock %d: %d\n", i, ret);
+ kfree(clk_init.name);
+ return ret;
+ }
+
+ clk_data->hws[i] = &data->cpu_clk;
+ kfree(clk_init.name);
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret < 0) {
+ dev_err(dev, "Failed to add clock provider\n");
+ return ret;
+ }
+
ret = cpufreq_register_driver(&cpufreq_qcom_hw_driver);
if (ret)
- dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n");
+ dev_err(dev, "CPUFreq HW driver failed to register\n");
else
- dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n");
+ dev_dbg(dev, "QCOM CPUFreq HW driver initialized\n");
return ret;
}
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 7d0d62a06bf3..c6fdf019dbde 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -39,7 +39,7 @@ static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq)
* In SPEAr1340, cpu clk's parent sys clk can take input from
* following sources
*/
- const char *sys_clk_src[] = {
+ static const char * const sys_clk_src[] = {
"sys_syn_clk",
"pll1_clk",
"pll2_clk",
diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c
index 6c88827f4e62..f98f53bf1011 100644
--- a/drivers/cpufreq/tegra186-cpufreq.c
+++ b/drivers/cpufreq/tegra186-cpufreq.c
@@ -65,8 +65,8 @@ struct tegra186_cpufreq_cluster {
struct tegra186_cpufreq_data {
void __iomem *regs;
- struct tegra186_cpufreq_cluster *clusters;
const struct tegra186_cpufreq_cpu *cpus;
+ struct tegra186_cpufreq_cluster clusters[];
};
static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
@@ -221,15 +221,12 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
struct tegra_bpmp *bpmp;
unsigned int i = 0, err;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev,
+ struct_size(data, clusters, TEGRA186_NUM_CLUSTERS),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->clusters = devm_kcalloc(&pdev->dev, TEGRA186_NUM_CLUSTERS,
- sizeof(*data->clusters), GFP_KERNEL);
- if (!data->clusters)
- return -ENOMEM;
-
data->cpus = tegra186_cpus;
bpmp = tegra_bpmp_get(&pdev->dev);
diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
index f64180dd2005..be4209d97cb3 100644
--- a/drivers/cpufreq/ti-cpufreq.c
+++ b/drivers/cpufreq/ti-cpufreq.c
@@ -39,6 +39,14 @@
#define OMAP34xx_ProdID_SKUID 0x4830A20C
#define OMAP3_SYSCON_BASE (0x48000000 + 0x2000 + 0x270)
+#define AM625_EFUSE_K_MPU_OPP 11
+#define AM625_EFUSE_S_MPU_OPP 19
+#define AM625_EFUSE_T_MPU_OPP 20
+
+#define AM625_SUPPORT_K_MPU_OPP BIT(0)
+#define AM625_SUPPORT_S_MPU_OPP BIT(1)
+#define AM625_SUPPORT_T_MPU_OPP BIT(2)
+
#define VERSION_COUNT 2
struct ti_cpufreq_data;
@@ -104,6 +112,25 @@ static unsigned long omap3_efuse_xlate(struct ti_cpufreq_data *opp_data,
return BIT(efuse);
}
+static unsigned long am625_efuse_xlate(struct ti_cpufreq_data *opp_data,
+ unsigned long efuse)
+{
+ unsigned long calculated_efuse = AM625_SUPPORT_K_MPU_OPP;
+
+ switch (efuse) {
+ case AM625_EFUSE_T_MPU_OPP:
+ calculated_efuse |= AM625_SUPPORT_T_MPU_OPP;
+ fallthrough;
+ case AM625_EFUSE_S_MPU_OPP:
+ calculated_efuse |= AM625_SUPPORT_S_MPU_OPP;
+ fallthrough;
+ case AM625_EFUSE_K_MPU_OPP:
+ calculated_efuse |= AM625_SUPPORT_K_MPU_OPP;
+ }
+
+ return calculated_efuse;
+}
+
static struct ti_cpufreq_soc_data am3x_soc_data = {
.efuse_xlate = amx3_efuse_xlate,
.efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ,
@@ -198,6 +225,14 @@ static struct ti_cpufreq_soc_data am3517_soc_data = {
.multi_regulator = false,
};
+static struct ti_cpufreq_soc_data am625_soc_data = {
+ .efuse_xlate = am625_efuse_xlate,
+ .efuse_offset = 0x0018,
+ .efuse_mask = 0x07c0,
+ .efuse_shift = 0x6,
+ .rev_offset = 0x0014,
+ .multi_regulator = false,
+};
/**
* ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC
@@ -301,6 +336,7 @@ static const struct of_device_id ti_cpufreq_of_match[] = {
{ .compatible = "ti,dra7", .data = &dra7_soc_data },
{ .compatible = "ti,omap34xx", .data = &omap34xx_soc_data, },
{ .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, },
+ { .compatible = "ti,am625", .data = &am625_soc_data, },
/* legacy */
{ .compatible = "ti,omap3430", .data = &omap34xx_soc_data, },
{ .compatible = "ti,omap3630", .data = &omap36xx_soc_data, },
diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c
index 821984947ed9..c80cf9ddabd8 100644
--- a/drivers/cpuidle/cpuidle-psci-domain.c
+++ b/drivers/cpuidle/cpuidle-psci-domain.c
@@ -181,7 +181,8 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
if (ret)
goto remove_pd;
- pr_info("Initialized CPU PM domain topology\n");
+ pr_info("Initialized CPU PM domain topology using %s mode\n",
+ use_osi ? "OSI" : "PC");
return 0;
put_node:
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
index 252f2a9686a6..7ca3d7d9b5ea 100644
--- a/drivers/cpuidle/dt_idle_states.c
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -211,18 +211,15 @@ int dt_init_idle_driver(struct cpuidle_driver *drv,
of_node_put(cpu_node);
if (err)
return err;
- /*
- * Update the driver state count only if some valid DT idle states
- * were detected
- */
- if (i)
- drv->state_count = state_idx;
+
+ /* Set the number of total supported idle states. */
+ drv->state_count = state_idx;
/*
* Return the number of present and valid DT idle states, which can
* also be 0 on platforms with missing DT idle states or legacy DT
* configuration predating the DT idle states bindings.
*/
- return i;
+ return state_idx - start_idx;
}
EXPORT_SYMBOL_GPL(dt_init_idle_driver);
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 768ced3d6fe8..0ac53c422c31 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -111,4 +111,22 @@ config CXL_REGION
select MEMREGION
select GET_FREE_REGION
+config CXL_REGION_INVALIDATION_TEST
+ bool "CXL: Region Cache Management Bypass (TEST)"
+ depends on CXL_REGION
+ help
+ CXL Region management and security operations potentially invalidate
+ the content of CPU caches without notifiying those caches to
+ invalidate the affected cachelines. The CXL Region driver attempts
+ to invalidate caches when those events occur. If that invalidation
+ fails the region will fail to enable. Reasons for cache
+ invalidation failure are due to the CPU not providing a cache
+ invalidation mechanism. For example usage of wbinvd is restricted to
+ bare metal x86. However, for testing purposes toggling this option
+ can disable that data integrity safety and proceed with enabling
+ regions when there might be conflicting contents in the CPU cache.
+
+ If unsure, or if this kernel is meant for production environments,
+ say N.
+
endif
diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
index a78270794150..db321f48ba52 100644
--- a/drivers/cxl/Makefile
+++ b/drivers/cxl/Makefile
@@ -9,5 +9,5 @@ obj-$(CONFIG_CXL_PORT) += cxl_port.o
cxl_mem-y := mem.o
cxl_pci-y := pci.o
cxl_acpi-y := acpi.o
-cxl_pmem-y := pmem.o
+cxl_pmem-y := pmem.o security.o
cxl_port-y := port.o
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index fb649683dd3a..ad0849af42d7 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -6,9 +6,120 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
+#include <asm/div64.h>
#include "cxlpci.h"
#include "cxl.h"
+#define CXL_RCRB_SIZE SZ_8K
+
+struct cxl_cxims_data {
+ int nr_maps;
+ u64 xormaps[];
+};
+
+/*
+ * Find a targets entry (n) in the host bridge interleave list.
+ * CXL Specfication 3.0 Table 9-22
+ */
+static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw,
+ int ig)
+{
+ int i = 0, n = 0;
+ u8 eiw;
+
+ /* IW: 2,4,6,8,12,16 begin building 'n' using xormaps */
+ if (iw != 3) {
+ for (i = 0; i < cximsd->nr_maps; i++)
+ n |= (hweight64(hpa & cximsd->xormaps[i]) & 1) << i;
+ }
+ /* IW: 3,6,12 add a modulo calculation to 'n' */
+ if (!is_power_of_2(iw)) {
+ if (ways_to_eiw(iw, &eiw))
+ return -1;
+ hpa &= GENMASK_ULL(51, eiw + ig);
+ n |= do_div(hpa, 3) << i;
+ }
+ return n;
+}
+
+static struct cxl_dport *cxl_hb_xor(struct cxl_root_decoder *cxlrd, int pos)
+{
+ struct cxl_cxims_data *cximsd = cxlrd->platform_data;
+ struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
+ struct cxl_decoder *cxld = &cxlsd->cxld;
+ int ig = cxld->interleave_granularity;
+ int iw = cxld->interleave_ways;
+ int n = 0;
+ u64 hpa;
+
+ if (dev_WARN_ONCE(&cxld->dev,
+ cxld->interleave_ways != cxlsd->nr_targets,
+ "misconfigured root decoder\n"))
+ return NULL;
+
+ hpa = cxlrd->res->start + pos * ig;
+
+ /* Entry (n) is 0 for no interleave (iw == 1) */
+ if (iw != 1)
+ n = cxl_xor_calc_n(hpa, cximsd, iw, ig);
+
+ if (n < 0)
+ return NULL;
+
+ return cxlrd->cxlsd.target[n];
+}
+
+struct cxl_cxims_context {
+ struct device *dev;
+ struct cxl_root_decoder *cxlrd;
+};
+
+static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+{
+ struct acpi_cedt_cxims *cxims = (struct acpi_cedt_cxims *)header;
+ struct cxl_cxims_context *ctx = arg;
+ struct cxl_root_decoder *cxlrd = ctx->cxlrd;
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct device *dev = ctx->dev;
+ struct cxl_cxims_data *cximsd;
+ unsigned int hbig, nr_maps;
+ int rc;
+
+ rc = eig_to_granularity(cxims->hbig, &hbig);
+ if (rc)
+ return rc;
+
+ /* Does this CXIMS entry apply to the given CXL Window? */
+ if (hbig != cxld->interleave_granularity)
+ return 0;
+
+ /* IW 1,3 do not use xormaps and skip this parsing entirely */
+ if (is_power_of_2(cxld->interleave_ways))
+ /* 2, 4, 8, 16 way */
+ nr_maps = ilog2(cxld->interleave_ways);
+ else
+ /* 6, 12 way */
+ nr_maps = ilog2(cxld->interleave_ways / 3);
+
+ if (cxims->nr_xormaps < nr_maps) {
+ dev_dbg(dev, "CXIMS nr_xormaps[%d] expected[%d]\n",
+ cxims->nr_xormaps, nr_maps);
+ return -ENXIO;
+ }
+
+ cximsd = devm_kzalloc(dev, struct_size(cximsd, xormaps, nr_maps),
+ GFP_KERNEL);
+ if (!cximsd)
+ return -ENOMEM;
+ memcpy(cximsd->xormaps, cxims->xormap_list,
+ nr_maps * sizeof(*cximsd->xormaps));
+ cximsd->nr_maps = nr_maps;
+ cxlrd->platform_data = cximsd;
+
+ return 0;
+}
+
static unsigned long cfmws_to_decoder_flags(int restrictions)
{
unsigned long flags = CXL_DECODER_F_ENABLE;
@@ -33,8 +144,10 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
int rc, expected_len;
unsigned int ways;
- if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
- dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
+ if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO &&
+ cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
+ dev_err(dev, "CFMWS Unknown Interleave Arithmetic: %d\n",
+ cfmws->interleave_arithmetic);
return -EINVAL;
}
@@ -48,7 +161,7 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
return -EINVAL;
}
- rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+ rc = eiw_to_ways(cfmws->interleave_ways, &ways);
if (rc) {
dev_err(dev, "CFMWS Interleave Ways (%d) invalid\n",
cfmws->interleave_ways);
@@ -70,6 +183,10 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
return 0;
}
+/*
+ * Note, @dev must be the first member, see 'struct cxl_chbs_context'
+ * and mock_acpi_table_parse_cedt()
+ */
struct cxl_cfmws_context {
struct device *dev;
struct cxl_port *root_port;
@@ -84,9 +201,11 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
struct cxl_cfmws_context *ctx = arg;
struct cxl_port *root_port = ctx->root_port;
struct resource *cxl_res = ctx->cxl_res;
+ struct cxl_cxims_context cxims_ctx;
struct cxl_root_decoder *cxlrd;
struct device *dev = ctx->dev;
struct acpi_cedt_cfmws *cfmws;
+ cxl_calc_hb_fn cxl_calc_hb;
struct cxl_decoder *cxld;
unsigned int ways, i, ig;
struct resource *res;
@@ -102,10 +221,10 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
return 0;
}
- rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+ rc = eiw_to_ways(cfmws->interleave_ways, &ways);
if (rc)
return rc;
- rc = cxl_to_granularity(cfmws->granularity, &ig);
+ rc = eig_to_granularity(cfmws->granularity, &ig);
if (rc)
return rc;
for (i = 0; i < ways; i++)
@@ -128,7 +247,12 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
if (rc)
goto err_insert;
- cxlrd = cxl_root_decoder_alloc(root_port, ways);
+ if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_MODULO)
+ cxl_calc_hb = cxl_hb_modulo;
+ else
+ cxl_calc_hb = cxl_hb_xor;
+
+ cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
if (IS_ERR(cxlrd))
return 0;
@@ -148,7 +272,25 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
ig = CXL_DECODER_MIN_GRANULARITY;
cxld->interleave_granularity = ig;
+ if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
+ if (ways != 1 && ways != 3) {
+ cxims_ctx = (struct cxl_cxims_context) {
+ .dev = dev,
+ .cxlrd = cxlrd,
+ };
+ rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CXIMS,
+ cxl_parse_cxims, &cxims_ctx);
+ if (rc < 0)
+ goto err_xormap;
+ if (!cxlrd->platform_data) {
+ dev_err(dev, "No CXIMS for HBIG %u\n", ig);
+ rc = -EINVAL;
+ goto err_xormap;
+ }
+ }
+ }
rc = cxl_decoder_add(cxld, target_map);
+err_xormap:
if (rc)
put_device(&cxld->dev);
else
@@ -193,34 +335,39 @@ static int add_host_bridge_uport(struct device *match, void *arg)
{
struct cxl_port *root_port = arg;
struct device *host = root_port->dev.parent;
- struct acpi_device *bridge = to_cxl_host_bridge(host, match);
+ struct acpi_device *hb = to_cxl_host_bridge(host, match);
struct acpi_pci_root *pci_root;
struct cxl_dport *dport;
struct cxl_port *port;
+ struct device *bridge;
int rc;
- if (!bridge)
+ if (!hb)
return 0;
- dport = cxl_find_dport_by_dev(root_port, match);
+ pci_root = acpi_pci_find_root(hb->handle);
+ bridge = pci_root->bus->bridge;
+ dport = cxl_find_dport_by_dev(root_port, bridge);
if (!dport) {
dev_dbg(host, "host bridge expected and not found\n");
return 0;
}
- /*
- * Note that this lookup already succeeded in
- * to_cxl_host_bridge(), so no need to check for failure here
- */
- pci_root = acpi_pci_find_root(bridge->handle);
- rc = devm_cxl_register_pci_bus(host, match, pci_root->bus);
+ if (dport->rch) {
+ dev_info(bridge, "host supports CXL (restricted)\n");
+ return 0;
+ }
+
+ rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
if (rc)
return rc;
- port = devm_cxl_add_port(host, match, dport->component_reg_phys, dport);
+ port = devm_cxl_add_port(host, bridge, dport->component_reg_phys,
+ dport);
if (IS_ERR(port))
return PTR_ERR(port);
- dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
+
+ dev_info(bridge, "host supports CXL\n");
return 0;
}
@@ -228,7 +375,9 @@ static int add_host_bridge_uport(struct device *match, void *arg)
struct cxl_chbs_context {
struct device *dev;
unsigned long long uid;
+ resource_size_t rcrb;
resource_size_t chbcr;
+ u32 cxl_version;
};
static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
@@ -244,51 +393,86 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
if (ctx->uid != chbs->uid)
return 0;
- ctx->chbcr = chbs->base;
+
+ ctx->cxl_version = chbs->cxl_version;
+ ctx->rcrb = CXL_RESOURCE_NONE;
+ ctx->chbcr = CXL_RESOURCE_NONE;
+
+ if (!chbs->base)
+ return 0;
+
+ if (chbs->cxl_version != ACPI_CEDT_CHBS_VERSION_CXL11) {
+ ctx->chbcr = chbs->base;
+ return 0;
+ }
+
+ if (chbs->length != CXL_RCRB_SIZE)
+ return 0;
+
+ ctx->rcrb = chbs->base;
+ ctx->chbcr = cxl_rcrb_to_component(ctx->dev, chbs->base,
+ CXL_RCRB_DOWNSTREAM);
return 0;
}
static int add_host_bridge_dport(struct device *match, void *arg)
{
- acpi_status status;
+ acpi_status rc;
+ struct device *bridge;
unsigned long long uid;
struct cxl_dport *dport;
struct cxl_chbs_context ctx;
+ struct acpi_pci_root *pci_root;
struct cxl_port *root_port = arg;
struct device *host = root_port->dev.parent;
- struct acpi_device *bridge = to_cxl_host_bridge(host, match);
+ struct acpi_device *hb = to_cxl_host_bridge(host, match);
- if (!bridge)
+ if (!hb)
return 0;
- status = acpi_evaluate_integer(bridge->handle, METHOD_NAME__UID, NULL,
- &uid);
- if (status != AE_OK) {
- dev_err(host, "unable to retrieve _UID of %s\n",
- dev_name(match));
+ rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid);
+ if (rc != AE_OK) {
+ dev_err(match, "unable to retrieve _UID\n");
return -ENODEV;
}
+ dev_dbg(match, "UID found: %lld\n", uid);
+
ctx = (struct cxl_chbs_context) {
- .dev = host,
+ .dev = match,
.uid = uid,
};
acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx);
- if (ctx.chbcr == 0) {
- dev_warn(host, "No CHBS found for Host Bridge: %s\n",
- dev_name(match));
+ if (!ctx.chbcr) {
+ dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n",
+ uid);
return 0;
}
- dport = devm_cxl_add_dport(root_port, match, uid, ctx.chbcr);
- if (IS_ERR(dport)) {
- dev_err(host, "failed to add downstream port: %s\n",
- dev_name(match));
- return PTR_ERR(dport);
+ if (ctx.rcrb != CXL_RESOURCE_NONE)
+ dev_dbg(match, "RCRB found for UID %lld: %pa\n", uid, &ctx.rcrb);
+
+ if (ctx.chbcr == CXL_RESOURCE_NONE) {
+ dev_warn(match, "CHBCR invalid for Host Bridge (UID %lld)\n",
+ uid);
+ return 0;
}
- dev_dbg(host, "add dport%llu: %s\n", uid, dev_name(match));
+
+ dev_dbg(match, "CHBCR found: %pa\n", &ctx.chbcr);
+
+ pci_root = acpi_pci_find_root(hb->handle);
+ bridge = pci_root->bus->bridge;
+ if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11)
+ dport = devm_cxl_add_rch_dport(root_port, bridge, uid,
+ ctx.chbcr, ctx.rcrb);
+ else
+ dport = devm_cxl_add_dport(root_port, bridge, uid,
+ ctx.chbcr);
+ if (IS_ERR(dport))
+ return PTR_ERR(dport);
+
return 0;
}
@@ -466,7 +650,6 @@ static int cxl_acpi_probe(struct platform_device *pdev)
root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
if (IS_ERR(root_port))
return PTR_ERR(root_port);
- dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
add_host_bridge_dport);
@@ -512,7 +695,8 @@ static int cxl_acpi_probe(struct platform_device *pdev)
return rc;
/* In case PCI is scanned before ACPI re-trigger memdev attach */
- return cxl_bus_rescan();
+ cxl_bus_rescan();
+ return 0;
}
static const struct acpi_device_id cxl_acpi_ids[] = {
@@ -536,7 +720,20 @@ static struct platform_driver cxl_acpi_driver = {
.id_table = cxl_test_ids,
};
-module_platform_driver(cxl_acpi_driver);
+static int __init cxl_acpi_init(void)
+{
+ return platform_driver_register(&cxl_acpi_driver);
+}
+
+static void __exit cxl_acpi_exit(void)
+{
+ platform_driver_unregister(&cxl_acpi_driver);
+ cxl_bus_drain();
+}
+
+module_init(cxl_acpi_init);
+module_exit(cxl_acpi_exit);
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(CXL);
MODULE_IMPORT_NS(ACPI);
+MODULE_SOFTDEP("pre: cxl_pmem");
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 1d8f87be283f..8c04672dca56 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -58,14 +58,6 @@ extern struct rw_semaphore cxl_dpa_rwsem;
bool is_switch_decoder(struct device *dev);
struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
-static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
- struct cxl_memdev *cxlmd)
-{
- if (!port)
- return NULL;
-
- return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
-}
int cxl_memdev_init(void);
void cxl_memdev_exit(void);
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index d1d2caea5c62..dcc16d7cb8f3 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -82,18 +82,23 @@ static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm)
cxlhdm->interleave_mask |= GENMASK(14, 12);
}
-static void __iomem *map_hdm_decoder_regs(struct cxl_port *port,
- void __iomem *crb)
+static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
+ struct cxl_component_regs *regs)
{
- struct cxl_component_reg_map map;
+ struct cxl_register_map map = {
+ .resource = port->component_reg_phys,
+ .base = crb,
+ .max_size = CXL_COMPONENT_REG_BLOCK_SIZE,
+ };
- cxl_probe_component_regs(&port->dev, crb, &map);
- if (!map.hdm_decoder.valid) {
+ cxl_probe_component_regs(&port->dev, crb, &map.component_map);
+ if (!map.component_map.hdm_decoder.valid) {
dev_err(&port->dev, "HDM decoder registers invalid\n");
- return IOMEM_ERR_PTR(-ENXIO);
+ return -ENXIO;
}
- return crb + map.hdm_decoder.offset;
+ return cxl_map_component_regs(&port->dev, regs, &map,
+ BIT(CXL_CM_CAP_CAP_ID_HDM));
}
/**
@@ -103,25 +108,25 @@ static void __iomem *map_hdm_decoder_regs(struct cxl_port *port,
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
{
struct device *dev = &port->dev;
- void __iomem *crb, *hdm;
struct cxl_hdm *cxlhdm;
+ void __iomem *crb;
+ int rc;
cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
if (!cxlhdm)
return ERR_PTR(-ENOMEM);
cxlhdm->port = port;
- crb = devm_cxl_iomap_block(dev, port->component_reg_phys,
- CXL_COMPONENT_REG_BLOCK_SIZE);
+ crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
if (!crb) {
dev_err(dev, "No component registers mapped\n");
return ERR_PTR(-ENXIO);
}
- hdm = map_hdm_decoder_regs(port, crb);
- if (IS_ERR(hdm))
- return ERR_CAST(hdm);
- cxlhdm->regs.hdm_decoder = hdm;
+ rc = map_hdm_decoder_regs(port, crb, &cxlhdm->regs);
+ iounmap(crb);
+ if (rc)
+ return ERR_PTR(rc);
parse_hdm_decoder_caps(cxlhdm);
if (cxlhdm->decoder_count == 0) {
@@ -489,10 +494,10 @@ static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
* Input validation ensures these warns never fire, but otherwise
* suppress unititalized variable usage warnings.
*/
- if (WARN_ONCE(ways_to_cxl(cxld->interleave_ways, &eiw),
+ if (WARN_ONCE(ways_to_eiw(cxld->interleave_ways, &eiw),
"invalid interleave_ways: %d\n", cxld->interleave_ways))
return;
- if (WARN_ONCE(granularity_to_cxl(cxld->interleave_granularity, &eig),
+ if (WARN_ONCE(granularity_to_eig(cxld->interleave_granularity, &eig),
"invalid interleave_granularity: %d\n",
cxld->interleave_granularity))
return;
@@ -736,16 +741,16 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
}
cxld->target_type = CXL_DECODER_EXPANDER;
}
- rc = cxl_to_ways(FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl),
- &cxld->interleave_ways);
+ rc = eiw_to_ways(FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl),
+ &cxld->interleave_ways);
if (rc) {
dev_warn(&port->dev,
"decoder%d.%d: Invalid interleave ways (ctrl: %#x)\n",
port->id, cxld->id, ctrl);
return rc;
}
- rc = cxl_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl),
- &cxld->interleave_granularity);
+ rc = eig_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl),
+ &cxld->interleave_granularity);
if (rc)
return rc;
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 0c90f13870a4..b03fba212799 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -140,13 +140,9 @@ static const char *cxl_mem_opcode_to_name(u16 opcode)
}
/**
- * cxl_mbox_send_cmd() - Send a mailbox command to a device.
+ * cxl_internal_send_cmd() - Kernel internal interface to send a mailbox command
* @cxlds: The device data for the operation
- * @opcode: Opcode for the mailbox command.
- * @in: The input payload for the mailbox command.
- * @in_size: The length of the input payload
- * @out: Caller allocated buffer for the output.
- * @out_size: Expected size of output.
+ * @mbox_cmd: initialized command to execute
*
* Context: Any context.
* Return:
@@ -161,40 +157,40 @@ static const char *cxl_mem_opcode_to_name(u16 opcode)
* error. While this distinction can be useful for commands from userspace, the
* kernel will only be able to use results when both are successful.
*/
-int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in,
- size_t in_size, void *out, size_t out_size)
+int cxl_internal_send_cmd(struct cxl_dev_state *cxlds,
+ struct cxl_mbox_cmd *mbox_cmd)
{
- const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode);
- struct cxl_mbox_cmd mbox_cmd = {
- .opcode = opcode,
- .payload_in = in,
- .size_in = in_size,
- .size_out = out_size,
- .payload_out = out,
- };
+ size_t out_size, min_out;
int rc;
- if (in_size > cxlds->payload_size || out_size > cxlds->payload_size)
+ if (mbox_cmd->size_in > cxlds->payload_size ||
+ mbox_cmd->size_out > cxlds->payload_size)
return -E2BIG;
- rc = cxlds->mbox_send(cxlds, &mbox_cmd);
+ out_size = mbox_cmd->size_out;
+ min_out = mbox_cmd->min_out;
+ rc = cxlds->mbox_send(cxlds, mbox_cmd);
if (rc)
return rc;
- if (mbox_cmd.return_code != CXL_MBOX_CMD_RC_SUCCESS)
- return cxl_mbox_cmd_rc2errno(&mbox_cmd);
+ if (mbox_cmd->return_code != CXL_MBOX_CMD_RC_SUCCESS)
+ return cxl_mbox_cmd_rc2errno(mbox_cmd);
+
+ if (!out_size)
+ return 0;
/*
- * Variable sized commands can't be validated and so it's up to the
- * caller to do that if they wish.
+ * Variable sized output needs to at least satisfy the caller's
+ * minimum if not the fully requested size.
*/
- if (cmd->info.size_out != CXL_VARIABLE_PAYLOAD) {
- if (mbox_cmd.size_out != out_size)
- return -EIO;
- }
+ if (min_out == 0)
+ min_out = out_size;
+
+ if (mbox_cmd->size_out < min_out)
+ return -EIO;
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cxl_mbox_send_cmd, CXL);
+EXPORT_SYMBOL_NS_GPL(cxl_internal_send_cmd, CXL);
static bool cxl_mem_raw_command_allowed(u16 opcode)
{
@@ -561,15 +557,25 @@ static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8
while (remaining) {
u32 xfer_size = min_t(u32, remaining, cxlds->payload_size);
- struct cxl_mbox_get_log log = {
+ struct cxl_mbox_cmd mbox_cmd;
+ struct cxl_mbox_get_log log;
+ int rc;
+
+ log = (struct cxl_mbox_get_log) {
.uuid = *uuid,
.offset = cpu_to_le32(offset),
- .length = cpu_to_le32(xfer_size)
+ .length = cpu_to_le32(xfer_size),
};
- int rc;
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LOG, &log, sizeof(log),
- out, xfer_size);
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_LOG,
+ .size_in = sizeof(log),
+ .payload_in = &log,
+ .size_out = xfer_size,
+ .payload_out = out,
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
if (rc < 0)
return rc;
@@ -615,19 +621,27 @@ static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel)
static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_dev_state *cxlds)
{
struct cxl_mbox_get_supported_logs *ret;
+ struct cxl_mbox_cmd mbox_cmd;
int rc;
ret = kvmalloc(cxlds->payload_size, GFP_KERNEL);
if (!ret)
return ERR_PTR(-ENOMEM);
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, 0, ret,
- cxlds->payload_size);
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_SUPPORTED_LOGS,
+ .size_out = cxlds->payload_size,
+ .payload_out = ret,
+ /* At least the record number field must be valid */
+ .min_out = 2,
+ };
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
if (rc < 0) {
kvfree(ret);
return ERR_PTR(rc);
}
+
return ret;
}
@@ -697,7 +711,6 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
/* Found the required CEL */
rc = 0;
}
-
out:
kvfree(gsl);
return rc;
@@ -719,11 +732,15 @@ EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds)
{
struct cxl_mbox_get_partition_info pi;
+ struct cxl_mbox_cmd mbox_cmd;
int rc;
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0,
- &pi, sizeof(pi));
-
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_PARTITION_INFO,
+ .size_out = sizeof(pi),
+ .payload_out = &pi,
+ };
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
if (rc)
return rc;
@@ -752,10 +769,15 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
{
/* See CXL 2.0 Table 175 Identify Memory Device Output Payload */
struct cxl_mbox_identify id;
+ struct cxl_mbox_cmd mbox_cmd;
int rc;
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id,
- sizeof(id));
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_IDENTIFY,
+ .size_out = sizeof(id),
+ .payload_out = &id,
+ };
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
if (rc < 0)
return rc;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 20ce488a7754..a74a93310d26 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -344,6 +344,7 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
* needed as this is ordered with cdev_add() publishing the device.
*/
cxlmd->cxlds = cxlds;
+ cxlds->cxlmd = cxlmd;
cdev = &cxlmd->cdev;
rc = cdev_device_add(cdev, dev);
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 9240df53ed87..57764e9cd19d 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -54,16 +54,13 @@ static int match_add_dports(struct pci_dev *pdev, void *data)
dev_dbg(&port->dev, "failed to find component registers\n");
port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap);
- dport = devm_cxl_add_dport(port, &pdev->dev, port_num,
- cxl_regmap_to_base(pdev, &map));
+ dport = devm_cxl_add_dport(port, &pdev->dev, port_num, map.resource);
if (IS_ERR(dport)) {
ctx->error = PTR_ERR(dport);
return PTR_ERR(dport);
}
ctx->count++;
- dev_dbg(&port->dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev));
-
return 0;
}
diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c
index 36aa5070d902..f3d2169b6731 100644
--- a/drivers/cxl/core/pmem.c
+++ b/drivers/cxl/core/pmem.c
@@ -99,7 +99,6 @@ static struct cxl_nvdimm_bridge *cxl_nvdimm_bridge_alloc(struct cxl_port *port)
dev = &cxl_nvb->dev;
cxl_nvb->port = port;
- cxl_nvb->state = CXL_NVB_NEW;
device_initialize(dev);
lockdep_set_class(&dev->mutex, &cxl_nvdimm_bridge_key);
device_set_pm_not_required(dev);
@@ -117,28 +116,7 @@ err:
static void unregister_nvb(void *_cxl_nvb)
{
struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb;
- bool flush;
- /*
- * If the bridge was ever activated then there might be in-flight state
- * work to flush. Once the state has been changed to 'dead' then no new
- * work can be queued by user-triggered bind.
- */
- device_lock(&cxl_nvb->dev);
- flush = cxl_nvb->state != CXL_NVB_NEW;
- cxl_nvb->state = CXL_NVB_DEAD;
- device_unlock(&cxl_nvb->dev);
-
- /*
- * Even though the device core will trigger device_release_driver()
- * before the unregister, it does not know about the fact that
- * cxl_nvdimm_bridge_driver defers ->remove() work. So, do the driver
- * release not and flush it before tearing down the nvdimm device
- * hierarchy.
- */
- device_release_driver(&cxl_nvb->dev);
- if (flush)
- flush_work(&cxl_nvb->state_work);
device_unregister(&cxl_nvb->dev);
}
@@ -188,7 +166,6 @@ static void cxl_nvdimm_release(struct device *dev)
{
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
- xa_destroy(&cxl_nvd->pmem_regions);
kfree(cxl_nvd);
}
@@ -220,7 +197,8 @@ EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm, CXL);
static struct lock_class_key cxl_nvdimm_key;
-static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
+static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb,
+ struct cxl_memdev *cxlmd)
{
struct cxl_nvdimm *cxl_nvd;
struct device *dev;
@@ -231,38 +209,78 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
dev = &cxl_nvd->dev;
cxl_nvd->cxlmd = cxlmd;
- xa_init(&cxl_nvd->pmem_regions);
+ cxlmd->cxl_nvd = cxl_nvd;
device_initialize(dev);
lockdep_set_class(&dev->mutex, &cxl_nvdimm_key);
device_set_pm_not_required(dev);
dev->parent = &cxlmd->dev;
dev->bus = &cxl_bus_type;
dev->type = &cxl_nvdimm_type;
+ /*
+ * A "%llx" string is 17-bytes vs dimm_id that is max
+ * NVDIMM_KEY_DESC_LEN
+ */
+ BUILD_BUG_ON(sizeof(cxl_nvd->dev_id) < 17 ||
+ sizeof(cxl_nvd->dev_id) > NVDIMM_KEY_DESC_LEN);
+ sprintf(cxl_nvd->dev_id, "%llx", cxlmd->cxlds->serial);
return cxl_nvd;
}
-static void cxl_nvd_unregister(void *dev)
+static void cxl_nvd_unregister(void *_cxl_nvd)
{
- device_unregister(dev);
+ struct cxl_nvdimm *cxl_nvd = _cxl_nvd;
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;
+
+ /*
+ * Either the bridge is in ->remove() context under the device_lock(),
+ * or cxlmd_release_nvdimm() is cancelling the bridge's release action
+ * for @cxl_nvd and doing it itself (while manually holding the bridge
+ * lock).
+ */
+ device_lock_assert(&cxl_nvb->dev);
+ cxl_nvd->cxlmd = NULL;
+ cxlmd->cxl_nvd = NULL;
+ device_unregister(&cxl_nvd->dev);
+}
+
+static void cxlmd_release_nvdimm(void *_cxlmd)
+{
+ struct cxl_memdev *cxlmd = _cxlmd;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;
+
+ device_lock(&cxl_nvb->dev);
+ if (cxlmd->cxl_nvd)
+ devm_release_action(&cxl_nvb->dev, cxl_nvd_unregister,
+ cxlmd->cxl_nvd);
+ device_unlock(&cxl_nvb->dev);
+ put_device(&cxl_nvb->dev);
}
/**
* devm_cxl_add_nvdimm() - add a bridge between a cxl_memdev and an nvdimm
- * @host: same host as @cxlmd
* @cxlmd: cxl_memdev instance that will perform LIBNVDIMM operations
*
* Return: 0 on success negative error code on failure.
*/
-int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd)
+int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)
{
+ struct cxl_nvdimm_bridge *cxl_nvb;
struct cxl_nvdimm *cxl_nvd;
struct device *dev;
int rc;
- cxl_nvd = cxl_nvdimm_alloc(cxlmd);
- if (IS_ERR(cxl_nvd))
- return PTR_ERR(cxl_nvd);
+ cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
+ if (!cxl_nvb)
+ return -ENODEV;
+
+ cxl_nvd = cxl_nvdimm_alloc(cxl_nvb, cxlmd);
+ if (IS_ERR(cxl_nvd)) {
+ rc = PTR_ERR(cxl_nvd);
+ goto err_alloc;
+ }
+ cxlmd->cxl_nvb = cxl_nvb;
dev = &cxl_nvd->dev;
rc = dev_set_name(dev, "pmem%d", cxlmd->id);
@@ -273,13 +291,34 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd)
if (rc)
goto err;
- dev_dbg(host, "%s: register %s\n", dev_name(dev->parent),
- dev_name(dev));
+ dev_dbg(&cxlmd->dev, "register %s\n", dev_name(dev));
+
+ /*
+ * The two actions below arrange for @cxl_nvd to be deleted when either
+ * the top-level PMEM bridge goes down, or the endpoint device goes
+ * through ->remove().
+ */
+ device_lock(&cxl_nvb->dev);
+ if (cxl_nvb->dev.driver)
+ rc = devm_add_action_or_reset(&cxl_nvb->dev, cxl_nvd_unregister,
+ cxl_nvd);
+ else
+ rc = -ENXIO;
+ device_unlock(&cxl_nvb->dev);
- return devm_add_action_or_reset(host, cxl_nvd_unregister, dev);
+ if (rc)
+ goto err_alloc;
+
+ /* @cxlmd carries a reference on @cxl_nvb until cxlmd_release_nvdimm */
+ return devm_add_action_or_reset(&cxlmd->dev, cxlmd_release_nvdimm, cxlmd);
err:
put_device(dev);
+err_alloc:
+ cxlmd->cxl_nvb = NULL;
+ cxlmd->cxl_nvd = NULL;
+ put_device(&cxl_nvb->dev);
+
return rc;
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm, CXL);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index e7556864ea80..b631a0520456 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -628,6 +628,8 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
iter = to_cxl_port(iter->dev.parent);
if (iter->host_bridge)
port->host_bridge = iter->host_bridge;
+ else if (parent_dport->rch)
+ port->host_bridge = parent_dport->dport;
else
port->host_bridge = iter->uport;
dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge));
@@ -655,16 +657,10 @@ err:
return ERR_PTR(rc);
}
-/**
- * devm_cxl_add_port - register a cxl_port in CXL memory decode hierarchy
- * @host: host device for devm operations
- * @uport: "physical" device implementing this upstream port
- * @component_reg_phys: (optional) for configurable cxl_port instances
- * @parent_dport: next hop up in the CXL memory decode hierarchy
- */
-struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
- resource_size_t component_reg_phys,
- struct cxl_dport *parent_dport)
+static struct cxl_port *__devm_cxl_add_port(struct device *host,
+ struct device *uport,
+ resource_size_t component_reg_phys,
+ struct cxl_dport *parent_dport)
{
struct cxl_port *port;
struct device *dev;
@@ -702,6 +698,41 @@ err:
put_device(dev);
return ERR_PTR(rc);
}
+
+/**
+ * devm_cxl_add_port - register a cxl_port in CXL memory decode hierarchy
+ * @host: host device for devm operations
+ * @uport: "physical" device implementing this upstream port
+ * @component_reg_phys: (optional) for configurable cxl_port instances
+ * @parent_dport: next hop up in the CXL memory decode hierarchy
+ */
+struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
+ resource_size_t component_reg_phys,
+ struct cxl_dport *parent_dport)
+{
+ struct cxl_port *port, *parent_port;
+
+ port = __devm_cxl_add_port(host, uport, component_reg_phys,
+ parent_dport);
+
+ parent_port = parent_dport ? parent_dport->port : NULL;
+ if (IS_ERR(port)) {
+ dev_dbg(uport, "Failed to add %s%s%s%s: %ld\n",
+ dev_name(&port->dev),
+ parent_port ? " to " : "",
+ parent_port ? dev_name(&parent_port->dev) : "",
+ parent_port ? "" : " (root port)",
+ PTR_ERR(port));
+ } else {
+ dev_dbg(uport, "%s added%s%s%s\n",
+ dev_name(&port->dev),
+ parent_port ? " to " : "",
+ parent_port ? dev_name(&parent_port->dev) : "",
+ parent_port ? "" : " (root port)");
+ }
+
+ return port;
+}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL);
struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port)
@@ -870,20 +901,10 @@ static void cxl_dport_unlink(void *data)
sysfs_remove_link(&port->dev.kobj, link_name);
}
-/**
- * devm_cxl_add_dport - append downstream port data to a cxl_port
- * @port: the cxl_port that references this dport
- * @dport_dev: firmware or PCI device representing the dport
- * @port_id: identifier for this dport in a decoder's target list
- * @component_reg_phys: optional location of CXL component registers
- *
- * Note that dports are appended to the devm release action's of the
- * either the port's host (for root ports), or the port itself (for
- * switch ports)
- */
-struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
- struct device *dport_dev, int port_id,
- resource_size_t component_reg_phys)
+static struct cxl_dport *
+__devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
+ int port_id, resource_size_t component_reg_phys,
+ resource_size_t rcrb)
{
char link_name[CXL_TARGET_STRLEN];
struct cxl_dport *dport;
@@ -913,6 +934,9 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
dport->port_id = port_id;
dport->component_reg_phys = component_reg_phys;
dport->port = port;
+ if (rcrb != CXL_RESOURCE_NONE)
+ dport->rch = true;
+ dport->rcrb = rcrb;
cond_cxl_root_lock(port);
rc = add_dport(port, dport);
@@ -935,8 +959,74 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
return dport;
}
+
+/**
+ * devm_cxl_add_dport - append VH downstream port data to a cxl_port
+ * @port: the cxl_port that references this dport
+ * @dport_dev: firmware or PCI device representing the dport
+ * @port_id: identifier for this dport in a decoder's target list
+ * @component_reg_phys: optional location of CXL component registers
+ *
+ * Note that dports are appended to the devm release action's of the
+ * either the port's host (for root ports), or the port itself (for
+ * switch ports)
+ */
+struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
+ struct device *dport_dev, int port_id,
+ resource_size_t component_reg_phys)
+{
+ struct cxl_dport *dport;
+
+ dport = __devm_cxl_add_dport(port, dport_dev, port_id,
+ component_reg_phys, CXL_RESOURCE_NONE);
+ if (IS_ERR(dport)) {
+ dev_dbg(dport_dev, "failed to add dport to %s: %ld\n",
+ dev_name(&port->dev), PTR_ERR(dport));
+ } else {
+ dev_dbg(dport_dev, "dport added to %s\n",
+ dev_name(&port->dev));
+ }
+
+ return dport;
+}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL);
+/**
+ * devm_cxl_add_rch_dport - append RCH downstream port data to a cxl_port
+ * @port: the cxl_port that references this dport
+ * @dport_dev: firmware or PCI device representing the dport
+ * @port_id: identifier for this dport in a decoder's target list
+ * @component_reg_phys: optional location of CXL component registers
+ * @rcrb: mandatory location of a Root Complex Register Block
+ *
+ * See CXL 3.0 9.11.8 CXL Devices Attached to an RCH
+ */
+struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
+ struct device *dport_dev, int port_id,
+ resource_size_t component_reg_phys,
+ resource_size_t rcrb)
+{
+ struct cxl_dport *dport;
+
+ if (rcrb == CXL_RESOURCE_NONE) {
+ dev_dbg(&port->dev, "failed to add RCH dport, missing RCRB\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dport = __devm_cxl_add_dport(port, dport_dev, port_id,
+ component_reg_phys, rcrb);
+ if (IS_ERR(dport)) {
+ dev_dbg(dport_dev, "failed to add RCH dport to %s: %ld\n",
+ dev_name(&port->dev), PTR_ERR(dport));
+ } else {
+ dev_dbg(dport_dev, "RCH dport added to %s\n",
+ dev_name(&port->dev));
+ }
+
+ return dport;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_rch_dport, CXL);
+
static int add_ep(struct cxl_ep *new)
{
struct cxl_port *port = new->dport->port;
@@ -1122,47 +1212,6 @@ static void reap_dports(struct cxl_port *port)
}
}
-int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
- struct cxl_dport *parent_dport)
-{
- struct cxl_port *parent_port = parent_dport->port;
- struct cxl_dev_state *cxlds = cxlmd->cxlds;
- struct cxl_port *endpoint, *iter, *down;
- int rc;
-
- /*
- * Now that the path to the root is established record all the
- * intervening ports in the chain.
- */
- for (iter = parent_port, down = NULL; !is_cxl_root(iter);
- down = iter, iter = to_cxl_port(iter->dev.parent)) {
- struct cxl_ep *ep;
-
- ep = cxl_ep_load(iter, cxlmd);
- ep->next = down;
- }
-
- endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
- cxlds->component_reg_phys, parent_dport);
- if (IS_ERR(endpoint))
- return PTR_ERR(endpoint);
-
- dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
-
- rc = cxl_endpoint_autoremove(cxlmd, endpoint);
- if (rc)
- return rc;
-
- if (!endpoint->dev.driver) {
- dev_err(&cxlmd->dev, "%s failed probe\n",
- dev_name(&endpoint->dev));
- return -ENXIO;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL);
-
static void cxl_detach_ep(void *data)
{
struct cxl_memdev *cxlmd = data;
@@ -1243,7 +1292,7 @@ static resource_size_t find_component_registers(struct device *dev)
pdev = to_pci_dev(dev);
cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map);
- return cxl_regmap_to_base(pdev, &map);
+ return map.resource;
}
static int add_port_attach_ep(struct cxl_memdev *cxlmd,
@@ -1320,6 +1369,13 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd)
struct device *iter;
int rc;
+ /*
+ * Skip intermediate port enumeration in the RCH case, there
+ * are no ports in between a host bridge and an endpoint.
+ */
+ if (cxlmd->cxlds->rcd)
+ return 0;
+
rc = devm_add_action_or_reset(&cxlmd->dev, cxl_detach_ep, cxlmd);
if (rc)
return rc;
@@ -1428,7 +1484,7 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
return rc;
}
-static struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
+struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
{
struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
struct cxl_decoder *cxld = &cxlsd->cxld;
@@ -1441,6 +1497,7 @@ static struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
return cxlrd->cxlsd.target[pos % iw];
}
+EXPORT_SYMBOL_NS_GPL(cxl_hb_modulo, CXL);
static struct lock_class_key cxl_decoder_key;
@@ -1502,6 +1559,7 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
* cxl_root_decoder_alloc - Allocate a root level decoder
* @port: owning CXL root of this decoder
* @nr_targets: static number of downstream targets
+ * @calc_hb: which host bridge covers the n'th position by granularity
*
* Return: A new cxl decoder to be registered by cxl_decoder_add(). A
* 'CXL root' decoder is one that decodes from a top-level / static platform
@@ -1509,7 +1567,8 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
* topology.
*/
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets)
+ unsigned int nr_targets,
+ cxl_calc_hb_fn calc_hb)
{
struct cxl_root_decoder *cxlrd;
struct cxl_switch_decoder *cxlsd;
@@ -1531,7 +1590,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
return ERR_PTR(rc);
}
- cxlrd->calc_hb = cxl_hb_modulo;
+ cxlrd->calc_hb = calc_hb;
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
@@ -1797,12 +1856,27 @@ static void cxl_bus_remove(struct device *dev)
static struct workqueue_struct *cxl_bus_wq;
-int cxl_bus_rescan(void)
+static void cxl_bus_rescan_queue(struct work_struct *w)
{
- return bus_rescan_devices(&cxl_bus_type);
+ int rc = bus_rescan_devices(&cxl_bus_type);
+
+ pr_debug("CXL bus rescan result: %d\n", rc);
+}
+
+void cxl_bus_rescan(void)
+{
+ static DECLARE_WORK(rescan_work, cxl_bus_rescan_queue);
+
+ queue_work(cxl_bus_wq, &rescan_work);
}
EXPORT_SYMBOL_NS_GPL(cxl_bus_rescan, CXL);
+void cxl_bus_drain(void)
+{
+ drain_workqueue(cxl_bus_wq);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, CXL);
+
bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
{
return queue_work(cxl_bus_wq, &cxlmd->detach_work);
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index f9ae5ad284ff..02f28da519e3 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -324,7 +324,7 @@ static ssize_t interleave_ways_store(struct device *dev,
if (rc)
return rc;
- rc = ways_to_cxl(val, &iw);
+ rc = ways_to_eiw(val, &iw);
if (rc)
return rc;
@@ -391,7 +391,7 @@ static ssize_t interleave_granularity_store(struct device *dev,
if (rc)
return rc;
- rc = granularity_to_cxl(val, &ig);
+ rc = granularity_to_eig(val, &ig);
if (rc)
return rc;
@@ -1028,7 +1028,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
parent_iw = parent_cxld->interleave_ways;
}
- rc = granularity_to_cxl(parent_ig, &peig);
+ rc = granularity_to_eig(parent_ig, &peig);
if (rc) {
dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n",
dev_name(parent_port->uport),
@@ -1036,7 +1036,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
return rc;
}
- rc = ways_to_cxl(parent_iw, &peiw);
+ rc = ways_to_eiw(parent_iw, &peiw);
if (rc) {
dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n",
dev_name(parent_port->uport),
@@ -1045,7 +1045,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
}
iw = cxl_rr->nr_targets;
- rc = ways_to_cxl(iw, &eiw);
+ rc = ways_to_eiw(iw, &eiw);
if (rc) {
dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n",
dev_name(port->uport), dev_name(&port->dev), iw);
@@ -1065,7 +1065,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
eig = peig;
}
- rc = cxl_to_granularity(eig, &ig);
+ rc = eig_to_granularity(eig, &ig);
if (rc) {
dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n",
dev_name(port->uport), dev_name(&port->dev),
@@ -1226,7 +1226,7 @@ static int cxl_region_attach(struct cxl_region *cxlr,
struct cxl_endpoint_decoder *cxled_target;
struct cxl_memdev *cxlmd_target;
- cxled_target = p->targets[pos];
+ cxled_target = p->targets[i];
if (!cxled_target)
continue;
@@ -1403,6 +1403,8 @@ static int attach_target(struct cxl_region *cxlr, const char *decoder, int pos)
goto out;
down_read(&cxl_dpa_rwsem);
rc = cxl_region_attach(cxlr, to_cxl_endpoint_decoder(dev), pos);
+ if (rc == 0)
+ set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
up_read(&cxl_dpa_rwsem);
up_write(&cxl_region_rwsem);
out:
@@ -1812,6 +1814,7 @@ static struct lock_class_key cxl_pmem_region_key;
static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
{
struct cxl_region_params *p = &cxlr->params;
+ struct cxl_nvdimm_bridge *cxl_nvb;
struct cxl_pmem_region *cxlr_pmem;
struct device *dev;
int i;
@@ -1839,6 +1842,18 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+ /*
+ * Regions never span CXL root devices, so by definition the
+ * bridge for one device is the same for all.
+ */
+ if (i == 0) {
+ cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
+ if (!cxl_nvb) {
+ cxlr_pmem = ERR_PTR(-ENODEV);
+ goto out;
+ }
+ cxlr->cxl_nvb = cxl_nvb;
+ }
m->cxlmd = cxlmd;
get_device(&cxlmd->dev);
m->start = cxled->dpa_res->start;
@@ -1848,6 +1863,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
dev = &cxlr_pmem->dev;
cxlr_pmem->cxlr = cxlr;
+ cxlr->cxlr_pmem = cxlr_pmem;
device_initialize(dev);
lockdep_set_class(&dev->mutex, &cxl_pmem_region_key);
device_set_pm_not_required(dev);
@@ -1860,9 +1876,36 @@ out:
return cxlr_pmem;
}
-static void cxlr_pmem_unregister(void *dev)
+static void cxlr_pmem_unregister(void *_cxlr_pmem)
{
- device_unregister(dev);
+ struct cxl_pmem_region *cxlr_pmem = _cxlr_pmem;
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
+
+ /*
+ * Either the bridge is in ->remove() context under the device_lock(),
+ * or cxlr_release_nvdimm() is cancelling the bridge's release action
+ * for @cxlr_pmem and doing it itself (while manually holding the bridge
+ * lock).
+ */
+ device_lock_assert(&cxl_nvb->dev);
+ cxlr->cxlr_pmem = NULL;
+ cxlr_pmem->cxlr = NULL;
+ device_unregister(&cxlr_pmem->dev);
+}
+
+static void cxlr_release_nvdimm(void *_cxlr)
+{
+ struct cxl_region *cxlr = _cxlr;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
+
+ device_lock(&cxl_nvb->dev);
+ if (cxlr->cxlr_pmem)
+ devm_release_action(&cxl_nvb->dev, cxlr_pmem_unregister,
+ cxlr->cxlr_pmem);
+ device_unlock(&cxl_nvb->dev);
+ cxlr->cxl_nvb = NULL;
+ put_device(&cxl_nvb->dev);
}
/**
@@ -1874,12 +1917,14 @@ static void cxlr_pmem_unregister(void *dev)
static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
{
struct cxl_pmem_region *cxlr_pmem;
+ struct cxl_nvdimm_bridge *cxl_nvb;
struct device *dev;
int rc;
cxlr_pmem = cxl_pmem_region_alloc(cxlr);
if (IS_ERR(cxlr_pmem))
return PTR_ERR(cxlr_pmem);
+ cxl_nvb = cxlr->cxl_nvb;
dev = &cxlr_pmem->dev;
rc = dev_set_name(dev, "pmem_region%d", cxlr->id);
@@ -1893,13 +1938,52 @@ static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
dev_name(dev));
- return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev);
+ device_lock(&cxl_nvb->dev);
+ if (cxl_nvb->dev.driver)
+ rc = devm_add_action_or_reset(&cxl_nvb->dev,
+ cxlr_pmem_unregister, cxlr_pmem);
+ else
+ rc = -ENXIO;
+ device_unlock(&cxl_nvb->dev);
+
+ if (rc)
+ goto err_bridge;
+
+ /* @cxlr carries a reference on @cxl_nvb until cxlr_release_nvdimm */
+ return devm_add_action_or_reset(&cxlr->dev, cxlr_release_nvdimm, cxlr);
err:
put_device(dev);
+err_bridge:
+ put_device(&cxl_nvb->dev);
+ cxlr->cxl_nvb = NULL;
return rc;
}
+static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
+{
+ if (!test_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags))
+ return 0;
+
+ if (!cpu_cache_has_invalidate_memregion()) {
+ if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) {
+ dev_warn(
+ &cxlr->dev,
+ "Bypassing cpu_cache_invalidate_memregion() for testing!\n");
+ clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
+ return 0;
+ } else {
+ dev_err(&cxlr->dev,
+ "Failed to synchronize CPU cache state\n");
+ return -ENXIO;
+ }
+ }
+
+ cpu_cache_invalidate_memregion(IORES_DESC_CXL);
+ clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
+ return 0;
+}
+
static int cxl_region_probe(struct device *dev)
{
struct cxl_region *cxlr = to_cxl_region(dev);
@@ -1915,14 +1999,21 @@ static int cxl_region_probe(struct device *dev)
if (p->state < CXL_CONFIG_COMMIT) {
dev_dbg(&cxlr->dev, "config state: %d\n", p->state);
rc = -ENXIO;
+ goto out;
}
+ rc = cxl_region_invalidate_memregion(cxlr);
+
/*
* From this point on any path that changes the region's state away from
* CXL_CONFIG_COMMIT is also responsible for releasing the driver.
*/
+out:
up_read(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
switch (cxlr->mode) {
case CXL_DECODER_PMEM:
return devm_cxl_add_pmem_region(cxlr);
@@ -1950,4 +2041,5 @@ void cxl_region_exit(void)
}
MODULE_IMPORT_NS(CXL);
+MODULE_IMPORT_NS(DEVMEM);
MODULE_ALIAS_CXL(CXL_DEVICE_REGION);
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 39a129c57d40..1476a0299c9b 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -7,6 +7,8 @@
#include <cxlmem.h>
#include <cxlpci.h>
+#include "core.h"
+
/**
* DOC: cxl registers
*
@@ -59,36 +61,48 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base,
for (cap = 1; cap <= cap_count; cap++) {
void __iomem *register_block;
- u32 hdr;
- int decoder_cnt;
+ struct cxl_reg_map *rmap;
u16 cap_id, offset;
- u32 length;
+ u32 length, hdr;
hdr = readl(base + cap * 0x4);
cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr);
offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr);
register_block = base + offset;
+ hdr = readl(register_block);
+ rmap = NULL;
switch (cap_id) {
- case CXL_CM_CAP_CAP_ID_HDM:
+ case CXL_CM_CAP_CAP_ID_HDM: {
+ int decoder_cnt;
+
dev_dbg(dev, "found HDM decoder capability (0x%x)\n",
offset);
- hdr = readl(register_block);
-
decoder_cnt = cxl_hdm_decoder_count(hdr);
length = 0x20 * decoder_cnt + 0x10;
-
- map->hdm_decoder.valid = true;
- map->hdm_decoder.offset = CXL_CM_OFFSET + offset;
- map->hdm_decoder.size = length;
+ rmap = &map->hdm_decoder;
+ break;
+ }
+ case CXL_CM_CAP_CAP_ID_RAS:
+ dev_dbg(dev, "found RAS capability (0x%x)\n",
+ offset);
+ length = CXL_RAS_CAPABILITY_LENGTH;
+ rmap = &map->ras;
break;
default:
dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id,
offset);
break;
}
+
+ if (!rmap)
+ continue;
+ rmap->valid = true;
+ rmap->id = cap_id;
+ rmap->offset = CXL_CM_OFFSET + offset;
+ rmap->size = length;
}
}
EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL);
@@ -117,6 +131,7 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base,
cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);
for (cap = 1; cap <= cap_count; cap++) {
+ struct cxl_reg_map *rmap;
u32 offset, length;
u16 cap_id;
@@ -125,28 +140,22 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base,
offset = readl(base + cap * 0x10 + 0x4);
length = readl(base + cap * 0x10 + 0x8);
+ rmap = NULL;
switch (cap_id) {
case CXLDEV_CAP_CAP_ID_DEVICE_STATUS:
dev_dbg(dev, "found Status capability (0x%x)\n", offset);
-
- map->status.valid = true;
- map->status.offset = offset;
- map->status.size = length;
+ rmap = &map->status;
break;
case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:
dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);
- map->mbox.valid = true;
- map->mbox.offset = offset;
- map->mbox.size = length;
+ rmap = &map->mbox;
break;
case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX:
dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset);
break;
case CXLDEV_CAP_CAP_ID_MEMDEV:
dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset);
- map->memdev.valid = true;
- map->memdev.offset = offset;
- map->memdev.size = length;
+ rmap = &map->memdev;
break;
default:
if (cap_id >= 0x8000)
@@ -155,6 +164,13 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base,
dev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset);
break;
}
+
+ if (!rmap)
+ continue;
+ rmap->valid = true;
+ rmap->id = cap_id;
+ rmap->offset = offset;
+ rmap->size = length;
}
}
EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL);
@@ -165,6 +181,9 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
void __iomem *ret_val;
struct resource *res;
+ if (WARN_ON_ONCE(addr == CXL_RESOURCE_NONE))
+ return NULL;
+
res = devm_request_mem_region(dev, addr, length, dev_name(dev));
if (!res) {
resource_size_t end = addr + length - 1;
@@ -180,67 +199,65 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
return ret_val;
}
-int cxl_map_component_regs(struct pci_dev *pdev,
- struct cxl_component_regs *regs,
- struct cxl_register_map *map)
+int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs,
+ struct cxl_register_map *map, unsigned long map_mask)
{
- struct device *dev = &pdev->dev;
- resource_size_t phys_addr;
- resource_size_t length;
-
- phys_addr = pci_resource_start(pdev, map->barno);
- phys_addr += map->block_offset;
+ struct mapinfo {
+ struct cxl_reg_map *rmap;
+ void __iomem **addr;
+ } mapinfo[] = {
+ { &map->component_map.hdm_decoder, &regs->hdm_decoder },
+ { &map->component_map.ras, &regs->ras },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mapinfo); i++) {
+ struct mapinfo *mi = &mapinfo[i];
+ resource_size_t phys_addr;
+ resource_size_t length;
- phys_addr += map->component_map.hdm_decoder.offset;
- length = map->component_map.hdm_decoder.size;
- regs->hdm_decoder = devm_cxl_iomap_block(dev, phys_addr, length);
- if (!regs->hdm_decoder)
- return -ENOMEM;
+ if (!mi->rmap->valid)
+ continue;
+ if (!test_bit(mi->rmap->id, &map_mask))
+ continue;
+ phys_addr = map->resource + mi->rmap->offset;
+ length = mi->rmap->size;
+ *(mi->addr) = devm_cxl_iomap_block(dev, phys_addr, length);
+ if (!*(mi->addr))
+ return -ENOMEM;
+ }
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL);
-int cxl_map_device_regs(struct pci_dev *pdev,
+int cxl_map_device_regs(struct device *dev,
struct cxl_device_regs *regs,
struct cxl_register_map *map)
{
- struct device *dev = &pdev->dev;
- resource_size_t phys_addr;
-
- phys_addr = pci_resource_start(pdev, map->barno);
- phys_addr += map->block_offset;
-
- if (map->device_map.status.valid) {
- resource_size_t addr;
+ resource_size_t phys_addr = map->resource;
+ struct mapinfo {
+ struct cxl_reg_map *rmap;
+ void __iomem **addr;
+ } mapinfo[] = {
+ { &map->device_map.status, &regs->status, },
+ { &map->device_map.mbox, &regs->mbox, },
+ { &map->device_map.memdev, &regs->memdev, },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mapinfo); i++) {
+ struct mapinfo *mi = &mapinfo[i];
resource_size_t length;
-
- addr = phys_addr + map->device_map.status.offset;
- length = map->device_map.status.size;
- regs->status = devm_cxl_iomap_block(dev, addr, length);
- if (!regs->status)
- return -ENOMEM;
- }
-
- if (map->device_map.mbox.valid) {
resource_size_t addr;
- resource_size_t length;
- addr = phys_addr + map->device_map.mbox.offset;
- length = map->device_map.mbox.size;
- regs->mbox = devm_cxl_iomap_block(dev, addr, length);
- if (!regs->mbox)
- return -ENOMEM;
- }
-
- if (map->device_map.memdev.valid) {
- resource_size_t addr;
- resource_size_t length;
+ if (!mi->rmap->valid)
+ continue;
- addr = phys_addr + map->device_map.memdev.offset;
- length = map->device_map.memdev.size;
- regs->memdev = devm_cxl_iomap_block(dev, addr, length);
- if (!regs->memdev)
+ addr = phys_addr + mi->rmap->offset;
+ length = mi->rmap->size;
+ *(mi->addr) = devm_cxl_iomap_block(dev, addr, length);
+ if (!*(mi->addr))
return -ENOMEM;
}
@@ -248,13 +265,24 @@ int cxl_map_device_regs(struct pci_dev *pdev,
}
EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL);
-static void cxl_decode_regblock(u32 reg_lo, u32 reg_hi,
+static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
struct cxl_register_map *map)
{
- map->block_offset = ((u64)reg_hi << 32) |
- (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
- map->barno = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo);
+ int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo);
+ u64 offset = ((u64)reg_hi << 32) |
+ (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
+
+ if (offset > pci_resource_len(pdev, bar)) {
+ dev_warn(&pdev->dev,
+ "BAR%d: %pr: too small (offset: %pa, type: %d)\n", bar,
+ &pdev->resource[bar], &offset, map->reg_type);
+ return false;
+ }
+
map->reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
+ map->resource = pci_resource_start(pdev, bar) + offset;
+ map->max_size = pci_resource_len(pdev, bar) - offset;
+ return true;
}
/**
@@ -274,7 +302,7 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
u32 regloc_size, regblocks;
int regloc, i;
- map->block_offset = U64_MAX;
+ map->resource = CXL_RESOURCE_NONE;
regloc = pci_find_dvsec_capability(pdev, PCI_DVSEC_VENDOR_ID_CXL,
CXL_DVSEC_REG_LOCATOR);
if (!regloc)
@@ -292,13 +320,79 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
pci_read_config_dword(pdev, regloc, &reg_lo);
pci_read_config_dword(pdev, regloc + 4, &reg_hi);
- cxl_decode_regblock(reg_lo, reg_hi, map);
+ if (!cxl_decode_regblock(pdev, reg_lo, reg_hi, map))
+ continue;
if (map->reg_type == type)
return 0;
}
- map->block_offset = U64_MAX;
+ map->resource = CXL_RESOURCE_NONE;
return -ENODEV;
}
EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL);
+
+resource_size_t cxl_rcrb_to_component(struct device *dev,
+ resource_size_t rcrb,
+ enum cxl_rcrb which)
+{
+ resource_size_t component_reg_phys;
+ void __iomem *addr;
+ u32 bar0, bar1;
+ u16 cmd;
+ u32 id;
+
+ if (which == CXL_RCRB_UPSTREAM)
+ rcrb += SZ_4K;
+
+ /*
+ * RCRB's BAR[0..1] point to component block containing CXL
+ * subsystem component registers. MEMBAR extraction follows
+ * the PCI Base spec here, esp. 64 bit extraction and memory
+ * ranges alignment (6.0, 7.5.1.2.1).
+ */
+ if (!request_mem_region(rcrb, SZ_4K, "CXL RCRB"))
+ return CXL_RESOURCE_NONE;
+ addr = ioremap(rcrb, SZ_4K);
+ if (!addr) {
+ dev_err(dev, "Failed to map region %pr\n", addr);
+ release_mem_region(rcrb, SZ_4K);
+ return CXL_RESOURCE_NONE;
+ }
+
+ id = readl(addr + PCI_VENDOR_ID);
+ cmd = readw(addr + PCI_COMMAND);
+ bar0 = readl(addr + PCI_BASE_ADDRESS_0);
+ bar1 = readl(addr + PCI_BASE_ADDRESS_1);
+ iounmap(addr);
+ release_mem_region(rcrb, SZ_4K);
+
+ /*
+ * Sanity check, see CXL 3.0 Figure 9-8 CXL Device that Does Not
+ * Remap Upstream Port and Component Registers
+ */
+ if (id == U32_MAX) {
+ if (which == CXL_RCRB_DOWNSTREAM)
+ dev_err(dev, "Failed to access Downstream Port RCRB\n");
+ return CXL_RESOURCE_NONE;
+ }
+ if (!(cmd & PCI_COMMAND_MEMORY))
+ return CXL_RESOURCE_NONE;
+ /* The RCRB is a Memory Window, and the MEM_TYPE_1M bit is obsolete */
+ if (bar0 & (PCI_BASE_ADDRESS_MEM_TYPE_1M | PCI_BASE_ADDRESS_SPACE_IO))
+ return CXL_RESOURCE_NONE;
+
+ component_reg_phys = bar0 & PCI_BASE_ADDRESS_MEM_MASK;
+ if (bar0 & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ component_reg_phys |= ((u64)bar1) << 32;
+
+ if (!component_reg_phys)
+ return CXL_RESOURCE_NONE;
+
+ /* MEMBAR is block size (64k) aligned. */
+ if (!IS_ALIGNED(component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE))
+ return CXL_RESOURCE_NONE;
+
+ return component_reg_phys;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_component, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ac75554b5d76..1b1cf459ac77 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -33,6 +33,7 @@
#define CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)
#define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
+#define CXL_CM_CAP_CAP_ID_RAS 0x2
#define CXL_CM_CAP_CAP_ID_HDM 0x5
#define CXL_CM_CAP_CAP_HDM_VERSION 1
@@ -61,6 +62,10 @@
#define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i)
#define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i)
+/* HDM decoder control register constants CXL 3.0 8.2.5.19.7 */
+#define CXL_DECODER_MIN_GRANULARITY 256
+#define CXL_DECODER_MAX_ENCODED_IG 6
+
static inline int cxl_hdm_decoder_count(u32 cap_hdr)
{
int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr);
@@ -69,23 +74,23 @@ static inline int cxl_hdm_decoder_count(u32 cap_hdr)
}
/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
-static inline int cxl_to_granularity(u16 ig, unsigned int *val)
+static inline int eig_to_granularity(u16 eig, unsigned int *granularity)
{
- if (ig > 6)
+ if (eig > CXL_DECODER_MAX_ENCODED_IG)
return -EINVAL;
- *val = 256 << ig;
+ *granularity = CXL_DECODER_MIN_GRANULARITY << eig;
return 0;
}
/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
-static inline int cxl_to_ways(u8 eniw, unsigned int *val)
+static inline int eiw_to_ways(u8 eiw, unsigned int *ways)
{
- switch (eniw) {
+ switch (eiw) {
case 0 ... 4:
- *val = 1 << eniw;
+ *ways = 1 << eiw;
break;
case 8 ... 10:
- *val = 3 << (eniw - 8);
+ *ways = 3 << (eiw - 8);
break;
default:
return -EINVAL;
@@ -94,20 +99,21 @@ static inline int cxl_to_ways(u8 eniw, unsigned int *val)
return 0;
}
-static inline int granularity_to_cxl(int g, u16 *ig)
+static inline int granularity_to_eig(int granularity, u16 *eig)
{
- if (g > SZ_16K || g < 256 || !is_power_of_2(g))
+ if (granularity > SZ_16K || granularity < CXL_DECODER_MIN_GRANULARITY ||
+ !is_power_of_2(granularity))
return -EINVAL;
- *ig = ilog2(g) - 8;
+ *eig = ilog2(granularity) - 8;
return 0;
}
-static inline int ways_to_cxl(unsigned int ways, u8 *iw)
+static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
{
if (ways > 16)
return -EINVAL;
if (is_power_of_2(ways)) {
- *iw = ilog2(ways);
+ *eiw = ilog2(ways);
return 0;
}
if (ways % 3)
@@ -115,10 +121,26 @@ static inline int ways_to_cxl(unsigned int ways, u8 *iw)
ways /= 3;
if (!is_power_of_2(ways))
return -EINVAL;
- *iw = ilog2(ways) + 8;
+ *eiw = ilog2(ways) + 8;
return 0;
}
+/* RAS Registers CXL 2.0 8.2.5.9 CXL RAS Capability Structure */
+#define CXL_RAS_UNCORRECTABLE_STATUS_OFFSET 0x0
+#define CXL_RAS_UNCORRECTABLE_STATUS_MASK (GENMASK(16, 14) | GENMASK(11, 0))
+#define CXL_RAS_UNCORRECTABLE_MASK_OFFSET 0x4
+#define CXL_RAS_UNCORRECTABLE_MASK_MASK (GENMASK(16, 14) | GENMASK(11, 0))
+#define CXL_RAS_UNCORRECTABLE_SEVERITY_OFFSET 0x8
+#define CXL_RAS_UNCORRECTABLE_SEVERITY_MASK (GENMASK(16, 14) | GENMASK(11, 0))
+#define CXL_RAS_CORRECTABLE_STATUS_OFFSET 0xC
+#define CXL_RAS_CORRECTABLE_STATUS_MASK GENMASK(6, 0)
+#define CXL_RAS_CORRECTABLE_MASK_OFFSET 0x10
+#define CXL_RAS_CORRECTABLE_MASK_MASK GENMASK(6, 0)
+#define CXL_RAS_CAP_CONTROL_OFFSET 0x14
+#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
+#define CXL_RAS_HEADER_LOG_OFFSET 0x18
+#define CXL_RAS_CAPABILITY_LENGTH 0x58
+
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
#define CXLDEV_CAP_ARRAY_CAP_ID 0
@@ -153,9 +175,11 @@ struct cxl_regs {
/*
* Common set of CXL Component register block base pointers
* @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
+ * @ras: CXL 2.0 8.2.5.9 CXL RAS Capability Structure
*/
struct_group_tagged(cxl_component_regs, component,
void __iomem *hdm_decoder;
+ void __iomem *ras;
);
/*
* Common set of CXL Device register block base pointers
@@ -170,12 +194,14 @@ struct cxl_regs {
struct cxl_reg_map {
bool valid;
+ int id;
unsigned long offset;
unsigned long size;
};
struct cxl_component_reg_map {
struct cxl_reg_map hdm_decoder;
+ struct cxl_reg_map ras;
};
struct cxl_device_reg_map {
@@ -187,17 +213,17 @@ struct cxl_device_reg_map {
/**
* struct cxl_register_map - DVSEC harvested register block mapping parameters
* @base: virtual base of the register-block-BAR + @block_offset
- * @block_offset: offset to start of register block in @barno
+ * @resource: physical resource base of the register block
+ * @max_size: maximum mapping size to perform register search
* @reg_type: see enum cxl_regloc_type
- * @barno: PCI BAR number containing the register block
* @component_map: cxl_reg_map for component registers
* @device_map: cxl_reg_maps for device registers
*/
struct cxl_register_map {
void __iomem *base;
- u64 block_offset;
+ resource_size_t resource;
+ resource_size_t max_size;
u8 reg_type;
- u8 barno;
union {
struct cxl_component_reg_map component_map;
struct cxl_device_reg_map device_map;
@@ -208,18 +234,23 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_reg_map *map);
void cxl_probe_device_regs(struct device *dev, void __iomem *base,
struct cxl_device_reg_map *map);
-int cxl_map_component_regs(struct pci_dev *pdev,
- struct cxl_component_regs *regs,
- struct cxl_register_map *map);
-int cxl_map_device_regs(struct pci_dev *pdev,
- struct cxl_device_regs *regs,
+int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs,
+ struct cxl_register_map *map,
+ unsigned long map_mask);
+int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs,
struct cxl_register_map *map);
enum cxl_regloc_type;
int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
struct cxl_register_map *map);
-void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
- resource_size_t length);
+
+enum cxl_rcrb {
+ CXL_RCRB_DOWNSTREAM,
+ CXL_RCRB_UPSTREAM,
+};
+resource_size_t cxl_rcrb_to_component(struct device *dev,
+ resource_size_t rcrb,
+ enum cxl_rcrb which);
#define CXL_RESOURCE_NONE ((resource_size_t) -1)
#define CXL_TARGET_STRLEN 20
@@ -248,7 +279,6 @@ enum cxl_decoder_type {
*/
#define CXL_DECODER_MAX_INTERLEAVE 16
-#define CXL_DECODER_MIN_GRANULARITY 256
/**
* struct cxl_decoder - Common CXL HDM Decoder Attributes
@@ -324,18 +354,23 @@ struct cxl_switch_decoder {
struct cxl_dport *target[];
};
+struct cxl_root_decoder;
+typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
+ int pos);
/**
* struct cxl_root_decoder - Static platform CXL address decoder
* @res: host / parent resource for region allocations
* @region_id: region id for next region provisioning event
* @calc_hb: which host bridge covers the n'th position by granularity
+ * @platform_data: platform specific configuration data
* @cxlsd: base cxl switch decoder
*/
struct cxl_root_decoder {
struct resource *res;
atomic_t region_id;
- struct cxl_dport *(*calc_hb)(struct cxl_root_decoder *cxlrd, int pos);
+ cxl_calc_hb_fn calc_hb;
+ void *platform_data;
struct cxl_switch_decoder cxlsd;
};
@@ -379,12 +414,21 @@ struct cxl_region_params {
int nr_targets;
};
+/*
+ * Flag whether this region needs to have its HPA span synchronized with
+ * CPU cache state at region activation time.
+ */
+#define CXL_REGION_F_INCOHERENT 0
+
/**
* struct cxl_region - CXL region
* @dev: This region's device
* @id: This region's id. Id is globally unique across all regions
* @mode: Endpoint decoder allocation / access mode
* @type: Endpoint decoder target type
+ * @cxl_nvb: nvdimm bridge for coordinating @cxlr_pmem setup / shutdown
+ * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge
+ * @flags: Region state flags
* @params: active + config params for the region
*/
struct cxl_region {
@@ -392,38 +436,26 @@ struct cxl_region {
int id;
enum cxl_decoder_mode mode;
enum cxl_decoder_type type;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct cxl_pmem_region *cxlr_pmem;
+ unsigned long flags;
struct cxl_region_params params;
};
-/**
- * enum cxl_nvdimm_brige_state - state machine for managing bus rescans
- * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
- * @CXL_NVB_DEAD: Set at brige unregistration to preclude async probing
- * @CXL_NVB_ONLINE: Target state after successful ->probe()
- * @CXL_NVB_OFFLINE: Target state after ->remove() or failed ->probe()
- */
-enum cxl_nvdimm_brige_state {
- CXL_NVB_NEW,
- CXL_NVB_DEAD,
- CXL_NVB_ONLINE,
- CXL_NVB_OFFLINE,
-};
-
struct cxl_nvdimm_bridge {
int id;
struct device dev;
struct cxl_port *port;
struct nvdimm_bus *nvdimm_bus;
struct nvdimm_bus_descriptor nd_desc;
- struct work_struct state_work;
- enum cxl_nvdimm_brige_state state;
};
+#define CXL_DEV_ID_LEN 19
+
struct cxl_nvdimm {
struct device dev;
struct cxl_memdev *cxlmd;
- struct cxl_nvdimm_bridge *bridge;
- struct xarray pmem_regions;
+ u8 dev_id[CXL_DEV_ID_LEN]; /* for nvdimm, string of 'serial' */
};
struct cxl_pmem_region_mapping {
@@ -438,7 +470,6 @@ struct cxl_pmem_region {
struct device dev;
struct cxl_region *cxlr;
struct nd_region *nd_region;
- struct cxl_nvdimm_bridge *bridge;
struct range hpa_range;
int nr_mappings;
struct cxl_pmem_region_mapping mapping[];
@@ -500,12 +531,16 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
* @dport: PCI bridge or firmware device representing the downstream link
* @port_id: unique hardware identifier for dport in decoder target list
* @component_reg_phys: downstream port component registers
+ * @rcrb: base address for the Root Complex Register Block
+ * @rch: Indicate whether this dport was enumerated in RCH or VH mode
* @port: reference to cxl_port that contains this downstream port
*/
struct cxl_dport {
struct device *dport;
int port_id;
resource_size_t component_reg_phys;
+ resource_size_t rcrb;
+ bool rch;
struct cxl_port *port;
};
@@ -562,11 +597,10 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
resource_size_t component_reg_phys,
struct cxl_dport *parent_dport);
-int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
- struct cxl_dport *parent_dport);
struct cxl_port *find_cxl_root(struct device *dev);
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
-int cxl_bus_rescan(void);
+void cxl_bus_rescan(void);
+void cxl_bus_drain(void);
struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
struct cxl_dport **dport);
bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
@@ -574,6 +608,10 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
struct device *dport, int port_id,
resource_size_t component_reg_phys);
+struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
+ struct device *dport_dev, int port_id,
+ resource_size_t component_reg_phys,
+ resource_size_t rcrb);
struct cxl_decoder *to_cxl_decoder(struct device *dev);
struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
@@ -581,7 +619,9 @@ struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
bool is_endpoint_decoder(struct device *dev);
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets);
+ unsigned int nr_targets,
+ cxl_calc_hb_fn calc_hb);
+struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos);
struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets);
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
@@ -637,7 +677,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm_bridge(struct device *dev);
-int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
+int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
#ifdef CONFIG_CXL_REGION
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 88e3a8e54b6a..ab138004f644 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -35,6 +35,8 @@
* @cdev: char dev core object for ioctl operations
* @cxlds: The device state backing this device
* @detach_work: active memdev lost a port in its ancestry
+ * @cxl_nvb: coordinate removal of @cxl_nvd if present
+ * @cxl_nvd: optional bridge to an nvdimm if the device supports pmem
* @id: id number of this memdev instance.
*/
struct cxl_memdev {
@@ -42,6 +44,8 @@ struct cxl_memdev {
struct cdev cdev;
struct cxl_dev_state *cxlds;
struct work_struct detach_work;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct cxl_nvdimm *cxl_nvd;
int id;
};
@@ -76,6 +80,15 @@ static inline bool is_cxl_endpoint(struct cxl_port *port)
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
+static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
+ struct cxl_memdev *cxlmd)
+{
+ if (!port)
+ return NULL;
+
+ return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
+}
+
/**
* struct cxl_mbox_cmd - A command to be submitted to hardware.
* @opcode: (input) The command set and command submitted to hardware.
@@ -88,6 +101,7 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
* outputs commands this is always expected to be deterministic. For
* variable sized output commands, it tells the exact number of bytes
* written.
+ * @min_out: (input) internal command output payload size validation
* @return_code: (output) Error code returned from hardware.
*
* This is the primary mechanism used to send commands to the hardware.
@@ -102,6 +116,7 @@ struct cxl_mbox_cmd {
void *payload_out;
size_t size_in;
size_t size_out;
+ size_t min_out;
u16 return_code;
};
@@ -186,8 +201,10 @@ struct cxl_endpoint_dvsec_info {
* Currently only memory devices are represented.
*
* @dev: The device associated with this CXL state
+ * @cxlmd: The device representing the CXL.mem capabilities of @dev
* @regs: Parsed register blocks
* @cxl_dvsec: Offset to the PCIe device DVSEC
+ * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH)
* @payload_size: Size of space for payload
* (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
* @lsa_size: Size of Label Storage Area
@@ -218,10 +235,12 @@ struct cxl_endpoint_dvsec_info {
*/
struct cxl_dev_state {
struct device *dev;
+ struct cxl_memdev *cxlmd;
struct cxl_regs regs;
int cxl_dvsec;
+ bool rcd;
size_t payload_size;
size_t lsa_size;
struct mutex mbox_mutex; /* Protects device mailbox and firmware */
@@ -273,6 +292,12 @@ enum cxl_opcode {
CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303,
CXL_MBOX_OP_SCAN_MEDIA = 0x4304,
CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305,
+ CXL_MBOX_OP_GET_SECURITY_STATE = 0x4500,
+ CXL_MBOX_OP_SET_PASSPHRASE = 0x4501,
+ CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502,
+ CXL_MBOX_OP_UNLOCK = 0x4503,
+ CXL_MBOX_OP_FREEZE_SECURITY = 0x4504,
+ CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE = 0x4505,
CXL_MBOX_OP_MAX = 0x10000
};
@@ -372,8 +397,43 @@ struct cxl_mem_command {
#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0)
};
-int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in,
- size_t in_size, void *out, size_t out_size);
+#define CXL_PMEM_SEC_STATE_USER_PASS_SET 0x01
+#define CXL_PMEM_SEC_STATE_MASTER_PASS_SET 0x02
+#define CXL_PMEM_SEC_STATE_LOCKED 0x04
+#define CXL_PMEM_SEC_STATE_FROZEN 0x08
+#define CXL_PMEM_SEC_STATE_USER_PLIMIT 0x10
+#define CXL_PMEM_SEC_STATE_MASTER_PLIMIT 0x20
+
+/* set passphrase input payload */
+struct cxl_set_pass {
+ u8 type;
+ u8 reserved[31];
+ /* CXL field using NVDIMM define, same length */
+ u8 old_pass[NVDIMM_PASSPHRASE_LEN];
+ u8 new_pass[NVDIMM_PASSPHRASE_LEN];
+} __packed;
+
+/* disable passphrase input payload */
+struct cxl_disable_pass {
+ u8 type;
+ u8 reserved[31];
+ u8 pass[NVDIMM_PASSPHRASE_LEN];
+} __packed;
+
+/* passphrase secure erase payload */
+struct cxl_pass_erase {
+ u8 type;
+ u8 reserved[31];
+ u8 pass[NVDIMM_PASSPHRASE_LEN];
+} __packed;
+
+enum {
+ CXL_PMEM_SEC_PASS_MASTER = 0,
+ CXL_PMEM_SEC_PASS_USER,
+};
+
+int cxl_internal_send_cmd(struct cxl_dev_state *cxlds,
+ struct cxl_mbox_cmd *cmd);
int cxl_dev_state_identify(struct cxl_dev_state *cxlds);
int cxl_await_media_ready(struct cxl_dev_state *cxlds);
int cxl_enumerate_cmds(struct cxl_dev_state *cxlds);
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index eec597dbe763..920909791bb9 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -62,15 +62,6 @@ enum cxl_regloc_type {
CXL_REGLOC_RBI_TYPES
};
-static inline resource_size_t cxl_regmap_to_base(struct pci_dev *pdev,
- struct cxl_register_map *map)
-{
- if (map->block_offset == U64_MAX)
- return CXL_RESOURCE_NONE;
-
- return pci_resource_start(pdev, map->barno) + map->block_offset;
-}
-
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm);
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 64ccf053d32c..39c4b54f0715 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -45,9 +45,60 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
return 0;
}
+static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
+ struct cxl_dport *parent_dport)
+{
+ struct cxl_port *parent_port = parent_dport->port;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_port *endpoint, *iter, *down;
+ resource_size_t component_reg_phys;
+ int rc;
+
+ /*
+ * Now that the path to the root is established record all the
+ * intervening ports in the chain.
+ */
+ for (iter = parent_port, down = NULL; !is_cxl_root(iter);
+ down = iter, iter = to_cxl_port(iter->dev.parent)) {
+ struct cxl_ep *ep;
+
+ ep = cxl_ep_load(iter, cxlmd);
+ ep->next = down;
+ }
+
+ /*
+ * The component registers for an RCD might come from the
+ * host-bridge RCRB if they are not already mapped via the
+ * typical register locator mechanism.
+ */
+ if (parent_dport->rch && cxlds->component_reg_phys == CXL_RESOURCE_NONE)
+ component_reg_phys = cxl_rcrb_to_component(
+ &cxlmd->dev, parent_dport->rcrb, CXL_RCRB_UPSTREAM);
+ else
+ component_reg_phys = cxlds->component_reg_phys;
+ endpoint = devm_cxl_add_port(host, &cxlmd->dev, component_reg_phys,
+ parent_dport);
+ if (IS_ERR(endpoint))
+ return PTR_ERR(endpoint);
+
+ rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+ if (rc)
+ return rc;
+
+ if (!endpoint->dev.driver) {
+ dev_err(&cxlmd->dev, "%s failed probe\n",
+ dev_name(&endpoint->dev));
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
static int cxl_mem_probe(struct device *dev)
{
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *endpoint_parent;
struct cxl_port *parent_port;
struct cxl_dport *dport;
struct dentry *dentry;
@@ -80,21 +131,34 @@ static int cxl_mem_probe(struct device *dev)
return -ENXIO;
}
- device_lock(&parent_port->dev);
- if (!parent_port->dev.driver) {
+ if (dport->rch)
+ endpoint_parent = parent_port->uport;
+ else
+ endpoint_parent = &parent_port->dev;
+
+ device_lock(endpoint_parent);
+ if (!endpoint_parent->driver) {
dev_err(dev, "CXL port topology %s not enabled\n",
- dev_name(&parent_port->dev));
+ dev_name(endpoint_parent));
rc = -ENXIO;
goto unlock;
}
- rc = devm_cxl_add_endpoint(cxlmd, dport);
+ rc = devm_cxl_add_endpoint(endpoint_parent, cxlmd, dport);
unlock:
- device_unlock(&parent_port->dev);
+ device_unlock(endpoint_parent);
put_device(&parent_port->dev);
if (rc)
return rc;
+ if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
+ rc = devm_cxl_add_nvdimm(cxlmd);
+ if (rc == -ENODEV)
+ dev_info(dev, "PMEM disabled by platform\n");
+ else
+ return rc;
+ }
+
/*
* The kernel may be operating out of CXL memory on this device,
* there is no spec defined way to determine whether this device
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index faeb5d9d7a7a..33083a522fd1 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -9,10 +9,13 @@
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
+#include <linux/aer.h>
#include <linux/io.h>
#include "cxlmem.h"
#include "cxlpci.h"
#include "cxl.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/cxl.h>
/**
* DOC: cxl pci
@@ -276,35 +279,22 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
static int cxl_map_regblock(struct pci_dev *pdev, struct cxl_register_map *map)
{
- void __iomem *addr;
- int bar = map->barno;
struct device *dev = &pdev->dev;
- resource_size_t offset = map->block_offset;
-
- /* Basic sanity check that BAR is big enough */
- if (pci_resource_len(pdev, bar) < offset) {
- dev_err(dev, "BAR%d: %pr: too small (offset: %pa)\n", bar,
- &pdev->resource[bar], &offset);
- return -ENXIO;
- }
- addr = pci_iomap(pdev, bar, 0);
- if (!addr) {
+ map->base = ioremap(map->resource, map->max_size);
+ if (!map->base) {
dev_err(dev, "failed to map registers\n");
return -ENOMEM;
}
- dev_dbg(dev, "Mapped CXL Memory Device resource bar %u @ %pa\n",
- bar, &offset);
-
- map->base = addr + map->block_offset;
+ dev_dbg(dev, "Mapped CXL Memory Device resource %pa\n", &map->resource);
return 0;
}
static void cxl_unmap_regblock(struct pci_dev *pdev,
struct cxl_register_map *map)
{
- pci_iounmap(pdev, map->base - map->block_offset);
+ iounmap(map->base);
map->base = NULL;
}
@@ -324,6 +314,9 @@ static int cxl_probe_regs(struct pci_dev *pdev, struct cxl_register_map *map)
return -ENXIO;
}
+ if (!comp_map->ras.valid)
+ dev_dbg(dev, "RAS registers not found\n");
+
dev_dbg(dev, "Set up component registers\n");
break;
case CXL_REGLOC_RBI_MEMDEV:
@@ -347,27 +340,6 @@ static int cxl_probe_regs(struct pci_dev *pdev, struct cxl_register_map *map)
return 0;
}
-static int cxl_map_regs(struct cxl_dev_state *cxlds, struct cxl_register_map *map)
-{
- struct device *dev = cxlds->dev;
- struct pci_dev *pdev = to_pci_dev(dev);
-
- switch (map->reg_type) {
- case CXL_REGLOC_RBI_COMPONENT:
- cxl_map_component_regs(pdev, &cxlds->regs.component, map);
- dev_dbg(dev, "Mapping component registers...\n");
- break;
- case CXL_REGLOC_RBI_MEMDEV:
- cxl_map_device_regs(pdev, &cxlds->regs.device_regs, map);
- dev_dbg(dev, "Probing device registers...\n");
- break;
- default:
- break;
- }
-
- return 0;
-}
-
static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
struct cxl_register_map *map)
{
@@ -418,6 +390,11 @@ static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds)
continue;
}
+ if (!pci_request_config_region_exclusive(pdev, off,
+ PCI_DOE_CAP_SIZEOF,
+ dev_name(dev)))
+ pci_err(pdev, "Failed to exclude DOE registers\n");
+
if (xa_insert(&cxlds->doe_mbs, off, doe_mb, GFP_KERNEL)) {
dev_err(dev, "xa_insert failed to insert MB @ %x\n",
off);
@@ -428,6 +405,20 @@ static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds)
}
}
+/*
+ * Assume that any RCIEP that emits the CXL memory expander class code
+ * is an RCD
+ */
+static bool is_cxl_restricted(struct pci_dev *pdev)
+{
+ return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END;
+}
+
+static void disable_aer(void *pdev)
+{
+ pci_disable_pcie_error_reporting(pdev);
+}
+
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct cxl_register_map map;
@@ -449,7 +440,9 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
cxlds = cxl_dev_state_create(&pdev->dev);
if (IS_ERR(cxlds))
return PTR_ERR(cxlds);
+ pci_set_drvdata(pdev, cxlds);
+ cxlds->rcd = is_cxl_restricted(pdev);
cxlds->serial = pci_get_dsn(pdev);
cxlds->cxl_dvsec = pci_find_dvsec_capability(
pdev, PCI_DVSEC_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);
@@ -461,7 +454,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
- rc = cxl_map_regs(cxlds, &map);
+ rc = cxl_map_device_regs(&pdev->dev, &cxlds->regs.device_regs, &map);
if (rc)
return rc;
@@ -474,10 +467,15 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
dev_warn(&pdev->dev, "No component registers (%d)\n", rc);
- cxlds->component_reg_phys = cxl_regmap_to_base(pdev, &map);
+ cxlds->component_reg_phys = map.resource;
devm_cxl_pci_create_doe(cxlds);
+ rc = cxl_map_component_regs(&pdev->dev, &cxlds->regs.component,
+ &map, BIT(CXL_CM_CAP_CAP_ID_RAS));
+ if (rc)
+ dev_dbg(&pdev->dev, "Failed to map RAS capability.\n");
+
rc = cxl_pci_setup_mailbox(cxlds);
if (rc)
return rc;
@@ -498,8 +496,13 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
- if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
- rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
+ if (cxlds->regs.ras) {
+ pci_enable_pcie_error_reporting(pdev);
+ rc = devm_add_action_or_reset(&pdev->dev, disable_aer, pdev);
+ if (rc)
+ return rc;
+ }
+ pci_save_state(pdev);
return rc;
}
@@ -511,10 +514,151 @@ static const struct pci_device_id cxl_mem_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, cxl_mem_pci_tbl);
+/* CXL spec rev3.0 8.2.4.16.1 */
+static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log)
+{
+ void __iomem *addr;
+ u32 *log_addr;
+ int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
+
+ addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET;
+ log_addr = log;
+
+ for (i = 0; i < log_u32_size; i++) {
+ *log_addr = readl(addr);
+ log_addr++;
+ addr += sizeof(u32);
+ }
+}
+
+/*
+ * Log the state of the RAS status registers and prepare them to log the
+ * next error status. Return 1 if reset needed.
+ */
+static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)
+{
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+ u32 hl[CXL_HEADERLOG_SIZE_U32];
+ void __iomem *addr;
+ u32 status;
+ u32 fe;
+
+ if (!cxlds->regs.ras)
+ return false;
+
+ addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
+ return false;
+
+ /* If multiple errors, log header points to first error from ctrl reg */
+ if (hweight32(status) > 1) {
+ addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
+ fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr)));
+ } else {
+ fe = status;
+ }
+
+ header_log_copy(cxlds, hl);
+ trace_cxl_aer_uncorrectable_error(dev, status, fe, hl);
+ writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
+
+ return true;
+}
+
+static pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+ bool ue;
+
+ /*
+ * A frozen channel indicates an impending reset which is fatal to
+ * CXL.mem operation, and will likely crash the system. On the off
+ * chance the situation is recoverable dump the status of the RAS
+ * capability registers and bounce the active state of the memdev.
+ */
+ ue = cxl_report_and_clear(cxlds);
+
+ switch (state) {
+ case pci_channel_io_normal:
+ if (ue) {
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ dev_warn(&pdev->dev,
+ "%s: frozen state error detected, disable CXL.mem\n",
+ dev_name(dev));
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ dev_warn(&pdev->dev,
+ "failure state error detected, request disconnect\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t cxl_slot_reset(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+
+ dev_info(&pdev->dev, "%s: restart CXL.mem after slot reset\n",
+ dev_name(dev));
+ pci_restore_state(pdev);
+ if (device_attach(dev) <= 0)
+ return PCI_ERS_RESULT_DISCONNECT;
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void cxl_error_resume(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+
+ dev_info(&pdev->dev, "%s: error resume %s\n", dev_name(dev),
+ dev->driver ? "successful" : "failed");
+}
+
+static void cxl_cor_error_detected(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+ void __iomem *addr;
+ u32 status;
+
+ if (!cxlds->regs.ras)
+ return;
+
+ addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
+ writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
+ trace_cxl_aer_correctable_error(dev, status);
+ }
+}
+
+static const struct pci_error_handlers cxl_error_handlers = {
+ .error_detected = cxl_error_detected,
+ .slot_reset = cxl_slot_reset,
+ .resume = cxl_error_resume,
+ .cor_error_detected = cxl_cor_error_detected,
+};
+
static struct pci_driver cxl_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = cxl_mem_pci_tbl,
.probe = cxl_pci_probe,
+ .err_handler = &cxl_error_handlers,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index 4c627d67281a..eedefebc4283 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -11,12 +11,7 @@
#include "cxlmem.h"
#include "cxl.h"
-/*
- * Ordered workqueue for cxl nvdimm device arrival and departure
- * to coordinate bus rescans when a bridge arrives and trigger remove
- * operations when the bridge is removed.
- */
-static struct workqueue_struct *cxl_pmem_wq;
+extern const struct nvdimm_security_ops *cxl_security_ops;
static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
@@ -27,78 +22,81 @@ static void clear_exclusive(void *cxlds)
static void unregister_nvdimm(void *nvdimm)
{
- struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
- struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge;
- struct cxl_pmem_region *cxlr_pmem;
- unsigned long index;
+ nvdimm_delete(nvdimm);
+}
- device_lock(&cxl_nvb->dev);
- dev_set_drvdata(&cxl_nvd->dev, NULL);
- xa_for_each(&cxl_nvd->pmem_regions, index, cxlr_pmem) {
- get_device(&cxlr_pmem->dev);
- device_unlock(&cxl_nvb->dev);
+static ssize_t provider_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
- device_release_driver(&cxlr_pmem->dev);
- put_device(&cxlr_pmem->dev);
+ return sysfs_emit(buf, "%s\n", dev_name(&cxl_nvd->dev));
+}
+static DEVICE_ATTR_RO(provider);
- device_lock(&cxl_nvb->dev);
- }
- device_unlock(&cxl_nvb->dev);
+static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_dev_state *cxlds = cxl_nvd->cxlmd->cxlds;
- nvdimm_delete(nvdimm);
- cxl_nvd->bridge = NULL;
+ return sysfs_emit(buf, "%lld\n", cxlds->serial);
}
+static DEVICE_ATTR_RO(id);
+
+static struct attribute *cxl_dimm_attributes[] = {
+ &dev_attr_id.attr,
+ &dev_attr_provider.attr,
+ NULL
+};
+
+static const struct attribute_group cxl_dimm_attribute_group = {
+ .name = "cxl",
+ .attrs = cxl_dimm_attributes,
+};
+
+static const struct attribute_group *cxl_dimm_attribute_groups[] = {
+ &cxl_dimm_attribute_group,
+ NULL
+};
static int cxl_nvdimm_probe(struct device *dev)
{
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;
unsigned long flags = 0, cmd_mask = 0;
struct cxl_dev_state *cxlds = cxlmd->cxlds;
- struct cxl_nvdimm_bridge *cxl_nvb;
struct nvdimm *nvdimm;
int rc;
- cxl_nvb = cxl_find_nvdimm_bridge(dev);
- if (!cxl_nvb)
- return -ENXIO;
-
- device_lock(&cxl_nvb->dev);
- if (!cxl_nvb->nvdimm_bus) {
- rc = -ENXIO;
- goto out;
- }
-
set_exclusive_cxl_commands(cxlds, exclusive_cmds);
rc = devm_add_action_or_reset(dev, clear_exclusive, cxlds);
if (rc)
- goto out;
+ return rc;
set_bit(NDD_LABELING, &flags);
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask);
- nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags,
- cmd_mask, 0, NULL);
- if (!nvdimm) {
- rc = -ENOMEM;
- goto out;
- }
+ nvdimm = __nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd,
+ cxl_dimm_attribute_groups, flags,
+ cmd_mask, 0, NULL, cxl_nvd->dev_id,
+ cxl_security_ops, NULL);
+ if (!nvdimm)
+ return -ENOMEM;
dev_set_drvdata(dev, nvdimm);
- cxl_nvd->bridge = cxl_nvb;
- rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
-out:
- device_unlock(&cxl_nvb->dev);
- put_device(&cxl_nvb->dev);
-
- return rc;
+ return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
}
static struct cxl_driver cxl_nvdimm_driver = {
.name = "cxl_nvdimm",
.probe = cxl_nvdimm_probe,
.id = CXL_DEVICE_NVDIMM,
+ .drv = {
+ .suppress_bind_attrs = true,
+ },
};
static int cxl_pmem_get_config_size(struct cxl_dev_state *cxlds,
@@ -121,6 +119,7 @@ static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
unsigned int buf_len)
{
struct cxl_mbox_get_lsa get_lsa;
+ struct cxl_mbox_cmd mbox_cmd;
int rc;
if (sizeof(*cmd) > buf_len)
@@ -132,9 +131,15 @@ static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
.offset = cpu_to_le32(cmd->in_offset),
.length = cpu_to_le32(cmd->in_length),
};
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_LSA,
+ .payload_in = &get_lsa,
+ .size_in = sizeof(get_lsa),
+ .size_out = cmd->in_length,
+ .payload_out = cmd->out_buf,
+ };
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa,
- sizeof(get_lsa), cmd->out_buf, cmd->in_length);
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
cmd->status = 0;
return rc;
@@ -145,6 +150,7 @@ static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
unsigned int buf_len)
{
struct cxl_mbox_set_lsa *set_lsa;
+ struct cxl_mbox_cmd mbox_cmd;
int rc;
if (sizeof(*cmd) > buf_len)
@@ -163,10 +169,13 @@ static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
.offset = cpu_to_le32(cmd->in_offset),
};
memcpy(set_lsa->data, cmd->in_buf, cmd->in_length);
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_SET_LSA,
+ .payload_in = set_lsa,
+ .size_in = struct_size(set_lsa, data, cmd->in_length),
+ };
- rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_SET_LSA, set_lsa,
- struct_size(set_lsa, data, cmd->in_length),
- NULL, 0);
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
/*
* Set "firmware" status (4-packed bytes at the end of the input
@@ -216,204 +225,48 @@ static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc,
return cxl_pmem_nvdimm_ctl(nvdimm, cmd, buf, buf_len);
}
-static bool online_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb)
-{
- if (cxl_nvb->nvdimm_bus)
- return true;
- cxl_nvb->nvdimm_bus =
- nvdimm_bus_register(&cxl_nvb->dev, &cxl_nvb->nd_desc);
- return cxl_nvb->nvdimm_bus != NULL;
-}
-
-static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb)
-{
- struct cxl_nvdimm *cxl_nvd;
-
- if (!is_cxl_nvdimm(dev))
- return 0;
-
- cxl_nvd = to_cxl_nvdimm(dev);
- if (cxl_nvd->bridge != cxl_nvb)
- return 0;
-
- device_release_driver(dev);
- return 0;
-}
-
-static int cxl_pmem_region_release_driver(struct device *dev, void *cxl_nvb)
-{
- struct cxl_pmem_region *cxlr_pmem;
-
- if (!is_cxl_pmem_region(dev))
- return 0;
-
- cxlr_pmem = to_cxl_pmem_region(dev);
- if (cxlr_pmem->bridge != cxl_nvb)
- return 0;
-
- device_release_driver(dev);
- return 0;
-}
-
-static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
- struct nvdimm_bus *nvdimm_bus)
+static void unregister_nvdimm_bus(void *_cxl_nvb)
{
- if (!nvdimm_bus)
- return;
+ struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb;
+ struct nvdimm_bus *nvdimm_bus = cxl_nvb->nvdimm_bus;
- /*
- * Set the state of cxl_nvdimm devices to unbound / idle before
- * nvdimm_bus_unregister() rips the nvdimm objects out from
- * underneath them.
- */
- bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
- cxl_pmem_region_release_driver);
- bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
- cxl_nvdimm_release_driver);
+ cxl_nvb->nvdimm_bus = NULL;
nvdimm_bus_unregister(nvdimm_bus);
}
-static void cxl_nvb_update_state(struct work_struct *work)
-{
- struct cxl_nvdimm_bridge *cxl_nvb =
- container_of(work, typeof(*cxl_nvb), state_work);
- struct nvdimm_bus *victim_bus = NULL;
- bool release = false, rescan = false;
-
- device_lock(&cxl_nvb->dev);
- switch (cxl_nvb->state) {
- case CXL_NVB_ONLINE:
- if (!online_nvdimm_bus(cxl_nvb)) {
- dev_err(&cxl_nvb->dev,
- "failed to establish nvdimm bus\n");
- release = true;
- } else
- rescan = true;
- break;
- case CXL_NVB_OFFLINE:
- case CXL_NVB_DEAD:
- victim_bus = cxl_nvb->nvdimm_bus;
- cxl_nvb->nvdimm_bus = NULL;
- break;
- default:
- break;
- }
- device_unlock(&cxl_nvb->dev);
-
- if (release)
- device_release_driver(&cxl_nvb->dev);
- if (rescan) {
- int rc = bus_rescan_devices(&cxl_bus_type);
-
- dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc);
- }
- offline_nvdimm_bus(cxl_nvb, victim_bus);
-
- put_device(&cxl_nvb->dev);
-}
-
-static void cxl_nvdimm_bridge_state_work(struct cxl_nvdimm_bridge *cxl_nvb)
-{
- /*
- * Take a reference that the workqueue will drop if new work
- * gets queued.
- */
- get_device(&cxl_nvb->dev);
- if (!queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
- put_device(&cxl_nvb->dev);
-}
-
-static void cxl_nvdimm_bridge_remove(struct device *dev)
-{
- struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
-
- if (cxl_nvb->state == CXL_NVB_ONLINE)
- cxl_nvb->state = CXL_NVB_OFFLINE;
- cxl_nvdimm_bridge_state_work(cxl_nvb);
-}
-
static int cxl_nvdimm_bridge_probe(struct device *dev)
{
struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
- if (cxl_nvb->state == CXL_NVB_DEAD)
- return -ENXIO;
-
- if (cxl_nvb->state == CXL_NVB_NEW) {
- cxl_nvb->nd_desc = (struct nvdimm_bus_descriptor) {
- .provider_name = "CXL",
- .module = THIS_MODULE,
- .ndctl = cxl_pmem_ctl,
- };
+ cxl_nvb->nd_desc = (struct nvdimm_bus_descriptor) {
+ .provider_name = "CXL",
+ .module = THIS_MODULE,
+ .ndctl = cxl_pmem_ctl,
+ };
- INIT_WORK(&cxl_nvb->state_work, cxl_nvb_update_state);
- }
+ cxl_nvb->nvdimm_bus =
+ nvdimm_bus_register(&cxl_nvb->dev, &cxl_nvb->nd_desc);
- cxl_nvb->state = CXL_NVB_ONLINE;
- cxl_nvdimm_bridge_state_work(cxl_nvb);
+ if (!cxl_nvb->nvdimm_bus)
+ return -ENOMEM;
- return 0;
+ return devm_add_action_or_reset(dev, unregister_nvdimm_bus, cxl_nvb);
}
static struct cxl_driver cxl_nvdimm_bridge_driver = {
.name = "cxl_nvdimm_bridge",
.probe = cxl_nvdimm_bridge_probe,
- .remove = cxl_nvdimm_bridge_remove,
.id = CXL_DEVICE_NVDIMM_BRIDGE,
+ .drv = {
+ .suppress_bind_attrs = true,
+ },
};
-static int match_cxl_nvdimm(struct device *dev, void *data)
-{
- return is_cxl_nvdimm(dev);
-}
-
static void unregister_nvdimm_region(void *nd_region)
{
nvdimm_region_delete(nd_region);
}
-static int cxl_nvdimm_add_region(struct cxl_nvdimm *cxl_nvd,
- struct cxl_pmem_region *cxlr_pmem)
-{
- int rc;
-
- rc = xa_insert(&cxl_nvd->pmem_regions, (unsigned long)cxlr_pmem,
- cxlr_pmem, GFP_KERNEL);
- if (rc)
- return rc;
-
- get_device(&cxlr_pmem->dev);
- return 0;
-}
-
-static void cxl_nvdimm_del_region(struct cxl_nvdimm *cxl_nvd,
- struct cxl_pmem_region *cxlr_pmem)
-{
- /*
- * It is possible this is called without a corresponding
- * cxl_nvdimm_add_region for @cxlr_pmem
- */
- cxlr_pmem = xa_erase(&cxl_nvd->pmem_regions, (unsigned long)cxlr_pmem);
- if (cxlr_pmem)
- put_device(&cxlr_pmem->dev);
-}
-
-static void release_mappings(void *data)
-{
- int i;
- struct cxl_pmem_region *cxlr_pmem = data;
- struct cxl_nvdimm_bridge *cxl_nvb = cxlr_pmem->bridge;
-
- device_lock(&cxl_nvb->dev);
- for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
- struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
- struct cxl_nvdimm *cxl_nvd = m->cxl_nvd;
-
- cxl_nvdimm_del_region(cxl_nvd, cxlr_pmem);
- }
- device_unlock(&cxl_nvb->dev);
-}
-
static void cxlr_pmem_remove_resource(void *res)
{
remove_resource(res);
@@ -429,8 +282,8 @@ static int cxl_pmem_region_probe(struct device *dev)
struct nd_mapping_desc mappings[CXL_DECODER_MAX_INTERLEAVE];
struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
struct cxl_pmem_region_info *info = NULL;
- struct cxl_nvdimm_bridge *cxl_nvb;
struct nd_interleave_set *nd_set;
struct nd_region_desc ndr_desc;
struct cxl_nvdimm *cxl_nvd;
@@ -438,28 +291,12 @@ static int cxl_pmem_region_probe(struct device *dev)
struct resource *res;
int rc, i = 0;
- cxl_nvb = cxl_find_nvdimm_bridge(&cxlr_pmem->mapping[0].cxlmd->dev);
- if (!cxl_nvb) {
- dev_dbg(dev, "bridge not found\n");
- return -ENXIO;
- }
- cxlr_pmem->bridge = cxl_nvb;
-
- device_lock(&cxl_nvb->dev);
- if (!cxl_nvb->nvdimm_bus) {
- dev_dbg(dev, "nvdimm bus not found\n");
- rc = -ENXIO;
- goto out_nvb;
- }
-
memset(&mappings, 0, sizeof(mappings));
memset(&ndr_desc, 0, sizeof(ndr_desc));
res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
- if (!res) {
- rc = -ENOMEM;
- goto out_nvb;
- }
+ if (!res)
+ return -ENOMEM;
res->name = "Persistent Memory";
res->start = cxlr_pmem->hpa_range.start;
@@ -469,11 +306,11 @@ static int cxl_pmem_region_probe(struct device *dev)
rc = insert_resource(&iomem_resource, res);
if (rc)
- goto out_nvb;
+ return rc;
rc = devm_add_action_or_reset(dev, cxlr_pmem_remove_resource, res);
if (rc)
- goto out_nvb;
+ return rc;
ndr_desc.res = res;
ndr_desc.provider_data = cxlr_pmem;
@@ -487,43 +324,23 @@ static int cxl_pmem_region_probe(struct device *dev)
}
nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
- if (!nd_set) {
- rc = -ENOMEM;
- goto out_nvb;
- }
+ if (!nd_set)
+ return -ENOMEM;
ndr_desc.memregion = cxlr->id;
set_bit(ND_REGION_CXL, &ndr_desc.flags);
set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
info = kmalloc_array(cxlr_pmem->nr_mappings, sizeof(*info), GFP_KERNEL);
- if (!info) {
- rc = -ENOMEM;
- goto out_nvb;
- }
-
- rc = devm_add_action_or_reset(dev, release_mappings, cxlr_pmem);
- if (rc)
- goto out_nvd;
+ if (!info)
+ return -ENOMEM;
for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
struct cxl_memdev *cxlmd = m->cxlmd;
struct cxl_dev_state *cxlds = cxlmd->cxlds;
- struct device *d;
-
- d = device_find_child(&cxlmd->dev, NULL, match_cxl_nvdimm);
- if (!d) {
- dev_dbg(dev, "[%d]: %s: no cxl_nvdimm found\n", i,
- dev_name(&cxlmd->dev));
- rc = -ENODEV;
- goto out_nvd;
- }
- /* safe to drop ref now with bridge lock held */
- put_device(d);
-
- cxl_nvd = to_cxl_nvdimm(d);
+ cxl_nvd = cxlmd->cxl_nvd;
nvdimm = dev_get_drvdata(&cxl_nvd->dev);
if (!nvdimm) {
dev_dbg(dev, "[%d]: %s: no nvdimm found\n", i,
@@ -532,14 +349,6 @@ static int cxl_pmem_region_probe(struct device *dev)
goto out_nvd;
}
- /*
- * Pin the region per nvdimm device as those may be released
- * out-of-order with respect to the region, and a single nvdimm
- * maybe associated with multiple regions
- */
- rc = cxl_nvdimm_add_region(cxl_nvd, cxlr_pmem);
- if (rc)
- goto out_nvd;
m->cxl_nvd = cxl_nvd;
mappings[i] = (struct nd_mapping_desc) {
.nvdimm = nvdimm,
@@ -572,9 +381,6 @@ static int cxl_pmem_region_probe(struct device *dev)
cxlr_pmem->nd_region);
out_nvd:
kfree(info);
-out_nvb:
- device_unlock(&cxl_nvb->dev);
- put_device(&cxl_nvb->dev);
return rc;
}
@@ -583,33 +389,11 @@ static struct cxl_driver cxl_pmem_region_driver = {
.name = "cxl_pmem_region",
.probe = cxl_pmem_region_probe,
.id = CXL_DEVICE_PMEM_REGION,
+ .drv = {
+ .suppress_bind_attrs = true,
+ },
};
-/*
- * Return all bridges to the CXL_NVB_NEW state to invalidate any
- * ->state_work referring to the now destroyed cxl_pmem_wq.
- */
-static int cxl_nvdimm_bridge_reset(struct device *dev, void *data)
-{
- struct cxl_nvdimm_bridge *cxl_nvb;
-
- if (!is_cxl_nvdimm_bridge(dev))
- return 0;
-
- cxl_nvb = to_cxl_nvdimm_bridge(dev);
- device_lock(dev);
- cxl_nvb->state = CXL_NVB_NEW;
- device_unlock(dev);
-
- return 0;
-}
-
-static void destroy_cxl_pmem_wq(void)
-{
- destroy_workqueue(cxl_pmem_wq);
- bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_bridge_reset);
-}
-
static __init int cxl_pmem_init(void)
{
int rc;
@@ -617,13 +401,9 @@ static __init int cxl_pmem_init(void)
set_bit(CXL_MEM_COMMAND_ID_SET_SHUTDOWN_STATE, exclusive_cmds);
set_bit(CXL_MEM_COMMAND_ID_SET_LSA, exclusive_cmds);
- cxl_pmem_wq = alloc_ordered_workqueue("cxl_pmem", 0);
- if (!cxl_pmem_wq)
- return -ENXIO;
-
rc = cxl_driver_register(&cxl_nvdimm_bridge_driver);
if (rc)
- goto err_bridge;
+ return rc;
rc = cxl_driver_register(&cxl_nvdimm_driver);
if (rc)
@@ -639,8 +419,6 @@ err_region:
cxl_driver_unregister(&cxl_nvdimm_driver);
err_nvdimm:
cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
-err_bridge:
- destroy_cxl_pmem_wq();
return rc;
}
@@ -649,7 +427,6 @@ static __exit void cxl_pmem_exit(void)
cxl_driver_unregister(&cxl_pmem_region_driver);
cxl_driver_unregister(&cxl_nvdimm_driver);
cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
- destroy_cxl_pmem_wq();
}
MODULE_LICENSE("GPL v2");
diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c
new file mode 100644
index 000000000000..4ad4bda2d18e
--- /dev/null
+++ b/drivers/cxl/security.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#include <linux/libnvdimm.h>
+#include <asm/unaligned.h>
+#include <linux/module.h>
+#include <linux/async.h>
+#include <linux/slab.h>
+#include <linux/memregion.h>
+#include "cxlmem.h"
+#include "cxl.h"
+
+static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
+ enum nvdimm_passphrase_type ptype)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ unsigned long security_flags = 0;
+ struct cxl_get_security_output {
+ __le32 flags;
+ } out;
+ struct cxl_mbox_cmd mbox_cmd;
+ u32 sec_out;
+ int rc;
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
+ .size_out = sizeof(out),
+ .payload_out = &out,
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc < 0)
+ return 0;
+
+ sec_out = le32_to_cpu(out.flags);
+ if (ptype == NVDIMM_MASTER) {
+ if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
+ set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
+ else
+ set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
+ if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PLIMIT)
+ set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
+ return security_flags;
+ }
+
+ if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
+ if (sec_out & CXL_PMEM_SEC_STATE_FROZEN ||
+ sec_out & CXL_PMEM_SEC_STATE_USER_PLIMIT)
+ set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
+
+ if (sec_out & CXL_PMEM_SEC_STATE_LOCKED)
+ set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
+ else
+ set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
+ } else {
+ set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
+ }
+
+ return security_flags;
+}
+
+static int cxl_pmem_security_change_key(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *old_data,
+ const struct nvdimm_key_data *new_data,
+ enum nvdimm_passphrase_type ptype)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_mbox_cmd mbox_cmd;
+ struct cxl_set_pass set_pass;
+
+ set_pass = (struct cxl_set_pass) {
+ .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
+ CXL_PMEM_SEC_PASS_USER,
+ };
+ memcpy(set_pass.old_pass, old_data->data, NVDIMM_PASSPHRASE_LEN);
+ memcpy(set_pass.new_pass, new_data->data, NVDIMM_PASSPHRASE_LEN);
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_SET_PASSPHRASE,
+ .size_in = sizeof(set_pass),
+ .payload_in = &set_pass,
+ };
+
+ return cxl_internal_send_cmd(cxlds, &mbox_cmd);
+}
+
+static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key_data,
+ enum nvdimm_passphrase_type ptype)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_disable_pass dis_pass;
+ struct cxl_mbox_cmd mbox_cmd;
+
+ dis_pass = (struct cxl_disable_pass) {
+ .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
+ CXL_PMEM_SEC_PASS_USER,
+ };
+ memcpy(dis_pass.pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_DISABLE_PASSPHRASE,
+ .size_in = sizeof(dis_pass),
+ .payload_in = &dis_pass,
+ };
+
+ return cxl_internal_send_cmd(cxlds, &mbox_cmd);
+}
+
+static int cxl_pmem_security_disable(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key_data)
+{
+ return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_USER);
+}
+
+static int cxl_pmem_security_disable_master(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key_data)
+{
+ return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_MASTER);
+}
+
+static int cxl_pmem_security_freeze(struct nvdimm *nvdimm)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_mbox_cmd mbox_cmd = {
+ .opcode = CXL_MBOX_OP_FREEZE_SECURITY,
+ };
+
+ return cxl_internal_send_cmd(cxlds, &mbox_cmd);
+}
+
+static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key_data)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ u8 pass[NVDIMM_PASSPHRASE_LEN];
+ struct cxl_mbox_cmd mbox_cmd;
+ int rc;
+
+ memcpy(pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_UNLOCK,
+ .size_in = NVDIMM_PASSPHRASE_LEN,
+ .payload_in = pass,
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key,
+ enum nvdimm_passphrase_type ptype)
+{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_mbox_cmd mbox_cmd;
+ struct cxl_pass_erase erase;
+ int rc;
+
+ erase = (struct cxl_pass_erase) {
+ .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
+ CXL_PMEM_SEC_PASS_USER,
+ };
+ memcpy(erase.pass, key->data, NVDIMM_PASSPHRASE_LEN);
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE,
+ .size_in = sizeof(erase),
+ .payload_in = &erase,
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static const struct nvdimm_security_ops __cxl_security_ops = {
+ .get_flags = cxl_pmem_get_security_flags,
+ .change_key = cxl_pmem_security_change_key,
+ .disable = cxl_pmem_security_disable,
+ .freeze = cxl_pmem_security_freeze,
+ .unlock = cxl_pmem_security_unlock,
+ .erase = cxl_pmem_security_passphrase_erase,
+ .disable_master = cxl_pmem_security_disable_master,
+};
+
+const struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops;
diff --git a/drivers/dax/hmem/device.c b/drivers/dax/hmem/device.c
index 97086fab698e..903325aac991 100644
--- a/drivers/dax/hmem/device.c
+++ b/drivers/dax/hmem/device.c
@@ -8,6 +8,13 @@
static bool nohmem;
module_param_named(disable, nohmem, bool, 0444);
+static struct resource hmem_active = {
+ .name = "HMEM devices",
+ .start = 0,
+ .end = -1,
+ .flags = IORESOURCE_MEM,
+};
+
void hmem_register_device(int target_nid, struct resource *r)
{
/* define a clean / non-busy resource for the platform device */
@@ -41,6 +48,12 @@ void hmem_register_device(int target_nid, struct resource *r)
goto out_pdev;
}
+ if (!__request_region(&hmem_active, res.start, resource_size(&res),
+ dev_name(&pdev->dev), 0)) {
+ dev_dbg(&pdev->dev, "hmem range %pr already active\n", &res);
+ goto out_active;
+ }
+
pdev->dev.numa_node = numa_map_to_online_node(target_nid);
info = (struct memregion_info) {
.target_node = target_nid,
@@ -66,6 +79,8 @@ void hmem_register_device(int target_nid, struct resource *r)
return;
out_resource:
+ __release_region(&hmem_active, res.start, resource_size(&res));
+out_active:
platform_device_put(pdev);
out_pdev:
memregion_free(id);
@@ -73,15 +88,6 @@ out_pdev:
static __init int hmem_register_one(struct resource *res, void *data)
{
- /*
- * If the resource is not a top-level resource it was already
- * assigned to a device by the HMAT parsing.
- */
- if (res->parent != &iomem_resource) {
- pr_info("HMEM: skip %pr, already claimed\n", res);
- return 0;
- }
-
hmem_register_device(phys_to_target_node(res->start), res);
return 0;
diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
index 6765c03334bc..f041edccd107 100644
--- a/drivers/devfreq/devfreq-event.c
+++ b/drivers/devfreq/devfreq-event.c
@@ -233,7 +233,7 @@ struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
mutex_lock(&devfreq_event_list_lock);
list_for_each_entry(edev, &devfreq_event_list, node) {
- if (edev->dev.parent && edev->dev.parent->of_node == node)
+ if (edev->dev.parent && device_match_of_node(edev->dev.parent, node))
goto out;
}
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 63347a5ae599..817c71da391a 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -776,8 +776,7 @@ static void remove_sysfs_files(struct devfreq *devfreq,
* @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq.
* @governor_name: name of the policy to choose frequency.
- * @data: private data for the governor. The devfreq framework does not
- * touch this value.
+ * @data: devfreq driver pass to governors, governor should not change it.
*/
struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
@@ -1011,8 +1010,7 @@ static void devm_devfreq_dev_release(struct device *dev, void *res)
* @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq.
* @governor_name: name of the policy to choose frequency.
- * @data: private data for the governor. The devfreq framework does not
- * touch this value.
+ * @data: devfreq driver pass to governors, governor should not change it.
*
* This function manages automatically the memory of devfreq device using device
* resource management and simplify the free operation for memory of devfreq
@@ -1059,7 +1057,7 @@ struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
mutex_lock(&devfreq_list_lock);
list_for_each_entry(devfreq, &devfreq_list, node) {
if (devfreq->dev.parent
- && devfreq->dev.parent->of_node == node) {
+ && device_match_of_node(devfreq->dev.parent, node)) {
mutex_unlock(&devfreq_list_lock);
return devfreq;
}
diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c
index ccc531ee6938..c1cc23bcb995 100644
--- a/drivers/devfreq/event/exynos-nocp.c
+++ b/drivers/devfreq/event/exynos-nocp.c
@@ -214,8 +214,7 @@ static int exynos_nocp_parse_dt(struct platform_device *pdev,
nocp->clk = NULL;
/* Maps the memory mapped IO to control nocp register */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index ab9db7adb3ad..d69672ccacc4 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -21,7 +21,7 @@ struct userspace_data {
static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
{
- struct userspace_data *data = df->data;
+ struct userspace_data *data = df->governor_data;
if (data->valid)
*freq = data->user_frequency;
@@ -40,7 +40,7 @@ static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr,
int err = 0;
mutex_lock(&devfreq->lock);
- data = devfreq->data;
+ data = devfreq->governor_data;
sscanf(buf, "%lu", &wanted);
data->user_frequency = wanted;
@@ -60,7 +60,7 @@ static ssize_t set_freq_show(struct device *dev,
int err = 0;
mutex_lock(&devfreq->lock);
- data = devfreq->data;
+ data = devfreq->governor_data;
if (data->valid)
err = sprintf(buf, "%lu\n", data->user_frequency);
@@ -91,7 +91,7 @@ static int userspace_init(struct devfreq *devfreq)
goto out;
}
data->valid = false;
- devfreq->data = data;
+ devfreq->governor_data = data;
err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
out:
@@ -107,8 +107,8 @@ static void userspace_exit(struct devfreq *devfreq)
if (devfreq->dev.kobj.sd)
sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
- kfree(devfreq->data);
- devfreq->data = NULL;
+ kfree(devfreq->governor_data);
+ devfreq->governor_data = NULL;
}
static int devfreq_userspace_handler(struct devfreq *devfreq,
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index dd0f83ee505b..b6c36914e7c6 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
+#include <linux/dma-fence-unwrap.h>
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
@@ -129,6 +130,7 @@ static struct file_system_type dma_buf_fs_type = {
static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
{
struct dma_buf *dmabuf;
+ int ret;
if (!is_dma_buf_file(file))
return -EINVAL;
@@ -144,7 +146,11 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
dmabuf->size >> PAGE_SHIFT)
return -EINVAL;
- return dmabuf->ops->mmap(dmabuf, vma);
+ dma_resv_lock(dmabuf->resv, NULL);
+ ret = dmabuf->ops->mmap(dmabuf, vma);
+ dma_resv_unlock(dmabuf->resv);
+
+ return ret;
}
static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
@@ -391,8 +397,10 @@ static long dma_buf_import_sync_file(struct dma_buf *dmabuf,
const void __user *user_data)
{
struct dma_buf_import_sync_file arg;
- struct dma_fence *fence;
+ struct dma_fence *fence, *f;
enum dma_resv_usage usage;
+ struct dma_fence_unwrap iter;
+ unsigned int num_fences;
int ret = 0;
if (copy_from_user(&arg, user_data, sizeof(arg)))
@@ -411,13 +419,21 @@ static long dma_buf_import_sync_file(struct dma_buf *dmabuf,
usage = (arg.flags & DMA_BUF_SYNC_WRITE) ? DMA_RESV_USAGE_WRITE :
DMA_RESV_USAGE_READ;
- dma_resv_lock(dmabuf->resv, NULL);
+ num_fences = 0;
+ dma_fence_unwrap_for_each(f, &iter, fence)
+ ++num_fences;
- ret = dma_resv_reserve_fences(dmabuf->resv, 1);
- if (!ret)
- dma_resv_add_fence(dmabuf->resv, fence, usage);
+ if (num_fences > 0) {
+ dma_resv_lock(dmabuf->resv, NULL);
- dma_resv_unlock(dmabuf->resv);
+ ret = dma_resv_reserve_fences(dmabuf->resv, num_fences);
+ if (!ret) {
+ dma_fence_unwrap_for_each(f, &iter, fence)
+ dma_resv_add_fence(dmabuf->resv, f, usage);
+ }
+
+ dma_resv_unlock(dmabuf->resv);
+ }
dma_fence_put(fence);
@@ -657,7 +673,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
dmabuf->file = file;
- mutex_init(&dmabuf->lock);
INIT_LIST_HEAD(&dmabuf->attachments);
mutex_lock(&db_list.lock);
@@ -796,6 +811,70 @@ static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach,
}
/**
+ * DOC: locking convention
+ *
+ * In order to avoid deadlock situations between dma-buf exports and importers,
+ * all dma-buf API users must follow the common dma-buf locking convention.
+ *
+ * Convention for importers
+ *
+ * 1. Importers must hold the dma-buf reservation lock when calling these
+ * functions:
+ *
+ * - dma_buf_pin()
+ * - dma_buf_unpin()
+ * - dma_buf_map_attachment()
+ * - dma_buf_unmap_attachment()
+ * - dma_buf_vmap()
+ * - dma_buf_vunmap()
+ *
+ * 2. Importers must not hold the dma-buf reservation lock when calling these
+ * functions:
+ *
+ * - dma_buf_attach()
+ * - dma_buf_dynamic_attach()
+ * - dma_buf_detach()
+ * - dma_buf_export(
+ * - dma_buf_fd()
+ * - dma_buf_get()
+ * - dma_buf_put()
+ * - dma_buf_mmap()
+ * - dma_buf_begin_cpu_access()
+ * - dma_buf_end_cpu_access()
+ * - dma_buf_map_attachment_unlocked()
+ * - dma_buf_unmap_attachment_unlocked()
+ * - dma_buf_vmap_unlocked()
+ * - dma_buf_vunmap_unlocked()
+ *
+ * Convention for exporters
+ *
+ * 1. These &dma_buf_ops callbacks are invoked with unlocked dma-buf
+ * reservation and exporter can take the lock:
+ *
+ * - &dma_buf_ops.attach()
+ * - &dma_buf_ops.detach()
+ * - &dma_buf_ops.release()
+ * - &dma_buf_ops.begin_cpu_access()
+ * - &dma_buf_ops.end_cpu_access()
+ *
+ * 2. These &dma_buf_ops callbacks are invoked with locked dma-buf
+ * reservation and exporter can't take the lock:
+ *
+ * - &dma_buf_ops.pin()
+ * - &dma_buf_ops.unpin()
+ * - &dma_buf_ops.map_dma_buf()
+ * - &dma_buf_ops.unmap_dma_buf()
+ * - &dma_buf_ops.mmap()
+ * - &dma_buf_ops.vmap()
+ * - &dma_buf_ops.vunmap()
+ *
+ * 3. Exporters must hold the dma-buf reservation lock when calling these
+ * functions:
+ *
+ * - dma_buf_move_notify()
+ */
+
+/**
* dma_buf_dynamic_attach - Add the device to dma_buf's attachments list
* @dmabuf: [in] buffer to attach device to.
* @dev: [in] device to be attached.
@@ -859,8 +938,8 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
dma_buf_is_dynamic(dmabuf)) {
struct sg_table *sgt;
+ dma_resv_lock(attach->dmabuf->resv, NULL);
if (dma_buf_is_dynamic(attach->dmabuf)) {
- dma_resv_lock(attach->dmabuf->resv, NULL);
ret = dmabuf->ops->pin(attach);
if (ret)
goto err_unlock;
@@ -873,8 +952,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
ret = PTR_ERR(sgt);
goto err_unpin;
}
- if (dma_buf_is_dynamic(attach->dmabuf))
- dma_resv_unlock(attach->dmabuf->resv);
+ dma_resv_unlock(attach->dmabuf->resv);
attach->sgt = sgt;
attach->dir = DMA_BIDIRECTIONAL;
}
@@ -890,8 +968,7 @@ err_unpin:
dmabuf->ops->unpin(attach);
err_unlock:
- if (dma_buf_is_dynamic(attach->dmabuf))
- dma_resv_unlock(attach->dmabuf->resv);
+ dma_resv_unlock(attach->dmabuf->resv);
dma_buf_detach(dmabuf, attach);
return ERR_PTR(ret);
@@ -934,24 +1011,22 @@ static void __unmap_dma_buf(struct dma_buf_attachment *attach,
*/
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
{
- if (WARN_ON(!dmabuf || !attach))
+ if (WARN_ON(!dmabuf || !attach || dmabuf != attach->dmabuf))
return;
+ dma_resv_lock(dmabuf->resv, NULL);
+
if (attach->sgt) {
- if (dma_buf_is_dynamic(attach->dmabuf))
- dma_resv_lock(attach->dmabuf->resv, NULL);
__unmap_dma_buf(attach, attach->sgt, attach->dir);
- if (dma_buf_is_dynamic(attach->dmabuf)) {
+ if (dma_buf_is_dynamic(attach->dmabuf))
dmabuf->ops->unpin(attach);
- dma_resv_unlock(attach->dmabuf->resv);
- }
}
-
- dma_resv_lock(dmabuf->resv, NULL);
list_del(&attach->node);
+
dma_resv_unlock(dmabuf->resv);
+
if (dmabuf->ops->detach)
dmabuf->ops->detach(dmabuf, attach);
@@ -1042,8 +1117,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
if (WARN_ON(!attach || !attach->dmabuf))
return ERR_PTR(-EINVAL);
- if (dma_buf_attachment_is_dynamic(attach))
- dma_resv_assert_held(attach->dmabuf->resv);
+ dma_resv_assert_held(attach->dmabuf->resv);
if (attach->sgt) {
/*
@@ -1058,7 +1132,6 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
}
if (dma_buf_is_dynamic(attach->dmabuf)) {
- dma_resv_assert_held(attach->dmabuf->resv);
if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) {
r = attach->dmabuf->ops->pin(attach);
if (r)
@@ -1101,6 +1174,34 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, DMA_BUF);
/**
+ * dma_buf_map_attachment_unlocked - Returns the scatterlist table of the attachment;
+ * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the
+ * dma_buf_ops.
+ * @attach: [in] attachment whose scatterlist is to be returned
+ * @direction: [in] direction of DMA transfer
+ *
+ * Unlocked variant of dma_buf_map_attachment().
+ */
+struct sg_table *
+dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach,
+ enum dma_data_direction direction)
+{
+ struct sg_table *sg_table;
+
+ might_sleep();
+
+ if (WARN_ON(!attach || !attach->dmabuf))
+ return ERR_PTR(-EINVAL);
+
+ dma_resv_lock(attach->dmabuf->resv, NULL);
+ sg_table = dma_buf_map_attachment(attach, direction);
+ dma_resv_unlock(attach->dmabuf->resv);
+
+ return sg_table;
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment_unlocked, DMA_BUF);
+
+/**
* dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might
* deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of
* dma_buf_ops.
@@ -1119,15 +1220,11 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
return;
- if (dma_buf_attachment_is_dynamic(attach))
- dma_resv_assert_held(attach->dmabuf->resv);
+ dma_resv_assert_held(attach->dmabuf->resv);
if (attach->sgt == sg_table)
return;
- if (dma_buf_is_dynamic(attach->dmabuf))
- dma_resv_assert_held(attach->dmabuf->resv);
-
__unmap_dma_buf(attach, sg_table, direction);
if (dma_buf_is_dynamic(attach->dmabuf) &&
@@ -1137,6 +1234,31 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, DMA_BUF);
/**
+ * dma_buf_unmap_attachment_unlocked - unmaps and decreases usecount of the buffer;might
+ * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of
+ * dma_buf_ops.
+ * @attach: [in] attachment to unmap buffer from
+ * @sg_table: [in] scatterlist info of the buffer to unmap
+ * @direction: [in] direction of DMA transfer
+ *
+ * Unlocked variant of dma_buf_unmap_attachment().
+ */
+void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach,
+ struct sg_table *sg_table,
+ enum dma_data_direction direction)
+{
+ might_sleep();
+
+ if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
+ return;
+
+ dma_resv_lock(attach->dmabuf->resv, NULL);
+ dma_buf_unmap_attachment(attach, sg_table, direction);
+ dma_resv_unlock(attach->dmabuf->resv);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF);
+
+/**
* dma_buf_move_notify - notify attachments that DMA-buf is moving
*
* @dmabuf: [in] buffer which is moving
@@ -1347,6 +1469,8 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, DMA_BUF);
int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
unsigned long pgoff)
{
+ int ret;
+
if (WARN_ON(!dmabuf || !vma))
return -EINVAL;
@@ -1367,7 +1491,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
vma_set_file(vma, dmabuf->file);
vma->vm_pgoff = pgoff;
- return dmabuf->ops->mmap(dmabuf, vma);
+ dma_resv_lock(dmabuf->resv, NULL);
+ ret = dmabuf->ops->mmap(dmabuf, vma);
+ dma_resv_unlock(dmabuf->resv);
+
+ return ret;
}
EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF);
@@ -1390,42 +1518,68 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF);
int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map)
{
struct iosys_map ptr;
- int ret = 0;
+ int ret;
iosys_map_clear(map);
if (WARN_ON(!dmabuf))
return -EINVAL;
+ dma_resv_assert_held(dmabuf->resv);
+
if (!dmabuf->ops->vmap)
return -EINVAL;
- mutex_lock(&dmabuf->lock);
if (dmabuf->vmapping_counter) {
dmabuf->vmapping_counter++;
BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr));
*map = dmabuf->vmap_ptr;
- goto out_unlock;
+ return 0;
}
BUG_ON(iosys_map_is_set(&dmabuf->vmap_ptr));
ret = dmabuf->ops->vmap(dmabuf, &ptr);
if (WARN_ON_ONCE(ret))
- goto out_unlock;
+ return ret;
dmabuf->vmap_ptr = ptr;
dmabuf->vmapping_counter = 1;
*map = dmabuf->vmap_ptr;
-out_unlock:
- mutex_unlock(&dmabuf->lock);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF);
/**
+ * dma_buf_vmap_unlocked - Create virtual mapping for the buffer object into kernel
+ * address space. Same restrictions as for vmap and friends apply.
+ * @dmabuf: [in] buffer to vmap
+ * @map: [out] returns the vmap pointer
+ *
+ * Unlocked version of dma_buf_vmap()
+ *
+ * Returns 0 on success, or a negative errno code otherwise.
+ */
+int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map)
+{
+ int ret;
+
+ iosys_map_clear(map);
+
+ if (WARN_ON(!dmabuf))
+ return -EINVAL;
+
+ dma_resv_lock(dmabuf->resv, NULL);
+ ret = dma_buf_vmap(dmabuf, map);
+ dma_resv_unlock(dmabuf->resv);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_vmap_unlocked, DMA_BUF);
+
+/**
* dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap.
* @dmabuf: [in] buffer to vunmap
* @map: [in] vmap pointer to vunmap
@@ -1435,20 +1589,36 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map)
if (WARN_ON(!dmabuf))
return;
+ dma_resv_assert_held(dmabuf->resv);
+
BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr));
BUG_ON(dmabuf->vmapping_counter == 0);
BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map));
- mutex_lock(&dmabuf->lock);
if (--dmabuf->vmapping_counter == 0) {
if (dmabuf->ops->vunmap)
dmabuf->ops->vunmap(dmabuf, map);
iosys_map_clear(&dmabuf->vmap_ptr);
}
- mutex_unlock(&dmabuf->lock);
}
EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF);
+/**
+ * dma_buf_vunmap_unlocked - Unmap a vmap obtained by dma_buf_vmap.
+ * @dmabuf: [in] buffer to vunmap
+ * @map: [in] vmap pointer to vunmap
+ */
+void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map)
+{
+ if (WARN_ON(!dmabuf))
+ return;
+
+ dma_resv_lock(dmabuf->resv, NULL);
+ dma_buf_vunmap(dmabuf, map);
+ dma_resv_unlock(dmabuf->resv);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, DMA_BUF);
+
#ifdef CONFIG_DEBUG_FS
static int dma_buf_debug_show(struct seq_file *s, void *unused)
{
diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
index 8f5848aa144f..59d158873f4c 100644
--- a/drivers/dma-buf/dma-heap.c
+++ b/drivers/dma-buf/dma-heap.c
@@ -233,18 +233,6 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
return ERR_PTR(-EINVAL);
}
- /* check the name is unique */
- mutex_lock(&heap_list_lock);
- list_for_each_entry(h, &heap_list, list) {
- if (!strcmp(h->name, exp_info->name)) {
- mutex_unlock(&heap_list_lock);
- pr_err("dma_heap: Already registered heap named %s\n",
- exp_info->name);
- return ERR_PTR(-EINVAL);
- }
- }
- mutex_unlock(&heap_list_lock);
-
heap = kzalloc(sizeof(*heap), GFP_KERNEL);
if (!heap)
return ERR_PTR(-ENOMEM);
@@ -283,13 +271,27 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
err_ret = ERR_CAST(dev_ret);
goto err2;
}
- /* Add heap to the list */
+
mutex_lock(&heap_list_lock);
+ /* check the name is unique */
+ list_for_each_entry(h, &heap_list, list) {
+ if (!strcmp(h->name, exp_info->name)) {
+ mutex_unlock(&heap_list_lock);
+ pr_err("dma_heap: Already registered heap named %s\n",
+ exp_info->name);
+ err_ret = ERR_PTR(-EINVAL);
+ goto err3;
+ }
+ }
+
+ /* Add heap to the list */
list_add(&heap->list, &heap_list);
mutex_unlock(&heap_list_lock);
return heap;
+err3:
+ device_destroy(dma_heap_class, heap->heap_devt);
err2:
cdev_del(&heap->heap_cdev);
err1:
diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c
index 28fb04eccdd0..1131fb943992 100644
--- a/drivers/dma-buf/heaps/cma_heap.c
+++ b/drivers/dma-buf/heaps/cma_heap.c
@@ -13,6 +13,7 @@
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include <linux/dma-map-ops.h>
+#include <linux/dma-resv.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/io.h>
@@ -182,6 +183,8 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
struct cma_heap_buffer *buffer = dmabuf->priv;
+ dma_resv_assert_held(dmabuf->resv);
+
if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
return -EINVAL;
diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
index fcf836ba9c1f..e8bd10e60998 100644
--- a/drivers/dma-buf/heaps/system_heap.c
+++ b/drivers/dma-buf/heaps/system_heap.c
@@ -13,6 +13,7 @@
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
#include <linux/dma-heap.h>
+#include <linux/dma-resv.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
@@ -201,6 +202,8 @@ static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
struct sg_page_iter piter;
int ret;
+ dma_resv_assert_held(dmabuf->resv);
+
for_each_sgtable_page(table, &piter, vma->vm_pgoff) {
struct page *page = sg_page_iter_page(&piter);
diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c
index 0a9b099d0518..c0979c8049b5 100644
--- a/drivers/dma-buf/st-dma-fence-chain.c
+++ b/drivers/dma-buf/st-dma-fence-chain.c
@@ -400,7 +400,7 @@ static int __find_race(void *arg)
struct dma_fence *fence = dma_fence_get(data->fc.tail);
int seqno;
- seqno = prandom_u32_max(data->fc.chain_length) + 1;
+ seqno = get_random_u32_inclusive(1, data->fc.chain_length);
err = dma_fence_chain_find_seqno(&fence, seqno);
if (err) {
@@ -429,7 +429,7 @@ static int __find_race(void *arg)
dma_fence_put(fence);
signal:
- seqno = prandom_u32_max(data->fc.chain_length - 1);
+ seqno = get_random_u32_below(data->fc.chain_length - 1);
dma_fence_signal(data->fc.fences[seqno]);
cond_resched();
}
@@ -637,7 +637,7 @@ static void randomise_fences(struct fence_chains *fc)
while (--count) {
unsigned int swp;
- swp = prandom_u32_max(count + 1);
+ swp = get_random_u32_below(count + 1);
if (swp == count)
continue;
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 2bcdb935a3ac..283816fbd72f 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -2,6 +2,7 @@
#include <linux/cred.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
+#include <linux/dma-resv.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -49,6 +50,8 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
{
struct udmabuf *ubuf = buf->priv;
+ dma_resv_assert_held(buf->resv);
+
if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
return -EINVAL;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 7524b62a8870..25e111ab21f8 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -462,7 +462,7 @@ config MV_XOR_V2
select DMA_ENGINE
select DMA_ENGINE_RAID
select ASYNC_TX_ENABLE_CHANNEL_SWITCH
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
help
Enable support for the Marvell version 2 XOR engine.
diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c
index 317ca76ccafd..a2cc520225d3 100644
--- a/drivers/dma/apple-admac.c
+++ b/drivers/dma/apple-admac.c
@@ -493,7 +493,7 @@ static struct dma_chan *admac_dma_of_xlate(struct of_phandle_args *dma_spec,
return NULL;
}
- return &ad->channels[index].chan;
+ return dma_get_slave_channel(&ad->channels[index].chan);
}
static int admac_drain_reports(struct admac_data *ad, int channo)
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 5a50423b7378..858bd64f1313 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -256,6 +256,8 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
ATC_SPIP_BOUNDARY(first->boundary));
channel_writel(atchan, DPIP, ATC_DPIP_HOLE(first->dst_hole) |
ATC_DPIP_BOUNDARY(first->boundary));
+ /* Don't allow CPU to reorder channel enable. */
+ wmb();
dma_writel(atdma, CHER, atchan->mask);
vdbg_dump_regs(atchan);
@@ -316,7 +318,8 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
struct at_desc *desc_first = atc_first_active(atchan);
struct at_desc *desc;
int ret;
- u32 ctrla, dscr, trials;
+ u32 ctrla, dscr;
+ unsigned int i;
/*
* If the cookie doesn't match to the currently running transfer then
@@ -386,7 +389,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
dscr = channel_readl(atchan, DSCR);
rmb(); /* ensure DSCR is read before CTRLA */
ctrla = channel_readl(atchan, CTRLA);
- for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) {
+ for (i = 0; i < ATC_MAX_DSCR_TRIALS; ++i) {
u32 new_dscr;
rmb(); /* ensure DSCR is read after CTRLA */
@@ -412,7 +415,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
rmb(); /* ensure DSCR is read before CTRLA */
ctrla = channel_readl(atchan, CTRLA);
}
- if (unlikely(trials >= ATC_MAX_DSCR_TRIALS))
+ if (unlikely(i == ATC_MAX_DSCR_TRIALS))
return -ETIMEDOUT;
/* for the first descriptor we can be more accurate */
@@ -462,18 +465,6 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
if (!atc_chan_is_cyclic(atchan))
dma_cookie_complete(txd);
- /* If the transfer was a memset, free our temporary buffer */
- if (desc->memset_buffer) {
- dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
- desc->memset_paddr);
- desc->memset_buffer = false;
- }
-
- /* move children to free_list */
- list_splice_init(&desc->tx_list, &atchan->free_list);
- /* move myself to free_list */
- list_move(&desc->desc_node, &atchan->free_list);
-
spin_unlock_irqrestore(&atchan->lock, flags);
dma_descriptor_unmap(txd);
@@ -483,42 +474,20 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
dmaengine_desc_get_callback_invoke(txd, NULL);
dma_run_dependencies(txd);
-}
-
-/**
- * atc_complete_all - finish work for all transactions
- * @atchan: channel to complete transactions for
- *
- * Eventually submit queued descriptors if any
- *
- * Assume channel is idle while calling this function
- * Called with atchan->lock held and bh disabled
- */
-static void atc_complete_all(struct at_dma_chan *atchan)
-{
- struct at_desc *desc, *_desc;
- LIST_HEAD(list);
- unsigned long flags;
-
- dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n");
spin_lock_irqsave(&atchan->lock, flags);
-
- /*
- * Submit queued descriptors ASAP, i.e. before we go through
- * the completed ones.
- */
- if (!list_empty(&atchan->queue))
- atc_dostart(atchan, atc_first_queued(atchan));
- /* empty active_list now it is completed */
- list_splice_init(&atchan->active_list, &list);
- /* empty queue list by moving descriptors (if any) to active_list */
- list_splice_init(&atchan->queue, &atchan->active_list);
-
+ /* move children to free_list */
+ list_splice_init(&desc->tx_list, &atchan->free_list);
+ /* add myself to free_list */
+ list_add(&desc->desc_node, &atchan->free_list);
spin_unlock_irqrestore(&atchan->lock, flags);
- list_for_each_entry_safe(desc, _desc, &list, desc_node)
- atc_chain_complete(atchan, desc);
+ /* If the transfer was a memset, free our temporary buffer */
+ if (desc->memset_buffer) {
+ dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
+ desc->memset_paddr);
+ desc->memset_buffer = false;
+ }
}
/**
@@ -527,26 +496,28 @@ static void atc_complete_all(struct at_dma_chan *atchan)
*/
static void atc_advance_work(struct at_dma_chan *atchan)
{
+ struct at_desc *desc;
unsigned long flags;
- int ret;
dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
spin_lock_irqsave(&atchan->lock, flags);
- ret = atc_chan_is_enabled(atchan);
- spin_unlock_irqrestore(&atchan->lock, flags);
- if (ret)
- return;
-
- if (list_empty(&atchan->active_list) ||
- list_is_singular(&atchan->active_list))
- return atc_complete_all(atchan);
+ if (atc_chan_is_enabled(atchan) || list_empty(&atchan->active_list))
+ return spin_unlock_irqrestore(&atchan->lock, flags);
- atc_chain_complete(atchan, atc_first_active(atchan));
+ desc = atc_first_active(atchan);
+ /* Remove the transfer node from the active list. */
+ list_del_init(&desc->desc_node);
+ spin_unlock_irqrestore(&atchan->lock, flags);
+ atc_chain_complete(atchan, desc);
/* advance work */
spin_lock_irqsave(&atchan->lock, flags);
- atc_dostart(atchan, atc_first_active(atchan));
+ if (!list_empty(&atchan->active_list)) {
+ desc = atc_first_queued(atchan);
+ list_move_tail(&desc->desc_node, &atchan->active_list);
+ atc_dostart(atchan, desc);
+ }
spin_unlock_irqrestore(&atchan->lock, flags);
}
@@ -558,6 +529,7 @@ static void atc_advance_work(struct at_dma_chan *atchan)
static void atc_handle_error(struct at_dma_chan *atchan)
{
struct at_desc *bad_desc;
+ struct at_desc *desc;
struct at_desc *child;
unsigned long flags;
@@ -570,13 +542,12 @@ static void atc_handle_error(struct at_dma_chan *atchan)
bad_desc = atc_first_active(atchan);
list_del_init(&bad_desc->desc_node);
- /* As we are stopped, take advantage to push queued descriptors
- * in active_list */
- list_splice_init(&atchan->queue, atchan->active_list.prev);
-
/* Try to restart the controller */
- if (!list_empty(&atchan->active_list))
- atc_dostart(atchan, atc_first_active(atchan));
+ if (!list_empty(&atchan->active_list)) {
+ desc = atc_first_queued(atchan);
+ list_move_tail(&desc->desc_node, &atchan->active_list);
+ atc_dostart(atchan, desc);
+ }
/*
* KERN_CRITICAL may seem harsh, but since this only happens
@@ -691,19 +662,11 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_irqsave(&atchan->lock, flags);
cookie = dma_cookie_assign(tx);
- if (list_empty(&atchan->active_list)) {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
- desc->txd.cookie);
- atc_dostart(atchan, desc);
- list_add_tail(&desc->desc_node, &atchan->active_list);
- } else {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
- desc->txd.cookie);
- list_add_tail(&desc->desc_node, &atchan->queue);
- }
-
+ list_add_tail(&desc->desc_node, &atchan->queue);
spin_unlock_irqrestore(&atchan->lock, flags);
+ dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+ desc->txd.cookie);
return cookie;
}
@@ -1445,11 +1408,8 @@ static int atc_terminate_all(struct dma_chan *chan)
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma *atdma = to_at_dma(chan->device);
int chan_id = atchan->chan_common.chan_id;
- struct at_desc *desc, *_desc;
unsigned long flags;
- LIST_HEAD(list);
-
dev_vdbg(chan2dev(chan), "%s\n", __func__);
/*
@@ -1468,19 +1428,15 @@ static int atc_terminate_all(struct dma_chan *chan)
cpu_relax();
/* active_list entries will end up before queued entries */
- list_splice_init(&atchan->queue, &list);
- list_splice_init(&atchan->active_list, &list);
-
- spin_unlock_irqrestore(&atchan->lock, flags);
-
- /* Flush all pending and queued descriptors */
- list_for_each_entry_safe(desc, _desc, &list, desc_node)
- atc_chain_complete(atchan, desc);
+ list_splice_tail_init(&atchan->queue, &atchan->free_list);
+ list_splice_tail_init(&atchan->active_list, &atchan->free_list);
clear_bit(ATC_IS_PAUSED, &atchan->status);
/* if channel dedicated to cyclic operations, free it */
clear_bit(ATC_IS_CYCLIC, &atchan->status);
+ spin_unlock_irqrestore(&atchan->lock, flags);
+
return 0;
}
@@ -1535,20 +1491,26 @@ atc_tx_status(struct dma_chan *chan,
}
/**
- * atc_issue_pending - try to finish work
+ * atc_issue_pending - takes the first transaction descriptor in the pending
+ * queue and starts the transfer.
* @chan: target DMA channel
*/
static void atc_issue_pending(struct dma_chan *chan)
{
- struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_desc *desc;
+ unsigned long flags;
dev_vdbg(chan2dev(chan), "issue_pending\n");
- /* Not needed for cyclic transfers */
- if (atc_chan_is_cyclic(atchan))
- return;
+ spin_lock_irqsave(&atchan->lock, flags);
+ if (atc_chan_is_enabled(atchan) || list_empty(&atchan->queue))
+ return spin_unlock_irqrestore(&atchan->lock, flags);
- atc_advance_work(atchan);
+ desc = atc_first_queued(atchan);
+ list_move_tail(&desc->desc_node, &atchan->active_list);
+ atc_dostart(atchan, desc);
+ spin_unlock_irqrestore(&atchan->lock, flags);
}
/**
@@ -1966,7 +1928,11 @@ static int __init at_dma_probe(struct platform_device *pdev)
dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "",
plat_dat->nr_channels);
- dma_async_device_register(&atdma->dma_common);
+ err = dma_async_device_register(&atdma->dma_common);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to register: %d.\n", err);
+ goto err_dma_async_device_register;
+ }
/*
* Do not return an error if the dmac node is not present in order to
@@ -1986,6 +1952,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
err_of_dma_controller_register:
dma_async_device_unregister(&atdma->dma_common);
+err_dma_async_device_register:
dma_pool_destroy(atdma->memset_pool);
err_memset_pool_create:
dma_pool_destroy(atdma->dma_desc_pool);
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index 4d1ebc040031..d4d382d74607 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -186,13 +186,13 @@
/* LLI == Linked List Item; aka DMA buffer descriptor */
struct at_lli {
/* values that are not changed by hardware */
- dma_addr_t saddr;
- dma_addr_t daddr;
+ u32 saddr;
+ u32 daddr;
/* value that may get written back: */
- u32 ctrla;
+ u32 ctrla;
/* more values that are not changed by hardware */
- u32 ctrlb;
- dma_addr_t dscr; /* chain to next lli */
+ u32 ctrlb;
+ u32 dscr; /* chain to next lli */
};
/**
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index c2808fd081d6..a9b96b18772f 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -312,6 +312,24 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev)
if (idxd->state != IDXD_DEV_ENABLED)
return -ENXIO;
+ /*
+ * User type WQ is enabled only when SVA is enabled for two reasons:
+ * - If no IOMMU or IOMMU Passthrough without SVA, userspace
+ * can directly access physical address through the WQ.
+ * - The IDXD cdev driver does not provide any ways to pin
+ * user pages and translate the address from user VA to IOVA or
+ * PA without IOMMU SVA. Therefore the application has no way
+ * to instruct the device to perform DMA function. This makes
+ * the cdev not usable for normal application usage.
+ */
+ if (!device_user_pasid_enabled(idxd)) {
+ idxd->cmd_status = IDXD_SCMD_WQ_USER_NO_IOMMU;
+ dev_dbg(&idxd->pdev->dev,
+ "User type WQ cannot be enabled without SVA.\n");
+
+ return -EOPNOTSUPP;
+ }
+
mutex_lock(&wq->wq_lock);
wq->type = IDXD_WQT_USER;
rc = drv_enable_wq(wq);
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 2c1e6f6daa62..6f44fa8f78a5 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -390,7 +390,7 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
clear_bit(WQ_FLAG_ATS_DISABLE, &wq->flags);
memset(wq->name, 0, WQ_NAME_SIZE);
wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER;
- wq->max_batch_size = WQ_DEFAULT_MAX_BATCH;
+ idxd_wq_set_max_batch_size(idxd->data->type, wq, WQ_DEFAULT_MAX_BATCH);
if (wq->opcap_bmap)
bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
}
@@ -730,13 +730,21 @@ static void idxd_device_wqs_clear_state(struct idxd_device *idxd)
void idxd_device_clear_state(struct idxd_device *idxd)
{
- if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
- return;
+ /* IDXD is always disabled. Other states are cleared only when IDXD is configurable. */
+ if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
+ /*
+ * Clearing wq state is protected by wq lock.
+ * So no need to be protected by device lock.
+ */
+ idxd_device_wqs_clear_state(idxd);
+
+ spin_lock(&idxd->dev_lock);
+ idxd_groups_clear_state(idxd);
+ idxd_engines_clear_state(idxd);
+ } else {
+ spin_lock(&idxd->dev_lock);
+ }
- idxd_device_wqs_clear_state(idxd);
- spin_lock(&idxd->dev_lock);
- idxd_groups_clear_state(idxd);
- idxd_engines_clear_state(idxd);
idxd->state = IDXD_DEV_DISABLED;
spin_unlock(&idxd->dev_lock);
}
@@ -869,7 +877,7 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
/* bytes 12-15 */
wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes);
- wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size);
+ idxd_wqcfg_set_max_batch_shift(idxd->data->type, wq->wqcfg, ilog2(wq->max_batch_size));
/* bytes 32-63 */
if (idxd->hw.wq_cap.op_config && wq->opcap_bmap) {
@@ -1051,7 +1059,7 @@ static int idxd_wq_load_config(struct idxd_wq *wq)
wq->priority = wq->wqcfg->priority;
wq->max_xfer_bytes = 1ULL << wq->wqcfg->max_xfer_shift;
- wq->max_batch_size = 1ULL << wq->wqcfg->max_batch_shift;
+ idxd_wq_set_max_batch_size(idxd->data->type, wq, 1U << wq->wqcfg->max_batch_shift);
for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
wqcfg_offset = WQCFG_OFFSET(idxd, wq->id, i);
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index 1196ab342f01..7ced8d283d98 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -548,6 +548,38 @@ static inline int idxd_wq_refcount(struct idxd_wq *wq)
return wq->client_count;
};
+/*
+ * Intel IAA does not support batch processing.
+ * The max batch size of device, max batch size of wq and
+ * max batch shift of wqcfg should be always 0 on IAA.
+ */
+static inline void idxd_set_max_batch_size(int idxd_type, struct idxd_device *idxd,
+ u32 max_batch_size)
+{
+ if (idxd_type == IDXD_TYPE_IAX)
+ idxd->max_batch_size = 0;
+ else
+ idxd->max_batch_size = max_batch_size;
+}
+
+static inline void idxd_wq_set_max_batch_size(int idxd_type, struct idxd_wq *wq,
+ u32 max_batch_size)
+{
+ if (idxd_type == IDXD_TYPE_IAX)
+ wq->max_batch_size = 0;
+ else
+ wq->max_batch_size = max_batch_size;
+}
+
+static inline void idxd_wqcfg_set_max_batch_shift(int idxd_type, union wqcfg *wqcfg,
+ u32 max_batch_shift)
+{
+ if (idxd_type == IDXD_TYPE_IAX)
+ wqcfg->max_batch_shift = 0;
+ else
+ wqcfg->max_batch_shift = max_batch_shift;
+}
+
int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv,
struct module *module, const char *mod_name);
#define idxd_driver_register(driver) \
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 2b18d512cbfc..09cbf0c179ba 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -183,7 +183,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
init_completion(&wq->wq_dead);
init_completion(&wq->wq_resurrect);
wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER;
- wq->max_batch_size = WQ_DEFAULT_MAX_BATCH;
+ idxd_wq_set_max_batch_size(idxd->data->type, wq, WQ_DEFAULT_MAX_BATCH);
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
if (!wq->wqcfg) {
@@ -418,7 +418,7 @@ static void idxd_read_caps(struct idxd_device *idxd)
idxd->max_xfer_bytes = 1ULL << idxd->hw.gen_cap.max_xfer_shift;
dev_dbg(dev, "max xfer size: %llu bytes\n", idxd->max_xfer_bytes);
- idxd->max_batch_size = 1U << idxd->hw.gen_cap.max_batch_shift;
+ idxd_set_max_batch_size(idxd->data->type, idxd, 1U << idxd->hw.gen_cap.max_batch_shift);
dev_dbg(dev, "max batch size: %u\n", idxd->max_batch_size);
if (idxd->hw.gen_cap.config_en)
set_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags);
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index bdaccf9e0436..7269bd54554f 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -1046,7 +1046,7 @@ static ssize_t wq_max_batch_size_store(struct device *dev, struct device_attribu
if (batch_size > idxd->max_batch_size)
return -EINVAL;
- wq->max_batch_size = (u32)batch_size;
+ idxd_wq_set_max_batch_size(idxd->data->type, wq, (u32)batch_size);
return count;
}
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
index f629ef6fd3c2..113834e1167b 100644
--- a/drivers/dma/mv_xor_v2.c
+++ b/drivers/dma/mv_xor_v2.c
@@ -893,6 +893,7 @@ static int mv_xor_v2_remove(struct platform_device *pdev)
tasklet_kill(&xor_dev->irq_tasklet);
clk_disable_unprepare(xor_dev->clk);
+ clk_disable_unprepare(xor_dev->reg_clk);
return 0;
}
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index e7034f6f3994..22a392fe6d32 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1247,14 +1247,14 @@ static int pxad_init_phys(struct platform_device *op,
return -ENOMEM;
for (i = 0; i < nb_phy_chans; i++)
- if (platform_get_irq(op, i) > 0)
+ if (platform_get_irq_optional(op, i) > 0)
nr_irq++;
for (i = 0; i < nb_phy_chans; i++) {
phy = &pdev->phys[i];
phy->base = pdev->base;
phy->idx = i;
- irq = platform_get_irq(op, i);
+ irq = platform_get_irq_optional(op, i);
if ((nr_irq > 1) && (irq > 0))
ret = devm_request_irq(&op->dev, irq,
pxad_chan_handler,
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
index 210f1a9eb441..04d1c33afc12 100644
--- a/drivers/dma/qcom/hidma.c
+++ b/drivers/dma/qcom/hidma.c
@@ -610,7 +610,7 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg)
return hidma_ll_inthandler(chirq, lldev);
}
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg)
{
struct hidma_lldev **lldevp = arg;
@@ -671,7 +671,7 @@ static int hidma_sysfs_init(struct hidma_dev *dev)
return device_create_file(dev->ddev.dev, dev->chid_attrs);
}
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
static void hidma_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
{
struct device *dev = msi_desc_to_dev(desc);
@@ -687,7 +687,7 @@ static void hidma_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
static void hidma_free_msis(struct hidma_dev *dmadev)
{
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
struct device *dev = dmadev->ddev.dev;
int i, virq;
@@ -704,7 +704,7 @@ static void hidma_free_msis(struct hidma_dev *dmadev)
static int hidma_request_msi(struct hidma_dev *dmadev,
struct platform_device *pdev)
{
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
int rc, i, virq;
rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 4891a1767e5a..37674029cb42 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -675,6 +675,8 @@ static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan)
chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
+ chan->status = DMA_PAUSED;
+
dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan);
}
@@ -789,9 +791,7 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
if (status & STM32_DMA_TCI) {
stm32_dma_irq_clear(chan, STM32_DMA_TCI);
if (scr & STM32_DMA_SCR_TCIE) {
- if (chan->status == DMA_PAUSED && !(scr & STM32_DMA_SCR_EN))
- stm32_dma_handle_chan_paused(chan);
- else
+ if (chan->status != DMA_PAUSED)
stm32_dma_handle_chan_done(chan, scr);
}
status &= ~STM32_DMA_TCI;
@@ -838,13 +838,11 @@ static int stm32_dma_pause(struct dma_chan *c)
return -EPERM;
spin_lock_irqsave(&chan->vchan.lock, flags);
+
ret = stm32_dma_disable_chan(chan);
- /*
- * A transfer complete flag is set to indicate the end of transfer due to the stream
- * interruption, so wait for interrupt
- */
if (!ret)
- chan->status = DMA_PAUSED;
+ stm32_dma_handle_chan_paused(chan);
+
spin_unlock_irqrestore(&chan->vchan.lock, flags);
return ret;
diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
index e28acbcb53f4..b9d4c843635f 100644
--- a/drivers/dma/stm32-mdma.c
+++ b/drivers/dma/stm32-mdma.c
@@ -1539,6 +1539,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec,
return NULL;
}
+ memset(&config, 0, sizeof(config));
config.request = dma_spec->args[0];
config.priority_level = dma_spec->args[1];
config.transfer_config = dma_spec->args[2];
diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c
index 4fdd9f06b723..4f1aeb81e9c7 100644
--- a/drivers/dma/ti/k3-udma-glue.c
+++ b/drivers/dma/ti/k3-udma-glue.c
@@ -299,6 +299,7 @@ struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev,
ret = device_register(&tx_chn->common.chan_dev);
if (ret) {
dev_err(dev, "Channel Device registration failed %d\n", ret);
+ put_device(&tx_chn->common.chan_dev);
tx_chn->common.chan_dev.parent = NULL;
goto err;
}
@@ -917,6 +918,7 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name,
ret = device_register(&rx_chn->common.chan_dev);
if (ret) {
dev_err(dev, "Channel Device registration failed %d\n", ret);
+ put_device(&rx_chn->common.chan_dev);
rx_chn->common.chan_dev.parent = NULL;
goto err;
}
@@ -1048,6 +1050,7 @@ k3_udma_glue_request_remote_rx_chn(struct device *dev, const char *name,
ret = device_register(&rx_chn->common.chan_dev);
if (ret) {
dev_err(dev, "Channel Device registration failed %d\n", ret);
+ put_device(&rx_chn->common.chan_dev);
rx_chn->common.chan_dev.parent = NULL;
goto err;
}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 456602d373b7..4cfdefbd744d 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -53,8 +53,8 @@ config EDAC_DECODE_MCE
has been initialized.
config EDAC_GHES
- bool "Output ACPI APEI/GHES BIOS detected errors via EDAC"
- depends on ACPI_APEI_GHES && (EDAC=y)
+ tristate "Output ACPI APEI/GHES BIOS detected errors via EDAC"
+ depends on ACPI_APEI_GHES
select UEFI_CPER
help
Not all machines support hardware-driven error report. Some of those
@@ -211,6 +211,7 @@ config EDAC_R82600
config EDAC_I5000
tristate "Intel Greencreek/Blackford chipset"
depends on X86 && PCI
+ depends on BROKEN
help
Support for error detection and correction the Intel
Greekcreek/Blackford chipsets.
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 2f854feeeb23..e3318e5575a3 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -4329,6 +4329,9 @@ static int __init amd64_edac_init(void)
int err = -ENODEV;
int i;
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
diff --git a/drivers/edac/armada_xp_edac.c b/drivers/edac/armada_xp_edac.c
index 038abbb83f4b..c4bd2fb9c46b 100644
--- a/drivers/edac/armada_xp_edac.c
+++ b/drivers/edac/armada_xp_edac.c
@@ -599,6 +599,9 @@ static int __init armada_xp_edac_init(void)
{
int res;
+ if (ghes_get_devices())
+ return -EBUSY;
+
/* only polling is supported */
edac_op_state = EDAC_OPSTATE_POLL;
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 0a638c97702a..15f63452a9be 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -298,6 +298,14 @@ DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
channel_dimm_label_show, channel_dimm_label_store, 6);
DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
channel_dimm_label_show, channel_dimm_label_store, 7);
+DEVICE_CHANNEL(ch8_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 8);
+DEVICE_CHANNEL(ch9_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 9);
+DEVICE_CHANNEL(ch10_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 10);
+DEVICE_CHANNEL(ch11_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 11);
/* Total possible dynamic DIMM Label attribute file table */
static struct attribute *dynamic_csrow_dimm_attr[] = {
@@ -309,6 +317,10 @@ static struct attribute *dynamic_csrow_dimm_attr[] = {
&dev_attr_legacy_ch5_dimm_label.attr.attr,
&dev_attr_legacy_ch6_dimm_label.attr.attr,
&dev_attr_legacy_ch7_dimm_label.attr.attr,
+ &dev_attr_legacy_ch8_dimm_label.attr.attr,
+ &dev_attr_legacy_ch9_dimm_label.attr.attr,
+ &dev_attr_legacy_ch10_dimm_label.attr.attr,
+ &dev_attr_legacy_ch11_dimm_label.attr.attr,
NULL
};
@@ -329,6 +341,14 @@ DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
channel_ce_count_show, NULL, 6);
DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
channel_ce_count_show, NULL, 7);
+DEVICE_CHANNEL(ch8_ce_count, S_IRUGO,
+ channel_ce_count_show, NULL, 8);
+DEVICE_CHANNEL(ch9_ce_count, S_IRUGO,
+ channel_ce_count_show, NULL, 9);
+DEVICE_CHANNEL(ch10_ce_count, S_IRUGO,
+ channel_ce_count_show, NULL, 10);
+DEVICE_CHANNEL(ch11_ce_count, S_IRUGO,
+ channel_ce_count_show, NULL, 11);
/* Total possible dynamic ce_count attribute file table */
static struct attribute *dynamic_csrow_ce_count_attr[] = {
@@ -340,6 +360,10 @@ static struct attribute *dynamic_csrow_ce_count_attr[] = {
&dev_attr_legacy_ch5_ce_count.attr.attr,
&dev_attr_legacy_ch6_ce_count.attr.attr,
&dev_attr_legacy_ch7_ce_count.attr.attr,
+ &dev_attr_legacy_ch8_ce_count.attr.attr,
+ &dev_attr_legacy_ch9_ce_count.attr.attr,
+ &dev_attr_legacy_ch10_ce_count.attr.attr,
+ &dev_attr_legacy_ch11_ce_count.attr.attr,
NULL
};
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 50ed9f2425bb..763c076d96f2 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -11,6 +11,7 @@
#ifndef __EDAC_MODULE_H__
#define __EDAC_MODULE_H__
+#include <acpi/ghes.h>
#include "edac_mc.h"
#include "edac_pci.h"
#include "edac_device.h"
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index c8fa7dcfdbd0..cf2b618c1ada 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -14,6 +14,7 @@
#include <linux/dmi.h>
#include "edac_module.h"
#include <ras/ras_event.h>
+#include <linux/notifier.h>
#define OTHER_DETAIL_LEN 400
@@ -53,12 +54,10 @@ static DEFINE_MUTEX(ghes_reg_mutex);
*/
static DEFINE_SPINLOCK(ghes_lock);
-/* "ghes_edac.force_load=1" skips the platform check */
-static bool __read_mostly force_load;
-module_param(force_load, bool, 0);
-
static bool system_scanned;
+static struct list_head *ghes_devs;
+
/* Memory Device - Type 17 of SMBIOS spec */
struct memdev_dmi_entry {
u8 type;
@@ -267,11 +266,14 @@ out:
return n;
}
-void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
+static int ghes_edac_report_mem_error(struct notifier_block *nb,
+ unsigned long val, void *data)
{
+ struct cper_sec_mem_err *mem_err = (struct cper_sec_mem_err *)data;
struct cper_mem_err_compact cmem;
struct edac_raw_error_desc *e;
struct mem_ctl_info *mci;
+ unsigned long sev = val;
struct ghes_pvt *pvt;
unsigned long flags;
char *p;
@@ -282,7 +284,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
* know.
*/
if (WARN_ON_ONCE(in_nmi()))
- return;
+ return NOTIFY_OK;
spin_lock_irqsave(&ghes_lock, flags);
@@ -374,36 +376,24 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
unlock:
spin_unlock_irqrestore(&ghes_lock, flags);
+
+ return NOTIFY_OK;
}
-/*
- * Known systems that are safe to enable this module.
- */
-static struct acpi_platform_list plat_list[] = {
- {"HPE ", "Server ", 0, ACPI_SIG_FADT, all_versions},
- { } /* End */
+static struct notifier_block ghes_edac_mem_err_nb = {
+ .notifier_call = ghes_edac_report_mem_error,
+ .priority = 0,
};
-int ghes_edac_register(struct ghes *ghes, struct device *dev)
+static int ghes_edac_register(struct device *dev)
{
bool fake = false;
struct mem_ctl_info *mci;
struct ghes_pvt *pvt;
struct edac_mc_layer layers[1];
unsigned long flags;
- int idx = -1;
int rc = 0;
- if (IS_ENABLED(CONFIG_X86)) {
- /* Check if safe to enable on this system */
- idx = acpi_match_platform_list(plat_list);
- if (!force_load && idx < 0)
- return -ENODEV;
- } else {
- force_load = true;
- idx = 0;
- }
-
/* finish another registration/unregistration instance first */
mutex_lock(&ghes_reg_mutex);
@@ -447,15 +437,10 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
pr_info("This system has a very crappy BIOS: It doesn't even list the DIMMS.\n");
pr_info("Its SMBIOS info is wrong. It is doubtful that the error report would\n");
pr_info("work on such system. Use this driver with caution\n");
- } else if (idx < 0) {
- pr_info("This EDAC driver relies on BIOS to enumerate memory and get error reports.\n");
- pr_info("Unfortunately, not all BIOSes reflect the memory layout correctly.\n");
- pr_info("So, the end result of using this driver varies from vendor to vendor.\n");
- pr_info("If you find incorrect reports, please contact your hardware vendor\n");
- pr_info("to correct its BIOS.\n");
- pr_info("This system has %d DIMM sockets.\n", ghes_hw.num_dimms);
}
+ pr_info("This system has %d DIMM sockets.\n", ghes_hw.num_dimms);
+
if (!fake) {
struct dimm_info *src, *dst;
int i = 0;
@@ -503,6 +488,8 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
ghes_pvt = pvt;
spin_unlock_irqrestore(&ghes_lock, flags);
+ ghes_register_report_chain(&ghes_edac_mem_err_nb);
+
/* only set on success */
refcount_set(&ghes_refcount, 1);
@@ -517,14 +504,11 @@ unlock:
return rc;
}
-void ghes_edac_unregister(struct ghes *ghes)
+static void ghes_edac_unregister(struct ghes *ghes)
{
struct mem_ctl_info *mci;
unsigned long flags;
- if (!force_load)
- return;
-
mutex_lock(&ghes_reg_mutex);
system_scanned = false;
@@ -548,6 +532,42 @@ void ghes_edac_unregister(struct ghes *ghes)
if (mci)
edac_mc_free(mci);
+ ghes_unregister_report_chain(&ghes_edac_mem_err_nb);
+
unlock:
mutex_unlock(&ghes_reg_mutex);
}
+
+static int __init ghes_edac_init(void)
+{
+ struct ghes *g, *g_tmp;
+
+ ghes_devs = ghes_get_devices();
+ if (!ghes_devs)
+ return -ENODEV;
+
+ if (list_empty(ghes_devs)) {
+ pr_info("GHES probing device list is empty");
+ return -ENODEV;
+ }
+
+ list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) {
+ ghes_edac_register(g->dev);
+ }
+
+ return 0;
+}
+module_init(ghes_edac_init);
+
+static void __exit ghes_edac_exit(void)
+{
+ struct ghes *g, *g_tmp;
+
+ list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) {
+ ghes_edac_unregister(g);
+ }
+}
+module_exit(ghes_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Output ACPI APEI/GHES BIOS detected errors via EDAC");
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index a22ea053f8e1..65aeea53e2df 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -304,11 +304,10 @@ static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus,
if (unlikely(pci_enable_device(pdev) < 0)) {
edac_dbg(2, "Failed to enable device %02x:%02x.%x\n",
bus, dev, fun);
+ pci_dev_put(pdev);
return NULL;
}
- pci_dev_get(pdev);
-
return pdev;
}
@@ -756,6 +755,9 @@ static int __init i10nm_init(void)
edac_dbg(2, "\n");
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index f76624ee82ef..49b4499269fb 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -279,7 +279,8 @@ static inline int from_nf_ferr(unsigned int mask)
#define FERR_NF_RECOVERABLE to_nf_mask(ERROR_NF_RECOVERABLE)
#define FERR_NF_UNCORRECTABLE to_nf_mask(ERROR_NF_UNCORRECTABLE)
-/* Defines to extract the vaious fields from the
+/*
+ * Defines to extract the various fields from the
* MTRx - Memory Technology Registers
*/
#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 10))
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index a07bbfd075d0..544dd19072ea 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -1271,9 +1271,12 @@ static int __init igen6_init(void)
edac_dbg(2, "\n");
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
- return -ENODEV;
+ return -EBUSY;
edac_op_state = EDAC_OPSTATE_NMI;
diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c
index 94cac7686a56..35ceaca578e1 100644
--- a/drivers/edac/layerscape_edac.c
+++ b/drivers/edac/layerscape_edac.c
@@ -38,6 +38,9 @@ static int __init fsl_ddr_mc_init(void)
{
int res;
+ if (ghes_get_devices())
+ return -EBUSY;
+
/* make sure error reporting method is sane */
switch (edac_op_state) {
case EDAC_OPSTATE_POLL:
diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c
index a20b299f1202..2b306f2cc605 100644
--- a/drivers/edac/pnd2_edac.c
+++ b/drivers/edac/pnd2_edac.c
@@ -1528,6 +1528,9 @@ static int __init pnd2_init(void)
edac_dbg(2, "\n");
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 8e39370fdb5c..0c779a0326b6 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -3634,6 +3634,9 @@ static int __init sbridge_init(void)
edac_dbg(2, "\n");
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c
index 7e2762f62eec..9397abb42c49 100644
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -653,6 +653,9 @@ static int __init skx_init(void)
edac_dbg(2, "\n");
+ if (ghes_get_devices())
+ return -EBUSY;
+
owner = edac_get_owner();
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c
index f13674081cb6..0bcd9f02c84a 100644
--- a/drivers/edac/thunderx_edac.c
+++ b/drivers/edac/thunderx_edac.c
@@ -2114,6 +2114,9 @@ static int __init thunderx_edac_init(void)
{
int rc = 0;
+ if (ghes_get_devices())
+ return -EBUSY;
+
rc = pci_register_driver(&thunderx_lmc_driver);
if (rc)
return rc;
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
index 54081403db4f..c52b9dd9154c 100644
--- a/drivers/edac/xgene_edac.c
+++ b/drivers/edac/xgene_edac.c
@@ -2004,6 +2004,9 @@ static int __init xgene_edac_init(void)
{
int rc;
+ if (ghes_get_devices())
+ return -EBUSY;
+
/* Make sure error reporting method is sane */
switch (edac_op_state) {
case EDAC_OPSTATE_POLL:
diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c
index 41041ff0fadb..2a120d8d3c27 100644
--- a/drivers/extcon/extcon-usbc-tusb320.c
+++ b/drivers/extcon/extcon-usbc-tusb320.c
@@ -327,7 +327,13 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
tusb320_extcon_irq_handler(priv, reg);
- tusb320_typec_irq_handler(priv, reg);
+
+ /*
+ * Type-C support is optional. Only call the Type-C handler if a
+ * port had been registered previously.
+ */
+ if (priv->port)
+ tusb320_typec_irq_handler(priv, reg);
regmap_write(priv->regmap, TUSB320_REG9, reg);
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index d5e86ef40b89..fa85c64d3ded 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -36,81 +36,6 @@
#include "common.h"
#define FFA_DRIVER_VERSION FFA_VERSION_1_0
-
-#define FFA_SMC(calling_convention, func_num) \
- ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \
- ARM_SMCCC_OWNER_STANDARD, (func_num))
-
-#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
-#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
-
-#define FFA_ERROR FFA_SMC_32(0x60)
-#define FFA_SUCCESS FFA_SMC_32(0x61)
-#define FFA_INTERRUPT FFA_SMC_32(0x62)
-#define FFA_VERSION FFA_SMC_32(0x63)
-#define FFA_FEATURES FFA_SMC_32(0x64)
-#define FFA_RX_RELEASE FFA_SMC_32(0x65)
-#define FFA_RXTX_MAP FFA_SMC_32(0x66)
-#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66)
-#define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
-#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
-#define FFA_ID_GET FFA_SMC_32(0x69)
-#define FFA_MSG_POLL FFA_SMC_32(0x6A)
-#define FFA_MSG_WAIT FFA_SMC_32(0x6B)
-#define FFA_YIELD FFA_SMC_32(0x6C)
-#define FFA_RUN FFA_SMC_32(0x6D)
-#define FFA_MSG_SEND FFA_SMC_32(0x6E)
-#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F)
-#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F)
-#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70)
-#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70)
-#define FFA_MEM_DONATE FFA_SMC_32(0x71)
-#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71)
-#define FFA_MEM_LEND FFA_SMC_32(0x72)
-#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72)
-#define FFA_MEM_SHARE FFA_SMC_32(0x73)
-#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73)
-#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74)
-#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74)
-#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75)
-#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76)
-#define FFA_MEM_RECLAIM FFA_SMC_32(0x77)
-#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78)
-#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79)
-#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A)
-#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B)
-#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C)
-
-/*
- * For some calls it is necessary to use SMC64 to pass or return 64-bit values.
- * For such calls FFA_FN_NATIVE(name) will choose the appropriate
- * (native-width) function ID.
- */
-#ifdef CONFIG_64BIT
-#define FFA_FN_NATIVE(name) FFA_FN64_##name
-#else
-#define FFA_FN_NATIVE(name) FFA_##name
-#endif
-
-/* FFA error codes. */
-#define FFA_RET_SUCCESS (0)
-#define FFA_RET_NOT_SUPPORTED (-1)
-#define FFA_RET_INVALID_PARAMETERS (-2)
-#define FFA_RET_NO_MEMORY (-3)
-#define FFA_RET_BUSY (-4)
-#define FFA_RET_INTERRUPTED (-5)
-#define FFA_RET_DENIED (-6)
-#define FFA_RET_RETRY (-7)
-#define FFA_RET_ABORTED (-8)
-
-#define MAJOR_VERSION_MASK GENMASK(30, 16)
-#define MINOR_VERSION_MASK GENMASK(15, 0)
-#define MAJOR_VERSION(x) ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x))))
-#define MINOR_VERSION(x) ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x))))
-#define PACK_VERSION_INFO(major, minor) \
- (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \
- FIELD_PREP(MINOR_VERSION_MASK, (minor)))
-#define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0)
#define FFA_MIN_VERSION FFA_VERSION_1_0
#define SENDER_ID_MASK GENMASK(31, 16)
@@ -121,12 +46,6 @@
(FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r)))
/*
- * FF-A specification mentions explicitly about '4K pages'. This should
- * not be confused with the kernel PAGE_SIZE, which is the translation
- * granule kernel is configured and may be one among 4K, 16K and 64K.
- */
-#define FFA_PAGE_SIZE SZ_4K
-/*
* Keeping RX TX buffer size as 4K for now
* 64K may be preferred to keep it min a page in 64K PAGE_SIZE config
*/
@@ -178,9 +97,9 @@ static struct ffa_drv_info *drv_info;
*/
static u32 ffa_compatible_version_find(u32 version)
{
- u16 major = MAJOR_VERSION(version), minor = MINOR_VERSION(version);
- u16 drv_major = MAJOR_VERSION(FFA_DRIVER_VERSION);
- u16 drv_minor = MINOR_VERSION(FFA_DRIVER_VERSION);
+ u16 major = FFA_MAJOR_VERSION(version), minor = FFA_MINOR_VERSION(version);
+ u16 drv_major = FFA_MAJOR_VERSION(FFA_DRIVER_VERSION);
+ u16 drv_minor = FFA_MINOR_VERSION(FFA_DRIVER_VERSION);
if ((major < drv_major) || (major == drv_major && minor <= drv_minor))
return version;
@@ -204,16 +123,16 @@ static int ffa_version_check(u32 *version)
if (ver.a0 < FFA_MIN_VERSION) {
pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n",
- MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0),
- MAJOR_VERSION(FFA_MIN_VERSION),
- MINOR_VERSION(FFA_MIN_VERSION));
+ FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0),
+ FFA_MAJOR_VERSION(FFA_MIN_VERSION),
+ FFA_MINOR_VERSION(FFA_MIN_VERSION));
return -EINVAL;
}
- pr_info("Driver version %d.%d\n", MAJOR_VERSION(FFA_DRIVER_VERSION),
- MINOR_VERSION(FFA_DRIVER_VERSION));
- pr_info("Firmware version %d.%d found\n", MAJOR_VERSION(ver.a0),
- MINOR_VERSION(ver.a0));
+ pr_info("Driver version %d.%d\n", FFA_MAJOR_VERSION(FFA_DRIVER_VERSION),
+ FFA_MINOR_VERSION(FFA_DRIVER_VERSION));
+ pr_info("Firmware version %d.%d found\n", FFA_MAJOR_VERSION(ver.a0),
+ FFA_MINOR_VERSION(ver.a0));
*version = ffa_compatible_version_find(ver.a0);
return 0;
diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c
index bd235833b687..5f47dbf4889a 100644
--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
+++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
@@ -110,6 +110,24 @@ found:
return 0;
}
+int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size)
+{
+ if (nvram_len) {
+ pr_warn("nvram already initialized\n");
+ return -EEXIST;
+ }
+
+ if (!bcm47xx_nvram_is_valid(nvram_start)) {
+ pr_err("No valid NVRAM found\n");
+ return -ENOENT;
+ }
+
+ bcm47xx_nvram_copy(nvram_start, res_size);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcm47xx_nvram_init_from_iomem);
+
/*
* On bcm47xx we need access to the NVRAM very early, so we can't use mtd
* subsystem to access flash. We can't even use platform device / driver to
diff --git a/drivers/firmware/cirrus/Kconfig b/drivers/firmware/cirrus/Kconfig
index f9503cb481d2..3ccbe14e4b0c 100644
--- a/drivers/firmware/cirrus/Kconfig
+++ b/drivers/firmware/cirrus/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-config CS_DSP
+config FW_CS_DSP
tristate
default n
diff --git a/drivers/firmware/cirrus/Makefile b/drivers/firmware/cirrus/Makefile
index f074e2638c9c..b91318ca0ff4 100644
--- a/drivers/firmware/cirrus/Makefile
+++ b/drivers/firmware/cirrus/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
#
-obj-$(CONFIG_CS_DSP) += cs_dsp.o
+obj-$(CONFIG_FW_CS_DSP) += cs_dsp.o
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 81cc3d0f6eec..f558b390fbfe 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -369,7 +369,7 @@ const char *cs_dsp_mem_region_name(unsigned int type)
return NULL;
}
}
-EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, FW_CS_DSP);
#ifdef CONFIG_DEBUG_FS
static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
@@ -480,7 +480,7 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
dsp->debugfs_root = root;
}
-EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
/**
* cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
@@ -492,17 +492,17 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
debugfs_remove_recursive(dsp->debugfs_root);
dsp->debugfs_root = NULL;
}
-EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
#else
void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
{
}
-EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
{
}
-EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
const char *s)
@@ -710,7 +710,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int
return -ETIMEDOUT;
}
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_acked_control, FW_CS_DSP);
static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
unsigned int off, const void *buf, size_t len)
@@ -752,7 +752,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
*
* Must be called with pwr_lock held.
*
- * Return: Zero for success, a negative number on error.
+ * Return: < 0 on error, 1 when the control value changed and 0 when it has not.
*/
int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
unsigned int off, const void *buf, size_t len)
@@ -767,18 +767,25 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
if (len + off * sizeof(u32) > ctl->len)
return -EINVAL;
- if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
ret = -EPERM;
- else if (buf != ctl->cache)
- memcpy(ctl->cache + off * sizeof(u32), buf, len);
+ } else if (buf != ctl->cache) {
+ if (memcmp(ctl->cache + off * sizeof(u32), buf, len))
+ memcpy(ctl->cache + off * sizeof(u32), buf, len);
+ else
+ return 0;
+ }
ctl->set = 1;
if (ctl->enabled && ctl->dsp->running)
ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ return 1;
}
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_ctrl, FW_CS_DSP);
static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
unsigned int off, void *buf, size_t len)
@@ -850,7 +857,7 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
return ret;
}
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_read_ctrl, FW_CS_DSP);
static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
{
@@ -1493,7 +1500,7 @@ struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, in
return rslt;
}
-EXPORT_SYMBOL_GPL(cs_dsp_get_ctl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, FW_CS_DSP);
static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp,
const struct cs_dsp_alg_region *alg_region)
@@ -1583,7 +1590,7 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
return NULL;
}
-EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, FW_CS_DSP);
static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
int type, __be32 id,
@@ -2217,7 +2224,7 @@ int cs_dsp_adsp1_init(struct cs_dsp *dsp)
return cs_dsp_common_init(dsp);
}
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP);
/**
* cs_dsp_adsp1_power_up() - Load and start the named firmware
@@ -2309,7 +2316,7 @@ err_mutex:
mutex_unlock(&dsp->pwr_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_up);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, FW_CS_DSP);
/**
* cs_dsp_adsp1_power_down() - Halts the DSP
@@ -2341,7 +2348,7 @@ void cs_dsp_adsp1_power_down(struct cs_dsp *dsp)
mutex_unlock(&dsp->pwr_lock);
}
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, FW_CS_DSP);
static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp)
{
@@ -2493,7 +2500,7 @@ int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq)
return ret;
}
-EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, FW_CS_DSP);
static void cs_dsp_stop_watchdog(struct cs_dsp *dsp)
{
@@ -2583,7 +2590,7 @@ err_mutex:
return ret;
}
-EXPORT_SYMBOL_GPL(cs_dsp_power_up);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, FW_CS_DSP);
/**
* cs_dsp_power_down() - Powers-down the DSP
@@ -2617,7 +2624,7 @@ void cs_dsp_power_down(struct cs_dsp *dsp)
cs_dsp_dbg(dsp, "Shutdown complete\n");
}
-EXPORT_SYMBOL_GPL(cs_dsp_power_down);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, FW_CS_DSP);
static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp)
{
@@ -2703,7 +2710,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_GPL(cs_dsp_run);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_run, FW_CS_DSP);
/**
* cs_dsp_stop() - Stops the firmware
@@ -2742,7 +2749,7 @@ void cs_dsp_stop(struct cs_dsp *dsp)
cs_dsp_dbg(dsp, "Execution stopped\n");
}
-EXPORT_SYMBOL_GPL(cs_dsp_stop);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, FW_CS_DSP);
static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
{
@@ -2804,7 +2811,7 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp)
return cs_dsp_common_init(dsp);
}
-EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP);
/**
* cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
@@ -2818,7 +2825,7 @@ int cs_dsp_halo_init(struct cs_dsp *dsp)
return cs_dsp_common_init(dsp);
}
-EXPORT_SYMBOL_GPL(cs_dsp_halo_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, FW_CS_DSP);
/**
* cs_dsp_remove() - Clean a cs_dsp before deletion
@@ -2838,7 +2845,7 @@ void cs_dsp_remove(struct cs_dsp *dsp)
cs_dsp_free_ctl_blk(ctl);
}
}
-EXPORT_SYMBOL_GPL(cs_dsp_remove);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, FW_CS_DSP);
/**
* cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
@@ -2875,7 +2882,7 @@ int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int me
return 0;
}
-EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, FW_CS_DSP);
/**
* cs_dsp_read_data_word() - Reads a word from DSP memory
@@ -2899,7 +2906,7 @@ int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_add
return 0;
}
-EXPORT_SYMBOL_GPL(cs_dsp_read_data_word);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, FW_CS_DSP);
/**
* cs_dsp_write_data_word() - Writes a word to DSP memory
@@ -2925,7 +2932,7 @@ int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_ad
return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
}
-EXPORT_SYMBOL_GPL(cs_dsp_write_data_word);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, FW_CS_DSP);
/**
* cs_dsp_remove_padding() - Convert unpacked words to packed bytes
@@ -2949,7 +2956,7 @@ void cs_dsp_remove_padding(u32 *buf, int nwords)
*pack_out++ = (u8)(word >> 16);
}
}
-EXPORT_SYMBOL_GPL(cs_dsp_remove_padding);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, FW_CS_DSP);
/**
* cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
@@ -3019,7 +3026,7 @@ void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
error:
mutex_unlock(&dsp->pwr_lock);
}
-EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, FW_CS_DSP);
/**
* cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
@@ -3079,7 +3086,7 @@ void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
exit_unlock:
mutex_unlock(&dsp->pwr_lock);
}
-EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, FW_CS_DSP);
/**
* cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
@@ -3099,7 +3106,7 @@ void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
mutex_unlock(&dsp->pwr_lock);
}
-EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, FW_CS_DSP);
static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
.validate_version = cs_dsp_validate_version,
@@ -3221,7 +3228,7 @@ int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
return 0;
}
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_write);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, FW_CS_DSP);
/**
* cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
@@ -3240,7 +3247,7 @@ int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
}
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_flush);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, FW_CS_DSP);
/**
* cs_dsp_chunk_read() - Parse data from a DSP memory chunk
@@ -3282,7 +3289,7 @@ int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
return result;
}
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_read);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP);
MODULE_DESCRIPTION("Cirrus Logic DSP Support");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index e4e5ea7ce910..053eae13f409 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -290,6 +290,7 @@ int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
return n;
}
+EXPORT_SYMBOL_GPL(cper_mem_err_location);
int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
{
@@ -310,6 +311,7 @@ int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
return n;
}
+EXPORT_SYMBOL_GPL(cper_dimm_err_location);
void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
struct cper_mem_err_compact *cmem)
@@ -331,6 +333,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
cmem->mem_array_handle = mem->mem_array_handle;
cmem->mem_dev_handle = mem->mem_dev_handle;
}
+EXPORT_SYMBOL_GPL(cper_mem_err_pack);
const char *cper_mem_err_unpack(struct trace_seq *p,
struct cper_mem_err_compact *cmem)
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index a52236e11e5f..4d6c5327471a 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -29,8 +29,8 @@ static void *efi_fb;
*/
static int __init efi_earlycon_remap_fb(void)
{
- /* bail if there is no bootconsole or it has been disabled already */
- if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
+ /* bail if there is no bootconsole or it was unregistered already */
+ if (!earlycon_console || !console_is_registered(earlycon_console))
return 0;
efi_fb = memremap(fb_base, screen_info.lfb_size,
@@ -42,8 +42,8 @@ early_initcall(efi_earlycon_remap_fb);
static int __init efi_earlycon_unmap_fb(void)
{
- /* unmap the bootconsole fb unless keep_bootcon has left it enabled */
- if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
+ /* unmap the bootconsole fb unless keep_bootcon left it registered */
+ if (efi_fb && !console_is_registered(earlycon_console))
memunmap(efi_fb);
return 0;
}
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index 3bddc152fcd4..97a9e84840a0 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -207,7 +207,7 @@ static int efi_pstore_erase(struct pstore_record *record)
static struct pstore_info efi_pstore_info = {
.owner = THIS_MODULE,
- .name = "efi",
+ .name = KBUILD_MODNAME,
.flags = PSTORE_FLAGS_DMESG,
.open = efi_pstore_open,
.close = efi_pstore_close,
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index a46df5d1d094..16dae588f0e3 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -337,6 +337,24 @@ static void __init efi_debugfs_init(void)
static inline void efi_debugfs_init(void) {}
#endif
+static void refresh_nv_rng_seed(struct work_struct *work)
+{
+ u8 seed[EFI_RANDOM_SEED_SIZE];
+
+ get_random_bytes(seed, sizeof(seed));
+ efi.set_variable(L"RandomSeed", &LINUX_EFI_RANDOM_SEED_TABLE_GUID,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS, sizeof(seed), seed);
+ memzero_explicit(seed, sizeof(seed));
+}
+static int refresh_nv_rng_seed_notification(struct notifier_block *nb, unsigned long action, void *data)
+{
+ static DECLARE_WORK(work, refresh_nv_rng_seed);
+ schedule_work(&work);
+ return NOTIFY_DONE;
+}
+static struct notifier_block refresh_nv_rng_seed_nb = { .notifier_call = refresh_nv_rng_seed_notification };
+
/*
* We register the efi subsystem with the firmware subsystem and the
* efivars subsystem with the efi subsystem, if the system was booted with
@@ -413,6 +431,7 @@ static int __init efisubsys_init(void)
platform_device_register_simple("efi_secret", 0, NULL, 0);
#endif
+ execute_with_initialized_rng(&refresh_nv_rng_seed_nb);
return 0;
err_remove_group:
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index b1601aad7e1a..453b67582fee 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -20,6 +20,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \
# disable the stackleak plugin
cflags-$(CONFIG_ARM64) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
-fpie $(DISABLE_STACKLEAK_PLUGIN) \
+ -fno-unwind-tables -fno-asynchronous-unwind-tables \
$(call cc-option,-mbranch-protection=none)
cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
-fno-builtin -fpic \
@@ -82,7 +83,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o
lib-$(CONFIG_ARM) += arm32-stub.o
-lib-$(CONFIG_ARM64) += arm64-stub.o
+lib-$(CONFIG_ARM64) += arm64-stub.o smbios.o
lib-$(CONFIG_X86) += x86-stub.o
lib-$(CONFIG_RISCV) += riscv-stub.o
lib-$(CONFIG_LOONGARCH) += loongarch-stub.o
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 259e4b852d63..f9de5217ea65 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -15,6 +15,21 @@
#include "efistub.h"
+static bool system_needs_vamap(void)
+{
+ const u8 *type1_family = efi_get_smbios_string(1, family);
+
+ /*
+ * Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
+ * has not been called prior.
+ */
+ if (!type1_family || strcmp(type1_family, "Altra"))
+ return false;
+
+ efi_warn("Working around broken SetVirtualAddressMap()\n");
+ return true;
+}
+
efi_status_t check_platform_features(void)
{
u64 tg;
@@ -24,7 +39,7 @@ efi_status_t check_platform_features(void)
* UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
* unnecessary.
*/
- if (VA_BITS_MIN >= 48)
+ if (VA_BITS_MIN >= 48 && !system_needs_vamap())
efi_novamap = true;
/* UEFI mandates support for 4 KB granularity, no need to check */
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index a30fb5d8ef05..eb03d5a9aac8 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -975,4 +975,32 @@ efi_enable_reset_attack_mitigation(void) { }
void efi_retrieve_tpm2_eventlog(void);
+struct efi_smbios_record {
+ u8 type;
+ u8 length;
+ u16 handle;
+};
+
+struct efi_smbios_type1_record {
+ struct efi_smbios_record header;
+
+ u8 manufacturer;
+ u8 product_name;
+ u8 version;
+ u8 serial_number;
+ efi_guid_t uuid;
+ u8 wakeup_type;
+ u8 sku_number;
+ u8 family;
+};
+
+#define efi_get_smbios_string(__type, __name) ({ \
+ int size = sizeof(struct efi_smbios_type ## __type ## _record); \
+ int off = offsetof(struct efi_smbios_type ## __type ## _record, \
+ __name); \
+ __efi_get_smbios_string(__type, off, size); \
+})
+
+const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
+
#endif
diff --git a/drivers/firmware/efi/libstub/smbios.c b/drivers/firmware/efi/libstub/smbios.c
new file mode 100644
index 000000000000..460418b7f5f5
--- /dev/null
+++ b/drivers/firmware/efi/libstub/smbios.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2022 Google LLC
+// Author: Ard Biesheuvel <ardb@google.com>
+
+#include <linux/efi.h>
+
+#include "efistub.h"
+
+typedef struct efi_smbios_protocol efi_smbios_protocol_t;
+
+struct efi_smbios_protocol {
+ efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
+ u16 *, struct efi_smbios_record *);
+ efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
+ unsigned long *, u8 *);
+ efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
+ efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
+ struct efi_smbios_record **,
+ efi_handle_t *);
+
+ u8 major_version;
+ u8 minor_version;
+};
+
+const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
+{
+ struct efi_smbios_record *record;
+ efi_smbios_protocol_t *smbios;
+ efi_status_t status;
+ u16 handle = 0xfffe;
+ const u8 *strtable;
+
+ status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
+ (void **)&smbios) ?:
+ efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ strtable = (u8 *)record + recsize;
+ for (int i = 1; i < ((u8 *)record)[offset]; i++) {
+ int len = strlen(strtable);
+
+ if (!len)
+ return NULL;
+ strtable += len + 1;
+ }
+ return strtable;
+}
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index c52bcaa9def6..9ca21feb9d45 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -149,12 +149,8 @@ static int coreboot_table_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;
- ret = bus_register(&coreboot_bus_type);
- if (!ret) {
- ret = coreboot_table_populate(dev, ptr);
- if (ret)
- bus_unregister(&coreboot_bus_type);
- }
+ ret = coreboot_table_populate(dev, ptr);
+
memunmap(ptr);
return ret;
@@ -169,7 +165,6 @@ static int __cb_dev_unregister(struct device *dev, void *dummy)
static int coreboot_table_remove(struct platform_device *pdev)
{
bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister);
- bus_unregister(&coreboot_bus_type);
return 0;
}
@@ -199,6 +194,32 @@ static struct platform_driver coreboot_table_driver = {
.of_match_table = of_match_ptr(coreboot_of_match),
},
};
-module_platform_driver(coreboot_table_driver);
+
+static int __init coreboot_table_driver_init(void)
+{
+ int ret;
+
+ ret = bus_register(&coreboot_bus_type);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&coreboot_table_driver);
+ if (ret) {
+ bus_unregister(&coreboot_bus_type);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit coreboot_table_driver_exit(void)
+{
+ platform_driver_unregister(&coreboot_table_driver);
+ bus_unregister(&coreboot_bus_type);
+}
+
+module_init(coreboot_table_driver_init);
+module_exit(coreboot_table_driver_exit);
+
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c
index af3d057e6421..2a4f07423365 100644
--- a/drivers/firmware/imx/scu-pd.c
+++ b/drivers/firmware/imx/scu-pd.c
@@ -108,6 +108,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* CONN SS */
{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
+ { "usb1phy", IMX_SC_R_USB_1_PHY, 1, false, 0},
{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index 4b8978b254f9..ec07bf26e5eb 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -228,6 +228,26 @@ static void rpi_register_clk_driver(struct device *dev)
-1, NULL, 0);
}
+unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
+{
+ struct rpi_firmware_clk_rate_request msg =
+ RPI_FIRMWARE_CLK_RATE_REQUEST(id);
+ int ret;
+
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+ &msg, sizeof(msg));
+ if (ret)
+ /*
+ * If our firmware doesn't support that operation, or fails, we
+ * assume the maximum clock rate is absolute maximum we can
+ * store over our type.
+ */
+ return UINT_MAX;
+
+ return le32_to_cpu(msg.rate);
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_clk_get_max_rate);
+
static void rpi_firmware_delete(struct kref *kref)
{
struct rpi_firmware *fw = container_of(kref, struct rpi_firmware,
@@ -268,12 +288,9 @@ static int rpi_firmware_probe(struct platform_device *pdev)
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;
- }
+ if (IS_ERR(fw->chan))
+ return dev_err_probe(dev, PTR_ERR(fw->chan),
+ "Failed to get mbox channel\n");
init_completion(&fw->c);
kref_init(&fw->consumers);
@@ -311,6 +328,18 @@ static int rpi_firmware_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id rpi_firmware_of_match[] = {
+ { .compatible = "raspberrypi,bcm2835-firmware", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_firmware_of_match);
+
+struct device_node *rpi_firmware_find_node(void)
+{
+ return of_find_matching_node(NULL, rpi_firmware_of_match);
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_find_node);
+
/**
* rpi_firmware_get - Get pointer to rpi_firmware structure.
* @firmware_node: Pointer to the firmware Device Tree node.
@@ -366,12 +395,6 @@ struct rpi_firmware *devm_rpi_firmware_get(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_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",
diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig
index 1c8ba1f47c7c..cde1ab8bd9d1 100644
--- a/drivers/firmware/tegra/Kconfig
+++ b/drivers/firmware/tegra/Kconfig
@@ -14,6 +14,7 @@ config TEGRA_IVC
config TEGRA_BPMP
bool "Tegra BPMP driver"
depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC
+ depends on !CPU_BIG_ENDIAN
help
BPMP (Boot and Power Management Processor) is designed to off-loading
the PM functions which include clock/DVFS/thermal/power from the CPU.
diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c
index 9d3874cdaaee..3ca2b5d9e66f 100644
--- a/drivers/firmware/tegra/bpmp-debugfs.c
+++ b/drivers/firmware/tegra/bpmp-debugfs.c
@@ -48,13 +48,9 @@ static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte)
return seqbuf_status(seqbuf);
}
-static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v)
+static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v)
{
- int err;
-
- err = seqbuf_read(seqbuf, v, 4);
- *v = le32_to_cpu(*v);
- return err;
+ return seqbuf_read(seqbuf, v, 4);
}
static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str)
@@ -109,10 +105,10 @@ out:
}
static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
- uint32_t *fd, uint32_t *len, bool write)
+ u32 *fd, u32 *len, bool write)
{
struct mrq_debug_request req = {
- .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO),
+ .cmd = write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@@ -147,10 +143,10 @@ static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
return 0;
}
-static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
+static int mrq_debug_close(struct tegra_bpmp *bpmp, u32 fd)
{
struct mrq_debug_request req = {
- .cmd = cpu_to_le32(CMD_DEBUG_CLOSE),
+ .cmd = CMD_DEBUG_CLOSE,
.frd = {
.fd = fd,
},
@@ -179,10 +175,10 @@ static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
}
static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
- char *data, size_t sz_data, uint32_t *nbytes)
+ char *data, size_t sz_data, u32 *nbytes)
{
struct mrq_debug_request req = {
- .cmd = cpu_to_le32(CMD_DEBUG_READ),
+ .cmd = CMD_DEBUG_READ,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@@ -196,7 +192,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
.size = sizeof(resp),
},
};
- uint32_t fd = 0, len = 0;
+ u32 fd = 0, len = 0;
int remaining, err;
mutex_lock(&bpmp_debug_lock);
@@ -245,7 +241,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
uint8_t *data, size_t sz_data)
{
struct mrq_debug_request req = {
- .cmd = cpu_to_le32(CMD_DEBUG_WRITE)
+ .cmd = CMD_DEBUG_WRITE
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@@ -259,7 +255,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
.size = sizeof(resp),
},
};
- uint32_t fd = 0, len = 0;
+ u32 fd = 0, len = 0;
size_t remaining;
int err;
@@ -308,7 +304,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
char fnamebuf[256];
const char *filename;
struct mrq_debug_request req = {
- .cmd = cpu_to_le32(CMD_DEBUG_READ),
+ .cmd = CMD_DEBUG_READ,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@@ -322,7 +318,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
.size = sizeof(resp),
},
};
- uint32_t fd = 0, len = 0;
+ u32 fd = 0, len = 0;
int remaining, err;
filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
@@ -406,8 +402,8 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
{
const size_t pathlen = SZ_256;
const size_t bufsize = SZ_16K;
- uint32_t dsize, attrs = 0;
struct dentry *dentry;
+ u32 dsize, attrs = 0;
struct seqbuf seqbuf;
char *buf, *pathbuf;
const char *name;
@@ -487,12 +483,12 @@ static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
size_t *nbytes)
{
struct mrq_debugfs_request req = {
- .cmd = cpu_to_le32(CMD_DEBUGFS_READ),
+ .cmd = CMD_DEBUGFS_READ,
.fop = {
- .fnameaddr = cpu_to_le32((uint32_t)name),
- .fnamelen = cpu_to_le32((uint32_t)sz_name),
- .dataaddr = cpu_to_le32((uint32_t)data),
- .datalen = cpu_to_le32((uint32_t)sz_data),
+ .fnameaddr = (u32)name,
+ .fnamelen = (u32)sz_name,
+ .dataaddr = (u32)data,
+ .datalen = (u32)sz_data,
},
};
struct mrq_debugfs_response resp;
@@ -525,12 +521,12 @@ static int mrq_debugfs_write(struct tegra_bpmp *bpmp,
dma_addr_t data, size_t sz_data)
{
const struct mrq_debugfs_request req = {
- .cmd = cpu_to_le32(CMD_DEBUGFS_WRITE),
+ .cmd = CMD_DEBUGFS_WRITE,
.fop = {
- .fnameaddr = cpu_to_le32((uint32_t)name),
- .fnamelen = cpu_to_le32((uint32_t)sz_name),
- .dataaddr = cpu_to_le32((uint32_t)data),
- .datalen = cpu_to_le32((uint32_t)sz_data),
+ .fnameaddr = (u32)name,
+ .fnamelen = (u32)sz_name,
+ .dataaddr = (u32)data,
+ .datalen = (u32)sz_data,
},
};
struct tegra_bpmp_message msg = {
@@ -548,10 +544,10 @@ static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr,
size_t size, size_t *nbytes)
{
const struct mrq_debugfs_request req = {
- .cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR),
+ .cmd = CMD_DEBUGFS_DUMPDIR,
.dumpdir = {
- .dataaddr = cpu_to_le32((uint32_t)addr),
- .datalen = cpu_to_le32((uint32_t)size),
+ .dataaddr = (u32)addr,
+ .datalen = (u32)size,
},
};
struct mrq_debugfs_response resp;
@@ -688,10 +684,10 @@ static const struct file_operations debugfs_fops = {
};
static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
- struct dentry *parent, uint32_t depth)
+ struct dentry *parent, u32 depth)
{
int err;
- uint32_t d, t;
+ u32 d, t;
const char *name;
struct dentry *dentry;
diff --git a/drivers/firmware/tegra/bpmp-tegra186.c b/drivers/firmware/tegra/bpmp-tegra186.c
index 63ab21d89c2c..2e26199041cd 100644
--- a/drivers/firmware/tegra/bpmp-tegra186.c
+++ b/drivers/firmware/tegra/bpmp-tegra186.c
@@ -18,8 +18,8 @@ struct tegra186_bpmp {
struct {
struct gen_pool *pool;
+ void __iomem *virt;
dma_addr_t phys;
- void *virt;
} tx, rx;
struct {
@@ -40,31 +40,27 @@ mbox_client_to_bpmp(struct mbox_client *client)
static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel *channel)
{
- void *frame;
+ int err;
- frame = tegra_ivc_read_get_next_frame(channel->ivc);
- if (IS_ERR(frame)) {
- channel->ib = NULL;
+ err = tegra_ivc_read_get_next_frame(channel->ivc, &channel->ib);
+ if (err) {
+ iosys_map_clear(&channel->ib);
return false;
}
- channel->ib = frame;
-
return true;
}
static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
{
- void *frame;
+ int err;
- frame = tegra_ivc_write_get_next_frame(channel->ivc);
- if (IS_ERR(frame)) {
- channel->ob = NULL;
+ err = tegra_ivc_write_get_next_frame(channel->ivc, &channel->ob);
+ if (err) {
+ iosys_map_clear(&channel->ob);
return false;
}
- channel->ob = frame;
-
return true;
}
@@ -109,6 +105,7 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
{
struct tegra186_bpmp *priv = bpmp->priv;
size_t message_size, queue_size;
+ struct iosys_map rx, tx;
unsigned int offset;
int err;
@@ -121,10 +118,11 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
queue_size = tegra_ivc_total_queue_size(message_size);
offset = queue_size * index;
- err = tegra_ivc_init(channel->ivc, NULL,
- priv->rx.virt + offset, priv->rx.phys + offset,
- priv->tx.virt + offset, priv->tx.phys + offset,
- 1, message_size, tegra186_bpmp_ivc_notify,
+ iosys_map_set_vaddr_iomem(&rx, priv->rx.virt + offset);
+ iosys_map_set_vaddr_iomem(&tx, priv->tx.virt + offset);
+
+ err = tegra_ivc_init(channel->ivc, NULL, &rx, priv->rx.phys + offset, &tx,
+ priv->tx.phys + offset, 1, message_size, tegra186_bpmp_ivc_notify,
bpmp);
if (err < 0) {
dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
@@ -179,7 +177,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
return -EPROBE_DEFER;
}
- priv->tx.virt = gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
+ priv->tx.virt = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
if (!priv->tx.virt) {
dev_err(bpmp->dev, "failed to allocate from TX pool\n");
return -ENOMEM;
@@ -192,7 +190,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
goto free_tx;
}
- priv->rx.virt = gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
+ priv->rx.virt = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
if (!priv->rx.virt) {
dev_err(bpmp->dev, "failed to allocate from RX pool\n");
err = -ENOMEM;
diff --git a/drivers/firmware/tegra/bpmp-tegra210.c b/drivers/firmware/tegra/bpmp-tegra210.c
index c9c830f658c3..6295f5640c15 100644
--- a/drivers/firmware/tegra/bpmp-tegra210.c
+++ b/drivers/firmware/tegra/bpmp-tegra210.c
@@ -137,8 +137,8 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
unsigned int index)
{
struct tegra210_bpmp *priv = bpmp->priv;
+ void __iomem *p;
u32 address;
- void *p;
/* Retrieve channel base address from BPMP */
writel(index << TRIGGER_ID_SHIFT | TRIGGER_CMD_GET,
@@ -149,8 +149,9 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
if (!p)
return -ENOMEM;
- channel->ib = p;
- channel->ob = p;
+ iosys_map_set_vaddr_iomem(&channel->ib, p);
+ iosys_map_set_vaddr_iomem(&channel->ob, p);
+
channel->index = index;
init_completion(&channel->completion);
channel->bpmp = bpmp;
@@ -199,10 +200,8 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
}
err = platform_get_irq_byname(pdev, "tx");
- if (err < 0) {
- dev_err(&pdev->dev, "failed to get TX IRQ: %d\n", err);
+ if (err < 0)
return err;
- }
priv->tx_irq_data = irq_get_irq_data(err);
if (!priv->tx_irq_data) {
@@ -211,10 +210,8 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
}
err = platform_get_irq_byname(pdev, "rx");
- if (err < 0) {
- dev_err(&pdev->dev, "failed to get rx IRQ: %d\n", err);
+ if (err < 0)
return err;
- }
err = devm_request_irq(&pdev->dev, err, rx_irq,
IRQF_NO_SUSPEND, dev_name(&pdev->dev), bpmp);
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 037db21de510..042c2043929d 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -201,13 +201,13 @@ static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
int err;
if (data && size > 0)
- memcpy_fromio(data, channel->ib->data, size);
+ tegra_bpmp_mb_read(data, &channel->ib, size);
err = tegra_bpmp_ack_response(channel);
if (err < 0)
return err;
- *ret = channel->ib->code;
+ *ret = tegra_bpmp_mb_read_field(&channel->ib, code);
return 0;
}
@@ -241,11 +241,11 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
unsigned int mrq, unsigned long flags,
const void *data, size_t size)
{
- channel->ob->code = mrq;
- channel->ob->flags = flags;
+ tegra_bpmp_mb_write_field(&channel->ob, code, mrq);
+ tegra_bpmp_mb_write_field(&channel->ob, flags, flags);
if (data && size > 0)
- memcpy_toio(channel->ob->data, data, size);
+ tegra_bpmp_mb_write(&channel->ob, data, size);
return tegra_bpmp_post_request(channel);
}
@@ -400,7 +400,7 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
const void *data, size_t size)
{
- unsigned long flags = channel->ib->flags;
+ unsigned long flags = tegra_bpmp_mb_read_field(&channel->ib, flags);
struct tegra_bpmp *bpmp = channel->bpmp;
int err;
@@ -417,10 +417,10 @@ void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
if (WARN_ON(!tegra_bpmp_is_response_channel_free(channel)))
return;
- channel->ob->code = code;
+ tegra_bpmp_mb_write_field(&channel->ob, code, code);
if (data && size > 0)
- memcpy_toio(channel->ob->data, data, size);
+ tegra_bpmp_mb_write(&channel->ob, data, size);
err = tegra_bpmp_post_response(channel);
if (WARN_ON(err < 0))
@@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
{
- struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
+ struct mrq_query_abi_request req = { .mrq = mrq };
struct mrq_query_abi_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_QUERY_ABI,
@@ -529,13 +529,13 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
struct tegra_bpmp_channel *channel,
void *data)
{
- struct mrq_ping_request *request;
+ struct mrq_ping_request request;
struct mrq_ping_response response;
- request = (struct mrq_ping_request *)channel->ib->data;
+ tegra_bpmp_mb_read(&request, &channel->ib, sizeof(request));
memset(&response, 0, sizeof(response));
- response.reply = request->challenge << 1;
+ response.reply = request.challenge << 1;
tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
}
@@ -648,7 +648,7 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
{
- unsigned long flags = channel->ob->flags;
+ unsigned long flags = tegra_bpmp_mb_read_field(&channel->ob, flags);
if ((flags & MSG_RING) == 0)
return;
@@ -666,8 +666,11 @@ void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
count = bpmp->soc->channels.thread.count;
busy = bpmp->threaded.busy;
- if (tegra_bpmp_is_request_ready(channel))
- tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
+ if (tegra_bpmp_is_request_ready(channel)) {
+ unsigned int mrq = tegra_bpmp_mb_read_field(&channel->ib, code);
+
+ tegra_bpmp_handle_mrq(bpmp, mrq, channel);
+ }
spin_lock(&bpmp->lock);
diff --git a/drivers/firmware/tegra/ivc.c b/drivers/firmware/tegra/ivc.c
index e2398cd7ca98..8c9aff9804c0 100644
--- a/drivers/firmware/tegra/ivc.c
+++ b/drivers/firmware/tegra/ivc.c
@@ -68,6 +68,12 @@ struct tegra_ivc_header {
} rx;
};
+#define tegra_ivc_header_read_field(hdr, field) \
+ iosys_map_rd_field(hdr, 0, struct tegra_ivc_header, field)
+
+#define tegra_ivc_header_write_field(hdr, field, value) \
+ iosys_map_wr_field(hdr, 0, struct tegra_ivc_header, field, value)
+
static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys)
{
if (!ivc->peer)
@@ -86,16 +92,15 @@ static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys)
DMA_TO_DEVICE);
}
-static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
- struct tegra_ivc_header *header)
+static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct iosys_map *map)
{
/*
* This function performs multiple checks on the same values with
* security implications, so create snapshots with READ_ONCE() to
* ensure that these checks use the same values.
*/
- u32 tx = READ_ONCE(header->tx.count);
- u32 rx = READ_ONCE(header->rx.count);
+ u32 tx = tegra_ivc_header_read_field(map, tx.count);
+ u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* Perform an over-full check to prevent denial of service attacks
@@ -113,11 +118,10 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
return tx == rx;
}
-static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
- struct tegra_ivc_header *header)
+static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct iosys_map *map)
{
- u32 tx = READ_ONCE(header->tx.count);
- u32 rx = READ_ONCE(header->rx.count);
+ u32 tx = tegra_ivc_header_read_field(map, tx.count);
+ u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* Invalid cases where the counters indicate that the queue is over
@@ -126,11 +130,10 @@ static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
return tx - rx >= ivc->num_frames;
}
-static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
- struct tegra_ivc_header *header)
+static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct iosys_map *map)
{
- u32 tx = READ_ONCE(header->tx.count);
- u32 rx = READ_ONCE(header->rx.count);
+ u32 tx = tegra_ivc_header_read_field(map, tx.count);
+ u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* This function isn't expected to be used in scenarios where an
@@ -143,8 +146,9 @@ static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
{
- WRITE_ONCE(ivc->tx.channel->tx.count,
- READ_ONCE(ivc->tx.channel->tx.count) + 1);
+ unsigned int count = tegra_ivc_header_read_field(&ivc->tx.map, tx.count);
+
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.count, count + 1);
if (ivc->tx.position == ivc->num_frames - 1)
ivc->tx.position = 0;
@@ -154,8 +158,9 @@ static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
{
- WRITE_ONCE(ivc->rx.channel->rx.count,
- READ_ONCE(ivc->rx.channel->rx.count) + 1);
+ unsigned int count = tegra_ivc_header_read_field(&ivc->rx.map, rx.count);
+
+ tegra_ivc_header_write_field(&ivc->rx.map, rx.count, count + 1);
if (ivc->rx.position == ivc->num_frames - 1)
ivc->rx.position = 0;
@@ -166,6 +171,7 @@ static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
+ unsigned int state;
/*
* tx.channel->state is set locally, so it is not synchronized with
@@ -175,7 +181,8 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
* asynchronous transition of rx.channel->state to
* TEGRA_IVC_STATE_ACK is not allowed.
*/
- if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+ state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
+ if (state != TEGRA_IVC_STATE_ESTABLISHED)
return -ECONNRESET;
/*
@@ -185,12 +192,12 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
* Synchronization is only necessary when these pointers indicate
* empty or full.
*/
- if (!tegra_ivc_empty(ivc, ivc->rx.channel))
+ if (!tegra_ivc_empty(ivc, &ivc->rx.map))
return 0;
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
- if (tegra_ivc_empty(ivc, ivc->rx.channel))
+ if (tegra_ivc_empty(ivc, &ivc->rx.map))
return -ENOSPC;
return 0;
@@ -199,29 +206,34 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, rx.count);
+ unsigned int state;
- if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+ state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
+ if (state != TEGRA_IVC_STATE_ESTABLISHED)
return -ECONNRESET;
- if (!tegra_ivc_full(ivc, ivc->tx.channel))
+ if (!tegra_ivc_full(ivc, &ivc->tx.map))
return 0;
tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
- if (tegra_ivc_full(ivc, ivc->tx.channel))
+ if (tegra_ivc_full(ivc, &ivc->tx.map))
return -ENOSPC;
return 0;
}
-static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc,
- struct tegra_ivc_header *header,
- unsigned int frame)
+static int tegra_ivc_frame_virt(struct tegra_ivc *ivc, const struct iosys_map *header,
+ unsigned int frame, struct iosys_map *map)
{
+ size_t offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame;
+
if (WARN_ON(frame >= ivc->num_frames))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
- return (void *)(header + 1) + ivc->frame_size * frame;
+ *map = IOSYS_MAP_INIT_OFFSET(header, offset);
+
+ return 0;
}
static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc,
@@ -264,16 +276,16 @@ static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
}
/* directly peek at the next frame rx'ed */
-void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
+int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map)
{
int err;
if (WARN_ON(ivc == NULL))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
err = tegra_ivc_check_read(ivc);
if (err < 0)
- return ERR_PTR(err);
+ return err;
/*
* Order observation of ivc->rx.position potentially indicating new
@@ -284,7 +296,7 @@ void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0,
ivc->frame_size);
- return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position);
+ return tegra_ivc_frame_virt(ivc, &ivc->rx.map, ivc->rx.position, map);
}
EXPORT_SYMBOL(tegra_ivc_read_get_next_frame);
@@ -320,7 +332,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc)
*/
tegra_ivc_invalidate(ivc, ivc->rx.phys + tx);
- if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1)
+ if (tegra_ivc_available(ivc, &ivc->rx.map) == ivc->num_frames - 1)
ivc->notify(ivc, ivc->notify_data);
return 0;
@@ -328,15 +340,15 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc)
EXPORT_SYMBOL(tegra_ivc_read_advance);
/* directly poke at the next frame to be tx'ed */
-void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc)
+int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map)
{
int err;
err = tegra_ivc_check_write(ivc);
if (err < 0)
- return ERR_PTR(err);
+ return err;
- return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position);
+ return tegra_ivc_frame_virt(ivc, &ivc->tx.map, ivc->tx.position, map);
}
EXPORT_SYMBOL(tegra_ivc_write_get_next_frame);
@@ -376,7 +388,7 @@ int tegra_ivc_write_advance(struct tegra_ivc *ivc)
*/
tegra_ivc_invalidate(ivc, ivc->tx.phys + rx);
- if (tegra_ivc_available(ivc, ivc->tx.channel) == 1)
+ if (tegra_ivc_available(ivc, &ivc->tx.map) == 1)
ivc->notify(ivc, ivc->notify_data);
return 0;
@@ -387,7 +399,7 @@ void tegra_ivc_reset(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
- ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_SYNC);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
ivc->notify(ivc, ivc->notify_data);
}
@@ -416,13 +428,14 @@ EXPORT_SYMBOL(tegra_ivc_reset);
int tegra_ivc_notified(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
- enum tegra_ivc_state state;
+ enum tegra_ivc_state rx_state, tx_state;
/* Copy the receiver's state out of shared memory. */
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
- state = READ_ONCE(ivc->rx.channel->tx.state);
+ rx_state = tegra_ivc_header_read_field(&ivc->rx.map, tx.state);
+ tx_state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
- if (state == TEGRA_IVC_STATE_SYNC) {
+ if (rx_state == TEGRA_IVC_STATE_SYNC) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@@ -436,8 +449,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
- ivc->tx.channel->tx.count = 0;
- ivc->rx.channel->rx.count = 0;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0);
+ tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0);
ivc->tx.position = 0;
ivc->rx.position = 0;
@@ -452,7 +465,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* Move to ACK state. We have just cleared our counters, so it
* is now safe for the remote end to start using these values.
*/
- ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ACK);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@@ -460,8 +473,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
ivc->notify(ivc, ivc->notify_data);
- } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC &&
- state == TEGRA_IVC_STATE_ACK) {
+ } else if (tx_state == TEGRA_IVC_STATE_SYNC &&
+ rx_state == TEGRA_IVC_STATE_ACK) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@@ -475,8 +488,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
- ivc->tx.channel->tx.count = 0;
- ivc->rx.channel->rx.count = 0;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0);
+ tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0);
ivc->tx.position = 0;
ivc->rx.position = 0;
@@ -492,7 +505,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* already cleared its counters, so it is safe to start
* writing/reading on this channel.
*/
- ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@@ -500,7 +513,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
ivc->notify(ivc, ivc->notify_data);
- } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) {
+ } else if (tx_state == TEGRA_IVC_STATE_ACK) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@@ -516,7 +529,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* cleared its counters, so it is safe to start writing/reading
* on this channel.
*/
- ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
+ tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@@ -533,7 +546,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
}
- if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+ if (tx_state != TEGRA_IVC_STATE_ESTABLISHED)
return -EAGAIN;
return 0;
@@ -609,8 +622,29 @@ static int tegra_ivc_check_params(unsigned long rx, unsigned long tx,
return 0;
}
-int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
- dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
+static inline void iosys_map_copy(struct iosys_map *dst, const struct iosys_map *src)
+{
+ *dst = *src;
+}
+
+static inline unsigned long iosys_map_get_address(const struct iosys_map *map)
+{
+ if (map->is_iomem)
+ return (unsigned long)map->vaddr_iomem;
+
+ return (unsigned long)map->vaddr;
+}
+
+static inline void *iosys_map_get_vaddr(const struct iosys_map *map)
+{
+ if (WARN_ON(map->is_iomem))
+ return NULL;
+
+ return map->vaddr;
+}
+
+int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, const struct iosys_map *rx,
+ dma_addr_t rx_phys, const struct iosys_map *tx, dma_addr_t tx_phys,
unsigned int num_frames, size_t frame_size,
void (*notify)(struct tegra_ivc *ivc, void *data),
void *data)
@@ -628,7 +662,7 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
if (frame_size > INT_MAX)
return -E2BIG;
- err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx,
+ err = tegra_ivc_check_params(iosys_map_get_address(rx), iosys_map_get_address(tx),
num_frames, frame_size);
if (err < 0)
return err;
@@ -636,12 +670,12 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
queue_size = tegra_ivc_total_queue_size(num_frames * frame_size);
if (peer) {
- ivc->rx.phys = dma_map_single(peer, rx, queue_size,
+ ivc->rx.phys = dma_map_single(peer, iosys_map_get_vaddr(rx), queue_size,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(peer, ivc->rx.phys))
return -ENOMEM;
- ivc->tx.phys = dma_map_single(peer, tx, queue_size,
+ ivc->tx.phys = dma_map_single(peer, iosys_map_get_vaddr(tx), queue_size,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(peer, ivc->tx.phys)) {
dma_unmap_single(peer, ivc->rx.phys, queue_size,
@@ -653,8 +687,8 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
ivc->tx.phys = tx_phys;
}
- ivc->rx.channel = rx;
- ivc->tx.channel = tx;
+ iosys_map_copy(&ivc->rx.map, rx);
+ iosys_map_copy(&ivc->tx.map, tx);
ivc->peer = peer;
ivc->notify = notify;
ivc->notify_data = data;
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index ebc32bbd9b83..039d92a595ec 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -429,15 +429,14 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
* during noirq phase, so we must manually poll the completion.
*/
ret = read_poll_timeout_atomic(try_wait_for_completion, done_state,
- true, 1,
+ done_state, 1,
info->desc->max_rx_timeout_ms * 1000,
false, &xfer->done);
}
- if (ret == -ETIMEDOUT || !done_state) {
+ if (ret == -ETIMEDOUT)
dev_err(dev, "Mbox timedout in resp(caller: %pS)\n",
(void *)_RET_IP_);
- }
/*
* NOTE: we might prefer not to need the mailbox ticker to manage the
@@ -3096,7 +3095,7 @@ u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
free_bit = find_first_zero_bit(desc->res_map, res_count);
if (free_bit != res_count) {
- set_bit(free_bit, desc->res_map);
+ __set_bit(free_bit, desc->res_map);
raw_spin_unlock_irqrestore(&res->lock, flags);
if (desc->num && free_bit < desc->num)
@@ -3127,10 +3126,10 @@ void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
if (desc->num && desc->start <= id &&
(desc->start + desc->num) > id)
- clear_bit(id - desc->start, desc->res_map);
+ __clear_bit(id - desc->start, desc->res_map);
else if (desc->num_sec && desc->start_sec <= id &&
(desc->start_sec + desc->num_sec) > id)
- clear_bit(id - desc->start_sec, desc->res_map);
+ __clear_bit(id - desc->start_sec, desc->res_map);
}
raw_spin_unlock_irqrestore(&res->lock, flags);
}
@@ -3201,9 +3200,8 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
valid_set = true;
res_count = res->desc[i].num + res->desc[i].num_sec;
- res->desc[i].res_map =
- devm_kzalloc(dev, BITS_TO_LONGS(res_count) *
- sizeof(*res->desc[i].res_map), GFP_KERNEL);
+ res->desc[i].res_map = devm_bitmap_zalloc(dev, res_count,
+ GFP_KERNEL);
if (!res->desc[i].res_map)
return ERR_PTR(-ENOMEM);
}
@@ -3400,13 +3398,11 @@ static int ti_sci_probe(struct platform_device *pdev)
if (!minfo->xfer_block)
return -ENOMEM;
- minfo->xfer_alloc_table = devm_kcalloc(dev,
- BITS_TO_LONGS(desc->max_msgs),
- sizeof(unsigned long),
- GFP_KERNEL);
+ minfo->xfer_alloc_table = devm_bitmap_zalloc(dev,
+ desc->max_msgs,
+ GFP_KERNEL);
if (!minfo->xfer_alloc_table)
return -ENOMEM;
- bitmap_zero(minfo->xfer_alloc_table, desc->max_msgs);
/* Pre-initialize the buffer pointer to pre-allocated buffers */
for (i = 0, xfer = minfo->xfer_block; i < desc->max_msgs; i++, xfer++) {
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 6c416955da53..bbe0a7cabb75 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -246,7 +246,9 @@ config FPGA_MGR_VERSAL_FPGA
config FPGA_M10_BMC_SEC_UPDATE
tristate "Intel MAX10 BMC Secure Update driver"
- depends on MFD_INTEL_M10_BMC && FW_UPLOAD
+ depends on MFD_INTEL_M10_BMC
+ select FW_LOADER
+ select FW_UPLOAD
help
Secure update support for the Intel MAX10 board management
controller.
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index 5f93a53846aa..9912b7a6a4b9 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -659,7 +659,7 @@ static void sbefifo_collect_async_ffdc(struct sbefifo *sbefifo)
}
ffdc_iov.iov_base = ffdc;
ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
- iov_iter_kvec(&ffdc_iter, WRITE, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
+ iov_iter_kvec(&ffdc_iter, ITER_DEST, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
cmd[0] = cpu_to_be32(2);
cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
@@ -756,7 +756,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len,
rbytes = (*resp_len) * sizeof(__be32);
resp_iov.iov_base = response;
resp_iov.iov_len = rbytes;
- iov_iter_kvec(&resp_iter, WRITE, &resp_iov, 1, rbytes);
+ iov_iter_kvec(&resp_iter, ITER_DEST, &resp_iov, 1, rbytes);
/* Perform the command */
rc = mutex_lock_interruptible(&sbefifo->lock);
@@ -839,7 +839,7 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
/* Prepare iov iterator */
resp_iov.iov_base = buf;
resp_iov.iov_len = len;
- iov_iter_init(&resp_iter, WRITE, &resp_iov, 1, len);
+ iov_iter_init(&resp_iter, ITER_DEST, &resp_iov, 1, len);
/* Perform the command */
rc = mutex_lock_interruptible(&sbefifo->lock);
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index 14e6b3e64add..6f3ded619c8b 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -226,7 +226,10 @@ found:
ioport_unmap(gp.pm);
goto out;
}
+ return 0;
+
out:
+ pci_dev_put(pdev);
return err;
}
@@ -234,6 +237,7 @@ static void __exit amd_gpio_exit(void)
{
gpiochip_remove(&gp.chip);
ioport_unmap(gp.pm);
+ pci_dev_put(gp.pdev);
}
module_init(amd_gpio_init);
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 870910bb9dd3..200e43a6f4b4 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -610,6 +610,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank)
return -ENODATA;
pctldev = of_pinctrl_get(pctlnp);
+ of_node_put(pctlnp);
if (!pctldev)
return -ENODEV;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4756ea08894f..a70522aef355 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -526,12 +526,13 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
if (ret)
return ret;
+ /* From this point, the .release() function cleans up gpio_device */
+ gdev->dev.release = gpiodevice_release;
+
ret = gpiochip_sysfs_register(gdev);
if (ret)
goto err_remove_device;
- /* From this point, the .release() function cleans up gpio_device */
- gdev->dev.release = gpiodevice_release;
dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base,
gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic");
@@ -597,10 +598,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct fwnode_handle *fwnode = NULL;
struct gpio_device *gdev;
unsigned long flags;
- int base = gc->base;
unsigned int i;
+ u32 ngpios = 0;
+ int base = 0;
int ret = 0;
- u32 ngpios;
if (gc->fwnode)
fwnode = gc->fwnode;
@@ -647,17 +648,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
else
gdev->owner = THIS_MODULE;
- gdev->descs = kcalloc(gc->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
- if (!gdev->descs) {
- ret = -ENOMEM;
- goto err_free_dev_name;
- }
-
/*
* Try the device properties if the driver didn't supply the number
* of GPIO lines.
*/
- if (gc->ngpio == 0) {
+ ngpios = gc->ngpio;
+ if (ngpios == 0) {
ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios);
if (ret == -ENODATA)
/*
@@ -668,7 +664,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
*/
ngpios = 0;
else if (ret)
- goto err_free_descs;
+ goto err_free_dev_name;
gc->ngpio = ngpios;
}
@@ -676,13 +672,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (gc->ngpio == 0) {
chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
ret = -EINVAL;
- goto err_free_descs;
+ goto err_free_dev_name;
}
if (gc->ngpio > FASTPATH_NGPIO)
chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
gc->ngpio, FASTPATH_NGPIO);
+ gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL);
+ if (!gdev->descs) {
+ ret = -ENOMEM;
+ goto err_free_dev_name;
+ }
+
gdev->label = kstrdup_const(gc->label ?: "unknown", GFP_KERNEL);
if (!gdev->label) {
ret = -ENOMEM;
@@ -701,11 +703,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* it may be a pipe dream. It will not happen before we get rid
* of the sysfs interface anyways.
*/
+ base = gc->base;
if (base < 0) {
base = gpiochip_find_base(gc->ngpio);
if (base < 0) {
- ret = base;
spin_unlock_irqrestore(&gpio_lock, flags);
+ ret = base;
+ base = 0;
goto err_free_label;
}
/*
@@ -816,6 +820,11 @@ err_remove_of_chip:
err_free_gpiochip_mask:
gpiochip_remove_pin_ranges(gc);
gpiochip_free_valid_mask(gc);
+ if (gdev->dev.release) {
+ /* release() has been registered by gpiochip_setup_dev() */
+ put_device(&gdev->dev);
+ goto err_print_message;
+ }
err_remove_from_list:
spin_lock_irqsave(&gpio_lock, flags);
list_del(&gdev->list);
@@ -829,13 +838,14 @@ err_free_dev_name:
err_free_ida:
ida_free(&gpio_ida, gdev->id);
err_free_gdev:
+ kfree(gdev);
+err_print_message:
/* failures here can mean systems won't boot... */
if (ret != -EPROBE_DEFER) {
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
- gdev->base, gdev->base + gdev->ngpio - 1,
+ base, base + (int)ngpios - 1,
gc->label ? : "generic", ret);
}
- kfree(gdev);
return ret;
}
EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 34f5a092c99e..315cbdf61979 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -8,7 +8,6 @@
menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
- select DRM_NOMODESET
select DRM_PANEL_ORIENTATION_QUIRKS
select HDMI
select FB_CMDLINE
@@ -19,6 +18,7 @@ menuconfig DRM
# gallium uses SYS_kcmp for os_same_file_description() to de-duplicate
# device and dmabuf fd. Let's make sure that is available for our userspace.
select KCMP
+ select VIDEO_NOMODESET
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
@@ -233,64 +233,8 @@ source "drivers/gpu/drm/i2c/Kconfig"
source "drivers/gpu/drm/arm/Kconfig"
-config DRM_RADEON
- tristate "ATI Radeon"
- depends on DRM && PCI && MMU
- depends on AGP || !AGP
- select FW_LOADER
- select DRM_DISPLAY_DP_HELPER
- select DRM_DISPLAY_HELPER
- select DRM_KMS_HELPER
- select DRM_TTM
- select DRM_TTM_HELPER
- select POWER_SUPPLY
- select HWMON
- select BACKLIGHT_CLASS_DEVICE
- select INTERVAL_TREE
- # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
- # ACPI_VIDEO's dependencies must also be selected.
- select INPUT if ACPI
- select ACPI_VIDEO if ACPI
- # On x86 ACPI_VIDEO also needs ACPI_WMI
- select X86_PLATFORM_DEVICES if ACPI && X86
- select ACPI_WMI if ACPI && X86
- help
- Choose this option if you have an ATI Radeon graphics card. There
- are both PCI and AGP versions. You don't need to choose this to
- run the Radeon in plain VGA mode.
-
- If M is selected, the module will be called radeon.
-
source "drivers/gpu/drm/radeon/Kconfig"
-config DRM_AMDGPU
- tristate "AMD GPU"
- depends on DRM && PCI && MMU
- select FW_LOADER
- select DRM_DISPLAY_DP_HELPER
- select DRM_DISPLAY_HDMI_HELPER
- select DRM_DISPLAY_HELPER
- select DRM_KMS_HELPER
- select DRM_SCHED
- select DRM_TTM
- select DRM_TTM_HELPER
- select POWER_SUPPLY
- select HWMON
- select BACKLIGHT_CLASS_DEVICE
- select INTERVAL_TREE
- select DRM_BUDDY
- # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
- # ACPI_VIDEO's dependencies must also be selected.
- select INPUT if ACPI
- select ACPI_VIDEO if ACPI
- # On x86 ACPI_VIDEO also needs ACPI_WMI
- select X86_PLATFORM_DEVICES if ACPI && X86
- select ACPI_WMI if ACPI && X86
- help
- Choose this option if you have a recent AMD Radeon graphics card.
-
- If M is selected, the module will be called amdgpu.
-
source "drivers/gpu/drm/amd/amdgpu/Kconfig"
source "drivers/gpu/drm/nouveau/Kconfig"
@@ -514,11 +458,6 @@ config DRM_EXPORT_FOR_TESTS
config DRM_PANEL_ORIENTATION_QUIRKS
tristate
-# Separate option because nomodeset parameter is global and expected built-in
-config DRM_NOMODESET
- bool
- default n
-
config DRM_LIB_RANDOM
bool
default n
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0b283e46f28b..cc637343d87b 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -5,35 +5,74 @@
CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE
-drm-y := drm_aperture.o drm_auth.o drm_cache.o \
- drm_file.o drm_gem.o drm_ioctl.o \
- drm_drv.o \
- drm_sysfs.o drm_mm.o \
- drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o drm_displayid.o \
- drm_trace_points.o drm_prime.o \
- drm_vma_manager.o \
- drm_modeset_lock.o drm_atomic.o drm_bridge.o \
- drm_framebuffer.o drm_connector.o drm_blend.o \
- drm_encoder.o drm_mode_object.o drm_property.o \
- drm_plane.o drm_color_mgmt.o drm_print.o \
- drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
- drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
- drm_client_modeset.o drm_atomic_uapi.o \
- drm_managed.o drm_vblank_work.o
-drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \
- drm_hashtab.o drm_irq.o drm_legacy_misc.o drm_lock.o \
- drm_memory.o drm_scatter.o drm_vm.o
+drm-y := \
+ drm_aperture.o \
+ drm_atomic.o \
+ drm_atomic_uapi.o \
+ drm_auth.o \
+ drm_blend.o \
+ drm_bridge.o \
+ drm_cache.o \
+ drm_client.o \
+ drm_client_modeset.o \
+ drm_color_mgmt.o \
+ drm_connector.o \
+ drm_crtc.o \
+ drm_displayid.o \
+ drm_drv.o \
+ drm_dumb_buffers.o \
+ drm_edid.o \
+ drm_encoder.o \
+ drm_file.o \
+ drm_fourcc.o \
+ drm_framebuffer.o \
+ drm_gem.o \
+ drm_ioctl.o \
+ drm_lease.o \
+ drm_managed.o \
+ drm_mm.o \
+ drm_mode_config.o \
+ drm_mode_object.o \
+ drm_modes.o \
+ drm_modeset_lock.o \
+ drm_plane.o \
+ drm_prime.o \
+ drm_print.o \
+ drm_property.o \
+ drm_syncobj.o \
+ drm_sysfs.o \
+ drm_trace_points.o \
+ drm_vblank.o \
+ drm_vblank_work.o \
+ drm_vma_manager.o \
+ drm_writeback.o
+drm-$(CONFIG_DRM_LEGACY) += \
+ drm_agpsupport.o \
+ drm_bufs.o \
+ drm_context.o \
+ drm_dma.o \
+ drm_hashtab.o \
+ drm_irq.o \
+ drm_legacy_misc.o \
+ drm_lock.o \
+ drm_memory.o \
+ drm_scatter.o \
+ drm_vm.o
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_PCI) += drm_pci.o
-drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
+drm-$(CONFIG_DEBUG_FS) += \
+ drm_debugfs.o \
+ drm_debugfs_crc.o
drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
-drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o
+drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
+ drm_privacy_screen.o \
+ drm_privacy_screen_x86.o
+drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
obj-$(CONFIG_DRM) += drm.o
-obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
#
@@ -59,18 +98,28 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
# Modesetting helpers
#
-drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
- drm_encoder_slave.o drm_flip_work.o \
- drm_probe_helper.o \
- drm_plane_helper.o drm_atomic_helper.o \
- drm_kms_helper_common.o \
- drm_simple_kms_helper.o drm_modeset_helper.o \
- drm_gem_atomic_helper.o \
- drm_gem_framebuffer_helper.o \
- drm_atomic_state_helper.o drm_damage_helper.o \
- drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
+drm_kms_helper-y := \
+ drm_atomic_helper.o \
+ drm_atomic_state_helper.o \
+ drm_bridge_connector.o \
+ drm_crtc_helper.o \
+ drm_damage_helper.o \
+ drm_encoder_slave.o \
+ drm_flip_work.o \
+ drm_format_helper.o \
+ drm_gem_atomic_helper.o \
+ drm_gem_framebuffer_helper.o \
+ drm_kms_helper_common.o \
+ drm_modeset_helper.o \
+ drm_plane_helper.o \
+ drm_probe_helper.o \
+ drm_rect.o \
+ drm_self_refresh_helper.o \
+ drm_simple_kms_helper.o
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
-drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
+drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += \
+ drm_fbdev_generic.o \
+ drm_fb_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
#
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 7777d55275de..5fcd510f1abb 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -1,4 +1,33 @@
# SPDX-License-Identifier: MIT
+
+config DRM_AMDGPU
+ tristate "AMD GPU"
+ depends on DRM && PCI && MMU
+ select FW_LOADER
+ select DRM_DISPLAY_DP_HELPER
+ select DRM_DISPLAY_HDMI_HELPER
+ select DRM_DISPLAY_HELPER
+ select DRM_KMS_HELPER
+ select DRM_SCHED
+ select DRM_TTM
+ select DRM_TTM_HELPER
+ select POWER_SUPPLY
+ select HWMON
+ select BACKLIGHT_CLASS_DEVICE
+ select INTERVAL_TREE
+ select DRM_BUDDY
+ # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
+ # ACPI_VIDEO's dependencies must also be selected.
+ select INPUT if ACPI
+ select ACPI_VIDEO if ACPI
+ # On x86 ACPI_VIDEO also needs ACPI_WMI
+ select X86_PLATFORM_DEVICES if ACPI && X86
+ select ACPI_WMI if ACPI && X86
+ help
+ Choose this option if you have a recent AMD Radeon graphics card.
+
+ If M is selected, the module will be called amdgpu.
+
config DRM_AMDGPU_SI
bool "Enable amdgpu support for SI parts"
depends on DRM_AMDGPU
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index 6ad39cf71bdd..798d0e9a60b7 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -58,7 +58,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \
amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \
amdgpu_fw_attestation.o amdgpu_securedisplay.o \
- amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o
+ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \
+ amdgpu_ring_mux.o
amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o
@@ -250,7 +251,7 @@ endif
amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o
amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
-amdgpu-$(CONFIG_HMM_MIRROR) += amdgpu_mn.o
+amdgpu-$(CONFIG_HMM_MIRROR) += amdgpu_hmm.o
include $(FULL_AMD_PATH)/pm/Makefile
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 8639a4f9c6e8..6b74df446694 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -82,7 +82,6 @@
#include "amdgpu_vce.h"
#include "amdgpu_vcn.h"
#include "amdgpu_jpeg.h"
-#include "amdgpu_mn.h"
#include "amdgpu_gmc.h"
#include "amdgpu_gfx.h"
#include "amdgpu_sdma.h"
@@ -219,10 +218,12 @@ extern int amdgpu_use_xgmi_p2p;
extern int sched_policy;
extern bool debug_evictions;
extern bool no_system_mem_limit;
+extern int halt_if_hws_hang;
#else
static const int __maybe_unused sched_policy = KFD_SCHED_POLICY_HWS;
static const bool __maybe_unused debug_evictions; /* = false */
static const bool __maybe_unused no_system_mem_limit;
+static const int __maybe_unused halt_if_hws_hang;
#endif
#ifdef CONFIG_HSA_AMD_P2P
extern bool pcie_p2p;
@@ -675,7 +676,7 @@ enum amd_hw_ip_block_type {
MAX_HWIP
};
-#define HWIP_MAX_INSTANCE 11
+#define HWIP_MAX_INSTANCE 28
#define HW_ID_MAX 300
#define IP_VERSION(mj, mn, rv) (((mj) << 16) | ((mn) << 8) | (rv))
@@ -1063,6 +1064,7 @@ struct amdgpu_device {
struct work_struct reset_work;
bool job_hang;
+ bool dc_enabled;
};
static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev)
@@ -1120,6 +1122,8 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type);
bool amdgpu_device_has_dc_support(struct amdgpu_device *adev);
+void amdgpu_device_set_sriov_virtual_display(struct amdgpu_device *adev);
+
int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
struct amdgpu_reset_context *reset_context);
@@ -1293,6 +1297,7 @@ void amdgpu_device_pcie_port_wreg(struct amdgpu_device *adev,
u32 reg, u32 v);
struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev,
struct dma_fence *gang);
+bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev);
/* atpx handler */
#if defined(CONFIG_VGA_SWITCHEROO)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index b14800ac179e..57b5e11446c6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -847,7 +847,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif;
if (atif->notifications.brightness_change) {
- if (amdgpu_device_has_dc_support(adev)) {
+ if (adev->dc_enabled) {
#if defined(CONFIG_DRM_AMD_DC)
struct amdgpu_display_manager *dm = &adev->dm;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 5d9a34601a1a..f99d4873bf22 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -195,7 +195,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
}
adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev,
- adev_to_drm(adev), &gpu_resources);
+ &gpu_resources);
amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size;
@@ -673,7 +673,7 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev,
goto err;
}
- ret = amdgpu_job_alloc(adev, 1, &job, NULL);
+ ret = amdgpu_job_alloc(adev, NULL, NULL, NULL, 1, &job);
if (ret)
goto err;
@@ -760,9 +760,7 @@ bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev)
void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bool reset)
{
- struct ras_err_data err_data = {0, 0, 0, NULL};
-
- amdgpu_umc_poison_handler(adev, &err_data, reset);
+ amdgpu_umc_poison_handler(adev, reset);
}
bool amdgpu_amdkfd_ras_query_utcl2_poison_status(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 647220a8762d..f50e3ba4d7a5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -353,7 +353,6 @@ int kgd2kfd_init(void);
void kgd2kfd_exit(void);
struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf);
bool kgd2kfd_device_init(struct kfd_dev *kfd,
- struct drm_device *ddev,
const struct kgd2kfd_shared_resources *gpu_resources);
void kgd2kfd_device_exit(struct kfd_dev *kfd);
void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm);
@@ -381,7 +380,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
}
static inline
-bool kgd2kfd_device_init(struct kfd_dev *kfd, struct drm_device *ddev,
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
const struct kgd2kfd_shared_resources *gpu_resources)
{
return false;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
index c8935d718207..4485bb29bec9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
@@ -41,5 +41,6 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = {
.get_atc_vmid_pasid_mapping_info =
kgd_gfx_v9_get_atc_vmid_pasid_mapping_info,
.set_vm_context_page_table_base = kgd_gfx_v9_set_vm_context_page_table_base,
+ .get_cu_occupancy = kgd_gfx_v9_get_cu_occupancy,
.program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
index 81e3b528bbc9..e92b93557c13 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
@@ -787,7 +787,7 @@ void kgd_gfx_v9_get_cu_occupancy(struct amdgpu_device *adev, int pasid,
for (se_idx = 0; se_idx < se_cnt; se_idx++) {
for (sh_idx = 0; sh_idx < sh_cnt; sh_idx++) {
- gfx_v9_0_select_se_sh(adev, se_idx, sh_idx, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, se_idx, sh_idx, 0xffffffff);
queue_map = RREG32_SOC15(GC, 0, mmSPI_CSQ_WF_ACTIVE_STATUS);
/*
@@ -820,7 +820,7 @@ void kgd_gfx_v9_get_cu_occupancy(struct amdgpu_device *adev, int pasid,
}
}
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
soc15_grbm_select(adev, 0, 0, 0, 0);
unlock_spi_csq_mutexes(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 84f44f7e4111..8782916e64a0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -29,6 +29,7 @@
#include "amdgpu_object.h"
#include "amdgpu_gem.h"
#include "amdgpu_vm.h"
+#include "amdgpu_hmm.h"
#include "amdgpu_amdkfd.h"
#include "amdgpu_dma_buf.h"
#include <uapi/linux/kfd_ioctl.h>
@@ -171,9 +172,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
(kfd_mem_limit.ttm_mem_used + ttm_mem_needed >
kfd_mem_limit.max_ttm_mem_limit) ||
(adev && adev->kfd.vram_used + vram_needed >
- adev->gmc.real_vram_size -
- atomic64_read(&adev->vram_pin_size) -
- reserved_for_pt)) {
+ adev->gmc.real_vram_size - reserved_for_pt)) {
ret = -ENOMEM;
goto release;
}
@@ -405,63 +404,15 @@ static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync)
static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem)
{
- struct amdgpu_device *bo_adev = amdgpu_ttm_adev(mem->bo->tbo.bdev);
- bool coherent = mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_COHERENT;
- bool uncached = mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_UNCACHED;
- uint32_t mapping_flags;
- uint64_t pte_flags;
- bool snoop = false;
+ uint32_t mapping_flags = AMDGPU_VM_PAGE_READABLE |
+ AMDGPU_VM_MTYPE_DEFAULT;
- mapping_flags = AMDGPU_VM_PAGE_READABLE;
if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE)
mapping_flags |= AMDGPU_VM_PAGE_WRITEABLE;
if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE)
mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE;
- switch (adev->asic_type) {
- case CHIP_ARCTURUS:
- case CHIP_ALDEBARAN:
- if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) {
- if (bo_adev == adev) {
- if (uncached)
- mapping_flags |= AMDGPU_VM_MTYPE_UC;
- else if (coherent)
- mapping_flags |= AMDGPU_VM_MTYPE_CC;
- else
- mapping_flags |= AMDGPU_VM_MTYPE_RW;
- if (adev->asic_type == CHIP_ALDEBARAN &&
- adev->gmc.xgmi.connected_to_cpu)
- snoop = true;
- } else {
- if (uncached || coherent)
- mapping_flags |= AMDGPU_VM_MTYPE_UC;
- else
- mapping_flags |= AMDGPU_VM_MTYPE_NC;
- if (amdgpu_xgmi_same_hive(adev, bo_adev))
- snoop = true;
- }
- } else {
- if (uncached || coherent)
- mapping_flags |= AMDGPU_VM_MTYPE_UC;
- else
- mapping_flags |= AMDGPU_VM_MTYPE_NC;
- snoop = true;
- }
- break;
- default:
- if (uncached || coherent)
- mapping_flags |= AMDGPU_VM_MTYPE_UC;
- else
- mapping_flags |= AMDGPU_VM_MTYPE_NC;
-
- if (!(mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM))
- snoop = true;
- }
-
- pte_flags = amdgpu_gem_va_map_flags(adev, mapping_flags);
- pte_flags |= snoop ? AMDGPU_PTE_SNOOPED : 0;
-
- return pte_flags;
+ return amdgpu_gem_va_map_flags(adev, mapping_flags);
}
/**
@@ -988,6 +939,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr,
struct amdkfd_process_info *process_info = mem->process_info;
struct amdgpu_bo *bo = mem->bo;
struct ttm_operation_ctx ctx = { true, false };
+ struct hmm_range *range;
int ret = 0;
mutex_lock(&process_info->lock);
@@ -998,7 +950,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr,
goto out;
}
- ret = amdgpu_mn_register(bo, user_addr);
+ ret = amdgpu_hmm_register(bo, user_addr);
if (ret) {
pr_err("%s: Failed to register MMU notifier: %d\n",
__func__, ret);
@@ -1017,7 +969,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr,
return 0;
}
- ret = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages);
+ ret = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages, &range);
if (ret) {
pr_err("%s: Failed to get user pages: %d\n", __func__, ret);
goto unregister_out;
@@ -1035,10 +987,10 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr,
amdgpu_bo_unreserve(bo);
release_out:
- amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
+ amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, range);
unregister_out:
if (ret)
- amdgpu_mn_unregister(bo);
+ amdgpu_hmm_unregister(bo);
out:
mutex_unlock(&process_info->lock);
return ret;
@@ -1673,6 +1625,11 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
}
}
+ if (flags & KFD_IOC_ALLOC_MEM_FLAGS_COHERENT)
+ alloc_flags |= AMDGPU_GEM_CREATE_COHERENT;
+ if (flags & KFD_IOC_ALLOC_MEM_FLAGS_UNCACHED)
+ alloc_flags |= AMDGPU_GEM_CREATE_UNCACHED;
+
*mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL);
if (!*mem) {
ret = -ENOMEM;
@@ -1817,7 +1774,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
mutex_unlock(&process_info->lock);
/* No more MMU notifiers */
- amdgpu_mn_unregister(mem->bo);
+ amdgpu_hmm_unregister(mem->bo);
ret = reserve_bo_and_cond_vms(mem, NULL, BO_VM_ALL, &ctx);
if (unlikely(ret))
@@ -1907,16 +1864,6 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
*/
mutex_lock(&mem->process_info->lock);
- /* Lock mmap-sem. If we find an invalid userptr BO, we can be
- * sure that the MMU notifier is no longer running
- * concurrently and the queues are actually stopped
- */
- if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) {
- mmap_write_lock(current->mm);
- is_invalid_userptr = atomic_read(&mem->invalid);
- mmap_write_unlock(current->mm);
- }
-
mutex_lock(&mem->lock);
domain = mem->domain;
@@ -2257,7 +2204,7 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct amdgpu_device *adev,
ret = drm_vma_node_allow(&obj->vma_node, drm_priv);
if (ret) {
- kfree(mem);
+ kfree(*mem);
return ret;
}
@@ -2372,6 +2319,8 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
/* Go through userptr_inval_list and update any invalid user_pages */
list_for_each_entry(mem, &process_info->userptr_inval_list,
validate_list.head) {
+ struct hmm_range *range;
+
invalid = atomic_read(&mem->invalid);
if (!invalid)
/* BO hasn't been invalidated since the last
@@ -2382,7 +2331,8 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
bo = mem->bo;
/* Get updated user pages */
- ret = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages);
+ ret = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages,
+ &range);
if (ret) {
pr_debug("Failed %d to get user pages\n", ret);
@@ -2401,7 +2351,7 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
* FIXME: Cannot ignore the return code, must hold
* notifier_lock
*/
- amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
+ amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, range);
}
/* Mark the BO as valid unless it was invalidated
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
index b81b77a9efa6..ac6fe0ae4609 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
@@ -101,39 +101,101 @@ void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev)
}
}
+static int amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device *adev,
+ struct vram_usagebyfirmware_v2_1 *fw_usage, int *usage_bytes)
+{
+ u32 start_addr, fw_size, drv_size;
+
+ start_addr = le32_to_cpu(fw_usage->start_address_in_kb);
+ fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
+ drv_size = le16_to_cpu(fw_usage->used_by_driver_in_kb);
+
+ DRM_DEBUG("atom firmware v2_1 requested %08x %dkb fw %dkb drv\n",
+ start_addr,
+ fw_size,
+ drv_size);
+
+ if ((start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==
+ (u32)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
+ ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
+ /* Firmware request VRAM reservation for SR-IOV */
+ adev->mman.fw_vram_usage_start_offset = (start_addr &
+ (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
+ adev->mman.fw_vram_usage_size = fw_size << 10;
+ /* Use the default scratch size */
+ *usage_bytes = 0;
+ } else {
+ *usage_bytes = drv_size << 10;
+ }
+ return 0;
+}
+
+static int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev,
+ struct vram_usagebyfirmware_v2_2 *fw_usage, int *usage_bytes)
+{
+ u32 fw_start_addr, fw_size, drv_start_addr, drv_size;
+
+ fw_start_addr = le32_to_cpu(fw_usage->fw_region_start_address_in_kb);
+ fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
+
+ drv_start_addr = le32_to_cpu(fw_usage->driver_region0_start_address_in_kb);
+ drv_size = le32_to_cpu(fw_usage->used_by_driver_region0_in_kb);
+
+ DRM_DEBUG("atom requested fw start at %08x %dkb and drv start at %08x %dkb\n",
+ fw_start_addr,
+ fw_size,
+ drv_start_addr,
+ drv_size);
+
+ if (amdgpu_sriov_vf(adev) &&
+ ((fw_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
+ ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
+ /* Firmware request VRAM reservation for SR-IOV */
+ adev->mman.fw_vram_usage_start_offset = (fw_start_addr &
+ (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
+ adev->mman.fw_vram_usage_size = fw_size << 10;
+ }
+
+ if (amdgpu_sriov_vf(adev) &&
+ ((drv_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
+ ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
+ /* driver request VRAM reservation for SR-IOV */
+ adev->mman.drv_vram_usage_start_offset = (drv_start_addr &
+ (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
+ adev->mman.drv_vram_usage_size = drv_size << 10;
+ }
+
+ *usage_bytes = 0;
+ return 0;
+}
+
int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev)
{
struct atom_context *ctx = adev->mode_info.atom_context;
int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
vram_usagebyfirmware);
- struct vram_usagebyfirmware_v2_1 *firmware_usage;
- uint32_t start_addr, size;
- uint16_t data_offset;
+ struct vram_usagebyfirmware_v2_1 *fw_usage_v2_1;
+ struct vram_usagebyfirmware_v2_2 *fw_usage_v2_2;
+ u16 data_offset;
+ u8 frev, crev;
int usage_bytes = 0;
- if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
- firmware_usage = (struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset);
- DRM_DEBUG("atom firmware requested %08x %dkb fw %dkb drv\n",
- le32_to_cpu(firmware_usage->start_address_in_kb),
- le16_to_cpu(firmware_usage->used_by_firmware_in_kb),
- le16_to_cpu(firmware_usage->used_by_driver_in_kb));
-
- start_addr = le32_to_cpu(firmware_usage->start_address_in_kb);
- size = le16_to_cpu(firmware_usage->used_by_firmware_in_kb);
-
- if ((uint32_t)(start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==
- (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
- ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
- /* Firmware request VRAM reservation for SR-IOV */
- adev->mman.fw_vram_usage_start_offset = (start_addr &
- (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
- adev->mman.fw_vram_usage_size = size << 10;
- /* Use the default scratch size */
- usage_bytes = 0;
- } else {
- usage_bytes = le16_to_cpu(firmware_usage->used_by_driver_in_kb) << 10;
+ if (amdgpu_atom_parse_data_header(ctx, index, NULL, &frev, &crev, &data_offset)) {
+ if (frev == 2 && crev == 1) {
+ fw_usage_v2_1 =
+ (struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset);
+ amdgpu_atomfirmware_allocate_fb_v2_1(adev,
+ fw_usage_v2_1,
+ &usage_bytes);
+ } else if (frev >= 2 && crev >= 2) {
+ fw_usage_v2_2 =
+ (struct vram_usagebyfirmware_v2_2 *)(ctx->bios + data_offset);
+ amdgpu_atomfirmware_allocate_fb_v2_2(adev,
+ fw_usage_v2_2,
+ &usage_bytes);
}
}
+
ctx->scratch_size_bytes = 0;
if (usage_bytes == 0)
usage_bytes = 20 * 1024;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index e363f56c72af..30c28a69e847 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -317,6 +317,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
if (!found)
return false;
+ pci_dev_put(pdev);
adev->bios = kmalloc(size, GFP_KERNEL);
if (!adev->bios) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 2168163aad2d..252a876b0725 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -209,6 +209,7 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list,
list_add_tail(&e->tv.head, &bucket[priority]);
e->user_pages = NULL;
+ e->range = NULL;
}
/* Connect the sorted buckets in the output list. */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
index 9caea1688fc3..e4d78491bcc7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
@@ -26,6 +26,8 @@
#include <drm/ttm/ttm_execbuf_util.h>
#include <drm/amdgpu_drm.h>
+struct hmm_range;
+
struct amdgpu_device;
struct amdgpu_bo;
struct amdgpu_bo_va;
@@ -36,6 +38,7 @@ struct amdgpu_bo_list_entry {
struct amdgpu_bo_va *bo_va;
uint32_t priority;
struct page **user_pages;
+ struct hmm_range *range;
bool user_invalidated;
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 491d4846fc02..2ebbc6382a06 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -26,7 +26,6 @@
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
@@ -328,7 +327,6 @@ static void amdgpu_connector_free_edid(struct drm_connector *connector)
kfree(amdgpu_connector->edid);
amdgpu_connector->edid = NULL;
- drm_connector_update_edid_property(connector, NULL);
}
static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 1bbd39b3b0fc..8516c814bc9b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -109,6 +109,7 @@ static int amdgpu_cs_p1_ib(struct amdgpu_cs_parser *p,
return r;
++(num_ibs[r]);
+ p->gang_leader_idx = r;
return 0;
}
@@ -287,20 +288,18 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
}
}
- if (!p->gang_size)
- return -EINVAL;
+ if (!p->gang_size) {
+ ret = -EINVAL;
+ goto free_partial_kdata;
+ }
for (i = 0; i < p->gang_size; ++i) {
- ret = amdgpu_job_alloc(p->adev, num_ibs[i], &p->jobs[i], vm);
- if (ret)
- goto free_all_kdata;
-
- ret = drm_sched_job_init(&p->jobs[i]->base, p->entities[i],
- &fpriv->vm);
+ ret = amdgpu_job_alloc(p->adev, vm, p->entities[i], vm,
+ num_ibs[i], &p->jobs[i]);
if (ret)
goto free_all_kdata;
}
- p->gang_leader = p->jobs[p->gang_size - 1];
+ p->gang_leader = p->jobs[p->gang_leader_idx];
if (p->ctx->vram_lost_counter != p->gang_leader->vram_lost_counter) {
ret = -ECANCELED;
@@ -430,7 +429,7 @@ static int amdgpu_cs_p2_dependencies(struct amdgpu_cs_parser *p,
dma_fence_put(old);
}
- r = amdgpu_sync_fence(&p->gang_leader->sync, fence);
+ r = amdgpu_sync_fence(&p->sync, fence);
dma_fence_put(fence);
if (r)
return r;
@@ -452,9 +451,20 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p,
return r;
}
- r = amdgpu_sync_fence(&p->gang_leader->sync, fence);
- dma_fence_put(fence);
+ r = amdgpu_sync_fence(&p->sync, fence);
+ if (r)
+ goto error;
+
+ /*
+ * When we have an explicit dependency it might be necessary to insert a
+ * pipeline sync to make sure that all caches etc are flushed and the
+ * next job actually sees the results from the previous one.
+ */
+ if (fence->context == p->gang_leader->base.entity->fence_context)
+ r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence);
+error:
+ dma_fence_put(fence);
return r;
}
@@ -910,7 +920,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
goto out_free_user_pages;
}
- r = amdgpu_ttm_tt_get_user_pages(bo, e->user_pages);
+ r = amdgpu_ttm_tt_get_user_pages(bo, e->user_pages, &e->range);
if (r) {
kvfree(e->user_pages);
e->user_pages = NULL;
@@ -988,10 +998,12 @@ out_free_user_pages:
if (!e->user_pages)
continue;
- amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
+ amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, e->range);
kvfree(e->user_pages);
e->user_pages = NULL;
+ e->range = NULL;
}
+ mutex_unlock(&p->bo_list->bo_list_mutex);
return r;
}
@@ -1101,7 +1113,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = amdgpu_sync_fence(&job->sync, fpriv->prt_va->last_pt_update);
+ r = amdgpu_sync_fence(&p->sync, fpriv->prt_va->last_pt_update);
if (r)
return r;
@@ -1112,7 +1124,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update);
+ r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update);
if (r)
return r;
}
@@ -1131,7 +1143,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update);
+ r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update);
if (r)
return r;
}
@@ -1144,7 +1156,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = amdgpu_sync_fence(&job->sync, vm->last_update);
+ r = amdgpu_sync_fence(&p->sync, vm->last_update);
if (r)
return r;
@@ -1176,7 +1188,6 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
{
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
- struct amdgpu_job *leader = p->gang_leader;
struct amdgpu_bo_list_entry *e;
unsigned int i;
int r;
@@ -1188,22 +1199,21 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
sync_mode = amdgpu_bo_explicit_sync(bo) ?
AMDGPU_SYNC_EXPLICIT : AMDGPU_SYNC_NE_OWNER;
- r = amdgpu_sync_resv(p->adev, &leader->sync, resv, sync_mode,
+ r = amdgpu_sync_resv(p->adev, &p->sync, resv, sync_mode,
&fpriv->vm);
if (r)
return r;
}
- for (i = 0; i < p->gang_size - 1; ++i) {
- r = amdgpu_sync_clone(&leader->sync, &p->jobs[i]->sync);
+ for (i = 0; i < p->gang_size; ++i) {
+ r = amdgpu_sync_push_to_job(&p->sync, p->jobs[i]);
if (r)
return r;
}
- r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_size - 1]);
+ r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]);
if (r && r != -ERESTARTSYS)
DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n");
-
return r;
}
@@ -1237,11 +1247,14 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
for (i = 0; i < p->gang_size; ++i)
drm_sched_job_arm(&p->jobs[i]->base);
- for (i = 0; i < (p->gang_size - 1); ++i) {
+ for (i = 0; i < p->gang_size; ++i) {
struct dma_fence *fence;
+ if (p->jobs[i] == leader)
+ continue;
+
fence = &p->jobs[i]->base.s_fence->scheduled;
- r = amdgpu_sync_fence(&leader->sync, fence);
+ r = drm_sched_job_add_dependency(&leader->base, fence);
if (r)
goto error_cleanup;
}
@@ -1264,7 +1277,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
- r |= !amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
+ r |= !amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, e->range);
+ e->range = NULL;
}
if (r) {
r = -EAGAIN;
@@ -1275,7 +1289,10 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
list_for_each_entry(e, &p->validated, tv.head) {
/* Everybody except for the gang leader uses READ */
- for (i = 0; i < (p->gang_size - 1); ++i) {
+ for (i = 0; i < p->gang_size; ++i) {
+ if (p->jobs[i] == leader)
+ continue;
+
dma_resv_add_fence(e->tv.bo->base.resv,
&p->jobs[i]->base.s_fence->finished,
DMA_RESV_USAGE_READ);
@@ -1285,7 +1302,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
e->tv.num_shared = 0;
}
- seq = amdgpu_ctx_add_fence(p->ctx, p->entities[p->gang_size - 1],
+ seq = amdgpu_ctx_add_fence(p->ctx, p->entities[p->gang_leader_idx],
p->fence);
amdgpu_cs_post_dependencies(p);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
index cbaa19b2b8a3..113f39510a72 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
@@ -54,6 +54,7 @@ struct amdgpu_cs_parser {
/* scheduler job objects */
unsigned int gang_size;
+ unsigned int gang_leader_idx;
struct drm_sched_entity *entities[AMDGPU_CS_GANG_SIZE];
struct amdgpu_job *jobs[AMDGPU_CS_GANG_SIZE];
struct amdgpu_job *gang_leader;
@@ -75,6 +76,8 @@ struct amdgpu_cs_parser {
unsigned num_post_deps;
struct amdgpu_cs_post_dep *post_deps;
+
+ struct amdgpu_sync sync;
};
int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index de61a85c4b02..0f16d3c09309 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -1969,7 +1969,7 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
amdgpu_ta_if_debugfs_init(adev);
#if defined(CONFIG_DRM_AMD_DC)
- if (amdgpu_device_has_dc_support(adev))
+ if (adev->dc_enabled)
dtn_debugfs_init(adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 64510898eedd..cfa411c12072 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -37,6 +37,7 @@
#include <linux/pci-p2pdma.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include <linux/vgaarb.h>
@@ -1568,7 +1569,7 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
* @pdev: pci dev pointer
* @state: vga_switcheroo state
*
- * Callback for the switcheroo driver. Suspends or resumes the
+ * Callback for the switcheroo driver. Suspends or resumes
* the asics before or after it is powered up using ACPI methods.
*/
static void amdgpu_switcheroo_set_state(struct pci_dev *pdev,
@@ -1915,6 +1916,16 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
}
}
+void amdgpu_device_set_sriov_virtual_display(struct amdgpu_device *adev)
+{
+ if (amdgpu_sriov_vf(adev) && !adev->enable_virtual_display) {
+ adev->mode_info.num_crtc = 1;
+ adev->enable_virtual_display = true;
+ DRM_INFO("virtual_display:%d, num_crtc:%d\n",
+ adev->enable_virtual_display, adev->mode_info.num_crtc);
+ }
+}
+
/**
* amdgpu_device_parse_gpu_info_fw - parse gpu info firmware
*
@@ -2397,7 +2408,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
adev->ip_blocks[i].status.hw = true;
/* right after GMC hw init, we create CSA */
- if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
+ if (amdgpu_mcbp) {
r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
AMDGPU_GEM_DOMAIN_VRAM,
AMDGPU_CSA_SIZE);
@@ -2462,6 +2473,11 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
if (!amdgpu_sriov_vf(adev)) {
struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev);
+ if (WARN_ON(!hive)) {
+ r = -ENOENT;
+ goto init_failed;
+ }
+
if (!hive->reset_domain ||
!amdgpu_reset_get_reset_domain(hive->reset_domain)) {
r = -ENOENT;
@@ -3347,8 +3363,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
*/
bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
{
- if (amdgpu_sriov_vf(adev) ||
- adev->enable_virtual_display ||
+ if (adev->enable_virtual_display ||
(adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK))
return false;
@@ -4171,21 +4186,15 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
r = amdgpu_device_ip_resume(adev);
- /* no matter what r is, always need to properly release full GPU */
- if (amdgpu_sriov_vf(adev)) {
- amdgpu_virt_init_data_exchange(adev);
- amdgpu_virt_release_full_gpu(adev, true);
- }
-
if (r) {
dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r);
- return r;
+ goto exit;
}
amdgpu_fence_driver_hw_init(adev);
r = amdgpu_device_ip_late_init(adev);
if (r)
- return r;
+ goto exit;
queue_delayed_work(system_wq, &adev->delayed_init_work,
msecs_to_jiffies(AMDGPU_RESUME_MS));
@@ -4193,9 +4202,18 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
if (!adev->in_s0ix) {
r = amdgpu_amdkfd_resume(adev, adev->in_runpm);
if (r)
- return r;
+ goto exit;
+ }
+
+exit:
+ if (amdgpu_sriov_vf(adev)) {
+ amdgpu_virt_init_data_exchange(adev);
+ amdgpu_virt_release_full_gpu(adev, true);
}
+ if (r)
+ return r;
+
/* Make sure IB tests flushed */
flush_delayed_work(&adev->delayed_init_work);
@@ -4213,25 +4231,27 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
amdgpu_ras_resume(adev);
- /*
- * Most of the connector probing functions try to acquire runtime pm
- * refs to ensure that the GPU is powered on when connector polling is
- * performed. Since we're calling this from a runtime PM callback,
- * trying to acquire rpm refs will cause us to deadlock.
- *
- * Since we're guaranteed to be holding the rpm lock, it's safe to
- * temporarily disable the rpm helpers so this doesn't deadlock us.
- */
+ if (adev->mode_info.num_crtc) {
+ /*
+ * Most of the connector probing functions try to acquire runtime pm
+ * refs to ensure that the GPU is powered on when connector polling is
+ * performed. Since we're calling this from a runtime PM callback,
+ * trying to acquire rpm refs will cause us to deadlock.
+ *
+ * Since we're guaranteed to be holding the rpm lock, it's safe to
+ * temporarily disable the rpm helpers so this doesn't deadlock us.
+ */
#ifdef CONFIG_PM
- dev->dev->power.disable_depth++;
+ dev->dev->power.disable_depth++;
#endif
- if (!amdgpu_device_has_dc_support(adev))
- drm_helper_hpd_irq_event(dev);
- else
- drm_kms_helper_hotplug_event(dev);
+ if (!adev->dc_enabled)
+ drm_helper_hpd_irq_event(dev);
+ else
+ drm_kms_helper_hotplug_event(dev);
#ifdef CONFIG_PM
- dev->dev->power.disable_depth--;
+ dev->dev->power.disable_depth--;
#endif
+ }
adev->in_suspend = false;
if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D0))
@@ -4580,6 +4600,10 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
if (amdgpu_gpu_recovery == 0)
goto disabled;
+ /* Skip soft reset check in fatal error mode */
+ if (!amdgpu_ras_is_poison_mode_supported(adev))
+ return true;
+
if (!amdgpu_device_ip_check_soft_reset(adev)) {
dev_info(adev->dev,"Timeout, but no hardware hang detected.\n");
return false;
@@ -5027,6 +5051,8 @@ static void amdgpu_device_resume_display_audio(struct amdgpu_device *adev)
pm_runtime_enable(&(p->dev));
pm_runtime_resume(&(p->dev));
}
+
+ pci_dev_put(p);
}
static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev)
@@ -5065,6 +5091,7 @@ static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev)
if (expires < ktime_get_mono_fast_ns()) {
dev_warn(adev->dev, "failed to suspend display audio\n");
+ pci_dev_put(p);
/* TODO: abort the succeeding gpu reset? */
return -ETIMEDOUT;
}
@@ -5072,97 +5099,10 @@ static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev)
pm_runtime_disable(&(p->dev));
+ pci_dev_put(p);
return 0;
}
-static void amdgpu_device_recheck_guilty_jobs(
- struct amdgpu_device *adev, struct list_head *device_list_handle,
- struct amdgpu_reset_context *reset_context)
-{
- int i, r = 0;
-
- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
- struct amdgpu_ring *ring = adev->rings[i];
- int ret = 0;
- struct drm_sched_job *s_job;
-
- if (!ring || !ring->sched.thread)
- continue;
-
- s_job = list_first_entry_or_null(&ring->sched.pending_list,
- struct drm_sched_job, list);
- if (s_job == NULL)
- continue;
-
- /* clear job's guilty and depend the folowing step to decide the real one */
- drm_sched_reset_karma(s_job);
- drm_sched_resubmit_jobs_ext(&ring->sched, 1);
-
- if (!s_job->s_fence->parent) {
- DRM_WARN("Failed to get a HW fence for job!");
- continue;
- }
-
- ret = dma_fence_wait_timeout(s_job->s_fence->parent, false, ring->sched.timeout);
- if (ret == 0) { /* timeout */
- DRM_ERROR("Found the real bad job! ring:%s, job_id:%llx\n",
- ring->sched.name, s_job->id);
-
-
- amdgpu_fence_driver_isr_toggle(adev, true);
-
- /* Clear this failed job from fence array */
- amdgpu_fence_driver_clear_job_fences(ring);
-
- amdgpu_fence_driver_isr_toggle(adev, false);
-
- /* Since the job won't signal and we go for
- * another resubmit drop this parent pointer
- */
- dma_fence_put(s_job->s_fence->parent);
- s_job->s_fence->parent = NULL;
-
- /* set guilty */
- drm_sched_increase_karma(s_job);
- amdgpu_reset_prepare_hwcontext(adev, reset_context);
-retry:
- /* do hw reset */
- if (amdgpu_sriov_vf(adev)) {
- amdgpu_virt_fini_data_exchange(adev);
- r = amdgpu_device_reset_sriov(adev, false);
- if (r)
- adev->asic_reset_res = r;
- } else {
- clear_bit(AMDGPU_SKIP_HW_RESET,
- &reset_context->flags);
- r = amdgpu_do_asic_reset(device_list_handle,
- reset_context);
- if (r && r == -EAGAIN)
- goto retry;
- }
-
- /*
- * add reset counter so that the following
- * resubmitted job could flush vmid
- */
- atomic_inc(&adev->gpu_reset_counter);
- continue;
- }
-
- /* got the hw fence, signal finished fence */
- atomic_dec(ring->sched.score);
- dma_fence_get(&s_job->s_fence->finished);
- dma_fence_signal(&s_job->s_fence->finished);
- dma_fence_put(&s_job->s_fence->finished);
-
- /* remove node from list and free the job */
- spin_lock(&ring->sched.job_list_lock);
- list_del_init(&s_job->list);
- spin_unlock(&ring->sched.job_list_lock);
- ring->sched.ops->free_job(s_job);
- }
-}
-
static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
@@ -5183,7 +5123,6 @@ static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev)
}
-
/**
* amdgpu_device_gpu_recover - reset the asic and recover scheduler
*
@@ -5206,7 +5145,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
int i, r = 0;
bool need_emergency_restart = false;
bool audio_suspended = false;
- int tmp_vram_lost_counter;
bool gpu_reset_for_dev_remove = false;
gpu_reset_for_dev_remove =
@@ -5352,7 +5290,6 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */
amdgpu_device_stop_pending_resets(tmp_adev);
}
- tmp_vram_lost_counter = atomic_read(&((adev)->vram_lost_counter));
/* Actual ASIC resets if needed.*/
/* Host driver will handle XGMI hive reset for SRIOV */
if (amdgpu_sriov_vf(adev)) {
@@ -5377,29 +5314,13 @@ skip_hw_reset:
/* Post ASIC reset for all devs .*/
list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
- /*
- * Sometimes a later bad compute job can block a good gfx job as gfx
- * and compute ring share internal GC HW mutually. We add an additional
- * guilty jobs recheck step to find the real guilty job, it synchronously
- * submits and pends for the first job being signaled. If it gets timeout,
- * we identify it as a real guilty job.
- */
- if (amdgpu_gpu_recovery == 2 &&
- !(tmp_vram_lost_counter < atomic_read(&adev->vram_lost_counter)))
- amdgpu_device_recheck_guilty_jobs(
- tmp_adev, device_list_handle, reset_context);
-
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
struct amdgpu_ring *ring = tmp_adev->rings[i];
if (!ring || !ring->sched.thread)
continue;
- /* No point to resubmit jobs if we didn't HW reset*/
- if (!tmp_adev->asic_reset_res && !job_signaled)
- drm_sched_resubmit_jobs(&ring->sched);
-
- drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res);
+ drm_sched_start(&ring->sched, true);
}
if (adev->enable_mes && adev->ip_versions[GC_HWIP][0] != IP_VERSION(11, 0, 3))
@@ -5441,6 +5362,8 @@ skip_sched_resume:
amdgpu_device_resume_display_audio(tmp_adev);
amdgpu_device_unset_mp1_state(tmp_adev);
+
+ amdgpu_ras_set_error_query_ready(tmp_adev, true);
}
recover_end:
@@ -5852,8 +5775,6 @@ void amdgpu_pci_resume(struct pci_dev *pdev)
if (!ring || !ring->sched.thread)
continue;
-
- drm_sched_resubmit_jobs(&ring->sched);
drm_sched_start(&ring->sched, true);
}
@@ -6044,3 +5965,44 @@ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev,
dma_fence_put(old);
return NULL;
}
+
+bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev)
+{
+ switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_SI
+ case CHIP_HAINAN:
+#endif
+ case CHIP_TOPAZ:
+ /* chips with no display hardware */
+ return false;
+#ifdef CONFIG_DRM_AMDGPU_SI
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ case CHIP_OLAND:
+#endif
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ case CHIP_BONAIRE:
+ case CHIP_HAWAII:
+ case CHIP_KAVERI:
+ case CHIP_KABINI:
+ case CHIP_MULLINS:
+#endif
+ case CHIP_TONGA:
+ case CHIP_FIJI:
+ case CHIP_POLARIS10:
+ case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
+ case CHIP_VEGAM:
+ case CHIP_CARRIZO:
+ case CHIP_STONEY:
+ /* chips with display hardware */
+ return true;
+ default:
+ /* IP discovery */
+ if (!adev->ip_versions[DCE_HWIP][0] ||
+ (adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK))
+ return false;
+ return true;
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 3993e6134914..1bbd56029a4f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -305,8 +305,13 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
goto out;
}
- if (!amdgpu_discovery_verify_binary_signature(adev->mman.discovery_bin)) {
- dev_warn(adev->dev, "get invalid ip discovery binary signature from vram\n");
+ if (!amdgpu_discovery_verify_binary_signature(adev->mman.discovery_bin) || amdgpu_discovery == 2) {
+ /* ignore the discovery binary from vram if discovery=2 in kernel module parameter */
+ if (amdgpu_discovery == 2)
+ dev_info(adev->dev,"force read ip discovery binary from file");
+ else
+ dev_warn(adev->dev, "get invalid ip discovery binary signature from vram\n");
+
/* retry read ip discovery binary from file */
r = amdgpu_discovery_read_binary_from_file(adev, adev->mman.discovery_bin);
if (r) {
@@ -1507,6 +1512,7 @@ static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
amdgpu_device_ip_block_add(adev, &soc21_common_ip_block);
break;
default:
@@ -1551,6 +1557,7 @@ static int amdgpu_discovery_set_gmc_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
amdgpu_device_ip_block_add(adev, &gmc_v11_0_ip_block);
break;
default:
@@ -1636,6 +1643,7 @@ static int amdgpu_discovery_set_psp_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(13, 0, 7):
case IP_VERSION(13, 0, 8):
case IP_VERSION(13, 0, 10):
+ case IP_VERSION(13, 0, 11):
amdgpu_device_ip_block_add(adev, &psp_v13_0_ip_block);
break;
case IP_VERSION(13, 0, 4):
@@ -1686,6 +1694,7 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(13, 0, 7):
case IP_VERSION(13, 0, 8):
case IP_VERSION(13, 0, 10):
+ case IP_VERSION(13, 0, 11):
amdgpu_device_ip_block_add(adev, &smu_v13_0_ip_block);
break;
default:
@@ -1697,9 +1706,17 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev)
return 0;
}
+#if defined(CONFIG_DRM_AMD_DC)
+static void amdgpu_discovery_set_sriov_display(struct amdgpu_device *adev)
+{
+ amdgpu_device_set_sriov_virtual_display(adev);
+ amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block);
+}
+#endif
+
static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev)
{
- if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) {
+ if (adev->enable_virtual_display) {
amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block);
return 0;
}
@@ -1727,7 +1744,10 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(3, 1, 6):
case IP_VERSION(3, 2, 0):
case IP_VERSION(3, 2, 1):
- amdgpu_device_ip_block_add(adev, &dm_ip_block);
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_discovery_set_sriov_display(adev);
+ else
+ amdgpu_device_ip_block_add(adev, &dm_ip_block);
break;
default:
dev_err(adev->dev,
@@ -1740,7 +1760,10 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
case IP_VERSION(12, 1, 0):
- amdgpu_device_ip_block_add(adev, &dm_ip_block);
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_discovery_set_sriov_display(adev);
+ else
+ amdgpu_device_ip_block_add(adev, &dm_ip_block);
break;
default:
dev_err(adev->dev,
@@ -1785,6 +1808,7 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
amdgpu_device_ip_block_add(adev, &gfx_v11_0_ip_block);
break;
default:
@@ -1948,6 +1972,7 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
amdgpu_device_ip_block_add(adev, &mes_v11_0_ip_block);
adev->enable_mes = true;
adev->enable_mes_kiq = true;
@@ -2161,6 +2186,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
break;
case IP_VERSION(10, 3, 1):
adev->family = AMDGPU_FAMILY_VGH;
+ adev->apu_flags |= AMD_APU_IS_VANGOGH;
break;
case IP_VERSION(10, 3, 3):
adev->family = AMDGPU_FAMILY_YC;
@@ -2177,6 +2203,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
adev->family = AMDGPU_FAMILY_GC_11_0_0;
break;
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
adev->family = AMDGPU_FAMILY_GC_11_0_1;
break;
default:
@@ -2194,6 +2221,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(10, 3, 6):
case IP_VERSION(10, 3, 7):
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
adev->flags |= AMD_IS_APU;
break;
default:
@@ -2250,6 +2278,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
adev->nbio.hdp_flush_reg = &nbio_v4_3_hdp_flush_reg;
break;
case IP_VERSION(7, 7, 0):
+ case IP_VERSION(7, 7, 1):
adev->nbio.funcs = &nbio_v7_7_funcs;
adev->nbio.hdp_flush_reg = &nbio_v7_7_hdp_flush_reg;
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 1a06b8d724f3..b22471b3bd63 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -39,11 +39,46 @@
#include <linux/pm_runtime.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
-#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
+/**
+ * amdgpu_display_hotplug_work_func - work handler for display hotplug event
+ *
+ * @work: work struct pointer
+ *
+ * This is the hotplug event work handler (all ASICs).
+ * The work gets scheduled from the IRQ handler if there
+ * was a hotplug interrupt. It walks through the connector table
+ * and calls hotplug handler for each connector. After this, it sends
+ * a DRM hotplug event to alert userspace.
+ *
+ * This design approach is required in order to defer hotplug event handling
+ * from the IRQ handler to a work handler because hotplug handler has to use
+ * mutexes which cannot be locked in an IRQ handler (since &mutex_lock may
+ * sleep).
+ */
+void amdgpu_display_hotplug_work_func(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+ hotplug_work);
+ struct drm_device *dev = adev_to_drm(adev);
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+ struct drm_connector_list_iter iter;
+
+ mutex_lock(&mode_config->mutex);
+ drm_connector_list_iter_begin(dev, &iter);
+ drm_for_each_connector_iter(connector, &iter)
+ amdgpu_connector_hotplug(connector);
+ drm_connector_list_iter_end(&iter);
+ mutex_unlock(&mode_config->mutex);
+ /* Just fire off a uevent and let userspace tell us what to do */
+ drm_helper_hpd_irq_event(dev);
+}
+
static int amdgpu_display_framebuffer_init(struct drm_device *dev,
struct amdgpu_framebuffer *rfb,
const struct drm_mode_fb_cmd2 *mode_cmd,
@@ -514,7 +549,7 @@ uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
*/
if ((bo_flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) &&
amdgpu_bo_support_uswc(bo_flags) &&
- amdgpu_device_asic_has_dc_support(adev->asic_type) &&
+ adev->dc_enabled &&
adev->mode_info.gpu_vm_support)
domain |= AMDGPU_GEM_DOMAIN_GTT;
#endif
@@ -1214,7 +1249,6 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
const struct drm_mode_config_funcs amdgpu_mode_funcs = {
.fb_create = amdgpu_display_user_framebuffer_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
};
static const struct drm_prop_enum_list amdgpu_underscan_enum_list[] =
@@ -1281,7 +1315,7 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
"dither",
amdgpu_dither_enum_list, sz);
- if (amdgpu_device_has_dc_support(adev)) {
+ if (adev->dc_enabled) {
adev->mode_info.abm_level_property =
drm_property_create_range(adev_to_drm(adev), 0,
"abm level", 0, 4);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
index 560352f7c317..9d19940f73c8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
@@ -35,6 +35,7 @@
#define amdgpu_display_add_encoder(adev, e, s, c) (adev)->mode_info.funcs->add_encoder((adev), (e), (s), (c))
#define amdgpu_display_add_connector(adev, ci, sd, ct, ib, coi, h, r) (adev)->mode_info.funcs->add_connector((adev), (ci), (sd), (ct), (ib), (coi), (h), (r))
+void amdgpu_display_hotplug_work_func(struct work_struct *work);
void amdgpu_display_update_priority(struct amdgpu_device *adev);
uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
uint64_t bo_flags);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index 7bd8e33b14be..271e30e34d93 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -328,7 +328,9 @@ amdgpu_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
if (dma_buf->ops == &amdgpu_dmabuf_ops) {
struct amdgpu_bo *other = gem_to_amdgpu_bo(dma_buf->priv);
- flags |= other->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+ flags |= other->flags & (AMDGPU_GEM_CREATE_CPU_GTT_USWC |
+ AMDGPU_GEM_CREATE_COHERENT |
+ AMDGPU_GEM_CREATE_UNCACHED);
}
ret = amdgpu_gem_object_create(adev, dma_buf->size, PAGE_SIZE,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index bf2d50c8c92a..7383272c6a3a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -25,6 +25,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_aperture.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem.h>
#include <drm/drm_vblank.h>
#include <drm/drm_managed.h>
@@ -230,17 +231,18 @@ module_param_named(vis_vramlimit, amdgpu_vis_vram_limit, int, 0444);
/**
* DOC: gartsize (uint)
- * Restrict the size of GART in Mib (32, 64, etc.) for testing. The default is -1 (The size depends on asic).
+ * Restrict the size of GART (for kernel use) in Mib (32, 64, etc.) for testing.
+ * The default is -1 (The size depends on asic).
*/
-MODULE_PARM_DESC(gartsize, "Size of GART to setup in megabytes (32, 64, etc., -1=auto)");
+MODULE_PARM_DESC(gartsize, "Size of kernel GART to setup in megabytes (32, 64, etc., -1=auto)");
module_param_named(gartsize, amdgpu_gart_size, uint, 0600);
/**
* DOC: gttsize (int)
- * Restrict the size of GTT domain in MiB for testing. The default is -1 (It's VRAM size if 3GB < VRAM < 3/4 RAM,
- * otherwise 3/4 RAM size).
+ * Restrict the size of GTT domain (for userspace use) in MiB for testing.
+ * The default is -1 (Use 1/2 RAM, minimum value is 3GB).
*/
-MODULE_PARM_DESC(gttsize, "Size of the GTT domain in megabytes (-1 = auto)");
+MODULE_PARM_DESC(gttsize, "Size of the GTT userspace domain in megabytes (-1 = auto)");
module_param_named(gttsize, amdgpu_gtt_size, int, 0600);
/**
@@ -533,7 +535,7 @@ module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444);
* DOC: gpu_recovery (int)
* Set to enable GPU recovery mechanism (1 = enable, 0 = disable). The default is -1 (auto, disabled except SRIOV).
*/
-MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (2 = advanced tdr mode, 1 = enable, 0 = disable, -1 = auto)");
+MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)");
module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444);
/**
@@ -1924,9 +1926,6 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x73AF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
{0x1002, 0x73BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
- /* Van Gogh */
- {0x1002, 0x163F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VANGOGH|AMD_IS_APU},
-
/* Yellow Carp */
{0x1002, 0x164D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_YELLOW_CARP|AMD_IS_APU},
{0x1002, 0x1681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_YELLOW_CARP|AMD_IS_APU},
@@ -2471,7 +2470,7 @@ static int amdgpu_runtime_idle_check_display(struct device *dev)
if (ret)
return ret;
- if (amdgpu_device_has_dc_support(adev)) {
+ if (adev->dc_enabled) {
struct drm_crtc *crtc;
drm_for_each_crtc(crtc, drm_dev) {
@@ -2572,6 +2571,8 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
amdgpu_device_baco_enter(drm_dev);
}
+ dev_dbg(&pdev->dev, "asic/device is runtime suspended\n");
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
index 4d9eb0137f8c..7d2a908438e9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
@@ -79,13 +79,15 @@
* That is, for an I2C EEPROM driver everything is controlled by
* the "eeprom_addr".
*
+ * See also top of amdgpu_ras_eeprom.c.
+ *
* P.S. If you need to write, lock and read the Identification Page,
* (M24M02-DR device only, which we do not use), change the "7" to
* "0xF" in the macro below, and let the client set bit 20 to 1 in
* "eeprom_addr", and set A10 to 0 to write into it, and A10 and A1 to
* 1 to lock it permanently.
*/
-#define MAKE_I2C_ADDR(_aa) ((0xA << 3) | (((_aa) >> 16) & 7))
+#define MAKE_I2C_ADDR(_aa) ((0xA << 3) | (((_aa) >> 16) & 0xF))
static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr,
u8 *eeprom_buf, u16 buf_size, bool read)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index d0d99ed607dd..00444203220d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -55,6 +55,7 @@ struct amdgpu_fence {
/* RB, DMA, etc. */
struct amdgpu_ring *ring;
+ ktime_t start_timestamp;
};
static struct kmem_cache *amdgpu_fence_slab;
@@ -199,6 +200,8 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
}
}
+ to_amdgpu_fence(fence)->start_timestamp = ktime_get();
+
/* This function can't be called concurrently anyway, otherwise
* emitting the fence would mess up the hardware ring buffer.
*/
@@ -407,6 +410,57 @@ unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
}
/**
+ * amdgpu_fence_last_unsignaled_time_us - the time fence emitted until now
+ * @ring: ring the fence is associated with
+ *
+ * Find the earliest fence unsignaled until now, calculate the time delta
+ * between the time fence emitted and now.
+ */
+u64 amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring *ring)
+{
+ struct amdgpu_fence_driver *drv = &ring->fence_drv;
+ struct dma_fence *fence;
+ uint32_t last_seq, sync_seq;
+
+ last_seq = atomic_read(&ring->fence_drv.last_seq);
+ sync_seq = READ_ONCE(ring->fence_drv.sync_seq);
+ if (last_seq == sync_seq)
+ return 0;
+
+ ++last_seq;
+ last_seq &= drv->num_fences_mask;
+ fence = drv->fences[last_seq];
+ if (!fence)
+ return 0;
+
+ return ktime_us_delta(ktime_get(),
+ to_amdgpu_fence(fence)->start_timestamp);
+}
+
+/**
+ * amdgpu_fence_update_start_timestamp - update the timestamp of the fence
+ * @ring: ring the fence is associated with
+ * @seq: the fence seq number to update.
+ * @timestamp: the start timestamp to update.
+ *
+ * The function called at the time the fence and related ib is about to
+ * resubmit to gpu in MCBP scenario. Thus we do not consider race condition
+ * with amdgpu_fence_process to modify the same fence.
+ */
+void amdgpu_fence_update_start_timestamp(struct amdgpu_ring *ring, uint32_t seq, ktime_t timestamp)
+{
+ struct amdgpu_fence_driver *drv = &ring->fence_drv;
+ struct dma_fence *fence;
+
+ seq &= drv->num_fences_mask;
+ fence = drv->fences[seq];
+ if (!fence)
+ return;
+
+ to_amdgpu_fence(fence)->start_timestamp = timestamp;
+}
+
+/**
* amdgpu_fence_driver_start_ring - make the fence driver
* ready for use on the requested ring.
*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
index e325150879df..2c38ac7bc643 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
@@ -29,9 +29,10 @@
#include "amdgpu_fru_eeprom.h"
#include "amdgpu_eeprom.h"
-#define FRU_EEPROM_MADDR 0x60000
+#define FRU_EEPROM_MADDR_6 0x60000
+#define FRU_EEPROM_MADDR_8 0x80000
-static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
+static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr)
{
/* Only server cards have the FRU EEPROM
* TODO: See if we can figure this out dynamically instead of
@@ -45,6 +46,11 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev))
return false;
+ /* The default I2C EEPROM address of the FRU.
+ */
+ if (fru_addr)
+ *fru_addr = FRU_EEPROM_MADDR_8;
+
/* VBIOS is of the format ###-DXXXYYYY-##. For SKU identification,
* we can use just the "DXXX" portion. If there were more models, we
* could convert the 3 characters to a hex integer and use a switch
@@ -57,21 +63,29 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
if (strnstr(atom_ctx->vbios_version, "D161",
sizeof(atom_ctx->vbios_version)) ||
strnstr(atom_ctx->vbios_version, "D163",
- sizeof(atom_ctx->vbios_version)))
+ sizeof(atom_ctx->vbios_version))) {
+ *fru_addr = FRU_EEPROM_MADDR_6;
return true;
- else
+ } else {
return false;
+ }
case CHIP_ALDEBARAN:
- /* All Aldebaran SKUs have the FRU */
+ /* All Aldebaran SKUs have an FRU */
+ if (!strnstr(atom_ctx->vbios_version, "D673",
+ sizeof(atom_ctx->vbios_version)))
+ if (fru_addr)
+ *fru_addr = FRU_EEPROM_MADDR_6;
return true;
case CHIP_SIENNA_CICHLID:
if (strnstr(atom_ctx->vbios_version, "D603",
- sizeof(atom_ctx->vbios_version))) {
+ sizeof(atom_ctx->vbios_version))) {
if (strnstr(atom_ctx->vbios_version, "D603GLXE",
- sizeof(atom_ctx->vbios_version)))
+ sizeof(atom_ctx->vbios_version))) {
return false;
- else
+ } else {
+ *fru_addr = FRU_EEPROM_MADDR_6;
return true;
+ }
} else {
return false;
}
@@ -80,41 +94,14 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
}
}
-static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr,
- unsigned char *buf, size_t buf_size)
-{
- int ret;
- u8 size;
-
- ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr, buf, 1);
- if (ret < 1) {
- DRM_WARN("FRU: Failed to get size field");
- return ret;
- }
-
- /* The size returned by the i2c requires subtraction of 0xC0 since the
- * size apparently always reports as 0xC0+actual size.
- */
- size = buf[0] & 0x3F;
- size = min_t(size_t, size, buf_size);
-
- ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr + 1,
- buf, size);
- if (ret < 1) {
- DRM_WARN("FRU: Failed to get data field");
- return ret;
- }
-
- return size;
-}
-
int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
{
- unsigned char buf[AMDGPU_PRODUCT_NAME_LEN];
- u32 addrptr;
+ unsigned char buf[8], *pia;
+ u32 addr, fru_addr;
int size, len;
+ u8 csum;
- if (!is_fru_eeprom_supported(adev))
+ if (!is_fru_eeprom_supported(adev, &fru_addr))
return 0;
/* If algo exists, it means that the i2c_adapter's initialized */
@@ -123,88 +110,102 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
return -ENODEV;
}
- /* There's a lot of repetition here. This is due to the FRU having
- * variable-length fields. To get the information, we have to find the
- * size of each field, and then keep reading along and reading along
- * until we get all of the data that we want. We use addrptr to track
- * the address as we go
- */
-
- /* The first fields are all of size 1-byte, from 0-7 are offsets that
- * contain information that isn't useful to us.
- * Bytes 8-a are all 1-byte and refer to the size of the entire struct,
- * and the language field, so just start from 0xb, manufacturer size
- */
- addrptr = FRU_EEPROM_MADDR + 0xb;
- size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
- if (size < 1) {
- DRM_ERROR("Failed to read FRU Manufacturer, ret:%d", size);
- return -EINVAL;
+ /* Read the IPMI Common header */
+ len = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, fru_addr, buf,
+ sizeof(buf));
+ if (len != 8) {
+ DRM_ERROR("Couldn't read the IPMI Common Header: %d", len);
+ return len < 0 ? len : -EIO;
}
- /* Increment the addrptr by the size of the field, and 1 due to the
- * size field being 1 byte. This pattern continues below.
- */
- addrptr += size + 1;
- size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
- if (size < 1) {
- DRM_ERROR("Failed to read FRU product name, ret:%d", size);
- return -EINVAL;
+ if (buf[0] != 1) {
+ DRM_ERROR("Bad IPMI Common Header version: 0x%02x", buf[0]);
+ return -EIO;
}
- len = size;
- if (len >= AMDGPU_PRODUCT_NAME_LEN) {
- DRM_WARN("FRU Product Name is larger than %d characters. This is likely a mistake",
- AMDGPU_PRODUCT_NAME_LEN);
- len = AMDGPU_PRODUCT_NAME_LEN - 1;
- }
- memcpy(adev->product_name, buf, len);
- adev->product_name[len] = '\0';
-
- addrptr += size + 1;
- size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
- if (size < 1) {
- DRM_ERROR("Failed to read FRU product number, ret:%d", size);
- return -EINVAL;
+ for (csum = 0; len > 0; len--)
+ csum += buf[len - 1];
+ if (csum) {
+ DRM_ERROR("Bad IPMI Common Header checksum: 0x%02x", csum);
+ return -EIO;
}
- len = size;
- /* Product number should only be 16 characters. Any more,
- * and something could be wrong. Cap it at 16 to be safe
- */
- if (len >= sizeof(adev->product_number)) {
- DRM_WARN("FRU Product Number is larger than 16 characters. This is likely a mistake");
- len = sizeof(adev->product_number) - 1;
- }
- memcpy(adev->product_number, buf, len);
- adev->product_number[len] = '\0';
+ /* Get the offset to the Product Info Area (PIA). */
+ addr = buf[4] * 8;
+ if (!addr)
+ return 0;
- addrptr += size + 1;
- size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
+ /* Get the absolute address to the PIA. */
+ addr += fru_addr;
- if (size < 1) {
- DRM_ERROR("Failed to read FRU product version, ret:%d", size);
- return -EINVAL;
+ /* Read the header of the PIA. */
+ len = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addr, buf, 3);
+ if (len != 3) {
+ DRM_ERROR("Couldn't read the Product Info Area header: %d", len);
+ return len < 0 ? len : -EIO;
}
- addrptr += size + 1;
- size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
+ if (buf[0] != 1) {
+ DRM_ERROR("Bad IPMI Product Info Area version: 0x%02x", buf[0]);
+ return -EIO;
+ }
- if (size < 1) {
- DRM_ERROR("Failed to read FRU serial number, ret:%d", size);
- return -EINVAL;
+ size = buf[1] * 8;
+ pia = kzalloc(size, GFP_KERNEL);
+ if (!pia)
+ return -ENOMEM;
+
+ /* Read the whole PIA. */
+ len = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addr, pia, size);
+ if (len != size) {
+ kfree(pia);
+ DRM_ERROR("Couldn't read the Product Info Area: %d", len);
+ return len < 0 ? len : -EIO;
}
- len = size;
- /* Serial number should only be 16 characters. Any more,
- * and something could be wrong. Cap it at 16 to be safe
- */
- if (len >= sizeof(adev->serial)) {
- DRM_WARN("FRU Serial Number is larger than 16 characters. This is likely a mistake");
- len = sizeof(adev->serial) - 1;
+ for (csum = 0; size > 0; size--)
+ csum += pia[size - 1];
+ if (csum) {
+ DRM_ERROR("Bad Product Info Area checksum: 0x%02x", csum);
+ return -EIO;
}
- memcpy(adev->serial, buf, len);
- adev->serial[len] = '\0';
+ /* Now extract useful information from the PIA.
+ *
+ * Skip the Manufacturer Name at [3] and go directly to
+ * the Product Name field.
+ */
+ addr = 3 + 1 + (pia[3] & 0x3F);
+ if (addr + 1 >= len)
+ goto Out;
+ memcpy(adev->product_name, pia + addr + 1,
+ min_t(size_t,
+ sizeof(adev->product_name),
+ pia[addr] & 0x3F));
+ adev->product_name[sizeof(adev->product_name) - 1] = '\0';
+
+ /* Go to the Product Part/Model Number field. */
+ addr += 1 + (pia[addr] & 0x3F);
+ if (addr + 1 >= len)
+ goto Out;
+ memcpy(adev->product_number, pia + addr + 1,
+ min_t(size_t,
+ sizeof(adev->product_number),
+ pia[addr] & 0x3F));
+ adev->product_number[sizeof(adev->product_number) - 1] = '\0';
+
+ /* Go to the Product Version field. */
+ addr += 1 + (pia[addr] & 0x3F);
+
+ /* Go to the Product Serial Number field. */
+ addr += 1 + (pia[addr] & 0x3F);
+ if (addr + 1 >= len)
+ goto Out;
+ memcpy(adev->serial, pia + addr + 1, min_t(size_t,
+ sizeof(adev->serial),
+ pia[addr] & 0x3F));
+ adev->serial[sizeof(adev->serial) - 1] = '\0';
+Out:
+ kfree(pia);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 8ef31d687ef3..62e98f1ad770 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -38,6 +38,7 @@
#include "amdgpu.h"
#include "amdgpu_display.h"
#include "amdgpu_dma_buf.h"
+#include "amdgpu_hmm.h"
#include "amdgpu_xgmi.h"
static const struct drm_gem_object_funcs amdgpu_gem_object_funcs;
@@ -87,7 +88,7 @@ static void amdgpu_gem_object_free(struct drm_gem_object *gobj)
struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj);
if (robj) {
- amdgpu_mn_unregister(robj);
+ amdgpu_hmm_unregister(robj);
amdgpu_bo_unref(&robj);
}
}
@@ -112,7 +113,7 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
bp.resv = resv;
bp.preferred_domain = initial_domain;
bp.flags = flags;
- bp.domain = initial_domain;
+ bp.domain = initial_domain | AMDGPU_GEM_DOMAIN_CPU;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
r = amdgpu_bo_create_user(adev, &bp, &ubo);
@@ -331,20 +332,10 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
}
initial_domain = (u32)(0xffffffff & args->in.domains);
-retry:
r = amdgpu_gem_object_create(adev, size, args->in.alignment,
- initial_domain,
- flags, ttm_bo_type_device, resv, &gobj);
+ initial_domain, flags, ttm_bo_type_device,
+ resv, &gobj);
if (r && r != -ERESTARTSYS) {
- if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) {
- flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
- goto retry;
- }
-
- if (initial_domain == AMDGPU_GEM_DOMAIN_VRAM) {
- initial_domain |= AMDGPU_GEM_DOMAIN_GTT;
- goto retry;
- }
DRM_DEBUG("Failed to allocate GEM object (%llu, %d, %llu, %d)\n",
size, initial_domain, args->in.alignment, r);
}
@@ -378,6 +369,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
struct amdgpu_device *adev = drm_to_adev(dev);
struct drm_amdgpu_gem_userptr *args = data;
struct drm_gem_object *gobj;
+ struct hmm_range *range;
struct amdgpu_bo *bo;
uint32_t handle;
int r;
@@ -413,14 +405,13 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
if (r)
goto release_object;
- if (args->flags & AMDGPU_GEM_USERPTR_REGISTER) {
- r = amdgpu_mn_register(bo, args->addr);
- if (r)
- goto release_object;
- }
+ r = amdgpu_hmm_register(bo, args->addr);
+ if (r)
+ goto release_object;
if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) {
- r = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages);
+ r = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages,
+ &range);
if (r)
goto release_object;
@@ -443,7 +434,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
user_pages_done:
if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE)
- amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
+ amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, range);
release_object:
drm_gem_object_put(gobj);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 9546adc8a76f..23692e5d4d13 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -583,10 +583,14 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
if (adev->gfx.gfx_off_req_count == 0 &&
!adev->gfx.gfx_off_state) {
/* If going to s2idle, no need to wait */
- if (adev->in_s0ix)
- delay = GFX_OFF_NO_DELAY;
- schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
+ if (adev->in_s0ix) {
+ if (!amdgpu_dpm_set_powergating_by_smu(adev,
+ AMD_IP_BLOCK_TYPE_GFX, true))
+ adev->gfx.gfx_off_state = true;
+ } else {
+ schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
delay);
+ }
}
} else {
if (adev->gfx.gfx_off_req_count == 0) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index 832b3807f1d6..b3df4787877e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -33,6 +33,7 @@
#include "amdgpu_imu.h"
#include "soc15.h"
#include "amdgpu_ras.h"
+#include "amdgpu_ring_mux.h"
/* GFX current status */
#define AMDGPU_GFX_NORMAL_MODE 0x00000000L
@@ -352,6 +353,9 @@ struct amdgpu_gfx {
struct amdgpu_gfx_ras *ras;
bool is_poweron;
+
+ struct amdgpu_ring sw_gfx_ring[AMDGPU_MAX_SW_GFX_RINGS];
+ struct amdgpu_ring_mux muxer;
};
#define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 34233a74248c..02a4c93673ce 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -479,6 +479,12 @@ int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev)
unsigned i;
unsigned vmhub, inv_eng;
+ if (adev->enable_mes) {
+ /* reserve engine 5 for firmware */
+ for (vmhub = 0; vmhub < AMDGPU_MAX_VMHUBS; vmhub++)
+ vm_inv_engs[vmhub] &= ~(1 << 5);
+ }
+
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
vmhub = ring->funcs->vmhub;
@@ -542,6 +548,8 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
case IP_VERSION(10, 3, 1):
/* YELLOW_CARP*/
case IP_VERSION(10, 3, 3):
+ case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
/* Don't enable it by default yet.
*/
if (amdgpu_tmz < 1) {
@@ -656,7 +664,7 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
}
if (amdgpu_sriov_vf(adev) ||
- !amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_DCE)) {
+ !amdgpu_device_has_display_hardware(adev)) {
size = 0;
} else {
size = amdgpu_gmc_get_vbios_fb_size(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index 1f3302aebeff..44367f03316f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -144,7 +144,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
node->base.start = node->mm_nodes[0].start;
} else {
node->mm_nodes[0].start = 0;
- node->mm_nodes[0].size = node->base.num_pages;
+ node->mm_nodes[0].size = PFN_UP(node->base.size);
node->base.start = AMDGPU_BO_INVALID_OFFSET;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
index b86c0b8252a5..65715cb395d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
@@ -49,9 +49,12 @@
#include "amdgpu.h"
#include "amdgpu_amdkfd.h"
+#include "amdgpu_hmm.h"
+
+#define MAX_WALK_BYTE (2UL << 30)
/**
- * amdgpu_mn_invalidate_gfx - callback to notify about mm change
+ * amdgpu_hmm_invalidate_gfx - callback to notify about mm change
*
* @mni: the range (mm) is about to update
* @range: details on the invalidation
@@ -60,9 +63,9 @@
* Block for operations on BOs to finish and mark pages as accessed and
* potentially dirty.
*/
-static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
- const struct mmu_notifier_range *range,
- unsigned long cur_seq)
+static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
+ const struct mmu_notifier_range *range,
+ unsigned long cur_seq)
{
struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
@@ -83,12 +86,12 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
return true;
}
-static const struct mmu_interval_notifier_ops amdgpu_mn_gfx_ops = {
- .invalidate = amdgpu_mn_invalidate_gfx,
+static const struct mmu_interval_notifier_ops amdgpu_hmm_gfx_ops = {
+ .invalidate = amdgpu_hmm_invalidate_gfx,
};
/**
- * amdgpu_mn_invalidate_hsa - callback to notify about mm change
+ * amdgpu_hmm_invalidate_hsa - callback to notify about mm change
*
* @mni: the range (mm) is about to update
* @range: details on the invalidation
@@ -97,9 +100,9 @@ static const struct mmu_interval_notifier_ops amdgpu_mn_gfx_ops = {
* We temporarily evict the BO attached to this range. This necessitates
* evicting all user-mode queues of the process.
*/
-static bool amdgpu_mn_invalidate_hsa(struct mmu_interval_notifier *mni,
- const struct mmu_notifier_range *range,
- unsigned long cur_seq)
+static bool amdgpu_hmm_invalidate_hsa(struct mmu_interval_notifier *mni,
+ const struct mmu_notifier_range *range,
+ unsigned long cur_seq)
{
struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
@@ -117,12 +120,12 @@ static bool amdgpu_mn_invalidate_hsa(struct mmu_interval_notifier *mni,
return true;
}
-static const struct mmu_interval_notifier_ops amdgpu_mn_hsa_ops = {
- .invalidate = amdgpu_mn_invalidate_hsa,
+static const struct mmu_interval_notifier_ops amdgpu_hmm_hsa_ops = {
+ .invalidate = amdgpu_hmm_invalidate_hsa,
};
/**
- * amdgpu_mn_register - register a BO for notifier updates
+ * amdgpu_hmm_register - register a BO for notifier updates
*
* @bo: amdgpu buffer object
* @addr: userptr addr we should monitor
@@ -130,25 +133,25 @@ static const struct mmu_interval_notifier_ops amdgpu_mn_hsa_ops = {
* Registers a mmu_notifier for the given BO at the specified address.
* Returns 0 on success, -ERRNO if anything goes wrong.
*/
-int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
+int amdgpu_hmm_register(struct amdgpu_bo *bo, unsigned long addr)
{
if (bo->kfd_bo)
return mmu_interval_notifier_insert(&bo->notifier, current->mm,
addr, amdgpu_bo_size(bo),
- &amdgpu_mn_hsa_ops);
+ &amdgpu_hmm_hsa_ops);
return mmu_interval_notifier_insert(&bo->notifier, current->mm, addr,
amdgpu_bo_size(bo),
- &amdgpu_mn_gfx_ops);
+ &amdgpu_hmm_gfx_ops);
}
/**
- * amdgpu_mn_unregister - unregister a BO for notifier updates
+ * amdgpu_hmm_unregister - unregister a BO for notifier updates
*
* @bo: amdgpu buffer object
*
* Remove any registration of mmu notifier updates from the buffer object.
*/
-void amdgpu_mn_unregister(struct amdgpu_bo *bo)
+void amdgpu_hmm_unregister(struct amdgpu_bo *bo)
{
if (!bo->notifier.mm)
return;
@@ -157,12 +160,12 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
}
int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
- struct mm_struct *mm, struct page **pages,
- uint64_t start, uint64_t npages,
- struct hmm_range **phmm_range, bool readonly,
- bool mmap_locked, void *owner)
+ uint64_t start, uint64_t npages, bool readonly,
+ void *owner, struct page **pages,
+ struct hmm_range **phmm_range)
{
struct hmm_range *hmm_range;
+ unsigned long end;
unsigned long timeout;
unsigned long i;
unsigned long *pfns;
@@ -184,32 +187,42 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
hmm_range->default_flags |= HMM_PFN_REQ_WRITE;
hmm_range->hmm_pfns = pfns;
hmm_range->start = start;
- hmm_range->end = start + npages * PAGE_SIZE;
+ end = start + npages * PAGE_SIZE;
hmm_range->dev_private_owner = owner;
- /* Assuming 512MB takes maxmium 1 second to fault page address */
- timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT;
- timeout = jiffies + msecs_to_jiffies(timeout);
+ do {
+ hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
+
+ pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
+ hmm_range->start, hmm_range->end);
+
+ /* Assuming 512MB takes maxmium 1 second to fault page address */
+ timeout = max((hmm_range->end - hmm_range->start) >> 29, 1UL);
+ timeout *= HMM_RANGE_DEFAULT_TIMEOUT;
+ timeout = jiffies + msecs_to_jiffies(timeout);
retry:
- hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
-
- if (likely(!mmap_locked))
- mmap_read_lock(mm);
-
- r = hmm_range_fault(hmm_range);
-
- if (likely(!mmap_locked))
- mmap_read_unlock(mm);
- if (unlikely(r)) {
- /*
- * FIXME: This timeout should encompass the retry from
- * mmu_interval_read_retry() as well.
- */
- if (r == -EBUSY && !time_after(jiffies, timeout))
- goto retry;
- goto out_free_pfns;
- }
+ hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
+ r = hmm_range_fault(hmm_range);
+ if (unlikely(r)) {
+ /*
+ * FIXME: This timeout should encompass the retry from
+ * mmu_interval_read_retry() as well.
+ */
+ if (r == -EBUSY && !time_after(jiffies, timeout))
+ goto retry;
+ goto out_free_pfns;
+ }
+
+ if (hmm_range->end == end)
+ break;
+ hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
+ hmm_range->start = hmm_range->end;
+ schedule();
+ } while (hmm_range->end < end);
+
+ hmm_range->start = start;
+ hmm_range->hmm_pfns = pfns;
/*
* Due to default_flags, all pages are HMM_PFN_VALID or
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.h
index 14a3c1864085..13ed94d3b01b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.h
@@ -31,23 +31,22 @@
#include <linux/interval_tree.h>
int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
- struct mm_struct *mm, struct page **pages,
- uint64_t start, uint64_t npages,
- struct hmm_range **phmm_range, bool readonly,
- bool mmap_locked, void *owner);
+ uint64_t start, uint64_t npages, bool readonly,
+ void *owner, struct page **pages,
+ struct hmm_range **phmm_range);
int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range);
#if defined(CONFIG_HMM_MIRROR)
-int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr);
-void amdgpu_mn_unregister(struct amdgpu_bo *bo);
+int amdgpu_hmm_register(struct amdgpu_bo *bo, unsigned long addr);
+void amdgpu_hmm_unregister(struct amdgpu_bo *bo);
#else
-static inline int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
+static inline int amdgpu_hmm_register(struct amdgpu_bo *bo, unsigned long addr)
{
DRM_WARN_ONCE("HMM_MIRROR kernel config option is not enabled, "
"add CONFIG_ZONE_DEVICE=y in config file to fix this\n");
return -ENODEV;
}
-static inline void amdgpu_mn_unregister(struct amdgpu_bo *bo) {}
+static inline void amdgpu_hmm_unregister(struct amdgpu_bo *bo) {}
#endif
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index 258cffe3c06a..bcccc348dbe2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -182,7 +182,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
need_ctx_switch = ring->current_ctx != fence_ctx;
if (ring->funcs->emit_pipeline_sync && job &&
- ((tmp = amdgpu_sync_get_fence(&job->sched_sync)) ||
+ ((tmp = amdgpu_sync_get_fence(&job->explicit_sync)) ||
(amdgpu_sriov_vf(adev) && need_ctx_switch) ||
amdgpu_vm_need_pipeline_sync(ring, job))) {
need_pipe_sync = true;
@@ -211,6 +211,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
}
}
+ amdgpu_ring_ib_begin(ring);
if (job && ring->funcs->init_cond_exec)
patch_offset = amdgpu_ring_init_cond_exec(ring);
@@ -285,6 +286,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
ring->hw_prio == AMDGPU_GFX_PIPE_PRIO_HIGH)
ring->funcs->emit_wave_limit(ring, false);
+ amdgpu_ring_ib_end(ring);
amdgpu_ring_commit(ring);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 03d115d2b5ed..2a9a2593dc18 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -170,26 +170,27 @@ bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
*
* @vm: vm to allocate id for
* @ring: ring we want to submit job to
- * @sync: sync object where we add dependencies
* @idle: resulting idle VMID
+ * @fence: fence to wait for if no id could be grabbed
*
* Try to find an idle VMID, if none is idle add a fence to wait to the sync
* object. Returns -ENOMEM when we are out of memory.
*/
static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
struct amdgpu_ring *ring,
- struct amdgpu_sync *sync,
- struct amdgpu_vmid **idle)
+ struct amdgpu_vmid **idle,
+ struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmhub = ring->funcs->vmhub;
struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
struct dma_fence **fences;
unsigned i;
- int r;
- if (!dma_fence_is_signaled(ring->vmid_wait))
- return amdgpu_sync_fence(sync, ring->vmid_wait);
+ if (!dma_fence_is_signaled(ring->vmid_wait)) {
+ *fence = dma_fence_get(ring->vmid_wait);
+ return 0;
+ }
fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_KERNEL);
if (!fences)
@@ -228,10 +229,10 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
return -ENOMEM;
}
- r = amdgpu_sync_fence(sync, &array->base);
+ *fence = dma_fence_get(&array->base);
dma_fence_put(ring->vmid_wait);
ring->vmid_wait = &array->base;
- return r;
+ return 0;
}
kfree(fences);
@@ -243,19 +244,17 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
*
* @vm: vm to allocate id for
* @ring: ring we want to submit job to
- * @sync: sync object where we add dependencies
- * @fence: fence protecting ID from reuse
* @job: job who wants to use the VMID
* @id: resulting VMID
+ * @fence: fence to wait for if no id could be grabbed
*
* Try to assign a reserved VMID.
*/
static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
struct amdgpu_ring *ring,
- struct amdgpu_sync *sync,
- struct dma_fence *fence,
struct amdgpu_job *job,
- struct amdgpu_vmid **id)
+ struct amdgpu_vmid **id,
+ struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmhub = ring->funcs->vmhub;
@@ -282,7 +281,8 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
if (tmp) {
*id = NULL;
- return amdgpu_sync_fence(sync, tmp);
+ *fence = dma_fence_get(tmp);
+ return 0;
}
needs_flush = true;
}
@@ -290,7 +290,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
/* Good we can use this VMID. Remember this submission as
* user of the VMID.
*/
- r = amdgpu_sync_fence(&(*id)->active, fence);
+ r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished);
if (r)
return r;
@@ -304,19 +304,17 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
*
* @vm: vm to allocate id for
* @ring: ring we want to submit job to
- * @sync: sync object where we add dependencies
- * @fence: fence protecting ID from reuse
* @job: job who wants to use the VMID
* @id: resulting VMID
+ * @fence: fence to wait for if no id could be grabbed
*
* Try to reuse a VMID for this submission.
*/
static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
struct amdgpu_ring *ring,
- struct amdgpu_sync *sync,
- struct dma_fence *fence,
struct amdgpu_job *job,
- struct amdgpu_vmid **id)
+ struct amdgpu_vmid **id,
+ struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmhub = ring->funcs->vmhub;
@@ -352,7 +350,8 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
/* Good, we can use this VMID. Remember this submission as
* user of the VMID.
*/
- r = amdgpu_sync_fence(&(*id)->active, fence);
+ r = amdgpu_sync_fence(&(*id)->active,
+ &job->base.s_fence->finished);
if (r)
return r;
@@ -370,15 +369,13 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
*
* @vm: vm to allocate id for
* @ring: ring we want to submit job to
- * @sync: sync object where we add dependencies
- * @fence: fence protecting ID from reuse
* @job: job who wants to use the VMID
+ * @fence: fence to wait for if no id could be grabbed
*
* Allocate an id for the vm, adding fences to the sync obj as necessary.
*/
int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
- struct amdgpu_sync *sync, struct dma_fence *fence,
- struct amdgpu_job *job)
+ struct amdgpu_job *job, struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmhub = ring->funcs->vmhub;
@@ -388,16 +385,16 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
int r = 0;
mutex_lock(&id_mgr->lock);
- r = amdgpu_vmid_grab_idle(vm, ring, sync, &idle);
+ r = amdgpu_vmid_grab_idle(vm, ring, &idle, fence);
if (r || !idle)
goto error;
if (vm->reserved_vmid[vmhub]) {
- r = amdgpu_vmid_grab_reserved(vm, ring, sync, fence, job, &id);
+ r = amdgpu_vmid_grab_reserved(vm, ring, job, &id, fence);
if (r || !id)
goto error;
} else {
- r = amdgpu_vmid_grab_used(vm, ring, sync, fence, job, &id);
+ r = amdgpu_vmid_grab_used(vm, ring, job, &id, fence);
if (r)
goto error;
@@ -406,7 +403,8 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
id = idle;
/* Remember this submission as user of the VMID */
- r = amdgpu_sync_fence(&id->active, fence);
+ r = amdgpu_sync_fence(&id->active,
+ &job->base.s_fence->finished);
if (r)
goto error;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
index 06c8a0034fa5..57efe61dceed 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
@@ -84,8 +84,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
unsigned vmhub);
int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
- struct amdgpu_sync *sync, struct dma_fence *fence,
- struct amdgpu_job *job);
+ struct amdgpu_job *job, struct dma_fence **fence);
void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
unsigned vmid);
void amdgpu_vmid_reset_all(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 89011bae7588..a6aef488a822 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -101,41 +101,6 @@ const char *soc15_ih_clientid_name[] = {
};
/**
- * amdgpu_hotplug_work_func - work handler for display hotplug event
- *
- * @work: work struct pointer
- *
- * This is the hotplug event work handler (all ASICs).
- * The work gets scheduled from the IRQ handler if there
- * was a hotplug interrupt. It walks through the connector table
- * and calls hotplug handler for each connector. After this, it sends
- * a DRM hotplug event to alert userspace.
- *
- * This design approach is required in order to defer hotplug event handling
- * from the IRQ handler to a work handler because hotplug handler has to use
- * mutexes which cannot be locked in an IRQ handler (since &mutex_lock may
- * sleep).
- */
-static void amdgpu_hotplug_work_func(struct work_struct *work)
-{
- struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
- hotplug_work);
- struct drm_device *dev = adev_to_drm(adev);
- struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_connector *connector;
- struct drm_connector_list_iter iter;
-
- mutex_lock(&mode_config->mutex);
- drm_connector_list_iter_begin(dev, &iter);
- drm_for_each_connector_iter(connector, &iter)
- amdgpu_connector_hotplug(connector);
- drm_connector_list_iter_end(&iter);
- mutex_unlock(&mode_config->mutex);
- /* Just fire off a uevent and let userspace tell us what to do */
- drm_helper_hpd_irq_event(dev);
-}
-
-/**
* amdgpu_irq_disable_all - disable *all* interrupts
*
* @adev: amdgpu device pointer
@@ -317,21 +282,6 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
}
}
- if (!amdgpu_device_has_dc_support(adev)) {
- if (!adev->enable_virtual_display)
- /* Disable vblank IRQs aggressively for power-saving */
- /* XXX: can this be enabled for DC? */
- adev_to_drm(adev)->vblank_disable_immediate = true;
-
- r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
- if (r)
- return r;
-
- /* Pre-DCE11 */
- INIT_WORK(&adev->hotplug_work,
- amdgpu_hotplug_work_func);
- }
-
INIT_WORK(&adev->irq.ih1_work, amdgpu_irq_handle_ih1);
INIT_WORK(&adev->irq.ih2_work, amdgpu_irq_handle_ih2);
INIT_WORK(&adev->irq.ih_soft_work, amdgpu_irq_handle_ih_soft);
@@ -345,11 +295,8 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
/* PCI devices require shared interrupts. */
r = request_irq(irq, amdgpu_irq_handler, IRQF_SHARED, adev_to_drm(adev)->driver->name,
adev_to_drm(adev));
- if (r) {
- if (!amdgpu_device_has_dc_support(adev))
- flush_work(&adev->hotplug_work);
+ if (r)
return r;
- }
adev->irq.installed = true;
adev->irq.irq = irq;
adev_to_drm(adev)->max_vblank_count = 0x00ffffff;
@@ -366,9 +313,6 @@ void amdgpu_irq_fini_hw(struct amdgpu_device *adev)
adev->irq.installed = false;
if (adev->irq.msi_enabled)
pci_free_irq_vectors(adev->pdev);
-
- if (!amdgpu_device_has_dc_support(adev))
- flush_work(&adev->hotplug_work);
}
amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index cd968e781077..9e549923622b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -88,8 +88,9 @@ exit:
return DRM_GPU_SCHED_STAT_NOMINAL;
}
-int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs,
- struct amdgpu_job **job, struct amdgpu_vm *vm)
+int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ struct drm_sched_entity *entity, void *owner,
+ unsigned int num_ibs, struct amdgpu_job **job)
{
if (num_ibs == 0)
return -EINVAL;
@@ -105,28 +106,34 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs,
(*job)->base.sched = &adev->rings[0]->sched;
(*job)->vm = vm;
- amdgpu_sync_create(&(*job)->sync);
- amdgpu_sync_create(&(*job)->sched_sync);
+ amdgpu_sync_create(&(*job)->explicit_sync);
(*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter);
(*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET;
- return 0;
+ if (!entity)
+ return 0;
+
+ return drm_sched_job_init(&(*job)->base, entity, owner);
}
-int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size,
- enum amdgpu_ib_pool_type pool_type,
- struct amdgpu_job **job)
+int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev,
+ struct drm_sched_entity *entity, void *owner,
+ size_t size, enum amdgpu_ib_pool_type pool_type,
+ struct amdgpu_job **job)
{
int r;
- r = amdgpu_job_alloc(adev, 1, job, NULL);
+ r = amdgpu_job_alloc(adev, NULL, entity, owner, 1, job);
if (r)
return r;
(*job)->num_ibs = 1;
r = amdgpu_ib_get(adev, NULL, size, pool_type, &(*job)->ibs[0]);
- if (r)
+ if (r) {
+ if (entity)
+ drm_sched_job_cleanup(&(*job)->base);
kfree(*job);
+ }
return r;
}
@@ -166,10 +173,13 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
drm_sched_job_cleanup(s_job);
- amdgpu_sync_free(&job->sync);
- amdgpu_sync_free(&job->sched_sync);
+ amdgpu_sync_free(&job->explicit_sync);
- dma_fence_put(&job->hw_fence);
+ /* only put the hw fence if has embedded fence */
+ if (!job->hw_fence.ops)
+ kfree(job);
+ else
+ dma_fence_put(&job->hw_fence);
}
void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
@@ -190,9 +200,11 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
void amdgpu_job_free(struct amdgpu_job *job)
{
+ if (job->base.entity)
+ drm_sched_job_cleanup(&job->base);
+
amdgpu_job_free_resources(job);
- amdgpu_sync_free(&job->sync);
- amdgpu_sync_free(&job->sched_sync);
+ amdgpu_sync_free(&job->explicit_sync);
if (job->gang_submit != &job->base.s_fence->scheduled)
dma_fence_put(job->gang_submit);
@@ -202,25 +214,16 @@ void amdgpu_job_free(struct amdgpu_job *job)
dma_fence_put(&job->hw_fence);
}
-int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity,
- void *owner, struct dma_fence **f)
+struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job)
{
- int r;
-
- if (!f)
- return -EINVAL;
-
- r = drm_sched_job_init(&job->base, entity, owner);
- if (r)
- return r;
+ struct dma_fence *f;
drm_sched_job_arm(&job->base);
-
- *f = dma_fence_get(&job->base.s_fence->finished);
+ f = dma_fence_get(&job->base.s_fence->finished);
amdgpu_job_free_resources(job);
drm_sched_entity_push_job(&job->base);
- return 0;
+ return f;
}
int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring,
@@ -238,35 +241,24 @@ int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring,
return 0;
}
-static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job,
- struct drm_sched_entity *s_entity)
+static struct dma_fence *
+amdgpu_job_prepare_job(struct drm_sched_job *sched_job,
+ struct drm_sched_entity *s_entity)
{
struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched);
struct amdgpu_job *job = to_amdgpu_job(sched_job);
- struct amdgpu_vm *vm = job->vm;
- struct dma_fence *fence;
+ struct dma_fence *fence = NULL;
int r;
- fence = amdgpu_sync_get_fence(&job->sync);
- if (fence && drm_sched_dependency_optimized(fence, s_entity)) {
- r = amdgpu_sync_fence(&job->sched_sync, fence);
- if (r)
- DRM_ERROR("Error adding fence (%d)\n", r);
- }
+ if (!fence && job->gang_submit)
+ fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit);
- while (fence == NULL && vm && !job->vmid) {
- r = amdgpu_vmid_grab(vm, ring, &job->sync,
- &job->base.s_fence->finished,
- job);
+ while (!fence && job->vm && !job->vmid) {
+ r = amdgpu_vmid_grab(job->vm, ring, job, &fence);
if (r)
DRM_ERROR("Error getting VM ID (%d)\n", r);
-
- fence = amdgpu_sync_get_fence(&job->sync);
}
- if (!fence && job->gang_submit)
- fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit);
-
return fence;
}
@@ -281,8 +273,6 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
job = to_amdgpu_job(sched_job);
finished = &job->base.s_fence->finished;
- BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL));
-
trace_amdgpu_sched_run_job(job);
/* Skip job if VRAM is lost and never resubmit gangs */
@@ -341,7 +331,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched)
}
const struct drm_sched_backend_ops amdgpu_sched_ops = {
- .dependency = amdgpu_job_dependency,
+ .prepare_job = amdgpu_job_prepare_job,
.run_job = amdgpu_job_run,
.timedout_job = amdgpu_job_timedout,
.free_job = amdgpu_job_free_cb
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
index ab7b150e5d50..a372802ea4e0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
@@ -47,8 +47,7 @@ enum amdgpu_ib_pool_type;
struct amdgpu_job {
struct drm_sched_job base;
struct amdgpu_vm *vm;
- struct amdgpu_sync sync;
- struct amdgpu_sync sched_sync;
+ struct amdgpu_sync explicit_sync;
struct dma_fence hw_fence;
struct dma_fence *gang_submit;
uint32_t preamble_status;
@@ -78,18 +77,20 @@ static inline struct amdgpu_ring *amdgpu_job_ring(struct amdgpu_job *job)
return to_amdgpu_ring(job->base.entity->rq->sched);
}
-int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs,
- struct amdgpu_job **job, struct amdgpu_vm *vm);
-int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size,
- enum amdgpu_ib_pool_type pool, struct amdgpu_job **job);
+int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ struct drm_sched_entity *entity, void *owner,
+ unsigned int num_ibs, struct amdgpu_job **job);
+int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev,
+ struct drm_sched_entity *entity, void *owner,
+ size_t size, enum amdgpu_ib_pool_type pool_type,
+ struct amdgpu_job **job);
void amdgpu_job_set_resources(struct amdgpu_job *job, struct amdgpu_bo *gds,
struct amdgpu_bo *gws, struct amdgpu_bo *oa);
void amdgpu_job_free_resources(struct amdgpu_job *job);
void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
struct amdgpu_job *leader);
void amdgpu_job_free(struct amdgpu_job *job);
-int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity,
- void *owner, struct dma_fence **f);
+struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job);
int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring,
struct dma_fence **fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
index 518eb0e40d32..6f81ed4fb0d9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
@@ -150,14 +150,15 @@ static int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle,
const unsigned ib_size_dw = 16;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
+ AMDGPU_IB_POOL_DIRECT, &job);
if (r)
return r;
ib = &job->ibs[0];
- ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0);
+ ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0,
+ PACKETJ_TYPE0);
ib->ptr[1] = 0xDEADBEEF;
for (i = 2; i < 16; i += 2) {
ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
@@ -234,3 +235,20 @@ int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
return 0;
}
+
+void jpeg_set_ras_funcs(struct amdgpu_device *adev)
+{
+ if (!adev->jpeg.ras)
+ return;
+
+ amdgpu_ras_register_ras_block(adev, &adev->jpeg.ras->ras_block);
+
+ strcpy(adev->jpeg.ras->ras_block.ras_comm.name, "jpeg");
+ adev->jpeg.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__JPEG;
+ adev->jpeg.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
+ adev->jpeg.ras_if = &adev->jpeg.ras->ras_block.ras_comm;
+
+ /* If don't define special ras_late_init function, use default ras_late_init */
+ if (!adev->jpeg.ras->ras_block.ras_late_init)
+ adev->jpeg.ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h
index 635dca59a70a..e8ca3e32ad52 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h
@@ -72,5 +72,6 @@ int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout);
int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry);
+void jpeg_set_ras_funcs(struct amdgpu_device *adev);
#endif /*__AMDGPU_JPEG_H__*/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 4e42dcb1950f..7aa7e52ca784 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -29,6 +29,7 @@
#include "amdgpu.h"
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
#include "amdgpu_uvd.h"
#include "amdgpu_vce.h"
#include "atom.h"
@@ -430,7 +431,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_DEC:
type = AMD_IP_BLOCK_TYPE_VCN;
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
- if (adev->uvd.harvest_config & (1 << i))
+ if (adev->vcn.harvest_config & (1 << i))
continue;
if (adev->vcn.inst[i].ring_dec.sched.ready)
@@ -442,7 +443,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC:
type = AMD_IP_BLOCK_TYPE_VCN;
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
- if (adev->uvd.harvest_config & (1 << i))
+ if (adev->vcn.harvest_config & (1 << i))
continue;
for (j = 0; j < adev->vcn.num_enc_rings; j++)
@@ -796,7 +797,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
dev_info->ids_flags = 0;
if (adev->flags & AMD_IS_APU)
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_FUSION;
- if (amdgpu_mcbp || amdgpu_sriov_vf(adev))
+ if (amdgpu_mcbp)
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_PREEMPTION;
if (amdgpu_is_tmz(adev))
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_TMZ;
@@ -1172,7 +1173,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
goto error_vm;
}
- if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
+ if (amdgpu_mcbp) {
uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_GMC_HOLE_MASK;
r = amdgpu_map_static_csa(adev, &fpriv->vm, adev->virt.csa_obj,
@@ -1236,7 +1237,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_VCE) != NULL)
amdgpu_vce_free_handles(adev, file_priv);
- if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
+ if (amdgpu_mcbp) {
/* TODO: how to handle reserve failure */
BUG_ON(amdgpu_bo_reserve(adev->virt.csa_obj, true));
amdgpu_vm_bo_del(adev, fpriv->csa_va);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
index ad980f4b66e1..97c05d08a551 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
@@ -91,14 +91,12 @@ struct amdgpu_mes {
struct amdgpu_bo *ucode_fw_obj[AMDGPU_MAX_MES_PIPES];
uint64_t ucode_fw_gpu_addr[AMDGPU_MAX_MES_PIPES];
uint32_t *ucode_fw_ptr[AMDGPU_MAX_MES_PIPES];
- uint32_t ucode_fw_version[AMDGPU_MAX_MES_PIPES];
uint64_t uc_start_addr[AMDGPU_MAX_MES_PIPES];
/* mes ucode data */
struct amdgpu_bo *data_fw_obj[AMDGPU_MAX_MES_PIPES];
uint64_t data_fw_gpu_addr[AMDGPU_MAX_MES_PIPES];
uint32_t *data_fw_ptr[AMDGPU_MAX_MES_PIPES];
- uint32_t data_fw_version[AMDGPU_MAX_MES_PIPES];
uint64_t data_start_addr[AMDGPU_MAX_MES_PIPES];
/* eop gpu obj */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 37322550d750..8a39300b1a84 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -36,7 +36,6 @@
#include <drm/drm_encoder.h>
#include <drm/drm_fixed.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_probe_helper.h>
#include <linux/i2c.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 2e8f6cd7a729..919bbea2e3ac 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -542,6 +542,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
/* GWS and OA don't need any alignment. */
page_align = bp->byte_align;
size <<= PAGE_SHIFT;
+
} else if (bp->domain & AMDGPU_GEM_DOMAIN_GDS) {
/* Both size and alignment must be a multiple of 4. */
page_align = ALIGN(bp->byte_align, 4);
@@ -580,11 +581,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE;
bo->tbo.bdev = &adev->mman.bdev;
- if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA |
- AMDGPU_GEM_DOMAIN_GDS))
- amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU);
- else
- amdgpu_bo_placement_from_domain(bo, bp->domain);
+ amdgpu_bo_placement_from_domain(bo, bp->domain);
if (bp->type == ttm_bo_type_kernel)
bo->tbo.priority = 1;
@@ -776,7 +773,7 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
return 0;
}
- r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap);
+ r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index effa7df3ddbf..7a2fc920739b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -52,6 +52,32 @@ static int psp_load_smu_fw(struct psp_context *psp);
static int psp_rap_terminate(struct psp_context *psp);
static int psp_securedisplay_terminate(struct psp_context *psp);
+static int psp_ring_init(struct psp_context *psp,
+ enum psp_ring_type ring_type)
+{
+ int ret = 0;
+ struct psp_ring *ring;
+ struct amdgpu_device *adev = psp->adev;
+
+ ring = &psp->km_ring;
+
+ ring->ring_type = ring_type;
+
+ /* allocate 4k Page of Local Frame Buffer memory for ring */
+ ring->ring_size = 0x1000;
+ ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->firmware.rbuf,
+ &ring->ring_mem_mc_addr,
+ (void **)&ring->ring_mem);
+ if (ret) {
+ ring->ring_size = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* Due to DF Cstate management centralized to PMFW, the firmware
* loading sequence will be updated as below:
@@ -139,6 +165,7 @@ static int psp_early_init(void *handle)
case IP_VERSION(13, 0, 5):
case IP_VERSION(13, 0, 8):
case IP_VERSION(13, 0, 10):
+ case IP_VERSION(13, 0, 11):
psp_v13_0_set_psp_funcs(psp);
psp->autoload_supported = true;
break;
@@ -172,6 +199,7 @@ void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx)
{
amdgpu_bo_free_kernel(&mem_ctx->shared_bo, &mem_ctx->shared_mc_addr,
&mem_ctx->shared_buf);
+ mem_ctx->shared_bo = NULL;
}
static void psp_free_shared_bufs(struct psp_context *psp)
@@ -182,6 +210,7 @@ static void psp_free_shared_bufs(struct psp_context *psp)
/* free TMR memory buffer */
pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr);
+ psp->tmr_bo = NULL;
/* free xgmi shared memory */
psp_ta_free_shared_buf(&psp->xgmi_context.context.mem_context);
@@ -484,26 +513,22 @@ static int psp_sw_fini(void *handle)
struct psp_gfx_cmd_resp *cmd = psp->cmd;
psp_memory_training_fini(psp);
- if (psp->sos_fw) {
- release_firmware(psp->sos_fw);
- psp->sos_fw = NULL;
- }
- if (psp->asd_fw) {
- release_firmware(psp->asd_fw);
- psp->asd_fw = NULL;
- }
- if (psp->ta_fw) {
- release_firmware(psp->ta_fw);
- psp->ta_fw = NULL;
- }
- if (psp->cap_fw) {
- release_firmware(psp->cap_fw);
- psp->cap_fw = NULL;
- }
- if (psp->toc_fw) {
- release_firmware(psp->toc_fw);
- psp->toc_fw = NULL;
- }
+
+ release_firmware(psp->sos_fw);
+ psp->sos_fw = NULL;
+
+ release_firmware(psp->asd_fw);
+ psp->asd_fw = NULL;
+
+ release_firmware(psp->ta_fw);
+ psp->ta_fw = NULL;
+
+ release_firmware(psp->cap_fw);
+ psp->cap_fw = NULL;
+
+ release_firmware(psp->toc_fw);
+ psp->toc_fw = NULL;
+
if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) ||
adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7))
psp_sysfs_fini(adev);
@@ -743,7 +768,7 @@ static int psp_load_toc(struct psp_context *psp,
/* Set up Trusted Memory Region */
static int psp_tmr_init(struct psp_context *psp)
{
- int ret;
+ int ret = 0;
int tmr_size;
void *tmr_buf;
void **pptr;
@@ -770,10 +795,12 @@ static int psp_tmr_init(struct psp_context *psp)
}
}
- pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
- ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_ALIGNMENT,
- AMDGPU_GEM_DOMAIN_VRAM,
- &psp->tmr_bo, &psp->tmr_mc_addr, pptr);
+ if (!psp->tmr_bo) {
+ pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
+ ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_ALIGNMENT,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ &psp->tmr_bo, &psp->tmr_mc_addr, pptr);
+ }
return ret;
}
@@ -831,7 +858,7 @@ static int psp_tmr_unload(struct psp_context *psp)
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
psp_prep_tmr_unload_cmd_buf(psp, cmd);
- dev_info(psp->adev->dev, "free PSP TMR buffer\n");
+ dev_dbg(psp->adev->dev, "free PSP TMR buffer\n");
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
@@ -988,6 +1015,8 @@ int psp_ta_unload(struct psp_context *psp, struct ta_context *context)
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+ context->resp_status = cmd->resp.status;
+
release_psp_cmd_buf(psp);
return ret;
@@ -1069,42 +1098,6 @@ int psp_ta_init_shared_buf(struct psp_context *psp,
&mem_ctx->shared_buf);
}
-static void psp_prep_ta_invoke_indirect_cmd_buf(struct psp_gfx_cmd_resp *cmd,
- uint32_t ta_cmd_id,
- struct ta_context *context)
-{
- cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
- cmd->cmd.cmd_invoke_cmd.session_id = context->session_id;
- cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
-
- cmd->cmd.cmd_invoke_cmd.buf.num_desc = 1;
- cmd->cmd.cmd_invoke_cmd.buf.total_size = context->mem_context.shared_mem_size;
- cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_size = context->mem_context.shared_mem_size;
- cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_phy_addr_lo =
- lower_32_bits(context->mem_context.shared_mc_addr);
- cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_phy_addr_hi =
- upper_32_bits(context->mem_context.shared_mc_addr);
-}
-
-int psp_ta_invoke_indirect(struct psp_context *psp,
- uint32_t ta_cmd_id,
- struct ta_context *context)
-{
- int ret;
- struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
-
- psp_prep_ta_invoke_indirect_cmd_buf(cmd, ta_cmd_id, context);
-
- ret = psp_cmd_submit_buf(psp, NULL, cmd,
- psp->fence_buf_mc_addr);
-
- context->resp_status = cmd->resp.status;
-
- release_psp_cmd_buf(psp);
-
- return ret;
-}
-
static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint32_t ta_cmd_id,
uint32_t session_id)
@@ -1547,7 +1540,7 @@ int psp_ras_terminate(struct psp_context *psp)
return ret;
}
-static int psp_ras_initialize(struct psp_context *psp)
+int psp_ras_initialize(struct psp_context *psp)
{
int ret;
uint32_t boot_cfg = 0xFF;
@@ -1610,7 +1603,7 @@ static int psp_ras_initialize(struct psp_context *psp)
psp->ras_context.context.mem_context.shared_mem_size = PSP_RAS_SHARED_MEM_SIZE;
psp->ras_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;
- if (!psp->ras_context.context.initialized) {
+ if (!psp->ras_context.context.mem_context.shared_buf) {
ret = psp_ta_init_shared_buf(psp, &psp->ras_context.context.mem_context);
if (ret)
return ret;
@@ -1631,7 +1624,9 @@ static int psp_ras_initialize(struct psp_context *psp)
else {
if (ras_cmd->ras_status)
dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status);
- amdgpu_ras_fini(psp->adev);
+
+ /* fail to load RAS TA */
+ psp->ras_context.context.initialized = false;
}
return ret;
@@ -1938,10 +1933,15 @@ static int psp_securedisplay_initialize(struct psp_context *psp)
} else
return ret;
+ mutex_lock(&psp->securedisplay_context.mutex);
+
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__QUERY_TA);
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA);
+
+ mutex_unlock(&psp->securedisplay_context.mutex);
+
if (ret) {
psp_securedisplay_terminate(psp);
/* free securedisplay shared memory */
@@ -1990,12 +1990,8 @@ int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
ta_cmd_id != TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC)
return -EINVAL;
- mutex_lock(&psp->securedisplay_context.mutex);
-
ret = psp_ta_invoke(psp, ta_cmd_id, &psp->securedisplay_context.context);
- mutex_unlock(&psp->securedisplay_context.mutex);
-
return ret;
}
/* SECUREDISPLAY end */
@@ -2732,8 +2728,6 @@ static int psp_suspend(void *handle)
}
out:
- psp_free_shared_bufs(psp);
-
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 58ce3ebb446c..cf4f60c66122 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -118,7 +118,6 @@ struct psp_funcs
int (*bootloader_load_dbg_drv)(struct psp_context *psp);
int (*bootloader_load_ras_drv)(struct psp_context *psp);
int (*bootloader_load_sos)(struct psp_context *psp);
- int (*ring_init)(struct psp_context *psp, enum psp_ring_type ring_type);
int (*ring_create)(struct psp_context *psp,
enum psp_ring_type ring_type);
int (*ring_stop)(struct psp_context *psp,
@@ -136,6 +135,12 @@ struct psp_funcs
int (*vbflash_stat)(struct psp_context *psp);
};
+struct ta_funcs {
+ int (*fn_ta_initialize)(struct psp_context *psp);
+ int (*fn_ta_invoke)(struct psp_context *psp, uint32_t ta_cmd_id);
+ int (*fn_ta_terminate)(struct psp_context *psp);
+};
+
#define AMDGPU_XGMI_MAX_CONNECTED_NODES 64
struct psp_xgmi_node_info {
uint64_t node_id;
@@ -309,6 +314,7 @@ struct psp_context
struct psp_gfx_cmd_resp *cmd;
const struct psp_funcs *funcs;
+ const struct ta_funcs *ta_funcs;
/* firmware buffer */
struct amdgpu_bo *fw_pri_bo;
@@ -389,7 +395,6 @@ struct amdgpu_psp_funcs {
};
-#define psp_ring_init(psp, type) (psp)->funcs->ring_init((psp), (type))
#define psp_ring_create(psp, type) (psp)->funcs->ring_create((psp), (type))
#define psp_ring_stop(psp, type) (psp)->funcs->ring_stop((psp), (type))
#define psp_ring_destroy(psp, type) ((psp)->funcs->ring_destroy((psp), (type)))
@@ -463,9 +468,6 @@ int psp_ta_load(struct psp_context *psp, struct ta_context *context);
int psp_ta_invoke(struct psp_context *psp,
uint32_t ta_cmd_id,
struct ta_context *context);
-int psp_ta_invoke_indirect(struct psp_context *psp,
- uint32_t ta_cmd_id,
- struct ta_context *context);
int psp_xgmi_initialize(struct psp_context *psp, bool set_extended_data, bool load_ta);
int psp_xgmi_terminate(struct psp_context *psp);
@@ -479,7 +481,7 @@ int psp_xgmi_get_topology_info(struct psp_context *psp,
int psp_xgmi_set_topology_info(struct psp_context *psp,
int number_devices,
struct psp_xgmi_topology_info *topology);
-
+int psp_ras_initialize(struct psp_context *psp);
int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
int psp_ras_enable_features(struct psp_context *psp,
union ta_ras_cmd_input *info, bool enable);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
index 0988e00612e5..468a67b302d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
@@ -41,30 +41,46 @@ static uint32_t get_bin_version(const uint8_t *bin)
return hdr->ucode_version;
}
-static void prep_ta_mem_context(struct psp_context *psp,
- struct ta_context *context,
+static int prep_ta_mem_context(struct ta_mem_context *mem_context,
uint8_t *shared_buf,
uint32_t shared_buf_len)
{
- context->mem_context.shared_mem_size = PAGE_ALIGN(shared_buf_len);
- psp_ta_init_shared_buf(psp, &context->mem_context);
+ if (mem_context->shared_mem_size < shared_buf_len)
+ return -EINVAL;
+ memset(mem_context->shared_buf, 0, mem_context->shared_mem_size);
+ memcpy((void *)mem_context->shared_buf, shared_buf, shared_buf_len);
- memcpy((void *)context->mem_context.shared_buf, shared_buf, shared_buf_len);
+ return 0;
}
static bool is_ta_type_valid(enum ta_type_id ta_type)
{
- bool ret = false;
+ switch (ta_type) {
+ case TA_TYPE_RAS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct ta_funcs ras_ta_funcs = {
+ .fn_ta_initialize = psp_ras_initialize,
+ .fn_ta_invoke = psp_ras_invoke,
+ .fn_ta_terminate = psp_ras_terminate
+};
+static void set_ta_context_funcs(struct psp_context *psp,
+ enum ta_type_id ta_type,
+ struct ta_context **pcontext)
+{
switch (ta_type) {
case TA_TYPE_RAS:
- ret = true;
+ *pcontext = &psp->ras_context.context;
+ psp->ta_funcs = &ras_ta_funcs;
break;
default:
break;
}
-
- return ret;
}
static const struct file_operations ta_load_debugfs_fops = {
@@ -85,8 +101,7 @@ static const struct file_operations ta_invoke_debugfs_fops = {
.owner = THIS_MODULE
};
-
-/**
+/*
* DOC: AMDGPU TA debugfs interfaces
*
* Three debugfs interfaces can be opened by a program to
@@ -111,15 +126,18 @@ static const struct file_operations ta_invoke_debugfs_fops = {
*
* - For TA invoke debugfs interface:
* Transmit buffer:
+ * - TA type (4bytes)
* - TA ID (4bytes)
* - TA CMD ID (4bytes)
- * - TA shard buf length (4bytes)
+ * - TA shard buf length
+ * (4bytes, value not beyond TA shared memory size)
* - TA shared buf
* Receive buffer:
* - TA shared buf
*
* - For TA unload debugfs interface:
* Transmit buffer:
+ * - TA type (4bytes)
* - TA ID (4bytes)
*/
@@ -131,59 +149,92 @@ static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t
uint32_t copy_pos = 0;
int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
- struct psp_context *psp = &adev->psp;
- struct ta_context context = {0};
+ struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
+ struct psp_context *psp = &adev->psp;
+ struct ta_context *context = NULL;
if (!buf)
return -EINVAL;
ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
if (ret || (!is_ta_type_valid(ta_type)))
- return -EINVAL;
+ return -EFAULT;
copy_pos += sizeof(uint32_t);
ret = copy_from_user((void *)&ta_bin_len, &buf[copy_pos], sizeof(uint32_t));
if (ret)
- return -EINVAL;
+ return -EFAULT;
copy_pos += sizeof(uint32_t);
ta_bin = kzalloc(ta_bin_len, GFP_KERNEL);
if (!ta_bin)
- ret = -ENOMEM;
+ return -ENOMEM;
if (copy_from_user((void *)ta_bin, &buf[copy_pos], ta_bin_len)) {
ret = -EFAULT;
goto err_free_bin;
}
- ret = psp_ras_terminate(psp);
- if (ret) {
- dev_err(adev->dev, "Failed to unload embedded RAS TA\n");
+ /* Set TA context and functions */
+ set_ta_context_funcs(psp, ta_type, &context);
+
+ if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
+ dev_err(adev->dev, "Unsupported function to terminate TA\n");
+ ret = -EOPNOTSUPP;
goto err_free_bin;
}
- context.ta_type = ta_type;
- context.ta_load_type = GFX_CMD_ID_LOAD_TA;
- context.bin_desc.fw_version = get_bin_version(ta_bin);
- context.bin_desc.size_bytes = ta_bin_len;
- context.bin_desc.start_addr = ta_bin;
+ /*
+ * Allocate TA shared buf in case shared buf was freed
+ * due to loading TA failed before.
+ */
+ if (!context->mem_context.shared_buf) {
+ ret = psp_ta_init_shared_buf(psp, &context->mem_context);
+ if (ret) {
+ ret = -ENOMEM;
+ goto err_free_bin;
+ }
+ }
+
+ ret = psp_fn_ta_terminate(psp);
+ if (ret || context->resp_status) {
+ dev_err(adev->dev,
+ "Failed to unload embedded TA (%d) and status (0x%X)\n",
+ ret, context->resp_status);
+ if (!ret)
+ ret = -EINVAL;
+ goto err_free_ta_shared_buf;
+ }
+
+ /* Prepare TA context for TA initialization */
+ context->ta_type = ta_type;
+ context->bin_desc.fw_version = get_bin_version(ta_bin);
+ context->bin_desc.size_bytes = ta_bin_len;
+ context->bin_desc.start_addr = ta_bin;
- ret = psp_ta_load(psp, &context);
+ if (!psp->ta_funcs->fn_ta_initialize) {
+ dev_err(adev->dev, "Unsupported function to initialize TA\n");
+ ret = -EOPNOTSUPP;
+ goto err_free_ta_shared_buf;
+ }
- if (ret || context.resp_status) {
- dev_err(adev->dev, "TA load via debugfs failed (%d) status %d\n",
- ret, context.resp_status);
+ ret = psp_fn_ta_initialize(psp);
+ if (ret || context->resp_status) {
+ dev_err(adev->dev, "Failed to load TA via debugfs (%d) and status (0x%X)\n",
+ ret, context->resp_status);
if (!ret)
ret = -EINVAL;
- goto err_free_bin;
+ goto err_free_ta_shared_buf;
}
- context.initialized = true;
- if (copy_to_user((char *)buf, (void *)&context.session_id, sizeof(uint32_t)))
+ if (copy_to_user((char *)buf, (void *)&context->session_id, sizeof(uint32_t)))
ret = -EFAULT;
+err_free_ta_shared_buf:
+ /* Only free TA shared buf when returns error code */
+ if (ret && context->mem_context.shared_buf)
+ psp_ta_free_shared_buf(&context->mem_context);
err_free_bin:
kfree(ta_bin);
@@ -192,58 +243,85 @@ err_free_bin:
static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
{
- uint32_t ta_id = 0;
- int ret = 0;
+ uint32_t ta_type = 0;
+ uint32_t ta_id = 0;
+ uint32_t copy_pos = 0;
+ int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
- struct psp_context *psp = &adev->psp;
- struct ta_context context = {0};
+ struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
+ struct psp_context *psp = &adev->psp;
+ struct ta_context *context = NULL;
if (!buf)
return -EINVAL;
- ret = copy_from_user((void *)&ta_id, buf, sizeof(uint32_t));
+ ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
+ if (ret || (!is_ta_type_valid(ta_type)))
+ return -EFAULT;
+
+ copy_pos += sizeof(uint32_t);
+
+ ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
if (ret)
- return -EINVAL;
+ return -EFAULT;
- context.session_id = ta_id;
+ set_ta_context_funcs(psp, ta_type, &context);
+ context->session_id = ta_id;
- ret = psp_ta_unload(psp, &context);
- if (!ret)
- context.initialized = false;
+ if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
+ dev_err(adev->dev, "Unsupported function to terminate TA\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = psp_fn_ta_terminate(psp);
+ if (ret || context->resp_status) {
+ dev_err(adev->dev, "Failed to unload TA via debugfs (%d) and status (0x%X)\n",
+ ret, context->resp_status);
+ if (!ret)
+ ret = -EINVAL;
+ }
+
+ if (context->mem_context.shared_buf)
+ psp_ta_free_shared_buf(&context->mem_context);
return ret;
}
static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
{
+ uint32_t ta_type = 0;
uint32_t ta_id = 0;
uint32_t cmd_id = 0;
uint32_t shared_buf_len = 0;
- uint8_t *shared_buf = NULL;
+ uint8_t *shared_buf = NULL;
uint32_t copy_pos = 0;
int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
- struct psp_context *psp = &adev->psp;
- struct ta_context context = {0};
+ struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;
+ struct psp_context *psp = &adev->psp;
+ struct ta_context *context = NULL;
if (!buf)
return -EINVAL;
+ ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
+ if (ret)
+ return -EFAULT;
+ copy_pos += sizeof(uint32_t);
+
ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
if (ret)
- return -EINVAL;
+ return -EFAULT;
copy_pos += sizeof(uint32_t);
ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t));
if (ret)
- return -EINVAL;
+ return -EFAULT;
copy_pos += sizeof(uint32_t);
ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t));
if (ret)
- return -EINVAL;
+ return -EFAULT;
copy_pos += sizeof(uint32_t);
shared_buf = kzalloc(shared_buf_len, GFP_KERNEL);
@@ -254,26 +332,39 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
goto err_free_shared_buf;
}
- context.session_id = ta_id;
+ set_ta_context_funcs(psp, ta_type, &context);
+
+ if (!context->initialized) {
+ dev_err(adev->dev, "TA is not initialized\n");
+ ret = -EINVAL;
+ goto err_free_shared_buf;
+ }
+
+ if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {
+ dev_err(adev->dev, "Unsupported function to invoke TA\n");
+ ret = -EOPNOTSUPP;
+ goto err_free_shared_buf;
+ }
- prep_ta_mem_context(psp, &context, shared_buf, shared_buf_len);
+ context->session_id = ta_id;
- ret = psp_ta_invoke_indirect(psp, cmd_id, &context);
+ ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);
+ if (ret)
+ goto err_free_shared_buf;
- if (ret || context.resp_status) {
- dev_err(adev->dev, "TA invoke via debugfs failed (%d) status %d\n",
- ret, context.resp_status);
- if (!ret)
+ ret = psp_fn_ta_invoke(psp, cmd_id);
+ if (ret || context->resp_status) {
+ dev_err(adev->dev, "Failed to invoke TA via debugfs (%d) and status (0x%X)\n",
+ ret, context->resp_status);
+ if (!ret) {
ret = -EINVAL;
- goto err_free_ta_shared_buf;
+ goto err_free_shared_buf;
+ }
}
- if (copy_to_user((char *)buf, context.mem_context.shared_buf, shared_buf_len))
+ if (copy_to_user((char *)buf, context->mem_context.shared_buf, shared_buf_len))
ret = -EFAULT;
-err_free_ta_shared_buf:
- psp_ta_free_shared_buf(&context.mem_context);
-
err_free_shared_buf:
kfree(shared_buf);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h
index cfc1542f63ef..14cd1c81c3e6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h
@@ -24,6 +24,11 @@
#ifndef __AMDGPU_PSP_TA_H__
#define __AMDGPU_PSP_TA_H__
+/* Calling set_ta_context_funcs is required before using the following macros */
+#define psp_fn_ta_initialize(psp) ((psp)->ta_funcs->fn_ta_initialize((psp)))
+#define psp_fn_ta_invoke(psp, ta_cmd_id) ((psp)->ta_funcs->fn_ta_invoke((psp), (ta_cmd_id)))
+#define psp_fn_ta_terminate(psp) ((psp)->ta_funcs->fn_ta_terminate((psp)))
+
void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index a4b47e1bd111..ad490c1e2f57 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -1267,7 +1267,7 @@ static ssize_t amdgpu_ras_sysfs_features_read(struct device *dev,
struct amdgpu_ras *con =
container_of(attr, struct amdgpu_ras, features_attr);
- return scnprintf(buf, PAGE_SIZE, "feature mask: 0x%x\n", con->features);
+ return sysfs_emit(buf, "feature mask: 0x%x\n", con->features);
}
static void amdgpu_ras_sysfs_remove_bad_page_node(struct amdgpu_device *adev)
@@ -1561,7 +1561,6 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
{
bool poison_stat = false;
struct amdgpu_device *adev = obj->adev;
- struct ras_err_data err_data = {0, 0, 0, NULL};
struct amdgpu_ras_block_object *block_obj =
amdgpu_ras_get_ras_block(adev, obj->head.block, 0);
@@ -1584,7 +1583,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
}
if (!adev->gmc.xgmi.connected_to_cpu)
- amdgpu_umc_poison_handler(adev, &err_data, false);
+ amdgpu_umc_poison_handler(adev, false);
if (block_obj->hw_ops->handle_poison_consumption)
poison_stat = block_obj->hw_ops->handle_poison_consumption(adev);
@@ -1949,7 +1948,12 @@ static void amdgpu_ras_do_recovery(struct work_struct *work)
reset_context.method = AMD_RESET_METHOD_NONE;
reset_context.reset_req_dev = adev;
- clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
+
+ /* Perform full reset in fatal error mode */
+ if (!amdgpu_ras_is_poison_mode_supported(ras->adev))
+ set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
+ else
+ clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
amdgpu_device_gpu_recover(ras->adev, NULL, &reset_context);
}
@@ -2344,7 +2348,8 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev)
adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC |
1 << AMDGPU_RAS_BLOCK__DF);
- if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0))
+ if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0) ||
+ adev->ip_versions[VCN_HWIP][0] == IP_VERSION(4, 0, 0))
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN |
1 << AMDGPU_RAS_BLOCK__JPEG);
else
@@ -2848,7 +2853,6 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb,
struct amdgpu_device *adev = NULL;
uint32_t gpu_id = 0;
uint32_t umc_inst = 0, ch_inst = 0;
- struct ras_err_data err_data = {0, 0, 0, NULL};
/*
* If the error was generated in UMC_V2, which belongs to GPU UMCs,
@@ -2887,31 +2891,10 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb,
dev_info(adev->dev, "Uncorrectable error detected in UMC inst: %d, chan_idx: %d",
umc_inst, ch_inst);
- err_data.err_addr =
- kcalloc(adev->umc.max_ras_err_cnt_per_query,
- sizeof(struct eeprom_table_record), GFP_KERNEL);
- if (!err_data.err_addr) {
- dev_warn(adev->dev,
- "Failed to alloc memory for umc error record in mca notifier!\n");
+ if (!amdgpu_umc_page_retirement_mca(adev, m->addr, ch_inst, umc_inst))
+ return NOTIFY_OK;
+ else
return NOTIFY_DONE;
- }
-
- /*
- * Translate UMC channel address to Physical address
- */
- if (adev->umc.ras &&
- adev->umc.ras->convert_ras_error_address)
- adev->umc.ras->convert_ras_error_address(adev,
- &err_data, m->addr, ch_inst, umc_inst);
-
- if (amdgpu_bad_page_threshold != 0) {
- amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
- err_data.err_addr_cnt);
- amdgpu_ras_save_bad_pages(adev);
- }
-
- kfree(err_data.err_addr);
- return NOTIFY_OK;
}
static struct notifier_block amdgpu_bad_page_nb = {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
index 84c241b9a2a1..2d9f3f4cd79e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
@@ -33,12 +33,29 @@
#include "amdgpu_reset.h"
-#define EEPROM_I2C_MADDR_VEGA20 0x0
-#define EEPROM_I2C_MADDR_ARCTURUS 0x40000
-#define EEPROM_I2C_MADDR_ARCTURUS_D342 0x0
-#define EEPROM_I2C_MADDR_SIENNA_CICHLID 0x0
-#define EEPROM_I2C_MADDR_ALDEBARAN 0x0
-#define EEPROM_I2C_MADDR_SMU_13_0_0 (0x54UL << 16)
+/* These are memory addresses as would be seen by one or more EEPROM
+ * chips strung on the I2C bus, usually by manipulating pins 1-3 of a
+ * set of EEPROM devices. They form a continuous memory space.
+ *
+ * The I2C device address includes the device type identifier, 1010b,
+ * which is a reserved value and indicates that this is an I2C EEPROM
+ * device. It also includes the top 3 bits of the 19 bit EEPROM memory
+ * address, namely bits 18, 17, and 16. This makes up the 7 bit
+ * address sent on the I2C bus with bit 0 being the direction bit,
+ * which is not represented here, and sent by the hardware directly.
+ *
+ * For instance,
+ * 50h = 1010000b => device type identifier 1010b, bits 18:16 = 000b, address 0.
+ * 54h = 1010100b => --"--, bits 18:16 = 100b, address 40000h.
+ * 56h = 1010110b => --"--, bits 18:16 = 110b, address 60000h.
+ * Depending on the size of the I2C EEPROM device(s), bits 18:16 may
+ * address memory in a device or a device on the I2C bus, depending on
+ * the status of pins 1-3. See top of amdgpu_eeprom.c.
+ *
+ * The RAS table lives either at address 0 or address 40000h of EEPROM.
+ */
+#define EEPROM_I2C_MADDR_0 0x0
+#define EEPROM_I2C_MADDR_4 0x40000
/*
* The 2 macros bellow represent the actual size in bytes that
@@ -90,6 +107,16 @@
static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
{
+ if (adev->asic_type == CHIP_IP_DISCOVERY) {
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(13, 0, 0):
+ case IP_VERSION(13, 0, 10):
+ return true;
+ default:
+ return false;
+ }
+ }
+
return adev->asic_type == CHIP_VEGA20 ||
adev->asic_type == CHIP_ARCTURUS ||
adev->asic_type == CHIP_SIENNA_CICHLID ||
@@ -107,16 +134,30 @@ static bool __get_eeprom_i2c_addr_arct(struct amdgpu_device *adev,
if (strnstr(atom_ctx->vbios_version,
"D342",
sizeof(atom_ctx->vbios_version)))
- control->i2c_address = EEPROM_I2C_MADDR_ARCTURUS_D342;
+ control->i2c_address = EEPROM_I2C_MADDR_0;
else
- control->i2c_address = EEPROM_I2C_MADDR_ARCTURUS;
+ control->i2c_address = EEPROM_I2C_MADDR_4;
return true;
}
+static bool __get_eeprom_i2c_addr_ip_discovery(struct amdgpu_device *adev,
+ struct amdgpu_ras_eeprom_control *control)
+{
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(13, 0, 0):
+ case IP_VERSION(13, 0, 10):
+ control->i2c_address = EEPROM_I2C_MADDR_4;
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
struct amdgpu_ras_eeprom_control *control)
{
+ struct atom_context *atom_ctx = adev->mode_info.atom_context;
u8 i2c_addr;
if (!control)
@@ -139,27 +180,34 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
switch (adev->asic_type) {
case CHIP_VEGA20:
- control->i2c_address = EEPROM_I2C_MADDR_VEGA20;
+ control->i2c_address = EEPROM_I2C_MADDR_0;
break;
case CHIP_ARCTURUS:
return __get_eeprom_i2c_addr_arct(adev, control);
case CHIP_SIENNA_CICHLID:
- control->i2c_address = EEPROM_I2C_MADDR_SIENNA_CICHLID;
+ control->i2c_address = EEPROM_I2C_MADDR_0;
break;
case CHIP_ALDEBARAN:
- control->i2c_address = EEPROM_I2C_MADDR_ALDEBARAN;
+ if (strnstr(atom_ctx->vbios_version, "D673",
+ sizeof(atom_ctx->vbios_version)))
+ control->i2c_address = EEPROM_I2C_MADDR_4;
+ else
+ control->i2c_address = EEPROM_I2C_MADDR_0;
break;
+ case CHIP_IP_DISCOVERY:
+ return __get_eeprom_i2c_addr_ip_discovery(adev, control);
+
default:
return false;
}
switch (adev->ip_versions[MP1_HWIP][0]) {
case IP_VERSION(13, 0, 0):
- control->i2c_address = EEPROM_I2C_MADDR_SMU_13_0_0;
+ control->i2c_address = EEPROM_I2C_MADDR_4;
break;
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
index 6546552e596c..5c4f93ee0c57 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
@@ -62,7 +62,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
if (!res)
goto fallback;
- BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
+ BUG_ON(start + size > res->size);
cur->mem_type = res->mem_type;
@@ -110,7 +110,7 @@ fallback:
cur->size = size;
cur->remaining = size;
cur->node = NULL;
- WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
+ WARN_ON(res && start + size > res->size);
return;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index d3558c34d406..dc474b809604 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -569,3 +569,15 @@ int amdgpu_ring_init_mqd(struct amdgpu_ring *ring)
return mqd_mgr->init_mqd(adev, ring->mqd_ptr, &prop);
}
+
+void amdgpu_ring_ib_begin(struct amdgpu_ring *ring)
+{
+ if (ring->is_sw_ring)
+ amdgpu_sw_ring_ib_begin(ring);
+}
+
+void amdgpu_ring_ib_end(struct amdgpu_ring *ring)
+{
+ if (ring->is_sw_ring)
+ amdgpu_sw_ring_ib_end(ring);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index 82c178a9033a..f752c7ae7f60 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -39,6 +39,7 @@ struct amdgpu_vm;
#define AMDGPU_MAX_RINGS 28
#define AMDGPU_MAX_HWIP_RINGS 8
#define AMDGPU_MAX_GFX_RINGS 2
+#define AMDGPU_MAX_SW_GFX_RINGS 2
#define AMDGPU_MAX_COMPUTE_RINGS 8
#define AMDGPU_MAX_VCE_RINGS 3
#define AMDGPU_MAX_UVD_ENC_RINGS 2
@@ -59,6 +60,7 @@ enum amdgpu_ring_priority_level {
#define AMDGPU_FENCE_FLAG_64BIT (1 << 0)
#define AMDGPU_FENCE_FLAG_INT (1 << 1)
#define AMDGPU_FENCE_FLAG_TC_WB_ONLY (1 << 2)
+#define AMDGPU_FENCE_FLAG_EXEC (1 << 3)
#define to_amdgpu_ring(s) container_of((s), struct amdgpu_ring, sched)
@@ -143,8 +145,13 @@ signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
uint32_t wait_seq,
signed long timeout);
unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring);
+
void amdgpu_fence_driver_isr_toggle(struct amdgpu_device *adev, bool stop);
+u64 amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring *ring);
+void amdgpu_fence_update_start_timestamp(struct amdgpu_ring *ring, uint32_t seq,
+ ktime_t timestamp);
+
/*
* Rings.
*/
@@ -279,6 +286,10 @@ struct amdgpu_ring {
bool is_mes_queue;
uint32_t hw_queue_id;
struct amdgpu_mes_ctx_data *mes_ctx;
+
+ bool is_sw_ring;
+ unsigned int entry_index;
+
};
#define amdgpu_ring_parse_cs(r, p, job, ib) ((r)->funcs->parse_cs((p), (job), (ib)))
@@ -307,6 +318,9 @@ struct amdgpu_ring {
#define amdgpu_ring_preempt_ib(r) (r)->funcs->preempt_ib(r)
int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw);
+void amdgpu_ring_ib_begin(struct amdgpu_ring *ring);
+void amdgpu_ring_ib_end(struct amdgpu_ring *ring);
+
void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);
void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib);
void amdgpu_ring_commit(struct amdgpu_ring *ring);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c
new file mode 100644
index 000000000000..62079f0e3ee8
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/slab.h>
+#include <drm/drm_print.h>
+
+#include "amdgpu_ring_mux.h"
+#include "amdgpu_ring.h"
+#include "amdgpu.h"
+
+#define AMDGPU_MUX_RESUBMIT_JIFFIES_TIMEOUT (HZ / 2)
+#define AMDGPU_MAX_LAST_UNSIGNALED_THRESHOLD_US 10000
+
+static const struct ring_info {
+ unsigned int hw_pio;
+ const char *ring_name;
+} sw_ring_info[] = {
+ { AMDGPU_RING_PRIO_DEFAULT, "gfx_low"},
+ { AMDGPU_RING_PRIO_2, "gfx_high"},
+};
+
+static struct kmem_cache *amdgpu_mux_chunk_slab;
+
+static inline struct amdgpu_mux_entry *amdgpu_ring_mux_sw_entry(struct amdgpu_ring_mux *mux,
+ struct amdgpu_ring *ring)
+{
+ return ring->entry_index < mux->ring_entry_size ?
+ &mux->ring_entry[ring->entry_index] : NULL;
+}
+
+/* copy packages on sw ring range[begin, end) */
+static void amdgpu_ring_mux_copy_pkt_from_sw_ring(struct amdgpu_ring_mux *mux,
+ struct amdgpu_ring *ring,
+ u64 s_start, u64 s_end)
+{
+ u64 start, end;
+ struct amdgpu_ring *real_ring = mux->real_ring;
+
+ start = s_start & ring->buf_mask;
+ end = s_end & ring->buf_mask;
+
+ if (start == end) {
+ DRM_ERROR("no more data copied from sw ring\n");
+ return;
+ }
+ if (start > end) {
+ amdgpu_ring_alloc(real_ring, (ring->ring_size >> 2) + end - start);
+ amdgpu_ring_write_multiple(real_ring, (void *)&ring->ring[start],
+ (ring->ring_size >> 2) - start);
+ amdgpu_ring_write_multiple(real_ring, (void *)&ring->ring[0], end);
+ } else {
+ amdgpu_ring_alloc(real_ring, end - start);
+ amdgpu_ring_write_multiple(real_ring, (void *)&ring->ring[start], end - start);
+ }
+}
+
+static void amdgpu_mux_resubmit_chunks(struct amdgpu_ring_mux *mux)
+{
+ struct amdgpu_mux_entry *e = NULL;
+ struct amdgpu_mux_chunk *chunk;
+ uint32_t seq, last_seq;
+ int i;
+
+ /*find low priority entries:*/
+ if (!mux->s_resubmit)
+ return;
+
+ for (i = 0; i < mux->num_ring_entries; i++) {
+ if (mux->ring_entry[i].ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT) {
+ e = &mux->ring_entry[i];
+ break;
+ }
+ }
+
+ if (!e) {
+ DRM_ERROR("%s no low priority ring found\n", __func__);
+ return;
+ }
+
+ last_seq = atomic_read(&e->ring->fence_drv.last_seq);
+ seq = mux->seqno_to_resubmit;
+ if (last_seq < seq) {
+ /*resubmit all the fences between (last_seq, seq]*/
+ list_for_each_entry(chunk, &e->list, entry) {
+ if (chunk->sync_seq > last_seq && chunk->sync_seq <= seq) {
+ amdgpu_fence_update_start_timestamp(e->ring,
+ chunk->sync_seq,
+ ktime_get());
+ amdgpu_ring_mux_copy_pkt_from_sw_ring(mux, e->ring,
+ chunk->start,
+ chunk->end);
+ mux->wptr_resubmit = chunk->end;
+ amdgpu_ring_commit(mux->real_ring);
+ }
+ }
+ }
+
+ del_timer(&mux->resubmit_timer);
+ mux->s_resubmit = false;
+}
+
+static void amdgpu_ring_mux_schedule_resubmit(struct amdgpu_ring_mux *mux)
+{
+ mod_timer(&mux->resubmit_timer, jiffies + AMDGPU_MUX_RESUBMIT_JIFFIES_TIMEOUT);
+}
+
+static void amdgpu_mux_resubmit_fallback(struct timer_list *t)
+{
+ struct amdgpu_ring_mux *mux = from_timer(mux, t, resubmit_timer);
+
+ if (!spin_trylock(&mux->lock)) {
+ amdgpu_ring_mux_schedule_resubmit(mux);
+ DRM_ERROR("reschedule resubmit\n");
+ return;
+ }
+ amdgpu_mux_resubmit_chunks(mux);
+ spin_unlock(&mux->lock);
+}
+
+int amdgpu_ring_mux_init(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring,
+ unsigned int entry_size)
+{
+ mux->real_ring = ring;
+ mux->num_ring_entries = 0;
+
+ mux->ring_entry = kcalloc(entry_size, sizeof(struct amdgpu_mux_entry), GFP_KERNEL);
+ if (!mux->ring_entry)
+ return -ENOMEM;
+
+ mux->ring_entry_size = entry_size;
+ mux->s_resubmit = false;
+
+ amdgpu_mux_chunk_slab = kmem_cache_create("amdgpu_mux_chunk",
+ sizeof(struct amdgpu_mux_chunk), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!amdgpu_mux_chunk_slab) {
+ DRM_ERROR("create amdgpu_mux_chunk cache failed\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&mux->lock);
+ timer_setup(&mux->resubmit_timer, amdgpu_mux_resubmit_fallback, 0);
+
+ return 0;
+}
+
+void amdgpu_ring_mux_fini(struct amdgpu_ring_mux *mux)
+{
+ struct amdgpu_mux_entry *e;
+ struct amdgpu_mux_chunk *chunk, *chunk2;
+ int i;
+
+ for (i = 0; i < mux->num_ring_entries; i++) {
+ e = &mux->ring_entry[i];
+ list_for_each_entry_safe(chunk, chunk2, &e->list, entry) {
+ list_del(&chunk->entry);
+ kmem_cache_free(amdgpu_mux_chunk_slab, chunk);
+ }
+ }
+ kmem_cache_destroy(amdgpu_mux_chunk_slab);
+ kfree(mux->ring_entry);
+ mux->ring_entry = NULL;
+ mux->num_ring_entries = 0;
+ mux->ring_entry_size = 0;
+}
+
+int amdgpu_ring_mux_add_sw_ring(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ struct amdgpu_mux_entry *e;
+
+ if (mux->num_ring_entries >= mux->ring_entry_size) {
+ DRM_ERROR("add sw ring exceeding max entry size\n");
+ return -ENOENT;
+ }
+
+ e = &mux->ring_entry[mux->num_ring_entries];
+ ring->entry_index = mux->num_ring_entries;
+ e->ring = ring;
+
+ INIT_LIST_HEAD(&e->list);
+ mux->num_ring_entries += 1;
+ return 0;
+}
+
+void amdgpu_ring_mux_set_wptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring, u64 wptr)
+{
+ struct amdgpu_mux_entry *e;
+
+ spin_lock(&mux->lock);
+
+ if (ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT)
+ amdgpu_mux_resubmit_chunks(mux);
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("cannot find entry for sw ring\n");
+ spin_unlock(&mux->lock);
+ return;
+ }
+
+ /* We could skip this set wptr as preemption in process. */
+ if (ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT && mux->pending_trailing_fence_signaled) {
+ spin_unlock(&mux->lock);
+ return;
+ }
+
+ e->sw_cptr = e->sw_wptr;
+ /* Update cptr if the package already copied in resubmit functions */
+ if (ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT && e->sw_cptr < mux->wptr_resubmit)
+ e->sw_cptr = mux->wptr_resubmit;
+ e->sw_wptr = wptr;
+ e->start_ptr_in_hw_ring = mux->real_ring->wptr;
+
+ /* Skip copying for the packages already resubmitted.*/
+ if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT || mux->wptr_resubmit < wptr) {
+ amdgpu_ring_mux_copy_pkt_from_sw_ring(mux, ring, e->sw_cptr, wptr);
+ e->end_ptr_in_hw_ring = mux->real_ring->wptr;
+ amdgpu_ring_commit(mux->real_ring);
+ } else {
+ e->end_ptr_in_hw_ring = mux->real_ring->wptr;
+ }
+ spin_unlock(&mux->lock);
+}
+
+u64 amdgpu_ring_mux_get_wptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ struct amdgpu_mux_entry *e;
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("cannot find entry for sw ring\n");
+ return 0;
+ }
+
+ return e->sw_wptr;
+}
+
+/**
+ * amdgpu_ring_mux_get_rptr - get the readptr of the software ring
+ * @mux: the multiplexer the software rings attach to
+ * @ring: the software ring of which we calculate the readptr
+ *
+ * The return value of the readptr is not precise while the other rings could
+ * write data onto the real ring buffer.After overwriting on the real ring, we
+ * can not decide if our packages have been excuted or not read yet. However,
+ * this function is only called by the tools such as umr to collect the latest
+ * packages for the hang analysis. We assume the hang happens near our latest
+ * submit. Thus we could use the following logic to give the clue:
+ * If the readptr is between start and end, then we return the copy pointer
+ * plus the distance from start to readptr. If the readptr is before start, we
+ * return the copy pointer. Lastly, if the readptr is past end, we return the
+ * write pointer.
+ */
+u64 amdgpu_ring_mux_get_rptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ struct amdgpu_mux_entry *e;
+ u64 readp, offset, start, end;
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("no sw entry found!\n");
+ return 0;
+ }
+
+ readp = amdgpu_ring_get_rptr(mux->real_ring);
+
+ start = e->start_ptr_in_hw_ring & mux->real_ring->buf_mask;
+ end = e->end_ptr_in_hw_ring & mux->real_ring->buf_mask;
+ if (start > end) {
+ if (readp <= end)
+ readp += mux->real_ring->ring_size >> 2;
+ end += mux->real_ring->ring_size >> 2;
+ }
+
+ if (start <= readp && readp <= end) {
+ offset = readp - start;
+ e->sw_rptr = (e->sw_cptr + offset) & ring->buf_mask;
+ } else if (readp < start) {
+ e->sw_rptr = e->sw_cptr;
+ } else {
+ /* end < readptr */
+ e->sw_rptr = e->sw_wptr;
+ }
+
+ return e->sw_rptr;
+}
+
+u64 amdgpu_sw_ring_get_rptr_gfx(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+
+ WARN_ON(!ring->is_sw_ring);
+ return amdgpu_ring_mux_get_rptr(mux, ring);
+}
+
+u64 amdgpu_sw_ring_get_wptr_gfx(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+
+ WARN_ON(!ring->is_sw_ring);
+ return amdgpu_ring_mux_get_wptr(mux, ring);
+}
+
+void amdgpu_sw_ring_set_wptr_gfx(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+
+ WARN_ON(!ring->is_sw_ring);
+ amdgpu_ring_mux_set_wptr(mux, ring, ring->wptr);
+}
+
+/* Override insert_nop to prevent emitting nops to the software rings */
+void amdgpu_sw_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
+{
+ WARN_ON(!ring->is_sw_ring);
+}
+
+const char *amdgpu_sw_ring_name(int idx)
+{
+ return idx < ARRAY_SIZE(sw_ring_info) ?
+ sw_ring_info[idx].ring_name : NULL;
+}
+
+unsigned int amdgpu_sw_ring_priority(int idx)
+{
+ return idx < ARRAY_SIZE(sw_ring_info) ?
+ sw_ring_info[idx].hw_pio : AMDGPU_RING_PRIO_DEFAULT;
+}
+
+/*Scan on low prio rings to have unsignaled fence and high ring has no fence.*/
+static int amdgpu_mcbp_scan(struct amdgpu_ring_mux *mux)
+{
+ struct amdgpu_ring *ring;
+ int i, need_preempt;
+
+ need_preempt = 0;
+ for (i = 0; i < mux->num_ring_entries; i++) {
+ ring = mux->ring_entry[i].ring;
+ if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT &&
+ amdgpu_fence_count_emitted(ring) > 0)
+ return 0;
+ if (ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT &&
+ amdgpu_fence_last_unsignaled_time_us(ring) >
+ AMDGPU_MAX_LAST_UNSIGNALED_THRESHOLD_US)
+ need_preempt = 1;
+ }
+ return need_preempt && !mux->s_resubmit;
+}
+
+/* Trigger Mid-Command Buffer Preemption (MCBP) and find if we need to resubmit. */
+static int amdgpu_mcbp_trigger_preempt(struct amdgpu_ring_mux *mux)
+{
+ int r;
+
+ spin_lock(&mux->lock);
+ mux->pending_trailing_fence_signaled = true;
+ r = amdgpu_ring_preempt_ib(mux->real_ring);
+ spin_unlock(&mux->lock);
+ return r;
+}
+
+void amdgpu_sw_ring_ib_begin(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+
+ WARN_ON(!ring->is_sw_ring);
+ if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) {
+ if (amdgpu_mcbp_scan(mux) > 0)
+ amdgpu_mcbp_trigger_preempt(mux);
+ return;
+ }
+
+ amdgpu_ring_mux_start_ib(mux, ring);
+}
+
+void amdgpu_sw_ring_ib_end(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+
+ WARN_ON(!ring->is_sw_ring);
+ if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT)
+ return;
+ amdgpu_ring_mux_end_ib(mux, ring);
+}
+
+void amdgpu_ring_mux_start_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ struct amdgpu_mux_entry *e;
+ struct amdgpu_mux_chunk *chunk;
+
+ spin_lock(&mux->lock);
+ amdgpu_mux_resubmit_chunks(mux);
+ spin_unlock(&mux->lock);
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("cannot find entry!\n");
+ return;
+ }
+
+ chunk = kmem_cache_alloc(amdgpu_mux_chunk_slab, GFP_KERNEL);
+ if (!chunk) {
+ DRM_ERROR("alloc amdgpu_mux_chunk_slab failed\n");
+ return;
+ }
+
+ chunk->start = ring->wptr;
+ list_add_tail(&chunk->entry, &e->list);
+}
+
+static void scan_and_remove_signaled_chunk(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ uint32_t last_seq = 0;
+ struct amdgpu_mux_entry *e;
+ struct amdgpu_mux_chunk *chunk, *tmp;
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("cannot find entry!\n");
+ return;
+ }
+
+ last_seq = atomic_read(&ring->fence_drv.last_seq);
+
+ list_for_each_entry_safe(chunk, tmp, &e->list, entry) {
+ if (chunk->sync_seq <= last_seq) {
+ list_del(&chunk->entry);
+ kmem_cache_free(amdgpu_mux_chunk_slab, chunk);
+ }
+ }
+}
+
+void amdgpu_ring_mux_end_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
+{
+ struct amdgpu_mux_entry *e;
+ struct amdgpu_mux_chunk *chunk;
+
+ e = amdgpu_ring_mux_sw_entry(mux, ring);
+ if (!e) {
+ DRM_ERROR("cannot find entry!\n");
+ return;
+ }
+
+ chunk = list_last_entry(&e->list, struct amdgpu_mux_chunk, entry);
+ if (!chunk) {
+ DRM_ERROR("cannot find chunk!\n");
+ return;
+ }
+
+ chunk->end = ring->wptr;
+ chunk->sync_seq = READ_ONCE(ring->fence_drv.sync_seq);
+
+ scan_and_remove_signaled_chunk(mux, ring);
+}
+
+bool amdgpu_mcbp_handle_trailing_fence_irq(struct amdgpu_ring_mux *mux)
+{
+ struct amdgpu_mux_entry *e;
+ struct amdgpu_ring *ring = NULL;
+ int i;
+
+ if (!mux->pending_trailing_fence_signaled)
+ return false;
+
+ if (mux->real_ring->trail_seq != le32_to_cpu(*mux->real_ring->trail_fence_cpu_addr))
+ return false;
+
+ for (i = 0; i < mux->num_ring_entries; i++) {
+ e = &mux->ring_entry[i];
+ if (e->ring->hw_prio <= AMDGPU_RING_PRIO_DEFAULT) {
+ ring = e->ring;
+ break;
+ }
+ }
+
+ if (!ring) {
+ DRM_ERROR("cannot find low priority ring\n");
+ return false;
+ }
+
+ amdgpu_fence_process(ring);
+ if (amdgpu_fence_count_emitted(ring) > 0) {
+ mux->s_resubmit = true;
+ mux->seqno_to_resubmit = ring->fence_drv.sync_seq;
+ amdgpu_ring_mux_schedule_resubmit(mux);
+ }
+
+ mux->pending_trailing_fence_signaled = false;
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.h
new file mode 100644
index 000000000000..4be45fc14954
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_RING_MUX__
+#define __AMDGPU_RING_MUX__
+
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include "amdgpu_ring.h"
+
+struct amdgpu_ring;
+
+/**
+ * struct amdgpu_mux_entry - the entry recording software rings copying information.
+ * @ring: the pointer to the software ring.
+ * @start_ptr_in_hw_ring: last start location copied to in the hardware ring.
+ * @end_ptr_in_hw_ring: last end location copied to in the hardware ring.
+ * @sw_cptr: the position of the copy pointer in the sw ring.
+ * @sw_rptr: the read pointer in software ring.
+ * @sw_wptr: the write pointer in software ring.
+ * @list: list head for amdgpu_mux_chunk
+ */
+struct amdgpu_mux_entry {
+ struct amdgpu_ring *ring;
+ u64 start_ptr_in_hw_ring;
+ u64 end_ptr_in_hw_ring;
+ u64 sw_cptr;
+ u64 sw_rptr;
+ u64 sw_wptr;
+ struct list_head list;
+};
+
+struct amdgpu_ring_mux {
+ struct amdgpu_ring *real_ring;
+
+ struct amdgpu_mux_entry *ring_entry;
+ unsigned int num_ring_entries;
+ unsigned int ring_entry_size;
+ /*the lock for copy data from different software rings*/
+ spinlock_t lock;
+ bool s_resubmit;
+ uint32_t seqno_to_resubmit;
+ u64 wptr_resubmit;
+ struct timer_list resubmit_timer;
+
+ bool pending_trailing_fence_signaled;
+};
+
+/**
+ * struct amdgpu_mux_chunk - save the location of indirect buffer's package on softare rings.
+ * @entry: the list entry.
+ * @sync_seq: the fence seqno related with the saved IB.
+ * @start:- start location on the software ring.
+ * @end:- end location on the software ring.
+ */
+struct amdgpu_mux_chunk {
+ struct list_head entry;
+ uint32_t sync_seq;
+ u64 start;
+ u64 end;
+};
+
+int amdgpu_ring_mux_init(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring,
+ unsigned int entry_size);
+void amdgpu_ring_mux_fini(struct amdgpu_ring_mux *mux);
+int amdgpu_ring_mux_add_sw_ring(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+void amdgpu_ring_mux_set_wptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring, u64 wptr);
+u64 amdgpu_ring_mux_get_wptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+u64 amdgpu_ring_mux_get_rptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+void amdgpu_ring_mux_start_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+void amdgpu_ring_mux_end_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+bool amdgpu_mcbp_handle_trailing_fence_irq(struct amdgpu_ring_mux *mux);
+
+u64 amdgpu_sw_ring_get_rptr_gfx(struct amdgpu_ring *ring);
+u64 amdgpu_sw_ring_get_wptr_gfx(struct amdgpu_ring *ring);
+void amdgpu_sw_ring_set_wptr_gfx(struct amdgpu_ring *ring);
+void amdgpu_sw_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);
+void amdgpu_sw_ring_ib_begin(struct amdgpu_ring *ring);
+void amdgpu_sw_ring_ib_end(struct amdgpu_ring *ring);
+const char *amdgpu_sw_ring_name(int idx);
+unsigned int amdgpu_sw_ring_priority(int idx);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
index cc7597a15fe9..2c1d82fc4c34 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
@@ -121,6 +121,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
switch (op) {
case 1:
+ mutex_lock(&psp->securedisplay_context.mutex);
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__QUERY_TA);
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA);
@@ -131,8 +132,10 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
else
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
}
+ mutex_unlock(&psp->securedisplay_context.mutex);
break;
case 2:
+ mutex_lock(&psp->securedisplay_context.mutex);
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_id;
@@ -146,6 +149,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
}
}
+ mutex_unlock(&psp->securedisplay_context.mutex);
break;
default:
dev_err(adev->dev, "Invalid input: %s\n", str);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
index 090e66a1b284..bac7976975bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -259,6 +259,14 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
return 0;
}
+/* Free the entry back to the slab */
+static void amdgpu_sync_entry_free(struct amdgpu_sync_entry *e)
+{
+ hash_del(&e->node);
+ dma_fence_put(e->fence);
+ kmem_cache_free(amdgpu_sync_slab, e);
+}
+
/**
* amdgpu_sync_peek_fence - get the next fence not signaled yet
*
@@ -280,9 +288,7 @@ struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync,
struct drm_sched_fence *s_fence = to_drm_sched_fence(f);
if (dma_fence_is_signaled(f)) {
- hash_del(&e->node);
- dma_fence_put(f);
- kmem_cache_free(amdgpu_sync_slab, e);
+ amdgpu_sync_entry_free(e);
continue;
}
if (ring && s_fence) {
@@ -355,15 +361,42 @@ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone)
if (r)
return r;
} else {
- hash_del(&e->node);
- dma_fence_put(f);
- kmem_cache_free(amdgpu_sync_slab, e);
+ amdgpu_sync_entry_free(e);
}
}
return 0;
}
+/**
+ * amdgpu_sync_push_to_job - push fences into job
+ * @sync: sync object to get the fences from
+ * @job: job to push the fences into
+ *
+ * Add all unsignaled fences from sync to job.
+ */
+int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job)
+{
+ struct amdgpu_sync_entry *e;
+ struct hlist_node *tmp;
+ struct dma_fence *f;
+ int i, r;
+
+ hash_for_each_safe(sync->fences, i, tmp, e, node) {
+ f = e->fence;
+ if (dma_fence_is_signaled(f)) {
+ amdgpu_sync_entry_free(e);
+ continue;
+ }
+
+ dma_fence_get(f);
+ r = drm_sched_job_add_dependency(&job->base, f);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr)
{
struct amdgpu_sync_entry *e;
@@ -375,9 +408,7 @@ int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr)
if (r)
return r;
- hash_del(&e->node);
- dma_fence_put(e->fence);
- kmem_cache_free(amdgpu_sync_slab, e);
+ amdgpu_sync_entry_free(e);
}
return 0;
@@ -396,11 +427,8 @@ void amdgpu_sync_free(struct amdgpu_sync *sync)
struct hlist_node *tmp;
unsigned int i;
- hash_for_each_safe(sync->fences, i, tmp, e, node) {
- hash_del(&e->node);
- dma_fence_put(e->fence);
- kmem_cache_free(amdgpu_sync_slab, e);
- }
+ hash_for_each_safe(sync->fences, i, tmp, e, node)
+ amdgpu_sync_entry_free(e);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
index 2d5c613cda10..cf1e9e858efd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
@@ -30,6 +30,7 @@ struct dma_fence;
struct dma_resv;
struct amdgpu_device;
struct amdgpu_ring;
+struct amdgpu_job;
enum amdgpu_sync_mode {
AMDGPU_SYNC_ALWAYS,
@@ -54,6 +55,7 @@ struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync,
struct amdgpu_ring *ring);
struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync);
int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone);
+int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job);
int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr);
void amdgpu_sync_free(struct amdgpu_sync *sync);
int amdgpu_sync_init(void);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 5e6ddc7e101c..677ad2016976 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -127,7 +127,7 @@ TRACE_EVENT(amdgpu_bo_create,
TP_fast_assign(
__entry->bo = bo;
- __entry->pages = bo->tbo.resource->num_pages;
+ __entry->pages = PFN_UP(bo->tbo.resource->size);
__entry->type = bo->tbo.resource->mem_type;
__entry->prefer = bo->preferred_domains;
__entry->allow = bo->allowed_domains;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 57277b1cf183..b4236572eae1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -58,6 +58,7 @@
#include "amdgpu_amdkfd.h"
#include "amdgpu_sdma.h"
#include "amdgpu_ras.h"
+#include "amdgpu_hmm.h"
#include "amdgpu_atomfirmware.h"
#include "amdgpu_res_cursor.h"
#include "bif/bif_4_1_d.h"
@@ -189,7 +190,6 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
struct amdgpu_device *adev = ring->adev;
unsigned offset, num_pages, num_dw, num_bytes;
uint64_t src_addr, dst_addr;
- struct dma_fence *fence;
struct amdgpu_job *job;
void *cpu_addr;
uint64_t flags;
@@ -229,7 +229,9 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes,
+ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ num_dw * 4 + num_bytes,
AMDGPU_IB_POOL_DELAYED, &job);
if (r)
return r;
@@ -269,18 +271,8 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
}
}
- r = amdgpu_job_submit(job, &adev->mman.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
- if (r)
- goto error_free;
-
- dma_fence_put(fence);
-
- return r;
-
-error_free:
- amdgpu_job_free(job);
- return r;
+ dma_fence_put(amdgpu_job_submit(job));
+ return 0;
}
/**
@@ -381,7 +373,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
dst.offset = 0;
r = amdgpu_ttm_copy_mem_to_mem(adev, &src, &dst,
- new_mem->num_pages << PAGE_SHIFT,
+ new_mem->size,
amdgpu_bo_encrypted(abo),
bo->base.resv, &fence);
if (r)
@@ -424,7 +416,7 @@ error:
static bool amdgpu_mem_visible(struct amdgpu_device *adev,
struct ttm_resource *mem)
{
- u64 mem_size = (u64)mem->num_pages << PAGE_SHIFT;
+ u64 mem_size = (u64)mem->size;
struct amdgpu_res_cursor cursor;
u64 end;
@@ -571,7 +563,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev,
struct ttm_resource *mem)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
- size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
+ size_t bus_size = (size_t)mem->size;
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
@@ -643,9 +635,6 @@ struct amdgpu_ttm_tt {
struct task_struct *usertask;
uint32_t userflags;
bool bound;
-#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
- struct hmm_range *range;
-#endif
};
#define ttm_to_amdgpu_ttm_tt(ptr) container_of(ptr, struct amdgpu_ttm_tt, ttm)
@@ -658,7 +647,8 @@ struct amdgpu_ttm_tt {
* Calling function must call amdgpu_ttm_tt_userptr_range_done() once and only
* once afterwards to stop HMM tracking
*/
-int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
+int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages,
+ struct hmm_range **range)
{
struct ttm_tt *ttm = bo->tbo.ttm;
struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
@@ -668,16 +658,15 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
bool readonly;
int r = 0;
+ /* Make sure get_user_pages_done() can cleanup gracefully */
+ *range = NULL;
+
mm = bo->notifier.mm;
if (unlikely(!mm)) {
DRM_DEBUG_DRIVER("BO is not registered?\n");
return -EFAULT;
}
- /* Another get_user_pages is running at the same time?? */
- if (WARN_ON(gtt->range))
- return -EFAULT;
-
if (!mmget_not_zero(mm)) /* Happens during process shutdown */
return -ESRCH;
@@ -694,9 +683,8 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
}
readonly = amdgpu_ttm_tt_is_readonly(ttm);
- r = amdgpu_hmm_range_get_pages(&bo->notifier, mm, pages, start,
- ttm->num_pages, &gtt->range, readonly,
- true, NULL);
+ r = amdgpu_hmm_range_get_pages(&bo->notifier, start, ttm->num_pages,
+ readonly, NULL, pages, range);
out_unlock:
mmap_read_unlock(mm);
if (r)
@@ -713,30 +701,24 @@ out_unlock:
*
* Returns: true if pages are still valid
*/
-bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
+bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm,
+ struct hmm_range *range)
{
struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
- bool r = false;
- if (!gtt || !gtt->userptr)
+ if (!gtt || !gtt->userptr || !range)
return false;
DRM_DEBUG_DRIVER("user_pages_done 0x%llx pages 0x%x\n",
gtt->userptr, ttm->num_pages);
- WARN_ONCE(!gtt->range || !gtt->range->hmm_pfns,
- "No user pages to check\n");
-
- if (gtt->range) {
- /*
- * FIXME: Must always hold notifier_lock for this, and must
- * not ignore the return code.
- */
- r = amdgpu_hmm_range_get_pages_done(gtt->range);
- gtt->range = NULL;
- }
+ WARN_ONCE(!range->hmm_pfns, "No user pages to check\n");
- return !r;
+ /*
+ * FIXME: Must always hold notifier_lock for this, and must
+ * not ignore the return code.
+ */
+ return !amdgpu_hmm_range_get_pages_done(range);
}
#endif
@@ -813,20 +795,6 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_device *bdev,
/* unmap the pages mapped to the device */
dma_unmap_sgtable(adev->dev, ttm->sg, direction, 0);
sg_free_table(ttm->sg);
-
-#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
- if (gtt->range) {
- unsigned long i;
-
- for (i = 0; i < ttm->num_pages; i++) {
- if (ttm->pages[i] !=
- hmm_pfn_to_page(gtt->range->hmm_pfns[i]))
- break;
- }
-
- WARN((i == ttm->num_pages), "Missing get_user_page_done\n");
- }
-#endif
}
static void amdgpu_ttm_gart_bind(struct amdgpu_device *adev,
@@ -1177,8 +1145,9 @@ int amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object *tbo,
* @addr: The address in the current tasks VM space to use
* @flags: Requirements of userptr object.
*
- * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages
- * to current task
+ * Called by amdgpu_gem_userptr_ioctl() and kfd_ioctl_alloc_memory_of_gpu() to
+ * bind userptr pages to current task and by kfd_ioctl_acquire_vm() to
+ * initialize GPU VM for a KFD process.
*/
int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
uint64_t addr, uint32_t flags)
@@ -1417,7 +1386,8 @@ static void amdgpu_ttm_vram_mm_access(struct amdgpu_device *adev, loff_t pos,
}
static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo,
- unsigned long offset, void *buf, int len, int write)
+ unsigned long offset, void *buf,
+ int len, int write)
{
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
@@ -1441,26 +1411,27 @@ static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo,
memcpy(adev->mman.sdma_access_ptr, buf, len);
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, AMDGPU_IB_POOL_DELAYED, &job);
+ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ num_dw * 4, AMDGPU_IB_POOL_DELAYED,
+ &job);
if (r)
goto out;
amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm);
- src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + src_mm.start;
+ src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) +
+ src_mm.start;
dst_addr = amdgpu_bo_gpu_offset(adev->mman.sdma_access_bo);
if (write)
swap(src_addr, dst_addr);
- amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr, PAGE_SIZE, false);
+ amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr,
+ PAGE_SIZE, false);
amdgpu_ring_pad_ib(adev->mman.buffer_funcs_ring, &job->ibs[0]);
WARN_ON(job->ibs[0].length_dw > num_dw);
- r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
- if (r) {
- amdgpu_job_free(job);
- goto out;
- }
+ fence = amdgpu_job_submit(job);
if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout))
r = -ETIMEDOUT;
@@ -1560,6 +1531,23 @@ static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev)
NULL, &adev->mman.fw_vram_usage_va);
}
+/*
+ * Driver Reservation functions
+ */
+/**
+ * amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * free drv reserved vram if it has been reserved.
+ */
+static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev)
+{
+ amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo,
+ NULL,
+ &adev->mman.drv_vram_usage_va);
+}
+
/**
* amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
*
@@ -1586,6 +1574,32 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
&adev->mman.fw_vram_usage_va);
}
+/**
+ * amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * create bo vram reservation from drv.
+ */
+static int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev)
+{
+ u64 vram_size = adev->gmc.visible_vram_size;
+
+ adev->mman.drv_vram_usage_va = NULL;
+ adev->mman.drv_vram_usage_reserved_bo = NULL;
+
+ if (adev->mman.drv_vram_usage_size == 0 ||
+ adev->mman.drv_vram_usage_size > vram_size)
+ return 0;
+
+ return amdgpu_bo_create_kernel_at(adev,
+ adev->mman.drv_vram_usage_start_offset,
+ adev->mman.drv_vram_usage_size,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->mman.drv_vram_usage_reserved_bo,
+ &adev->mman.drv_vram_usage_va);
+}
+
/*
* Memoy training reservation functions
*/
@@ -1754,6 +1768,14 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
}
/*
+ *The reserved vram for driver must be pinned to the specified
+ *place on the VRAM, so reserve it early.
+ */
+ r = amdgpu_ttm_drv_reserve_vram_init(adev);
+ if (r)
+ return r;
+
+ /*
* only NAVI10 and onwards ASIC support for IP discovery.
* If IP discovery enabled, a block of memory should be
* reserved for IP discovey.
@@ -1878,6 +1900,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL,
&adev->mman.sdma_access_ptr);
amdgpu_ttm_fw_reserve_vram_fini(adev);
+ amdgpu_ttm_drv_reserve_vram_fini(adev);
if (drm_dev_enter(adev_to_drm(adev), &idx)) {
@@ -1959,7 +1982,9 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
AMDGPU_IB_POOL_DELAYED;
int r;
- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, pool, job);
+ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ num_dw * 4, pool, job);
if (r)
return r;
@@ -1969,17 +1994,11 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
adev->gart.bo);
(*job)->vm_needs_flush = true;
}
- if (resv) {
- r = amdgpu_sync_resv(adev, &(*job)->sync, resv,
- AMDGPU_SYNC_ALWAYS,
- AMDGPU_FENCE_OWNER_UNDEFINED);
- if (r) {
- DRM_ERROR("sync failed (%d).\n", r);
- amdgpu_job_free(*job);
- return r;
- }
- }
- return 0;
+ if (!resv)
+ return 0;
+
+ return drm_sched_job_add_resv_dependencies(&(*job)->base, resv,
+ DMA_RESV_USAGE_BOOKKEEP);
}
int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
@@ -2024,8 +2043,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
if (direct_submit)
r = amdgpu_job_submit_direct(job, ring, fence);
else
- r = amdgpu_job_submit(job, &adev->mman.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, fence);
+ *fence = amdgpu_job_submit(job);
if (r)
goto error_free;
@@ -2070,16 +2088,8 @@ static int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data,
amdgpu_ring_pad_ib(ring, &job->ibs[0]);
WARN_ON(job->ibs[0].length_dw > num_dw);
- r = amdgpu_job_submit(job, &adev->mman.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, fence);
- if (r)
- goto error_free;
-
+ *fence = amdgpu_job_submit(job);
return 0;
-
-error_free:
- amdgpu_job_free(job);
- return r;
}
int amdgpu_fill_buffer(struct amdgpu_bo *bo,
@@ -2295,9 +2305,9 @@ static ssize_t amdgpu_iomem_read(struct file *f, char __user *buf,
if (p->mapping != adev->mman.bdev.dev_mapping)
return -EPERM;
- ptr = kmap(p);
+ ptr = kmap_local_page(p);
r = copy_to_user(buf, ptr + off, bytes);
- kunmap(p);
+ kunmap_local(ptr);
if (r)
return -EFAULT;
@@ -2346,9 +2356,9 @@ static ssize_t amdgpu_iomem_write(struct file *f, const char __user *buf,
if (p->mapping != adev->mman.bdev.dev_mapping)
return -EPERM;
- ptr = kmap(p);
+ ptr = kmap_local_page(p);
r = copy_from_user(ptr + off, buf, bytes);
- kunmap(p);
+ kunmap_local(ptr);
if (r)
return -EFAULT;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index 6a70818039dd..b4d8ba2789f3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -39,6 +39,8 @@
#define AMDGPU_POISON 0xd0bed0be
+struct hmm_range;
+
struct amdgpu_gtt_mgr {
struct ttm_resource_manager manager;
struct drm_mm mm;
@@ -84,6 +86,12 @@ struct amdgpu_mman {
struct amdgpu_bo *fw_vram_usage_reserved_bo;
void *fw_vram_usage_va;
+ /* driver VRAM reservation */
+ u64 drv_vram_usage_start_offset;
+ u64 drv_vram_usage_size;
+ struct amdgpu_bo *drv_vram_usage_reserved_bo;
+ void *drv_vram_usage_va;
+
/* PAGE_SIZE'd BO for process memory r/w over SDMA. */
struct amdgpu_bo *sdma_access_bo;
void *sdma_access_ptr;
@@ -149,15 +157,19 @@ void amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo);
uint64_t amdgpu_ttm_domain_start(struct amdgpu_device *adev, uint32_t type);
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
-int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages);
-bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm);
+int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages,
+ struct hmm_range **range);
+bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm,
+ struct hmm_range *range);
#else
static inline int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo,
- struct page **pages)
+ struct page **pages,
+ struct hmm_range **range)
{
return -EPERM;
}
-static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
+static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm,
+ struct hmm_range *range)
{
return false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index 1c36235b4539..552e06929229 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -125,6 +125,7 @@ enum psp_fw_type {
PSP_FW_TYPE_PSP_INTF_DRV,
PSP_FW_TYPE_PSP_DBG_DRV,
PSP_FW_TYPE_PSP_RAS_DRV,
+ PSP_FW_TYPE_MAX_INDEX,
};
/* version_major=2, version_minor=0 */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
index aad3c8b4c810..f76c19fc0392 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
@@ -22,6 +22,59 @@
*/
#include "amdgpu.h"
+#include "umc_v6_7.h"
+
+static int amdgpu_umc_convert_error_address(struct amdgpu_device *adev,
+ struct ras_err_data *err_data, uint64_t err_addr,
+ uint32_t ch_inst, uint32_t umc_inst)
+{
+ switch (adev->ip_versions[UMC_HWIP][0]) {
+ case IP_VERSION(6, 7, 0):
+ umc_v6_7_convert_error_address(adev,
+ err_data, err_addr, ch_inst, umc_inst);
+ break;
+ default:
+ dev_warn(adev->dev,
+ "UMC address to Physical address translation is not supported\n");
+ return AMDGPU_RAS_FAIL;
+ }
+
+ return AMDGPU_RAS_SUCCESS;
+}
+
+int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev,
+ uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst)
+{
+ struct ras_err_data err_data = {0, 0, 0, NULL};
+ int ret = AMDGPU_RAS_FAIL;
+
+ err_data.err_addr =
+ kcalloc(adev->umc.max_ras_err_cnt_per_query,
+ sizeof(struct eeprom_table_record), GFP_KERNEL);
+ if (!err_data.err_addr) {
+ dev_warn(adev->dev,
+ "Failed to alloc memory for umc error record in MCA notifier!\n");
+ return AMDGPU_RAS_FAIL;
+ }
+
+ /*
+ * Translate UMC channel address to Physical address
+ */
+ ret = amdgpu_umc_convert_error_address(adev, &err_data, err_addr,
+ ch_inst, umc_inst);
+ if (ret)
+ goto out;
+
+ if (amdgpu_bad_page_threshold != 0) {
+ amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
+ err_data.err_addr_cnt);
+ amdgpu_ras_save_bad_pages(adev);
+ }
+
+out:
+ kfree(err_data.err_addr);
+ return ret;
+}
static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev,
void *ras_error_status,
@@ -112,23 +165,29 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev,
return AMDGPU_RAS_SUCCESS;
}
-int amdgpu_umc_poison_handler(struct amdgpu_device *adev,
- void *ras_error_status,
- bool reset)
+int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset)
{
- int ret;
- struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
- struct ras_common_if head = {
- .block = AMDGPU_RAS_BLOCK__UMC,
- };
- struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
+ int ret = AMDGPU_RAS_SUCCESS;
- ret =
- amdgpu_umc_do_page_retirement(adev, ras_error_status, NULL, reset);
+ if (!adev->gmc.xgmi.connected_to_cpu) {
+ struct ras_err_data err_data = {0, 0, 0, NULL};
+ struct ras_common_if head = {
+ .block = AMDGPU_RAS_BLOCK__UMC,
+ };
+ struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
- if (ret == AMDGPU_RAS_SUCCESS && obj) {
- obj->err_data.ue_count += err_data->ue_count;
- obj->err_data.ce_count += err_data->ce_count;
+ ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
+
+ if (ret == AMDGPU_RAS_SUCCESS && obj) {
+ obj->err_data.ue_count += err_data.ue_count;
+ obj->err_data.ce_count += err_data.ce_count;
+ }
+ } else if (reset) {
+ /* MCA poison handler is only responsible for GPU reset,
+ * let MCA notifier do page retirement.
+ */
+ kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
+ amdgpu_ras_reset_gpu(adev);
}
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
index e46439274f3a..a6951160f13a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
@@ -51,9 +51,6 @@ struct amdgpu_umc_ras {
struct amdgpu_ras_block_object ras_block;
void (*err_cnt_init)(struct amdgpu_device *adev);
bool (*query_ras_poison_mode)(struct amdgpu_device *adev);
- void (*convert_ras_error_address)(struct amdgpu_device *adev,
- struct ras_err_data *err_data, uint64_t err_addr,
- uint32_t ch_inst, uint32_t umc_inst);
void (*ecc_info_query_ras_error_count)(struct amdgpu_device *adev,
void *ras_error_status);
void (*ecc_info_query_ras_error_address)(struct amdgpu_device *adev,
@@ -86,9 +83,7 @@ struct amdgpu_umc {
};
int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block);
-int amdgpu_umc_poison_handler(struct amdgpu_device *adev,
- void *ras_error_status,
- bool reset);
+int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset);
int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry);
@@ -101,4 +96,6 @@ void amdgpu_umc_fill_error_record(struct ras_err_data *err_data,
int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev,
void *ras_error_status,
struct amdgpu_iv_entry *entry);
+int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev,
+ uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 6eac649499d3..e00bb654e24b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -1132,7 +1132,9 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
unsigned offset_idx = 0;
unsigned offset[3] = { UVD_BASE_SI, 0, 0 };
- r = amdgpu_job_alloc_with_ib(adev, 64, direct ? AMDGPU_IB_POOL_DIRECT :
+ r = amdgpu_job_alloc_with_ib(ring->adev, &adev->uvd.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ 64, direct ? AMDGPU_IB_POOL_DIRECT :
AMDGPU_IB_POOL_DELAYED, &job);
if (r)
return r;
@@ -1175,16 +1177,13 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
if (r)
goto err_free;
} else {
- r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.base.resv,
- AMDGPU_SYNC_ALWAYS,
- AMDGPU_FENCE_OWNER_UNDEFINED);
+ r = drm_sched_job_add_resv_dependencies(&job->base,
+ bo->tbo.base.resv,
+ DMA_RESV_USAGE_KERNEL);
if (r)
goto err_free;
- r = amdgpu_job_submit(job, &adev->uvd.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, &f);
- if (r)
- goto err_free;
+ f = amdgpu_job_submit(job);
}
amdgpu_bo_reserve(bo, true);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 02cb3a12dd76..b239e874f2d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -450,8 +450,10 @@ static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
uint64_t addr;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
+ &job);
if (r)
return r;
@@ -538,7 +540,9 @@ static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
struct dma_fence *f = NULL;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
+ r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ ib_size_dw * 4,
direct ? AMDGPU_IB_POOL_DIRECT :
AMDGPU_IB_POOL_DELAYED, &job);
if (r)
@@ -570,8 +574,7 @@ static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
if (direct)
r = amdgpu_job_submit_direct(job, ring, &f);
else
- r = amdgpu_job_submit(job, &ring->adev->vce.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, &f);
+ f = amdgpu_job_submit(job);
if (r)
goto err;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 0b52af415b28..b1622ac9949f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -156,6 +156,9 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
break;
case IP_VERSION(3, 0, 2):
fw_name = FIRMWARE_VANGOGH;
+ if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
+ (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
+ adev->vcn.indirect_sram = true;
break;
case IP_VERSION(3, 0, 16):
fw_name = FIRMWARE_DIMGREY_CAVEFISH;
@@ -600,15 +603,16 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
struct amdgpu_ib *ib_msg,
struct dma_fence **fence)
{
+ u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
struct amdgpu_device *adev = ring->adev;
struct dma_fence *f = NULL;
struct amdgpu_job *job;
struct amdgpu_ib *ib;
- uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
int i, r;
- r = amdgpu_job_alloc_with_ib(adev, 64,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
+ 64, AMDGPU_IB_POOL_DIRECT,
+ &job);
if (r)
goto err;
@@ -787,8 +791,9 @@ static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring,
if (sq)
ib_size_dw += 8;
- r = amdgpu_job_alloc_with_ib(adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
+ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
+ &job);
if (r)
goto err;
@@ -916,8 +921,9 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand
if (sq)
ib_size_dw += 8;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
+ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
+ &job);
if (r)
return r;
@@ -982,8 +988,9 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han
if (sq)
ib_size_dw += 8;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
+ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
+ &job);
if (r)
return r;
@@ -1248,3 +1255,20 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
return 0;
}
+
+void amdgpu_vcn_set_ras_funcs(struct amdgpu_device *adev)
+{
+ if (!adev->vcn.ras)
+ return;
+
+ amdgpu_ras_register_ras_block(adev, &adev->vcn.ras->ras_block);
+
+ strcpy(adev->vcn.ras->ras_block.ras_comm.name, "vcn");
+ adev->vcn.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__VCN;
+ adev->vcn.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
+ adev->vcn.ras_if = &adev->vcn.ras->ras_block.ras_comm;
+
+ /* If don't define special ras_late_init function, use default ras_late_init */
+ if (!adev->vcn.ras->ras_block.ras_late_init)
+ adev->vcn.ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
index 253ea6b159df..dbb8d68a30c6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
@@ -399,5 +399,6 @@ void amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev,
int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry);
+void amdgpu_vcn_set_ras_funcs(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index c73abe54d974..15544f262ec1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -64,6 +64,10 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev)
ddev->driver_features &= ~DRIVER_ATOMIC;
adev->cg_flags = 0;
adev->pg_flags = 0;
+
+ /* enable mcbp for sriov asic_type before soc21 */
+ amdgpu_mcbp = (adev->asic_type < CHIP_IP_DISCOVERY) ? 1 : 0;
+
}
void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
@@ -424,11 +428,17 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev,
struct eeprom_table_record bp;
uint64_t retired_page;
uint32_t bp_idx, bp_cnt;
+ void *vram_usage_va = NULL;
+
+ if (adev->mman.fw_vram_usage_va)
+ vram_usage_va = adev->mman.fw_vram_usage_va;
+ else
+ vram_usage_va = adev->mman.drv_vram_usage_va;
if (bp_block_size) {
bp_cnt = bp_block_size / sizeof(uint64_t);
for (bp_idx = 0; bp_idx < bp_cnt; bp_idx++) {
- retired_page = *(uint64_t *)(adev->mman.fw_vram_usage_va +
+ retired_page = *(uint64_t *)(vram_usage_va +
bp_block_offset + bp_idx * sizeof(uint64_t));
bp.retired_page = retired_page;
@@ -639,7 +649,9 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
adev->virt.fw_reserve.p_vf2pf = NULL;
adev->virt.vf2pf_update_interval_ms = 0;
- if (adev->mman.fw_vram_usage_va != NULL) {
+ if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) {
+ DRM_WARN("Currently fw_vram and drv_vram should not have values at the same time!");
+ } else if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) {
/* go through this logic in ip_init and reset to init workqueue*/
amdgpu_virt_exchange_data(adev);
@@ -662,32 +674,40 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev)
uint32_t bp_block_size = 0;
struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL;
- if (adev->mman.fw_vram_usage_va != NULL) {
-
- adev->virt.fw_reserve.p_pf2vf =
- (struct amd_sriov_msg_pf2vf_info_header *)
- (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10));
- adev->virt.fw_reserve.p_vf2pf =
- (struct amd_sriov_msg_vf2pf_info_header *)
- (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
+ if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) {
+ if (adev->mman.fw_vram_usage_va) {
+ adev->virt.fw_reserve.p_pf2vf =
+ (struct amd_sriov_msg_pf2vf_info_header *)
+ (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10));
+ adev->virt.fw_reserve.p_vf2pf =
+ (struct amd_sriov_msg_vf2pf_info_header *)
+ (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
+ } else if (adev->mman.drv_vram_usage_va) {
+ adev->virt.fw_reserve.p_pf2vf =
+ (struct amd_sriov_msg_pf2vf_info_header *)
+ (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10));
+ adev->virt.fw_reserve.p_vf2pf =
+ (struct amd_sriov_msg_vf2pf_info_header *)
+ (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
+ }
amdgpu_virt_read_pf2vf_data(adev);
amdgpu_virt_write_vf2pf_data(adev);
/* bad page handling for version 2 */
if (adev->virt.fw_reserve.p_pf2vf->version == 2) {
- pf2vf_v2 = (struct amd_sriov_msg_pf2vf_info *)adev->virt.fw_reserve.p_pf2vf;
+ pf2vf_v2 = (struct amd_sriov_msg_pf2vf_info *)adev->virt.fw_reserve.p_pf2vf;
- bp_block_offset = ((uint64_t)pf2vf_v2->bp_block_offset_low & 0xFFFFFFFF) |
- ((((uint64_t)pf2vf_v2->bp_block_offset_high) << 32) & 0xFFFFFFFF00000000);
- bp_block_size = pf2vf_v2->bp_block_size;
+ bp_block_offset = ((uint64_t)pf2vf_v2->bp_block_offset_low & 0xFFFFFFFF) |
+ ((((uint64_t)pf2vf_v2->bp_block_offset_high) << 32) & 0xFFFFFFFF00000000);
+ bp_block_size = pf2vf_v2->bp_block_size;
- if (bp_block_size && !adev->virt.ras_init_done)
- amdgpu_virt_init_ras_err_handler_data(adev);
+ if (bp_block_size && !adev->virt.ras_init_done)
+ amdgpu_virt_init_ras_err_handler_data(adev);
- if (adev->virt.ras_init_done)
- amdgpu_virt_add_bad_page(adev, bp_block_offset, bp_block_size);
- }
+ if (adev->virt.ras_init_done)
+ amdgpu_virt_add_bad_page(adev, bp_block_offset, bp_block_size);
+ }
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
index 49c4347d154c..2b9d806e23af 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -75,6 +75,8 @@ struct amdgpu_vf_error_buffer {
uint64_t data[AMDGPU_VF_ERROR_ENTRY_SIZE];
};
+enum idh_request;
+
/**
* struct amdgpu_virt_ops - amdgpu device virt operations
*/
@@ -84,7 +86,8 @@ struct amdgpu_virt_ops {
int (*req_init_data)(struct amdgpu_device *adev);
int (*reset_gpu)(struct amdgpu_device *adev);
int (*wait_reset)(struct amdgpu_device *adev);
- void (*trans_msg)(struct amdgpu_device *adev, u32 req, u32 data1, u32 data2, u32 data3);
+ void (*trans_msg)(struct amdgpu_device *adev, enum idh_request req,
+ u32 data1, u32 data2, u32 data3);
};
/*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
index 500a1dc4fe02..53ff91fc6cf6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
@@ -498,7 +498,7 @@ static int amdgpu_vkms_sw_init(void *handle)
adev_to_drm(adev)->mode_config.preferred_depth = 24;
adev_to_drm(adev)->mode_config.prefer_shadow = 1;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
+ adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
@@ -513,6 +513,10 @@ static int amdgpu_vkms_sw_init(void *handle)
return r;
}
+ r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ if (r)
+ return r;
+
drm_kms_helper_poll_init(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = true;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 2291aa14d888..c05cff979004 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -45,22 +45,43 @@
/**
* DOC: GPUVM
*
- * GPUVM is similar to the legacy gart on older asics, however
- * rather than there being a single global gart table
- * for the entire GPU, there are multiple VM page tables active
- * at any given time. The VM page tables can contain a mix
- * vram pages and system memory pages and system memory pages
+ * GPUVM is the MMU functionality provided on the GPU.
+ * GPUVM is similar to the legacy GART on older asics, however
+ * rather than there being a single global GART table
+ * for the entire GPU, there can be multiple GPUVM page tables active
+ * at any given time. The GPUVM page tables can contain a mix
+ * VRAM pages and system pages (both memory and MMIO) and system pages
* can be mapped as snooped (cached system pages) or unsnooped
* (uncached system pages).
- * Each VM has an ID associated with it and there is a page table
- * associated with each VMID. When executing a command buffer,
- * the kernel tells the ring what VMID to use for that command
+ *
+ * Each active GPUVM has an ID associated with it and there is a page table
+ * linked with each VMID. When executing a command buffer,
+ * the kernel tells the engine what VMID to use for that command
* buffer. VMIDs are allocated dynamically as commands are submitted.
* The userspace drivers maintain their own address space and the kernel
* sets up their pages tables accordingly when they submit their
* command buffers and a VMID is assigned.
- * Cayman/Trinity support up to 8 active VMs at any given time;
- * SI supports 16.
+ * The hardware supports up to 16 active GPUVMs at any given time.
+ *
+ * Each GPUVM is represented by a 1-2 or 1-5 level page table, depending
+ * on the ASIC family. GPUVM supports RWX attributes on each page as well
+ * as other features such as encryption and caching attributes.
+ *
+ * VMID 0 is special. It is the GPUVM used for the kernel driver. In
+ * addition to an aperture managed by a page table, VMID 0 also has
+ * several other apertures. There is an aperture for direct access to VRAM
+ * and there is a legacy AGP aperture which just forwards accesses directly
+ * to the matching system physical addresses (or IOVAs when an IOMMU is
+ * present). These apertures provide direct access to these memories without
+ * incurring the overhead of a page table. VMID 0 is used by the kernel
+ * driver for tasks like memory management.
+ *
+ * GPU clients (i.e., engines on the GPU) use GPUVM VMIDs to access memory.
+ * For user applications, each application can have their own unique GPUVM
+ * address space. The application manages the address space and the kernel
+ * driver manages the GPUVM page tables for each process. If an GPU client
+ * accesses an invalid page, it will generate a GPU page fault, similar to
+ * accessing an invalid page on a CPU.
*/
#define START(node) ((node)->start)
@@ -143,32 +164,6 @@ int amdgpu_vm_set_pasid(struct amdgpu_device *adev, struct amdgpu_vm *vm,
return 0;
}
-/*
- * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS
- * happens while holding this lock anywhere to prevent deadlocks when
- * an MMU notifier runs in reclaim-FS context.
- */
-static inline void amdgpu_vm_eviction_lock(struct amdgpu_vm *vm)
-{
- mutex_lock(&vm->eviction_lock);
- vm->saved_flags = memalloc_noreclaim_save();
-}
-
-static inline int amdgpu_vm_eviction_trylock(struct amdgpu_vm *vm)
-{
- if (mutex_trylock(&vm->eviction_lock)) {
- vm->saved_flags = memalloc_noreclaim_save();
- return 1;
- }
- return 0;
-}
-
-static inline void amdgpu_vm_eviction_unlock(struct amdgpu_vm *vm)
-{
- memalloc_noreclaim_restore(vm->saved_flags);
- mutex_unlock(&vm->eviction_lock);
-}
-
/**
* amdgpu_vm_bo_evicted - vm_bo is evicted
*
@@ -567,6 +562,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync)
return 0;
+ amdgpu_ring_ib_begin(ring);
if (ring->funcs->init_cond_exec)
patch_offset = amdgpu_ring_init_cond_exec(ring);
@@ -627,6 +623,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
amdgpu_ring_emit_switch_buffer(ring);
amdgpu_ring_emit_switch_buffer(ring);
}
+ amdgpu_ring_ib_end(ring);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 83acb7bd80fe..6546e786bf00 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -492,7 +492,48 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m);
*/
static inline uint64_t amdgpu_vm_tlb_seq(struct amdgpu_vm *vm)
{
+ unsigned long flags;
+ spinlock_t *lock;
+
+ /*
+ * Workaround to stop racing between the fence signaling and handling
+ * the cb. The lock is static after initially setting it up, just make
+ * sure that the dma_fence structure isn't freed up.
+ */
+ rcu_read_lock();
+ lock = vm->last_tlb_flush->lock;
+ rcu_read_unlock();
+
+ spin_lock_irqsave(lock, flags);
+ spin_unlock_irqrestore(lock, flags);
+
return atomic64_read(&vm->tlb_seq);
}
+/*
+ * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS
+ * happens while holding this lock anywhere to prevent deadlocks when
+ * an MMU notifier runs in reclaim-FS context.
+ */
+static inline void amdgpu_vm_eviction_lock(struct amdgpu_vm *vm)
+{
+ mutex_lock(&vm->eviction_lock);
+ vm->saved_flags = memalloc_noreclaim_save();
+}
+
+static inline bool amdgpu_vm_eviction_trylock(struct amdgpu_vm *vm)
+{
+ if (mutex_trylock(&vm->eviction_lock)) {
+ vm->saved_flags = memalloc_noreclaim_save();
+ return true;
+ }
+ return false;
+}
+
+static inline void amdgpu_vm_eviction_unlock(struct amdgpu_vm *vm)
+{
+ memalloc_noreclaim_restore(vm->saved_flags);
+ mutex_unlock(&vm->eviction_lock);
+}
+
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
index 358b91243e37..b5f3bba851db 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
@@ -597,7 +597,9 @@ static int amdgpu_vm_pt_alloc(struct amdgpu_device *adev,
if (entry->bo)
return 0;
+ amdgpu_vm_eviction_unlock(vm);
r = amdgpu_vm_pt_create(adev, vm, cursor->level, immediate, &pt);
+ amdgpu_vm_eviction_lock(vm);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c
index 69e105fa41f6..59cf64216fbb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c
@@ -47,6 +47,32 @@ static int amdgpu_vm_sdma_map_table(struct amdgpu_bo_vm *table)
return r;
}
+/* Allocate a new job for @count PTE updates */
+static int amdgpu_vm_sdma_alloc_job(struct amdgpu_vm_update_params *p,
+ unsigned int count)
+{
+ enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE
+ : AMDGPU_IB_POOL_DELAYED;
+ struct drm_sched_entity *entity = p->immediate ? &p->vm->immediate
+ : &p->vm->delayed;
+ unsigned int ndw;
+ int r;
+
+ /* estimate how many dw we need */
+ ndw = AMDGPU_VM_SDMA_MIN_NUM_DW;
+ if (p->pages_addr)
+ ndw += count * 2;
+ ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW);
+
+ r = amdgpu_job_alloc_with_ib(p->adev, entity, AMDGPU_FENCE_OWNER_VM,
+ ndw * 4, pool, &p->job);
+ if (r)
+ return r;
+
+ p->num_dw_left = ndw;
+ return 0;
+}
+
/**
* amdgpu_vm_sdma_prepare - prepare SDMA command submission
*
@@ -61,21 +87,22 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p,
struct dma_resv *resv,
enum amdgpu_sync_mode sync_mode)
{
- enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE
- : AMDGPU_IB_POOL_DELAYED;
- unsigned int ndw = AMDGPU_VM_SDMA_MIN_NUM_DW;
+ struct amdgpu_sync sync;
int r;
- r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool, &p->job);
+ r = amdgpu_vm_sdma_alloc_job(p, 0);
if (r)
return r;
- p->num_dw_left = ndw;
-
if (!resv)
return 0;
- return amdgpu_sync_resv(p->adev, &p->job->sync, resv, sync_mode, p->vm);
+ amdgpu_sync_create(&sync);
+ r = amdgpu_sync_resv(p->adev, &sync, resv, sync_mode, p->vm);
+ if (!r)
+ r = amdgpu_sync_push_to_job(&sync, p->job);
+ amdgpu_sync_free(&sync);
+ return r;
}
/**
@@ -91,20 +118,16 @@ static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p,
struct dma_fence **fence)
{
struct amdgpu_ib *ib = p->job->ibs;
- struct drm_sched_entity *entity;
struct amdgpu_ring *ring;
struct dma_fence *f;
- int r;
- entity = p->immediate ? &p->vm->immediate : &p->vm->delayed;
- ring = container_of(entity->rq->sched, struct amdgpu_ring, sched);
+ ring = container_of(p->vm->delayed.rq->sched, struct amdgpu_ring,
+ sched);
WARN_ON(ib->length_dw == 0);
amdgpu_ring_pad_ib(ring, ib);
WARN_ON(ib->length_dw > p->num_dw_left);
- r = amdgpu_job_submit(p->job, entity, AMDGPU_FENCE_OWNER_VM, &f);
- if (r)
- goto error;
+ f = amdgpu_job_submit(p->job);
if (p->unlocked) {
struct dma_fence *tmp = dma_fence_get(f);
@@ -127,10 +150,6 @@ static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p,
}
dma_fence_put(f);
return 0;
-
-error:
- amdgpu_job_free(p->job);
- return r;
}
/**
@@ -210,8 +229,6 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p,
uint64_t flags)
{
struct amdgpu_bo *bo = &vmbo->bo;
- enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE
- : AMDGPU_IB_POOL_DELAYED;
struct dma_resv_iter cursor;
unsigned int i, ndw, nptes;
struct dma_fence *fence;
@@ -221,7 +238,7 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p,
/* Wait for PD/PT moves to be completed */
dma_resv_iter_begin(&cursor, bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
- r = amdgpu_sync_fence(&p->job->sync, fence);
+ r = drm_sched_job_add_dependency(&p->job->base, fence);
if (r) {
dma_resv_iter_end(&cursor);
return r;
@@ -238,19 +255,9 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p,
if (r)
return r;
- /* estimate how many dw we need */
- ndw = 32;
- if (p->pages_addr)
- ndw += count * 2;
- ndw = max(ndw, AMDGPU_VM_SDMA_MIN_NUM_DW);
- ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW);
-
- r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool,
- &p->job);
+ r = amdgpu_vm_sdma_alloc_job(p, count);
if (r)
return r;
-
- p->num_dw_left = ndw;
}
if (!p->pages_addr) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 73a517bcf5c1..faa12146635c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -435,11 +435,11 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
if (place->flags & TTM_PL_FLAG_TOPDOWN)
vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
- if (fpfn || lpfn != man->size)
+ if (fpfn || lpfn != mgr->mm.size)
/* Allocate blocks in desired range */
vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
- remaining_size = (u64)vres->base.num_pages << PAGE_SHIFT;
+ remaining_size = (u64)vres->base.size;
mutex_lock(&mgr->lock);
while (remaining_size) {
@@ -498,7 +498,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
LIST_HEAD(temp);
trim_list = &vres->blocks;
- original_size = (u64)vres->base.num_pages << PAGE_SHIFT;
+ original_size = (u64)vres->base.size;
/*
* If size value is rounded up to min_block_size, trim the last
@@ -533,8 +533,8 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
amdgpu_vram_mgr_block_size(block);
start >>= PAGE_SHIFT;
- if (start > vres->base.num_pages)
- start -= vres->base.num_pages;
+ if (start > PFN_UP(vres->base.size))
+ start -= PFN_UP(vres->base.size);
else
start = 0;
vres->base.start = max(vres->base.start, start);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
index 47159e9a0884..4b9e7b050ccd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -386,7 +386,6 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
if (ret) {
dev_err(adev->dev, "XGMI: failed initializing kobject for xgmi hive\n");
kobject_put(&hive->kobj);
- kfree(hive);
hive = NULL;
goto pro_end;
}
@@ -410,7 +409,6 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
dev_err(adev->dev, "XGMI: failed initializing reset domain for xgmi hive\n");
ret = -ENOMEM;
kobject_put(&hive->kobj);
- kfree(hive);
hive = NULL;
goto pro_end;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
index 6be9ac2b9c5b..18ae9433e463 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -2081,8 +2081,11 @@ amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder)
}
}
record += fake_edid_record->ucFakeEDIDLength ?
- fake_edid_record->ucFakeEDIDLength + 2 :
- sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
+ struct_size(fake_edid_record,
+ ucFakeEDIDString,
+ fake_edid_record->ucFakeEDIDLength) :
+ /* empty fake edid record must be 3 bytes long */
+ sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
break;
case LCD_PANEL_RESOLUTION_RECORD_TYPE:
panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 288fce7dc0ed..248f1a4e915f 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -21,6 +21,7 @@
*
*/
+#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
@@ -2800,8 +2801,6 @@ static int dce_v10_0_sw_init(void *handle)
adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
-
r = amdgpu_display_modeset_create_props(adev);
if (r)
return r;
@@ -2830,6 +2829,17 @@ static int dce_v10_0_sw_init(void *handle)
if (r)
return r;
+ /* Disable vblank IRQs aggressively for power-saving */
+ /* XXX: can this be enabled for DC? */
+ adev_to_drm(adev)->vblank_disable_immediate = true;
+
+ r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ if (r)
+ return r;
+
+ INIT_WORK(&adev->hotplug_work,
+ amdgpu_display_hotplug_work_func);
+
drm_kms_helper_poll_init(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = true;
@@ -2892,6 +2902,8 @@ static int dce_v10_0_hw_fini(void *handle)
dce_v10_0_pageflip_interrupt_fini(adev);
+ flush_work(&adev->hotplug_work);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index cbe5250b31cb..cd9c19060d89 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -21,6 +21,7 @@
*
*/
+#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
@@ -2918,8 +2919,6 @@ static int dce_v11_0_sw_init(void *handle)
adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
-
r = amdgpu_display_modeset_create_props(adev);
if (r)
return r;
@@ -2949,6 +2948,17 @@ static int dce_v11_0_sw_init(void *handle)
if (r)
return r;
+ /* Disable vblank IRQs aggressively for power-saving */
+ /* XXX: can this be enabled for DC? */
+ adev_to_drm(adev)->vblank_disable_immediate = true;
+
+ r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ if (r)
+ return r;
+
+ INIT_WORK(&adev->hotplug_work,
+ amdgpu_display_hotplug_work_func);
+
drm_kms_helper_poll_init(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = true;
@@ -3022,6 +3032,8 @@ static int dce_v11_0_hw_fini(void *handle)
dce_v11_0_pageflip_interrupt_fini(adev);
+ flush_work(&adev->hotplug_work);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index b1c44fab074f..76323deecc58 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -23,6 +23,7 @@
#include <linux/pci.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
@@ -2675,7 +2676,6 @@ static int dce_v6_0_sw_init(void *handle)
adev_to_drm(adev)->mode_config.preferred_depth = 24;
adev_to_drm(adev)->mode_config.prefer_shadow = 1;
adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
r = amdgpu_display_modeset_create_props(adev);
if (r)
@@ -2706,6 +2706,18 @@ static int dce_v6_0_sw_init(void *handle)
if (r)
return r;
+ /* Disable vblank IRQs aggressively for power-saving */
+ /* XXX: can this be enabled for DC? */
+ adev_to_drm(adev)->vblank_disable_immediate = true;
+
+ r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ if (r)
+ return r;
+
+ /* Pre-DCE11 */
+ INIT_WORK(&adev->hotplug_work,
+ amdgpu_display_hotplug_work_func);
+
drm_kms_helper_poll_init(adev_to_drm(adev));
return r;
@@ -2764,6 +2776,8 @@ static int dce_v6_0_hw_fini(void *handle)
dce_v6_0_pageflip_interrupt_fini(adev);
+ flush_work(&adev->hotplug_work);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index a22b45c92792..01cf3ab111cb 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -21,6 +21,7 @@
*
*/
+#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
@@ -2701,8 +2702,6 @@ static int dce_v8_0_sw_init(void *handle)
adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
-
r = amdgpu_display_modeset_create_props(adev);
if (r)
return r;
@@ -2731,6 +2730,18 @@ static int dce_v8_0_sw_init(void *handle)
if (r)
return r;
+ /* Disable vblank IRQs aggressively for power-saving */
+ /* XXX: can this be enabled for DC? */
+ adev_to_drm(adev)->vblank_disable_immediate = true;
+
+ r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ if (r)
+ return r;
+
+ /* Pre-DCE11 */
+ INIT_WORK(&adev->hotplug_work,
+ amdgpu_display_hotplug_work_func);
+
drm_kms_helper_poll_init(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = true;
@@ -2791,6 +2802,8 @@ static int dce_v8_0_hw_fini(void *handle)
dce_v8_0_pageflip_interrupt_fini(adev);
+ flush_work(&adev->hotplug_work);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index af94ac580d3e..49d34c7bbf20 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -4453,8 +4453,6 @@ static void gfx_v10_0_gpu_early_init(struct amdgpu_device *adev)
{
u32 gb_addr_config;
- adev->gfx.funcs = &gfx_v10_0_gfx_funcs;
-
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(10, 1, 10):
case IP_VERSION(10, 1, 1):
@@ -6911,6 +6909,8 @@ static int gfx_v10_0_kiq_init_queue(struct amdgpu_ring *ring)
mutex_unlock(&adev->srbm_mutex);
} else {
memset((void *)mqd, 0, sizeof(*mqd));
+ if (amdgpu_sriov_vf(adev) && adev->in_suspend)
+ amdgpu_ring_clear_ring(ring);
mutex_lock(&adev->srbm_mutex);
nv_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
amdgpu_ring_init_mqd(ring);
@@ -7593,6 +7593,8 @@ static int gfx_v10_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ adev->gfx.funcs = &gfx_v10_0_gfx_funcs;
+
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(10, 1, 10):
case IP_VERSION(10, 1, 1):
@@ -8489,7 +8491,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
control |= ib->length_dw | (vmid << 24);
- if ((amdgpu_sriov_vf(ring->adev) || amdgpu_mcbp) && (ib->flags & AMDGPU_IB_FLAG_PREEMPT)) {
+ if (amdgpu_mcbp && (ib->flags & AMDGPU_IB_FLAG_PREEMPT)) {
control |= INDIRECT_BUFFER_PRE_ENB(1);
if (flags & AMDGPU_IB_PREEMPTED)
@@ -8664,7 +8666,7 @@ static void gfx_v10_0_ring_emit_cntxcntl(struct amdgpu_ring *ring,
{
uint32_t dw2 = 0;
- if (amdgpu_mcbp || amdgpu_sriov_vf(ring->adev))
+ if (amdgpu_mcbp)
gfx_v10_0_ring_emit_ce_meta(ring,
(!amdgpu_sriov_vf(ring->adev) && flags & AMDGPU_IB_PREEMPTED) ? true : false);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index 0fecc5bf45bc..a56c6e106d00 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -77,6 +77,10 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_3_pfp.bin");
MODULE_FIRMWARE("amdgpu/gc_11_0_3_me.bin");
MODULE_FIRMWARE("amdgpu/gc_11_0_3_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_11_0_3_rlc.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_pfp.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_me.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_mec.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_rlc.bin");
static const struct soc15_reg_golden golden_settings_gc_11_0_1[] =
{
@@ -262,6 +266,7 @@ static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev)
{
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
soc15_program_register_sequence(adev,
golden_settings_gc_11_0_1,
(const u32)ARRAY_SIZE(golden_settings_gc_11_0_1));
@@ -843,7 +848,6 @@ static const struct amdgpu_gfx_funcs gfx_v11_0_gfx_funcs = {
static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
{
- adev->gfx.funcs = &gfx_v11_0_gfx_funcs;
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(11, 0, 0):
@@ -856,6 +860,7 @@ static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
adev->gfx.config.sc_earlyz_tile_fifo_size = 0x4C0;
break;
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
adev->gfx.config.max_hw_contexts = 8;
adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
@@ -1285,6 +1290,7 @@ static int gfx_v11_0_sw_init(void *handle)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
adev->gfx.me.num_me = 1;
adev->gfx.me.num_pipe_per_me = 1;
adev->gfx.me.num_queue_per_pipe = 1;
@@ -1626,7 +1632,8 @@ static void gfx_v11_0_constants_init(struct amdgpu_device *adev)
u32 tmp;
int i;
- WREG32_FIELD15_PREREG(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff);
+ if (!amdgpu_sriov_vf(adev))
+ WREG32_FIELD15_PREREG(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff);
gfx_v11_0_setup_rb(adev);
gfx_v11_0_get_cu_info(adev, &adev->gfx.cu_info);
@@ -2486,7 +2493,8 @@ static int gfx_v11_0_wait_for_rlc_autoload_complete(struct amdgpu_device *adev)
for (i = 0; i < adev->usec_timeout; i++) {
cp_status = RREG32_SOC15(GC, 0, regCP_STAT);
- if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(11, 0, 1))
+ if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(11, 0, 1) ||
+ adev->ip_versions[GC_HWIP][0] == IP_VERSION(11, 0, 4))
bootload_status = RREG32_SOC15(GC, 0,
regRLC_RLCS_BOOTLOAD_STATUS_gc_11_0_1);
else
@@ -4004,6 +4012,8 @@ static int gfx_v11_0_kiq_init_queue(struct amdgpu_ring *ring)
mutex_unlock(&adev->srbm_mutex);
} else {
memset((void *)mqd, 0, sizeof(*mqd));
+ if (amdgpu_sriov_vf(adev) && adev->in_suspend)
+ amdgpu_ring_clear_ring(ring);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
amdgpu_ring_init_mqd(ring);
@@ -4390,7 +4400,6 @@ static int gfx_v11_0_hw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int r;
- uint32_t tmp;
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
@@ -4409,15 +4418,14 @@ static int gfx_v11_0_hw_fini(void *handle)
amdgpu_mes_kiq_hw_fini(adev);
}
- if (amdgpu_sriov_vf(adev)) {
- gfx_v11_0_cp_gfx_enable(adev, false);
- /* Program KIQ position of RLC_CP_SCHEDULERS during destroy */
- tmp = RREG32_SOC15(GC, 0, regRLC_CP_SCHEDULERS);
- tmp &= 0xffffff00;
- WREG32_SOC15(GC, 0, regRLC_CP_SCHEDULERS, tmp);
-
+ if (amdgpu_sriov_vf(adev))
+ /* Remove the steps disabling CPG and clearing KIQ position,
+ * so that CP could perform IDLE-SAVE during switch. Those
+ * steps are necessary to avoid a DMAR error in gfx9 but it is
+ * not reproduced on gfx11.
+ */
return 0;
- }
+
gfx_v11_0_cp_enable(adev, false);
gfx_v11_0_enable_gui_idle_interrupt(adev, false);
@@ -4656,6 +4664,8 @@ static int gfx_v11_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ adev->gfx.funcs = &gfx_v11_0_gfx_funcs;
+
adev->gfx.num_gfx_rings = GFX11_NUM_GFX_RINGS;
adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
AMDGPU_MAX_COMPUTE_RINGS);
@@ -4673,6 +4683,26 @@ static int gfx_v11_0_early_init(void *handle)
return 0;
}
+static int gfx_v11_0_ras_late_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ struct ras_common_if *gfx_common_if;
+ int ret;
+
+ gfx_common_if = kzalloc(sizeof(struct ras_common_if), GFP_KERNEL);
+ if (!gfx_common_if)
+ return -ENOMEM;
+
+ gfx_common_if->block = AMDGPU_RAS_BLOCK__GFX;
+
+ ret = amdgpu_ras_feature_enable(adev, gfx_common_if, true);
+ if (ret)
+ dev_warn(adev->dev, "Failed to enable gfx11 ras feature\n");
+
+ kfree(gfx_common_if);
+ return 0;
+}
+
static int gfx_v11_0_late_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -4686,6 +4716,12 @@ static int gfx_v11_0_late_init(void *handle)
if (r)
return r;
+ if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(11, 0, 3)) {
+ r = gfx_v11_0_ras_late_init(handle);
+ if (r)
+ return r;
+ }
+
return 0;
}
@@ -5022,6 +5058,7 @@ static void gfx_v11_cntl_power_gating(struct amdgpu_device *adev, bool enable)
if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
WREG32_SOC15(GC, 0, regRLC_PG_DELAY_3, RLC_PG_DELAY_3_DEFAULT_GC_11_0_1);
break;
default:
@@ -5055,6 +5092,7 @@ static int gfx_v11_0_set_powergating_state(void *handle,
amdgpu_gfx_off_ctrl(adev, enable);
break;
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
gfx_v11_cntl_pg(adev, enable);
amdgpu_gfx_off_ctrl(adev, enable);
break;
@@ -5078,6 +5116,7 @@ static int gfx_v11_0_set_clockgating_state(void *handle,
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
gfx_v11_0_update_gfx_clock_gating(adev,
state == AMD_CG_STATE_GATE);
break;
@@ -5299,7 +5338,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
control |= ib->length_dw | (vmid << 24);
- if ((amdgpu_sriov_vf(ring->adev) || amdgpu_mcbp) && (ib->flags & AMDGPU_IB_FLAG_PREEMPT)) {
+ if (amdgpu_mcbp && (ib->flags & AMDGPU_IB_FLAG_PREEMPT)) {
control |= INDIRECT_BUFFER_PRE_ENB(1);
if (flags & AMDGPU_IB_PREEMPTED)
@@ -6060,6 +6099,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = {
.align_mask = 0xff,
.nop = PACKET3(PACKET3_NOP, 0x3FFF),
.support_64bit_ptrs = true,
+ .secure_submission_supported = true,
.vmhub = AMDGPU_GFXHUB_0,
.get_rptr = gfx_v11_0_ring_get_rptr_gfx,
.get_wptr = gfx_v11_0_ring_get_wptr_gfx,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 7f0b18b0d4c4..d47135606e3e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -4643,6 +4643,8 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring)
memset((void *)mqd, 0, sizeof(struct vi_mqd_allocation));
((struct vi_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF;
((struct vi_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF;
+ if (amdgpu_sriov_vf(adev) && adev->in_suspend)
+ amdgpu_ring_clear_ring(ring);
mutex_lock(&adev->srbm_mutex);
vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v8_0_mqd_init(ring);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 0320be4a5fc6..f202b45c413c 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -47,6 +47,7 @@
#include "amdgpu_ras.h"
+#include "amdgpu_ring_mux.h"
#include "gfx_v9_4.h"
#include "gfx_v9_0.h"
#include "gfx_v9_4_2.h"
@@ -56,6 +57,7 @@
#include "asic_reg/gc/gc_9_0_default.h"
#define GFX9_NUM_GFX_RINGS 1
+#define GFX9_NUM_SW_GFX_RINGS 2
#define GFX9_MEC_HPD_SIZE 4096
#define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
#define RLC_SAVE_RESTORE_ADDR_STARTING_OFFSET 0x00000000L
@@ -753,7 +755,7 @@ static void gfx_v9_0_set_rlc_funcs(struct amdgpu_device *adev);
static int gfx_v9_0_get_cu_info(struct amdgpu_device *adev,
struct amdgpu_cu_info *cu_info);
static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev);
-static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring);
+static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume);
static u64 gfx_v9_0_ring_get_rptr_compute(struct amdgpu_ring *ring);
static void gfx_v9_0_query_ras_error_count(struct amdgpu_device *adev,
void *ras_error_status);
@@ -826,9 +828,10 @@ static void gfx_v9_0_kiq_unmap_queues(struct amdgpu_ring *kiq_ring,
PACKET3_UNMAP_QUEUES_DOORBELL_OFFSET0(ring->doorbell_index));
if (action == PREEMPT_QUEUES_NO_UNMAP) {
- amdgpu_ring_write(kiq_ring, lower_32_bits(gpu_addr));
- amdgpu_ring_write(kiq_ring, upper_32_bits(gpu_addr));
- amdgpu_ring_write(kiq_ring, seq);
+ amdgpu_ring_write(kiq_ring, lower_32_bits(ring->wptr & ring->buf_mask));
+ amdgpu_ring_write(kiq_ring, 0);
+ amdgpu_ring_write(kiq_ring, 0);
+
} else {
amdgpu_ring_write(kiq_ring, 0);
amdgpu_ring_write(kiq_ring, 0);
@@ -1564,7 +1567,7 @@ static void gfx_v9_0_init_always_on_cu_mask(struct amdgpu_device *adev)
mask = 1;
cu_bitmap = 0;
counter = 0;
- gfx_v9_0_select_se_sh(adev, i, j, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, i, j, 0xffffffff);
for (k = 0; k < adev->gfx.config.max_cu_per_sh; k ++) {
if (cu_info->bitmap[i][j] & mask) {
@@ -1583,7 +1586,7 @@ static void gfx_v9_0_init_always_on_cu_mask(struct amdgpu_device *adev)
cu_info->ao_cu_bitmap[i][j] = cu_bitmap;
}
}
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
}
@@ -1605,7 +1608,7 @@ static void gfx_v9_0_init_lbpw(struct amdgpu_device *adev)
mutex_lock(&adev->grbm_idx_mutex);
/* set mmRLC_LB_INIT_CU_MASK thru broadcast mode to enable all SE/SH*/
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
WREG32_SOC15(GC, 0, mmRLC_LB_INIT_CU_MASK, 0xffffffff);
/* set mmRLC_LB_PARAMS = 0x003F_1006 */
@@ -1654,7 +1657,7 @@ static void gfx_v9_4_init_lbpw(struct amdgpu_device *adev)
mutex_lock(&adev->grbm_idx_mutex);
/* set mmRLC_LB_INIT_CU_MASK thru broadcast mode to enable all SE/SH*/
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
WREG32_SOC15(GC, 0, mmRLC_LB_INIT_CU_MASK, 0xffffffff);
/* set mmRLC_LB_PARAMS = 0x003F_1006 */
@@ -1919,8 +1922,6 @@ static int gfx_v9_0_gpu_early_init(struct amdgpu_device *adev)
u32 gb_addr_config;
int err;
- adev->gfx.funcs = &gfx_v9_0_gfx_funcs;
-
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(9, 0, 1):
adev->gfx.config.max_hw_contexts = 8;
@@ -2105,6 +2106,7 @@ static int gfx_v9_0_sw_init(void *handle)
struct amdgpu_ring *ring;
struct amdgpu_kiq *kiq;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ unsigned int hw_prio;
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(9, 0, 1):
@@ -2188,6 +2190,9 @@ static int gfx_v9_0_sw_init(void *handle)
sprintf(ring->name, "gfx_%d", i);
ring->use_doorbell = true;
ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1;
+
+ /* disable scheduler on the real ring */
+ ring->no_scheduler = true;
r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq,
AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP,
AMDGPU_RING_PRIO_DEFAULT, NULL);
@@ -2195,6 +2200,41 @@ static int gfx_v9_0_sw_init(void *handle)
return r;
}
+ /* set up the software rings */
+ if (adev->gfx.num_gfx_rings) {
+ for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++) {
+ ring = &adev->gfx.sw_gfx_ring[i];
+ ring->ring_obj = NULL;
+ sprintf(ring->name, amdgpu_sw_ring_name(i));
+ ring->use_doorbell = true;
+ ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1;
+ ring->is_sw_ring = true;
+ hw_prio = amdgpu_sw_ring_priority(i);
+ r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq,
+ AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP, hw_prio,
+ NULL);
+ if (r)
+ return r;
+ ring->wptr = 0;
+ }
+
+ /* init the muxer and add software rings */
+ r = amdgpu_ring_mux_init(&adev->gfx.muxer, &adev->gfx.gfx_ring[0],
+ GFX9_NUM_SW_GFX_RINGS);
+ if (r) {
+ DRM_ERROR("amdgpu_ring_mux_init failed(%d)\n", r);
+ return r;
+ }
+ for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++) {
+ r = amdgpu_ring_mux_add_sw_ring(&adev->gfx.muxer,
+ &adev->gfx.sw_gfx_ring[i]);
+ if (r) {
+ DRM_ERROR("amdgpu_ring_mux_add_sw_ring failed(%d)\n", r);
+ return r;
+ }
+ }
+ }
+
/* set up the compute queues - allocate horizontally across pipes */
ring_id = 0;
for (i = 0; i < adev->gfx.mec.num_mec; ++i) {
@@ -2245,6 +2285,12 @@ static int gfx_v9_0_sw_fini(void *handle)
int i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ if (adev->gfx.num_gfx_rings) {
+ for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++)
+ amdgpu_ring_fini(&adev->gfx.sw_gfx_ring[i]);
+ amdgpu_ring_mux_fini(&adev->gfx.muxer);
+ }
+
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
for (i = 0; i < adev->gfx.num_compute_rings; i++)
@@ -2324,13 +2370,13 @@ static void gfx_v9_0_setup_rb(struct amdgpu_device *adev)
mutex_lock(&adev->grbm_idx_mutex);
for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
- gfx_v9_0_select_se_sh(adev, i, j, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, i, j, 0xffffffff);
data = gfx_v9_0_get_rb_active_bitmap(adev);
active_rbs |= data << ((i * adev->gfx.config.max_sh_per_se + j) *
rb_bitmap_width_per_sh);
}
}
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
adev->gfx.config.backend_enable_mask = active_rbs;
@@ -2467,14 +2513,14 @@ static void gfx_v9_0_wait_for_rlc_serdes(struct amdgpu_device *adev)
mutex_lock(&adev->grbm_idx_mutex);
for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
- gfx_v9_0_select_se_sh(adev, i, j, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, i, j, 0xffffffff);
for (k = 0; k < adev->usec_timeout; k++) {
if (RREG32_SOC15(GC, 0, mmRLC_SERDES_CU_MASTER_BUSY) == 0)
break;
udelay(1);
}
if (k == adev->usec_timeout) {
- gfx_v9_0_select_se_sh(adev, 0xffffffff,
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff,
0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
DRM_INFO("Timeout wait for RLC serdes %u,%u\n",
@@ -2483,7 +2529,7 @@ static void gfx_v9_0_wait_for_rlc_serdes(struct amdgpu_device *adev)
}
}
}
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
mask = RLC_SERDES_NONCU_MASTER_BUSY__SE_MASTER_BUSY_MASK |
@@ -3583,6 +3629,8 @@ static int gfx_v9_0_kiq_init_queue(struct amdgpu_ring *ring)
memset((void *)mqd, 0, sizeof(struct v9_mqd_allocation));
((struct v9_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF;
((struct v9_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF;
+ if (amdgpu_sriov_vf(adev) && adev->in_suspend)
+ amdgpu_ring_clear_ring(ring);
mutex_lock(&adev->srbm_mutex);
soc15_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v9_0_mqd_init(ring);
@@ -4539,6 +4587,8 @@ static int gfx_v9_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ adev->gfx.funcs = &gfx_v9_0_gfx_funcs;
+
if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 1) ||
adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2))
adev->gfx.num_gfx_rings = 0;
@@ -5155,11 +5205,17 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
control |= ib->length_dw | (vmid << 24);
- if (amdgpu_sriov_vf(ring->adev) && (ib->flags & AMDGPU_IB_FLAG_PREEMPT)) {
+ if (ib->flags & AMDGPU_IB_FLAG_PREEMPT) {
control |= INDIRECT_BUFFER_PRE_ENB(1);
+ if (flags & AMDGPU_IB_PREEMPTED)
+ control |= INDIRECT_BUFFER_PRE_RESUME(1);
+
if (!(ib->flags & AMDGPU_IB_FLAG_CE) && vmid)
- gfx_v9_0_ring_emit_de_meta(ring);
+ gfx_v9_0_ring_emit_de_meta(ring,
+ (!amdgpu_sriov_vf(ring->adev) &&
+ flags & AMDGPU_IB_PREEMPTED) ?
+ true : false);
}
amdgpu_ring_write(ring, header);
@@ -5214,17 +5270,24 @@ static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
bool int_sel = flags & AMDGPU_FENCE_FLAG_INT;
bool writeback = flags & AMDGPU_FENCE_FLAG_TC_WB_ONLY;
+ bool exec = flags & AMDGPU_FENCE_FLAG_EXEC;
+ uint32_t dw2 = 0;
/* RELEASE_MEM - flush caches, send int */
amdgpu_ring_write(ring, PACKET3(PACKET3_RELEASE_MEM, 6));
- amdgpu_ring_write(ring, ((writeback ? (EOP_TC_WB_ACTION_EN |
- EOP_TC_NC_ACTION_EN) :
- (EOP_TCL1_ACTION_EN |
- EOP_TC_ACTION_EN |
- EOP_TC_WB_ACTION_EN |
- EOP_TC_MD_ACTION_EN)) |
- EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
- EVENT_INDEX(5)));
+
+ if (writeback) {
+ dw2 = EOP_TC_NC_ACTION_EN;
+ } else {
+ dw2 = EOP_TCL1_ACTION_EN | EOP_TC_ACTION_EN |
+ EOP_TC_MD_ACTION_EN;
+ }
+ dw2 |= EOP_TC_WB_ACTION_EN | EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+ EVENT_INDEX(5);
+ if (exec)
+ dw2 |= EOP_EXEC;
+
+ amdgpu_ring_write(ring, dw2);
amdgpu_ring_write(ring, DATA_SEL(write64bit ? 2 : 1) | INT_SEL(int_sel ? 2 : 0));
/*
@@ -5329,33 +5392,135 @@ static void gfx_v9_ring_emit_sb(struct amdgpu_ring *ring)
amdgpu_ring_write(ring, 0);
}
-static void gfx_v9_0_ring_emit_ce_meta(struct amdgpu_ring *ring)
+static void gfx_v9_0_ring_emit_ce_meta(struct amdgpu_ring *ring, bool resume)
{
+ struct amdgpu_device *adev = ring->adev;
struct v9_ce_ib_state ce_payload = {0};
- uint64_t csa_addr;
+ uint64_t offset, ce_payload_gpu_addr;
+ void *ce_payload_cpu_addr;
int cnt;
cnt = (sizeof(ce_payload) >> 2) + 4 - 2;
- csa_addr = amdgpu_csa_vaddr(ring->adev);
+
+ if (ring->is_mes_queue) {
+ offset = offsetof(struct amdgpu_mes_ctx_meta_data,
+ gfx[0].gfx_meta_data) +
+ offsetof(struct v9_gfx_meta_data, ce_payload);
+ ce_payload_gpu_addr =
+ amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset);
+ ce_payload_cpu_addr =
+ amdgpu_mes_ctx_get_offs_cpu_addr(ring, offset);
+ } else {
+ offset = offsetof(struct v9_gfx_meta_data, ce_payload);
+ ce_payload_gpu_addr = amdgpu_csa_vaddr(ring->adev) + offset;
+ ce_payload_cpu_addr = adev->virt.csa_cpu_addr + offset;
+ }
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, cnt));
amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(2) |
WRITE_DATA_DST_SEL(8) |
WR_CONFIRM) |
WRITE_DATA_CACHE_POLICY(0));
- amdgpu_ring_write(ring, lower_32_bits(csa_addr + offsetof(struct v9_gfx_meta_data, ce_payload)));
- amdgpu_ring_write(ring, upper_32_bits(csa_addr + offsetof(struct v9_gfx_meta_data, ce_payload)));
- amdgpu_ring_write_multiple(ring, (void *)&ce_payload, sizeof(ce_payload) >> 2);
+ amdgpu_ring_write(ring, lower_32_bits(ce_payload_gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(ce_payload_gpu_addr));
+
+ if (resume)
+ amdgpu_ring_write_multiple(ring, ce_payload_cpu_addr,
+ sizeof(ce_payload) >> 2);
+ else
+ amdgpu_ring_write_multiple(ring, (void *)&ce_payload,
+ sizeof(ce_payload) >> 2);
+}
+
+static int gfx_v9_0_ring_preempt_ib(struct amdgpu_ring *ring)
+{
+ int i, r = 0;
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *kiq_ring = &kiq->ring;
+ unsigned long flags;
+
+ if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
+ return -EINVAL;
+
+ spin_lock_irqsave(&kiq->ring_lock, flags);
+
+ if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size)) {
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
+ return -ENOMEM;
+ }
+
+ /* assert preemption condition */
+ amdgpu_ring_set_preempt_cond_exec(ring, false);
+
+ ring->trail_seq += 1;
+ amdgpu_ring_alloc(ring, 13);
+ gfx_v9_0_ring_emit_fence(ring, ring->trail_fence_gpu_addr,
+ ring->trail_seq, AMDGPU_FENCE_FLAG_EXEC | AMDGPU_FENCE_FLAG_INT);
+ /*reset the CP_VMID_PREEMPT after trailing fence*/
+ amdgpu_ring_emit_wreg(ring,
+ SOC15_REG_OFFSET(GC, 0, mmCP_VMID_PREEMPT),
+ 0x0);
+
+ /* assert IB preemption, emit the trailing fence */
+ kiq->pmf->kiq_unmap_queues(kiq_ring, ring, PREEMPT_QUEUES_NO_UNMAP,
+ ring->trail_fence_gpu_addr,
+ ring->trail_seq);
+
+ amdgpu_ring_commit(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
+
+ /* poll the trailing fence */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (ring->trail_seq ==
+ le32_to_cpu(*ring->trail_fence_cpu_addr))
+ break;
+ udelay(1);
+ }
+
+ if (i >= adev->usec_timeout) {
+ r = -EINVAL;
+ DRM_WARN("ring %d timeout to preempt ib\n", ring->idx);
+ }
+
+ amdgpu_ring_commit(ring);
+
+ /* deassert preemption condition */
+ amdgpu_ring_set_preempt_cond_exec(ring, true);
+ return r;
}
-static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring)
+static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume)
{
+ struct amdgpu_device *adev = ring->adev;
struct v9_de_ib_state de_payload = {0};
- uint64_t csa_addr, gds_addr;
+ uint64_t offset, gds_addr, de_payload_gpu_addr;
+ void *de_payload_cpu_addr;
int cnt;
- csa_addr = amdgpu_csa_vaddr(ring->adev);
- gds_addr = csa_addr + 4096;
+ if (ring->is_mes_queue) {
+ offset = offsetof(struct amdgpu_mes_ctx_meta_data,
+ gfx[0].gfx_meta_data) +
+ offsetof(struct v9_gfx_meta_data, de_payload);
+ de_payload_gpu_addr =
+ amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset);
+ de_payload_cpu_addr =
+ amdgpu_mes_ctx_get_offs_cpu_addr(ring, offset);
+
+ offset = offsetof(struct amdgpu_mes_ctx_meta_data,
+ gfx[0].gds_backup) +
+ offsetof(struct v9_gfx_meta_data, de_payload);
+ gds_addr = amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset);
+ } else {
+ offset = offsetof(struct v9_gfx_meta_data, de_payload);
+ de_payload_gpu_addr = amdgpu_csa_vaddr(ring->adev) + offset;
+ de_payload_cpu_addr = adev->virt.csa_cpu_addr + offset;
+
+ gds_addr = ALIGN(amdgpu_csa_vaddr(ring->adev) +
+ AMDGPU_CSA_SIZE - adev->gds.gds_size,
+ PAGE_SIZE);
+ }
+
de_payload.gds_backup_addrlo = lower_32_bits(gds_addr);
de_payload.gds_backup_addrhi = upper_32_bits(gds_addr);
@@ -5365,9 +5530,15 @@ static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring)
WRITE_DATA_DST_SEL(8) |
WR_CONFIRM) |
WRITE_DATA_CACHE_POLICY(0));
- amdgpu_ring_write(ring, lower_32_bits(csa_addr + offsetof(struct v9_gfx_meta_data, de_payload)));
- amdgpu_ring_write(ring, upper_32_bits(csa_addr + offsetof(struct v9_gfx_meta_data, de_payload)));
- amdgpu_ring_write_multiple(ring, (void *)&de_payload, sizeof(de_payload) >> 2);
+ amdgpu_ring_write(ring, lower_32_bits(de_payload_gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(de_payload_gpu_addr));
+
+ if (resume)
+ amdgpu_ring_write_multiple(ring, de_payload_cpu_addr,
+ sizeof(de_payload) >> 2);
+ else
+ amdgpu_ring_write_multiple(ring, (void *)&de_payload,
+ sizeof(de_payload) >> 2);
}
static void gfx_v9_0_ring_emit_frame_cntl(struct amdgpu_ring *ring, bool start,
@@ -5383,8 +5554,9 @@ static void gfx_v9_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
{
uint32_t dw2 = 0;
- if (amdgpu_sriov_vf(ring->adev))
- gfx_v9_0_ring_emit_ce_meta(ring);
+ gfx_v9_0_ring_emit_ce_meta(ring,
+ (!amdgpu_sriov_vf(ring->adev) &&
+ flags & AMDGPU_IB_PREEMPTED) ? true : false);
dw2 |= 0x80000000; /* set load_enable otherwise this package is just NOPs */
if (flags & AMDGPU_HAVE_CTX_SWITCH) {
@@ -5710,7 +5882,12 @@ static int gfx_v9_0_eop_irq(struct amdgpu_device *adev,
switch (me_id) {
case 0:
- amdgpu_fence_process(&adev->gfx.gfx_ring[0]);
+ if (adev->gfx.num_gfx_rings &&
+ !amdgpu_mcbp_handle_trailing_fence_irq(&adev->gfx.muxer)) {
+ /* Fence signals are handled on the software rings*/
+ for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++)
+ amdgpu_fence_process(&adev->gfx.sw_gfx_ring[i]);
+ }
break;
case 1:
case 2:
@@ -6482,7 +6659,7 @@ static void gfx_v9_0_reset_ras_error_count(struct amdgpu_device *adev)
for (i = 0; i < ARRAY_SIZE(gfx_v9_0_edc_counter_regs); i++) {
for (j = 0; j < gfx_v9_0_edc_counter_regs[i].se_num; j++) {
for (k = 0; k < gfx_v9_0_edc_counter_regs[i].instance; k++) {
- gfx_v9_0_select_se_sh(adev, j, 0x0, k);
+ amdgpu_gfx_select_se_sh(adev, j, 0x0, k);
RREG32(SOC15_REG_ENTRY_OFFSET(gfx_v9_0_edc_counter_regs[i]));
}
}
@@ -6544,7 +6721,7 @@ static void gfx_v9_0_query_ras_error_count(struct amdgpu_device *adev,
for (i = 0; i < ARRAY_SIZE(gfx_v9_0_edc_counter_regs); i++) {
for (j = 0; j < gfx_v9_0_edc_counter_regs[i].se_num; j++) {
for (k = 0; k < gfx_v9_0_edc_counter_regs[i].instance; k++) {
- gfx_v9_0_select_se_sh(adev, j, 0, k);
+ amdgpu_gfx_select_se_sh(adev, j, 0, k);
reg_value =
RREG32(SOC15_REG_ENTRY_OFFSET(gfx_v9_0_edc_counter_regs[i]));
if (reg_value)
@@ -6559,7 +6736,7 @@ static void gfx_v9_0_query_ras_error_count(struct amdgpu_device *adev,
err_data->ce_count += sec_count;
err_data->ue_count += ded_count;
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
gfx_v9_0_query_utc_edc_status(adev, err_data);
@@ -6707,6 +6884,62 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = {
.emit_cntxcntl = gfx_v9_ring_emit_cntxcntl,
.init_cond_exec = gfx_v9_0_ring_emit_init_cond_exec,
.patch_cond_exec = gfx_v9_0_ring_emit_patch_cond_exec,
+ .preempt_ib = gfx_v9_0_ring_preempt_ib,
+ .emit_frame_cntl = gfx_v9_0_ring_emit_frame_cntl,
+ .emit_wreg = gfx_v9_0_ring_emit_wreg,
+ .emit_reg_wait = gfx_v9_0_ring_emit_reg_wait,
+ .emit_reg_write_reg_wait = gfx_v9_0_ring_emit_reg_write_reg_wait,
+ .soft_recovery = gfx_v9_0_ring_soft_recovery,
+ .emit_mem_sync = gfx_v9_0_emit_mem_sync,
+};
+
+static const struct amdgpu_ring_funcs gfx_v9_0_sw_ring_funcs_gfx = {
+ .type = AMDGPU_RING_TYPE_GFX,
+ .align_mask = 0xff,
+ .nop = PACKET3(PACKET3_NOP, 0x3FFF),
+ .support_64bit_ptrs = true,
+ .secure_submission_supported = true,
+ .vmhub = AMDGPU_GFXHUB_0,
+ .get_rptr = amdgpu_sw_ring_get_rptr_gfx,
+ .get_wptr = amdgpu_sw_ring_get_wptr_gfx,
+ .set_wptr = amdgpu_sw_ring_set_wptr_gfx,
+ .emit_frame_size = /* totally 242 maximum if 16 IBs */
+ 5 + /* COND_EXEC */
+ 7 + /* PIPELINE_SYNC */
+ SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 +
+ SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 +
+ 2 + /* VM_FLUSH */
+ 8 + /* FENCE for VM_FLUSH */
+ 20 + /* GDS switch */
+ 4 + /* double SWITCH_BUFFER,
+ * the first COND_EXEC jump to the place just
+ * prior to this double SWITCH_BUFFER
+ */
+ 5 + /* COND_EXEC */
+ 7 + /* HDP_flush */
+ 4 + /* VGT_flush */
+ 14 + /* CE_META */
+ 31 + /* DE_META */
+ 3 + /* CNTX_CTRL */
+ 5 + /* HDP_INVL */
+ 8 + 8 + /* FENCE x2 */
+ 2 + /* SWITCH_BUFFER */
+ 7, /* gfx_v9_0_emit_mem_sync */
+ .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_gfx */
+ .emit_ib = gfx_v9_0_ring_emit_ib_gfx,
+ .emit_fence = gfx_v9_0_ring_emit_fence,
+ .emit_pipeline_sync = gfx_v9_0_ring_emit_pipeline_sync,
+ .emit_vm_flush = gfx_v9_0_ring_emit_vm_flush,
+ .emit_gds_switch = gfx_v9_0_ring_emit_gds_switch,
+ .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush,
+ .test_ring = gfx_v9_0_ring_test_ring,
+ .test_ib = gfx_v9_0_ring_test_ib,
+ .insert_nop = amdgpu_sw_ring_insert_nop,
+ .pad_ib = amdgpu_ring_generic_pad_ib,
+ .emit_switch_buffer = gfx_v9_ring_emit_sb,
+ .emit_cntxcntl = gfx_v9_ring_emit_cntxcntl,
+ .init_cond_exec = gfx_v9_0_ring_emit_init_cond_exec,
+ .patch_cond_exec = gfx_v9_0_ring_emit_patch_cond_exec,
.emit_frame_cntl = gfx_v9_0_ring_emit_frame_cntl,
.emit_wreg = gfx_v9_0_ring_emit_wreg,
.emit_reg_wait = gfx_v9_0_ring_emit_reg_wait,
@@ -6792,6 +7025,11 @@ static void gfx_v9_0_set_ring_funcs(struct amdgpu_device *adev)
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
adev->gfx.gfx_ring[i].funcs = &gfx_v9_0_ring_funcs_gfx;
+ if (adev->gfx.num_gfx_rings) {
+ for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++)
+ adev->gfx.sw_gfx_ring[i].funcs = &gfx_v9_0_sw_ring_funcs_gfx;
+ }
+
for (i = 0; i < adev->gfx.num_compute_rings; i++)
adev->gfx.compute_ring[i].funcs = &gfx_v9_0_ring_funcs_compute;
}
@@ -6963,7 +7201,7 @@ static int gfx_v9_0_get_cu_info(struct amdgpu_device *adev,
mask = 1;
ao_bitmap = 0;
counter = 0;
- gfx_v9_0_select_se_sh(adev, i, j, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, i, j, 0xffffffff);
gfx_v9_0_set_user_cu_inactive_bitmap(
adev, disable_masks[i * adev->gfx.config.max_sh_per_se + j]);
bitmap = gfx_v9_0_get_cu_active_bitmap(adev);
@@ -6996,7 +7234,7 @@ static int gfx_v9_0_get_cu_info(struct amdgpu_device *adev,
cu_info->ao_cu_bitmap[i % 4][j + i / 4] = ao_bitmap;
}
}
- gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
mutex_unlock(&adev->grbm_idx_mutex);
cu_info->number = active_cu_number;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
index 8cf53e039c11..3f8676d23a5e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
@@ -397,6 +397,9 @@ static void gfxhub_v2_1_gart_disable(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 0);
WREG32_SOC15(GC, 0, mmGCMC_VM_MX_L1_TLB_CNTL, tmp);
+ if (amdgpu_sriov_vf(adev))
+ return;
+
/* Setup L2 cache */
WREG32_FIELD15(GC, 0, GCVM_L2_CNTL, ENABLE_L2_CACHE, 0);
WREG32_SOC15(GC, 0, mmGCVM_L2_CNTL3, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
index 5d3fffd4929f..080ff11ca305 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
@@ -154,6 +154,9 @@ static void gfxhub_v3_0_3_init_system_aperture_regs(struct amdgpu_device *adev)
{
uint64_t value;
+ if (amdgpu_sriov_vf(adev))
+ return;
+
/* Disable AGP. */
WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BASE, 0);
WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, 0);
@@ -354,18 +357,6 @@ static void gfxhub_v3_0_3_program_invalidation(struct amdgpu_device *adev)
static int gfxhub_v3_0_3_gart_enable(struct amdgpu_device *adev)
{
- if (amdgpu_sriov_vf(adev)) {
- /*
- * GCMC_VM_FB_LOCATION_BASE/TOP is NULL for VF, becuase they are
- * VF copy registers so vbios post doesn't program them, for
- * SRIOV driver need to program them
- */
- WREG32_SOC15(GC, 0, regGCMC_VM_FB_LOCATION_BASE,
- adev->gmc.vram_start >> 24);
- WREG32_SOC15(GC, 0, regGCMC_VM_FB_LOCATION_TOP,
- adev->gmc.vram_end >> 24);
- }
-
/* GART Enable. */
gfxhub_v3_0_3_init_gart_aperture_regs(adev);
gfxhub_v3_0_3_init_system_aperture_regs(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index f513e2c2e964..21e46817d82d 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -371,7 +371,9 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
* translation. Avoid this by doing the invalidation from the SDMA
* itself.
*/
- r = amdgpu_job_alloc_with_ib(adev, 16 * 4, AMDGPU_IB_POOL_IMMEDIATE,
+ r = amdgpu_job_alloc_with_ib(ring->adev, &adev->mman.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ 16 * 4, AMDGPU_IB_POOL_IMMEDIATE,
&job);
if (r)
goto error_alloc;
@@ -380,10 +382,7 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
job->vm_needs_flush = true;
job->ibs->ptr[job->ibs->length_dw++] = ring->funcs->nop;
amdgpu_ring_pad_ib(ring, &job->ibs[0]);
- r = amdgpu_job_submit(job, &adev->mman.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
- if (r)
- goto error_submit;
+ fence = amdgpu_job_submit(job);
mutex_unlock(&adev->mman.gtt_window_lock);
@@ -392,9 +391,6 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
return;
-error_submit:
- amdgpu_job_free(job);
-
error_alloc:
mutex_unlock(&adev->mman.gtt_window_lock);
DRM_ERROR("Error flushing GPU TLB using the SDMA (%d)!\n", r);
@@ -612,6 +608,8 @@ static void gmc_v10_0_get_vm_pte(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping,
uint64_t *flags)
{
+ struct amdgpu_bo *bo = mapping->bo_va->base.bo;
+
*flags &= ~AMDGPU_PTE_EXECUTABLE;
*flags |= mapping->flags & AMDGPU_PTE_EXECUTABLE;
@@ -628,6 +626,11 @@ static void gmc_v10_0_get_vm_pte(struct amdgpu_device *adev,
*flags |= AMDGPU_PTE_SYSTEM;
*flags &= ~AMDGPU_PTE_VALID;
}
+
+ if (bo && bo->flags & (AMDGPU_GEM_CREATE_COHERENT |
+ AMDGPU_GEM_CREATE_UNCACHED))
+ *flags = (*flags & ~AMDGPU_PTE_MTYPE_NV10_MASK) |
+ AMDGPU_PTE_MTYPE_NV10(MTYPE_UC);
}
static unsigned gmc_v10_0_get_vbios_fb_size(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index 66dfb574cc7d..4326078689cd 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -503,6 +503,8 @@ static void gmc_v11_0_get_vm_pte(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping,
uint64_t *flags)
{
+ struct amdgpu_bo *bo = mapping->bo_va->base.bo;
+
*flags &= ~AMDGPU_PTE_EXECUTABLE;
*flags |= mapping->flags & AMDGPU_PTE_EXECUTABLE;
@@ -519,6 +521,11 @@ static void gmc_v11_0_get_vm_pte(struct amdgpu_device *adev,
*flags |= AMDGPU_PTE_SYSTEM;
*flags &= ~AMDGPU_PTE_VALID;
}
+
+ if (bo && bo->flags & (AMDGPU_GEM_CREATE_COHERENT |
+ AMDGPU_GEM_CREATE_UNCACHED))
+ *flags = (*flags & ~AMDGPU_PTE_MTYPE_NV10_MASK) |
+ AMDGPU_PTE_MTYPE_NV10(MTYPE_UC);
}
static unsigned gmc_v11_0_get_vbios_fb_size(struct amdgpu_device *adev)
@@ -551,7 +558,10 @@ static void gmc_v11_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.node_inst_num = adev->gmc.num_umc;
adev->umc.max_ras_err_cnt_per_query = UMC_V8_10_TOTAL_CHANNEL_NUM(adev);
adev->umc.channel_offs = UMC_V8_10_PER_CHANNEL_OFFSET;
- adev->umc.channel_idx_tbl = &umc_v8_10_channel_idx_tbl[0][0][0];
+ if (adev->umc.node_inst_num == 4)
+ adev->umc.channel_idx_tbl = &umc_v8_10_channel_idx_tbl_ext0[0][0][0];
+ else
+ adev->umc.channel_idx_tbl = &umc_v8_10_channel_idx_tbl[0][0][0];
adev->umc.ras = &umc_v8_10_ras;
break;
case IP_VERSION(8, 11, 0):
@@ -749,6 +759,7 @@ static int gmc_v11_0_sw_init(void *handle)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
adev->num_vmhubs = 2;
/*
* To fulfill 4-level page support,
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 67ca16a8027c..50386eb2eec8 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -1113,6 +1113,74 @@ static void gmc_v9_0_get_vm_pde(struct amdgpu_device *adev, int level,
}
}
+static void gmc_v9_0_get_coherence_flags(struct amdgpu_device *adev,
+ struct amdgpu_bo *bo,
+ struct amdgpu_bo_va_mapping *mapping,
+ uint64_t *flags)
+{
+ struct amdgpu_device *bo_adev = amdgpu_ttm_adev(bo->tbo.bdev);
+ bool is_vram = bo->tbo.resource->mem_type == TTM_PL_VRAM;
+ bool coherent = bo->flags & AMDGPU_GEM_CREATE_COHERENT;
+ bool uncached = bo->flags & AMDGPU_GEM_CREATE_UNCACHED;
+ unsigned int mtype;
+ bool snoop = false;
+
+ switch (adev->ip_versions[GC_HWIP][0]) {
+ case IP_VERSION(9, 4, 1):
+ case IP_VERSION(9, 4, 2):
+ if (is_vram) {
+ if (bo_adev == adev) {
+ if (uncached)
+ mtype = MTYPE_UC;
+ else if (coherent)
+ mtype = MTYPE_CC;
+ else
+ mtype = MTYPE_RW;
+ /* FIXME: is this still needed? Or does
+ * amdgpu_ttm_tt_pde_flags already handle this?
+ */
+ if (adev->ip_versions[GC_HWIP][0] ==
+ IP_VERSION(9, 4, 2) &&
+ adev->gmc.xgmi.connected_to_cpu)
+ snoop = true;
+ } else {
+ if (uncached || coherent)
+ mtype = MTYPE_UC;
+ else
+ mtype = MTYPE_NC;
+ if (mapping->bo_va->is_xgmi)
+ snoop = true;
+ }
+ } else {
+ if (uncached || coherent)
+ mtype = MTYPE_UC;
+ else
+ mtype = MTYPE_NC;
+ /* FIXME: is this still needed? Or does
+ * amdgpu_ttm_tt_pde_flags already handle this?
+ */
+ snoop = true;
+ }
+ break;
+ default:
+ if (uncached || coherent)
+ mtype = MTYPE_UC;
+ else
+ mtype = MTYPE_NC;
+
+ /* FIXME: is this still needed? Or does
+ * amdgpu_ttm_tt_pde_flags already handle this?
+ */
+ if (!is_vram)
+ snoop = true;
+ }
+
+ if (mtype != MTYPE_NC)
+ *flags = (*flags & ~AMDGPU_PTE_MTYPE_VG10_MASK) |
+ AMDGPU_PTE_MTYPE_VG10(mtype);
+ *flags |= snoop ? AMDGPU_PTE_SNOOPED : 0;
+}
+
static void gmc_v9_0_get_vm_pte(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping,
uint64_t *flags)
@@ -1128,14 +1196,9 @@ static void gmc_v9_0_get_vm_pte(struct amdgpu_device *adev,
*flags &= ~AMDGPU_PTE_VALID;
}
- if ((adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 1) ||
- adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2)) &&
- !(*flags & AMDGPU_PTE_SYSTEM) &&
- mapping->bo_va->is_xgmi)
- *flags |= AMDGPU_PTE_SNOOPED;
-
- if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2))
- *flags |= mapping->flags & AMDGPU_PTE_SNOOPED;
+ if (mapping->bo_va->base.bo)
+ gmc_v9_0_get_coherence_flags(adev, mapping->bo_va->base.bo,
+ mapping, flags);
}
static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index f87d0f6ffc93..f2b743a93915 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -807,16 +807,5 @@ static void jpeg_v2_5_set_ras_funcs(struct amdgpu_device *adev)
break;
}
- if (adev->jpeg.ras) {
- amdgpu_ras_register_ras_block(adev, &adev->jpeg.ras->ras_block);
-
- strcpy(adev->jpeg.ras->ras_block.ras_comm.name, "jpeg");
- adev->jpeg.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__JPEG;
- adev->jpeg.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
- adev->jpeg.ras_if = &adev->jpeg.ras->ras_block.ras_comm;
-
- /* If don't define special ras_late_init function, use default ras_late_init */
- if (!adev->jpeg.ras->ras_block.ras_late_init)
- adev->jpeg.ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
- }
+ jpeg_set_ras_funcs(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index 63b0d0b810ec..3beb731b2ce5 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -27,6 +27,7 @@
#include "soc15.h"
#include "soc15d.h"
#include "jpeg_v2_0.h"
+#include "jpeg_v4_0.h"
#include "vcn/vcn_4_0_0_offset.h"
#include "vcn/vcn_4_0_0_sh_mask.h"
@@ -38,6 +39,7 @@ static void jpeg_v4_0_set_dec_ring_funcs(struct amdgpu_device *adev);
static void jpeg_v4_0_set_irq_funcs(struct amdgpu_device *adev);
static int jpeg_v4_0_set_powergating_state(void *handle,
enum amd_powergating_state state);
+static void jpeg_v4_0_set_ras_funcs(struct amdgpu_device *adev);
/**
* jpeg_v4_0_early_init - set function pointers
@@ -55,6 +57,7 @@ static int jpeg_v4_0_early_init(void *handle)
jpeg_v4_0_set_dec_ring_funcs(adev);
jpeg_v4_0_set_irq_funcs(adev);
+ jpeg_v4_0_set_ras_funcs(adev);
return 0;
}
@@ -78,6 +81,18 @@ static int jpeg_v4_0_sw_init(void *handle)
if (r)
return r;
+ /* JPEG DJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->irq);
+ if (r)
+ return r;
+
+ /* JPEG EJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->irq);
+ if (r)
+ return r;
+
r = amdgpu_jpeg_sw_init(adev);
if (r)
return r;
@@ -167,6 +182,8 @@ static int jpeg_v4_0_hw_fini(void *handle)
RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
jpeg_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+ amdgpu_irq_put(adev, &adev->jpeg.inst->irq, 0);
+
return 0;
}
@@ -524,6 +541,10 @@ static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev,
case VCN_4_0__SRCID__JPEG_DECODE:
amdgpu_fence_process(&adev->jpeg.inst->ring_dec);
break;
+ case VCN_4_0__SRCID_DJPEG0_POISON:
+ case VCN_4_0__SRCID_EJPEG0_POISON:
+ amdgpu_jpeg_process_poison_irq(adev, source, entry);
+ break;
default:
DRM_DEV_ERROR(adev->dev, "Unhandled interrupt: %d %d\n",
entry->src_id, entry->src_data[0]);
@@ -607,3 +628,63 @@ const struct amdgpu_ip_block_version jpeg_v4_0_ip_block = {
.rev = 0,
.funcs = &jpeg_v4_0_ip_funcs,
};
+
+static uint32_t jpeg_v4_0_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_JPEG_V4_0_JPEG0:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG0_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG0_STATUS, POISONED_PF);
+ break;
+ case AMDGPU_JPEG_V4_0_JPEG1:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG1_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG1_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in JPEG%d sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool jpeg_v4_0_query_ras_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst = 0, sub = 0, poison_stat = 0;
+
+ for (inst = 0; inst < adev->jpeg.num_jpeg_inst; inst++)
+ for (sub = 0; sub < AMDGPU_JPEG_V4_0_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ jpeg_v4_0_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
+const struct amdgpu_ras_block_hw_ops jpeg_v4_0_ras_hw_ops = {
+ .query_poison_status = jpeg_v4_0_query_ras_poison_status,
+};
+
+static struct amdgpu_jpeg_ras jpeg_v4_0_ras = {
+ .ras_block = {
+ .hw_ops = &jpeg_v4_0_ras_hw_ops,
+ },
+};
+
+static void jpeg_v4_0_set_ras_funcs(struct amdgpu_device *adev)
+{
+ switch (adev->ip_versions[JPEG_HWIP][0]) {
+ case IP_VERSION(4, 0, 0):
+ adev->jpeg.ras = &jpeg_v4_0_ras;
+ break;
+ default:
+ break;
+ }
+
+ jpeg_set_ras_funcs(adev);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.h
index f1ed6ccfedca..07d36c2abd6b 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.h
@@ -24,6 +24,13 @@
#ifndef __JPEG_V4_0_H__
#define __JPEG_V4_0_H__
+enum amdgpu_jpeg_v4_0_sub_block {
+ AMDGPU_JPEG_V4_0_JPEG0 = 0,
+ AMDGPU_JPEG_V4_0_JPEG1,
+
+ AMDGPU_JPEG_V4_0_MAX_SUB_BLOCK,
+};
+
extern const struct amdgpu_ip_block_version jpeg_v4_0_ip_block;
#endif /* __JPEG_V4_0_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
index 067d10073a56..614394118a53 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
@@ -121,6 +121,10 @@ static int mes_v10_1_submit_pkt_and_poll_completion(struct amdgpu_mes *mes,
if (r < 1) {
DRM_ERROR("MES failed to response msg=%d\n",
x_pkt->header.opcode);
+
+ while (halt_if_hws_hang)
+ schedule();
+
return -ETIMEDOUT;
}
@@ -415,10 +419,6 @@ static int mes_v10_1_init_microcode(struct amdgpu_device *adev,
mes_hdr = (const struct mes_firmware_header_v1_0 *)
adev->mes.fw[pipe]->data;
- adev->mes.ucode_fw_version[pipe] =
- le32_to_cpu(mes_hdr->mes_ucode_version);
- adev->mes.ucode_fw_version[pipe] =
- le32_to_cpu(mes_hdr->mes_ucode_data_version);
adev->mes.uc_start_addr[pipe] =
le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
index f141fadd2d86..5459366f49ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -129,6 +129,10 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes,
if (r < 1) {
DRM_ERROR("MES failed to response msg=%d\n",
x_pkt->header.opcode);
+
+ while (halt_if_hws_hang)
+ schedule();
+
return -ETIMEDOUT;
}
@@ -384,6 +388,7 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes)
mes_set_hw_res_pkt.disable_reset = 1;
mes_set_hw_res_pkt.disable_mes_log = 1;
mes_set_hw_res_pkt.use_different_vmid_compute = 1;
+ mes_set_hw_res_pkt.enable_reg_active_poll = 1;
mes_set_hw_res_pkt.oversubscription_timer = 50;
return mes_v11_0_submit_pkt_and_poll_completion(mes,
@@ -485,10 +490,6 @@ static int mes_v11_0_init_microcode(struct amdgpu_device *adev,
mes_hdr = (const struct mes_firmware_header_v1_0 *)
adev->mes.fw[pipe]->data;
- adev->mes.ucode_fw_version[pipe] =
- le32_to_cpu(mes_hdr->mes_ucode_version);
- adev->mes.ucode_fw_version[pipe] =
- le32_to_cpu(mes_hdr->mes_ucode_data_version);
adev->mes.uc_start_addr[pipe] =
le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
@@ -1253,7 +1254,9 @@ static int mes_v11_0_kiq_hw_fini(struct amdgpu_device *adev)
if (adev->mes.ring.sched.ready)
mes_v11_0_kiq_dequeue_sched(adev);
- mes_v11_0_enable(adev, false);
+ if (!amdgpu_sriov_vf(adev))
+ mes_v11_0_enable(adev, false);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
index 998b5d17b271..0e664d0cc8d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@ -319,7 +319,7 @@ static void mmhub_v2_0_init_cache_regs(struct amdgpu_device *adev)
tmp = mmMMVM_L2_CNTL5_DEFAULT;
tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL5, L2_CACHE_SMALLK_FRAGMENT_SIZE, 0);
- WREG32_SOC15(GC, 0, mmMMVM_L2_CNTL5, tmp);
+ WREG32_SOC15(MMHUB, 0, mmMMVM_L2_CNTL5, tmp);
}
static void mmhub_v2_0_enable_system_domain(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
index 1b027d069ab4..4638ea7c2eec 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
@@ -243,7 +243,7 @@ static void mmhub_v2_3_init_cache_regs(struct amdgpu_device *adev)
tmp = mmMMVM_L2_CNTL5_DEFAULT;
tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL5, L2_CACHE_SMALLK_FRAGMENT_SIZE, 0);
- WREG32_SOC15(GC, 0, mmMMVM_L2_CNTL5, tmp);
+ WREG32_SOC15(MMHUB, 0, mmMMVM_L2_CNTL5, tmp);
}
static void mmhub_v2_3_enable_system_domain(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
index a1d26c4d80b8..16cc82215e2e 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
@@ -275,7 +275,7 @@ static void mmhub_v3_0_init_cache_regs(struct amdgpu_device *adev)
tmp = regMMVM_L2_CNTL5_DEFAULT;
tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL5, L2_CACHE_SMALLK_FRAGMENT_SIZE, 0);
- WREG32_SOC15(GC, 0, regMMVM_L2_CNTL5, tmp);
+ WREG32_SOC15(MMHUB, 0, regMMVM_L2_CNTL5, tmp);
}
static void mmhub_v3_0_enable_system_domain(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
index e8058edc1d10..6bdf2ef0298d 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
@@ -269,7 +269,7 @@ static void mmhub_v3_0_1_init_cache_regs(struct amdgpu_device *adev)
tmp = regMMVM_L2_CNTL5_DEFAULT;
tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL5, L2_CACHE_SMALLK_FRAGMENT_SIZE, 0);
- WREG32_SOC15(GC, 0, regMMVM_L2_CNTL5, tmp);
+ WREG32_SOC15(MMHUB, 0, regMMVM_L2_CNTL5, tmp);
}
static void mmhub_v3_0_1_enable_system_domain(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
index 770be0a8f7ce..45465acaa943 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
@@ -268,7 +268,7 @@ static void mmhub_v3_0_2_init_cache_regs(struct amdgpu_device *adev)
tmp = regMMVM_L2_CNTL5_DEFAULT;
tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL5, L2_CACHE_SMALLK_FRAGMENT_SIZE, 0);
- WREG32_SOC15(GC, 0, regMMVM_L2_CNTL5, tmp);
+ WREG32_SOC15(MMHUB, 0, regMMVM_L2_CNTL5, tmp);
}
static void mmhub_v3_0_2_enable_system_domain(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mmsch_v4_0.h b/drivers/gpu/drm/amd/amdgpu/mmsch_v4_0.h
index f772bb499f3e..0312c71c3af9 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmsch_v4_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/mmsch_v4_0.h
@@ -32,7 +32,6 @@
#define RB_ENABLED (1 << 0)
#define RB4_ENABLED (1 << 1)
-#define MMSCH_DOORBELL_OFFSET 0x8
#define MMSCH_VF_ENGINE_STATUS__PASS 0x1
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
index b3fba8dea63c..6853b93ac82e 100644
--- a/drivers/gpu/drm/amd/amdgpu/nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -82,10 +82,10 @@ static const struct amdgpu_video_codecs nv_video_codecs_encode =
/* Navi1x */
static const struct amdgpu_video_codec_info nv_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
@@ -100,10 +100,10 @@ static const struct amdgpu_video_codecs nv_video_codecs_decode =
/* Sienna Cichlid */
static const struct amdgpu_video_codec_info sc_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
@@ -125,10 +125,10 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] =
static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
@@ -149,7 +149,7 @@ static struct amdgpu_video_codecs sriov_sc_video_codecs_decode =
/* Beige Goby*/
static const struct amdgpu_video_codec_info bg_video_codecs_decode_array[] = {
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
};
@@ -166,7 +166,7 @@ static const struct amdgpu_video_codecs bg_video_codecs_encode = {
/* Yellow Carp*/
static const struct amdgpu_video_codec_info yc_video_codecs_decode_array[] = {
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
index ed2293686f0d..9de46fa8f46c 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
@@ -126,32 +126,6 @@ out:
return err;
}
-static int psp_v10_0_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v10_0_ring_create(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -245,7 +219,6 @@ static void psp_v10_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
static const struct psp_funcs psp_v10_0_funcs = {
.init_microcode = psp_v10_0_init_microcode,
- .ring_init = psp_v10_0_ring_init,
.ring_create = psp_v10_0_ring_create,
.ring_stop = psp_v10_0_ring_stop,
.ring_destroy = psp_v10_0_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index 9518b4394a6e..bd3e3e23a939 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -360,32 +360,6 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v11_0_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v11_0_ring_stop(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -779,7 +753,6 @@ static const struct psp_funcs psp_v11_0_funcs = {
.bootloader_load_spl = psp_v11_0_bootloader_load_spl,
.bootloader_load_sysdrv = psp_v11_0_bootloader_load_sysdrv,
.bootloader_load_sos = psp_v11_0_bootloader_load_sos,
- .ring_init = psp_v11_0_ring_init,
.ring_create = psp_v11_0_ring_create,
.ring_stop = psp_v11_0_ring_stop,
.ring_destroy = psp_v11_0_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
index ff13e1beb49b..5697760a819b 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
@@ -28,32 +28,6 @@
#include "mp/mp_11_0_8_offset.h"
-static int psp_v11_0_8_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v11_0_8_ring_stop(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -194,7 +168,6 @@ static void psp_v11_0_8_ring_set_wptr(struct psp_context *psp, uint32_t value)
}
static const struct psp_funcs psp_v11_0_8_funcs = {
- .ring_init = psp_v11_0_8_ring_init,
.ring_create = psp_v11_0_8_ring_create,
.ring_stop = psp_v11_0_8_ring_stop,
.ring_destroy = psp_v11_0_8_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
index 0b2ac418e4ac..8ed2281b6557 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
@@ -236,34 +236,6 @@ static void psp_v12_0_reroute_ih(struct psp_context *psp)
0x80000000, 0x8000FFFF, false);
}
-static int psp_v12_0_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- psp_v12_0_reroute_ih(psp);
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v12_0_ring_create(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -272,6 +244,8 @@ static int psp_v12_0_ring_create(struct psp_context *psp,
struct psp_ring *ring = &psp->km_ring;
struct amdgpu_device *adev = psp->adev;
+ psp_v12_0_reroute_ih(psp);
+
if (amdgpu_sriov_vf(psp->adev)) {
/* Write low address of the ring to C2PMSG_102 */
psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
@@ -425,7 +399,6 @@ static const struct psp_funcs psp_v12_0_funcs = {
.init_microcode = psp_v12_0_init_microcode,
.bootloader_load_sysdrv = psp_v12_0_bootloader_load_sysdrv,
.bootloader_load_sos = psp_v12_0_bootloader_load_sos,
- .ring_init = psp_v12_0_ring_init,
.ring_create = psp_v12_0_ring_create,
.ring_stop = psp_v12_0_ring_stop,
.ring_destroy = psp_v12_0_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
index 21d822b1d589..e6a26a7e5e5e 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
@@ -45,6 +45,9 @@ MODULE_FIRMWARE("amdgpu/psp_13_0_0_ta.bin");
MODULE_FIRMWARE("amdgpu/psp_13_0_7_sos.bin");
MODULE_FIRMWARE("amdgpu/psp_13_0_7_ta.bin");
MODULE_FIRMWARE("amdgpu/psp_13_0_10_sos.bin");
+MODULE_FIRMWARE("amdgpu/psp_13_0_10_ta.bin");
+MODULE_FIRMWARE("amdgpu/psp_13_0_11_toc.bin");
+MODULE_FIRMWARE("amdgpu/psp_13_0_11_ta.bin");
/* For large FW files the time to complete can be very long */
#define USBC_PD_POLLING_LIMIT_S 240
@@ -101,6 +104,7 @@ static int psp_v13_0_init_microcode(struct psp_context *psp)
case IP_VERSION(13, 0, 3):
case IP_VERSION(13, 0, 5):
case IP_VERSION(13, 0, 8):
+ case IP_VERSION(13, 0, 11):
err = psp_init_toc_microcode(psp, chip_name);
if (err)
return err;
@@ -267,32 +271,6 @@ static int psp_v13_0_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v13_0_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v13_0_ring_stop(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -728,7 +706,6 @@ static const struct psp_funcs psp_v13_0_funcs = {
.bootloader_load_dbg_drv = psp_v13_0_bootloader_load_dbg_drv,
.bootloader_load_ras_drv = psp_v13_0_bootloader_load_ras_drv,
.bootloader_load_sos = psp_v13_0_bootloader_load_sos,
- .ring_init = psp_v13_0_ring_init,
.ring_create = psp_v13_0_ring_create,
.ring_stop = psp_v13_0_ring_stop,
.ring_destroy = psp_v13_0_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
index 321089dfa7db..9d4e24e518e8 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
@@ -199,32 +199,6 @@ static int psp_v13_0_4_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v13_0_4_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static int psp_v13_0_4_ring_stop(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -373,7 +347,6 @@ static const struct psp_funcs psp_v13_0_4_funcs = {
.bootloader_load_intf_drv = psp_v13_0_4_bootloader_load_intf_drv,
.bootloader_load_dbg_drv = psp_v13_0_4_bootloader_load_dbg_drv,
.bootloader_load_sos = psp_v13_0_4_bootloader_load_sos,
- .ring_init = psp_v13_0_4_ring_init,
.ring_create = psp_v13_0_4_ring_create,
.ring_stop = psp_v13_0_4_ring_stop,
.ring_destroy = psp_v13_0_4_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
index 01f3bcc62a6c..157147c6c94e 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
@@ -160,32 +160,6 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v3_1_ring_init(struct psp_context *psp,
- enum psp_ring_type ring_type)
-{
- int ret = 0;
- struct psp_ring *ring;
- struct amdgpu_device *adev = psp->adev;
-
- ring = &psp->km_ring;
-
- ring->ring_type = ring_type;
-
- /* allocate 4k Page of Local Frame Buffer memory for ring */
- ring->ring_size = 0x1000;
- ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->firmware.rbuf,
- &ring->ring_mem_mc_addr,
- (void **)&ring->ring_mem);
- if (ret) {
- ring->ring_size = 0;
- return ret;
- }
-
- return 0;
-}
-
static void psp_v3_1_reroute_ih(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -401,7 +375,6 @@ static const struct psp_funcs psp_v3_1_funcs = {
.init_microcode = psp_v3_1_init_microcode,
.bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv,
.bootloader_load_sos = psp_v3_1_bootloader_load_sos,
- .ring_init = psp_v3_1_ring_init,
.ring_create = psp_v3_1_ring_create,
.ring_stop = psp_v3_1_ring_stop,
.ring_destroy = psp_v3_1_ring_destroy,
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 1122bd4eae98..4d780e4430e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -907,13 +907,13 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
/**
- * sdma_v4_0_gfx_stop - stop the gfx async dma engines
+ * sdma_v4_0_gfx_enable - enable the gfx async dma engines
*
* @adev: amdgpu_device pointer
- *
- * Stop the gfx async dma ring buffers (VEGA10).
+ * @enable: enable SDMA RB/IB
+ * control the gfx async dma ring buffers (VEGA10).
*/
-static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev)
+static void sdma_v4_0_gfx_enable(struct amdgpu_device *adev, bool enable)
{
u32 rb_cntl, ib_cntl;
int i;
@@ -922,10 +922,10 @@ static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev)
for (i = 0; i < adev->sdma.num_instances; i++) {
rb_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL);
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0);
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, enable ? 1 : 0);
WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
ib_cntl = RREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL);
- ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, enable ? 1 : 0);
WREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL, ib_cntl);
}
}
@@ -1044,7 +1044,7 @@ static void sdma_v4_0_enable(struct amdgpu_device *adev, bool enable)
int i;
if (!enable) {
- sdma_v4_0_gfx_stop(adev);
+ sdma_v4_0_gfx_enable(adev, enable);
sdma_v4_0_rlc_stop(adev);
if (adev->sdma.has_page_queue)
sdma_v4_0_page_stop(adev);
@@ -1960,8 +1960,10 @@ static int sdma_v4_0_suspend(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
/* SMU saves SDMA state for us */
- if (adev->in_s0ix)
+ if (adev->in_s0ix) {
+ sdma_v4_0_gfx_enable(adev, false);
return 0;
+ }
return sdma_v4_0_hw_fini(adev);
}
@@ -1971,8 +1973,12 @@ static int sdma_v4_0_resume(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
/* SMU restores SDMA state for us */
- if (adev->in_s0ix)
+ if (adev->in_s0ix) {
+ sdma_v4_0_enable(adev, true);
+ sdma_v4_0_gfx_enable(adev, true);
+ amdgpu_ttm_set_buffer_funcs_status(adev, true);
return 0;
+ }
return sdma_v4_0_hw_init(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index da3beb0bf2fa..049c26a45d85 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -455,6 +455,9 @@ static void sdma_v6_0_enable(struct amdgpu_device *adev, bool enable)
sdma_v6_0_rlc_stop(adev);
}
+ if (amdgpu_sriov_vf(adev))
+ return;
+
for (i = 0; i < adev->sdma.num_instances; i++) {
f32_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL));
f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1);
@@ -1523,6 +1526,7 @@ static const struct amdgpu_ring_funcs sdma_v6_0_ring_funcs = {
.align_mask = 0xf,
.nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
.support_64bit_ptrs = true,
+ .secure_submission_supported = true,
.vmhub = AMDGPU_GFXHUB_0,
.get_rptr = sdma_v6_0_ring_get_rptr,
.get_wptr = sdma_v6_0_ring_get_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index 4d5e718540aa..abca8b529721 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -112,14 +112,12 @@ static void si_dma_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
static void si_dma_stop(struct amdgpu_device *adev)
{
- struct amdgpu_ring *ring;
u32 rb_cntl;
unsigned i;
amdgpu_sdma_unset_buffer_funcs_helper(adev);
for (i = 0; i < adev->sdma.num_instances; i++) {
- ring = &adev->sdma.instance[i].ring;
/* dma0 */
rb_cntl = RREG32(DMA_RB_CNTL + sdma_offsets[i]);
rb_cntl &= ~DMA_RB_ENABLE;
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
index e3b2b6b4f1a6..7cd17dda32ce 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
@@ -103,10 +103,10 @@ static const struct amdgpu_video_codecs vega_video_codecs_encode =
/* Vega */
static const struct amdgpu_video_codec_info vega_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 4096, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
};
@@ -120,10 +120,10 @@ static const struct amdgpu_video_codecs vega_video_codecs_decode =
/* Raven */
static const struct amdgpu_video_codec_info rv_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 4096, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 4096, 4096, 0)},
@@ -138,10 +138,10 @@ static const struct amdgpu_video_codecs rv_video_codecs_decode =
/* Renoir, Arcturus */
static const struct amdgpu_video_codec_info rn_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4906, 3)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4906, 5)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4906, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15d.h b/drivers/gpu/drm/amd/amdgpu/soc15d.h
index 799925d22fc8..2357ff39323f 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15d.h
+++ b/drivers/gpu/drm/amd/amdgpu/soc15d.h
@@ -162,6 +162,7 @@
* 2 - Bypass
*/
#define INDIRECT_BUFFER_PRE_ENB(x) ((x) << 21)
+#define INDIRECT_BUFFER_PRE_RESUME(x) ((x) << 30)
#define PACKET3_COPY_DATA 0x40
#define PACKET3_PFP_SYNC_ME 0x42
#define PACKET3_COND_WRITE 0x45
@@ -184,6 +185,7 @@
#define EOP_TC_ACTION_EN (1 << 17) /* L2 */
#define EOP_TC_NC_ACTION_EN (1 << 19)
#define EOP_TC_MD_ACTION_EN (1 << 21) /* L2 metadata */
+#define EOP_EXEC (1 << 28) /* For Trailing Fence */
#define DATA_SEL(x) ((x) << 29)
/* 0 - discard
diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
index e08044008186..7d5fdf450d0c 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -43,6 +43,7 @@
#include "soc15.h"
#include "soc15_common.h"
#include "soc21.h"
+#include "mxgpu_nv.h"
static const struct amd_ip_funcs soc21_common_ip_funcs;
@@ -61,7 +62,7 @@ static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode =
static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array[] =
{
- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
@@ -322,8 +323,10 @@ soc21_asic_reset_method(struct amdgpu_device *adev)
switch (adev->ip_versions[MP1_HWIP][0]) {
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 7):
+ case IP_VERSION(13, 0, 10):
return AMD_RESET_METHOD_MODE1;
case IP_VERSION(13, 0, 4):
+ case IP_VERSION(13, 0, 11):
return AMD_RESET_METHOD_MODE2;
default:
if (amdgpu_dpm_is_baco_supported(adev))
@@ -584,10 +587,6 @@ static int soc21_common_early_init(void *handle)
AMD_PG_SUPPORT_JPEG |
AMD_PG_SUPPORT_ATHUB |
AMD_PG_SUPPORT_MMHUB;
- if (amdgpu_sriov_vf(adev)) {
- adev->cg_flags = 0;
- adev->pg_flags = 0;
- }
adev->external_rev_id = adev->rev_id + 0x1; // TODO: need update
break;
case IP_VERSION(11, 0, 2):
@@ -645,28 +644,63 @@ static int soc21_common_early_init(void *handle)
adev->pg_flags = AMD_PG_SUPPORT_VCN |
AMD_PG_SUPPORT_VCN_DPG |
AMD_PG_SUPPORT_JPEG;
- if (amdgpu_sriov_vf(adev)) {
- /* hypervisor control CG and PG enablement */
- adev->cg_flags = 0;
- adev->pg_flags = 0;
- }
adev->external_rev_id = adev->rev_id + 0x20;
break;
+ case IP_VERSION(11, 0, 4):
+ adev->cg_flags =
+ AMD_CG_SUPPORT_GFX_CGCG |
+ AMD_CG_SUPPORT_GFX_CGLS |
+ AMD_CG_SUPPORT_GFX_MGCG |
+ AMD_CG_SUPPORT_GFX_FGCG |
+ AMD_CG_SUPPORT_REPEATER_FGCG |
+ AMD_CG_SUPPORT_GFX_PERF_CLK |
+ AMD_CG_SUPPORT_MC_MGCG |
+ AMD_CG_SUPPORT_MC_LS |
+ AMD_CG_SUPPORT_HDP_MGCG |
+ AMD_CG_SUPPORT_HDP_LS |
+ AMD_CG_SUPPORT_ATHUB_MGCG |
+ AMD_CG_SUPPORT_ATHUB_LS |
+ AMD_CG_SUPPORT_IH_CG |
+ AMD_CG_SUPPORT_BIF_MGCG |
+ AMD_CG_SUPPORT_BIF_LS |
+ AMD_CG_SUPPORT_VCN_MGCG |
+ AMD_CG_SUPPORT_JPEG_MGCG;
+ adev->pg_flags = AMD_PG_SUPPORT_VCN |
+ AMD_PG_SUPPORT_GFX_PG |
+ AMD_PG_SUPPORT_JPEG;
+ adev->external_rev_id = adev->rev_id + 0x1;
+ break;
+
default:
/* FIXME: not supported yet */
return -EINVAL;
}
+ if (amdgpu_sriov_vf(adev)) {
+ amdgpu_virt_init_setting(adev);
+ xgpu_nv_mailbox_set_irq_funcs(adev);
+ }
+
return 0;
}
static int soc21_common_late_init(void *handle)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (amdgpu_sriov_vf(adev))
+ xgpu_nv_mailbox_get_irq(adev);
+
return 0;
}
static int soc21_common_sw_init(void *handle)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (amdgpu_sriov_vf(adev))
+ xgpu_nv_mailbox_add_irq_id(adev);
+
return 0;
}
@@ -704,6 +738,9 @@ static int soc21_common_hw_fini(void *handle)
/* disable the doorbell aperture */
soc21_enable_doorbell_aperture(adev, false);
+ if (amdgpu_sriov_vf(adev))
+ xgpu_nv_mailbox_put_irq(adev);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
index 5d5d031c9e7d..72fd963f178b 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
@@ -187,9 +187,9 @@ static void umc_v6_7_ecc_info_query_ras_error_count(struct amdgpu_device *adev,
}
}
-static void umc_v6_7_convert_error_address(struct amdgpu_device *adev,
- struct ras_err_data *err_data, uint64_t err_addr,
- uint32_t ch_inst, uint32_t umc_inst)
+void umc_v6_7_convert_error_address(struct amdgpu_device *adev,
+ struct ras_err_data *err_data, uint64_t err_addr,
+ uint32_t ch_inst, uint32_t umc_inst)
{
uint32_t channel_index;
uint64_t soc_pa, retired_page, column;
@@ -553,5 +553,4 @@ struct amdgpu_umc_ras umc_v6_7_ras = {
.query_ras_poison_mode = umc_v6_7_query_ras_poison_mode,
.ecc_info_query_ras_error_count = umc_v6_7_ecc_info_query_ras_error_count,
.ecc_info_query_ras_error_address = umc_v6_7_ecc_info_query_ras_error_address,
- .convert_ras_error_address = umc_v6_7_convert_error_address,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h
index fe41ed2f5945..105245d5b6e5 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h
@@ -71,5 +71,7 @@ extern const uint32_t
umc_v6_7_channel_idx_tbl_second[UMC_V6_7_UMC_INSTANCE_NUM][UMC_V6_7_CHANNEL_INSTANCE_NUM];
extern const uint32_t
umc_v6_7_channel_idx_tbl_first[UMC_V6_7_UMC_INSTANCE_NUM][UMC_V6_7_CHANNEL_INSTANCE_NUM];
-
+void umc_v6_7_convert_error_address(struct amdgpu_device *adev,
+ struct ras_err_data *err_data, uint64_t err_addr,
+ uint32_t ch_inst, uint32_t umc_inst);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
index 91235df54e22..b7da4528cf0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
@@ -46,6 +46,16 @@ const struct channelnum_map_colbit umc_v8_10_channelnum_map_colbit_table[] = {
};
const uint32_t
+ umc_v8_10_channel_idx_tbl_ext0[]
+ [UMC_V8_10_UMC_INSTANCE_NUM]
+ [UMC_V8_10_CHANNEL_INSTANCE_NUM] = {
+ {{1, 5}, {7, 3}},
+ {{14, 15}, {13, 12}},
+ {{10, 11}, {9, 8}},
+ {{6, 2}, {0, 4}}
+ };
+
+const uint32_t
umc_v8_10_channel_idx_tbl[]
[UMC_V8_10_UMC_INSTANCE_NUM]
[UMC_V8_10_CHANNEL_INSTANCE_NUM] = {
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.h b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.h
index 849ede88e111..25eaf4af5fcf 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.h
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.h
@@ -66,5 +66,9 @@ extern const uint32_t
[UMC_V8_10_UMC_INSTANCE_NUM]
[UMC_V8_10_CHANNEL_INSTANCE_NUM];
+extern const uint32_t
+ umc_v8_10_channel_idx_tbl_ext0[]
+ [UMC_V8_10_UMC_INSTANCE_NUM]
+ [UMC_V8_10_CHANNEL_INSTANCE_NUM];
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index 375c440957dc..5fe872f4bea7 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -216,8 +216,8 @@ static int uvd_v6_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle
uint64_t addr;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
+ AMDGPU_IB_POOL_DIRECT, &job);
if (r)
return r;
@@ -280,8 +280,8 @@ static int uvd_v6_0_enc_get_destroy_msg(struct amdgpu_ring *ring,
uint64_t addr;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
+ AMDGPU_IB_POOL_DIRECT, &job);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
index e668b3baa8c6..e407be6cb63c 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
@@ -213,7 +213,7 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring)
*
* Open up a stream for HW test
*/
-static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, u32 handle,
struct amdgpu_bo *bo,
struct dma_fence **fence)
{
@@ -224,8 +224,8 @@ static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle
uint64_t addr;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
+ AMDGPU_IB_POOL_DIRECT, &job);
if (r)
return r;
@@ -276,7 +276,7 @@ err:
*
* Close up a stream for HW test or if userspace failed to do so
*/
-static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, u32 handle,
struct amdgpu_bo *bo,
struct dma_fence **fence)
{
@@ -287,8 +287,8 @@ static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handl
uint64_t addr;
int i, r;
- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
- AMDGPU_IB_POOL_DIRECT, &job);
+ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
+ AMDGPU_IB_POOL_DIRECT, &job);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 8a7006d62a87..ec87b00f2e05 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -770,6 +770,33 @@ static void vcn_v2_5_enable_clock_gating(struct amdgpu_device *adev)
}
}
+static void vcn_v2_6_enable_ras(struct amdgpu_device *adev, int inst_idx,
+ bool indirect)
+{
+ uint32_t tmp;
+
+ if (adev->ip_versions[UVD_HWIP][0] != IP_VERSION(2, 6, 0))
+ return;
+
+ tmp = VCN_RAS_CNTL__VCPU_VCODEC_REARM_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_IH_EN_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_PMI_EN_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_STALL_EN_MASK;
+ WREG32_SOC15_DPG_MODE(inst_idx,
+ SOC15_DPG_MODE_OFFSET(VCN, 0, mmVCN_RAS_CNTL),
+ tmp, 0, indirect);
+
+ tmp = UVD_VCPU_INT_EN__RASCNTL_VCPU_VCODEC_EN_MASK;
+ WREG32_SOC15_DPG_MODE(inst_idx,
+ SOC15_DPG_MODE_OFFSET(VCN, 0, mmUVD_VCPU_INT_EN),
+ tmp, 0, indirect);
+
+ tmp = UVD_SYS_INT_EN__RASCNTL_VCPU_VCODEC_EN_MASK;
+ WREG32_SOC15_DPG_MODE(inst_idx,
+ SOC15_DPG_MODE_OFFSET(VCN, 0, mmUVD_SYS_INT_EN),
+ tmp, 0, indirect);
+}
+
static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, bool indirect)
{
volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr;
@@ -849,6 +876,8 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
VCN, 0, mmUVD_LMI_CTRL2), 0, 0, indirect);
+ vcn_v2_6_enable_ras(adev, inst_idx, indirect);
+
/* unblock VCPU register access */
WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
VCN, 0, mmUVD_RB_ARB_CTRL), 0, 0, indirect);
@@ -2002,16 +2031,5 @@ static void vcn_v2_5_set_ras_funcs(struct amdgpu_device *adev)
break;
}
- if (adev->vcn.ras) {
- amdgpu_ras_register_ras_block(adev, &adev->vcn.ras->ras_block);
-
- strcpy(adev->vcn.ras->ras_block.ras_comm.name, "vcn");
- adev->vcn.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__VCN;
- adev->vcn.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
- adev->vcn.ras_if = &adev->vcn.ras->ras_block.ras_comm;
-
- /* If don't define special ras_late_init function, use default ras_late_init */
- if (!adev->vcn.ras->ras_block.ras_late_init)
- adev->vcn.ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
- }
+ amdgpu_vcn_set_ras_funcs(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 897a5ce9c9da..1e2b22299975 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -31,6 +31,7 @@
#include "soc15_hw_ip.h"
#include "vcn_v2_0.h"
#include "mmsch_v4_0.h"
+#include "vcn_v4_0.h"
#include "vcn/vcn_4_0_0_offset.h"
#include "vcn/vcn_4_0_0_sh_mask.h"
@@ -64,6 +65,7 @@ static int vcn_v4_0_set_powergating_state(void *handle,
static int vcn_v4_0_pause_dpg_mode(struct amdgpu_device *adev,
int inst_idx, struct dpg_pause_state *new_state);
static void vcn_v4_0_unified_ring_set_wptr(struct amdgpu_ring *ring);
+static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev);
/**
* vcn_v4_0_early_init - set function pointers
@@ -84,6 +86,7 @@ static int vcn_v4_0_early_init(void *handle)
vcn_v4_0_set_unified_ring_funcs(adev);
vcn_v4_0_set_irq_funcs(adev);
+ vcn_v4_0_set_ras_funcs(adev);
return 0;
}
@@ -100,7 +103,6 @@ static int vcn_v4_0_sw_init(void *handle)
struct amdgpu_ring *ring;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int i, r;
- int vcn_doorbell_index = 0;
r = amdgpu_vcn_sw_init(adev);
if (r)
@@ -112,12 +114,6 @@ static int vcn_v4_0_sw_init(void *handle)
if (r)
return r;
- if (amdgpu_sriov_vf(adev)) {
- vcn_doorbell_index = adev->doorbell_index.vcn.vcn_ring0_1 - MMSCH_DOORBELL_OFFSET;
- /* get DWORD offset */
- vcn_doorbell_index = vcn_doorbell_index << 1;
- }
-
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
volatile struct amdgpu_vcn4_fw_shared *fw_shared;
@@ -132,10 +128,16 @@ static int vcn_v4_0_sw_init(void *handle)
if (r)
return r;
+ /* VCN POISON TRAP */
+ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
+ VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].irq);
+ if (r)
+ return r;
+
ring = &adev->vcn.inst[i].ring_enc[0];
ring->use_doorbell = true;
if (amdgpu_sriov_vf(adev))
- ring->doorbell_index = vcn_doorbell_index + i * (adev->vcn.num_enc_rings + 1) + 1;
+ ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + i * (adev->vcn.num_enc_rings + 1) + 1;
else
ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * i;
@@ -296,6 +298,7 @@ static int vcn_v4_0_hw_fini(void *handle)
}
}
+ amdgpu_irq_put(adev, &adev->vcn.inst[i].irq, 0);
}
return 0;
@@ -859,6 +862,28 @@ static void vcn_v4_0_enable_clock_gating(struct amdgpu_device *adev, int inst)
return;
}
+static void vcn_v4_0_enable_ras(struct amdgpu_device *adev, int inst_idx,
+ bool indirect)
+{
+ uint32_t tmp;
+
+ if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+ return;
+
+ tmp = VCN_RAS_CNTL__VCPU_VCODEC_REARM_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_IH_EN_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_PMI_EN_MASK |
+ VCN_RAS_CNTL__VCPU_VCODEC_STALL_EN_MASK;
+ WREG32_SOC15_DPG_MODE(inst_idx,
+ SOC15_DPG_MODE_OFFSET(VCN, 0, regVCN_RAS_CNTL),
+ tmp, 0, indirect);
+
+ tmp = UVD_SYS_INT_EN__RASCNTL_VCPU_VCODEC_EN_MASK;
+ WREG32_SOC15_DPG_MODE(inst_idx,
+ SOC15_DPG_MODE_OFFSET(VCN, 0, regUVD_SYS_INT_EN),
+ tmp, 0, indirect);
+}
+
/**
* vcn_v4_0_start_dpg_mode - VCN start with dpg mode
*
@@ -947,6 +972,8 @@ static int vcn_v4_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
VCN, inst_idx, regUVD_LMI_CTRL2), tmp, 0, indirect);
+ vcn_v4_0_enable_ras(adev, inst_idx, indirect);
+
/* enable master interrupt */
WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
VCN, inst_idx, regUVD_MASTINT_EN),
@@ -1939,6 +1966,9 @@ static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_
case VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE:
amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[0]);
break;
+ case VCN_4_0__SRCID_UVD_POISON:
+ amdgpu_vcn_process_poison_irq(adev, source, entry);
+ break;
default:
DRM_ERROR("Unhandled interrupt: %d %d\n",
entry->src_id, entry->src_data[0]);
@@ -2001,3 +2031,60 @@ const struct amdgpu_ip_block_version vcn_v4_0_ip_block =
.rev = 0,
.funcs = &vcn_v4_0_ip_funcs,
};
+
+static uint32_t vcn_v4_0_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_VCN_V4_0_VCPU_VCODEC:
+ reg_value = RREG32_SOC15(VCN, instance, regUVD_RAS_VCPU_VCODEC_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_VCPU_VCODEC_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in VCN%d, sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool vcn_v4_0_query_ras_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst, sub;
+ uint32_t poison_stat = 0;
+
+ for (inst = 0; inst < adev->vcn.num_vcn_inst; inst++)
+ for (sub = 0; sub < AMDGPU_VCN_V4_0_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ vcn_v4_0_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
+const struct amdgpu_ras_block_hw_ops vcn_v4_0_ras_hw_ops = {
+ .query_poison_status = vcn_v4_0_query_ras_poison_status,
+};
+
+static struct amdgpu_vcn_ras vcn_v4_0_ras = {
+ .ras_block = {
+ .hw_ops = &vcn_v4_0_ras_hw_ops,
+ },
+};
+
+static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev)
+{
+ switch (adev->ip_versions[VCN_HWIP][0]) {
+ case IP_VERSION(4, 0, 0):
+ adev->vcn.ras = &vcn_v4_0_ras;
+ break;
+ default:
+ break;
+ }
+
+ amdgpu_vcn_set_ras_funcs(adev);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.h b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.h
index 7c5c9d91bb52..7d3d11f40f27 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.h
@@ -24,6 +24,12 @@
#ifndef __VCN_V4_0_H__
#define __VCN_V4_0_H__
+enum amdgpu_vcn_v4_0_sub_block {
+ AMDGPU_VCN_V4_0_VCPU_VCODEC = 0,
+
+ AMDGPU_VCN_V4_0_MAX_SUB_BLOCK,
+};
+
extern const struct amdgpu_ip_block_version vcn_v4_0_ip_block;
#endif /* __VCN_V4_0_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
index 59dfca093155..1706081d054d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
@@ -267,7 +267,7 @@ static void vega20_ih_reroute_ih(struct amdgpu_device *adev)
/* vega20 ih reroute will go through psp this
* function is used for newer asics starting arcturus
*/
- if (adev->asic_type >= CHIP_ARCTURUS) {
+ if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) {
/* Reroute to IH ring 1 for VMC */
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12);
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
@@ -308,7 +308,7 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
adev->nbio.funcs->ih_control(adev);
- if (adev->asic_type == CHIP_ARCTURUS &&
+ if ((adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 2, 1)) &&
adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
if (adev->irq.ih.use_bus_addr) {
@@ -321,7 +321,7 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
/* psp firmware won't program IH_CHICKEN for aldebaran
* driver needs to program it properly according to
* MC_SPACE type in IH_RB_CNTL */
- if (adev->asic_type == CHIP_ALDEBARAN) {
+ if (adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 4, 0)) {
ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN_ALDEBARAN);
if (adev->irq.ih.use_bus_addr) {
ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index f6ffd7c96ff9..12ef782eb478 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -2111,6 +2111,8 @@ void vi_set_virt_ops(struct amdgpu_device *adev)
int vi_set_ip_blocks(struct amdgpu_device *adev)
{
+ amdgpu_device_set_sriov_virtual_display(adev);
+
switch (adev->asic_type) {
case CHIP_TOPAZ:
/* topaz has no DCE, UVD, VCE */
@@ -2130,7 +2132,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gfx_v8_0_ip_block);
amdgpu_device_ip_block_add(adev, &sdma_v3_0_ip_block);
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
- if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
+ if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
else if (amdgpu_device_has_dc_support(adev))
@@ -2150,7 +2152,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gfx_v8_0_ip_block);
amdgpu_device_ip_block_add(adev, &sdma_v3_0_ip_block);
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
- if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
+ if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
else if (amdgpu_device_has_dc_support(adev))
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 5feaba6a77de..6d291aa6386b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1950,7 +1950,7 @@ static int criu_checkpoint(struct file *filep,
{
int ret;
uint32_t num_devices, num_bos, num_objects;
- uint64_t priv_size, priv_offset = 0;
+ uint64_t priv_size, priv_offset = 0, bo_priv_offset;
if (!args->devices || !args->bos || !args->priv_data)
return -EINVAL;
@@ -1994,38 +1994,34 @@ static int criu_checkpoint(struct file *filep,
if (ret)
goto exit_unlock;
- ret = criu_checkpoint_bos(p, num_bos, (uint8_t __user *)args->bos,
- (uint8_t __user *)args->priv_data, &priv_offset);
- if (ret)
- goto exit_unlock;
+ /* Leave room for BOs in the private data. They need to be restored
+ * before events, but we checkpoint them last to simplify the error
+ * handling.
+ */
+ bo_priv_offset = priv_offset;
+ priv_offset += num_bos * sizeof(struct kfd_criu_bo_priv_data);
if (num_objects) {
ret = kfd_criu_checkpoint_queues(p, (uint8_t __user *)args->priv_data,
&priv_offset);
if (ret)
- goto close_bo_fds;
+ goto exit_unlock;
ret = kfd_criu_checkpoint_events(p, (uint8_t __user *)args->priv_data,
&priv_offset);
if (ret)
- goto close_bo_fds;
+ goto exit_unlock;
ret = kfd_criu_checkpoint_svm(p, (uint8_t __user *)args->priv_data, &priv_offset);
if (ret)
- goto close_bo_fds;
+ goto exit_unlock;
}
-close_bo_fds:
- if (ret) {
- /* If IOCTL returns err, user assumes all FDs opened in criu_dump_bos are closed */
- uint32_t i;
- struct kfd_criu_bo_bucket *bo_buckets = (struct kfd_criu_bo_bucket *) args->bos;
-
- for (i = 0; i < num_bos; i++) {
- if (bo_buckets[i].alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM)
- close_fd(bo_buckets[i].dmabuf_fd);
- }
- }
+ /* This must be the last thing in this function that can fail.
+ * Otherwise we leak dmabuf file descriptors.
+ */
+ ret = criu_checkpoint_bos(p, num_bos, (uint8_t __user *)args->bos,
+ (uint8_t __user *)args->priv_data, &bo_priv_offset);
exit_unlock:
mutex_unlock(&p->mutex);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 8bfdfd062ff6..3251f4783ba1 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -50,16 +50,6 @@ static inline unsigned int get_and_inc_gpu_processor_id(
return current_id;
}
-/* Static table to describe GPU Cache information */
-struct kfd_gpu_cache_info {
- uint32_t cache_size;
- uint32_t cache_level;
- uint32_t flags;
- /* Indicates how many Compute Units share this cache
- * within a SA. Value = 1 indicates the cache is not shared
- */
- uint32_t num_cu_shared;
-};
static struct kfd_gpu_cache_info kaveri_cache_info[] = {
{
@@ -891,6 +881,54 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = {
},
};
+static struct kfd_gpu_cache_info dummy_cache_info[] = {
+ {
+ /* TCP L1 Cache per CU */
+ .cache_size = 16,
+ .cache_level = 1,
+ .flags = (CRAT_CACHE_FLAGS_ENABLED |
+ CRAT_CACHE_FLAGS_DATA_CACHE |
+ CRAT_CACHE_FLAGS_SIMD_CACHE),
+ .num_cu_shared = 1,
+ },
+ {
+ /* Scalar L1 Instruction Cache per SQC */
+ .cache_size = 32,
+ .cache_level = 1,
+ .flags = (CRAT_CACHE_FLAGS_ENABLED |
+ CRAT_CACHE_FLAGS_INST_CACHE |
+ CRAT_CACHE_FLAGS_SIMD_CACHE),
+ .num_cu_shared = 2,
+ },
+ {
+ /* Scalar L1 Data Cache per SQC */
+ .cache_size = 16,
+ .cache_level = 1,
+ .flags = (CRAT_CACHE_FLAGS_ENABLED |
+ CRAT_CACHE_FLAGS_DATA_CACHE |
+ CRAT_CACHE_FLAGS_SIMD_CACHE),
+ .num_cu_shared = 2,
+ },
+ {
+ /* GL1 Data Cache per SA */
+ .cache_size = 128,
+ .cache_level = 1,
+ .flags = (CRAT_CACHE_FLAGS_ENABLED |
+ CRAT_CACHE_FLAGS_DATA_CACHE |
+ CRAT_CACHE_FLAGS_SIMD_CACHE),
+ .num_cu_shared = 6,
+ },
+ {
+ /* L2 Data Cache per GPU (Total Tex Cache) */
+ .cache_size = 2048,
+ .cache_level = 2,
+ .flags = (CRAT_CACHE_FLAGS_ENABLED |
+ CRAT_CACHE_FLAGS_DATA_CACHE |
+ CRAT_CACHE_FLAGS_SIMD_CACHE),
+ .num_cu_shared = 6,
+ },
+};
+
static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev,
struct crat_subtype_computeunit *cu)
{
@@ -1071,8 +1109,12 @@ static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache,
props->cachelines_per_tag = cache->lines_per_tag;
props->cache_assoc = cache->associativity;
props->cache_latency = cache->cache_latency;
+
memcpy(props->sibling_map, cache->sibling_map,
- sizeof(props->sibling_map));
+ CRAT_SIBLINGMAP_SIZE);
+
+ /* set the sibling_map_size as 32 for CRAT from ACPI */
+ props->sibling_map_size = CRAT_SIBLINGMAP_SIZE;
if (cache->flags & CRAT_CACHE_FLAGS_DATA_CACHE)
props->cache_type |= HSA_CACHE_TYPE_DATA;
@@ -1083,7 +1125,6 @@ static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache,
if (cache->flags & CRAT_CACHE_FLAGS_SIMD_CACHE)
props->cache_type |= HSA_CACHE_TYPE_HSACU;
- dev->cache_count++;
dev->node_props.caches_count++;
list_add_tail(&props->list, &dev->cache_props);
@@ -1291,125 +1332,6 @@ err:
return ret;
}
-/* Helper function. See kfd_fill_gpu_cache_info for parameter description */
-static int fill_in_l1_pcache(struct crat_subtype_cache *pcache,
- struct kfd_gpu_cache_info *pcache_info,
- struct kfd_cu_info *cu_info,
- int mem_available,
- int cu_bitmask,
- int cache_type, unsigned int cu_processor_id,
- int cu_block)
-{
- unsigned int cu_sibling_map_mask;
- int first_active_cu;
-
- /* First check if enough memory is available */
- if (sizeof(struct crat_subtype_cache) > mem_available)
- return -ENOMEM;
-
- cu_sibling_map_mask = cu_bitmask;
- cu_sibling_map_mask >>= cu_block;
- cu_sibling_map_mask &=
- ((1 << pcache_info[cache_type].num_cu_shared) - 1);
- first_active_cu = ffs(cu_sibling_map_mask);
-
- /* CU could be inactive. In case of shared cache find the first active
- * CU. and incase of non-shared cache check if the CU is inactive. If
- * inactive active skip it
- */
- if (first_active_cu) {
- memset(pcache, 0, sizeof(struct crat_subtype_cache));
- pcache->type = CRAT_SUBTYPE_CACHE_AFFINITY;
- pcache->length = sizeof(struct crat_subtype_cache);
- pcache->flags = pcache_info[cache_type].flags;
- pcache->processor_id_low = cu_processor_id
- + (first_active_cu - 1);
- pcache->cache_level = pcache_info[cache_type].cache_level;
- pcache->cache_size = pcache_info[cache_type].cache_size;
-
- /* Sibling map is w.r.t processor_id_low, so shift out
- * inactive CU
- */
- cu_sibling_map_mask =
- cu_sibling_map_mask >> (first_active_cu - 1);
-
- pcache->sibling_map[0] = (uint8_t)(cu_sibling_map_mask & 0xFF);
- pcache->sibling_map[1] =
- (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF);
- pcache->sibling_map[2] =
- (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF);
- pcache->sibling_map[3] =
- (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF);
- return 0;
- }
- return 1;
-}
-
-/* Helper function. See kfd_fill_gpu_cache_info for parameter description */
-static int fill_in_l2_l3_pcache(struct crat_subtype_cache *pcache,
- struct kfd_gpu_cache_info *pcache_info,
- struct kfd_cu_info *cu_info,
- int mem_available,
- int cache_type, unsigned int cu_processor_id)
-{
- unsigned int cu_sibling_map_mask;
- int first_active_cu;
- int i, j, k;
-
- /* First check if enough memory is available */
- if (sizeof(struct crat_subtype_cache) > mem_available)
- return -ENOMEM;
-
- cu_sibling_map_mask = cu_info->cu_bitmap[0][0];
- cu_sibling_map_mask &=
- ((1 << pcache_info[cache_type].num_cu_shared) - 1);
- first_active_cu = ffs(cu_sibling_map_mask);
-
- /* CU could be inactive. In case of shared cache find the first active
- * CU. and incase of non-shared cache check if the CU is inactive. If
- * inactive active skip it
- */
- if (first_active_cu) {
- memset(pcache, 0, sizeof(struct crat_subtype_cache));
- pcache->type = CRAT_SUBTYPE_CACHE_AFFINITY;
- pcache->length = sizeof(struct crat_subtype_cache);
- pcache->flags = pcache_info[cache_type].flags;
- pcache->processor_id_low = cu_processor_id
- + (first_active_cu - 1);
- pcache->cache_level = pcache_info[cache_type].cache_level;
- pcache->cache_size = pcache_info[cache_type].cache_size;
-
- /* Sibling map is w.r.t processor_id_low, so shift out
- * inactive CU
- */
- cu_sibling_map_mask =
- cu_sibling_map_mask >> (first_active_cu - 1);
- k = 0;
- for (i = 0; i < cu_info->num_shader_engines; i++) {
- for (j = 0; j < cu_info->num_shader_arrays_per_engine;
- j++) {
- pcache->sibling_map[k] =
- (uint8_t)(cu_sibling_map_mask & 0xFF);
- pcache->sibling_map[k+1] =
- (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF);
- pcache->sibling_map[k+2] =
- (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF);
- pcache->sibling_map[k+3] =
- (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF);
- k += 4;
- cu_sibling_map_mask =
- cu_info->cu_bitmap[i % 4][j + i / 4];
- cu_sibling_map_mask &= (
- (1 << pcache_info[cache_type].num_cu_shared)
- - 1);
- }
- }
- return 0;
- }
- return 1;
-}
-
-#define KFD_MAX_CACHE_TYPES 6
static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
struct kfd_gpu_cache_info *pcache_info)
@@ -1483,228 +1405,134 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
return i;
}
-/* kfd_fill_gpu_cache_info - Fill GPU cache info using kfd_gpu_cache_info
- * tables
- *
- * @kdev - [IN] GPU device
- * @gpu_processor_id - [IN] GPU processor ID to which these caches
- * associate
- * @available_size - [IN] Amount of memory available in pcache
- * @cu_info - [IN] Compute Unit info obtained from KGD
- * @pcache - [OUT] memory into which cache data is to be filled in.
- * @size_filled - [OUT] amount of data used up in pcache.
- * @num_of_entries - [OUT] number of caches added
- */
-static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev,
- int gpu_processor_id,
- int available_size,
- struct kfd_cu_info *cu_info,
- struct crat_subtype_cache *pcache,
- int *size_filled,
- int *num_of_entries)
+int kfd_get_gpu_cache_info(struct kfd_dev *kdev, struct kfd_gpu_cache_info **pcache_info)
{
- struct kfd_gpu_cache_info *pcache_info;
- struct kfd_gpu_cache_info cache_info[KFD_MAX_CACHE_TYPES];
int num_of_cache_types = 0;
- int i, j, k;
- int ct = 0;
- int mem_available = available_size;
- unsigned int cu_processor_id;
- int ret;
- unsigned int num_cu_shared;
switch (kdev->adev->asic_type) {
case CHIP_KAVERI:
- pcache_info = kaveri_cache_info;
+ *pcache_info = kaveri_cache_info;
num_of_cache_types = ARRAY_SIZE(kaveri_cache_info);
break;
case CHIP_HAWAII:
- pcache_info = hawaii_cache_info;
+ *pcache_info = hawaii_cache_info;
num_of_cache_types = ARRAY_SIZE(hawaii_cache_info);
break;
case CHIP_CARRIZO:
- pcache_info = carrizo_cache_info;
+ *pcache_info = carrizo_cache_info;
num_of_cache_types = ARRAY_SIZE(carrizo_cache_info);
break;
case CHIP_TONGA:
- pcache_info = tonga_cache_info;
+ *pcache_info = tonga_cache_info;
num_of_cache_types = ARRAY_SIZE(tonga_cache_info);
break;
case CHIP_FIJI:
- pcache_info = fiji_cache_info;
+ *pcache_info = fiji_cache_info;
num_of_cache_types = ARRAY_SIZE(fiji_cache_info);
break;
case CHIP_POLARIS10:
- pcache_info = polaris10_cache_info;
+ *pcache_info = polaris10_cache_info;
num_of_cache_types = ARRAY_SIZE(polaris10_cache_info);
break;
case CHIP_POLARIS11:
- pcache_info = polaris11_cache_info;
+ *pcache_info = polaris11_cache_info;
num_of_cache_types = ARRAY_SIZE(polaris11_cache_info);
break;
case CHIP_POLARIS12:
- pcache_info = polaris12_cache_info;
+ *pcache_info = polaris12_cache_info;
num_of_cache_types = ARRAY_SIZE(polaris12_cache_info);
break;
case CHIP_VEGAM:
- pcache_info = vegam_cache_info;
+ *pcache_info = vegam_cache_info;
num_of_cache_types = ARRAY_SIZE(vegam_cache_info);
break;
default:
switch (KFD_GC_VERSION(kdev)) {
case IP_VERSION(9, 0, 1):
- pcache_info = vega10_cache_info;
+ *pcache_info = vega10_cache_info;
num_of_cache_types = ARRAY_SIZE(vega10_cache_info);
break;
case IP_VERSION(9, 2, 1):
- pcache_info = vega12_cache_info;
+ *pcache_info = vega12_cache_info;
num_of_cache_types = ARRAY_SIZE(vega12_cache_info);
break;
case IP_VERSION(9, 4, 0):
case IP_VERSION(9, 4, 1):
- pcache_info = vega20_cache_info;
+ *pcache_info = vega20_cache_info;
num_of_cache_types = ARRAY_SIZE(vega20_cache_info);
break;
case IP_VERSION(9, 4, 2):
- pcache_info = aldebaran_cache_info;
+ *pcache_info = aldebaran_cache_info;
num_of_cache_types = ARRAY_SIZE(aldebaran_cache_info);
break;
case IP_VERSION(9, 1, 0):
case IP_VERSION(9, 2, 2):
- pcache_info = raven_cache_info;
+ *pcache_info = raven_cache_info;
num_of_cache_types = ARRAY_SIZE(raven_cache_info);
break;
case IP_VERSION(9, 3, 0):
- pcache_info = renoir_cache_info;
+ *pcache_info = renoir_cache_info;
num_of_cache_types = ARRAY_SIZE(renoir_cache_info);
break;
case IP_VERSION(10, 1, 10):
case IP_VERSION(10, 1, 2):
case IP_VERSION(10, 1, 3):
case IP_VERSION(10, 1, 4):
- pcache_info = navi10_cache_info;
+ *pcache_info = navi10_cache_info;
num_of_cache_types = ARRAY_SIZE(navi10_cache_info);
break;
case IP_VERSION(10, 1, 1):
- pcache_info = navi14_cache_info;
+ *pcache_info = navi14_cache_info;
num_of_cache_types = ARRAY_SIZE(navi14_cache_info);
break;
case IP_VERSION(10, 3, 0):
- pcache_info = sienna_cichlid_cache_info;
+ *pcache_info = sienna_cichlid_cache_info;
num_of_cache_types = ARRAY_SIZE(sienna_cichlid_cache_info);
break;
case IP_VERSION(10, 3, 2):
- pcache_info = navy_flounder_cache_info;
+ *pcache_info = navy_flounder_cache_info;
num_of_cache_types = ARRAY_SIZE(navy_flounder_cache_info);
break;
case IP_VERSION(10, 3, 4):
- pcache_info = dimgrey_cavefish_cache_info;
+ *pcache_info = dimgrey_cavefish_cache_info;
num_of_cache_types = ARRAY_SIZE(dimgrey_cavefish_cache_info);
break;
case IP_VERSION(10, 3, 1):
- pcache_info = vangogh_cache_info;
+ *pcache_info = vangogh_cache_info;
num_of_cache_types = ARRAY_SIZE(vangogh_cache_info);
break;
case IP_VERSION(10, 3, 5):
- pcache_info = beige_goby_cache_info;
+ *pcache_info = beige_goby_cache_info;
num_of_cache_types = ARRAY_SIZE(beige_goby_cache_info);
break;
case IP_VERSION(10, 3, 3):
- pcache_info = yellow_carp_cache_info;
+ *pcache_info = yellow_carp_cache_info;
num_of_cache_types = ARRAY_SIZE(yellow_carp_cache_info);
break;
case IP_VERSION(10, 3, 6):
- pcache_info = gc_10_3_6_cache_info;
+ *pcache_info = gc_10_3_6_cache_info;
num_of_cache_types = ARRAY_SIZE(gc_10_3_6_cache_info);
break;
case IP_VERSION(10, 3, 7):
- pcache_info = gfx1037_cache_info;
+ *pcache_info = gfx1037_cache_info;
num_of_cache_types = ARRAY_SIZE(gfx1037_cache_info);
break;
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
- pcache_info = cache_info;
+ case IP_VERSION(11, 0, 4):
num_of_cache_types =
- kfd_fill_gpu_cache_info_from_gfx_config(kdev, pcache_info);
+ kfd_fill_gpu_cache_info_from_gfx_config(kdev, *pcache_info);
break;
default:
- return -EINVAL;
- }
- }
-
- *size_filled = 0;
- *num_of_entries = 0;
-
- /* For each type of cache listed in the kfd_gpu_cache_info table,
- * go through all available Compute Units.
- * The [i,j,k] loop will
- * if kfd_gpu_cache_info.num_cu_shared = 1
- * will parse through all available CU
- * If (kfd_gpu_cache_info.num_cu_shared != 1)
- * then it will consider only one CU from
- * the shared unit
- */
-
- for (ct = 0; ct < num_of_cache_types; ct++) {
- cu_processor_id = gpu_processor_id;
- if (pcache_info[ct].cache_level == 1) {
- for (i = 0; i < cu_info->num_shader_engines; i++) {
- for (j = 0; j < cu_info->num_shader_arrays_per_engine; j++) {
- for (k = 0; k < cu_info->num_cu_per_sh;
- k += pcache_info[ct].num_cu_shared) {
- ret = fill_in_l1_pcache(pcache,
- pcache_info,
- cu_info,
- mem_available,
- cu_info->cu_bitmap[i % 4][j + i / 4],
- ct,
- cu_processor_id,
- k);
-
- if (ret < 0)
+ *pcache_info = dummy_cache_info;
+ num_of_cache_types = ARRAY_SIZE(dummy_cache_info);
+ pr_warn("dummy cache info is used temporarily and real cache info need update later.\n");
break;
-
- if (!ret) {
- pcache++;
- (*num_of_entries)++;
- mem_available -= sizeof(*pcache);
- (*size_filled) += sizeof(*pcache);
- }
-
- /* Move to next CU block */
- num_cu_shared = ((k + pcache_info[ct].num_cu_shared) <=
- cu_info->num_cu_per_sh) ?
- pcache_info[ct].num_cu_shared :
- (cu_info->num_cu_per_sh - k);
- cu_processor_id += num_cu_shared;
}
- }
- }
- } else {
- ret = fill_in_l2_l3_pcache(pcache,
- pcache_info,
- cu_info,
- mem_available,
- ct,
- cu_processor_id);
-
- if (ret < 0)
- break;
-
- if (!ret) {
- pcache++;
- (*num_of_entries)++;
- mem_available -= sizeof(*pcache);
- (*size_filled) += sizeof(*pcache);
- }
- }
}
-
- pr_debug("Added [%d] GPU cache entries\n", *num_of_entries);
-
- return 0;
+ return num_of_cache_types;
}
static bool kfd_ignore_crat(void)
@@ -2063,8 +1891,8 @@ static void kfd_find_numa_node_in_srat(struct kfd_dev *kdev)
struct acpi_table_header *table_header = NULL;
struct acpi_subtable_header *sub_header = NULL;
unsigned long table_end, subtable_len;
- u32 pci_id = pci_domain_nr(kdev->pdev->bus) << 16 |
- pci_dev_id(kdev->pdev);
+ u32 pci_id = pci_domain_nr(kdev->adev->pdev->bus) << 16 |
+ pci_dev_id(kdev->adev->pdev);
u32 bdf;
acpi_status status;
struct acpi_srat_cpu_affinity *cpu;
@@ -2139,7 +1967,7 @@ static void kfd_find_numa_node_in_srat(struct kfd_dev *kdev)
numa_node = 0;
if (numa_node != NUMA_NO_NODE)
- set_dev_node(&kdev->pdev->dev, numa_node);
+ set_dev_node(&kdev->adev->pdev->dev, numa_node);
}
#endif
@@ -2200,14 +2028,14 @@ static int kfd_fill_gpu_direct_io_link_to_cpu(int *avail_size,
sub_type_hdr->proximity_domain_from = proximity_domain;
#ifdef CONFIG_ACPI_NUMA
- if (kdev->pdev->dev.numa_node == NUMA_NO_NODE)
+ if (kdev->adev->pdev->dev.numa_node == NUMA_NO_NODE)
kfd_find_numa_node_in_srat(kdev);
#endif
#ifdef CONFIG_NUMA
- if (kdev->pdev->dev.numa_node == NUMA_NO_NODE)
+ if (kdev->adev->pdev->dev.numa_node == NUMA_NO_NODE)
sub_type_hdr->proximity_domain_to = 0;
else
- sub_type_hdr->proximity_domain_to = kdev->pdev->dev.numa_node;
+ sub_type_hdr->proximity_domain_to = kdev->adev->pdev->dev.numa_node;
#else
sub_type_hdr->proximity_domain_to = 0;
#endif
@@ -2263,8 +2091,6 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
struct kfd_cu_info cu_info;
int avail_size = *size;
uint32_t total_num_of_cu;
- int num_of_cache_entries = 0;
- int cache_mem_filled = 0;
uint32_t nid = 0;
int ret = 0;
@@ -2365,31 +2191,12 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
crat_table->length += sizeof(struct crat_subtype_memory);
crat_table->total_entries++;
- /* TODO: Fill in cache information. This information is NOT readily
- * available in KGD
- */
- sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
- sub_type_hdr->length);
- ret = kfd_fill_gpu_cache_info(kdev, cu->processor_id_low,
- avail_size,
- &cu_info,
- (struct crat_subtype_cache *)sub_type_hdr,
- &cache_mem_filled,
- &num_of_cache_entries);
-
- if (ret < 0)
- return ret;
-
- crat_table->length += cache_mem_filled;
- crat_table->total_entries += num_of_cache_entries;
- avail_size -= cache_mem_filled;
-
/* Fill in Subtype: IO_LINKS
* Only direct links are added here which is Link from GPU to
* its NUMA node. Indirect links are added by userspace.
*/
sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
- cache_mem_filled);
+ sub_type_hdr->length);
ret = kfd_fill_gpu_direct_io_link_to_cpu(&avail_size, kdev,
(struct crat_subtype_iolink *)sub_type_hdr, proximity_domain);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h
index 482ba84a728d..8d1e8ba58dee 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h
@@ -29,11 +29,10 @@
#pragma pack(1)
/*
- * 4CC signature values for the CRAT and CDIT ACPI tables
+ * 4CC signature value for the CRAT ACPI table
*/
#define CRAT_SIGNATURE "CRAT"
-#define CDIT_SIGNATURE "CDIT"
/*
* Component Resource Association Table (CRAT)
@@ -292,31 +291,22 @@ struct crat_subtype_generic {
uint32_t flags;
};
-/*
- * Component Locality Distance Information Table (CDIT)
- */
-#define CDIT_OEMID_LENGTH 6
-#define CDIT_OEMTABLEID_LENGTH 8
-
-struct cdit_header {
- uint32_t signature;
- uint32_t length;
- uint8_t revision;
- uint8_t checksum;
- uint8_t oem_id[CDIT_OEMID_LENGTH];
- uint8_t oem_table_id[CDIT_OEMTABLEID_LENGTH];
- uint32_t oem_revision;
- uint32_t creator_id;
- uint32_t creator_revision;
- uint32_t total_entries;
- uint16_t num_domains;
- uint8_t entry[1];
-};
-
#pragma pack()
struct kfd_dev;
+/* Static table to describe GPU Cache information */
+struct kfd_gpu_cache_info {
+ uint32_t cache_size;
+ uint32_t cache_level;
+ uint32_t flags;
+ /* Indicates how many Compute Units share this cache
+ * within a SA. Value = 1 indicates the cache is not shared
+ */
+ uint32_t num_cu_shared;
+};
+int kfd_get_gpu_cache_info(struct kfd_dev *kdev, struct kfd_gpu_cache_info **pcache_info);
+
int kfd_create_crat_image_acpi(void **crat_image, size_t *size);
void kfd_destroy_crat_image(void *crat_image);
int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 65a1d4f9004b..b8936340742b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -153,6 +153,7 @@ static void kfd_device_info_set_event_interrupt_class(struct kfd_dev *kfd)
case IP_VERSION(11, 0, 1):
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 3):
+ case IP_VERSION(11, 0, 4):
kfd->device_info.event_interrupt_class = &event_interrupt_class_v11;
break;
default:
@@ -227,7 +228,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
{
struct kfd_dev *kfd = NULL;
const struct kfd2kgd_calls *f2g = NULL;
- struct pci_dev *pdev = adev->pdev;
uint32_t gfx_target_version = 0;
switch (adev->asic_type) {
@@ -395,6 +395,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
f2g = &gfx_v11_kfd2kgd;
break;
case IP_VERSION(11, 0, 1):
+ case IP_VERSION(11, 0, 4):
gfx_target_version = 110003;
f2g = &gfx_v11_kfd2kgd;
break;
@@ -429,7 +430,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
kfd->adev = adev;
kfd_device_info_init(kfd, vf, gfx_target_version);
- kfd->pdev = pdev;
kfd->init_complete = false;
kfd->kfd2kgd = f2g;
atomic_set(&kfd->compute_profile, 0);
@@ -497,7 +497,10 @@ static int kfd_gws_init(struct kfd_dev *kfd)
(KFD_GC_VERSION(kfd) == IP_VERSION(9, 4, 1)
&& kfd->mec2_fw_version >= 0x30) ||
(KFD_GC_VERSION(kfd) == IP_VERSION(9, 4, 2)
- && kfd->mec2_fw_version >= 0x28))))
+ && kfd->mec2_fw_version >= 0x28) ||
+ (KFD_GC_VERSION(kfd) >= IP_VERSION(10, 3, 0)
+ && KFD_GC_VERSION(kfd) < IP_VERSION(11, 0, 0)
+ && kfd->mec2_fw_version >= 0x6b))))
ret = amdgpu_amdkfd_alloc_gws(kfd->adev,
kfd->adev->gds.gws_size, &kfd->gws);
@@ -511,12 +514,10 @@ static void kfd_smi_init(struct kfd_dev *dev)
}
bool kgd2kfd_device_init(struct kfd_dev *kfd,
- struct drm_device *ddev,
const struct kgd2kfd_shared_resources *gpu_resources)
{
unsigned int size, map_process_packet_size;
- kfd->ddev = ddev;
kfd->mec_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev,
KGD_ENGINE_MEC1);
kfd->mec2_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev,
@@ -541,7 +542,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
kfd->mec_fw_version < kfd->device_info.no_atomic_fw_version)) {
dev_info(kfd_device,
"skipped device %x:%x, PCI rejects atomics %d<%d\n",
- kfd->pdev->vendor, kfd->pdev->device,
+ kfd->adev->pdev->vendor, kfd->adev->pdev->device,
kfd->mec_fw_version,
kfd->device_info.no_atomic_fw_version);
return false;
@@ -650,8 +651,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
kfd_smi_init(kfd);
kfd->init_complete = true;
- dev_info(kfd_device, "added device %x:%x\n", kfd->pdev->vendor,
- kfd->pdev->device);
+ dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor,
+ kfd->adev->pdev->device);
pr_debug("Starting kfd with the following scheduling policy %d\n",
kfd->dqm->sched_policy);
@@ -676,7 +677,7 @@ alloc_gtt_mem_failure:
amdgpu_amdkfd_free_gws(kfd->adev, kfd->gws);
dev_err(kfd_device,
"device %x:%x NOT added due to errors\n",
- kfd->pdev->vendor, kfd->pdev->device);
+ kfd->adev->pdev->vendor, kfd->adev->pdev->device);
out:
return kfd->init_complete;
}
@@ -789,7 +790,7 @@ int kgd2kfd_resume_iommu(struct kfd_dev *kfd)
if (err)
dev_err(kfd_device,
"Failed to resume IOMMU for device %x:%x\n",
- kfd->pdev->vendor, kfd->pdev->device);
+ kfd->adev->pdev->vendor, kfd->adev->pdev->device);
return err;
}
@@ -801,7 +802,7 @@ static int kfd_resume(struct kfd_dev *kfd)
if (err)
dev_err(kfd_device,
"Error starting queue manager for device %x:%x\n",
- kfd->pdev->vendor, kfd->pdev->device);
+ kfd->adev->pdev->vendor, kfd->adev->pdev->device);
return err;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index 83e3ce9f6049..729d26d648af 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -506,6 +506,7 @@ int kfd_criu_restore_event(struct file *devkfd,
ret = create_other_event(p, ev, &ev_priv->event_id);
break;
}
+ mutex_unlock(&p->event_mutex);
exit:
if (ret)
@@ -513,8 +514,6 @@ exit:
kfree(ev_priv);
- mutex_unlock(&p->event_mutex);
-
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
index fbd0afe4da42..ec1bf611624e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
@@ -49,7 +49,7 @@ int kfd_iommu_check_device(struct kfd_dev *kfd)
return -ENODEV;
iommu_info.flags = 0;
- err = amd_iommu_device_info(kfd->pdev, &iommu_info);
+ err = amd_iommu_device_info(kfd->adev->pdev, &iommu_info);
if (err)
return err;
@@ -71,7 +71,7 @@ int kfd_iommu_device_init(struct kfd_dev *kfd)
return 0;
iommu_info.flags = 0;
- err = amd_iommu_device_info(kfd->pdev, &iommu_info);
+ err = amd_iommu_device_info(kfd->adev->pdev, &iommu_info);
if (err < 0) {
dev_err(kfd_device,
"error getting iommu info. is the iommu enabled?\n");
@@ -121,7 +121,7 @@ int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd)
return -EINVAL;
}
- err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread);
+ err = amd_iommu_bind_pasid(dev->adev->pdev, p->pasid, p->lead_thread);
if (!err)
pdd->bound = PDD_BOUND;
@@ -139,7 +139,8 @@ void kfd_iommu_unbind_process(struct kfd_process *p)
for (i = 0; i < p->n_pdds; i++)
if (p->pdds[i]->bound == PDD_BOUND)
- amd_iommu_unbind_pasid(p->pdds[i]->dev->pdev, p->pasid);
+ amd_iommu_unbind_pasid(p->pdds[i]->dev->adev->pdev,
+ p->pasid);
}
/* Callback for process shutdown invoked by the IOMMU driver */
@@ -222,7 +223,7 @@ static int kfd_bind_processes_to_device(struct kfd_dev *kfd)
continue;
}
- err = amd_iommu_bind_pasid(kfd->pdev, p->pasid,
+ err = amd_iommu_bind_pasid(kfd->adev->pdev, p->pasid,
p->lead_thread);
if (err < 0) {
pr_err("Unexpected pasid 0x%x binding failure\n",
@@ -282,9 +283,9 @@ void kfd_iommu_suspend(struct kfd_dev *kfd)
kfd_unbind_processes_from_device(kfd);
- amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
- amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL);
- amd_iommu_free_device(kfd->pdev);
+ amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev, NULL);
+ amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev, NULL);
+ amd_iommu_free_device(kfd->adev->pdev);
}
/** kfd_iommu_resume - Restore IOMMU after resume
@@ -302,20 +303,20 @@ int kfd_iommu_resume(struct kfd_dev *kfd)
pasid_limit = kfd_get_pasid_limit();
- err = amd_iommu_init_device(kfd->pdev, pasid_limit);
+ err = amd_iommu_init_device(kfd->adev->pdev, pasid_limit);
if (err)
return -ENXIO;
- amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
+ amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev,
iommu_pasid_shutdown_callback);
- amd_iommu_set_invalid_ppr_cb(kfd->pdev,
+ amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev,
iommu_invalid_ppr_cb);
err = kfd_bind_processes_to_device(kfd);
if (err) {
- amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
- amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL);
- amd_iommu_free_device(kfd->pdev);
+ amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev, NULL);
+ amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev, NULL);
+ amd_iommu_free_device(kfd->adev->pdev);
return err;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 22b077ac9a19..10048ce16aea 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -28,7 +28,6 @@
#include "amdgpu_sync.h"
#include "amdgpu_object.h"
#include "amdgpu_vm.h"
-#include "amdgpu_mn.h"
#include "amdgpu_res_cursor.h"
#include "kfd_priv.h"
#include "kfd_svm.h"
@@ -65,8 +64,11 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
num_bytes = npages * 8;
- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes,
- AMDGPU_IB_POOL_DELAYED, &job);
+ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ num_dw * 4 + num_bytes,
+ AMDGPU_IB_POOL_DELAYED,
+ &job);
if (r)
return r;
@@ -89,18 +91,10 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
cpu_addr = &job->ibs[0].ptr[num_dw];
amdgpu_gart_map(adev, 0, npages, addr, pte_flags, cpu_addr);
- r = amdgpu_job_submit(job, &adev->mman.entity,
- AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
- if (r)
- goto error_free;
-
+ fence = amdgpu_job_submit(job);
dma_fence_put(fence);
return r;
-
-error_free:
- amdgpu_job_free(job);
- return r;
}
/**
@@ -529,8 +523,8 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
for (addr = start; addr < end;) {
unsigned long next;
- vma = find_vma(mm, addr);
- if (!vma || addr < vma->vm_start)
+ vma = vma_lookup(mm, addr);
+ if (!vma)
break;
next = min(vma->vm_end, end);
@@ -798,8 +792,8 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm,
for (addr = start; addr < end;) {
unsigned long next;
- vma = find_vma(mm, addr);
- if (!vma || addr < vma->vm_start) {
+ vma = vma_lookup(mm, addr);
+ if (!vma) {
pr_debug("failed to find vma for prange %p\n", prange);
r = -EFAULT;
break;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h
deleted file mode 100644
index f9cd28690151..000000000000
--- a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR MIT */
-/*
- * Copyright 2014-2022 Advanced Micro Devices, Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef KFD_PM4_HEADERS_DIQ_H_
-#define KFD_PM4_HEADERS_DIQ_H_
-
-/*--------------------_INDIRECT_BUFFER-------------------- */
-
-#ifndef _PM4__INDIRECT_BUFFER_DEFINED
-#define _PM4__INDIRECT_BUFFER_DEFINED
-enum _INDIRECT_BUFFER_cache_policy_enum {
- cache_policy___indirect_buffer__lru = 0,
- cache_policy___indirect_buffer__stream = 1,
- cache_policy___indirect_buffer__bypass = 2
-};
-
-enum {
- IT_INDIRECT_BUFFER_PASID = 0x5C
-};
-
-struct pm4__indirect_buffer_pasid {
- union {
- union PM4_MES_TYPE_3_HEADER header; /* header */
- unsigned int ordinal1;
- };
-
- union {
- struct {
- unsigned int reserved1:2;
- unsigned int ib_base_lo:30;
- } bitfields2;
- unsigned int ordinal2;
- };
-
- union {
- struct {
- unsigned int ib_base_hi:16;
- unsigned int reserved2:16;
- } bitfields3;
- unsigned int ordinal3;
- };
-
- union {
- unsigned int control;
- unsigned int ordinal4;
- };
-
- union {
- struct {
- unsigned int pasid:10;
- unsigned int reserved4:22;
- } bitfields5;
- unsigned int ordinal5;
- };
-
-};
-
-#endif
-
-/*--------------------_RELEASE_MEM-------------------- */
-
-#ifndef _PM4__RELEASE_MEM_DEFINED
-#define _PM4__RELEASE_MEM_DEFINED
-enum _RELEASE_MEM_event_index_enum {
- event_index___release_mem__end_of_pipe = 5,
- event_index___release_mem__shader_done = 6
-};
-
-enum _RELEASE_MEM_cache_policy_enum {
- cache_policy___release_mem__lru = 0,
- cache_policy___release_mem__stream = 1,
- cache_policy___release_mem__bypass = 2
-};
-
-enum _RELEASE_MEM_dst_sel_enum {
- dst_sel___release_mem__memory_controller = 0,
- dst_sel___release_mem__tc_l2 = 1,
- dst_sel___release_mem__queue_write_pointer_register = 2,
- dst_sel___release_mem__queue_write_pointer_poll_mask_bit = 3
-};
-
-enum _RELEASE_MEM_int_sel_enum {
- int_sel___release_mem__none = 0,
- int_sel___release_mem__send_interrupt_only = 1,
- int_sel___release_mem__send_interrupt_after_write_confirm = 2,
- int_sel___release_mem__send_data_after_write_confirm = 3
-};
-
-enum _RELEASE_MEM_data_sel_enum {
- data_sel___release_mem__none = 0,
- data_sel___release_mem__send_32_bit_low = 1,
- data_sel___release_mem__send_64_bit_data = 2,
- data_sel___release_mem__send_gpu_clock_counter = 3,
- data_sel___release_mem__send_cp_perfcounter_hi_lo = 4,
- data_sel___release_mem__store_gds_data_to_memory = 5
-};
-
-struct pm4__release_mem {
- union {
- union PM4_MES_TYPE_3_HEADER header; /*header */
- unsigned int ordinal1;
- };
-
- union {
- struct {
- unsigned int event_type:6;
- unsigned int reserved1:2;
- enum _RELEASE_MEM_event_index_enum event_index:4;
- unsigned int tcl1_vol_action_ena:1;
- unsigned int tc_vol_action_ena:1;
- unsigned int reserved2:1;
- unsigned int tc_wb_action_ena:1;
- unsigned int tcl1_action_ena:1;
- unsigned int tc_action_ena:1;
- unsigned int reserved3:6;
- unsigned int atc:1;
- enum _RELEASE_MEM_cache_policy_enum cache_policy:2;
- unsigned int reserved4:5;
- } bitfields2;
- unsigned int ordinal2;
- };
-
- union {
- struct {
- unsigned int reserved5:16;
- enum _RELEASE_MEM_dst_sel_enum dst_sel:2;
- unsigned int reserved6:6;
- enum _RELEASE_MEM_int_sel_enum int_sel:3;
- unsigned int reserved7:2;
- enum _RELEASE_MEM_data_sel_enum data_sel:3;
- } bitfields3;
- unsigned int ordinal3;
- };
-
- union {
- struct {
- unsigned int reserved8:2;
- unsigned int address_lo_32b:30;
- } bitfields4;
- struct {
- unsigned int reserved9:3;
- unsigned int address_lo_64b:29;
- } bitfields5;
- unsigned int ordinal4;
- };
-
- unsigned int address_hi;
-
- unsigned int data_lo;
-
- unsigned int data_hi;
-
-};
-#endif
-
-
-/*--------------------_SET_CONFIG_REG-------------------- */
-
-#ifndef _PM4__SET_CONFIG_REG_DEFINED
-#define _PM4__SET_CONFIG_REG_DEFINED
-
-struct pm4__set_config_reg {
- union {
- union PM4_MES_TYPE_3_HEADER header; /*header */
- unsigned int ordinal1;
- };
-
- union {
- struct {
- unsigned int reg_offset:16;
- unsigned int reserved1:7;
- unsigned int vmid_shift:5;
- unsigned int insert_vmid:1;
- unsigned int reserved2:3;
- } bitfields2;
- unsigned int ordinal2;
- };
-
- unsigned int reg_data[1]; /*1..N of these fields */
-
-};
-#endif
-
-/*--------------------_WAIT_REG_MEM-------------------- */
-
-#ifndef _PM4__WAIT_REG_MEM_DEFINED
-#define _PM4__WAIT_REG_MEM_DEFINED
-enum _WAIT_REG_MEM_function_enum {
- function___wait_reg_mem__always_pass = 0,
- function___wait_reg_mem__less_than_ref_value = 1,
- function___wait_reg_mem__less_than_equal_to_the_ref_value = 2,
- function___wait_reg_mem__equal_to_the_reference_value = 3,
- function___wait_reg_mem__not_equal_reference_value = 4,
- function___wait_reg_mem__greater_than_or_equal_reference_value = 5,
- function___wait_reg_mem__greater_than_reference_value = 6,
- function___wait_reg_mem__reserved = 7
-};
-
-enum _WAIT_REG_MEM_mem_space_enum {
- mem_space___wait_reg_mem__register_space = 0,
- mem_space___wait_reg_mem__memory_space = 1
-};
-
-enum _WAIT_REG_MEM_operation_enum {
- operation___wait_reg_mem__wait_reg_mem = 0,
- operation___wait_reg_mem__wr_wait_wr_reg = 1
-};
-
-struct pm4__wait_reg_mem {
- union {
- union PM4_MES_TYPE_3_HEADER header; /*header */
- unsigned int ordinal1;
- };
-
- union {
- struct {
- enum _WAIT_REG_MEM_function_enum function:3;
- unsigned int reserved1:1;
- enum _WAIT_REG_MEM_mem_space_enum mem_space:2;
- enum _WAIT_REG_MEM_operation_enum operation:2;
- unsigned int reserved2:24;
- } bitfields2;
- unsigned int ordinal2;
- };
-
- union {
- struct {
- unsigned int reserved3:2;
- unsigned int memory_poll_addr_lo:30;
- } bitfields3;
- struct {
- unsigned int register_poll_addr:16;
- unsigned int reserved4:16;
- } bitfields4;
- struct {
- unsigned int register_write_addr:16;
- unsigned int reserved5:16;
- } bitfields5;
- unsigned int ordinal3;
- };
-
- union {
- struct {
- unsigned int poll_address_hi:16;
- unsigned int reserved6:16;
- } bitfields6;
- struct {
- unsigned int register_write_addr:16;
- unsigned int reserved7:16;
- } bitfields7;
- unsigned int ordinal4;
- };
-
- unsigned int reference;
-
- unsigned int mask;
-
- union {
- struct {
- unsigned int poll_interval:16;
- unsigned int reserved8:16;
- } bitfields8;
- unsigned int ordinal7;
- };
-
-};
-#endif
-
-
-#endif /* KFD_PM4_HEADERS_DIQ_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index bf610e3b683b..552c3ac85a13 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -254,8 +254,6 @@ struct kfd_dev {
struct amdgpu_device *adev;
struct kfd_device_info device_info;
- struct pci_dev *pdev;
- struct drm_device *ddev;
unsigned int id; /* topology stub index */
@@ -1365,7 +1363,7 @@ void kfd_dec_compute_active(struct kfd_dev *dev);
static inline int kfd_devcgroup_check_permission(struct kfd_dev *kfd)
{
#if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF)
- struct drm_device *ddev = kfd->ddev;
+ struct drm_device *ddev = adev_to_drm(kfd->adev);
return devcgroup_check_permission(DEVCG_DEV_CHAR, DRM_MAJOR,
ddev->render->index,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 951b63677248..a26257171ab7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1050,8 +1050,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
* for auto suspend
*/
if (pdd->runtime_inuse) {
- pm_runtime_mark_last_busy(pdd->dev->ddev->dev);
- pm_runtime_put_autosuspend(pdd->dev->ddev->dev);
+ pm_runtime_mark_last_busy(adev_to_drm(pdd->dev->adev)->dev);
+ pm_runtime_put_autosuspend(adev_to_drm(pdd->dev->adev)->dev);
pdd->runtime_inuse = false;
}
@@ -1633,9 +1633,9 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
* pdd is destroyed.
*/
if (!pdd->runtime_inuse) {
- err = pm_runtime_get_sync(dev->ddev->dev);
+ err = pm_runtime_get_sync(adev_to_drm(dev->adev)->dev);
if (err < 0) {
- pm_runtime_put_autosuspend(dev->ddev->dev);
+ pm_runtime_put_autosuspend(adev_to_drm(dev->adev)->dev);
return ERR_PTR(err);
}
}
@@ -1655,8 +1655,8 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
out:
/* balance runpm reference count and exit with error */
if (!pdd->runtime_inuse) {
- pm_runtime_mark_last_busy(dev->ddev->dev);
- pm_runtime_put_autosuspend(dev->ddev->dev);
+ pm_runtime_mark_last_busy(adev_to_drm(dev->adev)->dev);
+ pm_runtime_put_autosuspend(adev_to_drm(dev->adev)->dev);
}
return ERR_PTR(err);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 64fdf63093a0..814f99888ab1 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -26,7 +26,7 @@
#include "amdgpu_sync.h"
#include "amdgpu_object.h"
#include "amdgpu_vm.h"
-#include "amdgpu_mn.h"
+#include "amdgpu_hmm.h"
#include "amdgpu.h"
#include "amdgpu_xgmi.h"
#include "kfd_priv.h"
@@ -259,7 +259,7 @@ void svm_range_free_dma_mappings(struct svm_range *prange)
pr_debug("failed to find device idx %d\n", gpuidx);
continue;
}
- dev = &pdd->dev->pdev->dev;
+ dev = &pdd->dev->adev->pdev->dev;
svm_range_dma_unmap(dev, dma_addr, 0, prange->npages);
kvfree(dma_addr);
prange->dma_addr[gpuidx] = NULL;
@@ -1586,8 +1586,8 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
unsigned long npages;
bool readonly;
- vma = find_vma(mm, addr);
- if (!vma || addr < vma->vm_start) {
+ vma = vma_lookup(mm, addr);
+ if (!vma) {
r = -EFAULT;
goto unreserve_out;
}
@@ -1596,9 +1596,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
next = min(vma->vm_end, end);
npages = (next - addr) >> PAGE_SHIFT;
WRITE_ONCE(p->svms.faulting_task, current);
- r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL,
- addr, npages, &hmm_range,
- readonly, true, owner);
+ r = amdgpu_hmm_range_get_pages(&prange->notifier, addr, npages,
+ readonly, owner, NULL,
+ &hmm_range);
WRITE_ONCE(p->svms.faulting_task, NULL);
if (r) {
pr_debug("failed %d to get svm range pages\n", r);
@@ -2542,8 +2542,8 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr,
struct interval_tree_node *node;
unsigned long start_limit, end_limit;
- vma = find_vma(p->mm, addr << PAGE_SHIFT);
- if (!vma || (addr << PAGE_SHIFT) < vma->vm_start) {
+ vma = vma_lookup(p->mm, addr << PAGE_SHIFT);
+ if (!vma) {
pr_debug("VMA does not exist in address [0x%llx]\n", addr);
return -EFAULT;
}
@@ -2871,8 +2871,8 @@ retry_write_locked:
/* __do_munmap removed VMA, return success as we are handling stale
* retry fault.
*/
- vma = find_vma(mm, addr << PAGE_SHIFT);
- if (!vma || (addr << PAGE_SHIFT) < vma->vm_start) {
+ vma = vma_lookup(mm, addr << PAGE_SHIFT);
+ if (!vma) {
pr_debug("address 0x%llx VMA is removed\n", addr);
r = 0;
goto out_unlock_range;
@@ -3152,9 +3152,8 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size)
start <<= PAGE_SHIFT;
end = start + (size << PAGE_SHIFT);
do {
- vma = find_vma(p->mm, start);
- if (!vma || start < vma->vm_start ||
- (vma->vm_flags & device_vma))
+ vma = vma_lookup(p->mm, start);
+ if (!vma || (vma->vm_flags & device_vma))
return -EFAULT;
start = min(end, vma->vm_end);
} while (start < end);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index 3f0a4a415907..bceb1a5b2518 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -115,7 +115,7 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev)
down_read(&topology_lock);
list_for_each_entry(top_dev, &topology_device_list, list)
- if (top_dev->gpu && top_dev->gpu->pdev == pdev) {
+ if (top_dev->gpu && top_dev->gpu->adev->pdev == pdev) {
device = top_dev->gpu;
break;
}
@@ -364,7 +364,6 @@ static ssize_t kfd_cache_show(struct kobject *kobj, struct attribute *attr,
/* Making sure that the buffer is an empty string */
buffer[0] = 0;
-
cache = container_of(attr, struct kfd_cache_properties, attr);
if (cache->gpu && kfd_devcgroup_check_permission(cache->gpu))
return -EPERM;
@@ -379,12 +378,13 @@ static ssize_t kfd_cache_show(struct kobject *kobj, struct attribute *attr,
sysfs_show_32bit_prop(buffer, offs, "association", cache->cache_assoc);
sysfs_show_32bit_prop(buffer, offs, "latency", cache->cache_latency);
sysfs_show_32bit_prop(buffer, offs, "type", cache->cache_type);
+
offs += snprintf(buffer+offs, PAGE_SIZE-offs, "sibling_map ");
- for (i = 0; i < CRAT_SIBLINGMAP_SIZE; i++)
+ for (i = 0; i < cache->sibling_map_size; i++)
for (j = 0; j < sizeof(cache->sibling_map[0])*8; j++)
/* Check each bit */
offs += snprintf(buffer+offs, PAGE_SIZE-offs, "%d,",
- (cache->sibling_map[i] >> j) & 1);
+ (cache->sibling_map[i] >> j) & 1);
/* Replace the last "," with end of line */
buffer[offs-1] = '\n';
@@ -1169,13 +1169,12 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
local_mem_size = gpu->local_mem_info.local_mem_size_private +
gpu->local_mem_info.local_mem_size_public;
-
- buf[0] = gpu->pdev->devfn;
- buf[1] = gpu->pdev->subsystem_vendor |
- (gpu->pdev->subsystem_device << 16);
- buf[2] = pci_domain_nr(gpu->pdev->bus);
- buf[3] = gpu->pdev->device;
- buf[4] = gpu->pdev->bus->number;
+ buf[0] = gpu->adev->pdev->devfn;
+ buf[1] = gpu->adev->pdev->subsystem_vendor |
+ (gpu->adev->pdev->subsystem_device << 16);
+ buf[2] = pci_domain_nr(gpu->adev->pdev->bus);
+ buf[3] = gpu->adev->pdev->device;
+ buf[4] = gpu->adev->pdev->bus->number;
buf[5] = lower_32_bits(local_mem_size);
buf[6] = upper_32_bits(local_mem_size);
@@ -1198,7 +1197,6 @@ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu)
struct kfd_iolink_properties *iolink;
struct kfd_iolink_properties *p2plink;
- down_write(&topology_lock);
list_for_each_entry(dev, &topology_device_list, list) {
/* Discrete GPUs need their own topology device list
* entries. Don't assign them to CPU/APU nodes.
@@ -1222,7 +1220,6 @@ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu)
break;
}
}
- up_write(&topology_lock);
return out_dev;
}
@@ -1269,7 +1266,7 @@ static void kfd_set_iolink_no_atomics(struct kfd_topology_device *dev,
if (target_gpu_dev) {
uint32_t cap;
- pcie_capability_read_dword(target_gpu_dev->gpu->pdev,
+ pcie_capability_read_dword(target_gpu_dev->gpu->adev->pdev,
PCI_EXP_DEVCAP2, &cap);
if (!(cap & (PCI_EXP_DEVCAP2_ATOMIC_COMP32 |
@@ -1593,21 +1590,290 @@ out:
return ret;
}
+
+/* Helper function. See kfd_fill_gpu_cache_info for parameter description */
+static int fill_in_l1_pcache(struct kfd_cache_properties **props_ext,
+ struct kfd_gpu_cache_info *pcache_info,
+ struct kfd_cu_info *cu_info,
+ int cu_bitmask,
+ int cache_type, unsigned int cu_processor_id,
+ int cu_block)
+{
+ unsigned int cu_sibling_map_mask;
+ int first_active_cu;
+ struct kfd_cache_properties *pcache = NULL;
+
+ cu_sibling_map_mask = cu_bitmask;
+ cu_sibling_map_mask >>= cu_block;
+ cu_sibling_map_mask &= ((1 << pcache_info[cache_type].num_cu_shared) - 1);
+ first_active_cu = ffs(cu_sibling_map_mask);
+
+ /* CU could be inactive. In case of shared cache find the first active
+ * CU. and incase of non-shared cache check if the CU is inactive. If
+ * inactive active skip it
+ */
+ if (first_active_cu) {
+ pcache = kfd_alloc_struct(pcache);
+ if (!pcache)
+ return -ENOMEM;
+
+ memset(pcache, 0, sizeof(struct kfd_cache_properties));
+ pcache->processor_id_low = cu_processor_id + (first_active_cu - 1);
+ pcache->cache_level = pcache_info[cache_type].cache_level;
+ pcache->cache_size = pcache_info[cache_type].cache_size;
+
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_DATA_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_DATA;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_INST_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_INSTRUCTION;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_CPU_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_CPU;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_SIMD_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_HSACU;
+
+ /* Sibling map is w.r.t processor_id_low, so shift out
+ * inactive CU
+ */
+ cu_sibling_map_mask =
+ cu_sibling_map_mask >> (first_active_cu - 1);
+
+ pcache->sibling_map[0] = (uint8_t)(cu_sibling_map_mask & 0xFF);
+ pcache->sibling_map[1] =
+ (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF);
+ pcache->sibling_map[2] =
+ (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF);
+ pcache->sibling_map[3] =
+ (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF);
+
+ pcache->sibling_map_size = 4;
+ *props_ext = pcache;
+
+ return 0;
+ }
+ return 1;
+}
+
+/* Helper function. See kfd_fill_gpu_cache_info for parameter description */
+static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext,
+ struct kfd_gpu_cache_info *pcache_info,
+ struct kfd_cu_info *cu_info,
+ int cache_type, unsigned int cu_processor_id)
+{
+ unsigned int cu_sibling_map_mask;
+ int first_active_cu;
+ int i, j, k;
+ struct kfd_cache_properties *pcache = NULL;
+
+ cu_sibling_map_mask = cu_info->cu_bitmap[0][0];
+ cu_sibling_map_mask &=
+ ((1 << pcache_info[cache_type].num_cu_shared) - 1);
+ first_active_cu = ffs(cu_sibling_map_mask);
+
+ /* CU could be inactive. In case of shared cache find the first active
+ * CU. and incase of non-shared cache check if the CU is inactive. If
+ * inactive active skip it
+ */
+ if (first_active_cu) {
+ pcache = kfd_alloc_struct(pcache);
+ if (!pcache)
+ return -ENOMEM;
+
+ memset(pcache, 0, sizeof(struct kfd_cache_properties));
+ pcache->processor_id_low = cu_processor_id
+ + (first_active_cu - 1);
+ pcache->cache_level = pcache_info[cache_type].cache_level;
+ pcache->cache_size = pcache_info[cache_type].cache_size;
+
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_DATA_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_DATA;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_INST_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_INSTRUCTION;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_CPU_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_CPU;
+ if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_SIMD_CACHE)
+ pcache->cache_type |= HSA_CACHE_TYPE_HSACU;
+
+ /* Sibling map is w.r.t processor_id_low, so shift out
+ * inactive CU
+ */
+ cu_sibling_map_mask = cu_sibling_map_mask >> (first_active_cu - 1);
+ k = 0;
+
+ for (i = 0; i < cu_info->num_shader_engines; i++) {
+ for (j = 0; j < cu_info->num_shader_arrays_per_engine; j++) {
+ pcache->sibling_map[k] = (uint8_t)(cu_sibling_map_mask & 0xFF);
+ pcache->sibling_map[k+1] = (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF);
+ pcache->sibling_map[k+2] = (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF);
+ pcache->sibling_map[k+3] = (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF);
+ k += 4;
+
+ cu_sibling_map_mask = cu_info->cu_bitmap[i % 4][j + i / 4];
+ cu_sibling_map_mask &= ((1 << pcache_info[cache_type].num_cu_shared) - 1);
+ }
+ }
+ pcache->sibling_map_size = k;
+ *props_ext = pcache;
+ return 0;
+ }
+ return 1;
+}
+
+#define KFD_MAX_CACHE_TYPES 6
+
+/* kfd_fill_cache_non_crat_info - Fill GPU cache info using kfd_gpu_cache_info
+ * tables
+ */
+static void kfd_fill_cache_non_crat_info(struct kfd_topology_device *dev, struct kfd_dev *kdev)
+{
+ struct kfd_gpu_cache_info *pcache_info = NULL;
+ int i, j, k;
+ int ct = 0;
+ unsigned int cu_processor_id;
+ int ret;
+ unsigned int num_cu_shared;
+ struct kfd_cu_info cu_info;
+ struct kfd_cu_info *pcu_info;
+ int gpu_processor_id;
+ struct kfd_cache_properties *props_ext;
+ int num_of_entries = 0;
+ int num_of_cache_types = 0;
+ struct kfd_gpu_cache_info cache_info[KFD_MAX_CACHE_TYPES];
+
+ amdgpu_amdkfd_get_cu_info(kdev->adev, &cu_info);
+ pcu_info = &cu_info;
+
+ gpu_processor_id = dev->node_props.simd_id_base;
+
+ pcache_info = cache_info;
+ num_of_cache_types = kfd_get_gpu_cache_info(kdev, &pcache_info);
+ if (!num_of_cache_types) {
+ pr_warn("no cache info found\n");
+ return;
+ }
+
+ /* For each type of cache listed in the kfd_gpu_cache_info table,
+ * go through all available Compute Units.
+ * The [i,j,k] loop will
+ * if kfd_gpu_cache_info.num_cu_shared = 1
+ * will parse through all available CU
+ * If (kfd_gpu_cache_info.num_cu_shared != 1)
+ * then it will consider only one CU from
+ * the shared unit
+ */
+ for (ct = 0; ct < num_of_cache_types; ct++) {
+ cu_processor_id = gpu_processor_id;
+ if (pcache_info[ct].cache_level == 1) {
+ for (i = 0; i < pcu_info->num_shader_engines; i++) {
+ for (j = 0; j < pcu_info->num_shader_arrays_per_engine; j++) {
+ for (k = 0; k < pcu_info->num_cu_per_sh; k += pcache_info[ct].num_cu_shared) {
+
+ ret = fill_in_l1_pcache(&props_ext, pcache_info, pcu_info,
+ pcu_info->cu_bitmap[i % 4][j + i / 4], ct,
+ cu_processor_id, k);
+
+ if (ret < 0)
+ break;
+
+ if (!ret) {
+ num_of_entries++;
+ list_add_tail(&props_ext->list, &dev->cache_props);
+ }
+
+ /* Move to next CU block */
+ num_cu_shared = ((k + pcache_info[ct].num_cu_shared) <=
+ pcu_info->num_cu_per_sh) ?
+ pcache_info[ct].num_cu_shared :
+ (pcu_info->num_cu_per_sh - k);
+ cu_processor_id += num_cu_shared;
+ }
+ }
+ }
+ } else {
+ ret = fill_in_l2_l3_pcache(&props_ext, pcache_info,
+ pcu_info, ct, cu_processor_id);
+
+ if (ret < 0)
+ break;
+
+ if (!ret) {
+ num_of_entries++;
+ list_add_tail(&props_ext->list, &dev->cache_props);
+ }
+ }
+ }
+ dev->node_props.caches_count += num_of_entries;
+ pr_debug("Added [%d] GPU cache entries\n", num_of_entries);
+}
+
+static int kfd_topology_add_device_locked(struct kfd_dev *gpu, uint32_t gpu_id,
+ struct kfd_topology_device **dev)
+{
+ int proximity_domain = ++topology_crat_proximity_domain;
+ struct list_head temp_topology_device_list;
+ void *crat_image = NULL;
+ size_t image_size = 0;
+ int res;
+
+ res = kfd_create_crat_image_virtual(&crat_image, &image_size,
+ COMPUTE_UNIT_GPU, gpu,
+ proximity_domain);
+ if (res) {
+ pr_err("Error creating VCRAT for GPU (ID: 0x%x)\n",
+ gpu_id);
+ topology_crat_proximity_domain--;
+ goto err;
+ }
+
+ INIT_LIST_HEAD(&temp_topology_device_list);
+
+ res = kfd_parse_crat_table(crat_image,
+ &temp_topology_device_list,
+ proximity_domain);
+ if (res) {
+ pr_err("Error parsing VCRAT for GPU (ID: 0x%x)\n",
+ gpu_id);
+ topology_crat_proximity_domain--;
+ goto err;
+ }
+
+ kfd_topology_update_device_list(&temp_topology_device_list,
+ &topology_device_list);
+
+ *dev = kfd_assign_gpu(gpu);
+ if (WARN_ON(!*dev)) {
+ res = -ENODEV;
+ goto err;
+ }
+
+ /* Fill the cache affinity information here for the GPUs
+ * using VCRAT
+ */
+ kfd_fill_cache_non_crat_info(*dev, gpu);
+
+ /* Update the SYSFS tree, since we added another topology
+ * device
+ */
+ res = kfd_topology_update_sysfs();
+ if (!res)
+ sys_props.generation_count++;
+ else
+ pr_err("Failed to update GPU (ID: 0x%x) to sysfs topology. res=%d\n",
+ gpu_id, res);
+
+err:
+ kfd_destroy_crat_image(crat_image);
+ return res;
+}
+
int kfd_topology_add_device(struct kfd_dev *gpu)
{
uint32_t gpu_id;
struct kfd_topology_device *dev;
struct kfd_cu_info cu_info;
int res = 0;
- struct list_head temp_topology_device_list;
- void *crat_image = NULL;
- size_t image_size = 0;
- int proximity_domain;
int i;
const char *asic_name = amdgpu_asic_name[gpu->adev->asic_type];
- INIT_LIST_HEAD(&temp_topology_device_list);
-
gpu_id = kfd_generate_gpu_id(gpu);
pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
@@ -1617,50 +1883,13 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
* CRAT to create a new topology device. Once created assign the gpu to
* that topology device
*/
+ down_write(&topology_lock);
dev = kfd_assign_gpu(gpu);
- if (!dev) {
- down_write(&topology_lock);
- proximity_domain = ++topology_crat_proximity_domain;
-
- res = kfd_create_crat_image_virtual(&crat_image, &image_size,
- COMPUTE_UNIT_GPU, gpu,
- proximity_domain);
- if (res) {
- pr_err("Error creating VCRAT for GPU (ID: 0x%x)\n",
- gpu_id);
- topology_crat_proximity_domain--;
- return res;
- }
- res = kfd_parse_crat_table(crat_image,
- &temp_topology_device_list,
- proximity_domain);
- if (res) {
- pr_err("Error parsing VCRAT for GPU (ID: 0x%x)\n",
- gpu_id);
- topology_crat_proximity_domain--;
- goto err;
- }
-
- kfd_topology_update_device_list(&temp_topology_device_list,
- &topology_device_list);
-
- /* Update the SYSFS tree, since we added another topology
- * device
- */
- res = kfd_topology_update_sysfs();
- up_write(&topology_lock);
-
- if (!res)
- sys_props.generation_count++;
- else
- pr_err("Failed to update GPU (ID: 0x%x) to sysfs topology. res=%d\n",
- gpu_id, res);
- dev = kfd_assign_gpu(gpu);
- if (WARN_ON(!dev)) {
- res = -ENODEV;
- goto err;
- }
- }
+ if (!dev)
+ res = kfd_topology_add_device_locked(gpu, gpu_id, &dev);
+ up_write(&topology_lock);
+ if (res)
+ return res;
dev->gpu_id = gpu_id;
gpu->id = gpu_id;
@@ -1688,13 +1917,13 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
cu_info.num_shader_arrays_per_engine;
dev->node_props.gfx_target_version = gpu->device_info.gfx_target_version;
- dev->node_props.vendor_id = gpu->pdev->vendor;
- dev->node_props.device_id = gpu->pdev->device;
+ dev->node_props.vendor_id = gpu->adev->pdev->vendor;
+ dev->node_props.device_id = gpu->adev->pdev->device;
dev->node_props.capability |=
((dev->gpu->adev->rev_id << HSA_CAP_ASIC_REVISION_SHIFT) &
HSA_CAP_ASIC_REVISION_MASK);
- dev->node_props.location_id = pci_dev_id(gpu->pdev);
- dev->node_props.domain = pci_domain_nr(gpu->pdev->bus);
+ dev->node_props.location_id = pci_dev_id(gpu->adev->pdev);
+ dev->node_props.domain = pci_domain_nr(gpu->adev->pdev->bus);
dev->node_props.max_engine_clk_fcompute =
amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->adev);
dev->node_props.max_engine_clk_ccompute =
@@ -1783,11 +2012,9 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
kfd_debug_print_topology();
- if (!res)
- kfd_notify_gpu_change(gpu_id, 1);
-err:
- kfd_destroy_crat_image(crat_image);
- return res;
+ kfd_notify_gpu_change(gpu_id, 1);
+
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
index 9f6c949186c1..fca30d00a9bb 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
@@ -80,6 +80,8 @@ struct kfd_mem_properties {
struct attribute attr;
};
+#define CACHE_SIBLINGMAP_SIZE 64
+
struct kfd_cache_properties {
struct list_head list;
uint32_t processor_id_low;
@@ -90,10 +92,11 @@ struct kfd_cache_properties {
uint32_t cache_assoc;
uint32_t cache_latency;
uint32_t cache_type;
- uint8_t sibling_map[CRAT_SIBLINGMAP_SIZE];
+ uint8_t sibling_map[CACHE_SIBLINGMAP_SIZE];
struct kfd_dev *gpu;
struct kobject *kobj;
struct attribute attr;
+ uint32_t sibling_map_size;
};
struct kfd_iolink_properties {
@@ -128,7 +131,6 @@ struct kfd_topology_device {
uint32_t proximity_domain;
struct kfd_node_properties node_props;
struct list_head mem_props;
- uint32_t cache_count;
struct list_head cache_props;
struct list_head io_link_props;
struct list_head p2p_link_props;
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index 6925e0280dbe..2efe93f74f84 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -5,13 +5,21 @@ menu "Display Engine Configuration"
config DRM_AMD_DC
bool "AMD DC - Enable new display engine"
default y
+ depends on BROKEN || !CC_IS_CLANG || X86_64 || SPARC64 || ARM64
select SND_HDA_COMPONENT if SND_HDA_CORE
- select DRM_AMD_DC_DCN if (X86 || PPC_LONG_DOUBLE_128)
+ # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752
+ select DRM_AMD_DC_DCN if (X86 || PPC_LONG_DOUBLE_128 || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG))
help
Choose this option if you want to use the new display engine
support for AMDGPU. This adds required support for Vega and
Raven ASICs.
+ calculate_bandwidth() is presently broken on all !(X86_64 || SPARC64 || ARM64)
+ architectures built with Clang (all released versions), whereby the stack
+ frame gets blown up to well over 5k. This would cause an immediate kernel
+ panic on most architectures. We'll revert this when the following bug report
+ has been resolved: https://github.com/llvm/llvm-project/issues/41896.
+
config DRM_AMD_DC_DCN
def_bool n
help
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 589bee9acf16..77277d90b6e2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -82,7 +82,6 @@
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_edid.h>
#include <drm/drm_vblank.h>
@@ -1097,7 +1096,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
/* Initialize hardware. */
memset(&hw_params, 0, sizeof(hw_params));
hw_params.fb_base = adev->gmc.fb_start;
- hw_params.fb_offset = adev->gmc.aper_base;
+ hw_params.fb_offset = adev->vm_manager.vram_base_offset;
/* backdoor load firmware and trigger dmub running */
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
@@ -1219,7 +1218,7 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
pa_config->system_aperture.agp_top = (uint64_t)agp_top << 24;
pa_config->system_aperture.fb_base = adev->gmc.fb_start;
- pa_config->system_aperture.fb_offset = adev->gmc.aper_base;
+ pa_config->system_aperture.fb_offset = adev->vm_manager.vram_base_offset;
pa_config->system_aperture.fb_top = adev->gmc.fb_end;
pa_config->gart_config.page_table_start_addr = page_table_start.quad_part << 12;
@@ -1364,7 +1363,44 @@ static const struct dmi_system_id hpd_disconnect_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower Plus 7010"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower 7010"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF Plus 7010"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF 7010"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro Plus 7010"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro 7010"),
+ },
+ },
{}
+ /* TODO: refactor this from a fixed table to a dynamic option */
};
static void retrieve_dmi_info(struct amdgpu_display_manager *dm)
@@ -1397,9 +1433,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
memset(&init_params, 0, sizeof(init_params));
#endif
+ mutex_init(&adev->dm.dpia_aux_lock);
mutex_init(&adev->dm.dc_lock);
mutex_init(&adev->dm.audio_lock);
- spin_lock_init(&adev->dm.vblank_lock);
if(amdgpu_dm_irq_init(adev)) {
DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
@@ -1637,12 +1673,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
}
}
- if (amdgpu_dm_initialize_drm_device(adev)) {
- DRM_ERROR(
- "amdgpu: failed to initialize sw for display support.\n");
- goto error;
- }
-
/* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
* It is expected that DMUB will resend any pending notifications at this point, for
* example HPD from DPIA.
@@ -1650,6 +1680,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (dc_is_dmub_outbox_supported(adev->dm.dc))
dc_enable_dmub_outbox(adev->dm.dc);
+ if (amdgpu_dm_initialize_drm_device(adev)) {
+ DRM_ERROR(
+ "amdgpu: failed to initialize sw for display support.\n");
+ goto error;
+ }
+
/* create fake encoders for MST */
dm_dp_create_fake_mst_encoders(adev);
@@ -1762,6 +1798,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
mutex_destroy(&adev->dm.audio_lock);
mutex_destroy(&adev->dm.dc_lock);
+ mutex_destroy(&adev->dm.dpia_aux_lock);
return;
}
@@ -2813,7 +2850,6 @@ const struct amdgpu_ip_block_version dm_ip_block =
static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
.fb_create = amdgpu_display_user_framebuffer_create,
.get_format_info = amd_get_format_info,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = amdgpu_dm_atomic_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -3819,8 +3855,6 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
/* indicates support for immediate flip */
adev_to_drm(adev)->mode_config.async_page_flip = true;
- adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
-
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
@@ -4595,6 +4629,7 @@ static int dm_early_init(void *handle)
adev_to_drm(adev)->dev,
&dev_attr_s3_debug);
#endif
+ adev->dc_enabled = true;
return 0;
}
@@ -4834,6 +4869,35 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
return 0;
}
+static inline void fill_dc_dirty_rect(struct drm_plane *plane,
+ struct rect *dirty_rect, int32_t x,
+ int32_t y, int32_t width, int32_t height,
+ int *i, bool ffu)
+{
+ if (*i > DC_MAX_DIRTY_RECTS)
+ return;
+
+ if (*i == DC_MAX_DIRTY_RECTS)
+ goto out;
+
+ dirty_rect->x = x;
+ dirty_rect->y = y;
+ dirty_rect->width = width;
+ dirty_rect->height = height;
+
+ if (ffu)
+ drm_dbg(plane->dev,
+ "[PLANE:%d] PSR FFU dirty rect size (%d, %d)\n",
+ plane->base.id, width, height);
+ else
+ drm_dbg(plane->dev,
+ "[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)",
+ plane->base.id, x, y, width, height);
+
+out:
+ (*i)++;
+}
+
/**
* fill_dc_dirty_rects() - Fill DC dirty regions for PSR selective updates
*
@@ -4854,10 +4918,6 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
* addition, certain use cases - such as cursor and multi-plane overlay (MPO) -
* implicitly provide damage clips without any client support via the plane
* bounds.
- *
- * Today, amdgpu_dm only supports the MPO and cursor usecase.
- *
- * TODO: Also enable for FB_DAMAGE_CLIPS
*/
static void fill_dc_dirty_rects(struct drm_plane *plane,
struct drm_plane_state *old_plane_state,
@@ -4868,12 +4928,11 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
struct rect *dirty_rects = flip_addrs->dirty_rects;
uint32_t num_clips;
+ struct drm_mode_rect *clips;
bool bb_changed;
bool fb_changed;
uint32_t i = 0;
- flip_addrs->dirty_rect_count = 0;
-
/*
* Cursor plane has it's own dirty rect update interface. See
* dcn10_dmub_update_cursor_data and dmub_cmd_update_cursor_info_data
@@ -4881,20 +4940,20 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
if (plane->type == DRM_PLANE_TYPE_CURSOR)
return;
- /*
- * Today, we only consider MPO use-case for PSR SU. If MPO not
- * requested, and there is a plane update, do FFU.
- */
+ num_clips = drm_plane_get_damage_clips_count(new_plane_state);
+ clips = drm_plane_get_damage_clips(new_plane_state);
+
if (!dm_crtc_state->mpo_requested) {
- dirty_rects[0].x = 0;
- dirty_rects[0].y = 0;
- dirty_rects[0].width = dm_crtc_state->base.mode.crtc_hdisplay;
- dirty_rects[0].height = dm_crtc_state->base.mode.crtc_vdisplay;
- flip_addrs->dirty_rect_count = 1;
- DRM_DEBUG_DRIVER("[PLANE:%d] PSR FFU dirty rect size (%d, %d)\n",
- new_plane_state->plane->base.id,
- dm_crtc_state->base.mode.crtc_hdisplay,
- dm_crtc_state->base.mode.crtc_vdisplay);
+ if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS)
+ goto ffu;
+
+ for (; flip_addrs->dirty_rect_count < num_clips; clips++)
+ fill_dc_dirty_rect(new_plane_state->plane,
+ &dirty_rects[i], clips->x1,
+ clips->y1, clips->x2 - clips->x1,
+ clips->y2 - clips->y1,
+ &flip_addrs->dirty_rect_count,
+ false);
return;
}
@@ -4905,7 +4964,6 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
* If plane is moved or resized, also add old bounding box to dirty
* rects.
*/
- num_clips = drm_plane_get_damage_clips_count(new_plane_state);
fb_changed = old_plane_state->fb->base.id !=
new_plane_state->fb->base.id;
bb_changed = (old_plane_state->crtc_x != new_plane_state->crtc_x ||
@@ -4913,36 +4971,51 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
old_plane_state->crtc_w != new_plane_state->crtc_w ||
old_plane_state->crtc_h != new_plane_state->crtc_h);
- DRM_DEBUG_DRIVER("[PLANE:%d] PSR bb_changed:%d fb_changed:%d num_clips:%d\n",
- new_plane_state->plane->base.id,
- bb_changed, fb_changed, num_clips);
+ drm_dbg(plane->dev,
+ "[PLANE:%d] PSR bb_changed:%d fb_changed:%d num_clips:%d\n",
+ new_plane_state->plane->base.id,
+ bb_changed, fb_changed, num_clips);
- if (num_clips || fb_changed || bb_changed) {
- dirty_rects[i].x = new_plane_state->crtc_x;
- dirty_rects[i].y = new_plane_state->crtc_y;
- dirty_rects[i].width = new_plane_state->crtc_w;
- dirty_rects[i].height = new_plane_state->crtc_h;
- DRM_DEBUG_DRIVER("[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)\n",
- new_plane_state->plane->base.id,
- dirty_rects[i].x, dirty_rects[i].y,
- dirty_rects[i].width, dirty_rects[i].height);
- i += 1;
- }
-
- /* Add old plane bounding-box if plane is moved or resized */
if (bb_changed) {
- dirty_rects[i].x = old_plane_state->crtc_x;
- dirty_rects[i].y = old_plane_state->crtc_y;
- dirty_rects[i].width = old_plane_state->crtc_w;
- dirty_rects[i].height = old_plane_state->crtc_h;
- DRM_DEBUG_DRIVER("[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)\n",
- old_plane_state->plane->base.id,
- dirty_rects[i].x, dirty_rects[i].y,
- dirty_rects[i].width, dirty_rects[i].height);
- i += 1;
- }
+ fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
+ new_plane_state->crtc_x,
+ new_plane_state->crtc_y,
+ new_plane_state->crtc_w,
+ new_plane_state->crtc_h, &i, false);
+
+ /* Add old plane bounding-box if plane is moved or resized */
+ fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
+ old_plane_state->crtc_x,
+ old_plane_state->crtc_y,
+ old_plane_state->crtc_w,
+ old_plane_state->crtc_h, &i, false);
+ }
+
+ if (num_clips) {
+ for (; i < num_clips; clips++)
+ fill_dc_dirty_rect(new_plane_state->plane,
+ &dirty_rects[i], clips->x1,
+ clips->y1, clips->x2 - clips->x1,
+ clips->y2 - clips->y1, &i, false);
+ } else if (fb_changed && !bb_changed) {
+ fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
+ new_plane_state->crtc_x,
+ new_plane_state->crtc_y,
+ new_plane_state->crtc_w,
+ new_plane_state->crtc_h, &i, false);
+ }
+
+ if (i > DC_MAX_DIRTY_RECTS)
+ goto ffu;
flip_addrs->dirty_rect_count = i;
+ return;
+
+ffu:
+ fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[0], 0, 0,
+ dm_crtc_state->base.mode.crtc_hdisplay,
+ dm_crtc_state->base.mode.crtc_vdisplay,
+ &flip_addrs->dirty_rect_count, true);
}
static void update_stream_scaling_settings(const struct drm_display_mode *mode,
@@ -5607,16 +5680,14 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
{
struct drm_connector *drm_connector = &aconnector->base;
uint32_t link_bandwidth_kbps;
- uint32_t max_dsc_target_bpp_limit_override = 0;
struct dc *dc = sink->ctx->dc;
uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps;
uint32_t dsc_max_supported_bw_in_kbps;
+ uint32_t max_dsc_target_bpp_limit_override =
+ drm_connector->display_info.max_dsc_bpp;
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
dc_link_get_link_cap(aconnector->dc_link));
- if (stream->link && stream->link->local_sink)
- max_dsc_target_bpp_limit_override =
- stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
/* Set DSC policy according to dsc_clock_en */
dc_dsc_policy_set_enable_dsc_when_not_needed(
@@ -5689,7 +5760,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct drm_connector_state *con_state =
dm_state ? &dm_state->base : NULL;
struct dc_stream_state *stream = NULL;
- struct drm_display_mode mode = *drm_mode;
+ struct drm_display_mode mode;
struct drm_display_mode saved_mode;
struct drm_display_mode *freesync_mode = NULL;
bool native_mode_found = false;
@@ -5697,12 +5768,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false;
int mode_refresh;
int preferred_refresh = 0;
+ enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dsc_dec_dpcd_caps dsc_caps;
#endif
struct dc_sink *sink = NULL;
+ drm_mode_init(&mode, drm_mode);
memset(&saved_mode, 0, sizeof(saved_mode));
if (aconnector == NULL) {
@@ -5820,7 +5893,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED)
stream->use_vsc_sdp_for_colorimetry = true;
}
- mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space);
+ if (stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22)
+ tf = TRANSFER_FUNC_GAMMA_22;
+ mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf);
aconnector->psr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY;
}
@@ -6113,7 +6188,6 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
aconnector->base.name);
aconnector->base.force = DRM_FORCE_OFF;
- aconnector->base.override_edid = false;
return;
}
@@ -6148,11 +6222,73 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
}
-
- aconnector->base.override_edid = true;
create_eml_sink(aconnector);
}
+static enum dc_status dm_validate_stream_and_context(struct dc *dc,
+ struct dc_stream_state *stream)
+{
+ enum dc_status dc_result = DC_ERROR_UNEXPECTED;
+ struct dc_plane_state *dc_plane_state = NULL;
+ struct dc_state *dc_state = NULL;
+
+ if (!stream)
+ goto cleanup;
+
+ dc_plane_state = dc_create_plane_state(dc);
+ if (!dc_plane_state)
+ goto cleanup;
+
+ dc_state = dc_create_state(dc);
+ if (!dc_state)
+ goto cleanup;
+
+ /* populate stream to plane */
+ dc_plane_state->src_rect.height = stream->src.height;
+ dc_plane_state->src_rect.width = stream->src.width;
+ dc_plane_state->dst_rect.height = stream->src.height;
+ dc_plane_state->dst_rect.width = stream->src.width;
+ dc_plane_state->clip_rect.height = stream->src.height;
+ dc_plane_state->clip_rect.width = stream->src.width;
+ dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256;
+ dc_plane_state->plane_size.surface_size.height = stream->src.height;
+ dc_plane_state->plane_size.surface_size.width = stream->src.width;
+ dc_plane_state->plane_size.chroma_size.height = stream->src.height;
+ dc_plane_state->plane_size.chroma_size.width = stream->src.width;
+ dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
+ dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
+ dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
+ dc_plane_state->rotation = ROTATION_ANGLE_0;
+ dc_plane_state->is_tiling_rotated = false;
+ dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL;
+
+ dc_result = dc_validate_stream(dc, stream);
+ if (dc_result == DC_OK)
+ dc_result = dc_validate_plane(dc, dc_plane_state);
+
+ if (dc_result == DC_OK)
+ dc_result = dc_add_stream_to_ctx(dc, dc_state, stream);
+
+ if (dc_result == DC_OK && !dc_add_plane_to_context(
+ dc,
+ stream,
+ dc_plane_state,
+ dc_state))
+ dc_result = DC_FAIL_ATTACH_SURFACES;
+
+ if (dc_result == DC_OK)
+ dc_result = dc_validate_global_state(dc, dc_state, true);
+
+cleanup:
+ if (dc_state)
+ dc_release_state(dc_state);
+
+ if (dc_plane_state)
+ dc_plane_state_release(dc_plane_state);
+
+ return dc_result;
+}
+
struct dc_stream_state *
create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct drm_display_mode *drm_mode,
@@ -6179,6 +6315,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
+ if (dc_result == DC_OK)
+ dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
+
if (dc_result != DC_OK) {
DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d (%s)\n",
drm_mode->hdisplay,
@@ -6467,7 +6606,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
struct drm_connector_state *new_con_state;
struct amdgpu_dm_connector *aconnector;
struct dm_connector_state *dm_conn_state;
- int i, j;
+ int i, j, ret;
int vcpi, pbn_div, pbn, slot_num = 0;
for_each_new_connector_in_state(state, connector, new_con_state, i) {
@@ -6514,8 +6653,11 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
dm_conn_state->pbn = pbn;
dm_conn_state->vcpi_slots = slot_num;
- drm_dp_mst_atomic_enable_dsc(state, aconnector->port, dm_conn_state->pbn,
- false);
+ ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->port,
+ dm_conn_state->pbn, false);
+ if (ret < 0)
+ return ret;
+
continue;
}
@@ -7622,9 +7764,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
bundle->surface_updates[planes_count].plane_info =
&bundle->plane_infos[planes_count];
- fill_dc_dirty_rects(plane, old_plane_state, new_plane_state,
- new_crtc_state,
- &bundle->flip_addrs[planes_count]);
+ if (acrtc_state->stream->link->psr_settings.psr_feature_enabled)
+ fill_dc_dirty_rects(plane, old_plane_state,
+ new_plane_state, new_crtc_state,
+ &bundle->flip_addrs[planes_count]);
/*
* Only allow immediate flips for fast updates that don't
@@ -7840,6 +7983,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
*/
if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 &&
acrtc_attach->dm_irq_params.allow_psr_entry &&
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
+#endif
!acrtc_state->stream->link->psr_settings.psr_allow_active)
amdgpu_dm_psr_enable(acrtc_state->stream);
} else {
@@ -8301,8 +8447,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
if (amdgpu_dm_crc_window_is_activated(crtc)) {
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- acrtc->dm_irq_params.crc_window.update_win = true;
- acrtc->dm_irq_params.crc_window.skip_frame_cnt = 2;
+ acrtc->dm_irq_params.window_param.update_win = true;
+ acrtc->dm_irq_params.window_param.skip_frame_cnt = 2;
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
crc_rd_wrk->crtc = crtc;
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
@@ -9528,10 +9674,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dc_resource_is_dsc_encoding_supported(dc)) {
- if (!pre_validate_dsc(state, &dm_state, vars)) {
- ret = -EINVAL;
+ ret = pre_validate_dsc(state, &dm_state, vars);
+ if (ret != 0)
goto fail;
- }
}
#endif
@@ -9626,9 +9771,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
}
#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (!compute_mst_dsc_configs_for_state(state, dm_state->context, vars)) {
+ ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars);
+ if (ret) {
DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n");
- ret = -EINVAL;
goto fail;
}
@@ -10091,79 +10236,92 @@ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address,
return value;
}
-static int amdgpu_dm_set_dmub_async_sync_status(bool is_cmd_aux,
- struct dc_context *ctx,
- uint8_t status_type,
- uint32_t *operation_result)
+int amdgpu_dm_process_dmub_aux_transfer_sync(
+ struct dc_context *ctx,
+ unsigned int link_index,
+ struct aux_payload *payload,
+ enum aux_return_code_type *operation_result)
{
struct amdgpu_device *adev = ctx->driver_context;
- int return_status = -1;
struct dmub_notification *p_notify = adev->dm.dmub_notify;
+ int ret = -1;
- if (is_cmd_aux) {
- if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS) {
- return_status = p_notify->aux_reply.length;
- *operation_result = p_notify->result;
- } else if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT) {
- *operation_result = AUX_RET_ERROR_TIMEOUT;
- } else if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_FAIL) {
- *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
- } else {
- *operation_result = AUX_RET_ERROR_UNKNOWN;
+ mutex_lock(&adev->dm.dpia_aux_lock);
+ if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) {
+ *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
+ goto out;
+ }
+
+ if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
+ DRM_ERROR("wait_for_completion_timeout timeout!");
+ *operation_result = AUX_RET_ERROR_TIMEOUT;
+ goto out;
+ }
+
+ if (p_notify->result != AUX_RET_SUCCESS) {
+ /*
+ * Transient states before tunneling is enabled could
+ * lead to this error. We can ignore this for now.
+ */
+ if (p_notify->result != AUX_RET_ERROR_PROTOCOL_ERROR) {
+ DRM_WARN("DPIA AUX failed on 0x%x(%d), error %d\n",
+ payload->address, payload->length,
+ p_notify->result);
}
- } else {
- if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS) {
- return_status = 0;
- *operation_result = p_notify->sc_status;
- } else {
- *operation_result = SET_CONFIG_UNKNOWN_ERROR;
+ *operation_result = AUX_RET_ERROR_INVALID_REPLY;
+ goto out;
+ }
+
+
+ payload->reply[0] = adev->dm.dmub_notify->aux_reply.command;
+ if (!payload->write && p_notify->aux_reply.length &&
+ (payload->reply[0] == AUX_TRANSACTION_REPLY_AUX_ACK)) {
+
+ if (payload->length != p_notify->aux_reply.length) {
+ DRM_WARN("invalid read length %d from DPIA AUX 0x%x(%d)!\n",
+ p_notify->aux_reply.length,
+ payload->address, payload->length);
+ *operation_result = AUX_RET_ERROR_INVALID_REPLY;
+ goto out;
}
+
+ memcpy(payload->data, p_notify->aux_reply.data,
+ p_notify->aux_reply.length);
}
- return return_status;
+ /* success */
+ ret = p_notify->aux_reply.length;
+ *operation_result = p_notify->result;
+out:
+ mutex_unlock(&adev->dm.dpia_aux_lock);
+ return ret;
}
-int amdgpu_dm_process_dmub_aux_transfer_sync(bool is_cmd_aux, struct dc_context *ctx,
- unsigned int link_index, void *cmd_payload, void *operation_result)
+int amdgpu_dm_process_dmub_set_config_sync(
+ struct dc_context *ctx,
+ unsigned int link_index,
+ struct set_config_cmd_payload *payload,
+ enum set_config_status *operation_result)
{
struct amdgpu_device *adev = ctx->driver_context;
- int ret = 0;
+ bool is_cmd_complete;
+ int ret;
- if (is_cmd_aux) {
- dc_process_dmub_aux_transfer_async(ctx->dc,
- link_index, (struct aux_payload *)cmd_payload);
- } else if (dc_process_dmub_set_config_async(ctx->dc, link_index,
- (struct set_config_cmd_payload *)cmd_payload,
- adev->dm.dmub_notify)) {
- return amdgpu_dm_set_dmub_async_sync_status(is_cmd_aux,
- ctx, DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS,
- (uint32_t *)operation_result);
- }
+ mutex_lock(&adev->dm.dpia_aux_lock);
+ is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc,
+ link_index, payload, adev->dm.dmub_notify);
- ret = wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ);
- if (ret == 0) {
+ if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
+ ret = 0;
+ *operation_result = adev->dm.dmub_notify->sc_status;
+ } else {
DRM_ERROR("wait_for_completion_timeout timeout!");
- return amdgpu_dm_set_dmub_async_sync_status(is_cmd_aux,
- ctx, DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT,
- (uint32_t *)operation_result);
+ ret = -1;
+ *operation_result = SET_CONFIG_UNKNOWN_ERROR;
}
- if (is_cmd_aux) {
- if (adev->dm.dmub_notify->result == AUX_RET_SUCCESS) {
- struct aux_payload *payload = (struct aux_payload *)cmd_payload;
-
- payload->reply[0] = adev->dm.dmub_notify->aux_reply.command;
- if (!payload->write && adev->dm.dmub_notify->aux_reply.length &&
- payload->reply[0] == AUX_TRANSACTION_REPLY_AUX_ACK) {
- memcpy(payload->data, adev->dm.dmub_notify->aux_reply.data,
- adev->dm.dmub_notify->aux_reply.length);
- }
- }
- }
-
- return amdgpu_dm_set_dmub_async_sync_status(is_cmd_aux,
- ctx, DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS,
- (uint32_t *)operation_result);
+ mutex_unlock(&adev->dm.dpia_aux_lock);
+ return ret;
}
/*
@@ -10175,8 +10333,8 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(bool is_cmd_aux, struct dc_context
*/
bool check_seamless_boot_capability(struct amdgpu_device *adev)
{
- switch (adev->asic_type) {
- case CHIP_VANGOGH:
+ switch (adev->ip_versions[DCE_HWIP][0]) {
+ case IP_VERSION(3, 0, 1):
if (!adev->mman.keep_stolen_vga_memory)
return true;
break;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index b5ce15c43bcc..df3c25e32c65 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -51,12 +51,6 @@
#define AMDGPU_DMUB_NOTIFICATION_MAX 5
/*
- * DMUB Async to Sync Mechanism Status
- */
-#define DMUB_ASYNC_TO_SYNC_ACCESS_FAIL 1
-#define DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT 2
-#define DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS 3
-/*
#include "include/amdgpu_dal_power_if.h"
#include "amdgpu_dm_irq.h"
*/
@@ -65,7 +59,9 @@
#include "signal_types.h"
#include "amdgpu_dm_crc.h"
struct aux_payload;
+struct set_config_cmd_payload;
enum aux_return_code_type;
+enum set_config_status;
/* Forward declarations */
struct amdgpu_device;
@@ -366,13 +362,6 @@ struct amdgpu_display_manager {
struct mutex audio_lock;
/**
- * @vblank_lock:
- *
- * Guards access to deferred vblank work state.
- */
- spinlock_t vblank_lock;
-
- /**
* @audio_component:
*
* Used to notify ELD changes to sound driver.
@@ -555,6 +544,13 @@ struct amdgpu_display_manager {
* occurred on certain intel platform
*/
bool aux_hpd_discon_quirk;
+
+ /**
+ * @dpia_aux_lock:
+ *
+ * Guards access to DPIA AUX
+ */
+ struct mutex dpia_aux_lock;
};
enum dsc_clock_force_state {
@@ -798,9 +794,11 @@ void amdgpu_dm_update_connector_after_detect(
extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;
-int amdgpu_dm_process_dmub_aux_transfer_sync(bool is_cmd_aux,
- struct dc_context *ctx, unsigned int link_index,
- void *payload, void *operation_result);
+int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int link_index,
+ struct aux_payload *payload, enum aux_return_code_type *operation_result);
+
+int amdgpu_dm_process_dmub_set_config_sync(struct dc_context *ctx, unsigned int link_index,
+ struct set_config_cmd_payload *payload, enum set_config_status *operation_result);
bool check_seamless_boot_capability(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 8a441a22c46e..66df2394d7e4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -89,13 +89,13 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- acrtc->dm_irq_params.crc_window.x_start = 0;
- acrtc->dm_irq_params.crc_window.y_start = 0;
- acrtc->dm_irq_params.crc_window.x_end = 0;
- acrtc->dm_irq_params.crc_window.y_end = 0;
- acrtc->dm_irq_params.crc_window.activated = false;
- acrtc->dm_irq_params.crc_window.update_win = false;
- acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
+ acrtc->dm_irq_params.window_param.x_start = 0;
+ acrtc->dm_irq_params.window_param.y_start = 0;
+ acrtc->dm_irq_params.window_param.x_end = 0;
+ acrtc->dm_irq_params.window_param.y_end = 0;
+ acrtc->dm_irq_params.window_param.activated = false;
+ acrtc->dm_irq_params.window_param.update_win = false;
+ acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
spin_unlock_irq(&drm_dev->event_lock);
}
@@ -123,6 +123,8 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
phy_id = crc_rd_wrk->phy_inst;
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
+ mutex_lock(&psp->securedisplay_context.mutex);
+
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id =
@@ -133,6 +135,24 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
}
}
+
+ mutex_unlock(&psp->securedisplay_context.mutex);
+}
+
+static void
+amdgpu_dm_forward_crc_window(struct work_struct *work)
+{
+ struct crc_fw_work *crc_fw_wrk;
+ struct amdgpu_display_manager *dm;
+
+ crc_fw_wrk = container_of(work, struct crc_fw_work, forward_roi_work);
+ dm = crc_fw_wrk->dm;
+
+ mutex_lock(&dm->dc_lock);
+ dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->rect, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd);
+ mutex_unlock(&dm->dc_lock);
+
+ kfree(crc_fw_wrk);
}
bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc)
@@ -142,7 +162,7 @@ bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc)
bool ret = false;
spin_lock_irq(&drm_dev->event_lock);
- ret = acrtc->dm_irq_params.crc_window.activated;
+ ret = acrtc->dm_irq_params.window_param.activated;
spin_unlock_irq(&drm_dev->event_lock);
return ret;
@@ -187,9 +207,11 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
if (adev->dm.crc_rd_wrk) {
flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
spin_lock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
+
if (adev->dm.crc_rd_wrk->crtc == crtc) {
- dc_stream_stop_dmcu_crc_win_update(stream_state->ctx->dc,
- dm_crtc_state->stream);
+ /* stop ROI update on this crtc */
+ dc_stream_forward_crc_window(stream_state->ctx->dc,
+ NULL, stream_state, true);
adev->dm.crc_rd_wrk->crtc = NULL;
}
spin_unlock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
@@ -439,14 +461,9 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
enum amdgpu_dm_pipe_crc_source cur_crc_src;
struct amdgpu_crtc *acrtc = NULL;
struct amdgpu_device *adev = NULL;
- struct crc_rd_work *crc_rd_wrk = NULL;
- struct crc_params *crc_window = NULL, tmp_window;
+ struct crc_rd_work *crc_rd_wrk;
+ struct crc_fw_work *crc_fw_wrk;
unsigned long flags1, flags2;
- struct crtc_position position;
- uint32_t v_blank;
- uint32_t v_back_porch;
- uint32_t crc_window_latch_up_line;
- struct dc_crtc_timing *timing_out;
if (crtc == NULL)
return;
@@ -458,74 +475,54 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
spin_lock_irqsave(&drm_dev->event_lock, flags1);
stream_state = acrtc->dm_irq_params.stream;
cur_crc_src = acrtc->dm_irq_params.crc_src;
- timing_out = &stream_state->timing;
/* Early return if CRC capture is not enabled. */
if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
goto cleanup;
- if (dm_is_crc_source_crtc(cur_crc_src)) {
- if (acrtc->dm_irq_params.crc_window.activated) {
- if (acrtc->dm_irq_params.crc_window.update_win) {
- if (acrtc->dm_irq_params.crc_window.skip_frame_cnt) {
- acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1;
- goto cleanup;
- }
- crc_window = &tmp_window;
-
- tmp_window.windowa_x_start =
- acrtc->dm_irq_params.crc_window.x_start;
- tmp_window.windowa_y_start =
- acrtc->dm_irq_params.crc_window.y_start;
- tmp_window.windowa_x_end =
- acrtc->dm_irq_params.crc_window.x_end;
- tmp_window.windowa_y_end =
- acrtc->dm_irq_params.crc_window.y_end;
- tmp_window.windowb_x_start =
- acrtc->dm_irq_params.crc_window.x_start;
- tmp_window.windowb_y_start =
- acrtc->dm_irq_params.crc_window.y_start;
- tmp_window.windowb_x_end =
- acrtc->dm_irq_params.crc_window.x_end;
- tmp_window.windowb_y_end =
- acrtc->dm_irq_params.crc_window.y_end;
-
- dc_stream_forward_dmcu_crc_window(stream_state->ctx->dc,
- stream_state, crc_window);
-
- acrtc->dm_irq_params.crc_window.update_win = false;
-
- dc_stream_get_crtc_position(stream_state->ctx->dc, &stream_state, 1,
- &position.vertical_count,
- &position.nominal_vcount);
-
- v_blank = timing_out->v_total - timing_out->v_border_top -
- timing_out->v_addressable - timing_out->v_border_bottom;
-
- v_back_porch = v_blank - timing_out->v_front_porch -
- timing_out->v_sync_width;
-
- crc_window_latch_up_line = v_back_porch + timing_out->v_sync_width;
-
- /* take 3 lines margin*/
- if ((position.vertical_count + 3) >= crc_window_latch_up_line)
- acrtc->dm_irq_params.crc_window.skip_frame_cnt = 1;
- else
- acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
- } else {
- if (acrtc->dm_irq_params.crc_window.skip_frame_cnt == 0) {
- if (adev->dm.crc_rd_wrk) {
- crc_rd_wrk = adev->dm.crc_rd_wrk;
- spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2);
- crc_rd_wrk->phy_inst =
- stream_state->link->link_enc_hw_inst;
- spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2);
- schedule_work(&crc_rd_wrk->notify_ta_work);
- }
- } else {
- acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1;
- }
- }
+ if (!dm_is_crc_source_crtc(cur_crc_src))
+ goto cleanup;
+
+ if (!acrtc->dm_irq_params.window_param.activated)
+ goto cleanup;
+
+ if (acrtc->dm_irq_params.window_param.update_win) {
+ if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
+ acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
+ goto cleanup;
+ }
+
+ /* prepare work for dmub to update ROI */
+ crc_fw_wrk = kzalloc(sizeof(*crc_fw_wrk), GFP_ATOMIC);
+ if (!crc_fw_wrk)
+ goto cleanup;
+
+ INIT_WORK(&crc_fw_wrk->forward_roi_work, amdgpu_dm_forward_crc_window);
+ crc_fw_wrk->dm = &adev->dm;
+ crc_fw_wrk->stream = stream_state;
+ crc_fw_wrk->rect.x = acrtc->dm_irq_params.window_param.x_start;
+ crc_fw_wrk->rect.y = acrtc->dm_irq_params.window_param.y_start;
+ crc_fw_wrk->rect.width = acrtc->dm_irq_params.window_param.x_end -
+ acrtc->dm_irq_params.window_param.x_start;
+ crc_fw_wrk->rect.height = acrtc->dm_irq_params.window_param.y_end -
+ acrtc->dm_irq_params.window_param.y_start;
+ schedule_work(&crc_fw_wrk->forward_roi_work);
+
+ acrtc->dm_irq_params.window_param.update_win = false;
+ acrtc->dm_irq_params.window_param.skip_frame_cnt = 1;
+
+ } else {
+ if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
+ acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
+ goto cleanup;
+ }
+
+ if (adev->dm.crc_rd_wrk) {
+ crc_rd_wrk = adev->dm.crc_rd_wrk;
+ spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2);
+ crc_rd_wrk->phy_inst = stream_state->link->link_enc_hw_inst;
+ spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2);
+ schedule_work(&crc_rd_wrk->notify_ta_work);
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
index f07850db60a6..71bce608d751 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
@@ -40,7 +40,7 @@ enum amdgpu_dm_pipe_crc_source {
};
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
-struct crc_window_parm {
+struct crc_window_param {
uint16_t x_start;
uint16_t y_start;
uint16_t x_end;
@@ -53,6 +53,7 @@ struct crc_window_parm {
int skip_frame_cnt;
};
+/* read_work for driver to call PSP to read */
struct crc_rd_work {
struct work_struct notify_ta_work;
/* To protect crc_rd_work carried fields*/
@@ -60,6 +61,15 @@ struct crc_rd_work {
struct drm_crtc *crtc;
uint8_t phy_inst;
};
+
+/* forward_work for driver to forward ROI to dmu */
+struct crc_fw_work {
+ struct work_struct forward_roi_work;
+ struct amdgpu_display_manager *dm;
+ struct dc_stream_state *stream;
+ struct rect rect;
+ bool is_stop_cmd;
+};
#endif
static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source source)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 594fe8a4d02b..22125daf9dcf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -127,6 +127,9 @@ static void vblank_control_worker(struct work_struct *work)
amdgpu_dm_psr_disable(vblank_work->stream);
} else if (vblank_work->stream->link->psr_settings.psr_feature_enabled &&
!vblank_work->stream->link->psr_settings.psr_allow_active &&
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) &&
+#endif
vblank_work->acrtc->dm_irq_params.allow_psr_entry) {
amdgpu_dm_psr_enable(vblank_work->stream);
}
@@ -412,7 +415,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
{
struct amdgpu_crtc *acrtc = NULL;
struct drm_plane *cursor_plane;
-
+ bool is_dcn;
int res = -ENOMEM;
cursor_plane = kzalloc(sizeof(*cursor_plane), GFP_KERNEL);
@@ -450,8 +453,14 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
acrtc->otg_inst = -1;
dm->adev->mode_info.crtcs[crtc_index] = acrtc;
- drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
+
+ /* Don't enable DRM CRTC degamma property for DCE since it doesn't
+ * support programmable degamma anywhere.
+ */
+ is_dcn = dm->adev->dm.dc->caps.color.dpp.dcn_arch;
+ drm_crtc_enable_color_mgmt(&acrtc->base, is_dcn ? MAX_COLOR_LUT_ENTRIES : 0,
true, MAX_COLOR_LUT_ENTRIES);
+
drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
return 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index ee242d9d8b06..461037a3dd75 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -38,6 +38,10 @@
#include "link_hwss.h"
#include "dc/dc_dmub_srv.h"
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+#include "amdgpu_dm_psr.h"
+#endif
+
struct dmub_debugfs_trace_header {
uint32_t entry_count;
uint32_t reserved[3];
@@ -299,6 +303,8 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
case LINK_RATE_HIGH2:
case LINK_RATE_HIGH3:
case LINK_RATE_UHBR10:
+ case LINK_RATE_UHBR13_5:
+ case LINK_RATE_UHBR20:
break;
default:
valid_input = false;
@@ -2633,6 +2639,25 @@ static int dp_mst_progress_status_show(struct seq_file *m, void *unused)
return 0;
}
+/*
+ * Reports whether the connected display is a USB4 DPIA tunneled display
+ * Example usage: cat /sys/kernel/debug/dri/0/DP-8/is_dpia_link
+ */
+static int is_dpia_link_show(struct seq_file *m, void *data)
+{
+ struct drm_connector *connector = m->private;
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+ struct dc_link *link = aconnector->dc_link;
+
+ if (connector->status != connector_status_connected)
+ return -ENODEV;
+
+ seq_printf(m, "%s\n", (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ? "yes" :
+ (link->ep_type == DISPLAY_ENDPOINT_PHY) ? "no" : "unknown");
+
+ return 0;
+}
+
DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support);
DEFINE_SHOW_ATTRIBUTE(dmub_fw_state);
DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer);
@@ -2644,6 +2669,7 @@ DEFINE_SHOW_ATTRIBUTE(internal_display);
DEFINE_SHOW_ATTRIBUTE(psr_capability);
DEFINE_SHOW_ATTRIBUTE(dp_is_mst_connector);
DEFINE_SHOW_ATTRIBUTE(dp_mst_progress_status);
+DEFINE_SHOW_ATTRIBUTE(is_dpia_link);
static const struct file_operations dp_dsc_clock_en_debugfs_fops = {
.owner = THIS_MODULE,
@@ -2788,7 +2814,8 @@ static const struct {
{"max_bpc", &dp_max_bpc_debugfs_fops},
{"dsc_disable_passthrough", &dp_dsc_disable_passthrough_debugfs_fops},
{"is_mst_connector", &dp_is_mst_connector_fops},
- {"mst_progress_status", &dp_mst_progress_status_fops}
+ {"mst_progress_status", &dp_mst_progress_status_fops},
+ {"is_dpia_link", &is_dpia_link_fops}
};
#ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -3079,8 +3106,8 @@ static int crc_win_x_start_set(void *data, u64 val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- acrtc->dm_irq_params.crc_window.x_start = (uint16_t) val;
- acrtc->dm_irq_params.crc_window.update_win = false;
+ acrtc->dm_irq_params.window_param.x_start = (uint16_t) val;
+ acrtc->dm_irq_params.window_param.update_win = false;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3096,7 +3123,7 @@ static int crc_win_x_start_get(void *data, u64 *val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- *val = acrtc->dm_irq_params.crc_window.x_start;
+ *val = acrtc->dm_irq_params.window_param.x_start;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3116,8 +3143,8 @@ static int crc_win_y_start_set(void *data, u64 val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- acrtc->dm_irq_params.crc_window.y_start = (uint16_t) val;
- acrtc->dm_irq_params.crc_window.update_win = false;
+ acrtc->dm_irq_params.window_param.y_start = (uint16_t) val;
+ acrtc->dm_irq_params.window_param.update_win = false;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3133,7 +3160,7 @@ static int crc_win_y_start_get(void *data, u64 *val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- *val = acrtc->dm_irq_params.crc_window.y_start;
+ *val = acrtc->dm_irq_params.window_param.y_start;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3152,8 +3179,8 @@ static int crc_win_x_end_set(void *data, u64 val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- acrtc->dm_irq_params.crc_window.x_end = (uint16_t) val;
- acrtc->dm_irq_params.crc_window.update_win = false;
+ acrtc->dm_irq_params.window_param.x_end = (uint16_t) val;
+ acrtc->dm_irq_params.window_param.update_win = false;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3169,7 +3196,7 @@ static int crc_win_x_end_get(void *data, u64 *val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- *val = acrtc->dm_irq_params.crc_window.x_end;
+ *val = acrtc->dm_irq_params.window_param.x_end;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3188,8 +3215,8 @@ static int crc_win_y_end_set(void *data, u64 val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- acrtc->dm_irq_params.crc_window.y_end = (uint16_t) val;
- acrtc->dm_irq_params.crc_window.update_win = false;
+ acrtc->dm_irq_params.window_param.y_end = (uint16_t) val;
+ acrtc->dm_irq_params.window_param.update_win = false;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3205,7 +3232,7 @@ static int crc_win_y_end_get(void *data, u64 *val)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&drm_dev->event_lock);
- *val = acrtc->dm_irq_params.crc_window.y_end;
+ *val = acrtc->dm_irq_params.window_param.y_end;
spin_unlock_irq(&drm_dev->event_lock);
return 0;
@@ -3228,31 +3255,38 @@ static int crc_win_update_set(void *data, u64 val)
return 0;
if (val) {
+ new_acrtc = to_amdgpu_crtc(new_crtc);
+ mutex_lock(&adev->dm.dc_lock);
+ /* PSR may write to OTG CRC window control register,
+ * so close it before starting secure_display.
+ */
+ amdgpu_dm_psr_disable(new_acrtc->dm_irq_params.stream);
+
spin_lock_irq(&adev_to_drm(adev)->event_lock);
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
if (crc_rd_wrk->crtc) {
old_crtc = crc_rd_wrk->crtc;
old_acrtc = to_amdgpu_crtc(old_crtc);
}
- new_acrtc = to_amdgpu_crtc(new_crtc);
if (old_crtc && old_crtc != new_crtc) {
- old_acrtc->dm_irq_params.crc_window.activated = false;
- old_acrtc->dm_irq_params.crc_window.update_win = false;
- old_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
+ old_acrtc->dm_irq_params.window_param.activated = false;
+ old_acrtc->dm_irq_params.window_param.update_win = false;
+ old_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
- new_acrtc->dm_irq_params.crc_window.activated = true;
- new_acrtc->dm_irq_params.crc_window.update_win = true;
- new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
+ new_acrtc->dm_irq_params.window_param.activated = true;
+ new_acrtc->dm_irq_params.window_param.update_win = true;
+ new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
crc_rd_wrk->crtc = new_crtc;
} else {
- new_acrtc->dm_irq_params.crc_window.activated = true;
- new_acrtc->dm_irq_params.crc_window.update_win = true;
- new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
+ new_acrtc->dm_irq_params.window_param.activated = true;
+ new_acrtc->dm_irq_params.window_param.update_win = true;
+ new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
crc_rd_wrk->crtc = new_crtc;
}
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
+ mutex_unlock(&adev->dm.dc_lock);
}
return 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 6202e31c7e3a..a7fd98f57f94 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -495,7 +495,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
link->dp.mst_enabled = config->mst_enabled;
link->dp.usb4_enabled = config->usb4_enabled;
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
- link->adjust.auth_delay = 3;
+ link->adjust.auth_delay = 0;
link->adjust.hdcp1.disable = 0;
conn_state = aconnector->base.state;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index f0b01c8dc4a6..6994c9a1ed85 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -42,39 +42,6 @@
#include "dm_helpers.h"
#include "ddc_service_types.h"
-struct monitor_patch_info {
- unsigned int manufacturer_id;
- unsigned int product_id;
- void (*patch_func)(struct dc_edid_caps *edid_caps, unsigned int param);
- unsigned int patch_param;
-};
-static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param);
-
-static const struct monitor_patch_info monitor_patch_table[] = {
-{0x6D1E, 0x5BBF, set_max_dsc_bpp_limit, 15},
-{0x6D1E, 0x5B9A, set_max_dsc_bpp_limit, 15},
-};
-
-static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param)
-{
- if (edid_caps)
- edid_caps->panel_patch.max_dsc_target_bpp_limit = param;
-}
-
-static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps)
-{
- int i, ret = 0;
-
- for (i = 0; i < ARRAY_SIZE(monitor_patch_table); i++)
- if ((edid_caps->manufacturer_id == monitor_patch_table[i].manufacturer_id)
- && (edid_caps->product_id == monitor_patch_table[i].product_id)) {
- monitor_patch_table[i].patch_func(edid_caps, monitor_patch_table[i].patch_param);
- ret++;
- }
-
- return ret;
-}
-
/* dm_helpers_parse_edid_caps
*
* Parse edid caps
@@ -149,8 +116,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
kfree(sads);
kfree(sadb);
- amdgpu_dm_patch_edid_caps(edid_caps);
-
return result;
}
@@ -852,9 +817,8 @@ int dm_helper_dmub_aux_transfer_sync(
struct aux_payload *payload,
enum aux_return_code_type *operation_result)
{
- return amdgpu_dm_process_dmub_aux_transfer_sync(true, ctx,
- link->link_index, (void *)payload,
- (void *)operation_result);
+ return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload,
+ operation_result);
}
int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
@@ -862,9 +826,8 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
struct set_config_cmd_payload *payload,
enum set_config_status *operation_result)
{
- return amdgpu_dm_process_dmub_aux_transfer_sync(false, ctx,
- link->link_index, (void *)payload,
- (void *)operation_result);
+ return amdgpu_dm_process_dmub_set_config_sync(ctx, link->link_index, payload,
+ operation_result);
}
void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
@@ -1006,3 +969,11 @@ void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable)
{
/* TODO: add periodic detection implementation */
}
+
+void dm_helpers_dp_mst_update_branch_bandwidth(
+ struct dc_context *ctx,
+ struct dc_link *link)
+{
+ // TODO
+}
+
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h
index 79b5f9999fec..5c9303241aeb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h
@@ -39,7 +39,7 @@ struct dm_irq_params {
#ifdef CONFIG_DEBUG_FS
enum amdgpu_dm_pipe_crc_source crc_src;
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
- struct crc_window_parm crc_window;
+ struct crc_window_param window_param;
#endif
#endif
};
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 6ff96b4bdda5..1edf7385f8d8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -642,15 +642,18 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p
int count,
int k)
{
+ struct drm_connector *drm_connector;
int i;
for (i = 0; i < count; i++) {
+ drm_connector = &params[i].aconnector->base;
+
memset(&params[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg));
if (vars[i + k].dsc_enabled && dc_dsc_compute_config(
params[i].sink->ctx->dc->res_pool->dscs[0],
&params[i].sink->dsc_caps.dsc_dec_caps,
params[i].sink->ctx->dc->debug.dsc_min_slice_height_override,
- params[i].sink->edid_caps.panel_patch.max_dsc_target_bpp_limit,
+ drm_connector->display_info.max_dsc_bpp,
0,
params[i].timing,
&params[i].timing->dsc_cfg)) {
@@ -692,24 +695,28 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn)
struct dc_dsc_config dsc_config;
u64 kbps;
+ struct drm_connector *drm_connector = &param.aconnector->base;
+ uint32_t max_dsc_target_bpp_limit_override =
+ drm_connector->display_info.max_dsc_bpp;
+
kbps = div_u64((u64)pbn * 994 * 8 * 54, 64);
dc_dsc_compute_config(
param.sink->ctx->dc->res_pool->dscs[0],
&param.sink->dsc_caps.dsc_dec_caps,
param.sink->ctx->dc->debug.dsc_min_slice_height_override,
- param.sink->edid_caps.panel_patch.max_dsc_target_bpp_limit,
+ max_dsc_target_bpp_limit_override,
(int) kbps, param.timing, &dsc_config);
return dsc_config.bits_per_pixel;
}
-static bool increase_dsc_bpp(struct drm_atomic_state *state,
- struct drm_dp_mst_topology_state *mst_state,
- struct dc_link *dc_link,
- struct dsc_mst_fairness_params *params,
- struct dsc_mst_fairness_vars *vars,
- int count,
- int k)
+static int increase_dsc_bpp(struct drm_atomic_state *state,
+ struct drm_dp_mst_topology_state *mst_state,
+ struct dc_link *dc_link,
+ struct dsc_mst_fairness_params *params,
+ struct dsc_mst_fairness_vars *vars,
+ int count,
+ int k)
{
int i;
bool bpp_increased[MAX_PIPES];
@@ -719,6 +726,7 @@ static bool increase_dsc_bpp(struct drm_atomic_state *state,
int remaining_to_increase = 0;
int link_timeslots_used;
int fair_pbn_alloc;
+ int ret = 0;
for (i = 0; i < count; i++) {
if (vars[i + k].dsc_enabled) {
@@ -757,52 +765,60 @@ static bool increase_dsc_bpp(struct drm_atomic_state *state,
if (initial_slack[next_index] > fair_pbn_alloc) {
vars[next_index].pbn += fair_pbn_alloc;
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
- if (!drm_dp_mst_atomic_check(state)) {
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_dp_mst_atomic_check(state);
+ if (ret == 0) {
vars[next_index].bpp_x16 = bpp_x16_from_pbn(params[next_index], vars[next_index].pbn);
} else {
vars[next_index].pbn -= fair_pbn_alloc;
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
}
} else {
vars[next_index].pbn += initial_slack[next_index];
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
- if (!drm_dp_mst_atomic_check(state)) {
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_dp_mst_atomic_check(state);
+ if (ret == 0) {
vars[next_index].bpp_x16 = params[next_index].bw_range.max_target_bpp_x16;
} else {
vars[next_index].pbn -= initial_slack[next_index];
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
}
}
bpp_increased[next_index] = true;
remaining_to_increase--;
}
- return true;
+ return 0;
}
-static bool try_disable_dsc(struct drm_atomic_state *state,
- struct dc_link *dc_link,
- struct dsc_mst_fairness_params *params,
- struct dsc_mst_fairness_vars *vars,
- int count,
- int k)
+static int try_disable_dsc(struct drm_atomic_state *state,
+ struct dc_link *dc_link,
+ struct dsc_mst_fairness_params *params,
+ struct dsc_mst_fairness_vars *vars,
+ int count,
+ int k)
{
int i;
bool tried[MAX_PIPES];
@@ -810,6 +826,7 @@ static bool try_disable_dsc(struct drm_atomic_state *state,
int max_kbps_increase;
int next_index;
int remaining_to_try = 0;
+ int ret;
for (i = 0; i < count; i++) {
if (vars[i + k].dsc_enabled
@@ -840,49 +857,52 @@ static bool try_disable_dsc(struct drm_atomic_state *state,
break;
vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps);
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
- if (!drm_dp_mst_atomic_check(state)) {
+ ret = drm_dp_mst_atomic_check(state);
+ if (ret == 0) {
vars[next_index].dsc_enabled = false;
vars[next_index].bpp_x16 = 0;
} else {
vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps);
- if (drm_dp_atomic_find_time_slots(state,
- params[next_index].port->mgr,
- params[next_index].port,
- vars[next_index].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+ vars[next_index].pbn);
+ if (ret < 0)
+ return ret;
}
tried[next_index] = true;
remaining_to_try--;
}
- return true;
+ return 0;
}
-static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
- struct dc_state *dc_state,
- struct dc_link *dc_link,
- struct dsc_mst_fairness_vars *vars,
- struct drm_dp_mst_topology_mgr *mgr,
- int *link_vars_start_index)
+static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct dc_link *dc_link,
+ struct dsc_mst_fairness_vars *vars,
+ struct drm_dp_mst_topology_mgr *mgr,
+ int *link_vars_start_index)
{
struct dc_stream_state *stream;
struct dsc_mst_fairness_params params[MAX_PIPES];
struct amdgpu_dm_connector *aconnector;
struct drm_dp_mst_topology_state *mst_state = drm_atomic_get_mst_topology_state(state, mgr);
int count = 0;
- int i, k;
+ int i, k, ret;
bool debugfs_overwrite = false;
memset(params, 0, sizeof(params));
if (IS_ERR(mst_state))
- return false;
+ return PTR_ERR(mst_state);
mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link);
#if defined(CONFIG_DRM_AMD_DC_DCN)
@@ -933,7 +953,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
if (count == 0) {
ASSERT(0);
- return true;
+ return 0;
}
/* k is start index of vars for current phy link used by mst hub */
@@ -947,13 +967,17 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
vars[i + k].dsc_enabled = false;
vars[i + k].bpp_x16 = 0;
- if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
- vars[i + k].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
+ vars[i + k].pbn);
+ if (ret < 0)
+ return ret;
}
- if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) {
+ ret = drm_dp_mst_atomic_check(state);
+ if (ret == 0 && !debugfs_overwrite) {
set_dsc_configs_from_fairness_vars(params, vars, count, k);
- return true;
+ return 0;
+ } else if (ret != -ENOSPC) {
+ return ret;
}
/* Try max compression */
@@ -962,31 +986,36 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
vars[i + k].dsc_enabled = true;
vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
- if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
- params[i].port, vars[i + k].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
+ params[i].port, vars[i + k].pbn);
+ if (ret < 0)
+ return ret;
} else {
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
vars[i + k].dsc_enabled = false;
vars[i + k].bpp_x16 = 0;
- if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
- params[i].port, vars[i + k].pbn) < 0)
- return false;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
+ params[i].port, vars[i + k].pbn);
+ if (ret < 0)
+ return ret;
}
}
- if (drm_dp_mst_atomic_check(state))
- return false;
+ ret = drm_dp_mst_atomic_check(state);
+ if (ret != 0)
+ return ret;
/* Optimize degree of compression */
- if (!increase_dsc_bpp(state, mst_state, dc_link, params, vars, count, k))
- return false;
+ ret = increase_dsc_bpp(state, mst_state, dc_link, params, vars, count, k);
+ if (ret < 0)
+ return ret;
- if (!try_disable_dsc(state, dc_link, params, vars, count, k))
- return false;
+ ret = try_disable_dsc(state, dc_link, params, vars, count, k);
+ if (ret < 0)
+ return ret;
set_dsc_configs_from_fairness_vars(params, vars, count, k);
- return true;
+ return 0;
}
static bool is_dsc_need_re_compute(
@@ -1087,15 +1116,17 @@ static bool is_dsc_need_re_compute(
return is_dsc_need_re_compute;
}
-bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
- struct dc_state *dc_state,
- struct dsc_mst_fairness_vars *vars)
+int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars)
{
int i, j;
struct dc_stream_state *stream;
bool computed_streams[MAX_PIPES];
struct amdgpu_dm_connector *aconnector;
+ struct drm_dp_mst_topology_mgr *mst_mgr;
int link_vars_start_index = 0;
+ int ret = 0;
for (i = 0; i < dc_state->stream_count; i++)
computed_streams[i] = false;
@@ -1108,7 +1139,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->dc_sink)
+ if (!aconnector || !aconnector->dc_sink || !aconnector->port)
continue;
if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1118,19 +1149,16 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
continue;
if (dcn20_remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK)
- return false;
+ return -EINVAL;
if (!is_dsc_need_re_compute(state, dc_state, stream->link))
continue;
- mutex_lock(&aconnector->mst_mgr.lock);
- if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars,
- &aconnector->mst_mgr,
- &link_vars_start_index)) {
- mutex_unlock(&aconnector->mst_mgr.lock);
- return false;
- }
- mutex_unlock(&aconnector->mst_mgr.lock);
+ mst_mgr = aconnector->port->mgr;
+ ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
+ &link_vars_start_index);
+ if (ret != 0)
+ return ret;
for (j = 0; j < dc_state->stream_count; j++) {
if (dc_state->streams[j]->link == stream->link)
@@ -1143,22 +1171,23 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
if (stream->timing.flags.DSC == 1)
if (dc_stream_add_dsc_to_resource(stream->ctx->dc, dc_state, stream) != DC_OK)
- return false;
+ return -EINVAL;
}
- return true;
+ return ret;
}
-static bool
- pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
- struct dc_state *dc_state,
- struct dsc_mst_fairness_vars *vars)
+static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars)
{
int i, j;
struct dc_stream_state *stream;
bool computed_streams[MAX_PIPES];
struct amdgpu_dm_connector *aconnector;
+ struct drm_dp_mst_topology_mgr *mst_mgr;
int link_vars_start_index = 0;
+ int ret = 0;
for (i = 0; i < dc_state->stream_count; i++)
computed_streams[i] = false;
@@ -1171,7 +1200,7 @@ static bool
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->dc_sink)
+ if (!aconnector || !aconnector->dc_sink || !aconnector->port)
continue;
if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1183,14 +1212,11 @@ static bool
if (!is_dsc_need_re_compute(state, dc_state, stream->link))
continue;
- mutex_lock(&aconnector->mst_mgr.lock);
- if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars,
- &aconnector->mst_mgr,
- &link_vars_start_index)) {
- mutex_unlock(&aconnector->mst_mgr.lock);
- return false;
- }
- mutex_unlock(&aconnector->mst_mgr.lock);
+ mst_mgr = aconnector->port->mgr;
+ ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
+ &link_vars_start_index);
+ if (ret != 0)
+ return ret;
for (j = 0; j < dc_state->stream_count; j++) {
if (dc_state->streams[j]->link == stream->link)
@@ -1198,7 +1224,7 @@ static bool
}
}
- return true;
+ return ret;
}
static int find_crtc_index_in_state_by_stream(struct drm_atomic_state *state,
@@ -1253,9 +1279,9 @@ static bool is_dsc_precompute_needed(struct drm_atomic_state *state)
return ret;
}
-bool pre_validate_dsc(struct drm_atomic_state *state,
- struct dm_atomic_state **dm_state_ptr,
- struct dsc_mst_fairness_vars *vars)
+int pre_validate_dsc(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state_ptr,
+ struct dsc_mst_fairness_vars *vars)
{
int i;
struct dm_atomic_state *dm_state;
@@ -1264,11 +1290,12 @@ bool pre_validate_dsc(struct drm_atomic_state *state,
if (!is_dsc_precompute_needed(state)) {
DRM_INFO_ONCE("DSC precompute is not needed.\n");
- return true;
+ return 0;
}
- if (dm_atomic_get_state(state, dm_state_ptr)) {
+ ret = dm_atomic_get_state(state, dm_state_ptr);
+ if (ret != 0) {
DRM_INFO_ONCE("dm_atomic_get_state() failed\n");
- return false;
+ return ret;
}
dm_state = *dm_state_ptr;
@@ -1280,7 +1307,7 @@ bool pre_validate_dsc(struct drm_atomic_state *state,
local_dc_state = kmemdup(dm_state->context, sizeof(struct dc_state), GFP_KERNEL);
if (!local_dc_state)
- return false;
+ return -ENOMEM;
for (i = 0; i < local_dc_state->stream_count; i++) {
struct dc_stream_state *stream = dm_state->context->streams[i];
@@ -1316,9 +1343,9 @@ bool pre_validate_dsc(struct drm_atomic_state *state,
if (ret != 0)
goto clean_exit;
- if (!pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars)) {
+ ret = pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars);
+ if (ret != 0) {
DRM_INFO_ONCE("pre_compute_mst_dsc_configs_for_state() failed\n");
- ret = -EINVAL;
goto clean_exit;
}
@@ -1349,7 +1376,7 @@ clean_exit:
kfree(local_dc_state);
- return (ret == 0);
+ return ret;
}
static unsigned int kbps_from_pbn(unsigned int pbn)
@@ -1392,6 +1419,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
unsigned int upper_link_bw_in_kbps = 0, down_link_bw_in_kbps = 0;
unsigned int max_compressed_bw_in_kbps = 0;
struct dc_dsc_bw_range bw_range = {0};
+ struct drm_dp_mst_topology_mgr *mst_mgr;
/*
* check if the mode could be supported if DSC pass-through is supported
@@ -1400,7 +1428,8 @@ enum dc_status dm_dp_mst_is_port_support_mode(
*/
if (is_dsc_common_config_possible(stream, &bw_range) &&
aconnector->port->passthrough_aux) {
- mutex_lock(&aconnector->mst_mgr.lock);
+ mst_mgr = aconnector->port->mgr;
+ mutex_lock(&mst_mgr->lock);
cur_link_settings = stream->link->verified_link_cap;
@@ -1413,7 +1442,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps,
down_link_bw_in_kbps);
- mutex_unlock(&aconnector->mst_mgr.lock);
+ mutex_unlock(&mst_mgr->lock);
/*
* use the maximum dsc compression bandwidth as the required
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index b92a7c5671aa..97fd70df531b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -53,15 +53,15 @@ struct dsc_mst_fairness_vars {
struct amdgpu_dm_connector *aconnector;
};
-bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
- struct dc_state *dc_state,
- struct dsc_mst_fairness_vars *vars);
+int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars);
bool needs_dsc_aux_workaround(struct dc_link *link);
-bool pre_validate_dsc(struct drm_atomic_state *state,
- struct dm_atomic_state **dm_state_ptr,
- struct dsc_mst_fairness_vars *vars);
+int pre_validate_dsc(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state_ptr,
+ struct dsc_mst_fairness_vars *vars);
enum dc_status dm_dp_mst_is_port_support_mode(
struct amdgpu_dm_connector *aconnector,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index e6854f7270a6..3c50b3ff7954 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1600,6 +1600,10 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
supported_rotations);
+ if (dm->adev->ip_versions[DCE_HWIP][0] > IP_VERSION(3, 0, 1) &&
+ plane->type != DRM_PLANE_TYPE_CURSOR)
+ drm_plane_enable_fb_damage_clips(plane);
+
drm_plane_helper_add(plane, &dm_plane_helper_funcs);
#ifdef CONFIG_DRM_AMD_DC_HDR
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
index d3bc9dc21771..0f580ea37576 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
@@ -37,6 +37,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_encoder.h>
#include <drm/drm_atomic.h>
+#include "dcn10/dcn10_optc.h"
#include "dc/inc/core_types.h"
@@ -662,6 +663,69 @@ TRACE_EVENT(dcn_fpu,
)
);
+TRACE_EVENT(dcn_optc_lock_unlock_state,
+ TP_PROTO(const struct optc *optc_state, int instance, bool lock, const char *function, const int line),
+ TP_ARGS(optc_state, instance, lock, function, line),
+
+ TP_STRUCT__entry(
+ __field(const char *, function)
+ __field(int, instance)
+ __field(bool, lock)
+ __field(int, line)
+ __field(int, opp_count)
+ __field(int, max_h_total)
+ __field(int, max_v_total)
+ __field(int, min_h_blank)
+ __field(int, min_h_sync_width)
+ __field(int, min_v_sync_width)
+ __field(int, min_v_blank)
+ __field(int, min_v_blank_interlace)
+ __field(int, vstartup_start)
+ __field(int, vupdate_offset)
+ __field(int, vupdate_width)
+ __field(int, vready_offset)
+ ),
+ TP_fast_assign(
+ __entry->function = function;
+ __entry->instance = instance;
+ __entry->lock = lock;
+ __entry->line = line;
+ __entry->opp_count = optc_state->opp_count;
+ __entry->max_h_total = optc_state->max_h_total;
+ __entry->max_v_total = optc_state->max_v_total;
+ __entry->min_h_blank = optc_state->min_h_blank;
+ __entry->min_h_sync_width = optc_state->min_h_sync_width;
+ __entry->min_v_sync_width = optc_state->min_v_sync_width;
+ __entry->min_v_blank = optc_state->min_v_blank;
+ __entry->min_v_blank_interlace = optc_state->min_v_blank_interlace;
+ __entry->vstartup_start = optc_state->vstartup_start;
+ __entry->vupdate_offset = optc_state->vupdate_offset;
+ __entry->vupdate_width = optc_state->vupdate_width;
+ __entry->vready_offset = optc_state->vupdate_offset;
+ ),
+ TP_printk("%s: %s()+%d: optc_instance=%d opp_count=%d max_h_total=%d max_v_total=%d "
+ "min_h_blank=%d min_h_sync_width=%d min_v_sync_width=%d min_v_blank=%d "
+ "min_v_blank_interlace=%d vstartup_start=%d vupdate_offset=%d vupdate_width=%d "
+ "vready_offset=%d",
+ __entry->lock ? "Lock" : "Unlock",
+ __entry->function,
+ __entry->line,
+ __entry->instance,
+ __entry->opp_count,
+ __entry->max_h_total,
+ __entry->max_v_total,
+ __entry->min_h_blank,
+ __entry->min_h_sync_width,
+ __entry->min_v_sync_width,
+ __entry->min_v_blank,
+ __entry->min_v_blank_interlace,
+ __entry->vstartup_start,
+ __entry->vupdate_offset,
+ __entry->vupdate_width,
+ __entry->vready_offset
+ )
+);
+
#endif /* _AMDGPU_DM_TRACE_H_ */
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index ab0c6d191038..1743ca0a3641 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -31,6 +31,8 @@
#elif defined(CONFIG_PPC64)
#include <asm/switch_to.h>
#include <asm/cputable.h>
+#elif defined(CONFIG_ARM64)
+#include <asm/neon.h>
#endif
/**
@@ -99,6 +101,8 @@ void dc_fpu_begin(const char *function_name, const int line)
preempt_disable();
enable_kernel_fp();
}
+#elif defined(CONFIG_ARM64)
+ kernel_neon_begin();
#endif
}
@@ -136,6 +140,8 @@ void dc_fpu_end(const char *function_name, const int line)
disable_kernel_fp();
preempt_enable();
}
+#elif defined(CONFIG_ARM64)
+ kernel_neon_end();
#endif
}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index 9b8ea6e9a2b9..a1a00f432168 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -138,7 +138,9 @@ static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
- table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
+ table = ((ATOM_OBJECT_TABLE *) bios_get_image(&bp->base,
+ object_table_offset,
+ struct_size(table, asObjects, 1)));
if (!table)
return 0;
@@ -166,8 +168,9 @@ static struct graphics_object_id bios_parser_get_connector_id(
uint32_t connector_table_offset = bp->object_info_tbl_offset
+ le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
- ATOM_OBJECT_TABLE *tbl =
- GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
+ ATOM_OBJECT_TABLE *tbl = ((ATOM_OBJECT_TABLE *) bios_get_image(&bp->base,
+ connector_table_offset,
+ struct_size(tbl, asObjects, 1)));
if (!tbl) {
dm_error("Can't get connector table from atom bios.\n");
@@ -662,8 +665,9 @@ static enum bp_result get_ss_info_v3_1(
if (!DATA_TABLES(ASIC_InternalSS_Info))
return BP_RESULT_UNSUPPORTED;
- ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
- DATA_TABLES(ASIC_InternalSS_Info));
+ ss_table_header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(&bp->base,
+ DATA_TABLES(ASIC_InternalSS_Info),
+ struct_size(ss_table_header_include, asSpreadSpectrum, 1)));
table_size =
(le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
- sizeof(ATOM_COMMON_TABLE_HEADER))
@@ -1029,8 +1033,10 @@ static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
if (!DATA_TABLES(ASIC_InternalSS_Info))
return result;
- header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
- DATA_TABLES(ASIC_InternalSS_Info));
+ header = ((ATOM_ASIC_INTERNAL_SS_INFO_V2 *) bios_get_image(
+ &bp->base,
+ DATA_TABLES(ASIC_InternalSS_Info),
+ struct_size(header, asSpreadSpectrum, 1)));
memset(info, 0, sizeof(struct spread_spectrum_info));
@@ -1709,8 +1715,10 @@ static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
if (!DATA_TABLES(ASIC_InternalSS_Info))
return 0;
- header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
- DATA_TABLES(ASIC_InternalSS_Info));
+ header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V2 *) bios_get_image(
+ &bp->base,
+ DATA_TABLES(ASIC_InternalSS_Info),
+ struct_size(header_include, asSpreadSpectrum, 1)));
size = (le16_to_cpu(header_include->sHeader.usStructureSize)
- sizeof(ATOM_COMMON_TABLE_HEADER))
@@ -1746,8 +1754,9 @@ static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
if (!DATA_TABLES(ASIC_InternalSS_Info))
return number;
- header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
- DATA_TABLES(ASIC_InternalSS_Info));
+ header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(&bp->base,
+ DATA_TABLES(ASIC_InternalSS_Info),
+ struct_size(header_include, asSpreadSpectrum, 1)));
size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
sizeof(ATOM_COMMON_TABLE_HEADER)) /
sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
@@ -1789,11 +1798,13 @@ static enum bp_result bios_parser_get_gpio_pin_info(
if (!DATA_TABLES(GPIO_Pin_LUT))
return BP_RESULT_BADBIOSTABLE;
- header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
+ header = ((ATOM_GPIO_PIN_LUT *) bios_get_image(&bp->base,
+ DATA_TABLES(GPIO_Pin_LUT),
+ struct_size(header, asGPIO_Pin, 1)));
if (!header)
return BP_RESULT_BADBIOSTABLE;
- if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
+ if (sizeof(ATOM_COMMON_TABLE_HEADER) + struct_size(header, asGPIO_Pin, 1)
> le16_to_cpu(header->sHeader.usStructureSize))
return BP_RESULT_BADBIOSTABLE;
@@ -1978,7 +1989,8 @@ static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
offset += bp->object_info_tbl_offset;
- tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
+ tbl = ((ATOM_OBJECT_TABLE *) bios_get_image(&bp->base, offset,
+ struct_size(tbl, asObjects, 1)));
if (!tbl)
return NULL;
@@ -2600,8 +2612,7 @@ static enum bp_result update_slot_layout_info(
for (;;) {
- record_header = (ATOM_COMMON_RECORD_HEADER *)
- GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
+ record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
if (record_header == NULL) {
result = BP_RESULT_BADBIOSTABLE;
break;
@@ -2615,7 +2626,7 @@ static enum bp_result update_slot_layout_info(
if (record_header->ucRecordType ==
ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
- sizeof(ATOM_BRACKET_LAYOUT_RECORD)
+ struct_size(record, asConnInfo, 1)
<= record_header->ucRecordSize) {
record = (ATOM_BRACKET_LAYOUT_RECORD *)
(record_header);
@@ -2709,8 +2720,9 @@ static enum bp_result get_bracket_layout_record(
genericTableOffset = bp->object_info_tbl_offset +
bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
- object_table = (ATOM_OBJECT_TABLE *)
- GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
+ object_table = ((ATOM_OBJECT_TABLE *) bios_get_image(&bp->base,
+ genericTableOffset,
+ struct_size(object_table, asObjects, 1)));
if (!object_table)
return BP_RESULT_FAILURE;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index ee0456b5e14e..074e70a5c458 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -462,6 +462,7 @@ static enum bp_result get_gpio_i2c_info(
uint32_t count = 0;
unsigned int table_index = 0;
bool find_valid = false;
+ struct atom_gpio_pin_assignment *pin;
if (!info)
return BP_RESULT_BADINPUT;
@@ -489,20 +490,17 @@ static enum bp_result get_gpio_i2c_info(
- sizeof(struct atom_common_table_header))
/ sizeof(struct atom_gpio_pin_assignment);
+ pin = (struct atom_gpio_pin_assignment *) header->gpio_pin;
+
for (table_index = 0; table_index < count; table_index++) {
- if (((record->i2c_id & I2C_HW_CAP) == (
- header->gpio_pin[table_index].gpio_id &
- I2C_HW_CAP)) &&
- ((record->i2c_id & I2C_HW_ENGINE_ID_MASK) ==
- (header->gpio_pin[table_index].gpio_id &
- I2C_HW_ENGINE_ID_MASK)) &&
- ((record->i2c_id & I2C_HW_LANE_MUX) ==
- (header->gpio_pin[table_index].gpio_id &
- I2C_HW_LANE_MUX))) {
+ if (((record->i2c_id & I2C_HW_CAP) == (pin->gpio_id & I2C_HW_CAP)) &&
+ ((record->i2c_id & I2C_HW_ENGINE_ID_MASK) == (pin->gpio_id & I2C_HW_ENGINE_ID_MASK)) &&
+ ((record->i2c_id & I2C_HW_LANE_MUX) == (pin->gpio_id & I2C_HW_LANE_MUX))) {
/* still valid */
find_valid = true;
break;
}
+ pin = (struct atom_gpio_pin_assignment *)((uint8_t *)pin + sizeof(struct atom_gpio_pin_assignment));
}
/* If we don't find the entry that we are looking for then
@@ -2393,6 +2391,26 @@ static enum bp_result get_vram_info_v25(
return result;
}
+static enum bp_result get_vram_info_v30(
+ struct bios_parser *bp,
+ struct dc_vram_info *info)
+{
+ struct atom_vram_info_header_v3_0 *info_v30;
+ enum bp_result result = BP_RESULT_OK;
+
+ info_v30 = GET_IMAGE(struct atom_vram_info_header_v3_0,
+ DATA_TABLES(vram_info));
+
+ if (info_v30 == NULL)
+ return BP_RESULT_BADBIOSTABLE;
+
+ info->num_chans = info_v30->channel_num;
+ info->dram_channel_width_bytes = (1 << info_v30->channel_width) / 8;
+
+ return result;
+}
+
+
/*
* get_integrated_info_v11
*
@@ -3060,6 +3078,16 @@ static enum bp_result bios_parser_get_vram_info(
}
break;
+ case 3:
+ switch (revision.minor) {
+ case 0:
+ result = get_vram_info_v30(bp, info);
+ break;
+ default:
+ break;
+ }
+ break;
+
default:
return result;
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
index 3e5df27aa96f..1ce19d875358 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
@@ -26,6 +26,8 @@
#ifndef DAL_DC_RN_CLK_MGR_VBIOS_SMU_H_
#define DAL_DC_RN_CLK_MGR_VBIOS_SMU_H_
+enum dcn_pwr_state;
+
int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr);
int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz);
int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr);
@@ -33,7 +35,7 @@ int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int reque
int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz);
void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz);
int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz);
-void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, int display_count);
+void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state);
void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable);
void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr);
int rn_vbios_smu_is_periodic_retraining_disabled(struct clk_mgr_internal *clk_mgr);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h
index 8ea8ee57b39f..61bb1d86182e 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
// This is a stripped-down version of the smu11_driver_if.h file for the relevant DAL interfaces.
#define SMU11_DRIVER_IF_VERSION 0x40
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
index c1eaf571407a..1c0569b1dc8f 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
@@ -609,8 +609,10 @@ static void dcn31_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
}
bw_params->vram_type = bios_info->memory_type;
- bw_params->num_channels = bios_info->ma_channel_number;
+ bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4;
+ //bw_params->dram_channel_width_bytes = dc->ctx->asic_id.vram_width;
+ bw_params->num_channels = bios_info->ma_channel_number ? bios_info->ma_channel_number : 4;
for (i = 0; i < WM_SET_COUNT; i++) {
bw_params->wm_table.entries[i].wm_inst = i;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
index 090b2c02aee1..0827c7df2855 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
@@ -333,8 +333,8 @@ void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst
(support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
support = DCN_ZSTATE_SUPPORT_DISALLOW;
-
- if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)
+ if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY ||
+ support == DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY)
param = 1;
else
param = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
index 1131c6d73f6c..20a06c04e4a1 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
@@ -363,32 +363,32 @@ static struct wm_table ddr5_wm_table = {
.wm_inst = WM_A,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.72,
- .sr_exit_time_us = 9,
- .sr_enter_plus_exit_time_us = 11,
+ .sr_exit_time_us = 12.5,
+ .sr_enter_plus_exit_time_us = 14.5,
.valid = true,
},
{
.wm_inst = WM_B,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.72,
- .sr_exit_time_us = 9,
- .sr_enter_plus_exit_time_us = 11,
+ .sr_exit_time_us = 12.5,
+ .sr_enter_plus_exit_time_us = 14.5,
.valid = true,
},
{
.wm_inst = WM_C,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.72,
- .sr_exit_time_us = 9,
- .sr_enter_plus_exit_time_us = 11,
+ .sr_exit_time_us = 12.5,
+ .sr_enter_plus_exit_time_us = 14.5,
.valid = true,
},
{
.wm_inst = WM_D,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.72,
- .sr_exit_time_us = 9,
- .sr_enter_plus_exit_time_us = 11,
+ .sr_exit_time_us = 12.5,
+ .sr_enter_plus_exit_time_us = 14.5,
.valid = true,
},
}
@@ -400,32 +400,32 @@ static struct wm_table lpddr5_wm_table = {
.wm_inst = WM_A,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.65333,
- .sr_exit_time_us = 11.5,
- .sr_enter_plus_exit_time_us = 14.5,
+ .sr_exit_time_us = 16.5,
+ .sr_enter_plus_exit_time_us = 18.5,
.valid = true,
},
{
.wm_inst = WM_B,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.65333,
- .sr_exit_time_us = 11.5,
- .sr_enter_plus_exit_time_us = 14.5,
+ .sr_exit_time_us = 16.5,
+ .sr_enter_plus_exit_time_us = 18.5,
.valid = true,
},
{
.wm_inst = WM_C,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.65333,
- .sr_exit_time_us = 11.5,
- .sr_enter_plus_exit_time_us = 14.5,
+ .sr_exit_time_us = 16.5,
+ .sr_enter_plus_exit_time_us = 18.5,
.valid = true,
},
{
.wm_inst = WM_D,
.wm_type = WM_TYPE_PSTATE_CHG,
.pstate_latency_us = 11.65333,
- .sr_exit_time_us = 11.5,
- .sr_enter_plus_exit_time_us = 14.5,
+ .sr_exit_time_us = 16.5,
+ .sr_enter_plus_exit_time_us = 18.5,
.valid = true,
},
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
index ef0795b14a1f..f47cfe6b42bd 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
@@ -123,9 +123,10 @@ static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
uint32_t result;
result = dcn314_smu_wait_for_response(clk_mgr, 10, 200000);
- ASSERT(result == VBIOSSMC_Result_OK);
- smu_print("SMU response after wait: %d\n", result);
+ if (result != VBIOSSMC_Result_OK)
+ smu_print("SMU Response was not OK. SMU response after wait received is: %d\n",
+ result);
if (result == VBIOSSMC_Status_BUSY)
return -1;
@@ -216,6 +217,12 @@ int dcn314_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int request
VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
khz_to_mhz_ceil(requested_dcfclk_khz));
+#ifdef DBG
+ smu_print("actual_dcfclk_set_mhz %d is set to : %d\n",
+ actual_dcfclk_set_mhz,
+ actual_dcfclk_set_mhz * 1000);
+#endif
+
return actual_dcfclk_set_mhz * 1000;
}
@@ -339,8 +346,6 @@ void dcn314_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zs
if (!clk_mgr->smu_present)
return;
- // Arg[15:0] = 8/9/0 for Z8/Z9/disallow -> existing bits
- // Arg[16] = Disallow Z9 -> new bit
switch (support) {
case DCN_ZSTATE_SUPPORT_ALLOW:
@@ -359,6 +364,16 @@ void dcn314_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zs
param = (1 << 10);
break;
+ case DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY:
+ msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
+ param = (1 << 10) | (1 << 8);
+ break;
+
+ case DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY:
+ msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
+ param = (1 << 8);
+ break;
+
default: //DCN_ZSTATE_SUPPORT_UNKNOWN
msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
param = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
index 893991a0eb97..07edd9777edf 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
@@ -458,19 +458,6 @@ static void dcn315_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
dcn315_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
}
-static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
-{
- uint32_t max = 0;
- int i;
-
- for (i = 0; i < num_clocks; ++i) {
- if (clocks[i] > max)
- max = clocks[i];
- }
-
- return max;
-}
-
static void dcn315_clk_mgr_helper_populate_bw_params(
struct clk_mgr_internal *clk_mgr,
struct integrated_info *bios_info,
@@ -478,29 +465,21 @@ static void dcn315_clk_mgr_helper_populate_bw_params(
{
int i;
struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
- uint32_t max_pstate = 0, max_fclk = 0, min_pstate = 0;
+ uint32_t max_pstate = clock_table->NumDfPstatesEnabled - 1;
struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
- /* Find highest fclk pstate */
- for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) {
- if (clock_table->DfPstateTable[i].FClk > max_fclk) {
- max_fclk = clock_table->DfPstateTable[i].FClk;
- max_pstate = i;
- }
- }
-
/* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */
for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
int j;
- uint32_t min_fclk = clock_table->DfPstateTable[0].FClk;
- for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) {
- if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]
- && clock_table->DfPstateTable[j].FClk < min_fclk) {
- min_fclk = clock_table->DfPstateTable[j].FClk;
- min_pstate = j;
- }
+ /* DF table is sorted with clocks decreasing */
+ for (j = clock_table->NumDfPstatesEnabled - 2; j >= 0; j--) {
+ if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i])
+ max_pstate = j;
}
+ /* Max DCFCLK should match up with max pstate */
+ if (i == clock_table->NumDcfClkLevelsEnabled - 1)
+ max_pstate = 0;
/* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
@@ -511,9 +490,9 @@ static void dcn315_clk_mgr_helper_populate_bw_params(
bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
/* Now update clocks we do read */
- bw_params->clk_table.entries[i].fclk_mhz = min_fclk;
- bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk;
- bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage;
+ bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[max_pstate].FClk;
+ bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
+ bw_params->clk_table.entries[i].voltage = clock_table->SocVoltage[i];
bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i];
@@ -521,25 +500,16 @@ static void dcn315_clk_mgr_helper_populate_bw_params(
bw_params->clk_table.entries[i].wck_ratio = 1;
}
- /* Make sure to include at least one entry and highest pstate */
- if (max_pstate != min_pstate || i == 0) {
- bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
- bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
- bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage;
- bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS);
+ /* Make sure to include at least one entry */
+ if (i == 0) {
+ bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[0].FClk;
+ bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[0].MemClk;
+ bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[0].Voltage;
+ bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[0];
bw_params->clk_table.entries[i].wck_ratio = 1;
i++;
}
- bw_params->clk_table.num_entries = i--;
-
- /* Make sure all highest clocks are included*/
- bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
- bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS);
- bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS);
- ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS));
- bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
- bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
- bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
+ bw_params->clk_table.num_entries = i;
/* Set any 0 clocks to max default setting. Not an issue for
* power since we aren't doing switching in such case anyway
@@ -565,6 +535,11 @@ static void dcn315_clk_mgr_helper_populate_bw_params(
if (!bw_params->clk_table.entries[i].dtbclk_mhz)
bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
}
+
+ /* Make sure all highest default clocks are included*/
+ ASSERT(bw_params->clk_table.entries[i-1].phyclk_mhz == def_max.phyclk_mhz);
+ ASSERT(bw_params->clk_table.entries[i-1].phyclk_d18_mhz == def_max.phyclk_d18_mhz);
+ ASSERT(bw_params->clk_table.entries[i-1].dtbclk_mhz == def_max.dtbclk_mhz);
ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz);
bw_params->vram_type = bios_info->memory_type;
bw_params->num_channels = bios_info->ma_channel_number;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
index 187f5b27fdc8..3edc81e2d417 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
@@ -553,6 +553,7 @@ static void dcn316_clk_mgr_helper_populate_bw_params(
bw_params->vram_type = bios_info->memory_type;
bw_params->num_channels = bios_info->ma_channel_number;
+ bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4;
for (i = 0; i < WM_SET_COUNT; i++) {
bw_params->wm_table.entries[i].wm_inst = i;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index 6f77d8e538ab..200fcec19186 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -233,41 +233,6 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
DC_FP_END();
}
-static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
- struct dc_state *context,
- int ref_dtbclk_khz)
-{
- struct dccg *dccg = clk_mgr->dccg;
- uint32_t tg_mask = 0;
- int i;
-
- for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
- struct dtbclk_dto_params dto_params = {0};
-
- /* use mask to program DTO once per tg */
- if (pipe_ctx->stream_res.tg &&
- !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
- tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
-
- dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
- dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
-
- if (is_dp_128b_132b_signal(pipe_ctx)) {
- dto_params.pixclk_khz = pipe_ctx->stream->phy_pix_clk;
-
- if (pipe_ctx->stream_res.audio != NULL)
- dto_params.req_audio_dtbclk_khz = 24000;
- }
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
- dto_params.is_hdmi = true;
-
- dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
- //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
- }
- }
-}
-
/* Since DPPCLK request to PMFW needs to be exact (due to DPP DTO programming),
* update DPPCLK to be the exact frequency that will be set after the DPPCLK
* divider is updated. This will prevent rounding issues that could cause DPP
@@ -438,7 +403,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
}
if (!new_clocks->dtbclk_en) {
- new_clocks->ref_dtbclk_khz = 0;
+ new_clocks->ref_dtbclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
}
/* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
@@ -447,8 +412,6 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
/* DCCG requires KHz precision for DTBCLK */
clk_mgr_base->clks.ref_dtbclk_khz =
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DTBCLK, khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz));
-
- dcn32_update_clocks_update_dtb_dto(clk_mgr, context, clk_mgr_base->clks.ref_dtbclk_khz);
}
if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) {
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_smu13_driver_if.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_smu13_driver_if.h
index d30fbbdd1792..d3d5a8caccf8 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_smu13_driver_if.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_smu13_driver_if.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
// This is a stripped-down version of the smu13_driver_if.h file for the relevant DAL interfaces.
#define SMU13_DRIVER_IF_VERSION 0x18
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 997ab031f816..0cb8d1f934d1 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -135,9 +135,7 @@ static const char DC_BUILD_ID[] = "production-build";
* one or two (in the pipe-split case).
*/
-/*******************************************************************************
- * Private functions
- ******************************************************************************/
+/* Private functions */
static inline void elevate_update_type(enum surface_update_type *original, enum surface_update_type new)
{
@@ -401,9 +399,6 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
{
int i;
- if (memcmp(adjust, &stream->adjust, sizeof(struct dc_crtc_timing_adjust)) == 0)
- return true;
-
stream->adjust.v_total_max = adjust->v_total_max;
stream->adjust.v_total_mid = adjust->v_total_mid;
stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num;
@@ -424,18 +419,14 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
}
/**
- *****************************************************************************
- * Function: dc_stream_get_last_vrr_vtotal
+ * dc_stream_get_last_used_drr_vtotal - dc_stream_get_last_vrr_vtotal
*
- * @brief
- * Looks up the pipe context of dc_stream_state and gets the
- * last VTOTAL used by DRR (Dynamic Refresh Rate)
+ * @dc: [in] dc reference
+ * @stream: [in] Initial dc stream state
+ * @adjust: [in] Updated parameters for vertical_total_min and
*
- * @param [in] dc: dc reference
- * @param [in] stream: Initial dc stream state
- * @param [in] adjust: Updated parameters for vertical_total_min and
- * vertical_total_max
- *****************************************************************************
+ * Looks up the pipe context of dc_stream_state and gets the last VTOTAL used
+ * by DRR (Dynamic Refresh Rate)
*/
bool dc_stream_get_last_used_drr_vtotal(struct dc *dc,
struct dc_stream_state *stream,
@@ -491,86 +482,79 @@ bool dc_stream_get_crtc_position(struct dc *dc,
}
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-bool dc_stream_forward_dmcu_crc_window(struct dc *dc, struct dc_stream_state *stream,
- struct crc_params *crc_window)
+static inline void
+dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv,
+ struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop)
{
- int i;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- struct pipe_ctx *pipe;
- struct crc_region tmp_win, *crc_win;
- struct otg_phy_mux mapping_tmp, *mux_mapping;
-
- /*crc window can't be null*/
- if (!crc_window)
- return false;
-
- if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu))) {
- crc_win = &tmp_win;
- mux_mapping = &mapping_tmp;
- /*set crc window*/
- tmp_win.x_start = crc_window->windowa_x_start;
- tmp_win.y_start = crc_window->windowa_y_start;
- tmp_win.x_end = crc_window->windowa_x_end;
- tmp_win.y_end = crc_window->windowa_y_end;
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
- break;
- }
-
- /* Stream not found */
- if (i == MAX_PIPES)
- return false;
-
+ union dmub_rb_cmd cmd = {0};
- /*set mux routing info*/
- mapping_tmp.phy_output_num = stream->link->link_enc_hw_inst;
- mapping_tmp.otg_output_num = pipe->stream_res.tg->inst;
+ cmd.secure_display.roi_info.phy_id = mux_mapping->phy_output_num;
+ cmd.secure_display.roi_info.otg_id = mux_mapping->otg_output_num;
- dmcu->funcs->forward_crc_window(dmcu, crc_win, mux_mapping);
+ if (is_stop) {
+ cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY;
+ cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE;
} else {
- DC_LOG_DC("dmcu is not initialized");
- return false;
+ cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY;
+ cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY;
+ cmd.secure_display.roi_info.x_start = rect->x;
+ cmd.secure_display.roi_info.y_start = rect->y;
+ cmd.secure_display.roi_info.x_end = rect->x + rect->width;
+ cmd.secure_display.roi_info.y_end = rect->y + rect->height;
}
- return true;
+ dc_dmub_srv_cmd_queue(dmub_srv, &cmd);
+ dc_dmub_srv_cmd_execute(dmub_srv);
}
-bool dc_stream_stop_dmcu_crc_win_update(struct dc *dc, struct dc_stream_state *stream)
+static inline void
+dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu,
+ struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop)
{
- int i;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- struct pipe_ctx *pipe;
- struct otg_phy_mux mapping_tmp, *mux_mapping;
+ if (is_stop)
+ dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping);
+ else
+ dmcu->funcs->forward_crc_window(dmcu, rect, mux_mapping);
+}
- if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu))) {
- mux_mapping = &mapping_tmp;
+bool
+dc_stream_forward_crc_window(struct dc *dc,
+ struct rect *rect, struct dc_stream_state *stream, bool is_stop)
+{
+ struct dmcu *dmcu;
+ struct dc_dmub_srv *dmub_srv;
+ struct otg_phy_mux mux_mapping;
+ struct pipe_ctx *pipe;
+ int i;
- for (i = 0; i < MAX_PIPES; i++) {
- pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
- break;
- }
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
+ break;
+ }
- /* Stream not found */
- if (i == MAX_PIPES)
- return false;
+ /* Stream not found */
+ if (i == MAX_PIPES)
+ return false;
+ mux_mapping.phy_output_num = stream->link->link_enc_hw_inst;
+ mux_mapping.otg_output_num = pipe->stream_res.tg->inst;
- /*set mux routing info*/
- mapping_tmp.phy_output_num = stream->link->link_enc_hw_inst;
- mapping_tmp.otg_output_num = pipe->stream_res.tg->inst;
+ dmcu = dc->res_pool->dmcu;
+ dmub_srv = dc->ctx->dmub_srv;
- dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping);
- } else {
- DC_LOG_DC("dmcu is not initialized");
+ /* forward to dmub */
+ if (dmub_srv)
+ dc_stream_forward_dmub_crc_window(dmub_srv, rect, &mux_mapping, is_stop);
+ /* forward to dmcu */
+ else if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
+ dc_stream_forward_dmcu_crc_window(dmcu, rect, &mux_mapping, is_stop);
+ else
return false;
- }
return true;
}
-#endif
+#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
/**
* dc_stream_configure_crc() - Configure CRC capture for the given stream.
@@ -1070,6 +1054,8 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
int i, j;
struct dc_state *dangling_context = dc_create_state(dc);
struct dc_state *current_ctx;
+ struct pipe_ctx *pipe;
+ struct timing_generator *tg;
if (dangling_context == NULL)
return;
@@ -1112,6 +1098,18 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
}
if (should_disable && old_stream) {
+ pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+ tg = pipe->stream_res.tg;
+ /* When disabling plane for a phantom pipe, we must turn on the
+ * phantom OTG so the disable programming gets the double buffer
+ * update. Otherwise the pipe will be left in a partially disabled
+ * state that can result in underflow or hang when enabling it
+ * again for different use.
+ */
+ if (old_stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ if (tg->funcs->enable_crtc)
+ tg->funcs->enable_crtc(tg);
+ }
dc_rem_all_planes_for_stream(dc, old_stream, dangling_context);
disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);
@@ -1127,6 +1125,15 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
dc->hwss.interdependent_update_lock(dc, dc->current_state, false);
dc->hwss.post_unlock_program_front_end(dc, dangling_context);
}
+ /* We need to put the phantom OTG back into it's default (disabled) state or we
+ * can get corruption when transition from one SubVP config to a different one.
+ * The OTG is set to disable on falling edge of VUPDATE so the plane disable
+ * will still get it's double buffer update.
+ */
+ if (old_stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ if (tg->funcs->disable_phantom_crtc)
+ tg->funcs->disable_phantom_crtc(tg);
+ }
}
}
@@ -1219,9 +1226,7 @@ static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)
PERF_TRACE();
}
-/*******************************************************************************
- * Public functions
- ******************************************************************************/
+/* Public functions */
struct dc *dc_create(const struct dc_init_data *init_params)
{
@@ -1488,17 +1493,19 @@ static void program_timing_sync(
}
}
-static bool context_changed(
- struct dc *dc,
- struct dc_state *context)
+static bool streams_changed(struct dc *dc,
+ struct dc_stream_state *streams[],
+ uint8_t stream_count)
{
uint8_t i;
- if (context->stream_count != dc->current_state->stream_count)
+ if (stream_count != dc->current_state->stream_count)
return true;
for (i = 0; i < dc->current_state->stream_count; i++) {
- if (dc->current_state->streams[i] != context->streams[i])
+ if (dc->current_state->streams[i] != streams[i])
+ return true;
+ if (!streams[i]->link->link_state_valid)
return true;
}
@@ -1549,6 +1556,9 @@ bool dc_validate_boot_timing(const struct dc *dc,
if (tg_inst >= dc->res_pool->timing_generator_count)
return false;
+ if (tg_inst != link->link_enc->preferred_engine)
+ return false;
+
tg = dc->res_pool->timing_generators[tg_inst];
if (!tg->funcs->get_hw_timing)
@@ -1722,8 +1732,13 @@ void dc_z10_save_init(struct dc *dc)
dc->hwss.z10_save_init(dc);
}
-/*
- * Applies given context to HW and copy it into current context.
+/**
+ * dc_commit_state_no_check - Apply context to the hardware
+ *
+ * @dc: DC object with the current status to be updated
+ * @context: New state that will become the current status at the end of this function
+ *
+ * Applies given context to the hardware and copy it into current context.
* It's up to the user to release the src context afterwards.
*/
static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
@@ -1760,6 +1775,12 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
context->stream_count == 0)
dc->hwss.prepare_bandwidth(dc, context);
+ /* When SubVP is active, all HW programming must be done while
+ * SubVP lock is acquired
+ */
+ if (dc->hwss.subvp_pipe_control_lock)
+ dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use);
+
if (dc->debug.enable_double_buffered_dsc_pg_support)
dc->hwss.update_dsc_pg(dc, context, false);
@@ -1787,9 +1808,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
}
- if (dc->hwss.subvp_pipe_control_lock)
- dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use);
-
result = dc->hwss.apply_ctx_to_hw(dc, context);
if (result != DC_OK) {
@@ -1888,12 +1906,108 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
return result;
}
+/**
+ * dc_commit_streams - Commit current stream state
+ *
+ * @dc: DC object with the commit state to be configured in the hardware
+ * @streams: Array with a list of stream state
+ * @stream_count: Total of streams
+ *
+ * Function responsible for commit streams change to the hardware.
+ *
+ * Return:
+ * Return DC_OK if everything work as expected, otherwise, return a dc_status
+ * code.
+ */
+enum dc_status dc_commit_streams(struct dc *dc,
+ struct dc_stream_state *streams[],
+ uint8_t stream_count)
+{
+ int i, j;
+ struct dc_state *context;
+ enum dc_status res = DC_OK;
+ struct dc_validation_set set[MAX_STREAMS] = {0};
+
+ if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
+ return res;
+
+ if (!streams_changed(dc, streams, stream_count))
+ return res;
+
+ DC_LOG_DC("%s: %d streams\n", __func__, stream_count);
+
+ for (i = 0; i < stream_count; i++) {
+ struct dc_stream_state *stream = streams[i];
+ struct dc_stream_status *status = dc_stream_get_status(stream);
+
+ dc_stream_log(dc, stream);
+
+ set[i].stream = stream;
+
+ if (status) {
+ set[i].plane_count = status->plane_count;
+ for (j = 0; j < status->plane_count; j++)
+ set[i].plane_states[j] = status->plane_states[j];
+ }
+ }
+
+ context = dc_create_state(dc);
+ if (!context)
+ goto context_alloc_fail;
+
+ dc_resource_state_copy_construct_current(dc, context);
+
+ res = dc_validate_with_context(dc, set, stream_count, context, false);
+ if (res != DC_OK) {
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ }
+
+ res = dc_commit_state_no_check(dc, context);
+
+ for (i = 0; i < stream_count; i++) {
+ for (j = 0; j < context->stream_count; j++) {
+ if (streams[i]->stream_id == context->streams[j]->stream_id)
+ streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst;
+
+ if (dc_is_embedded_signal(streams[i]->signal)) {
+ struct dc_stream_status *status = dc_stream_get_status_from_state(context, streams[i]);
+
+ if (dc->hwss.is_abm_supported)
+ status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]);
+ else
+ status->is_abm_supported = true;
+ }
+ }
+ }
+
+fail:
+ dc_release_state(context);
+
+context_alloc_fail:
+
+ DC_LOG_DC("%s Finished.\n", __func__);
+
+ return res;
+}
+
+/* TODO: When the transition to the new commit sequence is done, remove this
+ * function in favor of dc_commit_streams. */
bool dc_commit_state(struct dc *dc, struct dc_state *context)
{
enum dc_status result = DC_ERROR_UNEXPECTED;
int i;
- if (!context_changed(dc, context))
+ /* TODO: Since change commit sequence can have a huge impact,
+ * we decided to only enable it for DCN3x. However, as soon as
+ * we get more confident about this change we'll need to enable
+ * the new sequence for all ASICs. */
+ if (dc->ctx->dce_version >= DCN_VERSION_3_2) {
+ result = dc_commit_streams(dc, context->streams, context->stream_count);
+ return result == DC_OK;
+ }
+
+ if (!streams_changed(dc, context->streams, context->stream_count))
return DC_OK;
DC_LOG_DC("%s: %d streams\n",
@@ -2950,7 +3064,7 @@ static bool update_planes_and_stream_state(struct dc *dc,
* Ensures that we have enough pipes for newly added MPO planes
*/
if (dc->res_pool->funcs->remove_phantom_pipes)
- dc->res_pool->funcs->remove_phantom_pipes(dc, context);
+ dc->res_pool->funcs->remove_phantom_pipes(dc, context, false);
/*remove old surfaces from context */
if (!dc_rem_all_planes_for_stream(dc, stream, context)) {
@@ -2987,6 +3101,19 @@ static bool update_planes_and_stream_state(struct dc *dc,
if (update_type == UPDATE_TYPE_FULL) {
if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) {
+ /* For phantom pipes we remove and create a new set of phantom pipes
+ * for each full update (because we don't know if we'll need phantom
+ * pipes until after the first round of validation). However, if validation
+ * fails we need to keep the existing phantom pipes (because we don't update
+ * the dc->current_state).
+ *
+ * The phantom stream/plane refcount is decremented for validation because
+ * we assume it'll be removed (the free comes when the dc_state is freed),
+ * but if validation fails we have to increment back the refcount so it's
+ * consistent.
+ */
+ if (dc->res_pool->funcs->retain_phantom_pipes)
+ dc->res_pool->funcs->retain_phantom_pipes(dc, dc->current_state);
BREAK_TO_DEBUGGER();
goto fail;
}
@@ -3297,22 +3424,6 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);
}
- if (update_type != UPDATE_TYPE_FAST) {
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
-
- if ((new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) ||
- subvp_prev_use) {
- // If old context or new context has phantom pipes, apply
- // the phantom timings now. We can't change the phantom
- // pipe configuration safely without driver acquiring
- // the DMCUB lock first.
- dc->hwss.apply_ctx_to_hw(dc, context);
- break;
- }
- }
- }
-
dc_dmub_update_dirty_rect(dc, surface_count, stream, srf_updates, context);
if (update_type != UPDATE_TYPE_FAST) {
@@ -3370,6 +3481,24 @@ static void commit_planes_for_stream(struct dc *dc,
return;
}
+ if (update_type != UPDATE_TYPE_FAST) {
+ for (j = 0; j < dc->res_pool->pipe_count; j++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+
+ if (dc->debug.visual_confirm == VISUAL_CONFIRM_SUBVP &&
+ pipe_ctx->stream && pipe_ctx->plane_state) {
+ /* Only update visual confirm for SUBVP here.
+ * The bar appears on all pipes, so we need to update the bar on all displays,
+ * so the information doesn't get stale.
+ */
+ struct mpcc_blnd_cfg blnd_cfg = { 0 };
+
+ dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color,
+ pipe_ctx->plane_res.hubp->inst);
+ }
+ }
+ }
+
if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
for (i = 0; i < surface_count; i++) {
struct dc_plane_state *plane_state = srf_updates[i].surface;
@@ -3487,7 +3616,6 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.update_plane_addr(dc, pipe_ctx);
}
}
-
}
if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
@@ -3524,6 +3652,44 @@ static void commit_planes_for_stream(struct dc *dc,
top_pipe_to_program->stream_res.tg);
}
+ /* For phantom pipe OTG enable, it has to be done after any previous pipe
+ * that was in use has already been programmed at gotten its double buffer
+ * update for "disable".
+ */
+ if (update_type != UPDATE_TYPE_FAST) {
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ /* If an active, non-phantom pipe is being transitioned into a phantom
+ * pipe, wait for the double buffer update to complete first before we do
+ * ANY phantom pipe programming.
+ */
+ if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
+ old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
+ old_pipe->stream_res.tg->funcs->wait_for_state(
+ old_pipe->stream_res.tg,
+ CRTC_STATE_VBLANK);
+ old_pipe->stream_res.tg->funcs->wait_for_state(
+ old_pipe->stream_res.tg,
+ CRTC_STATE_VACTIVE);
+ }
+ }
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
+
+ if ((new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) ||
+ subvp_prev_use) {
+ // If old context or new context has phantom pipes, apply
+ // the phantom timings now. We can't change the phantom
+ // pipe configuration safely without driver acquiring
+ // the DMCUB lock first.
+ dc->hwss.apply_ctx_to_hw(dc, context);
+ break;
+ }
+ }
+ }
+
if (update_type != UPDATE_TYPE_FAST)
dc->hwss.post_unlock_program_front_end(dc, context);
if (update_type != UPDATE_TYPE_FAST)
@@ -3563,10 +3729,24 @@ static void commit_planes_for_stream(struct dc *dc,
}
}
-/* Determines if the incoming context requires a applying transition state with unnecessary
- * pipe splitting and ODM disabled, due to hardware limitations. In a case where
- * the OPP associated with an MPCC might change due to plane additions, this function
+/**
+ * could_mpcc_tree_change_for_active_pipes - Check if an OPP associated with MPCC might change
+ *
+ * @dc: Used to get the current state status
+ * @stream: Target stream, which we want to remove the attached planes
+ * @surface_count: Number of surface update
+ * @is_plane_addition: [in] Fill out with true if it is a plane addition case
+ *
+ * DCN32x and newer support a feature named Dynamic ODM which can conflict with
+ * the MPO if used simultaneously in some specific configurations (e.g.,
+ * 4k@144). This function checks if the incoming context requires applying a
+ * transition state with unnecessary pipe splitting and ODM disabled to
+ * circumvent our hardware limitations to prevent this edge case. If the OPP
+ * associated with an MPCC might change due to plane additions, this function
* returns true.
+ *
+ * Return:
+ * Return true if OPP and MPCC might change, otherwise, return false.
*/
static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc,
struct dc_stream_state *stream,
@@ -3576,6 +3756,7 @@ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc,
struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream);
bool force_minimal_pipe_splitting = false;
+ bool subvp_active = false;
uint32_t i;
*is_plane_addition = false;
@@ -3608,39 +3789,55 @@ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc,
}
}
- /* For SubVP pipe split case when adding MPO video
- * we need to add a minimal transition. In this case
- * there will be 2 streams (1 main stream, 1 phantom
- * stream).
- */
- if (cur_stream_status &&
- dc->current_state->stream_count == 2 &&
- stream->mall_stream_config.type == SUBVP_MAIN) {
- bool is_pipe_split = false;
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream &&
- (dc->current_state->res_ctx.pipe_ctx[i].bottom_pipe ||
- dc->current_state->res_ctx.pipe_ctx[i].next_odm_pipe)) {
- is_pipe_split = true;
- break;
- }
+ if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) {
+ subvp_active = true;
+ break;
}
+ }
+ /* For SubVP when adding or removing planes we need to add a minimal transition
+ * (even when disabling all planes). Whenever disabling a phantom pipe, we
+ * must use the minimal transition path to disable the pipe correctly.
+ *
+ * We want to use the minimal transition whenever subvp is active, not only if
+ * a plane is being added / removed from a subvp stream (MPO plane can be added
+ * to a DRR pipe of SubVP + DRR config, in which case we still want to run through
+ * a min transition to disable subvp.
+ */
+ if (cur_stream_status && subvp_active) {
/* determine if minimal transition is required due to SubVP*/
- if (surface_count > 0 && is_pipe_split) {
- if (cur_stream_status->plane_count > surface_count) {
- force_minimal_pipe_splitting = true;
- } else if (cur_stream_status->plane_count < surface_count) {
- force_minimal_pipe_splitting = true;
- *is_plane_addition = true;
- }
+ if (cur_stream_status->plane_count > surface_count) {
+ force_minimal_pipe_splitting = true;
+ } else if (cur_stream_status->plane_count < surface_count) {
+ force_minimal_pipe_splitting = true;
+ *is_plane_addition = true;
}
}
return force_minimal_pipe_splitting;
}
+/**
+ * commit_minimal_transition_state - Create a transition pipe split state
+ *
+ * @dc: Used to get the current state status
+ * @transition_base_context: New transition state
+ *
+ * In some specific configurations, such as pipe split on multi-display with
+ * MPO and/or Dynamic ODM, removing a plane may cause unsupported pipe
+ * programming when moving to new planes. To mitigate those types of problems,
+ * this function adds a transition state that minimizes pipe usage before
+ * programming the new configuration. When adding a new plane, the current
+ * state requires the least pipes, so it is applied without splitting. When
+ * removing a plane, the new state requires the least pipes, so it is applied
+ * without splitting.
+ *
+ * Return:
+ * Return false if something is wrong in the transition state.
+ */
static bool commit_minimal_transition_state(struct dc *dc,
struct dc_state *transition_base_context)
{
@@ -3650,9 +3847,48 @@ static bool commit_minimal_transition_state(struct dc *dc,
bool temp_subvp_policy;
enum dc_status ret = DC_ERROR_UNEXPECTED;
unsigned int i, j;
+ unsigned int pipe_in_use = 0;
+ bool subvp_in_use = false;
if (!transition_context)
return false;
+ /* Setup:
+ * Store the current ODM and MPC config in some temp variables to be
+ * restored after we commit the transition state.
+ */
+
+ /* check current pipes in use*/
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &transition_base_context->res_ctx.pipe_ctx[i];
+
+ if (pipe->plane_state)
+ pipe_in_use++;
+ }
+
+ /* If SubVP is enabled and we are adding or removing planes from any main subvp
+ * pipe, we must use the minimal transition.
+ */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ subvp_in_use = true;
+ break;
+ }
+ }
+
+ /* When the OS add a new surface if we have been used all of pipes with odm combine
+ * and mpc split feature, it need use commit_minimal_transition_state to transition safely.
+ * After OS exit MPO, it will back to use odm and mpc split with all of pipes, we need
+ * call it again. Otherwise return true to skip.
+ *
+ * Reduce the scenarios to use dc_commit_state_no_check in the stage of flip. Especially
+ * enter/exit MPO when DCN still have enough resources.
+ */
+ if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use) {
+ dc_release_state(transition_context);
+ return true;
+ }
if (!dc->config.is_vmin_only_asic) {
tmp_mpc_policy = dc->debug.pipe_split_policy;
@@ -3667,7 +3903,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
dc_resource_state_copy_construct(transition_base_context, transition_context);
- //commit minimal state
+ /* commit minimal state */
if (dc->res_pool->funcs->validate_bandwidth(dc, transition_context, false)) {
for (i = 0; i < transition_context->stream_count; i++) {
struct dc_stream_status *stream_status = &transition_context->stream_status[i];
@@ -3685,10 +3921,12 @@ static bool commit_minimal_transition_state(struct dc *dc,
ret = dc_commit_state_no_check(dc, transition_context);
}
- /*always release as dc_commit_state_no_check retains in good case*/
+ /* always release as dc_commit_state_no_check retains in good case */
dc_release_state(transition_context);
- /*restore previous pipe split and odm policy*/
+ /* TearDown:
+ * Restore original configuration for ODM and MPO.
+ */
if (!dc->config.is_vmin_only_asic)
dc->debug.pipe_split_policy = tmp_mpc_policy;
@@ -3696,12 +3934,12 @@ static bool commit_minimal_transition_state(struct dc *dc,
dc->debug.force_disable_subvp = temp_subvp_policy;
if (ret != DC_OK) {
- /*this should never happen*/
+ /* this should never happen */
BREAK_TO_DEBUGGER();
return false;
}
- /*force full surface update*/
+ /* force full surface update */
for (i = 0; i < dc->current_state->stream_count; i++) {
for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF;
@@ -3719,6 +3957,7 @@ bool dc_update_planes_and_stream(struct dc *dc,
struct dc_state *context;
enum surface_update_type update_type;
int i;
+ struct mall_temp_config mall_temp_config;
/* In cases where MPO and split or ODM are used transitions can
* cause underflow. Apply stream configuration with minimal pipe
@@ -3750,11 +3989,29 @@ bool dc_update_planes_and_stream(struct dc *dc,
/* on plane removal, minimal state is the new one */
if (force_minimal_pipe_splitting && !is_plane_addition) {
+ /* Since all phantom pipes are removed in full validation,
+ * we have to save and restore the subvp/mall config when
+ * we do a minimal transition since the flags marking the
+ * pipe as subvp/phantom will be cleared (dc copy constructor
+ * creates a shallow copy).
+ */
+ if (dc->res_pool->funcs->save_mall_state)
+ dc->res_pool->funcs->save_mall_state(dc, context, &mall_temp_config);
if (!commit_minimal_transition_state(dc, context)) {
dc_release_state(context);
return false;
}
-
+ if (dc->res_pool->funcs->restore_mall_state)
+ dc->res_pool->funcs->restore_mall_state(dc, context, &mall_temp_config);
+
+ /* If we do a minimal transition with plane removal and the context
+ * has subvp we also have to retain back the phantom stream / planes
+ * since the refcount is decremented as part of the min transition
+ * (we commit a state with no subvp, so the phantom streams / planes
+ * had to be removed).
+ */
+ if (dc->res_pool->funcs->retain_phantom_pipes)
+ dc->res_pool->funcs->retain_phantom_pipes(dc, context);
update_type = UPDATE_TYPE_FULL;
}
@@ -3806,6 +4063,18 @@ void dc_commit_updates_for_stream(struct dc *dc,
struct dc_context *dc_ctx = dc->ctx;
int i, j;
+ /* TODO: Since change commit sequence can have a huge impact,
+ * we decided to only enable it for DCN3x. However, as soon as
+ * we get more confident about this change we'll need to enable
+ * the new sequence for all ASICs.
+ */
+ if (dc->ctx->dce_version >= DCN_VERSION_3_2) {
+ dc_update_planes_and_stream(dc, srf_updates,
+ surface_count, stream,
+ stream_update);
+ return;
+ }
+
stream_status = dc_stream_get_status(stream);
context = dc->current_state;
@@ -4387,21 +4656,17 @@ void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc)
dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down = true;
}
-/*
- *****************************************************************************
- * Function: dc_is_dmub_outbox_supported -
+/**
+ * dc_is_dmub_outbox_supported - Check if DMUB firmware support outbox notification
*
- * @brief
- * Checks whether DMUB FW supports outbox notifications, if supported
- * DM should register outbox interrupt prior to actually enabling interrupts
- * via dc_enable_dmub_outbox
+ * @dc: [in] dc structure
*
- * @param
- * [in] dc: dc structure
+ * Checks whether DMUB FW supports outbox notifications, if supported DM
+ * should register outbox interrupt prior to actually enabling interrupts
+ * via dc_enable_dmub_outbox
*
- * @return
- * True if DMUB FW supports outbox notifications, False otherwise
- *****************************************************************************
+ * Return:
+ * True if DMUB FW supports outbox notifications, False otherwise
*/
bool dc_is_dmub_outbox_supported(struct dc *dc)
{
@@ -4419,21 +4684,17 @@ bool dc_is_dmub_outbox_supported(struct dc *dc)
return dc->debug.enable_dmub_aux_for_legacy_ddc;
}
-/*
- *****************************************************************************
- * Function: dc_enable_dmub_notifications
+/**
+ * dc_enable_dmub_notifications - Check if dmub fw supports outbox
*
- * @brief
- * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox
- * notifications. All DMs shall switch to dc_is_dmub_outbox_supported.
- * This API shall be removed after switching.
+ * @dc: [in] dc structure
*
- * @param
- * [in] dc: dc structure
+ * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox
+ * notifications. All DMs shall switch to dc_is_dmub_outbox_supported. This
+ * API shall be removed after switching.
*
- * @return
- * True if DMUB FW supports outbox notifications, False otherwise
- *****************************************************************************
+ * Return:
+ * True if DMUB FW supports outbox notifications, False otherwise
*/
bool dc_enable_dmub_notifications(struct dc *dc)
{
@@ -4441,18 +4702,11 @@ bool dc_enable_dmub_notifications(struct dc *dc)
}
/**
- *****************************************************************************
- * Function: dc_enable_dmub_outbox
+ * dc_enable_dmub_outbox - Enables DMUB unsolicited notification
*
- * @brief
- * Enables DMUB unsolicited notifications to x86 via outbox
+ * dc: [in] dc structure
*
- * @param
- * [in] dc: dc structure
- *
- * @return
- * None
- *****************************************************************************
+ * Enables DMUB unsolicited notifications to x86 via outbox.
*/
void dc_enable_dmub_outbox(struct dc *dc)
{
@@ -4553,21 +4807,17 @@ uint8_t get_link_index_from_dpia_port_index(const struct dc *dc,
}
/**
- *****************************************************************************
- * Function: dc_process_dmub_set_config_async
+ * dc_process_dmub_set_config_async - Submits set_config command
*
- * @brief
- * Submits set_config command to dmub via inbox message
+ * @dc: [in] dc structure
+ * @link_index: [in] link_index: link index
+ * @payload: [in] aux payload
+ * @notify: [out] set_config immediate reply
*
- * @param
- * [in] dc: dc structure
- * [in] link_index: link index
- * [in] payload: aux payload
- * [out] notify: set_config immediate reply
+ * Submits set_config command to dmub via inbox message.
*
- * @return
- * True if successful, False if failure
- *****************************************************************************
+ * Return:
+ * True if successful, False if failure
*/
bool dc_process_dmub_set_config_async(struct dc *dc,
uint32_t link_index,
@@ -4603,21 +4853,17 @@ bool dc_process_dmub_set_config_async(struct dc *dc,
}
/**
- *****************************************************************************
- * Function: dc_process_dmub_set_mst_slots
+ * dc_process_dmub_set_mst_slots - Submits MST solt allocation
*
- * @brief
- * Submits mst slot allocation command to dmub via inbox message
+ * @dc: [in] dc structure
+ * @link_index: [in] link index
+ * @mst_alloc_slots: [in] mst slots to be allotted
+ * @mst_slots_in_use: [out] mst slots in use returned in failure case
*
- * @param
- * [in] dc: dc structure
- * [in] link_index: link index
- * [in] mst_alloc_slots: mst slots to be allotted
- * [out] mst_slots_in_use: mst slots in use returned in failure case
+ * Submits mst slot allocation command to dmub via inbox message
*
- * @return
- * DC_OK if successful, DC_ERROR if failure
- *****************************************************************************
+ * Return:
+ * DC_OK if successful, DC_ERROR if failure
*/
enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc,
uint32_t link_index,
@@ -4657,19 +4903,12 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc,
}
/**
- *****************************************************************************
- * Function: dc_process_dmub_dpia_hpd_int_enable
+ * dc_process_dmub_dpia_hpd_int_enable - Submits DPIA DPD interruption
*
- * @brief
- * Submits dpia hpd int enable command to dmub via inbox message
+ * @dc [in]: dc structure
+ * @hpd_int_enable [in]: 1 for hpd int enable, 0 to disable
*
- * @param
- * [in] dc: dc structure
- * [in] hpd_int_enable: 1 for hpd int enable, 0 to disable
- *
- * @return
- * None
- *****************************************************************************
+ * Submits dpia hpd int enable command to dmub via inbox message
*/
void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc,
uint32_t hpd_int_enable)
@@ -4698,16 +4937,13 @@ void dc_disable_accelerated_mode(struct dc *dc)
/**
- *****************************************************************************
- * dc_notify_vsync_int_state() - notifies vsync enable/disable state
+ * dc_notify_vsync_int_state - notifies vsync enable/disable state
* @dc: dc structure
- * @stream: stream where vsync int state changed
- * @enable: whether vsync is enabled or disabled
- *
- * Called when vsync is enabled/disabled
- * Will notify DMUB to start/stop ABM interrupts after steady state is reached
+ * @stream: stream where vsync int state changed
+ * @enable: whether vsync is enabled or disabled
*
- *****************************************************************************
+ * Called when vsync is enabled/disabled Will notify DMUB to start/stop ABM
+ * interrupts after steady state is reached.
*/
void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable)
{
@@ -4749,14 +4985,18 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause)
pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst);
}
-/*
- * dc_extended_blank_supported: Decide whether extended blank is supported
+
+/**
+ * dc_extended_blank_supported 0 Decide whether extended blank is supported
+ *
+ * @dc: [in] Current DC state
*
- * Extended blank is a freesync optimization feature to be enabled in the future.
- * During the extra vblank period gained from freesync, we have the ability to enter z9/z10.
+ * Extended blank is a freesync optimization feature to be enabled in the
+ * future. During the extra vblank period gained from freesync, we have the
+ * ability to enter z9/z10.
*
- * @param [in] dc: Current DC state
- * @return: Indicate whether extended blank is supported (true or false)
+ * Return:
+ * Indicate whether extended blank is supported (true or false)
*/
bool dc_extended_blank_supported(struct dc *dc)
{
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 7c2e3b8dc26a..471078fc3900 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -366,6 +366,7 @@ void get_hdr_visual_confirm_color(
struct tg_color *color)
{
uint32_t color_value = MAX_TG_COLOR_VALUE;
+ bool is_sdr = false;
/* Determine the overscan color based on the top-most (desktop) plane's context */
struct pipe_ctx *top_pipe_ctx = pipe_ctx;
@@ -382,7 +383,8 @@ void get_hdr_visual_confirm_color(
/* FreeSync 2 ARGB2101010 - set border color to pink */
color->color_r_cr = color_value;
color->color_b_cb = color_value;
- }
+ } else
+ is_sdr = true;
break;
case PIXEL_FORMAT_FP16:
if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) {
@@ -391,14 +393,19 @@ void get_hdr_visual_confirm_color(
} else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) {
/* FreeSync 2 HDR - set border color to green */
color->color_g_y = color_value;
- }
+ } else
+ is_sdr = true;
break;
default:
+ is_sdr = true;
+ break;
+ }
+
+ if (is_sdr) {
/* SDR - set border color to Gray */
color->color_r_cr = color_value/2;
color->color_b_cb = color_value/2;
color->color_g_y = color_value/2;
- break;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index d7b1ace6328a..342e906ae26e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -3378,7 +3378,7 @@ bool dc_link_setup_psr(struct dc_link *link,
case FAMILY_YELLOW_CARP:
case AMDGPU_FAMILY_GC_10_3_6:
case AMDGPU_FAMILY_GC_11_0_1:
- if (dc->debug.disable_z10)
+ if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
break;
default:
@@ -4229,6 +4229,7 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi
link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
+ dc->hwss.enable_audio_stream(pipe_ctx);
}
void core_link_enable_stream(
@@ -4308,10 +4309,7 @@ void core_link_enable_stream(
/* Still enable stream features & audio on seamless boot for DP external displays */
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
enable_stream_features(pipe_ctx);
- if (pipe_ctx->stream_res.audio != NULL) {
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
- dc->hwss.enable_audio_stream(pipe_ctx);
- }
+ dc->hwss.enable_audio_stream(pipe_ctx);
}
#if defined(CONFIG_DRM_AMD_DC_HDCP)
@@ -4665,6 +4663,10 @@ void dc_link_set_preferred_training_settings(struct dc *dc,
link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
}
+ if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link->type == dc_connection_mst_branch)
+ dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link);
+
/* Retrain now, or wait until next stream update to apply */
if (skip_immediate_retrain == false)
dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
index 651231387043..ce8d6a54ca54 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
@@ -82,6 +82,7 @@ struct dp_hdmi_dongle_signature_data {
#define HDMI_SCDC_STATUS_FLAGS 0x40
#define HDMI_SCDC_ERR_DETECT 0x50
#define HDMI_SCDC_TEST_CONFIG 0xC0
+#define HDMI_SCDC_DEVICE_ID 0xD3
union hdmi_scdc_update_read_data {
uint8_t byte[2];
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 1254d38f1778..dedd1246ce58 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -1912,7 +1912,7 @@ enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_train
return status;
}
-static void dpcd_exit_training_mode(struct dc_link *link)
+static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
{
uint8_t sink_status = 0;
uint8_t i;
@@ -1920,12 +1920,14 @@ static void dpcd_exit_training_mode(struct dc_link *link)
/* clear training pattern set */
dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
- /* poll for intra-hop disable */
- for (i = 0; i < 10; i++) {
- if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
- (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
- break;
- udelay(1000);
+ if (encoding == DP_128b_132b_ENCODING) {
+ /* poll for intra-hop disable */
+ for (i = 0; i < 10; i++) {
+ if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
+ (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
+ break;
+ udelay(1000);
+ }
}
}
@@ -2649,7 +2651,7 @@ enum link_training_result dc_link_dp_perform_link_training(
&lt_settings);
/* reset previous training states */
- dpcd_exit_training_mode(link);
+ dpcd_exit_training_mode(link, encoding);
/* configure link prior to entering training mode */
dpcd_configure_lttpr_mode(link, &lt_settings);
@@ -2670,7 +2672,7 @@ enum link_training_result dc_link_dp_perform_link_training(
ASSERT(0);
/* exit training mode */
- dpcd_exit_training_mode(link);
+ dpcd_exit_training_mode(link, encoding);
/* switch to video idle */
if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
@@ -2771,8 +2773,11 @@ bool perform_link_training_with_retries(
/* Update verified link settings to current one
* Because DPIA LT might fallback to lower link setting.
*/
- link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
- link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
+ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
+ link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
+ dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
+ }
}
} else {
status = dc_link_dp_perform_link_training(link,
@@ -3020,7 +3025,7 @@ static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
{
- enum dc_link_rate cable_max_link_rate = LINK_RATE_HIGH3;
+ enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN;
if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
cable_max_link_rate = LINK_RATE_UHBR20;
@@ -3083,15 +3088,29 @@ struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
max_link_cap.link_spread =
link->reported_link_cap.link_spread;
- /* Lower link settings based on cable attributes */
+ /* Lower link settings based on cable attributes
+ * Cable ID is a DP2 feature to identify max certified link rate that
+ * a cable can carry. The cable identification method requires both
+ * cable and display hardware support. Since the specs comes late, it is
+ * anticipated that the first round of DP2 cables and displays may not
+ * be fully compatible to reliably return cable ID data. Therefore the
+ * decision of our cable id policy is that if the cable can return non
+ * zero cable id data, we will take cable's link rate capability into
+ * account. However if we get zero data, the cable link rate capability
+ * is considered inconclusive. In this case, we will not take cable's
+ * capability into account to avoid of over limiting hardware capability
+ * from users. The max overall link rate capability is still determined
+ * after actual dp pre-training. Cable id is considered as an auxiliary
+ * method of determining max link bandwidth capability.
+ */
cable_max_link_rate = get_cable_max_link_rate(link);
if (!link->dc->debug.ignore_cable_id &&
+ cable_max_link_rate != LINK_RATE_UNKNOWN &&
cable_max_link_rate < max_link_cap.link_rate)
max_link_cap.link_rate = cable_max_link_rate;
- /*
- * account for lttpr repeaters cap
+ /* account for lttpr repeaters cap
* notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
*/
if (dp_is_lttpr_present(link)) {
@@ -4540,9 +4559,19 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
- pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
+ if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off
+ && pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
+ // Always use max settings here for DP 1.4a LL Compliance CTS
+ if (link->is_automated) {
+ pipe_ctx->link_config.dp_link_settings.lane_count =
+ link->verified_link_cap.lane_count;
+ pipe_ctx->link_config.dp_link_settings.link_rate =
+ link->verified_link_cap.link_rate;
+ pipe_ctx->link_config.dp_link_settings.link_spread =
+ link->verified_link_cap.link_spread;
+ }
core_link_enable_stream(link->dc->current_state, pipe_ctx);
+ }
}
}
@@ -4583,6 +4612,8 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
}
if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
+ // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
+ link->is_automated = true;
device_service_clear.bits.AUTOMATED_TEST = 1;
core_link_write_dpcd(
link,
@@ -5031,7 +5062,7 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
return true;
}
-bool dp_retrieve_lttpr_cap(struct dc_link *link)
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
{
uint8_t lttpr_dpcd_data[8];
enum dc_status status = DC_ERROR_UNEXPECTED;
@@ -5099,7 +5130,7 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
- return is_lttpr_present;
+ return status;
}
bool dp_is_lttpr_present(struct dc_link *link)
@@ -5227,76 +5258,45 @@ static void retrieve_cable_id(struct dc_link *link)
&link->dpcd_caps.cable_id, &usbc_cable_id);
}
-/* DPRX may take some time to respond to AUX messages after HPD asserted.
- * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600).
- */
-static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms)
+static enum dc_status wake_up_aux_channel(struct dc_link *link)
{
enum dc_status status = DC_ERROR_UNEXPECTED;
- uint8_t dpcd_data = 0;
- uint64_t start_ts = 0;
- uint64_t current_ts = 0;
- uint64_t time_taken_ms = 0;
- enum dc_connection_type type = dc_connection_none;
- bool lttpr_present;
- bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
+ uint32_t aux_channel_retry_cnt = 0;
+ uint8_t dpcd_power_state = '\0';
- lttpr_present = dp_is_lttpr_present(link) ||
- (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support);
- DC_LOG_DC("lttpr_present = %d.\n", lttpr_present ? 1 : 0);
+ while (status != DC_OK && aux_channel_retry_cnt < 10) {
+ status = core_link_read_dpcd(link, DP_SET_POWER,
+ &dpcd_power_state, sizeof(dpcd_power_state));
- /* Issue an AUX read to test DPRX responsiveness. If LTTPR is supported the first read is expected to
- * be to determine LTTPR capabilities. Otherwise trying to read power state should be an innocuous AUX read.
- */
- if (lttpr_present)
- status = core_link_read_dpcd(
- link,
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
- &dpcd_data,
- sizeof(dpcd_data));
- else
- status = core_link_read_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_data,
- sizeof(dpcd_data));
+ /* Delay 1 ms if AUX CH is in power down state. Based on spec
+ * section 2.3.1.2, if AUX CH may be powered down due to
+ * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
+ * signal and may need up to 1 ms before being able to reply.
+ */
+ if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
+ udelay(1000);
+ aux_channel_retry_cnt++;
+ }
+ }
if (status != DC_OK) {
- DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.",
- __func__,
- timeout_ms);
- start_ts = dm_get_timestamp(link->ctx);
-
- do {
- if (!dc_link_detect_sink(link, &type) || type == dc_connection_none)
- break;
-
- dpcd_data = DP_SET_POWER_D3;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_data,
- sizeof(dpcd_data));
-
- dpcd_data = DP_SET_POWER_D0;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_data,
- sizeof(dpcd_data));
-
- current_ts = dm_get_timestamp(link->ctx);
- time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000);
- } while (status != DC_OK && time_taken_ms < timeout_ms);
+ dpcd_power_state = DP_SET_POWER_D0;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_power_state,
+ sizeof(dpcd_power_state));
- DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s",
- __func__,
- (status == DC_OK) ? "succeeded" : "failed",
- time_taken_ms,
- (type == dc_connection_none) ? ". Unplugged." : ".");
+ dpcd_power_state = DP_SET_POWER_D3;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_power_state,
+ sizeof(dpcd_power_state));
+ return DC_ERROR_UNEXPECTED;
}
- return status;
+ return DC_OK;
}
static bool retrieve_link_cap(struct dc_link *link)
@@ -5308,7 +5308,6 @@ static bool retrieve_link_cap(struct dc_link *link)
/*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
*/
uint8_t dpcd_dprx_data = '\0';
- uint8_t dpcd_power_state = '\0';
struct dp_device_vendor_id sink_id;
union down_stream_port_count down_strm_port_count;
@@ -5316,11 +5315,9 @@ static bool retrieve_link_cap(struct dc_link *link)
union dp_downstream_port_present ds_port = { 0 };
enum dc_status status = DC_ERROR_UNEXPECTED;
uint32_t read_dpcd_retry_cnt = 3;
- uint32_t aux_channel_retry_cnt = 0;
int i;
struct dp_sink_hw_fw_revision dp_hw_fw_revision;
const uint32_t post_oui_delay = 30; // 30ms
- bool is_lttpr_present = false;
memset(dpcd_data, '\0', sizeof(dpcd_data));
memset(&down_strm_port_count,
@@ -5335,51 +5332,17 @@ static bool retrieve_link_cap(struct dc_link *link)
dc_link_aux_try_to_configure_timeout(link->ddc,
LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
- /* Try to ensure AUX channel active before proceeding. */
- if (link->dc->debug.aux_wake_wa.bits.enable_wa) {
- uint64_t timeout_ms = link->dc->debug.aux_wake_wa.bits.timeout_ms;
+ status = dp_retrieve_lttpr_cap(link);
- if (link->dc->debug.aux_wake_wa.bits.use_default_timeout)
- timeout_ms = LINK_AUX_WAKE_TIMEOUT_MS;
- status = wa_try_to_wake_dprx(link, timeout_ms);
- }
-
- while (status != DC_OK && aux_channel_retry_cnt < 10) {
- status = core_link_read_dpcd(link, DP_SET_POWER,
- &dpcd_power_state, sizeof(dpcd_power_state));
-
- /* Delay 1 ms if AUX CH is in power down state. Based on spec
- * section 2.3.1.2, if AUX CH may be powered down due to
- * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
- * signal and may need up to 1 ms before being able to reply.
- */
- if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
- udelay(1000);
- aux_channel_retry_cnt++;
- }
- }
-
- /* If aux channel is not active, return false and trigger another detect*/
if (status != DC_OK) {
- dpcd_power_state = DP_SET_POWER_D0;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_power_state,
- sizeof(dpcd_power_state));
-
- dpcd_power_state = DP_SET_POWER_D3;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_power_state,
- sizeof(dpcd_power_state));
- return false;
+ status = wake_up_aux_channel(link);
+ if (status == DC_OK)
+ dp_retrieve_lttpr_cap(link);
+ else
+ return false;
}
- is_lttpr_present = dp_retrieve_lttpr_cap(link);
-
- if (is_lttpr_present)
+ if (dp_is_lttpr_present(link))
configure_lttpr_mode_transparent(link);
/* Read DP tunneling information. */
@@ -5406,7 +5369,7 @@ static bool retrieve_link_cap(struct dc_link *link)
return false;
}
- if (!is_lttpr_present)
+ if (!dp_is_lttpr_present(link))
dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
{
@@ -7294,6 +7257,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
struct pipe_ctx *pipes =
&link->dc->current_state->res_ctx.pipe_ctx[0];
unsigned int i;
+ bool do_fallback = false;
for (i = 0; i < MAX_PIPES; i++) {
@@ -7326,32 +7290,23 @@ void dp_retrain_link_dp_test(struct dc_link *link,
memset(&link->cur_link_settings, 0,
sizeof(link->cur_link_settings));
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ do_fallback = true;
+
perform_link_training_with_retries(
link_setting,
skip_video_pattern,
LINK_TRAINING_ATTEMPTS,
&pipes[i],
SIGNAL_TYPE_DISPLAY_PORT,
- false);
+ do_fallback);
link->dc->hwss.enable_stream(&pipes[i]);
link->dc->hwss.unblank_stream(&pipes[i],
link_setting);
- if (pipes[i].stream_res.audio) {
- /* notify audio driver for
- * audio modes of monitor */
- pipes[i].stream_res.audio->funcs->az_enable(
- pipes[i].stream_res.audio);
-
- /* un-mute audio */
- /* TODO: audio should be per stream rather than
- * per link */
- pipes[i].stream_res.stream_enc->funcs->
- audio_mute_control(
- pipes[i].stream_res.stream_enc, false);
- }
+ link->dc->hwss.enable_audio_stream(&pipes[i]);
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
index 74e36b34d3f7..d130d58ac08e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
@@ -791,10 +791,14 @@ static enum link_training_result dpia_training_eq_transparent(
}
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
- dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
- dp_is_interlane_aligned(dpcd_lane_status_updated)) {
- result = LINK_TRAINING_SUCCESS;
- break;
+ dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status)) {
+ /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
+ * has to share encoders unlike DP and USBC
+ */
+ if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) {
+ result = LINK_TRAINING_SUCCESS;
+ break;
+ }
}
/* Update VS/PE. */
@@ -1008,7 +1012,8 @@ enum link_training_result dc_link_dpia_perform_link_training(
*/
if (result == LINK_TRAINING_SUCCESS) {
msleep(5);
- result = dp_check_link_loss_status(link, &lt_settings);
+ if (!link->is_automated)
+ result = dp_check_link_loss_status(link, &lt_settings);
} else if (result == LINK_TRAINING_ABORT) {
dpia_training_abort(link, &lt_settings, repeater_id);
} else {
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index fd8db482e56f..da164685547d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -1768,6 +1768,17 @@ bool dc_remove_plane_from_context(
return true;
}
+/**
+ * dc_rem_all_planes_for_stream - Remove planes attached to the target stream.
+ *
+ * @dc: Current dc state.
+ * @stream: Target stream, which we want to remove the attached plans.
+ * @context: New context.
+ *
+ * Return:
+ * Return true if DC was able to remove all planes from the target
+ * stream, otherwise, return false.
+ */
bool dc_rem_all_planes_for_stream(
const struct dc *dc,
struct dc_stream_state *stream,
@@ -2562,9 +2573,12 @@ enum dc_status resource_map_pool_resources(
/**
* dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
- * Is a shallow copy. Increments refcounts on existing streams and planes.
+ *
* @dc: copy out of dc->current_state
* @dst_ctx: copy into this
+ *
+ * This function makes a shallow copy of the current DC state and increments
+ * refcounts on existing streams and planes.
*/
void dc_resource_state_copy_construct_current(
const struct dc *dc,
@@ -2593,15 +2607,241 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
return dc->res_pool->res_cap->num_dsc > 0;
}
+static bool planes_changed_for_existing_stream(struct dc_state *context,
+ struct dc_stream_state *stream,
+ const struct dc_validation_set set[],
+ int set_count)
+{
+ int i, j;
+ struct dc_stream_status *stream_status = NULL;
+
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->streams[i] == stream) {
+ stream_status = &context->stream_status[i];
+ break;
+ }
+ }
+
+ if (!stream_status)
+ ASSERT(0);
+
+ for (i = 0; i < set_count; i++)
+ if (set[i].stream == stream)
+ break;
+
+ if (i == set_count)
+ ASSERT(0);
+
+ if (set[i].plane_count != stream_status->plane_count)
+ return true;
+
+ for (j = 0; j < set[i].plane_count; j++)
+ if (set[i].plane_states[j] != stream_status->plane_states[j])
+ return true;
+
+ return false;
+}
/**
- * dc_validate_global_state() - Determine if HW can support a given state
- * Checks HW resource availability and bandwidth requirement.
+ * dc_validate_with_context - Validate and update the potential new stream in the context object
+ *
+ * @dc: Used to get the current state status
+ * @set: An array of dc_validation_set with all the current streams reference
+ * @set_count: Total of streams
+ * @context: New context
+ * @fast_validate: Enable or disable fast validation
+ *
+ * This function updates the potential new stream in the context object. It
+ * creates multiple lists for the add, remove, and unchanged streams. In
+ * particular, if the unchanged streams have a plane that changed, it is
+ * necessary to remove all planes from the unchanged streams. In summary, this
+ * function is responsible for validating the new context.
+ *
+ * Return:
+ * In case of success, return DC_OK (1), otherwise, return a DC error.
+ */
+enum dc_status dc_validate_with_context(struct dc *dc,
+ const struct dc_validation_set set[],
+ int set_count,
+ struct dc_state *context,
+ bool fast_validate)
+{
+ struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
+ struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
+ struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
+ int old_stream_count = context->stream_count;
+ enum dc_status res = DC_ERROR_UNEXPECTED;
+ int unchanged_streams_count = 0;
+ int del_streams_count = 0;
+ int add_streams_count = 0;
+ bool found = false;
+ int i, j, k;
+
+ DC_LOGGER_INIT(dc->ctx->logger);
+
+ /* First build a list of streams to be remove from current context */
+ for (i = 0; i < old_stream_count; i++) {
+ struct dc_stream_state *stream = context->streams[i];
+
+ for (j = 0; j < set_count; j++) {
+ if (stream == set[j].stream) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ del_streams[del_streams_count++] = stream;
+
+ found = false;
+ }
+
+ /* Second, build a list of new streams */
+ for (i = 0; i < set_count; i++) {
+ struct dc_stream_state *stream = set[i].stream;
+
+ for (j = 0; j < old_stream_count; j++) {
+ if (stream == context->streams[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ add_streams[add_streams_count++] = stream;
+
+ found = false;
+ }
+
+ /* Build a list of unchanged streams which is necessary for handling
+ * planes change such as added, removed, and updated.
+ */
+ for (i = 0; i < set_count; i++) {
+ /* Check if stream is part of the delete list */
+ for (j = 0; j < del_streams_count; j++) {
+ if (set[i].stream == del_streams[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Check if stream is part of the add list */
+ for (j = 0; j < add_streams_count; j++) {
+ if (set[i].stream == add_streams[j]) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ unchanged_streams[unchanged_streams_count++] = set[i].stream;
+
+ found = false;
+ }
+
+ /* Remove all planes for unchanged streams if planes changed */
+ for (i = 0; i < unchanged_streams_count; i++) {
+ if (planes_changed_for_existing_stream(context,
+ unchanged_streams[i],
+ set,
+ set_count)) {
+ if (!dc_rem_all_planes_for_stream(dc,
+ unchanged_streams[i],
+ context)) {
+ res = DC_FAIL_DETACH_SURFACES;
+ goto fail;
+ }
+ }
+ }
+
+ /* Remove all planes for removed streams and then remove the streams */
+ for (i = 0; i < del_streams_count; i++) {
+ /* Need to cpy the dwb data from the old stream in order to efc to work */
+ if (del_streams[i]->num_wb_info > 0) {
+ for (j = 0; j < add_streams_count; j++) {
+ if (del_streams[i]->sink == add_streams[j]->sink) {
+ add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
+ for (k = 0; k < del_streams[i]->num_wb_info; k++)
+ add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
+ }
+ }
+ }
+
+ if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
+ res = DC_FAIL_DETACH_SURFACES;
+ goto fail;
+ }
+
+ res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
+ if (res != DC_OK)
+ goto fail;
+ }
+
+ /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
+ * matches. This may change in the future if seamless_boot_stream can be
+ * multiple.
+ */
+ for (i = 0; i < add_streams_count; i++) {
+ mark_seamless_boot_stream(dc, add_streams[i]);
+ if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
+ struct dc_stream_state *temp = add_streams[0];
+
+ add_streams[0] = add_streams[i];
+ add_streams[i] = temp;
+ break;
+ }
+ }
+
+ /* Add new streams and then add all planes for the new stream */
+ for (i = 0; i < add_streams_count; i++) {
+ calculate_phy_pix_clks(add_streams[i]);
+ res = dc_add_stream_to_ctx(dc, context, add_streams[i]);
+ if (res != DC_OK)
+ goto fail;
+
+ if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
+ res = DC_FAIL_ATTACH_SURFACES;
+ goto fail;
+ }
+ }
+
+ /* Add all planes for unchanged streams if planes changed */
+ for (i = 0; i < unchanged_streams_count; i++) {
+ if (planes_changed_for_existing_stream(context,
+ unchanged_streams[i],
+ set,
+ set_count)) {
+ if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
+ res = DC_FAIL_ATTACH_SURFACES;
+ goto fail;
+ }
+ }
+ }
+
+ res = dc_validate_global_state(dc, context, fast_validate);
+
+fail:
+ if (res != DC_OK)
+ DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
+ __func__,
+ res);
+
+ return res;
+}
+
+/**
+ * dc_validate_global_state() - Determine if hardware can support a given state
+ *
* @dc: dc struct for this driver
* @new_ctx: state to be validated
* @fast_validate: set to true if only yes/no to support matters
*
- * Return: DC_OK if the result can be programmed. Otherwise, an error code.
+ * Checks hardware resource availability and bandwidth requirement.
+ *
+ * Return:
+ * DC_OK if the result can be programmed. Otherwise, an error code.
*/
enum dc_status dc_validate_global_state(
struct dc *dc,
@@ -2789,6 +3029,12 @@ static void set_avi_info_frame(
hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
}
+ if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
+ stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) {
+ hdmi_info.bits.EC0_EC2 = 0;
+ hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
+ }
+
/* TODO: un-hardcode aspect ratio */
aspect = stream->timing.aspect_ratio;
@@ -3734,4 +3980,4 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
}
return true;
-} \ No newline at end of file
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 38d71b5c1f2d..20e534f73513 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -332,9 +332,21 @@ bool dc_stream_set_cursor_attributes(
dc = stream->ctx->dc;
- if (dc->debug.allow_sw_cursor_fallback && attributes->height * attributes->width * 4 > 16384)
- if (stream->mall_stream_config.type == SUBVP_MAIN)
+ /* SubVP is not compatible with HW cursor larger than 64 x 64 x 4.
+ * Therefore, if cursor is greater than 64 x 64 x 4, fallback to SW cursor in the following case:
+ * 1. For single display cases, if resolution is >= 5K and refresh rate < 120hz
+ * 2. For multi display cases, if resolution is >= 4K and refresh rate < 120hz
+ *
+ * [< 120hz is a requirement for SubVP configs]
+ */
+ if (dc->debug.allow_sw_cursor_fallback && attributes->height * attributes->width * 4 > 16384) {
+ if (dc->current_state->stream_count == 1 && stream->timing.v_addressable >= 2880 &&
+ ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
return false;
+ else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 2160 &&
+ ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
+ return false;
+ }
stream->cursor_attributes = *attributes;
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 737b221ca689..85ebeaa2de18 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -47,7 +47,7 @@ struct aux_payload;
struct set_config_cmd_payload;
struct dmub_notification;
-#define DC_VER "3.2.207"
+#define DC_VER "3.2.215"
#define MAX_SURFACES 3
#define MAX_PLANES 6
@@ -56,9 +56,7 @@ struct dmub_notification;
#define MIN_VIEWPORT_SIZE 12
#define MAX_NUM_EDP 2
-/*******************************************************************************
- * Display Core Interfaces
- ******************************************************************************/
+/* Display Core Interfaces */
struct dc_versions {
const char *dc_ver;
struct dmcu_version dmcu_version;
@@ -263,11 +261,13 @@ struct dc_caps {
uint32_t cache_line_size;
uint32_t cache_num_ways;
uint16_t subvp_fw_processing_delay_us;
+ uint8_t subvp_drr_max_vblank_margin_us;
uint16_t subvp_prefetch_end_to_mall_start_us;
uint8_t subvp_swath_height_margin_lines; // subvp start line must be aligned to 2 x swath height
uint16_t subvp_pstate_allow_width_us;
uint16_t subvp_vertical_int_margin_us;
bool seamless_odm;
+ uint8_t subvp_drr_vblank_start_margin_us;
};
struct dc_bug_wa {
@@ -395,6 +395,7 @@ struct dc_config {
bool disable_dmcu;
bool enable_4to1MPC;
bool enable_windowed_mpo_odm;
+ bool forceHBR2CP2520; // Used for switching between test patterns TPS4 and CP2520
uint32_t allow_edp_hotplug_detection;
bool clamp_min_dcfclk;
uint64_t vblank_alignment_dto_params;
@@ -408,6 +409,7 @@ struct dc_config {
bool use_default_clock_table;
bool force_bios_enable_lttpr;
uint8_t force_bios_fixed_vs;
+ int sdpif_request_limit_words_per_umc;
};
@@ -457,15 +459,15 @@ enum pipe_split_policy {
MPC_SPLIT_DYNAMIC = 0,
/**
- * @MPC_SPLIT_DYNAMIC: Avoid pipe split, which means that DC will not
+ * @MPC_SPLIT_AVOID: Avoid pipe split, which means that DC will not
* try any sort of split optimization.
*/
MPC_SPLIT_AVOID = 1,
/**
- * @MPC_SPLIT_DYNAMIC: With this option, DC will only try to optimize
- * the pipe utilization when using a single display; if the user
- * connects to a second display, DC will avoid pipe split.
+ * @MPC_SPLIT_AVOID_MULT_DISP: With this option, DC will only try to
+ * optimize the pipe utilization when using a single display; if the
+ * user connects to a second display, DC will avoid pipe split.
*/
MPC_SPLIT_AVOID_MULT_DISP = 2,
};
@@ -491,12 +493,17 @@ enum dcn_pwr_state {
enum dcn_zstate_support_state {
DCN_ZSTATE_SUPPORT_UNKNOWN,
DCN_ZSTATE_SUPPORT_ALLOW,
+ DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY,
+ DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY,
DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY,
DCN_ZSTATE_SUPPORT_DISALLOW,
};
-/*
- * For any clocks that may differ per pipe
- * only the max is stored in this structure
+
+/**
+ * struct dc_clocks - DC pipe clocks
+ *
+ * For any clocks that may differ per pipe only the max is stored in this
+ * structure
*/
struct dc_clocks {
int dispclk_khz;
@@ -523,6 +530,16 @@ struct dc_clocks {
bool prev_p_state_change_support;
bool fclk_prev_p_state_change_support;
int num_ways;
+
+ /*
+ * @fw_based_mclk_switching
+ *
+ * DC has a mechanism that leverage the variable refresh rate to switch
+ * memory clock in cases that we have a large latency to achieve the
+ * memory clock change and a short vblank window. DC has some
+ * requirements to enable this feature, and this field describes if the
+ * system support or not such a feature.
+ */
bool fw_based_mclk_switching;
bool fw_based_mclk_switching_shut_down;
int prev_num_ways;
@@ -764,7 +781,6 @@ struct dc_debug_options {
bool disable_mem_low_power;
bool pstate_enabled;
bool disable_dmcu;
- bool disable_psr;
bool force_abm_enable;
bool disable_stereo_support;
bool vsr_support;
@@ -828,6 +844,7 @@ struct dc_debug_options {
int crb_alloc_policy_min_disp_count;
bool disable_z10;
bool enable_z9_disable_interface;
+ bool psr_skip_crtc_disable;
union dpia_debug_options dpia_debug;
bool disable_fixed_vs_aux_timeout_wa;
bool force_disable_subvp;
@@ -836,6 +853,7 @@ struct dc_debug_options {
unsigned int force_subvp_num_ways;
unsigned int force_mall_ss_num_ways;
bool alloc_extra_way_for_cursor;
+ uint32_t subvp_extra_lines;
bool force_usr_allow;
/* uses value at boot and disables switch */
bool disable_dtb_ref_clk_switch;
@@ -853,6 +871,7 @@ struct dc_debug_options {
bool enable_dp_dig_pixel_rate_div_policy;
enum lttpr_mode lttpr_mode_override;
unsigned int dsc_delay_factor_wa_x1000;
+ unsigned int min_prefetch_in_strobe_ns;
};
struct gpu_info_soc_bounding_box_v1_0;
@@ -989,9 +1008,7 @@ void dc_init_callbacks(struct dc *dc,
void dc_deinit_callbacks(struct dc *dc);
void dc_destroy(struct dc **dc);
-/*******************************************************************************
- * Surface Interfaces
- ******************************************************************************/
+/* Surface Interfaces */
enum {
TRANSFER_FUNC_POINTS = 1025
@@ -1270,12 +1287,23 @@ void dc_post_update_surfaces_to_stream(
#include "dc_stream.h"
-/*
- * Structure to store surface/stream associations for validation
+/**
+ * struct dc_validation_set - Struct to store surface/stream associations for validation
*/
struct dc_validation_set {
+ /**
+ * @stream: Stream state properties
+ */
struct dc_stream_state *stream;
+
+ /**
+ * @plane_state: Surface state
+ */
struct dc_plane_state *plane_states[MAX_SURFACES];
+
+ /**
+ * @plane_count: Total of active planes
+ */
uint8_t plane_count;
};
@@ -1287,6 +1315,12 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla
void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info);
+enum dc_status dc_validate_with_context(struct dc *dc,
+ const struct dc_validation_set set[],
+ int set_count,
+ struct dc_state *context,
+ bool fast_validate);
+
bool dc_set_generic_gpio_for_stereo(bool enable,
struct gpio_service *gpio_service);
@@ -1322,15 +1356,12 @@ void dc_resource_state_destruct(struct dc_state *context);
bool dc_resource_is_dsc_encoding_supported(const struct dc *dc);
-/*
- * TODO update to make it about validation sets
- * Set up streams and links associated to drive sinks
- * The streams parameter is an absolute set of all active streams.
- *
- * After this call:
- * Phy, Encoder, Timing Generator are programmed and enabled.
- * New streams are enabled with blank stream; no memory read.
- */
+enum dc_status dc_commit_streams(struct dc *dc,
+ struct dc_stream_state *streams[],
+ uint8_t stream_count);
+
+/* TODO: When the transition to the new commit sequence is done, remove this
+ * function in favor of dc_commit_streams. */
bool dc_commit_state(struct dc *dc, struct dc_state *context);
struct dc_state *dc_create_state(struct dc *dc);
@@ -1338,9 +1369,7 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx);
void dc_retain_state(struct dc_state *context);
void dc_release_state(struct dc_state *context);
-/*******************************************************************************
- * Link Interfaces
- ******************************************************************************/
+/* Link Interfaces */
struct dpcd_caps {
union dpcd_rev dpcd_rev;
@@ -1442,9 +1471,7 @@ struct hdcp_caps {
uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane);
-/*******************************************************************************
- * Sink Interfaces - A sink corresponds to a display output device
- ******************************************************************************/
+/* Sink Interfaces - A sink corresponds to a display output device */
struct dc_container_id {
// 128bit GUID in binary form
@@ -1527,9 +1554,7 @@ struct dc_cursor {
};
-/*******************************************************************************
- * Interrupt interfaces
- ******************************************************************************/
+/* Interrupt interfaces */
enum dc_irq_source dc_interrupt_to_irq_source(
struct dc *dc,
uint32_t src_id,
@@ -1541,9 +1566,7 @@ enum dc_irq_source dc_get_hpd_irq_source_at_index(
void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable);
-/*******************************************************************************
- * Power Interfaces
- ******************************************************************************/
+/* Power Interfaces */
void dc_set_power_state(
struct dc *dc,
@@ -1616,14 +1639,10 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc,
void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc,
uint32_t hpd_int_enable);
-/*******************************************************************************
- * DSC Interfaces
- ******************************************************************************/
+/* DSC Interfaces */
#include "dc_dsc.h"
-/*******************************************************************************
- * Disable acc mode Interfaces
- ******************************************************************************/
+/* Disable acc mode Interfaces */
void dc_disable_accelerated_mode(struct dc *dc);
#endif /* DC_INTERFACE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 0541e87e4f38..6ccf477d1c4d 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -423,25 +423,20 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi
#ifdef CONFIG_DRM_AMD_DC_DCN
/**
- * ***********************************************************************************************
- * populate_subvp_cmd_drr_info: Helper to populate DRR pipe info for the DMCUB subvp command
+ * populate_subvp_cmd_drr_info - Helper to populate DRR pipe info for the DMCUB subvp command
*
- * Populate the DMCUB SubVP command with DRR pipe info. All the information required for calculating
- * the SubVP + DRR microschedule is populated here.
+ * @dc: [in] current dc state
+ * @subvp_pipe: [in] pipe_ctx for the SubVP pipe
+ * @vblank_pipe: [in] pipe_ctx for the DRR pipe
+ * @pipe_data: [in] Pipe data which stores the VBLANK/DRR info
+ *
+ * Populate the DMCUB SubVP command with DRR pipe info. All the information
+ * required for calculating the SubVP + DRR microschedule is populated here.
*
* High level algorithm:
* 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
* 2. Calculate the min and max vtotal which supports SubVP + DRR microschedule
* 3. Populate the drr_info with the min and max supported vtotal values
- *
- * @param [in] dc: current dc state
- * @param [in] subvp_pipe: pipe_ctx for the SubVP pipe
- * @param [in] vblank_pipe: pipe_ctx for the DRR pipe
- * @param [in] pipe_data: Pipe data which stores the VBLANK/DRR info
- *
- * @return: void
- *
- * ***********************************************************************************************
*/
static void populate_subvp_cmd_drr_info(struct dc *dc,
struct pipe_ctx *subvp_pipe,
@@ -482,33 +477,38 @@ static void populate_subvp_cmd_drr_info(struct dc *dc,
(((uint64_t)main_timing->pix_clk_100hz * 100)));
drr_active_us = div64_u64(((uint64_t)drr_timing->v_addressable * drr_timing->h_total * 1000000),
(((uint64_t)drr_timing->pix_clk_100hz * 100)));
- max_drr_vblank_us = div64_u64((subvp_active_us - prefetch_us - drr_active_us), 2) + drr_active_us;
- max_drr_mallregion_us = subvp_active_us - prefetch_us - mall_region_us;
+ max_drr_vblank_us = div64_u64((subvp_active_us - prefetch_us -
+ dc->caps.subvp_fw_processing_delay_us - drr_active_us), 2) + drr_active_us;
+ max_drr_mallregion_us = subvp_active_us - prefetch_us - mall_region_us - dc->caps.subvp_fw_processing_delay_us;
max_drr_supported_us = max_drr_vblank_us > max_drr_mallregion_us ? max_drr_vblank_us : max_drr_mallregion_us;
max_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * max_drr_supported_us),
(((uint64_t)drr_timing->h_total * 1000000)));
+ /* When calculating the max vtotal supported for SubVP + DRR cases, add
+ * margin due to possible rounding errors (being off by 1 line in the
+ * FW calculation can incorrectly push the P-State switch to wait 1 frame
+ * longer).
+ */
+ max_vtotal_supported = max_vtotal_supported - dc->caps.subvp_drr_max_vblank_margin_us;
+
pipe_data->pipe_config.vblank_data.drr_info.min_vtotal_supported = min_vtotal_supported;
pipe_data->pipe_config.vblank_data.drr_info.max_vtotal_supported = max_vtotal_supported;
+ pipe_data->pipe_config.vblank_data.drr_info.drr_vblank_start_margin = dc->caps.subvp_drr_vblank_start_margin_us;
}
/**
- * ***********************************************************************************************
- * populate_subvp_cmd_vblank_pipe_info: Helper to populate VBLANK pipe info for the DMUB subvp command
- *
- * Populate the DMCUB SubVP command with VBLANK pipe info. All the information required to calculate
- * the microschedule for SubVP + VBLANK case is stored in the pipe_data (subvp_data and vblank_data).
- * Also check if the VBLANK pipe is a DRR display -- if it is make a call to populate drr_info.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] cmd: DMUB cmd to be populated with SubVP info
- * @param [in] vblank_pipe: pipe_ctx for the VBLANK pipe
- * @param [in] cmd_pipe_index: index for the pipe array in DMCUB SubVP cmd
+ * populate_subvp_cmd_vblank_pipe_info - Helper to populate VBLANK pipe info for the DMUB subvp command
*
- * @return: void
+ * @dc: [in] current dc state
+ * @context: [in] new dc state
+ * @cmd: [in] DMUB cmd to be populated with SubVP info
+ * @vblank_pipe: [in] pipe_ctx for the VBLANK pipe
+ * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd
*
- * ***********************************************************************************************
+ * Populate the DMCUB SubVP command with VBLANK pipe info. All the information
+ * required to calculate the microschedule for SubVP + VBLANK case is stored in
+ * the pipe_data (subvp_data and vblank_data). Also check if the VBLANK pipe
+ * is a DRR display -- if it is make a call to populate drr_info.
*/
static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
struct dc_state *context,
@@ -551,22 +551,18 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
}
/**
- * ***********************************************************************************************
- * update_subvp_prefetch_end_to_mall_start: Helper for SubVP + SubVP case
+ * update_subvp_prefetch_end_to_mall_start - Helper for SubVP + SubVP case
*
- * For SubVP + SubVP, we use a single vertical interrupt to start the microschedule for both
- * SubVP pipes. In order for this to work correctly, the MALL REGION of both SubVP pipes must
- * start at the same time. This function lengthens the prefetch end to mall start delay of the
- * SubVP pipe that has the shorter prefetch so that both MALL REGION's will start at the same time.
+ * @dc: [in] current dc state
+ * @context: [in] new dc state
+ * @cmd: [in] DMUB cmd to be populated with SubVP info
+ * @subvp_pipes: [in] Array of SubVP pipes (should always be length 2)
*
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] cmd: DMUB cmd to be populated with SubVP info
- * @param [in] subvp_pipes: Array of SubVP pipes (should always be length 2)
- *
- * @return: void
- *
- * ***********************************************************************************************
+ * For SubVP + SubVP, we use a single vertical interrupt to start the
+ * microschedule for both SubVP pipes. In order for this to work correctly, the
+ * MALL REGION of both SubVP pipes must start at the same time. This function
+ * lengthens the prefetch end to mall start delay of the SubVP pipe that has
+ * the shorter prefetch so that both MALL REGION's will start at the same time.
*/
static void update_subvp_prefetch_end_to_mall_start(struct dc *dc,
struct dc_state *context,
@@ -608,22 +604,17 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc,
}
/**
- * ***************************************************************************************
- * setup_subvp_dmub_command: Helper to populate the SubVP pipe info for the DMUB subvp command
- *
- * Populate the DMCUB SubVP command with SubVP pipe info. All the information required to
- * calculate the microschedule for the SubVP pipe is stored in the pipe_data of the DMCUB
- * SubVP command.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] cmd: DMUB cmd to be populated with SubVP info
- * @param [in] subvp_pipe: pipe_ctx for the SubVP pipe
- * @param [in] cmd_pipe_index: index for the pipe array in DMCUB SubVP cmd
+ * populate_subvp_cmd_pipe_info - Helper to populate the SubVP pipe info for the DMUB subvp command
*
- * @return: void
+ * @dc: [in] current dc state
+ * @context: [in] new dc state
+ * @cmd: [in] DMUB cmd to be populated with SubVP info
+ * @subvp_pipe: [in] pipe_ctx for the SubVP pipe
+ * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd
*
- * ***************************************************************************************
+ * Populate the DMCUB SubVP command with SubVP pipe info. All the information
+ * required to calculate the microschedule for the SubVP pipe is stored in the
+ * pipe_data of the DMCUB SubVP command.
*/
static void populate_subvp_cmd_pipe_info(struct dc *dc,
struct dc_state *context,
@@ -703,19 +694,14 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
}
/**
- * ***************************************************************************************
- * dc_dmub_setup_subvp_dmub_command: Populate the DMCUB SubVP command
+ * dc_dmub_setup_subvp_dmub_command - Populate the DMCUB SubVP command
*
- * This function loops through each pipe and populates the DMUB
- * SubVP CMD info based on the pipe (e.g. SubVP, VBLANK).
+ * @dc: [in] current dc state
+ * @context: [in] new dc state
+ * @cmd: [in] DMUB cmd to be populated with SubVP info
*
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] cmd: DMUB cmd to be populated with SubVP info
- *
- * @return: void
- *
- * ***************************************************************************************
+ * This function loops through each pipe and populates the DMUB SubVP CMD info
+ * based on the pipe (e.g. SubVP, VBLANK).
*/
void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
struct dc_state *context,
@@ -882,11 +868,59 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
diag_data.is_cw6_enabled);
}
+static bool dc_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+{
+ struct pipe_ctx *test_pipe, *split_pipe;
+ const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
+ struct rect r1 = scl_data->recout, r2, r2_half;
+ int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
+ int cur_layer = pipe_ctx->plane_state->layer_index;
+
+ /**
+ * Disable the cursor if there's another pipe above this with a
+ * plane that contains this pipe's viewport to prevent double cursor
+ * and incorrect scaling artifacts.
+ */
+ for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+ test_pipe = test_pipe->top_pipe) {
+ // Skip invisible layer and pipe-split plane on same layer
+ if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer)
+ continue;
+
+ r2 = test_pipe->plane_res.scl_data.recout;
+ r2_r = r2.x + r2.width;
+ r2_b = r2.y + r2.height;
+ split_pipe = test_pipe;
+
+ /**
+ * There is another half plane on same layer because of
+ * pipe-split, merge together per same height.
+ */
+ for (split_pipe = pipe_ctx->top_pipe; split_pipe;
+ split_pipe = split_pipe->top_pipe)
+ if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
+ r2_half = split_pipe->plane_res.scl_data.recout;
+ r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
+ r2.width = r2.width + r2_half.width;
+ r2_r = r2.x + r2.width;
+ break;
+ }
+
+ if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
+ return true;
+ }
+
+ return false;
+}
+
static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
{
if (pipe_ctx->plane_state != NULL) {
if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
return false;
+
+ if (dc_can_pipe_disable_cursor(pipe_ctx))
+ return false;
}
if ((pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1 ||
@@ -962,19 +996,14 @@ static void dc_build_cursor_attribute_update_payload1(
}
/**
- * ***************************************************************************************
- * dc_send_update_cursor_info_to_dmu: Populate the DMCUB Cursor update info command
- *
- * This function would store the cursor related information and pass it into dmub
+ * dc_send_update_cursor_info_to_dmu - Populate the DMCUB Cursor update info command
*
- * @param [in] pCtx: pipe context
- * @param [in] pipe_idx: pipe index
+ * @pCtx: [in] pipe context
+ * @pipe_idx: [in] pipe index
*
- * @return: void
- *
- * ***************************************************************************************
+ * This function would store the cursor related information and pass it into
+ * dmub
*/
-
void dc_send_update_cursor_info_to_dmu(
struct pipe_ctx *pCtx, uint8_t pipe_idx)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index caf0c7af2d0b..2e18bcf6b11a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -117,7 +117,7 @@ struct psr_settings {
* Add a struct dc_panel_config under dc_link
*/
struct dc_panel_config {
- // extra panel power sequence parameters
+ /* extra panel power sequence parameters */
struct pps {
unsigned int extra_t3_ms;
unsigned int extra_t7_ms;
@@ -127,13 +127,21 @@ struct dc_panel_config {
unsigned int extra_t12_ms;
unsigned int extra_post_OUI_ms;
} pps;
- // ABM
+ /* PSR */
+ struct psr {
+ bool disable_psr;
+ bool disallow_psrsu;
+ bool rc_disable;
+ bool rc_allow_static_screen;
+ bool rc_allow_fullscreen_VPB;
+ } psr;
+ /* ABM */
struct varib {
unsigned int varibright_feature_enable;
unsigned int def_varibright_level;
unsigned int abm_config_setting;
} varib;
- // edp DSC
+ /* edp DSC */
struct dsc {
bool disable_dsc_edp;
unsigned int force_dsc_edp_policy;
@@ -143,6 +151,20 @@ struct dc_panel_config {
bool optimize_edp_link_rate; /* eDP ILR */
} ilr;
};
+
+/*
+ * USB4 DPIA BW ALLOCATION STRUCTS
+ */
+struct dc_dpia_bw_alloc {
+ int sink_verified_bw; // The Verified BW that sink can allocated and use that has been verified already
+ int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated
+ int padding_bw; // The Padding "Un-used" BW allocated by CM for padding reasons
+ int sink_max_bw; // The Max BW that sink can require/support
+ int estimated_bw; // The estimated available BW for this DPIA
+ int bw_granularity; // BW Granularity
+ bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3: DP-Tx & Dpia & CM
+};
+
/*
* A link contains one or more sinks and their connected status.
* The currently active signal type (HDMI, DP-SST, DP-MST) is also reported.
@@ -158,6 +180,14 @@ struct dc_link {
enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */
bool is_hpd_filter_disabled;
bool dp_ss_off;
+
+ /**
+ * @link_state_valid:
+ *
+ * If there is no link and local sink, this variable should be set to
+ * false. Otherwise, it should be set to true; usually, the function
+ * core_link_enable_stream sets this field to true.
+ */
bool link_state_valid;
bool aux_access_disabled;
bool sync_lt_in_progress;
@@ -168,6 +198,7 @@ struct dc_link {
bool is_dig_mapping_flexible;
bool hpd_status; /* HPD status of link without physical HPD pin. */
bool is_hpd_pending; /* Indicates a new received hpd */
+ bool is_automated; /* Indicates automated testing */
bool edp_sink_present;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 9e6025c98db9..dfd3df1d2f7e 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -41,6 +41,10 @@ struct timing_sync_info {
struct dc_stream_status {
int primary_otg_inst;
int stream_enc_inst;
+
+ /**
+ * @plane_count: Total of planes attached to a single stream
+ */
int plane_count;
int audio_inst;
struct timing_sync_info timing_sync_info;
@@ -140,7 +144,7 @@ struct test_pattern {
unsigned int cust_pattern_size;
};
-#define SUBVP_DRR_MARGIN_US 500 // 500us for DRR margin (SubVP + DRR)
+#define SUBVP_DRR_MARGIN_US 600 // 600us for DRR margin (SubVP + DRR)
enum mall_stream_type {
SUBVP_NONE, // subvp not in use
@@ -156,6 +160,17 @@ struct mall_stream_config {
struct dc_stream_state *paired_stream; // master / slave stream
};
+/* Temp struct used to save and restore MALL config
+ * during validation.
+ *
+ * TODO: Move MALL config into dc_state instead of stream struct
+ * to avoid needing to save/restore.
+ */
+struct mall_temp_config {
+ struct mall_stream_config mall_stream_config[MAX_PIPES];
+ bool is_phantom_plane[MAX_PIPES];
+};
+
struct dc_stream_state {
// sink is deprecated, new code should not reference
// this pointer
@@ -197,7 +212,18 @@ struct dc_stream_state {
bool use_vsc_sdp_for_colorimetry;
bool ignore_msa_timing_param;
+ /**
+ * @allow_freesync:
+ *
+ * It say if Freesync is enabled or not.
+ */
bool allow_freesync;
+
+ /**
+ * @vrr_active_variable:
+ *
+ * It describes if VRR is in use.
+ */
bool vrr_active_variable;
bool freesync_on_desktop;
@@ -517,10 +543,10 @@ bool dc_stream_get_crtc_position(struct dc *dc,
unsigned int *nom_v_pos);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-bool dc_stream_forward_dmcu_crc_window(struct dc *dc, struct dc_stream_state *stream,
- struct crc_params *crc_window);
-bool dc_stream_stop_dmcu_crc_win_update(struct dc *dc,
- struct dc_stream_state *stream);
+bool dc_stream_forward_crc_window(struct dc *dc,
+ struct rect *rect,
+ struct dc_stream_state *stream,
+ bool is_stop);
#endif
bool dc_stream_configure_crc(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_trace.h b/drivers/gpu/drm/amd/display/dc/dc_trace.h
index c711797e5c9e..bbec308a3a5e 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_trace.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_trace.h
@@ -40,3 +40,5 @@
#define TRACE_DCN_FPU(begin, function, line, ref_count) \
trace_dcn_fpu(begin, function, line, ref_count)
+#define TRACE_OPTC_LOCK_UNLOCK_STATE(optc, inst, lock) \
+ trace_dcn_optc_lock_unlock_state(optc, inst, lock, __func__, __LINE__)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index ad9041472cca..dc78e2404b48 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -993,4 +993,11 @@ struct display_endpoint_id {
enum display_endpoint_type ep_type;
};
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+struct otg_phy_mux {
+ uint8_t phy_output_num;
+ uint8_t otg_output_num;
+};
+#endif
+
#endif /* DC_TYPES_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
index fbb19e253f50..d3cc5ec46956 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -927,19 +927,20 @@ static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
static void dcn10_forward_crc_window(struct dmcu *dmcu,
- struct crc_region *crc_win,
+ struct rect *rect,
struct otg_phy_mux *mux_mapping)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
unsigned int dmcu_wait_reg_ready_interval = 100;
unsigned int crc_start = 0, crc_end = 0, otg_phy_mux = 0;
+ int x_start, y_start, x_end, y_end;
/* If microcontroller is not running, do nothing */
if (dmcu->dmcu_state != DMCU_RUNNING)
return;
- if (!crc_win)
+ if (!rect)
return;
/* waitDMCUReadyForCmd */
@@ -947,9 +948,14 @@ static void dcn10_forward_crc_window(struct dmcu *dmcu,
dmcu_wait_reg_ready_interval,
dmcu_max_retry_on_wait_reg_ready);
+ x_start = rect->x;
+ y_start = rect->y;
+ x_end = x_start + rect->width;
+ y_end = y_start + rect->height;
+
/* build up nitification data */
- crc_start = (((unsigned int) crc_win->x_start) << 16) | crc_win->y_start;
- crc_end = (((unsigned int) crc_win->x_end) << 16) | crc_win->y_end;
+ crc_start = (((unsigned int) x_start) << 16) | y_start;
+ crc_end = (((unsigned int) x_end) << 16) | y_end;
otg_phy_mux =
(((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
index bec5e9f787fc..2d3201b77d6a 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
@@ -399,7 +399,11 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
link->psr_settings.force_ffu_mode = 0;
copy_settings_data->force_ffu_mode = link->psr_settings.force_ffu_mode;
- if (link->fec_state == dc_link_fec_enabled &&
+ if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
+ !link->dc->debug.disable_fec) &&
+ (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
+ !link->panel_config.dsc.disable_dsc_edp &&
+ link->dc->caps.edp_dsc_support)) &&
link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 &&
(!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1,
sizeof(DP_SINK_DEVICE_STR_ID_1)) ||
@@ -409,6 +413,11 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
else
copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 0;
+ //WA for PSR1 on specific TCON, require frame delay for frame re-lock
+ copy_settings_data->relock_delay_frame_cnt = 0;
+ if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
+ copy_settings_data->relock_delay_frame_cnt = 2;
+
dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
dc_dmub_srv_cmd_execute(dc->dmub_srv);
dc_dmub_srv_wait_idle(dc->dmub_srv);
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index d260eaa1509e..913a1fe6b3da 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -688,16 +688,6 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
early_control = lane_count;
tg->funcs->set_early_control(tg, early_control);
-
- /* enable audio only within mode set */
- if (pipe_ctx->stream_res.audio != NULL) {
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
- }
-
-
-
-
}
static enum bp_result link_transmitter_control(
@@ -1081,12 +1071,14 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
struct dc *dc;
struct clk_mgr *clk_mgr;
unsigned int i, num_audio = 1;
+ const struct link_hwss *link_hwss;
if (!pipe_ctx->stream)
return;
dc = pipe_ctx->stream->ctx->dc;
clk_mgr = dc->clk_mgr;
+ link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res);
if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true)
return;
@@ -1103,56 +1095,35 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa)
/*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
clk_mgr->funcs->enable_pme_wa(clk_mgr);
- /* un-mute audio */
- /* TODO: audio should be per stream rather than per link */
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.hpo_dp_stream_enc, false);
- else
- pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.stream_enc, false);
+
+ link_hwss->enable_audio_packet(pipe_ctx);
+
if (pipe_ctx->stream_res.audio)
pipe_ctx->stream_res.audio->enabled = true;
}
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
}
void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
{
struct dc *dc;
struct clk_mgr *clk_mgr;
+ const struct link_hwss *link_hwss;
if (!pipe_ctx || !pipe_ctx->stream)
return;
dc = pipe_ctx->stream->ctx->dc;
clk_mgr = dc->clk_mgr;
+ link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res);
if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
return;
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.hpo_dp_stream_enc, true);
- else
- pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.stream_enc, true);
+ link_hwss->disable_audio_packet(pipe_ctx);
+
if (pipe_ctx->stream_res.audio) {
pipe_ctx->stream_res.audio->enabled = false;
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
- pipe_ctx->stream_res.hpo_dp_stream_enc);
- else
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
- pipe_ctx->stream_res.stream_enc);
- else
- pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
- pipe_ctx->stream_res.stream_enc);
-
if (clk_mgr->funcs->enable_pme_wa)
/*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
clk_mgr->funcs->enable_pme_wa(clk_mgr);
@@ -1163,9 +1134,6 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
* stream->stream_engine_id);
*/
}
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
}
void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
@@ -1487,6 +1455,9 @@ static enum dc_status apply_single_controller_ctx_to_hw(
unsigned int event_triggers = 0;
struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
struct dce_hwseq *hws = dc->hwseq;
+ const struct link_hwss *link_hwss = get_link_hwss(
+ link, &pipe_ctx->link_res);
+
if (hws->funcs.disable_stream_gating) {
hws->funcs.disable_stream_gating(dc, pipe_ctx);
@@ -1497,23 +1468,8 @@ static enum dc_status apply_single_controller_ctx_to_hw(
build_audio_output(context, pipe_ctx, &audio_output);
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- pipe_ctx->stream_res.audio->inst,
- &pipe_ctx->stream->audio_info);
- else
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.audio->inst,
- &pipe_ctx->stream->audio_info);
- else
- pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.audio->inst,
- &pipe_ctx->stream->audio_info,
- &audio_output.crtc_info);
+ link_hwss->setup_audio_output(pipe_ctx, &audio_output,
+ pipe_ctx->stream_res.audio->inst);
pipe_ctx->stream_res.audio->funcs->az_configure(
pipe_ctx->stream_res.audio,
@@ -1605,8 +1561,13 @@ static enum dc_status apply_single_controller_ctx_to_hw(
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
- pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
-
+ /* Phantom and main stream share the same link (because the stream
+ * is constructed with the same sink). Make sure not to override
+ * and link programming on the main.
+ */
+ if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) {
+ pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
+ }
return DC_OK;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
index 1b70b78e2fa1..af631085e88c 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -359,7 +359,8 @@ static const struct dce_audio_registers audio_regs[] = {
audio_regs(2),
audio_regs(3),
audio_regs(4),
- audio_regs(5)
+ audio_regs(5),
+ audio_regs(6),
};
#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\
diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c
index fc6aa098bda0..8db9f7514466 100644
--- a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c
@@ -1128,6 +1128,7 @@ struct resource_pool *dce60_create_resource_pool(
if (dce60_construct(num_virtual_links, dc, pool))
return &pool->base;
+ kfree(pool);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1325,6 +1326,7 @@ struct resource_pool *dce61_create_resource_pool(
if (dce61_construct(num_virtual_links, dc, pool))
return &pool->base;
+ kfree(pool);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1518,6 +1520,7 @@ struct resource_pool *dce64_create_resource_pool(
if (dce64_construct(num_virtual_links, dc, pool))
return &pool->base;
+ kfree(pool);
BREAK_TO_DEBUGGER();
return NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
index b28025960050..5825e6f412bd 100644
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
@@ -1137,6 +1137,7 @@ struct resource_pool *dce80_create_resource_pool(
if (dce80_construct(num_virtual_links, dc, pool))
return &pool->base;
+ kfree(pool);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1336,6 +1337,7 @@ struct resource_pool *dce81_create_resource_pool(
if (dce81_construct(num_virtual_links, dc, pool))
return &pool->base;
+ kfree(pool);
BREAK_TO_DEBUGGER();
return NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
index b9765b3899e1..ef52e6b6eccf 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
@@ -436,34 +436,48 @@ void dpp1_set_cursor_position(
uint32_t height)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
- int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x;
- int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y;
+ int x_pos = pos->x - param->viewport.x;
+ int y_pos = pos->y - param->viewport.y;
+ int x_hotspot = pos->x_hotspot;
+ int y_hotspot = pos->y_hotspot;
+ int src_x_offset = x_pos - pos->x_hotspot;
+ int src_y_offset = y_pos - pos->y_hotspot;
+ int cursor_height = (int)height;
+ int cursor_width = (int)width;
uint32_t cur_en = pos->enable ? 1 : 0;
- // Cursor width/height and hotspots need to be rotated for offset calculation
+ // Transform cursor width / height and hotspots for offset calculations
if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
- swap(width, height);
+ swap(cursor_height, cursor_width);
+ swap(x_hotspot, y_hotspot);
+
if (param->rotation == ROTATION_ANGLE_90) {
- src_x_offset = pos->x - pos->y_hotspot - param->viewport.x;
- src_y_offset = pos->y - pos->x_hotspot - param->viewport.y;
+ // hotspot = (-y, x)
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
+ src_y_offset = y_pos - y_hotspot;
+ } else if (param->rotation == ROTATION_ANGLE_270) {
+ // hotspot = (y, -x)
+ src_x_offset = x_pos - x_hotspot;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
} else if (param->rotation == ROTATION_ANGLE_180) {
+ // hotspot = (-x, -y)
if (!param->mirror)
- src_x_offset = pos->x - param->viewport.x;
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
- src_y_offset = pos->y - param->viewport.y;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
if (src_x_offset >= (int)param->viewport.width)
cur_en = 0; /* not visible beyond right edge*/
- if (src_x_offset + (int)width <= 0)
+ if (src_x_offset + cursor_width <= 0)
cur_en = 0; /* not visible beyond left edge*/
if (src_y_offset >= (int)param->viewport.height)
cur_en = 0; /* not visible beyond bottom edge*/
- if (src_y_offset + (int)height <= 0)
+ if (src_y_offset + cursor_height <= 0)
cur_en = 0; /* not visible beyond top edge*/
REG_UPDATE(CURSOR0_CONTROL,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
index e48fd044f572..ba1c0621f0f8 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
@@ -171,6 +171,7 @@ struct dcn_hubbub_registers {
uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B;
uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C;
uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D;
+ uint32_t SDPIF_REQUEST_RATE_LIMIT;
};
#define HUBBUB_REG_FIELD_LIST_DCN32(type) \
@@ -360,7 +361,8 @@ struct dcn_hubbub_registers {
type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C;\
type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C;\
type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D;\
- type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D
+ type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D;\
+ type SDPIF_REQUEST_RATE_LIMIT
struct dcn_hubbub_shift {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
index 52e201e9b091..a142a00bc432 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
@@ -1179,10 +1179,12 @@ void hubp1_cursor_set_position(
const struct dc_cursor_mi_param *param)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
- int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x;
- int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y;
+ int x_pos = pos->x - param->viewport.x;
+ int y_pos = pos->y - param->viewport.y;
int x_hotspot = pos->x_hotspot;
int y_hotspot = pos->y_hotspot;
+ int src_x_offset = x_pos - pos->x_hotspot;
+ int src_y_offset = y_pos - pos->y_hotspot;
int cursor_height = (int)hubp->curs_attr.height;
int cursor_width = (int)hubp->curs_attr.width;
uint32_t dst_x_offset;
@@ -1200,18 +1202,26 @@ void hubp1_cursor_set_position(
if (hubp->curs_attr.address.quad_part == 0)
return;
- // Rotated cursor width/height and hotspots tweaks for offset calculation
+ // Transform cursor width / height and hotspots for offset calculations
if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
swap(cursor_height, cursor_width);
+ swap(x_hotspot, y_hotspot);
+
if (param->rotation == ROTATION_ANGLE_90) {
- src_x_offset = pos->x - pos->y_hotspot - param->viewport.x;
- src_y_offset = pos->y - pos->x_hotspot - param->viewport.y;
+ // hotspot = (-y, x)
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
+ src_y_offset = y_pos - y_hotspot;
+ } else if (param->rotation == ROTATION_ANGLE_270) {
+ // hotspot = (y, -x)
+ src_x_offset = x_pos - x_hotspot;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
} else if (param->rotation == ROTATION_ANGLE_180) {
+ // hotspot = (-x, -y)
if (!param->mirror)
- src_x_offset = pos->x - param->viewport.x;
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
- src_y_offset = pos->y - param->viewport.y;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0;
@@ -1248,8 +1258,8 @@ void hubp1_cursor_set_position(
CURSOR_Y_POSITION, pos->y);
REG_SET_2(CURSOR_HOT_SPOT, 0,
- CURSOR_HOT_SPOT_X, x_hotspot,
- CURSOR_HOT_SPOT_Y, y_hotspot);
+ CURSOR_HOT_SPOT_X, pos->x_hotspot,
+ CURSOR_HOT_SPOT_Y, pos->y_hotspot);
REG_SET(CURSOR_DST_OFFSET, 0,
CURSOR_DST_X_OFFSET, dst_x_offset);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 11e4c4e46947..c8ec11839b4d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -97,10 +97,12 @@ void dcn10_lock_all_pipes(struct dc *dc,
bool lock)
{
struct pipe_ctx *pipe_ctx;
+ struct pipe_ctx *old_pipe_ctx;
struct timing_generator *tg;
int i;
for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
pipe_ctx = &context->res_ctx.pipe_ctx[i];
tg = pipe_ctx->stream_res.tg;
@@ -110,7 +112,7 @@ void dcn10_lock_all_pipes(struct dc *dc,
*/
if (pipe_ctx->top_pipe ||
!pipe_ctx->stream ||
- !pipe_ctx->plane_state ||
+ (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) ||
!tg->funcs->is_tg_enabled(tg))
continue;
@@ -867,6 +869,32 @@ static void false_optc_underflow_wa(
tg->funcs->clear_optc_underflow(tg);
}
+static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)
+{
+ struct pipe_ctx *other_pipe;
+ int vready_offset = pipe->pipe_dlg_param.vready_offset;
+
+ /* Always use the largest vready_offset of all connected pipes */
+ for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+
+ return vready_offset;
+}
+
enum dc_status dcn10_enable_stream_timing(
struct pipe_ctx *pipe_ctx,
struct dc_state *context,
@@ -910,7 +938,7 @@ enum dc_status dcn10_enable_stream_timing(
pipe_ctx->stream_res.tg->funcs->program_timing(
pipe_ctx->stream_res.tg,
&stream->timing,
- pipe_ctx->pipe_dlg_param.vready_offset,
+ calculate_vready_offset_for_group(pipe_ctx),
pipe_ctx->pipe_dlg_param.vstartup_start,
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width,
@@ -2188,6 +2216,12 @@ void dcn10_enable_vblanks_synchronization(
opp = grouped_pipes[i]->stream_res.opp;
tg = grouped_pipes[i]->stream_res.tg;
tg->funcs->get_otg_active_size(tg, &width, &height);
+
+ if (!tg->funcs->is_tg_enabled(tg)) {
+ DC_SYNC_INFO("Skipping timing sync on disabled OTG\n");
+ return;
+ }
+
if (opp->funcs->opp_program_dpg_dimensions)
opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
}
@@ -2250,6 +2284,12 @@ void dcn10_enable_timing_synchronization(
opp = grouped_pipes[i]->stream_res.opp;
tg = grouped_pipes[i]->stream_res.tg;
tg->funcs->get_otg_active_size(tg, &width, &height);
+
+ if (!tg->funcs->is_tg_enabled(tg)) {
+ DC_SYNC_INFO("Skipping timing sync on disabled OTG\n");
+ return;
+ }
+
if (opp->funcs->opp_program_dpg_dimensions)
opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
}
@@ -2900,7 +2940,7 @@ void dcn10_program_pipe(
pipe_ctx->stream_res.tg->funcs->program_global_sync(
pipe_ctx->stream_res.tg,
- pipe_ctx->pipe_dlg_param.vready_offset,
+ calculate_vready_offset_for_group(pipe_ctx),
pipe_ctx->pipe_dlg_param.vstartup_start,
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
index 33d780218790..c9e53dc49c92 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -27,6 +27,7 @@
#include "reg_helper.h"
#include "dcn10_optc.h"
#include "dc.h"
+#include "dc_trace.h"
#define REG(reg)\
optc1->tg_regs->reg
@@ -657,6 +658,8 @@ void optc1_lock(struct timing_generator *optc)
REG_WAIT(OTG_MASTER_UPDATE_LOCK,
UPDATE_LOCK_STATUS, 1,
1, 10);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true);
}
void optc1_unlock(struct timing_generator *optc)
@@ -665,6 +668,8 @@ void optc1_unlock(struct timing_generator *optc)
REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
OTG_MASTER_UPDATE_LOCK, 0);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, false);
}
void optc1_get_position(struct timing_generator *optc,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
index 56d30baf12df..6bfac8088ab0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
@@ -1295,47 +1295,6 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx)
return value;
}
-/*
- * Some architectures don't support soft-float (e.g. aarch64), on those
- * this function has to be called with hardfloat enabled, make sure not
- * to inline it so whatever fp stuff is done stays inside
- */
-static noinline void dcn10_resource_construct_fp(
- struct dc *dc)
-{
- if (dc->ctx->dce_version == DCN_VERSION_1_01) {
- struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc;
- struct dcn_ip_params *dcn_ip = dc->dcn_ip;
- struct display_mode_lib *dml = &dc->dml;
-
- dml->ip.max_num_dpp = 3;
- /* TODO how to handle 23.84? */
- dcn_soc->dram_clock_change_latency = 23;
- dcn_ip->max_num_dpp = 3;
- }
- if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) {
- dc->dcn_soc->urgent_latency = 3;
- dc->debug.disable_dmcu = true;
- dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f;
- }
-
-
- dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width;
- ASSERT(dc->dcn_soc->number_of_channels < 3);
- if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/
- dc->dcn_soc->number_of_channels = 2;
-
- if (dc->dcn_soc->number_of_channels == 1) {
- dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f;
- dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f;
- dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f;
- dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f;
- if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) {
- dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f;
- }
- }
-}
-
static bool verify_clock_values(struct dm_pp_clock_levels_with_voltage *clks)
{
int i;
@@ -1510,8 +1469,9 @@ static bool dcn10_resource_construct(
memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults));
memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults));
- /* Other architectures we build for build this with soft-float */
+ DC_FP_START();
dcn10_resource_construct_fp(dc);
+ DC_FP_END();
if (!dc->config.is_vmin_only_asic)
if (ASICREV_IS_RAVEN2(dc->ctx->asic_id.hw_internal_rev))
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h
index a85ed228dfc2..a9dd9ae23ec9 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h
@@ -27,204 +27,177 @@
#define TO_DCN20_DWBC(dwbc_base) \
container_of(dwbc_base, struct dcn20_dwbc, base)
-/* DCN */
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-#define BASE(seg) \
- BASE_INNER(seg)
-
-#define SR(reg_name)\
- .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
- mm ## reg_name
-
-#define SRI(reg_name, block, id)\
- .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
- mm ## block ## id ## _ ## reg_name
-
-#define SRI2(reg_name, block, id)\
- .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
- mm ## reg_name
-
-#define SRII(reg_name, block, id)\
- .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
- mm ## block ## id ## _ ## reg_name
-
-#define SF(reg_name, field_name, post_fix)\
- .field_name = reg_name ## __ ## field_name ## post_fix
-
-
#define DWBC_COMMON_REG_LIST_DCN2_0(inst) \
- SRI2(WB_ENABLE, CNV, inst),\
- SRI2(WB_EC_CONFIG, CNV, inst),\
- SRI2(CNV_MODE, CNV, inst),\
- SRI2(CNV_WINDOW_START, CNV, inst),\
- SRI2(CNV_WINDOW_SIZE, CNV, inst),\
- SRI2(CNV_UPDATE, CNV, inst),\
- SRI2(CNV_SOURCE_SIZE, CNV, inst),\
- SRI2(CNV_TEST_CNTL, CNV, inst),\
- SRI2(CNV_TEST_CRC_RED, CNV, inst),\
- SRI2(CNV_TEST_CRC_GREEN, CNV, inst),\
- SRI2(CNV_TEST_CRC_BLUE, CNV, inst),\
- SRI2(WBSCL_COEF_RAM_SELECT, WBSCL, inst),\
- SRI2(WBSCL_COEF_RAM_TAP_DATA, WBSCL, inst),\
- SRI2(WBSCL_MODE, WBSCL, inst),\
- SRI2(WBSCL_TAP_CONTROL, WBSCL, inst),\
- SRI2(WBSCL_DEST_SIZE, WBSCL, inst),\
- SRI2(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL, inst),\
- SRI2(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL, inst),\
- SRI2(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL, inst),\
- SRI2(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL, inst),\
- SRI2(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL, inst),\
- SRI2(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL, inst),\
- SRI2(WBSCL_ROUND_OFFSET, WBSCL, inst),\
- SRI2(WBSCL_OVERFLOW_STATUS, WBSCL, inst),\
- SRI2(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL, inst),\
- SRI2(WBSCL_TEST_CNTL, WBSCL, inst),\
- SRI2(WBSCL_TEST_CRC_RED, WBSCL, inst),\
- SRI2(WBSCL_TEST_CRC_GREEN, WBSCL, inst),\
- SRI2(WBSCL_TEST_CRC_BLUE, WBSCL, inst),\
- SRI2(WBSCL_BACKPRESSURE_CNT_EN, WBSCL, inst),\
- SRI2(WB_MCIF_BACKPRESSURE_CNT, WBSCL, inst),\
- SRI2(WBSCL_CLAMP_Y_RGB, WBSCL, inst),\
- SRI2(WBSCL_CLAMP_CBCR, WBSCL, inst),\
- SRI2(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL, inst),\
- SRI2(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL, inst),\
- SRI2(WBSCL_DEBUG, WBSCL, inst),\
- SRI2(WBSCL_TEST_DEBUG_INDEX, WBSCL, inst),\
- SRI2(WBSCL_TEST_DEBUG_DATA, WBSCL, inst),\
- SRI2(WB_DEBUG_CTRL, CNV, inst),\
- SRI2(WB_DBG_MODE, CNV, inst),\
- SRI2(WB_HW_DEBUG, CNV, inst),\
- SRI2(CNV_TEST_DEBUG_INDEX, CNV, inst),\
- SRI2(CNV_TEST_DEBUG_DATA, CNV, inst),\
- SRI2(WB_SOFT_RESET, CNV, inst),\
- SRI2(WB_WARM_UP_MODE_CTL1, CNV, inst),\
- SRI2(WB_WARM_UP_MODE_CTL2, CNV, inst)
+ SRI2_DWB(WB_ENABLE, CNV, inst),\
+ SRI2_DWB(WB_EC_CONFIG, CNV, inst),\
+ SRI2_DWB(CNV_MODE, CNV, inst),\
+ SRI2_DWB(CNV_WINDOW_START, CNV, inst),\
+ SRI2_DWB(CNV_WINDOW_SIZE, CNV, inst),\
+ SRI2_DWB(CNV_UPDATE, CNV, inst),\
+ SRI2_DWB(CNV_SOURCE_SIZE, CNV, inst),\
+ SRI2_DWB(CNV_TEST_CNTL, CNV, inst),\
+ SRI2_DWB(CNV_TEST_CRC_RED, CNV, inst),\
+ SRI2_DWB(CNV_TEST_CRC_GREEN, CNV, inst),\
+ SRI2_DWB(CNV_TEST_CRC_BLUE, CNV, inst),\
+ SRI2_DWB(WBSCL_COEF_RAM_SELECT, WBSCL, inst),\
+ SRI2_DWB(WBSCL_COEF_RAM_TAP_DATA, WBSCL, inst),\
+ SRI2_DWB(WBSCL_MODE, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TAP_CONTROL, WBSCL, inst),\
+ SRI2_DWB(WBSCL_DEST_SIZE, WBSCL, inst),\
+ SRI2_DWB(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL, inst),\
+ SRI2_DWB(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL, inst),\
+ SRI2_DWB(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL, inst),\
+ SRI2_DWB(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL, inst),\
+ SRI2_DWB(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL, inst),\
+ SRI2_DWB(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL, inst),\
+ SRI2_DWB(WBSCL_ROUND_OFFSET, WBSCL, inst),\
+ SRI2_DWB(WBSCL_OVERFLOW_STATUS, WBSCL, inst),\
+ SRI2_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_CNTL, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_CRC_RED, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_CRC_GREEN, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_CRC_BLUE, WBSCL, inst),\
+ SRI2_DWB(WBSCL_BACKPRESSURE_CNT_EN, WBSCL, inst),\
+ SRI2_DWB(WB_MCIF_BACKPRESSURE_CNT, WBSCL, inst),\
+ SRI2_DWB(WBSCL_CLAMP_Y_RGB, WBSCL, inst),\
+ SRI2_DWB(WBSCL_CLAMP_CBCR, WBSCL, inst),\
+ SRI2_DWB(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL, inst),\
+ SRI2_DWB(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL, inst),\
+ SRI2_DWB(WBSCL_DEBUG, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_DEBUG_INDEX, WBSCL, inst),\
+ SRI2_DWB(WBSCL_TEST_DEBUG_DATA, WBSCL, inst),\
+ SRI2_DWB(WB_DEBUG_CTRL, CNV, inst),\
+ SRI2_DWB(WB_DBG_MODE, CNV, inst),\
+ SRI2_DWB(WB_HW_DEBUG, CNV, inst),\
+ SRI2_DWB(CNV_TEST_DEBUG_INDEX, CNV, inst),\
+ SRI2_DWB(CNV_TEST_DEBUG_DATA, CNV, inst),\
+ SRI2_DWB(WB_SOFT_RESET, CNV, inst),\
+ SRI2_DWB(WB_WARM_UP_MODE_CTL1, CNV, inst),\
+ SRI2_DWB(WB_WARM_UP_MODE_CTL2, CNV, inst)
#define DWBC_COMMON_MASK_SH_LIST_DCN2_0(mask_sh) \
- SF(WB_ENABLE, WB_ENABLE, mask_sh),\
- SF(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, mask_sh),\
- SF(WB_EC_CONFIG, DISPCLK_G_WB_GATE_DIS, mask_sh),\
- SF(WB_EC_CONFIG, DISPCLK_G_WBSCL_GATE_DIS, mask_sh),\
- SF(WB_EC_CONFIG, WB_TEST_CLK_SEL, mask_sh),\
- SF(WB_EC_CONFIG, WB_LB_LS_DIS, mask_sh),\
- SF(WB_EC_CONFIG, WB_LB_SD_DIS, mask_sh),\
- SF(WB_EC_CONFIG, WB_LUT_LS_DIS, mask_sh),\
- SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_MODE_SEL, mask_sh),\
- SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_DIS, mask_sh),\
- SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_FORCE, mask_sh),\
- SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_STATE, mask_sh),\
- SF(WB_EC_CONFIG, WB_RAM_PW_SAVE_MODE, mask_sh),\
- SF(WB_EC_CONFIG, WBSCL_LUT_MEM_PWR_STATE, mask_sh),\
- SF(CNV_MODE, CNV_OUT_BPC, mask_sh),\
- SF(CNV_MODE, CNV_FRAME_CAPTURE_RATE, mask_sh),\
- SF(CNV_MODE, CNV_WINDOW_CROP_EN, mask_sh),\
- SF(CNV_MODE, CNV_STEREO_TYPE, mask_sh),\
- SF(CNV_MODE, CNV_INTERLACED_MODE, mask_sh),\
- SF(CNV_MODE, CNV_EYE_SELECTION, mask_sh),\
- SF(CNV_MODE, CNV_STEREO_POLARITY, mask_sh),\
- SF(CNV_MODE, CNV_INTERLACED_FIELD_ORDER, mask_sh),\
- SF(CNV_MODE, CNV_STEREO_SPLIT, mask_sh),\
- SF(CNV_MODE, CNV_NEW_CONTENT, mask_sh),\
- SF(CNV_MODE, CNV_FRAME_CAPTURE_EN_CURRENT, mask_sh),\
- SF(CNV_MODE, CNV_FRAME_CAPTURE_EN, mask_sh),\
- SF(CNV_WINDOW_START, CNV_WINDOW_START_X, mask_sh),\
- SF(CNV_WINDOW_START, CNV_WINDOW_START_Y, mask_sh),\
- SF(CNV_WINDOW_SIZE, CNV_WINDOW_WIDTH, mask_sh),\
- SF(CNV_WINDOW_SIZE, CNV_WINDOW_HEIGHT, mask_sh),\
- SF(CNV_UPDATE, CNV_UPDATE_PENDING, mask_sh),\
- SF(CNV_UPDATE, CNV_UPDATE_TAKEN, mask_sh),\
- SF(CNV_UPDATE, CNV_UPDATE_LOCK, mask_sh),\
- SF(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, mask_sh),\
- SF(CNV_SOURCE_SIZE, CNV_SOURCE_HEIGHT, mask_sh),\
- SF(CNV_TEST_CNTL, CNV_TEST_CRC_EN, mask_sh),\
- SF(CNV_TEST_CNTL, CNV_TEST_CRC_CONT_EN, mask_sh),\
- SF(CNV_TEST_CRC_RED, CNV_TEST_CRC_RED_MASK, mask_sh),\
- SF(CNV_TEST_CRC_RED, CNV_TEST_CRC_SIG_RED, mask_sh),\
- SF(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_GREEN_MASK, mask_sh),\
- SF(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_SIG_GREEN, mask_sh),\
- SF(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_BLUE_MASK, mask_sh),\
- SF(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_SIG_BLUE, mask_sh),\
- SF(WB_DEBUG_CTRL, WB_DEBUG_EN, mask_sh),\
- SF(WB_DEBUG_CTRL, WB_DEBUG_SEL, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_MODE_EN, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_DIN_FMT, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_36MODE, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_CMAP, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_PXLRATE_ERROR, mask_sh),\
- SF(WB_DBG_MODE, WB_DBG_SOURCE_WIDTH, mask_sh),\
- SF(WB_HW_DEBUG, WB_HW_DEBUG, mask_sh),\
- SF(WB_SOFT_RESET, WB_SOFT_RESET, mask_sh),\
- SF(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_INDEX, mask_sh),\
- SF(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_WRITE_EN, mask_sh),\
- SF(CNV_TEST_DEBUG_DATA, CNV_TEST_DEBUG_DATA, mask_sh),\
- SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_TAP_PAIR_IDX, mask_sh),\
- SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_PHASE, mask_sh),\
- SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_FILTER_TYPE, mask_sh),\
- SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF, mask_sh),\
- SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF_EN, mask_sh),\
- SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF, mask_sh),\
- SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF_EN, mask_sh),\
- SF(WBSCL_MODE, WBSCL_MODE, mask_sh),\
- SF(WBSCL_MODE, WBSCL_OUT_BIT_DEPTH, mask_sh),\
- SF(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_Y_RGB, mask_sh),\
- SF(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_CBCR, mask_sh),\
- SF(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_Y_RGB, mask_sh),\
- SF(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_CBCR, mask_sh),\
- SF(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT, mask_sh),\
- SF(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH, mask_sh),\
- SF(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL_H_SCALE_RATIO, mask_sh),\
- SF(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_FRAC_Y_RGB, mask_sh),\
- SF(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_INT_Y_RGB, mask_sh),\
- SF(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_FRAC_CBCR, mask_sh),\
- SF(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_INT_CBCR, mask_sh),\
- SF(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL_V_SCALE_RATIO, mask_sh),\
- SF(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_FRAC_Y_RGB, mask_sh),\
- SF(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_INT_Y_RGB, mask_sh),\
- SF(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_FRAC_CBCR, mask_sh),\
- SF(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_INT_CBCR, mask_sh),\
- SF(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, mask_sh),\
- SF(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR, mask_sh),\
- SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_FLAG, mask_sh),\
- SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_ACK, mask_sh),\
- SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_MASK, mask_sh),\
- SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_STATUS, mask_sh),\
- SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_TYPE, mask_sh),\
- SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_FLAG, mask_sh),\
- SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_ACK, mask_sh),\
- SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_MASK, mask_sh),\
- SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_STATUS, mask_sh),\
- SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_TYPE, mask_sh),\
- SF(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_EN, mask_sh),\
- SF(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_CONT_EN, mask_sh),\
- SF(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_RED_MASK, mask_sh),\
- SF(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_SIG_RED, mask_sh),\
- SF(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_GREEN_MASK, mask_sh),\
- SF(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_SIG_GREEN, mask_sh),\
- SF(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_BLUE_MASK, mask_sh),\
- SF(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_SIG_BLUE, mask_sh),\
- SF(WBSCL_BACKPRESSURE_CNT_EN, WBSCL_BACKPRESSURE_CNT_EN, mask_sh),\
- SF(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_Y_MAX_BACKPRESSURE, mask_sh),\
- SF(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_C_MAX_BACKPRESSURE, mask_sh),\
- SF(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_UPPER_Y_RGB, mask_sh),\
- SF(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_LOWER_Y_RGB, mask_sh),\
- SF(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_UPPER_CBCR, mask_sh),\
- SF(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_LOWER_CBCR, mask_sh),\
- SF(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, mask_sh),\
- SF(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_BLACK_COLOR_G_Y, mask_sh),\
- SF(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_B_CB, mask_sh),\
- SF(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_R_CR, mask_sh),\
- SF(WBSCL_DEBUG, WBSCL_DEBUG, mask_sh),\
- SF(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_INDEX, mask_sh),\
- SF(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_WRITE_EN, mask_sh),\
- SF(WBSCL_TEST_DEBUG_DATA, WBSCL_TEST_DEBUG_DATA, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, mask_sh),\
- SF(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, mask_sh)
+ SF_DWB(WB_ENABLE, WB_ENABLE, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, DISPCLK_G_WB_GATE_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, DISPCLK_G_WBSCL_GATE_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WB_TEST_CLK_SEL, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WB_LB_LS_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WB_LB_SD_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WB_LUT_LS_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_MODE_SEL, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_DIS, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_FORCE, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_STATE, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WB_RAM_PW_SAVE_MODE, mask_sh),\
+ SF_DWB(WB_EC_CONFIG, WBSCL_LUT_MEM_PWR_STATE, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_OUT_BPC, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_FRAME_CAPTURE_RATE, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_WINDOW_CROP_EN, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_STEREO_TYPE, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_INTERLACED_MODE, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_EYE_SELECTION, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_STEREO_POLARITY, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_INTERLACED_FIELD_ORDER, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_STEREO_SPLIT, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_NEW_CONTENT, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_FRAME_CAPTURE_EN_CURRENT, mask_sh),\
+ SF_DWB(CNV_MODE, CNV_FRAME_CAPTURE_EN, mask_sh),\
+ SF_DWB(CNV_WINDOW_START, CNV_WINDOW_START_X, mask_sh),\
+ SF_DWB(CNV_WINDOW_START, CNV_WINDOW_START_Y, mask_sh),\
+ SF_DWB(CNV_WINDOW_SIZE, CNV_WINDOW_WIDTH, mask_sh),\
+ SF_DWB(CNV_WINDOW_SIZE, CNV_WINDOW_HEIGHT, mask_sh),\
+ SF_DWB(CNV_UPDATE, CNV_UPDATE_PENDING, mask_sh),\
+ SF_DWB(CNV_UPDATE, CNV_UPDATE_TAKEN, mask_sh),\
+ SF_DWB(CNV_UPDATE, CNV_UPDATE_LOCK, mask_sh),\
+ SF_DWB(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, mask_sh),\
+ SF_DWB(CNV_SOURCE_SIZE, CNV_SOURCE_HEIGHT, mask_sh),\
+ SF_DWB(CNV_TEST_CNTL, CNV_TEST_CRC_EN, mask_sh),\
+ SF_DWB(CNV_TEST_CNTL, CNV_TEST_CRC_CONT_EN, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_RED, CNV_TEST_CRC_RED_MASK, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_RED, CNV_TEST_CRC_SIG_RED, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_GREEN_MASK, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_SIG_GREEN, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_BLUE_MASK, mask_sh),\
+ SF_DWB(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_SIG_BLUE, mask_sh),\
+ SF_DWB(WB_DEBUG_CTRL, WB_DEBUG_EN, mask_sh),\
+ SF_DWB(WB_DEBUG_CTRL, WB_DEBUG_SEL, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_MODE_EN, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_DIN_FMT, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_36MODE, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_CMAP, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_PXLRATE_ERROR, mask_sh),\
+ SF_DWB(WB_DBG_MODE, WB_DBG_SOURCE_WIDTH, mask_sh),\
+ SF_DWB(WB_HW_DEBUG, WB_HW_DEBUG, mask_sh),\
+ SF_DWB(WB_SOFT_RESET, WB_SOFT_RESET, mask_sh),\
+ SF_DWB(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_INDEX, mask_sh),\
+ SF_DWB(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_WRITE_EN, mask_sh),\
+ SF_DWB(CNV_TEST_DEBUG_DATA, CNV_TEST_DEBUG_DATA, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_TAP_PAIR_IDX, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_PHASE, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_FILTER_TYPE, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF_EN, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF_EN, mask_sh),\
+ SF_DWB(WBSCL_MODE, WBSCL_MODE, mask_sh),\
+ SF_DWB(WBSCL_MODE, WBSCL_OUT_BIT_DEPTH, mask_sh),\
+ SF_DWB(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_CBCR, mask_sh),\
+ SF_DWB(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_CBCR, mask_sh),\
+ SF_DWB(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT, mask_sh),\
+ SF_DWB(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH, mask_sh),\
+ SF_DWB(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL_H_SCALE_RATIO, mask_sh),\
+ SF_DWB(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_FRAC_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_INT_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_FRAC_CBCR, mask_sh),\
+ SF_DWB(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_INT_CBCR, mask_sh),\
+ SF_DWB(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL_V_SCALE_RATIO, mask_sh),\
+ SF_DWB(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_FRAC_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_INT_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_FRAC_CBCR, mask_sh),\
+ SF_DWB(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_INT_CBCR, mask_sh),\
+ SF_DWB(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR, mask_sh),\
+ SF_DWB(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_FLAG, mask_sh),\
+ SF_DWB(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_ACK, mask_sh),\
+ SF_DWB(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_MASK, mask_sh),\
+ SF_DWB(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_STATUS, mask_sh),\
+ SF_DWB(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_TYPE, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_FLAG, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_ACK, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_MASK, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_STATUS, mask_sh),\
+ SF_DWB(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_TYPE, mask_sh),\
+ SF_DWB(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_EN, mask_sh),\
+ SF_DWB(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_CONT_EN, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_RED_MASK, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_SIG_RED, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_GREEN_MASK, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_SIG_GREEN, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_BLUE_MASK, mask_sh),\
+ SF_DWB(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_SIG_BLUE, mask_sh),\
+ SF_DWB(WBSCL_BACKPRESSURE_CNT_EN, WBSCL_BACKPRESSURE_CNT_EN, mask_sh),\
+ SF_DWB(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_Y_MAX_BACKPRESSURE, mask_sh),\
+ SF_DWB(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_C_MAX_BACKPRESSURE, mask_sh),\
+ SF_DWB(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_UPPER_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_LOWER_Y_RGB, mask_sh),\
+ SF_DWB(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_UPPER_CBCR, mask_sh),\
+ SF_DWB(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_LOWER_CBCR, mask_sh),\
+ SF_DWB(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, mask_sh),\
+ SF_DWB(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_BLACK_COLOR_G_Y, mask_sh),\
+ SF_DWB(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_B_CB, mask_sh),\
+ SF_DWB(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_R_CR, mask_sh),\
+ SF_DWB(WBSCL_DEBUG, WBSCL_DEBUG, mask_sh),\
+ SF_DWB(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_INDEX, mask_sh),\
+ SF_DWB(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_WRITE_EN, mask_sh),\
+ SF_DWB(WBSCL_TEST_DEBUG_DATA, WBSCL_TEST_DEBUG_DATA, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, mask_sh),\
+ SF_DWB(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, mask_sh)
#define DWBC_REG_FIELD_LIST_DCN2_0(type) \
type WB_ENABLE;\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
index 938dba5249d4..4566bc7abf17 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
@@ -973,10 +973,12 @@ void hubp2_cursor_set_position(
const struct dc_cursor_mi_param *param)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
- int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x;
- int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y;
+ int x_pos = pos->x - param->viewport.x;
+ int y_pos = pos->y - param->viewport.y;
int x_hotspot = pos->x_hotspot;
int y_hotspot = pos->y_hotspot;
+ int src_x_offset = x_pos - pos->x_hotspot;
+ int src_y_offset = y_pos - pos->y_hotspot;
int cursor_height = (int)hubp->curs_attr.height;
int cursor_width = (int)hubp->curs_attr.width;
uint32_t dst_x_offset;
@@ -994,18 +996,26 @@ void hubp2_cursor_set_position(
if (hubp->curs_attr.address.quad_part == 0)
return;
- // Rotated cursor width/height and hotspots tweaks for offset calculation
+ // Transform cursor width / height and hotspots for offset calculations
if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
swap(cursor_height, cursor_width);
+ swap(x_hotspot, y_hotspot);
+
if (param->rotation == ROTATION_ANGLE_90) {
- src_x_offset = pos->x - pos->y_hotspot - param->viewport.x;
- src_y_offset = pos->y - pos->x_hotspot - param->viewport.y;
+ // hotspot = (-y, x)
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
+ src_y_offset = y_pos - y_hotspot;
+ } else if (param->rotation == ROTATION_ANGLE_270) {
+ // hotspot = (y, -x)
+ src_x_offset = x_pos - x_hotspot;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
} else if (param->rotation == ROTATION_ANGLE_180) {
+ // hotspot = (-x, -y)
if (!param->mirror)
- src_x_offset = pos->x - param->viewport.x;
+ src_x_offset = x_pos - (cursor_width - x_hotspot);
- src_y_offset = pos->y - param->viewport.y;
+ src_y_offset = y_pos - (cursor_height - y_hotspot);
}
dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0;
@@ -1042,8 +1052,8 @@ void hubp2_cursor_set_position(
CURSOR_Y_POSITION, pos->y);
REG_SET_2(CURSOR_HOT_SPOT, 0,
- CURSOR_HOT_SPOT_X, x_hotspot,
- CURSOR_HOT_SPOT_Y, y_hotspot);
+ CURSOR_HOT_SPOT_X, pos->x_hotspot,
+ CURSOR_HOT_SPOT_Y, pos->y_hotspot);
REG_SET(CURSOR_DST_OFFSET, 0,
CURSOR_DST_X_OFFSET, dst_x_offset);
@@ -1052,8 +1062,8 @@ void hubp2_cursor_set_position(
hubp->pos.cur_ctl.bits.cur_enable = cur_en;
hubp->pos.position.bits.x_pos = pos->x;
hubp->pos.position.bits.y_pos = pos->y;
- hubp->pos.hot_spot.bits.x_hot = x_hotspot;
- hubp->pos.hot_spot.bits.y_hot = y_hotspot;
+ hubp->pos.hot_spot.bits.x_hot = pos->x_hotspot;
+ hubp->pos.hot_spot.bits.y_hot = pos->y_hotspot;
hubp->pos.dst_offset.bits.dst_x_offset = dst_x_offset;
/* Cursor Rectangle Cache
* Cursor bitmaps have different hotspot values
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index a7e0001a8f46..6291a241158a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -1079,6 +1079,29 @@ void dcn20_blank_pixel_data(
0);
}
+ if (!blank && dc->debug.enable_single_display_2to1_odm_policy) {
+ /* when exiting dynamic ODM need to reinit DPG state for unused pipes */
+ struct pipe_ctx *old_odm_pipe = dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx].next_odm_pipe;
+
+ odm_pipe = pipe_ctx->next_odm_pipe;
+
+ while (old_odm_pipe) {
+ if (!odm_pipe || old_odm_pipe->pipe_idx != odm_pipe->pipe_idx)
+ dc->hwss.set_disp_pattern_generator(dc,
+ old_odm_pipe,
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+ CONTROLLER_DP_COLOR_SPACE_UDEFINED,
+ COLOR_DEPTH_888,
+ NULL,
+ 0,
+ 0,
+ 0);
+ old_odm_pipe = old_odm_pipe->next_odm_pipe;
+ if (odm_pipe)
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
+ }
+
if (!blank)
if (stream_res->abm) {
dc->hwss.set_pipe(pipe_ctx);
@@ -1287,6 +1310,19 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx
{
new_pipe->update_flags.raw = 0;
+ /* If non-phantom pipe is being transitioned to a phantom pipe,
+ * set disable and return immediately. This is because the pipe
+ * that was previously in use must be fully disabled before we
+ * can "enable" it as a phantom pipe (since the OTG will certainly
+ * be different). The post_unlock sequence will set the correct
+ * update flags to enable the phantom pipe.
+ */
+ if (old_pipe->plane_state && !old_pipe->plane_state->is_phantom &&
+ new_pipe->plane_state && new_pipe->plane_state->is_phantom) {
+ new_pipe->update_flags.bits.disable = 1;
+ return;
+ }
+
/* Exit on unchanged, unused pipe */
if (!old_pipe->plane_state && !new_pipe->plane_state)
return;
@@ -1616,6 +1652,31 @@ static void dcn20_update_dchubp_dpp(
hubp->funcs->phantom_hubp_post_enable(hubp);
}
+static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)
+{
+ struct pipe_ctx *other_pipe;
+ int vready_offset = pipe->pipe_dlg_param.vready_offset;
+
+ /* Always use the largest vready_offset of all connected pipes */
+ for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+ for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
+ if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+ vready_offset = other_pipe->pipe_dlg_param.vready_offset;
+ }
+
+ return vready_offset;
+}
static void dcn20_program_pipe(
struct dc *dc,
@@ -1634,16 +1695,14 @@ static void dcn20_program_pipe(
&& !pipe_ctx->prev_odm_pipe) {
pipe_ctx->stream_res.tg->funcs->program_global_sync(
pipe_ctx->stream_res.tg,
- pipe_ctx->pipe_dlg_param.vready_offset,
+ calculate_vready_offset_for_group(pipe_ctx),
pipe_ctx->pipe_dlg_param.vstartup_start,
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width);
if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) {
- pipe_ctx->stream_res.tg->funcs->wait_for_state(
- pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(
- pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
}
pipe_ctx->stream_res.tg->funcs->set_vtg_params(
@@ -1682,7 +1741,10 @@ static void dcn20_program_pipe(
* only do gamma programming for powering on, internal memcmp to avoid
* updating on slave planes
*/
- if (pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.out_tf)
+ if (pipe_ctx->update_flags.bits.enable ||
+ pipe_ctx->update_flags.bits.plane_changed ||
+ pipe_ctx->stream->update_flags.bits.out_tf ||
+ pipe_ctx->plane_state->update_flags.bits.output_tf_change)
hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
/* If the pipe has been enabled or has a different opp, we
@@ -1813,6 +1875,17 @@ void dcn20_program_front_end_for_ctx(
context->stream_status[0].plane_count > 1) {
pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
}
+
+ /* when dynamic ODM is active, pipes must be reconfigured when all planes are
+ * disabled, as some transitions will leave software and hardware state
+ * mismatched.
+ */
+ if (dc->debug.enable_single_display_2to1_odm_policy &&
+ pipe->stream &&
+ pipe->update_flags.bits.disable &&
+ !pipe->prev_odm_pipe &&
+ hws->funcs.update_odm)
+ hws->funcs.update_odm(dc, context, pipe);
}
}
@@ -1852,26 +1925,6 @@ void dcn20_post_unlock_program_front_end(
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
- struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-
- /* If an active, non-phantom pipe is being transitioned into a phantom
- * pipe, wait for the double buffer update to complete first before we do
- * phantom pipe programming (HUBP_VTG_SEL updates right away so that can
- * cause issues).
- */
- if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
- old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
- old_pipe->stream_res.tg->funcs->wait_for_state(
- old_pipe->stream_res.tg,
- CRTC_STATE_VBLANK);
- old_pipe->stream_res.tg->funcs->wait_for_state(
- old_pipe->stream_res.tg,
- CRTC_STATE_VACTIVE);
- }
- }
-
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (pipe->plane_state && !pipe->top_pipe) {
/* Program phantom pipe here to prevent a frame of underflow in the MPO transition
@@ -1881,6 +1934,11 @@ void dcn20_post_unlock_program_front_end(
*/
while (pipe) {
if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ /* When turning on the phantom pipe we want to run through the
+ * entire enable sequence, so apply all the "enable" flags.
+ */
+ if (dc->hwss.apply_update_flags_for_phantom)
+ dc->hwss.apply_update_flags_for_phantom(pipe);
if (dc->hwss.update_phantom_vp_position)
dc->hwss.update_phantom_vp_position(dc, context, pipe);
dcn20_program_pipe(dc, pipe, context);
@@ -1953,10 +2011,13 @@ void dcn20_prepare_bandwidth(
/* decrease compbuf size */
if (hubbub->funcs->program_compbuf_size) {
- if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes)
+ if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) {
compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes;
- else
+ dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes);
+ } else {
compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb;
+ dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb);
+ }
hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false);
}
@@ -2037,7 +2098,7 @@ bool dcn20_update_bandwidth(
pipe_ctx->stream_res.tg->funcs->program_global_sync(
pipe_ctx->stream_res.tg,
- pipe_ctx->pipe_dlg_param.vready_offset,
+ calculate_vready_offset_for_group(pipe_ctx),
pipe_ctx->pipe_dlg_param.vstartup_start,
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width);
@@ -2601,14 +2662,6 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
if (dc->hwseq->funcs.set_pixels_per_cycle)
dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx);
-
- /* enable audio only within mode set */
- if (pipe_ctx->stream_res.audio != NULL) {
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.hpo_dp_stream_enc);
- else if (dc_is_dp_signal(pipe_ctx->stream->signal))
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
- }
}
void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h
index 7bcee5894d2e..5ab32aa51e13 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h
@@ -29,13 +29,6 @@
#define TO_DCN20_MMHUBBUB(mcif_wb_base) \
container_of(mcif_wb_base, struct dcn20_mmhubbub, base)
-/* DCN */
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-#define BASE(seg) \
- BASE_INNER(seg)
-
#define MCIF_WB_COMMON_REG_LIST_DCN2_0(inst) \
SRI(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst),\
SRI(MCIF_WB_BUFMGR_CUR_LINE_R, MCIF_WB, inst),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
index 8224b9bf01d1..8a0dd0d7134b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -124,8 +124,6 @@ enum dcn20_clk_src_array_id {
* macros to expend register list macro defined in HW object header file */
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -138,6 +136,15 @@ enum dcn20_clk_src_array_id {
.reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
+#define SRI2_DWB(reg_name, block, id)\
+ .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
+ mm ## reg_name
+#define SF_DWB(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define SRIR(var_name, reg_name, block, id)\
.var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
@@ -1454,6 +1461,22 @@ enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_
return result;
}
+/**
+ * dcn20_split_stream_for_odm - Check if stream can be splited for ODM
+ *
+ * @dc: DC object with resource pool info required for pipe split
+ * @res_ctx: Persistent state of resources
+ * @prev_odm_pipe: Reference to the previous ODM pipe
+ * @next_odm_pipe: Reference to the next ODM pipe
+ *
+ * This function takes a logically active pipe and a logically free pipe and
+ * halves all the scaling parameters that need to be halved while populating
+ * the free pipe with the required resources and configuring the next/previous
+ * ODM pipe pointers.
+ *
+ * Return:
+ * Return true if split stream for ODM is possible, otherwise, return false.
+ */
bool dcn20_split_stream_for_odm(
const struct dc *dc,
struct resource_context *res_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h
index f1ef46e8da5b..e7a1b7fa2cce 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h
@@ -28,12 +28,6 @@
#include "vmid.h"
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-#define BASE(seg) \
- BASE_INNER(seg)
-
#define DCN20_VMID_REG_LIST(id)\
SRI(CNTL, DCN_VM_CONTEXT, id),\
SRI(PAGE_TABLE_BASE_ADDR_HI32, DCN_VM_CONTEXT, id),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
index 887081472c0d..fbcf0afeae0d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
@@ -94,8 +94,6 @@
* macros to expend register list macro defined in HW object header file */
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -671,12 +669,15 @@ static const struct dc_debug_options debug_defaults_diags = {
.disable_pplib_wm_range = true,
.disable_stutter = true,
.disable_48mhz_pwrdwn = true,
- .disable_psr = true,
.enable_tri_buf = true,
.use_max_lb = true
};
static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
.ilr = {
.optimize_edp_link_rate = true,
},
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h
index 1010930cf071..fc00ec0a0881 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h
@@ -27,21 +27,6 @@
#define TO_DCN30_DWBC(dwbc_base) \
container_of(dwbc_base, struct dcn30_dwbc, base)
-/* DCN */
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-#define BASE(seg) \
- BASE_INNER(seg)
-
-#define SF_DWB(reg_name, block, id, field_name, post_fix)\
- .field_name = block ## id ## _ ## reg_name ## __ ## field_name ## post_fix
-
- /* set field name */
-#define SF_DWB2(reg_name, block, id, field_name, post_fix)\
- .field_name = reg_name ## __ ## field_name ## post_fix
-
-
#define DWBC_COMMON_REG_LIST_DCN30(inst) \
SR(DWB_ENABLE_CLK_CTRL),\
SR(DWB_MEM_PWR_CTRL),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mmhubbub.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mmhubbub.h
index 7446e54bf5aa..376620a8f02f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mmhubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mmhubbub.h
@@ -31,13 +31,6 @@
#define TO_DCN30_MMHUBBUB(mcif_wb_base) \
container_of(mcif_wb_base, struct dcn30_mmhubbub, base)
-/* DCN */
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-#define BASE(seg) \
- BASE_INNER(seg)
-
#define MCIF_WB_COMMON_REG_LIST_DCN3_0(inst) \
SRI(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst),\
SRI(MCIF_WB_BUFMGR_STATUS, MCIF_WB, inst),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
index 892d3c4d01a1..867d60151aeb 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
@@ -30,6 +30,7 @@
#include "dc_dmub_srv.h"
#include "dml/dcn30/dcn30_fpu.h"
+#include "dc_trace.h"
#define REG(reg)\
optc1->tg_regs->reg
@@ -58,6 +59,8 @@ void optc3_triplebuffer_lock(struct timing_generator *optc)
REG_WAIT(OTG_MASTER_UPDATE_LOCK,
UPDATE_LOCK_STATUS, 1,
1, 10);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true);
}
void optc3_lock_doublebuffer_enable(struct timing_generator *optc)
@@ -93,6 +96,8 @@ void optc3_lock_doublebuffer_enable(struct timing_generator *optc)
MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0,
MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100,
OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true);
}
void optc3_lock_doublebuffer_disable(struct timing_generator *optc)
@@ -108,6 +113,8 @@ void optc3_lock_doublebuffer_disable(struct timing_generator *optc)
REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0);
REG_UPDATE(OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, 0);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true);
}
void optc3_lock(struct timing_generator *optc)
@@ -122,6 +129,8 @@ void optc3_lock(struct timing_generator *optc)
REG_WAIT(OTG_MASTER_UPDATE_LOCK,
UPDATE_LOCK_STATUS, 1,
1, 10);
+
+ TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true);
}
void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
index 020f512e9690..c18c52a60100 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
@@ -108,8 +108,6 @@ enum dcn30_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -142,6 +140,9 @@ enum dcn30_clk_src_array_id {
.reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
@@ -723,7 +724,6 @@ static const struct dc_debug_options debug_defaults_drv = {
.underflow_assert_delay_us = 0xFFFFFFFF,
.dwb_fi_phase = -1, // -1 = disable,
.dmub_command_table = true,
- .disable_psr = false,
.use_max_lb = true,
.exit_idle_opt_for_cursor_updates = true
};
@@ -742,11 +742,17 @@ static const struct dc_debug_options debug_defaults_diags = {
.scl_reset_length10 = true,
.dwb_fi_phase = -1, // -1 = disable
.dmub_command_table = true,
- .disable_psr = true,
.enable_tri_buf = true,
.use_max_lb = true
};
+static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
+};
+
static void dcn30_dpp_destroy(struct dpp **dpp)
{
kfree(TO_DCN20_DPP(*dpp));
@@ -1323,6 +1329,7 @@ static struct clock_source *dcn30_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -2212,6 +2219,11 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
}
}
+static void dcn30_get_panel_config_defaults(struct dc_panel_config *panel_config)
+{
+ *panel_config = panel_config_defaults;
+}
+
static const struct resource_funcs dcn30_res_pool_funcs = {
.destroy = dcn30_destroy_resource_pool,
.link_enc_create = dcn30_link_encoder_create,
@@ -2231,6 +2243,7 @@ static const struct resource_funcs dcn30_res_pool_funcs = {
.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
.update_bw_bounding_box = dcn30_update_bw_bounding_box,
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
+ .get_panel_config_defaults = dcn30_get_panel_config_defaults,
};
#define CTX ctx
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
index f04595b750ab..8cf10351f271 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
@@ -107,8 +107,6 @@ enum dcn301_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -146,6 +144,9 @@ enum dcn301_clk_src_array_id {
.reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
@@ -1288,6 +1289,7 @@ static struct clock_source *dcn301_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1491,6 +1493,8 @@ static bool dcn301_resource_construct(
dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
dc->caps.color.mpc.ocsc = 1;
+ dc->caps.dp_hdmi21_pcon_support = true;
+
/* read VBIOS LTTPR caps */
if (ctx->dc_bios->funcs->get_lttpr_caps) {
enum bp_result bp_query_result;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
index b925b6ddde5a..47cffd0e6830 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
@@ -112,10 +112,16 @@ static const struct dc_debug_options debug_defaults_diags = {
.dwb_fi_phase = -1, // -1 = disable
.dmub_command_table = true,
.enable_tri_buf = true,
- .disable_psr = true,
.use_max_lb = true
};
+static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
+};
+
enum dcn302_clk_src_array_id {
DCN302_CLK_SRC_PLL0,
DCN302_CLK_SRC_PLL1,
@@ -177,7 +183,6 @@ static const struct dc_plane_cap plane_cap = {
mm ## reg_name
/* DCN */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -210,6 +215,9 @@ static const struct dc_plane_cap plane_cap = {
.reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define SRII_MPC_RMU(reg_name, block, id)\
.RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
@@ -458,6 +466,7 @@ static struct clock_source *dcn302_clock_source_create(struct dc_context *ctx, s
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1132,6 +1141,11 @@ void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
DC_FP_END();
}
+static void dcn302_get_panel_config_defaults(struct dc_panel_config *panel_config)
+{
+ *panel_config = panel_config_defaults;
+}
+
static struct resource_funcs dcn302_res_pool_funcs = {
.destroy = dcn302_destroy_resource_pool,
.link_enc_create = dcn302_link_encoder_create,
@@ -1151,6 +1165,7 @@ static struct resource_funcs dcn302_res_pool_funcs = {
.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
.update_bw_bounding_box = dcn302_update_bw_bounding_box,
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
+ .get_panel_config_defaults = dcn302_get_panel_config_defaults,
};
static struct dc_cap_funcs cap_funcs = {
@@ -1266,6 +1281,8 @@ static bool dcn302_resource_construct(
dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
dc->caps.color.mpc.ocsc = 1;
+ dc->caps.dp_hdmi21_pcon_support = true;
+
/* read VBIOS LTTPR caps */
if (ctx->dc_bios->funcs->get_lttpr_caps) {
enum bp_result bp_query_result;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
index 527d5c902878..c14d35894b2e 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
@@ -96,7 +96,13 @@ static const struct dc_debug_options debug_defaults_diags = {
.dwb_fi_phase = -1, // -1 = disable
.dmub_command_table = true,
.enable_tri_buf = true,
- .disable_psr = true,
+};
+
+static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
};
enum dcn303_clk_src_array_id {
@@ -156,7 +162,6 @@ static const struct dc_plane_cap plane_cap = {
mm ## reg_name
/* DCN */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -189,6 +194,9 @@ static const struct dc_plane_cap plane_cap = {
.reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define SRII_MPC_RMU(reg_name, block, id)\
.RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
@@ -425,6 +433,7 @@ static struct clock_source *dcn303_clock_source_create(struct dc_context *ctx, s
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1055,6 +1064,10 @@ static void dcn303_destroy_resource_pool(struct resource_pool **pool)
*pool = NULL;
}
+static void dcn303_get_panel_config_defaults(struct dc_panel_config *panel_config)
+{
+ *panel_config = panel_config_defaults;
+}
void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
{
@@ -1082,6 +1095,7 @@ static struct resource_funcs dcn303_res_pool_funcs = {
.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
.update_bw_bounding_box = dcn303_update_bw_bounding_box,
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
+ .get_panel_config_defaults = dcn303_get_panel_config_defaults,
};
static struct dc_cap_funcs cap_funcs = {
@@ -1198,6 +1212,8 @@ static bool dcn303_resource_construct(
dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
dc->caps.color.mpc.ocsc = 1;
+ dc->caps.dp_hdmi21_pcon_support = true;
+
/* read VBIOS LTTPR caps */
if (ctx->dc_bios->funcs->get_lttpr_caps) {
enum bp_result bp_query_result;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
index de5e18c2a3ac..24e9ff65434d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
@@ -134,23 +134,10 @@ static void apg31_se_audio_setup(
/* Disable forced mem power off */
REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
-
- apg31_enable(apg);
-}
-
-static void apg31_audio_mute_control(
- struct apg *apg,
- bool mute)
-{
- if (mute)
- apg31_disable(apg);
- else
- apg31_enable(apg);
}
static struct apg_funcs dcn31_apg_funcs = {
.se_audio_setup = apg31_se_audio_setup,
- .audio_mute_control = apg31_audio_mute_control,
.enable_apg = apg31_enable,
.disable_apg = apg31_disable,
};
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
index 24f568e120d8..1b81f6773c53 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
@@ -84,10 +84,6 @@ struct apg_funcs {
unsigned int az_inst,
struct audio_info *audio_info);
- void (*audio_mute_control)(
- struct apg *apg,
- bool mute);
-
void (*enable_apg)(
struct apg *apg);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
index 814f401db3b3..16639bd03adf 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
@@ -600,14 +600,6 @@ static void dcn31_hpo_dp_stream_enc_map_stream_to_link(
}
}
-static void dcn31_hpo_dp_stream_enc_mute_control(
- struct hpo_dp_stream_encoder *enc,
- bool mute)
-{
- ASSERT(enc->apg);
- enc->apg->funcs->audio_mute_control(enc->apg, mute);
-}
-
static void dcn31_hpo_dp_stream_enc_audio_setup(
struct hpo_dp_stream_encoder *enc,
unsigned int az_inst,
@@ -726,7 +718,6 @@ static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
.stop_dp_info_packets = dcn31_hpo_dp_stream_enc_stop_dp_info_packets,
.dp_set_dsc_pps_info_packet = dcn31_hpo_dp_stream_enc_set_dsc_pps_info_packet,
.map_stream_to_link = dcn31_hpo_dp_stream_enc_map_stream_to_link,
- .audio_mute_control = dcn31_hpo_dp_stream_enc_mute_control,
.dp_audio_setup = dcn31_hpo_dp_stream_enc_audio_setup,
.dp_audio_enable = dcn31_hpo_dp_stream_enc_audio_enable,
.dp_audio_disable = dcn31_hpo_dp_stream_enc_audio_disable,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
index 84e1486f3d51..39a57bcd7866 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
@@ -87,6 +87,7 @@ static struct hubp_funcs dcn31_hubp_funcs = {
.hubp_init = hubp3_init,
.set_unbounded_requesting = hubp31_set_unbounded_requesting,
.hubp_soft_reset = hubp31_soft_reset,
+ .hubp_set_flip_int = hubp1_set_flip_int,
.hubp_in_blank = hubp1_in_blank,
.program_extended_blank = hubp31_program_extended_blank,
};
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
index bdf101547484..4226a051df41 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
@@ -89,7 +89,8 @@ static void enable_memory_low_power(struct dc *dc)
REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
}
- if (dc->debug.enable_mem_low_power.bits.mpc)
+ if (dc->debug.enable_mem_low_power.bits.mpc &&
+ dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode)
dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc);
@@ -141,7 +142,8 @@ void dcn31_init_hw(struct dc *dc)
if (!dcb->funcs->is_accelerated_mode(dcb)) {
hws->funcs.bios_golden_init(dc);
- hws->funcs.disable_vga(dc->hwseq);
+ if (hws->funcs.disable_vga)
+ hws->funcs.disable_vga(dc->hwseq);
}
// Initialize the dccg
if (res_pool->dccg->funcs->dccg_init)
@@ -621,3 +623,43 @@ void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
if (hws->ctx->dc->debug.hpo_optimization)
REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable);
}
+void dcn31_set_drr(struct pipe_ctx **pipe_ctx,
+ int num_pipes, struct dc_crtc_timing_adjust adjust)
+{
+ int i = 0;
+ struct drr_params params = {0};
+ unsigned int event_triggers = 0x2;/*Bit[1]: OTG_TRIG_A*/
+ unsigned int num_frames = 2;
+ params.vertical_total_max = adjust.v_total_max;
+ params.vertical_total_min = adjust.v_total_min;
+ params.vertical_total_mid = adjust.v_total_mid;
+ params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;
+ for (i = 0; i < num_pipes; i++) {
+ if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) {
+ if (pipe_ctx[i]->stream_res.tg->funcs->set_drr)
+ pipe_ctx[i]->stream_res.tg->funcs->set_drr(
+ pipe_ctx[i]->stream_res.tg, &params);
+ if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
+ if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control)
+ pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
+ pipe_ctx[i]->stream_res.tg,
+ event_triggers, num_frames);
+ }
+ }
+}
+void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx,
+ int num_pipes, const struct dc_static_screen_params *params)
+{
+ unsigned int i;
+ unsigned int triggers = 0;
+ if (params->triggers.surface_update)
+ triggers |= 0x600;/*bit 9 and bit10 : 110 0000 0000*/
+ if (params->triggers.cursor_update)
+ triggers |= 0x10;/*bit4*/
+ if (params->triggers.force_trigger)
+ triggers |= 0x1;
+ for (i = 0; i < num_pipes; i++)
+ pipe_ctx[i]->stream_res.tg->funcs->
+ set_static_screen_control(pipe_ctx[i]->stream_res.tg,
+ triggers, params->num_frames);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
index edfc01d6ad73..e7e03a8722e0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
@@ -56,4 +56,8 @@ bool dcn31_is_abm_supported(struct dc *dc,
void dcn31_init_pipes(struct dc *dc, struct dc_state *context);
void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable);
+void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx,
+ int num_pipes, const struct dc_static_screen_params *params);
+void dcn31_set_drr(struct pipe_ctx **pipe_ctx,
+ int num_pipes, struct dc_crtc_timing_adjust adjust);
#endif /* __DC_HWSS_DCN31_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
index 3a32810bbe38..7c2da70ffe21 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
@@ -64,9 +64,9 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.prepare_bandwidth = dcn20_prepare_bandwidth,
.optimize_bandwidth = dcn20_optimize_bandwidth,
.update_bandwidth = dcn20_update_bandwidth,
- .set_drr = dcn10_set_drr,
+ .set_drr = dcn31_set_drr,
.get_position = dcn10_get_position,
- .set_static_screen_control = dcn10_set_static_screen_control,
+ .set_static_screen_control = dcn31_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
index 63a677c8ee27..fe449f7aa771 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
@@ -40,6 +40,7 @@
#define FN(reg_name, field_name) \
optc1->tg_shift->field_name, optc1->tg_mask->field_name
+#define STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN 0x2000 /*bit 13*/
static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
{
@@ -231,6 +232,32 @@ void optc3_init_odm(struct timing_generator *optc)
OPTC_MEM_SEL, 0);
optc1->opp_count = 1;
}
+void optc31_set_static_screen_control(
+ struct timing_generator *optc,
+ uint32_t event_triggers,
+ uint32_t num_frames)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t framecount;
+ uint32_t events;
+
+ if (num_frames > 0xFF)
+ num_frames = 0xFF;
+ REG_GET_2(OTG_STATIC_SCREEN_CONTROL,
+ OTG_STATIC_SCREEN_EVENT_MASK, &events,
+ OTG_STATIC_SCREEN_FRAME_COUNT, &framecount);
+
+ if (events == event_triggers && num_frames == framecount)
+ return;
+ if ((event_triggers & STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN)
+ != 0)
+ event_triggers = event_triggers &
+ ~STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN;
+
+ REG_UPDATE_2(OTG_STATIC_SCREEN_CONTROL,
+ OTG_STATIC_SCREEN_EVENT_MASK, event_triggers,
+ OTG_STATIC_SCREEN_FRAME_COUNT, num_frames);
+}
static struct timing_generator_funcs dcn31_tg_funcs = {
.validate_timing = optc1_validate_timing,
@@ -266,7 +293,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
.set_drr = optc31_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc1_set_vtotal_min_max,
- .set_static_screen_control = optc1_set_static_screen_control,
+ .set_static_screen_control = optc31_set_static_screen_control,
.program_stereo = optc1_program_stereo,
.is_stereo_left_eye = optc1_is_stereo_left_eye,
.tg_init = optc3_tg_init,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
index 30b81a448ce2..5fc6c63580d7 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
@@ -263,5 +263,8 @@ bool optc31_immediate_disable_crtc(struct timing_generator *optc);
void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params);
void optc3_init_odm(struct timing_generator *optc);
-
+void optc31_set_static_screen_control(
+ struct timing_generator *optc,
+ uint32_t event_triggers,
+ uint32_t num_frames);
#endif /* __DC_OPTC_DCN31_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index fddc21a5a04c..3ca517dcc82d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -119,8 +119,6 @@ enum dcn31_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -153,6 +151,9 @@ enum dcn31_clk_src_array_id {
.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
@@ -911,6 +912,10 @@ static const struct dc_debug_options debug_defaults_diags = {
};
static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
.ilr = {
.optimize_edp_link_rate = true,
},
@@ -1625,6 +1630,7 @@ static struct clock_source *dcn31_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1634,6 +1640,31 @@ static bool is_dual_plane(enum surface_pixel_format format)
return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
}
+int dcn31x_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+{
+ uint32_t pipe_cnt;
+ int i;
+
+ dc_assert_fp_enabled();
+
+ pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+
+ for (i = 0; i < pipe_cnt; i++) {
+ pipes[i].pipe.src.gpuvm = 1;
+ if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE) {
+ //pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
+ pipes[i].pipe.src.hostvm = dc->vm_pa_config.is_hvm_enabled;
+ } else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_FALSE)
+ pipes[i].pipe.src.hostvm = false;
+ else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_TRUE)
+ pipes[i].pipe.src.hostvm = true;
+ }
+ return pipe_cnt;
+}
+
int dcn31_populate_dml_pipes_from_context(
struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
@@ -1645,7 +1676,7 @@ int dcn31_populate_dml_pipes_from_context(
bool upscaled = false;
DC_FP_START();
- dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
DC_FP_END();
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
@@ -1675,12 +1706,6 @@ int dcn31_populate_dml_pipes_from_context(
dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt);
DC_FP_END();
- if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE)
- pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
- else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_FALSE)
- pipes[pipe_cnt].pipe.src.hostvm = false;
- else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_TRUE)
- pipes[pipe_cnt].pipe.src.hostvm = true;
if (pipes[pipe_cnt].dout.dsc_enable) {
switch (timing->display_color_depth) {
@@ -1898,6 +1923,8 @@ static bool dcn31_resource_construct(
dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ if (dc->config.forceHBR2CP2520)
+ dc->caps.force_dp_tps4_for_cp2520 = false;
dc->caps.dp_hpo = true;
dc->caps.dp_hdmi21_pcon_support = true;
dc->caps.edp_dsc_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c
index 1bd7e0f327d8..0b769ee71405 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c
@@ -96,8 +96,15 @@ static void dccg314_set_pixel_rate_div(
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
+ // Don't program 0xF into the register field. Not valid since
+ // K1 / K2 field is only 1 / 2 bits wide
+ if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
dccg314_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2);
- if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA || (k1 == cur_k1 && k2 == cur_k2))
+ if (k1 == cur_k1 && k2 == cur_k2)
return;
switch (otg_inst) {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
index 7e773bf7b895..38842f938bed 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
@@ -49,18 +49,30 @@
#define CTX \
enc1->base.ctx
+static void enc314_reset_fifo(struct stream_encoder *enc, bool reset)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+ uint32_t reset_val = reset ? 1 : 0;
+ uint32_t is_symclk_on;
+
+ REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, reset_val);
+ REG_GET(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, &is_symclk_on);
+
+ if (is_symclk_on)
+ REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, reset_val, 10, 5000);
+ else
+ udelay(10);
+}
static void enc314_enable_fifo(struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
- /* TODO: Confirm if we need to wait for DIG_SYMCLK_FE_ON */
- REG_WAIT(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, 1, 10, 5000);
REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7);
- REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 1);
- REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, 1, 10, 5000);
- REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 0);
- REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, 0, 10, 5000);
+
+ enc314_reset_fifo(enc, true);
+ enc314_reset_fifo(enc, false);
+
REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 1);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
index 588c1c71241f..a0741794db62 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
@@ -348,10 +348,8 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
- return odm_combine_factor;
-
if (is_dp_128b_132b_signal(pipe_ctx)) {
+ *k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_1;
} else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
*k1_div = PIXEL_RATE_DIV_BY_1;
@@ -359,7 +357,7 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
*k2_div = PIXEL_RATE_DIV_BY_2;
else
*k2_div = PIXEL_RATE_DIV_BY_4;
- } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
if (two_pix_per_container) {
*k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_2;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
index 5b6c2d94ec71..31feb4b0edee 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
@@ -66,9 +66,9 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.prepare_bandwidth = dcn20_prepare_bandwidth,
.optimize_bandwidth = dcn20_optimize_bandwidth,
.update_bandwidth = dcn20_update_bandwidth,
- .set_drr = dcn10_set_drr,
+ .set_drr = dcn31_set_drr,
.get_position = dcn10_get_position,
- .set_static_screen_control = dcn10_set_static_screen_control,
+ .set_static_screen_control = dcn31_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
index 47eb162f1a75..41edbd64ea21 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
@@ -228,7 +228,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.set_drr = optc31_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc1_set_vtotal_min_max,
- .set_static_screen_control = optc1_set_static_screen_control,
+ .set_static_screen_control = optc31_set_static_screen_control,
.program_stereo = optc1_program_stereo,
.is_stereo_left_eye = optc1_is_stereo_left_eye,
.tg_init = optc3_tg_init,
@@ -237,11 +237,10 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.clear_optc_underflow = optc1_clear_optc_underflow,
.setup_global_swap_lock = NULL,
.get_crc = optc1_get_crc,
- .configure_crc = optc2_configure_crc,
+ .configure_crc = optc1_configure_crc,
.set_dsc_config = optc3_set_dsc_config,
.get_dsc_status = optc2_get_dsc_status,
.set_dwb_source = NULL,
- .set_odm_bypass = optc3_set_odm_bypass,
.set_odm_combine = optc314_set_odm_combine,
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
index 9066c511a052..f9ea1e86707f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
@@ -184,6 +184,9 @@ enum dcn31_clk_src_array_id {
.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
@@ -883,6 +886,7 @@ static const struct dc_plane_cap plane_cap = {
static const struct dc_debug_options debug_defaults_drv = {
.disable_z10 = false,
.enable_z9_disable_interface = true,
+ .psr_skip_crtc_disable = true,
.disable_dmcu = true,
.force_abm_enable = false,
.timing_trace = false,
@@ -937,6 +941,10 @@ static const struct dc_debug_options debug_defaults_diags = {
};
static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
.ilr = {
.optimize_edp_link_rate = true,
},
@@ -1766,6 +1774,8 @@ static bool dcn314_resource_construct(
dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ if (dc->config.forceHBR2CP2520)
+ dc->caps.force_dp_tps4_for_cp2520 = false;
dc->caps.dp_hpo = true;
dc->caps.dp_hdmi21_pcon_support = true;
dc->caps.edp_dsc_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
index 58746c437554..7887078c5f64 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
@@ -151,8 +151,6 @@ enum dcn31_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -185,6 +183,9 @@ enum dcn31_clk_src_array_id {
.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
@@ -907,6 +908,10 @@ static const struct dc_debug_options debug_defaults_diags = {
};
static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
.ilr = {
.optimize_edp_link_rate = true,
},
@@ -1623,6 +1628,7 @@ static struct clock_source *dcn31_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1643,7 +1649,7 @@ static int dcn315_populate_dml_pipes_from_context(
const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB;
DC_FP_START();
- dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
DC_FP_END();
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
@@ -1662,7 +1668,6 @@ static int dcn315_populate_dml_pipes_from_context(
pipes[pipe_cnt].pipe.src.immediate_flip = true;
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
- pipes[pipe_cnt].pipe.src.gpuvm = true;
pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
pipes[pipe_cnt].pipe.src.dcc_rate = 3;
pipes[pipe_cnt].dout.dsc_input_bpc = 0;
@@ -1703,7 +1708,9 @@ static int dcn315_populate_dml_pipes_from_context(
dc->config.enable_4to1MPC = true;
context->bw_ctx.dml.ip.det_buffer_size_kbytes =
(max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / 4) * DCN3_15_CRB_SEGMENT_SIZE_KB;
- } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) {
+ } else if (!is_dual_plane(pipe->plane_state->format)
+ && pipe->plane_state->src_rect.width <= 5120
+ && pipe->stream->timing.pix_clk_100hz < dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)) {
/* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */
context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
pipes[0].pipe.src.unbounded_req_mode = true;
@@ -1779,6 +1786,8 @@ static bool dcn315_resource_construct(
dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ if (dc->config.forceHBR2CP2520)
+ dc->caps.force_dp_tps4_for_cp2520 = false;
dc->caps.dp_hpo = true;
dc->caps.dp_hdmi21_pcon_support = true;
dc->caps.edp_dsc_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
index 6b40a11ac83a..b4d5076e124c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
@@ -142,8 +142,6 @@ enum dcn31_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
@@ -176,6 +174,9 @@ enum dcn31_clk_src_array_id {
.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
@@ -906,6 +907,10 @@ static const struct dc_debug_options debug_defaults_diags = {
};
static const struct dc_panel_config panel_config_defaults = {
+ .psr = {
+ .disable_psr = false,
+ .disallow_psrsu = false,
+ },
.ilr = {
.optimize_edp_link_rate = true,
},
@@ -1646,7 +1651,7 @@ static int dcn316_populate_dml_pipes_from_context(
const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_16_MIN_COMPBUF_SIZE_KB;
DC_FP_START();
- dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
DC_FP_END();
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
@@ -1665,7 +1670,6 @@ static int dcn316_populate_dml_pipes_from_context(
pipes[pipe_cnt].pipe.src.immediate_flip = true;
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
- pipes[pipe_cnt].pipe.src.gpuvm = true;
pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
pipes[pipe_cnt].pipe.src.dcc_rate = 3;
pipes[pipe_cnt].dout.dsc_input_bpc = 0;
@@ -1781,6 +1785,8 @@ static bool dcn316_resource_construct(
dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ if (dc->config.forceHBR2CP2520)
+ dc->caps.force_dp_tps4_for_cp2520 = false;
dc->caps.dp_hpo = true;
dc->caps.dp_hdmi21_pcon_support = true;
dc->caps.edp_dsc_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c
index e4daed44ef5f..e4472c6be6c3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c
@@ -96,8 +96,10 @@ static void dccg32_set_pixel_rate_div(
// Don't program 0xF into the register field. Not valid since
// K1 / K2 field is only 1 / 2 bits wide
- if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA)
+ if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) {
+ BREAK_TO_DEBUGGER();
return;
+ }
dccg32_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2);
if (k1 == cur_k1 && k2 == cur_k2)
@@ -223,11 +225,7 @@ static void dccg32_set_dtbclk_dto(
} else {
REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst],
DTBCLK_DTO_ENABLE[params->otg_inst], 0,
- PIPE_DTO_SRC_SEL[params->otg_inst], 1);
- if (params->is_hdmi)
- REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
- PIPE_DTO_SRC_SEL[params->otg_inst], 0);
-
+ PIPE_DTO_SRC_SEL[params->otg_inst], params->is_hdmi ? 0 : 1);
REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0);
REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
index 9fbb72369c10..5947c2cb0f30 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
@@ -41,6 +41,10 @@
#define FN(reg_name, field_name) \
hubbub2->shifts->field_name, hubbub2->masks->field_name
+/**
+ * @DCN32_CRB_SEGMENT_SIZE_KB: Maximum Configurable Return Buffer size for
+ * DCN32
+ */
#define DCN32_CRB_SEGMENT_SIZE_KB 64
static void dcn32_init_crb(struct hubbub *hubbub)
@@ -68,6 +72,23 @@ static void dcn32_init_crb(struct hubbub *hubbub)
REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x47F);
}
+void hubbub32_set_request_limit(struct hubbub *hubbub, int memory_channel_count, int words_per_channel)
+{
+ struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+
+ uint32_t request_limit = 3 * memory_channel_count * words_per_channel / 4;
+
+ ASSERT((request_limit & (~0xFFF)) == 0); //field is only 24 bits long
+ ASSERT(request_limit > 0); //field is only 24 bits long
+
+ if (request_limit > 0xFFF)
+ request_limit = 0xFFF;
+
+ if (request_limit > 0)
+ REG_UPDATE(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, request_limit);
+}
+
+
void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte)
{
struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
@@ -945,6 +966,7 @@ static const struct hubbub_funcs hubbub32_funcs = {
.init_crb = dcn32_init_crb,
.hubbub_read_state = hubbub2_read_state,
.force_usr_retraining_allow = hubbub32_force_usr_retraining_allow,
+ .set_request_limit = hubbub32_set_request_limit
};
void hubbub32_construct(struct dcn20_hubbub *hubbub2,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
index cda94e0e31bf..786f9ce07f92 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
@@ -82,7 +82,8 @@
SR(DCN_VM_FAULT_ADDR_MSB),\
SR(DCN_VM_FAULT_ADDR_LSB),\
SR(DCN_VM_FAULT_CNTL),\
- SR(DCN_VM_FAULT_STATUS)
+ SR(DCN_VM_FAULT_STATUS),\
+ SR(SDPIF_REQUEST_RATE_LIMIT)
#define HUBBUB_MASK_SH_LIST_DCN32(mask_sh)\
HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \
@@ -159,7 +160,8 @@
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \
- HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh)
+ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\
+ HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh)
bool hubbub32_program_urgent_watermarks(
struct hubbub *hubbub,
@@ -200,4 +202,6 @@ void hubbub32_construct(struct dcn20_hubbub *hubbub2,
int pixel_chunk_size_kb,
int config_return_buffer_size_kb);
+void hubbub32_set_request_limit(struct hubbub *hubbub, int umc_count, int words_per_umc);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
index cf5bd9713f54..b8767be1e4c5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
@@ -227,8 +227,13 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+ /* If PSR is supported on an eDP panel that's connected, but that panel is
+ * not in PSR at the time of trying to enter MALL SS, we have to include it
+ * in the static screen CAB calculation
+ */
if (!pipe->stream || !pipe->plane_state ||
- pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED ||
+ (pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
+ pipe->stream->link->psr_settings.psr_allow_active) ||
pipe->stream->mall_stream_config.type == SUBVP_PHANTOM)
continue;
@@ -257,11 +262,11 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
- /* For DCC:
- * meta_num_mblk = CEILING(full_mblk_width_ub_l*full_mblk_height_ub_l*Bpe/256/mblk_bytes, 1)
+ /*For DCC:
+ * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1)
*/
if (pipe->plane_state->dcc.enable)
- num_mblks += (mall_alloc_width_blk_aligned * mall_alloc_width_blk_aligned * bytes_per_pixel +
+ num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel +
(256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES);
bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES;
@@ -283,8 +288,7 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
using the max for calculation */
if (hubp->curs_attr.width > 0) {
- // Round cursor width to next multiple of 64
- cursor_size = (((hubp->curs_attr.width + 63) / 64) * 64) * hubp->curs_attr.height;
+ cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
switch (pipe->stream->cursor_attributes.color_format) {
case CURSOR_MODE_MONO:
@@ -309,11 +313,11 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
cursor_size > 16384) {
/* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1)
*/
- cache_lines_used += (((hubp->curs_attr.width * hubp->curs_attr.height * cursor_bpp +
- DCN3_2_MALL_MBLK_SIZE_BYTES - 1) / DCN3_2_MALL_MBLK_SIZE_BYTES) *
- DCN3_2_MALL_MBLK_SIZE_BYTES) / dc->caps.cache_line_size + 2;
+ cache_lines_used += (((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) /
+ DCN3_2_MALL_MBLK_SIZE_BYTES) * DCN3_2_MALL_MBLK_SIZE_BYTES) /
+ dc->caps.cache_line_size + 2;
+ break;
}
- break;
}
}
@@ -699,11 +703,7 @@ void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
- // For SubVP + DRR, also force disallow on the DRR pipe
- // (We will force allow in the DMUB sequence -- some DRR timings by default won't allow P-State so we have
- // to force once the vblank is stretched).
- if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN ||
- (pipe->stream->mall_stream_config.type == SUBVP_NONE && pipe->stream->ignore_msa_timing_param))) {
+ if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN)) {
struct hubp *hubp = pipe->plane_res.hubp;
if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
@@ -727,10 +727,7 @@ void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context)
struct hubp *hubp = pipe->plane_res.hubp;
if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) {
- //Round cursor width up to next multiple of 64
- int cursor_width = ((hubp->curs_attr.width + 63) / 64) * 64;
- int cursor_height = hubp->curs_attr.height;
- int cursor_size = cursor_width * cursor_height;
+ int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
switch (hubp->curs_attr.color_format) {
case CURSOR_MODE_MONO:
@@ -784,6 +781,10 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context)
if (hws && hws->funcs.update_mall_sel)
hws->funcs.update_mall_sel(dc, context);
+ //update subvp force pstate
+ if (hws && hws->funcs.subvp_update_force_pstate)
+ dc->hwseq->funcs.subvp_update_force_pstate(dc, context);
+
// Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
@@ -984,15 +985,14 @@ void dcn32_init_hw(struct dc *dc)
if (dc->res_pool->hubbub->funcs->init_crb)
dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
+ if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
+ dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
+
// Get DMCUB capabilities
if (dc->ctx->dmub_srv) {
dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub);
dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
}
-
- /* Enable support for ODM and windowed MPO if policy flag is set */
- if (dc->debug.enable_single_display_2to1_odm_policy)
- dc->config.enable_windowed_mpo_odm = true;
}
static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
@@ -1175,10 +1175,8 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
- return odm_combine_factor;
-
if (is_dp_128b_132b_signal(pipe_ctx)) {
+ *k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_1;
} else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
*k1_div = PIXEL_RATE_DIV_BY_1;
@@ -1186,7 +1184,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
*k2_div = PIXEL_RATE_DIV_BY_2;
else
*k2_div = PIXEL_RATE_DIV_BY_4;
- } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
if (two_pix_per_container) {
*k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_2;
@@ -1371,6 +1369,33 @@ void dcn32_update_phantom_vp_position(struct dc *dc,
}
}
+/* Treat the phantom pipe as if it needs to be fully enabled.
+ * If the pipe was previously in use but not phantom, it would
+ * have been disabled earlier in the sequence so we need to run
+ * the full enable sequence.
+ */
+void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
+{
+ phantom_pipe->update_flags.raw = 0;
+ if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ if (phantom_pipe->stream && phantom_pipe->plane_state) {
+ phantom_pipe->update_flags.bits.enable = 1;
+ phantom_pipe->update_flags.bits.mpcc = 1;
+ phantom_pipe->update_flags.bits.dppclk = 1;
+ phantom_pipe->update_flags.bits.hubp_interdependent = 1;
+ phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
+ phantom_pipe->update_flags.bits.gamut_remap = 1;
+ phantom_pipe->update_flags.bits.scaler = 1;
+ phantom_pipe->update_flags.bits.viewport = 1;
+ phantom_pipe->update_flags.bits.det_size = 1;
+ if (!phantom_pipe->top_pipe && !phantom_pipe->prev_odm_pipe) {
+ phantom_pipe->update_flags.bits.odm = 1;
+ phantom_pipe->update_flags.bits.global_sync = 1;
+ }
+ }
+ }
+}
+
bool dcn32_dsc_pg_status(
struct dce_hwseq *hws,
unsigned int dsc_inst)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
index ac3657a5b9ea..7de36529cf99 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
@@ -92,6 +92,8 @@ void dcn32_update_phantom_vp_position(struct dc *dc,
struct dc_state *context,
struct pipe_ctx *phantom_pipe);
+void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe);
+
bool dcn32_dsc_pg_status(
struct dce_hwseq *hws,
unsigned int dsc_inst);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
index 45a949ba6f3f..dc4649458567 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
@@ -110,6 +110,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.update_visual_confirm_color = dcn20_update_visual_confirm_color,
.update_phantom_vp_position = dcn32_update_phantom_vp_position,
.update_dsc_pg = dcn32_update_dsc_pg,
+ .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom,
};
static const struct hwseq_private_funcs dcn32_private_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c
index 41b0baf8e183..c3b089ba511a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c
@@ -211,7 +211,7 @@ static void mmhubbub32_config_mcif_arb(struct mcif_wb *mcif_wb,
REG_UPDATE(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_CLIENT_ARBITRATION_SLICE, params->arbitration_slice);
}
-const struct mcif_wb_funcs dcn32_mmhubbub_funcs = {
+static const struct mcif_wb_funcs dcn32_mmhubbub_funcs = {
.warmup_mcif = mmhubbub32_warmup_mcif,
.enable_mcif = mmhubbub2_enable_mcif,
.disable_mcif = mmhubbub2_disable_mcif,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
index 4edd0655965b..206a5ddbaf6d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
@@ -982,7 +982,7 @@ static bool mpc32_program_3dlut(
return true;
}
-const struct mpc_funcs dcn32_mpc_funcs = {
+static const struct mpc_funcs dcn32_mpc_funcs = {
.read_mpcc_state = mpc1_read_mpcc_state,
.insert_plane = mpc1_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c
index 2b33eeb213e2..2ee798965bc2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c
@@ -167,6 +167,13 @@ static void optc32_phantom_crtc_post_enable(struct timing_generator *optc)
REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000);
}
+static void optc32_disable_phantom_otg(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+ REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0);
+}
+
static void optc32_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing)
{
@@ -260,6 +267,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = {
.enable_crtc = optc32_enable_crtc,
.disable_crtc = optc32_disable_crtc,
.phantom_crtc_post_enable = optc32_phantom_crtc_post_enable,
+ .disable_phantom_crtc = optc32_disable_phantom_otg,
/* used by enable_timing_synchronization. Not need for FPGA */
.is_counter_moving = optc1_is_counter_moving,
.get_position = optc1_get_position,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index a88dd7b3d1c1..e4dbc8353ea3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -106,8 +106,6 @@ enum dcn32_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
#define BASE(seg) BASE_INNER(seg)
@@ -167,6 +165,9 @@ enum dcn32_clk_src_array_id {
REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## temp_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define DCCG_SRII(reg_name, block, id)\
REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
@@ -722,8 +723,9 @@ static const struct dc_debug_options debug_defaults_drv = {
/* Must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/
.enable_double_buffered_dsc_pg_support = true,
.enable_dp_dig_pixel_rate_div_policy = 1,
- .allow_sw_cursor_fallback = false,
+ .allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback"
.alloc_extra_way_for_cursor = true,
+ .min_prefetch_in_strobe_ns = 60000, // 60us
};
static const struct dc_debug_options debug_defaults_diags = {
@@ -829,6 +831,7 @@ static struct clock_source *dcn32_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1678,7 +1681,7 @@ static void dcn32_enable_phantom_plane(struct dc *dc,
/* Shadow pipe has small viewport. */
phantom_plane->clip_rect.y = 0;
- phantom_plane->clip_rect.height = phantom_stream->timing.v_addressable;
+ phantom_plane->clip_rect.height = phantom_stream->src.height;
phantom_plane->is_phantom = true;
@@ -1718,8 +1721,29 @@ static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc,
return phantom_stream;
}
+void dcn32_retain_phantom_pipes(struct dc *dc, struct dc_state *context)
+{
+ int i;
+ struct dc_plane_state *phantom_plane = NULL;
+ struct dc_stream_state *phantom_stream = NULL;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+ if (!pipe->top_pipe && !pipe->prev_odm_pipe &&
+ pipe->plane_state && pipe->stream &&
+ pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ phantom_plane = pipe->plane_state;
+ phantom_stream = pipe->stream;
+
+ dc_plane_state_retain(phantom_plane);
+ dc_stream_retain(phantom_stream);
+ }
+ }
+}
+
// return true if removed piped from ctx, false otherwise
-bool dcn32_remove_phantom_pipes(struct dc *dc, struct dc_state *context)
+bool dcn32_remove_phantom_pipes(struct dc *dc, struct dc_state *context, bool fast_update)
{
int i;
bool removed_pipe = false;
@@ -1746,14 +1770,23 @@ bool dcn32_remove_phantom_pipes(struct dc *dc, struct dc_state *context)
removed_pipe = true;
}
- // Clear all phantom stream info
- if (pipe->stream) {
- pipe->stream->mall_stream_config.type = SUBVP_NONE;
- pipe->stream->mall_stream_config.paired_stream = NULL;
- }
+ /* For non-full updates, a shallow copy of the current state
+ * is created. In this case we don't want to erase the current
+ * state (there can be 2 HIRQL threads, one in flip, and one in
+ * checkMPO) that can cause a race condition.
+ *
+ * This is just a workaround, needs a proper fix.
+ */
+ if (!fast_update) {
+ // Clear all phantom stream info
+ if (pipe->stream) {
+ pipe->stream->mall_stream_config.type = SUBVP_NONE;
+ pipe->stream->mall_stream_config.paired_stream = NULL;
+ }
- if (pipe->plane_state) {
- pipe->plane_state->is_phantom = false;
+ if (pipe->plane_state) {
+ pipe->plane_state->is_phantom = false;
+ }
}
}
return removed_pipe;
@@ -1900,7 +1933,7 @@ int dcn32_populate_dml_pipes_from_context(
pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal;
if (context->stream_count == 1 &&
- context->stream_status[0].plane_count <= 1 &&
+ context->stream_status[0].plane_count == 1 &&
!dc_is_hdmi_signal(res_ctx->pipe_ctx[i].stream->signal) &&
is_h_timing_divisible_by_2(res_ctx->pipe_ctx[i].stream) &&
pipe->stream->timing.pix_clk_100hz * 100 > DCN3_2_VMIN_DISPCLK_HZ &&
@@ -1918,30 +1951,36 @@ int dcn32_populate_dml_pipes_from_context(
timing = &pipe->stream->timing;
pipes[pipe_cnt].pipe.src.gpuvm = true;
- pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
- pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+ DC_FP_START();
+ dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt);
+ DC_FP_END();
pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_19;
- switch (pipe->stream->mall_stream_config.type) {
- case SUBVP_MAIN:
- pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport;
- subvp_in_use = true;
- break;
- case SUBVP_PHANTOM:
- pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe;
- pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;
- // Disallow unbounded req for SubVP according to DCHUB programming guide
- pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
- break;
- case SUBVP_NONE:
- pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_disable;
- pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;
- break;
- default:
- break;
+ /* Only populate DML input with subvp info for full updates.
+ * This is just a workaround -- needs a proper fix.
+ */
+ if (!fast_validate) {
+ switch (pipe->stream->mall_stream_config.type) {
+ case SUBVP_MAIN:
+ pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport;
+ subvp_in_use = true;
+ break;
+ case SUBVP_PHANTOM:
+ pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe;
+ pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;
+ // Disallow unbounded req for SubVP according to DCHUB programming guide
+ pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
+ break;
+ case SUBVP_NONE:
+ pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_disable;
+ pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;
+ break;
+ default:
+ break;
+ }
}
pipes[pipe_cnt].dout.dsc_input_bpc = 0;
@@ -2029,6 +2068,9 @@ static struct resource_funcs dcn32_res_pool_funcs = {
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
.add_phantom_pipes = dcn32_add_phantom_pipes,
.remove_phantom_pipes = dcn32_remove_phantom_pipes,
+ .retain_phantom_pipes = dcn32_retain_phantom_pipes,
+ .save_mall_state = dcn32_save_mall_state,
+ .restore_mall_state = dcn32_restore_mall_state,
};
@@ -2115,16 +2157,20 @@ static bool dcn32_resource_construct(
dc->caps.cache_num_ways = 16;
dc->caps.max_cab_allocation_bytes = 67108864; // 64MB = 1024 * 1024 * 64
dc->caps.subvp_fw_processing_delay_us = 15;
+ dc->caps.subvp_drr_max_vblank_margin_us = 40;
dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
dc->caps.subvp_swath_height_margin_lines = 16;
dc->caps.subvp_pstate_allow_width_us = 20;
dc->caps.subvp_vertical_int_margin_us = 30;
+ dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin
dc->caps.max_slave_planes = 2;
dc->caps.max_slave_yuv_planes = 2;
dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ if (dc->config.forceHBR2CP2520)
+ dc->caps.force_dp_tps4_for_cp2520 = false;
dc->caps.dp_hpo = true;
dc->caps.dp_hdmi21_pcon_support = true;
dc->caps.edp_dsc_support = true;
@@ -2408,6 +2454,9 @@ static bool dcn32_resource_construct(
pool->base.oem_device = NULL;
}
+ if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev) && (dc->config.sdpif_request_limit_words_per_umc == 0))
+ dc->config.sdpif_request_limit_words_per_umc = 16;
+
DC_FP_END();
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index f76120e67c16..13fbc574910b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -45,17 +45,6 @@
extern struct _vcs_dpi_ip_params_st dcn3_2_ip;
extern struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc;
-/* Temp struct used to save and restore MALL config
- * during validation.
- *
- * TODO: Move MALL config into dc_state instead of stream struct
- * to avoid needing to save/restore.
- */
-struct mall_temp_config {
- struct mall_stream_config mall_stream_config[MAX_PIPES];
- bool is_phantom_plane[MAX_PIPES];
-};
-
struct dcn32_resource_pool {
struct resource_pool base;
};
@@ -81,6 +70,9 @@ bool dcn32_release_post_bldn_3dlut(
struct dc_transfer_func **shaper);
bool dcn32_remove_phantom_pipes(struct dc *dc,
+ struct dc_state *context, bool fast_update);
+
+void dcn32_retain_phantom_pipes(struct dc *dc,
struct dc_state *context);
void dcn32_add_phantom_pipes(struct dc *dc,
@@ -1244,7 +1236,8 @@ void dcn32_restore_mall_state(struct dc *dc,
SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C), \
SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D), \
SR(DCN_VM_FAULT_ADDR_MSB), SR(DCN_VM_FAULT_ADDR_LSB), \
- SR(DCN_VM_FAULT_CNTL), SR(DCN_VM_FAULT_STATUS) \
+ SR(DCN_VM_FAULT_CNTL), SR(DCN_VM_FAULT_STATUS), \
+ SR(SDPIF_REQUEST_RATE_LIMIT) \
)
/* DCCG */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index b03a7814e96d..783935c4e664 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -97,21 +97,21 @@ uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_stat
* FLOOR(vp_x_start, blk_width)
*/
full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x +
- pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) +
+ pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) -
(pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width);
/* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) -
* FLOOR(vp_y_start, blk_height)
*/
full_vp_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y +
- full_vp_height + mblk_height - 1) / mblk_height * mblk_height) +
+ full_vp_height + mblk_height - 1) / mblk_height * mblk_height) -
(pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height);
/* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */
mall_alloc_width_blk_aligned = full_vp_width_blk_aligned;
/* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */
- mall_alloc_height_blk_aligned = (pipe->stream->timing.v_addressable - 1 + mblk_height - 1) /
+ mall_alloc_height_blk_aligned = (pipe->plane_res.scl_data.viewport.height - 1 + mblk_height - 1) /
mblk_height * mblk_height + mblk_height;
/* full_mblk_width_ub_l/c = mall_alloc_width_blk_aligned_l/c;
@@ -121,14 +121,19 @@ uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_stat
*/
num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
+
+ /*For DCC:
+ * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1)
+ */
+ if (pipe->plane_state->dcc.enable)
+ num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel +
+ (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES);
+
bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES;
// cache lines used is total bytes / cache_line size. Add +2 for worst case alignment
// (MALL is 64-byte aligned)
cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2;
- /* For DCC divide by 256 */
- if (pipe->plane_state->dcc.enable)
- cache_lines_per_plane = cache_lines_per_plane + (cache_lines_per_plane / 256) + 1;
cache_lines_used += cache_lines_per_plane;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index 61087f2385a9..d1f36df03c2e 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -109,8 +109,6 @@ enum dcn321_clk_src_array_id {
*/
/* DCN */
-/* TODO awful hack. fixup dcn20_dwb.h */
-#undef BASE_INNER
#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
#define BASE(seg) BASE_INNER(seg)
@@ -174,6 +172,9 @@ enum dcn321_clk_src_array_id {
REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
#define VUPDATE_SRII(reg_name, block, id)\
REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \
reg ## reg_name ## _ ## block ## id
@@ -720,8 +721,9 @@ static const struct dc_debug_options debug_defaults_drv = {
/*must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/
.enable_double_buffered_dsc_pg_support = true,
.enable_dp_dig_pixel_rate_div_policy = 1,
- .allow_sw_cursor_fallback = false,
+ .allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback"
.alloc_extra_way_for_cursor = true,
+ .min_prefetch_in_strobe_ns = 60000, // 60us
};
static const struct dc_debug_options debug_defaults_diags = {
@@ -741,7 +743,7 @@ static const struct dc_debug_options debug_defaults_diags = {
.dmub_command_table = true,
.enable_tri_buf = true,
.use_max_lb = true,
- .force_disable_subvp = true
+ .force_disable_subvp = true,
};
@@ -828,6 +830,7 @@ static struct clock_source *dcn321_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1618,6 +1621,9 @@ static struct resource_funcs dcn321_res_pool_funcs = {
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
.add_phantom_pipes = dcn32_add_phantom_pipes,
.remove_phantom_pipes = dcn32_remove_phantom_pipes,
+ .retain_phantom_pipes = dcn32_retain_phantom_pipes,
+ .save_mall_state = dcn32_save_mall_state,
+ .restore_mall_state = dcn32_restore_mall_state,
};
@@ -1703,10 +1709,12 @@ static bool dcn321_resource_construct(
dc->caps.cache_num_ways = 16;
dc->caps.max_cab_allocation_bytes = 33554432; // 32MB = 1024 * 1024 * 32
dc->caps.subvp_fw_processing_delay_us = 15;
+ dc->caps.subvp_drr_max_vblank_margin_us = 40;
dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
dc->caps.subvp_swath_height_margin_lines = 16;
dc->caps.subvp_pstate_allow_width_us = 20;
dc->caps.subvp_vertical_int_margin_us = 30;
+ dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin
dc->caps.max_slave_planes = 1;
dc->caps.max_slave_yuv_planes = 1;
dc->caps.max_slave_rgb_planes = 1;
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index e3e5c39895a3..af1c50ed905a 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -116,6 +116,11 @@ bool dm_helpers_dp_mst_start_top_mgr(
bool dm_helpers_dp_mst_stop_top_mgr(
struct dc_context *ctx,
struct dc_link *link);
+
+void dm_helpers_dp_mst_update_branch_bandwidth(
+ struct dc_context *ctx,
+ struct dc_link *link);
+
/**
* OS specific aux read callback.
*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index ca7d24000621..0ecea87cf48f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -33,6 +33,10 @@ ifdef CONFIG_PPC64
dml_ccflags := -mhard-float -maltivec
endif
+ifdef CONFIG_ARM64
+dml_rcflags := -mgeneral-regs-only
+endif
+
ifdef CONFIG_CC_IS_GCC
ifneq ($(call gcc-min-version, 70100),y)
IS_OLD_GCC = 1
@@ -55,8 +59,6 @@ frame_warn_flag := -Wframe-larger-than=2048
endif
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
-
-ifdef CONFIG_DRM_AMD_DC_DCN
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags)
@@ -88,7 +90,6 @@ CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calcs.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_auto.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_math.o := $(dml_ccflags) -Wno-tautological-compare
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn2x/dcn2x.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_rcflags)
@@ -105,7 +106,18 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_util_32.o := $(dml_rcf
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_rcflags)
-endif
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn314/display_mode_vba_314.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn314/display_rq_dlg_calc_314.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn314/dcn314_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/dcn30_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn32/dcn32_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn321/dcn321_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/dcn31_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn302/dcn302_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn303/dcn303_fpu.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_math.o := $(dml_rcflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_ccflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_rcflags)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h
index 74e86732e301..2cbdd75429ff 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h
@@ -29,6 +29,13 @@
#define DC__PRESENT 1
#define DC__PRESENT__1 1
#define DC__NUM_DPP 4
+
+/**
+ * @DC__VOLTAGE_STATES:
+ *
+ * Define the maximum amount of states supported by the ASIC. Every ASIC has a
+ * specific number of states; this macro defines the maximum number of states.
+ */
#define DC__VOLTAGE_STATES 20
#define DC__NUM_DPP__4 1
#define DC__NUM_DPP__0_PRESENT 1
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
index 99644d896222..c5e84190c17a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
@@ -27,6 +27,8 @@
#include "dcn10/dcn10_resource.h"
#include "dcn10_fpu.h"
+#include "resource.h"
+#include "amdgpu_dm/dc_fpu.h"
/**
* DOC: DCN10 FPU manipulation Overview
@@ -121,3 +123,37 @@ struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = {
.writeback_dram_clock_change_latency_us = 23.0,
.return_bus_width_bytes = 64,
};
+
+void dcn10_resource_construct_fp(struct dc *dc)
+{
+ dc_assert_fp_enabled();
+ if (dc->ctx->dce_version == DCN_VERSION_1_01) {
+ struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc;
+ struct dcn_ip_params *dcn_ip = dc->dcn_ip;
+ struct display_mode_lib *dml = &dc->dml;
+
+ dml->ip.max_num_dpp = 3;
+ /* TODO how to handle 23.84? */
+ dcn_soc->dram_clock_change_latency = 23;
+ dcn_ip->max_num_dpp = 3;
+ }
+ if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) {
+ dc->dcn_soc->urgent_latency = 3;
+ dc->debug.disable_dmcu = true;
+ dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f;
+ }
+
+ dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width;
+ ASSERT(dc->dcn_soc->number_of_channels < 3);
+ if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/
+ dc->dcn_soc->number_of_channels = 2;
+
+ if (dc->dcn_soc->number_of_channels == 1) {
+ dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f;
+ dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f;
+ dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f;
+ dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f;
+ if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev))
+ dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h
index e74ed4b4ce5b..63219ecd8478 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h
@@ -27,4 +27,6 @@
#ifndef __DCN10_FPU_H__
#define __DCN10_FPU_H__
+void dcn10_resource_construct_fp(struct dc *dc);
+
#endif /* __DCN20_FPU_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
index 45db40c41882..c26da3bb2892 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
@@ -565,7 +565,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
.dppclk_mhz = 847.06,
.phyclk_mhz = 810.0,
.socclk_mhz = 953.0,
- .dscclk_mhz = 489.0,
+ .dscclk_mhz = 300.0,
.dram_speed_mts = 2400.0,
},
{
@@ -576,7 +576,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
.dppclk_mhz = 960.00,
.phyclk_mhz = 810.0,
.socclk_mhz = 278.0,
- .dscclk_mhz = 287.67,
+ .dscclk_mhz = 342.86,
.dram_speed_mts = 2666.0,
},
{
@@ -587,7 +587,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
.dppclk_mhz = 1028.57,
.phyclk_mhz = 810.0,
.socclk_mhz = 715.0,
- .dscclk_mhz = 318.334,
+ .dscclk_mhz = 369.23,
.dram_speed_mts = 3200.0,
},
{
@@ -949,6 +949,7 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
int plane_count;
int i;
unsigned int optimized_min_dst_y_next_start_us;
+ bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > 1000.0;
plane_count = 0;
optimized_min_dst_y_next_start_us = 0;
@@ -963,6 +964,8 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
* 2. single eDP, on link 0, 1 plane and stutter period > 5ms
* Z10 only cases:
* 1. single eDP, on link 0, 1 plane and stutter period >= 5ms
+ * Z8 cases:
+ * 1. stutter period sufficient
* Zstate not allowed cases:
* 1. Everything else
*/
@@ -989,12 +992,15 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000)
return DCN_ZSTATE_SUPPORT_ALLOW;
- else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !dc->debug.disable_psr)
- return DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY;
+ else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr)
+ return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY;
else
- return DCN_ZSTATE_SUPPORT_DISALLOW;
- } else
+ return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY : DCN_ZSTATE_SUPPORT_DISALLOW;
+ } else if (allow_z8) {
+ return DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY;
+ } else {
return DCN_ZSTATE_SUPPORT_DISALLOW;
+ }
}
void dcn20_calculate_dlg_params(
@@ -1296,6 +1302,8 @@ int dcn20_populate_dml_pipes_from_context(
case SIGNAL_TYPE_DISPLAY_PORT_MST:
case SIGNAL_TYPE_DISPLAY_PORT:
pipes[pipe_cnt].dout.output_type = dm_dp;
+ if (is_dp_128b_132b_signal(&res_ctx->pipe_ctx[i]))
+ pipes[pipe_cnt].dout.output_type = dm_dp2p0;
break;
case SIGNAL_TYPE_EDP:
pipes[pipe_cnt].dout.output_type = dm_edp;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
index e1e92daba668..d4c0f9cdac8e 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
@@ -520,9 +520,7 @@ void dcn30_fpu_calculate_wm_and_dlg(
pipe_idx++;
}
- DC_FP_START();
dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
- DC_FP_END();
if (!pstate_en)
/* Restore full p-state latency */
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
index 479e2c1a1301..379729b02847 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
@@ -4851,7 +4851,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->SwathHeightYThisState[k],
v->SwathHeightCThisState[k],
v->HTotal[k] / v->PixelClock[k],
- v->UrgentLatency,
+ v->UrgLatency[i],
v->CursorBufferSize,
v->CursorWidth[k][0],
v->CursorBPP[k][0],
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
index 7dd0845d1bd9..b37d14369a62 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
@@ -483,7 +483,7 @@ void dcn31_calculate_wm_and_dlg_fp(
int pipe_cnt,
int vlevel)
{
- int i, pipe_idx, active_dpp_count = 0;
+ int i, pipe_idx, active_hubp_count = 0;
double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
dc_assert_fp_enabled();
@@ -529,7 +529,7 @@ void dcn31_calculate_wm_and_dlg_fp(
continue;
if (context->res_ctx.pipe_ctx[i].plane_state)
- active_dpp_count++;
+ active_hubp_count++;
pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
@@ -547,9 +547,22 @@ void dcn31_calculate_wm_and_dlg_fp(
}
dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
- /* For 31x apu pstate change is only supported if possible in vactive or if there are no active dpps */
+ /* For 31x apu pstate change is only supported if possible in vactive*/
context->bw_ctx.bw.dcn.clk.p_state_change_support =
- context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_dram_clock_change_vactive || !active_dpp_count;
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_dram_clock_change_vactive;
+ /* If DCN isn't making memory requests we can allow pstate change and lower clocks */
+ if (!active_hubp_count) {
+ context->bw_ctx.bw.dcn.clk.socclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dcfclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dramclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.fclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
+ for (i = 0; i < dc->res_pool->pipe_count; i++)
+ if (context->res_ctx.pipe_ctx[i].stream)
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = 0;
+ }
}
void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
@@ -797,3 +810,8 @@ void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
else
dml_init_instance(&dc->dml, &dcn3_16_soc, &dcn3_16_ip, DML_PROJECT_DCN31_FPGA);
}
+
+int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc)
+{
+ return soc->clock_limits[0].dispclk_mhz * 10000.0 / (1.0 + soc->dcn_downspread_percent / 100.0);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
index fd58b2561ec9..687d3522cc33 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
@@ -46,5 +46,10 @@ void dcn31_calculate_wm_and_dlg_fp(
void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc);
+int dcn31x_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate);
#endif /* __DCN31_FPU_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
index b612edb14417..ec351c8418cb 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
@@ -1052,17 +1052,16 @@ static bool CalculatePrefetchSchedule(
else
bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC;
/*rev 99*/
- prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane);
+ prefetch_bw_pr = bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane;
+ prefetch_bw_pr = dml_min(1, myPipe->VRatio) * prefetch_bw_pr;
max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime;
prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC;
- prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime));
prefetch_bw_oto = dml_max(prefetch_bw_pr, prefetch_sw_bytes / max_Tsw);
min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre);
Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4;
Tsw_oto = Lsw_oto * LineTime;
- prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC) / Tsw_oto;
#ifdef __DML_VBA_DEBUG__
dml_print("DML: HTotal: %d\n", myPipe->HTotal);
@@ -5083,7 +5082,7 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->SwathHeightYThisState[k],
v->SwathHeightCThisState[k],
v->HTotal[k] / v->PixelClock[k],
- v->UrgentLatency,
+ v->UrgLatency[i],
v->CursorBufferSize,
v->CursorWidth[k][0],
v->CursorBPP[k][0],
@@ -5361,6 +5360,58 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->ModeSupport[i][j] = true;
} else {
v->ModeSupport[i][j] = false;
+#ifdef __DML_VBA_DEBUG__
+ if (v->ScaleRatioAndTapsSupport == false)
+ dml_print("DML SUPPORT: ScaleRatioAndTapsSupport failed");
+ if (v->SourceFormatPixelAndScanSupport == false)
+ dml_print("DML SUPPORT: SourceFormatPixelAndScanSupport failed");
+ if (v->ViewportSizeSupport[i][j] == false)
+ dml_print("DML SUPPORT: ViewportSizeSupport failed");
+ if (v->LinkCapacitySupport[i] == false)
+ dml_print("DML SUPPORT: LinkCapacitySupport failed");
+ if (v->ODMCombine4To1SupportCheckOK[i] == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported failed");
+ if (v->NotEnoughDSCUnits[i] == true)
+ dml_print("DML SUPPORT: NotEnoughDSCUnits");
+ if (v->DTBCLKRequiredMoreThanSupported[i] == true)
+ dml_print("DML SUPPORT: DTBCLKRequiredMoreThanSupported");
+ if (v->ROBSupport[i][j] == false)
+ dml_print("DML SUPPORT: ROBSupport failed");
+ if (v->DISPCLK_DPPCLK_Support[i][j] == false)
+ dml_print("DML SUPPORT: DISPCLK_DPPCLK_Support failed");
+ if (v->TotalAvailablePipesSupport[i][j] == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported failed");
+ if (EnoughWritebackUnits == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported failed");
+ if (v->WritebackLatencySupport == false)
+ dml_print("DML SUPPORT: WritebackLatencySupport failed");
+ if (v->WritebackScaleRatioAndTapsSupport == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported ");
+ if (v->CursorSupport == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported failed");
+ if (v->PitchSupport == false)
+ dml_print("DML SUPPORT: PitchSupport failed");
+ if (ViewportExceedsSurface == true)
+ dml_print("DML SUPPORT: ViewportExceedsSurface failed");
+ if (v->PrefetchSupported[i][j] == false)
+ dml_print("DML SUPPORT: PrefetchSupported failed");
+ if (v->DynamicMetadataSupported[i][j] == false)
+ dml_print("DML SUPPORT: DSC422NativeNotSupported failed");
+ if (v->TotalVerticalActiveBandwidthSupport[i][j] == false)
+ dml_print("DML SUPPORT: TotalVerticalActiveBandwidthSupport failed");
+ if (v->VRatioInPrefetchSupported[i][j] == false)
+ dml_print("DML SUPPORT: VRatioInPrefetchSupported failed");
+ if (v->PTEBufferSizeNotExceeded[i][j] == false)
+ dml_print("DML SUPPORT: PTEBufferSizeNotExceeded failed");
+ if (v->NonsupportedDSCInputBPC == true)
+ dml_print("DML SUPPORT: NonsupportedDSCInputBPC failed");
+ if (!((v->HostVMEnable == false
+ && v->ImmediateFlipRequirement[0] != dm_immediate_flip_required)
+ || v->ImmediateFlipSupportedForState[i][j] == true))
+ dml_print("DML SUPPORT: ImmediateFlipRequirement failed");
+ if (FMTBufferExceeded == true)
+ dml_print("DML SUPPORT: FMTBufferExceeded failed");
+#endif
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
index cf420ad2b8dc..6a1cf6adea77 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
@@ -29,6 +29,7 @@
#include "dcn31/dcn31_hubbub.h"
#include "dcn314_fpu.h"
#include "dml/dcn20/dcn20_fpu.h"
+#include "dml/dcn31/dcn31_fpu.h"
#include "dml/display_mode_vba.h"
struct _vcs_dpi_ip_params_st dcn3_14_ip = {
@@ -146,10 +147,10 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = {
},
},
.num_states = 5,
- .sr_exit_time_us = 9.0,
- .sr_enter_plus_exit_time_us = 11.0,
- .sr_exit_z8_time_us = 442.0,
- .sr_enter_plus_exit_z8_time_us = 560.0,
+ .sr_exit_time_us = 16.5,
+ .sr_enter_plus_exit_time_us = 18.5,
+ .sr_exit_z8_time_us = 280.0,
+ .sr_enter_plus_exit_z8_time_us = 350.0,
.writeback_latency_us = 12.0,
.dram_channel_width_bytes = 4,
.round_trip_ping_latency_dcfclk_cycles = 106,
@@ -264,11 +265,8 @@ void dcn314_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p
dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
}
- if ((int)(dcn3_14_soc.dram_clock_change_latency_us * 1000)
- != dc->debug.dram_clock_change_latency_ns
- && dc->debug.dram_clock_change_latency_ns) {
- dcn3_14_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000;
- }
+ dcn20_patch_bounding_box(dc, &dcn3_14_soc);
+
if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN314);
else
@@ -291,7 +289,7 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
dc_assert_fp_enabled();
- dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
struct dc_crtc_timing *timing;
@@ -318,8 +316,6 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
pipes[pipe_cnt].pipe.src.immediate_flip = true;
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
- pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
- pipes[pipe_cnt].pipe.src.gpuvm = true;
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
index 0d12fd079cd6..950669f2c10d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
@@ -1074,17 +1074,16 @@ static bool CalculatePrefetchSchedule(
else
bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC;
/*rev 99*/
- prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane);
+ prefetch_bw_pr = bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane;
+ prefetch_bw_pr = dml_min(1, myPipe->VRatio) * prefetch_bw_pr;
max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime;
prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC;
- prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime));
prefetch_bw_oto = dml_max(prefetch_bw_pr, prefetch_sw_bytes / max_Tsw);
min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre);
Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4;
Tsw_oto = Lsw_oto * LineTime;
- prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC) / Tsw_oto;
#ifdef __DML_VBA_DEBUG__
dml_print("DML: HTotal: %d\n", myPipe->HTotal);
@@ -5180,7 +5179,7 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_
v->SwathHeightYThisState[k],
v->SwathHeightCThisState[k],
v->HTotal[k] / v->PixelClock[k],
- v->UrgentLatency,
+ v->UrgLatency[i],
v->CursorBufferSize,
v->CursorWidth[k][0],
v->CursorBPP[k][0],
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index f37c9a6b3b7e..f94abd124021 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -157,7 +157,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = {
.dispclk_dppclk_vco_speed_mhz = 4300.0,
.do_urgent_latency_adjustment = true,
.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 3000,
};
void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
@@ -211,7 +211,7 @@ void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
/* 'DalDummyClockChangeLatencyNs' registry key option set to 0x7FFFFFFF can be used to disable Set C for dummy p-state */
if (clk_mgr->base.ctx->dc->bb_overrides.dummy_clock_change_latency_ns != 0x7FFFFFFF) {
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].valid = true;
- clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us = 38;
+ clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us = 50;
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.fclk_change_latency_us = fclk_change_latency_us;
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us = sr_exit_time_us;
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
@@ -221,7 +221,7 @@ void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_uclk = min_uclk_mhz;
clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_uclk = 0xFFFF;
clk_mgr->base.bw_params->dummy_pstate_table[0].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[0].memclk_mhz * 16;
- clk_mgr->base.bw_params->dummy_pstate_table[0].dummy_pstate_latency_us = 38;
+ clk_mgr->base.bw_params->dummy_pstate_table[0].dummy_pstate_latency_us = 50;
clk_mgr->base.bw_params->dummy_pstate_table[1].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[1].memclk_mhz * 16;
clk_mgr->base.bw_params->dummy_pstate_table[1].dummy_pstate_latency_us = 9;
clk_mgr->base.bw_params->dummy_pstate_table[2].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz * 16;
@@ -256,16 +256,24 @@ int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
int vlevel)
{
const int max_latency_table_entries = 4;
- const struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
+ struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
int dummy_latency_index = 0;
+ enum clock_change_support temp_clock_change_support = vba->DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
dc_assert_fp_enabled();
while (dummy_latency_index < max_latency_table_entries) {
+ if (temp_clock_change_support != dm_dram_clock_change_unsupported)
+ vba->DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = temp_clock_change_support;
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
+ /* for subvp + DRR case, if subvp pipes are still present we support pstate */
+ if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported &&
+ dcn32_subvp_in_use(dc, context))
+ vba->DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = temp_clock_change_support;
+
if (vlevel < context->bw_ctx.dml.vba.soc.num_states &&
vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported)
break;
@@ -531,9 +539,12 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
unsigned int i, pipe_idx;
struct pipe_ctx *pipe;
uint32_t phantom_vactive, phantom_bp, pstate_width_fw_delay_lines;
+ unsigned int num_dpp;
unsigned int vlevel = context->bw_ctx.dml.vba.VoltageLevel;
unsigned int dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
unsigned int socclk = context->bw_ctx.dml.vba.SOCCLKPerState[vlevel];
+ struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
+ struct dc_stream_state *main_stream = ref_pipe->stream;
dc_assert_fp_enabled();
@@ -569,13 +580,26 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
phantom_vactive = get_subviewport_lines_needed_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx) +
pstate_width_fw_delay_lines + dc->caps.subvp_swath_height_margin_lines;
+ // W/A for DCC corruption with certain high resolution timings.
+ // Determing if pipesplit is used. If so, add meta_row_height to the phantom vactive.
+ num_dpp = vba->NoOfDPP[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]];
+ phantom_vactive += num_dpp > 1 ? vba->meta_row_height[vba->pipe_plane[pipe_idx]] : 0;
+
+ /* dc->debug.subvp_extra_lines 0 by default*/
+ phantom_vactive += dc->debug.subvp_extra_lines;
+
// For backporch of phantom pipe, use vstartup of the main pipe
phantom_bp = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
phantom_stream->dst.y = 0;
phantom_stream->dst.height = phantom_vactive;
+ /* When scaling, DML provides the end to end required number of lines for MALL.
+ * dst.height is always correct for this case, but src.height is not which causes a
+ * delta between main and phantom pipe scaling outputs. Need to adjust src.height on
+ * phantom for this case.
+ */
phantom_stream->src.y = 0;
- phantom_stream->src.height = phantom_vactive;
+ phantom_stream->src.height = (double)phantom_vactive * (double)main_stream->src.height / (double)main_stream->dst.height;
phantom_stream->timing.v_addressable = phantom_vactive;
phantom_stream->timing.v_front_porch = 1;
@@ -1128,7 +1152,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final ==
dm_prefetch_support_uclk_fclk_and_stutter) {
context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
- dm_prefetch_support_stutter;
+ dm_prefetch_support_fclk_and_stutter;
/* There are params (such as FabricClock) that need to be recalculated
* after validation fails (otherwise it will be 0). Calculation for
* phantom vactive requires call into DML, so we must ensure all the
@@ -1179,7 +1203,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
// If SubVP pipe config is unsupported (or cannot be used for UCLK switching)
// remove phantom pipes and repopulate dml pipes
if (!found_supported_config) {
- dc->res_pool->funcs->remove_phantom_pipes(dc, context);
+ dc->res_pool->funcs->remove_phantom_pipes(dc, context, false);
vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] = dm_dram_clock_change_unsupported;
*pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false);
@@ -1191,9 +1215,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
}
} else {
// Most populate phantom DLG params before programming hardware / timing for phantom pipe
- DC_FP_START();
dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt);
- DC_FP_END();
/* Call validate_apply_pipe_split flags after calling DML getters for
* phantom dlg params, or some of the VBA params indicating pipe split
@@ -1230,7 +1252,7 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
int pipe_cnt, int vlevel)
{
- int i, pipe_idx;
+ int i, pipe_idx, active_hubp_count = 0;
bool usr_retraining_support = false;
bool unbounded_req_enabled = false;
@@ -1275,6 +1297,8 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
+ if (context->res_ctx.pipe_ctx[i].plane_state)
+ active_hubp_count++;
pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt,
pipe_idx);
pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
@@ -1296,10 +1320,23 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
- context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+ if (context->res_ctx.pipe_ctx[i].plane_state)
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+ else
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = 0;
context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
pipe_idx++;
}
+ /* If DCN isn't making memory requests we can allow pstate change and lower clocks */
+ if (!active_hubp_count) {
+ context->bw_ctx.bw.dcn.clk.socclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dcfclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = 0;
+ context->bw_ctx.bw.dcn.clk.dramclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.fclk_khz = 0;
+ context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
+ }
/*save a original dppclock copy*/
context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
@@ -1481,7 +1518,7 @@ bool dcn32_internal_validate_bw(struct dc *dc,
return false;
// For each full update, remove all existing phantom pipes first
- dc->res_pool->funcs->remove_phantom_pipes(dc, context);
+ dc->res_pool->funcs->remove_phantom_pipes(dc, context, fast_validate);
dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
@@ -1494,11 +1531,8 @@ bool dcn32_internal_validate_bw(struct dc *dc,
dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
- if (!fast_validate) {
- DC_FP_START();
+ if (!fast_validate)
dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt);
- DC_FP_END();
- }
if (fast_validate ||
(dc->debug.dml_disallow_alternate_prefetch_modes &&
@@ -1734,6 +1768,10 @@ bool dcn32_internal_validate_bw(struct dc *dc,
}
if (repopulate_pipes) {
+ int flag_max_mpc_comb = vba->maxMpcComb;
+ int flag_vlevel = vlevel;
+ int i;
+
pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
/* repopulate_pipes = 1 means the pipes were either split or merged. In this case
@@ -1741,10 +1779,28 @@ bool dcn32_internal_validate_bw(struct dc *dc,
* ensure all the params are calculated correctly. We do not need to run the
* pipe split check again after this call (pipes are already split / merged).
* */
- if (!fast_validate) {
- context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
- dm_prefetch_support_uclk_fclk_and_stutter_if_possible;
- vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
+ context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+ dm_prefetch_support_uclk_fclk_and_stutter_if_possible;
+ vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
+ if (vlevel == context->bw_ctx.dml.soc.num_states) {
+ /* failed after DET size changes */
+ goto validate_fail;
+ } else if (flag_max_mpc_comb == 0 &&
+ flag_max_mpc_comb != context->bw_ctx.dml.vba.maxMpcComb) {
+ /* check the context constructed with pipe split flags is still valid*/
+ bool flags_valid = false;
+ for (i = flag_vlevel; i < context->bw_ctx.dml.soc.num_states; i++) {
+ if (vba->ModeSupport[i][flag_max_mpc_comb]) {
+ vba->maxMpcComb = flag_max_mpc_comb;
+ vba->VoltageLevel = i;
+ vlevel = i;
+ flags_valid = true;
+ }
+ }
+
+ /* this should never happen */
+ if (!flags_valid)
+ goto validate_fail;
}
}
*vlevel_out = vlevel;
@@ -1775,14 +1831,38 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
unsigned int dummy_latency_index = 0;
int maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
+ bool subvp_in_use = dcn32_subvp_in_use(dc, context);
unsigned int min_dram_speed_mts_margin;
+ bool need_fclk_lat_as_dummy = false;
+ bool is_subvp_p_drr = true;
dc_assert_fp_enabled();
- // Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK
- if (!pstate_en && dcn32_subvp_in_use(dc, context)) {
- context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
- pstate_en = true;
+ /* need to find dummy latency index for subvp */
+ if (subvp_in_use) {
+ /* Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK */
+ if (!pstate_en) {
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+ pstate_en = true;
+ is_subvp_p_drr = true;
+ }
+ dummy_latency_index = dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(dc,
+ context, pipes, pipe_cnt, vlevel);
+
+ /* For DCN32/321 need to validate with fclk pstate change latency equal to dummy so prefetch is
+ * scheduled correctly to account for dummy pstate.
+ */
+ if (context->bw_ctx.dml.soc.fclk_change_latency_us < dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us) {
+ need_fclk_lat_as_dummy = true;
+ context->bw_ctx.dml.soc.fclk_change_latency_us =
+ dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
+ }
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us =
+ dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
+ dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
+ if (is_subvp_p_drr) {
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+ }
}
context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
@@ -1803,6 +1883,14 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
*/
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
+ /* For DCN32/321 need to validate with fclk pstate change latency equal to dummy so
+ * prefetch is scheduled correctly to account for dummy pstate.
+ */
+ if (context->bw_ctx.dml.soc.fclk_change_latency_us < dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us) {
+ need_fclk_lat_as_dummy = true;
+ context->bw_ctx.dml.soc.fclk_change_latency_us =
+ dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
+ }
dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
dcfclk_from_fw_based_mclk_switching = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
@@ -1904,13 +1992,13 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
if (context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] ==
dm_dram_clock_change_unsupported) {
- int min_dram_speed_mts_offset = dc->clk_mgr->bw_params->clk_table.num_entries - 1;
+ int min_dram_speed_mts_offset = dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_memclk_levels - 1;
min_dram_speed_mts =
dc->clk_mgr->bw_params->clk_table.entries[min_dram_speed_mts_offset].memclk_mhz * 16;
}
- if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
+ if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && !subvp_in_use) {
/* find largest table entry that is lower than dram speed,
* but lower than DPM0 still uses DPM0
*/
@@ -1990,6 +2078,11 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
+ /* for proper prefetch calculations, if dummy lat > fclk lat, use fclk lat = dummy lat */
+ if (need_fclk_lat_as_dummy)
+ context->bw_ctx.dml.soc.fclk_change_latency_us =
+ dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
+
dcn32_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
if (!pstate_en)
@@ -1997,8 +2090,14 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
- if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching)
+ if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(dc, context);
+ }
+
+ /* revert fclk lat changes if required */
+ if (need_fclk_lat_as_dummy)
+ context->bw_ctx.dml.soc.fclk_change_latency_us =
+ dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.fclk_change_latency_us;
}
static void dcn32_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
@@ -2145,9 +2244,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
entry.fabricclk_mhz = 0;
entry.dram_speed_mts = 0;
- DC_FP_START();
insert_entry_into_table_sorted(table, num_entries, &entry);
- DC_FP_END();
}
// Insert the max DCFCLK
@@ -2155,9 +2252,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
entry.fabricclk_mhz = 0;
entry.dram_speed_mts = 0;
- DC_FP_START();
insert_entry_into_table_sorted(table, num_entries, &entry);
- DC_FP_END();
// Insert the UCLK DPMS
for (i = 0; i < num_uclk_dpms; i++) {
@@ -2165,9 +2260,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
entry.fabricclk_mhz = 0;
entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
- DC_FP_START();
insert_entry_into_table_sorted(table, num_entries, &entry);
- DC_FP_END();
}
// If FCLK is coarse grained, insert individual DPMs.
@@ -2177,9 +2270,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
entry.dram_speed_mts = 0;
- DC_FP_START();
insert_entry_into_table_sorted(table, num_entries, &entry);
- DC_FP_END();
}
}
// If FCLK fine grained, only insert max
@@ -2188,9 +2279,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
entry.fabricclk_mhz = max_fclk_mhz;
entry.dram_speed_mts = 0;
- DC_FP_START();
insert_entry_into_table_sorted(table, num_entries, &entry);
- DC_FP_END();
}
// At this point, the table contains all "points of interest" based on
@@ -2364,6 +2453,8 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
/* DML DSC delay factor workaround */
dcn3_2_ip.dsc_delay_factor_wa = dc->debug.dsc_delay_factor_wa_x1000 / 1000.0;
+ dcn3_2_ip.min_prefetch_in_strobe_us = dc->debug.min_prefetch_in_strobe_ns / 1000.0;
+
/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
dcn3_2_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
@@ -2523,3 +2614,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
}
}
+void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
+ int pipe_cnt)
+{
+ dc_assert_fp_enabled();
+
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 3a3dc2ce4c73..ab010e7e840b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -73,4 +73,7 @@ int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
void dcn32_patch_dpm_table(struct clk_bw_params *bw_params);
+void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
+ int pipe_cnt);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
index 3d184679f129..4b8f5fa0f0ad 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
@@ -670,6 +670,25 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->cursor_bw[k] = mode_lib->vba.NumberOfCursors[k] * mode_lib->vba.CursorWidth[k][0] * mode_lib->vba.CursorBPP[k][0] / 8 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * mode_lib->vba.VRatio[k];
}
+ v->NotEnoughDETSwathFillLatencyHiding = dml32_CalculateDETSwathFillLatencyHiding(
+ mode_lib->vba.NumberOfActiveSurfaces,
+ mode_lib->vba.ReturnBW,
+ v->UrgentLatency,
+ mode_lib->vba.SwathHeightY,
+ mode_lib->vba.SwathHeightC,
+ v->swath_width_luma_ub,
+ v->swath_width_chroma_ub,
+ v->BytePerPixelDETY,
+ v->BytePerPixelDETC,
+ mode_lib->vba.DETBufferSizeY,
+ mode_lib->vba.DETBufferSizeC,
+ mode_lib->vba.DPPPerPlane,
+ mode_lib->vba.HTotal,
+ mode_lib->vba.PixelClock,
+ mode_lib->vba.VRatio,
+ mode_lib->vba.VRatioChroma,
+ mode_lib->vba.UsesMALLForPStateChange);
+
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
v->MaxVStartupLines[k] = ((mode_lib->vba.Interlace[k] &&
!mode_lib->vba.ProgressiveToInterlaceUnitInOPP) ?
@@ -718,6 +737,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
do {
MaxTotalRDBandwidth = 0;
+ DestinationLineTimesForPrefetchLessThan2 = false;
+ VRatioPrefetchMoreThanMax = false;
#ifdef __DML_VBA_DEBUG__
dml_print("DML::%s: Start loop: VStartup = %d\n", __func__, mode_lib->vba.VStartupLines);
#endif
@@ -786,6 +807,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->SwathHeightY[k],
v->SwathHeightC[k],
TWait,
+ v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ ?
+ mode_lib->vba.ip.min_prefetch_in_strobe_us : 0,
/* Output */
&v->DSTXAfterScaler[k],
&v->DSTYAfterScaler[k],
@@ -1661,6 +1684,8 @@ static void mode_support_configuration(struct vba_vars_st *v,
&& mode_lib->vba.DCCMetaBufferSizeNotExceeded[i][j] == true
&& mode_lib->vba.NonsupportedDSCInputBPC == false
&& !mode_lib->vba.ExceededMALLSize
+ && (mode_lib->vba.NotEnoughDETSwathFillLatencyHidingPerState[i][j] == false
+ || i == v->soc.num_states - 1)
&& ((mode_lib->vba.HostVMEnable == false
&& !mode_lib->vba.ImmediateFlipRequiredFinal)
|| mode_lib->vba.ImmediateFlipSupportedForState[i][j])
@@ -3154,6 +3179,25 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.UrgentBurstFactorChroma,
mode_lib->vba.UrgentBurstFactorCursor);
+ mode_lib->vba.NotEnoughDETSwathFillLatencyHidingPerState[i][j] = dml32_CalculateDETSwathFillLatencyHiding(
+ mode_lib->vba.NumberOfActiveSurfaces,
+ mode_lib->vba.ReturnBWPerState[i][j],
+ mode_lib->vba.UrgLatency[i],
+ mode_lib->vba.SwathHeightYThisState,
+ mode_lib->vba.SwathHeightCThisState,
+ mode_lib->vba.swath_width_luma_ub_this_state,
+ mode_lib->vba.swath_width_chroma_ub_this_state,
+ mode_lib->vba.BytePerPixelInDETY,
+ mode_lib->vba.BytePerPixelInDETC,
+ mode_lib->vba.DETBufferSizeYThisState,
+ mode_lib->vba.DETBufferSizeCThisState,
+ mode_lib->vba.NoOfDPPThisState,
+ mode_lib->vba.HTotal,
+ mode_lib->vba.PixelClock,
+ mode_lib->vba.VRatio,
+ mode_lib->vba.VRatioChroma,
+ mode_lib->vba.UsesMALLForPStateChange);
+
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.VMDataOnlyReturnBWPerState = dml32_get_return_bw_mbps_vm_only(&mode_lib->vba.soc, i,
mode_lib->vba.DCFCLKState[i][j], mode_lib->vba.FabricClockPerState[i],
mode_lib->vba.DRAMSpeedPerState[i]);
@@ -3192,6 +3236,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.FCLKChangeLatency, mode_lib->vba.UrgLatency[i],
mode_lib->vba.SREnterPlusExitTime);
+ memset(&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull, 0, sizeof(DmlPipe));
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.myPipe.Dppclk = mode_lib->vba.RequiredDPPCLK[i][j][k];
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.myPipe.Dispclk = mode_lib->vba.RequiredDISPCLK[i][j];
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.myPipe.PixelClock = mode_lib->vba.PixelClock[k];
@@ -3244,6 +3289,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->swath_width_chroma_ub_this_state[k],
v->SwathHeightYThisState[k],
v->SwathHeightCThisState[k], v->TWait,
+ v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ ?
+ mode_lib->vba.ip.min_prefetch_in_strobe_us : 0,
/* Output */
&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTXAfterScaler[k],
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
index c62e0991358b..c8b28c83ddf4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
@@ -46,9 +46,14 @@
// Prefetch schedule max vratio
#define __DML_MAX_VRATIO_PRE__ 4.0
+#define __DML_VBA_MAX_DST_Y_PRE__ 63.75
+
#define BPP_INVALID 0
#define BPP_BLENDED_PIPE 0xffffffff
+#define MEM_STROBE_FREQ_MHZ 1600
+#define MEM_STROBE_MAX_DELIVERY_TIME_US 60.0
+
struct display_mode_lib;
void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib);
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
index 968924c491c1..5af601cff1a0 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
@@ -3417,6 +3417,7 @@ bool dml32_CalculatePrefetchSchedule(
unsigned int SwathHeightY,
unsigned int SwathHeightC,
double TWait,
+ double TPreReq,
/* Output */
double *DSTXAfterScaler,
double *DSTYAfterScaler,
@@ -3667,6 +3668,7 @@ bool dml32_CalculatePrefetchSchedule(
dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime -
(*DSTYAfterScaler + (double) *DSTXAfterScaler / (double) myPipe->HTotal);
+ dst_y_prefetch_equ = dml_min(dst_y_prefetch_equ, __DML_VBA_MAX_DST_Y_PRE__);
#ifdef __DML_VBA_DEBUG__
dml_print("DML::%s: HTotal = %d\n", __func__, myPipe->HTotal);
dml_print("DML::%s: min_Lsw = %f\n", __func__, min_Lsw);
@@ -3726,7 +3728,8 @@ bool dml32_CalculatePrefetchSchedule(
*VRatioPrefetchY = 0;
*VRatioPrefetchC = 0;
*RequiredPrefetchPixDataBWLuma = 0;
- if (dst_y_prefetch_equ > 1) {
+ if (dst_y_prefetch_equ > 1 &&
+ (Tpre_rounded >= TPreReq || dst_y_prefetch_equ == __DML_VBA_MAX_DST_Y_PRE__)) {
double PrefetchBandwidth1;
double PrefetchBandwidth2;
double PrefetchBandwidth3;
@@ -3872,7 +3875,11 @@ bool dml32_CalculatePrefetchSchedule(
}
if (dst_y_prefetch_oto < dst_y_prefetch_equ) {
- *DestinationLinesForPrefetch = dst_y_prefetch_oto;
+ if (dst_y_prefetch_oto * LineTime < TPreReq) {
+ *DestinationLinesForPrefetch = dst_y_prefetch_equ;
+ } else {
+ *DestinationLinesForPrefetch = dst_y_prefetch_oto;
+ }
TimeForFetchingMetaPTE = Tvm_oto;
TimeForFetchingRowInVBlank = Tr0_oto;
*PrefetchBandwidth = prefetch_bw_oto;
@@ -4397,7 +4404,7 @@ void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
if (v->NumberOfActiveSurfaces > 1) {
ActiveClockChangeLatencyHidingY = ActiveClockChangeLatencyHidingY
- - (1 - 1 / v->NumberOfActiveSurfaces) * SwathHeightY[k] * v->HTotal[k]
+ - (1.0 - 1.0 / v->NumberOfActiveSurfaces) * SwathHeightY[k] * v->HTotal[k]
/ v->PixelClock[k] / v->VRatio[k];
}
@@ -6221,3 +6228,72 @@ void dml32_CalculateImmediateFlipBandwithSupport(unsigned int NumberOfActiveSurf
*ImmediateFlipBandwidthSupport = (*TotalBandwidth <= ReturnBW);
*FractionOfUrgentBandwidth = *TotalBandwidth / ReturnBW;
}
+
+bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurfaces,
+ double ReturnBW,
+ double UrgentLatency,
+ unsigned int SwathHeightY[],
+ unsigned int SwathHeightC[],
+ unsigned int SwathWidthY[],
+ unsigned int SwathWidthC[],
+ double BytePerPixelInDETY[],
+ double BytePerPixelInDETC[],
+ unsigned int DETBufferSizeY[],
+ unsigned int DETBufferSizeC[],
+ unsigned int NumOfDPP[],
+ unsigned int HTotal[],
+ double PixelClock[],
+ double VRatioY[],
+ double VRatioC[],
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX])
+{
+ int k;
+ double SwathSizeAllSurfaces = 0;
+ double SwathSizeAllSurfacesInFetchTimeUs;
+ double DETSwathLatencyHidingUs;
+ double DETSwathLatencyHidingYUs;
+ double DETSwathLatencyHidingCUs;
+ double SwathSizePerSurfaceY[DC__NUM_DPP__MAX];
+ double SwathSizePerSurfaceC[DC__NUM_DPP__MAX];
+ bool NotEnoughDETSwathFillLatencyHiding = false;
+
+ /* calculate sum of single swath size for all pipes in bytes*/
+ for (k = 0; k < NumberOfActiveSurfaces; k++) {
+ SwathSizePerSurfaceY[k] += SwathHeightY[k] * SwathWidthY[k] * BytePerPixelInDETY[k] * NumOfDPP[k];
+
+ if (SwathHeightC[k] != 0)
+ SwathSizePerSurfaceC[k] += SwathHeightC[k] * SwathWidthC[k] * BytePerPixelInDETC[k] * NumOfDPP[k];
+ else
+ SwathSizePerSurfaceC[k] = 0;
+
+ SwathSizeAllSurfaces += SwathSizePerSurfaceY[k] + SwathSizePerSurfaceC[k];
+ }
+
+ SwathSizeAllSurfacesInFetchTimeUs = SwathSizeAllSurfaces / ReturnBW + UrgentLatency;
+
+ /* ensure all DET - 1 swath can hide a fetch for all surfaces */
+ for (k = 0; k < NumberOfActiveSurfaces; k++) {
+ double LineTime = HTotal[k] / PixelClock[k];
+
+ /* only care if surface is not phantom */
+ if (UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) {
+ DETSwathLatencyHidingYUs = (dml_floor(DETBufferSizeY[k] / BytePerPixelInDETY[k] / SwathWidthY[k], 1.0) - SwathHeightY[k]) / VRatioY[k] * LineTime;
+
+ if (SwathHeightC[k] != 0) {
+ DETSwathLatencyHidingCUs = (dml_floor(DETBufferSizeC[k] / BytePerPixelInDETC[k] / SwathWidthC[k], 1.0) - SwathHeightC[k]) / VRatioC[k] * LineTime;
+
+ DETSwathLatencyHidingUs = dml_min(DETSwathLatencyHidingYUs, DETSwathLatencyHidingCUs);
+ } else {
+ DETSwathLatencyHidingUs = DETSwathLatencyHidingYUs;
+ }
+
+ /* DET must be able to hide time to fetch 1 swath for each surface */
+ if (DETSwathLatencyHidingUs < SwathSizeAllSurfacesInFetchTimeUs) {
+ NotEnoughDETSwathFillLatencyHiding = true;
+ break;
+ }
+ }
+ }
+
+ return NotEnoughDETSwathFillLatencyHiding;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
index 2c3827546ac7..779c6805f599 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
@@ -30,7 +30,7 @@
#include "os_types.h"
#include "../dc_features.h"
#include "../display_mode_structs.h"
-#include "dml/display_mode_vba.h"
+#include "../display_mode_vba.h"
unsigned int dml32_dscceComputeDelay(
unsigned int bpc,
@@ -743,6 +743,7 @@ bool dml32_CalculatePrefetchSchedule(
unsigned int SwathHeightY,
unsigned int SwathHeightC,
double TWait,
+ double TPreReq,
/* Output */
double *DSTXAfterScaler,
double *DSTYAfterScaler,
@@ -1140,4 +1141,22 @@ void dml32_CalculateImmediateFlipBandwithSupport(unsigned int NumberOfActiveSurf
double *FractionOfUrgentBandwidth,
bool *ImmediateFlipBandwidthSupport);
+bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurfaces,
+ double ReturnBW,
+ double UrgentLatency,
+ unsigned int SwathHeightY[],
+ unsigned int SwathHeightC[],
+ unsigned int SwathWidthY[],
+ unsigned int SwathWidthC[],
+ double BytePerPixelInDETY[],
+ double BytePerPixelInDETC[],
+ unsigned int DETBufferSizeY[],
+ unsigned int DETBufferSizeC[],
+ unsigned int NumOfDPP[],
+ unsigned int HTotal[],
+ double PixelClock[],
+ double VRatioY[],
+ double VRatioC[],
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX]);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
index ec0486efab14..f4b176599be7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
@@ -126,9 +126,9 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = {
.sr_enter_plus_exit_z8_time_us = 320,
.writeback_latency_us = 12.0,
.round_trip_ping_latency_dcfclk_cycles = 263,
- .urgent_latency_pixel_data_only_us = 9.35,
- .urgent_latency_pixel_mixed_with_vm_data_us = 9.35,
- .urgent_latency_vm_data_only_us = 9.35,
+ .urgent_latency_pixel_data_only_us = 4,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4,
+ .urgent_latency_vm_data_only_us = 4,
.fclk_change_latency_us = 20,
.usr_retraining_latency_us = 2,
.smn_latency_us = 2,
@@ -156,7 +156,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = {
.dispclk_dppclk_vco_speed_mhz = 4300.0,
.do_urgent_latency_adjustment = true,
.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 3000,
};
static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
@@ -544,6 +544,8 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p
/* DML DSC delay factor workaround */
dcn3_21_ip.dsc_delay_factor_wa = dc->debug.dsc_delay_factor_wa_x1000 / 1000.0;
+ dcn3_21_ip.min_prefetch_in_strobe_us = dc->debug.min_prefetch_in_strobe_ns / 1000.0;
+
/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
dcn3_21_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
index f394b3f3922a..0bffae95f3a2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
@@ -105,14 +105,39 @@ enum source_macro_tile_size {
enum cursor_bpp {
dm_cur_2bit = 0, dm_cur_32bit = 1, dm_cur_64bit = 2
};
+
+/**
+ * @enum clock_change_support - It represents possible reasons to change the DRAM clock.
+ *
+ * DC may change the DRAM clock during its execution, and this enum tracks all
+ * the available methods. Note that every ASIC has their specific way to deal
+ * with these clock switch.
+ */
enum clock_change_support {
+ /**
+ * @dm_dram_clock_change_uninitialized: If you see this, we might have
+ * a code initialization issue
+ */
dm_dram_clock_change_uninitialized = 0,
+
+ /**
+ * @dm_dram_clock_change_vactive: Support DRAM switch in VActive
+ */
dm_dram_clock_change_vactive,
+
+ /**
+ * @dm_dram_clock_change_vblank: Support DRAM switch in VBlank
+ */
dm_dram_clock_change_vblank,
+
dm_dram_clock_change_vactive_w_mall_full_frame,
dm_dram_clock_change_vactive_w_mall_sub_vp,
dm_dram_clock_change_vblank_w_mall_full_frame,
dm_dram_clock_change_vblank_w_mall_sub_vp,
+
+ /**
+ * @dm_dram_clock_change_unsupported: Do not support DRAM switch
+ */
dm_dram_clock_change_unsupported
};
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
index d7be01ac0751..64d602e6412f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
@@ -367,6 +367,7 @@ struct _vcs_dpi_ip_params_st {
/* DM workarounds */
double dsc_delay_factor_wa; // TODO: Remove after implementing root cause fix
+ double min_prefetch_in_strobe_us;
};
struct _vcs_dpi_display_xfc_params_st {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
index 630f3395e90a..81e53e67cd0b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
@@ -419,6 +419,15 @@ struct vba_vars_st {
double MinPixelChunkSizeBytes;
unsigned int DCCMetaBufferSizeBytes;
// Pipe/Plane Parameters
+
+ /** @VoltageLevel:
+ * Every ASIC has a fixed number of DPM states, and some devices might
+ * have some particular voltage configuration that does not map
+ * directly to the DPM states. This field tells how many states the
+ * target device supports; even though this field combines the DPM and
+ * special SOC voltages, it mostly matches the total number of DPM
+ * states.
+ */
int VoltageLevel;
double FabricClock;
double DRAMSpeed;
@@ -1041,6 +1050,7 @@ struct vba_vars_st {
double MinFullDETBufferingTime;
double AverageReadBandwidthGBytePerSecond;
bool FirstMainPlane;
+ bool NotEnoughDETSwathFillLatencyHiding;
unsigned int ViewportWidthChroma[DC__NUM_DPP__MAX];
unsigned int ViewportHeightChroma[DC__NUM_DPP__MAX];
@@ -1153,7 +1163,7 @@ struct vba_vars_st {
double UrgBurstFactorLumaPre[DC__NUM_DPP__MAX];
double UrgBurstFactorChromaPre[DC__NUM_DPP__MAX];
bool NotUrgentLatencyHidingPre[DC__NUM_DPP__MAX];
- bool LinkCapacitySupport[DC__NUM_DPP__MAX];
+ bool LinkCapacitySupport[DC__VOLTAGE_STATES];
bool VREADY_AT_OR_AFTER_VSYNC[DC__NUM_DPP__MAX];
unsigned int MIN_DST_Y_NEXT_START[DC__NUM_DPP__MAX];
unsigned int VFrontPorch[DC__NUM_DPP__MAX];
@@ -1224,6 +1234,7 @@ struct vba_vars_st {
unsigned int BlockWidthC[DC__NUM_DPP__MAX];
unsigned int SubViewportLinesNeededInMALL[DC__NUM_DPP__MAX];
bool VActiveBandwithSupport[DC__VOLTAGE_STATES][2];
+ bool NotEnoughDETSwathFillLatencyHidingPerState[DC__VOLTAGE_STATES][2];
struct dummy_vars dummy_vars;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h
index e5fac9f4181d..dcff0dd2b6a1 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h
@@ -25,7 +25,7 @@
*/
-const qp_table qp_table_422_10bpc_min = {
+static const qp_table qp_table_422_10bpc_min = {
{ 6, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} },
{ 6.5, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} },
{ 7, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 7, 9, 9, 9, 11, 15} },
@@ -58,7 +58,7 @@ const qp_table qp_table_422_10bpc_min = {
};
-const qp_table qp_table_444_8bpc_max = {
+static const qp_table qp_table_444_8bpc_max = {
{ 6, { 4, 6, 8, 8, 9, 9, 9, 10, 11, 12, 12, 12, 12, 13, 15} },
{ 6.5, { 4, 6, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 12, 13, 15} },
{ 7, { 4, 5, 7, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 13, 14} },
@@ -99,7 +99,7 @@ const qp_table qp_table_444_8bpc_max = {
};
-const qp_table qp_table_420_12bpc_max = {
+static const qp_table qp_table_420_12bpc_max = {
{ 4, {11, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 21, 22} },
{ 4.5, {10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
{ 5, { 9, 11, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 21} },
@@ -132,7 +132,7 @@ const qp_table qp_table_420_12bpc_max = {
};
-const qp_table qp_table_444_10bpc_min = {
+static const qp_table qp_table_444_10bpc_min = {
{ 6, { 0, 4, 7, 7, 9, 9, 9, 9, 9, 10, 10, 10, 10, 12, 18} },
{ 6.5, { 0, 4, 6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 12, 18} },
{ 7, { 0, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 10, 10, 12, 17} },
@@ -185,7 +185,7 @@ const qp_table qp_table_444_10bpc_min = {
};
-const qp_table qp_table_420_8bpc_max = {
+static const qp_table qp_table_420_8bpc_max = {
{ 4, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 13, 14} },
{ 4.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
{ 5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 13} },
@@ -206,7 +206,7 @@ const qp_table qp_table_420_8bpc_max = {
};
-const qp_table qp_table_444_8bpc_min = {
+static const qp_table qp_table_444_8bpc_min = {
{ 6, { 0, 1, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 6, 9, 14} },
{ 6.5, { 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 9, 14} },
{ 7, { 0, 0, 2, 2, 4, 4, 4, 4, 4, 5, 5, 6, 6, 9, 13} },
@@ -247,7 +247,7 @@ const qp_table qp_table_444_8bpc_min = {
};
-const qp_table qp_table_444_12bpc_min = {
+static const qp_table qp_table_444_12bpc_min = {
{ 6, { 0, 5, 11, 11, 13, 13, 13, 13, 13, 14, 14, 14, 14, 17, 22} },
{ 6.5, { 0, 5, 10, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 17, 22} },
{ 7, { 0, 5, 10, 10, 12, 12, 12, 12, 12, 13, 13, 14, 14, 17, 21} },
@@ -312,7 +312,7 @@ const qp_table qp_table_444_12bpc_min = {
};
-const qp_table qp_table_420_12bpc_min = {
+static const qp_table qp_table_420_12bpc_min = {
{ 4, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21} },
{ 4.5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
{ 5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
@@ -345,7 +345,7 @@ const qp_table qp_table_420_12bpc_min = {
};
-const qp_table qp_table_422_12bpc_min = {
+static const qp_table qp_table_422_12bpc_min = {
{ 6, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} },
{ 6.5, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} },
{ 7, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
@@ -386,7 +386,7 @@ const qp_table qp_table_422_12bpc_min = {
};
-const qp_table qp_table_422_12bpc_max = {
+static const qp_table qp_table_422_12bpc_max = {
{ 6, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
{ 6.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
{ 7, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} },
@@ -427,7 +427,7 @@ const qp_table qp_table_422_12bpc_max = {
};
-const qp_table qp_table_444_12bpc_max = {
+static const qp_table qp_table_444_12bpc_max = {
{ 6, {12, 14, 16, 16, 17, 17, 17, 18, 19, 20, 20, 20, 20, 21, 23} },
{ 6.5, {12, 14, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 20, 21, 23} },
{ 7, {12, 13, 15, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 21, 22} },
@@ -492,7 +492,7 @@ const qp_table qp_table_444_12bpc_max = {
};
-const qp_table qp_table_420_8bpc_min = {
+static const qp_table qp_table_420_8bpc_min = {
{ 4, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 13} },
{ 4.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
{ 5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
@@ -513,7 +513,7 @@ const qp_table qp_table_420_8bpc_min = {
};
-const qp_table qp_table_422_8bpc_min = {
+static const qp_table qp_table_422_8bpc_min = {
{ 6, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
{ 6.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
{ 7, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
@@ -538,7 +538,7 @@ const qp_table qp_table_422_8bpc_min = {
};
-const qp_table qp_table_422_10bpc_max = {
+static const qp_table qp_table_422_10bpc_max = {
{ 6, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
{ 6.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
{ 7, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} },
@@ -571,7 +571,7 @@ const qp_table qp_table_422_10bpc_max = {
};
-const qp_table qp_table_420_10bpc_max = {
+static const qp_table qp_table_420_10bpc_max = {
{ 4, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 17, 18} },
{ 4.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
{ 5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 17} },
@@ -598,7 +598,7 @@ const qp_table qp_table_420_10bpc_max = {
};
-const qp_table qp_table_420_10bpc_min = {
+static const qp_table qp_table_420_10bpc_min = {
{ 4, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 17} },
{ 4.5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
{ 5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
@@ -625,7 +625,7 @@ const qp_table qp_table_420_10bpc_min = {
};
-const qp_table qp_table_444_10bpc_max = {
+static const qp_table qp_table_444_10bpc_max = {
{ 6, { 8, 10, 12, 12, 13, 13, 13, 14, 15, 16, 16, 16, 16, 17, 19} },
{ 6.5, { 8, 10, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 16, 17, 19} },
{ 7, { 8, 9, 11, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 17, 18} },
@@ -678,7 +678,7 @@ const qp_table qp_table_444_10bpc_max = {
};
-const qp_table qp_table_422_8bpc_max = {
+static const qp_table qp_table_422_8bpc_max = {
{ 6, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
{ 6.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
{ 7, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} },
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
index d635b73af46f..9fd8b269dd79 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
@@ -108,6 +108,13 @@ static const struct ddc_registers ddc_data_regs_dcn[] = {
ddc_data_regs_dcn2(4),
ddc_data_regs_dcn2(5),
{
+ // add a dummy entry for cases no such port
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ .ddc_setup = 0,
+ .phy_aux_cntl = 0,
+ .dc_gpio_aux_ctrl_5 = 0
+ },
+ {
DDC_GPIO_VGA_REG_LIST(DATA),
.ddc_setup = 0,
.phy_aux_cntl = 0,
@@ -122,6 +129,13 @@ static const struct ddc_registers ddc_clk_regs_dcn[] = {
ddc_clk_regs_dcn2(4),
ddc_clk_regs_dcn2(5),
{
+ // add a dummy entry for cases no such port
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ .ddc_setup = 0,
+ .phy_aux_cntl = 0,
+ .dc_gpio_aux_ctrl_5 = 0
+ },
+ {
DDC_GPIO_VGA_REG_LIST(CLK),
.ddc_setup = 0,
.phy_aux_cntl = 0,
@@ -242,8 +256,8 @@ static const struct hw_factory_funcs funcs = {
*/
void dal_hw_factory_dcn32_init(struct hw_factory *factory)
{
- factory->number_of_pins[GPIO_ID_DDC_DATA] = 6;
- factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 6;
+ factory->number_of_pins[GPIO_ID_DDC_DATA] = 8;
+ factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8;
factory->number_of_pins[GPIO_ID_GENERIC] = 4;
factory->number_of_pins[GPIO_ID_HPD] = 5;
factory->number_of_pins[GPIO_ID_GPIO_PAD] = 28;
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
index 6fd38cdd68c0..525bc8881950 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
@@ -94,11 +94,14 @@ static enum gpio_result set_config(
* is required for detection of AUX mode */
if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) {
if (!ddc_data_pd_en || !ddc_clk_pd_en) {
-
- REG_SET_2(gpio.MASK_reg, regval,
+ if (hw_gpio->base.en == GPIO_DDC_LINE_DDC_VGA) {
+ // bit 4 of mask has different usage in some cases
+ REG_SET(gpio.MASK_reg, regval, DC_GPIO_DDC1DATA_PD_EN, 1);
+ } else {
+ REG_SET_2(gpio.MASK_reg, regval,
DC_GPIO_DDC1DATA_PD_EN, 1,
DC_GPIO_DDC1CLK_PD_EN, 1);
-
+ }
if (config_data->type ==
GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
msleep(3);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 9498105c98ab..525f8f0b8732 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -115,6 +115,13 @@ struct resource_funcs {
int vlevel);
void (*update_soc_for_wm_a)(
struct dc *dc, struct dc_state *context);
+
+ /**
+ * @populate_dml_pipes - Populate pipe data struct
+ *
+ * Returns:
+ * Total of pipes available in the specific ASIC.
+ */
int (*populate_dml_pipes)(
struct dc *dc,
struct dc_state *context,
@@ -233,8 +240,11 @@ struct resource_funcs {
unsigned int pipe_cnt,
unsigned int index);
- bool (*remove_phantom_pipes)(struct dc *dc, struct dc_state *context);
+ bool (*remove_phantom_pipes)(struct dc *dc, struct dc_state *context, bool fast_update);
+ void (*retain_phantom_pipes)(struct dc *dc, struct dc_state *context);
void (*get_panel_config_defaults)(struct dc_panel_config *panel_config);
+ void (*save_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config);
+ void (*restore_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config);
};
struct audio_support{
@@ -413,7 +423,10 @@ struct pipe_ctx {
struct pll_settings pll_settings;
- /* link config records software decision for what link config should be
+ /**
+ * @link_config:
+ *
+ * link config records software decision for what link config should be
* enabled given current link capability and stream during hw resource
* mapping. This is to decouple the dependency on link capability during
* dc commit or update.
@@ -507,33 +520,62 @@ struct bw_context {
union bw_output bw;
struct display_mode_lib dml;
};
+
/**
- * struct dc_state - The full description of a state requested by a user
- *
- * @streams: Stream properties
- * @stream_status: The planes on a given stream
- * @res_ctx: Persistent state of resources
- * @bw_ctx: The output from bandwidth and watermark calculations and the DML
- * @pp_display_cfg: PowerPlay clocks and settings
- * @dcn_bw_vars: non-stack memory to support bandwidth calculations
- *
+ * struct dc_state - The full description of a state requested by users
*/
struct dc_state {
+ /**
+ * @streams: Stream state properties
+ */
struct dc_stream_state *streams[MAX_PIPES];
+
+ /**
+ * @stream_status: Planes status on a given stream
+ */
struct dc_stream_status stream_status[MAX_PIPES];
+
+ /**
+ * @stream_count: Total of streams in use
+ */
uint8_t stream_count;
uint8_t stream_mask;
+ /**
+ * @res_ctx: Persistent state of resources
+ */
struct resource_context res_ctx;
+ /**
+ * @bw_ctx: The output from bandwidth and watermark calculations and the DML
+ *
+ * Each context must have its own instance of VBA, and in order to
+ * initialize and obtain IP and SOC, the base DML instance from DC is
+ * initially copied into every context.
+ */
struct bw_context bw_ctx;
- /* Note: these are big structures, do *not* put on stack! */
+ /**
+ * @pp_display_cfg: PowerPlay clocks and settings
+ * Note: this is a big struct, do *not* put on stack!
+ */
struct dm_pp_display_configuration pp_display_cfg;
+
+ /**
+ * @dcn_bw_vars: non-stack memory to support bandwidth calculations
+ * Note: this is a big struct, do *not* put on stack!
+ */
struct dcn_bw_internal_vars dcn_bw_vars;
struct clk_mgr *clk_mgr;
+ /**
+ * @refcount: refcount reference
+ *
+ * Notice that dc_state is used around the code to capture the current
+ * context, so we need to pass it everywhere. That's why we want to use
+ * kref in this struct.
+ */
struct kref refcount;
struct {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
index b304d450b038..e8d8c5cb1309 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
@@ -193,7 +193,7 @@ enum dc_status dpcd_configure_lttpr_mode(
struct link_training_settings *lt_settings);
enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings);
-bool dp_retrieve_lttpr_cap(struct dc_link *link);
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
bool dp_is_lttpr_present(struct dc_link *link);
enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting);
void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index e7571c6f5ead..f2e1fcb668fb 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -167,10 +167,26 @@ struct hubbub_funcs {
void (*force_pstate_change_control)(struct hubbub *hubbub, bool force, bool allow);
void (*init_watermarks)(struct hubbub *hubbub);
+
+ /**
+ * @program_det_size:
+ *
+ * DE-Tile buffers (DET) is a memory that is used to convert the tiled
+ * data into linear, which the rest of the display can use to generate
+ * the graphics output. One of the main features of this component is
+ * that each pipe has a configurable DET buffer which means that when a
+ * pipe is not enabled, the device can assign the memory to other
+ * enabled pipes to try to be more efficient.
+ *
+ * DET logic is handled by dchubbub. Some ASICs provide a feature named
+ * Configurable Return Buffer (CRB) segments which can be allocated to
+ * compressed or detiled buffers.
+ */
void (*program_det_size)(struct hubbub *hubbub, int hubp_inst, unsigned det_buffer_size_in_kbyte);
void (*program_compbuf_size)(struct hubbub *hubbub, unsigned compbuf_size_kb, bool safe_to_increase);
void (*init_crb)(struct hubbub *hubbub);
void (*force_usr_retraining_allow)(struct hubbub *hubbub, bool allow);
+ void (*set_request_limit)(struct hubbub *hubbub, int memory_channel_count, int words_per_channel);
};
struct hubbub {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
index 8df2765cce78..de3113ecbc77 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
@@ -56,20 +56,6 @@ struct dmcu {
bool auto_load_dmcu;
};
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-struct crc_region {
- uint16_t x_start;
- uint16_t y_start;
- uint16_t x_end;
- uint16_t y_end;
-};
-
-struct otg_phy_mux {
- uint8_t phy_output_num;
- uint8_t otg_output_num;
-};
-#endif
-
struct dmcu_funcs {
bool (*dmcu_init)(struct dmcu *dmcu);
bool (*load_iram)(struct dmcu *dmcu,
@@ -100,7 +86,7 @@ struct dmcu_funcs {
bool (*recv_edid_cea_ack)(struct dmcu *dmcu, int *offset);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
void (*forward_crc_window)(struct dmcu *dmcu,
- struct crc_region *crc_win,
+ struct rect *rect,
struct otg_phy_mux *mux_mapping);
void (*stop_crc_win_update)(struct dmcu *dmcu,
struct otg_phy_mux *mux_mapping);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
index dcb80c4747b0..131fcfa28bca 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -83,10 +83,15 @@ static const struct dpp_input_csc_matrix __maybe_unused dpp_input_csc_matrix[] =
{COLOR_SPACE_YCBCR709,
{0x3265, 0x2000, 0, 0xe6ce, 0xf105, 0x2000, 0xfa01, 0xa7d, 0,
0x2000, 0x3b61, 0xe24f} },
-
{COLOR_SPACE_YCBCR709_LIMITED,
{0x39a6, 0x2568, 0, 0xe0d6, 0xeedd, 0x2568, 0xf925, 0x9a8, 0,
- 0x2568, 0x43ee, 0xdbb2} }
+ 0x2568, 0x43ee, 0xdbb2} },
+ {COLOR_SPACE_2020_YCBCR,
+ {0x2F30, 0x2000, 0, 0xE869, 0xEDB7, 0x2000, 0xFABC, 0xBC6, 0,
+ 0x2000, 0x3C34, 0xE1E6} },
+ {COLOR_SPACE_2020_RGB_LIMITEDRANGE,
+ {0x35E0, 0x255F, 0, 0xE2B3, 0xEB20, 0x255F, 0xF9FD, 0xB1E, 0,
+ 0x255F, 0x44BD, 0xDB43} }
};
struct dpp_grph_csc_adjustment {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
index cd2be729846b..a819f0f97c5f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
@@ -35,6 +35,13 @@
******************************************************************************/
#define MAX_AUDIOS 7
+
+/**
+ * @MAX_PIPES:
+ *
+ * Every ASIC support a fixed number of pipes; MAX_PIPES defines a large number
+ * to be used inside loops and for determining array sizes.
+ */
#define MAX_PIPES 6
#define MAX_DIG_LINK_ENCODERS 7
#define MAX_DWB_PIPES 1
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
index 42afa1952890..42db4b7b79fd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
@@ -243,6 +243,9 @@ struct stream_encoder_funcs {
uint32_t hubp_requestor_id,
enum dynamic_metadata_mode dmdata_mode);
+ /**
+ * @dp_set_odm_combine: Sets up DP stream encoder for ODM.
+ */
void (*dp_set_odm_combine)(
struct stream_encoder *enc,
bool odm_combine);
@@ -317,9 +320,6 @@ struct hpo_dp_stream_encoder_funcs {
uint32_t stream_enc_inst,
uint32_t link_enc_inst);
- void (*audio_mute_control)(
- struct hpo_dp_stream_encoder *enc, bool mute);
-
void (*dp_audio_setup)(
struct hpo_dp_stream_encoder *enc,
unsigned int az_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index 25a1df45b264..0e42e721dd15 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -185,6 +185,7 @@ struct timing_generator_funcs {
#ifdef CONFIG_DRM_AMD_DC_DCN
void (*phantom_crtc_post_enable)(struct timing_generator *tg);
#endif
+ void (*disable_phantom_crtc)(struct timing_generator *tg);
bool (*immediate_disable_crtc)(struct timing_generator *tg);
bool (*is_counter_moving)(struct timing_generator *tg);
void (*get_position)(struct timing_generator *tg,
@@ -301,6 +302,11 @@ struct timing_generator_funcs {
void (*get_dsc_status)(struct timing_generator *optc,
uint32_t *dsc_mode);
void (*set_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing);
+
+ /**
+ * @set_odm_combine: Set up the ODM block to read from the correct
+ * OPP(s) and turn on/off ODM memory.
+ */
void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing);
void (*set_h_timing_div_manual_mode)(struct timing_generator *optc, bool manual_mode);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index d04b68dad413..c43523f9ff6d 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -263,6 +263,7 @@ struct hw_sequencer_funcs {
void (*update_phantom_vp_position)(struct dc *dc,
struct dc_state *context,
struct pipe_ctx *phantom_pipe);
+ void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe);
void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
void (*subvp_pipe_control_lock)(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
index 89964c980b87..0f69946cce9f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
@@ -38,6 +38,7 @@ struct link_resource;
struct pipe_ctx;
struct encoder_set_dp_phy_pattern_param;
struct link_mst_stream_allocation_table;
+struct audio_output;
struct link_hwss_ext {
/* function pointers below may require to check for NULL if caller
@@ -79,6 +80,10 @@ struct link_hwss {
void (*disable_link_output)(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal);
+ void (*setup_audio_output)(struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output, uint32_t audio_inst);
+ void (*enable_audio_packet)(struct pipe_ctx *pipe_ctx);
+ void (*disable_audio_packet)(struct pipe_ctx *pipe_ctx);
};
#endif /* __DC_LINK_HWSS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
index 45f99351a0ab..5f4f6dd79511 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
@@ -28,20 +28,19 @@
#include "include/logger_interface.h"
#include "../dce110/irq_service_dce110.h"
+#include "irq_service_dcn201.h"
#include "dcn/dcn_2_0_3_offset.h"
#include "dcn/dcn_2_0_3_sh_mask.h"
#include "cyan_skillfish_ip_offset.h"
#include "soc15_hw_ip.h"
-
-#include "irq_service_dcn201.h"
-
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
-static enum dc_irq_source to_dal_irq_source_dcn201(struct irq_service *irq_service,
- uint32_t src_id,
- uint32_t ext_id)
+enum dc_irq_source to_dal_irq_source_dcn201(
+ struct irq_service *irq_service,
+ uint32_t src_id,
+ uint32_t ext_id)
{
switch (src_id) {
case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
@@ -79,7 +78,6 @@ static enum dc_irq_source to_dal_irq_source_dcn201(struct irq_service *irq_servi
default:
return DC_IRQ_SOURCE_INVALID;
}
- return DC_IRQ_SOURCE_INVALID;
}
static bool hpd_ack(
@@ -138,6 +136,11 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
.ack = NULL
};
+static const struct irq_source_info_funcs dmub_outbox_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
#undef BASE_INNER
#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.h b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.h
index 8e27c5e219a3..0cfd2f2d62e8 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.h
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Advanced Micro Devices, Inc.
+ * Copyright 2022 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
index 7bad39bba86b..d100edaedbbb 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
@@ -112,8 +112,15 @@ bool dal_irq_service_set(
dal_irq_service_ack(irq_service, source);
- if (info->funcs && info->funcs->set)
+ if (info->funcs && info->funcs->set) {
+ if (info->funcs->set == dal_irq_service_dummy_set) {
+ DC_LOG_WARNING("%s: src: %d, st: %d\n", __func__,
+ source, enable);
+ ASSERT(0);
+ }
+
return info->funcs->set(irq_service, info, enable);
+ }
dal_irq_service_set_generic(irq_service, info, enable);
@@ -146,8 +153,14 @@ bool dal_irq_service_ack(
return false;
}
- if (info->funcs && info->funcs->ack)
+ if (info->funcs && info->funcs->ack) {
+ if (info->funcs->ack == dal_irq_service_dummy_ack) {
+ DC_LOG_WARNING("%s: src: %d\n", __func__, source);
+ ASSERT(0);
+ }
+
return info->funcs->ack(irq_service, info);
+ }
dal_irq_service_ack_generic(irq_service, info);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c
new file mode 100644
index 000000000000..801a95b34e8c
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+/*********************************************************************/
+// USB4 DPIA BANDWIDTH ALLOCATION LOGIC
+/*********************************************************************/
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h
new file mode 100644
index 000000000000..669e995f825f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DC_INC_LINK_DP_DPIA_BW_H_
+#define DC_INC_LINK_DP_DPIA_BW_H_
+
+// XXX: TODO: Re-add for Phase 2
+/* Number of Host Routers per motherboard is 2 and 2 DPIA per host router */
+#define MAX_HR_NUM 2
+
+struct dc_host_router_bw_alloc {
+ int max_bw[MAX_HR_NUM]; // The Max BW that each Host Router has available to be shared btw DPIAs
+ int total_estimated_bw[MAX_HR_NUM]; // The Total Verified and available BW that Host Router has
+};
+
+/*
+ * Enable BW Allocation Mode Support from the DP-Tx side
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: SUCCESS or FAILURE
+ */
+bool set_dptx_usb4_bw_alloc_support(struct dc_link *link);
+
+/*
+ * Send a request from DP-Tx requesting to allocate BW remotely after
+ * allocating it locally. This will get processed by CM and a CB function
+ * will be called.
+ *
+ * @link: pointer to the dc_link struct instance
+ * @req_bw: The requested bw in Kbyte to allocated
+ *
+ * return: none
+ */
+void set_usb4_req_bw_req(struct dc_link *link, int req_bw);
+
+/*
+ * CB function for when the status of the Req above is complete. We will
+ * find out the result of allocating on CM and update structs accordingly
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: none
+ */
+void get_usb4_req_bw_resp(struct dc_link *link);
+
+#endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
index 4227adbc646a..33148b753c03 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
@@ -170,11 +170,63 @@ static void update_dio_stream_allocation_table(struct dc_link *link,
link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
}
+void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output, uint32_t audio_inst)
+{
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
+ pipe_ctx->stream_res.stream_enc,
+ audio_inst,
+ &pipe_ctx->stream->audio_info);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
+ pipe_ctx->stream_res.stream_enc,
+ audio_inst,
+ &pipe_ctx->stream->audio_info,
+ &audio_output->crtc_info);
+}
+
+void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(
+ pipe_ctx->stream_res.stream_enc);
+
+ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.stream_enc, false);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_source_sequence_trace(pipe_ctx->stream->link,
+ DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
+}
+
+void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.stream_enc, true);
+
+ if (pipe_ctx->stream_res.audio) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
+ pipe_ctx->stream_res.stream_enc);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
+ pipe_ctx->stream_res.stream_enc);
+ }
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_source_sequence_trace(pipe_ctx->stream->link,
+ DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
+}
+
static const struct link_hwss dio_link_hwss = {
.setup_stream_encoder = setup_dio_stream_encoder,
.reset_stream_encoder = reset_dio_stream_encoder,
.setup_stream_attribute = setup_dio_stream_attribute,
.disable_link_output = disable_dio_link_output,
+ .setup_audio_output = setup_dio_audio_output,
+ .enable_audio_packet = enable_dio_audio_packet,
+ .disable_audio_packet = disable_dio_audio_packet,
.ext = {
.set_throttled_vcp_size = set_dio_throttled_vcp_size,
.enable_dp_link_output = enable_dio_dp_link_output,
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
index 126d37f847a1..9a108c3d7831 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
@@ -50,5 +50,9 @@ void set_dio_dp_lane_settings(struct dc_link *link,
const struct link_resource *link_res,
const struct dc_link_settings *link_settings,
const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
+void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output, uint32_t audio_inst);
+void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
+void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
#endif /* __LINK_HWSS_DIO_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
index 64f7ea6a9aa3..861f3cd5b356 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
@@ -57,6 +57,9 @@ static const struct link_hwss dpia_link_hwss = {
.reset_stream_encoder = reset_dio_stream_encoder,
.setup_stream_attribute = setup_dio_stream_attribute,
.disable_link_output = disable_dio_link_output,
+ .setup_audio_output = setup_dio_audio_output,
+ .enable_audio_packet = enable_dio_audio_packet,
+ .disable_audio_packet = disable_dio_audio_packet,
.ext = {
.set_throttled_vcp_size = set_dio_throttled_vcp_size,
.enable_dp_link_output = enable_dio_dp_link_output,
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
index 153a88381f2c..2f46e1ac4ce0 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
@@ -262,11 +262,36 @@ static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
table);
}
+static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output, uint32_t audio_inst)
+{
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ audio_inst,
+ &pipe_ctx->stream->audio_info);
+}
+
+static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+}
+
+static void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+ if (pipe_ctx->stream_res.audio)
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+}
+
static const struct link_hwss hpo_dp_link_hwss = {
.setup_stream_encoder = setup_hpo_dp_stream_encoder,
.reset_stream_encoder = reset_hpo_dp_stream_encoder,
.setup_stream_attribute = setup_hpo_dp_stream_attribute,
.disable_link_output = disable_hpo_dp_link_output,
+ .setup_audio_output = setup_hpo_dp_audio_output,
+ .enable_audio_packet = enable_hpo_dp_audio_packet,
+ .disable_audio_packet = disable_hpo_dp_audio_packet,
.ext = {
.set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size,
.set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width,
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 7a8f61517424..33907feefebb 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -225,6 +225,12 @@ union dmub_psr_debug_flags {
* Use TPS3 signal when restore main link.
*/
uint32_t force_wakeup_by_tps3 : 1;
+
+ /**
+ * Back to back flip, therefore cannot power down PHY
+ */
+ uint32_t back_to_back_flip : 1;
+
} bitfields;
/**
@@ -401,8 +407,9 @@ union dmub_fw_boot_options {
uint32_t gpint_scratch8: 1; /* 1 if GPINT is in scratch8*/
uint32_t usb4_cm_version: 1; /**< 1 CM support */
uint32_t dpia_hpd_int_enable_supported: 1; /* 1 if dpia hpd int enable supported */
+ uint32_t usb4_dpia_bw_alloc_supported: 1; /* 1 if USB4 dpia BW allocation supported */
- uint32_t reserved : 16; /**< reserved */
+ uint32_t reserved : 15; /**< reserved */
} bits; /**< boot bits */
uint32_t all; /**< 32-bit access to bits */
};
@@ -731,6 +738,11 @@ enum dmub_cmd_type {
*/
/**
+ * Command type used for all SECURE_DISPLAY commands.
+ */
+ DMUB_CMD__SECURE_DISPLAY = 85,
+
+ /**
* Command type used to set DPIA HPD interrupt state
*/
DMUB_CMD__DPIA_HPD_INT_ENABLE = 86,
@@ -1017,13 +1029,14 @@ struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 {
uint16_t vtotal;
uint16_t htotal;
uint8_t vblank_pipe_index;
- uint8_t padding[2];
+ uint8_t padding[1];
struct {
uint8_t drr_in_use;
uint8_t drr_window_size_ms; // Indicates largest VMIN/VMAX adjustment per frame
uint16_t min_vtotal_supported; // Min VTOTAL that supports switching in VBLANK
uint16_t max_vtotal_supported; // Max VTOTAL that can support SubVP static scheduling
uint8_t use_ramping; // Use ramping or not
+ uint8_t drr_vblank_start_margin;
} drr_info; // DRR considered as part of SubVP + VBLANK case
} vblank_data;
} pipe_config;
@@ -1866,9 +1879,13 @@ struct dmub_cmd_psr_copy_settings_data {
*/
uint8_t use_phy_fsm;
/**
+ * frame delay for frame re-lock
+ */
+ uint8_t relock_delay_frame_cnt;
+ /**
* Explicit padding to 2 byte boundary.
*/
- uint8_t pad3[2];
+ uint8_t pad3;
};
/**
@@ -3144,6 +3161,33 @@ struct dmub_rb_cmd_get_usbc_cable_id {
};
/**
+ * Command type of a DMUB_CMD__SECURE_DISPLAY command
+ */
+enum dmub_cmd_secure_display_type {
+ DMUB_CMD__SECURE_DISPLAY_TEST_CMD = 0, /* test command to only check if inbox message works */
+ DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE,
+ DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY
+};
+
+/**
+ * Definition of a DMUB_CMD__SECURE_DISPLAY command
+ */
+struct dmub_rb_cmd_secure_display {
+ struct dmub_cmd_header header;
+ /**
+ * Data passed from driver to dmub firmware.
+ */
+ struct dmub_cmd_roi_info {
+ uint16_t x_start;
+ uint16_t x_end;
+ uint16_t y_start;
+ uint16_t y_end;
+ uint8_t otg_id;
+ uint8_t phy_id;
+ } roi_info;
+};
+
+/**
* union dmub_rb_cmd - DMUB inbox command.
*/
union dmub_rb_cmd {
@@ -3348,6 +3392,11 @@ union dmub_rb_cmd {
*/
struct dmub_rb_cmd_query_hpd_state query_hpd;
/**
+ * Definition of a DMUB_CMD__SECURE_DISPLAY command.
+ */
+ struct dmub_rb_cmd_secure_display secure_display;
+
+ /**
* Definition of a DMUB_CMD__DPIA_HPD_INT_ENABLE command.
*/
struct dmub_rb_cmd_dpia_hpd_int_enable dpia_hpd_int_enable;
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
index 447a0ec9cbe2..f6034213c700 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -61,7 +61,7 @@ static const int32_t numerator01[] = { 31308, 180000, 0, 0, 0};
static const int32_t numerator02[] = { 12920, 4500, 0, 0, 0};
static const int32_t numerator03[] = { 55, 99, 0, 0, 0};
static const int32_t numerator04[] = { 55, 99, 0, 0, 0};
-static const int32_t numerator05[] = { 2400, 2200, 2200, 2400, 2600};
+static const int32_t numerator05[] = { 2400, 2222, 2200, 2400, 2600};
/* one-time setup of X points */
void setup_x_points_distribution(void)
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 0f39ab9dc5b4..c2e00f7b8381 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -688,10 +688,10 @@ static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
if (app_tf != TRANSFER_FUNC_UNKNOWN) {
infopacket->valid = true;
- infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active]
-
- if (app_tf == TRANSFER_FUNC_GAMMA_22) {
- infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
+ if (app_tf != TRANSFER_FUNC_PQ2084) {
+ infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active]
+ if (app_tf == TRANSFER_FUNC_GAMMA_22)
+ infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
}
}
}
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index 1d8b746b02f2..edf5845f6a1f 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -35,7 +35,8 @@ struct mod_vrr_params;
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet,
- enum dc_color_space cs);
+ enum dc_color_space cs,
+ enum color_transfer_func tf);
void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet);
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index 27ceba9d6d65..69691058ab89 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -132,7 +132,8 @@ enum ColorimetryYCCDP {
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet,
- enum dc_color_space cs)
+ enum dc_color_space cs,
+ enum color_transfer_func tf)
{
unsigned int vsc_packet_revision = vsc_packet_undefined;
unsigned int i;
@@ -382,6 +383,9 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
colorimetryFormat = ColorimetryYCC_DP_AdobeYCC;
else if (cs == COLOR_SPACE_2020_YCBCR)
colorimetryFormat = ColorimetryYCC_DP_ITU2020YCbCr;
+
+ if (cs == COLOR_SPACE_2020_YCBCR && tf == TRANSFER_FUNC_GAMMA_22)
+ colorimetryFormat = ColorimetryYCC_DP_ITU709;
break;
default:
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
index 235259d6c5a1..9b5d9b2c9a6a 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -102,9 +102,18 @@ static const struct abm_parameters abm_settings_config1[abm_defines_max_level] =
{0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc},
};
+static const struct abm_parameters abm_settings_config2[abm_defines_max_level] = {
+// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart
+ {0xf0, 0xbf, 0x20, 0x00, 0x88, 0x99, 0xb3, 0x40, 0xe0, 0x0000, 0xcccc},
+ {0xd8, 0x85, 0x20, 0x00, 0x70, 0x90, 0xa8, 0x40, 0xc8, 0x0700, 0xb333},
+ {0xb8, 0x58, 0x20, 0x00, 0x64, 0x88, 0x78, 0x70, 0xa0, 0x7000, 0x9999},
+ {0x82, 0x40, 0x20, 0x00, 0x00, 0xb8, 0xb3, 0x70, 0x70, 0xc333, 0xb333},
+};
+
static const struct abm_parameters * const abm_settings[] = {
abm_settings_config0,
abm_settings_config1,
+ abm_settings_config2,
};
#define NUM_AMBI_LEVEL 5
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h
index 483769fb1736..537aee0536d3 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
#ifndef _dcn_3_0_0_OFFSET_HEADER
#define _dcn_3_0_0_OFFSET_HEADER
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h
index b79be3a25a80..f9d90b098519 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
#ifndef _dcn_3_0_0_SH_MASK_HEADER
#define _dcn_3_0_0_SH_MASK_HEADER
diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_offset.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_offset.h
index 363d2139cea2..db7e22720d00 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_offset.h
@@ -993,7 +993,8 @@
#define mmUVD_RAS_VCPU_VCODEC_STATUS_BASE_IDX 1
#define mmUVD_RAS_MMSCH_FATAL_ERROR 0x0058
#define mmUVD_RAS_MMSCH_FATAL_ERROR_BASE_IDX 1
-
+#define mmVCN_RAS_CNTL 0x04b9
+#define mmVCN_RAS_CNTL_BASE_IDX 1
/* JPEG 2_6_0 regs */
#define mmUVD_RAS_JPEG0_STATUS 0x0059
diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_sh_mask.h
index 8de883b76d90..874a8b7e1feb 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_2_5_sh_mask.h
@@ -3618,6 +3618,33 @@
#define UVD_RAS_MMSCH_FATAL_ERROR__POISONED_VF_MASK 0x7FFFFFFFL
#define UVD_RAS_MMSCH_FATAL_ERROR__POISONED_PF_MASK 0x80000000L
+//VCN 2_6_0 VCN_RAS_CNTL
+#define VCN_RAS_CNTL__VCPU_VCODEC_IH_EN__SHIFT 0x0
+#define VCN_RAS_CNTL__MMSCH_FATAL_ERROR_EN__SHIFT 0x1
+#define VCN_RAS_CNTL__VCPU_VCODEC_PMI_EN__SHIFT 0x4
+#define VCN_RAS_CNTL__MMSCH_PMI_EN__SHIFT 0x5
+#define VCN_RAS_CNTL__VCPU_VCODEC_REARM__SHIFT 0x8
+#define VCN_RAS_CNTL__MMSCH_REARM__SHIFT 0x9
+#define VCN_RAS_CNTL__VCPU_VCODEC_STALL_EN__SHIFT 0xc
+#define VCN_RAS_CNTL__VCPU_VCODEC_READY__SHIFT 0x10
+#define VCN_RAS_CNTL__MMSCH_READY__SHIFT 0x11
+#define VCN_RAS_CNTL__VCPU_VCODEC_IH_EN_MASK 0x00000001L
+#define VCN_RAS_CNTL__MMSCH_FATAL_ERROR_EN_MASK 0x00000002L
+#define VCN_RAS_CNTL__VCPU_VCODEC_PMI_EN_MASK 0x00000010L
+#define VCN_RAS_CNTL__MMSCH_PMI_EN_MASK 0x00000020L
+#define VCN_RAS_CNTL__VCPU_VCODEC_REARM_MASK 0x00000100L
+#define VCN_RAS_CNTL__MMSCH_REARM_MASK 0x00000200L
+#define VCN_RAS_CNTL__VCPU_VCODEC_STALL_EN_MASK 0x00001000L
+#define VCN_RAS_CNTL__VCPU_VCODEC_READY_MASK 0x00010000L
+#define VCN_RAS_CNTL__MMSCH_READY_MASK 0x00020000L
+
+//VCN 2_6_0 UVD_VCPU_INT_EN
+#define UVD_VCPU_INT_EN__RASCNTL_VCPU_VCODEC_EN__SHIFT 0x16
+#define UVD_VCPU_INT_EN__RASCNTL_VCPU_VCODEC_EN_MASK 0x00400000L
+
+//VCN 2_6_0 UVD_SYS_INT_EN
+#define UVD_SYS_INT_EN__RASCNTL_VCPU_VCODEC_EN_MASK 0x04000000L
+
/* JPEG 2_6_0 UVD_RAS_JPEG0_STATUS */
#define UVD_RAS_JPEG0_STATUS__POISONED_VF__SHIFT 0x0
#define UVD_RAS_JPEG0_STATUS__POISONED_PF__SHIFT 0x1f
diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h
index 15943bc21bc5..b78360a71bc9 100644
--- a/drivers/gpu/drm/amd/include/atombios.h
+++ b/drivers/gpu/drm/amd/include/atombios.h
@@ -4107,7 +4107,7 @@ typedef struct _ATOM_FAKE_EDID_PATCH_RECORD
{
UCHAR ucRecordType;
UCHAR ucFakeEDIDLength; // = 128 means EDID length is 128 bytes, otherwise the EDID length = ucFakeEDIDLength*128
- UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements.
+ UCHAR ucFakeEDIDString[]; // This actually has ucFakeEdidLength elements.
} ATOM_FAKE_EDID_PATCH_RECORD;
typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD
@@ -4386,7 +4386,7 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
typedef struct _ATOM_GPIO_PIN_LUT
{
ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1];
+ ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[];
}ATOM_GPIO_PIN_LUT;
/****************************************************************************/
@@ -4513,7 +4513,7 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH
USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
USHORT usConnObjectId; //Connector Object ID
USHORT usGPUObjectId; //GPU ID
- USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
+ USHORT usGraphicObjIds[]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
}ATOM_DISPLAY_OBJECT_PATH;
typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH
@@ -4530,7 +4530,7 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE
UCHAR ucNumOfDispPath;
UCHAR ucVersion;
UCHAR ucPadding[2];
- ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
+ ATOM_DISPLAY_OBJECT_PATH asDispPath[];
}ATOM_DISPLAY_OBJECT_PATH_TABLE;
typedef struct _ATOM_OBJECT //each object has this structure
@@ -4545,7 +4545,7 @@ typedef struct _ATOM_OBJECT_TABLE //Above 4 object table
{
UCHAR ucNumberOfObjects;
UCHAR ucPadding[3];
- ATOM_OBJECT asObjects[1];
+ ATOM_OBJECT asObjects[];
}ATOM_OBJECT_TABLE;
typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure
@@ -4733,7 +4733,7 @@ typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD
ATOM_COMMON_RECORD_HEADER sheader;
UCHAR ucNumberOfDevice;
UCHAR ucReserved;
- ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation
+ ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT"
}ATOM_CONNECTOR_DEVICE_TAG_RECORD;
@@ -4793,7 +4793,7 @@ typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD
ATOM_COMMON_RECORD_HEADER sheader;
UCHAR ucFlags; // Future expnadibility
UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object
- ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins
+ ATOM_GPIO_PIN_CONTROL_PAIR asGpio[]; // the real gpio pin pair determined by number of pins ucNumberOfPins
}ATOM_OBJECT_GPIO_CNTL_RECORD;
//Definitions for GPIO pin state
@@ -4982,7 +4982,7 @@ typedef struct _ATOM_BRACKET_LAYOUT_RECORD
UCHAR ucWidth;
UCHAR ucConnNum;
UCHAR ucReserved;
- ATOM_CONNECTOR_LAYOUT_INFO asConnInfo[1];
+ ATOM_CONNECTOR_LAYOUT_INFO asConnInfo[];
}ATOM_BRACKET_LAYOUT_RECORD;
@@ -5146,7 +5146,7 @@ typedef struct _ATOM_I2C_VOLTAGE_OBJECT_V3
UCHAR ucVoltageControlOffset;
UCHAR ucVoltageControlFlag; // Bit0: 0 - One byte data; 1 - Two byte data
UCHAR ulReserved[3];
- VOLTAGE_LUT_ENTRY asVolI2cLut[1]; // end with 0xff
+ VOLTAGE_LUT_ENTRY asVolI2cLut[]; // end with 0xff
}ATOM_I2C_VOLTAGE_OBJECT_V3;
// ATOM_I2C_VOLTAGE_OBJECT_V3.ucVoltageControlFlag
@@ -5161,7 +5161,7 @@ typedef struct _ATOM_GPIO_VOLTAGE_OBJECT_V3
UCHAR ucPhaseDelay; // phase delay in unit of micro second
UCHAR ucReserved;
ULONG ulGpioMaskVal; // GPIO Mask value
- VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[1];
+ VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[];
}ATOM_GPIO_VOLTAGE_OBJECT_V3;
typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
@@ -5171,7 +5171,7 @@ typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
UCHAR ucLeakageEntryNum; // indicate the entry number of LeakageId/Voltage Lut table
UCHAR ucReserved[2];
ULONG ulMaxVoltageLevel;
- LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1];
+ LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[];
}ATOM_LEAKAGE_VOLTAGE_OBJECT_V3;
@@ -6599,7 +6599,7 @@ typedef struct _ATOM_FUSION_SYSTEM_INFO_V3
typedef struct _ATOM_I2C_DATA_RECORD
{
UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop"
- UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually
+ UCHAR ucI2CData[]; //I2C data in bytes, should be less than 16 bytes usually
}ATOM_I2C_DATA_RECORD;
@@ -6610,14 +6610,14 @@ typedef struct _ATOM_I2C_DEVICE_SETUP_INFO
UCHAR ucSSChipID; //SS chip being used
UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip
UCHAR ucNumOfI2CDataRecords; //number of data block
- ATOM_I2C_DATA_RECORD asI2CData[1];
+ ATOM_I2C_DATA_RECORD asI2CData[];
}ATOM_I2C_DEVICE_SETUP_INFO;
//==========================================================================================
typedef struct _ATOM_ASIC_MVDD_INFO
{
ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1];
+ ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[];
}ATOM_ASIC_MVDD_INFO;
//==========================================================================================
@@ -6679,7 +6679,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO
typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V2
{
ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_ASIC_SS_ASSIGNMENT_V2 asSpreadSpectrum[1]; //this is point only.
+ ATOM_ASIC_SS_ASSIGNMENT_V2 asSpreadSpectrum[]; //this is point only.
}ATOM_ASIC_INTERNAL_SS_INFO_V2;
typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
@@ -6701,7 +6701,7 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
{
ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_ASIC_SS_ASSIGNMENT_V3 asSpreadSpectrum[1]; //this is pointer only.
+ ATOM_ASIC_SS_ASSIGNMENT_V3 asSpreadSpectrum[]; //this is pointer only.
}ATOM_ASIC_INTERNAL_SS_INFO_V3;
@@ -9292,7 +9292,7 @@ typedef struct {
typedef struct {
VFCT_IMAGE_HEADER VbiosHeader;
- UCHAR VbiosContent[1];
+ UCHAR VbiosContent[];
}GOP_VBIOS_CONTENT;
typedef struct {
diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h
index ff855cb21d3f..bbe1337a8cee 100644
--- a/drivers/gpu/drm/amd/include/atomfirmware.h
+++ b/drivers/gpu/drm/amd/include/atomfirmware.h
@@ -705,20 +705,65 @@ struct atom_gpio_pin_lut_v2_1
};
-/*
- ***************************************************************************
- Data Table vram_usagebyfirmware structure
- ***************************************************************************
-*/
+/*
+ * VBIOS/PRE-OS always reserve a FB region at the top of frame buffer. driver should not write
+ * access that region. driver can allocate their own reservation region as long as it does not
+ * overlap firwmare's reservation region.
+ * if (pre-NV1X) atom data table firmwareInfoTable version < 3.3:
+ * in this case, atom data table vram_usagebyfirmwareTable version always <= 2.1
+ * if VBIOS/UEFI GOP is posted:
+ * VBIOS/UEFIGOP update used_by_firmware_in_kb = total reserved size by VBIOS
+ * update start_address_in_kb = total_mem_size_in_kb - used_by_firmware_in_kb;
+ * ( total_mem_size_in_kb = reg(CONFIG_MEMSIZE)<<10)
+ * driver can allocate driver reservation region under firmware reservation,
+ * used_by_driver_in_kb = driver reservation size
+ * driver reservation start address = (start_address_in_kb - used_by_driver_in_kb)
+ * Comment1[hchan]: There is only one reservation at the beginning of the FB reserved by
+ * host driver. Host driver would overwrite the table with the following
+ * used_by_firmware_in_kb = total reserved size for pf-vf info exchange and
+ * set SRIOV_MSG_SHARE_RESERVATION mask start_address_in_kb = 0
+ * else there is no VBIOS reservation region:
+ * driver must allocate driver reservation region at top of FB.
+ * driver set used_by_driver_in_kb = driver reservation size
+ * driver reservation start address = (total_mem_size_in_kb - used_by_driver_in_kb)
+ * same as Comment1
+ * else (NV1X and after):
+ * if VBIOS/UEFI GOP is posted:
+ * VBIOS/UEFIGOP update:
+ * used_by_firmware_in_kb = atom_firmware_Info_v3_3.fw_reserved_size_in_kb;
+ * start_address_in_kb = total_mem_size_in_kb - used_by_firmware_in_kb;
+ * (total_mem_size_in_kb = reg(CONFIG_MEMSIZE)<<10)
+ * if vram_usagebyfirmwareTable version <= 2.1:
+ * driver can allocate driver reservation region under firmware reservation,
+ * driver set used_by_driver_in_kb = driver reservation size
+ * driver reservation start address = start_address_in_kb - used_by_driver_in_kb
+ * same as Comment1
+ * else driver can:
+ * allocate it reservation any place as long as it does overlap pre-OS FW reservation area
+ * set used_by_driver_region0_in_kb = driver reservation size
+ * set driver_region0_start_address_in_kb = driver reservation region start address
+ * Comment2[hchan]: Host driver can set used_by_firmware_in_kb and start_address_in_kb to
+ * zero as the reservation for VF as it doesn’t exist. And Host driver should also
+ * update atom_firmware_Info table to remove the same VBIOS reservation as well.
+ */
struct vram_usagebyfirmware_v2_1
{
- struct atom_common_table_header table_header;
- uint32_t start_address_in_kb;
- uint16_t used_by_firmware_in_kb;
- uint16_t used_by_driver_in_kb;
+ struct atom_common_table_header table_header;
+ uint32_t start_address_in_kb;
+ uint16_t used_by_firmware_in_kb;
+ uint16_t used_by_driver_in_kb;
};
+struct vram_usagebyfirmware_v2_2 {
+ struct atom_common_table_header table_header;
+ uint32_t fw_region_start_address_in_kb;
+ uint16_t used_by_firmware_in_kb;
+ uint16_t reserved;
+ uint32_t driver_region0_start_address_in_kb;
+ uint32_t used_by_driver_region0_in_kb;
+ uint32_t reserved32[7];
+};
/*
***************************************************************************
diff --git a/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_4_0.h b/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_4_0.h
index a81138c9e491..03cfa0517df2 100644
--- a/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_4_0.h
+++ b/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_4_0.h
@@ -38,4 +38,7 @@
#define VCN_4_0__SRCID__JPEG6_DECODE 174 // 0xae JRBC6 Decode interrupt
#define VCN_4_0__SRCID__JPEG7_DECODE 175 // 0xaf JRBC7 Decode interrupt
+#define VCN_4_0__SRCID_UVD_POISON 160
+#define VCN_4_0__SRCID_DJPEG0_POISON 161
+#define VCN_4_0__SRCID_EJPEG0_POISON 162
#endif
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index a40ead44778a..d18162e9ed1d 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -354,7 +354,8 @@ struct amd_pm_funcs {
int (*get_power_profile_mode)(void *handle, char *buf);
int (*set_power_profile_mode)(void *handle, long *input, uint32_t size);
int (*set_fine_grain_clk_vol)(void *handle, uint32_t type, long *input, uint32_t size);
- int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size);
+ int (*odn_edit_dpm_table)(void *handle, enum PP_OD_DPM_TABLE_COMMAND type,
+ long *input, uint32_t size);
int (*set_mp1_state)(void *handle, enum pp_mp1_state mp1_state);
int (*smu_i2c_bus_access)(void *handle, bool acquire);
int (*gfx_state_change_set)(void *handle, uint32_t state);
diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h
index 7e85cdc5bd34..dc694cb246d9 100644
--- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h
+++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h
@@ -222,7 +222,11 @@ union MESAPI_SET_HW_RESOURCES {
uint32_t apply_grbm_remote_register_dummy_read_wa : 1;
uint32_t second_gfx_pipe_enabled : 1;
uint32_t enable_level_process_quantum_check : 1;
- uint32_t reserved : 25;
+ uint32_t legacy_sch_mode : 1;
+ uint32_t disable_add_queue_wptr_mc_addr : 1;
+ uint32_t enable_mes_event_int_logging : 1;
+ uint32_t enable_reg_active_poll : 1;
+ uint32_t reserved : 21;
};
uint32_t uint32_t_all;
};
diff --git a/drivers/gpu/drm/amd/include/yellow_carp_offset.h b/drivers/gpu/drm/amd/include/yellow_carp_offset.h
index 28a56b56bcaf..0fea6a746611 100644
--- a/drivers/gpu/drm/amd/include/yellow_carp_offset.h
+++ b/drivers/gpu/drm/amd/include/yellow_carp_offset.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
#ifndef YELLOW_CARP_OFFSET_H
#define YELLOW_CARP_OFFSET_H
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index ec055858eb95..304190d5c9d2 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -838,7 +838,8 @@ static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, u
return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size);
}
-static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)
+static int pp_odn_edit_dpm_table(void *handle, enum PP_OD_DPM_TABLE_COMMAND type,
+ long *input, uint32_t size)
{
struct pp_hwmgr *hwmgr = handle;
@@ -1507,7 +1508,7 @@ static void pp_pm_compute_clocks(void *handle)
struct pp_hwmgr *hwmgr = handle;
struct amdgpu_device *adev = hwmgr->adev;
- if (!amdgpu_device_has_dc_support(adev)) {
+ if (!adev->dc_enabled) {
amdgpu_dpm_get_active_displays(adev);
adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count;
adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c
index 67d7da0b6fed..1d829402cd2e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c
@@ -75,8 +75,10 @@ int psm_init_power_state_table(struct pp_hwmgr *hwmgr)
for (i = 0; i < table_entries; i++) {
result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
if (result) {
+ kfree(hwmgr->current_ps);
kfree(hwmgr->request_ps);
kfree(hwmgr->ps);
+ hwmgr->current_ps = NULL;
hwmgr->request_ps = NULL;
hwmgr->ps = NULL;
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
index dad3e3741a4e..190af79f3236 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
@@ -67,22 +67,21 @@ int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
int vega10_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr,
uint32_t *speed)
{
- uint32_t current_rpm;
- uint32_t percent = 0;
-
- if (hwmgr->thermal_controller.fanInfo.bNoFan)
- return 0;
+ struct amdgpu_device *adev = hwmgr->adev;
+ uint32_t duty100, duty;
+ uint64_t tmp64;
- if (vega10_get_current_rpm(hwmgr, &current_rpm))
- return -1;
+ duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
+ CG_FDO_CTRL1, FMAX_DUTY100);
+ duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
+ CG_THERMAL_STATUS, FDO_PWM_DUTY);
- if (hwmgr->thermal_controller.
- advanceFanControlParameters.usMaxFanRPM != 0)
- percent = current_rpm * 255 /
- hwmgr->thermal_controller.
- advanceFanControlParameters.usMaxFanRPM;
+ if (!duty100)
+ return -EINVAL;
- *speed = MIN(percent, 255);
+ tmp64 = (uint64_t)duty * 255;
+ do_div(tmp64, duty100);
+ *speed = MIN((uint32_t)tmp64, 255);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
index 97b3ad369046..b30684c84e20 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
@@ -2961,7 +2961,8 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
data->od8_settings.od8_settings_array;
OverDriveTable_t *od_table =
&(data->smc_state_table.overdrive_table);
- int32_t input_index, input_clk, input_vol, i;
+ int32_t input_clk, input_vol, i;
+ uint32_t input_index;
int od8_id;
int ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 4fe75dd2b329..ca3beb5d8f27 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -161,7 +161,7 @@ int smu_get_dpm_freq_range(struct smu_context *smu,
int smu_set_gfx_power_up_by_imu(struct smu_context *smu)
{
- if (!smu->ppt_funcs && !smu->ppt_funcs->set_gfx_power_up_by_imu)
+ if (!smu->ppt_funcs || !smu->ppt_funcs->set_gfx_power_up_by_imu)
return -EOPNOTSUPP;
return smu->ppt_funcs->set_gfx_power_up_by_imu(smu);
@@ -585,6 +585,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
yellow_carp_set_ppt_funcs(smu);
break;
case IP_VERSION(13, 0, 4):
+ case IP_VERSION(13, 0, 11):
smu_v13_0_4_set_ppt_funcs(smu);
break;
case IP_VERSION(13, 0, 5):
@@ -1156,22 +1157,21 @@ static int smu_smc_hw_setup(struct smu_context *smu)
uint64_t features_supported;
int ret = 0;
- if (adev->in_suspend && smu_is_dpm_running(smu)) {
- dev_info(adev->dev, "dpm has been enabled\n");
- /* this is needed specifically */
- switch (adev->ip_versions[MP1_HWIP][0]) {
- case IP_VERSION(11, 0, 7):
- case IP_VERSION(11, 0, 11):
- case IP_VERSION(11, 5, 0):
- case IP_VERSION(11, 0, 12):
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(11, 0, 7):
+ case IP_VERSION(11, 0, 11):
+ case IP_VERSION(11, 5, 0):
+ case IP_VERSION(11, 0, 12):
+ if (adev->in_suspend && smu_is_dpm_running(smu)) {
+ dev_info(adev->dev, "dpm has been enabled\n");
ret = smu_system_features_control(smu, true);
if (ret)
dev_err(adev->dev, "Failed system features control!\n");
- break;
- default:
- break;
+ return ret;
}
- return ret;
+ break;
+ default:
+ break;
}
ret = smu_init_display_count(smu, 0);
@@ -1449,6 +1449,7 @@ static int smu_disable_dpms(struct smu_context *smu)
switch (adev->ip_versions[MP1_HWIP][0]) {
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 7):
+ case IP_VERSION(13, 0, 10):
return 0;
default:
break;
@@ -1517,7 +1518,7 @@ static int smu_disable_dpms(struct smu_context *smu)
}
if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 4, 2) &&
- adev->gfx.rlc.funcs->stop)
+ !amdgpu_sriov_vf(adev) && adev->gfx.rlc.funcs->stop)
adev->gfx.rlc.funcs->stop(adev);
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index e2fa3b066b96..3bc4128a22ac 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -168,6 +168,7 @@ struct smu_temperature_range {
int mem_crit_max;
int mem_emergency_max;
int software_shutdown_temp;
+ int software_shutdown_temp_offset;
};
struct smu_state_validation_block {
@@ -568,6 +569,10 @@ struct smu_context
u32 param_reg;
u32 msg_reg;
u32 resp_reg;
+
+ u32 debug_param_reg;
+ u32 debug_msg_reg;
+ u32 debug_resp_reg;
};
struct i2c_adapter;
@@ -1388,6 +1393,14 @@ enum smu_cmn2asic_mapping_type {
CMN2ASIC_MAPPING_WORKLOAD,
};
+enum smu_baco_seq {
+ BACO_SEQ_BACO = 0,
+ BACO_SEQ_MSR,
+ BACO_SEQ_BAMACO,
+ BACO_SEQ_ULPS,
+ BACO_SEQ_COUNT,
+};
+
#define MSG_MAP(msg, index, valid_in_vf) \
[SMU_MSG_##msg] = {1, (index), (valid_in_vf)}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
index 25c08f963f49..d6b13933a98f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
@@ -25,10 +25,10 @@
// *** IMPORTANT ***
// PMFW TEAM: Always increment the interface version on any change to this file
-#define SMU13_DRIVER_IF_VERSION 0x2C
+#define SMU13_DRIVER_IF_VERSION 0x35
//Increment this version if SkuTable_t or BoardTable_t change
-#define PPTABLE_VERSION 0x20
+#define PPTABLE_VERSION 0x27
#define NUM_GFXCLK_DPM_LEVELS 16
#define NUM_SOCCLK_DPM_LEVELS 8
@@ -96,7 +96,7 @@
#define FEATURE_MEM_TEMP_READ_BIT 47
#define FEATURE_ATHUB_MMHUB_PG_BIT 48
#define FEATURE_SOC_PCC_BIT 49
-#define FEATURE_SPARE_50_BIT 50
+#define FEATURE_EDC_PWRBRK_BIT 50
#define FEATURE_SPARE_51_BIT 51
#define FEATURE_SPARE_52_BIT 52
#define FEATURE_SPARE_53_BIT 53
@@ -282,15 +282,15 @@ typedef enum {
} I2cControllerPort_e;
typedef enum {
- I2C_CONTROLLER_NAME_VR_GFX = 0,
- I2C_CONTROLLER_NAME_VR_SOC,
- I2C_CONTROLLER_NAME_VR_VMEMP,
- I2C_CONTROLLER_NAME_VR_VDDIO,
- I2C_CONTROLLER_NAME_LIQUID0,
- I2C_CONTROLLER_NAME_LIQUID1,
- I2C_CONTROLLER_NAME_PLX,
- I2C_CONTROLLER_NAME_OTHER,
- I2C_CONTROLLER_NAME_COUNT,
+ I2C_CONTROLLER_NAME_VR_GFX = 0,
+ I2C_CONTROLLER_NAME_VR_SOC,
+ I2C_CONTROLLER_NAME_VR_VMEMP,
+ I2C_CONTROLLER_NAME_VR_VDDIO,
+ I2C_CONTROLLER_NAME_LIQUID0,
+ I2C_CONTROLLER_NAME_LIQUID1,
+ I2C_CONTROLLER_NAME_PLX,
+ I2C_CONTROLLER_NAME_FAN_INTAKE,
+ I2C_CONTROLLER_NAME_COUNT,
} I2cControllerName_e;
typedef enum {
@@ -302,6 +302,7 @@ typedef enum {
I2C_CONTROLLER_THROTTLER_LIQUID0,
I2C_CONTROLLER_THROTTLER_LIQUID1,
I2C_CONTROLLER_THROTTLER_PLX,
+ I2C_CONTROLLER_THROTTLER_FAN_INTAKE,
I2C_CONTROLLER_THROTTLER_INA3221,
I2C_CONTROLLER_THROTTLER_COUNT,
} I2cControllerThrottler_e;
@@ -309,8 +310,9 @@ typedef enum {
typedef enum {
I2C_CONTROLLER_PROTOCOL_VR_XPDE132G5,
I2C_CONTROLLER_PROTOCOL_VR_IR35217,
- I2C_CONTROLLER_PROTOCOL_TMP_TMP102A,
+ I2C_CONTROLLER_PROTOCOL_TMP_MAX31875,
I2C_CONTROLLER_PROTOCOL_INA3221,
+ I2C_CONTROLLER_PROTOCOL_TMP_MAX6604,
I2C_CONTROLLER_PROTOCOL_COUNT,
} I2cControllerProtocol_e;
@@ -690,6 +692,9 @@ typedef struct {
#define PP_OD_FEATURE_UCLK_BIT 8
#define PP_OD_FEATURE_ZERO_FAN_BIT 9
#define PP_OD_FEATURE_TEMPERATURE_BIT 10
+#define PP_OD_FEATURE_POWER_FEATURE_CTRL_BIT 11
+#define PP_OD_FEATURE_ASIC_TDC_BIT 12
+#define PP_OD_FEATURE_COUNT 13
typedef enum {
PP_OD_POWER_FEATURE_ALWAYS_ENABLED,
@@ -697,6 +702,11 @@ typedef enum {
PP_OD_POWER_FEATURE_ALWAYS_DISABLED,
} PP_OD_POWER_FEATURE_e;
+typedef enum {
+ FAN_MODE_AUTO = 0,
+ FAN_MODE_MANUAL_LINEAR,
+} FanMode_e;
+
typedef struct {
uint32_t FeatureCtrlMask;
@@ -708,8 +718,8 @@ typedef struct {
uint8_t RuntimePwrSavingFeaturesCtrl;
//Frequency changes
- int16_t GfxclkFmin; // MHz
- int16_t GfxclkFmax; // MHz
+ int16_t GfxclkFmin; // MHz
+ int16_t GfxclkFmax; // MHz
uint16_t UclkFmin; // MHz
uint16_t UclkFmax; // MHz
@@ -730,7 +740,12 @@ typedef struct {
uint8_t MaxOpTemp;
uint8_t Padding[4];
- uint32_t Spare[12];
+ uint16_t GfxVoltageFullCtrlMode;
+ uint16_t GfxclkFullCtrlMode;
+ uint16_t UclkFullCtrlMode;
+ int16_t AsicTdc;
+
+ uint32_t Spare[10];
uint32_t MmHubPadding[8]; // SMU internal use. Adding here instead of external as a workaround
} OverDriveTable_t;
@@ -748,8 +763,8 @@ typedef struct {
uint8_t IdlePwrSavingFeaturesCtrl;
uint8_t RuntimePwrSavingFeaturesCtrl;
- uint16_t GfxclkFmin; // MHz
- uint16_t GfxclkFmax; // MHz
+ int16_t GfxclkFmin; // MHz
+ int16_t GfxclkFmax; // MHz
uint16_t UclkFmin; // MHz
uint16_t UclkFmax; // MHz
@@ -769,7 +784,12 @@ typedef struct {
uint8_t MaxOpTemp;
uint8_t Padding[4];
- uint32_t Spare[12];
+ uint16_t GfxVoltageFullCtrlMode;
+ uint16_t GfxclkFullCtrlMode;
+ uint16_t UclkFullCtrlMode;
+ int16_t AsicTdc;
+
+ uint32_t Spare[10];
} OverDriveLimits_t;
@@ -903,7 +923,8 @@ typedef struct {
uint16_t FanStartTempMin;
uint16_t FanStartTempMax;
- uint32_t Spare[12];
+ uint16_t PowerMinPpt0[POWER_SOURCE_COUNT];
+ uint32_t Spare[11];
} MsgLimits_t;
@@ -1086,11 +1107,13 @@ typedef struct {
uint32_t GfxoffSpare[15];
// GFX GPO
- float DfllBtcMasterScalerM;
+ uint32_t DfllBtcMasterScalerM;
int32_t DfllBtcMasterScalerB;
- float DfllBtcSlaveScalerM;
+ uint32_t DfllBtcSlaveScalerM;
int32_t DfllBtcSlaveScalerB;
- uint32_t GfxGpoSpare[12];
+ uint32_t DfllPccAsWaitCtrl; //GDFLL_AS_WAIT_CTRL_PCC register value to be passed to RLC msg
+ uint32_t DfllPccAsStepCtrl; //GDFLL_AS_STEP_CTRL_PCC register value to be passed to RLC msg
+ uint32_t GfxGpoSpare[10];
// GFX DCS
@@ -1106,7 +1129,10 @@ typedef struct {
uint16_t DcsTimeout; //This is the amount of time SMU FW waits for RLC to put GFX into GFXOFF before reverting to the fallback mechanism of throttling GFXCLK to Fmin.
- uint32_t DcsSpare[16];
+ uint32_t DcsSpare[14];
+
+ // UCLK section
+ uint16_t ShadowFreqTableUclk[NUM_UCLK_DPM_LEVELS]; // In MHz
// UCLK section
uint8_t UseStrobeModeOptimizations; //Set to indicate that FW should use strobe mode optimizations
@@ -1163,13 +1189,14 @@ typedef struct {
uint16_t IntakeTempHighIntakeAcousticLimit;
uint16_t IntakeTempAcouticLimitReleaseRate;
- uint16_t FanStalledTempLimitOffset;
+ int16_t FanAbnormalTempLimitOffset;
uint16_t FanStalledTriggerRpm;
- uint16_t FanAbnormalTriggerRpm;
- uint16_t FanPadding;
-
- uint32_t FanSpare[14];
+ uint16_t FanAbnormalTriggerRpmCoeff;
+ uint16_t FanAbnormalDetectionEnable;
+ uint8_t FanIntakeSensorSupport;
+ uint8_t FanIntakePadding[3];
+ uint32_t FanSpare[13];
// SECTION: VDD_GFX AVFS
uint8_t OverrideGfxAvfsFuses;
@@ -1193,7 +1220,6 @@ typedef struct {
uint32_t dGbV_dT_vmin;
uint32_t dGbV_dT_vmax;
- //Unused: PMFW-9370
uint32_t V2F_vmin_range_low;
uint32_t V2F_vmin_range_high;
uint32_t V2F_vmax_range_low;
@@ -1238,8 +1264,21 @@ typedef struct {
// SECTION: Advanced Options
uint32_t DebugOverrides;
+ // Section: Total Board Power idle vs active coefficients
+ uint8_t TotalBoardPowerSupport;
+ uint8_t TotalBoardPowerPadding[3];
+
+ int16_t TotalIdleBoardPowerM;
+ int16_t TotalIdleBoardPowerB;
+ int16_t TotalBoardPowerM;
+ int16_t TotalBoardPowerB;
+
+ QuadraticInt_t qFeffCoeffGameClock[POWER_SOURCE_COUNT];
+ QuadraticInt_t qFeffCoeffBaseClock[POWER_SOURCE_COUNT];
+ QuadraticInt_t qFeffCoeffBoostClock[POWER_SOURCE_COUNT];
+
// SECTION: Sku Reserved
- uint32_t Spare[64];
+ uint32_t Spare[43];
// Padding for MMHUB - do not modify this
uint32_t MmHubPadding[8];
@@ -1304,7 +1343,8 @@ typedef struct {
// SECTION: Clock Spread Spectrum
// UCLK Spread Spectrum
- uint16_t UclkSpreadPadding;
+ uint8_t UclkTrainingModeSpreadPercent; // Q4.4
+ uint8_t UclkSpreadPadding;
uint16_t UclkSpreadFreq; // kHz
// UCLK Spread Spectrum
@@ -1317,11 +1357,7 @@ typedef struct {
// Section: Memory Config
uint8_t DramWidth; // Width of interface to the channel for each DRAM module. See DRAM_BIT_WIDTH_TYPE_e
- uint8_t PaddingMem1[3];
-
- // Section: Total Board Power
- uint16_t TotalBoardPower; //Only needed for TCP Estimated case, where TCP = TGP+Total Board Power
- uint16_t BoardPowerPadding;
+ uint8_t PaddingMem1[7];
// SECTION: UMC feature flags
uint8_t HsrEnabled;
@@ -1423,8 +1459,11 @@ typedef struct {
uint16_t Vcn1ActivityPercentage ;
uint32_t EnergyAccumulator;
- uint16_t AverageSocketPower ;
+ uint16_t AverageSocketPower;
+ uint16_t AverageTotalBoardPower;
+
uint16_t AvgTemperature[TEMP_COUNT];
+ uint16_t AvgTemperatureFanIntake;
uint8_t PcieRate ;
uint8_t PcieWidth ;
@@ -1592,5 +1631,7 @@ typedef struct {
#define IH_INTERRUPT_CONTEXT_ID_AUDIO_D0 0x5
#define IH_INTERRUPT_CONTEXT_ID_AUDIO_D3 0x6
#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7
+#define IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8
+#define IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
index 9ebb8f39732a..8b8266890a10 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
@@ -131,7 +131,13 @@
#define PPSMC_MSG_EnableAudioStutterWA 0x44
#define PPSMC_MSG_PowerUpUmsch 0x45
#define PPSMC_MSG_PowerDownUmsch 0x46
-#define PPSMC_Message_Count 0x47
+#define PPSMC_MSG_SetDcsArch 0x47
+#define PPSMC_MSG_TriggerVFFLR 0x48
+#define PPSMC_MSG_SetNumBadMemoryPagesRetired 0x49
+#define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A
+#define PPSMC_MSG_SetPriorityDeltaGain 0x4B
+#define PPSMC_MSG_AllowIHHostInterrupt 0x4C
+#define PPSMC_Message_Count 0x4D
//Debug Dump Message
#define DEBUGSMC_MSG_TestMessage 0x1
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_4_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_4_ppsmc.h
index d9b0cd752200..f4d6c07b56ea 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_4_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_4_ppsmc.h
@@ -54,14 +54,14 @@
#define PPSMC_MSG_TestMessage 0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
#define PPSMC_MSG_GetPmfwVersion 0x02 ///< Get PMFW version
#define PPSMC_MSG_GetDriverIfVersion 0x03 ///< Get PMFW_DRIVER_IF version
-#define PPSMC_MSG_EnableGfxOff 0x04 ///< Enable GFXOFF
-#define PPSMC_MSG_DisableGfxOff 0x05 ///< Disable GFXOFF
+#define PPSMC_MSG_SPARE0 0x04 ///< SPARE
+#define PPSMC_MSG_SPARE1 0x05 ///< SPARE
#define PPSMC_MSG_PowerDownVcn 0x06 ///< Power down VCN
#define PPSMC_MSG_PowerUpVcn 0x07 ///< Power up VCN; VCN is power gated by default
#define PPSMC_MSG_SetHardMinVcn 0x08 ///< For wireless display
#define PPSMC_MSG_SetSoftMinGfxclk 0x09 ///< Set SoftMin for GFXCLK, argument is frequency in MHz
-#define PPSMC_MSG_ActiveProcessNotify 0x0A ///< Needs update
-#define PPSMC_MSG_ForcePowerDownGfx 0x0B ///< Force power down GFX, i.e. enter GFXOFF
+#define PPSMC_MSG_SPARE2 0x0A ///< SPARE
+#define PPSMC_MSG_SPARE3 0x0B ///< SPARE
#define PPSMC_MSG_PrepareMp1ForUnload 0x0C ///< Prepare PMFW for GFX driver unload
#define PPSMC_MSG_SetDriverDramAddrHigh 0x0D ///< Set high 32 bits of DRAM address for Driver table transfer
#define PPSMC_MSG_SetDriverDramAddrLow 0x0E ///< Set low 32 bits of DRAM address for Driver table transfer
@@ -73,8 +73,7 @@
#define PPSMC_MSG_SetSoftMinFclk 0x14 ///< Set hard min for FCLK
#define PPSMC_MSG_SetSoftMinVcn 0x15 ///< Set soft min for VCN clocks (VCLK and DCLK)
-
-#define PPSMC_MSG_EnableGfxImu 0x16 ///< Needs update
+#define PPSMC_MSG_EnableGfxImu 0x16 ///< Enable GFX IMU
#define PPSMC_MSG_GetGfxclkFrequency 0x17 ///< Get GFX clock frequency
#define PPSMC_MSG_GetFclkFrequency 0x18 ///< Get FCLK frequency
@@ -102,8 +101,8 @@
#define PPSMC_MSG_SetHardMinIspxclkByFreq 0x2C ///< Set HardMin by frequency for ISPXCLK
#define PPSMC_MSG_PowerDownUmsch 0x2D ///< Power down VCN.UMSCH (aka VSCH) scheduler
#define PPSMC_MSG_PowerUpUmsch 0x2E ///< Power up VCN.UMSCH (aka VSCH) scheduler
-#define PPSMC_Message_IspStutterOn_MmhubPgDis 0x2F ///< ISP StutterOn mmHub PgDis
-#define PPSMC_Message_IspStutterOff_MmhubPgEn 0x30 ///< ISP StufferOff mmHub PgEn
+#define PPSMC_MSG_IspStutterOn_MmhubPgDis 0x2F ///< ISP StutterOn mmHub PgDis
+#define PPSMC_MSG_IspStutterOff_MmhubPgEn 0x30 ///< ISP StufferOff mmHub PgEn
#define PPSMC_Message_Count 0x31 ///< Total number of PPSMC messages
/** @}*/
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index 58098b82df66..a4e3425b1027 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -239,7 +239,9 @@
__SMU_DUMMY_MAP(DriverMode2Reset), \
__SMU_DUMMY_MAP(GetGfxOffStatus), \
__SMU_DUMMY_MAP(GetGfxOffEntryCount), \
- __SMU_DUMMY_MAP(LogGfxOffResidency),
+ __SMU_DUMMY_MAP(LogGfxOffResidency), \
+ __SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired), \
+ __SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel),
#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
index a9215494dcdd..d466db6f0ad4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
@@ -147,14 +147,6 @@ struct smu_11_5_power_context {
uint32_t max_fast_ppt_limit;
};
-enum smu_v11_0_baco_seq {
- BACO_SEQ_BACO = 0,
- BACO_SEQ_MSR,
- BACO_SEQ_BAMACO,
- BACO_SEQ_ULPS,
- BACO_SEQ_COUNT,
-};
-
#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3)
int smu_v11_0_init_microcode(struct smu_context *smu);
@@ -257,7 +249,7 @@ int smu_v11_0_baco_enter(struct smu_context *smu);
int smu_v11_0_baco_exit(struct smu_context *smu);
int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu,
- enum smu_v11_0_baco_seq baco_seq);
+ enum smu_baco_seq baco_seq);
int smu_v11_0_mode1_reset(struct smu_context *smu);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index 80fb583b18d9..865d6358918d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -31,7 +31,7 @@
#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x07
#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04
#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10 0x32
-#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x2C
+#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x35
#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_10 0x1D
#define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms
@@ -124,14 +124,6 @@ struct smu_13_0_power_context {
enum smu_13_0_power_state power_state;
};
-enum smu_v13_0_baco_seq {
- BACO_SEQ_BACO = 0,
- BACO_SEQ_MSR,
- BACO_SEQ_BAMACO,
- BACO_SEQ_ULPS,
- BACO_SEQ_COUNT,
-};
-
#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3)
int smu_v13_0_init_microcode(struct smu_context *smu);
@@ -218,6 +210,9 @@ int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu);
int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
struct pp_smu_nv_clock_table *max_clocks);
+int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu,
+ enum smu_baco_seq baco_seq);
+
bool smu_v13_0_baco_is_support(struct smu_context *smu);
enum smu_baco_state smu_v13_0_baco_get_state(struct smu_context *smu);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 74996a8fb671..697e98a0a20a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -377,7 +377,13 @@ static void sienna_cichlid_check_bxco_support(struct smu_context *smu)
if (((adev->pdev->device == 0x73A1) &&
(adev->pdev->revision == 0x00)) ||
((adev->pdev->device == 0x73BF) &&
- (adev->pdev->revision == 0xCF)))
+ (adev->pdev->revision == 0xCF)) ||
+ ((adev->pdev->device == 0x7422) &&
+ (adev->pdev->revision == 0x00)) ||
+ ((adev->pdev->device == 0x73A3) &&
+ (adev->pdev->revision == 0x00)) ||
+ ((adev->pdev->device == 0x73E3) &&
+ (adev->pdev->revision == 0x00)))
smu_baco->platform_support = false;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index dccbd9f70723..ad66d57aa102 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -79,6 +79,17 @@ MODULE_FIRMWARE("amdgpu/beige_goby_smc.bin");
#define mmTHM_BACO_CNTL_ARCT 0xA7
#define mmTHM_BACO_CNTL_ARCT_BASE_IDX 0
+static void smu_v11_0_poll_baco_exit(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t data, loop = 0;
+
+ do {
+ usleep_range(1000, 1100);
+ data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL);
+ } while ((data & 0x100) && (++loop < 100));
+}
+
int smu_v11_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -1576,7 +1587,7 @@ int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu)
}
int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu,
- enum smu_v11_0_baco_seq baco_seq)
+ enum smu_baco_seq baco_seq)
{
return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ArmD3, baco_seq, NULL);
}
@@ -1588,6 +1599,10 @@ bool smu_v11_0_baco_is_support(struct smu_context *smu)
if (amdgpu_sriov_vf(smu->adev) || !smu_baco->platform_support)
return false;
+ /* return true if ASIC is in BACO state already */
+ if (smu_v11_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER)
+ return true;
+
/* Arcturus does not support this bit mask */
if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) &&
!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
@@ -1685,7 +1700,18 @@ int smu_v11_0_baco_enter(struct smu_context *smu)
int smu_v11_0_baco_exit(struct smu_context *smu)
{
- return smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT);
+ int ret;
+
+ ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT);
+ if (!ret) {
+ /*
+ * Poll BACO exit status to ensure FW has completed
+ * BACO exit process to avoid timing issues.
+ */
+ smu_v11_0_poll_baco_exit(smu);
+ }
+
+ return ret;
}
int smu_v11_0_mode1_reset(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index 43fb102a65f5..f5e90e0a99df 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -250,6 +250,7 @@ int smu_v13_0_check_fw_status(struct smu_context *smu)
switch (adev->ip_versions[MP1_HWIP][0]) {
case IP_VERSION(13, 0, 4):
+ case IP_VERSION(13, 0, 11):
mp1_fw_flags = RREG32_PCIE(MP1_Public |
(smnMP1_V13_0_4_FIRMWARE_FLAGS & 0xffffffff));
break;
@@ -301,6 +302,7 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_YELLOW_CARP;
break;
case IP_VERSION(13, 0, 4):
+ case IP_VERSION(13, 0, 11):
smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_4;
break;
case IP_VERSION(13, 0, 5):
@@ -841,6 +843,7 @@ int smu_v13_0_gfx_off_control(struct smu_context *smu, bool enable)
case IP_VERSION(13, 0, 7):
case IP_VERSION(13, 0, 8):
case IP_VERSION(13, 0, 10):
+ case IP_VERSION(13, 0, 11):
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
if (enable)
@@ -1376,6 +1379,7 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev,
*/
uint32_t ctxid = entry->src_data[0];
uint32_t data;
+ uint32_t high;
if (client_id == SOC15_IH_CLIENTID_THM) {
switch (src_id) {
@@ -1432,6 +1436,36 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev,
schedule_work(&smu->throttling_logging_work);
break;
+ case 0x8:
+ high = smu->thermal_range.software_shutdown_temp +
+ smu->thermal_range.software_shutdown_temp_offset;
+ high = min_t(typeof(high),
+ SMU_THERMAL_MAXIMUM_ALERT_TEMP,
+ high);
+ dev_emerg(adev->dev, "Reduce soft CTF limit to %d (by an offset %d)\n",
+ high,
+ smu->thermal_range.software_shutdown_temp_offset);
+
+ data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL);
+ data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL,
+ DIG_THERM_INTH,
+ (high & 0xff));
+ data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
+ WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data);
+ break;
+ case 0x9:
+ high = min_t(typeof(high),
+ SMU_THERMAL_MAXIMUM_ALERT_TEMP,
+ smu->thermal_range.software_shutdown_temp);
+ dev_emerg(adev->dev, "Recover soft CTF limit to %d\n", high);
+
+ data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL);
+ data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL,
+ DIG_THERM_INTH,
+ (high & 0xff));
+ data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
+ WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data);
+ break;
}
}
}
@@ -2230,6 +2264,15 @@ int smu_v13_0_gfx_ulv_control(struct smu_context *smu,
return ret;
}
+int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu,
+ enum smu_baco_seq baco_seq)
+{
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_ArmD3,
+ baco_seq,
+ NULL);
+}
+
bool smu_v13_0_baco_is_support(struct smu_context *smu)
{
struct smu_baco_context *smu_baco = &smu->smu_baco;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 29529328152d..87d7c66e49ef 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -70,6 +70,26 @@
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
+#define mmMP1_SMN_C2PMSG_66 0x0282
+#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_82 0x0292
+#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_90 0x029a
+#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_75 0x028b
+#define mmMP1_SMN_C2PMSG_75_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_53 0x0275
+#define mmMP1_SMN_C2PMSG_53_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_54 0x0276
+#define mmMP1_SMN_C2PMSG_54_BASE_IDX 0
+
+#define DEBUGSMC_MSG_Mode1Reset 2
+
static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
@@ -120,6 +140,10 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0),
MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0),
MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
+ MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
+ MSG_MAP(SetNumBadMemoryPagesRetired, PPSMC_MSG_SetNumBadMemoryPagesRetired, 0),
+ MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel,
+ PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel, 0),
};
static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
@@ -1566,6 +1590,31 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
NULL);
}
+static int smu_v13_0_0_baco_enter(struct smu_context *smu)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))
+ return smu_v13_0_baco_set_armd3_sequence(smu,
+ smu_baco->maco_support ? BACO_SEQ_BAMACO : BACO_SEQ_BACO);
+ else
+ return smu_v13_0_baco_enter(smu);
+}
+
+static int smu_v13_0_0_baco_exit(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {
+ /* Wait for PMFW handling for the Dstate change */
+ usleep_range(10000, 11000);
+ return smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS);
+ } else {
+ return smu_v13_0_baco_exit(smu);
+ }
+}
+
static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -1763,6 +1812,69 @@ static int smu_v13_0_0_set_df_cstate(struct smu_context *smu,
NULL);
}
+static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
+{
+ int ret;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
+ ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
+ else
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL);
+
+ if (!ret)
+ msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
+
+ return ret;
+}
+
+static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+
+ smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
+ smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
+ smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
+}
+
+static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu,
+ uint32_t size)
+{
+ int ret = 0;
+
+ /* message SMU to update the bad page number on SMUBUS */
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_SetNumBadMemoryPagesRetired,
+ size, NULL);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "[%s] failed to message SMU to update bad memory pages number\n",
+ __func__);
+
+ return ret;
+}
+
+static int smu_v13_0_0_send_bad_mem_channel_flag(struct smu_context *smu,
+ uint32_t size)
+{
+ int ret = 0;
+
+ /* message SMU to update the bad channel info on SMUBUS */
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,
+ size, NULL);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "[%s] failed to message SMU to update bad memory pages channel info\n",
+ __func__);
+
+ return ret;
+}
+
static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
@@ -1827,12 +1939,14 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.baco_is_support = smu_v13_0_baco_is_support,
.baco_get_state = smu_v13_0_baco_get_state,
.baco_set_state = smu_v13_0_baco_set_state,
- .baco_enter = smu_v13_0_baco_enter,
- .baco_exit = smu_v13_0_baco_exit,
+ .baco_enter = smu_v13_0_0_baco_enter,
+ .baco_exit = smu_v13_0_0_baco_exit,
.mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported,
- .mode1_reset = smu_v13_0_mode1_reset,
+ .mode1_reset = smu_v13_0_0_mode1_reset,
.set_mp1_state = smu_v13_0_0_set_mp1_state,
.set_df_cstate = smu_v13_0_0_set_df_cstate,
+ .send_hbm_bad_pages_num = smu_v13_0_0_smu_send_bad_mem_page_num,
+ .send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
};
void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
@@ -1844,5 +1958,5 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
smu->table_map = smu_v13_0_0_table_map;
smu->pwr_src_map = smu_v13_0_0_pwr_src_map;
smu->workload_map = smu_v13_0_0_workload_map;
- smu_v13_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_0_set_smu_mailbox_registers(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index 97e1d55dcaad..8fa9a36c38b6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -1026,6 +1026,15 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = {
.set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu,
};
+static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+}
+
void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -1035,7 +1044,9 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu)
smu->feature_map = smu_v13_0_4_feature_mask_map;
smu->table_map = smu_v13_0_4_table_map;
smu->is_apu = true;
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+
+ if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 4))
+ smu_v13_0_4_set_smu_mailbox_registers(smu);
+ else
+ smu_v13_0_set_smu_mailbox_registers(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c4102cfb734c..c3c9ef523e59 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -122,6 +122,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0),
MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0),
MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
+ MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
};
static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
@@ -1222,6 +1223,7 @@ static int smu_v13_0_7_get_thermal_temperature_range(struct smu_context *smu,
range->mem_emergency_max = (pptable->SkuTable.TemperatureLimit[TEMP_MEM] + CTF_OFFSET_MEM)*
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
range->software_shutdown_temp = powerplay_table->software_shutdown_temp;
+ range->software_shutdown_temp_offset = pptable->SkuTable.FanAbnormalTempLimitOffset;
return 0;
}
@@ -1578,6 +1580,31 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu,
return ret;
}
+static int smu_v13_0_7_baco_enter(struct smu_context *smu)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))
+ return smu_v13_0_baco_set_armd3_sequence(smu,
+ smu_baco->maco_support ? BACO_SEQ_BAMACO : BACO_SEQ_BACO);
+ else
+ return smu_v13_0_baco_enter(smu);
+}
+
+static int smu_v13_0_7_baco_exit(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {
+ /* Wait for PMFW handling for the Dstate change */
+ usleep_range(10000, 11000);
+ return smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS);
+ } else {
+ return smu_v13_0_baco_exit(smu);
+ }
+}
+
static bool smu_v13_0_7_is_mode1_reset_supported(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -1655,8 +1682,8 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.baco_is_support = smu_v13_0_baco_is_support,
.baco_get_state = smu_v13_0_baco_get_state,
.baco_set_state = smu_v13_0_baco_set_state,
- .baco_enter = smu_v13_0_baco_enter,
- .baco_exit = smu_v13_0_baco_exit,
+ .baco_enter = smu_v13_0_7_baco_enter,
+ .baco_exit = smu_v13_0_7_baco_exit,
.mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported,
.mode1_reset = smu_v13_0_mode1_reset,
.set_mp1_state = smu_v13_0_7_set_mp1_state,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index e4f8f90ac5aa..768b6e7dbd77 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -233,6 +233,18 @@ static void __smu_cmn_send_msg(struct smu_context *smu,
WREG32(smu->msg_reg, msg);
}
+static int __smu_cmn_send_debug_msg(struct smu_context *smu,
+ u32 msg,
+ u32 param)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ WREG32(smu->debug_param_reg, param);
+ WREG32(smu->debug_msg_reg, msg);
+ WREG32(smu->debug_resp_reg, 0);
+
+ return 0;
+}
/**
* smu_cmn_send_msg_without_waiting -- send the message; don't wait for status
* @smu: pointer to an SMU context
@@ -386,6 +398,12 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
read_arg);
}
+int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
+ uint32_t msg)
+{
+ return __smu_cmn_send_debug_msg(smu, msg, 0);
+}
+
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
enum smu_cmn2asic_mapping_type type,
uint32_t index)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 1526ce09c399..f82cf76dd3a4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -42,6 +42,9 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
enum smu_message_type msg,
uint32_t *read_arg);
+int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
+ uint32_t msg);
+
int smu_cmn_wait_for_response(struct smu_context *smu);
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
index 9fce4239d4ad..3f4e719eebd8 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -9,7 +9,7 @@
#include <linux/platform_device.h>
#include <linux/component.h>
#include <linux/pm_runtime.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include "komeda_dev.h"
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index 451746ebbe71..62dc64550793 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -10,7 +10,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
@@ -59,7 +58,6 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
static const struct drm_driver komeda_kms_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
- .lastclose = drm_fb_helper_lastclose,
DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(komeda_gem_dma_dumb_create),
.fops = &komeda_cma_fops,
.name = "komeda",
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index 7030339fa232..3cfefadc7c9d 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -19,7 +19,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_of.h>
@@ -275,7 +274,7 @@ static void hdlcd_plane_atomic_update(struct drm_plane *plane,
dest_h = drm_rect_height(&new_plane_state->dst);
scanout_start = drm_fb_dma_get_gem_addr(fb, new_plane_state, 0);
- hdlcd = plane->dev->dev_private;
+ hdlcd = drm_to_hdlcd_priv(plane->dev);
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_LENGTH, fb->pitches[0]);
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_PITCH, fb->pitches[0]);
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_COUNT, dest_h - 1);
@@ -290,7 +289,6 @@ static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = {
static const struct drm_plane_funcs hdlcd_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
@@ -298,24 +296,19 @@ static const struct drm_plane_funcs hdlcd_plane_funcs = {
static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
{
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
struct drm_plane *plane = NULL;
u32 formats[ARRAY_SIZE(supported_formats)], i;
- int ret;
-
- plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL);
- if (!plane)
- return ERR_PTR(-ENOMEM);
for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
formats[i] = supported_formats[i].fourcc;
- ret = drm_universal_plane_init(drm, plane, 0xff, &hdlcd_plane_funcs,
- formats, ARRAY_SIZE(formats),
- NULL,
- DRM_PLANE_TYPE_PRIMARY, NULL);
- if (ret)
- return ERR_PTR(ret);
+ plane = drmm_universal_plane_alloc(drm, struct drm_plane, dev, 0xff,
+ &hdlcd_plane_funcs,
+ formats, ARRAY_SIZE(formats),
+ NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (IS_ERR(plane))
+ return plane;
drm_plane_helper_add(plane, &hdlcd_plane_helper_funcs);
hdlcd->plane = plane;
@@ -325,7 +318,7 @@ static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
int hdlcd_setup_crtc(struct drm_device *drm)
{
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
struct drm_plane *primary;
int ret;
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index a032003c340c..7043d1c9ed8f 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -26,7 +26,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
@@ -98,7 +98,7 @@ static void hdlcd_irq_uninstall(struct hdlcd_drm_private *hdlcd)
static int hdlcd_load(struct drm_device *drm, unsigned long flags)
{
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
struct platform_device *pdev = to_platform_device(drm->dev);
struct resource *res;
u32 version;
@@ -175,14 +175,21 @@ static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
-static void hdlcd_setup_mode_config(struct drm_device *drm)
+static int hdlcd_setup_mode_config(struct drm_device *drm)
{
- drm_mode_config_init(drm);
+ int ret;
+
+ ret = drmm_mode_config_init(drm);
+ if (ret)
+ return ret;
+
drm->mode_config.min_width = 0;
drm->mode_config.min_height = 0;
drm->mode_config.max_width = HDLCD_MAX_XRES;
drm->mode_config.max_height = HDLCD_MAX_YRES;
drm->mode_config.funcs = &hdlcd_mode_config_funcs;
+
+ return 0;
}
#ifdef CONFIG_DEBUG_FS
@@ -190,7 +197,7 @@ static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *drm = node->minor->dev;
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
seq_printf(m, "underrun : %d\n", atomic_read(&hdlcd->buffer_underrun_count));
seq_printf(m, "dma_end : %d\n", atomic_read(&hdlcd->dma_end_count));
@@ -203,7 +210,7 @@ static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *drm = node->minor->dev;
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
unsigned long clkrate = clk_get_rate(hdlcd->clk);
unsigned long mode_clock = hdlcd->crtc.mode.crtc_clock * 1000;
@@ -247,18 +254,18 @@ static int hdlcd_drm_bind(struct device *dev)
struct hdlcd_drm_private *hdlcd;
int ret;
- hdlcd = devm_kzalloc(dev, sizeof(*hdlcd), GFP_KERNEL);
- if (!hdlcd)
- return -ENOMEM;
+ hdlcd = devm_drm_dev_alloc(dev, &hdlcd_driver, typeof(*hdlcd), base);
+ if (IS_ERR(hdlcd))
+ return PTR_ERR(hdlcd);
- drm = drm_dev_alloc(&hdlcd_driver, dev);
- if (IS_ERR(drm))
- return PTR_ERR(drm);
+ drm = &hdlcd->base;
- drm->dev_private = hdlcd;
dev_set_drvdata(dev, drm);
- hdlcd_setup_mode_config(drm);
+ ret = hdlcd_setup_mode_config(drm);
+ if (ret)
+ goto err_free;
+
ret = hdlcd_load(drm, 0);
if (ret)
goto err_free;
@@ -317,17 +324,14 @@ err_unload:
hdlcd_irq_uninstall(hdlcd);
of_reserved_mem_device_release(drm->dev);
err_free:
- drm_mode_config_cleanup(drm);
dev_set_drvdata(dev, NULL);
- drm_dev_put(drm);
-
return ret;
}
static void hdlcd_drm_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct hdlcd_drm_private *hdlcd = drm->dev_private;
+ struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
@@ -341,10 +345,7 @@ static void hdlcd_drm_unbind(struct device *dev)
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
of_reserved_mem_device_release(dev);
- drm_mode_config_cleanup(drm);
- drm->dev_private = NULL;
dev_set_drvdata(dev, NULL);
- drm_dev_put(drm);
}
static const struct component_master_ops hdlcd_master_ops = {
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
index 909c39c28487..f1c1da2ac2db 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.h
+++ b/drivers/gpu/drm/arm/hdlcd_drv.h
@@ -7,6 +7,7 @@
#define __HDLCD_DRV_H__
struct hdlcd_drm_private {
+ struct drm_device base;
void __iomem *mmio;
struct clk *clk;
struct drm_crtc crtc;
@@ -20,6 +21,7 @@ struct hdlcd_drm_private {
#endif
};
+#define drm_to_hdlcd_priv(x) container_of(x, struct hdlcd_drm_private, base)
#define crtc_to_hdlcd_priv(x) container_of(x, struct hdlcd_drm_private, crtc)
static inline void hdlcd_write(struct hdlcd_drm_private *hdlcd,
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 962730772b2f..dc01c43f6193 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -514,7 +514,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs malidp_crtc_funcs = {
- .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = malidp_crtc_reset,
@@ -526,7 +525,7 @@ static const struct drm_crtc_funcs malidp_crtc_funcs = {
int malidp_crtc_init(struct drm_device *drm)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct drm_plane *primary = NULL, *plane;
int ret;
@@ -548,8 +547,8 @@ int malidp_crtc_init(struct drm_device *drm)
return -EINVAL;
}
- ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
- &malidp_crtc_funcs, NULL);
+ ret = drmm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
+ &malidp_crtc_funcs, NULL);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 1d0b0c54ccc7..589c1c66a6dc 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -19,10 +19,11 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
@@ -168,7 +169,7 @@ static void malidp_atomic_commit_se_config(struct drm_crtc *crtc,
*/
static int malidp_set_and_wait_config_valid(struct drm_device *drm)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
int ret;
@@ -189,7 +190,7 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm)
static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
{
struct drm_device *drm = state->dev;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
int loop = 5;
malidp->event = malidp->crtc.state->event;
@@ -230,7 +231,7 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *drm = state->dev;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
int i;
@@ -392,10 +393,12 @@ static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
static int malidp_init(struct drm_device *drm)
{
int ret;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
- drm_mode_config_init(drm);
+ ret = drmm_mode_config_init(drm);
+ if (ret)
+ goto out;
drm->mode_config.min_width = hwdev->min_line_size;
drm->mode_config.min_height = hwdev->min_line_size;
@@ -406,29 +409,21 @@ static int malidp_init(struct drm_device *drm)
ret = malidp_crtc_init(drm);
if (ret)
- goto crtc_fail;
+ goto out;
ret = malidp_mw_connector_init(drm);
if (ret)
- goto crtc_fail;
-
- return 0;
+ goto out;
-crtc_fail:
- drm_mode_config_cleanup(drm);
+out:
return ret;
}
-static void malidp_fini(struct drm_device *drm)
-{
- drm_mode_config_cleanup(drm);
-}
-
static int malidp_irq_init(struct platform_device *pdev)
{
int irq_de, irq_se, ret = 0;
struct drm_device *drm = dev_get_drvdata(&pdev->dev);
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
/* fetch the interrupts from DT */
@@ -462,7 +457,7 @@ static int malidp_dumb_create(struct drm_file *file_priv,
struct drm_device *drm,
struct drm_mode_create_dumb *args)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
/* allocate for the worst case scenario, i.e. rotated buffers */
u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 1);
@@ -508,7 +503,7 @@ static void malidp_error_stats_dump(const char *prefix,
static int malidp_show_stats(struct seq_file *m, void *arg)
{
struct drm_device *drm = m->private;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
unsigned long irqflags;
struct malidp_error_stats de_errors, se_errors;
@@ -531,7 +526,7 @@ static ssize_t malidp_debugfs_write(struct file *file, const char __user *ubuf,
{
struct seq_file *m = file->private_data;
struct drm_device *drm = m->private;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
unsigned long irqflags;
spin_lock_irqsave(&malidp->errors_lock, irqflags);
@@ -552,7 +547,7 @@ static const struct file_operations malidp_debugfs_fops = {
static void malidp_debugfs_init(struct drm_minor *minor)
{
- struct malidp_drm *malidp = minor->dev->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(minor->dev);
malidp_error_stats_init(&malidp->de_errors);
malidp_error_stats_init(&malidp->se_errors);
@@ -652,7 +647,7 @@ static ssize_t core_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
return snprintf(buf, PAGE_SIZE, "%08x\n", malidp->core_id);
}
@@ -670,7 +665,7 @@ ATTRIBUTE_GROUPS(mali_dp);
static int malidp_runtime_pm_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
/* we can only suspend if the hardware is in config mode */
@@ -689,7 +684,7 @@ static int malidp_runtime_pm_suspend(struct device *dev)
static int malidp_runtime_pm_resume(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
clk_prepare_enable(hwdev->pclk);
@@ -716,11 +711,13 @@ static int malidp_bind(struct device *dev)
int ret = 0, i;
u32 version, out_depth = 0;
- malidp = devm_kzalloc(dev, sizeof(*malidp), GFP_KERNEL);
- if (!malidp)
- return -ENOMEM;
+ malidp = devm_drm_dev_alloc(dev, &malidp_driver, typeof(*malidp), base);
+ if (IS_ERR(malidp))
+ return PTR_ERR(malidp);
+
+ drm = &malidp->base;
- hwdev = devm_kzalloc(dev, sizeof(*hwdev), GFP_KERNEL);
+ hwdev = drmm_kzalloc(drm, sizeof(*hwdev), GFP_KERNEL);
if (!hwdev)
return -ENOMEM;
@@ -753,13 +750,6 @@ static int malidp_bind(struct device *dev)
if (ret && ret != -ENODEV)
return ret;
- drm = drm_dev_alloc(&malidp_driver, dev);
- if (IS_ERR(drm)) {
- ret = PTR_ERR(drm);
- goto alloc_fail;
- }
-
- drm->dev_private = malidp;
dev_set_drvdata(dev, drm);
/* Enable power management */
@@ -878,17 +868,13 @@ irq_init_fail:
bind_fail:
of_node_put(malidp->crtc.port);
malidp->crtc.port = NULL;
- malidp_fini(drm);
query_hw_fail:
pm_runtime_put(dev);
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
malidp_runtime_pm_suspend(dev);
- drm->dev_private = NULL;
dev_set_drvdata(dev, NULL);
- drm_dev_put(drm);
-alloc_fail:
of_reserved_mem_device_release(dev);
return ret;
@@ -897,7 +883,7 @@ alloc_fail:
static void malidp_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
drm_dev_unregister(drm);
@@ -909,15 +895,12 @@ static void malidp_unbind(struct device *dev)
component_unbind_all(dev, drm);
of_node_put(malidp->crtc.port);
malidp->crtc.port = NULL;
- malidp_fini(drm);
pm_runtime_put(dev);
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
malidp_runtime_pm_suspend(dev);
- drm->dev_private = NULL;
dev_set_drvdata(dev, NULL);
- drm_dev_put(drm);
of_reserved_mem_device_release(dev);
}
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index cdfddfabf2d1..bc0387876dea 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -29,6 +29,7 @@ struct malidp_error_stats {
};
struct malidp_drm {
+ struct drm_device base;
struct malidp_hw_device *dev;
struct drm_crtc crtc;
struct drm_writeback_connector mw_connector;
@@ -44,6 +45,7 @@ struct malidp_drm {
#endif
};
+#define drm_to_malidp(x) container_of(x, struct malidp_drm, base)
#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc)
struct malidp_plane {
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index e9de542f9b7c..9b845d3f34e1 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -1168,7 +1168,7 @@ static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 ir
static irqreturn_t malidp_de_irq(int irq, void *arg)
{
struct drm_device *drm = arg;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev;
struct malidp_hw *hw;
const struct malidp_irq_map *de;
@@ -1226,7 +1226,7 @@ static irqreturn_t malidp_de_irq(int irq, void *arg)
static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
{
struct drm_device *drm = arg;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
wake_up(&malidp->wq);
@@ -1252,7 +1252,7 @@ void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
int malidp_de_irq_init(struct drm_device *drm, int irq)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
int ret;
@@ -1286,7 +1286,7 @@ void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
static irqreturn_t malidp_se_irq(int irq, void *arg)
{
struct drm_device *drm = arg;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
struct malidp_hw *hw = hwdev->hw;
const struct malidp_irq_map *se = &hw->map.se_irq_map;
@@ -1363,7 +1363,7 @@ static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
int malidp_se_irq_init(struct drm_device *drm, int irq)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct malidp_hw_device *hwdev = malidp->dev;
int ret;
diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index ef76d0e6ee2f..626709bec6f5 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -129,7 +129,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state);
- struct malidp_drm *malidp = encoder->dev->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(encoder->dev);
struct drm_framebuffer *fb;
int i, n_planes;
@@ -207,7 +207,7 @@ static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats)
int malidp_mw_connector_init(struct drm_device *drm)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
u32 *formats;
int ret, n_formats;
@@ -236,7 +236,7 @@ int malidp_mw_connector_init(struct drm_device *drm)
void malidp_mw_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *old_state)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
struct drm_writeback_connector *mw_conn = &malidp->mw_connector;
struct drm_connector_state *conn_state = mw_conn->base.state;
struct malidp_hw_device *hwdev = malidp->dev;
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 45f5e35e7f24..34547edf1ee3 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -68,14 +68,6 @@
/* readahead for partial-frame prefetch */
#define MALIDP_MMU_PREFETCH_READAHEAD 8
-static void malidp_de_plane_destroy(struct drm_plane *plane)
-{
- struct malidp_plane *mp = to_malidp_plane(plane);
-
- drm_plane_cleanup(plane);
- kfree(mp);
-}
-
/*
* Replicate what the default ->reset hook does: free the state pointer and
* allocate a new empty object. We just need enough space to store
@@ -151,7 +143,7 @@ bool malidp_format_mod_supported(struct drm_device *drm,
{
const struct drm_format_info *info;
const u64 *modifiers;
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
@@ -260,7 +252,6 @@ static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
static const struct drm_plane_funcs malidp_de_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = malidp_de_plane_destroy,
.reset = malidp_plane_reset,
.atomic_duplicate_state = malidp_duplicate_plane_state,
.atomic_destroy_state = malidp_destroy_plane_state,
@@ -931,7 +922,7 @@ static const uint64_t linear_only_modifiers[] = {
int malidp_de_planes_init(struct drm_device *drm)
{
- struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_drm *malidp = drm_to_malidp(drm);
const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
struct malidp_plane *plane = NULL;
enum drm_plane_type plane_type;
@@ -972,12 +963,6 @@ int malidp_de_planes_init(struct drm_device *drm)
for (i = 0; i < map->n_layers; i++) {
u8 id = map->layers[i].id;
- plane = kzalloc(sizeof(*plane), GFP_KERNEL);
- if (!plane) {
- ret = -ENOMEM;
- goto cleanup;
- }
-
/* build the list of DRM supported formats based on the map */
for (n = 0, j = 0; j < map->n_pixel_formats; j++) {
if ((map->pixel_formats[j].layer & id) == id)
@@ -990,13 +975,14 @@ int malidp_de_planes_init(struct drm_device *drm)
/*
* All the layers except smart layer supports AFBC modifiers.
*/
- ret = drm_universal_plane_init(drm, &plane->base, crtcs,
- &malidp_de_plane_funcs, formats, n,
- (id == DE_SMART) ? linear_only_modifiers : modifiers,
- plane_type, NULL);
-
- if (ret < 0)
+ plane = drmm_universal_plane_alloc(drm, struct malidp_plane, base,
+ crtcs, &malidp_de_plane_funcs, formats, n,
+ (id == DE_SMART) ? linear_only_modifiers :
+ modifiers, plane_type, NULL);
+ if (IS_ERR(plane)) {
+ ret = PTR_ERR(plane);
goto cleanup;
+ }
drm_plane_helper_add(&plane->base,
&malidp_de_plane_helper_funcs);
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index 38f5170c0fea..584cee123bd8 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -19,6 +19,8 @@
static const struct fb_ops armada_fb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_read = drm_fb_helper_cfb_read,
+ .fb_write = drm_fb_helper_cfb_write,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
@@ -72,7 +74,7 @@ static int armada_fbdev_create(struct drm_fb_helper *fbh,
if (IS_ERR(dfb))
return PTR_ERR(dfb);
- info = drm_fb_helper_alloc_fbi(fbh);
+ info = drm_fb_helper_alloc_info(fbh);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto err_fballoc;
@@ -155,7 +157,7 @@ void armada_fbdev_fini(struct drm_device *dev)
struct drm_fb_helper *fbh = priv->fbdev;
if (fbh) {
- drm_fb_helper_unregister_fbi(fbh);
+ drm_fb_helper_unregister_info(fbh);
drm_fb_helper_fini(fbh);
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 5430265ad458..26d10065d534 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -66,8 +66,8 @@ void armada_gem_free_object(struct drm_gem_object *obj)
if (dobj->obj.import_attach) {
/* We only ever display imported data */
if (dobj->sgt)
- dma_buf_unmap_attachment(dobj->obj.import_attach,
- dobj->sgt, DMA_TO_DEVICE);
+ dma_buf_unmap_attachment_unlocked(dobj->obj.import_attach,
+ dobj->sgt, DMA_TO_DEVICE);
drm_prime_gem_destroy(&dobj->obj, NULL);
}
@@ -539,8 +539,8 @@ int armada_gem_map_import(struct armada_gem_object *dobj)
{
int ret;
- dobj->sgt = dma_buf_map_attachment(dobj->obj.import_attach,
- DMA_TO_DEVICE);
+ dobj->sgt = dma_buf_map_attachment_unlocked(dobj->obj.import_attach,
+ DMA_TO_DEVICE);
if (IS_ERR(dobj->sgt)) {
ret = PTR_ERR(dobj->sgt);
dobj->sgt = NULL;
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
index a94f1a9e8f40..718119e168a6 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig
index fbcf2f45cef5..d367a90cd3de 100644
--- a/drivers/gpu/drm/ast/Kconfig
+++ b/drivers/gpu/drm/ast/Kconfig
@@ -2,10 +2,8 @@
config DRM_AST
tristate "AST server chips"
depends on DRM && PCI && MMU
+ select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
- select DRM_VRAM_HELPER
- select DRM_TTM
- select DRM_TTM_HELPER
help
Say yes for experimental AST GPU driver. Do not enable
this driver without having a working -modesetting,
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index b9392f31e629..420fc75c240e 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -33,7 +33,8 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_gem_vram_helper.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_probe_helper.h>
@@ -63,7 +64,7 @@ static const struct drm_driver ast_driver = {
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
- DRM_GEM_VRAM_DRIVER
+ DRM_GEM_SHMEM_DRIVER_OPS
};
/*
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 2e44b971c3a6..d51b81fea9c8 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -38,7 +38,6 @@
#include <drm/drm_encoder.h>
#include <drm/drm_mode.h>
#include <drm/drm_framebuffer.h>
-#include <drm/drm_fb_helper.h>
#define DRIVER_AUTHOR "Dave Airlie"
@@ -87,7 +86,7 @@ enum ast_tx_chip {
#define AST_DRAM_8Gx16 8
/*
- * Cursor plane
+ * Hardware cursor
*/
#define AST_MAX_HWC_WIDTH 64
@@ -96,8 +95,6 @@ enum ast_tx_chip {
#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2)
#define AST_HWC_SIGNATURE_SIZE 32
-#define AST_DEFAULT_HWC_NUM 2
-
/* define for signature structure */
#define AST_HWC_SIGNATURE_CHECKSUM 0x00
#define AST_HWC_SIGNATURE_SizeX 0x04
@@ -107,22 +104,21 @@ enum ast_tx_chip {
#define AST_HWC_SIGNATURE_HOTSPOTX 0x14
#define AST_HWC_SIGNATURE_HOTSPOTY 0x18
-struct ast_cursor_plane {
- struct drm_plane base;
+/*
+ * Planes
+ */
- struct {
- struct drm_gem_vram_object *gbo;
- struct iosys_map map;
- u64 off;
- } hwc[AST_DEFAULT_HWC_NUM];
+struct ast_plane {
+ struct drm_plane base;
- unsigned int next_hwc_index;
+ void __iomem *vaddr;
+ u64 offset;
+ unsigned long size;
};
-static inline struct ast_cursor_plane *
-to_ast_cursor_plane(struct drm_plane *plane)
+static inline struct ast_plane *to_ast_plane(struct drm_plane *plane)
{
- return container_of(plane, struct ast_cursor_plane, base);
+ return container_of(plane, struct ast_plane, base);
}
/*
@@ -175,8 +171,13 @@ struct ast_private {
uint32_t dram_type;
uint32_t mclk;
- struct drm_plane primary_plane;
- struct ast_cursor_plane cursor_plane;
+ void __iomem *vram;
+ unsigned long vram_base;
+ unsigned long vram_size;
+ unsigned long vram_fb_available;
+
+ struct ast_plane primary_plane;
+ struct ast_plane cursor_plane;
struct drm_crtc crtc;
struct {
struct {
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 067453266897..bffa310a0431 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -32,7 +32,6 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
-#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_managed.h>
#include "ast_drv.h"
@@ -461,8 +460,8 @@ struct ast_private *ast_device_create(const struct drm_driver *drv,
/* map reserved buffer */
ast->dp501_fw_buf = NULL;
- if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) {
- ast->dp501_fw_buf = pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0);
+ if (ast->vram_size < pci_resource_len(pdev, 0)) {
+ ast->dp501_fw_buf = pci_iomap_range(pdev, 0, ast->vram_size, 0);
if (!ast->dp501_fw_buf)
drm_info(dev, "failed to map reserved buffer!\n");
}
diff --git a/drivers/gpu/drm/ast/ast_mm.c b/drivers/gpu/drm/ast/ast_mm.c
index 6e999408dda9..248284a4b3ff 100644
--- a/drivers/gpu/drm/ast/ast_mm.c
+++ b/drivers/gpu/drm/ast/ast_mm.c
@@ -28,7 +28,6 @@
#include <linux/pci.h>
-#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
@@ -80,7 +79,6 @@ int ast_mm_init(struct ast_private *ast)
struct pci_dev *pdev = to_pci_dev(dev->dev);
resource_size_t base, size;
u32 vram_size;
- int ret;
base = pci_resource_start(pdev, 0);
size = pci_resource_len(pdev, 0);
@@ -91,11 +89,13 @@ int ast_mm_init(struct ast_private *ast)
vram_size = ast_get_vram_size(ast);
- ret = drmm_vram_helper_init(dev, base, vram_size);
- if (ret) {
- drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
- return ret;
- }
+ ast->vram = devm_ioremap_wc(dev->dev, base, vram_size);
+ if (!ast->vram)
+ return -ENOMEM;
+
+ ast->vram_base = base;
+ ast->vram_size = vram_size;
+ ast->vram_fb_available = vram_size;
return 0;
}
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 1bc0220e6783..c7443317c747 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -36,11 +36,13 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_damage_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_gem_vram_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -48,6 +50,8 @@
#include "ast_drv.h"
#include "ast_tables.h"
+#define AST_LUT_SIZE 256
+
static inline void ast_load_palette_index(struct ast_private *ast,
u8 index, u8 red, u8 green,
u8 blue)
@@ -62,20 +66,46 @@ static inline void ast_load_palette_index(struct ast_private *ast,
ast_io_read8(ast, AST_IO_SEQ_PORT);
}
-static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc)
+static void ast_crtc_set_gamma_linear(struct ast_private *ast,
+ const struct drm_format_info *format)
{
- u16 *r, *g, *b;
int i;
- if (!crtc->enabled)
- return;
+ switch (format->format) {
+ case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_XRGB8888:
+ for (i = 0; i < AST_LUT_SIZE; i++)
+ ast_load_palette_index(ast, i, i, i, i);
+ break;
+ default:
+ drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
+}
- r = crtc->gamma_store;
- g = r + crtc->gamma_size;
- b = g + crtc->gamma_size;
+static void ast_crtc_set_gamma(struct ast_private *ast,
+ const struct drm_format_info *format,
+ struct drm_color_lut *lut)
+{
+ int i;
- for (i = 0; i < 256; i++)
- ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8);
+ switch (format->format) {
+ case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_XRGB8888:
+ for (i = 0; i < AST_LUT_SIZE; i++)
+ ast_load_palette_index(ast, i,
+ lut[i].red >> 8,
+ lut[i].green >> 8,
+ lut[i].blue >> 8);
+ break;
+ default:
+ drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
}
static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
@@ -538,6 +568,29 @@ static void ast_wait_for_vretrace(struct ast_private *ast)
}
/*
+ * Planes
+ */
+
+static int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane,
+ void __iomem *vaddr, u64 offset, unsigned long size,
+ uint32_t possible_crtcs,
+ const struct drm_plane_funcs *funcs,
+ const uint32_t *formats, unsigned int format_count,
+ const uint64_t *format_modifiers,
+ enum drm_plane_type type)
+{
+ struct drm_plane *plane = &ast_plane->base;
+
+ ast_plane->vaddr = vaddr;
+ ast_plane->offset = offset;
+ ast_plane->size = size;
+
+ return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
+ formats, format_count, format_modifiers,
+ type, NULL);
+}
+
+/*
* Primary plane
*/
@@ -550,52 +603,62 @@ static const uint32_t ast_primary_plane_formats[] = {
static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *state)
{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
- plane);
- struct drm_crtc_state *crtc_state;
- struct ast_crtc_state *ast_crtc_state;
+ struct drm_device *dev = plane->dev;
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_crtc_state *new_crtc_state = NULL;
+ struct ast_crtc_state *new_ast_crtc_state;
int ret;
- if (!new_plane_state->crtc)
- return 0;
-
- crtc_state = drm_atomic_get_new_crtc_state(state,
- new_plane_state->crtc);
+ if (new_plane_state->crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
- ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
false, true);
- if (ret)
+ if (ret) {
return ret;
+ } else if (!new_plane_state->visible) {
+ if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */
+ return -EINVAL;
+ else
+ return 0;
+ }
- if (!new_plane_state->visible)
- return 0;
-
- ast_crtc_state = to_ast_crtc_state(crtc_state);
+ new_ast_crtc_state = to_ast_crtc_state(new_crtc_state);
- ast_crtc_state->format = new_plane_state->fb->format;
+ new_ast_crtc_state->format = new_plane_state->fb->format;
return 0;
}
-static void
-ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
+static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src,
+ struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr);
+
+ iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
+ drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
+}
+
+static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
- struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
- plane);
struct drm_device *dev = plane->dev;
struct ast_private *ast = to_ast_private(dev);
- struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
- plane);
- struct drm_gem_vram_object *gbo;
- s64 gpu_addr;
- struct drm_framebuffer *fb = new_state->fb;
- struct drm_framebuffer *old_fb = old_state->fb;
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_framebuffer *old_fb = old_plane_state->fb;
+ struct ast_plane *ast_plane = to_ast_plane(plane);
+ struct drm_rect damage;
+ struct drm_atomic_helper_damage_iter iter;
if (!old_fb || (fb->format != old_fb->format)) {
- struct drm_crtc_state *crtc_state = new_state->crtc->state;
+ struct drm_crtc *crtc = plane_state->crtc;
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info;
@@ -603,20 +666,28 @@ ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info);
}
- gbo = drm_gem_vram_of_gem(fb->obj[0]);
- gpu_addr = drm_gem_vram_offset(gbo);
- if (drm_WARN_ON_ONCE(dev, gpu_addr < 0))
- return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */
-
- ast_set_offset_reg(ast, fb);
- ast_set_start_address_crt1(ast, (u32)gpu_addr);
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage);
+ }
- ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00);
+ /*
+ * Some BMCs stop scanning out the video signal after the driver
+ * reprogrammed the offset or scanout address. This stalls display
+ * output for several seconds and makes the display unusable.
+ * Therefore only update the offset if it changes and reprogram the
+ * address after enabling the plane.
+ */
+ if (!old_fb || old_fb->pitches[0] != fb->pitches[0])
+ ast_set_offset_reg(ast, fb);
+ if (!old_fb) {
+ ast_set_start_address_crt1(ast, (u32)ast_plane->offset);
+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00);
+ }
}
-static void
-ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
+static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
struct ast_private *ast = to_ast_private(plane->dev);
@@ -624,7 +695,7 @@ ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
}
static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = {
- DRM_GEM_VRAM_PLANE_HELPER_FUNCS,
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
.atomic_check = ast_primary_plane_helper_atomic_check,
.atomic_update = ast_primary_plane_helper_atomic_update,
.atomic_disable = ast_primary_plane_helper_atomic_disable,
@@ -634,27 +705,30 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ DRM_GEM_SHADOW_PLANE_FUNCS,
};
static int ast_primary_plane_init(struct ast_private *ast)
{
struct drm_device *dev = &ast->base;
- struct drm_plane *primary_plane = &ast->primary_plane;
+ struct ast_plane *ast_primary_plane = &ast->primary_plane;
+ struct drm_plane *primary_plane = &ast_primary_plane->base;
+ void __iomem *vaddr = ast->vram;
+ u64 offset = ast->vram_base;
+ unsigned long cursor_size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
+ unsigned long size = ast->vram_fb_available - cursor_size;
int ret;
- ret = drm_universal_plane_init(dev, primary_plane, 0x01,
- &ast_primary_plane_funcs,
- ast_primary_plane_formats,
- ARRAY_SIZE(ast_primary_plane_formats),
- NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
+ ret = ast_plane_init(dev, ast_primary_plane, vaddr, offset, size,
+ 0x01, &ast_primary_plane_funcs,
+ ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats),
+ NULL, DRM_PLANE_TYPE_PRIMARY);
if (ret) {
- drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ drm_err(dev, "ast_plane_init() failed: %d\n", ret);
return ret;
}
drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
return 0;
}
@@ -774,99 +848,79 @@ static const uint32_t ast_cursor_plane_formats[] = {
static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *state)
{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
- plane);
- struct drm_framebuffer *fb = new_plane_state->fb;
- struct drm_crtc_state *crtc_state;
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_framebuffer *new_fb = new_plane_state->fb;
+ struct drm_crtc_state *new_crtc_state = NULL;
int ret;
- if (!new_plane_state->crtc)
- return 0;
-
- crtc_state = drm_atomic_get_new_crtc_state(state,
- new_plane_state->crtc);
+ if (new_plane_state->crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
- ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
true, true);
- if (ret)
+ if (ret || !new_plane_state->visible)
return ret;
- if (!new_plane_state->visible)
- return 0;
-
- if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT)
+ if (new_fb->width > AST_MAX_HWC_WIDTH || new_fb->height > AST_MAX_HWC_HEIGHT)
return -EINVAL;
return 0;
}
-static void
-ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
+static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
- struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane);
- struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
- plane);
- struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
- plane);
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state);
- struct drm_framebuffer *fb = new_state->fb;
+ struct ast_plane *ast_plane = to_ast_plane(plane);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct ast_private *ast = to_ast_private(plane->dev);
- struct iosys_map dst_map =
- ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map;
- u64 dst_off =
- ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off;
struct iosys_map src_map = shadow_plane_state->data[0];
+ struct drm_rect damage;
+ const u8 *src = src_map.vaddr; /* TODO: Use mapping abstraction properly */
+ u64 dst_off = ast_plane->offset;
+ u8 __iomem *dst = ast_plane->vaddr; /* TODO: Use mapping abstraction properly */
+ u8 __iomem *sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */
unsigned int offset_x, offset_y;
u16 x, y;
u8 x_offset, y_offset;
- u8 __iomem *dst;
- u8 __iomem *sig;
- const u8 *src;
-
- src = src_map.vaddr; /* TODO: Use mapping abstraction properly */
- dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */
- sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */
/*
- * Do data transfer to HW cursor BO. If a new cursor image was installed,
- * point the scanout engine to dst_gbo's offset and page-flip the HWC buffers.
+ * Do data transfer to hardware buffer and point the scanout
+ * engine to the offset.
*/
- ast_update_cursor_image(dst, src, fb->width, fb->height);
-
- if (new_state->fb != old_state->fb) {
+ if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) {
+ ast_update_cursor_image(dst, src, fb->width, fb->height);
ast_set_cursor_base(ast, dst_off);
-
- ++ast_cursor_plane->next_hwc_index;
- ast_cursor_plane->next_hwc_index %= ARRAY_SIZE(ast_cursor_plane->hwc);
}
/*
* Update location in HWC signature and registers.
*/
- writel(new_state->crtc_x, sig + AST_HWC_SIGNATURE_X);
- writel(new_state->crtc_y, sig + AST_HWC_SIGNATURE_Y);
+ writel(plane_state->crtc_x, sig + AST_HWC_SIGNATURE_X);
+ writel(plane_state->crtc_y, sig + AST_HWC_SIGNATURE_Y);
offset_x = AST_MAX_HWC_WIDTH - fb->width;
offset_y = AST_MAX_HWC_HEIGHT - fb->height;
- if (new_state->crtc_x < 0) {
- x_offset = (-new_state->crtc_x) + offset_x;
+ if (plane_state->crtc_x < 0) {
+ x_offset = (-plane_state->crtc_x) + offset_x;
x = 0;
} else {
x_offset = offset_x;
- x = new_state->crtc_x;
+ x = plane_state->crtc_x;
}
- if (new_state->crtc_y < 0) {
- y_offset = (-new_state->crtc_y) + offset_y;
+ if (plane_state->crtc_y < 0) {
+ y_offset = (-plane_state->crtc_y) + offset_y;
y = 0;
} else {
y_offset = offset_y;
- y = new_state->crtc_y;
+ y = plane_state->crtc_y;
}
ast_set_cursor_location(ast, x, y, x_offset, y_offset);
@@ -875,9 +929,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
ast_set_cursor_enabled(ast, true);
}
-static void
-ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
+static void ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
struct ast_private *ast = to_ast_private(plane->dev);
@@ -891,41 +944,22 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = {
.atomic_disable = ast_cursor_plane_helper_atomic_disable,
};
-static void ast_cursor_plane_destroy(struct drm_plane *plane)
-{
- struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane);
- size_t i;
- struct drm_gem_vram_object *gbo;
- struct iosys_map map;
-
- for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) {
- gbo = ast_cursor_plane->hwc[i].gbo;
- map = ast_cursor_plane->hwc[i].map;
- drm_gem_vram_vunmap(gbo, &map);
- drm_gem_vram_unpin(gbo);
- drm_gem_vram_put(gbo);
- }
-
- drm_plane_cleanup(plane);
-}
-
static const struct drm_plane_funcs ast_cursor_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = ast_cursor_plane_destroy,
+ .destroy = drm_plane_cleanup,
DRM_GEM_SHADOW_PLANE_FUNCS,
};
static int ast_cursor_plane_init(struct ast_private *ast)
{
struct drm_device *dev = &ast->base;
- struct ast_cursor_plane *ast_cursor_plane = &ast->cursor_plane;
+ struct ast_plane *ast_cursor_plane = &ast->cursor_plane;
struct drm_plane *cursor_plane = &ast_cursor_plane->base;
- size_t size, i;
- struct drm_gem_vram_object *gbo;
- struct iosys_map map;
+ size_t size;
+ void __iomem *vaddr;
+ u64 offset;
int ret;
- s64 off;
/*
* Allocate backing storage for cursors. The BOs are permanently
@@ -934,60 +968,26 @@ static int ast_cursor_plane_init(struct ast_private *ast)
size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
- for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) {
- gbo = drm_gem_vram_create(dev, size, 0);
- if (IS_ERR(gbo)) {
- ret = PTR_ERR(gbo);
- goto err_hwc;
- }
- ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
- DRM_GEM_VRAM_PL_FLAG_TOPDOWN);
- if (ret)
- goto err_drm_gem_vram_put;
- ret = drm_gem_vram_vmap(gbo, &map);
- if (ret)
- goto err_drm_gem_vram_unpin;
- off = drm_gem_vram_offset(gbo);
- if (off < 0) {
- ret = off;
- goto err_drm_gem_vram_vunmap;
- }
- ast_cursor_plane->hwc[i].gbo = gbo;
- ast_cursor_plane->hwc[i].map = map;
- ast_cursor_plane->hwc[i].off = off;
- }
+ if (ast->vram_fb_available < size)
+ return -ENOMEM;
- /*
- * Create the cursor plane. The plane's destroy callback will release
- * the backing storages' BO memory.
- */
+ vaddr = ast->vram + ast->vram_fb_available - size;
+ offset = ast->vram_base + ast->vram_fb_available - size;
- ret = drm_universal_plane_init(dev, cursor_plane, 0x01,
- &ast_cursor_plane_funcs,
- ast_cursor_plane_formats,
- ARRAY_SIZE(ast_cursor_plane_formats),
- NULL, DRM_PLANE_TYPE_CURSOR, NULL);
+ ret = ast_plane_init(dev, ast_cursor_plane, vaddr, offset, size,
+ 0x01, &ast_cursor_plane_funcs,
+ ast_cursor_plane_formats, ARRAY_SIZE(ast_cursor_plane_formats),
+ NULL, DRM_PLANE_TYPE_CURSOR);
if (ret) {
- drm_err(dev, "drm_universal_plane failed(): %d\n", ret);
- goto err_hwc;
+ drm_err(dev, "ast_plane_init() failed: %d\n", ret);
+ return ret;
}
drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(cursor_plane);
- return 0;
+ ast->vram_fb_available -= size;
-err_hwc:
- while (i) {
- --i;
- gbo = ast_cursor_plane->hwc[i].gbo;
- map = ast_cursor_plane->hwc[i].map;
-err_drm_gem_vram_vunmap:
- drm_gem_vram_vunmap(gbo, &map);
-err_drm_gem_vram_unpin:
- drm_gem_vram_unpin(gbo);
-err_drm_gem_vram_put:
- drm_gem_vram_put(gbo);
- }
- return ret;
+ return 0;
}
/*
@@ -1026,9 +1026,11 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
ast_set_color_reg(ast, format);
ast_set_vbios_color_reg(ast, format, vbios_mode_info);
+ if (crtc->state->gamma_lut)
+ ast_crtc_set_gamma(ast, format, crtc->state->gamma_lut->data);
+ else
+ ast_crtc_set_gamma_linear(ast, format);
}
-
- ast_crtc_load_lut(ast, crtc);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
@@ -1123,47 +1125,50 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+ struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
struct drm_device *dev = crtc->dev;
struct ast_crtc_state *ast_state;
const struct drm_format_info *format;
bool succ;
int ret;
- ret = drm_atomic_helper_check_crtc_state(crtc_state, false);
+ if (!crtc_state->enable)
+ return 0;
+
+ ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
if (ret)
return ret;
- if (!crtc_state->enable)
- goto out;
-
ast_state = to_ast_crtc_state(crtc_state);
format = ast_state->format;
if (drm_WARN_ON_ONCE(dev, !format))
return -EINVAL; /* BUG: We didn't set format in primary check(). */
+ /*
+ * The gamma LUT has to be reloaded after changing the primary
+ * plane's color format.
+ */
+ if (old_ast_crtc_state->format != format)
+ crtc_state->color_mgmt_changed = true;
+
+ if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
+ if (crtc_state->gamma_lut->length !=
+ AST_LUT_SIZE * sizeof(struct drm_color_lut)) {
+ drm_err(dev, "Wrong size for gamma_lut %zu\n",
+ crtc_state->gamma_lut->length);
+ return -EINVAL;
+ }
+ }
+
succ = ast_get_vbios_mode_info(format, &crtc_state->mode,
&crtc_state->adjusted_mode,
&ast_state->vbios_mode_info);
if (!succ)
return -EINVAL;
-out:
- return drm_atomic_add_affected_planes(state, crtc);
-}
-
-static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state)
-{
- struct drm_device *dev = crtc->dev;
- struct ast_private *ast = to_ast_private(dev);
-
- /*
- * Concurrent operations could possibly trigger a call to
- * drm_connector_helper_funcs.get_modes by trying to read the
- * display modes. Protect access to I/O registers by acquiring
- * the I/O-register lock. Released in atomic_flush().
- */
- mutex_lock(&ast->ioregs_lock);
+ return 0;
}
static void
@@ -1172,35 +1177,34 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc);
- struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
- crtc);
struct drm_device *dev = crtc->dev;
struct ast_private *ast = to_ast_private(dev);
struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
- struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info;
/*
* The gamma LUT has to be reloaded after changing the primary
* plane's color format.
*/
- if (old_ast_crtc_state->format != ast_crtc_state->format)
- ast_crtc_load_lut(ast, crtc);
+ if (crtc_state->enable && crtc_state->color_mgmt_changed) {
+ if (crtc_state->gamma_lut)
+ ast_crtc_set_gamma(ast,
+ ast_crtc_state->format,
+ crtc_state->gamma_lut->data);
+ else
+ ast_crtc_set_gamma_linear(ast, ast_crtc_state->format);
+ }
//Set Aspeed Display-Port
if (ast->tx_chip_types & AST_TX_ASTDP_BIT)
ast_dp_set_mode(crtc, vbios_mode_info);
-
- mutex_unlock(&ast->ioregs_lock);
}
-static void
-ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
struct drm_device *dev = crtc->dev;
struct ast_private *ast = to_ast_private(dev);
- struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
struct ast_vbios_mode_info *vbios_mode_info =
&ast_crtc_state->vbios_mode_info;
@@ -1217,12 +1221,9 @@ ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
-static void
-ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
- struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
- crtc);
+ struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
struct drm_device *dev = crtc->dev;
struct ast_private *ast = to_ast_private(dev);
@@ -1250,7 +1251,6 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
.mode_valid = ast_crtc_helper_mode_valid,
.atomic_check = ast_crtc_helper_atomic_check,
- .atomic_begin = ast_crtc_helper_atomic_begin,
.atomic_flush = ast_crtc_helper_atomic_flush,
.atomic_enable = ast_crtc_helper_atomic_enable,
.atomic_disable = ast_crtc_helper_atomic_disable,
@@ -1317,13 +1317,15 @@ static int ast_crtc_init(struct drm_device *dev)
struct drm_crtc *crtc = &ast->crtc;
int ret;
- ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane,
+ ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base,
&ast->cursor_plane.base, &ast_crtc_funcs,
NULL);
if (ret)
return ret;
- drm_mode_crtc_set_gamma_size(crtc, 256);
+ drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE);
+
drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
return 0;
@@ -1718,13 +1720,46 @@ static int ast_astdp_output_init(struct ast_private *ast)
* Mode config
*/
+static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct ast_private *ast = to_ast_private(state->dev);
+
+ /*
+ * Concurrent operations could possibly trigger a call to
+ * drm_connector_helper_funcs.get_modes by trying to read the
+ * display modes. Protect access to I/O registers by acquiring
+ * the I/O-register lock. Released in atomic_flush().
+ */
+ mutex_lock(&ast->ioregs_lock);
+ drm_atomic_helper_commit_tail_rpm(state);
+ mutex_unlock(&ast->ioregs_lock);
+}
+
static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = {
- .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+ .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail,
};
+static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
+ const struct drm_display_mode *mode)
+{
+ static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */
+ struct ast_private *ast = to_ast_private(dev);
+ unsigned long fbsize, fbpages, max_fbpages;
+
+ max_fbpages = (ast->vram_fb_available) >> PAGE_SHIFT;
+
+ fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
+ fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);
+
+ if (fbpages > max_fbpages)
+ return MODE_MEM;
+
+ return MODE_OK;
+}
+
static const struct drm_mode_config_funcs ast_mode_config_funcs = {
- .fb_create = drm_gem_fb_create,
- .mode_valid = drm_vram_helper_mode_valid,
+ .fb_create = drm_gem_fb_create_with_dirty,
+ .mode_valid = ast_mode_config_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -1732,7 +1767,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = {
int ast_mode_config_init(struct ast_private *ast)
{
struct drm_device *dev = &ast->base;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
int ret;
ret = drmm_mode_config_init(dev);
@@ -1743,8 +1777,6 @@ int ast_mode_config_init(struct ast_private *ast)
dev->mode_config.min_width = 0;
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(pdev, 0);
if (ast->chip == AST2100 ||
ast->chip == AST2200 ||
@@ -1761,7 +1793,6 @@ int ast_mode_config_init(struct ast_private *ast)
dev->mode_config.helper_private = &ast_mode_config_helper_funcs;
-
ret = ast_primary_plane_init(ast);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index f7e7f4e919c7..a2bb5b916235 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -19,7 +19,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 94de73cbeb2d..17445800248d 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -402,7 +402,8 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
void adv7533_dsi_power_on(struct adv7511 *adv);
void adv7533_dsi_power_off(struct adv7511 *adv);
-void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
+enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,
+ const struct drm_display_mode *mode);
int adv7533_patch_registers(struct adv7511 *adv);
int adv7533_patch_cec_registers(struct adv7511 *adv);
int adv7533_attach_dsi(struct adv7511 *adv);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index f887200e8abc..e7a6e456ed0d 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -697,7 +697,7 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
}
static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
@@ -791,9 +791,6 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
regmap_update_bits(adv7511->regmap, 0x17,
0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
- if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- adv7533_mode_set(adv7511, adj_mode);
-
drm_mode_copy(&adv7511->curr_mode, adj_mode);
/*
@@ -913,6 +910,18 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
adv7511_mode_set(adv, mode, adj_mode);
}
+static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+ if (adv->type == ADV7533 || adv->type == ADV7535)
+ return adv7533_mode_valid(adv, mode);
+ else
+ return adv7511_mode_valid(adv, mode);
+}
+
static int adv7511_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@@ -960,6 +969,7 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.enable = adv7511_bridge_enable,
.disable = adv7511_bridge_disable,
.mode_set = adv7511_bridge_mode_set,
+ .mode_valid = adv7511_bridge_mode_valid,
.attach = adv7511_bridge_attach,
.detect = adv7511_bridge_detect,
.get_edid = adv7511_bridge_get_edid,
@@ -1209,10 +1219,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
return ret;
ret = adv7511_init_regulators(adv7511);
- if (ret) {
- dev_err(dev, "failed to init regulators\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to init regulators\n");
/*
* The power down GPIO is optional. If present, toggle it from active to
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index ef6270806d1d..fdfeadcefe80 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -100,26 +100,27 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
regmap_write(adv->regmap_cec, 0x27, 0x0b);
}
-void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
+enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,
+ const struct drm_display_mode *mode)
{
+ int lanes;
struct mipi_dsi_device *dsi = adv->dsi;
- int lanes, ret;
-
- if (adv->num_dsi_lanes != 4)
- return;
if (mode->clock > 80000)
lanes = 4;
else
lanes = 3;
- if (lanes != dsi->lanes) {
- mipi_dsi_detach(dsi);
- dsi->lanes = lanes;
- ret = mipi_dsi_attach(dsi);
- if (ret)
- dev_err(&dsi->dev, "failed to change host lanes\n");
- }
+ /*
+ * TODO: add support for dynamic switching of lanes
+ * by using the bridge pre_enable() op . Till then filter
+ * out the modes which shall need different number of lanes
+ * than what was configured in the device tree.
+ */
+ if (lanes != dsi->lanes)
+ return MODE_BAD;
+
+ return MODE_OK;
}
int adv7533_patch_registers(struct adv7511 *adv)
@@ -148,16 +149,14 @@ int adv7533_attach_dsi(struct adv7511 *adv)
};
host = of_find_mipi_dsi_host_by_node(adv->host_node);
- if (!host) {
- dev_err(dev, "failed to find dsi host\n");
- return -EPROBE_DEFER;
- }
+ if (!host)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "failed to find dsi host\n");
dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
- if (IS_ERR(dsi)) {
- dev_err(dev, "failed to create dsi device\n");
- return PTR_ERR(dsi);
- }
+ if (IS_ERR(dsi))
+ return dev_err_probe(dev, PTR_ERR(dsi),
+ "failed to create dsi device\n");
adv->dsi = dsi;
@@ -167,10 +166,8 @@ int adv7533_attach_dsi(struct adv7511 *adv)
MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
ret = devm_mipi_dsi_attach(dev, dsi);
- if (ret < 0) {
- dev_err(dev, "failed to attach dsi to host\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to attach dsi to host\n");
return 0;
}
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index dfe4351c9bdd..21a9b8422bda 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -412,6 +412,7 @@ struct it6505 {
* Mutex protects extcon and interrupt functions from interfering
* each other.
*/
+ struct mutex irq_lock;
struct mutex extcon_lock;
struct mutex mode_lock; /* used to bridge_detect */
struct mutex aux_lock; /* used to aux data transfers */
@@ -421,6 +422,7 @@ struct it6505 {
struct notifier_block event_nb;
struct extcon_dev *extcon;
struct work_struct extcon_wq;
+ int extcon_state;
enum drm_connector_status connector_status;
enum link_train_status link_state;
struct work_struct link_works;
@@ -439,7 +441,7 @@ struct it6505 {
enum hdcp_state hdcp_status;
struct delayed_work hdcp_work;
struct work_struct hdcp_wait_ksv_list;
- struct completion wait_edid_complete;
+ struct completion extcon_completion;
u8 auto_train_retry;
bool hdcp_desired;
bool is_repeater;
@@ -724,28 +726,6 @@ static void it6505_calc_video_info(struct it6505 *it6505)
DRM_MODE_ARG(&it6505->video_info));
}
-static int it6505_drm_dp_link_probe(struct drm_dp_aux *aux,
- struct it6505_drm_dp_link *link)
-{
- u8 values[3];
- int err;
-
- memset(link, 0, sizeof(*link));
-
- err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
- if (err < 0)
- return err;
-
- link->revision = values[0];
- link->rate = drm_dp_bw_code_to_link_rate(values[1]);
- link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
-
- if (values[2] & DP_ENHANCED_FRAME_CAP)
- link->capabilities = DP_ENHANCED_FRAME_CAP;
-
- return 0;
-}
-
static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux,
struct it6505_drm_dp_link *link,
u8 mode)
@@ -1455,11 +1435,19 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505)
int bcaps;
if (it6505->dpcd[0] == 0) {
- it6505_aux_on(it6505);
- it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
- ARRAY_SIZE(it6505->dpcd));
+ dev_err(dev, "DPCD is not initialized");
+ return;
}
+ memset(link, 0, sizeof(*link));
+
+ link->revision = it6505->dpcd[0];
+ link->rate = drm_dp_bw_code_to_link_rate(it6505->dpcd[1]);
+ link->num_lanes = it6505->dpcd[2] & DP_MAX_LANE_COUNT_MASK;
+
+ if (it6505->dpcd[2] & DP_ENHANCED_FRAME_CAP)
+ link->capabilities = DP_ENHANCED_FRAME_CAP;
+
DRM_DEV_DEBUG_DRIVER(dev, "DPCD Rev.: %d.%d",
link->revision >> 4, link->revision & 0x0F);
@@ -2322,19 +2310,32 @@ static int it6505_process_hpd_irq(struct it6505 *it6505)
static void it6505_irq_hpd(struct it6505 *it6505)
{
struct device *dev = &it6505->client->dev;
+ int dp_sink_count;
it6505->hpd_state = it6505_get_sink_hpd_status(it6505);
DRM_DEV_DEBUG_DRIVER(dev, "hpd change interrupt, change to %s",
it6505->hpd_state ? "high" : "low");
- if (it6505->bridge.dev)
- drm_helper_hpd_irq_event(it6505->bridge.dev);
- DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d",
- it6505->sink_count);
-
if (it6505->hpd_state) {
- wait_for_completion_timeout(&it6505->wait_edid_complete,
- msecs_to_jiffies(6000));
+ wait_for_completion_timeout(&it6505->extcon_completion,
+ msecs_to_jiffies(1000));
+ it6505_aux_on(it6505);
+ if (it6505->dpcd[0] == 0) {
+ it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
+ ARRAY_SIZE(it6505->dpcd));
+ it6505_variable_config(it6505);
+ it6505_parse_link_capabilities(it6505);
+ }
+ it6505->auto_train_retry = AUTO_TRAIN_RETRY;
+
+ it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
+ DP_SET_POWER_D0);
+ dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT);
+ it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count);
+
+ DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d",
+ it6505->sink_count);
+
it6505_lane_termination_on(it6505);
it6505_lane_power_on(it6505);
@@ -2362,6 +2363,9 @@ static void it6505_irq_hpd(struct it6505 *it6505)
it6505_lane_off(it6505);
it6505_link_reset_step_train(it6505);
}
+
+ if (it6505->bridge.dev)
+ drm_helper_hpd_irq_event(it6505->bridge.dev);
}
static void it6505_irq_hpd_irq(struct it6505 *it6505)
@@ -2490,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
};
int int_status[3], i;
- msleep(100);
- mutex_lock(&it6505->extcon_lock);
+ mutex_lock(&it6505->irq_lock);
if (it6505->enable_drv_hold || !it6505->powered)
goto unlock;
@@ -2521,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
}
unlock:
- mutex_unlock(&it6505->extcon_lock);
+ mutex_unlock(&it6505->irq_lock);
return IRQ_HANDLED;
}
@@ -2624,26 +2627,14 @@ static enum drm_connector_status it6505_detect(struct it6505 *it6505)
goto unlock;
if (it6505->enable_drv_hold) {
- status = it6505_get_sink_hpd_status(it6505) ?
- connector_status_connected :
- connector_status_disconnected;
+ status = it6505->hpd_state ? connector_status_connected :
+ connector_status_disconnected;
goto unlock;
}
- if (it6505_get_sink_hpd_status(it6505)) {
- it6505_aux_on(it6505);
- it6505_drm_dp_link_probe(&it6505->aux, &it6505->link);
+ if (it6505->hpd_state) {
it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
DP_SET_POWER_D0);
- it6505->auto_train_retry = AUTO_TRAIN_RETRY;
-
- if (it6505->dpcd[0] == 0) {
- it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
- ARRAY_SIZE(it6505->dpcd));
- it6505_variable_config(it6505);
- it6505_parse_link_capabilities(it6505);
- }
-
dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT);
it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count);
DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count:%d branch:%d",
@@ -2685,31 +2676,44 @@ static void it6505_extcon_work(struct work_struct *work)
{
struct it6505 *it6505 = container_of(work, struct it6505, extcon_wq);
struct device *dev = &it6505->client->dev;
- int state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP);
- unsigned int pwroffretry = 0;
+ int state, ret;
if (it6505->enable_drv_hold)
return;
mutex_lock(&it6505->extcon_lock);
+ state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP);
DRM_DEV_DEBUG_DRIVER(dev, "EXTCON_DISP_DP = 0x%02x", state);
- if (state > 0) {
+
+ if (state == it6505->extcon_state || unlikely(state < 0))
+ goto unlock;
+ it6505->extcon_state = state;
+ if (state) {
DRM_DEV_DEBUG_DRIVER(dev, "start to power on");
msleep(100);
- it6505_poweron(it6505);
+ ret = pm_runtime_get_sync(dev);
+
+ /*
+ * On system resume, extcon_work can be triggered before
+ * pm_runtime_force_resume re-enables runtime power management.
+ * Handling the error here to make sure the bridge is powered on.
+ */
+ if (ret < 0)
+ it6505_poweron(it6505);
+
+ complete_all(&it6505->extcon_completion);
} else {
DRM_DEV_DEBUG_DRIVER(dev, "start to power off");
- while (it6505_poweroff(it6505) && pwroffretry++ < 5) {
- DRM_DEV_DEBUG_DRIVER(dev, "power off fail %d times",
- pwroffretry);
- }
+ pm_runtime_put_sync(dev);
+ reinit_completion(&it6505->extcon_completion);
drm_helper_hpd_irq_event(it6505->bridge.dev);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
DRM_DEV_DEBUG_DRIVER(dev, "power off it6505 success!");
}
+unlock:
mutex_unlock(&it6505->extcon_lock);
}
@@ -2860,10 +2864,7 @@ static int it6505_bridge_attach(struct drm_bridge *bridge,
}
/* Register aux channel */
- it6505->aux.name = "DP-AUX";
- it6505->aux.dev = dev;
it6505->aux.drm_dev = bridge->dev;
- it6505->aux.transfer = it6505_aux_transfer;
ret = drm_dp_aux_register(&it6505->aux);
@@ -2980,6 +2981,28 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge,
}
}
+static void it6505_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
+{
+ struct it6505 *it6505 = bridge_to_it6505(bridge);
+ struct device *dev = &it6505->client->dev;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "start");
+
+ pm_runtime_get_sync(dev);
+}
+
+static void it6505_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
+{
+ struct it6505 *it6505 = bridge_to_it6505(bridge);
+ struct device *dev = &it6505->client->dev;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "start");
+
+ pm_runtime_put_sync(dev);
+}
+
static enum drm_connector_status
it6505_bridge_detect(struct drm_bridge *bridge)
{
@@ -3014,6 +3037,8 @@ static const struct drm_bridge_funcs it6505_bridge_funcs = {
.mode_valid = it6505_bridge_mode_valid,
.atomic_enable = it6505_bridge_atomic_enable,
.atomic_disable = it6505_bridge_atomic_disable,
+ .atomic_pre_enable = it6505_bridge_atomic_pre_enable,
+ .atomic_post_disable = it6505_bridge_atomic_post_disable,
.detect = it6505_bridge_detect,
.get_edid = it6505_bridge_get_edid,
};
@@ -3032,8 +3057,10 @@ static __maybe_unused int it6505_bridge_suspend(struct device *dev)
return it6505_poweroff(it6505);
}
-static SIMPLE_DEV_PM_OPS(it6505_bridge_pm_ops, it6505_bridge_suspend,
- it6505_bridge_resume);
+static const struct dev_pm_ops it6505_bridge_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(it6505_bridge_suspend, it6505_bridge_resume, NULL)
+};
static int it6505_init_pdata(struct it6505 *it6505)
{
@@ -3250,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
if (!it6505)
return -ENOMEM;
+ mutex_init(&it6505->irq_lock);
mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock);
mutex_init(&it6505->aux_lock);
@@ -3305,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
INIT_WORK(&it6505->link_works, it6505_link_training_work);
INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);
INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work);
- init_completion(&it6505->wait_edid_complete);
+ init_completion(&it6505->extcon_completion);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
it6505->powered = false;
it6505->enable_drv_hold = DEFAULT_DRV_HOLD;
@@ -3315,6 +3343,12 @@ static int it6505_i2c_probe(struct i2c_client *client,
DRM_DEV_DEBUG_DRIVER(dev, "it6505 device name: %s", dev_name(dev));
debugfs_init(it6505);
+ pm_runtime_enable(dev);
+
+ it6505->aux.name = "DP-AUX";
+ it6505->aux.dev = dev;
+ it6505->aux.transfer = it6505_aux_transfer;
+ drm_dp_aux_init(&it6505->aux);
it6505->bridge.funcs = &it6505_bridge_funcs;
it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index 083337a27966..6a614e54b383 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -304,7 +304,6 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
}
switch (data & SWAUX_STATUS_MASK) {
- /* Ignore the DEFER cases as they are already handled in hardware */
case SWAUX_STATUS_NACK:
case SWAUX_STATUS_I2C_NACK:
/*
@@ -321,6 +320,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
case SWAUX_STATUS_ACKM:
len = data & SWAUX_M_MASK;
break;
+ case SWAUX_STATUS_DEFER:
+ case SWAUX_STATUS_I2C_DEFER:
+ if (is_native_aux)
+ msg->reply |= DP_AUX_NATIVE_REPLY_DEFER;
+ else
+ msg->reply |= DP_AUX_I2C_REPLY_DEFER;
+ len = data & SWAUX_M_MASK;
+ break;
case SWAUX_STATUS_INVALID:
return -EOPNOTSUPP;
case SWAUX_STATUS_TIMEOUT:
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 40d8ca37f5bc..aa51c61a78c7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2720,6 +2720,9 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
* if supported. In any case the default RGB888 format is added
*/
+ /* Default 8bit RGB fallback */
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+
if (max_bpc >= 16 && info->bpc == 16) {
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
@@ -2753,9 +2756,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
- /* Default 8bit RGB fallback */
- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
-
*num_output_fmts = i;
return output_fmts;
diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c
index 7f4fce1aa998..0b6a28436885 100644
--- a/drivers/gpu/drm/bridge/tc358762.c
+++ b/drivers/gpu/drm/bridge/tc358762.c
@@ -11,6 +11,7 @@
*/
#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
@@ -19,7 +20,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
index 02dc12b8151e..3ceb0e9f9bdc 100644
--- a/drivers/gpu/drm/bridge/tc358775.c
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -408,7 +408,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
(val >> 8) & 0xFF, val & 0xFF);
d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM |
- SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS);
+ SYS_RST_LCD | SYS_RST_I2CM);
usleep_range(30000, 40000);
d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 3c3561942eb6..eb24322df721 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -931,9 +931,9 @@ static void ti_sn_bridge_set_video_timings(struct ti_sn65dsi86 *pdata)
&pdata->bridge.encoder->crtc->state->adjusted_mode;
u8 hsync_polarity = 0, vsync_polarity = 0;
- if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
hsync_polarity = CHA_HSYNC_POLARITY;
- if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
vsync_polarity = CHA_VSYNC_POLARITY;
ti_sn65dsi86_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile
index 52cdda1180d9..17ac4a1006a8 100644
--- a/drivers/gpu/drm/display/Makefile
+++ b/drivers/gpu/drm/display/Makefile
@@ -3,13 +3,15 @@
obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o
drm_display_helper-y := drm_display_helper_mod.o
-drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += drm_dp_dual_mode_helper.o \
- drm_dp_helper.o \
- drm_dp_mst_topology.o \
- drm_dsc_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \
+ drm_dp_dual_mode_helper.o \
+ drm_dp_helper.o \
+ drm_dp_mst_topology.o \
+ drm_dsc_helper.o
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
-drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += drm_hdmi_helper.o \
- drm_scdc_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
+ drm_hdmi_helper.o \
+ drm_scdc_helper.o
drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
diff --git a/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
index 3ea53bb67d3b..bd61e20770a5 100644
--- a/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
@@ -63,23 +63,45 @@
ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter,
u8 offset, void *buffer, size_t size)
{
+ u8 zero = 0;
+ char *tmpbuf = NULL;
+ /*
+ * As sub-addressing is not supported by all adaptors,
+ * always explicitly read from the start and discard
+ * any bytes that come before the requested offset.
+ * This way, no matter whether the adaptor supports it
+ * or not, we'll end up reading the proper data.
+ */
struct i2c_msg msgs[] = {
{
.addr = DP_DUAL_MODE_SLAVE_ADDRESS,
.flags = 0,
.len = 1,
- .buf = &offset,
+ .buf = &zero,
},
{
.addr = DP_DUAL_MODE_SLAVE_ADDRESS,
.flags = I2C_M_RD,
- .len = size,
+ .len = size + offset,
.buf = buffer,
},
};
int ret;
+ if (offset) {
+ tmpbuf = kmalloc(size + offset, GFP_KERNEL);
+ if (!tmpbuf)
+ return -ENOMEM;
+
+ msgs[1].buf = tmpbuf;
+ }
+
ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+ if (tmpbuf)
+ memcpy(buffer, tmpbuf + offset, size);
+
+ kfree(tmpbuf);
+
if (ret < 0)
return ret;
if (ret != ARRAY_SIZE(msgs))
@@ -208,18 +230,6 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev,
if (ret)
return DRM_DP_DUAL_MODE_UNKNOWN;
- /*
- * Sigh. Some (maybe all?) type 1 adaptors are broken and ack
- * the offset but ignore it, and instead they just always return
- * data from the start of the HDMI ID buffer. So for a broken
- * type 1 HDMI adaptor a single byte read will always give us
- * 0x44, and for a type 1 DVI adaptor it should give 0x00
- * (assuming it implements any registers). Fortunately neither
- * of those values will match the type 2 signature of the
- * DP_DUAL_MODE_ADAPTOR_ID register so we can proceed with
- * the type 2 adaptor detection safely even in the presence
- * of broken type 1 adaptors.
- */
ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID,
&adaptor_id, sizeof(adaptor_id));
drm_dbg_kms(dev, "DP dual mode adaptor ID: %02x (err %zd)\n", adaptor_id, ret);
@@ -233,11 +243,10 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev,
return DRM_DP_DUAL_MODE_TYPE2_DVI;
}
/*
- * If neither a proper type 1 ID nor a broken type 1 adaptor
- * as described above, assume type 1, but let the user know
- * that we may have misdetected the type.
+ * If not a proper type 1 ID, still assume type 1, but let
+ * the user know that we may have misdetected the type.
*/
- if (!is_type1_adaptor(adaptor_id) && adaptor_id != hdmi_id[0])
+ if (!is_type1_adaptor(adaptor_id))
drm_err(dev, "Unexpected DP dual mode adaptor ID %02x\n", adaptor_id);
}
@@ -343,10 +352,8 @@ EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output);
* @enable: enable (as opposed to disable) the TMDS output buffers
*
* Set the state of the TMDS output buffers in the adaptor. For
- * type2 this is set via the DP_DUAL_MODE_TMDS_OEN register. As
- * some type 1 adaptors have problems with registers (see comments
- * in drm_dp_dual_mode_detect()) we avoid touching the register,
- * making this function a no-op on type 1 adaptors.
+ * type2 this is set via the DP_DUAL_MODE_TMDS_OEN register.
+ * Type1 adaptors do not support any register writes.
*
* Returns:
* 0 on success, negative error code on failure
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index ecd22c038c8c..51a46689cda7 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -5186,7 +5186,7 @@ int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm
mst_state = drm_atomic_get_mst_topology_state(state, mgr);
if (IS_ERR(mst_state))
- return -EINVAL;
+ return PTR_ERR(mst_state);
list_for_each_entry(pos, &mst_state->payloads, next) {
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 98cc3137c062..d579fd8f7cb8 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -924,59 +924,35 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
EXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
/**
- * drm_atomic_helper_check_crtc_state() - Check CRTC state for validity
+ * drm_atomic_helper_check_crtc_primary_plane() - Check CRTC state for primary plane
* @crtc_state: CRTC state to check
- * @can_disable_primary_planes: can the CRTC be enabled without a primary plane?
*
- * Checks that a desired CRTC update is valid. Drivers that provide
- * their own CRTC handling rather than helper-provided implementations may
- * still wish to call this function to avoid duplication of error checking
- * code.
- *
- * Note that @can_disable_primary_planes only tests if the CRTC can be
- * enabled without a primary plane. To test if a primary plane can be updated
- * without a CRTC, use drm_atomic_helper_check_plane_state() in the plane's
- * atomic check.
+ * Checks that a CRTC has at least one primary plane attached to it, which is
+ * a requirement on some hardware. Note that this only involves the CRTC side
+ * of the test. To test if the primary plane is visible or if it can be updated
+ * without the CRTC being enabled, use drm_atomic_helper_check_plane_state() in
+ * the plane's atomic check.
*
* RETURNS:
- * Zero if update appears valid, error code on failure
+ * 0 if a primary plane is attached to the CRTC, or an error code otherwise
*/
-int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state,
- bool can_disable_primary_planes)
+int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state)
{
- struct drm_device *dev = crtc_state->crtc->dev;
- struct drm_atomic_state *state = crtc_state->state;
-
- if (!crtc_state->enable)
- return 0;
+ struct drm_crtc *crtc = crtc_state->crtc;
+ struct drm_device *dev = crtc->dev;
+ struct drm_plane *plane;
/* needs at least one primary plane to be enabled */
- if (!can_disable_primary_planes) {
- bool has_primary_plane = false;
- struct drm_plane *plane;
-
- drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
- struct drm_plane_state *plane_state;
-
- if (plane->type != DRM_PLANE_TYPE_PRIMARY)
- continue;
- plane_state = drm_atomic_get_plane_state(state, plane);
- if (IS_ERR(plane_state))
- return PTR_ERR(plane_state);
- if (plane_state->fb && plane_state->crtc) {
- has_primary_plane = true;
- break;
- }
- }
- if (!has_primary_plane) {
- drm_dbg_kms(dev, "Cannot enable CRTC without a primary plane.\n");
- return -EINVAL;
- }
+ drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ return 0;
}
- return 0;
+ drm_dbg_atomic(dev, "[CRTC:%d:%s] primary plane missing\n", crtc->base.id, crtc->name);
+
+ return -EINVAL;
}
-EXPORT_SYMBOL(drm_atomic_helper_check_crtc_state);
+EXPORT_SYMBOL(drm_atomic_helper_check_crtc_primary_plane);
/**
* drm_atomic_helper_check_planes - validate state object for planes changes
@@ -2560,7 +2536,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
if (funcs->prepare_fb) {
ret = funcs->prepare_fb(plane, new_plane_state);
if (ret)
- goto fail;
+ goto fail_prepare_fb;
} else {
WARN_ON_ONCE(funcs->cleanup_fb);
@@ -2569,13 +2545,34 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
ret = drm_gem_plane_helper_prepare_fb(plane, new_plane_state);
if (ret)
- goto fail;
+ goto fail_prepare_fb;
+ }
+ }
+
+ for_each_new_plane_in_state(state, plane, new_plane_state, i) {
+ const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+ if (funcs->begin_fb_access) {
+ ret = funcs->begin_fb_access(plane, new_plane_state);
+ if (ret)
+ goto fail_begin_fb_access;
}
}
return 0;
-fail:
+fail_begin_fb_access:
+ for_each_new_plane_in_state(state, plane, new_plane_state, j) {
+ const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+ if (j >= i)
+ continue;
+
+ if (funcs->end_fb_access)
+ funcs->end_fb_access(plane, new_plane_state);
+ }
+ i = j; /* set i to upper limit to cleanup all planes */
+fail_prepare_fb:
for_each_new_plane_in_state(state, plane, new_plane_state, j) {
const struct drm_plane_helper_funcs *funcs;
@@ -2852,6 +2849,13 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
int i;
for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
+ const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+ if (funcs->end_fb_access)
+ funcs->end_fb_access(plane, new_plane_state);
+ }
+
+ for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
const struct drm_plane_helper_funcs *funcs;
struct drm_plane_state *plane_state;
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index bf31b9d92094..dfb57217253b 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -464,12 +464,12 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
/**
- * drm_atomic_helper_connector_tv_reset - Resets TV connector properties
+ * drm_atomic_helper_connector_tv_margins_reset - Resets TV connector properties
* @connector: DRM connector
*
* Resets the TV-related properties attached to a connector.
*/
-void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
+void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector)
{
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
struct drm_connector_state *state = connector->state;
@@ -479,7 +479,7 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
state->tv.margins.top = cmdline->tv_margins.top;
state->tv.margins.bottom = cmdline->tv_margins.bottom;
}
-EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
/**
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 79730fa1dd8e..c06d0639d552 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -687,6 +687,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
*/
return -EINVAL;
} else if (property == config->tv_select_subconnector_property) {
+ state->tv.select_subconnector = val;
+ } else if (property == config->tv_subconnector_property) {
state->tv.subconnector = val;
} else if (property == config->tv_left_margin_property) {
state->tv.margins.left = val;
@@ -795,6 +797,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
else
*val = connector->dpms;
} else if (property == config->tv_select_subconnector_property) {
+ *val = state->tv.select_subconnector;
+ } else if (property == config->tv_subconnector_property) {
*val = state->tv.subconnector;
} else if (property == config->tv_left_margin_property) {
*val = state->tv.margins.left;
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 2b230b4d6942..fd67efe37c63 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -235,10 +235,10 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{
struct drm_device *dev = buffer->client->dev;
- drm_gem_vunmap(buffer->gem, &buffer->map);
-
- if (buffer->gem)
+ if (buffer->gem) {
+ drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
drm_gem_object_put(buffer->gem);
+ }
if (buffer->handle)
drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
@@ -323,7 +323,7 @@ drm_client_buffer_vmap(struct drm_client_buffer *buffer,
* fd_install step out of the driver backend hooks, to make that
* final step optional for internal users.
*/
- ret = drm_gem_vmap(buffer->gem, map);
+ ret = drm_gem_vmap_unlocked(buffer->gem, map);
if (ret)
return ret;
@@ -345,7 +345,7 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
{
struct iosys_map *map = &buffer->map;
- drm_gem_vunmap(buffer->gem, map);
+ drm_gem_vunmap_unlocked(buffer->gem, map);
}
EXPORT_SYMBOL(drm_client_buffer_vunmap);
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index bbc535cc50dd..d553e793e673 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -1237,3 +1237,7 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
return ret;
}
EXPORT_SYMBOL(drm_client_modeset_dpms);
+
+#ifdef CONFIG_DRM_KUNIT_TEST
+#include "tests/drm_client_modeset_test.c"
+#endif
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 61c29ce74b03..547356e00341 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -274,6 +274,7 @@ static int __drm_connector_init(struct drm_device *dev,
INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes);
mutex_init(&connector->mutex);
+ mutex_init(&connector->edid_override_mutex);
connector->edid_blob_ptr = NULL;
connector->epoch_counter = 0;
connector->tile_blob_ptr = NULL;
@@ -582,6 +583,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
mutex_destroy(&connector->mutex);
memset(connector, 0, sizeof(*connector));
+
+ if (dev->registered)
+ drm_sysfs_hotplug_event(dev);
}
EXPORT_SYMBOL(drm_connector_cleanup);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7d86020b5244..a209659a996c 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -43,7 +43,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
@@ -434,6 +433,32 @@ done:
}
EXPORT_SYMBOL(drm_crtc_helper_set_mode);
+/**
+ * drm_crtc_helper_atomic_check() - Helper to check CRTC atomic-state
+ * @crtc: CRTC to check
+ * @state: atomic state object
+ *
+ * Provides a default CRTC-state check handler for CRTCs that only have
+ * one primary plane attached to it.
+ *
+ * This is often the case for the CRTC of simple framebuffers. See also
+ * drm_plane_helper_atomic_check() for the respective plane-state check
+ * helper function.
+ *
+ * RETURNS:
+ * Zero on success, or an errno code otherwise.
+ */
+int drm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+ if (!new_crtc_state->enable)
+ return 0;
+
+ return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
+}
+EXPORT_SYMBOL(drm_crtc_helper_atomic_check);
+
static void
drm_crtc_helper_disable(struct drm_crtc *crtc)
{
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 56041b604881..501a10edd0e1 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -56,9 +56,10 @@ struct drm_plane;
struct drm_plane_state;
struct drm_property;
struct edid;
+struct fwnode_handle;
struct kref;
+struct seq_file;
struct work_struct;
-struct fwnode_handle;
/* drm_crtc.c */
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
@@ -286,5 +287,17 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
/* drm_edid.c */
void drm_mode_fixup_1366x768(struct drm_display_mode *mode);
+int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m);
int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size);
int drm_edid_override_reset(struct drm_connector *connector);
+
+/* drm_edid_load.c */
+#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector);
+#else
+static inline const struct drm_edid *
+drm_edid_load_firmware(struct drm_connector *connector)
+{
+ return ERR_PTR(-ENOENT);
+}
+#endif
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 01ee3febb813..ee445f4605ba 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -328,13 +328,7 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf,
static int edid_show(struct seq_file *m, void *data)
{
- struct drm_connector *connector = m->private;
- struct drm_property_blob *edid = connector->edid_blob_ptr;
-
- if (connector->override_edid && edid)
- seq_write(m, edid->data, edid->length);
-
- return 0;
+ return drm_edid_override_show(m->private, m);
}
static int edid_open(struct inode *inode, struct file *file)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 8214a0b1ab7f..73b845a75d52 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/srcu.h>
+#include <drm/drm_accel.h>
#include <drm/drm_cache.h>
#include <drm/drm_client.h>
#include <drm/drm_color_mgmt.h>
@@ -90,6 +91,8 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
return &dev->primary;
case DRM_MINOR_RENDER:
return &dev->render;
+ case DRM_MINOR_ACCEL:
+ return &dev->accel;
default:
BUG();
}
@@ -104,9 +107,13 @@ static void drm_minor_alloc_release(struct drm_device *dev, void *data)
put_device(minor->kdev);
- spin_lock_irqsave(&drm_minor_lock, flags);
- idr_remove(&drm_minors_idr, minor->index);
- spin_unlock_irqrestore(&drm_minor_lock, flags);
+ if (minor->type == DRM_MINOR_ACCEL) {
+ accel_minor_remove(minor->index);
+ } else {
+ spin_lock_irqsave(&drm_minor_lock, flags);
+ idr_remove(&drm_minors_idr, minor->index);
+ spin_unlock_irqrestore(&drm_minor_lock, flags);
+ }
}
static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
@@ -123,13 +130,17 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
minor->dev = dev;
idr_preload(GFP_KERNEL);
- spin_lock_irqsave(&drm_minor_lock, flags);
- r = idr_alloc(&drm_minors_idr,
- NULL,
- 64 * type,
- 64 * (type + 1),
- GFP_NOWAIT);
- spin_unlock_irqrestore(&drm_minor_lock, flags);
+ if (type == DRM_MINOR_ACCEL) {
+ r = accel_minor_alloc();
+ } else {
+ spin_lock_irqsave(&drm_minor_lock, flags);
+ r = idr_alloc(&drm_minors_idr,
+ NULL,
+ 64 * type,
+ 64 * (type + 1),
+ GFP_NOWAIT);
+ spin_unlock_irqrestore(&drm_minor_lock, flags);
+ }
idr_preload_end();
if (r < 0)
@@ -161,10 +172,14 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
if (!minor)
return 0;
- ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
- if (ret) {
- DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
- goto err_debugfs;
+ if (minor->type == DRM_MINOR_ACCEL) {
+ accel_debugfs_init(minor, minor->index);
+ } else {
+ ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
+ if (ret) {
+ DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
+ goto err_debugfs;
+ }
}
ret = device_add(minor->kdev);
@@ -172,9 +187,13 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
goto err_debugfs;
/* replace NULL with @minor so lookups will succeed from now on */
- spin_lock_irqsave(&drm_minor_lock, flags);
- idr_replace(&drm_minors_idr, minor, minor->index);
- spin_unlock_irqrestore(&drm_minor_lock, flags);
+ if (minor->type == DRM_MINOR_ACCEL) {
+ accel_minor_replace(minor, minor->index);
+ } else {
+ spin_lock_irqsave(&drm_minor_lock, flags);
+ idr_replace(&drm_minors_idr, minor, minor->index);
+ spin_unlock_irqrestore(&drm_minor_lock, flags);
+ }
DRM_DEBUG("new minor registered %d\n", minor->index);
return 0;
@@ -194,9 +213,13 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
return;
/* replace @minor with NULL so lookups will fail from now on */
- spin_lock_irqsave(&drm_minor_lock, flags);
- idr_replace(&drm_minors_idr, NULL, minor->index);
- spin_unlock_irqrestore(&drm_minor_lock, flags);
+ if (minor->type == DRM_MINOR_ACCEL) {
+ accel_minor_replace(NULL, minor->index);
+ } else {
+ spin_lock_irqsave(&drm_minor_lock, flags);
+ idr_replace(&drm_minors_idr, NULL, minor->index);
+ spin_unlock_irqrestore(&drm_minor_lock, flags);
+ }
device_del(minor->kdev);
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
@@ -603,6 +626,13 @@ static int drm_dev_init(struct drm_device *dev,
/* no per-device feature limits by default */
dev->driver_features = ~0u;
+ if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL) &&
+ (drm_core_check_feature(dev, DRIVER_RENDER) ||
+ drm_core_check_feature(dev, DRIVER_MODESET))) {
+ DRM_ERROR("DRM driver can't be both a compute acceleration and graphics driver\n");
+ return -EINVAL;
+ }
+
drm_legacy_init_members(dev);
INIT_LIST_HEAD(&dev->filelist);
INIT_LIST_HEAD(&dev->filelist_internal);
@@ -615,7 +645,7 @@ static int drm_dev_init(struct drm_device *dev,
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex);
- ret = drmm_add_action(dev, drm_dev_init_release, NULL);
+ ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL);
if (ret)
return ret;
@@ -628,15 +658,21 @@ static int drm_dev_init(struct drm_device *dev,
dev->anon_inode = inode;
- if (drm_core_check_feature(dev, DRIVER_RENDER)) {
- ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
+ if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) {
+ ret = drm_minor_alloc(dev, DRM_MINOR_ACCEL);
if (ret)
goto err;
- }
+ } else {
+ if (drm_core_check_feature(dev, DRIVER_RENDER)) {
+ ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
+ if (ret)
+ goto err;
+ }
- ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
- if (ret)
- goto err;
+ ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
+ if (ret)
+ goto err;
+ }
ret = drm_legacy_create_map_hash(dev);
if (ret)
@@ -883,6 +919,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
if (ret)
goto err_minors;
+ ret = drm_minor_register(dev, DRM_MINOR_ACCEL);
+ if (ret)
+ goto err_minors;
+
ret = create_compat_control_link(dev);
if (ret)
goto err_minors;
@@ -902,12 +942,13 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
driver->name, driver->major, driver->minor,
driver->patchlevel, driver->date,
dev->dev ? dev_name(dev->dev) : "virtual device",
- dev->primary->index);
+ dev->primary ? dev->primary->index : dev->accel->index);
goto out_unlock;
err_minors:
remove_compat_control_link(dev);
+ drm_minor_unregister(dev, DRM_MINOR_ACCEL);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
out_unlock:
@@ -950,6 +991,7 @@ void drm_dev_unregister(struct drm_device *dev)
drm_legacy_rmmaps(dev);
remove_compat_control_link(dev);
+ drm_minor_unregister(dev, DRM_MINOR_ACCEL);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
}
@@ -1034,6 +1076,7 @@ static const struct file_operations drm_stub_fops = {
static void drm_core_exit(void)
{
drm_privacy_screen_lookup_exit();
+ accel_core_exit();
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
@@ -1061,6 +1104,10 @@ static int __init drm_core_init(void)
if (ret < 0)
goto error;
+ ret = accel_core_init();
+ if (ret < 0)
+ goto error;
+
drm_privacy_screen_lookup_init();
drm_core_init_complete = true;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 4005dab6147d..3841aba17abd 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -87,6 +87,8 @@ static int oui(u8 first, u8 second, u8 third)
#define EDID_QUIRK_FORCE_10BPC (1 << 11)
/* Non desktop display (i.e. HMD) */
#define EDID_QUIRK_NON_DESKTOP (1 << 12)
+/* Cap the DSC target bitrate to 15bpp */
+#define EDID_QUIRK_CAP_DSC_15BPP (1 << 13)
#define MICROSOFT_IEEE_OUI 0xca125c
@@ -147,6 +149,12 @@ static const struct edid_quirk {
EDID_QUIRK('F', 'C', 'M', 13600, EDID_QUIRK_PREFER_LARGE_75 |
EDID_QUIRK_DETAILED_IN_CM),
+ /* LG 27GP950 */
+ EDID_QUIRK('G', 'S', 'M', 0x5bbf, EDID_QUIRK_CAP_DSC_15BPP),
+
+ /* LG 27GN950 */
+ EDID_QUIRK('G', 'S', 'M', 0x5b9a, EDID_QUIRK_CAP_DSC_15BPP),
+
/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
EDID_QUIRK('L', 'G', 'D', 764, EDID_QUIRK_FORCE_10BPC),
@@ -1572,15 +1580,6 @@ struct drm_edid {
const struct edid *edid;
};
-static bool version_greater(const struct drm_edid *drm_edid,
- u8 version, u8 revision)
-{
- const struct edid *edid = drm_edid->edid;
-
- return edid->version > version ||
- (edid->version == version && edid->revision > revision);
-}
-
static int edid_hfeeodb_extension_block_count(const struct edid *edid);
static int edid_hfeeodb_block_count(const struct edid *edid)
@@ -1622,7 +1621,8 @@ static const void *edid_extension_block_data(const struct edid *edid, int index)
return edid_block_data(edid, index + 1);
}
-static int drm_edid_block_count(const struct drm_edid *drm_edid)
+/* EDID block count indicated in EDID, may exceed allocated size */
+static int __drm_edid_block_count(const struct drm_edid *drm_edid)
{
int num_blocks;
@@ -1642,12 +1642,18 @@ static int drm_edid_block_count(const struct drm_edid *drm_edid)
num_blocks = eeodb;
}
- /* Limit by allocated size */
- num_blocks = min(num_blocks, (int)drm_edid->size / EDID_LENGTH);
-
return num_blocks;
}
+/* EDID block count, limited by allocated size */
+static int drm_edid_block_count(const struct drm_edid *drm_edid)
+{
+ /* Limit by allocated size */
+ return min(__drm_edid_block_count(drm_edid),
+ (int)drm_edid->size / EDID_LENGTH);
+}
+
+/* EDID extension block count, limited by allocated size */
static int drm_edid_extension_block_count(const struct drm_edid *drm_edid)
{
return drm_edid_block_count(drm_edid) - 1;
@@ -1981,7 +1987,7 @@ bool drm_edid_block_valid(u8 *_block, int block_num, bool print_bad_edid,
status = edid_block_check(block, is_base_block);
if (status == EDID_BLOCK_HEADER_REPAIR) {
- DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
+ DRM_DEBUG_KMS("Fixing EDID header, your hardware may be failing\n");
edid_header_fix(block);
/* Retry with fixed header, update status if that worked. */
@@ -2042,6 +2048,36 @@ bool drm_edid_is_valid(struct edid *edid)
}
EXPORT_SYMBOL(drm_edid_is_valid);
+/**
+ * drm_edid_valid - sanity check EDID data
+ * @drm_edid: EDID data
+ *
+ * Sanity check an EDID. Cross check block count against allocated size and
+ * checksum the blocks.
+ *
+ * Return: True if the EDID data is valid, false otherwise.
+ */
+bool drm_edid_valid(const struct drm_edid *drm_edid)
+{
+ int i;
+
+ if (!drm_edid)
+ return false;
+
+ if (edid_size_by_blocks(__drm_edid_block_count(drm_edid)) != drm_edid->size)
+ return false;
+
+ for (i = 0; i < drm_edid_block_count(drm_edid); i++) {
+ const void *block = drm_edid_block_data(drm_edid, i);
+
+ if (!edid_block_valid(block, i == 0))
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(drm_edid_valid);
+
static struct edid *edid_filter_invalid_blocks(struct edid *edid,
size_t *alloc_size)
{
@@ -2168,58 +2204,91 @@ static void connector_bad_edid(struct drm_connector *connector,
if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS))
return;
- drm_dbg_kms(connector->dev, "%s: EDID is invalid:\n", connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID is invalid:\n",
+ connector->base.id, connector->name);
for (i = 0; i < num_blocks; i++)
edid_block_dump(KERN_DEBUG, edid + i, i);
}
/* Get override or firmware EDID */
-static struct edid *drm_get_override_edid(struct drm_connector *connector,
- size_t *alloc_size)
+static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector)
{
- struct edid *override = NULL;
+ const struct drm_edid *override = NULL;
- if (connector->override_edid)
- override = drm_edid_duplicate(connector->edid_blob_ptr->data);
+ mutex_lock(&connector->edid_override_mutex);
- if (!override)
- override = drm_load_edid_firmware(connector);
+ if (connector->edid_override)
+ override = drm_edid_dup(connector->edid_override);
- /* FIXME: Get alloc size from deeper down the stack */
- if (!IS_ERR_OR_NULL(override) && alloc_size)
- *alloc_size = edid_size(override);
+ mutex_unlock(&connector->edid_override_mutex);
+
+ if (!override)
+ override = drm_edid_load_firmware(connector);
return IS_ERR(override) ? NULL : override;
}
/* For debugfs edid_override implementation */
+int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m)
+{
+ const struct drm_edid *drm_edid;
+
+ mutex_lock(&connector->edid_override_mutex);
+
+ drm_edid = connector->edid_override;
+ if (drm_edid)
+ seq_write(m, drm_edid->edid, drm_edid->size);
+
+ mutex_unlock(&connector->edid_override_mutex);
+
+ return 0;
+}
+
+/* For debugfs edid_override implementation */
int drm_edid_override_set(struct drm_connector *connector, const void *edid,
size_t size)
{
- int ret;
+ const struct drm_edid *drm_edid;
- if (size < EDID_LENGTH || edid_size(edid) > size)
+ drm_edid = drm_edid_alloc(edid, size);
+ if (!drm_edid_valid(drm_edid)) {
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override invalid\n",
+ connector->base.id, connector->name);
+ drm_edid_free(drm_edid);
return -EINVAL;
+ }
- connector->override_edid = false;
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override set\n",
+ connector->base.id, connector->name);
- ret = drm_connector_update_edid_property(connector, edid);
- if (!ret)
- connector->override_edid = true;
+ mutex_lock(&connector->edid_override_mutex);
- return ret;
+ drm_edid_free(connector->edid_override);
+ connector->edid_override = drm_edid;
+
+ mutex_unlock(&connector->edid_override_mutex);
+
+ return 0;
}
/* For debugfs edid_override implementation */
int drm_edid_override_reset(struct drm_connector *connector)
{
- connector->override_edid = false;
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override reset\n",
+ connector->base.id, connector->name);
+
+ mutex_lock(&connector->edid_override_mutex);
- return drm_connector_update_edid_property(connector, NULL);
+ drm_edid_free(connector->edid_override);
+ connector->edid_override = NULL;
+
+ mutex_unlock(&connector->edid_override_mutex);
+
+ return 0;
}
/**
- * drm_add_override_edid_modes - add modes from override/firmware EDID
+ * drm_edid_override_connector_update - add modes from override/firmware EDID
* @connector: connector we're probing
*
* Add modes from the override/firmware EDID, if available. Only to be used from
@@ -2229,24 +2298,25 @@ int drm_edid_override_reset(struct drm_connector *connector)
*
* Return: The number of modes added or 0 if we couldn't find any.
*/
-int drm_add_override_edid_modes(struct drm_connector *connector)
+int drm_edid_override_connector_update(struct drm_connector *connector)
{
- struct edid *override;
+ const struct drm_edid *override;
int num_modes = 0;
- override = drm_get_override_edid(connector, NULL);
+ override = drm_edid_override_get(connector);
if (override) {
- drm_connector_update_edid_property(connector, override);
- num_modes = drm_add_edid_modes(connector, override);
- kfree(override);
+ num_modes = drm_edid_connector_update(connector, override);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n",
- connector->base.id, connector->name, num_modes);
+ drm_edid_free(override);
+
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n",
+ connector->base.id, connector->name, num_modes);
}
return num_modes;
}
-EXPORT_SYMBOL(drm_add_override_edid_modes);
+EXPORT_SYMBOL(drm_edid_override_connector_update);
typedef int read_block_fn(void *context, u8 *buf, unsigned int block, size_t len);
@@ -2289,12 +2359,19 @@ static struct edid *_drm_do_get_edid(struct drm_connector *connector,
{
enum edid_block_status status;
int i, num_blocks, invalid_blocks = 0;
+ const struct drm_edid *override;
struct edid *edid, *new;
size_t alloc_size = EDID_LENGTH;
- edid = drm_get_override_edid(connector, &alloc_size);
- if (edid)
+ override = drm_edid_override_get(connector);
+ if (override) {
+ alloc_size = override->size;
+ edid = kmemdup(override->edid, alloc_size, GFP_KERNEL);
+ drm_edid_free(override);
+ if (!edid)
+ return NULL;
goto ok;
+ }
edid = kmalloc(alloc_size, GFP_KERNEL);
if (!edid)
@@ -2397,7 +2474,7 @@ fail:
* adapter and use drm_get_edid() instead of abusing this function.
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
- * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority
* order. Having either of them bypasses actual EDID reads.
*
* Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2575,7 +2652,7 @@ EXPORT_SYMBOL(drm_get_edid);
* this function.
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
- * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority
* order. Having either of them bypasses actual EDID reads.
*
* The returned pointer must be freed using drm_edid_free().
@@ -2613,7 +2690,7 @@ EXPORT_SYMBOL(drm_edid_read_custom);
* Read EDID using the given I2C adapter.
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
- * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority
* order. Having either of them bypasses actual EDID reads.
*
* Prefer initializing connector->ddc with drm_connector_init_with_ddc() and
@@ -2649,7 +2726,7 @@ EXPORT_SYMBOL(drm_edid_read_ddc);
* Read EDID using the connector's I2C adapter.
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
- * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority
* order. Having either of them bypasses actual EDID reads.
*
* The returned pointer must be freed using drm_edid_free().
@@ -2730,6 +2807,8 @@ u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
if (edid_block_status_valid(status, edid_block_tag(base_block)))
panel_id = edid_extract_panel_id(base_block);
+ else
+ edid_block_dump(KERN_NOTICE, base_block, 0);
kfree(base_block);
@@ -2984,7 +3063,7 @@ is_rb(const struct detailed_timing *descriptor, void *data)
BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.cvt.flags) != 15);
if (descriptor->data.other_data.data.range.flags == DRM_EDID_CVT_SUPPORT_FLAG &&
- descriptor->data.other_data.data.range.formula.cvt.flags & 0x10)
+ descriptor->data.other_data.data.range.formula.cvt.flags & DRM_EDID_CVT_FLAGS_REDUCED_BLANKING)
*res = true;
}
@@ -3012,7 +3091,7 @@ find_gtf2(const struct detailed_timing *descriptor, void *data)
BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10);
- if (descriptor->data.other_data.data.range.flags == 0x02)
+ if (descriptor->data.other_data.data.range.flags == DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG)
*res = descriptor;
}
@@ -3077,20 +3156,53 @@ drm_gtf2_2j(const struct drm_edid *drm_edid)
return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0;
}
+static void
+get_timing_level(const struct detailed_timing *descriptor, void *data)
+{
+ int *res = data;
+
+ if (!is_display_descriptor(descriptor, EDID_DETAIL_MONITOR_RANGE))
+ return;
+
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10);
+
+ switch (descriptor->data.other_data.data.range.flags) {
+ case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG:
+ *res = LEVEL_GTF;
+ break;
+ case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG:
+ *res = LEVEL_GTF2;
+ break;
+ case DRM_EDID_CVT_SUPPORT_FLAG:
+ *res = LEVEL_CVT;
+ break;
+ default:
+ break;
+ }
+}
+
/* Get standard timing level (CVT/GTF/DMT). */
static int standard_timing_level(const struct drm_edid *drm_edid)
{
const struct edid *edid = drm_edid->edid;
- if (edid->revision >= 2) {
- if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
- return LEVEL_CVT;
- if (drm_gtf2_hbreak(drm_edid))
- return LEVEL_GTF2;
- if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
- return LEVEL_GTF;
+ if (edid->revision >= 4) {
+ /*
+ * If the range descriptor doesn't
+ * indicate otherwise default to CVT
+ */
+ int ret = LEVEL_CVT;
+
+ drm_for_each_detailed_block(drm_edid, get_timing_level, &ret);
+
+ return ret;
+ } else if (edid->revision >= 3 && drm_gtf2_hbreak(drm_edid)) {
+ return LEVEL_GTF2;
+ } else if (edid->revision >= 2) {
+ return LEVEL_GTF;
+ } else {
+ return LEVEL_DMT;
}
- return LEVEL_DMT;
}
/*
@@ -3113,6 +3225,35 @@ static int drm_mode_hsync(const struct drm_display_mode *mode)
return DIV_ROUND_CLOSEST(mode->clock, mode->htotal);
}
+static struct drm_display_mode *
+drm_gtf2_mode(struct drm_device *dev,
+ const struct drm_edid *drm_edid,
+ int hsize, int vsize, int vrefresh_rate)
+{
+ struct drm_display_mode *mode;
+
+ /*
+ * This is potentially wrong if there's ever a monitor with
+ * more than one ranges section, each claiming a different
+ * secondary GTF curve. Please don't do that.
+ */
+ mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+ if (!mode)
+ return NULL;
+
+ if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) {
+ drm_mode_destroy(dev, mode);
+ mode = drm_gtf_mode_complex(dev, hsize, vsize,
+ vrefresh_rate, 0, 0,
+ drm_gtf2_m(drm_edid),
+ drm_gtf2_2c(drm_edid),
+ drm_gtf2_k(drm_edid),
+ drm_gtf2_2j(drm_edid));
+ }
+
+ return mode;
+}
+
/*
* Take the standard timing params (in this case width, aspect, and refresh)
* and convert them into a real mode using CVT/GTF/DMT.
@@ -3201,23 +3342,7 @@ static struct drm_display_mode *drm_mode_std(struct drm_connector *connector,
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
break;
case LEVEL_GTF2:
- /*
- * This is potentially wrong if there's ever a monitor with
- * more than one ranges section, each claiming a different
- * secondary GTF curve. Please don't do that.
- */
- mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
- if (!mode)
- return NULL;
- if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) {
- drm_mode_destroy(dev, mode);
- mode = drm_gtf_mode_complex(dev, hsize, vsize,
- vrefresh_rate, 0, 0,
- drm_gtf2_m(drm_edid),
- drm_gtf2_2c(drm_edid),
- drm_gtf2_k(drm_edid),
- drm_gtf2_2j(drm_edid));
- }
+ mode = drm_gtf2_mode(dev, drm_edid, hsize, vsize, vrefresh_rate);
break;
case LEVEL_CVT:
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
@@ -3274,11 +3399,12 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
* timing block contains enough info for us to create and return a new struct
* drm_display_mode.
*/
-static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
+static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector,
const struct drm_edid *drm_edid,
const struct detailed_timing *timing,
u32 quirks)
{
+ struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
const struct detailed_pixel_timing *pt = &timing->data.pixel_data;
unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
@@ -3295,17 +3421,19 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
return NULL;
if (pt->misc & DRM_EDID_PT_STEREO) {
- DRM_DEBUG_KMS("stereo mode not supported\n");
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Stereo mode not supported\n",
+ connector->base.id, connector->name);
return NULL;
}
if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
- DRM_DEBUG_KMS("composite sync not supported\n");
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Composite sync not supported\n",
+ connector->base.id, connector->name);
}
/* it is incorrect if hsync/vsync width is zero */
if (!hsync_pulse_width || !vsync_pulse_width) {
- DRM_DEBUG_KMS("Incorrect Detailed timing. "
- "Wrong Hsync/Vsync pulse width\n");
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Incorrect Detailed timing. Wrong Hsync/Vsync pulse width\n",
+ connector->base.id, connector->name);
return NULL;
}
@@ -3415,7 +3543,7 @@ range_pixel_clock(const struct edid *edid, const u8 *t)
return 0;
/* 1.4 with CVT support gives us real precision, yay */
- if (edid->revision >= 4 && t[10] == 0x04)
+ if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG)
return (t[9] * 10000) - ((t[12] >> 2) * 250);
/* 1.3 is pathetic, so fuzz up a bit */
@@ -3441,7 +3569,7 @@ static bool mode_in_range(const struct drm_display_mode *mode,
return false;
/* 1.4 max horizontal check */
- if (edid->revision >= 4 && t[10] == 0x04)
+ if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG)
if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3))))
return false;
@@ -3533,6 +3661,35 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector,
return modes;
}
+static int drm_gtf2_modes_for_range(struct drm_connector *connector,
+ const struct drm_edid *drm_edid,
+ const struct detailed_timing *timing)
+{
+ int i, modes = 0;
+ struct drm_display_mode *newmode;
+ struct drm_device *dev = connector->dev;
+
+ for (i = 0; i < ARRAY_SIZE(extra_modes); i++) {
+ const struct minimode *m = &extra_modes[i];
+
+ newmode = drm_gtf2_mode(dev, drm_edid, m->w, m->h, m->r);
+ if (!newmode)
+ return modes;
+
+ drm_mode_fixup_1366x768(newmode);
+ if (!mode_in_range(newmode, drm_edid, timing) ||
+ !valid_inferred_mode(connector, newmode)) {
+ drm_mode_destroy(dev, newmode);
+ continue;
+ }
+
+ drm_mode_probed_add(connector, newmode);
+ modes++;
+ }
+
+ return modes;
+}
+
static int drm_cvt_modes_for_range(struct drm_connector *connector,
const struct drm_edid *drm_edid,
const struct detailed_timing *timing)
@@ -3577,25 +3734,29 @@ do_inferred_modes(const struct detailed_timing *timing, void *c)
closure->drm_edid,
timing);
- if (!version_greater(closure->drm_edid, 1, 1))
+ if (closure->drm_edid->edid->revision < 2)
return; /* GTF not defined yet */
switch (range->flags) {
- case 0x02: /* secondary gtf, XXX could do more */
- case 0x00: /* default gtf */
+ case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG:
+ closure->modes += drm_gtf2_modes_for_range(closure->connector,
+ closure->drm_edid,
+ timing);
+ break;
+ case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG:
closure->modes += drm_gtf_modes_for_range(closure->connector,
closure->drm_edid,
timing);
break;
- case 0x04: /* cvt, only in 1.4+ */
- if (!version_greater(closure->drm_edid, 1, 3))
+ case DRM_EDID_CVT_SUPPORT_FLAG:
+ if (closure->drm_edid->edid->revision < 4)
break;
closure->modes += drm_cvt_modes_for_range(closure->connector,
closure->drm_edid,
timing);
break;
- case 0x01: /* just the ranges, no formula */
+ case DRM_EDID_RANGE_LIMITS_ONLY_FLAG:
default:
break;
}
@@ -3609,7 +3770,7 @@ static int add_inferred_modes(struct drm_connector *connector,
.drm_edid = drm_edid,
};
- if (version_greater(drm_edid, 1, 0))
+ if (drm_edid->edid->revision >= 1)
drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure);
return closure.modes;
@@ -3686,7 +3847,7 @@ static int add_established_modes(struct drm_connector *connector,
}
}
- if (version_greater(drm_edid, 1, 0))
+ if (edid->revision >= 1)
drm_for_each_detailed_block(drm_edid, do_established_modes,
&closure);
@@ -3741,7 +3902,7 @@ static int add_standard_modes(struct drm_connector *connector,
}
}
- if (version_greater(drm_edid, 1, 0))
+ if (drm_edid->edid->revision >= 1)
drm_for_each_detailed_block(drm_edid, do_standard_modes,
&closure);
@@ -3821,7 +3982,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid)
.drm_edid = drm_edid,
};
- if (version_greater(drm_edid, 1, 2))
+ if (drm_edid->edid->revision >= 3)
drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure);
/* XXX should also look for CVT codes in VTB blocks */
@@ -3829,7 +3990,8 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid)
return closure.modes;
}
-static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode);
+static void fixup_detailed_cea_mode_clock(struct drm_connector *connector,
+ struct drm_display_mode *mode);
static void
do_detailed_mode(const struct detailed_timing *timing, void *c)
@@ -3840,7 +4002,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c)
if (!is_detailed_timing_descriptor(timing))
return;
- newmode = drm_mode_detailed(closure->connector->dev,
+ newmode = drm_mode_detailed(closure->connector,
closure->drm_edid, timing,
closure->quirks);
if (!newmode)
@@ -3854,7 +4016,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c)
* so fix up anything that looks like CEA/HDMI mode, but the clock
* is just slightly off.
*/
- fixup_detailed_cea_mode_clock(newmode);
+ fixup_detailed_cea_mode_clock(closure->connector, newmode);
drm_mode_probed_add(closure->connector, newmode);
closure->modes++;
@@ -3873,13 +4035,14 @@ static int add_detailed_modes(struct drm_connector *connector,
struct detailed_mode_closure closure = {
.connector = connector,
.drm_edid = drm_edid,
- .preferred = true,
.quirks = quirks,
};
- if (closure.preferred && !version_greater(drm_edid, 1, 3))
+ if (drm_edid->edid->revision >= 4)
+ closure.preferred = true; /* first detailed timing is always preferred */
+ else
closure.preferred =
- (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
+ drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING;
drm_for_each_detailed_block(drm_edid, do_detailed_mode, &closure);
@@ -4515,7 +4678,8 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
struct drm_display_mode *newmode;
if (!drm_valid_hdmi_vic(vic)) {
- DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
+ drm_err(connector->dev, "[CONNECTOR:%d:%s] Unknown HDMI VIC: %d\n",
+ connector->base.id, connector->name, vic);
return 0;
}
@@ -5122,7 +5286,8 @@ static int add_cea_modes(struct drm_connector *connector,
return modes;
}
-static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
+static void fixup_detailed_cea_mode_clock(struct drm_connector *connector,
+ struct drm_display_mode *mode)
{
const struct drm_display_mode *cea_mode;
int clock1, clock2, clock;
@@ -5160,8 +5325,10 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
if (mode->clock == clock)
return;
- DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
- type, vic, mode->clock, clock);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
+ connector->base.id, connector->name,
+ type, vic, mode->clock, clock);
mode->clock = clock;
}
@@ -5269,15 +5436,12 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
if (len >= 12)
connector->audio_latency[1] = db[12];
- DRM_DEBUG_KMS("HDMI: latency present %d %d, "
- "video latency %d %d, "
- "audio latency %d %d\n",
- connector->latency_present[0],
- connector->latency_present[1],
- connector->video_latency[0],
- connector->video_latency[1],
- connector->audio_latency[0],
- connector->audio_latency[1]);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] HDMI: latency present %d %d, video latency %d %d, audio latency %d %d\n",
+ connector->base.id, connector->name,
+ connector->latency_present[0], connector->latency_present[1],
+ connector->video_latency[0], connector->video_latency[1],
+ connector->audio_latency[0], connector->audio_latency[1]);
}
static void
@@ -5375,7 +5539,9 @@ static void drm_edid_to_eld(struct drm_connector *connector,
return;
mnl = get_monitor_name(drm_edid, &eld[DRM_ELD_MONITOR_NAME_STRING]);
- DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD monitor %s\n",
+ connector->base.id, connector->name,
+ &eld[DRM_ELD_MONITOR_NAME_STRING]);
eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT;
eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl;
@@ -5429,8 +5595,9 @@ static void drm_edid_to_eld(struct drm_connector *connector,
eld[DRM_ELD_BASELINE_ELD_LEN] =
DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
- DRM_DEBUG_KMS("ELD size %d, SAD count %d\n",
- drm_eld_size(eld), total_sad_count);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD size %d, SAD count %d\n",
+ connector->base.id, connector->name,
+ drm_eld_size(eld), total_sad_count);
}
static int _drm_edid_to_sad(const struct drm_edid *drm_edid,
@@ -5701,7 +5868,8 @@ static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
- DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] CEA VCDB 0x%02x\n",
+ connector->base.id, connector->name, db[2]);
if (db[2] & EDID_CEA_VCDB_QS)
info->rgb_quant_range_selectable = true;
@@ -5752,12 +5920,87 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
hdmi->y420_dc_modes = dc_mask;
}
+static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
+ const u8 *hf_scds)
+{
+ hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2;
+
+ if (!hdmi_dsc->v_1p2)
+ return;
+
+ hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420;
+ hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP;
+
+ if (hf_scds[11] & DRM_EDID_DSC_16BPC)
+ hdmi_dsc->bpc_supported = 16;
+ else if (hf_scds[11] & DRM_EDID_DSC_12BPC)
+ hdmi_dsc->bpc_supported = 12;
+ else if (hf_scds[11] & DRM_EDID_DSC_10BPC)
+ hdmi_dsc->bpc_supported = 10;
+ else
+ /* Supports min 8 BPC if DSC 1.2 is supported*/
+ hdmi_dsc->bpc_supported = 8;
+
+ if (cea_db_payload_len(hf_scds) >= 12 && hf_scds[12]) {
+ u8 dsc_max_slices;
+ u8 dsc_max_frl_rate;
+
+ dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
+ drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes,
+ &hdmi_dsc->max_frl_rate_per_lane);
+
+ dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES;
+
+ switch (dsc_max_slices) {
+ case 1:
+ hdmi_dsc->max_slices = 1;
+ hdmi_dsc->clk_per_slice = 340;
+ break;
+ case 2:
+ hdmi_dsc->max_slices = 2;
+ hdmi_dsc->clk_per_slice = 340;
+ break;
+ case 3:
+ hdmi_dsc->max_slices = 4;
+ hdmi_dsc->clk_per_slice = 340;
+ break;
+ case 4:
+ hdmi_dsc->max_slices = 8;
+ hdmi_dsc->clk_per_slice = 340;
+ break;
+ case 5:
+ hdmi_dsc->max_slices = 8;
+ hdmi_dsc->clk_per_slice = 400;
+ break;
+ case 6:
+ hdmi_dsc->max_slices = 12;
+ hdmi_dsc->clk_per_slice = 400;
+ break;
+ case 7:
+ hdmi_dsc->max_slices = 16;
+ hdmi_dsc->clk_per_slice = 400;
+ break;
+ case 0:
+ default:
+ hdmi_dsc->max_slices = 0;
+ hdmi_dsc->clk_per_slice = 0;
+ }
+ }
+
+ if (cea_db_payload_len(hf_scds) >= 13 && hf_scds[13])
+ hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES;
+}
+
/* Sink Capability Data Structure */
static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
const u8 *hf_scds)
{
struct drm_display_info *display = &connector->display_info;
struct drm_hdmi_info *hdmi = &display->hdmi;
+ struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
+ int max_tmds_clock = 0;
+ u8 max_frl_rate = 0;
+ bool dsc_support = false;
display->has_hdmi_infoframe = true;
@@ -5777,14 +6020,13 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
*/
if (hf_scds[5]) {
- /* max clock is 5000 KHz times block value */
- u32 max_tmds_clock = hf_scds[5] * 5000;
struct drm_scdc *scdc = &hdmi->scdc;
+ /* max clock is 5000 KHz times block value */
+ max_tmds_clock = hf_scds[5] * 5000;
+
if (max_tmds_clock > 340000) {
display->max_tmds_clock = max_tmds_clock;
- DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
- display->max_tmds_clock);
}
if (scdc->supported) {
@@ -5797,74 +6039,22 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
}
if (hf_scds[7]) {
- u8 max_frl_rate;
- u8 dsc_max_frl_rate;
- u8 dsc_max_slices;
- struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
-
- DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n");
max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4;
drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes,
&hdmi->max_frl_rate_per_lane);
- hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2;
-
- if (hdmi_dsc->v_1p2) {
- hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420;
- hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP;
-
- if (hf_scds[11] & DRM_EDID_DSC_16BPC)
- hdmi_dsc->bpc_supported = 16;
- else if (hf_scds[11] & DRM_EDID_DSC_12BPC)
- hdmi_dsc->bpc_supported = 12;
- else if (hf_scds[11] & DRM_EDID_DSC_10BPC)
- hdmi_dsc->bpc_supported = 10;
- else
- hdmi_dsc->bpc_supported = 0;
-
- dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
- drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes,
- &hdmi_dsc->max_frl_rate_per_lane);
- hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES;
-
- dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES;
- switch (dsc_max_slices) {
- case 1:
- hdmi_dsc->max_slices = 1;
- hdmi_dsc->clk_per_slice = 340;
- break;
- case 2:
- hdmi_dsc->max_slices = 2;
- hdmi_dsc->clk_per_slice = 340;
- break;
- case 3:
- hdmi_dsc->max_slices = 4;
- hdmi_dsc->clk_per_slice = 340;
- break;
- case 4:
- hdmi_dsc->max_slices = 8;
- hdmi_dsc->clk_per_slice = 340;
- break;
- case 5:
- hdmi_dsc->max_slices = 8;
- hdmi_dsc->clk_per_slice = 400;
- break;
- case 6:
- hdmi_dsc->max_slices = 12;
- hdmi_dsc->clk_per_slice = 400;
- break;
- case 7:
- hdmi_dsc->max_slices = 16;
- hdmi_dsc->clk_per_slice = 400;
- break;
- case 0:
- default:
- hdmi_dsc->max_slices = 0;
- hdmi_dsc->clk_per_slice = 0;
- }
- }
}
drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
+
+ if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) {
+ drm_parse_dsc_info(hdmi_dsc, hf_scds);
+ dsc_support = true;
+ }
+
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n",
+ connector->base.id, connector->name,
+ max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support));
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
@@ -5882,39 +6072,39 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30;
- DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 30.\n",
+ connector->base.id, connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
dc_bpc = 12;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36;
- DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 36.\n",
+ connector->base.id, connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
dc_bpc = 16;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48;
- DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 48.\n",
+ connector->base.id, connector->name);
}
if (dc_bpc == 0) {
- DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] No deep color support on this HDMI sink.\n",
+ connector->base.id, connector->name);
return;
}
- DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
- connector->name, dc_bpc);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Assigning HDMI sink color depth as %d bpc.\n",
+ connector->base.id, connector->name, dc_bpc);
info->bpc = dc_bpc;
/* YCRCB444 is optional according to spec. */
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes;
- DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does YCRCB444 in deep color.\n",
+ connector->base.id, connector->name);
}
/*
@@ -5922,8 +6112,8 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
* then deep color 36 bit must be supported.
*/
if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
- DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
- connector->name);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink should do DC_36, but does not!\n",
+ connector->base.id, connector->name);
}
}
@@ -5940,10 +6130,9 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
if (len >= 7)
info->max_tmds_clock = db[7] * 5000;
- DRM_DEBUG_KMS("HDMI: DVI dual %d, "
- "max TMDS clock %d kHz\n",
- info->dvi_dual,
- info->max_tmds_clock);
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n",
+ connector->base.id, connector->name,
+ info->dvi_dual, info->max_tmds_clock);
drm_parse_hdmi_deep_color_info(connector, db);
}
@@ -5963,8 +6152,9 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
if (version == 1 || version == 2 || (version == 3 && !desktop_usage))
info->non_desktop = true;
- drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n",
- version, db[5]);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] HMD or specialized display VSDB version %u: 0x%02x\n",
+ connector->base.id, connector->name, version, db[5]);
}
static void drm_parse_cea_ext(struct drm_connector *connector,
@@ -5985,8 +6175,10 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
info->cea_rev = edid_ext[1];
if (info->cea_rev != edid_ext[1])
- DRM_DEBUG_KMS("CEA extension version mismatch %u != %u\n",
- info->cea_rev, edid_ext[1]);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] CEA extension version mismatch %u != %u\n",
+ connector->base.id, connector->name,
+ info->cea_rev, edid_ext[1]);
/* The existence of a CTA extension should imply RGB support */
info->color_formats = DRM_COLOR_FORMAT_RGB444;
@@ -6033,10 +6225,13 @@ void get_monitor_range(const struct detailed_timing *timing, void *c)
return;
/*
- * Check for flag range limits only. If flag == 1 then
- * no additional timing information provided.
- * Default GTF, GTF Secondary curve and CVT are not
- * supported
+ * These limits are used to determine the VRR refresh
+ * rate range. Only the "range limits only" variant
+ * of the range descriptor seems to guarantee that
+ * any and all timings are accepted by the sink, as
+ * opposed to just timings conforming to the indicated
+ * formula (GTF/GTF2/CVT). Thus other variants of the
+ * range descriptor are not accepted here.
*/
if (range->flags != DRM_EDID_RANGE_LIMITS_ONLY_FLAG)
return;
@@ -6061,14 +6256,18 @@ static void drm_get_monitor_range(struct drm_connector *connector,
.drm_edid = drm_edid,
};
- if (!version_greater(drm_edid, 1, 1))
+ if (drm_edid->edid->revision < 4)
+ return;
+
+ if (!(drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ))
return;
drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure);
- DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n",
- info->monitor_range.min_vfreq,
- info->monitor_range.max_vfreq);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Supported Monitor Refresh rate range is %d Hz - %d Hz\n",
+ connector->base.id, connector->name,
+ info->monitor_range.min_vfreq, info->monitor_range.max_vfreq);
}
static void drm_parse_vesa_mso_data(struct drm_connector *connector,
@@ -6079,8 +6278,9 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector,
struct drm_display_info *info = &connector->display_info;
if (block->num_bytes < 3) {
- drm_dbg_kms(connector->dev, "Unexpected vendor block size %u\n",
- block->num_bytes);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Unexpected vendor block size %u\n",
+ connector->base.id, connector->name, block->num_bytes);
return;
}
@@ -6088,13 +6288,16 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector,
return;
if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) {
- drm_dbg_kms(connector->dev, "Unexpected VESA vendor block size\n");
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Unexpected VESA vendor block size\n",
+ connector->base.id, connector->name);
return;
}
switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) {
default:
- drm_dbg_kms(connector->dev, "Reserved MSO mode value\n");
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved MSO mode value\n",
+ connector->base.id, connector->name);
fallthrough;
case 0:
info->mso_stream_count = 0;
@@ -6114,12 +6317,16 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector,
info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso);
if (info->mso_pixel_overlap > 8) {
- drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value %u\n",
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Reserved MSO pixel overlap value %u\n",
+ connector->base.id, connector->name,
info->mso_pixel_overlap);
info->mso_pixel_overlap = 8;
}
- drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n",
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] MSO stream count %u, pixel overlap %u\n",
+ connector->base.id, connector->name,
info->mso_stream_count, info->mso_pixel_overlap);
}
@@ -6166,6 +6373,7 @@ static void drm_reset_display_info(struct drm_connector *connector)
info->mso_stream_count = 0;
info->mso_pixel_overlap = 0;
+ info->max_dsc_bpp = 0;
}
static u32 update_display_info(struct drm_connector *connector,
@@ -6202,8 +6410,9 @@ static u32 update_display_info(struct drm_connector *connector,
if (info->bpc == 0 && edid->revision == 3 &&
edid->input & DRM_EDID_DIGITAL_DFP_1_X) {
info->bpc = 8;
- DRM_DEBUG("%s: Assigning DFP sink color depth as %d bpc.\n",
- connector->name, info->bpc);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Assigning DFP sink color depth as %d bpc.\n",
+ connector->base.id, connector->name, info->bpc);
}
/* Only defined for 1.4 with digital displays */
@@ -6235,8 +6444,9 @@ static u32 update_display_info(struct drm_connector *connector,
break;
}
- DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
- connector->name, info->bpc);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
+ connector->base.id, connector->name, info->bpc);
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
info->color_formats |= DRM_COLOR_FORMAT_YCBCR444;
@@ -6247,11 +6457,15 @@ static u32 update_display_info(struct drm_connector *connector,
out:
if (quirks & EDID_QUIRK_NON_DESKTOP) {
- drm_dbg_kms(connector->dev, "Non-desktop display%s\n",
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n",
+ connector->base.id, connector->name,
info->non_desktop ? " (redundant quirk)" : "");
info->non_desktop = true;
}
+ if (quirks & EDID_QUIRK_CAP_DSC_15BPP)
+ info->max_dsc_bpp = 15;
+
return quirks;
}
@@ -6390,7 +6604,7 @@ static int _drm_edid_connector_update(struct drm_connector *connector,
num_modes += add_cea_modes(connector, drm_edid);
num_modes += add_alternate_cea_modes(connector, drm_edid);
num_modes += add_displayid_detailed_modes(connector, drm_edid);
- if (drm_edid->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
+ if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
num_modes += add_inferred_modes(connector, drm_edid);
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
@@ -6482,23 +6696,6 @@ int drm_edid_connector_update(struct drm_connector *connector,
{
int count;
- /*
- * FIXME: Reconcile the differences in override_edid handling between
- * this and drm_connector_update_edid_property().
- *
- * If override_edid is set, and the EDID passed in here originates from
- * drm_edid_read() and friends, it will be the override EDID, and there
- * are no issues. drm_connector_update_edid_property() ignoring requests
- * to set the EDID dates back to a time when override EDID was not
- * handled at the low level EDID read.
- *
- * The only way the EDID passed in here can be different from the
- * override EDID is when a driver passes in an EDID that does *not*
- * originate from drm_edid_read() and friends, or passes in a stale
- * cached version. This, in turn, is a question of when an override EDID
- * set via debugfs should take effect.
- */
-
count = _drm_edid_connector_update(connector, drm_edid);
_drm_update_tile_info(connector, drm_edid);
@@ -6513,10 +6710,6 @@ EXPORT_SYMBOL(drm_edid_connector_update);
static int _drm_connector_update_edid_property(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
- /* ignore requests to set edid when overridden */
- if (connector->override_edid)
- return 0;
-
/*
* Set the display info, using edid if available, otherwise resetting
* the values to defaults. This duplicates the work done in
@@ -6579,8 +6772,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
struct drm_edid drm_edid;
if (edid && !drm_edid_is_valid(edid)) {
- drm_warn(connector->dev, "%s: EDID invalid.\n",
- connector->name);
+ drm_warn(connector->dev, "[CONNECTOR:%d:%s] EDID invalid.\n",
+ connector->base.id, connector->name);
edid = NULL;
}
@@ -6837,7 +7030,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
* by non-zero YQ when receiving RGB. There doesn't seem to be any
* good way to tell which version of CEA-861 the sink supports, so
* we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based
- * on on CEA-861-F.
+ * on CEA-861-F.
*/
if (!is_hdmi2_sink(connector) ||
rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)
@@ -6956,11 +7149,14 @@ static void drm_parse_tiled_block(struct drm_connector *connector,
connector->tile_h_size = w + 1;
connector->tile_v_size = h + 1;
- DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
- DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
- DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
- num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
- DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] tile cap 0x%x, size %dx%d, num tiles %dx%d, location %dx%d, vend %c%c%c",
+ connector->base.id, connector->name,
+ tile->tile_cap,
+ connector->tile_h_size, connector->tile_v_size,
+ connector->num_h_tile, connector->num_v_tile,
+ connector->tile_h_loc, connector->tile_v_loc,
+ tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
if (!tg)
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index 37d8ba3ddb46..5d9ef267ebb3 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -11,12 +11,13 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_connector.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
+#include "drm_crtc_internal.h"
+
static char edid_firmware[PATH_MAX];
module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
@@ -159,44 +160,26 @@ static const u8 generic_edid[GENERIC_EDIDS][128] = {
},
};
-static int edid_size(const u8 *edid, int data_size)
-{
- if (data_size < EDID_LENGTH)
- return 0;
-
- return (edid[0x7e] + 1) * EDID_LENGTH;
-}
-
-static void *edid_load(struct drm_connector *connector, const char *name,
- const char *connector_name)
+static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)
{
const struct firmware *fw = NULL;
const u8 *fwdata;
- u8 *edid;
+ const struct drm_edid *drm_edid;
int fwsize, builtin;
- int i, valid_extensions = 0;
- bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS);
builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
if (builtin >= 0) {
fwdata = generic_edid[builtin];
fwsize = sizeof(generic_edid[builtin]);
} else {
- struct platform_device *pdev;
int err;
- pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
- if (IS_ERR(pdev)) {
- DRM_ERROR("Failed to register EDID firmware platform device "
- "for connector \"%s\"\n", connector_name);
- return ERR_CAST(pdev);
- }
-
- err = request_firmware(&fw, name, &pdev->dev);
- platform_device_unregister(pdev);
+ err = request_firmware(&fw, name, connector->dev->dev);
if (err) {
- DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
- name, err);
+ drm_err(connector->dev,
+ "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",
+ connector->base.id, connector->name,
+ name, err);
return ERR_PTR(err);
}
@@ -204,70 +187,26 @@ static void *edid_load(struct drm_connector *connector, const char *name,
fwsize = fw->size;
}
- if (edid_size(fwdata, fwsize) != fwsize) {
- DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
- "(expected %d, got %d\n", name,
- edid_size(fwdata, fwsize), (int)fwsize);
- edid = ERR_PTR(-EINVAL);
- goto out;
- }
-
- edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
- if (edid == NULL) {
- edid = ERR_PTR(-ENOMEM);
- goto out;
- }
+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n",
+ connector->base.id, connector->name,
+ builtin >= 0 ? "built-in" : "external", name);
- if (!drm_edid_block_valid(edid, 0, print_bad_edid,
- &connector->edid_corrupt)) {
- connector->bad_edid_counter++;
- DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
- name);
- kfree(edid);
- edid = ERR_PTR(-EINVAL);
- goto out;
+ drm_edid = drm_edid_alloc(fwdata, fwsize);
+ if (!drm_edid_valid(drm_edid)) {
+ drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name);
+ drm_edid_free(drm_edid);
+ drm_edid = ERR_PTR(-EINVAL);
}
- for (i = 1; i <= edid[0x7e]; i++) {
- if (i != valid_extensions + 1)
- memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
- edid + i * EDID_LENGTH, EDID_LENGTH);
- if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
- print_bad_edid,
- NULL))
- valid_extensions++;
- }
-
- if (valid_extensions != edid[0x7e]) {
- u8 *new_edid;
-
- edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
- DRM_INFO("Found %d valid extensions instead of %d in EDID data "
- "\"%s\" for connector \"%s\"\n", valid_extensions,
- edid[0x7e], name, connector_name);
- edid[0x7e] = valid_extensions;
-
- new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
- GFP_KERNEL);
- if (new_edid)
- edid = new_edid;
- }
-
- DRM_INFO("Got %s EDID base block and %d extension%s from "
- "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
- "external", valid_extensions, valid_extensions == 1 ? "" : "s",
- name, connector_name);
-
-out:
release_firmware(fw);
- return edid;
+
+ return drm_edid;
}
-struct edid *drm_load_edid_firmware(struct drm_connector *connector)
+const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)
{
- const char *connector_name = connector->name;
char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
- struct edid *edid;
+ const struct drm_edid *drm_edid;
if (edid_firmware[0] == '\0')
return ERR_PTR(-ENOENT);
@@ -288,7 +227,7 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
while ((edidname = strsep(&edidstr, ","))) {
colon = strchr(edidname, ':');
if (colon != NULL) {
- if (strncmp(connector_name, edidname, colon - edidname))
+ if (strncmp(connector->name, edidname, colon - edidname))
continue;
edidname = colon + 1;
break;
@@ -310,8 +249,9 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
if (*last == '\n')
*last = '\0';
- edid = edid_load(connector, edidname, connector_name);
+ drm_edid = edid_load(connector, edidname);
+
kfree(fwstr);
- return edid;
+ return drm_edid;
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 71edb80fe0fb..b3a731b9170a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,24 +30,17 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/console.h>
-#include <linux/dma-buf.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/sysrq.h>
-#include <linux/vmalloc.h>
#include <drm/drm_atomic.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
-#include "drm_crtc_helper_internal.h"
#include "drm_internal.h"
static bool drm_fbdev_emulation = true;
@@ -74,7 +67,7 @@ MODULE_PARM_DESC(drm_fbdev_overalloc,
* considered as a broken and legacy behaviour from a modern fbdev device.
*/
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
-static bool drm_leak_fbdev_smem = false;
+static bool drm_leak_fbdev_smem;
module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
MODULE_PARM_DESC(drm_leak_fbdev_smem,
"Allow unsafe leaking fbdev physical smem address [default=false]");
@@ -96,11 +89,13 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* It will automatically set up deferred I/O if the driver requires a shadow
* buffer.
*
- * At runtime drivers should restore the fbdev console by using
+ * Existing fbdev implementations should restore the fbdev console by using
* drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
* They should also notify the fb helper code from updates to the output
* configuration by using drm_fb_helper_output_poll_changed() as their
- * &drm_mode_config_funcs.output_poll_changed callback.
+ * &drm_mode_config_funcs.output_poll_changed callback. New implementations
+ * of fbdev should be build on top of struct &drm_client_funcs, which handles
+ * this automatically. Setting the old callbacks should be avoided.
*
* For suspend/resume consider using drm_mode_config_helper_suspend() and
* drm_mode_config_helper_resume() which takes care of fbdev as well.
@@ -368,115 +363,30 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
resume_work);
console_lock();
- fb_set_suspend(helper->fbdev, 0);
+ fb_set_suspend(helper->info, 0);
console_unlock();
}
-static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper,
- struct drm_clip_rect *clip,
- struct iosys_map *dst)
+static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper)
{
- struct drm_framebuffer *fb = fb_helper->fb;
- size_t offset = clip->y1 * fb->pitches[0];
- size_t len = clip->x2 - clip->x1;
- unsigned int y;
- void *src;
-
- switch (drm_format_info_bpp(fb->format, 0)) {
- case 1:
- offset += clip->x1 / 8;
- len = DIV_ROUND_UP(len + clip->x1 % 8, 8);
- break;
- case 2:
- offset += clip->x1 / 4;
- len = DIV_ROUND_UP(len + clip->x1 % 4, 4);
- break;
- case 4:
- offset += clip->x1 / 2;
- len = DIV_ROUND_UP(len + clip->x1 % 2, 2);
- break;
- default:
- offset += clip->x1 * fb->format->cpp[0];
- len *= fb->format->cpp[0];
- break;
- }
-
- src = fb_helper->fbdev->screen_buffer + offset;
- iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
-
- for (y = clip->y1; y < clip->y2; y++) {
- iosys_map_memcpy_to(dst, 0, src, len);
- iosys_map_incr(dst, fb->pitches[0]);
- src += fb->pitches[0];
- }
-}
-
-static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
- struct drm_clip_rect *clip)
-{
- struct drm_client_buffer *buffer = fb_helper->buffer;
- struct iosys_map map, dst;
- int ret;
-
- /*
- * We have to pin the client buffer to its current location while
- * flushing the shadow buffer. In the general case, concurrent
- * modesetting operations could try to move the buffer and would
- * fail. The modeset has to be serialized by acquiring the reservation
- * object of the underlying BO here.
- *
- * For fbdev emulation, we only have to protect against fbdev modeset
- * operations. Nothing else will involve the client buffer's BO. So it
- * is sufficient to acquire struct drm_fb_helper.lock here.
- */
- mutex_lock(&fb_helper->lock);
-
- ret = drm_client_buffer_vmap(buffer, &map);
- if (ret)
- goto out;
-
- dst = map;
- drm_fb_helper_damage_blit_real(fb_helper, clip, &dst);
-
- drm_client_buffer_vunmap(buffer);
-
-out:
- mutex_unlock(&fb_helper->lock);
-
- return ret;
-}
-
-static void drm_fb_helper_damage_work(struct work_struct *work)
-{
- struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
- damage_work);
struct drm_device *dev = helper->dev;
struct drm_clip_rect *clip = &helper->damage_clip;
struct drm_clip_rect clip_copy;
unsigned long flags;
int ret;
+ if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
+ return;
+
spin_lock_irqsave(&helper->damage_lock, flags);
clip_copy = *clip;
clip->x1 = clip->y1 = ~0;
clip->x2 = clip->y2 = 0;
spin_unlock_irqrestore(&helper->damage_lock, flags);
- /* Call damage handlers only if necessary */
- if (!(clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2))
- return;
-
- if (helper->buffer) {
- ret = drm_fb_helper_damage_blit(helper, &clip_copy);
- if (drm_WARN_ONCE(dev, ret, "Damage blitter failed: ret=%d\n", ret))
- goto err;
- }
-
- if (helper->fb->funcs->dirty) {
- ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
- if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret))
- goto err;
- }
+ ret = helper->funcs->fb_dirty(helper, &clip_copy);
+ if (ret)
+ goto err;
return;
@@ -493,6 +403,13 @@ err:
spin_unlock_irqrestore(&helper->damage_lock, flags);
}
+static void drm_fb_helper_damage_work(struct work_struct *work)
+{
+ struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, damage_work);
+
+ drm_fb_helper_fb_dirty(helper);
+}
+
/**
* drm_fb_helper_prepare - setup a drm_fb_helper structure
* @dev: DRM device
@@ -536,11 +453,6 @@ int drm_fb_helper_init(struct drm_device *dev,
{
int ret;
- if (!drm_fbdev_emulation) {
- dev->fb_helper = fb_helper;
- return 0;
- }
-
/*
* If this is not the generic fbdev client, initialize a drm_client
* without callbacks so we can use the modesets.
@@ -558,7 +470,7 @@ int drm_fb_helper_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_fb_helper_init);
/**
- * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
+ * drm_fb_helper_alloc_info - allocate fb_info and some of its members
* @fb_helper: driver-allocated fbdev helper
*
* A helper to alloc fb_info and the members cmap and apertures. Called
@@ -570,7 +482,7 @@ EXPORT_SYMBOL(drm_fb_helper_init);
* fb_info pointer if things went okay, pointer containing error code
* otherwise
*/
-struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
+struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
{
struct device *dev = fb_helper->dev->dev;
struct fb_info *info;
@@ -598,7 +510,7 @@ struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
goto err_free_cmap;
}
- fb_helper->fbdev = info;
+ fb_helper->info = info;
info->skip_vt_switch = true;
return info;
@@ -609,22 +521,22 @@ err_release:
framebuffer_release(info);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
+EXPORT_SYMBOL(drm_fb_helper_alloc_info);
/**
- * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
+ * drm_fb_helper_unregister_info - unregister fb_info framebuffer device
* @fb_helper: driver-allocated fbdev helper, can be NULL
*
* A wrapper around unregister_framebuffer, to release the fb_info
* framebuffer device. This must be called before releasing all resources for
* @fb_helper by calling drm_fb_helper_fini().
*/
-void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
+void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper)
{
- if (fb_helper && fb_helper->fbdev)
- unregister_framebuffer(fb_helper->fbdev);
+ if (fb_helper && fb_helper->info)
+ unregister_framebuffer(fb_helper->info);
}
-EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
+EXPORT_SYMBOL(drm_fb_helper_unregister_info);
/**
* drm_fb_helper_fini - finialize a &struct drm_fb_helper
@@ -647,13 +559,13 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
cancel_work_sync(&fb_helper->resume_work);
cancel_work_sync(&fb_helper->damage_work);
- info = fb_helper->fbdev;
+ info = fb_helper->info;
if (info) {
if (info->cmap.len)
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
- fb_helper->fbdev = NULL;
+ fb_helper->info = NULL;
mutex_lock(&kernel_fb_helper_lock);
if (!list_empty(&fb_helper->kernel_fb_list)) {
@@ -670,32 +582,24 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
}
EXPORT_SYMBOL(drm_fb_helper_fini);
-static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
-{
- struct drm_device *dev = fb_helper->dev;
- struct drm_framebuffer *fb = fb_helper->fb;
-
- return dev->mode_config.prefer_shadow_fbdev ||
- dev->mode_config.prefer_shadow ||
- fb->funcs->dirty;
-}
-
-static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
- u32 width, u32 height)
+static void drm_fb_helper_add_damage_clip(struct drm_fb_helper *helper, u32 x, u32 y,
+ u32 width, u32 height)
{
- struct drm_fb_helper *helper = info->par;
struct drm_clip_rect *clip = &helper->damage_clip;
unsigned long flags;
- if (!drm_fbdev_use_shadow_fb(helper))
- return;
-
spin_lock_irqsave(&helper->damage_lock, flags);
clip->x1 = min_t(u32, clip->x1, x);
clip->y1 = min_t(u32, clip->y1, y);
clip->x2 = max_t(u32, clip->x2, x + width);
clip->y2 = max_t(u32, clip->y2, y + height);
spin_unlock_irqrestore(&helper->damage_lock, flags);
+}
+
+static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y,
+ u32 width, u32 height)
+{
+ drm_fb_helper_add_damage_clip(helper, x, y, width, height);
schedule_work(&helper->damage_work);
}
@@ -739,6 +643,7 @@ static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off,
*/
void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist)
{
+ struct drm_fb_helper *helper = info->par;
unsigned long start, end, min_off, max_off;
struct fb_deferred_io_pageref *pageref;
struct drm_rect damage_area;
@@ -751,8 +656,6 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli
min_off = min(min_off, start);
max_off = max(max_off, end);
}
- if (min_off >= max_off)
- return;
/*
* As we can only track pages, we might reach beyond the end
@@ -761,53 +664,160 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli
*/
max_off = min(max_off, info->screen_size);
- drm_fb_helper_memory_range_to_clip(info, min_off, max_off - min_off, &damage_area);
- drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
- drm_rect_width(&damage_area),
- drm_rect_height(&damage_area));
+ if (min_off < max_off) {
+ drm_fb_helper_memory_range_to_clip(info, min_off, max_off - min_off, &damage_area);
+ drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
+ }
}
EXPORT_SYMBOL(drm_fb_helper_deferred_io);
+typedef ssize_t (*drm_fb_helper_read_screen)(struct fb_info *info, char __user *buf,
+ size_t count, loff_t pos);
+
+static ssize_t __drm_fb_helper_read(struct fb_info *info, char __user *buf, size_t count,
+ loff_t *ppos, drm_fb_helper_read_screen read_screen)
+{
+ loff_t pos = *ppos;
+ size_t total_size;
+ ssize_t ret;
+
+ if (info->screen_size)
+ total_size = info->screen_size;
+ else
+ total_size = info->fix.smem_len;
+
+ if (pos >= total_size)
+ return 0;
+ if (count >= total_size)
+ count = total_size;
+ if (total_size - count < pos)
+ count = total_size - pos;
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ ret = read_screen(info, buf, count, pos);
+ if (ret > 0)
+ *ppos += ret;
+
+ return ret;
+}
+
+typedef ssize_t (*drm_fb_helper_write_screen)(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t pos);
+
+static ssize_t __drm_fb_helper_write(struct fb_info *info, const char __user *buf, size_t count,
+ loff_t *ppos, drm_fb_helper_write_screen write_screen)
+{
+ loff_t pos = *ppos;
+ size_t total_size;
+ ssize_t ret;
+ int err = 0;
+
+ if (info->screen_size)
+ total_size = info->screen_size;
+ else
+ total_size = info->fix.smem_len;
+
+ if (pos > total_size)
+ return -EFBIG;
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+ if (total_size - count < pos) {
+ if (!err)
+ err = -ENOSPC;
+ count = total_size - pos;
+ }
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ /*
+ * Copy to framebuffer even if we already logged an error. Emulates
+ * the behavior of the original fbdev implementation.
+ */
+ ret = write_screen(info, buf, count, pos);
+ if (ret < 0)
+ return ret; /* return last error, if any */
+ else if (!ret)
+ return err; /* return previous error, if any */
+
+ *ppos += ret;
+
+ return ret;
+}
+
+static ssize_t drm_fb_helper_read_screen_buffer(struct fb_info *info, char __user *buf,
+ size_t count, loff_t pos)
+{
+ const char *src = info->screen_buffer + pos;
+
+ if (copy_to_user(buf, src, count))
+ return -EFAULT;
+
+ return count;
+}
+
/**
- * drm_fb_helper_sys_read - wrapper around fb_sys_read
+ * drm_fb_helper_sys_read - Implements struct &fb_ops.fb_read for system memory
* @info: fb_info struct pointer
* @buf: userspace buffer to read from framebuffer memory
* @count: number of bytes to read from framebuffer memory
* @ppos: read offset within framebuffer memory
*
- * A wrapper around fb_sys_read implemented by fbdev core
+ * Returns:
+ * The number of bytes read on success, or an error code otherwise.
*/
ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos)
{
- return fb_sys_read(info, buf, count, ppos);
+ return __drm_fb_helper_read(info, buf, count, ppos, drm_fb_helper_read_screen_buffer);
}
EXPORT_SYMBOL(drm_fb_helper_sys_read);
+static ssize_t drm_fb_helper_write_screen_buffer(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t pos)
+{
+ char *dst = info->screen_buffer + pos;
+
+ if (copy_from_user(dst, buf, count))
+ return -EFAULT;
+
+ return count;
+}
+
/**
- * drm_fb_helper_sys_write - wrapper around fb_sys_write
+ * drm_fb_helper_sys_write - Implements struct &fb_ops.fb_write for system memory
* @info: fb_info struct pointer
* @buf: userspace buffer to write to framebuffer memory
* @count: number of bytes to write to framebuffer memory
* @ppos: write offset within framebuffer memory
*
- * A wrapper around fb_sys_write implemented by fbdev core
+ * Returns:
+ * The number of bytes written on success, or an error code otherwise.
*/
ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct drm_fb_helper *helper = info->par;
loff_t pos = *ppos;
ssize_t ret;
struct drm_rect damage_area;
- ret = fb_sys_write(info, buf, count, ppos);
+ ret = __drm_fb_helper_write(info, buf, count, ppos, drm_fb_helper_write_screen_buffer);
if (ret <= 0)
return ret;
- drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
- drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
- drm_rect_width(&damage_area),
- drm_rect_height(&damage_area));
+ if (helper->funcs->fb_dirty) {
+ drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
+ drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
+ }
return ret;
}
@@ -823,8 +833,12 @@ EXPORT_SYMBOL(drm_fb_helper_sys_write);
void drm_fb_helper_sys_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
+ struct drm_fb_helper *helper = info->par;
+
sys_fillrect(info, rect);
- drm_fb_helper_damage(info, rect->dx, rect->dy, rect->width, rect->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height);
}
EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
@@ -838,8 +852,12 @@ EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
void drm_fb_helper_sys_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
+ struct drm_fb_helper *helper = info->par;
+
sys_copyarea(info, area);
- drm_fb_helper_damage(info, area->dx, area->dy, area->width, area->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height);
}
EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
@@ -853,11 +871,131 @@ EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
void drm_fb_helper_sys_imageblit(struct fb_info *info,
const struct fb_image *image)
{
+ struct drm_fb_helper *helper = info->par;
+
sys_imageblit(info, image);
- drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height);
}
EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
+static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count,
+ loff_t pos)
+{
+ const char __iomem *src = info->screen_base + pos;
+ size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
+ ssize_t ret = 0;
+ int err = 0;
+ char *tmp;
+
+ tmp = kmalloc(alloc_size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ while (count) {
+ size_t c = min_t(size_t, count, alloc_size);
+
+ memcpy_fromio(tmp, src, c);
+ if (copy_to_user(buf, tmp, c)) {
+ err = -EFAULT;
+ break;
+ }
+
+ src += c;
+ buf += c;
+ ret += c;
+ count -= c;
+ }
+
+ kfree(tmp);
+
+ return ret ? ret : err;
+}
+
+/**
+ * drm_fb_helper_cfb_read - Implements struct &fb_ops.fb_read for I/O memory
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to read from framebuffer memory
+ * @count: number of bytes to read from framebuffer memory
+ * @ppos: read offset within framebuffer memory
+ *
+ * Returns:
+ * The number of bytes read on success, or an error code otherwise.
+ */
+ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return __drm_fb_helper_read(info, buf, count, ppos, fb_read_screen_base);
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_read);
+
+static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count,
+ loff_t pos)
+{
+ char __iomem *dst = info->screen_base + pos;
+ size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
+ ssize_t ret = 0;
+ int err = 0;
+ u8 *tmp;
+
+ tmp = kmalloc(alloc_size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ while (count) {
+ size_t c = min_t(size_t, count, alloc_size);
+
+ if (copy_from_user(tmp, buf, c)) {
+ err = -EFAULT;
+ break;
+ }
+ memcpy_toio(dst, tmp, c);
+
+ dst += c;
+ buf += c;
+ ret += c;
+ count -= c;
+ }
+
+ kfree(tmp);
+
+ return ret ? ret : err;
+}
+
+/**
+ * drm_fb_helper_cfb_write - Implements struct &fb_ops.fb_write for I/O memory
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to write to framebuffer memory
+ * @count: number of bytes to write to framebuffer memory
+ * @ppos: write offset within framebuffer memory
+ *
+ * Returns:
+ * The number of bytes written on success, or an error code otherwise.
+ */
+ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct drm_fb_helper *helper = info->par;
+ loff_t pos = *ppos;
+ ssize_t ret;
+ struct drm_rect damage_area;
+
+ ret = __drm_fb_helper_write(info, buf, count, ppos, fb_write_screen_base);
+ if (ret <= 0)
+ return ret;
+
+ if (helper->funcs->fb_dirty) {
+ drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
+ drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_write);
+
/**
* drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
* @info: fbdev registered by the helper
@@ -868,8 +1006,12 @@ EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
void drm_fb_helper_cfb_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
+ struct drm_fb_helper *helper = info->par;
+
cfb_fillrect(info, rect);
- drm_fb_helper_damage(info, rect->dx, rect->dy, rect->width, rect->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height);
}
EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
@@ -883,8 +1025,12 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
void drm_fb_helper_cfb_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
+ struct drm_fb_helper *helper = info->par;
+
cfb_copyarea(info, area);
- drm_fb_helper_damage(info, area->dx, area->dy, area->width, area->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height);
}
EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
@@ -898,8 +1044,12 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
void drm_fb_helper_cfb_imageblit(struct fb_info *info,
const struct fb_image *image)
{
+ struct drm_fb_helper *helper = info->par;
+
cfb_imageblit(info, image);
- drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height);
+
+ if (helper->funcs->fb_dirty)
+ drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height);
}
EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
@@ -914,8 +1064,8 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
*/
void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
{
- if (fb_helper && fb_helper->fbdev)
- fb_set_suspend(fb_helper->fbdev, suspend);
+ if (fb_helper && fb_helper->info)
+ fb_set_suspend(fb_helper->info, suspend);
}
EXPORT_SYMBOL(drm_fb_helper_set_suspend);
@@ -938,20 +1088,20 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend);
void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
bool suspend)
{
- if (!fb_helper || !fb_helper->fbdev)
+ if (!fb_helper || !fb_helper->info)
return;
/* make sure there's no pending/ongoing resume */
flush_work(&fb_helper->resume_work);
if (suspend) {
- if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
+ if (fb_helper->info->state != FBINFO_STATE_RUNNING)
return;
console_lock();
} else {
- if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
+ if (fb_helper->info->state == FBINFO_STATE_RUNNING)
return;
if (!console_trylock()) {
@@ -960,7 +1110,7 @@ void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
}
}
- fb_set_suspend(fb_helper->fbdev, suspend);
+ fb_set_suspend(fb_helper->info, suspend);
console_unlock();
}
EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
@@ -1749,6 +1899,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
sizes.surface_height = config->max_height;
}
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+ fb_helper->hint_leak_smem_start = drm_leak_fbdev_smem;
+#endif
+
/* push down into drivers */
ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
if (ret < 0)
@@ -1850,7 +2004,7 @@ EXPORT_SYMBOL(drm_fb_helper_fill_info);
/*
* This is a continuation of drm_setup_crtcs() that sets up anything related
* to the framebuffer. During initialization, drm_setup_crtcs() is called before
- * the framebuffer has been allocated (fb_helper->fb and fb_helper->fbdev).
+ * the framebuffer has been allocated (fb_helper->fb and fb_helper->info).
* So, any setup that touches those fields needs to be done here instead of in
* drm_setup_crtcs().
*/
@@ -1858,7 +2012,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_connector_list_iter conn_iter;
- struct fb_info *info = fb_helper->fbdev;
+ struct fb_info *info = fb_helper->info;
unsigned int rotation, sw_rotations = 0;
struct drm_connector *connector;
struct drm_mode_set *modeset;
@@ -1942,11 +2096,11 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
fb_helper->deferred_setup = false;
- info = fb_helper->fbdev;
+ info = fb_helper->info;
info->var.pixclock = 0;
/* Shamelessly allow physical address leaking to userspace */
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
- if (!drm_leak_fbdev_smem)
+ if (!fb_helper->hint_leak_smem_start)
#endif
/* don't leak any physical addresses to userspace */
info->flags |= FBINFO_HIDE_SMEM_START;
@@ -2077,7 +2231,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
drm_setup_crtcs_fb(fb_helper);
mutex_unlock(&fb_helper->lock);
- drm_fb_helper_set_par(fb_helper->fbdev);
+ drm_fb_helper_set_par(fb_helper->info);
return 0;
}
@@ -2103,530 +2257,10 @@ EXPORT_SYMBOL(drm_fb_helper_lastclose);
*
* This function can be used as the
* &drm_mode_config_funcs.output_poll_changed callback for drivers that only
- * need to call drm_fb_helper_hotplug_event().
+ * need to call drm_fbdev.hotplug_event().
*/
void drm_fb_helper_output_poll_changed(struct drm_device *dev)
{
drm_fb_helper_hotplug_event(dev->fb_helper);
}
EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
-
-/* @user: 1=userspace, 0=fbcon */
-static int drm_fbdev_fb_open(struct fb_info *info, int user)
-{
- struct drm_fb_helper *fb_helper = info->par;
-
- /* No need to take a ref for fbcon because it unbinds on unregister */
- if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
- return -ENODEV;
-
- return 0;
-}
-
-static int drm_fbdev_fb_release(struct fb_info *info, int user)
-{
- struct drm_fb_helper *fb_helper = info->par;
-
- if (user)
- module_put(fb_helper->dev->driver->fops->owner);
-
- return 0;
-}
-
-static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
-{
- struct fb_info *fbi = fb_helper->fbdev;
- void *shadow = NULL;
-
- if (!fb_helper->dev)
- return;
-
- if (fbi) {
- if (fbi->fbdefio)
- fb_deferred_io_cleanup(fbi);
- if (drm_fbdev_use_shadow_fb(fb_helper))
- shadow = fbi->screen_buffer;
- }
-
- drm_fb_helper_fini(fb_helper);
-
- if (shadow)
- vfree(shadow);
- else if (fb_helper->buffer)
- drm_client_buffer_vunmap(fb_helper->buffer);
-
- drm_client_framebuffer_delete(fb_helper->buffer);
-}
-
-static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
-{
- drm_fbdev_cleanup(fb_helper);
- drm_client_release(&fb_helper->client);
- kfree(fb_helper);
-}
-
-/*
- * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
- * unregister_framebuffer() or fb_release().
- */
-static void drm_fbdev_fb_destroy(struct fb_info *info)
-{
- drm_fbdev_release(info->par);
-}
-
-static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
- struct drm_fb_helper *fb_helper = info->par;
-
- if (drm_fbdev_use_shadow_fb(fb_helper))
- return fb_deferred_io_mmap(info, vma);
- else if (fb_helper->dev->driver->gem_prime_mmap)
- return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
- else
- return -ENODEV;
-}
-
-static bool drm_fbdev_use_iomem(struct fb_info *info)
-{
- struct drm_fb_helper *fb_helper = info->par;
- struct drm_client_buffer *buffer = fb_helper->buffer;
-
- return !drm_fbdev_use_shadow_fb(fb_helper) && buffer->map.is_iomem;
-}
-
-static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count,
- loff_t pos)
-{
- const char __iomem *src = info->screen_base + pos;
- size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
- ssize_t ret = 0;
- int err = 0;
- char *tmp;
-
- tmp = kmalloc(alloc_size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- while (count) {
- size_t c = min_t(size_t, count, alloc_size);
-
- memcpy_fromio(tmp, src, c);
- if (copy_to_user(buf, tmp, c)) {
- err = -EFAULT;
- break;
- }
-
- src += c;
- buf += c;
- ret += c;
- count -= c;
- }
-
- kfree(tmp);
-
- return ret ? ret : err;
-}
-
-static ssize_t fb_read_screen_buffer(struct fb_info *info, char __user *buf, size_t count,
- loff_t pos)
-{
- const char *src = info->screen_buffer + pos;
-
- if (copy_to_user(buf, src, count))
- return -EFAULT;
-
- return count;
-}
-
-static ssize_t drm_fbdev_fb_read(struct fb_info *info, char __user *buf,
- size_t count, loff_t *ppos)
-{
- loff_t pos = *ppos;
- size_t total_size;
- ssize_t ret;
-
- if (info->screen_size)
- total_size = info->screen_size;
- else
- total_size = info->fix.smem_len;
-
- if (pos >= total_size)
- return 0;
- if (count >= total_size)
- count = total_size;
- if (total_size - count < pos)
- count = total_size - pos;
-
- if (drm_fbdev_use_iomem(info))
- ret = fb_read_screen_base(info, buf, count, pos);
- else
- ret = fb_read_screen_buffer(info, buf, count, pos);
-
- if (ret > 0)
- *ppos += ret;
-
- return ret;
-}
-
-static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count,
- loff_t pos)
-{
- char __iomem *dst = info->screen_base + pos;
- size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
- ssize_t ret = 0;
- int err = 0;
- u8 *tmp;
-
- tmp = kmalloc(alloc_size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- while (count) {
- size_t c = min_t(size_t, count, alloc_size);
-
- if (copy_from_user(tmp, buf, c)) {
- err = -EFAULT;
- break;
- }
- memcpy_toio(dst, tmp, c);
-
- dst += c;
- buf += c;
- ret += c;
- count -= c;
- }
-
- kfree(tmp);
-
- return ret ? ret : err;
-}
-
-static ssize_t fb_write_screen_buffer(struct fb_info *info, const char __user *buf, size_t count,
- loff_t pos)
-{
- char *dst = info->screen_buffer + pos;
-
- if (copy_from_user(dst, buf, count))
- return -EFAULT;
-
- return count;
-}
-
-static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- loff_t pos = *ppos;
- size_t total_size;
- ssize_t ret;
- struct drm_rect damage_area;
- int err = 0;
-
- if (info->screen_size)
- total_size = info->screen_size;
- else
- total_size = info->fix.smem_len;
-
- if (pos > total_size)
- return -EFBIG;
- if (count > total_size) {
- err = -EFBIG;
- count = total_size;
- }
- if (total_size - count < pos) {
- if (!err)
- err = -ENOSPC;
- count = total_size - pos;
- }
-
- /*
- * Copy to framebuffer even if we already logged an error. Emulates
- * the behavior of the original fbdev implementation.
- */
- if (drm_fbdev_use_iomem(info))
- ret = fb_write_screen_base(info, buf, count, pos);
- else
- ret = fb_write_screen_buffer(info, buf, count, pos);
-
- if (ret < 0)
- return ret; /* return last error, if any */
- else if (!ret)
- return err; /* return previous error, if any */
-
- *ppos += ret;
-
- drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
- drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
- drm_rect_width(&damage_area),
- drm_rect_height(&damage_area));
-
- return ret;
-}
-
-static void drm_fbdev_fb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect)
-{
- if (drm_fbdev_use_iomem(info))
- drm_fb_helper_cfb_fillrect(info, rect);
- else
- drm_fb_helper_sys_fillrect(info, rect);
-}
-
-static void drm_fbdev_fb_copyarea(struct fb_info *info,
- const struct fb_copyarea *area)
-{
- if (drm_fbdev_use_iomem(info))
- drm_fb_helper_cfb_copyarea(info, area);
- else
- drm_fb_helper_sys_copyarea(info, area);
-}
-
-static void drm_fbdev_fb_imageblit(struct fb_info *info,
- const struct fb_image *image)
-{
- if (drm_fbdev_use_iomem(info))
- drm_fb_helper_cfb_imageblit(info, image);
- else
- drm_fb_helper_sys_imageblit(info, image);
-}
-
-static const struct fb_ops drm_fbdev_fb_ops = {
- .owner = THIS_MODULE,
- DRM_FB_HELPER_DEFAULT_OPS,
- .fb_open = drm_fbdev_fb_open,
- .fb_release = drm_fbdev_fb_release,
- .fb_destroy = drm_fbdev_fb_destroy,
- .fb_mmap = drm_fbdev_fb_mmap,
- .fb_read = drm_fbdev_fb_read,
- .fb_write = drm_fbdev_fb_write,
- .fb_fillrect = drm_fbdev_fb_fillrect,
- .fb_copyarea = drm_fbdev_fb_copyarea,
- .fb_imageblit = drm_fbdev_fb_imageblit,
-};
-
-static struct fb_deferred_io drm_fbdev_defio = {
- .delay = HZ / 20,
- .deferred_io = drm_fb_helper_deferred_io,
-};
-
-/*
- * This function uses the client API to create a framebuffer backed by a dumb buffer.
- *
- * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
- * fb_copyarea, fb_imageblit.
- */
-static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct drm_client_dev *client = &fb_helper->client;
- struct drm_device *dev = fb_helper->dev;
- struct drm_client_buffer *buffer;
- struct drm_framebuffer *fb;
- struct fb_info *fbi;
- u32 format;
- struct iosys_map map;
- int ret;
-
- drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
- sizes->surface_width, sizes->surface_height,
- sizes->surface_bpp);
-
- format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
- buffer = drm_client_framebuffer_create(client, sizes->surface_width,
- sizes->surface_height, format);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
-
- fb_helper->buffer = buffer;
- fb_helper->fb = buffer->fb;
- fb = buffer->fb;
-
- fbi = drm_fb_helper_alloc_fbi(fb_helper);
- if (IS_ERR(fbi))
- return PTR_ERR(fbi);
-
- fbi->fbops = &drm_fbdev_fb_ops;
- fbi->screen_size = sizes->surface_height * fb->pitches[0];
- fbi->fix.smem_len = fbi->screen_size;
- fbi->flags = FBINFO_DEFAULT;
-
- drm_fb_helper_fill_info(fbi, fb_helper, sizes);
-
- if (drm_fbdev_use_shadow_fb(fb_helper)) {
- fbi->screen_buffer = vzalloc(fbi->screen_size);
- if (!fbi->screen_buffer)
- return -ENOMEM;
- fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
-
- fbi->fbdefio = &drm_fbdev_defio;
- fb_deferred_io_init(fbi);
- } else {
- /* buffer is mapped for HW framebuffer */
- ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
- if (ret)
- return ret;
- if (map.is_iomem) {
- fbi->screen_base = map.vaddr_iomem;
- } else {
- fbi->screen_buffer = map.vaddr;
- fbi->flags |= FBINFO_VIRTFB;
- }
-
- /*
- * Shamelessly leak the physical address to user-space. As
- * page_to_phys() is undefined for I/O memory, warn in this
- * case.
- */
-#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
- if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0 &&
- !drm_WARN_ON_ONCE(dev, map.is_iomem))
- fbi->fix.smem_start =
- page_to_phys(virt_to_page(fbi->screen_buffer));
-#endif
- }
-
- return 0;
-}
-
-static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
- .fb_probe = drm_fb_helper_generic_probe,
-};
-
-static void drm_fbdev_client_unregister(struct drm_client_dev *client)
-{
- struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
-
- if (fb_helper->fbdev)
- /* drm_fbdev_fb_destroy() takes care of cleanup */
- drm_fb_helper_unregister_fbi(fb_helper);
- else
- drm_fbdev_release(fb_helper);
-}
-
-static int drm_fbdev_client_restore(struct drm_client_dev *client)
-{
- drm_fb_helper_lastclose(client->dev);
-
- return 0;
-}
-
-static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
-{
- struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
- struct drm_device *dev = client->dev;
- int ret;
-
- /* Setup is not retried if it has failed */
- if (!fb_helper->dev && fb_helper->funcs)
- return 0;
-
- if (dev->fb_helper)
- return drm_fb_helper_hotplug_event(dev->fb_helper);
-
- if (!dev->mode_config.num_connector) {
- drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
- return 0;
- }
-
- drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
-
- ret = drm_fb_helper_init(dev, fb_helper);
- if (ret)
- goto err;
-
- if (!drm_drv_uses_atomic_modeset(dev))
- drm_helper_disable_unused_functions(dev);
-
- ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
- if (ret)
- goto err_cleanup;
-
- return 0;
-
-err_cleanup:
- drm_fbdev_cleanup(fb_helper);
-err:
- fb_helper->dev = NULL;
- fb_helper->fbdev = NULL;
-
- drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
-
- return ret;
-}
-
-static const struct drm_client_funcs drm_fbdev_client_funcs = {
- .owner = THIS_MODULE,
- .unregister = drm_fbdev_client_unregister,
- .restore = drm_fbdev_client_restore,
- .hotplug = drm_fbdev_client_hotplug,
-};
-
-/**
- * drm_fbdev_generic_setup() - Setup generic fbdev emulation
- * @dev: DRM device
- * @preferred_bpp: Preferred bits per pixel for the device.
- * @dev->mode_config.preferred_depth is used if this is zero.
- *
- * This function sets up generic fbdev emulation for drivers that supports
- * dumb buffers with a virtual address and that can be mmap'ed.
- * drm_fbdev_generic_setup() shall be called after the DRM driver registered
- * the new DRM device with drm_dev_register().
- *
- * Restore, hotplug events and teardown are all taken care of. Drivers that do
- * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
- * Simple drivers might use drm_mode_config_helper_suspend().
- *
- * Drivers that set the dirty callback on their framebuffer will get a shadow
- * fbdev buffer that is blitted onto the real buffer. This is done in order to
- * make deferred I/O work with all kinds of buffers. A shadow buffer can be
- * requested explicitly by setting struct drm_mode_config.prefer_shadow or
- * struct drm_mode_config.prefer_shadow_fbdev to true beforehand. This is
- * required to use generic fbdev emulation with SHMEM helpers.
- *
- * This function is safe to call even when there are no connectors present.
- * Setup will be retried on the next hotplug event.
- *
- * The fbdev is destroyed by drm_dev_unregister().
- */
-void drm_fbdev_generic_setup(struct drm_device *dev,
- unsigned int preferred_bpp)
-{
- struct drm_fb_helper *fb_helper;
- int ret;
-
- drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
- drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
-
- if (!drm_fbdev_emulation)
- return;
-
- fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
- if (!fb_helper) {
- drm_err(dev, "Failed to allocate fb_helper\n");
- return;
- }
-
- ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
- if (ret) {
- kfree(fb_helper);
- drm_err(dev, "Failed to register client: %d\n", ret);
- return;
- }
-
- /*
- * FIXME: This mixes up depth with bpp, which results in a glorious
- * mess, resulting in some drivers picking wrong fbdev defaults and
- * others wrong preferred_depth defaults.
- */
- if (!preferred_bpp)
- preferred_bpp = dev->mode_config.preferred_depth;
- if (!preferred_bpp)
- preferred_bpp = 32;
- fb_helper->preferred_bpp = preferred_bpp;
-
- ret = drm_fbdev_client_hotplug(&fb_helper->client);
- if (ret)
- drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
-
- drm_client_register(&fb_helper->client);
-}
-EXPORT_SYMBOL(drm_fbdev_generic_setup);
diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c
new file mode 100644
index 000000000000..ab8695669279
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbdev_generic.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: MIT
+
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_print.h>
+
+#include <drm/drm_fbdev_generic.h>
+
+static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
+{
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_framebuffer *fb = fb_helper->fb;
+
+ return dev->mode_config.prefer_shadow_fbdev ||
+ dev->mode_config.prefer_shadow ||
+ fb->funcs->dirty;
+}
+
+/* @user: 1=userspace, 0=fbcon */
+static int drm_fbdev_fb_open(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ /* No need to take a ref for fbcon because it unbinds on unregister */
+ if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int drm_fbdev_fb_release(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ if (user)
+ module_put(fb_helper->dev->driver->fops->owner);
+
+ return 0;
+}
+
+static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
+{
+ struct fb_info *fbi = fb_helper->info;
+ void *shadow = NULL;
+
+ if (!fb_helper->dev)
+ return;
+
+ if (fbi) {
+ if (fbi->fbdefio)
+ fb_deferred_io_cleanup(fbi);
+ if (drm_fbdev_use_shadow_fb(fb_helper))
+ shadow = fbi->screen_buffer;
+ }
+
+ drm_fb_helper_fini(fb_helper);
+
+ if (shadow)
+ vfree(shadow);
+ else if (fb_helper->buffer)
+ drm_client_buffer_vunmap(fb_helper->buffer);
+
+ drm_client_framebuffer_delete(fb_helper->buffer);
+}
+
+static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
+{
+ drm_fbdev_cleanup(fb_helper);
+ drm_client_release(&fb_helper->client);
+ kfree(fb_helper);
+}
+
+/*
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
+ * unregister_framebuffer() or fb_release().
+ */
+static void drm_fbdev_fb_destroy(struct fb_info *info)
+{
+ drm_fbdev_release(info->par);
+}
+
+static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ if (drm_fbdev_use_shadow_fb(fb_helper))
+ return fb_deferred_io_mmap(info, vma);
+ else if (fb_helper->dev->driver->gem_prime_mmap)
+ return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+ else
+ return -ENODEV;
+}
+
+static bool drm_fbdev_use_iomem(struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_client_buffer *buffer = fb_helper->buffer;
+
+ return !drm_fbdev_use_shadow_fb(fb_helper) && buffer->map.is_iomem;
+}
+
+static ssize_t drm_fbdev_fb_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+
+ if (drm_fbdev_use_iomem(info))
+ ret = drm_fb_helper_cfb_read(info, buf, count, ppos);
+ else
+ ret = drm_fb_helper_sys_read(info, buf, count, ppos);
+
+ return ret;
+}
+
+static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+
+ if (drm_fbdev_use_iomem(info))
+ ret = drm_fb_helper_cfb_write(info, buf, count, ppos);
+ else
+ ret = drm_fb_helper_sys_write(info, buf, count, ppos);
+
+ return ret;
+}
+
+static void drm_fbdev_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ if (drm_fbdev_use_iomem(info))
+ drm_fb_helper_cfb_fillrect(info, rect);
+ else
+ drm_fb_helper_sys_fillrect(info, rect);
+}
+
+static void drm_fbdev_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ if (drm_fbdev_use_iomem(info))
+ drm_fb_helper_cfb_copyarea(info, area);
+ else
+ drm_fb_helper_sys_copyarea(info, area);
+}
+
+static void drm_fbdev_fb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ if (drm_fbdev_use_iomem(info))
+ drm_fb_helper_cfb_imageblit(info, image);
+ else
+ drm_fb_helper_sys_imageblit(info, image);
+}
+
+static const struct fb_ops drm_fbdev_fb_ops = {
+ .owner = THIS_MODULE,
+ DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_open = drm_fbdev_fb_open,
+ .fb_release = drm_fbdev_fb_release,
+ .fb_destroy = drm_fbdev_fb_destroy,
+ .fb_mmap = drm_fbdev_fb_mmap,
+ .fb_read = drm_fbdev_fb_read,
+ .fb_write = drm_fbdev_fb_write,
+ .fb_fillrect = drm_fbdev_fb_fillrect,
+ .fb_copyarea = drm_fbdev_fb_copyarea,
+ .fb_imageblit = drm_fbdev_fb_imageblit,
+};
+
+static struct fb_deferred_io drm_fbdev_defio = {
+ .delay = HZ / 20,
+ .deferred_io = drm_fb_helper_deferred_io,
+};
+
+/*
+ * This function uses the client API to create a framebuffer backed by a dumb buffer.
+ */
+static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_client_buffer *buffer;
+ struct drm_framebuffer *fb;
+ struct fb_info *fbi;
+ u32 format;
+ struct iosys_map map;
+ int ret;
+
+ drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+
+ format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+ buffer = drm_client_framebuffer_create(client, sizes->surface_width,
+ sizes->surface_height, format);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ fb_helper->buffer = buffer;
+ fb_helper->fb = buffer->fb;
+ fb = buffer->fb;
+
+ fbi = drm_fb_helper_alloc_info(fb_helper);
+ if (IS_ERR(fbi))
+ return PTR_ERR(fbi);
+
+ fbi->fbops = &drm_fbdev_fb_ops;
+ fbi->screen_size = sizes->surface_height * fb->pitches[0];
+ fbi->fix.smem_len = fbi->screen_size;
+ fbi->flags = FBINFO_DEFAULT;
+
+ drm_fb_helper_fill_info(fbi, fb_helper, sizes);
+
+ if (drm_fbdev_use_shadow_fb(fb_helper)) {
+ fbi->screen_buffer = vzalloc(fbi->screen_size);
+ if (!fbi->screen_buffer)
+ return -ENOMEM;
+ fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
+
+ fbi->fbdefio = &drm_fbdev_defio;
+ fb_deferred_io_init(fbi);
+ } else {
+ /* buffer is mapped for HW framebuffer */
+ ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
+ if (ret)
+ return ret;
+ if (map.is_iomem) {
+ fbi->screen_base = map.vaddr_iomem;
+ } else {
+ fbi->screen_buffer = map.vaddr;
+ fbi->flags |= FBINFO_VIRTFB;
+ }
+
+ /*
+ * Shamelessly leak the physical address to user-space. As
+ * page_to_phys() is undefined for I/O memory, warn in this
+ * case.
+ */
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+ if (fb_helper->hint_leak_smem_start && fbi->fix.smem_start == 0 &&
+ !drm_WARN_ON_ONCE(dev, map.is_iomem))
+ fbi->fix.smem_start =
+ page_to_phys(virt_to_page(fbi->screen_buffer));
+#endif
+ }
+
+ return 0;
+}
+
+static void drm_fbdev_damage_blit_real(struct drm_fb_helper *fb_helper,
+ struct drm_clip_rect *clip,
+ struct iosys_map *dst)
+{
+ struct drm_framebuffer *fb = fb_helper->fb;
+ size_t offset = clip->y1 * fb->pitches[0];
+ size_t len = clip->x2 - clip->x1;
+ unsigned int y;
+ void *src;
+
+ switch (drm_format_info_bpp(fb->format, 0)) {
+ case 1:
+ offset += clip->x1 / 8;
+ len = DIV_ROUND_UP(len + clip->x1 % 8, 8);
+ break;
+ case 2:
+ offset += clip->x1 / 4;
+ len = DIV_ROUND_UP(len + clip->x1 % 4, 4);
+ break;
+ case 4:
+ offset += clip->x1 / 2;
+ len = DIV_ROUND_UP(len + clip->x1 % 2, 2);
+ break;
+ default:
+ offset += clip->x1 * fb->format->cpp[0];
+ len *= fb->format->cpp[0];
+ break;
+ }
+
+ src = fb_helper->info->screen_buffer + offset;
+ iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
+
+ for (y = clip->y1; y < clip->y2; y++) {
+ iosys_map_memcpy_to(dst, 0, src, len);
+ iosys_map_incr(dst, fb->pitches[0]);
+ src += fb->pitches[0];
+ }
+}
+
+static int drm_fbdev_damage_blit(struct drm_fb_helper *fb_helper,
+ struct drm_clip_rect *clip)
+{
+ struct drm_client_buffer *buffer = fb_helper->buffer;
+ struct iosys_map map, dst;
+ int ret;
+
+ /*
+ * We have to pin the client buffer to its current location while
+ * flushing the shadow buffer. In the general case, concurrent
+ * modesetting operations could try to move the buffer and would
+ * fail. The modeset has to be serialized by acquiring the reservation
+ * object of the underlying BO here.
+ *
+ * For fbdev emulation, we only have to protect against fbdev modeset
+ * operations. Nothing else will involve the client buffer's BO. So it
+ * is sufficient to acquire struct drm_fb_helper.lock here.
+ */
+ mutex_lock(&fb_helper->lock);
+
+ ret = drm_client_buffer_vmap(buffer, &map);
+ if (ret)
+ goto out;
+
+ dst = map;
+ drm_fbdev_damage_blit_real(fb_helper, clip, &dst);
+
+ drm_client_buffer_vunmap(buffer);
+
+out:
+ mutex_unlock(&fb_helper->lock);
+
+ return ret;
+}
+
+static int drm_fbdev_fb_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip)
+{
+ struct drm_device *dev = helper->dev;
+ int ret;
+
+ if (!drm_fbdev_use_shadow_fb(helper))
+ return 0;
+
+ /* Call damage handlers only if necessary */
+ if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2))
+ return 0;
+
+ if (helper->buffer) {
+ ret = drm_fbdev_damage_blit(helper, clip);
+ if (drm_WARN_ONCE(dev, ret, "Damage blitter failed: ret=%d\n", ret))
+ return ret;
+ }
+
+ if (helper->fb->funcs->dirty) {
+ ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1);
+ if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret))
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
+ .fb_probe = drm_fbdev_fb_probe,
+ .fb_dirty = drm_fbdev_fb_dirty,
+};
+
+static void drm_fbdev_client_unregister(struct drm_client_dev *client)
+{
+ struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+ if (fb_helper->info)
+ /* drm_fbdev_fb_destroy() takes care of cleanup */
+ drm_fb_helper_unregister_info(fb_helper);
+ else
+ drm_fbdev_release(fb_helper);
+}
+
+static int drm_fbdev_client_restore(struct drm_client_dev *client)
+{
+ drm_fb_helper_lastclose(client->dev);
+
+ return 0;
+}
+
+static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
+{
+ struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+ struct drm_device *dev = client->dev;
+ int ret;
+
+ /* Setup is not retried if it has failed */
+ if (!fb_helper->dev && fb_helper->funcs)
+ return 0;
+
+ if (dev->fb_helper)
+ return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+ if (!dev->mode_config.num_connector) {
+ drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
+ return 0;
+ }
+
+ drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
+
+ ret = drm_fb_helper_init(dev, fb_helper);
+ if (ret)
+ goto err;
+
+ if (!drm_drv_uses_atomic_modeset(dev))
+ drm_helper_disable_unused_functions(dev);
+
+ ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
+ if (ret)
+ goto err_cleanup;
+
+ return 0;
+
+err_cleanup:
+ drm_fbdev_cleanup(fb_helper);
+err:
+ fb_helper->dev = NULL;
+ fb_helper->info = NULL;
+
+ drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
+
+ return ret;
+}
+
+static const struct drm_client_funcs drm_fbdev_client_funcs = {
+ .owner = THIS_MODULE,
+ .unregister = drm_fbdev_client_unregister,
+ .restore = drm_fbdev_client_restore,
+ .hotplug = drm_fbdev_client_hotplug,
+};
+
+/**
+ * drm_fbdev_generic_setup() - Setup generic fbdev emulation
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ * @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up generic fbdev emulation for drivers that supports
+ * dumb buffers with a virtual address and that can be mmap'ed.
+ * drm_fbdev_generic_setup() shall be called after the DRM driver registered
+ * the new DRM device with drm_dev_register().
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * Drivers that set the dirty callback on their framebuffer will get a shadow
+ * fbdev buffer that is blitted onto the real buffer. This is done in order to
+ * make deferred I/O work with all kinds of buffers. A shadow buffer can be
+ * requested explicitly by setting struct drm_mode_config.prefer_shadow or
+ * struct drm_mode_config.prefer_shadow_fbdev to true beforehand. This is
+ * required to use generic fbdev emulation with SHMEM helpers.
+ *
+ * This function is safe to call even when there are no connectors present.
+ * Setup will be retried on the next hotplug event.
+ *
+ * The fbdev is destroyed by drm_dev_unregister().
+ */
+void drm_fbdev_generic_setup(struct drm_device *dev,
+ unsigned int preferred_bpp)
+{
+ struct drm_fb_helper *fb_helper;
+ int ret;
+
+ drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+ drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+
+ fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+ if (!fb_helper)
+ return;
+
+ ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
+ if (ret) {
+ kfree(fb_helper);
+ drm_err(dev, "Failed to register client: %d\n", ret);
+ return;
+ }
+
+ /*
+ * FIXME: This mixes up depth with bpp, which results in a glorious
+ * mess, resulting in some drivers picking wrong fbdev defaults and
+ * others wrong preferred_depth defaults.
+ */
+ if (!preferred_bpp)
+ preferred_bpp = dev->mode_config.preferred_depth;
+ if (!preferred_bpp)
+ preferred_bpp = 32;
+ fb_helper->preferred_bpp = preferred_bpp;
+
+ ret = drm_fbdev_client_hotplug(&fb_helper->client);
+ if (ret)
+ drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+
+ drm_client_register(&fb_helper->client);
+}
+EXPORT_SYMBOL(drm_fbdev_generic_setup);
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index a8b4d918e9a3..64b4a3a87fbb 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -326,7 +326,7 @@ static int drm_cpu_valid(void)
* Creates and initializes a drm_file structure for the file private data in \p
* filp and add it into the double linked list in \p dev.
*/
-static int drm_open_helper(struct file *filp, struct drm_minor *minor)
+int drm_open_helper(struct file *filp, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct drm_file *priv;
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 3ee59bae9d2f..74ff33c2ddaa 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -660,6 +660,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
return 0;
}
+ } else if (dst_format == (DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN)) {
+ if (fb_format == DRM_FORMAT_RGB565) {
+ drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+ return 0;
+ }
} else if (dst_format == DRM_FORMAT_RGB888) {
if (fb_format == DRM_FORMAT_XRGB8888) {
drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
@@ -678,6 +683,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
return 0;
}
+ } else if (dst_format == DRM_FORMAT_BGRX8888) {
+ if (fb_format == DRM_FORMAT_XRGB8888) {
+ drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+ return 0;
+ }
}
drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index e09331bb3bc7..6242dfbe9240 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -297,12 +297,12 @@ const struct drm_format_info *__drm_format_info(u32 format)
.vsub = 2, .is_yuv = true },
{ .format = DRM_FORMAT_Q410, .depth = 0,
.num_planes = 3, .char_per_block = { 2, 2, 2 },
- .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
- .vsub = 0, .is_yuv = true },
+ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1,
+ .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_Q401, .depth = 0,
.num_planes = 3, .char_per_block = { 2, 2, 2 },
- .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
- .vsub = 0, .is_yuv = true },
+ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1,
+ .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2,
.char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
.hsub = 2, .vsub = 2, .is_yuv = true},
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 8b68a3c1e6ab..b8db675e7fb5 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1158,6 +1158,8 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
{
int ret;
+ dma_resv_assert_held(obj->resv);
+
if (!obj->funcs->vmap)
return -EOPNOTSUPP;
@@ -1173,6 +1175,8 @@ EXPORT_SYMBOL(drm_gem_vmap);
void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
{
+ dma_resv_assert_held(obj->resv);
+
if (iosys_map_is_null(map))
return;
@@ -1184,6 +1188,26 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
}
EXPORT_SYMBOL(drm_gem_vunmap);
+int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
+{
+ int ret;
+
+ dma_resv_lock(obj->resv, NULL);
+ ret = drm_gem_vmap(obj, map);
+ dma_resv_unlock(obj->resv);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_gem_vmap_unlocked);
+
+void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
+{
+ dma_resv_lock(obj->resv, NULL);
+ drm_gem_vunmap(obj, map);
+ dma_resv_unlock(obj->resv);
+}
+EXPORT_SYMBOL(drm_gem_vunmap_unlocked);
+
/**
* drm_gem_lock_reservations - Sets up the ww context and acquires
* the lock on an array of GEM objects.
diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c
index b6a0110eb64a..e42800718f51 100644
--- a/drivers/gpu/drm/drm_gem_atomic_helper.c
+++ b/drivers/gpu/drm/drm_gem_atomic_helper.c
@@ -360,48 +360,43 @@ void drm_gem_reset_shadow_plane(struct drm_plane *plane)
EXPORT_SYMBOL(drm_gem_reset_shadow_plane);
/**
- * drm_gem_prepare_shadow_fb - prepares shadow framebuffers
+ * drm_gem_begin_shadow_fb_access - prepares shadow framebuffers for CPU access
* @plane: the plane
* @plane_state: the plane state of type struct drm_shadow_plane_state
*
- * This function implements struct &drm_plane_helper_funcs.prepare_fb. It
+ * This function implements struct &drm_plane_helper_funcs.begin_fb_access. It
* maps all buffer objects of the plane's framebuffer into kernel address
- * space and stores them in &struct drm_shadow_plane_state.map. The
- * framebuffer will be synchronized as part of the atomic commit.
+ * space and stores them in struct &drm_shadow_plane_state.map. The first data
+ * bytes are available in struct &drm_shadow_plane_state.data.
*
- * See drm_gem_cleanup_shadow_fb() for cleanup.
+ * See drm_gem_end_shadow_fb_access() for cleanup.
*
* Returns:
* 0 on success, or a negative errno code otherwise.
*/
-int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state)
+int drm_gem_begin_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
- int ret;
if (!fb)
return 0;
- ret = drm_gem_plane_helper_prepare_fb(plane, plane_state);
- if (ret)
- return ret;
-
return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
}
-EXPORT_SYMBOL(drm_gem_prepare_shadow_fb);
+EXPORT_SYMBOL(drm_gem_begin_shadow_fb_access);
/**
- * drm_gem_cleanup_shadow_fb - releases shadow framebuffers
+ * drm_gem_end_shadow_fb_access - releases shadow framebuffers from CPU access
* @plane: the plane
* @plane_state: the plane state of type struct drm_shadow_plane_state
*
- * This function implements struct &drm_plane_helper_funcs.cleanup_fb.
- * This function unmaps all buffer objects of the plane's framebuffer.
+ * This function implements struct &drm_plane_helper_funcs.end_fb_access. It
+ * undoes all effects of drm_gem_begin_shadow_fb_access() in reverse order.
*
- * See drm_gem_prepare_shadow_fb() for more information.
+ * See drm_gem_begin_shadow_fb_access() for more information.
*/
-void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state)
+void drm_gem_end_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
@@ -411,46 +406,45 @@ void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *
drm_gem_fb_vunmap(fb, shadow_plane_state->map);
}
-EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb);
+EXPORT_SYMBOL(drm_gem_end_shadow_fb_access);
/**
- * drm_gem_simple_kms_prepare_shadow_fb - prepares shadow framebuffers
+ * drm_gem_simple_kms_begin_shadow_fb_access - prepares shadow framebuffers for CPU access
* @pipe: the simple display pipe
* @plane_state: the plane state of type struct drm_shadow_plane_state
*
- * This function implements struct drm_simple_display_funcs.prepare_fb. It
- * maps all buffer objects of the plane's framebuffer into kernel address
- * space and stores them in struct drm_shadow_plane_state.map. The
- * framebuffer will be synchronized as part of the atomic commit.
+ * This function implements struct drm_simple_display_funcs.begin_fb_access.
*
- * See drm_gem_simple_kms_cleanup_shadow_fb() for cleanup.
+ * See drm_gem_begin_shadow_fb_access() for details and
+ * drm_gem_simple_kms_cleanup_shadow_fb() for cleanup.
*
* Returns:
* 0 on success, or a negative errno code otherwise.
*/
-int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state)
+int drm_gem_simple_kms_begin_shadow_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
{
- return drm_gem_prepare_shadow_fb(&pipe->plane, plane_state);
+ return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state);
}
-EXPORT_SYMBOL(drm_gem_simple_kms_prepare_shadow_fb);
+EXPORT_SYMBOL(drm_gem_simple_kms_begin_shadow_fb_access);
/**
- * drm_gem_simple_kms_cleanup_shadow_fb - releases shadow framebuffers
+ * drm_gem_simple_kms_end_shadow_fb_access - releases shadow framebuffers from CPU access
* @pipe: the simple display pipe
* @plane_state: the plane state of type struct drm_shadow_plane_state
*
- * This function implements struct drm_simple_display_funcs.cleanup_fb.
- * This function unmaps all buffer objects of the plane's framebuffer.
+ * This function implements struct drm_simple_display_funcs.end_fb_access.
+ * It undoes all effects of drm_gem_simple_kms_begin_shadow_fb_access() in
+ * reverse order.
*
- * See drm_gem_simple_kms_prepare_shadow_fb().
+ * See drm_gem_simple_kms_begin_shadow_fb_access().
*/
-void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state)
+void drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
{
- drm_gem_cleanup_shadow_fb(&pipe->plane, plane_state);
+ drm_gem_end_shadow_fb_access(&pipe->plane, plane_state);
}
-EXPORT_SYMBOL(drm_gem_simple_kms_cleanup_shadow_fb);
+EXPORT_SYMBOL(drm_gem_simple_kms_end_shadow_fb_access);
/**
* drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane
diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c
index f6901ff97bbb..1e658c448366 100644
--- a/drivers/gpu/drm/drm_gem_dma_helper.c
+++ b/drivers/gpu/drm/drm_gem_dma_helper.c
@@ -230,7 +230,7 @@ void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj)
if (gem_obj->import_attach) {
if (dma_obj->vaddr)
- dma_buf_vunmap(gem_obj->import_attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(gem_obj->import_attach->dmabuf, &map);
drm_prime_gem_destroy(gem_obj, dma_obj->sgt);
} else if (dma_obj->vaddr) {
if (dma_obj->map_noncoherent)
@@ -581,7 +581,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev,
struct iosys_map map;
int ret;
- ret = dma_buf_vmap(attach->dmabuf, &map);
+ ret = dma_buf_vmap_unlocked(attach->dmabuf, &map);
if (ret) {
DRM_ERROR("Failed to vmap PRIME buffer\n");
return ERR_PTR(ret);
@@ -589,7 +589,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev,
obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt);
if (IS_ERR(obj)) {
- dma_buf_vunmap(attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(attach->dmabuf, &map);
return obj;
}
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 880a4975507f..e93533b86037 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <drm/drm_damage_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
@@ -354,7 +353,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
ret = -EINVAL;
goto err_drm_gem_vunmap;
}
- ret = drm_gem_vmap(obj, &map[i]);
+ ret = drm_gem_vmap_unlocked(obj, &map[i]);
if (ret)
goto err_drm_gem_vunmap;
}
@@ -376,7 +375,7 @@ err_drm_gem_vunmap:
obj = drm_gem_fb_get_obj(fb, i);
if (!obj)
continue;
- drm_gem_vunmap(obj, &map[i]);
+ drm_gem_vunmap_unlocked(obj, &map[i]);
}
return ret;
}
@@ -403,7 +402,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
continue;
if (iosys_map_is_null(&map[i]))
continue;
- drm_gem_vunmap(obj, &map[i]);
+ drm_gem_vunmap_unlocked(obj, &map[i]);
}
}
EXPORT_SYMBOL(drm_gem_fb_vunmap);
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 35138f8a375c..b602cd72a120 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -571,12 +571,20 @@ static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
- int ret;
WARN_ON(shmem->base.import_attach);
- ret = drm_gem_shmem_get_pages(shmem);
- WARN_ON_ONCE(ret != 0);
+ mutex_lock(&shmem->pages_lock);
+
+ /*
+ * We should have already pinned the pages when the buffer was first
+ * mmap'd, vm_open() just grabs an additional reference for the new
+ * mm the vma is getting copied into (ie. on fork()).
+ */
+ if (!WARN_ON_ONCE(!shmem->pages_use_count))
+ shmem->pages_use_count++;
+
+ mutex_unlock(&shmem->pages_lock);
drm_gem_vm_open(vma);
}
@@ -622,10 +630,8 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
}
ret = drm_gem_shmem_get_pages(shmem);
- if (ret) {
- drm_gem_vm_close(vma);
+ if (ret)
return ret;
- }
vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c
index e5fc875990c4..d5962a34c01d 100644
--- a/drivers/gpu/drm/drm_gem_ttm_helper.c
+++ b/drivers/gpu/drm/drm_gem_ttm_helper.c
@@ -64,13 +64,8 @@ int drm_gem_ttm_vmap(struct drm_gem_object *gem,
struct iosys_map *map)
{
struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
- int ret;
-
- dma_resv_lock(gem->resv, NULL);
- ret = ttm_bo_vmap(bo, map);
- dma_resv_unlock(gem->resv);
- return ret;
+ return ttm_bo_vmap(bo, map);
}
EXPORT_SYMBOL(drm_gem_ttm_vmap);
@@ -87,9 +82,7 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem,
{
struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
- dma_resv_lock(gem->resv, NULL);
ttm_bo_vunmap(bo, map);
- dma_resv_unlock(gem->resv);
}
EXPORT_SYMBOL(drm_gem_ttm_vunmap);
diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c
index 125160b534be..b6c7e3803bb3 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -433,25 +433,19 @@ int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map)
{
int ret;
- ret = ttm_bo_reserve(&gbo->bo, true, false, NULL);
- if (ret)
- return ret;
+ dma_resv_assert_held(gbo->bo.base.resv);
ret = drm_gem_vram_pin_locked(gbo, 0);
if (ret)
- goto err_ttm_bo_unreserve;
+ return ret;
ret = drm_gem_vram_kmap_locked(gbo, map);
if (ret)
goto err_drm_gem_vram_unpin_locked;
- ttm_bo_unreserve(&gbo->bo);
-
return 0;
err_drm_gem_vram_unpin_locked:
drm_gem_vram_unpin_locked(gbo);
-err_ttm_bo_unreserve:
- ttm_bo_unreserve(&gbo->bo);
return ret;
}
EXPORT_SYMBOL(drm_gem_vram_vmap);
@@ -467,16 +461,10 @@ EXPORT_SYMBOL(drm_gem_vram_vmap);
void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo,
struct iosys_map *map)
{
- int ret;
-
- ret = ttm_bo_reserve(&gbo->bo, false, false, NULL);
- if (WARN_ONCE(ret, "ttm_bo_reserve_failed(): ret=%d\n", ret))
- return;
+ dma_resv_assert_held(gbo->bo.base.resv);
drm_gem_vram_kunmap_locked(gbo, map);
drm_gem_vram_unpin_locked(gbo);
-
- ttm_bo_unreserve(&gbo->bo);
}
EXPORT_SYMBOL(drm_gem_vram_vunmap);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 7bb98e6a446d..5ea5e260118c 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -104,7 +104,8 @@ static inline void drm_vblank_flush_worker(struct drm_vblank_crtc *vblank)
static inline void drm_vblank_destroy_worker(struct drm_vblank_crtc *vblank)
{
- kthread_destroy_worker(vblank->worker);
+ if (vblank->worker)
+ kthread_destroy_worker(vblank->worker);
}
int drm_vblank_worker_init(struct drm_vblank_crtc *vblank);
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 3ec02748d56f..497ef4b6a90a 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -606,7 +606,7 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
/*
- * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
+ * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of
* the payload in a long packet transmitted from the peripheral back to the
* host processor
* @dsi: DSI peripheral device
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 939d621c9ad4..688c8afe0bf1 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
count = 0;
connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
drm_for_each_connector_iter(connector, &conn_iter) {
- if (connector->registration_state != DRM_CONNECTOR_REGISTERED)
- continue;
-
/* only expose writeback connectors if userspace understands them */
if (!file_priv->writeback_connectors &&
(connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 304004fb80aa..3c8034a8c27b 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1750,11 +1750,78 @@ static int drm_mode_parse_cmdline_options(const char *str,
return 0;
}
-static const char * const drm_named_modes_whitelist[] = {
- "NTSC",
- "PAL",
+struct drm_named_mode {
+ const char *name;
+ unsigned int pixel_clock_khz;
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int flags;
+};
+
+#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \
+ { \
+ .name = _name, \
+ .pixel_clock_khz = _pclk, \
+ .xres = _x, \
+ .yres = _y, \
+ .flags = _flags, \
+ }
+
+static const struct drm_named_mode drm_named_modes[] = {
+ NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
+ NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
};
+static int drm_mode_parse_cmdline_named_mode(const char *name,
+ unsigned int name_end,
+ struct drm_cmdline_mode *cmdline_mode)
+{
+ unsigned int i;
+
+ if (!name_end)
+ return 0;
+
+ /* If the name starts with a digit, it's not a named mode */
+ if (isdigit(name[0]))
+ return 0;
+
+ /*
+ * If there's an equal sign in the name, the command-line
+ * contains only an option and no mode.
+ */
+ if (strnchr(name, name_end, '='))
+ return 0;
+
+ /* The connection status extras can be set without a mode. */
+ if (name_end == 1 &&
+ (name[0] == 'd' || name[0] == 'D' || name[0] == 'e'))
+ return 0;
+
+ /*
+ * We're sure we're a named mode at this point, iterate over the
+ * list of modes we're aware of.
+ */
+ for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) {
+ const struct drm_named_mode *mode = &drm_named_modes[i];
+ int ret;
+
+ ret = str_has_prefix(name, mode->name);
+ if (ret != name_end)
+ continue;
+
+ strcpy(cmdline_mode->name, mode->name);
+ cmdline_mode->pixel_clock = mode->pixel_clock_khz;
+ cmdline_mode->xres = mode->xres;
+ cmdline_mode->yres = mode->yres;
+ cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+ cmdline_mode->specified = true;
+
+ return 1;
+ }
+
+ return -EINVAL;
+}
+
/**
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector
* @mode_option: optional per connector mode option
@@ -1791,7 +1858,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
const char *options_ptr = NULL;
char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
- int i, len, ret;
+ int len, ret;
memset(mode, 0, sizeof(*mode));
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
@@ -1801,20 +1868,24 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
name = mode_option;
+ /* Locate the start of named options */
+ options_ptr = strchr(name, ',');
+ if (options_ptr)
+ options_off = options_ptr - name;
+ else
+ options_off = strlen(name);
+
/* Try to locate the bpp and refresh specifiers, if any */
- bpp_ptr = strchr(name, '-');
+ bpp_ptr = strnchr(name, options_off, '-');
+ while (bpp_ptr && !isdigit(bpp_ptr[1]))
+ bpp_ptr = strnchr(bpp_ptr + 1, options_off, '-');
if (bpp_ptr)
bpp_off = bpp_ptr - name;
- refresh_ptr = strchr(name, '@');
+ refresh_ptr = strnchr(name, options_off, '@');
if (refresh_ptr)
refresh_off = refresh_ptr - name;
- /* Locate the start of named options */
- options_ptr = strchr(name, ',');
- if (options_ptr)
- options_off = options_ptr - name;
-
/* Locate the end of the name / resolution, and parse it */
if (bpp_ptr) {
mode_end = bpp_off;
@@ -1828,18 +1899,19 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
parse_extras = true;
}
- /* First check for a named mode */
- for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
- ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
- if (ret == mode_end) {
- if (refresh_ptr)
- return false; /* named + refresh is invalid */
+ if (!mode_end)
+ return false;
- strcpy(mode->name, drm_named_modes_whitelist[i]);
- mode->specified = true;
- break;
- }
- }
+ ret = drm_mode_parse_cmdline_named_mode(name, mode_end, mode);
+ if (ret < 0)
+ return false;
+
+ /*
+ * Having a mode that starts by a letter (and thus is named) and
+ * an at-sign (used to specify a refresh rate) is disallowed.
+ */
+ if (ret && refresh_ptr)
+ return false;
/* No named mode? Check for a normal mode argument, e.g. 1024x768 */
if (!mode->specified && isdigit(name[0])) {
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index 8a0c0e0bb5bd..52d8800a8ab8 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -134,6 +134,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
},
.driver_data = (void *)&lcd800x1280_rightside_up,
+ }, { /* Acer Switch V 10 (SW5-017) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
+ },
+ .driver_data = (void *)&lcd800x1280_rightside_up,
}, { /* Anbernic Win600 */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic"),
@@ -319,6 +325,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
+ }, { /* Nanote UMPC-01 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"),
+ },
+ .driver_data = (void *)&lcd1200x1920_rightside_up,
}, { /* OneGX1 Pro */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"),
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 865bd999b187..ba6a9136a065 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -298,7 +298,9 @@ EXPORT_SYMBOL(drm_plane_helper_destroy);
* scale and positioning are not expected to change since the plane is always
* a fullscreen scanout buffer.
*
- * This is often the case for the primary plane of simple framebuffers.
+ * This is often the case for the primary plane of simple framebuffers. See
+ * also drm_crtc_helper_atomic_check() for the respective CRTC-state check
+ * helper function.
*
* RETURNS:
* Zero on success, or an errno code otherwise.
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index eb09e86044c6..f924b8b4ab6b 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -781,6 +781,8 @@ int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev;
+ dma_resv_assert_held(dma_buf->resv);
+
if (!dev->driver->gem_prime_mmap)
return -ENOSYS;
@@ -940,7 +942,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
get_dma_buf(dma_buf);
- sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto fail_detach;
@@ -958,7 +960,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
return obj;
fail_unmap:
- dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL);
fail_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
@@ -1056,7 +1058,7 @@ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
attach = obj->import_attach;
if (sg)
- dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(attach, sg, DMA_BIDIRECTIONAL);
dma_buf = attach->dmabuf;
dma_buf_detach(attach->dmabuf, attach);
/* remove the reference */
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 69b0b2b9cc1c..bcd9611dabfd 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -36,7 +36,6 @@
#include <drm/drm_client.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
@@ -367,7 +366,7 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector)
* override/firmware EDID.
*/
if (count == 0 && connector->status == connector_status_connected)
- count = drm_add_override_edid_modes(connector);
+ count = drm_edid_override_connector_update(connector);
return count;
}
diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c
index 0460e874896e..85c79a38c13a 100644
--- a/drivers/gpu/drm/drm_rect.c
+++ b/drivers/gpu/drm/drm_rect.c
@@ -80,7 +80,7 @@ static u32 clip_scaled(int src, int dst, int *clip)
* @dst: destination window rectangle
* @clip: clip rectangle
*
- * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
+ * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by
* the corresponding amounts, retaining the vertical and horizontal scaling
* factors from @src to @dst.
*
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index e9f782119d3d..3ef420ec4534 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -102,10 +102,14 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
int ret;
- ret = drm_atomic_helper_check_crtc_state(crtc_state, false);
+ if (!crtc_state->enable)
+ goto out;
+
+ ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
if (ret)
return ret;
+out:
return drm_atomic_add_affected_planes(state, crtc);
}
@@ -281,6 +285,30 @@ static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
pipe->funcs->cleanup_fb(pipe, state);
}
+static int drm_simple_kms_plane_begin_fb_access(struct drm_plane *plane,
+ struct drm_plane_state *new_plane_state)
+{
+ struct drm_simple_display_pipe *pipe;
+
+ pipe = container_of(plane, struct drm_simple_display_pipe, plane);
+ if (!pipe->funcs || !pipe->funcs->begin_fb_access)
+ return 0;
+
+ return pipe->funcs->begin_fb_access(pipe, new_plane_state);
+}
+
+static void drm_simple_kms_plane_end_fb_access(struct drm_plane *plane,
+ struct drm_plane_state *new_plane_state)
+{
+ struct drm_simple_display_pipe *pipe;
+
+ pipe = container_of(plane, struct drm_simple_display_pipe, plane);
+ if (!pipe->funcs || !pipe->funcs->end_fb_access)
+ return;
+
+ pipe->funcs->end_fb_access(pipe, new_plane_state);
+}
+
static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
uint32_t format,
uint64_t modifier)
@@ -291,6 +319,8 @@ static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
.prepare_fb = drm_simple_kms_plane_prepare_fb,
.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
+ .begin_fb_access = drm_simple_kms_plane_begin_fb_access,
+ .end_fb_access = drm_simple_kms_plane_end_fb_access,
.atomic_check = drm_simple_kms_plane_atomic_check,
.atomic_update = drm_simple_kms_plane_atomic_update,
};
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 430e00b16eec..b8da978d85bb 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -19,6 +19,7 @@
#include <linux/kdev_t.h>
#include <linux/slab.h>
+#include <drm/drm_accel.h>
#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
@@ -471,19 +472,26 @@ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
struct device *kdev;
int r;
- if (minor->type == DRM_MINOR_RENDER)
- minor_str = "renderD%d";
- else
- minor_str = "card%d";
-
kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
if (!kdev)
return ERR_PTR(-ENOMEM);
device_initialize(kdev);
- kdev->devt = MKDEV(DRM_MAJOR, minor->index);
- kdev->class = drm_class;
- kdev->type = &drm_sysfs_device_minor;
+
+ if (minor->type == DRM_MINOR_ACCEL) {
+ minor_str = "accel%d";
+ accel_set_device_instance_params(kdev, minor->index);
+ } else {
+ if (minor->type == DRM_MINOR_RENDER)
+ minor_str = "renderD%d";
+ else
+ minor_str = "card%d";
+
+ kdev->devt = MKDEV(DRM_MAJOR, minor->index);
+ kdev->class = drm_class;
+ kdev->type = &drm_sysfs_device_minor;
+ }
+
kdev->parent = minor->dev->dev;
kdev->release = drm_sysfs_release;
dev_set_drvdata(kdev, minor);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index f32f4771dada..2bb4c25565dc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -6,13 +6,14 @@
#ifndef __ETNAVIV_DRV_H__
#define __ETNAVIV_DRV_H__
+#include <linux/io.h>
#include <linux/list.h>
#include <linux/mm_types.h>
#include <linux/sizes.h>
#include <linux/time64.h>
#include <linux/types.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/etnaviv_drm.h>
#include <drm/gpu_scheduler.h>
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
index f418e0b75772..44b5f3c35aab 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -83,10 +83,15 @@ static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
{
struct etnaviv_dump_registers *reg = iter->data;
unsigned int i;
+ u32 read_addr;
for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
+ read_addr = etnaviv_dump_registers[i];
+ if (read_addr >= VIVS_PM_POWER_CONTROLS &&
+ read_addr <= VIVS_PM_PULSE_EATER)
+ read_addr = gpu_fix_power_address(gpu, read_addr);
reg->reg = cpu_to_le32(etnaviv_dump_registers[i]);
- reg->value = cpu_to_le32(gpu_read(gpu, etnaviv_dump_registers[i]));
+ reg->value = cpu_to_le32(gpu_read(gpu, read_addr));
}
etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index cc386f8a7116..68e4446a94ad 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -130,7 +130,7 @@ static int etnaviv_gem_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
{
pgprot_t vm_page_prot;
- vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
vm_page_prot = vm_get_page_prot(vma->vm_flags);
@@ -165,7 +165,8 @@ static vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf)
struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
- struct page **pages, *page;
+ struct page **pages;
+ unsigned long pfn;
pgoff_t pgoff;
int err;
@@ -189,12 +190,12 @@ static vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf)
/* We don't use vmf->pgoff since that has the fake offset: */
pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
- page = pages[pgoff];
+ pfn = page_to_pfn(pages[pgoff]);
VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address,
- page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
+ pfn, pfn << PAGE_SHIFT);
- return vmf_insert_page(vma, vmf->address, page);
+ return vmf_insert_pfn(vma, vmf->address, pfn);
}
int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
@@ -258,7 +259,12 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
if (mapping->use == 0) {
mutex_lock(&mmu_context->lock);
if (mapping->context == mmu_context)
- mapping->use += 1;
+ if (va && mapping->iova != va) {
+ etnaviv_iommu_reap_mapping(mapping);
+ mapping = NULL;
+ } else {
+ mapping->use += 1;
+ }
else
mapping = NULL;
mutex_unlock(&mmu_context->lock);
@@ -504,7 +510,6 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
kfree(mapping);
}
- drm_gem_free_mmap_offset(obj);
etnaviv_obj->ops->release(etnaviv_obj);
drm_gem_object_release(obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index 63688e6e4580..baa81cbf701a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -96,6 +96,7 @@ struct etnaviv_gem_submit {
int out_fence_id;
struct list_head node; /* GPU active submit list */
struct etnaviv_cmdbuf cmdbuf;
+ struct pid *pid; /* submitting process */
bool runtime_resumed;
u32 exec_state;
u32 flags;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 3fa2da149639..7031db145a77 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -65,7 +65,7 @@ static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj)
struct iosys_map map = IOSYS_MAP_INIT_VADDR(etnaviv_obj->vaddr);
if (etnaviv_obj->vaddr)
- dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(etnaviv_obj->base.import_attach->dmabuf, &map);
/* Don't drop the pages for imported dmabuf, as they are not
* ours, just free the array we allocated:
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 1ac916b24891..1491159d0d20 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -399,6 +399,9 @@ static void submit_cleanup(struct kref *kref)
mutex_unlock(&submit->gpu->fence_lock);
dma_fence_put(submit->out_fence);
}
+
+ put_pid(submit->pid);
+
kfree(submit->pmrs);
kfree(submit);
}
@@ -422,6 +425,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
struct sync_file *sync_file = NULL;
struct ww_acquire_ctx ticket;
int out_fence_fd = -1;
+ struct pid *pid = get_pid(task_pid(current));
void *stream;
int ret;
@@ -519,6 +523,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
goto err_submit_ww_acquire;
}
+ submit->pid = pid;
+
ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &submit->cmdbuf,
ALIGN(args->stream_size, 8) + 8);
if (ret)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 37018bc55810..51320eeebfcf 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -416,6 +416,12 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
if (gpu->identity.model == chipModel_GC700)
gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
+ /* These models/revisions don't have the 2D pipe bit */
+ if ((gpu->identity.model == chipModel_GC500 &&
+ gpu->identity.revision <= 2) ||
+ gpu->identity.model == chipModel_GC300)
+ gpu->identity.features |= chipFeatures_PIPE_2D;
+
if ((gpu->identity.model == chipModel_GC500 &&
gpu->identity.revision < 2) ||
(gpu->identity.model == chipModel_GC300 &&
@@ -449,8 +455,9 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5);
}
- /* GC600 idle register reports zero bits where modules aren't present */
- if (gpu->identity.model == chipModel_GC600)
+ /* GC600/300 idle register reports zero bits where modules aren't present */
+ if (gpu->identity.model == chipModel_GC600 ||
+ gpu->identity.model == chipModel_GC300)
gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
VIVS_HI_IDLE_STATE_RA |
VIVS_HI_IDLE_STATE_SE |
@@ -583,7 +590,7 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu)
u32 pmc, ppc;
/* enable clock gating */
- ppc = gpu_read(gpu, VIVS_PM_POWER_CONTROLS);
+ ppc = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS);
ppc |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING;
/* Disable stall module clock gating for 4.3.0.1 and 4.3.0.2 revs */
@@ -591,9 +598,9 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu)
gpu->identity.revision == 0x4302)
ppc |= VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING;
- gpu_write(gpu, VIVS_PM_POWER_CONTROLS, ppc);
+ gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, ppc);
- pmc = gpu_read(gpu, VIVS_PM_MODULE_CONTROLS);
+ pmc = gpu_read_power(gpu, VIVS_PM_MODULE_CONTROLS);
/* Disable PA clock gating for GC400+ without bugfix except for GC420 */
if (gpu->identity.model >= chipModel_GC400 &&
@@ -616,19 +623,20 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu)
/* Disable TX clock gating on affected core revisions. */
if (etnaviv_is_model_rev(gpu, GC4000, 0x5222) ||
- etnaviv_is_model_rev(gpu, GC2000, 0x5108))
+ etnaviv_is_model_rev(gpu, GC2000, 0x5108) ||
+ etnaviv_is_model_rev(gpu, GC2000, 0x6202) ||
+ etnaviv_is_model_rev(gpu, GC2000, 0x6203))
pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX;
- /* Disable SE, RA and TX clock gating on affected core revisions. */
+ /* Disable SE and RA clock gating on affected core revisions. */
if (etnaviv_is_model_rev(gpu, GC7000, 0x6202))
pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_SE |
- VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA |
- VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX;
+ VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA;
pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ;
pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ;
- gpu_write(gpu, VIVS_PM_MODULE_CONTROLS, pmc);
+ gpu_write_power(gpu, VIVS_PM_MODULE_CONTROLS, pmc);
}
void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
@@ -688,11 +696,11 @@ static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu)
(gpu->identity.features & chipFeatures_PIPE_3D))
{
/* Performance fix: disable internal DFS */
- pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER);
+ pulse_eater = gpu_read_power(gpu, VIVS_PM_PULSE_EATER);
pulse_eater |= BIT(18);
}
- gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater);
+ gpu_write_power(gpu, VIVS_PM_PULSE_EATER, pulse_eater);
}
static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
@@ -1045,12 +1053,28 @@ pm_put:
}
#endif
-void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu)
+void etnaviv_gpu_recover_hang(struct etnaviv_gem_submit *submit)
{
+ struct etnaviv_gpu *gpu = submit->gpu;
+ char *comm = NULL, *cmd = NULL;
+ struct task_struct *task;
unsigned int i;
dev_err(gpu->dev, "recover hung GPU!\n");
+ task = get_pid_task(submit->pid, PIDTYPE_PID);
+ if (task) {
+ comm = kstrdup(task->comm, GFP_KERNEL);
+ cmd = kstrdup_quotable_cmdline(task, GFP_KERNEL);
+ put_task_struct(task);
+ }
+
+ if (comm && cmd)
+ dev_err(gpu->dev, "offending task: %s (%s)\n", comm, cmd);
+
+ kfree(cmd);
+ kfree(comm);
+
if (pm_runtime_get_sync(gpu->dev) < 0)
goto pm_put;
@@ -1294,9 +1318,9 @@ static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu,
u32 val;
/* disable clock gating */
- val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS);
+ val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS);
val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING;
- gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val);
+ gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val);
/* enable debug register */
val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
@@ -1327,9 +1351,9 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu,
gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val);
/* enable clock gating */
- val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS);
+ val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS);
val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING;
- gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val);
+ gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val);
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 85eddd492774..f1204b070fb8 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -10,6 +10,7 @@
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "etnaviv_drv.h"
+#include "common.xml.h"
struct etnaviv_gem_submit;
struct etnaviv_vram_mapping;
@@ -159,6 +160,26 @@ static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg)
return readl(gpu->mmio + reg);
}
+static inline u32 gpu_fix_power_address(struct etnaviv_gpu *gpu, u32 reg)
+{
+ /* Power registers in GC300 < 2.0 are offset by 0x100 */
+ if (gpu->identity.model == chipModel_GC300 &&
+ gpu->identity.revision < 0x2000)
+ reg += 0x100;
+
+ return reg;
+}
+
+static inline void gpu_write_power(struct etnaviv_gpu *gpu, u32 reg, u32 data)
+{
+ writel(data, gpu->mmio + gpu_fix_power_address(gpu, reg));
+}
+
+static inline u32 gpu_read_power(struct etnaviv_gpu *gpu, u32 reg)
+{
+ return readl(gpu->mmio + gpu_fix_power_address(gpu, reg));
+}
+
int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
@@ -168,7 +189,7 @@ bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu);
int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
#endif
-void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu);
+void etnaviv_gpu_recover_hang(struct etnaviv_gem_submit *submit);
void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
u32 fence, struct drm_etnaviv_timespec *timeout);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
index f2fc645c7956..57f334e24189 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
@@ -70,6 +70,37 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
},
{
.model = 0x7000,
+ .revision = 0x6203,
+ .product_id = 0x70003,
+ .customer_id = 0x4,
+ .eco_id = 0,
+ .stream_count = 16,
+ .register_max = 64,
+ .thread_count = 512,
+ .shader_core_count = 2,
+ .vertex_cache_size = 16,
+ .vertex_output_buffer_size = 1024,
+ .pixel_pipes = 1,
+ .instruction_count = 512,
+ .num_constants = 320,
+ .buffer_size = 0,
+ .varyings_count = 16,
+ .features = 0xe0287c8d,
+ .minor_features0 = 0xc1589eff,
+ .minor_features1 = 0xfefbfad9,
+ .minor_features2 = 0xeb9d4fbf,
+ .minor_features3 = 0xedfffced,
+ .minor_features4 = 0xdb0dafc7,
+ .minor_features5 = 0x3b5ac333,
+ .minor_features6 = 0xfcce6000,
+ .minor_features7 = 0xfffbfa6f,
+ .minor_features8 = 0x00e10ef3,
+ .minor_features9 = 0x00c8003c,
+ .minor_features10 = 0x00004040,
+ .minor_features11 = 0x00000024,
+ },
+ {
+ .model = 0x7000,
.revision = 0x6204,
.product_id = ~0U,
.customer_id = ~0U,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index dc1aa738c4f1..67bdce5326c6 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -80,10 +80,10 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
return -EINVAL;
for_each_sgtable_dma_sg(sgt, sg, i) {
- u32 pa = sg_dma_address(sg) - sg->offset;
+ phys_addr_t pa = sg_dma_address(sg) - sg->offset;
size_t bytes = sg_dma_len(sg) + sg->offset;
- VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
+ VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes);
ret = etnaviv_context_map(context, da, pa, bytes, prot);
if (ret)
@@ -135,6 +135,19 @@ static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu_context *context,
drm_mm_remove_node(&mapping->vram_node);
}
+void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping)
+{
+ struct etnaviv_iommu_context *context = mapping->context;
+
+ lockdep_assert_held(&context->lock);
+ WARN_ON(mapping->use);
+
+ etnaviv_iommu_remove_mapping(context, mapping);
+ etnaviv_iommu_context_put(mapping->context);
+ mapping->context = NULL;
+ list_del_init(&mapping->mmu_node);
+}
+
static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context,
struct drm_mm_node *node, size_t size)
{
@@ -202,10 +215,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context,
* this mapping.
*/
list_for_each_entry_safe(m, n, &list, scan_node) {
- etnaviv_iommu_remove_mapping(context, m);
- etnaviv_iommu_context_put(m->context);
- m->context = NULL;
- list_del_init(&m->mmu_node);
+ etnaviv_iommu_reap_mapping(m);
list_del_init(&m->scan_node);
}
@@ -257,10 +267,7 @@ static int etnaviv_iommu_insert_exact(struct etnaviv_iommu_context *context,
}
list_for_each_entry_safe(m, n, &scan_list, scan_node) {
- etnaviv_iommu_remove_mapping(context, m);
- etnaviv_iommu_context_put(m->context);
- m->context = NULL;
- list_del_init(&m->mmu_node);
+ etnaviv_iommu_reap_mapping(m);
list_del_init(&m->scan_node);
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
index e4a0b7d09c2e..c01a147f0dfd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
@@ -91,6 +91,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context,
struct etnaviv_vram_mapping *mapping, u64 va);
void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context,
struct etnaviv_vram_mapping *mapping);
+void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping);
int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu_context *ctx,
struct etnaviv_vram_mapping *mapping,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index 72e2553fbc98..d29f467eee13 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -67,7 +67,7 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job
/* get the GPU back into the init state */
etnaviv_core_dump(submit);
- etnaviv_gpu_recover_hang(gpu);
+ etnaviv_gpu_recover_hang(submit);
drm_sched_resubmit_jobs(&gpu->sched);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 767afd2bfa82..55c92372fca0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -49,6 +49,8 @@ static const struct fb_ops exynos_drm_fb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_mmap = exynos_drm_fb_mmap,
+ .fb_read = drm_fb_helper_cfb_read,
+ .fb_write = drm_fb_helper_cfb_write,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
@@ -63,7 +65,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
unsigned int size = fb->width * fb->height * fb->format->cpp[0];
unsigned long offset;
- fbi = drm_fb_helper_alloc_fbi(helper);
+ fbi = drm_fb_helper_alloc_info(helper);
if (IS_ERR(fbi)) {
DRM_DEV_ERROR(to_dma_dev(helper->dev),
"failed to allocate fb info.\n");
@@ -201,7 +203,7 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
drm_framebuffer_remove(fb);
}
- drm_fb_helper_unregister_fbi(fb_helper);
+ drm_fb_helper_unregister_info(fb_helper);
drm_fb_helper_fini(fb_helper);
}
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index b4acc3422ba4..8579c7629f5e 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -20,7 +20,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index aa3ecf771fd3..8d5a37b8f110 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -147,6 +147,8 @@ static const struct fb_ops psbfb_unaccel_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_setcolreg = psbfb_setcolreg,
+ .fb_read = drm_fb_helper_cfb_read,
+ .fb_write = drm_fb_helper_cfb_write,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
@@ -268,7 +270,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper,
memset(dev_priv->vram_addr + backing->offset, 0, size);
- info = drm_fb_helper_alloc_fbi(fb_helper);
+ info = drm_fb_helper_alloc_info(fb_helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto err_drm_gem_object_put;
@@ -286,7 +288,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper,
info->fbops = &psbfb_unaccel_ops;
- info->fix.smem_start = dev->mode_config.fb_base;
+ info->fix.smem_start = dev_priv->fb_base;
info->fix.smem_len = size;
info->fix.ywrapstep = 0;
info->fix.ypanstep = 0;
@@ -296,7 +298,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper,
info->screen_size = size;
if (dev_priv->gtt.stolen_size) {
- info->apertures->ranges[0].base = dev->mode_config.fb_base;
+ info->apertures->ranges[0].base = dev_priv->fb_base;
info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
}
@@ -383,7 +385,7 @@ static int psb_fbdev_destroy(struct drm_device *dev,
{
struct drm_framebuffer *fb = fb_helper->fb;
- drm_fb_helper_unregister_fbi(fb_helper);
+ drm_fb_helper_unregister_info(fb_helper);
drm_fb_helper_fini(fb_helper);
drm_framebuffer_unregister_private(fb);
@@ -527,7 +529,7 @@ void psb_modeset_init(struct drm_device *dev)
/* set memory base */
/* Oaktrail and Poulsbo should use BAR 2*/
- pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev->mode_config.fb_base));
+ pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev_priv->fb_base));
/* num pipes is 2 for PSB but 1 for Mrst */
for (i = 0; i < dev_priv->num_pipe; i++)
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index ae544b69fc47..a5df6d2f2cab 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -523,6 +523,7 @@ struct drm_psb_private {
uint32_t blc_adj2;
struct drm_fb_helper *fb_helper;
+ resource_size_t fb_base;
bool dsr_enable;
u32 dsr_fb_update;
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index d0addd478815..fa636206f232 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -355,7 +355,7 @@ static void gud_connector_reset(struct drm_connector *connector)
drm_atomic_helper_connector_reset(connector);
connector->state->tv = gconn->initial_tv_state;
/* Set margins from command line */
- drm_atomic_helper_connector_tv_reset(connector);
+ drm_atomic_helper_connector_tv_margins_reset(connector);
if (gconn->initial_brightness >= 0)
connector->state->tv.brightness = gconn->initial_brightness;
}
diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index 8d1630b8edac..d57dab104358 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -18,7 +18,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index fe4269c5aa0a..22053c613644 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -17,6 +17,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_managed.h>
@@ -105,7 +106,6 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
dev->mode_config.max_width = 1920;
dev->mode_config.max_height = 1200;
- dev->mode_config.fb_base = priv->fb_base;
dev->mode_config.preferred_depth = 32;
dev->mode_config.prefer_shadow = 1;
@@ -212,7 +212,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv)
{
struct drm_device *dev = &priv->dev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
- resource_size_t addr, size, ioaddr, iosize;
+ resource_size_t ioaddr, iosize;
ioaddr = pci_resource_start(pdev, 1);
iosize = pci_resource_len(pdev, 1);
@@ -222,16 +222,6 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv)
return -ENOMEM;
}
- addr = pci_resource_start(pdev, 0);
- size = pci_resource_len(pdev, 0);
- priv->fb_map = devm_ioremap(dev->dev, addr, size);
- if (!priv->fb_map) {
- drm_err(dev, "Cannot map framebuffer\n");
- return -ENOMEM;
- }
- priv->fb_base = addr;
- priv->fb_size = size;
-
return 0;
}
@@ -271,7 +261,8 @@ static int hibmc_load(struct drm_device *dev)
if (ret)
goto err;
- ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), priv->fb_size);
+ ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
if (ret) {
drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
goto err;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 7d263f4d7078..f957552c6c50 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -19,7 +19,6 @@
#include <linux/i2c.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
struct hibmc_connector {
@@ -32,9 +31,6 @@ struct hibmc_connector {
struct hibmc_drm_private {
/* hw */
void __iomem *mmio;
- void __iomem *fb_map;
- resource_size_t fb_base;
- resource_size_t fb_size;
/* drm */
struct drm_device dev;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index c228091fb0e6..8c6d2ea2a472 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -11,6 +11,8 @@
* Jianhua Li <lijianhua@huawei.com>
*/
+#include <linux/io.h>
+
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index a0d5aa727d58..d9978b79828c 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -658,7 +658,7 @@ static enum drm_mode_status dsi_encoder_mode_valid(struct drm_encoder *encoder,
* reset adj_mode to the mode value each time,
* so we don't adjust the mode twice
*/
- drm_mode_copy(&adj_mode, mode);
+ drm_mode_init(&adj_mode, mode);
crtc_funcs = crtc->helper_private;
if (crtc_funcs && crtc_funcs->mode_fixup)
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 73ee7f25f734..9c5d49bf40c9 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -19,7 +19,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
index ca127ff797f7..427c20ba3404 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
@@ -11,7 +11,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_simple_kms_helper.h>
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 28e732f94bf2..6c6b57298797 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
@@ -8,7 +8,6 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index d444e7fffb54..a14d2896aebb 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1174,6 +1174,8 @@ static int tda998x_audio_codec_init(struct tda998x_priv *priv,
struct hdmi_codec_pdata codec_data = {
.ops = &audio_codec_ops,
.max_i2s_channels = 2,
+ .no_i2s_capture = 1,
+ .no_spdif_capture = 1,
};
if (priv->audio_port_enable[AUDIO_ROUTE_I2S])
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile
index 39328567c200..7cc38d25ee5c 100644
--- a/drivers/gpu/drm/i915/Kconfig.profile
+++ b/drivers/gpu/drm/i915/Kconfig.profile
@@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT
default 640 # milliseconds
help
How long to wait (in milliseconds) for a preemption event to occur
- when submitting a new context via execlists. If the current context
- does not hit an arbitration point and yield to HW before the timer
- expires, the HW will be reset to allow the more important context
- to execute.
+ when submitting a new context. If the current context does not hit
+ an arbitration point and yield to HW before the timer expires, the
+ HW will be reset to allow the more important context to execute.
+
+ This is adjustable via
+ /sys/class/drm/card?/engine/*/preempt_timeout_ms
+
+ May be 0 to disable the timeout.
+
+ The compiled in default may get overridden at driver probe time on
+ certain platforms and certain engines which will be reflected in the
+ sysfs control.
+
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE
+ int "Preempt timeout for compute engines (ms, jiffy granularity)"
+ default 7500 # milliseconds
+ help
+ How long to wait (in milliseconds) for a preemption event to occur
+ when submitting a new context to a compute capable engine. If the
+ current context does not hit an arbitration point and yield to HW
+ before the timer expires, the HW will be reset to allow the more
+ important context to execute.
This is adjustable via
/sys/class/drm/card?/engine/*/preempt_timeout_ms
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index cea00aaca04b..01974b82d205 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -127,9 +127,11 @@ gt-y += \
gt/intel_sseu.o \
gt/intel_sseu_debugfs.o \
gt/intel_timeline.o \
+ gt/intel_wopcm.o \
gt/intel_workarounds.o \
gt/shmem_utils.o \
gt/sysfs_engines.o
+
# x86 intel-gtt module support
gt-$(CONFIG_X86) += gt/intel_ggtt_gmch.o
# autogenerated null render state
@@ -183,8 +185,7 @@ i915-y += \
i915_trace_points.o \
i915_ttm_buddy_manager.o \
i915_vma.o \
- i915_vma_resource.o \
- intel_wopcm.o
+ i915_vma_resource.o
# general-purpose microcontroller (GuC) support
i915-y += gt/uc/intel_uc.o \
@@ -209,6 +210,9 @@ i915-y += gt/uc/intel_uc.o \
# graphics system controller (GSC) support
i915-y += gt/intel_gsc.o
+# graphics hardware monitoring (HWMON) support
+i915-$(CONFIG_HWMON) += i915_hwmon.o
+
# modesetting core code
i915-y += \
display/hsw_ips.o \
@@ -244,6 +248,7 @@ i915-y += \
display/intel_global_state.o \
display/intel_hdcp.o \
display/intel_hotplug.o \
+ display/intel_hti.o \
display/intel_lpe_audio.o \
display/intel_modeset_verify.o \
display/intel_modeset_setup.o \
@@ -310,15 +315,18 @@ i915-y += \
i915-y += i915_perf.o
-# Protected execution platform (PXP) support
-i915-$(CONFIG_DRM_I915_PXP) += \
+# Protected execution platform (PXP) support. Base support is required for HuC
+i915-y += \
pxp/intel_pxp.o \
+ pxp/intel_pxp_tee.o \
+ pxp/intel_pxp_huc.o
+
+i915-$(CONFIG_DRM_I915_PXP) += \
pxp/intel_pxp_cmd.o \
pxp/intel_pxp_debugfs.o \
pxp/intel_pxp_irq.o \
pxp/intel_pxp_pm.o \
- pxp/intel_pxp_session.o \
- pxp/intel_pxp_tee.o
+ pxp/intel_pxp_session.o
# Post-mortem debug and GPU hang state capture
i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index e3e3d27ffb53..3593938dcd87 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -8,6 +8,7 @@
#include <linux/string_helpers.h>
#include "g4x_dp.h"
+#include "i915_reg.h"
#include "intel_audio.h"
#include "intel_backlight.h"
#include "intel_connector.h"
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.h b/drivers/gpu/drm/i915/display/g4x_dp.h
index e1f50263a725..a38b3e1e01d3 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.h
+++ b/drivers/gpu/drm/i915/display/g4x_dp.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
-#include "i915_reg.h"
+#include "i915_reg_defs.h"
enum pipe;
enum port;
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index 2b73f5ff0d02..121caeaa409b 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -6,6 +6,7 @@
*/
#include "g4x_hdmi.h"
+#include "i915_reg.h"
#include "intel_audio.h"
#include "intel_connector.h"
#include "intel_crtc.h"
@@ -78,6 +79,18 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
return ret;
}
+static int g4x_hdmi_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+
+ if (HAS_PCH_SPLIT(i915))
+ crtc_state->has_pch_encoder = true;
+
+ return intel_hdmi_compute_config(encoder, crtc_state, conn_state);
+}
+
static void intel_hdmi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
@@ -543,7 +556,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv,
"HDMI %c", port_name(port));
intel_encoder->hotplug = intel_hdmi_hotplug;
- intel_encoder->compute_config = intel_hdmi_compute_config;
+ intel_encoder->compute_config = g4x_hdmi_compute_config;
if (HAS_PCH_SPLIT(dev_priv)) {
intel_encoder->disable = pch_disable_hdmi;
intel_encoder->post_disable = pch_post_disable_hdmi;
@@ -585,7 +598,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv,
} else {
intel_encoder->pipe_mask = ~0;
}
- intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
+ intel_encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG);
intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
/*
* BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
@@ -593,7 +606,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv,
* only one port anyway, nothing is lost by allowing it.
*/
if (IS_G4X(dev_priv))
- intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
+ intel_encoder->cloneable |= BIT(INTEL_OUTPUT_HDMI);
dig_port->hdmi.hdmi_reg = hdmi_reg;
dig_port->dp.output_reg = INVALID_MMIO_REG;
diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c
index a5be4af792cb..83aa3800245f 100644
--- a/drivers/gpu/drm/i915/display/hsw_ips.c
+++ b/drivers/gpu/drm/i915/display/hsw_ips.c
@@ -104,8 +104,7 @@ static bool hsw_ips_need_disable(struct intel_atomic_state *state,
* Disable IPS before we program the LUT.
*/
if (IS_HASWELL(i915) &&
- (new_crtc_state->uapi.color_mgmt_changed ||
- new_crtc_state->update_pipe) &&
+ intel_crtc_needs_color_update(new_crtc_state) &&
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
return true;
@@ -146,8 +145,7 @@ static bool hsw_ips_need_enable(struct intel_atomic_state *state,
* Re-enable IPS after the LUT has been programmed.
*/
if (IS_HASWELL(i915) &&
- (new_crtc_state->uapi.color_mgmt_changed ||
- new_crtc_state->update_pipe) &&
+ intel_crtc_needs_color_update(new_crtc_state) &&
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
return true;
@@ -155,7 +153,7 @@ static bool hsw_ips_need_enable(struct intel_atomic_state *state,
* We can't read out IPS on broadwell, assume the worst and
* forcibly enable IPS on the first fastset.
*/
- if (new_crtc_state->update_pipe && old_crtc_state->inherited)
+ if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited)
return true;
return !old_crtc_state->ips_enabled;
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c
index 5afbe3e98ee8..ecaeb7dc196b 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.c
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c
@@ -8,6 +8,9 @@
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
+#include "i915_irq.h"
+#include "i915_reg.h"
+#include "i9xx_plane.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
#include "intel_de.h"
@@ -15,7 +18,6 @@
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_sprite.h"
-#include "i9xx_plane.h"
/* Primary plane formats for gen <= 3 */
static const u32 i8xx_primary_formats[] = {
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index ed4d93942dbd..d16b30a2dded 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -29,6 +29,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_mipi_dsi.h>
+#include "i915_reg.h"
#include "icl_dsi.h"
#include "icl_dsi_regs.h"
#include "intel_atomic.h"
@@ -1974,16 +1975,8 @@ static void icl_dsi_add_properties(struct intel_connector *connector)
{
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
- u32 allowed_scalers;
- allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) |
- BIT(DRM_MODE_SCALE_FULLSCREEN) |
- BIT(DRM_MODE_SCALE_CENTER);
-
- drm_connector_attach_scaling_mode_property(&connector->base,
- allowed_scalers);
-
- connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+ intel_attach_scaling_mode_property(&connector->base);
drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector),
@@ -1993,7 +1986,6 @@ static void icl_dsi_add_properties(struct intel_connector *connector)
void icl_dsi_init(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_dsi *intel_dsi;
struct intel_encoder *encoder;
struct intel_connector *intel_connector;
@@ -2018,7 +2010,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
connector = &intel_connector->base;
/* register DSI encoder with DRM subsystem */
- drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs,
+ drm_encoder_init(&dev_priv->drm, &encoder->base, &gen11_dsi_encoder_funcs,
DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
@@ -2042,12 +2034,10 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
encoder->is_clock_enabled = gen11_dsi_is_clock_enabled;
/* register DSI connector with DRM subsystem */
- drm_connector_init(dev, connector, &gen11_dsi_connector_funcs,
+ drm_connector_init(&dev_priv->drm, connector, &gen11_dsi_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
intel_connector->get_hw_state = intel_connector_get_hw_state;
/* attach connector to encoder */
@@ -2055,9 +2045,9 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL, NULL);
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
drm_err(&dev_priv->drm, "DSI fixed mode info missing\n");
diff --git a/drivers/gpu/drm/i915/display/icl_dsi_regs.h b/drivers/gpu/drm/i915/display/icl_dsi_regs.h
index f78f28b8dd94..d4845ac65acc 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi_regs.h
+++ b/drivers/gpu/drm/i915/display/icl_dsi_regs.h
@@ -6,7 +6,7 @@
#ifndef __ICL_DSI_REGS_H__
#define __ICL_DSI_REGS_H__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
/* Gen11 DSI */
#define _MMIO_DSI(tc, dsi0, dsi1) _MMIO_TRANS((tc) - TRANSCODER_DSI_0, \
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 18f0a5ae3bac..6621aa245caf 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -252,6 +252,11 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
if (crtc_state->hw.gamma_lut)
drm_property_blob_get(crtc_state->hw.gamma_lut);
+ if (crtc_state->pre_csc_lut)
+ drm_property_blob_get(crtc_state->pre_csc_lut);
+ if (crtc_state->post_csc_lut)
+ drm_property_blob_get(crtc_state->post_csc_lut);
+
crtc_state->update_pipe = false;
crtc_state->disable_lp_wm = false;
crtc_state->disable_cxsr = false;
@@ -274,6 +279,9 @@ static void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state)
drm_property_blob_put(crtc_state->hw.degamma_lut);
drm_property_blob_put(crtc_state->hw.gamma_lut);
drm_property_blob_put(crtc_state->hw.ctm);
+
+ drm_property_blob_put(crtc_state->pre_csc_lut);
+ drm_property_blob_put(crtc_state->post_csc_lut);
}
void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index aaa6708256d5..10e1fc9d0698 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -425,6 +425,47 @@ static bool intel_plane_do_async_flip(struct intel_plane *plane,
return DISPLAY_VER(i915) < 13 || old_crtc_state->uapi.async_flip;
}
+static bool i9xx_must_disable_cxsr(const struct intel_crtc_state *new_crtc_state,
+ const struct intel_plane_state *old_plane_state,
+ const struct intel_plane_state *new_plane_state)
+{
+ struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane);
+ bool old_visible = old_plane_state->uapi.visible;
+ bool new_visible = new_plane_state->uapi.visible;
+ u32 old_ctl = old_plane_state->ctl;
+ u32 new_ctl = new_plane_state->ctl;
+ bool modeset, turn_on, turn_off;
+
+ if (plane->id == PLANE_CURSOR)
+ return false;
+
+ modeset = intel_crtc_needs_modeset(new_crtc_state);
+ turn_off = old_visible && (!new_visible || modeset);
+ turn_on = new_visible && (!old_visible || modeset);
+
+ /* Must disable CxSR around plane enable/disable */
+ if (turn_on || turn_off)
+ return true;
+
+ if (!old_visible || !new_visible)
+ return false;
+
+ /*
+ * Most plane control register updates are blocked while in CxSR.
+ *
+ * Tiling mode is one exception where the primary plane can
+ * apparently handle it, whereas the sprites can not (the
+ * sprite issue being only relevant on VLV/CHV where CxSR
+ * is actually possible with a sprite enabled).
+ */
+ if (plane->id == PLANE_PRIMARY) {
+ old_ctl &= ~DISP_TILED;
+ new_ctl &= ~DISP_TILED;
+ }
+
+ return old_ctl != new_ctl;
+}
+
static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state,
const struct intel_plane_state *old_plane_state,
@@ -482,17 +523,9 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr
if (turn_on) {
if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
new_crtc_state->update_wm_pre = true;
-
- /* must disable cxsr around plane enable/disable */
- if (plane->id != PLANE_CURSOR)
- new_crtc_state->disable_cxsr = true;
} else if (turn_off) {
if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
new_crtc_state->update_wm_post = true;
-
- /* must disable cxsr around plane enable/disable */
- if (plane->id != PLANE_CURSOR)
- new_crtc_state->disable_cxsr = true;
} else if (intel_wm_need_update(old_plane_state, new_plane_state)) {
if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) {
/* FIXME bollocks */
@@ -504,6 +537,10 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr
if (visible || was_visible)
new_crtc_state->fb_bits |= plane->frontbuffer_bit;
+ if (HAS_GMCH(dev_priv) &&
+ i9xx_must_disable_cxsr(new_crtc_state, old_plane_state, new_plane_state))
+ new_crtc_state->disable_cxsr = true;
+
/*
* ILK/SNB DVSACNTR/Sprite Enable
* IVB SPR_CTL/Sprite Enable
@@ -720,7 +757,7 @@ void intel_plane_update_noarm(struct intel_plane *plane,
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- trace_intel_plane_update_noarm(&plane->base, crtc);
+ trace_intel_plane_update_noarm(plane, crtc);
if (plane->update_noarm)
plane->update_noarm(plane, crtc_state, plane_state);
@@ -732,7 +769,7 @@ void intel_plane_update_arm(struct intel_plane *plane,
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- trace_intel_plane_update_arm(&plane->base, crtc);
+ trace_intel_plane_update_arm(plane, crtc);
if (crtc_state->do_async_flip && plane->async_flip)
plane->async_flip(plane, crtc_state, plane_state, true);
@@ -745,7 +782,7 @@ void intel_plane_disable_arm(struct intel_plane *plane,
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- trace_intel_plane_disable_arm(&plane->base, crtc);
+ trace_intel_plane_disable_arm(plane, crtc);
plane->disable_arm(plane, crtc_state);
}
@@ -1005,7 +1042,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
*/
if (intel_crtc_needs_modeset(crtc_state)) {
ret = i915_sw_fence_await_reservation(&state->commit_ready,
- old_obj->base.resv, NULL,
+ old_obj->base.resv,
false, 0,
GFP_KERNEL);
if (ret < 0)
@@ -1039,8 +1076,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
struct dma_fence *fence;
ret = i915_sw_fence_await_reservation(&state->commit_ready,
- obj->base.resv, NULL,
- false,
+ obj->base.resv, false,
i915_fence_timeout(dev_priv),
GFP_KERNEL);
if (ret < 0)
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index aacbc6da84ef..98c3322b4549 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -250,7 +250,7 @@ static const struct hdmi_aud_ncts hdmi_aud_ncts_36bpp[] = {
/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
int i;
@@ -260,17 +260,17 @@ static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_sta
break;
}
- if (DISPLAY_VER(dev_priv) < 12 && adjusted_mode->crtc_clock > 148500)
+ if (DISPLAY_VER(i915) < 12 && adjusted_mode->crtc_clock > 148500)
i = ARRAY_SIZE(hdmi_audio_clock);
if (i == ARRAY_SIZE(hdmi_audio_clock)) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"HDMI audio pixel clock setting for %d not found, falling back to defaults\n",
adjusted_mode->crtc_clock);
i = 1;
}
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"Configuring HDMI audio for pixel clock %d (0x%08x)\n",
hdmi_audio_clock[i].clock,
hdmi_audio_clock[i].config);
@@ -304,96 +304,67 @@ static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state,
return 0;
}
-static bool intel_eld_uptodate(struct drm_connector *connector,
- i915_reg_t reg_eldv, u32 bits_eldv,
- i915_reg_t reg_elda, u32 bits_elda,
- i915_reg_t reg_edid)
+/* ELD buffer size in dwords */
+static int g4x_eld_buffer_size(struct drm_i915_private *i915)
{
- struct drm_i915_private *dev_priv = to_i915(connector->dev);
- const u8 *eld = connector->eld;
u32 tmp;
- int i;
-
- tmp = intel_de_read(dev_priv, reg_eldv);
- tmp &= bits_eldv;
-
- if (!tmp)
- return false;
- tmp = intel_de_read(dev_priv, reg_elda);
- tmp &= ~bits_elda;
- intel_de_write(dev_priv, reg_elda, tmp);
+ tmp = intel_de_read(i915, G4X_AUD_CNTL_ST);
- for (i = 0; i < drm_eld_size(eld) / 4; i++)
- if (intel_de_read(dev_priv, reg_edid) != *((const u32 *)eld + i))
- return false;
-
- return true;
+ return REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp);
}
static void g4x_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- u32 eldv, tmp;
-
- tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
- if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
- eldv = G4X_ELDV_DEVCL_DEVBLC;
- else
- eldv = G4X_ELDV_DEVCTG;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
/* Invalidate ELD */
- tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST);
- tmp &= ~eldv;
- intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp);
+ intel_de_rmw(i915, G4X_AUD_CNTL_ST,
+ G4X_ELD_VALID, 0);
+
+ intel_crtc_wait_for_next_vblank(crtc);
+ intel_crtc_wait_for_next_vblank(crtc);
}
static void g4x_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
- const u8 *eld = connector->eld;
- u32 eldv;
- u32 tmp;
- int len, i;
+ const u32 *eld = (const u32 *)connector->eld;
+ int eld_buffer_size, len, i;
- tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID);
- if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL)
- eldv = G4X_ELDV_DEVCL_DEVBLC;
- else
- eldv = G4X_ELDV_DEVCTG;
+ intel_crtc_wait_for_next_vblank(crtc);
- if (intel_eld_uptodate(connector,
- G4X_AUD_CNTL_ST, eldv,
- G4X_AUD_CNTL_ST, G4X_ELD_ADDR_MASK,
- G4X_HDMIW_HDMIEDID))
- return;
+ intel_de_rmw(i915, G4X_AUD_CNTL_ST,
+ G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0);
- tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST);
- tmp &= ~(eldv | G4X_ELD_ADDR_MASK);
- len = (tmp >> 9) & 0x1f; /* ELD buffer size */
- intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp);
+ eld_buffer_size = g4x_eld_buffer_size(i915);
+ len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
- len = min(drm_eld_size(eld) / 4, len);
for (i = 0; i < len; i++)
- intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID,
- *((const u32 *)eld + i));
+ intel_de_write(i915, G4X_HDMIW_HDMIEDID, eld[i]);
+ for (; i < eld_buffer_size; i++)
+ intel_de_write(i915, G4X_HDMIW_HDMIEDID, 0);
- tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST);
- tmp |= eldv;
- intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp);
+ drm_WARN_ON(&i915->drm,
+ (intel_de_read(i915, G4X_AUD_CNTL_ST) & G4X_ELD_ADDRESS_MASK) != 0);
+
+ intel_de_rmw(i915, G4X_AUD_CNTL_ST,
+ 0, G4X_ELD_VALID);
}
static void
hsw_dp_audio_config_update(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct i915_audio_component *acomp = dev_priv->display.audio.component;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct i915_audio_component *acomp = i915->display.audio.component;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum port port = encoder->port;
const struct dp_aud_n_m *nm;
@@ -403,12 +374,12 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder,
rate = acomp ? acomp->aud_sample_rate[port] : 0;
nm = audio_config_dp_get_n_m(crtc_state, rate);
if (nm)
- drm_dbg_kms(&dev_priv->drm, "using Maud %u, Naud %u\n", nm->m,
+ drm_dbg_kms(&i915->drm, "using Maud %u, Naud %u\n", nm->m,
nm->n);
else
- drm_dbg_kms(&dev_priv->drm, "using automatic Maud, Naud\n");
+ drm_dbg_kms(&i915->drm, "using automatic Maud, Naud\n");
- tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder));
+ tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder));
tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
@@ -420,9 +391,9 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder,
tmp |= AUD_CONFIG_N_PROG_ENABLE;
}
- intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp);
+ intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp);
- tmp = intel_de_read(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder));
+ tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder));
tmp &= ~AUD_CONFIG_M_MASK;
tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
@@ -433,15 +404,15 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder,
tmp |= AUD_M_CTS_M_PROG_ENABLE;
}
- intel_de_write(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp);
+ intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp);
}
static void
hsw_hdmi_audio_config_update(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct i915_audio_component *acomp = dev_priv->display.audio.component;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct i915_audio_component *acomp = i915->display.audio.component;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum port port = encoder->port;
int n, rate;
@@ -449,7 +420,7 @@ hsw_hdmi_audio_config_update(struct intel_encoder *encoder,
rate = acomp ? acomp->aud_sample_rate[port] : 0;
- tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder));
+ tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder));
tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
@@ -457,25 +428,25 @@ hsw_hdmi_audio_config_update(struct intel_encoder *encoder,
n = audio_config_hdmi_get_n(crtc_state, rate);
if (n != 0) {
- drm_dbg_kms(&dev_priv->drm, "using N %d\n", n);
+ drm_dbg_kms(&i915->drm, "using N %d\n", n);
tmp &= ~AUD_CONFIG_N_MASK;
tmp |= AUD_CONFIG_N(n);
tmp |= AUD_CONFIG_N_PROG_ENABLE;
} else {
- drm_dbg_kms(&dev_priv->drm, "using automatic N\n");
+ drm_dbg_kms(&i915->drm, "using automatic N\n");
}
- intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp);
+ intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp);
/*
* Let's disable "Enable CTS or M Prog bit"
* and let HW calculate the value
*/
- tmp = intel_de_read(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder));
+ tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder));
tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
- intel_de_write(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp);
+ intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp);
}
static void
@@ -488,33 +459,48 @@ hsw_audio_config_update(struct intel_encoder *encoder,
hsw_hdmi_audio_config_update(encoder, crtc_state);
}
+/* ELD buffer size in dwords */
+static int hsw_eld_buffer_size(struct drm_i915_private *i915,
+ enum transcoder cpu_transcoder)
+{
+ u32 tmp;
+
+ tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder));
+
+ return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
+}
+
static void hsw_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
- u32 tmp;
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
/* Disable timestamps */
- tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder));
- tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
- tmp |= AUD_CONFIG_N_PROG_ENABLE;
- tmp &= ~AUD_CONFIG_UPPER_N_MASK;
- tmp &= ~AUD_CONFIG_LOWER_N_MASK;
- if (intel_crtc_has_dp_encoder(old_crtc_state))
- tmp |= AUD_CONFIG_N_VALUE_INDEX;
- intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp);
+ intel_de_rmw(i915, HSW_AUD_CFG(cpu_transcoder),
+ AUD_CONFIG_N_VALUE_INDEX |
+ AUD_CONFIG_UPPER_N_MASK |
+ AUD_CONFIG_LOWER_N_MASK,
+ AUD_CONFIG_N_PROG_ENABLE |
+ (intel_crtc_has_dp_encoder(old_crtc_state) ?
+ AUD_CONFIG_N_VALUE_INDEX : 0));
/* Invalidate ELD */
- tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD);
- tmp &= ~AUDIO_ELD_VALID(cpu_transcoder);
- tmp &= ~AUDIO_OUTPUT_ENABLE(cpu_transcoder);
- intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp);
+ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
+ AUDIO_ELD_VALID(cpu_transcoder), 0);
+
+ intel_crtc_wait_for_next_vblank(crtc);
+ intel_crtc_wait_for_next_vblank(crtc);
- mutex_unlock(&dev_priv->display.audio.mutex);
+ /* Disable audio presence detect */
+ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
+ AUDIO_OUTPUT_ENABLE(cpu_transcoder), 0);
+
+ mutex_unlock(&i915->display.audio.mutex);
}
static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder,
@@ -626,178 +612,190 @@ static void enable_audio_dsc_wa(struct intel_encoder *encoder,
intel_de_write(i915, AUD_CONFIG_BE, val);
}
-#undef ROUNDING_FACTOR
-
static void hsw_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
- const u8 *eld = connector->eld;
- u32 tmp;
- int len, i;
+ const u32 *eld = (const u32 *)connector->eld;
+ int eld_buffer_size, len, i;
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
/* Enable Audio WA for 4k DSC usecases */
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP))
enable_audio_dsc_wa(encoder, crtc_state);
- /* Enable audio presence detect, invalidate ELD */
- tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD);
- tmp |= AUDIO_OUTPUT_ENABLE(cpu_transcoder);
- tmp &= ~AUDIO_ELD_VALID(cpu_transcoder);
- intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp);
+ /* Enable audio presence detect */
+ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
+ 0, AUDIO_OUTPUT_ENABLE(cpu_transcoder));
- /*
- * FIXME: We're supposed to wait for vblank here, but we have vblanks
- * disabled during the mode set. The proper fix would be to push the
- * rest of the setup into a vblank work item, queued here, but the
- * infrastructure is not there yet.
- */
+ intel_crtc_wait_for_next_vblank(crtc);
+
+ /* Invalidate ELD */
+ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
+ AUDIO_ELD_VALID(cpu_transcoder), 0);
+
+ /* Reset ELD address */
+ intel_de_rmw(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder),
+ IBX_ELD_ADDRESS_MASK, 0);
- /* Reset ELD write address */
- tmp = intel_de_read(dev_priv, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder));
- tmp &= ~IBX_ELD_ADDRESS_MASK;
- intel_de_write(dev_priv, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp);
+ eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder);
+ len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
- /* Up to 84 bytes of hw ELD buffer */
- len = min(drm_eld_size(eld), 84);
- for (i = 0; i < len / 4; i++)
- intel_de_write(dev_priv, HSW_AUD_EDID_DATA(cpu_transcoder),
- *((const u32 *)eld + i));
+ for (i = 0; i < len; i++)
+ intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), eld[i]);
+ for (; i < eld_buffer_size; i++)
+ intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), 0);
+
+ drm_WARN_ON(&i915->drm,
+ (intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)) &
+ IBX_ELD_ADDRESS_MASK) != 0);
/* ELD valid */
- tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD);
- tmp |= AUDIO_ELD_VALID(cpu_transcoder);
- intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp);
+ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
+ 0, AUDIO_ELD_VALID(cpu_transcoder));
/* Enable timestamps */
hsw_audio_config_update(encoder, crtc_state);
- mutex_unlock(&dev_priv->display.audio.mutex);
+ mutex_unlock(&i915->display.audio.mutex);
+}
+
+struct ilk_audio_regs {
+ i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
+};
+
+static void ilk_audio_regs_init(struct drm_i915_private *i915,
+ enum pipe pipe,
+ struct ilk_audio_regs *regs)
+{
+ if (HAS_PCH_IBX(i915)) {
+ regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
+ regs->aud_config = IBX_AUD_CFG(pipe);
+ regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
+ regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
+ } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ regs->hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
+ regs->aud_config = VLV_AUD_CFG(pipe);
+ regs->aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
+ regs->aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
+ } else {
+ regs->hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
+ regs->aud_config = CPT_AUD_CFG(pipe);
+ regs->aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
+ regs->aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
+ }
+}
+
+/* ELD buffer size in dwords */
+static int ilk_eld_buffer_size(struct drm_i915_private *i915,
+ enum pipe pipe)
+{
+ struct ilk_audio_regs regs;
+ u32 tmp;
+
+ ilk_audio_regs_init(i915, pipe, &regs);
+
+ tmp = intel_de_read(i915, regs.aud_cntl_st);
+
+ return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
}
static void ilk_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
- enum pipe pipe = crtc->pipe;
enum port port = encoder->port;
- u32 tmp, eldv;
- i915_reg_t aud_config, aud_cntrl_st2;
+ enum pipe pipe = crtc->pipe;
+ struct ilk_audio_regs regs;
- if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
+ if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
- if (HAS_PCH_IBX(dev_priv)) {
- aud_config = IBX_AUD_CFG(pipe);
- aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- aud_config = VLV_AUD_CFG(pipe);
- aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
- } else {
- aud_config = CPT_AUD_CFG(pipe);
- aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
- }
+ ilk_audio_regs_init(i915, pipe, &regs);
- /* Disable timestamps */
- tmp = intel_de_read(dev_priv, aud_config);
- tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
- tmp |= AUD_CONFIG_N_PROG_ENABLE;
- tmp &= ~AUD_CONFIG_UPPER_N_MASK;
- tmp &= ~AUD_CONFIG_LOWER_N_MASK;
- if (intel_crtc_has_dp_encoder(old_crtc_state))
- tmp |= AUD_CONFIG_N_VALUE_INDEX;
- intel_de_write(dev_priv, aud_config, tmp);
+ mutex_lock(&i915->display.audio.mutex);
- eldv = IBX_ELD_VALID(port);
+ /* Disable timestamps */
+ intel_de_rmw(i915, regs.aud_config,
+ AUD_CONFIG_N_VALUE_INDEX |
+ AUD_CONFIG_UPPER_N_MASK |
+ AUD_CONFIG_LOWER_N_MASK,
+ AUD_CONFIG_N_PROG_ENABLE |
+ (intel_crtc_has_dp_encoder(old_crtc_state) ?
+ AUD_CONFIG_N_VALUE_INDEX : 0));
/* Invalidate ELD */
- tmp = intel_de_read(dev_priv, aud_cntrl_st2);
- tmp &= ~eldv;
- intel_de_write(dev_priv, aud_cntrl_st2, tmp);
+ intel_de_rmw(i915, regs.aud_cntrl_st2,
+ IBX_ELD_VALID(port), 0);
+
+ mutex_unlock(&i915->display.audio.mutex);
+
+ intel_crtc_wait_for_next_vblank(crtc);
+ intel_crtc_wait_for_next_vblank(crtc);
}
static void ilk_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
- enum pipe pipe = crtc->pipe;
+ const u32 *eld = (const u32 *)connector->eld;
enum port port = encoder->port;
- const u8 *eld = connector->eld;
- u32 tmp, eldv;
- int len, i;
- i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
+ enum pipe pipe = crtc->pipe;
+ int eld_buffer_size, len, i;
+ struct ilk_audio_regs regs;
- if (drm_WARN_ON(&dev_priv->drm, port == PORT_A))
+ if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
- /*
- * FIXME: We're supposed to wait for vblank here, but we have vblanks
- * disabled during the mode set. The proper fix would be to push the
- * rest of the setup into a vblank work item, queued here, but the
- * infrastructure is not there yet.
- */
+ intel_crtc_wait_for_next_vblank(crtc);
- if (HAS_PCH_IBX(dev_priv)) {
- hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
- aud_config = IBX_AUD_CFG(pipe);
- aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
- aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
- } else if (IS_VALLEYVIEW(dev_priv) ||
- IS_CHERRYVIEW(dev_priv)) {
- hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
- aud_config = VLV_AUD_CFG(pipe);
- aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
- aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
- } else {
- hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
- aud_config = CPT_AUD_CFG(pipe);
- aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
- aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
- }
+ ilk_audio_regs_init(i915, pipe, &regs);
- eldv = IBX_ELD_VALID(port);
+ mutex_lock(&i915->display.audio.mutex);
/* Invalidate ELD */
- tmp = intel_de_read(dev_priv, aud_cntrl_st2);
- tmp &= ~eldv;
- intel_de_write(dev_priv, aud_cntrl_st2, tmp);
+ intel_de_rmw(i915, regs.aud_cntrl_st2,
+ IBX_ELD_VALID(port), 0);
+
+ /* Reset ELD address */
+ intel_de_rmw(i915, regs.aud_cntl_st,
+ IBX_ELD_ADDRESS_MASK, 0);
- /* Reset ELD write address */
- tmp = intel_de_read(dev_priv, aud_cntl_st);
- tmp &= ~IBX_ELD_ADDRESS_MASK;
- intel_de_write(dev_priv, aud_cntl_st, tmp);
+ eld_buffer_size = ilk_eld_buffer_size(i915, pipe);
+ len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
- /* Up to 84 bytes of hw ELD buffer */
- len = min(drm_eld_size(eld), 84);
- for (i = 0; i < len / 4; i++)
- intel_de_write(dev_priv, hdmiw_hdmiedid,
- *((const u32 *)eld + i));
+ for (i = 0; i < len; i++)
+ intel_de_write(i915, regs.hdmiw_hdmiedid, eld[i]);
+ for (; i < eld_buffer_size; i++)
+ intel_de_write(i915, regs.hdmiw_hdmiedid, 0);
+
+ drm_WARN_ON(&i915->drm,
+ (intel_de_read(i915, regs.aud_cntl_st) & IBX_ELD_ADDRESS_MASK) != 0);
/* ELD valid */
- tmp = intel_de_read(dev_priv, aud_cntrl_st2);
- tmp |= eldv;
- intel_de_write(dev_priv, aud_cntrl_st2, tmp);
+ intel_de_rmw(i915, regs.aud_cntrl_st2,
+ 0, IBX_ELD_VALID(port));
/* Enable timestamps */
- tmp = intel_de_read(dev_priv, aud_config);
- tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
- tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
- tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
- if (intel_crtc_has_dp_encoder(crtc_state))
- tmp |= AUD_CONFIG_N_VALUE_INDEX;
- else
- tmp |= audio_config_hdmi_pixel_clock(crtc_state);
- intel_de_write(dev_priv, aud_config, tmp);
+ intel_de_rmw(i915, regs.aud_config,
+ AUD_CONFIG_N_VALUE_INDEX |
+ AUD_CONFIG_N_PROG_ENABLE |
+ AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK,
+ (intel_crtc_has_dp_encoder(crtc_state) ?
+ AUD_CONFIG_N_VALUE_INDEX :
+ audio_config_hdmi_pixel_clock(crtc_state)));
+
+ mutex_unlock(&i915->display.audio.mutex);
}
/**
@@ -813,8 +811,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct i915_audio_component *acomp = dev_priv->display.audio.component;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_connector *connector = conn_state->connector;
const struct drm_display_mode *adjusted_mode =
@@ -825,30 +823,30 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
if (!crtc_state->has_audio)
return;
- drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n",
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n",
connector->base.id, connector->name,
encoder->base.base.id, encoder->base.name,
pipe_name(pipe), drm_eld_size(connector->eld));
/* FIXME precompute the ELD in .compute_config() */
if (!connector->eld[0])
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"Bogus ELD on [CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
- if (dev_priv->display.funcs.audio)
- dev_priv->display.funcs.audio->audio_codec_enable(encoder,
- crtc_state,
- conn_state);
+ if (i915->display.funcs.audio)
+ i915->display.funcs.audio->audio_codec_enable(encoder,
+ crtc_state,
+ conn_state);
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
encoder->audio_connector = connector;
/* referred in audio callbacks */
- dev_priv->display.audio.encoder_map[pipe] = encoder;
- mutex_unlock(&dev_priv->display.audio.mutex);
+ i915->display.audio.encoder_map[pipe] = encoder;
+ mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
@@ -856,10 +854,10 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
pipe = -1;
acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
- (int) port, (int) pipe);
+ (int)port, (int)pipe);
}
- intel_lpe_audio_notify(dev_priv, pipe, port, connector->eld,
+ intel_lpe_audio_notify(i915, pipe, port, connector->eld,
crtc_state->port_clock,
intel_crtc_has_dp_encoder(crtc_state));
}
@@ -877,8 +875,8 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct i915_audio_component *acomp = dev_priv->display.audio.component;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_connector *connector = old_conn_state->connector;
enum port port = encoder->port;
@@ -887,19 +885,19 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
if (!old_crtc_state->has_audio)
return;
- drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n",
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n",
connector->base.id, connector->name,
encoder->base.base.id, encoder->base.name, pipe_name(pipe));
- if (dev_priv->display.funcs.audio)
- dev_priv->display.funcs.audio->audio_codec_disable(encoder,
- old_crtc_state,
- old_conn_state);
+ if (i915->display.funcs.audio)
+ i915->display.funcs.audio->audio_codec_disable(encoder,
+ old_crtc_state,
+ old_conn_state);
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
encoder->audio_connector = NULL;
- dev_priv->display.audio.encoder_map[pipe] = NULL;
- mutex_unlock(&dev_priv->display.audio.mutex);
+ i915->display.audio.encoder_map[pipe] = NULL;
+ mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
@@ -907,10 +905,10 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
pipe = -1;
acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
- (int) port, (int) pipe);
+ (int)port, (int)pipe);
}
- intel_lpe_audio_notify(dev_priv, pipe, port, NULL, 0, false);
+ intel_lpe_audio_notify(i915, pipe, port, NULL, 0, false);
}
static const struct intel_audio_funcs g4x_audio_funcs = {
@@ -930,19 +928,18 @@ static const struct intel_audio_funcs hsw_audio_funcs = {
/**
* intel_audio_hooks_init - Set up chip specific audio hooks
- * @dev_priv: device private
+ * @i915: device private
*/
-void intel_audio_hooks_init(struct drm_i915_private *dev_priv)
+void intel_audio_hooks_init(struct drm_i915_private *i915)
{
- if (IS_G4X(dev_priv)) {
- dev_priv->display.funcs.audio = &g4x_audio_funcs;
- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- dev_priv->display.funcs.audio = &ilk_audio_funcs;
- } else if (IS_HASWELL(dev_priv) || DISPLAY_VER(dev_priv) >= 8) {
- dev_priv->display.funcs.audio = &hsw_audio_funcs;
- } else if (HAS_PCH_SPLIT(dev_priv)) {
- dev_priv->display.funcs.audio = &ilk_audio_funcs;
- }
+ if (IS_G4X(i915))
+ i915->display.funcs.audio = &g4x_audio_funcs;
+ else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ i915->display.funcs.audio = &ilk_audio_funcs;
+ else if (IS_HASWELL(i915) || DISPLAY_VER(i915) >= 8)
+ i915->display.funcs.audio = &hsw_audio_funcs;
+ else if (HAS_PCH_SPLIT(i915))
+ i915->display.funcs.audio = &ilk_audio_funcs;
}
struct aud_ts_cdclk_m_n {
@@ -1000,7 +997,7 @@ static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state,
return drm_atomic_commit(&state->base);
}
-static void glk_force_audio_cdclk(struct drm_i915_private *dev_priv,
+static void glk_force_audio_cdclk(struct drm_i915_private *i915,
bool enable)
{
struct drm_modeset_acquire_ctx ctx;
@@ -1008,13 +1005,13 @@ static void glk_force_audio_cdclk(struct drm_i915_private *dev_priv,
struct intel_crtc *crtc;
int ret;
- crtc = intel_first_crtc(dev_priv);
+ crtc = intel_first_crtc(i915);
if (!crtc)
return;
drm_modeset_acquire_init(&ctx, 0);
- state = drm_atomic_state_alloc(&dev_priv->drm);
- if (drm_WARN_ON(&dev_priv->drm, !state))
+ state = drm_atomic_state_alloc(&i915->drm);
+ if (drm_WARN_ON(&i915->drm, !state))
return;
state->acquire_ctx = &ctx;
@@ -1028,7 +1025,7 @@ retry:
goto retry;
}
- drm_WARN_ON(&dev_priv->drm, ret);
+ drm_WARN_ON(&i915->drm, ret);
drm_atomic_state_put(state);
@@ -1038,30 +1035,30 @@ retry:
static unsigned long i915_audio_component_get_power(struct device *kdev)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
intel_wakeref_t ret;
/* Catch potential impedance mismatches before they occur! */
BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long));
- ret = intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO_PLAYBACK);
+ ret = intel_display_power_get(i915, POWER_DOMAIN_AUDIO_PLAYBACK);
- if (dev_priv->display.audio.power_refcount++ == 0) {
- if (DISPLAY_VER(dev_priv) >= 9) {
- intel_de_write(dev_priv, AUD_FREQ_CNTRL,
- dev_priv->display.audio.freq_cntrl);
- drm_dbg_kms(&dev_priv->drm,
+ if (i915->display.audio.power_refcount++ == 0) {
+ if (DISPLAY_VER(i915) >= 9) {
+ intel_de_write(i915, AUD_FREQ_CNTRL,
+ i915->display.audio.freq_cntrl);
+ drm_dbg_kms(&i915->drm,
"restored AUD_FREQ_CNTRL to 0x%x\n",
- dev_priv->display.audio.freq_cntrl);
+ i915->display.audio.freq_cntrl);
}
/* Force CDCLK to 2*BCLK as long as we need audio powered. */
- if (IS_GEMINILAKE(dev_priv))
- glk_force_audio_cdclk(dev_priv, true);
+ if (IS_GEMINILAKE(i915))
+ glk_force_audio_cdclk(i915, true);
- if (DISPLAY_VER(dev_priv) >= 10)
- intel_de_write(dev_priv, AUD_PIN_BUF_CTL,
- (intel_de_read(dev_priv, AUD_PIN_BUF_CTL) | AUD_PIN_BUF_ENABLE));
+ if (DISPLAY_VER(i915) >= 10)
+ intel_de_rmw(i915, AUD_PIN_BUF_CTL,
+ 0, AUD_PIN_BUF_ENABLE);
}
return ret;
@@ -1070,24 +1067,23 @@ static unsigned long i915_audio_component_get_power(struct device *kdev)
static void i915_audio_component_put_power(struct device *kdev,
unsigned long cookie)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
/* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */
- if (--dev_priv->display.audio.power_refcount == 0)
- if (IS_GEMINILAKE(dev_priv))
- glk_force_audio_cdclk(dev_priv, false);
+ if (--i915->display.audio.power_refcount == 0)
+ if (IS_GEMINILAKE(i915))
+ glk_force_audio_cdclk(i915, false);
- intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO_PLAYBACK, cookie);
+ intel_display_power_put(i915, POWER_DOMAIN_AUDIO_PLAYBACK, cookie);
}
static void i915_audio_component_codec_wake_override(struct device *kdev,
bool enable)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
unsigned long cookie;
- u32 tmp;
- if (DISPLAY_VER(dev_priv) < 9)
+ if (DISPLAY_VER(i915) < 9)
return;
cookie = i915_audio_component_get_power(kdev);
@@ -1096,15 +1092,13 @@ static void i915_audio_component_codec_wake_override(struct device *kdev,
* Enable/disable generating the codec wake signal, overriding the
* internal logic to generate the codec wake to controller.
*/
- tmp = intel_de_read(dev_priv, HSW_AUD_CHICKENBIT);
- tmp &= ~SKL_AUD_CODEC_WAKE_SIGNAL;
- intel_de_write(dev_priv, HSW_AUD_CHICKENBIT, tmp);
+ intel_de_rmw(i915, HSW_AUD_CHICKENBIT,
+ SKL_AUD_CODEC_WAKE_SIGNAL, 0);
usleep_range(1000, 1500);
if (enable) {
- tmp = intel_de_read(dev_priv, HSW_AUD_CHICKENBIT);
- tmp |= SKL_AUD_CODEC_WAKE_SIGNAL;
- intel_de_write(dev_priv, HSW_AUD_CHICKENBIT, tmp);
+ intel_de_rmw(i915, HSW_AUD_CHICKENBIT,
+ 0, SKL_AUD_CODEC_WAKE_SIGNAL);
usleep_range(1000, 1500);
}
@@ -1114,12 +1108,12 @@ static void i915_audio_component_codec_wake_override(struct device *kdev,
/* Get CDCLK in kHz */
static int i915_audio_component_get_cdclk_freq(struct device *kdev)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
- if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DDI(dev_priv)))
+ if (drm_WARN_ON_ONCE(&i915->drm, !HAS_DDI(i915)))
return -ENODEV;
- return dev_priv->display.cdclk.hw.cdclk;
+ return i915->display.cdclk.hw.cdclk;
}
/*
@@ -1132,24 +1126,24 @@ static int i915_audio_component_get_cdclk_freq(struct device *kdev)
* will get the right intel_encoder with port matched
* Non-MST & (pipe < 0): get the right intel_encoder with port matched
*/
-static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
- int port, int pipe)
+static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915,
+ int port, int pipe)
{
- struct intel_encoder *encoder;
-
/* MST */
if (pipe >= 0) {
- if (drm_WARN_ON(&dev_priv->drm,
- pipe >= ARRAY_SIZE(dev_priv->display.audio.encoder_map)))
+ struct intel_encoder *encoder;
+
+ if (drm_WARN_ON(&i915->drm,
+ pipe >= ARRAY_SIZE(i915->display.audio.encoder_map)))
return NULL;
- encoder = dev_priv->display.audio.encoder_map[pipe];
+ encoder = i915->display.audio.encoder_map[pipe];
/*
* when bootup, audio driver may not know it is
* MST or not. So it will poll all the port & pipe
* combinations
*/
- if (encoder != NULL && encoder->port == port &&
+ if (encoder && encoder->port == port &&
encoder->type == INTEL_OUTPUT_DP_MST)
return encoder;
}
@@ -1158,15 +1152,13 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
if (pipe > 0)
return NULL;
- for_each_pipe(dev_priv, pipe) {
- encoder = dev_priv->display.audio.encoder_map[pipe];
- if (encoder == NULL)
- continue;
+ for_each_pipe(i915, pipe) {
+ struct intel_encoder *encoder;
- if (encoder->type == INTEL_OUTPUT_DP_MST)
- continue;
+ encoder = i915->display.audio.encoder_map[pipe];
- if (port == encoder->port)
+ if (encoder && encoder->port == port &&
+ encoder->type != INTEL_OUTPUT_DP_MST)
return encoder;
}
@@ -1176,23 +1168,23 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
int pipe, int rate)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
- struct i915_audio_component *acomp = dev_priv->display.audio.component;
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
+ struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_encoder *encoder;
struct intel_crtc *crtc;
unsigned long cookie;
int err = 0;
- if (!HAS_DDI(dev_priv))
+ if (!HAS_DDI(i915))
return 0;
cookie = i915_audio_component_get_power(kdev);
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
/* 1. get the pipe */
- encoder = get_saved_enc(dev_priv, port, pipe);
+ encoder = get_saved_enc(i915, port, pipe);
if (!encoder || !encoder->base.crtc) {
- drm_dbg_kms(&dev_priv->drm, "Not valid for port %c\n",
+ drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
port_name(port));
err = -ENODEV;
goto unlock;
@@ -1206,7 +1198,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
hsw_audio_config_update(encoder, crtc->config);
unlock:
- mutex_unlock(&dev_priv->display.audio.mutex);
+ mutex_unlock(&i915->display.audio.mutex);
i915_audio_component_put_power(kdev, cookie);
return err;
}
@@ -1215,18 +1207,18 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
int pipe, bool *enabled,
unsigned char *buf, int max_bytes)
{
- struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(kdev);
struct intel_encoder *intel_encoder;
const u8 *eld;
int ret = -EINVAL;
- mutex_lock(&dev_priv->display.audio.mutex);
+ mutex_lock(&i915->display.audio.mutex);
- intel_encoder = get_saved_enc(dev_priv, port, pipe);
+ intel_encoder = get_saved_enc(i915, port, pipe);
if (!intel_encoder) {
- drm_dbg_kms(&dev_priv->drm, "Not valid for port %c\n",
+ drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
port_name(port));
- mutex_unlock(&dev_priv->display.audio.mutex);
+ mutex_unlock(&i915->display.audio.mutex);
return ret;
}
@@ -1238,7 +1230,7 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
memcpy(buf, eld, min(max_bytes, ret));
}
- mutex_unlock(&dev_priv->display.audio.mutex);
+ mutex_unlock(&i915->display.audio.mutex);
return ret;
}
@@ -1256,25 +1248,25 @@ static int i915_audio_component_bind(struct device *i915_kdev,
struct device *hda_kdev, void *data)
{
struct i915_audio_component *acomp = data;
- struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
int i;
- if (drm_WARN_ON(&dev_priv->drm, acomp->base.ops || acomp->base.dev))
+ if (drm_WARN_ON(&i915->drm, acomp->base.ops || acomp->base.dev))
return -EEXIST;
- if (drm_WARN_ON(&dev_priv->drm,
+ if (drm_WARN_ON(&i915->drm,
!device_link_add(hda_kdev, i915_kdev,
DL_FLAG_STATELESS)))
return -ENOMEM;
- drm_modeset_lock_all(&dev_priv->drm);
+ drm_modeset_lock_all(&i915->drm);
acomp->base.ops = &i915_audio_component_ops;
acomp->base.dev = i915_kdev;
BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
acomp->aud_sample_rate[i] = 0;
- dev_priv->display.audio.component = acomp;
- drm_modeset_unlock_all(&dev_priv->drm);
+ i915->display.audio.component = acomp;
+ drm_modeset_unlock_all(&i915->drm);
return 0;
}
@@ -1283,19 +1275,19 @@ static void i915_audio_component_unbind(struct device *i915_kdev,
struct device *hda_kdev, void *data)
{
struct i915_audio_component *acomp = data;
- struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
+ struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
- drm_modeset_lock_all(&dev_priv->drm);
+ drm_modeset_lock_all(&i915->drm);
acomp->base.ops = NULL;
acomp->base.dev = NULL;
- dev_priv->display.audio.component = NULL;
- drm_modeset_unlock_all(&dev_priv->drm);
+ i915->display.audio.component = NULL;
+ drm_modeset_unlock_all(&i915->drm);
device_link_remove(hda_kdev, i915_kdev);
- if (dev_priv->display.audio.power_refcount)
- drm_err(&dev_priv->drm, "audio power refcount %d after unbind\n",
- dev_priv->display.audio.power_refcount);
+ if (i915->display.audio.power_refcount)
+ drm_err(&i915->drm, "audio power refcount %d after unbind\n",
+ i915->display.audio.power_refcount);
}
static const struct component_ops i915_audio_component_bind_ops = {
@@ -1314,7 +1306,7 @@ static const struct component_ops i915_audio_component_bind_ops = {
/**
* i915_audio_component_init - initialize and register the audio component
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
*
* This will register with the component framework a child component which
* will bind dynamically to the snd_hda_intel driver's corresponding master
@@ -1328,83 +1320,83 @@ static const struct component_ops i915_audio_component_bind_ops = {
* We ignore any error during registration and continue with reduced
* functionality (i.e. without HDMI audio).
*/
-static void i915_audio_component_init(struct drm_i915_private *dev_priv)
+static void i915_audio_component_init(struct drm_i915_private *i915)
{
u32 aud_freq, aud_freq_init;
int ret;
- ret = component_add_typed(dev_priv->drm.dev,
+ ret = component_add_typed(i915->drm.dev,
&i915_audio_component_bind_ops,
I915_COMPONENT_AUDIO);
if (ret < 0) {
- drm_err(&dev_priv->drm,
+ drm_err(&i915->drm,
"failed to add audio component (%d)\n", ret);
/* continue with reduced functionality */
return;
}
- if (DISPLAY_VER(dev_priv) >= 9) {
- aud_freq_init = intel_de_read(dev_priv, AUD_FREQ_CNTRL);
+ if (DISPLAY_VER(i915) >= 9) {
+ aud_freq_init = intel_de_read(i915, AUD_FREQ_CNTRL);
- if (DISPLAY_VER(dev_priv) >= 12)
+ if (DISPLAY_VER(i915) >= 12)
aud_freq = AUD_FREQ_GEN12;
else
aud_freq = aud_freq_init;
/* use BIOS provided value for TGL and RKL unless it is a known bad value */
- if ((IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) &&
+ if ((IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915)) &&
aud_freq_init != AUD_FREQ_TGL_BROKEN)
aud_freq = aud_freq_init;
- drm_dbg_kms(&dev_priv->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n",
+ drm_dbg_kms(&i915->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n",
aud_freq, aud_freq_init);
- dev_priv->display.audio.freq_cntrl = aud_freq;
+ i915->display.audio.freq_cntrl = aud_freq;
}
/* init with current cdclk */
- intel_audio_cdclk_change_post(dev_priv);
+ intel_audio_cdclk_change_post(i915);
- dev_priv->display.audio.component_registered = true;
+ i915->display.audio.component_registered = true;
}
/**
* i915_audio_component_cleanup - deregister the audio component
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
*
* Deregisters the audio component, breaking any existing binding to the
* corresponding snd_hda_intel driver's master component.
*/
-static void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
+static void i915_audio_component_cleanup(struct drm_i915_private *i915)
{
- if (!dev_priv->display.audio.component_registered)
+ if (!i915->display.audio.component_registered)
return;
- component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops);
- dev_priv->display.audio.component_registered = false;
+ component_del(i915->drm.dev, &i915_audio_component_bind_ops);
+ i915->display.audio.component_registered = false;
}
/**
* intel_audio_init() - Initialize the audio driver either using
* component framework or using lpe audio bridge
- * @dev_priv: the i915 drm device private data
+ * @i915: the i915 drm device private data
*
*/
-void intel_audio_init(struct drm_i915_private *dev_priv)
+void intel_audio_init(struct drm_i915_private *i915)
{
- if (intel_lpe_audio_init(dev_priv) < 0)
- i915_audio_component_init(dev_priv);
+ if (intel_lpe_audio_init(i915) < 0)
+ i915_audio_component_init(i915);
}
/**
* intel_audio_deinit() - deinitialize the audio driver
- * @dev_priv: the i915 drm device private data
+ * @i915: the i915 drm device private data
*
*/
-void intel_audio_deinit(struct drm_i915_private *dev_priv)
+void intel_audio_deinit(struct drm_i915_private *i915)
{
- if (dev_priv->display.audio.lpe.platdev != NULL)
- intel_lpe_audio_teardown(dev_priv);
+ if (i915->display.audio.lpe.platdev != NULL)
+ intel_lpe_audio_teardown(i915);
else
- i915_audio_component_cleanup(dev_priv);
+ i915_audio_component_cleanup(i915);
}
diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h
index d1e5844e3484..616e7b1275c4 100644
--- a/drivers/gpu/drm/i915/display/intel_audio_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h
@@ -6,18 +6,13 @@
#ifndef __INTEL_AUDIO_REGS_H__
#define __INTEL_AUDIO_REGS_H__
-#include "i915_reg_defs.h"
-
-#define G4X_AUD_VID_DID _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x62020)
-#define INTEL_AUDIO_DEVCL 0x808629FB
-#define INTEL_AUDIO_DEVBLC 0x80862801
-#define INTEL_AUDIO_DEVCTG 0x80862802
+#include "intel_display_reg_defs.h"
#define G4X_AUD_CNTL_ST _MMIO(0x620B4)
-#define G4X_ELDV_DEVCL_DEVBLC (1 << 13)
-#define G4X_ELDV_DEVCTG (1 << 14)
-#define G4X_ELD_ADDR_MASK (0xf << 5)
-#define G4X_ELD_ACK (1 << 4)
+#define G4X_ELD_VALID REG_BIT(14)
+#define G4X_ELD_BUFFER_SIZE_MASK REG_GENMASK(13, 9)
+#define G4X_ELD_ADDRESS_MASK REG_GENMASK(8, 5)
+#define G4X_ELD_ACK REG_BIT(4)
#define G4X_HDMIW_HDMIEDID _MMIO(0x6210C)
#define _IBX_HDMIW_HDMIEDID_A 0xE2050
@@ -28,12 +23,12 @@
#define _IBX_AUD_CNTL_ST_B 0xE21B4
#define IBX_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CNTL_ST_A, \
_IBX_AUD_CNTL_ST_B)
-#define IBX_ELD_BUFFER_SIZE_MASK (0x1f << 10)
-#define IBX_ELD_ADDRESS_MASK (0x1f << 5)
-#define IBX_ELD_ACK (1 << 4)
+#define IBX_ELD_BUFFER_SIZE_MASK REG_GENMASK(14, 10)
+#define IBX_ELD_ADDRESS_MASK REG_GENMASK(9, 5)
+#define IBX_ELD_ACK REG_BIT(4)
#define IBX_AUD_CNTL_ST2 _MMIO(0xE20C0)
-#define IBX_CP_READY(port) ((1 << 1) << (((port) - 1) * 4))
-#define IBX_ELD_VALID(port) ((1 << 0) << (((port) - 1) * 4))
+#define IBX_CP_READY(port) REG_BIT(((port) - 1) * 4 + 1)
+#define IBX_ELD_VALID(port) REG_BIT(((port) - 1) * 4 + 0)
#define _CPT_HDMIW_HDMIEDID_A 0xE5050
#define _CPT_HDMIW_HDMIEDID_B 0xE5150
@@ -60,34 +55,30 @@
#define _VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000)
#define _VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100)
#define VLV_AUD_CFG(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CONFIG_A, _VLV_AUD_CONFIG_B)
-
-#define AUD_CONFIG_N_VALUE_INDEX (1 << 29)
-#define AUD_CONFIG_N_PROG_ENABLE (1 << 28)
-#define AUD_CONFIG_UPPER_N_SHIFT 20
-#define AUD_CONFIG_UPPER_N_MASK (0xff << 20)
-#define AUD_CONFIG_LOWER_N_SHIFT 4
-#define AUD_CONFIG_LOWER_N_MASK (0xfff << 4)
-#define AUD_CONFIG_N_MASK (AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK)
-#define AUD_CONFIG_N(n) \
- (((((n) >> 12) & 0xff) << AUD_CONFIG_UPPER_N_SHIFT) | \
- (((n) & 0xfff) << AUD_CONFIG_LOWER_N_SHIFT))
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK (0xf << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 (0 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 (1 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 (2 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 (3 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 (4 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 (5 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 (6 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 (7 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 (8 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 (9 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_296703 (10 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_297000 (11 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_593407 (12 << 16)
-#define AUD_CONFIG_PIXEL_CLOCK_HDMI_594000 (13 << 16)
-#define AUD_CONFIG_DISABLE_NCTS (1 << 3)
+#define AUD_CONFIG_N_VALUE_INDEX REG_BIT(29)
+#define AUD_CONFIG_N_PROG_ENABLE REG_BIT(28)
+#define AUD_CONFIG_UPPER_N_MASK REG_GENMASK(27, 20)
+#define AUD_CONFIG_LOWER_N_MASK REG_GENMASK(15, 4)
+#define AUD_CONFIG_N_MASK (AUD_CONFIG_UPPER_N_MASK | \
+ AUD_CONFIG_LOWER_N_MASK)
+#define AUD_CONFIG_N(n) (REG_FIELD_PREP(AUD_CONFIG_UPPER_N_MASK, (n) >> 12) | \
+ REG_FIELD_PREP(AUD_CONFIG_LOWER_N_MASK, (n) & 0xfff))
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK REG_GENMASK(19, 16)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 0)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 1)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 2)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 3)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 4)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 5)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 6)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 7)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 8)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 9)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_296703 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 10)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_297000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 11)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_593407 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 12)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_594000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 13)
+#define AUD_CONFIG_DISABLE_NCTS REG_BIT(3)
#define _HSW_AUD_CONFIG_A 0x65000
#define _HSW_AUD_CONFIG_B 0x65100
@@ -100,9 +91,9 @@
#define _HSW_AUD_M_CTS_ENABLE_A 0x65028
#define _HSW_AUD_M_CTS_ENABLE_B 0x65128
#define HSW_AUD_M_CTS_ENABLE(trans) _MMIO_TRANS(trans, _HSW_AUD_M_CTS_ENABLE_A, _HSW_AUD_M_CTS_ENABLE_B)
-#define AUD_M_CTS_M_VALUE_INDEX (1 << 21)
-#define AUD_M_CTS_M_PROG_ENABLE (1 << 20)
-#define AUD_CONFIG_M_MASK 0xfffff
+#define AUD_M_CTS_M_VALUE_INDEX REG_BIT(21)
+#define AUD_M_CTS_M_PROG_ENABLE REG_BIT(20)
+#define AUD_CONFIG_M_MASK REG_GENMASK(19, 0)
#define _HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4
#define _HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4
@@ -130,11 +121,11 @@
#define AUD_DP_2DOT0_CTRL(trans) _MMIO_TRANS(trans, _AUD_TCA_DP_2DOT0_CTRL, _AUD_TCB_DP_2DOT0_CTRL)
#define AUD_ENABLE_SDP_SPLIT REG_BIT(31)
-#define HSW_AUD_CHICKENBIT _MMIO(0x65f10)
-#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15)
+#define HSW_AUD_CHICKENBIT _MMIO(0x65f10)
+#define SKL_AUD_CODEC_WAKE_SIGNAL REG_BIT(15)
#define AUD_FREQ_CNTRL _MMIO(0x65900)
-#define AUD_PIN_BUF_CTL _MMIO(0x48414)
+#define AUD_PIN_BUF_CTL _MMIO(0x48414)
#define AUD_PIN_BUF_ENABLE REG_BIT(31)
#define AUD_TS_CDCLK_M _MMIO(0x65ea0)
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c
index beba39a38c87..71af88a70461 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_backlight.c
@@ -10,6 +10,7 @@
#include <acpi/video.h>
+#include "i915_reg.h"
#include "intel_backlight.h"
#include "intel_backlight_regs.h"
#include "intel_connector.h"
diff --git a/drivers/gpu/drm/i915/display/intel_backlight_regs.h b/drivers/gpu/drm/i915/display/intel_backlight_regs.h
index 50c1210f6d5d..344eb8096bd2 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_backlight_regs.h
@@ -6,7 +6,7 @@
#ifndef __INTEL_BACKLIGHT_REGS_H__
#define __INTEL_BACKLIGHT_REGS_H__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
#define _VLV_BLC_PWM_CTL2_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61250)
#define _VLV_BLC_PWM_CTL2_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61350)
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 28bdb936cd1f..572a4e3769f3 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -414,7 +414,7 @@ static void *generate_lfp_data_ptrs(struct drm_i915_private *i915,
ptrs->lvds_entries++;
if (size != 0 || ptrs->lvds_entries != 3) {
- kfree(ptrs);
+ kfree(ptrs_block);
return NULL;
}
@@ -2188,7 +2188,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
const u8 *ddc_pin_map;
int n_entries;
- if (IS_ALDERLAKE_P(i915)) {
+ if (HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) {
ddc_pin_map = adlp_ddc_pin_map;
n_entries = ARRAY_SIZE(adlp_ddc_pin_map);
} else if (IS_ALDERLAKE_S(i915)) {
@@ -2676,6 +2676,14 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata,
drm_dbg_kms(&i915->drm,
"Port %c VBT DP max link rate: %d\n",
port_name(port), dp_max_link_rate);
+
+ /*
+ * FIXME need to implement support for VBT
+ * vswing/preemph tables should this ever trigger.
+ */
+ drm_WARN(&i915->drm, child->use_vbt_vswing,
+ "Port %c asks to use VBT vswing/preemph tables\n",
+ port_name(port));
}
static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c
index 4ace026b29bd..1c236f02b380 100644
--- a/drivers/gpu/drm/i915/display/intel_bw.c
+++ b/drivers/gpu/drm/i915/display/intel_bw.c
@@ -439,7 +439,8 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
return ret;
}
- if (dram_info->type == INTEL_DRAM_LPDDR4 || dram_info->type == INTEL_DRAM_LPDDR5)
+ if (DISPLAY_VER(dev_priv) < 14 &&
+ (dram_info->type == INTEL_DRAM_LPDDR4 || dram_info->type == INTEL_DRAM_LPDDR5))
num_channels *= 2;
qi.deinterleave = qi.deinterleave ? : DIV_ROUND_UP(num_channels, is_y_tile ? 4 : 2);
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index ed05070b7307..b74e36d76013 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -24,6 +24,7 @@
#include <linux/time.h>
#include "hsw_ips.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
#include "intel_audio.h"
@@ -1220,11 +1221,6 @@ static void skl_cdclk_uninit_hw(struct drm_i915_private *dev_priv)
skl_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE);
}
-static bool has_cdclk_squasher(struct drm_i915_private *i915)
-{
- return IS_DG2(i915);
-}
-
struct intel_cdclk_vals {
u32 cdclk;
u16 refclk;
@@ -1520,7 +1516,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv,
return;
}
- if (has_cdclk_squasher(dev_priv))
+ if (HAS_CDCLK_SQUASH(dev_priv))
squash_ctl = intel_de_read(dev_priv, CDCLK_SQUASH_CTL);
if (squash_ctl & CDCLK_SQUASH_ENABLE) {
@@ -1689,6 +1685,38 @@ static u32 cdclk_squash_waveform(struct drm_i915_private *dev_priv,
return 0xffff;
}
+static void icl_cdclk_pll_update(struct drm_i915_private *i915, int vco)
+{
+ if (i915->display.cdclk.hw.vco != 0 &&
+ i915->display.cdclk.hw.vco != vco)
+ icl_cdclk_pll_disable(i915);
+
+ if (i915->display.cdclk.hw.vco != vco)
+ icl_cdclk_pll_enable(i915, vco);
+}
+
+static void bxt_cdclk_pll_update(struct drm_i915_private *i915, int vco)
+{
+ if (i915->display.cdclk.hw.vco != 0 &&
+ i915->display.cdclk.hw.vco != vco)
+ bxt_de_pll_disable(i915);
+
+ if (i915->display.cdclk.hw.vco != vco)
+ bxt_de_pll_enable(i915, vco);
+}
+
+static void dg2_cdclk_squash_program(struct drm_i915_private *i915,
+ u16 waveform)
+{
+ u32 squash_ctl = 0;
+
+ if (waveform)
+ squash_ctl = CDCLK_SQUASH_ENABLE |
+ CDCLK_SQUASH_WINDOW_SIZE(0xf) | waveform;
+
+ intel_de_write(i915, CDCLK_SQUASH_CTL, squash_ctl);
+}
+
static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@@ -1724,21 +1752,10 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0) {
if (dev_priv->display.cdclk.hw.vco != vco)
adlp_cdclk_pll_crawl(dev_priv, vco);
- } else if (DISPLAY_VER(dev_priv) >= 11) {
- if (dev_priv->display.cdclk.hw.vco != 0 &&
- dev_priv->display.cdclk.hw.vco != vco)
- icl_cdclk_pll_disable(dev_priv);
-
- if (dev_priv->display.cdclk.hw.vco != vco)
- icl_cdclk_pll_enable(dev_priv, vco);
- } else {
- if (dev_priv->display.cdclk.hw.vco != 0 &&
- dev_priv->display.cdclk.hw.vco != vco)
- bxt_de_pll_disable(dev_priv);
-
- if (dev_priv->display.cdclk.hw.vco != vco)
- bxt_de_pll_enable(dev_priv, vco);
- }
+ } else if (DISPLAY_VER(dev_priv) >= 11)
+ icl_cdclk_pll_update(dev_priv, vco);
+ else
+ bxt_cdclk_pll_update(dev_priv, vco);
waveform = cdclk_squash_waveform(dev_priv, cdclk);
@@ -1747,15 +1764,8 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
else
clock = cdclk;
- if (has_cdclk_squasher(dev_priv)) {
- u32 squash_ctl = 0;
-
- if (waveform)
- squash_ctl = CDCLK_SQUASH_ENABLE |
- CDCLK_SQUASH_WINDOW_SIZE(0xf) | waveform;
-
- intel_de_write(dev_priv, CDCLK_SQUASH_CTL, squash_ctl);
- }
+ if (HAS_CDCLK_SQUASH(dev_priv))
+ dg2_cdclk_squash_program(dev_priv, waveform);
val = bxt_cdclk_cd2x_div_sel(dev_priv, clock, vco) |
bxt_cdclk_cd2x_pipe(dev_priv, pipe) |
@@ -1845,7 +1855,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
expected = skl_cdclk_decimal(cdclk);
/* Figure out what CD2X divider we should be using for this cdclk */
- if (has_cdclk_squasher(dev_priv))
+ if (HAS_CDCLK_SQUASH(dev_priv))
clock = dev_priv->display.cdclk.hw.vco / 2;
else
clock = dev_priv->display.cdclk.hw.cdclk;
@@ -1976,7 +1986,7 @@ static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv,
* the moment all platforms with squasher use a fixed cd2x
* divider.
*/
- if (!has_cdclk_squasher(dev_priv))
+ if (!HAS_CDCLK_SQUASH(dev_priv))
return false;
return a->cdclk != b->cdclk &&
@@ -2028,7 +2038,7 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv,
* the moment all platforms with squasher use a fixed cd2x
* divider.
*/
- if (has_cdclk_squasher(dev_priv))
+ if (HAS_CDCLK_SQUASH(dev_priv))
return false;
return a->cdclk != b->cdclk &&
@@ -2464,10 +2474,6 @@ static int bdw_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state)
if (min_cdclk < 0)
return min_cdclk;
- /*
- * FIXME should also account for plane ratio
- * once 64bpp pixel formats are supported.
- */
cdclk = bdw_calc_cdclk(min_cdclk);
cdclk_state->logical.cdclk = cdclk;
@@ -2534,10 +2540,6 @@ static int skl_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state)
vco = skl_dpll0_vco(cdclk_state);
- /*
- * FIXME should also account for plane ratio
- * once 64bpp pixel formats are supported.
- */
cdclk = skl_calc_cdclk(min_cdclk, vco);
cdclk_state->logical.vco = vco;
@@ -2754,7 +2756,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
- if (drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
+ if (intel_crtc_needs_modeset(crtc_state))
pipe = INVALID_PIPE;
}
@@ -2762,12 +2764,12 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
drm_dbg_kms(&dev_priv->drm,
- "Can change cdclk via squasher\n");
+ "Can change cdclk via squashing\n");
} else if (intel_cdclk_can_crawl(dev_priv,
&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
drm_dbg_kms(&dev_priv->drm,
- "Can change cdclk via crawl\n");
+ "Can change cdclk via crawling\n");
} else if (pipe != INVALID_PIPE) {
new_cdclk_state->pipe = pipe;
@@ -2777,7 +2779,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
} else if (intel_cdclk_needs_modeset(&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
/* All pipes must be switched off while we change the cdclk. */
- ret = intel_modeset_all_pipes(state);
+ ret = intel_modeset_all_pipes(state, "CDCLK change");
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index 6bda4274eae9..250e83f1f5ac 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -22,12 +22,11 @@
*
*/
+#include "i915_reg.h"
#include "intel_color.h"
#include "intel_de.h"
#include "intel_display_types.h"
-#include "intel_dpll.h"
#include "intel_dsb.h"
-#include "vlv_dsi_pll.h"
struct intel_color_funcs {
int (*color_check)(struct intel_crtc_state *crtc_state);
@@ -186,31 +185,31 @@ static void ilk_update_pipe_csc(struct intel_crtc *crtc,
const u16 coeff[9],
const u16 postoff[3])
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
- intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_HI(pipe), preoff[0]);
- intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_ME(pipe), preoff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_LO(pipe), preoff[2]);
+ intel_de_write_fw(i915, PIPE_CSC_PREOFF_HI(pipe), preoff[0]);
+ intel_de_write_fw(i915, PIPE_CSC_PREOFF_ME(pipe), preoff[1]);
+ intel_de_write_fw(i915, PIPE_CSC_PREOFF_LO(pipe), preoff[2]);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RY_GY(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_RY_GY(pipe),
coeff[0] << 16 | coeff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16);
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RU_GU(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_RU_GU(pipe),
coeff[3] << 16 | coeff[4]);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16);
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RV_GV(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_RV_GV(pipe),
coeff[6] << 16 | coeff[7]);
- intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16);
+ intel_de_write_fw(i915, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16);
- if (DISPLAY_VER(dev_priv) >= 7) {
- intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_HI(pipe),
+ if (DISPLAY_VER(i915) >= 7) {
+ intel_de_write_fw(i915, PIPE_CSC_POSTOFF_HI(pipe),
postoff[0]);
- intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_ME(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_POSTOFF_ME(pipe),
postoff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_LO(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_POSTOFF_LO(pipe),
postoff[2]);
}
}
@@ -220,55 +219,55 @@ static void icl_update_output_csc(struct intel_crtc *crtc,
const u16 coeff[9],
const u16 postoff[3])
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe),
coeff[0] << 16 | coeff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BY(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BY(pipe),
coeff[2] << 16);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe),
coeff[3] << 16 | coeff[4]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BU(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BU(pipe),
coeff[5] << 16);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe),
coeff[6] << 16 | coeff[7]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BV(pipe),
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BV(pipe),
coeff[8] << 16);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]);
- intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]);
+ intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]);
}
static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
/*
* FIXME if there's a gamma LUT after the CSC, we should
* do the range compression using the gamma LUT instead.
*/
return crtc_state->limited_color_range &&
- (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) ||
- IS_DISPLAY_VER(dev_priv, 9, 10));
+ (IS_HASWELL(i915) || IS_BROADWELL(i915) ||
+ IS_DISPLAY_VER(i915, 9, 10));
}
static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
- u16 coeffs[9])
+ u16 coeffs[9], bool limited_color_range)
{
const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data;
const u64 *input;
u64 temp[9];
int i;
- if (ilk_csc_limited_range(crtc_state))
+ if (limited_color_range)
input = ctm_mult_by_limited(temp, ctm->matrix);
else
input = ctm->matrix;
@@ -315,13 +314,13 @@ static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
bool limited_color_range = ilk_csc_limited_range(crtc_state);
if (crtc_state->hw.ctm) {
u16 coeff[9];
- ilk_csc_convert_ctm(crtc_state, coeff);
+ ilk_csc_convert_ctm(crtc_state, coeff, limited_color_range);
ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff,
limited_color_range ?
ilk_csc_postoff_limited_range :
@@ -341,7 +340,7 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
* LUT is needed but CSC is not we need to load an
* identity matrix.
*/
- drm_WARN_ON(&dev_priv->drm, !IS_GEMINILAKE(dev_priv));
+ drm_WARN_ON(&i915->drm, !IS_GEMINILAKE(i915));
ilk_update_pipe_csc(crtc, ilk_csc_off_zero,
ilk_csc_coeff_identity,
@@ -356,7 +355,7 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state)
if (crtc_state->hw.ctm) {
u16 coeff[9];
- ilk_csc_convert_ctm(crtc_state, coeff);
+ ilk_csc_convert_ctm(crtc_state, coeff, false);
ilk_update_pipe_csc(crtc, ilk_csc_off_zero,
coeff, ilk_csc_off_zero);
}
@@ -375,7 +374,7 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state)
static void chv_load_cgm_csc(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_ctm *ctm = blob->data;
enum pipe pipe = crtc->pipe;
u16 coeffs[9];
@@ -399,15 +398,15 @@ static void chv_load_cgm_csc(struct intel_crtc *crtc,
coeffs[i] |= (abs_coeff >> 20) & 0xfff;
}
- intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF01(pipe),
+ intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF01(pipe),
coeffs[1] << 16 | coeffs[0]);
- intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF23(pipe),
+ intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF23(pipe),
coeffs[3] << 16 | coeffs[2]);
- intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF45(pipe),
+ intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF45(pipe),
coeffs[5] << 16 | coeffs[4]);
- intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF67(pipe),
+ intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF67(pipe),
coeffs[7] << 16 | coeffs[6]);
- intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF8(pipe),
+ intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF8(pipe),
coeffs[8]);
}
@@ -426,32 +425,32 @@ static u32 intel_color_lut_pack(u32 val, int bit_precision)
static u32 i9xx_lut_8(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->red, 8) << 16 |
- drm_color_lut_extract(color->green, 8) << 8 |
- drm_color_lut_extract(color->blue, 8);
+ return REG_FIELD_PREP(PALETTE_RED_MASK, drm_color_lut_extract(color->red, 8)) |
+ REG_FIELD_PREP(PALETTE_GREEN_MASK, drm_color_lut_extract(color->green, 8)) |
+ REG_FIELD_PREP(PALETTE_BLUE_MASK, drm_color_lut_extract(color->blue, 8));
}
static void i9xx_lut_8_pack(struct drm_color_lut *entry, u32 val)
{
- entry->red = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_RED_MASK, val), 8);
- entry->green = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_GREEN_MASK, val), 8);
- entry->blue = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_BLUE_MASK, val), 8);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(PALETTE_RED_MASK, val), 8);
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(PALETTE_GREEN_MASK, val), 8);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(PALETTE_BLUE_MASK, val), 8);
}
/* i965+ "10.6" bit interpolated format "even DW" (low 8 bits) */
static u32 i965_lut_10p6_ldw(const struct drm_color_lut *color)
{
- return (color->red & 0xff) << 16 |
- (color->green & 0xff) << 8 |
- (color->blue & 0xff);
+ return REG_FIELD_PREP(PALETTE_RED_MASK, color->red & 0xff) |
+ REG_FIELD_PREP(PALETTE_GREEN_MASK, color->green & 0xff) |
+ REG_FIELD_PREP(PALETTE_BLUE_MASK, color->blue & 0xff);
}
/* i965+ "10.6" interpolated format "odd DW" (high 8 bits) */
static u32 i965_lut_10p6_udw(const struct drm_color_lut *color)
{
- return (color->red >> 8) << 16 |
- (color->green >> 8) << 8 |
- (color->blue >> 8);
+ return REG_FIELD_PREP(PALETTE_RED_MASK, color->red >> 8) |
+ REG_FIELD_PREP(PALETTE_GREEN_MASK, color->green >> 8) |
+ REG_FIELD_PREP(PALETTE_BLUE_MASK, color->blue >> 8);
}
static void i965_lut_10p6_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
@@ -472,26 +471,42 @@ static u16 i965_lut_11p6_max_pack(u32 val)
static u32 ilk_lut_10(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->red, 10) << 20 |
- drm_color_lut_extract(color->green, 10) << 10 |
- drm_color_lut_extract(color->blue, 10);
+ return REG_FIELD_PREP(PREC_PALETTE_10_RED_MASK, drm_color_lut_extract(color->red, 10)) |
+ REG_FIELD_PREP(PREC_PALETTE_10_GREEN_MASK, drm_color_lut_extract(color->green, 10)) |
+ REG_FIELD_PREP(PREC_PALETTE_10_BLUE_MASK, drm_color_lut_extract(color->blue, 10));
}
static void ilk_lut_10_pack(struct drm_color_lut *entry, u32 val)
{
- entry->red = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_RED_MASK, val), 10);
- entry->green = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_GREEN_MASK, val), 10);
- entry->blue = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_BLUE_MASK, val), 10);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_RED_MASK, val), 10);
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_GREEN_MASK, val), 10);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_BLUE_MASK, val), 10);
+}
+
+/* ilk+ "12.4" interpolated format (low 6 bits) */
+static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color)
+{
+ return REG_FIELD_PREP(PREC_PALETTE_12P4_RED_LDW_MASK, color->red & 0x3f) |
+ REG_FIELD_PREP(PREC_PALETTE_12P4_GREEN_LDW_MASK, color->green & 0x3f) |
+ REG_FIELD_PREP(PREC_PALETTE_12P4_BLUE_LDW_MASK, color->blue & 0x3f);
+}
+
+/* ilk+ "12.4" interpolated format (high 10 bits) */
+static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color)
+{
+ return REG_FIELD_PREP(PREC_PALETTE_12P4_RED_UDW_MASK, color->red >> 6) |
+ REG_FIELD_PREP(PREC_PALETTE_12P4_GREEN_UDW_MASK, color->green >> 6) |
+ REG_FIELD_PREP(PREC_PALETTE_12P4_BLUE_UDW_MASK, color->blue >> 6);
}
-static void icl_lut_multi_seg_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
+static void ilk_lut_12p4_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
{
- entry->red = REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_UDW_MASK, udw) << 6 |
- REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_LDW_MASK, ldw);
- entry->green = REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_UDW_MASK, udw) << 6 |
- REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_LDW_MASK, ldw);
- entry->blue = REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_UDW_MASK, udw) << 6 |
- REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw);
+ entry->red = REG_FIELD_GET(PREC_PALETTE_12P4_RED_UDW_MASK, udw) << 6 |
+ REG_FIELD_GET(PREC_PALETTE_12P4_RED_LDW_MASK, ldw);
+ entry->green = REG_FIELD_GET(PREC_PALETTE_12P4_GREEN_UDW_MASK, udw) << 6 |
+ REG_FIELD_GET(PREC_PALETTE_12P4_GREEN_LDW_MASK, ldw);
+ entry->blue = REG_FIELD_GET(PREC_PALETTE_12P4_BLUE_UDW_MASK, udw) << 6 |
+ REG_FIELD_GET(PREC_PALETTE_12P4_BLUE_LDW_MASK, ldw);
}
static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
@@ -513,31 +528,31 @@ static void i9xx_color_commit_arm(const struct intel_crtc_state *crtc_state)
static void ilk_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
/* update PIPECONF GAMMA_MODE */
ilk_set_pipeconf(crtc_state);
- intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
+ intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
+ intel_de_write(i915, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode);
- intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
+ intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
u32 val = 0;
@@ -550,15 +565,65 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
val |= SKL_BOTTOM_COLOR_GAMMA_ENABLE;
if (crtc_state->csc_enable)
val |= SKL_BOTTOM_COLOR_CSC_ENABLE;
- intel_de_write(dev_priv, SKL_BOTTOM_COLOR(pipe), val);
+ intel_de_write(i915, SKL_BOTTOM_COLOR(pipe), val);
- intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe),
+ intel_de_write(i915, GAMMA_MODE(crtc->pipe),
crtc_state->gamma_mode);
- intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe),
+ intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe),
crtc_state->csc_mode);
}
+static struct drm_property_blob *
+create_linear_lut(struct drm_i915_private *i915, int lut_size)
+{
+ struct drm_property_blob *blob;
+ struct drm_color_lut *lut;
+ int i;
+
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * lut_size,
+ NULL);
+ if (IS_ERR(blob))
+ return blob;
+
+ lut = blob->data;
+
+ for (i = 0; i < lut_size; i++) {
+ u16 val = 0xffff * i / (lut_size - 1);
+
+ lut[i].red = val;
+ lut[i].green = val;
+ lut[i].blue = val;
+ }
+
+ return blob;
+}
+
+static struct drm_property_blob *
+create_resized_lut(struct drm_i915_private *i915,
+ const struct drm_property_blob *blob_in, int lut_out_size)
+{
+ int i, lut_in_size = drm_color_lut_size(blob_in);
+ struct drm_property_blob *blob_out;
+ const struct drm_color_lut *lut_in;
+ struct drm_color_lut *lut_out;
+
+ blob_out = drm_property_create_blob(&i915->drm,
+ sizeof(lut_out[0]) * lut_out_size,
+ NULL);
+ if (IS_ERR(blob_out))
+ return blob_out;
+
+ lut_in = blob_in->data;
+ lut_out = blob_out->data;
+
+ for (i = 0; i < lut_out_size; i++)
+ lut_out[i] = lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
+
+ return blob_out;
+}
+
static void i9xx_load_lut_8(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -580,12 +645,9 @@ static void i9xx_load_lut_8(struct intel_crtc *crtc,
static void i9xx_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
- assert_pll_enabled(dev_priv, crtc->pipe);
-
- i9xx_load_lut_8(crtc, gamma_lut);
+ i9xx_load_lut_8(crtc, post_csc_lut);
}
static void i965_load_lut_10p6(struct intel_crtc *crtc,
@@ -611,24 +673,18 @@ static void i965_load_lut_10p6(struct intel_crtc *crtc,
static void i965_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
-
- if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
- assert_dsi_pll_enabled(dev_priv);
- else
- assert_pll_enabled(dev_priv, crtc->pipe);
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
- i9xx_load_lut_8(crtc, gamma_lut);
+ i9xx_load_lut_8(crtc, post_csc_lut);
else
- i965_load_lut_10p6(crtc, gamma_lut);
+ i965_load_lut_10p6(crtc, post_csc_lut);
}
static void ilk_load_lut_8(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut;
enum pipe pipe = crtc->pipe;
int i;
@@ -639,34 +695,36 @@ static void ilk_load_lut_8(struct intel_crtc *crtc,
lut = blob->data;
for (i = 0; i < 256; i++)
- intel_de_write_fw(dev_priv, LGC_PALETTE(pipe, i),
+ intel_de_write_fw(i915, LGC_PALETTE(pipe, i),
i9xx_lut_8(&lut[i]));
}
static void ilk_load_lut_10(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
for (i = 0; i < lut_size; i++)
- intel_de_write_fw(dev_priv, PREC_PALETTE(pipe, i),
+ intel_de_write_fw(i915, PREC_PALETTE(pipe, i),
ilk_lut_10(&lut[i]));
}
static void ilk_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, gamma_lut);
+ ilk_load_lut_8(crtc, blob);
break;
case GAMMA_MODE_MODE_10BIT:
- ilk_load_lut_10(crtc, gamma_lut);
+ ilk_load_lut_10(crtc, blob);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -691,27 +749,22 @@ static void ivb_load_lut_10(struct intel_crtc *crtc,
const struct drm_property_blob *blob,
u32 prec_index)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int hw_lut_size = ivb_lut_10_size(prec_index);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
- for (i = 0; i < hw_lut_size; i++) {
- /* We discard half the user entries in split gamma mode */
- const struct drm_color_lut *entry =
- &lut[i * (lut_size - 1) / (hw_lut_size - 1)];
-
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), prec_index++);
- intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe),
- ilk_lut_10(entry));
+ for (i = 0; i < lut_size; i++) {
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), prec_index++);
+ intel_de_write_fw(i915, PREC_PAL_DATA(pipe),
+ ilk_lut_10(&lut[i]));
}
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
}
/* On BDW+ the index auto increment mode actually works */
@@ -719,73 +772,63 @@ static void bdw_load_lut_10(struct intel_crtc *crtc,
const struct drm_property_blob *blob,
u32 prec_index)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int hw_lut_size = ivb_lut_10_size(prec_index);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe),
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
prec_index | PAL_PREC_AUTO_INCREMENT);
- for (i = 0; i < hw_lut_size; i++) {
- /* We discard half the user entries in split gamma mode */
- const struct drm_color_lut *entry =
- &lut[i * (lut_size - 1) / (hw_lut_size - 1)];
-
- intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe),
- ilk_lut_10(entry));
- }
+ for (i = 0; i < lut_size; i++)
+ intel_de_write_fw(i915, PREC_PAL_DATA(pipe),
+ ilk_lut_10(&lut[i]));
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
}
static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
/* Program the max register to clamp values > 1.0. */
intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), 1 << 16);
intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), 1 << 16);
intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), 1 << 16);
+}
- /*
- * Program the gc max 2 register to clamp values > 1.0.
- * ToDo: Extend the ABI to be able to program values
- * from 3.0 to 7.0
- */
- if (DISPLAY_VER(dev_priv) >= 10) {
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0),
- 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1),
- 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2),
- 1 << 16);
- }
+static void glk_load_lut_ext2_max(const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ enum pipe pipe = crtc->pipe;
+
+ /* Program the max register to clamp values > 1.0. */
+ intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), 1 << 16);
+ intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), 1 << 16);
+ intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), 1 << 16);
}
static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
- const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, blob);
break;
case GAMMA_MODE_MODE_SPLIT:
- ivb_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
+ ivb_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
- ivb_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
+ ivb_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
break;
case GAMMA_MODE_MODE_10BIT:
@@ -802,19 +845,19 @@ static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
static void bdw_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
- const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
- const struct drm_property_blob *blob = gamma_lut ?: degamma_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
ilk_load_lut_8(crtc, blob);
break;
case GAMMA_MODE_MODE_SPLIT:
- bdw_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE |
+ bdw_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
- bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE |
+ bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
break;
case GAMMA_MODE_MODE_10BIT:
@@ -837,21 +880,22 @@ static int glk_degamma_lut_size(struct drm_i915_private *i915)
return 35;
}
-static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state)
+static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ const struct drm_color_lut *lut = blob->data;
+ int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
- int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size;
- const struct drm_color_lut *lut = crtc_state->hw.degamma_lut->data;
/*
* When setting the auto-increment bit, the hardware seems to
* ignore the index bits, so we need to reset it to index 0
* separately.
*/
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe),
+ intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe),
PRE_CSC_GAMC_AUTO_INCREMENT);
for (i = 0; i < lut_size; i++) {
@@ -868,71 +912,34 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state)
* ToDo: Extend to max 7.0. Enable 32 bit input value
* as compared to just 16 to achieve this.
*/
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe),
+ intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe),
lut[i].green);
}
/* Clamp values > 1.0. */
- while (i++ < glk_degamma_lut_size(dev_priv))
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+ while (i++ < glk_degamma_lut_size(i915))
+ intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
-}
-
-static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_state)
-{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
- int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size;
-
- /*
- * When setting the auto-increment bit, the hardware seems to
- * ignore the index bits, so we need to reset it to index 0
- * separately.
- */
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe),
- PRE_CSC_GAMC_AUTO_INCREMENT);
-
- for (i = 0; i < lut_size; i++) {
- u32 v = (i << 16) / (lut_size - 1);
-
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), v);
- }
-
- /* Clamp values > 1.0. */
- while (i++ < 35)
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
-
- intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_luts(const struct intel_crtc_state *crtc_state)
{
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- /*
- * On GLK+ both pipe CSC and degamma LUT are controlled
- * by csc_enable. Hence for the cases where the CSC is
- * needed but degamma LUT is not we need to load a
- * linear degamma LUT. In fact we'll just always load
- * the degama LUT so that we don't have to reload
- * it every time the pipe CSC is being enabled.
- */
- if (crtc_state->hw.degamma_lut)
- glk_load_degamma_lut(crtc_state);
- else
- glk_load_degamma_lut_linear(crtc_state);
+ if (pre_csc_lut)
+ glk_load_degamma_lut(crtc_state, pre_csc_lut);
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, gamma_lut);
+ ilk_load_lut_8(crtc, post_csc_lut);
break;
case GAMMA_MODE_MODE_10BIT:
- bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
+ bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ glk_load_lut_ext2_max(crtc_state);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -940,23 +947,9 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state)
}
}
-/* ilk+ "12.4" interpolated format (high 10 bits) */
-static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color)
-{
- return (color->red >> 6) << 20 | (color->green >> 6) << 10 |
- (color->blue >> 6);
-}
-
-/* ilk+ "12.4" interpolated format (low 6 bits) */
-static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color)
-{
- return (color->red & 0x3f) << 24 | (color->green & 0x3f) << 14 |
- (color->blue & 0x3f) << 4;
-}
-
static void
-icl_load_gcmax(const struct intel_crtc_state *crtc_state,
- const struct drm_color_lut *color)
+ivb_load_lut_max(const struct intel_crtc_state *crtc_state,
+ const struct drm_color_lut *color)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
@@ -971,7 +964,7 @@ static void
icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- const struct drm_property_blob *blob = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *blob = crtc_state->post_csc_lut;
const struct drm_color_lut *lut = blob->data;
enum pipe pipe = crtc->pipe;
int i;
@@ -1000,7 +993,7 @@ static void
icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- const struct drm_property_blob *blob = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *blob = crtc_state->post_csc_lut;
const struct drm_color_lut *lut = blob->data;
const struct drm_color_lut *entry;
enum pipe pipe = crtc->pipe;
@@ -1048,29 +1041,32 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
/* The last entry in the LUT is to be programmed in GCMAX */
entry = &lut[256 * 8 * 128];
- icl_load_gcmax(crtc_state, entry);
- ivb_load_lut_ext_max(crtc_state);
+ ivb_load_lut_max(crtc_state, entry);
}
static void icl_load_luts(const struct intel_crtc_state *crtc_state)
{
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- if (crtc_state->hw.degamma_lut)
- glk_load_degamma_lut(crtc_state);
+ if (pre_csc_lut)
+ glk_load_degamma_lut(crtc_state, pre_csc_lut);
switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, gamma_lut);
+ ilk_load_lut_8(crtc, post_csc_lut);
break;
case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
icl_program_gamma_superfine_segment(crtc_state);
icl_program_gamma_multi_segment(crtc_state);
+ ivb_load_lut_ext_max(crtc_state);
+ glk_load_lut_ext2_max(crtc_state);
break;
case GAMMA_MODE_MODE_10BIT:
- bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0));
+ bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
+ glk_load_lut_ext2_max(crtc_state);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -1082,61 +1078,61 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state)
static u32 chv_cgm_degamma_ldw(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->green, 14) << 16 |
- drm_color_lut_extract(color->blue, 14);
+ return REG_FIELD_PREP(CGM_PIPE_DEGAMMA_GREEN_LDW_MASK, drm_color_lut_extract(color->green, 14)) |
+ REG_FIELD_PREP(CGM_PIPE_DEGAMMA_BLUE_LDW_MASK, drm_color_lut_extract(color->blue, 14));
}
static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->red, 14);
+ return REG_FIELD_PREP(CGM_PIPE_DEGAMMA_RED_UDW_MASK, drm_color_lut_extract(color->red, 14));
}
static void chv_load_cgm_degamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
for (i = 0; i < lut_size; i++) {
- intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 0),
+ intel_de_write_fw(i915, CGM_PIPE_DEGAMMA(pipe, i, 0),
chv_cgm_degamma_ldw(&lut[i]));
- intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 1),
+ intel_de_write_fw(i915, CGM_PIPE_DEGAMMA(pipe, i, 1),
chv_cgm_degamma_udw(&lut[i]));
}
}
static u32 chv_cgm_gamma_ldw(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->green, 10) << 16 |
- drm_color_lut_extract(color->blue, 10);
+ return REG_FIELD_PREP(CGM_PIPE_GAMMA_GREEN_LDW_MASK, drm_color_lut_extract(color->green, 10)) |
+ REG_FIELD_PREP(CGM_PIPE_GAMMA_BLUE_LDW_MASK, drm_color_lut_extract(color->blue, 10));
}
static u32 chv_cgm_gamma_udw(const struct drm_color_lut *color)
{
- return drm_color_lut_extract(color->red, 10);
+ return REG_FIELD_PREP(CGM_PIPE_GAMMA_RED_UDW_MASK, drm_color_lut_extract(color->red, 10));
}
static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
{
- entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10);
- entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10);
- entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10);
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_LDW_MASK, ldw), 10);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_LDW_MASK, ldw), 10);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_UDW_MASK, udw), 10);
}
static void chv_load_cgm_gamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
for (i = 0; i < lut_size; i++) {
- intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0),
+ intel_de_write_fw(i915, CGM_PIPE_GAMMA(pipe, i, 0),
chv_cgm_gamma_ldw(&lut[i]));
- intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1),
+ intel_de_write_fw(i915, CGM_PIPE_GAMMA(pipe, i, 1),
chv_cgm_gamma_udw(&lut[i]));
}
}
@@ -1144,46 +1140,46 @@ static void chv_load_cgm_gamma(struct intel_crtc *crtc,
static void chv_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
- const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
+ const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
const struct drm_property_blob *ctm = crtc_state->hw.ctm;
if (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC)
chv_load_cgm_csc(crtc, ctm);
if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
- chv_load_cgm_degamma(crtc, degamma_lut);
+ chv_load_cgm_degamma(crtc, pre_csc_lut);
if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
- chv_load_cgm_gamma(crtc, gamma_lut);
+ chv_load_cgm_gamma(crtc, post_csc_lut);
else
i965_load_luts(crtc_state);
- intel_de_write_fw(dev_priv, CGM_PIPE_MODE(crtc->pipe),
+ intel_de_write_fw(i915, CGM_PIPE_MODE(crtc->pipe),
crtc_state->cgm_mode);
}
void intel_color_load_luts(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- dev_priv->display.funcs.color->load_luts(crtc_state);
+ i915->display.funcs.color->load_luts(crtc_state);
}
void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- if (dev_priv->display.funcs.color->color_commit_noarm)
- dev_priv->display.funcs.color->color_commit_noarm(crtc_state);
+ if (i915->display.funcs.color->color_commit_noarm)
+ i915->display.funcs.color->color_commit_noarm(crtc_state);
}
void intel_color_commit_arm(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- dev_priv->display.funcs.color->color_commit_arm(crtc_state);
+ i915->display.funcs.color->color_commit_arm(crtc_state);
}
static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
@@ -1194,8 +1190,8 @@ static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
- return !old_crtc_state->hw.gamma_lut &&
- !old_crtc_state->hw.degamma_lut;
+ return !old_crtc_state->post_csc_lut &&
+ !old_crtc_state->pre_csc_lut;
}
static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
@@ -1214,46 +1210,28 @@ static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode)
return false;
- return !old_crtc_state->hw.gamma_lut;
-}
-
-static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
-{
- struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
- struct intel_atomic_state *state =
- to_intel_atomic_state(new_crtc_state->uapi.state);
- const struct intel_crtc_state *old_crtc_state =
- intel_atomic_get_old_crtc_state(state, crtc);
-
- /*
- * The hardware degamma is active whenever the pipe
- * CSC is active. Thus even if the old state has no
- * software degamma we need to avoid clobbering the
- * linear hardware degamma mid scanout.
- */
- return !old_crtc_state->csc_enable &&
- !old_crtc_state->hw.gamma_lut;
+ return !old_crtc_state->post_csc_lut;
}
int intel_color_check(struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- return dev_priv->display.funcs.color->color_check(crtc_state);
+ return i915->display.funcs.color->color_check(crtc_state);
}
void intel_color_get_config(struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- if (dev_priv->display.funcs.color->read_luts)
- dev_priv->display.funcs.color->read_luts(crtc_state);
+ if (i915->display.funcs.color->read_luts)
+ i915->display.funcs.color->read_luts(crtc_state);
}
static bool need_plane_update(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+ struct drm_i915_private *i915 = to_i915(plane->base.dev);
/*
* On pre-SKL the pipe gamma enable and pipe csc enable for
@@ -1261,7 +1239,7 @@ static bool need_plane_update(struct intel_plane *plane,
* We have to reconfigure that even if the plane is inactive.
*/
return crtc_state->active_planes & BIT(plane->id) ||
- (DISPLAY_VER(dev_priv) < 9 &&
+ (DISPLAY_VER(i915) < 9 &&
plane->id == PLANE_PRIMARY);
}
@@ -1269,7 +1247,7 @@ static int
intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
struct intel_atomic_state *state =
to_intel_atomic_state(new_crtc_state->uapi.state);
const struct intel_crtc_state *old_crtc_state =
@@ -1277,14 +1255,14 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state)
struct intel_plane *plane;
if (!new_crtc_state->hw.active ||
- drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi))
+ intel_crtc_needs_modeset(new_crtc_state))
return 0;
if (new_crtc_state->gamma_enable == old_crtc_state->gamma_enable &&
new_crtc_state->csc_enable == old_crtc_state->csc_enable)
return 0;
- for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+ for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) {
struct intel_plane_state *plane_state;
if (!need_plane_update(plane, new_crtc_state))
@@ -1295,6 +1273,10 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state)
return PTR_ERR(plane_state);
new_crtc_state->update_planes |= BIT(plane->id);
+
+ /* plane control register changes blocked by CxSR */
+ if (HAS_GMCH(i915))
+ new_crtc_state->disable_cxsr = true;
}
return 0;
@@ -1319,7 +1301,7 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected)
static int check_luts(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
int gamma_length, degamma_length;
@@ -1331,15 +1313,15 @@ static int check_luts(const struct intel_crtc_state *crtc_state)
/* C8 relies on its palette being stored in the legacy LUT */
if (crtc_state->c8_planes) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"C8 pixelformat requires the legacy LUT\n");
return -EINVAL;
}
- degamma_length = INTEL_INFO(dev_priv)->display.color.degamma_lut_size;
- gamma_length = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
- degamma_tests = INTEL_INFO(dev_priv)->display.color.degamma_lut_tests;
- gamma_tests = INTEL_INFO(dev_priv)->display.color.gamma_lut_tests;
+ degamma_length = INTEL_INFO(i915)->display.color.degamma_lut_size;
+ gamma_length = INTEL_INFO(i915)->display.color.gamma_lut_size;
+ degamma_tests = INTEL_INFO(i915)->display.color.degamma_lut_tests;
+ gamma_tests = INTEL_INFO(i915)->display.color.gamma_lut_tests;
if (check_lut_size(degamma_lut, degamma_length) ||
check_lut_size(gamma_lut, gamma_length))
@@ -1361,6 +1343,40 @@ static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state)
return GAMMA_MODE_MODE_10BIT; /* i965+ only */
}
+void intel_color_assert_luts(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ /* make sure {pre,post}_csc_lut were correctly assigned */
+ if (DISPLAY_VER(i915) >= 11 || HAS_GMCH(i915)) {
+ drm_WARN_ON(&i915->drm,
+ crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut);
+ drm_WARN_ON(&i915->drm,
+ crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
+ } else if (DISPLAY_VER(i915) == 10) {
+ drm_WARN_ON(&i915->drm,
+ crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
+ crtc_state->pre_csc_lut != i915->display.color.glk_linear_degamma_lut);
+ drm_WARN_ON(&i915->drm,
+ crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
+ } else if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
+ drm_WARN_ON(&i915->drm,
+ crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
+ crtc_state->pre_csc_lut != crtc_state->hw.gamma_lut);
+ drm_WARN_ON(&i915->drm,
+ crtc_state->post_csc_lut != crtc_state->hw.degamma_lut &&
+ crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
+ }
+}
+
+static void intel_assign_luts(struct intel_crtc_state *crtc_state)
+{
+ drm_property_replace_blob(&crtc_state->pre_csc_lut,
+ crtc_state->hw.degamma_lut);
+ drm_property_replace_blob(&crtc_state->post_csc_lut,
+ crtc_state->hw.gamma_lut);
+}
+
static int i9xx_color_check(struct intel_crtc_state *crtc_state)
{
int ret;
@@ -1379,6 +1395,8 @@ static int i9xx_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
+ intel_assign_luts(crtc_state);
+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
return 0;
@@ -1433,11 +1451,27 @@ static int chv_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
+ intel_assign_luts(crtc_state);
+
crtc_state->preload_luts = chv_can_preload_luts(crtc_state);
return 0;
}
+static bool ilk_gamma_enable(const struct intel_crtc_state *crtc_state)
+{
+ return (crtc_state->hw.gamma_lut ||
+ crtc_state->hw.degamma_lut) &&
+ !crtc_state->c8_planes;
+}
+
+static bool ilk_csc_enable(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
+ ilk_csc_limited_range(crtc_state) ||
+ crtc_state->hw.ctm;
+}
+
static u32 ilk_gamma_mode(const struct intel_crtc_state *crtc_state)
{
if (!crtc_state->gamma_enable ||
@@ -1458,28 +1492,54 @@ static u32 ilk_csc_mode(const struct intel_crtc_state *crtc_state)
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)
return CSC_BLACK_SCREEN_OFFSET;
+ if (crtc_state->hw.degamma_lut)
+ return CSC_MODE_YUV_TO_RGB;
+
return CSC_MODE_YUV_TO_RGB |
CSC_POSITION_BEFORE_GAMMA;
}
+static void ilk_assign_luts(struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->hw.degamma_lut ||
+ crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) {
+ drm_property_replace_blob(&crtc_state->pre_csc_lut,
+ crtc_state->hw.degamma_lut);
+ drm_property_replace_blob(&crtc_state->post_csc_lut,
+ crtc_state->hw.gamma_lut);
+ } else {
+ drm_property_replace_blob(&crtc_state->pre_csc_lut,
+ crtc_state->hw.gamma_lut);
+ drm_property_replace_blob(&crtc_state->post_csc_lut,
+ NULL);
+ }
+}
+
static int ilk_color_check(struct intel_crtc_state *crtc_state)
{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int ret;
ret = check_luts(crtc_state);
if (ret)
return ret;
- crtc_state->gamma_enable =
- crtc_state->hw.gamma_lut &&
- !crtc_state->c8_planes;
+ if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
+ drm_dbg_kms(&i915->drm,
+ "Degamma and gamma together are not possible\n");
+ return -EINVAL;
+ }
- /*
- * We don't expose the ctm on ilk/snb currently, also RGB
- * limited range output is handled by the hw automagically.
- */
- crtc_state->csc_enable =
- crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB;
+ if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
+ crtc_state->hw.ctm) {
+ drm_dbg_kms(&i915->drm,
+ "YCbCr and CTM together are not possible\n");
+ return -EINVAL;
+ }
+
+ crtc_state->gamma_enable = ilk_gamma_enable(crtc_state);
+
+ crtc_state->csc_enable = ilk_csc_enable(crtc_state);
crtc_state->gamma_mode = ilk_gamma_mode(crtc_state);
@@ -1489,6 +1549,8 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
+ ilk_assign_luts(crtc_state);
+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
return 0;
@@ -1496,14 +1558,10 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
static u32 ivb_gamma_mode(const struct intel_crtc_state *crtc_state)
{
- if (!crtc_state->gamma_enable ||
- crtc_state_is_legacy_gamma(crtc_state))
- return GAMMA_MODE_MODE_8BIT;
- else if (crtc_state->hw.gamma_lut &&
- crtc_state->hw.degamma_lut)
+ if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut)
return GAMMA_MODE_MODE_SPLIT;
- else
- return GAMMA_MODE_MODE_10BIT;
+
+ return ilk_gamma_mode(crtc_state);
}
static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state)
@@ -1522,10 +1580,41 @@ static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state)
return CSC_POSITION_BEFORE_GAMMA;
}
+static int ivb_assign_luts(struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_property_blob *degamma_lut, *gamma_lut;
+
+ if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
+ ilk_assign_luts(crtc_state);
+ return 0;
+ }
+
+ drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state->hw.degamma_lut) != 1024);
+ drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state->hw.gamma_lut) != 1024);
+
+ degamma_lut = create_resized_lut(i915, crtc_state->hw.degamma_lut, 512);
+ if (IS_ERR(degamma_lut))
+ return PTR_ERR(degamma_lut);
+
+ gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut, 512);
+ if (IS_ERR(gamma_lut)) {
+ drm_property_blob_put(degamma_lut);
+ return PTR_ERR(gamma_lut);
+ }
+
+ drm_property_replace_blob(&crtc_state->pre_csc_lut, degamma_lut);
+ drm_property_replace_blob(&crtc_state->post_csc_lut, gamma_lut);
+
+ drm_property_blob_put(degamma_lut);
+ drm_property_blob_put(gamma_lut);
+
+ return 0;
+}
+
static int ivb_color_check(struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- bool limited_color_range = ilk_csc_limited_range(crtc_state);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int ret;
ret = check_luts(crtc_state);
@@ -1534,19 +1623,21 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
crtc_state->hw.ctm) {
- drm_dbg_kms(&dev_priv->drm,
- "YCBCR and CTM together are not possible\n");
+ drm_dbg_kms(&i915->drm,
+ "YCbCr and CTM together are not possible\n");
return -EINVAL;
}
- crtc_state->gamma_enable =
- (crtc_state->hw.gamma_lut ||
- crtc_state->hw.degamma_lut) &&
- !crtc_state->c8_planes;
+ if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
+ crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
+ drm_dbg_kms(&i915->drm,
+ "YCbCr and degamma+gamma together are not possible\n");
+ return -EINVAL;
+ }
- crtc_state->csc_enable =
- crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
- crtc_state->hw.ctm || limited_color_range;
+ crtc_state->gamma_enable = ilk_gamma_enable(crtc_state);
+
+ crtc_state->csc_enable = ilk_csc_enable(crtc_state);
crtc_state->gamma_mode = ivb_gamma_mode(crtc_state);
@@ -1556,6 +1647,10 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
+ ret = ivb_assign_luts(crtc_state);
+ if (ret)
+ return ret;
+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
return 0;
@@ -1570,9 +1665,26 @@ static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state)
return GAMMA_MODE_MODE_10BIT;
}
+static void glk_assign_luts(struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ intel_assign_luts(crtc_state);
+
+ /*
+ * On GLK+ both pipe CSC and degamma LUT are controlled
+ * by csc_enable. Hence for the cases where the CSC is
+ * needed but degamma LUT is not we need to load a
+ * linear degamma LUT.
+ */
+ if (crtc_state->csc_enable && !crtc_state->pre_csc_lut)
+ drm_property_replace_blob(&crtc_state->pre_csc_lut,
+ i915->display.color.glk_linear_degamma_lut);
+}
+
static int glk_color_check(struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int ret;
ret = check_luts(crtc_state);
@@ -1581,8 +1693,15 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
crtc_state->hw.ctm) {
- drm_dbg_kms(&dev_priv->drm,
- "YCBCR and CTM together are not possible\n");
+ drm_dbg_kms(&i915->drm,
+ "YCbCr and CTM together are not possible\n");
+ return -EINVAL;
+ }
+
+ if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
+ crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
+ drm_dbg_kms(&i915->drm,
+ "YCbCr and degamma+gamma together are not possible\n");
return -EINVAL;
}
@@ -1604,7 +1723,9 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
- crtc_state->preload_luts = glk_can_preload_luts(crtc_state);
+ glk_assign_luts(crtc_state);
+
+ crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
return 0;
}
@@ -1664,6 +1785,8 @@ static int icl_color_check(struct intel_crtc_state *crtc_state)
crtc_state->csc_mode = icl_csc_mode(crtc_state);
+ intel_assign_luts(crtc_state);
+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
return 0;
@@ -1749,19 +1872,19 @@ static int icl_gamma_precision(const struct intel_crtc_state *crtc_state)
int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- if (HAS_GMCH(dev_priv)) {
- if (IS_CHERRYVIEW(dev_priv))
+ if (HAS_GMCH(i915)) {
+ if (IS_CHERRYVIEW(i915))
return chv_gamma_precision(crtc_state);
else
return i9xx_gamma_precision(crtc_state);
} else {
- if (DISPLAY_VER(dev_priv) >= 11)
+ if (DISPLAY_VER(i915) >= 11)
return icl_gamma_precision(crtc_state);
- else if (DISPLAY_VER(dev_priv) == 10)
+ else if (DISPLAY_VER(i915) == 10)
return glk_gamma_precision(crtc_state);
- else if (IS_IRONLAKE(dev_priv))
+ else if (IS_IRONLAKE(i915))
return ilk_gamma_precision(crtc_state);
}
@@ -1846,7 +1969,7 @@ static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc)
int i;
blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH,
+ sizeof(lut[0]) * LEGACY_LUT_LENGTH,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1869,7 +1992,7 @@ static void i9xx_read_luts(struct intel_crtc_state *crtc_state)
if (!crtc_state->gamma_enable)
return;
- crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc);
+ crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
}
static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc)
@@ -1881,7 +2004,7 @@ static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc)
struct drm_color_lut *lut;
blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * lut_size,
+ sizeof(lut[0]) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1910,21 +2033,21 @@ static void i965_read_luts(struct intel_crtc_state *crtc_state)
return;
if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
- crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc);
+ crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
else
- crtc_state->hw.gamma_lut = i965_read_lut_10p6(crtc);
+ crtc_state->post_csc_lut = i965_read_lut_10p6(crtc);
}
static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
- blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * lut_size,
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1932,8 +2055,8 @@ static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc)
lut = blob->data;
for (i = 0; i < lut_size; i++) {
- u32 ldw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0));
- u32 udw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1));
+ u32 ldw = intel_de_read_fw(i915, CGM_PIPE_GAMMA(pipe, i, 0));
+ u32 udw = intel_de_read_fw(i915, CGM_PIPE_GAMMA(pipe, i, 1));
chv_cgm_gamma_pack(&lut[i], ldw, udw);
}
@@ -1946,21 +2069,21 @@ static void chv_read_luts(struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
- crtc_state->hw.gamma_lut = chv_read_cgm_gamma(crtc);
+ crtc_state->post_csc_lut = chv_read_cgm_gamma(crtc);
else
i965_read_luts(crtc_state);
}
static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
int i;
- blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH,
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * LEGACY_LUT_LENGTH,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1968,7 +2091,7 @@ static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc)
lut = blob->data;
for (i = 0; i < LEGACY_LUT_LENGTH; i++) {
- u32 val = intel_de_read_fw(dev_priv, LGC_PALETTE(pipe, i));
+ u32 val = intel_de_read_fw(i915, LGC_PALETTE(pipe, i));
i9xx_lut_8_pack(&lut[i], val);
}
@@ -1978,14 +2101,14 @@ static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc)
static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
- blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * lut_size,
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
@@ -1993,7 +2116,7 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc)
lut = blob->data;
for (i = 0; i < lut_size; i++) {
- u32 val = intel_de_read_fw(dev_priv, PREC_PALETTE(pipe, i));
+ u32 val = intel_de_read_fw(i915, PREC_PALETTE(pipe, i));
ilk_lut_10_pack(&lut[i], val);
}
@@ -2013,10 +2136,10 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state)
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
+ crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
break;
case GAMMA_MODE_MODE_10BIT:
- crtc_state->hw.gamma_lut = ilk_read_lut_10(crtc);
+ crtc_state->post_csc_lut = ilk_read_lut_10(crtc);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -2028,33 +2151,33 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state)
static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
u32 prec_index)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
int i, hw_lut_size = ivb_lut_10_size(prec_index);
- int lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
+ int lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
- drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size);
+ drm_WARN_ON(&i915->drm, lut_size != hw_lut_size);
- blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * lut_size,
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
lut = blob->data;
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe),
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
prec_index | PAL_PREC_AUTO_INCREMENT);
for (i = 0; i < lut_size; i++) {
- u32 val = intel_de_read_fw(dev_priv, PREC_PAL_DATA(pipe));
+ u32 val = intel_de_read_fw(i915, PREC_PAL_DATA(pipe));
ilk_lut_10_pack(&lut[i], val);
}
- intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
return blob;
}
@@ -2068,10 +2191,10 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state)
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
+ crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
break;
case GAMMA_MODE_MODE_10BIT:
- crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -2082,31 +2205,31 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state)
static struct drm_property_blob *
icl_read_lut_multi_segment(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
- blob = drm_property_create_blob(&dev_priv->drm,
- sizeof(struct drm_color_lut) * lut_size,
+ blob = drm_property_create_blob(&i915->drm,
+ sizeof(lut[0]) * lut_size,
NULL);
if (IS_ERR(blob))
return NULL;
lut = blob->data;
- intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe),
PAL_PREC_AUTO_INCREMENT);
for (i = 0; i < 9; i++) {
- u32 ldw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe));
- u32 udw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe));
+ u32 ldw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe));
+ u32 udw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe));
- icl_lut_multi_seg_pack(&lut[i], ldw, udw);
+ ilk_lut_12p4_pack(&lut[i], ldw, udw);
}
- intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe), 0);
/*
* FIXME readouts from PAL_PREC_DATA register aren't giving
@@ -2126,13 +2249,13 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
case GAMMA_MODE_MODE_8BIT:
- crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc);
+ crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
break;
case GAMMA_MODE_MODE_10BIT:
- crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
break;
case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
- crtc_state->hw.gamma_lut = icl_read_lut_multi_segment(crtc);
+ crtc_state->post_csc_lut = icl_read_lut_multi_segment(crtc);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -2217,41 +2340,58 @@ static const struct intel_color_funcs ilk_color_funcs = {
.read_luts = ilk_read_luts,
};
-void intel_color_init(struct intel_crtc *crtc)
+void intel_color_crtc_init(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- bool has_ctm = INTEL_INFO(dev_priv)->display.color.degamma_lut_size != 0;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ bool has_ctm = INTEL_INFO(i915)->display.color.degamma_lut_size != 0;
drm_mode_crtc_set_gamma_size(&crtc->base, 256);
- if (HAS_GMCH(dev_priv)) {
- if (IS_CHERRYVIEW(dev_priv)) {
- dev_priv->display.funcs.color = &chv_color_funcs;
- } else if (DISPLAY_VER(dev_priv) >= 4) {
- dev_priv->display.funcs.color = &i965_color_funcs;
- } else {
- dev_priv->display.funcs.color = &i9xx_color_funcs;
- }
- } else {
- if (DISPLAY_VER(dev_priv) >= 11)
- dev_priv->display.funcs.color = &icl_color_funcs;
- else if (DISPLAY_VER(dev_priv) == 10)
- dev_priv->display.funcs.color = &glk_color_funcs;
- else if (DISPLAY_VER(dev_priv) == 9)
- dev_priv->display.funcs.color = &skl_color_funcs;
- else if (DISPLAY_VER(dev_priv) == 8)
- dev_priv->display.funcs.color = &bdw_color_funcs;
- else if (DISPLAY_VER(dev_priv) == 7) {
- if (IS_HASWELL(dev_priv))
- dev_priv->display.funcs.color = &hsw_color_funcs;
- else
- dev_priv->display.funcs.color = &ivb_color_funcs;
- } else
- dev_priv->display.funcs.color = &ilk_color_funcs;
- }
-
drm_crtc_enable_color_mgmt(&crtc->base,
- INTEL_INFO(dev_priv)->display.color.degamma_lut_size,
+ INTEL_INFO(i915)->display.color.degamma_lut_size,
has_ctm,
- INTEL_INFO(dev_priv)->display.color.gamma_lut_size);
+ INTEL_INFO(i915)->display.color.gamma_lut_size);
+}
+
+int intel_color_init(struct drm_i915_private *i915)
+{
+ struct drm_property_blob *blob;
+
+ if (DISPLAY_VER(i915) != 10)
+ return 0;
+
+ blob = create_linear_lut(i915, INTEL_INFO(i915)->display.color.degamma_lut_size);
+ if (IS_ERR(blob))
+ return PTR_ERR(blob);
+
+ i915->display.color.glk_linear_degamma_lut = blob;
+
+ return 0;
+}
+
+void intel_color_init_hooks(struct drm_i915_private *i915)
+{
+ if (HAS_GMCH(i915)) {
+ if (IS_CHERRYVIEW(i915))
+ i915->display.funcs.color = &chv_color_funcs;
+ else if (DISPLAY_VER(i915) >= 4)
+ i915->display.funcs.color = &i965_color_funcs;
+ else
+ i915->display.funcs.color = &i9xx_color_funcs;
+ } else {
+ if (DISPLAY_VER(i915) >= 11)
+ i915->display.funcs.color = &icl_color_funcs;
+ else if (DISPLAY_VER(i915) == 10)
+ i915->display.funcs.color = &glk_color_funcs;
+ else if (DISPLAY_VER(i915) == 9)
+ i915->display.funcs.color = &skl_color_funcs;
+ else if (DISPLAY_VER(i915) == 8)
+ i915->display.funcs.color = &bdw_color_funcs;
+ else if (IS_HASWELL(i915))
+ i915->display.funcs.color = &hsw_color_funcs;
+ else if (DISPLAY_VER(i915) == 7)
+ i915->display.funcs.color = &ivb_color_funcs;
+ else
+ i915->display.funcs.color = &ilk_color_funcs;
+ }
}
diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h
index fd873425e082..2a5ada67774d 100644
--- a/drivers/gpu/drm/i915/display/intel_color.h
+++ b/drivers/gpu/drm/i915/display/intel_color.h
@@ -10,9 +10,12 @@
struct intel_crtc_state;
struct intel_crtc;
+struct drm_i915_private;
struct drm_property_blob;
-void intel_color_init(struct intel_crtc *crtc);
+void intel_color_init_hooks(struct drm_i915_private *i915);
+int intel_color_init(struct drm_i915_private *i915);
+void intel_color_crtc_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state);
void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state);
void intel_color_commit_arm(const struct intel_crtc_state *crtc_state);
@@ -22,5 +25,6 @@ int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_stat
bool intel_color_lut_equal(struct drm_property_blob *blob1,
struct drm_property_blob *blob2,
u32 gamma_mode, u32 bit_precision);
+void intel_color_assert_luts(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_COLOR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c
index 64890f39c3cc..8b870b2dd4f9 100644
--- a/drivers/gpu/drm/i915/display/intel_combo_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c
@@ -3,6 +3,7 @@
* Copyright © 2018 Intel Corporation
*/
+#include "i915_reg.h"
#include "intel_combo_phy.h"
#include "intel_combo_phy_regs.h"
#include "intel_de.h"
@@ -53,7 +54,6 @@ static const struct icl_procmon {
static const struct icl_procmon *
icl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy)
{
- const struct icl_procmon *procmon;
u32 val;
val = intel_de_read(dev_priv, ICL_PORT_COMP_DW3(phy));
@@ -62,23 +62,16 @@ icl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy)
MISSING_CASE(val);
fallthrough;
case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0:
- procmon = &icl_procmon_values[PROCMON_0_85V_DOT_0];
- break;
+ return &icl_procmon_values[PROCMON_0_85V_DOT_0];
case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_0:
- procmon = &icl_procmon_values[PROCMON_0_95V_DOT_0];
- break;
+ return &icl_procmon_values[PROCMON_0_95V_DOT_0];
case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_1:
- procmon = &icl_procmon_values[PROCMON_0_95V_DOT_1];
- break;
+ return &icl_procmon_values[PROCMON_0_95V_DOT_1];
case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_0:
- procmon = &icl_procmon_values[PROCMON_1_05V_DOT_0];
- break;
+ return &icl_procmon_values[PROCMON_1_05V_DOT_0];
case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_1:
- procmon = &icl_procmon_values[PROCMON_1_05V_DOT_1];
- break;
+ return &icl_procmon_values[PROCMON_1_05V_DOT_1];
}
-
- return procmon;
}
static void icl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 6d5cbeb8df4d..6205ddd3ded0 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -293,3 +293,21 @@ intel_attach_dp_colorspace_property(struct drm_connector *connector)
if (!drm_mode_create_dp_colorspace_property(connector))
drm_connector_attach_colorspace_property(connector);
}
+
+void
+intel_attach_scaling_mode_property(struct drm_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->dev);
+ u32 scaling_modes;
+
+ scaling_modes = BIT(DRM_MODE_SCALE_ASPECT) |
+ BIT(DRM_MODE_SCALE_FULLSCREEN);
+
+ /* On GMCH platforms borders are only possible on the LVDS port */
+ if (!HAS_GMCH(i915) || connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ scaling_modes |= BIT(DRM_MODE_SCALE_CENTER);
+
+ drm_connector_attach_scaling_mode_property(connector, scaling_modes);
+
+ connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h
index 661a37a3c6d8..9d2bc261b204 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.h
+++ b/drivers/gpu/drm/i915/display/intel_connector.h
@@ -6,7 +6,7 @@
#ifndef __INTEL_CONNECTOR_H__
#define __INTEL_CONNECTOR_H__
-#include "intel_display.h"
+#include <linux/types.h>
struct drm_connector;
struct edid;
@@ -32,5 +32,6 @@ void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
void intel_attach_aspect_ratio_property(struct drm_connector *connector);
void intel_attach_hdmi_colorspace_property(struct drm_connector *connector);
void intel_attach_dp_colorspace_property(struct drm_connector *connector);
+void intel_attach_scaling_mode_property(struct drm_connector *connector);
#endif /* __INTEL_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 4a8ff2f97608..797ad9489f7e 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -34,6 +34,8 @@
#include <drm/drm_probe_helper.h>
#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_connector.h"
#include "intel_crt.h"
#include "intel_crtc.h"
@@ -1044,17 +1046,14 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
intel_connector_attach_encoder(intel_connector, &crt->base);
crt->base.type = INTEL_OUTPUT_ANALOG;
- crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI);
+ crt->base.cloneable = BIT(INTEL_OUTPUT_DVO) | BIT(INTEL_OUTPUT_HDMI);
if (IS_I830(dev_priv))
crt->base.pipe_mask = BIT(PIPE_A);
else
crt->base.pipe_mask = ~0;
- if (DISPLAY_VER(dev_priv) == 2)
- connector->interlace_allowed = 0;
- else
- connector->interlace_allowed = 1;
- connector->doublescan_allowed = 0;
+ if (DISPLAY_VER(dev_priv) != 2)
+ connector->interlace_allowed = true;
crt->adpa_reg = adpa_reg;
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 6792a9056f46..037fc140b585 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -365,9 +365,8 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
- intel_color_init(crtc);
-
- intel_crtc_drrs_init(crtc);
+ intel_color_crtc_init(crtc);
+ intel_drrs_crtc_init(crtc);
intel_crtc_crc_init(crtc);
cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE);
@@ -387,8 +386,7 @@ static bool intel_crtc_needs_vblank_work(const struct intel_crtc_state *crtc_sta
return crtc_state->hw.active &&
!intel_crtc_needs_modeset(crtc_state) &&
!crtc_state->preload_luts &&
- (crtc_state->uapi.color_mgmt_changed ||
- crtc_state->update_pipe);
+ intel_crtc_needs_color_update(crtc_state);
}
static void intel_crtc_vblank_work(struct kthread_work *base)
diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
index e9212f69c360..e3273fe8ddac 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
@@ -298,11 +298,13 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
pipe_config->csc_mode, pipe_config->gamma_mode,
pipe_config->gamma_enable, pipe_config->csc_enable);
- drm_dbg_kms(&i915->drm, "degamma lut: %d entries, gamma lut: %d entries\n",
- pipe_config->hw.degamma_lut ?
- drm_color_lut_size(pipe_config->hw.degamma_lut) : 0,
- pipe_config->hw.gamma_lut ?
- drm_color_lut_size(pipe_config->hw.gamma_lut) : 0);
+ drm_dbg_kms(&i915->drm, "pre csc lut: %s%d entries, post csc lut: %d entries\n",
+ pipe_config->pre_csc_lut && pipe_config->pre_csc_lut ==
+ i915->display.color.glk_linear_degamma_lut ? "(linear) " : "",
+ pipe_config->pre_csc_lut ?
+ drm_color_lut_size(pipe_config->pre_csc_lut) : 0,
+ pipe_config->post_csc_lut ?
+ drm_color_lut_size(pipe_config->post_csc_lut) : 0);
dump_planes:
if (!state)
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 87899e89b3a7..d190fa0d393b 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -10,12 +10,13 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
#include "intel_cursor.h"
#include "intel_de.h"
-#include "intel_display_types.h"
#include "intel_display.h"
+#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_fb_pin.h"
#include "intel_frontbuffer.h"
@@ -631,8 +632,10 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
*
* FIXME bigjoiner fastpath would be good
*/
- if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) ||
- crtc_state->update_pipe || crtc_state->bigjoiner_pipes)
+ if (!crtc_state->hw.active ||
+ intel_crtc_needs_modeset(crtc_state) ||
+ intel_crtc_needs_fastset(crtc_state) ||
+ crtc_state->bigjoiner_pipes)
goto slow;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 69ecf2a3d6c6..0f1ec2a98cc8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -31,6 +31,7 @@
#include <drm/drm_privacy_screen_consumer.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_audio.h"
#include "intel_audio_regs.h"
#include "intel_backlight.h"
@@ -44,6 +45,7 @@
#include "intel_display_power.h"
#include "intel_display_types.h"
#include "intel_dkl_phy.h"
+#include "intel_dkl_phy_regs.h"
#include "intel_dp.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
@@ -55,14 +57,15 @@
#include "intel_hdcp.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
+#include "intel_hti.h"
#include "intel_lspcon.h"
+#include "intel_mg_phy_regs.h"
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_quirks.h"
#include "intel_snps_phy.h"
#include "intel_sprite.h"
#include "intel_tc.h"
-#include "intel_tc_phy_regs.h"
#include "intel_vdsc.h"
#include "intel_vrr.h"
#include "skl_scaler.h"
@@ -845,22 +848,65 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
}
static enum intel_display_power_domain
-intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port)
+intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
{
- /* ICL+ HW requires corresponding AUX IOs to be powered up for PSR with
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
+
+ /*
+ * ICL+ HW requires corresponding AUX IOs to be powered up for PSR with
* DC states enabled at the same time, while for driver initiated AUX
* transfers we need the same AUX IOs to be powered but with DC states
- * disabled. Accordingly use the AUX power domain here which leaves DC
- * states enabled.
- * However, for non-A AUX ports the corresponding non-EDP transcoders
- * would have already enabled power well 2 and DC_OFF. This means we can
- * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
- * specific AUX_IO reference without powering up any extra wells.
- * Note that PSR is enabled only on Port A even though this function
- * returns the correct domain for other ports too.
+ * disabled. Accordingly use the AUX_IO_<port> power domain here which
+ * leaves DC states enabled.
+ *
+ * Before MTL TypeC PHYs (in all TypeC modes and both DP/HDMI) also require
+ * AUX IO to be enabled, but all these require DC_OFF to be enabled as
+ * well, so we can acquire a wider AUX_<port> power domain reference
+ * instead of a specific AUX_IO_<port> reference without powering up any
+ * extra wells.
*/
- return dig_port->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
- intel_aux_power_domain(dig_port);
+ if (intel_encoder_can_psr(&dig_port->base))
+ return intel_display_power_aux_io_domain(i915, dig_port->aux_ch);
+ else if (DISPLAY_VER(i915) < 14 &&
+ (intel_crtc_has_dp_encoder(crtc_state) ||
+ intel_phy_is_tc(i915, phy)))
+ return intel_aux_power_domain(dig_port);
+ else
+ return POWER_DOMAIN_INVALID;
+}
+
+static void
+main_link_aux_power_domain_get(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum intel_display_power_domain domain =
+ intel_ddi_main_link_aux_domain(dig_port, crtc_state);
+
+ drm_WARN_ON(&i915->drm, dig_port->aux_wakeref);
+
+ if (domain == POWER_DOMAIN_INVALID)
+ return;
+
+ dig_port->aux_wakeref = intel_display_power_get(i915, domain);
+}
+
+static void
+main_link_aux_power_domain_put(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum intel_display_power_domain domain =
+ intel_ddi_main_link_aux_domain(dig_port, crtc_state);
+ intel_wakeref_t wf;
+
+ wf = fetch_and_zero(&dig_port->aux_wakeref);
+ if (!wf)
+ return;
+
+ intel_display_power_put(i915, domain, wf);
}
static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
@@ -868,7 +914,6 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_digital_port *dig_port;
- enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
/*
* TODO: Add support for MST encoders. Atm, the following should never
@@ -887,17 +932,7 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
dig_port->ddi_io_power_domain);
}
- /*
- * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
- * ports.
- */
- if (intel_crtc_has_dp_encoder(crtc_state) ||
- intel_phy_is_tc(dev_priv, phy)) {
- drm_WARN_ON(&dev_priv->drm, dig_port->aux_wakeref);
- dig_port->aux_wakeref =
- intel_display_power_get(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port));
- }
+ main_link_aux_power_domain_get(dig_port, crtc_state);
}
void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder,
@@ -1263,11 +1298,11 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
for (ln = 0; ln < 2; ln++) {
int level;
- intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port), ln, 0);
+ intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port, ln), 0);
level = intel_ddi_level(encoder, crtc_state, 2*ln+0);
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port, ln),
DKL_TX_PRESHOOT_COEFF_MASK |
DKL_TX_DE_EMPAHSIS_COEFF_MASK |
DKL_TX_VSWING_CONTROL_MASK,
@@ -1277,7 +1312,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
level = intel_ddi_level(encoder, crtc_state, 2*ln+1);
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port, ln),
DKL_TX_PRESHOOT_COEFF_MASK |
DKL_TX_DE_EMPAHSIS_COEFF_MASK |
DKL_TX_VSWING_CONTROL_MASK,
@@ -1285,7 +1320,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) |
DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing));
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln),
DKL_TX_DP20BITMODE, 0);
if (IS_ALDERLAKE_P(dev_priv)) {
@@ -1304,7 +1339,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(0);
}
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln),
DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK |
DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK,
val);
@@ -2017,8 +2052,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
return;
if (DISPLAY_VER(dev_priv) >= 12) {
- ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 0);
- ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 1);
+ ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 0));
+ ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 1));
} else {
ln0 = intel_de_read(dev_priv, MG_DP_MODE(0, tc_port));
ln1 = intel_de_read(dev_priv, MG_DP_MODE(1, tc_port));
@@ -2079,8 +2114,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
}
if (DISPLAY_VER(dev_priv) >= 12) {
- intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 0, ln0);
- intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 1, ln1);
+ intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 0), ln0);
+ intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 1), ln1);
} else {
intel_de_write(dev_priv, MG_DP_MODE(0, tc_port), ln0);
intel_de_write(dev_priv, MG_DP_MODE(1, tc_port), ln1);
@@ -2736,10 +2771,7 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
intel_ddi_post_disable_dp(state, encoder, old_crtc_state,
old_conn_state);
- if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port)
- intel_display_power_put(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port),
- fetch_and_zero(&dig_port->aux_wakeref));
+ main_link_aux_power_domain_put(dig_port, old_crtc_state);
if (is_tc_port)
intel_tc_port_put_link(dig_port);
@@ -3060,12 +3092,7 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state,
if (is_tc_port)
intel_tc_port_get_link(dig_port, crtc_state->lane_count);
- if (intel_crtc_has_dp_encoder(crtc_state) || is_tc_port) {
- drm_WARN_ON(&dev_priv->drm, dig_port->aux_wakeref);
- dig_port->aux_wakeref =
- intel_display_power_get(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port));
- }
+ main_link_aux_power_domain_get(dig_port, crtc_state);
if (is_tc_port && !intel_tc_port_in_tbt_alt_mode(dig_port))
/*
@@ -3085,7 +3112,7 @@ static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder)
int ln;
for (ln = 0; ln < 2; ln++)
- intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port), ln, DKL_PCS_DW5_CORE_SOFTRESET, 0);
+ intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port, ln), DKL_PCS_DW5_CORE_SOFTRESET, 0);
}
static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
@@ -3524,7 +3551,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
if (drm_WARN_ON(&i915->drm, !pll))
return;
- if (intel_get_shared_dpll_id(i915, pll) == DPLL_ID_ICL_TBTPLL)
+ if (pll->info->id == DPLL_ID_ICL_TBTPLL)
port_dpll_id = ICL_PORT_DPLL_DEFAULT;
else
port_dpll_id = ICL_PORT_DPLL_MG_PHY;
@@ -3537,7 +3564,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
icl_set_active_port_dpll(crtc_state, port_dpll_id);
- if (intel_get_shared_dpll_id(i915, crtc_state->shared_dpll) == DPLL_ID_ICL_TBTPLL)
+ if (crtc_state->shared_dpll->info->id == DPLL_ID_ICL_TBTPLL)
crtc_state->port_clock = icl_calc_tbt_pll_link(i915, encoder->port);
else
crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll,
@@ -3579,7 +3606,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder,
enum phy phy = intel_port_to_phy(i915, encoder->port);
if (intel_phy_is_tc(i915, phy))
- intel_tc_port_sanitize(enc_to_dig_port(encoder));
+ intel_tc_port_sanitize_mode(enc_to_dig_port(encoder));
if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
intel_dp_sync_state(encoder, crtc_state);
@@ -3789,11 +3816,17 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
static void intel_ddi_encoder_reset(struct drm_encoder *encoder)
{
+ struct drm_i915_private *i915 = to_i915(encoder->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder));
+ struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+ enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
intel_dp->reset_link_params = true;
intel_pps_encoder_reset(intel_dp);
+
+ if (intel_phy_is_tc(i915, phy))
+ intel_tc_port_init_mode(dig_port);
}
static const struct drm_encoder_funcs intel_ddi_funcs = {
@@ -4106,12 +4139,6 @@ intel_ddi_max_lanes(struct intel_digital_port *dig_port)
return max_lanes;
}
-static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
-{
- return i915->hti_state & HDPORT_ENABLED &&
- i915->hti_state & HDPORT_DDI_USED(phy);
-}
-
static enum hpd_pin xelpd_hpd_pin(struct drm_i915_private *dev_priv,
enum port port)
{
@@ -4240,7 +4267,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
* driver. In that case we should skip initializing the corresponding
* outputs.
*/
- if (hti_uses_phy(dev_priv, phy)) {
+ if (intel_hti_uses_phy(dev_priv, phy)) {
drm_dbg_kms(&dev_priv->drm, "PORT %c / PHY %c reserved by HTI\n",
port_name(port), phy_name(phy));
return;
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 461c62c88413..6c2686ecb62a 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -76,6 +76,7 @@
#include "g4x_hdmi.h"
#include "hsw_ips.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_utils.h"
#include "icl_dsi.h"
#include "intel_acpi.h"
@@ -90,6 +91,7 @@
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dp_link_training.h"
+#include "intel_dpio_phy.h"
#include "intel_dpt.h"
#include "intel_dsb.h"
#include "intel_fbc.h"
@@ -99,6 +101,7 @@
#include "intel_frontbuffer.h"
#include "intel_hdcp.h"
#include "intel_hotplug.h"
+#include "intel_hti.h"
#include "intel_modeset_verify.h"
#include "intel_modeset_setup.h"
#include "intel_overlay.h"
@@ -831,13 +834,27 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
}
static int
+intel_display_commit_duplicated_state(struct intel_atomic_state *state,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ int ret;
+
+ ret = drm_atomic_helper_commit_duplicated_state(&state->base, ctx);
+
+ drm_WARN_ON(&i915->drm, ret == -EDEADLK);
+
+ return ret;
+}
+
+static int
__intel_display_resume(struct drm_i915_private *i915,
struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
- int i, ret;
+ int i;
intel_modeset_setup_hw_state(i915, ctx);
intel_vga_redisable(i915);
@@ -863,11 +880,7 @@ __intel_display_resume(struct drm_i915_private *i915,
if (!HAS_GMCH(i915))
to_intel_atomic_state(state)->skip_intermediate_wm = true;
- ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
-
- drm_WARN_ON(&i915->drm, ret == -EDEADLK);
-
- return ret;
+ return intel_display_commit_duplicated_state(to_intel_atomic_state(state), ctx);
}
static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
@@ -878,8 +891,7 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
- struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
+ struct drm_modeset_acquire_ctx *ctx = &dev_priv->display.restore.reset_ctx;
struct drm_atomic_state *state;
int ret;
@@ -906,10 +918,10 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
* Need mode_config.mutex so that we don't
* trample ongoing ->detect() and whatnot.
*/
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
drm_modeset_acquire_init(ctx, 0);
while (1) {
- ret = drm_modeset_lock_all_ctx(dev, ctx);
+ ret = drm_modeset_lock_all_ctx(&dev_priv->drm, ctx);
if (ret != -EDEADLK)
break;
@@ -919,7 +931,7 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
* Disabling the crtcs gracefully seems nicer. Also the
* g33 docs say we should at least disable all the planes.
*/
- state = drm_atomic_helper_duplicate_state(dev, ctx);
+ state = drm_atomic_helper_duplicate_state(&dev_priv->drm, ctx);
if (IS_ERR(state)) {
ret = PTR_ERR(state);
drm_err(&dev_priv->drm, "Duplicating state failed with %i\n",
@@ -927,7 +939,7 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
return;
}
- ret = drm_atomic_helper_disable_all(dev, ctx);
+ ret = drm_atomic_helper_disable_all(&dev_priv->drm, ctx);
if (ret) {
drm_err(&dev_priv->drm, "Suspending crtc's failed with %i\n",
ret);
@@ -935,13 +947,13 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv)
return;
}
- dev_priv->modeset_restore_state = state;
+ dev_priv->display.restore.modeset_state = state;
state->acquire_ctx = ctx;
}
void intel_display_finish_reset(struct drm_i915_private *i915)
{
- struct drm_modeset_acquire_ctx *ctx = &i915->reset_ctx;
+ struct drm_modeset_acquire_ctx *ctx = &i915->display.restore.reset_ctx;
struct drm_atomic_state *state;
int ret;
@@ -952,14 +964,14 @@ void intel_display_finish_reset(struct drm_i915_private *i915)
if (!test_bit(I915_RESET_MODESET, &to_gt(i915)->reset.flags))
return;
- state = fetch_and_zero(&i915->modeset_restore_state);
+ state = fetch_and_zero(&i915->display.restore.modeset_state);
if (!state)
goto unlock;
/* reset doesn't touch the display */
if (!gpu_reset_clobbers_display(i915)) {
/* for testing only restore the display */
- ret = __intel_display_resume(i915, state, ctx);
+ ret = intel_display_commit_duplicated_state(to_intel_atomic_state(state), ctx);
if (ret)
drm_err(&i915->drm,
"Restoring old state failed with %i\n", ret);
@@ -1252,8 +1264,6 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
if (needs_cursorclk_wa(old_crtc_state) &&
!needs_cursorclk_wa(new_crtc_state))
icl_wa_cursorclkgating(dev_priv, pipe, false);
-
- intel_drrs_activate(new_crtc_state);
}
static void intel_crtc_enable_flip_done(struct intel_atomic_state *state,
@@ -2434,7 +2444,7 @@ int intel_display_suspend(struct drm_device *dev)
drm_err(&dev_priv->drm, "Suspending crtc's failed with %i\n",
ret);
else
- dev_priv->modeset_restore_state = state;
+ dev_priv->display.restore.modeset_state = state;
return ret;
}
@@ -3723,12 +3733,16 @@ out:
static u8 bigjoiner_pipes(struct drm_i915_private *i915)
{
+ u8 pipes;
+
if (DISPLAY_VER(i915) >= 12)
- return BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D);
+ pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D);
else if (DISPLAY_VER(i915) >= 11)
- return BIT(PIPE_B) | BIT(PIPE_C);
+ pipes = BIT(PIPE_B) | BIT(PIPE_C);
else
- return 0;
+ pipes = 0;
+
+ return pipes & RUNTIME_INFO(i915)->pipe_mask;
}
static bool transcoder_ddi_func_is_enabled(struct drm_i915_private *dev_priv,
@@ -4041,20 +4055,19 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_display_power_domain_set power_domain_set = { };
bool active;
u32 tmp;
- if (!intel_display_power_get_in_set_if_enabled(dev_priv, &power_domain_set,
+ if (!intel_display_power_get_in_set_if_enabled(dev_priv, &crtc->hw_readout_power_domains,
POWER_DOMAIN_PIPE(crtc->pipe)))
return false;
pipe_config->shared_dpll = NULL;
- active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_set);
+ active = hsw_get_transcoder_state(crtc, pipe_config, &crtc->hw_readout_power_domains);
if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) &&
- bxt_get_dsi_transcoder_state(crtc, pipe_config, &power_domain_set)) {
+ bxt_get_dsi_transcoder_state(crtc, pipe_config, &crtc->hw_readout_power_domains)) {
drm_WARN_ON(&dev_priv->drm, active);
active = true;
}
@@ -4113,7 +4126,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
pipe_config->ips_linetime =
REG_FIELD_GET(HSW_IPS_LINETIME_MASK, tmp);
- if (intel_display_power_get_in_set_if_enabled(dev_priv, &power_domain_set,
+ if (intel_display_power_get_in_set_if_enabled(dev_priv, &crtc->hw_readout_power_domains,
POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe))) {
if (DISPLAY_VER(dev_priv) >= 9)
skl_get_pfit_config(pipe_config);
@@ -4144,7 +4157,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
}
out:
- intel_display_power_put_all_in_set(dev_priv, &power_domain_set);
+ intel_display_power_put_all_in_set(dev_priv, &crtc->hw_readout_power_domains);
return active;
}
@@ -4572,8 +4585,8 @@ static bool encoders_cloneable(const struct intel_encoder *a,
const struct intel_encoder *b)
{
/* masks could be asymmetric, so check both ways */
- return a == b || (a->cloneable & (1 << b->type) &&
- b->cloneable & (1 << a->type));
+ return a == b || (a->cloneable & BIT(b->type) &&
+ b->cloneable & BIT(a->type));
}
static bool check_single_encoder_cloning(struct intel_atomic_state *state,
@@ -4824,14 +4837,14 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
- bool mode_changed = intel_crtc_needs_modeset(crtc_state);
int ret;
if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv) &&
- mode_changed && !crtc_state->hw.active)
+ intel_crtc_needs_modeset(crtc_state) &&
+ !crtc_state->hw.active)
crtc_state->update_wm_post = true;
- if (mode_changed) {
+ if (intel_crtc_needs_modeset(crtc_state)) {
ret = intel_dpll_crtc_get_shared_dpll(state, crtc);
if (ret)
return ret;
@@ -4844,8 +4857,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
if (c8_planes_changed(crtc_state))
crtc_state->uapi.color_mgmt_changed = true;
- if (mode_changed || crtc_state->update_pipe ||
- crtc_state->uapi.color_mgmt_changed) {
+ if (intel_crtc_needs_color_update(crtc_state)) {
ret = intel_color_check(crtc_state);
if (ret)
return ret;
@@ -4871,7 +4883,8 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
}
if (DISPLAY_VER(dev_priv) >= 9) {
- if (mode_changed || crtc_state->update_pipe) {
+ if (intel_crtc_needs_modeset(crtc_state) ||
+ intel_crtc_needs_fastset(crtc_state)) {
ret = skl_update_scaler_crtc(crtc_state);
if (ret)
return ret;
@@ -5637,39 +5650,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_I(name.y2); \
} while (0)
-/* This is required for BDW+ where there is only one set of registers for
- * switching between high and low RR.
- * This macro can be used whenever a comparison has to be made between one
- * hw state and multiple sw state variables.
- */
-#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) do { \
- if (!intel_compare_link_m_n(&current_config->name, \
- &pipe_config->name) && \
- !intel_compare_link_m_n(&current_config->alt_name, \
- &pipe_config->name)) { \
- pipe_config_mismatch(fastset, crtc, __stringify(name), \
- "(expected tu %i data %i/%i link %i/%i, " \
- "or tu %i data %i/%i link %i/%i, " \
- "found tu %i, data %i/%i link %i/%i)", \
- current_config->name.tu, \
- current_config->name.data_m, \
- current_config->name.data_n, \
- current_config->name.link_m, \
- current_config->name.link_n, \
- current_config->alt_name.tu, \
- current_config->alt_name.data_m, \
- current_config->alt_name.data_n, \
- current_config->alt_name.link_m, \
- current_config->alt_name.link_n, \
- pipe_config->name.tu, \
- pipe_config->name.data_m, \
- pipe_config->name.data_n, \
- pipe_config->name.link_m, \
- pipe_config->name.link_n); \
- ret = false; \
- } \
-} while (0)
-
#define PIPE_CONF_CHECK_FLAGS(name, mask) do { \
if ((current_config->name ^ pipe_config->name) & (mask)) { \
pipe_config_mismatch(fastset, crtc, __stringify(name), \
@@ -5738,7 +5718,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) {
if (!fastset || !pipe_config->seamless_m_n)
- PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2);
+ PIPE_CONF_CHECK_M_N(dp_m_n);
} else {
PIPE_CONF_CHECK_M_N(dp_m_n);
PIPE_CONF_CHECK_M_N(dp_m2_n2);
@@ -5815,7 +5795,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
bp_gamma = intel_color_get_gamma_bit_precision(pipe_config);
if (bp_gamma)
- PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
+ PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, post_csc_lut, bp_gamma);
if (current_config->active_planes) {
PIPE_CONF_CHECK_BOOL(has_psr);
@@ -5937,7 +5917,8 @@ intel_verify_planes(struct intel_atomic_state *state)
plane_state->uapi.visible);
}
-int intel_modeset_all_pipes(struct intel_atomic_state *state)
+int intel_modeset_all_pipes(struct intel_atomic_state *state,
+ const char *reason)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_crtc *crtc;
@@ -5955,10 +5936,14 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state)
return PTR_ERR(crtc_state);
if (!crtc_state->hw.active ||
- drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
+ intel_crtc_needs_modeset(crtc_state))
continue;
+ drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Full modeset due to %s\n",
+ crtc->base.base.id, crtc->base.name, reason);
+
crtc_state->uapi.mode_changed = true;
+ crtc_state->update_pipe = false;
ret = drm_atomic_add_affected_connectors(&state->base,
&crtc->base);
@@ -6134,7 +6119,8 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta
return;
new_crtc_state->uapi.mode_changed = false;
- new_crtc_state->update_pipe = true;
+ if (!intel_crtc_needs_modeset(new_crtc_state))
+ new_crtc_state->update_pipe = true;
}
static int intel_crtc_add_planes_to_state(struct intel_atomic_state *state,
@@ -6906,12 +6892,19 @@ static int intel_atomic_check(struct drm_device *dev,
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
+ intel_color_assert_luts(new_crtc_state);
+
ret = intel_async_flip_check_hw(state, crtc);
if (ret)
goto fail;
+ /* Either full modeset or fastset (or neither), never both */
+ drm_WARN_ON(&dev_priv->drm,
+ intel_crtc_needs_modeset(new_crtc_state) &&
+ intel_crtc_needs_fastset(new_crtc_state));
+
if (!intel_crtc_needs_modeset(new_crtc_state) &&
- !new_crtc_state->update_pipe)
+ !intel_crtc_needs_fastset(new_crtc_state))
continue;
intel_crtc_state_dump(new_crtc_state, state,
@@ -6947,12 +6940,8 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state)
return ret;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
- bool mode_changed = intel_crtc_needs_modeset(crtc_state);
-
- if (mode_changed || crtc_state->update_pipe ||
- crtc_state->uapi.color_mgmt_changed) {
+ if (intel_crtc_needs_color_update(crtc_state))
intel_dsb_prepare(crtc_state);
- }
}
return 0;
@@ -7033,14 +7022,13 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state,
* CRTC was enabled.
*/
if (!modeset) {
- if (new_crtc_state->uapi.color_mgmt_changed ||
- new_crtc_state->update_pipe)
+ if (intel_crtc_needs_color_update(new_crtc_state))
intel_color_commit_arm(new_crtc_state);
if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
bdw_set_pipemisc(new_crtc_state);
- if (new_crtc_state->update_pipe)
+ if (intel_crtc_needs_fastset(new_crtc_state))
intel_pipe_fastset(old_crtc_state, new_crtc_state);
}
@@ -7099,25 +7087,23 @@ static void intel_update_crtc(struct intel_atomic_state *state,
if (!modeset) {
if (new_crtc_state->preload_luts &&
- (new_crtc_state->uapi.color_mgmt_changed ||
- new_crtc_state->update_pipe))
+ intel_crtc_needs_color_update(new_crtc_state))
intel_color_load_luts(new_crtc_state);
intel_pre_plane_update(state, crtc);
- if (new_crtc_state->update_pipe)
+ if (intel_crtc_needs_fastset(new_crtc_state))
intel_encoders_update_pipe(state, crtc);
if (DISPLAY_VER(i915) >= 11 &&
- new_crtc_state->update_pipe)
+ intel_crtc_needs_fastset(new_crtc_state))
icl_set_pipe_chicken(new_crtc_state);
}
intel_fbc_update(state, crtc);
if (!modeset &&
- (new_crtc_state->uapi.color_mgmt_changed ||
- new_crtc_state->update_pipe))
+ intel_crtc_needs_color_update(new_crtc_state))
intel_color_commit_noarm(new_crtc_state);
intel_crtc_planes_update_noarm(state, crtc);
@@ -7139,7 +7125,7 @@ static void intel_update_crtc(struct intel_atomic_state *state,
* valid pipe configuration from the BIOS we need to take care
* of enabling them on the CRTC's first fastset.
*/
- if (new_crtc_state->update_pipe && !modeset &&
+ if (intel_crtc_needs_fastset(new_crtc_state) && !modeset &&
old_crtc_state->inherited)
intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
}
@@ -7162,9 +7148,7 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
intel_fbc_disable(crtc);
intel_disable_shared_dpll(old_crtc_state);
- /* FIXME unify this for all platforms */
- if (!new_crtc_state->hw.active &&
- !HAS_GMCH(dev_priv))
+ if (!new_crtc_state->hw.active)
intel_initial_watermarks(state, crtc);
}
@@ -7499,9 +7483,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (intel_crtc_needs_modeset(new_crtc_state) ||
- new_crtc_state->update_pipe) {
+ intel_crtc_needs_fastset(new_crtc_state))
intel_modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]);
- }
}
intel_commit_modeset_disables(state);
@@ -7605,6 +7588,12 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
/*
+ * Activate DRRS after state readout to avoid
+ * dp_m_n vs. dp_m2_n2 confusion on BDW+.
+ */
+ intel_drrs_activate(new_crtc_state);
+
+ /*
* DSB cleanup is done in cleanup_work aligning with framebuffer
* cleanup. So copy and reset the dsb structure to sync with
* commit_done and later do dsb cleanup in cleanup_work.
@@ -8344,6 +8333,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
if (!HAS_DISPLAY(dev_priv))
return;
+ intel_color_init_hooks(dev_priv);
intel_init_cdclk_hooks(dev_priv);
intel_audio_hooks_init(dev_priv);
@@ -8585,7 +8575,7 @@ static void intel_mode_config_init(struct drm_i915_private *i915)
struct drm_mode_config *mode_config = &i915->drm.mode_config;
drm_mode_config_init(&i915->drm);
- INIT_LIST_HEAD(&i915->global_obj_list);
+ INIT_LIST_HEAD(&i915->display.global.obj_list);
mode_config->min_width = 0;
mode_config->min_height = 0;
@@ -8674,6 +8664,10 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915)
if (ret)
goto cleanup_vga_client_pw_domain_dmc;
+ ret = intel_color_init(i915);
+ if (ret)
+ goto cleanup_vga_client_pw_domain_dmc;
+
ret = intel_dbuf_init(i915);
if (ret)
goto cleanup_vga_client_pw_domain_dmc;
@@ -8746,12 +8740,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
if (i915->display.cdclk.max_cdclk_freq == 0)
intel_update_max_cdclk(i915);
- /*
- * If the platform has HTI, we need to find out whether it has reserved
- * any display resources before we create our display outputs.
- */
- if (INTEL_INFO(i915)->display.has_hti)
- i915->hti_state = intel_de_read(i915, HDPORT_STATE);
+ intel_hti_init(i915);
/* Just disable it once at startup */
intel_vga_disable(i915);
@@ -8914,14 +8903,14 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
void intel_display_resume(struct drm_device *dev)
{
struct drm_i915_private *i915 = to_i915(dev);
- struct drm_atomic_state *state = i915->modeset_restore_state;
+ struct drm_atomic_state *state = i915->display.restore.modeset_state;
struct drm_modeset_acquire_ctx ctx;
int ret;
if (!HAS_DISPLAY(i915))
return;
- i915->modeset_restore_state = NULL;
+ i915->display.restore.modeset_state = NULL;
if (state)
state->acquire_ctx = &ctx;
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 884e8e67b17c..714030136b7f 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -53,6 +53,7 @@ struct intel_digital_port;
struct intel_dp;
struct intel_encoder;
struct intel_initial_plane_config;
+struct intel_link_m_n;
struct intel_load_detect_pipe;
struct intel_plane;
struct intel_plane_state;
@@ -61,24 +62,6 @@ struct intel_remapped_info;
struct intel_rotation_info;
struct pci_dev;
-enum i915_gpio {
- GPIOA,
- GPIOB,
- GPIOC,
- GPIOD,
- GPIOE,
- GPIOF,
- GPIOG,
- GPIOH,
- __GPIOI_UNUSED,
- GPIOJ,
- GPIOK,
- GPIOL,
- GPIOM,
- GPION,
- GPIOO,
-};
-
/*
* Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
* rest have consecutive values and match the enum values of transcoders
@@ -279,17 +262,6 @@ enum tc_port_mode {
TC_PORT_LEGACY,
};
-enum dpio_channel {
- DPIO_CH0,
- DPIO_CH1
-};
-
-enum dpio_phy {
- DPIO_PHY0,
- DPIO_PHY1,
- DPIO_PHY2,
-};
-
enum aux_ch {
AUX_CH_A,
AUX_CH_B,
@@ -316,15 +288,6 @@ enum aux_ch {
#define aux_ch_name(a) ((a) + 'A')
-/* Used by dp and fdi links */
-struct intel_link_m_n {
- u32 tu;
- u32 data_m;
- u32 data_n;
- u32 link_m;
- u32 link_n;
-};
-
enum phy {
PHY_NONE = -1,
@@ -469,10 +432,6 @@ enum hpd_pin {
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
for_each_if((intel_encoder)->base.crtc == (__crtc))
-#define for_each_connector_on_encoder(dev, __encoder, intel_connector) \
- list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \
- for_each_if((intel_connector)->base.encoder == (__encoder))
-
#define for_each_old_intel_plane_in_state(__state, plane, old_plane_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->base.dev->mode_config.num_total_plane && \
@@ -683,7 +642,8 @@ void intel_modeset_driver_remove(struct drm_i915_private *i915);
void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915);
void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915);
void intel_display_resume(struct drm_device *dev);
-int intel_modeset_all_pipes(struct intel_atomic_state *state);
+int intel_modeset_all_pipes(struct intel_atomic_state *state,
+ const char *reason);
void intel_modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
struct intel_power_domain_mask *old_domains);
void intel_modeset_put_crtc_power_domains(struct intel_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 9b51148e8ba5..57ddce3ba02b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -14,6 +14,7 @@
#include <linux/workqueue.h>
#include <drm/drm_connector.h>
+#include <drm/drm_modeset_lock.h>
#include "intel_cdclk.h"
#include "intel_display.h"
@@ -28,6 +29,7 @@
struct drm_i915_private;
struct drm_property;
+struct drm_property_blob;
struct i915_audio_component;
struct i915_hdcp_comp_master;
struct intel_atomic_state;
@@ -309,6 +311,10 @@ struct intel_display {
} cdclk;
struct {
+ struct drm_property_blob *glk_linear_degamma_lut;
+ } color;
+
+ struct {
/* The current hardware dbuf configuration */
u8 enabled_slices;
@@ -340,6 +346,10 @@ struct intel_display {
} fdi;
struct {
+ struct list_head obj_list;
+ } global;
+
+ struct {
/*
* Base address of where the gmbus and gpio blocks are located
* (either on PCH or on SoC for platforms without PCH).
@@ -366,6 +376,16 @@ struct intel_display {
} hdcp;
struct {
+ /*
+ * HTI (aka HDPORT) state read during initial hw readout. Most
+ * platforms don't have HTI, so this will just stay 0. Those
+ * that do will use this later to figure out which PLLs and PHYs
+ * are unavailable for driver usage.
+ */
+ u32 state;
+ } hti;
+
+ struct {
struct i915_power_domains domains;
/* Shadow for DISPLAY_PHY_CONTROL which can't be safely read */
@@ -392,6 +412,12 @@ struct intel_display {
} quirks;
struct {
+ /* restore state for suspend/resume and display reset */
+ struct drm_atomic_state *modeset_state;
+ struct drm_modeset_acquire_ctx reset_ctx;
+ } restore;
+
+ struct {
enum {
I915_SAGV_UNKNOWN = 0,
I915_SAGV_DISABLED,
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 7c7253a2541c..7bcd90384a46 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -9,6 +9,8 @@
#include <drm/drm_fourcc.h>
#include "i915_debugfs.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_debugfs.h"
#include "intel_display_power.h"
@@ -22,6 +24,7 @@
#include "intel_fbdev.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
+#include "intel_hotplug.h"
#include "intel_panel.h"
#include "intel_pm.h"
#include "intel_psr.h"
@@ -127,7 +130,6 @@ static int i915_vbt(struct seq_file *m, void *unused)
static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_device *dev = &dev_priv->drm;
struct intel_framebuffer *fbdev_fb = NULL;
struct drm_framebuffer *drm_fb;
@@ -146,8 +148,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
}
#endif
- mutex_lock(&dev->mode_config.fb_lock);
- drm_for_each_fb(drm_fb, dev) {
+ mutex_lock(&dev_priv->drm.mode_config.fb_lock);
+ drm_for_each_fb(drm_fb, &dev_priv->drm) {
struct intel_framebuffer *fb = to_intel_framebuffer(drm_fb);
if (fb == fbdev_fb)
continue;
@@ -162,7 +164,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
i915_debugfs_describe_obj(m, intel_fb_obj(&fb->base));
seq_putc(m, '\n');
}
- mutex_unlock(&dev->mode_config.fb_lock);
+ mutex_unlock(&dev_priv->drm.mode_config.fb_lock);
return 0;
}
@@ -897,7 +899,6 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc)
static int i915_display_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_device *dev = &dev_priv->drm;
struct intel_crtc *crtc;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
@@ -905,22 +906,22 @@ static int i915_display_info(struct seq_file *m, void *unused)
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
- drm_modeset_lock_all(dev);
+ drm_modeset_lock_all(&dev_priv->drm);
seq_printf(m, "CRTC info\n");
seq_printf(m, "---------\n");
- for_each_intel_crtc(dev, crtc)
+ for_each_intel_crtc(&dev_priv->drm, crtc)
intel_crtc_info(m, crtc);
seq_printf(m, "\n");
seq_printf(m, "Connector info\n");
seq_printf(m, "--------------\n");
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter)
intel_connector_info(m, connector);
drm_connector_list_iter_end(&conn_iter);
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
@@ -930,10 +931,9 @@ static int i915_display_info(struct seq_file *m, void *unused)
static int i915_shared_dplls_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_device *dev = &dev_priv->drm;
int i;
- drm_modeset_lock_all(dev);
+ drm_modeset_lock_all(&dev_priv->drm);
seq_printf(m, "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n",
dev_priv->display.dpll.ref_clks.nssc,
@@ -978,7 +978,7 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
seq_printf(m, " mg_pll_tdc_coldst_bias: 0x%08x\n",
pll->state.hw_state.mg_pll_tdc_coldst_bias);
}
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
return 0;
}
@@ -986,14 +986,13 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
static int i915_ddb_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_device *dev = &dev_priv->drm;
struct skl_ddb_entry *entry;
struct intel_crtc *crtc;
if (DISPLAY_VER(dev_priv) < 9)
return -ENODEV;
- drm_modeset_lock_all(dev);
+ drm_modeset_lock_all(&dev_priv->drm);
seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
@@ -1017,53 +1016,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
entry->end, skl_ddb_entry_size(entry));
}
- drm_modeset_unlock_all(dev);
-
- return 0;
-}
-
-static int i915_drrs_status(struct seq_file *m, void *unused)
-{
- struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_connector_list_iter conn_iter;
- struct intel_connector *connector;
- struct intel_crtc *crtc;
-
- drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
- for_each_intel_connector_iter(connector, &conn_iter) {
- seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n",
- connector->base.base.id, connector->base.name,
- intel_drrs_type_str(intel_panel_drrs_type(connector)));
- }
- drm_connector_list_iter_end(&conn_iter);
-
- seq_puts(m, "\n");
-
- for_each_intel_crtc(&dev_priv->drm, crtc) {
- const struct intel_crtc_state *crtc_state =
- to_intel_crtc_state(crtc->base.state);
-
- seq_printf(m, "[CRTC:%d:%s]:\n",
- crtc->base.base.id, crtc->base.name);
-
- mutex_lock(&crtc->drrs.mutex);
-
- /* DRRS Supported */
- seq_printf(m, "\tDRRS Enabled: %s\n",
- str_yes_no(crtc_state->has_drrs));
-
- seq_printf(m, "\tDRRS Active: %s\n",
- str_yes_no(intel_drrs_is_active(crtc)));
-
- seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n",
- crtc->drrs.busy_frontbuffer_bits);
-
- seq_printf(m, "\tDRRS refresh rate: %s\n",
- crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ?
- "low" : "high");
-
- mutex_unlock(&crtc->drrs.mutex);
- }
+ drm_modeset_unlock_all(&dev_priv->drm);
return 0;
}
@@ -1107,13 +1060,12 @@ static int i915_lpsp_status(struct seq_file *m, void *unused)
static int i915_dp_mst_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct drm_device *dev = &dev_priv->drm;
struct intel_encoder *intel_encoder;
struct intel_digital_port *dig_port;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
continue;
@@ -1200,12 +1152,11 @@ static ssize_t i915_displayport_test_active_write(struct file *file,
static int i915_displayport_test_active_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct intel_dp *intel_dp;
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct intel_encoder *encoder;
@@ -1250,12 +1201,11 @@ static const struct file_operations i915_displayport_test_active_fops = {
static int i915_displayport_test_data_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct intel_dp *intel_dp;
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct intel_encoder *encoder;
@@ -1304,12 +1254,11 @@ DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_data);
static int i915_displayport_test_type_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct intel_dp *intel_dp;
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct intel_encoder *encoder;
@@ -1336,7 +1285,6 @@ DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_type);
static void wm_latency_show(struct seq_file *m, const u16 wm[8])
{
struct drm_i915_private *dev_priv = m->private;
- struct drm_device *dev = &dev_priv->drm;
int level;
int num_levels;
@@ -1349,7 +1297,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8])
else
num_levels = ilk_wm_max_level(dev_priv) + 1;
- drm_modeset_lock_all(dev);
+ drm_modeset_lock_all(&dev_priv->drm);
for (level = 0; level < num_levels; level++) {
unsigned int latency = wm[level];
@@ -1370,7 +1318,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8])
level, wm[level], latency / 10, latency % 10);
}
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
}
static int pri_wm_latency_show(struct seq_file *m, void *data)
@@ -1453,7 +1401,6 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
{
struct seq_file *m = file->private_data;
struct drm_i915_private *dev_priv = m->private;
- struct drm_device *dev = &dev_priv->drm;
u16 new[8] = { 0 };
int num_levels;
int level;
@@ -1483,12 +1430,12 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
if (ret != num_levels)
return -EINVAL;
- drm_modeset_lock_all(dev);
+ drm_modeset_lock_all(&dev_priv->drm);
for (level = 0; level < num_levels; level++)
wm[level] = new[level];
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
return len;
}
@@ -1566,209 +1513,6 @@ static const struct file_operations i915_cur_wm_latency_fops = {
.write = cur_wm_latency_write
};
-static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
-{
- struct drm_i915_private *dev_priv = m->private;
- struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
-
- /* Synchronize with everything first in case there's been an HPD
- * storm, but we haven't finished handling it in the kernel yet
- */
- intel_synchronize_irq(dev_priv);
- flush_work(&dev_priv->display.hotplug.dig_port_work);
- flush_delayed_work(&dev_priv->display.hotplug.hotplug_work);
-
- seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold);
- seq_printf(m, "Detected: %s\n",
- str_yes_no(delayed_work_pending(&hotplug->reenable_work)));
-
- return 0;
-}
-
-static ssize_t i915_hpd_storm_ctl_write(struct file *file,
- const char __user *ubuf, size_t len,
- loff_t *offp)
-{
- struct seq_file *m = file->private_data;
- struct drm_i915_private *dev_priv = m->private;
- struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
- unsigned int new_threshold;
- int i;
- char *newline;
- char tmp[16];
-
- if (len >= sizeof(tmp))
- return -EINVAL;
-
- if (copy_from_user(tmp, ubuf, len))
- return -EFAULT;
-
- tmp[len] = '\0';
-
- /* Strip newline, if any */
- newline = strchr(tmp, '\n');
- if (newline)
- *newline = '\0';
-
- if (strcmp(tmp, "reset") == 0)
- new_threshold = HPD_STORM_DEFAULT_THRESHOLD;
- else if (kstrtouint(tmp, 10, &new_threshold) != 0)
- return -EINVAL;
-
- if (new_threshold > 0)
- drm_dbg_kms(&dev_priv->drm,
- "Setting HPD storm detection threshold to %d\n",
- new_threshold);
- else
- drm_dbg_kms(&dev_priv->drm, "Disabling HPD storm detection\n");
-
- spin_lock_irq(&dev_priv->irq_lock);
- hotplug->hpd_storm_threshold = new_threshold;
- /* Reset the HPD storm stats so we don't accidentally trigger a storm */
- for_each_hpd_pin(i)
- hotplug->stats[i].count = 0;
- spin_unlock_irq(&dev_priv->irq_lock);
-
- /* Re-enable hpd immediately if we were in an irq storm */
- flush_delayed_work(&dev_priv->display.hotplug.reenable_work);
-
- return len;
-}
-
-static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file)
-{
- return single_open(file, i915_hpd_storm_ctl_show, inode->i_private);
-}
-
-static const struct file_operations i915_hpd_storm_ctl_fops = {
- .owner = THIS_MODULE,
- .open = i915_hpd_storm_ctl_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = i915_hpd_storm_ctl_write
-};
-
-static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data)
-{
- struct drm_i915_private *dev_priv = m->private;
-
- seq_printf(m, "Enabled: %s\n",
- str_yes_no(dev_priv->display.hotplug.hpd_short_storm_enabled));
-
- return 0;
-}
-
-static int
-i915_hpd_short_storm_ctl_open(struct inode *inode, struct file *file)
-{
- return single_open(file, i915_hpd_short_storm_ctl_show,
- inode->i_private);
-}
-
-static ssize_t i915_hpd_short_storm_ctl_write(struct file *file,
- const char __user *ubuf,
- size_t len, loff_t *offp)
-{
- struct seq_file *m = file->private_data;
- struct drm_i915_private *dev_priv = m->private;
- struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
- char *newline;
- char tmp[16];
- int i;
- bool new_state;
-
- if (len >= sizeof(tmp))
- return -EINVAL;
-
- if (copy_from_user(tmp, ubuf, len))
- return -EFAULT;
-
- tmp[len] = '\0';
-
- /* Strip newline, if any */
- newline = strchr(tmp, '\n');
- if (newline)
- *newline = '\0';
-
- /* Reset to the "default" state for this system */
- if (strcmp(tmp, "reset") == 0)
- new_state = !HAS_DP_MST(dev_priv);
- else if (kstrtobool(tmp, &new_state) != 0)
- return -EINVAL;
-
- drm_dbg_kms(&dev_priv->drm, "%sabling HPD short storm detection\n",
- new_state ? "En" : "Dis");
-
- spin_lock_irq(&dev_priv->irq_lock);
- hotplug->hpd_short_storm_enabled = new_state;
- /* Reset the HPD storm stats so we don't accidentally trigger a storm */
- for_each_hpd_pin(i)
- hotplug->stats[i].count = 0;
- spin_unlock_irq(&dev_priv->irq_lock);
-
- /* Re-enable hpd immediately if we were in an irq storm */
- flush_delayed_work(&dev_priv->display.hotplug.reenable_work);
-
- return len;
-}
-
-static const struct file_operations i915_hpd_short_storm_ctl_fops = {
- .owner = THIS_MODULE,
- .open = i915_hpd_short_storm_ctl_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = i915_hpd_short_storm_ctl_write,
-};
-
-static int i915_drrs_ctl_set(void *data, u64 val)
-{
- struct drm_i915_private *dev_priv = data;
- struct drm_device *dev = &dev_priv->drm;
- struct intel_crtc *crtc;
-
- for_each_intel_crtc(dev, crtc) {
- struct intel_crtc_state *crtc_state;
- struct drm_crtc_commit *commit;
- int ret;
-
- ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex);
- if (ret)
- return ret;
-
- crtc_state = to_intel_crtc_state(crtc->base.state);
-
- if (!crtc_state->hw.active ||
- !crtc_state->has_drrs)
- goto out;
-
- commit = crtc_state->uapi.commit;
- if (commit) {
- ret = wait_for_completion_interruptible(&commit->hw_done);
- if (ret)
- goto out;
- }
-
- drm_dbg(&dev_priv->drm,
- "Manually %sactivating DRRS\n", val ? "" : "de");
-
- if (val)
- intel_drrs_activate(crtc_state);
- else
- intel_drrs_deactivate(crtc_state);
-
-out:
- drm_modeset_unlock(&crtc->base.mutex);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(i915_drrs_ctl_fops, NULL, i915_drrs_ctl_set, "%llu\n");
-
static ssize_t
i915_fifo_underrun_reset_write(struct file *filp,
const char __user *ubuf,
@@ -1776,7 +1520,6 @@ i915_fifo_underrun_reset_write(struct file *filp,
{
struct drm_i915_private *dev_priv = filp->private_data;
struct intel_crtc *crtc;
- struct drm_device *dev = &dev_priv->drm;
int ret;
bool reset;
@@ -1787,7 +1530,7 @@ i915_fifo_underrun_reset_write(struct file *filp,
if (!reset)
return cnt;
- for_each_intel_crtc(dev, crtc) {
+ for_each_intel_crtc(&dev_priv->drm, crtc) {
struct drm_crtc_commit *commit;
struct intel_crtc_state *crtc_state;
@@ -1842,7 +1585,6 @@ static const struct drm_info_list intel_display_debugfs_list[] = {
{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
{"i915_dp_mst_info", i915_dp_mst_info, 0},
{"i915_ddb_info", i915_ddb_info, 0},
- {"i915_drrs_status", i915_drrs_status, 0},
{"i915_lpsp_status", i915_lpsp_status, 0},
};
@@ -1857,9 +1599,6 @@ static const struct {
{"i915_dp_test_data", &i915_displayport_test_data_fops},
{"i915_dp_test_type", &i915_displayport_test_type_fops},
{"i915_dp_test_active", &i915_displayport_test_active_fops},
- {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
- {"i915_hpd_short_storm_ctl", &i915_hpd_short_storm_ctl_fops},
- {"i915_drrs_ctl", &i915_drrs_ctl_fops},
{"i915_edp_psr_debug", &i915_edp_psr_debug_fops},
};
@@ -1882,6 +1621,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
intel_dmc_debugfs_register(i915);
intel_fbc_debugfs_register(i915);
+ intel_hpd_debugfs_register(i915);
skl_watermark_ipc_debugfs_register(i915);
}
@@ -2195,6 +1935,8 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector)
if (!root)
return;
+ intel_drrs_connector_debugfs_add(intel_connector);
+
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
debugfs_create_file("i915_panel_timings", S_IRUGO, root,
connector, &i915_panel_fops);
@@ -2247,6 +1989,7 @@ void intel_crtc_debugfs_add(struct drm_crtc *crtc)
return;
crtc_updates_add(crtc);
+ intel_drrs_crtc_debugfs_add(to_intel_crtc(crtc));
intel_fbc_crtc_debugfs_add(to_intel_crtc(crtc));
debugfs_create_file("i915_current_bpc", 0444, crtc->debugfs_entry, crtc,
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 1e608b9e5055..3adba64937de 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -129,6 +129,18 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
return "AUDIO_MMIO";
case POWER_DOMAIN_AUDIO_PLAYBACK:
return "AUDIO_PLAYBACK";
+ case POWER_DOMAIN_AUX_IO_A:
+ return "AUX_IO_A";
+ case POWER_DOMAIN_AUX_IO_B:
+ return "AUX_IO_B";
+ case POWER_DOMAIN_AUX_IO_C:
+ return "AUX_IO_C";
+ case POWER_DOMAIN_AUX_IO_D:
+ return "AUX_IO_D";
+ case POWER_DOMAIN_AUX_IO_E:
+ return "AUX_IO_E";
+ case POWER_DOMAIN_AUX_IO_F:
+ return "AUX_IO_F";
case POWER_DOMAIN_AUX_A:
return "AUX_A";
case POWER_DOMAIN_AUX_B:
@@ -153,8 +165,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
return "AUX_USBC5";
case POWER_DOMAIN_AUX_USBC6:
return "AUX_USBC6";
- case POWER_DOMAIN_AUX_IO_A:
- return "AUX_IO_A";
case POWER_DOMAIN_AUX_TBT1:
return "AUX_TBT1";
case POWER_DOMAIN_AUX_TBT2:
@@ -1148,10 +1158,9 @@ static void hsw_assert_cdclk(struct drm_i915_private *dev_priv)
static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_crtc *crtc;
- for_each_intel_crtc(dev, crtc)
+ for_each_intel_crtc(&dev_priv->drm, crtc)
I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
pipe_name(crtc->pipe));
@@ -2290,6 +2299,7 @@ struct intel_ddi_port_domains {
enum intel_display_power_domain ddi_lanes;
enum intel_display_power_domain ddi_io;
+ enum intel_display_power_domain aux_io;
enum intel_display_power_domain aux_legacy_usbc;
enum intel_display_power_domain aux_tbt;
};
@@ -2304,6 +2314,7 @@ i9xx_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_A,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_A,
+ .aux_io = POWER_DOMAIN_AUX_IO_A,
.aux_legacy_usbc = POWER_DOMAIN_AUX_A,
.aux_tbt = POWER_DOMAIN_INVALID,
},
@@ -2319,6 +2330,7 @@ d11_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_A,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_A,
+ .aux_io = POWER_DOMAIN_AUX_IO_A,
.aux_legacy_usbc = POWER_DOMAIN_AUX_A,
.aux_tbt = POWER_DOMAIN_INVALID,
}, {
@@ -2329,6 +2341,7 @@ d11_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_C,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_C,
+ .aux_io = POWER_DOMAIN_AUX_IO_C,
.aux_legacy_usbc = POWER_DOMAIN_AUX_C,
.aux_tbt = POWER_DOMAIN_AUX_TBT1,
},
@@ -2344,6 +2357,7 @@ d12_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_A,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_A,
+ .aux_io = POWER_DOMAIN_AUX_IO_A,
.aux_legacy_usbc = POWER_DOMAIN_AUX_A,
.aux_tbt = POWER_DOMAIN_INVALID,
}, {
@@ -2354,6 +2368,7 @@ d12_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_TC1,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_TC1,
+ .aux_io = POWER_DOMAIN_INVALID,
.aux_legacy_usbc = POWER_DOMAIN_AUX_USBC1,
.aux_tbt = POWER_DOMAIN_AUX_TBT1,
},
@@ -2369,6 +2384,7 @@ d13_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_A,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_A,
+ .aux_io = POWER_DOMAIN_AUX_IO_A,
.aux_legacy_usbc = POWER_DOMAIN_AUX_A,
.aux_tbt = POWER_DOMAIN_INVALID,
}, {
@@ -2379,6 +2395,7 @@ d13_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_TC1,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_TC1,
+ .aux_io = POWER_DOMAIN_INVALID,
.aux_legacy_usbc = POWER_DOMAIN_AUX_USBC1,
.aux_tbt = POWER_DOMAIN_AUX_TBT1,
}, {
@@ -2389,6 +2406,7 @@ d13_port_domains[] = {
.ddi_lanes = POWER_DOMAIN_PORT_DDI_LANES_D,
.ddi_io = POWER_DOMAIN_PORT_DDI_IO_D,
+ .aux_io = POWER_DOMAIN_AUX_IO_D,
.aux_legacy_usbc = POWER_DOMAIN_AUX_D,
.aux_tbt = POWER_DOMAIN_INVALID,
},
@@ -2434,7 +2452,7 @@ intel_display_power_ddi_io_domain(struct drm_i915_private *i915, enum port port)
{
const struct intel_ddi_port_domains *domains = intel_port_domains_for_port(i915, port);
- if (drm_WARN_ON(&i915->drm, !domains) || domains->ddi_io == POWER_DOMAIN_INVALID)
+ if (drm_WARN_ON(&i915->drm, !domains || domains->ddi_io == POWER_DOMAIN_INVALID))
return POWER_DOMAIN_PORT_DDI_IO_A;
return domains->ddi_io + (int)(port - domains->port_start);
@@ -2445,7 +2463,7 @@ intel_display_power_ddi_lanes_domain(struct drm_i915_private *i915, enum port po
{
const struct intel_ddi_port_domains *domains = intel_port_domains_for_port(i915, port);
- if (drm_WARN_ON(&i915->drm, !domains) || domains->ddi_lanes == POWER_DOMAIN_INVALID)
+ if (drm_WARN_ON(&i915->drm, !domains || domains->ddi_lanes == POWER_DOMAIN_INVALID))
return POWER_DOMAIN_PORT_DDI_LANES_A;
return domains->ddi_lanes + (int)(port - domains->port_start);
@@ -2467,11 +2485,22 @@ intel_port_domains_for_aux_ch(struct drm_i915_private *i915, enum aux_ch aux_ch)
}
enum intel_display_power_domain
+intel_display_power_aux_io_domain(struct drm_i915_private *i915, enum aux_ch aux_ch)
+{
+ const struct intel_ddi_port_domains *domains = intel_port_domains_for_aux_ch(i915, aux_ch);
+
+ if (drm_WARN_ON(&i915->drm, !domains || domains->aux_io == POWER_DOMAIN_INVALID))
+ return POWER_DOMAIN_AUX_IO_A;
+
+ return domains->aux_io + (int)(aux_ch - domains->aux_ch_start);
+}
+
+enum intel_display_power_domain
intel_display_power_legacy_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch)
{
const struct intel_ddi_port_domains *domains = intel_port_domains_for_aux_ch(i915, aux_ch);
- if (drm_WARN_ON(&i915->drm, !domains) || domains->aux_legacy_usbc == POWER_DOMAIN_INVALID)
+ if (drm_WARN_ON(&i915->drm, !domains || domains->aux_legacy_usbc == POWER_DOMAIN_INVALID))
return POWER_DOMAIN_AUX_A;
return domains->aux_legacy_usbc + (int)(aux_ch - domains->aux_ch_start);
@@ -2482,7 +2511,7 @@ intel_display_power_tbt_aux_domain(struct drm_i915_private *i915, enum aux_ch au
{
const struct intel_ddi_port_domains *domains = intel_port_domains_for_aux_ch(i915, aux_ch);
- if (drm_WARN_ON(&i915->drm, !domains) || domains->aux_tbt == POWER_DOMAIN_INVALID)
+ if (drm_WARN_ON(&i915->drm, !domains || domains->aux_tbt == POWER_DOMAIN_INVALID))
return POWER_DOMAIN_AUX_TBT1;
return domains->aux_tbt + (int)(aux_ch - domains->aux_ch_start);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 7136ea3f233e..2154d900b1aa 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -6,11 +6,12 @@
#ifndef __INTEL_DISPLAY_POWER_H__
#define __INTEL_DISPLAY_POWER_H__
-#include "intel_runtime_pm.h"
+#include "intel_wakeref.h"
enum aux_ch;
enum dpio_channel;
enum dpio_phy;
+enum i915_drm_suspend_mode;
enum port;
struct drm_i915_private;
struct i915_power_well;
@@ -76,6 +77,14 @@ enum intel_display_power_domain {
POWER_DOMAIN_VGA,
POWER_DOMAIN_AUDIO_MMIO,
POWER_DOMAIN_AUDIO_PLAYBACK,
+
+ POWER_DOMAIN_AUX_IO_A,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
+ POWER_DOMAIN_AUX_IO_D,
+ POWER_DOMAIN_AUX_IO_E,
+ POWER_DOMAIN_AUX_IO_F,
+
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
@@ -90,8 +99,6 @@ enum intel_display_power_domain {
POWER_DOMAIN_AUX_USBC5,
POWER_DOMAIN_AUX_USBC6,
- POWER_DOMAIN_AUX_IO_A,
-
POWER_DOMAIN_AUX_TBT1,
POWER_DOMAIN_AUX_TBT2,
POWER_DOMAIN_AUX_TBT3,
@@ -249,6 +256,8 @@ intel_display_power_ddi_lanes_domain(struct drm_i915_private *i915, enum port po
enum intel_display_power_domain
intel_display_power_ddi_io_domain(struct drm_i915_private *i915, enum port port);
enum intel_display_power_domain
+intel_display_power_aux_io_domain(struct drm_i915_private *i915, enum aux_ch aux_ch);
+enum intel_display_power_domain
intel_display_power_legacy_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch);
enum intel_display_power_domain
intel_display_power_tbt_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c
index dc04afc6cc8f..f5d66ca85b19 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_map.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c
@@ -170,6 +170,8 @@ I915_DECL_PW_DOMAINS(vlv_pwdoms_display,
POWER_DOMAIN_VGA,
POWER_DOMAIN_AUDIO_MMIO,
POWER_DOMAIN_AUDIO_PLAYBACK,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_GMBUS,
@@ -179,6 +181,8 @@ I915_DECL_PW_DOMAINS(vlv_pwdoms_dpio_cmn_bc,
POWER_DOMAIN_PORT_DDI_LANES_B,
POWER_DOMAIN_PORT_DDI_LANES_C,
POWER_DOMAIN_PORT_CRT,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
@@ -186,6 +190,8 @@ I915_DECL_PW_DOMAINS(vlv_pwdoms_dpio_cmn_bc,
I915_DECL_PW_DOMAINS(vlv_pwdoms_dpio_tx_bc_lanes,
POWER_DOMAIN_PORT_DDI_LANES_B,
POWER_DOMAIN_PORT_DDI_LANES_C,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
@@ -243,6 +249,9 @@ I915_DECL_PW_DOMAINS(chv_pwdoms_display,
POWER_DOMAIN_VGA,
POWER_DOMAIN_AUDIO_MMIO,
POWER_DOMAIN_AUDIO_PLAYBACK,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
+ POWER_DOMAIN_AUX_IO_D,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_AUX_D,
@@ -252,12 +261,15 @@ I915_DECL_PW_DOMAINS(chv_pwdoms_display,
I915_DECL_PW_DOMAINS(chv_pwdoms_dpio_cmn_bc,
POWER_DOMAIN_PORT_DDI_LANES_B,
POWER_DOMAIN_PORT_DDI_LANES_C,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(chv_pwdoms_dpio_cmn_d,
POWER_DOMAIN_PORT_DDI_LANES_D,
+ POWER_DOMAIN_AUX_IO_D,
POWER_DOMAIN_AUX_D,
POWER_DOMAIN_INIT);
@@ -305,6 +317,9 @@ static const struct i915_power_well_desc_list chv_power_wells[] = {
POWER_DOMAIN_VGA, \
POWER_DOMAIN_AUDIO_MMIO, \
POWER_DOMAIN_AUDIO_PLAYBACK, \
+ POWER_DOMAIN_AUX_IO_B, \
+ POWER_DOMAIN_AUX_IO_C, \
+ POWER_DOMAIN_AUX_IO_D, \
POWER_DOMAIN_AUX_B, \
POWER_DOMAIN_AUX_C, \
POWER_DOMAIN_AUX_D
@@ -318,6 +333,7 @@ I915_DECL_PW_DOMAINS(skl_pwdoms_dc_off,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_MODESET,
POWER_DOMAIN_GT_IRQ,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(skl_pwdoms_ddi_io_a_e,
@@ -407,6 +423,8 @@ static const struct i915_power_well_desc_list skl_power_wells[] = {
POWER_DOMAIN_VGA, \
POWER_DOMAIN_AUDIO_MMIO, \
POWER_DOMAIN_AUDIO_PLAYBACK, \
+ POWER_DOMAIN_AUX_IO_B, \
+ POWER_DOMAIN_AUX_IO_C, \
POWER_DOMAIN_AUX_B, \
POWER_DOMAIN_AUX_C
@@ -420,16 +438,20 @@ I915_DECL_PW_DOMAINS(bxt_pwdoms_dc_off,
POWER_DOMAIN_GMBUS,
POWER_DOMAIN_MODESET,
POWER_DOMAIN_GT_IRQ,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(bxt_pwdoms_dpio_cmn_a,
POWER_DOMAIN_PORT_DDI_LANES_A,
+ POWER_DOMAIN_AUX_IO_A,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(bxt_pwdoms_dpio_cmn_bc,
POWER_DOMAIN_PORT_DDI_LANES_B,
POWER_DOMAIN_PORT_DDI_LANES_C,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
@@ -483,6 +505,8 @@ static const struct i915_power_well_desc_list bxt_power_wells[] = {
POWER_DOMAIN_VGA, \
POWER_DOMAIN_AUDIO_MMIO, \
POWER_DOMAIN_AUDIO_PLAYBACK, \
+ POWER_DOMAIN_AUX_IO_B, \
+ POWER_DOMAIN_AUX_IO_C, \
POWER_DOMAIN_AUX_B, \
POWER_DOMAIN_AUX_C
@@ -496,6 +520,7 @@ I915_DECL_PW_DOMAINS(glk_pwdoms_dc_off,
POWER_DOMAIN_GMBUS,
POWER_DOMAIN_MODESET,
POWER_DOMAIN_GT_IRQ,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_ddi_io_a, POWER_DOMAIN_PORT_DDI_IO_A);
@@ -504,29 +529,34 @@ I915_DECL_PW_DOMAINS(glk_pwdoms_ddi_io_c, POWER_DOMAIN_PORT_DDI_IO_C);
I915_DECL_PW_DOMAINS(glk_pwdoms_dpio_cmn_a,
POWER_DOMAIN_PORT_DDI_LANES_A,
+ POWER_DOMAIN_AUX_IO_A,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_dpio_cmn_b,
POWER_DOMAIN_PORT_DDI_LANES_B,
+ POWER_DOMAIN_AUX_IO_B,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_dpio_cmn_c,
POWER_DOMAIN_PORT_DDI_LANES_C,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_aux_a,
- POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_IO_A,
+ POWER_DOMAIN_AUX_A,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_aux_b,
+ POWER_DOMAIN_AUX_IO_B,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(glk_pwdoms_aux_c,
+ POWER_DOMAIN_AUX_IO_C,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_INIT);
@@ -617,6 +647,11 @@ I915_DECL_PW_DOMAINS(icl_pwdoms_pw_4,
POWER_DOMAIN_VGA, \
POWER_DOMAIN_AUDIO_MMIO, \
POWER_DOMAIN_AUDIO_PLAYBACK, \
+ POWER_DOMAIN_AUX_IO_B, \
+ POWER_DOMAIN_AUX_IO_C, \
+ POWER_DOMAIN_AUX_IO_D, \
+ POWER_DOMAIN_AUX_IO_E, \
+ POWER_DOMAIN_AUX_IO_F, \
POWER_DOMAIN_AUX_B, \
POWER_DOMAIN_AUX_C, \
POWER_DOMAIN_AUX_D, \
@@ -658,13 +693,23 @@ I915_DECL_PW_DOMAINS(icl_pwdoms_ddi_io_e, POWER_DOMAIN_PORT_DDI_IO_E);
I915_DECL_PW_DOMAINS(icl_pwdoms_ddi_io_f, POWER_DOMAIN_PORT_DDI_IO_F);
I915_DECL_PW_DOMAINS(icl_pwdoms_aux_a,
- POWER_DOMAIN_AUX_A,
- POWER_DOMAIN_AUX_IO_A);
-I915_DECL_PW_DOMAINS(icl_pwdoms_aux_b, POWER_DOMAIN_AUX_B);
-I915_DECL_PW_DOMAINS(icl_pwdoms_aux_c, POWER_DOMAIN_AUX_C);
-I915_DECL_PW_DOMAINS(icl_pwdoms_aux_d, POWER_DOMAIN_AUX_D);
-I915_DECL_PW_DOMAINS(icl_pwdoms_aux_e, POWER_DOMAIN_AUX_E);
-I915_DECL_PW_DOMAINS(icl_pwdoms_aux_f, POWER_DOMAIN_AUX_F);
+ POWER_DOMAIN_AUX_IO_A,
+ POWER_DOMAIN_AUX_A);
+I915_DECL_PW_DOMAINS(icl_pwdoms_aux_b,
+ POWER_DOMAIN_AUX_IO_B,
+ POWER_DOMAIN_AUX_B);
+I915_DECL_PW_DOMAINS(icl_pwdoms_aux_c,
+ POWER_DOMAIN_AUX_IO_C,
+ POWER_DOMAIN_AUX_C);
+I915_DECL_PW_DOMAINS(icl_pwdoms_aux_d,
+ POWER_DOMAIN_AUX_IO_D,
+ POWER_DOMAIN_AUX_D);
+I915_DECL_PW_DOMAINS(icl_pwdoms_aux_e,
+ POWER_DOMAIN_AUX_IO_E,
+ POWER_DOMAIN_AUX_E);
+I915_DECL_PW_DOMAINS(icl_pwdoms_aux_f,
+ POWER_DOMAIN_AUX_IO_F,
+ POWER_DOMAIN_AUX_F);
I915_DECL_PW_DOMAINS(icl_pwdoms_aux_tbt1, POWER_DOMAIN_AUX_TBT1);
I915_DECL_PW_DOMAINS(icl_pwdoms_aux_tbt2, POWER_DOMAIN_AUX_TBT2);
I915_DECL_PW_DOMAINS(icl_pwdoms_aux_tbt3, POWER_DOMAIN_AUX_TBT3);
@@ -816,6 +861,7 @@ I915_DECL_PW_DOMAINS(tgl_pwdoms_dc_off,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_MODESET,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(tgl_pwdoms_ddi_io_tc1, POWER_DOMAIN_PORT_DDI_IO_TC1);
@@ -1012,6 +1058,7 @@ I915_DECL_PW_DOMAINS(rkl_pwdoms_dc_off,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_MODESET,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
static const struct i915_power_well_desc rkl_power_wells_main[] = {
@@ -1094,6 +1141,7 @@ I915_DECL_PW_DOMAINS(dg1_pwdoms_dc_off,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_MODESET,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(dg1_pwdoms_pw_2,
@@ -1215,6 +1263,9 @@ I915_DECL_PW_DOMAINS(xelpd_pwdoms_pw_a,
POWER_DOMAIN_PORT_DDI_LANES_TC4, \
POWER_DOMAIN_VGA, \
POWER_DOMAIN_AUDIO_PLAYBACK, \
+ POWER_DOMAIN_AUX_IO_C, \
+ POWER_DOMAIN_AUX_IO_D, \
+ POWER_DOMAIN_AUX_IO_E, \
POWER_DOMAIN_AUX_C, \
POWER_DOMAIN_AUX_D, \
POWER_DOMAIN_AUX_E, \
@@ -1255,6 +1306,7 @@ I915_DECL_PW_DOMAINS(xelpd_pwdoms_dc_off,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_MODESET,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
static const struct i915_power_well_desc xelpd_power_wells_main[] = {
@@ -1376,6 +1428,7 @@ I915_DECL_PW_DOMAINS(xelpdp_pwdoms_dc_off,
POWER_DOMAIN_MODESET,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
+ POWER_DOMAIN_DC_OFF,
POWER_DOMAIN_INIT);
I915_DECL_PW_DOMAINS(xelpdp_pwdoms_aux_tc1,
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c
index 1d18eee56253..8710dd41ffd4 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c
@@ -13,6 +13,7 @@
#include "intel_display_power_well.h"
#include "intel_display_types.h"
#include "intel_dkl_phy.h"
+#include "intel_dkl_phy_regs.h"
#include "intel_dmc.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
@@ -531,7 +532,7 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
tc_port = TGL_AUX_PW_TO_TC_PORT(i915_power_well_instance(power_well)->hsw.idx);
- if (wait_for(intel_dkl_phy_read(dev_priv, DKL_CMN_UC_DW_27(tc_port), 2) &
+ if (wait_for(intel_dkl_phy_read(dev_priv, DKL_CMN_UC_DW_27(tc_port)) &
DKL_CMN_UC_DW27_UC_HEALTH, 1))
drm_warn(&dev_priv->drm,
"Timeout waiting TC uC health\n");
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h
index e13b521e322a..ba7cb977e7c7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h
@@ -7,8 +7,8 @@
#include <linux/types.h>
-#include "intel_display.h"
#include "intel_display_power.h"
+#include "intel_dpio_phy.h"
struct drm_i915_private;
struct i915_power_well;
diff --git a/drivers/gpu/drm/i915/display/intel_display_reg_defs.h b/drivers/gpu/drm/i915/display/intel_display_reg_defs.h
new file mode 100644
index 000000000000..02605418ff08
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_display_reg_defs.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_DISPLAY_REG_DEFS_H__
+#define __INTEL_DISPLAY_REG_DEFS_H__
+
+#include "i915_reg_defs.h"
+
+#define DISPLAY_MMIO_BASE(dev_priv) (INTEL_INFO(dev_priv)->display.mmio_offset)
+
+#define VLV_DISPLAY_BASE 0x180000
+
+/*
+ * Named helper wrappers around _PICK_EVEN() and _PICK().
+ */
+#define _PIPE(pipe, a, b) _PICK_EVEN(pipe, a, b)
+#define _PLANE(plane, a, b) _PICK_EVEN(plane, a, b)
+#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b)
+#define _PORT(port, a, b) _PICK_EVEN(port, a, b)
+#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b)
+#define _PHY(phy, a, b) _PICK_EVEN(phy, a, b)
+
+#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
+#define _MMIO_PLANE(plane, a, b) _MMIO(_PLANE(plane, a, b))
+#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
+#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
+#define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b))
+#define _MMIO_PHY(phy, a, b) _MMIO(_PHY(phy, a, b))
+
+#define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__)
+
+#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
+#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
+#define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
+#define _MMIO_PLL3(pll, ...) _MMIO(_PICK(pll, __VA_ARGS__))
+
+/*
+ * Device info offset array based helpers for groups of registers with unevenly
+ * spaced base offsets.
+ */
+#define _MMIO_PIPE2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->display.pipe_offsets[(pipe)] - \
+ INTEL_INFO(dev_priv)->display.pipe_offsets[PIPE_A] + \
+ DISPLAY_MMIO_BASE(dev_priv) + (reg))
+#define _MMIO_TRANS2(tran, reg) _MMIO(INTEL_INFO(dev_priv)->display.trans_offsets[(tran)] - \
+ INTEL_INFO(dev_priv)->display.trans_offsets[TRANSCODER_A] + \
+ DISPLAY_MMIO_BASE(dev_priv) + (reg))
+#define _MMIO_CURSOR2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->display.cursor_offsets[(pipe)] - \
+ INTEL_INFO(dev_priv)->display.cursor_offsets[PIPE_A] + \
+ DISPLAY_MMIO_BASE(dev_priv) + (reg))
+
+#endif /* __INTEL_DISPLAY_REG_DEFS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h
index 2dd5a4b7f5d8..725aba3fa531 100644
--- a/drivers/gpu/drm/i915/display/intel_display_trace.h
+++ b/drivers/gpu/drm/i915/display/intel_display_trace.h
@@ -18,11 +18,15 @@
#include "intel_crtc.h"
#include "intel_display_types.h"
+#define __dev_name_i915(i915) dev_name((i915)->drm.dev)
+#define __dev_name_kms(obj) dev_name((obj)->base.dev->dev)
+
TRACE_EVENT(intel_pipe_enable,
TP_PROTO(struct intel_crtc *crtc),
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__array(u32, frame, 3)
__array(u32, scanline, 3)
__field(enum pipe, pipe)
@@ -30,6 +34,7 @@ TRACE_EVENT(intel_pipe_enable,
TP_fast_assign(
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_crtc *it__;
+ __assign_str(dev, __dev_name_kms(crtc));
for_each_intel_crtc(&dev_priv->drm, it__) {
__entry->frame[it__->pipe] = intel_crtc_get_vblank_counter(it__);
__entry->scanline[it__->pipe] = intel_get_crtc_scanline(it__);
@@ -37,8 +42,8 @@ TRACE_EVENT(intel_pipe_enable,
__entry->pipe = crtc->pipe;
),
- TP_printk("pipe %c enable, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
- pipe_name(__entry->pipe),
+ TP_printk("dev %s, pipe %c enable, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
__entry->frame[PIPE_A], __entry->scanline[PIPE_A],
__entry->frame[PIPE_B], __entry->scanline[PIPE_B],
__entry->frame[PIPE_C], __entry->scanline[PIPE_C])
@@ -49,6 +54,7 @@ TRACE_EVENT(intel_pipe_disable,
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__array(u32, frame, 3)
__array(u32, scanline, 3)
__field(enum pipe, pipe)
@@ -57,6 +63,7 @@ TRACE_EVENT(intel_pipe_disable,
TP_fast_assign(
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_crtc *it__;
+ __assign_str(dev, __dev_name_kms(crtc));
for_each_intel_crtc(&dev_priv->drm, it__) {
__entry->frame[it__->pipe] = intel_crtc_get_vblank_counter(it__);
__entry->scanline[it__->pipe] = intel_get_crtc_scanline(it__);
@@ -64,8 +71,8 @@ TRACE_EVENT(intel_pipe_disable,
__entry->pipe = crtc->pipe;
),
- TP_printk("pipe %c disable, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
- pipe_name(__entry->pipe),
+ TP_printk("dev %s, pipe %c disable, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
__entry->frame[PIPE_A], __entry->scanline[PIPE_A],
__entry->frame[PIPE_B], __entry->scanline[PIPE_B],
__entry->frame[PIPE_C], __entry->scanline[PIPE_C])
@@ -76,6 +83,7 @@ TRACE_EVENT(intel_pipe_crc,
TP_ARGS(crtc, crcs),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -83,16 +91,19 @@ TRACE_EVENT(intel_pipe_crc,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
memcpy(__entry->crcs, crcs, sizeof(__entry->crcs));
),
- TP_printk("pipe %c, frame=%u, scanline=%u crc=%08x %08x %08x %08x %08x",
- pipe_name(__entry->pipe), __entry->frame, __entry->scanline,
- __entry->crcs[0], __entry->crcs[1], __entry->crcs[2],
- __entry->crcs[3], __entry->crcs[4])
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u crc=%08x %08x %08x %08x %08x",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
+ __entry->crcs[0], __entry->crcs[1],
+ __entry->crcs[2], __entry->crcs[3],
+ __entry->crcs[4])
);
TRACE_EVENT(intel_cpu_fifo_underrun,
@@ -100,6 +111,7 @@ TRACE_EVENT(intel_cpu_fifo_underrun,
TP_ARGS(dev_priv, pipe),
TP_STRUCT__entry(
+ __string(dev, __dev_name_i915(dev_priv))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -107,13 +119,14 @@ TRACE_EVENT(intel_cpu_fifo_underrun,
TP_fast_assign(
struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe),
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
__entry->frame, __entry->scanline)
);
@@ -122,6 +135,7 @@ TRACE_EVENT(intel_pch_fifo_underrun,
TP_ARGS(dev_priv, pch_transcoder),
TP_STRUCT__entry(
+ __string(dev, __dev_name_i915(dev_priv))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -130,13 +144,14 @@ TRACE_EVENT(intel_pch_fifo_underrun,
TP_fast_assign(
enum pipe pipe = pch_transcoder;
struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ __assign_str(dev, __dev_name_i915(dev_priv));
__entry->pipe = pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pch transcoder %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe),
+ TP_printk("dev %s, pch transcoder %c, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
__entry->frame, __entry->scanline)
);
@@ -145,6 +160,7 @@ TRACE_EVENT(intel_memory_cxsr,
TP_ARGS(dev_priv, old, new),
TP_STRUCT__entry(
+ __string(dev, __dev_name_i915(dev_priv))
__array(u32, frame, 3)
__array(u32, scanline, 3)
__field(bool, old)
@@ -153,6 +169,7 @@ TRACE_EVENT(intel_memory_cxsr,
TP_fast_assign(
struct intel_crtc *crtc;
+ __assign_str(dev, __dev_name_i915(dev_priv));
for_each_intel_crtc(&dev_priv->drm, crtc) {
__entry->frame[crtc->pipe] = intel_crtc_get_vblank_counter(crtc);
__entry->scanline[crtc->pipe] = intel_get_crtc_scanline(crtc);
@@ -161,8 +178,8 @@ TRACE_EVENT(intel_memory_cxsr,
__entry->new = new;
),
- TP_printk("%s->%s, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
- str_on_off(__entry->old), str_on_off(__entry->new),
+ TP_printk("dev %s, cxsr %s->%s, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u",
+ __get_str(dev), str_on_off(__entry->old), str_on_off(__entry->new),
__entry->frame[PIPE_A], __entry->scanline[PIPE_A],
__entry->frame[PIPE_B], __entry->scanline[PIPE_B],
__entry->frame[PIPE_C], __entry->scanline[PIPE_C])
@@ -173,6 +190,7 @@ TRACE_EVENT(g4x_wm,
TP_ARGS(crtc, wm),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -191,6 +209,7 @@ TRACE_EVENT(g4x_wm,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
@@ -208,8 +227,9 @@ TRACE_EVENT(g4x_wm,
__entry->fbc = wm->fbc_en;
),
- TP_printk("pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s",
- pipe_name(__entry->pipe), __entry->frame, __entry->scanline,
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
__entry->primary, __entry->sprite, __entry->cursor,
str_yes_no(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc,
str_yes_no(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc,
@@ -221,6 +241,7 @@ TRACE_EVENT(vlv_wm,
TP_ARGS(crtc, wm),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -235,6 +256,7 @@ TRACE_EVENT(vlv_wm,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
@@ -248,9 +270,10 @@ TRACE_EVENT(vlv_wm,
__entry->sr_cursor = wm->sr.cursor;
),
- TP_printk("pipe %c, frame=%u, scanline=%u, level=%d, cxsr=%d, wm %d/%d/%d/%d, sr %d/%d",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline, __entry->level, __entry->cxsr,
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u, level=%d, cxsr=%d, wm %d/%d/%d/%d, sr %d/%d",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
+ __entry->level, __entry->cxsr,
__entry->primary, __entry->sprite0, __entry->sprite1, __entry->cursor,
__entry->sr_plane, __entry->sr_cursor)
);
@@ -260,6 +283,7 @@ TRACE_EVENT(vlv_fifo_size,
TP_ARGS(crtc, sprite0_start, sprite1_start, fifo_size),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -269,6 +293,7 @@ TRACE_EVENT(vlv_fifo_size,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
@@ -277,90 +302,96 @@ TRACE_EVENT(vlv_fifo_size,
__entry->fifo_size = fifo_size;
),
- TP_printk("pipe %c, frame=%u, scanline=%u, %d/%d/%d",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline, __entry->sprite0_start,
- __entry->sprite1_start, __entry->fifo_size)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u, %d/%d/%d",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
+ __entry->sprite0_start, __entry->sprite1_start, __entry->fifo_size)
);
TRACE_EVENT(intel_plane_update_noarm,
- TP_PROTO(struct drm_plane *plane, struct intel_crtc *crtc),
+ TP_PROTO(struct intel_plane *plane, struct intel_crtc *crtc),
TP_ARGS(plane, crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
__array(int, src, 4)
__array(int, dst, 4)
- __string(name, plane->name)
+ __string(name, plane->base.name)
),
TP_fast_assign(
- __assign_str(name, plane->name);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name);
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
- memcpy(__entry->src, &plane->state->src, sizeof(__entry->src));
- memcpy(__entry->dst, &plane->state->dst, sizeof(__entry->dst));
+ memcpy(__entry->src, &plane->base.state->src, sizeof(__entry->src));
+ memcpy(__entry->dst, &plane->base.state->dst, sizeof(__entry->dst));
),
- TP_printk("pipe %c, plane %s, frame=%u, scanline=%u, " DRM_RECT_FP_FMT " -> " DRM_RECT_FMT,
- pipe_name(__entry->pipe), __get_str(name),
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u, " DRM_RECT_FP_FMT " -> " DRM_RECT_FMT,
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
__entry->frame, __entry->scanline,
DRM_RECT_FP_ARG((const struct drm_rect *)__entry->src),
DRM_RECT_ARG((const struct drm_rect *)__entry->dst))
);
TRACE_EVENT(intel_plane_update_arm,
- TP_PROTO(struct drm_plane *plane, struct intel_crtc *crtc),
+ TP_PROTO(struct intel_plane *plane, struct intel_crtc *crtc),
TP_ARGS(plane, crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
__array(int, src, 4)
__array(int, dst, 4)
- __string(name, plane->name)
+ __string(name, plane->base.name)
),
TP_fast_assign(
- __assign_str(name, plane->name);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name);
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
- memcpy(__entry->src, &plane->state->src, sizeof(__entry->src));
- memcpy(__entry->dst, &plane->state->dst, sizeof(__entry->dst));
+ memcpy(__entry->src, &plane->base.state->src, sizeof(__entry->src));
+ memcpy(__entry->dst, &plane->base.state->dst, sizeof(__entry->dst));
),
- TP_printk("pipe %c, plane %s, frame=%u, scanline=%u, " DRM_RECT_FP_FMT " -> " DRM_RECT_FMT,
- pipe_name(__entry->pipe), __get_str(name),
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u, " DRM_RECT_FP_FMT " -> " DRM_RECT_FMT,
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
__entry->frame, __entry->scanline,
DRM_RECT_FP_ARG((const struct drm_rect *)__entry->src),
DRM_RECT_ARG((const struct drm_rect *)__entry->dst))
);
TRACE_EVENT(intel_plane_disable_arm,
- TP_PROTO(struct drm_plane *plane, struct intel_crtc *crtc),
+ TP_PROTO(struct intel_plane *plane, struct intel_crtc *crtc),
TP_ARGS(plane, crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
- __string(name, plane->name)
+ __string(name, plane->base.name)
),
TP_fast_assign(
- __assign_str(name, plane->name);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name);
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, plane %s, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __get_str(name),
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
__entry->frame, __entry->scanline)
);
@@ -369,6 +400,8 @@ TRACE_EVENT(intel_fbc_activate,
TP_ARGS(plane),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
+ __string(name, plane->base.name)
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -377,13 +410,16 @@ TRACE_EVENT(intel_fbc_activate,
TP_fast_assign(
struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
plane->pipe);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name)
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame, __entry->scanline)
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_fbc_deactivate,
@@ -391,6 +427,8 @@ TRACE_EVENT(intel_fbc_deactivate,
TP_ARGS(plane),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
+ __string(name, plane->base.name)
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -399,13 +437,16 @@ TRACE_EVENT(intel_fbc_deactivate,
TP_fast_assign(
struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
plane->pipe);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name)
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame, __entry->scanline)
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_fbc_nuke,
@@ -413,6 +454,8 @@ TRACE_EVENT(intel_fbc_nuke,
TP_ARGS(plane),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(plane))
+ __string(name, plane->base.name)
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -421,13 +464,16 @@ TRACE_EVENT(intel_fbc_nuke,
TP_fast_assign(
struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
plane->pipe);
+ __assign_str(dev, __dev_name_kms(plane));
+ __assign_str(name, plane->base.name)
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame, __entry->scanline)
+ TP_printk("dev %s, pipe %c, plane %s, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe), __get_str(name),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_crtc_vblank_work_start,
@@ -435,20 +481,22 @@ TRACE_EVENT(intel_crtc_vblank_work_start,
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_crtc_vblank_work_end,
@@ -456,20 +504,22 @@ TRACE_EVENT(intel_crtc_vblank_work_end,
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_pipe_update_start,
@@ -477,6 +527,7 @@ TRACE_EVENT(intel_pipe_update_start,
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -485,6 +536,7 @@ TRACE_EVENT(intel_pipe_update_start,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
__entry->scanline = intel_get_crtc_scanline(crtc);
@@ -492,9 +544,10 @@ TRACE_EVENT(intel_pipe_update_start,
__entry->max = crtc->debug.max_vbl;
),
- TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline, __entry->min, __entry->max)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
+ __entry->min, __entry->max)
);
TRACE_EVENT(intel_pipe_update_vblank_evaded,
@@ -502,6 +555,7 @@ TRACE_EVENT(intel_pipe_update_vblank_evaded,
TP_ARGS(crtc),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
@@ -510,6 +564,7 @@ TRACE_EVENT(intel_pipe_update_vblank_evaded,
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = crtc->debug.start_vbl_count;
__entry->scanline = crtc->debug.scanline_start;
@@ -517,9 +572,10 @@ TRACE_EVENT(intel_pipe_update_vblank_evaded,
__entry->max = crtc->debug.max_vbl;
),
- TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline, __entry->min, __entry->max)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline,
+ __entry->min, __entry->max)
);
TRACE_EVENT(intel_pipe_update_end,
@@ -527,56 +583,64 @@ TRACE_EVENT(intel_pipe_update_end,
TP_ARGS(crtc, frame, scanline_end),
TP_STRUCT__entry(
+ __string(dev, __dev_name_kms(crtc))
__field(enum pipe, pipe)
__field(u32, frame)
__field(u32, scanline)
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_kms(crtc));
__entry->pipe = crtc->pipe;
__entry->frame = frame;
__entry->scanline = scanline_end;
),
- TP_printk("pipe %c, frame=%u, scanline=%u",
- pipe_name(__entry->pipe), __entry->frame,
- __entry->scanline)
+ TP_printk("dev %s, pipe %c, frame=%u, scanline=%u",
+ __get_str(dev), pipe_name(__entry->pipe),
+ __entry->frame, __entry->scanline)
);
TRACE_EVENT(intel_frontbuffer_invalidate,
- TP_PROTO(unsigned int frontbuffer_bits, unsigned int origin),
- TP_ARGS(frontbuffer_bits, origin),
+ TP_PROTO(struct drm_i915_private *i915,
+ unsigned int frontbuffer_bits, unsigned int origin),
+ TP_ARGS(i915, frontbuffer_bits, origin),
TP_STRUCT__entry(
+ __string(dev, __dev_name_i915(i915))
__field(unsigned int, frontbuffer_bits)
__field(unsigned int, origin)
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_i915(i915));
__entry->frontbuffer_bits = frontbuffer_bits;
__entry->origin = origin;
),
- TP_printk("frontbuffer_bits=0x%08x, origin=%u",
- __entry->frontbuffer_bits, __entry->origin)
+ TP_printk("dev %s, frontbuffer_bits=0x%08x, origin=%u",
+ __get_str(dev), __entry->frontbuffer_bits, __entry->origin)
);
TRACE_EVENT(intel_frontbuffer_flush,
- TP_PROTO(unsigned int frontbuffer_bits, unsigned int origin),
- TP_ARGS(frontbuffer_bits, origin),
+ TP_PROTO(struct drm_i915_private *i915,
+ unsigned int frontbuffer_bits, unsigned int origin),
+ TP_ARGS(i915, frontbuffer_bits, origin),
TP_STRUCT__entry(
+ __string(dev, __dev_name_i915(i915))
__field(unsigned int, frontbuffer_bits)
__field(unsigned int, origin)
),
TP_fast_assign(
+ __assign_str(dev, __dev_name_i915(i915));
__entry->frontbuffer_bits = frontbuffer_bits;
__entry->origin = origin;
),
- TP_printk("frontbuffer_bits=0x%08x, origin=%u",
- __entry->frontbuffer_bits, __entry->origin)
+ TP_printk("dev %s, frontbuffer_bits=0x%08x, origin=%u",
+ __get_str(dev), __entry->frontbuffer_bits, __entry->origin)
);
#endif /* __INTEL_DISPLAY_TRACE_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 298d00a11f47..f07395065a69 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -969,6 +969,15 @@ struct intel_mpllb_state {
u32 mpllb_sscstep;
};
+/* Used by dp and fdi links */
+struct intel_link_m_n {
+ u32 tu;
+ u32 data_m;
+ u32 data_n;
+ u32 link_m;
+ u32 link_n;
+};
+
struct intel_crtc_state {
/*
* uapi (drm) state. This is the software state shown to userspace.
@@ -1001,11 +1010,15 @@ struct intel_crtc_state {
*/
struct {
bool active, enable;
+ /* logical state of LUTs */
struct drm_property_blob *degamma_lut, *gamma_lut, *ctm;
struct drm_display_mode mode, pipe_mode, adjusted_mode;
enum drm_scaling_filter scaling_filter;
} hw;
+ /* actual state of LUTs */
+ struct drm_property_blob *pre_csc_lut, *post_csc_lut;
+
/**
* quirks - bitfield with hw state readout quirks
*
@@ -1362,6 +1375,7 @@ struct intel_crtc {
u16 vmax_vblank_start;
struct intel_display_power_domain_set enabled_power_domains;
+ struct intel_display_power_domain_set hw_readout_power_domains;
struct intel_overlay *overlay;
struct intel_crtc_state *config;
@@ -1799,51 +1813,6 @@ struct intel_dp_mst_encoder {
struct intel_connector *connector;
};
-static inline enum dpio_channel
-vlv_dig_port_to_channel(struct intel_digital_port *dig_port)
-{
- switch (dig_port->base.port) {
- default:
- MISSING_CASE(dig_port->base.port);
- fallthrough;
- case PORT_B:
- case PORT_D:
- return DPIO_CH0;
- case PORT_C:
- return DPIO_CH1;
- }
-}
-
-static inline enum dpio_phy
-vlv_dig_port_to_phy(struct intel_digital_port *dig_port)
-{
- switch (dig_port->base.port) {
- default:
- MISSING_CASE(dig_port->base.port);
- fallthrough;
- case PORT_B:
- case PORT_C:
- return DPIO_PHY0;
- case PORT_D:
- return DPIO_PHY1;
- }
-}
-
-static inline enum dpio_channel
-vlv_pipe_to_channel(enum pipe pipe)
-{
- switch (pipe) {
- default:
- MISSING_CASE(pipe);
- fallthrough;
- case PIPE_A:
- case PIPE_C:
- return DPIO_CH0;
- case PIPE_B:
- return DPIO_CH1;
- }
-}
-
struct intel_load_detect_pipe {
struct drm_atomic_state *restore_state;
};
@@ -2040,15 +2009,16 @@ static inline bool
intel_crtc_has_type(const struct intel_crtc_state *crtc_state,
enum intel_output_type type)
{
- return crtc_state->output_types & (1 << type);
+ return crtc_state->output_types & BIT(type);
}
+
static inline bool
intel_crtc_has_dp_encoder(const struct intel_crtc_state *crtc_state)
{
return crtc_state->output_types &
- ((1 << INTEL_OUTPUT_DP) |
- (1 << INTEL_OUTPUT_DP_MST) |
- (1 << INTEL_OUTPUT_EDP));
+ (BIT(INTEL_OUTPUT_DP) |
+ BIT(INTEL_OUTPUT_DP_MST) |
+ BIT(INTEL_OUTPUT_EDP));
}
static inline bool
@@ -2057,6 +2027,20 @@ intel_crtc_needs_modeset(const struct intel_crtc_state *crtc_state)
return drm_atomic_crtc_needs_modeset(&crtc_state->uapi);
}
+static inline bool
+intel_crtc_needs_fastset(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->update_pipe;
+}
+
+static inline bool
+intel_crtc_needs_color_update(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->uapi.color_mgmt_changed ||
+ intel_crtc_needs_fastset(crtc_state) ||
+ intel_crtc_needs_modeset(crtc_state);
+}
+
static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state)
{
return i915_ggtt_offset(plane_state->ggtt_vma);
diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.c b/drivers/gpu/drm/i915/display/intel_dkl_phy.c
index 710b030c7ed5..57cc3edba016 100644
--- a/drivers/gpu/drm/i915/display/intel_dkl_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.c
@@ -9,9 +9,10 @@
#include "intel_de.h"
#include "intel_display.h"
#include "intel_dkl_phy.h"
+#include "intel_dkl_phy_regs.h"
static void
-dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx)
+dkl_phy_set_hip_idx(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg)
{
enum tc_port tc_port = DKL_REG_TC_PORT(reg);
@@ -19,28 +20,27 @@ dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx)
intel_de_write(i915,
HIP_INDEX_REG(tc_port),
- HIP_INDEX_VAL(tc_port, idx));
+ HIP_INDEX_VAL(tc_port, reg.bank_idx));
}
/**
* intel_dkl_phy_read - read a Dekel PHY register
* @i915: i915 device instance
* @reg: Dekel PHY register
- * @ln: lane instance of @reg
*
* Read the @reg Dekel PHY register.
*
* Returns the read value.
*/
u32
-intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln)
+intel_dkl_phy_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg)
{
u32 val;
spin_lock(&i915->display.dkl.phy_lock);
- dkl_phy_set_hip_idx(i915, reg, ln);
- val = intel_de_read(i915, reg);
+ dkl_phy_set_hip_idx(i915, reg);
+ val = intel_de_read(i915, DKL_REG_MMIO(reg));
spin_unlock(&i915->display.dkl.phy_lock);
@@ -51,18 +51,17 @@ intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln)
* intel_dkl_phy_write - write a Dekel PHY register
* @i915: i915 device instance
* @reg: Dekel PHY register
- * @ln: lane instance of @reg
* @val: value to write
*
* Write @val to the @reg Dekel PHY register.
*/
void
-intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val)
+intel_dkl_phy_write(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 val)
{
spin_lock(&i915->display.dkl.phy_lock);
- dkl_phy_set_hip_idx(i915, reg, ln);
- intel_de_write(i915, reg, val);
+ dkl_phy_set_hip_idx(i915, reg);
+ intel_de_write(i915, DKL_REG_MMIO(reg), val);
spin_unlock(&i915->display.dkl.phy_lock);
}
@@ -71,7 +70,6 @@ intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 v
* intel_dkl_phy_rmw - read-modify-write a Dekel PHY register
* @i915: i915 device instance
* @reg: Dekel PHY register
- * @ln: lane instance of @reg
* @clear: mask to clear
* @set: mask to set
*
@@ -79,12 +77,12 @@ intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 v
* this value back to the register if the value differs from the read one.
*/
void
-intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set)
+intel_dkl_phy_rmw(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 clear, u32 set)
{
spin_lock(&i915->display.dkl.phy_lock);
- dkl_phy_set_hip_idx(i915, reg, ln);
- intel_de_rmw(i915, reg, clear, set);
+ dkl_phy_set_hip_idx(i915, reg);
+ intel_de_rmw(i915, DKL_REG_MMIO(reg), clear, set);
spin_unlock(&i915->display.dkl.phy_lock);
}
@@ -93,17 +91,16 @@ intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 cle
* intel_dkl_phy_posting_read - do a posting read from a Dekel PHY register
* @i915: i915 device instance
* @reg: Dekel PHY register
- * @ln: lane instance of @reg
*
* Read the @reg Dekel PHY register without returning the read value.
*/
void
-intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln)
+intel_dkl_phy_posting_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg)
{
spin_lock(&i915->display.dkl.phy_lock);
- dkl_phy_set_hip_idx(i915, reg, ln);
- intel_de_posting_read(i915, reg);
+ dkl_phy_set_hip_idx(i915, reg);
+ intel_de_posting_read(i915, DKL_REG_MMIO(reg));
spin_unlock(&i915->display.dkl.phy_lock);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.h b/drivers/gpu/drm/i915/display/intel_dkl_phy.h
index 260ad121a0b1..570ee36f9386 100644
--- a/drivers/gpu/drm/i915/display/intel_dkl_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.h
@@ -8,17 +8,17 @@
#include <linux/types.h>
-#include "i915_reg_defs.h"
+#include "intel_dkl_phy_regs.h"
struct drm_i915_private;
u32
-intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln);
+intel_dkl_phy_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg);
void
-intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val);
+intel_dkl_phy_write(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 val);
void
-intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set);
+intel_dkl_phy_rmw(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 clear, u32 set);
void
-intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln);
+intel_dkl_phy_posting_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg);
#endif /* __INTEL_DKL_PHY_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h
new file mode 100644
index 000000000000..56085b32956d
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_DKL_PHY_REGS__
+#define __INTEL_DKL_PHY_REGS__
+
+#include <linux/types.h>
+
+struct intel_dkl_phy_reg {
+ u32 reg:24;
+ u32 bank_idx:4;
+};
+
+#define _DKL_PHY1_BASE 0x168000
+#define _DKL_PHY2_BASE 0x169000
+#define _DKL_PHY3_BASE 0x16A000
+#define _DKL_PHY4_BASE 0x16B000
+#define _DKL_PHY5_BASE 0x16C000
+#define _DKL_PHY6_BASE 0x16D000
+
+#define DKL_REG_TC_PORT(__reg) \
+ (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE))
+
+/* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */
+#define DKL_REG_MMIO(__reg) _MMIO((__reg).reg)
+
+#define _DKL_REG_PHY_BASE(tc_port) _PORT(tc_port, \
+ _DKL_PHY1_BASE, \
+ _DKL_PHY2_BASE)
+
+#define _DKL_BANK_SHIFT 12
+#define _DKL_REG_BANK_OFFSET(phy_offset) \
+ ((phy_offset) & ((1 << _DKL_BANK_SHIFT) - 1))
+#define _DKL_REG_BANK_IDX(phy_offset) \
+ (((phy_offset) >> _DKL_BANK_SHIFT) & 0xf)
+
+#define _DKL_REG(tc_port, phy_offset) \
+ ((const struct intel_dkl_phy_reg) { \
+ .reg = _DKL_REG_PHY_BASE(tc_port) + \
+ _DKL_REG_BANK_OFFSET(phy_offset), \
+ .bank_idx = _DKL_REG_BANK_IDX(phy_offset), \
+ })
+
+#define _DKL_REG_LN(tc_port, ln_idx, ln0_offs, ln1_offs) \
+ _DKL_REG(tc_port, (ln0_offs) + (ln_idx) * ((ln1_offs) - (ln0_offs)))
+
+#define _DKL_PCS_DW5_LN0 0x0014
+#define _DKL_PCS_DW5_LN1 0x1014
+#define DKL_PCS_DW5(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_PCS_DW5_LN0, \
+ _DKL_PCS_DW5_LN1)
+#define DKL_PCS_DW5_CORE_SOFTRESET REG_BIT(11)
+
+#define _DKL_PLL_DIV0 0x2200
+#define DKL_PLL_DIV0(tc_port) _DKL_REG(tc_port, \
+ _DKL_PLL_DIV0)
+#define DKL_PLL_DIV0_AFC_STARTUP_MASK REG_GENMASK(27, 25)
+#define DKL_PLL_DIV0_AFC_STARTUP(val) REG_FIELD_PREP(DKL_PLL_DIV0_AFC_STARTUP_MASK, (val))
+#define DKL_PLL_DIV0_INTEG_COEFF(x) ((x) << 16)
+#define DKL_PLL_DIV0_INTEG_COEFF_MASK (0x1F << 16)
+#define DKL_PLL_DIV0_PROP_COEFF(x) ((x) << 12)
+#define DKL_PLL_DIV0_PROP_COEFF_MASK (0xF << 12)
+#define DKL_PLL_DIV0_FBPREDIV_SHIFT (8)
+#define DKL_PLL_DIV0_FBPREDIV(x) ((x) << DKL_PLL_DIV0_FBPREDIV_SHIFT)
+#define DKL_PLL_DIV0_FBPREDIV_MASK (0xF << DKL_PLL_DIV0_FBPREDIV_SHIFT)
+#define DKL_PLL_DIV0_FBDIV_INT(x) ((x) << 0)
+#define DKL_PLL_DIV0_FBDIV_INT_MASK (0xFF << 0)
+#define DKL_PLL_DIV0_MASK (DKL_PLL_DIV0_INTEG_COEFF_MASK | \
+ DKL_PLL_DIV0_PROP_COEFF_MASK | \
+ DKL_PLL_DIV0_FBPREDIV_MASK | \
+ DKL_PLL_DIV0_FBDIV_INT_MASK)
+
+#define _DKL_PLL_DIV1 0x2204
+#define DKL_PLL_DIV1(tc_port) _DKL_REG(tc_port, \
+ _DKL_PLL_DIV1)
+#define DKL_PLL_DIV1_IREF_TRIM(x) ((x) << 16)
+#define DKL_PLL_DIV1_IREF_TRIM_MASK (0x1F << 16)
+#define DKL_PLL_DIV1_TDC_TARGET_CNT(x) ((x) << 0)
+#define DKL_PLL_DIV1_TDC_TARGET_CNT_MASK (0xFF << 0)
+
+#define _DKL_PLL_SSC 0x2210
+#define DKL_PLL_SSC(tc_port) _DKL_REG(tc_port, \
+ _DKL_PLL_SSC)
+#define DKL_PLL_SSC_IREF_NDIV_RATIO(x) ((x) << 29)
+#define DKL_PLL_SSC_IREF_NDIV_RATIO_MASK (0x7 << 29)
+#define DKL_PLL_SSC_STEP_LEN(x) ((x) << 16)
+#define DKL_PLL_SSC_STEP_LEN_MASK (0xFF << 16)
+#define DKL_PLL_SSC_STEP_NUM(x) ((x) << 11)
+#define DKL_PLL_SSC_STEP_NUM_MASK (0x7 << 11)
+#define DKL_PLL_SSC_EN (1 << 9)
+
+#define _DKL_PLL_BIAS 0x2214
+#define DKL_PLL_BIAS(tc_port) _DKL_REG(tc_port, \
+ _DKL_PLL_BIAS)
+#define DKL_PLL_BIAS_FRAC_EN_H (1 << 30)
+#define DKL_PLL_BIAS_FBDIV_SHIFT (8)
+#define DKL_PLL_BIAS_FBDIV_FRAC(x) ((x) << DKL_PLL_BIAS_FBDIV_SHIFT)
+#define DKL_PLL_BIAS_FBDIV_FRAC_MASK (0x3FFFFF << DKL_PLL_BIAS_FBDIV_SHIFT)
+
+#define _DKL_PLL_TDC_COLDST_BIAS 0x2218
+#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _DKL_REG(tc_port, \
+ _DKL_PLL_TDC_COLDST_BIAS)
+#define DKL_PLL_TDC_SSC_STEP_SIZE(x) ((x) << 8)
+#define DKL_PLL_TDC_SSC_STEP_SIZE_MASK (0xFF << 8)
+#define DKL_PLL_TDC_FEED_FWD_GAIN(x) ((x) << 0)
+#define DKL_PLL_TDC_FEED_FWD_GAIN_MASK (0xFF << 0)
+
+#define _DKL_REFCLKIN_CTL 0x212C
+#define DKL_REFCLKIN_CTL(tc_port) _DKL_REG(tc_port, \
+ _DKL_REFCLKIN_CTL)
+/* Bits are the same as MG_REFCLKIN_CTL */
+
+#define _DKL_CLKTOP2_HSCLKCTL 0x20D4
+#define DKL_CLKTOP2_HSCLKCTL(rc_port) _DKL_REG(tc_port, \
+ _DKL_CLKTOP2_HSCLKCTL)
+/* Bits are the same as MG_CLKTOP2_HSCLKCTL */
+
+#define _DKL_CLKTOP2_CORECLKCTL1 0x20D8
+#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _DKL_REG(tc_port, \
+ _DKL_CLKTOP2_CORECLKCTL1)
+/* Bits are the same as MG_CLKTOP2_CORECLKCTL1 */
+
+#define _DKL_TX_DPCNTL0_LN0 0x02C0
+#define _DKL_TX_DPCNTL0_LN1 0x12C0
+#define DKL_TX_DPCNTL0(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_DPCNTL0_LN0, \
+ _DKL_TX_DPCNTL0_LN1)
+#define DKL_TX_PRESHOOT_COEFF(x) ((x) << 13)
+#define DKL_TX_PRESHOOT_COEFF_MASK (0x1f << 13)
+#define DKL_TX_DE_EMPHASIS_COEFF(x) ((x) << 8)
+#define DKL_TX_DE_EMPAHSIS_COEFF_MASK (0x1f << 8)
+#define DKL_TX_VSWING_CONTROL(x) ((x) << 0)
+#define DKL_TX_VSWING_CONTROL_MASK (0x7 << 0)
+
+#define _DKL_TX_DPCNTL1_LN0 0x02C4
+#define _DKL_TX_DPCNTL1_LN1 0x12C4
+#define DKL_TX_DPCNTL1(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_DPCNTL1_LN0, \
+ _DKL_TX_DPCNTL1_LN1)
+/* Bits are the same as DKL_TX_DPCNTRL0 */
+
+#define _DKL_TX_DPCNTL2_LN0 0x02C8
+#define _DKL_TX_DPCNTL2_LN1 0x12C8
+#define DKL_TX_DPCNTL2(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_DPCNTL2_LN0, \
+ _DKL_TX_DPCNTL2_LN1)
+#define DKL_TX_DP20BITMODE REG_BIT(2)
+#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK REG_GENMASK(4, 3)
+#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val))
+#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5)
+#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val))
+
+#define _DKL_TX_FW_CALIB_LN0 0x02F8
+#define _DKL_TX_FW_CALIB_LN1 0x12F8
+#define DKL_TX_FW_CALIB(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_FW_CALIB_LN0, \
+ _DKL_TX_FW_CALIB_LN1)
+#define DKL_TX_CFG_DISABLE_WAIT_INIT (1 << 7)
+
+#define _DKL_TX_PMD_LANE_SUS_LN0 0x0D00
+#define _DKL_TX_PMD_LANE_SUS_LN1 0x1D00
+#define DKL_TX_PMD_LANE_SUS(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_PMD_LANE_SUS_LN0, \
+ _DKL_TX_PMD_LANE_SUS_LN1)
+
+#define _DKL_TX_DW17_LN0 0x0DC4
+#define _DKL_TX_DW17_LN1 0x1DC4
+#define DKL_TX_DW17(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_DW17_LN0, \
+ _DKL_TX_DW17_LN1)
+
+#define _DKL_TX_DW18_LN0 0x0DC8
+#define _DKL_TX_DW18_LN1 0x1DC8
+#define DKL_TX_DW18(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_TX_DW18_LN0, \
+ _DKL_TX_DW18_LN1)
+
+#define _DKL_DP_MODE_LN0 0x00A0
+#define _DKL_DP_MODE_LN1 0x10A0
+#define DKL_DP_MODE(tc_port, ln) _DKL_REG_LN(tc_port, ln, \
+ _DKL_DP_MODE_LN0, \
+ _DKL_DP_MODE_LN1)
+
+#define _DKL_CMN_UC_DW27 0x236C
+#define DKL_CMN_UC_DW_27(tc_port) _DKL_REG(tc_port, \
+ _DKL_CMN_UC_DW27)
+#define DKL_CMN_UC_DW27_UC_HEALTH (0x1 << 15)
+
+/*
+ * Each Dekel PHY is addressed through a 4KB aperture. Each PHY has more than
+ * 4KB of register space, so a separate index is programmed in HIP_INDEX_REG0
+ * or HIP_INDEX_REG1, based on the port number, to set the upper 2 address
+ * bits that point the 4KB window into the full PHY register space.
+ */
+#define _HIP_INDEX_REG0 0x1010A0
+#define _HIP_INDEX_REG1 0x1010A4
+#define HIP_INDEX_REG(tc_port) _MMIO((tc_port) < 4 ? _HIP_INDEX_REG0 \
+ : _HIP_INDEX_REG1)
+#define _HIP_INDEX_SHIFT(tc_port) (8 * ((tc_port) % 4))
+#define HIP_INDEX_VAL(tc_port, val) ((val) << _HIP_INDEX_SHIFT(tc_port))
+
+#endif /* __INTEL_DKL_PHY_REGS__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
index e52ecc0738a6..eff3add70611 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -52,8 +52,8 @@
#define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE
-#define DG2_DMC_PATH DMC_PATH(dg2, 2, 07)
-#define DG2_DMC_VERSION_REQUIRED DMC_VERSION(2, 07)
+#define DG2_DMC_PATH DMC_PATH(dg2, 2, 08)
+#define DG2_DMC_VERSION_REQUIRED DMC_VERSION(2, 8)
MODULE_FIRMWARE(DG2_DMC_PATH);
#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16)
@@ -1065,12 +1065,13 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused)
seq_printf(m, "fw loaded: %s\n",
str_yes_no(intel_dmc_has_payload(i915)));
seq_printf(m, "path: %s\n", dmc->fw_path);
- seq_printf(m, "Pipe A fw support: %s\n",
+ seq_printf(m, "Pipe A fw needed: %s\n",
str_yes_no(GRAPHICS_VER(i915) >= 12));
seq_printf(m, "Pipe A fw loaded: %s\n",
str_yes_no(dmc->dmc_info[DMC_FW_PIPEA].payload));
- seq_printf(m, "Pipe B fw support: %s\n",
- str_yes_no(IS_ALDERLAKE_P(i915)));
+ seq_printf(m, "Pipe B fw needed: %s\n",
+ str_yes_no(IS_ALDERLAKE_P(i915) ||
+ DISPLAY_VER(i915) >= 14));
seq_printf(m, "Pipe B fw loaded: %s\n",
str_yes_no(dmc->dmc_info[DMC_FW_PIPEB].payload));
@@ -1081,22 +1082,19 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused)
DMC_VERSION_MINOR(dmc->version));
if (DISPLAY_VER(i915) >= 12) {
- if (IS_DGFX(i915)) {
+ i915_reg_t dc3co_reg;
+
+ if (IS_DGFX(i915) || DISPLAY_VER(i915) >= 14) {
+ dc3co_reg = DG1_DMC_DEBUG3;
dc5_reg = DG1_DMC_DEBUG_DC5_COUNT;
} else {
+ dc3co_reg = TGL_DMC_DEBUG3;
dc5_reg = TGL_DMC_DEBUG_DC5_COUNT;
dc6_reg = TGL_DMC_DEBUG_DC6_COUNT;
}
- /*
- * NOTE: DMC_DEBUG3 is a general purpose reg.
- * According to B.Specs:49196 DMC f/w reuses DC5/6 counter
- * reg for DC3CO debugging and validation,
- * but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter.
- */
seq_printf(m, "DC3CO count: %d\n",
- intel_de_read(i915, IS_DGFX(i915) ?
- DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3));
+ intel_de_read(i915, dc3co_reg));
} else {
dc5_reg = IS_BROXTON(i915) ? BXT_DMC_DC3_DC5_COUNT :
SKL_DMC_DC3_DC5_COUNT;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2b5bc95a8b0d..67089711d9e2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -46,6 +46,7 @@
#include "g4x_dp.h"
#include "i915_debugfs.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_backlight.h"
@@ -2306,6 +2307,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ bool fastset = true;
/*
* If BIOS has set an unsupported or non-standard link rate for some
@@ -2313,9 +2315,10 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
*/
if (intel_dp_rate_index(intel_dp->source_rates, intel_dp->num_source_rates,
crtc_state->port_clock) < 0) {
- drm_dbg_kms(&i915->drm, "Forcing full modeset due to unsupported link rate\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset due to unsupported link rate\n",
+ encoder->base.base.id, encoder->base.name);
crtc_state->uapi.connectors_changed = true;
- return false;
+ fastset = false;
}
/*
@@ -2326,18 +2329,20 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
* Remove once we have readout for DSC.
*/
if (crtc_state->dsc.compression_enable) {
- drm_dbg_kms(&i915->drm, "Forcing full modeset due to DSC being enabled\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset due to DSC being enabled\n",
+ encoder->base.base.id, encoder->base.name);
crtc_state->uapi.mode_changed = true;
- return false;
+ fastset = false;
}
if (CAN_PSR(intel_dp)) {
- drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset to compute PSR state\n",
+ encoder->base.base.id, encoder->base.name);
crtc_state->uapi.mode_changed = true;
- return false;
+ fastset = false;
}
- return true;
+ return fastset;
}
static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp)
@@ -2686,7 +2691,6 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
str_enable_disable(tmp));
}
-
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
{
u8 dprx = 0;
@@ -4873,6 +4877,12 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
intel_pps_vdd_off_sync(intel_dp);
+ /*
+ * Ensure power off delay is respected on module remove, so that we can
+ * reduce delays at driver probe. See pps_init_timestamps().
+ */
+ intel_pps_wait_power_cycle(intel_dp);
+
intel_dp_aux_fini(intel_dp);
}
@@ -5174,19 +5184,6 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
if (has_gamut_metadata_dip(dev_priv, port))
drm_connector_attach_hdr_output_metadata_property(connector);
- if (intel_dp_is_edp(intel_dp)) {
- u32 allowed_scalers;
-
- allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
- if (!HAS_GMCH(dev_priv))
- allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
-
- drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
-
- connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
-
- }
-
if (HAS_VRR(dev_priv))
drm_connector_attach_vrr_capable_property(connector);
}
@@ -5199,8 +5196,7 @@ intel_edp_add_properties(struct intel_dp *intel_dp)
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
- if (!fixed_mode)
- return;
+ intel_attach_scaling_mode_property(&connector->base);
drm_connector_set_panel_orientation_with_quirk(&connector->base,
i915->display.vbt.orientation,
@@ -5208,16 +5204,43 @@ intel_edp_add_properties(struct intel_dp *intel_dp)
fixed_mode->vdisplay);
}
+static void intel_edp_backlight_setup(struct intel_dp *intel_dp,
+ struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ enum pipe pipe = INVALID_PIPE;
+
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ /*
+ * Figure out the current pipe for the initial backlight setup.
+ * If the current pipe isn't valid, try the PPS pipe, and if that
+ * fails just assume pipe A.
+ */
+ pipe = vlv_active_pipe(intel_dp);
+
+ if (pipe != PIPE_A && pipe != PIPE_B)
+ pipe = intel_dp->pps.pps_pipe;
+
+ if (pipe != PIPE_A && pipe != PIPE_B)
+ pipe = PIPE_A;
+
+ drm_dbg_kms(&i915->drm,
+ "[CONNECTOR:%d:%s] using pipe %c for initial backlight setup\n",
+ connector->base.base.id, connector->base.name,
+ pipe_name(pipe));
+ }
+
+ intel_backlight_setup(connector, pipe);
+}
+
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct intel_connector *intel_connector)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector = &intel_connector->base;
struct drm_display_mode *fixed_mode;
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
bool has_dpcd;
- enum pipe pipe = INVALID_PIPE;
struct edid *edid;
if (!intel_dp_is_edp(intel_dp))
@@ -5230,7 +5253,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
* with an already powered-on LVDS power sequencer.
*/
if (intel_get_lvds_encoder(dev_priv)) {
- drm_WARN_ON(dev,
+ drm_WARN_ON(&dev_priv->drm,
!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
drm_info(&dev_priv->drm,
"LVDS was detected, not registering eDP\n");
@@ -5246,11 +5269,12 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
if (!has_dpcd) {
/* if this fails, presume the device is a ghost */
drm_info(&dev_priv->drm,
- "failed to retrieve link info, disabling eDP\n");
+ "[ENCODER:%d:%s] failed to retrieve link info, disabling eDP\n",
+ encoder->base.base.id, encoder->base.name);
goto out_vdd_off;
}
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
edid = drm_get_edid(connector, &intel_dp->aux.ddc);
if (!edid) {
/* Fallback to EDID from ACPI OpRegion, if any */
@@ -5275,9 +5299,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
intel_bios_init_panel(dev_priv, &intel_connector->panel,
encoder->devdata, IS_ERR(edid) ? NULL : edid);
- intel_panel_add_edid_fixed_modes(intel_connector,
- intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE ||
- intel_vrr_is_capable(intel_connector));
+ intel_panel_add_edid_fixed_modes(intel_connector, true);
/* MSO requires information from the EDID */
intel_edp_mso_init(intel_dp);
@@ -5290,30 +5312,18 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
if (!intel_panel_preferred_fixed_mode(intel_connector))
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- /*
- * Figure out the current pipe for the initial backlight setup.
- * If the current pipe isn't valid, try the PPS pipe, and if that
- * fails just assume pipe A.
- */
- pipe = vlv_active_pipe(intel_dp);
-
- if (pipe != PIPE_A && pipe != PIPE_B)
- pipe = intel_dp->pps.pps_pipe;
-
- if (pipe != PIPE_A && pipe != PIPE_B)
- pipe = PIPE_A;
-
- drm_dbg_kms(&dev_priv->drm,
- "using pipe %c for initial backlight setup\n",
- pipe_name(pipe));
+ if (!intel_panel_preferred_fixed_mode(intel_connector)) {
+ drm_info(&dev_priv->drm,
+ "[ENCODER:%d:%s] failed to find fixed mode for the panel, disabling eDP\n",
+ encoder->base.base.id, encoder->base.name);
+ goto out_vdd_off;
}
intel_panel_init(intel_connector);
- intel_backlight_setup(intel_connector, pipe);
+ intel_edp_backlight_setup(intel_dp, intel_connector);
intel_edp_add_properties(intel_dp);
@@ -5415,7 +5425,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
if (!HAS_GMCH(dev_priv))
connector->interlace_allowed = true;
- connector->doublescan_allowed = 0;
intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index 48c375c65a41..664bebdecea7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -4,6 +4,7 @@
*/
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_trace.h"
#include "intel_display_types.h"
#include "intel_dp_aux.h"
diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
index 88689124c013..e0c177161407 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
@@ -11,6 +11,7 @@
#include <drm/display/drm_hdcp_helper.h>
#include <drm/drm_print.h>
+#include "i915_reg.h"
#include "intel_ddi.h"
#include "intel_de.h"
#include "intel_display_types.h"
@@ -19,28 +20,20 @@
#include "intel_hdcp.h"
#include "intel_hdcp_regs.h"
-static unsigned int transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
+static u32 transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
{
- u32 stream_enc_mask;
-
switch (cpu_transcoder) {
case TRANSCODER_A:
- stream_enc_mask = HDCP_STATUS_STREAM_A_ENC;
- break;
+ return HDCP_STATUS_STREAM_A_ENC;
case TRANSCODER_B:
- stream_enc_mask = HDCP_STATUS_STREAM_B_ENC;
- break;
+ return HDCP_STATUS_STREAM_B_ENC;
case TRANSCODER_C:
- stream_enc_mask = HDCP_STATUS_STREAM_C_ENC;
- break;
+ return HDCP_STATUS_STREAM_C_ENC;
case TRANSCODER_D:
- stream_enc_mask = HDCP_STATUS_STREAM_D_ENC;
- break;
+ return HDCP_STATUS_STREAM_D_ENC;
default:
- stream_enc_mask = 0;
+ return 0;
}
-
- return stream_enc_mask;
}
static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 03604a37931c..4077a979a924 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -29,6 +29,7 @@
#include <drm/drm_probe_helper.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_connector.h"
@@ -793,7 +794,35 @@ static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
return false;
}
-static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
+static int intel_dp_mst_add_properties(struct intel_dp *intel_dp,
+ struct drm_connector *connector,
+ const char *pathprop)
+{
+ struct drm_i915_private *i915 = to_i915(connector->dev);
+
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.path_property, 0);
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tile_property, 0);
+
+ intel_attach_force_audio_property(connector);
+ intel_attach_broadcast_rgb_property(connector);
+
+ /*
+ * Reuse the prop from the SST connector because we're
+ * not allowed to create new props after device registration.
+ */
+ connector->max_bpc_property =
+ intel_dp->attached_connector->base.max_bpc_property;
+ if (connector->max_bpc_property)
+ drm_connector_attach_max_bpc_property(connector, 6, 12);
+
+ return drm_connector_set_path_property(connector, pathprop);
+}
+
+static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_port *port,
+ const char *pathprop)
{
struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@@ -833,28 +862,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
goto err;
}
- drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
- drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
-
- ret = drm_connector_set_path_property(connector, pathprop);
+ ret = intel_dp_mst_add_properties(intel_dp, connector, pathprop);
if (ret)
goto err;
- intel_attach_force_audio_property(connector);
- intel_attach_broadcast_rgb_property(connector);
-
ret = intel_dp_hdcp_init(dig_port, intel_connector);
if (ret)
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP MST init failed, skipping.\n",
connector->name, connector->base.id);
- /*
- * Reuse the prop from the SST connector because we're
- * not allowed to create new props after device registration.
- */
- connector->max_bpc_property =
- intel_dp->attached_connector->base.max_bpc_property;
- if (connector->max_bpc_property)
- drm_connector_attach_max_bpc_property(connector, 6, 12);
return connector;
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
index 8732b8722ed7..7eb7440b3180 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include "i915_reg.h"
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
@@ -655,6 +656,48 @@ bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
return mask;
}
+enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port)
+{
+ switch (dig_port->base.port) {
+ default:
+ MISSING_CASE(dig_port->base.port);
+ fallthrough;
+ case PORT_B:
+ case PORT_D:
+ return DPIO_CH0;
+ case PORT_C:
+ return DPIO_CH1;
+ }
+}
+
+enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port)
+{
+ switch (dig_port->base.port) {
+ default:
+ MISSING_CASE(dig_port->base.port);
+ fallthrough;
+ case PORT_B:
+ case PORT_C:
+ return DPIO_PHY0;
+ case PORT_D:
+ return DPIO_PHY1;
+ }
+}
+
+enum dpio_channel vlv_pipe_to_channel(enum pipe pipe)
+{
+ switch (pipe) {
+ default:
+ MISSING_CASE(pipe);
+ fallthrough;
+ case PIPE_A:
+ case PIPE_C:
+ return DPIO_CH0;
+ case PIPE_B:
+ return DPIO_CH1;
+ }
+}
+
void chv_set_phy_signal_level(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
index 9c3d008e8e1a..9c7725dacb47 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h
@@ -8,13 +8,24 @@
#include <linux/types.h>
-enum dpio_channel;
-enum dpio_phy;
+enum pipe;
enum port;
struct drm_i915_private;
struct intel_crtc_state;
+struct intel_digital_port;
struct intel_encoder;
+enum dpio_channel {
+ DPIO_CH0,
+ DPIO_CH1,
+};
+
+enum dpio_phy {
+ DPIO_PHY0,
+ DPIO_PHY1,
+ DPIO_PHY2,
+};
+
void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port,
enum dpio_phy *phy, enum dpio_channel *ch);
void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder,
@@ -30,6 +41,10 @@ void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
u8 lane_lat_optim_mask);
u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder);
+enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port);
+enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port);
+enum dpio_channel vlv_pipe_to_channel(enum pipe pipe);
+
void chv_set_phy_signal_level(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
u32 deemph_reg_value, u32 margin_reg_value,
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index b15ba78d64d6..c236aafe9be0 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -6,10 +6,12 @@
#include <linux/kernel.h>
#include <linux/string_helpers.h>
+#include "i915_reg.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display.h"
#include "intel_display_types.h"
+#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_lvds.h"
#include "intel_panel.h"
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 64dd603dc69a..1974eb580ed1 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -23,15 +23,18 @@
#include <linux/string_helpers.h>
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dkl_phy.h"
+#include "intel_dkl_phy_regs.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_dpll_mgr.h"
+#include "intel_hti.h"
+#include "intel_mg_phy_regs.h"
#include "intel_pch_refclk.h"
#include "intel_tc.h"
-#include "intel_tc_phy_regs.h"
/**
* DOC: Display PLLs
@@ -153,28 +156,6 @@ intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
return &dev_priv->display.dpll.shared_dplls[id];
}
-/**
- * intel_get_shared_dpll_id - get the id of a DPLL
- * @dev_priv: i915 device instance
- * @pll: the DPLL
- *
- * Returns:
- * The id of @pll
- */
-enum intel_dpll_id
-intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- long pll_idx = pll - dev_priv->display.dpll.shared_dplls;
-
- if (drm_WARN_ON(&dev_priv->drm,
- pll_idx < 0 ||
- pll_idx >= dev_priv->display.dpll.num_shared_dpll))
- return -1;
-
- return pll_idx;
-}
-
/* For ILK+ */
void assert_shared_dpll(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
@@ -385,20 +366,30 @@ intel_reference_shared_dpll(struct intel_atomic_state *state,
if (shared_dpll[id].pipe_mask == 0)
shared_dpll[id].hw_state = *pll_state;
- drm_dbg(&i915->drm, "using %s for pipe %c\n", pll->info->name,
- pipe_name(crtc->pipe));
+ drm_WARN_ON(&i915->drm, (shared_dpll[id].pipe_mask & BIT(crtc->pipe)) != 0);
shared_dpll[id].pipe_mask |= BIT(crtc->pipe);
+
+ drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] reserving %s\n",
+ crtc->base.base.id, crtc->base.name, pll->info->name);
}
static void intel_unreference_shared_dpll(struct intel_atomic_state *state,
const struct intel_crtc *crtc,
const struct intel_shared_dpll *pll)
{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
struct intel_shared_dpll_state *shared_dpll;
+ const enum intel_dpll_id id = pll->info->id;
shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
- shared_dpll[pll->info->id].pipe_mask &= ~BIT(crtc->pipe);
+
+ drm_WARN_ON(&i915->drm, (shared_dpll[id].pipe_mask & BIT(crtc->pipe)) == 0);
+
+ shared_dpll[id].pipe_mask &= ~BIT(crtc->pipe);
+
+ drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] releasing %s\n",
+ crtc->base.base.id, crtc->base.name, pll->info->name);
}
static void intel_put_dpll(struct intel_atomic_state *state,
@@ -709,8 +700,6 @@ struct hsw_wrpll_rnp {
static unsigned hsw_wrpll_get_budget_for_freq(int clock)
{
- unsigned budget;
-
switch (clock) {
case 25175000:
case 25200000:
@@ -743,21 +732,18 @@ static unsigned hsw_wrpll_get_budget_for_freq(int clock)
case 222750000:
case 296703000:
case 297000000:
- budget = 0;
- break;
+ return 0;
case 233500000:
case 245250000:
case 247750000:
case 253250000:
case 298000000:
- budget = 1500;
- break;
+ return 1500;
case 169128000:
case 169500000:
case 179500000:
case 202000000:
- budget = 2000;
- break;
+ return 2000;
case 256250000:
case 262500000:
case 270000000:
@@ -767,18 +753,13 @@ static unsigned hsw_wrpll_get_budget_for_freq(int clock)
case 281250000:
case 286000000:
case 291750000:
- budget = 4000;
- break;
+ return 4000;
case 267250000:
case 268500000:
- budget = 5000;
- break;
+ return 5000;
default:
- budget = 1000;
- break;
+ return 1000;
}
-
- return budget;
}
static void hsw_wrpll_update_rnp(u64 freq2k, unsigned int budget,
@@ -3184,14 +3165,6 @@ static void icl_update_active_dpll(struct intel_atomic_state *state,
icl_set_active_port_dpll(crtc_state, port_dpll_id);
}
-static u32 intel_get_hti_plls(struct drm_i915_private *i915)
-{
- if (!(i915->hti_state & HDPORT_ENABLED))
- return 0;
-
- return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->hti_state);
-}
-
static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -3266,7 +3239,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state,
}
/* Eliminate DPLLs from consideration if reserved by HTI */
- dpll_mask &= ~intel_get_hti_plls(dev_priv);
+ dpll_mask &= ~intel_hti_dpll_mask(dev_priv);
port_dpll->pll = intel_find_shared_dpll(state, crtc,
&port_dpll->hw_state,
@@ -3510,11 +3483,11 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv,
* they are on different building blocks
*/
hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv,
- DKL_REFCLKIN_CTL(tc_port), 2);
+ DKL_REFCLKIN_CTL(tc_port));
hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK;
hw_state->mg_clktop2_hsclkctl =
- intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2);
+ intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port));
hw_state->mg_clktop2_hsclkctl &=
MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
@@ -3522,32 +3495,32 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv,
MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK;
hw_state->mg_clktop2_coreclkctl1 =
- intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2);
+ intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port));
hw_state->mg_clktop2_coreclkctl1 &=
MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
- hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port), 2);
+ hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port));
val = DKL_PLL_DIV0_MASK;
if (dev_priv->display.vbt.override_afc_startup)
val |= DKL_PLL_DIV0_AFC_STARTUP_MASK;
hw_state->mg_pll_div0 &= val;
- hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2);
+ hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port));
hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK |
DKL_PLL_DIV1_TDC_TARGET_CNT_MASK);
- hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2);
+ hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port));
hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK |
DKL_PLL_SSC_STEP_LEN_MASK |
DKL_PLL_SSC_STEP_NUM_MASK |
DKL_PLL_SSC_EN);
- hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2);
+ hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port));
hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H |
DKL_PLL_BIAS_FBDIV_FRAC_MASK);
hw_state->mg_pll_tdc_coldst_bias =
- intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2);
+ intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK |
DKL_PLL_TDC_FEED_FWD_GAIN_MASK);
@@ -3736,57 +3709,57 @@ static void dkl_pll_write(struct drm_i915_private *dev_priv,
* though on different building block
*/
/* All the registers are RMW */
- val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port));
val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK;
val |= hw_state->mg_refclkin_ctl;
- intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val);
- val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port));
val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
val |= hw_state->mg_clktop2_coreclkctl1;
- intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val);
- val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port));
val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK);
val |= hw_state->mg_clktop2_hsclkctl;
- intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val);
val = DKL_PLL_DIV0_MASK;
if (dev_priv->display.vbt.override_afc_startup)
val |= DKL_PLL_DIV0_AFC_STARTUP_MASK;
- intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), 2, val,
+ intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val,
hw_state->mg_pll_div0);
- val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port));
val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK |
DKL_PLL_DIV1_TDC_TARGET_CNT_MASK);
val |= hw_state->mg_pll_div1;
- intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), val);
- val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port));
val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK |
DKL_PLL_SSC_STEP_LEN_MASK |
DKL_PLL_SSC_STEP_NUM_MASK |
DKL_PLL_SSC_EN);
val |= hw_state->mg_pll_ssc;
- intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), val);
- val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port));
val &= ~(DKL_PLL_BIAS_FRAC_EN_H |
DKL_PLL_BIAS_FBDIV_FRAC_MASK);
val |= hw_state->mg_pll_bias;
- intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), val);
- val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2);
+ val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK |
DKL_PLL_TDC_FEED_FWD_GAIN_MASK);
val |= hw_state->mg_pll_tdc_coldst_bias;
- intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2, val);
+ intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val);
- intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2);
+ intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
}
static void icl_pll_power_enable(struct drm_i915_private *dev_priv,
@@ -4188,6 +4161,8 @@ void intel_shared_dpll_init(struct drm_i915_private *dev_priv)
const struct dpll_info *dpll_info;
int i;
+ mutex_init(&dev_priv->display.dpll.lock);
+
if (IS_DG2(dev_priv))
/* No shared DPLLs on DG2; port PLLs are part of the PHY */
dpll_mgr = NULL;
@@ -4232,7 +4207,6 @@ void intel_shared_dpll_init(struct drm_i915_private *dev_priv)
dev_priv->display.dpll.mgr = dpll_mgr;
dev_priv->display.dpll.num_shared_dpll = i;
- mutex_init(&dev_priv->display.dpll.lock);
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index 3247dc300ae4..3854f1b4299a 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -328,9 +328,6 @@ struct intel_shared_dpll {
struct intel_shared_dpll *
intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
enum intel_dpll_id id);
-enum intel_dpll_id
-intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll);
void assert_shared_dpll(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
bool state);
diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
index ac587647e1f5..ad1a37b515fb 100644
--- a/drivers/gpu/drm/i915/display/intel_dpt.c
+++ b/drivers/gpu/drm/i915/display/intel_dpt.c
@@ -5,6 +5,7 @@
#include "gem/i915_gem_domain.h"
#include "gem/i915_gem_internal.h"
+#include "gem/i915_gem_lmem.h"
#include "gt/gen8_ppgtt.h"
#include "i915_drv.h"
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c
index 7da4a9cbe4ba..5b9e44443814 100644
--- a/drivers/gpu/drm/i915/display/intel_drrs.c
+++ b/drivers/gpu/drm/i915/display/intel_drrs.c
@@ -4,6 +4,7 @@
*/
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_de.h"
#include "intel_display_types.h"
@@ -284,16 +285,124 @@ void intel_drrs_flush(struct drm_i915_private *dev_priv,
}
/**
- * intel_crtc_drrs_init - Init DRRS for CRTC
+ * intel_drrs_crtc_init - Init DRRS for CRTC
* @crtc: crtc
*
* This function is called only once at driver load to initialize basic
* DRRS stuff.
*
*/
-void intel_crtc_drrs_init(struct intel_crtc *crtc)
+void intel_drrs_crtc_init(struct intel_crtc *crtc)
{
INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work);
mutex_init(&crtc->drrs.mutex);
crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
}
+
+static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused)
+{
+ struct intel_crtc *crtc = m->private;
+ const struct intel_crtc_state *crtc_state;
+ int ret;
+
+ ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex);
+ if (ret)
+ return ret;
+
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+
+ mutex_lock(&crtc->drrs.mutex);
+
+ seq_printf(m, "DRRS enabled: %s\n",
+ str_yes_no(crtc_state->has_drrs));
+
+ seq_printf(m, "DRRS active: %s\n",
+ str_yes_no(intel_drrs_is_active(crtc)));
+
+ seq_printf(m, "DRRS refresh rate: %s\n",
+ crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ?
+ "low" : "high");
+
+ seq_printf(m, "DRRS busy frontbuffer bits: 0x%x\n",
+ crtc->drrs.busy_frontbuffer_bits);
+
+ mutex_unlock(&crtc->drrs.mutex);
+
+ drm_modeset_unlock(&crtc->base.mutex);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_status);
+
+static int intel_drrs_debugfs_ctl_set(void *data, u64 val)
+{
+ struct intel_crtc *crtc = data;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_crtc_state *crtc_state;
+ struct drm_crtc_commit *commit;
+ int ret;
+
+ ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex);
+ if (ret)
+ return ret;
+
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+
+ if (!crtc_state->hw.active ||
+ !crtc_state->has_drrs)
+ goto out;
+
+ commit = crtc_state->uapi.commit;
+ if (commit) {
+ ret = wait_for_completion_interruptible(&commit->hw_done);
+ if (ret)
+ goto out;
+ }
+
+ drm_dbg(&i915->drm,
+ "Manually %sactivating DRRS\n", val ? "" : "de");
+
+ if (val)
+ intel_drrs_activate(crtc_state);
+ else
+ intel_drrs_deactivate(crtc_state);
+
+out:
+ drm_modeset_unlock(&crtc->base.mutex);
+
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(intel_drrs_debugfs_ctl_fops,
+ NULL, intel_drrs_debugfs_ctl_set, "%llu\n");
+
+void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc)
+{
+ debugfs_create_file("i915_drrs_status", 0444, crtc->base.debugfs_entry,
+ crtc, &intel_drrs_debugfs_status_fops);
+
+ debugfs_create_file("i915_drrs_ctl", 0644, crtc->base.debugfs_entry,
+ crtc, &intel_drrs_debugfs_ctl_fops);
+}
+
+static int intel_drrs_debugfs_type_show(struct seq_file *m, void *unused)
+{
+ struct intel_connector *connector = m->private;
+
+ seq_printf(m, "DRRS type: %s\n",
+ intel_drrs_type_str(intel_panel_drrs_type(connector)));
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_type);
+
+void intel_drrs_connector_debugfs_add(struct intel_connector *connector)
+{
+ if (intel_panel_drrs_type(connector) == DRRS_TYPE_NONE)
+ return;
+
+ debugfs_create_file("i915_drrs_type", 0444, connector->base.debugfs_entry,
+ connector, &intel_drrs_debugfs_type_fops);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h
index 3ad1be1ad9c1..8ef5f93a80ff 100644
--- a/drivers/gpu/drm/i915/display/intel_drrs.h
+++ b/drivers/gpu/drm/i915/display/intel_drrs.h
@@ -23,6 +23,8 @@ void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
void intel_drrs_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
-void intel_crtc_drrs_init(struct intel_crtc *crtc);
+void intel_drrs_crtc_init(struct intel_crtc *crtc);
+void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc);
+void intel_drrs_connector_debugfs_add(struct intel_connector *connector);
#endif /* __INTEL_DRRS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
index fc9c3e41c333..1e1c6107d51b 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -7,6 +7,7 @@
#include "gem/i915_gem_internal.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dsb.h"
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
index 75e8cc4337c9..fce69fa446d5 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
+++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
@@ -137,9 +137,9 @@ static enum port intel_dsi_seq_port_to_port(struct intel_dsi *intel_dsi,
return ffs(intel_dsi->ports) - 1;
if (seq_port) {
- if (intel_dsi->ports & PORT_B)
+ if (intel_dsi->ports & BIT(PORT_B))
return PORT_B;
- else if (intel_dsi->ports & PORT_C)
+ else if (intel_dsi->ports & BIT(PORT_C))
return PORT_C;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 5572e43026e4..c86f9890754d 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -32,6 +32,7 @@
#include <drm/drm_crtc.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_types.h"
@@ -491,8 +492,8 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
intel_encoder->pipe_mask = ~0;
if (dvo->type != INTEL_DVO_CHIP_LVDS)
- intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
- (1 << INTEL_OUTPUT_DVO);
+ intel_encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) |
+ BIT(INTEL_OUTPUT_DVO);
switch (dvo->type) {
case INTEL_DVO_CHIP_TMDS:
@@ -515,8 +516,6 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
drm_connector_helper_add(connector,
&intel_dvo_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
intel_connector_attach_encoder(intel_connector, intel_encoder);
if (dvo->type == INTEL_DVO_CHIP_LVDS) {
diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
index 50205f064d93..ecff7b190856 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo_dev.h
+++ b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
@@ -23,12 +23,12 @@
#ifndef __INTEL_DVO_DEV_H__
#define __INTEL_DVO_DEV_H__
-#include <linux/i2c.h>
-
-#include <drm/drm_crtc.h>
-
#include "i915_reg_defs.h"
+enum drm_connector_status;
+struct drm_display_mode;
+struct i2c_adapter;
+
struct intel_dvo_device {
const char *name;
int type;
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index eefa33c555ac..63137ae5ab21 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fb.c
@@ -301,6 +301,19 @@ static bool plane_caps_contain_all(u8 caps, u8 mask)
}
/**
+ * intel_fb_is_tiled_modifier: Check if a modifier is a tiled modifier type
+ * @modifier: Modifier to check
+ *
+ * Returns:
+ * Returns %true if @modifier is a tiled modifier.
+ */
+bool intel_fb_is_tiled_modifier(u64 modifier)
+{
+ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
+ INTEL_PLANE_CAP_TILING_MASK);
+}
+
+/**
* intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type
* @modifier: Modifier to check
*
diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h
index 12386f13a4e0..4662b812b934 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.h
+++ b/drivers/gpu/drm/i915/display/intel_fb.h
@@ -29,6 +29,7 @@ struct intel_plane_state;
#define INTEL_PLANE_CAP_TILING_Yf BIT(5)
#define INTEL_PLANE_CAP_TILING_4 BIT(6)
+bool intel_fb_is_tiled_modifier(u64 modifier);
bool intel_fb_is_ccs_modifier(u64 modifier);
bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier);
bool intel_fb_is_mc_ccs_modifier(u64 modifier);
diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c
index 1dddd6abd77b..6900acbb1381 100644
--- a/drivers/gpu/drm/i915/display/intel_fb_pin.c
+++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c
@@ -167,7 +167,6 @@ retry:
ret = i915_gem_object_attach_phys(obj, alignment);
else if (!ret && HAS_LMEM(dev_priv))
ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0);
- /* TODO: Do we need to sync when migration becomes async? */
if (!ret)
ret = i915_gem_object_pin_pages(obj);
if (ret)
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index f38175304928..b5ee5ea0d010 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -670,6 +670,7 @@ static void intel_fbc_nuke(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
+ lockdep_assert_held(&fbc->lock);
drm_WARN_ON(&i915->drm, fbc->flip_pending);
trace_intel_fbc_nuke(fbc->state.plane);
@@ -679,6 +680,8 @@ static void intel_fbc_nuke(struct intel_fbc *fbc)
static void intel_fbc_activate(struct intel_fbc *fbc)
{
+ lockdep_assert_held(&fbc->lock);
+
intel_fbc_hw_activate(fbc);
intel_fbc_nuke(fbc);
@@ -687,9 +690,7 @@ static void intel_fbc_activate(struct intel_fbc *fbc)
static void intel_fbc_deactivate(struct intel_fbc *fbc, const char *reason)
{
- struct drm_i915_private *i915 = fbc->i915;
-
- drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock));
+ lockdep_assert_held(&fbc->lock);
if (fbc->active)
intel_fbc_hw_deactivate(fbc);
@@ -1009,7 +1010,8 @@ static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
- /* The use of a CPU fence is one of two ways to detect writes by the
+ /*
+ * The use of a CPU fence is one of two ways to detect writes by the
* CPU to the scanout and trigger updates to the FBC.
*
* The other method is by software tracking (see
@@ -1019,12 +1021,6 @@ static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state)
* Note that is possible for a tiled surface to be unmappable (and
* so have no fence associated with it) due to aperture constraints
* at the time of pinning.
- *
- * FIXME with 90/270 degree rotation we should use the fence on
- * the normal GTT view (the rotated view doesn't even have a
- * fence). Would need changes to the FBC fence Y offset as well.
- * For now this will effectively disable FBC with 90/270 degree
- * rotation.
*/
return DISPLAY_VER(i915) >= 9 ||
(plane_state->flags & PLANE_HAS_FENCE &&
@@ -1187,7 +1183,7 @@ static bool intel_fbc_can_flip_nuke(struct intel_atomic_state *state,
const struct drm_framebuffer *old_fb = old_plane_state->hw.fb;
const struct drm_framebuffer *new_fb = new_plane_state->hw.fb;
- if (drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi))
+ if (intel_crtc_needs_modeset(new_crtc_state))
return false;
if (!intel_fbc_is_ok(old_plane_state) ||
@@ -1227,6 +1223,8 @@ static bool __intel_fbc_pre_update(struct intel_atomic_state *state,
struct intel_fbc *fbc = plane->fbc;
bool need_vblank_wait = false;
+ lockdep_assert_held(&fbc->lock);
+
fbc->flip_pending = true;
if (intel_fbc_can_flip_nuke(state, crtc, plane))
@@ -1284,7 +1282,7 @@ static void __intel_fbc_disable(struct intel_fbc *fbc)
struct drm_i915_private *i915 = fbc->i915;
struct intel_plane *plane = fbc->state.plane;
- drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock));
+ lockdep_assert_held(&fbc->lock);
drm_WARN_ON(&i915->drm, fbc->active);
drm_dbg_kms(&i915->drm, "Disabling FBC on [PLANE:%d:%s]\n",
@@ -1299,9 +1297,9 @@ static void __intel_fbc_disable(struct intel_fbc *fbc)
static void __intel_fbc_post_update(struct intel_fbc *fbc)
{
- struct drm_i915_private *i915 = fbc->i915;
+ lockdep_assert_held(&fbc->lock);
- drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock));
+ fbc->flip_pending = false;
if (!fbc->busy_bits)
intel_fbc_activate(fbc);
@@ -1324,10 +1322,8 @@ void intel_fbc_post_update(struct intel_atomic_state *state,
mutex_lock(&fbc->lock);
- if (fbc->state.plane == plane) {
- fbc->flip_pending = false;
+ if (fbc->state.plane == plane)
__intel_fbc_post_update(fbc);
- }
mutex_unlock(&fbc->lock);
}
@@ -1437,6 +1433,8 @@ static void __intel_fbc_enable(struct intel_atomic_state *state,
intel_atomic_get_new_plane_state(state, plane);
struct intel_fbc *fbc = plane->fbc;
+ lockdep_assert_held(&fbc->lock);
+
if (fbc->state.plane) {
if (fbc->state.plane != plane)
return;
@@ -1522,7 +1520,8 @@ void intel_fbc_update(struct intel_atomic_state *state,
mutex_lock(&fbc->lock);
- if (crtc_state->update_pipe && plane_state->no_fbc_reason) {
+ if (intel_crtc_needs_fastset(crtc_state) &&
+ plane_state->no_fbc_reason) {
if (fbc->state.plane == plane)
__intel_fbc_disable(fbc);
} else {
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
index 112aa0447a0d..5575d7abdc09 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
@@ -124,6 +124,8 @@ static const struct fb_ops intelfb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_set_par = intel_fbdev_set_par,
+ .fb_read = drm_fb_helper_cfb_read,
+ .fb_write = drm_fb_helper_cfb_write,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
@@ -175,7 +177,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
}
if (IS_ERR(obj)) {
- drm_err(&dev_priv->drm, "failed to allocate framebuffer\n");
+ drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj);
return PTR_ERR(obj);
}
@@ -254,9 +256,9 @@ static int intelfb_create(struct drm_fb_helper *helper,
goto out_unlock;
}
- info = drm_fb_helper_alloc_fbi(helper);
+ info = drm_fb_helper_alloc_info(helper);
if (IS_ERR(info)) {
- drm_err(&dev_priv->drm, "Failed to allocate fb_info\n");
+ drm_err(&dev_priv->drm, "Failed to allocate fb_info (%pe)\n", info);
ret = PTR_ERR(info);
goto out_unpin;
}
@@ -291,7 +293,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
vaddr = i915_vma_pin_iomap(vma);
if (IS_ERR(vaddr)) {
drm_err(&dev_priv->drm,
- "Failed to remap framebuffer into virtual memory\n");
+ "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr);
ret = PTR_ERR(vaddr);
goto out_unpin;
}
@@ -584,7 +586,7 @@ void intel_fbdev_unregister(struct drm_i915_private *dev_priv)
if (!current_is_async())
intel_fbdev_sync(ifbdev);
- drm_fb_helper_unregister_fbi(&ifbdev->helper);
+ drm_fb_helper_unregister_info(&ifbdev->helper);
}
void intel_fbdev_fini(struct drm_i915_private *dev_priv)
@@ -627,7 +629,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
if (!ifbdev || !ifbdev->vma)
goto set_suspend;
- info = ifbdev->helper.fbdev;
+ info = ifbdev->helper.info;
if (synchronous) {
/* Flush any pending work to turn the console on, and then
diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
index 7f47e5c85c81..063f1da4f229 100644
--- a/drivers/gpu/drm/i915/display/intel_fdi.c
+++ b/drivers/gpu/drm/i915/display/intel_fdi.c
@@ -5,6 +5,7 @@
#include <linux/string_helpers.h>
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_crtc.h"
#include "intel_ddi.h"
diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.h b/drivers/gpu/drm/i915/display/intel_fifo_underrun.h
index e04f22ac1f49..2e47d7d3c101 100644
--- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.h
+++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.h
@@ -8,9 +8,8 @@
#include <linux/types.h>
-#include "intel_display.h"
-
struct drm_i915_private;
+enum pipe;
bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum pipe pipe, bool enable);
diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
index d80e3e8a9b01..17a7aa8b28c2 100644
--- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
@@ -88,7 +88,7 @@ static void frontbuffer_flush(struct drm_i915_private *i915,
if (!frontbuffer_bits)
return;
- trace_intel_frontbuffer_flush(frontbuffer_bits, origin);
+ trace_intel_frontbuffer_flush(i915, frontbuffer_bits, origin);
might_sleep();
intel_drrs_flush(i915, frontbuffer_bits);
@@ -176,7 +176,7 @@ void __intel_fb_invalidate(struct intel_frontbuffer *front,
spin_unlock(&i915->display.fb_tracking.lock);
}
- trace_intel_frontbuffer_invalidate(frontbuffer_bits, origin);
+ trace_intel_frontbuffer_invalidate(i915, frontbuffer_bits, origin);
might_sleep();
intel_psr_invalidate(i915, frontbuffer_bits, origin);
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
index 7a19215ad844..02b593b1e2ea 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.c
+++ b/drivers/gpu/drm/i915/display/intel_global_state.c
@@ -45,14 +45,14 @@ void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,
obj->state = state;
obj->funcs = funcs;
- list_add_tail(&obj->head, &dev_priv->global_obj_list);
+ list_add_tail(&obj->head, &dev_priv->display.global.obj_list);
}
void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)
{
struct intel_global_obj *obj, *next;
- list_for_each_entry_safe(obj, next, &dev_priv->global_obj_list, head) {
+ list_for_each_entry_safe(obj, next, &dev_priv->display.global.obj_list, head) {
list_del(&obj->head);
drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1);
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
index 1f16fa3073c9..f01ee0bb3e5a 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.h
+++ b/drivers/gpu/drm/i915/display/intel_global_state.h
@@ -27,7 +27,7 @@ struct intel_global_obj {
};
#define intel_for_each_global_obj(obj, dev_priv) \
- list_for_each_entry(obj, &(dev_priv)->global_obj_list, head)
+ list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
#define for_each_new_global_obj_in_state(__state, obj, new_obj_state, __i) \
for ((__i) = 0; \
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index 74443f57f62d..a5840a28a69d 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -34,6 +34,8 @@
#include <drm/display/drm_hdcp_helper.h>
#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_gmbus.h"
@@ -49,9 +51,27 @@ struct intel_gmbus {
struct drm_i915_private *i915;
};
+enum gmbus_gpio {
+ GPIOA,
+ GPIOB,
+ GPIOC,
+ GPIOD,
+ GPIOE,
+ GPIOF,
+ GPIOG,
+ GPIOH,
+ __GPIOI_UNUSED,
+ GPIOJ,
+ GPIOK,
+ GPIOL,
+ GPIOM,
+ GPION,
+ GPIOO,
+};
+
struct gmbus_pin {
const char *name;
- enum i915_gpio gpio;
+ enum gmbus_gpio gpio;
};
/* Map gmbus pin pairs to names and registers. */
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
index 2a3733e8966c..8023c85c7fa0 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h
@@ -6,7 +6,7 @@
#ifndef __INTEL_HDCP_REGS_H__
#define __INTEL_HDCP_REGS_H__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
/* HDCP Key Registers */
#define HDCP_KEY_CONF _MMIO(0x66c00)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 7816b2a33fee..bac85d88054f 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -42,6 +42,7 @@
#include "i915_debugfs.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_connector.h"
#include "intel_ddi.h"
@@ -2057,13 +2058,6 @@ static bool hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, int bpc
if (!intel_hdmi_source_bpc_possible(dev_priv, bpc))
return false;
- /*
- * HDMI deep color affects the clocks, so it's only possible
- * when not cloning with other encoder types.
- */
- if (bpc > 8 && crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI))
- return false;
-
/* Display Wa_1405510057:icl,ehl */
if (intel_hdmi_is_ycbcr420(crtc_state) &&
bpc == 10 && DISPLAY_VER(dev_priv) == 11 &&
@@ -2190,9 +2184,13 @@ static bool intel_hdmi_has_audio(struct intel_encoder *encoder,
}
static enum intel_output_format
-intel_hdmi_output_format(struct intel_connector *connector,
+intel_hdmi_output_format(const struct intel_crtc_state *crtc_state,
+ struct intel_connector *connector,
bool ycbcr_420_output)
{
+ if (!crtc_state->has_hdmi_sink)
+ return INTEL_OUTPUT_FORMAT_RGB;
+
if (connector->base.ycbcr_420_allowed && ycbcr_420_output)
return INTEL_OUTPUT_FORMAT_YCBCR420;
else
@@ -2211,7 +2209,8 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode);
int ret;
- crtc_state->output_format = intel_hdmi_output_format(connector, ycbcr_420_only);
+ crtc_state->output_format =
+ intel_hdmi_output_format(crtc_state, connector, ycbcr_420_only);
if (ycbcr_420_only && !intel_hdmi_is_ycbcr420(crtc_state)) {
drm_dbg_kms(&i915->drm,
@@ -2226,13 +2225,19 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
!drm_mode_is_420_also(info, adjusted_mode))
return ret;
- crtc_state->output_format = intel_hdmi_output_format(connector, true);
+ crtc_state->output_format = intel_hdmi_output_format(crtc_state, connector, true);
ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
}
return ret;
}
+static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->uapi.encoder_mask &&
+ !is_power_of_2(crtc_state->uapi.encoder_mask);
+}
+
int intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
@@ -2248,8 +2253,9 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
return -EINVAL;
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
- pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_hdmi,
- conn_state);
+ pipe_config->has_hdmi_sink =
+ intel_has_hdmi_sink(intel_hdmi, conn_state) &&
+ !intel_hdmi_is_cloned(pipe_config);
if (pipe_config->has_hdmi_sink)
pipe_config->has_infoframe = true;
@@ -2257,9 +2263,6 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
pipe_config->pixel_multiplier = 2;
- if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
- pipe_config->has_pch_encoder = true;
-
pipe_config->has_audio =
intel_hdmi_has_audio(encoder, pipe_config, conn_state);
@@ -2355,7 +2358,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
}
static void
-intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
+intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector));
@@ -2371,16 +2374,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
* CONFIG1 pin, but no such luck on our hardware.
*
* The only method left to us is to check the VBT to see
- * if the port is a dual mode capable DP port. But let's
- * only do that when we sucesfully read the EDID, to avoid
- * confusing log messages about DP dual mode adaptors when
- * there's nothing connected to the port.
+ * if the port is a dual mode capable DP port.
*/
if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
- /* An overridden EDID imply that we want this port for testing.
- * Make sure not to set limits for that port.
- */
- if (has_edid && !connector->override_edid &&
+ if (!connector->force &&
intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
drm_dbg_kms(&dev_priv->drm,
"Assuming DP dual mode adaptor presence based on VBT\n");
@@ -2435,18 +2432,18 @@ intel_hdmi_set_edid(struct drm_connector *connector)
intel_gmbus_force_bit(i2c, false);
}
- intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
-
to_intel_connector(connector)->detect_edid = edid;
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+ intel_hdmi_dp_dual_mode_detect(connector);
+
connected = true;
}
+ intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
+
cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid);
return connected;
@@ -2956,9 +2953,8 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
ddc);
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
- connector->interlace_allowed = 1;
- connector->doublescan_allowed = 0;
- connector->stereo_allowed = 1;
+ connector->interlace_allowed = true;
+ connector->stereo_allowed = true;
if (DISPLAY_VER(dev_priv) >= 10)
connector->ycbcr_420_allowed = true;
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 93f65a917c36..774dda2376ed 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -6,20 +6,20 @@
#ifndef __INTEL_HDMI_H__
#define __INTEL_HDMI_H__
-#include <linux/hdmi.h>
#include <linux/types.h>
+enum hdmi_infoframe_type;
+enum port;
struct drm_connector;
+struct drm_connector_state;
struct drm_encoder;
struct drm_i915_private;
struct intel_connector;
+struct intel_crtc_state;
struct intel_digital_port;
struct intel_encoder;
-struct intel_crtc_state;
struct intel_hdmi;
-struct drm_connector_state;
union hdmi_infoframe;
-enum port;
void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector);
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index f7a2f485b177..907ab7526cb4 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -90,6 +90,9 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
return HPD_PORT_A + port - PORT_A;
}
+/* Threshold == 5 for long IRQs, 50 for short */
+#define HPD_STORM_DEFAULT_THRESHOLD 50
+
#define HPD_STORM_DETECT_PERIOD 1000
#define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000)
#define HPD_RETRY_DELAY 1000
@@ -175,14 +178,13 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv,
static void
intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
bool hpd_disabled = false;
lockdep_assert_held(&dev_priv->irq_lock);
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
enum hpd_pin pin;
@@ -208,7 +210,7 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
/* Enable polling and queue hotplug re-enabling. */
if (hpd_disabled) {
- drm_kms_helper_poll_enable(dev);
+ drm_kms_helper_poll_enable(&dev_priv->drm);
mod_delayed_work(system_wq, &dev_priv->display.hotplug.reenable_work,
msecs_to_jiffies(HPD_STORM_REENABLE_DELAY));
}
@@ -219,7 +221,6 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
struct drm_i915_private *dev_priv =
container_of(work, typeof(*dev_priv),
display.hotplug.reenable_work.work);
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
intel_wakeref_t wakeref;
@@ -229,7 +230,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
spin_lock_irq(&dev_priv->irq_lock);
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
pin = intel_connector_hpd_pin(connector);
if (pin == HPD_NONE ||
@@ -367,14 +368,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
struct drm_i915_private *dev_priv =
container_of(work, struct drm_i915_private,
display.hotplug.hotplug_work.work);
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
u32 changed = 0, retry = 0;
u32 hpd_event_bits;
u32 hpd_retry_bits;
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
drm_dbg_kms(&dev_priv->drm, "running encoder hotplug functions\n");
spin_lock_irq(&dev_priv->irq_lock);
@@ -389,7 +389,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
spin_unlock_irq(&dev_priv->irq_lock);
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
enum hpd_pin pin;
u32 hpd_bit;
@@ -426,10 +426,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
}
}
drm_connector_list_iter_end(&conn_iter);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
if (changed)
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(&dev_priv->drm);
/* Remove shared HPD pins that have changed */
retry &= ~changed;
@@ -612,16 +612,15 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
struct drm_i915_private *dev_priv =
container_of(work, struct drm_i915_private,
display.hotplug.poll_init_work);
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
bool enabled;
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
enabled = READ_ONCE(dev_priv->display.hotplug.poll_enabled);
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
enum hpd_pin pin;
@@ -638,16 +637,16 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
drm_connector_list_iter_end(&conn_iter);
if (enabled)
- drm_kms_helper_poll_enable(dev);
+ drm_kms_helper_poll_enable(&dev_priv->drm);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
/*
* We might have missed any hotplugs that happened while we were
* in the middle of disabling polling
*/
if (!enabled)
- drm_helper_hpd_irq_event(dev);
+ drm_helper_hpd_irq_event(&dev_priv->drm);
}
/**
@@ -711,14 +710,23 @@ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv)
schedule_work(&dev_priv->display.hotplug.poll_init_work);
}
-void intel_hpd_init_work(struct drm_i915_private *dev_priv)
+void intel_hpd_init_early(struct drm_i915_private *i915)
{
- INIT_DELAYED_WORK(&dev_priv->display.hotplug.hotplug_work,
+ INIT_DELAYED_WORK(&i915->display.hotplug.hotplug_work,
i915_hotplug_work_func);
- INIT_WORK(&dev_priv->display.hotplug.dig_port_work, i915_digport_work_func);
- INIT_WORK(&dev_priv->display.hotplug.poll_init_work, i915_hpd_poll_init_work);
- INIT_DELAYED_WORK(&dev_priv->display.hotplug.reenable_work,
+ INIT_WORK(&i915->display.hotplug.dig_port_work, i915_digport_work_func);
+ INIT_WORK(&i915->display.hotplug.poll_init_work, i915_hpd_poll_init_work);
+ INIT_DELAYED_WORK(&i915->display.hotplug.reenable_work,
intel_hpd_irq_storm_reenable_work);
+
+ i915->display.hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
+ /* If we have MST support, we want to avoid doing short HPD IRQ storm
+ * detection, as short HPD storms will occur as a natural part of
+ * sideband messaging with MST.
+ * On older platforms however, IRQ storms can occur with both long and
+ * short pulses, as seen on some G4x systems.
+ */
+ i915->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(i915);
}
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
@@ -767,3 +775,169 @@ void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
dev_priv->display.hotplug.stats[pin].state = HPD_ENABLED;
spin_unlock_irq(&dev_priv->irq_lock);
}
+
+static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
+{
+ struct drm_i915_private *dev_priv = m->private;
+ struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
+
+ /* Synchronize with everything first in case there's been an HPD
+ * storm, but we haven't finished handling it in the kernel yet
+ */
+ intel_synchronize_irq(dev_priv);
+ flush_work(&dev_priv->display.hotplug.dig_port_work);
+ flush_delayed_work(&dev_priv->display.hotplug.hotplug_work);
+
+ seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold);
+ seq_printf(m, "Detected: %s\n",
+ str_yes_no(delayed_work_pending(&hotplug->reenable_work)));
+
+ return 0;
+}
+
+static ssize_t i915_hpd_storm_ctl_write(struct file *file,
+ const char __user *ubuf, size_t len,
+ loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct drm_i915_private *dev_priv = m->private;
+ struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
+ unsigned int new_threshold;
+ int i;
+ char *newline;
+ char tmp[16];
+
+ if (len >= sizeof(tmp))
+ return -EINVAL;
+
+ if (copy_from_user(tmp, ubuf, len))
+ return -EFAULT;
+
+ tmp[len] = '\0';
+
+ /* Strip newline, if any */
+ newline = strchr(tmp, '\n');
+ if (newline)
+ *newline = '\0';
+
+ if (strcmp(tmp, "reset") == 0)
+ new_threshold = HPD_STORM_DEFAULT_THRESHOLD;
+ else if (kstrtouint(tmp, 10, &new_threshold) != 0)
+ return -EINVAL;
+
+ if (new_threshold > 0)
+ drm_dbg_kms(&dev_priv->drm,
+ "Setting HPD storm detection threshold to %d\n",
+ new_threshold);
+ else
+ drm_dbg_kms(&dev_priv->drm, "Disabling HPD storm detection\n");
+
+ spin_lock_irq(&dev_priv->irq_lock);
+ hotplug->hpd_storm_threshold = new_threshold;
+ /* Reset the HPD storm stats so we don't accidentally trigger a storm */
+ for_each_hpd_pin(i)
+ hotplug->stats[i].count = 0;
+ spin_unlock_irq(&dev_priv->irq_lock);
+
+ /* Re-enable hpd immediately if we were in an irq storm */
+ flush_delayed_work(&dev_priv->display.hotplug.reenable_work);
+
+ return len;
+}
+
+static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, i915_hpd_storm_ctl_show, inode->i_private);
+}
+
+static const struct file_operations i915_hpd_storm_ctl_fops = {
+ .owner = THIS_MODULE,
+ .open = i915_hpd_storm_ctl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = i915_hpd_storm_ctl_write
+};
+
+static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data)
+{
+ struct drm_i915_private *dev_priv = m->private;
+
+ seq_printf(m, "Enabled: %s\n",
+ str_yes_no(dev_priv->display.hotplug.hpd_short_storm_enabled));
+
+ return 0;
+}
+
+static int
+i915_hpd_short_storm_ctl_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, i915_hpd_short_storm_ctl_show,
+ inode->i_private);
+}
+
+static ssize_t i915_hpd_short_storm_ctl_write(struct file *file,
+ const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct drm_i915_private *dev_priv = m->private;
+ struct intel_hotplug *hotplug = &dev_priv->display.hotplug;
+ char *newline;
+ char tmp[16];
+ int i;
+ bool new_state;
+
+ if (len >= sizeof(tmp))
+ return -EINVAL;
+
+ if (copy_from_user(tmp, ubuf, len))
+ return -EFAULT;
+
+ tmp[len] = '\0';
+
+ /* Strip newline, if any */
+ newline = strchr(tmp, '\n');
+ if (newline)
+ *newline = '\0';
+
+ /* Reset to the "default" state for this system */
+ if (strcmp(tmp, "reset") == 0)
+ new_state = !HAS_DP_MST(dev_priv);
+ else if (kstrtobool(tmp, &new_state) != 0)
+ return -EINVAL;
+
+ drm_dbg_kms(&dev_priv->drm, "%sabling HPD short storm detection\n",
+ new_state ? "En" : "Dis");
+
+ spin_lock_irq(&dev_priv->irq_lock);
+ hotplug->hpd_short_storm_enabled = new_state;
+ /* Reset the HPD storm stats so we don't accidentally trigger a storm */
+ for_each_hpd_pin(i)
+ hotplug->stats[i].count = 0;
+ spin_unlock_irq(&dev_priv->irq_lock);
+
+ /* Re-enable hpd immediately if we were in an irq storm */
+ flush_delayed_work(&dev_priv->display.hotplug.reenable_work);
+
+ return len;
+}
+
+static const struct file_operations i915_hpd_short_storm_ctl_fops = {
+ .owner = THIS_MODULE,
+ .open = i915_hpd_short_storm_ctl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = i915_hpd_short_storm_ctl_write,
+};
+
+void intel_hpd_debugfs_register(struct drm_i915_private *i915)
+{
+ struct drm_minor *minor = i915->drm.primary;
+
+ debugfs_create_file("i915_hpd_storm_ctl", 0644, minor->debugfs_root,
+ i915, &i915_hpd_storm_ctl_fops);
+ debugfs_create_file("i915_hpd_short_storm_ctl", 0644, minor->debugfs_root,
+ i915, &i915_hpd_short_storm_ctl_fops);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h
index b87e95d606e6..424ae5dbf5a0 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.h
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.h
@@ -22,11 +22,12 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
u32 pin_mask, u32 long_mask);
void intel_hpd_trigger_irq(struct intel_digital_port *dig_port);
void intel_hpd_init(struct drm_i915_private *dev_priv);
-void intel_hpd_init_work(struct drm_i915_private *dev_priv);
+void intel_hpd_init_early(struct drm_i915_private *i915);
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
enum port port);
bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
+void intel_hpd_debugfs_register(struct drm_i915_private *i915);
#endif /* __INTEL_HOTPLUG_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hti.c b/drivers/gpu/drm/i915/display/intel_hti.c
new file mode 100644
index 000000000000..12a1f4ce1a77
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hti.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "intel_de.h"
+#include "intel_display.h"
+#include "intel_hti.h"
+#include "intel_hti_regs.h"
+
+void intel_hti_init(struct drm_i915_private *i915)
+{
+ /*
+ * If the platform has HTI, we need to find out whether it has reserved
+ * any display resources before we create our display outputs.
+ */
+ if (INTEL_INFO(i915)->display.has_hti)
+ i915->display.hti.state = intel_de_read(i915, HDPORT_STATE);
+}
+
+bool intel_hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
+{
+ return i915->display.hti.state & HDPORT_ENABLED &&
+ i915->display.hti.state & HDPORT_DDI_USED(phy);
+}
+
+u32 intel_hti_dpll_mask(struct drm_i915_private *i915)
+{
+ if (!(i915->display.hti.state & HDPORT_ENABLED))
+ return 0;
+
+ /*
+ * Note: This is subtle. The values must coincide with what's defined
+ * for the platform.
+ */
+ return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->display.hti.state);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hti.h b/drivers/gpu/drm/i915/display/intel_hti.h
new file mode 100644
index 000000000000..2893d6668657
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hti.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_HTI_H__
+#define __INTEL_HTI_H__
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+enum phy;
+
+void intel_hti_init(struct drm_i915_private *i915);
+bool intel_hti_uses_phy(struct drm_i915_private *i915, enum phy phy);
+u32 intel_hti_dpll_mask(struct drm_i915_private *i915);
+
+#endif /* __INTEL_HTI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hti_regs.h b/drivers/gpu/drm/i915/display/intel_hti_regs.h
new file mode 100644
index 000000000000..e206f2837fc8
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hti_regs.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_HTI_REGS_H__
+#define __INTEL_HTI_REGS_H__
+
+#include "i915_reg_defs.h"
+
+#define HDPORT_STATE _MMIO(0x45050)
+#define HDPORT_DPLL_USED_MASK REG_GENMASK(15, 12)
+#define HDPORT_DDI_USED(phy) REG_BIT(2 * (phy) + 1)
+#define HDPORT_ENABLED REG_BIT(0)
+
+#endif /* __INTEL_HTI_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c
index dca6003ccac8..8aaaef4d7856 100644
--- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c
@@ -71,6 +71,8 @@
#include <drm/intel_lpe_audio.h>
#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_lpe_audio.h"
#include "intel_pci_config.h"
@@ -80,8 +82,7 @@
static struct platform_device *
lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
+ struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
struct platform_device_info pinfo = {};
struct resource *rsc;
struct platform_device *platdev;
@@ -101,14 +102,14 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
rsc[0].flags = IORESOURCE_IRQ;
rsc[0].name = "hdmi-lpe-audio-irq";
- rsc[1].start = pci_resource_start(pdev, GTTMMADR_BAR) +
+ rsc[1].start = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) +
I915_HDMI_LPE_AUDIO_BASE;
- rsc[1].end = pci_resource_start(pdev, GTTMMADR_BAR) +
+ rsc[1].end = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) +
I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1;
rsc[1].flags = IORESOURCE_MEM;
rsc[1].name = "hdmi-lpe-audio-mmio";
- pinfo.parent = dev->dev;
+ pinfo.parent = dev_priv->drm.dev;
pinfo.name = "hdmi-lpe-audio";
pinfo.id = -1;
pinfo.res = rsc;
diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c
index 15d59de8810e..9ff1c0b223ad 100644
--- a/drivers/gpu/drm/i915/display/intel_lspcon.c
+++ b/drivers/gpu/drm/i915/display/intel_lspcon.c
@@ -28,6 +28,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dp.h"
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index e5352239b2a2..7bf1bdfd03ec 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -39,6 +39,7 @@
#include <drm/drm_edid.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_backlight.h"
#include "intel_connector.h"
@@ -78,9 +79,9 @@ struct intel_lvds_encoder {
struct intel_connector *attached_connector;
};
-static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
+static struct intel_lvds_encoder *to_lvds_encoder(struct intel_encoder *encoder)
{
- return container_of(encoder, struct intel_lvds_encoder, base.base);
+ return container_of(encoder, struct intel_lvds_encoder, base);
}
bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
@@ -103,7 +104,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
intel_wakeref_t wakeref;
bool ret;
@@ -123,7 +124,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
u32 tmp, flags = 0;
pipe_config->output_types |= BIT(INTEL_OUTPUT_LVDS);
@@ -229,7 +230,7 @@ static void intel_pre_enable_lvds(struct intel_atomic_state *state,
const struct intel_crtc_state *pipe_config,
const struct drm_connector_state *conn_state)
{
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
@@ -312,7 +313,7 @@ static void intel_enable_lvds(struct intel_atomic_state *state,
const struct drm_connector_state *conn_state)
{
struct drm_device *dev = encoder->base.dev;
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
struct drm_i915_private *dev_priv = to_i915(dev);
intel_de_write(dev_priv, lvds_encoder->reg,
@@ -334,7 +335,7 @@ static void intel_disable_lvds(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
intel_de_write(dev_priv, PP_CONTROL(0),
@@ -413,7 +414,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
{
struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
struct intel_lvds_encoder *lvds_encoder =
- to_lvds_encoder(&intel_encoder->base);
+ to_lvds_encoder(intel_encoder);
struct intel_connector *intel_connector =
lvds_encoder->attached_connector;
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
@@ -775,7 +776,7 @@ bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv)
{
struct intel_encoder *encoder = intel_get_lvds_encoder(dev_priv);
- return encoder && to_lvds_encoder(&encoder->base)->is_dual_link;
+ return encoder && to_lvds_encoder(encoder)->is_dual_link;
}
static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
@@ -814,6 +815,11 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
}
+static void intel_lvds_add_properties(struct drm_connector *connector)
+{
+ intel_attach_scaling_mode_property(connector);
+}
+
/**
* intel_lvds_init - setup LVDS connectors on this device
* @dev_priv: i915 device
@@ -823,7 +829,6 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
*/
void intel_lvds_init(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_lvds_encoder *lvds_encoder;
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
@@ -833,11 +838,10 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
i915_reg_t lvds_reg;
u32 lvds;
u8 pin;
- u32 allowed_scalers;
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds)) {
- drm_WARN(dev, !dev_priv->display.vbt.int_lvds_support,
+ drm_WARN(&dev_priv->drm, !dev_priv->display.vbt.int_lvds_support,
"Useless DMI match. Internal LVDS support disabled by VBT\n");
return;
}
@@ -886,10 +890,10 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
intel_encoder = &lvds_encoder->base;
encoder = &intel_encoder->base;
connector = &intel_connector->base;
- drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
+ drm_connector_init(&dev_priv->drm, &intel_connector->base, &intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
- drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
+ drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS, "LVDS");
intel_encoder->enable = intel_enable_lvds;
@@ -920,17 +924,10 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
lvds_encoder->reg = lvds_reg;
- /* create the scaling mode property */
- allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT);
- allowed_scalers |= BIT(DRM_MODE_SCALE_FULLSCREEN);
- allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
- drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
- connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+ intel_lvds_add_properties(connector);
intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps);
lvds_encoder->init_lvds_val = lvds;
@@ -947,7 +944,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
* Attempt to get the fixed panel mode from DDC. Assume that the
* preferred mode is the right one.
*/
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
edid = drm_get_edid_switcheroo(connector,
intel_gmbus_get_adapter(dev_priv, pin));
@@ -971,8 +968,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
IS_ERR(edid) ? NULL : edid);
/* Try EDID first */
- intel_panel_add_edid_fixed_modes(intel_connector,
- intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE);
+ intel_panel_add_edid_fixed_modes(intel_connector, true);
/* Failed to get EDID, what about VBT? */
if (!intel_panel_preferred_fixed_mode(intel_connector))
@@ -986,7 +982,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
if (!intel_panel_preferred_fixed_mode(intel_connector))
intel_panel_add_encoder_fixed_mode(intel_connector, intel_encoder);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
/* If we still don't have a mode after all that, give up. */
if (!intel_panel_preferred_fixed_mode(intel_connector))
diff --git a/drivers/gpu/drm/i915/display/intel_tc_phy_regs.h b/drivers/gpu/drm/i915/display/intel_mg_phy_regs.h
index 5a545086f959..0e8248bce52d 100644
--- a/drivers/gpu/drm/i915/display/intel_tc_phy_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_mg_phy_regs.h
@@ -3,10 +3,10 @@
* Copyright © 2022 Intel Corporation
*/
-#ifndef __INTEL_TC_PHY_REGS__
-#define __INTEL_TC_PHY_REGS__
+#ifndef __INTEL_MG_PHY_REGS__
+#define __INTEL_MG_PHY_REGS__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
#define MG_PHY_PORT_LN(ln, tc_port, ln0p1, ln0p2, ln1p1) \
_MMIO(_PORT(tc_port, ln0p1, ln0p2) + (ln) * ((ln1p1) - (ln0p1)))
@@ -277,4 +277,4 @@
_MG_PLL_TDC_COLDST_BIAS_PORT1, \
_MG_PLL_TDC_COLDST_BIAS_PORT2)
-#endif /* __INTEL_TC_PHY_REGS__ */
+#endif /* __INTEL_MG_PHY_REGS__ */
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
index cbfabd58b75a..96395bfbd41d 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
@@ -10,6 +10,7 @@
#include <drm/drm_atomic_state_helper.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_bw.h"
#include "intel_color.h"
@@ -155,6 +156,12 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state
crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
+ /* assume 1:1 mapping */
+ drm_property_replace_blob(&crtc_state->hw.degamma_lut,
+ crtc_state->pre_csc_lut);
+ drm_property_replace_blob(&crtc_state->hw.gamma_lut,
+ crtc_state->post_csc_lut);
+
drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
crtc_state->hw.degamma_lut);
drm_property_replace_blob(&crtc_state->uapi.gamma_lut,
@@ -205,13 +212,21 @@ static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder)
{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
+ struct intel_connector *found_connector = NULL;
- for_each_connector_on_encoder(dev, &encoder->base, connector)
- return connector;
+ drm_connector_list_iter_begin(&i915->drm, &conn_iter);
+ for_each_intel_connector_iter(connector, &conn_iter) {
+ if (&encoder->base == connector->base.encoder) {
+ found_connector = connector;
+ break;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
- return NULL;
+ return found_connector;
}
static void intel_sanitize_fifo_underrun_reporting(const struct intel_crtc_state *crtc_state)
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
index 0fdcf2e6d57f..842d70f0dfd2 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
@@ -227,7 +227,8 @@ void intel_modeset_verify_crtc(struct intel_crtc *crtc,
struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state)
{
- if (!intel_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->update_pipe)
+ if (!intel_crtc_needs_modeset(new_crtc_state) &&
+ !intel_crtc_needs_fastset(new_crtc_state))
return;
intel_wm_state_verify(crtc, new_crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index caa07ef34f21..e0184745632c 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -463,7 +463,6 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
struct intel_connector *connector;
struct drm_connector_list_iter conn_iter;
struct opregion_asle *asle = dev_priv->display.opregion.asle;
- struct drm_device *dev = &dev_priv->drm;
drm_dbg(&dev_priv->drm, "bclp = 0x%08x\n", bclp);
@@ -480,7 +479,7 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
if (bclp > 255)
return ASLC_BACKLIGHT_FAILED;
- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+ drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL);
/*
* Update backlight on all connectors that support backlight (usually
@@ -488,13 +487,13 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
*/
drm_dbg_kms(&dev_priv->drm, "updating opregion backlight %d/255\n",
bclp);
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter)
intel_backlight_set_acpi(connector->base.state, bclp, 255);
drm_connector_list_iter_end(&conn_iter);
asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
- drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 41cec9dc4223..1640726bfbf6 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -31,6 +31,7 @@
#include <linux/kernel.h>
#include <linux/pwm.h>
+#include "i915_reg.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
@@ -85,9 +86,10 @@ static bool is_alt_drrs_mode(const struct drm_display_mode *mode,
static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
const struct drm_display_mode *preferred_mode)
{
- return drm_mode_match(mode, preferred_mode,
- DRM_MODE_MATCH_FLAGS |
- DRM_MODE_MATCH_3D_FLAGS) &&
+ u32 sync_flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC |
+ DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC;
+
+ return (mode->flags & ~sync_flags) == (preferred_mode->flags & ~sync_flags) &&
mode->hdisplay == preferred_mode->hdisplay &&
mode->vdisplay == preferred_mode->vdisplay;
}
@@ -147,12 +149,24 @@ int intel_panel_get_modes(struct intel_connector *connector)
return num_modes;
}
-enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
+static bool has_drrs_modes(struct intel_connector *connector)
{
- if (list_empty(&connector->panel.fixed_modes) ||
- list_is_singular(&connector->panel.fixed_modes))
- return DRRS_TYPE_NONE;
+ const struct drm_display_mode *mode1;
+
+ list_for_each_entry(mode1, &connector->panel.fixed_modes, head) {
+ const struct drm_display_mode *mode2 = mode1;
+
+ list_for_each_entry_continue(mode2, &connector->panel.fixed_modes, head) {
+ if (is_alt_drrs_mode(mode1, mode2))
+ return true;
+ }
+ }
+
+ return false;
+}
+enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
+{
return connector->panel.vbt.drrs_type;
}
@@ -653,6 +667,9 @@ int intel_panel_init(struct intel_connector *connector)
intel_backlight_init_funcs(panel);
+ if (!has_drrs_modes(connector))
+ connector->panel.vbt.drrs_type = DRRS_TYPE_NONE;
+
drm_dbg_kms(connector->base.dev,
"[CONNECTOR:%d:%s] DRRS type: %s\n",
connector->base.base.id, connector->base.name,
diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c
index 837152dca063..cecc0d007cf3 100644
--- a/drivers/gpu/drm/i915/display/intel_pch_display.c
+++ b/drivers/gpu/drm/i915/display/intel_pch_display.c
@@ -4,6 +4,7 @@
*/
#include "g4x_dp.h"
+#include "i915_reg.h"
#include "intel_crt.h"
#include "intel_de.h"
#include "intel_display_types.h"
diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
index a66097cdc1e0..08a94365b7d1 100644
--- a/drivers/gpu/drm/i915/display/intel_pch_refclk.c
+++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
@@ -3,6 +3,7 @@
* Copyright © 2021 Intel Corporation
*/
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_panel.h"
diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
index 8ac263f471be..e9774670e3f6 100644
--- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
@@ -24,11 +24,12 @@
*
*/
-#include <linux/circ_buf.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_de.h"
#include "intel_display_types.h"
@@ -75,7 +76,6 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
enum pipe pipe,
enum intel_pipe_crc_source *source)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_encoder *encoder;
struct intel_crtc *crtc;
struct intel_digital_port *dig_port;
@@ -83,8 +83,8 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
*source = INTEL_PIPE_CRC_SOURCE_PIPE;
- drm_modeset_lock_all(dev);
- for_each_intel_encoder(dev, encoder) {
+ drm_modeset_lock_all(&dev_priv->drm);
+ for_each_intel_encoder(&dev_priv->drm, encoder) {
if (!encoder->base.crtc)
continue;
@@ -111,7 +111,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
*source = INTEL_PIPE_CRC_SOURCE_DP_D;
break;
default:
- drm_WARN(dev, 1, "nonexisting DP port %c\n",
+ drm_WARN(&dev_priv->drm, 1, "nonexisting DP port %c\n",
port_name(dig_port->base.port));
break;
}
@@ -120,7 +120,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
break;
}
}
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
return ret;
}
diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c
index 21944f5bf3a8..9bbf41a076f7 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.c
+++ b/drivers/gpu/drm/i915/display/intel_pps.c
@@ -5,10 +5,12 @@
#include "g4x_dp.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_power_well.h"
#include "intel_display_types.h"
#include "intel_dp.h"
+#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_lvds.h"
#include "intel_pps.h"
@@ -1098,7 +1100,13 @@ bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp)
static void pps_init_timestamps(struct intel_dp *intel_dp)
{
- intel_dp->pps.panel_power_off_time = ktime_get_boottime();
+ /*
+ * Initialize panel power off time to 0, assuming panel power could have
+ * been toggled between kernel boot and now only by a previously loaded
+ * and removed i915, which has already ensured sufficient power off
+ * delay at module remove.
+ */
+ intel_dp->pps.panel_power_off_time = 0;
intel_dp->pps.last_power_on = jiffies;
intel_dp->pps.last_backlight_off = jiffies;
}
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index d4cce627d7a8..5b678916e6db 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -27,6 +27,7 @@
#include "display/intel_dp.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_crtc.h"
#include "intel_de.h"
@@ -533,7 +534,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
val |= psr_compute_idle_frames(intel_dp) << EDP_PSR2_IDLE_FRAME_SHIFT;
- if (!IS_ALDERLAKE_P(dev_priv))
+ if (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv))
val |= EDP_SU_TRACK_ENABLE;
if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12)
@@ -616,7 +617,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
static bool
transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder trans)
{
- if (IS_ALDERLAKE_P(dev_priv))
+ if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14)
return trans == TRANSCODER_A || trans == TRANSCODER_B;
else if (DISPLAY_VER(dev_priv) >= 12)
return trans == TRANSCODER_A;
@@ -696,7 +697,7 @@ dc3co_is_pipe_port_compatible(struct intel_dp *intel_dp,
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
enum port port = dig_port->base.port;
- if (IS_ALDERLAKE_P(dev_priv))
+ if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14)
return pipe <= PIPE_B && port <= PORT_B;
else
return pipe == PIPE_A && port == PORT_A;
@@ -779,6 +780,7 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
u16 y_granularity = 0;
@@ -795,11 +797,11 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp,
return intel_dp->psr.su_y_granularity == 4;
/*
- * adl_p has 1 line granularity. For other platforms with SW tracking we
- * can adjust the y coordinates to match sink requirement if multiple of
- * 4.
+ * adl_p and display 14+ platforms has 1 line granularity.
+ * For other platforms with SW tracking we can adjust the y coordinates
+ * to match sink requirement if multiple of 4.
*/
- if (IS_ALDERLAKE_P(dev_priv))
+ if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14)
y_granularity = intel_dp->psr.su_y_granularity;
else if (intel_dp->psr.su_y_granularity <= 2)
y_granularity = 4;
@@ -809,6 +811,10 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp,
if (y_granularity == 0 || crtc_vdisplay % y_granularity)
return false;
+ if (crtc_state->dsc.compression_enable &&
+ vdsc_cfg->slice_height % y_granularity)
+ return false;
+
crtc_state->su_y_granularity = y_granularity;
return true;
}
@@ -883,7 +889,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
* resolution requires DSC to be enabled, priority is given to DSC
* over PSR2.
*/
- if (crtc_state->dsc.compression_enable) {
+ if (crtc_state->dsc.compression_enable &&
+ (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv))) {
drm_dbg_kms(&dev_priv->drm,
"PSR2 cannot be enabled since DSC is enabled\n");
return false;
@@ -1469,26 +1476,27 @@ unlock:
static u32 man_trk_ctl_enable_bit_get(struct drm_i915_private *dev_priv)
{
- return IS_ALDERLAKE_P(dev_priv) ? 0 : PSR2_MAN_TRK_CTL_ENABLE;
+ return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ? 0 :
+ PSR2_MAN_TRK_CTL_ENABLE;
}
static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv)
{
- return IS_ALDERLAKE_P(dev_priv) ?
+ return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ?
ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME :
PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
}
static u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv)
{
- return IS_ALDERLAKE_P(dev_priv) ?
+ return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ?
ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE :
PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE;
}
static u32 man_trk_ctl_continuos_full_frame(struct drm_i915_private *dev_priv)
{
- return IS_ALDERLAKE_P(dev_priv) ?
+ return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ?
ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME :
PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME;
}
@@ -1627,7 +1635,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
if (clip->y1 == -1)
goto exit;
- if (IS_ALDERLAKE_P(dev_priv)) {
+ if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) {
val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1);
val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1);
} else {
@@ -1664,14 +1672,19 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c
struct drm_rect *pipe_clip)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- const u16 y_alignment = crtc_state->su_y_granularity;
+ const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
+ u16 y_alignment;
+
+ /* ADLP aligns the SU region to vdsc slice height in case dsc is enabled */
+ if (crtc_state->dsc.compression_enable &&
+ (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14))
+ y_alignment = vdsc_cfg->slice_height;
+ else
+ y_alignment = crtc_state->su_y_granularity;
pipe_clip->y1 -= pipe_clip->y1 % y_alignment;
if (pipe_clip->y2 % y_alignment)
pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment;
-
- if (IS_ALDERLAKE_P(dev_priv) && crtc_state->dsc.compression_enable)
- drm_warn(&dev_priv->drm, "Missing PSR2 sel fetch alignment with DSC\n");
}
/*
@@ -2054,13 +2067,12 @@ static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp)
static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
{
struct drm_connector_list_iter conn_iter;
- struct drm_device *dev = &dev_priv->drm;
struct drm_modeset_acquire_ctx ctx;
struct drm_atomic_state *state;
struct drm_connector *conn;
int err = 0;
- state = drm_atomic_state_alloc(dev);
+ state = drm_atomic_state_alloc(&dev_priv->drm);
if (!state)
return -ENOMEM;
@@ -2069,7 +2081,7 @@ static int intel_psr_fastset_force(struct drm_i915_private *dev_priv)
retry:
- drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
drm_for_each_connector_iter(conn, &conn_iter) {
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
@@ -2201,8 +2213,11 @@ static void _psr_invalidate_handle(struct intel_dp *intel_dp)
if (intel_dp->psr.psr2_sel_fetch_enabled) {
u32 val;
- if (intel_dp->psr.psr2_sel_fetch_cff_enabled)
+ if (intel_dp->psr.psr2_sel_fetch_cff_enabled) {
+ /* Send one update otherwise lag is observed in screen */
+ intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
return;
+ }
val = man_trk_ctl_enable_bit_get(dev_priv) |
man_trk_ctl_partial_frame_bit_get(dev_priv) |
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 774c1dc31a52..329b9d9af667 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -37,6 +37,7 @@
#include <drm/drm_edid.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_connector.h"
#include "intel_crtc.h"
@@ -199,7 +200,7 @@ to_intel_sdvo_connector(struct drm_connector *connector)
container_of((conn_state), struct intel_sdvo_connector_state, base.base)
static bool
-intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags);
+intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo);
static bool
intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
@@ -1297,13 +1298,28 @@ static bool intel_sdvo_limited_color_range(struct intel_encoder *encoder,
return intel_hdmi_limited_color_range(crtc_state, conn_state);
}
+static bool intel_sdvo_has_audio(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state)
+{
+ struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+ const struct intel_digital_connector_state *intel_conn_state =
+ to_intel_digital_connector_state(conn_state);
+
+ if (!crtc_state->has_hdmi_sink)
+ return false;
+
+ if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
+ return intel_sdvo->has_hdmi_audio;
+ else
+ return intel_conn_state->force_audio == HDMI_AUDIO_ON;
+}
+
static int intel_sdvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
{
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
- struct intel_sdvo_connector_state *intel_sdvo_state =
- to_intel_sdvo_connector_state(conn_state);
struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(conn_state->connector);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
@@ -1362,13 +1378,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo, conn_state);
- if (pipe_config->has_hdmi_sink) {
- if (intel_sdvo_state->base.force_audio == HDMI_AUDIO_AUTO)
- pipe_config->has_audio = intel_sdvo->has_hdmi_audio;
- else
- pipe_config->has_audio =
- intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON;
- }
+ pipe_config->has_audio = intel_sdvo_has_audio(encoder, pipe_config, conn_state);
pipe_config->limited_color_range =
intel_sdvo_limited_color_range(encoder, pipe_config,
@@ -2290,17 +2300,12 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
static int intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{
- struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
struct drm_i915_private *dev_priv = to_i915(connector->dev);
- int num_modes = 0;
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
- num_modes += intel_panel_get_modes(to_intel_connector(connector));
- num_modes += intel_ddc_get_modes(connector, &intel_sdvo->ddc);
-
- return num_modes;
+ return intel_panel_get_modes(to_intel_connector(connector));
}
static int intel_sdvo_get_modes(struct drm_connector *connector)
@@ -2627,7 +2632,7 @@ intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo)
}
static bool
-intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
+intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo)
{
return intel_sdvo_check_supp_encode(intel_sdvo);
}
@@ -2689,9 +2694,8 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
drm_connector_helper_add(drm_connector,
&intel_sdvo_connector_helper_funcs);
- connector->base.base.interlace_allowed = 1;
- connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
+ connector->base.base.interlace_allowed = true;
connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
intel_connector_attach_encoder(&connector->base, &encoder->base);
@@ -2733,7 +2737,7 @@ static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
}
static bool
-intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
+intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
@@ -2741,16 +2745,13 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising DVI device %d\n", device);
+ DRM_DEBUG_KMS("initialising DVI type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
return false;
- if (device == 0)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
- else if (device == 1)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
+ intel_sdvo_connector->output_flag = type;
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
@@ -2770,7 +2771,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
- if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
+ if (intel_sdvo_is_hdmi_connector(intel_sdvo)) {
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
intel_sdvo_connector->is_hdmi = true;
}
@@ -2787,14 +2788,14 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
}
static bool
-intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
+intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising TV type %d\n", type);
+ DRM_DEBUG_KMS("initialising TV type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2826,14 +2827,14 @@ err:
}
static bool
-intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
+intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising analog device %d\n", device);
+ DRM_DEBUG_KMS("initialising analog type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2845,10 +2846,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
- if (device == 0)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
- else if (device == 1)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+ intel_sdvo_connector->output_flag = type;
if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
kfree(intel_sdvo_connector);
@@ -2859,7 +2857,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
}
static bool
-intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
+intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_i915_private *i915 = to_i915(encoder->dev);
@@ -2867,7 +2865,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
- DRM_DEBUG_KMS("initialising LVDS device %d\n", device);
+ DRM_DEBUG_KMS("initialising LVDS type 0x%x\n", type);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
@@ -2878,10 +2876,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
- if (device == 0)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
- else if (device == 1)
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+ intel_sdvo_connector->output_flag = type;
if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
kfree(intel_sdvo_connector);
@@ -2937,63 +2932,61 @@ static u16 intel_sdvo_filter_output_flags(u16 flags)
return flags;
}
-static bool
-intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags)
+static bool intel_sdvo_output_init(struct intel_sdvo *sdvo, u16 type)
{
+ if (type & SDVO_TMDS_MASK)
+ return intel_sdvo_dvi_init(sdvo, type);
+ else if (type & SDVO_TV_MASK)
+ return intel_sdvo_tv_init(sdvo, type);
+ else if (type & SDVO_RGB_MASK)
+ return intel_sdvo_analog_init(sdvo, type);
+ else if (type & SDVO_LVDS_MASK)
+ return intel_sdvo_lvds_init(sdvo, type);
+ else
+ return false;
+}
+
+static bool
+intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
+{
+ static const u16 probe_order[] = {
+ SDVO_OUTPUT_TMDS0,
+ SDVO_OUTPUT_TMDS1,
+ /* TV has no XXX1 function block */
+ SDVO_OUTPUT_SVID0,
+ SDVO_OUTPUT_CVBS0,
+ SDVO_OUTPUT_YPRPB0,
+ SDVO_OUTPUT_RGB0,
+ SDVO_OUTPUT_RGB1,
+ SDVO_OUTPUT_LVDS0,
+ SDVO_OUTPUT_LVDS1,
+ };
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
+ u16 flags;
+ int i;
- flags = intel_sdvo_filter_output_flags(flags);
+ flags = intel_sdvo_filter_output_flags(intel_sdvo->caps.output_flags);
+
+ if (flags == 0) {
+ DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%04x)\n",
+ SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags);
+ return false;
+ }
intel_sdvo->controlled_output = flags;
intel_sdvo_select_ddc_bus(i915, intel_sdvo);
- if (flags & SDVO_OUTPUT_TMDS0)
- if (!intel_sdvo_dvi_init(intel_sdvo, 0))
- return false;
+ for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+ u16 type = flags & probe_order[i];
- if (flags & SDVO_OUTPUT_TMDS1)
- if (!intel_sdvo_dvi_init(intel_sdvo, 1))
- return false;
-
- /* TV has no XXX1 function block */
- if (flags & SDVO_OUTPUT_SVID0)
- if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0))
- return false;
+ if (!type)
+ continue;
- if (flags & SDVO_OUTPUT_CVBS0)
- if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))
+ if (!intel_sdvo_output_init(intel_sdvo, type))
return false;
-
- if (flags & SDVO_OUTPUT_YPRPB0)
- if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0))
- return false;
-
- if (flags & SDVO_OUTPUT_RGB0)
- if (!intel_sdvo_analog_init(intel_sdvo, 0))
- return false;
-
- if (flags & SDVO_OUTPUT_RGB1)
- if (!intel_sdvo_analog_init(intel_sdvo, 1))
- return false;
-
- if (flags & SDVO_OUTPUT_LVDS0)
- if (!intel_sdvo_lvds_init(intel_sdvo, 0))
- return false;
-
- if (flags & SDVO_OUTPUT_LVDS1)
- if (!intel_sdvo_lvds_init(intel_sdvo, 1))
- return false;
-
- if (flags == 0) {
- unsigned char bytes[2];
-
- memcpy(bytes, &intel_sdvo->caps.output_flags, 2);
- DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
- SDVO_NAME(intel_sdvo),
- bytes[0], bytes[1]);
- return false;
}
+
intel_sdvo->base.pipe_mask = ~0;
return true;
@@ -3369,8 +3362,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
intel_sdvo->colorimetry_cap =
intel_sdvo_get_colorimetry_cap(intel_sdvo);
- if (intel_sdvo_output_setup(intel_sdvo,
- intel_sdvo->caps.output_flags) != true) {
+ if (!intel_sdvo_output_setup(intel_sdvo)) {
drm_dbg_kms(&dev_priv->drm,
"SDVO output failed to setup on %s\n",
SDVO_NAME(intel_sdvo));
@@ -3421,9 +3413,12 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
(intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
/* check currently supported outputs */
intel_sdvo->caps.output_flags &
- (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
+ (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
+ SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 |
+ SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N',
intel_sdvo->caps.output_flags &
- (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
+ (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
+ SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
return true;
err_output:
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
index 937cefd6f78f..c799e891f8b5 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
@@ -5,6 +5,7 @@
#include <linux/util_macros.h>
+#include "i915_reg.h"
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy_regs.h b/drivers/gpu/drm/i915/display/intel_snps_phy_regs.h
index 0543465aaf14..a04d692169d4 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy_regs.h
@@ -6,7 +6,7 @@
#ifndef __INTEL_SNPS_PHY_REGS__
#define __INTEL_SNPS_PHY_REGS__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
#define _SNPS_PHY_A_BASE 0x168000
#define _SNPS_PHY_B_BASE 0x169000
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 7649c50b5445..e6b4d24b9cd0 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -42,6 +42,7 @@
#include <drm/drm_rect.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_vgpu.h"
#include "i9xx_plane.h"
#include "intel_atomic_plane.h"
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h
index 4f63e4967731..4635c7ad23f9 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.h
+++ b/drivers/gpu/drm/i915/display/intel_sprite.h
@@ -8,14 +8,13 @@
#include <linux/types.h>
-#include "intel_display.h"
-
struct drm_device;
struct drm_display_mode;
struct drm_file;
struct drm_i915_private;
struct intel_crtc_state;
struct intel_plane_state;
+enum pipe;
/*
* FIXME: We should instead only take spinlocks once for the entire update
@@ -34,12 +33,6 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
int chv_plane_check_rotation(const struct intel_plane_state *plane_state);
-static inline u8 icl_hdr_plane_mask(void)
-{
- return BIT(PLANE_PRIMARY) |
- BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1);
-}
-
int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index e5af955b5600..70624b4b2d38 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -8,9 +8,10 @@
#include "intel_display.h"
#include "intel_display_power_map.h"
#include "intel_display_types.h"
+#include "intel_dkl_phy_regs.h"
#include "intel_dp_mst.h"
+#include "intel_mg_phy_regs.h"
#include "intel_tc.h"
-#include "intel_tc_phy_regs.h"
static const char *tc_port_mode_name(enum tc_port_mode mode)
{
@@ -408,14 +409,9 @@ static bool adl_tc_phy_take_ownership(struct intel_digital_port *dig_port,
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct intel_uncore *uncore = &i915->uncore;
enum port port = dig_port->base.port;
- u32 val;
- val = intel_uncore_read(uncore, DDI_BUF_CTL(port));
- if (take)
- val |= DDI_BUF_CTL_TC_PHY_OWNERSHIP;
- else
- val &= ~DDI_BUF_CTL_TC_PHY_OWNERSHIP;
- intel_uncore_write(uncore, DDI_BUF_CTL(port), val);
+ intel_uncore_rmw(uncore, DDI_BUF_CTL(port), DDI_BUF_CTL_TC_PHY_OWNERSHIP,
+ take ? DDI_BUF_CTL_TC_PHY_OWNERSHIP : 0);
return true;
}
@@ -687,18 +683,58 @@ static void
intel_tc_port_link_init_refcount(struct intel_digital_port *dig_port,
int refcount)
{
+ dig_port->tc_link_refcount = refcount;
+}
+
+/**
+ * intel_tc_port_init_mode: Read out HW state and init the given port's TypeC mode
+ * @dig_port: digital port
+ *
+ * Read out the HW state and initialize the TypeC mode of @dig_port. The mode
+ * will be locked until intel_tc_port_sanitize_mode() is called.
+ */
+void intel_tc_port_init_mode(struct intel_digital_port *dig_port)
+{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ intel_wakeref_t tc_cold_wref;
+ enum intel_display_power_domain domain;
+
+ mutex_lock(&dig_port->tc_lock);
+ drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED);
+ drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount);
- dig_port->tc_link_refcount = refcount;
+
+ tc_cold_wref = tc_cold_block(dig_port, &domain);
+
+ dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
+ /* Prevent changing dig_port->tc_mode until intel_tc_port_sanitize_mode() is called. */
+ intel_tc_port_link_init_refcount(dig_port, 1);
+ dig_port->tc_lock_wakeref = tc_cold_block(dig_port, &dig_port->tc_lock_power_domain);
+
+ tc_cold_unblock(dig_port, domain, tc_cold_wref);
+
+ drm_dbg_kms(&i915->drm, "Port %s: init mode (%s)\n",
+ dig_port->tc_port_name,
+ tc_port_mode_name(dig_port->tc_mode));
+
+ mutex_unlock(&dig_port->tc_lock);
}
-void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
+/**
+ * intel_tc_port_sanitize_mode: Sanitize the given port's TypeC mode
+ * @dig_port: digital port
+ *
+ * Sanitize @dig_port's TypeC mode wrt. the encoder's state right after driver
+ * loading and system resume:
+ * If the encoder is enabled keep the TypeC mode/PHY connected state locked until
+ * the encoder is disabled.
+ * If the encoder is disabled make sure the PHY is disconnected.
+ */
+void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct intel_encoder *encoder = &dig_port->base;
- intel_wakeref_t tc_cold_wref;
- enum intel_display_power_domain domain;
int active_links = 0;
mutex_lock(&dig_port->tc_lock);
@@ -708,21 +744,14 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
else if (encoder->base.crtc)
active_links = to_intel_crtc(encoder->base.crtc)->active;
- drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED);
- drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
-
- tc_cold_wref = tc_cold_block(dig_port, &domain);
+ drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount != 1);
+ intel_tc_port_link_init_refcount(dig_port, active_links);
- dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
if (active_links) {
if (!icl_tc_phy_is_connected(dig_port))
drm_dbg_kms(&i915->drm,
"Port %s: PHY disconnected with %d active link(s)\n",
dig_port->tc_port_name, active_links);
- intel_tc_port_link_init_refcount(dig_port, active_links);
-
- dig_port->tc_lock_wakeref = tc_cold_block(dig_port,
- &dig_port->tc_lock_power_domain);
} else {
/*
* TBT-alt is the default mode in any case the PHY ownership is not
@@ -736,9 +765,10 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
dig_port->tc_port_name,
tc_port_mode_name(dig_port->tc_mode));
icl_tc_phy_disconnect(dig_port);
- }
- tc_cold_unblock(dig_port, domain, tc_cold_wref);
+ tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain,
+ fetch_and_zero(&dig_port->tc_lock_wakeref));
+ }
drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n",
dig_port->tc_port_name,
@@ -923,4 +953,6 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
dig_port->tc_mode = TC_PORT_DISCONNECTED;
dig_port->tc_link_refcount = 0;
tc_port_load_fia_params(i915, dig_port);
+
+ intel_tc_port_init_mode(dig_port);
}
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index 6b47b29f551c..d54082e2d5e8 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.h
+++ b/drivers/gpu/drm/i915/display/intel_tc.h
@@ -24,7 +24,8 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port);
void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
int required_lanes);
-void intel_tc_port_sanitize(struct intel_digital_port *dig_port);
+void intel_tc_port_init_mode(struct intel_digital_port *dig_port);
+void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port);
void intel_tc_port_lock(struct intel_digital_port *dig_port);
void intel_tc_port_unlock(struct intel_digital_port *dig_port);
void intel_tc_port_flush_work(struct intel_digital_port *dig_port);
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index dcf89d701f0f..4d2101ca1692 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -35,6 +35,8 @@
#include <drm/drm_edid.h>
#include "i915_drv.h"
+#include "i915_reg.h"
+#include "i915_irq.h"
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_de.h"
@@ -1880,18 +1882,56 @@ static const struct drm_encoder_funcs intel_tv_enc_funcs = {
.destroy = intel_encoder_destroy,
};
+static void intel_tv_add_properties(struct drm_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->dev);
+ struct drm_connector_state *conn_state = connector->state;
+ const char *tv_format_names[ARRAY_SIZE(tv_modes)];
+ int i;
+
+ /* BIOS margin values */
+ conn_state->tv.margins.left = 54;
+ conn_state->tv.margins.top = 36;
+ conn_state->tv.margins.right = 46;
+ conn_state->tv.margins.bottom = 37;
+
+ conn_state->tv.mode = 0;
+
+ /* Create TV properties then attach current values */
+ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+ /* 1080p50/1080p60 not supported on gen3 */
+ if (DISPLAY_VER(i915) == 3 && tv_modes[i].oversample == 1)
+ break;
+
+ tv_format_names[i] = tv_modes[i].name;
+ }
+ drm_mode_create_tv_properties(&i915->drm, i, tv_format_names);
+
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tv_mode_property,
+ conn_state->tv.mode);
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tv_left_margin_property,
+ conn_state->tv.margins.left);
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tv_top_margin_property,
+ conn_state->tv.margins.top);
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tv_right_margin_property,
+ conn_state->tv.margins.right);
+ drm_object_attach_property(&connector->base,
+ i915->drm.mode_config.tv_bottom_margin_property,
+ conn_state->tv.margins.bottom);
+}
+
void
intel_tv_init(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct intel_tv *intel_tv;
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
u32 tv_dac_on, tv_dac_off, save_tv_dac;
- const char *tv_format_names[ARRAY_SIZE(tv_modes)];
- int i, initial_mode = 0;
- struct drm_connector_state *state;
if ((intel_de_read(dev_priv, TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
return;
@@ -1937,7 +1977,6 @@ intel_tv_init(struct drm_i915_private *dev_priv)
intel_encoder = &intel_tv->base;
connector = &intel_connector->base;
- state = connector->state;
/*
* The documentation, for the older chipsets at least, recommend
@@ -1951,10 +1990,10 @@ intel_tv_init(struct drm_i915_private *dev_priv)
*/
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- drm_connector_init(dev, connector, &intel_tv_connector_funcs,
+ drm_connector_init(&dev_priv->drm, connector, &intel_tv_connector_funcs,
DRM_MODE_CONNECTOR_SVIDEO);
- drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
+ drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_tv_enc_funcs,
DRM_MODE_ENCODER_TVDAC, "TV");
intel_encoder->compute_config = intel_tv_compute_config;
@@ -1974,41 +2013,7 @@ intel_tv_init(struct drm_i915_private *dev_priv)
intel_encoder->cloneable = 0;
intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
- /* BIOS margin values */
- state->tv.margins.left = 54;
- state->tv.margins.top = 36;
- state->tv.margins.right = 46;
- state->tv.margins.bottom = 37;
-
- state->tv.mode = initial_mode;
-
drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
- /* Create TV properties then attach current values */
- for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
- /* 1080p50/1080p60 not supported on gen3 */
- if (DISPLAY_VER(dev_priv) == 3 &&
- tv_modes[i].oversample == 1)
- break;
-
- tv_format_names[i] = tv_modes[i].name;
- }
- drm_mode_create_tv_properties(dev, i, tv_format_names);
-
- drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
- state->tv.mode);
- drm_object_attach_property(&connector->base,
- dev->mode_config.tv_left_margin_property,
- state->tv.margins.left);
- drm_object_attach_property(&connector->base,
- dev->mode_config.tv_top_margin_property,
- state->tv.margins.top);
- drm_object_attach_property(&connector->base,
- dev->mode_config.tv_right_margin_property,
- state->tv.margins.right);
- drm_object_attach_property(&connector->base,
- dev->mode_config.tv_bottom_margin_property,
- state->tv.margins.bottom);
+ intel_tv_add_properties(connector);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index 269f9792390d..9d3b77b41b5c 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -10,6 +10,7 @@
#include <drm/display/drm_dsc_helper.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c
index b5d058404c14..a69bfcac9a94 100644
--- a/drivers/gpu/drm/i915/display/intel_vga.c
+++ b/drivers/gpu/drm/i915/display/intel_vga.c
@@ -10,6 +10,7 @@
#include <video/vga.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_vga.h"
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index 5eac99021875..7b1357e82b69 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -5,6 +5,7 @@
*/
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_vrr.h"
diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c
index 4092679be21e..d7390067b7d4 100644
--- a/drivers/gpu/drm/i915/display/skl_scaler.c
+++ b/drivers/gpu/drm/i915/display/skl_scaler.c
@@ -2,6 +2,8 @@
/*
* Copyright © 2020 Intel Corporation
*/
+
+#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_fb.h"
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 7cb713043408..76490cc59d8f 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -9,6 +9,8 @@
#include <drm/drm_fourcc.h>
#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_atomic_plane.h"
#include "intel_de.h"
#include "intel_display_types.h"
@@ -246,6 +248,11 @@ bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id);
}
+u8 icl_hdr_plane_mask(void)
+{
+ return BIT(PLANE_PRIMARY) | BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1);
+}
+
bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id)
{
return DISPLAY_VER(dev_priv) >= 11 &&
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h
index 351040b64dc7..be64c201f9b3 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.h
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h
@@ -30,6 +30,7 @@ int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
enum plane_id plane_id);
+u8 icl_hdr_plane_mask(void);
bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id);
#endif
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index 18178b01375e..e0766d1be966 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -1706,26 +1706,10 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state,
return -EINVAL;
}
- wp->y_tiled = modifier == I915_FORMAT_MOD_Y_TILED ||
- modifier == I915_FORMAT_MOD_4_TILED ||
- modifier == I915_FORMAT_MOD_Yf_TILED ||
- modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
- modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED;
- wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
- modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
- modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS ||
- modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
+ wp->y_tiled = modifier != I915_FORMAT_MOD_X_TILED &&
+ intel_fb_is_tiled_modifier(modifier);
+ wp->rc_surface = intel_fb_is_ccs_modifier(modifier);
wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier);
wp->width = width;
@@ -2498,7 +2482,7 @@ skl_compute_ddb(struct intel_atomic_state *state)
if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
/* TODO: Implement vblank synchronized MBUS joining changes */
- ret = intel_modeset_all_pipes(state);
+ ret = intel_modeset_all_pipes(state, "MBUS joining change");
if (ret)
return ret;
}
@@ -2760,7 +2744,7 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state,
* power well the hardware state will go out of sync
* with the software state.
*/
- if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) &&
+ if (!intel_crtc_needs_modeset(new_crtc_state) &&
skl_plane_selected_wm_equals(plane,
&old_crtc_state->wm.skl.optimal,
&new_crtc_state->wm.skl.optimal))
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index b3f5ca280ef2..84481030883a 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -31,6 +31,7 @@
#include <drm/drm_mipi_dsi.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_backlight.h"
#include "intel_connector.h"
@@ -1659,19 +1660,10 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
static void vlv_dsi_add_properties(struct intel_connector *connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
const struct drm_display_mode *fixed_mode =
intel_panel_preferred_fixed_mode(connector);
- u32 allowed_scalers;
- allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
- if (!HAS_GMCH(dev_priv))
- allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
-
- drm_connector_attach_scaling_mode_property(&connector->base,
- allowed_scalers);
-
- connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+ intel_attach_scaling_mode_property(&connector->base);
drm_connector_set_panel_orientation_with_quirk(&connector->base,
intel_dsi_get_panel_orientation(connector),
@@ -1854,7 +1846,6 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi)
void vlv_dsi_init(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_dsi *intel_dsi;
struct intel_encoder *intel_encoder;
struct drm_encoder *encoder;
@@ -1891,7 +1882,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
connector = &intel_connector->base;
- drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
+ drm_encoder_init(&dev_priv->drm, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
"DSI %c", port_name(port));
intel_encoder->compute_config = intel_dsi_compute_config;
@@ -1974,20 +1965,18 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_dsi_vbt_gpio_init(intel_dsi,
intel_dsi_get_hw_state(intel_encoder, &pipe));
- drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
+ drm_connector_init(&dev_priv->drm, connector, &intel_dsi_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
intel_connector_attach_encoder(intel_connector, intel_encoder);
- mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev_priv->drm.mode_config.mutex);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
- mutex_unlock(&dev->mode_config.mutex);
+ mutex_unlock(&dev_priv->drm.mode_config.mutex);
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
drm_dbg_kms(&dev_priv->drm, "no fixed mode\n");
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_regs.h b/drivers/gpu/drm/i915/display/vlv_dsi_regs.h
index e065b8f2ee08..abbe427e462e 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi_regs.h
+++ b/drivers/gpu/drm/i915/display/vlv_dsi_regs.h
@@ -6,7 +6,7 @@
#ifndef __VLV_DSI_REGS_H__
#define __VLV_DSI_REGS_H__
-#include "i915_reg_defs.h"
+#include "intel_display_reg_defs.h"
#define VLV_MIPI_BASE VLV_DISPLAY_BASE
#define BXT_MIPI_BASE 0x60000
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
index 0512afdd20d8..b3b398fe689c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
@@ -113,7 +113,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj,
clflush = clflush_work_create(obj);
if (clflush) {
i915_sw_fence_await_reservation(&clflush->base.chain,
- obj->base.resv, NULL, true,
+ obj->base.resv, true,
i915_fence_timeout(i915),
I915_FENCE_GFP);
dma_resv_add_fence(obj->base.resv, &clflush->base.dma,
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 1e29b1e6d186..7f2831efc798 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -546,7 +546,7 @@ set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
}
if (intel_engine_uses_guc(master)) {
- DRM_DEBUG("bonding extension not supported with GuC submission");
+ drm_dbg(&i915->drm, "bonding extension not supported with GuC submission");
return -ENODEV;
}
@@ -1452,7 +1452,7 @@ static void engines_idle_release(struct i915_gem_context *ctx,
int err;
/* serialises with execbuf */
- set_bit(CONTEXT_CLOSED_BIT, &ce->flags);
+ intel_context_close(ce);
if (!intel_context_pin_if_active(ce))
continue;
@@ -2298,7 +2298,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
}
args->ctx_id = id;
- drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id);
return 0;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index f5062d0c6333..fd556a076d05 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -25,43 +25,44 @@ static struct drm_i915_gem_object *dma_buf_to_obj(struct dma_buf *buf)
return to_intel_bo(buf->priv);
}
-static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
{
- struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
- struct sg_table *st;
+ struct drm_i915_gem_object *obj = dma_buf_to_obj(attach->dmabuf);
+ struct sg_table *sgt;
struct scatterlist *src, *dst;
int ret, i;
- /* Copy sg so that we make an independent mapping */
- st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (st == NULL) {
+ /*
+ * Make a copy of the object's sgt, so that we can make an independent
+ * mapping
+ */
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt) {
ret = -ENOMEM;
goto err;
}
- ret = sg_alloc_table(st, obj->mm.pages->nents, GFP_KERNEL);
+ ret = sg_alloc_table(sgt, obj->mm.pages->orig_nents, GFP_KERNEL);
if (ret)
goto err_free;
- src = obj->mm.pages->sgl;
- dst = st->sgl;
- for (i = 0; i < obj->mm.pages->nents; i++) {
+ dst = sgt->sgl;
+ for_each_sg(obj->mm.pages->sgl, src, obj->mm.pages->orig_nents, i) {
sg_set_page(dst, sg_page(src), src->length, 0);
dst = sg_next(dst);
- src = sg_next(src);
}
- ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC);
+ ret = dma_map_sgtable(attach->dev, sgt, dir, DMA_ATTR_SKIP_CPU_SYNC);
if (ret)
goto err_free_sg;
- return st;
+ return sgt;
err_free_sg:
- sg_free_table(st);
+ sg_free_table(sgt);
err_free:
- kfree(st);
+ kfree(sgt);
err:
return ERR_PTR(ret);
}
@@ -72,7 +73,7 @@ static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf,
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
void *vaddr;
- vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB);
+ vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
if (IS_ERR(vaddr))
return PTR_ERR(vaddr);
@@ -96,6 +97,8 @@ static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *
struct drm_i915_private *i915 = to_i915(obj->base.dev);
int ret;
+ dma_resv_assert_held(dma_buf->resv);
+
if (obj->base.size < vma->vm_end - vma->vm_start)
return -EINVAL;
@@ -236,15 +239,14 @@ struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags)
static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
- struct sg_table *pages;
- unsigned int sg_page_sizes;
+ struct sg_table *sgt;
assert_object_held(obj);
- pages = dma_buf_map_attachment(obj->base.import_attach,
- DMA_BIDIRECTIONAL);
- if (IS_ERR(pages))
- return PTR_ERR(pages);
+ sgt = dma_buf_map_attachment(obj->base.import_attach,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
/*
* DG1 is special here since it still snoops transactions even with
@@ -261,16 +263,15 @@ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
(!HAS_LLC(i915) && !IS_DG1(i915)))
wbinvd_on_all_cpus();
- sg_page_sizes = i915_sg_dma_sizes(pages->sgl);
- __i915_gem_object_set_pages(obj, pages, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, sgt);
return 0;
}
static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj,
- struct sg_table *pages)
+ struct sg_table *sgt)
{
- dma_buf_unmap_attachment(obj->base.import_attach, pages,
+ dma_buf_unmap_attachment(obj->base.import_attach, sgt,
DMA_BIDIRECTIONAL);
}
@@ -313,7 +314,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
get_dma_buf(dma_buf);
obj = i915_gem_object_alloc();
- if (obj == NULL) {
+ if (!obj) {
ret = -ENOMEM;
goto fail_detach;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 845023c14eb3..da09767fda07 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -30,6 +30,7 @@
#include "i915_gem_context.h"
#include "i915_gem_evict.h"
#include "i915_gem_ioctls.h"
+#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_user_extensions.h"
@@ -53,13 +54,13 @@ enum {
#define DBG_FORCE_RELOC 0 /* choose one of the above! */
};
-/* __EXEC_OBJECT_NO_RESERVE is BIT(31), defined in i915_vma.h */
-#define __EXEC_OBJECT_HAS_PIN BIT(30)
-#define __EXEC_OBJECT_HAS_FENCE BIT(29)
-#define __EXEC_OBJECT_USERPTR_INIT BIT(28)
-#define __EXEC_OBJECT_NEEDS_MAP BIT(27)
-#define __EXEC_OBJECT_NEEDS_BIAS BIT(26)
-#define __EXEC_OBJECT_INTERNAL_FLAGS (~0u << 26) /* all of the above + */
+/* __EXEC_OBJECT_ flags > BIT(29) defined in i915_vma.h */
+#define __EXEC_OBJECT_HAS_PIN BIT(29)
+#define __EXEC_OBJECT_HAS_FENCE BIT(28)
+#define __EXEC_OBJECT_USERPTR_INIT BIT(27)
+#define __EXEC_OBJECT_NEEDS_MAP BIT(26)
+#define __EXEC_OBJECT_NEEDS_BIAS BIT(25)
+#define __EXEC_OBJECT_INTERNAL_FLAGS (~0u << 25) /* all of the above + */
#define __EXEC_OBJECT_RESERVED (__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_FENCE)
#define __EXEC_HAS_RELOC BIT(31)
@@ -2101,7 +2102,8 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
eb->composite_fence ?
eb->composite_fence :
&eb->requests[j]->fence,
- flags | __EXEC_OBJECT_NO_RESERVE);
+ flags | __EXEC_OBJECT_NO_RESERVE |
+ __EXEC_OBJECT_NO_REQUEST_AWAIT);
}
}
@@ -2148,7 +2150,8 @@ err_skip:
return err;
}
-static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
+static int i915_gem_check_execbuffer(struct drm_i915_private *i915,
+ struct drm_i915_gem_execbuffer2 *exec)
{
if (exec->flags & __I915_EXEC_ILLEGAL_FLAGS)
return -EINVAL;
@@ -2161,7 +2164,7 @@ static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
}
if (exec->DR4 == 0xffffffff) {
- DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
+ drm_dbg(&i915->drm, "UXA submitting garbage DR4, fixing up\n");
exec->DR4 = 0;
}
if (exec->DR1 || exec->DR4)
@@ -2424,7 +2427,7 @@ gen8_dispatch_bsd_engine(struct drm_i915_private *dev_priv,
/* Check whether the file_priv has already selected one ring. */
if ((int)file_priv->bsd_engine < 0)
file_priv->bsd_engine =
- prandom_u32_max(num_vcs_engines(dev_priv));
+ get_random_u32_below(num_vcs_engines(dev_priv));
return file_priv->bsd_engine;
}
@@ -2799,7 +2802,8 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
syncobj = drm_syncobj_find(eb->file, user_fence.handle);
if (!syncobj) {
- DRM_DEBUG("Invalid syncobj handle provided\n");
+ drm_dbg(&eb->i915->drm,
+ "Invalid syncobj handle provided\n");
return -ENOENT;
}
@@ -2807,7 +2811,8 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
if (!fence && user_fence.flags &&
!(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) {
- DRM_DEBUG("Syncobj handle has no fence\n");
+ drm_dbg(&eb->i915->drm,
+ "Syncobj handle has no fence\n");
drm_syncobj_put(syncobj);
return -EINVAL;
}
@@ -2816,7 +2821,9 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
err = dma_fence_chain_find_seqno(&fence, point);
if (err && !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) {
- DRM_DEBUG("Syncobj handle missing requested point %llu\n", point);
+ drm_dbg(&eb->i915->drm,
+ "Syncobj handle missing requested point %llu\n",
+ point);
dma_fence_put(fence);
drm_syncobj_put(syncobj);
return err;
@@ -2842,7 +2849,8 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
* 0) would break the timeline.
*/
if (user_fence.flags & I915_EXEC_FENCE_WAIT) {
- DRM_DEBUG("Trying to wait & signal the same timeline point.\n");
+ drm_dbg(&eb->i915->drm,
+ "Trying to wait & signal the same timeline point.\n");
dma_fence_put(fence);
drm_syncobj_put(syncobj);
return -EINVAL;
@@ -2913,14 +2921,16 @@ static int add_fence_array(struct i915_execbuffer *eb)
syncobj = drm_syncobj_find(eb->file, user_fence.handle);
if (!syncobj) {
- DRM_DEBUG("Invalid syncobj handle provided\n");
+ drm_dbg(&eb->i915->drm,
+ "Invalid syncobj handle provided\n");
return -ENOENT;
}
if (user_fence.flags & I915_EXEC_FENCE_WAIT) {
fence = drm_syncobj_fence_get(syncobj);
if (!fence) {
- DRM_DEBUG("Syncobj handle has no fence\n");
+ drm_dbg(&eb->i915->drm,
+ "Syncobj handle has no fence\n");
drm_syncobj_put(syncobj);
return -EINVAL;
}
@@ -2954,11 +2964,6 @@ await_fence_array(struct i915_execbuffer *eb,
int err;
for (n = 0; n < eb->num_fences; n++) {
- struct drm_syncobj *syncobj;
- unsigned int flags;
-
- syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2);
-
if (!eb->fences[n].dma_fence)
continue;
@@ -3520,7 +3525,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- err = i915_gem_check_execbuffer(args);
+ err = i915_gem_check_execbuffer(i915, args);
if (err)
return err;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c
index 629acb403a2c..f66bcefc09ec 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c
@@ -35,7 +35,6 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct sg_table *st;
struct scatterlist *sg;
- unsigned int sg_page_sizes;
unsigned int npages;
int max_order = MAX_ORDER;
unsigned int max_segment;
@@ -64,7 +63,6 @@ create_st:
sg = st->sgl;
st->nents = 0;
- sg_page_sizes = 0;
do {
int order = min(fls(npages) - 1, max_order);
@@ -83,7 +81,6 @@ create_st:
} while (1);
sg_set_page(sg, page, PAGE_SIZE << order, 0);
- sg_page_sizes |= PAGE_SIZE << order;
st->nents++;
npages -= 1 << order;
@@ -105,7 +102,7 @@ create_st:
goto err;
}
- __i915_gem_object_set_pages(obj, st, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, st);
return 0;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
index 73d9eda1d6b7..c29efdef8313 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
@@ -330,7 +330,7 @@ retry:
if (ret)
goto err_rpm;
- ret = intel_gt_reset_trylock(ggtt->vm.gt, &srcu);
+ ret = intel_gt_reset_lock_interruptible(ggtt->vm.gt, &srcu);
if (ret)
goto err_pages;
@@ -413,7 +413,7 @@ retry:
vma->mmo = mmo;
if (CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)
- intel_wakeref_auto(&to_gt(i915)->userfault_wakeref,
+ intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref,
msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND));
if (write) {
@@ -557,11 +557,13 @@ void i915_gem_object_runtime_pm_release_mmap_offset(struct drm_i915_gem_object *
drm_vma_node_unmap(&bo->base.vma_node, bdev->dev_mapping);
- if (obj->userfault_count) {
- /* rpm wakeref provide exclusive access */
- list_del(&obj->userfault_link);
- obj->userfault_count = 0;
- }
+ /*
+ * We have exclusive access here via runtime suspend. All other callers
+ * must first grab the rpm wakeref.
+ */
+ GEM_BUG_ON(!obj->userfault_count);
+ list_del(&obj->userfault_link);
+ obj->userfault_count = 0;
}
void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj)
@@ -587,13 +589,6 @@ void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj)
spin_lock(&obj->mmo.lock);
}
spin_unlock(&obj->mmo.lock);
-
- if (obj->userfault_count) {
- mutex_lock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock);
- list_del(&obj->userfault_link);
- mutex_unlock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock);
- obj->userfault_count = 0;
- }
}
static struct i915_mmap_offset *
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index 369006c5317f..733696057761 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -290,7 +290,21 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
__i915_gem_object_free_mmaps(obj);
atomic_set(&obj->mm.pages_pin_count, 0);
+
+ /*
+ * dma_buf_unmap_attachment() requires reservation to be
+ * locked. The imported GEM shouldn't share reservation lock
+ * and ttm_bo_cleanup_memtype_use() shouldn't be invoked for
+ * dma-buf, so it's safe to take the lock.
+ */
+ if (obj->base.import_attach)
+ i915_gem_object_lock(obj, NULL);
+
__i915_gem_object_put_pages(obj);
+
+ if (obj->base.import_attach)
+ i915_gem_object_unlock(obj);
+
GEM_BUG_ON(i915_gem_object_has_pages(obj));
}
@@ -444,6 +458,16 @@ i915_gem_object_read_from_page_iomap(struct drm_i915_gem_object *obj, u64 offset
io_mapping_unmap(src_map);
}
+static bool object_has_mappable_iomem(struct drm_i915_gem_object *obj)
+{
+ GEM_BUG_ON(!i915_gem_object_has_iomem(obj));
+
+ if (IS_DGFX(to_i915(obj->base.dev)))
+ return i915_ttm_resource_mappable(i915_gem_to_ttm(obj)->resource);
+
+ return true;
+}
+
/**
* i915_gem_object_read_from_page - read data from the page of a GEM object
* @obj: GEM object to read from
@@ -466,7 +490,7 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset,
if (i915_gem_object_has_struct_page(obj))
i915_gem_object_read_from_page_kmap(obj, offset, dst, size);
- else if (i915_gem_object_has_iomem(obj))
+ else if (i915_gem_object_has_iomem(obj) && object_has_mappable_iomem(obj))
i915_gem_object_read_from_page_iomap(obj, offset, dst, size);
else
return -ENODEV;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 1723af9b0f6a..3db53769864c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -403,8 +403,7 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
unsigned long n);
void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
- struct sg_table *pages,
- unsigned int sg_page_sizes);
+ struct sg_table *pages);
int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
@@ -482,6 +481,10 @@ void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
void *__must_check i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj,
enum i915_map_type type);
+enum i915_map_type i915_coherent_map_type(struct drm_i915_private *i915,
+ struct drm_i915_gem_object *obj,
+ bool always_coherent);
+
void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj,
unsigned long offset,
unsigned long size);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index 4df50b049cea..05a27723ebb8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -16,8 +16,7 @@
#include "i915_gem_mman.h"
void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
- struct sg_table *pages,
- unsigned int sg_page_sizes)
+ struct sg_table *pages)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
unsigned long supported = RUNTIME_INFO(i915)->page_sizes;
@@ -45,8 +44,8 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
obj->mm.pages = pages;
- GEM_BUG_ON(!sg_page_sizes);
- obj->mm.page_sizes.phys = sg_page_sizes;
+ obj->mm.page_sizes.phys = i915_sg_dma_sizes(pages->sgl);
+ GEM_BUG_ON(!obj->mm.page_sizes.phys);
/*
* Calculate the supported page-sizes which fit into the given
@@ -466,6 +465,18 @@ void *i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj,
return ret;
}
+enum i915_map_type i915_coherent_map_type(struct drm_i915_private *i915,
+ struct drm_i915_gem_object *obj,
+ bool always_coherent)
+{
+ if (i915_gem_object_is_lmem(obj))
+ return I915_MAP_WC;
+ if (HAS_LLC(i915) || always_coherent)
+ return I915_MAP_WB;
+ else
+ return I915_MAP_WC;
+}
+
void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj,
unsigned long offset,
unsigned long size)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
index 0d0e46dae559..68453572275b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
@@ -79,7 +79,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
/* We're no longer struct page backed */
obj->mem_flags &= ~I915_BO_FLAG_STRUCT_PAGE;
- __i915_gem_object_set_pages(obj, st, sg->length);
+ __i915_gem_object_set_pages(obj, st);
return 0;
@@ -209,11 +209,8 @@ static int i915_gem_object_shmem_to_phys(struct drm_i915_gem_object *obj)
return 0;
err_xfer:
- if (!IS_ERR_OR_NULL(pages)) {
- unsigned int sg_page_sizes = i915_sg_dma_sizes(pages->sgl);
-
- __i915_gem_object_set_pages(obj, pages, sg_page_sizes);
- }
+ if (!IS_ERR_OR_NULL(pages))
+ __i915_gem_object_set_pages(obj, pages);
return err;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c
index 3428f735e786..0d812f4d787d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c
@@ -22,9 +22,12 @@
void i915_gem_suspend(struct drm_i915_private *i915)
{
+ struct intel_gt *gt;
+ unsigned int i;
+
GEM_TRACE("%s\n", dev_name(i915->drm.dev));
- intel_wakeref_auto(&to_gt(i915)->userfault_wakeref, 0);
+ intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, 0);
flush_workqueue(i915->wq);
/*
@@ -36,7 +39,8 @@ void i915_gem_suspend(struct drm_i915_private *i915)
* state. Fortunately, the kernel_context is disposable and we do
* not rely on its state.
*/
- intel_gt_suspend_prepare(to_gt(i915));
+ for_each_gt(gt, i915, i)
+ intel_gt_suspend_prepare(gt);
i915_gem_drain_freed_objects(i915);
}
@@ -131,7 +135,9 @@ void i915_gem_suspend_late(struct drm_i915_private *i915)
&i915->mm.purge_list,
NULL
}, **phase;
+ struct intel_gt *gt;
unsigned long flags;
+ unsigned int i;
bool flush = false;
/*
@@ -154,7 +160,8 @@ void i915_gem_suspend_late(struct drm_i915_private *i915)
* machine in an unusable condition.
*/
- intel_gt_suspend_late(to_gt(i915));
+ for_each_gt(gt, i915, i)
+ intel_gt_suspend_late(gt);
spin_lock_irqsave(&i915->mm.obj_lock, flags);
for (phase = phases; *phase; phase++) {
@@ -212,7 +219,8 @@ int i915_gem_freeze_late(struct drm_i915_private *i915)
void i915_gem_resume(struct drm_i915_private *i915)
{
- int ret;
+ struct intel_gt *gt;
+ int ret, i, j;
GEM_TRACE("%s\n", dev_name(i915->drm.dev));
@@ -224,8 +232,25 @@ void i915_gem_resume(struct drm_i915_private *i915)
* guarantee that the context image is complete. So let's just reset
* it and start again.
*/
- intel_gt_resume(to_gt(i915));
+ for_each_gt(gt, i915, i)
+ if (intel_gt_resume(gt))
+ goto err_wedged;
ret = lmem_restore(i915, I915_TTM_BACKUP_ALLOW_GPU);
GEM_WARN_ON(ret);
+
+ return;
+
+err_wedged:
+ for_each_gt(gt, i915, j) {
+ if (!intel_gt_is_wedged(gt)) {
+ dev_err(i915->drm.dev,
+ "Failed to re-initialize GPU[%u], declaring it wedged!\n",
+ j);
+ intel_gt_set_wedged(gt);
+ }
+
+ if (j == i)
+ break;
+ }
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 11125c32dd35..9c759df700ca 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -247,7 +247,7 @@ rebuild_st:
if (i915_gem_object_can_bypass_llc(obj))
obj->cache_dirty = true;
- __i915_gem_object_set_pages(obj, st, i915_sg_dma_sizes(st->sgl));
+ __i915_gem_object_set_pages(obj, st);
return 0;
@@ -369,14 +369,14 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj,
__start_cpu_write(obj);
/*
- * On non-LLC platforms, force the flush-on-acquire if this is ever
+ * On non-LLC igfx platforms, force the flush-on-acquire if this is ever
* swapped-in. Our async flush path is not trust worthy enough yet(and
* happens in the wrong order), and with some tricks it's conceivable
* for userspace to change the cache-level to I915_CACHE_NONE after the
* pages are swapped-in, and since execbuf binds the object before doing
* the async flush, we have a race window.
*/
- if (!HAS_LLC(i915))
+ if (!HAS_LLC(i915) && !IS_DGFX(i915))
obj->cache_dirty = true;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index acc561c0f0aa..bc9521078807 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -77,22 +77,26 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *i915,
mutex_unlock(&i915->mm.stolen_lock);
}
-static int i915_adjust_stolen(struct drm_i915_private *i915,
- struct resource *dsm)
+static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm)
+{
+ return (dsm->start != 0 || HAS_LMEMBAR_SMEM_STOLEN(i915)) && dsm->end > dsm->start;
+}
+
+static int adjust_stolen(struct drm_i915_private *i915,
+ struct resource *dsm)
{
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
struct intel_uncore *uncore = ggtt->vm.gt->uncore;
- struct resource *r;
- if (dsm->start == 0 || dsm->end <= dsm->start)
+ if (!valid_stolen_size(i915, dsm))
return -EINVAL;
/*
+ * Make sure we don't clobber the GTT if it's within stolen memory
+ *
* TODO: We have yet too encounter the case where the GTT wasn't at the
* end of stolen. With that assumption we could simplify this.
*/
-
- /* Make sure we don't clobber the GTT if it's within stolen memory */
if (GRAPHICS_VER(i915) <= 4 &&
!IS_G33(i915) && !IS_PINEVIEW(i915) && !IS_G4X(i915)) {
struct resource stolen[2] = {*dsm, *dsm};
@@ -131,12 +135,25 @@ static int i915_adjust_stolen(struct drm_i915_private *i915,
}
}
+ if (!valid_stolen_size(i915, dsm))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int request_smem_stolen(struct drm_i915_private *i915,
+ struct resource *dsm)
+{
+ struct resource *r;
+
/*
- * With stolen lmem, we don't need to check if the address range
- * overlaps with the non-stolen system memory range, since lmem is local
- * to the gpu.
+ * With stolen lmem, we don't need to request system memory for the
+ * address range since it's local to the gpu.
+ *
+ * Starting MTL, in IGFX devices the stolen memory is exposed via
+ * LMEMBAR and shall be considered similar to stolen lmem.
*/
- if (HAS_LMEM(i915))
+ if (HAS_LMEM(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915))
return 0;
/*
@@ -371,8 +388,6 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915,
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val);
- *base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK;
-
switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
case GEN8_STOLEN_RESERVED_1M:
*size = 1024 * 1024;
@@ -390,41 +405,30 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915,
*size = 8 * 1024 * 1024;
MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
}
+
+ if (HAS_LMEMBAR_SMEM_STOLEN(i915))
+ /* the base is initialized to stolen top so subtract size to get base */
+ *base -= *size;
+ else
+ *base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK;
}
-static int i915_gem_init_stolen(struct intel_memory_region *mem)
+/*
+ * Initialize i915->dsm_reserved to contain the reserved space within the Data
+ * Stolen Memory. This is a range on the top of DSM that is reserved, not to
+ * be used by driver, so must be excluded from the region passed to the
+ * allocator later. In the spec this is also called as WOPCM.
+ *
+ * Our expectation is that the reserved space is at the top of the stolen
+ * region, as it has been the case for every platform, and *never* at the
+ * bottom, so the calculation here can be simplified.
+ */
+static int init_reserved_stolen(struct drm_i915_private *i915)
{
- struct drm_i915_private *i915 = mem->i915;
struct intel_uncore *uncore = &i915->uncore;
resource_size_t reserved_base, stolen_top;
- resource_size_t reserved_total, reserved_size;
-
- mutex_init(&i915->mm.stolen_lock);
-
- if (intel_vgpu_active(i915)) {
- drm_notice(&i915->drm,
- "%s, disabling use of stolen memory\n",
- "iGVT-g active");
- return 0;
- }
-
- if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
- drm_notice(&i915->drm,
- "%s, disabling use of stolen memory\n",
- "DMAR active");
- return 0;
- }
-
- if (resource_size(&mem->region) == 0)
- return 0;
-
- i915->dsm = mem->region;
-
- if (i915_adjust_stolen(i915, &i915->dsm))
- return 0;
-
- GEM_BUG_ON(i915->dsm.start == 0);
- GEM_BUG_ON(i915->dsm.end <= i915->dsm.start);
+ resource_size_t reserved_size;
+ int ret = 0;
stolen_top = i915->dsm.end + 1;
reserved_base = stolen_top;
@@ -455,17 +459,16 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
&reserved_base, &reserved_size);
}
- /*
- * Our expectation is that the reserved space is at the top of the
- * stolen region and *never* at the bottom. If we see !reserved_base,
- * it likely means we failed to read the registers correctly.
- */
+ /* No reserved stolen */
+ if (reserved_base == stolen_top)
+ goto bail_out;
+
if (!reserved_base) {
drm_err(&i915->drm,
"inconsistent reservation %pa + %pa; ignoring\n",
&reserved_base, &reserved_size);
- reserved_base = stolen_top;
- reserved_size = 0;
+ ret = -EINVAL;
+ goto bail_out;
}
i915->dsm_reserved =
@@ -475,19 +478,55 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
drm_err(&i915->drm,
"Stolen reserved area %pR outside stolen memory %pR\n",
&i915->dsm_reserved, &i915->dsm);
- return 0;
+ ret = -EINVAL;
+ goto bail_out;
}
+ return 0;
+
+bail_out:
+ i915->dsm_reserved =
+ (struct resource)DEFINE_RES_MEM(reserved_base, 0);
+
+ return ret;
+}
+
+static int i915_gem_init_stolen(struct intel_memory_region *mem)
+{
+ struct drm_i915_private *i915 = mem->i915;
+
+ mutex_init(&i915->mm.stolen_lock);
+
+ if (intel_vgpu_active(i915)) {
+ drm_notice(&i915->drm,
+ "%s, disabling use of stolen memory\n",
+ "iGVT-g active");
+ return -ENOSPC;
+ }
+
+ if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
+ drm_notice(&i915->drm,
+ "%s, disabling use of stolen memory\n",
+ "DMAR active");
+ return -ENOSPC;
+ }
+
+ if (adjust_stolen(i915, &mem->region))
+ return -ENOSPC;
+
+ if (request_smem_stolen(i915, &mem->region))
+ return -ENOSPC;
+
+ i915->dsm = mem->region;
+
+ if (init_reserved_stolen(i915))
+ return -ENOSPC;
+
/* Exclude the reserved region from driver use */
- mem->region.end = reserved_base - 1;
+ mem->region.end = i915->dsm_reserved.start - 1;
mem->io_size = min(mem->io_size, resource_size(&mem->region));
- /* It is possible for the reserved area to end before the end of stolen
- * memory, so just consider the start. */
- reserved_total = stolen_top - reserved_base;
-
- i915->stolen_usable_size =
- resource_size(&i915->dsm) - reserved_total;
+ i915->stolen_usable_size = resource_size(&mem->region);
drm_dbg(&i915->drm,
"Memory reserved for graphics device: %lluK, usable: %lluK\n",
@@ -495,7 +534,7 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
(u64)i915->stolen_usable_size >> 10);
if (i915->stolen_usable_size == 0)
- return 0;
+ return -ENOSPC;
/* Basic memrange allocator for stolen space. */
drm_mm_init(&i915->mm.stolen, 0, i915->stolen_usable_size);
@@ -589,7 +628,7 @@ static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
sg_dma_len(pages->sgl),
POISON_INUSE);
- __i915_gem_object_set_pages(obj, pages, obj->stolen->size);
+ __i915_gem_object_set_pages(obj, pages);
return 0;
}
@@ -733,11 +772,17 @@ i915_gem_object_create_stolen(struct drm_i915_private *i915,
static int init_stolen_smem(struct intel_memory_region *mem)
{
+ int err;
+
/*
* Initialise stolen early so that we may reserve preallocated
* objects for the BIOS to KMS transition.
*/
- return i915_gem_init_stolen(mem);
+ err = i915_gem_init_stolen(mem);
+ if (err)
+ drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n");
+
+ return 0;
}
static int release_stolen_smem(struct intel_memory_region *mem)
@@ -754,26 +799,25 @@ static const struct intel_memory_region_ops i915_region_stolen_smem_ops = {
static int init_stolen_lmem(struct intel_memory_region *mem)
{
+ struct drm_i915_private *i915 = mem->i915;
int err;
if (GEM_WARN_ON(resource_size(&mem->region) == 0))
- return -ENODEV;
+ return 0;
- /*
- * TODO: For stolen lmem we mostly just care about populating the dsm
- * related bits and setting up the drm_mm allocator for the range.
- * Perhaps split up i915_gem_init_stolen() for this.
- */
err = i915_gem_init_stolen(mem);
- if (err)
- return err;
+ if (err) {
+ drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n");
+ return 0;
+ }
- if (mem->io_size && !io_mapping_init_wc(&mem->iomap,
- mem->io_start,
- mem->io_size)) {
- err = -EIO;
+ if (mem->io_size &&
+ !io_mapping_init_wc(&mem->iomap, mem->io_start, mem->io_size))
goto err_cleanup;
- }
+
+ drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n",
+ &mem->io_start);
+ drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &mem->region.start);
return 0;
@@ -796,6 +840,29 @@ static const struct intel_memory_region_ops i915_region_stolen_lmem_ops = {
.init_object = _i915_gem_object_stolen_init,
};
+static int mtl_get_gms_size(struct intel_uncore *uncore)
+{
+ u16 ggc, gms;
+
+ ggc = intel_uncore_read16(uncore, GGC);
+
+ /* check GGMS, should be fixed 0x3 (8MB) */
+ if ((ggc & GGMS_MASK) != GGMS_MASK)
+ return -EIO;
+
+ /* return valid GMS value, -EIO if invalid */
+ gms = REG_FIELD_GET(GMS_MASK, ggc);
+ switch (gms) {
+ case 0x0 ... 0x04:
+ return gms * 32;
+ case 0xf0 ... 0xfe:
+ return (gms - 0xf0 + 1) * 4;
+ default:
+ MISSING_CASE(gms);
+ return -EIO;
+ }
+}
+
struct intel_memory_region *
i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
u16 instance)
@@ -806,6 +873,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
struct intel_memory_region *mem;
resource_size_t io_start, io_size;
resource_size_t min_page_size;
+ int ret;
if (WARN_ON_ONCE(instance))
return ERR_PTR(-ENODEV);
@@ -813,12 +881,8 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
if (!i915_pci_resource_valid(pdev, GEN12_LMEM_BAR))
return ERR_PTR(-ENXIO);
- /* Use DSM base address instead for stolen memory */
- dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE);
- if (IS_DG1(uncore->i915)) {
+ if (HAS_LMEMBAR_SMEM_STOLEN(i915) || IS_DG1(i915)) {
lmem_size = pci_resource_len(pdev, GEN12_LMEM_BAR);
- if (WARN_ON(lmem_size < dsm_base))
- return ERR_PTR(-ENODEV);
} else {
resource_size_t lmem_range;
@@ -827,13 +891,39 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
lmem_size *= SZ_1G;
}
- dsm_size = lmem_size - dsm_base;
- if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) {
+ if (HAS_LMEMBAR_SMEM_STOLEN(i915)) {
+ /*
+ * MTL dsm size is in GGC register.
+ * Also MTL uses offset to DSMBASE in ptes, so i915
+ * uses dsm_base = 0 to setup stolen region.
+ */
+ ret = mtl_get_gms_size(uncore);
+ if (ret < 0) {
+ drm_err(&i915->drm, "invalid MTL GGC register setting\n");
+ return ERR_PTR(ret);
+ }
+
+ dsm_base = 0;
+ dsm_size = (resource_size_t)(ret * SZ_1M);
+
+ GEM_BUG_ON(pci_resource_len(pdev, GEN12_LMEM_BAR) != SZ_256M);
+ GEM_BUG_ON((dsm_size + SZ_8M) > lmem_size);
+ } else {
+ /* Use DSM base address instead for stolen memory */
+ dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK;
+ if (WARN_ON(lmem_size < dsm_base))
+ return ERR_PTR(-ENODEV);
+ dsm_size = lmem_size - dsm_base;
+ }
+
+ io_size = dsm_size;
+ if (HAS_LMEMBAR_SMEM_STOLEN(i915)) {
+ io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + SZ_8M;
+ } else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) {
io_start = 0;
io_size = 0;
} else {
io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + dsm_base;
- io_size = dsm_size;
}
min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K :
@@ -847,16 +937,6 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
if (IS_ERR(mem))
return mem;
- /*
- * TODO: consider creating common helper to just print all the
- * interesting stuff from intel_memory_region, which we can use for all
- * our probed regions.
- */
-
- drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n",
- &mem->io_start);
- drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &dsm_base);
-
intel_memory_region_set_name(mem, "stolen-local");
mem->private = true;
@@ -881,6 +961,7 @@ i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
intel_memory_region_set_name(mem, "stolen-system");
mem->private = true;
+
return mem;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index a4aa9500fa17..1e50fb0d6bfc 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -279,7 +279,7 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
struct i915_ttm_tt *i915_tt;
int ret;
- if (!obj)
+ if (i915_ttm_is_ghost_object(bo))
return NULL;
i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL);
@@ -362,7 +362,7 @@ static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo,
{
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
- if (!obj)
+ if (i915_ttm_is_ghost_object(bo))
return false;
/*
@@ -509,18 +509,9 @@ static int i915_ttm_shrink(struct drm_i915_gem_object *obj, unsigned int flags)
static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
{
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
- intel_wakeref_t wakeref = 0;
-
- if (bo->resource && likely(obj)) {
- /* ttm_bo_release() already has dma_resv_lock */
- if (i915_ttm_cpu_maps_iomem(bo->resource))
- wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm);
+ if (bo->resource && !i915_ttm_is_ghost_object(bo)) {
__i915_gem_object_pages_fini(obj);
-
- if (wakeref)
- intel_runtime_pm_put(&to_i915(obj->base.dev)->runtime_pm, wakeref);
-
i915_ttm_free_cached_io_rsgt(obj);
}
}
@@ -612,6 +603,10 @@ static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
WARN_ON_ONCE(obj->mm.madv == I915_MADV_WILLNEED);
+ err = ttm_bo_wait(bo, true, false);
+ if (err)
+ return err;
+
err = i915_ttm_move_notify(bo);
if (err)
return err;
@@ -624,7 +619,7 @@ static void i915_ttm_swap_notify(struct ttm_buffer_object *bo)
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
int ret;
- if (!obj)
+ if (i915_ttm_is_ghost_object(bo))
return;
ret = i915_ttm_move_notify(bo);
@@ -649,7 +644,7 @@ bool i915_ttm_resource_mappable(struct ttm_resource *res)
if (!i915_ttm_cpu_maps_iomem(res))
return true;
- return bman_res->used_visible_size == bman_res->base.num_pages;
+ return bman_res->used_visible_size == PFN_UP(bman_res->base.size);
}
static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem)
@@ -657,7 +652,7 @@ static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource
struct drm_i915_gem_object *obj = i915_ttm_to_gem(mem->bo);
bool unknown_state;
- if (!obj)
+ if (i915_ttm_is_ghost_object(mem->bo))
return -EINVAL;
if (!kref_get_unless_zero(&obj->base.refcount))
@@ -690,7 +685,7 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
unsigned long base;
unsigned int ofs;
- GEM_BUG_ON(!obj);
+ GEM_BUG_ON(i915_ttm_is_ghost_object(bo));
GEM_WARN_ON(bo->ttm);
base = obj->mm.region->iomap.base - obj->mm.region->region.start;
@@ -699,6 +694,50 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + ofs;
}
+static int i915_ttm_access_memory(struct ttm_buffer_object *bo,
+ unsigned long offset, void *buf,
+ int len, int write)
+{
+ struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
+ resource_size_t iomap = obj->mm.region->iomap.base -
+ obj->mm.region->region.start;
+ unsigned long page = offset >> PAGE_SHIFT;
+ unsigned long bytes_left = len;
+
+ /*
+ * TODO: For now just let it fail if the resource is non-mappable,
+ * otherwise we need to perform the memcpy from the gpu here, without
+ * interfering with the object (like moving the entire thing).
+ */
+ if (!i915_ttm_resource_mappable(bo->resource))
+ return -EIO;
+
+ offset -= page << PAGE_SHIFT;
+ do {
+ unsigned long bytes = min(bytes_left, PAGE_SIZE - offset);
+ void __iomem *ptr;
+ dma_addr_t daddr;
+
+ daddr = i915_gem_object_get_dma_address(obj, page);
+ ptr = ioremap_wc(iomap + daddr + offset, bytes);
+ if (!ptr)
+ return -EIO;
+
+ if (write)
+ memcpy_toio(ptr, buf, bytes);
+ else
+ memcpy_fromio(buf, ptr, bytes);
+ iounmap(ptr);
+
+ page++;
+ buf += bytes;
+ bytes_left -= bytes;
+ offset = 0;
+ } while (bytes_left);
+
+ return len;
+}
+
/*
* All callbacks need to take care not to downcast a struct ttm_buffer_object
* without checking its subclass, since it might be a TTM ghost object.
@@ -715,6 +754,7 @@ static struct ttm_device_funcs i915_ttm_bo_driver = {
.delete_mem_notify = i915_ttm_delete_mem_notify,
.io_mem_reserve = i915_ttm_io_mem_reserve,
.io_mem_pfn = i915_ttm_io_mem_pfn,
+ .access_memory = i915_ttm_access_memory,
};
/**
@@ -779,8 +819,7 @@ static int __i915_ttm_get_pages(struct drm_i915_gem_object *obj,
GEM_BUG_ON(obj->mm.rsgt);
obj->mm.rsgt = rsgt;
- __i915_gem_object_set_pages(obj, &rsgt->table,
- i915_sg_dma_sizes(rsgt->table.sgl));
+ __i915_gem_object_set_pages(obj, &rsgt->table);
}
GEM_BUG_ON(bo->ttm && ((obj->base.size >> PAGE_SHIFT) < bo->ttm->num_pages));
@@ -990,15 +1029,11 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
struct vm_area_struct *area = vmf->vma;
struct ttm_buffer_object *bo = area->vm_private_data;
struct drm_device *dev = bo->base.dev;
- struct drm_i915_gem_object *obj;
+ struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
intel_wakeref_t wakeref = 0;
vm_fault_t ret;
int idx;
- obj = i915_ttm_to_gem(bo);
- if (!obj)
- return VM_FAULT_SIGBUS;
-
/* Sanity check that we allow writing into this object */
if (unlikely(i915_gem_object_is_readonly(obj) &&
area->vm_flags & VM_WRITE))
@@ -1013,9 +1048,6 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
}
- if (i915_ttm_cpu_maps_iomem(bo->resource))
- wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm);
-
if (!i915_ttm_resource_mappable(bo->resource)) {
int err = -ENODEV;
int i;
@@ -1035,13 +1067,17 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
}
if (err) {
- drm_dbg(dev, "Unable to make resource CPU accessible\n");
+ drm_dbg(dev, "Unable to make resource CPU accessible(err = %pe)\n",
+ ERR_PTR(err));
dma_resv_unlock(bo->base.resv);
ret = VM_FAULT_SIGBUS;
goto out_rpm;
}
}
+ if (i915_ttm_cpu_maps_iomem(bo->resource))
+ wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm);
+
if (drm_dev_enter(dev, &idx)) {
ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
TTM_BO_VM_NUM_PREFAULT);
@@ -1053,16 +1089,21 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
goto out_rpm;
- /* ttm_bo_vm_reserve() already has dma_resv_lock */
+ /*
+ * ttm_bo_vm_reserve() already has dma_resv_lock.
+ * userfault_count is protected by dma_resv lock and rpm wakeref.
+ */
if (ret == VM_FAULT_NOPAGE && wakeref && !obj->userfault_count) {
obj->userfault_count = 1;
- mutex_lock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock);
- list_add(&obj->userfault_link, &to_gt(to_i915(obj->base.dev))->lmem_userfault_list);
- mutex_unlock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock);
+ spin_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock);
+ list_add(&obj->userfault_link, &to_i915(obj->base.dev)->runtime_pm.lmem_userfault_list);
+ spin_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock);
+
+ GEM_WARN_ON(!i915_ttm_cpu_maps_iomem(bo->resource));
}
if (wakeref & CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)
- intel_wakeref_auto(&to_gt(to_i915(obj->base.dev))->userfault_wakeref,
+ intel_wakeref_auto(&to_i915(obj->base.dev)->runtime_pm.userfault_wakeref,
msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND));
i915_ttm_adjust_lru(obj);
@@ -1094,7 +1135,7 @@ static void ttm_vm_open(struct vm_area_struct *vma)
struct drm_i915_gem_object *obj =
i915_ttm_to_gem(vma->vm_private_data);
- GEM_BUG_ON(!obj);
+ GEM_BUG_ON(i915_ttm_is_ghost_object(vma->vm_private_data));
i915_gem_object_get(obj);
}
@@ -1103,7 +1144,7 @@ static void ttm_vm_close(struct vm_area_struct *vma)
struct drm_i915_gem_object *obj =
i915_ttm_to_gem(vma->vm_private_data);
- GEM_BUG_ON(!obj);
+ GEM_BUG_ON(i915_ttm_is_ghost_object(vma->vm_private_data));
i915_gem_object_put(obj);
}
@@ -1124,7 +1165,29 @@ static u64 i915_ttm_mmap_offset(struct drm_i915_gem_object *obj)
static void i915_ttm_unmap_virtual(struct drm_i915_gem_object *obj)
{
+ struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+ intel_wakeref_t wakeref = 0;
+
+ assert_object_held_shared(obj);
+
+ if (i915_ttm_cpu_maps_iomem(bo->resource)) {
+ wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm);
+
+ /* userfault_count is protected by obj lock and rpm wakeref. */
+ if (obj->userfault_count) {
+ spin_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock);
+ list_del(&obj->userfault_link);
+ spin_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock);
+ obj->userfault_count = 0;
+ }
+ }
+
+ GEM_WARN_ON(obj->userfault_count);
+
ttm_bo_unmap_virtual(i915_gem_to_ttm(obj));
+
+ if (wakeref)
+ intel_runtime_pm_put(&to_i915(obj->base.dev)->runtime_pm, wakeref);
}
static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = {
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
index e4842b4296fc..2a94a99ef76b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h
@@ -28,18 +28,26 @@ i915_gem_to_ttm(struct drm_i915_gem_object *obj)
void i915_ttm_bo_destroy(struct ttm_buffer_object *bo);
/**
+ * i915_ttm_is_ghost_object - Check if the ttm bo is a ghost object.
+ * @bo: Pointer to the ttm buffer object
+ *
+ * Return: True if the ttm bo is not a i915 object but a ghost ttm object,
+ * False otherwise.
+ */
+static inline bool i915_ttm_is_ghost_object(struct ttm_buffer_object *bo)
+{
+ return bo->destroy != i915_ttm_bo_destroy;
+}
+
+/**
* i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding
* struct drm_i915_gem_object.
*
- * Return: Pointer to the embedding struct ttm_buffer_object, or NULL
- * if the object was not an i915 ttm object.
+ * Return: Pointer to the embedding struct ttm_buffer_object.
*/
static inline struct drm_i915_gem_object *
i915_ttm_to_gem(struct ttm_buffer_object *bo)
{
- if (bo->destroy != i915_ttm_bo_destroy)
- return NULL;
-
return container_of(bo, struct drm_i915_gem_object, __do_not_access);
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
index 9a7e50534b84..f59f812dc6d2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
@@ -560,7 +560,7 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
bool clear;
int ret;
- if (GEM_WARN_ON(!obj)) {
+ if (GEM_WARN_ON(i915_ttm_is_ghost_object(bo))) {
ttm_bo_move_null(bo, dst_mem);
return 0;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
index f34e01a7fefb..9348b1804d53 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
@@ -131,7 +131,6 @@ static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
unsigned int max_segment = i915_sg_segment_size(obj->base.dev->dev);
struct sg_table *st;
- unsigned int sg_page_sizes;
struct page **pvec;
int ret;
@@ -170,8 +169,7 @@ alloc_table:
if (i915_gem_object_can_bypass_llc(obj))
obj->cache_dirty = true;
- sg_page_sizes = i915_sg_dma_sizes(st->sgl);
- __i915_gem_object_set_pages(obj, st, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, st);
return 0;
@@ -292,7 +290,7 @@ int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj)
if (!i915_gem_object_is_readonly(obj))
gup_flags |= FOLL_WRITE;
- pinned = ret = 0;
+ pinned = 0;
while (pinned < num_pages) {
ret = pin_user_pages_fast(obj->userptr.ptr + pinned * PAGE_SIZE,
num_pages - pinned, gup_flags,
@@ -302,7 +300,6 @@ int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj)
pinned += ret;
}
- ret = 0;
ret = i915_gem_object_lock_interruptible(obj, NULL);
if (ret)
@@ -428,9 +425,10 @@ probe_range(struct mm_struct *mm, unsigned long addr, unsigned long len)
{
VMA_ITERATOR(vmi, mm, addr);
struct vm_area_struct *vma;
+ unsigned long end = addr + len;
mmap_read_lock(mm);
- for_each_vma_range(vmi, vma, addr + len) {
+ for_each_vma_range(vmi, vma, end) {
/* Check for holes, note that we also update the addr below */
if (vma->vm_start > addr)
break;
@@ -442,7 +440,7 @@ probe_range(struct mm_struct *mm, unsigned long addr, unsigned long len)
}
mmap_read_unlock(mm);
- if (vma)
+ if (vma || addr < end)
return -EFAULT;
return 0;
}
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c b/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
index f963b8e1e37b..cbd9b624a788 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
@@ -68,7 +68,7 @@ static int huge_get_pages(struct drm_i915_gem_object *obj)
if (i915_gem_gtt_prepare_pages(obj, pages))
goto err;
- __i915_gem_object_set_pages(obj, pages, PAGE_SIZE);
+ __i915_gem_object_set_pages(obj, pages);
return 0;
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
index c570cf780079..beaf27e09e8a 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
@@ -136,7 +136,7 @@ static int get_huge_pages(struct drm_i915_gem_object *obj)
goto err;
GEM_BUG_ON(sg_page_sizes != obj->mm.page_mask);
- __i915_gem_object_set_pages(obj, st, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, st);
return 0;
@@ -210,7 +210,6 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
const u64 max_len = rounddown_pow_of_two(UINT_MAX);
struct sg_table *st;
struct scatterlist *sg;
- unsigned int sg_page_sizes;
u64 rem;
st = kmalloc(sizeof(*st), GFP);
@@ -226,7 +225,6 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
rem = obj->base.size;
sg = st->sgl;
st->nents = 0;
- sg_page_sizes = 0;
do {
unsigned int page_size = get_largest_page_size(i915, rem);
unsigned int len = min(page_size * div_u64(rem, page_size),
@@ -239,8 +237,6 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
sg_dma_len(sg) = len;
sg_dma_address(sg) = page_size;
- sg_page_sizes |= len;
-
st->nents++;
rem -= len;
@@ -254,7 +250,7 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
i915_sg_trim(st);
- __i915_gem_object_set_pages(obj, st, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, st);
return 0;
}
@@ -286,7 +282,7 @@ static int fake_get_huge_pages_single(struct drm_i915_gem_object *obj)
sg_dma_len(sg) = obj->base.size;
sg_dma_address(sg) = page_size;
- __i915_gem_object_set_pages(obj, st, sg->length);
+ __i915_gem_object_set_pages(obj, st);
return 0;
#undef GFP
@@ -1161,7 +1157,8 @@ static int igt_write_huge(struct drm_i915_private *i915,
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
size = obj->base.size;
- if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K)
+ if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
+ !HAS_64K_PAGES(i915))
size = round_up(size, I915_GTT_PAGE_SIZE_2M);
n = 0;
@@ -1214,6 +1211,10 @@ static int igt_write_huge(struct drm_i915_private *i915,
* size and ensure the vma offset is at the start of the pt
* boundary, however to improve coverage we opt for testing both
* aligned and unaligned offsets.
+ *
+ * With PS64 this is no longer the case, but to ensure we
+ * sometimes get the compact layout for smaller objects, apply
+ * the round_up anyway.
*/
if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K)
offset_low = round_down(offset_low,
@@ -1411,6 +1412,7 @@ static int igt_ppgtt_sanity_check(void *arg)
{ SZ_2M + SZ_4K, SZ_64K | SZ_4K },
{ SZ_2M + SZ_4K, SZ_2M | SZ_4K },
{ SZ_2M + SZ_64K, SZ_2M | SZ_64K },
+ { SZ_2M + SZ_64K, SZ_64K },
};
int i, j;
int err;
@@ -1540,6 +1542,154 @@ out_put:
return err;
}
+static int igt_ppgtt_mixed(void *arg)
+{
+ struct drm_i915_private *i915 = arg;
+ const unsigned long flags = PIN_OFFSET_FIXED | PIN_USER;
+ struct drm_i915_gem_object *obj, *on;
+ struct i915_gem_engines *engines;
+ struct i915_gem_engines_iter it;
+ struct i915_address_space *vm;
+ struct i915_gem_context *ctx;
+ struct intel_context *ce;
+ struct file *file;
+ I915_RND_STATE(prng);
+ LIST_HEAD(objects);
+ struct intel_memory_region *mr;
+ struct i915_vma *vma;
+ unsigned int count;
+ u32 i, addr;
+ int *order;
+ int n, err;
+
+ /*
+ * Sanity check mixing 4K and 64K pages within the same page-table via
+ * the new PS64 TLB hint.
+ */
+
+ if (!HAS_64K_PAGES(i915)) {
+ pr_info("device lacks PS64, skipping\n");
+ return 0;
+ }
+
+ file = mock_file(i915);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ ctx = hugepage_ctx(i915, file);
+ if (IS_ERR(ctx)) {
+ err = PTR_ERR(ctx);
+ goto out;
+ }
+ vm = i915_gem_context_get_eb_vm(ctx);
+
+ i = 0;
+ addr = 0;
+ do {
+ u32 sz;
+
+ sz = i915_prandom_u32_max_state(SZ_4M, &prng);
+ sz = max_t(u32, sz, SZ_4K);
+
+ mr = i915->mm.regions[INTEL_REGION_LMEM_0];
+ if (i & 1)
+ mr = i915->mm.regions[INTEL_REGION_SMEM];
+
+ obj = i915_gem_object_create_region(mr, sz, 0, 0);
+ if (IS_ERR(obj)) {
+ err = PTR_ERR(obj);
+ goto out_vm;
+ }
+
+ list_add_tail(&obj->st_link, &objects);
+
+ vma = i915_vma_instance(obj, vm, NULL);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ goto err_put;
+ }
+
+ addr = round_up(addr, mr->min_page_size);
+ err = i915_vma_pin(vma, 0, 0, addr | flags);
+ if (err)
+ goto err_put;
+
+ if (mr->type == INTEL_MEMORY_LOCAL &&
+ (vma->resource->page_sizes_gtt & I915_GTT_PAGE_SIZE_4K)) {
+ err = -EINVAL;
+ goto err_put;
+ }
+
+ addr += obj->base.size;
+ i++;
+ } while (addr <= SZ_16M);
+
+ n = 0;
+ count = 0;
+ for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
+ count++;
+ if (!intel_engine_can_store_dword(ce->engine))
+ continue;
+
+ n++;
+ }
+ i915_gem_context_unlock_engines(ctx);
+ if (!n)
+ goto err_put;
+
+ order = i915_random_order(count * count, &prng);
+ if (!order) {
+ err = -ENOMEM;
+ goto err_put;
+ }
+
+ i = 0;
+ addr = 0;
+ engines = i915_gem_context_lock_engines(ctx);
+ list_for_each_entry(obj, &objects, st_link) {
+ u32 rnd = i915_prandom_u32_max_state(UINT_MAX, &prng);
+
+ addr = round_up(addr, obj->mm.region->min_page_size);
+
+ ce = engines->engines[order[i] % engines->num_engines];
+ i = (i + 1) % (count * count);
+ if (!ce || !intel_engine_can_store_dword(ce->engine))
+ continue;
+
+ err = __igt_write_huge(ce, obj, obj->base.size, addr, 0, rnd);
+ if (err)
+ break;
+
+ err = __igt_write_huge(ce, obj, obj->base.size, addr,
+ offset_in_page(rnd) / sizeof(u32), rnd + 1);
+ if (err)
+ break;
+
+ err = __igt_write_huge(ce, obj, obj->base.size, addr,
+ (PAGE_SIZE / sizeof(u32)) - 1,
+ rnd + 2);
+ if (err)
+ break;
+
+ addr += obj->base.size;
+
+ cond_resched();
+ }
+
+ i915_gem_context_unlock_engines(ctx);
+ kfree(order);
+err_put:
+ list_for_each_entry_safe(obj, on, &objects, st_link) {
+ list_del(&obj->st_link);
+ i915_gem_object_put(obj);
+ }
+out_vm:
+ i915_vm_put(vm);
+out:
+ fput(file);
+ return err;
+}
+
static int igt_tmpfs_fallback(void *arg)
{
struct drm_i915_private *i915 = arg;
@@ -1803,6 +1953,7 @@ int i915_gem_huge_page_live_selftests(struct drm_i915_private *i915)
SUBTEST(igt_ppgtt_smoke_huge),
SUBTEST(igt_ppgtt_sanity_check),
SUBTEST(igt_ppgtt_compact),
+ SUBTEST(igt_ppgtt_mixed),
};
if (!HAS_PPGTT(i915)) {
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
index 9a6a6b5b722b..692a16914ca0 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
@@ -13,6 +13,7 @@
#include "gt/intel_gt_regs.h"
#include "gem/i915_gem_lmem.h"
+#include "gem/selftests/igt_gem_utils.h"
#include "selftests/igt_flush_test.h"
#include "selftests/mock_drm.h"
#include "selftests/i915_random.h"
@@ -457,21 +458,6 @@ static int verify_buffer(const struct tiled_blits *t,
return ret;
}
-static int move_to_active(struct i915_vma *vma,
- struct i915_request *rq,
- unsigned int flags)
-{
- int err;
-
- i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, flags);
- i915_vma_unlock(vma);
-
- return err;
-}
-
static int pin_buffer(struct i915_vma *vma, u64 addr)
{
int err;
@@ -525,11 +511,11 @@ tiled_blit(struct tiled_blits *t,
goto err_bb;
}
- err = move_to_active(t->batch, rq, 0);
+ err = igt_vma_move_to_active_unlocked(t->batch, rq, 0);
if (!err)
- err = move_to_active(src->vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(src->vma, rq, 0);
if (!err)
- err = move_to_active(dst->vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(dst->vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
t->batch->node.start,
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
index a666d7e610f5..c228fe4aba50 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
@@ -239,9 +239,7 @@ static int gpu_set(struct context *ctx, unsigned long offset, u32 v)
}
intel_ring_advance(rq, cs);
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
out_rq:
i915_request_add(rq);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index c6ad67b90e8a..a0ff51d71d07 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -179,97 +179,108 @@ out_file:
}
struct parallel_switch {
- struct task_struct *tsk;
+ struct kthread_worker *worker;
+ struct kthread_work work;
struct intel_context *ce[2];
+ int result;
};
-static int __live_parallel_switch1(void *data)
+static void __live_parallel_switch1(struct kthread_work *work)
{
- struct parallel_switch *arg = data;
+ struct parallel_switch *arg =
+ container_of(work, typeof(*arg), work);
IGT_TIMEOUT(end_time);
unsigned long count;
count = 0;
+ arg->result = 0;
do {
struct i915_request *rq = NULL;
- int err, n;
+ int n;
- err = 0;
- for (n = 0; !err && n < ARRAY_SIZE(arg->ce); n++) {
+ for (n = 0; !arg->result && n < ARRAY_SIZE(arg->ce); n++) {
struct i915_request *prev = rq;
rq = i915_request_create(arg->ce[n]);
if (IS_ERR(rq)) {
i915_request_put(prev);
- return PTR_ERR(rq);
+ arg->result = PTR_ERR(rq);
+ break;
}
i915_request_get(rq);
if (prev) {
- err = i915_request_await_dma_fence(rq, &prev->fence);
+ arg->result =
+ i915_request_await_dma_fence(rq,
+ &prev->fence);
i915_request_put(prev);
}
i915_request_add(rq);
}
+
+ if (IS_ERR_OR_NULL(rq))
+ break;
+
if (i915_request_wait(rq, 0, HZ) < 0)
- err = -ETIME;
+ arg->result = -ETIME;
+
i915_request_put(rq);
- if (err)
- return err;
count++;
- } while (!__igt_timeout(end_time, NULL));
+ } while (!arg->result && !__igt_timeout(end_time, NULL));
- pr_info("%s: %lu switches (sync)\n", arg->ce[0]->engine->name, count);
- return 0;
+ pr_info("%s: %lu switches (sync) <%d>\n",
+ arg->ce[0]->engine->name, count, arg->result);
}
-static int __live_parallel_switchN(void *data)
+static void __live_parallel_switchN(struct kthread_work *work)
{
- struct parallel_switch *arg = data;
+ struct parallel_switch *arg =
+ container_of(work, typeof(*arg), work);
struct i915_request *rq = NULL;
IGT_TIMEOUT(end_time);
unsigned long count;
int n;
count = 0;
+ arg->result = 0;
do {
- for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
+ for (n = 0; !arg->result && n < ARRAY_SIZE(arg->ce); n++) {
struct i915_request *prev = rq;
- int err = 0;
rq = i915_request_create(arg->ce[n]);
if (IS_ERR(rq)) {
i915_request_put(prev);
- return PTR_ERR(rq);
+ arg->result = PTR_ERR(rq);
+ break;
}
i915_request_get(rq);
if (prev) {
- err = i915_request_await_dma_fence(rq, &prev->fence);
+ arg->result =
+ i915_request_await_dma_fence(rq,
+ &prev->fence);
i915_request_put(prev);
}
i915_request_add(rq);
- if (err) {
- i915_request_put(rq);
- return err;
- }
}
count++;
- } while (!__igt_timeout(end_time, NULL));
- i915_request_put(rq);
+ } while (!arg->result && !__igt_timeout(end_time, NULL));
- pr_info("%s: %lu switches (many)\n", arg->ce[0]->engine->name, count);
- return 0;
+ if (!IS_ERR_OR_NULL(rq))
+ i915_request_put(rq);
+
+ pr_info("%s: %lu switches (many) <%d>\n",
+ arg->ce[0]->engine->name, count, arg->result);
}
static int live_parallel_switch(void *arg)
{
struct drm_i915_private *i915 = arg;
- static int (* const func[])(void *arg) = {
+ static void (* const func[])(struct kthread_work *) = {
__live_parallel_switch1,
__live_parallel_switchN,
NULL,
@@ -277,7 +288,7 @@ static int live_parallel_switch(void *arg)
struct parallel_switch *data = NULL;
struct i915_gem_engines *engines;
struct i915_gem_engines_iter it;
- int (* const *fn)(void *arg);
+ void (* const *fn)(struct kthread_work *);
struct i915_gem_context *ctx;
struct intel_context *ce;
struct file *file;
@@ -348,9 +359,22 @@ static int live_parallel_switch(void *arg)
}
}
+ for (n = 0; n < count; n++) {
+ struct kthread_worker *worker;
+
+ if (!data[n].ce[0])
+ continue;
+
+ worker = kthread_create_worker(0, "igt/parallel:%s",
+ data[n].ce[0]->engine->name);
+ if (IS_ERR(worker))
+ goto out;
+
+ data[n].worker = worker;
+ }
+
for (fn = func; !err && *fn; fn++) {
struct igt_live_test t;
- int n;
err = igt_live_test_begin(&t, i915, __func__, "");
if (err)
@@ -360,30 +384,17 @@ static int live_parallel_switch(void *arg)
if (!data[n].ce[0])
continue;
- data[n].tsk = kthread_run(*fn, &data[n],
- "igt/parallel:%s",
- data[n].ce[0]->engine->name);
- if (IS_ERR(data[n].tsk)) {
- err = PTR_ERR(data[n].tsk);
- break;
- }
- get_task_struct(data[n].tsk);
+ data[n].result = 0;
+ kthread_init_work(&data[n].work, *fn);
+ kthread_queue_work(data[n].worker, &data[n].work);
}
- yield(); /* start all threads before we kthread_stop() */
-
for (n = 0; n < count; n++) {
- int status;
-
- if (IS_ERR_OR_NULL(data[n].tsk))
- continue;
-
- status = kthread_stop(data[n].tsk);
- if (status && !err)
- err = status;
-
- put_task_struct(data[n].tsk);
- data[n].tsk = NULL;
+ if (data[n].ce[0]) {
+ kthread_flush_work(&data[n].work);
+ if (data[n].result && !err)
+ err = data[n].result;
+ }
}
if (igt_live_test_end(&t))
@@ -399,6 +410,9 @@ out:
intel_context_unpin(data[n].ce[m]);
intel_context_put(data[n].ce[m]);
}
+
+ if (data[n].worker)
+ kthread_destroy_worker(data[n].worker);
}
kfree(data);
out_file:
@@ -970,15 +984,11 @@ retry:
goto err_batch;
}
- err = i915_request_await_object(rq, batch->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(batch, rq, 0);
+ err = i915_vma_move_to_active(batch, rq, 0);
if (err)
goto skip_request;
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
if (err)
goto skip_request;
@@ -1539,9 +1549,7 @@ static int write_to_scratch(struct i915_gem_context *ctx,
}
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
i915_vma_unlock(vma);
if (err)
goto skip_request;
@@ -1675,9 +1683,7 @@ static int read_from_scratch(struct i915_gem_context *ctx,
}
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(vma);
if (err)
goto skip_request;
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
index 51ed824b020c..e57f9390076c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c
@@ -6,8 +6,12 @@
#include "i915_drv.h"
#include "i915_selftest.h"
+#include "gem/i915_gem_context.h"
+#include "mock_context.h"
#include "mock_dmabuf.h"
+#include "igt_gem_utils.h"
+#include "selftests/mock_drm.h"
#include "selftests/mock_gem_device.h"
static int igt_dmabuf_export(void *arg)
@@ -140,6 +144,75 @@ out_ret:
return err;
}
+static int verify_access(struct drm_i915_private *i915,
+ struct drm_i915_gem_object *native_obj,
+ struct drm_i915_gem_object *import_obj)
+{
+ struct i915_gem_engines_iter it;
+ struct i915_gem_context *ctx;
+ struct intel_context *ce;
+ struct i915_vma *vma;
+ struct file *file;
+ u32 *vaddr;
+ int err = 0, i;
+
+ file = mock_file(i915);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ ctx = live_context(i915, file);
+ if (IS_ERR(ctx)) {
+ err = PTR_ERR(ctx);
+ goto out_file;
+ }
+
+ for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
+ if (intel_engine_can_store_dword(ce->engine))
+ break;
+ }
+ i915_gem_context_unlock_engines(ctx);
+ if (!ce)
+ goto out_file;
+
+ vma = i915_vma_instance(import_obj, ce->vm, NULL);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ goto out_file;
+ }
+
+ err = i915_vma_pin(vma, 0, 0, PIN_USER);
+ if (err)
+ goto out_file;
+
+ err = igt_gpu_fill_dw(ce, vma, 0,
+ vma->size >> PAGE_SHIFT, 0xdeadbeaf);
+ i915_vma_unpin(vma);
+ if (err)
+ goto out_file;
+
+ err = i915_gem_object_wait(import_obj, 0, MAX_SCHEDULE_TIMEOUT);
+ if (err)
+ goto out_file;
+
+ vaddr = i915_gem_object_pin_map_unlocked(native_obj, I915_MAP_WB);
+ if (IS_ERR(vaddr)) {
+ err = PTR_ERR(vaddr);
+ goto out_file;
+ }
+
+ for (i = 0; i < native_obj->base.size / sizeof(u32); i += PAGE_SIZE / sizeof(u32)) {
+ if (vaddr[i] != 0xdeadbeaf) {
+ pr_err("Data mismatch [%d]=%u\n", i, vaddr[i]);
+ err = -EINVAL;
+ goto out_file;
+ }
+ }
+
+out_file:
+ fput(file);
+ return err;
+}
+
static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
struct intel_memory_region **regions,
unsigned int num_regions)
@@ -154,7 +227,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
force_different_devices = true;
- obj = __i915_gem_object_create_user(i915, PAGE_SIZE,
+ obj = __i915_gem_object_create_user(i915, SZ_8M,
regions, num_regions);
if (IS_ERR(obj)) {
pr_err("__i915_gem_object_create_user failed with err=%ld\n",
@@ -206,6 +279,10 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
i915_gem_object_unlock(import_obj);
+ err = verify_access(i915, obj, import_obj);
+ if (err)
+ goto out_import;
+
/* Now try a fake an importer */
import_attach = dma_buf_attach(dmabuf, obj->base.dev->dev);
if (IS_ERR(import_attach)) {
@@ -213,7 +290,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
goto out_import;
}
- st = dma_buf_map_attachment(import_attach, DMA_BIDIRECTIONAL);
+ st = dma_buf_map_attachment_unlocked(import_attach, DMA_BIDIRECTIONAL);
if (IS_ERR(st)) {
err = PTR_ERR(st);
goto out_detach;
@@ -226,7 +303,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
timeout = -ETIME;
}
err = timeout > 0 ? 0 : timeout;
- dma_buf_unmap_attachment(import_attach, st, DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(import_attach, st, DMA_BIDIRECTIONAL);
out_detach:
dma_buf_detach(dmabuf, import_attach);
out_import:
@@ -296,7 +373,7 @@ static int igt_dmabuf_import(void *arg)
goto out_obj;
}
- err = dma_buf_vmap(dmabuf, &map);
+ err = dma_buf_vmap_unlocked(dmabuf, &map);
dma_map = err ? NULL : map.vaddr;
if (!dma_map) {
pr_err("dma_buf_vmap failed\n");
@@ -337,7 +414,7 @@ static int igt_dmabuf_import(void *arg)
err = 0;
out_dma_map:
- dma_buf_vunmap(dmabuf, &map);
+ dma_buf_vunmap_unlocked(dmabuf, &map);
out_obj:
i915_gem_object_put(obj);
out_dmabuf:
@@ -358,7 +435,7 @@ static int igt_dmabuf_import_ownership(void *arg)
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
- err = dma_buf_vmap(dmabuf, &map);
+ err = dma_buf_vmap_unlocked(dmabuf, &map);
ptr = err ? NULL : map.vaddr;
if (!ptr) {
pr_err("dma_buf_vmap failed\n");
@@ -367,7 +444,7 @@ static int igt_dmabuf_import_ownership(void *arg)
}
memset(ptr, 0xc5, PAGE_SIZE);
- dma_buf_vunmap(dmabuf, &map);
+ dma_buf_vunmap_unlocked(dmabuf, &map);
obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
if (IS_ERR(obj)) {
@@ -418,7 +495,7 @@ static int igt_dmabuf_export_vmap(void *arg)
}
i915_gem_object_put(obj);
- err = dma_buf_vmap(dmabuf, &map);
+ err = dma_buf_vmap_unlocked(dmabuf, &map);
ptr = err ? NULL : map.vaddr;
if (!ptr) {
pr_err("dma_buf_vmap failed\n");
@@ -435,7 +512,7 @@ static int igt_dmabuf_export_vmap(void *arg)
memset(ptr, 0xc5, dmabuf->size);
err = 0;
- dma_buf_vunmap(dmabuf, &map);
+ dma_buf_vunmap_unlocked(dmabuf, &map);
out:
dma_buf_put(dmabuf);
return err;
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index b73c91aa5450..3f658d5717d8 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -8,6 +8,7 @@
#include <linux/prime_numbers.h>
#include "gem/i915_gem_internal.h"
+#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "gem/i915_gem_ttm.h"
#include "gem/i915_gem_ttm_move.h"
@@ -16,6 +17,7 @@
#include "gt/intel_gt.h"
#include "gt/intel_gt_pm.h"
#include "gt/intel_migrate.h"
+#include "i915_reg.h"
#include "i915_ttm_buddy_manager.h"
#include "huge_gem_object.h"
@@ -564,10 +566,8 @@ retry:
goto err_unpin;
}
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq,
- EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq,
+ EXEC_OBJECT_WRITE);
i915_request_add(rq);
err_unpin:
@@ -1607,9 +1607,7 @@ retry:
goto out_unpin;
}
- err = i915_request_await_object(rq, vma->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
err = engine->emit_bb_start(rq, vma->node.start, 0, 0);
i915_request_get(rq);
diff --git a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
index 3c55e77b0f1b..374b10ac430e 100644
--- a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
+++ b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
@@ -131,17 +131,13 @@ int igt_gpu_fill_dw(struct intel_context *ce,
}
i915_vma_lock(batch);
- err = i915_request_await_object(rq, batch->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(batch, rq, 0);
+ err = i915_vma_move_to_active(batch, rq, 0);
i915_vma_unlock(batch);
if (err)
goto skip_request;
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(vma);
if (err)
goto skip_request;
diff --git a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
index 4221cf84d175..1379fbc14431 100644
--- a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
+++ b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
@@ -9,6 +9,8 @@
#include <linux/types.h>
+#include "i915_vma.h"
+
struct i915_request;
struct i915_gem_context;
struct i915_vma;
@@ -29,4 +31,16 @@ int igt_gpu_fill_dw(struct intel_context *ce,
struct i915_vma *vma, u64 offset,
unsigned long count, u32 val);
+static inline int __must_check
+igt_vma_move_to_active_unlocked(struct i915_vma *vma, struct i915_request *rq,
+ unsigned int flags)
+{
+ int err;
+
+ i915_vma_lock(vma);
+ err = _i915_vma_move_to_active(vma, rq, &rq->fence, flags);
+ i915_vma_unlock(vma);
+ return err;
+}
+
#endif /* __IGT_GEM_UTILS_H__ */
diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c
index e49fa6fa6aee..e1c76e5bfa82 100644
--- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c
@@ -396,15 +396,17 @@ int gen8_emit_init_breadcrumb(struct i915_request *rq)
return 0;
}
-static int __gen125_emit_bb_start(struct i915_request *rq,
- u64 offset, u32 len,
- const unsigned int flags,
- u32 arb)
+static int __xehp_emit_bb_start(struct i915_request *rq,
+ u64 offset, u32 len,
+ const unsigned int flags,
+ u32 arb)
{
struct intel_context *ce = rq->context;
u32 wa_offset = lrc_indirect_bb(ce);
u32 *cs;
+ GEM_BUG_ON(!ce->wa_bb_page);
+
cs = intel_ring_begin(rq, 12);
if (IS_ERR(cs))
return PTR_ERR(cs);
@@ -435,18 +437,18 @@ static int __gen125_emit_bb_start(struct i915_request *rq,
return 0;
}
-int gen125_emit_bb_start_noarb(struct i915_request *rq,
- u64 offset, u32 len,
- const unsigned int flags)
+int xehp_emit_bb_start_noarb(struct i915_request *rq,
+ u64 offset, u32 len,
+ const unsigned int flags)
{
- return __gen125_emit_bb_start(rq, offset, len, flags, MI_ARB_DISABLE);
+ return __xehp_emit_bb_start(rq, offset, len, flags, MI_ARB_DISABLE);
}
-int gen125_emit_bb_start(struct i915_request *rq,
- u64 offset, u32 len,
- const unsigned int flags)
+int xehp_emit_bb_start(struct i915_request *rq,
+ u64 offset, u32 len,
+ const unsigned int flags)
{
- return __gen125_emit_bb_start(rq, offset, len, flags, MI_ARB_ENABLE);
+ return __xehp_emit_bb_start(rq, offset, len, flags, MI_ARB_ENABLE);
}
int gen8_emit_bb_start_noarb(struct i915_request *rq,
@@ -583,6 +585,8 @@ u32 *gen8_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs)
u32 *gen8_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
{
cs = gen8_emit_pipe_control(cs,
+ PIPE_CONTROL_CS_STALL |
+ PIPE_CONTROL_TLB_INVALIDATE |
PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
PIPE_CONTROL_DEPTH_CACHE_FLUSH |
PIPE_CONTROL_DC_FLUSH_ENABLE,
@@ -600,15 +604,21 @@ u32 *gen8_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
u32 *gen11_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
{
+ cs = gen8_emit_pipe_control(cs,
+ PIPE_CONTROL_CS_STALL |
+ PIPE_CONTROL_TLB_INVALIDATE |
+ PIPE_CONTROL_TILE_CACHE_FLUSH |
+ PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
+ PIPE_CONTROL_DEPTH_CACHE_FLUSH |
+ PIPE_CONTROL_DC_FLUSH_ENABLE,
+ 0);
+
+ /*XXX: Look at gen8_emit_fini_breadcrumb_rcs */
cs = gen8_emit_ggtt_write_rcs(cs,
rq->fence.seqno,
hwsp_offset(rq),
- PIPE_CONTROL_CS_STALL |
- PIPE_CONTROL_TILE_CACHE_FLUSH |
- PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
- PIPE_CONTROL_DEPTH_CACHE_FLUSH |
- PIPE_CONTROL_DC_FLUSH_ENABLE |
- PIPE_CONTROL_FLUSH_ENABLE);
+ PIPE_CONTROL_FLUSH_ENABLE |
+ PIPE_CONTROL_CS_STALL);
return gen8_emit_fini_breadcrumb_tail(rq, cs);
}
@@ -715,6 +725,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
{
struct drm_i915_private *i915 = rq->engine->i915;
u32 flags = (PIPE_CONTROL_CS_STALL |
+ PIPE_CONTROL_TLB_INVALIDATE |
PIPE_CONTROL_TILE_CACHE_FLUSH |
PIPE_CONTROL_FLUSH_L3 |
PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
@@ -731,11 +742,15 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
else if (rq->engine->class == COMPUTE_CLASS)
flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS;
+ cs = gen12_emit_pipe_control(cs, PIPE_CONTROL0_HDC_PIPELINE_FLUSH, flags, 0);
+
+ /*XXX: Look at gen8_emit_fini_breadcrumb_rcs */
cs = gen12_emit_ggtt_write_rcs(cs,
rq->fence.seqno,
hwsp_offset(rq),
- PIPE_CONTROL0_HDC_PIPELINE_FLUSH,
- flags);
+ 0,
+ PIPE_CONTROL_FLUSH_ENABLE |
+ PIPE_CONTROL_CS_STALL);
return gen12_emit_fini_breadcrumb_tail(rq, cs);
}
diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h
index e4d24c811dd6..655e5c00ddc2 100644
--- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h
+++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h
@@ -32,12 +32,12 @@ int gen8_emit_bb_start(struct i915_request *rq,
u64 offset, u32 len,
const unsigned int flags);
-int gen125_emit_bb_start_noarb(struct i915_request *rq,
- u64 offset, u32 len,
- const unsigned int flags);
-int gen125_emit_bb_start(struct i915_request *rq,
- u64 offset, u32 len,
- const unsigned int flags);
+int xehp_emit_bb_start_noarb(struct i915_request *rq,
+ u64 offset, u32 len,
+ const unsigned int flags);
+int xehp_emit_bb_start(struct i915_request *rq,
+ u64 offset, u32 len,
+ const unsigned int flags);
u32 *gen8_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs);
u32 *gen12_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs);
diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
index 2128b7a72a25..4daaa6f55668 100644
--- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
@@ -476,6 +476,7 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
const gen8_pte_t pte_encode = vm->pte_encode(0, cache_level, flags);
unsigned int rem = sg_dma_len(iter->sg);
u64 start = vma_res->start;
+ u64 end = start + vma_res->vma_size;
GEM_BUG_ON(!i915_vm_is_4lvl(vm));
@@ -489,9 +490,10 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
gen8_pte_t encode = pte_encode;
unsigned int page_size;
gen8_pte_t *vaddr;
- u16 index, max;
+ u16 index, max, nent, i;
max = I915_PDES;
+ nent = 1;
if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
@@ -503,25 +505,37 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
vaddr = px_vaddr(pd);
} else {
- if (encode & GEN12_PPGTT_PTE_LM) {
- GEM_BUG_ON(__gen8_pte_index(start, 0) % 16);
- GEM_BUG_ON(rem < I915_GTT_PAGE_SIZE_64K);
- GEM_BUG_ON(!IS_ALIGNED(iter->dma,
- I915_GTT_PAGE_SIZE_64K));
-
- index = __gen8_pte_index(start, 0) / 16;
- page_size = I915_GTT_PAGE_SIZE_64K;
-
- max /= 16;
-
- vaddr = px_vaddr(pd);
- vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K;
+ index = __gen8_pte_index(start, 0);
+ page_size = I915_GTT_PAGE_SIZE;
- pt->is_compact = true;
- } else {
- GEM_BUG_ON(pt->is_compact);
- index = __gen8_pte_index(start, 0);
- page_size = I915_GTT_PAGE_SIZE;
+ if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) {
+ /*
+ * Device local-memory on these platforms should
+ * always use 64K pages or larger (including GTT
+ * alignment), therefore if we know the whole
+ * page-table needs to be filled we can always
+ * safely use the compact-layout. Otherwise fall
+ * back to the TLB hint with PS64. If this is
+ * system memory we only bother with PS64.
+ */
+ if ((encode & GEN12_PPGTT_PTE_LM) &&
+ end - start >= SZ_2M && !index) {
+ index = __gen8_pte_index(start, 0) / 16;
+ page_size = I915_GTT_PAGE_SIZE_64K;
+
+ max /= 16;
+
+ vaddr = px_vaddr(pd);
+ vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K;
+
+ pt->is_compact = true;
+ } else if (IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
+ rem >= I915_GTT_PAGE_SIZE_64K &&
+ !(index % 16)) {
+ encode |= GEN12_PTE_PS64;
+ page_size = I915_GTT_PAGE_SIZE_64K;
+ nent = 16;
+ }
}
vaddr = px_vaddr(pt);
@@ -529,7 +543,12 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
do {
GEM_BUG_ON(rem < page_size);
- vaddr[index++] = encode | iter->dma;
+
+ for (i = 0; i < nent; i++) {
+ vaddr[index++] =
+ encode | (iter->dma + i *
+ I915_GTT_PAGE_SIZE);
+ }
start += page_size;
iter->dma += page_size;
@@ -745,6 +764,8 @@ static void __xehpsdv_ppgtt_insert_entry_lm(struct i915_address_space *vm,
GEM_BUG_ON(!IS_ALIGNED(addr, SZ_64K));
GEM_BUG_ON(!IS_ALIGNED(offset, SZ_64K));
+ /* XXX: we don't strictly need to use this layout */
+
if (!pt->is_compact) {
vaddr = px_vaddr(pd);
vaddr[gen8_pd_index(idx, 1)] |= GEN12_PDE_64K;
@@ -929,29 +950,18 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt,
*/
ppgtt->vm.has_read_only = !IS_GRAPHICS_VER(gt->i915, 11, 12);
- if (HAS_LMEM(gt->i915)) {
+ if (HAS_LMEM(gt->i915))
ppgtt->vm.alloc_pt_dma = alloc_pt_lmem;
-
- /*
- * On some platforms the hw has dropped support for 4K GTT pages
- * when dealing with LMEM, and due to the design of 64K GTT
- * pages in the hw, we can only mark the *entire* page-table as
- * operating in 64K GTT mode, since the enable bit is still on
- * the pde, and not the pte. And since we still need to allow
- * 4K GTT pages for SMEM objects, we can't have a "normal" 4K
- * page-table with scratch pointing to LMEM, since that's
- * undefined from the hw pov. The simplest solution is to just
- * move the 64K scratch page to SMEM on such platforms and call
- * it a day, since that should work for all configurations.
- */
- if (HAS_64K_PAGES(gt->i915))
- ppgtt->vm.alloc_scratch_dma = alloc_pt_dma;
- else
- ppgtt->vm.alloc_scratch_dma = alloc_pt_lmem;
- } else {
+ else
ppgtt->vm.alloc_pt_dma = alloc_pt_dma;
- ppgtt->vm.alloc_scratch_dma = alloc_pt_dma;
- }
+
+ /*
+ * Using SMEM here instead of LMEM has the advantage of not reserving
+ * high performance memory for a "never" used filler page. It also
+ * removes the device access that would be required to initialise the
+ * scratch page, reducing pressure on an even scarcer resource.
+ */
+ ppgtt->vm.alloc_scratch_dma = alloc_pt_dma;
ppgtt->vm.pte_encode = gen8_pte_encode;
diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
index be09fb2e883a..fb62b7b8cbcd 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.h
+++ b/drivers/gpu/drm/i915/gt/intel_context.h
@@ -276,6 +276,14 @@ static inline bool intel_context_is_barrier(const struct intel_context *ce)
return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
}
+static inline void intel_context_close(struct intel_context *ce)
+{
+ set_bit(CONTEXT_CLOSED_BIT, &ce->flags);
+
+ if (ce->ops->close)
+ ce->ops->close(ce);
+}
+
static inline bool intel_context_is_closed(const struct intel_context *ce)
{
return test_bit(CONTEXT_CLOSED_BIT, &ce->flags);
diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
index 04eacae1aca5..e36670f2e626 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
@@ -43,6 +43,8 @@ struct intel_context_ops {
void (*revoke)(struct intel_context *ce, struct i915_request *rq,
unsigned int preempt_timeout_ms);
+ void (*close)(struct intel_context *ce);
+
int (*pre_pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void **vaddr);
int (*pin)(struct intel_context *ce, void *vaddr);
void (*unpin)(struct intel_context *ce);
@@ -197,8 +199,6 @@ struct intel_context {
* context's submissions is complete.
*/
struct i915_sw_fence blocked;
- /** @number_committed_requests: number of committed requests */
- int number_committed_requests;
/** @requests: list of active requests on this context */
struct list_head requests;
/** @prio: the context's current guc priority */
@@ -208,6 +208,11 @@ struct intel_context {
* each priority bucket
*/
u32 prio_count[GUC_CLIENT_PRIORITY_NUM];
+ /**
+ * @sched_disable_delay_work: worker to disable scheduling on this
+ * context
+ */
+ struct delayed_work sched_disable_delay_work;
} guc_state;
struct {
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h
index 04e435bce79b..cbc8b857d5f7 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine.h
@@ -348,4 +348,10 @@ intel_engine_get_hung_context(struct intel_engine_cs *engine)
return engine->hung_ce;
}
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value);
+u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value);
+u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value);
+u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value);
+u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value);
+
#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 1f7188129cd1..c33e0d72d670 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -13,6 +13,8 @@
#include "i915_cmd_parser.h"
#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
#include "intel_breadcrumbs.h"
#include "intel_context.h"
#include "intel_engine.h"
@@ -244,6 +246,13 @@ static const struct engine_info intel_engines[] = {
{ .graphics_ver = 12, .base = GEN12_COMPUTE3_RING_BASE }
}
},
+ [GSC0] = {
+ .class = OTHER_CLASS,
+ .instance = OTHER_GSC_INSTANCE,
+ .mmio_bases = {
+ { .graphics_ver = 12, .base = MTL_GSC_RING_BASE }
+ }
+ },
};
/**
@@ -324,6 +333,7 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class)
case VIDEO_DECODE_CLASS:
case VIDEO_ENHANCEMENT_CLASS:
case COPY_ENGINE_CLASS:
+ case OTHER_CLASS:
if (GRAPHICS_VER(gt->i915) < 8)
return 0;
return GEN8_LR_CONTEXT_OTHER_SIZE;
@@ -415,6 +425,7 @@ static u32 get_reset_domain(u8 ver, enum intel_engine_id id)
[CCS1] = GEN11_GRDOM_RENDER,
[CCS2] = GEN11_GRDOM_RENDER,
[CCS3] = GEN11_GRDOM_RENDER,
+ [GSC0] = GEN12_GRDOM_GSC,
};
GEM_BUG_ON(id >= ARRAY_SIZE(engine_reset_domains) ||
!engine_reset_domains[id]);
@@ -486,6 +497,17 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id,
engine->logical_mask = BIT(logical_instance);
__sprint_engine_name(engine);
+ if ((engine->class == COMPUTE_CLASS && !RCS_MASK(engine->gt) &&
+ __ffs(CCS_MASK(engine->gt)) == engine->instance) ||
+ engine->class == RENDER_CLASS)
+ engine->flags |= I915_ENGINE_FIRST_RENDER_COMPUTE;
+
+ /* features common between engines sharing EUs */
+ if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) {
+ engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE;
+ engine->flags |= I915_ENGINE_HAS_EU_PRIORITY;
+ }
+
engine->props.heartbeat_interval_ms =
CONFIG_DRM_I915_HEARTBEAT_INTERVAL;
engine->props.max_busywait_duration_ns =
@@ -497,20 +519,34 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id,
engine->props.timeslice_duration_ms =
CONFIG_DRM_I915_TIMESLICE_DURATION;
- /* Override to uninterruptible for OpenCL workloads. */
- if (GRAPHICS_VER(i915) == 12 && engine->class == RENDER_CLASS)
- engine->props.preempt_timeout_ms = 0;
-
- if ((engine->class == COMPUTE_CLASS && !RCS_MASK(engine->gt) &&
- __ffs(CCS_MASK(engine->gt)) == engine->instance) ||
- engine->class == RENDER_CLASS)
- engine->flags |= I915_ENGINE_FIRST_RENDER_COMPUTE;
-
- /* features common between engines sharing EUs */
- if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) {
- engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE;
- engine->flags |= I915_ENGINE_HAS_EU_PRIORITY;
- }
+ /*
+ * Mid-thread pre-emption is not available in Gen12. Unfortunately,
+ * some compute workloads run quite long threads. That means they get
+ * reset due to not pre-empting in a timely manner. So, bump the
+ * pre-emption timeout value to be much higher for compute engines.
+ */
+ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE))
+ engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
+
+ /* Cap properties according to any system limits */
+#define CLAMP_PROP(field) \
+ do { \
+ u64 clamp = intel_clamp_##field(engine, engine->props.field); \
+ if (clamp != engine->props.field) { \
+ drm_notice(&engine->i915->drm, \
+ "Warning, clamping %s to %lld to prevent overflow\n", \
+ #field, clamp); \
+ engine->props.field = clamp; \
+ } \
+ } while (0)
+
+ CLAMP_PROP(heartbeat_interval_ms);
+ CLAMP_PROP(max_busywait_duration_ns);
+ CLAMP_PROP(preempt_timeout_ms);
+ CLAMP_PROP(stop_timeout_ms);
+ CLAMP_PROP(timeslice_duration_ms);
+
+#undef CLAMP_PROP
engine->defaults = engine->props; /* never to change again */
@@ -534,6 +570,55 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id,
return 0;
}
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value)
+{
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+
+ return value;
+}
+
+u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value)
+{
+ value = min(value, jiffies_to_nsecs(2));
+
+ return value;
+}
+
+u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value)
+{
+ /*
+ * NB: The GuC API only supports 32bit values. However, the limit is further
+ * reduced due to internal calculations which would otherwise overflow.
+ */
+ if (intel_guc_submission_is_wanted(&engine->gt->uc.guc))
+ value = min_t(u64, value, guc_policy_max_preempt_timeout_ms());
+
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+
+ return value;
+}
+
+u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value)
+{
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+
+ return value;
+}
+
+u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value)
+{
+ /*
+ * NB: The GuC API only supports 32bit values. However, the limit is further
+ * reduced due to internal calculations which would otherwise overflow.
+ */
+ if (intel_guc_submission_is_wanted(&engine->gt->uc.guc))
+ value = min_t(u64, value, guc_policy_max_exec_quantum_ms());
+
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+
+ return value;
+}
+
static void __setup_engine_capabilities(struct intel_engine_cs *engine)
{
struct drm_i915_private *i915 = engine->i915;
@@ -1274,8 +1359,13 @@ int intel_engines_init(struct intel_gt *gt)
return err;
err = setup(engine);
- if (err)
+ if (err) {
+ intel_engine_cleanup_common(engine);
return err;
+ }
+
+ /* The backend should now be responsible for cleanup */
+ GEM_BUG_ON(engine->release == NULL);
err = engine_init_common(engine);
if (err)
@@ -1554,11 +1644,11 @@ void intel_engine_get_instdone(const struct intel_engine_cs *engine,
for_each_ss_steering(iter, engine->gt, slice, subslice) {
instdone->sampler[slice][subslice] =
intel_gt_mcr_read(engine->gt,
- GEN7_SAMPLER_INSTDONE,
+ GEN8_SAMPLER_INSTDONE,
slice, subslice);
instdone->row[slice][subslice] =
intel_gt_mcr_read(engine->gt,
- GEN7_ROW_INSTDONE,
+ GEN8_ROW_INSTDONE,
slice, subslice);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
index a3698f611f45..9a527e1f5be6 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
@@ -22,9 +22,37 @@
static bool next_heartbeat(struct intel_engine_cs *engine)
{
+ struct i915_request *rq;
long delay;
delay = READ_ONCE(engine->props.heartbeat_interval_ms);
+
+ rq = engine->heartbeat.systole;
+
+ /*
+ * FIXME: The final period extension is disabled if the period has been
+ * modified from the default. This is to prevent issues with certain
+ * selftests which override the value and expect specific behaviour.
+ * Once the selftests have been updated to either cope with variable
+ * heartbeat periods (or to override the pre-emption timeout as well,
+ * or just to add a selftest specific override of the extension), the
+ * generic override can be removed.
+ */
+ if (rq && rq->sched.attr.priority >= I915_PRIORITY_BARRIER &&
+ delay == engine->defaults.heartbeat_interval_ms) {
+ long longer;
+
+ /*
+ * The final try is at the highest priority possible. Up until now
+ * a pre-emption might not even have been attempted. So make sure
+ * this last attempt allows enough time for a pre-emption to occur.
+ */
+ longer = READ_ONCE(engine->props.preempt_timeout_ms) * 2;
+ longer = intel_clamp_heartbeat_interval_ms(engine, longer);
+ if (longer > delay)
+ delay = longer;
+ }
+
if (!delay)
return false;
@@ -288,6 +316,17 @@ int intel_engine_set_heartbeat(struct intel_engine_cs *engine,
if (!delay && !intel_engine_has_preempt_reset(engine))
return -ENODEV;
+ /* FIXME: Remove together with equally marked hack in next_heartbeat. */
+ if (delay != engine->defaults.heartbeat_interval_ms &&
+ delay < 2 * engine->props.preempt_timeout_ms) {
+ if (intel_engine_uses_guc(engine))
+ drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may downgrade individual engine resets to full GPU resets!\n",
+ engine->name);
+ else
+ drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may cause engine resets to target innocent contexts!\n",
+ engine->name);
+ }
+
intel_engine_pm_get(engine);
err = mutex_lock_interruptible(&ce->timeline->mutex);
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h
index fe1a0d5fd4b1..ee3efd06ee54 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h
@@ -201,6 +201,7 @@
#define RING_CONTEXT_STATUS_PTR(base) _MMIO((base) + 0x3a0)
#define RING_CTX_TIMESTAMP(base) _MMIO((base) + 0x3a8) /* gen8+ */
#define RING_PREDICATE_RESULT(base) _MMIO((base) + 0x3b8)
+#define MI_PREDICATE_RESULT_2_ENGINE(base) _MMIO((base) + 0x3bc)
#define RING_FORCE_TO_NONPRIV(base, i) _MMIO(((base) + 0x4D0) + (i) * 4)
#define RING_FORCE_TO_NONPRIV_DENY REG_BIT(30)
#define RING_FORCE_TO_NONPRIV_ADDRESS_MASK REG_GENMASK(25, 2)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 6b5d4ea22b67..4fd54fb8810f 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -136,6 +136,7 @@ enum intel_engine_id {
CCS2,
CCS3,
#define _CCS(n) (CCS0 + (n))
+ GSC0,
I915_NUM_ENGINES
#define INVALID_ENGINE ((enum intel_engine_id)-1)
};
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c
index 46a174f8aa00..cd4f1b126f75 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_user.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c
@@ -140,6 +140,7 @@ const char *intel_engine_class_repr(u8 class)
[COPY_ENGINE_CLASS] = "bcs",
[VIDEO_DECODE_CLASS] = "vcs",
[VIDEO_ENHANCEMENT_CLASS] = "vecs",
+ [OTHER_CLASS] = "other",
[COMPUTE_CLASS] = "ccs",
};
@@ -190,6 +191,15 @@ static void add_legacy_ring(struct legacy_ring *ring,
ring->instance++;
}
+static void engine_rename(struct intel_engine_cs *engine, const char *name, u16 instance)
+{
+ char old[sizeof(engine->name)];
+
+ memcpy(old, engine->name, sizeof(engine->name));
+ scnprintf(engine->name, sizeof(engine->name), "%s%u", name, instance);
+ drm_dbg(&engine->i915->drm, "renamed %s to %s\n", old, engine->name);
+}
+
void intel_engines_driver_register(struct drm_i915_private *i915)
{
struct legacy_ring ring = {};
@@ -205,11 +215,19 @@ void intel_engines_driver_register(struct drm_i915_private *i915)
struct intel_engine_cs *engine =
container_of((struct rb_node *)it, typeof(*engine),
uabi_node);
- char old[sizeof(engine->name)];
if (intel_gt_has_unrecoverable_error(engine->gt))
continue; /* ignore incomplete engines */
+ /*
+ * We don't want to expose the GSC engine to the users, but we
+ * still rename it so it is easier to identify in the debug logs
+ */
+ if (engine->id == GSC0) {
+ engine_rename(engine, "gsc", 0);
+ continue;
+ }
+
GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes));
engine->uabi_class = uabi_classes[engine->class];
@@ -219,11 +237,9 @@ void intel_engines_driver_register(struct drm_i915_private *i915)
i915->engine_uabi_class_count[engine->uabi_class]++;
/* Replace the internal name with the final user facing name */
- memcpy(old, engine->name, sizeof(engine->name));
- scnprintf(engine->name, sizeof(engine->name), "%s%u",
- intel_engine_class_repr(engine->class),
- engine->uabi_instance);
- DRM_DEBUG_DRIVER("renamed %s to %s\n", old, engine->name);
+ engine_rename(engine,
+ intel_engine_class_repr(engine->class),
+ engine->uabi_instance);
rb_link_node(&engine->uabi_node, prev, p);
rb_insert_color(&engine->uabi_node, &i915->uabi_engines);
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index c718e6dc40b5..2daffa7c7dfd 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -110,6 +110,7 @@
#include <linux/string_helpers.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_vgpu.h"
#include "gen8_engine_cs.h"
@@ -3471,9 +3472,9 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine)
if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) {
if (intel_engine_has_preemption(engine))
- engine->emit_bb_start = gen125_emit_bb_start;
+ engine->emit_bb_start = xehp_emit_bb_start;
else
- engine->emit_bb_start = gen125_emit_bb_start_noarb;
+ engine->emit_bb_start = xehp_emit_bb_start_noarb;
} else {
if (intel_engine_has_preemption(engine))
engine->emit_bb_start = gen8_emit_bb_start;
@@ -3689,7 +3690,7 @@ static void virtual_engine_initial_hint(struct virtual_engine *ve)
* NB This does not force us to execute on this engine, it will just
* typically be the first we inspect for submission.
*/
- swp = prandom_u32_max(ve->num_siblings);
+ swp = get_random_u32_below(ve->num_siblings);
if (swp)
swap(ve->siblings[swp], ve->siblings[0]);
}
@@ -3921,6 +3922,7 @@ static struct intel_context *
execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
unsigned long flags)
{
+ struct drm_i915_private *i915 = siblings[0]->i915;
struct virtual_engine *ve;
unsigned int n;
int err;
@@ -3929,7 +3931,7 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
if (!ve)
return ERR_PTR(-ENOMEM);
- ve->base.i915 = siblings[0]->i915;
+ ve->base.i915 = i915;
ve->base.gt = siblings[0]->gt;
ve->base.uncore = siblings[0]->uncore;
ve->base.id = -1;
@@ -3988,8 +3990,9 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
GEM_BUG_ON(!is_power_of_2(sibling->mask));
if (sibling->mask & ve->base.mask) {
- DRM_DEBUG("duplicate %s entry in load balancer\n",
- sibling->name);
+ drm_dbg(&i915->drm,
+ "duplicate %s entry in load balancer\n",
+ sibling->name);
err = -EINVAL;
goto err_put;
}
@@ -4023,8 +4026,9 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
*/
if (ve->base.class != OTHER_CLASS) {
if (ve->base.class != sibling->class) {
- DRM_DEBUG("invalid mixing of engine class, sibling %d, already %d\n",
- sibling->class, ve->base.class);
+ drm_dbg(&i915->drm,
+ "invalid mixing of engine class, sibling %d, already %d\n",
+ sibling->class, ve->base.class);
err = -EINVAL;
goto err_put;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 2049a00417af..8145851ad23d 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -560,7 +560,7 @@ static int init_ggtt(struct i915_ggtt *ggtt)
* why.
*/
ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE,
- intel_wopcm_guc_size(&ggtt->vm.i915->wopcm));
+ intel_wopcm_guc_size(&ggtt->vm.gt->wopcm));
ret = intel_vgt_balloon(ggtt);
if (ret)
@@ -871,8 +871,8 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
u32 pte_flags;
int ret;
- GEM_WARN_ON(pci_resource_len(pdev, GTTMMADR_BAR) != gen6_gttmmadr_size(i915));
- phys_addr = pci_resource_start(pdev, GTTMMADR_BAR) + gen6_gttadr_offset(i915);
+ GEM_WARN_ON(pci_resource_len(pdev, GEN4_GTTMMADR_BAR) != gen6_gttmmadr_size(i915));
+ phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915);
/*
* On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range
@@ -931,11 +931,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
unsigned int size;
u16 snb_gmch_ctl;
- if (!HAS_LMEM(i915)) {
- if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR))
+ if (!HAS_LMEM(i915) && !HAS_LMEMBAR_SMEM_STOLEN(i915)) {
+ if (!i915_pci_resource_valid(pdev, GEN4_GMADR_BAR))
return -ENXIO;
- ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR);
+ ggtt->gmadr = pci_resource(pdev, GEN4_GMADR_BAR);
ggtt->mappable_end = resource_size(&ggtt->gmadr);
}
@@ -986,7 +986,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
ggtt->vm.pte_encode = gen8_ggtt_pte_encode;
- setup_private_pat(ggtt->vm.gt->uncore);
+ setup_private_pat(ggtt->vm.gt);
return ggtt_probe_common(ggtt, size);
}
@@ -1089,10 +1089,10 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
unsigned int size;
u16 snb_gmch_ctl;
- if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR))
+ if (!i915_pci_resource_valid(pdev, GEN4_GMADR_BAR))
return -ENXIO;
- ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR);
+ ggtt->gmadr = pci_resource(pdev, GEN4_GMADR_BAR);
ggtt->mappable_end = resource_size(&ggtt->gmadr);
/*
@@ -1308,7 +1308,7 @@ void i915_ggtt_resume(struct i915_ggtt *ggtt)
wbinvd_on_all_cpus();
if (GRAPHICS_VER(ggtt->vm.i915) >= 8)
- setup_private_pat(ggtt->vm.gt->uncore);
+ setup_private_pat(ggtt->vm.gt);
intel_ggtt_restore_fences(ggtt);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
index ea775e601686..995082d45cb2 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
@@ -816,8 +816,8 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
if (obj->bit_17 == NULL) {
obj->bit_17 = bitmap_zalloc(page_count, GFP_KERNEL);
if (obj->bit_17 == NULL) {
- DRM_ERROR("Failed to allocate memory for bit 17 "
- "record\n");
+ drm_err(&to_i915(obj->base.dev)->drm,
+ "Failed to allocate memory for bit 17 record\n");
return;
}
}
diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
index d4e9702d3c8e..f50ea92910d9 100644
--- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
+++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
@@ -187,6 +187,10 @@
#define MI_BATCH_RESOURCE_STREAMER REG_BIT(10)
#define MI_BATCH_PREDICATE REG_BIT(15) /* HSW+ on RCS only*/
+#define MI_OPCODE(x) (((x) >> 23) & 0x3f)
+#define IS_MI_LRI_CMD(x) (MI_OPCODE(x) == MI_OPCODE(MI_INSTR(0x22, 0)))
+#define MI_LRI_LEN(x) (((x) & 0xff) + 1)
+
/*
* 3D instructions used by the kernel
*/
diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c
index 7af6db3194dd..976fdf27e790 100644
--- a/drivers/gpu/drm/i915/gt/intel_gsc.c
+++ b/drivers/gpu/drm/i915/gt/intel_gsc.c
@@ -7,6 +7,7 @@
#include <linux/mei_aux.h>
#include "i915_drv.h"
#include "i915_reg.h"
+#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "gt/intel_gsc.h"
#include "gt/intel_gt.h"
@@ -142,8 +143,14 @@ static void gsc_destroy_one(struct drm_i915_private *i915,
struct intel_gsc_intf *intf = &gsc->intf[intf_id];
if (intf->adev) {
- auxiliary_device_delete(&intf->adev->aux_dev);
- auxiliary_device_uninit(&intf->adev->aux_dev);
+ struct auxiliary_device *aux_dev = &intf->adev->aux_dev;
+
+ if (intf_id == 0)
+ intel_huc_unregister_gsc_notifier(&gsc_to_gt(gsc)->uc.huc,
+ aux_dev->dev.bus);
+
+ auxiliary_device_delete(aux_dev);
+ auxiliary_device_uninit(aux_dev);
intf->adev = NULL;
}
@@ -242,14 +249,24 @@ add_device:
goto fail;
}
+ intf->adev = adev; /* needed by the notifier */
+
+ if (intf_id == 0)
+ intel_huc_register_gsc_notifier(&gsc_to_gt(gsc)->uc.huc,
+ aux_dev->dev.bus);
+
ret = auxiliary_device_add(aux_dev);
if (ret < 0) {
drm_err(&i915->drm, "gsc aux add failed %d\n", ret);
+ if (intf_id == 0)
+ intel_huc_unregister_gsc_notifier(&gsc_to_gt(gsc)->uc.huc,
+ aux_dev->dev.bus);
+ intf->adev = NULL;
+
/* adev will be freed with the put_device() and .release sequence */
auxiliary_device_uninit(aux_dev);
goto fail;
}
- intf->adev = adev;
return;
fail:
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index d0b03a928b9a..767e329e1cc5 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -12,6 +12,7 @@
#include "i915_drv.h"
#include "i915_perf_oa_regs.h"
+#include "i915_reg.h"
#include "intel_context.h"
#include "intel_engine_pm.h"
#include "intel_engine_regs.h"
@@ -40,8 +41,6 @@ void intel_gt_common_init_early(struct intel_gt *gt)
{
spin_lock_init(gt->irq_lock);
- INIT_LIST_HEAD(&gt->lmem_userfault_list);
- mutex_init(&gt->lmem_userfault_lock);
INIT_LIST_HEAD(&gt->closed_vma);
spin_lock_init(&gt->closed_lock);
@@ -56,6 +55,7 @@ void intel_gt_common_init_early(struct intel_gt *gt)
seqcount_mutex_init(&gt->tlb.seqno, &gt->tlb.invalidate_lock);
intel_gt_pm_init_early(gt);
+ intel_wopcm_init_early(&gt->wopcm);
intel_uc_init_early(&gt->uc);
intel_rps_init_early(&gt->rps);
}
@@ -192,7 +192,7 @@ int intel_gt_init_hw(struct intel_gt *gt)
ret = i915_ppgtt_init_hw(gt);
if (ret) {
- DRM_ERROR("Enabling PPGTT failed (%d)\n", ret);
+ drm_err(&i915->drm, "Enabling PPGTT failed (%d)\n", ret);
goto out;
}
@@ -231,6 +231,16 @@ static void gen6_clear_engine_error_register(struct intel_engine_cs *engine)
GEN6_RING_FAULT_REG_POSTING_READ(engine);
}
+i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt)
+{
+ /* GT0_PERF_LIMIT_REASONS is available only for Gen11+ */
+ if (GRAPHICS_VER(gt->i915) < 11)
+ return INVALID_MMIO_REG;
+
+ return gt->type == GT_MEDIA ?
+ MTL_MEDIA_PERF_LIMIT_REASONS : GT0_PERF_LIMIT_REASONS;
+}
+
void
intel_gt_clear_error_registers(struct intel_gt *gt,
intel_engine_mask_t engine_mask)
@@ -254,13 +264,17 @@ intel_gt_clear_error_registers(struct intel_gt *gt,
* some errors might have become stuck,
* mask them.
*/
- DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir);
+ drm_dbg(&gt->i915->drm, "EIR stuck: 0x%08x, masking\n", eir);
rmw_set(uncore, EMR, eir);
intel_uncore_write(uncore, GEN2_IIR,
I915_MASTER_ERROR_INTERRUPT);
}
- if (GRAPHICS_VER(i915) >= 12) {
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ intel_gt_mcr_multicast_rmw(gt, XEHP_RING_FAULT_REG,
+ RING_FAULT_VALID, 0);
+ intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG);
+ } else if (GRAPHICS_VER(i915) >= 12) {
rmw_clear(uncore, GEN12_RING_FAULT_REG, RING_FAULT_VALID);
intel_uncore_posting_read(uncore, GEN12_RING_FAULT_REG);
} else if (GRAPHICS_VER(i915) >= 8) {
@@ -298,6 +312,42 @@ static void gen6_check_faults(struct intel_gt *gt)
}
}
+static void xehp_check_faults(struct intel_gt *gt)
+{
+ u32 fault;
+
+ /*
+ * Although the fault register now lives in an MCR register range,
+ * the GAM registers are special and we only truly need to read
+ * the "primary" GAM instance rather than handling each instance
+ * individually. intel_gt_mcr_read_any() will automatically steer
+ * toward the primary instance.
+ */
+ fault = intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG);
+ if (fault & RING_FAULT_VALID) {
+ u32 fault_data0, fault_data1;
+ u64 fault_addr;
+
+ fault_data0 = intel_gt_mcr_read_any(gt, XEHP_FAULT_TLB_DATA0);
+ fault_data1 = intel_gt_mcr_read_any(gt, XEHP_FAULT_TLB_DATA1);
+
+ fault_addr = ((u64)(fault_data1 & FAULT_VA_HIGH_BITS) << 44) |
+ ((u64)fault_data0 << 12);
+
+ drm_dbg(&gt->i915->drm, "Unexpected fault\n"
+ "\tAddr: 0x%08x_%08x\n"
+ "\tAddress space: %s\n"
+ "\tEngine ID: %d\n"
+ "\tSource ID: %d\n"
+ "\tType: %d\n",
+ upper_32_bits(fault_addr), lower_32_bits(fault_addr),
+ fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT",
+ GEN8_RING_FAULT_ENGINE_ID(fault),
+ RING_FAULT_SRCID(fault),
+ RING_FAULT_FAULT_TYPE(fault));
+ }
+}
+
static void gen8_check_faults(struct intel_gt *gt)
{
struct intel_uncore *uncore = gt->uncore;
@@ -344,7 +394,9 @@ void intel_gt_check_and_clear_faults(struct intel_gt *gt)
struct drm_i915_private *i915 = gt->i915;
/* From GEN8 onwards we only have one 'All Engine Fault Register' */
- if (GRAPHICS_VER(i915) >= 8)
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50))
+ xehp_check_faults(gt);
+ else if (GRAPHICS_VER(i915) >= 8)
gen8_check_faults(gt);
else if (GRAPHICS_VER(i915) >= 6)
gen6_check_faults(gt);
@@ -625,8 +677,13 @@ int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout)
return -EINTR;
}
- return timeout ? timeout : intel_uc_wait_for_idle(&gt->uc,
- remaining_timeout);
+ if (timeout)
+ return timeout;
+
+ if (remaining_timeout < 0)
+ remaining_timeout = 0;
+
+ return intel_uc_wait_for_idle(&gt->uc, remaining_timeout);
}
int intel_gt_init(struct intel_gt *gt)
@@ -807,7 +864,6 @@ static int intel_gt_tile_setup(struct intel_gt *gt, phys_addr_t phys_addr)
}
intel_uncore_init_early(gt->uncore, gt);
- intel_wakeref_auto_init(&gt->userfault_wakeref, gt->uncore->rpm);
ret = intel_uncore_setup_mmio(gt->uncore, phys_addr);
if (ret)
@@ -828,7 +884,7 @@ int intel_gt_probe_all(struct drm_i915_private *i915)
unsigned int i;
int ret;
- mmio_bar = GRAPHICS_VER(i915) == 2 ? GEN2_GTTMMADR_BAR : GTTMMADR_BAR;
+ mmio_bar = intel_mmio_bar(GRAPHICS_VER(i915));
phys_addr = pci_resource_start(pdev, mmio_bar);
/*
@@ -939,7 +995,10 @@ void intel_gt_info_print(const struct intel_gt_info *info,
}
struct reg_and_bit {
- i915_reg_t reg;
+ union {
+ i915_reg_t reg;
+ i915_mcr_reg_t mcr_reg;
+ };
u32 bit;
};
@@ -965,6 +1024,32 @@ get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
return rb;
}
+/*
+ * HW architecture suggest typical invalidation time at 40us,
+ * with pessimistic cases up to 100us and a recommendation to
+ * cap at 1ms. We go a bit higher just in case.
+ */
+#define TLB_INVAL_TIMEOUT_US 100
+#define TLB_INVAL_TIMEOUT_MS 4
+
+/*
+ * On Xe_HP the TLB invalidation registers are located at the same MMIO offsets
+ * but are now considered MCR registers. Since they exist within a GAM range,
+ * the primary instance of the register rolls up the status from each unit.
+ */
+static int wait_for_invalidate(struct intel_gt *gt, struct reg_and_bit rb)
+{
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
+ return intel_gt_mcr_wait_for_reg(gt, rb.mcr_reg, rb.bit, 0,
+ TLB_INVAL_TIMEOUT_US,
+ TLB_INVAL_TIMEOUT_MS);
+ else
+ return __intel_wait_for_register_fw(gt->uncore, rb.reg, rb.bit, 0,
+ TLB_INVAL_TIMEOUT_US,
+ TLB_INVAL_TIMEOUT_MS,
+ NULL);
+}
+
static void mmio_invalidate_full(struct intel_gt *gt)
{
static const i915_reg_t gen8_regs[] = {
@@ -980,6 +1065,13 @@ static void mmio_invalidate_full(struct intel_gt *gt)
[COPY_ENGINE_CLASS] = GEN12_BLT_TLB_INV_CR,
[COMPUTE_CLASS] = GEN12_COMPCTX_TLB_INV_CR,
};
+ static const i915_mcr_reg_t xehp_regs[] = {
+ [RENDER_CLASS] = XEHP_GFX_TLB_INV_CR,
+ [VIDEO_DECODE_CLASS] = XEHP_VD_TLB_INV_CR,
+ [VIDEO_ENHANCEMENT_CLASS] = XEHP_VE_TLB_INV_CR,
+ [COPY_ENGINE_CLASS] = XEHP_BLT_TLB_INV_CR,
+ [COMPUTE_CLASS] = XEHP_COMPCTX_TLB_INV_CR,
+ };
struct drm_i915_private *i915 = gt->i915;
struct intel_uncore *uncore = gt->uncore;
struct intel_engine_cs *engine;
@@ -988,7 +1080,10 @@ static void mmio_invalidate_full(struct intel_gt *gt)
const i915_reg_t *regs;
unsigned int num = 0;
- if (GRAPHICS_VER(i915) == 12) {
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ regs = NULL;
+ num = ARRAY_SIZE(xehp_regs);
+ } else if (GRAPHICS_VER(i915) == 12) {
regs = gen12_regs;
num = ARRAY_SIZE(gen12_regs);
} else if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) <= 11) {
@@ -1013,11 +1108,22 @@ static void mmio_invalidate_full(struct intel_gt *gt)
if (!intel_engine_pm_is_awake(engine))
continue;
- rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
- if (!i915_mmio_reg_offset(rb.reg))
- continue;
-
- intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ intel_gt_mcr_multicast_write_fw(gt,
+ xehp_regs[engine->class],
+ BIT(engine->instance));
+ } else {
+ rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+ if (!i915_mmio_reg_offset(rb.reg))
+ continue;
+
+ if (GRAPHICS_VER(i915) == 12 && (engine->class == VIDEO_DECODE_CLASS ||
+ engine->class == VIDEO_ENHANCEMENT_CLASS ||
+ engine->class == COMPUTE_CLASS))
+ rb.bit = _MASKED_BIT_ENABLE(rb.bit);
+
+ intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+ }
awake |= engine->mask;
}
@@ -1037,22 +1143,17 @@ static void mmio_invalidate_full(struct intel_gt *gt)
for_each_engine_masked(engine, gt, awake, tmp) {
struct reg_and_bit rb;
- /*
- * HW architecture suggest typical invalidation time at 40us,
- * with pessimistic cases up to 100us and a recommendation to
- * cap at 1ms. We go a bit higher just in case.
- */
- const unsigned int timeout_us = 100;
- const unsigned int timeout_ms = 4;
-
- rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
- if (__intel_wait_for_register_fw(uncore,
- rb.reg, rb.bit, 0,
- timeout_us, timeout_ms,
- NULL))
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ rb.mcr_reg = xehp_regs[engine->class];
+ rb.bit = BIT(engine->instance);
+ } else {
+ rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+ }
+
+ if (wait_for_invalidate(gt, rb))
drm_err_ratelimited(&gt->i915->drm,
"%s TLB invalidation did not complete in %ums!\n",
- engine->name, timeout_ms);
+ engine->name, TLB_INVAL_TIMEOUT_MS);
}
/*
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h
index 2ee582e287c8..e0365d556248 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt.h
@@ -60,6 +60,7 @@ void intel_gt_driver_late_release_all(struct drm_i915_private *i915);
int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout);
void intel_gt_check_and_clear_faults(struct intel_gt *gt);
+i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt);
void intel_gt_clear_error_registers(struct intel_gt *gt,
intel_engine_mask_t engine_mask);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
index 3f656d3dba9a..2a6a4ca7fdad 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
@@ -107,7 +107,7 @@ static u32 gen9_read_clock_frequency(struct intel_uncore *uncore)
return freq;
}
-static u32 gen5_read_clock_frequency(struct intel_uncore *uncore)
+static u32 gen6_read_clock_frequency(struct intel_uncore *uncore)
{
/*
* PRMs say:
@@ -119,7 +119,27 @@ static u32 gen5_read_clock_frequency(struct intel_uncore *uncore)
return 12500000;
}
-static u32 gen2_read_clock_frequency(struct intel_uncore *uncore)
+static u32 gen5_read_clock_frequency(struct intel_uncore *uncore)
+{
+ /*
+ * 63:32 increments every 1000 ns
+ * 31:0 mbz
+ */
+ return 1000000000 / 1000;
+}
+
+static u32 g4x_read_clock_frequency(struct intel_uncore *uncore)
+{
+ /*
+ * 63:20 increments every 1/4 ns
+ * 19:0 mbz
+ *
+ * -> 63:32 increments every 1024 ns
+ */
+ return 1000000000 / 1024;
+}
+
+static u32 gen4_read_clock_frequency(struct intel_uncore *uncore)
{
/*
* PRMs say:
@@ -127,8 +147,10 @@ static u32 gen2_read_clock_frequency(struct intel_uncore *uncore)
* "The value in this register increments once every 16
* hclks." (through the “Clocking Configuration”
* (“CLKCFG”) MCHBAR register)
+ *
+ * Testing on actual hardware has shown there is no /16.
*/
- return RUNTIME_INFO(uncore->i915)->rawclk_freq * 1000 / 16;
+ return RUNTIME_INFO(uncore->i915)->rawclk_freq * 1000;
}
static u32 read_clock_frequency(struct intel_uncore *uncore)
@@ -137,10 +159,16 @@ static u32 read_clock_frequency(struct intel_uncore *uncore)
return gen11_read_clock_frequency(uncore);
else if (GRAPHICS_VER(uncore->i915) >= 9)
return gen9_read_clock_frequency(uncore);
- else if (GRAPHICS_VER(uncore->i915) >= 5)
+ else if (GRAPHICS_VER(uncore->i915) >= 6)
+ return gen6_read_clock_frequency(uncore);
+ else if (GRAPHICS_VER(uncore->i915) == 5)
return gen5_read_clock_frequency(uncore);
+ else if (IS_G4X(uncore->i915))
+ return g4x_read_clock_frequency(uncore);
+ else if (GRAPHICS_VER(uncore->i915) == 4)
+ return gen4_read_clock_frequency(uncore);
else
- return gen2_read_clock_frequency(uncore);
+ return 0;
}
void intel_gt_init_clock_frequency(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_irq.c b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
index f26882fdc24c..6f6b9e04d916 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_irq.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
@@ -17,6 +17,9 @@
static void guc_irq_handler(struct intel_guc *guc, u16 iir)
{
+ if (unlikely(!guc->interrupts.enabled))
+ return;
+
if (iir & GUC_INTR_GUC2HOST)
intel_guc_to_host_event_handler(guc);
}
@@ -44,8 +47,9 @@ gen11_gt_engine_identity(struct intel_gt *gt,
!time_after32(local_clock() >> 10, timeout_ts));
if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) {
- DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
- bank, bit, ident);
+ drm_err(&gt->i915->drm,
+ "INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
+ bank, bit, ident);
return 0;
}
@@ -81,35 +85,27 @@ gen11_other_irq_handler(struct intel_gt *gt, const u8 instance,
instance, iir);
}
-static void
-gen11_engine_irq_handler(struct intel_gt *gt, const u8 class,
- const u8 instance, const u16 iir)
+static struct intel_gt *pick_gt(struct intel_gt *gt, u8 class, u8 instance)
{
- struct intel_engine_cs *engine;
-
- /*
- * Platforms with standalone media have their media engines in another
- * GT.
- */
- if (MEDIA_VER(gt->i915) >= 13 &&
- (class == VIDEO_DECODE_CLASS || class == VIDEO_ENHANCEMENT_CLASS)) {
- if (!gt->i915->media_gt)
- goto err;
+ struct intel_gt *media_gt = gt->i915->media_gt;
- gt = gt->i915->media_gt;
+ /* we expect the non-media gt to be passed in */
+ GEM_BUG_ON(gt == media_gt);
+
+ if (!media_gt)
+ return gt;
+
+ switch (class) {
+ case VIDEO_DECODE_CLASS:
+ case VIDEO_ENHANCEMENT_CLASS:
+ return media_gt;
+ case OTHER_CLASS:
+ if (instance == OTHER_GSC_INSTANCE && HAS_ENGINE(media_gt, GSC0))
+ return media_gt;
+ fallthrough;
+ default:
+ return gt;
}
-
- if (instance <= MAX_ENGINE_INSTANCE)
- engine = gt->engine_class[class][instance];
- else
- engine = NULL;
-
- if (likely(engine))
- return intel_engine_cs_irq(engine, iir);
-
-err:
- WARN_ONCE(1, "unhandled engine interrupt class=0x%x, instance=0x%x\n",
- class, instance);
}
static void
@@ -122,8 +118,17 @@ gen11_gt_identity_handler(struct intel_gt *gt, const u32 identity)
if (unlikely(!intr))
return;
- if (class <= COPY_ENGINE_CLASS || class == COMPUTE_CLASS)
- return gen11_engine_irq_handler(gt, class, instance, intr);
+ /*
+ * Platforms with standalone media have the media and GSC engines in
+ * another GT.
+ */
+ gt = pick_gt(gt, class, instance);
+
+ if (class <= MAX_ENGINE_CLASS && instance <= MAX_ENGINE_INSTANCE) {
+ struct intel_engine_cs *engine = gt->engine_class[class][instance];
+ if (engine)
+ return intel_engine_cs_irq(engine, intr);
+ }
if (class == OTHER_CLASS)
return gen11_other_irq_handler(gt, instance, intr);
@@ -206,7 +211,7 @@ void gen11_gt_irq_reset(struct intel_gt *gt)
intel_uncore_write(uncore, GEN11_VCS_VECS_INTR_ENABLE, 0);
if (CCS_MASK(gt))
intel_uncore_write(uncore, GEN12_CCS_RSVD_INTR_ENABLE, 0);
- if (HAS_HECI_GSC(gt->i915))
+ if (HAS_HECI_GSC(gt->i915) || HAS_ENGINE(gt, GSC0))
intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE, 0);
/* Restore masks irqs on RCS, BCS, VCS and VECS engines. */
@@ -233,7 +238,7 @@ void gen11_gt_irq_reset(struct intel_gt *gt)
intel_uncore_write(uncore, GEN12_CCS0_CCS1_INTR_MASK, ~0);
if (HAS_ENGINE(gt, CCS2) || HAS_ENGINE(gt, CCS3))
intel_uncore_write(uncore, GEN12_CCS2_CCS3_INTR_MASK, ~0);
- if (HAS_HECI_GSC(gt->i915))
+ if (HAS_HECI_GSC(gt->i915) || HAS_ENGINE(gt, GSC0))
intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_MASK, ~0);
intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0);
@@ -249,7 +254,8 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
{
struct intel_uncore *uncore = gt->uncore;
u32 irqs = GT_RENDER_USER_INTERRUPT;
- const u32 gsc_mask = GSC_IRQ_INTF(0) | GSC_IRQ_INTF(1);
+ u32 guc_mask = intel_uc_wants_guc(&gt->uc) ? GUC_INTR_GUC2HOST : 0;
+ u32 gsc_mask = 0;
u32 dmask;
u32 smask;
@@ -261,6 +267,11 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
dmask = irqs << 16 | irqs;
smask = irqs << 16;
+ if (HAS_ENGINE(gt, GSC0))
+ gsc_mask = irqs;
+ else if (HAS_HECI_GSC(gt->i915))
+ gsc_mask = GSC_IRQ_INTF(0) | GSC_IRQ_INTF(1);
+
BUILD_BUG_ON(irqs & 0xffff0000);
/* Enable RCS, BCS, VCS and VECS class interrupts. */
@@ -268,9 +279,8 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
intel_uncore_write(uncore, GEN11_VCS_VECS_INTR_ENABLE, dmask);
if (CCS_MASK(gt))
intel_uncore_write(uncore, GEN12_CCS_RSVD_INTR_ENABLE, smask);
- if (HAS_HECI_GSC(gt->i915))
- intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE,
- gsc_mask);
+ if (gsc_mask)
+ intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE, gsc_mask);
/* Unmask irqs on RCS, BCS, VCS and VECS engines. */
intel_uncore_write(uncore, GEN11_RCS0_RSVD_INTR_MASK, ~smask);
@@ -296,9 +306,22 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
intel_uncore_write(uncore, GEN12_CCS0_CCS1_INTR_MASK, ~dmask);
if (HAS_ENGINE(gt, CCS2) || HAS_ENGINE(gt, CCS3))
intel_uncore_write(uncore, GEN12_CCS2_CCS3_INTR_MASK, ~dmask);
- if (HAS_HECI_GSC(gt->i915))
+ if (gsc_mask)
intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_MASK, ~gsc_mask);
+ if (guc_mask) {
+ /* the enable bit is common for both GTs but the masks are separate */
+ u32 mask = gt->type == GT_MEDIA ?
+ REG_FIELD_PREP(ENGINE0_MASK, guc_mask) :
+ REG_FIELD_PREP(ENGINE1_MASK, guc_mask);
+
+ intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE,
+ REG_FIELD_PREP(ENGINE1_MASK, guc_mask));
+
+ /* we might not be the first GT to write this reg */
+ intel_uncore_rmw(uncore, MTL_GUC_MGUC_INTR_MASK, mask, 0);
+ }
+
/*
* RPS interrupts will get enabled/disabled on demand when RPS itself
* is enabled/disabled.
@@ -307,10 +330,6 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
gt->pm_imr = ~gt->pm_ier;
intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0);
intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK, ~0);
-
- /* Same thing for GuC interrupts */
- intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE, 0);
- intel_uncore_write(uncore, GEN11_GUC_SG_INTR_MASK, ~0);
}
void gen5_gt_irq_handler(struct intel_gt *gt, u32 gt_iir)
@@ -359,7 +378,8 @@ void gen6_gt_irq_handler(struct intel_gt *gt, u32 gt_iir)
if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
GT_BSD_CS_ERROR_INTERRUPT |
GT_CS_MASTER_ERROR_INTERRUPT))
- DRM_DEBUG("Command parser error, gt_iir 0x%08x\n", gt_iir);
+ drm_dbg(&gt->i915->drm, "Command parser error, gt_iir 0x%08x\n",
+ gt_iir);
if (gt_iir & GT_PARITY_ERROR(gt->i915))
gen7_parity_error_irq_handler(gt, gt_iir);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
index e79405a45312..d9a8ff9e5e57 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
@@ -40,6 +40,9 @@ static const char * const intel_steering_types[] = {
"L3BANK",
"MSLICE",
"LNCF",
+ "GAM",
+ "DSS",
+ "OADDRM",
"INSTANCE 0",
};
@@ -48,14 +51,23 @@ static const struct intel_mmio_range icl_l3bank_steering_table[] = {
{},
};
+/*
+ * Although the bspec lists more "MSLICE" ranges than shown here, some of those
+ * are of a "GAM" subclass that has special rules. Thus we use a separate
+ * GAM table farther down for those.
+ */
static const struct intel_mmio_range xehpsdv_mslice_steering_table[] = {
- { 0x004000, 0x004AFF },
- { 0x00C800, 0x00CFFF },
{ 0x00DD00, 0x00DDFF },
{ 0x00E900, 0x00FFFF }, /* 0xEA00 - OxEFFF is unused */
{},
};
+static const struct intel_mmio_range xehpsdv_gam_steering_table[] = {
+ { 0x004000, 0x004AFF },
+ { 0x00C800, 0x00CFFF },
+ {},
+};
+
static const struct intel_mmio_range xehpsdv_lncf_steering_table[] = {
{ 0x00B000, 0x00B0FF },
{ 0x00D800, 0x00D8FF },
@@ -89,9 +101,47 @@ static const struct intel_mmio_range pvc_instance0_steering_table[] = {
{},
};
+static const struct intel_mmio_range xelpg_instance0_steering_table[] = {
+ { 0x000B00, 0x000BFF }, /* SQIDI */
+ { 0x001000, 0x001FFF }, /* SQIDI */
+ { 0x004000, 0x0048FF }, /* GAM */
+ { 0x008700, 0x0087FF }, /* SQIDI */
+ { 0x00B000, 0x00B0FF }, /* NODE */
+ { 0x00C800, 0x00CFFF }, /* GAM */
+ { 0x00D880, 0x00D8FF }, /* NODE */
+ { 0x00DD00, 0x00DDFF }, /* OAAL2 */
+ {},
+};
+
+static const struct intel_mmio_range xelpg_l3bank_steering_table[] = {
+ { 0x00B100, 0x00B3FF },
+ {},
+};
+
+/* DSS steering is used for SLICE ranges as well */
+static const struct intel_mmio_range xelpg_dss_steering_table[] = {
+ { 0x005200, 0x0052FF }, /* SLICE */
+ { 0x005500, 0x007FFF }, /* SLICE */
+ { 0x008140, 0x00815F }, /* SLICE (0x8140-0x814F), DSS (0x8150-0x815F) */
+ { 0x0094D0, 0x00955F }, /* SLICE (0x94D0-0x951F), DSS (0x9520-0x955F) */
+ { 0x009680, 0x0096FF }, /* DSS */
+ { 0x00D800, 0x00D87F }, /* SLICE */
+ { 0x00DC00, 0x00DCFF }, /* SLICE */
+ { 0x00DE80, 0x00E8FF }, /* DSS (0xE000-0xE0FF reserved) */
+ {},
+};
+
+static const struct intel_mmio_range xelpmp_oaddrm_steering_table[] = {
+ { 0x393200, 0x39323F },
+ { 0x393400, 0x3934FF },
+ {},
+};
+
void intel_gt_mcr_init(struct intel_gt *gt)
{
struct drm_i915_private *i915 = gt->i915;
+ unsigned long fuse;
+ int i;
/*
* An mslice is unavailable only if both the meml3 for the slice is
@@ -109,14 +159,36 @@ void intel_gt_mcr_init(struct intel_gt *gt)
drm_warn(&i915->drm, "mslice mask all zero!\n");
}
- if (IS_PONTEVECCHIO(i915)) {
+ if (MEDIA_VER(i915) >= 13 && gt->type == GT_MEDIA) {
+ gt->steering_table[OADDRM] = xelpmp_oaddrm_steering_table;
+ } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) {
+ fuse = REG_FIELD_GET(GT_L3_EXC_MASK,
+ intel_uncore_read(gt->uncore, XEHP_FUSE4));
+
+ /*
+ * Despite the register field being named "exclude mask" the
+ * bits actually represent enabled banks (two banks per bit).
+ */
+ for_each_set_bit(i, &fuse, 3)
+ gt->info.l3bank_mask |= 0x3 << 2 * i;
+
+ gt->steering_table[INSTANCE0] = xelpg_instance0_steering_table;
+ gt->steering_table[L3BANK] = xelpg_l3bank_steering_table;
+ gt->steering_table[DSS] = xelpg_dss_steering_table;
+ } else if (IS_PONTEVECCHIO(i915)) {
gt->steering_table[INSTANCE0] = pvc_instance0_steering_table;
} else if (IS_DG2(i915)) {
gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table;
gt->steering_table[LNCF] = dg2_lncf_steering_table;
+ /*
+ * No need to hook up the GAM table since it has a dedicated
+ * steering control register on DG2 and can use implicit
+ * steering.
+ */
} else if (IS_XEHPSDV(i915)) {
gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table;
gt->steering_table[LNCF] = xehpsdv_lncf_steering_table;
+ gt->steering_table[GAM] = xehpsdv_gam_steering_table;
} else if (GRAPHICS_VER(i915) >= 11 &&
GRAPHICS_VER_FULL(i915) < IP_VER(12, 50)) {
gt->steering_table[L3BANK] = icl_l3bank_steering_table;
@@ -135,6 +207,19 @@ void intel_gt_mcr_init(struct intel_gt *gt)
}
/*
+ * Although the rest of the driver should use MCR-specific functions to
+ * read/write MCR registers, we still use the regular intel_uncore_* functions
+ * internally to implement those, so we need a way for the functions in this
+ * file to "cast" an i915_mcr_reg_t into an i915_reg_t.
+ */
+static i915_reg_t mcr_reg_cast(const i915_mcr_reg_t mcr)
+{
+ i915_reg_t r = { .reg = mcr.reg };
+
+ return r;
+}
+
+/*
* rw_with_mcr_steering_fw - Access a register with specific MCR steering
* @uncore: pointer to struct intel_uncore
* @reg: register being accessed
@@ -148,14 +233,26 @@ void intel_gt_mcr_init(struct intel_gt *gt)
* Caller needs to make sure the relevant forcewake wells are up.
*/
static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
- i915_reg_t reg, u8 rw_flag,
+ i915_mcr_reg_t reg, u8 rw_flag,
int group, int instance, u32 value)
{
u32 mcr_mask, mcr_ss, mcr, old_mcr, val = 0;
lockdep_assert_held(&uncore->lock);
- if (GRAPHICS_VER(uncore->i915) >= 11) {
+ if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70)) {
+ /*
+ * Always leave the hardware in multicast mode when doing reads
+ * (see comment about Wa_22013088509 below) and only change it
+ * to unicast mode when doing writes of a specific instance.
+ *
+ * No need to save old steering reg value.
+ */
+ intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR,
+ REG_FIELD_PREP(MTL_MCR_GROUPID, group) |
+ REG_FIELD_PREP(MTL_MCR_INSTANCEID, instance) |
+ (rw_flag == FW_REG_READ ? GEN11_MCR_MULTICAST : 0));
+ } else if (GRAPHICS_VER(uncore->i915) >= 11) {
mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK;
mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance);
@@ -173,39 +270,53 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
*/
if (rw_flag == FW_REG_WRITE)
mcr_mask |= GEN11_MCR_MULTICAST;
+
+ mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
+ old_mcr = mcr;
+
+ mcr &= ~mcr_mask;
+ mcr |= mcr_ss;
+ intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
} else {
mcr_mask = GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK;
mcr_ss = GEN8_MCR_SLICE(group) | GEN8_MCR_SUBSLICE(instance);
- }
- old_mcr = mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
+ mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
+ old_mcr = mcr;
- mcr &= ~mcr_mask;
- mcr |= mcr_ss;
- intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
+ mcr &= ~mcr_mask;
+ mcr |= mcr_ss;
+ intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
+ }
if (rw_flag == FW_REG_READ)
- val = intel_uncore_read_fw(uncore, reg);
+ val = intel_uncore_read_fw(uncore, mcr_reg_cast(reg));
else
- intel_uncore_write_fw(uncore, reg, value);
-
- mcr &= ~mcr_mask;
- mcr |= old_mcr & mcr_mask;
+ intel_uncore_write_fw(uncore, mcr_reg_cast(reg), value);
- intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
+ /*
+ * For pre-MTL platforms, we need to restore the old value of the
+ * steering control register to ensure that implicit steering continues
+ * to behave as expected. For MTL and beyond, we need only reinstate
+ * the 'multicast' bit (and only if we did a write that cleared it).
+ */
+ if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70) && rw_flag == FW_REG_WRITE)
+ intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
+ else if (GRAPHICS_VER_FULL(uncore->i915) < IP_VER(12, 70))
+ intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, old_mcr);
return val;
}
static u32 rw_with_mcr_steering(struct intel_uncore *uncore,
- i915_reg_t reg, u8 rw_flag,
+ i915_mcr_reg_t reg, u8 rw_flag,
int group, int instance,
u32 value)
{
enum forcewake_domains fw_domains;
u32 val;
- fw_domains = intel_uncore_forcewake_for_reg(uncore, reg,
+ fw_domains = intel_uncore_forcewake_for_reg(uncore, mcr_reg_cast(reg),
rw_flag);
fw_domains |= intel_uncore_forcewake_for_reg(uncore,
GEN8_MCR_SELECTOR,
@@ -233,7 +344,7 @@ static u32 rw_with_mcr_steering(struct intel_uncore *uncore,
* group/instance.
*/
u32 intel_gt_mcr_read(struct intel_gt *gt,
- i915_reg_t reg,
+ i915_mcr_reg_t reg,
int group, int instance)
{
return rw_with_mcr_steering(gt->uncore, reg, FW_REG_READ, group, instance, 0);
@@ -250,7 +361,7 @@ u32 intel_gt_mcr_read(struct intel_gt *gt,
* Write an MCR register in unicast mode after steering toward a specific
* group/instance.
*/
-void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_reg_t reg, u32 value,
+void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value,
int group, int instance)
{
rw_with_mcr_steering(gt->uncore, reg, FW_REG_WRITE, group, instance, value);
@@ -265,9 +376,16 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_reg_t reg, u32 value,
* Write an MCR register in multicast mode to update all instances.
*/
void intel_gt_mcr_multicast_write(struct intel_gt *gt,
- i915_reg_t reg, u32 value)
+ i915_mcr_reg_t reg, u32 value)
{
- intel_uncore_write(gt->uncore, reg, value);
+ /*
+ * Ensure we have multicast behavior, just in case some non-i915 agent
+ * left the hardware in unicast mode.
+ */
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+ intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
+
+ intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value);
}
/**
@@ -281,9 +399,44 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt,
* domains; use intel_gt_mcr_multicast_write() in cases where forcewake should
* be obtained automatically.
*/
-void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 value)
+void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value)
{
- intel_uncore_write_fw(gt->uncore, reg, value);
+ /*
+ * Ensure we have multicast behavior, just in case some non-i915 agent
+ * left the hardware in unicast mode.
+ */
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+ intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
+
+ intel_uncore_write_fw(gt->uncore, mcr_reg_cast(reg), value);
+}
+
+/**
+ * intel_gt_mcr_multicast_rmw - Performs a multicast RMW operations
+ * @gt: GT structure
+ * @reg: the MCR register to read and write
+ * @clear: bits to clear during RMW
+ * @set: bits to set during RMW
+ *
+ * Performs a read-modify-write on an MCR register in a multicast manner.
+ * This operation only makes sense on MCR registers where all instances are
+ * expected to have the same value. The read will target any non-terminated
+ * instance and the write will be applied to all instances.
+ *
+ * This function assumes the caller is already holding any necessary forcewake
+ * domains; use intel_gt_mcr_multicast_rmw() in cases where forcewake should
+ * be obtained automatically.
+ *
+ * Returns the old (unmodified) value read.
+ */
+u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg,
+ u32 clear, u32 set)
+{
+ u32 val = intel_gt_mcr_read_any(gt, reg);
+
+ intel_gt_mcr_multicast_write(gt, reg, (val & ~clear) | set);
+
+ return val;
}
/*
@@ -301,7 +454,7 @@ void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 va
* for @type steering too.
*/
static bool reg_needs_read_steering(struct intel_gt *gt,
- i915_reg_t reg,
+ i915_mcr_reg_t reg,
enum intel_steering_type type)
{
const u32 offset = i915_mmio_reg_offset(reg);
@@ -332,6 +485,8 @@ static void get_nonterminated_steering(struct intel_gt *gt,
enum intel_steering_type type,
u8 *group, u8 *instance)
{
+ u32 dss;
+
switch (type) {
case L3BANK:
*group = 0; /* unused */
@@ -351,6 +506,15 @@ static void get_nonterminated_steering(struct intel_gt *gt,
*group = __ffs(gt->info.mslice_mask) << 1;
*instance = 0; /* unused */
break;
+ case GAM:
+ *group = IS_DG2(gt->i915) ? 1 : 0;
+ *instance = 0;
+ break;
+ case DSS:
+ dss = intel_sseu_find_first_xehp_dss(&gt->info.sseu, 0, 0);
+ *group = dss / GEN_DSS_PER_GSLICE;
+ *instance = dss % GEN_DSS_PER_GSLICE;
+ break;
case INSTANCE0:
/*
* There are a lot of MCR types for which instance (0, 0)
@@ -359,6 +523,13 @@ static void get_nonterminated_steering(struct intel_gt *gt,
*group = 0;
*instance = 0;
break;
+ case OADDRM:
+ if ((VDBOX_MASK(gt) | VEBOX_MASK(gt) | gt->info.sfc_mask) & BIT(0))
+ *group = 0;
+ else
+ *group = 1;
+ *instance = 0;
+ break;
default:
MISSING_CASE(type);
*group = 0;
@@ -380,7 +551,7 @@ static void get_nonterminated_steering(struct intel_gt *gt,
* steering.
*/
void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt,
- i915_reg_t reg,
+ i915_mcr_reg_t reg,
u8 *group, u8 *instance)
{
int type;
@@ -409,7 +580,7 @@ void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt,
*
* Returns the value from a non-terminated instance of @reg.
*/
-u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg)
+u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg)
{
int type;
u8 group, instance;
@@ -423,7 +594,7 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg)
}
}
- return intel_uncore_read_fw(gt->uncore, reg);
+ return intel_uncore_read_fw(gt->uncore, mcr_reg_cast(reg));
}
/**
@@ -436,7 +607,7 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg)
*
* Returns the value from a non-terminated instance of @reg.
*/
-u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg)
+u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg)
{
int type;
u8 group, instance;
@@ -450,7 +621,7 @@ u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg)
}
}
- return intel_uncore_read(gt->uncore, reg);
+ return intel_uncore_read(gt->uncore, mcr_reg_cast(reg));
}
static void report_steering_type(struct drm_printer *p,
@@ -483,11 +654,20 @@ static void report_steering_type(struct drm_printer *p,
void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt,
bool dump_table)
{
- drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n",
- gt->default_steering.groupid,
- gt->default_steering.instanceid);
-
- if (IS_PONTEVECCHIO(gt->i915)) {
+ /*
+ * Starting with MTL we no longer have default steering;
+ * all ranges are explicitly steered.
+ */
+ if (GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70))
+ drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n",
+ gt->default_steering.groupid,
+ gt->default_steering.instanceid);
+
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) {
+ for (int i = 0; i < NUM_STEERING_TYPES; i++)
+ if (gt->steering_table[i])
+ report_steering_type(p, gt, i, dump_table);
+ } else if (IS_PONTEVECCHIO(gt->i915)) {
report_steering_type(p, gt, INSTANCE0, dump_table);
} else if (HAS_MSLICE_STEERING(gt->i915)) {
report_steering_type(p, gt, MSLICE, dump_table);
@@ -520,3 +700,60 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss,
return;
}
}
+
+/**
+ * intel_gt_mcr_wait_for_reg_fw - wait until MCR register matches expected state
+ * @gt: GT structure
+ * @reg: the register to read
+ * @mask: mask to apply to register value
+ * @value: value to wait for
+ * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait
+ * @slow_timeout_ms: slow timeout in millisecond
+ *
+ * This routine waits until the target register @reg contains the expected
+ * @value after applying the @mask, i.e. it waits until ::
+ *
+ * (intel_gt_mcr_read_any_fw(gt, reg) & mask) == value
+ *
+ * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds.
+ * For atomic context @slow_timeout_ms must be zero and @fast_timeout_us
+ * must be not larger than 20,0000 microseconds.
+ *
+ * This function is basically an MCR-friendly version of
+ * __intel_wait_for_register_fw(). Generally this function will only be used
+ * on GAM registers which are a bit special --- although they're MCR registers,
+ * reads (e.g., waiting for status updates) are always directed to the primary
+ * instance.
+ *
+ * Note that this routine assumes the caller holds forcewake asserted, it is
+ * not suitable for very long waits.
+ *
+ * Return: 0 if the register matches the desired condition, or -ETIMEDOUT.
+ */
+int intel_gt_mcr_wait_for_reg(struct intel_gt *gt,
+ i915_mcr_reg_t reg,
+ u32 mask,
+ u32 value,
+ unsigned int fast_timeout_us,
+ unsigned int slow_timeout_ms)
+{
+ int ret;
+
+ lockdep_assert_not_held(&gt->uncore->lock);
+
+#define done ((intel_gt_mcr_read_any(gt, reg) & mask) == value)
+
+ /* Catch any overuse of this function */
+ might_sleep_if(slow_timeout_ms);
+ GEM_BUG_ON(fast_timeout_us > 20000);
+ GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms);
+
+ ret = -ETIMEDOUT;
+ if (fast_timeout_us && fast_timeout_us <= 20000)
+ ret = _wait_for_atomic(done, fast_timeout_us, 0);
+ if (ret && slow_timeout_ms)
+ ret = wait_for(done, slow_timeout_ms);
+
+ return ret;
+#undef done
+}
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
index 77a8b11c287d..ae93b20e1c17 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
@@ -11,21 +11,24 @@
void intel_gt_mcr_init(struct intel_gt *gt);
u32 intel_gt_mcr_read(struct intel_gt *gt,
- i915_reg_t reg,
+ i915_mcr_reg_t reg,
int group, int instance);
-u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg);
-u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg);
+u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg);
+u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg);
void intel_gt_mcr_unicast_write(struct intel_gt *gt,
- i915_reg_t reg, u32 value,
+ i915_mcr_reg_t reg, u32 value,
int group, int instance);
void intel_gt_mcr_multicast_write(struct intel_gt *gt,
- i915_reg_t reg, u32 value);
+ i915_mcr_reg_t reg, u32 value);
void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt,
- i915_reg_t reg, u32 value);
+ i915_mcr_reg_t reg, u32 value);
+
+u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg,
+ u32 clear, u32 set);
void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt,
- i915_reg_t reg,
+ i915_mcr_reg_t reg,
u8 *group, u8 *instance);
void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt,
@@ -34,6 +37,13 @@ void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt,
void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss,
unsigned int *group, unsigned int *instance);
+int intel_gt_mcr_wait_for_reg(struct intel_gt *gt,
+ i915_mcr_reg_t reg,
+ u32 mask,
+ u32 value,
+ unsigned int fast_timeout_us,
+ unsigned int slow_timeout_ms);
+
/*
* Helper for for_each_ss_steering loop. On pre-Xe_HP platforms, subslice
* presence is determined by using the group/instance as direct lookups in the
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
index f553e2173bda..16db85fab0b1 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
@@ -7,6 +7,7 @@
#include <linux/suspend.h>
#include "i915_drv.h"
+#include "i915_irq.h"
#include "i915_params.h"
#include "intel_context.h"
#include "intel_engine_pm.h"
@@ -19,10 +20,31 @@
#include "intel_rc6.h"
#include "intel_rps.h"
#include "intel_wakeref.h"
+#include "intel_pcode.h"
#include "pxp/intel_pxp_pm.h"
#define I915_GT_SUSPEND_IDLE_TIMEOUT (HZ / 2)
+static void mtl_media_busy(struct intel_gt *gt)
+{
+ /* Wa_14017073508: mtl */
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0) &&
+ gt->type == GT_MEDIA)
+ snb_pcode_write_p(gt->uncore, PCODE_MBOX_GT_STATE,
+ PCODE_MBOX_GT_STATE_MEDIA_BUSY,
+ PCODE_MBOX_GT_STATE_DOMAIN_MEDIA, 0);
+}
+
+static void mtl_media_idle(struct intel_gt *gt)
+{
+ /* Wa_14017073508: mtl */
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0) &&
+ gt->type == GT_MEDIA)
+ snb_pcode_write_p(gt->uncore, PCODE_MBOX_GT_STATE,
+ PCODE_MBOX_GT_STATE_MEDIA_NOT_BUSY,
+ PCODE_MBOX_GT_STATE_DOMAIN_MEDIA, 0);
+}
+
static void user_forcewake(struct intel_gt *gt, bool suspend)
{
int count = atomic_read(&gt->user_wakeref);
@@ -70,6 +92,9 @@ static int __gt_unpark(struct intel_wakeref *wf)
GT_TRACE(gt, "\n");
+ /* Wa_14017073508: mtl */
+ mtl_media_busy(gt);
+
/*
* It seems that the DMC likes to transition between the DC states a lot
* when there are no connected displays (no active power domains) during
@@ -119,6 +144,9 @@ static int __gt_park(struct intel_wakeref *wf)
GEM_BUG_ON(!wakeref);
intel_display_power_put_async(i915, POWER_DOMAIN_GT_IRQ, wakeref);
+ /* Wa_14017073508: mtl */
+ mtl_media_idle(gt);
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c
index 108b9e76c32e..83df4cd5e06c 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c
@@ -83,19 +83,6 @@ static int fw_domains_show(struct seq_file *m, void *data)
}
DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(fw_domains);
-static void print_rc6_res(struct seq_file *m,
- const char *title,
- const i915_reg_t reg)
-{
- struct intel_gt *gt = m->private;
- intel_wakeref_t wakeref;
-
- with_intel_runtime_pm(gt->uncore->rpm, wakeref)
- seq_printf(m, "%s %u (%llu us)\n", title,
- intel_uncore_read(gt->uncore, reg),
- intel_rc6_residency_us(&gt->rc6, reg));
-}
-
static int vlv_drpc(struct seq_file *m)
{
struct intel_gt *gt = m->private;
@@ -115,8 +102,8 @@ static int vlv_drpc(struct seq_file *m)
seq_printf(m, "Media Power Well: %s\n",
(pw_status & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down");
- print_rc6_res(m, "Render RC6 residency since boot:", GEN6_GT_GFX_RC6);
- print_rc6_res(m, "Media RC6 residency since boot:", VLV_GT_MEDIA_RC6);
+ intel_rc6_print_residency(m, "Render RC6 residency since boot:", INTEL_RC6_RES_RC6);
+ intel_rc6_print_residency(m, "Media RC6 residency since boot:", INTEL_RC6_RES_VLV_MEDIA);
return fw_domains_show(m, NULL);
}
@@ -192,11 +179,11 @@ static int gen6_drpc(struct seq_file *m)
}
/* Not exactly sure what this is */
- print_rc6_res(m, "RC6 \"Locked to RPn\" residency since boot:",
- GEN6_GT_GFX_RC6_LOCKED);
- print_rc6_res(m, "RC6 residency since boot:", GEN6_GT_GFX_RC6);
- print_rc6_res(m, "RC6+ residency since boot:", GEN6_GT_GFX_RC6p);
- print_rc6_res(m, "RC6++ residency since boot:", GEN6_GT_GFX_RC6pp);
+ intel_rc6_print_residency(m, "RC6 \"Locked to RPn\" residency since boot:",
+ INTEL_RC6_RES_RC6_LOCKED);
+ intel_rc6_print_residency(m, "RC6 residency since boot:", INTEL_RC6_RES_RC6);
+ intel_rc6_print_residency(m, "RC6+ residency since boot:", INTEL_RC6_RES_RC6p);
+ intel_rc6_print_residency(m, "RC6++ residency since boot:", INTEL_RC6_RES_RC6pp);
if (GRAPHICS_VER(i915) <= 7) {
seq_printf(m, "RC6 voltage: %dmV\n",
@@ -269,6 +256,61 @@ static int ilk_drpc(struct seq_file *m)
return 0;
}
+static int mtl_drpc(struct seq_file *m)
+{
+ struct intel_gt *gt = m->private;
+ struct intel_uncore *uncore = gt->uncore;
+ u32 gt_core_status, rcctl1, mt_fwake_req;
+ u32 mtl_powergate_enable = 0, mtl_powergate_status = 0;
+
+ mt_fwake_req = intel_uncore_read_fw(uncore, FORCEWAKE_MT);
+ gt_core_status = intel_uncore_read(uncore, MTL_MIRROR_TARGET_WP1);
+
+ rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL);
+ mtl_powergate_enable = intel_uncore_read(uncore, GEN9_PG_ENABLE);
+ mtl_powergate_status = intel_uncore_read(uncore,
+ GEN9_PWRGT_DOMAIN_STATUS);
+
+ seq_printf(m, "RC6 Enabled: %s\n",
+ str_yes_no(rcctl1 & GEN6_RC_CTL_RC6_ENABLE));
+ if (gt->type == GT_MEDIA) {
+ seq_printf(m, "Media Well Gating Enabled: %s\n",
+ str_yes_no(mtl_powergate_enable & GEN9_MEDIA_PG_ENABLE));
+ } else {
+ seq_printf(m, "Render Well Gating Enabled: %s\n",
+ str_yes_no(mtl_powergate_enable & GEN9_RENDER_PG_ENABLE));
+ }
+
+ seq_puts(m, "Current RC state: ");
+ switch (REG_FIELD_GET(MTL_CC_MASK, gt_core_status)) {
+ case MTL_CC0:
+ seq_puts(m, "RC0\n");
+ break;
+ case MTL_CC6:
+ seq_puts(m, "RC6\n");
+ break;
+ default:
+ MISSING_CASE(REG_FIELD_GET(MTL_CC_MASK, gt_core_status));
+ seq_puts(m, "Unknown\n");
+ break;
+ }
+
+ seq_printf(m, "Multi-threaded Forcewake Request: 0x%x\n", mt_fwake_req);
+ if (gt->type == GT_MEDIA)
+ seq_printf(m, "Media Power Well: %s\n",
+ (mtl_powergate_status &
+ GEN9_PWRGT_MEDIA_STATUS_MASK) ? "Up" : "Down");
+ else
+ seq_printf(m, "Render Power Well: %s\n",
+ (mtl_powergate_status &
+ GEN9_PWRGT_RENDER_STATUS_MASK) ? "Up" : "Down");
+
+ /* Works for both render and media gt's */
+ intel_rc6_print_residency(m, "RC6 residency since boot:", INTEL_RC6_RES_RC6);
+
+ return fw_domains_show(m, NULL);
+}
+
static int drpc_show(struct seq_file *m, void *unused)
{
struct intel_gt *gt = m->private;
@@ -277,7 +319,9 @@ static int drpc_show(struct seq_file *m, void *unused)
int err = -ENODEV;
with_intel_runtime_pm(gt->uncore->rpm, wakeref) {
- if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
+ err = mtl_drpc(m);
+ else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
err = vlv_drpc(m);
else if (GRAPHICS_VER(i915) >= 6)
err = gen6_drpc(m);
@@ -307,7 +351,7 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p)
drm_printf(p, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
MEMSTAT_VID_SHIFT);
drm_printf(p, "Current P-state: %d\n",
- (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
+ REG_FIELD_GET(MEMSTAT_PSTATE_MASK, rgvstat));
} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
u32 rpmodectl, freq_sts;
@@ -344,162 +388,7 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p)
drm_printf(p, "efficient (RPe) frequency: %d MHz\n",
intel_gpu_freq(rps, rps->efficient_freq));
} else if (GRAPHICS_VER(i915) >= 6) {
- u32 rp_state_limits;
- u32 gt_perf_status;
- struct intel_rps_freq_caps caps;
- u32 rpmodectl, rpinclimit, rpdeclimit;
- u32 rpstat, cagf, reqf;
- u32 rpcurupei, rpcurup, rpprevup;
- u32 rpcurdownei, rpcurdown, rpprevdown;
- u32 rpupei, rpupt, rpdownei, rpdownt;
- u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
-
- rp_state_limits = intel_uncore_read(uncore, GEN6_RP_STATE_LIMITS);
- gen6_rps_get_freq_caps(rps, &caps);
- if (IS_GEN9_LP(i915))
- gt_perf_status = intel_uncore_read(uncore, BXT_GT_PERF_STATUS);
- else
- gt_perf_status = intel_uncore_read(uncore, GEN6_GT_PERF_STATUS);
-
- /* RPSTAT1 is in the GT power well */
- intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
-
- reqf = intel_uncore_read(uncore, GEN6_RPNSWREQ);
- if (GRAPHICS_VER(i915) >= 9) {
- reqf >>= 23;
- } else {
- reqf &= ~GEN6_TURBO_DISABLE;
- if (IS_HASWELL(i915) || IS_BROADWELL(i915))
- reqf >>= 24;
- else
- reqf >>= 25;
- }
- reqf = intel_gpu_freq(rps, reqf);
-
- rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL);
- rpinclimit = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
- rpdeclimit = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
-
- rpstat = intel_uncore_read(uncore, GEN6_RPSTAT1);
- rpcurupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK;
- rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK;
- rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK;
- rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
- rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK;
- rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK;
-
- rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI);
- rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
-
- rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI);
- rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
-
- cagf = intel_rps_read_actual_frequency(rps);
-
- intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
-
- if (GRAPHICS_VER(i915) >= 11) {
- pm_ier = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE);
- pm_imr = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK);
- /*
- * The equivalent to the PM ISR & IIR cannot be read
- * without affecting the current state of the system
- */
- pm_isr = 0;
- pm_iir = 0;
- } else if (GRAPHICS_VER(i915) >= 8) {
- pm_ier = intel_uncore_read(uncore, GEN8_GT_IER(2));
- pm_imr = intel_uncore_read(uncore, GEN8_GT_IMR(2));
- pm_isr = intel_uncore_read(uncore, GEN8_GT_ISR(2));
- pm_iir = intel_uncore_read(uncore, GEN8_GT_IIR(2));
- } else {
- pm_ier = intel_uncore_read(uncore, GEN6_PMIER);
- pm_imr = intel_uncore_read(uncore, GEN6_PMIMR);
- pm_isr = intel_uncore_read(uncore, GEN6_PMISR);
- pm_iir = intel_uncore_read(uncore, GEN6_PMIIR);
- }
- pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
-
- drm_printf(p, "Video Turbo Mode: %s\n",
- str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO));
- drm_printf(p, "HW control enabled: %s\n",
- str_yes_no(rpmodectl & GEN6_RP_ENABLE));
- drm_printf(p, "SW control enabled: %s\n",
- str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
-
- drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
- pm_ier, pm_imr, pm_mask);
- if (GRAPHICS_VER(i915) <= 10)
- drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n",
- pm_isr, pm_iir);
- drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n",
- rps->pm_intrmsk_mbz);
- drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
- drm_printf(p, "Render p-state ratio: %d\n",
- (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8);
- drm_printf(p, "Render p-state VID: %d\n",
- gt_perf_status & 0xff);
- drm_printf(p, "Render p-state limit: %d\n",
- rp_state_limits & 0xff);
- drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat);
- drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl);
- drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit);
- drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit);
- drm_printf(p, "RPNSWREQ: %dMHz\n", reqf);
- drm_printf(p, "CAGF: %dMHz\n", cagf);
- drm_printf(p, "RP CUR UP EI: %d (%lldns)\n",
- rpcurupei,
- intel_gt_pm_interval_to_ns(gt, rpcurupei));
- drm_printf(p, "RP CUR UP: %d (%lldns)\n",
- rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup));
- drm_printf(p, "RP PREV UP: %d (%lldns)\n",
- rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup));
- drm_printf(p, "Up threshold: %d%%\n",
- rps->power.up_threshold);
- drm_printf(p, "RP UP EI: %d (%lldns)\n",
- rpupei, intel_gt_pm_interval_to_ns(gt, rpupei));
- drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n",
- rpupt, intel_gt_pm_interval_to_ns(gt, rpupt));
-
- drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n",
- rpcurdownei,
- intel_gt_pm_interval_to_ns(gt, rpcurdownei));
- drm_printf(p, "RP CUR DOWN: %d (%lldns)\n",
- rpcurdown,
- intel_gt_pm_interval_to_ns(gt, rpcurdown));
- drm_printf(p, "RP PREV DOWN: %d (%lldns)\n",
- rpprevdown,
- intel_gt_pm_interval_to_ns(gt, rpprevdown));
- drm_printf(p, "Down threshold: %d%%\n",
- rps->power.down_threshold);
- drm_printf(p, "RP DOWN EI: %d (%lldns)\n",
- rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei));
- drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n",
- rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt));
-
- drm_printf(p, "Lowest (RPN) frequency: %dMHz\n",
- intel_gpu_freq(rps, caps.min_freq));
- drm_printf(p, "Nominal (RP1) frequency: %dMHz\n",
- intel_gpu_freq(rps, caps.rp1_freq));
- drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n",
- intel_gpu_freq(rps, caps.rp0_freq));
- drm_printf(p, "Max overclocked frequency: %dMHz\n",
- intel_gpu_freq(rps, rps->max_freq));
-
- drm_printf(p, "Current freq: %d MHz\n",
- intel_gpu_freq(rps, rps->cur_freq));
- drm_printf(p, "Actual freq: %d MHz\n", cagf);
- drm_printf(p, "Idle freq: %d MHz\n",
- intel_gpu_freq(rps, rps->idle_freq));
- drm_printf(p, "Min freq: %d MHz\n",
- intel_gpu_freq(rps, rps->min_freq));
- drm_printf(p, "Boost freq: %d MHz\n",
- intel_gpu_freq(rps, rps->boost_freq));
- drm_printf(p, "Max freq: %d MHz\n",
- intel_gpu_freq(rps, rps->max_freq));
- drm_printf(p,
- "efficient (RPe) frequency: %d MHz\n",
- intel_gpu_freq(rps, rps->efficient_freq));
+ gen6_rps_frequency_dump(rps, p);
} else {
drm_puts(p, "no P-state info available\n");
}
@@ -655,6 +544,44 @@ static bool rps_eval(void *data)
DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rps_boost);
+static int perf_limit_reasons_get(void *data, u64 *val)
+{
+ struct intel_gt *gt = data;
+ intel_wakeref_t wakeref;
+
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ *val = intel_uncore_read(gt->uncore, intel_gt_perf_limit_reasons_reg(gt));
+
+ return 0;
+}
+
+static int perf_limit_reasons_clear(void *data, u64 val)
+{
+ struct intel_gt *gt = data;
+ intel_wakeref_t wakeref;
+
+ /*
+ * Clear the upper 16 "log" bits, the lower 16 "status" bits are
+ * read-only. The upper 16 "log" bits are identical to the lower 16
+ * "status" bits except that the "log" bits remain set until cleared.
+ */
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ intel_uncore_rmw(gt->uncore, intel_gt_perf_limit_reasons_reg(gt),
+ GT0_PERF_LIMIT_REASONS_LOG_MASK, 0);
+
+ return 0;
+}
+
+static bool perf_limit_reasons_eval(void *data)
+{
+ struct intel_gt *gt = data;
+
+ return i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt));
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(perf_limit_reasons_fops, perf_limit_reasons_get,
+ perf_limit_reasons_clear, "%llu\n");
+
void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root)
{
static const struct intel_gt_debugfs_file files[] = {
@@ -664,6 +591,7 @@ void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root)
{ "forcewake_user", &forcewake_user_fops, NULL},
{ "llc", &llc_fops, llc_eval },
{ "rps_boost", &rps_boost_fops, rps_eval },
+ { "perf_limit_reasons", &perf_limit_reasons_fops, perf_limit_reasons_eval },
};
intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
index 2275ee47da95..c3cd92691795 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
@@ -7,6 +7,27 @@
#define __INTEL_GT_REGS__
#include "i915_reg_defs.h"
+#include "display/intel_display_reg_defs.h" /* VLV_DISPLAY_BASE */
+
+#define MCR_REG(offset) ((const i915_mcr_reg_t){ .reg = (offset) })
+
+/*
+ * The perf control registers are technically multicast registers, but the
+ * driver never needs to read/write them directly; we only use them to build
+ * lists of registers (where they're mixed in with other non-MCR registers)
+ * and then operate on the offset directly. For now we'll just define them
+ * as non-multicast so we can place them on the same list, but we may want
+ * to try to come up with a better way to handle heterogeneous lists of
+ * registers in the future.
+ */
+#define PERF_REG(offset) _MMIO(offset)
+
+/* MTL workpoint reg to get core C state and actual freq of 3D, SAMedia */
+#define MTL_MIRROR_TARGET_WP1 _MMIO(0xc60)
+#define MTL_CAGF_MASK REG_GENMASK(8, 0)
+#define MTL_CC0 0x0
+#define MTL_CC6 0x3
+#define MTL_CC_MASK REG_GENMASK(12, 9)
/* RPM unit config (Gen8+) */
#define RPM_CONFIG0 _MMIO(0xd00)
@@ -39,9 +60,17 @@
#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0xd84)
#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0xd88)
+#define FORCEWAKE_ACK_GSC _MMIO(0xdf8)
+#define FORCEWAKE_ACK_GT_MTL _MMIO(0xdfc)
+
+#define GMD_ID_GRAPHICS _MMIO(0xd8c)
+#define GMD_ID_MEDIA _MMIO(MTL_MEDIA_GSI_BASE + 0xd8c)
+
#define MCFG_MCR_SELECTOR _MMIO(0xfd0)
+#define MTL_MCR_SELECTOR _MMIO(0xfd4)
#define SF_MCR_SELECTOR _MMIO(0xfd8)
#define GEN8_MCR_SELECTOR _MMIO(0xfdc)
+#define GAM_MCR_SELECTOR _MMIO(0xfe0)
#define GEN8_MCR_SLICE(slice) (((slice) & 3) << 26)
#define GEN8_MCR_SLICE_MASK GEN8_MCR_SLICE(3)
#define GEN8_MCR_SUBSLICE(subslice) (((subslice) & 3) << 24)
@@ -51,6 +80,8 @@
#define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf)
#define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24)
#define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7)
+#define MTL_MCR_GROUPID REG_GENMASK(11, 8)
+#define MTL_MCR_INSTANCEID REG_GENMASK(3, 0)
#define IPEIR_I965 _MMIO(0x2064)
#define IPEHR_I965 _MMIO(0x2068)
@@ -326,11 +357,12 @@
#define GEN7_TLB_RD_ADDR _MMIO(0x4700)
#define GEN12_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4)
+#define XEHP_PAT_INDEX(index) MCR_REG(0x4800 + (index) * 4)
-#define XEHP_TILE0_ADDR_RANGE _MMIO(0x4900)
+#define XEHP_TILE0_ADDR_RANGE MCR_REG(0x4900)
#define XEHP_TILE_LMEM_RANGE_SHIFT 8
-#define XEHP_FLAT_CCS_BASE_ADDR _MMIO(0x4910)
+#define XEHP_FLAT_CCS_BASE_ADDR MCR_REG(0x4910)
#define XEHP_CCS_BASE_SHIFT 8
#define GAMTARBMODE _MMIO(0x4a08)
@@ -380,17 +412,18 @@
#define CHICKEN_RASTER_2 _MMIO(0x6208)
#define TBIMR_FAST_CLIP REG_BIT(5)
-#define VFLSKPD _MMIO(0x62a8)
+#define VFLSKPD MCR_REG(0x62a8)
#define DIS_OVER_FETCH_CACHE REG_BIT(1)
#define DIS_MULT_MISS_RD_SQUASH REG_BIT(0)
-#define FF_MODE2 _MMIO(0x6604)
+#define GEN12_FF_MODE2 _MMIO(0x6604)
+#define XEHP_FF_MODE2 MCR_REG(0x6604)
#define FF_MODE2_GS_TIMER_MASK REG_GENMASK(31, 24)
#define FF_MODE2_GS_TIMER_224 REG_FIELD_PREP(FF_MODE2_GS_TIMER_MASK, 224)
#define FF_MODE2_TDS_TIMER_MASK REG_GENMASK(23, 16)
#define FF_MODE2_TDS_TIMER_128 REG_FIELD_PREP(FF_MODE2_TDS_TIMER_MASK, 4)
-#define XEHPG_INSTDONE_GEOM_SVG _MMIO(0x666c)
+#define XEHPG_INSTDONE_GEOM_SVG MCR_REG(0x666c)
#define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */
#define RC_OP_FLUSH_ENABLE (1 << 0)
@@ -418,6 +451,7 @@
#define HIZ_CHICKEN _MMIO(0x7018)
#define CHV_HZ_8X8_MODE_IN_1X REG_BIT(15)
#define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14)
+#define HZ_DEPTH_TEST_LE_GE_OPT_DISABLE REG_BIT(13)
#define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3)
#define GEN8_L3CNTLREG _MMIO(0x7034)
@@ -439,23 +473,16 @@
#define GEN8_HDC_CHICKEN1 _MMIO(0x7304)
#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304)
+#define XEHP_COMMON_SLICE_CHICKEN3 MCR_REG(0x7304)
#define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12)
#define XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE REG_BIT(12)
#define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11)
#define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9)
-/* GEN9 chicken */
-#define SLICE_ECO_CHICKEN0 _MMIO(0x7308)
-#define PIXEL_MASK_CAMMING_DISABLE (1 << 14)
-
-#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308)
-#define DISABLE_PIXEL_MASK_CAMMING (1 << 14)
-
#define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c)
-#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11)
-
-#define SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c)
+#define XEHP_SLICE_COMMON_ECO_CHICKEN1 MCR_REG(0x731c)
#define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14)
+#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11)
#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice) * 0x4)
#define GEN10_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + ((slice) / 3) * 0x34 + \
@@ -482,9 +509,12 @@
#define VF_PREEMPTION _MMIO(0x83a4)
#define PREEMPTION_VERTEX_COUNT REG_GENMASK(15, 0)
+#define VFG_PREEMPTION_CHICKEN _MMIO(0x83b4)
+#define POLYGON_TRIFAN_LINELOOP_DISABLE REG_BIT(4)
+
#define GEN8_RC6_CTX_INFO _MMIO(0x8504)
-#define GEN12_SQCM _MMIO(0x8724)
+#define XEHP_SQCM MCR_REG(0x8724)
#define EN_32B_ACCESS REG_BIT(30)
#define HSW_IDICR _MMIO(0x9008)
@@ -516,6 +546,8 @@
#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0)
/* Fuse readout registers for GT */
+#define XEHP_FUSE4 _MMIO(0x9114)
+#define GT_L3_EXC_MASK REG_GENMASK(6, 4)
#define GEN10_MIRROR_FUSE3 _MMIO(0x9118)
#define GEN10_L3BANK_PAIR_COUNT 4
#define GEN10_L3BANK_MASK 0x0F
@@ -619,6 +651,7 @@
#define XEHPC_GRDOM_BLT3 REG_BIT(26)
#define XEHPC_GRDOM_BLT2 REG_BIT(25)
#define XEHPC_GRDOM_BLT1 REG_BIT(24)
+#define GEN12_GRDOM_GSC REG_BIT(21)
#define GEN11_GRDOM_SFC3 REG_BIT(20)
#define GEN11_GRDOM_SFC2 REG_BIT(19)
#define GEN11_GRDOM_SFC1 REG_BIT(18)
@@ -644,6 +677,9 @@
#define GEN7_MISCCPCTL _MMIO(0x9424)
#define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0)
+
+#define GEN8_MISCCPCTL MCR_REG(0x9424)
+#define GEN8_DOP_CLOCK_GATE_ENABLE REG_BIT(0)
#define GEN12_DOP_CLOCK_GATE_RENDER_ENABLE REG_BIT(1)
#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2)
#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1 << 4)
@@ -697,7 +733,8 @@
#define GAMTLBVEBOX0_CLKGATE_DIS REG_BIT(16)
#define LTCDD_CLKGATE_DIS REG_BIT(10)
-#define SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4)
+#define GEN11_SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4)
+#define XEHP_SLICE_UNIT_LEVEL_CLKGATE MCR_REG(0x94d4)
#define SARBUNIT_CLKGATE_DIS (1 << 5)
#define RCCUNIT_CLKGATE_DIS (1 << 7)
#define MSCUNIT_CLKGATE_DIS (1 << 10)
@@ -705,27 +742,27 @@
#define L3_CLKGATE_DIS REG_BIT(16)
#define L3_CR2X_CLKGATE_DIS REG_BIT(17)
-#define SCCGCTL94DC _MMIO(0x94dc)
+#define SCCGCTL94DC MCR_REG(0x94dc)
#define CG3DDISURB REG_BIT(14)
#define UNSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x94e4)
#define VSUNIT_CLKGATE_DIS_TGL REG_BIT(19)
#define PSDUNIT_CLKGATE_DIS REG_BIT(5)
-#define SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524)
+#define GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE MCR_REG(0x9524)
#define DSS_ROUTER_CLKGATE_DIS REG_BIT(28)
#define GWUNIT_CLKGATE_DIS REG_BIT(16)
-#define SUBSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x9528)
+#define SUBSLICE_UNIT_LEVEL_CLKGATE2 MCR_REG(0x9528)
#define CPSSUNIT_CLKGATE_DIS REG_BIT(9)
-#define SSMCGCTL9530 _MMIO(0x9530)
+#define SSMCGCTL9530 MCR_REG(0x9530)
#define RTFUNIT_CLKGATE_DIS REG_BIT(18)
-#define GEN10_DFR_RATIO_EN_AND_CHICKEN _MMIO(0x9550)
+#define GEN10_DFR_RATIO_EN_AND_CHICKEN MCR_REG(0x9550)
#define DFR_DISABLE (1 << 9)
-#define INF_UNIT_LEVEL_CLKGATE _MMIO(0x9560)
+#define INF_UNIT_LEVEL_CLKGATE MCR_REG(0x9560)
#define CGPSF_CLKGATE_DIS (1 << 3)
#define MICRO_BP0_0 _MMIO(0x9800)
@@ -770,12 +807,9 @@
#define GEN6_RP_DOWN_TIMEOUT _MMIO(0xa010)
#define GEN6_RP_INTERRUPT_LIMITS _MMIO(0xa014)
#define GEN6_RPSTAT1 _MMIO(0xa01c)
-#define GEN6_CAGF_SHIFT 8
-#define HSW_CAGF_SHIFT 7
-#define GEN9_CAGF_SHIFT 23
-#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT)
-#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT)
-#define GEN9_CAGF_MASK (0x1ff << GEN9_CAGF_SHIFT)
+#define GEN6_CAGF_MASK REG_GENMASK(14, 8)
+#define HSW_CAGF_MASK REG_GENMASK(13, 7)
+#define GEN9_CAGF_MASK REG_GENMASK(31, 23)
#define GEN6_RP_CONTROL _MMIO(0xa024)
#define GEN6_RP_MEDIA_TURBO (1 << 11)
#define GEN6_RP_MEDIA_MODE_MASK (3 << 9)
@@ -898,6 +932,8 @@
#define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4)
#define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4)
+#define FORCEWAKE_REQ_GSC _MMIO(0xa618)
+
#define CHV_POWER_SS0_SIG1 _MMIO(0xa720)
#define CHV_POWER_SS0_SIG2 _MMIO(0xa724)
#define CHV_POWER_SS1_SIG1 _MMIO(0xa728)
@@ -935,7 +971,8 @@
/* MOCS (Memory Object Control State) registers */
#define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */
-#define GEN9_LNCFCMOCS_REG_COUNT 32
+#define XEHP_LNCFCMOCS(i) MCR_REG(0xb020 + (i) * 4)
+#define LNCFCMOCS_REG_COUNT 32
#define GEN7_L3CNTLREG3 _MMIO(0xb024)
@@ -951,15 +988,10 @@
#define GEN7_L3LOG(slice, i) _MMIO(0xb070 + (slice) * 0x200 + (i) * 4)
#define GEN7_L3LOG_SIZE 0x80
-#define GEN10_SCRATCH_LNCF2 _MMIO(0xb0a0)
-#define PMFLUSHDONE_LNICRSDROP (1 << 20)
-#define PMFLUSH_GAPL3UNBLOCK (1 << 21)
-#define PMFLUSHDONE_LNEBLK (1 << 22)
-
-#define XEHP_L3NODEARBCFG _MMIO(0xb0b4)
+#define XEHP_L3NODEARBCFG MCR_REG(0xb0b4)
#define XEHP_LNESPARE REG_BIT(19)
-#define GEN8_L3SQCREG1 _MMIO(0xb100)
+#define GEN8_L3SQCREG1 MCR_REG(0xb100)
/*
* Note that on CHV the following has an off-by-one error wrt. to BSpec.
* Using the formula in BSpec leads to a hang, while the formula here works
@@ -970,31 +1002,28 @@
#define L3_HIGH_PRIO_CREDITS(x) (((x) >> 1) << 14)
#define L3_PRIO_CREDITS_MASK ((0x1f << 19) | (0x1f << 14))
-#define GEN10_L3_CHICKEN_MODE_REGISTER _MMIO(0xb114)
-#define GEN11_I2M_WRITE_DISABLE (1 << 28)
-
-#define GEN8_L3SQCREG4 _MMIO(0xb118)
+#define GEN8_L3SQCREG4 MCR_REG(0xb118)
#define GEN11_LQSC_CLEAN_EVICT_DISABLE (1 << 6)
#define GEN8_LQSC_RO_PERF_DIS (1 << 27)
#define GEN8_LQSC_FLUSH_COHERENT_LINES (1 << 21)
#define GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE REG_BIT(22)
-#define GEN9_SCRATCH1 _MMIO(0xb11c)
+#define GEN9_SCRATCH1 MCR_REG(0xb11c)
#define EVICTION_PERF_FIX_ENABLE REG_BIT(8)
-#define BDW_SCRATCH1 _MMIO(0xb11c)
+#define BDW_SCRATCH1 MCR_REG(0xb11c)
#define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1 << 2)
-#define GEN11_SCRATCH2 _MMIO(0xb140)
+#define GEN11_SCRATCH2 MCR_REG(0xb140)
#define GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE (1 << 19)
-#define GEN11_L3SQCREG5 _MMIO(0xb158)
+#define XEHP_L3SQCREG5 MCR_REG(0xb158)
#define L3_PWM_TIMER_INIT_VAL_MASK REG_GENMASK(9, 0)
-#define MLTICTXCTL _MMIO(0xb170)
+#define MLTICTXCTL MCR_REG(0xb170)
#define TDONRENDER REG_BIT(2)
-#define XEHP_L3SCQREG7 _MMIO(0xb188)
+#define XEHP_L3SCQREG7 MCR_REG(0xb188)
#define BLEND_FILL_CACHING_OPT_DIS REG_BIT(3)
#define XEHPC_L3SCRUB _MMIO(0xb18c)
@@ -1002,7 +1031,7 @@
#define SCRUB_RATE_PER_BANK_MASK REG_GENMASK(2, 0)
#define SCRUB_RATE_4B_PER_CLK REG_FIELD_PREP(SCRUB_RATE_PER_BANK_MASK, 0x6)
-#define L3SQCREG1_CCS0 _MMIO(0xb200)
+#define L3SQCREG1_CCS0 MCR_REG(0xb200)
#define FLUSHALLNONCOH REG_BIT(5)
#define GEN11_GLBLINVL _MMIO(0xb404)
@@ -1027,11 +1056,14 @@
#define GEN9_BLT_MOCS(i) _MMIO(__GEN9_BCS0_MOCS0 + (i) * 4)
#define GEN12_FAULT_TLB_DATA0 _MMIO(0xceb8)
+#define XEHP_FAULT_TLB_DATA0 MCR_REG(0xceb8)
#define GEN12_FAULT_TLB_DATA1 _MMIO(0xcebc)
+#define XEHP_FAULT_TLB_DATA1 MCR_REG(0xcebc)
#define FAULT_VA_HIGH_BITS (0xf << 0)
#define FAULT_GTT_SEL (1 << 4)
#define GEN12_RING_FAULT_REG _MMIO(0xcec4)
+#define XEHP_RING_FAULT_REG MCR_REG(0xcec4)
#define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7)
#define RING_FAULT_GTTSEL_MASK (1 << 11)
#define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff)
@@ -1039,16 +1071,21 @@
#define RING_FAULT_VALID (1 << 0)
#define GEN12_GFX_TLB_INV_CR _MMIO(0xced8)
+#define XEHP_GFX_TLB_INV_CR MCR_REG(0xced8)
#define GEN12_VD_TLB_INV_CR _MMIO(0xcedc)
+#define XEHP_VD_TLB_INV_CR MCR_REG(0xcedc)
#define GEN12_VE_TLB_INV_CR _MMIO(0xcee0)
+#define XEHP_VE_TLB_INV_CR MCR_REG(0xcee0)
#define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4)
+#define XEHP_BLT_TLB_INV_CR MCR_REG(0xcee4)
#define GEN12_COMPCTX_TLB_INV_CR _MMIO(0xcf04)
+#define XEHP_COMPCTX_TLB_INV_CR MCR_REG(0xcf04)
-#define GEN12_MERT_MOD_CTRL _MMIO(0xcf28)
-#define RENDER_MOD_CTRL _MMIO(0xcf2c)
-#define COMP_MOD_CTRL _MMIO(0xcf30)
-#define VDBX_MOD_CTRL _MMIO(0xcf34)
-#define VEBX_MOD_CTRL _MMIO(0xcf38)
+#define XEHP_MERT_MOD_CTRL MCR_REG(0xcf28)
+#define RENDER_MOD_CTRL MCR_REG(0xcf2c)
+#define COMP_MOD_CTRL MCR_REG(0xcf30)
+#define VDBX_MOD_CTRL MCR_REG(0xcf34)
+#define VEBX_MOD_CTRL MCR_REG(0xcf38)
#define FORCE_MISS_FTLB REG_BIT(3)
#define GEN12_GAMSTLB_CTRL _MMIO(0xcf4c)
@@ -1063,48 +1100,52 @@
#define GEN12_GAM_DONE _MMIO(0xcf68)
#define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */
+#define GEN8_HALF_SLICE_CHICKEN1 MCR_REG(0xe100)
#define GEN7_MAX_PS_THREAD_DEP (8 << 12)
#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1 << 10)
#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1 << 4)
#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1 << 3)
#define GEN7_SAMPLER_INSTDONE _MMIO(0xe160)
+#define GEN8_SAMPLER_INSTDONE MCR_REG(0xe160)
#define GEN7_ROW_INSTDONE _MMIO(0xe164)
+#define GEN8_ROW_INSTDONE MCR_REG(0xe164)
-#define HALF_SLICE_CHICKEN2 _MMIO(0xe180)
+#define HALF_SLICE_CHICKEN2 MCR_REG(0xe180)
#define GEN8_ST_PO_DISABLE (1 << 13)
-#define HALF_SLICE_CHICKEN3 _MMIO(0xe184)
+#define HSW_HALF_SLICE_CHICKEN3 _MMIO(0xe184)
+#define GEN8_HALF_SLICE_CHICKEN3 MCR_REG(0xe184)
#define HSW_SAMPLE_C_PERFORMANCE (1 << 9)
#define GEN8_CENTROID_PIXEL_OPT_DIS (1 << 8)
#define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1 << 5)
#define GEN8_SAMPLER_POWER_BYPASS_DIS (1 << 1)
-#define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188)
+#define GEN9_HALF_SLICE_CHICKEN5 MCR_REG(0xe188)
#define GEN9_DG_MIRROR_FIX_ENABLE (1 << 5)
#define GEN9_CCS_TLB_PREFETCH_ENABLE (1 << 3)
-#define GEN10_SAMPLER_MODE _MMIO(0xe18c)
+#define GEN10_SAMPLER_MODE MCR_REG(0xe18c)
#define ENABLE_SMALLPL REG_BIT(15)
#define SC_DISABLE_POWER_OPTIMIZATION_EBB REG_BIT(9)
#define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5)
-#define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194)
+#define GEN9_HALF_SLICE_CHICKEN7 MCR_REG(0xe194)
#define DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA REG_BIT(15)
#define GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR REG_BIT(8)
#define GEN9_ENABLE_YV12_BUGFIX REG_BIT(4)
#define GEN9_ENABLE_GPGPU_PREEMPTION REG_BIT(2)
-#define GEN10_CACHE_MODE_SS _MMIO(0xe420)
+#define GEN10_CACHE_MODE_SS MCR_REG(0xe420)
#define ENABLE_EU_COUNT_FOR_TDL_FLUSH REG_BIT(10)
#define DISABLE_ECC REG_BIT(5)
#define FLOAT_BLEND_OPTIMIZATION_ENABLE REG_BIT(4)
#define ENABLE_PREFETCH_INTO_IC REG_BIT(3)
-#define EU_PERF_CNTL0 _MMIO(0xe458)
-#define EU_PERF_CNTL4 _MMIO(0xe45c)
+#define EU_PERF_CNTL0 PERF_REG(0xe458)
+#define EU_PERF_CNTL4 PERF_REG(0xe45c)
-#define GEN9_ROW_CHICKEN4 _MMIO(0xe48c)
+#define GEN9_ROW_CHICKEN4 MCR_REG(0xe48c)
#define GEN12_DISABLE_GRF_CLEAR REG_BIT(13)
#define XEHP_DIS_BBL_SYSPIPE REG_BIT(11)
#define GEN12_DISABLE_TDL_PUSH REG_BIT(9)
@@ -1116,7 +1157,7 @@
#define HSW_ROW_CHICKEN3 _MMIO(0xe49c)
#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6)
-#define GEN8_ROW_CHICKEN _MMIO(0xe4f0)
+#define GEN8_ROW_CHICKEN MCR_REG(0xe4f0)
#define FLOW_CONTROL_ENABLE REG_BIT(15)
#define UGM_BACKUP_MODE REG_BIT(13)
#define MDQ_ARBITRATION_MODE REG_BIT(12)
@@ -1127,42 +1168,43 @@
#define DISABLE_EARLY_EOT REG_BIT(1)
#define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4)
+
+#define GEN8_ROW_CHICKEN2 MCR_REG(0xe4f4)
#define GEN12_DISABLE_READ_SUPPRESSION REG_BIT(15)
#define GEN12_DISABLE_EARLY_READ REG_BIT(14)
#define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12)
#define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8)
+#define GEN12_DISABLE_DOP_GATING REG_BIT(0)
-#define RT_CTRL _MMIO(0xe530)
+#define RT_CTRL MCR_REG(0xe530)
#define DIS_NULL_QUERY REG_BIT(10)
#define STACKID_CTRL REG_GENMASK(6, 5)
#define STACKID_CTRL_512 REG_FIELD_PREP(STACKID_CTRL, 0x2)
-#define EU_PERF_CNTL1 _MMIO(0xe558)
-#define EU_PERF_CNTL5 _MMIO(0xe55c)
+#define EU_PERF_CNTL1 PERF_REG(0xe558)
+#define EU_PERF_CNTL5 PERF_REG(0xe55c)
-#define GEN12_HDC_CHICKEN0 _MMIO(0xe5f0)
+#define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0)
#define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11)
-#define ICL_HDC_MODE _MMIO(0xe5f4)
+#define ICL_HDC_MODE MCR_REG(0xe5f4)
-#define EU_PERF_CNTL2 _MMIO(0xe658)
-#define EU_PERF_CNTL6 _MMIO(0xe65c)
-#define EU_PERF_CNTL3 _MMIO(0xe758)
+#define EU_PERF_CNTL2 PERF_REG(0xe658)
+#define EU_PERF_CNTL6 PERF_REG(0xe65c)
+#define EU_PERF_CNTL3 PERF_REG(0xe758)
-#define LSC_CHICKEN_BIT_0 _MMIO(0xe7c8)
+#define LSC_CHICKEN_BIT_0 MCR_REG(0xe7c8)
#define DISABLE_D8_D16_COASLESCE REG_BIT(30)
#define FORCE_1_SUB_MESSAGE_PER_FRAGMENT REG_BIT(15)
-#define LSC_CHICKEN_BIT_0_UDW _MMIO(0xe7c8 + 4)
+#define LSC_CHICKEN_BIT_0_UDW MCR_REG(0xe7c8 + 4)
#define DIS_CHAIN_2XSIMD8 REG_BIT(55 - 32)
#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)
#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32)
#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)
#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
-#define SARB_CHICKEN1 _MMIO(0xe90c)
+#define SARB_CHICKEN1 MCR_REG(0xe90c)
#define COMP_CKN_IN REG_GENMASK(30, 29)
-#define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100)
-
#define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4)
#define DOP_CLOCK_GATING_DISABLE (1 << 0)
#define PUSH_CONSTANT_DEREF_DISABLE (1 << 8)
@@ -1339,8 +1381,7 @@
#define MEMSTAT_ILK _MMIO(0x111f8)
#define MEMSTAT_VID_MASK 0x7f00
#define MEMSTAT_VID_SHIFT 8
-#define MEMSTAT_PSTATE_MASK 0x00f8
-#define MEMSTAT_PSTATE_SHIFT 3
+#define MEMSTAT_PSTATE_MASK REG_GENMASK(7, 3)
#define MEMSTAT_MON_ACTV (1 << 2)
#define MEMSTAT_SRC_CTL_MASK 0x0003
#define MEMSTAT_SRC_CTL_CORE 0
@@ -1481,6 +1522,8 @@
#define FORCEWAKE_MEDIA_VLV _MMIO(0x1300b8)
#define FORCEWAKE_ACK_MEDIA_VLV _MMIO(0x1300bc)
+#define MTL_MEDIA_MC6 _MMIO(0x138048)
+
#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c)
#define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7
@@ -1510,10 +1553,15 @@
#define VLV_RENDER_C0_COUNT _MMIO(0x138118)
#define VLV_MEDIA_C0_COUNT _MMIO(0x13811c)
+#define GEN12_RPSTAT1 _MMIO(0x1381b4)
+#define GEN12_VOLTAGE_MASK REG_GENMASK(10, 0)
+#define GEN12_CAGF_MASK REG_GENMASK(19, 11)
+
#define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + ((x) * 4))
#define GEN11_CSME (31)
#define GEN11_GUNIT (28)
#define GEN11_GUC (25)
+#define MTL_MGUC (24)
#define GEN11_WDPERF (20)
#define GEN11_KCR (19)
#define GEN11_GTPM (16)
@@ -1568,6 +1616,7 @@
#define GEN11_VECS0_VECS1_INTR_MASK _MMIO(0x1900d0)
#define GEN12_VECS2_VECS3_INTR_MASK _MMIO(0x1900d4)
#define GEN11_GUC_SG_INTR_MASK _MMIO(0x1900e8)
+#define MTL_GUC_MGUC_INTR_MASK _MMIO(0x1900e8) /* MTL+ */
#define GEN11_GPM_WGBOXPERF_INTR_MASK _MMIO(0x1900ec)
#define GEN11_CRYPTO_RSVD_INTR_MASK _MMIO(0x1900f0)
#define GEN11_GUNIT_CSME_INTR_MASK _MMIO(0x1900f4)
@@ -1580,6 +1629,11 @@
#define GEN12_SFC_DONE(n) _MMIO(0x1cc000 + (n) * 0x1000)
+#define GT0_PACKAGE_ENERGY_STATUS _MMIO(0x250004)
+#define GT0_PACKAGE_RAPL_LIMIT _MMIO(0x250008)
+#define GT0_PACKAGE_POWER_SKU_UNIT _MMIO(0x250068)
+#define GT0_PLATFORM_ENERGY_STATUS _MMIO(0x25006c)
+
/*
* Standalone Media's non-engine GT registers are located at their regular GT
* offsets plus 0x380000. This extra offset is stored inside the intel_uncore
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_requests.c b/drivers/gpu/drm/i915/gt/intel_gt_requests.c
index edb881d75630..1dfd01668c79 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_requests.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_requests.c
@@ -199,7 +199,7 @@ out_active: spin_lock(&timelines->lock);
if (remaining_timeout)
*remaining_timeout = timeout;
- return active_count ? timeout : 0;
+ return active_count ? timeout ?: -ETIME : 0;
}
static void retire_work_handler(struct work_struct *work)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
index d651ccd0ab20..9486dd3bed99 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
@@ -22,11 +22,9 @@ bool is_object_gt(struct kobject *kobj)
return !strncmp(kobj->name, "gt", 2);
}
-struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
+struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
const char *name)
{
- struct kobject *kobj = &dev->kobj;
-
/*
* We are interested at knowing from where the interface
* has been called, whether it's called from gt/ or from
@@ -38,6 +36,7 @@ struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
* "struct drm_i915_private *" type.
*/
if (!is_object_gt(kobj)) {
+ struct device *dev = kobj_to_dev(kobj);
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
return to_gt(i915);
@@ -51,18 +50,18 @@ static struct kobject *gt_get_parent_obj(struct intel_gt *gt)
return &gt->i915->drm.primary->kdev->kobj;
}
-static ssize_t id_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t id_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buf)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
return sysfs_emit(buf, "%u\n", gt->info.id);
}
-static DEVICE_ATTR_RO(id);
+static struct kobj_attribute attr_id = __ATTR_RO(id);
static struct attribute *id_attrs[] = {
- &dev_attr_id.attr,
+ &attr_id.attr,
NULL,
};
ATTRIBUTE_GROUPS(id);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
index 6232923a420d..18bab835be02 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
@@ -18,11 +18,6 @@ bool is_object_gt(struct kobject *kobj);
struct drm_i915_private *kobj_to_i915(struct kobject *kobj);
-struct kobject *
-intel_gt_create_kobj(struct intel_gt *gt,
- struct kobject *dir,
- const char *name);
-
static inline struct intel_gt *kobj_to_gt(struct kobject *kobj)
{
return container_of(kobj, struct intel_gt, sysfs_gt);
@@ -30,7 +25,7 @@ static inline struct intel_gt *kobj_to_gt(struct kobject *kobj)
void intel_gt_sysfs_register(struct intel_gt *gt);
void intel_gt_sysfs_unregister(struct intel_gt *gt);
-struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
+struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
const char *name);
#endif /* SYSFS_GT_H */
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
index 180dd6f3ef57..cf71305ad586 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
@@ -24,14 +24,15 @@ enum intel_gt_sysfs_op {
};
static int
-sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
+sysfs_gt_attribute_w_func(struct kobject *kobj, struct attribute *attr,
int (func)(struct intel_gt *gt, u32 val), u32 val)
{
struct intel_gt *gt;
int ret;
- if (!is_object_gt(&dev->kobj)) {
+ if (!is_object_gt(kobj)) {
int i;
+ struct device *dev = kobj_to_dev(kobj);
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
for_each_gt(gt, i915, i) {
@@ -40,7 +41,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
break;
}
} else {
- gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
ret = func(gt, val);
}
@@ -48,7 +49,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
}
static u32
-sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
+sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr,
u32 (func)(struct intel_gt *gt),
enum intel_gt_sysfs_op op)
{
@@ -57,8 +58,9 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
ret = (op == INTEL_GT_SYSFS_MAX) ? 0 : (u32) -1;
- if (!is_object_gt(&dev->kobj)) {
+ if (!is_object_gt(kobj)) {
int i;
+ struct device *dev = kobj_to_dev(kobj);
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
for_each_gt(gt, i915, i) {
@@ -77,7 +79,7 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
}
}
} else {
- gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
ret = func(gt);
}
@@ -92,23 +94,90 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
#define sysfs_gt_attribute_r_max_func(d, a, f) \
sysfs_gt_attribute_r_func(d, a, f, INTEL_GT_SYSFS_MAX)
+#define INTEL_GT_SYSFS_SHOW(_name, _attr_type) \
+ static ssize_t _name##_show_common(struct kobject *kobj, \
+ struct attribute *attr, char *buff) \
+ { \
+ u32 val = sysfs_gt_attribute_r_##_attr_type##_func(kobj, attr, \
+ __##_name##_show); \
+ \
+ return sysfs_emit(buff, "%u\n", val); \
+ } \
+ static ssize_t _name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buff) \
+ { \
+ return _name ##_show_common(kobj, &attr->attr, buff); \
+ } \
+ static ssize_t _name##_dev_show(struct device *dev, \
+ struct device_attribute *attr, char *buff) \
+ { \
+ return _name##_show_common(&dev->kobj, &attr->attr, buff); \
+ }
+
+#define INTEL_GT_SYSFS_STORE(_name, _func) \
+ static ssize_t _name##_store_common(struct kobject *kobj, \
+ struct attribute *attr, \
+ const char *buff, size_t count) \
+ { \
+ int ret; \
+ u32 val; \
+ \
+ ret = kstrtou32(buff, 0, &val); \
+ if (ret) \
+ return ret; \
+ \
+ ret = sysfs_gt_attribute_w_func(kobj, attr, _func, val); \
+ \
+ return ret ?: count; \
+ } \
+ static ssize_t _name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buff, \
+ size_t count) \
+ { \
+ return _name##_store_common(kobj, &attr->attr, buff, count); \
+ } \
+ static ssize_t _name##_dev_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buff, size_t count) \
+ { \
+ return _name##_store_common(&dev->kobj, &attr->attr, buff, count); \
+ }
+
+#define INTEL_GT_SYSFS_SHOW_MAX(_name) INTEL_GT_SYSFS_SHOW(_name, max)
+#define INTEL_GT_SYSFS_SHOW_MIN(_name) INTEL_GT_SYSFS_SHOW(_name, min)
+
+#define INTEL_GT_ATTR_RW(_name) \
+ static struct kobj_attribute attr_##_name = __ATTR_RW(_name)
+
+#define INTEL_GT_ATTR_RO(_name) \
+ static struct kobj_attribute attr_##_name = __ATTR_RO(_name)
+
+#define INTEL_GT_DUAL_ATTR_RW(_name) \
+ static struct device_attribute dev_attr_##_name = __ATTR(_name, 0644, \
+ _name##_dev_show, \
+ _name##_dev_store); \
+ INTEL_GT_ATTR_RW(_name)
+
+#define INTEL_GT_DUAL_ATTR_RO(_name) \
+ static struct device_attribute dev_attr_##_name = __ATTR(_name, 0444, \
+ _name##_dev_show, \
+ NULL); \
+ INTEL_GT_ATTR_RO(_name)
+
#ifdef CONFIG_PM
-static u32 get_residency(struct intel_gt *gt, i915_reg_t reg)
+static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id)
{
intel_wakeref_t wakeref;
u64 res = 0;
with_intel_runtime_pm(gt->uncore->rpm, wakeref)
- res = intel_rc6_residency_us(&gt->rc6, reg);
+ res = intel_rc6_residency_us(&gt->rc6, id);
return DIV_ROUND_CLOSEST_ULL(res, 1000);
}
-static ssize_t rc6_enable_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
+static u8 get_rc6_mask(struct intel_gt *gt)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
u8 mask = 0;
if (HAS_RC6(gt->i915))
@@ -118,105 +187,105 @@ static ssize_t rc6_enable_show(struct device *dev,
if (HAS_RC6pp(gt->i915))
mask |= BIT(2);
- return sysfs_emit(buff, "%x\n", mask);
+ return mask;
}
-static u32 __rc6_residency_ms_show(struct intel_gt *gt)
+static ssize_t rc6_enable_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buff)
{
- return get_residency(gt, GEN6_GT_GFX_RC6);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+
+ return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
}
-static ssize_t rc6_residency_ms_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
+static ssize_t rc6_enable_dev_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buff)
{
- u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
- __rc6_residency_ms_show);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name);
- return sysfs_emit(buff, "%u\n", rc6_residency);
+ return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
}
-static u32 __rc6p_residency_ms_show(struct intel_gt *gt)
+static u32 __rc6_residency_ms_show(struct intel_gt *gt)
{
- return get_residency(gt, GEN6_GT_GFX_RC6p);
+ return get_residency(gt, INTEL_RC6_RES_RC6);
}
-static ssize_t rc6p_residency_ms_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
+static u32 __rc6p_residency_ms_show(struct intel_gt *gt)
{
- u32 rc6p_residency = sysfs_gt_attribute_r_min_func(dev, attr,
- __rc6p_residency_ms_show);
-
- return sysfs_emit(buff, "%u\n", rc6p_residency);
+ return get_residency(gt, INTEL_RC6_RES_RC6p);
}
static u32 __rc6pp_residency_ms_show(struct intel_gt *gt)
{
- return get_residency(gt, GEN6_GT_GFX_RC6pp);
-}
-
-static ssize_t rc6pp_residency_ms_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
-{
- u32 rc6pp_residency = sysfs_gt_attribute_r_min_func(dev, attr,
- __rc6pp_residency_ms_show);
-
- return sysfs_emit(buff, "%u\n", rc6pp_residency);
+ return get_residency(gt, INTEL_RC6_RES_RC6pp);
}
static u32 __media_rc6_residency_ms_show(struct intel_gt *gt)
{
- return get_residency(gt, VLV_GT_MEDIA_RC6);
+ return get_residency(gt, INTEL_RC6_RES_VLV_MEDIA);
}
-static ssize_t media_rc6_residency_ms_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
-{
- u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
- __media_rc6_residency_ms_show);
+INTEL_GT_SYSFS_SHOW_MIN(rc6_residency_ms);
+INTEL_GT_SYSFS_SHOW_MIN(rc6p_residency_ms);
+INTEL_GT_SYSFS_SHOW_MIN(rc6pp_residency_ms);
+INTEL_GT_SYSFS_SHOW_MIN(media_rc6_residency_ms);
- return sysfs_emit(buff, "%u\n", rc6_residency);
-}
-
-static DEVICE_ATTR_RO(rc6_enable);
-static DEVICE_ATTR_RO(rc6_residency_ms);
-static DEVICE_ATTR_RO(rc6p_residency_ms);
-static DEVICE_ATTR_RO(rc6pp_residency_ms);
-static DEVICE_ATTR_RO(media_rc6_residency_ms);
+INTEL_GT_DUAL_ATTR_RO(rc6_enable);
+INTEL_GT_DUAL_ATTR_RO(rc6_residency_ms);
+INTEL_GT_DUAL_ATTR_RO(rc6p_residency_ms);
+INTEL_GT_DUAL_ATTR_RO(rc6pp_residency_ms);
+INTEL_GT_DUAL_ATTR_RO(media_rc6_residency_ms);
static struct attribute *rc6_attrs[] = {
+ &attr_rc6_enable.attr,
+ &attr_rc6_residency_ms.attr,
+ NULL
+};
+
+static struct attribute *rc6p_attrs[] = {
+ &attr_rc6p_residency_ms.attr,
+ &attr_rc6pp_residency_ms.attr,
+ NULL
+};
+
+static struct attribute *media_rc6_attrs[] = {
+ &attr_media_rc6_residency_ms.attr,
+ NULL
+};
+
+static struct attribute *rc6_dev_attrs[] = {
&dev_attr_rc6_enable.attr,
&dev_attr_rc6_residency_ms.attr,
NULL
};
-static struct attribute *rc6p_attrs[] = {
+static struct attribute *rc6p_dev_attrs[] = {
&dev_attr_rc6p_residency_ms.attr,
&dev_attr_rc6pp_residency_ms.attr,
NULL
};
-static struct attribute *media_rc6_attrs[] = {
+static struct attribute *media_rc6_dev_attrs[] = {
&dev_attr_media_rc6_residency_ms.attr,
NULL
};
static const struct attribute_group rc6_attr_group[] = {
{ .attrs = rc6_attrs, },
- { .name = power_group_name, .attrs = rc6_attrs, },
+ { .name = power_group_name, .attrs = rc6_dev_attrs, },
};
static const struct attribute_group rc6p_attr_group[] = {
{ .attrs = rc6p_attrs, },
- { .name = power_group_name, .attrs = rc6p_attrs, },
+ { .name = power_group_name, .attrs = rc6p_dev_attrs, },
};
static const struct attribute_group media_rc6_attr_group[] = {
{ .attrs = media_rc6_attrs, },
- { .name = power_group_name, .attrs = media_rc6_attrs, },
+ { .name = power_group_name, .attrs = media_rc6_dev_attrs, },
};
static int __intel_gt_sysfs_create_group(struct kobject *kobj,
@@ -271,104 +340,34 @@ static u32 __act_freq_mhz_show(struct intel_gt *gt)
return intel_rps_read_actual_frequency(&gt->rps);
}
-static ssize_t act_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 actual_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __act_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", actual_freq);
-}
-
static u32 __cur_freq_mhz_show(struct intel_gt *gt)
{
return intel_rps_get_requested_frequency(&gt->rps);
}
-static ssize_t cur_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 cur_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __cur_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", cur_freq);
-}
-
static u32 __boost_freq_mhz_show(struct intel_gt *gt)
{
return intel_rps_get_boost_frequency(&gt->rps);
}
-static ssize_t boost_freq_mhz_show(struct device *dev,
- struct device_attribute *attr,
- char *buff)
-{
- u32 boost_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __boost_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", boost_freq);
-}
-
static int __boost_freq_mhz_store(struct intel_gt *gt, u32 val)
{
return intel_rps_set_boost_frequency(&gt->rps, val);
}
-static ssize_t boost_freq_mhz_store(struct device *dev,
- struct device_attribute *attr,
- const char *buff, size_t count)
-{
- ssize_t ret;
- u32 val;
-
- ret = kstrtou32(buff, 0, &val);
- if (ret)
- return ret;
-
- return sysfs_gt_attribute_w_func(dev, attr,
- __boost_freq_mhz_store, val) ?: count;
-}
-
-static u32 __rp0_freq_mhz_show(struct intel_gt *gt)
+static u32 __RP0_freq_mhz_show(struct intel_gt *gt)
{
return intel_rps_get_rp0_frequency(&gt->rps);
}
-static ssize_t RP0_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 rp0_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __rp0_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", rp0_freq);
-}
-
-static u32 __rp1_freq_mhz_show(struct intel_gt *gt)
-{
- return intel_rps_get_rp1_frequency(&gt->rps);
-}
-
-static ssize_t RP1_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 rp1_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __rp1_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", rp1_freq);
-}
-
-static u32 __rpn_freq_mhz_show(struct intel_gt *gt)
+static u32 __RPn_freq_mhz_show(struct intel_gt *gt)
{
return intel_rps_get_rpn_frequency(&gt->rps);
}
-static ssize_t RPn_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
+static u32 __RP1_freq_mhz_show(struct intel_gt *gt)
{
- u32 rpn_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __rpn_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", rpn_freq);
+ return intel_rps_get_rp1_frequency(&gt->rps);
}
static u32 __max_freq_mhz_show(struct intel_gt *gt)
@@ -376,71 +375,21 @@ static u32 __max_freq_mhz_show(struct intel_gt *gt)
return intel_rps_get_max_frequency(&gt->rps);
}
-static ssize_t max_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 max_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __max_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", max_freq);
-}
-
static int __set_max_freq(struct intel_gt *gt, u32 val)
{
return intel_rps_set_max_frequency(&gt->rps, val);
}
-static ssize_t max_freq_mhz_store(struct device *dev,
- struct device_attribute *attr,
- const char *buff, size_t count)
-{
- int ret;
- u32 val;
-
- ret = kstrtou32(buff, 0, &val);
- if (ret)
- return ret;
-
- ret = sysfs_gt_attribute_w_func(dev, attr, __set_max_freq, val);
-
- return ret ?: count;
-}
-
static u32 __min_freq_mhz_show(struct intel_gt *gt)
{
return intel_rps_get_min_frequency(&gt->rps);
}
-static ssize_t min_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 min_freq = sysfs_gt_attribute_r_min_func(dev, attr,
- __min_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", min_freq);
-}
-
static int __set_min_freq(struct intel_gt *gt, u32 val)
{
return intel_rps_set_min_frequency(&gt->rps, val);
}
-static ssize_t min_freq_mhz_store(struct device *dev,
- struct device_attribute *attr,
- const char *buff, size_t count)
-{
- int ret;
- u32 val;
-
- ret = kstrtou32(buff, 0, &val);
- if (ret)
- return ret;
-
- ret = sysfs_gt_attribute_w_func(dev, attr, __set_min_freq, val);
-
- return ret ?: count;
-}
-
static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
{
struct intel_rps *rps = &gt->rps;
@@ -448,23 +397,31 @@ static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
return intel_gpu_freq(rps, rps->efficient_freq);
}
-static ssize_t vlv_rpe_freq_mhz_show(struct device *dev,
- struct device_attribute *attr, char *buff)
-{
- u32 rpe_freq = sysfs_gt_attribute_r_max_func(dev, attr,
- __vlv_rpe_freq_mhz_show);
-
- return sysfs_emit(buff, "%u\n", rpe_freq);
-}
-
-#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store) \
- static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, _show, _store); \
- static struct device_attribute dev_attr_rps_##_name = __ATTR(rps_##_name, _mode, _show, _store)
-
-#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \
- INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL)
-#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \
- INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store)
+INTEL_GT_SYSFS_SHOW_MAX(act_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(boost_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(cur_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(RP0_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(RP1_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(RPn_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(max_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MIN(min_freq_mhz);
+INTEL_GT_SYSFS_SHOW_MAX(vlv_rpe_freq_mhz);
+INTEL_GT_SYSFS_STORE(boost_freq_mhz, __boost_freq_mhz_store);
+INTEL_GT_SYSFS_STORE(max_freq_mhz, __set_max_freq);
+INTEL_GT_SYSFS_STORE(min_freq_mhz, __set_min_freq);
+
+#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store, _show_dev, _store_dev) \
+ static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, \
+ _show_dev, _store_dev); \
+ static struct kobj_attribute attr_rps_##_name = __ATTR(rps_##_name, _mode, \
+ _show, _store)
+
+#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \
+ INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL, \
+ _name##_dev_show, NULL)
+#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \
+ INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store, \
+ _name##_dev_show, _name##_dev_store)
/* The below macros generate static structures */
INTEL_GT_RPS_SYSFS_ATTR_RO(act_freq_mhz);
@@ -475,32 +432,31 @@ INTEL_GT_RPS_SYSFS_ATTR_RO(RP1_freq_mhz);
INTEL_GT_RPS_SYSFS_ATTR_RO(RPn_freq_mhz);
INTEL_GT_RPS_SYSFS_ATTR_RW(max_freq_mhz);
INTEL_GT_RPS_SYSFS_ATTR_RW(min_freq_mhz);
-
-static DEVICE_ATTR_RO(vlv_rpe_freq_mhz);
-
-#define GEN6_ATTR(s) { \
- &dev_attr_##s##_act_freq_mhz.attr, \
- &dev_attr_##s##_cur_freq_mhz.attr, \
- &dev_attr_##s##_boost_freq_mhz.attr, \
- &dev_attr_##s##_max_freq_mhz.attr, \
- &dev_attr_##s##_min_freq_mhz.attr, \
- &dev_attr_##s##_RP0_freq_mhz.attr, \
- &dev_attr_##s##_RP1_freq_mhz.attr, \
- &dev_attr_##s##_RPn_freq_mhz.attr, \
+INTEL_GT_RPS_SYSFS_ATTR_RO(vlv_rpe_freq_mhz);
+
+#define GEN6_ATTR(p, s) { \
+ &p##attr_##s##_act_freq_mhz.attr, \
+ &p##attr_##s##_cur_freq_mhz.attr, \
+ &p##attr_##s##_boost_freq_mhz.attr, \
+ &p##attr_##s##_max_freq_mhz.attr, \
+ &p##attr_##s##_min_freq_mhz.attr, \
+ &p##attr_##s##_RP0_freq_mhz.attr, \
+ &p##attr_##s##_RP1_freq_mhz.attr, \
+ &p##attr_##s##_RPn_freq_mhz.attr, \
NULL, \
}
-#define GEN6_RPS_ATTR GEN6_ATTR(rps)
-#define GEN6_GT_ATTR GEN6_ATTR(gt)
+#define GEN6_RPS_ATTR GEN6_ATTR(, rps)
+#define GEN6_GT_ATTR GEN6_ATTR(dev_, gt)
static const struct attribute * const gen6_rps_attrs[] = GEN6_RPS_ATTR;
static const struct attribute * const gen6_gt_attrs[] = GEN6_GT_ATTR;
-static ssize_t punit_req_freq_mhz_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t punit_req_freq_mhz_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
u32 preq = intel_rps_read_punit_req_frequency(&gt->rps);
return sysfs_emit(buff, "%u\n", preq);
@@ -508,20 +464,20 @@ static ssize_t punit_req_freq_mhz_show(struct device *dev,
struct intel_gt_bool_throttle_attr {
struct attribute attr;
- ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+ ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);
- i915_reg_t reg32;
+ i915_reg_t (*reg32)(struct intel_gt *gt);
u32 mask;
};
-static ssize_t throttle_reason_bool_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t throttle_reason_bool_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
struct intel_gt_bool_throttle_attr *t_attr =
(struct intel_gt_bool_throttle_attr *) attr;
- bool val = rps_read_mask_mmio(&gt->rps, t_attr->reg32, t_attr->mask);
+ bool val = rps_read_mask_mmio(&gt->rps, t_attr->reg32(gt), t_attr->mask);
return sysfs_emit(buff, "%u\n", val);
}
@@ -530,11 +486,11 @@ static ssize_t throttle_reason_bool_show(struct device *dev,
struct intel_gt_bool_throttle_attr attr_##sysfs_func__ = { \
.attr = { .name = __stringify(sysfs_func__), .mode = 0444 }, \
.show = throttle_reason_bool_show, \
- .reg32 = GT0_PERF_LIMIT_REASONS, \
+ .reg32 = intel_gt_perf_limit_reasons_reg, \
.mask = mask__, \
}
-static DEVICE_ATTR_RO(punit_req_freq_mhz);
+INTEL_GT_ATTR_RO(punit_req_freq_mhz);
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_status, GT0_PERF_LIMIT_REASONS_MASK);
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl1, POWER_LIMIT_1_MASK);
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl2, POWER_LIMIT_2_MASK);
@@ -597,8 +553,8 @@ static const struct attribute *throttle_reason_attrs[] = {
#define U8_8_VAL_MASK 0xffff
#define U8_8_SCALE_TO_VALUE "0.00390625"
-static ssize_t freq_factor_scale_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t freq_factor_scale_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
return sysfs_emit(buff, "%s\n", U8_8_SCALE_TO_VALUE);
@@ -610,11 +566,11 @@ static u32 media_ratio_mode_to_factor(u32 mode)
return !mode ? mode : 256 / mode;
}
-static ssize_t media_freq_factor_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t media_freq_factor_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
intel_wakeref_t wakeref;
u32 mode;
@@ -641,11 +597,11 @@ static ssize_t media_freq_factor_show(struct device *dev,
return sysfs_emit(buff, "%u\n", media_ratio_mode_to_factor(mode));
}
-static ssize_t media_freq_factor_store(struct device *dev,
- struct device_attribute *attr,
+static ssize_t media_freq_factor_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
const char *buff, size_t count)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
u32 factor, mode;
int err;
@@ -670,11 +626,11 @@ static ssize_t media_freq_factor_store(struct device *dev,
return err ?: count;
}
-static ssize_t media_RP0_freq_mhz_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t media_RP0_freq_mhz_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
u32 val;
int err;
@@ -691,11 +647,11 @@ static ssize_t media_RP0_freq_mhz_show(struct device *dev,
return sysfs_emit(buff, "%u\n", val);
}
-static ssize_t media_RPn_freq_mhz_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t media_RPn_freq_mhz_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buff)
{
- struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
u32 val;
int err;
@@ -712,17 +668,17 @@ static ssize_t media_RPn_freq_mhz_show(struct device *dev,
return sysfs_emit(buff, "%u\n", val);
}
-static DEVICE_ATTR_RW(media_freq_factor);
-static struct device_attribute dev_attr_media_freq_factor_scale =
+INTEL_GT_ATTR_RW(media_freq_factor);
+static struct kobj_attribute attr_media_freq_factor_scale =
__ATTR(media_freq_factor.scale, 0444, freq_factor_scale_show, NULL);
-static DEVICE_ATTR_RO(media_RP0_freq_mhz);
-static DEVICE_ATTR_RO(media_RPn_freq_mhz);
+INTEL_GT_ATTR_RO(media_RP0_freq_mhz);
+INTEL_GT_ATTR_RO(media_RPn_freq_mhz);
static const struct attribute *media_perf_power_attrs[] = {
- &dev_attr_media_freq_factor.attr,
- &dev_attr_media_freq_factor_scale.attr,
- &dev_attr_media_RP0_freq_mhz.attr,
- &dev_attr_media_RPn_freq_mhz.attr,
+ &attr_media_freq_factor.attr,
+ &attr_media_freq_factor_scale.attr,
+ &attr_media_RP0_freq_mhz.attr,
+ &attr_media_RPn_freq_mhz.attr,
NULL
};
@@ -754,20 +710,29 @@ static const struct attribute * const rps_defaults_attrs[] = {
NULL
};
-static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj,
- const struct attribute * const *attrs)
+static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj)
{
+ const struct attribute * const *attrs;
+ struct attribute *vlv_attr;
int ret;
if (GRAPHICS_VER(gt->i915) < 6)
return 0;
+ if (is_object_gt(kobj)) {
+ attrs = gen6_rps_attrs;
+ vlv_attr = &attr_rps_vlv_rpe_freq_mhz.attr;
+ } else {
+ attrs = gen6_gt_attrs;
+ vlv_attr = &dev_attr_gt_vlv_rpe_freq_mhz.attr;
+ }
+
ret = sysfs_create_files(kobj, attrs);
if (ret)
return ret;
if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915))
- ret = sysfs_create_file(kobj, &dev_attr_vlv_rpe_freq_mhz.attr);
+ ret = sysfs_create_file(kobj, vlv_attr);
return ret;
}
@@ -778,9 +743,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
intel_sysfs_rc6_init(gt, kobj);
- ret = is_object_gt(kobj) ?
- intel_sysfs_rps_init(gt, kobj, gen6_rps_attrs) :
- intel_sysfs_rps_init(gt, kobj, gen6_gt_attrs);
+ ret = intel_sysfs_rps_init(gt, kobj);
if (ret)
drm_warn(&gt->i915->drm,
"failed to create gt%u RPS sysfs files (%pe)",
@@ -790,13 +753,13 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
if (!is_object_gt(kobj))
return;
- ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr);
+ ret = sysfs_create_file(kobj, &attr_punit_req_freq_mhz.attr);
if (ret)
drm_warn(&gt->i915->drm,
"failed to create gt%u punit_req_freq_mhz sysfs (%pe)",
gt->info.id, ERR_PTR(ret));
- if (GRAPHICS_VER(gt->i915) >= 11) {
+ if (i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt))) {
ret = sysfs_create_files(kobj, throttle_reason_attrs);
if (ret)
drm_warn(&gt->i915->drm,
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h
index f19c2de77ff6..c1d9cd255e06 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h
@@ -20,6 +20,7 @@
#include "intel_gsc.h"
#include "i915_vma.h"
+#include "i915_perf_types.h"
#include "intel_engine_types.h"
#include "intel_gt_buffer_pool_types.h"
#include "intel_hwconfig.h"
@@ -30,6 +31,7 @@
#include "intel_migrate_types.h"
#include "intel_wakeref.h"
#include "pxp/intel_pxp_types.h"
+#include "intel_wopcm.h"
struct drm_i915_private;
struct i915_ggtt;
@@ -59,6 +61,9 @@ enum intel_steering_type {
L3BANK,
MSLICE,
LNCF,
+ GAM,
+ DSS,
+ OADDRM,
/*
* On some platforms there are multiple types of MCR registers that
@@ -97,6 +102,7 @@ struct intel_gt {
struct intel_uc uc;
struct intel_gsc gsc;
+ struct intel_wopcm wopcm;
struct {
/* Serialize global tlb invalidations */
@@ -141,20 +147,6 @@ struct intel_gt {
struct intel_wakeref wakeref;
atomic_t user_wakeref;
- /**
- * Protects access to lmem usefault list.
- * It is required, if we are outside of the runtime suspend path,
- * access to @lmem_userfault_list requires always first grabbing the
- * runtime pm, to ensure we can't race against runtime suspend.
- * Once we have that we also need to grab @lmem_userfault_lock,
- * at which point we have exclusive access.
- * The runtime suspend path is special since it doesn't really hold any locks,
- * but instead has exclusive access by virtue of all other accesses requiring
- * holding the runtime pm wakeref.
- */
- struct mutex lmem_userfault_lock;
- struct list_head lmem_userfault_list;
-
struct list_head closed_vma;
spinlock_t closed_lock; /* guards the list of closed_vma */
@@ -170,9 +162,6 @@ struct intel_gt {
*/
intel_wakeref_t awake;
- /* Manual runtime pm autosuspend delay for user GGTT/lmem mmaps */
- struct intel_wakeref_auto userfault_wakeref;
-
u32 clock_frequency;
u32 clock_period_ns;
@@ -286,6 +275,8 @@ struct intel_gt {
/* sysfs defaults per gt */
struct gt_defaults defaults;
struct kobject *sysfs_defaults;
+
+ struct i915_perf_gt perf;
};
struct intel_gt_definition {
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 2eaeba14319e..2ba3983984b9 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -12,9 +12,11 @@
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
+#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_utils.h"
#include "intel_gt.h"
+#include "intel_gt_mcr.h"
#include "intel_gt_regs.h"
#include "intel_gtt.h"
@@ -269,11 +271,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
memset64(vm->min_alignment, I915_GTT_MIN_ALIGNMENT,
ARRAY_SIZE(vm->min_alignment));
- if (HAS_64K_PAGES(vm->i915) && NEEDS_COMPACT_PT(vm->i915) &&
- subclass == VM_CLASS_PPGTT) {
- vm->min_alignment[INTEL_MEMORY_LOCAL] = I915_GTT_PAGE_SIZE_2M;
- vm->min_alignment[INTEL_MEMORY_STOLEN_LOCAL] = I915_GTT_PAGE_SIZE_2M;
- } else if (HAS_64K_PAGES(vm->i915)) {
+ if (HAS_64K_PAGES(vm->i915)) {
vm->min_alignment[INTEL_MEMORY_LOCAL] = I915_GTT_PAGE_SIZE_64K;
vm->min_alignment[INTEL_MEMORY_STOLEN_LOCAL] = I915_GTT_PAGE_SIZE_64K;
}
@@ -343,7 +341,8 @@ int setup_scratch_page(struct i915_address_space *vm)
*/
size = I915_GTT_PAGE_SIZE_4K;
if (i915_vm_is_4lvl(vm) &&
- HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K))
+ HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K) &&
+ !HAS_64K_PAGES(vm->i915))
size = I915_GTT_PAGE_SIZE_64K;
do {
@@ -385,18 +384,6 @@ skip:
if (size == I915_GTT_PAGE_SIZE_4K)
return -ENOMEM;
- /*
- * If we need 64K minimum GTT pages for device local-memory,
- * like on XEHPSDV, then we need to fail the allocation here,
- * otherwise we can't safely support the insertion of
- * local-memory pages for this vm, since the HW expects the
- * correct physical alignment and size when the page-table is
- * operating in 64K GTT mode, which includes any scratch PTEs,
- * since userspace can still touch them.
- */
- if (HAS_64K_PAGES(vm->i915))
- return -ENOMEM;
-
size = I915_GTT_PAGE_SIZE_4K;
} while (1);
}
@@ -493,6 +480,18 @@ static void tgl_setup_private_ppat(struct intel_uncore *uncore)
intel_uncore_write(uncore, GEN12_PAT_INDEX(7), GEN8_PPAT_WB);
}
+static void xehp_setup_private_ppat(struct intel_gt *gt)
+{
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(0), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(1), GEN8_PPAT_WC);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(2), GEN8_PPAT_WT);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(3), GEN8_PPAT_UC);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(4), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(5), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(6), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(7), GEN8_PPAT_WB);
+}
+
static void icl_setup_private_ppat(struct intel_uncore *uncore)
{
intel_uncore_write(uncore,
@@ -585,13 +584,16 @@ static void chv_setup_private_ppat(struct intel_uncore *uncore)
intel_uncore_write(uncore, GEN8_PRIVATE_PAT_HI, upper_32_bits(pat));
}
-void setup_private_pat(struct intel_uncore *uncore)
+void setup_private_pat(struct intel_gt *gt)
{
- struct drm_i915_private *i915 = uncore->i915;
+ struct intel_uncore *uncore = gt->uncore;
+ struct drm_i915_private *i915 = gt->i915;
GEM_BUG_ON(GRAPHICS_VER(i915) < 8);
- if (GRAPHICS_VER(i915) >= 12)
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50))
+ xehp_setup_private_ppat(gt);
+ else if (GRAPHICS_VER(i915) >= 12)
tgl_setup_private_ppat(uncore);
else if (GRAPHICS_VER(i915) >= 11)
icl_setup_private_ppat(uncore);
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index c0ca53cba9f0..4d75ba4bb41d 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -93,6 +93,7 @@ typedef u64 gen8_pte_t;
#define GEN12_GGTT_PTE_LM BIT_ULL(1)
#define GEN12_PDE_64K BIT(6)
+#define GEN12_PTE_PS64 BIT(8)
/*
* Cacheability Control is a 4-bit value. The low three bits are stored in bits
@@ -667,7 +668,7 @@ void ppgtt_unbind_vma(struct i915_address_space *vm,
void gtt_write_workarounds(struct intel_gt *gt);
-void setup_private_pat(struct intel_uncore *uncore);
+void setup_private_pat(struct intel_gt *gt);
int i915_vm_alloc_pt_stash(struct i915_address_space *vm,
struct i915_vm_pt_stash *stash,
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 3955292483a6..7771a19008c6 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -20,6 +20,30 @@
#include "intel_ring.h"
#include "shmem_utils.h"
+/*
+ * The per-platform tables are u8-encoded in @data. Decode @data and set the
+ * addresses' offset and commands in @regs. The following encoding is used
+ * for each byte. There are 2 steps: decoding commands and decoding addresses.
+ *
+ * Commands:
+ * [7]: create NOPs - number of NOPs are set in lower bits
+ * [6]: When creating MI_LOAD_REGISTER_IMM command, allow to set
+ * MI_LRI_FORCE_POSTED
+ * [5:0]: Number of NOPs or registers to set values to in case of
+ * MI_LOAD_REGISTER_IMM
+ *
+ * Addresses: these are decoded after a MI_LOAD_REGISTER_IMM command by "count"
+ * number of registers. They are set by using the REG/REG16 macros: the former
+ * is used for offsets smaller than 0x200 while the latter is for values bigger
+ * than that. Those macros already set all the bits documented below correctly:
+ *
+ * [7]: When a register offset needs more than 6 bits, use additional bytes, to
+ * follow, for the lower bits
+ * [6:0]: Register offset, without considering the engine base.
+ *
+ * This function only tweaks the commands and register offsets. Values are not
+ * filled out.
+ */
static void set_offsets(u32 *regs,
const u8 *data,
const struct intel_engine_cs *engine,
@@ -264,6 +288,39 @@ static const u8 dg2_xcs_offsets[] = {
END
};
+static const u8 mtl_xcs_offsets[] = {
+ NOP(1),
+ LRI(13, POSTED),
+ REG16(0x244),
+ REG(0x034),
+ REG(0x030),
+ REG(0x038),
+ REG(0x03c),
+ REG(0x168),
+ REG(0x140),
+ REG(0x110),
+ REG(0x1c0),
+ REG(0x1c4),
+ REG(0x1c8),
+ REG(0x180),
+ REG16(0x2b4),
+ NOP(4),
+
+ NOP(1),
+ LRI(9, POSTED),
+ REG16(0x3a8),
+ REG16(0x28c),
+ REG16(0x288),
+ REG16(0x284),
+ REG16(0x280),
+ REG16(0x27c),
+ REG16(0x278),
+ REG16(0x274),
+ REG16(0x270),
+
+ END
+};
+
static const u8 gen8_rcs_offsets[] = {
NOP(1),
LRI(14, POSTED),
@@ -606,6 +663,49 @@ static const u8 dg2_rcs_offsets[] = {
END
};
+static const u8 mtl_rcs_offsets[] = {
+ NOP(1),
+ LRI(15, POSTED),
+ REG16(0x244),
+ REG(0x034),
+ REG(0x030),
+ REG(0x038),
+ REG(0x03c),
+ REG(0x168),
+ REG(0x140),
+ REG(0x110),
+ REG(0x1c0),
+ REG(0x1c4),
+ REG(0x1c8),
+ REG(0x180),
+ REG16(0x2b4),
+ REG(0x120),
+ REG(0x124),
+
+ NOP(1),
+ LRI(9, POSTED),
+ REG16(0x3a8),
+ REG16(0x28c),
+ REG16(0x288),
+ REG16(0x284),
+ REG16(0x280),
+ REG16(0x27c),
+ REG16(0x278),
+ REG16(0x274),
+ REG16(0x270),
+
+ NOP(2),
+ LRI(2, POSTED),
+ REG16(0x5a8),
+ REG16(0x5ac),
+
+ NOP(6),
+ LRI(1, 0),
+ REG(0x0c8),
+
+ END
+};
+
#undef END
#undef REG16
#undef REG
@@ -624,7 +724,9 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine)
!intel_engine_has_relative_mmio(engine));
if (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE) {
- if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
+ if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70))
+ return mtl_rcs_offsets;
+ else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
return dg2_rcs_offsets;
else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50))
return xehp_rcs_offsets;
@@ -637,7 +739,9 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine)
else
return gen8_rcs_offsets;
} else {
- if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
+ if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70))
+ return mtl_xcs_offsets;
+ else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
return dg2_xcs_offsets;
else if (GRAPHICS_VER(engine->i915) >= 12)
return gen12_xcs_offsets;
@@ -745,19 +849,18 @@ static int lrc_ring_cmd_buf_cctl(const struct intel_engine_cs *engine)
static u32
lrc_ring_indirect_offset_default(const struct intel_engine_cs *engine)
{
- switch (GRAPHICS_VER(engine->i915)) {
- default:
- MISSING_CASE(GRAPHICS_VER(engine->i915));
- fallthrough;
- case 12:
+ if (GRAPHICS_VER(engine->i915) >= 12)
return GEN12_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
- case 11:
+ else if (GRAPHICS_VER(engine->i915) >= 11)
return GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
- case 9:
+ else if (GRAPHICS_VER(engine->i915) >= 9)
return GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
- case 8:
+ else if (GRAPHICS_VER(engine->i915) >= 8)
return GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
- }
+
+ GEM_BUG_ON(GRAPHICS_VER(engine->i915) < 8);
+
+ return 0;
}
static void
@@ -1012,7 +1115,7 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine)
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
context_size += I915_GTT_PAGE_SIZE; /* for redzone */
- if (GRAPHICS_VER(engine->i915) == 12) {
+ if (GRAPHICS_VER(engine->i915) >= 12) {
ce->wa_bb_page = context_size / PAGE_SIZE;
context_size += PAGE_SIZE;
}
@@ -1718,24 +1821,16 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine)
unsigned int i;
int err;
- if (!(engine->flags & I915_ENGINE_HAS_RCS_REG_STATE))
+ if (GRAPHICS_VER(engine->i915) >= 11 ||
+ !(engine->flags & I915_ENGINE_HAS_RCS_REG_STATE))
return;
- switch (GRAPHICS_VER(engine->i915)) {
- case 12:
- case 11:
- return;
- case 9:
+ if (GRAPHICS_VER(engine->i915) == 9) {
wa_bb_fn[0] = gen9_init_indirectctx_bb;
wa_bb_fn[1] = NULL;
- break;
- case 8:
+ } else if (GRAPHICS_VER(engine->i915) == 8) {
wa_bb_fn[0] = gen8_init_indirectctx_bb;
wa_bb_fn[1] = NULL;
- break;
- default:
- MISSING_CASE(GRAPHICS_VER(engine->i915));
- return;
}
err = lrc_create_wa_ctx(engine);
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.h b/drivers/gpu/drm/i915/gt/intel_lrc.h
index a390f0813c8b..7111bae759f3 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.h
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.h
@@ -110,6 +110,8 @@ enum {
#define XEHP_SW_CTX_ID_WIDTH 16
#define XEHP_SW_COUNTER_SHIFT 58
#define XEHP_SW_COUNTER_WIDTH 6
+#define GEN12_GUC_SW_CTX_ID_SHIFT 39
+#define GEN12_GUC_SW_CTX_ID_WIDTH 16
static inline void lrc_runtime_start(struct intel_context *ce)
{
diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c b/drivers/gpu/drm/i915/gt/intel_migrate.c
index aaaf1906026c..b405a04135ca 100644
--- a/drivers/gpu/drm/i915/gt/intel_migrate.c
+++ b/drivers/gpu/drm/i915/gt/intel_migrate.c
@@ -10,6 +10,7 @@
#include "intel_gtt.h"
#include "intel_migrate.h"
#include "intel_ring.h"
+#include "gem/i915_gem_lmem.h"
struct insert_pte_data {
u64 offset;
diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c
index 152244d7f62a..49fdd509527a 100644
--- a/drivers/gpu/drm/i915/gt/intel_mocs.c
+++ b/drivers/gpu/drm/i915/gt/intel_mocs.c
@@ -7,6 +7,7 @@
#include "intel_engine.h"
#include "intel_gt.h"
+#include "intel_gt_mcr.h"
#include "intel_gt_regs.h"
#include "intel_mocs.h"
#include "intel_ring.h"
@@ -609,14 +610,17 @@ static u32 l3cc_combine(u16 low, u16 high)
0; \
i++)
-static void init_l3cc_table(struct intel_uncore *uncore,
+static void init_l3cc_table(struct intel_gt *gt,
const struct drm_i915_mocs_table *table)
{
unsigned int i;
u32 l3cc;
for_each_l3cc(l3cc, table, i)
- intel_uncore_write_fw(uncore, GEN9_LNCFCMOCS(i), l3cc);
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_LNCFCMOCS(i), l3cc);
+ else
+ intel_uncore_write_fw(gt->uncore, GEN9_LNCFCMOCS(i), l3cc);
}
void intel_mocs_init_engine(struct intel_engine_cs *engine)
@@ -636,7 +640,7 @@ void intel_mocs_init_engine(struct intel_engine_cs *engine)
init_mocs_table(engine, &table);
if (flags & HAS_RENDER_L3CC && engine->class == RENDER_CLASS)
- init_l3cc_table(engine->uncore, &table);
+ init_l3cc_table(engine->gt, &table);
}
static u32 global_mocs_offset(void)
@@ -672,7 +676,7 @@ void intel_mocs_init(struct intel_gt *gt)
* memory transactions including guc transactions
*/
if (flags & HAS_RENDER_L3CC)
- init_l3cc_table(gt->uncore, &table);
+ init_l3cc_table(gt, &table);
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
index f8d0523f4c18..2ee4051e4d96 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.c
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
@@ -551,6 +551,23 @@ static void __intel_rc6_disable(struct intel_rc6 *rc6)
intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
}
+static void rc6_res_reg_init(struct intel_rc6 *rc6)
+{
+ memset(rc6->res_reg, INVALID_MMIO_REG.reg, sizeof(rc6->res_reg));
+
+ switch (rc6_to_gt(rc6)->type) {
+ case GT_MEDIA:
+ rc6->res_reg[INTEL_RC6_RES_RC6] = MTL_MEDIA_MC6;
+ break;
+ default:
+ rc6->res_reg[INTEL_RC6_RES_RC6_LOCKED] = GEN6_GT_GFX_RC6_LOCKED;
+ rc6->res_reg[INTEL_RC6_RES_RC6] = GEN6_GT_GFX_RC6;
+ rc6->res_reg[INTEL_RC6_RES_RC6p] = GEN6_GT_GFX_RC6p;
+ rc6->res_reg[INTEL_RC6_RES_RC6pp] = GEN6_GT_GFX_RC6pp;
+ break;
+ }
+}
+
void intel_rc6_init(struct intel_rc6 *rc6)
{
struct drm_i915_private *i915 = rc6_to_i915(rc6);
@@ -562,6 +579,8 @@ void intel_rc6_init(struct intel_rc6 *rc6)
if (!rc6_supported(rc6))
return;
+ rc6_res_reg_init(rc6);
+
if (IS_CHERRYVIEW(i915))
err = chv_rc6_init(rc6);
else if (IS_VALLEYVIEW(i915))
@@ -736,31 +755,19 @@ static u64 vlv_residency_raw(struct intel_uncore *uncore, const i915_reg_t reg)
return lower | (u64)upper << 8;
}
-u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, const i915_reg_t reg)
+u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, enum intel_rc6_res_type id)
{
struct drm_i915_private *i915 = rc6_to_i915(rc6);
struct intel_uncore *uncore = rc6_to_uncore(rc6);
u64 time_hw, prev_hw, overflow_hw;
+ i915_reg_t reg = rc6->res_reg[id];
unsigned int fw_domains;
unsigned long flags;
- unsigned int i;
u32 mul, div;
if (!rc6->supported)
return 0;
- /*
- * Store previous hw counter values for counter wrap-around handling.
- *
- * There are only four interesting registers and they live next to each
- * other so we can use the relative address, compared to the smallest
- * one as the index into driver storage.
- */
- i = (i915_mmio_reg_offset(reg) -
- i915_mmio_reg_offset(GEN6_GT_GFX_RC6_LOCKED)) / sizeof(u32);
- if (drm_WARN_ON_ONCE(&i915->drm, i >= ARRAY_SIZE(rc6->cur_residency)))
- return 0;
-
fw_domains = intel_uncore_forcewake_for_reg(uncore, reg, FW_REG_READ);
spin_lock_irqsave(&uncore->lock, flags);
@@ -789,11 +796,11 @@ u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, const i915_reg_t reg)
/*
* Counter wrap handling.
*
- * But relying on a sufficient frequency of queries otherwise counters
- * can still wrap.
+ * Store previous hw counter values for counter wrap-around handling. But
+ * relying on a sufficient frequency of queries otherwise counters can still wrap.
*/
- prev_hw = rc6->prev_hw_residency[i];
- rc6->prev_hw_residency[i] = time_hw;
+ prev_hw = rc6->prev_hw_residency[id];
+ rc6->prev_hw_residency[id] = time_hw;
/* RC6 delta from last sample. */
if (time_hw >= prev_hw)
@@ -802,8 +809,8 @@ u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, const i915_reg_t reg)
time_hw += overflow_hw - prev_hw;
/* Add delta to RC6 extended raw driver copy. */
- time_hw += rc6->cur_residency[i];
- rc6->cur_residency[i] = time_hw;
+ time_hw += rc6->cur_residency[id];
+ rc6->cur_residency[id] = time_hw;
intel_uncore_forcewake_put__locked(uncore, fw_domains);
spin_unlock_irqrestore(&uncore->lock, flags);
@@ -811,9 +818,22 @@ u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, const i915_reg_t reg)
return mul_u64_u32_div(time_hw, mul, div);
}
-u64 intel_rc6_residency_us(struct intel_rc6 *rc6, i915_reg_t reg)
+u64 intel_rc6_residency_us(struct intel_rc6 *rc6, enum intel_rc6_res_type id)
+{
+ return DIV_ROUND_UP_ULL(intel_rc6_residency_ns(rc6, id), 1000);
+}
+
+void intel_rc6_print_residency(struct seq_file *m, const char *title,
+ enum intel_rc6_res_type id)
{
- return DIV_ROUND_UP_ULL(intel_rc6_residency_ns(rc6, reg), 1000);
+ struct intel_gt *gt = m->private;
+ i915_reg_t reg = gt->rc6.res_reg[id];
+ intel_wakeref_t wakeref;
+
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ seq_printf(m, "%s %u (%llu us)\n", title,
+ intel_uncore_read(gt->uncore, reg),
+ intel_rc6_residency_us(&gt->rc6, id));
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.h b/drivers/gpu/drm/i915/gt/intel_rc6.h
index b6fea71afc22..456fa668a276 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.h
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.h
@@ -6,10 +6,11 @@
#ifndef INTEL_RC6_H
#define INTEL_RC6_H
-#include "i915_reg_defs.h"
+#include <linux/types.h>
-struct intel_engine_cs;
+enum intel_rc6_res_type;
struct intel_rc6;
+struct seq_file;
void intel_rc6_init(struct intel_rc6 *rc6);
void intel_rc6_fini(struct intel_rc6 *rc6);
@@ -21,7 +22,9 @@ void intel_rc6_sanitize(struct intel_rc6 *rc6);
void intel_rc6_enable(struct intel_rc6 *rc6);
void intel_rc6_disable(struct intel_rc6 *rc6);
-u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, i915_reg_t reg);
-u64 intel_rc6_residency_us(struct intel_rc6 *rc6, i915_reg_t reg);
+u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, enum intel_rc6_res_type id);
+u64 intel_rc6_residency_us(struct intel_rc6 *rc6, enum intel_rc6_res_type id);
+void intel_rc6_print_residency(struct seq_file *m, const char *title,
+ enum intel_rc6_res_type id);
#endif /* INTEL_RC6_H */
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6_types.h b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
index e747492b2f46..fa23c4dce00b 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
@@ -13,9 +13,20 @@
struct drm_i915_gem_object;
+/* RC6 residency types */
+enum intel_rc6_res_type {
+ INTEL_RC6_RES_RC6_LOCKED,
+ INTEL_RC6_RES_RC6,
+ INTEL_RC6_RES_RC6p,
+ INTEL_RC6_RES_RC6pp,
+ INTEL_RC6_RES_MAX,
+ INTEL_RC6_RES_VLV_MEDIA = INTEL_RC6_RES_RC6p,
+};
+
struct intel_rc6 {
- u64 prev_hw_residency[4];
- u64 cur_residency[4];
+ i915_reg_t res_reg[INTEL_RC6_RES_MAX];
+ u64 prev_hw_residency[INTEL_RC6_RES_MAX];
+ u64 cur_residency[INTEL_RC6_RES_MAX];
u32 ctl_enable;
diff --git a/drivers/gpu/drm/i915/gt/intel_renderstate.c b/drivers/gpu/drm/i915/gt/intel_renderstate.c
index 5121e6dc2fa5..9c1ae070ee7b 100644
--- a/drivers/gpu/drm/i915/gt/intel_renderstate.c
+++ b/drivers/gpu/drm/i915/gt/intel_renderstate.c
@@ -215,9 +215,7 @@ int intel_renderstate_emit(struct intel_renderstate *so,
if (!so->vma)
return 0;
- err = i915_request_await_object(rq, so->vma->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(so->vma, rq, 0);
+ err = i915_vma_move_to_active(so->vma, rq, 0);
if (err)
return err;
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index b36674356986..24736ebee17c 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -1278,7 +1278,7 @@ static void intel_gt_reset_global(struct intel_gt *gt,
kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
/* Use a watchdog to ensure that our reset completes */
- intel_wedge_on_timeout(&w, gt, 5 * HZ) {
+ intel_wedge_on_timeout(&w, gt, 60 * HZ) {
intel_display_prepare_reset(gt->i915);
intel_gt_reset(gt, engine_mask, reason);
@@ -1407,15 +1407,19 @@ out:
intel_runtime_pm_put(gt->uncore->rpm, wakeref);
}
-int intel_gt_reset_trylock(struct intel_gt *gt, int *srcu)
+static int _intel_gt_reset_lock(struct intel_gt *gt, int *srcu, bool retry)
{
might_lock(&gt->reset.backoff_srcu);
- might_sleep();
+ if (retry)
+ might_sleep();
rcu_read_lock();
while (test_bit(I915_RESET_BACKOFF, &gt->reset.flags)) {
rcu_read_unlock();
+ if (!retry)
+ return -EBUSY;
+
if (wait_event_interruptible(gt->reset.queue,
!test_bit(I915_RESET_BACKOFF,
&gt->reset.flags)))
@@ -1429,6 +1433,16 @@ int intel_gt_reset_trylock(struct intel_gt *gt, int *srcu)
return 0;
}
+int intel_gt_reset_trylock(struct intel_gt *gt, int *srcu)
+{
+ return _intel_gt_reset_lock(gt, srcu, false);
+}
+
+int intel_gt_reset_lock_interruptible(struct intel_gt *gt, int *srcu)
+{
+ return _intel_gt_reset_lock(gt, srcu, true);
+}
+
void intel_gt_reset_unlock(struct intel_gt *gt, int tag)
__releases(&gt->reset.backoff_srcu)
{
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.h b/drivers/gpu/drm/i915/gt/intel_reset.h
index adc734e67387..25c975b6e8fc 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.h
+++ b/drivers/gpu/drm/i915/gt/intel_reset.h
@@ -39,6 +39,7 @@ int __intel_engine_reset_bh(struct intel_engine_cs *engine,
void __i915_request_reset(struct i915_request *rq, bool guilty);
int __must_check intel_gt_reset_trylock(struct intel_gt *gt, int *srcu);
+int __must_check intel_gt_reset_lock_interruptible(struct intel_gt *gt, int *srcu);
void intel_gt_reset_unlock(struct intel_gt *gt, int tag);
void intel_gt_set_wedged(struct intel_gt *gt);
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
index d5d6f1fadcae..356c787e11d3 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
@@ -12,7 +12,9 @@
#include "gen6_ppgtt.h"
#include "gen7_renderclear.h"
#include "i915_drv.h"
+#include "i915_irq.h"
#include "i915_mitigations.h"
+#include "i915_reg.h"
#include "intel_breadcrumbs.h"
#include "intel_context.h"
#include "intel_engine_regs.h"
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index 6b86250c31ab..9ad3bc7201cb 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -430,7 +430,8 @@ static int __gen5_rps_set(struct intel_rps *rps, u8 val)
rgvswctl = intel_uncore_read16(uncore, MEMSWCTL);
if (rgvswctl & MEMCTL_CMD_STS) {
- DRM_DEBUG("gpu busy, RCS change rejected\n");
+ drm_dbg(&rps_to_i915(rps)->drm,
+ "gpu busy, RCS change rejected\n");
return -EBUSY; /* still busy with another command */
}
@@ -625,9 +626,7 @@ static void gen5_rps_disable(struct intel_rps *rps)
rgvswctl = intel_uncore_read16(uncore, MEMSWCTL);
/* Ack interrupts, disable EFC interrupt */
- intel_uncore_write(uncore, MEMINTREN,
- intel_uncore_read(uncore, MEMINTREN) &
- ~MEMINT_EVAL_CHG_EN);
+ intel_uncore_rmw(uncore, MEMINTREN, MEMINT_EVAL_CHG_EN, 0);
intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG);
/* Go back to the starting frequency */
@@ -1016,9 +1015,15 @@ void intel_rps_boost(struct i915_request *rq)
if (rps_uses_slpc(rps)) {
slpc = rps_to_slpc(rps);
+ if (slpc->min_freq_softlimit >= slpc->boost_freq)
+ return;
+
/* Return if old value is non zero */
- if (!atomic_fetch_inc(&slpc->num_waiters))
+ if (!atomic_fetch_inc(&slpc->num_waiters)) {
+ GT_TRACE(rps_to_gt(rps), "boost fence:%llx:%llx\n",
+ rq->fence.context, rq->fence.seqno);
schedule_work(&slpc->boost_work);
+ }
return;
}
@@ -1085,15 +1090,25 @@ static u32 intel_rps_read_state_cap(struct intel_rps *rps)
return intel_uncore_read(uncore, GEN6_RP_STATE_CAP);
}
-/**
- * gen6_rps_get_freq_caps - Get freq caps exposed by HW
- * @rps: the intel_rps structure
- * @caps: returned freq caps
- *
- * Returned "caps" frequencies should be converted to MHz using
- * intel_gpu_freq()
- */
-void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
+static void
+mtl_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
+{
+ struct intel_uncore *uncore = rps_to_uncore(rps);
+ u32 rp_state_cap = rps_to_gt(rps)->type == GT_MEDIA ?
+ intel_uncore_read(uncore, MTL_MEDIAP_STATE_CAP) :
+ intel_uncore_read(uncore, MTL_RP_STATE_CAP);
+ u32 rpe = rps_to_gt(rps)->type == GT_MEDIA ?
+ intel_uncore_read(uncore, MTL_MPE_FREQUENCY) :
+ intel_uncore_read(uncore, MTL_GT_RPE_FREQUENCY);
+
+ /* MTL values are in units of 16.67 MHz */
+ caps->rp0_freq = REG_FIELD_GET(MTL_RP0_CAP_MASK, rp_state_cap);
+ caps->min_freq = REG_FIELD_GET(MTL_RPN_CAP_MASK, rp_state_cap);
+ caps->rp1_freq = REG_FIELD_GET(MTL_RPE_MASK, rpe);
+}
+
+static void
+__gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
{
struct drm_i915_private *i915 = rps_to_i915(rps);
u32 rp_state_cap;
@@ -1128,6 +1143,24 @@ void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *c
}
}
+/**
+ * gen6_rps_get_freq_caps - Get freq caps exposed by HW
+ * @rps: the intel_rps structure
+ * @caps: returned freq caps
+ *
+ * Returned "caps" frequencies should be converted to MHz using
+ * intel_gpu_freq()
+ */
+void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
+{
+ struct drm_i915_private *i915 = rps_to_i915(rps);
+
+ if (IS_METEORLAKE(i915))
+ return mtl_get_freq_caps(rps, caps);
+ else
+ return __gen6_rps_get_freq_caps(rps, caps);
+}
+
static void gen6_rps_init(struct intel_rps *rps)
{
struct drm_i915_private *i915 = rps_to_i915(rps);
@@ -1921,7 +1954,8 @@ void gen6_rps_irq_handler(struct intel_rps *rps, u32 pm_iir)
intel_engine_cs_irq(gt->engine[VECS0], pm_iir >> 10);
if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
- DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
+ drm_dbg(&rps_to_i915(rps)->drm,
+ "Command parser error, pm_iir 0x%08x\n", pm_iir);
}
void gen5_rps_irq_handler(struct intel_rps *rps)
@@ -2040,22 +2074,45 @@ void intel_rps_sanitize(struct intel_rps *rps)
rps_disable_interrupts(rps);
}
+u32 intel_rps_read_rpstat_fw(struct intel_rps *rps)
+{
+ struct drm_i915_private *i915 = rps_to_i915(rps);
+ i915_reg_t rpstat;
+
+ rpstat = (GRAPHICS_VER(i915) >= 12) ? GEN12_RPSTAT1 : GEN6_RPSTAT1;
+
+ return intel_uncore_read_fw(rps_to_gt(rps)->uncore, rpstat);
+}
+
+u32 intel_rps_read_rpstat(struct intel_rps *rps)
+{
+ struct drm_i915_private *i915 = rps_to_i915(rps);
+ i915_reg_t rpstat;
+
+ rpstat = (GRAPHICS_VER(i915) >= 12) ? GEN12_RPSTAT1 : GEN6_RPSTAT1;
+
+ return intel_uncore_read(rps_to_gt(rps)->uncore, rpstat);
+}
+
u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat)
{
struct drm_i915_private *i915 = rps_to_i915(rps);
u32 cagf;
- if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
- cagf = (rpstat >> 8) & 0xff;
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
+ cagf = REG_FIELD_GET(MTL_CAGF_MASK, rpstat);
+ else if (GRAPHICS_VER(i915) >= 12)
+ cagf = REG_FIELD_GET(GEN12_CAGF_MASK, rpstat);
+ else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ cagf = REG_FIELD_GET(RPE_MASK, rpstat);
else if (GRAPHICS_VER(i915) >= 9)
- cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT;
+ cagf = REG_FIELD_GET(GEN9_CAGF_MASK, rpstat);
else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
- cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
+ cagf = REG_FIELD_GET(HSW_CAGF_MASK, rpstat);
else if (GRAPHICS_VER(i915) >= 6)
- cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
+ cagf = REG_FIELD_GET(GEN6_CAGF_MASK, rpstat);
else
- cagf = gen5_invert_freq(rps, (rpstat & MEMSTAT_PSTATE_MASK) >>
- MEMSTAT_PSTATE_SHIFT);
+ cagf = gen5_invert_freq(rps, REG_FIELD_GET(MEMSTAT_PSTATE_MASK, rpstat));
return cagf;
}
@@ -2066,7 +2123,15 @@ static u32 read_cagf(struct intel_rps *rps)
struct intel_uncore *uncore = rps_to_uncore(rps);
u32 freq;
- if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ /*
+ * For Gen12+ reading freq from HW does not need a forcewake and
+ * registers will return 0 freq when GT is in RC6
+ */
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) {
+ freq = intel_uncore_read(uncore, MTL_MIRROR_TARGET_WP1);
+ } else if (GRAPHICS_VER(i915) >= 12) {
+ freq = intel_uncore_read(uncore, GEN12_RPSTAT1);
+ } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
vlv_punit_get(i915);
freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
vlv_punit_put(i915);
@@ -2191,6 +2256,213 @@ u32 intel_rps_get_rpn_frequency(struct intel_rps *rps)
return intel_gpu_freq(rps, rps->min_freq);
}
+static void rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
+{
+ struct intel_gt *gt = rps_to_gt(rps);
+ struct drm_i915_private *i915 = gt->i915;
+ struct intel_uncore *uncore = gt->uncore;
+ struct intel_rps_freq_caps caps;
+ u32 rp_state_limits;
+ u32 gt_perf_status;
+ u32 rpmodectl, rpinclimit, rpdeclimit;
+ u32 rpstat, cagf, reqf;
+ u32 rpcurupei, rpcurup, rpprevup;
+ u32 rpcurdownei, rpcurdown, rpprevdown;
+ u32 rpupei, rpupt, rpdownei, rpdownt;
+ u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
+
+ rp_state_limits = intel_uncore_read(uncore, GEN6_RP_STATE_LIMITS);
+ gen6_rps_get_freq_caps(rps, &caps);
+ if (IS_GEN9_LP(i915))
+ gt_perf_status = intel_uncore_read(uncore, BXT_GT_PERF_STATUS);
+ else
+ gt_perf_status = intel_uncore_read(uncore, GEN6_GT_PERF_STATUS);
+
+ /* RPSTAT1 is in the GT power well */
+ intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
+
+ reqf = intel_uncore_read(uncore, GEN6_RPNSWREQ);
+ if (GRAPHICS_VER(i915) >= 9) {
+ reqf >>= 23;
+ } else {
+ reqf &= ~GEN6_TURBO_DISABLE;
+ if (IS_HASWELL(i915) || IS_BROADWELL(i915))
+ reqf >>= 24;
+ else
+ reqf >>= 25;
+ }
+ reqf = intel_gpu_freq(rps, reqf);
+
+ rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL);
+ rpinclimit = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
+ rpdeclimit = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
+
+ rpstat = intel_rps_read_rpstat(rps);
+ rpcurupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK;
+ rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK;
+ rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK;
+ rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
+ rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK;
+ rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK;
+
+ rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI);
+ rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
+
+ rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI);
+ rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
+
+ cagf = intel_rps_read_actual_frequency(rps);
+
+ intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
+
+ if (GRAPHICS_VER(i915) >= 11) {
+ pm_ier = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE);
+ pm_imr = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK);
+ /*
+ * The equivalent to the PM ISR & IIR cannot be read
+ * without affecting the current state of the system
+ */
+ pm_isr = 0;
+ pm_iir = 0;
+ } else if (GRAPHICS_VER(i915) >= 8) {
+ pm_ier = intel_uncore_read(uncore, GEN8_GT_IER(2));
+ pm_imr = intel_uncore_read(uncore, GEN8_GT_IMR(2));
+ pm_isr = intel_uncore_read(uncore, GEN8_GT_ISR(2));
+ pm_iir = intel_uncore_read(uncore, GEN8_GT_IIR(2));
+ } else {
+ pm_ier = intel_uncore_read(uncore, GEN6_PMIER);
+ pm_imr = intel_uncore_read(uncore, GEN6_PMIMR);
+ pm_isr = intel_uncore_read(uncore, GEN6_PMISR);
+ pm_iir = intel_uncore_read(uncore, GEN6_PMIIR);
+ }
+ pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
+
+ drm_printf(p, "Video Turbo Mode: %s\n",
+ str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO));
+ drm_printf(p, "HW control enabled: %s\n",
+ str_yes_no(rpmodectl & GEN6_RP_ENABLE));
+ drm_printf(p, "SW control enabled: %s\n",
+ str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
+
+ drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
+ pm_ier, pm_imr, pm_mask);
+ if (GRAPHICS_VER(i915) <= 10)
+ drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n",
+ pm_isr, pm_iir);
+ drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n",
+ rps->pm_intrmsk_mbz);
+ drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
+ drm_printf(p, "Render p-state ratio: %d\n",
+ (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8);
+ drm_printf(p, "Render p-state VID: %d\n",
+ gt_perf_status & 0xff);
+ drm_printf(p, "Render p-state limit: %d\n",
+ rp_state_limits & 0xff);
+ drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat);
+ drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl);
+ drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit);
+ drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit);
+ drm_printf(p, "RPNSWREQ: %dMHz\n", reqf);
+ drm_printf(p, "CAGF: %dMHz\n", cagf);
+ drm_printf(p, "RP CUR UP EI: %d (%lldns)\n",
+ rpcurupei,
+ intel_gt_pm_interval_to_ns(gt, rpcurupei));
+ drm_printf(p, "RP CUR UP: %d (%lldns)\n",
+ rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup));
+ drm_printf(p, "RP PREV UP: %d (%lldns)\n",
+ rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup));
+ drm_printf(p, "Up threshold: %d%%\n",
+ rps->power.up_threshold);
+ drm_printf(p, "RP UP EI: %d (%lldns)\n",
+ rpupei, intel_gt_pm_interval_to_ns(gt, rpupei));
+ drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n",
+ rpupt, intel_gt_pm_interval_to_ns(gt, rpupt));
+
+ drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n",
+ rpcurdownei,
+ intel_gt_pm_interval_to_ns(gt, rpcurdownei));
+ drm_printf(p, "RP CUR DOWN: %d (%lldns)\n",
+ rpcurdown,
+ intel_gt_pm_interval_to_ns(gt, rpcurdown));
+ drm_printf(p, "RP PREV DOWN: %d (%lldns)\n",
+ rpprevdown,
+ intel_gt_pm_interval_to_ns(gt, rpprevdown));
+ drm_printf(p, "Down threshold: %d%%\n",
+ rps->power.down_threshold);
+ drm_printf(p, "RP DOWN EI: %d (%lldns)\n",
+ rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei));
+ drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n",
+ rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt));
+
+ drm_printf(p, "Lowest (RPN) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.min_freq));
+ drm_printf(p, "Nominal (RP1) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.rp1_freq));
+ drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.rp0_freq));
+ drm_printf(p, "Max overclocked frequency: %dMHz\n",
+ intel_gpu_freq(rps, rps->max_freq));
+
+ drm_printf(p, "Current freq: %d MHz\n",
+ intel_gpu_freq(rps, rps->cur_freq));
+ drm_printf(p, "Actual freq: %d MHz\n", cagf);
+ drm_printf(p, "Idle freq: %d MHz\n",
+ intel_gpu_freq(rps, rps->idle_freq));
+ drm_printf(p, "Min freq: %d MHz\n",
+ intel_gpu_freq(rps, rps->min_freq));
+ drm_printf(p, "Boost freq: %d MHz\n",
+ intel_gpu_freq(rps, rps->boost_freq));
+ drm_printf(p, "Max freq: %d MHz\n",
+ intel_gpu_freq(rps, rps->max_freq));
+ drm_printf(p,
+ "efficient (RPe) frequency: %d MHz\n",
+ intel_gpu_freq(rps, rps->efficient_freq));
+}
+
+static void slpc_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
+{
+ struct intel_gt *gt = rps_to_gt(rps);
+ struct intel_uncore *uncore = gt->uncore;
+ struct intel_rps_freq_caps caps;
+ u32 pm_mask;
+
+ gen6_rps_get_freq_caps(rps, &caps);
+ pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
+
+ drm_printf(p, "PM MASK=0x%08x\n", pm_mask);
+ drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n",
+ rps->pm_intrmsk_mbz);
+ drm_printf(p, "RPSTAT1: 0x%08x\n", intel_rps_read_rpstat(rps));
+ drm_printf(p, "RPNSWREQ: %dMHz\n", intel_rps_get_requested_frequency(rps));
+ drm_printf(p, "Lowest (RPN) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.min_freq));
+ drm_printf(p, "Nominal (RP1) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.rp1_freq));
+ drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n",
+ intel_gpu_freq(rps, caps.rp0_freq));
+ drm_printf(p, "Current freq: %d MHz\n",
+ intel_rps_get_requested_frequency(rps));
+ drm_printf(p, "Actual freq: %d MHz\n",
+ intel_rps_read_actual_frequency(rps));
+ drm_printf(p, "Min freq: %d MHz\n",
+ intel_rps_get_min_frequency(rps));
+ drm_printf(p, "Boost freq: %d MHz\n",
+ intel_rps_get_boost_frequency(rps));
+ drm_printf(p, "Max freq: %d MHz\n",
+ intel_rps_get_max_frequency(rps));
+ drm_printf(p,
+ "efficient (RPe) frequency: %d MHz\n",
+ intel_gpu_freq(rps, caps.rp1_freq));
+}
+
+void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
+{
+ if (rps_uses_slpc(rps))
+ return slpc_frequency_dump(rps, p);
+ else
+ return rps_frequency_dump(rps, p);
+}
+
static int set_max_freq(struct intel_rps *rps, u32 val)
{
struct drm_i915_private *i915 = rps_to_i915(rps);
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.h b/drivers/gpu/drm/i915/gt/intel_rps.h
index 4509dfdc52e0..9e1cad9ba0e9 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.h
+++ b/drivers/gpu/drm/i915/gt/intel_rps.h
@@ -10,6 +10,7 @@
#include "i915_reg_defs.h"
struct i915_request;
+struct drm_printer;
void intel_rps_init_early(struct intel_rps *rps);
void intel_rps_init(struct intel_rps *rps);
@@ -47,6 +48,8 @@ u32 intel_rps_get_rp1_frequency(struct intel_rps *rps);
u32 intel_rps_get_rpn_frequency(struct intel_rps *rps);
u32 intel_rps_read_punit_req(struct intel_rps *rps);
u32 intel_rps_read_punit_req_frequency(struct intel_rps *rps);
+u32 intel_rps_read_rpstat(struct intel_rps *rps);
+u32 intel_rps_read_rpstat_fw(struct intel_rps *rps);
void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps);
void intel_rps_raise_unslice(struct intel_rps *rps);
void intel_rps_lower_unslice(struct intel_rps *rps);
@@ -54,6 +57,8 @@ void intel_rps_lower_unslice(struct intel_rps *rps);
u32 intel_rps_read_throttle_reason(struct intel_rps *rps);
bool rps_read_mask_mmio(struct intel_rps *rps, i915_reg_t reg32, u32 mask);
+void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p);
+
void gen5_rps_irq_handler(struct intel_rps *rps);
void gen6_rps_irq_handler(struct intel_rps *rps, u32 pm_iir);
void gen11_rps_irq_handler(struct intel_rps *rps, u32 pm_iir);
diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c
index 66f21c735d54..6c6198a257ac 100644
--- a/drivers/gpu/drm/i915/gt/intel_sseu.c
+++ b/drivers/gpu/drm/i915/gt/intel_sseu.c
@@ -677,8 +677,8 @@ u32 intel_sseu_make_rpcs(struct intel_gt *gt,
* If i915/perf is active, we want a stable powergating configuration
* on the system. Use the configuration pinned by i915/perf.
*/
- if (i915->perf.exclusive_stream)
- req_sseu = &i915->perf.sseu;
+ if (gt->perf.exclusive_stream)
+ req_sseu = &gt->perf.sseu;
slices = hweight8(req_sseu->slice_mask);
subslices = hweight8(req_sseu->subslice_mask);
diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/gt/intel_wopcm.c
index 322fb9eeb880..7ebbcc191c2d 100644
--- a/drivers/gpu/drm/i915/intel_wopcm.c
+++ b/drivers/gpu/drm/i915/gt/intel_wopcm.c
@@ -64,9 +64,9 @@
#define GEN9_GUC_FW_RESERVED SZ_128K
#define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED)
-static inline struct drm_i915_private *wopcm_to_i915(struct intel_wopcm *wopcm)
+static inline struct intel_gt *wopcm_to_gt(struct intel_wopcm *wopcm)
{
- return container_of(wopcm, struct drm_i915_private, wopcm);
+ return container_of(wopcm, struct intel_gt, wopcm);
}
/**
@@ -77,7 +77,8 @@ static inline struct drm_i915_private *wopcm_to_i915(struct intel_wopcm *wopcm)
*/
void intel_wopcm_init_early(struct intel_wopcm *wopcm)
{
- struct drm_i915_private *i915 = wopcm_to_i915(wopcm);
+ struct intel_gt *gt = wopcm_to_gt(wopcm);
+ struct drm_i915_private *i915 = gt->i915;
if (!HAS_GT_UC(i915))
return;
@@ -157,10 +158,11 @@ static bool check_hw_restrictions(struct drm_i915_private *i915,
return true;
}
-static bool __check_layout(struct drm_i915_private *i915, u32 wopcm_size,
+static bool __check_layout(struct intel_gt *gt, u32 wopcm_size,
u32 guc_wopcm_base, u32 guc_wopcm_size,
u32 guc_fw_size, u32 huc_fw_size)
{
+ struct drm_i915_private *i915 = gt->i915;
const u32 ctx_rsvd = context_reserved_size(i915);
u32 size;
@@ -181,12 +183,14 @@ static bool __check_layout(struct drm_i915_private *i915, u32 wopcm_size,
return false;
}
- size = huc_fw_size + WOPCM_RESERVED_SIZE;
- if (unlikely(guc_wopcm_base < size)) {
- drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n",
- intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC),
- guc_wopcm_base / SZ_1K, size / SZ_1K);
- return false;
+ if (intel_uc_supports_huc(&gt->uc)) {
+ size = huc_fw_size + WOPCM_RESERVED_SIZE;
+ if (unlikely(guc_wopcm_base < size)) {
+ drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n",
+ intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC),
+ guc_wopcm_base / SZ_1K, size / SZ_1K);
+ return false;
+ }
}
return check_hw_restrictions(i915, guc_wopcm_base, guc_wopcm_size,
@@ -228,8 +232,8 @@ static bool __wopcm_regs_writable(struct intel_uncore *uncore)
*/
void intel_wopcm_init(struct intel_wopcm *wopcm)
{
- struct drm_i915_private *i915 = wopcm_to_i915(wopcm);
- struct intel_gt *gt = to_gt(i915);
+ struct intel_gt *gt = wopcm_to_gt(wopcm);
+ struct drm_i915_private *i915 = gt->i915;
u32 guc_fw_size = intel_uc_fw_get_upload_size(&gt->uc.guc.fw);
u32 huc_fw_size = intel_uc_fw_get_upload_size(&gt->uc.huc.fw);
u32 ctx_rsvd = context_reserved_size(i915);
@@ -275,6 +279,19 @@ void intel_wopcm_init(struct intel_wopcm *wopcm)
}
/*
+ * On platforms with a media GT, the WOPCM is partitioned between the
+ * two GTs, so we would have to take that into account when doing the
+ * math below. There is also a new section reserved for the GSC context
+ * that would have to be factored in. However, all platforms with a
+ * media GT also have GuC depriv enabled, so the WOPCM regs are
+ * pre-locked and therefore we don't have to do the math ourselves.
+ */
+ if (unlikely(i915->media_gt)) {
+ drm_err(&i915->drm, "Unlocked WOPCM regs with media GT\n");
+ return;
+ }
+
+ /*
* Aligned value of guc_wopcm_base will determine available WOPCM space
* for HuC firmware and mandatory reserved area.
*/
@@ -295,7 +312,7 @@ void intel_wopcm_init(struct intel_wopcm *wopcm)
guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K);
check:
- if (__check_layout(i915, wopcm_size, guc_wopcm_base, guc_wopcm_size,
+ if (__check_layout(gt, wopcm_size, guc_wopcm_base, guc_wopcm_size,
guc_fw_size, huc_fw_size)) {
wopcm->guc.base = guc_wopcm_base;
wopcm->guc.size = guc_wopcm_size;
diff --git a/drivers/gpu/drm/i915/intel_wopcm.h b/drivers/gpu/drm/i915/gt/intel_wopcm.h
index 17d6aa86008a..17d6aa86008a 100644
--- a/drivers/gpu/drm/i915/intel_wopcm.h
+++ b/drivers/gpu/drm/i915/gt/intel_wopcm.h
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
index a821e3d405db..2afb4f80a954 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
@@ -4,6 +4,7 @@
*/
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_context.h"
#include "intel_engine_pm.h"
#include "intel_engine_regs.h"
@@ -17,46 +18,68 @@
/**
* DOC: Hardware workarounds
*
- * This file is intended as a central place to implement most [1]_ of the
- * required workarounds for hardware to work as originally intended. They fall
- * in five basic categories depending on how/when they are applied:
+ * Hardware workarounds are register programming documented to be executed in
+ * the driver that fall outside of the normal programming sequences for a
+ * platform. There are some basic categories of workarounds, depending on
+ * how/when they are applied:
*
- * - Workarounds that touch registers that are saved/restored to/from the HW
- * context image. The list is emitted (via Load Register Immediate commands)
- * everytime a new context is created.
- * - GT workarounds. The list of these WAs is applied whenever these registers
- * revert to default values (on GPU reset, suspend/resume [2]_, etc..).
- * - Display workarounds. The list is applied during display clock-gating
- * initialization.
- * - Workarounds that whitelist a privileged register, so that UMDs can manage
- * them directly. This is just a special case of a MMMIO workaround (as we
- * write the list of these to/be-whitelisted registers to some special HW
- * registers).
- * - Workaround batchbuffers, that get executed automatically by the hardware
- * on every HW context restore.
+ * - Context workarounds: workarounds that touch registers that are
+ * saved/restored to/from the HW context image. The list is emitted (via Load
+ * Register Immediate commands) once when initializing the device and saved in
+ * the default context. That default context is then used on every context
+ * creation to have a "primed golden context", i.e. a context image that
+ * already contains the changes needed to all the registers.
*
- * .. [1] Please notice that there are other WAs that, due to their nature,
- * cannot be applied from a central place. Those are peppered around the rest
- * of the code, as needed.
+ * - Engine workarounds: the list of these WAs is applied whenever the specific
+ * engine is reset. It's also possible that a set of engine classes share a
+ * common power domain and they are reset together. This happens on some
+ * platforms with render and compute engines. In this case (at least) one of
+ * them need to keeep the workaround programming: the approach taken in the
+ * driver is to tie those workarounds to the first compute/render engine that
+ * is registered. When executing with GuC submission, engine resets are
+ * outside of kernel driver control, hence the list of registers involved in
+ * written once, on engine initialization, and then passed to GuC, that
+ * saves/restores their values before/after the reset takes place. See
+ * ``drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c`` for reference.
*
- * .. [2] Technically, some registers are powercontext saved & restored, so they
- * survive a suspend/resume. In practice, writing them again is not too
- * costly and simplifies things. We can revisit this in the future.
+ * - GT workarounds: the list of these WAs is applied whenever these registers
+ * revert to their default values: on GPU reset, suspend/resume [1]_, etc.
+ *
+ * - Register whitelist: some workarounds need to be implemented in userspace,
+ * but need to touch privileged registers. The whitelist in the kernel
+ * instructs the hardware to allow the access to happen. From the kernel side,
+ * this is just a special case of a MMIO workaround (as we write the list of
+ * these to/be-whitelisted registers to some special HW registers).
+ *
+ * - Workaround batchbuffers: buffers that get executed automatically by the
+ * hardware on every HW context restore. These buffers are created and
+ * programmed in the default context so the hardware always go through those
+ * programming sequences when switching contexts. The support for workaround
+ * batchbuffers is enabled these hardware mechanisms:
*
- * Layout
- * ~~~~~~
+ * #. INDIRECT_CTX: A batchbuffer and an offset are provided in the default
+ * context, pointing the hardware to jump to that location when that offset
+ * is reached in the context restore. Workaround batchbuffer in the driver
+ * currently uses this mechanism for all platforms.
*
- * Keep things in this file ordered by WA type, as per the above (context, GT,
- * display, register whitelist, batchbuffer). Then, inside each type, keep the
- * following order:
+ * #. BB_PER_CTX_PTR: A batchbuffer is provided in the default context,
+ * pointing the hardware to a buffer to continue executing after the
+ * engine registers are restored in a context restore sequence. This is
+ * currently not used in the driver.
*
- * - Infrastructure functions and macros
- * - WAs per platform in standard gen/chrono order
- * - Public functions to init or apply the given workaround type.
+ * - Other: There are WAs that, due to their nature, cannot be applied from a
+ * central place. Those are peppered around the rest of the code, as needed.
+ * Workarounds related to the display IP are the main example.
+ *
+ * .. [1] Technically, some registers are powercontext saved & restored, so they
+ * survive a suspend/resume. In practice, writing them again is not too
+ * costly and simplifies things, so it's the approach taken in the driver.
*/
-static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name)
+static void wa_init_start(struct i915_wa_list *wal, struct intel_gt *gt,
+ const char *name, const char *engine_name)
{
+ wal->gt = gt;
wal->name = name;
wal->engine_name = engine_name;
}
@@ -80,13 +103,14 @@ static void wa_init_finish(struct i915_wa_list *wal)
if (!wal->count)
return;
- DRM_DEBUG_DRIVER("Initialized %u %s workarounds on %s\n",
- wal->wa_count, wal->name, wal->engine_name);
+ drm_dbg(&wal->gt->i915->drm, "Initialized %u %s workarounds on %s\n",
+ wal->wa_count, wal->name, wal->engine_name);
}
static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa)
{
unsigned int addr = i915_mmio_reg_offset(wa->reg);
+ struct drm_i915_private *i915 = wal->gt->i915;
unsigned int start = 0, end = wal->count;
const unsigned int grow = WA_LIST_CHUNK;
struct i915_wa *wa_;
@@ -99,7 +123,7 @@ static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa)
list = kmalloc_array(ALIGN(wal->count + 1, grow), sizeof(*wa),
GFP_KERNEL);
if (!list) {
- DRM_ERROR("No space for workaround init!\n");
+ drm_err(&i915->drm, "No space for workaround init!\n");
return;
}
@@ -122,9 +146,10 @@ static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa)
wa_ = &wal->list[mid];
if ((wa->clr | wa_->clr) && !(wa->clr & ~wa_->clr)) {
- DRM_ERROR("Discarding overwritten w/a for reg %04x (clear: %08x, set: %08x)\n",
- i915_mmio_reg_offset(wa_->reg),
- wa_->clr, wa_->set);
+ drm_err(&i915->drm,
+ "Discarding overwritten w/a for reg %04x (clear: %08x, set: %08x)\n",
+ i915_mmio_reg_offset(wa_->reg),
+ wa_->clr, wa_->set);
wa_->set &= ~wa->clr;
}
@@ -166,6 +191,21 @@ static void wa_add(struct i915_wa_list *wal, i915_reg_t reg,
_wa_add(wal, &wa);
}
+static void wa_mcr_add(struct i915_wa_list *wal, i915_mcr_reg_t reg,
+ u32 clear, u32 set, u32 read_mask, bool masked_reg)
+{
+ struct i915_wa wa = {
+ .mcr_reg = reg,
+ .clr = clear,
+ .set = set,
+ .read = read_mask,
+ .masked_reg = masked_reg,
+ .is_mcr = 1,
+ };
+
+ _wa_add(wal, &wa);
+}
+
static void
wa_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set)
{
@@ -173,6 +213,12 @@ wa_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set)
}
static void
+wa_mcr_write_clr_set(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 clear, u32 set)
+{
+ wa_mcr_add(wal, reg, clear, set, clear, false);
+}
+
+static void
wa_write(struct i915_wa_list *wal, i915_reg_t reg, u32 set)
{
wa_write_clr_set(wal, reg, ~0, set);
@@ -185,11 +231,23 @@ wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set)
}
static void
+wa_mcr_write_or(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 set)
+{
+ wa_mcr_write_clr_set(wal, reg, set, set);
+}
+
+static void
wa_write_clr(struct i915_wa_list *wal, i915_reg_t reg, u32 clr)
{
wa_write_clr_set(wal, reg, clr, 0);
}
+static void
+wa_mcr_write_clr(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 clr)
+{
+ wa_mcr_write_clr_set(wal, reg, clr, 0);
+}
+
/*
* WA operations on "masked register". A masked register has the upper 16 bits
* documented as "masked" in b-spec. Its purpose is to allow writing to just a
@@ -208,18 +266,37 @@ wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
}
static void
+wa_mcr_masked_en(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 val)
+{
+ wa_mcr_add(wal, reg, 0, _MASKED_BIT_ENABLE(val), val, true);
+}
+
+static void
wa_masked_dis(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
{
wa_add(wal, reg, 0, _MASKED_BIT_DISABLE(val), val, true);
}
static void
+wa_mcr_masked_dis(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 val)
+{
+ wa_mcr_add(wal, reg, 0, _MASKED_BIT_DISABLE(val), val, true);
+}
+
+static void
wa_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg,
u32 mask, u32 val)
{
wa_add(wal, reg, 0, _MASKED_FIELD(mask, val), mask, true);
}
+static void
+wa_mcr_masked_field_set(struct i915_wa_list *wal, i915_mcr_reg_t reg,
+ u32 mask, u32 val)
+{
+ wa_mcr_add(wal, reg, 0, _MASKED_FIELD(mask, val), mask, true);
+}
+
static void gen6_ctx_workarounds_init(struct intel_engine_cs *engine,
struct i915_wa_list *wal)
{
@@ -241,8 +318,8 @@ static void gen8_ctx_workarounds_init(struct intel_engine_cs *engine,
wa_masked_en(wal, RING_MI_MODE(RENDER_RING_BASE), ASYNC_FLIP_PERF_DISABLE);
/* WaDisablePartialInstShootdown:bdw,chv */
- wa_masked_en(wal, GEN8_ROW_CHICKEN,
- PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN,
+ PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
/* Use Force Non-Coherent whenever executing a 3D context. This is a
* workaround for a possible hang in the unlikely event a TLB
@@ -288,18 +365,18 @@ static void bdw_ctx_workarounds_init(struct intel_engine_cs *engine,
gen8_ctx_workarounds_init(engine, wal);
/* WaDisableThreadStallDopClockGating:bdw (pre-production) */
- wa_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
/* WaDisableDopClockGating:bdw
*
* Also see the related UCGTCL1 write in bdw_init_clock_gating()
* to disable EUTC clock gating.
*/
- wa_masked_en(wal, GEN7_ROW_CHICKEN2,
- DOP_CLOCK_GATING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2,
+ DOP_CLOCK_GATING_DISABLE);
- wa_masked_en(wal, HALF_SLICE_CHICKEN3,
- GEN8_SAMPLER_POWER_BYPASS_DIS);
+ wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3,
+ GEN8_SAMPLER_POWER_BYPASS_DIS);
wa_masked_en(wal, HDC_CHICKEN0,
/* WaForceContextSaveRestoreNonCoherent:bdw */
@@ -314,7 +391,7 @@ static void chv_ctx_workarounds_init(struct intel_engine_cs *engine,
gen8_ctx_workarounds_init(engine, wal);
/* WaDisableThreadStallDopClockGating:chv */
- wa_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
/* Improve HiZ throughput on CHV. */
wa_masked_en(wal, HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
@@ -333,21 +410,21 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine,
*/
wa_masked_en(wal, COMMON_SLICE_CHICKEN2,
GEN9_PBE_COMPRESSED_HASH_SELECTION);
- wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
- GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR);
+ wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
+ GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR);
}
/* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */
/* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */
- wa_masked_en(wal, GEN8_ROW_CHICKEN,
- FLOW_CONTROL_ENABLE |
- PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN,
+ FLOW_CONTROL_ENABLE |
+ PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */
/* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */
- wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
- GEN9_ENABLE_YV12_BUGFIX |
- GEN9_ENABLE_GPGPU_PREEMPTION);
+ wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
+ GEN9_ENABLE_YV12_BUGFIX |
+ GEN9_ENABLE_GPGPU_PREEMPTION);
/* Wa4x4STCOptimizationDisable:skl,bxt,kbl,glk,cfl */
/* WaDisablePartialResolveInVc:skl,bxt,kbl,cfl */
@@ -356,8 +433,8 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine,
GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE);
/* WaCcsTlbPrefetchDisable:skl,bxt,kbl,glk,cfl */
- wa_masked_dis(wal, GEN9_HALF_SLICE_CHICKEN5,
- GEN9_CCS_TLB_PREFETCH_ENABLE);
+ wa_mcr_masked_dis(wal, GEN9_HALF_SLICE_CHICKEN5,
+ GEN9_CCS_TLB_PREFETCH_ENABLE);
/* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl,cfl */
wa_masked_en(wal, HDC_CHICKEN0,
@@ -386,11 +463,11 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine,
IS_KABYLAKE(i915) ||
IS_COFFEELAKE(i915) ||
IS_COMETLAKE(i915))
- wa_masked_en(wal, HALF_SLICE_CHICKEN3,
- GEN8_SAMPLER_POWER_BYPASS_DIS);
+ wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3,
+ GEN8_SAMPLER_POWER_BYPASS_DIS);
/* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */
- wa_masked_en(wal, HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
+ wa_mcr_masked_en(wal, HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
/*
* Supporting preemption with fine-granularity requires changes in the
@@ -469,8 +546,8 @@ static void bxt_ctx_workarounds_init(struct intel_engine_cs *engine,
gen9_ctx_workarounds_init(engine, wal);
/* WaDisableThreadStallDopClockGating:bxt */
- wa_masked_en(wal, GEN8_ROW_CHICKEN,
- STALL_DOP_GATING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN,
+ STALL_DOP_GATING_DISABLE);
/* WaToEnableHwFixForPushConstHWBug:bxt */
wa_masked_en(wal, COMMON_SLICE_CHICKEN2,
@@ -490,8 +567,8 @@ static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine,
GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
/* WaDisableSbeCacheDispatchPortSharing:kbl */
- wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1,
- GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1,
+ GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
}
static void glk_ctx_workarounds_init(struct intel_engine_cs *engine,
@@ -514,8 +591,8 @@ static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine,
GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
/* WaDisableSbeCacheDispatchPortSharing:cfl */
- wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1,
- GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
+ wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1,
+ GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
}
static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
@@ -534,13 +611,13 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
* (the register is whitelisted in hardware now, so UMDs can opt in
* for coherency if they have a good reason).
*/
- wa_masked_en(wal, ICL_HDC_MODE, HDC_FORCE_NON_COHERENT);
+ wa_mcr_masked_en(wal, ICL_HDC_MODE, HDC_FORCE_NON_COHERENT);
/* WaEnableFloatBlendOptimization:icl */
- wa_add(wal, GEN10_CACHE_MODE_SS, 0,
- _MASKED_BIT_ENABLE(FLOAT_BLEND_OPTIMIZATION_ENABLE),
- 0 /* write-only, so skip validation */,
- true);
+ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
+ _MASKED_BIT_ENABLE(FLOAT_BLEND_OPTIMIZATION_ENABLE),
+ 0 /* write-only, so skip validation */,
+ true);
/* WaDisableGPGPUMidThreadPreemption:icl */
wa_masked_field_set(wal, GEN8_CS_CHICKEN1,
@@ -548,8 +625,8 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL);
/* allow headerless messages for preemptible GPGPU context */
- wa_masked_en(wal, GEN10_SAMPLER_MODE,
- GEN11_SAMPLER_ENABLE_HEADLESS_MSG);
+ wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE,
+ GEN11_SAMPLER_ENABLE_HEADLESS_MSG);
/* Wa_1604278689:icl,ehl */
wa_write(wal, IVB_FBC_RT_BASE, 0xFFFFFFFF & ~ILK_FBC_RT_VALID);
@@ -558,7 +635,7 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
0xFFFFFFFF);
/* Wa_1406306137:icl,ehl */
- wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU);
+ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU);
}
/*
@@ -569,13 +646,13 @@ static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine,
struct i915_wa_list *wal)
{
wa_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP);
- wa_write_clr_set(wal, GEN11_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK,
- REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f));
- wa_add(wal,
- FF_MODE2,
- FF_MODE2_TDS_TIMER_MASK,
- FF_MODE2_TDS_TIMER_128,
- 0, false);
+ wa_mcr_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK,
+ REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f));
+ wa_mcr_add(wal,
+ XEHP_FF_MODE2,
+ FF_MODE2_TDS_TIMER_MASK,
+ FF_MODE2_TDS_TIMER_128,
+ 0, false);
}
/*
@@ -599,7 +676,7 @@ static void gen12_ctx_gt_tuning_init(struct intel_engine_cs *engine,
* verification is ignored.
*/
wa_add(wal,
- FF_MODE2,
+ GEN12_FF_MODE2,
FF_MODE2_TDS_TIMER_MASK,
FF_MODE2_TDS_TIMER_128,
0, false);
@@ -608,6 +685,8 @@ static void gen12_ctx_gt_tuning_init(struct intel_engine_cs *engine,
static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
struct i915_wa_list *wal)
{
+ struct drm_i915_private *i915 = engine->i915;
+
gen12_ctx_gt_tuning_init(engine, wal);
/*
@@ -637,10 +716,14 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
* to Wa_1608008084.
*/
wa_add(wal,
- FF_MODE2,
+ GEN12_FF_MODE2,
FF_MODE2_GS_TIMER_MASK,
FF_MODE2_GS_TIMER_224,
0, false);
+
+ if (!IS_DG1(i915))
+ /* Wa_1806527549 */
+ wa_masked_en(wal, HIZ_CHICKEN, HZ_DEPTH_TEST_LE_GE_OPT_DISABLE);
}
static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine,
@@ -664,27 +747,27 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine,
/* Wa_16011186671:dg2_g11 */
if (IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) {
- wa_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH);
- wa_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE);
+ wa_mcr_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH);
+ wa_mcr_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE);
}
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) {
/* Wa_14010469329:dg2_g10 */
- wa_masked_en(wal, GEN11_COMMON_SLICE_CHICKEN3,
- XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE);
+ wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3,
+ XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE);
/*
* Wa_22010465075:dg2_g10
* Wa_22010613112:dg2_g10
* Wa_14010698770:dg2_g10
*/
- wa_masked_en(wal, GEN11_COMMON_SLICE_CHICKEN3,
- GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
+ wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3,
+ GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
}
/* Wa_16013271637:dg2 */
- wa_masked_en(wal, SLICE_COMMON_ECO_CHICKEN1,
- MSC_MSAA_REODER_BUF_BYPASS_DISABLE);
+ wa_mcr_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1,
+ MSC_MSAA_REODER_BUF_BYPASS_DISABLE);
/* Wa_14014947963:dg2 */
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) ||
@@ -768,7 +851,7 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
{
struct drm_i915_private *i915 = engine->i915;
- wa_init_start(wal, name, engine->name);
+ wa_init_start(wal, engine->gt, name, engine->name);
/* Applies to all engines */
/*
@@ -1076,18 +1159,23 @@ static void __set_mcr_steering(struct i915_wa_list *wal,
wa_write_clr_set(wal, steering_reg, mcr_mask, mcr);
}
-static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal,
- unsigned int slice, unsigned int subslice)
+static void debug_dump_steering(struct intel_gt *gt)
{
struct drm_printer p = drm_debug_printer("MCR Steering:");
+ if (drm_debug_enabled(DRM_UT_DRIVER))
+ intel_gt_mcr_report_steering(&p, gt, false);
+}
+
+static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal,
+ unsigned int slice, unsigned int subslice)
+{
__set_mcr_steering(wal, GEN8_MCR_SELECTOR, slice, subslice);
gt->default_steering.groupid = slice;
gt->default_steering.instanceid = subslice;
- if (drm_debug_enabled(DRM_UT_DRIVER))
- intel_gt_mcr_report_steering(&p, gt, false);
+ debug_dump_steering(gt);
}
static void
@@ -1181,6 +1269,9 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal)
gt->steering_table[MSLICE] = NULL;
}
+ if (IS_XEHPSDV(gt->i915) && slice_mask & BIT(0))
+ gt->steering_table[GAM] = NULL;
+
slice = __ffs(slice_mask);
subslice = intel_sseu_find_first_xehp_dss(sseu, GEN_DSS_PER_GSLICE, slice) %
GEN_DSS_PER_GSLICE;
@@ -1198,6 +1289,13 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal)
*/
__set_mcr_steering(wal, MCFG_MCR_SELECTOR, 0, 2);
__set_mcr_steering(wal, SF_MCR_SELECTOR, 0, 2);
+
+ /*
+ * On DG2, GAM registers have a dedicated steering control register
+ * and must always be programmed to a hardcoded groupid of "1."
+ */
+ if (IS_DG2(gt->i915))
+ __set_mcr_steering(wal, GAM_MCR_SELECTOR, 1, 0);
}
static void
@@ -1254,22 +1352,22 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
PSDUNIT_CLKGATE_DIS);
/* Wa_1406680159:icl,ehl */
- wa_write_or(wal,
- SUBSLICE_UNIT_LEVEL_CLKGATE,
- GWUNIT_CLKGATE_DIS);
+ wa_mcr_write_or(wal,
+ GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE,
+ GWUNIT_CLKGATE_DIS);
/* Wa_1607087056:icl,ehl,jsl */
if (IS_ICELAKE(i915) ||
IS_JSL_EHL_GRAPHICS_STEP(i915, STEP_A0, STEP_B0))
wa_write_or(wal,
- SLICE_UNIT_LEVEL_CLKGATE,
+ GEN11_SLICE_UNIT_LEVEL_CLKGATE,
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
/*
* This is not a documented workaround, but rather an optimization
* to reduce sampler power.
*/
- wa_write_clr(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE);
+ wa_mcr_write_clr(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE);
}
/*
@@ -1303,7 +1401,7 @@ gen12_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
wa_14011060649(gt, wal);
/* Wa_14011059788:tgl,rkl,adl-s,dg1,adl-p */
- wa_write_or(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE);
+ wa_mcr_write_or(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE);
}
static void
@@ -1315,14 +1413,14 @@ tgl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
/* Wa_1409420604:tgl */
if (IS_TGL_UY_GRAPHICS_STEP(i915, STEP_A0, STEP_B0))
- wa_write_or(wal,
- SUBSLICE_UNIT_LEVEL_CLKGATE2,
- CPSSUNIT_CLKGATE_DIS);
+ wa_mcr_write_or(wal,
+ SUBSLICE_UNIT_LEVEL_CLKGATE2,
+ CPSSUNIT_CLKGATE_DIS);
/* Wa_1607087056:tgl also know as BUG:1409180338 */
if (IS_TGL_UY_GRAPHICS_STEP(i915, STEP_A0, STEP_B0))
wa_write_or(wal,
- SLICE_UNIT_LEVEL_CLKGATE,
+ GEN11_SLICE_UNIT_LEVEL_CLKGATE,
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
/* Wa_1408615072:tgl[a0] */
@@ -1341,14 +1439,14 @@ dg1_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
/* Wa_1607087056:dg1 */
if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0))
wa_write_or(wal,
- SLICE_UNIT_LEVEL_CLKGATE,
+ GEN11_SLICE_UNIT_LEVEL_CLKGATE,
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
/* Wa_1409420604:dg1 */
if (IS_DG1(i915))
- wa_write_or(wal,
- SUBSLICE_UNIT_LEVEL_CLKGATE2,
- CPSSUNIT_CLKGATE_DIS);
+ wa_mcr_write_or(wal,
+ SUBSLICE_UNIT_LEVEL_CLKGATE2,
+ CPSSUNIT_CLKGATE_DIS);
/* Wa_1408615072:dg1 */
/* Empirical testing shows this register is unaffected by engine reset. */
@@ -1365,7 +1463,7 @@ xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
xehp_init_mcr(gt, wal);
/* Wa_1409757795:xehpsdv */
- wa_write_or(wal, SCCGCTL94DC, CG3DDISURB);
+ wa_mcr_write_or(wal, SCCGCTL94DC, CG3DDISURB);
/* Wa_16011155590:xehpsdv */
if (IS_XEHPSDV_GRAPHICS_STEP(i915, STEP_A0, STEP_B0))
@@ -1445,8 +1543,8 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
CG3DDISCFEG_CLKGATE_DIS);
/* Wa_14011006942:dg2 */
- wa_write_or(wal, SUBSLICE_UNIT_LEVEL_CLKGATE,
- DSS_ROUTER_CLKGATE_DIS);
+ wa_mcr_write_or(wal, GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE,
+ DSS_ROUTER_CLKGATE_DIS);
}
if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) {
@@ -1457,7 +1555,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
wa_write_or(wal, UNSLCGCTL9444, LTCDD_CLKGATE_DIS);
/* Wa_14011371254:dg2_g10 */
- wa_write_or(wal, SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS);
+ wa_mcr_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS);
/* Wa_14011431319:dg2_g10 */
wa_write_or(wal, UNSLCGCTL9440, GAMTLBOACS_CLKGATE_DIS |
@@ -1493,21 +1591,21 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
GAMEDIA_CLKGATE_DIS);
/* Wa_14011028019:dg2_g10 */
- wa_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS);
+ wa_mcr_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS);
}
/* Wa_14014830051:dg2 */
- wa_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN);
+ wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN);
/*
* The following are not actually "workarounds" but rather
* recommended tuning settings documented in the bspec's
* performance guide section.
*/
- wa_write_or(wal, GEN12_SQCM, EN_32B_ACCESS);
+ wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS);
/* Wa_14015795083 */
- wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+ wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
}
static void
@@ -1516,7 +1614,27 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
pvc_init_mcr(gt, wal);
/* Wa_14015795083 */
- wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+ wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+}
+
+static void
+xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
+{
+ /* FIXME: Actual workarounds will be added in future patch(es) */
+
+ /*
+ * Unlike older platforms, we no longer setup implicit steering here;
+ * all MCR accesses are explicitly steered.
+ */
+ debug_dump_steering(gt);
+}
+
+static void
+xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
+{
+ /* FIXME: Actual workarounds will be added in future patch(es) */
+
+ debug_dump_steering(gt);
}
static void
@@ -1524,7 +1642,18 @@ gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal)
{
struct drm_i915_private *i915 = gt->i915;
- if (IS_PONTEVECCHIO(i915))
+ if (gt->type == GT_MEDIA) {
+ if (MEDIA_VER(i915) >= 13)
+ xelpmp_gt_workarounds_init(gt, wal);
+ else
+ MISSING_CASE(MEDIA_VER(i915));
+
+ return;
+ }
+
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
+ xelpg_gt_workarounds_init(gt, wal);
+ else if (IS_PONTEVECCHIO(i915))
pvc_gt_workarounds_init(gt, wal);
else if (IS_DG2(i915))
dg2_gt_workarounds_init(gt, wal);
@@ -1572,7 +1701,7 @@ void intel_gt_init_workarounds(struct intel_gt *gt)
{
struct i915_wa_list *wal = &gt->wa_list;
- wa_init_start(wal, "GT", "global");
+ wa_init_start(wal, gt, "GT", "global");
gt_init_workarounds(gt, wal);
wa_init_finish(wal);
}
@@ -1594,12 +1723,14 @@ wal_get_fw_for_rmw(struct intel_uncore *uncore, const struct i915_wa_list *wal)
}
static bool
-wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from)
+wa_verify(struct intel_gt *gt, const struct i915_wa *wa, u32 cur,
+ const char *name, const char *from)
{
if ((cur ^ wa->set) & wa->read) {
- DRM_ERROR("%s workaround lost on %s! (reg[%x]=0x%x, relevant bits were 0x%x vs expected 0x%x)\n",
- name, from, i915_mmio_reg_offset(wa->reg),
- cur, cur & wa->read, wa->set & wa->read);
+ drm_err(&gt->i915->drm,
+ "%s workaround lost on %s! (reg[%x]=0x%x, relevant bits were 0x%x vs expected 0x%x)\n",
+ name, from, i915_mmio_reg_offset(wa->reg),
+ cur, cur & wa->read, wa->set & wa->read);
return false;
}
@@ -1607,9 +1738,9 @@ wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from)
return true;
}
-static void
-wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal)
+static void wa_list_apply(const struct i915_wa_list *wal)
{
+ struct intel_gt *gt = wal->gt;
struct intel_uncore *uncore = gt->uncore;
enum forcewake_domains fw;
unsigned long flags;
@@ -1628,14 +1759,25 @@ wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal)
u32 val, old = 0;
/* open-coded rmw due to steering */
- old = wa->clr ? intel_gt_mcr_read_any_fw(gt, wa->reg) : 0;
+ if (wa->clr)
+ old = wa->is_mcr ?
+ intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) :
+ intel_uncore_read_fw(uncore, wa->reg);
val = (old & ~wa->clr) | wa->set;
- if (val != old || !wa->clr)
- intel_uncore_write_fw(uncore, wa->reg, val);
+ if (val != old || !wa->clr) {
+ if (wa->is_mcr)
+ intel_gt_mcr_multicast_write_fw(gt, wa->mcr_reg, val);
+ else
+ intel_uncore_write_fw(uncore, wa->reg, val);
+ }
+
+ if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
+ u32 val = wa->is_mcr ?
+ intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) :
+ intel_uncore_read_fw(uncore, wa->reg);
- if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
- wa_verify(wa, intel_gt_mcr_read_any_fw(gt, wa->reg),
- wal->name, "application");
+ wa_verify(gt, wa, val, wal->name, "application");
+ }
}
intel_uncore_forcewake_put__locked(uncore, fw);
@@ -1644,7 +1786,7 @@ wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal)
void intel_gt_apply_workarounds(struct intel_gt *gt)
{
- wa_list_apply(gt, &gt->wa_list);
+ wa_list_apply(&gt->wa_list);
}
static bool wa_list_verify(struct intel_gt *gt,
@@ -1664,8 +1806,9 @@ static bool wa_list_verify(struct intel_gt *gt,
intel_uncore_forcewake_get__locked(uncore, fw);
for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
- ok &= wa_verify(wa,
- intel_gt_mcr_read_any_fw(gt, wa->reg),
+ ok &= wa_verify(wal->gt, wa, wa->is_mcr ?
+ intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) :
+ intel_uncore_read_fw(uncore, wa->reg),
wal->name, from);
intel_uncore_forcewake_put__locked(uncore, fw);
@@ -1712,11 +1855,35 @@ whitelist_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags)
}
static void
+whitelist_mcr_reg_ext(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 flags)
+{
+ struct i915_wa wa = {
+ .mcr_reg = reg,
+ .is_mcr = 1,
+ };
+
+ if (GEM_DEBUG_WARN_ON(wal->count >= RING_MAX_NONPRIV_SLOTS))
+ return;
+
+ if (GEM_DEBUG_WARN_ON(!is_nonpriv_flags_valid(flags)))
+ return;
+
+ wa.mcr_reg.reg |= flags;
+ _wa_add(wal, &wa);
+}
+
+static void
whitelist_reg(struct i915_wa_list *wal, i915_reg_t reg)
{
whitelist_reg_ext(wal, reg, RING_FORCE_TO_NONPRIV_ACCESS_RW);
}
+static void
+whitelist_mcr_reg(struct i915_wa_list *wal, i915_mcr_reg_t reg)
+{
+ whitelist_mcr_reg_ext(wal, reg, RING_FORCE_TO_NONPRIV_ACCESS_RW);
+}
+
static void gen9_whitelist_build(struct i915_wa_list *w)
{
/* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */
@@ -1742,7 +1909,7 @@ static void skl_whitelist_build(struct intel_engine_cs *engine)
gen9_whitelist_build(w);
/* WaDisableLSQCROPERFforOCL:skl */
- whitelist_reg(w, GEN8_L3SQCREG4);
+ whitelist_mcr_reg(w, GEN8_L3SQCREG4);
}
static void bxt_whitelist_build(struct intel_engine_cs *engine)
@@ -1763,7 +1930,7 @@ static void kbl_whitelist_build(struct intel_engine_cs *engine)
gen9_whitelist_build(w);
/* WaDisableLSQCROPERFforOCL:kbl */
- whitelist_reg(w, GEN8_L3SQCREG4);
+ whitelist_mcr_reg(w, GEN8_L3SQCREG4);
}
static void glk_whitelist_build(struct intel_engine_cs *engine)
@@ -1828,10 +1995,10 @@ static void icl_whitelist_build(struct intel_engine_cs *engine)
switch (engine->class) {
case RENDER_CLASS:
/* WaAllowUMDToModifyHalfSliceChicken7:icl */
- whitelist_reg(w, GEN9_HALF_SLICE_CHICKEN7);
+ whitelist_mcr_reg(w, GEN9_HALF_SLICE_CHICKEN7);
/* WaAllowUMDToModifySamplerMode:icl */
- whitelist_reg(w, GEN10_SAMPLER_MODE);
+ whitelist_mcr_reg(w, GEN10_SAMPLER_MODE);
/* WaEnableStateCacheRedirectToCS:icl */
whitelist_reg(w, GEN9_SLICE_COMMON_ECO_CHICKEN1);
@@ -1987,7 +2154,7 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine)
struct drm_i915_private *i915 = engine->i915;
struct i915_wa_list *w = &engine->whitelist;
- wa_init_start(w, "whitelist", engine->name);
+ wa_init_start(w, engine->gt, "whitelist", engine->name);
if (IS_PONTEVECCHIO(i915))
pvc_whitelist_build(engine);
@@ -2107,24 +2274,21 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) {
/* Wa_14013392000:dg2_g11 */
- wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE);
-
- /* Wa_16011620976:dg2_g11 */
- wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
IS_DG2_G11(i915) || IS_DG2_G12(i915)) {
/* Wa_1509727124:dg2 */
- wa_masked_en(wal, GEN10_SAMPLER_MODE,
- SC_DISABLE_POWER_OPTIMIZATION_EBB);
+ wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE,
+ SC_DISABLE_POWER_OPTIMIZATION_EBB);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0) ||
IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) {
/* Wa_14012419201:dg2 */
- wa_masked_en(wal, GEN9_ROW_CHICKEN4,
- GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX);
+ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4,
+ GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) ||
@@ -2133,13 +2297,13 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
* Wa_22012826095:dg2
* Wa_22013059131:dg2
*/
- wa_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW,
- MAXREQS_PER_BANK,
- REG_FIELD_PREP(MAXREQS_PER_BANK, 2));
+ wa_mcr_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW,
+ MAXREQS_PER_BANK,
+ REG_FIELD_PREP(MAXREQS_PER_BANK, 2));
/* Wa_22013059131:dg2 */
- wa_write_or(wal, LSC_CHICKEN_BIT_0,
- FORCE_1_SUB_MESSAGE_PER_FRAGMENT);
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0,
+ FORCE_1_SUB_MESSAGE_PER_FRAGMENT);
}
/* Wa_1308578152:dg2_g10 when first gslice is fused off */
@@ -2152,19 +2316,19 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
IS_DG2_G11(i915) || IS_DG2_G12(i915)) {
/* Wa_22013037850:dg2 */
- wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW,
- DISABLE_128B_EVICTION_COMMAND_UDW);
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW,
+ DISABLE_128B_EVICTION_COMMAND_UDW);
/* Wa_22012856258:dg2 */
- wa_masked_en(wal, GEN7_ROW_CHICKEN2,
- GEN12_DISABLE_READ_SUPPRESSION);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2,
+ GEN12_DISABLE_READ_SUPPRESSION);
/*
* Wa_22010960976:dg2
* Wa_14013347512:dg2
*/
- wa_masked_dis(wal, GEN12_HDC_CHICKEN0,
- LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK);
+ wa_mcr_masked_dis(wal, XEHP_HDC_CHICKEN0,
+ LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) {
@@ -2172,8 +2336,8 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
* Wa_1608949956:dg2_g10
* Wa_14010198302:dg2_g10
*/
- wa_masked_en(wal, GEN8_ROW_CHICKEN,
- MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN,
+ MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE);
/*
* Wa_14010918519:dg2_g10
@@ -2181,31 +2345,31 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
* LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping,
* so ignoring verification.
*/
- wa_add(wal, LSC_CHICKEN_BIT_0_UDW, 0,
- FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE,
- 0, false);
+ wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0,
+ FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE,
+ 0, false);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) {
/* Wa_22010430635:dg2 */
- wa_masked_en(wal,
- GEN9_ROW_CHICKEN4,
- GEN12_DISABLE_GRF_CLEAR);
+ wa_mcr_masked_en(wal,
+ GEN9_ROW_CHICKEN4,
+ GEN12_DISABLE_GRF_CLEAR);
/* Wa_14010648519:dg2 */
- wa_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE);
+ wa_mcr_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE);
}
/* Wa_14013202645:dg2 */
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) ||
IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0))
- wa_write_or(wal, RT_CTRL, DIS_NULL_QUERY);
+ wa_mcr_write_or(wal, RT_CTRL, DIS_NULL_QUERY);
/* Wa_22012532006:dg2 */
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_C0) ||
IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0))
- wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
- DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA);
+ wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
+ DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA);
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) {
/* Wa_14010680813:dg2_g10 */
@@ -2216,17 +2380,16 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0) ||
IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) {
/* Wa_14012362059:dg2 */
- wa_write_or(wal, GEN12_MERT_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
}
if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) ||
IS_DG2_G10(i915)) {
/* Wa_22014600077:dg2 */
- wa_add(wal, GEN10_CACHE_MODE_SS, 0,
- _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH),
- 0 /* Wa_14012342262 :write-only reg, so skip
- verification */,
- true);
+ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
+ _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH),
+ 0 /* Wa_14012342262 write-only reg, so skip verification */,
+ true);
}
if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) ||
@@ -2253,7 +2416,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) ||
IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
/* Wa_1606931601:tgl,rkl,dg1,adl-s,adl-p */
- wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ);
/*
* Wa_1407928979:tgl A*
@@ -2282,14 +2445,14 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) ||
IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
/* Wa_1409804808:tgl,rkl,dg1[a0],adl-s,adl-p */
- wa_masked_en(wal, GEN7_ROW_CHICKEN2,
- GEN12_PUSH_CONST_DEREF_HOLD_DIS);
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2,
+ GEN12_PUSH_CONST_DEREF_HOLD_DIS);
/*
* Wa_1409085225:tgl
* Wa_14010229206:tgl,rkl,dg1[a0],adl-s,adl-p
*/
- wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH);
+ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH);
}
if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) ||
@@ -2313,9 +2476,9 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) ||
IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
/* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */
- wa_masked_en(wal,
- GEN10_SAMPLER_MODE,
- ENABLE_SMALLPL);
+ wa_mcr_masked_en(wal,
+ GEN10_SAMPLER_MODE,
+ ENABLE_SMALLPL);
}
if (GRAPHICS_VER(i915) == 11) {
@@ -2349,9 +2512,9 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
* Wa_1405733216:icl
* Formerly known as WaDisableCleanEvicts
*/
- wa_write_or(wal,
- GEN8_L3SQCREG4,
- GEN11_LQSC_CLEAN_EVICT_DISABLE);
+ wa_mcr_write_or(wal,
+ GEN8_L3SQCREG4,
+ GEN11_LQSC_CLEAN_EVICT_DISABLE);
/* Wa_1606682166:icl */
wa_write_or(wal,
@@ -2359,10 +2522,10 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
GEN7_DISABLE_SAMPLER_PREFETCH);
/* Wa_1409178092:icl */
- wa_write_clr_set(wal,
- GEN11_SCRATCH2,
- GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE,
- 0);
+ wa_mcr_write_clr_set(wal,
+ GEN11_SCRATCH2,
+ GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE,
+ 0);
/* WaEnable32PlaneMode:icl */
wa_masked_en(wal, GEN9_CSFE_CHICKEN1_RCS,
@@ -2389,12 +2552,64 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
FF_DOP_CLOCK_GATE_DISABLE);
}
- if (IS_GRAPHICS_VER(i915, 9, 12)) {
- /* FtrPerCtxtPreemptionGranularityControl:skl,bxt,kbl,cfl,cnl,icl,tgl */
+ /*
+ * Intel platforms that support fine-grained preemption (i.e., gen9 and
+ * beyond) allow the kernel-mode driver to choose between two different
+ * options for controlling preemption granularity and behavior.
+ *
+ * Option 1 (hardware default):
+ * Preemption settings are controlled in a global manner via
+ * kernel-only register CS_DEBUG_MODE1 (0x20EC). Any granularity
+ * and settings chosen by the kernel-mode driver will apply to all
+ * userspace clients.
+ *
+ * Option 2:
+ * Preemption settings are controlled on a per-context basis via
+ * register CS_CHICKEN1 (0x2580). CS_CHICKEN1 is saved/restored on
+ * context switch and is writable by userspace (e.g., via
+ * MI_LOAD_REGISTER_IMMEDIATE instructions placed in a batch buffer)
+ * which allows different userspace drivers/clients to select
+ * different settings, or to change those settings on the fly in
+ * response to runtime needs. This option was known by name
+ * "FtrPerCtxtPreemptionGranularityControl" at one time, although
+ * that name is somewhat misleading as other non-granularity
+ * preemption settings are also impacted by this decision.
+ *
+ * On Linux, our policy has always been to let userspace drivers
+ * control preemption granularity/settings (Option 2). This was
+ * originally mandatory on gen9 to prevent ABI breakage (old gen9
+ * userspace developed before object-level preemption was enabled would
+ * not behave well if i915 were to go with Option 1 and enable that
+ * preemption in a global manner). On gen9 each context would have
+ * object-level preemption disabled by default (see
+ * WaDisable3DMidCmdPreemption in gen9_ctx_workarounds_init), but
+ * userspace drivers could opt-in to object-level preemption as they
+ * saw fit. For post-gen9 platforms, we continue to utilize Option 2;
+ * even though it is no longer necessary for ABI compatibility when
+ * enabling a new platform, it does ensure that userspace will be able
+ * to implement any workarounds that show up requiring temporary
+ * adjustments to preemption behavior at runtime.
+ *
+ * Notes/Workarounds:
+ * - Wa_14015141709: On DG2 and early steppings of MTL,
+ * CS_CHICKEN1[0] does not disable object-level preemption as
+ * it is supposed to (nor does CS_DEBUG_MODE1[0] if we had been
+ * using Option 1). Effectively this means userspace is unable
+ * to disable object-level preemption on these platforms/steppings
+ * despite the setting here.
+ *
+ * - Wa_16013994831: May require that userspace program
+ * CS_CHICKEN1[10] when certain runtime conditions are true.
+ * Userspace requires Option 2 to be in effect for their update of
+ * CS_CHICKEN1[10] to be effective.
+ *
+ * Other workarounds may appear in the future that will also require
+ * Option 2 behavior to allow proper userspace implementation.
+ */
+ if (GRAPHICS_VER(i915) >= 9)
wa_masked_en(wal,
GEN7_FF_SLICE_CS_CHICKEN1,
GEN9_FFSC_PERCTX_PREEMPT_CTRL);
- }
if (IS_SKYLAKE(i915) ||
IS_KABYLAKE(i915) ||
@@ -2420,36 +2635,36 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE);
/* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */
- wa_write_or(wal,
- BDW_SCRATCH1,
- GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
+ wa_mcr_write_or(wal,
+ BDW_SCRATCH1,
+ GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
/* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */
if (IS_GEN9_LP(i915))
- wa_write_clr_set(wal,
- GEN8_L3SQCREG1,
- L3_PRIO_CREDITS_MASK,
- L3_GENERAL_PRIO_CREDITS(62) |
- L3_HIGH_PRIO_CREDITS(2));
+ wa_mcr_write_clr_set(wal,
+ GEN8_L3SQCREG1,
+ L3_PRIO_CREDITS_MASK,
+ L3_GENERAL_PRIO_CREDITS(62) |
+ L3_HIGH_PRIO_CREDITS(2));
/* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */
- wa_write_or(wal,
- GEN8_L3SQCREG4,
- GEN8_LQSC_FLUSH_COHERENT_LINES);
+ wa_mcr_write_or(wal,
+ GEN8_L3SQCREG4,
+ GEN8_LQSC_FLUSH_COHERENT_LINES);
/* Disable atomics in L3 to prevent unrecoverable hangs */
wa_write_clr_set(wal, GEN9_SCRATCH_LNCF1,
GEN9_LNCF_NONIA_COHERENT_ATOMICS_ENABLE, 0);
- wa_write_clr_set(wal, GEN8_L3SQCREG4,
- GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE, 0);
- wa_write_clr_set(wal, GEN9_SCRATCH1,
- EVICTION_PERF_FIX_ENABLE, 0);
+ wa_mcr_write_clr_set(wal, GEN8_L3SQCREG4,
+ GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE, 0);
+ wa_mcr_write_clr_set(wal, GEN9_SCRATCH1,
+ EVICTION_PERF_FIX_ENABLE, 0);
}
if (IS_HASWELL(i915)) {
/* WaSampleCChickenBitEnable:hsw */
wa_masked_en(wal,
- HALF_SLICE_CHICKEN3, HSW_SAMPLE_C_PERFORMANCE);
+ HSW_HALF_SLICE_CHICKEN3, HSW_SAMPLE_C_PERFORMANCE);
wa_masked_dis(wal,
CACHE_MODE_0_GEN7,
@@ -2657,7 +2872,7 @@ ccs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
{
if (IS_PVC_CT_STEP(engine->i915, STEP_A0, STEP_C0)) {
/* Wa_14014999345:pvc */
- wa_masked_en(wal, GEN10_CACHE_MODE_SS, DISABLE_ECC);
+ wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, DISABLE_ECC);
}
}
@@ -2683,8 +2898,8 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915,
}
if (IS_DG2(i915)) {
- wa_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS);
- wa_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512);
+ wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS);
+ wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512);
/*
* This is also listed as Wa_22012654132 for certain DG2
@@ -2695,10 +2910,10 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915,
* back for verification on DG2 (due to Wa_14012342262), so
* we need to explicitly skip the readback.
*/
- wa_add(wal, GEN10_CACHE_MODE_SS, 0,
- _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC),
- 0 /* write-only, so skip validation */,
- true);
+ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
+ _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC),
+ 0 /* write-only, so skip validation */,
+ true);
}
/*
@@ -2707,8 +2922,8 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915,
* platforms.
*/
if (INTEL_INFO(i915)->tuning_thread_rr_after_dep)
- wa_masked_field_set(wal, GEN9_ROW_CHICKEN4, THREAD_EX_ARB_MODE,
- THREAD_EX_ARB_MODE_RR_AFTER_DEP);
+ wa_mcr_masked_field_set(wal, GEN9_ROW_CHICKEN4, THREAD_EX_ARB_MODE,
+ THREAD_EX_ARB_MODE_RR_AFTER_DEP);
}
/*
@@ -2734,30 +2949,30 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
if (IS_XEHPSDV(i915)) {
/* Wa_1409954639 */
- wa_masked_en(wal,
- GEN8_ROW_CHICKEN,
- SYSTOLIC_DOP_CLOCK_GATING_DIS);
+ wa_mcr_masked_en(wal,
+ GEN8_ROW_CHICKEN,
+ SYSTOLIC_DOP_CLOCK_GATING_DIS);
/* Wa_1607196519 */
- wa_masked_en(wal,
- GEN9_ROW_CHICKEN4,
- GEN12_DISABLE_GRF_CLEAR);
+ wa_mcr_masked_en(wal,
+ GEN9_ROW_CHICKEN4,
+ GEN12_DISABLE_GRF_CLEAR);
/* Wa_14010670810:xehpsdv */
- wa_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE);
+ wa_mcr_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE);
/* Wa_14010449647:xehpsdv */
- wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1,
- GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE);
+ wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1,
+ GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE);
/* Wa_18011725039:xehpsdv */
if (IS_XEHPSDV_GRAPHICS_STEP(i915, STEP_A1, STEP_B0)) {
- wa_masked_dis(wal, MLTICTXCTL, TDONRENDER);
- wa_write_or(wal, L3SQCREG1_CCS0, FLUSHALLNONCOH);
+ wa_mcr_masked_dis(wal, MLTICTXCTL, TDONRENDER);
+ wa_mcr_write_or(wal, L3SQCREG1_CCS0, FLUSHALLNONCOH);
}
/* Wa_14012362059:xehpsdv */
- wa_write_or(wal, GEN12_MERT_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
/* Wa_14014368820:xehpsdv */
wa_write_or(wal, GEN12_GAMCNTRL_CTRL, INVALIDATION_BROADCAST_MODE_DIS |
@@ -2766,26 +2981,37 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
if (IS_DG2(i915) || IS_PONTEVECCHIO(i915)) {
/* Wa_14015227452:dg2,pvc */
- wa_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE);
+ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE);
/* Wa_22014226127:dg2,pvc */
- wa_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE);
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE);
/* Wa_16015675438:dg2,pvc */
wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE);
/* Wa_18018781329:dg2,pvc */
- wa_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
- wa_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
- wa_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB);
- wa_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB);
+ }
+
+ if (IS_DG2(i915)) {
+ /*
+ * Wa_16011620976:dg2_g11
+ * Wa_22015475538:dg2
+ */
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8);
+
+ /* Wa_18017747507:dg2 */
+ wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE);
}
}
static void
engine_init_workarounds(struct intel_engine_cs *engine, struct i915_wa_list *wal)
{
- if (I915_SELFTEST_ONLY(GRAPHICS_VER(engine->i915) < 4))
+ if (GRAPHICS_VER(engine->i915) < 4)
return;
engine_fake_wa_init(engine, wal);
@@ -2810,17 +3036,14 @@ void intel_engine_init_workarounds(struct intel_engine_cs *engine)
{
struct i915_wa_list *wal = &engine->wa_list;
- if (GRAPHICS_VER(engine->i915) < 4)
- return;
-
- wa_init_start(wal, "engine", engine->name);
+ wa_init_start(wal, engine->gt, "engine", engine->name);
engine_init_workarounds(engine, wal);
wa_init_finish(wal);
}
void intel_engine_apply_workarounds(struct intel_engine_cs *engine)
{
- wa_list_apply(engine->gt, &engine->wa_list);
+ wa_list_apply(&engine->wa_list);
}
static const struct i915_range mcr_ranges_gen8[] = {
@@ -2964,9 +3187,7 @@ retry:
goto err_vma;
}
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
if (err == 0)
err = wa_list_srm(rq, wal, vma);
@@ -2994,7 +3215,7 @@ retry:
if (mcr_range(rq->engine->i915, i915_mmio_reg_offset(wa->reg)))
continue;
- if (!wa_verify(wa, results[i], wal->name, from))
+ if (!wa_verify(wal->gt, wa, results[i], wal->name, from))
err = -ENXIO;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
index 8a4b6de4e754..e14188120e66 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
@@ -10,15 +10,23 @@
#include "i915_reg_defs.h"
+struct intel_gt;
+
struct i915_wa {
- i915_reg_t reg;
+ union {
+ i915_reg_t reg;
+ i915_mcr_reg_t mcr_reg;
+ };
u32 clr;
u32 set;
u32 read;
- bool masked_reg;
+
+ u32 masked_reg:1;
+ u32 is_mcr:1;
};
struct i915_wa_list {
+ struct intel_gt *gt;
const char *name;
const char *engine_name;
struct i915_wa *list;
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
index 1b75f478d1b8..881b64f3e7b9 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
@@ -39,6 +39,16 @@ static int perf_end(struct intel_gt *gt)
return igt_flush_test(gt->i915);
}
+static i915_reg_t timestamp_reg(struct intel_engine_cs *engine)
+{
+ struct drm_i915_private *i915 = engine->i915;
+
+ if (GRAPHICS_VER(i915) == 5 || IS_G4X(i915))
+ return RING_TIMESTAMP_UDW(engine->mmio_base);
+ else
+ return RING_TIMESTAMP(engine->mmio_base);
+}
+
static int write_timestamp(struct i915_request *rq, int slot)
{
struct intel_timeline *tl =
@@ -55,7 +65,7 @@ static int write_timestamp(struct i915_request *rq, int slot)
if (GRAPHICS_VER(rq->engine->i915) >= 8)
cmd++;
*cs++ = cmd;
- *cs++ = i915_mmio_reg_offset(RING_TIMESTAMP(rq->engine->mmio_base));
+ *cs++ = i915_mmio_reg_offset(timestamp_reg(rq->engine));
*cs++ = tl->hwsp_offset + slot * sizeof(u32);
*cs++ = 0;
@@ -125,7 +135,7 @@ static int perf_mi_bb_start(void *arg)
enum intel_engine_id id;
int err = 0;
- if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */
+ if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */
return 0;
perf_begin(gt);
@@ -135,6 +145,9 @@ static int perf_mi_bb_start(void *arg)
u32 cycles[COUNT];
int i;
+ if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0)
+ continue;
+
intel_engine_pm_get(engine);
batch = create_empty_batch(ce);
@@ -249,7 +262,7 @@ static int perf_mi_noop(void *arg)
enum intel_engine_id id;
int err = 0;
- if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */
+ if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */
return 0;
perf_begin(gt);
@@ -259,6 +272,9 @@ static int perf_mi_noop(void *arg)
u32 cycles[COUNT];
int i;
+ if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0)
+ continue;
+
intel_engine_pm_get(engine);
base = create_empty_batch(ce);
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_pm.c b/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
index 0dcb3ed44a73..87c94314cf67 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
@@ -317,7 +317,7 @@ static int live_engine_busy_stats(void *arg)
ENGINE_TRACE(engine, "measuring busy time\n");
preempt_disable();
de = intel_engine_get_busy_time(engine, &t[0]);
- mdelay(10);
+ mdelay(100);
de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
preempt_enable();
dt = ktime_sub(t[1], t[0]);
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 1e08b2473b99..ab2e9a6a2452 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -85,8 +85,6 @@ static int wait_for_reset(struct intel_engine_cs *engine,
break;
} while (time_before(jiffies, timeout));
- flush_scheduled_work();
-
if (rq->fence.error != -EIO) {
pr_err("%s: hanging request %llx:%lld not reset\n",
engine->name,
@@ -2766,9 +2764,7 @@ static int create_gang(struct intel_engine_cs *engine,
i915_request_get(rq);
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, false);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
vma->node.start,
@@ -3182,15 +3178,11 @@ create_gpr_client(struct intel_engine_cs *engine,
}
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, false);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
i915_vma_unlock(vma);
i915_vma_lock(batch);
if (!err)
- err = i915_request_await_object(rq, batch->obj, false);
- if (!err)
err = i915_vma_move_to_active(batch, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
@@ -3475,12 +3467,14 @@ static int random_priority(struct rnd_state *rnd)
struct preempt_smoke {
struct intel_gt *gt;
+ struct kthread_work work;
struct i915_gem_context **contexts;
struct intel_engine_cs *engine;
struct drm_i915_gem_object *batch;
unsigned int ncontext;
struct rnd_state prng;
unsigned long count;
+ int result;
};
static struct i915_gem_context *smoke_context(struct preempt_smoke *smoke)
@@ -3521,9 +3515,7 @@ static int smoke_submit(struct preempt_smoke *smoke,
if (vma) {
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, false);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
vma->node.start,
@@ -3540,34 +3532,31 @@ unpin:
return err;
}
-static int smoke_crescendo_thread(void *arg)
+static void smoke_crescendo_work(struct kthread_work *work)
{
- struct preempt_smoke *smoke = arg;
+ struct preempt_smoke *smoke = container_of(work, typeof(*smoke), work);
IGT_TIMEOUT(end_time);
unsigned long count;
count = 0;
do {
struct i915_gem_context *ctx = smoke_context(smoke);
- int err;
- err = smoke_submit(smoke,
- ctx, count % I915_PRIORITY_MAX,
- smoke->batch);
- if (err)
- return err;
+ smoke->result = smoke_submit(smoke, ctx,
+ count % I915_PRIORITY_MAX,
+ smoke->batch);
count++;
- } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL));
+ } while (!smoke->result && count < smoke->ncontext &&
+ !__igt_timeout(end_time, NULL));
smoke->count = count;
- return 0;
}
static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
#define BATCH BIT(0)
{
- struct task_struct *tsk[I915_NUM_ENGINES] = {};
+ struct kthread_worker *worker[I915_NUM_ENGINES] = {};
struct preempt_smoke *arg;
struct intel_engine_cs *engine;
enum intel_engine_id id;
@@ -3578,6 +3567,8 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
if (!arg)
return -ENOMEM;
+ memset(arg, 0, I915_NUM_ENGINES * sizeof(*arg));
+
for_each_engine(engine, smoke->gt, id) {
arg[id] = *smoke;
arg[id].engine = engine;
@@ -3585,31 +3576,28 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
arg[id].batch = NULL;
arg[id].count = 0;
- tsk[id] = kthread_run(smoke_crescendo_thread, arg,
- "igt/smoke:%d", id);
- if (IS_ERR(tsk[id])) {
- err = PTR_ERR(tsk[id]);
+ worker[id] = kthread_create_worker(0, "igt/smoke:%d", id);
+ if (IS_ERR(worker[id])) {
+ err = PTR_ERR(worker[id]);
break;
}
- get_task_struct(tsk[id]);
- }
- yield(); /* start all threads before we kthread_stop() */
+ kthread_init_work(&arg[id].work, smoke_crescendo_work);
+ kthread_queue_work(worker[id], &arg[id].work);
+ }
count = 0;
for_each_engine(engine, smoke->gt, id) {
- int status;
-
- if (IS_ERR_OR_NULL(tsk[id]))
+ if (IS_ERR_OR_NULL(worker[id]))
continue;
- status = kthread_stop(tsk[id]);
- if (status && !err)
- err = status;
+ kthread_flush_work(&arg[id].work);
+ if (arg[id].result && !err)
+ err = arg[id].result;
count += arg[id].count;
- put_task_struct(tsk[id]);
+ kthread_destroy_worker(worker[id]);
}
pr_info("Submitted %lu crescendo:%x requests across %d engines and %d contexts\n",
diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
index be94f863bdef..b46425aeb2f0 100644
--- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
@@ -36,6 +36,19 @@ static int cmp_u32(const void *A, const void *B)
return 0;
}
+static u32 read_timestamp(struct intel_engine_cs *engine)
+{
+ struct drm_i915_private *i915 = engine->i915;
+
+ /* On i965 the first read tends to give a stale value */
+ ENGINE_READ_FW(engine, RING_TIMESTAMP);
+
+ if (GRAPHICS_VER(i915) == 5 || IS_G4X(i915))
+ return ENGINE_READ_FW(engine, RING_TIMESTAMP_UDW);
+ else
+ return ENGINE_READ_FW(engine, RING_TIMESTAMP);
+}
+
static void measure_clocks(struct intel_engine_cs *engine,
u32 *out_cycles, ktime_t *out_dt)
{
@@ -45,13 +58,13 @@ static void measure_clocks(struct intel_engine_cs *engine,
for (i = 0; i < 5; i++) {
local_irq_disable();
- cycles[i] = -ENGINE_READ_FW(engine, RING_TIMESTAMP);
+ cycles[i] = -read_timestamp(engine);
dt[i] = ktime_get();
udelay(1000);
dt[i] = ktime_sub(ktime_get(), dt[i]);
- cycles[i] += ENGINE_READ_FW(engine, RING_TIMESTAMP);
+ cycles[i] += read_timestamp(engine);
local_irq_enable();
}
@@ -78,25 +91,6 @@ static int live_gt_clocks(void *arg)
if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */
return 0;
- if (GRAPHICS_VER(gt->i915) == 5)
- /*
- * XXX CS_TIMESTAMP low dword is dysfunctional?
- *
- * Ville's experiments indicate the high dword still works,
- * but at a correspondingly reduced frequency.
- */
- return 0;
-
- if (GRAPHICS_VER(gt->i915) == 4)
- /*
- * XXX CS_TIMESTAMP appears gibberish
- *
- * Ville's experiments indicate that it mostly appears 'stuck'
- * in that we see the register report the same cycle count
- * for a couple of reads.
- */
- return 0;
-
intel_gt_pm_get(gt);
intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index 7f3bb1d34dfb..bc05ef48c194 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -99,22 +99,6 @@ static u64 hws_address(const struct i915_vma *hws,
return hws->node.start + offset_in_page(sizeof(u32)*rq->fence.context);
}
-static int move_to_active(struct i915_vma *vma,
- struct i915_request *rq,
- unsigned int flags)
-{
- int err;
-
- i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj,
- flags & EXEC_OBJECT_WRITE);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, flags);
- i915_vma_unlock(vma);
-
- return err;
-}
-
static struct i915_request *
hang_create_request(struct hang *h, struct intel_engine_cs *engine)
{
@@ -175,11 +159,11 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
goto unpin_hws;
}
- err = move_to_active(vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
if (err)
goto cancel_rq;
- err = move_to_active(hws, rq, 0);
+ err = igt_vma_move_to_active_unlocked(hws, rq, 0);
if (err)
goto cancel_rq;
@@ -866,10 +850,13 @@ static int igt_reset_active_engine(void *arg)
}
struct active_engine {
- struct task_struct *task;
+ struct kthread_worker *worker;
+ struct kthread_work work;
struct intel_engine_cs *engine;
unsigned long resets;
unsigned int flags;
+ bool stop;
+ int result;
};
#define TEST_ACTIVE BIT(0)
@@ -900,10 +887,10 @@ static int active_request_put(struct i915_request *rq)
return err;
}
-static int active_engine(void *data)
+static void active_engine(struct kthread_work *work)
{
I915_RND_STATE(prng);
- struct active_engine *arg = data;
+ struct active_engine *arg = container_of(work, typeof(*arg), work);
struct intel_engine_cs *engine = arg->engine;
struct i915_request *rq[8] = {};
struct intel_context *ce[ARRAY_SIZE(rq)];
@@ -913,16 +900,17 @@ static int active_engine(void *data)
for (count = 0; count < ARRAY_SIZE(ce); count++) {
ce[count] = intel_context_create(engine);
if (IS_ERR(ce[count])) {
- err = PTR_ERR(ce[count]);
- pr_err("[%s] Create context #%ld failed: %d!\n", engine->name, count, err);
+ arg->result = PTR_ERR(ce[count]);
+ pr_err("[%s] Create context #%ld failed: %d!\n",
+ engine->name, count, arg->result);
while (--count)
intel_context_put(ce[count]);
- return err;
+ return;
}
}
count = 0;
- while (!kthread_should_stop()) {
+ while (!READ_ONCE(arg->stop)) {
unsigned int idx = count++ & (ARRAY_SIZE(rq) - 1);
struct i915_request *old = rq[idx];
struct i915_request *new;
@@ -967,7 +955,7 @@ static int active_engine(void *data)
intel_context_put(ce[count]);
}
- return err;
+ arg->result = err;
}
static int __igt_reset_engines(struct intel_gt *gt,
@@ -1022,7 +1010,7 @@ static int __igt_reset_engines(struct intel_gt *gt,
memset(threads, 0, sizeof(*threads) * I915_NUM_ENGINES);
for_each_engine(other, gt, tmp) {
- struct task_struct *tsk;
+ struct kthread_worker *worker;
threads[tmp].resets =
i915_reset_engine_count(global, other);
@@ -1036,19 +1024,21 @@ static int __igt_reset_engines(struct intel_gt *gt,
threads[tmp].engine = other;
threads[tmp].flags = flags;
- tsk = kthread_run(active_engine, &threads[tmp],
- "igt/%s", other->name);
- if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
- pr_err("[%s] Thread spawn failed: %d!\n", engine->name, err);
+ worker = kthread_create_worker(0, "igt/%s",
+ other->name);
+ if (IS_ERR(worker)) {
+ err = PTR_ERR(worker);
+ pr_err("[%s] Worker create failed: %d!\n",
+ engine->name, err);
goto unwind;
}
- threads[tmp].task = tsk;
- get_task_struct(tsk);
- }
+ threads[tmp].worker = worker;
- yield(); /* start all threads before we begin */
+ kthread_init_work(&threads[tmp].work, active_engine);
+ kthread_queue_work(threads[tmp].worker,
+ &threads[tmp].work);
+ }
st_engine_heartbeat_disable_no_pm(engine);
GEM_BUG_ON(test_and_set_bit(I915_RESET_ENGINE + id,
@@ -1197,17 +1187,20 @@ unwind:
for_each_engine(other, gt, tmp) {
int ret;
- if (!threads[tmp].task)
+ if (!threads[tmp].worker)
continue;
- ret = kthread_stop(threads[tmp].task);
+ WRITE_ONCE(threads[tmp].stop, true);
+ kthread_flush_work(&threads[tmp].work);
+ ret = READ_ONCE(threads[tmp].result);
if (ret) {
pr_err("kthread for other engine %s failed, err=%d\n",
other->name, ret);
if (!err)
err = ret;
}
- put_task_struct(threads[tmp].task);
+
+ kthread_destroy_worker(threads[tmp].worker);
/* GuC based resets are not logged per engine */
if (!using_guc) {
@@ -1510,18 +1503,9 @@ static int __igt_reset_evict_vma(struct intel_gt *gt,
}
}
- i915_vma_lock(arg.vma);
- err = i915_request_await_object(rq, arg.vma->obj,
- flags & EXEC_OBJECT_WRITE);
- if (err == 0) {
- err = i915_vma_move_to_active(arg.vma, rq, flags);
- if (err)
- pr_err("[%s] Move to active failed: %d!\n", engine->name, err);
- } else {
- pr_err("[%s] Request await failed: %d!\n", engine->name, err);
- }
-
- i915_vma_unlock(arg.vma);
+ err = igt_vma_move_to_active_unlocked(arg.vma, rq, flags);
+ if (err)
+ pr_err("[%s] Move to active failed: %d!\n", engine->name, err);
if (flags & EXEC_OBJECT_NEEDS_FENCE)
i915_vma_unpin_fence(arg.vma);
diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c
index 82d3f8058995..7c56ffd2c659 100644
--- a/drivers/gpu/drm/i915/gt/selftest_lrc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c
@@ -452,9 +452,7 @@ retry:
*cs++ = i915_ggtt_offset(scratch) + RING_TAIL_IDX * sizeof(u32);
*cs++ = 0;
- err = i915_request_await_object(rq, scratch->obj, true);
- if (!err)
- err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
i915_request_get(rq);
i915_request_add(rq);
@@ -602,9 +600,7 @@ __gpr_read(struct intel_context *ce, struct i915_vma *scratch, u32 *slot)
}
i915_vma_lock(scratch);
- err = i915_request_await_object(rq, scratch->obj, true);
- if (!err)
- err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(scratch);
i915_request_get(rq);
@@ -1053,21 +1049,6 @@ store_context(struct intel_context *ce, struct i915_vma *scratch)
return batch;
}
-static int move_to_active(struct i915_request *rq,
- struct i915_vma *vma,
- unsigned int flags)
-{
- int err;
-
- i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, flags);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, flags);
- i915_vma_unlock(vma);
-
- return err;
-}
-
static struct i915_request *
record_registers(struct intel_context *ce,
struct i915_vma *before,
@@ -1093,19 +1074,19 @@ record_registers(struct intel_context *ce,
if (IS_ERR(rq))
goto err_after;
- err = move_to_active(rq, before, EXEC_OBJECT_WRITE);
+ err = igt_vma_move_to_active_unlocked(before, rq, EXEC_OBJECT_WRITE);
if (err)
goto err_rq;
- err = move_to_active(rq, b_before, 0);
+ err = igt_vma_move_to_active_unlocked(b_before, rq, 0);
if (err)
goto err_rq;
- err = move_to_active(rq, after, EXEC_OBJECT_WRITE);
+ err = igt_vma_move_to_active_unlocked(after, rq, EXEC_OBJECT_WRITE);
if (err)
goto err_rq;
- err = move_to_active(rq, b_after, 0);
+ err = igt_vma_move_to_active_unlocked(b_after, rq, 0);
if (err)
goto err_rq;
@@ -1243,7 +1224,7 @@ static int poison_registers(struct intel_context *ce, u32 poison, u32 *sema)
goto err_batch;
}
- err = move_to_active(rq, batch, 0);
+ err = igt_vma_move_to_active_unlocked(batch, rq, 0);
if (err)
goto err_rq;
diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c
index 2b0c87999949..0dc5309c90a4 100644
--- a/drivers/gpu/drm/i915/gt/selftest_migrate.c
+++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c
@@ -6,6 +6,7 @@
#include <linux/sort.h>
#include "gem/i915_gem_internal.h"
+#include "gem/i915_gem_lmem.h"
#include "selftests/i915_random.h"
diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
index c1d861333c44..f27cc28608d4 100644
--- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
@@ -7,6 +7,7 @@
#include "gt/intel_gpu_commands.h"
#include "i915_selftest.h"
+#include "gem/selftests/igt_gem_utils.h"
#include "gem/selftests/mock_context.h"
#include "selftests/igt_reset.h"
#include "selftests/igt_spinner.h"
@@ -228,9 +229,7 @@ static int check_mocs_engine(struct live_mocs *arg,
return PTR_ERR(rq);
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, true);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(vma);
/* Read the mocs tables back using SRM */
diff --git a/drivers/gpu/drm/i915/gt/selftest_rc6.c b/drivers/gpu/drm/i915/gt/selftest_rc6.c
index 8c70b7e12074..2ceeadecc639 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rc6.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rc6.c
@@ -19,11 +19,11 @@ static u64 rc6_residency(struct intel_rc6 *rc6)
/* XXX VLV_GT_MEDIA_RC6? */
- result = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6);
+ result = intel_rc6_residency_ns(rc6, INTEL_RC6_RES_RC6);
if (HAS_RC6p(rc6_to_i915(rc6)))
- result += intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6p);
+ result += intel_rc6_residency_ns(rc6, INTEL_RC6_RES_RC6p);
if (HAS_RC6pp(rc6_to_i915(rc6)))
- result += intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6pp);
+ result += intel_rc6_residency_ns(rc6, INTEL_RC6_RES_RC6pp);
return result;
}
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index cfb4708dd62e..39f1b7564170 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -652,9 +652,7 @@ int live_rps_frequency_cs(void *arg)
goto err_vma;
}
- err = i915_request_await_object(rq, vma->obj, false);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
vma->node.start,
@@ -793,9 +791,7 @@ int live_rps_frequency_srm(void *arg)
goto err_vma;
}
- err = i915_request_await_object(rq, vma->obj, false);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
vma->node.start,
@@ -1107,21 +1103,27 @@ static u64 __measure_power(int duration_ms)
return div64_u64(1000 * 1000 * dE, dt);
}
-static u64 measure_power_at(struct intel_rps *rps, int *freq)
+static u64 measure_power(struct intel_rps *rps, int *freq)
{
u64 x[5];
int i;
- *freq = rps_set_check(rps, *freq);
for (i = 0; i < 5; i++)
x[i] = __measure_power(5);
- *freq = (*freq + read_cagf(rps)) / 2;
+
+ *freq = (*freq + intel_rps_read_actual_frequency(rps)) / 2;
/* A simple triangle filter for better result stability */
sort(x, 5, sizeof(*x), cmp_u64, NULL);
return div_u64(x[1] + 2 * x[2] + x[3], 4);
}
+static u64 measure_power_at(struct intel_rps *rps, int *freq)
+{
+ *freq = rps_set_check(rps, *freq);
+ return measure_power(rps, freq);
+}
+
int live_rps_power(void *arg)
{
struct intel_gt *gt = arg;
diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c
index f8a1d27df272..bd44ce73a504 100644
--- a/drivers/gpu/drm/i915/gt/selftest_slpc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c
@@ -11,7 +11,16 @@
enum test_type {
VARY_MIN,
VARY_MAX,
- MAX_GRANTED
+ MAX_GRANTED,
+ SLPC_POWER,
+ TILE_INTERACTION,
+};
+
+struct slpc_thread {
+ struct kthread_worker *worker;
+ struct kthread_work work;
+ struct intel_gt *gt;
+ int result;
};
static int slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 freq)
@@ -41,6 +50,39 @@ static int slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 freq)
return ret;
}
+static int slpc_set_freq(struct intel_gt *gt, u32 freq)
+{
+ int err;
+ struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
+
+ err = slpc_set_max_freq(slpc, freq);
+ if (err) {
+ pr_err("Unable to update max freq");
+ return err;
+ }
+
+ err = slpc_set_min_freq(slpc, freq);
+ if (err) {
+ pr_err("Unable to update min freq");
+ return err;
+ }
+
+ return err;
+}
+
+static u64 measure_power_at_freq(struct intel_gt *gt, int *freq, u64 *power)
+{
+ int err = 0;
+
+ err = slpc_set_freq(gt, *freq);
+ if (err)
+ return err;
+ *freq = intel_rps_read_actual_frequency(&gt->rps);
+ *power = measure_power(&gt->rps, freq);
+
+ return err;
+}
+
static int vary_max_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps,
u32 *max_act_freq)
{
@@ -113,6 +155,58 @@ static int vary_min_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps,
return err;
}
+static int slpc_power(struct intel_gt *gt, struct intel_engine_cs *engine)
+{
+ struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
+ struct {
+ u64 power;
+ int freq;
+ } min, max;
+ int err = 0;
+
+ /*
+ * Our fundamental assumption is that running at lower frequency
+ * actually saves power. Let's see if our RAPL measurement supports
+ * that theory.
+ */
+ if (!librapl_supported(gt->i915))
+ return 0;
+
+ min.freq = slpc->min_freq;
+ err = measure_power_at_freq(gt, &min.freq, &min.power);
+
+ if (err)
+ return err;
+
+ max.freq = slpc->rp0_freq;
+ err = measure_power_at_freq(gt, &max.freq, &max.power);
+
+ if (err)
+ return err;
+
+ pr_info("%s: min:%llumW @ %uMHz, max:%llumW @ %uMHz\n",
+ engine->name,
+ min.power, min.freq,
+ max.power, max.freq);
+
+ if (10 * min.freq >= 9 * max.freq) {
+ pr_notice("Could not control frequency, ran at [%uMHz, %uMhz]\n",
+ min.freq, max.freq);
+ }
+
+ if (11 * min.power > 10 * max.power) {
+ pr_err("%s: did not conserve power when setting lower frequency!\n",
+ engine->name);
+ err = -EINVAL;
+ }
+
+ /* Restore min/max frequencies */
+ slpc_set_max_freq(slpc, slpc->rp0_freq);
+ slpc_set_min_freq(slpc, slpc->min_freq);
+
+ return err;
+}
+
static int max_granted_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps, u32 *max_act_freq)
{
struct intel_gt *gt = rps_to_gt(rps);
@@ -126,7 +220,8 @@ static int max_granted_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps,
*max_act_freq = intel_rps_read_actual_frequency(rps);
if (*max_act_freq != slpc->rp0_freq) {
/* Check if there was some throttling by pcode */
- perf_limit_reasons = intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS);
+ perf_limit_reasons = intel_uncore_read(gt->uncore,
+ intel_gt_perf_limit_reasons_reg(gt));
/* If not, this is an error */
if (!(perf_limit_reasons & GT0_PERF_LIMIT_REASONS_MASK)) {
@@ -153,6 +248,11 @@ static int run_test(struct intel_gt *gt, int test_type)
if (!intel_uc_uses_guc_slpc(&gt->uc))
return 0;
+ if (slpc->min_freq == slpc->rp0_freq) {
+ pr_err("Min/Max are fused to the same value\n");
+ return -EINVAL;
+ }
+
if (igt_spinner_init(&spin, gt))
return -ENOMEM;
@@ -167,17 +267,14 @@ static int run_test(struct intel_gt *gt, int test_type)
}
/*
- * FIXME: With efficient frequency enabled, GuC can request
- * frequencies higher than the SLPC max. While this is fixed
- * in GuC, we level set these tests with RPn as min.
+ * Set min frequency to RPn so that we can test the whole
+ * range of RPn-RP0. This also turns off efficient freq
+ * usage and makes results more predictable.
*/
err = slpc_set_min_freq(slpc, slpc->min_freq);
- if (err)
+ if (err) {
+ pr_err("Unable to update min freq!");
return err;
-
- if (slpc->min_freq == slpc->rp0_freq) {
- pr_err("Min/Max are fused to the same value\n");
- return -EINVAL;
}
intel_gt_pm_wait_for_idle(gt);
@@ -222,9 +319,10 @@ static int run_test(struct intel_gt *gt, int test_type)
break;
case MAX_GRANTED:
+ case TILE_INTERACTION:
/* Media engines have a different RP0 */
- if (engine->class == VIDEO_DECODE_CLASS ||
- engine->class == VIDEO_ENHANCEMENT_CLASS) {
+ if (gt->type != GT_MEDIA && (engine->class == VIDEO_DECODE_CLASS ||
+ engine->class == VIDEO_ENHANCEMENT_CLASS)) {
igt_spinner_end(&spin);
st_engine_heartbeat_enable(engine);
err = 0;
@@ -233,17 +331,24 @@ static int run_test(struct intel_gt *gt, int test_type)
err = max_granted_freq(slpc, rps, &max_act_freq);
break;
- }
- pr_info("Max actual frequency for %s was %d\n",
- engine->name, max_act_freq);
+ case SLPC_POWER:
+ err = slpc_power(gt, engine);
+ break;
+ }
- /* Actual frequency should rise above min */
- if (max_act_freq <= slpc_min_freq) {
- pr_err("Actual freq did not rise above min\n");
- pr_err("Perf Limit Reasons: 0x%x\n",
- intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS));
- err = -EINVAL;
+ if (test_type != SLPC_POWER) {
+ pr_info("Max actual frequency for %s was %d\n",
+ engine->name, max_act_freq);
+
+ /* Actual frequency should rise above min */
+ if (max_act_freq <= slpc->min_freq) {
+ pr_err("Actual freq did not rise above min\n");
+ pr_err("Perf Limit Reasons: 0x%x\n",
+ intel_uncore_read(gt->uncore,
+ intel_gt_perf_limit_reasons_reg(gt)));
+ err = -EINVAL;
+ }
}
igt_spinner_end(&spin);
@@ -270,26 +375,116 @@ static int run_test(struct intel_gt *gt, int test_type)
static int live_slpc_vary_min(void *arg)
{
struct drm_i915_private *i915 = arg;
- struct intel_gt *gt = to_gt(i915);
+ struct intel_gt *gt;
+ unsigned int i;
+ int ret;
+
+ for_each_gt(gt, i915, i) {
+ ret = run_test(gt, VARY_MIN);
+ if (ret)
+ return ret;
+ }
- return run_test(gt, VARY_MIN);
+ return ret;
}
static int live_slpc_vary_max(void *arg)
{
struct drm_i915_private *i915 = arg;
- struct intel_gt *gt = to_gt(i915);
+ struct intel_gt *gt;
+ unsigned int i;
+ int ret;
+
+ for_each_gt(gt, i915, i) {
+ ret = run_test(gt, VARY_MAX);
+ if (ret)
+ return ret;
+ }
- return run_test(gt, VARY_MAX);
+ return ret;
}
/* check if pcode can grant RP0 */
static int live_slpc_max_granted(void *arg)
{
struct drm_i915_private *i915 = arg;
- struct intel_gt *gt = to_gt(i915);
+ struct intel_gt *gt;
+ unsigned int i;
+ int ret;
+
+ for_each_gt(gt, i915, i) {
+ ret = run_test(gt, MAX_GRANTED);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int live_slpc_power(void *arg)
+{
+ struct drm_i915_private *i915 = arg;
+ struct intel_gt *gt;
+ unsigned int i;
+ int ret;
+
+ for_each_gt(gt, i915, i) {
+ ret = run_test(gt, SLPC_POWER);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void slpc_spinner_thread(struct kthread_work *work)
+{
+ struct slpc_thread *thread = container_of(work, typeof(*thread), work);
+
+ thread->result = run_test(thread->gt, TILE_INTERACTION);
+}
+
+static int live_slpc_tile_interaction(void *arg)
+{
+ struct drm_i915_private *i915 = arg;
+ struct intel_gt *gt;
+ struct slpc_thread *threads;
+ int i = 0, ret = 0;
+
+ threads = kcalloc(I915_MAX_GT, sizeof(*threads), GFP_KERNEL);
+ if (!threads)
+ return -ENOMEM;
+
+ for_each_gt(gt, i915, i) {
+ threads[i].worker = kthread_create_worker(0, "igt/slpc_parallel:%d", gt->info.id);
+
+ if (IS_ERR(threads[i].worker)) {
+ ret = PTR_ERR(threads[i].worker);
+ break;
+ }
+
+ threads[i].gt = gt;
+ kthread_init_work(&threads[i].work, slpc_spinner_thread);
+ kthread_queue_work(threads[i].worker, &threads[i].work);
+ }
+
+ for_each_gt(gt, i915, i) {
+ int status;
+
+ if (IS_ERR_OR_NULL(threads[i].worker))
+ continue;
- return run_test(gt, MAX_GRANTED);
+ kthread_flush_work(&threads[i].work);
+ status = READ_ONCE(threads[i].result);
+ if (status && !ret) {
+ pr_err("%s GT %d failed ", __func__, gt->info.id);
+ ret = status;
+ }
+ kthread_destroy_worker(threads[i].worker);
+ }
+
+ kfree(threads);
+ return ret;
}
int intel_slpc_live_selftests(struct drm_i915_private *i915)
@@ -298,10 +493,17 @@ int intel_slpc_live_selftests(struct drm_i915_private *i915)
SUBTEST(live_slpc_vary_max),
SUBTEST(live_slpc_vary_min),
SUBTEST(live_slpc_max_granted),
+ SUBTEST(live_slpc_power),
+ SUBTEST(live_slpc_tile_interaction),
};
- if (intel_gt_is_wedged(to_gt(i915)))
- return 0;
+ struct intel_gt *gt;
+ unsigned int i;
+
+ for_each_gt(gt, i915, i) {
+ if (intel_gt_is_wedged(gt))
+ return 0;
+ }
return i915_live_subtests(tests, i915);
}
diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
index 67a9aab801dd..96e3861706d6 100644
--- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
@@ -66,14 +66,14 @@ reference_lists_init(struct intel_gt *gt, struct wa_lists *lists)
memset(lists, 0, sizeof(*lists));
- wa_init_start(&lists->gt_wa_list, "GT_REF", "global");
+ wa_init_start(&lists->gt_wa_list, gt, "GT_REF", "global");
gt_init_workarounds(gt, &lists->gt_wa_list);
wa_init_finish(&lists->gt_wa_list);
for_each_engine(engine, gt, id) {
struct i915_wa_list *wal = &lists->engine[id].wa_list;
- wa_init_start(wal, "REF", engine->name);
+ wa_init_start(wal, gt, "REF", engine->name);
engine_init_workarounds(engine, wal);
wa_init_finish(wal);
@@ -139,9 +139,7 @@ read_nonprivs(struct intel_context *ce)
}
i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(vma);
if (err)
goto err_req;
@@ -632,16 +630,12 @@ retry:
goto err_request;
}
- err = i915_request_await_object(rq, batch->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(batch, rq, 0);
+ err = i915_vma_move_to_active(batch, rq, 0);
if (err)
goto err_request;
- err = i915_request_await_object(rq, scratch->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(scratch, rq,
- EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(scratch, rq,
+ EXEC_OBJECT_WRITE);
if (err)
goto err_request;
@@ -860,9 +854,7 @@ static int read_whitelisted_registers(struct intel_context *ce,
return PTR_ERR(rq);
i915_vma_lock(results);
- err = i915_request_await_object(rq, results->obj, true);
- if (err == 0)
- err = i915_vma_move_to_active(results, rq, EXEC_OBJECT_WRITE);
+ err = i915_vma_move_to_active(results, rq, EXEC_OBJECT_WRITE);
i915_vma_unlock(results);
if (err)
goto err_req;
@@ -944,9 +936,7 @@ static int scrub_whitelisted_registers(struct intel_context *ce)
}
i915_vma_lock(batch);
- err = i915_request_await_object(rq, batch->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(batch, rq, 0);
+ err = i915_vma_move_to_active(batch, rq, 0);
i915_vma_unlock(batch);
if (err)
goto err_request;
@@ -991,7 +981,7 @@ static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg)
/* Alas, we must pardon some whitelists. Mistakes already made */
static const struct regmask pardon[] = {
{ GEN9_CTX_PREEMPT_REG, 9 },
- { GEN8_L3SQCREG4, 9 },
+ { _MMIO(0xb118), 9 }, /* GEN8_L3SQCREG4 */
};
return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon));
diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c
index 967031056202..f2d9858d827c 100644
--- a/drivers/gpu/drm/i915/gt/sysfs_engines.c
+++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c
@@ -144,7 +144,7 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
+ unsigned long long duration, clamped;
int err;
/*
@@ -168,7 +168,8 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr,
if (err)
return err;
- if (duration > jiffies_to_nsecs(2))
+ clamped = intel_clamp_max_busywait_duration_ns(engine, duration);
+ if (duration != clamped)
return -EINVAL;
WRITE_ONCE(engine->props.max_busywait_duration_ns, duration);
@@ -203,7 +204,7 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
+ unsigned long long duration, clamped;
int err;
/*
@@ -218,7 +219,8 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr,
if (err)
return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
+ clamped = intel_clamp_timeslice_duration_ms(engine, duration);
+ if (duration != clamped)
return -EINVAL;
WRITE_ONCE(engine->props.timeslice_duration_ms, duration);
@@ -256,7 +258,7 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
+ unsigned long long duration, clamped;
int err;
/*
@@ -272,7 +274,8 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr,
if (err)
return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
+ clamped = intel_clamp_stop_timeout_ms(engine, duration);
+ if (duration != clamped)
return -EINVAL;
WRITE_ONCE(engine->props.stop_timeout_ms, duration);
@@ -306,7 +309,7 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long timeout;
+ unsigned long long timeout, clamped;
int err;
/*
@@ -322,7 +325,8 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr,
if (err)
return err;
- if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
+ clamped = intel_clamp_preempt_timeout_ms(engine, timeout);
+ if (timeout != clamped)
return -EINVAL;
WRITE_ONCE(engine->props.preempt_timeout_ms, timeout);
@@ -362,7 +366,7 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long delay;
+ unsigned long long delay, clamped;
int err;
/*
@@ -379,7 +383,8 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr,
if (err)
return err;
- if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
+ clamped = intel_clamp_heartbeat_interval_ms(engine, delay);
+ if (delay != clamped)
return -EINVAL;
err = intel_engine_set_heartbeat(engine, delay);
diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
index 29ef8afc8c2e..f359bef046e0 100644
--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
@@ -117,6 +117,7 @@ enum intel_guc_action {
INTEL_GUC_ACTION_ENTER_S_STATE = 0x501,
INTEL_GUC_ACTION_EXIT_S_STATE = 0x502,
INTEL_GUC_ACTION_GLOBAL_SCHED_POLICY_CHANGE = 0x506,
+ INTEL_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV = 0x509,
INTEL_GUC_ACTION_SCHED_CONTEXT = 0x1000,
INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_SET = 0x1001,
INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002,
diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h
index 4c840a2639dc..811add10c30d 100644
--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h
@@ -128,6 +128,15 @@ enum slpc_media_ratio_mode {
SLPC_MEDIA_RATIO_MODE_FIXED_ONE_TO_TWO = 2,
};
+enum slpc_gucrc_mode {
+ SLPC_GUCRC_MODE_HW = 0,
+ SLPC_GUCRC_MODE_GUCRC_NO_RC6 = 1,
+ SLPC_GUCRC_MODE_GUCRC_STATIC_TIMEOUT = 2,
+ SLPC_GUCRC_MODE_GUCRC_DYNAMIC_HYSTERESIS = 3,
+
+ SLPC_GUCRC_MODE_MAX,
+};
+
enum slpc_event_id {
SLPC_EVENT_RESET = 0,
SLPC_EVENT_SHUTDOWN = 1,
diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h
index 4a59478c3b5c..58012edd4eb0 100644
--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h
@@ -82,9 +82,16 @@
#define GUC_KLV_SELF_CFG_G2H_CTB_SIZE_LEN 1u
/*
+ * Global scheduling policy update keys.
+ */
+enum {
+ GUC_SCHEDULING_POLICIES_KLV_ID_RENDER_COMPUTE_YIELD = 0x1001,
+};
+
+/*
* Per context scheduling policy update keys.
*/
-enum {
+enum {
GUC_CONTEXT_POLICIES_KLV_ID_EXECUTION_QUANTUM = 0x2001,
GUC_CONTEXT_POLICIES_KLV_ID_PREEMPTION_TIMEOUT = 0x2002,
GUC_CONTEXT_POLICIES_KLV_ID_SCHEDULING_PRIORITY = 0x2003,
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
index bac06e3d6f2c..52aede324788 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
@@ -98,6 +98,8 @@ static void gen9_enable_guc_interrupts(struct intel_guc *guc)
gt->pm_guc_events);
gen6_gt_pm_enable_irq(gt, gt->pm_guc_events);
spin_unlock_irq(gt->irq_lock);
+
+ guc->interrupts.enabled = true;
}
static void gen9_disable_guc_interrupts(struct intel_guc *guc)
@@ -105,6 +107,7 @@ static void gen9_disable_guc_interrupts(struct intel_guc *guc)
struct intel_gt *gt = guc_to_gt(guc);
assert_rpm_wakelock_held(&gt->i915->runtime_pm);
+ guc->interrupts.enabled = false;
spin_lock_irq(gt->irq_lock);
@@ -116,39 +119,39 @@ static void gen9_disable_guc_interrupts(struct intel_guc *guc)
gen9_reset_guc_interrupts(guc);
}
+static bool __gen11_reset_guc_interrupts(struct intel_gt *gt)
+{
+ u32 irq = gt->type == GT_MEDIA ? MTL_MGUC : GEN11_GUC;
+
+ lockdep_assert_held(gt->irq_lock);
+ return gen11_gt_reset_one_iir(gt, 0, irq);
+}
+
static void gen11_reset_guc_interrupts(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
spin_lock_irq(gt->irq_lock);
- gen11_gt_reset_one_iir(gt, 0, GEN11_GUC);
+ __gen11_reset_guc_interrupts(gt);
spin_unlock_irq(gt->irq_lock);
}
static void gen11_enable_guc_interrupts(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
- u32 events = REG_FIELD_PREP(ENGINE1_MASK, GUC_INTR_GUC2HOST);
spin_lock_irq(gt->irq_lock);
- WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_GUC));
- intel_uncore_write(gt->uncore,
- GEN11_GUC_SG_INTR_ENABLE, events);
- intel_uncore_write(gt->uncore,
- GEN11_GUC_SG_INTR_MASK, ~events);
+ __gen11_reset_guc_interrupts(gt);
spin_unlock_irq(gt->irq_lock);
+
+ guc->interrupts.enabled = true;
}
static void gen11_disable_guc_interrupts(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
- spin_lock_irq(gt->irq_lock);
-
- intel_uncore_write(gt->uncore, GEN11_GUC_SG_INTR_MASK, ~0);
- intel_uncore_write(gt->uncore, GEN11_GUC_SG_INTR_ENABLE, 0);
-
- spin_unlock_irq(gt->irq_lock);
+ guc->interrupts.enabled = false;
intel_synchronize_irq(gt->i915);
gen11_reset_guc_interrupts(guc);
@@ -156,7 +159,8 @@ static void gen11_disable_guc_interrupts(struct intel_guc *guc)
void intel_guc_init_early(struct intel_guc *guc)
{
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+ struct intel_gt *gt = guc_to_gt(guc);
+ struct drm_i915_private *i915 = gt->i915;
intel_uc_fw_init_early(&guc->fw, INTEL_UC_FW_TYPE_GUC);
intel_guc_ct_init_early(&guc->ct);
@@ -168,12 +172,17 @@ void intel_guc_init_early(struct intel_guc *guc)
mutex_init(&guc->send_mutex);
spin_lock_init(&guc->irq_lock);
if (GRAPHICS_VER(i915) >= 11) {
- guc->notify_reg = GEN11_GUC_HOST_INTERRUPT;
guc->interrupts.reset = gen11_reset_guc_interrupts;
guc->interrupts.enable = gen11_enable_guc_interrupts;
guc->interrupts.disable = gen11_disable_guc_interrupts;
- guc->send_regs.base =
- i915_mmio_reg_offset(GEN11_SOFT_SCRATCH(0));
+ if (gt->type == GT_MEDIA) {
+ guc->notify_reg = MEDIA_GUC_HOST_INTERRUPT;
+ guc->send_regs.base = i915_mmio_reg_offset(MEDIA_SOFT_SCRATCH(0));
+ } else {
+ guc->notify_reg = GEN11_GUC_HOST_INTERRUPT;
+ guc->send_regs.base = i915_mmio_reg_offset(GEN11_SOFT_SCRATCH(0));
+ }
+
guc->send_regs.count = GEN11_SOFT_SCRATCH_COUNT;
} else {
@@ -441,6 +450,7 @@ err_log:
err_fw:
intel_uc_fw_fini(&guc->fw);
out:
+ intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_INIT_FAIL);
i915_probe_error(gt->i915, "failed with %d\n", ret);
return ret;
}
@@ -870,14 +880,14 @@ void intel_guc_load_status(struct intel_guc *guc, struct drm_printer *p)
u32 status = intel_uncore_read(uncore, GUC_STATUS);
u32 i;
- drm_printf(p, "\nGuC status 0x%08x:\n", status);
+ drm_printf(p, "GuC status 0x%08x:\n", status);
drm_printf(p, "\tBootrom status = 0x%x\n",
(status & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT);
drm_printf(p, "\tuKernel status = 0x%x\n",
(status & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT);
drm_printf(p, "\tMIA Core status = 0x%x\n",
(status & GS_MIA_MASK) >> GS_MIA_SHIFT);
- drm_puts(p, "\nScratch registers:\n");
+ drm_puts(p, "Scratch registers:\n");
for (i = 0; i < 16; i++) {
drm_printf(p, "\t%2d: \t0x%x\n",
i, intel_uncore_read(uncore, SOFT_SCRATCH(i)));
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 804133df1ac9..1bb3f9829286 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -78,6 +78,7 @@ struct intel_guc {
/** @interrupts: pointers to GuC interrupt-managing functions. */
struct {
+ bool enabled;
void (*reset)(struct intel_guc *guc);
void (*enable)(struct intel_guc *guc);
void (*disable)(struct intel_guc *guc);
@@ -113,6 +114,10 @@ struct intel_guc {
*/
struct list_head guc_id_list;
/**
+ * @guc_ids_in_use: Number single-lrc guc_ids in use
+ */
+ unsigned int guc_ids_in_use;
+ /**
* @destroyed_contexts: list of contexts waiting to be destroyed
* (deregistered with the GuC)
*/
@@ -132,6 +137,16 @@ struct intel_guc {
* @reset_fail_mask: mask of engines that failed to reset
*/
intel_engine_mask_t reset_fail_mask;
+ /**
+ * @sched_disable_delay_ms: schedule disable delay, in ms, for
+ * contexts
+ */
+ unsigned int sched_disable_delay_ms;
+ /**
+ * @sched_disable_gucid_threshold: threshold of min remaining available
+ * guc_ids before we start bypassing the schedule disable delay
+ */
+ unsigned int sched_disable_gucid_threshold;
} submission_state;
/**
@@ -316,9 +331,11 @@ retry:
return err;
}
+/* Only call this from the interrupt handler code */
static inline void intel_guc_to_host_event_handler(struct intel_guc *guc)
{
- intel_guc_ct_event_handler(&guc->ct);
+ if (guc->interrupts.enabled)
+ intel_guc_ct_event_handler(&guc->ct);
}
/* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */
@@ -466,4 +483,6 @@ void intel_guc_write_barrier(struct intel_guc *guc);
void intel_guc_dump_time_info(struct intel_guc *guc, struct drm_printer *p);
+int intel_guc_sched_disable_gucid_threshold_max(struct intel_guc *guc);
+
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 74cbe8eaf531..a7f737c4792e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -5,6 +5,7 @@
#include <linux/bsearch.h>
+#include "gem/i915_gem_lmem.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_mcr.h"
@@ -277,24 +278,16 @@ __mmio_reg_add(struct temp_regset *regset, struct guc_mmio_reg *reg)
return slot;
}
-#define GUC_REGSET_STEERING(group, instance) ( \
- FIELD_PREP(GUC_REGSET_STEERING_GROUP, (group)) | \
- FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, (instance)) | \
- GUC_REGSET_NEEDS_STEERING \
-)
-
static long __must_check guc_mmio_reg_add(struct intel_gt *gt,
struct temp_regset *regset,
- i915_reg_t reg, u32 flags)
+ u32 offset, u32 flags)
{
u32 count = regset->storage_used - (regset->registers - regset->storage);
- u32 offset = i915_mmio_reg_offset(reg);
struct guc_mmio_reg entry = {
.offset = offset,
.flags = flags,
};
struct guc_mmio_reg *slot;
- u8 group, inst;
/*
* The mmio list is built using separate lists within the driver.
@@ -306,17 +299,6 @@ static long __must_check guc_mmio_reg_add(struct intel_gt *gt,
sizeof(entry), guc_mmio_reg_cmp))
return 0;
- /*
- * The GuC doesn't have a default steering, so we need to explicitly
- * steer all registers that need steering. However, we do not keep track
- * of all the steering ranges, only of those that have a chance of using
- * a non-default steering from the i915 pov. Instead of adding such
- * tracking, it is easier to just program the default steering for all
- * regs that don't need a non-default one.
- */
- intel_gt_mcr_get_nonterminated_steering(gt, reg, &group, &inst);
- entry.flags |= GUC_REGSET_STEERING(group, inst);
-
slot = __mmio_reg_add(regset, &entry);
if (IS_ERR(slot))
return PTR_ERR(slot);
@@ -335,6 +317,38 @@ static long __must_check guc_mmio_reg_add(struct intel_gt *gt,
#define GUC_MMIO_REG_ADD(gt, regset, reg, masked) \
guc_mmio_reg_add(gt, \
regset, \
+ i915_mmio_reg_offset(reg), \
+ (masked) ? GUC_REGSET_MASKED : 0)
+
+#define GUC_REGSET_STEERING(group, instance) ( \
+ FIELD_PREP(GUC_REGSET_STEERING_GROUP, (group)) | \
+ FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, (instance)) | \
+ GUC_REGSET_NEEDS_STEERING \
+)
+
+static long __must_check guc_mcr_reg_add(struct intel_gt *gt,
+ struct temp_regset *regset,
+ i915_mcr_reg_t reg, u32 flags)
+{
+ u8 group, inst;
+
+ /*
+ * The GuC doesn't have a default steering, so we need to explicitly
+ * steer all registers that need steering. However, we do not keep track
+ * of all the steering ranges, only of those that have a chance of using
+ * a non-default steering from the i915 pov. Instead of adding such
+ * tracking, it is easier to just program the default steering for all
+ * regs that don't need a non-default one.
+ */
+ intel_gt_mcr_get_nonterminated_steering(gt, reg, &group, &inst);
+ flags |= GUC_REGSET_STEERING(group, inst);
+
+ return guc_mmio_reg_add(gt, regset, i915_mmio_reg_offset(reg), flags);
+}
+
+#define GUC_MCR_REG_ADD(gt, regset, reg, masked) \
+ guc_mcr_reg_add(gt, \
+ regset, \
(reg), \
(masked) ? GUC_REGSET_MASKED : 0)
@@ -372,8 +386,21 @@ static int guc_mmio_regset_init(struct temp_regset *regset,
false);
/* add in local MOCS registers */
- for (i = 0; i < GEN9_LNCFCMOCS_REG_COUNT; i++)
- ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false);
+ for (i = 0; i < LNCFCMOCS_REG_COUNT; i++)
+ if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50))
+ ret |= GUC_MCR_REG_ADD(gt, regset, XEHP_LNCFCMOCS(i), false);
+ else
+ ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false);
+
+ if (GRAPHICS_VER(engine->i915) >= 12) {
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL0, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL1, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL2, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL3, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL4, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL5, false);
+ ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL6, false);
+ }
return ret ? -1 : 0;
}
@@ -461,6 +488,11 @@ static void fill_engine_enable_masks(struct intel_gt *gt,
info_map_write(info_map, engine_enabled_masks[GUC_BLITTER_CLASS], BCS_MASK(gt));
info_map_write(info_map, engine_enabled_masks[GUC_VIDEO_CLASS], VDBOX_MASK(gt));
info_map_write(info_map, engine_enabled_masks[GUC_VIDEOENHANCE_CLASS], VEBOX_MASK(gt));
+
+ /* The GSC engine is an instance (6) of OTHER_CLASS */
+ if (gt->engine[GSC0])
+ info_map_write(info_map, engine_enabled_masks[GUC_GSC_OTHER_CLASS],
+ BIT(gt->engine[GSC0]->instance));
}
#define LR_HW_CONTEXT_SIZE (80 * sizeof(u32))
@@ -502,9 +534,6 @@ static int guc_prep_golden_context(struct intel_guc *guc)
}
for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) {
- if (engine_class == OTHER_CLASS)
- continue;
-
guc_class = engine_class_to_guc_class(engine_class);
if (!info_map_read(&info_map, engine_enabled_masks[guc_class]))
@@ -582,9 +611,6 @@ static void guc_init_golden_context(struct intel_guc *guc)
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) {
- if (engine_class == OTHER_CLASS)
- continue;
-
guc_class = engine_class_to_guc_class(engine_class);
if (!ads_blob_read(guc, system_info.engine_enabled_masks[guc_class]))
continue;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 8f1165146013..1c1b85073b4b 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -132,6 +132,11 @@ static const struct __guc_mmio_reg_descr xe_lpd_blt_inst_regs[] = {
COMMON_BASE_ENGINE_INSTANCE,
};
+/* XE_LPD - GSC Per-Engine-Instance */
+static const struct __guc_mmio_reg_descr xe_lpd_gsc_inst_regs[] = {
+ COMMON_BASE_ENGINE_INSTANCE,
+};
+
/* GEN9 - Global */
static const struct __guc_mmio_reg_descr default_global_regs[] = {
COMMON_BASE_GLOBAL,
@@ -165,16 +170,20 @@ static const struct __guc_mmio_reg_descr empty_regs_list[] = {
}
/* List of lists */
-static struct __guc_mmio_reg_descr_group default_lists[] = {
+static const struct __guc_mmio_reg_descr_group default_lists[] = {
MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
+ MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_COMPUTE_CLASS),
+ MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_COMPUTE_CLASS),
MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
+ MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_GSC_OTHER_CLASS),
+ MAKE_REGLIST(xe_lpd_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_GSC_OTHER_CLASS),
{}
};
@@ -182,12 +191,16 @@ static const struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
+ MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_COMPUTE_CLASS),
+ MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_COMPUTE_CLASS),
MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
+ MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_GSC_OTHER_CLASS),
+ MAKE_REGLIST(xe_lpd_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_GSC_OTHER_CLASS),
{}
};
@@ -240,19 +253,19 @@ static void guc_capture_free_extlists(struct __guc_mmio_reg_descr_group *reglist
struct __ext_steer_reg {
const char *name;
- i915_reg_t reg;
+ i915_mcr_reg_t reg;
};
static const struct __ext_steer_reg xe_extregs[] = {
- {"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
- {"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
+ {"GEN8_SAMPLER_INSTDONE", GEN8_SAMPLER_INSTDONE},
+ {"GEN8_ROW_INSTDONE", GEN8_ROW_INSTDONE}
};
static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
const struct __ext_steer_reg *extlist,
int slice_id, int subslice_id)
{
- ext->reg = extlist->reg;
+ ext->reg = _MMIO(i915_mmio_reg_offset(extlist->reg));
ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
ext->regname = extlist->name;
@@ -419,6 +432,46 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
return default_lists;
}
+static const char *
+__stringify_type(u32 type)
+{
+ switch (type) {
+ case GUC_CAPTURE_LIST_TYPE_GLOBAL:
+ return "Global";
+ case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
+ return "Class";
+ case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
+ return "Instance";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+static const char *
+__stringify_engclass(u32 class)
+{
+ switch (class) {
+ case GUC_RENDER_CLASS:
+ return "Render";
+ case GUC_VIDEO_CLASS:
+ return "Video";
+ case GUC_VIDEOENHANCE_CLASS:
+ return "VideoEnhance";
+ case GUC_BLITTER_CLASS:
+ return "Blitter";
+ case GUC_COMPUTE_CLASS:
+ return "Compute";
+ case GUC_GSC_OTHER_CLASS:
+ return "GSC-Other";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
static int
guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
struct guc_mmio_reg *ptr, u16 num_entries)
@@ -482,32 +535,55 @@ guc_cap_list_num_regs(struct intel_guc_state_capture *gc, u32 owner, u32 type, u
return num_regs;
}
-int
-intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
- size_t *size)
+static int
+guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
+ size_t *size, bool is_purpose_est)
{
struct intel_guc_state_capture *gc = guc->capture;
+ struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid];
int num_regs;
- if (!gc->reglists)
+ if (!gc->reglists) {
+ drm_warn(&i915->drm, "GuC-capture: No reglist on this device\n");
return -ENODEV;
+ }
if (cache->is_valid) {
*size = cache->size;
return cache->status;
}
+ if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
+ !guc_capture_get_one_list(gc->reglists, owner, type, classid)) {
+ if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
+ drm_warn(&i915->drm, "Missing GuC-Err-Cap reglist Global!\n");
+ else
+ drm_warn(&i915->drm, "Missing GuC-Err-Cap reglist %s(%u):%s(%u)!\n",
+ __stringify_type(type), type,
+ __stringify_engclass(classid), classid);
+ return -ENODATA;
+ }
+
num_regs = guc_cap_list_num_regs(gc, owner, type, classid);
+ /* intentional empty lists can exist depending on hw config */
if (!num_regs)
return -ENODATA;
- *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
- (num_regs * sizeof(struct guc_mmio_reg)));
+ if (size)
+ *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
+ (num_regs * sizeof(struct guc_mmio_reg)));
return 0;
}
+int
+intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
+ size_t *size)
+{
+ return guc_capture_getlistsize(guc, owner, type, classid, size, false);
+}
+
static void guc_capture_create_prealloc_nodes(struct intel_guc *guc);
int
@@ -606,7 +682,7 @@ guc_capture_output_min_size_est(struct intel_guc *guc)
struct intel_gt *gt = guc_to_gt(guc);
struct intel_engine_cs *engine;
enum intel_engine_id id;
- int worst_min_size = 0, num_regs = 0;
+ int worst_min_size = 0;
size_t tmp = 0;
if (!guc->capture)
@@ -627,21 +703,19 @@ guc_capture_output_min_size_est(struct intel_guc *guc)
worst_min_size += sizeof(struct guc_state_capture_group_header_t) +
(3 * sizeof(struct guc_state_capture_header_t));
- if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp))
- num_regs += tmp;
+ if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp, true))
+ worst_min_size += tmp;
- if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
- engine->class, &tmp)) {
- num_regs += tmp;
+ if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
+ engine->class, &tmp, true)) {
+ worst_min_size += tmp;
}
- if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
- engine->class, &tmp)) {
- num_regs += tmp;
+ if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
+ engine->class, &tmp, true)) {
+ worst_min_size += tmp;
}
}
- worst_min_size += (num_regs * sizeof(struct guc_mmio_reg));
-
return worst_min_size;
}
@@ -658,15 +732,23 @@ static void check_guc_capture_size(struct intel_guc *guc)
int spare_size = min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
u32 buffer_size = intel_guc_log_section_size_capture(&guc->log);
+ /*
+ * NOTE: min_size is much smaller than the capture region allocation (DG2: <80K vs 1MB)
+ * Additionally, its based on space needed to fit all engines getting reset at once
+ * within the same G2H handler task slot. This is very unlikely. However, if GuC really
+ * does run out of space for whatever reason, we will see an separate warning message
+ * when processing the G2H event capture-notification, search for:
+ * INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE.
+ */
if (min_size < 0)
drm_warn(&i915->drm, "Failed to calculate GuC error state capture buffer minimum size: %d!\n",
min_size);
else if (min_size > buffer_size)
- drm_warn(&i915->drm, "GuC error state capture buffer is too small: %d < %d\n",
+ drm_warn(&i915->drm, "GuC error state capture buffer maybe small: %d < %d\n",
buffer_size, min_size);
else if (spare_size > buffer_size)
- drm_notice(&i915->drm, "GuC error state capture buffer maybe too small: %d < %d (min = %d)\n",
- buffer_size, spare_size, min_size);
+ drm_dbg(&i915->drm, "GuC error state capture buffer lacks spare size: %d < %d (min = %d)\n",
+ buffer_size, spare_size, min_size);
}
/*
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c
index 25f09a420561..7269eb0bbedf 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c
@@ -71,12 +71,73 @@ static bool intel_eval_slpc_support(void *data)
return intel_guc_slpc_is_used(guc);
}
+static int guc_sched_disable_delay_ms_get(void *data, u64 *val)
+{
+ struct intel_guc *guc = data;
+
+ if (!intel_guc_submission_is_used(guc))
+ return -ENODEV;
+
+ *val = (u64)guc->submission_state.sched_disable_delay_ms;
+
+ return 0;
+}
+
+static int guc_sched_disable_delay_ms_set(void *data, u64 val)
+{
+ struct intel_guc *guc = data;
+
+ if (!intel_guc_submission_is_used(guc))
+ return -ENODEV;
+
+ /* clamp to a practical limit, 1 minute is reasonable for a longest delay */
+ guc->submission_state.sched_disable_delay_ms = min_t(u64, val, 60000);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(guc_sched_disable_delay_ms_fops,
+ guc_sched_disable_delay_ms_get,
+ guc_sched_disable_delay_ms_set, "%lld\n");
+
+static int guc_sched_disable_gucid_threshold_get(void *data, u64 *val)
+{
+ struct intel_guc *guc = data;
+
+ if (!intel_guc_submission_is_used(guc))
+ return -ENODEV;
+
+ *val = guc->submission_state.sched_disable_gucid_threshold;
+ return 0;
+}
+
+static int guc_sched_disable_gucid_threshold_set(void *data, u64 val)
+{
+ struct intel_guc *guc = data;
+
+ if (!intel_guc_submission_is_used(guc))
+ return -ENODEV;
+
+ if (val > intel_guc_sched_disable_gucid_threshold_max(guc))
+ guc->submission_state.sched_disable_gucid_threshold =
+ intel_guc_sched_disable_gucid_threshold_max(guc);
+ else
+ guc->submission_state.sched_disable_gucid_threshold = val;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(guc_sched_disable_gucid_threshold_fops,
+ guc_sched_disable_gucid_threshold_get,
+ guc_sched_disable_gucid_threshold_set, "%lld\n");
+
void intel_guc_debugfs_register(struct intel_guc *guc, struct dentry *root)
{
static const struct intel_gt_debugfs_file files[] = {
{ "guc_info", &guc_info_fops, NULL },
{ "guc_registered_contexts", &guc_registered_contexts_fops, NULL },
{ "guc_slpc_info", &guc_slpc_info_fops, &intel_eval_slpc_support},
+ { "guc_sched_disable_delay_ms", &guc_sched_disable_delay_ms_fops, NULL },
+ { "guc_sched_disable_gucid_threshold", &guc_sched_disable_gucid_threshold_fops,
+ NULL },
};
if (!intel_guc_is_supported(guc))
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
index a0372735cddb..5b86b2e286e0 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
@@ -10,12 +10,15 @@
*/
#include "gt/intel_gt.h"
+#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "intel_guc_fw.h"
#include "i915_drv.h"
-static void guc_prepare_xfer(struct intel_uncore *uncore)
+static void guc_prepare_xfer(struct intel_gt *gt)
{
+ struct intel_uncore *uncore = gt->uncore;
+
u32 shim_flags = GUC_ENABLE_READ_CACHE_LOGIC |
GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA |
GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA |
@@ -35,8 +38,9 @@ static void guc_prepare_xfer(struct intel_uncore *uncore)
if (GRAPHICS_VER(uncore->i915) == 9) {
/* DOP Clock Gating Enable for GuC clocks */
- intel_uncore_rmw(uncore, GEN7_MISCCPCTL,
- 0, GEN8_DOP_CLOCK_GATE_GUC_ENABLE);
+ intel_gt_mcr_multicast_write(gt, GEN8_MISCCPCTL,
+ GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
+ intel_gt_mcr_read_any(gt, GEN8_MISCCPCTL));
/* allows for 5us (in 10ns units) before GT can go to RC6 */
intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF);
@@ -168,7 +172,7 @@ int intel_guc_fw_upload(struct intel_guc *guc)
struct intel_uncore *uncore = gt->uncore;
int ret;
- guc_prepare_xfer(uncore);
+ guc_prepare_xfer(gt);
/*
* Note that GuC needs the CSS header plus uKernel code to be copied
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
index 323b055e5db9..4ae5fc2f6002 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
@@ -47,7 +47,8 @@
#define GUC_VIDEOENHANCE_CLASS 2
#define GUC_BLITTER_CLASS 3
#define GUC_COMPUTE_CLASS 4
-#define GUC_LAST_ENGINE_CLASS GUC_COMPUTE_CLASS
+#define GUC_GSC_OTHER_CLASS 5
+#define GUC_LAST_ENGINE_CLASS GUC_GSC_OTHER_CLASS
#define GUC_MAX_ENGINE_CLASSES 16
#define GUC_MAX_INSTANCES_PER_CLASS 32
@@ -169,6 +170,7 @@ static u8 engine_class_guc_class_map[] = {
[COPY_ENGINE_CLASS] = GUC_BLITTER_CLASS,
[VIDEO_DECODE_CLASS] = GUC_VIDEO_CLASS,
[VIDEO_ENHANCEMENT_CLASS] = GUC_VIDEOENHANCE_CLASS,
+ [OTHER_CLASS] = GUC_GSC_OTHER_CLASS,
[COMPUTE_CLASS] = GUC_COMPUTE_CLASS,
};
@@ -178,12 +180,13 @@ static u8 guc_class_engine_class_map[] = {
[GUC_VIDEO_CLASS] = VIDEO_DECODE_CLASS,
[GUC_VIDEOENHANCE_CLASS] = VIDEO_ENHANCEMENT_CLASS,
[GUC_COMPUTE_CLASS] = COMPUTE_CLASS,
+ [GUC_GSC_OTHER_CLASS] = OTHER_CLASS,
};
static inline u8 engine_class_to_guc_class(u8 class)
{
BUILD_BUG_ON(ARRAY_SIZE(engine_class_guc_class_map) != MAX_ENGINE_CLASS + 1);
- GEM_BUG_ON(class > MAX_ENGINE_CLASS || class == OTHER_CLASS);
+ GEM_BUG_ON(class > MAX_ENGINE_CLASS);
return engine_class_guc_class_map[class];
}
@@ -290,6 +293,25 @@ struct guc_update_context_policy {
struct guc_klv_generic_dw_t klv[GUC_CONTEXT_POLICIES_KLV_NUM_IDS];
} __packed;
+/* Format of the UPDATE_SCHEDULING_POLICIES H2G data packet */
+struct guc_update_scheduling_policy_header {
+ u32 action;
+} __packed;
+
+/*
+ * Can't dynmically allocate memory for the scheduling policy KLV because
+ * it will be sent from within the reset path. Need a fixed size lump on
+ * the stack instead :(.
+ *
+ * Currently, there is only one KLV defined, which has 1 word of KL + 2 words of V.
+ */
+#define MAX_SCHEDULING_POLICY_SIZE 3
+
+struct guc_update_scheduling_policy {
+ struct guc_update_scheduling_policy_header header;
+ u32 data[MAX_SCHEDULING_POLICY_SIZE];
+} __packed;
+
#define GUC_POWER_UNSPECIFIED 0
#define GUC_POWER_D0 1
#define GUC_POWER_D1 2
@@ -298,6 +320,9 @@ struct guc_update_context_policy {
/* Scheduling policy settings */
+#define GLOBAL_SCHEDULE_POLICY_RC_YIELD_DURATION 100 /* in ms */
+#define GLOBAL_SCHEDULE_POLICY_RC_YIELD_RATIO 50 /* in percent */
+
#define GLOBAL_POLICY_MAX_NUM_WI 15
/* Don't reset an engine upon preemption failure */
@@ -305,6 +330,27 @@ struct guc_update_context_policy {
#define GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US 500000
+/*
+ * GuC converts the timeout to clock ticks internally. Different platforms have
+ * different GuC clocks. Thus, the maximum value before overflow is platform
+ * dependent. Current worst case scenario is about 110s. So, the spec says to
+ * limit to 100s to be safe.
+ */
+#define GUC_POLICY_MAX_EXEC_QUANTUM_US (100 * 1000 * 1000UL)
+#define GUC_POLICY_MAX_PREEMPT_TIMEOUT_US (100 * 1000 * 1000UL)
+
+static inline u32 guc_policy_max_exec_quantum_ms(void)
+{
+ BUILD_BUG_ON(GUC_POLICY_MAX_EXEC_QUANTUM_US >= UINT_MAX);
+ return GUC_POLICY_MAX_EXEC_QUANTUM_US / 1000;
+}
+
+static inline u32 guc_policy_max_preempt_timeout_ms(void)
+{
+ BUILD_BUG_ON(GUC_POLICY_MAX_PREEMPT_TIMEOUT_US >= UINT_MAX);
+ return GUC_POLICY_MAX_PREEMPT_TIMEOUT_US / 1000;
+}
+
struct guc_policies {
u32 submission_queue_depth[GUC_MAX_ENGINE_CLASSES];
/* In micro seconds. How much time to allow before DPC processing is
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index 55d3ef93e86f..68331c538b0a 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -16,15 +16,15 @@
#if defined(CONFIG_DRM_I915_DEBUG_GUC)
#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_2M
#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_16M
-#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_4M
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M
#elif defined(CONFIG_DRM_I915_DEBUG_GEM)
#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_1M
#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_2M
-#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_4M
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M
#else
#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_8K
#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_64K
-#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_2M
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M
#endif
static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c
index 8f8dd05835c5..b5855091cf6a 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c
@@ -11,9 +11,20 @@
static bool __guc_rc_supported(struct intel_guc *guc)
{
+ struct intel_gt *gt = guc_to_gt(guc);
+
+ /*
+ * Wa_14017073508: mtl
+ * Do not enable gucrc to avoid additional interrupts which
+ * may disrupt pcode wa.
+ */
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0) &&
+ gt->type == GT_MEDIA)
+ return false;
+
/* GuC RC is unavailable for pre-Gen12 */
return guc->submission_supported &&
- GRAPHICS_VER(guc_to_gt(guc)->i915) >= 12;
+ GRAPHICS_VER(gt->i915) >= 12;
}
static bool __guc_rc_selected(struct intel_guc *guc)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
index a7092f711e9c..9915de32e894 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h
@@ -36,6 +36,7 @@
#define SOFT_SCRATCH_COUNT 16
#define GEN11_SOFT_SCRATCH(n) _MMIO(0x190240 + (n) * 4)
+#define MEDIA_SOFT_SCRATCH(n) _MMIO(0x190310 + (n) * 4)
#define GEN11_SOFT_SCRATCH_COUNT 4
#define UOS_RSA_SCRATCH(i) _MMIO(0xc200 + (i) * 4)
@@ -101,6 +102,7 @@
#define GUC_SEND_INTERRUPT _MMIO(0xc4c8)
#define GUC_SEND_TRIGGER (1<<0)
#define GEN11_GUC_HOST_INTERRUPT _MMIO(0x1901f0)
+#define MEDIA_GUC_HOST_INTERRUPT _MMIO(0x190304)
#define GEN12_GUC_SEM_INTR_ENABLES _MMIO(0xc71c)
#define GUC_SEM_INTR_ROUTE_TO_GUC BIT(31)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
index fdd895f73f9f..63464933cbce 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
@@ -137,6 +137,17 @@ static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value)
return ret > 0 ? -EPROTO : ret;
}
+static int guc_action_slpc_unset_param(struct intel_guc *guc, u8 id)
+{
+ u32 request[] = {
+ GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,
+ SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1),
+ id,
+ };
+
+ return intel_guc_send(guc, request, ARRAY_SIZE(request));
+}
+
static bool slpc_is_running(struct intel_guc_slpc *slpc)
{
return slpc_get_state(slpc) == SLPC_GLOBAL_STATE_RUNNING;
@@ -190,6 +201,15 @@ static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value)
return ret;
}
+static int slpc_unset_param(struct intel_guc_slpc *slpc, u8 id)
+{
+ struct intel_guc *guc = slpc_to_guc(slpc);
+
+ GEM_BUG_ON(id >= SLPC_MAX_PARAM);
+
+ return guc_action_slpc_unset_param(guc, id);
+}
+
static int slpc_force_min_freq(struct intel_guc_slpc *slpc, u32 freq)
{
struct drm_i915_private *i915 = slpc_to_i915(slpc);
@@ -263,6 +283,7 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc)
slpc->max_freq_softlimit = 0;
slpc->min_freq_softlimit = 0;
+ slpc->min_is_rpmax = false;
slpc->boost_freq = 0;
atomic_set(&slpc->num_waiters, 0);
@@ -588,6 +609,39 @@ static int slpc_set_softlimits(struct intel_guc_slpc *slpc)
return 0;
}
+static bool is_slpc_min_freq_rpmax(struct intel_guc_slpc *slpc)
+{
+ struct drm_i915_private *i915 = slpc_to_i915(slpc);
+ int slpc_min_freq;
+ int ret;
+
+ ret = intel_guc_slpc_get_min_freq(slpc, &slpc_min_freq);
+ if (ret) {
+ drm_err(&i915->drm,
+ "Failed to get min freq: (%d)\n",
+ ret);
+ return false;
+ }
+
+ if (slpc_min_freq == SLPC_MAX_FREQ_MHZ)
+ return true;
+ else
+ return false;
+}
+
+static void update_server_min_softlimit(struct intel_guc_slpc *slpc)
+{
+ /* For server parts, SLPC min will be at RPMax.
+ * Use min softlimit to clamp it to RP0 instead.
+ */
+ if (!slpc->min_freq_softlimit &&
+ is_slpc_min_freq_rpmax(slpc)) {
+ slpc->min_is_rpmax = true;
+ slpc->min_freq_softlimit = slpc->rp0_freq;
+ (slpc_to_gt(slpc))->defaults.min_freq = slpc->min_freq_softlimit;
+ }
+}
+
static int slpc_use_fused_rp0(struct intel_guc_slpc *slpc)
{
/* Force SLPC to used platform rp0 */
@@ -610,6 +664,52 @@ static void slpc_get_rp_values(struct intel_guc_slpc *slpc)
slpc->boost_freq = slpc->rp0_freq;
}
+/**
+ * intel_guc_slpc_override_gucrc_mode() - override GUCRC mode
+ * @slpc: pointer to intel_guc_slpc.
+ * @mode: new value of the mode.
+ *
+ * This function will override the GUCRC mode.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode)
+{
+ int ret;
+ struct drm_i915_private *i915 = slpc_to_i915(slpc);
+ intel_wakeref_t wakeref;
+
+ if (mode >= SLPC_GUCRC_MODE_MAX)
+ return -EINVAL;
+
+ with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
+ ret = slpc_set_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE, mode);
+ if (ret)
+ drm_err(&i915->drm,
+ "Override gucrc mode %d failed %d\n",
+ mode, ret);
+ }
+
+ return ret;
+}
+
+int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc)
+{
+ struct drm_i915_private *i915 = slpc_to_i915(slpc);
+ intel_wakeref_t wakeref;
+ int ret = 0;
+
+ with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
+ ret = slpc_unset_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE);
+ if (ret)
+ drm_err(&i915->drm,
+ "Unsetting gucrc mode failed %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
/*
* intel_guc_slpc_enable() - Start SLPC
* @slpc: pointer to intel_guc_slpc.
@@ -647,6 +747,9 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
slpc_get_rp_values(slpc);
+ /* Handle the case where min=max=RPmax */
+ update_server_min_softlimit(slpc);
+
/* Set SLPC max limit to RP0 */
ret = slpc_use_fused_rp0(slpc);
if (unlikely(ret)) {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h
index 82a98f78f96c..17ed515f6a85 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h
@@ -9,6 +9,8 @@
#include "intel_guc_submission.h"
#include "intel_guc_slpc_types.h"
+#define SLPC_MAX_FREQ_MHZ 4250
+
struct intel_gt;
struct drm_printer;
@@ -42,5 +44,7 @@ int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val);
void intel_guc_pm_intrmsk_enable(struct intel_gt *gt);
void intel_guc_slpc_boost(struct intel_guc_slpc *slpc);
void intel_guc_slpc_dec_waiters(struct intel_guc_slpc *slpc);
+int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc);
+int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode);
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h
index 73d208123528..a6ef53b04e04 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h
@@ -19,6 +19,9 @@ struct intel_guc_slpc {
bool supported;
bool selected;
+ /* Indicates this is a server part */
+ bool min_is_rpmax;
+
/* platform frequency limits */
u32 min_freq;
u32 rp0_freq;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index 1db59eeb34db..0a42f1807f52 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -6,6 +6,7 @@
#include <linux/circ_buf.h>
#include "gem/i915_gem_context.h"
+#include "gem/i915_gem_lmem.h"
#include "gt/gen8_engine_cs.h"
#include "gt/intel_breadcrumbs.h"
#include "gt/intel_context.h"
@@ -29,6 +30,7 @@
#include "intel_guc_submission.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_trace.h"
/**
@@ -65,7 +67,13 @@
* corresponding G2H returns indicating the scheduling disable operation has
* completed it is safe to unpin the context. While a disable is in flight it
* isn't safe to resubmit the context so a fence is used to stall all future
- * requests of that context until the G2H is returned.
+ * requests of that context until the G2H is returned. Because this interaction
+ * with the GuC takes a non-zero amount of time we delay the disabling of
+ * scheduling after the pin count goes to zero by a configurable period of time
+ * (see SCHED_DISABLE_DELAY_MS). The thought is this gives the user a window of
+ * time to resubmit something on the context before doing this costly operation.
+ * This delay is only done if the context isn't closed and the guc_id usage is
+ * less than a threshold (see NUM_SCHED_DISABLE_GUC_IDS_THRESHOLD).
*
* Context deregistration:
* Before a context can be destroyed or if we steal its guc_id we must
@@ -163,7 +171,8 @@ guc_create_parallel(struct intel_engine_cs **engines,
#define SCHED_STATE_PENDING_ENABLE BIT(5)
#define SCHED_STATE_REGISTERED BIT(6)
#define SCHED_STATE_POLICY_REQUIRED BIT(7)
-#define SCHED_STATE_BLOCKED_SHIFT 8
+#define SCHED_STATE_CLOSED BIT(8)
+#define SCHED_STATE_BLOCKED_SHIFT 9
#define SCHED_STATE_BLOCKED BIT(SCHED_STATE_BLOCKED_SHIFT)
#define SCHED_STATE_BLOCKED_MASK (0xfff << SCHED_STATE_BLOCKED_SHIFT)
@@ -173,12 +182,20 @@ static inline void init_sched_state(struct intel_context *ce)
ce->guc_state.sched_state &= SCHED_STATE_BLOCKED_MASK;
}
+/*
+ * Kernel contexts can have SCHED_STATE_REGISTERED after suspend.
+ * A context close can race with the submission path, so SCHED_STATE_CLOSED
+ * can be set immediately before we try to register.
+ */
+#define SCHED_STATE_VALID_INIT \
+ (SCHED_STATE_BLOCKED_MASK | \
+ SCHED_STATE_CLOSED | \
+ SCHED_STATE_REGISTERED)
+
__maybe_unused
static bool sched_state_is_init(struct intel_context *ce)
{
- /* Kernel contexts can have SCHED_STATE_REGISTERED after suspend. */
- return !(ce->guc_state.sched_state &
- ~(SCHED_STATE_BLOCKED_MASK | SCHED_STATE_REGISTERED));
+ return !(ce->guc_state.sched_state & ~SCHED_STATE_VALID_INIT);
}
static inline bool
@@ -319,6 +336,17 @@ static inline void clr_context_policy_required(struct intel_context *ce)
ce->guc_state.sched_state &= ~SCHED_STATE_POLICY_REQUIRED;
}
+static inline bool context_close_done(struct intel_context *ce)
+{
+ return ce->guc_state.sched_state & SCHED_STATE_CLOSED;
+}
+
+static inline void set_context_close_done(struct intel_context *ce)
+{
+ lockdep_assert_held(&ce->guc_state.lock);
+ ce->guc_state.sched_state |= SCHED_STATE_CLOSED;
+}
+
static inline u32 context_blocked(struct intel_context *ce)
{
return (ce->guc_state.sched_state & SCHED_STATE_BLOCKED_MASK) >>
@@ -343,25 +371,6 @@ static inline void decr_context_blocked(struct intel_context *ce)
ce->guc_state.sched_state -= SCHED_STATE_BLOCKED;
}
-static inline bool context_has_committed_requests(struct intel_context *ce)
-{
- return !!ce->guc_state.number_committed_requests;
-}
-
-static inline void incr_context_committed_requests(struct intel_context *ce)
-{
- lockdep_assert_held(&ce->guc_state.lock);
- ++ce->guc_state.number_committed_requests;
- GEM_BUG_ON(ce->guc_state.number_committed_requests < 0);
-}
-
-static inline void decr_context_committed_requests(struct intel_context *ce)
-{
- lockdep_assert_held(&ce->guc_state.lock);
- --ce->guc_state.number_committed_requests;
- GEM_BUG_ON(ce->guc_state.number_committed_requests < 0);
-}
-
static struct intel_context *
request_to_scheduling_context(struct i915_request *rq)
{
@@ -1067,6 +1076,12 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc)
xa_unlock(&guc->context_lookup);
+ if (test_bit(CONTEXT_GUC_INIT, &ce->flags) &&
+ (cancel_delayed_work(&ce->guc_state.sched_disable_delay_work))) {
+ /* successful cancel so jump straight to close it */
+ intel_context_sched_disable_unpin(ce);
+ }
+
spin_lock(&ce->guc_state.lock);
/*
@@ -1387,7 +1402,9 @@ static void guc_timestamp_ping(struct work_struct *wrk)
/*
* Synchronize with gt reset to make sure the worker does not
- * corrupt the engine/guc stats.
+ * corrupt the engine/guc stats. NB: can't actually block waiting
+ * for a reset to complete as the reset requires flushing out
+ * this worker thread if started. So waiting would deadlock.
*/
ret = intel_gt_reset_trylock(gt, &srcu);
if (ret)
@@ -1994,6 +2011,9 @@ static int new_guc_id(struct intel_guc *guc, struct intel_context *ce)
if (unlikely(ret < 0))
return ret;
+ if (!intel_context_is_parent(ce))
+ ++guc->submission_state.guc_ids_in_use;
+
ce->guc_id.id = ret;
return 0;
}
@@ -2003,14 +2023,16 @@ static void __release_guc_id(struct intel_guc *guc, struct intel_context *ce)
GEM_BUG_ON(intel_context_is_child(ce));
if (!context_guc_id_invalid(ce)) {
- if (intel_context_is_parent(ce))
+ if (intel_context_is_parent(ce)) {
bitmap_release_region(guc->submission_state.guc_ids_bitmap,
ce->guc_id.id,
order_base_2(ce->parallel.number_children
+ 1));
- else
+ } else {
+ --guc->submission_state.guc_ids_in_use;
ida_simple_remove(&guc->submission_state.guc_ids,
ce->guc_id.id);
+ }
clr_ctx_id_mapping(guc, ce->guc_id.id);
set_context_guc_id_invalid(ce);
}
@@ -2429,6 +2451,10 @@ static int guc_context_policy_init_v70(struct intel_context *ce, bool loop)
int ret;
/* NB: For both of these, zero means disabled. */
+ GEM_BUG_ON(overflows_type(engine->props.timeslice_duration_ms * 1000,
+ execution_quantum));
+ GEM_BUG_ON(overflows_type(engine->props.preempt_timeout_ms * 1000,
+ preemption_timeout));
execution_quantum = engine->props.timeslice_duration_ms * 1000;
preemption_timeout = engine->props.preempt_timeout_ms * 1000;
@@ -2462,6 +2488,10 @@ static void guc_context_policy_init_v69(struct intel_engine_cs *engine,
desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69;
/* NB: For both of these, zero means disabled. */
+ GEM_BUG_ON(overflows_type(engine->props.timeslice_duration_ms * 1000,
+ desc->execution_quantum));
+ GEM_BUG_ON(overflows_type(engine->props.preempt_timeout_ms * 1000,
+ desc->preemption_timeout));
desc->execution_quantum = engine->props.timeslice_duration_ms * 1000;
desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000;
}
@@ -2998,41 +3028,104 @@ guc_context_revoke(struct intel_context *ce, struct i915_request *rq,
}
}
-static void guc_context_sched_disable(struct intel_context *ce)
+static void do_sched_disable(struct intel_guc *guc, struct intel_context *ce,
+ unsigned long flags)
+ __releases(ce->guc_state.lock)
{
- struct intel_guc *guc = ce_to_guc(ce);
- unsigned long flags;
struct intel_runtime_pm *runtime_pm = &ce->engine->gt->i915->runtime_pm;
intel_wakeref_t wakeref;
u16 guc_id;
+ lockdep_assert_held(&ce->guc_state.lock);
+ guc_id = prep_context_pending_disable(ce);
+
+ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+
+ with_intel_runtime_pm(runtime_pm, wakeref)
+ __guc_context_sched_disable(guc, ce, guc_id);
+}
+
+static bool bypass_sched_disable(struct intel_guc *guc,
+ struct intel_context *ce)
+{
+ lockdep_assert_held(&ce->guc_state.lock);
GEM_BUG_ON(intel_context_is_child(ce));
+ if (submission_disabled(guc) || context_guc_id_invalid(ce) ||
+ !ctx_id_mapped(guc, ce->guc_id.id)) {
+ clr_context_enabled(ce);
+ return true;
+ }
+
+ return !context_enabled(ce);
+}
+
+static void __delay_sched_disable(struct work_struct *wrk)
+{
+ struct intel_context *ce =
+ container_of(wrk, typeof(*ce), guc_state.sched_disable_delay_work.work);
+ struct intel_guc *guc = ce_to_guc(ce);
+ unsigned long flags;
+
spin_lock_irqsave(&ce->guc_state.lock, flags);
+ if (bypass_sched_disable(guc, ce)) {
+ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+ intel_context_sched_disable_unpin(ce);
+ } else {
+ do_sched_disable(guc, ce, flags);
+ }
+}
+
+static bool guc_id_pressure(struct intel_guc *guc, struct intel_context *ce)
+{
/*
- * We have to check if the context has been disabled by another thread,
- * check if submssion has been disabled to seal a race with reset and
- * finally check if any more requests have been committed to the
- * context ensursing that a request doesn't slip through the
- * 'context_pending_disable' fence.
+ * parent contexts are perma-pinned, if we are unpinning do schedule
+ * disable immediately.
*/
- if (unlikely(!context_enabled(ce) || submission_disabled(guc) ||
- context_has_committed_requests(ce))) {
- clr_context_enabled(ce);
+ if (intel_context_is_parent(ce))
+ return true;
+
+ /*
+ * If we are beyond the threshold for avail guc_ids, do schedule disable immediately.
+ */
+ return guc->submission_state.guc_ids_in_use >
+ guc->submission_state.sched_disable_gucid_threshold;
+}
+
+static void guc_context_sched_disable(struct intel_context *ce)
+{
+ struct intel_guc *guc = ce_to_guc(ce);
+ u64 delay = guc->submission_state.sched_disable_delay_ms;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ce->guc_state.lock, flags);
+
+ if (bypass_sched_disable(guc, ce)) {
+ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+ intel_context_sched_disable_unpin(ce);
+ } else if (!intel_context_is_closed(ce) && !guc_id_pressure(guc, ce) &&
+ delay) {
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
- goto unpin;
+ mod_delayed_work(system_unbound_wq,
+ &ce->guc_state.sched_disable_delay_work,
+ msecs_to_jiffies(delay));
+ } else {
+ do_sched_disable(guc, ce, flags);
}
- guc_id = prep_context_pending_disable(ce);
+}
- spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+static void guc_context_close(struct intel_context *ce)
+{
+ unsigned long flags;
- with_intel_runtime_pm(runtime_pm, wakeref)
- __guc_context_sched_disable(guc, ce, guc_id);
+ if (test_bit(CONTEXT_GUC_INIT, &ce->flags) &&
+ cancel_delayed_work(&ce->guc_state.sched_disable_delay_work))
+ __delay_sched_disable(&ce->guc_state.sched_disable_delay_work.work);
- return;
-unpin:
- intel_context_sched_disable_unpin(ce);
+ spin_lock_irqsave(&ce->guc_state.lock, flags);
+ set_context_close_done(ce);
+ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
}
static inline void guc_lrc_desc_unpin(struct intel_context *ce)
@@ -3071,7 +3164,6 @@ static void __guc_context_destroy(struct intel_context *ce)
ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_HIGH] ||
ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_KMD_NORMAL] ||
ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_NORMAL]);
- GEM_BUG_ON(ce->guc_state.number_committed_requests);
lrc_fini(ce);
intel_context_fini(ce);
@@ -3340,8 +3432,6 @@ static void remove_from_context(struct i915_request *rq)
guc_prio_fini(rq, ce);
- decr_context_committed_requests(ce);
-
spin_unlock_irq(&ce->guc_state.lock);
atomic_dec(&ce->guc_id.ref);
@@ -3351,6 +3441,8 @@ static void remove_from_context(struct i915_request *rq)
static const struct intel_context_ops guc_context_ops = {
.alloc = guc_context_alloc,
+ .close = guc_context_close,
+
.pre_pin = guc_context_pre_pin,
.pin = guc_context_pin,
.unpin = guc_context_unpin,
@@ -3433,6 +3525,10 @@ static void guc_context_init(struct intel_context *ce)
rcu_read_unlock();
ce->guc_state.prio = map_i915_prio_to_guc_prio(prio);
+
+ INIT_DELAYED_WORK(&ce->guc_state.sched_disable_delay_work,
+ __delay_sched_disable);
+
set_bit(CONTEXT_GUC_INIT, &ce->flags);
}
@@ -3471,6 +3567,26 @@ static int guc_request_alloc(struct i915_request *rq)
guc_context_init(ce);
/*
+ * If the context gets closed while the execbuf is ongoing, the context
+ * close code will race with the below code to cancel the delayed work.
+ * If the context close wins the race and cancels the work, it will
+ * immediately call the sched disable (see guc_context_close), so there
+ * is a chance we can get past this check while the sched_disable code
+ * is being executed. To make sure that code completes before we check
+ * the status further down, we wait for the close process to complete.
+ * Else, this code path could send a request down thinking that the
+ * context is still in a schedule-enable mode while the GuC ends up
+ * dropping the request completely because the disable did go from the
+ * context_close path right to GuC just prior. In the event the CT is
+ * full, we could potentially need to wait up to 1.5 seconds.
+ */
+ if (cancel_delayed_work_sync(&ce->guc_state.sched_disable_delay_work))
+ intel_context_sched_disable_unpin(ce);
+ else if (intel_context_is_closed(ce))
+ if (wait_for(context_close_done(ce), 1500))
+ drm_warn(&guc_to_gt(guc)->i915->drm,
+ "timed out waiting on context sched close before realloc\n");
+ /*
* Call pin_guc_id here rather than in the pinning step as with
* dma_resv, contexts can be repeatedly pinned / unpinned trashing the
* guc_id and creating horrible race conditions. This is especially bad
@@ -3524,7 +3640,6 @@ out:
list_add_tail(&rq->guc_fence_link, &ce->guc_state.fences);
}
- incr_context_committed_requests(ce);
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
return 0;
@@ -3600,6 +3715,8 @@ static int guc_virtual_context_alloc(struct intel_context *ce)
static const struct intel_context_ops virtual_guc_context_ops = {
.alloc = guc_virtual_context_alloc,
+ .close = guc_context_close,
+
.pre_pin = guc_virtual_context_pre_pin,
.pin = guc_virtual_context_pin,
.unpin = guc_virtual_context_unpin,
@@ -3689,6 +3806,8 @@ static void guc_child_context_destroy(struct kref *kref)
static const struct intel_context_ops virtual_parent_context_ops = {
.alloc = guc_virtual_context_alloc,
+ .close = guc_context_close,
+
.pre_pin = guc_context_pre_pin,
.pin = guc_parent_context_pin,
.unpin = guc_parent_context_unpin,
@@ -3995,6 +4114,9 @@ static inline void guc_kernel_context_pin(struct intel_guc *guc,
if (context_guc_id_invalid(ce))
pin_guc_id(guc, ce);
+ if (!test_bit(CONTEXT_GUC_INIT, &ce->flags))
+ guc_context_init(ce);
+
try_context_registration(ce, true);
}
@@ -4093,7 +4215,7 @@ static void guc_default_vfuncs(struct intel_engine_cs *engine)
engine->emit_bb_start = gen8_emit_bb_start;
if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50))
- engine->emit_bb_start = gen125_emit_bb_start;
+ engine->emit_bb_start = xehp_emit_bb_start;
}
static void rcs_submission_override(struct intel_engine_cs *engine)
@@ -4177,6 +4299,98 @@ int intel_guc_submission_setup(struct intel_engine_cs *engine)
return 0;
}
+struct scheduling_policy {
+ /* internal data */
+ u32 max_words, num_words;
+ u32 count;
+ /* API data */
+ struct guc_update_scheduling_policy h2g;
+};
+
+static u32 __guc_scheduling_policy_action_size(struct scheduling_policy *policy)
+{
+ u32 *start = (void *)&policy->h2g;
+ u32 *end = policy->h2g.data + policy->num_words;
+ size_t delta = end - start;
+
+ return delta;
+}
+
+static struct scheduling_policy *__guc_scheduling_policy_start_klv(struct scheduling_policy *policy)
+{
+ policy->h2g.header.action = INTEL_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV;
+ policy->max_words = ARRAY_SIZE(policy->h2g.data);
+ policy->num_words = 0;
+ policy->count = 0;
+
+ return policy;
+}
+
+static void __guc_scheduling_policy_add_klv(struct scheduling_policy *policy,
+ u32 action, u32 *data, u32 len)
+{
+ u32 *klv_ptr = policy->h2g.data + policy->num_words;
+
+ GEM_BUG_ON((policy->num_words + 1 + len) > policy->max_words);
+ *(klv_ptr++) = FIELD_PREP(GUC_KLV_0_KEY, action) |
+ FIELD_PREP(GUC_KLV_0_LEN, len);
+ memcpy(klv_ptr, data, sizeof(u32) * len);
+ policy->num_words += 1 + len;
+ policy->count++;
+}
+
+static int __guc_action_set_scheduling_policies(struct intel_guc *guc,
+ struct scheduling_policy *policy)
+{
+ int ret;
+
+ ret = intel_guc_send(guc, (u32 *)&policy->h2g,
+ __guc_scheduling_policy_action_size(policy));
+ if (ret < 0)
+ return ret;
+
+ if (ret != policy->count) {
+ drm_warn(&guc_to_gt(guc)->i915->drm, "GuC global scheduler policy processed %d of %d KLVs!",
+ ret, policy->count);
+ if (ret > policy->count)
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static int guc_init_global_schedule_policy(struct intel_guc *guc)
+{
+ struct scheduling_policy policy;
+ struct intel_gt *gt = guc_to_gt(guc);
+ intel_wakeref_t wakeref;
+ int ret = 0;
+
+ if (GET_UC_VER(guc) < MAKE_UC_VER(70, 3, 0))
+ return 0;
+
+ __guc_scheduling_policy_start_klv(&policy);
+
+ with_intel_runtime_pm(&gt->i915->runtime_pm, wakeref) {
+ u32 yield[] = {
+ GLOBAL_SCHEDULE_POLICY_RC_YIELD_DURATION,
+ GLOBAL_SCHEDULE_POLICY_RC_YIELD_RATIO,
+ };
+
+ __guc_scheduling_policy_add_klv(&policy,
+ GUC_SCHEDULING_POLICIES_KLV_ID_RENDER_COMPUTE_YIELD,
+ yield, ARRAY_SIZE(yield));
+
+ ret = __guc_action_set_scheduling_policies(guc, &policy);
+ if (ret)
+ i915_probe_error(gt->i915,
+ "Failed to configure global scheduling policies: %pe!\n",
+ ERR_PTR(ret));
+ }
+
+ return ret;
+}
+
void intel_guc_submission_enable(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
@@ -4189,6 +4403,7 @@ void intel_guc_submission_enable(struct intel_guc *guc)
guc_init_lrc_mapping(guc);
guc_init_engine_stats(guc);
+ guc_init_global_schedule_policy(guc);
}
void intel_guc_submission_disable(struct intel_guc *guc)
@@ -4219,6 +4434,26 @@ static bool __guc_submission_selected(struct intel_guc *guc)
return i915->params.enable_guc & ENABLE_GUC_SUBMISSION;
}
+int intel_guc_sched_disable_gucid_threshold_max(struct intel_guc *guc)
+{
+ return guc->submission_state.num_guc_ids - NUMBER_MULTI_LRC_GUC_ID(guc);
+}
+
+/*
+ * This default value of 33 milisecs (+1 milisec round up) ensures 30fps or higher
+ * workloads are able to enjoy the latency reduction when delaying the schedule-disable
+ * operation. This matches the 30fps game-render + encode (real world) workload this
+ * knob was tested against.
+ */
+#define SCHED_DISABLE_DELAY_MS 34
+
+/*
+ * A threshold of 75% is a reasonable starting point considering that real world apps
+ * generally don't get anywhere near this.
+ */
+#define NUM_SCHED_DISABLE_GUCIDS_DEFAULT_THRESHOLD(__guc) \
+ (((intel_guc_sched_disable_gucid_threshold_max(guc)) * 3) / 4)
+
void intel_guc_submission_init_early(struct intel_guc *guc)
{
xa_init_flags(&guc->context_lookup, XA_FLAGS_LOCK_IRQ);
@@ -4235,7 +4470,10 @@ void intel_guc_submission_init_early(struct intel_guc *guc)
spin_lock_init(&guc->timestamp.lock);
INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping);
+ guc->submission_state.sched_disable_delay_ms = SCHED_DISABLE_DELAY_MS;
guc->submission_state.num_guc_ids = GUC_MAX_CONTEXT_ID;
+ guc->submission_state.sched_disable_gucid_threshold =
+ NUM_SCHED_DISABLE_GUCIDS_DEFAULT_THRESHOLD(guc);
guc->submission_supported = __guc_submission_supported(guc);
guc->submission_selected = __guc_submission_selected(guc);
}
@@ -4669,7 +4907,7 @@ void intel_guc_submission_print_info(struct intel_guc *guc,
drm_printf(p, "GuC Number Outstanding Submission G2H: %u\n",
atomic_read(&guc->outstanding_submission_g2h));
- drm_printf(p, "GuC tasklet count: %u\n\n",
+ drm_printf(p, "GuC tasklet count: %u\n",
atomic_read(&sched_engine->tasklet.count));
spin_lock_irqsave(&sched_engine->lock, flags);
@@ -4717,7 +4955,7 @@ static inline void guc_log_context(struct drm_printer *p,
atomic_read(&ce->pin_count));
drm_printf(p, "\t\tGuC ID Ref Count: %u\n",
atomic_read(&ce->guc_id.ref));
- drm_printf(p, "\t\tSchedule State: 0x%x\n\n",
+ drm_printf(p, "\t\tSchedule State: 0x%x\n",
ce->guc_state.sched_state);
}
@@ -4746,7 +4984,7 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc,
READ_ONCE(*ce->parallel.guc.wq_head));
drm_printf(p, "\t\tWQI Tail: %u\n",
READ_ONCE(*ce->parallel.guc.wq_tail));
- drm_printf(p, "\t\tWQI Status: %u\n\n",
+ drm_printf(p, "\t\tWQI Status: %u\n",
READ_ONCE(*ce->parallel.guc.wq_status));
}
@@ -4754,7 +4992,7 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc,
emit_bb_start_parent_no_preempt_mid_batch) {
u8 i;
- drm_printf(p, "\t\tChildren Go: %u\n\n",
+ drm_printf(p, "\t\tChildren Go: %u\n",
get_children_go_value(ce));
for (i = 0; i < ce->parallel.number_children; ++i)
drm_printf(p, "\t\tChildren Join: %u\n",
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c
index 3bb8838e325a..410905da8e97 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c
@@ -10,6 +10,9 @@
#include "intel_huc.h"
#include "i915_drv.h"
+#include <linux/device/bus.h>
+#include <linux/mei_aux.h>
+
/**
* DOC: HuC
*
@@ -42,12 +45,240 @@
* HuC-specific commands.
*/
+/*
+ * MEI-GSC load is an async process. The probing of the exposed aux device
+ * (see intel_gsc.c) usually happens a few seconds after i915 probe, depending
+ * on when the kernel schedules it. Unless something goes terribly wrong, we're
+ * guaranteed for this to happen during boot, so the big timeout is a safety net
+ * that we never expect to need.
+ * MEI-PXP + HuC load usually takes ~300ms, but if the GSC needs to be resumed
+ * and/or reset, this can take longer. Note that the kernel might schedule
+ * other work between the i915 init/resume and the MEI one, which can add to
+ * the delay.
+ */
+#define GSC_INIT_TIMEOUT_MS 10000
+#define PXP_INIT_TIMEOUT_MS 5000
+
+static int sw_fence_dummy_notify(struct i915_sw_fence *sf,
+ enum i915_sw_fence_notify state)
+{
+ return NOTIFY_DONE;
+}
+
+static void __delayed_huc_load_complete(struct intel_huc *huc)
+{
+ if (!i915_sw_fence_done(&huc->delayed_load.fence))
+ i915_sw_fence_complete(&huc->delayed_load.fence);
+}
+
+static void delayed_huc_load_complete(struct intel_huc *huc)
+{
+ hrtimer_cancel(&huc->delayed_load.timer);
+ __delayed_huc_load_complete(huc);
+}
+
+static void __gsc_init_error(struct intel_huc *huc)
+{
+ huc->delayed_load.status = INTEL_HUC_DELAYED_LOAD_ERROR;
+ __delayed_huc_load_complete(huc);
+}
+
+static void gsc_init_error(struct intel_huc *huc)
+{
+ hrtimer_cancel(&huc->delayed_load.timer);
+ __gsc_init_error(huc);
+}
+
+static void gsc_init_done(struct intel_huc *huc)
+{
+ hrtimer_cancel(&huc->delayed_load.timer);
+
+ /* MEI-GSC init is done, now we wait for MEI-PXP to bind */
+ huc->delayed_load.status = INTEL_HUC_WAITING_ON_PXP;
+ if (!i915_sw_fence_done(&huc->delayed_load.fence))
+ hrtimer_start(&huc->delayed_load.timer,
+ ms_to_ktime(PXP_INIT_TIMEOUT_MS),
+ HRTIMER_MODE_REL);
+}
+
+static enum hrtimer_restart huc_delayed_load_timer_callback(struct hrtimer *hrtimer)
+{
+ struct intel_huc *huc = container_of(hrtimer, struct intel_huc, delayed_load.timer);
+
+ if (!intel_huc_is_authenticated(huc)) {
+ if (huc->delayed_load.status == INTEL_HUC_WAITING_ON_GSC)
+ drm_notice(&huc_to_gt(huc)->i915->drm,
+ "timed out waiting for MEI GSC init to load HuC\n");
+ else if (huc->delayed_load.status == INTEL_HUC_WAITING_ON_PXP)
+ drm_notice(&huc_to_gt(huc)->i915->drm,
+ "timed out waiting for MEI PXP init to load HuC\n");
+ else
+ MISSING_CASE(huc->delayed_load.status);
+
+ __gsc_init_error(huc);
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static void huc_delayed_load_start(struct intel_huc *huc)
+{
+ ktime_t delay;
+
+ GEM_BUG_ON(intel_huc_is_authenticated(huc));
+
+ /*
+ * On resume we don't have to wait for MEI-GSC to be re-probed, but we
+ * do need to wait for MEI-PXP to reset & re-bind
+ */
+ switch (huc->delayed_load.status) {
+ case INTEL_HUC_WAITING_ON_GSC:
+ delay = ms_to_ktime(GSC_INIT_TIMEOUT_MS);
+ break;
+ case INTEL_HUC_WAITING_ON_PXP:
+ delay = ms_to_ktime(PXP_INIT_TIMEOUT_MS);
+ break;
+ default:
+ gsc_init_error(huc);
+ return;
+ }
+
+ /*
+ * This fence is always complete unless we're waiting for the
+ * GSC device to come up to load the HuC. We arm the fence here
+ * and complete it when we confirm that the HuC is loaded from
+ * the PXP bind callback.
+ */
+ GEM_BUG_ON(!i915_sw_fence_done(&huc->delayed_load.fence));
+ i915_sw_fence_fini(&huc->delayed_load.fence);
+ i915_sw_fence_reinit(&huc->delayed_load.fence);
+ i915_sw_fence_await(&huc->delayed_load.fence);
+ i915_sw_fence_commit(&huc->delayed_load.fence);
+
+ hrtimer_start(&huc->delayed_load.timer, delay, HRTIMER_MODE_REL);
+}
+
+static int gsc_notifier(struct notifier_block *nb, unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct intel_huc *huc = container_of(nb, struct intel_huc, delayed_load.nb);
+ struct intel_gsc_intf *intf = &huc_to_gt(huc)->gsc.intf[0];
+
+ if (!intf->adev || &intf->adev->aux_dev.dev != dev)
+ return 0;
+
+ switch (action) {
+ case BUS_NOTIFY_BOUND_DRIVER: /* mei driver bound to aux device */
+ gsc_init_done(huc);
+ break;
+
+ case BUS_NOTIFY_DRIVER_NOT_BOUND: /* mei driver fails to be bound */
+ case BUS_NOTIFY_UNBIND_DRIVER: /* mei driver about to be unbound */
+ drm_info(&huc_to_gt(huc)->i915->drm,
+ "mei driver not bound, disabling HuC load\n");
+ gsc_init_error(huc);
+ break;
+ }
+
+ return 0;
+}
+
+void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus)
+{
+ int ret;
+
+ if (!intel_huc_is_loaded_by_gsc(huc))
+ return;
+
+ huc->delayed_load.nb.notifier_call = gsc_notifier;
+ ret = bus_register_notifier(bus, &huc->delayed_load.nb);
+ if (ret) {
+ drm_err(&huc_to_gt(huc)->i915->drm,
+ "failed to register GSC notifier\n");
+ huc->delayed_load.nb.notifier_call = NULL;
+ gsc_init_error(huc);
+ }
+}
+
+void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus)
+{
+ if (!huc->delayed_load.nb.notifier_call)
+ return;
+
+ delayed_huc_load_complete(huc);
+
+ bus_unregister_notifier(bus, &huc->delayed_load.nb);
+ huc->delayed_load.nb.notifier_call = NULL;
+}
+
+static void delayed_huc_load_init(struct intel_huc *huc)
+{
+ /*
+ * Initialize fence to be complete as this is expected to be complete
+ * unless there is a delayed HuC load in progress.
+ */
+ i915_sw_fence_init(&huc->delayed_load.fence,
+ sw_fence_dummy_notify);
+ i915_sw_fence_commit(&huc->delayed_load.fence);
+
+ hrtimer_init(&huc->delayed_load.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ huc->delayed_load.timer.function = huc_delayed_load_timer_callback;
+}
+
+static void delayed_huc_load_fini(struct intel_huc *huc)
+{
+ /*
+ * the fence is initialized in init_early, so we need to clean it up
+ * even if HuC loading is off.
+ */
+ delayed_huc_load_complete(huc);
+ i915_sw_fence_fini(&huc->delayed_load.fence);
+}
+
+static bool vcs_supported(struct intel_gt *gt)
+{
+ intel_engine_mask_t mask = gt->info.engine_mask;
+
+ /*
+ * We reach here from i915_driver_early_probe for the primary GT before
+ * its engine mask is set, so we use the device info engine mask for it;
+ * this means we're not taking VCS fusing into account, but if the
+ * primary GT supports VCS engines we expect at least one of them to
+ * remain unfused so we're fine.
+ * For other GTs we expect the GT-specific mask to be set before we
+ * call this function.
+ */
+ GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);
+
+ if (gt_is_root(gt))
+ mask = RUNTIME_INFO(gt->i915)->platform_engine_mask;
+ else
+ mask = gt->info.engine_mask;
+
+ return __ENGINE_INSTANCES_MASK(mask, VCS0, I915_MAX_VCS);
+}
+
void intel_huc_init_early(struct intel_huc *huc)
{
struct drm_i915_private *i915 = huc_to_gt(huc)->i915;
+ struct intel_gt *gt = huc_to_gt(huc);
intel_uc_fw_init_early(&huc->fw, INTEL_UC_FW_TYPE_HUC);
+ /*
+ * we always init the fence as already completed, even if HuC is not
+ * supported. This way we don't have to distinguish between HuC not
+ * supported/disabled or already loaded, and can focus on if the load
+ * is currently in progress (fence not complete) or not, which is what
+ * we care about for stalling userspace submissions.
+ */
+ delayed_huc_load_init(huc);
+
+ if (!vcs_supported(gt)) {
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
+ return;
+ }
+
if (GRAPHICS_VER(i915) >= 11) {
huc->status.reg = GEN11_HUC_KERNEL_LOAD_INFO;
huc->status.mask = HUC_LOAD_SUCCESSFUL;
@@ -113,16 +344,59 @@ int intel_huc_init(struct intel_huc *huc)
return 0;
out:
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_INIT_FAIL);
drm_info(&i915->drm, "HuC init failed with %d\n", err);
return err;
}
void intel_huc_fini(struct intel_huc *huc)
{
+ /*
+ * the fence is initialized in init_early, so we need to clean it up
+ * even if HuC loading is off.
+ */
+ delayed_huc_load_fini(huc);
+
+ if (intel_uc_fw_is_loadable(&huc->fw))
+ intel_uc_fw_fini(&huc->fw);
+}
+
+void intel_huc_suspend(struct intel_huc *huc)
+{
if (!intel_uc_fw_is_loadable(&huc->fw))
return;
- intel_uc_fw_fini(&huc->fw);
+ /*
+ * in the unlikely case that we're suspending before the GSC has
+ * completed its loading sequence, just stop waiting. We'll restart
+ * on resume.
+ */
+ delayed_huc_load_complete(huc);
+}
+
+int intel_huc_wait_for_auth_complete(struct intel_huc *huc)
+{
+ struct intel_gt *gt = huc_to_gt(huc);
+ int ret;
+
+ ret = __intel_wait_for_register(gt->uncore,
+ huc->status.reg,
+ huc->status.mask,
+ huc->status.value,
+ 2, 50, NULL);
+
+ /* mark the load process as complete even if the wait failed */
+ delayed_huc_load_complete(huc);
+
+ if (ret) {
+ drm_err(&gt->i915->drm, "HuC: Firmware not verified %d\n", ret);
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
+ return ret;
+ }
+
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING);
+ drm_info(&gt->i915->drm, "HuC authenticated\n");
+ return 0;
}
/**
@@ -161,27 +435,18 @@ int intel_huc_auth(struct intel_huc *huc)
}
/* Check authentication status, it should be done by now */
- ret = __intel_wait_for_register(gt->uncore,
- huc->status.reg,
- huc->status.mask,
- huc->status.value,
- 2, 50, NULL);
- if (ret) {
- DRM_ERROR("HuC: Firmware not verified %d\n", ret);
+ ret = intel_huc_wait_for_auth_complete(huc);
+ if (ret)
goto fail;
- }
- intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING);
- drm_info(&gt->i915->drm, "HuC authenticated\n");
return 0;
fail:
i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret);
- intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
return ret;
}
-static bool huc_is_authenticated(struct intel_huc *huc)
+bool intel_huc_is_authenticated(struct intel_huc *huc)
{
struct intel_gt *gt = huc_to_gt(huc);
intel_wakeref_t wakeref;
@@ -200,13 +465,8 @@ static bool huc_is_authenticated(struct intel_huc *huc)
* This function reads status register to verify if HuC
* firmware was successfully loaded.
*
- * Returns:
- * * -ENODEV if HuC is not present on this platform,
- * * -EOPNOTSUPP if HuC firmware is disabled,
- * * -ENOPKG if HuC firmware was not installed,
- * * -ENOEXEC if HuC firmware is invalid or mismatched,
- * * 0 if HuC firmware is not running,
- * * 1 if HuC firmware is authenticated and running.
+ * The return values match what is expected for the I915_PARAM_HUC_STATUS
+ * getparam.
*/
int intel_huc_check_status(struct intel_huc *huc)
{
@@ -219,11 +479,21 @@ int intel_huc_check_status(struct intel_huc *huc)
return -ENOPKG;
case INTEL_UC_FIRMWARE_ERROR:
return -ENOEXEC;
+ case INTEL_UC_FIRMWARE_INIT_FAIL:
+ return -ENOMEM;
+ case INTEL_UC_FIRMWARE_LOAD_FAIL:
+ return -EIO;
default:
break;
}
- return huc_is_authenticated(huc);
+ return intel_huc_is_authenticated(huc);
+}
+
+static bool huc_has_delayed_load(struct intel_huc *huc)
+{
+ return intel_huc_is_loaded_by_gsc(huc) &&
+ (huc->delayed_load.status != INTEL_HUC_DELAYED_LOAD_ERROR);
}
void intel_huc_update_auth_status(struct intel_huc *huc)
@@ -231,9 +501,11 @@ void intel_huc_update_auth_status(struct intel_huc *huc)
if (!intel_uc_fw_is_loadable(&huc->fw))
return;
- if (huc_is_authenticated(huc))
+ if (intel_huc_is_authenticated(huc))
intel_uc_fw_change_status(&huc->fw,
INTEL_UC_FIRMWARE_RUNNING);
+ else if (huc_has_delayed_load(huc))
+ huc_delayed_load_start(huc);
}
/**
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h
index d7e25b6e879e..52db03620c60 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h
@@ -7,9 +7,21 @@
#define _INTEL_HUC_H_
#include "i915_reg_defs.h"
+#include "i915_sw_fence.h"
#include "intel_uc_fw.h"
#include "intel_huc_fw.h"
+#include <linux/notifier.h>
+#include <linux/hrtimer.h>
+
+struct bus_type;
+
+enum intel_huc_delayed_load_status {
+ INTEL_HUC_WAITING_ON_GSC = 0,
+ INTEL_HUC_WAITING_ON_PXP,
+ INTEL_HUC_DELAYED_LOAD_ERROR,
+};
+
struct intel_huc {
/* Generic uC firmware management */
struct intel_uc_fw fw;
@@ -20,14 +32,27 @@ struct intel_huc {
u32 mask;
u32 value;
} status;
+
+ struct {
+ struct i915_sw_fence fence;
+ struct hrtimer timer;
+ struct notifier_block nb;
+ enum intel_huc_delayed_load_status status;
+ } delayed_load;
};
void intel_huc_init_early(struct intel_huc *huc);
int intel_huc_init(struct intel_huc *huc);
void intel_huc_fini(struct intel_huc *huc);
+void intel_huc_suspend(struct intel_huc *huc);
int intel_huc_auth(struct intel_huc *huc);
+int intel_huc_wait_for_auth_complete(struct intel_huc *huc);
int intel_huc_check_status(struct intel_huc *huc);
void intel_huc_update_auth_status(struct intel_huc *huc);
+bool intel_huc_is_authenticated(struct intel_huc *huc);
+
+void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus);
+void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus);
static inline int intel_huc_sanitize(struct intel_huc *huc)
{
@@ -56,6 +81,12 @@ static inline bool intel_huc_is_loaded_by_gsc(const struct intel_huc *huc)
return huc->fw.loaded_via_gsc;
}
+static inline bool intel_huc_wait_required(struct intel_huc *huc)
+{
+ return intel_huc_is_used(huc) && intel_huc_is_loaded_by_gsc(huc) &&
+ !intel_huc_is_authenticated(huc);
+}
+
void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p);
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
index 9d6ab1e01639..4f246416db17 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
@@ -3,9 +3,43 @@
* Copyright © 2014-2019 Intel Corporation
*/
+#include "gt/intel_gsc.h"
#include "gt/intel_gt.h"
+#include "intel_huc.h"
#include "intel_huc_fw.h"
#include "i915_drv.h"
+#include "pxp/intel_pxp_huc.h"
+
+int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc)
+{
+ int ret;
+
+ if (!intel_huc_is_loaded_by_gsc(huc))
+ return -ENODEV;
+
+ if (!intel_uc_fw_is_loadable(&huc->fw))
+ return -ENOEXEC;
+
+ /*
+ * If we abort a suspend, HuC might still be loaded when the mei
+ * component gets re-bound and this function called again. If so, just
+ * mark the HuC as loaded.
+ */
+ if (intel_huc_is_authenticated(huc)) {
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING);
+ return 0;
+ }
+
+ GEM_WARN_ON(intel_uc_fw_is_loaded(&huc->fw));
+
+ ret = intel_pxp_huc_load_and_auth(&huc_to_gt(huc)->pxp);
+ if (ret)
+ return ret;
+
+ intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_TRANSFERRED);
+
+ return intel_huc_wait_for_auth_complete(huc);
+}
/**
* intel_huc_fw_upload() - load HuC uCode to device via DMA transfer
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
index 12f264ee3e0b..db42e238b45f 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
@@ -8,6 +8,7 @@
struct intel_huc;
+int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc);
int intel_huc_fw_upload(struct intel_huc *huc);
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
index dbd048b77e19..2a508b137e90 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
@@ -357,8 +357,8 @@ static int uc_init_wopcm(struct intel_uc *uc)
{
struct intel_gt *gt = uc_to_gt(uc);
struct intel_uncore *uncore = gt->uncore;
- u32 base = intel_wopcm_guc_base(&gt->i915->wopcm);
- u32 size = intel_wopcm_guc_size(&gt->i915->wopcm);
+ u32 base = intel_wopcm_guc_base(&gt->wopcm);
+ u32 size = intel_wopcm_guc_size(&gt->wopcm);
u32 huc_agent = intel_uc_uses_huc(uc) ? HUC_LOADING_AGENT_GUC : 0;
u32 mask;
int err;
@@ -636,8 +636,10 @@ void intel_uc_runtime_suspend(struct intel_uc *uc)
{
struct intel_guc *guc = &uc->guc;
- if (!intel_guc_is_ready(guc))
+ if (!intel_guc_is_ready(guc)) {
+ guc->interrupts.enabled = false;
return;
+ }
/*
* Wait for any outstanding CTB before tearing down communication /w the
@@ -657,8 +659,10 @@ void intel_uc_suspend(struct intel_uc *uc)
intel_wakeref_t wakeref;
int err;
- if (!intel_guc_is_ready(guc))
+ if (!intel_guc_is_ready(guc)) {
+ guc->interrupts.enabled = false;
return;
+ }
with_intel_runtime_pm(&uc_to_gt(uc)->i915->runtime_pm, wakeref) {
err = intel_guc_suspend(guc);
@@ -718,6 +722,7 @@ int intel_uc_runtime_resume(struct intel_uc *uc)
static const struct intel_uc_ops uc_ops_off = {
.init_hw = __uc_check_hw,
+ .fini = __uc_fini, /* to clean-up the init_early initialization */
};
static const struct intel_uc_ops uc_ops_on = {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index b91ad4aede1f..0c80ba51a4bd 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -93,7 +93,8 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
fw_def(BROXTON, 0, guc_mmp(bxt, 70, 1, 1)) \
fw_def(SKYLAKE, 0, guc_mmp(skl, 70, 1, 1))
-#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_raw, huc_mmp) \
+#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_raw, huc_mmp, huc_gsc) \
+ fw_def(DG2, 0, huc_gsc(dg2)) \
fw_def(ALDERLAKE_P, 0, huc_raw(tgl)) \
fw_def(ALDERLAKE_P, 0, huc_mmp(tgl, 7, 9, 3)) \
fw_def(ALDERLAKE_S, 0, huc_raw(tgl)) \
@@ -141,6 +142,9 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
#define MAKE_HUC_FW_PATH_BLANK(prefix_) \
__MAKE_UC_FW_PATH_BLANK(prefix_, "_huc")
+#define MAKE_HUC_FW_PATH_GSC(prefix_) \
+ __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc_gsc")
+
#define MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \
__MAKE_UC_FW_PATH_MMP(prefix_, "_huc_", major_, minor_, patch_)
@@ -153,7 +157,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
MODULE_FIRMWARE(uc_);
INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH_MAJOR, MAKE_GUC_FW_PATH_MMP)
-INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP)
+INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP, MAKE_HUC_FW_PATH_GSC)
/*
* The next expansion of the table macros (in __uc_fw_auto_select below) provides
@@ -168,6 +172,7 @@ struct __packed uc_fw_blob {
u8 major;
u8 minor;
u8 patch;
+ bool loaded_via_gsc;
};
#define UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
@@ -176,16 +181,16 @@ struct __packed uc_fw_blob {
.patch = patch_, \
.path = path_,
-#define UC_FW_BLOB_NEW(major_, minor_, patch_, path_) \
+#define UC_FW_BLOB_NEW(major_, minor_, patch_, gsc_, path_) \
{ UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
- .legacy = false }
+ .legacy = false, .loaded_via_gsc = gsc_ }
#define UC_FW_BLOB_OLD(major_, minor_, patch_, path_) \
{ UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
.legacy = true }
#define GUC_FW_BLOB(prefix_, major_, minor_) \
- UC_FW_BLOB_NEW(major_, minor_, 0, \
+ UC_FW_BLOB_NEW(major_, minor_, 0, false, \
MAKE_GUC_FW_PATH_MAJOR(prefix_, major_, minor_))
#define GUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \
@@ -193,12 +198,15 @@ struct __packed uc_fw_blob {
MAKE_GUC_FW_PATH_MMP(prefix_, major_, minor_, patch_))
#define HUC_FW_BLOB(prefix_) \
- UC_FW_BLOB_NEW(0, 0, 0, MAKE_HUC_FW_PATH_BLANK(prefix_))
+ UC_FW_BLOB_NEW(0, 0, 0, false, MAKE_HUC_FW_PATH_BLANK(prefix_))
#define HUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \
UC_FW_BLOB_OLD(major_, minor_, patch_, \
MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_))
+#define HUC_FW_BLOB_GSC(prefix_) \
+ UC_FW_BLOB_NEW(0, 0, 0, true, MAKE_HUC_FW_PATH_GSC(prefix_))
+
struct __packed uc_fw_platform_requirement {
enum intel_platform p;
u8 rev; /* first platform rev using this FW */
@@ -224,7 +232,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, GUC_FW_BLOB_MMP)
};
static const struct uc_fw_platform_requirement blobs_huc[] = {
- INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP)
+ INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP, HUC_FW_BLOB_GSC)
};
static const struct fw_blobs_by_type blobs_all[INTEL_UC_FW_NUM_TYPES] = {
[INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) },
@@ -272,6 +280,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
uc_fw->file_wanted.path = blob->path;
uc_fw->file_wanted.major_ver = blob->major;
uc_fw->file_wanted.minor_ver = blob->minor;
+ uc_fw->loaded_via_gsc = blob->loaded_via_gsc;
found = true;
break;
}
@@ -469,10 +478,11 @@ static int check_gsc_manifest(const struct firmware *fw,
return 0;
}
-static int check_ccs_header(struct drm_i915_private *i915,
+static int check_ccs_header(struct intel_gt *gt,
const struct firmware *fw,
struct intel_uc_fw *uc_fw)
{
+ struct drm_i915_private *i915 = gt->i915;
struct uc_css_header *css;
size_t size;
@@ -514,10 +524,10 @@ static int check_ccs_header(struct drm_i915_private *i915,
/* Sanity check whether this fw is not larger than whole WOPCM memory */
size = __intel_uc_fw_get_upload_size(uc_fw);
- if (unlikely(size >= i915->wopcm.size)) {
+ if (unlikely(size >= gt->wopcm.size)) {
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
- size, (size_t)i915->wopcm.size);
+ size, (size_t)gt->wopcm.size);
return -E2BIG;
}
@@ -545,7 +555,8 @@ static int check_ccs_header(struct drm_i915_private *i915,
*/
int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
{
- struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
+ struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
+ struct drm_i915_private *i915 = gt->i915;
struct intel_uc_fw_file file_ideal;
struct device *dev = i915->drm.dev;
struct drm_i915_gem_object *obj;
@@ -553,7 +564,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
bool old_ver = false;
int err;
- GEM_BUG_ON(!i915->wopcm.size);
+ GEM_BUG_ON(!gt->wopcm.size);
GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw));
err = i915_inject_probe_error(i915, -ENXIO);
@@ -566,6 +577,17 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
+ if (!err && fw->size > INTEL_UC_RSVD_GGTT_PER_FW) {
+ drm_err(&i915->drm,
+ "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n",
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
+ fw->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K);
+
+ /* try to find another blob to load */
+ release_firmware(fw);
+ err = -ENOENT;
+ }
+
/* Any error is terminal if overriding. Don't bother searching for older versions */
if (err && intel_uc_fw_is_overridden(uc_fw))
goto fail;
@@ -595,7 +617,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
if (uc_fw->loaded_via_gsc)
err = check_gsc_manifest(fw, uc_fw);
else
- err = check_ccs_header(i915, fw, uc_fw);
+ err = check_ccs_header(gt, fw, uc_fw);
if (err)
goto fail;
@@ -668,14 +690,30 @@ fail:
static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
{
- struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
+ struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
+ struct i915_ggtt *ggtt = gt->ggtt;
struct drm_mm_node *node = &ggtt->uc_fw;
+ u32 offset = uc_fw->type * INTEL_UC_RSVD_GGTT_PER_FW;
+
+ /*
+ * The media GT shares the GGTT with the root GT, which means that
+ * we need to use different offsets for the binaries on the media GT.
+ * To keep the math simple, we use 8MB for the root tile and 8MB for
+ * the media one. This will need to be updated if we ever have more
+ * than 1 media GT.
+ */
+ BUILD_BUG_ON(INTEL_UC_FW_NUM_TYPES * INTEL_UC_RSVD_GGTT_PER_FW > SZ_8M);
+ GEM_BUG_ON(gt->type == GT_MEDIA && gt->info.id > 1);
+ if (gt->type == GT_MEDIA)
+ offset += SZ_8M;
GEM_BUG_ON(!drm_mm_node_allocated(node));
GEM_BUG_ON(upper_32_bits(node->start));
GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
+ GEM_BUG_ON(offset + uc_fw->obj->base.size > node->size);
+ GEM_BUG_ON(uc_fw->obj->base.size > INTEL_UC_RSVD_GGTT_PER_FW);
- return lower_32_bits(node->start);
+ return lower_32_bits(node->start + offset);
}
static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
@@ -690,7 +728,6 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
dummy->bi.pages = obj->mm.pages;
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
- GEM_BUG_ON(dummy->node_size > ggtt->uc_fw.size);
/* uc_fw->obj cache domains were not controlled across suspend */
if (i915_gem_object_has_struct_page(obj))
@@ -904,7 +941,6 @@ int intel_uc_fw_init(struct intel_uc_fw *uc_fw)
out_unpin:
i915_gem_object_unpin_pages(uc_fw->obj);
out:
- intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_INIT_FAIL);
return err;
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
index cb586f7df270..bc898ba5355d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
@@ -6,6 +6,7 @@
#ifndef _INTEL_UC_FW_H_
#define _INTEL_UC_FW_H_
+#include <linux/sizes.h>
#include <linux/types.h>
#include "intel_uc_fw_abi.h"
#include "intel_device_info.h"
@@ -114,6 +115,19 @@ struct intel_uc_fw {
(uc)->fw.file_selected.minor_ver, \
(uc)->fw.file_selected.patch_ver))
+/*
+ * When we load the uC binaries, we pin them in a reserved section at the top of
+ * the GGTT, which is ~18 MBs. On multi-GT systems where the GTs share the GGTT,
+ * we also need to make sure that each binary is pinned to a unique location
+ * during load, because the different GT can go through the FW load at the same
+ * time (see uc_fw_ggtt_offset() for details).
+ * Given that the available space is much greater than what is required by the
+ * binaries, to keep things simple instead of dynamically partitioning the
+ * reserved section to make space for all the blobs we can just reserve a static
+ * chunk for each binary.
+ */
+#define INTEL_UC_RSVD_GGTT_PER_FW SZ_2M
+
#ifdef CONFIG_DRM_I915_DEBUG_GUC
void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
enum intel_uc_fw_status status);
diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c
index 01f8cd3c3134..d91b58f70403 100644
--- a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c
@@ -35,11 +35,14 @@ static int intel_hang_guc(void *arg)
struct i915_request *rq;
intel_wakeref_t wakeref;
struct i915_gpu_error *global = &gt->i915->gpu_error;
- struct intel_engine_cs *engine;
+ struct intel_engine_cs *engine = intel_selftest_find_any_engine(gt);
unsigned int reset_count;
u32 guc_status;
u32 old_beat;
+ if (!engine)
+ return 0;
+
ctx = kernel_context(gt->i915, NULL);
if (IS_ERR(ctx)) {
drm_err(&gt->i915->drm, "Failed get kernel context: %ld\n", PTR_ERR(ctx));
@@ -48,14 +51,13 @@ static int intel_hang_guc(void *arg)
wakeref = intel_runtime_pm_get(gt->uncore->rpm);
- ce = intel_context_create(gt->engine[BCS0]);
+ ce = intel_context_create(engine);
if (IS_ERR(ce)) {
ret = PTR_ERR(ce);
drm_err(&gt->i915->drm, "Failed to create spinner request: %d\n", ret);
goto err;
}
- engine = ce->engine;
reset_count = i915_reset_count(global);
old_beat = engine->props.heartbeat_interval_ms;
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c
index eef3bba8a41b..9bafac1eaf48 100644
--- a/drivers/gpu/drm/i915/gvt/cfg_space.c
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -244,7 +244,7 @@ static void emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
}
/**
- * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write
+ * intel_vgpu_emulate_cfg_write - emulate vGPU configuration space write
* @vgpu: target vgpu
* @offset: offset
* @p_data: write data ptr
@@ -354,9 +354,9 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size =
- pci_resource_len(pdev, GTTMMADR_BAR);
+ pci_resource_len(pdev, GEN4_GTTMMADR_BAR);
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
- pci_resource_len(pdev, GTT_APERTURE_BAR);
+ pci_resource_len(pdev, GEN4_GMADR_BAR);
memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);
diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c
index de13f102d4fd..0ebf5fbf0e39 100644
--- a/drivers/gpu/drm/i915/gvt/cmd_parser.c
+++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt_regs.h"
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
index c7722c818b4d..c033249e73f4 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -36,6 +36,8 @@
#include "i915_reg.h"
#include "gvt.h"
+#include "display/intel_dpio_phy.h"
+
static int get_edp_pipe(struct intel_vgpu *vgpu)
{
u32 data = vgpu_vreg(vgpu, _TRANS_DDI_FUNC_CTL_EDP);
diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c
index 01e54b45c5c1..355f1c0e8664 100644
--- a/drivers/gpu/drm/i915/gvt/dmabuf.c
+++ b/drivers/gpu/drm/i915/gvt/dmabuf.c
@@ -88,7 +88,7 @@ static int vgpu_gem_get_pages(
sg_dma_address(sg) = dma_addr;
}
- __i915_gem_object_set_pages(obj, st, PAGE_SIZE);
+ __i915_gem_object_set_pages(obj, st);
out:
if (ret) {
dma_addr_t dma_addr;
diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.h b/drivers/gpu/drm/i915/gvt/dmabuf.h
index 5f8f03fb1d1b..3dcdb6570eda 100644
--- a/drivers/gpu/drm/i915/gvt/dmabuf.h
+++ b/drivers/gpu/drm/i915/gvt/dmabuf.h
@@ -48,7 +48,7 @@ struct intel_vgpu_fb_info {
struct intel_vgpu_dmabuf_obj *obj;
};
-/**
+/*
* struct intel_vgpu_dmabuf_obj- Intel vGPU device buffer object
*/
struct intel_vgpu_dmabuf_obj {
diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c
index 54fe442238c6..a683c22d5b64 100644
--- a/drivers/gpu/drm/i915/gvt/firmware.c
+++ b/drivers/gpu/drm/i915/gvt/firmware.c
@@ -104,7 +104,7 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
memcpy(p, gvt->firmware.mmio, info->mmio_size);
- crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4;
+ crc32_start = offsetof(struct gvt_firmware_header, version);
h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start);
firmware_attr.size = size;
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
index ce0eb03709c3..51e5e8fb505b 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.c
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -282,11 +282,6 @@ static inline int get_next_pt_type(int type)
return gtt_type_table[type].next_pt_type;
}
-static inline int get_pt_type(int type)
-{
- return gtt_type_table[type].pt_type;
-}
-
static inline int get_entry_type(int type)
{
return gtt_type_table[type].entry_type;
@@ -2785,7 +2780,7 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt)
* intel_gvt_clean_gtt - clean up mm components of a GVT device
* @gvt: GVT device
*
- * This function is called at the driver unloading stage, to clean up the
+ * This function is called at the driver unloading stage, to clean up
* the mm components of a GVT device.
*
*/
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index dbf8d7470b2c..62823c0e13ab 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -227,8 +227,6 @@ struct intel_vgpu {
unsigned long nr_cache_entries;
struct mutex cache_lock;
- atomic_t released;
-
struct kvm_page_track_notifier_node track_node;
#define NR_BKT (1 << 18)
struct hlist_head ptable[NR_BKT];
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index daac2050d77d..735fc83e7026 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -43,6 +43,7 @@
#include "intel_mchbar_regs.h"
#include "display/intel_display_types.h"
#include "display/intel_dmc_regs.h"
+#include "display/intel_dpio_phy.h"
#include "display/intel_fbc.h"
#include "display/vlv_dsi_pll_regs.h"
#include "gt/intel_gt_regs.h"
@@ -734,7 +735,7 @@ static i915_reg_t force_nonpriv_white_list[] = {
_MMIO(0x770c),
_MMIO(0x83a8),
_MMIO(0xb110),
- GEN8_L3SQCREG4,//_MMIO(0xb118)
+ _MMIO(0xb118),
_MMIO(0xe100),
_MMIO(0xe18c),
_MMIO(0xe48c),
@@ -2257,7 +2258,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
MMIO_DFH(_MMIO(0x2438), D_ALL, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0x243c), D_ALL, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0x7018), D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
- MMIO_DFH(HALF_SLICE_CHICKEN3, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
+ MMIO_DFH(HSW_HALF_SLICE_CHICKEN3, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(GEN7_HALF_SLICE_CHICKEN1, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
/* display */
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 7a45e5360caf..077892a9aa8f 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -664,8 +664,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
return -ESRCH;
}
- kvm_get_kvm(vgpu->vfio_device.kvm);
-
if (__kvmgt_vgpu_exist(vgpu))
return -EEXIST;
@@ -676,6 +674,7 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
vgpu->track_node.track_write = kvmgt_page_track_write;
vgpu->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
+ kvm_get_kvm(vgpu->vfio_device.kvm);
kvm_page_track_register_notifier(vgpu->vfio_device.kvm,
&vgpu->track_node);
@@ -684,7 +683,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
intel_gvt_activate_vgpu(vgpu);
- atomic_set(&vgpu->released, 0);
return 0;
}
@@ -706,24 +704,20 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
if (!vgpu->attached)
return;
- if (atomic_cmpxchg(&vgpu->released, 0, 1))
- return;
-
intel_gvt_release_vgpu(vgpu);
debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs));
kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm,
&vgpu->track_node);
+ kvm_put_kvm(vgpu->vfio_device.kvm);
+
kvmgt_protect_table_destroy(vgpu);
gvt_cache_destroy(vgpu);
intel_vgpu_release_msi_eventfd_ctx(vgpu);
vgpu->attached = false;
-
- if (vgpu->vfio_device.kvm)
- kvm_put_kvm(vgpu->vfio_device.kvm);
}
static u64 intel_vgpu_get_bar_addr(struct intel_vgpu *vgpu, int bar)
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 9acc00505fde..5b5def6ddef7 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -37,6 +37,7 @@
#include "i915_reg.h"
#include "gvt.h"
+#include "display/intel_dpio_phy.h"
#include "gt/intel_gt_regs.h"
/**
diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c
index 1c6e941c9666..490e8ae51228 100644
--- a/drivers/gpu/drm/i915/gvt/mmio_context.c
+++ b/drivers/gpu/drm/i915/gvt/mmio_context.c
@@ -34,6 +34,7 @@
*/
#include "i915_drv.h"
+#include "i915_reg.h"
#include "gt/intel_context.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gpu_commands.h"
@@ -106,15 +107,15 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
{RCS0, GEN8_CS_CHICKEN1, 0xffff, true}, /* 0x2580 */
{RCS0, COMMON_SLICE_CHICKEN2, 0xffff, true}, /* 0x7014 */
{RCS0, GEN9_CS_DEBUG_MODE1, 0xffff, false}, /* 0x20ec */
- {RCS0, GEN8_L3SQCREG4, 0, false}, /* 0xb118 */
- {RCS0, GEN9_SCRATCH1, 0, false}, /* 0xb11c */
+ {RCS0, _MMIO(0xb118), 0, false}, /* GEN8_L3SQCREG4 */
+ {RCS0, _MMIO(0xb11c), 0, false}, /* GEN9_SCRATCH1 */
{RCS0, GEN9_SCRATCH_LNCF1, 0, false}, /* 0xb008 */
{RCS0, GEN7_HALF_SLICE_CHICKEN1, 0xffff, true}, /* 0xe100 */
- {RCS0, HALF_SLICE_CHICKEN2, 0xffff, true}, /* 0xe180 */
- {RCS0, HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */
- {RCS0, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */
- {RCS0, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */
- {RCS0, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */
+ {RCS0, _MMIO(0xe180), 0xffff, true}, /* HALF_SLICE_CHICKEN2 */
+ {RCS0, _MMIO(0xe184), 0xffff, true}, /* GEN8_HALF_SLICE_CHICKEN3 */
+ {RCS0, _MMIO(0xe188), 0xffff, true}, /* GEN9_HALF_SLICE_CHICKEN5 */
+ {RCS0, _MMIO(0xe194), 0xffff, true}, /* GEN9_HALF_SLICE_CHICKEN7 */
+ {RCS0, _MMIO(0xe4f0), 0xffff, true}, /* GEN8_ROW_CHICKEN */
{RCS0, TRVATTL3PTRDW(0), 0, true}, /* 0x4de0 */
{RCS0, TRVATTL3PTRDW(1), 0, true}, /* 0x4de4 */
{RCS0, TRNULLDETCT, 0, true}, /* 0x4de8 */
diff --git a/drivers/gpu/drm/i915/gvt/page_track.c b/drivers/gpu/drm/i915/gvt/page_track.c
index 3375b51c75f1..df34e73cba41 100644
--- a/drivers/gpu/drm/i915/gvt/page_track.c
+++ b/drivers/gpu/drm/i915/gvt/page_track.c
@@ -120,7 +120,7 @@ int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
}
/**
- * intel_vgpu_enable_page_track - cancel write-protection on guest page
+ * intel_vgpu_disable_page_track - cancel write-protection on guest page
* @vgpu: a vGPU
* @gfn: the gfn of guest page
*
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index d6fe94cd0fdb..9cd8fcbf7cad 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -570,9 +570,8 @@ retry:
if (gmadr_bytes == 8)
bb->bb_start_cmd_va[2] = 0;
- ret = i915_vma_move_to_active(bb->vma,
- workload->req,
- 0);
+ ret = i915_vma_move_to_active(bb->vma, workload->req,
+ __EXEC_OBJECT_NO_REQUEST_AWAIT);
if (ret)
goto err;
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index 56c71474008a..3c529c2705dd 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -158,7 +158,7 @@ void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt)
}
/**
- * intel_gvt_active_vgpu - activate a virtual GPU
+ * intel_gvt_activate_vgpu - activate a virtual GPU
* @vgpu: virtual GPU
*
* This function is called when user wants to activate a virtual GPU.
@@ -172,7 +172,7 @@ void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu)
}
/**
- * intel_gvt_deactive_vgpu - deactivate a virtual GPU
+ * intel_gvt_deactivate_vgpu - deactivate a virtual GPU
* @vgpu: virtual GPU
*
* This function is called when user wants to deactivate a virtual GPU.
@@ -295,7 +295,7 @@ out_free_vgpu:
}
/**
- * intel_gvt_destroy_vgpu - destroy an idle virtual GPU
+ * intel_gvt_destroy_idle_vgpu - destroy an idle virtual GPU
* @vgpu: virtual GPU
*
* This function is called when user wants to destroy an idle virtual GPU.
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ae987e92251d..6c7ac73b69a5 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -688,8 +688,8 @@ i915_drop_caches_set(void *data, u64 val)
unsigned int flags;
int ret;
- DRM_DEBUG("Dropping caches: 0x%08llx [0x%08llx]\n",
- val, val & DROP_ALL);
+ drm_dbg(&i915->drm, "Dropping caches: 0x%08llx [0x%08llx]\n",
+ val, val & DROP_ALL);
ret = gt_drop_caches(to_gt(i915), val);
if (ret)
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index f2a15d8155f4..69103ae37779 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -81,6 +81,7 @@
#include "i915_drm_client.h"
#include "i915_drv.h"
#include "i915_getparam.h"
+#include "i915_hwmon.h"
#include "i915_ioc32.h"
#include "i915_ioctl.h"
#include "i915_irq.h"
@@ -337,7 +338,8 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
if (i915_inject_probe_failure(dev_priv))
return -ENODEV;
- intel_device_info_subplatform_init(dev_priv);
+ intel_device_info_runtime_init_early(dev_priv);
+
intel_step_init(dev_priv);
intel_uncore_mmio_debug_init_early(dev_priv);
@@ -370,8 +372,6 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
if (ret)
goto err_ttm;
- intel_wopcm_init_early(&dev_priv->wopcm);
-
ret = intel_root_gt_init_early(dev_priv);
if (ret < 0)
goto err_rootgt;
@@ -739,7 +739,6 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
*/
static void i915_driver_register(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_gt *gt;
unsigned int i;
@@ -749,7 +748,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
intel_vgpu_register(dev_priv);
/* Reveal our presence to userspace */
- if (drm_dev_register(dev, 0)) {
+ if (drm_dev_register(&dev_priv->drm, 0)) {
drm_err(&dev_priv->drm,
"Failed to register driver for userspace access!\n");
return;
@@ -764,6 +763,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
for_each_gt(gt, dev_priv, i)
intel_gt_driver_register(gt);
+ i915_hwmon_register(dev_priv);
+
intel_display_driver_register(dev_priv);
intel_power_domains_enable(dev_priv);
@@ -796,6 +797,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
for_each_gt(gt, dev_priv, i)
intel_gt_driver_unregister(gt);
+ i915_hwmon_unregister(dev_priv);
+
i915_perf_unregister(dev_priv);
i915_pmu_unregister(dev_priv);
@@ -894,10 +897,6 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (IS_ERR(i915))
return PTR_ERR(i915);
- /* Disable nuclear pageflip by default on pre-ILK */
- if (!i915->params.nuclear_pageflip && DISPLAY_VER(i915) < 5)
- i915->drm.driver_features &= ~DRIVER_ATOMIC;
-
ret = pci_enable_device(pdev);
if (ret)
goto out_fini;
@@ -1093,32 +1092,30 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_encoder *encoder;
if (!HAS_DISPLAY(dev_priv))
return;
- drm_modeset_lock_all(dev);
- for_each_intel_encoder(dev, encoder)
+ drm_modeset_lock_all(&dev_priv->drm);
+ for_each_intel_encoder(&dev_priv->drm, encoder)
if (encoder->suspend)
encoder->suspend(encoder);
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
}
static void intel_shutdown_encoders(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
struct intel_encoder *encoder;
if (!HAS_DISPLAY(dev_priv))
return;
- drm_modeset_lock_all(dev);
- for_each_intel_encoder(dev, encoder)
+ drm_modeset_lock_all(&dev_priv->drm);
+ for_each_intel_encoder(&dev_priv->drm, encoder)
if (encoder->shutdown)
encoder->shutdown(encoder);
- drm_modeset_unlock_all(dev);
+ drm_modeset_unlock_all(&dev_priv->drm);
}
void i915_driver_shutdown(struct drm_i915_private *i915)
@@ -1662,7 +1659,8 @@ static int intel_runtime_suspend(struct device *kdev)
intel_runtime_pm_enable_interrupts(dev_priv);
- intel_gt_runtime_resume(to_gt(dev_priv));
+ for_each_gt(gt, dev_priv, i)
+ intel_gt_runtime_resume(gt);
enable_rpm_wakeref_asserts(rpm);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bdc81db76dbd..a380db36d52c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -40,7 +40,6 @@
#include "display/intel_display_core.h"
#include "gem/i915_gem_context_types.h"
-#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_shrinker.h"
#include "gem/i915_gem_stolen.h"
@@ -63,7 +62,6 @@
#include "intel_runtime_pm.h"
#include "intel_step.h"
#include "intel_uncore.h"
-#include "intel_wopcm.h"
struct drm_i915_clock_gating_funcs;
struct drm_i915_gem_object;
@@ -75,9 +73,6 @@ struct intel_limit;
struct intel_overlay_error_state;
struct vlv_s0ix_state;
-/* Threshold == 5 for long IRQs, 50 for short */
-#define HPD_STORM_DEFAULT_THRESHOLD 50
-
#define I915_GEM_GPU_DOMAINS \
(I915_GEM_DOMAIN_RENDER | \
I915_GEM_DOMAIN_SAMPLER | \
@@ -239,8 +234,6 @@ struct drm_i915_private {
struct intel_gvt *gvt;
- struct intel_wopcm wopcm;
-
struct pci_dev *bridge_dev;
struct rb_root uabi_engines;
@@ -291,28 +284,13 @@ struct drm_i915_private {
unsigned long gem_quirks;
- struct drm_atomic_state *modeset_restore_state;
- struct drm_modeset_acquire_ctx reset_ctx;
-
struct i915_gem_mm mm;
- /* Kernel Modesetting */
-
- struct list_head global_obj_list;
-
bool mchbar_need_disable;
struct intel_l3_parity l3_parity;
/*
- * HTI (aka HDPORT) state read during initial hw readout. Most
- * platforms don't have HTI, so this will just stay 0. Those that do
- * will use this later to figure out which PLLs and PHYs are unavailable
- * for driver usage.
- */
- u32 hti_state;
-
- /*
* edram size in MB.
* Cannot be determined by PCIID. You must always read a register.
*/
@@ -353,6 +331,8 @@ struct drm_i915_private {
struct i915_perf perf;
+ struct i915_hwmon *hwmon;
+
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
struct intel_gt gt0;
@@ -742,6 +722,10 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define IS_XEHPSDV_GRAPHICS_STEP(__i915, since, until) \
(IS_XEHPSDV(__i915) && IS_GRAPHICS_STEP(__i915, since, until))
+#define IS_MTL_GRAPHICS_STEP(__i915, variant, since, until) \
+ (IS_SUBPLATFORM(__i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_##variant) && \
+ IS_GRAPHICS_STEP(__i915, since, until))
+
/*
* DG2 hardware steppings are a bit unusual. The hardware design was forked to
* create three variants (G10, G11, and G12) which each have distinct
@@ -780,12 +764,15 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define __HAS_ENGINE(engine_mask, id) ((engine_mask) & BIT(id))
#define HAS_ENGINE(gt, id) __HAS_ENGINE((gt)->info.engine_mask, id)
-#define ENGINE_INSTANCES_MASK(gt, first, count) ({ \
+#define __ENGINE_INSTANCES_MASK(mask, first, count) ({ \
unsigned int first__ = (first); \
unsigned int count__ = (count); \
- ((gt)->info.engine_mask & \
- GENMASK(first__ + count__ - 1, first__)) >> first__; \
+ ((mask) & GENMASK(first__ + count__ - 1, first__)) >> first__; \
})
+
+#define ENGINE_INSTANCES_MASK(gt, first, count) \
+ __ENGINE_INSTANCES_MASK((gt)->info.engine_mask, first, count)
+
#define RCS_MASK(gt) \
ENGINE_INSTANCES_MASK(gt, RCS0, I915_MAX_RCS)
#define BCS_MASK(gt) \
@@ -871,6 +858,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_DOUBLE_BUFFERED_M_N(dev_priv) (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
#define HAS_CDCLK_CRAWL(dev_priv) (INTEL_INFO(dev_priv)->display.has_cdclk_crawl)
+#define HAS_CDCLK_SQUASH(dev_priv) (INTEL_INFO(dev_priv)->display.has_cdclk_squash)
#define HAS_DDI(dev_priv) (INTEL_INFO(dev_priv)->display.has_ddi)
#define HAS_FPGA_DBG_UNCLAIMED(dev_priv) (INTEL_INFO(dev_priv)->display.has_fpga_dbg)
#define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr)
@@ -900,19 +888,17 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm)
#define HAS_64BIT_RELOC(dev_priv) (INTEL_INFO(dev_priv)->has_64bit_reloc)
+#define HAS_OA_BPC_REPORTING(dev_priv) \
+ (INTEL_INFO(dev_priv)->has_oa_bpc_reporting)
+#define HAS_OA_SLICE_CONTRIB_LIMITS(dev_priv) \
+ (INTEL_INFO(dev_priv)->has_oa_slice_contrib_limits)
+
/*
* Set this flag, when platform requires 64K GTT page sizes or larger for
* device local memory access.
*/
#define HAS_64K_PAGES(dev_priv) (INTEL_INFO(dev_priv)->has_64k_pages)
-/*
- * Set this flag when platform doesn't allow both 64k pages and 4k pages in
- * the same PT. this flag means we need to support compact PT layout for the
- * ppGTT when using the 64K GTT pages.
- */
-#define NEEDS_COMPACT_PT(dev_priv) (INTEL_INFO(dev_priv)->needs_compact_pt)
-
#define HAS_IPC(dev_priv) (INTEL_INFO(dev_priv)->display.has_ipc)
#define HAS_REGION(i915, i) (RUNTIME_INFO(i915)->memory_regions & (i))
@@ -938,6 +924,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch)
+#define HAS_GMD_ID(i915) (INTEL_INFO(i915)->has_gmd_id)
+
#define HAS_LSPCON(dev_priv) (IS_DISPLAY_VER(dev_priv, 9, 10))
#define HAS_L3_CCS_READ(i915) (INTEL_INFO(i915)->has_l3_ccs_read)
@@ -976,6 +964,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_ONE_EU_PER_FUSE_BIT(i915) (INTEL_INFO(i915)->has_one_eu_per_fuse_bit)
+#define HAS_LMEMBAR_SMEM_STOLEN(i915) (!HAS_LMEM(i915) && \
+ GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
+
/* intel_device_info.c */
static inline struct intel_device_info *
mkwrite_device_info(struct drm_i915_private *dev_priv)
@@ -983,16 +974,4 @@ mkwrite_device_info(struct drm_i915_private *dev_priv)
return (struct intel_device_info *)INTEL_INFO(dev_priv);
}
-static inline enum i915_map_type
-i915_coherent_map_type(struct drm_i915_private *i915,
- struct drm_i915_gem_object *obj, bool always_coherent)
-{
- if (i915_gem_object_is_lmem(obj))
- return I915_MAP_WC;
- if (HAS_LLC(i915) || always_coherent)
- return I915_MAP_WB;
- else
- return I915_MAP_WC;
-}
-
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2bdddb61ebd7..8468ca9885fd 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -843,7 +843,7 @@ void i915_gem_runtime_suspend(struct drm_i915_private *i915)
__i915_gem_object_release_mmap_gtt(obj);
list_for_each_entry_safe(obj, on,
- &to_gt(i915)->lmem_userfault_list, userfault_link)
+ &i915->runtime_pm.lmem_userfault_list, userfault_link)
i915_gem_object_runtime_pm_release_mmap_offset(obj);
/*
@@ -1128,6 +1128,8 @@ void i915_gem_drain_workqueue(struct drm_i915_private *i915)
int i915_gem_init(struct drm_i915_private *dev_priv)
{
+ struct intel_gt *gt;
+ unsigned int i;
int ret;
/* We need to fallback to 4K pages if host doesn't support huge gtt. */
@@ -1138,8 +1140,10 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
if (ret)
return ret;
- intel_uc_fetch_firmwares(&to_gt(dev_priv)->uc);
- intel_wopcm_init(&dev_priv->wopcm);
+ for_each_gt(gt, dev_priv, i) {
+ intel_uc_fetch_firmwares(&gt->uc);
+ intel_wopcm_init(&gt->wopcm);
+ }
ret = i915_init_ggtt(dev_priv);
if (ret) {
@@ -1158,9 +1162,11 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
*/
intel_init_clock_gating(dev_priv);
- ret = intel_gt_init(to_gt(dev_priv));
- if (ret)
- goto err_unlock;
+ for_each_gt(gt, dev_priv, i) {
+ ret = intel_gt_init(gt);
+ if (ret)
+ goto err_unlock;
+ }
return 0;
@@ -1173,8 +1179,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
err_unlock:
i915_gem_drain_workqueue(dev_priv);
- if (ret != -EIO)
- intel_uc_cleanup_firmwares(&to_gt(dev_priv)->uc);
+ if (ret != -EIO) {
+ for_each_gt(gt, dev_priv, i) {
+ intel_gt_driver_remove(gt);
+ intel_gt_driver_release(gt);
+ intel_uc_cleanup_firmwares(&gt->uc);
+ }
+ }
if (ret == -EIO) {
/*
@@ -1182,10 +1193,12 @@ err_unlock:
* as wedged. But we only want to do this when the GPU is angry,
* for all other failure, such as an allocation failure, bail.
*/
- if (!intel_gt_is_wedged(to_gt(dev_priv))) {
- i915_probe_error(dev_priv,
- "Failed to initialize GPU, declaring it wedged!\n");
- intel_gt_set_wedged(to_gt(dev_priv));
+ for_each_gt(gt, dev_priv, i) {
+ if (!intel_gt_is_wedged(gt)) {
+ i915_probe_error(dev_priv,
+ "Failed to initialize GPU, declaring it wedged!\n");
+ intel_gt_set_wedged(gt);
+ }
}
/* Minimal basic recovery for KMS */
@@ -1213,23 +1226,27 @@ void i915_gem_driver_unregister(struct drm_i915_private *i915)
void i915_gem_driver_remove(struct drm_i915_private *dev_priv)
{
- intel_wakeref_auto_fini(&to_gt(dev_priv)->userfault_wakeref);
+ struct intel_gt *gt;
+ unsigned int i;
i915_gem_suspend_late(dev_priv);
- intel_gt_driver_remove(to_gt(dev_priv));
+ for_each_gt(gt, dev_priv, i)
+ intel_gt_driver_remove(gt);
dev_priv->uabi_engines = RB_ROOT;
/* Flush any outstanding unpin_work. */
i915_gem_drain_workqueue(dev_priv);
-
- i915_gem_drain_freed_objects(dev_priv);
}
void i915_gem_driver_release(struct drm_i915_private *dev_priv)
{
- intel_gt_driver_release(to_gt(dev_priv));
+ struct intel_gt *gt;
+ unsigned int i;
- intel_uc_cleanup_firmwares(&to_gt(dev_priv)->uc);
+ for_each_gt(gt, dev_priv, i) {
+ intel_gt_driver_release(gt);
+ intel_uc_cleanup_firmwares(&gt->uc);
+ }
/* Flush any outstanding work, including i915_gem_context.release_work. */
i915_gem_drain_workqueue(dev_priv);
@@ -1259,7 +1276,7 @@ void i915_gem_init_early(struct drm_i915_private *dev_priv)
void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
{
- i915_gem_drain_freed_objects(dev_priv);
+ i915_gem_drain_workqueue(dev_priv);
GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
drm_WARN_ON(&dev_priv->drm, dev_priv->mm.shrink_count);
@@ -1271,7 +1288,7 @@ int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file)
struct i915_drm_client *client;
int ret = -ENOMEM;
- DRM_DEBUG("\n");
+ drm_dbg(&i915->drm, "\n");
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c
index 342c8ca6414e..61ef2d9cfa62 100644
--- a/drivers/gpu/drm/i915/i915_getparam.c
+++ b/drivers/gpu/drm/i915/i915_getparam.c
@@ -175,8 +175,11 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data,
case I915_PARAM_PERF_REVISION:
value = i915_perf_ioctl_version();
break;
+ case I915_PARAM_OA_TIMESTAMP_FREQUENCY:
+ value = i915_perf_oa_timestamp_frequency(i915);
+ break;
default:
- DRM_DEBUG("Unknown parameter %d\n", param->param);
+ drm_dbg(&i915->drm, "Unknown parameter %d\n", param->param);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 9ea2fe34e7d3..9d5d5a397b64 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -55,6 +55,7 @@
#include "i915_drv.h"
#include "i915_gpu_error.h"
#include "i915_memcpy.h"
+#include "i915_reg.h"
#include "i915_scatterlist.h"
#include "i915_utils.h"
@@ -1221,7 +1222,10 @@ static void engine_record_registers(struct intel_engine_coredump *ee)
if (GRAPHICS_VER(i915) >= 6) {
ee->rc_psmi = ENGINE_READ(engine, RING_PSMI_CTL);
- if (GRAPHICS_VER(i915) >= 12)
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50))
+ ee->fault_reg = intel_gt_mcr_read_any(engine->gt,
+ XEHP_RING_FAULT_REG);
+ else if (GRAPHICS_VER(i915) >= 12)
ee->fault_reg = intel_uncore_read(engine->uncore,
GEN12_RING_FAULT_REG);
else if (GRAPHICS_VER(i915) >= 8)
@@ -1820,7 +1824,12 @@ static void gt_record_global_regs(struct intel_gt_coredump *gt)
if (GRAPHICS_VER(i915) == 7)
gt->err_int = intel_uncore_read(uncore, GEN7_ERR_INT);
- if (GRAPHICS_VER(i915) >= 12) {
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ gt->fault_data0 = intel_gt_mcr_read_any((struct intel_gt *)gt->_gt,
+ XEHP_FAULT_TLB_DATA0);
+ gt->fault_data1 = intel_gt_mcr_read_any((struct intel_gt *)gt->_gt,
+ XEHP_FAULT_TLB_DATA1);
+ } else if (GRAPHICS_VER(i915) >= 12) {
gt->fault_data0 = intel_uncore_read(uncore,
GEN12_FAULT_TLB_DATA0);
gt->fault_data1 = intel_uncore_read(uncore,
diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c
new file mode 100644
index 000000000000..c588a17f97e9
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_hwmon.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/types.h>
+
+#include "i915_drv.h"
+#include "i915_hwmon.h"
+#include "i915_reg.h"
+#include "intel_mchbar_regs.h"
+#include "intel_pcode.h"
+#include "gt/intel_gt.h"
+#include "gt/intel_gt_regs.h"
+
+/*
+ * SF_* - scale factors for particular quantities according to hwmon spec.
+ * - voltage - millivolts
+ * - power - microwatts
+ * - curr - milliamperes
+ * - energy - microjoules
+ * - time - milliseconds
+ */
+#define SF_VOLTAGE 1000
+#define SF_POWER 1000000
+#define SF_CURR 1000
+#define SF_ENERGY 1000000
+#define SF_TIME 1000
+
+struct hwm_reg {
+ i915_reg_t gt_perf_status;
+ i915_reg_t pkg_power_sku_unit;
+ i915_reg_t pkg_power_sku;
+ i915_reg_t pkg_rapl_limit;
+ i915_reg_t energy_status_all;
+ i915_reg_t energy_status_tile;
+};
+
+struct hwm_energy_info {
+ u32 reg_val_prev;
+ long accum_energy; /* Accumulated energy for energy1_input */
+};
+
+struct hwm_drvdata {
+ struct i915_hwmon *hwmon;
+ struct intel_uncore *uncore;
+ struct device *hwmon_dev;
+ struct hwm_energy_info ei; /* Energy info for energy1_input */
+ char name[12];
+ int gt_n;
+};
+
+struct i915_hwmon {
+ struct hwm_drvdata ddat;
+ struct hwm_drvdata ddat_gt[I915_MAX_GT];
+ struct mutex hwmon_lock; /* counter overflow logic and rmw */
+ struct hwm_reg rg;
+ int scl_shift_power;
+ int scl_shift_energy;
+ int scl_shift_time;
+};
+
+static void
+hwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat,
+ i915_reg_t reg, u32 clear, u32 set)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ struct intel_uncore *uncore = ddat->uncore;
+ intel_wakeref_t wakeref;
+
+ mutex_lock(&hwmon->hwmon_lock);
+
+ with_intel_runtime_pm(uncore->rpm, wakeref)
+ intel_uncore_rmw(uncore, reg, clear, set);
+
+ mutex_unlock(&hwmon->hwmon_lock);
+}
+
+/*
+ * This function's return type of u64 allows for the case where the scaling
+ * of the field taken from the 32-bit register value might cause a result to
+ * exceed 32 bits.
+ */
+static u64
+hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr,
+ u32 field_msk, int nshift, u32 scale_factor)
+{
+ struct intel_uncore *uncore = ddat->uncore;
+ intel_wakeref_t wakeref;
+ u32 reg_value;
+
+ with_intel_runtime_pm(uncore->rpm, wakeref)
+ reg_value = intel_uncore_read(uncore, rgadr);
+
+ reg_value = REG_FIELD_GET(field_msk, reg_value);
+
+ return mul_u64_u32_shr(reg_value, scale_factor, nshift);
+}
+
+static void
+hwm_field_scale_and_write(struct hwm_drvdata *ddat, i915_reg_t rgadr,
+ int nshift, unsigned int scale_factor, long lval)
+{
+ u32 nval;
+
+ /* Computation in 64-bits to avoid overflow. Round to nearest. */
+ nval = DIV_ROUND_CLOSEST_ULL((u64)lval << nshift, scale_factor);
+
+ hwm_locked_with_pm_intel_uncore_rmw(ddat, rgadr,
+ PKG_PWR_LIM_1,
+ REG_FIELD_PREP(PKG_PWR_LIM_1, nval));
+}
+
+/*
+ * hwm_energy - Obtain energy value
+ *
+ * The underlying energy hardware register is 32-bits and is subject to
+ * overflow. How long before overflow? For example, with an example
+ * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and
+ * a power draw of 1000 watts, the 32-bit counter will overflow in
+ * approximately 4.36 minutes.
+ *
+ * Examples:
+ * 1 watt: (2^32 >> 14) / 1 W / (60 * 60 * 24) secs/day -> 3 days
+ * 1000 watts: (2^32 >> 14) / 1000 W / 60 secs/min -> 4.36 minutes
+ *
+ * The function significantly increases overflow duration (from 4.36
+ * minutes) by accumulating the energy register into a 'long' as allowed by
+ * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()),
+ * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and
+ * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before
+ * energy1_input overflows. This at 1000 W is an overflow duration of 278 years.
+ */
+static void
+hwm_energy(struct hwm_drvdata *ddat, long *energy)
+{
+ struct intel_uncore *uncore = ddat->uncore;
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ struct hwm_energy_info *ei = &ddat->ei;
+ intel_wakeref_t wakeref;
+ i915_reg_t rgaddr;
+ u32 reg_val;
+
+ if (ddat->gt_n >= 0)
+ rgaddr = hwmon->rg.energy_status_tile;
+ else
+ rgaddr = hwmon->rg.energy_status_all;
+
+ mutex_lock(&hwmon->hwmon_lock);
+
+ with_intel_runtime_pm(uncore->rpm, wakeref)
+ reg_val = intel_uncore_read(uncore, rgaddr);
+
+ if (reg_val >= ei->reg_val_prev)
+ ei->accum_energy += reg_val - ei->reg_val_prev;
+ else
+ ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val;
+ ei->reg_val_prev = reg_val;
+
+ *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY,
+ hwmon->scl_shift_energy);
+ mutex_unlock(&hwmon->hwmon_lock);
+}
+
+static ssize_t
+hwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ intel_wakeref_t wakeref;
+ u32 r, x, y, x_w = 2; /* 2 bits */
+ u64 tau4, out;
+
+ with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+ r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
+
+ x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r);
+ y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r);
+ /*
+ * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17)
+ * = (4 | x) << (y - 2)
+ * where (y - 2) ensures a 1.x fixed point representation of 1.x
+ * However because y can be < 2, we compute
+ * tau4 = (4 | x) << y
+ * but add 2 when doing the final right shift to account for units
+ */
+ tau4 = ((1 << x_w) | x) << y;
+ /* val in hwmon interface units (millisec) */
+ out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
+
+ return sysfs_emit(buf, "%llu\n", out);
+}
+
+static ssize_t
+hwm_power1_max_interval_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ u32 x, y, rxy, x_w = 2; /* 2 bits */
+ u64 tau4, r, max_win;
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ /*
+ * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12
+ * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds
+ */
+#define PKG_MAX_WIN_DEFAULT 0x12ull
+
+ /*
+ * val must be < max in hwmon interface units. The steps below are
+ * explained in i915_power1_max_interval_show()
+ */
+ r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT);
+ x = REG_FIELD_GET(PKG_MAX_WIN_X, r);
+ y = REG_FIELD_GET(PKG_MAX_WIN_Y, r);
+ tau4 = ((1 << x_w) | x) << y;
+ max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
+
+ if (val > max_win)
+ return -EINVAL;
+
+ /* val in hw units */
+ val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME);
+ /* Convert to 1.x * power(2,y) */
+ if (!val)
+ return -EINVAL;
+ y = ilog2(val);
+ /* x = (val - (1 << y)) >> (y - 2); */
+ x = (val - (1ul << y)) << x_w >> y;
+
+ rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y);
+
+ hwm_locked_with_pm_intel_uncore_rmw(ddat, hwmon->rg.pkg_rapl_limit,
+ PKG_PWR_LIM_1_TIME, rxy);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(power1_max_interval, 0664,
+ hwm_power1_max_interval_show,
+ hwm_power1_max_interval_store, 0);
+
+static struct attribute *hwm_attributes[] = {
+ &sensor_dev_attr_power1_max_interval.dev_attr.attr,
+ NULL
+};
+
+static umode_t hwm_attributes_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+ struct i915_hwmon *hwmon = ddat->hwmon;
+
+ if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr)
+ return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? attr->mode : 0;
+
+ return 0;
+}
+
+static const struct attribute_group hwm_attrgroup = {
+ .attrs = hwm_attributes,
+ .is_visible = hwm_attributes_visible,
+};
+
+static const struct attribute_group *hwm_groups[] = {
+ &hwm_attrgroup,
+ NULL
+};
+
+static const struct hwmon_channel_info *hwm_info[] = {
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
+ HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT),
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
+ HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT),
+ NULL
+};
+
+static const struct hwmon_channel_info *hwm_gt_info[] = {
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
+ NULL
+};
+
+/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
+static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
+{
+ return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP,
+ POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval);
+}
+
+static int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval)
+{
+ return snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP,
+ POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval);
+}
+
+static umode_t
+hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
+{
+ struct drm_i915_private *i915 = ddat->uncore->i915;
+
+ switch (attr) {
+ case hwmon_in_input:
+ return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0;
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ intel_wakeref_t wakeref;
+ u32 reg_value;
+
+ switch (attr) {
+ case hwmon_in_input:
+ with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+ reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
+ /* HW register value in units of 2.5 millivolt */
+ *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t
+hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
+{
+ struct drm_i915_private *i915 = ddat->uncore->i915;
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_power_max:
+ return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0;
+ case hwmon_power_rated_max:
+ return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0;
+ case hwmon_power_crit:
+ return (hwm_pcode_read_i1(i915, &uval) ||
+ !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ int ret;
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_power_max:
+ *val = hwm_field_read_and_scale(ddat,
+ hwmon->rg.pkg_rapl_limit,
+ PKG_PWR_LIM_1,
+ hwmon->scl_shift_power,
+ SF_POWER);
+ return 0;
+ case hwmon_power_rated_max:
+ *val = hwm_field_read_and_scale(ddat,
+ hwmon->rg.pkg_power_sku,
+ PKG_PKG_TDP,
+ hwmon->scl_shift_power,
+ SF_POWER);
+ return 0;
+ case hwmon_power_crit:
+ ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
+ if (ret)
+ return ret;
+ if (!(uval & POWER_SETUP_I1_WATTS))
+ return -ENODEV;
+ *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
+ SF_POWER, POWER_SETUP_I1_SHIFT);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_power_max:
+ hwm_field_scale_and_write(ddat,
+ hwmon->rg.pkg_rapl_limit,
+ hwmon->scl_shift_power,
+ SF_POWER, val);
+ return 0;
+ case hwmon_power_crit:
+ uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
+ return hwm_pcode_write_i1(ddat->uncore->i915, uval);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t
+hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ i915_reg_t rgaddr;
+
+ switch (attr) {
+ case hwmon_energy_input:
+ if (ddat->gt_n >= 0)
+ rgaddr = hwmon->rg.energy_status_tile;
+ else
+ rgaddr = hwmon->rg.energy_status_all;
+ return i915_mmio_reg_valid(rgaddr) ? 0444 : 0;
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val)
+{
+ switch (attr) {
+ case hwmon_energy_input:
+ hwm_energy(ddat, val);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t
+hwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr)
+{
+ struct drm_i915_private *i915 = ddat->uncore->i915;
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_curr_crit:
+ return (hwm_pcode_read_i1(i915, &uval) ||
+ (uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val)
+{
+ int ret;
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_curr_crit:
+ ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
+ if (ret)
+ return ret;
+ if (uval & POWER_SETUP_I1_WATTS)
+ return -ENODEV;
+ *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
+ SF_CURR, POWER_SETUP_I1_SHIFT);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val)
+{
+ u32 uval;
+
+ switch (attr) {
+ case hwmon_curr_crit:
+ uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR);
+ return hwm_pcode_write_i1(ddat->uncore->i915, uval);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t
+hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
+
+ switch (type) {
+ case hwmon_in:
+ return hwm_in_is_visible(ddat, attr);
+ case hwmon_power:
+ return hwm_power_is_visible(ddat, attr, channel);
+ case hwmon_energy:
+ return hwm_energy_is_visible(ddat, attr);
+ case hwmon_curr:
+ return hwm_curr_is_visible(ddat, attr);
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_in:
+ return hwm_in_read(ddat, attr, val);
+ case hwmon_power:
+ return hwm_power_read(ddat, attr, channel, val);
+ case hwmon_energy:
+ return hwm_energy_read(ddat, attr, val);
+ case hwmon_curr:
+ return hwm_curr_read(ddat, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long val)
+{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_power:
+ return hwm_power_write(ddat, attr, channel, val);
+ case hwmon_curr:
+ return hwm_curr_write(ddat, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_ops hwm_ops = {
+ .is_visible = hwm_is_visible,
+ .read = hwm_read,
+ .write = hwm_write,
+};
+
+static const struct hwmon_chip_info hwm_chip_info = {
+ .ops = &hwm_ops,
+ .info = hwm_info,
+};
+
+static umode_t
+hwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
+
+ switch (type) {
+ case hwmon_energy:
+ return hwm_energy_is_visible(ddat, attr);
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_energy:
+ return hwm_energy_read(ddat, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_ops hwm_gt_ops = {
+ .is_visible = hwm_gt_is_visible,
+ .read = hwm_gt_read,
+};
+
+static const struct hwmon_chip_info hwm_gt_chip_info = {
+ .ops = &hwm_gt_ops,
+ .info = hwm_gt_info,
+};
+
+static void
+hwm_get_preregistration_info(struct drm_i915_private *i915)
+{
+ struct i915_hwmon *hwmon = i915->hwmon;
+ struct intel_uncore *uncore = &i915->uncore;
+ struct hwm_drvdata *ddat = &hwmon->ddat;
+ intel_wakeref_t wakeref;
+ u32 val_sku_unit = 0;
+ struct intel_gt *gt;
+ long energy;
+ int i;
+
+ /* Available for all Gen12+/dGfx */
+ hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
+
+ if (IS_DG1(i915) || IS_DG2(i915)) {
+ hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT;
+ hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU;
+ hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT;
+ hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS;
+ hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
+ } else if (IS_XEHPSDV(i915)) {
+ hwmon->rg.pkg_power_sku_unit = GT0_PACKAGE_POWER_SKU_UNIT;
+ hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
+ hwmon->rg.pkg_rapl_limit = GT0_PACKAGE_RAPL_LIMIT;
+ hwmon->rg.energy_status_all = GT0_PLATFORM_ENERGY_STATUS;
+ hwmon->rg.energy_status_tile = GT0_PACKAGE_ENERGY_STATUS;
+ } else {
+ hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG;
+ hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
+ hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG;
+ hwmon->rg.energy_status_all = INVALID_MMIO_REG;
+ hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
+ }
+
+ with_intel_runtime_pm(uncore->rpm, wakeref) {
+ /*
+ * The contents of register hwmon->rg.pkg_power_sku_unit do not change,
+ * so read it once and store the shift values.
+ */
+ if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit))
+ val_sku_unit = intel_uncore_read(uncore,
+ hwmon->rg.pkg_power_sku_unit);
+ }
+
+ hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
+ hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
+ hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
+
+ /*
+ * Initialize 'struct hwm_energy_info', i.e. set fields to the
+ * first value of the energy register read
+ */
+ if (i915_mmio_reg_valid(hwmon->rg.energy_status_all))
+ hwm_energy(ddat, &energy);
+ if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) {
+ for_each_gt(gt, i915, i)
+ hwm_energy(&hwmon->ddat_gt[i], &energy);
+ }
+}
+
+void i915_hwmon_register(struct drm_i915_private *i915)
+{
+ struct device *dev = i915->drm.dev;
+ struct i915_hwmon *hwmon;
+ struct device *hwmon_dev;
+ struct hwm_drvdata *ddat;
+ struct hwm_drvdata *ddat_gt;
+ struct intel_gt *gt;
+ int i;
+
+ /* hwmon is available only for dGfx */
+ if (!IS_DGFX(i915))
+ return;
+
+ hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+ if (!hwmon)
+ return;
+
+ i915->hwmon = hwmon;
+ mutex_init(&hwmon->hwmon_lock);
+ ddat = &hwmon->ddat;
+
+ ddat->hwmon = hwmon;
+ ddat->uncore = &i915->uncore;
+ snprintf(ddat->name, sizeof(ddat->name), "i915");
+ ddat->gt_n = -1;
+
+ for_each_gt(gt, i915, i) {
+ ddat_gt = hwmon->ddat_gt + i;
+
+ ddat_gt->hwmon = hwmon;
+ ddat_gt->uncore = gt->uncore;
+ snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i);
+ ddat_gt->gt_n = i;
+ }
+
+ hwm_get_preregistration_info(i915);
+
+ /* hwmon_dev points to device hwmon<i> */
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat->name,
+ ddat,
+ &hwm_chip_info,
+ hwm_groups);
+ if (IS_ERR(hwmon_dev)) {
+ i915->hwmon = NULL;
+ return;
+ }
+
+ ddat->hwmon_dev = hwmon_dev;
+
+ for_each_gt(gt, i915, i) {
+ ddat_gt = hwmon->ddat_gt + i;
+ /*
+ * Create per-gt directories only if a per-gt attribute is
+ * visible. Currently this is only energy
+ */
+ if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0))
+ continue;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat_gt->name,
+ ddat_gt,
+ &hwm_gt_chip_info,
+ NULL);
+ if (!IS_ERR(hwmon_dev))
+ ddat_gt->hwmon_dev = hwmon_dev;
+ }
+}
+
+void i915_hwmon_unregister(struct drm_i915_private *i915)
+{
+ fetch_and_zero(&i915->hwmon);
+}
diff --git a/drivers/gpu/drm/i915/i915_hwmon.h b/drivers/gpu/drm/i915/i915_hwmon.h
new file mode 100644
index 000000000000..7ca9cf2c34c9
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_hwmon.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __I915_HWMON_H__
+#define __I915_HWMON_H__
+
+struct drm_i915_private;
+
+#if IS_REACHABLE(CONFIG_HWMON)
+void i915_hwmon_register(struct drm_i915_private *i915);
+void i915_hwmon_unregister(struct drm_i915_private *i915);
+#else
+static inline void i915_hwmon_register(struct drm_i915_private *i915) { };
+static inline void i915_hwmon_unregister(struct drm_i915_private *i915) { };
+#endif
+
+#endif /* __I915_HWMON_H__ */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 86a42d9e8041..edfe363af838 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -28,7 +28,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/circ_buf.h>
#include <linux/slab.h>
#include <linux/sysrq.h>
@@ -248,7 +247,7 @@ void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
intel_uncore_posting_read(uncore, iir);
}
-void gen2_irq_reset(struct intel_uncore *uncore)
+static void gen2_irq_reset(struct intel_uncore *uncore)
{
intel_uncore_write16(uncore, GEN2_IMR, 0xffff);
intel_uncore_posting_read16(uncore, GEN2_IMR);
@@ -309,8 +308,8 @@ void gen3_irq_init(struct intel_uncore *uncore,
intel_uncore_posting_read(uncore, imr);
}
-void gen2_irq_init(struct intel_uncore *uncore,
- u32 imr_val, u32 ier_val)
+static void gen2_irq_init(struct intel_uncore *uncore,
+ u32 imr_val, u32 ier_val)
{
gen2_assert_iir_is_zero(uncore);
@@ -325,15 +324,10 @@ i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
u32 mask,
u32 bits)
{
- u32 val;
-
lockdep_assert_held(&dev_priv->irq_lock);
drm_WARN_ON(&dev_priv->drm, bits & ~mask);
- val = intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_EN);
- val &= ~mask;
- val |= bits;
- intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_EN, val);
+ intel_uncore_rmw(&dev_priv->uncore, PORT_HOTPLUG_EN, mask, bits);
}
/**
@@ -1057,8 +1051,8 @@ static void ivb_parity_work(struct work_struct *work)
if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice))
goto out;
- misccpctl = intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL);
- intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+ misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL,
+ GEN7_DOP_CLOCK_GATE_ENABLE, 0);
intel_uncore_posting_read(&dev_priv->uncore, GEN7_MISCCPCTL);
while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
@@ -1091,8 +1085,9 @@ static void ivb_parity_work(struct work_struct *work)
kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj,
KOBJ_CHANGE, parity_event);
- DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
- slice, row, bank, subbank);
+ drm_dbg(&dev_priv->drm,
+ "Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
+ slice, row, bank, subbank);
kfree(parity_event[4]);
kfree(parity_event[3]);
@@ -1689,8 +1684,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
* bits this time around.
*/
intel_uncore_write(&dev_priv->uncore, VLV_MASTER_IER, 0);
- ier = intel_uncore_read(&dev_priv->uncore, VLV_IER);
- intel_uncore_write(&dev_priv->uncore, VLV_IER, 0);
+ ier = intel_uncore_rmw(&dev_priv->uncore, VLV_IER, ~0, 0);
if (gt_iir)
intel_uncore_write(&dev_priv->uncore, GTIIR, gt_iir);
@@ -1775,8 +1769,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
* bits this time around.
*/
intel_uncore_write(&dev_priv->uncore, GEN8_MASTER_IRQ, 0);
- ier = intel_uncore_read(&dev_priv->uncore, VLV_IER);
- intel_uncore_write(&dev_priv->uncore, VLV_IER, 0);
+ ier = intel_uncore_rmw(&dev_priv->uncore, VLV_IER, ~0, 0);
gen8_gt_irq_handler(to_gt(dev_priv), master_ctl);
@@ -1981,8 +1974,7 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
if (ddi_hotplug_trigger) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_DDI);
- intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_DDI, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
ddi_hotplug_trigger, dig_hotplug_reg,
@@ -1993,8 +1985,7 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
if (tc_hotplug_trigger) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_TC);
- intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_TC, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
tc_hotplug_trigger, dig_hotplug_reg,
@@ -2019,8 +2010,7 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
if (hotplug_trigger) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
hotplug_trigger, dig_hotplug_reg,
@@ -2031,8 +2021,7 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
if (hotplug2_trigger) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG2);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG2, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
hotplug2_trigger, dig_hotplug_reg,
@@ -2052,8 +2041,7 @@ static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
{
u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL);
- intel_uncore_write(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
hotplug_trigger, dig_hotplug_reg,
@@ -2232,8 +2220,7 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
{
u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
hotplug_trigger, dig_hotplug_reg,
@@ -2252,8 +2239,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
if (trigger_tc) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL);
- intel_uncore_write(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
trigger_tc, dig_hotplug_reg,
@@ -2264,8 +2250,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
if (trigger_tbt) {
u32 dig_hotplug_reg;
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL);
- intel_uncore_write(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg);
+ dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, 0, 0);
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
trigger_tbt, dig_hotplug_reg,
@@ -2355,8 +2340,7 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
else
iir_reg = EDP_PSR_IIR;
- psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg);
- intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir);
+ psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0);
if (psr_iir)
found = true;
@@ -2426,8 +2410,7 @@ static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv,
/* clear TE in dsi IIR */
port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A;
- tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_IDENT_REG(port));
- intel_uncore_write(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), tmp);
+ tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0);
}
static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915)
@@ -2791,7 +2774,8 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg)
master_ctl = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, master_ctl);
} else {
- DRM_ERROR("Tile not supported: 0x%08x\n", master_tile_ctl);
+ drm_err(&i915->drm, "Tile not supported: 0x%08x\n",
+ master_tile_ctl);
dg1_master_intr_enable(regs);
return IRQ_NONE;
}
@@ -2884,7 +2868,6 @@ static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc,
{
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
enum port port;
- u32 tmp;
if (!(intel_crtc->mode_flags &
(I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0)))
@@ -2896,16 +2879,10 @@ static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc,
else
port = PORT_A;
- tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_MASK_REG(port));
- if (enable)
- tmp &= ~DSI_TE_EVENT;
- else
- tmp |= DSI_TE_EVENT;
-
- intel_uncore_write(&dev_priv->uncore, DSI_INTR_MASK_REG(port), tmp);
+ intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT,
+ enable ? 0 : DSI_TE_EVENT);
- tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_IDENT_REG(port));
- intel_uncore_write(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), tmp);
+ intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0);
return true;
}
@@ -3020,7 +2997,7 @@ static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV);
i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
- intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT));
+ intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0);
i9xx_pipestat_irq_reset(dev_priv);
@@ -3118,7 +3095,7 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv)
{
struct intel_uncore *uncore = &dev_priv->uncore;
- gen8_master_intr_disable(dev_priv->uncore.regs);
+ gen8_master_intr_disable(uncore->regs);
gen8_gt_irq_reset(to_gt(dev_priv));
gen8_display_irq_reset(dev_priv);
@@ -3250,7 +3227,7 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv)
{
struct intel_uncore *uncore = &dev_priv->uncore;
- intel_uncore_write(&dev_priv->uncore, GEN8_MASTER_IRQ, 0);
+ intel_uncore_write(uncore, GEN8_MASTER_IRQ, 0);
intel_uncore_posting_read(&dev_priv->uncore, GEN8_MASTER_IRQ);
gen8_gt_irq_reset(to_gt(dev_priv));
@@ -3290,23 +3267,20 @@ static u32 ibx_hotplug_enables(struct drm_i915_private *i915,
static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
/*
* Enable digital hotplug on the PCH, and configure the DP short pulse
* duration to 2ms (which is the minimum in the Display Port spec).
* The pulse duration bits are reserved on LPT+.
*/
- hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- hotplug &= ~(PORTA_HOTPLUG_ENABLE |
- PORTB_HOTPLUG_ENABLE |
- PORTC_HOTPLUG_ENABLE |
- PORTD_HOTPLUG_ENABLE |
- PORTB_PULSE_DURATION_MASK |
- PORTC_PULSE_DURATION_MASK |
- PORTD_PULSE_DURATION_MASK);
- hotplug |= intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG,
+ PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ PORTD_HOTPLUG_ENABLE |
+ PORTB_PULSE_DURATION_MASK |
+ PORTC_PULSE_DURATION_MASK |
+ PORTD_PULSE_DURATION_MASK,
+ intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables));
}
static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3353,30 +3327,24 @@ static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915,
static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
- hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_DDI);
- hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) |
- SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) |
- SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) |
- SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D));
- hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_DDI, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI,
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) |
+ SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D),
+ intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables));
}
static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
- hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_TC);
- hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) |
- ICP_TC_HPD_ENABLE(HPD_PORT_TC2) |
- ICP_TC_HPD_ENABLE(HPD_PORT_TC3) |
- ICP_TC_HPD_ENABLE(HPD_PORT_TC4) |
- ICP_TC_HPD_ENABLE(HPD_PORT_TC5) |
- ICP_TC_HPD_ENABLE(HPD_PORT_TC6));
- hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_TC, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC,
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC1) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC2) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC3) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC4) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC5) |
+ ICP_TC_HPD_ENABLE(HPD_PORT_TC6),
+ intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables));
}
static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3411,62 +3379,54 @@ static u32 gen11_hotplug_enables(struct drm_i915_private *i915,
}
}
-static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv)
+static void dg1_hpd_invert(struct drm_i915_private *i915)
{
- u32 val;
-
- val = intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN1);
- val |= (INVERT_DDIA_HPD |
- INVERT_DDIB_HPD |
- INVERT_DDIC_HPD |
- INVERT_DDID_HPD);
- intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN1, val);
+ u32 val = (INVERT_DDIA_HPD |
+ INVERT_DDIB_HPD |
+ INVERT_DDIC_HPD |
+ INVERT_DDID_HPD);
+ intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, 0, val);
+}
+static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv)
+{
+ dg1_hpd_invert(dev_priv);
icp_hpd_irq_setup(dev_priv);
}
static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
- hotplug = intel_uncore_read(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL);
- hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
- hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL,
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6),
+ intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables));
}
static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
- hotplug = intel_uncore_read(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL);
- hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
- GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
- hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL,
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+ GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6),
+ intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables));
}
static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
{
u32 hotplug_irqs, enabled_irqs;
- u32 val;
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd);
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd);
- val = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IMR);
- val &= ~hotplug_irqs;
- val |= ~enabled_irqs & hotplug_irqs;
- intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IMR, val);
+ intel_uncore_rmw(&dev_priv->uncore, GEN11_DE_HPD_IMR, hotplug_irqs,
+ ~enabled_irqs & hotplug_irqs);
intel_uncore_posting_read(&dev_priv->uncore, GEN11_DE_HPD_IMR);
gen11_tc_hpd_detection_setup(dev_priv);
@@ -3506,29 +3466,22 @@ static u32 spt_hotplug2_enables(struct drm_i915_private *i915,
static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 val, hotplug;
-
/* Display WA #1179 WaHardHangonHotPlug: cnp */
if (HAS_PCH_CNP(dev_priv)) {
- val = intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN1);
- val &= ~CHASSIS_CLK_REQ_DURATION_MASK;
- val |= CHASSIS_CLK_REQ_DURATION(0xf);
- intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN1, val);
+ intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN1, CHASSIS_CLK_REQ_DURATION_MASK,
+ CHASSIS_CLK_REQ_DURATION(0xf));
}
/* Enable digital hotplug on the PCH */
- hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- hotplug &= ~(PORTA_HOTPLUG_ENABLE |
- PORTB_HOTPLUG_ENABLE |
- PORTC_HOTPLUG_ENABLE |
- PORTD_HOTPLUG_ENABLE);
- hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG,
+ PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ PORTD_HOTPLUG_ENABLE,
+ intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables));
- hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG2);
- hotplug &= ~PORTE_HOTPLUG_ENABLE;
- hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG2, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, PORTE_HOTPLUG_ENABLE,
+ intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables));
}
static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3560,18 +3513,14 @@ static u32 ilk_hotplug_enables(struct drm_i915_private *i915,
static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
/*
* Enable digital hotplug on the CPU, and configure the DP short pulse
* duration to 2ms (which is the minimum in the Display Port spec)
* The pulse duration bits are reserved on HSW+.
*/
- hotplug = intel_uncore_read(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL);
- hotplug &= ~(DIGITAL_PORTA_HOTPLUG_ENABLE |
- DIGITAL_PORTA_PULSE_DURATION_MASK);
- hotplug |= intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL,
+ DIGITAL_PORTA_HOTPLUG_ENABLE | DIGITAL_PORTA_PULSE_DURATION_MASK,
+ intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables));
}
static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3619,17 +3568,12 @@ static u32 bxt_hotplug_enables(struct drm_i915_private *i915,
static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
{
- u32 hotplug;
-
- hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- hotplug &= ~(PORTA_HOTPLUG_ENABLE |
- PORTB_HOTPLUG_ENABLE |
- PORTC_HOTPLUG_ENABLE |
- BXT_DDIA_HPD_INVERT |
- BXT_DDIB_HPD_INVERT |
- BXT_DDIC_HPD_INVERT);
- hotplug |= intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables);
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug);
+ intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG,
+ PORTA_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE |
+ PORTC_HOTPLUG_ENABLE |
+ BXT_DDI_HPD_INVERT_MASK,
+ intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables));
}
static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3928,7 +3872,7 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv)
i9xx_pipestat_irq_reset(dev_priv);
- GEN2_IRQ_RESET(uncore);
+ gen2_irq_reset(uncore);
dev_priv->irq_mask = ~0u;
}
@@ -3954,7 +3898,7 @@ static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv)
I915_MASTER_ERROR_INTERRUPT |
I915_USER_INTERRUPT;
- GEN2_IRQ_INIT(uncore, dev_priv->irq_mask, enable_mask);
+ gen2_irq_init(uncore, dev_priv->irq_mask, enable_mask);
/* Interrupt setup is already guaranteed to be single-threaded, this is
* just to make the assert_spin_locked check happy. */
@@ -3997,7 +3941,7 @@ static void i8xx_error_irq_ack(struct drm_i915_private *i915,
static void i8xx_error_irq_handler(struct drm_i915_private *dev_priv,
u16 eir, u16 eir_stuck)
{
- DRM_DEBUG("Master Error: EIR 0x%04x\n", eir);
+ drm_dbg(&dev_priv->drm, "Master Error: EIR 0x%04x\n", eir);
if (eir_stuck)
drm_dbg(&dev_priv->drm, "EIR stuck: 0x%04x, masked\n",
@@ -4009,9 +3953,7 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
{
u32 emr;
- *eir = intel_uncore_read(&dev_priv->uncore, EIR);
-
- intel_uncore_write(&dev_priv->uncore, EIR, *eir);
+ *eir = intel_uncore_rmw(&dev_priv->uncore, EIR, 0, 0);
*eir_stuck = intel_uncore_read(&dev_priv->uncore, EIR);
if (*eir_stuck == 0)
@@ -4027,15 +3969,14 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
* (or by a GPU reset) so we mask any bit that
* remains set.
*/
- emr = intel_uncore_read(&dev_priv->uncore, EMR);
- intel_uncore_write(&dev_priv->uncore, EMR, 0xffffffff);
+ emr = intel_uncore_rmw(&dev_priv->uncore, EMR, ~0, 0xffffffff);
intel_uncore_write(&dev_priv->uncore, EMR, emr | *eir_stuck);
}
static void i9xx_error_irq_handler(struct drm_i915_private *dev_priv,
u32 eir, u32 eir_stuck)
{
- DRM_DEBUG("Master Error, EIR 0x%08x\n", eir);
+ drm_dbg(&dev_priv->drm, "Master Error, EIR 0x%08x\n", eir);
if (eir_stuck)
drm_dbg(&dev_priv->drm, "EIR stuck: 0x%08x, masked\n",
@@ -4095,7 +4036,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv)
if (I915_HAS_HOTPLUG(dev_priv)) {
i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
- intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT));
+ intel_uncore_rmw(&dev_priv->uncore, PORT_HOTPLUG_STAT, 0, 0);
}
i9xx_pipestat_irq_reset(dev_priv);
@@ -4109,8 +4050,8 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv)
struct intel_uncore *uncore = &dev_priv->uncore;
u32 enable_mask;
- intel_uncore_write(&dev_priv->uncore, EMR, ~(I915_ERROR_PAGE_TABLE |
- I915_ERROR_MEMORY_REFRESH));
+ intel_uncore_write(uncore, EMR, ~(I915_ERROR_PAGE_TABLE |
+ I915_ERROR_MEMORY_REFRESH));
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask =
@@ -4205,7 +4146,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv)
struct intel_uncore *uncore = &dev_priv->uncore;
i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
- intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT));
+ intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0);
i9xx_pipestat_irq_reset(dev_priv);
@@ -4232,7 +4173,7 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv)
error_mask = ~(I915_ERROR_PAGE_TABLE |
I915_ERROR_MEMORY_REFRESH);
}
- intel_uncore_write(&dev_priv->uncore, EMR, error_mask);
+ intel_uncore_write(uncore, EMR, error_mask);
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask =
@@ -4383,7 +4324,6 @@ void intel_hpd_irq_setup(struct drm_i915_private *i915)
*/
void intel_irq_init(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = &dev_priv->drm;
int i;
INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work);
@@ -4399,9 +4339,9 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
intel_hpd_init_pins(dev_priv);
- intel_hpd_init_work(dev_priv);
+ intel_hpd_init_early(dev_priv);
- dev->vblank_disable_immediate = true;
+ dev_priv->drm.vblank_disable_immediate = true;
/* Most platforms treat the display irq block as an always-on
* power domain. vlv/chv can disable it at runtime and need
@@ -4413,15 +4353,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
dev_priv->display_irqs_enabled = false;
- dev_priv->display.hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
- /* If we have MST support, we want to avoid doing short HPD IRQ storm
- * detection, as short HPD storms will occur as a natural part of
- * sideband messaging with MST.
- * On older platforms however, IRQ storms can occur with both long and
- * short pulses, as seen on some G4x systems.
- */
- dev_priv->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv);
-
if (HAS_GMCH(dev_priv)) {
if (I915_HAS_HOTPLUG(dev_priv))
dev_priv->display.funcs.hotplug = &i915_hpd_funcs;
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index 82639d9d7e82..9b004fc3444e 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -90,12 +90,9 @@ void i965_disable_vblank(struct drm_crtc *crtc);
void ilk_disable_vblank(struct drm_crtc *crtc);
void bdw_disable_vblank(struct drm_crtc *crtc);
-void gen2_irq_reset(struct intel_uncore *uncore);
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
i915_reg_t iir, i915_reg_t ier);
-void gen2_irq_init(struct intel_uncore *uncore,
- u32 imr_val, u32 ier_val);
void gen3_irq_init(struct intel_uncore *uncore,
i915_reg_t imr, u32 imr_val,
i915_reg_t ier, u32 ier_val,
@@ -111,9 +108,6 @@ void gen3_irq_init(struct intel_uncore *uncore,
#define GEN3_IRQ_RESET(uncore, type) \
gen3_irq_reset((uncore), type##IMR, type##IIR, type##IER)
-#define GEN2_IRQ_RESET(uncore) \
- gen2_irq_reset(uncore)
-
#define GEN8_IRQ_INIT_NDX(uncore, type, which, imr_val, ier_val) \
({ \
unsigned int which_ = which; \
@@ -129,7 +123,4 @@ void gen3_irq_init(struct intel_uncore *uncore,
type##IER, ier_val, \
type##IIR)
-#define GEN2_IRQ_INIT(uncore, imr_val, ier_val) \
- gen2_irq_init((uncore), imr_val, ier_val)
-
#endif /* __I915_IRQ_H__ */
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index cd4487a1d3be..6da9784fe4a2 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -1023,6 +1023,8 @@ static const struct intel_device_info adl_p_info = {
.has_logical_ring_contexts = 1, \
.has_logical_ring_elsq = 1, \
.has_mslice_steering = 1, \
+ .has_oa_bpc_reporting = 1, \
+ .has_oa_slice_contrib_limits = 1, \
.has_rc6 = 1, \
.has_reset_engine = 1, \
.has_rps = 1, \
@@ -1042,7 +1044,6 @@ static const struct intel_device_info xehpsdv_info = {
PLATFORM(INTEL_XEHPSDV),
NO_DISPLAY,
.has_64k_pages = 1,
- .needs_compact_pt = 1,
.has_media_ratio_mode = 1,
.__runtime.platform_engine_mask =
BIT(RCS0) | BIT(BCS0) |
@@ -1064,8 +1065,8 @@ static const struct intel_device_info xehpsdv_info = {
.has_64k_pages = 1, \
.has_guc_deprivilege = 1, \
.has_heci_pxp = 1, \
- .needs_compact_pt = 1, \
.has_media_ratio_mode = 1, \
+ .display.has_cdclk_squash = 1, \
.__runtime.platform_engine_mask = \
BIT(RCS0) | BIT(BCS0) | \
BIT(VECS0) | BIT(VECS1) | \
@@ -1077,7 +1078,6 @@ static const struct intel_device_info dg2_info = {
XE_LPD_FEATURES,
.__runtime.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
BIT(TRANSCODER_C) | BIT(TRANSCODER_D),
- .require_force_probe = 1,
};
static const struct intel_device_info ats_m_info = {
@@ -1144,6 +1144,9 @@ static const struct intel_device_info mtl_info = {
.display.has_modular_fia = 1,
.extra_gt_list = xelpmp_extra_gt,
.has_flat_ccs = 0,
+ .has_gmd_id = 1,
+ .has_guc_deprivilege = 1,
+ .has_mslice_steering = 0,
.has_snoop = 1,
.__runtime.memory_regions = REGION_SMEM | REGION_STOLEN_LMEM,
.__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(CCS0),
@@ -1296,9 +1299,7 @@ bool i915_pci_resource_valid(struct pci_dev *pdev, int bar)
static bool intel_mmio_bar_valid(struct pci_dev *pdev, struct intel_device_info *intel_info)
{
- int gttmmaddr_bar = intel_info->__runtime.graphics.ip.ver == 2 ? GEN2_GTTMMADR_BAR : GTTMMADR_BAR;
-
- return i915_pci_resource_valid(pdev, gttmmaddr_bar);
+ return i915_pci_resource_valid(pdev, intel_mmio_bar(intel_info->__runtime.graphics.ip.ver));
}
static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 0defbb43ceea..00e09bb18b13 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -204,15 +204,18 @@
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_clock_utils.h"
+#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_lrc.h"
#include "gt/intel_lrc_reg.h"
#include "gt/intel_ring.h"
+#include "gt/uc/intel_guc_slpc.h"
#include "i915_drv.h"
#include "i915_file_private.h"
#include "i915_perf.h"
#include "i915_perf_oa_regs.h"
+#include "i915_reg.h"
/* HW requires this to be a power of two, between 128k and 16M, though driver
* is currently generally designed assuming the largest 16M size is used such
@@ -286,6 +289,7 @@ static u32 i915_perf_stream_paranoid = true;
#define OAREPORT_REASON_CTX_SWITCH (1<<3)
#define OAREPORT_REASON_CLK_RATIO (1<<5)
+#define HAS_MI_SET_PREDICATE(i915) (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50))
/* For sysctl proc_dointvec_minmax of i915_oa_max_sample_rate
*
@@ -320,6 +324,8 @@ static const struct i915_oa_format oa_formats[I915_OA_FORMAT_MAX] = {
[I915_OA_FORMAT_A12] = { 0, 64 },
[I915_OA_FORMAT_A12_B8_C8] = { 2, 128 },
[I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 },
+ [I915_OAR_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 },
+ [I915_OA_FORMAT_A24u40_A14u32_B8_C8] = { 5, 256 },
};
#define SAMPLE_OA_REPORT (1<<0)
@@ -462,7 +468,7 @@ static u32 gen7_oa_hw_tail_read(struct i915_perf_stream *stream)
static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream)
{
u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma);
- int report_size = stream->oa_buffer.format_size;
+ int report_size = stream->oa_buffer.format->size;
unsigned long flags;
bool pollin;
u32 hw_tail;
@@ -525,9 +531,9 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream)
if (OA_TAKEN(hw_tail, tail) > report_size &&
__ratelimit(&stream->perf->tail_pointer_race))
- DRM_NOTE("unlanded report(s) head=0x%x "
- "tail=0x%x hw_tail=0x%x\n",
- head, tail, hw_tail);
+ drm_notice(&stream->uncore->i915->drm,
+ "unlanded report(s) head=0x%x tail=0x%x hw_tail=0x%x\n",
+ head, tail, hw_tail);
stream->oa_buffer.tail = gtt_offset + tail;
stream->oa_buffer.aging_tail = gtt_offset + hw_tail;
@@ -599,7 +605,7 @@ static int append_oa_sample(struct i915_perf_stream *stream,
size_t *offset,
const u8 *report)
{
- int report_size = stream->oa_buffer.format_size;
+ int report_size = stream->oa_buffer.format->size;
struct drm_i915_perf_record_header header;
header.type = DRM_I915_PERF_RECORD_SAMPLE;
@@ -649,14 +655,13 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream,
size_t *offset)
{
struct intel_uncore *uncore = stream->uncore;
- int report_size = stream->oa_buffer.format_size;
+ int report_size = stream->oa_buffer.format->size;
u8 *oa_buf_base = stream->oa_buffer.vaddr;
u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma);
u32 mask = (OA_BUFFER_SIZE - 1);
size_t start_offset = *offset;
unsigned long flags;
u32 head, tail;
- u32 taken;
int ret = 0;
if (drm_WARN_ON(&uncore->i915->drm, !stream->enabled))
@@ -692,7 +697,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream,
for (/* none */;
- (taken = OA_TAKEN(tail, head));
+ OA_TAKEN(tail, head);
head = (head + report_size) & mask) {
u8 *report = oa_buf_base + head;
u32 *report32 = (void *)report;
@@ -774,7 +779,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream,
* switches since it's not-uncommon for periodic samples to
* identify a switch before any 'context switch' report.
*/
- if (!stream->perf->exclusive_stream->ctx ||
+ if (!stream->ctx ||
stream->specific_ctx_id == ctx_id ||
stream->oa_buffer.last_ctx_id == stream->specific_ctx_id ||
reason & OAREPORT_REASON_CTX_SWITCH) {
@@ -783,7 +788,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream,
* While filtering for a single context we avoid
* leaking the IDs of other contexts.
*/
- if (stream->perf->exclusive_stream->ctx &&
+ if (stream->ctx &&
stream->specific_ctx_id != ctx_id) {
report32[2] = INVALID_CTX_ID;
}
@@ -943,14 +948,13 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream,
size_t *offset)
{
struct intel_uncore *uncore = stream->uncore;
- int report_size = stream->oa_buffer.format_size;
+ int report_size = stream->oa_buffer.format->size;
u8 *oa_buf_base = stream->oa_buffer.vaddr;
u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma);
u32 mask = (OA_BUFFER_SIZE - 1);
size_t start_offset = *offset;
unsigned long flags;
u32 head, tail;
- u32 taken;
int ret = 0;
if (drm_WARN_ON(&uncore->i915->drm, !stream->enabled))
@@ -984,7 +988,7 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream,
for (/* none */;
- (taken = OA_TAKEN(tail, head));
+ OA_TAKEN(tail, head);
head = (head + report_size) & mask) {
u8 *report = oa_buf_base + head;
u32 *report32 = (void *)report;
@@ -1012,7 +1016,8 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream,
*/
if (report32[0] == 0) {
if (__ratelimit(&stream->perf->spurious_report_rs))
- DRM_NOTE("Skipping spurious, invalid OA report\n");
+ drm_notice(&uncore->i915->drm,
+ "Skipping spurious, invalid OA report\n");
continue;
}
@@ -1233,6 +1238,196 @@ retry:
return stream->pinned_ctx;
}
+static int
+__store_reg_to_mem(struct i915_request *rq, i915_reg_t reg, u32 ggtt_offset)
+{
+ u32 *cs, cmd;
+
+ cmd = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
+ if (GRAPHICS_VER(rq->engine->i915) >= 8)
+ cmd++;
+
+ cs = intel_ring_begin(rq, 4);
+ if (IS_ERR(cs))
+ return PTR_ERR(cs);
+
+ *cs++ = cmd;
+ *cs++ = i915_mmio_reg_offset(reg);
+ *cs++ = ggtt_offset;
+ *cs++ = 0;
+
+ intel_ring_advance(rq, cs);
+
+ return 0;
+}
+
+static int
+__read_reg(struct intel_context *ce, i915_reg_t reg, u32 ggtt_offset)
+{
+ struct i915_request *rq;
+ int err;
+
+ rq = i915_request_create(ce);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ i915_request_get(rq);
+
+ err = __store_reg_to_mem(rq, reg, ggtt_offset);
+
+ i915_request_add(rq);
+ if (!err && i915_request_wait(rq, 0, HZ / 2) < 0)
+ err = -ETIME;
+
+ i915_request_put(rq);
+
+ return err;
+}
+
+static int
+gen12_guc_sw_ctx_id(struct intel_context *ce, u32 *ctx_id)
+{
+ struct i915_vma *scratch;
+ u32 *val;
+ int err;
+
+ scratch = __vm_create_scratch_for_read_pinned(&ce->engine->gt->ggtt->vm, 4);
+ if (IS_ERR(scratch))
+ return PTR_ERR(scratch);
+
+ err = i915_vma_sync(scratch);
+ if (err)
+ goto err_scratch;
+
+ err = __read_reg(ce, RING_EXECLIST_STATUS_HI(ce->engine->mmio_base),
+ i915_ggtt_offset(scratch));
+ if (err)
+ goto err_scratch;
+
+ val = i915_gem_object_pin_map_unlocked(scratch->obj, I915_MAP_WB);
+ if (IS_ERR(val)) {
+ err = PTR_ERR(val);
+ goto err_scratch;
+ }
+
+ *ctx_id = *val;
+ i915_gem_object_unpin_map(scratch->obj);
+
+err_scratch:
+ i915_vma_unpin_and_release(&scratch, 0);
+ return err;
+}
+
+/*
+ * For execlist mode of submission, pick an unused context id
+ * 0 - (NUM_CONTEXT_TAG -1) are used by other contexts
+ * XXX_MAX_CONTEXT_HW_ID is used by idle context
+ *
+ * For GuC mode of submission read context id from the upper dword of the
+ * EXECLIST_STATUS register. Note that we read this value only once and expect
+ * that the value stays fixed for the entire OA use case. There are cases where
+ * GuC KMD implementation may deregister a context to reuse it's context id, but
+ * we prevent that from happening to the OA context by pinning it.
+ */
+static int gen12_get_render_context_id(struct i915_perf_stream *stream)
+{
+ u32 ctx_id, mask;
+ int ret;
+
+ if (intel_engine_uses_guc(stream->engine)) {
+ ret = gen12_guc_sw_ctx_id(stream->pinned_ctx, &ctx_id);
+ if (ret)
+ return ret;
+
+ mask = ((1U << GEN12_GUC_SW_CTX_ID_WIDTH) - 1) <<
+ (GEN12_GUC_SW_CTX_ID_SHIFT - 32);
+ } else if (GRAPHICS_VER_FULL(stream->engine->i915) >= IP_VER(12, 50)) {
+ ctx_id = (XEHP_MAX_CONTEXT_HW_ID - 1) <<
+ (XEHP_SW_CTX_ID_SHIFT - 32);
+
+ mask = ((1U << XEHP_SW_CTX_ID_WIDTH) - 1) <<
+ (XEHP_SW_CTX_ID_SHIFT - 32);
+ } else {
+ ctx_id = (GEN12_MAX_CONTEXT_HW_ID - 1) <<
+ (GEN11_SW_CTX_ID_SHIFT - 32);
+
+ mask = ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) <<
+ (GEN11_SW_CTX_ID_SHIFT - 32);
+ }
+ stream->specific_ctx_id = ctx_id & mask;
+ stream->specific_ctx_id_mask = mask;
+
+ return 0;
+}
+
+static bool oa_find_reg_in_lri(u32 *state, u32 reg, u32 *offset, u32 end)
+{
+ u32 idx = *offset;
+ u32 len = min(MI_LRI_LEN(state[idx]) + idx, end);
+ bool found = false;
+
+ idx++;
+ for (; idx < len; idx += 2) {
+ if (state[idx] == reg) {
+ found = true;
+ break;
+ }
+ }
+
+ *offset = idx;
+ return found;
+}
+
+static u32 oa_context_image_offset(struct intel_context *ce, u32 reg)
+{
+ u32 offset, len = (ce->engine->context_size - PAGE_SIZE) / 4;
+ u32 *state = ce->lrc_reg_state;
+
+ for (offset = 0; offset < len; ) {
+ if (IS_MI_LRI_CMD(state[offset])) {
+ /*
+ * We expect reg-value pairs in MI_LRI command, so
+ * MI_LRI_LEN() should be even, if not, issue a warning.
+ */
+ drm_WARN_ON(&ce->engine->i915->drm,
+ MI_LRI_LEN(state[offset]) & 0x1);
+
+ if (oa_find_reg_in_lri(state, reg, &offset, len))
+ break;
+ } else {
+ offset++;
+ }
+ }
+
+ return offset < len ? offset : U32_MAX;
+}
+
+static int set_oa_ctx_ctrl_offset(struct intel_context *ce)
+{
+ i915_reg_t reg = GEN12_OACTXCONTROL(ce->engine->mmio_base);
+ struct i915_perf *perf = &ce->engine->i915->perf;
+ u32 offset = perf->ctx_oactxctrl_offset;
+
+ /* Do this only once. Failure is stored as offset of U32_MAX */
+ if (offset)
+ goto exit;
+
+ offset = oa_context_image_offset(ce, i915_mmio_reg_offset(reg));
+ perf->ctx_oactxctrl_offset = offset;
+
+ drm_dbg(&ce->engine->i915->drm,
+ "%s oa ctx control at 0x%08x dword offset\n",
+ ce->engine->name, offset);
+
+exit:
+ return offset && offset != U32_MAX ? 0 : -ENODEV;
+}
+
+static bool engine_supports_mi_query(struct intel_engine_cs *engine)
+{
+ return engine->class == RENDER_CLASS;
+}
+
/**
* oa_get_render_ctx_id - determine and hold ctx hw id
* @stream: An i915-perf stream opened for OA metrics
@@ -1246,11 +1441,27 @@ retry:
static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
{
struct intel_context *ce;
+ int ret = 0;
ce = oa_pin_context(stream);
if (IS_ERR(ce))
return PTR_ERR(ce);
+ if (engine_supports_mi_query(stream->engine)) {
+ /*
+ * We are enabling perf query here. If we don't find the context
+ * offset here, just return an error.
+ */
+ ret = set_oa_ctx_ctrl_offset(ce);
+ if (ret) {
+ intel_context_unpin(ce);
+ drm_err(&stream->perf->i915->drm,
+ "Enabling perf query failed for %s\n",
+ stream->engine->name);
+ return ret;
+ }
+ }
+
switch (GRAPHICS_VER(ce->engine->i915)) {
case 7: {
/*
@@ -1292,24 +1503,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
case 11:
case 12:
- if (GRAPHICS_VER_FULL(ce->engine->i915) >= IP_VER(12, 50)) {
- stream->specific_ctx_id_mask =
- ((1U << XEHP_SW_CTX_ID_WIDTH) - 1) <<
- (XEHP_SW_CTX_ID_SHIFT - 32);
- stream->specific_ctx_id =
- (XEHP_MAX_CONTEXT_HW_ID - 1) <<
- (XEHP_SW_CTX_ID_SHIFT - 32);
- } else {
- stream->specific_ctx_id_mask =
- ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << (GEN11_SW_CTX_ID_SHIFT - 32);
- /*
- * Pick an unused context id
- * 0 - BITS_PER_LONG are used by other contexts
- * GEN12_MAX_CONTEXT_HW_ID (0x7ff) is used by idle context
- */
- stream->specific_ctx_id =
- (GEN12_MAX_CONTEXT_HW_ID - 1) << (GEN11_SW_CTX_ID_SHIFT - 32);
- }
+ ret = gen12_get_render_context_id(stream);
break;
default:
@@ -1323,7 +1517,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
stream->specific_ctx_id,
stream->specific_ctx_id_mask);
- return 0;
+ return ret;
}
/**
@@ -1375,8 +1569,9 @@ free_noa_wait(struct i915_perf_stream *stream)
static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
{
struct i915_perf *perf = stream->perf;
+ struct intel_gt *gt = stream->engine->gt;
- if (WARN_ON(stream != perf->exclusive_stream))
+ if (WARN_ON(stream != gt->perf.exclusive_stream))
return;
/*
@@ -1385,11 +1580,20 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
*
* See i915_oa_init_reg_state() and lrc_configure_all_contexts()
*/
- WRITE_ONCE(perf->exclusive_stream, NULL);
+ WRITE_ONCE(gt->perf.exclusive_stream, NULL);
perf->ops.disable_metric_set(stream);
free_oa_buffer(stream);
+ /*
+ * Wa_16011777198:dg2: Unset the override of GUCRC mode to enable rc6.
+ */
+ if (intel_uc_uses_guc_rc(&gt->uc) &&
+ (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) ||
+ IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)))
+ drm_WARN_ON(&gt->i915->drm,
+ intel_guc_slpc_unset_gucrc_mode(&gt->uc.guc.slpc));
+
intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL);
intel_engine_pm_put(stream->engine);
@@ -1400,8 +1604,9 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
free_noa_wait(stream);
if (perf->spurious_report_rs.missed) {
- DRM_NOTE("%d spurious OA report notices suppressed due to ratelimiting\n",
- perf->spurious_report_rs.missed);
+ drm_notice(&gt->i915->drm,
+ "%d spurious OA report notices suppressed due to ratelimiting\n",
+ perf->spurious_report_rs.missed);
}
}
@@ -1563,6 +1768,7 @@ static void gen12_init_oa_buffer(struct i915_perf_stream *stream)
static int alloc_oa_buffer(struct i915_perf_stream *stream)
{
struct drm_i915_private *i915 = stream->perf->i915;
+ struct intel_gt *gt = stream->engine->gt;
struct drm_i915_gem_object *bo;
struct i915_vma *vma;
int ret;
@@ -1582,11 +1788,22 @@ static int alloc_oa_buffer(struct i915_perf_stream *stream)
i915_gem_object_set_cache_coherency(bo, I915_CACHE_LLC);
/* PreHSW required 512K alignment, HSW requires 16M */
- vma = i915_gem_object_ggtt_pin(bo, NULL, 0, SZ_16M, 0);
+ vma = i915_vma_instance(bo, &gt->ggtt->vm, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto err_unref;
}
+
+ /*
+ * PreHSW required 512K alignment.
+ * HSW and onwards, align to requested size of OA buffer.
+ */
+ ret = i915_vma_pin(vma, 0, SZ_16M, PIN_GLOBAL | PIN_HIGH);
+ if (ret) {
+ drm_err(&gt->i915->drm, "Failed to pin OA buffer %d\n", ret);
+ goto err_unref;
+ }
+
stream->oa_buffer.vma = vma;
stream->oa_buffer.vaddr =
@@ -1636,6 +1853,7 @@ static u32 *save_restore_register(struct i915_perf_stream *stream, u32 *cs,
static int alloc_noa_wait(struct i915_perf_stream *stream)
{
struct drm_i915_private *i915 = stream->perf->i915;
+ struct intel_gt *gt = stream->engine->gt;
struct drm_i915_gem_object *bo;
struct i915_vma *vma;
const u64 delay_ticks = 0xffffffffffffffff -
@@ -1654,6 +1872,9 @@ static int alloc_noa_wait(struct i915_perf_stream *stream)
DELTA_TARGET,
N_CS_GPR
};
+ i915_reg_t mi_predicate_result = HAS_MI_SET_PREDICATE(i915) ?
+ MI_PREDICATE_RESULT_2_ENGINE(base) :
+ MI_PREDICATE_RESULT_1(RENDER_RING_BASE);
bo = i915_gem_object_create_internal(i915, 4096);
if (IS_ERR(bo)) {
@@ -1673,12 +1894,16 @@ retry:
* multiple OA config BOs will have a jump to this address and it
* needs to be fixed during the lifetime of the i915/perf stream.
*/
- vma = i915_gem_object_ggtt_pin_ww(bo, &ww, NULL, 0, 0, PIN_HIGH);
+ vma = i915_vma_instance(bo, &gt->ggtt->vm, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto out_ww;
}
+ ret = i915_vma_pin_ww(vma, &ww, 0, 0, PIN_GLOBAL | PIN_HIGH);
+ if (ret)
+ goto out_ww;
+
batch = cs = i915_gem_object_pin_map(bo, I915_MAP_WB);
if (IS_ERR(batch)) {
ret = PTR_ERR(batch);
@@ -1691,7 +1916,7 @@ retry:
stream, cs, true /* save */, CS_GPR(i),
INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2);
cs = save_restore_register(
- stream, cs, true /* save */, MI_PREDICATE_RESULT_1(RENDER_RING_BASE),
+ stream, cs, true /* save */, mi_predicate_result,
INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1);
/* First timestamp snapshot location. */
@@ -1745,7 +1970,10 @@ retry:
*/
*cs++ = MI_LOAD_REGISTER_REG | (3 - 2);
*cs++ = i915_mmio_reg_offset(CS_GPR(JUMP_PREDICATE));
- *cs++ = i915_mmio_reg_offset(MI_PREDICATE_RESULT_1(RENDER_RING_BASE));
+ *cs++ = i915_mmio_reg_offset(mi_predicate_result);
+
+ if (HAS_MI_SET_PREDICATE(i915))
+ *cs++ = MI_SET_PREDICATE | 1;
/* Restart from the beginning if we had timestamps roll over. */
*cs++ = (GRAPHICS_VER(i915) < 8 ?
@@ -1755,6 +1983,9 @@ retry:
*cs++ = i915_ggtt_offset(vma) + (ts0 - batch) * 4;
*cs++ = 0;
+ if (HAS_MI_SET_PREDICATE(i915))
+ *cs++ = MI_SET_PREDICATE;
+
/*
* Now add the diff between to previous timestamps and add it to :
* (((1 * << 64) - 1) - delay_ns)
@@ -1782,7 +2013,10 @@ retry:
*/
*cs++ = MI_LOAD_REGISTER_REG | (3 - 2);
*cs++ = i915_mmio_reg_offset(CS_GPR(JUMP_PREDICATE));
- *cs++ = i915_mmio_reg_offset(MI_PREDICATE_RESULT_1(RENDER_RING_BASE));
+ *cs++ = i915_mmio_reg_offset(mi_predicate_result);
+
+ if (HAS_MI_SET_PREDICATE(i915))
+ *cs++ = MI_SET_PREDICATE | 1;
/* Predicate the jump. */
*cs++ = (GRAPHICS_VER(i915) < 8 ?
@@ -1792,13 +2026,16 @@ retry:
*cs++ = i915_ggtt_offset(vma) + (jump - batch) * 4;
*cs++ = 0;
+ if (HAS_MI_SET_PREDICATE(i915))
+ *cs++ = MI_SET_PREDICATE;
+
/* Restore registers. */
for (i = 0; i < N_CS_GPR; i++)
cs = save_restore_register(
stream, cs, false /* restore */, CS_GPR(i),
INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2);
cs = save_restore_register(
- stream, cs, false /* restore */, MI_PREDICATE_RESULT_1(RENDER_RING_BASE),
+ stream, cs, false /* restore */, mi_predicate_result,
INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1);
/* And return to the ring. */
@@ -2017,9 +2254,7 @@ retry:
goto err_add_request;
}
- err = i915_request_await_object(rq, vma->obj, 0);
- if (!err)
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = i915_vma_move_to_active(vma, rq, 0);
if (err)
goto err_add_request;
@@ -2283,11 +2518,12 @@ static int gen12_configure_oar_context(struct i915_perf_stream *stream,
{
int err;
struct intel_context *ce = stream->pinned_ctx;
- u32 format = stream->oa_buffer.format;
+ u32 format = stream->oa_buffer.format->format;
+ u32 offset = stream->perf->ctx_oactxctrl_offset;
struct flex regs_context[] = {
{
GEN8_OACTXCONTROL,
- stream->perf->ctx_oactxctrl_offset + 1,
+ offset + 1,
active ? GEN8_OA_COUNTER_RESUME : 0,
},
};
@@ -2312,12 +2548,13 @@ static int gen12_configure_oar_context(struct i915_perf_stream *stream,
},
};
- /* Modify the context image of pinned context with regs_context*/
+ /* Modify the context image of pinned context with regs_context */
err = intel_context_lock_pinned(ce);
if (err)
return err;
- err = gen8_modify_context(ce, regs_context, ARRAY_SIZE(regs_context));
+ err = gen8_modify_context(ce, regs_context,
+ ARRAY_SIZE(regs_context));
intel_context_unlock_pinned(ce);
if (err)
return err;
@@ -2359,10 +2596,11 @@ oa_configure_all_contexts(struct i915_perf_stream *stream,
{
struct drm_i915_private *i915 = stream->perf->i915;
struct intel_engine_cs *engine;
+ struct intel_gt *gt = stream->engine->gt;
struct i915_gem_context *ctx, *cn;
int err;
- lockdep_assert_held(&stream->perf->lock);
+ lockdep_assert_held(&gt->perf.lock);
/*
* The OA register config is setup through the context image. This image
@@ -2442,6 +2680,7 @@ lrc_configure_all_contexts(struct i915_perf_stream *stream,
const struct i915_oa_config *oa_config,
struct i915_active *active)
{
+ u32 ctx_oactxctrl = stream->perf->ctx_oactxctrl_offset;
/* The MMIO offsets for Flex EU registers aren't contiguous */
const u32 ctx_flexeu0 = stream->perf->ctx_flexeu0_offset;
#define ctx_flexeuN(N) (ctx_flexeu0 + 2 * (N) + 1)
@@ -2452,7 +2691,7 @@ lrc_configure_all_contexts(struct i915_perf_stream *stream,
},
{
GEN8_OACTXCONTROL,
- stream->perf->ctx_oactxctrl_offset + 1,
+ ctx_oactxctrl + 1,
},
{ EU_PERF_CNTL0, ctx_flexeuN(0) },
{ EU_PERF_CNTL1, ctx_flexeuN(1) },
@@ -2540,12 +2779,26 @@ static int
gen12_enable_metric_set(struct i915_perf_stream *stream,
struct i915_active *active)
{
+ struct drm_i915_private *i915 = stream->perf->i915;
struct intel_uncore *uncore = stream->uncore;
struct i915_oa_config *oa_config = stream->oa_config;
bool periodic = stream->periodic;
u32 period_exponent = stream->period_exponent;
+ u32 sqcnt1;
int ret;
+ /*
+ * Wa_1508761755:xehpsdv, dg2
+ * EU NOA signals behave incorrectly if EU clock gating is enabled.
+ * Disable thread stall DOP gating and EU DOP gating.
+ */
+ if (IS_XEHPSDV(i915) || IS_DG2(i915)) {
+ intel_gt_mcr_multicast_write(uncore->gt, GEN8_ROW_CHICKEN,
+ _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
+ intel_uncore_write(uncore, GEN7_ROW_CHICKEN2,
+ _MASKED_BIT_ENABLE(GEN12_DISABLE_DOP_GATING));
+ }
+
intel_uncore_write(uncore, GEN12_OAG_OA_DEBUG,
/* Disable clk ratio reports, like previous Gens. */
_MASKED_BIT_ENABLE(GEN12_OAG_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS |
@@ -2563,6 +2816,16 @@ gen12_enable_metric_set(struct i915_perf_stream *stream,
: 0);
/*
+ * Initialize Super Queue Internal Cnt Register
+ * Set PMON Enable in order to collect valid metrics.
+ * Enable byets per clock reporting in OA for XEHPSDV onward.
+ */
+ sqcnt1 = GEN12_SQCNT1_PMON_ENABLE |
+ (HAS_OA_BPC_REPORTING(i915) ? GEN12_SQCNT1_OABPC : 0);
+
+ intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1);
+
+ /*
* Update all contexts prior writing the mux configurations as we need
* to make sure all slices/subslices are ON before writing to NOA
* registers.
@@ -2611,6 +2874,19 @@ static void gen11_disable_metric_set(struct i915_perf_stream *stream)
static void gen12_disable_metric_set(struct i915_perf_stream *stream)
{
struct intel_uncore *uncore = stream->uncore;
+ struct drm_i915_private *i915 = stream->perf->i915;
+ u32 sqcnt1;
+
+ /*
+ * Wa_1508761755:xehpsdv, dg2
+ * Enable thread stall DOP gating and EU DOP gating.
+ */
+ if (IS_XEHPSDV(i915) || IS_DG2(i915)) {
+ intel_gt_mcr_multicast_write(uncore->gt, GEN8_ROW_CHICKEN,
+ _MASKED_BIT_DISABLE(STALL_DOP_GATING_DISABLE));
+ intel_uncore_write(uncore, GEN7_ROW_CHICKEN2,
+ _MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING));
+ }
/* Reset all contexts' slices/subslices configurations. */
gen12_configure_all_contexts(stream, NULL, NULL);
@@ -2621,6 +2897,12 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream)
/* Make sure we disable noa to save power. */
intel_uncore_rmw(uncore, RPM_CONFIG1, GEN10_GT_NOA_ENABLE, 0);
+
+ sqcnt1 = GEN12_SQCNT1_PMON_ENABLE |
+ (HAS_OA_BPC_REPORTING(i915) ? GEN12_SQCNT1_OABPC : 0);
+
+ /* Reset PMON Enable to save power. */
+ intel_uncore_rmw(uncore, GEN12_SQCNT1, sqcnt1, 0);
}
static void gen7_oa_enable(struct i915_perf_stream *stream)
@@ -2630,7 +2912,7 @@ static void gen7_oa_enable(struct i915_perf_stream *stream)
u32 ctx_id = stream->specific_ctx_id;
bool periodic = stream->periodic;
u32 period_exponent = stream->period_exponent;
- u32 report_format = stream->oa_buffer.format;
+ u32 report_format = stream->oa_buffer.format->format;
/*
* Reset buf pointers so we don't forward reports from before now.
@@ -2656,7 +2938,7 @@ static void gen7_oa_enable(struct i915_perf_stream *stream)
static void gen8_oa_enable(struct i915_perf_stream *stream)
{
struct intel_uncore *uncore = stream->uncore;
- u32 report_format = stream->oa_buffer.format;
+ u32 report_format = stream->oa_buffer.format->format;
/*
* Reset buf pointers so we don't forward reports from before now.
@@ -2682,7 +2964,7 @@ static void gen8_oa_enable(struct i915_perf_stream *stream)
static void gen12_oa_enable(struct i915_perf_stream *stream)
{
struct intel_uncore *uncore = stream->uncore;
- u32 report_format = stream->oa_buffer.format;
+ u32 report_format = stream->oa_buffer.format->format;
/*
* If we don't want OA reports from the OA buffer, then we don't even
@@ -2838,6 +3120,30 @@ get_sseu_config(struct intel_sseu *out_sseu,
return i915_gem_user_to_context_sseu(engine->gt, drm_sseu, out_sseu);
}
+/*
+ * OA timestamp frequency = CS timestamp frequency in most platforms. On some
+ * platforms OA unit ignores the CTC_SHIFT and the 2 timestamps differ. In such
+ * cases, return the adjusted CS timestamp frequency to the user.
+ */
+u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915)
+{
+ /* Wa_18013179988:dg2 */
+ if (IS_DG2(i915)) {
+ intel_wakeref_t wakeref;
+ u32 reg, shift;
+
+ with_intel_runtime_pm(to_gt(i915)->uncore->rpm, wakeref)
+ reg = intel_uncore_read(to_gt(i915)->uncore, RPM_CONFIG0);
+
+ shift = REG_FIELD_GET(GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK,
+ reg);
+
+ return to_gt(i915)->clock_frequency << (3 - shift);
+ }
+
+ return to_gt(i915)->clock_frequency;
+}
+
/**
* i915_oa_stream_init - validate combined props for OA stream and init
* @stream: An i915 perf stream
@@ -2862,7 +3168,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
{
struct drm_i915_private *i915 = stream->perf->i915;
struct i915_perf *perf = stream->perf;
- int format_size;
+ struct intel_gt *gt;
int ret;
if (!props->engine) {
@@ -2870,6 +3176,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
"OA engine not specified\n");
return -EINVAL;
}
+ gt = props->engine->gt;
/*
* If the sysfs metrics/ directory wasn't registered for some
@@ -2900,7 +3207,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
* counter reports and marshal to the appropriate client
* we currently only allow exclusive access
*/
- if (perf->exclusive_stream) {
+ if (gt->perf.exclusive_stream) {
drm_dbg(&stream->perf->i915->drm,
"OA unit already in use\n");
return -EBUSY;
@@ -2917,20 +3224,15 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
stream->sample_size = sizeof(struct drm_i915_perf_record_header);
- format_size = perf->oa_formats[props->oa_format].size;
+ stream->oa_buffer.format = &perf->oa_formats[props->oa_format];
+ if (drm_WARN_ON(&i915->drm, stream->oa_buffer.format->size == 0))
+ return -EINVAL;
stream->sample_flags = props->sample_flags;
- stream->sample_size += format_size;
-
- stream->oa_buffer.format_size = format_size;
- if (drm_WARN_ON(&i915->drm, stream->oa_buffer.format_size == 0))
- return -EINVAL;
+ stream->sample_size += stream->oa_buffer.format->size;
stream->hold_preemption = props->hold_preemption;
- stream->oa_buffer.format =
- perf->oa_formats[props->oa_format].format;
-
stream->periodic = props->oa_periodic;
if (stream->periodic)
stream->period_exponent = props->oa_period_exponent;
@@ -2974,14 +3276,31 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
intel_engine_pm_get(stream->engine);
intel_uncore_forcewake_get(stream->uncore, FORCEWAKE_ALL);
+ /*
+ * Wa_16011777198:dg2: GuC resets render as part of the Wa. This causes
+ * OA to lose the configuration state. Prevent this by overriding GUCRC
+ * mode.
+ */
+ if (intel_uc_uses_guc_rc(&gt->uc) &&
+ (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) ||
+ IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) {
+ ret = intel_guc_slpc_override_gucrc_mode(&gt->uc.guc.slpc,
+ SLPC_GUCRC_MODE_GUCRC_NO_RC6);
+ if (ret) {
+ drm_dbg(&stream->perf->i915->drm,
+ "Unable to override gucrc mode\n");
+ goto err_config;
+ }
+ }
+
ret = alloc_oa_buffer(stream);
if (ret)
goto err_oa_buf_alloc;
stream->ops = &i915_oa_stream_ops;
- perf->sseu = props->sseu;
- WRITE_ONCE(perf->exclusive_stream, stream);
+ stream->engine->gt->perf.sseu = props->sseu;
+ WRITE_ONCE(gt->perf.exclusive_stream, stream);
ret = i915_perf_stream_enable_sync(stream);
if (ret) {
@@ -2999,11 +3318,12 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
stream->poll_check_timer.function = oa_poll_check_timer_cb;
init_waitqueue_head(&stream->poll_wq);
spin_lock_init(&stream->oa_buffer.ptr_lock);
+ mutex_init(&stream->lock);
return 0;
err_enable:
- WRITE_ONCE(perf->exclusive_stream, NULL);
+ WRITE_ONCE(gt->perf.exclusive_stream, NULL);
perf->ops.disable_metric_set(stream);
free_oa_buffer(stream);
@@ -3033,7 +3353,7 @@ void i915_oa_init_reg_state(const struct intel_context *ce,
return;
/* perf.exclusive_stream serialised by lrc_configure_all_contexts() */
- stream = READ_ONCE(engine->i915->perf.exclusive_stream);
+ stream = READ_ONCE(engine->gt->perf.exclusive_stream);
if (stream && GRAPHICS_VER(stream->perf->i915) < 12)
gen8_update_reg_state_unlocked(ce, stream);
}
@@ -3062,7 +3382,6 @@ static ssize_t i915_perf_read(struct file *file,
loff_t *ppos)
{
struct i915_perf_stream *stream = file->private_data;
- struct i915_perf *perf = stream->perf;
size_t offset = 0;
int ret;
@@ -3086,14 +3405,14 @@ static ssize_t i915_perf_read(struct file *file,
if (ret)
return ret;
- mutex_lock(&perf->lock);
+ mutex_lock(&stream->lock);
ret = stream->ops->read(stream, buf, count, &offset);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&stream->lock);
} while (!offset && !ret);
} else {
- mutex_lock(&perf->lock);
+ mutex_lock(&stream->lock);
ret = stream->ops->read(stream, buf, count, &offset);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&stream->lock);
}
/* We allow the poll checking to sometimes report false positive EPOLLIN
@@ -3140,9 +3459,6 @@ static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer)
* &i915_perf_stream_ops->poll_wait to call poll_wait() with a wait queue that
* will be woken for new stream data.
*
- * Note: The &perf->lock mutex has been taken to serialize
- * with any non-file-operation driver hooks.
- *
* Returns: any poll events that are ready without sleeping
*/
static __poll_t i915_perf_poll_locked(struct i915_perf_stream *stream,
@@ -3181,12 +3497,11 @@ static __poll_t i915_perf_poll_locked(struct i915_perf_stream *stream,
static __poll_t i915_perf_poll(struct file *file, poll_table *wait)
{
struct i915_perf_stream *stream = file->private_data;
- struct i915_perf *perf = stream->perf;
__poll_t ret;
- mutex_lock(&perf->lock);
+ mutex_lock(&stream->lock);
ret = i915_perf_poll_locked(stream, file, wait);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&stream->lock);
return ret;
}
@@ -3285,9 +3600,6 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
* @cmd: the ioctl request
* @arg: the ioctl data
*
- * Note: The &perf->lock mutex has been taken to serialize
- * with any non-file-operation driver hooks.
- *
* Returns: zero on success or a negative error code. Returns -EINVAL for
* an unknown ioctl request.
*/
@@ -3325,12 +3637,11 @@ static long i915_perf_ioctl(struct file *file,
unsigned long arg)
{
struct i915_perf_stream *stream = file->private_data;
- struct i915_perf *perf = stream->perf;
long ret;
- mutex_lock(&perf->lock);
+ mutex_lock(&stream->lock);
ret = i915_perf_ioctl_locked(stream, cmd, arg);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&stream->lock);
return ret;
}
@@ -3342,7 +3653,7 @@ static long i915_perf_ioctl(struct file *file,
* Frees all resources associated with the given i915 perf @stream, disabling
* any associated data capture in the process.
*
- * Note: The &perf->lock mutex has been taken to serialize
+ * Note: The &gt->perf.lock mutex has been taken to serialize
* with any non-file-operation driver hooks.
*/
static void i915_perf_destroy_locked(struct i915_perf_stream *stream)
@@ -3374,10 +3685,16 @@ static int i915_perf_release(struct inode *inode, struct file *file)
{
struct i915_perf_stream *stream = file->private_data;
struct i915_perf *perf = stream->perf;
+ struct intel_gt *gt = stream->engine->gt;
- mutex_lock(&perf->lock);
+ /*
+ * Within this call, we know that the fd is being closed and we have no
+ * other user of stream->lock. Use the perf lock to destroy the stream
+ * here.
+ */
+ mutex_lock(&gt->perf.lock);
i915_perf_destroy_locked(stream);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&gt->perf.lock);
/* Release the reference the perf stream kept on the driver. */
drm_dev_put(&perf->i915->drm);
@@ -3410,7 +3727,7 @@ static const struct file_operations fops = {
* See i915_perf_ioctl_open() for interface details.
*
* Implements further stream config validation and stream initialization on
- * behalf of i915_perf_open_ioctl() with the &perf->lock mutex
+ * behalf of i915_perf_open_ioctl() with the &gt->perf.lock mutex
* taken to serialize with any non-file-operation driver hooks.
*
* Note: at this point the @props have only been validated in isolation and
@@ -3565,8 +3882,10 @@ err:
static u64 oa_exponent_to_ns(struct i915_perf *perf, int exponent)
{
- return intel_gt_clock_interval_to_ns(to_gt(perf->i915),
- 2ULL << exponent);
+ u64 nom = (2ULL << exponent) * NSEC_PER_SEC;
+ u32 den = i915_perf_oa_timestamp_frequency(perf->i915);
+
+ return div_u64(nom + den - 1, den);
}
static __always_inline bool
@@ -3794,7 +4113,7 @@ static int read_properties_unlocked(struct i915_perf *perf,
* mutex to avoid an awkward lockdep with mmap_lock.
*
* Most of the implementation details are handled by
- * i915_perf_open_ioctl_locked() after taking the &perf->lock
+ * i915_perf_open_ioctl_locked() after taking the &gt->perf.lock
* mutex for serializing with any non-file-operation driver hooks.
*
* Return: A newly opened i915 Perf stream file descriptor or negative
@@ -3805,6 +4124,7 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data,
{
struct i915_perf *perf = &to_i915(dev)->perf;
struct drm_i915_perf_open_param *param = data;
+ struct intel_gt *gt;
struct perf_open_properties props;
u32 known_open_flags;
int ret;
@@ -3831,9 +4151,11 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
- mutex_lock(&perf->lock);
+ gt = props.engine->gt;
+
+ mutex_lock(&gt->perf.lock);
ret = i915_perf_open_ioctl_locked(perf, param, &props, file);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&gt->perf.lock);
return ret;
}
@@ -3849,6 +4171,7 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data,
void i915_perf_register(struct drm_i915_private *i915)
{
struct i915_perf *perf = &i915->perf;
+ struct intel_gt *gt = to_gt(i915);
if (!perf->i915)
return;
@@ -3857,13 +4180,13 @@ void i915_perf_register(struct drm_i915_private *i915)
* i915_perf_open_ioctl(); considering that we register after
* being exposed to userspace.
*/
- mutex_lock(&perf->lock);
+ mutex_lock(&gt->perf.lock);
perf->metrics_kobj =
kobject_create_and_add("metrics",
&i915->drm.primary->kdev->kobj);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&gt->perf.lock);
}
/**
@@ -3939,6 +4262,11 @@ static const struct i915_range gen12_oa_b_counters[] = {
{}
};
+static const struct i915_range xehp_oa_b_counters[] = {
+ { .start = 0xdc48, .end = 0xdc48 }, /* OAA_ENABLE_REG */
+ { .start = 0xdd00, .end = 0xdd48 }, /* OAG_LCE0_0 - OAA_LENABLE_REG */
+};
+
static const struct i915_range gen7_oa_mux_regs[] = {
{ .start = 0x91b8, .end = 0x91cc }, /* OA_PERFCNT[1-2], OA_PERFMATRIX */
{ .start = 0x9800, .end = 0x9888 }, /* MICRO_BP0_0 - NOA_WRITE */
@@ -4013,6 +4341,12 @@ static bool gen12_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr)
return reg_in_range_table(addr, gen12_oa_b_counters);
}
+static bool xehp_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr)
+{
+ return reg_in_range_table(addr, xehp_oa_b_counters) ||
+ reg_in_range_table(addr, gen12_oa_b_counters);
+}
+
static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr)
{
return reg_in_range_table(addr, gen12_oa_mux_regs);
@@ -4411,11 +4745,47 @@ static void oa_init_supported_formats(struct i915_perf *perf)
oa_format_add(perf, I915_OA_FORMAT_C4_B8);
break;
+ case INTEL_DG2:
+ oa_format_add(perf, I915_OAR_FORMAT_A32u40_A4u32_B8_C8);
+ oa_format_add(perf, I915_OA_FORMAT_A24u40_A14u32_B8_C8);
+ break;
+
default:
MISSING_CASE(platform);
}
}
+static void i915_perf_init_info(struct drm_i915_private *i915)
+{
+ struct i915_perf *perf = &i915->perf;
+
+ switch (GRAPHICS_VER(i915)) {
+ case 8:
+ perf->ctx_oactxctrl_offset = 0x120;
+ perf->ctx_flexeu0_offset = 0x2ce;
+ perf->gen8_valid_ctx_bit = BIT(25);
+ break;
+ case 9:
+ perf->ctx_oactxctrl_offset = 0x128;
+ perf->ctx_flexeu0_offset = 0x3de;
+ perf->gen8_valid_ctx_bit = BIT(16);
+ break;
+ case 11:
+ perf->ctx_oactxctrl_offset = 0x124;
+ perf->ctx_flexeu0_offset = 0x78e;
+ perf->gen8_valid_ctx_bit = BIT(16);
+ break;
+ case 12:
+ /*
+ * Calculate offset at runtime in oa_pin_context for gen12 and
+ * cache the value in perf->ctx_oactxctrl_offset.
+ */
+ break;
+ default:
+ MISSING_CASE(GRAPHICS_VER(i915));
+ }
+}
+
/**
* i915_perf_init - initialize i915-perf state on module bind
* @i915: i915 device instance
@@ -4429,12 +4799,6 @@ void i915_perf_init(struct drm_i915_private *i915)
{
struct i915_perf *perf = &i915->perf;
- /* XXX const struct i915_perf_ops! */
-
- /* i915_perf is not enabled for DG2 yet */
- if (IS_DG2(i915))
- return;
-
perf->oa_formats = oa_formats;
if (IS_HASWELL(i915)) {
perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr;
@@ -4454,6 +4818,7 @@ void i915_perf_init(struct drm_i915_private *i915)
* execlist mode by default.
*/
perf->ops.read = gen8_oa_read;
+ i915_perf_init_info(i915);
if (IS_GRAPHICS_VER(i915, 8, 9)) {
perf->ops.is_valid_b_counter_reg =
@@ -4473,18 +4838,6 @@ void i915_perf_init(struct drm_i915_private *i915)
perf->ops.enable_metric_set = gen8_enable_metric_set;
perf->ops.disable_metric_set = gen8_disable_metric_set;
perf->ops.oa_hw_tail_read = gen8_oa_hw_tail_read;
-
- if (GRAPHICS_VER(i915) == 8) {
- perf->ctx_oactxctrl_offset = 0x120;
- perf->ctx_flexeu0_offset = 0x2ce;
-
- perf->gen8_valid_ctx_bit = BIT(25);
- } else {
- perf->ctx_oactxctrl_offset = 0x128;
- perf->ctx_flexeu0_offset = 0x3de;
-
- perf->gen8_valid_ctx_bit = BIT(16);
- }
} else if (GRAPHICS_VER(i915) == 11) {
perf->ops.is_valid_b_counter_reg =
gen7_is_valid_b_counter_addr;
@@ -4498,13 +4851,10 @@ void i915_perf_init(struct drm_i915_private *i915)
perf->ops.enable_metric_set = gen8_enable_metric_set;
perf->ops.disable_metric_set = gen11_disable_metric_set;
perf->ops.oa_hw_tail_read = gen8_oa_hw_tail_read;
-
- perf->ctx_oactxctrl_offset = 0x124;
- perf->ctx_flexeu0_offset = 0x78e;
-
- perf->gen8_valid_ctx_bit = BIT(16);
} else if (GRAPHICS_VER(i915) == 12) {
perf->ops.is_valid_b_counter_reg =
+ HAS_OA_SLICE_CONTRIB_LIMITS(i915) ?
+ xehp_is_valid_b_counter_addr :
gen12_is_valid_b_counter_addr;
perf->ops.is_valid_mux_reg =
gen12_is_valid_mux_addr;
@@ -4516,14 +4866,15 @@ void i915_perf_init(struct drm_i915_private *i915)
perf->ops.enable_metric_set = gen12_enable_metric_set;
perf->ops.disable_metric_set = gen12_disable_metric_set;
perf->ops.oa_hw_tail_read = gen12_oa_hw_tail_read;
-
- perf->ctx_flexeu0_offset = 0;
- perf->ctx_oactxctrl_offset = 0x144;
}
}
if (perf->ops.enable_metric_set) {
- mutex_init(&perf->lock);
+ struct intel_gt *gt;
+ int i;
+
+ for_each_gt(gt, i915, i)
+ mutex_init(&gt->perf.lock);
/* Choose a representative limit */
oa_sample_rate_hard_limit = to_gt(i915)->clock_frequency / 2;
diff --git a/drivers/gpu/drm/i915/i915_perf.h b/drivers/gpu/drm/i915/i915_perf.h
index 1d1329e5af3a..f96e09a4af04 100644
--- a/drivers/gpu/drm/i915/i915_perf.h
+++ b/drivers/gpu/drm/i915/i915_perf.h
@@ -57,4 +57,6 @@ static inline void i915_oa_config_put(struct i915_oa_config *oa_config)
kref_put(&oa_config->ref, i915_oa_config_release);
}
+u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915);
+
#endif /* __I915_PERF_H__ */
diff --git a/drivers/gpu/drm/i915/i915_perf_oa_regs.h b/drivers/gpu/drm/i915/i915_perf_oa_regs.h
index f31c9f13a9fc..381d94101610 100644
--- a/drivers/gpu/drm/i915/i915_perf_oa_regs.h
+++ b/drivers/gpu/drm/i915/i915_perf_oa_regs.h
@@ -97,7 +97,7 @@
#define GEN12_OAR_OACONTROL_COUNTER_FORMAT_SHIFT 1
#define GEN12_OAR_OACONTROL_COUNTER_ENABLE (1 << 0)
-#define GEN12_OACTXCONTROL _MMIO(0x2360)
+#define GEN12_OACTXCONTROL(base) _MMIO((base) + 0x360)
#define GEN12_OAR_OASTATUS _MMIO(0x2968)
/* Gen12 OAG unit */
@@ -134,4 +134,8 @@
#define GDT_CHICKEN_BITS _MMIO(0x9840)
#define GT_NOA_ENABLE 0x00000080
+#define GEN12_SQCNT1 _MMIO(0x8718)
+#define GEN12_SQCNT1_PMON_ENABLE REG_BIT(30)
+#define GEN12_SQCNT1_OABPC REG_BIT(29)
+
#endif /* __INTEL_PERF_OA_REGS__ */
diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h
index 05cb9a335a97..ca150b7af3f2 100644
--- a/drivers/gpu/drm/i915/i915_perf_types.h
+++ b/drivers/gpu/drm/i915/i915_perf_types.h
@@ -147,6 +147,11 @@ struct i915_perf_stream {
struct intel_engine_cs *engine;
/**
+ * @lock: Lock associated with operations on stream
+ */
+ struct mutex lock;
+
+ /**
* @sample_flags: Flags representing the `DRM_I915_PERF_PROP_SAMPLE_*`
* properties given when opening a stream, representing the contents
* of a single sample as read() by userspace.
@@ -245,11 +250,10 @@ struct i915_perf_stream {
* @oa_buffer: State of the OA buffer.
*/
struct {
+ const struct i915_oa_format *format;
struct i915_vma *vma;
u8 *vaddr;
u32 last_ctx_id;
- int format;
- int format_size;
int size_exponent;
/**
@@ -380,6 +384,26 @@ struct i915_oa_ops {
u32 (*oa_hw_tail_read)(struct i915_perf_stream *stream);
};
+struct i915_perf_gt {
+ /*
+ * Lock associated with anything below within this structure.
+ */
+ struct mutex lock;
+
+ /**
+ * @sseu: sseu configuration selected to run while perf is active,
+ * applies to all contexts.
+ */
+ struct intel_sseu sseu;
+
+ /*
+ * @exclusive_stream: The stream currently using the OA unit. This is
+ * sometimes accessed outside a syscall associated to its file
+ * descriptor.
+ */
+ struct i915_perf_stream *exclusive_stream;
+};
+
struct i915_perf {
struct drm_i915_private *i915;
@@ -397,25 +421,6 @@ struct i915_perf {
*/
struct idr metrics_idr;
- /*
- * Lock associated with anything below within this structure
- * except exclusive_stream.
- */
- struct mutex lock;
-
- /*
- * The stream currently using the OA unit. If accessed
- * outside a syscall associated to its file
- * descriptor.
- */
- struct i915_perf_stream *exclusive_stream;
-
- /**
- * @sseu: sseu configuration selected to run while perf is active,
- * applies to all contexts.
- */
- struct intel_sseu sseu;
-
/**
* For rate limiting any notifications of spurious
* invalid OA reports
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 958b37123bf1..52531ab28c5f 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -148,13 +148,13 @@ static u64 __get_rc6(struct intel_gt *gt)
struct drm_i915_private *i915 = gt->i915;
u64 val;
- val = intel_rc6_residency_ns(&gt->rc6, GEN6_GT_GFX_RC6);
+ val = intel_rc6_residency_ns(&gt->rc6, INTEL_RC6_RES_RC6);
if (HAS_RC6p(i915))
- val += intel_rc6_residency_ns(&gt->rc6, GEN6_GT_GFX_RC6p);
+ val += intel_rc6_residency_ns(&gt->rc6, INTEL_RC6_RES_RC6p);
if (HAS_RC6pp(i915))
- val += intel_rc6_residency_ns(&gt->rc6, GEN6_GT_GFX_RC6pp);
+ val += intel_rc6_residency_ns(&gt->rc6, INTEL_RC6_RES_RC6pp);
return val;
}
@@ -371,7 +371,6 @@ static void
frequency_sample(struct intel_gt *gt, unsigned int period_ns)
{
struct drm_i915_private *i915 = gt->i915;
- struct intel_uncore *uncore = gt->uncore;
struct i915_pmu *pmu = &i915->pmu;
struct intel_rps *rps = &gt->rps;
@@ -394,7 +393,7 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns)
* case we assume the system is running at the intended
* frequency. Fortunately, the read should rarely fail!
*/
- val = intel_uncore_read_fw(uncore, GEN6_RPSTAT1);
+ val = intel_rps_read_rpstat_fw(rps);
if (val)
val = intel_rps_get_cagf(rps, val);
else
diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c
index 6ec9c9fb7b0d..00871ef99792 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -250,8 +250,9 @@ static int query_perf_config_data(struct drm_i915_private *i915,
return total_size;
if (query_item->length < total_size) {
- DRM_DEBUG("Invalid query config data item size=%u expected=%u\n",
- query_item->length, total_size);
+ drm_dbg(&i915->drm,
+ "Invalid query config data item size=%u expected=%u\n",
+ query_item->length, total_size);
return -EINVAL;
}
@@ -418,9 +419,10 @@ static int query_perf_config_list(struct drm_i915_private *i915,
} while (n_configs > alloc);
if (query_item->length < sizeof_perf_config_list(n_configs)) {
- DRM_DEBUG("Invalid query config list item size=%u expected=%zu\n",
- query_item->length,
- sizeof_perf_config_list(n_configs));
+ drm_dbg(&i915->drm,
+ "Invalid query config list item size=%u expected=%zu\n",
+ query_item->length,
+ sizeof_perf_config_list(n_configs));
kfree(oa_config_ids);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index da35bb2db26b..8e1892d14774 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -26,6 +26,7 @@
#define _I915_REG_H_
#include "i915_reg_defs.h"
+#include "display/intel_display_reg_defs.h"
/**
* DOC: The i915 register macro definition style guide
@@ -115,75 +116,6 @@
* #define GEN8_BAR _MMIO(0xb888)
*/
-#define DISPLAY_MMIO_BASE(dev_priv) (INTEL_INFO(dev_priv)->display.mmio_offset)
-
-/*
- * Given the first two numbers __a and __b of arbitrarily many evenly spaced
- * numbers, pick the 0-based __index'th value.
- *
- * Always prefer this over _PICK() if the numbers are evenly spaced.
- */
-#define _PICK_EVEN(__index, __a, __b) ((__a) + (__index) * ((__b) - (__a)))
-
-/*
- * Given the arbitrary numbers in varargs, pick the 0-based __index'th number.
- *
- * Always prefer _PICK_EVEN() over this if the numbers are evenly spaced.
- */
-#define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index])
-
-/*
- * Named helper wrappers around _PICK_EVEN() and _PICK().
- */
-#define _PIPE(pipe, a, b) _PICK_EVEN(pipe, a, b)
-#define _PLANE(plane, a, b) _PICK_EVEN(plane, a, b)
-#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b)
-#define _PORT(port, a, b) _PICK_EVEN(port, a, b)
-#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b)
-#define _PHY(phy, a, b) _PICK_EVEN(phy, a, b)
-
-#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
-#define _MMIO_PLANE(plane, a, b) _MMIO(_PLANE(plane, a, b))
-#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
-#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
-#define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b))
-#define _MMIO_PHY(phy, a, b) _MMIO(_PHY(phy, a, b))
-
-#define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__)
-
-#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
-#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
-#define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
-#define _MMIO_PLL3(pll, ...) _MMIO(_PICK(pll, __VA_ARGS__))
-
-
-/*
- * Device info offset array based helpers for groups of registers with unevenly
- * spaced base offsets.
- */
-#define _MMIO_PIPE2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->display.pipe_offsets[(pipe)] - \
- INTEL_INFO(dev_priv)->display.pipe_offsets[PIPE_A] + \
- DISPLAY_MMIO_BASE(dev_priv) + (reg))
-#define _MMIO_TRANS2(tran, reg) _MMIO(INTEL_INFO(dev_priv)->display.trans_offsets[(tran)] - \
- INTEL_INFO(dev_priv)->display.trans_offsets[TRANSCODER_A] + \
- DISPLAY_MMIO_BASE(dev_priv) + (reg))
-#define _MMIO_CURSOR2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->display.cursor_offsets[(pipe)] - \
- INTEL_INFO(dev_priv)->display.cursor_offsets[PIPE_A] + \
- DISPLAY_MMIO_BASE(dev_priv) + (reg))
-
-#define __MASKED_FIELD(mask, value) ((mask) << 16 | (value))
-#define _MASKED_FIELD(mask, value) ({ \
- if (__builtin_constant_p(mask)) \
- BUILD_BUG_ON_MSG(((mask) & 0xffff0000), "Incorrect mask"); \
- if (__builtin_constant_p(value)) \
- BUILD_BUG_ON_MSG((value) & 0xffff0000, "Incorrect value"); \
- if (__builtin_constant_p(mask) && __builtin_constant_p(value)) \
- BUILD_BUG_ON_MSG((value) & ~(mask), \
- "Incorrect value for mask"); \
- __MASKED_FIELD(mask, value); })
-#define _MASKED_BIT_ENABLE(a) ({ typeof(a) _a = (a); _MASKED_FIELD(_a, _a); })
-#define _MASKED_BIT_DISABLE(a) (_MASKED_FIELD((a), 0))
-
#define GU_CNTL _MMIO(0x101010)
#define LMEM_INIT REG_BIT(7)
@@ -970,6 +902,7 @@
#define GEN11_VEBOX2_RING_BASE 0x1d8000
#define XEHP_VEBOX3_RING_BASE 0x1e8000
#define XEHP_VEBOX4_RING_BASE 0x1f8000
+#define MTL_GSC_RING_BASE 0x11a000
#define GEN12_COMPUTE0_RING_BASE 0x1a000
#define GEN12_COMPUTE1_RING_BASE 0x1c000
#define GEN12_COMPUTE2_RING_BASE 0x1e000
@@ -1147,11 +1080,6 @@
#define MBUS_JOIN_PIPE_SELECT(pipe) REG_FIELD_PREP(MBUS_JOIN_PIPE_SELECT_MASK, pipe)
#define MBUS_JOIN_PIPE_SELECT_NONE MBUS_JOIN_PIPE_SELECT(7)
-#define HDPORT_STATE _MMIO(0x45050)
-#define HDPORT_DPLL_USED_MASK REG_GENMASK(15, 12)
-#define HDPORT_DDI_USED(phy) REG_BIT(2 * (phy) + 1)
-#define HDPORT_ENABLED REG_BIT(0)
-
/* Make render/texture TLB fetches lower priorty than associated data
* fetches. This is not turned on by default
*/
@@ -1781,9 +1709,10 @@
#define _PALETTE_A 0xa000
#define _PALETTE_B 0xa800
#define _CHV_PALETTE_C 0xc000
-#define PALETTE_RED_MASK REG_GENMASK(23, 16)
-#define PALETTE_GREEN_MASK REG_GENMASK(15, 8)
-#define PALETTE_BLUE_MASK REG_GENMASK(7, 0)
+/* 8bit mode / i965+ 10.6 interpolated mode ldw/udw */
+#define PALETTE_RED_MASK REG_GENMASK(23, 16)
+#define PALETTE_GREEN_MASK REG_GENMASK(15, 8)
+#define PALETTE_BLUE_MASK REG_GENMASK(7, 0)
#define PALETTE(pipe, i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + \
_PICK((pipe), _PALETTE_A, \
_PALETTE_B, _CHV_PALETTE_C) + \
@@ -1796,6 +1725,15 @@
#define XEHPSDV_RP_STATE_CAP _MMIO(0x250014)
#define PVC_RP_STATE_CAP _MMIO(0x281014)
+#define MTL_RP_STATE_CAP _MMIO(0x138000)
+#define MTL_MEDIAP_STATE_CAP _MMIO(0x138020)
+#define MTL_RP0_CAP_MASK REG_GENMASK(8, 0)
+#define MTL_RPN_CAP_MASK REG_GENMASK(24, 16)
+
+#define MTL_GT_RPE_FREQUENCY _MMIO(0x13800c)
+#define MTL_MPE_FREQUENCY _MMIO(0x13802c)
+#define MTL_RPE_MASK REG_GENMASK(8, 0)
+
#define GT0_PERF_LIMIT_REASONS _MMIO(0x1381a8)
#define GT0_PERF_LIMIT_REASONS_MASK 0xde3
#define PROCHOT_MASK REG_BIT(0)
@@ -1806,6 +1744,8 @@
#define POWER_LIMIT_4_MASK REG_BIT(8)
#define POWER_LIMIT_1_MASK REG_BIT(10)
#define POWER_LIMIT_2_MASK REG_BIT(11)
+#define GT0_PERF_LIMIT_REASONS_LOG_MASK REG_GENMASK(31, 16)
+#define MTL_MEDIA_PERF_LIMIT_REASONS _MMIO(0x138030)
#define CHV_CLK_CTL1 _MMIO(0x101100)
#define VLV_CLK_CTL2 _MMIO(0x101104)
@@ -3747,9 +3687,10 @@
/* Skylake+ pipe bottom (background) color */
#define _SKL_BOTTOM_COLOR_A 0x70034
+#define _SKL_BOTTOM_COLOR_B 0x71034
#define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31)
#define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30)
-#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE2(pipe, _SKL_BOTTOM_COLOR_A)
+#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B)
#define _ICL_PIPE_A_STATUS 0x70058
#define ICL_PIPESTATUS(pipe) _MMIO_PIPE2(pipe, _ICL_PIPE_A_STATUS)
@@ -5367,17 +5308,24 @@
/* legacy palette */
#define _LGC_PALETTE_A 0x4a000
#define _LGC_PALETTE_B 0x4a800
-#define LGC_PALETTE_RED_MASK REG_GENMASK(23, 16)
-#define LGC_PALETTE_GREEN_MASK REG_GENMASK(15, 8)
-#define LGC_PALETTE_BLUE_MASK REG_GENMASK(7, 0)
+/* see PALETTE_* for the bits */
#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
/* ilk/snb precision palette */
#define _PREC_PALETTE_A 0x4b000
#define _PREC_PALETTE_B 0x4c000
-#define PREC_PALETTE_RED_MASK REG_GENMASK(29, 20)
-#define PREC_PALETTE_GREEN_MASK REG_GENMASK(19, 10)
-#define PREC_PALETTE_BLUE_MASK REG_GENMASK(9, 0)
+/* 10bit mode */
+#define PREC_PALETTE_10_RED_MASK REG_GENMASK(29, 20)
+#define PREC_PALETTE_10_GREEN_MASK REG_GENMASK(19, 10)
+#define PREC_PALETTE_10_BLUE_MASK REG_GENMASK(9, 0)
+/* 12.4 interpolated mode ldw */
+#define PREC_PALETTE_12P4_RED_LDW_MASK REG_GENMASK(29, 24)
+#define PREC_PALETTE_12P4_GREEN_LDW_MASK REG_GENMASK(19, 14)
+#define PREC_PALETTE_12P4_BLUE_LDW_MASK REG_GENMASK(9, 4)
+/* 12.4 interpolated mode udw */
+#define PREC_PALETTE_12P4_RED_UDW_MASK REG_GENMASK(29, 20)
+#define PREC_PALETTE_12P4_GREEN_UDW_MASK REG_GENMASK(19, 10)
+#define PREC_PALETTE_12P4_BLUE_UDW_MASK REG_GENMASK(9, 0)
#define PREC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _PREC_PALETTE_A, _PREC_PALETTE_B) + (i) * 4)
#define _PREC_PIPEAGCMAX 0x4d000
@@ -5847,6 +5795,11 @@
#define ICL_DSSM_CDCLK_PLL_REFCLK_19_2MHz (1 << 29)
#define ICL_DSSM_CDCLK_PLL_REFCLK_38_4MHz (2 << 29)
+#define GMD_ID_DISPLAY _MMIO(0x510a0)
+#define GMD_ID_ARCH_MASK REG_GENMASK(31, 22)
+#define GMD_ID_RELEASE_MASK REG_GENMASK(21, 14)
+#define GMD_ID_STEP REG_GENMASK(5, 0)
+
/*GEN11 chicken */
#define _PIPEA_CHICKEN 0x70038
#define _PIPEB_CHICKEN 0x71038
@@ -6647,6 +6600,12 @@
#define DG1_PCODE_STATUS 0x7E
#define DG1_UNCORE_GET_INIT_STATUS 0x0
#define DG1_UNCORE_INIT_STATUS_COMPLETE 0x1
+#define PCODE_POWER_SETUP 0x7C
+#define POWER_SETUP_SUBCOMMAND_READ_I1 0x4
+#define POWER_SETUP_SUBCOMMAND_WRITE_I1 0x5
+#define POWER_SETUP_I1_WATTS REG_BIT(31)
+#define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */
+#define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0)
#define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23
#define XEHP_PCODE_FREQUENCY_CONFIG 0x6e /* xehpsdv, pvc */
/* XEHP_PCODE_FREQUENCY_CONFIG sub-commands (param1) */
@@ -6656,6 +6615,15 @@
/* XEHP_PCODE_FREQUENCY_CONFIG param2 */
#define PCODE_MBOX_DOMAIN_NONE 0x0
#define PCODE_MBOX_DOMAIN_MEDIAFF 0x3
+
+/* Wa_14017210380: mtl */
+#define PCODE_MBOX_GT_STATE 0x50
+/* sub-commands (param1) */
+#define PCODE_MBOX_GT_STATE_MEDIA_BUSY 0x1
+#define PCODE_MBOX_GT_STATE_MEDIA_NOT_BUSY 0x2
+/* param2 */
+#define PCODE_MBOX_GT_STATE_DOMAIN_MEDIA 0x1
+
#define GEN6_PCODE_DATA _MMIO(0x138128)
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
@@ -7413,185 +7381,6 @@ enum skl_power_gate {
_ADLS_DPLL4_CFGCR1, \
_ADLS_DPLL3_CFGCR1)
-#define _DKL_PHY1_BASE 0x168000
-#define _DKL_PHY2_BASE 0x169000
-#define _DKL_PHY3_BASE 0x16A000
-#define _DKL_PHY4_BASE 0x16B000
-#define _DKL_PHY5_BASE 0x16C000
-#define _DKL_PHY6_BASE 0x16D000
-
-#define DKL_REG_TC_PORT(__reg) \
- (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE))
-
-/* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */
-#define _DKL_PCS_DW5 0x14
-#define DKL_PCS_DW5(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PCS_DW5)
-#define DKL_PCS_DW5_CORE_SOFTRESET REG_BIT(11)
-
-#define _DKL_PLL_DIV0 0x200
-#define DKL_PLL_DIV0_AFC_STARTUP_MASK REG_GENMASK(27, 25)
-#define DKL_PLL_DIV0_AFC_STARTUP(val) REG_FIELD_PREP(DKL_PLL_DIV0_AFC_STARTUP_MASK, (val))
-#define DKL_PLL_DIV0_INTEG_COEFF(x) ((x) << 16)
-#define DKL_PLL_DIV0_INTEG_COEFF_MASK (0x1F << 16)
-#define DKL_PLL_DIV0_PROP_COEFF(x) ((x) << 12)
-#define DKL_PLL_DIV0_PROP_COEFF_MASK (0xF << 12)
-#define DKL_PLL_DIV0_FBPREDIV_SHIFT (8)
-#define DKL_PLL_DIV0_FBPREDIV(x) ((x) << DKL_PLL_DIV0_FBPREDIV_SHIFT)
-#define DKL_PLL_DIV0_FBPREDIV_MASK (0xF << DKL_PLL_DIV0_FBPREDIV_SHIFT)
-#define DKL_PLL_DIV0_FBDIV_INT(x) ((x) << 0)
-#define DKL_PLL_DIV0_FBDIV_INT_MASK (0xFF << 0)
-#define DKL_PLL_DIV0_MASK (DKL_PLL_DIV0_INTEG_COEFF_MASK | \
- DKL_PLL_DIV0_PROP_COEFF_MASK | \
- DKL_PLL_DIV0_FBPREDIV_MASK | \
- DKL_PLL_DIV0_FBDIV_INT_MASK)
-#define DKL_PLL_DIV0(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PLL_DIV0)
-
-#define _DKL_PLL_DIV1 0x204
-#define DKL_PLL_DIV1_IREF_TRIM(x) ((x) << 16)
-#define DKL_PLL_DIV1_IREF_TRIM_MASK (0x1F << 16)
-#define DKL_PLL_DIV1_TDC_TARGET_CNT(x) ((x) << 0)
-#define DKL_PLL_DIV1_TDC_TARGET_CNT_MASK (0xFF << 0)
-#define DKL_PLL_DIV1(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PLL_DIV1)
-
-#define _DKL_PLL_SSC 0x210
-#define DKL_PLL_SSC_IREF_NDIV_RATIO(x) ((x) << 29)
-#define DKL_PLL_SSC_IREF_NDIV_RATIO_MASK (0x7 << 29)
-#define DKL_PLL_SSC_STEP_LEN(x) ((x) << 16)
-#define DKL_PLL_SSC_STEP_LEN_MASK (0xFF << 16)
-#define DKL_PLL_SSC_STEP_NUM(x) ((x) << 11)
-#define DKL_PLL_SSC_STEP_NUM_MASK (0x7 << 11)
-#define DKL_PLL_SSC_EN (1 << 9)
-#define DKL_PLL_SSC(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PLL_SSC)
-
-#define _DKL_PLL_BIAS 0x214
-#define DKL_PLL_BIAS_FRAC_EN_H (1 << 30)
-#define DKL_PLL_BIAS_FBDIV_SHIFT (8)
-#define DKL_PLL_BIAS_FBDIV_FRAC(x) ((x) << DKL_PLL_BIAS_FBDIV_SHIFT)
-#define DKL_PLL_BIAS_FBDIV_FRAC_MASK (0x3FFFFF << DKL_PLL_BIAS_FBDIV_SHIFT)
-#define DKL_PLL_BIAS(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PLL_BIAS)
-
-#define _DKL_PLL_TDC_COLDST_BIAS 0x218
-#define DKL_PLL_TDC_SSC_STEP_SIZE(x) ((x) << 8)
-#define DKL_PLL_TDC_SSC_STEP_SIZE_MASK (0xFF << 8)
-#define DKL_PLL_TDC_FEED_FWD_GAIN(x) ((x) << 0)
-#define DKL_PLL_TDC_FEED_FWD_GAIN_MASK (0xFF << 0)
-#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_PLL_TDC_COLDST_BIAS)
-
-#define _DKL_REFCLKIN_CTL 0x12C
-/* Bits are the same as MG_REFCLKIN_CTL */
-#define DKL_REFCLKIN_CTL(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_REFCLKIN_CTL)
-
-#define _DKL_CLKTOP2_HSCLKCTL 0xD4
-/* Bits are the same as MG_CLKTOP2_HSCLKCTL */
-#define DKL_CLKTOP2_HSCLKCTL(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_CLKTOP2_HSCLKCTL)
-
-#define _DKL_CLKTOP2_CORECLKCTL1 0xD8
-/* Bits are the same as MG_CLKTOP2_CORECLKCTL1 */
-#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_CLKTOP2_CORECLKCTL1)
-
-#define _DKL_TX_DPCNTL0 0x2C0
-#define DKL_TX_PRESHOOT_COEFF(x) ((x) << 13)
-#define DKL_TX_PRESHOOT_COEFF_MASK (0x1f << 13)
-#define DKL_TX_DE_EMPHASIS_COEFF(x) ((x) << 8)
-#define DKL_TX_DE_EMPAHSIS_COEFF_MASK (0x1f << 8)
-#define DKL_TX_VSWING_CONTROL(x) ((x) << 0)
-#define DKL_TX_VSWING_CONTROL_MASK (0x7 << 0)
-#define DKL_TX_DPCNTL0(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_DPCNTL0)
-
-#define _DKL_TX_DPCNTL1 0x2C4
-/* Bits are the same as DKL_TX_DPCNTRL0 */
-#define DKL_TX_DPCNTL1(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_DPCNTL1)
-
-#define _DKL_TX_DPCNTL2 0x2C8
-#define DKL_TX_DP20BITMODE REG_BIT(2)
-#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK REG_GENMASK(4, 3)
-#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val))
-#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5)
-#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val))
-#define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_DPCNTL2)
-
-#define _DKL_TX_FW_CALIB 0x2F8
-#define DKL_TX_CFG_DISABLE_WAIT_INIT (1 << 7)
-#define DKL_TX_FW_CALIB(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_FW_CALIB)
-
-#define _DKL_TX_PMD_LANE_SUS 0xD00
-#define DKL_TX_PMD_LANE_SUS(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_PMD_LANE_SUS)
-
-#define _DKL_TX_DW17 0xDC4
-#define DKL_TX_DW17(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_DW17)
-
-#define _DKL_TX_DW18 0xDC8
-#define DKL_TX_DW18(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_TX_DW18)
-
-#define _DKL_DP_MODE 0xA0
-#define DKL_DP_MODE(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_DP_MODE)
-
-#define _DKL_CMN_UC_DW27 0x36C
-#define DKL_CMN_UC_DW27_UC_HEALTH (0x1 << 15)
-#define DKL_CMN_UC_DW_27(tc_port) _MMIO(_PORT(tc_port, \
- _DKL_PHY1_BASE, \
- _DKL_PHY2_BASE) + \
- _DKL_CMN_UC_DW27)
-
-/*
- * Each Dekel PHY is addressed through a 4KB aperture. Each PHY has more than
- * 4KB of register space, so a separate index is programmed in HIP_INDEX_REG0
- * or HIP_INDEX_REG1, based on the port number, to set the upper 2 address
- * bits that point the 4KB window into the full PHY register space.
- */
-#define _HIP_INDEX_REG0 0x1010A0
-#define _HIP_INDEX_REG1 0x1010A4
-#define HIP_INDEX_REG(tc_port) _MMIO((tc_port) < 4 ? _HIP_INDEX_REG0 \
- : _HIP_INDEX_REG1)
-#define _HIP_INDEX_SHIFT(tc_port) (8 * ((tc_port) % 4))
-#define HIP_INDEX_VAL(tc_port, val) ((val) << _HIP_INDEX_SHIFT(tc_port))
-
/* BXT display engine PLL */
#define BXT_DE_PLL_CTL _MMIO(0x6d000)
#define BXT_DE_PLL_RATIO(x) (x) /* {60,65,100} * 19.2MHz */
@@ -7775,12 +7564,10 @@ enum skl_power_gate {
#define _PAL_PREC_DATA_A 0x4A404
#define _PAL_PREC_DATA_B 0x4AC04
#define _PAL_PREC_DATA_C 0x4B404
+/* see PREC_PALETTE_* for the bits */
#define _PAL_PREC_GC_MAX_A 0x4A410
#define _PAL_PREC_GC_MAX_B 0x4AC10
#define _PAL_PREC_GC_MAX_C 0x4B410
-#define PREC_PAL_DATA_RED_MASK REG_GENMASK(29, 20)
-#define PREC_PAL_DATA_GREEN_MASK REG_GENMASK(19, 10)
-#define PREC_PAL_DATA_BLUE_MASK REG_GENMASK(9, 0)
#define _PAL_PREC_EXT_GC_MAX_A 0x4A420
#define _PAL_PREC_EXT_GC_MAX_B 0x4AC20
#define _PAL_PREC_EXT_GC_MAX_C 0x4B420
@@ -7813,12 +7600,7 @@ enum skl_power_gate {
#define _PAL_PREC_MULTI_SEG_DATA_A 0x4A40C
#define _PAL_PREC_MULTI_SEG_DATA_B 0x4AC0C
-#define PAL_PREC_MULTI_SEG_RED_LDW_MASK REG_GENMASK(29, 24)
-#define PAL_PREC_MULTI_SEG_RED_UDW_MASK REG_GENMASK(29, 20)
-#define PAL_PREC_MULTI_SEG_GREEN_LDW_MASK REG_GENMASK(19, 14)
-#define PAL_PREC_MULTI_SEG_GREEN_UDW_MASK REG_GENMASK(19, 10)
-#define PAL_PREC_MULTI_SEG_BLUE_LDW_MASK REG_GENMASK(9, 4)
-#define PAL_PREC_MULTI_SEG_BLUE_UDW_MASK REG_GENMASK(9, 0)
+/* see PREC_PALETTE_12P4_* for the bits */
#define PREC_PAL_MULTI_SEG_INDEX(pipe) _MMIO_PIPE(pipe, \
_PAL_PREC_MULTI_SEG_INDEX_A, \
@@ -7879,13 +7661,17 @@ enum skl_power_gate {
#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C)
#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910)
#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000)
-#define CGM_PIPE_DEGAMMA_RED_MASK REG_GENMASK(13, 0)
-#define CGM_PIPE_DEGAMMA_GREEN_MASK REG_GENMASK(29, 16)
-#define CGM_PIPE_DEGAMMA_BLUE_MASK REG_GENMASK(13, 0)
+/* cgm degamma ldw */
+#define CGM_PIPE_DEGAMMA_GREEN_LDW_MASK REG_GENMASK(29, 16)
+#define CGM_PIPE_DEGAMMA_BLUE_LDW_MASK REG_GENMASK(13, 0)
+/* cgm degamma udw */
+#define CGM_PIPE_DEGAMMA_RED_UDW_MASK REG_GENMASK(13, 0)
#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000)
-#define CGM_PIPE_GAMMA_RED_MASK REG_GENMASK(9, 0)
-#define CGM_PIPE_GAMMA_GREEN_MASK REG_GENMASK(25, 16)
-#define CGM_PIPE_GAMMA_BLUE_MASK REG_GENMASK(9, 0)
+/* cgm gamma ldw */
+#define CGM_PIPE_GAMMA_GREEN_LDW_MASK REG_GENMASK(25, 16)
+#define CGM_PIPE_GAMMA_BLUE_LDW_MASK REG_GENMASK(9, 0)
+/* cgm gamma udw */
+#define CGM_PIPE_GAMMA_RED_UDW_MASK REG_GENMASK(9, 0)
#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00)
#define CGM_PIPE_MODE_GAMMA (1 << 2)
#define CGM_PIPE_MODE_CSC (1 << 1)
@@ -7962,8 +7748,13 @@ enum skl_power_gate {
_ICL_PIPE_DSS_CTL2_PB, \
_ICL_PIPE_DSS_CTL2_PC)
+#define GGC _MMIO(0x108040)
+#define GMS_MASK REG_GENMASK(15, 8)
+#define GGMS_MASK REG_GENMASK(7, 6)
+
#define GEN12_GSMBASE _MMIO(0x108100)
#define GEN12_DSMBASE _MMIO(0x1080C0)
+#define GEN12_BDSM_MASK REG_GENMASK64(63, 20)
#define XEHP_CLOCK_GATE_DIS _MMIO(0x101014)
#define SGSI_SIDECLK_DIS REG_BIT(17)
@@ -8344,6 +8135,11 @@ enum skl_power_gate {
#define GEN12_CULLBIT2 _MMIO(0x7030)
#define GEN12_STATE_ACK_DEBUG _MMIO(0x20BC)
+#define _MTL_CLKGATE_DIS_TRANS_A 0x604E8
+#define _MTL_CLKGATE_DIS_TRANS_B 0x614E8
+#define MTL_CLKGATE_DIS_TRANS(trans) _MMIO_TRANS2(trans, _MTL_CLKGATE_DIS_TRANS_A)
+#define MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS REG_BIT(7)
+
#define MTL_LATENCY_LP0_LP1 _MMIO(0x45780)
#define MTL_LATENCY_LP2_LP3 _MMIO(0x45784)
#define MTL_LATENCY_LP4_LP5 _MMIO(0x45788)
@@ -8367,4 +8163,6 @@ enum skl_power_gate {
#define MTL_TRAS_MASK REG_GENMASK(16, 8)
#define MTL_TRDPRE_MASK REG_GENMASK(7, 0)
+#define MTL_MEDIA_GSI_BASE 0x380000
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_reg_defs.h b/drivers/gpu/drm/i915/i915_reg_defs.h
index 8f486f77609f..be43580a6979 100644
--- a/drivers/gpu/drm/i915/i915_reg_defs.h
+++ b/drivers/gpu/drm/i915/i915_reg_defs.h
@@ -98,29 +98,54 @@
*/
#define REG_FIELD_GET64(__mask, __val) ((u64)FIELD_GET(__mask, __val))
+#define __MASKED_FIELD(mask, value) ((mask) << 16 | (value))
+#define _MASKED_FIELD(mask, value) ({ \
+ if (__builtin_constant_p(mask)) \
+ BUILD_BUG_ON_MSG(((mask) & 0xffff0000), "Incorrect mask"); \
+ if (__builtin_constant_p(value)) \
+ BUILD_BUG_ON_MSG((value) & 0xffff0000, "Incorrect value"); \
+ if (__builtin_constant_p(mask) && __builtin_constant_p(value)) \
+ BUILD_BUG_ON_MSG((value) & ~(mask), \
+ "Incorrect value for mask"); \
+ __MASKED_FIELD(mask, value); })
+#define _MASKED_BIT_ENABLE(a) ({ typeof(a) _a = (a); _MASKED_FIELD(_a, _a); })
+#define _MASKED_BIT_DISABLE(a) (_MASKED_FIELD((a), 0))
+
+/*
+ * Given the first two numbers __a and __b of arbitrarily many evenly spaced
+ * numbers, pick the 0-based __index'th value.
+ *
+ * Always prefer this over _PICK() if the numbers are evenly spaced.
+ */
+#define _PICK_EVEN(__index, __a, __b) ((__a) + (__index) * ((__b) - (__a)))
+
+/*
+ * Given the arbitrary numbers in varargs, pick the 0-based __index'th number.
+ *
+ * Always prefer _PICK_EVEN() over this if the numbers are evenly spaced.
+ */
+#define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index])
+
typedef struct {
u32 reg;
} i915_reg_t;
#define _MMIO(r) ((const i915_reg_t){ .reg = (r) })
-#define INVALID_MMIO_REG _MMIO(0)
-
-static __always_inline u32 i915_mmio_reg_offset(i915_reg_t reg)
-{
- return reg.reg;
-}
-
-static inline bool i915_mmio_reg_equal(i915_reg_t a, i915_reg_t b)
-{
- return i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b);
-}
+typedef struct {
+ u32 reg;
+} i915_mcr_reg_t;
-static inline bool i915_mmio_reg_valid(i915_reg_t reg)
-{
- return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG);
-}
+#define INVALID_MMIO_REG _MMIO(0)
-#define VLV_DISPLAY_BASE 0x180000
+/*
+ * These macros can be used on either i915_reg_t or i915_mcr_reg_t since they're
+ * simply operations on the register's offset and don't care about the MCR vs
+ * non-MCR nature of the register.
+ */
+#define i915_mmio_reg_offset(r) \
+ _Generic((r), i915_reg_t: (r).reg, i915_mcr_reg_t: (r).reg)
+#define i915_mmio_reg_equal(a, b) (i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b))
+#define i915_mmio_reg_valid(r) (!i915_mmio_reg_equal(r, INVALID_MMIO_REG))
#endif /* __I915_REG_DEFS__ */
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 62fad16a55e8..f949a9495758 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -1621,6 +1621,20 @@ i915_request_await_object(struct i915_request *to,
return ret;
}
+static void i915_request_await_huc(struct i915_request *rq)
+{
+ struct intel_huc *huc = &rq->context->engine->gt->uc.huc;
+
+ /* don't stall kernel submissions! */
+ if (!rcu_access_pointer(rq->context->gem_context))
+ return;
+
+ if (intel_huc_wait_required(huc))
+ i915_sw_fence_await_sw_fence(&rq->submit,
+ &huc->delayed_load.fence,
+ &rq->hucq);
+}
+
static struct i915_request *
__i915_request_ensure_parallel_ordering(struct i915_request *rq,
struct intel_timeline *timeline)
@@ -1703,6 +1717,16 @@ __i915_request_add_to_timeline(struct i915_request *rq)
struct i915_request *prev;
/*
+ * Media workloads may require HuC, so stall them until HuC loading is
+ * complete. Note that HuC not being loaded when a user submission
+ * arrives can only happen when HuC is loaded via GSC and in that case
+ * we still expect the window between us starting to accept submissions
+ * and HuC loading completion to be small (a few hundred ms).
+ */
+ if (rq->engine->class == VIDEO_DECODE_CLASS)
+ i915_request_await_huc(rq);
+
+ /*
* Dependency tracking and request ordering along the timeline
* is special cased so that we can eliminate redundant ordering
* operations while building the request (we know that the timeline
diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
index 47041ec68df8..f5e1bb5e857a 100644
--- a/drivers/gpu/drm/i915/i915_request.h
+++ b/drivers/gpu/drm/i915/i915_request.h
@@ -348,6 +348,11 @@ struct i915_request {
#define GUC_PRIO_FINI 0xfe
u8 guc_prio;
+ /**
+ * @hucq: wait queue entry used to wait on the HuC load to complete
+ */
+ wait_queue_entry_t hucq;
+
I915_SELFTEST_DECLARE(struct {
struct list_head link;
unsigned long delay;
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index dcc081874ec8..114e5e39aa72 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -158,7 +158,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
u32 page_alignment)
{
struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
- const u64 size = res->num_pages << PAGE_SHIFT;
+ const u64 size = res->size;
const u32 max_segment = round_down(UINT_MAX, page_alignment);
struct drm_buddy *mm = bman_res->mm;
struct list_head *blocks = &bman_res->blocks;
@@ -177,7 +177,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
i915_refct_sgt_init(rsgt, size);
st = &rsgt->table;
- if (sg_alloc_table(st, res->num_pages, GFP_KERNEL)) {
+ if (sg_alloc_table(st, PFN_UP(res->size), GFP_KERNEL)) {
i915_refct_sgt_put(rsgt);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h
index f54de0499be7..bdf3e22c0a34 100644
--- a/drivers/gpu/drm/i915/i915_selftest.h
+++ b/drivers/gpu/drm/i915/i915_selftest.h
@@ -92,12 +92,14 @@ int __i915_subtests(const char *caller,
T, ARRAY_SIZE(T), data)
#define i915_live_subtests(T, data) ({ \
typecheck(struct drm_i915_private *, data); \
+ (data)->gt[0]->uc.guc.submission_state.sched_disable_delay_ms = 0; \
__i915_subtests(__func__, \
__i915_live_setup, __i915_live_teardown, \
T, ARRAY_SIZE(T), data); \
})
#define intel_gt_live_subtests(T, data) ({ \
typecheck(struct intel_gt *, data); \
+ (data)->uc.guc.submission_state.sched_disable_delay_ms = 0; \
__i915_subtests(__func__, \
__intel_gt_live_setup, __intel_gt_live_teardown, \
T, ARRAY_SIZE(T), data); \
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
index 6fc0d1b89690..cc2a8821d22a 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -571,7 +571,6 @@ int __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
struct dma_resv *resv,
- const struct dma_fence_ops *exclude,
bool write,
unsigned long timeout,
gfp_t gfp)
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h
index 619fc5a22f0c..f752bfc7c6e1 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.h
+++ b/drivers/gpu/drm/i915/i915_sw_fence.h
@@ -91,7 +91,6 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
struct dma_resv *resv,
- const struct dma_fence_ops *exclude,
bool write,
unsigned long timeout,
gfp_t gfp);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 1e2750210831..595e8b574990 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -218,7 +218,8 @@ static const struct bin_attribute error_state_attr = {
static void i915_setup_error_capture(struct device *kdev)
{
if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr))
- DRM_ERROR("error_state sysfs setup failed\n");
+ drm_err(&kdev_minor_to_i915(kdev)->drm,
+ "error_state sysfs setup failed\n");
}
static void i915_teardown_error_capture(struct device *kdev)
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 37b5c9e9d260..f6f9228a1351 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -15,7 +15,6 @@
#include "gt/intel_engine.h"
#include "i915_drv.h"
-#include "i915_irq.h"
/* object tracking */
@@ -671,21 +670,6 @@ TRACE_EVENT_CONDITION(i915_reg_rw,
(u32)(__entry->val >> 32))
);
-TRACE_EVENT(intel_gpu_freq_change,
- TP_PROTO(u32 freq),
- TP_ARGS(freq),
-
- TP_STRUCT__entry(
- __field(u32, freq)
- ),
-
- TP_fast_assign(
- __entry->freq = freq;
- ),
-
- TP_printk("new_freq=%u", __entry->freq)
-);
-
/**
* DOC: i915_ppgtt_create and i915_ppgtt_release tracepoints
*
diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
index e19452f0e100..7e611476c7a4 100644
--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
+++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
@@ -62,8 +62,8 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man,
if (place->fpfn || lpfn != man->size)
bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION;
- GEM_BUG_ON(!bman_res->base.num_pages);
- size = bman_res->base.num_pages << PAGE_SHIFT;
+ GEM_BUG_ON(!bman_res->base.size);
+ size = bman_res->base.size;
min_page_size = bman->default_page_size;
if (bo->page_alignment)
@@ -72,7 +72,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man,
GEM_BUG_ON(min_page_size < mm->chunk_size);
GEM_BUG_ON(!IS_ALIGNED(size, min_page_size));
- if (place->fpfn + bman_res->base.num_pages != place->lpfn &&
+ if (place->fpfn + PFN_UP(bman_res->base.size) != place->lpfn &&
place->flags & TTM_PL_FLAG_CONTIGUOUS) {
unsigned long pages;
@@ -108,7 +108,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man,
goto err_free_blocks;
if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
- u64 original_size = (u64)bman_res->base.num_pages << PAGE_SHIFT;
+ u64 original_size = (u64)bman_res->base.size;
drm_buddy_block_trim(mm,
original_size,
@@ -116,7 +116,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man,
}
if (lpfn <= bman->visible_size) {
- bman_res->used_visible_size = bman_res->base.num_pages;
+ bman_res->used_visible_size = PFN_UP(bman_res->base.size);
} else {
struct drm_buddy_block *block;
@@ -228,7 +228,7 @@ static bool i915_ttm_buddy_man_compatible(struct ttm_resource_manager *man,
if (!place->fpfn &&
place->lpfn == i915_ttm_buddy_man_visible_size(man))
- return bman_res->used_visible_size == res->num_pages;
+ return bman_res->used_visible_size == PFN_UP(res->size);
/* Check each drm buddy block individually */
list_for_each_entry(block, &bman_res->blocks, link) {
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index f17c09ead7d7..703fee6b5f75 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -73,14 +73,16 @@ static void vma_print_allocator(struct i915_vma *vma, const char *reason)
char buf[512];
if (!vma->node.stack) {
- DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: unknown owner\n",
- vma->node.start, vma->node.size, reason);
+ drm_dbg(&to_i915(vma->obj->base.dev)->drm,
+ "vma.node [%08llx + %08llx] %s: unknown owner\n",
+ vma->node.start, vma->node.size, reason);
return;
}
stack_depot_snprint(vma->node.stack, buf, sizeof(buf), 0);
- DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: inserted at %s\n",
- vma->node.start, vma->node.size, reason, buf);
+ drm_dbg(&to_i915(vma->obj->base.dev)->drm,
+ "vma.node [%08llx + %08llx] %s: inserted at %s\n",
+ vma->node.start, vma->node.size, reason, buf);
}
#else
@@ -776,21 +778,15 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
alignment = max(alignment, i915_vm_obj_min_alignment(vma->vm, vma->obj));
- /*
- * for compact-pt we round up the reservation to prevent
- * any smaller pages being used within the same PDE
- */
- if (NEEDS_COMPACT_PT(vma->vm->i915))
- size = round_up(size, alignment);
/* If binding the object/GGTT view requires more space than the entire
* aperture has, reject it early before evicting everything in a vain
* attempt to find space.
*/
if (size > end) {
- DRM_DEBUG("Attempting to bind an object larger than the aperture: request=%llu > %s aperture=%llu\n",
- size, flags & PIN_MAPPABLE ? "mappable" : "total",
- end);
+ drm_dbg(&to_i915(vma->obj->base.dev)->drm,
+ "Attempting to bind an object larger than the aperture: request=%llu > %s aperture=%llu\n",
+ size, flags & PIN_MAPPABLE ? "mappable" : "total", end);
return -ENOSPC;
}
@@ -820,7 +816,8 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
* forseeable future. See also i915_ggtt_offset().
*/
if (upper_32_bits(end - 1) &&
- vma->page_sizes.sg > I915_GTT_PAGE_SIZE) {
+ vma->page_sizes.sg > I915_GTT_PAGE_SIZE &&
+ !HAS_64K_PAGES(vma->vm->i915)) {
/*
* We can't mix 64K and 4K PTEs in the same page-table
* (2M block), and so to avoid the ugliness and
@@ -1847,6 +1844,11 @@ int _i915_vma_move_to_active(struct i915_vma *vma,
GEM_BUG_ON(!vma->pages);
+ if (!(flags & __EXEC_OBJECT_NO_REQUEST_AWAIT)) {
+ err = i915_request_await_object(rq, vma->obj, flags & EXEC_OBJECT_WRITE);
+ if (unlikely(err))
+ return err;
+ }
err = __i915_vma_move_to_active(vma, rq);
if (unlikely(err))
return err;
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index aecd9c64486b..0757977a489b 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -55,6 +55,7 @@ static inline bool i915_vma_is_active(const struct i915_vma *vma)
/* do not reserve memory to prevent deadlocks */
#define __EXEC_OBJECT_NO_RESERVE BIT(31)
+#define __EXEC_OBJECT_NO_REQUEST_AWAIT BIT(30)
int __must_check _i915_vma_move_to_active(struct i915_vma *vma,
struct i915_request *rq,
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index 20575eb77ea7..849baf6c3b3c 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -29,9 +29,11 @@
#include "display/intel_cdclk.h"
#include "display/intel_de.h"
-#include "intel_device_info.h"
+#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
+#include "i915_reg.h"
#include "i915_utils.h"
+#include "intel_device_info.h"
#define PLATFORM_NAME(x) [INTEL_##x] = #x
static const char * const platform_names[] = {
@@ -231,7 +233,7 @@ static bool find_devid(u16 id, const u16 *p, unsigned int num)
return false;
}
-void intel_device_info_subplatform_init(struct drm_i915_private *i915)
+static void intel_device_info_subplatform_init(struct drm_i915_private *i915)
{
const struct intel_device_info *info = INTEL_INFO(i915);
const struct intel_runtime_info *rinfo = RUNTIME_INFO(i915);
@@ -288,6 +290,78 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915)
RUNTIME_INFO(i915)->platform_mask[pi] |= mask;
}
+static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct intel_ip_version *ip)
+{
+ struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ void __iomem *addr;
+ u32 val;
+ u8 expected_ver = ip->ver;
+ u8 expected_rel = ip->rel;
+
+ addr = pci_iomap_range(pdev, 0, offset, sizeof(u32));
+ if (drm_WARN_ON(&i915->drm, !addr))
+ return;
+
+ val = ioread32(addr);
+ pci_iounmap(pdev, addr);
+
+ ip->ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val);
+ ip->rel = REG_FIELD_GET(GMD_ID_RELEASE_MASK, val);
+ ip->step = REG_FIELD_GET(GMD_ID_STEP, val);
+
+ /* Sanity check against expected versions from device info */
+ if (IP_VER(ip->ver, ip->rel) < IP_VER(expected_ver, expected_rel))
+ drm_dbg(&i915->drm,
+ "Hardware reports GMD IP version %u.%u (REG[0x%x] = 0x%08x) but minimum expected is %u.%u\n",
+ ip->ver, ip->rel, offset, val, expected_ver, expected_rel);
+}
+
+/*
+ * Setup the graphics version for the current device. This must be done before
+ * any code that performs checks on GRAPHICS_VER or DISPLAY_VER, so this
+ * function should be called very early in the driver initialization sequence.
+ *
+ * Regular MMIO access is not yet setup at the point this function is called so
+ * we peek at the appropriate MMIO offset directly. The GMD_ID register is
+ * part of an 'always on' power well by design, so we don't need to worry about
+ * forcewake while reading it.
+ */
+static void intel_ipver_early_init(struct drm_i915_private *i915)
+{
+ struct intel_runtime_info *runtime = RUNTIME_INFO(i915);
+
+ if (!HAS_GMD_ID(i915)) {
+ drm_WARN_ON(&i915->drm, RUNTIME_INFO(i915)->graphics.ip.ver > 12);
+ /*
+ * On older platforms, graphics and media share the same ip
+ * version and release.
+ */
+ RUNTIME_INFO(i915)->media.ip =
+ RUNTIME_INFO(i915)->graphics.ip;
+ return;
+ }
+
+ ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_GRAPHICS),
+ &runtime->graphics.ip);
+ ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_DISPLAY),
+ &runtime->display.ip);
+ ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_MEDIA),
+ &runtime->media.ip);
+}
+
+/**
+ * intel_device_info_runtime_init_early - initialize early runtime info
+ * @i915: the i915 device
+ *
+ * Determine early intel_device_info fields at runtime. This function needs
+ * to be called before the MMIO has been setup.
+ */
+void intel_device_info_runtime_init_early(struct drm_i915_private *i915)
+{
+ intel_ipver_early_init(i915);
+ intel_device_info_subplatform_init(i915);
+}
+
/**
* intel_device_info_runtime_init - initialize runtime info
* @dev_priv: the i915 device
@@ -415,7 +489,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
if (DISPLAY_VER(dev_priv) >= 11 && (dfsm & ICL_DFSM_DMC_DISABLE))
runtime->has_dmc = 0;
- if (DISPLAY_VER(dev_priv) >= 10 &&
+ if (IS_DISPLAY_VER(dev_priv, 10, 12) &&
(dfsm & GLK_DFSM_DISPLAY_DSC_DISABLE))
runtime->has_dsc = 0;
}
@@ -442,6 +516,11 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
runtime->has_dmc = false;
runtime->has_dsc = false;
}
+
+ /* Disable nuclear pageflip by default on pre-g4x */
+ if (!dev_priv->params.nuclear_pageflip &&
+ DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
+ dev_priv->drm.driver_features &= ~DRIVER_ATOMIC;
}
void intel_driver_caps_print(const struct intel_driver_caps *caps,
diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
index d638235e1d26..d588e5fd2eea 100644
--- a/drivers/gpu/drm/i915/intel_device_info.h
+++ b/drivers/gpu/drm/i915/intel_device_info.h
@@ -146,13 +146,13 @@ enum intel_ppgtt_type {
/* Keep has_* in alphabetical order */ \
func(has_64bit_reloc); \
func(has_64k_pages); \
- func(needs_compact_pt); \
func(gpu_reset_clobbers_display); \
func(has_reset_engine); \
func(has_3d_pipeline); \
func(has_4tile); \
func(has_flat_ccs); \
func(has_global_mocs); \
+ func(has_gmd_id); \
func(has_gt_uc); \
func(has_heci_pxp); \
func(has_heci_gscfi); \
@@ -164,6 +164,8 @@ enum intel_ppgtt_type {
func(has_logical_ring_elsq); \
func(has_media_ratio_mode); \
func(has_mslice_steering); \
+ func(has_oa_bpc_reporting); \
+ func(has_oa_slice_contrib_limits); \
func(has_one_eu_per_fuse_bit); \
func(has_pxp); \
func(has_rc6); \
@@ -180,6 +182,7 @@ enum intel_ppgtt_type {
/* Keep in alphabetical order */ \
func(cursor_needs_physical); \
func(has_cdclk_crawl); \
+ func(has_cdclk_squash); \
func(has_ddi); \
func(has_dp_mst); \
func(has_dsb); \
@@ -195,20 +198,25 @@ enum intel_ppgtt_type {
func(overlay_needs_physical); \
func(supports_tv);
-struct ip_version {
+struct intel_ip_version {
u8 ver;
u8 rel;
+ u8 step;
};
struct intel_runtime_info {
+ /*
+ * Single "graphics" IP version that represents
+ * render, compute and copy behavior.
+ */
struct {
- struct ip_version ip;
+ struct intel_ip_version ip;
} graphics;
struct {
- struct ip_version ip;
+ struct intel_ip_version ip;
} media;
struct {
- struct ip_version ip;
+ struct intel_ip_version ip;
} display;
/*
@@ -308,7 +316,7 @@ struct intel_driver_caps {
const char *intel_platform_name(enum intel_platform platform);
-void intel_device_info_subplatform_init(struct drm_i915_private *dev_priv);
+void intel_device_info_runtime_init_early(struct drm_i915_private *dev_priv);
void intel_device_info_runtime_init(struct drm_i915_private *dev_priv);
void intel_device_info_print(const struct intel_device_info *info,
diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c
index 2403ccd52c74..bba8cb6e8ae4 100644
--- a/drivers/gpu/drm/i915/intel_dram.c
+++ b/drivers/gpu/drm/i915/intel_dram.c
@@ -471,8 +471,7 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915)
u32 val = intel_uncore_read(&i915->uncore, MTL_MEM_SS_INFO_GLOBAL);
struct dram_info *dram_info = &i915->dram_info;
- val = REG_FIELD_GET(MTL_DDR_TYPE_MASK, val);
- switch (val) {
+ switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) {
case 0:
dram_info->type = INTEL_DRAM_DDR4;
break;
diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
index 8279dc580a3e..ce6b3c3b636a 100644
--- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
+++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
@@ -6,6 +6,7 @@
#include "display/intel_audio_regs.h"
#include "display/intel_backlight_regs.h"
#include "display/intel_dmc_regs.h"
+#include "display/intel_dpio_phy.h"
#include "display/vlv_dsi_pll_regs.h"
#include "gt/intel_gt_regs.h"
#include "gvt/gvt.h"
@@ -102,7 +103,7 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter)
MMIO_D(_MMIO(0x2438));
MMIO_D(_MMIO(0x243c));
MMIO_D(_MMIO(0x7018));
- MMIO_D(HALF_SLICE_CHICKEN3);
+ MMIO_D(HSW_HALF_SLICE_CHICKEN3);
MMIO_D(GEN7_HALF_SLICE_CHICKEN1);
/* display */
MMIO_F(_MMIO(0x60220), 0x20);
diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h
index ffc702b79579..f93e9af43ac3 100644
--- a/drivers/gpu/drm/i915/intel_mchbar_regs.h
+++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h
@@ -189,6 +189,21 @@
#define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2)
#define DG1_QCLK_REFERENCE REG_BIT(10)
+/*
+ * *_PACKAGE_POWER_SKU - SKU power and timing parameters.
+ */
+#define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930)
+#define PKG_PKG_TDP GENMASK_ULL(14, 0)
+#define PKG_MAX_WIN GENMASK_ULL(54, 48)
+#define PKG_MAX_WIN_X GENMASK_ULL(54, 53)
+#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48)
+
+#define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938)
+#define PKG_PWR_UNIT REG_GENMASK(3, 0)
+#define PKG_ENERGY_UNIT REG_GENMASK(12, 8)
+#define PKG_TIME_UNIT REG_GENMASK(19, 16)
+#define PCU_PACKAGE_ENERGY_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x593c)
+
#define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948)
#define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994)
#define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998)
@@ -198,6 +213,12 @@
#define GEN10_FREQ_INFO_REC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5ef0)
#define RPE_MASK REG_GENMASK(15, 8)
+#define PCU_PACKAGE_RAPL_LIMIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x59a0)
+#define PKG_PWR_LIM_1 REG_GENMASK(14, 0)
+#define PKG_PWR_LIM_1_EN REG_BIT(15)
+#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17)
+#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22)
+#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17)
/* snb MCH registers for priority tuning */
#define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10)
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index 9a4a7fb55582..b9a164efd6ae 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -38,7 +38,7 @@ static int __iopagetest(struct intel_memory_region *mem,
u8 value, resource_size_t offset,
const void *caller)
{
- int byte = prandom_u32_max(pagesize);
+ int byte = get_random_u32_below(pagesize);
u8 result[3];
memset_io(va, value, pagesize); /* or GPF! */
@@ -92,7 +92,7 @@ static int iopagetest(struct intel_memory_region *mem,
static resource_size_t random_page(resource_size_t last)
{
/* Limited to low 44b (16TiB), but should suffice for a spot check */
- return prandom_u32_max(last >> PAGE_SHIFT) << PAGE_SHIFT;
+ return get_random_u32_below(last >> PAGE_SHIFT) << PAGE_SHIFT;
}
static int iomemtest(struct intel_memory_region *mem,
diff --git a/drivers/gpu/drm/i915/intel_pci_config.h b/drivers/gpu/drm/i915/intel_pci_config.h
index 4977a524ce6f..23b8e519f333 100644
--- a/drivers/gpu/drm/i915/intel_pci_config.h
+++ b/drivers/gpu/drm/i915/intel_pci_config.h
@@ -7,11 +7,29 @@
#define __INTEL_PCI_CONFIG_H__
/* PCI BARs */
-#define GTTMMADR_BAR 0
-#define GEN2_GTTMMADR_BAR 1
-#define GFXMEM_BAR 2
-#define GTT_APERTURE_BAR GFXMEM_BAR
-#define GEN12_LMEM_BAR GFXMEM_BAR
+#define GEN2_GMADR_BAR 0
+#define GEN2_MMADR_BAR 1 /* MMIO+GTT, despite the name */
+#define GEN2_IO_BAR 2 /* 85x/865 */
+
+#define GEN3_MMADR_BAR 0 /* MMIO only */
+#define GEN3_IO_BAR 1
+#define GEN3_GMADR_BAR 2
+#define GEN3_GTTADR_BAR 3 /* GTT only */
+
+#define GEN4_GTTMMADR_BAR 0 /* MMIO+GTT */
+#define GEN4_GMADR_BAR 2
+#define GEN4_IO_BAR 4
+
+#define GEN12_LMEM_BAR 2
+
+static inline int intel_mmio_bar(int graphics_ver)
+{
+ switch (graphics_ver) {
+ case 2: return GEN2_MMADR_BAR;
+ case 3: return GEN3_MMADR_BAR;
+ default: return GEN4_GTTMMADR_BAR;
+ }
+}
/* BSM in include/drm/i915_drm.h */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 8f86f56e7ca4..73c88b1c9545 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -30,6 +30,8 @@
#include "display/skl_watermark.h"
#include "gt/intel_engine_regs.h"
+#include "gt/intel_gt.h"
+#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
@@ -58,25 +60,20 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)
* Must match Sampler, Pixel Back End, and Media. See
* WaCompressedResourceSamplerPbeMediaNewHashMode.
*/
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) |
- SKL_DE_COMPRESSED_HASH_MODE);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, SKL_DE_COMPRESSED_HASH_MODE);
}
/* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, SKL_EDP_PSR_FIX_RDWRAP);
/* WaEnableChickenDCPR:skl,bxt,kbl,glk,cfl */
- intel_uncore_write(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1,
- intel_uncore_read(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1, 0, MASK_WAKEMEM);
/*
* WaFbcWakeMemOn:skl,bxt,kbl,glk,cfl
* Display WA #0859: skl,bxt,kbl,glk,cfl
*/
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) |
- DISP_FBC_MEMORY_WAKE);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_MEMORY_WAKE);
}
static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -84,15 +81,13 @@ static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WaDisableSDEUnitClockGating:bxt */
- intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/*
* FIXME:
* GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ applies on 3x6 GT SKUs only.
*/
- intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
- GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
/*
* Wa: Backlight PWM may stop in the asserted state, causing backlight
@@ -113,16 +108,13 @@ static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
* WaFbcTurnOffFbcWatermark:bxt
* Display WA #0562: bxt
*/
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) |
- DISP_FBC_WM_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
/*
* WaFbcHighMemBwCorruptionAvoidance:bxt
* Display WA #0883: bxt
*/
- intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
- intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) |
- DPFC_DISABLE_DUMMY0);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), 0, DPFC_DISABLE_DUMMY0);
}
static void glk_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -895,19 +887,14 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
wm = intel_calculate_wm(pixel_rate, &pnv_cursor_wm,
pnv_display_wm.fifo_size,
4, latency->cursor_sr);
- reg = intel_uncore_read(&dev_priv->uncore, DSPFW3);
- reg &= ~DSPFW_CURSOR_SR_MASK;
- reg |= FW_WM(wm, CURSOR_SR);
- intel_uncore_write(&dev_priv->uncore, DSPFW3, reg);
+ intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_CURSOR_SR_MASK,
+ FW_WM(wm, CURSOR_SR));
/* Display HPLL off SR */
wm = intel_calculate_wm(pixel_rate, &pnv_display_hplloff_wm,
pnv_display_hplloff_wm.fifo_size,
cpp, latency->display_hpll_disable);
- reg = intel_uncore_read(&dev_priv->uncore, DSPFW3);
- reg &= ~DSPFW_HPLL_SR_MASK;
- reg |= FW_WM(wm, HPLL_SR);
- intel_uncore_write(&dev_priv->uncore, DSPFW3, reg);
+ intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_HPLL_SR_MASK, FW_WM(wm, HPLL_SR));
/* cursor HPLL off SR */
wm = intel_calculate_wm(pixel_rate, &pnv_cursor_hplloff_wm,
@@ -1337,34 +1324,14 @@ static bool g4x_compute_fbc_en(const struct g4x_wm_state *wm_state,
return true;
}
-static int g4x_compute_pipe_wm(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
+static int _g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state)
{
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal;
u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
const struct g4x_pipe_wm *raw;
- const struct intel_plane_state *old_plane_state;
- const struct intel_plane_state *new_plane_state;
- struct intel_plane *plane;
enum plane_id plane_id;
- int i, level;
- unsigned int dirty = 0;
-
- for_each_oldnew_intel_plane_in_state(state, plane,
- old_plane_state,
- new_plane_state, i) {
- if (new_plane_state->hw.crtc != &crtc->base &&
- old_plane_state->hw.crtc != &crtc->base)
- continue;
-
- if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
- dirty |= BIT(plane->id);
- }
-
- if (!dirty)
- return 0;
+ int level;
level = G4X_WM_LEVEL_NORMAL;
if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
@@ -1417,6 +1384,34 @@ static int g4x_compute_pipe_wm(struct intel_atomic_state *state,
return 0;
}
+static int g4x_compute_pipe_wm(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ const struct intel_plane_state *old_plane_state;
+ const struct intel_plane_state *new_plane_state;
+ struct intel_plane *plane;
+ unsigned int dirty = 0;
+ int i;
+
+ for_each_oldnew_intel_plane_in_state(state, plane,
+ old_plane_state,
+ new_plane_state, i) {
+ if (new_plane_state->hw.crtc != &crtc->base &&
+ old_plane_state->hw.crtc != &crtc->base)
+ continue;
+
+ if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
+ dirty |= BIT(plane->id);
+ }
+
+ if (!dirty)
+ return 0;
+
+ return _g4x_compute_pipe_wm(crtc_state);
+}
+
static int g4x_compute_intermediate_wm(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -1431,7 +1426,7 @@ static int g4x_compute_intermediate_wm(struct intel_atomic_state *state,
enum plane_id plane_id;
if (!new_crtc_state->hw.active ||
- drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) {
+ intel_crtc_needs_modeset(new_crtc_state)) {
*intermediate = *optimal;
intermediate->cxsr = false;
@@ -1857,64 +1852,17 @@ static bool vlv_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state,
vlv_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level);
}
-static int vlv_compute_pipe_wm(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
+static int _vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state)
{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
const struct vlv_fifo_state *fifo_state =
&crtc_state->wm.vlv.fifo_state;
u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
int num_active_planes = hweight8(active_planes);
- bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi);
- const struct intel_plane_state *old_plane_state;
- const struct intel_plane_state *new_plane_state;
- struct intel_plane *plane;
enum plane_id plane_id;
- int level, ret, i;
- unsigned int dirty = 0;
-
- for_each_oldnew_intel_plane_in_state(state, plane,
- old_plane_state,
- new_plane_state, i) {
- if (new_plane_state->hw.crtc != &crtc->base &&
- old_plane_state->hw.crtc != &crtc->base)
- continue;
-
- if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
- dirty |= BIT(plane->id);
- }
-
- /*
- * DSPARB registers may have been reset due to the
- * power well being turned off. Make sure we restore
- * them to a consistent state even if no primary/sprite
- * planes are initially active.
- */
- if (needs_modeset)
- crtc_state->fifo_changed = true;
-
- if (!dirty)
- return 0;
-
- /* cursor changes don't warrant a FIFO recompute */
- if (dirty & ~BIT(PLANE_CURSOR)) {
- const struct intel_crtc_state *old_crtc_state =
- intel_atomic_get_old_crtc_state(state, crtc);
- const struct vlv_fifo_state *old_fifo_state =
- &old_crtc_state->wm.vlv.fifo_state;
-
- ret = vlv_compute_fifo(crtc_state);
- if (ret)
- return ret;
-
- if (needs_modeset ||
- memcmp(old_fifo_state, fifo_state,
- sizeof(*fifo_state)) != 0)
- crtc_state->fifo_changed = true;
- }
+ int level;
/* initially allow all levels */
wm_state->num_levels = intel_wm_num_levels(dev_priv);
@@ -1961,6 +1909,66 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state,
return 0;
}
+static int vlv_compute_pipe_wm(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ const struct intel_plane_state *old_plane_state;
+ const struct intel_plane_state *new_plane_state;
+ struct intel_plane *plane;
+ unsigned int dirty = 0;
+ int i;
+
+ for_each_oldnew_intel_plane_in_state(state, plane,
+ old_plane_state,
+ new_plane_state, i) {
+ if (new_plane_state->hw.crtc != &crtc->base &&
+ old_plane_state->hw.crtc != &crtc->base)
+ continue;
+
+ if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
+ dirty |= BIT(plane->id);
+ }
+
+ /*
+ * DSPARB registers may have been reset due to the
+ * power well being turned off. Make sure we restore
+ * them to a consistent state even if no primary/sprite
+ * planes are initially active. We also force a FIFO
+ * recomputation so that we are sure to sanitize the
+ * FIFO setting we took over from the BIOS even if there
+ * are no active planes on the crtc.
+ */
+ if (intel_crtc_needs_modeset(crtc_state))
+ dirty = ~0;
+
+ if (!dirty)
+ return 0;
+
+ /* cursor changes don't warrant a FIFO recompute */
+ if (dirty & ~BIT(PLANE_CURSOR)) {
+ const struct intel_crtc_state *old_crtc_state =
+ intel_atomic_get_old_crtc_state(state, crtc);
+ const struct vlv_fifo_state *old_fifo_state =
+ &old_crtc_state->wm.vlv.fifo_state;
+ const struct vlv_fifo_state *new_fifo_state =
+ &crtc_state->wm.vlv.fifo_state;
+ int ret;
+
+ ret = vlv_compute_fifo(crtc_state);
+ if (ret)
+ return ret;
+
+ if (intel_crtc_needs_modeset(crtc_state) ||
+ memcmp(old_fifo_state, new_fifo_state,
+ sizeof(*new_fifo_state)) != 0)
+ crtc_state->fifo_changed = true;
+ }
+
+ return _vlv_compute_pipe_wm(crtc_state);
+}
+
#define VLV_FIFO(plane, value) \
(((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV)
@@ -2075,7 +2083,7 @@ static int vlv_compute_intermediate_wm(struct intel_atomic_state *state,
int level;
if (!new_crtc_state->hw.active ||
- drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) {
+ intel_crtc_needs_modeset(new_crtc_state)) {
*intermediate = *optimal;
intermediate->cxsr = false;
@@ -3133,7 +3141,7 @@ static int ilk_compute_intermediate_wm(struct intel_atomic_state *state,
*/
*a = new_crtc_state->wm.ilk.optimal;
if (!new_crtc_state->hw.active ||
- drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) ||
+ intel_crtc_needs_modeset(new_crtc_state) ||
state->skip_intermediate_wm)
return 0;
@@ -3458,7 +3466,6 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
{
struct ilk_wm_values *previous = &dev_priv->display.wm.hw;
unsigned int dirty;
- u32 val;
dirty = ilk_compute_wm_dirty(dev_priv, previous, results);
if (!dirty)
@@ -3474,32 +3481,20 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
intel_uncore_write(&dev_priv->uncore, WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]);
if (dirty & WM_DIRTY_DDB) {
- if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
- val = intel_uncore_read(&dev_priv->uncore, WM_MISC);
- if (results->partitioning == INTEL_DDB_PART_1_2)
- val &= ~WM_MISC_DATA_PARTITION_5_6;
- else
- val |= WM_MISC_DATA_PARTITION_5_6;
- intel_uncore_write(&dev_priv->uncore, WM_MISC, val);
- } else {
- val = intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL2);
- if (results->partitioning == INTEL_DDB_PART_1_2)
- val &= ~DISP_DATA_PARTITION_5_6;
- else
- val |= DISP_DATA_PARTITION_5_6;
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL2, val);
- }
- }
-
- if (dirty & WM_DIRTY_FBC) {
- val = intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL);
- if (results->enable_fbc_wm)
- val &= ~DISP_FBC_WM_DIS;
+ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+ intel_uncore_rmw(&dev_priv->uncore, WM_MISC, WM_MISC_DATA_PARTITION_5_6,
+ results->partitioning == INTEL_DDB_PART_1_2 ? 0 :
+ WM_MISC_DATA_PARTITION_5_6);
else
- val |= DISP_FBC_WM_DIS;
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, val);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL2, DISP_DATA_PARTITION_5_6,
+ results->partitioning == INTEL_DDB_PART_1_2 ? 0 :
+ DISP_DATA_PARTITION_5_6);
}
+ if (dirty & WM_DIRTY_FBC)
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, DISP_FBC_WM_DIS,
+ results->enable_fbc_wm ? 0 : DISP_FBC_WM_DIS);
+
if (dirty & WM_DIRTY_LP(1) &&
previous->wm_lp_spr[0] != results->wm_lp_spr[0])
intel_uncore_write(&dev_priv->uncore, WM1S_LP_ILK, results->wm_lp_spr[0]);
@@ -3824,6 +3819,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv)
plane_id, USHRT_MAX);
g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX);
+ g4x_invalidate_wms(crtc, active, level);
+
crtc_state->wm.g4x.optimal = *active;
crtc_state->wm.g4x.intermediate = *active;
@@ -3860,37 +3857,30 @@ void g4x_wm_sanitize(struct drm_i915_private *dev_priv)
to_intel_crtc_state(crtc->base.state);
struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
- struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal;
enum plane_id plane_id = plane->id;
- int level;
+ int level, num_levels = intel_wm_num_levels(dev_priv);
if (plane_state->uapi.visible)
continue;
- for (level = 0; level < 3; level++) {
+ for (level = 0; level < num_levels; level++) {
struct g4x_pipe_wm *raw =
&crtc_state->wm.g4x.raw[level];
raw->plane[plane_id] = 0;
- wm_state->wm.plane[plane_id] = 0;
- }
- if (plane_id == PLANE_PRIMARY) {
- for (level = 0; level < 3; level++) {
- struct g4x_pipe_wm *raw =
- &crtc_state->wm.g4x.raw[level];
+ if (plane_id == PLANE_PRIMARY)
raw->fbc = 0;
- }
-
- wm_state->sr.fbc = 0;
- wm_state->hpll.fbc = 0;
- wm_state->fbc_en = false;
}
}
for_each_intel_crtc(&dev_priv->drm, crtc) {
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
+ int ret;
+
+ ret = _g4x_compute_pipe_wm(crtc_state);
+ drm_WARN_ON(&dev_priv->drm, ret);
crtc_state->wm.g4x.intermediate =
crtc_state->wm.g4x.optimal;
@@ -4016,30 +4006,27 @@ void vlv_wm_sanitize(struct drm_i915_private *dev_priv)
to_intel_crtc_state(crtc->base.state);
struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
- struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
- const struct vlv_fifo_state *fifo_state =
- &crtc_state->wm.vlv.fifo_state;
enum plane_id plane_id = plane->id;
- int level;
+ int level, num_levels = intel_wm_num_levels(dev_priv);
if (plane_state->uapi.visible)
continue;
- for (level = 0; level < wm_state->num_levels; level++) {
+ for (level = 0; level < num_levels; level++) {
struct g4x_pipe_wm *raw =
&crtc_state->wm.vlv.raw[level];
raw->plane[plane_id] = 0;
-
- wm_state->wm[level].plane[plane_id] =
- vlv_invert_wm_value(raw->plane[plane_id],
- fifo_state->plane[plane_id]);
}
}
for_each_intel_crtc(&dev_priv->drm, crtc) {
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
+ int ret;
+
+ ret = _vlv_compute_pipe_wm(crtc_state);
+ drm_WARN_ON(&dev_priv->drm, ret);
crtc_state->wm.vlv.intermediate =
crtc_state->wm.vlv.optimal;
@@ -4057,9 +4044,9 @@ void vlv_wm_sanitize(struct drm_i915_private *dev_priv)
*/
static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv)
{
- intel_uncore_write(&dev_priv->uncore, WM3_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM3_LP_ILK) & ~WM_LP_ENABLE);
- intel_uncore_write(&dev_priv->uncore, WM2_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM2_LP_ILK) & ~WM_LP_ENABLE);
- intel_uncore_write(&dev_priv->uncore, WM1_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM1_LP_ILK) & ~WM_LP_ENABLE);
+ intel_uncore_rmw(&dev_priv->uncore, WM3_LP_ILK, WM_LP_ENABLE, 0);
+ intel_uncore_rmw(&dev_priv->uncore, WM2_LP_ILK, WM_LP_ENABLE, 0);
+ intel_uncore_rmw(&dev_priv->uncore, WM1_LP_ILK, WM_LP_ENABLE, 0);
/*
* Don't touch WM_LP_SPRITE_ENABLE here.
@@ -4113,11 +4100,9 @@ static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv)
enum pipe pipe;
for_each_pipe(dev_priv, pipe) {
- intel_uncore_write(&dev_priv->uncore, DSPCNTR(pipe),
- intel_uncore_read(&dev_priv->uncore, DSPCNTR(pipe)) |
- DISP_TRICKLE_FEED_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, DSPCNTR(pipe), 0, DISP_TRICKLE_FEED_DISABLE);
- intel_uncore_write(&dev_priv->uncore, DSPSURF(pipe), intel_uncore_read(&dev_priv->uncore, DSPSURF(pipe)));
+ intel_uncore_rmw(&dev_priv->uncore, DSPSURF(pipe), 0, 0);
intel_uncore_posting_read(&dev_priv->uncore, DSPSURF(pipe));
}
}
@@ -4164,19 +4149,13 @@ static void ilk_init_clock_gating(struct drm_i915_private *dev_priv)
*/
if (IS_IRONLAKE_M(dev_priv)) {
/* WaFbcAsynchFlipDisableFbcQueue:ilk */
- intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1,
- intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS);
- intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2,
- intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_DPARB_GATE);
}
intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, dspclk_gate);
- intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2,
- intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT);
g4x_disable_trickle_feed(dev_priv);
@@ -4196,8 +4175,7 @@ static void cpt_init_clock_gating(struct drm_i915_private *dev_priv)
intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE |
PCH_DPLUNIT_CLOCK_GATE_DISABLE |
PCH_CPUNIT_CLOCK_GATE_DISABLE);
- intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN2, intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN2) |
- DPLS_EDP_PPS_FIX_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN2, 0, DPLS_EDP_PPS_FIX_DIS);
/* The below fixes the weird display corruption, a few pixels shifted
* downward, on (only) LVDS of some HP laptops with IVY.
*/
@@ -4235,9 +4213,7 @@ static void gen6_init_clock_gating(struct drm_i915_private *dev_priv)
intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, dspclk_gate);
- intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2,
- intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT);
intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1,
intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) |
@@ -4297,14 +4273,12 @@ static void lpt_init_clock_gating(struct drm_i915_private *dev_priv)
* disabled when not needed anymore in order to save power.
*/
if (HAS_PCH_LPT_LP(dev_priv))
- intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D,
- intel_uncore_read(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D) |
- PCH_LP_PARTITION_LEVEL_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D,
+ 0, PCH_LP_PARTITION_LEVEL_DISABLE);
/* WADPOClockGatingDisable:hsw */
- intel_uncore_write(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A),
- intel_uncore_read(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A)) |
- TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A),
+ 0, TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
}
static void lpt_suspend_hw(struct drm_i915_private *dev_priv)
@@ -4325,22 +4299,22 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv,
u32 val;
/* WaTempDisableDOPClkGating:bdw */
- misccpctl = intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL);
- intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+ misccpctl = intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL,
+ GEN8_DOP_CLOCK_GATE_ENABLE, 0);
- val = intel_uncore_read(&dev_priv->uncore, GEN8_L3SQCREG1);
+ val = intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1);
val &= ~L3_PRIO_CREDITS_MASK;
val |= L3_GENERAL_PRIO_CREDITS(general_prio_credits);
val |= L3_HIGH_PRIO_CREDITS(high_prio_credits);
- intel_uncore_write(&dev_priv->uncore, GEN8_L3SQCREG1, val);
+ intel_gt_mcr_multicast_write(to_gt(dev_priv), GEN8_L3SQCREG1, val);
/*
* Wait at least 100 clocks before re-enabling clock gating.
* See the definition of L3SQCREG1 in BSpec.
*/
- intel_uncore_posting_read(&dev_priv->uncore, GEN8_L3SQCREG1);
+ intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1);
udelay(1);
- intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl);
+ intel_gt_mcr_multicast_write(to_gt(dev_priv), GEN8_MISCCPCTL, misccpctl);
}
static void icl_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4363,8 +4337,7 @@ static void gen12lp_init_clock_gating(struct drm_i915_private *dev_priv)
/* Wa_1409825376:tgl (pre-prod)*/
if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_C0))
- intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
- TGL_VRH_GATING_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, 0, TGL_VRH_GATING_DIS);
/* Wa_14013723622:tgl,rkl,dg1,adl-s */
if (DISPLAY_VER(dev_priv) == 12)
@@ -4389,8 +4362,7 @@ static void dg1_init_clock_gating(struct drm_i915_private *dev_priv)
/* Wa_1409836686:dg1[a0] */
if (IS_DG1_GRAPHICS_STEP(dev_priv, STEP_A0, STEP_B0))
- intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
- DPT_GATING_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, 0, DPT_GATING_DIS);
}
static void xehpsdv_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4432,8 +4404,7 @@ static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
return;
/* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */
- intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, intel_uncore_read(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D) |
- CNP_PWM_CGE_GATING_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, 0, CNP_PWM_CGE_GATING_DISABLE);
}
static void cfl_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4442,23 +4413,20 @@ static void cfl_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WAC6entrylatency:cfl */
- intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) |
- FBC_LLC_FULLY_OPEN);
+ intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
/*
* WaFbcTurnOffFbcWatermark:cfl
* Display WA #0562: cfl
*/
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) |
- DISP_FBC_WM_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
/*
* WaFbcNukeOnHostModify:cfl
* Display WA #0873: cfl
*/
- intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
- intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) |
- DPFC_NUKE_ON_ANY_MODIFICATION);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
+ 0, DPFC_NUKE_ON_ANY_MODIFICATION);
}
static void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4466,33 +4434,30 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WAC6entrylatency:kbl */
- intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) |
- FBC_LLC_FULLY_OPEN);
+ intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
/* WaDisableSDEUnitClockGating:kbl */
if (IS_KBL_GRAPHICS_STEP(dev_priv, 0, STEP_C0))
- intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6,
+ 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/* WaDisableGamClockGating:kbl */
if (IS_KBL_GRAPHICS_STEP(dev_priv, 0, STEP_C0))
- intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) |
- GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1,
+ 0, GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
/*
* WaFbcTurnOffFbcWatermark:kbl
* Display WA #0562: kbl
*/
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) |
- DISP_FBC_WM_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
/*
* WaFbcNukeOnHostModify:kbl
* Display WA #0873: kbl
*/
- intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
- intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) |
- DPFC_NUKE_ON_ANY_MODIFICATION);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
+ 0, DPFC_NUKE_ON_ANY_MODIFICATION);
}
static void skl_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4500,35 +4465,30 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WaDisableDopClockGating:skl */
- intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL) &
- ~GEN7_DOP_CLOCK_GATE_ENABLE);
+ intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL,
+ GEN8_DOP_CLOCK_GATE_ENABLE, 0);
/* WAC6entrylatency:skl */
- intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) |
- FBC_LLC_FULLY_OPEN);
+ intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
/*
* WaFbcTurnOffFbcWatermark:skl
* Display WA #0562: skl
*/
- intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) |
- DISP_FBC_WM_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
/*
* WaFbcNukeOnHostModify:skl
* Display WA #0873: skl
*/
- intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
- intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) |
- DPFC_NUKE_ON_ANY_MODIFICATION);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
+ 0, DPFC_NUKE_ON_ANY_MODIFICATION);
/*
* WaFbcHighMemBwCorruptionAvoidance:skl
* Display WA #0883: skl
*/
- intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A),
- intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) |
- DPFC_DISABLE_DUMMY0);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), 0, DPFC_DISABLE_DUMMY0);
}
static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4536,43 +4496,37 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
enum pipe pipe;
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A),
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) |
- HSW_FBCQ_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS);
/* WaSwitchSolVfFArbitrationPriority:bdw */
- intel_uncore_write(&dev_priv->uncore, GAM_ECOCHK, intel_uncore_read(&dev_priv->uncore, GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
+ intel_uncore_rmw(&dev_priv->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL);
/* WaPsrDPAMaskVBlankInSRD:bdw */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, DPA_MASK_VBLANK_SRD);
for_each_pipe(dev_priv, pipe) {
/* WaPsrDPRSUnmaskVBlankInSRD:bdw */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) |
- BDW_DPRS_MASK_VBLANK_SRD);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
+ 0, BDW_DPRS_MASK_VBLANK_SRD);
}
/* WaVSRefCountFullforceMissDisable:bdw */
/* WaDSRefCountFullforceMissDisable:bdw */
- intel_uncore_write(&dev_priv->uncore, GEN7_FF_THREAD_MODE,
- intel_uncore_read(&dev_priv->uncore, GEN7_FF_THREAD_MODE) &
- ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_FF_THREAD_MODE,
+ GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME, 0);
intel_uncore_write(&dev_priv->uncore, RING_PSMI_CTL(RENDER_RING_BASE),
_MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
/* WaDisableSDEUnitClockGating:bdw */
- intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/* WaProgramL3SqcReg1Default:bdw */
gen8_set_l3sqc_credits(dev_priv, 30, 2);
/* WaKVMNotificationOnConfigChange:bdw */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR2_1, intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR2_1)
- | KVM_CONFIG_CHANGE_NOTIFICATION_SELECT);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR2_1,
+ 0, KVM_CONFIG_CHANGE_NOTIFICATION_SELECT);
lpt_init_clock_gating(dev_priv);
@@ -4581,38 +4535,30 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
* Also see the CHICKEN2 write in bdw_init_workarounds() to disable DOP
* clock gating.
*/
- intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1,
- intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) | GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1, 0, GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
}
static void hsw_init_clock_gating(struct drm_i915_private *dev_priv)
{
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
- intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A),
- intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) |
- HSW_FBCQ_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS);
/* This is required by WaCatErrorRejectionIssue:hsw */
- intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
/* WaSwitchSolVfFArbitrationPriority:hsw */
- intel_uncore_write(&dev_priv->uncore, GAM_ECOCHK, intel_uncore_read(&dev_priv->uncore, GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
+ intel_uncore_rmw(&dev_priv->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL);
lpt_init_clock_gating(dev_priv);
}
static void ivb_init_clock_gating(struct drm_i915_private *dev_priv)
{
- u32 snpcr;
-
intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
/* WaFbcAsynchFlipDisableFbcQueue:ivb */
- intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1,
- intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS);
+ intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS);
/* WaDisableBackToBackFlipFix:ivb */
intel_uncore_write(&dev_priv->uncore, IVB_CHICKEN3,
@@ -4638,16 +4584,13 @@ static void ivb_init_clock_gating(struct drm_i915_private *dev_priv)
GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
/* This is required by WaCatErrorRejectionIssue:ivb */
- intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
g4x_disable_trickle_feed(dev_priv);
- snpcr = intel_uncore_read(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR);
- snpcr &= ~GEN6_MBC_SNPCR_MASK;
- snpcr |= GEN6_MBC_SNPCR_MED;
- intel_uncore_write(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR, snpcr);
+ intel_uncore_rmw(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR, GEN6_MBC_SNPCR_MASK,
+ GEN6_MBC_SNPCR_MED);
if (!HAS_PCH_NOP(dev_priv))
cpt_init_clock_gating(dev_priv);
@@ -4667,9 +4610,8 @@ static void vlv_init_clock_gating(struct drm_i915_private *dev_priv)
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
/* This is required by WaCatErrorRejectionIssue:vlv */
- intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
/*
* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
@@ -4681,8 +4623,7 @@ static void vlv_init_clock_gating(struct drm_i915_private *dev_priv)
/* WaDisableL3Bank2xClockGate:vlv
* Disabling L3 clock gating- MMIO 940c[25] = 1
* Set bit 25, to disable L3_BANK_2x_CLK_GATING */
- intel_uncore_write(&dev_priv->uncore, GEN7_UCGCTL4,
- intel_uncore_read(&dev_priv->uncore, GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_UCGCTL4, 0, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
/*
* WaDisableVLVClockGating_VBIIssue:vlv
@@ -4696,21 +4637,18 @@ static void chv_init_clock_gating(struct drm_i915_private *dev_priv)
{
/* WaVSRefCountFullforceMissDisable:chv */
/* WaDSRefCountFullforceMissDisable:chv */
- intel_uncore_write(&dev_priv->uncore, GEN7_FF_THREAD_MODE,
- intel_uncore_read(&dev_priv->uncore, GEN7_FF_THREAD_MODE) &
- ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_FF_THREAD_MODE,
+ GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME, 0);
/* WaDisableSemaphoreAndSyncFlipWait:chv */
intel_uncore_write(&dev_priv->uncore, RING_PSMI_CTL(RENDER_RING_BASE),
_MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
/* WaDisableCSUnitClockGating:chv */
- intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) |
- GEN6_CSUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1, 0, GEN6_CSUNIT_CLOCK_GATE_DISABLE);
/* WaDisableSDEUnitClockGating:chv */
- intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/*
* WaProgramL3SqcReg1Default:chv
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index 575d67bc6ffe..cf89d0c2a2d9 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -244,7 +244,7 @@ void intel_region_ttm_resource_free(struct intel_memory_region *mem,
struct ttm_resource_manager *man = mem->region_private;
struct ttm_buffer_object mock_bo = {};
- mock_bo.base.size = res->num_pages << PAGE_SHIFT;
+ mock_bo.base.size = res->size;
mock_bo.bdev = &mem->i915->bdev;
res->bo = &mock_bo;
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 744cca507946..129746713d07 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -633,6 +633,8 @@ void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm)
runtime_pm);
int count = atomic_read(&rpm->wakeref_count);
+ intel_wakeref_auto_fini(&rpm->userfault_wakeref);
+
drm_WARN(&i915->drm, count,
"i915 raw-wakerefs=%d wakelocks=%d on cleanup\n",
intel_rpm_raw_wakeref_count(count),
@@ -652,4 +654,7 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm)
rpm->available = HAS_RUNTIME_PM(i915);
init_intel_runtime_pm_wakeref(rpm);
+ INIT_LIST_HEAD(&rpm->lmem_userfault_list);
+ spin_lock_init(&rpm->lmem_userfault_lock);
+ intel_wakeref_auto_init(&rpm->userfault_wakeref, rpm);
}
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h
index d9160e3ff4af..98b8b28baaa1 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.h
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.h
@@ -53,6 +53,28 @@ struct intel_runtime_pm {
bool irqs_enabled;
bool no_wakeref_tracking;
+ /*
+ * Protects access to lmem usefault list.
+ * It is required, if we are outside of the runtime suspend path,
+ * access to @lmem_userfault_list requires always first grabbing the
+ * runtime pm, to ensure we can't race against runtime suspend.
+ * Once we have that we also need to grab @lmem_userfault_lock,
+ * at which point we have exclusive access.
+ * The runtime suspend path is special since it doesn't really hold any locks,
+ * but instead has exclusive access by virtue of all other accesses requiring
+ * holding the runtime pm wakeref.
+ */
+ spinlock_t lmem_userfault_lock;
+
+ /*
+ * Keep list of userfaulted gem obj, which require to release their
+ * mmap mappings at runtime suspend path.
+ */
+ struct list_head lmem_userfault_list;
+
+ /* Manual runtime pm autosuspend delay for user GGTT/lmem mmaps */
+ struct intel_wakeref_auto userfault_wakeref;
+
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
/*
* To aide detection of wakeref leaks and general misuse, we
diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c
index 42b3133d8387..84a6fe736a3b 100644
--- a/drivers/gpu/drm/i915/intel_step.c
+++ b/drivers/gpu/drm/i915/intel_step.c
@@ -131,10 +131,27 @@ static const struct intel_step_info adls_rpls_revids[] = {
[0xC] = { COMMON_GT_MEDIA_STEP(D0), .display_step = STEP_C0 },
};
+static const struct intel_step_info adlp_rplp_revids[] = {
+ [0x4] = { COMMON_GT_MEDIA_STEP(C0), .display_step = STEP_E0 },
+};
+
static const struct intel_step_info adlp_n_revids[] = {
[0x0] = { COMMON_GT_MEDIA_STEP(A0), .display_step = STEP_D0 },
};
+static u8 gmd_to_intel_step(struct drm_i915_private *i915,
+ struct intel_ip_version *gmd)
+{
+ u8 step = gmd->step + STEP_A0;
+
+ if (step >= STEP_FUTURE) {
+ drm_dbg(&i915->drm, "Using future steppings\n");
+ return STEP_FUTURE;
+ }
+
+ return step;
+}
+
static void pvc_step_init(struct drm_i915_private *i915, int pci_revid);
void intel_step_init(struct drm_i915_private *i915)
@@ -144,6 +161,18 @@ void intel_step_init(struct drm_i915_private *i915)
int revid = INTEL_REVID(i915);
struct intel_step_info step = {};
+ if (HAS_GMD_ID(i915)) {
+ step.graphics_step = gmd_to_intel_step(i915,
+ &RUNTIME_INFO(i915)->graphics.ip);
+ step.media_step = gmd_to_intel_step(i915,
+ &RUNTIME_INFO(i915)->media.ip);
+ step.display_step = gmd_to_intel_step(i915,
+ &RUNTIME_INFO(i915)->display.ip);
+ RUNTIME_INFO(i915)->step = step;
+
+ return;
+ }
+
if (IS_PONTEVECCHIO(i915)) {
pvc_step_init(i915, revid);
return;
@@ -162,6 +191,9 @@ void intel_step_init(struct drm_i915_private *i915)
} else if (IS_ADLP_N(i915)) {
revids = adlp_n_revids;
size = ARRAY_SIZE(adlp_n_revids);
+ } else if (IS_ADLP_RPLP(i915)) {
+ revids = adlp_rplp_revids;
+ size = ARRAY_SIZE(adlp_rplp_revids);
} else if (IS_ALDERLAKE_P(i915)) {
revids = adlp_revids;
size = ARRAY_SIZE(adlp_revids);
diff --git a/drivers/gpu/drm/i915/intel_step.h b/drivers/gpu/drm/i915/intel_step.h
index a6b12bfa9744..96dfca4cba73 100644
--- a/drivers/gpu/drm/i915/intel_step.h
+++ b/drivers/gpu/drm/i915/intel_step.h
@@ -11,6 +11,10 @@
struct drm_i915_private;
struct intel_step_info {
+ /*
+ * It is expected to have 4 number steps per letter. Deviation from
+ * the expectation breaks gmd_to_intel_step().
+ */
u8 graphics_step; /* Represents the compute tile on Xe_HPC */
u8 display_step;
u8 media_step;
@@ -23,21 +27,43 @@ struct intel_step_info {
func(A0) \
func(A1) \
func(A2) \
+ func(A3) \
func(B0) \
func(B1) \
func(B2) \
func(B3) \
func(C0) \
func(C1) \
+ func(C2) \
+ func(C3) \
func(D0) \
func(D1) \
+ func(D2) \
+ func(D3) \
func(E0) \
+ func(E1) \
+ func(E2) \
+ func(E3) \
func(F0) \
+ func(F1) \
+ func(F2) \
+ func(F3) \
func(G0) \
+ func(G1) \
+ func(G2) \
+ func(G3) \
func(H0) \
+ func(H1) \
+ func(H2) \
+ func(H3) \
func(I0) \
func(I1) \
- func(J0)
+ func(I2) \
+ func(I3) \
+ func(J0) \
+ func(J1) \
+ func(J2) \
+ func(J3)
/*
* Symbolic steppings that do not match the hardware. These are valid both as gt
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 5cd423c7b646..8006a6c61466 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -29,6 +29,7 @@
#include "i915_drv.h"
#include "i915_iosf_mbi.h"
+#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_vgpu.h"
#include "intel_pm.h"
@@ -104,6 +105,7 @@ static const char * const forcewake_domain_names[] = {
"vebox1",
"vebox2",
"vebox3",
+ "gsc",
};
const char *
@@ -177,8 +179,9 @@ static inline void
fw_domain_wait_ack_clear(const struct intel_uncore_forcewake_domain *d)
{
if (wait_ack_clear(d, FORCEWAKE_KERNEL)) {
- DRM_ERROR("%s: timed out waiting for forcewake ack to clear.\n",
- intel_uncore_forcewake_domain_to_str(d->id));
+ drm_err(&d->uncore->i915->drm,
+ "%s: timed out waiting for forcewake ack to clear.\n",
+ intel_uncore_forcewake_domain_to_str(d->id));
add_taint_for_CI(d->uncore->i915, TAINT_WARN); /* CI now unreliable */
}
}
@@ -225,11 +228,12 @@ fw_domain_wait_ack_with_fallback(const struct intel_uncore_forcewake_domain *d,
fw_clear(d, FORCEWAKE_KERNEL_FALLBACK);
} while (!ack_detected && pass++ < 10);
- DRM_DEBUG_DRIVER("%s had to use fallback to %s ack, 0x%x (passes %u)\n",
- intel_uncore_forcewake_domain_to_str(d->id),
- type == ACK_SET ? "set" : "clear",
- fw_ack(d),
- pass);
+ drm_dbg(&d->uncore->i915->drm,
+ "%s had to use fallback to %s ack, 0x%x (passes %u)\n",
+ intel_uncore_forcewake_domain_to_str(d->id),
+ type == ACK_SET ? "set" : "clear",
+ fw_ack(d),
+ pass);
return ack_detected ? 0 : -ETIMEDOUT;
}
@@ -254,8 +258,9 @@ static inline void
fw_domain_wait_ack_set(const struct intel_uncore_forcewake_domain *d)
{
if (wait_ack_set(d, FORCEWAKE_KERNEL)) {
- DRM_ERROR("%s: timed out waiting for forcewake ack request.\n",
- intel_uncore_forcewake_domain_to_str(d->id));
+ drm_err(&d->uncore->i915->drm,
+ "%s: timed out waiting for forcewake ack request.\n",
+ intel_uncore_forcewake_domain_to_str(d->id));
add_taint_for_CI(d->uncore->i915, TAINT_WARN); /* CI now unreliable */
}
}
@@ -888,10 +893,13 @@ void assert_forcewakes_active(struct intel_uncore *uncore,
spin_unlock_irq(&uncore->lock);
}
-/* We give fast paths for the really cool registers */
+/*
+ * We give fast paths for the really cool registers. The second range includes
+ * media domains (and the GSC starting from Xe_LPM+)
+ */
#define NEEDS_FORCE_WAKE(reg) ({ \
u32 __reg = (reg); \
- __reg < 0x40000 || __reg >= GEN11_BSD_RING_BASE; \
+ __reg < 0x40000 || __reg >= 0x116000; \
})
static int fw_range_cmp(u32 offset, const struct intel_forcewake_range *entry)
@@ -1131,6 +1139,45 @@ static const struct i915_range pvc_shadowed_regs[] = {
{ .start = 0x1F8510, .end = 0x1F8550 },
};
+static const struct i915_range mtl_shadowed_regs[] = {
+ { .start = 0x2030, .end = 0x2030 },
+ { .start = 0x2510, .end = 0x2550 },
+ { .start = 0xA008, .end = 0xA00C },
+ { .start = 0xA188, .end = 0xA188 },
+ { .start = 0xA278, .end = 0xA278 },
+ { .start = 0xA540, .end = 0xA56C },
+ { .start = 0xC050, .end = 0xC050 },
+ { .start = 0xC340, .end = 0xC340 },
+ { .start = 0xC4C8, .end = 0xC4C8 },
+ { .start = 0xC4E0, .end = 0xC4E0 },
+ { .start = 0xC600, .end = 0xC600 },
+ { .start = 0xC658, .end = 0xC658 },
+ { .start = 0xCFD4, .end = 0xCFDC },
+ { .start = 0x22030, .end = 0x22030 },
+ { .start = 0x22510, .end = 0x22550 },
+};
+
+static const struct i915_range xelpmp_shadowed_regs[] = {
+ { .start = 0x1C0030, .end = 0x1C0030 },
+ { .start = 0x1C0510, .end = 0x1C0550 },
+ { .start = 0x1C8030, .end = 0x1C8030 },
+ { .start = 0x1C8510, .end = 0x1C8550 },
+ { .start = 0x1D0030, .end = 0x1D0030 },
+ { .start = 0x1D0510, .end = 0x1D0550 },
+ { .start = 0x38A008, .end = 0x38A00C },
+ { .start = 0x38A188, .end = 0x38A188 },
+ { .start = 0x38A278, .end = 0x38A278 },
+ { .start = 0x38A540, .end = 0x38A56C },
+ { .start = 0x38A618, .end = 0x38A618 },
+ { .start = 0x38C050, .end = 0x38C050 },
+ { .start = 0x38C340, .end = 0x38C340 },
+ { .start = 0x38C4C8, .end = 0x38C4C8 },
+ { .start = 0x38C4E0, .end = 0x38C4E4 },
+ { .start = 0x38C600, .end = 0x38C600 },
+ { .start = 0x38C658, .end = 0x38C658 },
+ { .start = 0x38CFD4, .end = 0x38CFDC },
+};
+
static int mmio_range_cmp(u32 key, const struct i915_range *range)
{
if (key < range->start)
@@ -1639,25 +1686,27 @@ static const struct intel_forcewake_range __pvc_fw_ranges[] = {
GEN_FW_RANGE(0x12000, 0x12fff, 0), /*
0x12000 - 0x127ff: always on
0x12800 - 0x12fff: reserved */
- GEN_FW_RANGE(0x13000, 0x23fff, FORCEWAKE_GT), /*
+ GEN_FW_RANGE(0x13000, 0x19fff, FORCEWAKE_GT), /*
0x13000 - 0x135ff: gt
0x13600 - 0x147ff: reserved
0x14800 - 0x153ff: gt
- 0x15400 - 0x19fff: reserved
- 0x1a000 - 0x1ffff: gt
- 0x20000 - 0x21fff: reserved
- 0x22000 - 0x23fff: gt */
+ 0x15400 - 0x19fff: reserved */
+ GEN_FW_RANGE(0x1a000, 0x21fff, FORCEWAKE_RENDER), /*
+ 0x1a000 - 0x1ffff: render
+ 0x20000 - 0x21fff: reserved */
+ GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT),
GEN_FW_RANGE(0x24000, 0x2417f, 0), /*
24000 - 0x2407f: always on
24080 - 0x2417f: reserved */
- GEN_FW_RANGE(0x24180, 0x3ffff, FORCEWAKE_GT), /*
+ GEN_FW_RANGE(0x24180, 0x25fff, FORCEWAKE_GT), /*
0x24180 - 0x241ff: gt
0x24200 - 0x251ff: reserved
0x25200 - 0x252ff: gt
- 0x25300 - 0x25fff: reserved
- 0x26000 - 0x27fff: gt
- 0x28000 - 0x2ffff: reserved
- 0x30000 - 0x3ffff: gt */
+ 0x25300 - 0x25fff: reserved */
+ GEN_FW_RANGE(0x26000, 0x2ffff, FORCEWAKE_RENDER), /*
+ 0x26000 - 0x27fff: render
+ 0x28000 - 0x2ffff: reserved */
+ GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT),
GEN_FW_RANGE(0x40000, 0x1bffff, 0),
GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), /*
0x1c0000 - 0x1c2bff: VD0
@@ -1679,6 +1728,162 @@ static const struct intel_forcewake_range __pvc_fw_ranges[] = {
GEN_FW_RANGE(0x3e0000, 0x3effff, FORCEWAKE_GT),
};
+static const struct intel_forcewake_range __mtl_fw_ranges[] = {
+ GEN_FW_RANGE(0x0, 0xaff, 0),
+ GEN_FW_RANGE(0xb00, 0xbff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0xc00, 0xfff, 0),
+ GEN_FW_RANGE(0x1000, 0x1fff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), /*
+ 0x4000 - 0x48ff: render
+ 0x4900 - 0x51ff: reserved */
+ GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), /*
+ 0x5200 - 0x53ff: render
+ 0x5400 - 0x54ff: reserved
+ 0x5500 - 0x7fff: render */
+ GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x8140, 0x817f, FORCEWAKE_RENDER), /*
+ 0x8140 - 0x815f: render
+ 0x8160 - 0x817f: reserved */
+ GEN_FW_RANGE(0x8180, 0x81ff, 0),
+ GEN_FW_RANGE(0x8200, 0x94cf, FORCEWAKE_GT), /*
+ 0x8200 - 0x87ff: gt
+ 0x8800 - 0x8dff: reserved
+ 0x8e00 - 0x8f7f: gt
+ 0x8f80 - 0x8fff: reserved
+ 0x9000 - 0x947f: gt
+ 0x9480 - 0x94cf: reserved */
+ GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0x9560, 0x967f, 0), /*
+ 0x9560 - 0x95ff: always on
+ 0x9600 - 0x967f: reserved */
+ GEN_FW_RANGE(0x9680, 0x97ff, FORCEWAKE_RENDER), /*
+ 0x9680 - 0x96ff: render
+ 0x9700 - 0x97ff: reserved */
+ GEN_FW_RANGE(0x9800, 0xcfff, FORCEWAKE_GT), /*
+ 0x9800 - 0xb4ff: gt
+ 0xb500 - 0xbfff: reserved
+ 0xc000 - 0xcfff: gt */
+ GEN_FW_RANGE(0xd000, 0xd7ff, 0), /*
+ 0xd000 - 0xd3ff: always on
+ 0xd400 - 0xd7ff: reserved */
+ GEN_FW_RANGE(0xd800, 0xd87f, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0xd880, 0xdbff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0xdc00, 0xdcff, FORCEWAKE_RENDER),
+ GEN_FW_RANGE(0xdd00, 0xde7f, FORCEWAKE_GT), /*
+ 0xdd00 - 0xddff: gt
+ 0xde00 - 0xde7f: reserved */
+ GEN_FW_RANGE(0xde80, 0xe8ff, FORCEWAKE_RENDER), /*
+ 0xde80 - 0xdfff: render
+ 0xe000 - 0xe0ff: reserved
+ 0xe100 - 0xe8ff: render */
+ GEN_FW_RANGE(0xe900, 0xe9ff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0xea00, 0x147ff, 0), /*
+ 0xea00 - 0x11fff: reserved
+ 0x12000 - 0x127ff: always on
+ 0x12800 - 0x147ff: reserved */
+ GEN_FW_RANGE(0x14800, 0x19fff, FORCEWAKE_GT), /*
+ 0x14800 - 0x153ff: gt
+ 0x15400 - 0x19fff: reserved */
+ GEN_FW_RANGE(0x1a000, 0x21fff, FORCEWAKE_RENDER), /*
+ 0x1a000 - 0x1bfff: render
+ 0x1c000 - 0x21fff: reserved */
+ GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x24000, 0x2ffff, 0), /*
+ 0x24000 - 0x2407f: always on
+ 0x24080 - 0x2ffff: reserved */
+ GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT)
+};
+
+/*
+ * Note that the register ranges here are the final offsets after
+ * translation of the GSI block to the 0x380000 offset.
+ *
+ * NOTE: There are a couple MCR ranges near the bottom of this table
+ * that need to power up either VD0 or VD2 depending on which replicated
+ * instance of the register we're trying to access. Our forcewake logic
+ * at the moment doesn't have a good way to take steering into consideration,
+ * and the driver doesn't even access any registers in those ranges today,
+ * so for now we just mark those ranges as FORCEWAKE_ALL. That will ensure
+ * proper operation if we do start using the ranges in the future, and we
+ * can determine at that time whether it's worth adding extra complexity to
+ * the forcewake handling to take steering into consideration.
+ */
+static const struct intel_forcewake_range __xelpmp_fw_ranges[] = {
+ GEN_FW_RANGE(0x0, 0x115fff, 0), /* render GT range */
+ GEN_FW_RANGE(0x116000, 0x11ffff, FORCEWAKE_GSC), /*
+ 0x116000 - 0x117fff: gsc
+ 0x118000 - 0x119fff: reserved
+ 0x11a000 - 0x11efff: gsc
+ 0x11f000 - 0x11ffff: reserved */
+ GEN_FW_RANGE(0x120000, 0x1bffff, 0), /* non-GT range */
+ GEN_FW_RANGE(0x1c0000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX0), /*
+ 0x1c0000 - 0x1c3dff: VD0
+ 0x1c3e00 - 0x1c3eff: reserved
+ 0x1c3f00 - 0x1c3fff: VD0
+ 0x1c4000 - 0x1c7fff: reserved */
+ GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0), /*
+ 0x1c8000 - 0x1ca0ff: VE0
+ 0x1ca100 - 0x1cbfff: reserved */
+ GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_MEDIA_VDBOX0), /*
+ 0x1cc000 - 0x1cdfff: VD0
+ 0x1ce000 - 0x1cffff: reserved */
+ GEN_FW_RANGE(0x1d0000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX2), /*
+ 0x1d0000 - 0x1d3dff: VD2
+ 0x1d3e00 - 0x1d3eff: reserved
+ 0x1d4000 - 0x1d7fff: VD2 */
+ GEN_FW_RANGE(0x1d8000, 0x1da0ff, FORCEWAKE_MEDIA_VEBOX1),
+ GEN_FW_RANGE(0x1da100, 0x380aff, 0), /*
+ 0x1da100 - 0x23ffff: reserved
+ 0x240000 - 0x37ffff: non-GT range
+ 0x380000 - 0x380aff: reserved */
+ GEN_FW_RANGE(0x380b00, 0x380bff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x380c00, 0x380fff, 0),
+ GEN_FW_RANGE(0x381000, 0x38817f, FORCEWAKE_GT), /*
+ 0x381000 - 0x381fff: gt
+ 0x382000 - 0x383fff: reserved
+ 0x384000 - 0x384aff: gt
+ 0x384b00 - 0x3851ff: reserved
+ 0x385200 - 0x3871ff: gt
+ 0x387200 - 0x387fff: reserved
+ 0x388000 - 0x38813f: gt
+ 0x388140 - 0x38817f: reserved */
+ GEN_FW_RANGE(0x388180, 0x3882ff, 0), /*
+ 0x388180 - 0x3881ff: always on
+ 0x388200 - 0x3882ff: reserved */
+ GEN_FW_RANGE(0x388300, 0x38955f, FORCEWAKE_GT), /*
+ 0x388300 - 0x38887f: gt
+ 0x388880 - 0x388fff: reserved
+ 0x389000 - 0x38947f: gt
+ 0x389480 - 0x38955f: reserved */
+ GEN_FW_RANGE(0x389560, 0x389fff, 0), /*
+ 0x389560 - 0x3895ff: always on
+ 0x389600 - 0x389fff: reserved */
+ GEN_FW_RANGE(0x38a000, 0x38cfff, FORCEWAKE_GT), /*
+ 0x38a000 - 0x38afff: gt
+ 0x38b000 - 0x38bfff: reserved
+ 0x38c000 - 0x38cfff: gt */
+ GEN_FW_RANGE(0x38d000, 0x38d11f, 0),
+ GEN_FW_RANGE(0x38d120, 0x391fff, FORCEWAKE_GT), /*
+ 0x38d120 - 0x38dfff: gt
+ 0x38e000 - 0x38efff: reserved
+ 0x38f000 - 0x38ffff: gt
+ 0x389000 - 0x391fff: reserved */
+ GEN_FW_RANGE(0x392000, 0x392fff, 0), /*
+ 0x392000 - 0x3927ff: always on
+ 0x392800 - 0x292fff: reserved */
+ GEN_FW_RANGE(0x393000, 0x3931ff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x393200, 0x39323f, FORCEWAKE_ALL), /* instance-based, see note above */
+ GEN_FW_RANGE(0x393240, 0x3933ff, FORCEWAKE_GT),
+ GEN_FW_RANGE(0x393400, 0x3934ff, FORCEWAKE_ALL), /* instance-based, see note above */
+ GEN_FW_RANGE(0x393500, 0x393c7f, 0), /*
+ 0x393500 - 0x393bff: reserved
+ 0x393c00 - 0x393c7f: always on */
+ GEN_FW_RANGE(0x393c80, 0x393dff, FORCEWAKE_GT),
+};
+
static void
ilk_dummy_write(struct intel_uncore *uncore)
{
@@ -2021,6 +2226,7 @@ static int __fw_domain_init(struct intel_uncore *uncore,
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX1));
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX2 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX2));
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX3 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX3));
+ BUILD_BUG_ON(FORCEWAKE_GSC != (1 << FW_DOMAIN_ID_GSC));
d->mask = BIT(domain_id);
@@ -2085,17 +2291,26 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
(ret ?: (ret = __fw_domain_init((uncore__), (id__), (set__), (ack__))))
if (GRAPHICS_VER(i915) >= 11) {
- /* we'll prune the domains of missing engines later */
- intel_engine_mask_t emask = RUNTIME_INFO(i915)->platform_engine_mask;
+ intel_engine_mask_t emask;
int i;
+ /* we'll prune the domains of missing engines later */
+ emask = uncore->gt->info.engine_mask;
+
uncore->fw_get_funcs = &uncore_get_fallback;
- fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
- FORCEWAKE_RENDER_GEN9,
- FORCEWAKE_ACK_RENDER_GEN9);
- fw_domain_init(uncore, FW_DOMAIN_ID_GT,
- FORCEWAKE_GT_GEN9,
- FORCEWAKE_ACK_GT_GEN9);
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
+ fw_domain_init(uncore, FW_DOMAIN_ID_GT,
+ FORCEWAKE_GT_GEN9,
+ FORCEWAKE_ACK_GT_MTL);
+ else
+ fw_domain_init(uncore, FW_DOMAIN_ID_GT,
+ FORCEWAKE_GT_GEN9,
+ FORCEWAKE_ACK_GT_GEN9);
+
+ if (RCS_MASK(uncore->gt) || CCS_MASK(uncore->gt))
+ fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE_RENDER_GEN9,
+ FORCEWAKE_ACK_RENDER_GEN9);
for (i = 0; i < I915_MAX_VCS; i++) {
if (!__HAS_ENGINE(emask, _VCS(i)))
@@ -2113,6 +2328,10 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
FORCEWAKE_MEDIA_VEBOX_GEN11(i),
FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
}
+
+ if (uncore->gt->type == GT_MEDIA)
+ fw_domain_init(uncore, FW_DOMAIN_ID_GSC,
+ FORCEWAKE_REQ_GSC, FORCEWAKE_ACK_GSC);
} else if (IS_GRAPHICS_VER(i915, 9, 10)) {
uncore->fw_get_funcs = &uncore_get_fallback;
fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
@@ -2300,6 +2519,22 @@ static void uncore_raw_init(struct intel_uncore *uncore)
}
}
+static int uncore_media_forcewake_init(struct intel_uncore *uncore)
+{
+ struct drm_i915_private *i915 = uncore->i915;
+
+ if (MEDIA_VER(i915) >= 13) {
+ ASSIGN_FW_DOMAINS_TABLE(uncore, __xelpmp_fw_ranges);
+ ASSIGN_SHADOW_TABLE(uncore, xelpmp_shadowed_regs);
+ ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable);
+ } else {
+ MISSING_CASE(MEDIA_VER(i915));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int uncore_forcewake_init(struct intel_uncore *uncore)
{
struct drm_i915_private *i915 = uncore->i915;
@@ -2314,7 +2549,14 @@ static int uncore_forcewake_init(struct intel_uncore *uncore)
ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable);
- if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 60)) {
+ if (uncore->gt->type == GT_MEDIA)
+ return uncore_media_forcewake_init(uncore);
+
+ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) {
+ ASSIGN_FW_DOMAINS_TABLE(uncore, __mtl_fw_ranges);
+ ASSIGN_SHADOW_TABLE(uncore, mtl_shadowed_regs);
+ ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable);
+ } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 60)) {
ASSIGN_FW_DOMAINS_TABLE(uncore, __pvc_fw_ranges);
ASSIGN_SHADOW_TABLE(uncore, pvc_shadowed_regs);
ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable);
diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
index 5022bac80b67..e9e38490815d 100644
--- a/drivers/gpu/drm/i915/intel_uncore.h
+++ b/drivers/gpu/drm/i915/intel_uncore.h
@@ -62,6 +62,7 @@ enum forcewake_domain_id {
FW_DOMAIN_ID_MEDIA_VEBOX1,
FW_DOMAIN_ID_MEDIA_VEBOX2,
FW_DOMAIN_ID_MEDIA_VEBOX3,
+ FW_DOMAIN_ID_GSC,
FW_DOMAIN_ID_COUNT
};
@@ -82,6 +83,7 @@ enum forcewake_domains {
FORCEWAKE_MEDIA_VEBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX1),
FORCEWAKE_MEDIA_VEBOX2 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX2),
FORCEWAKE_MEDIA_VEBOX3 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX3),
+ FORCEWAKE_GSC = BIT(FW_DOMAIN_ID_GSC),
FORCEWAKE_ALL = BIT(FW_DOMAIN_ID_COUNT) - 1,
};
@@ -380,20 +382,6 @@ __uncore_write(write_notrace, 32, l, false)
*/
__uncore_read(read64, 64, q, true)
-static inline u64
-intel_uncore_read64_2x32(struct intel_uncore *uncore,
- i915_reg_t lower_reg, i915_reg_t upper_reg)
-{
- u32 upper, lower, old_upper, loop = 0;
- upper = intel_uncore_read(uncore, upper_reg);
- do {
- old_upper = upper;
- lower = intel_uncore_read(uncore, lower_reg);
- upper = intel_uncore_read(uncore, upper_reg);
- } while (upper != old_upper && loop++ < 2);
- return (u64)upper << 32 | lower;
-}
-
#define intel_uncore_posting_read(...) ((void)intel_uncore_read_notrace(__VA_ARGS__))
#define intel_uncore_posting_read16(...) ((void)intel_uncore_read16_notrace(__VA_ARGS__))
@@ -431,15 +419,15 @@ intel_uncore_read64_2x32(struct intel_uncore *uncore,
#define intel_uncore_write64_fw(...) __raw_uncore_write64(__VA_ARGS__)
#define intel_uncore_posting_read_fw(...) ((void)intel_uncore_read_fw(__VA_ARGS__))
-static inline void intel_uncore_rmw(struct intel_uncore *uncore,
- i915_reg_t reg, u32 clear, u32 set)
+static inline u32 intel_uncore_rmw(struct intel_uncore *uncore,
+ i915_reg_t reg, u32 clear, u32 set)
{
u32 old, val;
old = intel_uncore_read(uncore, reg);
val = (old & ~clear) | set;
- if (val != old)
- intel_uncore_write(uncore, reg, val);
+ intel_uncore_write(uncore, reg, val);
+ return old;
}
static inline void intel_uncore_rmw_fw(struct intel_uncore *uncore,
@@ -453,6 +441,36 @@ static inline void intel_uncore_rmw_fw(struct intel_uncore *uncore,
intel_uncore_write_fw(uncore, reg, val);
}
+static inline u64
+intel_uncore_read64_2x32(struct intel_uncore *uncore,
+ i915_reg_t lower_reg, i915_reg_t upper_reg)
+{
+ u32 upper, lower, old_upper, loop = 0;
+ enum forcewake_domains fw_domains;
+ unsigned long flags;
+
+ fw_domains = intel_uncore_forcewake_for_reg(uncore, lower_reg,
+ FW_REG_READ);
+
+ fw_domains |= intel_uncore_forcewake_for_reg(uncore, upper_reg,
+ FW_REG_READ);
+
+ spin_lock_irqsave(&uncore->lock, flags);
+ intel_uncore_forcewake_get__locked(uncore, fw_domains);
+
+ upper = intel_uncore_read_fw(uncore, upper_reg);
+ do {
+ old_upper = upper;
+ lower = intel_uncore_read_fw(uncore, lower_reg);
+ upper = intel_uncore_read_fw(uncore, upper_reg);
+ } while (upper != old_upper && loop++ < 2);
+
+ intel_uncore_forcewake_put__locked(uncore, fw_domains);
+ spin_unlock_irqrestore(&uncore->lock, flags);
+
+ return (u64)upper << 32 | lower;
+}
+
static inline int intel_uncore_write_and_verify(struct intel_uncore *uncore,
i915_reg_t reg, u32 val,
u32 mask, u32 expected_val)
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c
index 69cdaaddc4a9..5efe61f67546 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c
@@ -103,19 +103,15 @@ static int create_vcs_context(struct intel_pxp *pxp)
static void destroy_vcs_context(struct intel_pxp *pxp)
{
- intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce));
+ if (pxp->ce)
+ intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce));
}
-void intel_pxp_init(struct intel_pxp *pxp)
+static void pxp_init_full(struct intel_pxp *pxp)
{
struct intel_gt *gt = pxp_to_gt(pxp);
int ret;
- if (!HAS_PXP(gt->i915))
- return;
-
- mutex_init(&pxp->tee_mutex);
-
/*
* we'll use the completion to check if there is a termination pending,
* so we start it as completed and we reinit it when a termination
@@ -124,8 +120,7 @@ void intel_pxp_init(struct intel_pxp *pxp)
init_completion(&pxp->termination);
complete_all(&pxp->termination);
- mutex_init(&pxp->arb_mutex);
- INIT_WORK(&pxp->session_work, intel_pxp_session_work);
+ intel_pxp_session_management_init(pxp);
ret = create_vcs_context(pxp);
if (ret)
@@ -143,11 +138,26 @@ out_context:
destroy_vcs_context(pxp);
}
-void intel_pxp_fini(struct intel_pxp *pxp)
+void intel_pxp_init(struct intel_pxp *pxp)
{
- if (!intel_pxp_is_enabled(pxp))
+ struct intel_gt *gt = pxp_to_gt(pxp);
+
+ /* we rely on the mei PXP module */
+ if (!IS_ENABLED(CONFIG_INTEL_MEI_PXP))
return;
+ /*
+ * If HuC is loaded by GSC but PXP is disabled, we can skip the init of
+ * the full PXP session/object management and just init the tee channel.
+ */
+ if (HAS_PXP(gt->i915))
+ pxp_init_full(pxp);
+ else if (intel_huc_is_loaded_by_gsc(&gt->uc.huc) && intel_uc_uses_huc(&gt->uc))
+ intel_pxp_tee_component_init(pxp);
+}
+
+void intel_pxp_fini(struct intel_pxp *pxp)
+{
pxp->arb_is_valid = false;
intel_pxp_tee_component_fini(pxp);
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h
index 73847e535cab..2da309088c6d 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h
@@ -12,7 +12,6 @@
struct intel_pxp;
struct drm_i915_gem_object;
-#ifdef CONFIG_DRM_I915_PXP
struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp);
bool intel_pxp_is_enabled(const struct intel_pxp *pxp);
bool intel_pxp_is_active(const struct intel_pxp *pxp);
@@ -32,36 +31,5 @@ int intel_pxp_key_check(struct intel_pxp *pxp,
bool assign);
void intel_pxp_invalidate(struct intel_pxp *pxp);
-#else
-static inline void intel_pxp_init(struct intel_pxp *pxp)
-{
-}
-
-static inline void intel_pxp_fini(struct intel_pxp *pxp)
-{
-}
-
-static inline int intel_pxp_start(struct intel_pxp *pxp)
-{
- return -ENODEV;
-}
-
-static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp)
-{
- return false;
-}
-
-static inline bool intel_pxp_is_active(const struct intel_pxp *pxp)
-{
- return false;
-}
-
-static inline int intel_pxp_key_check(struct intel_pxp *pxp,
- struct drm_i915_gem_object *obj,
- bool assign)
-{
- return -ENODEV;
-}
-#endif
#endif /* __INTEL_PXP_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_42.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_42.h
new file mode 100644
index 000000000000..739f9072fa5f
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_42.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2020, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_FW_INTERFACE_42_H__
+#define __INTEL_PXP_FW_INTERFACE_42_H__
+
+#include <linux/types.h>
+#include "intel_pxp_cmd_interface_cmn.h"
+
+/* PXP-Opcode for Init Session */
+#define PXP42_CMDID_INIT_SESSION 0x1e
+
+/* PXP-Input-Packet: Init Session (Arb-Session) */
+struct pxp42_create_arb_in {
+ struct pxp_cmd_header header;
+ u32 protection_mode;
+#define PXP42_ARB_SESSION_MODE_HEAVY 0x2
+ u32 session_id;
+} __packed;
+
+/* PXP-Output-Packet: Init Session */
+struct pxp42_create_arb_out {
+ struct pxp_cmd_header header;
+} __packed;
+
+#endif /* __INTEL_PXP_FW_INTERFACE_42_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h
new file mode 100644
index 000000000000..ad67e3f49c20
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2022, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_FW_INTERFACE_43_H__
+#define __INTEL_PXP_FW_INTERFACE_43_H__
+
+#include <linux/types.h>
+#include "intel_pxp_cmd_interface_cmn.h"
+
+/* PXP-Cmd-Op definitions */
+#define PXP43_CMDID_START_HUC_AUTH 0x0000003A
+
+/* PXP-Input-Packet: HUC-Authentication */
+struct pxp43_start_huc_auth_in {
+ struct pxp_cmd_header header;
+ __le64 huc_base_address;
+} __packed;
+
+/* PXP-Output-Packet: HUC-Authentication */
+struct pxp43_start_huc_auth_out {
+ struct pxp_cmd_header header;
+} __packed;
+
+#endif /* __INTEL_PXP_FW_INTERFACE_43_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h
new file mode 100644
index 000000000000..c2f23394f9b8
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2022, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_FW_INTERFACE_CMN_H__
+#define __INTEL_PXP_FW_INTERFACE_CMN_H__
+
+#include <linux/types.h>
+
+#define PXP_APIVER(x, y) (((x) & 0xFFFF) << 16 | ((y) & 0xFFFF))
+
+/*
+ * there are a lot of status codes for PXP, but we only define the cross-API
+ * common ones that we actually can handle in the kernel driver. Other failure
+ * codes should be printed to error msg for debug.
+ */
+enum pxp_status {
+ PXP_STATUS_SUCCESS = 0x0,
+ PXP_STATUS_OP_NOT_PERMITTED = 0x4013
+};
+
+/* Common PXP FW message header */
+struct pxp_cmd_header {
+ u32 api_version;
+ u32 command_id;
+ union {
+ u32 status; /* out */
+ u32 stream_id; /* in */
+ };
+ /* Length of the message (excluding the header) */
+ u32 buffer_len;
+} __packed;
+
+#endif /* __INTEL_PXP_FW_INTERFACE_CMN_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c
new file mode 100644
index 000000000000..2e1165522950
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2021-2022, Intel Corporation. All rights reserved.
+ */
+
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+
+#include "gem/i915_gem_region.h"
+#include "gt/intel_gt.h"
+
+#include "intel_pxp.h"
+#include "intel_pxp_huc.h"
+#include "intel_pxp_tee.h"
+#include "intel_pxp_types.h"
+#include "intel_pxp_cmd_interface_43.h"
+
+int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp)
+{
+ struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_huc *huc = &gt->uc.huc;
+ struct pxp43_start_huc_auth_in huc_in = {0};
+ struct pxp43_start_huc_auth_out huc_out = {0};
+ dma_addr_t huc_phys_addr;
+ u8 client_id = 0;
+ u8 fence_id = 0;
+ int err;
+
+ if (!pxp->pxp_component)
+ return -ENODEV;
+
+ huc_phys_addr = i915_gem_object_get_dma_address(huc->fw.obj, 0);
+
+ /* write the PXP message into the lmem (the sg list) */
+ huc_in.header.api_version = PXP_APIVER(4, 3);
+ huc_in.header.command_id = PXP43_CMDID_START_HUC_AUTH;
+ huc_in.header.status = 0;
+ huc_in.header.buffer_len = sizeof(huc_in.huc_base_address);
+ huc_in.huc_base_address = huc_phys_addr;
+
+ err = intel_pxp_tee_stream_message(pxp, client_id, fence_id,
+ &huc_in, sizeof(huc_in),
+ &huc_out, sizeof(huc_out));
+ if (err < 0) {
+ drm_err(&gt->i915->drm,
+ "Failed to send HuC load and auth command to GSC [%d]!\n",
+ err);
+ return err;
+ }
+
+ /*
+ * HuC does sometimes survive suspend/resume (it depends on how "deep"
+ * a sleep state the device reaches) so we can end up here on resume
+ * with HuC already loaded, in which case the GSC will return
+ * PXP_STATUS_OP_NOT_PERMITTED. We can therefore consider the GuC
+ * correctly transferred in this scenario; if the same error is ever
+ * returned with HuC not loaded we'll still catch it when we check the
+ * authentication bit later.
+ */
+ if (huc_out.header.status != PXP_STATUS_SUCCESS &&
+ huc_out.header.status != PXP_STATUS_OP_NOT_PERMITTED) {
+ drm_err(&gt->i915->drm,
+ "HuC load failed with GSC error = 0x%x\n",
+ huc_out.header.status);
+ return -EPROTO;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h
new file mode 100644
index 000000000000..e40847a91c39
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2021-2022, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_HUC_H__
+#define __INTEL_PXP_HUC_H__
+
+struct intel_pxp;
+
+int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp);
+
+#endif /* __INTEL_PXP_HUC_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h
index 8b5793654844..8c292dc86f68 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h
@@ -27,6 +27,14 @@ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir);
static inline void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir)
{
}
+
+static inline void intel_pxp_irq_enable(struct intel_pxp *pxp)
+{
+}
+
+static inline void intel_pxp_irq_disable(struct intel_pxp *pxp)
+{
+}
#endif
#endif /* __INTEL_PXP_IRQ_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
index 1bb5b5249157..85572360c71a 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
@@ -77,6 +77,7 @@ static int pxp_create_arb_session(struct intel_pxp *pxp)
drm_err(&gt->i915->drm, "arb session failed to go in play\n");
return ret;
}
+ drm_dbg(&gt->i915->drm, "PXP ARB session is alive\n");
if (!++pxp->key_instance)
++pxp->key_instance;
@@ -137,7 +138,7 @@ static void pxp_terminate_complete(struct intel_pxp *pxp)
complete_all(&pxp->termination);
}
-void intel_pxp_session_work(struct work_struct *work)
+static void pxp_session_work(struct work_struct *work)
{
struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);
struct intel_gt *gt = pxp_to_gt(pxp);
@@ -172,3 +173,9 @@ void intel_pxp_session_work(struct work_struct *work)
intel_runtime_pm_put(gt->uncore->rpm, wakeref);
}
+
+void intel_pxp_session_management_init(struct intel_pxp *pxp)
+{
+ mutex_init(&pxp->arb_mutex);
+ INIT_WORK(&pxp->session_work, pxp_session_work);
+}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h
index ba4c9d2b94b7..903ac52cffa1 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h
@@ -8,8 +8,13 @@
#include <linux/types.h>
-struct work_struct;
-
-void intel_pxp_session_work(struct work_struct *work);
+struct intel_pxp;
+#ifdef CONFIG_DRM_I915_PXP
+void intel_pxp_session_management_init(struct intel_pxp *pxp);
+#else
+static inline void intel_pxp_session_management_init(struct intel_pxp *pxp)
+{
+}
+#endif
#endif /* __INTEL_PXP_SESSION_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
index 4b6f5655fab5..b0c9170b1395 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
@@ -8,11 +8,14 @@
#include <drm/i915_pxp_tee_interface.h>
#include <drm/i915_component.h>
+#include "gem/i915_gem_lmem.h"
+
#include "i915_drv.h"
#include "intel_pxp.h"
#include "intel_pxp_session.h"
#include "intel_pxp_tee.h"
-#include "intel_pxp_tee_interface.h"
+#include "intel_pxp_cmd_interface_42.h"
+#include "intel_pxp_huc.h"
static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev)
{
@@ -69,6 +72,47 @@ unlock:
return ret;
}
+int intel_pxp_tee_stream_message(struct intel_pxp *pxp,
+ u8 client_id, u32 fence_id,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len)
+{
+ /* TODO: for bigger objects we need to use a sg of 4k pages */
+ const size_t max_msg_size = PAGE_SIZE;
+ struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct i915_pxp_component *pxp_component = pxp->pxp_component;
+ unsigned int offset = 0;
+ struct scatterlist *sg;
+ int ret;
+
+ if (msg_in_len > max_msg_size || msg_out_len > max_msg_size)
+ return -ENOSPC;
+
+ mutex_lock(&pxp->tee_mutex);
+
+ if (unlikely(!pxp_component || !pxp_component->ops->gsc_command)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ GEM_BUG_ON(!pxp->stream_cmd.obj);
+
+ sg = i915_gem_object_get_sg_dma(pxp->stream_cmd.obj, 0, &offset);
+
+ memcpy(pxp->stream_cmd.vaddr, msg_in, msg_in_len);
+
+ ret = pxp_component->ops->gsc_command(pxp_component->tee_dev, client_id,
+ fence_id, sg, msg_in_len, sg);
+ if (ret < 0)
+ drm_err(&i915->drm, "Failed to send PXP TEE gsc command\n");
+ else
+ memcpy(msg_out, pxp->stream_cmd.vaddr, msg_out_len);
+
+unlock:
+ mutex_unlock(&pxp->tee_mutex);
+ return ret;
+}
+
/**
* i915_pxp_tee_component_bind - bind function to pass the function pointers to pxp_tee
* @i915_kdev: pointer to i915 kernel device
@@ -84,24 +128,36 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev,
{
struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
+ struct intel_uc *uc = &pxp_to_gt(pxp)->uc;
intel_wakeref_t wakeref;
+ int ret = 0;
mutex_lock(&pxp->tee_mutex);
pxp->pxp_component = data;
pxp->pxp_component->tee_dev = tee_kdev;
mutex_unlock(&pxp->tee_mutex);
+ if (intel_uc_uses_huc(uc) && intel_huc_is_loaded_by_gsc(&uc->huc)) {
+ with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
+ /* load huc via pxp */
+ ret = intel_huc_fw_load_and_auth_via_gsc(&uc->huc);
+ if (ret < 0)
+ drm_err(&i915->drm, "failed to load huc via gsc %d\n", ret);
+ }
+ }
+
/* if we are suspended, the HW will be re-initialized on resume */
wakeref = intel_runtime_pm_get_if_in_use(&i915->runtime_pm);
if (!wakeref)
return 0;
/* the component is required to fully start the PXP HW */
- intel_pxp_init_hw(pxp);
+ if (intel_pxp_is_enabled(pxp))
+ intel_pxp_init_hw(pxp);
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
- return 0;
+ return ret;
}
static void i915_pxp_tee_component_unbind(struct device *i915_kdev,
@@ -111,8 +167,9 @@ static void i915_pxp_tee_component_unbind(struct device *i915_kdev,
struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
intel_wakeref_t wakeref;
- with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref)
- intel_pxp_fini_hw(pxp);
+ if (intel_pxp_is_enabled(pxp))
+ with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref)
+ intel_pxp_fini_hw(pxp);
mutex_lock(&pxp->tee_mutex);
pxp->pxp_component = NULL;
@@ -124,22 +181,92 @@ static const struct component_ops i915_pxp_tee_component_ops = {
.unbind = i915_pxp_tee_component_unbind,
};
+static int alloc_streaming_command(struct intel_pxp *pxp)
+{
+ struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_gem_object *obj = NULL;
+ void *cmd;
+ int err;
+
+ pxp->stream_cmd.obj = NULL;
+ pxp->stream_cmd.vaddr = NULL;
+
+ if (!IS_DGFX(i915))
+ return 0;
+
+ /* allocate lmem object of one page for PXP command memory and store it */
+ obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, I915_BO_ALLOC_CONTIGUOUS);
+ if (IS_ERR(obj)) {
+ drm_err(&i915->drm, "Failed to allocate pxp streaming command!\n");
+ return PTR_ERR(obj);
+ }
+
+ err = i915_gem_object_pin_pages_unlocked(obj);
+ if (err) {
+ drm_err(&i915->drm, "Failed to pin gsc message page!\n");
+ goto out_put;
+ }
+
+ /* map the lmem into the virtual memory pointer */
+ cmd = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(i915, obj, true));
+ if (IS_ERR(cmd)) {
+ drm_err(&i915->drm, "Failed to map gsc message page!\n");
+ err = PTR_ERR(cmd);
+ goto out_unpin;
+ }
+
+ memset(cmd, 0, obj->base.size);
+
+ pxp->stream_cmd.obj = obj;
+ pxp->stream_cmd.vaddr = cmd;
+
+ return 0;
+
+out_unpin:
+ i915_gem_object_unpin_pages(obj);
+out_put:
+ i915_gem_object_put(obj);
+ return err;
+}
+
+static void free_streaming_command(struct intel_pxp *pxp)
+{
+ struct drm_i915_gem_object *obj = fetch_and_zero(&pxp->stream_cmd.obj);
+
+ if (!obj)
+ return;
+
+ i915_gem_object_unpin_map(obj);
+ i915_gem_object_unpin_pages(obj);
+ i915_gem_object_put(obj);
+}
+
int intel_pxp_tee_component_init(struct intel_pxp *pxp)
{
int ret;
struct intel_gt *gt = pxp_to_gt(pxp);
struct drm_i915_private *i915 = gt->i915;
+ mutex_init(&pxp->tee_mutex);
+
+ ret = alloc_streaming_command(pxp);
+ if (ret)
+ return ret;
+
ret = component_add_typed(i915->drm.dev, &i915_pxp_tee_component_ops,
I915_COMPONENT_PXP);
if (ret < 0) {
drm_err(&i915->drm, "Failed to add PXP component (%d)\n", ret);
- return ret;
+ goto out_free;
}
pxp->pxp_component_added = true;
return 0;
+
+out_free:
+ free_streaming_command(pxp);
+ return ret;
}
void intel_pxp_tee_component_fini(struct intel_pxp *pxp)
@@ -151,20 +278,22 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp)
component_del(i915->drm.dev, &i915_pxp_tee_component_ops);
pxp->pxp_component_added = false;
+
+ free_streaming_command(pxp);
}
int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
int arb_session_id)
{
struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
- struct pxp_tee_create_arb_in msg_in = {0};
- struct pxp_tee_create_arb_out msg_out = {0};
+ struct pxp42_create_arb_in msg_in = {0};
+ struct pxp42_create_arb_out msg_out = {0};
int ret;
- msg_in.header.api_version = PXP_TEE_APIVER;
- msg_in.header.command_id = PXP_TEE_ARB_CMDID;
+ msg_in.header.api_version = PXP_APIVER(4, 2);
+ msg_in.header.command_id = PXP42_CMDID_INIT_SESSION;
msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header);
- msg_in.protection_mode = PXP_TEE_ARB_PROTECTION_MODE;
+ msg_in.protection_mode = PXP42_ARB_SESSION_MODE_HEAVY;
msg_in.session_id = arb_session_id;
ret = intel_pxp_tee_io_message(pxp,
@@ -174,6 +303,9 @@ int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
if (ret)
drm_err(&i915->drm, "Failed to send tee msg ret=[%d]\n", ret);
+ else if (msg_out.header.status != 0x0)
+ drm_warn(&i915->drm, "PXP firmware failed arb session init request ret=[0x%08x]\n",
+ msg_out.header.status);
return ret;
}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h
index c136053ce340..aeb3dfe7ce96 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h
@@ -14,4 +14,9 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp);
int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
int arb_session_id);
+int intel_pxp_tee_stream_message(struct intel_pxp *pxp,
+ u8 client_id, u32 fence_id,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len);
+
#endif /* __INTEL_PXP_TEE_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h
deleted file mode 100644
index 36e9b0868f5c..000000000000
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright(c) 2020, Intel Corporation. All rights reserved.
- */
-
-#ifndef __INTEL_PXP_TEE_INTERFACE_H__
-#define __INTEL_PXP_TEE_INTERFACE_H__
-
-#include <linux/types.h>
-
-#define PXP_TEE_APIVER 0x40002
-#define PXP_TEE_ARB_CMDID 0x1e
-#define PXP_TEE_ARB_PROTECTION_MODE 0x2
-
-/* PXP TEE message header */
-struct pxp_tee_cmd_header {
- u32 api_version;
- u32 command_id;
- u32 status;
- /* Length of the message (excluding the header) */
- u32 buffer_len;
-} __packed;
-
-/* PXP TEE message input to create a arbitrary session */
-struct pxp_tee_create_arb_in {
- struct pxp_tee_cmd_header header;
- u32 protection_mode;
- u32 session_id;
-} __packed;
-
-/* PXP TEE message output to create a arbitrary session */
-struct pxp_tee_create_arb_out {
- struct pxp_tee_cmd_header header;
-} __packed;
-
-#endif /* __INTEL_PXP_TEE_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
index 7ce5f37ee12e..f74b1e11a505 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
@@ -53,6 +53,12 @@ struct intel_pxp {
/** @tee_mutex: protects the tee channel binding and messaging. */
struct mutex tee_mutex;
+ /** @stream_cmd: LMEM obj used to send stream PXP commands to the GSC */
+ struct {
+ struct drm_i915_gem_object *obj; /* contains PXP command memory */
+ void *vaddr; /* virtual memory for PXP command */
+ } stream_cmd;
+
/**
* @hw_state_invalidated: if the HW perceives an attack on the integrity
* of the encryption it will invalidate the keys and expect SW to
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index e050a2de5fd1..eae7d947d7de 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -27,6 +27,7 @@
#include "gem/i915_gem_context.h"
#include "gem/i915_gem_internal.h"
+#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "gem/selftests/mock_context.h"
#include "gt/intel_context.h"
@@ -60,7 +61,6 @@ static int fake_get_pages(struct drm_i915_gem_object *obj)
#define PFN_BIAS 0x1000
struct sg_table *pages;
struct scatterlist *sg;
- unsigned int sg_page_sizes;
typeof(obj->base.size) rem;
pages = kmalloc(sizeof(*pages), GFP);
@@ -73,7 +73,6 @@ static int fake_get_pages(struct drm_i915_gem_object *obj)
return -ENOMEM;
}
- sg_page_sizes = 0;
rem = obj->base.size;
for (sg = pages->sgl; sg; sg = sg_next(sg)) {
unsigned long len = min_t(typeof(rem), rem, BIT(31));
@@ -82,13 +81,12 @@ static int fake_get_pages(struct drm_i915_gem_object *obj)
sg_set_page(sg, pfn_to_page(PFN_BIAS), len, 0);
sg_dma_address(sg) = page_to_phys(sg_page(sg));
sg_dma_len(sg) = len;
- sg_page_sizes |= len;
rem -= len;
}
GEM_BUG_ON(rem);
- __i915_gem_object_set_pages(obj, pages, sg_page_sizes);
+ __i915_gem_object_set_pages(obj, pages);
return 0;
#undef GFP
@@ -1113,15 +1111,8 @@ static int misaligned_case(struct i915_address_space *vm, struct intel_memory_re
expected_node_size = expected_vma_size;
if (HAS_64K_PAGES(vm->i915) && i915_gem_object_is_lmem(obj)) {
- /*
- * The compact-pt should expand lmem node to 2MB for the ppGTT,
- * for all other cases we should only expect 64K.
- */
expected_vma_size = round_up(size, I915_GTT_PAGE_SIZE_64K);
- if (NEEDS_COMPACT_PT(vm->i915) && !i915_is_ggtt(vm))
- expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_2M);
- else
- expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_64K);
+ expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_64K);
}
if (vma->size != expected_vma_size || vma->node.size != expected_node_size) {
diff --git a/drivers/gpu/drm/i915/selftests/i915_perf.c b/drivers/gpu/drm/i915/selftests/i915_perf.c
index 429c6d73b159..24dde5531423 100644
--- a/drivers/gpu/drm/i915/selftests/i915_perf.c
+++ b/drivers/gpu/drm/i915/selftests/i915_perf.c
@@ -102,6 +102,12 @@ test_stream(struct i915_perf *perf)
I915_OA_FORMAT_A32u40_A4u32_B8_C8 : I915_OA_FORMAT_C4_B8,
};
struct i915_perf_stream *stream;
+ struct intel_gt *gt;
+
+ if (!props.engine)
+ return NULL;
+
+ gt = props.engine->gt;
if (!oa_config)
return NULL;
@@ -116,12 +122,12 @@ test_stream(struct i915_perf *perf)
stream->perf = perf;
- mutex_lock(&perf->lock);
+ mutex_lock(&gt->perf.lock);
if (i915_oa_stream_init(stream, &param, &props)) {
kfree(stream);
stream = NULL;
}
- mutex_unlock(&perf->lock);
+ mutex_unlock(&gt->perf.lock);
i915_oa_config_put(oa_config);
@@ -130,11 +136,11 @@ test_stream(struct i915_perf *perf)
static void stream_destroy(struct i915_perf_stream *stream)
{
- struct i915_perf *perf = stream->perf;
+ struct intel_gt *gt = stream->engine->gt;
- mutex_lock(&perf->lock);
+ mutex_lock(&gt->perf.lock);
i915_perf_destroy_locked(stream);
- mutex_unlock(&perf->lock);
+ mutex_unlock(&gt->perf.lock);
}
static int live_sanitycheck(void *arg)
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index 818a4909c1f3..0daa8669181d 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -299,9 +299,18 @@ __live_request_alloc(struct intel_context *ce)
return intel_context_create_request(ce);
}
-static int __igt_breadcrumbs_smoketest(void *arg)
+struct smoke_thread {
+ struct kthread_worker *worker;
+ struct kthread_work work;
+ struct smoketest *t;
+ bool stop;
+ int result;
+};
+
+static void __igt_breadcrumbs_smoketest(struct kthread_work *work)
{
- struct smoketest *t = arg;
+ struct smoke_thread *thread = container_of(work, typeof(*thread), work);
+ struct smoketest *t = thread->t;
const unsigned int max_batch = min(t->ncontexts, t->max_batch) - 1;
const unsigned int total = 4 * t->ncontexts + 1;
unsigned int num_waits = 0, num_fences = 0;
@@ -320,8 +329,10 @@ static int __igt_breadcrumbs_smoketest(void *arg)
*/
requests = kcalloc(total, sizeof(*requests), GFP_KERNEL);
- if (!requests)
- return -ENOMEM;
+ if (!requests) {
+ thread->result = -ENOMEM;
+ return;
+ }
order = i915_random_order(total, &prng);
if (!order) {
@@ -329,7 +340,7 @@ static int __igt_breadcrumbs_smoketest(void *arg)
goto out_requests;
}
- while (!kthread_should_stop()) {
+ while (!READ_ONCE(thread->stop)) {
struct i915_sw_fence *submit, *wait;
unsigned int n, count;
@@ -437,7 +448,7 @@ static int __igt_breadcrumbs_smoketest(void *arg)
kfree(order);
out_requests:
kfree(requests);
- return err;
+ thread->result = err;
}
static int mock_breadcrumbs_smoketest(void *arg)
@@ -450,7 +461,7 @@ static int mock_breadcrumbs_smoketest(void *arg)
.request_alloc = __mock_request_alloc
};
unsigned int ncpus = num_online_cpus();
- struct task_struct **threads;
+ struct smoke_thread *threads;
unsigned int n;
int ret = 0;
@@ -479,28 +490,37 @@ static int mock_breadcrumbs_smoketest(void *arg)
}
for (n = 0; n < ncpus; n++) {
- threads[n] = kthread_run(__igt_breadcrumbs_smoketest,
- &t, "igt/%d", n);
- if (IS_ERR(threads[n])) {
- ret = PTR_ERR(threads[n]);
+ struct kthread_worker *worker;
+
+ worker = kthread_create_worker(0, "igt/%d", n);
+ if (IS_ERR(worker)) {
+ ret = PTR_ERR(worker);
ncpus = n;
break;
}
- get_task_struct(threads[n]);
+ threads[n].worker = worker;
+ threads[n].t = &t;
+ threads[n].stop = false;
+ threads[n].result = 0;
+
+ kthread_init_work(&threads[n].work,
+ __igt_breadcrumbs_smoketest);
+ kthread_queue_work(worker, &threads[n].work);
}
- yield(); /* start all threads before we begin */
msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies));
for (n = 0; n < ncpus; n++) {
int err;
- err = kthread_stop(threads[n]);
+ WRITE_ONCE(threads[n].stop, true);
+ kthread_flush_work(&threads[n].work);
+ err = READ_ONCE(threads[n].result);
if (err < 0 && !ret)
ret = err;
- put_task_struct(threads[n]);
+ kthread_destroy_worker(threads[n].worker);
}
pr_info("Completed %lu waits for %lu fence across %d cpus\n",
atomic_long_read(&t.num_waits),
@@ -1203,9 +1223,7 @@ static int live_all_engines(void *arg)
goto out_request;
}
- err = i915_request_await_object(request[idx], batch->obj, 0);
- if (err == 0)
- err = i915_vma_move_to_active(batch, request[idx], 0);
+ err = i915_vma_move_to_active(batch, request[idx], 0);
GEM_BUG_ON(err);
err = engine->emit_bb_start(request[idx],
@@ -1332,10 +1350,7 @@ static int live_sequential_engines(void *arg)
}
}
- err = i915_request_await_object(request[idx],
- batch->obj, false);
- if (err == 0)
- err = i915_vma_move_to_active(batch, request[idx], 0);
+ err = i915_vma_move_to_active(batch, request[idx], 0);
GEM_BUG_ON(err);
err = engine->emit_bb_start(request[idx],
@@ -1419,9 +1434,18 @@ out_free:
return err;
}
-static int __live_parallel_engine1(void *arg)
+struct parallel_thread {
+ struct kthread_worker *worker;
+ struct kthread_work work;
+ struct intel_engine_cs *engine;
+ int result;
+};
+
+static void __live_parallel_engine1(struct kthread_work *work)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread =
+ container_of(work, typeof(*thread), work);
+ struct intel_engine_cs *engine = thread->engine;
IGT_TIMEOUT(end_time);
unsigned long count;
int err = 0;
@@ -1452,12 +1476,14 @@ static int __live_parallel_engine1(void *arg)
intel_engine_pm_put(engine);
pr_info("%s: %lu request + sync\n", engine->name, count);
- return err;
+ thread->result = err;
}
-static int __live_parallel_engineN(void *arg)
+static void __live_parallel_engineN(struct kthread_work *work)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread =
+ container_of(work, typeof(*thread), work);
+ struct intel_engine_cs *engine = thread->engine;
IGT_TIMEOUT(end_time);
unsigned long count;
int err = 0;
@@ -1479,7 +1505,7 @@ static int __live_parallel_engineN(void *arg)
intel_engine_pm_put(engine);
pr_info("%s: %lu requests\n", engine->name, count);
- return err;
+ thread->result = err;
}
static bool wake_all(struct drm_i915_private *i915)
@@ -1505,9 +1531,11 @@ static int wait_for_all(struct drm_i915_private *i915)
return -ETIME;
}
-static int __live_parallel_spin(void *arg)
+static void __live_parallel_spin(struct kthread_work *work)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread =
+ container_of(work, typeof(*thread), work);
+ struct intel_engine_cs *engine = thread->engine;
struct igt_spinner spin;
struct i915_request *rq;
int err = 0;
@@ -1520,7 +1548,8 @@ static int __live_parallel_spin(void *arg)
if (igt_spinner_init(&spin, engine->gt)) {
wake_all(engine->i915);
- return -ENOMEM;
+ thread->result = -ENOMEM;
+ return;
}
intel_engine_pm_get(engine);
@@ -1553,22 +1582,22 @@ static int __live_parallel_spin(void *arg)
out_spin:
igt_spinner_fini(&spin);
- return err;
+ thread->result = err;
}
static int live_parallel_engines(void *arg)
{
struct drm_i915_private *i915 = arg;
- static int (* const func[])(void *arg) = {
+ static void (* const func[])(struct kthread_work *) = {
__live_parallel_engine1,
__live_parallel_engineN,
__live_parallel_spin,
NULL,
};
const unsigned int nengines = num_uabi_engines(i915);
+ struct parallel_thread *threads;
struct intel_engine_cs *engine;
- int (* const *fn)(void *arg);
- struct task_struct **tsk;
+ void (* const *fn)(struct kthread_work *);
int err = 0;
/*
@@ -1576,8 +1605,8 @@ static int live_parallel_engines(void *arg)
* tests that we load up the system maximally.
*/
- tsk = kcalloc(nengines, sizeof(*tsk), GFP_KERNEL);
- if (!tsk)
+ threads = kcalloc(nengines, sizeof(*threads), GFP_KERNEL);
+ if (!threads)
return -ENOMEM;
for (fn = func; !err && *fn; fn++) {
@@ -1594,37 +1623,44 @@ static int live_parallel_engines(void *arg)
idx = 0;
for_each_uabi_engine(engine, i915) {
- tsk[idx] = kthread_run(*fn, engine,
- "igt/parallel:%s",
- engine->name);
- if (IS_ERR(tsk[idx])) {
- err = PTR_ERR(tsk[idx]);
+ struct kthread_worker *worker;
+
+ worker = kthread_create_worker(0, "igt/parallel:%s",
+ engine->name);
+ if (IS_ERR(worker)) {
+ err = PTR_ERR(worker);
break;
}
- get_task_struct(tsk[idx++]);
- }
- yield(); /* start all threads before we kthread_stop() */
+ threads[idx].worker = worker;
+ threads[idx].result = 0;
+ threads[idx].engine = engine;
+
+ kthread_init_work(&threads[idx].work, *fn);
+ kthread_queue_work(worker, &threads[idx].work);
+ idx++;
+ }
idx = 0;
for_each_uabi_engine(engine, i915) {
int status;
- if (IS_ERR(tsk[idx]))
+ if (!threads[idx].worker)
break;
- status = kthread_stop(tsk[idx]);
+ kthread_flush_work(&threads[idx].work);
+ status = READ_ONCE(threads[idx].result);
if (status && !err)
err = status;
- put_task_struct(tsk[idx++]);
+ kthread_destroy_worker(threads[idx++].worker);
}
if (igt_live_test_end(&t))
err = -EIO;
}
- kfree(tsk);
+ kfree(threads);
return err;
}
@@ -1669,10 +1705,11 @@ static int live_breadcrumbs_smoketest(void *arg)
{
struct drm_i915_private *i915 = arg;
const unsigned int nengines = num_uabi_engines(i915);
- const unsigned int ncpus = num_online_cpus();
+ const unsigned int ncpus = /* saturate with nengines * ncpus */
+ max_t(int, 2, DIV_ROUND_UP(num_online_cpus(), nengines));
unsigned long num_waits, num_fences;
struct intel_engine_cs *engine;
- struct task_struct **threads;
+ struct smoke_thread *threads;
struct igt_live_test live;
intel_wakeref_t wakeref;
struct smoketest *smoke;
@@ -1741,28 +1778,31 @@ static int live_breadcrumbs_smoketest(void *arg)
goto out_flush;
}
/* One ring interleaved between requests from all cpus */
- smoke[idx].max_batch /= num_online_cpus() + 1;
+ smoke[idx].max_batch /= ncpus + 1;
pr_debug("Limiting batches to %d requests on %s\n",
smoke[idx].max_batch, engine->name);
for (n = 0; n < ncpus; n++) {
- struct task_struct *tsk;
+ unsigned int i = idx * ncpus + n;
+ struct kthread_worker *worker;
- tsk = kthread_run(__igt_breadcrumbs_smoketest,
- &smoke[idx], "igt/%d.%d", idx, n);
- if (IS_ERR(tsk)) {
- ret = PTR_ERR(tsk);
+ worker = kthread_create_worker(0, "igt/%d.%d", idx, n);
+ if (IS_ERR(worker)) {
+ ret = PTR_ERR(worker);
goto out_flush;
}
- get_task_struct(tsk);
- threads[idx * ncpus + n] = tsk;
+ threads[i].worker = worker;
+ threads[i].t = &smoke[idx];
+
+ kthread_init_work(&threads[i].work,
+ __igt_breadcrumbs_smoketest);
+ kthread_queue_work(worker, &threads[i].work);
}
idx++;
}
- yield(); /* start all threads before we begin */
msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies));
out_flush:
@@ -1771,17 +1811,19 @@ out_flush:
num_fences = 0;
for_each_uabi_engine(engine, i915) {
for (n = 0; n < ncpus; n++) {
- struct task_struct *tsk = threads[idx * ncpus + n];
+ unsigned int i = idx * ncpus + n;
int err;
- if (!tsk)
+ if (!threads[i].worker)
continue;
- err = kthread_stop(tsk);
+ WRITE_ONCE(threads[i].stop, true);
+ kthread_flush_work(&threads[i].work);
+ err = READ_ONCE(threads[i].result);
if (err < 0 && !ret)
ret = err;
- put_task_struct(tsk);
+ kthread_destroy_worker(threads[i].worker);
}
num_waits += atomic_long_read(&smoke[idx].num_waits);
@@ -2891,9 +2933,18 @@ out:
return err;
}
-static int p_sync0(void *arg)
+struct p_thread {
+ struct perf_stats p;
+ struct kthread_worker *worker;
+ struct kthread_work work;
+ struct intel_engine_cs *engine;
+ int result;
+};
+
+static void p_sync0(struct kthread_work *work)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = container_of(work, typeof(*thread), work);
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct intel_context *ce;
IGT_TIMEOUT(end_time);
@@ -2902,13 +2953,16 @@ static int p_sync0(void *arg)
int err = 0;
ce = intel_context_create(engine);
- if (IS_ERR(ce))
- return PTR_ERR(ce);
+ if (IS_ERR(ce)) {
+ thread->result = PTR_ERR(ce);
+ return;
+ }
err = intel_context_pin(ce);
if (err) {
intel_context_put(ce);
- return err;
+ thread->result = err;
+ return;
}
if (intel_engine_supports_stats(engine)) {
@@ -2958,12 +3012,13 @@ static int p_sync0(void *arg)
intel_context_unpin(ce);
intel_context_put(ce);
- return err;
+ thread->result = err;
}
-static int p_sync1(void *arg)
+static void p_sync1(struct kthread_work *work)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = container_of(work, typeof(*thread), work);
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct i915_request *prev = NULL;
struct intel_context *ce;
@@ -2973,13 +3028,16 @@ static int p_sync1(void *arg)
int err = 0;
ce = intel_context_create(engine);
- if (IS_ERR(ce))
- return PTR_ERR(ce);
+ if (IS_ERR(ce)) {
+ thread->result = PTR_ERR(ce);
+ return;
+ }
err = intel_context_pin(ce);
if (err) {
intel_context_put(ce);
- return err;
+ thread->result = err;
+ return;
}
if (intel_engine_supports_stats(engine)) {
@@ -3031,12 +3089,13 @@ static int p_sync1(void *arg)
intel_context_unpin(ce);
intel_context_put(ce);
- return err;
+ thread->result = err;
}
-static int p_many(void *arg)
+static void p_many(struct kthread_work *work)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = container_of(work, typeof(*thread), work);
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct intel_context *ce;
IGT_TIMEOUT(end_time);
@@ -3045,13 +3104,16 @@ static int p_many(void *arg)
bool busy;
ce = intel_context_create(engine);
- if (IS_ERR(ce))
- return PTR_ERR(ce);
+ if (IS_ERR(ce)) {
+ thread->result = PTR_ERR(ce);
+ return;
+ }
err = intel_context_pin(ce);
if (err) {
intel_context_put(ce);
- return err;
+ thread->result = err;
+ return;
}
if (intel_engine_supports_stats(engine)) {
@@ -3092,26 +3154,23 @@ static int p_many(void *arg)
intel_context_unpin(ce);
intel_context_put(ce);
- return err;
+ thread->result = err;
}
static int perf_parallel_engines(void *arg)
{
struct drm_i915_private *i915 = arg;
- static int (* const func[])(void *arg) = {
+ static void (* const func[])(struct kthread_work *) = {
p_sync0,
p_sync1,
p_many,
NULL,
};
const unsigned int nengines = num_uabi_engines(i915);
+ void (* const *fn)(struct kthread_work *);
struct intel_engine_cs *engine;
- int (* const *fn)(void *arg);
struct pm_qos_request qos;
- struct {
- struct perf_stats p;
- struct task_struct *tsk;
- } *engines;
+ struct p_thread *engines;
int err = 0;
engines = kcalloc(nengines, sizeof(*engines), GFP_KERNEL);
@@ -3134,36 +3193,45 @@ static int perf_parallel_engines(void *arg)
idx = 0;
for_each_uabi_engine(engine, i915) {
+ struct kthread_worker *worker;
+
intel_engine_pm_get(engine);
memset(&engines[idx].p, 0, sizeof(engines[idx].p));
- engines[idx].p.engine = engine;
- engines[idx].tsk = kthread_run(*fn, &engines[idx].p,
- "igt:%s", engine->name);
- if (IS_ERR(engines[idx].tsk)) {
- err = PTR_ERR(engines[idx].tsk);
+ worker = kthread_create_worker(0, "igt:%s",
+ engine->name);
+ if (IS_ERR(worker)) {
+ err = PTR_ERR(worker);
intel_engine_pm_put(engine);
break;
}
- get_task_struct(engines[idx++].tsk);
- }
+ engines[idx].worker = worker;
+ engines[idx].result = 0;
+ engines[idx].p.engine = engine;
+ engines[idx].engine = engine;
- yield(); /* start all threads before we kthread_stop() */
+ kthread_init_work(&engines[idx].work, *fn);
+ kthread_queue_work(worker, &engines[idx].work);
+ idx++;
+ }
idx = 0;
for_each_uabi_engine(engine, i915) {
int status;
- if (IS_ERR(engines[idx].tsk))
+ if (!engines[idx].worker)
break;
- status = kthread_stop(engines[idx].tsk);
+ kthread_flush_work(&engines[idx].work);
+ status = READ_ONCE(engines[idx].result);
if (status && !err)
err = status;
intel_engine_pm_put(engine);
- put_task_struct(engines[idx++].tsk);
+
+ kthread_destroy_worker(engines[idx].worker);
+ idx++;
}
if (igt_live_test_end(&t))
diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c
index 0c22594ae274..16978ac59797 100644
--- a/drivers/gpu/drm/i915/selftests/igt_spinner.c
+++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c
@@ -119,22 +119,6 @@ static u64 hws_address(const struct i915_vma *hws,
return hws->node.start + seqno_offset(rq->fence.context);
}
-static int move_to_active(struct i915_vma *vma,
- struct i915_request *rq,
- unsigned int flags)
-{
- int err;
-
- i915_vma_lock(vma);
- err = i915_request_await_object(rq, vma->obj,
- flags & EXEC_OBJECT_WRITE);
- if (err == 0)
- err = i915_vma_move_to_active(vma, rq, flags);
- i915_vma_unlock(vma);
-
- return err;
-}
-
struct i915_request *
igt_spinner_create_request(struct igt_spinner *spin,
struct intel_context *ce,
@@ -165,11 +149,11 @@ igt_spinner_create_request(struct igt_spinner *spin,
if (IS_ERR(rq))
return ERR_CAST(rq);
- err = move_to_active(vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
if (err)
goto cancel_rq;
- err = move_to_active(hws, rq, 0);
+ err = igt_vma_move_to_active_unlocked(hws, rq, 0);
if (err)
goto cancel_rq;
diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c
index fda9bb79c049..e4281508d580 100644
--- a/drivers/gpu/drm/i915/selftests/intel_uncore.c
+++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c
@@ -70,6 +70,8 @@ static int intel_shadow_table_check(void)
{ gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) },
{ dg2_shadowed_regs, ARRAY_SIZE(dg2_shadowed_regs) },
{ pvc_shadowed_regs, ARRAY_SIZE(pvc_shadowed_regs) },
+ { mtl_shadowed_regs, ARRAY_SIZE(mtl_shadowed_regs) },
+ { xelpmp_shadowed_regs, ARRAY_SIZE(xelpmp_shadowed_regs) },
};
const struct i915_range *range;
unsigned int i, j;
@@ -117,6 +119,8 @@ int intel_uncore_mock_selftests(void)
{ __gen12_fw_ranges, ARRAY_SIZE(__gen12_fw_ranges), true },
{ __xehp_fw_ranges, ARRAY_SIZE(__xehp_fw_ranges), true },
{ __pvc_fw_ranges, ARRAY_SIZE(__pvc_fw_ranges), true },
+ { __mtl_fw_ranges, ARRAY_SIZE(__mtl_fw_ranges), true },
+ { __xelpmp_fw_ranges, ARRAY_SIZE(__xelpmp_fw_ranges), true },
};
int err, i;
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index fff11c90f1fa..f6a7c0bd2955 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -67,7 +67,6 @@ static void mock_device_release(struct drm_device *dev)
intel_gt_driver_remove(to_gt(i915));
i915_gem_drain_workqueue(i915);
- i915_gem_drain_freed_objects(i915);
mock_fini_ggtt(to_gt(i915)->ggtt);
destroy_workqueue(i915->wq);
diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
index bac21fe84ca5..6324eb32d4dd 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -41,7 +41,7 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
}
pages = &obj->mm.rsgt->table;
- __i915_gem_object_set_pages(obj, pages, i915_sg_dma_sizes(pages->sgl));
+ __i915_gem_object_set_pages(obj, pages);
return 0;
diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c
index c26001300ebd..6eea6e1a99c0 100644
--- a/drivers/gpu/drm/i915/vlv_sideband.c
+++ b/drivers/gpu/drm/i915/vlv_sideband.c
@@ -8,6 +8,8 @@
#include "i915_reg.h"
#include "vlv_sideband.h"
+#include "display/intel_dpio_phy.h"
+
/*
* IOSF sideband, see VLV2_SidebandMsg_HAS.docx and
* VLV_VLV2_PUNIT_HAS_0.8.docx
diff --git a/drivers/gpu/drm/i915/vlv_suspend.c b/drivers/gpu/drm/i915/vlv_suspend.c
index 664fde244f59..02e63ed77f60 100644
--- a/drivers/gpu/drm/i915/vlv_suspend.c
+++ b/drivers/gpu/drm/i915/vlv_suspend.c
@@ -194,7 +194,6 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *i915)
{
struct vlv_s0ix_state *s = i915->vlv_s0ix_state;
struct intel_uncore *uncore = &i915->uncore;
- u32 val;
int i;
if (!s)
@@ -262,15 +261,11 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *i915)
* be restored, as they are used to control the s0ix suspend/resume
* sequence by the caller.
*/
- val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL);
- val &= VLV_GTLC_ALLOWWAKEREQ;
- val |= s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ;
- intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val);
+ intel_uncore_rmw(uncore, VLV_GTLC_WAKE_CTRL, ~VLV_GTLC_ALLOWWAKEREQ,
+ s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ);
- val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG);
- val &= VLV_GFX_CLK_FORCE_ON_BIT;
- val |= s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT;
- intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val);
+ intel_uncore_rmw(uncore, VLV_GTLC_SURVIVABILITY_REG, ~VLV_GFX_CLK_FORCE_ON_BIT,
+ s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT);
intel_uncore_write(uncore, VLV_PMWGICZ, s->pmwgicz);
@@ -308,14 +303,10 @@ static int vlv_wait_for_pw_status(struct drm_i915_private *i915,
static int vlv_force_gfx_clock(struct drm_i915_private *i915, bool force_on)
{
struct intel_uncore *uncore = &i915->uncore;
- u32 val;
int err;
- val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG);
- val &= ~VLV_GFX_CLK_FORCE_ON_BIT;
- if (force_on)
- val |= VLV_GFX_CLK_FORCE_ON_BIT;
- intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val);
+ intel_uncore_rmw(uncore, VLV_GTLC_SURVIVABILITY_REG, VLV_GFX_CLK_FORCE_ON_BIT,
+ force_on ? VLV_GFX_CLK_FORCE_ON_BIT : 0);
if (!force_on)
return 0;
@@ -340,11 +331,8 @@ static int vlv_allow_gt_wake(struct drm_i915_private *i915, bool allow)
u32 val;
int err;
- val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL);
- val &= ~VLV_GTLC_ALLOWWAKEREQ;
- if (allow)
- val |= VLV_GTLC_ALLOWWAKEREQ;
- intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val);
+ intel_uncore_rmw(uncore, VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ,
+ allow ? VLV_GTLC_ALLOWWAKEREQ : 0);
intel_uncore_posting_read(uncore, VLV_GTLC_WAKE_CTRL);
mask = VLV_GTLC_ALLOWWAKEACK;
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
index b4f82ebca532..18df3888b7f9 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-kms.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -7,7 +7,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
@@ -21,7 +21,6 @@ DEFINE_DRM_GEM_DMA_FOPS(dcss_cma_fops);
static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 8dd8b0f912af..e060fa6cbcb9 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 41799011f73b..c45fc8f4744d 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/i2c.h>
#include <linux/media-bus-format.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -23,7 +24,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index ab4d1c878fda..d6832f506322 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -19,7 +19,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 06723b2e9b84..0fa0b590830b 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -8,6 +8,7 @@
#include <linux/component.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
@@ -16,7 +17,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index ab0515d2c420..3d5af44bf92d 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -32,7 +32,7 @@
#include <drm/drm_encoder.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -1018,7 +1018,6 @@ static const struct drm_bridge_funcs ingenic_drm_bridge_funcs = {
static const struct drm_mode_config_funcs ingenic_drm_mode_config_funcs = {
.fb_create = ingenic_drm_gem_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -1629,7 +1628,11 @@ static int ingenic_drm_init(void)
return err;
}
- return platform_driver_register(&ingenic_drm_driver);
+ err = platform_driver_register(&ingenic_drm_driver);
+ if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && err)
+ platform_driver_unregister(ingenic_ipu_driver_ptr);
+
+ return err;
}
module_init(ingenic_drm_init);
diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c
index 2382ccb3ee99..d29c678f6c91 100644
--- a/drivers/gpu/drm/kmb/kmb_drv.c
+++ b/drivers/gpu/drm/kmb/kmb_drv.c
@@ -15,7 +15,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c
index a42f63f6f957..d172a302f902 100644
--- a/drivers/gpu/drm/kmb/kmb_plane.c
+++ b/drivers/gpu/drm/kmb/kmb_plane.c
@@ -9,7 +9,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c
index 011be7ff51e1..bc8fb4e38d0a 100644
--- a/drivers/gpu/drm/lima/lima_devfreq.c
+++ b/drivers/gpu/drm/lima/lima_devfreq.c
@@ -112,11 +112,6 @@ int lima_devfreq_init(struct lima_device *ldev)
unsigned long cur_freq;
int ret;
const char *regulator_names[] = { "mali", NULL };
- const char *clk_names[] = { "core", NULL };
- struct dev_pm_opp_config config = {
- .regulator_names = regulator_names,
- .clk_names = clk_names,
- };
if (!device_property_present(dev, "operating-points-v2"))
/* Optional, continue without devfreq */
@@ -124,7 +119,15 @@ int lima_devfreq_init(struct lima_device *ldev)
spin_lock_init(&ldevfreq->lock);
- ret = devm_pm_opp_set_config(dev, &config);
+ /*
+ * clkname is set separately so it is not affected by the optional
+ * regulator setting which may return error.
+ */
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_set_regulators(dev, regulator_names);
if (ret) {
/* Continue if the optional regulator is missing */
if (ret != -ENODEV)
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
index e82931712d8a..ff003403fbbc 100644
--- a/drivers/gpu/drm/lima/lima_sched.c
+++ b/drivers/gpu/drm/lima/lima_sched.c
@@ -371,7 +371,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
} else {
buffer_chunk->size = lima_bo_size(bo);
- ret = drm_gem_shmem_vmap(&bo->base, &map);
+ ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
if (ret) {
kvfree(et);
goto out;
@@ -379,7 +379,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size);
- drm_gem_shmem_vunmap(&bo->base, &map);
+ drm_gem_vunmap_unlocked(&bo->base.base, &map);
}
buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size;
diff --git a/drivers/gpu/drm/logicvc/logicvc_drm.c b/drivers/gpu/drm/logicvc/logicvc_drm.c
index cc9a4e965f77..9de24d9f0c96 100644
--- a/drivers/gpu/drm/logicvc/logicvc_drm.c
+++ b/drivers/gpu/drm/logicvc/logicvc_drm.c
@@ -17,7 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/logicvc/logicvc_mode.c b/drivers/gpu/drm/logicvc/logicvc_mode.c
index d8207ffda1af..9971950ebd4e 100644
--- a/drivers/gpu/drm/logicvc/logicvc_mode.c
+++ b/drivers/gpu/drm/logicvc/logicvc_mode.c
@@ -10,7 +10,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode_config.h>
@@ -26,7 +25,6 @@
static const struct drm_mode_config_funcs logicvc_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
index 1c4482ad507d..4aedb050d2a5 100644
--- a/drivers/gpu/drm/mcde/mcde_drv.c
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -69,7 +69,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -203,7 +203,6 @@ DEFINE_DRM_GEM_DMA_FOPS(drm_fops);
static const struct drm_driver mcde_drm_driver = {
.driver_features =
DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
- .lastclose = drm_fb_helper_lastclose,
.ioctls = NULL,
.fops = &drm_fops,
.name = "mcde",
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 002b0f6cae1a..84daeaffab6a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -29,17 +29,22 @@
#define DISP_REG_OVL_DATAPATH_CON 0x0024
#define OVL_LAYER_SMI_ID_EN BIT(0)
#define OVL_BGCLR_SEL_IN BIT(2)
+#define OVL_LAYER_AFBC_EN(n) BIT(4+n)
#define DISP_REG_OVL_ROI_BGCLR 0x0028
#define DISP_REG_OVL_SRC_CON 0x002c
#define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n))
#define DISP_REG_OVL_SRC_SIZE(n) (0x0038 + 0x20 * (n))
#define DISP_REG_OVL_OFFSET(n) (0x003c + 0x20 * (n))
+#define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n))
+#define OVL_PITCH_MSB_2ND_SUBBUF BIT(16)
#define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n))
#define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n))
#define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n))
#define DISP_REG_OVL_ADDR_MT2701 0x0040
#define DISP_REG_OVL_ADDR_MT8173 0x0f40
#define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n))
+#define DISP_REG_OVL_HDR_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x04)
+#define DISP_REG_OVL_HDR_PITCH(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x08)
#define GMC_THRESHOLD_BITS 16
#define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4)
@@ -67,6 +72,7 @@ struct mtk_disp_ovl_data {
unsigned int layer_nr;
bool fmt_rgb565_is_0;
bool smi_id_en;
+ bool supports_afbc;
};
/*
@@ -172,7 +178,14 @@ void mtk_ovl_stop(struct device *dev)
reg = reg & ~OVL_LAYER_SMI_ID_EN;
writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
}
+}
+static void mtk_ovl_set_afbc(struct mtk_disp_ovl *ovl, struct cmdq_pkt *cmdq_pkt,
+ int idx, bool enabled)
+{
+ mtk_ddp_write_mask(cmdq_pkt, enabled ? OVL_LAYER_AFBC_EN(idx) : 0,
+ &ovl->cmdq_reg, ovl->regs,
+ DISP_REG_OVL_DATAPATH_CON, OVL_LAYER_AFBC_EN(idx));
}
void mtk_ovl_config(struct device *dev, unsigned int w,
@@ -310,11 +323,23 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr;
- unsigned int pitch = pending->pitch & 0xffff;
+ unsigned int hdr_addr = pending->hdr_addr;
+ unsigned int pitch = pending->pitch;
+ unsigned int hdr_pitch = pending->hdr_pitch;
unsigned int fmt = pending->format;
unsigned int offset = (pending->y << 16) | pending->x;
unsigned int src_size = (pending->height << 16) | pending->width;
unsigned int con;
+ bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR;
+ union overlay_pitch {
+ struct split_pitch {
+ u16 lsb;
+ u16 msb;
+ } split_pitch;
+ u32 pitch;
+ } overlay_pitch;
+
+ overlay_pitch.pitch = pitch;
if (!pending->enable) {
mtk_ovl_layer_off(dev, idx, cmdq_pkt);
@@ -335,9 +360,12 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
addr += pending->pitch - 1;
}
+ if (ovl->data->supports_afbc)
+ mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, is_afbc);
+
mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_CON(idx));
- mtk_ddp_write_relaxed(cmdq_pkt, pitch, &ovl->cmdq_reg, ovl->regs,
+ mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_PITCH(idx));
mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_SRC_SIZE(idx));
@@ -346,6 +374,20 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_ADDR(ovl, idx));
+ if (is_afbc) {
+ mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
+ DISP_REG_OVL_HDR_ADDR(ovl, idx));
+ mtk_ddp_write_relaxed(cmdq_pkt,
+ OVL_PITCH_MSB_2ND_SUBBUF | overlay_pitch.split_pitch.msb,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
+ mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs,
+ DISP_REG_OVL_HDR_PITCH(ovl, idx));
+ } else {
+ mtk_ddp_write_relaxed(cmdq_pkt,
+ overlay_pitch.split_pitch.msb,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
+ }
+
mtk_ovl_layer_on(dev, idx, cmdq_pkt);
}
@@ -492,6 +534,15 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
.smi_id_en = true,
};
+static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
+ .addr = DISP_REG_OVL_ADDR_MT8173,
+ .gmc_bits = 10,
+ .layer_nr = 4,
+ .fmt_rgb565_is_0 = true,
+ .smi_id_en = true,
+ .supports_afbc = true,
+};
+
static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-ovl",
.data = &mt2701_ovl_driver_data},
@@ -505,6 +556,8 @@ static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
.data = &mt8192_ovl_driver_data},
{ .compatible = "mediatek,mt8192-disp-ovl-2l",
.data = &mt8192_ovl_2l_driver_data},
+ { .compatible = "mediatek,mt8195-disp-ovl",
+ .data = &mt8195_ovl_driver_data},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 508a6d994e83..4317595a15d1 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -461,9 +461,6 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi)
if (--dpi->refcount != 0)
return;
- if (dpi->pinctrl && dpi->pins_gpio)
- pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
-
mtk_dpi_disable(dpi);
clk_disable_unprepare(dpi->pixel_clk);
clk_disable_unprepare(dpi->engine_clk);
@@ -488,9 +485,6 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
goto err_pixel;
}
- if (dpi->pinctrl && dpi->pins_dpi)
- pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
-
return 0;
err_pixel:
@@ -721,12 +715,18 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
mtk_dpi_power_off(dpi);
+
+ if (dpi->pinctrl && dpi->pins_gpio)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
}
static void mtk_dpi_bridge_enable(struct drm_bridge *bridge)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ if (dpi->pinctrl && dpi->pins_dpi)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
+
mtk_dpi_power_on(dpi);
mtk_dpi_set_display_mode(dpi, &dpi->mode);
mtk_dpi_enable(dpi);
@@ -929,6 +929,20 @@ static const struct mtk_dpi_conf mt8183_conf = {
.csc_enable_bit = CSC_ENABLE,
};
+static const struct mtk_dpi_conf mt8188_dpintf_conf = {
+ .cal_factor = mt8195_dpintf_calculate_factor,
+ .max_clock_khz = 600000,
+ .output_fmts = mt8195_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
+ .pixels_per_iter = 4,
+ .input_2pixel = false,
+ .dimension_mask = DPINTF_HPW_MASK,
+ .hvsize_mask = DPINTF_HSIZE_MASK,
+ .channel_swap_shift = DPINTF_CH_SWAP,
+ .yuv422_en_bit = DPINTF_YUV422_EN,
+ .csc_enable_bit = DPINTF_CSC_ENABLE,
+};
+
static const struct mtk_dpi_conf mt8192_conf = {
.cal_factor = mt8183_calculate_factor,
.reg_h_fre_con = 0xe0,
@@ -1079,6 +1093,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8183-dpi",
.data = &mt8183_conf,
},
+ { .compatible = "mediatek,mt8188-dp-intf",
+ .data = &mt8188_dpintf_conf,
+ },
{ .compatible = "mediatek,mt8192-dpi",
.data = &mt8192_conf,
},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 91f58db5915f..cd5b18ef7951 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -17,7 +17,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
@@ -387,6 +387,12 @@ static int mtk_drm_kms_init(struct drm_device *drm)
goto put_mutex_dev;
/*
+ * Ensure internal panels are at the top of the connector list before
+ * crtc creation.
+ */
+ drm_helper_move_panel_connectors_to_head(drm);
+
+ /*
* We currently support two fixed data streams, each optional,
* and each statically assigned to a crtc:
* OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
@@ -631,6 +637,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8183-dpi",
.data = (void *)MTK_DPI },
+ { .compatible = "mediatek,mt8188-dp-intf",
+ .data = (void *)MTK_DP_INTF },
{ .compatible = "mediatek,mt8192-dpi",
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8195-dp-intf",
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 2f5e007dd380..d54fbf34b000 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -11,6 +11,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
+#include <linux/align.h>
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
@@ -32,6 +33,14 @@ static const u32 formats[] = {
DRM_FORMAT_YUYV,
};
+static const u64 modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
+ AFBC_FORMAT_MOD_SPLIT |
+ AFBC_FORMAT_MOD_SPARSE),
+ DRM_FORMAT_MOD_INVALID,
+};
+
static void mtk_plane_reset(struct drm_plane *plane)
{
struct mtk_plane_state *state;
@@ -51,6 +60,7 @@ static void mtk_plane_reset(struct drm_plane *plane)
state->base.plane = plane;
state->pending.format = DRM_FORMAT_RGB565;
+ state->pending.modifier = DRM_FORMAT_MOD_LINEAR;
}
static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
@@ -71,6 +81,32 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane
return &state->base;
}
+static bool mtk_plane_format_mod_supported(struct drm_plane *plane,
+ uint32_t format,
+ uint64_t modifier)
+{
+ if (modifier == DRM_FORMAT_MOD_LINEAR)
+ return true;
+
+ if (modifier != DRM_FORMAT_MOD_ARM_AFBC(
+ AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
+ AFBC_FORMAT_MOD_SPLIT |
+ AFBC_FORMAT_MOD_SPARSE))
+ return false;
+
+ if (format != DRM_FORMAT_XRGB8888 &&
+ format != DRM_FORMAT_ARGB8888 &&
+ format != DRM_FORMAT_BGRX8888 &&
+ format != DRM_FORMAT_BGRA8888 &&
+ format != DRM_FORMAT_ABGR8888 &&
+ format != DRM_FORMAT_XBGR8888 &&
+ format != DRM_FORMAT_RGB888 &&
+ format != DRM_FORMAT_BGR888)
+ return false;
+
+ return true;
+}
+
static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
@@ -119,21 +155,52 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
struct drm_gem_object *gem;
struct mtk_drm_gem_obj *mtk_gem;
unsigned int pitch, format;
+ u64 modifier;
dma_addr_t addr;
+ dma_addr_t hdr_addr = 0;
+ unsigned int hdr_pitch = 0;
gem = fb->obj[0];
mtk_gem = to_mtk_gem_obj(gem);
addr = mtk_gem->dma_addr;
pitch = fb->pitches[0];
format = fb->format->format;
+ modifier = fb->modifier;
- addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
- addr += (new_state->src.y1 >> 16) * pitch;
+ if (modifier == DRM_FORMAT_MOD_LINEAR) {
+ addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
+ addr += (new_state->src.y1 >> 16) * pitch;
+ } else {
+ int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH)
+ / AFBC_DATA_BLOCK_WIDTH;
+ int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT)
+ / AFBC_DATA_BLOCK_HEIGHT;
+ int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH;
+ int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT;
+ int hdr_size;
+
+ hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;
+ pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
+ AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0];
+
+ hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT);
+
+ hdr_addr = addr + hdr_pitch * y_offset_in_blocks +
+ AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
+ /* The data plane is offset by 1 additional block. */
+ addr = addr + hdr_size +
+ pitch * y_offset_in_blocks +
+ AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
+ fb->format->cpp[0] * (x_offset_in_blocks + 1);
+ }
mtk_plane_state->pending.enable = true;
mtk_plane_state->pending.pitch = pitch;
+ mtk_plane_state->pending.hdr_pitch = hdr_pitch;
mtk_plane_state->pending.format = format;
+ mtk_plane_state->pending.modifier = modifier;
mtk_plane_state->pending.addr = addr;
+ mtk_plane_state->pending.hdr_addr = hdr_addr;
mtk_plane_state->pending.x = new_state->dst.x1;
mtk_plane_state->pending.y = new_state->dst.y1;
mtk_plane_state->pending.width = drm_rect_width(&new_state->dst);
@@ -172,6 +239,7 @@ static const struct drm_plane_funcs mtk_plane_funcs = {
.reset = mtk_plane_reset,
.atomic_duplicate_state = mtk_plane_duplicate_state,
.atomic_destroy_state = mtk_drm_plane_destroy_state,
+ .format_mod_supported = mtk_plane_format_mod_supported,
};
static int mtk_plane_atomic_check(struct drm_plane *plane,
@@ -253,7 +321,7 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
err = drm_universal_plane_init(dev, plane, possible_crtcs,
&mtk_plane_funcs, formats,
- ARRAY_SIZE(formats), NULL, type, NULL);
+ ARRAY_SIZE(formats), modifiers, type, NULL);
if (err) {
DRM_ERROR("failed to initialize plane\n");
return err;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
index 2d5ec66e3df1..8f39011cdbfc 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
@@ -10,12 +10,20 @@
#include <drm/drm_crtc.h>
#include <linux/types.h>
+#define AFBC_DATA_BLOCK_WIDTH 32
+#define AFBC_DATA_BLOCK_HEIGHT 8
+#define AFBC_HEADER_BLOCK_SIZE 16
+#define AFBC_HEADER_ALIGNMENT 1024
+
struct mtk_plane_pending_state {
bool config;
bool enable;
dma_addr_t addr;
+ dma_addr_t hdr_addr;
unsigned int pitch;
+ unsigned int hdr_pitch;
unsigned int format;
+ unsigned long long modifier;
unsigned int x;
unsigned int y;
unsigned int width;
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 4c80b6896dc3..0a8e0a13f516 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1202,9 +1202,10 @@ static enum drm_connector_status mtk_hdmi_detect(struct mtk_hdmi *hdmi)
return mtk_hdmi_update_plugged_status(hdmi);
}
-static int mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
+static enum drm_mode_status
+mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
struct drm_bridge *next_bridge;
@@ -1217,7 +1218,7 @@ static int mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
if (next_bridge) {
struct drm_display_mode adjusted_mode;
- drm_mode_copy(&adjusted_mode, mode);
+ drm_mode_init(&adjusted_mode, mode);
if (!drm_bridge_chain_mode_fixup(next_bridge, mode,
&adjusted_mode))
return MODE_BAD;
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 3b24a924b7b9..79bfe3938d3c 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -18,7 +18,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index 5675bc2a92cf..3f73b211fa8e 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -116,9 +116,10 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
return i;
}
-static int meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *display_info,
- const struct drm_display_mode *mode)
+static enum drm_mode_status
+meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *display_info,
+ const struct drm_display_mode *mode)
{
if (meson_cvbs_get_mode(mode))
return MODE_OK;
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index ece6cd102dbb..976f0ab2006b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -11,6 +11,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index f0c2349404b4..9e604dbb8e44 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -18,7 +18,6 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_plane.h>
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c
index be389ed91cbd..bd6e573c9a1a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
@@ -284,7 +284,8 @@ static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc,
pixpllcp = pixpllc->p - 1;
pixpllcs = pixpllc->s;
- xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
+ // For G200SE A, BIT(7) should be set unconditionally.
+ xpixpllcm = BIT(7) | pixpllcm;
xpixpllcn = pixpllcn;
xpixpllcp = (pixpllcs << 3) | pixpllcp;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index bbab2549243a..0a5aaf78172a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -579,13 +579,13 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st
struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
int ret;
- ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false);
- if (ret)
- return ret;
-
if (!new_crtc_state->enable)
return 0;
+ ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
+ if (ret)
+ return ret;
+
if (new_crtc_state->mode_changed) {
if (funcs->pixpllc_atomic_check) {
ret = funcs->pixpllc_atomic_check(crtc, new_state);
@@ -601,7 +601,7 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st
}
}
- return drm_atomic_add_affected_planes(new_state, crtc);
+ return 0;
}
void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
@@ -824,7 +824,6 @@ int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_avail
dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH;
dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
dev->mode_config.preferred_depth = 24;
- dev->mode_config.fb_base = mdev->vram_res->start;
dev->mode_config.funcs = &mgag200_mode_config_funcs;
dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs;
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index 2c8b9899625b..948785ed07bb 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -500,7 +500,7 @@ static const struct adreno_gpu_funcs funcs = {
#endif
.gpu_state_get = a3xx_gpu_state_get,
.gpu_state_put = adreno_gpu_state_put,
- .create_address_space = adreno_iommu_create_address_space,
+ .create_address_space = adreno_create_address_space,
.get_rptr = a3xx_get_rptr,
},
};
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index 7cb8d9849c07..3e09d3a7a0ac 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -606,8 +606,7 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) {
static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
{
- *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO,
- REG_A4XX_RBBM_PERFCTR_CP_0_HI);
+ *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
return 0;
}
@@ -635,7 +634,7 @@ static const struct adreno_gpu_funcs funcs = {
#endif
.gpu_state_get = a4xx_gpu_state_get,
.gpu_state_put = adreno_gpu_state_put,
- .create_address_space = adreno_iommu_create_address_space,
+ .create_address_space = adreno_create_address_space,
.get_rptr = a4xx_get_rptr,
},
.get_timestamp = a4xx_get_timestamp,
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 3dcec7acb384..660ba0db8900 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -605,11 +605,9 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
a5xx_ucode_check_version(a5xx_gpu, a5xx_gpu->pfp_bo);
}
- gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO,
- REG_A5XX_CP_ME_INSTR_BASE_HI, a5xx_gpu->pm4_iova);
+ gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, a5xx_gpu->pm4_iova);
- gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO,
- REG_A5XX_CP_PFP_INSTR_BASE_HI, a5xx_gpu->pfp_iova);
+ gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, a5xx_gpu->pfp_iova);
return 0;
}
@@ -868,8 +866,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
* memory rendering at this point in time and we don't want to block off
* part of the virtual memory space.
*/
- gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO,
- REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000);
+ gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 0x00000000);
gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000);
/* Put the GPU into 64 bit by default */
@@ -908,8 +905,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
return ret;
/* Set the ringbuffer address */
- gpu_write64(gpu, REG_A5XX_CP_RB_BASE, REG_A5XX_CP_RB_BASE_HI,
- gpu->rb[0]->iova);
+ gpu_write64(gpu, REG_A5XX_CP_RB_BASE, gpu->rb[0]->iova);
/*
* If the microcode supports the WHERE_AM_I opcode then we can use that
@@ -936,7 +932,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
}
gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR,
- REG_A5XX_CP_RB_RPTR_ADDR_HI, shadowptr(a5xx_gpu, gpu->rb[0]));
+ shadowptr(a5xx_gpu, gpu->rb[0]));
} else if (gpu->nr_rings > 1) {
/* Disable preemption if WHERE_AM_I isn't available */
a5xx_preempt_fini(gpu);
@@ -1239,9 +1235,9 @@ static void a5xx_fault_detect_irq(struct msm_gpu *gpu)
gpu_read(gpu, REG_A5XX_RBBM_STATUS),
gpu_read(gpu, REG_A5XX_CP_RB_RPTR),
gpu_read(gpu, REG_A5XX_CP_RB_WPTR),
- gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI),
+ gpu_read64(gpu, REG_A5XX_CP_IB1_BASE),
gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ),
- gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI),
+ gpu_read64(gpu, REG_A5XX_CP_IB2_BASE),
gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ));
/* Turn off the hangcheck timer to keep it from bothering us */
@@ -1427,8 +1423,7 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu)
static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
{
- *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO,
- REG_A5XX_RBBM_ALWAYSON_COUNTER_HI);
+ *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO);
return 0;
}
@@ -1465,8 +1460,7 @@ static int a5xx_crashdumper_run(struct msm_gpu *gpu,
if (IS_ERR_OR_NULL(dumper->ptr))
return -EINVAL;
- gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO,
- REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova);
+ gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, dumper->iova);
gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1);
@@ -1666,8 +1660,7 @@ static u64 a5xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
{
u64 busy_cycles;
- busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
- REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
+ busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO);
*out_sample_rate = clk_get_rate(gpu->core_clk);
return busy_cycles;
@@ -1705,7 +1698,7 @@ static const struct adreno_gpu_funcs funcs = {
.gpu_busy = a5xx_gpu_busy,
.gpu_state_get = a5xx_gpu_state_get,
.gpu_state_put = a5xx_gpu_state_put,
- .create_address_space = adreno_iommu_create_address_space,
+ .create_address_space = adreno_create_address_space,
.get_rptr = a5xx_get_rptr,
},
.get_timestamp = a5xx_get_timestamp,
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
index 8abc9a2b114a..7658e89844b4 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
@@ -137,7 +137,6 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu)
/* Set the address of the incoming preemption record */
gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO,
- REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI,
a5xx_gpu->preempt_iova[ring->id]);
a5xx_gpu->next_ring = ring;
@@ -211,8 +210,7 @@ void a5xx_preempt_hw_init(struct msm_gpu *gpu)
}
/* Write a 0 to signal that we aren't switching pagetables */
- gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO,
- REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI, 0);
+ gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO, 0);
/* Reset the preemption state */
set_preempt_state(a5xx_gpu, PREEMPT_NONE);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index e033d6a67a20..6484b97c5344 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1213,19 +1213,17 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo,
static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu)
{
- struct iommu_domain *domain;
struct msm_mmu *mmu;
- domain = iommu_domain_alloc(&platform_bus_type);
- if (!domain)
+ mmu = msm_iommu_new(gmu->dev, 0);
+ if (!mmu)
return -ENODEV;
+ if (IS_ERR(mmu))
+ return PTR_ERR(mmu);
- mmu = msm_iommu_new(gmu->dev, domain);
gmu->aspace = msm_gem_address_space_create(mmu, "gmu", 0x0, 0x80000000);
- if (IS_ERR(gmu->aspace)) {
- iommu_domain_free(domain);
+ if (IS_ERR(gmu->aspace))
return PTR_ERR(gmu->aspace);
- }
return 0;
}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index fdc578016e0b..36c8fb699b56 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -247,8 +247,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, submit->seqno);
trace_msm_gpu_submit_flush(submit,
- gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO,
- REG_A6XX_CP_ALWAYS_ON_COUNTER_HI));
+ gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO));
a6xx_flush(gpu, ring);
}
@@ -947,8 +946,7 @@ static int a6xx_ucode_init(struct msm_gpu *gpu)
}
}
- gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE,
- REG_A6XX_CP_SQE_INSTR_BASE+1, a6xx_gpu->sqe_iova);
+ gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE, a6xx_gpu->sqe_iova);
return 0;
}
@@ -999,8 +997,7 @@ static int hw_init(struct msm_gpu *gpu)
* memory rendering at this point in time and we don't want to block off
* part of the virtual memory space.
*/
- gpu_write64(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO,
- REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000);
+ gpu_write64(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 0x00000000);
gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000);
/* Turn on 64 bit addressing for all blocks */
@@ -1049,11 +1046,9 @@ static int hw_init(struct msm_gpu *gpu)
if (!adreno_is_a650_family(adreno_gpu)) {
/* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */
- gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO,
- REG_A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000);
+ gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000);
gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX_LO,
- REG_A6XX_UCHE_GMEM_RANGE_MAX_HI,
0x00100000 + adreno_gpu->gmem - 1);
}
@@ -1145,8 +1140,7 @@ static int hw_init(struct msm_gpu *gpu)
goto out;
/* Set the ringbuffer address */
- gpu_write64(gpu, REG_A6XX_CP_RB_BASE, REG_A6XX_CP_RB_BASE_HI,
- gpu->rb[0]->iova);
+ gpu_write64(gpu, REG_A6XX_CP_RB_BASE, gpu->rb[0]->iova);
/* Targets that support extended APRIV can use the RPTR shadow from
* hardware but all the other ones need to disable the feature. Targets
@@ -1178,7 +1172,6 @@ static int hw_init(struct msm_gpu *gpu)
}
gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR_LO,
- REG_A6XX_CP_RB_RPTR_ADDR_HI,
shadowptr(a6xx_gpu, gpu->rb[0]));
}
@@ -1499,9 +1492,9 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)
gpu_read(gpu, REG_A6XX_RBBM_STATUS),
gpu_read(gpu, REG_A6XX_CP_RB_RPTR),
gpu_read(gpu, REG_A6XX_CP_RB_WPTR),
- gpu_read64(gpu, REG_A6XX_CP_IB1_BASE, REG_A6XX_CP_IB1_BASE_HI),
+ gpu_read64(gpu, REG_A6XX_CP_IB1_BASE),
gpu_read(gpu, REG_A6XX_CP_IB1_REM_SIZE),
- gpu_read64(gpu, REG_A6XX_CP_IB2_BASE, REG_A6XX_CP_IB2_BASE_HI),
+ gpu_read64(gpu, REG_A6XX_CP_IB2_BASE),
gpu_read(gpu, REG_A6XX_CP_IB2_REM_SIZE));
/* Turn off the hangcheck timer to keep it from bothering us */
@@ -1712,8 +1705,7 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
/* Force the GPU power on so we can read this register */
a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
- *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO,
- REG_A6XX_CP_ALWAYS_ON_COUNTER_HI);
+ *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO);
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
@@ -1786,43 +1778,16 @@ a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
- struct iommu_domain *iommu;
- struct msm_mmu *mmu;
- struct msm_gem_address_space *aspace;
- u64 start, size;
-
- iommu = iommu_domain_alloc(&platform_bus_type);
- if (!iommu)
- return NULL;
+ unsigned long quirks = 0;
/*
* This allows GPU to set the bus attributes required to use system
* cache on behalf of the iommu page table walker.
*/
if (!IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice))
- adreno_set_llc_attributes(iommu);
-
- mmu = msm_iommu_new(&pdev->dev, iommu);
- if (IS_ERR(mmu)) {
- iommu_domain_free(iommu);
- return ERR_CAST(mmu);
- }
-
- /*
- * Use the aperture start or SZ_16M, whichever is greater. This will
- * ensure that we align with the allocated pagetable range while still
- * allowing room in the lower 32 bits for GMEM and whatnot
- */
- start = max_t(u64, SZ_16M, iommu->geometry.aperture_start);
- size = iommu->geometry.aperture_end - start + 1;
-
- aspace = msm_gem_address_space_create(mmu, "gpu",
- start & GENMASK_ULL(48, 0), size);
+ quirks |= IO_PGTABLE_QUIRK_ARM_OUTER_WBWA;
- if (IS_ERR(aspace) && !IS_ERR(mmu))
- mmu->funcs->destroy(mmu);
-
- return aspace;
+ return adreno_iommu_create_address_space(gpu, pdev, quirks);
}
static struct msm_gem_address_space *
@@ -1851,6 +1816,39 @@ static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return ring->memptrs->rptr = gpu_read(gpu, REG_A6XX_CP_RB_RPTR);
}
+static bool a6xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
+{
+ struct msm_cp_state cp_state = {
+ .ib1_base = gpu_read64(gpu, REG_A6XX_CP_IB1_BASE),
+ .ib2_base = gpu_read64(gpu, REG_A6XX_CP_IB2_BASE),
+ .ib1_rem = gpu_read(gpu, REG_A6XX_CP_IB1_REM_SIZE),
+ .ib2_rem = gpu_read(gpu, REG_A6XX_CP_IB2_REM_SIZE),
+ };
+ bool progress;
+
+ /*
+ * Adjust the remaining data to account for what has already been
+ * fetched from memory, but not yet consumed by the SQE.
+ *
+ * This is not *technically* correct, the amount buffered could
+ * exceed the IB size due to hw prefetching ahead, but:
+ *
+ * (1) We aren't trying to find the exact position, just whether
+ * progress has been made
+ * (2) The CP_REG_TO_MEM at the end of a submit should be enough
+ * to prevent prefetching into an unrelated submit. (And
+ * either way, at some point the ROQ will be full.)
+ */
+ cp_state.ib1_rem += gpu_read(gpu, REG_A6XX_CP_CSQ_IB1_STAT) >> 16;
+ cp_state.ib2_rem += gpu_read(gpu, REG_A6XX_CP_CSQ_IB2_STAT) >> 16;
+
+ progress = !!memcmp(&cp_state, &ring->last_cp_state, sizeof(cp_state));
+
+ ring->last_cp_state = cp_state;
+
+ return progress;
+}
+
static u32 a618_get_speed_bin(u32 fuse)
{
if (fuse == 0)
@@ -1906,7 +1904,7 @@ static u32 fuse_to_supp_hw(struct device *dev, struct adreno_rev rev, u32 fuse)
if (val == UINT_MAX) {
DRM_DEV_ERROR(dev,
- "missing support for speed-bin: %u. Some OPPs may not be supported by hardware",
+ "missing support for speed-bin: %u. Some OPPs may not be supported by hardware\n",
fuse);
return UINT_MAX;
}
@@ -1916,7 +1914,7 @@ static u32 fuse_to_supp_hw(struct device *dev, struct adreno_rev rev, u32 fuse)
static int a6xx_set_supported_hw(struct device *dev, struct adreno_rev rev)
{
- u32 supp_hw = UINT_MAX;
+ u32 supp_hw;
u32 speedbin;
int ret;
@@ -1928,15 +1926,13 @@ static int a6xx_set_supported_hw(struct device *dev, struct adreno_rev rev)
if (ret == -ENOENT) {
return 0;
} else if (ret) {
- DRM_DEV_ERROR(dev,
- "failed to read speed-bin (%d). Some OPPs may not be supported by hardware",
- ret);
- goto done;
+ dev_err_probe(dev, ret,
+ "failed to read speed-bin. Some OPPs may not be supported by hardware\n");
+ return ret;
}
supp_hw = fuse_to_supp_hw(dev, rev, speedbin);
-done:
ret = devm_pm_opp_set_supported_hw(dev, &supp_hw, 1);
if (ret)
return ret;
@@ -1969,6 +1965,7 @@ static const struct adreno_gpu_funcs funcs = {
.create_address_space = a6xx_create_address_space,
.create_private_address_space = a6xx_create_private_address_space,
.get_rptr = a6xx_get_rptr,
+ .progress = a6xx_progress,
},
.get_timestamp = a6xx_get_timestamp,
};
@@ -2005,13 +2002,6 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), info->rev)))
adreno_gpu->base.hw_apriv = true;
- /*
- * For now only clamp to idle freq for devices where this is known not
- * to cause power supply issues:
- */
- if (info && (info->revn == 618))
- gpu->clamp_to_idle = true;
-
a6xx_llc_slices_init(pdev, a6xx_gpu);
ret = a6xx_set_supported_hw(&pdev->dev, config->rev);
@@ -2026,6 +2016,13 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
+ /*
+ * For now only clamp to idle freq for devices where this is known not
+ * to cause power supply issues:
+ */
+ if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu))
+ gpu->clamp_to_idle = true;
+
/* Check if there is a GMU phandle and set it up */
node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
index a5c3d1ed255a..a023d5f962dc 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -147,8 +147,7 @@ static int a6xx_crashdumper_run(struct msm_gpu *gpu,
/* Make sure all pending memory writes are posted */
wmb();
- gpu_write64(gpu, REG_A6XX_CP_CRASH_SCRIPT_BASE_LO,
- REG_A6XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova);
+ gpu_write64(gpu, REG_A6XX_CP_CRASH_SCRIPT_BASE_LO, dumper->iova);
gpu_write(gpu, REG_A6XX_CP_CRASH_DUMP_CNTL, 1);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 5a0e8491cd3a..57586c794b84 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -191,37 +191,38 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid);
}
-void adreno_set_llc_attributes(struct iommu_domain *iommu)
+struct msm_gem_address_space *
+adreno_create_address_space(struct msm_gpu *gpu,
+ struct platform_device *pdev)
{
- iommu_set_pgtable_quirks(iommu, IO_PGTABLE_QUIRK_ARM_OUTER_WBWA);
+ return adreno_iommu_create_address_space(gpu, pdev, 0);
}
struct msm_gem_address_space *
adreno_iommu_create_address_space(struct msm_gpu *gpu,
- struct platform_device *pdev)
+ struct platform_device *pdev,
+ unsigned long quirks)
{
- struct iommu_domain *iommu;
+ struct iommu_domain_geometry *geometry;
struct msm_mmu *mmu;
struct msm_gem_address_space *aspace;
u64 start, size;
- iommu = iommu_domain_alloc(&platform_bus_type);
- if (!iommu)
- return NULL;
-
- mmu = msm_iommu_new(&pdev->dev, iommu);
- if (IS_ERR(mmu)) {
- iommu_domain_free(iommu);
+ mmu = msm_iommu_new(&pdev->dev, quirks);
+ if (IS_ERR_OR_NULL(mmu))
return ERR_CAST(mmu);
- }
+
+ geometry = msm_iommu_get_geometry(mmu);
+ if (IS_ERR(geometry))
+ return ERR_CAST(geometry);
/*
* Use the aperture start or SZ_16M, whichever is greater. This will
* ensure that we align with the allocated pagetable range while still
* allowing room in the lower 32 bits for GMEM and whatnot
*/
- start = max_t(u64, SZ_16M, iommu->geometry.aperture_start);
- size = iommu->geometry.aperture_end - start + 1;
+ start = max_t(u64, SZ_16M, geometry->aperture_start);
+ size = geometry->aperture_end - start + 1;
aspace = msm_gem_address_space_create(mmu, "gpu",
start & GENMASK_ULL(48, 0), size);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index e7adc5c632d0..5d4b1c95033f 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -335,10 +335,13 @@ void adreno_show_object(struct drm_printer *p, void **ptr, int len,
* attached targets
*/
struct msm_gem_address_space *
-adreno_iommu_create_address_space(struct msm_gpu *gpu,
- struct platform_device *pdev);
+adreno_create_address_space(struct msm_gpu *gpu,
+ struct platform_device *pdev);
-void adreno_set_llc_attributes(struct iommu_domain *iommu);
+struct msm_gem_address_space *
+adreno_iommu_create_address_space(struct msm_gpu *gpu,
+ struct platform_device *pdev,
+ unsigned long quirks);
int adreno_read_speedbin(struct device *dev, u32 *speedbin);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 2c14646661b7..0f71e8fe7be7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -237,12 +237,13 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
+ drm_mode_init(&mode, &phys_enc->cached_mode);
+
if (!phys_enc->hw_ctl->ops.setup_intf_cfg) {
DPU_ERROR("invalid encoder %d\n", phys_enc != NULL);
return;
}
- mode = phys_enc->cached_mode;
if (!phys_enc->hw_intf->ops.setup_timing_gen) {
DPU_ERROR("timing engine setup is not supported\n");
return;
@@ -634,7 +635,9 @@ static int dpu_encoder_phys_vid_get_frame_count(
{
struct intf_status s = {0};
u32 fetch_start = 0;
- struct drm_display_mode mode = phys_enc->cached_mode;
+ struct drm_display_mode mode;
+
+ drm_mode_init(&mode, &phys_enc->cached_mode);
if (!dpu_encoder_phys_vid_is_master(phys_enc))
return -EINVAL;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index f436a1f3419d..d95540309d4d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -434,6 +434,12 @@ static const struct dpu_format dpu_format_map[] = {
DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV,
DPU_FETCH_LINEAR, 2),
+ PSEUDO_YUV_FMT_LOOSE(P010,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ DPU_CHROMA_420, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_YUV,
+ DPU_FETCH_LINEAR, 2),
+
INTERLEAVED_YUV_FMT(VYUY,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y,
@@ -524,12 +530,26 @@ static const struct dpu_format dpu_format_map_ubwc[] = {
true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
+ INTERLEAVED_RGB_FMT_TILED(XRGB2101010,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED,
+ DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC),
+
PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV |
DPU_FORMAT_FLAG_COMPRESSED,
DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12),
+
+ PSEUDO_YUV_FMT_TILED(P010,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ DPU_CHROMA_420, DPU_FORMAT_FLAG_DX |
+ DPU_FORMAT_FLAG_YUV |
+ DPU_FORMAT_FLAG_COMPRESSED,
+ DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_UBWC),
};
/* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support
@@ -571,13 +591,15 @@ static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt)
{DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
{DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC},
{DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+ {DRM_FORMAT_XRGB2101010, COLOR_FMT_RGBA1010102_UBWC},
{DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
{DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
};
int color_fmt = -1;
int i;
- if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
+ if (fmt->base.pixel_format == DRM_FORMAT_NV12 ||
+ fmt->base.pixel_format == DRM_FORMAT_P010) {
if (DPU_FORMAT_IS_DX(fmt)) {
if (fmt->unpack_tight)
color_fmt = COLOR_FMT_NV12_BPP10_UBWC;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 27f029fdc682..2196e205efa5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -156,6 +156,7 @@ static const uint32_t plane_formats[] = {
DRM_FORMAT_RGBX8888,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB2101010,
DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
DRM_FORMAT_RGB565,
@@ -184,6 +185,7 @@ static const uint32_t plane_formats_yuv[] = {
DRM_FORMAT_RGBA8888,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_RGBX8888,
@@ -208,6 +210,7 @@ static const uint32_t plane_formats_yuv[] = {
DRM_FORMAT_RGBX4444,
DRM_FORMAT_BGRX4444,
+ DRM_FORMAT_P010,
DRM_FORMAT_NV12,
DRM_FORMAT_NV21,
DRM_FORMAT_NV16,
@@ -318,6 +321,18 @@ static const struct dpu_caps sc7180_dpu_caps = {
.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
};
+static const struct dpu_caps sm6115_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0x4,
+ .qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_20,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .max_linewidth = 2160,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
static const struct dpu_caps sm8150_dpu_caps = {
.max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.max_mixer_blendstages = 0xb,
@@ -472,6 +487,19 @@ static const struct dpu_mdp_cfg sc8180x_mdp[] = {
},
};
+static const struct dpu_mdp_cfg sm6115_mdp[] = {
+ {
+ .name = "top_0", .id = MDP_TOP,
+ .base = 0x0, .len = 0x494,
+ .features = 0,
+ .highest_bank_bit = 0x1,
+ .clk_ctrls[DPU_CLK_CTRL_VIG0] = {
+ .reg_off = 0x2ac, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA0] = {
+ .reg_off = 0x2ac, .bit_off = 8},
+ },
+};
+
static const struct dpu_mdp_cfg sm8250_mdp[] = {
{
.name = "top_0", .id = MDP_TOP,
@@ -849,6 +877,16 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = {
sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
};
+static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 =
+ _VIG_SBLK("0", 2, DPU_SSPP_SCALER_QSEED3LITE);
+
+static const struct dpu_sspp_cfg sm6115_sspp[] = {
+ SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SM8250_MASK,
+ sm6115_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
+ SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0),
+};
+
static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 =
_VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE);
static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 =
@@ -1175,6 +1213,13 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = {
-1),
};
+static const struct dpu_pingpong_cfg sc7280_pp[] = {
+ PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
+ PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
+ PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
+ PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
+};
+
static struct dpu_pingpong_cfg qcm2290_pp[] = {
PP_BLK("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk,
DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
@@ -1198,13 +1243,6 @@ static const struct dpu_merge_3d_cfg sm8150_merge_3d[] = {
MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x83200),
};
-static const struct dpu_pingpong_cfg sc7280_pp[] = {
- PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
- PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
- PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
- PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
-};
-
/*************************************************************
* DSC sub blocks config
*************************************************************/
@@ -1587,6 +1625,35 @@ static const struct dpu_perf_cfg sc7180_perf_data = {
.bw_inefficiency_factor = 120,
};
+static const struct dpu_perf_cfg sm6115_perf_data = {
+ .max_bw_low = 3100000,
+ .max_bw_high = 4000000,
+ .min_core_ib = 2400000,
+ .min_llcc_ib = 800000,
+ .min_dram_ib = 800000,
+ .min_prefill_lines = 24,
+ .danger_lut_tbl = {0xff, 0xffff, 0x0},
+ .safe_lut_tbl = {0xfff0, 0xff00, 0xffff},
+ .qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc7180_qos_linear),
+ .entries = sc7180_qos_linear
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
+ .entries = sc7180_qos_macrotile
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_nrt),
+ .entries = sc7180_qos_nrt
+ },
+ /* TODO: macrotile-qseed is different from macrotile */
+ },
+ .cdp_cfg = {
+ {.rd_enable = 1, .wr_enable = 1},
+ {.rd_enable = 1, .wr_enable = 0}
+ },
+ .clk_inefficiency_factor = 105,
+ .bw_inefficiency_factor = 120,
+};
+
static const struct dpu_perf_cfg sm8150_perf_data = {
.max_bw_low = 12800000,
.max_bw_high = 12800000,
@@ -1798,6 +1865,28 @@ static const struct dpu_mdss_cfg sc7180_dpu_cfg = {
.mdss_irqs = IRQ_SC7180_MASK,
};
+static const struct dpu_mdss_cfg sm6115_dpu_cfg = {
+ .caps = &sm6115_dpu_caps,
+ .mdp_count = ARRAY_SIZE(sm6115_mdp),
+ .mdp = sm6115_mdp,
+ .ctl_count = ARRAY_SIZE(qcm2290_ctl),
+ .ctl = qcm2290_ctl,
+ .sspp_count = ARRAY_SIZE(sm6115_sspp),
+ .sspp = sm6115_sspp,
+ .mixer_count = ARRAY_SIZE(qcm2290_lm),
+ .mixer = qcm2290_lm,
+ .dspp_count = ARRAY_SIZE(qcm2290_dspp),
+ .dspp = qcm2290_dspp,
+ .pingpong_count = ARRAY_SIZE(qcm2290_pp),
+ .pingpong = qcm2290_pp,
+ .intf_count = ARRAY_SIZE(qcm2290_intf),
+ .intf = qcm2290_intf,
+ .vbif_count = ARRAY_SIZE(sdm845_vbif),
+ .vbif = sdm845_vbif,
+ .perf = &sm6115_perf_data,
+ .mdss_irqs = IRQ_SC7180_MASK,
+};
+
static const struct dpu_mdss_cfg sm8150_dpu_cfg = {
.caps = &sm8150_dpu_caps,
.mdp_count = ARRAY_SIZE(sdm845_mdp),
@@ -1932,6 +2021,7 @@ static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = {
{ .hw_rev = DPU_HW_VER_510, .dpu_cfg = &sc8180x_dpu_cfg},
{ .hw_rev = DPU_HW_VER_600, .dpu_cfg = &sm8250_dpu_cfg},
{ .hw_rev = DPU_HW_VER_620, .dpu_cfg = &sc7180_dpu_cfg},
+ { .hw_rev = DPU_HW_VER_630, .dpu_cfg = &sm6115_dpu_cfg},
{ .hw_rev = DPU_HW_VER_650, .dpu_cfg = &qcm2290_dpu_cfg},
{ .hw_rev = DPU_HW_VER_720, .dpu_cfg = &sc7280_dpu_cfg},
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 38aa38ab1568..3b645d5aa9aa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -44,6 +44,7 @@
#define DPU_HW_VER_510 DPU_HW_VER(5, 1, 1) /* sc8180 */
#define DPU_HW_VER_600 DPU_HW_VER(6, 0, 0) /* sm8250 */
#define DPU_HW_VER_620 DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */
+#define DPU_HW_VER_630 DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */
#define DPU_HW_VER_650 DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */
#define DPU_HW_VER_720 DPU_HW_VER(7, 2, 0) /* sc7280 */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
index f2ddcfb6f7ee..3662df698dae 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
@@ -42,7 +42,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
u32 initial_lines)
{
struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
- u32 data, lsb, bpp;
+ u32 data;
u32 slice_last_group_size;
u32 det_thresh_flatness;
bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
@@ -56,14 +56,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
data = (initial_lines << 20);
data |= ((slice_last_group_size - 1) << 18);
/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
- data |= dsc->bits_per_pixel << 12;
- lsb = dsc->bits_per_pixel % 4;
- bpp = dsc->bits_per_pixel / 4;
- bpp *= 4;
- bpp <<= 4;
- bpp |= lsb;
-
- data |= bpp << 8;
+ data |= (dsc->bits_per_pixel << 8);
data |= (dsc->block_pred_enable << 7);
data |= (dsc->line_buf_depth << 3);
data |= (dsc->simple_422 << 2);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 5e6e2626151e..b71199511a52 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -194,7 +194,7 @@ struct dpu_debugfs_regset32 {
struct dpu_kms *dpu_kms;
};
-static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data)
+static int dpu_regset32_show(struct seq_file *s, void *data)
{
struct dpu_debugfs_regset32 *regset = s->private;
struct dpu_kms *dpu_kms = regset->dpu_kms;
@@ -227,19 +227,7 @@ static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data)
return 0;
}
-
-static int dpu_debugfs_open_regset32(struct inode *inode,
- struct file *file)
-{
- return single_open(file, _dpu_debugfs_show_regset32, inode->i_private);
-}
-
-static const struct file_operations dpu_fops_regset32 = {
- .open = dpu_debugfs_open_regset32,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dpu_regset32);
void dpu_debugfs_create_regset32(const char *name, umode_t mode,
void *parent,
@@ -259,7 +247,7 @@ void dpu_debugfs_create_regset32(const char *name, umode_t mode,
regset->blk_len = length;
regset->dpu_kms = dpu_kms;
- debugfs_create_file(name, mode, parent, regset, &dpu_fops_regset32);
+ debugfs_create_file(name, mode, parent, regset, &dpu_regset32_fops);
}
static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
@@ -1304,6 +1292,7 @@ static const struct of_device_id dpu_dt_match[] = {
{ .compatible = "qcom,sc7180-dpu", },
{ .compatible = "qcom,sc7280-dpu", },
{ .compatible = "qcom,sc8180x-dpu", },
+ { .compatible = "qcom,sm6115-dpu", },
{ .compatible = "qcom,sm8150-dpu", },
{ .compatible = "qcom,sm8250-dpu", },
{}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 658005f609f4..86719020afe2 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -69,9 +69,11 @@ static const uint32_t qcom_compressed_supported_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XRGB2101010,
DRM_FORMAT_BGR565,
DRM_FORMAT_NV12,
+ DRM_FORMAT_P010,
};
/**
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index 964573d26d26..9a1a0769575d 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -387,7 +387,7 @@ static int mdp4_kms_init(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct mdp4_kms *mdp4_kms;
struct msm_kms *kms = NULL;
- struct iommu_domain *iommu;
+ struct msm_mmu *mmu;
struct msm_gem_address_space *aspace;
int irq, ret;
u32 major, minor;
@@ -499,10 +499,15 @@ static int mdp4_kms_init(struct drm_device *dev)
mdp4_disable(mdp4_kms);
mdelay(16);
- iommu = iommu_domain_alloc(pdev->dev.bus);
- if (iommu) {
- struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu);
-
+ mmu = msm_iommu_new(&pdev->dev, 0);
+ if (IS_ERR(mmu)) {
+ ret = PTR_ERR(mmu);
+ goto fail;
+ } else if (!mmu) {
+ DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys "
+ "contig buffers for scanout\n");
+ aspace = NULL;
+ } else {
aspace = msm_gem_address_space_create(mmu,
"mdp4", 0x1000, 0x100000000 - 0x1000);
@@ -514,10 +519,6 @@ static int mdp4_kms_init(struct drm_device *dev)
}
kms->aspace = aspace;
- } else {
- DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys "
- "contig buffers for scanout\n");
- aspace = NULL;
}
ret = modeset_init(mdp4_kms);
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index b0d21838a134..29ae5c9613f3 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -203,7 +203,7 @@ static int mdp5_set_split_display(struct msm_kms *kms,
slave_encoder);
}
-static void mdp5_destroy(struct platform_device *pdev);
+static void mdp5_destroy(struct mdp5_kms *mdp5_kms);
static void mdp5_kms_destroy(struct msm_kms *kms)
{
@@ -223,7 +223,7 @@ static void mdp5_kms_destroy(struct msm_kms *kms)
}
mdp_kms_destroy(&mdp5_kms->base);
- mdp5_destroy(mdp5_kms->pdev);
+ mdp5_destroy(mdp5_kms);
}
#ifdef CONFIG_DEBUG_FS
@@ -559,6 +559,8 @@ static int mdp5_kms_init(struct drm_device *dev)
int irq, i, ret;
ret = mdp5_init(to_platform_device(dev->dev), dev);
+ if (ret)
+ return ret;
/* priv->kms would have been populated by the MDP5 driver */
kms = priv->kms;
@@ -632,9 +634,8 @@ fail:
return ret;
}
-static void mdp5_destroy(struct platform_device *pdev)
+static void mdp5_destroy(struct mdp5_kms *mdp5_kms)
{
- struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
int i;
if (mdp5_kms->ctlm)
@@ -648,7 +649,7 @@ static void mdp5_destroy(struct platform_device *pdev)
kfree(mdp5_kms->intfs[i]);
if (mdp5_kms->rpm_enabled)
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(&mdp5_kms->pdev->dev);
drm_atomic_private_obj_fini(&mdp5_kms->glob_state);
drm_modeset_lock_fini(&mdp5_kms->glob_state_lock);
@@ -797,8 +798,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
goto fail;
}
- platform_set_drvdata(pdev, mdp5_kms);
-
spin_lock_init(&mdp5_kms->resource_lock);
mdp5_kms->dev = dev;
@@ -839,6 +838,9 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
*/
clk_set_rate(mdp5_kms->core_clk, 200000000);
+ /* set uninit-ed kms */
+ priv->kms = &mdp5_kms->base.base;
+
pm_runtime_enable(&pdev->dev);
mdp5_kms->rpm_enabled = true;
@@ -890,13 +892,10 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
if (ret)
goto fail;
- /* set uninit-ed kms */
- priv->kms = &mdp5_kms->base.base;
-
return 0;
fail:
if (mdp5_kms)
- mdp5_destroy(pdev);
+ mdp5_destroy(mdp5_kms);
return ret;
}
@@ -953,7 +952,8 @@ static int mdp5_dev_remove(struct platform_device *pdev)
static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+ struct msm_drm_private *priv = platform_get_drvdata(pdev);
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
DBG("");
@@ -963,7 +963,8 @@ static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
static __maybe_unused int mdp5_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+ struct msm_drm_private *priv = platform_get_drvdata(pdev);
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
DBG("");
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index a49f6dbbe888..7ff60e5ff325 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -857,7 +857,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
dp = container_of(dp_display, struct dp_display_private, dp_display);
- dp->panel->dp_mode.drm_mode = mode->drm_mode;
+ drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
dp_panel_init_panel_info(dp->panel);
@@ -1600,20 +1600,10 @@ error:
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
{
- struct msm_drm_private *priv;
+ struct msm_drm_private *priv = dev->dev_private;
struct dp_display_private *dp_priv;
int ret;
- if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev))
- return -EINVAL;
-
- priv = dev->dev_private;
-
- if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
- DRM_DEV_ERROR(dev->dev, "too many bridges\n");
- return -ENOSPC;
- }
-
dp_display->drm_dev = dev;
dp_priv = container_of(dp_display, struct dp_display_private, dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 36bb6191d2f0..f1f1d646539d 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -49,23 +49,26 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux,
struct dp_link_info *link)
{
u8 value;
- int err;
+ ssize_t len;
+ int i;
if (link->revision < 0x11)
return 0;
- err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
- if (err < 0)
- return err;
+ len = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
+ if (len < 0)
+ return len;
value &= ~DP_SET_POWER_MASK;
value |= DP_SET_POWER_D0;
- err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
- if (err < 0)
- return err;
-
- usleep_range(1000, 2000);
+ /* retry for 1ms to give the sink time to wake up */
+ for (i = 0; i < 3; i++) {
+ len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
+ usleep_range(1000, 2000);
+ if (len == 1)
+ break;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 8a95c744972a..31fdee2052be 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -211,14 +211,9 @@ void __exit msm_dsi_unregister(void)
int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
struct drm_encoder *encoder)
{
- struct msm_drm_private *priv;
+ struct msm_drm_private *priv = dev->dev_private;
int ret;
- if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
- return -EINVAL;
-
- priv = dev->dev_private;
-
if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
DRM_DEV_ERROR(dev->dev, "too many bridges\n");
return -ENOSPC;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 7fbf391c024f..89aadd3b3202 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -21,6 +21,7 @@
#include <video/mipi_display.h>
+#include <drm/display/drm_dsc_helper.h>
#include <drm/drm_of.h>
#include "dsi.h"
@@ -33,7 +34,7 @@
#define DSI_RESET_TOGGLE_DELAY_MS 20
-static int dsi_populate_dsc_params(struct drm_dsc_config *dsc);
+static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc);
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
{
@@ -842,17 +843,15 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay)
{
struct drm_dsc_config *dsc = msm_host->dsc;
- u32 reg, intf_width, reg_ctrl, reg_ctrl2;
+ u32 reg, reg_ctrl, reg_ctrl2;
u32 slice_per_intf, total_bytes_per_intf;
u32 pkt_per_line;
- u32 bytes_in_slice;
u32 eol_byte_num;
/* first calculate dsc parameters and then program
* compress mode registers
*/
- intf_width = hdisplay;
- slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width);
+ slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width);
/* If slice_per_pkt is greater than slice_per_intf
* then default to 1. This can happen during partial
@@ -861,12 +860,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod
if (slice_per_intf > dsc->slice_count)
dsc->slice_count = 1;
- slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width);
- bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8);
-
- dsc->slice_chunk_size = bytes_in_slice;
-
- total_bytes_per_intf = bytes_in_slice * slice_per_intf;
+ total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf;
eol_byte_num = total_bytes_per_intf % 3;
pkt_per_line = slice_per_intf / dsc->slice_count;
@@ -892,7 +886,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod
reg_ctrl |= reg;
reg_ctrl2 &= ~DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH__MASK;
- reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(bytes_in_slice);
+ reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(dsc->slice_chunk_size);
dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
@@ -915,6 +909,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
u32 va_end = va_start + mode->vdisplay;
u32 hdisplay = mode->hdisplay;
u32 wc;
+ int ret;
DBG("");
@@ -950,7 +945,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
/* we do the calculations for dsc parameters here so that
* panel can use these parameters
*/
- dsi_populate_dsc_params(dsc);
+ ret = dsi_populate_dsc_params(msm_host, dsc);
+ if (ret)
+ return;
/* Divide the display by 3 but keep back/font porch and
* pulse width same
@@ -1754,18 +1751,20 @@ static char bpg_offset[DSC_NUM_BUF_RANGES] = {
2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12
};
-static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
-{
- int mux_words_size;
- int groups_per_line, groups_total;
- int min_rate_buffer_size;
- int hrd_delay;
- int pre_num_extra_mux_bits, num_extra_mux_bits;
- int slice_bits;
- int target_bpp_x16;
- int data;
- int final_value, final_scale;
+static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc)
+{
int i;
+ u16 bpp = dsc->bits_per_pixel >> 4;
+
+ if (dsc->bits_per_pixel & 0xf) {
+ DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support fractional bits_per_pixel\n");
+ return -EINVAL;
+ }
+
+ if (dsc->bits_per_component != 8) {
+ DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support bits_per_component != 8 yet\n");
+ return -EOPNOTSUPP;
+ }
dsc->rc_model_size = 8192;
dsc->first_line_bpg_offset = 12;
@@ -1783,16 +1782,21 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
dsc->rc_range_params[i].range_min_qp = min_qp[i];
dsc->rc_range_params[i].range_max_qp = max_qp[i];
- dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i];
+ /*
+ * Range BPG Offset contains two's-complement signed values that fill
+ * 8 bits, yet the registers and DCS PPS field are only 6 bits wide.
+ */
+ dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i] & DSC_RANGE_BPG_OFFSET_MASK;
}
- dsc->initial_offset = 6144; /* Not bpp 12 */
- if (dsc->bits_per_pixel != 8)
+ dsc->initial_offset = 6144; /* Not bpp 12 */
+ if (bpp != 8)
dsc->initial_offset = 2048; /* bpp = 12 */
- mux_words_size = 48; /* bpc == 8/10 */
- if (dsc->bits_per_component == 12)
- mux_words_size = 64;
+ if (dsc->bits_per_component <= 10)
+ dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+ else
+ dsc->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
dsc->initial_xmit_delay = 512;
dsc->initial_scale_value = 32;
@@ -1804,63 +1808,8 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
dsc->flatness_max_qp = 12;
dsc->rc_quant_incr_limit0 = 11;
dsc->rc_quant_incr_limit1 = 11;
- dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
-
- /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of
- * params are calculated
- */
- groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3);
- dsc->slice_chunk_size = dsc->slice_width * dsc->bits_per_pixel / 8;
- if ((dsc->slice_width * dsc->bits_per_pixel) % 8)
- dsc->slice_chunk_size++;
- /* rbs-min */
- min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset +
- dsc->initial_xmit_delay * dsc->bits_per_pixel +
- groups_per_line * dsc->first_line_bpg_offset;
-
- hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->bits_per_pixel);
-
- dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
-
- dsc->initial_scale_value = 8 * dsc->rc_model_size /
- (dsc->rc_model_size - dsc->initial_offset);
-
- slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height;
-
- groups_total = groups_per_line * dsc->slice_height;
-
- data = dsc->first_line_bpg_offset * 2048;
-
- dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
-
- pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->bits_per_component + 4) - 2);
-
- num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
- ((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
-
- data = 2048 * (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits);
- dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
-
- /* bpp * 16 + 0.5 */
- data = dsc->bits_per_pixel * 16;
- data *= 2;
- data++;
- data /= 2;
- target_bpp_x16 = data;
-
- data = (dsc->initial_xmit_delay * target_bpp_x16) / 16;
- final_value = dsc->rc_model_size - data + num_extra_mux_bits;
- dsc->final_offset = final_value;
-
- final_scale = 8 * dsc->rc_model_size / (dsc->rc_model_size - final_value);
-
- data = (final_scale - 9) * (dsc->nfl_bpg_offset + dsc->slice_bpg_offset);
- dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
-
- dsc->scale_decrement_interval = groups_per_line / (dsc->initial_scale_value - 8);
-
- return 0;
+ return drm_dsc_compute_rc_parameters(dsc);
}
static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index 7fc0975cb869..ee6051367679 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -549,6 +549,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
{ .compatible = "qcom,dsi-phy-14nm",
.data = &dsi_phy_14nm_cfgs },
+ { .compatible = "qcom,dsi-phy-14nm-2290",
+ .data = &dsi_phy_14nm_2290_cfgs },
{ .compatible = "qcom,dsi-phy-14nm-660",
.data = &dsi_phy_14nm_660_cfgs },
{ .compatible = "qcom,dsi-phy-14nm-8953",
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index 60a99c6525b2..1096afedd616 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -50,6 +50,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
index 0f8f4ca46429..9f488adea7f5 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
@@ -1081,3 +1081,20 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs = {
.io_start = { 0x1a94400, 0x1a96400 },
.num_dsi_phy = 2,
};
+
+const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs = {
+ .has_phy_lane = true,
+ .regulator_data = dsi_phy_14nm_17mA_regulators,
+ .num_regulators = ARRAY_SIZE(dsi_phy_14nm_17mA_regulators),
+ .ops = {
+ .enable = dsi_14nm_phy_enable,
+ .disable = dsi_14nm_phy_disable,
+ .pll_init = dsi_pll_14nm_init,
+ .save_pll_state = dsi_14nm_pll_save_state,
+ .restore_pll_state = dsi_14nm_pll_restore_state,
+ },
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
+ .io_start = { 0x5e94400 },
+ .num_dsi_phy = 1,
+};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index f28fb21e3891..4d3fdc806bef 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -68,16 +68,17 @@ static void msm_hdmi_destroy(struct hdmi *hdmi)
destroy_workqueue(hdmi->workq);
msm_hdmi_hdcp_destroy(hdmi);
+ if (hdmi->i2c)
+ msm_hdmi_i2c_destroy(hdmi->i2c);
+}
+
+static void msm_hdmi_put_phy(struct hdmi *hdmi)
+{
if (hdmi->phy_dev) {
put_device(hdmi->phy_dev);
hdmi->phy = NULL;
hdmi->phy_dev = NULL;
}
-
- if (hdmi->i2c)
- msm_hdmi_i2c_destroy(hdmi->i2c);
-
- platform_set_drvdata(hdmi->pdev, NULL);
}
static int msm_hdmi_get_phy(struct hdmi *hdmi)
@@ -93,22 +94,18 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
}
phy_pdev = of_find_device_by_node(phy_node);
- if (phy_pdev)
- hdmi->phy = platform_get_drvdata(phy_pdev);
-
of_node_put(phy_node);
- if (!phy_pdev) {
- DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
- return -EPROBE_DEFER;
- }
+ if (!phy_pdev)
+ return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
+
+ hdmi->phy = platform_get_drvdata(phy_pdev);
if (!hdmi->phy) {
- DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
put_device(&phy_pdev->dev);
- return -EPROBE_DEFER;
+ return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
}
- hdmi->phy_dev = get_device(&phy_pdev->dev);
+ hdmi->phy_dev = &phy_pdev->dev;
return 0;
}
@@ -117,142 +114,10 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
* we are to EPROBE_DEFER we want to do it here, rather than later
* at modeset_init() time
*/
-static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
+static int msm_hdmi_init(struct hdmi *hdmi)
{
- struct hdmi_platform_config *config = pdev->dev.platform_data;
- struct hdmi *hdmi = NULL;
- struct resource *res;
- int i, ret;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi) {
- ret = -ENOMEM;
- goto fail;
- }
-
- hdmi->pdev = pdev;
- hdmi->config = config;
- spin_lock_init(&hdmi->reg_lock);
-
- ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge);
- if (ret && ret != -ENODEV)
- goto fail;
-
- hdmi->mmio = msm_ioremap(pdev, config->mmio_name);
- if (IS_ERR(hdmi->mmio)) {
- ret = PTR_ERR(hdmi->mmio);
- goto fail;
- }
-
- /* HDCP needs physical address of hdmi register */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- config->mmio_name);
- if (!res) {
- ret = -EINVAL;
- goto fail;
- }
- hdmi->mmio_phy_addr = res->start;
-
- hdmi->qfprom_mmio = msm_ioremap(pdev, config->qfprom_mmio_name);
- if (IS_ERR(hdmi->qfprom_mmio)) {
- DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n");
- hdmi->qfprom_mmio = NULL;
- }
-
- hdmi->hpd_regs = devm_kcalloc(&pdev->dev,
- config->hpd_reg_cnt,
- sizeof(hdmi->hpd_regs[0]),
- GFP_KERNEL);
- if (!hdmi->hpd_regs) {
- ret = -ENOMEM;
- goto fail;
- }
- for (i = 0; i < config->hpd_reg_cnt; i++)
- hdmi->hpd_regs[i].supply = config->hpd_reg_names[i];
-
- ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %d\n", ret);
- goto fail;
- }
-
- hdmi->pwr_regs = devm_kcalloc(&pdev->dev,
- config->pwr_reg_cnt,
- sizeof(hdmi->pwr_regs[0]),
- GFP_KERNEL);
- if (!hdmi->pwr_regs) {
- ret = -ENOMEM;
- goto fail;
- }
-
- for (i = 0; i < config->pwr_reg_cnt; i++)
- hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];
-
- ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret);
- goto fail;
- }
-
- hdmi->hpd_clks = devm_kcalloc(&pdev->dev,
- config->hpd_clk_cnt,
- sizeof(hdmi->hpd_clks[0]),
- GFP_KERNEL);
- if (!hdmi->hpd_clks) {
- ret = -ENOMEM;
- goto fail;
- }
- for (i = 0; i < config->hpd_clk_cnt; i++) {
- struct clk *clk;
-
- clk = msm_clk_get(pdev, config->hpd_clk_names[i]);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- DRM_DEV_ERROR(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
- config->hpd_clk_names[i], ret);
- goto fail;
- }
-
- hdmi->hpd_clks[i] = clk;
- }
-
- hdmi->pwr_clks = devm_kcalloc(&pdev->dev,
- config->pwr_clk_cnt,
- sizeof(hdmi->pwr_clks[0]),
- GFP_KERNEL);
- if (!hdmi->pwr_clks) {
- ret = -ENOMEM;
- goto fail;
- }
- for (i = 0; i < config->pwr_clk_cnt; i++) {
- struct clk *clk;
-
- clk = msm_clk_get(pdev, config->pwr_clk_names[i]);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- DRM_DEV_ERROR(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
- config->pwr_clk_names[i], ret);
- goto fail;
- }
-
- hdmi->pwr_clks[i] = clk;
- }
-
- hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
- /* This will catch e.g. -EPROBE_DEFER */
- if (IS_ERR(hdmi->hpd_gpiod)) {
- ret = PTR_ERR(hdmi->hpd_gpiod);
- DRM_DEV_ERROR(&pdev->dev, "failed to get hpd gpio: (%d)\n", ret);
- goto fail;
- }
-
- if (!hdmi->hpd_gpiod)
- DBG("failed to get HPD gpio");
-
- if (hdmi->hpd_gpiod)
- gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
-
- pm_runtime_enable(&pdev->dev);
+ struct platform_device *pdev = hdmi->pdev;
+ int ret;
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
@@ -264,25 +129,18 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
goto fail;
}
- ret = msm_hdmi_get_phy(hdmi);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n");
- goto fail;
- }
-
hdmi->hdcp_ctrl = msm_hdmi_hdcp_init(hdmi);
if (IS_ERR(hdmi->hdcp_ctrl)) {
dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");
hdmi->hdcp_ctrl = NULL;
}
- return hdmi;
+ return 0;
fail:
- if (hdmi)
- msm_hdmi_destroy(hdmi);
+ msm_hdmi_destroy(hdmi);
- return ERR_PTR(ret);
+ return ret;
}
/* Second part of initialization, the drm/kms level modeset_init,
@@ -297,7 +155,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
struct drm_device *dev, struct drm_encoder *encoder)
{
struct msm_drm_private *priv = dev->dev_private;
- struct platform_device *pdev = hdmi->pdev;
int ret;
if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
@@ -337,13 +194,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
drm_connector_attach_encoder(hdmi->connector, hdmi->encoder);
- hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
- if (!hdmi->irq) {
- ret = -EINVAL;
- DRM_DEV_ERROR(dev->dev, "failed to get irq\n");
- goto fail;
- }
-
ret = devm_request_irq(dev->dev, hdmi->irq,
msm_hdmi_irq, IRQF_TRIGGER_HIGH,
"hdmi_isr", hdmi);
@@ -363,8 +213,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
priv->bridges[priv->num_bridges++] = hdmi->bridge;
- platform_set_drvdata(pdev, hdmi);
-
return 0;
fail:
@@ -392,7 +240,7 @@ fail:
static const char *hpd_reg_names_8960[] = {"core-vdda"};
static const char *hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"};
-static struct hdmi_platform_config hdmi_tx_8960_config = {
+static const struct hdmi_platform_config hdmi_tx_8960_config = {
HDMI_CFG(hpd_reg, 8960),
HDMI_CFG(hpd_clk, 8960),
};
@@ -402,7 +250,7 @@ static const char *pwr_clk_names_8x74[] = {"extp", "alt_iface"};
static const char *hpd_clk_names_8x74[] = {"iface", "core", "mdp_core"};
static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
-static struct hdmi_platform_config hdmi_tx_8974_config = {
+static const struct hdmi_platform_config hdmi_tx_8974_config = {
HDMI_CFG(pwr_reg, 8x74),
HDMI_CFG(pwr_clk, 8x74),
HDMI_CFG(hpd_clk, 8x74),
@@ -517,26 +365,12 @@ static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev)
static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct msm_drm_private *priv = dev_get_drvdata(master);
- struct hdmi_platform_config *hdmi_cfg;
- struct hdmi *hdmi;
- struct device_node *of_node = dev->of_node;
+ struct hdmi *hdmi = dev_get_drvdata(dev);
int err;
- hdmi_cfg = (struct hdmi_platform_config *)
- of_device_get_match_data(dev);
- if (!hdmi_cfg) {
- DRM_DEV_ERROR(dev, "unknown hdmi_cfg: %pOFn\n", of_node);
- return -ENXIO;
- }
-
- hdmi_cfg->mmio_name = "core_physical";
- hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
-
- dev->platform_data = hdmi_cfg;
-
- hdmi = msm_hdmi_init(to_platform_device(dev));
- if (IS_ERR(hdmi))
- return PTR_ERR(hdmi);
+ err = msm_hdmi_init(hdmi);
+ if (err)
+ return err;
priv->hdmi = hdmi;
err = msm_hdmi_register_audio_driver(hdmi, dev);
@@ -569,12 +403,150 @@ static const struct component_ops msm_hdmi_ops = {
static int msm_hdmi_dev_probe(struct platform_device *pdev)
{
+ const struct hdmi_platform_config *config;
+ struct device *dev = &pdev->dev;
+ struct hdmi *hdmi;
+ struct resource *res;
+ int i, ret;
+
+ config = of_device_get_match_data(dev);
+ if (!config)
+ return -EINVAL;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->pdev = pdev;
+ hdmi->config = config;
+ spin_lock_init(&hdmi->reg_lock);
+
+ ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge);
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ hdmi->mmio = msm_ioremap(pdev, "core_physical");
+ if (IS_ERR(hdmi->mmio))
+ return PTR_ERR(hdmi->mmio);
+
+ /* HDCP needs physical address of hdmi register */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "core_physical");
+ if (!res)
+ return -EINVAL;
+ hdmi->mmio_phy_addr = res->start;
+
+ hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical");
+ if (IS_ERR(hdmi->qfprom_mmio)) {
+ DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n");
+ hdmi->qfprom_mmio = NULL;
+ }
+
+ hdmi->irq = platform_get_irq(pdev, 0);
+ if (hdmi->irq < 0)
+ return hdmi->irq;
+
+ hdmi->hpd_regs = devm_kcalloc(&pdev->dev,
+ config->hpd_reg_cnt,
+ sizeof(hdmi->hpd_regs[0]),
+ GFP_KERNEL);
+ if (!hdmi->hpd_regs)
+ return -ENOMEM;
+
+ for (i = 0; i < config->hpd_reg_cnt; i++)
+ hdmi->hpd_regs[i].supply = config->hpd_reg_names[i];
+
+ ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get hpd regulators\n");
+
+ hdmi->pwr_regs = devm_kcalloc(&pdev->dev,
+ config->pwr_reg_cnt,
+ sizeof(hdmi->pwr_regs[0]),
+ GFP_KERNEL);
+ if (!hdmi->pwr_regs)
+ return -ENOMEM;
+
+ for (i = 0; i < config->pwr_reg_cnt; i++)
+ hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];
+
+ ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get pwr regulators\n");
+
+ hdmi->hpd_clks = devm_kcalloc(&pdev->dev,
+ config->hpd_clk_cnt,
+ sizeof(hdmi->hpd_clks[0]),
+ GFP_KERNEL);
+ if (!hdmi->hpd_clks)
+ return -ENOMEM;
+
+ for (i = 0; i < config->hpd_clk_cnt; i++) {
+ struct clk *clk;
+
+ clk = msm_clk_get(pdev, config->hpd_clk_names[i]);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "failed to get hpd clk: %s\n",
+ config->hpd_clk_names[i]);
+
+ hdmi->hpd_clks[i] = clk;
+ }
+
+ hdmi->pwr_clks = devm_kcalloc(&pdev->dev,
+ config->pwr_clk_cnt,
+ sizeof(hdmi->pwr_clks[0]),
+ GFP_KERNEL);
+ if (!hdmi->pwr_clks)
+ return -ENOMEM;
+
+ for (i = 0; i < config->pwr_clk_cnt; i++) {
+ struct clk *clk;
+
+ clk = msm_clk_get(pdev, config->pwr_clk_names[i]);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "failed to get pwr clk: %s\n",
+ config->pwr_clk_names[i]);
+
+ hdmi->pwr_clks[i] = clk;
+ }
+
+ hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
+ /* This will catch e.g. -EPROBE_DEFER */
+ if (IS_ERR(hdmi->hpd_gpiod))
+ return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod),
+ "failed to get hpd gpio\n");
+
+ if (!hdmi->hpd_gpiod)
+ DBG("failed to get HPD gpio");
+
+ if (hdmi->hpd_gpiod)
+ gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
+
+ ret = msm_hdmi_get_phy(hdmi);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n");
+ return ret;
+ }
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, hdmi);
+
return component_add(&pdev->dev, &msm_hdmi_ops);
}
static int msm_hdmi_dev_remove(struct platform_device *pdev)
{
+ struct hdmi *hdmi = dev_get_drvdata(&pdev->dev);
+
component_del(&pdev->dev, &msm_hdmi_ops);
+
+ msm_hdmi_put_phy(hdmi);
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 04a74381aaf7..e8dbee50637f 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -86,9 +86,6 @@ struct hdmi {
/* platform config data (ie. from DT, or pdata) */
struct hdmi_platform_config {
- const char *mmio_name;
- const char *qfprom_mmio_name;
-
/* regulators that need to be on for hpd: */
const char **hpd_reg_names;
int hpd_reg_cnt;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 105b5b48e828..8b0b0ac74a6f 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -277,7 +277,6 @@ static int msm_drm_uninit(struct device *dev)
struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev)
{
- struct iommu_domain *domain;
struct msm_gem_address_space *aspace;
struct msm_mmu *mmu;
struct device *mdp_dev = dev->dev;
@@ -293,22 +292,21 @@ struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev)
else
iommu_dev = mdss_dev;
- domain = iommu_domain_alloc(iommu_dev->bus);
- if (!domain) {
+ mmu = msm_iommu_new(iommu_dev, 0);
+ if (IS_ERR(mmu))
+ return ERR_CAST(mmu);
+
+ if (!mmu) {
drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n");
return NULL;
}
- mmu = msm_iommu_new(iommu_dev, domain);
- if (IS_ERR(mmu)) {
- iommu_domain_free(domain);
- return ERR_CAST(mmu);
- }
-
aspace = msm_gem_address_space_create(mmu, "mdp_kms",
0x1000, 0x100000000 - 0x1000);
- if (IS_ERR(aspace))
+ if (IS_ERR(aspace)) {
+ dev_err(mdp_dev, "aspace create, error %pe\n", aspace);
mmu->funcs->destroy(mmu);
+ }
return aspace;
}
@@ -420,7 +418,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
priv->dev = ddev;
priv->wq = alloc_ordered_workqueue("msm", 0);
- priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD;
INIT_LIST_HEAD(&priv->objects);
mutex_init(&priv->obj_lock);
@@ -819,6 +816,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
case MSM_INFO_GET_OFFSET:
case MSM_INFO_GET_IOVA:
case MSM_INFO_SET_IOVA:
+ case MSM_INFO_GET_FLAGS:
/* value returned as immediate, not pointer, so len==0: */
if (args->len)
return -EINVAL;
@@ -846,6 +844,15 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
case MSM_INFO_SET_IOVA:
ret = msm_ioctl_gem_info_set_iova(dev, file, obj, args->value);
break;
+ case MSM_INFO_GET_FLAGS:
+ if (obj->import_attach) {
+ ret = -EINVAL;
+ break;
+ }
+ /* Hide internal kernel-only flags: */
+ args->value = to_msm_bo(obj)->flags & MSM_BO_FLAGS;
+ ret = 0;
+ break;
case MSM_INFO_SET_NAME:
/* length check should leave room for terminating null: */
if (args->len >= sizeof(msm_obj->name)) {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b2ea262296a4..d4e0ef608950 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -224,7 +224,13 @@ struct msm_drm_private {
struct drm_atomic_state *pm_state;
- /* For hang detection, in ms */
+ /**
+ * hangcheck_period: For hang detection, in ms
+ *
+ * Note that in practice, a submit/job will get at least two hangcheck
+ * periods, due to checking for progress being implemented as simply
+ * "have the CP position registers changed since last time?"
+ */
unsigned int hangcheck_period;
/**
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 46168eccfac4..31e1e30cb52a 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -93,7 +93,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
goto fail;
}
- fbi = drm_fb_helper_alloc_fbi(helper);
+ fbi = drm_fb_helper_alloc_info(helper);
if (IS_ERR(fbi)) {
DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n");
ret = PTR_ERR(fbi);
@@ -109,8 +109,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
drm_fb_helper_fill_info(fbi, helper, sizes);
- dev->mode_config.fb_base = paddr;
-
fbi->screen_base = msm_gem_get_vaddr(bo);
if (IS_ERR(fbi->screen_base)) {
ret = PTR_ERR(fbi->screen_base);
@@ -184,7 +182,7 @@ void msm_fbdev_free(struct drm_device *dev)
DBG();
- drm_fb_helper_unregister_fbi(helper);
+ drm_fb_helper_unregister_info(helper);
drm_fb_helper_fini(helper);
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c
index 1de14e67f96b..051bdbc093cf 100644
--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c
+++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c
@@ -15,7 +15,7 @@
/* Default disabled for now until it has some more testing on the different
* iommu combinations that can be paired with the driver:
*/
-static bool enable_eviction = false;
+static bool enable_eviction = true;
MODULE_PARM_DESC(enable_eviction, "Enable swappable GEM buffers");
module_param(enable_eviction, bool, 0600);
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 45a3e5cadc7d..73a2ca122c57 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -334,8 +334,7 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
if (ret)
return ret;
- /* exclusive fences must be ordered */
- if (no_implicit && !write)
+ if (no_implicit)
continue;
ret = drm_sched_job_add_implicit_dependencies(&submit->base,
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 021f4e29b613..30ed45af76ad 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -492,6 +492,21 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
round_jiffies_up(jiffies + msecs_to_jiffies(priv->hangcheck_period)));
}
+static bool made_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
+{
+ if (ring->hangcheck_progress_retries >= DRM_MSM_HANGCHECK_PROGRESS_RETRIES)
+ return false;
+
+ if (!gpu->funcs->progress)
+ return false;
+
+ if (!gpu->funcs->progress(gpu, ring))
+ return false;
+
+ ring->hangcheck_progress_retries++;
+ return true;
+}
+
static void hangcheck_handler(struct timer_list *t)
{
struct msm_gpu *gpu = from_timer(gpu, t, hangcheck_timer);
@@ -502,9 +517,12 @@ static void hangcheck_handler(struct timer_list *t)
if (fence != ring->hangcheck_fence) {
/* some progress has been made.. ya! */
ring->hangcheck_fence = fence;
- } else if (fence_before(fence, ring->fctx->last_fence)) {
+ ring->hangcheck_progress_retries = 0;
+ } else if (fence_before(fence, ring->fctx->last_fence) &&
+ !made_progress(gpu, ring)) {
/* no progress and not done.. hung! */
ring->hangcheck_fence = fence;
+ ring->hangcheck_progress_retries = 0;
DRM_DEV_ERROR(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n",
gpu->name, ring->id);
DRM_DEV_ERROR(dev->dev, "%s: completed fence: %u\n",
@@ -830,6 +848,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs,
const char *name, struct msm_gpu_config *config)
{
+ struct msm_drm_private *priv = drm->dev_private;
int i, ret, nr_rings = config->nr_rings;
void *memptrs;
uint64_t memptrs_iova;
@@ -857,6 +876,16 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
kthread_init_work(&gpu->recover_work, recover_worker);
kthread_init_work(&gpu->fault_work, fault_worker);
+ priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD;
+
+ /*
+ * If progress detection is supported, halve the hangcheck timer
+ * duration, as it takes two iterations of the hangcheck handler
+ * to detect a hang.
+ */
+ if (funcs->progress)
+ priv->hangcheck_period /= 2;
+
timer_setup(&gpu->hangcheck_timer, hangcheck_handler, 0);
spin_lock_init(&gpu->perf_lock);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 58a72e6b1400..651786bc55e5 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -78,6 +78,15 @@ struct msm_gpu_funcs {
struct msm_gem_address_space *(*create_private_address_space)
(struct msm_gpu *gpu);
uint32_t (*get_rptr)(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
+
+ /**
+ * progress: Has the GPU made progress?
+ *
+ * Return true if GPU position in cmdstream has advanced (or changed)
+ * since the last call. To avoid false negatives, this should account
+ * for cmdstream that is buffered in this FIFO upstream of the CP fw.
+ */
+ bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
};
/* Additional state for iommu faults: */
@@ -237,6 +246,7 @@ struct msm_gpu {
#define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */
#define DRM_MSM_HANGCHECK_DEFAULT_PERIOD 500 /* in ms */
+#define DRM_MSM_HANGCHECK_PROGRESS_RETRIES 3
struct timer_list hangcheck_timer;
/* Fault info for most recent iova fault: */
@@ -540,7 +550,7 @@ static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or)
msm_rmw(gpu->mmio + (reg << 2), mask, or);
}
-static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi)
+static inline u64 gpu_read64(struct msm_gpu *gpu, u32 reg)
{
u64 val;
@@ -558,17 +568,17 @@ static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi)
* when the lo is read, so make sure to read the lo first to trigger
* that
*/
- val = (u64) msm_readl(gpu->mmio + (lo << 2));
- val |= ((u64) msm_readl(gpu->mmio + (hi << 2)) << 32);
+ val = (u64) msm_readl(gpu->mmio + (reg << 2));
+ val |= ((u64) msm_readl(gpu->mmio + ((reg + 1) << 2)) << 32);
return val;
}
-static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
+static inline void gpu_write64(struct msm_gpu *gpu, u32 reg, u64 val)
{
/* Why not a writeq here? Read the screed above */
- msm_writel(lower_32_bits(val), gpu->mmio + (lo << 2));
- msm_writel(upper_32_bits(val), gpu->mmio + (hi << 2));
+ msm_writel(lower_32_bits(val), gpu->mmio + (reg << 2));
+ msm_writel(upper_32_bits(val), gpu->mmio + ((reg + 1) << 2));
}
int msm_gpu_pm_suspend(struct msm_gpu *gpu);
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 5577cea7c009..c2507582ecf3 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -186,6 +186,13 @@ int msm_iommu_pagetable_params(struct msm_mmu *mmu,
return 0;
}
+struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu)
+{
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
+
+ return &iommu->domain->geometry;
+}
+
static const struct msm_mmu_funcs pagetable_funcs = {
.map = msm_iommu_pagetable_map,
.unmap = msm_iommu_pagetable_unmap,
@@ -367,17 +374,23 @@ static const struct msm_mmu_funcs funcs = {
.resume_translation = msm_iommu_resume_translation,
};
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
+struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks)
{
+ struct iommu_domain *domain;
struct msm_iommu *iommu;
int ret;
+ domain = iommu_domain_alloc(dev->bus);
if (!domain)
- return ERR_PTR(-ENODEV);
+ return NULL;
+
+ iommu_set_pgtable_quirks(domain, quirks);
iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
- if (!iommu)
+ if (!iommu) {
+ iommu_domain_free(domain);
return ERR_PTR(-ENOMEM);
+ }
iommu->domain = domain;
msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU);
@@ -386,6 +399,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
ret = iommu_attach_device(iommu->domain, dev);
if (ret) {
+ iommu_domain_free(domain);
kfree(iommu);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
index e13c5c12b775..86b28add1fff 100644
--- a/drivers/gpu/drm/msm/msm_mdss.c
+++ b/drivers/gpu/drm/msm/msm_mdss.c
@@ -22,6 +22,7 @@
#define HW_REV 0x0
#define HW_INTR_STATUS 0x0010
+#define UBWC_DEC_HW_VERSION 0x58
#define UBWC_STATIC 0x144
#define UBWC_CTRL_2 0x150
#define UBWC_PREDICTION_MODE 0x154
@@ -174,9 +175,63 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
return 0;
}
+#define UBWC_1_0 0x10000000
+#define UBWC_2_0 0x20000000
+#define UBWC_3_0 0x30000000
+#define UBWC_4_0 0x40000000
+
+static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss,
+ u32 ubwc_static)
+{
+ writel_relaxed(ubwc_static, msm_mdss->mmio + UBWC_STATIC);
+}
+
+static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss,
+ unsigned int ubwc_version,
+ u32 ubwc_swizzle,
+ u32 highest_bank_bit,
+ u32 macrotile_mode)
+{
+ u32 value = (ubwc_swizzle & 0x1) |
+ (highest_bank_bit & 0x3) << 4 |
+ (macrotile_mode & 0x1) << 12;
+
+ if (ubwc_version == UBWC_3_0)
+ value |= BIT(10);
+
+ if (ubwc_version == UBWC_1_0)
+ value |= BIT(8);
+
+ writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
+}
+
+static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss,
+ unsigned int ubwc_version,
+ u32 ubwc_swizzle,
+ u32 ubwc_static,
+ u32 highest_bank_bit,
+ u32 macrotile_mode)
+{
+ u32 value = (ubwc_swizzle & 0x7) |
+ (ubwc_static & 0x1) << 3 |
+ (highest_bank_bit & 0x7) << 4 |
+ (macrotile_mode & 0x1) << 12;
+
+ writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
+
+ if (ubwc_version == UBWC_3_0) {
+ writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2);
+ writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE);
+ } else {
+ writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2);
+ writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE);
+ }
+}
+
static int msm_mdss_enable(struct msm_mdss *msm_mdss)
{
int ret;
+ u32 hw_rev;
/*
* Several components have AXI clocks that can only be turned on if
@@ -198,26 +253,39 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
if (msm_mdss->is_mdp5)
return 0;
+ hw_rev = readl_relaxed(msm_mdss->mmio + HW_REV);
+ dev_dbg(msm_mdss->dev, "HW_REV: 0x%x\n", hw_rev);
+ dev_dbg(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n",
+ readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION));
+
/*
* ubwc config is part of the "mdss" region which is not accessible
* from the rest of the driver. hardcode known configurations here
+ *
+ * Decoder version can be read from the UBWC_DEC_HW_VERSION reg,
+ * UBWC_n and the rest of params comes from hw_catalog.
+ * Unforunately this driver can not access hw catalog, so we have to
+ * hardcode them here.
*/
- switch (readl_relaxed(msm_mdss->mmio + HW_REV)) {
+ switch (hw_rev) {
case DPU_HW_VER_500:
case DPU_HW_VER_501:
- writel_relaxed(0x420, msm_mdss->mmio + UBWC_STATIC);
+ msm_mdss_setup_ubwc_dec_30(msm_mdss, UBWC_3_0, 0, 2, 0);
break;
case DPU_HW_VER_600:
- /* TODO: 0x102e for LP_DDR4 */
- writel_relaxed(0x103e, msm_mdss->mmio + UBWC_STATIC);
- writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2);
- writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE);
+ /* TODO: highest_bank_bit = 2 for LP_DDR4 */
+ msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1);
break;
case DPU_HW_VER_620:
- writel_relaxed(0x1e, msm_mdss->mmio + UBWC_STATIC);
+ /* UBWC_2_0 */
+ msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x1e);
+ break;
+ case DPU_HW_VER_630:
+ /* UBWC_2_0 */
+ msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x11f);
break;
case DPU_HW_VER_720:
- writel_relaxed(0x101e, msm_mdss->mmio + UBWC_STATIC);
+ msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_3_0, 6, 1, 1, 1);
break;
}
@@ -445,6 +513,7 @@ static const struct of_device_id mdss_dt_match[] = {
{ .compatible = "qcom,sc7180-mdss" },
{ .compatible = "qcom,sc7280-mdss" },
{ .compatible = "qcom,sc8180x-mdss" },
+ { .compatible = "qcom,sm6115-mdss" },
{ .compatible = "qcom,sm8150-mdss" },
{ .compatible = "qcom,sm8250-mdss" },
{}
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index de158e1bf765..74cd81e701ff 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -40,7 +40,7 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
mmu->type = type;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
+struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks);
struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu);
static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
@@ -58,5 +58,6 @@ void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr,
int *asid);
+struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu);
#endif /* __MSM_MMU_H__ */
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h
index 2a5045abe46e..698b333abccd 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.h
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.h
@@ -35,6 +35,11 @@ struct msm_rbmemptrs {
volatile u64 ttbr0;
};
+struct msm_cp_state {
+ uint64_t ib1_base, ib2_base;
+ uint32_t ib1_rem, ib2_rem;
+};
+
struct msm_ringbuffer {
struct msm_gpu *gpu;
int id;
@@ -64,6 +69,29 @@ struct msm_ringbuffer {
uint64_t memptrs_iova;
struct msm_fence_context *fctx;
+ /**
+ * hangcheck_progress_retries:
+ *
+ * The number of extra hangcheck duration cycles that we have given
+ * due to it appearing that the GPU is making forward progress.
+ *
+ * For GPU generations which support progress detection (see.
+ * msm_gpu_funcs::progress()), if the GPU appears to be making progress
+ * (ie. the CP has advanced in the command stream, we'll allow up to
+ * DRM_MSM_HANGCHECK_PROGRESS_RETRIES expirations of the hangcheck timer
+ * before killing the job. But to detect progress we need two sample
+ * points, so the duration of the hangcheck timer is halved. In other
+ * words we'll let the submit run for up to:
+ *
+ * (DRM_MSM_HANGCHECK_DEFAULT_PERIOD / 2) * (DRM_MSM_HANGCHECK_PROGRESS_RETRIES + 1)
+ */
+ int hangcheck_progress_retries;
+
+ /**
+ * last_cp_state: The state of the CP at the last call to gpu->progress()
+ */
+ struct msm_cp_state last_cp_state;
+
/*
* preempt_lock protects preemption and serializes wptr updates against
* preemption. Can be aquired from irq context.
diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c
index 075002ed6fb0..cc2ceb301b96 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_drv.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode_config.h>
diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c
index b1092aab1423..262bc43b1079 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_kms.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c
@@ -5,6 +5,7 @@
* This code is based on drivers/gpu/drm/mxsfb/mxsfb*
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -15,6 +16,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_color_mgmt.h>
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_dma_helper.h>
@@ -31,13 +33,126 @@
/* -----------------------------------------------------------------------------
* CRTC
*/
+
+/*
+ * For conversion from YCbCr to RGB, the CSC operates as follows:
+ *
+ * |R| |A1 A2 A3| |Y + D1|
+ * |G| = |B1 B2 B3| * |Cb + D2|
+ * |B| |C1 C2 C3| |Cr + D3|
+ *
+ * The A, B and C coefficients are expressed as Q2.8 fixed point values, and
+ * the D coefficients as Q0.8. Despite the reference manual stating the
+ * opposite, the D1, D2 and D3 offset values are added to Y, Cb and Cr, not
+ * subtracted. They must thus be programmed with negative values.
+ */
+static const u32 lcdif_yuv2rgb_coeffs[3][2][6] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ /*
+ * BT.601 limited range:
+ *
+ * |R| |1.1644 0.0000 1.5960| |Y - 16 |
+ * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
+ * |B| |1.1644 2.0172 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x199) | CSC0_COEF1_B1(0x12a),
+ CSC0_COEF2_B2(0x79c) | CSC0_COEF2_B3(0x730),
+ CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x204),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ [DRM_COLOR_YCBCR_FULL_RANGE] = {
+ /*
+ * BT.601 full range:
+ *
+ * |R| |1.0000 0.0000 1.4020| |Y - 0 |
+ * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
+ * |B| |1.0000 1.7720 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x167) | CSC0_COEF1_B1(0x100),
+ CSC0_COEF2_B2(0x7a8) | CSC0_COEF2_B3(0x749),
+ CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1c6),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ /*
+ * Rec.709 limited range:
+ *
+ * |R| |1.1644 0.0000 1.7927| |Y - 16 |
+ * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
+ * |B| |1.1644 2.1124 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x1cb) | CSC0_COEF1_B1(0x12a),
+ CSC0_COEF2_B2(0x7c9) | CSC0_COEF2_B3(0x778),
+ CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x21d),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ [DRM_COLOR_YCBCR_FULL_RANGE] = {
+ /*
+ * Rec.709 full range:
+ *
+ * |R| |1.0000 0.0000 1.5748| |Y - 0 |
+ * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
+ * |B| |1.0000 1.8556 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x193) | CSC0_COEF1_B1(0x100),
+ CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x788),
+ CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1db),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ /*
+ * BT.2020 limited range:
+ *
+ * |R| |1.1644 0.0000 1.6787| |Y - 16 |
+ * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
+ * |B| |1.1644 2.1418 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x1ae) | CSC0_COEF1_B1(0x12a),
+ CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x759),
+ CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x224),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ [DRM_COLOR_YCBCR_FULL_RANGE] = {
+ /*
+ * BT.2020 full range:
+ *
+ * |R| |1.0000 0.0000 1.4746| |Y - 0 |
+ * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
+ * |B| |1.0000 1.8814 0.0000| |Cr - 128|
+ */
+ CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
+ CSC0_COEF1_A3(0x179) | CSC0_COEF1_B1(0x100),
+ CSC0_COEF2_B2(0x7d6) | CSC0_COEF2_B3(0x76e),
+ CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1e2),
+ CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
+ CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
+ },
+ },
+};
+
static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
+ struct drm_plane_state *plane_state,
const u32 bus_format)
{
struct drm_device *drm = lcdif->drm;
- const u32 format = lcdif->crtc.primary->state->fb->format->format;
-
- writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL);
+ const u32 format = plane_state->fb->format->format;
+ bool in_yuv = false;
+ bool out_yuv = false;
switch (bus_format) {
case MEDIA_BUS_FMT_RGB565_1X16:
@@ -51,24 +166,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
case MEDIA_BUS_FMT_UYVY8_1X16:
writel(DISP_PARA_LINE_PATTERN_UYVY_H,
lcdif->base + LCDC_V8_DISP_PARA);
-
- /* CSC: BT.601 Full Range RGB to YCbCr coefficients. */
- writel(CSC0_COEF0_A2(0x096) | CSC0_COEF0_A1(0x04c),
- lcdif->base + LCDC_V8_CSC0_COEF0);
- writel(CSC0_COEF1_B1(0x7d5) | CSC0_COEF1_A3(0x01d),
- lcdif->base + LCDC_V8_CSC0_COEF1);
- writel(CSC0_COEF2_B3(0x080) | CSC0_COEF2_B2(0x7ac),
- lcdif->base + LCDC_V8_CSC0_COEF2);
- writel(CSC0_COEF3_C2(0x795) | CSC0_COEF3_C1(0x080),
- lcdif->base + LCDC_V8_CSC0_COEF3);
- writel(CSC0_COEF4_D1(0x000) | CSC0_COEF4_C3(0x7ec),
- lcdif->base + LCDC_V8_CSC0_COEF4);
- writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080),
- lcdif->base + LCDC_V8_CSC0_COEF5);
-
- writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr,
- lcdif->base + LCDC_V8_CSC0_CTRL);
-
+ out_yuv = true;
break;
default:
dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format);
@@ -76,6 +174,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
}
switch (format) {
+ /* RGB Formats */
case DRM_FORMAT_RGB565:
writel(CTRLDESCL0_5_BPP_16_RGB565,
lcdif->base + LCDC_V8_CTRLDESCL0_5);
@@ -100,10 +199,84 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
writel(CTRLDESCL0_5_BPP_32_ARGB8888,
lcdif->base + LCDC_V8_CTRLDESCL0_5);
break;
+
+ /* YUV Formats */
+ case DRM_FORMAT_YUYV:
+ writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_VY2UY1,
+ lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ in_yuv = true;
+ break;
+ case DRM_FORMAT_YVYU:
+ writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_UY2VY1,
+ lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ in_yuv = true;
+ break;
+ case DRM_FORMAT_UYVY:
+ writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2VY1U,
+ lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ in_yuv = true;
+ break;
+ case DRM_FORMAT_VYUY:
+ writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2UY1V,
+ lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ in_yuv = true;
+ break;
+
default:
dev_err(drm->dev, "Unknown pixel format 0x%x\n", format);
break;
}
+
+ /*
+ * The CSC differentiates between "YCbCr" and "YUV", but the reference
+ * manual doesn't detail how they differ. Experiments showed that the
+ * luminance value is unaffected, only the calculations involving chroma
+ * values differ. The YCbCr mode behaves as expected, with chroma values
+ * being offset by 128. The YUV mode isn't fully understood.
+ */
+ if (!in_yuv && out_yuv) {
+ /* RGB -> YCbCr */
+ writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr,
+ lcdif->base + LCDC_V8_CSC0_CTRL);
+
+ /*
+ * CSC: BT.601 Limited Range RGB to YCbCr coefficients.
+ *
+ * |Y | | 0.2568 0.5041 0.0979| |R| |16 |
+ * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128|
+ * |Cr| | 0.4392 0.4392 -0.3678| |B| |128|
+ */
+ writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041),
+ lcdif->base + LCDC_V8_CSC0_COEF0);
+ writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019),
+ lcdif->base + LCDC_V8_CSC0_COEF1);
+ writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6),
+ lcdif->base + LCDC_V8_CSC0_COEF2);
+ writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070),
+ lcdif->base + LCDC_V8_CSC0_COEF3);
+ writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee),
+ lcdif->base + LCDC_V8_CSC0_COEF4);
+ writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080),
+ lcdif->base + LCDC_V8_CSC0_COEF5);
+ } else if (in_yuv && !out_yuv) {
+ /* YCbCr -> RGB */
+ const u32 *coeffs =
+ lcdif_yuv2rgb_coeffs[plane_state->color_encoding]
+ [plane_state->color_range];
+
+ writel(CSC0_CTRL_CSC_MODE_YCbCr2RGB,
+ lcdif->base + LCDC_V8_CSC0_CTRL);
+
+ writel(coeffs[0], lcdif->base + LCDC_V8_CSC0_COEF0);
+ writel(coeffs[1], lcdif->base + LCDC_V8_CSC0_COEF1);
+ writel(coeffs[2], lcdif->base + LCDC_V8_CSC0_COEF2);
+ writel(coeffs[3], lcdif->base + LCDC_V8_CSC0_COEF3);
+ writel(coeffs[4], lcdif->base + LCDC_V8_CSC0_COEF4);
+ writel(coeffs[5], lcdif->base + LCDC_V8_CSC0_COEF5);
+ } else {
+ /* RGB -> RGB, YCbCr -> YCbCr: bypass colorspace converter. */
+ writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL);
+ }
}
static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags)
@@ -142,14 +315,36 @@ static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags)
CTRLDESCL0_1_WIDTH(m->hdisplay),
lcdif->base + LCDC_V8_CTRLDESCL0_1);
- writel(CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]),
- lcdif->base + LCDC_V8_CTRLDESCL0_3);
+ /*
+ * Undocumented P_SIZE and T_SIZE register but those written in the
+ * downstream kernel those registers control the AXI burst size. As of
+ * now there are two known values:
+ * 1 - 128Byte
+ * 2 - 256Byte
+ * Downstream set it to 256B burst size to improve the memory
+ * efficiency so set it here too.
+ */
+ ctrl = CTRLDESCL0_3_P_SIZE(2) | CTRLDESCL0_3_T_SIZE(2) |
+ CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]);
+ writel(ctrl, lcdif->base + LCDC_V8_CTRLDESCL0_3);
}
static void lcdif_enable_controller(struct lcdif_drm_private *lcdif)
{
u32 reg;
+ /* Set FIFO Panic watermarks, low 1/3, high 2/3 . */
+ writel(FIELD_PREP(PANIC0_THRES_LOW_MASK, 1 * PANIC0_THRES_MAX / 3) |
+ FIELD_PREP(PANIC0_THRES_HIGH_MASK, 2 * PANIC0_THRES_MAX / 3),
+ lcdif->base + LCDC_V8_PANIC0_THRES);
+
+ /*
+ * Enable FIFO Panic, this does not generate interrupt, but
+ * boosts NoC priority based on FIFO Panic watermarks.
+ */
+ writel(INT_ENABLE_D1_PLANE_PANIC_EN,
+ lcdif->base + LCDC_V8_INT_ENABLE_D1);
+
reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
reg |= DISP_PARA_DISP_ON;
writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
@@ -177,6 +372,9 @@ static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)
reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
reg &= ~DISP_PARA_DISP_ON;
writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
+
+ /* Disable FIFO Panic NoC priority booster. */
+ writel(0, lcdif->base + LCDC_V8_INT_ENABLE_D1);
}
static void lcdif_reset_block(struct lcdif_drm_private *lcdif)
@@ -188,6 +386,7 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif)
}
static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif,
+ struct drm_plane_state *plane_state,
struct drm_bridge_state *bridge_state,
const u32 bus_format)
{
@@ -210,7 +409,7 @@ static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif,
/* Mandatory eLCDIF reset as per the Reference Manual */
lcdif_reset_block(lcdif);
- lcdif_set_formats(lcdif, bus_format);
+ lcdif_set_formats(lcdif, plane_state, bus_format);
lcdif_set_mode(lcdif, bus_flags);
}
@@ -293,7 +492,7 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc,
pm_runtime_get_sync(drm->dev);
- lcdif_crtc_mode_set_nofb(lcdif, bridge_state, bus_format);
+ lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format);
/* Write cur_buf as well to avoid an initial corrupt frame */
paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0);
@@ -437,12 +636,19 @@ static const struct drm_plane_funcs lcdif_plane_funcs = {
};
static const u32 lcdif_primary_plane_formats[] = {
+ /* RGB */
DRM_FORMAT_RGB565,
DRM_FORMAT_RGB888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_XRGB4444,
DRM_FORMAT_XRGB8888,
+
+ /* Packed YCbCr */
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
};
static const u64 lcdif_modifiers[] = {
@@ -456,6 +662,11 @@ static const u64 lcdif_modifiers[] = {
int lcdif_kms_init(struct lcdif_drm_private *lcdif)
{
+ const u32 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+ BIT(DRM_COLOR_YCBCR_BT2020);
+ const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE);
struct drm_encoder *encoder = &lcdif->encoder;
struct drm_crtc *crtc = &lcdif->crtc;
int ret;
@@ -471,6 +682,14 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif)
if (ret)
return ret;
+ ret = drm_plane_create_color_properties(&lcdif->planes.primary,
+ supported_encodings,
+ supported_ranges,
+ DRM_COLOR_YCBCR_BT601,
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if (ret)
+ return ret;
+
drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs);
ret = drm_crtc_init_with_planes(lcdif->drm, crtc,
&lcdif->planes.primary, NULL,
diff --git a/drivers/gpu/drm/mxsfb/lcdif_regs.h b/drivers/gpu/drm/mxsfb/lcdif_regs.h
index c70220651e3a..c55dfb236c1d 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_regs.h
+++ b/drivers/gpu/drm/mxsfb/lcdif_regs.h
@@ -130,7 +130,7 @@
#define CTRL_FETCH_START_OPTION_BPV BIT(9)
#define CTRL_FETCH_START_OPTION_RESV GENMASK(9, 8)
#define CTRL_FETCH_START_OPTION_MASK GENMASK(9, 8)
-#define CTRL_NEG BIT(4)
+#define CTRL_NEG BIT(4)
#define CTRL_INV_PXCK BIT(3)
#define CTRL_INV_DE BIT(2)
#define CTRL_INV_VS BIT(1)
@@ -138,9 +138,9 @@
#define DISP_PARA_DISP_ON BIT(31)
#define DISP_PARA_SWAP_EN BIT(30)
-#define DISP_PARA_LINE_PATTERN_UYVY_H (GENMASK(29, 28) | BIT(26))
-#define DISP_PARA_LINE_PATTERN_RGB565 GENMASK(28, 26)
-#define DISP_PARA_LINE_PATTERN_RGB888 0
+#define DISP_PARA_LINE_PATTERN_UYVY_H (0xd << 26)
+#define DISP_PARA_LINE_PATTERN_RGB565 (0x7 << 26)
+#define DISP_PARA_LINE_PATTERN_RGB888 (0x0 << 26)
#define DISP_PARA_LINE_PATTERN_MASK GENMASK(29, 26)
#define DISP_PARA_DISP_MODE_MASK GENMASK(25, 24)
#define DISP_PARA_BGND_R_MASK GENMASK(23, 16)
@@ -186,10 +186,14 @@
#define INT_ENABLE_D1_PLANE_PANIC_EN BIT(0)
#define CTRLDESCL0_1_HEIGHT(n) (((n) & 0xffff) << 16)
-#define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16)
+#define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16)
#define CTRLDESCL0_1_WIDTH(n) ((n) & 0xffff)
#define CTRLDESCL0_1_WIDTH_MASK GENMASK(15, 0)
+#define CTRLDESCL0_3_P_SIZE(n) (((n) << 20) & CTRLDESCL0_3_P_SIZE_MASK)
+#define CTRLDESCL0_3_P_SIZE_MASK GENMASK(22, 20)
+#define CTRLDESCL0_3_T_SIZE(n) (((n) << 16) & CTRLDESCL0_3_T_SIZE_MASK)
+#define CTRLDESCL0_3_T_SIZE_MASK GENMASK(17, 16)
#define CTRLDESCL0_3_PITCH(n) ((n) & 0xffff)
#define CTRLDESCL0_3_PITCH_MASK GENMASK(15, 0)
@@ -198,21 +202,24 @@
#define CTRLDESCL0_5_EN BIT(31)
#define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30)
-#define CTRLDESCL0_5_BPP_16_RGB565 BIT(26)
-#define CTRLDESCL0_5_BPP_16_ARGB1555 (BIT(26) | BIT(24))
-#define CTRLDESCL0_5_BPP_16_ARGB4444 (BIT(26) | BIT(25))
-#define CTRLDESCL0_5_BPP_YCbCr422 (BIT(26) | BIT(25) | BIT(24))
-#define CTRLDESCL0_5_BPP_24_RGB888 BIT(27)
-#define CTRLDESCL0_5_BPP_32_ARGB8888 (BIT(27) | BIT(24))
-#define CTRLDESCL0_5_BPP_32_ABGR8888 (BIT(27) | BIT(25))
+#define CTRLDESCL0_5_BPP_16_RGB565 (0x4 << 24)
+#define CTRLDESCL0_5_BPP_16_ARGB1555 (0x5 << 24)
+#define CTRLDESCL0_5_BPP_16_ARGB4444 (0x6 << 24)
+#define CTRLDESCL0_5_BPP_YCbCr422 (0x7 << 24)
+#define CTRLDESCL0_5_BPP_24_RGB888 (0x8 << 24)
+#define CTRLDESCL0_5_BPP_32_ARGB8888 (0x9 << 24)
+#define CTRLDESCL0_5_BPP_32_ABGR8888 (0xa << 24)
#define CTRLDESCL0_5_BPP_MASK GENMASK(27, 24)
-#define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U 0
-#define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V BIT(14)
-#define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 BIT(15)
-#define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (BIT(15) | BIT(14))
+#define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U (0x0 << 14)
+#define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V (0x1 << 14)
+#define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 (0x2 << 14)
+#define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (0x3 << 14)
#define CTRLDESCL0_5_YUV_FORMAT_MASK GENMASK(15, 14)
-#define CSC0_CTRL_CSC_MODE_RGB2YCbCr GENMASK(2, 1)
+#define CSC0_CTRL_CSC_MODE_YUV2RGB (0x0 << 1)
+#define CSC0_CTRL_CSC_MODE_YCbCr2RGB (0x1 << 1)
+#define CSC0_CTRL_CSC_MODE_RGB2YUV (0x2 << 1)
+#define CSC0_CTRL_CSC_MODE_RGB2YCbCr (0x3 << 1)
#define CSC0_CTRL_CSC_MODE_MASK GENMASK(2, 1)
#define CSC0_CTRL_BYPASS BIT(0)
@@ -248,6 +255,7 @@
#define PANIC0_THRES_LOW_MASK GENMASK(24, 16)
#define PANIC0_THRES_HIGH_MASK GENMASK(8, 0)
+#define PANIC0_THRES_MAX 511
#define LCDIF_MIN_XRES 120
#define LCDIF_MIN_YRES 120
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index b29b332ed381..810edea0a31e 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -20,7 +20,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
index 60586fb8275e..5e5617006da5 100644
--- a/drivers/gpu/drm/nouveau/Kbuild
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -54,10 +54,6 @@ nouveau-y += nouveau_bios.o
nouveau-y += nouveau_connector.o
nouveau-y += nouveau_display.o
nouveau-y += nouveau_dp.o
-nouveau-y += nouveau_fbcon.o
-nouveau-y += nv04_fbcon.o
-nouveau-y += nv50_fbcon.o
-nouveau-y += nvc0_fbcon.o
include $(src)/dispnv04/Kbuild
include $(src)/dispnv50/Kbuild
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index ee92d576d277..0e0f117bc70b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -23,6 +23,7 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h>
@@ -37,7 +38,6 @@
#include "nouveau_crtc.h"
#include "hw.h"
#include "nvreg.h"
-#include "nouveau_fbcon.h"
#include "disp.h"
#include "nouveau_dma.h"
@@ -761,7 +761,8 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
- nvif_notify_dtor(&nv_crtc->vblank);
+ nvif_event_dtor(&nv_crtc->vblank);
+ nvif_head_dtor(&nv_crtc->head);
kfree(nv_crtc);
}
@@ -914,14 +915,6 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y, enum mode_set_atomic state)
{
- struct nouveau_drm *drm = nouveau_drm(crtc->dev);
- struct drm_device *dev = drm->dev;
-
- if (state == ENTER_ATOMIC_MODE_SET)
- nouveau_fbcon_accel_save_disable(dev);
- else
- nouveau_fbcon_accel_restore(dev);
-
return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
}
@@ -1080,10 +1073,10 @@ nv04_finish_page_flip(struct nouveau_channel *chan,
}
int
-nv04_flip_complete(struct nvif_notify *notify)
+nv04_flip_complete(struct nvif_event *event, void *argv, u32 argc)
{
- struct nouveau_cli *cli = (void *)notify->object->client;
- struct nouveau_drm *drm = cli->drm;
+ struct nv04_display *disp = container_of(event, typeof(*disp), flip);
+ struct nouveau_drm *drm = disp->drm;
struct nouveau_channel *chan = drm->channel;
struct nv04_page_flip_state state;
@@ -1094,7 +1087,7 @@ nv04_flip_complete(struct nvif_notify *notify)
state.bpp / 8);
}
- return NVIF_NOTIFY_KEEP;
+ return NVIF_EVENT_KEEP;
}
static int
@@ -1279,13 +1272,13 @@ static const struct drm_plane_funcs nv04_primary_plane_funcs = {
DRM_PLANE_NON_ATOMIC_FUNCS,
};
-static int nv04_crtc_vblank_handler(struct nvif_notify *notify)
+static int
+nv04_crtc_vblank_handler(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_crtc *nv_crtc =
- container_of(notify, struct nouveau_crtc, vblank);
+ struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank);
drm_crtc_handle_vblank(&nv_crtc->base);
- return NVIF_NOTIFY_KEEP;
+ return NVIF_EVENT_KEEP;
}
int
@@ -1341,14 +1334,10 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
nv04_cursor_init(nv_crtc);
- ret = nvif_notify_ctor(&disp->disp.object, "kmsVbl", nv04_crtc_vblank_handler,
- false, NV04_DISP_NTFY_VBLANK,
- &(struct nvif_notify_head_req_v0) {
- .head = nv_crtc->index,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &nv_crtc->vblank);
+ ret = nvif_head_ctor(&disp->disp, nv_crtc->base.name, nv_crtc->index, &nv_crtc->head);
+ if (ret)
+ return ret;
- return ret;
+ return nvif_head_vblank_event_ctor(&nv_crtc->head, "kmsVbl", nv04_crtc_vblank_handler,
+ false, &nv_crtc->vblank);
}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c
index 99fee4d8cd31..e9ac3fb27ff7 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -61,7 +61,7 @@ nv04_display_fini(struct drm_device *dev, bool runtime, bool suspend)
struct drm_crtc *crtc;
/* Disable flip completion events. */
- nvif_notify_put(&disp->flip);
+ nvif_event_block(&disp->flip);
/* Disable vblank interrupts. */
NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
@@ -121,7 +121,7 @@ nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
encoder->enc_save(&encoder->base.base);
/* Enable flip completion events. */
- nvif_notify_get(&disp->flip);
+ nvif_event_allow(&disp->flip);
if (!resume)
return 0;
@@ -202,7 +202,7 @@ nv04_display_destroy(struct drm_device *dev)
nouveau_hw_save_vga_fonts(dev, 0);
- nvif_notify_dtor(&disp->flip);
+ nvif_event_dtor(&disp->flip);
nouveau_display(dev)->priv = NULL;
vfree(disp);
@@ -227,6 +227,8 @@ nv04_display_create(struct drm_device *dev)
if (!disp)
return -ENOMEM;
+ disp->drm = drm;
+
nvif_object_map(&drm->client.device.object, NULL, 0);
nouveau_display(dev)->priv = disp;
@@ -239,9 +241,10 @@ nv04_display_create(struct drm_device *dev)
/* Request page flip completion event. */
if (drm->channel) {
- nvif_notify_ctor(&drm->channel->nvsw, "kmsFlip", nv04_flip_complete,
- false, NV04_NVSW_NTFY_UEVENT,
- NULL, 0, 0, &disp->flip);
+ ret = nvif_event_ctor(&drm->channel->nvsw, "kmsFlip", 0, nv04_flip_complete,
+ true, NULL, 0, &disp->flip);
+ if (ret)
+ return ret;
}
nouveau_hw_save_vga_fonts(dev, 1);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index f0a24126641a..11a6663758ec 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -6,6 +6,8 @@
#include "nouveau_display.h"
+#include <nvif/event.h>
+
struct nouveau_encoder;
enum nv04_fp_display_regs {
@@ -84,7 +86,8 @@ struct nv04_display {
uint32_t saved_vga_font[4][16384];
uint32_t dac_users[4];
struct nouveau_bo *image[2];
- struct nvif_notify flip;
+ struct nvif_event flip;
+ struct nouveau_drm *drm;
};
static inline struct nv04_display *
@@ -179,5 +182,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
);
}
-int nv04_flip_complete(struct nvif_notify *);
+int nv04_flip_complete(struct nvif_event *, void *, u32);
#endif
diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c
index b834e8a9ae77..9c942fbd836d 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/crc.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c
@@ -463,7 +463,7 @@ void nv50_crc_atomic_set(struct nv50_head *head,
if (!outp)
return;
- func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src),
+ func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src),
&crc->ctx[crc->ctx_idx]);
}
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 33c97d510999..edcb2529b402 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -46,8 +46,8 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
-#include <nvif/cl5070.h>
#include <nvif/event.h>
+#include <nvif/if0012.h>
#include <nvif/if0014.h>
#include <nvif/timer.h>
@@ -64,7 +64,6 @@
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
#include "nouveau_fence.h"
-#include "nouveau_fbcon.h"
#include <subdev/bios/dp.h>
@@ -131,7 +130,7 @@ nv50_dmac_kick(struct nvif_push *push)
{
struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push);
- dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr;
+ dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr;
if (dmac->put != dmac->cur) {
/* Push buffer fetches are not coherent with BAR1, we need to ensure
* writes have been flushed right through to VRAM before writing PUT.
@@ -194,7 +193,7 @@ nv50_dmac_wait(struct nvif_push *push, u32 size)
if (WARN_ON(size > dmac->max))
return -EINVAL;
- dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr;
+ dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr;
if (dmac->cur + size >= dmac->max) {
int ret = nv50_dmac_wind(dmac);
if (ret)
@@ -317,52 +316,6 @@ nv50_outp_dump_caps(struct nouveau_drm *drm,
outp->base.base.name, outp->caps.dp_interlace);
}
-static void
-nv50_outp_release(struct nouveau_encoder *nv_encoder)
-{
- struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_RELEASE,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = nv_encoder->dcb->hashm,
- };
-
- nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
- nv_encoder->or = -1;
- nv_encoder->link = 0;
-}
-
-static int
-nv50_outp_acquire(struct nouveau_encoder *nv_encoder, bool hda)
-{
- struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
- struct nv50_disp *disp = nv50_disp(drm->dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_acquire_v0 info;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_ACQUIRE,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = nv_encoder->dcb->hashm,
- .info.hda = hda,
- };
- int ret;
-
- ret = nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
- if (ret) {
- NV_ERROR(drm, "error acquiring output path: %d\n", ret);
- return ret;
- }
-
- nv_encoder->or = args.info.or;
- nv_encoder->link = args.info.link;
- return 0;
-}
-
static int
nv50_outp_atomic_check_view(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
@@ -489,9 +442,9 @@ nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
struct nv50_core *core = nv50_disp(encoder->dev)->core;
const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE);
- core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL);
+ core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL);
nv_encoder->crtc = NULL;
- nv50_outp_release(nv_encoder);
+ nvif_outp_release(&nv_encoder->outp);
}
static void
@@ -516,9 +469,9 @@ nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT);
- nv50_outp_acquire(nv_encoder, false);
+ nvif_outp_acquire_rgb_crt(&nv_encoder->outp);
- core->func->dac->ctrl(core, nv_encoder->or, ctrl, asyh);
+ core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh);
asyh->or.depth = 0;
nv_encoder->crtc = &nv_crtc->base;
@@ -634,7 +587,7 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id,
nv_connector = nouveau_connector(nv_encoder->audio.connector);
nv_crtc = nouveau_crtc(nv_encoder->crtc);
- if (!nv_crtc || nv_encoder->or != port || nv_crtc->index != dev_id)
+ if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id)
continue;
*enabled = nv_encoder->audio.enabled;
@@ -718,33 +671,37 @@ nv50_audio_component_fini(struct nouveau_drm *drm)
/******************************************************************************
* Audio
*****************************************************************************/
+static bool
+nv50_audio_supported(struct drm_encoder *encoder)
+{
+ struct nv50_disp *disp = nv50_disp(encoder->dev);
+
+ if (disp->disp->object.oclass <= GT200_DISP ||
+ disp->disp->object.oclass == GT206_DISP)
+ return false;
+
+ return true;
+}
+
static void
nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_hda_eld_v0 eld;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
- (0x0100 << nv_crtc->index),
- };
+ struct nvif_outp *outp = &nv_encoder->outp;
+
+ if (!nv50_audio_supported(encoder))
+ return;
mutex_lock(&drm->audio.lock);
if (nv_encoder->audio.enabled) {
nv_encoder->audio.enabled = false;
nv_encoder->audio.connector = NULL;
- nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
+ nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0);
}
mutex_unlock(&drm->audio.lock);
- nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
- nv_crtc->index);
+ nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index);
}
static void
@@ -754,159 +711,101 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct __packed {
- struct {
- struct nv50_disp_mthd_v1 mthd;
- struct nv50_disp_sor_hda_eld_v0 eld;
- } base;
- u8 data[sizeof(nv_connector->base.eld)];
- } args = {
- .base.mthd.version = 1,
- .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
- .base.mthd.hasht = nv_encoder->dcb->hasht,
- .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
- (0x0100 << nv_crtc->index),
- };
-
- if (!drm_detect_monitor_audio(nv_connector->edid))
+ struct nvif_outp *outp = &nv_encoder->outp;
+
+ if (!nv50_audio_supported(encoder) || !drm_detect_monitor_audio(nv_connector->edid))
return;
mutex_lock(&drm->audio.lock);
- memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
-
- nvif_mthd(&disp->disp->object, 0, &args,
- sizeof(args.base) + drm_eld_size(args.data));
+ nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld,
+ drm_eld_size(nv_connector->base.eld));
nv_encoder->audio.enabled = true;
nv_encoder->audio.connector = &nv_connector->base;
mutex_unlock(&drm->audio.lock);
- nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
- nv_crtc->index);
+ nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index);
}
/******************************************************************************
* HDMI
*****************************************************************************/
static void
-nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_hdmi_pwr_v0 pwr;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
- (0x0100 << nv_crtc->index),
- };
-
- nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
-}
-
-static void
nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
struct nouveau_connector *nv_connector, struct drm_atomic_state *state,
- struct drm_display_mode *mode)
+ struct drm_display_mode *mode, bool hda)
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_hdmi_pwr_v0 pwr;
- u8 infoframes[2 * 17]; /* two frames, up to 17 bytes each */
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
- (0x0100 << nv_crtc->index),
- .pwr.state = 1,
- .pwr.rekey = 56, /* binary driver, and tegra, constant */
- };
- struct drm_hdmi_info *hdmi;
+ struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi;
+ union hdmi_infoframe infoframe = { 0 };
+ const u8 rekey = 56; /* binary driver, and tegra, constant */
+ u8 scdc = 0;
u32 max_ac_packet;
- union hdmi_infoframe avi_frame;
- union hdmi_infoframe vendor_frame;
- bool high_tmds_clock_ratio = false, scrambling = false;
- u8 config;
- int ret;
- int size;
-
- if (!drm_detect_hdmi_monitor(nv_connector->edid))
- return;
-
- hdmi = &nv_connector->base.display_info.hdmi;
-
- ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi,
- &nv_connector->base, mode);
- if (!ret) {
- drm_hdmi_avi_infoframe_quant_range(&avi_frame.avi,
- &nv_connector->base, mode,
- HDMI_QUANTIZATION_RANGE_FULL);
- /* We have an AVI InfoFrame, populate it to the display */
- args.pwr.avi_infoframe_length
- = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17);
- }
-
- ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi,
- &nv_connector->base, mode);
- if (!ret) {
- /* We have a Vendor InfoFrame, populate it to the display */
- args.pwr.vendor_infoframe_length
- = hdmi_infoframe_pack(&vendor_frame,
- args.infoframes
- + args.pwr.avi_infoframe_length,
- 17);
- }
+ struct {
+ struct nvif_outp_infoframe_v0 infoframe;
+ u8 data[17];
+ } args = { 0 };
+ int ret, size;
max_ac_packet = mode->htotal - mode->hdisplay;
- max_ac_packet -= args.pwr.rekey;
+ max_ac_packet -= rekey;
max_ac_packet -= 18; /* constant from tegra */
- args.pwr.max_ac_packet = max_ac_packet / 32;
+ max_ac_packet /= 32;
if (hdmi->scdc.scrambling.supported) {
- high_tmds_clock_ratio = mode->clock > 340000;
- scrambling = high_tmds_clock_ratio ||
- hdmi->scdc.scrambling.low_rates;
- }
+ const bool high_tmds_clock_ratio = mode->clock > 340000;
- args.pwr.scdc =
- NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE * scrambling |
- NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 * high_tmds_clock_ratio;
+ ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc);
+ if (ret < 0) {
+ NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret);
+ return;
+ }
- size = sizeof(args.base)
- + sizeof(args.pwr)
- + args.pwr.avi_infoframe_length
- + args.pwr.vendor_infoframe_length;
- nvif_mthd(&disp->disp->object, 0, &args, size);
+ scdc &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE);
+ if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates)
+ scdc |= SCDC_SCRAMBLING_ENABLE;
+ if (high_tmds_clock_ratio)
+ scdc |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
- nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode);
+ ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, scdc);
+ if (ret < 0)
+ NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n",
+ scdc, ret);
+ }
- /* If SCDC is supported by the downstream monitor, update
- * divider / scrambling settings to what we programmed above.
- */
- if (!hdmi->scdc.scrambling.supported)
+ ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true,
+ max_ac_packet, rekey, scdc, hda);
+ if (ret)
return;
- ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
- NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret);
- return;
+ /* AVI InfoFrame. */
+ args.infoframe.version = 0;
+ args.infoframe.head = nv_crtc->index;
+
+ if (!drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, &nv_connector->base, mode)) {
+ drm_hdmi_avi_infoframe_quant_range(&infoframe.avi, &nv_connector->base, mode,
+ HDMI_QUANTIZATION_RANGE_FULL);
+
+ size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data));
+ } else {
+ size = 0;
}
- config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE);
- config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 * high_tmds_clock_ratio;
- config |= SCDC_SCRAMBLING_ENABLE * scrambling;
- ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config);
- if (ret < 0)
- NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n",
- config, ret);
+
+ nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, &args.infoframe, size);
+
+ /* Vendor InfoFrame. */
+ memset(&args.data, 0, sizeof(args.data));
+ if (!drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi,
+ &nv_connector->base, mode))
+ size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data));
+ else
+ size = 0;
+
+ nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size);
+
+ nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode);
}
/******************************************************************************
@@ -979,16 +878,6 @@ nv50_msto_prepare(struct drm_atomic_state *state,
struct nv50_mstc *mstc = msto->mstc;
struct nv50_mstm *mstm = mstc->mstm;
struct drm_dp_mst_atomic_payload *payload;
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_dp_mst_vcpi_v0 vcpi;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI,
- .base.hasht = mstm->outp->dcb->hasht,
- .base.hashm = (0xf0ff & mstm->outp->dcb->hashm) |
- (0x0100 << msto->head->base.index),
- };
NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name);
@@ -997,22 +886,16 @@ nv50_msto_prepare(struct drm_atomic_state *state,
// TODO: Figure out if we want to do a better job of handling VCPI allocation failures here?
if (msto->disabled) {
drm_dp_remove_payload(mgr, mst_state, payload);
+
+ nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0);
} else {
if (msto->enabled)
drm_dp_add_payload_part1(mgr, mst_state, payload);
- args.vcpi.start_slot = payload->vc_start_slot;
- args.vcpi.num_slots = payload->time_slots;
- args.vcpi.pbn = payload->pbn;
- args.vcpi.aligned_pbn = payload->time_slots * mst_state->pbn_div;
+ nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index,
+ payload->vc_start_slot, payload->time_slots,
+ payload->pbn, payload->time_slots * mst_state->pbn_div);
}
-
- NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n",
- msto->encoder.name, msto->head->base.base.name,
- args.vcpi.start_slot, args.vcpi.num_slots,
- args.vcpi.pbn, args.vcpi.aligned_pbn);
-
- nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args));
}
static int
@@ -1107,10 +990,12 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
if (WARN_ON(!mstc))
return;
- if (!mstm->links++)
- nv50_outp_acquire(mstm->outp, false /*XXX: MST audio.*/);
+ if (!mstm->links++) {
+ /*XXX: MST audio. */
+ nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true);
+ }
- if (mstm->outp->link & 1)
+ if (mstm->outp->outp.or.link & 1)
proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B;
@@ -1405,7 +1290,7 @@ nv50_mstm_prepare(struct drm_atomic_state *state,
if (mstm->disabled) {
if (!mstm->links)
- nv50_outp_release(mstm->outp);
+ nvif_outp_release(&mstm->outp->outp);
mstm->disabled = false;
}
}
@@ -1473,26 +1358,6 @@ nv50_mstm_remove(struct nv50_mstm *mstm)
drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false);
}
-static int
-nv50_mstm_enable(struct nv50_mstm *mstm, int state)
-{
- struct nouveau_encoder *outp = mstm->outp;
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_dp_mst_link_v0 mst;
- } args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
- .base.hasht = outp->dcb->hasht,
- .base.hashm = outp->dcb->hashm,
- .mst.state = state,
- };
- struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
- struct nvif_object *disp = &drm->display->disp.object;
-
- return nvif_mthd(disp, 0, &args, sizeof(args));
-}
-
int
nv50_mstm_detect(struct nouveau_encoder *outp)
{
@@ -1513,15 +1378,9 @@ nv50_mstm_detect(struct nouveau_encoder *outp)
return ret;
/* And start enabling */
- ret = nv50_mstm_enable(mstm, true);
- if (ret)
- return ret;
-
ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true);
- if (ret) {
- nv50_mstm_enable(mstm, false);
+ if (ret)
return ret;
- }
mstm->is_mst = true;
return 1;
@@ -1623,7 +1482,7 @@ nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
asyh->or.depth = depth;
}
- core->func->sor->ctrl(core, nv_encoder->or, nv_encoder->ctrl, asyh);
+ core->func->sor->ctrl(core, nv_encoder->outp.or.id, nv_encoder->ctrl, asyh);
}
/* TODO: Should we extend this to PWM-only backlights?
@@ -1666,8 +1525,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
nv50_audio_disable(encoder, nv_crtc);
- nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
- nv50_outp_release(nv_encoder);
+ nvif_outp_release(&nv_encoder->outp);
nv_encoder->crtc = NULL;
}
@@ -1679,16 +1537,8 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
struct nv50_head_atom *asyh =
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base));
struct drm_display_mode *mode = &asyh->state.adjusted_mode;
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_lvds_script_v0 lvds;
- } lvds = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = nv_encoder->dcb->hashm,
- };
struct nv50_disp *disp = nv50_disp(encoder->dev);
+ struct nvif_outp *outp = &nv_encoder->outp;
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_connector *nv_connector;
@@ -1696,7 +1546,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
struct nouveau_backlight *backlight;
#endif
struct nvbios *bios = &drm->vbios;
- bool hda = false;
+ bool lvds_dual = false, lvds_8bpc = false, hda = false;
u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM;
u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT;
@@ -1707,11 +1557,16 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
disp->disp->object.oclass >= GF110_DISP) &&
drm_detect_monitor_audio(nv_connector->edid))
hda = true;
- nv50_outp_acquire(nv_encoder, hda);
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
- if (nv_encoder->link & 1) {
+ if (disp->disp->object.oclass == NV50_DISP ||
+ !drm_detect_hdmi_monitor(nv_connector->edid))
+ nvif_outp_acquire_tmds(outp, nv_crtc->index, false, 0, 0, 0, false);
+ else
+ nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda);
+
+ if (nv_encoder->outp.or.link & 1) {
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A;
/* Only enable dual-link if:
* - Need to (i.e. rate > 165MHz)
@@ -1726,44 +1581,41 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
} else {
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B;
}
-
- nv50_hdmi_enable(&nv_encoder->base.base, nv_crtc, nv_connector, state, mode);
break;
case DCB_OUTPUT_LVDS:
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM;
if (bios->fp_no_ddc) {
- if (bios->fp.dual_link)
- lvds.lvds.script |= 0x0100;
- if (bios->fp.if_is_24bit)
- lvds.lvds.script |= 0x0200;
+ lvds_dual = bios->fp.dual_link;
+ lvds_8bpc = bios->fp.if_is_24bit;
} else {
if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
if (((u8 *)nv_connector->edid)[121] == 2)
- lvds.lvds.script |= 0x0100;
+ lvds_dual = true;
} else
if (mode->clock >= bios->fp.duallink_transition_clk) {
- lvds.lvds.script |= 0x0100;
+ lvds_dual = true;
}
- if (lvds.lvds.script & 0x0100) {
+ if (lvds_dual) {
if (bios->fp.strapless_is_24bit & 2)
- lvds.lvds.script |= 0x0200;
+ lvds_8bpc = true;
} else {
if (bios->fp.strapless_is_24bit & 1)
- lvds.lvds.script |= 0x0200;
+ lvds_8bpc = true;
}
if (asyh->or.bpc == 8)
- lvds.lvds.script |= 0x0200;
+ lvds_8bpc = true;
}
- nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds));
+ nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc);
break;
case DCB_OUTPUT_DP:
+ nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false);
depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
- if (nv_encoder->link & 1)
+ if (nv_encoder->outp.or.link & 1)
proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B;
@@ -1921,9 +1773,9 @@ nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s
struct nv50_core *core = nv50_disp(encoder->dev)->core;
const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE);
- core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL);
+ core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL);
nv_encoder->crtc = NULL;
- nv50_outp_release(nv_encoder);
+ nvif_outp_release(&nv_encoder->outp);
}
static void
@@ -1944,8 +1796,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
break;
}
- nv50_outp_acquire(nv_encoder, false);
-
switch (asyh->or.bpc) {
case 10: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; break;
case 8: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; break;
@@ -1955,15 +1805,19 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
+ ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
+ nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false);
+ break;
case DCB_OUTPUT_DP:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
+ nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false);
break;
default:
BUG();
break;
}
- core->func->pior->ctrl(core, nv_encoder->or, ctrl, asyh);
+ core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh);
nv_encoder->crtc = &nv_crtc->base;
}
@@ -2587,7 +2441,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev)
static const struct drm_mode_config_funcs
nv50_disp_func = {
.fb_create = nouveau_user_framebuffer_create,
- .output_poll_changed = nouveau_fbcon_output_poll_changed,
+ .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = nv50_disp_atomic_check,
.atomic_commit = nv50_disp_atomic_commit,
.atomic_state_alloc = nv50_disp_atomic_state_alloc,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index c3c57be54e1c..f006e56e1e08 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -517,7 +517,8 @@ nv50_head_destroy(struct drm_crtc *crtc)
{
struct nv50_head *head = nv50_head(crtc);
- nvif_notify_dtor(&head->base.vblank);
+ nvif_event_dtor(&head->base.vblank);
+ nvif_head_dtor(&head->base.head);
nv50_lut_fini(&head->olut);
drm_crtc_cleanup(crtc);
kfree(head);
@@ -554,15 +555,15 @@ nvd9_head_func = {
.late_register = nv50_head_late_register,
};
-static int nv50_head_vblank_handler(struct nvif_notify *notify)
+static int
+nv50_head_vblank_handler(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_crtc *nv_crtc =
- container_of(notify, struct nouveau_crtc, vblank);
+ struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank);
if (drm_crtc_handle_vblank(&nv_crtc->base))
nv50_crc_handle_vblank(nv50_head(&nv_crtc->base));
- return NVIF_NOTIFY_KEEP;
+ return NVIF_EVENT_KEEP;
}
struct nv50_head *
@@ -624,14 +625,12 @@ nv50_head_create(struct drm_device *dev, int index)
}
}
- ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler,
- false, NV04_DISP_NTFY_VBLANK,
- &(struct nvif_notify_head_req_v0) {
- .head = nv_crtc->index,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &nv_crtc->vblank);
+ ret = nvif_head_ctor(disp->disp, head->base.base.name, head->base.index, &head->base.head);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = nvif_head_vblank_event_ctor(&head->base.head, "kmsVbl", nv50_head_vblank_handler,
+ false, &nv_crtc->vblank);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/acr.h b/drivers/gpu/drm/nouveau/include/nvfw/acr.h
index e65d6a8db104..6f19560bc54b 100644
--- a/drivers/gpu/drm/nouveau/include/nvfw/acr.h
+++ b/drivers/gpu/drm/nouveau/include/nvfw/acr.h
@@ -39,6 +39,23 @@ struct wpr_header_v1 {
void wpr_header_v1_dump(struct nvkm_subdev *, const struct wpr_header_v1 *);
+struct wpr_generic_header {
+#define WPR_GENERIC_HEADER_ID_LSF_UCODE_DESC 1
+#define WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER 2
+#define WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR 3
+#define WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER 4
+ u16 identifier;
+ u16 version;
+ u32 size;
+};
+
+struct wpr_header_v2 {
+ struct wpr_generic_header hdr;
+ struct wpr_header_v1 wpr;
+};
+
+void wpr_header_v2_dump(struct nvkm_subdev *, const struct wpr_header_v2 *);
+
struct lsf_signature {
u8 prd_keys[2][16];
u8 dbg_keys[2][16];
@@ -89,6 +106,74 @@ struct lsb_header_v1 {
void lsb_header_v1_dump(struct nvkm_subdev *, struct lsb_header_v1 *);
+struct lsb_header_v2 {
+ struct wpr_generic_header hdr;
+ struct lsf_signature_v2 {
+ struct wpr_generic_header hdr;
+ u32 falcon_id;
+ u8 prd_present;
+ u8 dbg_present;
+ u16 reserved;
+ u32 sig_size;
+ u8 prod_sig[2][384 + 128];
+ u8 debug_sig[2][384 + 128];
+ u16 sig_algo_ver;
+ u16 sig_algo;
+ u16 hash_algo_ver;
+ u16 hash_algo;
+ u32 sig_algo_padding_type;
+ u8 depmap[11 * 2 * 4];
+ u32 depmap_count;
+ u8 supports_versioning;
+ u8 pad[3];
+ u32 ls_ucode_version;
+ u32 ls_ucode_id;
+ u32 ucode_ls_encrypted;
+ u32 ls_eng_algo_type;
+ u32 ls_eng_algo_ver;
+ u8 ls_enc_iv[16];
+ u8 rsvd[36];
+ } signature;
+ u32 ucode_off;
+ u32 ucode_size;
+ u32 data_size;
+ u32 bl_code_size;
+ u32 bl_imem_off;
+ u32 bl_data_off;
+ u32 bl_data_size;
+ u32 rsvd0;
+ u32 app_code_off;
+ u32 app_code_size;
+ u32 app_data_off;
+ u32 app_data_size;
+ u32 app_imem_offset;
+ u32 app_dmem_offset;
+ u32 flags;
+ u32 monitor_code_offset;
+ u32 monitor_data_offset;
+ u32 manifest_offset;
+ struct hs_fmc_params {
+ u8 hs_fmc;
+ u8 padding[3];
+ u16 pkc_algo;
+ u16 pkc_algo_version;
+ u32 engid_mask;
+ u32 ucode_id;
+ u32 fuse_ver;
+ u8 pkc_signature[384 + 128];
+ u8 pkc_key[2048];
+ u8 rsvd[4];
+ } hs_fmc_params;
+ struct hs_ovl_sig_blob_params {
+ u8 hs_ovl_sig_blob_present;
+ u32 hs_ovl_sig_blob_offset;
+ u32 hs_ovl_sig_blob_size;
+ } hs_ovl_sig_blob_params;
+ u8 rsvd[20];
+};
+
+void lsb_header_v2_dump(struct nvkm_subdev *, struct lsb_header_v2 *);
+
struct flcn_acr_desc {
union {
u8 reserved_dmem[0x200];
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/hs.h b/drivers/gpu/drm/nouveau/include/nvfw/hs.h
index b53bbc4cd130..8c4cd08a7b5f 100644
--- a/drivers/gpu/drm/nouveau/include/nvfw/hs.h
+++ b/drivers/gpu/drm/nouveau/include/nvfw/hs.h
@@ -17,6 +17,20 @@ struct nvfw_hs_header {
const struct nvfw_hs_header *nvfw_hs_header(struct nvkm_subdev *, const void *);
+struct nvfw_hs_header_v2 {
+ u32 sig_prod_offset;
+ u32 sig_prod_size;
+ u32 patch_loc;
+ u32 patch_sig;
+ u32 meta_data_offset;
+ u32 meta_data_size;
+ u32 num_sig;
+ u32 header_offset;
+ u32 header_size;
+};
+
+const struct nvfw_hs_header_v2 *nvfw_hs_header_v2(struct nvkm_subdev *, const void *);
+
struct nvfw_hs_load_header {
u32 non_sec_code_off;
u32 non_sec_code_size;
@@ -28,4 +42,18 @@ struct nvfw_hs_load_header {
const struct nvfw_hs_load_header *
nvfw_hs_load_header(struct nvkm_subdev *, const void *);
+
+struct nvfw_hs_load_header_v2 {
+ u32 os_code_offset;
+ u32 os_code_size;
+ u32 os_data_offset;
+ u32 os_data_size;
+ u32 num_apps;
+ struct {
+ u32 offset;
+ u32 size;
+ } app[0];
+};
+
+const struct nvfw_hs_load_header_v2 *nvfw_hs_load_header_v2(struct nvkm_subdev *, const void *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/ls.h b/drivers/gpu/drm/nouveau/include/nvfw/ls.h
index f63692a2a16c..d531121bfa35 100644
--- a/drivers/gpu/drm/nouveau/include/nvfw/ls.h
+++ b/drivers/gpu/drm/nouveau/include/nvfw/ls.h
@@ -50,4 +50,55 @@ struct nvfw_ls_desc_v1 {
const struct nvfw_ls_desc_v1 *
nvfw_ls_desc_v1(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_desc_v2 {
+ u32 descriptor_size;
+ u32 image_size;
+ u32 tools_version;
+ u32 app_version;
+ char date[64];
+ u32 secure_bootloader;
+ u32 bootloader_start_offset;
+ u32 bootloader_size;
+ u32 bootloader_imem_offset;
+ u32 bootloader_entry_point;
+ u32 app_start_offset;
+ u32 app_size;
+ u32 app_imem_offset;
+ u32 app_imem_entry;
+ u32 app_dmem_offset;
+ u32 app_resident_code_offset;
+ u32 app_resident_code_size;
+ u32 app_resident_data_offset;
+ u32 app_resident_data_size;
+ u32 nb_imem_overlays;
+ u32 nb_dmem_overlays;
+ struct {
+ u32 start;
+ u32 size;
+ } load_ovl[64];
+};
+
+const struct nvfw_ls_desc_v2 *nvfw_ls_desc_v2(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_hsbl_bin_hdr {
+ u32 bin_magic;
+ u32 bin_ver;
+ u32 bin_size;
+ u32 header_offset;
+};
+
+const struct nvfw_ls_hsbl_bin_hdr *nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *, const void *);
+
+struct nvfw_ls_hsbl_hdr {
+ u32 sig_prod_offset;
+ u32 sig_prod_size;
+ u32 patch_loc;
+ u32 patch_sig;
+ u32 meta_data_offset;
+ u32 meta_data_size;
+ u32 num_sig;
+};
+
+const struct nvfw_ls_hsbl_hdr *nvfw_ls_hsbl_hdr(struct nvkm_subdev *, const void *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h
index 9a37ad4179cb..b3331d679c4e 100644
--- a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h
+++ b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h
@@ -10,6 +10,7 @@ struct nv_sec2_args {
};
#define NV_SEC2_UNIT_INIT 0x01
+#define NV_SEC2_UNIT_UNLOAD 0x06
#define NV_SEC2_UNIT_ACR 0x08
struct nv_sec2_init_msg {
@@ -33,6 +34,29 @@ struct nv_sec2_init_msg {
u16 sw_managed_area_size;
};
+struct nv_sec2_init_msg_v1 {
+ struct nvfw_falcon_msg hdr;
+#define NV_SEC2_INIT_MSG_INIT 0x00
+ u8 msg_type;
+
+ u8 num_queues;
+ u16 os_debug_entry_point;
+
+ struct {
+ u32 offset;
+ u16 size;
+ u8 index;
+#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ 0x00
+#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ 0x01
+ u8 id;
+ } queue_info[2];
+
+ u32 sw_managed_area_offset;
+ u16 sw_managed_area_size;
+
+ u32 unkn[8];
+};
+
struct nv_sec2_acr_cmd {
struct nvfw_falcon_cmd hdr;
#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00
@@ -57,4 +81,25 @@ struct nv_sec2_acr_bootstrap_falcon_msg {
u32 error_code;
u32 falcon_id;
};
+
+#define NV_SEC2_UNIT_V2_INIT 0x01
+#define NV_SEC2_UNIT_V2_UNLOAD 0x05
+#define NV_SEC2_UNIT_V2_ACR 0x07
+
+struct nv_sec2_acr_bootstrap_falcon_cmd_v1 {
+ struct nv_sec2_acr_cmd cmd;
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO 0x00000001
+ u32 flags;
+ u32 falcon_id;
+ u32 unkn08;
+ u32 unkn0c;
+};
+
+struct nv_sec2_acr_bootstrap_falcon_msg_v1 {
+ struct nv_sec2_acr_msg msg;
+ u32 error_code;
+ u32 falcon_id;
+ u32 unkn08;
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0046.h b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h
index d490d401870a..eca7c3950654 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/cl0046.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h
@@ -2,28 +2,5 @@
#ifndef __NVIF_CL0046_H__
#define __NVIF_CL0046_H__
-#define NV04_DISP_NTFY_VBLANK 0x00
#define NV04_DISP_NTFY_CONN 0x01
-
-struct nv04_disp_mthd_v0 {
- __u8 version;
-#define NV04_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv04_disp_scanoutpos_v0 {
- __u8 version;
- __u8 pad01[7];
- __s64 time[2];
- __u16 vblanks;
- __u16 vblanke;
- __u16 vtotal;
- __u16 vline;
- __u16 hblanks;
- __u16 hblanke;
- __u16 htotal;
- __u16 hline;
-};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl006b.h b/drivers/gpu/drm/nouveau/include/nvif/cl006b.h
deleted file mode 100644
index c960c449e430..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl006b.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL006B_H__
-#define __NVIF_CL006B_H__
-
-struct nv03_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 offset;
- __u64 pushbuf;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
index 59759c4fb62e..8b5a240d57e4 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
@@ -68,7 +68,7 @@ struct nv_device_time_v0 {
/* Returns the number of available runlists. */
#define NV_DEVICE_HOST_RUNLISTS NV_DEVICE_HOST(0x00000000)
-/* Returns the number of available channels. */
+/* Returns the number of available channels (0 if per-runlist). */
#define NV_DEVICE_HOST_CHANNELS NV_DEVICE_HOST(0x00000001)
/* Returns a mask of available engine types on runlist(data). */
@@ -90,4 +90,6 @@ struct nv_device_time_v0 {
#define NV_DEVICE_HOST_RUNLIST_ENGINES_SEC2 0x00004000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC 0x00008000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVENC 0x00010000
+/* Returns the number of available channels on runlist(data). */
+#define NV_DEVICE_HOST_RUNLIST_CHANNELS NV_DEVICE_HOST(0x00000101)
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506e.h b/drivers/gpu/drm/nouveau/include/nvif/cl506e.h
deleted file mode 100644
index 9df289c7a84f..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl506e.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL506E_H__
-#define __NVIF_CL506E_H__
-
-struct nv50_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[6];
- __u64 vmm;
- __u64 pushbuf;
- __u64 offset;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506f.h b/drivers/gpu/drm/nouveau/include/nvif/cl506f.h
deleted file mode 100644
index 327c96a994bb..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl506f.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL506F_H__
-#define __NVIF_CL506F_H__
-
-struct nv50_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 ilength;
- __u64 ioffset;
- __u64 pushbuf;
- __u64 vmm;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
deleted file mode 100644
index 56affb606adf..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL5070_H__
-#define __NVIF_CL5070_H__
-
-#define NV50_DISP_MTHD 0x00
-
-struct nv50_disp_mthd_v0 {
- __u8 version;
-#define NV50_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv50_disp_scanoutpos_v0 {
- __u8 version;
- __u8 pad01[7];
- __s64 time[2];
- __u16 vblanks;
- __u16 vblanke;
- __u16 vtotal;
- __u16 vline;
- __u16 hblanks;
- __u16 hblanke;
- __u16 htotal;
- __u16 hline;
-};
-
-struct nv50_disp_mthd_v1 {
- __u8 version;
-#define NV50_DISP_MTHD_V1_ACQUIRE 0x01
-#define NV50_DISP_MTHD_V1_RELEASE 0x02
-#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
-#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
-#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
-#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25
-#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26
- __u8 method;
- __u16 hasht;
- __u16 hashm;
- __u8 pad06[2];
-};
-
-struct nv50_disp_acquire_v0 {
- __u8 version;
- __u8 or;
- __u8 link;
- __u8 hda;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_hda_eld_v0 {
- __u8 version;
- __u8 pad01[7];
- __u8 data[];
-};
-
-struct nv50_disp_sor_hdmi_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 max_ac_packet;
- __u8 rekey;
- __u8 avi_infoframe_length;
- __u8 vendor_infoframe_length;
-#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE (1 << 0)
-#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 (1 << 1)
- __u8 scdc;
- __u8 pad07[1];
-};
-
-struct nv50_disp_sor_lvds_script_v0 {
- __u8 version;
- __u8 pad01[1];
- __u16 script;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_dp_mst_link_v0 {
- __u8 version;
- __u8 state;
- __u8 pad02[6];
-};
-
-struct nv50_disp_sor_dp_mst_vcpi_v0 {
- __u8 version;
- __u8 pad01[1];
- __u8 start_slot;
- __u8 num_slots;
- __u16 pbn;
- __u16 aligned_pbn;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826e.h b/drivers/gpu/drm/nouveau/include/nvif/cl826e.h
deleted file mode 100644
index 1b6496d31580..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl826e.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL826E_H__
-#define __NVIF_CL826E_H__
-
-struct g82_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[6];
- __u64 vmm;
- __u64 pushbuf;
- __u64 offset;
-};
-
-#define NV826E_V0_NTFY_NON_STALL_INTERRUPT 0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826f.h b/drivers/gpu/drm/nouveau/include/nvif/cl826f.h
deleted file mode 100644
index 148602264a76..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl826f.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL826F_H__
-#define __NVIF_CL826F_H__
-
-struct g82_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 ilength;
- __u64 ioffset;
- __u64 pushbuf;
- __u64 vmm;
-};
-
-#define NV826F_V0_NTFY_NON_STALL_INTERRUPT 0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl906f.h b/drivers/gpu/drm/nouveau/include/nvif/cl906f.h
deleted file mode 100644
index 3823d6891b55..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl906f.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL906F_H__
-#define __NVIF_CL906F_H__
-
-struct fermi_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 ilength;
- __u64 ioffset;
- __u64 vmm;
-};
-
-#define NV906F_V0_NTFY_NON_STALL_INTERRUPT 0x00
-#define NV906F_V0_NTFY_KILLED 0x01
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cla06f.h b/drivers/gpu/drm/nouveau/include/nvif/cla06f.h
deleted file mode 100644
index cfa18f1fbf83..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cla06f.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CLA06F_H__
-#define __NVIF_CLA06F_H__
-
-struct kepler_channel_gpfifo_a_v0 {
- __u8 version;
- __u8 priv;
- __u16 chid;
- __u32 ilength;
- __u64 ioffset;
- __u64 runlist;
- __u64 vmm;
- __u64 inst;
-};
-
-#define NVA06F_V0_NTFY_NON_STALL_INTERRUPT 0x00
-#define NVA06F_V0_NTFY_KILLED 0x01
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
index 8641db649f48..ad1e5de84e80 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -32,11 +32,17 @@
#define NVIF_CLASS_VMM_GM200 /* ifb00d.h */ 0x8000b00d
#define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d
+#define NVIF_CLASS_EVENT /* if000e.h */ 0x8000000e
+
#define NVIF_CLASS_DISP /* if0010.h */ 0x80000010
#define NVIF_CLASS_CONN /* if0011.h */ 0x80000011
#define NVIF_CLASS_OUTP /* if0012.h */ 0x80000012
+#define NVIF_CLASS_HEAD /* if0013.h */ 0x80000013
#define NVIF_CLASS_DISP_CHAN /* if0014.h */ 0x80000014
+#define NVIF_CLASS_CHAN /* if0020.h */ 0x80000020
+#define NVIF_CLASS_CGRP /* if0021.h */ 0x80000021
+
/* the below match nvidia-assigned (either in hw, or sw) class numbers */
#define NV_NULL_CLASS 0x00000030
@@ -58,25 +64,30 @@
#define NV04_DISP /* cl0046.h */ 0x00000046
#define VOLTA_USERMODE_A 0x0000c361
+#define TURING_USERMODE_A 0x0000c461
+#define AMPERE_USERMODE_A 0x0000c561
#define MAXWELL_FAULT_BUFFER_A /* clb069.h */ 0x0000b069
#define VOLTA_FAULT_BUFFER_A /* clb069.h */ 0x0000c369
-#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b
-#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e
-#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e
-#define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e
-
-#define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f
-#define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f
-#define FERMI_CHANNEL_GPFIFO /* cl906f.h */ 0x0000906f
-#define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f
-#define KEPLER_CHANNEL_GPFIFO_B /* cla06f.h */ 0x0000a16f
-#define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f
-#define PASCAL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000c06f
-#define VOLTA_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c36f
-#define TURING_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c46f
-#define AMPERE_CHANNEL_GPFIFO_B /* clc36f.h */ 0x0000c76f
+#define NV03_CHANNEL_DMA /* if0020.h */ 0x0000006b
+#define NV10_CHANNEL_DMA /* if0020.h */ 0x0000006e
+#define NV17_CHANNEL_DMA /* if0020.h */ 0x0000176e
+#define NV40_CHANNEL_DMA /* if0020.h */ 0x0000406e
+
+#define KEPLER_CHANNEL_GROUP_A /* if0021.h */ 0x0000a06c
+
+#define NV50_CHANNEL_GPFIFO /* if0020.h */ 0x0000506f
+#define G82_CHANNEL_GPFIFO /* if0020.h */ 0x0000826f
+#define FERMI_CHANNEL_GPFIFO /* if0020.h */ 0x0000906f
+#define KEPLER_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000a06f
+#define KEPLER_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000a16f
+#define MAXWELL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000b06f
+#define PASCAL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c06f
+#define VOLTA_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c36f
+#define TURING_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c46f
+#define AMPERE_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c56f
+#define AMPERE_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000c76f
#define NV50_DISP /* if0010.h */ 0x00005070
#define G82_DISP /* if0010.h */ 0x00008270
@@ -179,6 +190,8 @@
#define TURING_A /* cl9097.h */ 0x0000c597
+#define AMPERE_B /* cl9097.h */ 0x0000c797
+
#define NV74_BSP 0x000074b0
#define GT212_MSVLD 0x000085b1
@@ -206,6 +219,7 @@
#define PASCAL_DMA_COPY_B 0x0000c1b5
#define VOLTA_DMA_COPY_A 0x0000c3b5
#define TURING_DMA_COPY_A 0x0000c5b5
+#define AMPERE_DMA_COPY_A 0x0000c6b5
#define AMPERE_DMA_COPY_B 0x0000c7b5
#define FERMI_DECOMPRESS 0x000090b8
@@ -222,6 +236,7 @@
#define PASCAL_COMPUTE_B 0x0000c1c0
#define VOLTA_COMPUTE_A 0x0000c3c0
#define TURING_COMPUTE_A 0x0000c5c0
+#define AMPERE_COMPUTE_B 0x0000c7c0
#define NV74_CIPHER 0x000074c1
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clb069.h b/drivers/gpu/drm/nouveau/include/nvif/clb069.h
index eef5d0227bab..d7689de35ab2 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/clb069.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/clb069.h
@@ -8,5 +8,8 @@ struct nvif_clb069_v0 {
__u32 put;
};
-#define NVB069_V0_NTFY_FAULT 0x00
+union nvif_clb069_event_args {
+ struct nvif_clb069_event_vn {
+ } vn;
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clc36f.h b/drivers/gpu/drm/nouveau/include/nvif/clc36f.h
deleted file mode 100644
index f66885891238..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/clc36f.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CLC36F_H__
-#define __NVIF_CLC36F_H__
-
-struct volta_channel_gpfifo_a_v0 {
- __u8 version;
- __u8 priv;
- __u16 chid;
- __u32 ilength;
- __u64 ioffset;
- __u64 runlist;
- __u64 vmm;
- __u64 inst;
- __u32 token;
-};
-
-#define NVC36F_V0_NTFY_NON_STALL_INTERRUPT 0x00
-#define NVC36F_V0_NTFY_KILLED 0x01
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h
index f72a8f138f47..dc355e1dfafa 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/conn.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h
@@ -2,6 +2,7 @@
#ifndef __NVIF_CONN_H__
#define __NVIF_CONN_H__
#include <nvif/object.h>
+#include <nvif/event.h>
struct nvif_disp;
struct nvif_conn {
@@ -11,8 +12,17 @@ struct nvif_conn {
int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *);
void nvif_conn_dtor(struct nvif_conn *);
+static inline int
+nvif_conn_id(struct nvif_conn *conn)
+{
+ return conn->object.handle;
+}
+
#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */
#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1
#define NVIF_CONN_HPD_STATUS_PRESENT 2
int nvif_conn_hpd_status(struct nvif_conn *);
+
+int nvif_conn_event_ctor(struct nvif_conn *, const char *name, nvif_event_func, u8 types,
+ struct nvif_event *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/disp.h b/drivers/gpu/drm/nouveau/include/nvif/disp.h
index 742632ad3bea..56eb7293e01c 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/disp.h
@@ -7,6 +7,7 @@ struct nvif_disp {
struct nvif_object object;
unsigned long conn_mask;
unsigned long outp_mask;
+ unsigned long head_mask;
};
int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass,
diff --git a/drivers/gpu/drm/nouveau/include/nvif/event.h b/drivers/gpu/drm/nouveau/include/nvif/event.h
index a6b1ee4f10ca..68bf6635841f 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/event.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/event.h
@@ -1,63 +1,36 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_EVENT_H__
#define __NVIF_EVENT_H__
-
-struct nvif_notify_req_v0 {
- __u8 version;
- __u8 reply;
- __u8 pad02[5];
-#define NVIF_NOTIFY_V0_ROUTE_NVIF 0x00
- __u8 route;
- __u64 token; /* must be unique */
- __u8 data[]; /* request data (below) */
-};
-
-struct nvif_notify_rep_v0 {
- __u8 version;
- __u8 pad01[6];
- __u8 route;
- __u64 token;
- __u8 data[]; /* reply data (below) */
-};
-
-struct nvif_notify_head_req_v0 {
- /* nvif_notify_req ... */
- __u8 version;
- __u8 head;
- __u8 pad02[6];
-};
-
-struct nvif_notify_head_rep_v0 {
- /* nvif_notify_rep ... */
- __u8 version;
- __u8 pad01[7];
-};
-
-struct nvif_notify_conn_req_v0 {
- /* nvif_notify_req ... */
- __u8 version;
-#define NVIF_NOTIFY_CONN_V0_PLUG 0x01
-#define NVIF_NOTIFY_CONN_V0_UNPLUG 0x02
-#define NVIF_NOTIFY_CONN_V0_IRQ 0x04
-#define NVIF_NOTIFY_CONN_V0_ANY 0x07
- __u8 mask;
- __u8 conn;
- __u8 pad03[5];
-};
-
-struct nvif_notify_conn_rep_v0 {
- /* nvif_notify_rep ... */
- __u8 version;
- __u8 mask;
- __u8 pad02[6];
-};
-
-struct nvif_notify_uevent_req {
- /* nvif_notify_req ... */
-};
-
-struct nvif_notify_uevent_rep {
- /* nvif_notify_rep ... */
-};
-
+#include <nvif/object.h>
+#include <nvif/if000e.h>
+struct nvif_event;
+
+#define NVIF_EVENT_KEEP 0
+#define NVIF_EVENT_DROP 1
+typedef int (*nvif_event_func)(struct nvif_event *, void *repv, u32 repc);
+
+struct nvif_event {
+ struct nvif_object object;
+ nvif_event_func func;
+};
+
+static inline bool
+nvif_event_constructed(struct nvif_event *event)
+{
+ return nvif_object_constructed(&event->object);
+}
+
+int nvif_event_ctor_(struct nvif_object *, const char *, u32, nvif_event_func, bool,
+ struct nvif_event_v0 *, u32, bool, struct nvif_event *);
+
+static inline int
+nvif_event_ctor(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func,
+ bool wait, struct nvif_event_v0 *args, u32 argc, struct nvif_event *event)
+{
+ return nvif_event_ctor_(parent, name, handle, func, wait, args, argc, true, event);
+}
+
+void nvif_event_dtor(struct nvif_event *);
+int nvif_event_allow(struct nvif_event *);
+int nvif_event_block(struct nvif_event *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/head.h b/drivers/gpu/drm/nouveau/include/nvif/head.h
new file mode 100644
index 000000000000..3ec36999e956
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/head.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_HEAD_H__
+#define __NVIF_HEAD_H__
+#include <nvif/object.h>
+#include <nvif/event.h>
+struct nvif_disp;
+
+struct nvif_head {
+ struct nvif_object object;
+};
+
+int nvif_head_ctor(struct nvif_disp *, const char *name, int id, struct nvif_head *);
+void nvif_head_dtor(struct nvif_head *);
+
+static inline int
+nvif_head_id(struct nvif_head *head)
+{
+ return head->object.handle;
+}
+
+int nvif_head_vblank_event_ctor(struct nvif_head *, const char *name, nvif_event_func, bool wait,
+ struct nvif_event *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0004.h b/drivers/gpu/drm/nouveau/include/nvif/if0004.h
index d324c73c27fb..1d916a137941 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0004.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0004.h
@@ -2,7 +2,10 @@
#ifndef __NVIF_IF0004_H__
#define __NVIF_IF0004_H__
-#define NV04_NVSW_NTFY_UEVENT 0x00
+union nv04_nvsw_event_args {
+ struct nv04_nvsw_event_vn {
+ } vn;
+};
#define NV04_NVSW_GET_REF 0x00
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if000e.h b/drivers/gpu/drm/nouveau/include/nvif/if000e.h
new file mode 100644
index 000000000000..90a936cb1766
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if000e.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_IF000E_H__
+#define __NVIF_IF000E_H__
+
+union nvif_event_args {
+ struct nvif_event_v0 {
+ __u8 version;
+ __u8 wait;
+ __u8 pad02[6];
+ __u8 data[];
+ } v0;
+};
+
+#define NVIF_EVENT_V0_ALLOW 0x00
+#define NVIF_EVENT_V0_BLOCK 0x01
+
+union nvif_event_allow_args {
+ struct nvif_event_allow_vn {
+ } vn;
+};
+
+union nvif_event_block_args {
+ struct nvif_event_block_vn {
+ } vn;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0010.h b/drivers/gpu/drm/nouveau/include/nvif/if0010.h
index fc236ef28965..4c835bbe6fe3 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0010.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0010.h
@@ -8,6 +8,7 @@ union nvif_disp_args {
__u8 pad01[3];
__u32 conn_mask;
__u32 outp_mask;
+ __u32 head_mask;
} v0;
};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
index 04ba6581f840..69b0b779f942 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
@@ -10,6 +10,17 @@ union nvif_conn_args {
} v0;
};
+union nvif_conn_event_args {
+ struct nvif_conn_event_v0 {
+ __u8 version;
+#define NVIF_CONN_EVENT_V0_PLUG 0x01
+#define NVIF_CONN_EVENT_V0_UNPLUG 0x02
+#define NVIF_CONN_EVENT_V0_IRQ 0x04
+ __u8 types;
+ __u8 pad02[6];
+ } v0;
+};
+
#define NVIF_CONN_V0_HPD_STATUS 0x00000000
union nvif_conn_hpd_status_args {
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
index 243bd35d942f..eb99d84eb844 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
@@ -11,6 +11,13 @@ union nvif_outp_args {
};
#define NVIF_OUTP_V0_LOAD_DETECT 0x00
+#define NVIF_OUTP_V0_ACQUIRE 0x01
+#define NVIF_OUTP_V0_RELEASE 0x02
+#define NVIF_OUTP_V0_INFOFRAME 0x03
+#define NVIF_OUTP_V0_HDA_ELD 0x04
+#define NVIF_OUTP_V0_DP_AUX_PWR 0x05
+#define NVIF_OUTP_V0_DP_RETRAIN 0x06
+#define NVIF_OUTP_V0_DP_MST_VCPI 0x07
union nvif_outp_load_detect_args {
struct nvif_outp_load_detect_v0 {
@@ -20,4 +27,95 @@ union nvif_outp_load_detect_args {
__u32 data; /*TODO: move vbios loadval parsing into nvkm */
} v0;
};
+
+union nvif_outp_acquire_args {
+ struct nvif_outp_acquire_v0 {
+ __u8 version;
+#define NVIF_OUTP_ACQUIRE_V0_RGB_CRT 0x00
+#define NVIF_OUTP_ACQUIRE_V0_TV 0x01
+#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02
+#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03
+#define NVIF_OUTP_ACQUIRE_V0_DP 0x04
+ __u8 proto;
+ __u8 or;
+ __u8 link;
+ __u8 pad04[4];
+ union {
+ struct {
+ __u8 head;
+ __u8 hdmi;
+ __u8 hdmi_max_ac_packet;
+ __u8 hdmi_rekey;
+#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0)
+#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1)
+ __u8 hdmi_scdc;
+ __u8 hdmi_hda;
+ __u8 pad06[2];
+ } tmds;
+ struct {
+ __u8 dual;
+ __u8 bpc8;
+ __u8 pad02[6];
+ } lvds;
+ struct {
+ __u8 link_nr; /* 0 = highest possible. */
+ __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */
+ __u8 hda;
+ __u8 mst;
+ __u8 pad04[4];
+ __u8 dpcd[16];
+ } dp;
+ };
+ } v0;
+};
+
+union nvif_outp_release_args {
+ struct nvif_outp_release_vn {
+ } vn;
+};
+
+union nvif_outp_infoframe_args {
+ struct nvif_outp_infoframe_v0 {
+ __u8 version;
+#define NVIF_OUTP_INFOFRAME_V0_AVI 0
+#define NVIF_OUTP_INFOFRAME_V0_VSI 1
+ __u8 type;
+ __u8 head;
+ __u8 pad03[5];
+ __u8 data[];
+ } v0;
+};
+
+union nvif_outp_hda_eld_args {
+ struct nvif_outp_hda_eld_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+ __u8 data[];
+ } v0;
+};
+
+union nvif_outp_dp_aux_pwr_args {
+ struct nvif_outp_dp_aux_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 pad02[6];
+ } v0;
+};
+
+union nvif_outp_dp_retrain_args {
+ struct nvif_outp_dp_retrain_vn {
+ } vn;
+};
+
+union nvif_outp_dp_mst_vcpi_args {
+ struct nvif_outp_dp_mst_vcpi_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 start_slot;
+ __u8 num_slots;
+ __u16 pbn;
+ __u16 aligned_pbn;
+ } v0;
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0013.h b/drivers/gpu/drm/nouveau/include/nvif/if0013.h
new file mode 100644
index 000000000000..6756c7467ae4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0013.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_IF0013_H__
+#define __NVIF_IF0013_H__
+
+union nvif_head_args {
+ struct nvif_head_v0 {
+ __u8 version;
+ __u8 id;
+ __u8 pad02[6];
+ } v0;
+};
+
+union nvif_head_event_args {
+ struct nvif_head_event_vn {
+ } vn;
+};
+
+#define NVIF_HEAD_V0_SCANOUTPOS 0x00
+
+union nvif_head_scanoutpos_args {
+ struct nvif_head_scanoutpos_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __s64 time[2];
+ __u16 vblanks;
+ __u16 vblanke;
+ __u16 vtotal;
+ __u16 vline;
+ __u16 hblanks;
+ __u16 hblanke;
+ __u16 htotal;
+ __u16 hline;
+ } v0;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0020.h b/drivers/gpu/drm/nouveau/include/nvif/if0020.h
new file mode 100644
index 000000000000..085e0ae8a450
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0020.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_IF0020_H__
+#define __NVIF_IF0020_H__
+
+union nvif_chan_args {
+ struct nvif_chan_v0 {
+ __u8 version;
+ __u8 namelen;
+ __u8 runlist;
+ __u8 runq;
+ __u8 priv;
+ __u8 pad05;
+ __u16 devm;
+ __u64 vmm;
+
+ __u64 ctxdma;
+ __u64 offset;
+ __u64 length;
+
+ __u64 huserd;
+ __u64 ouserd;
+
+ __u32 token;
+ __u16 chid;
+ __u8 pad3e;
+#define NVIF_CHAN_V0_INST_APER_VRAM 0
+#define NVIF_CHAN_V0_INST_APER_HOST 1
+#define NVIF_CHAN_V0_INST_APER_NCOH 2
+#define NVIF_CHAN_V0_INST_APER_INST 0xff
+ __u8 aper;
+ __u64 inst;
+
+ __u8 name[];
+ } v0;
+};
+
+union nvif_chan_event_args {
+ struct nvif_chan_event_v0 {
+ __u8 version;
+#define NVIF_CHAN_EVENT_V0_NON_STALL_INTR 0x00
+#define NVIF_CHAN_EVENT_V0_KILLED 0x01
+ __u8 type;
+ } v0;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0021.h b/drivers/gpu/drm/nouveau/include/nvif/if0021.h
new file mode 100644
index 000000000000..5013def90455
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0021.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_IF0021_H__
+#define __NVIF_IF0021_H__
+
+union nvif_cgrp_args {
+ struct nvif_cgrp_v0 {
+ __u8 version;
+ __u8 namelen;
+ __u8 runlist;
+ __u8 pad03[3];
+ __u16 cgid;
+ __u64 vmm;
+ __u8 name[];
+ } v0;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
index 886c63fe753f..4e047bb1fc07 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
@@ -15,10 +15,6 @@ struct nvif_ioctl_v0 {
#define NVIF_IOCTL_V0_WR 0x06
#define NVIF_IOCTL_V0_MAP 0x07
#define NVIF_IOCTL_V0_UNMAP 0x08
-#define NVIF_IOCTL_V0_NTFY_NEW 0x09
-#define NVIF_IOCTL_V0_NTFY_DEL 0x0a
-#define NVIF_IOCTL_V0_NTFY_GET 0x0b
-#define NVIF_IOCTL_V0_NTFY_PUT 0x0c
__u8 type;
__u8 pad02[4];
#define NVIF_IOCTL_V0_OWNER_NVIF 0x00
@@ -63,6 +59,14 @@ struct nvif_ioctl_new_v0 {
struct nvif_ioctl_del {
};
+struct nvif_ioctl_mthd_v0 {
+ /* nvif_ioctl ... */
+ __u8 version;
+ __u8 method;
+ __u8 pad02[6];
+ __u8 data[]; /* method data (class.h) */
+};
+
struct nvif_ioctl_rd_v0 {
/* nvif_ioctl ... */
__u8 version;
@@ -95,43 +99,4 @@ struct nvif_ioctl_map_v0 {
struct nvif_ioctl_unmap {
};
-
-struct nvif_ioctl_ntfy_new_v0 {
- /* nvif_ioctl ... */
- __u8 version;
- __u8 event;
- __u8 index;
- __u8 pad03[5];
- __u8 data[]; /* event request data (event.h) */
-};
-
-struct nvif_ioctl_ntfy_del_v0 {
- /* nvif_ioctl ... */
- __u8 version;
- __u8 index;
- __u8 pad02[6];
-};
-
-struct nvif_ioctl_ntfy_get_v0 {
- /* nvif_ioctl ... */
- __u8 version;
- __u8 index;
- __u8 pad02[6];
-};
-
-struct nvif_ioctl_ntfy_put_v0 {
- /* nvif_ioctl ... */
- __u8 version;
- __u8 index;
- __u8 pad02[6];
-};
-
-struct nvif_ioctl_mthd_v0 {
- /* nvif_ioctl ... */
- __u8 version;
- __u8 method;
- __u8 pad02[6];
- __u8 data[]; /* method data (class.h) */
-};
-
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/notify.h b/drivers/gpu/drm/nouveau/include/nvif/notify.h
deleted file mode 100644
index 39f6b7ee1719..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/notify.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_NOTIFY_H__
-#define __NVIF_NOTIFY_H__
-
-struct nvif_notify {
- struct nvif_object *object;
- const char *name;
- int index;
-
-#define NVIF_NOTIFY_USER 0
-#define NVIF_NOTIFY_WORK 1
- unsigned long flags;
- atomic_t putcnt;
- void (*dtor)(struct nvif_notify *);
-#define NVIF_NOTIFY_DROP 0
-#define NVIF_NOTIFY_KEEP 1
- int (*func)(struct nvif_notify *);
-
- /* this is const for a *very* good reason - the data might be on the
- * stack from an irq handler. if you're not nvif/notify.c then you
- * should probably think twice before casting it away...
- */
- const void *data;
- u32 size;
- struct work_struct work;
-};
-
-int nvif_notify_ctor(struct nvif_object *, const char *name,
- int (*func)(struct nvif_notify *), bool work, u8 type,
- void *data, u32 size, u32 reply, struct nvif_notify *);
-int nvif_notify_dtor(struct nvif_notify *);
-int nvif_notify_get(struct nvif_notify *);
-int nvif_notify_put(struct nvif_notify *);
-int nvif_notify(const void *, u32, const void *, u32);
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h
index 0d6aa07a9184..45daadec3c0c 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/outp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h
@@ -2,13 +2,32 @@
#ifndef __NVIF_OUTP_H__
#define __NVIF_OUTP_H__
#include <nvif/object.h>
+#include <nvif/if0012.h>
struct nvif_disp;
struct nvif_outp {
struct nvif_object object;
+
+ struct {
+ int id;
+ int link;
+ } or;
};
int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *);
void nvif_outp_dtor(struct nvif_outp *);
int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
+int nvif_outp_acquire_rgb_crt(struct nvif_outp *);
+int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
+ bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda);
+int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
+int nvif_outp_acquire_dp(struct nvif_outp *, u8 dpcd[16],
+ int link_nr, int link_bw, bool hda, bool mst);
+void nvif_outp_release(struct nvif_outp *);
+int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
+int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
+int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable);
+int nvif_outp_dp_retrain(struct nvif_outp *);
+int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head,
+ u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
index 2f86606e708c..0d9fc741a719 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
@@ -10,28 +10,19 @@ struct nvkm_client {
u64 device;
u32 debug;
- struct nvkm_client_notify *notify[32];
struct rb_root objroot;
void *data;
- int (*ntfy)(const void *, u32, const void *, u32);
+ int (*event)(u64 token, void *argv, u32 argc);
struct list_head umem;
spinlock_t lock;
};
-int nvkm_client_new(const char *name, u64 device, const char *cfg,
- const char *dbg,
- int (*)(const void *, u32, const void *, u32),
- struct nvkm_client **);
+int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
+ int (*)(u64, void *, u32), struct nvkm_client **);
struct nvkm_client *nvkm_client_search(struct nvkm_client *, u64 handle);
-int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *,
- void *data, u32 size);
-int nvkm_client_notify_del(struct nvkm_client *, int index);
-int nvkm_client_notify_get(struct nvkm_client *, int index);
-int nvkm_client_notify_put(struct nvkm_client *, int index);
-
/* logging for client-facing objects */
#define nvif_printk(o,l,p,f,a...) do { \
const struct nvkm_object *_object = (o); \
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
index efede1f11e1d..f65b5009acf7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -2,6 +2,7 @@
#ifndef __NVKM_DEVICE_H__
#define __NVKM_DEVICE_H__
#include <core/oclass.h>
+#include <core/intr.h>
enum nvkm_subdev_type;
enum nvkm_device_type {
@@ -60,6 +61,16 @@ struct nvkm_device {
#undef NVKM_LAYOUT_INST
#undef NVKM_LAYOUT_ONCE
struct list_head subdev;
+
+ struct {
+ struct list_head intr;
+ struct list_head prio[NVKM_INTR_PRIO_NR];
+ spinlock_t lock;
+ int irq;
+ bool alloc;
+ bool armed;
+ bool legacy_done;
+ } intr;
};
struct nvkm_subdev *nvkm_device_subdev(struct nvkm_device *, int type, int inst);
@@ -72,6 +83,7 @@ struct nvkm_device_func {
int (*preinit)(struct nvkm_device *);
int (*init)(struct nvkm_device *);
void (*fini)(struct nvkm_device *, bool suspend);
+ int (*irq)(struct nvkm_device *);
resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar);
resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar);
bool cpu_coherent;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
index e58923b67d74..b67b9c1a6b4e 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
@@ -12,12 +12,6 @@ struct nvkm_engine {
const struct nvkm_engine_func *func;
struct nvkm_subdev subdev;
spinlock_t lock;
-
- struct {
- refcount_t refcount;
- struct mutex mutex;
- bool enabled;
- } use;
};
struct nvkm_engine_func {
@@ -27,6 +21,7 @@ struct nvkm_engine_func {
int (*info)(struct nvkm_engine *, u64 mthd, u64 *data);
int (*init)(struct nvkm_engine *);
int (*fini)(struct nvkm_engine *, bool suspend);
+ int (*reset)(struct nvkm_engine *);
void (*intr)(struct nvkm_engine *);
void (*tile)(struct nvkm_engine *, int region, struct nvkm_fb_tile *);
bool (*chsw_load)(struct nvkm_engine *);
@@ -54,6 +49,7 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *,
struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *);
void nvkm_engine_unref(struct nvkm_engine **);
+int nvkm_engine_reset(struct nvkm_engine *);
void nvkm_engine_tile(struct nvkm_engine *, int region);
bool nvkm_engine_chsw_load(struct nvkm_engine *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
index a7a413f07a78..82b267c11147 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
@@ -2,34 +2,76 @@
#ifndef __NVKM_EVENT_H__
#define __NVKM_EVENT_H__
#include <core/os.h>
-struct nvkm_notify;
struct nvkm_object;
+struct nvkm_oclass;
+struct nvkm_uevent;
struct nvkm_event {
const struct nvkm_event_func *func;
+ struct nvkm_subdev *subdev;
int types_nr;
int index_nr;
spinlock_t refs_lock;
spinlock_t list_lock;
- struct list_head list;
int *refs;
+
+ struct list_head ntfy;
};
struct nvkm_event_func {
- int (*ctor)(struct nvkm_object *, void *data, u32 size,
- struct nvkm_notify *);
- void (*send)(void *data, u32 size, struct nvkm_notify *);
void (*init)(struct nvkm_event *, int type, int index);
void (*fini)(struct nvkm_event *, int type, int index);
};
-int nvkm_event_init(const struct nvkm_event_func *func, int types_nr,
- int index_nr, struct nvkm_event *);
+int __nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *, int types_nr,
+ int index_nr, struct nvkm_event *);
+
+/* Each nvkm_event needs its own lockdep class due to inter-dependencies, to
+ * prevent lockdep false-positives.
+ *
+ * Inlining the spinlock initialisation ensures each is unique.
+ */
+static __always_inline int
+nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev,
+ int types_nr, int index_nr, struct nvkm_event *event)
+{
+ spin_lock_init(&event->refs_lock);
+ spin_lock_init(&event->list_lock);
+ return __nvkm_event_init(func, subdev, types_nr, index_nr, event);
+}
+
void nvkm_event_fini(struct nvkm_event *);
-void nvkm_event_get(struct nvkm_event *, u32 types, int index);
-void nvkm_event_put(struct nvkm_event *, u32 types, int index);
-void nvkm_event_send(struct nvkm_event *, u32 types, int index,
- void *data, u32 size);
+
+#define NVKM_EVENT_KEEP 0
+#define NVKM_EVENT_DROP 1
+struct nvkm_event_ntfy;
+typedef int (*nvkm_event_func)(struct nvkm_event_ntfy *, u32 bits);
+
+struct nvkm_event_ntfy {
+ struct nvkm_event *event;
+ int id;
+ u32 bits;
+ bool wait;
+ nvkm_event_func func;
+
+ atomic_t allowed;
+ bool running;
+
+ struct list_head head;
+};
+
+void nvkm_event_ntfy(struct nvkm_event *, int id, u32 bits);
+bool nvkm_event_ntfy_valid(struct nvkm_event *, int id, u32 bits);
+void nvkm_event_ntfy_add(struct nvkm_event *, int id, u32 bits, bool wait, nvkm_event_func,
+ struct nvkm_event_ntfy *);
+void nvkm_event_ntfy_del(struct nvkm_event_ntfy *);
+void nvkm_event_ntfy_allow(struct nvkm_event_ntfy *);
+void nvkm_event_ntfy_block(struct nvkm_event_ntfy *);
+
+typedef int (*nvkm_uevent_func)(struct nvkm_object *, u64 token, u32 bits);
+
+int nvkm_uevent_new(const struct nvkm_oclass *, void *argv, u32 argc, struct nvkm_object **);
+int nvkm_uevent_add(struct nvkm_uevent *, struct nvkm_event *, int id, u32 bits, nvkm_uevent_func);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
index fd9a3f9a518e..b857cf142c4a 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
@@ -1,34 +1,166 @@
#ifndef __NVKM_FALCON_H__
#define __NVKM_FALCON_H__
+#include <core/firmware.h>
#include <engine/falcon.h>
+enum nvkm_falcon_mem {
+ IMEM,
+ DMEM,
+ EMEM,
+};
+
+static inline const char *
+nvkm_falcon_mem(enum nvkm_falcon_mem mem)
+{
+ switch (mem) {
+ case IMEM: return "imem";
+ case DMEM: return "dmem";
+ case EMEM: return "emem";
+ default:
+ WARN_ON(1);
+ return "?mem";
+ }
+}
+
+struct nvkm_falcon_func_pio {
+ int min;
+ int max;
+ void (*wr_init)(struct nvkm_falcon *, u8 port, bool sec, u32 mem_base);
+ void (*wr)(struct nvkm_falcon *, u8 port, const u8 *img, int len, u16 tag);
+ void (*rd_init)(struct nvkm_falcon *, u8 port, u32 mem_base);
+ void (*rd)(struct nvkm_falcon *, u8 port, const u8 *img, int len);
+};
+
+struct nvkm_falcon_func_dma {
+ int (*init)(struct nvkm_falcon *, u64 dma_addr, int xfer_len,
+ enum nvkm_falcon_mem, bool sec, u32 *cmd);
+ void (*xfer)(struct nvkm_falcon *, u32 mem_base, u32 dma_base, u32 cmd);
+ bool (*done)(struct nvkm_falcon *);
+};
+
int nvkm_falcon_ctor(const struct nvkm_falcon_func *, struct nvkm_subdev *owner,
const char *name, u32 addr, struct nvkm_falcon *);
void nvkm_falcon_dtor(struct nvkm_falcon *);
+int nvkm_falcon_reset(struct nvkm_falcon *);
+int nvkm_falcon_pio_wr(struct nvkm_falcon *, const u8 *img, u32 img_base, u8 port,
+ enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec);
+int nvkm_falcon_pio_rd(struct nvkm_falcon *, u8 port, enum nvkm_falcon_mem type, u32 mem_base,
+ const u8 *img, u32 img_base, int len);
+int nvkm_falcon_dma_wr(struct nvkm_falcon *, const u8 *img, u64 dma_addr, u32 dma_base,
+ enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec);
+
+int gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
+int gm200_flcn_disable(struct nvkm_falcon *);
+int gm200_flcn_enable(struct nvkm_falcon *);
+void gm200_flcn_bind_inst(struct nvkm_falcon *, int, u64);
+int gm200_flcn_bind_stat(struct nvkm_falcon *, bool);
+extern const struct nvkm_falcon_func_pio gm200_flcn_imem_pio;
+extern const struct nvkm_falcon_func_pio gm200_flcn_dmem_pio;
+void gm200_flcn_tracepc(struct nvkm_falcon *);
+
+int gp102_flcn_reset_eng(struct nvkm_falcon *);
+extern const struct nvkm_falcon_func_pio gp102_flcn_emem_pio;
+
+int ga102_flcn_select(struct nvkm_falcon *);
+int ga102_flcn_reset_prep(struct nvkm_falcon *);
+int ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
+extern const struct nvkm_falcon_func_dma ga102_flcn_dma;
void nvkm_falcon_v1_load_imem(struct nvkm_falcon *,
void *, u32, u32, u16, u8, bool);
void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8);
-void nvkm_falcon_v1_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *);
-void nvkm_falcon_v1_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
-int nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *, u32);
-int nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *, u32);
-void nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *, u32 start_addr);
void nvkm_falcon_v1_start(struct nvkm_falcon *);
-int nvkm_falcon_v1_enable(struct nvkm_falcon *);
-void nvkm_falcon_v1_disable(struct nvkm_falcon *);
-void gp102_sec2_flcn_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
-int gp102_sec2_flcn_enable(struct nvkm_falcon *);
+#define FLCN_PRINTK(f,l,p,fmt,a...) ({ \
+ if ((f)->owner->name != (f)->name) \
+ nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, "%s:"fmt, (f)->name, ##a); \
+ else \
+ nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, fmt, ##a); \
+})
+#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK((f), DEBUG, info, " "fmt"\n", ##a)
+#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK((f), ERROR, err, " "fmt"\n", ##a)
+#define FLCN_ERRON(f,c,fmt,a...) \
+ ({ bool _cond = (c); _cond ? FLCN_ERR(f, fmt, ##a) : FLCN_DBG(f, fmt, ##a); _cond; })
+
+
+struct nvkm_falcon_fw {
+ const struct nvkm_falcon_fw_func {
+ int (*signature)(struct nvkm_falcon_fw *, u32 *sig_base_src);
+ int (*reset)(struct nvkm_falcon_fw *);
+ int (*setup)(struct nvkm_falcon_fw *);
+ int (*load)(struct nvkm_falcon_fw *);
+ int (*load_bld)(struct nvkm_falcon_fw *);
+ int (*boot)(struct nvkm_falcon_fw *,
+ u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr);
+ } *func;
+ struct nvkm_firmware fw;
+
+ u32 sig_base_prd;
+ u32 sig_base_dbg;
+ u32 sig_base_img;
+ u32 sig_size;
+ int sig_nr;
+ u8 *sigs;
+ u32 fuse_ver;
+ u32 engine_id;
+ u32 ucode_id;
+
+ u32 nmem_base_img;
+ u32 nmem_base;
+ u32 nmem_size;
+
+ u32 imem_base_img;
+ u32 imem_base;
+ u32 imem_size;
+
+ u32 dmem_base_img;
+ u32 dmem_base;
+ u32 dmem_size;
+ u32 dmem_sign;
+
+ u8 *boot;
+ u32 boot_size;
+ u32 boot_addr;
+
+ struct nvkm_falcon *falcon;
+ struct nvkm_memory *inst;
+ struct nvkm_vmm *vmm;
+ struct nvkm_vma *vma;
+};
+
+int nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *, const char *name, struct nvkm_device *,
+ bool bl, const void *src, u32 len, struct nvkm_falcon *,
+ struct nvkm_falcon_fw *);
+int nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *, const char *name,
+ struct nvkm_subdev *, const char *bl, const char *img, int ver,
+ struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw);
+int nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *, const char *name,
+ struct nvkm_subdev *, const char *img, int ver, struct nvkm_falcon *,
+ struct nvkm_falcon_fw *);
+int nvkm_falcon_fw_sign(struct nvkm_falcon_fw *, u32 sig_base_img, u32 sig_size, const u8 *sigs,
+ int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg);
+int nvkm_falcon_fw_patch(struct nvkm_falcon_fw *);
+void nvkm_falcon_fw_dtor(struct nvkm_falcon_fw *);
+int nvkm_falcon_fw_oneinit(struct nvkm_falcon_fw *, struct nvkm_falcon *, struct nvkm_vmm *,
+ struct nvkm_memory *inst);
+int nvkm_falcon_fw_boot(struct nvkm_falcon_fw *, struct nvkm_subdev *user,
+ bool release, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr);
+
+extern const struct nvkm_falcon_fw_func gm200_flcn_fw;
+int gm200_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *);
+int gm200_flcn_fw_reset(struct nvkm_falcon_fw *);
+int gm200_flcn_fw_load(struct nvkm_falcon_fw *);
+int gm200_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
+
+int ga100_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *);
+
+extern const struct nvkm_falcon_fw_func ga102_flcn_fw;
+int ga102_flcn_fw_load(struct nvkm_falcon_fw *);
+int ga102_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
-#define FLCN_PRINTK(t,f,fmt,a...) do { \
- if ((f)->owner->name != (f)->name) \
- nvkm_##t((f)->owner, "%s: "fmt"\n", (f)->name, ##a); \
- else \
- nvkm_##t((f)->owner, fmt"\n", ##a); \
-} while(0)
-#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK(debug, (f), fmt, ##a)
-#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK(error, (f), fmt, ##a)
+#define FLCNFW_PRINTK(f,l,p,fmt,a...) FLCN_PRINTK((f)->falcon, l, p, "%s: "fmt, (f)->fw.name, ##a)
+#define FLCNFW_DBG(f,fmt,a...) FLCNFW_PRINTK((f), DEBUG, info, fmt"\n", ##a)
+#define FLCNFW_ERR(f,fmt,a...) FLCNFW_PRINTK((f), ERROR, err, fmt"\n", ##a)
/**
* struct nvfw_falcon_msg - header for all messages
@@ -72,6 +204,7 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name,
void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **);
void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
u32 index, u32 offset, u32 size);
+bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *);
int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size);
void nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
index 85bcb80f6873..d4e507e252b1 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
@@ -1,9 +1,34 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FIRMWARE_H__
#define __NVKM_FIRMWARE_H__
+#include <core/memory.h>
#include <core/option.h>
#include <core/subdev.h>
+struct nvkm_firmware {
+ const struct nvkm_firmware_func {
+ enum nvkm_firmware_type {
+ NVKM_FIRMWARE_IMG_RAM,
+ NVKM_FIRMWARE_IMG_DMA,
+ } type;
+ } *func;
+ const char *name;
+ struct nvkm_device *device;
+
+ int len;
+ u8 *img;
+ u64 phys;
+
+ struct nvkm_firmware_mem {
+ struct nvkm_memory memory;
+ struct scatterlist sgl;
+ } mem;
+};
+
+int nvkm_firmware_ctor(const struct nvkm_firmware_func *, const char *name, struct nvkm_device *,
+ const void *ptr, int len, struct nvkm_firmware *);
+void nvkm_firmware_dtor(struct nvkm_firmware *);
+
int nvkm_firmware_get(const struct nvkm_subdev *, const char *fwname, int ver,
const struct firmware **);
void nvkm_firmware_put(const struct firmware *);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h
new file mode 100644
index 000000000000..a003d6a544b0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_INTR_H__
+#define __NVKM_INTR_H__
+#include <core/os.h>
+struct nvkm_device;
+struct nvkm_subdev;
+
+enum nvkm_intr_prio {
+ NVKM_INTR_PRIO_VBLANK = 0,
+ NVKM_INTR_PRIO_NORMAL,
+ NVKM_INTR_PRIO_NR
+};
+
+enum nvkm_intr_type {
+ NVKM_INTR_SUBDEV = -1, /* lookup vector by requesting subdev, in mapping table. */
+ NVKM_INTR_VECTOR_0 = 0,
+};
+
+struct nvkm_intr {
+ const struct nvkm_intr_func {
+ bool (*pending)(struct nvkm_intr *);
+ void (*unarm)(struct nvkm_intr *);
+ void (*rearm)(struct nvkm_intr *);
+ void (*block)(struct nvkm_intr *, int leaf, u32 mask);
+ void (*allow)(struct nvkm_intr *, int leaf, u32 mask);
+ void (*reset)(struct nvkm_intr *, int leaf, u32 mask);
+ } *func;
+ const struct nvkm_intr_data {
+ int type; /* enum nvkm_subdev_type (+ve), enum nvkm_intr_type (-ve) */
+ int inst;
+ int leaf;
+ u32 mask; /* 0-terminated. */
+ bool legacy; /* auto-create "legacy" nvkm_subdev_intr() handler */
+ } *data;
+
+ struct nvkm_subdev *subdev;
+ int leaves;
+ u32 *stat;
+ u32 *mask;
+
+ struct list_head head;
+};
+
+void nvkm_intr_ctor(struct nvkm_device *);
+void nvkm_intr_dtor(struct nvkm_device *);
+int nvkm_intr_install(struct nvkm_device *);
+void nvkm_intr_unarm(struct nvkm_device *);
+void nvkm_intr_rearm(struct nvkm_device *);
+
+int nvkm_intr_add(const struct nvkm_intr_func *, const struct nvkm_intr_data *,
+ struct nvkm_subdev *, int leaves, struct nvkm_intr *);
+void nvkm_intr_block(struct nvkm_subdev *, enum nvkm_intr_type);
+void nvkm_intr_allow(struct nvkm_subdev *, enum nvkm_intr_type);
+
+struct nvkm_inth;
+typedef irqreturn_t (*nvkm_inth_func)(struct nvkm_inth *);
+
+struct nvkm_inth {
+ struct nvkm_intr *intr;
+ int leaf;
+ u32 mask;
+ nvkm_inth_func func;
+
+ atomic_t allowed;
+
+ struct list_head head;
+};
+
+int nvkm_inth_add(struct nvkm_intr *, enum nvkm_intr_type, enum nvkm_intr_prio,
+ struct nvkm_subdev *, nvkm_inth_func, struct nvkm_inth *);
+void nvkm_inth_allow(struct nvkm_inth *);
+void nvkm_inth_block(struct nvkm_inth *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
index 7afe1579b20f..58108dea5aeb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
@@ -1,8 +1,10 @@
/* SPDX-License-Identifier: MIT */
+NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top)
+NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp)
+NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VFN , struct nvkm_vfn , vfn)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PCI , struct nvkm_pci , pci)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VBIOS , struct nvkm_bios , bios)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_DEVINIT , struct nvkm_devinit , devinit)
-NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PRIVRING, struct nvkm_subdev , privring)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GPIO , struct nvkm_gpio , gpio)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_I2C , struct nvkm_i2c , i2c)
@@ -23,7 +25,6 @@ NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VOLT , struct nvkm_volt , volt)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_ICCSENSE, struct nvkm_iccsense, iccsense)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_THERM , struct nvkm_therm , therm)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_CLK , struct nvkm_clk , clk)
-NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp)
NVKM_LAYOUT_INST(NVKM_SUBDEV_IOCTRL , struct nvkm_subdev , ioctrl, 3)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_FLA , struct nvkm_subdev , fla)
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
index 74d3f1a809d7..d3b6a68ddda3 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
@@ -37,6 +37,7 @@ struct nvkm_memory_func {
void (*release)(struct nvkm_memory *);
int (*map)(struct nvkm_memory *, u64 offset, struct nvkm_vmm *,
struct nvkm_vma *, void *argv, u32 argc);
+ int (*kmap)(struct nvkm_memory *, struct nvkm_memory **);
};
struct nvkm_memory_ptrs {
@@ -63,6 +64,7 @@ void nvkm_memory_tags_put(struct nvkm_memory *, struct nvkm_device *,
#define nvkm_memory_boot(p,v) (p)->func->boot((p),(v))
#define nvkm_memory_map(p,o,vm,va,av,ac) \
(p)->func->map((p),(o),(vm),(va),(av),(ac))
+#define nvkm_memory_kmap(p,i) ((p)->func->kmap ? (p)->func->kmap((p), (i)) : -ENOSYS)
/* accessor macros - kmap()/done() must bracket use of the other accessor
* macros to guarantee correct behaviour across all chipsets
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
deleted file mode 100644
index 3d358a66db3a..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVKM_NOTIFY_H__
-#define __NVKM_NOTIFY_H__
-#include <core/os.h>
-struct nvkm_object;
-
-struct nvkm_notify {
- struct nvkm_event *event;
- struct list_head head;
-#define NVKM_NOTIFY_USER 0
-#define NVKM_NOTIFY_WORK 1
- unsigned long flags;
- int block;
-#define NVKM_NOTIFY_DROP 0
-#define NVKM_NOTIFY_KEEP 1
- int (*func)(struct nvkm_notify *);
-
- /* set by nvkm_event ctor */
- u32 types;
- int index;
- u32 size;
-
- struct work_struct work;
- /* this is const for a *very* good reason - the data might be on the
- * stack from an irq handler. if you're not core/notify.c then you
- * should probably think twice before casting it away...
- */
- const void *data;
-};
-
-int nvkm_notify_init(struct nvkm_object *, struct nvkm_event *,
- int (*func)(struct nvkm_notify *), bool work,
- void *data, u32 size, u32 reply,
- struct nvkm_notify *);
-void nvkm_notify_fini(struct nvkm_notify *);
-void nvkm_notify_get(struct nvkm_notify *);
-void nvkm_notify_put(struct nvkm_notify *);
-void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
index 7efcd5d2f2ff..ed1f66360782 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
@@ -4,6 +4,7 @@
#include <core/oclass.h>
struct nvkm_event;
struct nvkm_gpuobj;
+struct nvkm_uevent;
struct nvkm_object {
const struct nvkm_object_func *func;
@@ -43,6 +44,7 @@ struct nvkm_object_func {
int (*bind)(struct nvkm_object *, struct nvkm_gpuobj *, int align,
struct nvkm_gpuobj **);
int (*sclass)(struct nvkm_object *, int index, struct nvkm_oclass *);
+ int (*uevent)(struct nvkm_object *, void *argv, u32 argc, struct nvkm_uevent *);
};
void nvkm_object_ctor(const struct nvkm_object_func *,
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
index d7ba3205207f..4486d9862849 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
@@ -34,4 +34,24 @@ nvkm_blob_dtor(struct nvkm_blob *blob)
blob->data = NULL;
blob->size = 0;
}
+
+#define nvkm_list_find_next(p,h,m,c) ({ \
+ typeof(p) _p = NULL; \
+ list_for_each_entry_continue(p, (h), m) { \
+ if (c) { \
+ _p = p; \
+ break; \
+ } \
+ } \
+ _p; \
+})
+#define nvkm_list_find(p,h,m,c) \
+ (p = container_of((h), typeof(*p), m), nvkm_list_find_next(p, (h), m, (c)))
+#define nvkm_list_foreach(p,h,m,c) \
+ for (p = nvkm_list_find(p, (h), m, (c)); p; p = nvkm_list_find_next(p, (h), m, (c)))
+
+/*FIXME: remove after */
+#define nvkm_fifo_chan nvkm_chan
+#define nvkm_fifo_chan_func nvkm_chan_func
+#define nvkm_fifo_cgrp nvkm_cgrp
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
index 96113c8bee8c..bce6e1ba09ea 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
@@ -17,10 +17,19 @@ struct nvkm_subdev {
struct nvkm_device *device;
enum nvkm_subdev_type type;
int inst;
+
char name[16];
u32 debug;
- struct list_head head;
+ struct {
+ refcount_t refcount;
+ struct mutex mutex;
+ bool enabled;
+ } use;
+
+ struct nvkm_inth inth;
+
+ struct list_head head;
void **pself;
bool oneinit;
};
@@ -38,22 +47,41 @@ struct nvkm_subdev_func {
extern const char *nvkm_subdev_type[NVKM_SUBDEV_NR];
int nvkm_subdev_new_(const struct nvkm_subdev_func *, struct nvkm_device *, enum nvkm_subdev_type,
int inst, struct nvkm_subdev **);
-void nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *,
- enum nvkm_subdev_type, int inst, struct nvkm_subdev *);
+void __nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *,
+ enum nvkm_subdev_type, int inst, struct nvkm_subdev *);
+
+static inline void
+nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)
+{
+ __nvkm_subdev_ctor(func, device, type, inst, subdev);
+ mutex_init(&subdev->use.mutex);
+}
+
void nvkm_subdev_disable(struct nvkm_device *, enum nvkm_subdev_type, int inst);
void nvkm_subdev_del(struct nvkm_subdev **);
+int nvkm_subdev_ref(struct nvkm_subdev *);
+void nvkm_subdev_unref(struct nvkm_subdev *);
int nvkm_subdev_preinit(struct nvkm_subdev *);
+int nvkm_subdev_oneinit(struct nvkm_subdev *);
int nvkm_subdev_init(struct nvkm_subdev *);
int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend);
int nvkm_subdev_info(struct nvkm_subdev *, u64, u64 *);
void nvkm_subdev_intr(struct nvkm_subdev *);
/* subdev logging */
-#define nvkm_printk_(s,l,p,f,a...) do { \
- const struct nvkm_subdev *_subdev = (s); \
- if (CONFIG_NOUVEAU_DEBUG >= (l) && _subdev->debug >= (l)) \
- dev_##p(_subdev->device->dev, "%s: "f, _subdev->name, ##a); \
+#define nvkm_printk_ok(s,u,l) \
+ ((CONFIG_NOUVEAU_DEBUG >= (l)) && ((s)->debug >= (l) || ((u) && (u)->debug >= (l))))
+#define nvkm_printk___(s,u,l,p,f,a...) do { \
+ if (nvkm_printk_ok((s), (u), (l))) { \
+ if ((u) && (u) != (s)) \
+ dev_##p((s)->device->dev, "%s(%s):"f, (s)->name, (u)->name, ##a); \
+ else \
+ dev_##p((s)->device->dev, "%s:"f, (s)->name, ##a); \
+ } \
} while(0)
+#define nvkm_printk__(s,l,p,f,a...) nvkm_printk___((s), (s), (l), p, f, ##a)
+#define nvkm_printk_(s,l,p,f,a...) nvkm_printk__((s), (l), p, " "f, ##a)
#define nvkm_printk(s,l,p,f,a...) nvkm_printk_((s), NV_DBG_##l, p, f, ##a)
#define nvkm_fatal(s,f,a...) nvkm_printk((s), FATAL, crit, f, ##a)
#define nvkm_error(s,f,a...) nvkm_printk((s), ERROR, err, f, ##a)
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
index 924009dd2bb0..ccee53d4e4ec 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
@@ -8,7 +8,6 @@ struct nvkm_device_tegra {
const struct nvkm_device_tegra_func *func;
struct nvkm_device device;
struct platform_device *pdev;
- int irq;
struct reset_control *rst;
struct clk *clk;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
index cfd2da8e66fe..b616a1e8ca02 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
@@ -12,4 +12,6 @@ int gp100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gp102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int gv100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int tu102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
+int ga100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
+int ga102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 8b5d8a434be8..ad9aef2df48f 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -16,6 +16,7 @@ struct nvkm_disp {
struct list_head conns;
struct nvkm_event hpd;
+#define NVKM_DISP_HEAD_EVENT_VBLANK BIT(0)
struct nvkm_event vblank;
struct {
@@ -31,13 +32,7 @@ struct nvkm_disp {
struct {
unsigned long mask;
int nr;
- } wndw, head, dac;
-
- struct {
- unsigned long mask;
- int nr;
- u32 lvdsconf;
- } sor;
+ } wndw, head, dac, sor;
struct {
unsigned long mask;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
index b593407b9e36..cd86d9198e4a 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
@@ -16,15 +16,16 @@ enum nvkm_falcon_dmaidx {
struct nvkm_falcon {
const struct nvkm_falcon_func *func;
- const struct nvkm_subdev *owner;
+ struct nvkm_subdev *owner;
const char *name;
u32 addr;
+ u32 addr2;
struct mutex mutex;
struct mutex dmem_mutex;
bool oneinit;
- const struct nvkm_subdev *user;
+ struct nvkm_subdev *user;
u8 version;
u8 secret;
@@ -50,13 +51,42 @@ struct nvkm_falcon {
struct nvkm_engine engine;
};
-int nvkm_falcon_get(struct nvkm_falcon *, const struct nvkm_subdev *);
-void nvkm_falcon_put(struct nvkm_falcon *, const struct nvkm_subdev *);
+int nvkm_falcon_get(struct nvkm_falcon *, struct nvkm_subdev *);
+void nvkm_falcon_put(struct nvkm_falcon *, struct nvkm_subdev *);
int nvkm_falcon_new_(const struct nvkm_falcon_func *, struct nvkm_device *,
enum nvkm_subdev_type, int inst, bool enable, u32 addr, struct nvkm_engine **);
struct nvkm_falcon_func {
+ int (*disable)(struct nvkm_falcon *);
+ int (*enable)(struct nvkm_falcon *);
+ int (*select)(struct nvkm_falcon *);
+ u32 addr2;
+ bool reset_pmc;
+ int (*reset_eng)(struct nvkm_falcon *);
+ int (*reset_prep)(struct nvkm_falcon *);
+ int (*reset_wait_mem_scrubbing)(struct nvkm_falcon *);
+
+ u32 debug;
+ void (*bind_inst)(struct nvkm_falcon *, int target, u64 addr);
+ int (*bind_stat)(struct nvkm_falcon *, bool intr);
+ bool bind_intr;
+
+ const struct nvkm_falcon_func_pio *imem_pio;
+ const struct nvkm_falcon_func_dma *imem_dma;
+
+ const struct nvkm_falcon_func_pio *dmem_pio;
+ const struct nvkm_falcon_func_dma *dmem_dma;
+
+ u32 emem_addr;
+ const struct nvkm_falcon_func_pio *emem_pio;
+
+ struct {
+ u32 head;
+ u32 tail;
+ u32 stride;
+ } cmdq, msgq;
+
struct {
u32 *data;
u32 size;
@@ -66,29 +96,11 @@ struct nvkm_falcon_func {
u32 size;
} data;
void (*init)(struct nvkm_falcon *);
- void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *);
-
- u32 debug;
- u32 fbif;
+ void (*intr)(struct nvkm_falcon *, struct nvkm_chan *);
void (*load_imem)(struct nvkm_falcon *, void *, u32, u32, u16, u8, bool);
void (*load_dmem)(struct nvkm_falcon *, void *, u32, u32, u8);
- void (*read_dmem)(struct nvkm_falcon *, u32, u32, u8, void *);
- u32 emem_addr;
- void (*bind_context)(struct nvkm_falcon *, struct nvkm_memory *);
- int (*wait_for_halt)(struct nvkm_falcon *, u32);
- int (*clear_interrupt)(struct nvkm_falcon *, u32);
- void (*set_start_addr)(struct nvkm_falcon *, u32 start_addr);
void (*start)(struct nvkm_falcon *);
- int (*enable)(struct nvkm_falcon *falcon);
- void (*disable)(struct nvkm_falcon *falcon);
- int (*reset)(struct nvkm_falcon *);
-
- struct {
- u32 head;
- u32 tail;
- u32 stride;
- } cmdq, msgq;
struct nvkm_sclass sclass[];
};
@@ -116,13 +128,5 @@ nvkm_falcon_mask(struct nvkm_falcon *falcon, u32 addr, u32 mask, u32 val)
void nvkm_falcon_load_imem(struct nvkm_falcon *, void *, u32, u32, u16, u8,
bool);
void nvkm_falcon_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8);
-void nvkm_falcon_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *);
-void nvkm_falcon_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
-void nvkm_falcon_set_start_addr(struct nvkm_falcon *, u32);
void nvkm_falcon_start(struct nvkm_falcon *);
-int nvkm_falcon_wait_for_halt(struct nvkm_falcon *, u32);
-int nvkm_falcon_clear_interrupt(struct nvkm_falcon *, u32);
-int nvkm_falcon_enable(struct nvkm_falcon *);
-void nvkm_falcon_disable(struct nvkm_falcon *);
-int nvkm_falcon_reset(struct nvkm_falcon *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
index 15099913504d..221abd6c4310 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
@@ -6,56 +6,76 @@
#include <core/event.h>
struct nvkm_fault_data;
-#define NVKM_FIFO_CHID_NR 4096
#define NVKM_FIFO_ENGN_NR 16
-struct nvkm_fifo_engn {
- struct nvkm_object *object;
- int refcount;
- int usecount;
-};
-
-struct nvkm_fifo_chan {
- const struct nvkm_fifo_chan_func *func;
- struct nvkm_fifo *fifo;
- u32 engm;
- struct nvkm_object object;
+struct nvkm_chan {
+ const struct nvkm_chan_func *func;
+ char name[64];
+ struct nvkm_cgrp *cgrp;
+ int runq;
- struct list_head head;
- u16 chid;
struct nvkm_gpuobj *inst;
- struct nvkm_gpuobj *push;
struct nvkm_vmm *vmm;
- u64 addr;
- u32 size;
+ struct nvkm_gpuobj *push;
+ int id;
+
+ struct {
+ struct nvkm_memory *mem;
+ u32 base;
+ } userd;
+
+ u32 ramfc_offset;
+ struct nvkm_gpuobj *ramfc;
+ struct nvkm_gpuobj *cache;
+ struct nvkm_gpuobj *eng;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_ramht *ramht;
+
+ spinlock_t lock;
+ atomic_t blocked;
+ atomic_t errored;
- struct nvkm_fifo_engn engn[NVKM_FIFO_ENGN_NR];
+ struct list_head cctxs;
+ struct list_head head;
};
+struct nvkm_chan *nvkm_chan_get_chid(struct nvkm_engine *, int id, unsigned long *irqflags);
+struct nvkm_chan *nvkm_chan_get_inst(struct nvkm_engine *, u64 inst, unsigned long *irqflags);
+void nvkm_chan_put(struct nvkm_chan **, unsigned long irqflags);
+
struct nvkm_fifo {
const struct nvkm_fifo_func *func;
struct nvkm_engine engine;
- DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR);
- int nr;
- struct list_head chan;
+ struct nvkm_chid *chid;
+ struct nvkm_chid *cgid;
+
+ struct list_head runqs;
+ struct list_head runls;
+
+ struct {
+#define NVKM_FIFO_NONSTALL_EVENT BIT(0)
+ struct nvkm_event event;
+ struct nvkm_inth intr;
+ } nonstall;
+
+ struct {
+ u32 chan_msec;
+ } timeout;
+
+ struct {
+ struct nvkm_memory *mem;
+ struct nvkm_vma *bar1;
+ } userd;
+
spinlock_t lock;
struct mutex mutex;
-
- struct nvkm_event uevent; /* async user trigger */
- struct nvkm_event kevent; /* channel killed */
};
void nvkm_fifo_fault(struct nvkm_fifo *, struct nvkm_fault_data *);
void nvkm_fifo_pause(struct nvkm_fifo *, unsigned long *);
void nvkm_fifo_start(struct nvkm_fifo *, unsigned long *);
-
-void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags,
- struct nvkm_fifo_chan **);
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags);
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags);
+bool nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *);
int nv04_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int nv10_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
@@ -63,6 +83,7 @@ int nv17_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int nv40_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int nv50_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int g84_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
+int g98_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gf100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gk104_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gk110_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
@@ -70,10 +91,9 @@ int gk208_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gk20a_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gm107_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gm200_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
-int gm20b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gp100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
-int gp10b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gv100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int tu102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
+int ga100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int ga102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
index b28b752ffaa2..a2333cfe6955 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
@@ -54,4 +54,5 @@ int gp108_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gp10b_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
int gv100_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
int tu102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
+int ga102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
index 97bd3092f68a..9baf197ac833 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
@@ -12,4 +12,5 @@ struct nvkm_nvdec {
};
int gm107_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
+int ga102_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
index 06264c840eae..8d48fb20fa54 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
@@ -10,15 +10,18 @@ struct nvkm_sec2 {
struct nvkm_engine engine;
struct nvkm_falcon falcon;
+ atomic_t running;
+ atomic_t initmsg;
+
struct nvkm_falcon_qmgr *qmgr;
struct nvkm_falcon_cmdq *cmdq;
struct nvkm_falcon_msgq *msgq;
struct work_struct work;
- bool initmsg_received;
};
int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
int gp108_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
int tu102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
+int ga102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
index c0b254f7f0b5..73d2a6ae9ab2 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
@@ -36,7 +36,7 @@ struct nvkm_acr {
const struct nvkm_acr_func *func;
struct nvkm_subdev subdev;
- struct list_head hsfw, hsf;
+ struct list_head hsfw;
struct list_head lsfw, lsf;
u64 managed_falcons;
@@ -50,6 +50,7 @@ struct nvkm_acr {
struct nvkm_vmm *vmm;
bool done;
+ struct nvkm_acr_lsf *rtos;
const struct firmware *wpr_fw;
bool wpr_comp;
@@ -64,7 +65,9 @@ int gm20b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gp102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int gp108_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int gp10b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
+int gv100_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int tu102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
+int ga102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
struct nvkm_acr_lsfw {
const struct nvkm_acr_lsf_func *func;
@@ -77,6 +80,7 @@ struct nvkm_acr_lsfw {
const struct firmware *sig;
+ bool secure_bootloader;
u32 bootloader_size;
u32 bootloader_imem_offset;
@@ -87,10 +91,19 @@ struct nvkm_acr_lsfw {
u32 app_resident_code_size;
u32 app_resident_data_offset;
u32 app_resident_data_size;
+ u32 app_imem_offset;
+ u32 app_dmem_offset;
u32 ucode_size;
u32 data_size;
+ u32 fuse_ver;
+ u32 engine_id;
+ u32 ucode_id;
+ u32 sig_size;
+ u32 sig_nr;
+ u8 *sigs;
+
struct {
u32 lsb;
u32 img;
@@ -105,10 +118,10 @@ struct nvkm_acr_lsf_func {
#define NVKM_ACR_LSF_DMACTL_REQ_CTX 0x00000004
#define NVKM_ACR_LSF_FORCE_PRIV_LOAD 0x00000008
u32 flags;
+ u32 bl_entry;
u32 bld_size;
void (*bld_write)(struct nvkm_acr *, u32 bld, struct nvkm_acr_lsfw *);
void (*bld_patch)(struct nvkm_acr *, u32 bld, s64 adjust);
- int (*boot)(struct nvkm_falcon *);
u64 bootstrap_falcons;
int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
@@ -122,8 +135,20 @@ int
nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *);
+
+int
+nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *, struct nvkm_falcon *,
+ enum nvkm_acr_lsf_id, const char *path,
+ int ver, const struct nvkm_acr_lsf_func *);
+
int
nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *);
+
+int
+nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *, struct nvkm_falcon *,
+ enum nvkm_acr_lsf_id, const char *path,
+ int ver, const struct nvkm_acr_lsf_func *,
+ const void *, u32, const void *, u32);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
index 9c78f072d62b..e40bbf378a8d 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
@@ -2,18 +2,21 @@
#define __NVKM_FAULT_H__
#include <core/subdev.h>
#include <core/event.h>
-#include <core/notify.h>
struct nvkm_fault {
const struct nvkm_fault_func *func;
struct nvkm_subdev subdev;
+ struct nvkm_inth info_fault;
+
struct nvkm_fault_buffer *buffer[2];
int buffer_nr;
+#define NVKM_FAULT_BUFFER_EVENT_PENDING BIT(0)
struct nvkm_event event;
- struct nvkm_notify nrpfb;
+ struct nvkm_event_ntfy nrpfb;
+ struct work_struct nrpfb_work;
struct nvkm_device_oclass user;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
index ef6a6297148c..40768373cdd9 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
@@ -35,6 +35,11 @@ struct nvkm_fb {
struct nvkm_blob vpr_scrubber;
+ struct {
+ struct page *flush_page;
+ dma_addr_t flush_page_addr;
+ } sysmem;
+
struct nvkm_ram *ram;
struct {
@@ -53,6 +58,8 @@ struct nvkm_fb {
struct nvkm_memory *mmu_wr;
};
+int nvkm_fb_mem_unlock(struct nvkm_fb *);
+
void nvkm_fb_tile_init(struct nvkm_fb *, int region, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void nvkm_fb_tile_fini(struct nvkm_fb *, int region, struct nvkm_fb_tile *);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
index 0e46ea1fe972..537c4fc58b4f 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
@@ -8,9 +8,6 @@
#include <subdev/bios/gpio.h>
struct nvkm_gpio_ntfy_req {
-#define NVKM_GPIO_HI 0x01
-#define NVKM_GPIO_LO 0x02
-#define NVKM_GPIO_TOGGLED 0x03
u8 mask;
u8 line;
};
@@ -23,6 +20,9 @@ struct nvkm_gpio {
const struct nvkm_gpio_func *func;
struct nvkm_subdev subdev;
+#define NVKM_GPIO_HI BIT(0)
+#define NVKM_GPIO_LO BIT(1)
+#define NVKM_GPIO_TOGGLED (NVKM_GPIO_HI | NVKM_GPIO_LO)
struct nvkm_event event;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
index cf42a59d4e58..72619d7df73e 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
@@ -5,9 +5,12 @@
#include <core/falcon.h>
struct nvkm_gsp {
+ const struct nvkm_gsp_func *func;
struct nvkm_subdev subdev;
+
struct nvkm_falcon falcon;
};
int gv100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
+int ga102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
index 146e13292203..40a1065ae626 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -7,20 +7,6 @@
#include <subdev/bios.h>
#include <subdev/bios/i2c.h>
-struct nvkm_i2c_ntfy_req {
-#define NVKM_I2C_PLUG 0x01
-#define NVKM_I2C_UNPLUG 0x02
-#define NVKM_I2C_IRQ 0x04
-#define NVKM_I2C_DONE 0x08
-#define NVKM_I2C_ANY 0x0f
- u8 mask;
- u8 port;
-};
-
-struct nvkm_i2c_ntfy_rep {
- u8 mask;
-};
-
struct nvkm_i2c_bus_probe {
struct i2c_board_info dev;
u8 udelay; /* set to 0 to use the standard delay */
@@ -79,6 +65,11 @@ struct nvkm_i2c {
struct list_head bus;
struct list_head aux;
+#define NVKM_I2C_PLUG BIT(0)
+#define NVKM_I2C_UNPLUG BIT(1)
+#define NVKM_I2C_IRQ BIT(2)
+#define NVKM_I2C_DONE BIT(3)
+#define NVKM_I2C_ANY (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | NVKM_I2C_IRQ | NVKM_I2C_DONE)
struct nvkm_event event;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
index f967b97d163c..fcdaefc99fe8 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
@@ -28,7 +28,7 @@ u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr);
void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data);
int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero,
struct nvkm_memory **);
-
+int nvkm_instobj_wrap(struct nvkm_device *, struct nvkm_memory *, struct nvkm_memory **);
int nv04_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **);
int nv40_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
index d32a326a9290..64294042ec07 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
@@ -4,7 +4,8 @@
#include <core/subdev.h>
#include <core/mm.h>
-#define NVKM_LTC_MAX_ZBC_CNT 16
+#define NVKM_LTC_MAX_ZBC_COLOR_CNT 32
+#define NVKM_LTC_MAX_ZBC_DEPTH_CNT 16
struct nvkm_ltc {
const struct nvkm_ltc_func *func;
@@ -18,11 +19,13 @@ struct nvkm_ltc {
u32 tag_base;
struct nvkm_memory *tag_ram;
- int zbc_min;
- int zbc_max;
- u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4];
- u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
- u32 zbc_stencil[NVKM_LTC_MAX_ZBC_CNT];
+ int zbc_color_min;
+ int zbc_color_max;
+ u32 zbc_color[NVKM_LTC_MAX_ZBC_COLOR_CNT][4];
+ int zbc_depth_min;
+ int zbc_depth_max;
+ u32 zbc_depth[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
+ u32 zbc_stencil[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
};
void nvkm_ltc_tags_clear(struct nvkm_device *, u32 first, u32 count);
@@ -41,4 +44,5 @@ int gm200_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gp100_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
int gp102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
int gp10b_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
+int ga102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
index cb86a56e68d4..127ac545e4b2 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
@@ -6,15 +6,14 @@
struct nvkm_mc {
const struct nvkm_mc_func *func;
struct nvkm_subdev subdev;
+
+ struct nvkm_intr intr;
};
void nvkm_mc_enable(struct nvkm_device *, enum nvkm_subdev_type, int);
void nvkm_mc_disable(struct nvkm_device *, enum nvkm_subdev_type, int);
bool nvkm_mc_enabled(struct nvkm_device *, enum nvkm_subdev_type, int);
void nvkm_mc_reset(struct nvkm_device *, enum nvkm_subdev_type, int);
-void nvkm_mc_intr(struct nvkm_device *, bool *handled);
-void nvkm_mc_intr_unarm(struct nvkm_device *);
-void nvkm_mc_intr_rearm(struct nvkm_device *);
void nvkm_mc_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int, bool enable);
void nvkm_mc_unk260(struct nvkm_device *, u32 data);
@@ -31,6 +30,5 @@ int gk104_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gk20a_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int gp100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int gp10b_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
-int tu102_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int ga100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
index 74c19bdfb757..3c103101d5fc 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
@@ -13,7 +13,6 @@ struct nvkm_pci {
const struct nvkm_pci_func *func;
struct nvkm_subdev subdev;
struct pci_dev *pdev;
- int irq;
struct {
struct agp_bridge_data *bridge;
@@ -38,6 +37,7 @@ void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data);
void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data);
u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 value);
void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow);
+void nvkm_pci_msi_rearm(struct nvkm_device *);
int nv04_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **);
int nv40_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
index ee75c5524c43..73e717b980b8 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
@@ -21,6 +21,7 @@ struct nvkm_top_device {
struct list_head head;
};
+int nvkm_top_parse(struct nvkm_device *);
u32 nvkm_top_addr(struct nvkm_device *, enum nvkm_subdev_type, int);
u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_subdev_type, int);
u32 nvkm_top_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h
new file mode 100644
index 000000000000..cc6d0796c265
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_VFN_H__
+#define __NVKM_VFN_H__
+#include <core/subdev.h>
+
+struct nvkm_vfn {
+ const struct nvkm_vfn_func *func;
+ struct nvkm_subdev subdev;
+
+ struct {
+ u32 priv;
+ u32 user;
+ } addr;
+
+ struct nvkm_intr intr;
+
+ struct nvkm_device_oclass user;
+};
+
+int gv100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
+int tu102_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
+int ga100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 5bee655e7e63..82dab51d8aeb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -27,7 +27,6 @@
#include <nvif/ioctl.h>
#include <nvif/class.h>
#include <nvif/cl0002.h>
-#include <nvif/cla06f.h>
#include <nvif/unpack.h>
#include "nouveau_drv.h"
@@ -253,7 +252,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
struct nouveau_abi16_chan *chan;
struct nvif_device *device;
- u64 engine;
+ u64 engine, runm;
int ret;
if (unlikely(!abi16))
@@ -263,6 +262,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
return nouveau_abi16_put(abi16, -ENODEV);
device = &abi16->device;
+ engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
/* hack to allow channel engine type specification on kepler */
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
@@ -276,19 +276,18 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
default:
return nouveau_abi16_put(abi16, -ENOSYS);
}
- } else {
- engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
- }
- if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
- engine = nvif_fifo_runlist(device, engine);
- else
- engine = nvif_fifo_runlist_ce(device);
- init->fb_ctxdma_handle = engine;
- init->tt_ctxdma_handle = 0;
+ init->fb_ctxdma_handle = 0;
+ init->tt_ctxdma_handle = 0;
+ }
}
- if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
+ if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
+ runm = nvif_fifo_runlist(device, engine);
+ else
+ runm = nvif_fifo_runlist_ce(device);
+
+ if (!runm || init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
return nouveau_abi16_put(abi16, -EINVAL);
/* allocate "abi16 channel" data and make up a handle for it */
@@ -300,8 +299,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
list_add(&chan->head, &abi16->channels);
/* create channel object and initialise dma and fence management */
- ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
- init->tt_ctxdma_handle, false, &chan->chan);
+ ret = nouveau_channel_new(drm, device, false, runm, init->fb_ctxdma_handle,
+ init->tt_ctxdma_handle, &chan->chan);
if (ret)
goto done;
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index a614582779ca..40409a29f5b6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -264,7 +264,11 @@ nva3_set_intensity(struct backlight_device *bd)
u32 div, val;
div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or));
- val = (bd->props.brightness * div) / 100;
+
+ val = backlight_get_brightness(bd);
+ if (val)
+ val = (val * div) / 100;
+
if (div) {
nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or),
val |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 126b3c6e12f9..a11871e3119c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -532,7 +532,7 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
if (ret)
return ret;
- ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages, &nvbo->kmap);
+ ret = ttm_bo_kmap(&nvbo->bo, 0, PFN_UP(nvbo->bo.base.size), &nvbo->kmap);
ttm_bo_unreserve(&nvbo->bo);
return ret;
@@ -856,6 +856,9 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
int (*init)(struct nouveau_channel *, u32 handle);
} _methods[] = {
{ "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init },
+ { "GRCE", 0, 0xc7b5, nve0_bo_move_copy, nvc0_bo_move_init },
+ { "COPY", 4, 0xc6b5, nve0_bo_move_copy, nve0_bo_move_init },
+ { "GRCE", 0, 0xc6b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init },
@@ -1236,7 +1239,7 @@ vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
} else {
/* make sure bo is in mappable vram */
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA ||
- bo->resource->start + bo->resource->num_pages < mappable)
+ bo->resource->start + PFN_UP(bo->resource->size) < mappable)
return 0;
for (i = 0; i < nvbo->placement.num_placement; ++i) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo0039.c b/drivers/gpu/drm/nouveau/nouveau_bo0039.c
index 7390132129fe..e2ce44adaa5c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo0039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo0039.c
@@ -52,7 +52,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
u32 src_offset = old_reg->start << PAGE_SHIFT;
u32 dst_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, new_reg);
u32 dst_offset = new_reg->start << PAGE_SHIFT;
- u32 page_count = new_reg->num_pages;
+ u32 page_count = PFN_UP(new_reg->size);
int ret;
ret = PUSH_WAIT(push, 3);
@@ -62,7 +62,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
PUSH_MTHD(push, NV039, SET_CONTEXT_DMA_BUFFER_IN, src_ctxdma,
SET_CONTEXT_DMA_BUFFER_OUT, dst_ctxdma);
- page_count = new_reg->num_pages;
+ page_count = PFN_UP(new_reg->size);
while (page_count) {
int line_count = (page_count > 2047) ? 2047 : page_count;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo5039.c b/drivers/gpu/drm/nouveau/nouveau_bo5039.c
index 4c75c7b3804c..c6cf3629a9f9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo5039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo5039.c
@@ -41,7 +41,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
- u64 length = (new_reg->num_pages << PAGE_SHIFT);
+ u64 length = new_reg->size;
u64 src_offset = mem->vma[0].addr;
u64 dst_offset = mem->vma[1].addr;
int src_tiled = !!mem->kind;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
index ed6c09d67840..9b7ba31fae13 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
@@ -44,7 +44,7 @@ nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- PUSH_NVSQ(push, NV74C1, 0x0304, new_reg->num_pages << PAGE_SHIFT,
+ PUSH_NVSQ(push, NV74C1, 0x0304, new_reg->size,
0x0308, upper_32_bits(mem->vma[0].addr),
0x030c, lower_32_bits(mem->vma[0].addr),
0x0310, upper_32_bits(mem->vma[1].addr),
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
index dec29b2d8bb2..a15a38a87a95 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
@@ -44,10 +44,10 @@ nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct nvif_push *push = chan->chan.push;
u64 src_offset = mem->vma[0].addr;
u64 dst_offset = mem->vma[1].addr;
- u32 page_count = new_reg->num_pages;
+ u32 page_count = PFN_UP(new_reg->size);
int ret;
- page_count = new_reg->num_pages;
+ page_count = PFN_UP(new_reg->size);
while (page_count) {
int line_count = (page_count > 8191) ? 8191 : page_count;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo9039.c b/drivers/gpu/drm/nouveau/nouveau_bo9039.c
index 776b04976cdf..d2bb2687d401 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo9039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo9039.c
@@ -42,10 +42,10 @@ nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct nouveau_mem *mem = nouveau_mem(old_reg);
u64 src_offset = mem->vma[0].addr;
u64 dst_offset = mem->vma[1].addr;
- u32 page_count = new_reg->num_pages;
+ u32 page_count = PFN_UP(new_reg->size);
int ret;
- page_count = new_reg->num_pages;
+ page_count = PFN_UP(new_reg->size);
while (page_count) {
int line_count = (page_count > 2047) ? 2047 : page_count;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
index 8499f58213e3..4618f4f5ab56 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
@@ -37,10 +37,10 @@ nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct nvif_push *push = chan->chan.push;
u64 src_offset = mem->vma[0].addr;
u64 dst_offset = mem->vma[1].addr;
- u32 page_count = new_reg->num_pages;
+ u32 page_count = PFN_UP(new_reg->size);
int ret;
- page_count = new_reg->num_pages;
+ page_count = PFN_UP(new_reg->size);
while (page_count) {
int line_count = (page_count > 8191) ? 8191 : page_count;
diff --git a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
index 575212472e7a..07a5c6302c98 100644
--- a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
@@ -58,7 +58,7 @@ nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
PITCH_IN, PAGE_SIZE,
PITCH_OUT, PAGE_SIZE,
LINE_LENGTH_IN, PAGE_SIZE,
- LINE_COUNT, new_reg->num_pages);
+ LINE_COUNT, PFN_UP(new_reg->size));
PUSH_IMMD(push, NVA0B5, LAUNCH_DMA,
NVDEF(NVA0B5, LAUNCH_DMA, DATA_TRANSFER_TYPE, NON_PIPELINED) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 48dea5d0c580..e648ecd0c1a0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -25,12 +25,7 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
-#include <nvif/cl006b.h>
-#include <nvif/cl506f.h>
-#include <nvif/cl906f.h>
-#include <nvif/cla06f.h>
-#include <nvif/clc36f.h>
-#include <nvif/ioctl.h>
+#include <nvif/if0020.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@@ -46,15 +41,17 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
static int
-nouveau_channel_killed(struct nvif_notify *ntfy)
+nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill);
+ struct nouveau_channel *chan = container_of(event, typeof(*chan), kill);
struct nouveau_cli *cli = (void *)chan->user.client;
+
NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid);
atomic_set(&chan->killed, 1);
if (chan->fence)
nouveau_fence_context_kill(chan->fence, -ENODEV);
- return NVIF_NOTIFY_DROP;
+
+ return NVIF_EVENT_DROP;
}
int
@@ -96,8 +93,9 @@ nouveau_channel_del(struct nouveau_channel **pchan)
nvif_object_dtor(&chan->nvsw);
nvif_object_dtor(&chan->gart);
nvif_object_dtor(&chan->vram);
- nvif_notify_dtor(&chan->kill);
+ nvif_event_dtor(&chan->kill);
nvif_object_dtor(&chan->user);
+ nvif_mem_dtor(&chan->mem_userd);
nvif_object_dtor(&chan->push.ctxdma);
nouveau_vma_del(&chan->push.vma);
nouveau_bo_unmap(chan->push.buffer);
@@ -247,134 +245,113 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
}
static int
-nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
- u64 runlist, bool priv, struct nouveau_channel **pchan)
+nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool priv, u64 runm,
+ struct nouveau_channel **pchan)
{
- static const u16 oclasses[] = { AMPERE_CHANNEL_GPFIFO_B,
- TURING_CHANNEL_GPFIFO_A,
- VOLTA_CHANNEL_GPFIFO_A,
- PASCAL_CHANNEL_GPFIFO_A,
- MAXWELL_CHANNEL_GPFIFO_A,
- KEPLER_CHANNEL_GPFIFO_B,
- KEPLER_CHANNEL_GPFIFO_A,
- FERMI_CHANNEL_GPFIFO,
- G82_CHANNEL_GPFIFO,
- NV50_CHANNEL_GPFIFO,
- 0 };
- const u16 *oclass = oclasses;
- union {
- struct nv50_channel_gpfifo_v0 nv50;
- struct fermi_channel_gpfifo_v0 fermi;
- struct kepler_channel_gpfifo_a_v0 kepler;
- struct volta_channel_gpfifo_a_v0 volta;
+ static const struct {
+ s32 oclass;
+ int version;
+ } hosts[] = {
+ { AMPERE_CHANNEL_GPFIFO_B, 0 },
+ { AMPERE_CHANNEL_GPFIFO_A, 0 },
+ { TURING_CHANNEL_GPFIFO_A, 0 },
+ { VOLTA_CHANNEL_GPFIFO_A, 0 },
+ { PASCAL_CHANNEL_GPFIFO_A, 0 },
+ { MAXWELL_CHANNEL_GPFIFO_A, 0 },
+ { KEPLER_CHANNEL_GPFIFO_B, 0 },
+ { KEPLER_CHANNEL_GPFIFO_A, 0 },
+ { FERMI_CHANNEL_GPFIFO , 0 },
+ { G82_CHANNEL_GPFIFO , 0 },
+ { NV50_CHANNEL_GPFIFO , 0 },
+ { NV40_CHANNEL_DMA , 0 },
+ { NV17_CHANNEL_DMA , 0 },
+ { NV10_CHANNEL_DMA , 0 },
+ { NV03_CHANNEL_DMA , 0 },
+ {}
+ };
+ struct {
+ struct nvif_chan_v0 chan;
+ char name[TASK_COMM_LEN+16];
} args;
+ struct nouveau_cli *cli = (void *)device->object.client;
struct nouveau_channel *chan;
- u32 size;
- int ret;
+ const u64 plength = 0x10000;
+ const u64 ioffset = plength;
+ const u64 ilength = 0x02000;
+ char name[TASK_COMM_LEN];
+ int cid, ret;
+ u64 size;
+
+ cid = nvif_mclass(&device->object, hosts);
+ if (cid < 0)
+ return cid;
+
+ if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO)
+ size = plength;
+ else
+ size = ioffset + ilength;
/* allocate dma push buffer */
- ret = nouveau_channel_prep(drm, device, 0x12000, &chan);
+ ret = nouveau_channel_prep(drm, device, size, &chan);
*pchan = chan;
if (ret)
return ret;
/* create channel object */
- do {
- if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) {
- args.volta.version = 0;
- args.volta.ilength = 0x02000;
- args.volta.ioffset = 0x10000 + chan->push.addr;
- args.volta.runlist = runlist;
- args.volta.vmm = nvif_handle(&chan->vmm->vmm.object);
- args.volta.priv = priv;
- size = sizeof(args.volta);
- } else
- if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
- args.kepler.version = 0;
- args.kepler.ilength = 0x02000;
- args.kepler.ioffset = 0x10000 + chan->push.addr;
- args.kepler.runlist = runlist;
- args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object);
- args.kepler.priv = priv;
- size = sizeof(args.kepler);
- } else
- if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
- args.fermi.version = 0;
- args.fermi.ilength = 0x02000;
- args.fermi.ioffset = 0x10000 + chan->push.addr;
- args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object);
- size = sizeof(args.fermi);
- } else {
- args.nv50.version = 0;
- args.nv50.ilength = 0x02000;
- args.nv50.ioffset = 0x10000 + chan->push.addr;
- args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
- args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object);
- size = sizeof(args.nv50);
- }
-
- ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
- *oclass++, &args, size, &chan->user);
- if (ret == 0) {
- if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) {
- chan->chid = args.volta.chid;
- chan->inst = args.volta.inst;
- chan->token = args.volta.token;
- } else
- if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) {
- chan->chid = args.kepler.chid;
- chan->inst = args.kepler.inst;
- } else
- if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
- chan->chid = args.fermi.chid;
- } else {
- chan->chid = args.nv50.chid;
- }
+ args.chan.version = 0;
+ args.chan.namelen = sizeof(args.name);
+ args.chan.runlist = __ffs64(runm);
+ args.chan.runq = 0;
+ args.chan.priv = priv;
+ args.chan.devm = BIT(0);
+ if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO) {
+ args.chan.vmm = 0;
+ args.chan.ctxdma = nvif_handle(&chan->push.ctxdma);
+ args.chan.offset = chan->push.addr;
+ args.chan.length = 0;
+ } else {
+ args.chan.vmm = nvif_handle(&chan->vmm->vmm.object);
+ if (hosts[cid].oclass < FERMI_CHANNEL_GPFIFO)
+ args.chan.ctxdma = nvif_handle(&chan->push.ctxdma);
+ else
+ args.chan.ctxdma = 0;
+ args.chan.offset = ioffset + chan->push.addr;
+ args.chan.length = ilength;
+ }
+ args.chan.huserd = 0;
+ args.chan.ouserd = 0;
+
+ /* allocate userd */
+ if (hosts[cid].oclass >= VOLTA_CHANNEL_GPFIFO_A) {
+ ret = nvif_mem_ctor(&cli->mmu, "abi16ChanUSERD", NVIF_CLASS_MEM_GF100,
+ NVIF_MEM_VRAM | NVIF_MEM_COHERENT | NVIF_MEM_MAPPABLE,
+ 0, PAGE_SIZE, NULL, 0, &chan->mem_userd);
+ if (ret)
return ret;
- }
- } while (*oclass);
- nouveau_channel_del(pchan);
- return ret;
-}
+ args.chan.huserd = nvif_handle(&chan->mem_userd.object);
+ args.chan.ouserd = 0;
-static int
-nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
- struct nouveau_channel **pchan)
-{
- static const u16 oclasses[] = { NV40_CHANNEL_DMA,
- NV17_CHANNEL_DMA,
- NV10_CHANNEL_DMA,
- NV03_CHANNEL_DMA,
- 0 };
- const u16 *oclass = oclasses;
- struct nv03_channel_dma_v0 args;
- struct nouveau_channel *chan;
- int ret;
+ chan->userd = &chan->mem_userd.object;
+ } else {
+ chan->userd = &chan->user;
+ }
- /* allocate dma push buffer */
- ret = nouveau_channel_prep(drm, device, 0x10000, &chan);
- *pchan = chan;
- if (ret)
- return ret;
+ get_task_comm(name, current);
+ snprintf(args.name, sizeof(args.name), "%s[%d]", name, task_pid_nr(current));
- /* create channel object */
- args.version = 0;
- args.pushbuf = nvif_handle(&chan->push.ctxdma);
- args.offset = chan->push.addr;
-
- do {
- ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
- *oclass++, &args, sizeof(args),
- &chan->user);
- if (ret == 0) {
- chan->chid = args.chid;
- return ret;
- }
- } while (ret && *oclass);
+ ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, hosts[cid].oclass,
+ &args, sizeof(args), &chan->user);
+ if (ret) {
+ nouveau_channel_del(pchan);
+ return ret;
+ }
- nouveau_channel_del(pchan);
- return ret;
+ chan->runlist = args.chan.runlist;
+ chan->chid = args.chan.chid;
+ chan->inst = args.chan.inst;
+ chan->token = args.chan.token;
+ return 0;
}
static int
@@ -385,18 +362,24 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
struct nv_dma_v0 args = {};
int ret, i;
- ret = nvif_object_map(&chan->user, NULL, 0);
+ ret = nvif_object_map(chan->userd, NULL, 0);
if (ret)
return ret;
- if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO &&
- chan->user.oclass < AMPERE_CHANNEL_GPFIFO_B) {
- ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled",
- nouveau_channel_killed,
- true, NV906F_V0_NTFY_KILLED,
- NULL, 0, 0, &chan->kill);
+ if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
+ struct {
+ struct nvif_event_v0 base;
+ struct nvif_chan_event_v0 host;
+ } args;
+
+ args.host.version = 0;
+ args.host.type = NVIF_CHAN_EVENT_V0_KILLED;
+
+ ret = nvif_event_ctor(&chan->user, "abi16ChanKilled", chan->chid,
+ nouveau_channel_killed, false,
+ &args.base, sizeof(args), &chan->kill);
if (ret == 0)
- ret = nvif_notify_get(&chan->kill);
+ ret = nvif_event_allow(&chan->kill);
if (ret) {
NV_ERROR(drm, "Failed to request channel kill "
"notification: %d\n", ret);
@@ -503,24 +486,18 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
int
nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
- u32 arg0, u32 arg1, bool priv,
- struct nouveau_channel **pchan)
+ bool priv, u64 runm, u32 vram, u32 gart, struct nouveau_channel **pchan)
{
struct nouveau_cli *cli = (void *)device->object.client;
int ret;
- /* hack until fencenv50 is fixed, and agp access relaxed */
- ret = nouveau_channel_ind(drm, device, arg0, priv, pchan);
+ ret = nouveau_channel_ctor(drm, device, priv, runm, pchan);
if (ret) {
- NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
- ret = nouveau_channel_dma(drm, device, pchan);
- if (ret) {
- NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret);
- return ret;
- }
+ NV_PRINTK(dbg, cli, "channel create, %d\n", ret);
+ return ret;
}
- ret = nouveau_channel_init(*pchan, arg0, arg1);
+ ret = nouveau_channel_init(*pchan, vram, gart);
if (ret) {
NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
nouveau_channel_del(pchan);
@@ -534,6 +511,12 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
return ret;
}
+void
+nouveau_channels_fini(struct nouveau_drm *drm)
+{
+ kfree(drm->runl);
+}
+
int
nouveau_channels_init(struct nouveau_drm *drm)
{
@@ -541,20 +524,53 @@ nouveau_channels_init(struct nouveau_drm *drm)
struct nv_device_info_v1 m;
struct {
struct nv_device_info_v1_data channels;
+ struct nv_device_info_v1_data runlists;
} v;
} args = {
.m.version = 1,
.m.count = sizeof(args.v) / sizeof(args.v.channels),
.v.channels.mthd = NV_DEVICE_HOST_CHANNELS,
+ .v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS,
};
struct nvif_object *device = &drm->client.device.object;
- int ret;
+ int ret, i;
ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
- if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
+ if (ret ||
+ args.v.runlists.mthd == NV_DEVICE_INFO_INVALID || !args.v.runlists.data ||
+ args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
return -ENODEV;
- drm->chan.nr = args.v.channels.data;
- drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr);
+ drm->chan_nr = drm->chan_total = args.v.channels.data;
+ drm->runl_nr = fls64(args.v.runlists.data);
+ drm->runl = kcalloc(drm->runl_nr, sizeof(*drm->runl), GFP_KERNEL);
+ if (!drm->runl)
+ return -ENOMEM;
+
+ if (drm->chan_nr == 0) {
+ for (i = 0; i < drm->runl_nr; i++) {
+ if (!(args.v.runlists.data & BIT(i)))
+ continue;
+
+ args.v.channels.mthd = NV_DEVICE_HOST_RUNLIST_CHANNELS;
+ args.v.channels.data = i;
+
+ ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
+ if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
+ return -ENODEV;
+
+ drm->runl[i].chan_nr = args.v.channels.data;
+ drm->runl[i].chan_id_base = drm->chan_total;
+ drm->runl[i].context_base = dma_fence_context_alloc(drm->runl[i].chan_nr);
+
+ drm->chan_total += drm->runl[i].chan_nr;
+ }
+ } else {
+ drm->runl[0].context_base = dma_fence_context_alloc(drm->chan_nr);
+ for (i = 1; i < drm->runl_nr; i++)
+ drm->runl[i].context_base = drm->runl[0].context_base;
+
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h
index 98ba9d27e6b4..e06a8ffed31a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.h
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.h
@@ -2,7 +2,7 @@
#ifndef __NOUVEAU_CHAN_H__
#define __NOUVEAU_CHAN_H__
#include <nvif/object.h>
-#include <nvif/notify.h>
+#include <nvif/event.h>
#include <nvif/push.h>
struct nvif_device;
@@ -16,6 +16,10 @@ struct nouveau_channel {
struct nouveau_drm *drm;
struct nouveau_vmm *vmm;
+ struct nvif_mem mem_userd;
+ struct nvif_object *userd;
+
+ int runlist;
int chid;
u64 inst;
u32 token;
@@ -50,15 +54,15 @@ struct nouveau_channel {
struct nvif_object user;
- struct nvif_notify kill;
+ struct nvif_event kill;
atomic_t killed;
};
int nouveau_channels_init(struct nouveau_drm *);
+void nouveau_channels_fini(struct nouveau_drm *);
-int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *,
- u32 arg0, u32 arg1, bool priv,
- struct nouveau_channel **);
+int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u64 runm,
+ u32 vram, u32 gart, struct nouveau_channel **);
void nouveau_channel_del(struct nouveau_channel **);
int nouveau_channel_idle(struct nouveau_channel *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 1991bbb1d05c..086b66b60d91 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -47,8 +47,7 @@
#include "nouveau_crtc.h"
#include <nvif/class.h>
-#include <nvif/cl0046.h>
-#include <nvif/event.h>
+#include <nvif/if0011.h>
struct drm_display_mode *
nouveau_conn_native_mode(struct drm_connector *connector)
@@ -396,7 +395,8 @@ static void
nouveau_connector_destroy(struct drm_connector *connector)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
- nvif_notify_dtor(&nv_connector->hpd);
+ nvif_event_dtor(&nv_connector->irq);
+ nvif_event_dtor(&nv_connector->hpd);
kfree(nv_connector->edid);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
@@ -1162,39 +1162,38 @@ nouveau_connector_funcs_lvds = {
};
void
-nouveau_connector_hpd(struct drm_connector *connector)
+nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits)
{
- struct nouveau_drm *drm = nouveau_drm(connector->dev);
- u32 mask = drm_connector_mask(connector);
+ struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev);
+ u32 mask = drm_connector_mask(&nv_connector->base);
+ unsigned long flags;
- mutex_lock(&drm->hpd_lock);
+ spin_lock_irqsave(&drm->hpd_lock, flags);
if (!(drm->hpd_pending & mask)) {
+ nv_connector->hpd_pending |= bits;
drm->hpd_pending |= mask;
schedule_work(&drm->hpd_work);
}
- mutex_unlock(&drm->hpd_lock);
+ spin_unlock_irqrestore(&drm->hpd_lock, flags);
}
static int
-nouveau_connector_hotplug(struct nvif_notify *notify)
+nouveau_connector_irq(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_connector *nv_connector =
- container_of(notify, typeof(*nv_connector), hpd);
- struct drm_connector *connector = &nv_connector->base;
- struct drm_device *dev = connector->dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- const struct nvif_notify_conn_rep_v0 *rep = notify->data;
- bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
+ struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), irq);
- if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
- nouveau_dp_irq(drm, nv_connector);
- return NVIF_NOTIFY_KEEP;
- }
+ schedule_work(&nv_connector->irq_work);
+ return NVIF_EVENT_KEEP;
+}
- NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", connector->name);
- nouveau_connector_hpd(connector);
+static int
+nouveau_connector_hotplug(struct nvif_event *event, void *repv, u32 repc)
+{
+ struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), hpd);
+ struct nvif_conn_event_v0 *rep = repv;
- return NVIF_NOTIFY_KEEP;
+ nouveau_connector_hpd(nv_connector, rep->types);
+ return NVIF_EVENT_KEEP;
}
static ssize_t
@@ -1290,6 +1289,7 @@ nouveau_connector_create(struct drm_device *dev,
connector = &nv_connector->base;
nv_connector->index = index;
+ INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq);
/* attempt to parse vbios connector type and hotplug gpio */
nv_connector->dcb = olddcb_conn(dev, index);
@@ -1401,6 +1401,7 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_init(dev, connector, funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) {
ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
@@ -1409,6 +1410,25 @@ nouveau_connector_create(struct drm_device *dev,
kfree(nv_connector);
return ERR_PTR(ret);
}
+
+ ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug",
+ nouveau_connector_hotplug,
+ NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG,
+ &nv_connector->hpd);
+ if (ret == 0)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ if (nv_connector->aux.transfer) {
+ ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsDpIrq",
+ nouveau_connector_irq, NVIF_CONN_EVENT_V0_IRQ,
+ &nv_connector->irq);
+ if (ret) {
+ nvif_event_dtor(&nv_connector->hpd);
+ nvif_conn_dtor(&nv_connector->conn);
+ kfree(nv_connector);
+ return ERR_PTR(ret);
+ }
+ }
}
connector->funcs->reset(connector);
@@ -1452,21 +1472,6 @@ nouveau_connector_create(struct drm_device *dev,
break;
}
- ret = nvif_notify_ctor(&disp->disp.object, "kmsHotplug",
- nouveau_connector_hotplug,
- true, NV04_DISP_NTFY_CONN,
- &(struct nvif_notify_conn_req_v0) {
- .mask = NVIF_NOTIFY_CONN_V0_ANY,
- .conn = index,
- },
- sizeof(struct nvif_notify_conn_req_v0),
- sizeof(struct nvif_notify_conn_rep_v0),
- &nv_connector->hpd);
- if (ret)
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- else
- connector->polled = DRM_CONNECTOR_POLL_HPD;
-
drm_connector_register(connector);
return connector;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index f4e17ff68bf9..35bcb541722b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -27,7 +27,7 @@
#ifndef __NOUVEAU_CONNECTOR_H__
#define __NOUVEAU_CONNECTOR_H__
#include <nvif/conn.h>
-#include <nvif/notify.h>
+#include <nvif/event.h>
#include <nvhw/class/cl507d.h>
#include <nvhw/class/cl907d.h>
@@ -124,7 +124,10 @@ struct nouveau_connector {
u8 *dcb;
struct nvif_conn conn;
- struct nvif_notify hpd;
+ u64 hpd_pending;
+ struct nvif_event hpd;
+ struct nvif_event irq;
+ struct work_struct irq_work;
struct drm_dp_aux aux;
@@ -198,7 +201,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
struct drm_connector *
nouveau_connector_create(struct drm_device *, const struct dcb_output *);
-void nouveau_connector_hpd(struct drm_connector *connector);
+void nouveau_connector_hpd(struct nouveau_connector *, u64 bits);
extern int nouveau_tv_disable;
extern int nouveau_ignorelid;
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 7f63be2ec35d..c717f664a7b8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -26,16 +26,17 @@
#ifndef __NOUVEAU_CRTC_H__
#define __NOUVEAU_CRTC_H__
-
#include <drm/drm_crtc.h>
-#include <nvif/notify.h>
+#include <nvif/head.h>
+#include <nvif/event.h>
struct nouveau_crtc {
struct drm_crtc base;
+ struct nvif_head head;
int index;
- struct nvif_notify vblank;
+ struct nvif_event vblank;
uint32_t dpms_saved_fp_control;
uint32_t fp_users;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index a2f5df568ca5..ec3ffff487fc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -35,15 +35,14 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
-#include "nouveau_fbcon.h"
#include "nouveau_crtc.h"
#include "nouveau_gem.h"
#include "nouveau_connector.h"
#include "nv50_display.h"
#include <nvif/class.h>
-#include <nvif/cl0046.h>
-#include <nvif/event.h>
+#include <nvif/if0011.h>
+#include <nvif/if0013.h>
#include <dispnv50/crc.h>
int
@@ -52,7 +51,7 @@ nouveau_display_vblank_enable(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc;
nv_crtc = nouveau_crtc(crtc);
- nvif_notify_get(&nv_crtc->vblank);
+ nvif_event_allow(&nv_crtc->vblank);
return 0;
}
@@ -63,7 +62,7 @@ nouveau_display_vblank_disable(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc;
nv_crtc = nouveau_crtc(crtc);
- nvif_notify_put(&nv_crtc->vblank);
+ nvif_event_block(&nv_crtc->vblank);
}
static inline int
@@ -84,24 +83,20 @@ static bool
nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime)
{
- struct {
- struct nv04_disp_mthd_v0 base;
- struct nv04_disp_scanoutpos_v0 scan;
- } args = {
- .base.method = NV04_DISP_SCANOUTPOS,
- .base.head = nouveau_crtc(crtc)->index,
- };
- struct nouveau_display *disp = nouveau_display(crtc->dev);
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
+ struct nvif_head *head = &nouveau_crtc(crtc)->head;
+ struct nvif_head_scanoutpos_v0 args;
int retry = 20;
bool ret = false;
+ args.version = 0;
+
do {
- ret = nvif_mthd(&disp->disp.object, 0, &args, sizeof(args));
+ ret = nvif_mthd(&head->object, NVIF_HEAD_V0_SCANOUTPOS, &args, sizeof(args));
if (ret != 0)
return false;
- if (args.scan.vline) {
+ if (args.vline) {
ret = true;
break;
}
@@ -109,11 +104,10 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
if (retry) ndelay(vblank->linedur_ns);
} while (retry--);
- *hpos = args.scan.hline;
- *vpos = calc(args.scan.vblanks, args.scan.vblanke,
- args.scan.vtotal, args.scan.vline);
- if (stime) *stime = ns_to_ktime(args.scan.time[0]);
- if (etime) *etime = ns_to_ktime(args.scan.time[1]);
+ *hpos = args.hline;
+ *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
+ if (stime) *stime = ns_to_ktime(args.time[0]);
+ if (etime) *etime = ns_to_ktime(args.time[1]);
return ret;
}
@@ -397,7 +391,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.fb_create = nouveau_user_framebuffer_create,
- .output_poll_changed = nouveau_fbcon_output_poll_changed,
+ .output_poll_changed = drm_fb_helper_output_poll_changed,
};
@@ -456,9 +450,9 @@ nouveau_display_hpd_resume(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- mutex_lock(&drm->hpd_lock);
+ spin_lock_irq(&drm->hpd_lock);
drm->hpd_pending = ~0;
- mutex_unlock(&drm->hpd_lock);
+ spin_unlock_irq(&drm->hpd_lock);
schedule_work(&drm->hpd_work);
}
@@ -475,10 +469,10 @@ nouveau_display_hpd_work(struct work_struct *work)
pm_runtime_get_sync(dev->dev);
- mutex_lock(&drm->hpd_lock);
+ spin_lock_irq(&drm->hpd_lock);
pending = drm->hpd_pending;
drm->hpd_pending = 0;
- mutex_unlock(&drm->hpd_lock);
+ spin_unlock_irq(&drm->hpd_lock);
/* Nothing to do, exit early without updating the last busy counter */
if (!pending)
@@ -488,14 +482,30 @@ nouveau_display_hpd_work(struct work_struct *work)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
enum drm_connector_status old_status = connector->status;
- u64 old_epoch_counter = connector->epoch_counter;
+ u64 bits, old_epoch_counter = connector->epoch_counter;
if (!(pending & drm_connector_mask(connector)))
continue;
- connector->status = drm_helper_probe_detect(connector, NULL,
- false);
+ spin_lock_irq(&drm->hpd_lock);
+ bits = nv_connector->hpd_pending;
+ nv_connector->hpd_pending = 0;
+ spin_unlock_irq(&drm->hpd_lock);
+
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] plug:%d unplug:%d irq:%d\n",
+ connector->base.id, connector->name,
+ !!(bits & NVIF_CONN_EVENT_V0_PLUG),
+ !!(bits & NVIF_CONN_EVENT_V0_UNPLUG),
+ !!(bits & NVIF_CONN_EVENT_V0_IRQ));
+
+ if (bits & NVIF_CONN_EVENT_V0_IRQ) {
+ if (nouveau_dp_link_check(nv_connector))
+ continue;
+ }
+
+ connector->status = drm_helper_probe_detect(connector, NULL, false);
if (old_epoch_counter == connector->epoch_counter)
continue;
@@ -573,7 +583,8 @@ nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
- nvif_notify_get(&conn->hpd);
+ nvif_event_allow(&conn->hpd);
+ nvif_event_allow(&conn->irq);
}
drm_connector_list_iter_end(&conn_iter);
@@ -608,7 +619,8 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
- nvif_notify_put(&conn->hpd);
+ nvif_event_block(&conn->irq);
+ nvif_event_block(&conn->hpd);
}
drm_connector_list_iter_end(&conn_iter);
@@ -659,7 +671,6 @@ int
nouveau_display_create(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvkm_device *device = nvxx_device(&drm->client.device);
struct nouveau_display *disp;
int ret;
@@ -672,7 +683,6 @@ nouveau_display_create(struct drm_device *dev)
drm_mode_create_dvi_i_properties(dev);
dev->mode_config.funcs = &nouveau_mode_config_funcs;
- dev->mode_config.fb_base = device->func->resource_addr(device, 1);
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -734,7 +744,7 @@ nouveau_display_create(struct drm_device *dev)
}
INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work);
- mutex_init(&drm->hpd_lock);
+ spin_lock_init(&drm->hpd_lock);
#ifdef CONFIG_ACPI
drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy;
register_acpi_notifier(&drm->acpi_nb);
@@ -768,8 +778,7 @@ nouveau_display_destroy(struct drm_device *dev)
nvif_disp_dtor(&disp->disp);
- nouveau_drm(dev)->display = NULL;
- mutex_destroy(&drm->hpd_lock);
+ drm->display = NULL;
kfree(disp);
}
@@ -778,6 +787,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
+ /* Disable console. */
+ drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true);
+
if (drm_drv_uses_atomic_modeset(dev)) {
if (!runtime) {
disp->suspend = drm_atomic_helper_suspend(dev);
@@ -805,8 +817,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
drm_atomic_helper_resume(dev, disp->suspend);
disp->suspend = NULL;
}
- return;
}
+
+ /* Enable console. */
+ drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false);
}
int
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index ddb75d80bc53..b90cac6d5772 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -42,9 +42,9 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
{
uint64_t val;
- val = nvif_rd32(&chan->user, chan->user_get);
+ val = nvif_rd32(chan->userd, chan->user_get);
if (chan->user_get_hi)
- val |= (uint64_t)nvif_rd32(&chan->user, chan->user_get_hi) << 32;
+ val |= (uint64_t)nvif_rd32(chan->userd, chan->user_get_hi) << 32;
/* reset counter as long as GET is still advancing, this is
* to avoid misdetecting a GPU lockup if the GPU happens to
@@ -86,7 +86,7 @@ nv50_dma_push(struct nouveau_channel *chan, u64 offset, int length)
/* Flush writes. */
nouveau_bo_rd32(pb, 0);
- nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put);
+ nvif_wr32(chan->userd, 0x8c, chan->dma.ib_put);
if (user->func && user->func->doorbell)
user->func->doorbell(user, chan->token);
chan->dma.ib_free--;
@@ -98,7 +98,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count)
uint32_t cnt = 0, prev_get = 0;
while (chan->dma.ib_free < count) {
- uint32_t get = nvif_rd32(&chan->user, 0x88);
+ uint32_t get = nvif_rd32(chan->userd, 0x88);
if (get != prev_get) {
prev_get = get;
cnt = 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index 20fe53815b20..789857faa048 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -33,7 +33,6 @@
#include <nvif/if000c.h>
#include <nvif/if500b.h>
#include <nvif/if900b.h>
-#include <nvif/if000c.h>
#include <nvhw/class/cla0b5.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 20db8ea1a0ba..e00876f92aee 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -29,8 +29,7 @@
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
-#include <nvif/class.h>
-#include <nvif/cl5070.h>
+#include <nvif/if0011.h>
MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)");
static int nouveau_mst = 1;
@@ -140,12 +139,17 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
* TODO: look into checking this before probing I2C to detect DVI/HDMI
*/
hpd = nvif_conn_hpd_status(&nv_connector->conn);
- if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT)
+ if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) {
+ nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
+ }
+ nvif_outp_dp_aux_pwr(&nv_encoder->outp, true);
status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
- if (status == connector_status_disconnected)
+ if (status == connector_status_disconnected) {
+ nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
+ }
/* If we're in MST mode, we're done here */
if (mstm && mstm->can_mst && mstm->is_mst) {
@@ -193,6 +197,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
ret = NOUVEAU_DP_MST;
goto out;
} else if (ret != 0) {
+ nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
}
}
@@ -206,14 +211,28 @@ out:
return ret;
}
-void nouveau_dp_irq(struct nouveau_drm *drm,
- struct nouveau_connector *nv_connector)
+bool
+nouveau_dp_link_check(struct nouveau_connector *nv_connector)
+{
+ struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
+
+ if (!nv_encoder || nv_encoder->outp.or.id < 0)
+ return true;
+
+ return nvif_outp_dp_retrain(&nv_encoder->outp) == 0;
+}
+
+void
+nouveau_dp_irq(struct work_struct *work)
{
+ struct nouveau_connector *nv_connector =
+ container_of(work, typeof(*nv_connector), irq_work);
struct drm_connector *connector = &nv_connector->base;
struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
+ struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
struct nv50_mstm *mstm;
+ u64 hpd = 0;
int ret;
- bool send_hpd = false;
if (!outp)
return;
@@ -225,14 +244,14 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
if (mstm && mstm->is_mst) {
if (!nv50_mstm_service(drm, nv_connector, mstm))
- send_hpd = true;
+ hpd |= NVIF_CONN_EVENT_V0_UNPLUG;
} else {
drm_dp_cec_irq(&nv_connector->aux);
if (nouveau_dp_has_sink_count(connector, outp)) {
ret = drm_dp_read_sink_count(&nv_connector->aux);
if (ret != outp->dp.sink_count)
- send_hpd = true;
+ hpd |= NVIF_CONN_EVENT_V0_PLUG;
if (ret >= 0)
outp->dp.sink_count = ret;
}
@@ -240,8 +259,7 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
mutex_unlock(&outp->dp.hpd_irq_lock);
- if (send_hpd)
- nouveau_connector_hpd(connector);
+ nouveau_connector_hpd(nv_connector, NVIF_CONN_EVENT_V0_IRQ | hpd);
}
/* TODO:
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index fd99ec0f4257..80f154b6adab 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -33,6 +33,8 @@
#include <drm/drm_aperture.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_vblank.h>
@@ -49,7 +51,6 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
-#include <nvif/cla06f.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@@ -62,7 +63,6 @@
#include "nouveau_bios.h"
#include "nouveau_ioctl.h"
#include "nouveau_abi16.h"
-#include "nouveau_fbcon.h"
#include "nouveau_fence.h"
#include "nouveau_debugfs.h"
#include "nouveau_usif.h"
@@ -316,28 +316,19 @@ static void
nouveau_accel_ce_init(struct nouveau_drm *drm)
{
struct nvif_device *device = &drm->client.device;
+ u64 runm;
int ret = 0;
/* Allocate channel that has access to a (preferably async) copy
* engine, to use for TTM buffer moves.
*/
- if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
- ret = nouveau_channel_new(drm, device,
- nvif_fifo_runlist_ce(device), 0,
- true, &drm->cechan);
- } else
- if (device->info.chipset >= 0xa3 &&
- device->info.chipset != 0xaa &&
- device->info.chipset != 0xac) {
- /* Prior to Kepler, there's only a single runlist, so all
- * engines can be accessed from any channel.
- *
- * We still want to use a separate channel though.
- */
- ret = nouveau_channel_new(drm, device, NvDmaFB, NvDmaTT, false,
- &drm->cechan);
+ runm = nvif_fifo_runlist_ce(device);
+ if (!runm) {
+ NV_DEBUG(drm, "no ce runlist\n");
+ return;
}
+ ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->cechan);
if (ret)
NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
}
@@ -355,23 +346,17 @@ static void
nouveau_accel_gr_init(struct nouveau_drm *drm)
{
struct nvif_device *device = &drm->client.device;
- u32 arg0, arg1;
+ u64 runm;
int ret;
- if (device->info.family >= NV_DEVICE_INFO_V0_AMPERE)
- return;
-
/* Allocate channel that has access to the graphics engine. */
- if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
- arg0 = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR);
- arg1 = 1;
- } else {
- arg0 = NvDmaFB;
- arg1 = NvDmaTT;
+ runm = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR);
+ if (!runm) {
+ NV_DEBUG(drm, "no gr runlist\n");
+ return;
}
- ret = nouveau_channel_new(drm, device, arg0, arg1, false,
- &drm->channel);
+ ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->channel);
if (ret) {
NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
nouveau_accel_gr_fini(drm);
@@ -436,6 +421,7 @@ nouveau_accel_fini(struct nouveau_drm *drm)
nouveau_accel_gr_fini(drm);
if (drm->fence)
nouveau_fence(drm)->dtor(drm);
+ nouveau_channels_fini(drm);
}
static void
@@ -485,6 +471,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
case PASCAL_CHANNEL_GPFIFO_A:
case VOLTA_CHANNEL_GPFIFO_A:
case TURING_CHANNEL_GPFIFO_A:
+ case AMPERE_CHANNEL_GPFIFO_A:
case AMPERE_CHANNEL_GPFIFO_B:
ret = nvc0_fence_create(drm);
break;
@@ -611,7 +598,6 @@ nouveau_drm_device_init(struct drm_device *dev)
nouveau_hwmon_init(dev);
nouveau_svm_init(drm);
nouveau_dmem_init(drm);
- nouveau_fbcon_init(dev);
nouveau_led_init(dev);
if (nouveau_pmops_runtime()) {
@@ -655,7 +641,6 @@ nouveau_drm_device_fini(struct drm_device *dev)
}
nouveau_led_fini(dev);
- nouveau_fbcon_fini(dev);
nouveau_dmem_fini(drm);
nouveau_svm_fini(drm);
nouveau_hwmon_fini(dev);
@@ -809,6 +794,11 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
if (ret)
goto fail_drm_dev_init;
+ if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024)
+ drm_fbdev_generic_setup(drm_dev, 8);
+ else
+ drm_fbdev_generic_setup(drm_dev, 32);
+
quirk_broken_nv_runpm(pdev);
return 0;
@@ -865,8 +855,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
nouveau_led_suspend(dev);
if (dev->mode_config.num_crtc) {
- NV_DEBUG(drm, "suspending console...\n");
- nouveau_fbcon_set_suspend(dev, 1);
NV_DEBUG(drm, "suspending display...\n");
ret = nouveau_display_suspend(dev, runtime);
if (ret)
@@ -940,8 +928,6 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
if (dev->mode_config.num_crtc) {
NV_DEBUG(drm, "resuming display...\n");
nouveau_display_resume(dev, runtime);
- NV_DEBUG(drm, "resuming console...\n");
- nouveau_fbcon_set_suspend(dev, 0);
}
nouveau_led_resume(dev);
@@ -1296,7 +1282,6 @@ static void nouveau_display_options(void)
DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable);
DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid);
DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink);
- DRM_DEBUG_DRIVER("... nofbaccel : %d\n", nouveau_nofbaccel);
DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config);
DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug);
DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 84df5ddae4d0..d6dd07bfa64a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -78,11 +78,6 @@ enum nouveau_drm_object_route {
NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY,
};
-enum nouveau_drm_notify_route {
- NVDRM_NOTIFY_NVIF = 0,
- NVDRM_NOTIFY_USIF
-};
-
enum nouveau_drm_handle {
NVDRM_CHAN = 0xcccc0000, /* |= client chid */
NVDRM_NVSW = 0x55550000,
@@ -179,16 +174,19 @@ struct nouveau_drm {
void *fence;
/* Global channel management. */
+ int chan_total; /* Number of channels across all runlists. */
+ int chan_nr; /* 0 if per-runlist CHIDs. */
+ int runl_nr;
struct {
- int nr;
+ int chan_nr;
+ int chan_id_base;
u64 context_base;
- } chan;
+ } *runl;
/* context for accelerated drm-internal operations */
struct nouveau_channel *cechan;
struct nouveau_channel *channel;
struct nvkm_gpuobj *notify;
- struct nouveau_fbdev *fbcon;
struct nvif_object ntfy;
/* nv10-nv40 tiling regions */
@@ -201,10 +199,8 @@ struct nouveau_drm {
struct nvbios vbios;
struct nouveau_display *display;
struct work_struct hpd_work;
- struct mutex hpd_lock;
+ spinlock_t hpd_lock;
u32 hpd_pending;
- struct work_struct fbcon_work;
- int fbcon_new_state;
#ifdef CONFIG_ACPI
struct notifier_block acpi_nb;
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index b72e5783a00f..70c1ad6c4d9d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -48,7 +48,6 @@ struct nouveau_encoder {
struct dcb_output *dcb;
struct nvif_outp outp;
int or;
- int link;
struct i2c_adapter *i2c;
struct nvkm_i2c_aux *aux;
@@ -142,8 +141,8 @@ enum nouveau_dp_status {
};
int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *);
-void nouveau_dp_irq(struct nouveau_drm *drm,
- struct nouveau_connector *nv_connector);
+bool nouveau_dp_link_check(struct nouveau_connector *);
+void nouveau_dp_irq(struct work_struct *);
enum drm_mode_status nv50_dp_mode_valid(struct drm_connector *,
struct nouveau_encoder *,
const struct drm_display_mode *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 3c7e0c9d6baf..e87de7906f78 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -231,9 +231,9 @@ void
nouveau_fbcon_accel_save_disable(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- if (drm->fbcon && drm->fbcon->helper.fbdev) {
- drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
- drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+ if (drm->fbcon && drm->fbcon->helper.info) {
+ drm->fbcon->saved_flags = drm->fbcon->helper.info->flags;
+ drm->fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED;
}
}
@@ -241,9 +241,8 @@ void
nouveau_fbcon_accel_restore(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- if (drm->fbcon && drm->fbcon->helper.fbdev) {
- drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
- }
+ if (drm->fbcon && drm->fbcon->helper.info)
+ drm->fbcon->helper.info->flags = drm->fbcon->saved_flags;
}
static void
@@ -253,8 +252,8 @@ nouveau_fbcon_accel_fini(struct drm_device *dev)
struct nouveau_fbdev *fbcon = drm->fbcon;
if (fbcon && drm->channel) {
console_lock();
- if (fbcon->helper.fbdev)
- fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+ if (fbcon->helper.info)
+ fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED;
console_unlock();
nouveau_channel_idle(drm->channel);
nvif_object_dtor(&fbcon->twod);
@@ -272,7 +271,7 @@ nouveau_fbcon_accel_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_fbdev *fbcon = drm->fbcon;
- struct fb_info *info = fbcon->helper.fbdev;
+ struct fb_info *info = fbcon->helper.info;
int ret;
if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA)
@@ -290,7 +289,7 @@ nouveau_fbcon_accel_init(struct drm_device *dev)
static void
nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
{
- struct fb_info *info = fbcon->helper.fbdev;
+ struct fb_info *info = fbcon->helper.info;
struct fb_fillrect rect;
/* Clear the entire fbcon. The drm will program every connector
@@ -363,7 +362,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
}
}
- info = drm_fb_helper_alloc_fbi(helper);
+ info = drm_fb_helper_alloc_info(helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto out_unlock;
@@ -420,7 +419,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
struct drm_framebuffer *fb = fbcon->helper.fb;
struct nouveau_bo *nvbo;
- drm_fb_helper_unregister_fbi(&fbcon->helper);
+ drm_fb_helper_unregister_info(&fbcon->helper);
drm_fb_helper_fini(&fbcon->helper);
if (fb && fb->obj[0]) {
@@ -586,8 +585,8 @@ nouveau_fbcon_init(struct drm_device *dev)
if (ret)
goto fini;
- if (fbcon->helper.fbdev)
- fbcon->helper.fbdev->pixmap.buf_align = 4;
+ if (fbcon->helper.info)
+ fbcon->helper.info->pixmap.buf_align = 4;
return 0;
fini:
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
deleted file mode 100644
index 1796d8824580..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 Maarten Maathuis.
- * All Rights Reserved.
- *
- * 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 (including the
- * next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __NOUVEAU_FBCON_H__
-#define __NOUVEAU_FBCON_H__
-
-#include <drm/drm_fb_helper.h>
-
-#include "nouveau_display.h"
-
-struct nouveau_vma;
-
-struct nouveau_fbdev {
- struct drm_fb_helper helper; /* must be first */
- unsigned int saved_flags;
- struct nvif_object surf2d;
- struct nvif_object clip;
- struct nvif_object rop;
- struct nvif_object patt;
- struct nvif_object gdi;
- struct nvif_object blit;
- struct nvif_object twod;
- struct nouveau_vma *vma;
-
- struct mutex hotplug_lock;
- bool hotplug_waiting;
-};
-
-void nouveau_fbcon_restore(void);
-
-int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
-int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
-int nv04_fbcon_accel_init(struct fb_info *info);
-
-int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
-int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
-int nv50_fbcon_accel_init(struct fb_info *info);
-
-int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
-int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
-int nvc0_fbcon_accel_init(struct fb_info *info);
-
-void nouveau_fbcon_gpu_lockup(struct fb_info *info);
-
-int nouveau_fbcon_init(struct drm_device *dev);
-void nouveau_fbcon_fini(struct drm_device *dev);
-void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
-void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
-void nouveau_fbcon_accel_restore(struct drm_device *dev);
-
-void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
-void nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon);
-extern int nouveau_nofbaccel;
-
-#endif /* __NV50_FBCON_H__ */
-
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index abcac7db4347..ee5e9d40c166 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -29,9 +29,7 @@
#include <linux/sched/signal.h>
#include <trace/events/dma_fence.h>
-#include <nvif/cl826e.h>
-#include <nvif/notify.h>
-#include <nvif/event.h>
+#include <nvif/if0020.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@@ -79,10 +77,6 @@ nouveau_local_fence(struct dma_fence *fence, struct nouveau_drm *drm)
fence->ops != &nouveau_fence_ops_uevent)
return NULL;
- if (fence->context < drm->chan.context_base ||
- fence->context >= drm->chan.context_base + drm->chan.nr)
- return NULL;
-
return from_fence(fence);
}
@@ -90,8 +84,9 @@ void
nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
{
struct nouveau_fence *fence;
+ unsigned long flags;
- spin_lock_irq(&fctx->lock);
+ spin_lock_irqsave(&fctx->lock, flags);
while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);
@@ -99,16 +94,16 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
dma_fence_set_error(&fence->base, error);
if (nouveau_fence_signal(fence))
- nvif_notify_put(&fctx->notify);
+ nvif_event_block(&fctx->event);
}
- spin_unlock_irq(&fctx->lock);
+ spin_unlock_irqrestore(&fctx->lock, flags);
}
void
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
nouveau_fence_context_kill(fctx, 0);
- nvif_notify_dtor(&fctx->notify);
+ nvif_event_dtor(&fctx->event);
fctx->dead = 1;
/*
@@ -150,12 +145,11 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc
}
static int
-nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
+nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_fence_chan *fctx =
- container_of(notify, typeof(*fctx), notify);
+ struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event);
unsigned long flags;
- int ret = NVIF_NOTIFY_KEEP;
+ int ret = NVIF_EVENT_KEEP;
spin_lock_irqsave(&fctx->lock, flags);
if (!list_empty(&fctx->pending)) {
@@ -165,7 +159,7 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
fence = list_entry(fctx->pending.next, typeof(*fence), head);
chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (nouveau_fence_update(chan, fctx))
- ret = NVIF_NOTIFY_DROP;
+ ret = NVIF_EVENT_DROP;
}
spin_unlock_irqrestore(&fctx->lock, flags);
@@ -177,12 +171,16 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
{
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
struct nouveau_cli *cli = (void *)chan->user.client;
+ struct {
+ struct nvif_event_v0 base;
+ struct nvif_chan_event_v0 host;
+ } args;
int ret;
INIT_LIST_HEAD(&fctx->flip);
INIT_LIST_HEAD(&fctx->pending);
spin_lock_init(&fctx->lock);
- fctx->context = chan->drm->chan.context_base + chan->chid;
+ fctx->context = chan->drm->runl[chan->runlist].context_base + chan->chid;
if (chan == chan->drm->cechan)
strcpy(fctx->name, "copy engine channel");
@@ -195,13 +193,12 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
if (!priv->uevent)
return;
- ret = nvif_notify_ctor(&chan->user, "fenceNonStallIntr",
- nouveau_fence_wait_uevent_handler,
- false, NV826E_V0_NTFY_NON_STALL_INTERRUPT,
- &(struct nvif_notify_uevent_req) { },
- sizeof(struct nvif_notify_uevent_req),
- sizeof(struct nvif_notify_uevent_rep),
- &fctx->notify);
+ args.host.version = 0;
+ args.host.type = NVIF_CHAN_EVENT_V0_NON_STALL_INTR;
+
+ ret = nvif_event_ctor(&chan->user, "fenceNonStallIntr", (chan->runlist << 16) | chan->chid,
+ nouveau_fence_wait_uevent_handler, false,
+ &args.base, sizeof(args), &fctx->event);
WARN_ON(ret);
}
@@ -230,7 +227,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
spin_lock_irq(&fctx->lock);
if (nouveau_fence_update(chan, fctx))
- nvif_notify_put(&fctx->notify);
+ nvif_event_block(&fctx->event);
list_add_tail(&fence->head, &fctx->pending);
spin_unlock_irq(&fctx->lock);
@@ -254,7 +251,7 @@ nouveau_fence_done(struct nouveau_fence *fence)
spin_lock_irqsave(&fctx->lock, flags);
chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (chan && nouveau_fence_update(chan, fctx))
- nvif_notify_put(&fctx->notify);
+ nvif_event_block(&fctx->event);
spin_unlock_irqrestore(&fctx->lock, flags);
}
return dma_fence_is_signaled(&fence->base);
@@ -505,13 +502,13 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f)
bool ret;
if (!fctx->notify_ref++)
- nvif_notify_get(&fctx->notify);
+ nvif_event_allow(&fctx->event);
ret = nouveau_fence_no_signaling(f);
if (ret)
set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags);
else if (!--fctx->notify_ref)
- nvif_notify_put(&fctx->notify);
+ nvif_event_block(&fctx->event);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index 4887caa69c65..0ca2bc85adf6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -3,7 +3,7 @@
#define __NOUVEAU_FENCE_H__
#include <linux/dma-fence.h>
-#include <nvif/notify.h>
+#include <nvif/event.h>
struct nouveau_drm;
struct nouveau_bo;
@@ -44,7 +44,7 @@ struct nouveau_fence_chan {
u32 context;
char name[32];
- struct nvif_notify notify;
+ struct nvif_event event;
int notify_ref, dead;
};
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index fab542a758ff..ac5793c96957 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -679,7 +679,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
}
if (!nvbo->kmap.virtual) {
- ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages,
+ ret = ttm_bo_kmap(&nvbo->bo, 0, PFN_UP(nvbo->bo.base.size),
&nvbo->kmap);
if (ret) {
NV_PRINTK(err, cli, "failed kmap for reloc\n");
@@ -868,8 +868,7 @@ revalidate:
if (unlikely(cmd != req->suffix0)) {
if (!nvbo->kmap.virtual) {
ret = ttm_bo_kmap(&nvbo->bo, 0,
- nvbo->bo.resource->
- num_pages,
+ PFN_UP(nvbo->bo.base.size),
&nvbo->kmap);
if (ret) {
WIND_RING(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 76f8edefa637..1fde3a5d7c32 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -115,7 +115,7 @@ nouveau_mem_host(struct ttm_resource *reg, struct ttm_tt *tt)
mutex_lock(&drm->master.lock);
ret = nvif_mem_ctor_type(mmu, "ttmHostMem", cli->mem->oclass, type, PAGE_SHIFT,
- reg->num_pages << PAGE_SHIFT,
+ reg->size,
&args, sizeof(args), &mem->mem);
mutex_unlock(&drm->master.lock);
return ret;
@@ -128,7 +128,7 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page)
struct nouveau_cli *cli = mem->cli;
struct nouveau_drm *drm = cli->drm;
struct nvif_mmu *mmu = &cli->mmu;
- u64 size = ALIGN(reg->num_pages << PAGE_SHIFT, 1 << page);
+ u64 size = ALIGN(reg->size, 1 << page);
int ret;
mutex_lock(&drm->master.lock);
diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c
index df0fe58ca3ab..1d49ebdfd5dc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_nvif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c
@@ -27,12 +27,10 @@
******************************************************************************/
#include <core/client.h>
-#include <core/notify.h>
#include <core/ioctl.h>
#include <nvif/client.h>
#include <nvif/driver.h>
-#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvif/ioctl.h>
@@ -72,10 +70,23 @@ nvkm_client_suspend(void *priv)
}
static int
+nvkm_client_event(u64 token, void *repv, u32 repc)
+{
+ struct nvif_object *object = (void *)(unsigned long)token;
+ struct nvif_event *event = container_of(object, typeof(*event), object);
+
+ if (event->func(event, repv, repc) == NVIF_EVENT_KEEP)
+ return NVKM_EVENT_KEEP;
+
+ return NVKM_EVENT_DROP;
+}
+
+static int
nvkm_client_driver_init(const char *name, u64 device, const char *cfg,
const char *dbg, void **ppriv)
{
- return nvkm_client_new(name, device, cfg, dbg, nvif_notify, (struct nvkm_client **)ppriv);
+ return nvkm_client_new(name, device, cfg, dbg, nvkm_client_event,
+ (struct nvkm_client **)ppriv);
}
const struct nvif_driver
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
index 31a5b81ee9fc..a74ba8d84ba7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -24,7 +24,7 @@
#include "nouveau_chan.h"
#include "nouveau_dmem.h"
-#include <nvif/notify.h>
+#include <nvif/event.h>
#include <nvif/object.h>
#include <nvif/vmm.h>
@@ -51,7 +51,8 @@ struct nouveau_svm {
u32 putaddr;
u32 get;
u32 put;
- struct nvif_notify notify;
+ struct nvif_event notify;
+ struct work_struct work;
struct nouveau_svm_fault {
u64 inst;
@@ -711,13 +712,11 @@ out:
return ret;
}
-static int
-nouveau_svm_fault(struct nvif_notify *notify)
+static void
+nouveau_svm_fault(struct work_struct *work)
{
- struct nouveau_svm_fault_buffer *buffer =
- container_of(notify, typeof(*buffer), notify);
- struct nouveau_svm *svm =
- container_of(buffer, typeof(*svm), buffer[buffer->id]);
+ struct nouveau_svm_fault_buffer *buffer = container_of(work, typeof(*buffer), work);
+ struct nouveau_svm *svm = container_of(buffer, typeof(*svm), buffer[buffer->id]);
struct nvif_object *device = &svm->drm->client.device.object;
struct nouveau_svmm *svmm;
struct {
@@ -737,7 +736,7 @@ nouveau_svm_fault(struct nvif_notify *notify)
buffer->put = nvif_rd32(device, buffer->putaddr);
buffer->get = nvif_rd32(device, buffer->getaddr);
if (buffer->get == buffer->put)
- return NVIF_NOTIFY_KEEP;
+ return;
}
buffer->fault_nr = 0;
@@ -881,7 +880,15 @@ nouveau_svm_fault(struct nvif_notify *notify)
/* Issue fault replay to the GPU. */
if (replay)
nouveau_svm_fault_replay(svm);
- return NVIF_NOTIFY_KEEP;
+}
+
+static int
+nouveau_svm_event(struct nvif_event *event, void *argv, u32 argc)
+{
+ struct nouveau_svm_fault_buffer *buffer = container_of(event, typeof(*buffer), notify);
+
+ schedule_work(&buffer->work);
+ return NVIF_EVENT_KEEP;
}
static struct nouveau_pfnmap_args *
@@ -936,7 +943,9 @@ static void
nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
{
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
- nvif_notify_put(&buffer->notify);
+
+ nvif_event_block(&buffer->notify);
+ flush_work(&buffer->work);
}
static int
@@ -944,10 +953,12 @@ nouveau_svm_fault_buffer_init(struct nouveau_svm *svm, int id)
{
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
struct nvif_object *device = &svm->drm->client.device.object;
+
buffer->get = nvif_rd32(device, buffer->getaddr);
buffer->put = nvif_rd32(device, buffer->putaddr);
SVM_DBG(svm, "get %08x put %08x (init)", buffer->get, buffer->put);
- return nvif_notify_get(&buffer->notify);
+
+ return nvif_event_allow(&buffer->notify);
}
static void
@@ -956,15 +967,18 @@ nouveau_svm_fault_buffer_dtor(struct nouveau_svm *svm, int id)
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
int i;
+ if (!nvif_object_constructed(&buffer->object))
+ return;
+
+ nouveau_svm_fault_buffer_fini(svm, id);
+
if (buffer->fault) {
for (i = 0; buffer->fault[i] && i < buffer->entries; i++)
kfree(buffer->fault[i]);
kvfree(buffer->fault);
}
- nouveau_svm_fault_buffer_fini(svm, id);
-
- nvif_notify_dtor(&buffer->notify);
+ nvif_event_dtor(&buffer->notify);
nvif_object_dtor(&buffer->object);
}
@@ -990,10 +1004,10 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)
buffer->entries = args.entries;
buffer->getaddr = args.get;
buffer->putaddr = args.put;
+ INIT_WORK(&buffer->work, nouveau_svm_fault);
- ret = nvif_notify_ctor(&buffer->object, "svmFault", nouveau_svm_fault,
- true, NVB069_V0_NTFY_FAULT, NULL, 0, 0,
- &buffer->notify);
+ ret = nvif_event_ctor(&buffer->object, "svmFault", id, nouveau_svm_event, true, NULL, 0,
+ &buffer->notify);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 9602c30928f2..1469a88910e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -139,7 +139,7 @@ nv04_gart_manager_new(struct ttm_resource_manager *man,
mem = nouveau_mem(*res);
ttm_resource_init(bo, place, *res);
ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0,
- (long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]);
+ (long)(*res)->size, &mem->vma[0]);
if (ret) {
nouveau_mem_del(man, *res);
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c
index 36df6840c099..002d1479ba89 100644
--- a/drivers/gpu/drm/nouveau/nouveau_usif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_usif.c
@@ -151,12 +151,6 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
case NVIF_IOCTL_V0_NEW:
ret = usif_object_new(filp, data, size, argv, argc, abi16);
break;
- case NVIF_IOCTL_V0_NTFY_NEW:
- case NVIF_IOCTL_V0_NTFY_DEL:
- case NVIF_IOCTL_V0_NTFY_GET:
- case NVIF_IOCTL_V0_NTFY_PUT:
- ret = -ENOSYS;
- break;
default:
ret = nvif_client_ioctl(client, argv, argc);
break;
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 60cd8c0463df..789393b94291 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -7,7 +7,6 @@
#include "nouveau_drv.h"
#include "nouveau_acpi.h"
-#include "nouveau_fbcon.h"
#include "nouveau_vga.h"
static unsigned int
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
deleted file mode 100644
index 92f3fb6765ab..000000000000
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright 2009 Ben Skeggs
- * Copyright 2008 Stuart Bennett
- *
- * 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 (including the next
- * paragraph) 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.
- */
-#define NVIF_DEBUG_PRINT_DISABLE
-#include "nouveau_drv.h"
-#include "nouveau_dma.h"
-#include "nouveau_fbcon.h"
-
-#include <nvif/push006c.h>
-
-int
-nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret;
-
- ret = PUSH_WAIT(push, 4);
- if (ret)
- return ret;
-
- PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
- 0x0304, (region->dy << 16) | region->dx,
- 0x0308, (region->height << 16) | region->width);
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret;
-
- ret = PUSH_WAIT(push, 7);
- if (ret)
- return ret;
-
- PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR)
- PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
- else
- PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
- PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
- 0x0404, (rect->width << 16) | rect->height);
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- uint32_t fg;
- uint32_t bg;
- uint32_t dsize;
- uint32_t *data = (uint32_t *)image->data;
- int ret;
-
- if (image->depth != 1)
- return -ENODEV;
-
- ret = PUSH_WAIT(push, 8);
- if (ret)
- return ret;
-
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
- bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
- } else {
- fg = image->fg_color;
- bg = image->bg_color;
- }
-
- PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
- 0x0be8, ((image->dy + image->height) << 16) |
- ((image->dx + image->width) & 0xffff),
- 0x0bec, bg,
- 0x0bf0, fg,
- 0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
- 0x0bf8, (image->height << 16) | image->width,
- 0x0bfc, (image->dy << 16) | (image->dx & 0xffff));
-
- dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
- while (dsize) {
- int iter_len = dsize > 128 ? 128 : dsize;
-
- ret = PUSH_WAIT(push, iter_len + 1);
- if (ret)
- return ret;
-
- PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
- data += iter_len;
- dsize -= iter_len;
- }
-
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv04_fbcon_accel_init(struct fb_info *info)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct drm_device *dev = nfbdev->helper.dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_device *device = &drm->client.device;
- struct nvif_push *push = chan->chan.push;
- int surface_fmt, pattern_fmt, rect_fmt;
- int ret;
-
- switch (info->var.bits_per_pixel) {
- case 8:
- surface_fmt = 1;
- pattern_fmt = 3;
- rect_fmt = 3;
- break;
- case 16:
- surface_fmt = 4;
- pattern_fmt = 1;
- rect_fmt = 1;
- break;
- case 32:
- switch (info->var.transp.length) {
- case 0: /* depth 24 */
- case 8: /* depth 32 */
- break;
- default:
- return -EINVAL;
- }
-
- surface_fmt = 6;
- pattern_fmt = 3;
- rect_fmt = 3;
- break;
- default:
- return -EINVAL;
- }
-
- ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062,
- device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
- 0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
- if (ret)
- return ret;
-
- ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
- NULL, 0, &nfbdev->clip);
- if (ret)
- return ret;
-
- ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
- NULL, 0, &nfbdev->rop);
- if (ret)
- return ret;
-
- ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
- NULL, 0, &nfbdev->patt);
- if (ret)
- return ret;
-
- ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
- NULL, 0, &nfbdev->gdi);
- if (ret)
- return ret;
-
- ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
- device->info.chipset >= 0x11 ? 0x009f : 0x005f,
- NULL, 0, &nfbdev->blit);
- if (ret)
- return ret;
-
- if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
- nouveau_fbcon_gpu_lockup(info);
- return 0;
- }
-
- PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
- PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
- 0x0188, chan->vram.handle);
- PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
- 0x0304, info->fix.line_length | (info->fix.line_length << 16),
- 0x0308, info->fix.smem_start - dev->mode_config.fb_base,
- 0x030c, info->fix.smem_start - dev->mode_config.fb_base);
-
- PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
- PUSH_NVSQ(push, NV043, 0x0300, 0x55);
-
- PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
- PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
-#ifdef __BIG_ENDIAN
- 0x0304, 2,
-#else
- 0x0304, 1,
-#endif
- 0x0308, 0,
- 0x030c, 1,
- 0x0310, ~0,
- 0x0314, ~0,
- 0x0318, ~0,
- 0x031c, ~0);
-
- PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
- PUSH_NVSQ(push, NV019, 0x0300, 0,
- 0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
-
- PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
- PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
- PUSH_NVSQ(push, NV05F, 0x02fc, 3);
- if (nfbdev->blit.oclass == 0x009f) {
- PUSH_NVSQ(push, NV09F, 0x0120, 0,
- 0x0124, 1,
- 0x0128, 2);
- }
-
- PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
- PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
- PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
- 0x018c, nfbdev->rop.handle);
- PUSH_NVSQ(push, NV04A, 0x0304, 1);
- PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
- PUSH_NVSQ(push, NV04A, 0x02fc, 3);
-
- PUSH_KICK(push);
- return 0;
-}
-
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
deleted file mode 100644
index 71f92e4750f9..000000000000
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#define NVIF_DEBUG_PRINT_DISABLE
-#include "nouveau_drv.h"
-#include "nouveau_dma.h"
-#include "nouveau_fbcon.h"
-#include "nouveau_vmm.h"
-
-#include <nvif/push206e.h>
-
-#include <nvhw/class/cl502d.h>
-
-int
-nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- u32 colour;
- int ret;
-
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR)
- colour = ((uint32_t *)info->pseudo_palette)[rect->color];
- else
- colour = rect->color;
-
- ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 11);
- if (ret)
- return ret;
-
- if (rect->rop != ROP_COPY) {
- PUSH_MTHD(push, NV502D, SET_OPERATION,
- NVDEF(NV502D, SET_OPERATION, V, ROP_AND));
- }
-
- PUSH_MTHD(push, NV502D, SET_RENDER_SOLID_PRIM_COLOR, colour);
-
- PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
- RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
- RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
- RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
-
- if (rect->rop != ROP_COPY) {
- PUSH_MTHD(push, NV502D, SET_OPERATION,
- NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
- }
-
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret;
-
- ret = PUSH_WAIT(push, 12);
- if (ret)
- return ret;
-
- PUSH_MTHD(push, NV502D, WAIT_FOR_IDLE, 0);
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
- SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
- SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
- SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
- SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
- PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- uint32_t dwords, *data = (uint32_t *)image->data;
- uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
- uint32_t *palette = info->pseudo_palette, bg, fg;
- int ret;
-
- if (image->depth != 1)
- return -ENODEV;
-
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- bg = palette[image->bg_color] | mask;
- fg = palette[image->fg_color] | mask;
- } else {
- bg = image->bg_color;
- fg = image->fg_color;
- }
-
- ret = PUSH_WAIT(push, 11);
- if (ret)
- return ret;
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_COLOR0, bg,
- SET_PIXELS_FROM_CPU_COLOR1, fg);
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
- SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
- SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
- SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
- SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
-
- dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
- while (dwords) {
- int count = dwords > 2047 ? 2047 : dwords;
-
- ret = PUSH_WAIT(push, count + 1);
- if (ret)
- return ret;
-
- dwords -= count;
-
- PUSH_NINC(push, NV502D, PIXELS_FROM_CPU_DATA, data, count);
- data += count;
- }
-
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nv50_fbcon_accel_init(struct fb_info *info)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct drm_device *dev = nfbdev->helper.dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret, format;
-
- switch (info->var.bits_per_pixel) {
- case 8:
- format = NV502D_SET_DST_FORMAT_V_Y8;
- break;
- case 15:
- format = NV502D_SET_DST_FORMAT_V_X1R5G5B5;
- break;
- case 16:
- format = NV502D_SET_DST_FORMAT_V_R5G6B5;
- break;
- case 32:
- switch (info->var.transp.length) {
- case 0: /* depth 24 */
- case 8: /* depth 32, just use 24.. */
- format = NV502D_SET_DST_FORMAT_V_X8R8G8B8;
- break;
- case 2: /* depth 30 */
- format = NV502D_SET_DST_FORMAT_V_A2B10G10R10;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
-
- ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x502d, 0x502d,
- NULL, 0, &nfbdev->twod);
- if (ret)
- return ret;
-
- ret = PUSH_WAIT(push, 56);
- if (ret) {
- nouveau_fbcon_gpu_lockup(info);
- return ret;
- }
-
- PUSH_MTHD(push, NV502D, SET_OBJECT, nfbdev->twod.handle);
- PUSH_MTHD(push, NV502D, SET_DST_CONTEXT_DMA, chan->vram.handle,
- SET_SRC_CONTEXT_DMA, chan->vram.handle,
- SET_SEMAPHORE_CONTEXT_DMA, chan->vram.handle);
-
- PUSH_MTHD(push, NV502D, SET_DST_FORMAT,
- NVVAL(NV502D, SET_DST_FORMAT, V, format),
-
- SET_DST_MEMORY_LAYOUT,
- NVDEF(NV502D, SET_DST_MEMORY_LAYOUT, V, PITCH));
-
- PUSH_MTHD(push, NV502D, SET_DST_PITCH, info->fix.line_length,
- SET_DST_WIDTH, info->var.xres_virtual,
- SET_DST_HEIGHT, info->var.yres_virtual,
-
- SET_DST_OFFSET_UPPER,
- NVVAL(NV502D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
-
- SET_DST_OFFSET_LOWER,
- NVVAL(NV502D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
-
- PUSH_MTHD(push, NV502D, SET_SRC_FORMAT,
- NVVAL(NV502D, SET_SRC_FORMAT, V, format),
-
- SET_SRC_MEMORY_LAYOUT,
- NVDEF(NV502D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
-
- PUSH_MTHD(push, NV502D, SET_SRC_PITCH, info->fix.line_length,
- SET_SRC_WIDTH, info->var.xres_virtual,
- SET_SRC_HEIGHT, info->var.yres_virtual,
-
- SET_SRC_OFFSET_UPPER,
- NVVAL(NV502D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
-
- SET_SRC_OFFSET_LOWER,
- NVVAL(NV502D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
-
- PUSH_MTHD(push, NV502D, SET_CLIP_ENABLE,
- NVDEF(NV502D, SET_CLIP_ENABLE, V, FALSE));
-
- PUSH_MTHD(push, NV502D, SET_ROP,
- NVVAL(NV502D, SET_ROP, V, 0x55));
-
- PUSH_MTHD(push, NV502D, SET_OPERATION,
- NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
-
- PUSH_MTHD(push, NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
- NVDEF(NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
-
- SET_MONOCHROME_PATTERN_FORMAT,
- NVDEF(NV502D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
-
- PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_MODE,
- NVDEF(NV502D, RENDER_SOLID_PRIM_MODE, V, RECTS),
-
- SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
- NVVAL(NV502D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE,
- NVDEF(NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
-
- SET_PIXELS_FROM_CPU_COLOR_FORMAT,
- NVVAL(NV502D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
-
- SET_PIXELS_FROM_CPU_INDEX_FORMAT,
- NVDEF(NV502D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
-
- SET_PIXELS_FROM_CPU_MONO_FORMAT,
- NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
-
- SET_PIXELS_FROM_CPU_WRAP,
- NVDEF(NV502D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
- NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
- SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
- SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
- SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
- NVDEF(NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
-
- PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
- SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
- PUSH_KICK(push);
- return 0;
-}
-
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index c3526a8622e3..812b8c62eeba 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -76,12 +76,18 @@ nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
return ret;
}
+static inline u32
+nv84_fence_chid(struct nouveau_channel *chan)
+{
+ return chan->drm->runl[chan->runlist].chan_id_base + chan->chid;
+}
+
static int
nv84_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel *chan = fence->channel;
struct nv84_fence_chan *fctx = chan->fence;
- u64 addr = fctx->vma->addr + chan->chid * 16;
+ u64 addr = fctx->vma->addr + nv84_fence_chid(chan) * 16;
return fctx->base.emit32(chan, addr, fence->base.seqno);
}
@@ -91,7 +97,7 @@ nv84_fence_sync(struct nouveau_fence *fence,
struct nouveau_channel *prev, struct nouveau_channel *chan)
{
struct nv84_fence_chan *fctx = chan->fence;
- u64 addr = fctx->vma->addr + prev->chid * 16;
+ u64 addr = fctx->vma->addr + nv84_fence_chid(prev) * 16;
return fctx->base.sync32(chan, addr, fence->base.seqno);
}
@@ -100,7 +106,7 @@ static u32
nv84_fence_read(struct nouveau_channel *chan)
{
struct nv84_fence_priv *priv = chan->drm->fence;
- return nouveau_bo_rd32(priv->bo, chan->chid * 16/4);
+ return nouveau_bo_rd32(priv->bo, nv84_fence_chid(chan) * 16/4);
}
static void
@@ -109,7 +115,7 @@ nv84_fence_context_del(struct nouveau_channel *chan)
struct nv84_fence_priv *priv = chan->drm->fence;
struct nv84_fence_chan *fctx = chan->fence;
- nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
+ nouveau_bo_wr32(priv->bo, nv84_fence_chid(chan) * 16 / 4, fctx->base.sequence);
mutex_lock(&priv->mutex);
nouveau_vma_del(&fctx->vma);
mutex_unlock(&priv->mutex);
@@ -152,9 +158,9 @@ nv84_fence_suspend(struct nouveau_drm *drm)
struct nv84_fence_priv *priv = drm->fence;
int i;
- priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr));
+ priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan_total));
if (priv->suspend) {
- for (i = 0; i < drm->chan.nr; i++)
+ for (i = 0; i < drm->chan_total; i++)
priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
}
@@ -168,7 +174,7 @@ nv84_fence_resume(struct nouveau_drm *drm)
int i;
if (priv->suspend) {
- for (i = 0; i < drm->chan.nr; i++)
+ for (i = 0; i < drm->chan_total; i++)
nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
vfree(priv->suspend);
priv->suspend = NULL;
@@ -204,7 +210,7 @@ nv84_fence_create(struct nouveau_drm *drm)
priv->base.context_new = nv84_fence_context_new;
priv->base.context_del = nv84_fence_context_del;
- priv->base.uevent = drm->client.device.info.family < NV_DEVICE_INFO_V0_AMPERE;
+ priv->base.uevent = true;
mutex_init(&priv->mutex);
@@ -216,7 +222,7 @@ nv84_fence_create(struct nouveau_drm *drm)
* will lose CPU/GPU coherency!
*/
NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
- ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0,
+ ret = nouveau_bo_new(&drm->client, 16 * drm->chan_total, 0,
domain, 0, 0, NULL, NULL, &priv->bo);
if (ret == 0) {
ret = nouveau_bo_pin(priv->bo, domain, false);
diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
deleted file mode 100644
index 7908a1a3e00f..000000000000
--- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#define NVIF_DEBUG_PRINT_DISABLE
-#include "nouveau_drv.h"
-#include "nouveau_dma.h"
-#include "nouveau_fbcon.h"
-#include "nouveau_vmm.h"
-
-#include <nvif/push906f.h>
-
-#include <nvhw/class/cl902d.h>
-
-int
-nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- u32 colour;
- int ret;
-
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR)
- colour = ((uint32_t *)info->pseudo_palette)[rect->color];
- else
- colour = rect->color;
-
- ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 9);
- if (ret)
- return ret;
-
- if (rect->rop != ROP_COPY) {
- PUSH_IMMD(push, NV902D, SET_OPERATION,
- NVDEF(NV902D, SET_OPERATION, V, ROP_AND));
- }
-
- PUSH_MTHD(push, NV902D, SET_RENDER_SOLID_PRIM_COLOR, colour);
-
- PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
- RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
- RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
- RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
-
- if (rect->rop != ROP_COPY) {
- PUSH_IMMD(push, NV902D, SET_OPERATION,
- NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
- }
-
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret;
-
- ret = PUSH_WAIT(push, 11);
- if (ret)
- return ret;
-
- PUSH_IMMD(push, NV902D, WAIT_FOR_IDLE, 0);
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
- SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
- SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
- SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
- SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
- PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- uint32_t dwords, *data = (uint32_t *)image->data;
- uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
- uint32_t *palette = info->pseudo_palette, bg, fg;
- int ret;
-
- if (image->depth != 1)
- return -ENODEV;
-
- if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
- info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- bg = palette[image->bg_color] | mask;
- fg = palette[image->fg_color] | mask;
- } else {
- bg = image->bg_color;
- fg = image->fg_color;
- }
-
- ret = PUSH_WAIT(push, 11);
- if (ret)
- return ret;
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_COLOR0, bg,
- SET_PIXELS_FROM_CPU_COLOR1, fg);
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
- SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
- SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
- SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
- SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
-
- dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
- while (dwords) {
- int count = dwords > 2047 ? 2047 : dwords;
-
- ret = PUSH_WAIT(push, count + 1);
- if (ret)
- return ret;
-
- dwords -= count;
-
- PUSH_NINC(push, NV902D, PIXELS_FROM_CPU_DATA, data, count);
- data += count;
- }
-
- PUSH_KICK(push);
- return 0;
-}
-
-int
-nvc0_fbcon_accel_init(struct fb_info *info)
-{
- struct nouveau_fbdev *nfbdev = info->par;
- struct drm_device *dev = nfbdev->helper.dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_channel *chan = drm->channel;
- struct nvif_push *push = chan->chan.push;
- int ret, format;
-
- ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x902d, 0x902d,
- NULL, 0, &nfbdev->twod);
- if (ret)
- return ret;
-
- switch (info->var.bits_per_pixel) {
- case 8:
- format = NV902D_SET_DST_FORMAT_V_Y8;
- break;
- case 15:
- format = NV902D_SET_DST_FORMAT_V_X1R5G5B5;
- break;
- case 16:
- format = NV902D_SET_DST_FORMAT_V_R5G6B5;
- break;
- case 32:
- switch (info->var.transp.length) {
- case 0: /* depth 24 */
- case 8: /* depth 32, just use 24.. */
- format = NV902D_SET_DST_FORMAT_V_X8R8G8B8;
- break;
- case 2: /* depth 30 */
- format = NV902D_SET_DST_FORMAT_V_A2B10G10R10;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
-
- ret = PUSH_WAIT(push, 52);
- if (ret) {
- WARN_ON(1);
- nouveau_fbcon_gpu_lockup(info);
- return ret;
- }
-
- PUSH_MTHD(push, NV902D, SET_OBJECT, nfbdev->twod.handle);
-
- PUSH_MTHD(push, NV902D, SET_DST_FORMAT,
- NVVAL(NV902D, SET_DST_FORMAT, V, format),
-
- SET_DST_MEMORY_LAYOUT,
- NVDEF(NV902D, SET_DST_MEMORY_LAYOUT, V, PITCH));
-
- PUSH_MTHD(push, NV902D, SET_DST_PITCH, info->fix.line_length,
- SET_DST_WIDTH, info->var.xres_virtual,
- SET_DST_HEIGHT, info->var.yres_virtual,
-
- SET_DST_OFFSET_UPPER,
- NVVAL(NV902D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
-
- SET_DST_OFFSET_LOWER,
- NVVAL(NV902D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
-
- PUSH_MTHD(push, NV902D, SET_SRC_FORMAT,
- NVVAL(NV902D, SET_SRC_FORMAT, V, format),
-
- SET_SRC_MEMORY_LAYOUT,
- NVDEF(NV902D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
-
- PUSH_MTHD(push, NV902D, SET_SRC_PITCH, info->fix.line_length,
- SET_SRC_WIDTH, info->var.xres_virtual,
- SET_SRC_HEIGHT, info->var.yres_virtual,
-
- SET_SRC_OFFSET_UPPER,
- NVVAL(NV902D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
-
- SET_SRC_OFFSET_LOWER,
- NVVAL(NV902D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
-
- PUSH_IMMD(push, NV902D, SET_CLIP_ENABLE,
- NVDEF(NV902D, SET_CLIP_ENABLE, V, FALSE));
-
- PUSH_IMMD(push, NV902D, SET_ROP,
- NVVAL(NV902D, SET_ROP, V, 0x55));
-
- PUSH_IMMD(push, NV902D, SET_OPERATION,
- NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
-
- PUSH_MTHD(push, NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
- NVDEF(NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
-
- SET_MONOCHROME_PATTERN_FORMAT,
- NVDEF(NV902D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
-
- PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_MODE,
- NVDEF(NV902D, RENDER_SOLID_PRIM_MODE, V, RECTS),
-
- SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
- NVVAL(NV902D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE,
- NVDEF(NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
-
- SET_PIXELS_FROM_CPU_COLOR_FORMAT,
- NVVAL(NV902D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
-
- SET_PIXELS_FROM_CPU_INDEX_FORMAT,
- NVDEF(NV902D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
-
- SET_PIXELS_FROM_CPU_MONO_FORMAT,
- NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
-
- SET_PIXELS_FROM_CPU_WRAP,
- NVDEF(NV902D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
-
- PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
- NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
- SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
- SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
- SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
-
- PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
- NVDEF(NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
-
- PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
- SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
- SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
- PUSH_KICK(push);
- return 0;
-}
-
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild
index 6abc4bc42e35..b7963a39dd91 100644
--- a/drivers/gpu/drm/nouveau/nvif/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvif/Kbuild
@@ -5,10 +5,11 @@ nvif-y += nvif/conn.o
nvif-y += nvif/device.o
nvif-y += nvif/disp.o
nvif-y += nvif/driver.o
+nvif-y += nvif/event.o
nvif-y += nvif/fifo.o
+nvif-y += nvif/head.o
nvif-y += nvif/mem.o
nvif-y += nvif/mmu.o
-nvif-y += nvif/notify.o
nvif-y += nvif/outp.o
nvif-y += nvif/timer.o
nvif-y += nvif/vmm.o
diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c
index 4ce935d58c90..a3cf91aeae2d 100644
--- a/drivers/gpu/drm/nouveau/nvif/conn.c
+++ b/drivers/gpu/drm/nouveau/nvif/conn.c
@@ -27,6 +27,25 @@
#include <nvif/if0011.h>
int
+nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func func, u8 types,
+ struct nvif_event *event)
+{
+ struct {
+ struct nvif_event_v0 base;
+ struct nvif_conn_event_v0 conn;
+ } args;
+ int ret;
+
+ args.conn.version = 0;
+ args.conn.types = types;
+
+ ret = nvif_event_ctor_(&conn->object, name ?: "nvifConnHpd", nvif_conn_id(conn),
+ func, true, &args.base, sizeof(args), false, event);
+ NVIF_DEBUG(&conn->object, "[NEW EVENT:HPD types:%02x]", types);
+ return ret;
+}
+
+int
nvif_conn_hpd_status(struct nvif_conn *conn)
{
struct nvif_conn_hpd_status_v0 args;
diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c
index 926b0c04b1e8..09915f2715af 100644
--- a/drivers/gpu/drm/nouveau/nvif/disp.c
+++ b/drivers/gpu/drm/nouveau/nvif/disp.c
@@ -72,9 +72,10 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct
if (ret)
return ret;
- NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x",
- args.conn_mask, args.outp_mask);
+ NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x head_mask:%08x",
+ args.conn_mask, args.outp_mask, args.head_mask);
disp->conn_mask = args.conn_mask;
disp->outp_mask = args.outp_mask;
+ disp->head_mask = args.head_mask;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvif/event.c b/drivers/gpu/drm/nouveau/nvif/event.c
new file mode 100644
index 000000000000..61ff4d6eba9f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvif/event.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 <nvif/event.h>
+#include <nvif/printf.h>
+
+#include <nvif/class.h>
+#include <nvif/if000e.h>
+
+int
+nvif_event_block(struct nvif_event *event)
+{
+ if (nvif_event_constructed(event)) {
+ int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_BLOCK, NULL, 0);
+ NVIF_ERRON(ret, &event->object, "[BLOCK]");
+ return ret;
+ }
+ return 0;
+}
+
+int
+nvif_event_allow(struct nvif_event *event)
+{
+ if (nvif_event_constructed(event)) {
+ int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_ALLOW, NULL, 0);
+ NVIF_ERRON(ret, &event->object, "[ALLOW]");
+ return ret;
+ }
+ return 0;
+}
+
+void
+nvif_event_dtor(struct nvif_event *event)
+{
+ nvif_object_dtor(&event->object);
+}
+
+int
+nvif_event_ctor_(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func,
+ bool wait, struct nvif_event_v0 *args, u32 argc, bool warn,
+ struct nvif_event *event)
+{
+ struct nvif_event_v0 _args;
+ int ret;
+
+ if (!args) {
+ args = &_args;
+ argc = sizeof(_args);
+ }
+
+ args->version = 0;
+ args->wait = wait;
+
+ ret = nvif_object_ctor(parent, name ?: "nvifEvent", handle,
+ NVIF_CLASS_EVENT, args, argc, &event->object);
+ NVIF_ERRON(ret && warn, parent, "[NEW EVENT wait:%d size:%zd]",
+ args->wait, argc - sizeof(*args));
+ if (ret)
+ return ret;
+
+ event->func = func;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/head.c b/drivers/gpu/drm/nouveau/nvif/head.c
new file mode 100644
index 000000000000..f00e01d232db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvif/head.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 <nvif/head.h>
+#include <nvif/disp.h>
+#include <nvif/printf.h>
+
+#include <nvif/class.h>
+#include <nvif/if0013.h>
+
+int
+nvif_head_vblank_event_ctor(struct nvif_head *head, const char *name, nvif_event_func func,
+ bool wait, struct nvif_event *event)
+{
+ int ret = nvif_event_ctor(&head->object, name ?: "nvifHeadVBlank", nvif_head_id(head),
+ func, wait, NULL, 0, event);
+ NVIF_ERRON(ret, &head->object, "[NEW EVENT:VBLANK]");
+ return ret;
+}
+
+void
+nvif_head_dtor(struct nvif_head *head)
+{
+ nvif_object_dtor(&head->object);
+}
+
+int
+nvif_head_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_head *head)
+{
+ struct nvif_head_v0 args;
+ int ret;
+
+ args.version = 0;
+ args.id = id;
+
+ ret = nvif_object_ctor(&disp->object, name ? name : "nvifHead", id, NVIF_CLASS_HEAD,
+ &args, sizeof(args), &head->object);
+ NVIF_ERRON(ret, &disp->object, "[NEW head id:%d]", args.id);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c
deleted file mode 100644
index 143c8dc6889e..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/notify.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <nvif/client.h>
-#include <nvif/driver.h>
-#include <nvif/notify.h>
-#include <nvif/object.h>
-#include <nvif/ioctl.h>
-#include <nvif/event.h>
-
-static inline int
-nvif_notify_put_(struct nvif_notify *notify)
-{
- struct nvif_object *object = notify->object;
- struct {
- struct nvif_ioctl_v0 ioctl;
- struct nvif_ioctl_ntfy_put_v0 ntfy;
- } args = {
- .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT,
- .ntfy.index = notify->index,
- };
-
- if (atomic_inc_return(&notify->putcnt) != 1)
- return 0;
-
- return nvif_object_ioctl(object, &args, sizeof(args), NULL);
-}
-
-int
-nvif_notify_put(struct nvif_notify *notify)
-{
- if (likely(notify->object) &&
- test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
- int ret = nvif_notify_put_(notify);
- if (test_bit(NVIF_NOTIFY_WORK, &notify->flags))
- flush_work(&notify->work);
- return ret;
- }
- return 0;
-}
-
-static inline int
-nvif_notify_get_(struct nvif_notify *notify)
-{
- struct nvif_object *object = notify->object;
- struct {
- struct nvif_ioctl_v0 ioctl;
- struct nvif_ioctl_ntfy_get_v0 ntfy;
- } args = {
- .ioctl.type = NVIF_IOCTL_V0_NTFY_GET,
- .ntfy.index = notify->index,
- };
-
- if (atomic_dec_return(&notify->putcnt) != 0)
- return 0;
-
- return nvif_object_ioctl(object, &args, sizeof(args), NULL);
-}
-
-int
-nvif_notify_get(struct nvif_notify *notify)
-{
- if (likely(notify->object) &&
- !test_and_set_bit(NVIF_NOTIFY_USER, &notify->flags))
- return nvif_notify_get_(notify);
- return 0;
-}
-
-static inline int
-nvif_notify_func(struct nvif_notify *notify, bool keep)
-{
- int ret = notify->func(notify);
- if (ret == NVIF_NOTIFY_KEEP ||
- !test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
- if (!keep)
- atomic_dec(&notify->putcnt);
- else
- nvif_notify_get_(notify);
- }
- return ret;
-}
-
-static void
-nvif_notify_work(struct work_struct *work)
-{
- struct nvif_notify *notify = container_of(work, typeof(*notify), work);
- nvif_notify_func(notify, true);
-}
-
-int
-nvif_notify(const void *header, u32 length, const void *data, u32 size)
-{
- struct nvif_notify *notify = NULL;
- const union {
- struct nvif_notify_rep_v0 v0;
- } *args = header;
- int ret = NVIF_NOTIFY_DROP;
-
- if (length == sizeof(args->v0) && args->v0.version == 0) {
- if (WARN_ON(args->v0.route))
- return NVIF_NOTIFY_DROP;
- notify = (void *)(unsigned long)args->v0.token;
- }
-
- if (!WARN_ON(notify == NULL)) {
- struct nvif_client *client = notify->object->client;
- if (!WARN_ON(notify->size != size)) {
- atomic_inc(&notify->putcnt);
- if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
- memcpy((void *)notify->data, data, size);
- schedule_work(&notify->work);
- return NVIF_NOTIFY_DROP;
- }
- notify->data = data;
- ret = nvif_notify_func(notify, client->driver->keep);
- notify->data = NULL;
- }
- }
-
- return ret;
-}
-
-int
-nvif_notify_dtor(struct nvif_notify *notify)
-{
- struct nvif_object *object = notify->object;
- struct {
- struct nvif_ioctl_v0 ioctl;
- struct nvif_ioctl_ntfy_del_v0 ntfy;
- } args = {
- .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL,
- .ntfy.index = notify->index,
- };
- int ret = nvif_notify_put(notify);
- if (ret >= 0 && object) {
- ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
- notify->object = NULL;
- kfree((void *)notify->data);
- }
- return ret;
-}
-
-int
-nvif_notify_ctor(struct nvif_object *object, const char *name,
- int (*func)(struct nvif_notify *), bool work, u8 event,
- void *data, u32 size, u32 reply, struct nvif_notify *notify)
-{
- struct {
- struct nvif_ioctl_v0 ioctl;
- struct nvif_ioctl_ntfy_new_v0 ntfy;
- struct nvif_notify_req_v0 req;
- } *args;
- int ret = -ENOMEM;
-
- notify->object = object;
- notify->name = name ? name : "nvifNotify";
- notify->flags = 0;
- atomic_set(&notify->putcnt, 1);
- notify->func = func;
- notify->data = NULL;
- notify->size = reply;
- if (work) {
- INIT_WORK(&notify->work, nvif_notify_work);
- set_bit(NVIF_NOTIFY_WORK, &notify->flags);
- notify->data = kmalloc(notify->size, GFP_KERNEL);
- if (!notify->data)
- goto done;
- }
-
- if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
- goto done;
- args->ioctl.version = 0;
- args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW;
- args->ntfy.version = 0;
- args->ntfy.event = event;
- args->req.version = 0;
- args->req.reply = notify->size;
- args->req.route = 0;
- args->req.token = (unsigned long)(void *)notify;
-
- memcpy(args->req.data, data, size);
- ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
- notify->index = args->ntfy.index;
- kfree(args);
-done:
- if (ret)
- nvif_notify_dtor(notify);
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c
index 7bfe91a8d6f9..7da39f1eae9f 100644
--- a/drivers/gpu/drm/nouveau/nvif/outp.c
+++ b/drivers/gpu/drm/nouveau/nvif/outp.c
@@ -24,7 +24,177 @@
#include <nvif/printf.h>
#include <nvif/class.h>
-#include <nvif/if0012.h>
+
+int
+nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head,
+ u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn)
+{
+ struct nvif_outp_dp_mst_vcpi_v0 args;
+ int ret;
+
+ args.version = 0;
+ args.head = head;
+ args.start_slot = start_slot;
+ args.num_slots = num_slots;
+ args.pbn = pbn;
+ args.aligned_pbn = aligned_pbn;
+
+ ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_VCPI, &args, sizeof(args));
+ NVIF_ERRON(ret, &outp->object,
+ "[DP_MST_VCPI head:%d start_slot:%02x num_slots:%02x pbn:%04x aligned_pbn:%04x]",
+ args.head, args.start_slot, args.num_slots, args.pbn, args.aligned_pbn);
+ return ret;
+}
+
+int
+nvif_outp_dp_retrain(struct nvif_outp *outp)
+{
+ int ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RETRAIN, NULL, 0);
+ NVIF_ERRON(ret, &outp->object, "[DP_RETRAIN]");
+ return ret;
+}
+
+int
+nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable)
+{
+ struct nvif_outp_dp_aux_pwr_v0 args;
+ int ret;
+
+ args.version = 0;
+ args.state = enable;
+
+ ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_PWR, &args, sizeof(args));
+ NVIF_ERRON(ret, &outp->object, "[DP_AUX_PWR state:%d]", args.state);
+ return ret;
+}
+
+int
+nvif_outp_hda_eld(struct nvif_outp *outp, int head, void *data, u32 size)
+{
+ struct {
+ struct nvif_outp_hda_eld_v0 mthd;
+ u8 data[128];
+ } args;
+ int ret;
+
+ if (WARN_ON(size > ARRAY_SIZE(args.data)))
+ return -EINVAL;
+
+ args.mthd.version = 0;
+ args.mthd.head = head;
+
+ memcpy(args.data, data, size);
+ ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, &args, sizeof(args.mthd) + size);
+ NVIF_ERRON(ret, &outp->object, "[HDA_ELD head:%d size:%d]", head, size);
+ return ret;
+}
+
+int
+nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_v0 *args, u32 size)
+{
+ int ret;
+
+ args->type = type;
+
+ ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INFOFRAME, args, sizeof(*args) + size);
+ NVIF_ERRON(ret, &outp->object, "[INFOFRAME type:%d size:%d]", type, size);
+ return ret;
+}
+
+void
+nvif_outp_release(struct nvif_outp *outp)
+{
+ int ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_RELEASE, NULL, 0);
+ NVIF_ERRON(ret, &outp->object, "[RELEASE]");
+ outp->or.id = -1;
+}
+
+static inline int
+nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args)
+{
+ int ret;
+
+ args->version = 0;
+ args->proto = proto;
+
+ ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args));
+ if (ret)
+ return ret;
+
+ outp->or.id = args->or;
+ outp->or.link = args->link;
+ return 0;
+}
+
+int
+nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[16],
+ int link_nr, int link_bw, bool hda, bool mst)
+{
+ struct nvif_outp_acquire_v0 args;
+ int ret;
+
+ args.dp.link_nr = link_nr;
+ args.dp.link_bw = link_bw;
+ args.dp.hda = hda;
+ args.dp.mst = mst;
+ memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd));
+
+ ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args);
+ NVIF_ERRON(ret, &outp->object,
+ "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d",
+ args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link);
+ return ret;
+}
+
+int
+nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8)
+{
+ struct nvif_outp_acquire_v0 args;
+ int ret;
+
+ args.lvds.dual = dual;
+ args.lvds.bpc8 = bpc8;
+
+ ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_LVDS, &args);
+ NVIF_ERRON(ret, &outp->object,
+ "[ACQUIRE proto:LVDS dual:%d 8bpc:%d] or:%d link:%d",
+ args.lvds.dual, args.lvds.bpc8, args.or, args.link);
+ return ret;
+}
+
+int
+nvif_outp_acquire_tmds(struct nvif_outp *outp, int head,
+ bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda)
+{
+ struct nvif_outp_acquire_v0 args;
+ int ret;
+
+ args.tmds.head = head;
+ args.tmds.hdmi = hdmi;
+ args.tmds.hdmi_max_ac_packet = max_ac_packet;
+ args.tmds.hdmi_rekey = rekey;
+ args.tmds.hdmi_scdc = scdc;
+ args.tmds.hdmi_hda = hda;
+
+ ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args);
+ NVIF_ERRON(ret, &outp->object,
+ "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]"
+ " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet,
+ args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda,
+ args.or, args.link);
+ return ret;
+}
+
+int
+nvif_outp_acquire_rgb_crt(struct nvif_outp *outp)
+{
+ struct nvif_outp_acquire_v0 args;
+ int ret;
+
+ ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_RGB_CRT, &args);
+ NVIF_ERRON(ret, &outp->object, "[ACQUIRE proto:RGB_CRT] or:%d", args.or);
+ return ret;
+}
int
nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval)
@@ -58,5 +228,9 @@ nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_out
ret = nvif_object_ctor(&disp->object, name ?: "nvifOutp", id, NVIF_CLASS_OUTP,
&args, sizeof(args), &outp->object);
NVIF_ERRON(ret, &disp->object, "[NEW outp id:%d]", id);
- return ret;
+ if (ret)
+ return ret;
+
+ outp->or.id = -1;
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvif/user.c b/drivers/gpu/drm/nouveau/nvif/user.c
index d89f5b67b304..b648a5e036af 100644
--- a/drivers/gpu/drm/nouveau/nvif/user.c
+++ b/drivers/gpu/drm/nouveau/nvif/user.c
@@ -41,7 +41,9 @@ nvif_user_ctor(struct nvif_device *device, const char *name)
int version;
const struct nvif_user_func *func;
} users[] = {
- { VOLTA_USERMODE_A, -1, &nvif_userc361 },
+ { AMPERE_USERMODE_A, -1, &nvif_userc361 },
+ { TURING_USERMODE_A, -1, &nvif_userc361 },
+ { VOLTA_USERMODE_A, -1, &nvif_userc361 },
{}
};
int cid, ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
index 2b471ab585b4..e40712023c73 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
@@ -5,12 +5,13 @@ nvkm-y += nvkm/core/enum.o
nvkm-y += nvkm/core/event.o
nvkm-y += nvkm/core/firmware.o
nvkm-y += nvkm/core/gpuobj.o
+nvkm-y += nvkm/core/intr.o
nvkm-y += nvkm/core/ioctl.o
nvkm-y += nvkm/core/memory.o
nvkm-y += nvkm/core/mm.o
-nvkm-y += nvkm/core/notify.o
nvkm-y += nvkm/core/object.o
nvkm-y += nvkm/core/oproxy.o
nvkm-y += nvkm/core/option.o
nvkm-y += nvkm/core/ramht.o
nvkm-y += nvkm/core/subdev.o
+nvkm-y += nvkm/core/uevent.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c
index 0c8c55c73b12..ebdeb8eb9e77 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/client.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c
@@ -23,7 +23,6 @@
*/
#include <core/client.h>
#include <core/device.h>
-#include <core/notify.h>
#include <core/option.h>
#include <nvif/class.h>
@@ -44,7 +43,7 @@ nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){
args->v0.name[sizeof(args->v0.name) - 1] = 0;
ret = nvkm_client_new(args->v0.name, args->v0.device, NULL,
- NULL, oclass->client->ntfy, &client);
+ NULL, oclass->client->event, &client);
if (ret)
return ret;
} else
@@ -68,113 +67,6 @@ nvkm_uclient_sclass = {
.ctor = nvkm_uclient_new,
};
-struct nvkm_client_notify {
- struct nvkm_client *client;
- struct nvkm_notify n;
- u8 version;
- u8 size;
- union {
- struct nvif_notify_rep_v0 v0;
- } rep;
-};
-
-static int
-nvkm_client_notify(struct nvkm_notify *n)
-{
- struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
- struct nvkm_client *client = notify->client;
- return client->ntfy(&notify->rep, notify->size, n->data, n->size);
-}
-
-int
-nvkm_client_notify_put(struct nvkm_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_put(&client->notify[index]->n);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_get(struct nvkm_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_get(&client->notify[index]->n);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_del(struct nvkm_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_fini(&client->notify[index]->n);
- kfree(client->notify[index]);
- client->notify[index] = NULL;
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_new(struct nvkm_object *object,
- struct nvkm_event *event, void *data, u32 size)
-{
- struct nvkm_client *client = object->client;
- struct nvkm_client_notify *notify;
- union {
- struct nvif_notify_req_v0 v0;
- } *req = data;
- u8 index, reply;
- int ret = -ENOSYS;
-
- for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
- if (!client->notify[index])
- break;
- }
-
- if (index == ARRAY_SIZE(client->notify))
- return -ENOSPC;
-
- notify = kzalloc(sizeof(*notify), GFP_KERNEL);
- if (!notify)
- return -ENOMEM;
-
- nvif_ioctl(object, "notify new size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, true))) {
- nvif_ioctl(object, "notify new vers %d reply %d route %02x "
- "token %llx\n", req->v0.version,
- req->v0.reply, req->v0.route, req->v0.token);
- notify->version = req->v0.version;
- notify->size = sizeof(notify->rep.v0);
- notify->rep.v0.version = req->v0.version;
- notify->rep.v0.route = req->v0.route;
- notify->rep.v0.token = req->v0.token;
- reply = req->v0.reply;
- }
-
- if (ret == 0) {
- ret = nvkm_notify_init(object, event, nvkm_client_notify,
- false, data, size, reply, &notify->n);
- if (ret == 0) {
- client->notify[index] = notify;
- notify->client = client;
- return index;
- }
- }
-
- kfree(notify);
- return ret;
-}
-
static const struct nvkm_object_func nvkm_client;
struct nvkm_client *
nvkm_client_search(struct nvkm_client *client, u64 handle)
@@ -255,23 +147,13 @@ nvkm_client_child_get(struct nvkm_object *object, int index,
static int
nvkm_client_fini(struct nvkm_object *object, bool suspend)
{
- struct nvkm_client *client = nvkm_client(object);
- const char *name[2] = { "fini", "suspend" };
- int i;
- nvif_debug(object, "%s notify\n", name[suspend]);
- for (i = 0; i < ARRAY_SIZE(client->notify); i++)
- nvkm_client_notify_put(client, i);
return 0;
}
static void *
nvkm_client_dtor(struct nvkm_object *object)
{
- struct nvkm_client *client = nvkm_client(object);
- int i;
- for (i = 0; i < ARRAY_SIZE(client->notify); i++)
- nvkm_client_notify_del(client, i);
- return client;
+ return nvkm_client(object);
}
static const struct nvkm_object_func
@@ -283,10 +165,8 @@ nvkm_client = {
};
int
-nvkm_client_new(const char *name, u64 device, const char *cfg,
- const char *dbg,
- int (*ntfy)(const void *, u32, const void *, u32),
- struct nvkm_client **pclient)
+nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
+ int (*event)(u64, void *, u32), struct nvkm_client **pclient)
{
struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass };
struct nvkm_client *client;
@@ -300,7 +180,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg,
client->device = device;
client->debug = nvkm_dbgopt(dbg, "CLIENT");
client->objroot = RB_ROOT;
- client->ntfy = ntfy;
+ client->event = event;
INIT_LIST_HEAD(&client->umem);
spin_lock_init(&client->lock);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
index e41a39ae1597..36a31e9eea22 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
@@ -35,16 +35,23 @@ nvkm_engine_chsw_load(struct nvkm_engine *engine)
return false;
}
+int
+nvkm_engine_reset(struct nvkm_engine *engine)
+{
+ if (engine->func->reset)
+ return engine->func->reset(engine);
+
+ nvkm_subdev_fini(&engine->subdev, false);
+ return nvkm_subdev_init(&engine->subdev);
+}
+
void
nvkm_engine_unref(struct nvkm_engine **pengine)
{
struct nvkm_engine *engine = *pengine;
+
if (engine) {
- if (refcount_dec_and_mutex_lock(&engine->use.refcount, &engine->use.mutex)) {
- nvkm_subdev_fini(&engine->subdev, false);
- engine->use.enabled = false;
- mutex_unlock(&engine->use.mutex);
- }
+ nvkm_subdev_unref(&engine->subdev);
*pengine = NULL;
}
}
@@ -53,21 +60,13 @@ struct nvkm_engine *
nvkm_engine_ref(struct nvkm_engine *engine)
{
int ret;
+
if (engine) {
- if (!refcount_inc_not_zero(&engine->use.refcount)) {
- mutex_lock(&engine->use.mutex);
- if (!refcount_inc_not_zero(&engine->use.refcount)) {
- engine->use.enabled = true;
- if ((ret = nvkm_subdev_init(&engine->subdev))) {
- engine->use.enabled = false;
- mutex_unlock(&engine->use.mutex);
- return ERR_PTR(ret);
- }
- refcount_set(&engine->use.refcount, 1);
- }
- mutex_unlock(&engine->use.mutex);
- }
+ ret = nvkm_subdev_ref(&engine->subdev);
+ if (ret)
+ return ERR_PTR(ret);
}
+
return engine;
}
@@ -91,14 +90,10 @@ static int
nvkm_engine_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)
{
struct nvkm_engine *engine = nvkm_engine(subdev);
- if (engine->func->info) {
- if (!IS_ERR((engine = nvkm_engine_ref(engine)))) {
- int ret = engine->func->info(engine, mthd, data);
- nvkm_engine_unref(&engine);
- return ret;
- }
- return PTR_ERR(engine);
- }
+
+ if (engine->func->info)
+ return engine->func->info(engine, mthd, data);
+
return -ENOSYS;
}
@@ -117,26 +112,6 @@ nvkm_engine_init(struct nvkm_subdev *subdev)
struct nvkm_engine *engine = nvkm_engine(subdev);
struct nvkm_fb *fb = subdev->device->fb;
int ret = 0, i;
- s64 time;
-
- if (!engine->use.enabled) {
- nvkm_trace(subdev, "init skipped, engine has no users\n");
- return ret;
- }
-
- if (engine->func->oneinit && !engine->subdev.oneinit) {
- nvkm_trace(subdev, "one-time init running...\n");
- time = ktime_to_us(ktime_get());
- ret = engine->func->oneinit(engine);
- if (ret) {
- nvkm_trace(subdev, "one-time init failed, %d\n", ret);
- return ret;
- }
-
- engine->subdev.oneinit = true;
- time = ktime_to_us(ktime_get()) - time;
- nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
- }
if (engine->func->init)
ret = engine->func->init(engine);
@@ -147,6 +122,17 @@ nvkm_engine_init(struct nvkm_subdev *subdev)
}
static int
+nvkm_engine_oneinit(struct nvkm_subdev *subdev)
+{
+ struct nvkm_engine *engine = nvkm_engine(subdev);
+
+ if (engine->func->oneinit)
+ return engine->func->oneinit(engine);
+
+ return 0;
+}
+
+static int
nvkm_engine_preinit(struct nvkm_subdev *subdev)
{
struct nvkm_engine *engine = nvkm_engine(subdev);
@@ -161,7 +147,6 @@ nvkm_engine_dtor(struct nvkm_subdev *subdev)
struct nvkm_engine *engine = nvkm_engine(subdev);
if (engine->func->dtor)
return engine->func->dtor(engine);
- mutex_destroy(&engine->use.mutex);
return engine;
}
@@ -169,6 +154,7 @@ const struct nvkm_subdev_func
nvkm_engine = {
.dtor = nvkm_engine_dtor,
.preinit = nvkm_engine_preinit,
+ .oneinit = nvkm_engine_oneinit,
.init = nvkm_engine_init,
.fini = nvkm_engine_fini,
.info = nvkm_engine_info,
@@ -179,10 +165,9 @@ int
nvkm_engine_ctor(const struct nvkm_engine_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, bool enable, struct nvkm_engine *engine)
{
- nvkm_subdev_ctor(&nvkm_engine, device, type, inst, &engine->subdev);
engine->func = func;
- refcount_set(&engine->use.refcount, 0);
- mutex_init(&engine->use.mutex);
+ nvkm_subdev_ctor(&nvkm_engine, device, type, inst, &engine->subdev);
+ refcount_set(&engine->subdev.use.refcount, 0);
if (!nvkm_boolopt(device->cfgopt, engine->subdev.name, enable)) {
nvkm_debug(&engine->subdev, "disabled\n");
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c
index 006618d77aa4..a6c877135598 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/event.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c
@@ -20,54 +20,171 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <core/event.h>
-#include <core/notify.h>
+#include <core/subdev.h>
-void
+static void
nvkm_event_put(struct nvkm_event *event, u32 types, int index)
{
assert_spin_locked(&event->refs_lock);
+
+ nvkm_trace(event->subdev, "event: decr %08x on %d\n", types, index);
+
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (--event->refs[index * event->types_nr + type] == 0) {
+ nvkm_trace(event->subdev, "event: blocking %d on %d\n", type, index);
if (event->func->fini)
event->func->fini(event, 1 << type, index);
}
}
}
-void
+static void
nvkm_event_get(struct nvkm_event *event, u32 types, int index)
{
assert_spin_locked(&event->refs_lock);
+
+ nvkm_trace(event->subdev, "event: incr %08x on %d\n", types, index);
+
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (++event->refs[index * event->types_nr + type] == 1) {
+ nvkm_trace(event->subdev, "event: allowing %d on %d\n", type, index);
if (event->func->init)
event->func->init(event, 1 << type, index);
}
}
}
+static void
+nvkm_event_ntfy_state(struct nvkm_event_ntfy *ntfy)
+{
+ struct nvkm_event *event = ntfy->event;
+ unsigned long flags;
+
+ nvkm_trace(event->subdev, "event: ntfy state changed\n");
+ spin_lock_irqsave(&event->refs_lock, flags);
+
+ if (atomic_read(&ntfy->allowed) != ntfy->running) {
+ if (ntfy->running) {
+ nvkm_event_put(ntfy->event, ntfy->bits, ntfy->id);
+ ntfy->running = false;
+ } else {
+ nvkm_event_get(ntfy->event, ntfy->bits, ntfy->id);
+ ntfy->running = true;
+ }
+ }
+
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+}
+
+static void
+nvkm_event_ntfy_remove(struct nvkm_event_ntfy *ntfy)
+{
+ spin_lock_irq(&ntfy->event->list_lock);
+ list_del_init(&ntfy->head);
+ spin_unlock_irq(&ntfy->event->list_lock);
+}
+
+static void
+nvkm_event_ntfy_insert(struct nvkm_event_ntfy *ntfy)
+{
+ spin_lock_irq(&ntfy->event->list_lock);
+ list_add_tail(&ntfy->head, &ntfy->event->ntfy);
+ spin_unlock_irq(&ntfy->event->list_lock);
+}
+
+static void
+nvkm_event_ntfy_block_(struct nvkm_event_ntfy *ntfy, bool wait)
+{
+ struct nvkm_subdev *subdev = ntfy->event->subdev;
+
+ nvkm_trace(subdev, "event: ntfy block %08x on %d wait:%d\n", ntfy->bits, ntfy->id, wait);
+
+ if (atomic_xchg(&ntfy->allowed, 0) == 1) {
+ nvkm_event_ntfy_state(ntfy);
+ if (wait)
+ nvkm_event_ntfy_remove(ntfy);
+ }
+}
+
void
-nvkm_event_send(struct nvkm_event *event, u32 types, int index,
- void *data, u32 size)
+nvkm_event_ntfy_block(struct nvkm_event_ntfy *ntfy)
{
- struct nvkm_notify *notify;
+ if (ntfy->event)
+ nvkm_event_ntfy_block_(ntfy, ntfy->wait);
+}
+
+void
+nvkm_event_ntfy_allow(struct nvkm_event_ntfy *ntfy)
+{
+ nvkm_trace(ntfy->event->subdev, "event: ntfy allow %08x on %d\n", ntfy->bits, ntfy->id);
+
+ if (atomic_xchg(&ntfy->allowed, 1) == 0) {
+ nvkm_event_ntfy_state(ntfy);
+ if (ntfy->wait)
+ nvkm_event_ntfy_insert(ntfy);
+ }
+}
+
+void
+nvkm_event_ntfy_del(struct nvkm_event_ntfy *ntfy)
+{
+ struct nvkm_event *event = ntfy->event;
+
+ if (!event)
+ return;
+
+ nvkm_trace(event->subdev, "event: ntfy del %08x on %d\n", ntfy->bits, ntfy->id);
+
+ nvkm_event_ntfy_block_(ntfy, false);
+ nvkm_event_ntfy_remove(ntfy);
+ ntfy->event = NULL;
+}
+
+void
+nvkm_event_ntfy_add(struct nvkm_event *event, int id, u32 bits, bool wait, nvkm_event_func func,
+ struct nvkm_event_ntfy *ntfy)
+{
+ nvkm_trace(event->subdev, "event: ntfy add %08x on %d wait:%d\n", id, bits, wait);
+
+ ntfy->event = event;
+ ntfy->id = id;
+ ntfy->bits = bits;
+ ntfy->wait = wait;
+ ntfy->func = func;
+ atomic_set(&ntfy->allowed, 0);
+ ntfy->running = false;
+ INIT_LIST_HEAD(&ntfy->head);
+ if (!ntfy->wait)
+ nvkm_event_ntfy_insert(ntfy);
+}
+
+bool
+nvkm_event_ntfy_valid(struct nvkm_event *event, int id, u32 bits)
+{
+ return true;
+}
+
+void
+nvkm_event_ntfy(struct nvkm_event *event, int id, u32 bits)
+{
+ struct nvkm_event_ntfy *ntfy, *ntmp;
unsigned long flags;
- if (!event->refs || WARN_ON(index >= event->index_nr))
+ if (!event->refs || WARN_ON(id >= event->index_nr))
return;
+ nvkm_trace(event->subdev, "event: ntfy %08x on %d\n", bits, id);
spin_lock_irqsave(&event->list_lock, flags);
- list_for_each_entry(notify, &event->list, head) {
- if (notify->index == index && (notify->types & types)) {
- if (event->func->send) {
- event->func->send(data, size, notify);
- continue;
- }
- nvkm_notify_send(notify, data, size);
+
+ list_for_each_entry_safe(ntfy, ntmp, &event->ntfy, head) {
+ if (ntfy->id == id && ntfy->bits & bits) {
+ if (atomic_read(&ntfy->allowed))
+ ntfy->func(ntfy, ntfy->bits & bits);
}
}
+
spin_unlock_irqrestore(&event->list_lock, flags);
}
@@ -81,20 +198,17 @@ nvkm_event_fini(struct nvkm_event *event)
}
int
-nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
- struct nvkm_event *event)
+__nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev,
+ int types_nr, int index_nr, struct nvkm_event *event)
{
- event->refs = kzalloc(array3_size(index_nr, types_nr,
- sizeof(*event->refs)),
- GFP_KERNEL);
+ event->refs = kzalloc(array3_size(index_nr, types_nr, sizeof(*event->refs)), GFP_KERNEL);
if (!event->refs)
return -ENOMEM;
event->func = func;
+ event->subdev = subdev;
event->types_nr = types_nr;
event->index_nr = index_nr;
- spin_lock_init(&event->refs_lock);
- spin_lock_init(&event->list_lock);
- INIT_LIST_HEAD(&event->list);
+ INIT_LIST_HEAD(&event->ntfy);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
index ca1f8463cff5..fcf2a002f6cb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
@@ -22,6 +22,9 @@
#include <core/device.h>
#include <core/firmware.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+
int
nvkm_firmware_load_name(const struct nvkm_subdev *subdev, const char *base,
const char *name, int ver, const struct firmware **pfw)
@@ -107,3 +110,127 @@ nvkm_firmware_put(const struct firmware *fw)
{
release_firmware(fw);
}
+
+#define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory)
+
+static int
+nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
+ struct nvkm_vma *vma, void *argv, u32 argc)
+{
+ struct nvkm_firmware *fw = nvkm_firmware_mem(memory);
+ struct nvkm_vmm_map map = {
+ .memory = &fw->mem.memory,
+ .offset = offset,
+ .sgl = &fw->mem.sgl,
+ };
+
+ if (WARN_ON(fw->func->type != NVKM_FIRMWARE_IMG_DMA))
+ return -ENOSYS;
+
+ return nvkm_vmm_map(vmm, vma, argv, argc, &map);
+}
+
+static u64
+nvkm_firmware_mem_size(struct nvkm_memory *memory)
+{
+ return sg_dma_len(&nvkm_firmware_mem(memory)->mem.sgl);
+}
+
+static u64
+nvkm_firmware_mem_addr(struct nvkm_memory *memory)
+{
+ return nvkm_firmware_mem(memory)->phys;
+}
+
+static u8
+nvkm_firmware_mem_page(struct nvkm_memory *memory)
+{
+ return PAGE_SHIFT;
+}
+
+static enum nvkm_memory_target
+nvkm_firmware_mem_target(struct nvkm_memory *memory)
+{
+ return NVKM_MEM_TARGET_HOST;
+}
+
+static void *
+nvkm_firmware_mem_dtor(struct nvkm_memory *memory)
+{
+ return NULL;
+}
+
+static const struct nvkm_memory_func
+nvkm_firmware_mem = {
+ .dtor = nvkm_firmware_mem_dtor,
+ .target = nvkm_firmware_mem_target,
+ .page = nvkm_firmware_mem_page,
+ .addr = nvkm_firmware_mem_addr,
+ .size = nvkm_firmware_mem_size,
+ .map = nvkm_firmware_mem_map,
+};
+
+void
+nvkm_firmware_dtor(struct nvkm_firmware *fw)
+{
+ struct nvkm_memory *memory = &fw->mem.memory;
+
+ if (!fw->img)
+ return;
+
+ switch (fw->func->type) {
+ case NVKM_FIRMWARE_IMG_RAM:
+ kfree(fw->img);
+ break;
+ case NVKM_FIRMWARE_IMG_DMA:
+ nvkm_memory_unref(&memory);
+ dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ fw->img = NULL;
+}
+
+int
+nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
+ struct nvkm_device *device, const void *src, int len, struct nvkm_firmware *fw)
+{
+ fw->func = func;
+ fw->name = name;
+ fw->device = device;
+ fw->len = len;
+
+ switch (fw->func->type) {
+ case NVKM_FIRMWARE_IMG_RAM:
+ fw->img = kmemdup(src, fw->len, GFP_KERNEL);
+ break;
+ case NVKM_FIRMWARE_IMG_DMA: {
+ dma_addr_t addr;
+
+ len = ALIGN(fw->len, PAGE_SIZE);
+
+ fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL);
+ if (fw->img) {
+ memcpy(fw->img, src, fw->len);
+ fw->phys = addr;
+ }
+
+ sg_init_one(&fw->mem.sgl, fw->img, len);
+ sg_dma_address(&fw->mem.sgl) = fw->phys;
+ sg_dma_len(&fw->mem.sgl) = len;
+ }
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (!fw->img)
+ return -ENOMEM;
+
+ nvkm_memory_ctor(&nvkm_firmware_mem, &fw->mem.memory);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/intr.c b/drivers/gpu/drm/nouveau/nvkm/core/intr.c
new file mode 100644
index 000000000000..e20b7ca218c3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/intr.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 <core/intr.h>
+#include <core/device.h>
+#include <core/subdev.h>
+#include <subdev/pci.h>
+#include <subdev/top.h>
+
+static int
+nvkm_intr_xlat(struct nvkm_subdev *subdev, struct nvkm_intr *intr,
+ enum nvkm_intr_type type, int *leaf, u32 *mask)
+{
+ struct nvkm_device *device = subdev->device;
+
+ if (type < NVKM_INTR_VECTOR_0) {
+ if (type == NVKM_INTR_SUBDEV) {
+ const struct nvkm_intr_data *data = intr->data;
+ struct nvkm_top_device *tdev;
+
+ while (data && data->mask) {
+ if (data->type == NVKM_SUBDEV_TOP) {
+ list_for_each_entry(tdev, &device->top->device, head) {
+ if (tdev->intr >= 0 &&
+ tdev->type == subdev->type &&
+ tdev->inst == subdev->inst) {
+ if (data->mask & BIT(tdev->intr)) {
+ *leaf = data->leaf;
+ *mask = BIT(tdev->intr);
+ return 0;
+ }
+ }
+ }
+ } else
+ if (data->type == subdev->type && data->inst == subdev->inst) {
+ *leaf = data->leaf;
+ *mask = data->mask;
+ return 0;
+ }
+
+ data++;
+ }
+ } else {
+ return -ENOSYS;
+ }
+ } else {
+ if (type < intr->leaves * sizeof(*intr->stat) * 8) {
+ *leaf = type / 32;
+ *mask = BIT(type % 32);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static struct nvkm_intr *
+nvkm_intr_find(struct nvkm_subdev *subdev, enum nvkm_intr_type type, int *leaf, u32 *mask)
+{
+ struct nvkm_intr *intr;
+ int ret;
+
+ list_for_each_entry(intr, &subdev->device->intr.intr, head) {
+ ret = nvkm_intr_xlat(subdev, intr, type, leaf, mask);
+ if (ret == 0)
+ return intr;
+ }
+
+ return NULL;
+}
+
+static void
+nvkm_intr_allow_locked(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ intr->mask[leaf] |= mask;
+ if (intr->func->allow) {
+ if (intr->func->reset)
+ intr->func->reset(intr, leaf, mask);
+ intr->func->allow(intr, leaf, mask);
+ }
+}
+
+void
+nvkm_intr_allow(struct nvkm_subdev *subdev, enum nvkm_intr_type type)
+{
+ struct nvkm_device *device = subdev->device;
+ struct nvkm_intr *intr;
+ unsigned long flags;
+ int leaf;
+ u32 mask;
+
+ intr = nvkm_intr_find(subdev, type, &leaf, &mask);
+ if (intr) {
+ nvkm_debug(intr->subdev, "intr %d/%08x allowed by %s\n", leaf, mask, subdev->name);
+ spin_lock_irqsave(&device->intr.lock, flags);
+ nvkm_intr_allow_locked(intr, leaf, mask);
+ spin_unlock_irqrestore(&device->intr.lock, flags);
+ }
+}
+
+static void
+nvkm_intr_block_locked(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ intr->mask[leaf] &= ~mask;
+ if (intr->func->block)
+ intr->func->block(intr, leaf, mask);
+}
+
+void
+nvkm_intr_block(struct nvkm_subdev *subdev, enum nvkm_intr_type type)
+{
+ struct nvkm_device *device = subdev->device;
+ struct nvkm_intr *intr;
+ unsigned long flags;
+ int leaf;
+ u32 mask;
+
+ intr = nvkm_intr_find(subdev, type, &leaf, &mask);
+ if (intr) {
+ nvkm_debug(intr->subdev, "intr %d/%08x blocked by %s\n", leaf, mask, subdev->name);
+ spin_lock_irqsave(&device->intr.lock, flags);
+ nvkm_intr_block_locked(intr, leaf, mask);
+ spin_unlock_irqrestore(&device->intr.lock, flags);
+ }
+}
+
+static void
+nvkm_intr_rearm_locked(struct nvkm_device *device)
+{
+ struct nvkm_intr *intr;
+
+ list_for_each_entry(intr, &device->intr.intr, head)
+ intr->func->rearm(intr);
+}
+
+static void
+nvkm_intr_unarm_locked(struct nvkm_device *device)
+{
+ struct nvkm_intr *intr;
+
+ list_for_each_entry(intr, &device->intr.intr, head)
+ intr->func->unarm(intr);
+}
+
+static irqreturn_t
+nvkm_intr(int irq, void *arg)
+{
+ struct nvkm_device *device = arg;
+ struct nvkm_intr *intr;
+ struct nvkm_inth *inth;
+ irqreturn_t ret = IRQ_NONE;
+ bool pending = false;
+ int prio, leaf;
+
+ /* Disable all top-level interrupt sources, and re-arm MSI interrupts. */
+ spin_lock(&device->intr.lock);
+ if (!device->intr.armed)
+ goto done_unlock;
+
+ nvkm_intr_unarm_locked(device);
+ nvkm_pci_msi_rearm(device);
+
+ /* Fetch pending interrupt masks. */
+ list_for_each_entry(intr, &device->intr.intr, head) {
+ if (intr->func->pending(intr))
+ pending = true;
+ }
+
+ if (!pending)
+ goto done;
+
+ /* Check that GPU is still on the bus by reading NV_PMC_BOOT_0. */
+ if (WARN_ON(nvkm_rd32(device, 0x000000) == 0xffffffff))
+ goto done;
+
+ /* Execute handlers. */
+ for (prio = 0; prio < ARRAY_SIZE(device->intr.prio); prio++) {
+ list_for_each_entry(inth, &device->intr.prio[prio], head) {
+ struct nvkm_intr *intr = inth->intr;
+
+ if (intr->stat[inth->leaf] & inth->mask) {
+ if (atomic_read(&inth->allowed)) {
+ if (intr->func->reset)
+ intr->func->reset(intr, inth->leaf, inth->mask);
+ if (inth->func(inth) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+ }
+ }
+ }
+ }
+
+ /* Nothing handled? Some debugging/protection from IRQ storms is in order... */
+ if (ret == IRQ_NONE) {
+ list_for_each_entry(intr, &device->intr.intr, head) {
+ for (leaf = 0; leaf < intr->leaves; leaf++) {
+ if (intr->stat[leaf]) {
+ nvkm_warn(intr->subdev, "intr%d: %08x\n",
+ leaf, intr->stat[leaf]);
+ nvkm_intr_block_locked(intr, leaf, intr->stat[leaf]);
+ }
+ }
+ }
+ }
+
+done:
+ /* Re-enable all top-level interrupt sources. */
+ nvkm_intr_rearm_locked(device);
+done_unlock:
+ spin_unlock(&device->intr.lock);
+ return ret;
+}
+
+int
+nvkm_intr_add(const struct nvkm_intr_func *func, const struct nvkm_intr_data *data,
+ struct nvkm_subdev *subdev, int leaves, struct nvkm_intr *intr)
+{
+ struct nvkm_device *device = subdev->device;
+ int i;
+
+ intr->func = func;
+ intr->data = data;
+ intr->subdev = subdev;
+ intr->leaves = leaves;
+ intr->stat = kcalloc(leaves, sizeof(*intr->stat), GFP_KERNEL);
+ intr->mask = kcalloc(leaves, sizeof(*intr->mask), GFP_KERNEL);
+ if (!intr->stat || !intr->mask) {
+ kfree(intr->stat);
+ return -ENOMEM;
+ }
+
+ if (intr->subdev->debug >= NV_DBG_DEBUG) {
+ for (i = 0; i < intr->leaves; i++)
+ intr->mask[i] = ~0;
+ }
+
+ spin_lock_irq(&device->intr.lock);
+ list_add_tail(&intr->head, &device->intr.intr);
+ spin_unlock_irq(&device->intr.lock);
+ return 0;
+}
+
+static irqreturn_t
+nvkm_intr_subdev(struct nvkm_inth *inth)
+{
+ struct nvkm_subdev *subdev = container_of(inth, typeof(*subdev), inth);
+
+ nvkm_subdev_intr(subdev);
+ return IRQ_HANDLED;
+}
+
+static void
+nvkm_intr_subdev_add_dev(struct nvkm_intr *intr, enum nvkm_subdev_type type, int inst)
+{
+ struct nvkm_subdev *subdev;
+ enum nvkm_intr_prio prio;
+ int ret;
+
+ subdev = nvkm_device_subdev(intr->subdev->device, type, inst);
+ if (!subdev || !subdev->func->intr)
+ return;
+
+ if (type == NVKM_ENGINE_DISP)
+ prio = NVKM_INTR_PRIO_VBLANK;
+ else
+ prio = NVKM_INTR_PRIO_NORMAL;
+
+ ret = nvkm_inth_add(intr, NVKM_INTR_SUBDEV, prio, subdev, nvkm_intr_subdev, &subdev->inth);
+ if (WARN_ON(ret))
+ return;
+
+ nvkm_inth_allow(&subdev->inth);
+}
+
+static void
+nvkm_intr_subdev_add(struct nvkm_intr *intr)
+{
+ const struct nvkm_intr_data *data;
+ struct nvkm_device *device = intr->subdev->device;
+ struct nvkm_top_device *tdev;
+
+ for (data = intr->data; data && data->mask; data++) {
+ if (data->legacy) {
+ if (data->type == NVKM_SUBDEV_TOP) {
+ list_for_each_entry(tdev, &device->top->device, head) {
+ if (tdev->intr < 0 || !(data->mask & BIT(tdev->intr)))
+ continue;
+
+ nvkm_intr_subdev_add_dev(intr, tdev->type, tdev->inst);
+ }
+ } else {
+ nvkm_intr_subdev_add_dev(intr, data->type, data->inst);
+ }
+ }
+ }
+}
+
+void
+nvkm_intr_rearm(struct nvkm_device *device)
+{
+ struct nvkm_intr *intr;
+ int i;
+
+ if (unlikely(!device->intr.legacy_done)) {
+ list_for_each_entry(intr, &device->intr.intr, head)
+ nvkm_intr_subdev_add(intr);
+ device->intr.legacy_done = true;
+ }
+
+ spin_lock_irq(&device->intr.lock);
+ list_for_each_entry(intr, &device->intr.intr, head) {
+ for (i = 0; intr->func->block && i < intr->leaves; i++) {
+ intr->func->block(intr, i, ~0);
+ intr->func->allow(intr, i, intr->mask[i]);
+ }
+ }
+
+ nvkm_intr_rearm_locked(device);
+ device->intr.armed = true;
+ spin_unlock_irq(&device->intr.lock);
+}
+
+void
+nvkm_intr_unarm(struct nvkm_device *device)
+{
+ spin_lock_irq(&device->intr.lock);
+ nvkm_intr_unarm_locked(device);
+ device->intr.armed = false;
+ spin_unlock_irq(&device->intr.lock);
+}
+
+int
+nvkm_intr_install(struct nvkm_device *device)
+{
+ int ret;
+
+ device->intr.irq = device->func->irq(device);
+ if (device->intr.irq < 0)
+ return device->intr.irq;
+
+ ret = request_irq(device->intr.irq, nvkm_intr, IRQF_SHARED, "nvkm", device);
+ if (ret)
+ return ret;
+
+ device->intr.alloc = true;
+ return 0;
+}
+
+void
+nvkm_intr_dtor(struct nvkm_device *device)
+{
+ struct nvkm_intr *intr, *intt;
+
+ list_for_each_entry_safe(intr, intt, &device->intr.intr, head) {
+ list_del(&intr->head);
+ kfree(intr->mask);
+ kfree(intr->stat);
+ }
+
+ if (device->intr.alloc)
+ free_irq(device->intr.irq, device);
+}
+
+void
+nvkm_intr_ctor(struct nvkm_device *device)
+{
+ int i;
+
+ INIT_LIST_HEAD(&device->intr.intr);
+ for (i = 0; i < ARRAY_SIZE(device->intr.prio); i++)
+ INIT_LIST_HEAD(&device->intr.prio[i]);
+
+ spin_lock_init(&device->intr.lock);
+ device->intr.armed = false;
+}
+
+void
+nvkm_inth_block(struct nvkm_inth *inth)
+{
+ if (unlikely(!inth->intr))
+ return;
+
+ atomic_set(&inth->allowed, 0);
+}
+
+void
+nvkm_inth_allow(struct nvkm_inth *inth)
+{
+ struct nvkm_intr *intr = inth->intr;
+ unsigned long flags;
+
+ if (unlikely(!inth->intr))
+ return;
+
+ spin_lock_irqsave(&intr->subdev->device->intr.lock, flags);
+ if (!atomic_xchg(&inth->allowed, 1)) {
+ if ((intr->mask[inth->leaf] & inth->mask) != inth->mask)
+ nvkm_intr_allow_locked(intr, inth->leaf, inth->mask);
+ }
+ spin_unlock_irqrestore(&intr->subdev->device->intr.lock, flags);
+}
+
+int
+nvkm_inth_add(struct nvkm_intr *intr, enum nvkm_intr_type type, enum nvkm_intr_prio prio,
+ struct nvkm_subdev *subdev, nvkm_inth_func func, struct nvkm_inth *inth)
+{
+ struct nvkm_device *device = subdev->device;
+ int ret;
+
+ if (WARN_ON(inth->mask))
+ return -EBUSY;
+
+ ret = nvkm_intr_xlat(subdev, intr, type, &inth->leaf, &inth->mask);
+ if (ret)
+ return ret;
+
+ nvkm_debug(intr->subdev, "intr %d/%08x requested by %s\n",
+ inth->leaf, inth->mask, subdev->name);
+
+ inth->intr = intr;
+ inth->func = func;
+ atomic_set(&inth->allowed, 0);
+ list_add_tail(&inth->head, &device->intr.prio[prio]);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
index 45f920da89af..0b33287e43a7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
@@ -47,6 +47,26 @@ nvkm_ioctl_nop(struct nvkm_client *client,
return ret;
}
+#include <nvif/class.h>
+
+static int
+nvkm_ioctl_sclass_(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
+{
+ if ( object->func->uevent &&
+ !object->func->uevent(object, NULL, 0, NULL) && index-- == 0) {
+ oclass->ctor = nvkm_uevent_new;
+ oclass->base.minver = 0;
+ oclass->base.maxver = 0;
+ oclass->base.oclass = NVIF_CLASS_EVENT;
+ return 0;
+ }
+
+ if (object->func->sclass)
+ return object->func->sclass(object, index, oclass);
+
+ return -ENOSYS;
+}
+
static int
nvkm_ioctl_sclass(struct nvkm_client *client,
struct nvkm_object *object, void *data, u32 size)
@@ -64,8 +84,7 @@ nvkm_ioctl_sclass(struct nvkm_client *client,
if (size != args->v0.count * sizeof(args->v0.oclass[0]))
return -EINVAL;
- while (object->func->sclass &&
- object->func->sclass(object, i, &oclass) >= 0) {
+ while (nvkm_ioctl_sclass_(object, i, &oclass) >= 0) {
if (i < args->v0.count) {
args->v0.oclass[i].oclass = oclass.base.oclass;
args->v0.oclass[i].minver = oclass.base.minver;
@@ -100,7 +119,7 @@ nvkm_ioctl_new(struct nvkm_client *client,
} else
return ret;
- if (!parent->func->sclass) {
+ if (!parent->func->sclass && !parent->func->uevent) {
nvif_ioctl(parent, "cannot have children\n");
return -EINVAL;
}
@@ -113,7 +132,7 @@ nvkm_ioctl_new(struct nvkm_client *client,
oclass.object = args->v0.object;
oclass.client = client;
oclass.parent = parent;
- ret = parent->func->sclass(parent, i++, &oclass);
+ ret = nvkm_ioctl_sclass_(parent, i++, &oclass);
if (ret)
return ret;
} while (oclass.base.oclass != args->v0.oclass);
@@ -294,90 +313,6 @@ nvkm_ioctl_unmap(struct nvkm_client *client,
return ret;
}
-static int
-nvkm_ioctl_ntfy_new(struct nvkm_client *client,
- struct nvkm_object *object, void *data, u32 size)
-{
- union {
- struct nvif_ioctl_ntfy_new_v0 v0;
- } *args = data;
- struct nvkm_event *event;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "ntfy new size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
- nvif_ioctl(object, "ntfy new vers %d event %02x\n",
- args->v0.version, args->v0.event);
- ret = nvkm_object_ntfy(object, args->v0.event, &event);
- if (ret == 0) {
- ret = nvkm_client_notify_new(object, event, data, size);
- if (ret >= 0) {
- args->v0.index = ret;
- ret = 0;
- }
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_del(struct nvkm_client *client,
- struct nvkm_object *object, void *data, u32 size)
-{
- union {
- struct nvif_ioctl_ntfy_del_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "ntfy del size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "ntfy del vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_del(client, args->v0.index);
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_get(struct nvkm_client *client,
- struct nvkm_object *object, void *data, u32 size)
-{
- union {
- struct nvif_ioctl_ntfy_get_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "ntfy get size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "ntfy get vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_get(client, args->v0.index);
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_put(struct nvkm_client *client,
- struct nvkm_object *object, void *data, u32 size)
-{
- union {
- struct nvif_ioctl_ntfy_put_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "ntfy put size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "ntfy put vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_put(client, args->v0.index);
- }
-
- return ret;
-}
-
static struct {
int version;
int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32);
@@ -392,10 +327,6 @@ nvkm_ioctl_v0[] = {
{ 0x00, nvkm_ioctl_wr },
{ 0x00, nvkm_ioctl_map },
{ 0x00, nvkm_ioctl_unmap },
- { 0x00, nvkm_ioctl_ntfy_new },
- { 0x00, nvkm_ioctl_ntfy_del },
- { 0x00, nvkm_ioctl_ntfy_get },
- { 0x00, nvkm_ioctl_ntfy_put },
};
static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/notify.c b/drivers/gpu/drm/nouveau/nvkm/core/notify.c
deleted file mode 100644
index 023610d01458..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/core/notify.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-#include <core/notify.h>
-#include <core/event.h>
-
-static inline void
-nvkm_notify_put_locked(struct nvkm_notify *notify)
-{
- if (notify->block++ == 0)
- nvkm_event_put(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_put(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
- if (likely(event) &&
- test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_put_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
- flush_work(&notify->work);
- }
-}
-
-static inline void
-nvkm_notify_get_locked(struct nvkm_notify *notify)
-{
- if (--notify->block == 0)
- nvkm_event_get(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_get(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
- if (likely(event) &&
- !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_get_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- }
-}
-
-static inline void
-nvkm_notify_func(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- int ret = notify->func(notify);
- unsigned long flags;
- if ((ret == NVKM_NOTIFY_KEEP) ||
- !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_get_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- }
-}
-
-static void
-nvkm_notify_work(struct work_struct *work)
-{
- struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
- nvkm_notify_func(notify);
-}
-
-void
-nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
-
- assert_spin_locked(&event->list_lock);
- BUG_ON(size != notify->size);
-
- spin_lock_irqsave(&event->refs_lock, flags);
- if (notify->block) {
- spin_unlock_irqrestore(&event->refs_lock, flags);
- return;
- }
- nvkm_notify_put_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
-
- if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
- memcpy((void *)notify->data, data, size);
- schedule_work(&notify->work);
- } else {
- notify->data = data;
- nvkm_notify_func(notify);
- notify->data = NULL;
- }
-}
-
-void
-nvkm_notify_fini(struct nvkm_notify *notify)
-{
- unsigned long flags;
- if (notify->event) {
- nvkm_notify_put(notify);
- spin_lock_irqsave(&notify->event->list_lock, flags);
- list_del(&notify->head);
- spin_unlock_irqrestore(&notify->event->list_lock, flags);
- kfree((void *)notify->data);
- notify->event = NULL;
- }
-}
-
-int
-nvkm_notify_init(struct nvkm_object *object, struct nvkm_event *event,
- int (*func)(struct nvkm_notify *), bool work,
- void *data, u32 size, u32 reply,
- struct nvkm_notify *notify)
-{
- unsigned long flags;
- int ret = -ENODEV;
- if ((notify->event = event), event->refs) {
- ret = event->func->ctor(object, data, size, notify);
- if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
- notify->flags = 0;
- notify->block = 1;
- notify->func = func;
- notify->data = NULL;
- if (ret = 0, work) {
- INIT_WORK(&notify->work, nvkm_notify_work);
- set_bit(NVKM_NOTIFY_WORK, &notify->flags);
- notify->data = kmalloc(reply, GFP_KERNEL);
- if (!notify->data)
- ret = -ENOMEM;
- }
- }
- if (ret == 0) {
- spin_lock_irqsave(&event->list_lock, flags);
- list_add_tail(&notify->head, &event->list);
- spin_unlock_irqrestore(&event->list_lock, flags);
- }
- }
- if (ret)
- notify->event = NULL;
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c
index 16299837a296..3385528da650 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c
@@ -47,7 +47,12 @@ nvkm_oproxy_map(struct nvkm_object *object, void *argv, u32 argc,
static int
nvkm_oproxy_unmap(struct nvkm_object *object)
{
- return nvkm_object_unmap(nvkm_oproxy(object)->object);
+ struct nvkm_oproxy *oproxy = nvkm_oproxy(object);
+
+ if (unlikely(!oproxy->object))
+ return 0;
+
+ return nvkm_object_unmap(oproxy->object);
}
static int
@@ -106,6 +111,18 @@ nvkm_oproxy_sclass(struct nvkm_object *object, int index,
}
static int
+nvkm_oproxy_uevent(struct nvkm_object *object, void *argv, u32 argc,
+ struct nvkm_uevent *uevent)
+{
+ struct nvkm_oproxy *oproxy = nvkm_oproxy(object);
+
+ if (!oproxy->object->func->uevent)
+ return -ENOSYS;
+
+ return oproxy->object->func->uevent(oproxy->object, argv, argc, uevent);
+}
+
+static int
nvkm_oproxy_fini(struct nvkm_object *object, bool suspend)
{
struct nvkm_oproxy *oproxy = nvkm_oproxy(object);
@@ -188,6 +205,7 @@ nvkm_oproxy_func = {
.wr32 = nvkm_oproxy_wr32,
.bind = nvkm_oproxy_bind,
.sclass = nvkm_oproxy_sclass,
+ .uevent = nvkm_oproxy_uevent,
};
void
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
index a74b7acb6832..6c20e827a069 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
@@ -54,7 +54,7 @@ int
nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
{
struct nvkm_device *device = subdev->device;
- const char *action = suspend ? "suspend" : "fini";
+ const char *action = suspend ? "suspend" : subdev->use.enabled ? "fini" : "reset";
s64 time;
nvkm_trace(subdev, "%s running...\n", action);
@@ -68,6 +68,7 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
return ret;
}
}
+ subdev->use.enabled = false;
nvkm_mc_reset(device, subdev->type, subdev->inst);
@@ -97,30 +98,49 @@ nvkm_subdev_preinit(struct nvkm_subdev *subdev)
return 0;
}
-int
-nvkm_subdev_init(struct nvkm_subdev *subdev)
+static int
+nvkm_subdev_oneinit_(struct nvkm_subdev *subdev)
{
s64 time;
int ret;
- nvkm_trace(subdev, "init running...\n");
+ if (!subdev->func->oneinit || subdev->oneinit)
+ return 0;
+
+ nvkm_trace(subdev, "one-time init running...\n");
time = ktime_to_us(ktime_get());
+ ret = subdev->func->oneinit(subdev);
+ if (ret) {
+ nvkm_error(subdev, "one-time init failed, %d\n", ret);
+ return ret;
+ }
- if (subdev->func->oneinit && !subdev->oneinit) {
- s64 time;
- nvkm_trace(subdev, "one-time init running...\n");
- time = ktime_to_us(ktime_get());
- ret = subdev->func->oneinit(subdev);
- if (ret) {
- nvkm_error(subdev, "one-time init failed, %d\n", ret);
- return ret;
- }
+ subdev->oneinit = true;
+ time = ktime_to_us(ktime_get()) - time;
+ nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
+ return 0;
+}
- subdev->oneinit = true;
- time = ktime_to_us(ktime_get()) - time;
- nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
+static int
+nvkm_subdev_init_(struct nvkm_subdev *subdev)
+{
+ s64 time;
+ int ret;
+
+ if (subdev->use.enabled) {
+ nvkm_trace(subdev, "init skipped, already running\n");
+ return 0;
}
+ nvkm_trace(subdev, "init running...\n");
+ time = ktime_to_us(ktime_get());
+
+ ret = nvkm_subdev_oneinit_(subdev);
+ if (ret)
+ return ret;
+
+ subdev->use.enabled = true;
+
if (subdev->func->init) {
ret = subdev->func->init(subdev);
if (ret) {
@@ -134,6 +154,64 @@ nvkm_subdev_init(struct nvkm_subdev *subdev)
return 0;
}
+int
+nvkm_subdev_init(struct nvkm_subdev *subdev)
+{
+ int ret;
+
+ mutex_lock(&subdev->use.mutex);
+ if (refcount_read(&subdev->use.refcount) == 0) {
+ nvkm_trace(subdev, "init skipped, no users\n");
+ mutex_unlock(&subdev->use.mutex);
+ return 0;
+ }
+
+ ret = nvkm_subdev_init_(subdev);
+ mutex_unlock(&subdev->use.mutex);
+ return ret;
+}
+
+int
+nvkm_subdev_oneinit(struct nvkm_subdev *subdev)
+{
+ int ret;
+
+ mutex_lock(&subdev->use.mutex);
+ ret = nvkm_subdev_oneinit_(subdev);
+ mutex_unlock(&subdev->use.mutex);
+ return ret;
+}
+
+void
+nvkm_subdev_unref(struct nvkm_subdev *subdev)
+{
+ if (refcount_dec_and_mutex_lock(&subdev->use.refcount, &subdev->use.mutex)) {
+ nvkm_subdev_fini(subdev, false);
+ mutex_unlock(&subdev->use.mutex);
+ }
+}
+
+int
+nvkm_subdev_ref(struct nvkm_subdev *subdev)
+{
+ int ret;
+
+ if (subdev && !refcount_inc_not_zero(&subdev->use.refcount)) {
+ mutex_lock(&subdev->use.mutex);
+ if (!refcount_inc_not_zero(&subdev->use.refcount)) {
+ if ((ret = nvkm_subdev_init_(subdev))) {
+ mutex_unlock(&subdev->use.mutex);
+ return ret;
+ }
+
+ refcount_set(&subdev->use.refcount, 1);
+ }
+ mutex_unlock(&subdev->use.mutex);
+ }
+
+ return 0;
+}
+
void
nvkm_subdev_del(struct nvkm_subdev **psubdev)
{
@@ -146,6 +224,7 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev)
list_del(&subdev->head);
if (subdev->func->dtor)
*psubdev = subdev->func->dtor(subdev);
+ mutex_destroy(&subdev->use.mutex);
time = ktime_to_us(ktime_get()) - time;
nvkm_trace(subdev, "destroy completed in %lldus\n", time);
kfree(*psubdev);
@@ -167,8 +246,8 @@ nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int
}
void
-nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)
+__nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)
{
subdev->func = func;
subdev->device = device;
@@ -180,6 +259,8 @@ nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device
else
strscpy(subdev->name, nvkm_subdev_type[type], sizeof(subdev->name));
subdev->debug = nvkm_dbgopt(device->dbgopt, subdev->name);
+
+ refcount_set(&subdev->use.refcount, 1);
list_add_tail(&subdev->head, &device->subdev);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/uevent.c b/drivers/gpu/drm/nouveau/nvkm/core/uevent.c
new file mode 100644
index 000000000000..ba9d9edaec75
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/uevent.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#define nvkm_uevent(p) container_of((p), struct nvkm_uevent, object)
+#include <core/event.h>
+#include <core/client.h>
+
+#include <nvif/if000e.h>
+
+struct nvkm_uevent {
+ struct nvkm_object object;
+ struct nvkm_object *parent;
+ nvkm_uevent_func func;
+ bool wait;
+
+ struct nvkm_event_ntfy ntfy;
+ atomic_t allowed;
+};
+
+static int
+nvkm_uevent_mthd_block(struct nvkm_uevent *uevent, union nvif_event_block_args *args, u32 argc)
+{
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ nvkm_event_ntfy_block(&uevent->ntfy);
+ atomic_set(&uevent->allowed, 0);
+ return 0;
+}
+
+static int
+nvkm_uevent_mthd_allow(struct nvkm_uevent *uevent, union nvif_event_allow_args *args, u32 argc)
+{
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ nvkm_event_ntfy_allow(&uevent->ntfy);
+ atomic_set(&uevent->allowed, 1);
+ return 0;
+}
+
+static int
+nvkm_uevent_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
+{
+ struct nvkm_uevent *uevent = nvkm_uevent(object);
+
+ switch (mthd) {
+ case NVIF_EVENT_V0_ALLOW: return nvkm_uevent_mthd_allow(uevent, argv, argc);
+ case NVIF_EVENT_V0_BLOCK: return nvkm_uevent_mthd_block(uevent, argv, argc);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int
+nvkm_uevent_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_uevent *uevent = nvkm_uevent(object);
+
+ nvkm_event_ntfy_block(&uevent->ntfy);
+ return 0;
+}
+
+static int
+nvkm_uevent_init(struct nvkm_object *object)
+{
+ struct nvkm_uevent *uevent = nvkm_uevent(object);
+
+ if (atomic_read(&uevent->allowed))
+ nvkm_event_ntfy_allow(&uevent->ntfy);
+
+ return 0;
+}
+
+static void *
+nvkm_uevent_dtor(struct nvkm_object *object)
+{
+ struct nvkm_uevent *uevent = nvkm_uevent(object);
+
+ nvkm_event_ntfy_del(&uevent->ntfy);
+ return uevent;
+}
+
+static const struct nvkm_object_func
+nvkm_uevent = {
+ .dtor = nvkm_uevent_dtor,
+ .init = nvkm_uevent_init,
+ .fini = nvkm_uevent_fini,
+ .mthd = nvkm_uevent_mthd,
+};
+
+static int
+nvkm_uevent_ntfy(struct nvkm_event_ntfy *ntfy, u32 bits)
+{
+ struct nvkm_uevent *uevent = container_of(ntfy, typeof(*uevent), ntfy);
+ struct nvkm_client *client = uevent->object.client;
+
+ if (uevent->func)
+ return uevent->func(uevent->parent, uevent->object.token, bits);
+
+ return client->event(uevent->object.token, NULL, 0);
+}
+
+int
+nvkm_uevent_add(struct nvkm_uevent *uevent, struct nvkm_event *event, int id, u32 bits,
+ nvkm_uevent_func func)
+{
+ if (WARN_ON(uevent->func))
+ return -EBUSY;
+
+ nvkm_event_ntfy_add(event, id, bits, uevent->wait, nvkm_uevent_ntfy, &uevent->ntfy);
+ uevent->func = func;
+ return 0;
+}
+
+int
+nvkm_uevent_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_object *parent = oclass->parent;
+ struct nvkm_uevent *uevent;
+ union nvif_event_args *args = argv;
+
+ if (argc < sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ if (!(uevent = kzalloc(sizeof(*uevent), GFP_KERNEL)))
+ return -ENOMEM;
+ *pobject = &uevent->object;
+
+ nvkm_object_ctor(&nvkm_uevent, oclass, &uevent->object);
+ uevent->parent = parent;
+ uevent->func = NULL;
+ uevent->wait = args->v0.wait;
+ uevent->ntfy.event = NULL;
+ return parent->func->uevent(parent, &args->v0.data, argc - sizeof(args->v0), uevent);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
index ba88613e1e46..8bf1635ffabc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
@@ -8,3 +8,5 @@ nvkm-y += nvkm/engine/ce/gp100.o
nvkm-y += nvkm/engine/ce/gp102.o
nvkm-y += nvkm/engine/ce/gv100.o
nvkm-y += nvkm/engine/ce/tu102.o
+nvkm-y += nvkm/engine/ce/ga100.o
+nvkm-y += nvkm/engine/ce/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c
new file mode 100644
index 000000000000..6648ed62daa6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <subdev/vfn.h>
+
+#include <nvif/class.h>
+
+static irqreturn_t
+ga100_ce_intr(struct nvkm_inth *inth)
+{
+ struct nvkm_subdev *subdev = container_of(inth, typeof(*subdev), inth);
+
+ /*TODO*/
+ nvkm_error(subdev, "intr\n");
+ return IRQ_NONE;
+}
+
+int
+ga100_ce_fini(struct nvkm_engine *engine, bool suspend)
+{
+ nvkm_inth_block(&engine->subdev.inth);
+ return 0;
+}
+
+int
+ga100_ce_init(struct nvkm_engine *engine)
+{
+ nvkm_inth_allow(&engine->subdev.inth);
+ return 0;
+}
+
+int
+ga100_ce_oneinit(struct nvkm_engine *engine)
+{
+ struct nvkm_subdev *subdev = &engine->subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 vector;
+
+ vector = nvkm_rd32(device, 0x10442c + (subdev->inst * 0x80)) & 0x00000fff;
+
+ return nvkm_inth_add(&device->vfn->intr, vector, NVKM_INTR_PRIO_NORMAL,
+ subdev, ga100_ce_intr, &subdev->inth);
+}
+
+static const struct nvkm_engine_func
+ga100_ce = {
+ .oneinit = ga100_ce_oneinit,
+ .init = ga100_ce_init,
+ .fini = ga100_ce_fini,
+ .cclass = &gv100_ce_cclass,
+ .sclass = {
+ { -1, -1, AMPERE_DMA_COPY_A },
+ {}
+ }
+};
+
+int
+ga100_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+{
+ return nvkm_engine_new_(&ga100_ce, device, type, inst, true, pengine);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usergv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c
index 3dc3b8b312de..9f3448ad625f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usergv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Red Hat Inc.
+ * Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -19,27 +19,26 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "user.h"
+#include "priv.h"
-static int
-gv100_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
- enum nvkm_object_map *type, u64 *addr, u64 *size)
-{
- struct nvkm_device *device = object->engine->subdev.device;
- *addr = 0x810000 + device->func->resource_addr(device, 0);
- *size = 0x010000;
- *type = NVKM_OBJECT_MAP_IO;
- return 0;
-}
+#include <nvif/class.h>
-static const struct nvkm_object_func
-gv100_fifo_user = {
- .map = gv100_fifo_user_map,
+static const struct nvkm_engine_func
+ga102_ce = {
+ .oneinit = ga100_ce_oneinit,
+ .init = ga100_ce_init,
+ .fini = ga100_ce_fini,
+ .cclass = &gv100_ce_cclass,
+ .sclass = {
+ { -1, -1, AMPERE_DMA_COPY_A },
+ { -1, -1, AMPERE_DMA_COPY_B },
+ {}
+ }
};
int
-gv100_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
- struct nvkm_object **pobject)
+ga102_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
{
- return nvkm_object_new_(&gv100_fifo_user, oclass, argv, argc, pobject);
+ return nvkm_engine_new_(&ga102_ce, device, type, inst, true, pengine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
index 09a112af2f89..c9bf6305c3ec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
@@ -40,7 +40,7 @@ gt215_ce_isr_error_name[] = {
};
void
-gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan)
+gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_chan *chan)
{
struct nvkm_subdev *subdev = &ce->engine.subdev;
struct nvkm_device *device = subdev->device;
@@ -55,9 +55,9 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan)
nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] "
"subc %d mthd %04x data %08x\n", ssta,
- en ? en->name : "", chan ? chan->chid : -1,
+ en ? en->name : "", chan ? chan->id : -1,
chan ? chan->inst->addr : 0,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->name : "unknown",
subc, mthd, data);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
index cd53b93664d6..c4c046916fa6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
@@ -8,4 +8,8 @@ void gk104_ce_intr(struct nvkm_engine *);
void gp100_ce_intr(struct nvkm_engine *);
extern const struct nvkm_object_func gv100_ce_cclass;
+
+int ga100_ce_oneinit(struct nvkm_engine *);
+int ga100_ce_init(struct nvkm_engine *);
+int ga100_ce_fini(struct nvkm_engine *, bool);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
index be2a7181dc15..caca4f639895 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
@@ -81,8 +81,7 @@ g84_cipher_intr(struct nvkm_engine *cipher)
{
struct nvkm_subdev *subdev = &cipher->subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo *fifo = device->fifo;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
u32 stat = nvkm_rd32(device, 0x102130);
u32 mthd = nvkm_rd32(device, 0x102190);
u32 data = nvkm_rd32(device, 0x102194);
@@ -90,16 +89,16 @@ g84_cipher_intr(struct nvkm_engine *cipher)
unsigned long flags;
char msg[128];
- chan = nvkm_fifo_chan_inst(fifo, (u64)inst << 12, &flags);
+ chan = nvkm_chan_get_inst(cipher, (u64)inst << 12, &flags);
if (stat) {
nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat);
nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] "
"mthd %04x data %08x\n", stat, msg,
- chan ? chan->chid : -1, (u64)inst << 12,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->id : -1, (u64)inst << 12,
+ chan ? chan->name : "unknown",
mthd, data);
}
- nvkm_fifo_chan_put(fifo, flags, &chan);
+ nvkm_chan_put(&chan, flags);
nvkm_wr32(device, 0x102130, stat);
nvkm_wr32(device, 0x10200c, 0x10);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index d8cf71fb0512..364fea320cb3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -1095,7 +1095,7 @@ nv98_chipset = {
.volt = { 0x00000001, nv40_volt_new },
.disp = { 0x00000001, g94_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, g84_gr_new },
.mspdec = { 0x00000001, g98_mspdec_new },
.msppp = { 0x00000001, g98_msppp_new },
@@ -1161,7 +1161,7 @@ nva3_chipset = {
.ce = { 0x00000001, gt215_ce_new },
.disp = { 0x00000001, gt215_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, gt215_gr_new },
.mpeg = { 0x00000001, g84_mpeg_new },
.mspdec = { 0x00000001, gt215_mspdec_new },
@@ -1195,7 +1195,7 @@ nva5_chipset = {
.ce = { 0x00000001, gt215_ce_new },
.disp = { 0x00000001, gt215_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, gt215_gr_new },
.mspdec = { 0x00000001, gt215_mspdec_new },
.msppp = { 0x00000001, gt215_msppp_new },
@@ -1228,7 +1228,7 @@ nva8_chipset = {
.ce = { 0x00000001, gt215_ce_new },
.disp = { 0x00000001, gt215_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, gt215_gr_new },
.mspdec = { 0x00000001, gt215_mspdec_new },
.msppp = { 0x00000001, gt215_msppp_new },
@@ -1259,7 +1259,7 @@ nvaa_chipset = {
.volt = { 0x00000001, nv40_volt_new },
.disp = { 0x00000001, mcp77_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, gt200_gr_new },
.mspdec = { 0x00000001, g98_mspdec_new },
.msppp = { 0x00000001, g98_msppp_new },
@@ -1291,7 +1291,7 @@ nvac_chipset = {
.volt = { 0x00000001, nv40_volt_new },
.disp = { 0x00000001, mcp77_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, mcp79_gr_new },
.mspdec = { 0x00000001, g98_mspdec_new },
.msppp = { 0x00000001, g98_msppp_new },
@@ -1325,7 +1325,7 @@ nvaf_chipset = {
.ce = { 0x00000001, gt215_ce_new },
.disp = { 0x00000001, mcp89_disp_new },
.dma = { 0x00000001, nv50_dma_new },
- .fifo = { 0x00000001, g84_fifo_new },
+ .fifo = { 0x00000001, g98_fifo_new },
.gr = { 0x00000001, mcp89_gr_new },
.mspdec = { 0x00000001, gt215_mspdec_new },
.msppp = { 0x00000001, gt215_msppp_new },
@@ -2130,7 +2130,7 @@ nv12b_chipset = {
.volt = { 0x00000001, gm20b_volt_new },
.ce = { 0x00000004, gm200_ce_new },
.dma = { 0x00000001, gf119_dma_new },
- .fifo = { 0x00000001, gm20b_fifo_new },
+ .fifo = { 0x00000001, gm200_fifo_new },
.gr = { 0x00000001, gm20b_gr_new },
.sw = { 0x00000001, gf100_sw_new },
};
@@ -2356,7 +2356,7 @@ nv13b_chipset = {
.top = { 0x00000001, gk104_top_new },
.ce = { 0x00000001, gp100_ce_new },
.dma = { 0x00000001, gf119_dma_new },
- .fifo = { 0x00000001, gp10b_fifo_new },
+ .fifo = { 0x00000001, gp100_fifo_new },
.gr = { 0x00000001, gp10b_gr_new },
.sw = { 0x00000001, gf100_sw_new },
};
@@ -2364,7 +2364,7 @@ nv13b_chipset = {
static const struct nvkm_device_chip
nv140_chipset = {
.name = "GV100",
- .acr = { 0x00000001, gp108_acr_new },
+ .acr = { 0x00000001, gv100_acr_new },
.bar = { 0x00000001, gm107_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.bus = { 0x00000001, gf100_bus_new },
@@ -2385,6 +2385,7 @@ nv140_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, gv100_vfn_new },
.ce = { 0x000001ff, gv100_ce_new },
.disp = { 0x00000001, gv100_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2411,7 +2412,7 @@ nv162_chipset = {
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
- .mc = { 0x00000001, tu102_mc_new },
+ .mc = { 0x00000001, gp100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.pmu = { 0x00000001, gp102_pmu_new },
@@ -2419,6 +2420,7 @@ nv162_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, tu102_vfn_new },
.ce = { 0x0000001f, tu102_ce_new },
.disp = { 0x00000001, tu102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2445,7 +2447,7 @@ nv164_chipset = {
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
- .mc = { 0x00000001, tu102_mc_new },
+ .mc = { 0x00000001, gp100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.pmu = { 0x00000001, gp102_pmu_new },
@@ -2453,6 +2455,7 @@ nv164_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, tu102_vfn_new },
.ce = { 0x0000001f, tu102_ce_new },
.disp = { 0x00000001, tu102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2479,7 +2482,7 @@ nv166_chipset = {
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
- .mc = { 0x00000001, tu102_mc_new },
+ .mc = { 0x00000001, gp100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.pmu = { 0x00000001, gp102_pmu_new },
@@ -2487,6 +2490,7 @@ nv166_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, tu102_vfn_new },
.ce = { 0x0000001f, tu102_ce_new },
.disp = { 0x00000001, tu102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2513,7 +2517,7 @@ nv167_chipset = {
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
- .mc = { 0x00000001, tu102_mc_new },
+ .mc = { 0x00000001, gp100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.pmu = { 0x00000001, gp102_pmu_new },
@@ -2521,6 +2525,7 @@ nv167_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, tu102_vfn_new },
.ce = { 0x0000001f, tu102_ce_new },
.disp = { 0x00000001, tu102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2547,7 +2552,7 @@ nv168_chipset = {
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
.ltc = { 0x00000001, gp102_ltc_new },
- .mc = { 0x00000001, tu102_mc_new },
+ .mc = { 0x00000001, gp100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.pmu = { 0x00000001, gp102_pmu_new },
@@ -2555,6 +2560,7 @@ nv168_chipset = {
.therm = { 0x00000001, gp100_therm_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
+ .vfn = { 0x00000001, tu102_vfn_new },
.ce = { 0x0000001f, tu102_ce_new },
.disp = { 0x00000001, tu102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
@@ -2571,6 +2577,7 @@ nv170_chipset = {
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga100_fb_new },
.gpio = { 0x00000001, gk104_gpio_new },
.i2c = { 0x00000001, gm200_i2c_new },
@@ -2581,111 +2588,159 @@ nv170_chipset = {
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x000003ff, ga100_ce_new },
+ .fifo = { 0x00000001, ga100_fifo_new },
};
static const struct nvkm_device_chip
nv172_chipset = {
.name = "GA102",
+ .acr = { 0x00000001, ga102_acr_new },
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga102_fb_new },
.gpio = { 0x00000001, ga102_gpio_new },
+ .gsp = { 0x00000001, ga102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
+ .ltc = { 0x00000001, ga102_ltc_new },
.mc = { 0x00000001, ga100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
.disp = { 0x00000001, ga102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ga102_gr_new },
+ .nvdec = { 0x00000001, ga102_nvdec_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
};
static const struct nvkm_device_chip
nv173_chipset = {
.name = "GA103",
+ .acr = { 0x00000001, ga102_acr_new },
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga102_fb_new },
.gpio = { 0x00000001, ga102_gpio_new },
+ .gsp = { 0x00000001, ga102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
+ .ltc = { 0x00000001, ga102_ltc_new },
.mc = { 0x00000001, ga100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
.disp = { 0x00000001, ga102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ga102_gr_new },
+ .nvdec = { 0x00000001, ga102_nvdec_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
};
static const struct nvkm_device_chip
nv174_chipset = {
.name = "GA104",
+ .acr = { 0x00000001, ga102_acr_new },
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga102_fb_new },
.gpio = { 0x00000001, ga102_gpio_new },
+ .gsp = { 0x00000001, ga102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
+ .ltc = { 0x00000001, ga102_ltc_new },
.mc = { 0x00000001, ga100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
.disp = { 0x00000001, ga102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ga102_gr_new },
+ .nvdec = { 0x00000001, ga102_nvdec_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
};
static const struct nvkm_device_chip
nv176_chipset = {
.name = "GA106",
+ .acr = { 0x00000001, ga102_acr_new },
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga102_fb_new },
.gpio = { 0x00000001, ga102_gpio_new },
+ .gsp = { 0x00000001, ga102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
+ .ltc = { 0x00000001, ga102_ltc_new },
.mc = { 0x00000001, ga100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
.disp = { 0x00000001, ga102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ga102_gr_new },
+ .nvdec = { 0x00000001, ga102_nvdec_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
};
static const struct nvkm_device_chip
nv177_chipset = {
.name = "GA107",
+ .acr = { 0x00000001, ga102_acr_new },
.bar = { 0x00000001, tu102_bar_new },
.bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
+ .fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga102_fb_new },
.gpio = { 0x00000001, ga102_gpio_new },
+ .gsp = { 0x00000001, ga102_gsp_new },
.i2c = { 0x00000001, gm200_i2c_new },
.imem = { 0x00000001, nv50_instmem_new },
+ .ltc = { 0x00000001, ga102_ltc_new },
.mc = { 0x00000001, ga100_mc_new },
.mmu = { 0x00000001, tu102_mmu_new },
.pci = { 0x00000001, gp100_pci_new },
.privring = { 0x00000001, gm200_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, ga100_top_new },
+ .vfn = { 0x00000001, ga100_vfn_new },
+ .ce = { 0x0000001f, ga102_ce_new },
.disp = { 0x00000001, ga102_disp_new },
.dma = { 0x00000001, gv100_dma_new },
.fifo = { 0x00000001, ga102_fifo_new },
+ .gr = { 0x00000001, ga102_gr_new },
+ .nvdec = { 0x00000001, ga102_nvdec_new },
+ .sec2 = { 0x00000001, ga102_sec2_new },
};
struct nvkm_subdev *
@@ -2734,6 +2789,8 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend)
if (device->func->fini)
device->func->fini(device, suspend);
+ nvkm_intr_unarm(device);
+
time = ktime_to_us(ktime_get()) - time;
nvdev_trace(device, "%s completed in %lldus...\n", action, time);
return 0;
@@ -2759,6 +2816,8 @@ nvkm_device_preinit(struct nvkm_device *device)
nvdev_trace(device, "preinit running...\n");
time = ktime_to_us(ktime_get());
+ nvkm_intr_unarm(device);
+
if (device->func->preinit) {
ret = device->func->preinit(device);
if (ret)
@@ -2775,6 +2834,14 @@ nvkm_device_preinit(struct nvkm_device *device)
if (ret)
goto fail;
+ ret = nvkm_top_parse(device);
+ if (ret)
+ goto fail;
+
+ ret = nvkm_fb_mem_unlock(device->fb);
+ if (ret)
+ goto fail;
+
time = ktime_to_us(ktime_get()) - time;
nvdev_trace(device, "preinit completed in %lldus\n", time);
return 0;
@@ -2800,6 +2867,8 @@ nvkm_device_init(struct nvkm_device *device)
nvdev_trace(device, "init running...\n");
time = ktime_to_us(ktime_get());
+ nvkm_intr_rearm(device);
+
if (device->func->init) {
ret = device->func->init(device);
if (ret)
@@ -2837,6 +2906,8 @@ nvkm_device_del(struct nvkm_device **pdevice)
if (device) {
mutex_lock(&nv_devices_mutex);
+ nvkm_intr_dtor(device);
+
list_for_each_entry_safe_reverse(subdev, subtmp, &device->subdev, head)
nvkm_subdev_del(&subdev);
@@ -3144,6 +3215,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
device->name = device->chip->name;
mutex_init(&device->mutex);
+ nvkm_intr_ctor(device);
#define NVKM_LAYOUT_ONCE(type,data,ptr) \
if (device->chip->ptr.inst && (subdev_mask & (BIT_ULL(type)))) { \
@@ -3185,7 +3257,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
#undef NVKM_LAYOUT_INST
#undef NVKM_LAYOUT_ONCE
- ret = 0;
+ ret = nvkm_intr_install(device);
done:
if (device->pri && (!mmio || ret)) {
iounmap(device->pri);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
index f302d2b5782a..abccb2bb68a6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
@@ -1574,6 +1574,12 @@ nvkm_device_pci_resource_size(struct nvkm_device *device, unsigned bar)
return pci_resource_len(pdev->pdev, bar);
}
+static int
+nvkm_device_pci_irq(struct nvkm_device *device)
+{
+ return nvkm_device_pci(device)->pdev->irq;
+}
+
static void
nvkm_device_pci_fini(struct nvkm_device *device, bool suspend)
{
@@ -1612,6 +1618,7 @@ nvkm_device_pci_func = {
.dtor = nvkm_device_pci_dtor,
.preinit = nvkm_device_pci_preinit,
.fini = nvkm_device_pci_fini,
+ .irq = nvkm_device_pci_irq,
.resource_addr = nvkm_device_pci_resource_addr,
.resource_size = nvkm_device_pci_resource_size,
.cpu_coherent = !IS_ENABLED(CONFIG_ARM),
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
index 93949b3c7214..24faaac15891 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -27,6 +27,7 @@
#include <subdev/therm.h>
#include <subdev/timer.h>
#include <subdev/top.h>
+#include <subdev/vfn.h>
#include <subdev/volt.h>
#include <engine/bsp.h>
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
index ac9e122586bc..87caa4a72921 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -206,45 +206,12 @@ nvkm_device_tegra_resource_size(struct nvkm_device *device, unsigned bar)
return res ? resource_size(res) : 0;
}
-static irqreturn_t
-nvkm_device_tegra_intr(int irq, void *arg)
-{
- struct nvkm_device_tegra *tdev = arg;
- struct nvkm_device *device = &tdev->device;
- bool handled = false;
- nvkm_mc_intr_unarm(device);
- nvkm_mc_intr(device, &handled);
- nvkm_mc_intr_rearm(device);
- return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static void
-nvkm_device_tegra_fini(struct nvkm_device *device, bool suspend)
-{
- struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
- if (tdev->irq) {
- free_irq(tdev->irq, tdev);
- tdev->irq = 0;
- }
-}
-
static int
-nvkm_device_tegra_init(struct nvkm_device *device)
+nvkm_device_tegra_irq(struct nvkm_device *device)
{
struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
- int irq, ret;
-
- irq = platform_get_irq_byname(tdev->pdev, "stall");
- if (irq < 0)
- return irq;
- ret = request_irq(irq, nvkm_device_tegra_intr,
- IRQF_SHARED, "nvkm", tdev);
- if (ret)
- return ret;
-
- tdev->irq = irq;
- return 0;
+ return platform_get_irq_byname(tdev->pdev, "stall");
}
static void *
@@ -260,8 +227,7 @@ static const struct nvkm_device_func
nvkm_device_tegra_func = {
.tegra = nvkm_device_tegra,
.dtor = nvkm_device_tegra_dtor,
- .init = nvkm_device_tegra_init,
- .fini = nvkm_device_tegra_fini,
+ .irq = nvkm_device_tegra_irq,
.resource_addr = nvkm_device_tegra_resource_addr,
.resource_size = nvkm_device_tegra_resource_size,
.cpu_coherent = false,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index 45f509c11c36..9b39ec341615 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -342,6 +342,8 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index,
sclass = &device->mmu->user;
else if (device->fault && index-- == 0)
sclass = &device->fault->user;
+ else if (device->vfn && index-- == 0)
+ sclass = &device->vfn->user;
else
return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
index 600072a904be..e1aecd3fe96c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -28,9 +28,7 @@ nvkm-y += nvkm/engine/disp/gv100.o
nvkm-y += nvkm/engine/disp/tu102.o
nvkm-y += nvkm/engine/disp/ga102.o
-nvkm-y += nvkm/engine/disp/rootnv04.o
-nvkm-y += nvkm/engine/disp/rootnv50.o
-
nvkm-y += nvkm/engine/disp/udisp.o
nvkm-y += nvkm/engine/disp/uconn.o
nvkm-y += nvkm/engine/disp/uoutp.o
+nvkm-y += nvkm/engine/disp/uhead.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
index 65c99d948b68..73104b59f97f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -29,7 +29,6 @@
#include "outp.h"
#include <core/client.h>
-#include <core/notify.h>
#include <core/ramht.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@@ -57,32 +56,8 @@ nvkm_disp_vblank_init(struct nvkm_event *event, int type, int id)
head->func->vblank_get(head);
}
-static int
-nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_disp *disp =
- container_of(notify->event, typeof(*disp), vblank);
- union {
- struct nvif_notify_head_req_v0 v0;
- } *req = data;
- int ret = -ENOSYS;
-
- if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
- notify->size = sizeof(struct nvif_notify_head_rep_v0);
- if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
- notify->types = 1;
- notify->index = req->v0.head;
- return 0;
- }
- }
-
- return ret;
-}
-
static const struct nvkm_event_func
nvkm_disp_vblank_func = {
- .ctor = nvkm_disp_vblank_ctor,
.init = nvkm_disp_vblank_init,
.fini = nvkm_disp_vblank_fini,
};
@@ -90,59 +65,7 @@ nvkm_disp_vblank_func = {
void
nvkm_disp_vblank(struct nvkm_disp *disp, int head)
{
- struct nvif_notify_head_rep_v0 rep = {};
- nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
-}
-
-static int
-nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_disp *disp =
- container_of(notify->event, typeof(*disp), hpd);
- union {
- struct nvif_notify_conn_req_v0 v0;
- } *req = data;
- struct nvkm_outp *outp;
- int ret = -ENOSYS;
-
- if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
- notify->size = sizeof(struct nvif_notify_conn_rep_v0);
- list_for_each_entry(outp, &disp->outps, head) {
- if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
- if (ret = -ENODEV, outp->conn->hpd.event) {
- notify->types = req->v0.mask;
- notify->index = req->v0.conn;
- ret = 0;
- }
- break;
- }
- }
- }
-
- return ret;
-}
-
-static const struct nvkm_event_func
-nvkm_disp_hpd_func = {
- .ctor = nvkm_disp_hpd_ctor
-};
-
-int
-nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
-{
- struct nvkm_disp *disp = nvkm_disp(object->engine);
- switch (type) {
- case NV04_DISP_NTFY_VBLANK:
- *event = &disp->vblank;
- return 0;
- case NV04_DISP_NTFY_CONN:
- *event = &disp->hpd;
- return 0;
- default:
- break;
- }
- return -EINVAL;
+ nvkm_event_ntfy(&disp->vblank, head, NVKM_DISP_HEAD_EVENT_VBLANK);
}
static int
@@ -343,9 +266,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
/* Apparently we need to create a new one! */
ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
if (ret) {
- nvkm_error(&disp->engine.subdev,
- "failed to create outp %d conn: %d\n",
- outp->index, ret);
+ nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret);
nvkm_conn_del(&outp->conn);
list_del(&outp->head);
nvkm_outp_del(&outp);
@@ -355,10 +276,6 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
list_add_tail(&outp->conn->head, &disp->conns);
}
- ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
- if (ret)
- return ret;
-
if (disp->func->oneinit) {
ret = disp->func->oneinit(disp);
if (ret)
@@ -382,7 +299,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
list_for_each_entry(head, &disp->heads, head)
i = max(i, head->id + 1);
- return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank);
+ return nvkm_event_init(&nvkm_disp_vblank_func, subdev, 1, i, &disp->vblank);
}
static void *
@@ -406,7 +323,6 @@ nvkm_disp_dtor(struct nvkm_engine *engine)
}
nvkm_event_fini(&disp->vblank);
- nvkm_event_fini(&disp->hpd);
while (!list_empty(&disp->conns)) {
conn = list_first_entry(&disp->conns, typeof(*conn), head);
@@ -473,5 +389,6 @@ nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
mutex_init(&disp->super.mutex);
}
- return nvkm_event_init(func->uevent, 1, ARRAY_SIZE(disp->chan), &disp->uevent);
+ return nvkm_event_init(func->uevent, &disp->engine.subdev, 1, ARRAY_SIZE(disp->chan),
+ &disp->uevent);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
index 7ed11801a3ae..fbdae1137864 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -29,38 +29,14 @@
#include <nvif/event.h>
-static int
-nvkm_conn_hpd(struct nvkm_notify *notify)
-{
- struct nvkm_conn *conn = container_of(notify, typeof(*conn), hpd);
- struct nvkm_disp *disp = conn->disp;
- struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
- const struct nvkm_gpio_ntfy_rep *line = notify->data;
- struct nvif_notify_conn_rep_v0 rep;
- int index = conn->index;
-
- CONN_DBG(conn, "HPD: %d", line->mask);
-
- if (!nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
- rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
- else
- rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
- rep.version = 0;
-
- nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
- return NVKM_NOTIFY_KEEP;
-}
-
void
nvkm_conn_fini(struct nvkm_conn *conn)
{
- nvkm_notify_put(&conn->hpd);
}
void
nvkm_conn_init(struct nvkm_conn *conn)
{
- nvkm_notify_get(&conn->hpd);
}
void
@@ -68,7 +44,6 @@ nvkm_conn_del(struct nvkm_conn **pconn)
{
struct nvkm_conn *conn = *pconn;
if (conn) {
- nvkm_notify_fini(&conn->hpd);
kfree(*pconn);
*pconn = NULL;
}
@@ -106,20 +81,6 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
}
conn->info.hpd = func.line;
-
- ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
- true, &(struct nvkm_gpio_ntfy_req) {
- .mask = NVKM_GPIO_TOGGLED,
- .line = func.line,
- },
- sizeof(struct nvkm_gpio_ntfy_req),
- sizeof(struct nvkm_gpio_ntfy_rep),
- &conn->hpd);
- if (ret) {
- CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret);
- } else {
- CONN_DBG(conn, "func %02x (HPD)", info->hpd);
- }
}
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
index f109634ce5ca..a0600e72b0ec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
@@ -3,7 +3,6 @@
#define __NVKM_DISP_CONN_H__
#include "priv.h"
-#include <core/notify.h>
#include <subdev/bios.h>
#include <subdev/bios/conn.h>
@@ -12,8 +11,6 @@ struct nvkm_conn {
int index;
struct nvbios_connE info;
- struct nvkm_notify hpd;
-
struct list_head head;
struct nvkm_object object;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index c1b3206f27e6..40c8ea43c42f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -274,70 +274,17 @@ nvkm_dp_train_cr(struct lt_state *lt)
}
static int
-nvkm_dp_train_links(struct nvkm_outp *outp, int rate)
+nvkm_dp_train_link(struct nvkm_outp *outp, int rate)
{
struct nvkm_ior *ior = outp->ior;
- struct nvkm_disp *disp = outp->disp;
- struct nvkm_subdev *subdev = &disp->engine.subdev;
- struct nvkm_bios *bios = subdev->device->bios;
struct lt_state lt = {
.outp = outp,
+ .pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED,
};
- u32 lnkcmp;
u8 sink[2], data;
int ret;
- OUTP_DBG(outp, "training %d x %d MB/s", ior->dp.nr, ior->dp.bw * 27);
-
- /* Intersect misc. capabilities of the OR and sink. */
- if (disp->engine.subdev.device->chipset < 0x110)
- outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED;
- if (disp->engine.subdev.device->chipset < 0xd0)
- outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
- lt.pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
-
- if (AMPERE_IED_HACK(disp) && (lnkcmp = lt.outp->dp.info.script[0])) {
- /* Execute BeforeLinkTraining script from DP Info table. */
- while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
- lnkcmp += 3;
- lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
-
- nvbios_init(&outp->disp->engine.subdev, lnkcmp,
- init.outp = &outp->info;
- init.or = ior->id;
- init.link = ior->asy.link;
- );
- }
-
- /* Set desired link configuration on the source. */
- if ((lnkcmp = lt.outp->dp.info.lnkcmp)) {
- if (outp->dp.version < 0x30) {
- while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp))
- lnkcmp += 4;
- lnkcmp = nvbios_rd16(bios, lnkcmp + 2);
- } else {
- while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
- lnkcmp += 3;
- lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
- }
-
- nvbios_init(subdev, lnkcmp,
- init.outp = &outp->info;
- init.or = ior->id;
- init.link = ior->asy.link;
- );
- }
-
- ret = ior->func->dp->links(ior, outp->dp.aux);
- if (ret) {
- if (ret < 0) {
- OUTP_ERR(outp, "train failed with %d", ret);
- return ret;
- }
- return 0;
- }
-
- ior->func->dp->power(ior, ior->dp.nr);
+ OUTP_DBG(outp, "training %dx%02x", ior->dp.nr, ior->dp.bw);
/* Select LTTPR non-transparent mode if we have a valid configuration,
* use transparent mode otherwise.
@@ -393,6 +340,71 @@ nvkm_dp_train_links(struct nvkm_outp *outp, int rate)
return ret;
}
+static int
+nvkm_dp_train_links(struct nvkm_outp *outp, int rate)
+{
+ struct nvkm_ior *ior = outp->ior;
+ struct nvkm_disp *disp = outp->disp;
+ struct nvkm_subdev *subdev = &disp->engine.subdev;
+ struct nvkm_bios *bios = subdev->device->bios;
+ u32 lnkcmp;
+ int ret;
+
+ OUTP_DBG(outp, "programming link for %dx%02x", ior->dp.nr, ior->dp.bw);
+
+ /* Intersect misc. capabilities of the OR and sink. */
+ if (disp->engine.subdev.device->chipset < 0x110)
+ outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED;
+ if (disp->engine.subdev.device->chipset < 0xd0)
+ outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
+
+ if (AMPERE_IED_HACK(disp) && (lnkcmp = outp->dp.info.script[0])) {
+ /* Execute BeforeLinkTraining script from DP Info table. */
+ while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
+ lnkcmp += 3;
+ lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
+
+ nvbios_init(&outp->disp->engine.subdev, lnkcmp,
+ init.outp = &outp->info;
+ init.or = ior->id;
+ init.link = ior->asy.link;
+ );
+ }
+
+ /* Set desired link configuration on the source. */
+ if ((lnkcmp = outp->dp.info.lnkcmp)) {
+ if (outp->dp.version < 0x30) {
+ while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp))
+ lnkcmp += 4;
+ lnkcmp = nvbios_rd16(bios, lnkcmp + 2);
+ } else {
+ while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
+ lnkcmp += 3;
+ lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
+ }
+
+ nvbios_init(subdev, lnkcmp,
+ init.outp = &outp->info;
+ init.or = ior->id;
+ init.link = ior->asy.link;
+ );
+ }
+
+ ret = ior->func->dp->links(ior, outp->dp.aux);
+ if (ret) {
+ if (ret < 0) {
+ OUTP_ERR(outp, "train failed with %d", ret);
+ return ret;
+ }
+ return 0;
+ }
+
+ ior->func->dp->power(ior, ior->dp.nr);
+
+ /* Attempt to train the link in this configuration. */
+ return nvkm_dp_train_link(outp, rate);
+}
+
static void
nvkm_dp_train_fini(struct nvkm_outp *outp)
{
@@ -439,6 +451,16 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
int ret = -EINVAL, nr, rate;
u8 pwr;
+ /* Retraining link? Skip source configuration, it can mess up the active modeset. */
+ if (atomic_read(&outp->dp.lt.done)) {
+ for (rate = 0; rate < outp->dp.rates; rate++) {
+ if (outp->dp.rate[rate].rate == ior->dp.bw * 27000)
+ return nvkm_dp_train_link(outp, ret);
+ }
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
/* Ensure sink is not in a low-power state. */
if (!nvkm_rdaux(outp->dp.aux, DPCD_SC00, &pwr, 1)) {
if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
@@ -455,6 +477,21 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
/* Link training. */
OUTP_DBG(outp, "training");
nvkm_dp_train_init(outp);
+
+ /* Validate and train at configuration requested (if any) on ACQUIRE. */
+ if (outp->dp.lt.nr) {
+ for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
+ for (rate = 0; nr == outp->dp.lt.nr && rate < outp->dp.rates; rate++) {
+ if (outp->dp.rate[rate].rate / 27000 == outp->dp.lt.bw) {
+ ior->dp.bw = outp->dp.rate[rate].rate / 27000;
+ ior->dp.nr = nr;
+ ret = nvkm_dp_train_links(outp, rate);
+ }
+ }
+ }
+ }
+
+ /* Otherwise, loop through all valid link configurations that support the data rate. */
for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) {
if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
@@ -465,6 +502,8 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
}
}
}
+
+ /* Finish up. */
nvkm_dp_train_fini(outp);
if (ret < 0)
OUTP_ERR(outp, "training failed");
@@ -595,18 +634,38 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp)
return outp->dp.rates != 0;
}
-static bool
-nvkm_dp_enable(struct nvkm_outp *outp, bool enable)
+void
+nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
{
+ struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
struct nvkm_i2c_aux *aux = outp->dp.aux;
- if (enable) {
- if (!outp->dp.present) {
- OUTP_DBG(outp, "aux power -> always");
- nvkm_i2c_aux_monitor(aux, true);
- outp->dp.present = true;
+ if (auxpwr && !outp->dp.aux_pwr) {
+ /* eDP panels need powering on by us (if the VBIOS doesn't default it
+ * to on) before doing any AUX channel transactions. LVDS panel power
+ * is handled by the SOR itself, and not required for LVDS DDC.
+ */
+ if (outp->conn->info.type == DCB_CONNECTOR_eDP) {
+ int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
+ if (power == 0) {
+ nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
+ outp->dp.aux_pwr_pu = true;
+ }
+
+ /* We delay here unconditionally, even if already powered,
+ * because some laptop panels having a significant resume
+ * delay before the panel begins responding.
+ *
+ * This is likely a bit of a hack, but no better idea for
+ * handling this at the moment.
+ */
+ msleep(300);
}
+ OUTP_DBG(outp, "aux power -> always");
+ nvkm_i2c_aux_monitor(aux, true);
+ outp->dp.aux_pwr = true;
+
/* Detect any LTTPRs before reading DPCD receiver caps. */
if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, outp->dp.lttpr, sizeof(outp->dp.lttpr)) &&
outp->dp.lttpr[0] >= 0x14 && outp->dp.lttpr[2]) {
@@ -659,96 +718,41 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool enable)
outp->dp.rates++;
}
}
-
- return true;
}
- }
-
- if (outp->dp.present) {
+ } else
+ if (!auxpwr && outp->dp.aux_pwr) {
OUTP_DBG(outp, "aux power -> demand");
nvkm_i2c_aux_monitor(aux, false);
- outp->dp.present = false;
- }
-
- atomic_set(&outp->dp.lt.done, 0);
- return false;
-}
-
-static int
-nvkm_dp_hpd(struct nvkm_notify *notify)
-{
- const struct nvkm_i2c_ntfy_rep *line = notify->data;
- struct nvkm_outp *outp = container_of(notify, typeof(*outp), dp.hpd);
- struct nvkm_conn *conn = outp->conn;
- struct nvkm_disp *disp = outp->disp;
- struct nvif_notify_conn_rep_v0 rep = {};
+ outp->dp.aux_pwr = false;
+ atomic_set(&outp->dp.lt.done, 0);
- OUTP_DBG(outp, "HPD: %d", line->mask);
- if (line->mask & NVKM_I2C_IRQ) {
- if (atomic_read(&outp->dp.lt.done))
- outp->func->acquire(outp);
- rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ;
- } else {
- nvkm_dp_enable(outp, true);
+ /* Restore eDP panel GPIO to its prior state if we changed it, as
+ * it could potentially interfere with other outputs.
+ */
+ if (outp->conn->info.type == DCB_CONNECTOR_eDP) {
+ if (outp->dp.aux_pwr_pu) {
+ nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0);
+ outp->dp.aux_pwr_pu = false;
+ }
+ }
}
-
- if (line->mask & NVKM_I2C_UNPLUG)
- rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
- if (line->mask & NVKM_I2C_PLUG)
- rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
-
- nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
- return NVKM_NOTIFY_KEEP;
}
static void
nvkm_dp_fini(struct nvkm_outp *outp)
{
- nvkm_notify_put(&outp->dp.hpd);
nvkm_dp_enable(outp, false);
}
static void
nvkm_dp_init(struct nvkm_outp *outp)
{
- struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
-
- nvkm_notify_put(&outp->conn->hpd);
-
- /* eDP panels need powering on by us (if the VBIOS doesn't default it
- * to on) before doing any AUX channel transactions. LVDS panel power
- * is handled by the SOR itself, and not required for LVDS DDC.
- */
- if (outp->conn->info.type == DCB_CONNECTOR_eDP) {
- int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
- if (power == 0)
- nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
-
- /* We delay here unconditionally, even if already powered,
- * because some laptop panels having a significant resume
- * delay before the panel begins responding.
- *
- * This is likely a bit of a hack, but no better idea for
- * handling this at the moment.
- */
- msleep(300);
-
- /* If the eDP panel can't be detected, we need to restore
- * the panel power GPIO to avoid breaking another output.
- */
- if (!nvkm_dp_enable(outp, true) && power == 0)
- nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0);
- } else {
- nvkm_dp_enable(outp, true);
- }
-
- nvkm_notify_get(&outp->dp.hpd);
+ nvkm_dp_enable(outp, outp->dp.enabled);
}
static void *
nvkm_dp_dtor(struct nvkm_outp *outp)
{
- nvkm_notify_fini(&outp->dp.hpd);
return outp;
}
@@ -797,21 +801,6 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n
OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, cnt, len);
- /* hotplug detect, replaces gpio-based mechanism with aux events */
- ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true,
- &(struct nvkm_i2c_ntfy_req) {
- .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG |
- NVKM_I2C_IRQ,
- .port = outp->dp.aux->id,
- },
- sizeof(struct nvkm_i2c_ntfy_req),
- sizeof(struct nvkm_i2c_ntfy_rep),
- &outp->dp.hpd);
- if (ret) {
- OUTP_ERR(outp, "error monitoring aux hpd: %d", ret);
- return ret;
- }
-
mutex_init(&outp->dp.mutex);
atomic_set(&outp->dp.lt.done, 0);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
index 1d86baa6a424..9a6be43916bc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
@@ -6,6 +6,7 @@
int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *,
struct nvkm_outp **);
void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
+void nvkm_dp_enable(struct nvkm_outp *, bool auxpwr);
/* DPCD Receiver Capabilities */
#define DPCD_RC00_DPCD_REV 0x00000
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
index 4966a51af3d7..23ae451ba473 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -29,9 +29,54 @@
#include <nvif/class.h>
-void
-g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
- u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
+static void
+g84_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe vsi;
+ const u32 hoff = head * 0x800;
+
+ nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000);
+ if (!size)
+ return;
+
+ pack_hdmi_infoframe(&vsi, data, size);
+
+ nvkm_wr32(device, 0x616544 + hoff, vsi.header);
+ nvkm_wr32(device, 0x616548 + hoff, vsi.subpack0_low);
+ nvkm_wr32(device, 0x61654c + hoff, vsi.subpack0_high);
+ /* Is there a second (or up to fourth?) set of subpack registers here? */
+ /* nvkm_wr32(device, 0x616550 + hoff, vsi.subpack1_low); */
+ /* nvkm_wr32(device, 0x616554 + hoff, vsi.subpack1_high); */
+
+ nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001);
+}
+
+static void
+g84_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe avi;
+ const u32 hoff = head * 0x800;
+
+ pack_hdmi_infoframe(&avi, data, size);
+
+ nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x616528 + hoff, avi.header);
+ nvkm_wr32(device, 0x61652c + hoff, avi.subpack0_low);
+ nvkm_wr32(device, 0x616530 + hoff, avi.subpack0_high);
+ nvkm_wr32(device, 0x616534 + hoff, avi.subpack1_low);
+ nvkm_wr32(device, 0x616538 + hoff, avi.subpack1_high);
+
+ nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
+}
+
+
+static void
+g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
@@ -39,31 +84,13 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
- struct packed_hdmi_infoframe avi_infoframe;
- struct packed_hdmi_infoframe vendor_infoframe;
-
- pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
- pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000);
- nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000);
- nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
return;
}
- /* AVI InfoFrame */
- nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
- if (avi_size) {
- nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header);
- nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low);
- nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high);
- nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low);
- nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high);
- nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
- }
-
/* Audio InfoFrame */
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x616508 + hoff, 0x000a0184);
@@ -71,17 +98,6 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
nvkm_wr32(device, 0x616510 + hoff, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001);
- /* Vendor InfoFrame */
- nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000);
- if (vendor_size) {
- nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header);
- nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low);
- nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high);
- /* Is there a second (or up to fourth?) set of subpack registers here? */
- /* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */
- /* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */
- nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001);
- }
nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
@@ -96,14 +112,19 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
}
+const struct nvkm_ior_func_hdmi
+g84_sor_hdmi = {
+ .ctrl = g84_sor_hdmi_ctrl,
+ .infoframe_avi = g84_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = g84_sor_hdmi_infoframe_vsi,
+};
+
static const struct nvkm_ior_func
g84_sor = {
.state = nv50_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
- .hdmi = {
- .ctrl = g84_sor_hdmi_ctrl,
- },
+ .hdmi = &g84_sor_hdmi,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
index 7489d0d7fce0..52099b75f52a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
@@ -105,10 +105,7 @@ ga102_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = ga102_sor_clock,
- .hdmi = {
- .ctrl = gv100_sor_hdmi_ctrl,
- .scdc = gm200_sor_hdmi_scdc,
- },
+ .hdmi = &gv100_sor_hdmi,
.dp = &ga102_sor_dp,
.hda = &gv100_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 39822f1b5b95..a48e9bdf4cd0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -202,19 +202,61 @@ gf119_sor_dp = {
};
static void
-gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
- u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
+gf119_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe vsi;
+ const u32 hoff = head * 0x800;
+
+ pack_hdmi_infoframe(&vsi, data, size);
+
+ nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000);
+ if (!size)
+ return;
+
+ /*
+ * These appear to be the audio infoframe registers,
+ * but no other set of infoframe registers has yet
+ * been found.
+ */
+ nvkm_wr32(device, 0x616738 + hoff, vsi.header);
+ nvkm_wr32(device, 0x61673c + hoff, vsi.subpack0_low);
+ nvkm_wr32(device, 0x616740 + hoff, vsi.subpack0_high);
+ /* Is there a second (or further?) set of subpack registers here? */
+
+ nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001);
+}
+
+static void
+gf119_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe avi;
+ const u32 hoff = head * 0x800;
+
+ pack_hdmi_infoframe(&avi, data, size);
+
+ nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x61671c + hoff, avi.header);
+ nvkm_wr32(device, 0x616720 + hoff, avi.subpack0_low);
+ nvkm_wr32(device, 0x616724 + hoff, avi.subpack0_high);
+ nvkm_wr32(device, 0x616728 + hoff, avi.subpack1_low);
+ nvkm_wr32(device, 0x61672c + hoff, avi.subpack1_high);
+
+ nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001);
+}
+
+static void
+gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
- struct packed_hdmi_infoframe avi_infoframe;
- struct packed_hdmi_infoframe vendor_infoframe;
-
- pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
- pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000);
@@ -224,32 +266,6 @@ gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
return;
}
- /* AVI InfoFrame */
- nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
- if (avi_size) {
- nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header);
- nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low);
- nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high);
- nvkm_wr32(device, 0x616728 + hoff, avi_infoframe.subpack1_low);
- nvkm_wr32(device, 0x61672c + hoff, avi_infoframe.subpack1_high);
- nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001);
- }
-
- /* GENERIC(?) / Vendor InfoFrame? */
- nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000);
- if (vendor_size) {
- /*
- * These appear to be the audio infoframe registers,
- * but no other set of infoframe registers has yet
- * been found.
- */
- nvkm_wr32(device, 0x616738 + hoff, vendor_infoframe.header);
- nvkm_wr32(device, 0x61673c + hoff, vendor_infoframe.subpack0_low);
- nvkm_wr32(device, 0x616740 + hoff, vendor_infoframe.subpack0_high);
- /* Is there a second (or further?) set of subpack registers here? */
- nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001);
- }
-
/* ??? InfoFrame? */
nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6167ac + hoff, 0x00000010);
@@ -259,6 +275,13 @@ gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
}
+static const struct nvkm_ior_func_hdmi
+gf119_sor_hdmi = {
+ .ctrl = gf119_sor_hdmi_ctrl,
+ .infoframe_avi = gf119_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gf119_sor_hdmi_infoframe_vsi,
+};
+
void
gf119_sor_clock(struct nvkm_ior *sor)
{
@@ -305,9 +328,7 @@ gf119_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gf119_sor_hdmi_ctrl,
- },
+ .hdmi = &gf119_sor_hdmi,
.dp = &gf119_sor_dp,
.hda = &gf119_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
index 7248e9ec835e..876a21a0cebb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -30,8 +30,51 @@
#include <nvif/class.h>
void
-gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
- u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
+gk104_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe vsi;
+ const u32 hoff = head * 0x400;
+
+ pack_hdmi_infoframe(&vsi, data, size);
+
+ /* GENERIC(?) / Vendor InfoFrame? */
+ nvkm_mask(device, 0x690100 + hoff, 0x00010001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x690108 + hoff, vsi.header);
+ nvkm_wr32(device, 0x69010c + hoff, vsi.subpack0_low);
+ nvkm_wr32(device, 0x690110 + hoff, vsi.subpack0_high);
+ /* Is there a second (or further?) set of subpack registers here? */
+ nvkm_mask(device, 0x690100 + hoff, 0x00000001, 0x00000001);
+}
+
+void
+gk104_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe avi;
+ const u32 hoff = head * 0x400;
+
+ pack_hdmi_infoframe(&avi, data, size);
+
+ /* AVI InfoFrame */
+ nvkm_mask(device, 0x690000 + hoff, 0x00000001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x690008 + hoff, avi.header);
+ nvkm_wr32(device, 0x69000c + hoff, avi.subpack0_low);
+ nvkm_wr32(device, 0x690010 + hoff, avi.subpack0_high);
+ nvkm_wr32(device, 0x690014 + hoff, avi.subpack1_low);
+ nvkm_wr32(device, 0x690018 + hoff, avi.subpack1_high);
+
+ nvkm_mask(device, 0x690000 + hoff, 0x00000001, 0x00000001);
+}
+
+void
+gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
@@ -39,11 +82,6 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
rekey;
const u32 hoff = head * 0x800;
const u32 hdmi = head * 0x400;
- struct packed_hdmi_infoframe avi_infoframe;
- struct packed_hdmi_infoframe vendor_infoframe;
-
- pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
- pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000);
@@ -53,28 +91,6 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
return;
}
- /* AVI InfoFrame */
- nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
- if (avi_size) {
- nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header);
- nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low);
- nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high);
- nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low);
- nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high);
- nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001);
- }
-
- /* GENERIC(?) / Vendor InfoFrame? */
- nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000);
- if (vendor_size) {
- nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header);
- nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low);
- nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high);
- /* Is there a second (or further?) set of subpack registers here? */
- nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001);
- }
-
-
/* ??? InfoFrame? */
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010);
@@ -87,14 +103,19 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
}
+const struct nvkm_ior_func_hdmi
+gk104_sor_hdmi = {
+ .ctrl = gk104_sor_hdmi_ctrl,
+ .infoframe_avi = gk104_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gk104_sor_hdmi_infoframe_vsi,
+};
+
static const struct nvkm_ior_func
gk104_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gk104_sor_hdmi_ctrl,
- },
+ .hdmi = &gk104_sor_hdmi,
.dp = &gf119_sor_dp,
.hda = &gf119_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
index 9e9ef49bd8ac..b4d8e868616f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -70,9 +70,7 @@ gm107_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gk104_sor_hdmi_ctrl,
- },
+ .hdmi = &gk104_sor_hdmi,
.dp = &gm107_sor_dp,
.hda = &gf119_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
index 4ecc8f98af6e..562ebae57d44 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
@@ -79,6 +79,14 @@ gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
ior->tmds.high_speed = !!(scdc & 0x2);
}
+const struct nvkm_ior_func_hdmi
+gm200_sor_hdmi = {
+ .ctrl = gk104_sor_hdmi_ctrl,
+ .scdc = gm200_sor_hdmi_scdc,
+ .infoframe_avi = gk104_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gk104_sor_hdmi_infoframe_vsi,
+};
+
void
gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior)
{
@@ -131,10 +139,7 @@ gm200_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gk104_sor_hdmi_ctrl,
- .scdc = gm200_sor_hdmi_scdc,
- },
+ .hdmi = &gm200_sor_hdmi,
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
index 7172a9dfd89b..7f1eb4332040 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
@@ -37,10 +37,7 @@ gp100_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gk104_sor_hdmi_ctrl,
- .scdc = gm200_sor_hdmi_scdc,
- },
+ .hdmi = &gm200_sor_hdmi,
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
index 70c49e7af9cf..a2c7c6f83dcd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -92,9 +92,53 @@ gt215_sor_dp = {
.watermark = g94_sor_dp_watermark,
};
-void
-gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
- u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
+static void
+gt215_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe vsi;
+ const u32 soff = nv50_ior_base(ior);
+
+ pack_hdmi_infoframe(&vsi, data, size);
+
+ nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x61c544 + soff, vsi.header);
+ nvkm_wr32(device, 0x61c548 + soff, vsi.subpack0_low);
+ nvkm_wr32(device, 0x61c54c + soff, vsi.subpack0_high);
+ /* Is there a second (or up to fourth?) set of subpack registers here? */
+ /* nvkm_wr32(device, 0x61c550 + soff, vsi.subpack1_low); */
+ /* nvkm_wr32(device, 0x61c554 + soff, vsi.subpack1_high); */
+
+ nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001);
+}
+
+static void
+gt215_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe avi;
+ const u32 soff = nv50_ior_base(ior);
+
+ pack_hdmi_infoframe(&avi, data, size);
+
+ nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
+ if (size)
+ return;
+
+ nvkm_wr32(device, 0x61c528 + soff, avi.header);
+ nvkm_wr32(device, 0x61c52c + soff, avi.subpack0_low);
+ nvkm_wr32(device, 0x61c530 + soff, avi.subpack0_high);
+ nvkm_wr32(device, 0x61c534 + soff, avi.subpack1_low);
+ nvkm_wr32(device, 0x61c538 + soff, avi.subpack1_high);
+
+ nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001);
+}
+
+static void
+gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
@@ -102,11 +146,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
max_ac_packet << 16 |
rekey;
const u32 soff = nv50_ior_base(ior);
- struct packed_hdmi_infoframe avi_infoframe;
- struct packed_hdmi_infoframe vendor_infoframe;
-
- pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
- pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000);
@@ -116,17 +155,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
return;
}
- /* AVI InfoFrame */
- nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
- if (avi_size) {
- nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header);
- nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low);
- nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high);
- nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low);
- nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high);
- nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001);
- }
-
/* Audio InfoFrame */
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x61c508 + soff, 0x000a0184);
@@ -134,18 +162,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
nvkm_wr32(device, 0x61c510 + soff, 0x00000000);
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001);
- /* Vendor InfoFrame */
- nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000);
- if (vendor_size) {
- nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header);
- nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low);
- nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high);
- /* Is there a second (or up to fourth?) set of subpack registers here? */
- /* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */
- /* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */
- nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001);
- }
-
nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
@@ -159,14 +175,19 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
}
+const struct nvkm_ior_func_hdmi
+gt215_sor_hdmi = {
+ .ctrl = gt215_sor_hdmi_ctrl,
+ .infoframe_avi = gt215_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gt215_sor_hdmi_infoframe_vsi,
+};
+
static const struct nvkm_ior_func
gt215_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
- .hdmi = {
- .ctrl = gt215_sor_hdmi_ctrl,
- },
+ .hdmi = &gt215_sor_hdmi,
.dp = &gt215_sor_dp,
.hda = &gt215_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
index 6b9d49270fa7..115d0997fd62 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
@@ -96,9 +96,54 @@ gv100_sor_dp = {
.watermark = gv100_sor_dp_watermark,
};
-void
-gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
- u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
+static void
+gv100_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe vsi;
+ const u32 hoff = head * 0x400;
+
+ pack_hdmi_infoframe(&vsi, data, size);
+
+ nvkm_mask(device, 0x6f0100 + hoff, 0x00010001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x6f0108 + hoff, vsi.header);
+ nvkm_wr32(device, 0x6f010c + hoff, vsi.subpack0_low);
+ nvkm_wr32(device, 0x6f0110 + hoff, vsi.subpack0_high);
+ nvkm_wr32(device, 0x6f0114 + hoff, 0x00000000);
+ nvkm_wr32(device, 0x6f0118 + hoff, 0x00000000);
+ nvkm_wr32(device, 0x6f011c + hoff, 0x00000000);
+ nvkm_wr32(device, 0x6f0120 + hoff, 0x00000000);
+ nvkm_wr32(device, 0x6f0124 + hoff, 0x00000000);
+ nvkm_mask(device, 0x6f0100 + hoff, 0x00000001, 0x00000001);
+}
+
+static void
+gv100_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size)
+{
+ struct nvkm_device *device = ior->disp->engine.subdev.device;
+ struct packed_hdmi_infoframe avi;
+ const u32 hoff = head * 0x400;
+
+ pack_hdmi_infoframe(&avi, data, size);
+
+ nvkm_mask(device, 0x6f0000 + hoff, 0x00000001, 0x00000000);
+ if (!size)
+ return;
+
+ nvkm_wr32(device, 0x6f0008 + hoff, avi.header);
+ nvkm_wr32(device, 0x6f000c + hoff, avi.subpack0_low);
+ nvkm_wr32(device, 0x6f0010 + hoff, avi.subpack0_high);
+ nvkm_wr32(device, 0x6f0014 + hoff, avi.subpack1_low);
+ nvkm_wr32(device, 0x6f0018 + hoff, avi.subpack1_high);
+
+ nvkm_mask(device, 0x6f0000 + hoff, 0x00000001, 0x00000001);
+}
+
+static void
+gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
@@ -106,11 +151,6 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
rekey;
const u32 hoff = head * 0x800;
const u32 hdmi = head * 0x400;
- struct packed_hdmi_infoframe avi_infoframe;
- struct packed_hdmi_infoframe vendor_infoframe;
-
- pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
- pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x6165c0 + hoff, 0x40000000, 0x00000000);
@@ -120,32 +160,6 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
return;
}
- /* AVI InfoFrame (AVI). */
- nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000000);
- if (avi_size) {
- nvkm_wr32(device, 0x6f0008 + hdmi, avi_infoframe.header);
- nvkm_wr32(device, 0x6f000c + hdmi, avi_infoframe.subpack0_low);
- nvkm_wr32(device, 0x6f0010 + hdmi, avi_infoframe.subpack0_high);
- nvkm_wr32(device, 0x6f0014 + hdmi, avi_infoframe.subpack1_low);
- nvkm_wr32(device, 0x6f0018 + hdmi, avi_infoframe.subpack1_high);
- nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000001);
- }
-
- /* Vendor-specific InfoFrame (VSI). */
- nvkm_mask(device, 0x6f0100 + hdmi, 0x00010001, 0x00000000);
- if (vendor_size) {
- nvkm_wr32(device, 0x6f0108 + hdmi, vendor_infoframe.header);
- nvkm_wr32(device, 0x6f010c + hdmi, vendor_infoframe.subpack0_low);
- nvkm_wr32(device, 0x6f0110 + hdmi, vendor_infoframe.subpack0_high);
- nvkm_wr32(device, 0x6f0114 + hdmi, 0x00000000);
- nvkm_wr32(device, 0x6f0118 + hdmi, 0x00000000);
- nvkm_wr32(device, 0x6f011c + hdmi, 0x00000000);
- nvkm_wr32(device, 0x6f0120 + hdmi, 0x00000000);
- nvkm_wr32(device, 0x6f0124 + hdmi, 0x00000000);
- nvkm_mask(device, 0x6f0100 + hdmi, 0x00000001, 0x00000001);
- }
-
-
/* General Control (GCP). */
nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6f00cc + hdmi, 0x00000010);
@@ -158,6 +172,14 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe
nvkm_mask(device, 0x6165c0 + hoff, 0x401f007f, ctrl);
}
+const struct nvkm_ior_func_hdmi
+gv100_sor_hdmi = {
+ .ctrl = gv100_sor_hdmi_ctrl,
+ .scdc = gm200_sor_hdmi_scdc,
+ .infoframe_avi = gv100_sor_hdmi_infoframe_avi,
+ .infoframe_vsi = gv100_sor_hdmi_infoframe_vsi,
+};
+
void
gv100_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
{
@@ -190,10 +212,7 @@ gv100_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gv100_sor_hdmi_ctrl,
- .scdc = gm200_sor_hdmi_scdc,
- },
+ .hdmi = &gv100_sor_hdmi,
.dp = &gv100_sor_dp,
.hda = &gv100_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
index 83152c26fe3e..7f5d13d13c94 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
@@ -39,44 +39,6 @@ nvkm_head_find(struct nvkm_disp *disp, int id)
return NULL;
}
-int
-nvkm_head_mthd_scanoutpos(struct nvkm_object *object,
- struct nvkm_head *head, void *data, u32 size)
-{
- union {
- struct nv04_disp_scanoutpos_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "head scanoutpos size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "head scanoutpos vers %d\n",
- args->v0.version);
-
- head->func->state(head, &head->arm);
- args->v0.vtotal = head->arm.vtotal;
- args->v0.vblanks = head->arm.vblanks;
- args->v0.vblanke = head->arm.vblanke;
- args->v0.htotal = head->arm.htotal;
- args->v0.hblanks = head->arm.hblanks;
- args->v0.hblanke = head->arm.hblanke;
-
- /* We don't support reading htotal/vtotal on pre-NV50 VGA,
- * so we have to give up and trigger the timestamping
- * fallback in the drm core.
- */
- if (!args->v0.vtotal || !args->v0.htotal)
- return -ENOTSUPP;
-
- args->v0.time[0] = ktime_to_ns(ktime_get());
- head->func->rgpos(head, &args->v0.hline, &args->v0.vline);
- args->v0.time[1] = ktime_to_ns(ktime_get());
- } else
- return ret;
-
- return 0;
-}
-
void
nvkm_head_del(struct nvkm_head **phead)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
index 84a2989193cf..856252bf559a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_HEAD_H__
#define __NVKM_DISP_HEAD_H__
+#include <nvif/object.h>
#include "priv.h"
struct nvkm_head {
@@ -26,12 +27,12 @@ struct nvkm_head {
u8 depth;
} or;
} arm, asy;
+
+ struct nvkm_object object;
};
int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id);
void nvkm_head_del(struct nvkm_head **);
-int nvkm_head_mthd_scanoutpos(struct nvkm_object *,
- struct nvkm_head *, void *, u32);
struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id);
struct nvkm_head_func {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
index 671c4674ffcc..da1b1a626ef2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -63,12 +63,12 @@ struct nvkm_ior_func {
void (*war_2)(struct nvkm_ior *);
void (*war_3)(struct nvkm_ior *);
- struct {
- void (*ctrl)(struct nvkm_ior *, int head, bool enable,
- u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size,
- u8 *vendor, u8 vendor_size);
+ const struct nvkm_ior_func_hdmi {
+ void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey);
void (*scdc)(struct nvkm_ior *, u8 scdc);
- } hdmi;
+ void (*infoframe_avi)(struct nvkm_ior *, int head, void *data, u32 size);
+ void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size);
+ } *hdmi;
const struct nvkm_ior_func_dp {
u8 lanes[4];
@@ -124,9 +124,10 @@ void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
void nv50_sor_clock(struct nvkm_ior *);
int g84_sor_new(struct nvkm_disp *, int);
-void g84_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
+extern const struct nvkm_ior_func_hdmi g84_sor_hdmi;
int g94_sor_cnt(struct nvkm_disp *, unsigned long *);
+
void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
extern const struct nvkm_ior_func_dp g94_sor_dp;
int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *);
@@ -137,7 +138,7 @@ void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8);
void g94_sor_dp_watermark(struct nvkm_ior *, int, u8);
-void gt215_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
+extern const struct nvkm_ior_func_hdmi gt215_sor_hdmi;
void gt215_sor_dp_audio(struct nvkm_ior *, int, bool);
extern const struct nvkm_ior_func_hda gt215_sor_hda;
@@ -156,12 +157,16 @@ void gf119_sor_hda_hpd(struct nvkm_ior *, int, bool);
void gf119_sor_hda_eld(struct nvkm_ior *, int, u8 *, u8);
int gk104_sor_new(struct nvkm_disp *, int);
-void gk104_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
+extern const struct nvkm_ior_func_hdmi gk104_sor_hdmi;
+void gk104_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8);
+void gk104_sor_hdmi_infoframe_avi(struct nvkm_ior *, int, void *, u32);
+void gk104_sor_hdmi_infoframe_vsi(struct nvkm_ior *, int, void *, u32);
void gm107_sor_dp_pattern(struct nvkm_ior *, int);
void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *);
int gm200_sor_route_get(struct nvkm_outp *, int *);
+extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi;
void gm200_sor_hdmi_scdc(struct nvkm_ior *, u8);
extern const struct nvkm_ior_func_dp gm200_sor_dp;
void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);
@@ -170,7 +175,7 @@ int gp100_sor_new(struct nvkm_disp *, int);
int gv100_sor_cnt(struct nvkm_disp *, unsigned long *);
void gv100_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
-void gv100_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
+extern const struct nvkm_ior_func_hdmi gv100_sor_hdmi;
void gv100_sor_dp_audio(struct nvkm_ior *, int, bool);
void gv100_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
void gv100_sor_dp_watermark(struct nvkm_ior *, int, u8);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
index 916b1d477b0b..841e3b69fcaf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
@@ -31,9 +31,7 @@ mcp77_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
- .hdmi = {
- .ctrl = g84_sor_hdmi_ctrl,
- },
+ .hdmi = &g84_sor_hdmi,
.dp = &g94_sor_dp,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
index a5a0b9439374..f96ba4752655 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
@@ -44,9 +44,7 @@ mcp89_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
- .hdmi = {
- .ctrl = gt215_sor_hdmi_ctrl,
- },
+ .hdmi = &gt215_sor_hdmi,
.dp = &mcp89_sor_dp,
.hda = &gt215_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index a46e13cc9ff1..be8116802960 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -503,7 +503,7 @@ nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
void
nv50_disp_chan_uevent_send(struct nvkm_disp *disp, int chid)
{
- nvkm_event_send(&disp->uevent, NVKM_DISP_EVENT_CHAN_AWAKEN, chid, NULL, 0);
+ nvkm_event_ntfy(&disp->uevent, chid, NVKM_DISP_EVENT_CHAN_AWAKEN);
}
const struct nvkm_event_func
@@ -1238,6 +1238,8 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head)
if (!ior)
return;
+ outp = ior->asy.outp;
+
/* For some reason, NVIDIA decided not to:
*
* A) Give dual-link LVDS a separate EVO protocol, like for TMDS.
@@ -1247,13 +1249,13 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head)
* Override the values we usually read from HW with the same
* data we pass though an ioctl instead.
*/
- if (ior->type == SOR && ior->asy.proto == LVDS) {
- head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18;
- ior->asy.link = (disp->sor.lvdsconf & 0x0100) ? 3 : 1;
+ if (outp && ior->type == SOR && ior->asy.proto == LVDS) {
+ head->asy.or.depth = outp->lvds.bpc8 ? 24 : 18;
+ ior->asy.link = outp->lvds.dual ? 3 : 1;
}
/* Handle any link training, etc. */
- if ((outp = ior->asy.outp) && outp->func->acquire)
+ if (outp && outp->func->acquire)
outp->func->acquire(outp);
/* Execute OnInt2 IED script. */
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 3f3924c41957..b7631c1ab242 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -2,7 +2,6 @@
#ifndef __NVKM_DISP_OUTP_H__
#define __NVKM_DISP_OUTP_H__
#include "priv.h"
-#include <core/notify.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@@ -28,13 +27,19 @@ struct nvkm_outp {
union {
struct {
+ bool dual;
+ bool bpc8;
+ } lvds;
+
+ struct {
struct nvbios_dpout info;
u8 version;
struct nvkm_i2c_aux *aux;
- struct nvkm_notify hpd;
- bool present;
+ bool enabled;
+ bool aux_pwr;
+ bool aux_pwr_pu;
u8 lttpr[6];
u8 lttprs;
u8 dpcd[16];
@@ -49,12 +54,17 @@ struct nvkm_outp {
struct mutex mutex;
struct {
atomic_t done;
+ u8 nr;
+ u8 bw;
bool mst;
} lt;
} dp;
};
struct nvkm_object object;
+ struct {
+ struct nvkm_head *head;
+ } asy;
};
int nvkm_outp_new_(const struct nvkm_outp_func *, struct nvkm_disp *, int index,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
index cb25dfe849f0..ec5292a8f3c8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -42,10 +42,6 @@ struct nvkm_disp_func {
} user[];
};
-int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
-int nv04_disp_mthd(struct nvkm_object *, u32, void *, u32);
-int nv50_disp_root_mthd_(struct nvkm_object *, u32, void *, u32);
-
int nv50_disp_oneinit(struct nvkm_disp *);
int nv50_disp_init(struct nvkm_disp *);
void nv50_disp_fini(struct nvkm_disp *);
@@ -86,4 +82,5 @@ extern const struct nvkm_event_func gv100_disp_chan_uevent;
int nvkm_udisp_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
int nvkm_uconn_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
int nvkm_uoutp_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
+int nvkm_uhead_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
deleted file mode 100644
index 0af45ccd140c..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "chan.h"
-#include "head.h"
-#include "ior.h"
-#include "outp.h"
-
-#include <core/client.h>
-
-#include <nvif/class.h>
-#include <nvif/cl5070.h>
-#include <nvif/unpack.h>
-
-int
-nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
-{
- union {
- struct nv50_disp_mthd_v0 v0;
- struct nv50_disp_mthd_v1 v1;
- } *args = data;
- struct nvkm_disp *disp = nvkm_udisp(object);
- struct nvkm_outp *temp, *outp = NULL;
- struct nvkm_head *head;
- u16 type, mask = 0;
- int hidx, ret = -ENOSYS;
-
- if (mthd != NV50_DISP_MTHD)
- return -EINVAL;
-
- nvif_ioctl(object, "disp mthd size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
- nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
- args->v0.version, args->v0.method, args->v0.head);
- mthd = args->v0.method;
- hidx = args->v0.head;
- } else
- if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
- nvif_ioctl(object, "disp mthd vers %d mthd %02x "
- "type %04x mask %04x\n",
- args->v1.version, args->v1.method,
- args->v1.hasht, args->v1.hashm);
- mthd = args->v1.method;
- type = args->v1.hasht;
- mask = args->v1.hashm;
- hidx = ffs((mask >> 8) & 0x0f) - 1;
- } else
- return ret;
-
- if (!(head = nvkm_head_find(disp, hidx)))
- return -ENXIO;
-
- if (mask) {
- list_for_each_entry(temp, &disp->outps, head) {
- if ((temp->info.hasht == type) &&
- (temp->info.hashm & mask) == mask) {
- outp = temp;
- break;
- }
- }
- if (outp == NULL)
- return -ENXIO;
- }
-
- switch (mthd) {
- case NV50_DISP_SCANOUTPOS: {
- return nvkm_head_mthd_scanoutpos(object, head, data, size);
- }
- default:
- break;
- }
-
- switch (mthd * !!outp) {
- case NV50_DISP_MTHD_V1_ACQUIRE: {
- union {
- struct nv50_disp_acquire_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, args->v0.hda);
- if (ret == 0) {
- args->v0.or = outp->ior->id;
- args->v0.link = outp->ior->asy.link;
- }
- }
- return ret;
- }
- break;
- case NV50_DISP_MTHD_V1_RELEASE:
- nvkm_outp_release(outp, NVKM_OUTP_USER);
- return 0;
- case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
- union {
- struct nv50_disp_sor_hda_eld_v0 v0;
- } *args = data;
- struct nvkm_ior *ior = outp->ior;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "disp sor hda eld size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
- nvif_ioctl(object, "disp sor hda eld vers %d\n",
- args->v0.version);
- if (size > 0x60)
- return -E2BIG;
- } else
- return ret;
-
- if (!ior->hda)
- return -ENODEV;
-
- if (size && args->v0.data[0]) {
- if (outp->info.type == DCB_OUTPUT_DP)
- ior->func->dp->audio(ior, hidx, true);
- ior->func->hda->hpd(ior, hidx, true);
- ior->func->hda->eld(ior, hidx, data, size);
- } else {
- if (outp->info.type == DCB_OUTPUT_DP)
- ior->func->dp->audio(ior, hidx, false);
- ior->func->hda->hpd(ior, hidx, false);
- }
-
- return 0;
- }
- break;
- case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: {
- union {
- struct nv50_disp_sor_hdmi_pwr_v0 v0;
- } *args = data;
- u8 *vendor, vendor_size;
- u8 *avi, avi_size;
- int ret = -ENOSYS;
-
- nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
- nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
- "max_ac_packet %d rekey %d scdc %d\n",
- args->v0.version, args->v0.state,
- args->v0.max_ac_packet, args->v0.rekey,
- args->v0.scdc);
- if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
- return -EINVAL;
- if ((args->v0.avi_infoframe_length
- + args->v0.vendor_infoframe_length) > size)
- return -EINVAL;
- else
- if ((args->v0.avi_infoframe_length
- + args->v0.vendor_infoframe_length) < size)
- return -E2BIG;
- avi = data;
- avi_size = args->v0.avi_infoframe_length;
- vendor = avi + avi_size;
- vendor_size = args->v0.vendor_infoframe_length;
- } else
- return ret;
-
- if (!outp->ior->func->hdmi.ctrl)
- return -ENODEV;
-
- outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state,
- args->v0.max_ac_packet,
- args->v0.rekey, avi, avi_size,
- vendor, vendor_size);
-
- if (outp->ior->func->hdmi.scdc)
- outp->ior->func->hdmi.scdc(outp->ior, args->v0.scdc);
-
- return 0;
- }
- break;
- case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
- union {
- struct nv50_disp_sor_lvds_script_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
- nvif_ioctl(object, "disp sor lvds script size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "disp sor lvds script "
- "vers %d name %04x\n",
- args->v0.version, args->v0.script);
- disp->sor.lvdsconf = args->v0.script;
- return 0;
- } else
- return ret;
- }
- break;
- case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
- union {
- struct nv50_disp_sor_dp_mst_link_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
- nvif_ioctl(object, "disp sor dp mst link size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
- args->v0.version, args->v0.state);
- outp->dp.lt.mst = !!args->v0.state;
- return 0;
- } else
- return ret;
- }
- break;
- case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
- union {
- struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
- nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(object, "disp sor dp mst vcpi vers %d "
- "slot %02x/%02x pbn %04x/%04x\n",
- args->v0.version, args->v0.start_slot,
- args->v0.num_slots, args->v0.pbn,
- args->v0.aligned_pbn);
- if (!outp->ior->func->dp->vcpi)
- return -ENODEV;
- outp->ior->func->dp->vcpi(outp->ior, hidx,
- args->v0.start_slot,
- args->v0.num_slots,
- args->v0.pbn,
- args->v0.aligned_pbn);
- return 0;
- } else
- return ret;
- }
- break;
- default:
- break;
- }
-
- return -EINVAL;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
index e4ad1a6f6c88..f5242a672279 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
@@ -88,10 +88,7 @@ tu102_sor = {
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
- .hdmi = {
- .ctrl = gv100_sor_hdmi_ctrl,
- .scdc = gm200_sor_hdmi_scdc,
- },
+ .hdmi = &gv100_sor_hdmi,
.dp = &tu102_sor_dp,
.hda = &gv100_sor_hda,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
index fd9f18144c26..dad942be6679 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
@@ -21,12 +21,86 @@
*/
#define nvkm_uconn(p) container_of((p), struct nvkm_conn, object)
#include "conn.h"
+#include "outp.h"
+#include <core/client.h>
+#include <core/event.h>
#include <subdev/gpio.h>
+#include <subdev/i2c.h>
#include <nvif/if0011.h>
static int
+nvkm_uconn_uevent_aux(struct nvkm_object *object, u64 token, u32 bits)
+{
+ union nvif_conn_event_args args;
+
+ args.v0.version = 0;
+ args.v0.types = 0;
+ if (bits & NVKM_I2C_PLUG)
+ args.v0.types |= NVIF_CONN_EVENT_V0_PLUG;
+ if (bits & NVKM_I2C_UNPLUG)
+ args.v0.types |= NVIF_CONN_EVENT_V0_UNPLUG;
+ if (bits & NVKM_I2C_IRQ)
+ args.v0.types |= NVIF_CONN_EVENT_V0_IRQ;
+
+ return object->client->event(token, &args, sizeof(args.v0));
+}
+
+static int
+nvkm_uconn_uevent_gpio(struct nvkm_object *object, u64 token, u32 bits)
+{
+ union nvif_conn_event_args args;
+
+ args.v0.version = 0;
+ args.v0.types = 0;
+ if (bits & NVKM_GPIO_HI)
+ args.v0.types |= NVIF_CONN_EVENT_V0_PLUG;
+ if (bits & NVKM_GPIO_LO)
+ args.v0.types |= NVIF_CONN_EVENT_V0_UNPLUG;
+
+ return object->client->event(token, &args, sizeof(args.v0));
+}
+
+static int
+nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
+{
+ struct nvkm_conn *conn = nvkm_uconn(object);
+ struct nvkm_device *device = conn->disp->engine.subdev.device;
+ struct nvkm_outp *outp;
+ union nvif_conn_event_args *args = argv;
+ u64 bits = 0;
+
+ if (!uevent) {
+ if (conn->info.hpd == DCB_GPIO_UNUSED)
+ return -ENOSYS;
+ return 0;
+ }
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ list_for_each_entry(outp, &conn->disp->outps, head) {
+ if (outp->info.connector == conn->index && outp->dp.aux) {
+ if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ;
+
+ return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits,
+ nvkm_uconn_uevent_aux);
+ }
+ }
+
+ if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_GPIO_HI;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO;
+ if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ)
+ return -EINVAL;
+
+ return nvkm_uevent_add(uevent, &device->gpio->event, conn->info.hpd, bits,
+ nvkm_uconn_uevent_gpio);
+}
+
+static int
nvkm_uconn_mthd_hpd_status(struct nvkm_conn *conn, void *argv, u32 argc)
{
struct nvkm_gpio *gpio = conn->disp->engine.subdev.device->gpio;
@@ -82,6 +156,7 @@ static const struct nvkm_object_func
nvkm_uconn = {
.dtor = nvkm_uconn_dtor,
.mthd = nvkm_uconn_mthd,
+ .uevent = nvkm_uconn_uevent,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
index 0841e7ce0343..0268d1d75805 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
@@ -21,6 +21,7 @@
*/
#include "priv.h"
#include "conn.h"
+#include "head.h"
#include "outp.h"
#include <nvif/class.h>
@@ -43,6 +44,12 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl
return 0;
}
+ if (index-- == 0) {
+ sclass->base = (struct nvkm_sclass) { 0, 0, NVIF_CLASS_HEAD };
+ sclass->ctor = nvkm_uhead_new;
+ return 0;
+ }
+
if (disp->func->user[index].ctor) {
sclass->base = disp->func->user[index].base;
sclass->ctor = disp->func->user[index].ctor;
@@ -52,17 +59,6 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl
return -EINVAL;
}
-static int
-nvkm_udisp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
-{
- struct nvkm_disp *disp = nvkm_udisp(object);
-
- if (disp->engine.subdev.device->card_type >= NV_50)
- return nv50_disp_root_mthd_(object, mthd, argv, argc);
-
- return nv04_disp_mthd(object, mthd, argv, argc);
-}
-
static void *
nvkm_udisp_dtor(struct nvkm_object *object)
{
@@ -78,8 +74,6 @@ nvkm_udisp_dtor(struct nvkm_object *object)
static const struct nvkm_object_func
nvkm_udisp = {
.dtor = nvkm_udisp_dtor,
- .mthd = nvkm_udisp_mthd,
- .ntfy = nvkm_disp_ntfy,
.sclass = nvkm_udisp_sclass,
};
@@ -89,6 +83,7 @@ nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv
struct nvkm_disp *disp = nvkm_disp(oclass->engine);
struct nvkm_conn *conn;
struct nvkm_outp *outp;
+ struct nvkm_head *head;
union nvif_disp_args *args = argv;
if (argc != sizeof(args->v0) || args->v0.version != 0)
@@ -111,5 +106,9 @@ nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv
list_for_each_entry(outp, &disp->outps, head)
args->v0.outp_mask |= BIT(outp->index);
+ args->v0.head_mask = 0;
+ list_for_each_entry(head, &disp->heads, head)
+ args->v0.head_mask |= BIT(head->id);
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c
new file mode 100644
index 000000000000..f072cec16040
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#define nvkm_uhead(p) container_of((p), struct nvkm_head, object)
+#include "head.h"
+#include <core/event.h>
+
+#include <nvif/if0013.h>
+
+#include <nvif/event.h>
+
+static int
+nvkm_uhead_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
+{
+ struct nvkm_head *head = nvkm_uhead(object);
+ union nvif_head_event_args *args = argv;
+
+ if (!uevent)
+ return 0;
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ return nvkm_uevent_add(uevent, &head->disp->vblank, head->id,
+ NVKM_DISP_HEAD_EVENT_VBLANK, NULL);
+}
+
+static int
+nvkm_uhead_mthd_scanoutpos(struct nvkm_head *head, void *argv, u32 argc)
+{
+ union nvif_head_scanoutpos_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ head->func->state(head, &head->arm);
+ args->v0.vtotal = head->arm.vtotal;
+ args->v0.vblanks = head->arm.vblanks;
+ args->v0.vblanke = head->arm.vblanke;
+ args->v0.htotal = head->arm.htotal;
+ args->v0.hblanks = head->arm.hblanks;
+ args->v0.hblanke = head->arm.hblanke;
+
+ /* We don't support reading htotal/vtotal on pre-NV50 VGA,
+ * so we have to give up and trigger the timestamping
+ * fallback in the drm core.
+ */
+ if (!args->v0.vtotal || !args->v0.htotal)
+ return -ENOTSUPP;
+
+ args->v0.time[0] = ktime_to_ns(ktime_get());
+ head->func->rgpos(head, &args->v0.hline, &args->v0.vline);
+ args->v0.time[1] = ktime_to_ns(ktime_get());
+ return 0;
+}
+
+static int
+nvkm_uhead_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
+{
+ struct nvkm_head *head = nvkm_uhead(object);
+
+ switch (mthd) {
+ case NVIF_HEAD_V0_SCANOUTPOS: return nvkm_uhead_mthd_scanoutpos(head, argv, argc);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void *
+nvkm_uhead_dtor(struct nvkm_object *object)
+{
+ struct nvkm_head *head = nvkm_uhead(object);
+ struct nvkm_disp *disp = head->disp;
+
+ spin_lock(&disp->client.lock);
+ head->object.func = NULL;
+ spin_unlock(&disp->client.lock);
+ return NULL;
+}
+
+static const struct nvkm_object_func
+nvkm_uhead = {
+ .dtor = nvkm_uhead_dtor,
+ .mthd = nvkm_uhead_mthd,
+ .uevent = nvkm_uhead_uevent,
+};
+
+int
+nvkm_uhead_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject)
+{
+ struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+ struct nvkm_head *head;
+ union nvif_head_args *args = argv;
+ int ret;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!(head = nvkm_head_find(disp, args->v0.id)))
+ return -EINVAL;
+
+ ret = -EBUSY;
+ spin_lock(&disp->client.lock);
+ if (!head->object.func) {
+ nvkm_object_ctor(&nvkm_uhead, oclass, &head->object);
+ *pobject = &head->object;
+ ret = 0;
+ }
+ spin_unlock(&disp->client.lock);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index abedb3e86361..4f0ca709c85a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -21,11 +21,238 @@
*/
#define nvkm_uoutp(p) container_of((p), struct nvkm_outp, object)
#include "outp.h"
+#include "dp.h"
+#include "head.h"
#include "ior.h"
#include <nvif/if0012.h>
static int
+nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ struct nvkm_ior *ior = outp->ior;
+ union nvif_outp_dp_mst_vcpi_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!ior->func->dp || !ior->func->dp->vcpi || !nvkm_head_find(outp->disp, args->v0.head))
+ return -EINVAL;
+
+ ior->func->dp->vcpi(ior, args->v0.head, args->v0.start_slot, args->v0.num_slots,
+ args->v0.pbn, args->v0.aligned_pbn);
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_retrain_args *args = argv;
+
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ if (!atomic_read(&outp->dp.lt.done))
+ return 0;
+
+ return outp->func->acquire(outp);
+}
+
+static int
+nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_dp_aux_pwr_args *args = argv;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ outp->dp.enabled = !!args->v0.state;
+ nvkm_dp_enable(outp, outp->dp.enabled);
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ struct nvkm_ior *ior = outp->ior;
+ union nvif_outp_hda_eld_args *args = argv;
+
+ if (argc < sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ argc -= sizeof(args->v0);
+
+ if (!ior->hda || !nvkm_head_find(outp->disp, args->v0.head))
+ return -EINVAL;
+ if (argc > 0x60)
+ return -E2BIG;
+
+ if (argc && args->v0.data[0]) {
+ if (outp->info.type == DCB_OUTPUT_DP)
+ ior->func->dp->audio(ior, args->v0.head, true);
+ ior->func->hda->hpd(ior, args->v0.head, true);
+ ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc);
+ } else {
+ if (outp->info.type == DCB_OUTPUT_DP)
+ ior->func->dp->audio(ior, args->v0.head, false);
+ ior->func->hda->hpd(ior, args->v0.head, false);
+ }
+
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ struct nvkm_ior *ior = outp->ior;
+ union nvif_outp_infoframe_args *args = argv;
+ ssize_t size = argc - sizeof(*args);
+
+ if (argc < sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (!nvkm_head_find(outp->disp, args->v0.head))
+ return -EINVAL;
+
+ switch (ior->func->hdmi ? args->v0.type : 0xff) {
+ case NVIF_OUTP_INFOFRAME_V0_AVI:
+ ior->func->hdmi->infoframe_avi(ior, args->v0.head, &args->v0.data, size);
+ return 0;
+ case NVIF_OUTP_INFOFRAME_V0_VSI:
+ ior->func->hdmi->infoframe_vsi(ior, args->v0.head, &args->v0.data, size);
+ return 0;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int
+nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ struct nvkm_head *head = outp->asy.head;
+ struct nvkm_ior *ior = outp->ior;
+ union nvif_outp_release_args *args = argv;
+
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ if (ior->func->hdmi && head) {
+ ior->func->hdmi->infoframe_avi(ior, head->id, NULL, 0);
+ ior->func->hdmi->infoframe_vsi(ior, head->id, NULL, 0);
+ ior->func->hdmi->ctrl(ior, head->id, false, 0, 0);
+ }
+
+ nvkm_outp_release(outp, NVKM_OUTP_USER);
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[16],
+ u8 link_nr, u8 link_bw, bool hda, bool mst)
+{
+ int ret;
+
+ ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda);
+ if (ret)
+ return ret;
+
+ memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd));
+ outp->dp.lt.nr = link_nr;
+ outp->dp.lt.bw = link_bw;
+ outp->dp.lt.mst = mst;
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet,
+ u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
+{
+ struct nvkm_ior *ior;
+ int ret;
+
+ if (!(outp->asy.head = nvkm_head_find(outp->disp, head)))
+ return -EINVAL;
+
+ ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda);
+ if (ret)
+ return ret;
+
+ ior = outp->ior;
+
+ if (hdmi) {
+ if (!ior->func->hdmi ||
+ hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f ||
+ (hdmi_scdc && !ior->func->hdmi->scdc)) {
+ nvkm_outp_release(outp, NVKM_OUTP_USER);
+ return -EINVAL;
+ }
+
+ ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey);
+ if (ior->func->hdmi->scdc)
+ ior->func->hdmi->scdc(ior, hdmi_scdc);
+ }
+
+ return 0;
+}
+
+static int
+nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8)
+{
+ if (outp->info.type != DCB_OUTPUT_LVDS)
+ return -EINVAL;
+
+ outp->lvds.dual = dual;
+ outp->lvds.bpc8 = bpc8;
+
+ return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
+}
+
+static int
+nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+ union nvif_outp_acquire_args *args = argv;
+ int ret;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (outp->ior)
+ return -EBUSY;
+
+ switch (args->v0.proto) {
+ case NVIF_OUTP_ACQUIRE_V0_RGB_CRT:
+ ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
+ break;
+ case NVIF_OUTP_ACQUIRE_V0_TMDS:
+ ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head,
+ args->v0.tmds.hdmi,
+ args->v0.tmds.hdmi_max_ac_packet,
+ args->v0.tmds.hdmi_rekey,
+ args->v0.tmds.hdmi_scdc,
+ args->v0.tmds.hdmi_hda);
+ break;
+ case NVIF_OUTP_ACQUIRE_V0_LVDS:
+ ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
+ break;
+ case NVIF_OUTP_ACQUIRE_V0_DP:
+ ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd,
+ args->v0.dp.link_nr,
+ args->v0.dp.link_bw,
+ args->v0.dp.hda != 0,
+ args->v0.dp.mst != 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ args->v0.or = outp->ior->id;
+ args->v0.link = outp->ior->asy.link;
+ return 0;
+}
+
+static int
nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
{
union nvif_outp_load_detect_args *args = argv;
@@ -49,10 +276,28 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
+nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
+{
+ switch (mthd) {
+ case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
+ case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
+ case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_MST_VCPI: return nvkm_uoutp_mthd_dp_mst_vcpi(outp, argv, argc);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int
nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
{
switch (mthd) {
case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc);
+ case NVIF_OUTP_V0_ACQUIRE : return nvkm_uoutp_mthd_acquire (outp, argv, argc);
+ case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc);
default:
break;
}
@@ -73,6 +318,11 @@ nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
if (ret <= 0)
goto done;
+ if (outp->ior)
+ ret = nvkm_uoutp_mthd_acquired(outp, mthd, argv, argc);
+ else
+ ret = -EIO;
+
done:
mutex_unlock(&disp->super.mutex);
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
index 43b7dec45179..d619b40a42c3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
@@ -65,10 +65,10 @@ nvkm_falcon_intr(struct nvkm_engine *engine)
u32 dest = nvkm_rd32(device, base + 0x01c);
u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16);
u32 inst = nvkm_rd32(device, base + 0x050) & 0x3fffffff;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
unsigned long flags;
- chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags);
+ chan = nvkm_chan_get_inst(engine, (u64)inst << 12, &flags);
if (intr & 0x00000040) {
if (falcon->func->intr) {
@@ -89,7 +89,7 @@ nvkm_falcon_intr(struct nvkm_engine *engine)
nvkm_wr32(device, base + 0x004, intr);
}
- nvkm_fifo_chan_put(device->fifo, flags, &chan);
+ nvkm_chan_put(&chan, flags);
}
static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
index 5e831d347a95..5a074b9970ab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
@@ -1,11 +1,18 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/fifo/base.o
+nvkm-y += nvkm/engine/fifo/cgrp.o
+nvkm-y += nvkm/engine/fifo/chan.o
+nvkm-y += nvkm/engine/fifo/chid.o
+nvkm-y += nvkm/engine/fifo/runl.o
+nvkm-y += nvkm/engine/fifo/runq.o
+
nvkm-y += nvkm/engine/fifo/nv04.o
nvkm-y += nvkm/engine/fifo/nv10.o
nvkm-y += nvkm/engine/fifo/nv17.o
nvkm-y += nvkm/engine/fifo/nv40.o
nvkm-y += nvkm/engine/fifo/nv50.o
nvkm-y += nvkm/engine/fifo/g84.o
+nvkm-y += nvkm/engine/fifo/g98.o
nvkm-y += nvkm/engine/fifo/gf100.o
nvkm-y += nvkm/engine/fifo/gk104.o
nvkm-y += nvkm/engine/fifo/gk110.o
@@ -13,28 +20,11 @@ nvkm-y += nvkm/engine/fifo/gk208.o
nvkm-y += nvkm/engine/fifo/gk20a.o
nvkm-y += nvkm/engine/fifo/gm107.o
nvkm-y += nvkm/engine/fifo/gm200.o
-nvkm-y += nvkm/engine/fifo/gm20b.o
nvkm-y += nvkm/engine/fifo/gp100.o
-nvkm-y += nvkm/engine/fifo/gp10b.o
nvkm-y += nvkm/engine/fifo/gv100.o
nvkm-y += nvkm/engine/fifo/tu102.o
+nvkm-y += nvkm/engine/fifo/ga100.o
nvkm-y += nvkm/engine/fifo/ga102.o
-nvkm-y += nvkm/engine/fifo/chan.o
-nvkm-y += nvkm/engine/fifo/channv50.o
-nvkm-y += nvkm/engine/fifo/chang84.o
-
-nvkm-y += nvkm/engine/fifo/dmanv04.o
-nvkm-y += nvkm/engine/fifo/dmanv10.o
-nvkm-y += nvkm/engine/fifo/dmanv17.o
-nvkm-y += nvkm/engine/fifo/dmanv40.o
-
-nvkm-y += nvkm/engine/fifo/gpfifonv50.o
-nvkm-y += nvkm/engine/fifo/gpfifog84.o
-nvkm-y += nvkm/engine/fifo/gpfifogf100.o
-nvkm-y += nvkm/engine/fifo/gpfifogk104.o
-nvkm-y += nvkm/engine/fifo/gpfifogv100.o
-nvkm-y += nvkm/engine/fifo/gpfifotu102.o
-
-nvkm-y += nvkm/engine/fifo/usergv100.o
-nvkm-y += nvkm/engine/fifo/usertu102.o
+nvkm-y += nvkm/engine/fifo/ucgrp.o
+nvkm-y += nvkm/engine/fifo/uchan.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
index 58b8df75fc40..5ea9a2ff0663 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
@@ -23,25 +23,32 @@
*/
#include "priv.h"
#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+#include "runq.h"
-#include <core/client.h>
#include <core/gpuobj.h>
-#include <core/notify.h>
+#include <subdev/bar.h>
#include <subdev/mc.h>
+#include <subdev/mmu.h>
-#include <nvif/event.h>
#include <nvif/cl0080.h>
#include <nvif/unpack.h>
-void
-nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid)
+bool
+nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *engine)
{
- unsigned long flags;
- if (WARN_ON(!fifo->func->recover_chan))
- return;
- spin_lock_irqsave(&fifo->lock, flags);
- fifo->func->recover_chan(fifo, chid);
- spin_unlock_irqrestore(&fifo->lock, flags);
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+
+ nvkm_runl_foreach(runl, engine->subdev.device->fifo) {
+ nvkm_runl_foreach_engn(engn, runl) {
+ if (engn->engine == engine)
+ return engn->func->chsw ? engn->func->chsw(engn) : false;
+ }
+ }
+
+ return false;
}
void
@@ -59,160 +66,23 @@ nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
void
nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
{
- return fifo->func->fault(fifo, info);
-}
-
-void
-nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags,
- struct nvkm_fifo_chan **pchan)
-{
- struct nvkm_fifo_chan *chan = *pchan;
- if (likely(chan)) {
- *pchan = NULL;
- spin_unlock_irqrestore(&fifo->lock, flags);
- }
-}
-
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst)
-{
- struct nvkm_fifo_chan *chan;
- list_for_each_entry(chan, &fifo->chan, head) {
- if (chan->inst->addr == inst) {
- list_del(&chan->head);
- list_add(&chan->head, &fifo->chan);
- return chan;
- }
- }
- return NULL;
-}
-
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags)
-{
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- spin_lock_irqsave(&fifo->lock, flags);
- if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) {
- *rflags = flags;
- return chan;
- }
- spin_unlock_irqrestore(&fifo->lock, flags);
- return NULL;
-}
-
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
-{
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- spin_lock_irqsave(&fifo->lock, flags);
- list_for_each_entry(chan, &fifo->chan, head) {
- if (chan->chid == chid) {
- list_del(&chan->head);
- list_add(&chan->head, &fifo->chan);
- *rflags = flags;
- return chan;
- }
- }
- spin_unlock_irqrestore(&fifo->lock, flags);
- return NULL;
-}
-
-void
-nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid)
-{
- nvkm_event_send(&fifo->kevent, 1, chid, NULL, 0);
-}
-
-static int
-nvkm_fifo_kevent_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- if (size == 0) {
- notify->size = 0;
- notify->types = 1;
- notify->index = chan->chid;
- return 0;
- }
- return -ENOSYS;
-}
-
-static const struct nvkm_event_func
-nvkm_fifo_kevent_func = {
- .ctor = nvkm_fifo_kevent_ctor,
-};
-
-static void
-nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- fifo->func->uevent_fini(fifo);
-}
-
-static void
-nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
- struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- fifo->func->uevent_init(fifo);
-}
-
-static int
-nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- union {
- struct nvif_notify_uevent_req none;
- } *req = data;
- int ret = -ENOSYS;
-
- if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
- notify->size = sizeof(struct nvif_notify_uevent_rep);
- notify->types = 1;
- notify->index = 0;
- }
-
- return ret;
-}
-
-static const struct nvkm_event_func
-nvkm_fifo_uevent_func = {
- .ctor = nvkm_fifo_uevent_ctor,
- .init = nvkm_fifo_uevent_init,
- .fini = nvkm_fifo_uevent_fini,
-};
-
-void
-nvkm_fifo_uevent(struct nvkm_fifo *fifo)
-{
- struct nvif_notify_uevent_rep rep = {
- };
- nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
+ return fifo->func->mmu_fault->recover(fifo, info);
}
static int
-nvkm_fifo_class_new_(struct nvkm_device *device,
- const struct nvkm_oclass *oclass, void *data, u32 size,
- struct nvkm_object **pobject)
+nvkm_fifo_class_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
+ void *argv, u32 argc, struct nvkm_object **pobject)
{
struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
- return fifo->func->class_new(fifo, oclass, data, size, pobject);
-}
-static const struct nvkm_device_oclass
-nvkm_fifo_class_ = {
- .ctor = nvkm_fifo_class_new_,
-};
+ if (oclass->engn == &fifo->func->cgrp.user)
+ return nvkm_ucgrp_new(fifo, oclass, argv, argc, pobject);
-static int
-nvkm_fifo_class_new(struct nvkm_device *device,
- const struct nvkm_oclass *oclass, void *data, u32 size,
- struct nvkm_object **pobject)
-{
- const struct nvkm_fifo_chan_oclass *sclass = oclass->engn;
- struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
- return sclass->ctor(fifo, oclass, data, size, pobject);
+ if (oclass->engn == &fifo->func->chan.user)
+ return nvkm_uchan_new(fifo, NULL, oclass, argv, argc, pobject);
+
+ WARN_ON(1);
+ return -ENOSYS;
}
static const struct nvkm_device_oclass
@@ -221,24 +91,28 @@ nvkm_fifo_class = {
};
static int
-nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index,
- const struct nvkm_device_oclass **class)
+nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class)
{
struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
- const struct nvkm_fifo_chan_oclass *sclass;
+ const struct nvkm_fifo_func_cgrp *cgrp = &fifo->func->cgrp;
+ const struct nvkm_fifo_func_chan *chan = &fifo->func->chan;
int c = 0;
- if (fifo->func->class_get) {
- int ret = fifo->func->class_get(fifo, index, oclass);
- if (ret == 0)
- *class = &nvkm_fifo_class_;
- return ret;
+ /* *_CHANNEL_GROUP_* */
+ if (cgrp->user.oclass) {
+ if (c++ == index) {
+ oclass->base = cgrp->user;
+ oclass->engn = &fifo->func->cgrp.user;
+ *class = &nvkm_fifo_class;
+ return 0;
+ }
}
- while ((sclass = fifo->func->chan[c])) {
+ /* *_CHANNEL_DMA, *_CHANNEL_GPFIFO_* */
+ if (chan->user.oclass) {
if (c++ == index) {
- oclass->base = sclass->base;
- oclass->engn = sclass;
+ oclass->base = chan->user;
+ oclass->engn = &fifo->func->chan.user;
*class = &nvkm_fifo_class;
return 0;
}
@@ -247,19 +121,47 @@ nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index,
return c;
}
-static void
-nvkm_fifo_intr(struct nvkm_engine *engine)
+static int
+nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
- fifo->func->intr(fifo);
+ struct nvkm_runl *runl;
+
+ nvkm_inth_block(&fifo->engine.subdev.inth);
+
+ nvkm_runl_foreach(runl, fifo)
+ nvkm_runl_fini(runl);
+
+ return 0;
}
static int
-nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
+nvkm_fifo_init(struct nvkm_engine *engine)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
- if (fifo->func->fini)
- fifo->func->fini(fifo);
+ struct nvkm_runq *runq;
+ struct nvkm_runl *runl;
+ u32 mask = 0;
+
+ if (fifo->func->init_pbdmas) {
+ nvkm_runq_foreach(runq, fifo)
+ mask |= BIT(runq->id);
+
+ fifo->func->init_pbdmas(fifo, mask);
+
+ nvkm_runq_foreach(runq, fifo)
+ runq->func->init(runq);
+ }
+
+ nvkm_runl_foreach(runl, fifo) {
+ if (runl->func->init)
+ runl->func->init(runl);
+ }
+
+ if (fifo->func->init)
+ fifo->func->init(fifo);
+
+ nvkm_inth_allow(&fifo->engine.subdev.inth);
return 0;
}
@@ -267,22 +169,146 @@ static int
nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ int ret;
+
+ ret = nvkm_subdev_oneinit(&fifo->engine.subdev);
+ if (ret)
+ return ret;
+
switch (mthd) {
- case NV_DEVICE_HOST_CHANNELS: *data = fifo->nr; return 0;
+ case NV_DEVICE_HOST_CHANNELS: *data = fifo->chid ? fifo->chid->nr : 0; return 0;
+ case NV_DEVICE_HOST_RUNLISTS:
+ *data = 0;
+ nvkm_runl_foreach(runl, fifo)
+ *data |= BIT(runl->id);
+ return 0;
+ case NV_DEVICE_HOST_RUNLIST_ENGINES:
+ runl = nvkm_runl_get(fifo, *data, 0);
+ if (runl) {
+ *data = 0;
+ nvkm_runl_foreach_engn(engn, runl) {
+#define CASE(n) case NVKM_ENGINE_##n: *data |= NV_DEVICE_HOST_RUNLIST_ENGINES_##n; break
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_DMAOBJ:
+ break;
+ CASE(SW );
+ CASE(GR );
+ CASE(MPEG );
+ CASE(ME );
+ CASE(CIPHER);
+ CASE(BSP );
+ CASE(VP );
+ CASE(CE );
+ CASE(SEC );
+ CASE(MSVLD );
+ CASE(MSPDEC);
+ CASE(MSPPP );
+ CASE(MSENC );
+ CASE(VIC );
+ CASE(SEC2 );
+ CASE(NVDEC );
+ CASE(NVENC );
+ default:
+ WARN_ON(1);
+ break;
+ }
+#undef CASE
+ }
+ return 0;
+ }
+ return -EINVAL;
+ case NV_DEVICE_HOST_RUNLIST_CHANNELS:
+ if (!fifo->chid) {
+ runl = nvkm_runl_get(fifo, *data, 0);
+ if (runl) {
+ *data = runl->chid->nr;
+ return 0;
+ }
+ }
+ return -EINVAL;
default:
- if (fifo->func->info)
- return fifo->func->info(fifo, mthd, data);
break;
}
+
return -ENOSYS;
}
static int
nvkm_fifo_oneinit(struct nvkm_engine *engine)
{
+ struct nvkm_subdev *subdev = &engine->subdev;
+ struct nvkm_device *device = subdev->device;
struct nvkm_fifo *fifo = nvkm_fifo(engine);
- if (fifo->func->oneinit)
- return fifo->func->oneinit(fifo);
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ int ret, nr, i;
+
+ /* Initialise CHID/CGID allocator(s) on GPUs where they aren't per-runlist. */
+ if (fifo->func->chid_nr) {
+ ret = fifo->func->chid_ctor(fifo, fifo->func->chid_nr(fifo));
+ if (ret)
+ return ret;
+ }
+
+ /* Create runqueues for each PBDMA. */
+ if (fifo->func->runq_nr) {
+ for (nr = fifo->func->runq_nr(fifo), i = 0; i < nr; i++) {
+ if (!nvkm_runq_new(fifo, i))
+ return -ENOMEM;
+ }
+ }
+
+ /* Create runlists. */
+ ret = fifo->func->runl_ctor(fifo);
+ if (ret)
+ return ret;
+
+ nvkm_runl_foreach(runl, fifo) {
+ RUNL_DEBUG(runl, "chan:%06x", runl->chan);
+ nvkm_runl_foreach_engn(engn, runl) {
+ ENGN_DEBUG(engn, "");
+ }
+ }
+
+ /* Register interrupt handler. */
+ if (fifo->func->intr) {
+ ret = nvkm_inth_add(&device->mc->intr, NVKM_INTR_SUBDEV, NVKM_INTR_PRIO_NORMAL,
+ subdev, fifo->func->intr, &subdev->inth);
+ if (ret) {
+ nvkm_error(subdev, "intr %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* Initialise non-stall intr handling. */
+ if (fifo->func->nonstall_ctor) {
+ ret = fifo->func->nonstall_ctor(fifo);
+ if (ret) {
+ nvkm_error(subdev, "nonstall %d\n", ret);
+ }
+ }
+
+ /* Allocate USERD + BAR1 polling area. */
+ if (fifo->func->chan.func->userd->bar == 1) {
+ struct nvkm_vmm *bar1 = nvkm_bar_bar1_vmm(device);
+
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, fifo->chid->nr *
+ fifo->func->chan.func->userd->size, 0, true,
+ &fifo->userd.mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_vmm_get(bar1, 12, nvkm_memory_size(fifo->userd.mem), &fifo->userd.bar1);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_map(fifo->userd.mem, 0, bar1, fifo->userd.bar1, NULL, 0);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -292,25 +318,28 @@ nvkm_fifo_preinit(struct nvkm_engine *engine)
nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO, 0);
}
-static int
-nvkm_fifo_init(struct nvkm_engine *engine)
-{
- struct nvkm_fifo *fifo = nvkm_fifo(engine);
- fifo->func->init(fifo);
- return 0;
-}
-
static void *
nvkm_fifo_dtor(struct nvkm_engine *engine)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
- void *data = fifo;
- if (fifo->func->dtor)
- data = fifo->func->dtor(fifo);
- nvkm_event_fini(&fifo->kevent);
- nvkm_event_fini(&fifo->uevent);
+ struct nvkm_runl *runl, *runt;
+ struct nvkm_runq *runq, *rtmp;
+
+ if (fifo->userd.bar1)
+ nvkm_vmm_put(nvkm_bar_bar1_vmm(engine->subdev.device), &fifo->userd.bar1);
+ nvkm_memory_unref(&fifo->userd.mem);
+
+ list_for_each_entry_safe(runl, runt, &fifo->runls, head)
+ nvkm_runl_del(runl);
+ list_for_each_entry_safe(runq, rtmp, &fifo->runqs, head)
+ nvkm_runq_del(runq);
+
+ nvkm_chid_unref(&fifo->cgid);
+ nvkm_chid_unref(&fifo->chid);
+
+ nvkm_event_fini(&fifo->nonstall.event);
mutex_destroy(&fifo->mutex);
- return data;
+ return fifo;
}
static const struct nvkm_engine_func
@@ -321,37 +350,40 @@ nvkm_fifo = {
.info = nvkm_fifo_info,
.init = nvkm_fifo_init,
.fini = nvkm_fifo_fini,
- .intr = nvkm_fifo_intr,
.base.sclass = nvkm_fifo_class_get,
};
int
-nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, int nr, struct nvkm_fifo *fifo)
+nvkm_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo)
{
+ struct nvkm_fifo *fifo;
int ret;
+ if (!(fifo = *pfifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
+ return -ENOMEM;
+
fifo->func = func;
- INIT_LIST_HEAD(&fifo->chan);
+ INIT_LIST_HEAD(&fifo->runqs);
+ INIT_LIST_HEAD(&fifo->runls);
+ /*TODO: Needs to be >CTXSW_TIMEOUT, so RC can recover before this is hit.
+ * CTXSW_TIMEOUT HW default seems to differ between GPUs, so just a
+ * large number for now until we support changing it.
+ */
+ fifo->timeout.chan_msec = 10000;
spin_lock_init(&fifo->lock);
mutex_init(&fifo->mutex);
- if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
- fifo->nr = NVKM_FIFO_CHID_NR;
- else
- fifo->nr = nr;
- bitmap_clear(fifo->mask, 0, fifo->nr);
-
ret = nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine);
if (ret)
return ret;
- if (func->uevent_init) {
- ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1,
- &fifo->uevent);
+ if (func->nonstall) {
+ ret = nvkm_event_init(func->nonstall, &fifo->engine.subdev, 1, 1,
+ &fifo->nonstall.event);
if (ret)
return ret;
}
- return nvkm_event_init(&nvkm_fifo_kevent_func, 1, nr, &fifo->kevent);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c
new file mode 100644
index 000000000000..ea53fb3d5d06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+#include "priv.h"
+
+#include <core/gpuobj.h>
+#include <subdev/mmu.h>
+
+static void
+nvkm_cgrp_ectx_put(struct nvkm_cgrp *cgrp, struct nvkm_ectx **pectx)
+{
+ struct nvkm_ectx *ectx = *pectx;
+
+ if (ectx) {
+ struct nvkm_engn *engn = ectx->engn;
+
+ if (refcount_dec_and_test(&ectx->refs)) {
+ CGRP_TRACE(cgrp, "dtor ectx %d[%s]", engn->id, engn->engine->subdev.name);
+ nvkm_object_del(&ectx->object);
+ list_del(&ectx->head);
+ kfree(ectx);
+ }
+
+ *pectx = NULL;
+ }
+}
+
+static int
+nvkm_cgrp_ectx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_ectx **pectx,
+ struct nvkm_chan *chan, struct nvkm_client *client)
+{
+ struct nvkm_engine *engine = engn->engine;
+ struct nvkm_oclass cclass = {
+ .client = client,
+ .engine = engine,
+ };
+ struct nvkm_ectx *ectx;
+ int ret = 0;
+
+ /* Look for an existing context for this engine in the channel group. */
+ ectx = nvkm_list_find(ectx, &cgrp->ectxs, head, ectx->engn == engn);
+ if (ectx) {
+ refcount_inc(&ectx->refs);
+ *pectx = ectx;
+ return 0;
+ }
+
+ /* Nope - create a fresh one. */
+ CGRP_TRACE(cgrp, "ctor ectx %d[%s]", engn->id, engn->engine->subdev.name);
+ if (!(ectx = *pectx = kzalloc(sizeof(*ectx), GFP_KERNEL)))
+ return -ENOMEM;
+
+ ectx->engn = engn;
+ refcount_set(&ectx->refs, 1);
+ refcount_set(&ectx->uses, 0);
+ list_add_tail(&ectx->head, &cgrp->ectxs);
+
+ /* Allocate the HW structures. */
+ if (engine->func->fifo.cclass)
+ ret = engine->func->fifo.cclass(chan, &cclass, &ectx->object);
+ else if (engine->func->cclass)
+ ret = nvkm_object_new_(engine->func->cclass, &cclass, NULL, 0, &ectx->object);
+
+ if (ret)
+ nvkm_cgrp_ectx_put(cgrp, pectx);
+
+ return ret;
+}
+
+void
+nvkm_cgrp_vctx_put(struct nvkm_cgrp *cgrp, struct nvkm_vctx **pvctx)
+{
+ struct nvkm_vctx *vctx = *pvctx;
+
+ if (vctx) {
+ struct nvkm_engn *engn = vctx->ectx->engn;
+
+ if (refcount_dec_and_test(&vctx->refs)) {
+ CGRP_TRACE(cgrp, "dtor vctx %d[%s]", engn->id, engn->engine->subdev.name);
+ nvkm_vmm_put(vctx->vmm, &vctx->vma);
+ nvkm_gpuobj_del(&vctx->inst);
+
+ nvkm_cgrp_ectx_put(cgrp, &vctx->ectx);
+ if (vctx->vmm) {
+ atomic_dec(&vctx->vmm->engref[engn->engine->subdev.type]);
+ nvkm_vmm_unref(&vctx->vmm);
+ }
+ list_del(&vctx->head);
+ kfree(vctx);
+ }
+
+ *pvctx = NULL;
+ }
+}
+
+int
+nvkm_cgrp_vctx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_chan *chan,
+ struct nvkm_vctx **pvctx, struct nvkm_client *client)
+{
+ struct nvkm_ectx *ectx;
+ struct nvkm_vctx *vctx;
+ int ret;
+
+ /* Look for an existing sub-context for this engine+VEID in the channel group. */
+ vctx = nvkm_list_find(vctx, &cgrp->vctxs, head,
+ vctx->ectx->engn == engn && vctx->vmm == chan->vmm);
+ if (vctx) {
+ refcount_inc(&vctx->refs);
+ *pvctx = vctx;
+ return 0;
+ }
+
+ /* Nope - create a fresh one. But, context first. */
+ ret = nvkm_cgrp_ectx_get(cgrp, engn, &ectx, chan, client);
+ if (ret) {
+ CGRP_ERROR(cgrp, "ectx %d[%s]: %d", engn->id, engn->engine->subdev.name, ret);
+ return ret;
+ }
+
+ /* Now, create the sub-context. */
+ CGRP_TRACE(cgrp, "ctor vctx %d[%s]", engn->id, engn->engine->subdev.name);
+ if (!(vctx = *pvctx = kzalloc(sizeof(*vctx), GFP_KERNEL))) {
+ nvkm_cgrp_ectx_put(cgrp, &ectx);
+ return -ENOMEM;
+ }
+
+ vctx->ectx = ectx;
+ vctx->vmm = nvkm_vmm_ref(chan->vmm);
+ refcount_set(&vctx->refs, 1);
+ list_add_tail(&vctx->head, &cgrp->vctxs);
+
+ /* MMU on some GPUs needs to know engine usage for TLB invalidation. */
+ if (vctx->vmm)
+ atomic_inc(&vctx->vmm->engref[engn->engine->subdev.type]);
+
+ /* Allocate the HW structures. */
+ if (engn->func->bind) {
+ ret = nvkm_object_bind(vctx->ectx->object, NULL, 0, &vctx->inst);
+ if (ret == 0 && engn->func->ctor)
+ ret = engn->func->ctor(engn, vctx);
+ }
+
+ if (ret)
+ nvkm_cgrp_vctx_put(cgrp, pvctx);
+
+ return ret;
+}
+
+static void
+nvkm_cgrp_del(struct kref *kref)
+{
+ struct nvkm_cgrp *cgrp = container_of(kref, typeof(*cgrp), kref);
+ struct nvkm_runl *runl = cgrp->runl;
+
+ if (runl->cgid)
+ nvkm_chid_put(runl->cgid, cgrp->id, &cgrp->lock);
+
+ mutex_destroy(&cgrp->mutex);
+ nvkm_vmm_unref(&cgrp->vmm);
+ kfree(cgrp);
+}
+
+void
+nvkm_cgrp_unref(struct nvkm_cgrp **pcgrp)
+{
+ struct nvkm_cgrp *cgrp = *pcgrp;
+
+ if (!cgrp)
+ return;
+
+ kref_put(&cgrp->kref, nvkm_cgrp_del);
+ *pcgrp = NULL;
+}
+
+struct nvkm_cgrp *
+nvkm_cgrp_ref(struct nvkm_cgrp *cgrp)
+{
+ if (cgrp)
+ kref_get(&cgrp->kref);
+
+ return cgrp;
+}
+
+void
+nvkm_cgrp_put(struct nvkm_cgrp **pcgrp, unsigned long irqflags)
+{
+ struct nvkm_cgrp *cgrp = *pcgrp;
+
+ if (!cgrp)
+ return;
+
+ *pcgrp = NULL;
+ spin_unlock_irqrestore(&cgrp->lock, irqflags);
+}
+
+int
+nvkm_cgrp_new(struct nvkm_runl *runl, const char *name, struct nvkm_vmm *vmm, bool hw,
+ struct nvkm_cgrp **pcgrp)
+{
+ struct nvkm_cgrp *cgrp;
+
+ if (!(cgrp = *pcgrp = kmalloc(sizeof(*cgrp), GFP_KERNEL)))
+ return -ENOMEM;
+
+ cgrp->func = runl->fifo->func->cgrp.func;
+ strscpy(cgrp->name, name, sizeof(cgrp->name));
+ cgrp->runl = runl;
+ cgrp->vmm = nvkm_vmm_ref(vmm);
+ cgrp->hw = hw;
+ cgrp->id = -1;
+ kref_init(&cgrp->kref);
+ INIT_LIST_HEAD(&cgrp->chans);
+ cgrp->chan_nr = 0;
+ spin_lock_init(&cgrp->lock);
+ INIT_LIST_HEAD(&cgrp->ectxs);
+ INIT_LIST_HEAD(&cgrp->vctxs);
+ mutex_init(&cgrp->mutex);
+ atomic_set(&cgrp->rc, NVKM_CGRP_RC_NONE);
+
+ if (runl->cgid) {
+ cgrp->id = nvkm_chid_get(runl->cgid, cgrp);
+ if (cgrp->id < 0) {
+ RUNL_ERROR(runl, "!cgids");
+ nvkm_cgrp_unref(pcgrp);
+ return -ENOSPC;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h
index d0ac60b06720..5f6abd59a6ff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h
@@ -1,11 +1,75 @@
-#ifndef __NVKM_FIFO_CGRP_H__
-#define __NVKM_FIFO_CGRP_H__
-#include "priv.h"
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_CGRP_H__
+#define __NVKM_CGRP_H__
+#include <core/os.h>
+struct nvkm_chan;
+struct nvkm_client;
+
+struct nvkm_vctx {
+ struct nvkm_ectx *ectx;
+ struct nvkm_vmm *vmm;
+ refcount_t refs;
+
+ struct nvkm_gpuobj *inst;
+ struct nvkm_vma *vma;
-struct nvkm_fifo_cgrp {
- int id;
struct list_head head;
- struct list_head chan;
+};
+
+struct nvkm_ectx {
+ struct nvkm_engn *engn;
+ refcount_t refs;
+ refcount_t uses;
+
+ struct nvkm_object *object;
+
+ struct list_head head;
+};
+
+struct nvkm_cgrp {
+ const struct nvkm_cgrp_func {
+ void (*preempt)(struct nvkm_cgrp *);
+ } *func;
+ char name[64];
+ struct nvkm_runl *runl;
+ struct nvkm_vmm *vmm;
+ bool hw;
+ int id;
+ struct kref kref;
+
+ struct list_head chans;
int chan_nr;
+
+ spinlock_t lock; /* protects irq handler channel (group) lookup */
+
+ struct list_head ectxs;
+ struct list_head vctxs;
+ struct mutex mutex;
+
+#define NVKM_CGRP_RC_NONE 0
+#define NVKM_CGRP_RC_PENDING 1
+#define NVKM_CGRP_RC_RUNNING 2
+ atomic_t rc;
+
+ struct list_head head;
};
+
+int nvkm_cgrp_new(struct nvkm_runl *, const char *name, struct nvkm_vmm *, bool hw,
+ struct nvkm_cgrp **);
+struct nvkm_cgrp *nvkm_cgrp_ref(struct nvkm_cgrp *);
+void nvkm_cgrp_unref(struct nvkm_cgrp **);
+int nvkm_cgrp_vctx_get(struct nvkm_cgrp *, struct nvkm_engn *, struct nvkm_chan *,
+ struct nvkm_vctx **, struct nvkm_client *);
+void nvkm_cgrp_vctx_put(struct nvkm_cgrp *, struct nvkm_vctx **);
+
+void nvkm_cgrp_put(struct nvkm_cgrp **, unsigned long irqflags);
+
+#define nvkm_cgrp_foreach_chan(chan,cgrp) list_for_each_entry((chan), &(cgrp)->chans, head)
+#define nvkm_cgrp_foreach_chan_safe(chan,ctmp,cgrp) \
+ list_for_each_entry_safe((chan), (ctmp), &(cgrp)->chans, head)
+
+#define CGRP_PRCLI(c,l,p,f,a...) RUNL_PRINT((c)->runl, l, p, "%04x:[%s]"f, (c)->id, (c)->name, ##a)
+#define CGRP_PRINT(c,l,p,f,a...) RUNL_PRINT((c)->runl, l, p, "%04x:"f, (c)->id, ##a)
+#define CGRP_ERROR(c,f,a...) CGRP_PRCLI((c), ERROR, err, " "f"\n", ##a)
+#define CGRP_TRACE(c,f,a...) CGRP_PRINT((c), TRACE, info, " "f"\n", ##a)
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
index 2e7f32cebf2a..b7c9d6115bce 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
@@ -22,285 +22,265 @@
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
+#include "cgrp.h"
+#include "chid.h"
+#include "runl.h"
+#include "priv.h"
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <core/oproxy.h>
+#include <core/ramht.h>
#include <subdev/mmu.h>
#include <engine/dma.h>
-struct nvkm_fifo_chan_object {
- struct nvkm_oproxy oproxy;
- struct nvkm_fifo_chan *chan;
- int hash;
+#include <nvif/if0020.h>
+
+const struct nvkm_event_func
+nvkm_chan_event = {
};
-static struct nvkm_fifo_engn *
-nvkm_fifo_chan_engn(struct nvkm_fifo_chan *chan, struct nvkm_engine *engine)
+void
+nvkm_chan_cctx_bind(struct nvkm_chan *chan, struct nvkm_engn *engn, struct nvkm_cctx *cctx)
{
- int engi = chan->fifo->func->engine_id(chan->fifo, engine);
- if (engi >= 0)
- return &chan->engn[engi];
- return NULL;
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+ struct nvkm_runl *runl = cgrp->runl;
+ struct nvkm_engine *engine = engn->engine;
+
+ if (!engn->func->bind)
+ return;
+
+ CHAN_TRACE(chan, "%sbind cctx %d[%s]", cctx ? "" : "un", engn->id, engine->subdev.name);
+
+ /* Prevent any channel in channel group from being rescheduled, kick them
+ * off host and any engine(s) they're loaded on.
+ */
+ if (cgrp->hw)
+ nvkm_runl_block(runl);
+ else
+ nvkm_chan_block(chan);
+ nvkm_chan_preempt(chan, true);
+
+ /* Update context pointer. */
+ engn->func->bind(engn, cctx, chan);
+
+ /* Resume normal operation. */
+ if (cgrp->hw)
+ nvkm_runl_allow(runl);
+ else
+ nvkm_chan_allow(chan);
}
-static int
-nvkm_fifo_chan_child_fini(struct nvkm_oproxy *base, bool suspend)
+void
+nvkm_chan_cctx_put(struct nvkm_chan *chan, struct nvkm_cctx **pcctx)
{
- struct nvkm_fifo_chan_object *object =
- container_of(base, typeof(*object), oproxy);
- struct nvkm_engine *engine = object->oproxy.object->engine;
- struct nvkm_fifo_chan *chan = object->chan;
- struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine);
- const char *name = engine->subdev.name;
- int ret = 0;
-
- if (--engn->usecount)
- return 0;
+ struct nvkm_cctx *cctx = *pcctx;
- if (chan->func->engine_fini) {
- ret = chan->func->engine_fini(chan, engine, suspend);
- if (ret) {
- nvif_error(&chan->object,
- "detach %s failed, %d\n", name, ret);
- return ret;
+ if (cctx) {
+ struct nvkm_engn *engn = cctx->vctx->ectx->engn;
+
+ if (refcount_dec_and_mutex_lock(&cctx->refs, &chan->cgrp->mutex)) {
+ CHAN_TRACE(chan, "dtor cctx %d[%s]", engn->id, engn->engine->subdev.name);
+ nvkm_cgrp_vctx_put(chan->cgrp, &cctx->vctx);
+ list_del(&cctx->head);
+ kfree(cctx);
+ mutex_unlock(&chan->cgrp->mutex);
}
- }
- if (engn->object) {
- ret = nvkm_object_fini(engn->object, suspend);
- if (ret && suspend)
- return ret;
+ *pcctx = NULL;
}
-
- nvif_trace(&chan->object, "detached %s\n", name);
- return ret;
}
-static int
-nvkm_fifo_chan_child_init(struct nvkm_oproxy *base)
+int
+nvkm_chan_cctx_get(struct nvkm_chan *chan, struct nvkm_engn *engn, struct nvkm_cctx **pcctx,
+ struct nvkm_client *client)
{
- struct nvkm_fifo_chan_object *object =
- container_of(base, typeof(*object), oproxy);
- struct nvkm_engine *engine = object->oproxy.object->engine;
- struct nvkm_fifo_chan *chan = object->chan;
- struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine);
- const char *name = engine->subdev.name;
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+ struct nvkm_vctx *vctx;
+ struct nvkm_cctx *cctx;
int ret;
- if (engn->usecount++)
+ /* Look for an existing channel context for this engine+VEID. */
+ mutex_lock(&cgrp->mutex);
+ cctx = nvkm_list_find(cctx, &chan->cctxs, head,
+ cctx->vctx->ectx->engn == engn && cctx->vctx->vmm == chan->vmm);
+ if (cctx) {
+ refcount_inc(&cctx->refs);
+ *pcctx = cctx;
+ mutex_unlock(&chan->cgrp->mutex);
return 0;
+ }
- if (engn->object) {
- ret = nvkm_object_init(engn->object);
- if (ret)
- return ret;
+ /* Nope - create a fresh one. But, sub-context first. */
+ ret = nvkm_cgrp_vctx_get(cgrp, engn, chan, &vctx, client);
+ if (ret) {
+ CHAN_ERROR(chan, "vctx %d[%s]: %d", engn->id, engn->engine->subdev.name, ret);
+ goto done;
}
- if (chan->func->engine_init) {
- ret = chan->func->engine_init(chan, engine);
- if (ret) {
- nvif_error(&chan->object,
- "attach %s failed, %d\n", name, ret);
- return ret;
- }
+ /* Now, create the channel context - to track engine binding. */
+ CHAN_TRACE(chan, "ctor cctx %d[%s]", engn->id, engn->engine->subdev.name);
+ if (!(cctx = *pcctx = kzalloc(sizeof(*cctx), GFP_KERNEL))) {
+ nvkm_cgrp_vctx_put(cgrp, &vctx);
+ ret = -ENOMEM;
+ goto done;
}
- nvif_trace(&chan->object, "attached %s\n", name);
- return 0;
+ cctx->vctx = vctx;
+ refcount_set(&cctx->refs, 1);
+ refcount_set(&cctx->uses, 0);
+ list_add_tail(&cctx->head, &chan->cctxs);
+done:
+ mutex_unlock(&cgrp->mutex);
+ return ret;
}
-static void
-nvkm_fifo_chan_child_del(struct nvkm_oproxy *base)
+int
+nvkm_chan_preempt_locked(struct nvkm_chan *chan, bool wait)
{
- struct nvkm_fifo_chan_object *object =
- container_of(base, typeof(*object), oproxy);
- struct nvkm_engine *engine = object->oproxy.base.engine;
- struct nvkm_fifo_chan *chan = object->chan;
- struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine);
-
- if (chan->func->object_dtor)
- chan->func->object_dtor(chan, object->hash);
-
- if (!--engn->refcount) {
- if (chan->func->engine_dtor)
- chan->func->engine_dtor(chan, engine);
- nvkm_object_del(&engn->object);
- if (chan->vmm)
- atomic_dec(&chan->vmm->engref[engine->subdev.type]);
- }
-}
+ struct nvkm_runl *runl = chan->cgrp->runl;
-static const struct nvkm_oproxy_func
-nvkm_fifo_chan_child_func = {
- .dtor[0] = nvkm_fifo_chan_child_del,
- .init[0] = nvkm_fifo_chan_child_init,
- .fini[0] = nvkm_fifo_chan_child_fini,
-};
+ CHAN_TRACE(chan, "preempt");
+ chan->func->preempt(chan);
+ if (!wait)
+ return 0;
+
+ return nvkm_runl_preempt_wait(runl);
+}
-static int
-nvkm_fifo_chan_child_new(const struct nvkm_oclass *oclass, void *data, u32 size,
- struct nvkm_object **pobject)
+int
+nvkm_chan_preempt(struct nvkm_chan *chan, bool wait)
{
- struct nvkm_engine *engine = oclass->engine;
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent);
- struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine);
- struct nvkm_fifo_chan_object *object;
- int ret = 0;
+ int ret;
- if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
- return -ENOMEM;
- nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy);
- object->chan = chan;
- *pobject = &object->oproxy.base;
-
- if (!engn->refcount++) {
- struct nvkm_oclass cclass = {
- .client = oclass->client,
- .engine = oclass->engine,
- };
-
- if (chan->vmm)
- atomic_inc(&chan->vmm->engref[engine->subdev.type]);
-
- if (engine->func->fifo.cclass) {
- ret = engine->func->fifo.cclass(chan, &cclass,
- &engn->object);
- } else
- if (engine->func->cclass) {
- ret = nvkm_object_new_(engine->func->cclass, &cclass,
- NULL, 0, &engn->object);
- }
- if (ret)
- return ret;
+ if (!chan->func->preempt)
+ return 0;
- if (chan->func->engine_ctor) {
- ret = chan->func->engine_ctor(chan, oclass->engine,
- engn->object);
- if (ret)
- return ret;
- }
- }
+ mutex_lock(&chan->cgrp->runl->mutex);
+ ret = nvkm_chan_preempt_locked(chan, wait);
+ mutex_unlock(&chan->cgrp->runl->mutex);
+ return ret;
+}
- ret = oclass->base.ctor(&(const struct nvkm_oclass) {
- .base = oclass->base,
- .engn = oclass->engn,
- .handle = oclass->handle,
- .object = oclass->object,
- .client = oclass->client,
- .parent = engn->object ?
- engn->object :
- oclass->parent,
- .engine = engine,
- }, data, size, &object->oproxy.object);
- if (ret)
- return ret;
+void
+nvkm_chan_remove_locked(struct nvkm_chan *chan)
+{
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+ struct nvkm_runl *runl = cgrp->runl;
- if (chan->func->object_ctor) {
- object->hash =
- chan->func->object_ctor(chan, object->oproxy.object);
- if (object->hash < 0)
- return object->hash;
- }
+ if (list_empty(&chan->head))
+ return;
- return 0;
+ CHAN_TRACE(chan, "remove");
+ if (!--cgrp->chan_nr) {
+ runl->cgrp_nr--;
+ list_del(&cgrp->head);
+ }
+ runl->chan_nr--;
+ list_del_init(&chan->head);
+ atomic_set(&runl->changed, 1);
}
-static int
-nvkm_fifo_chan_child_get(struct nvkm_object *object, int index,
- struct nvkm_oclass *oclass)
+void
+nvkm_chan_remove(struct nvkm_chan *chan, bool preempt)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- struct nvkm_fifo *fifo = chan->fifo;
- struct nvkm_engine *engine;
- u32 engm = chan->engm;
- int engi, ret, c;
-
- for (; c = 0, engi = __ffs(engm), engm; engm &= ~(1ULL << engi)) {
- if (!(engine = fifo->func->id_engine(fifo, engi)))
- continue;
- oclass->engine = engine;
- oclass->base.oclass = 0;
-
- if (engine->func->fifo.sclass) {
- ret = engine->func->fifo.sclass(oclass, index);
- if (oclass->base.oclass) {
- if (!oclass->base.ctor)
- oclass->base.ctor = nvkm_object_new;
- oclass->ctor = nvkm_fifo_chan_child_new;
- return 0;
- }
+ struct nvkm_runl *runl = chan->cgrp->runl;
+
+ mutex_lock(&runl->mutex);
+ if (preempt && chan->func->preempt)
+ nvkm_chan_preempt_locked(chan, true);
+ nvkm_chan_remove_locked(chan);
+ nvkm_runl_update_locked(runl, true);
+ mutex_unlock(&runl->mutex);
+}
- index -= ret;
- continue;
- }
+void
+nvkm_chan_insert(struct nvkm_chan *chan)
+{
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+ struct nvkm_runl *runl = cgrp->runl;
- while (engine->func->sclass[c].oclass) {
- if (c++ == index) {
- oclass->base = engine->func->sclass[index];
- if (!oclass->base.ctor)
- oclass->base.ctor = nvkm_object_new;
- oclass->ctor = nvkm_fifo_chan_child_new;
- return 0;
- }
- }
- index -= c;
+ mutex_lock(&runl->mutex);
+ if (WARN_ON(!list_empty(&chan->head))) {
+ mutex_unlock(&runl->mutex);
+ return;
}
- return -EINVAL;
+ CHAN_TRACE(chan, "insert");
+ list_add_tail(&chan->head, &cgrp->chans);
+ runl->chan_nr++;
+ if (!cgrp->chan_nr++) {
+ list_add_tail(&cgrp->head, &cgrp->runl->cgrps);
+ runl->cgrp_nr++;
+ }
+ atomic_set(&runl->changed, 1);
+ nvkm_runl_update_locked(runl, true);
+ mutex_unlock(&runl->mutex);
}
-static int
-nvkm_fifo_chan_ntfy(struct nvkm_object *object, u32 type,
- struct nvkm_event **pevent)
+static void
+nvkm_chan_block_locked(struct nvkm_chan *chan)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- if (chan->func->ntfy)
- return chan->func->ntfy(chan, type, pevent);
- return -ENODEV;
+ CHAN_TRACE(chan, "block %d", atomic_read(&chan->blocked));
+ if (atomic_inc_return(&chan->blocked) == 1)
+ chan->func->stop(chan);
}
-static int
-nvkm_fifo_chan_map(struct nvkm_object *object, void *argv, u32 argc,
- enum nvkm_object_map *type, u64 *addr, u64 *size)
+void
+nvkm_chan_error(struct nvkm_chan *chan, bool preempt)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- *type = NVKM_OBJECT_MAP_IO;
- *addr = chan->addr;
- *size = chan->size;
- return 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (atomic_inc_return(&chan->errored) == 1) {
+ CHAN_ERROR(chan, "errored - disabling channel");
+ nvkm_chan_block_locked(chan);
+ if (preempt)
+ chan->func->preempt(chan);
+ nvkm_event_ntfy(&chan->cgrp->runl->chid->event, chan->id, NVKM_CHAN_EVENT_ERRORED);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
}
-static int
-nvkm_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+void
+nvkm_chan_block(struct nvkm_chan *chan)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- chan->func->fini(chan);
- return 0;
+ spin_lock_irq(&chan->lock);
+ nvkm_chan_block_locked(chan);
+ spin_unlock_irq(&chan->lock);
}
-static int
-nvkm_fifo_chan_init(struct nvkm_object *object)
+void
+nvkm_chan_allow(struct nvkm_chan *chan)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- chan->func->init(chan);
- return 0;
+ spin_lock_irq(&chan->lock);
+ CHAN_TRACE(chan, "allow %d", atomic_read(&chan->blocked));
+ if (atomic_dec_and_test(&chan->blocked))
+ chan->func->start(chan);
+ spin_unlock_irq(&chan->lock);
}
-static void *
-nvkm_fifo_chan_dtor(struct nvkm_object *object)
+void
+nvkm_chan_del(struct nvkm_chan **pchan)
{
- struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
- struct nvkm_fifo *fifo = chan->fifo;
- void *data = chan->func->dtor(chan);
- unsigned long flags;
+ struct nvkm_chan *chan = *pchan;
+
+ if (!chan)
+ return;
+
+ if (chan->func->ramfc->clear)
+ chan->func->ramfc->clear(chan);
- spin_lock_irqsave(&fifo->lock, flags);
- if (!list_empty(&chan->head)) {
- __clear_bit(chan->chid, fifo->mask);
- list_del(&chan->head);
+ nvkm_ramht_del(&chan->ramht);
+ nvkm_gpuobj_del(&chan->pgd);
+ nvkm_gpuobj_del(&chan->eng);
+ nvkm_gpuobj_del(&chan->cache);
+ nvkm_gpuobj_del(&chan->ramfc);
+
+ nvkm_memory_unref(&chan->userd.mem);
+
+ if (chan->cgrp) {
+ nvkm_chid_put(chan->cgrp->runl->chid, chan->id, &chan->cgrp->lock);
+ nvkm_cgrp_unref(&chan->cgrp);
}
- spin_unlock_irqrestore(&fifo->lock, flags);
if (chan->vmm) {
nvkm_vmm_part(chan->vmm, chan->inst->memory);
@@ -309,85 +289,192 @@ nvkm_fifo_chan_dtor(struct nvkm_object *object)
nvkm_gpuobj_del(&chan->push);
nvkm_gpuobj_del(&chan->inst);
- return data;
+ kfree(chan);
}
-static const struct nvkm_object_func
-nvkm_fifo_chan_func = {
- .dtor = nvkm_fifo_chan_dtor,
- .init = nvkm_fifo_chan_init,
- .fini = nvkm_fifo_chan_fini,
- .ntfy = nvkm_fifo_chan_ntfy,
- .map = nvkm_fifo_chan_map,
- .sclass = nvkm_fifo_chan_child_get,
-};
+void
+nvkm_chan_put(struct nvkm_chan **pchan, unsigned long irqflags)
+{
+ struct nvkm_chan *chan = *pchan;
+
+ if (!chan)
+ return;
+
+ *pchan = NULL;
+ spin_unlock_irqrestore(&chan->cgrp->lock, irqflags);
+}
+
+struct nvkm_chan *
+nvkm_chan_get_inst(struct nvkm_engine *engine, u64 inst, unsigned long *pirqflags)
+{
+ struct nvkm_fifo *fifo = engine->subdev.device->fifo;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ struct nvkm_chan *chan;
+
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn(engn, runl) {
+ if (engine == &fifo->engine || engn->engine == engine) {
+ chan = nvkm_runl_chan_get_inst(runl, inst, pirqflags);
+ if (chan || engn->engine == engine)
+ return chan;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+struct nvkm_chan *
+nvkm_chan_get_chid(struct nvkm_engine *engine, int id, unsigned long *pirqflags)
+{
+ struct nvkm_fifo *fifo = engine->subdev.device->fifo;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn(engn, runl) {
+ if (fifo->chid || engn->engine == engine)
+ return nvkm_runl_chan_get_chid(runl, id, pirqflags);
+ }
+ }
+
+ return NULL;
+}
int
-nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *func,
- struct nvkm_fifo *fifo, u32 size, u32 align, bool zero,
- u64 hvmm, u64 push, u32 engm, int bar, u32 base,
- u32 user, const struct nvkm_oclass *oclass,
- struct nvkm_fifo_chan *chan)
+nvkm_chan_new_(const struct nvkm_chan_func *func, struct nvkm_runl *runl, int runq,
+ struct nvkm_cgrp *cgrp, const char *name, bool priv, u32 devm, struct nvkm_vmm *vmm,
+ struct nvkm_dmaobj *dmaobj, u64 offset, u64 length,
+ struct nvkm_memory *userd, u64 ouserd, struct nvkm_chan **pchan)
{
- struct nvkm_client *client = oclass->client;
+ struct nvkm_fifo *fifo = runl->fifo;
struct nvkm_device *device = fifo->engine.subdev.device;
- struct nvkm_dmaobj *dmaobj;
- unsigned long flags;
+ struct nvkm_chan *chan;
int ret;
- nvkm_object_ctor(&nvkm_fifo_chan_func, oclass, &chan->object);
+ /* Validate arguments against class requirements. */
+ if ((runq && runq >= runl->func->runqs) ||
+ (!func->inst->vmm != !vmm) ||
+ ((func->userd->bar < 0) == !userd) ||
+ (!func->ramfc->ctxdma != !dmaobj) ||
+ ((func->ramfc->devm < devm) && devm != BIT(0)) ||
+ (!func->ramfc->priv && priv)) {
+ RUNL_DEBUG(runl, "args runq:%d:%d vmm:%d:%p userd:%d:%p "
+ "push:%d:%p devm:%08x:%08x priv:%d:%d",
+ runl->func->runqs, runq, func->inst->vmm, vmm,
+ func->userd->bar < 0, userd, func->ramfc->ctxdma, dmaobj,
+ func->ramfc->devm, devm, func->ramfc->priv, priv);
+ return -EINVAL;
+ }
+
+ if (!(chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL)))
+ return -ENOMEM;
+
chan->func = func;
- chan->fifo = fifo;
- chan->engm = engm;
+ strscpy(chan->name, name, sizeof(chan->name));
+ chan->runq = runq;
+ chan->id = -1;
+ spin_lock_init(&chan->lock);
+ atomic_set(&chan->blocked, 1);
+ atomic_set(&chan->errored, 0);
+ INIT_LIST_HEAD(&chan->cctxs);
INIT_LIST_HEAD(&chan->head);
- /* instance memory */
- ret = nvkm_gpuobj_new(device, size, align, zero, NULL, &chan->inst);
- if (ret)
- return ret;
+ /* Join channel group.
+ *
+ * GK110 and newer support channel groups (aka TSGs), where individual channels
+ * share a timeslice, and, engine context(s).
+ *
+ * As such, engine contexts are tracked in nvkm_cgrp and we need them even when
+ * channels aren't in an API channel group, and on HW that doesn't support TSGs.
+ */
+ if (!cgrp) {
+ ret = nvkm_cgrp_new(runl, chan->name, vmm, fifo->func->cgrp.force, &chan->cgrp);
+ if (ret) {
+ RUNL_DEBUG(runl, "cgrp %d", ret);
+ return ret;
+ }
- /* allocate push buffer ctxdma instance */
- if (push) {
- dmaobj = nvkm_dmaobj_search(client, push);
- if (IS_ERR(dmaobj))
- return PTR_ERR(dmaobj);
+ cgrp = chan->cgrp;
+ } else {
+ if (cgrp->runl != runl || cgrp->vmm != vmm) {
+ RUNL_DEBUG(runl, "cgrp %d %d", cgrp->runl != runl, cgrp->vmm != vmm);
+ return -EINVAL;
+ }
- ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16,
- &chan->push);
- if (ret)
- return ret;
+ chan->cgrp = nvkm_cgrp_ref(cgrp);
}
- /* channel address space */
- if (hvmm) {
- struct nvkm_vmm *vmm = nvkm_uvmm_search(client, hvmm);
- if (IS_ERR(vmm))
- return PTR_ERR(vmm);
+ /* Allocate instance block. */
+ ret = nvkm_gpuobj_new(device, func->inst->size, 0x1000, func->inst->zero, NULL,
+ &chan->inst);
+ if (ret) {
+ RUNL_DEBUG(runl, "inst %d", ret);
+ return ret;
+ }
- if (vmm->mmu != device->mmu)
+ /* Initialise virtual address-space. */
+ if (func->inst->vmm) {
+ if (WARN_ON(vmm->mmu != device->mmu))
return -EINVAL;
ret = nvkm_vmm_join(vmm, chan->inst->memory);
- if (ret)
+ if (ret) {
+ RUNL_DEBUG(runl, "vmm %d", ret);
return ret;
+ }
chan->vmm = nvkm_vmm_ref(vmm);
}
- /* allocate channel id */
- spin_lock_irqsave(&fifo->lock, flags);
- chan->chid = find_first_zero_bit(fifo->mask, NVKM_FIFO_CHID_NR);
- if (chan->chid >= NVKM_FIFO_CHID_NR) {
- spin_unlock_irqrestore(&fifo->lock, flags);
+ /* Allocate HW ctxdma for push buffer. */
+ if (func->ramfc->ctxdma) {
+ ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16, &chan->push);
+ if (ret) {
+ RUNL_DEBUG(runl, "bind %d", ret);
+ return ret;
+ }
+ }
+
+ /* Allocate channel ID. */
+ chan->id = nvkm_chid_get(runl->chid, chan);
+ if (chan->id < 0) {
+ RUNL_ERROR(runl, "!chids");
return -ENOSPC;
}
- list_add(&chan->head, &fifo->chan);
- __set_bit(chan->chid, fifo->mask);
- spin_unlock_irqrestore(&fifo->lock, flags);
-
- /* determine address of this channel's user registers */
- chan->addr = device->func->resource_addr(device, bar) +
- base + user * chan->chid;
- chan->size = user;
+
+ if (cgrp->id < 0)
+ cgrp->id = chan->id;
+
+ /* Initialise USERD. */
+ if (func->userd->bar < 0) {
+ if (ouserd + chan->func->userd->size >= nvkm_memory_size(userd)) {
+ RUNL_DEBUG(runl, "ouserd %llx", ouserd);
+ return -EINVAL;
+ }
+
+ ret = nvkm_memory_kmap(userd, &chan->userd.mem);
+ if (ret) {
+ RUNL_DEBUG(runl, "userd %d", ret);
+ return ret;
+ }
+
+ chan->userd.base = ouserd;
+ } else {
+ chan->userd.mem = nvkm_memory_ref(fifo->userd.mem);
+ chan->userd.base = chan->id * chan->func->userd->size;
+ }
+
+ if (chan->func->userd->clear)
+ chan->func->userd->clear(chan);
+
+ /* Initialise RAMFC. */
+ ret = chan->func->ramfc->write(chan, offset, length, devm, priv);
+ if (ret) {
+ RUNL_DEBUG(runl, "ramfc %d", ret);
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
index e53504354841..85b94f699128 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
@@ -1,35 +1,78 @@
/* SPDX-License-Identifier: MIT */
-#ifndef __NVKM_FIFO_CHAN_H__
-#define __NVKM_FIFO_CHAN_H__
-#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object)
-#include "priv.h"
-
-struct nvkm_fifo_chan_func {
- void *(*dtor)(struct nvkm_fifo_chan *);
- void (*init)(struct nvkm_fifo_chan *);
- void (*fini)(struct nvkm_fifo_chan *);
- int (*ntfy)(struct nvkm_fifo_chan *, u32 type, struct nvkm_event **);
- int (*engine_ctor)(struct nvkm_fifo_chan *, struct nvkm_engine *,
- struct nvkm_object *);
- void (*engine_dtor)(struct nvkm_fifo_chan *, struct nvkm_engine *);
- int (*engine_init)(struct nvkm_fifo_chan *, struct nvkm_engine *);
- int (*engine_fini)(struct nvkm_fifo_chan *, struct nvkm_engine *,
- bool suspend);
- int (*object_ctor)(struct nvkm_fifo_chan *, struct nvkm_object *);
- void (*object_dtor)(struct nvkm_fifo_chan *, int);
- u32 (*submit_token)(struct nvkm_fifo_chan *);
+#ifndef __NVKM_CHAN_H__
+#define __NVKM_CHAN_H__
+#include <engine/fifo.h>
+struct nvkm_dmaobj;
+struct nvkm_engn;
+struct nvkm_runl;
+
+extern const struct nvkm_event_func nvkm_chan_event;
+
+struct nvkm_cctx {
+ struct nvkm_vctx *vctx;
+ refcount_t refs;
+ refcount_t uses;
+
+ struct list_head head;
};
-int nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *, struct nvkm_fifo *,
- u32 size, u32 align, bool zero, u64 vm, u64 push,
- u32 engm, int bar, u32 base, u32 user,
- const struct nvkm_oclass *, struct nvkm_fifo_chan *);
+struct nvkm_chan_func {
+ const struct nvkm_chan_func_inst {
+ u32 size;
+ bool zero;
+ bool vmm;
+ } *inst;
-struct nvkm_fifo_chan_oclass {
- int (*ctor)(struct nvkm_fifo *, const struct nvkm_oclass *,
- void *data, u32 size, struct nvkm_object **);
- struct nvkm_sclass base;
+ const struct nvkm_chan_func_userd {
+ int bar;
+ u32 base;
+ u32 size;
+ void (*clear)(struct nvkm_chan *);
+ } *userd;
+
+ const struct nvkm_chan_func_ramfc {
+ const struct nvkm_ramfc_layout {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+ } *layout;
+ int (*write)(struct nvkm_chan *, u64 offset, u64 length, u32 devm, bool priv);
+ void (*clear)(struct nvkm_chan *);
+ bool ctxdma;
+ u32 devm;
+ bool priv;
+ } *ramfc;
+
+ void (*bind)(struct nvkm_chan *);
+ void (*unbind)(struct nvkm_chan *);
+ void (*start)(struct nvkm_chan *);
+ void (*stop)(struct nvkm_chan *);
+ void (*preempt)(struct nvkm_chan *);
+ u32 (*doorbell_handle)(struct nvkm_chan *);
};
-int gf100_fifo_chan_ntfy(struct nvkm_fifo_chan *, u32, struct nvkm_event **);
+int nvkm_chan_new_(const struct nvkm_chan_func *, struct nvkm_runl *, int runq, struct nvkm_cgrp *,
+ const char *name, bool priv, u32 devm, struct nvkm_vmm *, struct nvkm_dmaobj *,
+ u64 offset, u64 length, struct nvkm_memory *userd, u64 userd_bar1,
+ struct nvkm_chan **);
+void nvkm_chan_del(struct nvkm_chan **);
+void nvkm_chan_allow(struct nvkm_chan *);
+void nvkm_chan_block(struct nvkm_chan *);
+void nvkm_chan_error(struct nvkm_chan *, bool preempt);
+void nvkm_chan_insert(struct nvkm_chan *);
+void nvkm_chan_remove(struct nvkm_chan *, bool preempt);
+void nvkm_chan_remove_locked(struct nvkm_chan *);
+int nvkm_chan_preempt(struct nvkm_chan *, bool wait);
+int nvkm_chan_preempt_locked(struct nvkm_chan *, bool wait);
+int nvkm_chan_cctx_get(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx **,
+ struct nvkm_client * /*TODO: remove need for this */);
+void nvkm_chan_cctx_put(struct nvkm_chan *, struct nvkm_cctx **);
+void nvkm_chan_cctx_bind(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx *);
+
+#define CHAN_PRCLI(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:[%s]"f, (c)->id, (c)->name, ##a)
+#define CHAN_PRINT(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:"f, (c)->id, ##a)
+#define CHAN_ERROR(c,f,a...) CHAN_PRCLI((c), ERROR, err, " "f"\n", ##a)
+#define CHAN_TRACE(c,f,a...) CHAN_PRINT((c), TRACE, info, " "f"\n", ##a)
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c
deleted file mode 100644
index 3492c561f2cf..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv50.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-#include <subdev/mmu.h>
-#include <subdev/timer.h>
-
-#include <nvif/cl826e.h>
-
-static int
-g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
- struct nvkm_event **pevent)
-{
- switch (type) {
- case NV826E_V0_NTFY_NON_STALL_INTERRUPT:
- *pevent = &chan->fifo->uevent;
- return 0;
- default:
- break;
- }
- return -EINVAL;
-}
-
-static int
-g84_fifo_chan_engine_addr(struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : return -1;
- case NVKM_ENGINE_GR : return 0x0020;
- case NVKM_ENGINE_VP :
- case NVKM_ENGINE_MSPDEC: return 0x0040;
- case NVKM_ENGINE_MPEG :
- case NVKM_ENGINE_MSPPP : return 0x0060;
- case NVKM_ENGINE_BSP :
- case NVKM_ENGINE_MSVLD : return 0x0080;
- case NVKM_ENGINE_CIPHER:
- case NVKM_ENGINE_SEC : return 0x00a0;
- case NVKM_ENGINE_CE : return 0x00c0;
- default:
- WARN_ON(1);
- return -1;
- }
-}
-
-static int
-g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nv50_fifo *fifo = chan->fifo;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 engn, save;
- int offset;
- bool done;
-
- offset = g84_fifo_chan_engine_addr(engine);
- if (offset < 0)
- return 0;
-
- engn = fifo->base.func->engine_id(&fifo->base, engine) - 1;
- save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn);
- nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);
- done = nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
- break;
- ) >= 0;
- nvkm_wr32(device, 0x002520, save);
- if (!done) {
- nvkm_error(subdev, "channel %d [%s] unload timeout\n",
- chan->base.chid, chan->base.object.client->name);
- if (suspend)
- return -EBUSY;
- }
-
- nvkm_kmap(chan->eng);
- nvkm_wo32(chan->eng, offset + 0x00, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x04, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x08, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
- nvkm_done(chan->eng);
- return 0;
-}
-
-
-static int
-g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nvkm_gpuobj *engn = *nv50_fifo_chan_engine(chan, engine);
- u64 limit, start;
- int offset;
-
- offset = g84_fifo_chan_engine_addr(engine);
- if (offset < 0)
- return 0;
- limit = engn->addr + engn->size - 1;
- start = engn->addr;
-
- nvkm_kmap(chan->eng);
- nvkm_wo32(chan->eng, offset + 0x00, 0x00190000);
- nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit));
- nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start));
- nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
- nvkm_done(chan->eng);
- return 0;
-}
-
-static int
-g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine,
- struct nvkm_object *object)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
-
- if (g84_fifo_chan_engine_addr(engine) < 0)
- return 0;
-
- return nvkm_object_bind(object, NULL, 0, nv50_fifo_chan_engine(chan, engine));
-}
-
-static int
-g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_object *object)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- u32 handle = object->handle;
- u32 context;
-
- switch (object->engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : context = 0x00000000; break;
- case NVKM_ENGINE_GR : context = 0x00100000; break;
- case NVKM_ENGINE_MPEG :
- case NVKM_ENGINE_MSPPP : context = 0x00200000; break;
- case NVKM_ENGINE_ME :
- case NVKM_ENGINE_CE : context = 0x00300000; break;
- case NVKM_ENGINE_VP :
- case NVKM_ENGINE_MSPDEC: context = 0x00400000; break;
- case NVKM_ENGINE_CIPHER:
- case NVKM_ENGINE_SEC :
- case NVKM_ENGINE_VIC : context = 0x00500000; break;
- case NVKM_ENGINE_BSP :
- case NVKM_ENGINE_MSVLD : context = 0x00600000; break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context);
-}
-
-static void
-g84_fifo_chan_init(struct nvkm_fifo_chan *base)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nv50_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u64 addr = chan->ramfc->addr >> 8;
- u32 chid = chan->base.chid;
-
- nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr);
- nv50_fifo_runlist_update(fifo);
-}
-
-static const struct nvkm_fifo_chan_func
-g84_fifo_chan_func = {
- .dtor = nv50_fifo_chan_dtor,
- .init = g84_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .ntfy = g84_fifo_chan_ntfy,
- .engine_ctor = g84_fifo_chan_engine_ctor,
- .engine_dtor = nv50_fifo_chan_engine_dtor,
- .engine_init = g84_fifo_chan_engine_init,
- .engine_fini = g84_fifo_chan_engine_fini,
- .object_ctor = g84_fifo_chan_object_ctor,
- .object_dtor = nv50_fifo_chan_object_dtor,
-};
-
-int
-g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push,
- const struct nvkm_oclass *oclass,
- struct nv50_fifo_chan *chan)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int ret;
-
- if (!vmm)
- return -EINVAL;
-
- ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base,
- 0x10000, 0x1000, false, vmm, push,
- BIT(G84_FIFO_ENGN_SW) |
- BIT(G84_FIFO_ENGN_GR) |
- BIT(G84_FIFO_ENGN_MPEG) |
- BIT(G84_FIFO_ENGN_MSPPP) |
- BIT(G84_FIFO_ENGN_ME) |
- BIT(G84_FIFO_ENGN_CE0) |
- BIT(G84_FIFO_ENGN_VP) |
- BIT(G84_FIFO_ENGN_MSPDEC) |
- BIT(G84_FIFO_ENGN_CIPHER) |
- BIT(G84_FIFO_ENGN_SEC) |
- BIT(G84_FIFO_ENGN_VIC) |
- BIT(G84_FIFO_ENGN_BSP) |
- BIT(G84_FIFO_ENGN_MSVLD) |
- BIT(G84_FIFO_ENGN_DMA),
- 0, 0xc00000, 0x2000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst,
- &chan->eng);
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst,
- &chan->pgd);
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst,
- &chan->cache);
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst,
- &chan->ramfc);
- if (ret)
- return ret;
-
- return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h
deleted file mode 100644
index f7ac1061fa84..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __GF100_FIFO_CHAN_H__
-#define __GF100_FIFO_CHAN_H__
-#define gf100_fifo_chan(p) container_of((p), struct gf100_fifo_chan, base)
-#include "chan.h"
-#include "gf100.h"
-
-struct gf100_fifo_chan {
- struct nvkm_fifo_chan base;
- struct gf100_fifo *fifo;
-
- struct list_head head;
- bool killed;
-
-#define GF100_FIFO_ENGN_GR 0
-#define GF100_FIFO_ENGN_MSPDEC 1
-#define GF100_FIFO_ENGN_MSPPP 2
-#define GF100_FIFO_ENGN_MSVLD 3
-#define GF100_FIFO_ENGN_CE0 4
-#define GF100_FIFO_ENGN_CE1 5
-#define GF100_FIFO_ENGN_SW 15
- struct gf100_fifo_engn {
- struct nvkm_gpuobj *inst;
- struct nvkm_vma *vma;
- } engn[NVKM_FIFO_ENGN_NR];
-};
-
-extern const struct nvkm_fifo_chan_oclass gf100_fifo_gpfifo_oclass;
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
deleted file mode 100644
index 9713daee6c76..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __GK104_FIFO_CHAN_H__
-#define __GK104_FIFO_CHAN_H__
-#define gk104_fifo_chan(p) container_of((p), struct gk104_fifo_chan, base)
-#include "chan.h"
-#include "gk104.h"
-
-struct gk104_fifo_chan {
- struct nvkm_fifo_chan base;
- struct gk104_fifo *fifo;
- int runl;
-
- struct nvkm_fifo_cgrp *cgrp;
- struct list_head head;
- bool killed;
-
-#define GK104_FIFO_ENGN_SW 15
- struct gk104_fifo_engn {
- struct nvkm_gpuobj *inst;
- struct nvkm_vma *vma;
- } engn[NVKM_FIFO_ENGN_NR];
-};
-
-extern const struct nvkm_fifo_chan_func gk104_fifo_gpfifo_func;
-
-int gk104_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
- void *data, u32 size, struct nvkm_object **);
-void *gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *);
-void gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *);
-void gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *);
-struct gk104_fifo_engn *gk104_fifo_gpfifo_engine(struct gk104_fifo_chan *, struct nvkm_engine *);
-int gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *, struct nvkm_engine *,
- struct nvkm_object *);
-void gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *,
- struct nvkm_engine *);
-int gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *);
-int gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *);
-
-int gv100_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
- void *data, u32 size, struct nvkm_object **);
-int gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *,
- struct gk104_fifo *, u64 *, u16 *, u64, u64, u64,
- u64 *, bool, u32 *, const struct nvkm_oclass *,
- struct nvkm_object **);
-int gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *,
- struct nvkm_engine *);
-int gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *,
- struct nvkm_engine *, bool);
-
-int tu102_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
- void *data, u32 size, struct nvkm_object **);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h
deleted file mode 100644
index 727bc8976b40..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NV04_FIFO_CHAN_H__
-#define __NV04_FIFO_CHAN_H__
-#define nv04_fifo_chan(p) container_of((p), struct nv04_fifo_chan, base)
-#include "chan.h"
-#include "nv04.h"
-
-struct nv04_fifo_chan {
- struct nvkm_fifo_chan base;
- struct nv04_fifo *fifo;
- u32 ramfc;
-#define NV04_FIFO_ENGN_SW 0
-#define NV04_FIFO_ENGN_GR 1
-#define NV04_FIFO_ENGN_MPEG 2
-#define NV04_FIFO_ENGN_DMA 3
- struct nvkm_gpuobj *engn[NVKM_FIFO_ENGN_NR];
-};
-
-extern const struct nvkm_fifo_chan_func nv04_fifo_dma_func;
-void *nv04_fifo_dma_dtor(struct nvkm_fifo_chan *);
-void nv04_fifo_dma_init(struct nvkm_fifo_chan *);
-void nv04_fifo_dma_fini(struct nvkm_fifo_chan *);
-void nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *, int);
-
-extern const struct nvkm_fifo_chan_oclass nv04_fifo_dma_oclass;
-extern const struct nvkm_fifo_chan_oclass nv10_fifo_dma_oclass;
-extern const struct nvkm_fifo_chan_oclass nv17_fifo_dma_oclass;
-extern const struct nvkm_fifo_chan_oclass nv40_fifo_dma_oclass;
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c
deleted file mode 100644
index c44d7c81dd52..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv50.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-#include <subdev/mmu.h>
-#include <subdev/timer.h>
-
-static int
-nv50_fifo_chan_engine_addr(struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : return -1;
- case NVKM_ENGINE_GR : return 0x0000;
- case NVKM_ENGINE_MPEG : return 0x0060;
- default:
- WARN_ON(1);
- return -1;
- }
-}
-
-struct nvkm_gpuobj **
-nv50_fifo_chan_engine(struct nv50_fifo_chan *chan, struct nvkm_engine *engine)
-{
- int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine);
- if (engi >= 0)
- return &chan->engn[engi];
- return NULL;
-}
-
-static int
-nv50_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nv50_fifo *fifo = chan->fifo;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- int offset, ret = 0;
- u32 me;
-
- offset = nv50_fifo_chan_engine_addr(engine);
- if (offset < 0)
- return 0;
-
- /* HW bug workaround:
- *
- * PFIFO will hang forever if the connected engines don't report
- * that they've processed the context switch request.
- *
- * In order for the kickoff to work, we need to ensure all the
- * connected engines are in a state where they can answer.
- *
- * Newer chipsets don't seem to suffer from this issue, and well,
- * there's also a "ignore these engines" bitmask reg we can use
- * if we hit the issue there..
- */
- me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001);
-
- /* do the kickoff... */
- nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
- break;
- ) < 0) {
- nvkm_error(subdev, "channel %d [%s] unload timeout\n",
- chan->base.chid, chan->base.object.client->name);
- if (suspend)
- ret = -EBUSY;
- }
- nvkm_wr32(device, 0x00b860, me);
-
- if (ret == 0) {
- nvkm_kmap(chan->eng);
- nvkm_wo32(chan->eng, offset + 0x00, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x04, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x08, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
- nvkm_done(chan->eng);
- }
-
- return ret;
-}
-
-static int
-nv50_fifo_chan_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nvkm_gpuobj *engn = *nv50_fifo_chan_engine(chan, engine);
- u64 limit, start;
- int offset;
-
- offset = nv50_fifo_chan_engine_addr(engine);
- if (offset < 0)
- return 0;
- limit = engn->addr + engn->size - 1;
- start = engn->addr;
-
- nvkm_kmap(chan->eng);
- nvkm_wo32(chan->eng, offset + 0x00, 0x00190000);
- nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit));
- nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start));
- nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
- nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
- nvkm_done(chan->eng);
- return 0;
-}
-
-void
-nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- nvkm_gpuobj_del(nv50_fifo_chan_engine(chan, engine));
-}
-
-static int
-nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine,
- struct nvkm_object *object)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
-
- if (nv50_fifo_chan_engine_addr(engine) < 0)
- return 0;
-
- return nvkm_object_bind(object, NULL, 0, nv50_fifo_chan_engine(chan, engine));
-}
-
-void
-nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *base, int cookie)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- nvkm_ramht_remove(chan->ramht, cookie);
-}
-
-static int
-nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_object *object)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- u32 handle = object->handle;
- u32 context;
-
- switch (object->engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : context = 0x00000000; break;
- case NVKM_ENGINE_GR : context = 0x00100000; break;
- case NVKM_ENGINE_MPEG : context = 0x00200000; break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context);
-}
-
-void
-nv50_fifo_chan_fini(struct nvkm_fifo_chan *base)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nv50_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 chid = chan->base.chid;
-
- /* remove channel from runlist, fifo will unload context */
- nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
- nv50_fifo_runlist_update(fifo);
- nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000);
-}
-
-static void
-nv50_fifo_chan_init(struct nvkm_fifo_chan *base)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- struct nv50_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u64 addr = chan->ramfc->addr >> 12;
- u32 chid = chan->base.chid;
-
- nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr);
- nv50_fifo_runlist_update(fifo);
-}
-
-void *
-nv50_fifo_chan_dtor(struct nvkm_fifo_chan *base)
-{
- struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
- nvkm_ramht_del(&chan->ramht);
- nvkm_gpuobj_del(&chan->pgd);
- nvkm_gpuobj_del(&chan->eng);
- nvkm_gpuobj_del(&chan->cache);
- nvkm_gpuobj_del(&chan->ramfc);
- return chan;
-}
-
-static const struct nvkm_fifo_chan_func
-nv50_fifo_chan_func = {
- .dtor = nv50_fifo_chan_dtor,
- .init = nv50_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .engine_ctor = nv50_fifo_chan_engine_ctor,
- .engine_dtor = nv50_fifo_chan_engine_dtor,
- .engine_init = nv50_fifo_chan_engine_init,
- .engine_fini = nv50_fifo_chan_engine_fini,
- .object_ctor = nv50_fifo_chan_object_ctor,
- .object_dtor = nv50_fifo_chan_object_dtor,
-};
-
-int
-nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push,
- const struct nvkm_oclass *oclass,
- struct nv50_fifo_chan *chan)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int ret;
-
- if (!vmm)
- return -EINVAL;
-
- ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base,
- 0x10000, 0x1000, false, vmm, push,
- BIT(NV50_FIFO_ENGN_SW) |
- BIT(NV50_FIFO_ENGN_GR) |
- BIT(NV50_FIFO_ENGN_MPEG) |
- BIT(NV50_FIFO_ENGN_DMA),
- 0, 0xc00000, 0x2000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->base.inst,
- &chan->ramfc);
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->base.inst,
- &chan->eng);
- if (ret)
- return ret;
-
- ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst,
- &chan->pgd);
- if (ret)
- return ret;
-
- return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h
deleted file mode 100644
index 3a95730d7ff5..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NV50_FIFO_CHAN_H__
-#define __NV50_FIFO_CHAN_H__
-#define nv50_fifo_chan(p) container_of((p), struct nv50_fifo_chan, base)
-#include "chan.h"
-#include "nv50.h"
-
-struct nv50_fifo_chan {
- struct nv50_fifo *fifo;
- struct nvkm_fifo_chan base;
-
- struct nvkm_gpuobj *ramfc;
- struct nvkm_gpuobj *cache;
- struct nvkm_gpuobj *eng;
- struct nvkm_gpuobj *pgd;
- struct nvkm_ramht *ramht;
-
-#define NV50_FIFO_ENGN_SW 0
-#define NV50_FIFO_ENGN_GR 1
-#define NV50_FIFO_ENGN_MPEG 2
-#define NV50_FIFO_ENGN_DMA 3
-
-#define G84_FIFO_ENGN_SW 0
-#define G84_FIFO_ENGN_GR 1
-#define G84_FIFO_ENGN_MPEG 2
-#define G84_FIFO_ENGN_MSPPP 2
-#define G84_FIFO_ENGN_ME 3
-#define G84_FIFO_ENGN_CE0 3
-#define G84_FIFO_ENGN_VP 4
-#define G84_FIFO_ENGN_MSPDEC 4
-#define G84_FIFO_ENGN_CIPHER 5
-#define G84_FIFO_ENGN_SEC 5
-#define G84_FIFO_ENGN_VIC 5
-#define G84_FIFO_ENGN_BSP 6
-#define G84_FIFO_ENGN_MSVLD 6
-#define G84_FIFO_ENGN_DMA 7
- struct nvkm_gpuobj *engn[NVKM_FIFO_ENGN_NR];
-};
-
-int nv50_fifo_chan_ctor(struct nv50_fifo *, u64 vmm, u64 push,
- const struct nvkm_oclass *, struct nv50_fifo_chan *);
-void *nv50_fifo_chan_dtor(struct nvkm_fifo_chan *);
-void nv50_fifo_chan_fini(struct nvkm_fifo_chan *);
-struct nvkm_gpuobj **nv50_fifo_chan_engine(struct nv50_fifo_chan *, struct nvkm_engine *);
-void nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *, struct nvkm_engine *);
-void nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *, int);
-
-int g84_fifo_chan_ctor(struct nv50_fifo *, u64 vmm, u64 push,
- const struct nvkm_oclass *, struct nv50_fifo_chan *);
-
-extern const struct nvkm_fifo_chan_oclass nv50_fifo_gpfifo_oclass;
-extern const struct nvkm_fifo_chan_oclass g84_fifo_gpfifo_oclass;
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c
new file mode 100644
index 000000000000..23944d95efd5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "chid.h"
+
+void
+nvkm_chid_put(struct nvkm_chid *chid, int id, spinlock_t *data_lock)
+{
+ if (id >= 0) {
+ spin_lock_irq(&chid->lock);
+ spin_lock(data_lock);
+ chid->data[id] = NULL;
+ spin_unlock(data_lock);
+ clear_bit(id, chid->used);
+ spin_unlock_irq(&chid->lock);
+ }
+}
+
+int
+nvkm_chid_get(struct nvkm_chid *chid, void *data)
+{
+ int id = -1, cid;
+
+ spin_lock_irq(&chid->lock);
+ cid = find_first_zero_bit(chid->used, chid->nr);
+ if (cid < chid->nr) {
+ set_bit(cid, chid->used);
+ chid->data[cid] = data;
+ id = cid;
+ }
+ spin_unlock_irq(&chid->lock);
+ return id;
+}
+
+static void
+nvkm_chid_del(struct kref *kref)
+{
+ struct nvkm_chid *chid = container_of(kref, typeof(*chid), kref);
+
+ nvkm_event_fini(&chid->event);
+
+ kvfree(chid->data);
+ kfree(chid);
+}
+
+void
+nvkm_chid_unref(struct nvkm_chid **pchid)
+{
+ struct nvkm_chid *chid = *pchid;
+
+ if (!chid)
+ return;
+
+ kref_put(&chid->kref, nvkm_chid_del);
+ *pchid = NULL;
+}
+
+struct nvkm_chid *
+nvkm_chid_ref(struct nvkm_chid *chid)
+{
+ if (chid)
+ kref_get(&chid->kref);
+
+ return chid;
+}
+
+int
+nvkm_chid_new(const struct nvkm_event_func *func, struct nvkm_subdev *subdev,
+ int nr, int first, int count, struct nvkm_chid **pchid)
+{
+ struct nvkm_chid *chid;
+ int id;
+
+ if (!(chid = *pchid = kzalloc(struct_size(chid, used, nr), GFP_KERNEL)))
+ return -ENOMEM;
+
+ kref_init(&chid->kref);
+ chid->nr = nr;
+ chid->mask = chid->nr - 1;
+ spin_lock_init(&chid->lock);
+
+ if (!(chid->data = kvzalloc(sizeof(*chid->data) * nr, GFP_KERNEL))) {
+ nvkm_chid_unref(pchid);
+ return -ENOMEM;
+ }
+
+ for (id = 0; id < first; id++)
+ __set_bit(id, chid->used);
+ for (id = first + count; id < nr; id++)
+ __set_bit(id, chid->used);
+
+ return nvkm_event_init(func, subdev, 1, nr, &chid->event);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h
new file mode 100644
index 000000000000..2a42efb18401
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_CHID_H__
+#define __NVKM_CHID_H__
+#include <core/event.h>
+
+struct nvkm_chid {
+ struct kref kref;
+ int nr;
+ u32 mask;
+
+ struct nvkm_event event;
+
+ void **data;
+
+ spinlock_t lock;
+ unsigned long used[];
+};
+
+int nvkm_chid_new(const struct nvkm_event_func *, struct nvkm_subdev *,
+ int nr, int first, int count, struct nvkm_chid **pchid);
+struct nvkm_chid *nvkm_chid_ref(struct nvkm_chid *);
+void nvkm_chid_unref(struct nvkm_chid **);
+int nvkm_chid_get(struct nvkm_chid *, void *data);
+void nvkm_chid_put(struct nvkm_chid *, int id, spinlock_t *data_lock);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
deleted file mode 100644
index dbcdc5fab990..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv04.h"
-#include "regsnv04.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-#include <subdev/instmem.h>
-
-#include <nvif/class.h>
-#include <nvif/cl006b.h>
-#include <nvif/unpack.h>
-
-void
-nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem;
-
- mutex_lock(&chan->fifo->base.mutex);
- nvkm_ramht_remove(imem->ramht, cookie);
- mutex_unlock(&chan->fifo->base.mutex);
-}
-
-static int
-nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_object *object)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem;
- u32 context = 0x80000000 | chan->base.chid << 24;
- u32 handle = object->handle;
- int hash;
-
- switch (object->engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : context |= 0x00000000; break;
- case NVKM_ENGINE_GR : context |= 0x00010000; break;
- case NVKM_ENGINE_MPEG : context |= 0x00020000; break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- mutex_lock(&chan->fifo->base.mutex);
- hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4,
- handle, context);
- mutex_unlock(&chan->fifo->base.mutex);
- return hash;
-}
-
-void
-nv04_fifo_dma_fini(struct nvkm_fifo_chan *base)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nv04_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_memory *fctx = device->imem->ramfc;
- const struct nv04_fifo_ramfc *c;
- unsigned long flags;
- u32 mask = fifo->base.nr - 1;
- u32 data = chan->ramfc;
- u32 chid;
-
- /* prevent fifo context switches */
- spin_lock_irqsave(&fifo->base.lock, flags);
- nvkm_wr32(device, NV03_PFIFO_CACHES, 0);
-
- /* if this channel is active, replace it with a null context */
- chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask;
- if (chid == chan->base.chid) {
- nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0);
- nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
-
- c = fifo->ramfc;
- nvkm_kmap(fctx);
- do {
- u32 rm = ((1ULL << c->bits) - 1) << c->regs;
- u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
- u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs;
- u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm);
- nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
- } while ((++c)->bits);
- nvkm_done(fctx);
-
- c = fifo->ramfc;
- do {
- nvkm_wr32(device, c->regp, 0x00000000);
- } while ((++c)->bits);
-
- nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1);
- nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1);
- }
-
- /* restore normal operation, after disabling dma mode */
- nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
- nvkm_wr32(device, NV03_PFIFO_CACHES, 1);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-}
-
-void
-nv04_fifo_dma_init(struct nvkm_fifo_chan *base)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nv04_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 mask = 1 << chan->base.chid;
- unsigned long flags;
- spin_lock_irqsave(&fifo->base.lock, flags);
- nvkm_mask(device, NV04_PFIFO_MODE, mask, mask);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-}
-
-void *
-nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nv04_fifo *fifo = chan->fifo;
- struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem;
- const struct nv04_fifo_ramfc *c = fifo->ramfc;
-
- nvkm_kmap(imem->ramfc);
- do {
- nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000);
- } while ((++c)->bits);
- nvkm_done(imem->ramfc);
- return chan;
-}
-
-const struct nvkm_fifo_chan_func
-nv04_fifo_dma_func = {
- .dtor = nv04_fifo_dma_dtor,
- .init = nv04_fifo_dma_init,
- .fini = nv04_fifo_dma_fini,
- .object_ctor = nv04_fifo_dma_object_ctor,
- .object_dtor = nv04_fifo_dma_object_dtor,
-};
-
-static int
-nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nv04_fifo_chan *chan = NULL;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
- "offset %08x\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base,
- 0x1000, 0x1000, false, 0, args->v0.pushbuf,
- BIT(NV04_FIFO_ENGN_SW) |
- BIT(NV04_FIFO_ENGN_GR) |
- BIT(NV04_FIFO_ENGN_DMA),
- 0, 0x800000, 0x10000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- chan->ramfc = chan->base.chid * 32;
-
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.push->addr >> 4);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x10,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- nvkm_done(imem->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-nv04_fifo_dma_oclass = {
- .base.oclass = NV03_CHANNEL_DMA,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = nv04_fifo_dma_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c
deleted file mode 100644
index 07d80d54a07c..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv04.h"
-#include "regsnv04.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <subdev/instmem.h>
-
-#include <nvif/class.h>
-#include <nvif/cl006b.h>
-#include <nvif/unpack.h>
-
-static int
-nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nv04_fifo_chan *chan = NULL;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
- "offset %08x\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base,
- 0x1000, 0x1000, false, 0, args->v0.pushbuf,
- BIT(NV04_FIFO_ENGN_SW) |
- BIT(NV04_FIFO_ENGN_GR) |
- BIT(NV04_FIFO_ENGN_DMA),
- 0, 0x800000, 0x10000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- chan->ramfc = chan->base.chid * 32;
-
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x14,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- nvkm_done(imem->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-nv10_fifo_dma_oclass = {
- .base.oclass = NV10_CHANNEL_DMA,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = nv10_fifo_dma_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c
deleted file mode 100644
index edd70a114218..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv04.h"
-#include "regsnv04.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <subdev/instmem.h>
-
-#include <nvif/class.h>
-#include <nvif/cl006b.h>
-#include <nvif/unpack.h>
-
-static int
-nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nv04_fifo_chan *chan = NULL;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
- "offset %08x\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base,
- 0x1000, 0x1000, false, 0, args->v0.pushbuf,
- BIT(NV04_FIFO_ENGN_SW) |
- BIT(NV04_FIFO_ENGN_GR) |
- BIT(NV04_FIFO_ENGN_MPEG) | /* NV31- */
- BIT(NV04_FIFO_ENGN_DMA),
- 0, 0x800000, 0x10000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- chan->ramfc = chan->base.chid * 64;
-
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x14,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- nvkm_done(imem->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-nv17_fifo_dma_oclass = {
- .base.oclass = NV17_CHANNEL_DMA,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = nv17_fifo_dma_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c
deleted file mode 100644
index 0411fb908457..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv04.h"
-#include "regsnv04.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-#include <subdev/instmem.h>
-
-#include <nvif/class.h>
-#include <nvif/cl006b.h>
-#include <nvif/unpack.h>
-
-static bool
-nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW:
- return false;
- case NVKM_ENGINE_GR:
- *reg = 0x0032e0;
- *ctx = 0x38;
- return true;
- case NVKM_ENGINE_MPEG:
- if (engine->subdev.device->chipset < 0x44)
- return false;
- *reg = 0x00330c;
- *ctx = 0x54;
- return true;
- default:
- WARN_ON(1);
- return false;
- }
-}
-
-static struct nvkm_gpuobj **
-nv40_fifo_dma_engn(struct nv04_fifo_chan *chan, struct nvkm_engine *engine)
-{
- int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine);
- if (engi >= 0)
- return &chan->engn[engi];
- return NULL;
-}
-
-static int
-nv40_fifo_dma_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nv04_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- unsigned long flags;
- u32 reg, ctx;
- int chid;
-
- if (!nv40_fifo_dma_engine(engine, &reg, &ctx))
- return 0;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- nvkm_mask(device, 0x002500, 0x00000001, 0x00000000);
-
- chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1);
- if (chid == chan->base.chid)
- nvkm_wr32(device, reg, 0x00000000);
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000);
- nvkm_done(imem->ramfc);
-
- nvkm_mask(device, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
- return 0;
-}
-
-static int
-nv40_fifo_dma_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nv04_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- unsigned long flags;
- u32 inst, reg, ctx;
- int chid;
-
- if (!nv40_fifo_dma_engine(engine, &reg, &ctx))
- return 0;
- inst = (*nv40_fifo_dma_engn(chan, engine))->addr >> 4;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- nvkm_mask(device, 0x002500, 0x00000001, 0x00000000);
-
- chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1);
- if (chid == chan->base.chid)
- nvkm_wr32(device, reg, inst);
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + ctx, inst);
- nvkm_done(imem->ramfc);
-
- nvkm_mask(device, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
- return 0;
-}
-
-static void
-nv40_fifo_dma_engine_dtor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- nvkm_gpuobj_del(nv40_fifo_dma_engn(chan, engine));
-}
-
-static int
-nv40_fifo_dma_engine_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine,
- struct nvkm_object *object)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- u32 reg, ctx;
-
- if (!nv40_fifo_dma_engine(engine, &reg, &ctx))
- return 0;
-
- return nvkm_object_bind(object, NULL, 0, nv40_fifo_dma_engn(chan, engine));
-}
-
-static int
-nv40_fifo_dma_object_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_object *object)
-{
- struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
- struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem;
- u32 context = chan->base.chid << 23;
- u32 handle = object->handle;
- int hash;
-
- switch (object->engine->subdev.type) {
- case NVKM_ENGINE_DMAOBJ:
- case NVKM_ENGINE_SW : context |= 0x00000000; break;
- case NVKM_ENGINE_GR : context |= 0x00100000; break;
- case NVKM_ENGINE_MPEG : context |= 0x00200000; break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- mutex_lock(&chan->fifo->base.mutex);
- hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4,
- handle, context);
- mutex_unlock(&chan->fifo->base.mutex);
- return hash;
-}
-
-static const struct nvkm_fifo_chan_func
-nv40_fifo_dma_func = {
- .dtor = nv04_fifo_dma_dtor,
- .init = nv04_fifo_dma_init,
- .fini = nv04_fifo_dma_fini,
- .engine_ctor = nv40_fifo_dma_engine_ctor,
- .engine_dtor = nv40_fifo_dma_engine_dtor,
- .engine_init = nv40_fifo_dma_engine_init,
- .engine_fini = nv40_fifo_dma_engine_fini,
- .object_ctor = nv40_fifo_dma_object_ctor,
- .object_dtor = nv04_fifo_dma_object_dtor,
-};
-
-static int
-nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nv04_fifo_chan *chan = NULL;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_instmem *imem = device->imem;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
- "offset %08x\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base,
- 0x1000, 0x1000, false, 0, args->v0.pushbuf,
- BIT(NV04_FIFO_ENGN_SW) |
- BIT(NV04_FIFO_ENGN_GR) |
- BIT(NV04_FIFO_ENGN_MPEG) |
- BIT(NV04_FIFO_ENGN_DMA),
- 0, 0xc00000, 0x1000, oclass, &chan->base);
- chan->fifo = fifo;
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- chan->ramfc = chan->base.chid * 128;
-
- nvkm_kmap(imem->ramfc);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 |
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
- nvkm_done(imem->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-nv40_fifo_dma_oclass = {
- .base.oclass = NV40_CHANNEL_DMA,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = nv40_fifo_dma_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
index 3885c3830b94..6b229a3fbd97 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
@@ -21,112 +21,211 @@
*
* Authors: Ben Skeggs
*/
-#include "nv50.h"
-#include "channv50.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "runl.h"
+
+#include <core/ramht.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
static void
-g84_fifo_uevent_fini(struct nvkm_fifo *fifo)
+g84_chan_bind(struct nvkm_chan *chan)
{
- struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x40000000, 0x00000000);
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x002600 + (chan->id * 4), chan->ramfc->addr >> 8);
}
-static void
-g84_fifo_uevent_init(struct nvkm_fifo *fifo)
+static int
+g84_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
{
- struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x40000000, 0x40000000);
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+ const u32 limit2 = ilog2(length / 8);
+ int ret;
+
+ ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->inst, &chan->eng);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->inst, &chan->pgd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->inst, &chan->cache);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->inst, &chan->ramfc);
+ if (ret)
+ return ret;
+
+ ret = nvkm_ramht_new(device, 0x8000, 16, chan->inst, &chan->ramht);
+ if (ret)
+ return ret;
+
+ nvkm_kmap(chan->ramfc);
+ nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078);
+ nvkm_wo32(chan->ramfc, 0x44, 0x01003fff);
+ nvkm_wo32(chan->ramfc, 0x48, chan->push->node->offset >> 4);
+ nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(offset));
+ nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff);
+ nvkm_wo32(chan->ramfc, 0x78, 0x00000000);
+ nvkm_wo32(chan->ramfc, 0x7c, 0x30000000 | devm);
+ nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj->node->offset >> 4));
+ nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10);
+ nvkm_wo32(chan->ramfc, 0x98, chan->inst->addr >> 12);
+ nvkm_done(chan->ramfc);
+ return 0;
}
-static struct nvkm_engine *
-g84_fifo_id_engine(struct nvkm_fifo *fifo, int engi)
+static const struct nvkm_chan_func_ramfc
+g84_chan_ramfc = {
+ .write = g84_chan_ramfc_write,
+ .ctxdma = true,
+ .devm = 0xfff,
+};
+
+const struct nvkm_chan_func
+g84_chan = {
+ .inst = &nv50_chan_inst,
+ .userd = &nv50_chan_userd,
+ .ramfc = &g84_chan_ramfc,
+ .bind = g84_chan_bind,
+ .unbind = nv50_chan_unbind,
+ .start = nv50_chan_start,
+ .stop = nv50_chan_stop,
+};
+
+static void
+g84_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
{
- struct nvkm_device *device = fifo->engine.subdev.device;
- struct nvkm_engine *engine;
- enum nvkm_subdev_type type;
-
- switch (engi) {
- case G84_FIFO_ENGN_SW : type = NVKM_ENGINE_SW; break;
- case G84_FIFO_ENGN_GR : type = NVKM_ENGINE_GR; break;
- case G84_FIFO_ENGN_MPEG :
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSPPP, 0)))
- return engine;
- type = NVKM_ENGINE_MPEG;
- break;
- case G84_FIFO_ENGN_ME :
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_CE, 0)))
- return engine;
- type = NVKM_ENGINE_ME;
- break;
- case G84_FIFO_ENGN_VP :
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSPDEC, 0)))
- return engine;
- type = NVKM_ENGINE_VP;
- break;
- case G84_FIFO_ENGN_CIPHER:
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_VIC, 0)))
- return engine;
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_SEC, 0)))
- return engine;
- type = NVKM_ENGINE_CIPHER;
- break;
- case G84_FIFO_ENGN_BSP :
- if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSVLD, 0)))
- return engine;
- type = NVKM_ENGINE_BSP;
- break;
- case G84_FIFO_ENGN_DMA : type = NVKM_ENGINE_DMAOBJ; break;
+ struct nvkm_subdev *subdev = &chan->cgrp->runl->fifo->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u64 start = 0, limit = 0;
+ u32 flags = 0, ptr0, save;
+
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_GR : ptr0 = 0x0020; break;
+ case NVKM_ENGINE_VP :
+ case NVKM_ENGINE_MSPDEC: ptr0 = 0x0040; break;
+ case NVKM_ENGINE_MPEG :
+ case NVKM_ENGINE_MSPPP : ptr0 = 0x0060; break;
+ case NVKM_ENGINE_BSP :
+ case NVKM_ENGINE_MSVLD : ptr0 = 0x0080; break;
+ case NVKM_ENGINE_CIPHER:
+ case NVKM_ENGINE_SEC : ptr0 = 0x00a0; break;
+ case NVKM_ENGINE_CE : ptr0 = 0x00c0; break;
default:
WARN_ON(1);
- return NULL;
+ return;
+ }
+
+ if (!cctx) {
+ save = nvkm_mask(device, 0x002520, 0x0000003f, BIT(engn->id - 1));
+ nvkm_wr32(device, 0x0032fc, chan->inst->addr >> 12);
+ nvkm_msec(device, 2000,
+ if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
+ break;
+ );
+ nvkm_wr32(device, 0x002520, save);
+ } else {
+ flags = 0x00190000;
+ start = cctx->vctx->inst->addr;
+ limit = start + cctx->vctx->inst->size - 1;
}
- return nvkm_device_engine(fifo->engine.subdev.device, type, 0);
+ nvkm_kmap(chan->eng);
+ nvkm_wo32(chan->eng, ptr0 + 0x00, flags);
+ nvkm_wo32(chan->eng, ptr0 + 0x04, lower_32_bits(limit));
+ nvkm_wo32(chan->eng, ptr0 + 0x08, lower_32_bits(start));
+ nvkm_wo32(chan->eng, ptr0 + 0x0c, upper_32_bits(limit) << 24 |
+ lower_32_bits(start));
+ nvkm_wo32(chan->eng, ptr0 + 0x10, 0x00000000);
+ nvkm_wo32(chan->eng, ptr0 + 0x14, 0x00000000);
+ nvkm_done(chan->eng);
}
+const struct nvkm_engn_func
+g84_engn = {
+ .bind = g84_ectx_bind,
+ .ramht_add = nv50_eobj_ramht_add,
+ .ramht_del = nv50_eobj_ramht_del,
+};
+
+static void
+g84_fifo_nonstall_block(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x40000000, 0x00000000);
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+static void
+g84_fifo_nonstall_allow(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x40000000, 0x40000000);
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+const struct nvkm_event_func
+g84_fifo_nonstall = {
+ .init = g84_fifo_nonstall_allow,
+ .fini = g84_fifo_nonstall_block,
+};
+
static int
-g84_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine)
+g84_fifo_runl_ctor(struct nvkm_fifo *fifo)
{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_SW : return G84_FIFO_ENGN_SW;
- case NVKM_ENGINE_GR : return G84_FIFO_ENGN_GR;
- case NVKM_ENGINE_MPEG :
- case NVKM_ENGINE_MSPPP : return G84_FIFO_ENGN_MPEG;
- case NVKM_ENGINE_CE : return G84_FIFO_ENGN_CE0;
- case NVKM_ENGINE_VP :
- case NVKM_ENGINE_MSPDEC: return G84_FIFO_ENGN_VP;
- case NVKM_ENGINE_CIPHER:
- case NVKM_ENGINE_SEC : return G84_FIFO_ENGN_CIPHER;
- case NVKM_ENGINE_BSP :
- case NVKM_ENGINE_MSVLD : return G84_FIFO_ENGN_BSP;
- case NVKM_ENGINE_DMAOBJ: return G84_FIFO_ENGN_DMA;
- default:
- WARN_ON(1);
- return -1;
- }
+ struct nvkm_runl *runl;
+
+ runl = nvkm_runl_new(fifo, 0, 0, 0);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
+
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0);
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0);
+ nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_GR, 0);
+ nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MPEG, 0);
+ nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_ME, 0);
+ nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_VP, 0);
+ nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_CIPHER, 0);
+ nvkm_runl_add(runl, 6, fifo->func->engn, NVKM_ENGINE_BSP, 0);
+ return 0;
}
static const struct nvkm_fifo_func
g84_fifo = {
- .dtor = nv50_fifo_dtor,
- .oneinit = nv50_fifo_oneinit,
+ .chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = nv50_fifo_chid_ctor,
+ .runl_ctor = g84_fifo_runl_ctor,
.init = nv50_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = g84_fifo_engine_id,
- .id_engine = g84_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .uevent_init = g84_fifo_uevent_init,
- .uevent_fini = g84_fifo_uevent_fini,
- .chan = {
- &g84_fifo_gpfifo_oclass,
- NULL
- },
+ .nonstall = &g84_fifo_nonstall,
+ .runl = &nv50_runl,
+ .engn = &g84_engn,
+ .engn_sw = &nv50_engn_sw,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, G82_CHANNEL_GPFIFO }, &g84_chan },
};
int
g84_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv50_fifo_new_(&g84_fifo, device, type, inst, pfifo);
+ return nvkm_fifo_new_(&g84_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c
new file mode 100644
index 000000000000..c6ca050c38bf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+#include "chan.h"
+#include "runl.h"
+
+#include <nvif/class.h>
+
+static int
+g98_fifo_runl_ctor(struct nvkm_fifo *fifo)
+{
+ struct nvkm_runl *runl;
+
+ runl = nvkm_runl_new(fifo, 0, 0, 0);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
+
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0);
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0);
+ nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_GR, 0);
+ nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MSPPP, 0);
+ nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_CE, 0);
+ nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_MSPDEC, 0);
+ nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_SEC, 0);
+ nvkm_runl_add(runl, 6, fifo->func->engn, NVKM_ENGINE_MSVLD, 0);
+ return 0;
+}
+
+static const struct nvkm_fifo_func
+g98_fifo = {
+ .chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = nv50_fifo_chid_ctor,
+ .runl_ctor = g98_fifo_runl_ctor,
+ .init = nv50_fifo_init,
+ .intr = nv04_fifo_intr,
+ .pause = nv04_fifo_pause,
+ .start = nv04_fifo_start,
+ .nonstall = &g84_fifo_nonstall,
+ .runl = &nv50_runl,
+ .engn = &g84_engn,
+ .engn_sw = &nv50_engn_sw,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, G82_CHANNEL_GPFIFO }, &g84_chan },
+};
+
+int
+g98_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_fifo **pfifo)
+{
+ return nvkm_fifo_new_(&g98_fifo, device, type, inst, pfifo);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
new file mode 100644
index 000000000000..12a5d99d5e77
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+#include "runq.h"
+
+#include <core/gpuobj.h>
+#include <subdev/top.h>
+#include <subdev/vfn.h>
+
+#include <nvif/class.h>
+
+/*TODO: allocate? */
+#define GA100_FIFO_NONSTALL_VECTOR 0
+
+static u32
+ga100_chan_doorbell_handle(struct nvkm_chan *chan)
+{
+ return (chan->cgrp->runl->doorbell << 16) | chan->id;
+}
+
+static void
+ga100_chan_stop(struct nvkm_chan *chan)
+{
+ struct nvkm_runl *runl = chan->cgrp->runl;
+
+ nvkm_wr32(runl->fifo->engine.subdev.device, runl->chan + (chan->id * 4), 0x00000003);
+}
+
+static void
+ga100_chan_start(struct nvkm_chan *chan)
+{
+ struct nvkm_runl *runl = chan->cgrp->runl;
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ const int gfid = 0;
+
+ nvkm_wr32(device, runl->chan + (chan->id * 4), 0x00000002);
+ nvkm_wr32(device, runl->addr + 0x0090, (gfid << 16) | chan->id); /* INTERNAL_DOORBELL. */
+}
+
+static void
+ga100_chan_unbind(struct nvkm_chan *chan)
+{
+ struct nvkm_runl *runl = chan->cgrp->runl;
+
+ nvkm_wr32(runl->fifo->engine.subdev.device, runl->chan + (chan->id * 4), 0xffffffff);
+}
+
+static int
+ga100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ const u32 limit2 = ilog2(length / 8);
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x010, 0x0000face);
+ nvkm_wo32(chan->inst, 0x030, 0x7ffff902);
+ nvkm_wo32(chan->inst, 0x048, lower_32_bits(offset));
+ nvkm_wo32(chan->inst, 0x04c, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->inst, 0x084, 0x20400000);
+ nvkm_wo32(chan->inst, 0x094, 0x30000000 | devm);
+ nvkm_wo32(chan->inst, 0x0e4, priv ? 0x00000020 : 0x00000000);
+ nvkm_wo32(chan->inst, 0x0e8, chan->id);
+ nvkm_wo32(chan->inst, 0x0f4, 0x00001000 | (priv ? 0x00000100 : 0x00000000));
+ nvkm_wo32(chan->inst, 0x0f8, 0x80000000 | GA100_FIFO_NONSTALL_VECTOR);
+ nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000);
+ nvkm_done(chan->inst);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+ga100_chan_ramfc = {
+ .write = ga100_chan_ramfc_write,
+ .devm = 0xfff,
+ .priv = true,
+};
+
+const struct nvkm_chan_func
+ga100_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gv100_chan_userd,
+ .ramfc = &ga100_chan_ramfc,
+ .unbind = ga100_chan_unbind,
+ .start = ga100_chan_start,
+ .stop = ga100_chan_stop,
+ .preempt = gk110_chan_preempt,
+ .doorbell_handle = ga100_chan_doorbell_handle,
+};
+
+static void
+ga100_cgrp_preempt(struct nvkm_cgrp *cgrp)
+{
+ struct nvkm_runl *runl = cgrp->runl;
+
+ nvkm_wr32(runl->fifo->engine.subdev.device, runl->addr + 0x098, 0x01000000 | cgrp->id);
+}
+
+const struct nvkm_cgrp_func
+ga100_cgrp = {
+ .preempt = ga100_cgrp_preempt,
+};
+
+static int
+ga100_engn_cxid(struct nvkm_engn *engn, bool *cgid)
+{
+ struct nvkm_runl *runl = engn->runl;
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u32 stat = nvkm_rd32(device, runl->addr + 0x200 + engn->id * 0x40);
+
+ ENGN_DEBUG(engn, "status %08x", stat);
+ *cgid = true;
+
+ switch ((stat & 0x0000e000) >> 13) {
+ case 0 /* INVALID */: return -ENODEV;
+ case 1 /* VALID */:
+ case 5 /* SAVE */: return (stat & 0x00000fff);
+ case 6 /* LOAD */: return (stat & 0x0fff0000) >> 16;
+ case 7 /* SWITCH */:
+ if (nvkm_engine_chsw_load(engn->engine))
+ return (stat & 0x0fff0000) >> 16;
+ return (stat & 0x00000fff);
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ return -ENODEV;
+}
+
+const struct nvkm_engn_func
+ga100_engn = {
+ .cxid = ga100_engn_cxid,
+ .ctor = gk104_ectx_ctor,
+ .bind = gv100_ectx_bind,
+};
+
+const struct nvkm_engn_func
+ga100_engn_ce = {
+ .cxid = ga100_engn_cxid,
+ .ctor = gv100_ectx_ce_ctor,
+ .bind = gv100_ectx_ce_bind,
+};
+
+static bool
+ga100_runq_idle(struct nvkm_runq *runq)
+{
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
+
+ return !(nvkm_rd32(device, 0x04015c + (runq->id * 0x800)) & 0x0000e000);
+}
+
+static bool
+ga100_runq_intr_1(struct nvkm_runq *runq, struct nvkm_runl *runl)
+{
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
+ u32 inte = nvkm_rd32(device, 0x040180 + (runq->id * 0x800));
+ u32 intr = nvkm_rd32(device, 0x040148 + (runq->id * 0x800));
+ u32 stat = intr & inte;
+
+ if (!stat) {
+ RUNQ_DEBUG(runq, "inte1 %08x %08x", intr, inte);
+ return false;
+ }
+
+ if (stat & 0x80000000) {
+ u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x0800)) & runl->chid->mask;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+
+ RUNQ_ERROR(runq, "CTXNOTVALID chid:%d", chid);
+ chan = nvkm_runl_chan_get_chid(runl, chid, &flags);
+ if (chan) {
+ nvkm_chan_error(chan, true);
+ nvkm_chan_put(&chan, flags);
+ }
+
+ nvkm_mask(device, 0x0400ac + (runq->id * 0x800), 0x00030000, 0x00030000);
+ stat &= ~0x80000000;
+ }
+
+ if (stat) {
+ RUNQ_ERROR(runq, "intr1 %08x", stat);
+ nvkm_wr32(device, 0x0401a0 + (runq->id * 0x800), stat);
+ }
+
+ nvkm_wr32(device, 0x040148 + (runq->id * 0x800), intr);
+ return true;
+}
+
+static bool
+ga100_runq_intr_0(struct nvkm_runq *runq, struct nvkm_runl *runl)
+{
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
+ u32 inte = nvkm_rd32(device, 0x040170 + (runq->id * 0x800));
+ u32 intr = nvkm_rd32(device, 0x040108 + (runq->id * 0x800));
+ u32 stat = intr & inte;
+
+ if (!stat) {
+ RUNQ_DEBUG(runq, "inte0 %08x %08x", intr, inte);
+ return false;
+ }
+
+ /*TODO: expand on this when fixing up gf100's version. */
+ if (stat & 0xc6afe000) {
+ u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x0800)) & runl->chid->mask;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+
+ RUNQ_ERROR(runq, "intr0 %08x", stat);
+ chan = nvkm_runl_chan_get_chid(runl, chid, &flags);
+ if (chan) {
+ nvkm_chan_error(chan, true);
+ nvkm_chan_put(&chan, flags);
+ }
+
+ stat &= ~0xc6afe000;
+ }
+
+ if (stat) {
+ RUNQ_ERROR(runq, "intr0 %08x", stat);
+ nvkm_wr32(device, 0x040190 + (runq->id * 0x800), stat);
+ }
+
+ nvkm_wr32(device, 0x040108 + (runq->id * 0x800), intr);
+ return true;
+}
+
+static bool
+ga100_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *runl)
+{
+ bool intr0 = ga100_runq_intr_0(runq, runl);
+ bool intr1 = ga100_runq_intr_1(runq, runl);
+
+ return intr0 || intr1;
+}
+
+static void
+ga100_runq_init(struct nvkm_runq *runq)
+{
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x040108 + (runq->id * 0x800), 0xffffffff); /* INTR_0 */
+ nvkm_wr32(device, 0x040148 + (runq->id * 0x800), 0xffffffff); /* INTR_1 */
+ nvkm_wr32(device, 0x040170 + (runq->id * 0x800), 0xffffffff); /* INTR_0_EN_SET_TREE */
+ nvkm_wr32(device, 0x040180 + (runq->id * 0x800), 0xffffffff); /* INTR_1_EN_SET_TREE */
+}
+
+const struct nvkm_runq_func
+ga100_runq = {
+ .init = ga100_runq_init,
+ .intr = ga100_runq_intr,
+ .idle = ga100_runq_idle,
+};
+
+static bool
+ga100_runl_preempt_pending(struct nvkm_runl *runl)
+{
+ return nvkm_rd32(runl->fifo->engine.subdev.device, runl->addr + 0x098) & 0x00100000;
+}
+
+static void
+ga100_runl_preempt(struct nvkm_runl *runl)
+{
+ nvkm_wr32(runl->fifo->engine.subdev.device, runl->addr + 0x098, 0x00000000);
+}
+
+static void
+ga100_runl_allow(struct nvkm_runl *runl, u32 engm)
+{
+ nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x094, 0x00000001, 0x00000000);
+}
+
+static void
+ga100_runl_block(struct nvkm_runl *runl, u32 engm)
+{
+ nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x094, 0x00000001, 0x00000001);
+}
+
+static bool
+ga100_runl_pending(struct nvkm_runl *runl)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+
+ return nvkm_rd32(device, runl->addr + 0x08c) & 0x00008000;
+}
+
+static void
+ga100_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u64 addr = nvkm_memory_addr(memory) + start;
+
+ nvkm_wr32(device, runl->addr + 0x080, lower_32_bits(addr));
+ nvkm_wr32(device, runl->addr + 0x084, upper_32_bits(addr));
+ nvkm_wr32(device, runl->addr + 0x088, count);
+}
+
+static irqreturn_t
+ga100_runl_intr(struct nvkm_inth *inth)
+{
+ struct nvkm_runl *runl = container_of(inth, typeof(*runl), inth);
+ struct nvkm_engn *engn;
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u32 inte = nvkm_rd32(device, runl->addr + 0x120);
+ u32 intr = nvkm_rd32(device, runl->addr + 0x100);
+ u32 stat = intr & inte;
+ u32 info;
+
+ if (!stat) {
+ RUNL_DEBUG(runl, "inte %08x %08x", intr, inte);
+ return IRQ_NONE;
+ }
+
+ if (stat & 0x00000007) {
+ nvkm_runl_foreach_engn_cond(engn, runl, stat & BIT(engn->id)) {
+ info = nvkm_rd32(device, runl->addr + 0x224 + (engn->id * 0x40));
+
+ tu102_fifo_intr_ctxsw_timeout_info(engn, info);
+
+ nvkm_wr32(device, runl->addr + 0x100, BIT(engn->id));
+ stat &= ~BIT(engn->id);
+ }
+ }
+
+ if (stat & 0x00000300) {
+ nvkm_wr32(device, runl->addr + 0x100, stat & 0x00000300);
+ stat &= ~0x00000300;
+ }
+
+ if (stat & 0x00010000) {
+ if (runl->runq[0]) {
+ if (runl->runq[0]->func->intr(runl->runq[0], runl))
+ stat &= ~0x00010000;
+ }
+ }
+
+ if (stat & 0x00020000) {
+ if (runl->runq[1]) {
+ if (runl->runq[1]->func->intr(runl->runq[1], runl))
+ stat &= ~0x00020000;
+ }
+ }
+
+ if (stat) {
+ RUNL_ERROR(runl, "intr %08x", stat);
+ nvkm_wr32(device, runl->addr + 0x140, stat);
+ }
+
+ nvkm_wr32(device, runl->addr + 0x180, 0x00000001);
+ return IRQ_HANDLED;
+}
+
+static void
+ga100_runl_fini(struct nvkm_runl *runl)
+{
+ nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x300, 0x80000000, 0x00000000);
+ nvkm_inth_block(&runl->inth);
+}
+
+static void
+ga100_runl_init(struct nvkm_runl *runl)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_runq *runq;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ int i;
+
+ /* Submit NULL runlist and preempt. */
+ nvkm_wr32(device, runl->addr + 0x088, 0x00000000);
+ runl->func->preempt(runl);
+
+ /* Enable doorbell. */
+ nvkm_mask(device, runl->addr + 0x300, 0x80000000, 0x80000000);
+
+ nvkm_wr32(device, runl->addr + 0x100, 0xffffffff); /* INTR_0 */
+ nvkm_wr32(device, runl->addr + 0x140, 0xffffffff); /* INTR_0_EN_CLEAR_TREE(0) */
+ nvkm_wr32(device, runl->addr + 0x120, 0x000f1307); /* INTR_0_EN_SET_TREE(0) */
+ nvkm_wr32(device, runl->addr + 0x148, 0xffffffff); /* INTR_0_EN_CLEAR_TREE(1) */
+ nvkm_wr32(device, runl->addr + 0x128, 0x00000000); /* INTR_0_EN_SET_TREE(1) */
+
+ /* Init PBDMA(s). */
+ for (i = 0; i < runl->runq_nr; i++) {
+ runq = runl->runq[i];
+ runq->func->init(runq);
+ }
+
+ nvkm_inth_allow(&runl->inth);
+}
+
+const struct nvkm_runl_func
+ga100_runl = {
+ .init = ga100_runl_init,
+ .fini = ga100_runl_fini,
+ .size = 16,
+ .update = nv50_runl_update,
+ .insert_cgrp = gv100_runl_insert_cgrp,
+ .insert_chan = gv100_runl_insert_chan,
+ .commit = ga100_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = ga100_runl_pending,
+ .block = ga100_runl_block,
+ .allow = ga100_runl_allow,
+ .preempt = ga100_runl_preempt,
+ .preempt_pending = ga100_runl_preempt_pending,
+};
+
+static int
+ga100_runl_new(struct nvkm_fifo *fifo, int id, u32 addr, struct nvkm_runl **prunl)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_runl *runl;
+ u32 chcfg = nvkm_rd32(device, addr + 0x004);
+ u32 chnum = 1 << (chcfg & 0x0000000f);
+ u32 chaddr = (chcfg & 0xfffffff0);
+ u32 dbcfg = nvkm_rd32(device, addr + 0x008);
+ u32 vector = nvkm_rd32(device, addr + 0x160);
+ int i, ret;
+
+ runl = *prunl = nvkm_runl_new(fifo, id, addr, chnum);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
+
+ for (i = 0; i < 2; i++) {
+ u32 pbcfg = nvkm_rd32(device, addr + 0x010 + (i * 0x04));
+ if (pbcfg & 0x80000000) {
+ runl->runq[runl->runq_nr] =
+ nvkm_runq_new(fifo, ((pbcfg & 0x03fffc00) - 0x040000) / 0x800);
+ if (!runl->runq[runl->runq_nr])
+ return -ENOMEM;
+
+ runl->runq_nr++;
+ }
+ }
+
+ ret = nvkm_inth_add(&device->vfn->intr, vector & 0x00000fff, NVKM_INTR_PRIO_NORMAL,
+ &fifo->engine.subdev, ga100_runl_intr, &runl->inth);
+ if (ret)
+ return ret;
+
+ runl->chan = chaddr;
+ runl->doorbell = dbcfg >> 16;
+ return 0;
+}
+
+static irqreturn_t
+ga100_fifo_nonstall_intr(struct nvkm_inth *inth)
+{
+ struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), nonstall.intr);
+
+ nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
+ return IRQ_HANDLED;
+}
+
+static void
+ga100_fifo_nonstall_block(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+
+ nvkm_inth_block(&fifo->nonstall.intr);
+}
+
+static void
+ga100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+
+ nvkm_inth_allow(&fifo->nonstall.intr);
+}
+
+const struct nvkm_event_func
+ga100_fifo_nonstall = {
+ .init = ga100_fifo_nonstall_allow,
+ .fini = ga100_fifo_nonstall_block,
+};
+
+int
+ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo)
+{
+ return nvkm_inth_add(&fifo->engine.subdev.device->vfn->intr, GA100_FIFO_NONSTALL_VECTOR,
+ NVKM_INTR_PRIO_NORMAL, &fifo->engine.subdev, ga100_fifo_nonstall_intr,
+ &fifo->nonstall.intr);
+}
+
+int
+ga100_fifo_runl_ctor(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_top_device *tdev;
+ struct nvkm_runl *runl;
+ int id = 0, ret;
+
+ nvkm_list_foreach(tdev, &device->top->device, head, tdev->runlist >= 0) {
+ runl = nvkm_runl_get(fifo, -1, tdev->runlist);
+ if (!runl) {
+ ret = ga100_runl_new(fifo, id++, tdev->runlist, &runl);
+ if (ret)
+ return ret;
+ }
+
+ if (tdev->engine < 0)
+ continue;
+
+ nvkm_runl_add(runl, tdev->engine, (tdev->type == NVKM_ENGINE_CE) ?
+ fifo->func->engn_ce : fifo->func->engn, tdev->type, tdev->inst);
+ }
+
+ return 0;
+}
+
+static const struct nvkm_fifo_func
+ga100_fifo = {
+ .runl_ctor = ga100_fifo_runl_ctor,
+ .mmu_fault = &tu102_fifo_mmu_fault,
+ .nonstall_ctor = ga100_fifo_nonstall_ctor,
+ .nonstall = &ga100_fifo_nonstall,
+ .runl = &ga100_runl,
+ .runq = &ga100_runq,
+ .engn = &ga100_engn,
+ .engn_ce = &ga100_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &ga100_cgrp, .force = true },
+ .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_A }, &ga100_chan },
+};
+
+int
+ga100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_fifo **pfifo)
+{
+ return nvkm_fifo_new_(&ga100_fifo, device, type, inst, pfifo);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
index c630dbd2911a..2cdf5da339b6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c
@@ -19,293 +19,27 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#define ga102_fifo(p) container_of((p), struct ga102_fifo, base.engine)
-#define ga102_chan(p) container_of((p), struct ga102_chan, object)
-#include <engine/fifo.h>
-#include "user.h"
+#include "priv.h"
-#include <core/memory.h>
-#include <subdev/mmu.h>
-#include <subdev/timer.h>
-#include <subdev/top.h>
-
-#include <nvif/cl0080.h>
-#include <nvif/clc36f.h>
#include <nvif/class.h>
-struct ga102_fifo {
- struct nvkm_fifo base;
-};
-
-struct ga102_chan {
- struct nvkm_object object;
-
- struct {
- u32 runl;
- u32 chan;
- } ctrl;
-
- struct nvkm_memory *mthd;
- struct nvkm_memory *inst;
- struct nvkm_memory *user;
- struct nvkm_memory *runl;
-
- struct nvkm_vmm *vmm;
-};
-
-static int
-ga102_chan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
-{
- if (index == 0) {
- oclass->ctor = nvkm_object_new;
- oclass->base = (struct nvkm_sclass) { -1, -1, AMPERE_DMA_COPY_B };
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int
-ga102_chan_map(struct nvkm_object *object, void *argv, u32 argc,
- enum nvkm_object_map *type, u64 *addr, u64 *size)
-{
- struct ga102_chan *chan = ga102_chan(object);
- struct nvkm_device *device = chan->object.engine->subdev.device;
- u64 bar2 = nvkm_memory_bar2(chan->user);
-
- if (bar2 == ~0ULL)
- return -EFAULT;
-
- *type = NVKM_OBJECT_MAP_IO;
- *addr = device->func->resource_addr(device, 3) + bar2;
- *size = 0x1000;
- return 0;
-}
-
-static int
-ga102_chan_fini(struct nvkm_object *object, bool suspend)
-{
- struct ga102_chan *chan = ga102_chan(object);
- struct nvkm_device *device = chan->object.engine->subdev.device;
-
- nvkm_wr32(device, chan->ctrl.chan, 0x00000003);
-
- nvkm_wr32(device, chan->ctrl.runl + 0x098, 0x01000000);
- nvkm_msec(device, 2000,
- if (!(nvkm_rd32(device, chan->ctrl.runl + 0x098) & 0x00100000))
- break;
- );
-
- nvkm_wr32(device, chan->ctrl.runl + 0x088, 0);
-
- nvkm_wr32(device, chan->ctrl.chan, 0xffffffff);
- return 0;
-}
-
-static int
-ga102_chan_init(struct nvkm_object *object)
-{
- struct ga102_chan *chan = ga102_chan(object);
- struct nvkm_device *device = chan->object.engine->subdev.device;
-
- nvkm_mask(device, chan->ctrl.runl + 0x300, 0x80000000, 0x80000000);
-
- nvkm_wr32(device, chan->ctrl.runl + 0x080, lower_32_bits(nvkm_memory_addr(chan->runl)));
- nvkm_wr32(device, chan->ctrl.runl + 0x084, upper_32_bits(nvkm_memory_addr(chan->runl)));
- nvkm_wr32(device, chan->ctrl.runl + 0x088, 2);
-
- nvkm_wr32(device, chan->ctrl.chan, 0x00000002);
- nvkm_wr32(device, chan->ctrl.runl + 0x0090, 0);
- return 0;
-}
-
-static void *
-ga102_chan_dtor(struct nvkm_object *object)
-{
- struct ga102_chan *chan = ga102_chan(object);
-
- if (chan->vmm) {
- nvkm_vmm_part(chan->vmm, chan->inst);
- nvkm_vmm_unref(&chan->vmm);
- }
-
- nvkm_memory_unref(&chan->runl);
- nvkm_memory_unref(&chan->user);
- nvkm_memory_unref(&chan->inst);
- nvkm_memory_unref(&chan->mthd);
- return chan;
-}
-
-static const struct nvkm_object_func
-ga102_chan = {
- .dtor = ga102_chan_dtor,
- .init = ga102_chan_init,
- .fini = ga102_chan_fini,
- .map = ga102_chan_map,
- .sclass = ga102_chan_sclass,
-};
-
-static int
-ga102_chan_new(struct nvkm_device *device,
- const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject)
-{
- struct volta_channel_gpfifo_a_v0 *args = argv;
- struct nvkm_top_device *tdev;
- struct nvkm_vmm *vmm;
- struct ga102_chan *chan;
- int ret;
-
- if (argc != sizeof(*args))
- return -ENOSYS;
-
- vmm = nvkm_uvmm_search(oclass->client, args->vmm);
- if (IS_ERR(vmm))
- return PTR_ERR(vmm);
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
-
- nvkm_object_ctor(&ga102_chan, oclass, &chan->object);
- *pobject = &chan->object;
-
- list_for_each_entry(tdev, &device->top->device, head) {
- if (tdev->type == NVKM_ENGINE_CE) {
- chan->ctrl.runl = tdev->runlist;
- break;
- }
- }
-
- if (!chan->ctrl.runl)
- return -ENODEV;
-
- chan->ctrl.chan = nvkm_rd32(device, chan->ctrl.runl + 0x004) & 0xfffffff0;
-
- args->chid = 0;
- args->inst = 0;
- args->token = nvkm_rd32(device, chan->ctrl.runl + 0x008) & 0xffff0000;
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->mthd);
- if (ret)
- return ret;
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->inst);
- if (ret)
- return ret;
-
- nvkm_kmap(chan->inst);
- nvkm_wo32(chan->inst, 0x010, 0x0000face);
- nvkm_wo32(chan->inst, 0x030, 0x7ffff902);
- nvkm_wo32(chan->inst, 0x048, lower_32_bits(args->ioffset));
- nvkm_wo32(chan->inst, 0x04c, upper_32_bits(args->ioffset) |
- (order_base_2(args->ilength / 8) << 16));
- nvkm_wo32(chan->inst, 0x084, 0x20400000);
- nvkm_wo32(chan->inst, 0x094, 0x30000001);
- nvkm_wo32(chan->inst, 0x0ac, 0x00020000);
- nvkm_wo32(chan->inst, 0x0e4, 0x00000000);
- nvkm_wo32(chan->inst, 0x0e8, 0);
- nvkm_wo32(chan->inst, 0x0f4, 0x00001000);
- nvkm_wo32(chan->inst, 0x0f8, 0x10003080);
- nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000);
- nvkm_wo32(chan->inst, 0x220, lower_32_bits(nvkm_memory_bar2(chan->mthd)));
- nvkm_wo32(chan->inst, 0x224, upper_32_bits(nvkm_memory_bar2(chan->mthd)));
- nvkm_done(chan->inst);
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->user);
- if (ret)
- return ret;
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->runl);
- if (ret)
- return ret;
-
- nvkm_kmap(chan->runl);
- nvkm_wo32(chan->runl, 0x00, 0x80030001);
- nvkm_wo32(chan->runl, 0x04, 1);
- nvkm_wo32(chan->runl, 0x08, 0);
- nvkm_wo32(chan->runl, 0x0c, 0x00000000);
- nvkm_wo32(chan->runl, 0x10, lower_32_bits(nvkm_memory_addr(chan->user)));
- nvkm_wo32(chan->runl, 0x14, upper_32_bits(nvkm_memory_addr(chan->user)));
- nvkm_wo32(chan->runl, 0x18, lower_32_bits(nvkm_memory_addr(chan->inst)));
- nvkm_wo32(chan->runl, 0x1c, upper_32_bits(nvkm_memory_addr(chan->inst)));
- nvkm_done(chan->runl);
-
- ret = nvkm_vmm_join(vmm, chan->inst);
- if (ret)
- return ret;
-
- chan->vmm = nvkm_vmm_ref(vmm);
- return 0;
-}
-
-static const struct nvkm_device_oclass
-ga102_chan_oclass = {
- .ctor = ga102_chan_new,
-};
-
-static int
-ga102_user_new(struct nvkm_device *device,
- const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject)
-{
- return tu102_fifo_user_new(oclass, argv, argc, pobject);
-}
-
-static const struct nvkm_device_oclass
-ga102_user_oclass = {
- .ctor = ga102_user_new,
-};
-
-static int
-ga102_fifo_sclass(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class)
-{
- if (index == 0) {
- oclass->base = (struct nvkm_sclass) { -1, -1, VOLTA_USERMODE_A };
- *class = &ga102_user_oclass;
- return 0;
- } else
- if (index == 1) {
- oclass->base = (struct nvkm_sclass) { 0, 0, AMPERE_CHANNEL_GPFIFO_B };
- *class = &ga102_chan_oclass;
- return 0;
- }
-
- return 2;
-}
-
-static int
-ga102_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
-{
- switch (mthd) {
- case NV_DEVICE_HOST_CHANNELS: *data = 1; return 0;
- default:
- break;
- }
-
- return -ENOSYS;
-}
-
-static void *
-ga102_fifo_dtor(struct nvkm_engine *engine)
-{
- return ga102_fifo(engine);
-}
-
-static const struct nvkm_engine_func
+static const struct nvkm_fifo_func
ga102_fifo = {
- .dtor = ga102_fifo_dtor,
- .info = ga102_fifo_info,
- .base.sclass = ga102_fifo_sclass,
+ .runl_ctor = ga100_fifo_runl_ctor,
+ .mmu_fault = &tu102_fifo_mmu_fault,
+ .nonstall_ctor = ga100_fifo_nonstall_ctor,
+ .nonstall = &ga100_fifo_nonstall,
+ .runl = &ga100_runl,
+ .runq = &ga100_runq,
+ .engn = &ga100_engn,
+ .engn_ce = &ga100_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &ga100_cgrp, .force = true },
+ .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_B }, &ga100_chan },
};
int
ga102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- struct ga102_fifo *fifo;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
-
- nvkm_engine_ctor(&ga102_fifo, device, type, inst, true, &fifo->base.engine);
- *pfifo = &fifo->base;
- return 0;
+ return nvkm_fifo_new_(&ga102_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
index 8b4f36b3e34b..5bb65258c36d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
@@ -21,186 +21,456 @@
*
* Authors: Ben Skeggs
*/
-#include "gf100.h"
-#include "changf100.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+#include "runq.h"
-#include <core/client.h>
-#include <core/enum.h>
#include <core/gpuobj.h>
#include <subdev/bar.h>
#include <subdev/fault.h>
+#include <subdev/mc.h>
+#include <subdev/mmu.h>
#include <engine/sw.h>
#include <nvif/class.h>
+void
+gf100_chan_preempt(struct nvkm_chan *chan)
+{
+ nvkm_wr32(chan->cgrp->runl->fifo->engine.subdev.device, 0x002634, chan->id);
+}
+
static void
-gf100_fifo_uevent_init(struct nvkm_fifo *fifo)
+gf100_chan_stop(struct nvkm_chan *chan)
{
- struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x80000000, 0x80000000);
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_mask(device, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
}
static void
-gf100_fifo_uevent_fini(struct nvkm_fifo *fifo)
+gf100_chan_start(struct nvkm_chan *chan)
{
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x003004 + (chan->id * 8), 0x001f0001);
+}
+
+static void gf100_fifo_intr_engine(struct nvkm_fifo *);
+
+static void
+gf100_chan_unbind(struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x80000000, 0x00000000);
+
+ /*TODO: Is this cargo-culted, or necessary? RM does *something* here... Why? */
+ gf100_fifo_intr_engine(fifo);
+
+ nvkm_wr32(device, 0x003000 + (chan->id * 8), 0x00000000);
}
+static void
+gf100_chan_bind(struct nvkm_chan *chan)
+{
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x003000 + (chan->id * 8), 0xc0000000 | chan->inst->addr >> 12);
+}
+
+static int
+gf100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
+ const u32 limit2 = ilog2(length / 8);
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x08, lower_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x0c, upper_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x10, 0x0000face);
+ nvkm_wo32(chan->inst, 0x30, 0xfffff902);
+ nvkm_wo32(chan->inst, 0x48, lower_32_bits(offset));
+ nvkm_wo32(chan->inst, 0x4c, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->inst, 0x54, 0x00000002);
+ nvkm_wo32(chan->inst, 0x84, 0x20400000);
+ nvkm_wo32(chan->inst, 0x94, 0x30000000 | devm);
+ nvkm_wo32(chan->inst, 0x9c, 0x00000100);
+ nvkm_wo32(chan->inst, 0xa4, 0x1f1f1f1f);
+ nvkm_wo32(chan->inst, 0xa8, 0x1f1f1f1f);
+ nvkm_wo32(chan->inst, 0xac, 0x0000001f);
+ nvkm_wo32(chan->inst, 0xb8, 0xf8000000);
+ nvkm_wo32(chan->inst, 0xf8, 0x10003080); /* 0x002310 */
+ nvkm_wo32(chan->inst, 0xfc, 0x10000010); /* 0x002350 */
+ nvkm_done(chan->inst);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+gf100_chan_ramfc = {
+ .write = gf100_chan_ramfc_write,
+ .devm = 0xfff,
+};
+
void
-gf100_fifo_runlist_commit(struct gf100_fifo *fifo)
+gf100_chan_userd_clear(struct nvkm_chan *chan)
{
- struct gf100_fifo_chan *chan;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_memory *cur;
- int nr = 0;
- int target;
+ nvkm_kmap(chan->userd.mem);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x040, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x044, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x048, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x04c, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x050, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x058, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x05c, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x060, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x088, 0x00000000);
+ nvkm_wo32(chan->userd.mem, chan->userd.base + 0x08c, 0x00000000);
+ nvkm_done(chan->userd.mem);
+}
- mutex_lock(&fifo->base.mutex);
- cur = fifo->runlist.mem[fifo->runlist.active];
- fifo->runlist.active = !fifo->runlist.active;
+static const struct nvkm_chan_func_userd
+gf100_chan_userd = {
+ .bar = 1,
+ .size = 0x1000,
+ .clear = gf100_chan_userd_clear,
+};
- nvkm_kmap(cur);
- list_for_each_entry(chan, &fifo->chan, head) {
- nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid);
- nvkm_wo32(cur, (nr * 8) + 4, 0x00000004);
- nr++;
- }
- nvkm_done(cur);
+const struct nvkm_chan_func_inst
+gf100_chan_inst = {
+ .size = 0x1000,
+ .zero = true,
+ .vmm = true,
+};
- switch (nvkm_memory_target(cur)) {
- case NVKM_MEM_TARGET_VRAM: target = 0; break;
- case NVKM_MEM_TARGET_NCOH: target = 3; break;
+static const struct nvkm_chan_func
+gf100_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gf100_chan_userd,
+ .ramfc = &gf100_chan_ramfc,
+ .bind = gf100_chan_bind,
+ .unbind = gf100_chan_unbind,
+ .start = gf100_chan_start,
+ .stop = gf100_chan_stop,
+ .preempt = gf100_chan_preempt,
+};
+
+static void
+gf100_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
+{
+ u64 addr = 0ULL;
+ u32 ptr0;
+
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_SW : return;
+ case NVKM_ENGINE_GR : ptr0 = 0x0210; break;
+ case NVKM_ENGINE_CE : ptr0 = 0x0230 + (engn->engine->subdev.inst * 0x10); break;
+ case NVKM_ENGINE_MSPDEC: ptr0 = 0x0250; break;
+ case NVKM_ENGINE_MSPPP : ptr0 = 0x0260; break;
+ case NVKM_ENGINE_MSVLD : ptr0 = 0x0270; break;
default:
- mutex_unlock(&fifo->base.mutex);
WARN_ON(1);
return;
}
- nvkm_wr32(device, 0x002270, (nvkm_memory_addr(cur) >> 12) |
- (target << 28));
- nvkm_wr32(device, 0x002274, 0x01f00000 | nr);
+ if (cctx) {
+ addr = cctx->vctx->vma->addr;
+ addr |= 4ULL;
+ }
- if (wait_event_timeout(fifo->runlist.wait,
- !(nvkm_rd32(device, 0x00227c) & 0x00100000),
- msecs_to_jiffies(2000)) == 0)
- nvkm_error(subdev, "runlist update timeout\n");
- mutex_unlock(&fifo->base.mutex);
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, ptr0 + 0, lower_32_bits(addr));
+ nvkm_wo32(chan->inst, ptr0 + 4, upper_32_bits(addr));
+ nvkm_done(chan->inst);
}
-void
-gf100_fifo_runlist_remove(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+static int
+gf100_ectx_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx)
+{
+ int ret;
+
+ ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma);
+ if (ret)
+ return ret;
+
+ return nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, NULL, 0);
+}
+
+bool
+gf100_engn_mmu_fault_triggered(struct nvkm_engn *engn)
{
- mutex_lock(&fifo->base.mutex);
- list_del_init(&chan->head);
- mutex_unlock(&fifo->base.mutex);
+ struct nvkm_runl *runl = engn->runl;
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ u32 data = nvkm_rd32(device, 0x002a30 + (engn->id * 4));
+
+ ENGN_DEBUG(engn, "%08x: mmu fault triggered", data);
+ if (!(data & 0x00000100))
+ return false;
+
+ spin_lock(&fifo->lock);
+ nvkm_mask(device, 0x002a30 + (engn->id * 4), 0x00000100, 0x00000000);
+ if (atomic_dec_and_test(&runl->rc_triggered))
+ nvkm_mask(device, 0x002140, 0x00000100, 0x00000100);
+ spin_unlock(&fifo->lock);
+ return true;
}
void
-gf100_fifo_runlist_insert(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+gf100_engn_mmu_fault_trigger(struct nvkm_engn *engn)
{
- mutex_lock(&fifo->base.mutex);
- list_add_tail(&chan->head, &fifo->chan);
- mutex_unlock(&fifo->base.mutex);
+ struct nvkm_runl *runl = engn->runl;
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+
+ ENGN_DEBUG(engn, "triggering mmu fault on 0x%02x", engn->fault);
+ spin_lock(&fifo->lock);
+ if (atomic_inc_return(&runl->rc_triggered) == 1)
+ nvkm_mask(device, 0x002140, 0x00000100, 0x00000000);
+ nvkm_wr32(device, 0x002100, 0x00000100);
+ nvkm_wr32(device, 0x002a30 + (engn->id * 4), 0x00000100 | engn->fault);
+ spin_unlock(&fifo->lock);
}
-static struct nvkm_engine *
-gf100_fifo_id_engine(struct nvkm_fifo *fifo, int engi)
+/*TODO: clean all this up. */
+struct gf100_engn_status {
+ bool busy;
+ bool save;
+ bool unk0;
+ bool unk1;
+ u8 chid;
+};
+
+static void
+gf100_engn_status(struct nvkm_engn *engn, struct gf100_engn_status *status)
{
- enum nvkm_subdev_type type;
- int inst;
+ u32 stat = nvkm_rd32(engn->engine->subdev.device, 0x002640 + (engn->id * 4));
- switch (engi) {
- case GF100_FIFO_ENGN_GR : type = NVKM_ENGINE_GR ; inst = 0; break;
- case GF100_FIFO_ENGN_MSPDEC: type = NVKM_ENGINE_MSPDEC; inst = 0; break;
- case GF100_FIFO_ENGN_MSPPP : type = NVKM_ENGINE_MSPPP ; inst = 0; break;
- case GF100_FIFO_ENGN_MSVLD : type = NVKM_ENGINE_MSVLD ; inst = 0; break;
- case GF100_FIFO_ENGN_CE0 : type = NVKM_ENGINE_CE ; inst = 0; break;
- case GF100_FIFO_ENGN_CE1 : type = NVKM_ENGINE_CE ; inst = 1; break;
- case GF100_FIFO_ENGN_SW : type = NVKM_ENGINE_SW ; inst = 0; break;
- default:
- WARN_ON(1);
- return NULL;
- }
+ status->busy = (stat & 0x10000000);
+ status->save = (stat & 0x00100000);
+ status->unk0 = (stat & 0x00004000);
+ status->unk1 = (stat & 0x00001000);
+ status->chid = (stat & 0x0000007f);
- return nvkm_device_engine(fifo->engine.subdev.device, type, inst);
+ ENGN_DEBUG(engn, "%08x: busy %d save %d unk0 %d unk1 %d chid %d",
+ stat, status->busy, status->save, status->unk0, status->unk1, status->chid);
}
static int
-gf100_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_GR : return GF100_FIFO_ENGN_GR;
- case NVKM_ENGINE_MSPDEC: return GF100_FIFO_ENGN_MSPDEC;
- case NVKM_ENGINE_MSPPP : return GF100_FIFO_ENGN_MSPPP;
- case NVKM_ENGINE_MSVLD : return GF100_FIFO_ENGN_MSVLD;
- case NVKM_ENGINE_CE : return GF100_FIFO_ENGN_CE0 + engine->subdev.inst;
- case NVKM_ENGINE_SW : return GF100_FIFO_ENGN_SW;
- default:
- WARN_ON(1);
- return -1;
+gf100_engn_cxid(struct nvkm_engn *engn, bool *cgid)
+{
+ struct gf100_engn_status status;
+
+ gf100_engn_status(engn, &status);
+ if (status.busy) {
+ *cgid = false;
+ return status.chid;
}
+
+ return -ENODEV;
}
-static void
-gf100_fifo_recover_work(struct work_struct *w)
+static bool
+gf100_engn_chsw(struct nvkm_engn *engn)
{
- struct gf100_fifo *fifo = container_of(w, typeof(*fifo), recover.work);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_engine *engine;
- unsigned long flags;
- u32 engm, engn, todo;
+ struct gf100_engn_status status;
+
+ gf100_engn_status(engn, &status);
+ if (status.busy && (status.unk0 || status.unk1))
+ return true;
- spin_lock_irqsave(&fifo->base.lock, flags);
- engm = fifo->recover.mask;
- fifo->recover.mask = 0ULL;
- spin_unlock_irqrestore(&fifo->base.lock, flags);
+ return false;
+}
- nvkm_mask(device, 0x002630, engm, engm);
+static const struct nvkm_engn_func
+gf100_engn = {
+ .chsw = gf100_engn_chsw,
+ .cxid = gf100_engn_cxid,
+ .mmu_fault_trigger = gf100_engn_mmu_fault_trigger,
+ .mmu_fault_triggered = gf100_engn_mmu_fault_triggered,
+ .ctor = gf100_ectx_ctor,
+ .bind = gf100_ectx_bind,
+};
- for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT_ULL(engn)) {
- if ((engine = gf100_fifo_id_engine(&fifo->base, engn))) {
- nvkm_subdev_fini(&engine->subdev, false);
- WARN_ON(nvkm_subdev_init(&engine->subdev));
+const struct nvkm_engn_func
+gf100_engn_sw = {
+};
+
+static const struct nvkm_bitfield
+gf100_runq_intr_0_names[] = {
+/* { 0x00008000, "" } seen with null ib push */
+ { 0x00200000, "ILLEGAL_MTHD" },
+ { 0x00800000, "EMPTY_SUBC" },
+ {}
+};
+
+bool
+gf100_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *null)
+{
+ struct nvkm_subdev *subdev = &runq->fifo->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 mask = nvkm_rd32(device, 0x04010c + (runq->id * 0x2000));
+ u32 stat = nvkm_rd32(device, 0x040108 + (runq->id * 0x2000)) & mask;
+ u32 addr = nvkm_rd32(device, 0x0400c0 + (runq->id * 0x2000));
+ u32 data = nvkm_rd32(device, 0x0400c4 + (runq->id * 0x2000));
+ u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x2000)) & runq->fifo->chid->mask;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00003ffc);
+ u32 show = stat;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+ char msg[128];
+
+ if (stat & 0x00800000) {
+ if (device->sw) {
+ if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data))
+ show &= ~0x00800000;
}
}
- gf100_fifo_runlist_commit(fifo);
- nvkm_wr32(device, 0x00262c, engm);
- nvkm_mask(device, 0x002630, engm, 0x00000000);
+ if (show) {
+ nvkm_snprintbf(msg, sizeof(msg), runq->func->intr_0_names, show);
+ chan = nvkm_chan_get_chid(&runq->fifo->engine, chid, &flags);
+ nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] "
+ "subc %d mthd %04x data %08x\n",
+ runq->id, show, msg, chid, chan ? chan->inst->addr : 0,
+ chan ? chan->name : "unknown", subc, mthd, data);
+
+ /*TODO: use proper procedure for clearing each exception / debug output */
+ if ((stat & 0xc67fe000) && chan)
+ nvkm_chan_error(chan, true);
+ nvkm_chan_put(&chan, flags);
+ }
+
+ nvkm_wr32(device, 0x0400c0 + (runq->id * 0x2000), 0x80600008);
+ nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), stat);
+ return true;
+}
+
+void
+gf100_runq_init(struct nvkm_runq *runq)
+{
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
+
+ nvkm_mask(device, 0x04013c + (runq->id * 0x2000), 0x10000100, 0x00000000);
+ nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), 0xffffffff); /* INTR */
+ nvkm_wr32(device, 0x04010c + (runq->id * 0x2000), 0xfffffeff); /* INTREN */
+}
+
+static const struct nvkm_runq_func
+gf100_runq = {
+ .init = gf100_runq_init,
+ .intr = gf100_runq_intr,
+ .intr_0_names = gf100_runq_intr_0_names,
+};
+
+bool
+gf100_runl_preempt_pending(struct nvkm_runl *runl)
+{
+ return nvkm_rd32(runl->fifo->engine.subdev.device, 0x002634) & 0x00100000;
}
static void
-gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine,
- struct gf100_fifo_chan *chan)
+gf100_runl_fault_clear(struct nvkm_runl *runl)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 chid = chan->base.chid;
- int engi = gf100_fifo_engine_id(&fifo->base, engine);
+ nvkm_mask(runl->fifo->engine.subdev.device, 0x00262c, 0x00000000, 0x00000000);
+}
+
+static void
+gf100_runl_allow(struct nvkm_runl *runl, u32 engm)
+{
+ nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, 0x00000000);
+}
+
+static void
+gf100_runl_block(struct nvkm_runl *runl, u32 engm)
+{
+ nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, engm);
+}
+
+static bool
+gf100_runl_pending(struct nvkm_runl *runl)
+{
+ return nvkm_rd32(runl->fifo->engine.subdev.device, 0x00227c) & 0x00100000;
+}
+
+static void
+gf100_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u64 addr = nvkm_memory_addr(memory) + start;
+ int target;
+
+ switch (nvkm_memory_target(memory)) {
+ case NVKM_MEM_TARGET_VRAM: target = 0; break;
+ case NVKM_MEM_TARGET_NCOH: target = 3; break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ nvkm_wr32(device, 0x002270, (target << 28) | (addr >> 12));
+ nvkm_wr32(device, 0x002274, 0x01f00000 | count);
+}
+
+static void
+gf100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
+{
+ nvkm_wo32(memory, offset + 0, chan->id);
+ nvkm_wo32(memory, offset + 4, 0x00000004);
+}
- nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n",
- engine->subdev.name, chid);
- assert_spin_locked(&fifo->base.lock);
+static const struct nvkm_runl_func
+gf100_runl = {
+ .size = 8,
+ .update = nv50_runl_update,
+ .insert_chan = gf100_runl_insert_chan,
+ .commit = gf100_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gf100_runl_pending,
+ .block = gf100_runl_block,
+ .allow = gf100_runl_allow,
+ .fault_clear = gf100_runl_fault_clear,
+ .preempt_pending = gf100_runl_preempt_pending,
+};
- nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
- list_del_init(&chan->head);
- chan->killed = true;
+static void
+gf100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+ unsigned long flags;
- if (engi >= 0 && engi != GF100_FIFO_ENGN_SW)
- fifo->recover.mask |= BIT(engi);
- schedule_work(&fifo->recover.work);
- nvkm_fifo_kevent(&fifo->base, chid);
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x80000000);
+ spin_unlock_irqrestore(&fifo->lock, flags);
}
+void
+gf100_fifo_nonstall_block(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x00000000);
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+const struct nvkm_event_func
+gf100_fifo_nonstall = {
+ .init = gf100_fifo_nonstall_allow,
+ .fini = gf100_fifo_nonstall_block,
+};
+
static const struct nvkm_enum
-gf100_fifo_fault_engine[] = {
+gf100_fifo_mmu_fault_engine[] = {
{ 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR },
{ 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB },
{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
{ 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM },
- { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO },
+ { 0x07, "PFIFO" },
{ 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD },
{ 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP },
{ 0x13, "PCOUNTER" },
@@ -212,7 +482,7 @@ gf100_fifo_fault_engine[] = {
};
static const struct nvkm_enum
-gf100_fifo_fault_reason[] = {
+gf100_fifo_mmu_fault_reason[] = {
{ 0x00, "PT_NOT_PRESENT" },
{ 0x01, "PT_TOO_SHORT" },
{ 0x02, "PAGE_NOT_PRESENT" },
@@ -226,7 +496,7 @@ gf100_fifo_fault_reason[] = {
};
static const struct nvkm_enum
-gf100_fifo_fault_hubclient[] = {
+gf100_fifo_mmu_fault_hubclient[] = {
{ 0x01, "PCOPY0" },
{ 0x02, "PCOPY1" },
{ 0x04, "DISPATCH" },
@@ -245,7 +515,7 @@ gf100_fifo_fault_hubclient[] = {
};
static const struct nvkm_enum
-gf100_fifo_fault_gpcclient[] = {
+gf100_fifo_mmu_fault_gpcclient[] = {
{ 0x01, "TEX" },
{ 0x0c, "ESETUP" },
{ 0x0e, "CTXCTL" },
@@ -253,29 +523,55 @@ gf100_fifo_fault_gpcclient[] = {
{}
};
-static void
-gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
+const struct nvkm_enum
+gf100_fifo_mmu_fault_access[] = {
+ { 0x00, "READ" },
+ { 0x01, "WRITE" },
+ {}
+};
+
+void
+gf100_fifo_mmu_fault_recover(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
{
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
- const struct nvkm_enum *er, *eu, *ec;
+ const struct nvkm_enum *er, *ee, *ec, *ea;
struct nvkm_engine *engine = NULL;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ struct nvkm_chan *chan;
unsigned long flags;
- char gpcid[8] = "";
+ char ct[8] = "HUB/";
+
+ /* Lookup engine by MMU fault ID. */
+ nvkm_runl_foreach(runl, fifo) {
+ engn = nvkm_runl_find_engn(engn, runl, engn->fault == info->engine);
+ if (engn) {
+ /* Fault triggered by CTXSW_TIMEOUT recovery procedure. */
+ if (engn->func->mmu_fault_triggered &&
+ engn->func->mmu_fault_triggered(engn)) {
+ nvkm_runl_rc_engn(runl, engn);
+ return;
+ }
+
+ engine = engn->engine;
+ break;
+ }
+ }
- er = nvkm_enum_find(gf100_fifo_fault_reason, info->reason);
- eu = nvkm_enum_find(gf100_fifo_fault_engine, info->engine);
+ er = nvkm_enum_find(fifo->func->mmu_fault->reason, info->reason);
+ ee = nvkm_enum_find(fifo->func->mmu_fault->engine, info->engine);
if (info->hub) {
- ec = nvkm_enum_find(gf100_fifo_fault_hubclient, info->client);
+ ec = nvkm_enum_find(fifo->func->mmu_fault->hubclient, info->client);
} else {
- ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, info->client);
- snprintf(gpcid, sizeof(gpcid), "GPC%d/", info->gpc);
+ ec = nvkm_enum_find(fifo->func->mmu_fault->gpcclient, info->client);
+ snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
}
+ ea = nvkm_enum_find(fifo->func->mmu_fault->access, info->access);
- if (eu && eu->data2) {
- switch (eu->data2) {
+ /* Handle BAR faults. */
+ if (ee && ee->data2) {
+ switch (ee->data2) {
case NVKM_SUBDEV_BAR:
nvkm_bar_bar1_reset(device);
break;
@@ -286,77 +582,104 @@ gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
break;
default:
- engine = nvkm_device_engine(device, eu->data2, eu->inst);
break;
}
}
- chan = nvkm_fifo_chan_inst(&fifo->base, info->inst, &flags);
+ chan = nvkm_chan_get_inst(&fifo->engine, info->inst, &flags);
nvkm_error(subdev,
- "%s fault at %010llx engine %02x [%s] client %02x [%s%s] "
- "reason %02x [%s] on channel %d [%010llx %s]\n",
- info->access ? "write" : "read", info->addr,
- info->engine, eu ? eu->name : "",
- info->client, gpcid, ec ? ec->name : "",
- info->reason, er ? er->name : "", chan ? chan->chid : -1,
- info->inst, chan ? chan->object.client->name : "unknown");
-
- if (engine && chan)
- gf100_fifo_recover(fifo, engine, (void *)chan);
- nvkm_fifo_chan_put(&fifo->base, flags, &chan);
+ "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
+ "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
+ info->access, ea ? ea->name : "", info->addr,
+ info->engine, ee ? ee->name : engine ? engine->subdev.name : "",
+ info->client, ct, ec ? ec->name : "",
+ info->reason, er ? er->name : "",
+ chan ? chan->id : -1, info->inst, chan ? chan->name : "unknown");
+
+ /* Handle host/engine faults. */
+ if (chan)
+ nvkm_runl_rc_cgrp(chan->cgrp);
+
+ nvkm_chan_put(&chan, flags);
}
-static const struct nvkm_enum
-gf100_fifo_sched_reason[] = {
- { 0x0a, "CTXSW_TIMEOUT" },
- {}
+static const struct nvkm_fifo_func_mmu_fault
+gf100_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gf100_fifo_mmu_fault_access,
+ .engine = gf100_fifo_mmu_fault_engine,
+ .reason = gf100_fifo_mmu_fault_reason,
+ .hubclient = gf100_fifo_mmu_fault_hubclient,
+ .gpcclient = gf100_fifo_mmu_fault_gpcclient,
};
-static void
-gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo)
+void
+gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo, u32 engm)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_engine *engine;
- struct gf100_fifo_chan *chan;
- unsigned long flags;
- u32 engn;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- for (engn = 0; engn < 6; engn++) {
- u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
- u32 busy = (stat & 0x80000000);
- u32 save = (stat & 0x00100000); /* maybe? */
- u32 unk0 = (stat & 0x00040000);
- u32 unk1 = (stat & 0x00001000);
- u32 chid = (stat & 0x0000007f);
- (void)save;
-
- if (busy && unk0 && unk1) {
- list_for_each_entry(chan, &fifo->chan, head) {
- if (chan->base.chid == chid) {
- engine = gf100_fifo_id_engine(&fifo->base, engn);
- if (!engine)
- break;
- gf100_fifo_recover(fifo, engine, chan);
- break;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn, *engn2;
+ bool cgid, cgid2;
+ int id, id2;
+
+ nvkm_runl_foreach(runl, fifo) {
+ /* Stop the runlist, and go through all engines serving it. */
+ nvkm_runl_block(runl);
+ nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) {
+ /* Determine what channel (group) the engine is on. */
+ id = engn->func->cxid(engn, &cgid);
+ if (id >= 0) {
+ /* Trigger MMU fault on any engine(s) on that channel (group). */
+ nvkm_runl_foreach_engn_cond(engn2, runl, engn2->func->cxid) {
+ id2 = engn2->func->cxid(engn2, &cgid2);
+ if (cgid2 == cgid && id2 == id)
+ engn2->func->mmu_fault_trigger(engn2);
}
}
}
+ nvkm_runl_allow(runl); /* HW will keep runlist blocked via ERROR_SCHED_DISABLE. */
}
- spin_unlock_irqrestore(&fifo->base.lock, flags);
}
static void
-gf100_fifo_intr_sched(struct gf100_fifo *fifo)
+gf100_fifo_intr_sched_ctxsw(struct nvkm_fifo *fifo)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ u32 engm = 0;
+
+ /* Look for any engines that are busy, and awaiting chsw ack. */
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn_cond(engn, runl, engn->func->chsw) {
+ if (WARN_ON(engn->fault < 0) || !engn->func->chsw(engn))
+ continue;
+
+ engm |= BIT(engn->id);
+ }
+ }
+
+ if (!engm)
+ return;
+
+ fifo->func->intr_ctxsw_timeout(fifo, engm);
+}
+
+static const struct nvkm_enum
+gf100_fifo_intr_sched_names[] = {
+ { 0x0a, "CTXSW_TIMEOUT" },
+ {}
+};
+
+void
+gf100_fifo_intr_sched(struct nvkm_fifo *fifo)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 intr = nvkm_rd32(device, 0x00254c);
u32 code = intr & 0x000000ff;
const struct nvkm_enum *en;
- en = nvkm_enum_find(gf100_fifo_sched_reason, code);
+ en = nvkm_enum_find(gf100_fifo_intr_sched_names, code);
nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
@@ -370,7 +693,7 @@ gf100_fifo_intr_sched(struct gf100_fifo *fifo)
}
void
-gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
+gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit)
{
struct nvkm_device *device = fifo->engine.subdev.device;
u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
@@ -393,61 +716,45 @@ gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
nvkm_fifo_fault(fifo, &info);
}
-static const struct nvkm_bitfield
-gf100_fifo_pbdma_intr[] = {
-/* { 0x00008000, "" } seen with null ib push */
- { 0x00200000, "ILLEGAL_MTHD" },
- { 0x00800000, "EMPTY_SUBC" },
- {}
-};
-
-static void
-gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit)
+void
+gf100_fifo_intr_mmu_fault(struct nvkm_fifo *fifo)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000));
- u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000));
- u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000));
- u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00003ffc);
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- u32 show= stat;
- char msg[128];
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ unsigned long mask = nvkm_rd32(device, 0x00259c);
+ int unit;
- if (stat & 0x00800000) {
- if (device->sw) {
- if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data))
- show &= ~0x00800000;
- }
+ for_each_set_bit(unit, &mask, 32) {
+ fifo->func->intr_mmu_fault_unit(fifo, unit);
+ nvkm_wr32(device, 0x00259c, BIT(unit));
}
+}
- if (show) {
- nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show);
- chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags);
- nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] "
- "subc %d mthd %04x data %08x\n",
- unit, show, msg, chid, chan ? chan->inst->addr : 0,
- chan ? chan->object.client->name : "unknown",
- subc, mthd, data);
- nvkm_fifo_chan_put(&fifo->base, flags, &chan);
+bool
+gf100_fifo_intr_pbdma(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_runq *runq;
+ u32 mask = nvkm_rd32(device, 0x0025a0);
+ bool handled = false;
+
+ nvkm_runq_foreach_cond(runq, fifo, mask & BIT(runq->id)) {
+ if (runq->func->intr(runq, NULL))
+ handled = true;
+
+ nvkm_wr32(device, 0x0025a0, BIT(runq->id));
}
- nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008);
- nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat);
+ return handled;
}
static void
-gf100_fifo_intr_runlist(struct gf100_fifo *fifo)
+gf100_fifo_intr_runlist(struct nvkm_fifo *fifo)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 intr = nvkm_rd32(device, 0x002a00);
if (intr & 0x10000000) {
- wake_up(&fifo->runlist.wait);
nvkm_wr32(device, 0x002a00, 0x10000000);
intr &= ~0x10000000;
}
@@ -459,9 +766,9 @@ gf100_fifo_intr_runlist(struct gf100_fifo *fifo)
}
static void
-gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn)
+gf100_fifo_intr_engine_unit(struct nvkm_fifo *fifo, int engn)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04));
u32 inte = nvkm_rd32(device, 0x002628);
@@ -472,22 +779,22 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn)
for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) {
- nvkm_fifo_uevent(&fifo->base);
+ nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
ints &= ~1;
}
if (ints) {
- nvkm_error(subdev, "ENGINE %d %d %01x",
- engn, unkn, ints);
+ nvkm_error(subdev, "ENGINE %d %d %01x", engn, unkn, ints);
nvkm_mask(device, 0x002628, ints, 0);
}
}
}
-void
-gf100_fifo_intr_engine(struct gf100_fifo *fifo)
+static void
+gf100_fifo_intr_engine(struct nvkm_fifo *fifo)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
u32 mask = nvkm_rd32(device, 0x0025a4);
+
while (mask) {
u32 unit = __ffs(mask);
gf100_fifo_intr_engine_unit(fifo, unit);
@@ -495,11 +802,11 @@ gf100_fifo_intr_engine(struct gf100_fifo *fifo)
}
}
-static void
-gf100_fifo_intr(struct nvkm_fifo *base)
+static irqreturn_t
+gf100_fifo_intr(struct nvkm_inth *inth)
{
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth);
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 mask = nvkm_rd32(device, 0x002140);
u32 stat = nvkm_rd32(device, 0x002100) & mask;
@@ -532,25 +839,13 @@ gf100_fifo_intr(struct nvkm_fifo *base)
}
if (stat & 0x10000000) {
- u32 mask = nvkm_rd32(device, 0x00259c);
- while (mask) {
- u32 unit = __ffs(mask);
- gf100_fifo_intr_fault(&fifo->base, unit);
- nvkm_wr32(device, 0x00259c, (1 << unit));
- mask &= ~(1 << unit);
- }
+ gf100_fifo_intr_mmu_fault(fifo);
stat &= ~0x10000000;
}
if (stat & 0x20000000) {
- u32 mask = nvkm_rd32(device, 0x0025a0);
- while (mask) {
- u32 unit = __ffs(mask);
- gf100_fifo_intr_pbdma(fifo, unit);
- nvkm_wr32(device, 0x0025a0, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x20000000;
+ if (gf100_fifo_intr_pbdma(fifo))
+ stat &= ~0x20000000;
}
if (stat & 0x40000000) {
@@ -565,71 +860,26 @@ gf100_fifo_intr(struct nvkm_fifo *base)
if (stat) {
nvkm_error(subdev, "INTR %08x\n", stat);
+ spin_lock(&fifo->lock);
nvkm_mask(device, 0x002140, stat, 0x00000000);
+ spin_unlock(&fifo->lock);
nvkm_wr32(device, 0x002100, stat);
}
-}
-
-static int
-gf100_fifo_oneinit(struct nvkm_fifo *base)
-{
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_vmm *bar = nvkm_bar_bar1_vmm(device);
- int ret;
-
- /* Determine number of PBDMAs by checking valid enable bits. */
- nvkm_wr32(device, 0x002204, 0xffffffff);
- fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x002204));
- nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr);
-
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000,
- false, &fifo->runlist.mem[0]);
- if (ret)
- return ret;
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000,
- false, &fifo->runlist.mem[1]);
- if (ret)
- return ret;
- init_waitqueue_head(&fifo->runlist.wait);
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000,
- 0x1000, false, &fifo->user.mem);
- if (ret)
- return ret;
-
- ret = nvkm_vmm_get(bar, 12, nvkm_memory_size(fifo->user.mem),
- &fifo->user.bar);
- if (ret)
- return ret;
-
- return nvkm_memory_map(fifo->user.mem, 0, bar, fifo->user.bar, NULL, 0);
-}
-
-static void
-gf100_fifo_fini(struct nvkm_fifo *base)
-{
- struct gf100_fifo *fifo = gf100_fifo(base);
- flush_work(&fifo->recover.work);
+ return IRQ_HANDLED;
}
static void
-gf100_fifo_init(struct nvkm_fifo *base)
+gf100_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask)
{
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int i;
+ struct nvkm_device *device = fifo->engine.subdev.device;
/* Enable PBDMAs. */
- nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1);
- nvkm_wr32(device, 0x002204, (1 << fifo->pbdma_nr) - 1);
+ nvkm_wr32(device, 0x000204, mask);
+ nvkm_wr32(device, 0x002204, mask);
/* Assign engines to PBDMAs. */
- if (fifo->pbdma_nr >= 3) {
+ if ((mask & 7) == 7) {
nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */
nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */
nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */
@@ -638,62 +888,82 @@ gf100_fifo_init(struct nvkm_fifo *base)
nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */
}
- /* PBDMA[n] */
- for (i = 0; i < fifo->pbdma_nr; i++) {
- nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
- nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
- nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
- }
+ nvkm_mask(device, 0x002a04, 0xbfffffff, 0xbfffffff);
+}
+
+static void
+gf100_fifo_init(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
nvkm_mask(device, 0x002200, 0x00000001, 0x00000001);
- nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar->addr >> 12);
+ nvkm_wr32(device, 0x002254, 0x10000000 | fifo->userd.bar1->addr >> 12);
nvkm_wr32(device, 0x002100, 0xffffffff);
nvkm_wr32(device, 0x002140, 0x7fffffff);
nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
}
-static void *
-gf100_fifo_dtor(struct nvkm_fifo *base)
+static int
+gf100_fifo_runl_ctor(struct nvkm_fifo *fifo)
+{
+ struct nvkm_runl *runl;
+
+ runl = nvkm_runl_new(fifo, 0, 0, 0);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
+
+ nvkm_runl_add(runl, 0, fifo->func->engn, NVKM_ENGINE_GR, 0);
+ nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_MSPDEC, 0);
+ nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MSPPP, 0);
+ nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_MSVLD, 0);
+ nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_CE, 0);
+ nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_CE, 1);
+ nvkm_runl_add(runl, 15, &gf100_engn_sw, NVKM_ENGINE_SW, 0);
+ return 0;
+}
+
+int
+gf100_fifo_runq_nr(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ u32 save;
+
+ /* Determine number of PBDMAs by checking valid enable bits. */
+ save = nvkm_mask(device, 0x000204, 0xffffffff, 0xffffffff);
+ save = nvkm_mask(device, 0x000204, 0xffffffff, save);
+ return hweight32(save);
+}
+
+int
+gf100_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
{
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- nvkm_vmm_put(nvkm_bar_bar1_vmm(device), &fifo->user.bar);
- nvkm_memory_unref(&fifo->user.mem);
- nvkm_memory_unref(&fifo->runlist.mem[0]);
- nvkm_memory_unref(&fifo->runlist.mem[1]);
- return fifo;
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->chid);
}
static const struct nvkm_fifo_func
gf100_fifo = {
- .dtor = gf100_fifo_dtor,
- .oneinit = gf100_fifo_oneinit,
+ .chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = gf100_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gf100_fifo_runl_ctor,
.init = gf100_fifo_init,
- .fini = gf100_fifo_fini,
+ .init_pbdmas = gf100_fifo_init_pbdmas,
.intr = gf100_fifo_intr,
- .fault = gf100_fifo_fault,
- .engine_id = gf100_fifo_engine_id,
- .id_engine = gf100_fifo_id_engine,
- .uevent_init = gf100_fifo_uevent_init,
- .uevent_fini = gf100_fifo_uevent_fini,
- .chan = {
- &gf100_fifo_gpfifo_oclass,
- NULL
- },
+ .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gf100_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gf100_runl,
+ .runq = &gf100_runq,
+ .engn = &gf100_engn,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, FERMI_CHANNEL_GPFIFO }, &gf100_chan },
};
int
gf100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- struct gf100_fifo *fifo;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
- INIT_LIST_HEAD(&fifo->chan);
- INIT_WORK(&fifo->recover.work, gf100_fifo_recover_work);
- *pfifo = &fifo->base;
-
- return nvkm_fifo_ctor(&gf100_fifo, device, type, inst, 128, &fifo->base);
+ return nvkm_fifo_new_(&gf100_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
deleted file mode 100644
index b8642490eb2f..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __GF100_FIFO_H__
-#define __GF100_FIFO_H__
-#define gf100_fifo(p) container_of((p), struct gf100_fifo, base)
-#include "priv.h"
-
-#include <subdev/mmu.h>
-
-struct gf100_fifo_chan;
-struct gf100_fifo {
- struct nvkm_fifo base;
-
- struct list_head chan;
-
- struct {
- struct work_struct work;
- u64 mask;
- } recover;
-
- int pbdma_nr;
-
- struct {
- struct nvkm_memory *mem[2];
- int active;
- wait_queue_head_t wait;
- } runlist;
-
- struct {
- struct nvkm_memory *mem;
- struct nvkm_vma *bar;
- } user;
-};
-
-void gf100_fifo_intr_engine(struct gf100_fifo *);
-void gf100_fifo_runlist_insert(struct gf100_fifo *, struct gf100_fifo_chan *);
-void gf100_fifo_runlist_remove(struct gf100_fifo *, struct gf100_fifo_chan *);
-void gf100_fifo_runlist_commit(struct gf100_fifo *);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
index e771bd519ee2..d8a4d773a58c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -21,643 +21,318 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
+#include "priv.h"
#include "cgrp.h"
-#include "changk104.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+#include "runq.h"
-#include <core/client.h>
#include <core/gpuobj.h>
-#include <subdev/bar.h>
-#include <subdev/fault.h>
-#include <subdev/timer.h>
+#include <subdev/mc.h>
+#include <subdev/mmu.h>
#include <subdev/top.h>
-#include <engine/sw.h>
#include <nvif/class.h>
-#include <nvif/cl0080.h>
+#include <nvif/if900d.h>
void
-gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn,
- struct gk104_fifo_engine_status *status)
+gk104_chan_stop(struct nvkm_chan *chan)
{
- struct nvkm_engine *engine = fifo->engine[engn].engine;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x08));
-
- status->busy = !!(stat & 0x80000000);
- status->faulted = !!(stat & 0x40000000);
- status->next.tsg = !!(stat & 0x10000000);
- status->next.id = (stat & 0x0fff0000) >> 16;
- status->chsw = !!(stat & 0x00008000);
- status->save = !!(stat & 0x00004000);
- status->load = !!(stat & 0x00002000);
- status->prev.tsg = !!(stat & 0x00001000);
- status->prev.id = (stat & 0x00000fff);
- status->chan = NULL;
-
- if (status->busy && status->chsw) {
- if (status->load && status->save) {
- if (engine && nvkm_engine_chsw_load(engine))
- status->chan = &status->next;
- else
- status->chan = &status->prev;
- } else
- if (status->load) {
- status->chan = &status->next;
- } else {
- status->chan = &status->prev;
- }
- } else
- if (status->load) {
- status->chan = &status->prev;
- }
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
- nvkm_debug(subdev, "engine %02d: busy %d faulted %d chsw %d "
- "save %d load %d %sid %d%s-> %sid %d%s\n",
- engn, status->busy, status->faulted,
- status->chsw, status->save, status->load,
- status->prev.tsg ? "tsg" : "ch", status->prev.id,
- status->chan == &status->prev ? "*" : " ",
- status->next.tsg ? "tsg" : "ch", status->next.id,
- status->chan == &status->next ? "*" : " ");
-}
-
-int
-gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *argv, u32 argc, struct nvkm_object **pobject)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- if (oclass->engn == &fifo->func->chan) {
- const struct gk104_fifo_chan_user *user = oclass->engn;
- return user->ctor(fifo, oclass, argv, argc, pobject);
- } else
- if (oclass->engn == &fifo->func->user) {
- const struct gk104_fifo_user_user *user = oclass->engn;
- return user->ctor(oclass, argv, argc, pobject);
- }
- WARN_ON(1);
- return -EINVAL;
-}
-
-int
-gk104_fifo_class_get(struct nvkm_fifo *base, int index,
- struct nvkm_oclass *oclass)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- int c = 0;
-
- if (fifo->func->user.ctor && c++ == index) {
- oclass->base = fifo->func->user.user;
- oclass->engn = &fifo->func->user;
- return 0;
- }
-
- if (fifo->func->chan.ctor && c++ == index) {
- oclass->base = fifo->func->chan.user;
- oclass->engn = &fifo->func->chan;
- return 0;
- }
-
- return c;
+ nvkm_mask(device, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
}
void
-gk104_fifo_uevent_fini(struct nvkm_fifo *fifo)
+gk104_chan_start(struct nvkm_chan *chan)
{
- struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x80000000, 0x00000000);
-}
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
-void
-gk104_fifo_uevent_init(struct nvkm_fifo *fifo)
-{
- struct nvkm_device *device = fifo->engine.subdev.device;
- nvkm_mask(device, 0x002140, 0x80000000, 0x80000000);
+ nvkm_mask(device, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
}
void
-gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
- struct nvkm_memory *mem, int nr)
+gk104_chan_unbind(struct nvkm_chan *chan)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- int target;
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
- switch (nvkm_memory_target(mem)) {
- case NVKM_MEM_TARGET_VRAM: target = 0; break;
- case NVKM_MEM_TARGET_NCOH: target = 3; break;
- default:
- WARN_ON(1);
- return;
- }
-
- nvkm_wr32(device, 0x002270, (nvkm_memory_addr(mem) >> 12) |
- (target << 28));
- nvkm_wr32(device, 0x002274, (runl << 20) | nr);
-
- if (nvkm_msec(device, 2000,
- if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000))
- break;
- ) < 0)
- nvkm_error(subdev, "runlist %d update timeout\n", runl);
+ nvkm_wr32(device, 0x800000 + (chan->id * 8), 0x00000000);
}
void
-gk104_fifo_runlist_update(struct gk104_fifo *fifo, int runl)
+gk104_chan_bind_inst(struct nvkm_chan *chan)
{
- const struct gk104_fifo_runlist_func *func = fifo->func->runlist;
- struct gk104_fifo_chan *chan;
- struct nvkm_memory *mem;
- struct nvkm_fifo_cgrp *cgrp;
- int nr = 0;
-
- mutex_lock(&fifo->base.mutex);
- mem = fifo->runlist[runl].mem[fifo->runlist[runl].next];
- fifo->runlist[runl].next = !fifo->runlist[runl].next;
-
- nvkm_kmap(mem);
- list_for_each_entry(chan, &fifo->runlist[runl].chan, head) {
- func->chan(chan, mem, nr++ * func->size);
- }
-
- list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) {
- func->cgrp(cgrp, mem, nr++ * func->size);
- list_for_each_entry(chan, &cgrp->chan, head) {
- func->chan(chan, mem, nr++ * func->size);
- }
- }
- nvkm_done(mem);
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
- func->commit(fifo, runl, mem, nr);
- mutex_unlock(&fifo->base.mutex);
+ nvkm_wr32(device, 0x800000 + (chan->id * 8), 0x80000000 | chan->inst->addr >> 12);
}
void
-gk104_fifo_runlist_remove(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
-{
- struct nvkm_fifo_cgrp *cgrp = chan->cgrp;
- mutex_lock(&fifo->base.mutex);
- if (!list_empty(&chan->head)) {
- list_del_init(&chan->head);
- if (cgrp && !--cgrp->chan_nr)
- list_del_init(&cgrp->head);
- }
- mutex_unlock(&fifo->base.mutex);
-}
-
-void
-gk104_fifo_runlist_insert(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
-{
- struct nvkm_fifo_cgrp *cgrp = chan->cgrp;
- mutex_lock(&fifo->base.mutex);
- if (cgrp) {
- if (!cgrp->chan_nr++)
- list_add_tail(&cgrp->head, &fifo->runlist[chan->runl].cgrp);
- list_add_tail(&chan->head, &cgrp->chan);
- } else {
- list_add_tail(&chan->head, &fifo->runlist[chan->runl].chan);
- }
- mutex_unlock(&fifo->base.mutex);
-}
-
-void
-gk104_fifo_runlist_chan(struct gk104_fifo_chan *chan,
- struct nvkm_memory *memory, u32 offset)
-{
- nvkm_wo32(memory, offset + 0, chan->base.chid);
- nvkm_wo32(memory, offset + 4, 0x00000000);
-}
-
-const struct gk104_fifo_runlist_func
-gk104_fifo_runlist = {
- .size = 8,
- .chan = gk104_fifo_runlist_chan,
- .commit = gk104_fifo_runlist_commit,
+gk104_chan_bind(struct nvkm_chan *chan)
+{
+ struct nvkm_runl *runl = chan->cgrp->runl;
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+
+ nvkm_mask(device, 0x800004 + (chan->id * 8), 0x000f0000, runl->id << 16);
+ gk104_chan_bind_inst(chan);
+}
+
+static int
+gk104_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
+ const u32 limit2 = ilog2(length / 8);
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x08, lower_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x0c, upper_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x10, 0x0000face);
+ nvkm_wo32(chan->inst, 0x30, 0xfffff902);
+ nvkm_wo32(chan->inst, 0x48, lower_32_bits(offset));
+ nvkm_wo32(chan->inst, 0x4c, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->inst, 0x84, 0x20400000);
+ nvkm_wo32(chan->inst, 0x94, 0x30000000 | devm);
+ nvkm_wo32(chan->inst, 0x9c, 0x00000100);
+ nvkm_wo32(chan->inst, 0xac, 0x0000001f);
+ nvkm_wo32(chan->inst, 0xe4, priv ? 0x00000020 : 0x00000000);
+ nvkm_wo32(chan->inst, 0xe8, chan->id);
+ nvkm_wo32(chan->inst, 0xb8, 0xf8000000);
+ nvkm_wo32(chan->inst, 0xf8, 0x10003080); /* 0x002310 */
+ nvkm_wo32(chan->inst, 0xfc, 0x10000010); /* 0x002350 */
+ nvkm_done(chan->inst);
+ return 0;
+}
+
+const struct nvkm_chan_func_ramfc
+gk104_chan_ramfc = {
+ .write = gk104_chan_ramfc_write,
+ .devm = 0xfff,
+ .priv = true,
};
-void
-gk104_fifo_pbdma_init(struct gk104_fifo *fifo)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1);
-}
-
-int
-gk104_fifo_pbdma_nr(struct gk104_fifo *fifo)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- /* Determine number of PBDMAs by checking valid enable bits. */
- nvkm_wr32(device, 0x000204, 0xffffffff);
- return hweight32(nvkm_rd32(device, 0x000204));
-}
-
-const struct gk104_fifo_pbdma_func
-gk104_fifo_pbdma = {
- .nr = gk104_fifo_pbdma_nr,
- .init = gk104_fifo_pbdma_init,
+const struct nvkm_chan_func_userd
+gk104_chan_userd = {
+ .bar = 1,
+ .size = 0x200,
+ .clear = gf100_chan_userd_clear,
};
-struct nvkm_engine *
-gk104_fifo_id_engine(struct nvkm_fifo *base, int engi)
-{
- if (engi == GK104_FIFO_ENGN_SW)
- return nvkm_device_engine(base->engine.subdev.device, NVKM_ENGINE_SW, 0);
-
- return gk104_fifo(base)->engine[engi].engine;
-}
-
-int
-gk104_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- int engn;
+static const struct nvkm_chan_func
+gk104_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gk104_chan_userd,
+ .ramfc = &gk104_chan_ramfc,
+ .bind = gk104_chan_bind,
+ .unbind = gk104_chan_unbind,
+ .start = gk104_chan_start,
+ .stop = gk104_chan_stop,
+ .preempt = gf100_chan_preempt,
+};
- if (engine->subdev.type == NVKM_ENGINE_SW)
- return GK104_FIFO_ENGN_SW;
+static void
+gk104_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
+{
+ u32 ptr0, ptr1 = 0;
+ u64 addr = 0ULL;
+
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_SW : return;
+ case NVKM_ENGINE_GR : ptr0 = 0x0210; break;
+ case NVKM_ENGINE_SEC : ptr0 = 0x0220; break;
+ case NVKM_ENGINE_MSPDEC: ptr0 = 0x0250; break;
+ case NVKM_ENGINE_MSPPP : ptr0 = 0x0260; break;
+ case NVKM_ENGINE_MSVLD : ptr0 = 0x0270; break;
+ case NVKM_ENGINE_VIC : ptr0 = 0x0280; break;
+ case NVKM_ENGINE_MSENC : ptr0 = 0x0290; break;
+ case NVKM_ENGINE_NVDEC :
+ ptr1 = 0x0270;
+ ptr0 = 0x0210;
+ break;
+ case NVKM_ENGINE_NVENC :
+ if (!engn->engine->subdev.inst)
+ ptr1 = 0x0290;
+ ptr0 = 0x0210;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
- for (engn = 0; engn < fifo->engine_nr && engine; engn++) {
- if (fifo->engine[engn].engine == engine)
- return engn;
+ if (cctx) {
+ addr = cctx->vctx->vma->addr;
+ addr |= 4ULL;
}
- WARN_ON(1);
- return -1;
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, ptr0 + 0, lower_32_bits(addr));
+ nvkm_wo32(chan->inst, ptr0 + 4, upper_32_bits(addr));
+ if (ptr1) {
+ nvkm_wo32(chan->inst, ptr1 + 0, lower_32_bits(addr));
+ nvkm_wo32(chan->inst, ptr1 + 4, upper_32_bits(addr));
+ }
+ nvkm_done(chan->inst);
}
-static void
-gk104_fifo_recover_work(struct work_struct *w)
+int
+gk104_ectx_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx)
{
- struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_engine *engine;
- unsigned long flags;
- u32 engm, runm, todo;
- int engn, runl;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- runm = fifo->recover.runm;
- engm = fifo->recover.engm;
- fifo->recover.engm = 0;
- fifo->recover.runm = 0;
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-
- nvkm_mask(device, 0x002630, runm, runm);
-
- for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) {
- if ((engine = fifo->engine[engn].engine)) {
- nvkm_subdev_fini(&engine->subdev, false);
- WARN_ON(nvkm_subdev_init(&engine->subdev));
- }
- }
+ struct gf100_vmm_map_v0 args = { .priv = 1 };
+ int ret;
- for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl))
- gk104_fifo_runlist_update(fifo, runl);
+ ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma);
+ if (ret)
+ return ret;
- nvkm_wr32(device, 0x00262c, runm);
- nvkm_mask(device, 0x002630, runm, 0x00000000);
+ return nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, &args, sizeof(args));
}
-static void gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn);
+/*TODO: clean this up */
+struct gk104_engn_status {
+ bool busy;
+ bool faulted;
+ bool chsw;
+ bool save;
+ bool load;
+ struct {
+ bool tsg;
+ u32 id;
+ } prev, next, *chan;
+};
static void
-gk104_fifo_recover_runl(struct gk104_fifo *fifo, int runl)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 runm = BIT(runl);
-
- assert_spin_locked(&fifo->base.lock);
- if (fifo->recover.runm & runm)
- return;
- fifo->recover.runm |= runm;
-
- /* Block runlist to prevent channel assignment(s) from changing. */
- nvkm_mask(device, 0x002630, runm, runm);
-
- /* Schedule recovery. */
- nvkm_warn(subdev, "runlist %d: scheduled for recovery\n", runl);
- schedule_work(&fifo->recover.work);
-}
-
-static struct gk104_fifo_chan *
-gk104_fifo_recover_chid(struct gk104_fifo *fifo, int runl, int chid)
+gk104_engn_status(struct nvkm_engn *engn, struct gk104_engn_status *status)
{
- struct gk104_fifo_chan *chan;
- struct nvkm_fifo_cgrp *cgrp;
+ u32 stat = nvkm_rd32(engn->runl->fifo->engine.subdev.device, 0x002640 + (engn->id * 0x08));
- list_for_each_entry(chan, &fifo->runlist[runl].chan, head) {
- if (chan->base.chid == chid) {
- list_del_init(&chan->head);
- return chan;
- }
- }
+ status->busy = !!(stat & 0x80000000);
+ status->faulted = !!(stat & 0x40000000);
+ status->next.tsg = !!(stat & 0x10000000);
+ status->next.id = (stat & 0x0fff0000) >> 16;
+ status->chsw = !!(stat & 0x00008000);
+ status->save = !!(stat & 0x00004000);
+ status->load = !!(stat & 0x00002000);
+ status->prev.tsg = !!(stat & 0x00001000);
+ status->prev.id = (stat & 0x00000fff);
+ status->chan = NULL;
- list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) {
- if (cgrp->id == chid) {
- chan = list_first_entry(&cgrp->chan, typeof(*chan), head);
- list_del_init(&chan->head);
- if (!--cgrp->chan_nr)
- list_del_init(&cgrp->head);
- return chan;
+ if (status->busy && status->chsw) {
+ if (status->load && status->save) {
+ if (nvkm_engine_chsw_load(engn->engine))
+ status->chan = &status->next;
+ else
+ status->chan = &status->prev;
+ } else
+ if (status->load) {
+ status->chan = &status->next;
+ } else {
+ status->chan = &status->prev;
}
+ } else
+ if (status->load) {
+ status->chan = &status->prev;
}
- return NULL;
-}
-
-static void
-gk104_fifo_recover_chan(struct nvkm_fifo *base, int chid)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 stat = nvkm_rd32(device, 0x800004 + (chid * 0x08));
- const u32 runl = (stat & 0x000f0000) >> 16;
- const bool used = (stat & 0x00000001);
- unsigned long engn, engm = fifo->runlist[runl].engm;
- struct gk104_fifo_chan *chan;
-
- assert_spin_locked(&fifo->base.lock);
- if (!used)
- return;
-
- /* Lookup SW state for channel, and mark it as dead. */
- chan = gk104_fifo_recover_chid(fifo, runl, chid);
- if (chan) {
- chan->killed = true;
- nvkm_fifo_kevent(&fifo->base, chid);
- }
-
- /* Disable channel. */
- nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800);
- nvkm_warn(subdev, "channel %d: killed\n", chid);
-
- /* Block channel assignments from changing during recovery. */
- gk104_fifo_recover_runl(fifo, runl);
-
- /* Schedule recovery for any engines the channel is on. */
- for_each_set_bit(engn, &engm, fifo->engine_nr) {
- struct gk104_fifo_engine_status status;
- gk104_fifo_engine_status(fifo, engn, &status);
- if (!status.chan || status.chan->id != chid)
- continue;
- gk104_fifo_recover_engn(fifo, engn);
- }
+ ENGN_DEBUG(engn, "%08x: busy %d faulted %d chsw %d save %d load %d %sid %d%s-> %sid %d%s",
+ stat, status->busy, status->faulted, status->chsw, status->save, status->load,
+ status->prev.tsg ? "tsg" : "ch", status->prev.id,
+ status->chan == &status->prev ? "*" : " ",
+ status->next.tsg ? "tsg" : "ch", status->next.id,
+ status->chan == &status->next ? "*" : " ");
}
-static void
-gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn)
+int
+gk104_engn_cxid(struct nvkm_engn *engn, bool *cgid)
{
- struct nvkm_engine *engine = fifo->engine[engn].engine;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 runl = fifo->engine[engn].runl;
- const u32 engm = BIT(engn);
- struct gk104_fifo_engine_status status;
- int mmui = -1;
-
- assert_spin_locked(&fifo->base.lock);
- if (fifo->recover.engm & engm)
- return;
- fifo->recover.engm |= engm;
-
- /* Block channel assignments from changing during recovery. */
- gk104_fifo_recover_runl(fifo, runl);
+ struct gk104_engn_status status;
- /* Determine which channel (if any) is currently on the engine. */
- gk104_fifo_engine_status(fifo, engn, &status);
+ gk104_engn_status(engn, &status);
if (status.chan) {
- /* The channel is not longer viable, kill it. */
- gk104_fifo_recover_chan(&fifo->base, status.chan->id);
+ *cgid = status.chan->tsg;
+ return status.chan->id;
}
- /* Determine MMU fault ID for the engine, if we're not being
- * called from the fault handler already.
- */
- if (!status.faulted && engine) {
- mmui = nvkm_top_fault_id(device, engine->subdev.type, engine->subdev.inst);
- if (mmui < 0) {
- const struct nvkm_enum *en = fifo->func->fault.engine;
- for (; en && en->name; en++) {
- if (en->data2 == engine->subdev.type &&
- en->inst == engine->subdev.inst) {
- mmui = en->value;
- break;
- }
- }
- }
- WARN_ON(mmui < 0);
- }
-
- /* Trigger a MMU fault for the engine.
- *
- * No good idea why this is needed, but nvgpu does something similar,
- * and it makes recovery from CTXSW_TIMEOUT a lot more reliable.
- */
- if (mmui >= 0) {
- nvkm_wr32(device, 0x002a30 + (engn * 0x04), 0x00000100 | mmui);
-
- /* Wait for fault to trigger. */
- nvkm_msec(device, 2000,
- gk104_fifo_engine_status(fifo, engn, &status);
- if (status.faulted)
- break;
- );
-
- /* Release MMU fault trigger, and ACK the fault. */
- nvkm_wr32(device, 0x002a30 + (engn * 0x04), 0x00000000);
- nvkm_wr32(device, 0x00259c, BIT(mmui));
- nvkm_wr32(device, 0x002100, 0x10000000);
- }
-
- /* Schedule recovery. */
- nvkm_warn(subdev, "engine %d: scheduled for recovery\n", engn);
- schedule_work(&fifo->recover.work);
+ return -ENODEV;
}
-static void
-gk104_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
+bool
+gk104_engn_chsw(struct nvkm_engn *engn)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const struct nvkm_enum *er, *ee, *ec, *ea;
- struct nvkm_engine *engine = NULL;
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- const char *en = "";
- char ct[8] = "HUB/";
-
- er = nvkm_enum_find(fifo->func->fault.reason, info->reason);
- ee = nvkm_enum_find(fifo->func->fault.engine, info->engine);
- if (info->hub) {
- ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client);
- } else {
- ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client);
- snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
- }
- ea = nvkm_enum_find(fifo->func->fault.access, info->access);
+ struct gk104_engn_status status;
- if (ee && ee->data2) {
- switch (ee->data2) {
- case NVKM_SUBDEV_BAR:
- nvkm_bar_bar1_reset(device);
- break;
- case NVKM_SUBDEV_INSTMEM:
- nvkm_bar_bar2_reset(device);
- break;
- case NVKM_ENGINE_IFB:
- nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
- break;
- default:
- engine = nvkm_device_engine(device, ee->data2, 0);
- break;
- }
- }
-
- if (ee == NULL) {
- struct nvkm_subdev *subdev = nvkm_top_fault(device, info->engine);
- if (subdev) {
- if (subdev->func == &nvkm_engine)
- engine = container_of(subdev, typeof(*engine), subdev);
- en = engine->subdev.name;
- }
- } else {
- en = ee->name;
- }
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst);
-
- nvkm_error(subdev,
- "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
- "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
- info->access, ea ? ea->name : "", info->addr,
- info->engine, ee ? ee->name : en,
- info->client, ct, ec ? ec->name : "",
- info->reason, er ? er->name : "", chan ? chan->chid : -1,
- info->inst, chan ? chan->object.client->name : "unknown");
-
- /* Kill the channel that caused the fault. */
- if (chan)
- gk104_fifo_recover_chan(&fifo->base, chan->chid);
-
- /* Channel recovery will probably have already done this for the
- * correct engine(s), but just in case we can't find the channel
- * information...
- */
- if (engine) {
- int engn = fifo->base.func->engine_id(&fifo->base, engine);
- if (engn >= 0 && engn != GK104_FIFO_ENGN_SW)
- gk104_fifo_recover_engn(fifo, engn);
- }
+ gk104_engn_status(engn, &status);
+ if (status.busy && status.chsw)
+ return true;
- spin_unlock_irqrestore(&fifo->base.lock, flags);
+ return false;
}
-static const struct nvkm_enum
-gk104_fifo_bind_reason[] = {
- { 0x01, "BIND_NOT_UNBOUND" },
- { 0x02, "SNOOP_WITHOUT_BAR1" },
- { 0x03, "UNBIND_WHILE_RUNNING" },
- { 0x05, "INVALID_RUNLIST" },
- { 0x06, "INVALID_CTX_TGT" },
- { 0x0b, "UNBIND_WHILE_PARKED" },
- {}
+const struct nvkm_engn_func
+gk104_engn = {
+ .chsw = gk104_engn_chsw,
+ .cxid = gk104_engn_cxid,
+ .mmu_fault_trigger = gf100_engn_mmu_fault_trigger,
+ .mmu_fault_triggered = gf100_engn_mmu_fault_triggered,
+ .ctor = gk104_ectx_ctor,
+ .bind = gk104_ectx_bind,
};
-void
-gk104_fifo_intr_bind(struct gk104_fifo *fifo)
+const struct nvkm_engn_func
+gk104_engn_ce = {
+ .chsw = gk104_engn_chsw,
+ .cxid = gk104_engn_cxid,
+ .mmu_fault_trigger = gf100_engn_mmu_fault_trigger,
+ .mmu_fault_triggered = gf100_engn_mmu_fault_triggered,
+};
+
+bool
+gk104_runq_idle(struct nvkm_runq *runq)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 intr = nvkm_rd32(device, 0x00252c);
- u32 code = intr & 0x000000ff;
- const struct nvkm_enum *en =
- nvkm_enum_find(gk104_fifo_bind_reason, code);
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
- nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : "");
+ return !(nvkm_rd32(device, 0x003080 + (runq->id * 4)) & 0x0000e000);
}
-static const struct nvkm_enum
-gk104_fifo_sched_reason[] = {
- { 0x0a, "CTXSW_TIMEOUT" },
+static const struct nvkm_bitfield
+gk104_runq_intr_1_names[] = {
+ { 0x00000001, "HCE_RE_ILLEGAL_OP" },
+ { 0x00000002, "HCE_RE_ALIGNB" },
+ { 0x00000004, "HCE_PRIV" },
+ { 0x00000008, "HCE_ILLEGAL_MTHD" },
+ { 0x00000010, "HCE_ILLEGAL_CLASS" },
{}
};
-static void
-gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo)
+static bool
+gk104_runq_intr_1(struct nvkm_runq *runq)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- unsigned long flags, engm = 0;
- u32 engn;
-
- /* We need to ACK the SCHED_ERROR here, and prevent it reasserting,
- * as MMU_FAULT cannot be triggered while it's pending.
- */
- spin_lock_irqsave(&fifo->base.lock, flags);
- nvkm_mask(device, 0x002140, 0x00000100, 0x00000000);
- nvkm_wr32(device, 0x002100, 0x00000100);
-
- for (engn = 0; engn < fifo->engine_nr; engn++) {
- struct gk104_fifo_engine_status status;
-
- gk104_fifo_engine_status(fifo, engn, &status);
- if (!status.busy || !status.chsw)
- continue;
-
- engm |= BIT(engn);
- }
-
- for_each_set_bit(engn, &engm, fifo->engine_nr)
- gk104_fifo_recover_engn(fifo, engn);
-
- nvkm_mask(device, 0x002140, 0x00000100, 0x00000100);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-}
-
-static void
-gk104_fifo_intr_sched(struct gk104_fifo *fifo)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &runq->fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
- u32 intr = nvkm_rd32(device, 0x00254c);
- u32 code = intr & 0x000000ff;
- const struct nvkm_enum *en =
- nvkm_enum_find(gk104_fifo_sched_reason, code);
-
- nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
+ u32 mask = nvkm_rd32(device, 0x04014c + (runq->id * 0x2000));
+ u32 stat = nvkm_rd32(device, 0x040148 + (runq->id * 0x2000)) & mask;
+ u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x2000)) & 0xfff;
+ char msg[128];
- switch (code) {
- case 0x0a:
- gk104_fifo_intr_sched_ctxsw(fifo);
- break;
- default:
- break;
+ if (stat & 0x80000000) {
+ if (runq->func->intr_1_ctxnotvalid &&
+ runq->func->intr_1_ctxnotvalid(runq, chid))
+ stat &= ~0x80000000;
}
-}
-void
-gk104_fifo_intr_chsw(struct gk104_fifo *fifo)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0x00256c);
- nvkm_error(subdev, "CHSW_ERROR %08x\n", stat);
- nvkm_wr32(device, 0x00256c, stat);
-}
+ if (stat) {
+ nvkm_snprintbf(msg, sizeof(msg), gk104_runq_intr_1_names, stat);
+ nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n",
+ runq->id, stat, msg, chid,
+ nvkm_rd32(device, 0x040150 + (runq->id * 0x2000)),
+ nvkm_rd32(device, 0x040154 + (runq->id * 0x2000)));
+ }
-void
-gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0x00259c);
- nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat);
+ nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), stat);
+ return true;
}
-static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
+const struct nvkm_bitfield
+gk104_runq_intr_0_names[] = {
{ 0x00000001, "MEMREQ" },
{ 0x00000002, "MEMACK_TIMEOUT" },
{ 0x00000004, "MEMACK_EXTRA" },
@@ -691,430 +366,111 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
{}
};
-void
-gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit)
+bool
+gk104_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *null)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000));
- u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask;
- u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000));
- u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000));
- u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00003ffc);
- u32 show = stat;
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- char msg[128];
-
- if (stat & 0x00800000) {
- if (device->sw) {
- if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data))
- show &= ~0x00800000;
- }
- }
-
- nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008);
-
- if (show) {
- nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show);
- chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags);
- nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] "
- "subc %d mthd %04x data %08x\n",
- unit, show, msg, chid, chan ? chan->inst->addr : 0,
- chan ? chan->object.client->name : "unknown",
- subc, mthd, data);
- nvkm_fifo_chan_put(&fifo->base, flags, &chan);
- }
+ bool intr0 = gf100_runq_intr(runq, NULL);
+ bool intr1 = gk104_runq_intr_1(runq);
- nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat);
+ return intr0 || intr1;
}
-static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
- { 0x00000001, "HCE_RE_ILLEGAL_OP" },
- { 0x00000002, "HCE_RE_ALIGNB" },
- { 0x00000004, "HCE_PRIV" },
- { 0x00000008, "HCE_ILLEGAL_MTHD" },
- { 0x00000010, "HCE_ILLEGAL_CLASS" },
- {}
-};
-
void
-gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit)
+gk104_runq_init(struct nvkm_runq *runq)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000));
- u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask;
- u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff;
- char msg[128];
+ struct nvkm_device *device = runq->fifo->engine.subdev.device;
- if (stat) {
- nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_1, stat);
- nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n",
- unit, stat, msg, chid,
- nvkm_rd32(device, 0x040150 + (unit * 0x2000)),
- nvkm_rd32(device, 0x040154 + (unit * 0x2000)));
- }
+ gf100_runq_init(runq);
- nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat);
+ nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), 0xffffffff); /* HCE.INTR */
+ nvkm_wr32(device, 0x04014c + (runq->id * 0x2000), 0xffffffff); /* HCE.INTREN */
}
-void
-gk104_fifo_intr_runlist(struct gk104_fifo *fifo)
+static u32
+gk104_runq_runm(struct nvkm_runq *runq)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 mask = nvkm_rd32(device, 0x002a00);
- while (mask) {
- int runl = __ffs(mask);
- wake_up(&fifo->runlist[runl].wait);
- nvkm_wr32(device, 0x002a00, 1 << runl);
- mask &= ~(1 << runl);
- }
+ return nvkm_rd32(runq->fifo->engine.subdev.device, 0x002390 + (runq->id * 0x04));
}
+const struct nvkm_runq_func
+gk104_runq = {
+ .init = gk104_runq_init,
+ .intr = gk104_runq_intr,
+ .intr_0_names = gk104_runq_intr_0_names,
+ .idle = gk104_runq_idle,
+};
+
void
-gk104_fifo_intr_engine(struct gk104_fifo *fifo)
+gk104_runl_fault_clear(struct nvkm_runl *runl)
{
- nvkm_fifo_uevent(&fifo->base);
-}
-
-static void
-gk104_fifo_intr(struct nvkm_fifo *base)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 mask = nvkm_rd32(device, 0x002140);
- u32 stat = nvkm_rd32(device, 0x002100) & mask;
-
- if (stat & 0x00000001) {
- gk104_fifo_intr_bind(fifo);
- nvkm_wr32(device, 0x002100, 0x00000001);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000010) {
- nvkm_error(subdev, "PIO_ERROR\n");
- nvkm_wr32(device, 0x002100, 0x00000010);
- stat &= ~0x00000010;
- }
-
- if (stat & 0x00000100) {
- gk104_fifo_intr_sched(fifo);
- nvkm_wr32(device, 0x002100, 0x00000100);
- stat &= ~0x00000100;
- }
-
- if (stat & 0x00010000) {
- gk104_fifo_intr_chsw(fifo);
- nvkm_wr32(device, 0x002100, 0x00010000);
- stat &= ~0x00010000;
- }
-
- if (stat & 0x00800000) {
- nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n");
- nvkm_wr32(device, 0x002100, 0x00800000);
- stat &= ~0x00800000;
- }
-
- if (stat & 0x01000000) {
- nvkm_error(subdev, "LB_ERROR\n");
- nvkm_wr32(device, 0x002100, 0x01000000);
- stat &= ~0x01000000;
- }
-
- if (stat & 0x08000000) {
- gk104_fifo_intr_dropped_fault(fifo);
- nvkm_wr32(device, 0x002100, 0x08000000);
- stat &= ~0x08000000;
- }
-
- if (stat & 0x10000000) {
- u32 mask = nvkm_rd32(device, 0x00259c);
- while (mask) {
- u32 unit = __ffs(mask);
- fifo->func->intr.fault(&fifo->base, unit);
- nvkm_wr32(device, 0x00259c, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x10000000;
- }
-
- if (stat & 0x20000000) {
- u32 mask = nvkm_rd32(device, 0x0025a0);
- while (mask) {
- u32 unit = __ffs(mask);
- gk104_fifo_intr_pbdma_0(fifo, unit);
- gk104_fifo_intr_pbdma_1(fifo, unit);
- nvkm_wr32(device, 0x0025a0, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x20000000;
- }
-
- if (stat & 0x40000000) {
- gk104_fifo_intr_runlist(fifo);
- stat &= ~0x40000000;
- }
-
- if (stat & 0x80000000) {
- nvkm_wr32(device, 0x002100, 0x80000000);
- gk104_fifo_intr_engine(fifo);
- stat &= ~0x80000000;
- }
-
- if (stat) {
- nvkm_error(subdev, "INTR %08x\n", stat);
- nvkm_mask(device, 0x002140, stat, 0x00000000);
- nvkm_wr32(device, 0x002100, stat);
- }
+ nvkm_wr32(runl->fifo->engine.subdev.device, 0x00262c, BIT(runl->id));
}
void
-gk104_fifo_fini(struct nvkm_fifo *base)
+gk104_runl_allow(struct nvkm_runl *runl, u32 engm)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- flush_work(&fifo->recover.work);
- /* allow mmu fault interrupts, even when we're not using fifo */
- nvkm_mask(device, 0x002140, 0x10000000, 0x10000000);
+ nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, BIT(runl->id), 0x00000000);
}
-int
-gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data)
+void
+gk104_runl_block(struct nvkm_runl *runl, u32 engm)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- switch (mthd) {
- case NV_DEVICE_HOST_RUNLISTS:
- *data = (1ULL << fifo->runlist_nr) - 1;
- return 0;
- case NV_DEVICE_HOST_RUNLIST_ENGINES: {
- if (*data < fifo->runlist_nr) {
- unsigned long engm = fifo->runlist[*data].engm;
- struct nvkm_engine *engine;
- int engn;
- *data = 0;
- for_each_set_bit(engn, &engm, fifo->engine_nr) {
- if ((engine = fifo->engine[engn].engine)) {
-#define CASE(n) case NVKM_ENGINE_##n: *data |= NV_DEVICE_HOST_RUNLIST_ENGINES_##n; break
- switch (engine->subdev.type) {
- CASE(SW );
- CASE(GR );
- CASE(MPEG );
- CASE(ME );
- CASE(CIPHER);
- CASE(BSP );
- CASE(VP );
- CASE(CE );
- CASE(SEC );
- CASE(MSVLD );
- CASE(MSPDEC);
- CASE(MSPPP );
- CASE(MSENC );
- CASE(VIC );
- CASE(SEC2 );
- CASE(NVDEC );
- CASE(NVENC );
- default:
- WARN_ON(1);
- break;
- }
- }
- }
- return 0;
- }
- }
- return -EINVAL;
- default:
- return -EINVAL;
- }
+ nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, BIT(runl->id), BIT(runl->id));
}
-int
-gk104_fifo_oneinit(struct nvkm_fifo *base)
+bool
+gk104_runl_pending(struct nvkm_runl *runl)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_vmm *bar = nvkm_bar_bar1_vmm(device);
- struct nvkm_top_device *tdev;
- int pbid, ret, i, j;
- u32 *map;
-
- fifo->pbdma_nr = fifo->func->pbdma->nr(fifo);
- nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr);
-
- /* Read PBDMA->runlist(s) mapping from HW. */
- if (!(map = kcalloc(fifo->pbdma_nr, sizeof(*map), GFP_KERNEL)))
- return -ENOMEM;
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
- for (i = 0; i < fifo->pbdma_nr; i++)
- map[i] = nvkm_rd32(device, 0x002390 + (i * 0x04));
-
- /* Determine runlist configuration from topology device info. */
- list_for_each_entry(tdev, &device->top->device, head) {
- const int engn = tdev->engine;
- char _en[16], *en;
-
- if (engn < 0)
- continue;
-
- /* Determine which PBDMA handles requests for this engine. */
- for (j = 0, pbid = -1; j < fifo->pbdma_nr; j++) {
- if (map[j] & BIT(tdev->runlist)) {
- pbid = j;
- break;
- }
- }
-
- fifo->engine[engn].engine = nvkm_device_engine(device, tdev->type, tdev->inst);
- if (!fifo->engine[engn].engine) {
- snprintf(_en, sizeof(_en), "%s, %d",
- nvkm_subdev_type[tdev->type], tdev->inst);
- en = _en;
- } else {
- en = fifo->engine[engn].engine->subdev.name;
- }
-
- nvkm_debug(subdev, "engine %2d: runlist %2d pbdma %2d (%s)\n",
- tdev->engine, tdev->runlist, pbid, en);
-
- fifo->engine[engn].runl = tdev->runlist;
- fifo->engine[engn].pbid = pbid;
- fifo->engine_nr = max(fifo->engine_nr, engn + 1);
- fifo->runlist[tdev->runlist].engm |= BIT(engn);
- fifo->runlist[tdev->runlist].engm_sw |= BIT(engn);
- if (tdev->type == NVKM_ENGINE_GR)
- fifo->runlist[tdev->runlist].engm_sw |= BIT(GK104_FIFO_ENGN_SW);
- fifo->runlist_nr = max(fifo->runlist_nr, tdev->runlist + 1);
- }
-
- kfree(map);
-
- for (i = 0; i < fifo->runlist_nr; i++) {
- for (j = 0; j < ARRAY_SIZE(fifo->runlist[i].mem); j++) {
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
- fifo->base.nr * 2/* TSG+chan */ *
- fifo->func->runlist->size,
- 0x1000, false,
- &fifo->runlist[i].mem[j]);
- if (ret)
- return ret;
- }
-
- init_waitqueue_head(&fifo->runlist[i].wait);
- INIT_LIST_HEAD(&fifo->runlist[i].cgrp);
- INIT_LIST_HEAD(&fifo->runlist[i].chan);
- }
-
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
- fifo->base.nr * 0x200, 0x1000, true,
- &fifo->user.mem);
- if (ret)
- return ret;
-
- ret = nvkm_vmm_get(bar, 12, nvkm_memory_size(fifo->user.mem),
- &fifo->user.bar);
- if (ret)
- return ret;
-
- return nvkm_memory_map(fifo->user.mem, 0, bar, fifo->user.bar, NULL, 0);
+ return nvkm_rd32(device, 0x002284 + (runl->id * 0x08)) & 0x00100000;
}
void
-gk104_fifo_init(struct nvkm_fifo *base)
+gk104_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int i;
-
- /* Enable PBDMAs. */
- fifo->func->pbdma->init(fifo);
-
- /* PBDMA[n] */
- for (i = 0; i < fifo->pbdma_nr; i++) {
- nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
- nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
- nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
- }
-
- /* PBDMA[n].HCE */
- for (i = 0; i < fifo->pbdma_nr; i++) {
- nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
- nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
- }
-
- nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar->addr >> 12);
-
- if (fifo->func->pbdma->init_timeout)
- fifo->func->pbdma->init_timeout(fifo);
-
- nvkm_wr32(device, 0x002100, 0xffffffff);
- nvkm_wr32(device, 0x002140, 0x7fffffff);
-}
-
-void *
-gk104_fifo_dtor(struct nvkm_fifo *base)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int i;
-
- nvkm_vmm_put(nvkm_bar_bar1_vmm(device), &fifo->user.bar);
- nvkm_memory_unref(&fifo->user.mem);
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ u64 addr = nvkm_memory_addr(memory) + start;
+ int target;
- for (i = 0; i < fifo->runlist_nr; i++) {
- nvkm_memory_unref(&fifo->runlist[i].mem[1]);
- nvkm_memory_unref(&fifo->runlist[i].mem[0]);
+ switch (nvkm_memory_target(memory)) {
+ case NVKM_MEM_TARGET_VRAM: target = 0; break;
+ case NVKM_MEM_TARGET_NCOH: target = 3; break;
+ default:
+ WARN_ON(1);
+ return;
}
- return fifo;
+ spin_lock_irq(&fifo->lock);
+ nvkm_wr32(device, 0x002270, (target << 28) | (addr >> 12));
+ nvkm_wr32(device, 0x002274, (runl->id << 20) | count);
+ spin_unlock_irq(&fifo->lock);
}
-static const struct nvkm_fifo_func
-gk104_fifo_ = {
- .dtor = gk104_fifo_dtor,
- .oneinit = gk104_fifo_oneinit,
- .info = gk104_fifo_info,
- .init = gk104_fifo_init,
- .fini = gk104_fifo_fini,
- .intr = gk104_fifo_intr,
- .fault = gk104_fifo_fault,
- .engine_id = gk104_fifo_engine_id,
- .id_engine = gk104_fifo_id_engine,
- .uevent_init = gk104_fifo_uevent_init,
- .uevent_fini = gk104_fifo_uevent_fini,
- .recover_chan = gk104_fifo_recover_chan,
- .class_get = gk104_fifo_class_get,
- .class_new = gk104_fifo_class_new,
-};
-
-int
-gk104_fifo_new_(const struct gk104_fifo_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, int nr, struct nvkm_fifo **pfifo)
+void
+gk104_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
{
- struct gk104_fifo *fifo;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
- fifo->func = func;
- INIT_WORK(&fifo->recover.work, gk104_fifo_recover_work);
- *pfifo = &fifo->base;
-
- return nvkm_fifo_ctor(&gk104_fifo_, device, type, inst, nr, &fifo->base);
+ nvkm_wo32(memory, offset + 0, chan->id);
+ nvkm_wo32(memory, offset + 4, 0x00000000);
}
-const struct nvkm_enum
-gk104_fifo_fault_access[] = {
- { 0x0, "READ" },
- { 0x1, "WRITE" },
- {}
+static const struct nvkm_runl_func
+gk104_runl = {
+ .size = 8,
+ .update = nv50_runl_update,
+ .insert_chan = gk104_runl_insert_chan,
+ .commit = gk104_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gk104_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .fault_clear = gk104_runl_fault_clear,
+ .preempt_pending = gf100_runl_preempt_pending,
};
-const struct nvkm_enum
-gk104_fifo_fault_engine[] = {
+static const struct nvkm_enum
+gk104_fifo_mmu_fault_engine[] = {
{ 0x00, "GR", NULL, NVKM_ENGINE_GR },
{ 0x01, "DISPLAY" },
{ 0x02, "CAPTURE" },
@@ -1122,14 +478,14 @@ gk104_fifo_fault_engine[] = {
{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
{ 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM },
{ 0x06, "SCHED" },
- { 0x07, "HOST0", NULL, NVKM_ENGINE_FIFO },
- { 0x08, "HOST1", NULL, NVKM_ENGINE_FIFO },
- { 0x09, "HOST2", NULL, NVKM_ENGINE_FIFO },
- { 0x0a, "HOST3", NULL, NVKM_ENGINE_FIFO },
- { 0x0b, "HOST4", NULL, NVKM_ENGINE_FIFO },
- { 0x0c, "HOST5", NULL, NVKM_ENGINE_FIFO },
- { 0x0d, "HOST6", NULL, NVKM_ENGINE_FIFO },
- { 0x0e, "HOST7", NULL, NVKM_ENGINE_FIFO },
+ { 0x07, "HOST0" },
+ { 0x08, "HOST1" },
+ { 0x09, "HOST2" },
+ { 0x0a, "HOST3" },
+ { 0x0b, "HOST4" },
+ { 0x0c, "HOST5" },
+ { 0x0d, "HOST6" },
+ { 0x0e, "HOST7" },
{ 0x0f, "HOSTSR" },
{ 0x10, "MSVLD", NULL, NVKM_ENGINE_MSVLD },
{ 0x11, "MSPPP", NULL, NVKM_ENGINE_MSPPP },
@@ -1145,7 +501,7 @@ gk104_fifo_fault_engine[] = {
};
const struct nvkm_enum
-gk104_fifo_fault_reason[] = {
+gk104_fifo_mmu_fault_reason[] = {
{ 0x00, "PDE" },
{ 0x01, "PDE_SIZE" },
{ 0x02, "PTE" },
@@ -1166,7 +522,7 @@ gk104_fifo_fault_reason[] = {
};
const struct nvkm_enum
-gk104_fifo_fault_hubclient[] = {
+gk104_fifo_mmu_fault_hubclient[] = {
{ 0x00, "VIP" },
{ 0x01, "CE0" },
{ 0x02, "CE1" },
@@ -1203,7 +559,7 @@ gk104_fifo_fault_hubclient[] = {
};
const struct nvkm_enum
-gk104_fifo_fault_gpcclient[] = {
+gk104_fifo_mmu_fault_gpcclient[] = {
{ 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
{ 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
{ 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
@@ -1228,22 +584,250 @@ gk104_fifo_fault_gpcclient[] = {
{}
};
-static const struct gk104_fifo_func
+const struct nvkm_fifo_func_mmu_fault
+gk104_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gf100_fifo_mmu_fault_access,
+ .engine = gk104_fifo_mmu_fault_engine,
+ .reason = gk104_fifo_mmu_fault_reason,
+ .hubclient = gk104_fifo_mmu_fault_hubclient,
+ .gpcclient = gk104_fifo_mmu_fault_gpcclient,
+};
+
+static const struct nvkm_enum
+gk104_fifo_intr_bind_reason[] = {
+ { 0x01, "BIND_NOT_UNBOUND" },
+ { 0x02, "SNOOP_WITHOUT_BAR1" },
+ { 0x03, "UNBIND_WHILE_RUNNING" },
+ { 0x05, "INVALID_RUNLIST" },
+ { 0x06, "INVALID_CTX_TGT" },
+ { 0x0b, "UNBIND_WHILE_PARKED" },
+ {}
+};
+
+void
+gk104_fifo_intr_bind(struct nvkm_fifo *fifo)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ u32 intr = nvkm_rd32(subdev->device, 0x00252c);
+ u32 code = intr & 0x000000ff;
+ const struct nvkm_enum *en = nvkm_enum_find(gk104_fifo_intr_bind_reason, code);
+
+ nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : "");
+}
+
+void
+gk104_fifo_intr_chsw(struct nvkm_fifo *fifo)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 stat = nvkm_rd32(device, 0x00256c);
+
+ nvkm_error(subdev, "CHSW_ERROR %08x\n", stat);
+ nvkm_wr32(device, 0x00256c, stat);
+}
+
+static void
+gk104_fifo_intr_dropped_fault(struct nvkm_fifo *fifo)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ u32 stat = nvkm_rd32(subdev->device, 0x00259c);
+
+ nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat);
+}
+
+void
+gk104_fifo_intr_runlist(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_runl *runl;
+ u32 mask = nvkm_rd32(device, 0x002a00);
+
+ nvkm_runl_foreach_cond(runl, fifo, mask & BIT(runl->id)) {
+ nvkm_wr32(device, 0x002a00, BIT(runl->id));
+ }
+}
+
+irqreturn_t
+gk104_fifo_intr(struct nvkm_inth *inth)
+{
+ struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth);
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 mask = nvkm_rd32(device, 0x002140);
+ u32 stat = nvkm_rd32(device, 0x002100) & mask;
+
+ if (stat & 0x00000001) {
+ gk104_fifo_intr_bind(fifo);
+ nvkm_wr32(device, 0x002100, 0x00000001);
+ stat &= ~0x00000001;
+ }
+
+ if (stat & 0x00000010) {
+ nvkm_error(subdev, "PIO_ERROR\n");
+ nvkm_wr32(device, 0x002100, 0x00000010);
+ stat &= ~0x00000010;
+ }
+
+ if (stat & 0x00000100) {
+ gf100_fifo_intr_sched(fifo);
+ nvkm_wr32(device, 0x002100, 0x00000100);
+ stat &= ~0x00000100;
+ }
+
+ if (stat & 0x00010000) {
+ gk104_fifo_intr_chsw(fifo);
+ nvkm_wr32(device, 0x002100, 0x00010000);
+ stat &= ~0x00010000;
+ }
+
+ if (stat & 0x00800000) {
+ nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n");
+ nvkm_wr32(device, 0x002100, 0x00800000);
+ stat &= ~0x00800000;
+ }
+
+ if (stat & 0x01000000) {
+ nvkm_error(subdev, "LB_ERROR\n");
+ nvkm_wr32(device, 0x002100, 0x01000000);
+ stat &= ~0x01000000;
+ }
+
+ if (stat & 0x08000000) {
+ gk104_fifo_intr_dropped_fault(fifo);
+ nvkm_wr32(device, 0x002100, 0x08000000);
+ stat &= ~0x08000000;
+ }
+
+ if (stat & 0x10000000) {
+ gf100_fifo_intr_mmu_fault(fifo);
+ stat &= ~0x10000000;
+ }
+
+ if (stat & 0x20000000) {
+ if (gf100_fifo_intr_pbdma(fifo))
+ stat &= ~0x20000000;
+ }
+
+ if (stat & 0x40000000) {
+ gk104_fifo_intr_runlist(fifo);
+ stat &= ~0x40000000;
+ }
+
+ if (stat & 0x80000000) {
+ nvkm_wr32(device, 0x002100, 0x80000000);
+ nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
+ stat &= ~0x80000000;
+ }
+
+ if (stat) {
+ nvkm_error(subdev, "INTR %08x\n", stat);
+ spin_lock(&fifo->lock);
+ nvkm_mask(device, 0x002140, stat, 0x00000000);
+ spin_unlock(&fifo->lock);
+ nvkm_wr32(device, 0x002100, stat);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void
+gk104_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x000204, mask);
+ nvkm_mask(device, 0x002a04, 0xbfffffff, 0xbfffffff);
+}
+
+void
+gk104_fifo_init(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+
+ if (fifo->func->chan.func->userd->bar == 1)
+ nvkm_wr32(device, 0x002254, 0x10000000 | fifo->userd.bar1->addr >> 12);
+
+ nvkm_wr32(device, 0x002100, 0xffffffff);
+ nvkm_wr32(device, 0x002140, 0x7fffffff);
+}
+
+int
+gk104_fifo_runl_ctor(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_top_device *tdev;
+ struct nvkm_runl *runl;
+ struct nvkm_runq *runq;
+ const struct nvkm_engn_func *func;
+
+ nvkm_list_foreach(tdev, &device->top->device, head, tdev->runlist >= 0) {
+ runl = nvkm_runl_get(fifo, tdev->runlist, tdev->runlist);
+ if (!runl) {
+ runl = nvkm_runl_new(fifo, tdev->runlist, tdev->runlist, 0);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
+
+ nvkm_runq_foreach_cond(runq, fifo, gk104_runq_runm(runq) & BIT(runl->id)) {
+ if (WARN_ON(runl->runq_nr == ARRAY_SIZE(runl->runq)))
+ return -ENOMEM;
+
+ runl->runq[runl->runq_nr++] = runq;
+ }
+
+ }
+
+ if (tdev->engine < 0)
+ continue;
+
+ switch (tdev->type) {
+ case NVKM_ENGINE_CE:
+ func = fifo->func->engn_ce;
+ break;
+ case NVKM_ENGINE_GR:
+ nvkm_runl_add(runl, 15, &gf100_engn_sw, NVKM_ENGINE_SW, 0);
+ fallthrough;
+ default:
+ func = fifo->func->engn;
+ break;
+ }
+
+ nvkm_runl_add(runl, tdev->engine, func, tdev->type, tdev->inst);
+ }
+
+ return 0;
+}
+
+int
+gk104_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return 4096;
+}
+
+static const struct nvkm_fifo_func
gk104_fifo = {
- .intr.fault = gf100_fifo_intr_fault,
- .pbdma = &gk104_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gk104_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gk104_fifo_runlist,
- .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
+ .chid_nr = gk104_fifo_chid_nr,
+ .chid_ctor = gf100_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gk104_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gk104_runl,
+ .runq = &gk104_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk104_chan },
};
int
gk104_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gk104_fifo, device, type, inst, 4096, pfifo);
+ return nvkm_fifo_new_(&gk104_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
deleted file mode 100644
index f2d12ae73944..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __GK104_FIFO_H__
-#define __GK104_FIFO_H__
-#define gk104_fifo(p) container_of((p), struct gk104_fifo, base)
-#include "priv.h"
-struct nvkm_fifo_cgrp;
-
-#include <core/enum.h>
-#include <subdev/mmu.h>
-
-struct gk104_fifo_chan;
-struct gk104_fifo {
- const struct gk104_fifo_func *func;
- struct nvkm_fifo base;
-
- struct {
- struct work_struct work;
- u32 engm;
- u32 runm;
- } recover;
-
- int pbdma_nr;
-
- struct {
- struct nvkm_engine *engine;
- int runl;
- int pbid;
- } engine[16];
- int engine_nr;
-
- struct {
- struct nvkm_memory *mem[2];
- int next;
- wait_queue_head_t wait;
- struct list_head cgrp;
- struct list_head chan;
- u32 engm;
- u32 engm_sw;
- } runlist[16];
- int runlist_nr;
-
- struct {
- struct nvkm_memory *mem;
- struct nvkm_vma *bar;
- } user;
-};
-
-struct gk104_fifo_func {
- struct {
- void (*fault)(struct nvkm_fifo *, int unit);
- } intr;
-
- const struct gk104_fifo_pbdma_func {
- int (*nr)(struct gk104_fifo *);
- void (*init)(struct gk104_fifo *);
- void (*init_timeout)(struct gk104_fifo *);
- } *pbdma;
-
- struct {
- const struct nvkm_enum *access;
- const struct nvkm_enum *engine;
- const struct nvkm_enum *reason;
- const struct nvkm_enum *hubclient;
- const struct nvkm_enum *gpcclient;
- } fault;
-
- const struct gk104_fifo_runlist_func {
- u8 size;
- void (*cgrp)(struct nvkm_fifo_cgrp *,
- struct nvkm_memory *, u32 offset);
- void (*chan)(struct gk104_fifo_chan *,
- struct nvkm_memory *, u32 offset);
- void (*commit)(struct gk104_fifo *, int runl,
- struct nvkm_memory *, int entries);
- } *runlist;
-
- struct gk104_fifo_user_user {
- struct nvkm_sclass user;
- int (*ctor)(const struct nvkm_oclass *, void *, u32,
- struct nvkm_object **);
- } user;
-
- struct gk104_fifo_chan_user {
- struct nvkm_sclass user;
- int (*ctor)(struct gk104_fifo *, const struct nvkm_oclass *,
- void *, u32, struct nvkm_object **);
- } chan;
- bool cgrp_force;
-};
-
-struct gk104_fifo_engine_status {
- bool busy;
- bool faulted;
- bool chsw;
- bool save;
- bool load;
- struct {
- bool tsg;
- u32 id;
- } prev, next, *chan;
-};
-
-int gk104_fifo_new_(const struct gk104_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type,
- int index, int nr, struct nvkm_fifo **);
-void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *);
-void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *);
-void gk104_fifo_runlist_update(struct gk104_fifo *, int runl);
-void gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn,
- struct gk104_fifo_engine_status *status);
-void gk104_fifo_intr_bind(struct gk104_fifo *fifo);
-void gk104_fifo_intr_chsw(struct gk104_fifo *fifo);
-void gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo);
-void gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit);
-void gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit);
-void gk104_fifo_intr_runlist(struct gk104_fifo *fifo);
-void gk104_fifo_intr_engine(struct gk104_fifo *fifo);
-void *gk104_fifo_dtor(struct nvkm_fifo *base);
-int gk104_fifo_oneinit(struct nvkm_fifo *base);
-int gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data);
-void gk104_fifo_init(struct nvkm_fifo *base);
-void gk104_fifo_fini(struct nvkm_fifo *base);
-int gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *argv, u32 argc, struct nvkm_object **pobject);
-int gk104_fifo_class_get(struct nvkm_fifo *base, int index,
- struct nvkm_oclass *oclass);
-void gk104_fifo_uevent_fini(struct nvkm_fifo *fifo);
-void gk104_fifo_uevent_init(struct nvkm_fifo *fifo);
-
-extern const struct gk104_fifo_pbdma_func gk104_fifo_pbdma;
-int gk104_fifo_pbdma_nr(struct gk104_fifo *);
-void gk104_fifo_pbdma_init(struct gk104_fifo *);
-extern const struct nvkm_enum gk104_fifo_fault_access[];
-extern const struct nvkm_enum gk104_fifo_fault_engine[];
-extern const struct nvkm_enum gk104_fifo_fault_reason[];
-extern const struct nvkm_enum gk104_fifo_fault_hubclient[];
-extern const struct nvkm_enum gk104_fifo_fault_gpcclient[];
-extern const struct gk104_fifo_runlist_func gk104_fifo_runlist;
-void gk104_fifo_runlist_chan(struct gk104_fifo_chan *,
- struct nvkm_memory *, u32);
-void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl,
- struct nvkm_memory *, int);
-
-extern const struct gk104_fifo_runlist_func gk110_fifo_runlist;
-void gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
- struct nvkm_memory *, u32);
-
-extern const struct gk104_fifo_pbdma_func gk208_fifo_pbdma;
-void gk208_fifo_pbdma_init_timeout(struct gk104_fifo *);
-
-void gm107_fifo_intr_fault(struct nvkm_fifo *, int);
-extern const struct nvkm_enum gm107_fifo_fault_engine[];
-extern const struct gk104_fifo_runlist_func gm107_fifo_runlist;
-
-extern const struct gk104_fifo_pbdma_func gm200_fifo_pbdma;
-int gm200_fifo_pbdma_nr(struct gk104_fifo *);
-
-void gp100_fifo_intr_fault(struct nvkm_fifo *, int);
-extern const struct nvkm_enum gp100_fifo_fault_engine[];
-
-extern const struct nvkm_enum gv100_fifo_fault_access[];
-extern const struct nvkm_enum gv100_fifo_fault_reason[];
-extern const struct nvkm_enum gv100_fifo_fault_hubclient[];
-extern const struct nvkm_enum gv100_fifo_fault_gpcclient[];
-void gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
- struct nvkm_memory *, u32);
-void gv100_fifo_runlist_chan(struct gk104_fifo_chan *,
- struct nvkm_memory *, u32);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c
index 915278c7e012..a8ff21cf7712 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c
@@ -21,47 +21,112 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
+#include "priv.h"
#include "cgrp.h"
-#include "changk104.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
#include <core/memory.h>
+#include <subdev/timer.h>
#include <nvif/class.h>
void
-gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp,
- struct nvkm_memory *memory, u32 offset)
+gk110_chan_preempt(struct nvkm_chan *chan)
+{
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+
+ if (cgrp->hw) {
+ cgrp->func->preempt(cgrp);
+ return;
+ }
+
+ gf100_chan_preempt(chan);
+}
+
+const struct nvkm_chan_func
+gk110_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gk104_chan_userd,
+ .ramfc = &gk104_chan_ramfc,
+ .bind = gk104_chan_bind,
+ .unbind = gk104_chan_unbind,
+ .start = gk104_chan_start,
+ .stop = gk104_chan_stop,
+ .preempt = gk110_chan_preempt,
+};
+
+static void
+gk110_cgrp_preempt(struct nvkm_cgrp *cgrp)
+{
+ nvkm_wr32(cgrp->runl->fifo->engine.subdev.device, 0x002634, 0x01000000 | cgrp->id);
+}
+
+const struct nvkm_cgrp_func
+gk110_cgrp = {
+ .preempt = gk110_cgrp_preempt,
+};
+
+void
+gk110_runl_insert_cgrp(struct nvkm_cgrp *cgrp, struct nvkm_memory *memory, u64 offset)
{
nvkm_wo32(memory, offset + 0, (cgrp->chan_nr << 26) | (128 << 18) |
(3 << 14) | 0x00002000 | cgrp->id);
nvkm_wo32(memory, offset + 4, 0x00000000);
}
-const struct gk104_fifo_runlist_func
-gk110_fifo_runlist = {
+const struct nvkm_runl_func
+gk110_runl = {
.size = 8,
- .cgrp = gk110_fifo_runlist_cgrp,
- .chan = gk104_fifo_runlist_chan,
- .commit = gk104_fifo_runlist_commit,
+ .update = nv50_runl_update,
+ .insert_cgrp = gk110_runl_insert_cgrp,
+ .insert_chan = gk104_runl_insert_chan,
+ .commit = gk104_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gk104_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .fault_clear = gk104_runl_fault_clear,
+ .preempt_pending = gf100_runl_preempt_pending,
};
-static const struct gk104_fifo_func
+int
+gk110_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ int ret;
+
+ ret = nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->cgid);
+ if (ret)
+ return ret;
+
+ return gf100_fifo_chid_ctor(fifo, nr);
+}
+
+static const struct nvkm_fifo_func
gk110_fifo = {
- .intr.fault = gf100_fifo_intr_fault,
- .pbdma = &gk104_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gk104_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gk110_fifo_runlist,
- .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_B}, gk104_fifo_gpfifo_new },
+ .chid_nr = gk104_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gk104_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gk110_runl,
+ .runq = &gk104_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp },
+ .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_B }, &gk110_chan },
};
int
gk110_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gk110_fifo, device, type, inst, 4096, pfifo);
+ return nvkm_fifo_new_(&gk110_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
index cb703693de52..8fa2b0be141a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
@@ -21,44 +21,57 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
-#include "changk104.h"
+#include "priv.h"
+#include "runq.h"
#include <nvif/class.h>
void
-gk208_fifo_pbdma_init_timeout(struct gk104_fifo *fifo)
+gk208_runq_init(struct nvkm_runq *runq)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- int i;
+ gk104_runq_init(runq);
- for (i = 0; i < fifo->pbdma_nr; i++)
- nvkm_wr32(device, 0x04012c + (i * 0x2000), 0x0000ffff);
+ nvkm_wr32(runq->fifo->engine.subdev.device, 0x04012c + (runq->id * 0x2000), 0x000f4240);
}
-const struct gk104_fifo_pbdma_func
-gk208_fifo_pbdma = {
- .nr = gk104_fifo_pbdma_nr,
- .init = gk104_fifo_pbdma_init,
- .init_timeout = gk208_fifo_pbdma_init_timeout,
+const struct nvkm_runq_func
+gk208_runq = {
+ .init = gk208_runq_init,
+ .intr = gk104_runq_intr,
+ .intr_0_names = gk104_runq_intr_0_names,
+ .idle = gk104_runq_idle,
};
-static const struct gk104_fifo_func
+static int
+gk208_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return 1024;
+}
+
+static const struct nvkm_fifo_func
gk208_fifo = {
- .intr.fault = gf100_fifo_intr_fault,
- .pbdma = &gk208_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gk104_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gk110_fifo_runlist,
- .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
+ .chid_nr = gk208_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gk104_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gk110_runl,
+ .runq = &gk208_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp },
+ .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk110_chan },
};
int
gk208_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gk208_fifo, device, type, inst, 1024, pfifo);
+ return nvkm_fifo_new_(&gk208_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
index 6e35cf44c640..b63ca836130f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
@@ -19,27 +19,34 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
-#include "gk104.h"
-#include "changk104.h"
+#include "priv.h"
#include <nvif/class.h>
-static const struct gk104_fifo_func
+static const struct nvkm_fifo_func
gk20a_fifo = {
- .intr.fault = gf100_fifo_intr_fault,
- .pbdma = &gk208_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gk104_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gk110_fifo_runlist,
- .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
+ .chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gk104_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gk110_runl,
+ .runq = &gk208_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ }, &gk110_cgrp },
+ .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk110_chan },
};
int
gk20a_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gk20a_fifo, device, type, inst, 128, pfifo);
+ return nvkm_fifo_new_(&gk20a_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c
index 7af6e687d474..5ba60021b510 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c
@@ -21,46 +21,65 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
-#include "changk104.h"
+#include "priv.h"
+#include "chan.h"
+#include "runl.h"
#include <core/gpuobj.h>
#include <subdev/fault.h>
#include <nvif/class.h>
+const struct nvkm_chan_func
+gm107_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gk104_chan_userd,
+ .ramfc = &gk104_chan_ramfc,
+ .bind = gk104_chan_bind_inst,
+ .unbind = gk104_chan_unbind,
+ .start = gk104_chan_start,
+ .stop = gk104_chan_stop,
+ .preempt = gk110_chan_preempt,
+};
+
static void
-gm107_fifo_runlist_chan(struct gk104_fifo_chan *chan,
- struct nvkm_memory *memory, u32 offset)
+gm107_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
{
- nvkm_wo32(memory, offset + 0, chan->base.chid);
- nvkm_wo32(memory, offset + 4, chan->base.inst->addr >> 12);
+ nvkm_wo32(memory, offset + 0, chan->id);
+ nvkm_wo32(memory, offset + 4, chan->inst->addr >> 12);
}
-const struct gk104_fifo_runlist_func
-gm107_fifo_runlist = {
+const struct nvkm_runl_func
+gm107_runl = {
.size = 8,
- .cgrp = gk110_fifo_runlist_cgrp,
- .chan = gm107_fifo_runlist_chan,
- .commit = gk104_fifo_runlist_commit,
+ .update = nv50_runl_update,
+ .insert_cgrp = gk110_runl_insert_cgrp,
+ .insert_chan = gm107_runl_insert_chan,
+ .commit = gk104_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gk104_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .fault_clear = gk104_runl_fault_clear,
+ .preempt_pending = gf100_runl_preempt_pending,
};
-const struct nvkm_enum
-gm107_fifo_fault_engine[] = {
+static const struct nvkm_enum
+gm107_fifo_mmu_fault_engine[] = {
{ 0x01, "DISPLAY" },
{ 0x02, "CAPTURE" },
{ 0x03, "IFB", NULL, NVKM_ENGINE_IFB },
{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
{ 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM },
{ 0x06, "SCHED" },
- { 0x07, "HOST0", NULL, NVKM_ENGINE_FIFO },
- { 0x08, "HOST1", NULL, NVKM_ENGINE_FIFO },
- { 0x09, "HOST2", NULL, NVKM_ENGINE_FIFO },
- { 0x0a, "HOST3", NULL, NVKM_ENGINE_FIFO },
- { 0x0b, "HOST4", NULL, NVKM_ENGINE_FIFO },
- { 0x0c, "HOST5", NULL, NVKM_ENGINE_FIFO },
- { 0x0d, "HOST6", NULL, NVKM_ENGINE_FIFO },
- { 0x0e, "HOST7", NULL, NVKM_ENGINE_FIFO },
+ { 0x07, "HOST0" },
+ { 0x08, "HOST1" },
+ { 0x09, "HOST2" },
+ { 0x0a, "HOST3" },
+ { 0x0b, "HOST4" },
+ { 0x0c, "HOST5" },
+ { 0x0d, "HOST6" },
+ { 0x0e, "HOST7" },
{ 0x0f, "HOSTSR" },
{ 0x13, "PERF" },
{ 0x17, "PMU" },
@@ -68,8 +87,18 @@ gm107_fifo_fault_engine[] = {
{}
};
+const struct nvkm_fifo_func_mmu_fault
+gm107_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gf100_fifo_mmu_fault_access,
+ .engine = gm107_fifo_mmu_fault_engine,
+ .reason = gk104_fifo_mmu_fault_reason,
+ .hubclient = gk104_fifo_mmu_fault_hubclient,
+ .gpcclient = gk104_fifo_mmu_fault_gpcclient,
+};
+
void
-gm107_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
+gm107_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit)
{
struct nvkm_device *device = fifo->engine.subdev.device;
u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
@@ -92,22 +121,36 @@ gm107_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
nvkm_fifo_fault(fifo, &info);
}
-static const struct gk104_fifo_func
+static int
+gm107_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return 2048;
+}
+
+static const struct nvkm_fifo_func
gm107_fifo = {
- .intr.fault = gm107_fifo_intr_fault,
- .pbdma = &gk208_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gm107_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gm107_fifo_runlist,
- .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_B}, gk104_fifo_gpfifo_new },
+ .chid_nr = gm107_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gf100_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gm107_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gm107_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gm107_runl,
+ .runq = &gk208_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp },
+ .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_B }, &gm107_chan },
};
int
gm107_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gm107_fifo, device, type, inst, 2048, pfifo);
+ return nvkm_fifo_new_(&gm107_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c
index 573658cb6c73..d92d1ac39191 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c
@@ -21,41 +21,46 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
-#include "changk104.h"
+#include "priv.h"
#include <nvif/class.h>
int
-gm200_fifo_pbdma_nr(struct gk104_fifo *fifo)
+gm200_fifo_runq_nr(struct nvkm_fifo *fifo)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- return nvkm_rd32(device, 0x002004) & 0x000000ff;
+ return nvkm_rd32(fifo->engine.subdev.device, 0x002004) & 0x000000ff;
}
-const struct gk104_fifo_pbdma_func
-gm200_fifo_pbdma = {
- .nr = gm200_fifo_pbdma_nr,
- .init = gk104_fifo_pbdma_init,
- .init_timeout = gk208_fifo_pbdma_init_timeout,
-};
+int
+gm200_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return nvkm_rd32(fifo->engine.subdev.device, 0x002008);
+}
-static const struct gk104_fifo_func
+static const struct nvkm_fifo_func
gm200_fifo = {
- .intr.fault = gm107_fifo_intr_fault,
- .pbdma = &gm200_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gm107_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gm107_fifo_runlist,
- .chan = {{0,0,MAXWELL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
+ .chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gm200_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gm107_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gm107_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gm107_runl,
+ .runq = &gk208_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp },
+ .chan = {{ 0, 0, MAXWELL_CHANNEL_GPFIFO_A }, &gm107_chan },
};
int
gm200_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gm200_fifo, device, type, inst, 4096, pfifo);
+ return nvkm_fifo_new_(&gm200_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c
deleted file mode 100644
index 556c97e54f14..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "gk104.h"
-#include "changk104.h"
-
-#include <nvif/class.h>
-
-static const struct gk104_fifo_func
-gm20b_fifo = {
- .intr.fault = gm107_fifo_intr_fault,
- .pbdma = &gm200_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gm107_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gm107_fifo_runlist,
- .chan = {{0,0,MAXWELL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
-};
-
-int
-gm20b_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
- struct nvkm_fifo **pfifo)
-{
- return gk104_fifo_new_(&gm20b_fifo, device, type, inst, 512, pfifo);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c
index 6b46b6b65b87..65bdb6a7d517 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c
@@ -21,30 +21,54 @@
*
* Authors: Ben Skeggs
*/
-#include "gk104.h"
-#include "changk104.h"
+#include "priv.h"
+#include "runl.h"
+#include <core/gpuobj.h>
#include <subdev/fault.h>
#include <nvif/class.h>
-const struct nvkm_enum
-gp100_fifo_fault_engine[] = {
+static void
+gp100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
+{
+ nvkm_wo32(memory, offset + 0, chan->id | chan->runq << 14);
+ nvkm_wo32(memory, offset + 4, chan->inst->addr >> 12);
+}
+
+static const struct nvkm_runl_func
+gp100_runl = {
+ .runqs = 2,
+ .size = 8,
+ .update = nv50_runl_update,
+ .insert_cgrp = gk110_runl_insert_cgrp,
+ .insert_chan = gp100_runl_insert_chan,
+ .commit = gk104_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gk104_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .fault_clear = gk104_runl_fault_clear,
+ .preempt_pending = gf100_runl_preempt_pending,
+};
+
+static const struct nvkm_enum
+gp100_fifo_mmu_fault_engine[] = {
{ 0x01, "DISPLAY" },
{ 0x03, "IFB", NULL, NVKM_ENGINE_IFB },
{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
{ 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM },
- { 0x06, "HOST0", NULL, NVKM_ENGINE_FIFO },
- { 0x07, "HOST1", NULL, NVKM_ENGINE_FIFO },
- { 0x08, "HOST2", NULL, NVKM_ENGINE_FIFO },
- { 0x09, "HOST3", NULL, NVKM_ENGINE_FIFO },
- { 0x0a, "HOST4", NULL, NVKM_ENGINE_FIFO },
- { 0x0b, "HOST5", NULL, NVKM_ENGINE_FIFO },
- { 0x0c, "HOST6", NULL, NVKM_ENGINE_FIFO },
- { 0x0d, "HOST7", NULL, NVKM_ENGINE_FIFO },
- { 0x0e, "HOST8", NULL, NVKM_ENGINE_FIFO },
- { 0x0f, "HOST9", NULL, NVKM_ENGINE_FIFO },
- { 0x10, "HOST10", NULL, NVKM_ENGINE_FIFO },
+ { 0x06, "HOST0" },
+ { 0x07, "HOST1" },
+ { 0x08, "HOST2" },
+ { 0x09, "HOST3" },
+ { 0x0a, "HOST4" },
+ { 0x0b, "HOST5" },
+ { 0x0c, "HOST6" },
+ { 0x0d, "HOST7" },
+ { 0x0e, "HOST8" },
+ { 0x0f, "HOST9" },
+ { 0x10, "HOST10" },
{ 0x13, "PERF" },
{ 0x17, "PMU" },
{ 0x18, "PTP" },
@@ -52,8 +76,18 @@ gp100_fifo_fault_engine[] = {
{}
};
-void
-gp100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
+static const struct nvkm_fifo_func_mmu_fault
+gp100_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gf100_fifo_mmu_fault_access,
+ .engine = gp100_fifo_mmu_fault_engine,
+ .reason = gk104_fifo_mmu_fault_reason,
+ .hubclient = gk104_fifo_mmu_fault_hubclient,
+ .gpcclient = gk104_fifo_mmu_fault_gpcclient,
+};
+
+static void
+gp100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit)
{
struct nvkm_device *device = fifo->engine.subdev.device;
u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
@@ -76,23 +110,30 @@ gp100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
nvkm_fifo_fault(fifo, &info);
}
-static const struct gk104_fifo_func
+static const struct nvkm_fifo_func
gp100_fifo = {
- .intr.fault = gp100_fifo_intr_fault,
- .pbdma = &gm200_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gp100_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gm107_fifo_runlist,
- .chan = {{0,0,PASCAL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
- .cgrp_force = true,
+ .chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gm200_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_mmu_fault_unit = gp100_fifo_intr_mmu_fault_unit,
+ .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gp100_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gp100_runl,
+ .runq = &gk208_runq,
+ .engn = &gk104_engn,
+ .engn_ce = &gk104_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true },
+ .chan = {{ 0, 0, PASCAL_CHANNEL_GPFIFO_A }, &gm107_chan },
};
int
gp100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gp100_fifo, device, type, inst, 4096, pfifo);
+ return nvkm_fifo_new_(&gp100_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c
deleted file mode 100644
index 7a5929cb4d29..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "gk104.h"
-#include "changk104.h"
-
-#include <nvif/class.h>
-
-static const struct gk104_fifo_func
-gp10b_fifo = {
- .intr.fault = gp100_fifo_intr_fault,
- .pbdma = &gm200_fifo_pbdma,
- .fault.access = gk104_fifo_fault_access,
- .fault.engine = gp100_fifo_fault_engine,
- .fault.reason = gk104_fifo_fault_reason,
- .fault.hubclient = gk104_fifo_fault_hubclient,
- .fault.gpcclient = gk104_fifo_fault_gpcclient,
- .runlist = &gm107_fifo_runlist,
- .chan = {{0,0,PASCAL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new },
- .cgrp_force = true,
-};
-
-int
-gp10b_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
- struct nvkm_fifo **pfifo)
-{
- return gk104_fifo_new_(&gp10b_fifo, device, type, inst, 512, pfifo);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c
deleted file mode 100644
index 2121f517b1dd..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv50.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-
-#include <nvif/class.h>
-#include <nvif/cl826f.h>
-#include <nvif/unpack.h>
-
-static int
-g84_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct g82_channel_gpfifo_v0 v0;
- } *args = data;
- struct nv50_fifo *fifo = nv50_fifo(base);
- struct nv50_fifo_chan *chan;
- u64 ioffset, ilength;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "pushbuf %llx ioffset %016llx "
- "ilength %08x\n",
- args->v0.version, args->v0.vmm, args->v0.pushbuf,
- args->v0.ioffset, args->v0.ilength);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = g84_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf,
- oclass, chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- nvkm_kmap(chan->ramfc);
- nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078);
- nvkm_wo32(chan->ramfc, 0x44, 0x01003fff);
- nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4);
- nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset));
- nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
- nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff);
- nvkm_wo32(chan->ramfc, 0x78, 0x00000000);
- nvkm_wo32(chan->ramfc, 0x7c, 0x30000001);
- nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj->node->offset >> 4));
- nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10);
- nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12);
- nvkm_done(chan->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-g84_fifo_gpfifo_oclass = {
- .base.oclass = G82_CHANNEL_GPFIFO,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = g84_fifo_gpfifo_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
deleted file mode 100644
index 4e78bbe3b94b..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "changf100.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include <nvif/class.h>
-#include <nvif/cl906f.h>
-#include <nvif/unpack.h>
-
-int
-gf100_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
- struct nvkm_event **pevent)
-{
- switch (type) {
- case NV906F_V0_NTFY_NON_STALL_INTERRUPT:
- *pevent = &chan->fifo->uevent;
- return 0;
- case NV906F_V0_NTFY_KILLED:
- *pevent = &chan->fifo->kevent;
- return 0;
- default:
- break;
- }
- return -EINVAL;
-}
-
-static u32
-gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_SW : return 0;
- case NVKM_ENGINE_GR : return 0x0210;
- case NVKM_ENGINE_CE : return 0x0230 + (engine->subdev.inst * 0x10);
- case NVKM_ENGINE_MSPDEC: return 0x0250;
- case NVKM_ENGINE_MSPPP : return 0x0260;
- case NVKM_ENGINE_MSVLD : return 0x0270;
- default:
- WARN_ON(1);
- return 0;
- }
-}
-
-static struct gf100_fifo_engn *
-gf100_fifo_gpfifo_engine(struct gf100_fifo_chan *chan, struct nvkm_engine *engine)
-{
- int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine);
- if (engi >= 0)
- return &chan->engn[engi];
- return NULL;
-}
-
-static int
-gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- const u32 offset = gf100_fifo_gpfifo_engine_addr(engine);
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_gpuobj *inst = chan->base.inst;
- int ret = 0;
-
- mutex_lock(&chan->fifo->base.mutex);
- nvkm_wr32(device, 0x002634, chan->base.chid);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x002634) == chan->base.chid)
- break;
- ) < 0) {
- nvkm_error(subdev, "channel %d [%s] kick timeout\n",
- chan->base.chid, chan->base.object.client->name);
- ret = -ETIMEDOUT;
- }
- mutex_unlock(&chan->fifo->base.mutex);
-
- if (ret && suspend)
- return ret;
-
- if (offset) {
- nvkm_kmap(inst);
- nvkm_wo32(inst, offset + 0x00, 0x00000000);
- nvkm_wo32(inst, offset + 0x04, 0x00000000);
- nvkm_done(inst);
- }
-
- return ret;
-}
-
-static int
-gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- const u32 offset = gf100_fifo_gpfifo_engine_addr(engine);
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
- struct nvkm_gpuobj *inst = chan->base.inst;
-
- if (offset) {
- nvkm_kmap(inst);
- nvkm_wo32(inst, offset + 0x00, lower_32_bits(engn->vma->addr) | 4);
- nvkm_wo32(inst, offset + 0x04, upper_32_bits(engn->vma->addr));
- nvkm_done(inst);
- }
-
- return 0;
-}
-
-static void
-gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
- nvkm_vmm_put(chan->base.vmm, &engn->vma);
- nvkm_gpuobj_del(&engn->inst);
-}
-
-static int
-gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine,
- struct nvkm_object *object)
-{
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
- int ret;
-
- if (!gf100_fifo_gpfifo_engine_addr(engine))
- return 0;
-
- ret = nvkm_object_bind(object, NULL, 0, &engn->inst);
- if (ret)
- return ret;
-
- ret = nvkm_vmm_get(chan->base.vmm, 12, engn->inst->size, &engn->vma);
- if (ret)
- return ret;
-
- return nvkm_memory_map(engn->inst, 0, chan->base.vmm, engn->vma, NULL, 0);
-}
-
-static void
-gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
-{
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct gf100_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 coff = chan->base.chid * 8;
-
- if (!list_empty(&chan->head) && !chan->killed) {
- gf100_fifo_runlist_remove(fifo, chan);
- nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000);
- gf100_fifo_runlist_commit(fifo);
- }
-
- gf100_fifo_intr_engine(fifo);
-
- nvkm_wr32(device, 0x003000 + coff, 0x00000000);
-}
-
-static void
-gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
-{
- struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
- struct gf100_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 addr = chan->base.inst->addr >> 12;
- u32 coff = chan->base.chid * 8;
-
- nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr);
-
- if (list_empty(&chan->head) && !chan->killed) {
- gf100_fifo_runlist_insert(fifo, chan);
- nvkm_wr32(device, 0x003004 + coff, 0x001f0001);
- gf100_fifo_runlist_commit(fifo);
- }
-}
-
-static void *
-gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base)
-{
- return gf100_fifo_chan(base);
-}
-
-static const struct nvkm_fifo_chan_func
-gf100_fifo_gpfifo_func = {
- .dtor = gf100_fifo_gpfifo_dtor,
- .init = gf100_fifo_gpfifo_init,
- .fini = gf100_fifo_gpfifo_fini,
- .ntfy = gf100_fifo_chan_ntfy,
- .engine_ctor = gf100_fifo_gpfifo_engine_ctor,
- .engine_dtor = gf100_fifo_gpfifo_engine_dtor,
- .engine_init = gf100_fifo_gpfifo_engine_init,
- .engine_fini = gf100_fifo_gpfifo_engine_fini,
-};
-
-static int
-gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- union {
- struct fermi_channel_gpfifo_v0 v0;
- } *args = data;
- struct gf100_fifo *fifo = gf100_fifo(base);
- struct nvkm_object *parent = oclass->parent;
- struct gf100_fifo_chan *chan;
- u64 usermem, ioffset, ilength;
- int ret = -ENOSYS, i;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "ioffset %016llx ilength %08x\n",
- args->v0.version, args->v0.vmm, args->v0.ioffset,
- args->v0.ilength);
- if (!args->v0.vmm)
- return -EINVAL;
- } else
- return ret;
-
- /* allocate channel */
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
- chan->fifo = fifo;
- INIT_LIST_HEAD(&chan->head);
-
- ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base,
- 0x1000, 0x1000, true, args->v0.vmm, 0,
- BIT(GF100_FIFO_ENGN_GR) |
- BIT(GF100_FIFO_ENGN_MSPDEC) |
- BIT(GF100_FIFO_ENGN_MSPPP) |
- BIT(GF100_FIFO_ENGN_MSVLD) |
- BIT(GF100_FIFO_ENGN_CE0) |
- BIT(GF100_FIFO_ENGN_CE1) |
- BIT(GF100_FIFO_ENGN_SW),
- 1, fifo->user.bar->addr, 0x1000,
- oclass, &chan->base);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- /* clear channel control registers */
-
- usermem = chan->base.chid * 0x1000;
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- nvkm_kmap(fifo->user.mem);
- for (i = 0; i < 0x1000; i += 4)
- nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000);
- nvkm_done(fifo->user.mem);
- usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
-
- /* RAMFC */
- nvkm_kmap(chan->base.inst);
- nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x10, 0x0000face);
- nvkm_wo32(chan->base.inst, 0x30, 0xfffff902);
- nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset));
- nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) |
- (ilength << 16));
- nvkm_wo32(chan->base.inst, 0x54, 0x00000002);
- nvkm_wo32(chan->base.inst, 0x84, 0x20400000);
- nvkm_wo32(chan->base.inst, 0x94, 0x30000001);
- nvkm_wo32(chan->base.inst, 0x9c, 0x00000100);
- nvkm_wo32(chan->base.inst, 0xa4, 0x1f1f1f1f);
- nvkm_wo32(chan->base.inst, 0xa8, 0x1f1f1f1f);
- nvkm_wo32(chan->base.inst, 0xac, 0x0000001f);
- nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000);
- nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */
- nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */
- nvkm_done(chan->base.inst);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-gf100_fifo_gpfifo_oclass = {
- .base.oclass = FERMI_CHANNEL_GPFIFO,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = gf100_fifo_gpfifo_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
deleted file mode 100644
index 80456ec70e8a..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "changk104.h"
-#include "cgrp.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <subdev/fb.h>
-#include <subdev/mmu.h>
-#include <subdev/timer.h>
-
-#include <nvif/class.h>
-#include <nvif/cla06f.h>
-#include <nvif/unpack.h>
-
-int
-gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *chan)
-{
- struct gk104_fifo *fifo = chan->fifo;
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_client *client = chan->base.object.client;
- struct nvkm_fifo_cgrp *cgrp = chan->cgrp;
- int ret = 0;
-
- if (cgrp)
- nvkm_wr32(device, 0x002634, cgrp->id | 0x01000000);
- else
- nvkm_wr32(device, 0x002634, chan->base.chid);
- if (nvkm_msec(device, 2000,
- if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
- break;
- ) < 0) {
- nvkm_error(subdev, "%s %d [%s] kick timeout\n",
- cgrp ? "tsg" : "channel",
- cgrp ? cgrp->id : chan->base.chid, client->name);
- nvkm_fifo_recover_chan(&fifo->base, chan->base.chid);
- ret = -ETIMEDOUT;
- }
- return ret;
-}
-
-int
-gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan)
-{
- int ret;
- mutex_lock(&chan->base.fifo->mutex);
- ret = gk104_fifo_gpfifo_kick_locked(chan);
- mutex_unlock(&chan->base.fifo->mutex);
- return ret;
-}
-
-static u32
-gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_SW :
- case NVKM_ENGINE_CE : return 0;
- case NVKM_ENGINE_GR : return 0x0210;
- case NVKM_ENGINE_SEC : return 0x0220;
- case NVKM_ENGINE_MSPDEC: return 0x0250;
- case NVKM_ENGINE_MSPPP : return 0x0260;
- case NVKM_ENGINE_MSVLD : return 0x0270;
- case NVKM_ENGINE_VIC : return 0x0280;
- case NVKM_ENGINE_MSENC : return 0x0290;
- case NVKM_ENGINE_NVDEC : return 0x02100270;
- case NVKM_ENGINE_NVENC :
- if (engine->subdev.inst)
- return 0x0210;
- return 0x02100290;
- default:
- WARN_ON(1);
- return 0;
- }
-}
-
-struct gk104_fifo_engn *
-gk104_fifo_gpfifo_engine(struct gk104_fifo_chan *chan, struct nvkm_engine *engine)
-{
- int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine);
- if (engi >= 0)
- return &chan->engn[engi];
- return NULL;
-}
-
-static int
-gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct nvkm_gpuobj *inst = chan->base.inst;
- u32 offset = gk104_fifo_gpfifo_engine_addr(engine);
- int ret;
-
- ret = gk104_fifo_gpfifo_kick(chan);
- if (ret && suspend)
- return ret;
-
- if (offset) {
- nvkm_kmap(inst);
- nvkm_wo32(inst, (offset & 0xffff) + 0x00, 0x00000000);
- nvkm_wo32(inst, (offset & 0xffff) + 0x04, 0x00000000);
- if ((offset >>= 16)) {
- nvkm_wo32(inst, offset + 0x00, 0x00000000);
- nvkm_wo32(inst, offset + 0x04, 0x00000000);
- }
- nvkm_done(inst);
- }
-
- return ret;
-}
-
-static int
-gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine);
- struct nvkm_gpuobj *inst = chan->base.inst;
- u32 offset = gk104_fifo_gpfifo_engine_addr(engine);
-
- if (offset) {
- u32 datalo = lower_32_bits(engn->vma->addr) | 0x00000004;
- u32 datahi = upper_32_bits(engn->vma->addr);
- nvkm_kmap(inst);
- nvkm_wo32(inst, (offset & 0xffff) + 0x00, datalo);
- nvkm_wo32(inst, (offset & 0xffff) + 0x04, datahi);
- if ((offset >>= 16)) {
- nvkm_wo32(inst, offset + 0x00, datalo);
- nvkm_wo32(inst, offset + 0x04, datahi);
- }
- nvkm_done(inst);
- }
-
- return 0;
-}
-
-void
-gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine);
- nvkm_vmm_put(chan->base.vmm, &engn->vma);
- nvkm_gpuobj_del(&engn->inst);
-}
-
-int
-gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine,
- struct nvkm_object *object)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine);
- int ret;
-
- if (!gk104_fifo_gpfifo_engine_addr(engine)) {
- if (engine->subdev.type != NVKM_ENGINE_CE ||
- engine->subdev.device->card_type < GV100)
- return 0;
- }
-
- ret = nvkm_object_bind(object, NULL, 0, &engn->inst);
- if (ret)
- return ret;
-
- if (!gk104_fifo_gpfifo_engine_addr(engine))
- return 0;
-
- ret = nvkm_vmm_get(chan->base.vmm, 12, engn->inst->size, &engn->vma);
- if (ret)
- return ret;
-
- return nvkm_memory_map(engn->inst, 0, chan->base.vmm, engn->vma, NULL, 0);
-}
-
-void
-gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 coff = chan->base.chid * 8;
-
- if (!list_empty(&chan->head)) {
- gk104_fifo_runlist_remove(fifo, chan);
- nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800);
- gk104_fifo_gpfifo_kick(chan);
- gk104_fifo_runlist_update(fifo, chan->runl);
- }
-
- nvkm_wr32(device, 0x800000 + coff, 0x00000000);
-}
-
-void
-gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo *fifo = chan->fifo;
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u32 addr = chan->base.inst->addr >> 12;
- u32 coff = chan->base.chid * 8;
-
- nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->runl << 16);
- nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr);
-
- if (list_empty(&chan->head) && !chan->killed) {
- gk104_fifo_runlist_insert(fifo, chan);
- nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
- gk104_fifo_runlist_update(fifo, chan->runl);
- nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
- }
-}
-
-void *
-gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- kfree(chan->cgrp);
- return chan;
-}
-
-const struct nvkm_fifo_chan_func
-gk104_fifo_gpfifo_func = {
- .dtor = gk104_fifo_gpfifo_dtor,
- .init = gk104_fifo_gpfifo_init,
- .fini = gk104_fifo_gpfifo_fini,
- .ntfy = gf100_fifo_chan_ntfy,
- .engine_ctor = gk104_fifo_gpfifo_engine_ctor,
- .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
- .engine_init = gk104_fifo_gpfifo_engine_init,
- .engine_fini = gk104_fifo_gpfifo_engine_fini,
-};
-
-static int
-gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
- u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv,
- const struct nvkm_oclass *oclass,
- struct nvkm_object **pobject)
-{
- struct gk104_fifo_chan *chan;
- int runlist = ffs(*runlists) -1, ret, i;
- u64 usermem;
-
- if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr)
- return -EINVAL;
- *runlists = BIT_ULL(runlist);
-
- /* Allocate the channel. */
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
- chan->fifo = fifo;
- chan->runl = runlist;
- INIT_LIST_HEAD(&chan->head);
-
- ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base,
- 0x1000, 0x1000, true, vmm, 0, fifo->runlist[runlist].engm_sw,
- 1, fifo->user.bar->addr, 0x200,
- oclass, &chan->base);
- if (ret)
- return ret;
-
- *chid = chan->base.chid;
- *inst = chan->base.inst->addr;
-
- /* Hack to support GPUs where even individual channels should be
- * part of a channel group.
- */
- if (fifo->func->cgrp_force) {
- if (!(chan->cgrp = kmalloc(sizeof(*chan->cgrp), GFP_KERNEL)))
- return -ENOMEM;
- chan->cgrp->id = chan->base.chid;
- INIT_LIST_HEAD(&chan->cgrp->head);
- INIT_LIST_HEAD(&chan->cgrp->chan);
- chan->cgrp->chan_nr = 0;
- }
-
- /* Clear channel control registers. */
- usermem = chan->base.chid * 0x200;
- ilength = order_base_2(ilength / 8);
-
- nvkm_kmap(fifo->user.mem);
- for (i = 0; i < 0x200; i += 4)
- nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000);
- nvkm_done(fifo->user.mem);
- usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
-
- /* RAMFC */
- nvkm_kmap(chan->base.inst);
- nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x10, 0x0000face);
- nvkm_wo32(chan->base.inst, 0x30, 0xfffff902);
- nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset));
- nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) |
- (ilength << 16));
- nvkm_wo32(chan->base.inst, 0x84, 0x20400000);
- nvkm_wo32(chan->base.inst, 0x94, 0x30000001);
- nvkm_wo32(chan->base.inst, 0x9c, 0x00000100);
- nvkm_wo32(chan->base.inst, 0xac, 0x0000001f);
- nvkm_wo32(chan->base.inst, 0xe4, priv ? 0x00000020 : 0x00000000);
- nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid);
- nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000);
- nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */
- nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */
- nvkm_done(chan->base.inst);
- return 0;
-}
-
-int
-gk104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct kepler_channel_gpfifo_a_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "ioffset %016llx ilength %08x "
- "runlist %016llx priv %d\n",
- args->v0.version, args->v0.vmm, args->v0.ioffset,
- args->v0.ilength, args->v0.runlist, args->v0.priv);
- return gk104_fifo_gpfifo_new_(fifo,
- &args->v0.runlist,
- &args->v0.chid,
- args->v0.vmm,
- args->v0.ioffset,
- args->v0.ilength,
- &args->v0.inst,
- args->v0.priv,
- oclass, pobject);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c
deleted file mode 100644
index 428f9b41165c..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2018 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "changk104.h"
-#include "cgrp.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-
-#include <nvif/clc36f.h>
-#include <nvif/unpack.h>
-
-static u32
-gv100_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *chan)
-{
- return chan->chid;
-}
-
-static int
-gv100_fifo_gpfifo_engine_valid(struct gk104_fifo_chan *chan, bool ce, bool valid)
-{
- struct nvkm_subdev *subdev = &chan->base.fifo->engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 mask = ce ? 0x00020000 : 0x00010000;
- const u32 data = valid ? mask : 0x00000000;
- int ret;
-
- /* Block runlist to prevent the channel from being rescheduled. */
- mutex_lock(&chan->fifo->base.mutex);
- nvkm_mask(device, 0x002630, BIT(chan->runl), BIT(chan->runl));
-
- /* Preempt the channel. */
- ret = gk104_fifo_gpfifo_kick_locked(chan);
- if (ret == 0) {
- /* Update engine context validity. */
- nvkm_kmap(chan->base.inst);
- nvkm_mo32(chan->base.inst, 0x0ac, mask, data);
- nvkm_done(chan->base.inst);
- }
-
- /* Resume runlist. */
- nvkm_mask(device, 0x002630, BIT(chan->runl), 0);
- mutex_unlock(&chan->fifo->base.mutex);
- return ret;
-}
-
-int
-gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine, bool suspend)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct nvkm_gpuobj *inst = chan->base.inst;
- int ret;
-
- if (engine->subdev.type == NVKM_ENGINE_CE) {
- ret = gv100_fifo_gpfifo_engine_valid(chan, true, false);
- if (ret && suspend)
- return ret;
-
- nvkm_kmap(inst);
- nvkm_wo32(chan->base.inst, 0x220, 0x00000000);
- nvkm_wo32(chan->base.inst, 0x224, 0x00000000);
- nvkm_done(inst);
- return ret;
- }
-
- ret = gv100_fifo_gpfifo_engine_valid(chan, false, false);
- if (ret && suspend)
- return ret;
-
- nvkm_kmap(inst);
- nvkm_wo32(inst, 0x0210, 0x00000000);
- nvkm_wo32(inst, 0x0214, 0x00000000);
- nvkm_done(inst);
- return ret;
-}
-
-int
-gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
- struct nvkm_engine *engine)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine);
- struct nvkm_gpuobj *inst = chan->base.inst;
-
- if (engine->subdev.type == NVKM_ENGINE_CE) {
- const u64 bar2 = nvkm_memory_bar2(engn->inst->memory);
-
- nvkm_kmap(inst);
- nvkm_wo32(chan->base.inst, 0x220, lower_32_bits(bar2));
- nvkm_wo32(chan->base.inst, 0x224, upper_32_bits(bar2));
- nvkm_done(inst);
-
- return gv100_fifo_gpfifo_engine_valid(chan, true, true);
- }
-
- nvkm_kmap(inst);
- nvkm_wo32(inst, 0x210, lower_32_bits(engn->vma->addr) | 0x00000004);
- nvkm_wo32(inst, 0x214, upper_32_bits(engn->vma->addr));
- nvkm_done(inst);
-
- return gv100_fifo_gpfifo_engine_valid(chan, false, true);
-}
-
-static const struct nvkm_fifo_chan_func
-gv100_fifo_gpfifo = {
- .dtor = gk104_fifo_gpfifo_dtor,
- .init = gk104_fifo_gpfifo_init,
- .fini = gk104_fifo_gpfifo_fini,
- .ntfy = gf100_fifo_chan_ntfy,
- .engine_ctor = gk104_fifo_gpfifo_engine_ctor,
- .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
- .engine_init = gv100_fifo_gpfifo_engine_init,
- .engine_fini = gv100_fifo_gpfifo_engine_fini,
- .submit_token = gv100_fifo_gpfifo_submit_token,
-};
-
-int
-gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *func,
- struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
- u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv,
- u32 *token, const struct nvkm_oclass *oclass,
- struct nvkm_object **pobject)
-{
- struct gk104_fifo_chan *chan;
- int runlist = ffs(*runlists) -1, ret, i;
- u64 usermem;
-
- if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr)
- return -EINVAL;
- *runlists = BIT_ULL(runlist);
-
- /* Allocate the channel. */
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
- chan->fifo = fifo;
- chan->runl = runlist;
- INIT_LIST_HEAD(&chan->head);
-
- ret = nvkm_fifo_chan_ctor(func, &fifo->base, 0x1000, 0x1000, true, vmm,
- 0, fifo->runlist[runlist].engm, 1, fifo->user.bar->addr, 0x200,
- oclass, &chan->base);
- if (ret)
- return ret;
-
- *chid = chan->base.chid;
- *inst = chan->base.inst->addr;
- *token = chan->base.func->submit_token(&chan->base);
-
- /* Hack to support GPUs where even individual channels should be
- * part of a channel group.
- */
- if (fifo->func->cgrp_force) {
- if (!(chan->cgrp = kmalloc(sizeof(*chan->cgrp), GFP_KERNEL)))
- return -ENOMEM;
- chan->cgrp->id = chan->base.chid;
- INIT_LIST_HEAD(&chan->cgrp->head);
- INIT_LIST_HEAD(&chan->cgrp->chan);
- chan->cgrp->chan_nr = 0;
- }
-
- /* Clear channel control registers. */
- usermem = chan->base.chid * 0x200;
- ilength = order_base_2(ilength / 8);
-
- nvkm_kmap(fifo->user.mem);
- for (i = 0; i < 0x200; i += 4)
- nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000);
- nvkm_done(fifo->user.mem);
- usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
-
- /* RAMFC */
- nvkm_kmap(chan->base.inst);
- nvkm_wo32(chan->base.inst, 0x008, lower_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x00c, upper_32_bits(usermem));
- nvkm_wo32(chan->base.inst, 0x010, 0x0000face);
- nvkm_wo32(chan->base.inst, 0x030, 0x7ffff902);
- nvkm_wo32(chan->base.inst, 0x048, lower_32_bits(ioffset));
- nvkm_wo32(chan->base.inst, 0x04c, upper_32_bits(ioffset) |
- (ilength << 16));
- nvkm_wo32(chan->base.inst, 0x084, 0x20400000);
- nvkm_wo32(chan->base.inst, 0x094, 0x30000001);
- nvkm_wo32(chan->base.inst, 0x0e4, priv ? 0x00000020 : 0x00000000);
- nvkm_wo32(chan->base.inst, 0x0e8, chan->base.chid);
- nvkm_wo32(chan->base.inst, 0x0f4, 0x00001000);
- nvkm_wo32(chan->base.inst, 0x0f8, 0x10003080);
- nvkm_mo32(chan->base.inst, 0x218, 0x00000000, 0x00000000);
- nvkm_done(chan->base.inst);
- return 0;
-}
-
-int
-gv100_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct volta_channel_gpfifo_a_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "ioffset %016llx ilength %08x "
- "runlist %016llx priv %d\n",
- args->v0.version, args->v0.vmm, args->v0.ioffset,
- args->v0.ilength, args->v0.runlist, args->v0.priv);
- return gv100_fifo_gpfifo_new_(&gv100_fifo_gpfifo, fifo,
- &args->v0.runlist,
- &args->v0.chid,
- args->v0.vmm,
- args->v0.ioffset,
- args->v0.ilength,
- &args->v0.inst,
- args->v0.priv,
- &args->v0.token,
- oclass, pobject);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c
deleted file mode 100644
index d8f28ec1e4a8..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: Ben Skeggs
- */
-#include "channv50.h"
-
-#include <core/client.h>
-#include <core/ramht.h>
-
-#include <nvif/class.h>
-#include <nvif/cl506f.h>
-#include <nvif/unpack.h>
-
-static int
-nv50_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct nv50_channel_gpfifo_v0 v0;
- } *args = data;
- struct nv50_fifo *fifo = nv50_fifo(base);
- struct nv50_fifo_chan *chan;
- u64 ioffset, ilength;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "pushbuf %llx ioffset %016llx "
- "ilength %08x\n",
- args->v0.version, args->v0.vmm, args->v0.pushbuf,
- args->v0.ioffset, args->v0.ilength);
- if (!args->v0.pushbuf)
- return -EINVAL;
- } else
- return ret;
-
- if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
- return -ENOMEM;
- *pobject = &chan->base.object;
-
- ret = nv50_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf,
- oclass, chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- nvkm_kmap(chan->ramfc);
- nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078);
- nvkm_wo32(chan->ramfc, 0x44, 0x01003fff);
- nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4);
- nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset));
- nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
- nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff);
- nvkm_wo32(chan->ramfc, 0x78, 0x00000000);
- nvkm_wo32(chan->ramfc, 0x7c, 0x30000001);
- nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj->node->offset >> 4));
- nvkm_done(chan->ramfc);
- return 0;
-}
-
-const struct nvkm_fifo_chan_oclass
-nv50_fifo_gpfifo_oclass = {
- .base.oclass = NV50_CHANNEL_GPFIFO,
- .base.minver = 0,
- .base.maxver = 0,
- .ctor = nv50_fifo_gpfifo_new,
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c
deleted file mode 100644
index 99aafa103a31..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2018 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "changk104.h"
-#include "cgrp.h"
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-
-#include <nvif/clc36f.h>
-#include <nvif/unpack.h>
-
-static u32
-tu102_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *base)
-{
- struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
- return (chan->runl << 16) | chan->base.chid;
-}
-
-static const struct nvkm_fifo_chan_func
-tu102_fifo_gpfifo = {
- .dtor = gk104_fifo_gpfifo_dtor,
- .init = gk104_fifo_gpfifo_init,
- .fini = gk104_fifo_gpfifo_fini,
- .ntfy = gf100_fifo_chan_ntfy,
- .engine_ctor = gk104_fifo_gpfifo_engine_ctor,
- .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
- .engine_init = gv100_fifo_gpfifo_engine_init,
- .engine_fini = gv100_fifo_gpfifo_engine_fini,
- .submit_token = tu102_fifo_gpfifo_submit_token,
-};
-
-int
-tu102_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
- void *data, u32 size, struct nvkm_object **pobject)
-{
- struct nvkm_object *parent = oclass->parent;
- union {
- struct volta_channel_gpfifo_a_v0 v0;
- } *args = data;
- int ret = -ENOSYS;
-
- nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
- nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
- "ioffset %016llx ilength %08x "
- "runlist %016llx priv %d\n",
- args->v0.version, args->v0.vmm, args->v0.ioffset,
- args->v0.ilength, args->v0.runlist, args->v0.priv);
- return gv100_fifo_gpfifo_new_(&tu102_fifo_gpfifo, fifo,
- &args->v0.runlist,
- &args->v0.chid,
- args->v0.vmm,
- args->v0.ioffset,
- args->v0.ilength,
- &args->v0.inst,
- args->v0.priv,
- &args->v0.token,
- oclass, pobject);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c
index faf0fe9f704c..33066c8cdc64 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c
@@ -19,32 +19,180 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "gk104.h"
+#include "priv.h"
+#include "chan.h"
+#include "chid.h"
#include "cgrp.h"
-#include "changk104.h"
-#include "user.h"
+#include "runl.h"
+#include "runq.h"
#include <core/gpuobj.h>
+#include <subdev/mmu.h>
#include <nvif/class.h>
+static u32
+gv100_chan_doorbell_handle(struct nvkm_chan *chan)
+{
+ return chan->id;
+}
+
+static int
+gv100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
+ const u32 limit2 = ilog2(length / 8);
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x008, lower_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x00c, upper_32_bits(userd));
+ nvkm_wo32(chan->inst, 0x010, 0x0000face);
+ nvkm_wo32(chan->inst, 0x030, 0x7ffff902);
+ nvkm_wo32(chan->inst, 0x048, lower_32_bits(offset));
+ nvkm_wo32(chan->inst, 0x04c, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->inst, 0x084, 0x20400000);
+ nvkm_wo32(chan->inst, 0x094, 0x30000000 | devm);
+ nvkm_wo32(chan->inst, 0x0e4, priv ? 0x00000020 : 0x00000000);
+ nvkm_wo32(chan->inst, 0x0e8, chan->id);
+ nvkm_wo32(chan->inst, 0x0f4, 0x00001000 | (priv ? 0x00000100 : 0x00000000));
+ nvkm_wo32(chan->inst, 0x0f8, 0x10003080);
+ nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000);
+ nvkm_done(chan->inst);
+ return 0;
+}
+
+const struct nvkm_chan_func_ramfc
+gv100_chan_ramfc = {
+ .write = gv100_chan_ramfc_write,
+ .devm = 0xfff,
+ .priv = true,
+};
+
+const struct nvkm_chan_func_userd
+gv100_chan_userd = {
+ .bar = -1,
+ .size = 0x200,
+ .clear = gf100_chan_userd_clear,
+};
+
+static const struct nvkm_chan_func
+gv100_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gv100_chan_userd,
+ .ramfc = &gv100_chan_ramfc,
+ .bind = gk104_chan_bind_inst,
+ .unbind = gk104_chan_unbind,
+ .start = gk104_chan_start,
+ .stop = gk104_chan_stop,
+ .preempt = gk110_chan_preempt,
+ .doorbell_handle = gv100_chan_doorbell_handle,
+};
+
+void
+gv100_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
+{
+ u64 addr = 0ULL;
+
+ if (cctx) {
+ addr = cctx->vctx->vma->addr;
+ addr |= 4ULL;
+ }
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x210, lower_32_bits(addr));
+ nvkm_wo32(chan->inst, 0x214, upper_32_bits(addr));
+ nvkm_mo32(chan->inst, 0x0ac, 0x00010000, cctx ? 0x00010000 : 0x00000000);
+ nvkm_done(chan->inst);
+}
+
+const struct nvkm_engn_func
+gv100_engn = {
+ .chsw = gk104_engn_chsw,
+ .cxid = gk104_engn_cxid,
+ .ctor = gk104_ectx_ctor,
+ .bind = gv100_ectx_bind,
+};
+
+void
+gv100_ectx_ce_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
+{
+ const u64 bar2 = cctx ? nvkm_memory_bar2(cctx->vctx->inst->memory) : 0ULL;
+
+ nvkm_kmap(chan->inst);
+ nvkm_wo32(chan->inst, 0x220, lower_32_bits(bar2));
+ nvkm_wo32(chan->inst, 0x224, upper_32_bits(bar2));
+ nvkm_mo32(chan->inst, 0x0ac, 0x00020000, cctx ? 0x00020000 : 0x00000000);
+ nvkm_done(chan->inst);
+}
+
+int
+gv100_ectx_ce_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx)
+{
+ if (nvkm_memory_bar2(vctx->inst->memory) == ~0ULL)
+ return -EFAULT;
+
+ return 0;
+}
+
+const struct nvkm_engn_func
+gv100_engn_ce = {
+ .chsw = gk104_engn_chsw,
+ .cxid = gk104_engn_cxid,
+ .ctor = gv100_ectx_ce_ctor,
+ .bind = gv100_ectx_ce_bind,
+};
+
+static bool
+gv100_runq_intr_1_ctxnotvalid(struct nvkm_runq *runq, int chid)
+{
+ struct nvkm_fifo *fifo = runq->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+
+ RUNQ_ERROR(runq, "CTXNOTVALID chid:%d", chid);
+
+ chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags);
+ if (WARN_ON_ONCE(!chan))
+ return false;
+
+ nvkm_chan_error(chan, true);
+ nvkm_chan_put(&chan, flags);
+
+ nvkm_mask(device, 0x0400ac + (runq->id * 0x2000), 0x00030000, 0x00030000);
+ nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), 0x80000000);
+ return true;
+}
+
+const struct nvkm_runq_func
+gv100_runq = {
+ .init = gk208_runq_init,
+ .intr = gk104_runq_intr,
+ .intr_0_names = gk104_runq_intr_0_names,
+ .intr_1_ctxnotvalid = gv100_runq_intr_1_ctxnotvalid,
+ .idle = gk104_runq_idle,
+};
+
+void
+gv100_runl_preempt(struct nvkm_runl *runl)
+{
+ nvkm_wr32(runl->fifo->engine.subdev.device, 0x002638, BIT(runl->id));
+}
+
void
-gv100_fifo_runlist_chan(struct gk104_fifo_chan *chan,
- struct nvkm_memory *memory, u32 offset)
+gv100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
{
- struct nvkm_memory *usermem = chan->fifo->user.mem;
- const u64 user = nvkm_memory_addr(usermem) + (chan->base.chid * 0x200);
- const u64 inst = chan->base.inst->addr;
+ const u64 user = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
+ const u64 inst = chan->inst->addr;
- nvkm_wo32(memory, offset + 0x0, lower_32_bits(user));
+ nvkm_wo32(memory, offset + 0x0, lower_32_bits(user) | chan->runq << 1);
nvkm_wo32(memory, offset + 0x4, upper_32_bits(user));
- nvkm_wo32(memory, offset + 0x8, lower_32_bits(inst) | chan->base.chid);
+ nvkm_wo32(memory, offset + 0x8, lower_32_bits(inst) | chan->id);
nvkm_wo32(memory, offset + 0xc, upper_32_bits(inst));
}
void
-gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp,
- struct nvkm_memory *memory, u32 offset)
+gv100_runl_insert_cgrp(struct nvkm_cgrp *cgrp, struct nvkm_memory *memory, u64 offset)
{
nvkm_wo32(memory, offset + 0x0, (128 << 24) | (3 << 16) | 0x00000001);
nvkm_wo32(memory, offset + 0x4, cgrp->chan_nr);
@@ -52,16 +200,24 @@ gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp,
nvkm_wo32(memory, offset + 0xc, 0x00000000);
}
-static const struct gk104_fifo_runlist_func
-gv100_fifo_runlist = {
+static const struct nvkm_runl_func
+gv100_runl = {
+ .runqs = 2,
.size = 16,
- .cgrp = gv100_fifo_runlist_cgrp,
- .chan = gv100_fifo_runlist_chan,
- .commit = gk104_fifo_runlist_commit,
+ .update = nv50_runl_update,
+ .insert_cgrp = gv100_runl_insert_cgrp,
+ .insert_chan = gv100_runl_insert_chan,
+ .commit = gk104_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = gk104_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .preempt = gv100_runl_preempt,
+ .preempt_pending = gf100_runl_preempt_pending,
};
const struct nvkm_enum
-gv100_fifo_fault_gpcclient[] = {
+gv100_fifo_mmu_fault_gpcclient[] = {
{ 0x00, "T1_0" },
{ 0x01, "T1_1" },
{ 0x02, "T1_2" },
@@ -163,7 +319,7 @@ gv100_fifo_fault_gpcclient[] = {
};
const struct nvkm_enum
-gv100_fifo_fault_hubclient[] = {
+gv100_fifo_mmu_fault_hubclient[] = {
{ 0x00, "VIP" },
{ 0x01, "CE0" },
{ 0x02, "CE1" },
@@ -225,7 +381,7 @@ gv100_fifo_fault_hubclient[] = {
};
const struct nvkm_enum
-gv100_fifo_fault_reason[] = {
+gv100_fifo_mmu_fault_reason[] = {
{ 0x00, "PDE" },
{ 0x01, "PDE_SIZE" },
{ 0x02, "PTE" },
@@ -246,7 +402,7 @@ gv100_fifo_fault_reason[] = {
};
static const struct nvkm_enum
-gv100_fifo_fault_engine[] = {
+gv100_fifo_mmu_fault_engine[] = {
{ 0x01, "DISPLAY" },
{ 0x03, "PTP" },
{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
@@ -273,7 +429,7 @@ gv100_fifo_fault_engine[] = {
};
const struct nvkm_enum
-gv100_fifo_fault_access[] = {
+gv100_fifo_mmu_fault_access[] = {
{ 0x0, "VIRT_READ" },
{ 0x1, "VIRT_WRITE" },
{ 0x2, "VIRT_ATOMIC" },
@@ -286,23 +442,51 @@ gv100_fifo_fault_access[] = {
{}
};
-static const struct gk104_fifo_func
+static const struct nvkm_fifo_func_mmu_fault
+gv100_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gv100_fifo_mmu_fault_access,
+ .engine = gv100_fifo_mmu_fault_engine,
+ .reason = gv100_fifo_mmu_fault_reason,
+ .hubclient = gv100_fifo_mmu_fault_hubclient,
+ .gpcclient = gv100_fifo_mmu_fault_gpcclient,
+};
+
+static void
+gv100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo, u32 engm)
+{
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id))
+ nvkm_runl_rc_engn(runl, engn);
+ }
+}
+
+static const struct nvkm_fifo_func
gv100_fifo = {
- .pbdma = &gm200_fifo_pbdma,
- .fault.access = gv100_fifo_fault_access,
- .fault.engine = gv100_fifo_fault_engine,
- .fault.reason = gv100_fifo_fault_reason,
- .fault.hubclient = gv100_fifo_fault_hubclient,
- .fault.gpcclient = gv100_fifo_fault_gpcclient,
- .runlist = &gv100_fifo_runlist,
- .user = {{-1,-1,VOLTA_USERMODE_A }, gv100_fifo_user_new },
- .chan = {{ 0, 0,VOLTA_CHANNEL_GPFIFO_A}, gv100_fifo_gpfifo_new },
- .cgrp_force = true,
+ .chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gm200_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
+ .init = gk104_fifo_init,
+ .init_pbdmas = gk104_fifo_init_pbdmas,
+ .intr = gk104_fifo_intr,
+ .intr_ctxsw_timeout = gv100_fifo_intr_ctxsw_timeout,
+ .mmu_fault = &gv100_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &gv100_runl,
+ .runq = &gv100_runq,
+ .engn = &gv100_engn,
+ .engn_ce = &gv100_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true },
+ .chan = {{ 0, 0, VOLTA_CHANNEL_GPFIFO_A }, &gv100_chan },
};
int
gv100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&gv100_fifo, device, type, inst, 4096, pfifo);
+ return nvkm_fifo_new_(&gv100_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
index c6730c124769..674faf002b20 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
@@ -21,38 +21,201 @@
*
* Authors: Ben Skeggs
*/
-#include "nv04.h"
-#include "channv04.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+
#include "regsnv04.h"
-#include <core/client.h>
#include <core/ramht.h>
#include <subdev/instmem.h>
+#include <subdev/mc.h>
#include <subdev/timer.h>
#include <engine/sw.h>
-static const struct nv04_fifo_ramfc
-nv04_fifo_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
- {}
+#include <nvif/class.h>
+
+void
+nv04_chan_stop(struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_memory *fctx = device->imem->ramfc;
+ const struct nvkm_ramfc_layout *c;
+ unsigned long flags;
+ u32 data = chan->ramfc_offset;
+ u32 chid;
+
+ /* prevent fifo context switches */
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_wr32(device, NV03_PFIFO_CACHES, 0);
+
+ /* if this channel is active, replace it with a null context */
+ chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->chid->mask;
+ if (chid == chan->id) {
+ nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0);
+ nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
+
+ c = chan->func->ramfc->layout;
+ nvkm_kmap(fctx);
+ do {
+ u32 rm = ((1ULL << c->bits) - 1) << c->regs;
+ u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
+ u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs;
+ u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm);
+ nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
+ } while ((++c)->bits);
+ nvkm_done(fctx);
+
+ c = chan->func->ramfc->layout;
+ do {
+ nvkm_wr32(device, c->regp, 0x00000000);
+ } while ((++c)->bits);
+
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1);
+ }
+
+ /* restore normal operation, after disabling dma mode */
+ nvkm_mask(device, NV04_PFIFO_MODE, BIT(chan->id), 0);
+ nvkm_wr32(device, NV03_PFIFO_CACHES, 1);
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+void
+nv04_chan_start(struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ nvkm_mask(fifo->engine.subdev.device, NV04_PFIFO_MODE, BIT(chan->id), BIT(chan->id));
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+void
+nv04_chan_ramfc_clear(struct nvkm_chan *chan)
+{
+ struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc;
+ const struct nvkm_ramfc_layout *c = chan->func->ramfc->layout;
+
+ nvkm_kmap(ramfc);
+ do {
+ nvkm_wo32(ramfc, chan->ramfc_offset + c->ctxp, 0x00000000);
+ } while ((++c)->bits);
+ nvkm_done(ramfc);
+}
+
+static int
+nv04_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc;
+ const u32 base = chan->id * 32;
+
+ chan->ramfc_offset = base;
+
+ nvkm_kmap(ramfc);
+ nvkm_wo32(ramfc, base + 0x00, offset);
+ nvkm_wo32(ramfc, base + 0x04, offset);
+ nvkm_wo32(ramfc, base + 0x08, chan->push->addr >> 4);
+ nvkm_wo32(ramfc, base + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nvkm_done(ramfc);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+nv04_chan_ramfc = {
+ .layout = (const struct nvkm_ramfc_layout[]) {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+ },
+ .write = nv04_chan_ramfc_write,
+ .clear = nv04_chan_ramfc_clear,
+ .ctxdma = true,
+};
+
+const struct nvkm_chan_func_userd
+nv04_chan_userd = {
+ .bar = 0,
+ .base = 0x800000,
+ .size = 0x010000,
+};
+
+const struct nvkm_chan_func_inst
+nv04_chan_inst = {
+ .size = 0x1000,
+};
+
+static const struct nvkm_chan_func
+nv04_chan = {
+ .inst = &nv04_chan_inst,
+ .userd = &nv04_chan_userd,
+ .ramfc = &nv04_chan_ramfc,
+ .start = nv04_chan_start,
+ .stop = nv04_chan_stop,
+};
+
+const struct nvkm_cgrp_func
+nv04_cgrp = {
+};
+
+void
+nv04_eobj_ramht_del(struct nvkm_chan *chan, int hash)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_instmem *imem = fifo->engine.subdev.device->imem;
+
+ mutex_lock(&fifo->mutex);
+ nvkm_ramht_remove(imem->ramht, hash);
+ mutex_unlock(&fifo->mutex);
+}
+
+static int
+nv04_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_instmem *imem = fifo->engine.subdev.device->imem;
+ u32 context = 0x80000000 | chan->id << 24 | engn->id << 16;
+ int hash;
+
+ mutex_lock(&fifo->mutex);
+ hash = nvkm_ramht_insert(imem->ramht, eobj, chan->id, 4, eobj->handle, context);
+ mutex_unlock(&fifo->mutex);
+ return hash;
+}
+
+const struct nvkm_engn_func
+nv04_engn = {
+ .ramht_add = nv04_eobj_ramht_add,
+ .ramht_del = nv04_eobj_ramht_del,
};
void
-nv04_fifo_pause(struct nvkm_fifo *base, unsigned long *pflags)
-__acquires(fifo->base.lock)
+nv04_fifo_pause(struct nvkm_fifo *fifo, unsigned long *pflags)
+__acquires(fifo->lock)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
unsigned long flags;
- spin_lock_irqsave(&fifo->base.lock, flags);
+ spin_lock_irqsave(&fifo->lock, flags);
*pflags = flags;
nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000000);
@@ -81,50 +244,21 @@ __acquires(fifo->base.lock)
}
void
-nv04_fifo_start(struct nvkm_fifo *base, unsigned long *pflags)
-__releases(fifo->base.lock)
+nv04_fifo_start(struct nvkm_fifo *fifo, unsigned long *pflags)
+__releases(fifo->lock)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
unsigned long flags = *pflags;
nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000001);
- spin_unlock_irqrestore(&fifo->base.lock, flags);
+ spin_unlock_irqrestore(&fifo->lock, flags);
}
-struct nvkm_engine *
-nv04_fifo_id_engine(struct nvkm_fifo *fifo, int engi)
-{
- enum nvkm_subdev_type type;
-
- switch (engi) {
- case NV04_FIFO_ENGN_SW : type = NVKM_ENGINE_SW; break;
- case NV04_FIFO_ENGN_GR : type = NVKM_ENGINE_GR; break;
- case NV04_FIFO_ENGN_MPEG: type = NVKM_ENGINE_MPEG; break;
- case NV04_FIFO_ENGN_DMA : type = NVKM_ENGINE_DMAOBJ; break;
- default:
- WARN_ON(1);
- return NULL;
- }
-
- return nvkm_device_engine(fifo->engine.subdev.device, type, 0);
-}
-
-int
-nv04_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine)
-{
- switch (engine->subdev.type) {
- case NVKM_ENGINE_SW : return NV04_FIFO_ENGN_SW;
- case NVKM_ENGINE_GR : return NV04_FIFO_ENGN_GR;
- case NVKM_ENGINE_MPEG : return NV04_FIFO_ENGN_MPEG;
- case NVKM_ENGINE_DMAOBJ: return NV04_FIFO_ENGN_DMA;
- default:
- WARN_ON(1);
- return 0;
- }
-}
+const struct nvkm_runl_func
+nv04_runl = {
+};
static const char *
nv_dma_state_err(u32 state)
@@ -166,11 +300,11 @@ nv04_fifo_swmthd(struct nvkm_device *device, u32 chid, u32 addr, u32 data)
}
static void
-nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get)
+nv04_fifo_intr_cache_error(struct nvkm_fifo *fifo, u32 chid, u32 get)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
unsigned long flags;
u32 pull0 = nvkm_rd32(device, 0x003250);
u32 mthd, data;
@@ -193,12 +327,12 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get)
if (!(pull0 & 0x00000100) ||
!nv04_fifo_swmthd(device, chid, mthd, data)) {
- chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags);
+ chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags);
nvkm_error(subdev, "CACHE_ERROR - "
"ch %d [%s] subc %d mthd %04x data %08x\n",
- chid, chan ? chan->object.client->name : "unknown",
+ chid, chan ? chan->name : "unknown",
(mthd >> 13) & 7, mthd & 0x1ffc, data);
- nvkm_fifo_chan_put(&fifo->base, flags, &chan);
+ nvkm_chan_put(&chan, flags);
}
nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
@@ -217,20 +351,20 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get)
}
static void
-nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid)
+nv04_fifo_intr_dma_pusher(struct nvkm_fifo *fifo, u32 chid)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 dma_get = nvkm_rd32(device, 0x003244);
u32 dma_put = nvkm_rd32(device, 0x003240);
u32 push = nvkm_rd32(device, 0x003220);
u32 state = nvkm_rd32(device, 0x003228);
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
unsigned long flags;
const char *name;
- chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags);
- name = chan ? chan->object.client->name : "unknown";
+ chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags);
+ name = chan ? chan->name : "unknown";
if (device->card_type == NV_50) {
u32 ho_get = nvkm_rd32(device, 0x003328);
u32 ho_put = nvkm_rd32(device, 0x003320);
@@ -261,18 +395,18 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid)
if (dma_get != dma_put)
nvkm_wr32(device, 0x003244, dma_put);
}
- nvkm_fifo_chan_put(&fifo->base, flags, &chan);
+ nvkm_chan_put(&chan, flags);
nvkm_wr32(device, 0x003228, 0x00000000);
nvkm_wr32(device, 0x003220, 0x00000001);
nvkm_wr32(device, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
}
-void
-nv04_fifo_intr(struct nvkm_fifo *base)
+irqreturn_t
+nv04_fifo_intr(struct nvkm_inth *inth)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth);
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0);
u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask;
@@ -281,16 +415,16 @@ nv04_fifo_intr(struct nvkm_fifo *base)
reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1;
nvkm_wr32(device, NV03_PFIFO_CACHES, 0);
- chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & (fifo->base.nr - 1);
+ chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->chid->mask;
get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET);
if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
- nv04_fifo_cache_error(fifo, chid, get);
+ nv04_fifo_intr_cache_error(fifo, chid, get);
stat &= ~NV_PFIFO_INTR_CACHE_ERROR;
}
if (stat & NV_PFIFO_INTR_DMA_PUSHER) {
- nv04_fifo_dma_pusher(fifo, chid);
+ nv04_fifo_intr_dma_pusher(fifo, chid);
stat &= ~NV_PFIFO_INTR_DMA_PUSHER;
}
@@ -313,7 +447,7 @@ nv04_fifo_intr(struct nvkm_fifo *base)
if (stat & 0x40000000) {
nvkm_wr32(device, 0x002100, 0x40000000);
- nvkm_fifo_uevent(&fifo->base);
+ nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
stat &= ~0x40000000;
}
}
@@ -325,13 +459,13 @@ nv04_fifo_intr(struct nvkm_fifo *base)
}
nvkm_wr32(device, NV03_PFIFO_CACHES, reassign);
+ return IRQ_HANDLED;
}
void
-nv04_fifo_init(struct nvkm_fifo *base)
+nv04_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
struct nvkm_memory *ramro = imem->ramro;
@@ -346,7 +480,7 @@ nv04_fifo_init(struct nvkm_fifo *base)
nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8);
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
@@ -357,43 +491,53 @@ nv04_fifo_init(struct nvkm_fifo *base)
}
int
-nv04_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, int nr, const struct nv04_fifo_ramfc *ramfc,
- struct nvkm_fifo **pfifo)
+nv04_fifo_runl_ctor(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo;
- int ret;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
- fifo->ramfc = ramfc;
- *pfifo = &fifo->base;
+ struct nvkm_runl *runl;
- ret = nvkm_fifo_ctor(func, device, type, inst, nr, &fifo->base);
- if (ret)
- return ret;
+ runl = nvkm_runl_new(fifo, 0, 0, 0);
+ if (IS_ERR(runl))
+ return PTR_ERR(runl);
- set_bit(nr - 1, fifo->base.mask); /* inactive channel */
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0);
+ nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0);
+ nvkm_runl_add(runl, 1, fifo->func->engn , NVKM_ENGINE_GR, 0);
+ nvkm_runl_add(runl, 2, fifo->func->engn , NVKM_ENGINE_MPEG, 0); /* NV31- */
return 0;
}
+int
+nv04_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ /* The last CHID is reserved by HW as a "channel invalid" marker. */
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr - 1, &fifo->chid);
+}
+
+static int
+nv04_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return 16;
+}
+
static const struct nvkm_fifo_func
nv04_fifo = {
+ .chid_nr = nv04_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
+ .runl_ctor = nv04_fifo_runl_ctor,
.init = nv04_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = nv04_fifo_engine_id,
- .id_engine = nv04_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .chan = {
- &nv04_fifo_dma_oclass,
- NULL
- },
+ .runl = &nv04_runl,
+ .engn = &nv04_engn,
+ .engn_sw = &nv04_engn,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, NV03_CHANNEL_DMA }, &nv04_chan },
};
int
nv04_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv04_fifo_new_(&nv04_fifo, device, type, inst, 16, nv04_fifo_ramfc, pfifo);
+ return nvkm_fifo_new_(&nv04_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
deleted file mode 100644
index 3f23bcde4a54..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NV04_FIFO_H__
-#define __NV04_FIFO_H__
-#define nv04_fifo(p) container_of((p), struct nv04_fifo, base)
-#include "priv.h"
-
-struct nv04_fifo_ramfc {
- unsigned bits:6;
- unsigned ctxs:5;
- unsigned ctxp:8;
- unsigned regs:5;
- unsigned regp;
-};
-
-struct nv04_fifo {
- struct nvkm_fifo base;
- const struct nv04_fifo_ramfc *ramfc;
-};
-
-int nv04_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
- int nr, const struct nv04_fifo_ramfc *, struct nvkm_fifo **);
-void nv04_fifo_init(struct nvkm_fifo *);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
index f8887f0f2f82..a4bcf6b0a7e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
@@ -21,41 +21,93 @@
*
* Authors: Ben Skeggs
*/
-#include "nv04.h"
-#include "channv04.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "runl.h"
+
+#include <core/gpuobj.h>
+#include <subdev/instmem.h>
+
#include "regsnv04.h"
-static const struct nv04_fifo_ramfc
-nv10_fifo_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
- {}
+#include <nvif/class.h>
+
+static int
+nv10_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc;
+ const u32 base = chan->id * 32;
+
+ chan->ramfc_offset = base;
+
+ nvkm_kmap(ramfc);
+ nvkm_wo32(ramfc, base + 0x00, offset);
+ nvkm_wo32(ramfc, base + 0x04, offset);
+ nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4);
+ nvkm_wo32(ramfc, base + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nvkm_done(ramfc);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+nv10_chan_ramfc = {
+ .layout = (const struct nvkm_ramfc_layout[]) {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+ },
+ .write = nv10_chan_ramfc_write,
+ .clear = nv04_chan_ramfc_clear,
+ .ctxdma = true,
+};
+
+static const struct nvkm_chan_func
+nv10_chan = {
+ .inst = &nv04_chan_inst,
+ .userd = &nv04_chan_userd,
+ .ramfc = &nv10_chan_ramfc,
+ .start = nv04_chan_start,
+ .stop = nv04_chan_stop,
};
+int
+nv10_fifo_chid_nr(struct nvkm_fifo *fifo)
+{
+ return 32;
+}
+
static const struct nvkm_fifo_func
nv10_fifo = {
+ .chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
+ .runl_ctor = nv04_fifo_runl_ctor,
.init = nv04_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = nv04_fifo_engine_id,
- .id_engine = nv04_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .chan = {
- &nv10_fifo_dma_oclass,
- NULL
- },
+ .runl = &nv04_runl,
+ .engn = &nv04_engn,
+ .engn_sw = &nv04_engn,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, NV10_CHANNEL_DMA }, &nv10_chan },
};
int
nv10_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv04_fifo_new_(&nv10_fifo, device, type, inst, 32, nv10_fifo_ramfc, pfifo);
+ return nvkm_fifo_new_(&nv10_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
index 3f94c7b5b054..c70f44fd4f3b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
@@ -21,37 +21,78 @@
*
* Authors: Ben Skeggs
*/
-#include "nv04.h"
-#include "channv04.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+
#include "regsnv04.h"
#include <core/ramht.h>
#include <subdev/instmem.h>
-static const struct nv04_fifo_ramfc
-nv17_fifo_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
- { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
- { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
- { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
- { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
- { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
- {}
+#include <nvif/class.h>
+
+static int
+nv17_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc;
+ const u32 base = chan->id * 64;
+
+ chan->ramfc_offset = base;
+
+ nvkm_kmap(ramfc);
+ nvkm_wo32(ramfc, base + 0x00, offset);
+ nvkm_wo32(ramfc, base + 0x04, offset);
+ nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4);
+ nvkm_wo32(ramfc, base + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nvkm_done(ramfc);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+nv17_chan_ramfc = {
+ .layout = (const struct nvkm_ramfc_layout[]) {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ {}
+ },
+ .write = nv17_chan_ramfc_write,
+ .clear = nv04_chan_ramfc_clear,
+ .ctxdma = true,
+};
+
+static const struct nvkm_chan_func
+nv17_chan = {
+ .inst = &nv04_chan_inst,
+ .userd = &nv04_chan_userd,
+ .ramfc = &nv17_chan_ramfc,
+ .start = nv04_chan_start,
+ .stop = nv04_chan_stop,
};
static void
-nv17_fifo_init(struct nvkm_fifo *base)
+nv17_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
struct nvkm_memory *ramro = imem->ramro;
@@ -67,7 +108,7 @@ nv17_fifo_init(struct nvkm_fifo *base)
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 |
0x00010000);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
@@ -79,21 +120,23 @@ nv17_fifo_init(struct nvkm_fifo *base)
static const struct nvkm_fifo_func
nv17_fifo = {
+ .chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
+ .runl_ctor = nv04_fifo_runl_ctor,
.init = nv17_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = nv04_fifo_engine_id,
- .id_engine = nv04_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .chan = {
- &nv17_fifo_dma_oclass,
- NULL
- },
+ .runl = &nv04_runl,
+ .engn = &nv04_engn,
+ .engn_sw = &nv04_engn,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, NV17_CHANNEL_DMA }, &nv17_chan },
};
int
nv17_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv04_fifo_new_(&nv17_fifo, device, type, inst, 32, nv17_fifo_ramfc, pfifo);
+ return nvkm_fifo_new_(&nv17_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
index f9ea46809bc0..e50a94b6d7f8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
@@ -21,46 +21,166 @@
*
* Authors: Ben Skeggs
*/
-#include "nv04.h"
-#include "channv04.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+
#include "regsnv04.h"
#include <core/ramht.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
-static const struct nv04_fifo_ramfc
-nv40_fifo_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 2, 28, 0x18, 28, 0x002058 },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
- { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
- { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
- { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
- { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
- { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
- { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
- { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
- { 32, 0, 0x40, 0, 0x0032e4 },
- { 32, 0, 0x44, 0, 0x0032e8 },
- { 32, 0, 0x4c, 0, 0x002088 },
- { 32, 0, 0x50, 0, 0x003300 },
- { 32, 0, 0x54, 0, 0x00330c },
- {}
+#include <nvif/class.h>
+
+static int
+nv40_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc;
+ const u32 base = chan->id * 128;
+
+ chan->ramfc_offset = base;
+
+ nvkm_kmap(ramfc);
+ nvkm_wo32(ramfc, base + 0x00, offset);
+ nvkm_wo32(ramfc, base + 0x04, offset);
+ nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4);
+ nvkm_wo32(ramfc, base + 0x18, 0x30000000 |
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nvkm_wo32(ramfc, base + 0x3c, 0x0001ffff);
+ nvkm_done(ramfc);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+nv40_chan_ramfc = {
+ .layout = (const struct nvkm_ramfc_layout[]) {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 2, 28, 0x18, 28, 0x002058 },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
+ { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
+ { 32, 0, 0x40, 0, 0x0032e4 },
+ { 32, 0, 0x44, 0, 0x0032e8 },
+ { 32, 0, 0x4c, 0, 0x002088 },
+ { 32, 0, 0x50, 0, 0x003300 },
+ { 32, 0, 0x54, 0, 0x00330c },
+ {}
+ },
+ .write = nv40_chan_ramfc_write,
+ .clear = nv04_chan_ramfc_clear,
+ .ctxdma = true,
+};
+
+static const struct nvkm_chan_func_userd
+nv40_chan_userd = {
+ .bar = 0,
+ .base = 0xc00000,
+ .size = 0x001000,
+};
+
+static const struct nvkm_chan_func
+nv40_chan = {
+ .inst = &nv04_chan_inst,
+ .userd = &nv40_chan_userd,
+ .ramfc = &nv40_chan_ramfc,
+ .start = nv04_chan_start,
+ .stop = nv04_chan_stop,
};
+static int
+nv40_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan)
+{
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_instmem *imem = fifo->engine.subdev.device->imem;
+ u32 context = chan->id << 23 | engn->id << 20;
+ int hash;
+
+ mutex_lock(&fifo->mutex);
+ hash = nvkm_ramht_insert(imem->ramht, eobj, chan->id, 4, eobj->handle, context);
+ mutex_unlock(&fifo->mutex);
+ return hash;
+}
+
static void
-nv40_fifo_init(struct nvkm_fifo *base)
+nv40_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_memory *ramfc = device->imem->ramfc;
+ u32 inst = 0x00000000, reg, ctx;
+ int chid;
+
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_GR:
+ reg = 0x0032e0;
+ ctx = 0x38;
+ break;
+ case NVKM_ENGINE_MPEG:
+ if (WARN_ON(device->chipset < 0x44))
+ return;
+ reg = 0x00330c;
+ ctx = 0x54;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (cctx)
+ inst = cctx->vctx->inst->addr >> 4;
+
+ spin_lock_irq(&fifo->lock);
+ nvkm_mask(device, 0x002500, 0x00000001, 0x00000000);
+
+ chid = nvkm_rd32(device, 0x003204) & (fifo->chid->nr - 1);
+ if (chid == chan->id)
+ nvkm_wr32(device, reg, inst);
+
+ nvkm_kmap(ramfc);
+ nvkm_wo32(ramfc, chan->ramfc_offset + ctx, inst);
+ nvkm_done(ramfc);
+
+ nvkm_mask(device, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irq(&fifo->lock);
+}
+
+static const struct nvkm_engn_func
+nv40_engn = {
+ .bind = nv40_ectx_bind,
+ .ramht_add = nv40_eobj_ramht_add,
+ .ramht_del = nv04_eobj_ramht_del,
+};
+
+static const struct nvkm_engn_func
+nv40_engn_sw = {
+ .ramht_add = nv40_eobj_ramht_add,
+ .ramht_del = nv04_eobj_ramht_del,
+};
+
+static void
+nv40_fifo_init(struct nvkm_fifo *fifo)
+{
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_fb *fb = device->fb;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
@@ -98,7 +218,7 @@ nv40_fifo_init(struct nvkm_fifo *base)
break;
}
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
@@ -110,21 +230,23 @@ nv40_fifo_init(struct nvkm_fifo *base)
static const struct nvkm_fifo_func
nv40_fifo = {
+ .chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
+ .runl_ctor = nv04_fifo_runl_ctor,
.init = nv40_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = nv04_fifo_engine_id,
- .id_engine = nv04_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .chan = {
- &nv40_fifo_dma_oclass,
- NULL
- },
+ .runl = &nv04_runl,
+ .engn = &nv40_engn,
+ .engn_sw = &nv40_engn_sw,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, NV40_CHANNEL_DMA }, &nv40_chan },
};
int
nv40_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv04_fifo_new_(&nv40_fifo, device, type, inst, 32, nv40_fifo_ramfc, pfifo);
+ return nvkm_fifo_new_(&nv40_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
index a08742cf425a..954b5f3a7d57 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
@@ -21,62 +21,325 @@
*
* Authors: Ben Skeggs
*/
-#include "nv50.h"
-#include "channv50.h"
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
-#include <core/gpuobj.h>
+#include <core/ramht.h>
+#include <subdev/timer.h>
-static void
-nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo)
+#include <nvif/class.h>
+
+void
+nv50_eobj_ramht_del(struct nvkm_chan *chan, int hash)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_memory *cur;
- int i, p;
+ nvkm_ramht_remove(chan->ramht, hash);
+}
- cur = fifo->runlist[fifo->cur_runlist];
- fifo->cur_runlist = !fifo->cur_runlist;
+int
+nv50_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan)
+{
+ return nvkm_ramht_insert(chan->ramht, eobj, 0, 4, eobj->handle, engn->id << 20);
+}
- nvkm_kmap(cur);
- for (i = 0, p = 0; i < fifo->base.nr; i++) {
- if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000)
- nvkm_wo32(cur, p++ * 4, i);
- }
- nvkm_done(cur);
+void
+nv50_chan_stop(struct nvkm_chan *chan)
+{
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
- nvkm_wr32(device, 0x0032f4, nvkm_memory_addr(cur) >> 12);
- nvkm_wr32(device, 0x0032ec, p);
- nvkm_wr32(device, 0x002500, 0x00000101);
+ nvkm_mask(device, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
}
void
-nv50_fifo_runlist_update(struct nv50_fifo *fifo)
+nv50_chan_start(struct nvkm_chan *chan)
{
- mutex_lock(&fifo->base.mutex);
- nv50_fifo_runlist_update_locked(fifo);
- mutex_unlock(&fifo->base.mutex);
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_mask(device, 0x002600 + (chan->id * 4), 0x80000000, 0x80000000);
}
-int
-nv50_fifo_oneinit(struct nvkm_fifo *base)
+void
+nv50_chan_unbind(struct nvkm_chan *chan)
{
- struct nv50_fifo *fifo = nv50_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x002600 + (chan->id * 4), 0x00000000);
+}
+
+static void
+nv50_chan_bind(struct nvkm_chan *chan)
+{
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ nvkm_wr32(device, 0x002600 + (chan->id * 4), chan->ramfc->addr >> 12);
+}
+
+static int
+nv50_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
+{
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+ const u32 limit2 = ilog2(length / 8);
int ret;
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000,
- false, &fifo->runlist[0]);
+ ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->inst, &chan->ramfc);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->inst, &chan->eng);
if (ret)
return ret;
- return nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000,
- false, &fifo->runlist[1]);
+ ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->inst, &chan->pgd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_ramht_new(device, 0x8000, 16, chan->inst, &chan->ramht);
+ if (ret)
+ return ret;
+
+ nvkm_kmap(chan->ramfc);
+ nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078);
+ nvkm_wo32(chan->ramfc, 0x44, 0x01003fff);
+ nvkm_wo32(chan->ramfc, 0x48, chan->push->node->offset >> 4);
+ nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(offset));
+ nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(offset) | (limit2 << 16));
+ nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff);
+ nvkm_wo32(chan->ramfc, 0x78, 0x00000000);
+ nvkm_wo32(chan->ramfc, 0x7c, 0x30000000 | devm);
+ nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj->node->offset >> 4));
+ nvkm_done(chan->ramfc);
+ return 0;
+}
+
+static const struct nvkm_chan_func_ramfc
+nv50_chan_ramfc = {
+ .write = nv50_chan_ramfc_write,
+ .ctxdma = true,
+ .devm = 0xfff,
+};
+
+const struct nvkm_chan_func_userd
+nv50_chan_userd = {
+ .bar = 0,
+ .base = 0xc00000,
+ .size = 0x002000,
+};
+
+const struct nvkm_chan_func_inst
+nv50_chan_inst = {
+ .size = 0x10000,
+ .vmm = true,
+};
+
+static const struct nvkm_chan_func
+nv50_chan = {
+ .inst = &nv50_chan_inst,
+ .userd = &nv50_chan_userd,
+ .ramfc = &nv50_chan_ramfc,
+ .bind = nv50_chan_bind,
+ .unbind = nv50_chan_unbind,
+ .start = nv50_chan_start,
+ .stop = nv50_chan_stop,
+};
+
+static void
+nv50_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
+{
+ struct nvkm_subdev *subdev = &chan->cgrp->runl->fifo->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ u64 start = 0, limit = 0;
+ u32 flags = 0, ptr0, save;
+
+ switch (engn->engine->subdev.type) {
+ case NVKM_ENGINE_GR : ptr0 = 0x0000; break;
+ case NVKM_ENGINE_MPEG : ptr0 = 0x0060; break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (!cctx) {
+ /* HW bug workaround:
+ *
+ * PFIFO will hang forever if the connected engines don't report
+ * that they've processed the context switch request.
+ *
+ * In order for the kickoff to work, we need to ensure all the
+ * connected engines are in a state where they can answer.
+ *
+ * Newer chipsets don't seem to suffer from this issue, and well,
+ * there's also a "ignore these engines" bitmask reg we can use
+ * if we hit the issue there..
+ */
+ save = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001);
+
+ /* Tell engines to save out contexts. */
+ nvkm_wr32(device, 0x0032fc, chan->inst->addr >> 12);
+ nvkm_msec(device, 2000,
+ if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
+ break;
+ );
+ nvkm_wr32(device, 0x00b860, save);
+ } else {
+ flags = 0x00190000;
+ start = cctx->vctx->inst->addr;
+ limit = start + cctx->vctx->inst->size - 1;
+ }
+
+ nvkm_kmap(chan->eng);
+ nvkm_wo32(chan->eng, ptr0 + 0x00, flags);
+ nvkm_wo32(chan->eng, ptr0 + 0x04, lower_32_bits(limit));
+ nvkm_wo32(chan->eng, ptr0 + 0x08, lower_32_bits(start));
+ nvkm_wo32(chan->eng, ptr0 + 0x0c, upper_32_bits(limit) << 24 |
+ lower_32_bits(start));
+ nvkm_wo32(chan->eng, ptr0 + 0x10, 0x00000000);
+ nvkm_wo32(chan->eng, ptr0 + 0x14, 0x00000000);
+ nvkm_done(chan->eng);
}
+static const struct nvkm_engn_func
+nv50_engn = {
+ .bind = nv50_ectx_bind,
+ .ramht_add = nv50_eobj_ramht_add,
+ .ramht_del = nv50_eobj_ramht_del,
+};
+
+const struct nvkm_engn_func
+nv50_engn_sw = {
+ .ramht_add = nv50_eobj_ramht_add,
+ .ramht_del = nv50_eobj_ramht_del,
+};
+
+static bool
+nv50_runl_pending(struct nvkm_runl *runl)
+{
+ return nvkm_rd32(runl->fifo->engine.subdev.device, 0x0032ec) & 0x00000100;
+}
+
+int
+nv50_runl_wait(struct nvkm_runl *runl)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+
+ nvkm_msec(fifo->engine.subdev.device, fifo->timeout.chan_msec,
+ if (!nvkm_runl_update_pending(runl))
+ return 0;
+ usleep_range(1, 2);
+ );
+
+ return -ETIMEDOUT;
+}
+
+static void
+nv50_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u64 addr = nvkm_memory_addr(memory) + start;
+
+ nvkm_wr32(device, 0x0032f4, addr >> 12);
+ nvkm_wr32(device, 0x0032ec, count);
+}
+
+static void
+nv50_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
+{
+ nvkm_wo32(memory, offset, chan->id);
+}
+
+static struct nvkm_memory *
+nv50_runl_alloc(struct nvkm_runl *runl, u32 *offset)
+{
+ const u32 segment = ALIGN((runl->cgrp_nr + runl->chan_nr) * runl->func->size, 0x1000);
+ const u32 maxsize = (runl->cgid ? runl->cgid->nr : 0) + runl->chid->nr;
+ int ret;
+
+ if (unlikely(!runl->mem)) {
+ ret = nvkm_memory_new(runl->fifo->engine.subdev.device, NVKM_MEM_TARGET_INST,
+ maxsize * 2 * runl->func->size, 0, false, &runl->mem);
+ if (ret) {
+ RUNL_ERROR(runl, "alloc %d\n", ret);
+ return ERR_PTR(ret);
+ }
+ } else {
+ if (runl->offset + segment >= nvkm_memory_size(runl->mem)) {
+ ret = runl->func->wait(runl);
+ if (ret) {
+ RUNL_DEBUG(runl, "rewind timeout");
+ return ERR_PTR(ret);
+ }
+
+ runl->offset = 0;
+ }
+ }
+
+ *offset = runl->offset;
+ runl->offset += segment;
+ return runl->mem;
+}
+
+int
+nv50_runl_update(struct nvkm_runl *runl)
+{
+ struct nvkm_memory *memory;
+ struct nvkm_cgrp *cgrp;
+ struct nvkm_chan *chan;
+ u32 start, offset, count;
+
+ /*TODO: prio, interleaving. */
+
+ RUNL_TRACE(runl, "RAMRL: update cgrps:%d chans:%d", runl->cgrp_nr, runl->chan_nr);
+ memory = nv50_runl_alloc(runl, &start);
+ if (IS_ERR(memory))
+ return PTR_ERR(memory);
+
+ RUNL_TRACE(runl, "RAMRL: update start:%08x", start);
+ offset = start;
+
+ nvkm_kmap(memory);
+ nvkm_runl_foreach_cgrp(cgrp, runl) {
+ if (cgrp->hw) {
+ CGRP_TRACE(cgrp, " RAMRL+%08x: chans:%d", offset, cgrp->chan_nr);
+ runl->func->insert_cgrp(cgrp, memory, offset);
+ offset += runl->func->size;
+ }
+
+ nvkm_cgrp_foreach_chan(chan, cgrp) {
+ CHAN_TRACE(chan, "RAMRL+%08x: [%s]", offset, chan->name);
+ runl->func->insert_chan(chan, memory, offset);
+ offset += runl->func->size;
+ }
+ }
+ nvkm_done(memory);
+
+ /*TODO: look into using features on newer HW to guarantee forward progress. */
+ list_rotate_left(&runl->cgrps);
+
+ count = (offset - start) / runl->func->size;
+ RUNL_TRACE(runl, "RAMRL: commit start:%08x count:%d", start, count);
+
+ runl->func->commit(runl, memory, start, count);
+ return 0;
+}
+
+const struct nvkm_runl_func
+nv50_runl = {
+ .size = 4,
+ .update = nv50_runl_update,
+ .insert_chan = nv50_runl_insert_chan,
+ .commit = nv50_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = nv50_runl_pending,
+};
+
void
-nv50_fifo_init(struct nvkm_fifo *base)
+nv50_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv50_fifo *fifo = nv50_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_runl *runl = nvkm_runl_first(fifo);
+ struct nvkm_device *device = fifo->engine.subdev.device;
int i;
nvkm_mask(device, 0x000200, 0x00000100, 0x00000000);
@@ -89,61 +352,47 @@ nv50_fifo_init(struct nvkm_fifo *base)
for (i = 0; i < 128; i++)
nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000);
- nv50_fifo_runlist_update_locked(fifo);
+
+ atomic_set(&runl->changed, 1);
+ runl->func->update(runl);
nvkm_wr32(device, 0x003200, 0x00000001);
nvkm_wr32(device, 0x003250, 0x00000001);
nvkm_wr32(device, 0x002500, 0x00000001);
}
-void *
-nv50_fifo_dtor(struct nvkm_fifo *base)
+int
+nv50_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
{
- struct nv50_fifo *fifo = nv50_fifo(base);
- nvkm_memory_unref(&fifo->runlist[1]);
- nvkm_memory_unref(&fifo->runlist[0]);
- return fifo;
+ /* CHID 0 is unusable (some kind of PIO channel?), 127 is "channel invalid". */
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 1, nr - 2, &fifo->chid);
}
int
-nv50_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo)
+nv50_fifo_chid_nr(struct nvkm_fifo *fifo)
{
- struct nv50_fifo *fifo;
- int ret;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
- *pfifo = &fifo->base;
-
- ret = nvkm_fifo_ctor(func, device, type, inst, 128, &fifo->base);
- if (ret)
- return ret;
-
- set_bit(0, fifo->base.mask); /* PIO channel */
- set_bit(127, fifo->base.mask); /* inactive channel */
- return 0;
+ return 128;
}
static const struct nvkm_fifo_func
nv50_fifo = {
- .dtor = nv50_fifo_dtor,
- .oneinit = nv50_fifo_oneinit,
+ .chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = nv50_fifo_chid_ctor,
+ .runl_ctor = nv04_fifo_runl_ctor,
.init = nv50_fifo_init,
.intr = nv04_fifo_intr,
- .engine_id = nv04_fifo_engine_id,
- .id_engine = nv04_fifo_id_engine,
.pause = nv04_fifo_pause,
.start = nv04_fifo_start,
- .chan = {
- &nv50_fifo_gpfifo_oclass,
- NULL
- },
+ .runl = &nv50_runl,
+ .engn = &nv50_engn,
+ .engn_sw = &nv50_engn_sw,
+ .cgrp = {{ }, &nv04_cgrp },
+ .chan = {{ 0, 0, NV50_CHANNEL_GPFIFO }, &nv50_chan },
};
int
nv50_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- return nv50_fifo_new_(&nv50_fifo, device, type, inst, pfifo);
+ return nvkm_fifo_new_(&nv50_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
deleted file mode 100644
index 0111e7e5a4e3..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NV50_FIFO_H__
-#define __NV50_FIFO_H__
-#define nv50_fifo(p) container_of((p), struct nv50_fifo, base)
-#include "priv.h"
-
-struct nv50_fifo {
- struct nvkm_fifo base;
- struct nvkm_memory *runlist[2];
- int cur_runlist;
-};
-
-int nv50_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
- struct nvkm_fifo **);
-
-void *nv50_fifo_dtor(struct nvkm_fifo *);
-int nv50_fifo_oneinit(struct nvkm_fifo *);
-void nv50_fifo_init(struct nvkm_fifo *);
-void nv50_fifo_runlist_update(struct nv50_fifo *);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
index 79cec57647f0..4d448be19224 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
@@ -3,46 +3,207 @@
#define __NVKM_FIFO_PRIV_H__
#define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine)
#include <engine/fifo.h>
+#include <core/enum.h>
+struct nvkm_cctx;
+struct nvkm_cgrp;
+struct nvkm_engn;
+struct nvkm_memory;
+struct nvkm_runl;
+struct nvkm_runq;
+struct nvkm_vctx;
-int nvkm_fifo_ctor(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
- int nr, struct nvkm_fifo *);
-void nvkm_fifo_uevent(struct nvkm_fifo *);
-void nvkm_fifo_kevent(struct nvkm_fifo *, int chid);
-void nvkm_fifo_recover_chan(struct nvkm_fifo *, int chid);
-
-struct nvkm_fifo_chan *
-nvkm_fifo_chan_inst_locked(struct nvkm_fifo *, u64 inst);
-
-struct nvkm_fifo_chan_oclass;
struct nvkm_fifo_func {
- void *(*dtor)(struct nvkm_fifo *);
- int (*oneinit)(struct nvkm_fifo *);
- int (*info)(struct nvkm_fifo *, u64 mthd, u64 *data);
+ int (*chid_nr)(struct nvkm_fifo *);
+ int (*chid_ctor)(struct nvkm_fifo *, int nr);
+ int (*runq_nr)(struct nvkm_fifo *);
+ int (*runl_ctor)(struct nvkm_fifo *);
+
void (*init)(struct nvkm_fifo *);
- void (*fini)(struct nvkm_fifo *);
- void (*intr)(struct nvkm_fifo *);
- void (*fault)(struct nvkm_fifo *, struct nvkm_fault_data *);
- int (*engine_id)(struct nvkm_fifo *, struct nvkm_engine *);
- struct nvkm_engine *(*id_engine)(struct nvkm_fifo *, int engi);
+ void (*init_pbdmas)(struct nvkm_fifo *, u32 mask);
+
+ irqreturn_t (*intr)(struct nvkm_inth *);
+ void (*intr_mmu_fault_unit)(struct nvkm_fifo *, int unit);
+ void (*intr_ctxsw_timeout)(struct nvkm_fifo *, u32 engm);
+
+ const struct nvkm_fifo_func_mmu_fault {
+ void (*recover)(struct nvkm_fifo *, struct nvkm_fault_data *);
+ const struct nvkm_enum *access;
+ const struct nvkm_enum *engine;
+ const struct nvkm_enum *reason;
+ const struct nvkm_enum *hubclient;
+ const struct nvkm_enum *gpcclient;
+ } *mmu_fault;
+
void (*pause)(struct nvkm_fifo *, unsigned long *);
void (*start)(struct nvkm_fifo *, unsigned long *);
- void (*uevent_init)(struct nvkm_fifo *);
- void (*uevent_fini)(struct nvkm_fifo *);
- void (*recover_chan)(struct nvkm_fifo *, int chid);
- int (*class_get)(struct nvkm_fifo *, int index, struct nvkm_oclass *);
- int (*class_new)(struct nvkm_fifo *, const struct nvkm_oclass *,
- void *, u32, struct nvkm_object **);
- const struct nvkm_fifo_chan_oclass *chan[];
+
+ int (*nonstall_ctor)(struct nvkm_fifo *);
+ const struct nvkm_event_func *nonstall;
+
+ const struct nvkm_runl_func *runl;
+ const struct nvkm_runq_func *runq;
+ const struct nvkm_engn_func *engn;
+ const struct nvkm_engn_func *engn_sw;
+ const struct nvkm_engn_func *engn_ce;
+
+ struct nvkm_fifo_func_cgrp {
+ struct nvkm_sclass user;
+ const struct nvkm_cgrp_func *func;
+ bool force;
+ } cgrp;
+
+ struct nvkm_fifo_func_chan {
+ struct nvkm_sclass user;
+ const struct nvkm_chan_func *func;
+ } chan;
};
-void nv04_fifo_intr(struct nvkm_fifo *);
-int nv04_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *);
-struct nvkm_engine *nv04_fifo_id_engine(struct nvkm_fifo *, int);
+int nvkm_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
+ struct nvkm_fifo **);
+
+int nv04_fifo_chid_ctor(struct nvkm_fifo *, int);
+int nv04_fifo_runl_ctor(struct nvkm_fifo *);
+void nv04_fifo_init(struct nvkm_fifo *);
+irqreturn_t nv04_fifo_intr(struct nvkm_inth *);
void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *);
void nv04_fifo_start(struct nvkm_fifo *, unsigned long *);
+extern const struct nvkm_runl_func nv04_runl;
+extern const struct nvkm_engn_func nv04_engn;
+extern const struct nvkm_cgrp_func nv04_cgrp;
+extern const struct nvkm_chan_func_inst nv04_chan_inst;
+extern const struct nvkm_chan_func_userd nv04_chan_userd;
+void nv04_chan_ramfc_clear(struct nvkm_chan *);
+void nv04_chan_start(struct nvkm_chan *);
+void nv04_chan_stop(struct nvkm_chan *);
+void nv04_eobj_ramht_del(struct nvkm_chan *, int);
+
+int nv10_fifo_chid_nr(struct nvkm_fifo *);
+
+int nv50_fifo_chid_nr(struct nvkm_fifo *);
+int nv50_fifo_chid_ctor(struct nvkm_fifo *, int);
+void nv50_fifo_init(struct nvkm_fifo *);
+extern const struct nvkm_runl_func nv50_runl;
+int nv50_runl_update(struct nvkm_runl *);
+int nv50_runl_wait(struct nvkm_runl *);
+extern const struct nvkm_engn_func nv50_engn_sw;
+extern const struct nvkm_chan_func_inst nv50_chan_inst;
+extern const struct nvkm_chan_func_userd nv50_chan_userd;
+void nv50_chan_unbind(struct nvkm_chan *);
+void nv50_chan_start(struct nvkm_chan *);
+void nv50_chan_stop(struct nvkm_chan *);
+void nv50_chan_preempt(struct nvkm_chan *);
+int nv50_eobj_ramht_add(struct nvkm_engn *, struct nvkm_object *, struct nvkm_chan *);
+void nv50_eobj_ramht_del(struct nvkm_chan *, int);
+
+extern const struct nvkm_event_func g84_fifo_nonstall;
+extern const struct nvkm_engn_func g84_engn;
+extern const struct nvkm_chan_func g84_chan;
+
+int gf100_fifo_chid_ctor(struct nvkm_fifo *, int);
+int gf100_fifo_runq_nr(struct nvkm_fifo *);
+bool gf100_fifo_intr_pbdma(struct nvkm_fifo *);
+void gf100_fifo_intr_mmu_fault(struct nvkm_fifo *);
+void gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int);
+void gf100_fifo_intr_sched(struct nvkm_fifo *);
+void gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *, u32);
+void gf100_fifo_mmu_fault_recover(struct nvkm_fifo *, struct nvkm_fault_data *);
+extern const struct nvkm_enum gf100_fifo_mmu_fault_access[];
+extern const struct nvkm_event_func gf100_fifo_nonstall;
+bool gf100_runl_preempt_pending(struct nvkm_runl *);
+void gf100_runq_init(struct nvkm_runq *);
+bool gf100_runq_intr(struct nvkm_runq *, struct nvkm_runl *);
+void gf100_engn_mmu_fault_trigger(struct nvkm_engn *);
+bool gf100_engn_mmu_fault_triggered(struct nvkm_engn *);
+extern const struct nvkm_engn_func gf100_engn_sw;
+extern const struct nvkm_chan_func_inst gf100_chan_inst;
+void gf100_chan_userd_clear(struct nvkm_chan *);
+void gf100_chan_preempt(struct nvkm_chan *);
+
+int gk104_fifo_chid_nr(struct nvkm_fifo *);
+int gk104_fifo_runl_ctor(struct nvkm_fifo *);
+void gk104_fifo_init(struct nvkm_fifo *);
+void gk104_fifo_init_pbdmas(struct nvkm_fifo *, u32);
+irqreturn_t gk104_fifo_intr(struct nvkm_inth *);
+void gk104_fifo_intr_runlist(struct nvkm_fifo *);
+void gk104_fifo_intr_chsw(struct nvkm_fifo *);
+void gk104_fifo_intr_bind(struct nvkm_fifo *);
+extern const struct nvkm_fifo_func_mmu_fault gk104_fifo_mmu_fault;
+extern const struct nvkm_enum gk104_fifo_mmu_fault_reason[];
+extern const struct nvkm_enum gk104_fifo_mmu_fault_hubclient[];
+extern const struct nvkm_enum gk104_fifo_mmu_fault_gpcclient[];
+void gk104_runl_insert_chan(struct nvkm_chan *, struct nvkm_memory *, u64);
+void gk104_runl_commit(struct nvkm_runl *, struct nvkm_memory *, u32, int);
+bool gk104_runl_pending(struct nvkm_runl *);
+void gk104_runl_block(struct nvkm_runl *, u32);
+void gk104_runl_allow(struct nvkm_runl *, u32);
+void gk104_runl_fault_clear(struct nvkm_runl *);
+extern const struct nvkm_runq_func gk104_runq;
+void gk104_runq_init(struct nvkm_runq *);
+bool gk104_runq_intr(struct nvkm_runq *, struct nvkm_runl *);
+extern const struct nvkm_bitfield gk104_runq_intr_0_names[];
+bool gk104_runq_idle(struct nvkm_runq *);
+extern const struct nvkm_engn_func gk104_engn;
+bool gk104_engn_chsw(struct nvkm_engn *);
+int gk104_engn_cxid(struct nvkm_engn *, bool *cgid);
+int gk104_ectx_ctor(struct nvkm_engn *, struct nvkm_vctx *);
+extern const struct nvkm_engn_func gk104_engn_ce;
+extern const struct nvkm_chan_func_userd gk104_chan_userd;
+extern const struct nvkm_chan_func_ramfc gk104_chan_ramfc;
+void gk104_chan_bind(struct nvkm_chan *);
+void gk104_chan_bind_inst(struct nvkm_chan *);
+void gk104_chan_unbind(struct nvkm_chan *);
+void gk104_chan_start(struct nvkm_chan *);
+void gk104_chan_stop(struct nvkm_chan *);
+
+int gk110_fifo_chid_ctor(struct nvkm_fifo *, int);
+extern const struct nvkm_runl_func gk110_runl;
+extern const struct nvkm_cgrp_func gk110_cgrp;
+void gk110_runl_insert_cgrp(struct nvkm_cgrp *, struct nvkm_memory *, u64);
+extern const struct nvkm_chan_func gk110_chan;
+void gk110_chan_preempt(struct nvkm_chan *);
+
+extern const struct nvkm_runq_func gk208_runq;
+void gk208_runq_init(struct nvkm_runq *);
+
+void gm107_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int);
+extern const struct nvkm_fifo_func_mmu_fault gm107_fifo_mmu_fault;
+extern const struct nvkm_runl_func gm107_runl;
+extern const struct nvkm_chan_func gm107_chan;
+
+int gm200_fifo_chid_nr(struct nvkm_fifo *);
+int gm200_fifo_runq_nr(struct nvkm_fifo *);
+
+extern const struct nvkm_enum gv100_fifo_mmu_fault_access[];
+extern const struct nvkm_enum gv100_fifo_mmu_fault_reason[];
+extern const struct nvkm_enum gv100_fifo_mmu_fault_hubclient[];
+extern const struct nvkm_enum gv100_fifo_mmu_fault_gpcclient[];
+void gv100_runl_insert_cgrp(struct nvkm_cgrp *, struct nvkm_memory *, u64);
+void gv100_runl_insert_chan(struct nvkm_chan *, struct nvkm_memory *, u64);
+void gv100_runl_preempt(struct nvkm_runl *);
+extern const struct nvkm_runq_func gv100_runq;
+extern const struct nvkm_engn_func gv100_engn;
+void gv100_ectx_bind(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *);
+extern const struct nvkm_engn_func gv100_engn_ce;
+int gv100_ectx_ce_ctor(struct nvkm_engn *, struct nvkm_vctx *);
+void gv100_ectx_ce_bind(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *);
+extern const struct nvkm_chan_func_userd gv100_chan_userd;
+extern const struct nvkm_chan_func_ramfc gv100_chan_ramfc;
+
+void tu102_fifo_intr_ctxsw_timeout_info(struct nvkm_engn *, u32 info);
+extern const struct nvkm_fifo_func_mmu_fault tu102_fifo_mmu_fault;
-void gf100_fifo_intr_fault(struct nvkm_fifo *, int);
+int ga100_fifo_runl_ctor(struct nvkm_fifo *);
+int ga100_fifo_nonstall_ctor(struct nvkm_fifo *);
+extern const struct nvkm_event_func ga100_fifo_nonstall;
+extern const struct nvkm_runl_func ga100_runl;
+extern const struct nvkm_runq_func ga100_runq;
+extern const struct nvkm_engn_func ga100_engn;
+extern const struct nvkm_engn_func ga100_engn_ce;
+extern const struct nvkm_cgrp_func ga100_cgrp;
+extern const struct nvkm_chan_func ga100_chan;
-int gk104_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *);
-struct nvkm_engine *gk104_fifo_id_engine(struct nvkm_fifo *, int);
+int nvkm_uchan_new(struct nvkm_fifo *, struct nvkm_cgrp *, const struct nvkm_oclass *,
+ void *argv, u32 argc, struct nvkm_object **);
+int nvkm_ucgrp_new(struct nvkm_fifo *, const struct nvkm_oclass *, void *argv, u32 argc,
+ struct nvkm_object **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c
new file mode 100644
index 000000000000..b5836cbc29aa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "runl.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "priv.h"
+#include "runq.h"
+
+#include <core/gpuobj.h>
+#include <subdev/timer.h>
+#include <subdev/top.h>
+
+struct nvkm_cgrp *
+nvkm_engn_cgrp_get(struct nvkm_engn *engn, unsigned long *pirqflags)
+{
+ struct nvkm_cgrp *cgrp = NULL;
+ struct nvkm_chan *chan;
+ bool cgid;
+ int id;
+
+ id = engn->func->cxid(engn, &cgid);
+ if (id < 0)
+ return NULL;
+
+ if (!cgid) {
+ chan = nvkm_runl_chan_get_chid(engn->runl, id, pirqflags);
+ if (chan)
+ cgrp = chan->cgrp;
+ } else {
+ cgrp = nvkm_runl_cgrp_get_cgid(engn->runl, id, pirqflags);
+ }
+
+ WARN_ON(!cgrp);
+ return cgrp;
+}
+
+static void
+nvkm_runl_rc(struct nvkm_runl *runl)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_cgrp *cgrp, *gtmp;
+ struct nvkm_chan *chan, *ctmp;
+ struct nvkm_engn *engn;
+ unsigned long flags;
+ int rc, state, i;
+ bool reset;
+
+ /* Runlist is blocked before scheduling recovery - fetch count. */
+ BUG_ON(!mutex_is_locked(&runl->mutex));
+ rc = atomic_xchg(&runl->rc_pending, 0);
+ if (!rc)
+ return;
+
+ /* Look for channel groups flagged for RC. */
+ nvkm_runl_foreach_cgrp_safe(cgrp, gtmp, runl) {
+ state = atomic_cmpxchg(&cgrp->rc, NVKM_CGRP_RC_PENDING, NVKM_CGRP_RC_RUNNING);
+ if (state == NVKM_CGRP_RC_PENDING) {
+ /* Disable all channels in them, and remove from runlist. */
+ nvkm_cgrp_foreach_chan_safe(chan, ctmp, cgrp) {
+ nvkm_chan_error(chan, false);
+ nvkm_chan_remove_locked(chan);
+ }
+ }
+ }
+
+ /* On GPUs with runlist preempt, wait for PBDMA(s) servicing runlist to go idle. */
+ if (runl->func->preempt) {
+ for (i = 0; i < runl->runq_nr; i++) {
+ struct nvkm_runq *runq = runl->runq[i];
+
+ if (runq) {
+ nvkm_msec(fifo->engine.subdev.device, 2000,
+ if (runq->func->idle(runq))
+ break;
+ );
+ }
+ }
+ }
+
+ /* Look for engines that are still on flagged channel groups - reset them. */
+ nvkm_runl_foreach_engn_cond(engn, runl, engn->func->cxid) {
+ cgrp = nvkm_engn_cgrp_get(engn, &flags);
+ if (!cgrp) {
+ ENGN_DEBUG(engn, "cxid not valid");
+ continue;
+ }
+
+ reset = atomic_read(&cgrp->rc) == NVKM_CGRP_RC_RUNNING;
+ nvkm_cgrp_put(&cgrp, flags);
+ if (!reset) {
+ ENGN_DEBUG(engn, "cxid not in recovery");
+ continue;
+ }
+
+ ENGN_DEBUG(engn, "resetting...");
+ /*TODO: can we do something less of a potential catastrophe on failure? */
+ WARN_ON(nvkm_engine_reset(engn->engine));
+ }
+
+ /* Submit runlist update, and clear any remaining exception state. */
+ runl->func->update(runl);
+ if (runl->func->fault_clear)
+ runl->func->fault_clear(runl);
+
+ /* Unblock runlist processing. */
+ while (rc--)
+ nvkm_runl_allow(runl);
+ runl->func->wait(runl);
+}
+
+static void
+nvkm_runl_rc_runl(struct nvkm_runl *runl)
+{
+ RUNL_ERROR(runl, "rc scheduled");
+
+ nvkm_runl_block(runl);
+ if (runl->func->preempt)
+ runl->func->preempt(runl);
+
+ atomic_inc(&runl->rc_pending);
+ schedule_work(&runl->work);
+}
+
+void
+nvkm_runl_rc_cgrp(struct nvkm_cgrp *cgrp)
+{
+ if (atomic_cmpxchg(&cgrp->rc, NVKM_CGRP_RC_NONE, NVKM_CGRP_RC_PENDING) != NVKM_CGRP_RC_NONE)
+ return;
+
+ CGRP_ERROR(cgrp, "rc scheduled");
+ nvkm_runl_rc_runl(cgrp->runl);
+}
+
+void
+nvkm_runl_rc_engn(struct nvkm_runl *runl, struct nvkm_engn *engn)
+{
+ struct nvkm_cgrp *cgrp;
+ unsigned long flags;
+
+ /* Lookup channel group currently on engine. */
+ cgrp = nvkm_engn_cgrp_get(engn, &flags);
+ if (!cgrp) {
+ ENGN_DEBUG(engn, "rc skipped, not on channel");
+ return;
+ }
+
+ nvkm_runl_rc_cgrp(cgrp);
+ nvkm_cgrp_put(&cgrp, flags);
+}
+
+static void
+nvkm_runl_work(struct work_struct *work)
+{
+ struct nvkm_runl *runl = container_of(work, typeof(*runl), work);
+
+ mutex_lock(&runl->mutex);
+ nvkm_runl_rc(runl);
+ mutex_unlock(&runl->mutex);
+
+}
+
+struct nvkm_chan *
+nvkm_runl_chan_get_inst(struct nvkm_runl *runl, u64 inst, unsigned long *pirqflags)
+{
+ struct nvkm_chid *chid = runl->chid;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+ int id;
+
+ spin_lock_irqsave(&chid->lock, flags);
+ for_each_set_bit(id, chid->used, chid->nr) {
+ chan = chid->data[id];
+ if (likely(chan)) {
+ if (chan->inst->addr == inst) {
+ spin_lock(&chan->cgrp->lock);
+ *pirqflags = flags;
+ spin_unlock(&chid->lock);
+ return chan;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&chid->lock, flags);
+ return NULL;
+}
+
+struct nvkm_chan *
+nvkm_runl_chan_get_chid(struct nvkm_runl *runl, int id, unsigned long *pirqflags)
+{
+ struct nvkm_chid *chid = runl->chid;
+ struct nvkm_chan *chan;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chid->lock, flags);
+ if (!WARN_ON(id >= chid->nr)) {
+ chan = chid->data[id];
+ if (likely(chan)) {
+ spin_lock(&chan->cgrp->lock);
+ *pirqflags = flags;
+ spin_unlock(&chid->lock);
+ return chan;
+ }
+ }
+ spin_unlock_irqrestore(&chid->lock, flags);
+ return NULL;
+}
+
+struct nvkm_cgrp *
+nvkm_runl_cgrp_get_cgid(struct nvkm_runl *runl, int id, unsigned long *pirqflags)
+{
+ struct nvkm_chid *cgid = runl->cgid;
+ struct nvkm_cgrp *cgrp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cgid->lock, flags);
+ if (!WARN_ON(id >= cgid->nr)) {
+ cgrp = cgid->data[id];
+ if (likely(cgrp)) {
+ spin_lock(&cgrp->lock);
+ *pirqflags = flags;
+ spin_unlock(&cgid->lock);
+ return cgrp;
+ }
+ }
+ spin_unlock_irqrestore(&cgid->lock, flags);
+ return NULL;
+}
+
+int
+nvkm_runl_preempt_wait(struct nvkm_runl *runl)
+{
+ return nvkm_msec(runl->fifo->engine.subdev.device, runl->fifo->timeout.chan_msec,
+ if (!runl->func->preempt_pending(runl))
+ break;
+
+ nvkm_runl_rc(runl);
+ usleep_range(1, 2);
+ ) < 0 ? -ETIMEDOUT : 0;
+}
+
+bool
+nvkm_runl_update_pending(struct nvkm_runl *runl)
+{
+ if (!runl->func->pending(runl))
+ return false;
+
+ nvkm_runl_rc(runl);
+ return true;
+}
+
+void
+nvkm_runl_update_locked(struct nvkm_runl *runl, bool wait)
+{
+ if (atomic_xchg(&runl->changed, 0) && runl->func->update) {
+ runl->func->update(runl);
+ if (wait)
+ runl->func->wait(runl);
+ }
+}
+
+void
+nvkm_runl_allow(struct nvkm_runl *runl)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ if (!--runl->blocked) {
+ RUNL_TRACE(runl, "running");
+ runl->func->allow(runl, ~0);
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+void
+nvkm_runl_block(struct nvkm_runl *runl)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ if (!runl->blocked++) {
+ RUNL_TRACE(runl, "stopped");
+ runl->func->block(runl, ~0);
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+}
+
+void
+nvkm_runl_fini(struct nvkm_runl *runl)
+{
+ if (runl->func->fini)
+ runl->func->fini(runl);
+
+ flush_work(&runl->work);
+}
+
+void
+nvkm_runl_del(struct nvkm_runl *runl)
+{
+ struct nvkm_engn *engn, *engt;
+
+ nvkm_memory_unref(&runl->mem);
+
+ list_for_each_entry_safe(engn, engt, &runl->engns, head) {
+ list_del(&engn->head);
+ kfree(engn);
+ }
+
+ nvkm_chid_unref(&runl->chid);
+ nvkm_chid_unref(&runl->cgid);
+
+ list_del(&runl->head);
+ mutex_destroy(&runl->mutex);
+ kfree(runl);
+}
+
+struct nvkm_engn *
+nvkm_runl_add(struct nvkm_runl *runl, int engi, const struct nvkm_engn_func *func,
+ enum nvkm_subdev_type type, int inst)
+{
+ struct nvkm_fifo *fifo = runl->fifo;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_engine *engine;
+ struct nvkm_engn *engn;
+
+ engine = nvkm_device_engine(device, type, inst);
+ if (!engine) {
+ RUNL_DEBUG(runl, "engn %d.%d[%s] not found", engi, inst, nvkm_subdev_type[type]);
+ return NULL;
+ }
+
+ if (!(engn = kzalloc(sizeof(*engn), GFP_KERNEL)))
+ return NULL;
+
+ engn->func = func;
+ engn->runl = runl;
+ engn->id = engi;
+ engn->engine = engine;
+ engn->fault = -1;
+ list_add_tail(&engn->head, &runl->engns);
+
+ /* Lookup MMU engine ID for fault handling. */
+ if (device->top)
+ engn->fault = nvkm_top_fault_id(device, engine->subdev.type, engine->subdev.inst);
+
+ if (engn->fault < 0 && fifo->func->mmu_fault) {
+ const struct nvkm_enum *map = fifo->func->mmu_fault->engine;
+
+ while (map->name) {
+ if (map->data2 == engine->subdev.type && map->inst == engine->subdev.inst) {
+ engn->fault = map->value;
+ break;
+ }
+ map++;
+ }
+ }
+
+ return engn;
+}
+
+struct nvkm_runl *
+nvkm_runl_get(struct nvkm_fifo *fifo, int runi, u32 addr)
+{
+ struct nvkm_runl *runl;
+
+ nvkm_runl_foreach(runl, fifo) {
+ if ((runi >= 0 && runl->id == runi) || (runi < 0 && runl->addr == addr))
+ return runl;
+ }
+
+ return NULL;
+}
+
+struct nvkm_runl *
+nvkm_runl_new(struct nvkm_fifo *fifo, int runi, u32 addr, int id_nr)
+{
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ struct nvkm_runl *runl;
+ int ret;
+
+ if (!(runl = kzalloc(sizeof(*runl), GFP_KERNEL)))
+ return NULL;
+
+ runl->func = fifo->func->runl;
+ runl->fifo = fifo;
+ runl->id = runi;
+ runl->addr = addr;
+ INIT_LIST_HEAD(&runl->engns);
+ INIT_LIST_HEAD(&runl->cgrps);
+ atomic_set(&runl->changed, 0);
+ mutex_init(&runl->mutex);
+ INIT_WORK(&runl->work, nvkm_runl_work);
+ atomic_set(&runl->rc_triggered, 0);
+ atomic_set(&runl->rc_pending, 0);
+ list_add_tail(&runl->head, &fifo->runls);
+
+ if (!fifo->chid) {
+ if ((ret = nvkm_chid_new(&nvkm_chan_event, subdev, id_nr, 0, id_nr, &runl->cgid)) ||
+ (ret = nvkm_chid_new(&nvkm_chan_event, subdev, id_nr, 0, id_nr, &runl->chid))) {
+ RUNL_ERROR(runl, "cgid/chid: %d", ret);
+ nvkm_runl_del(runl);
+ return NULL;
+ }
+ } else {
+ runl->cgid = nvkm_chid_ref(fifo->cgid);
+ runl->chid = nvkm_chid_ref(fifo->chid);
+ }
+
+ return runl;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
new file mode 100644
index 000000000000..c93d21bb7bd5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
@@ -0,0 +1,125 @@
+#ifndef __NVKM_RUNL_H__
+#define __NVKM_RUNL_H__
+#include <core/intr.h>
+struct nvkm_cctx;
+struct nvkm_cgrp;
+struct nvkm_chan;
+struct nvkm_memory;
+struct nvkm_object;
+struct nvkm_vctx;
+enum nvkm_subdev_type;
+
+struct nvkm_engn {
+ const struct nvkm_engn_func {
+ bool (*chsw)(struct nvkm_engn *);
+ int (*cxid)(struct nvkm_engn *, bool *cgid);
+ void (*mmu_fault_trigger)(struct nvkm_engn *);
+ bool (*mmu_fault_triggered)(struct nvkm_engn *);
+ int (*ctor)(struct nvkm_engn *, struct nvkm_vctx *);
+ void (*bind)(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *);
+ int (*ramht_add)(struct nvkm_engn *, struct nvkm_object *, struct nvkm_chan *);
+ void (*ramht_del)(struct nvkm_chan *, int hash);
+ } *func;
+ struct nvkm_runl *runl;
+ int id;
+
+ struct nvkm_engine *engine;
+
+ int fault;
+
+ struct list_head head;
+};
+
+#define ENGN_PRINT(e,l,p,f,a...) \
+ RUNL_PRINT((e)->runl, l, p, "%02d[%8s]:"f, (e)->id, (e)->engine->subdev.name, ##a)
+#define ENGN_DEBUG(e,f,a...) ENGN_PRINT((e), DEBUG, info, " "f"\n", ##a)
+
+struct nvkm_runl {
+ const struct nvkm_runl_func {
+ void (*init)(struct nvkm_runl *);
+ void (*fini)(struct nvkm_runl *);
+ int runqs;
+ u8 size;
+ int (*update)(struct nvkm_runl *);
+ void (*insert_cgrp)(struct nvkm_cgrp *, struct nvkm_memory *, u64 offset);
+ void (*insert_chan)(struct nvkm_chan *, struct nvkm_memory *, u64 offset);
+ void (*commit)(struct nvkm_runl *, struct nvkm_memory *, u32 start, int count);
+ int (*wait)(struct nvkm_runl *);
+ bool (*pending)(struct nvkm_runl *);
+ void (*block)(struct nvkm_runl *, u32 engm);
+ void (*allow)(struct nvkm_runl *, u32 engm);
+ void (*fault_clear)(struct nvkm_runl *);
+ void (*preempt)(struct nvkm_runl *);
+ bool (*preempt_pending)(struct nvkm_runl *);
+ } *func;
+ struct nvkm_fifo *fifo;
+ int id;
+ u32 addr;
+ u32 chan;
+ u16 doorbell;
+
+ struct nvkm_chid *cgid;
+#define NVKM_CHAN_EVENT_ERRORED BIT(0)
+ struct nvkm_chid *chid;
+
+ struct list_head engns;
+
+ struct nvkm_runq *runq[2];
+ int runq_nr;
+
+ struct nvkm_inth inth;
+
+ struct list_head cgrps;
+ int cgrp_nr;
+ int chan_nr;
+ atomic_t changed;
+ struct nvkm_memory *mem;
+ u32 offset;
+ struct mutex mutex;
+
+ int blocked;
+
+ struct work_struct work;
+ atomic_t rc_triggered;
+ atomic_t rc_pending;
+
+ struct list_head head;
+};
+
+struct nvkm_runl *nvkm_runl_new(struct nvkm_fifo *, int runi, u32 addr, int id_nr);
+struct nvkm_runl *nvkm_runl_get(struct nvkm_fifo *, int runi, u32 addr);
+struct nvkm_engn *nvkm_runl_add(struct nvkm_runl *, int engi, const struct nvkm_engn_func *,
+ enum nvkm_subdev_type, int inst);
+void nvkm_runl_del(struct nvkm_runl *);
+void nvkm_runl_fini(struct nvkm_runl *);
+void nvkm_runl_block(struct nvkm_runl *);
+void nvkm_runl_allow(struct nvkm_runl *);
+void nvkm_runl_update_locked(struct nvkm_runl *, bool wait);
+bool nvkm_runl_update_pending(struct nvkm_runl *);
+int nvkm_runl_preempt_wait(struct nvkm_runl *);
+
+void nvkm_runl_rc_engn(struct nvkm_runl *, struct nvkm_engn *);
+void nvkm_runl_rc_cgrp(struct nvkm_cgrp *);
+
+struct nvkm_cgrp *nvkm_runl_cgrp_get_cgid(struct nvkm_runl *, int cgid, unsigned long *irqflags);
+struct nvkm_chan *nvkm_runl_chan_get_chid(struct nvkm_runl *, int chid, unsigned long *irqflags);
+struct nvkm_chan *nvkm_runl_chan_get_inst(struct nvkm_runl *, u64 inst, unsigned long *irqflags);
+
+#define nvkm_runl_find_engn(engn,runl,cond) nvkm_list_find(engn, &(runl)->engns, head, (cond))
+
+#define nvkm_runl_first(fifo) list_first_entry(&(fifo)->runls, struct nvkm_runl, head)
+#define nvkm_runl_foreach(runl,fifo) list_for_each_entry((runl), &(fifo)->runls, head)
+#define nvkm_runl_foreach_cond(runl,fifo,cond) nvkm_list_foreach(runl, &(fifo)->runls, head, (cond))
+#define nvkm_runl_foreach_engn(engn,runl) list_for_each_entry((engn), &(runl)->engns, head)
+#define nvkm_runl_foreach_engn_cond(engn,runl,cond) \
+ nvkm_list_foreach(engn, &(runl)->engns, head, (cond))
+#define nvkm_runl_foreach_cgrp(cgrp,runl) list_for_each_entry((cgrp), &(runl)->cgrps, head)
+#define nvkm_runl_foreach_cgrp_safe(cgrp,gtmp,runl) \
+ list_for_each_entry_safe((cgrp), (gtmp), &(runl)->cgrps, head)
+
+#define RUNL_PRINT(r,l,p,f,a...) \
+ nvkm_printk__(&(r)->fifo->engine.subdev, NV_DBG_##l, p, "%06x:"f, (r)->addr, ##a)
+#define RUNL_ERROR(r,f,a...) RUNL_PRINT((r), ERROR, err, " "f"\n", ##a)
+#define RUNL_DEBUG(r,f,a...) RUNL_PRINT((r), DEBUG, info, " "f"\n", ##a)
+#define RUNL_TRACE(r,f,a...) RUNL_PRINT((r), TRACE, info, " "f"\n", ##a)
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c
new file mode 100644
index 000000000000..33bcf5fb3ef0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "runq.h"
+#include "priv.h"
+
+void
+nvkm_runq_del(struct nvkm_runq *runq)
+{
+ list_del(&runq->head);
+ kfree(runq);
+}
+
+struct nvkm_runq *
+nvkm_runq_new(struct nvkm_fifo *fifo, int pbid)
+{
+ struct nvkm_runq *runq;
+
+ if (!(runq = kzalloc(sizeof(*runq), GFP_KERNEL)))
+ return NULL;
+
+ runq->func = fifo->func->runq;
+ runq->fifo = fifo;
+ runq->id = pbid;
+ list_add_tail(&runq->head, &fifo->runqs);
+ return runq;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h
new file mode 100644
index 000000000000..2cb4836e8b31
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_RUNQ_H__
+#define __NVKM_RUNQ_H__
+#include <core/os.h>
+struct nvkm_runl;
+
+struct nvkm_runq {
+ const struct nvkm_runq_func {
+ void (*init)(struct nvkm_runq *);
+ bool (*intr)(struct nvkm_runq *, struct nvkm_runl *);
+ const struct nvkm_bitfield *intr_0_names;
+ bool (*intr_1_ctxnotvalid)(struct nvkm_runq *, int chid);
+ bool (*idle)(struct nvkm_runq *);
+ } *func;
+ struct nvkm_fifo *fifo;
+ int id;
+
+ struct list_head head;
+};
+
+struct nvkm_runq *nvkm_runq_new(struct nvkm_fifo *, int pbid);
+void nvkm_runq_del(struct nvkm_runq *);
+
+#define nvkm_runq_foreach(runq,fifo) list_for_each_entry((runq), &(fifo)->runqs, head)
+#define nvkm_runq_foreach_cond(runq,fifo,cond) nvkm_list_foreach(runq, &(fifo)->runqs, head, (cond))
+
+#define RUNQ_PRINT(r,l,p,f,a...) \
+ nvkm_printk__(&(r)->fifo->engine.subdev, NV_DBG_##l, p, "PBDMA%d:"f, (r)->id, ##a)
+#define RUNQ_ERROR(r,f,a...) RUNQ_PRINT((r), ERROR, err, " "f"\n", ##a)
+#define RUNQ_DEBUG(r,f,a...) RUNQ_PRINT((r), DEBUG, info, " "f"\n", ##a)
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
index 260b197f81bc..ea9e151dbb48 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
@@ -19,46 +19,83 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "gk104.h"
+#include "priv.h"
#include "cgrp.h"
-#include "changk104.h"
-#include "user.h"
+#include "chan.h"
+#include "runl.h"
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <subdev/bar.h>
-#include <subdev/fault.h>
-#include <subdev/top.h>
-#include <subdev/timer.h>
-#include <engine/sw.h>
+#include <core/memory.h>
+#include <subdev/mc.h>
+#include <subdev/vfn.h>
#include <nvif/class.h>
+static u32
+tu102_chan_doorbell_handle(struct nvkm_chan *chan)
+{
+ return (chan->cgrp->runl->id << 16) | chan->id;
+}
+
static void
-tu102_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
- struct nvkm_memory *mem, int nr)
+tu102_chan_start(struct nvkm_chan *chan)
{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- u64 addr = nvkm_memory_addr(mem);
- /*XXX: target? */
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ gk104_chan_start(chan);
+ nvkm_wr32(device, device->vfn->addr.user + 0x0090, chan->func->doorbell_handle(chan));
+}
+
+static const struct nvkm_chan_func
+tu102_chan = {
+ .inst = &gf100_chan_inst,
+ .userd = &gv100_chan_userd,
+ .ramfc = &gv100_chan_ramfc,
+ .bind = gk104_chan_bind_inst,
+ .unbind = gk104_chan_unbind,
+ .start = tu102_chan_start,
+ .stop = gk104_chan_stop,
+ .preempt = gk110_chan_preempt,
+ .doorbell_handle = tu102_chan_doorbell_handle,
+};
+
+static bool
+tu102_runl_pending(struct nvkm_runl *runl)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+
+ return nvkm_rd32(device, 0x002b0c + (runl->id * 0x10)) & 0x00008000;
+}
- nvkm_wr32(device, 0x002b00 + (runl * 0x10), lower_32_bits(addr));
- nvkm_wr32(device, 0x002b04 + (runl * 0x10), upper_32_bits(addr));
- nvkm_wr32(device, 0x002b08 + (runl * 0x10), nr);
+static void
+tu102_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
+{
+ struct nvkm_device *device = runl->fifo->engine.subdev.device;
+ u64 addr = nvkm_memory_addr(memory) + start;
+ /*XXX: target? */
- /*XXX: how to wait? can you even wait? */
+ nvkm_wr32(device, 0x002b00 + (runl->id * 0x10), lower_32_bits(addr));
+ nvkm_wr32(device, 0x002b04 + (runl->id * 0x10), upper_32_bits(addr));
+ nvkm_wr32(device, 0x002b08 + (runl->id * 0x10), count);
}
-static const struct gk104_fifo_runlist_func
-tu102_fifo_runlist = {
+static const struct nvkm_runl_func
+tu102_runl = {
+ .runqs = 2,
.size = 16,
- .cgrp = gv100_fifo_runlist_cgrp,
- .chan = gv100_fifo_runlist_chan,
- .commit = tu102_fifo_runlist_commit,
+ .update = nv50_runl_update,
+ .insert_cgrp = gv100_runl_insert_cgrp,
+ .insert_chan = gv100_runl_insert_chan,
+ .commit = tu102_runl_commit,
+ .wait = nv50_runl_wait,
+ .pending = tu102_runl_pending,
+ .block = gk104_runl_block,
+ .allow = gk104_runl_allow,
+ .preempt = gv100_runl_preempt,
+ .preempt_pending = gf100_runl_preempt_pending,
};
static const struct nvkm_enum
-tu102_fifo_fault_engine[] = {
+tu102_fifo_mmu_fault_engine[] = {
{ 0x01, "DISPLAY" },
{ 0x03, "PTP" },
{ 0x06, "PWR_PMU" },
@@ -85,305 +122,82 @@ tu102_fifo_fault_engine[] = {
{}
};
-static void
-tu102_fifo_pbdma_init(struct gk104_fifo *fifo)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- const u32 mask = (1 << fifo->pbdma_nr) - 1;
- /*XXX: this is a bit of a guess at this point in time. */
- nvkm_mask(device, 0xb65000, 0x80000fff, 0x80000000 | mask);
-}
-
-static const struct gk104_fifo_pbdma_func
-tu102_fifo_pbdma = {
- .nr = gm200_fifo_pbdma_nr,
- .init = tu102_fifo_pbdma_init,
- .init_timeout = gk208_fifo_pbdma_init_timeout,
-};
-
-static const struct gk104_fifo_func
-tu102_fifo = {
- .pbdma = &tu102_fifo_pbdma,
- .fault.access = gv100_fifo_fault_access,
- .fault.engine = tu102_fifo_fault_engine,
- .fault.reason = gv100_fifo_fault_reason,
- .fault.hubclient = gv100_fifo_fault_hubclient,
- .fault.gpcclient = gv100_fifo_fault_gpcclient,
- .runlist = &tu102_fifo_runlist,
- .user = {{-1,-1,VOLTA_USERMODE_A }, tu102_fifo_user_new },
- .chan = {{ 0, 0,TURING_CHANNEL_GPFIFO_A}, tu102_fifo_gpfifo_new },
- .cgrp_force = true,
+const struct nvkm_fifo_func_mmu_fault
+tu102_fifo_mmu_fault = {
+ .recover = gf100_fifo_mmu_fault_recover,
+ .access = gv100_fifo_mmu_fault_access,
+ .engine = tu102_fifo_mmu_fault_engine,
+ .reason = gv100_fifo_mmu_fault_reason,
+ .hubclient = gv100_fifo_mmu_fault_hubclient,
+ .gpcclient = gv100_fifo_mmu_fault_gpcclient,
};
-static void
-tu102_fifo_recover_work(struct work_struct *w)
+void
+tu102_fifo_intr_ctxsw_timeout_info(struct nvkm_engn *engn, u32 info)
{
- struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- struct nvkm_engine *engine;
+ struct nvkm_runl *runl = engn->runl;
+ struct nvkm_cgrp *cgrp;
unsigned long flags;
- u32 engm, runm, todo;
- int engn, runl;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
- runm = fifo->recover.runm;
- engm = fifo->recover.engm;
- fifo->recover.engm = 0;
- fifo->recover.runm = 0;
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-
- nvkm_mask(device, 0x002630, runm, runm);
-
- for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) {
- if ((engine = fifo->engine[engn].engine)) {
- nvkm_subdev_fini(&engine->subdev, false);
- WARN_ON(nvkm_subdev_init(&engine->subdev));
- }
- }
-
- for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl))
- gk104_fifo_runlist_update(fifo, runl);
-
- nvkm_mask(device, 0x002630, runm, 0x00000000);
-}
-
-static void tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn);
-
-static void
-tu102_fifo_recover_runl(struct gk104_fifo *fifo, int runl)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 runm = BIT(runl);
-
- assert_spin_locked(&fifo->base.lock);
- if (fifo->recover.runm & runm)
- return;
- fifo->recover.runm |= runm;
-
- /* Block runlist to prevent channel assignment(s) from changing. */
- nvkm_mask(device, 0x002630, runm, runm);
-
- /* Schedule recovery. */
- nvkm_warn(subdev, "runlist %d: scheduled for recovery\n", runl);
- schedule_work(&fifo->recover.work);
-}
-
-static struct gk104_fifo_chan *
-tu102_fifo_recover_chid(struct gk104_fifo *fifo, int runl, int chid)
-{
- struct gk104_fifo_chan *chan;
- struct nvkm_fifo_cgrp *cgrp;
-
- list_for_each_entry(chan, &fifo->runlist[runl].chan, head) {
- if (chan->base.chid == chid) {
- list_del_init(&chan->head);
- return chan;
- }
- }
-
- list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) {
- if (cgrp->id == chid) {
- chan = list_first_entry(&cgrp->chan, typeof(*chan), head);
- list_del_init(&chan->head);
- if (!--cgrp->chan_nr)
- list_del_init(&cgrp->head);
- return chan;
- }
- }
-
- return NULL;
-}
-static void
-tu102_fifo_recover_chan(struct nvkm_fifo *base, int chid)
-{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 stat = nvkm_rd32(device, 0x800004 + (chid * 0x08));
- const u32 runl = (stat & 0x000f0000) >> 16;
- const bool used = (stat & 0x00000001);
- unsigned long engn, engm = fifo->runlist[runl].engm;
- struct gk104_fifo_chan *chan;
-
- assert_spin_locked(&fifo->base.lock);
- if (!used)
+ /* Check that engine hasn't become unstuck since timeout raised. */
+ ENGN_DEBUG(engn, "CTXSW_TIMEOUT %08x", info);
+ if (info & 0xc0000000)
return;
- /* Lookup SW state for channel, and mark it as dead. */
- chan = tu102_fifo_recover_chid(fifo, runl, chid);
- if (chan) {
- chan->killed = true;
- nvkm_fifo_kevent(&fifo->base, chid);
- }
-
- /* Disable channel. */
- nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800);
- nvkm_warn(subdev, "channel %d: killed\n", chid);
-
- /* Block channel assignments from changing during recovery. */
- tu102_fifo_recover_runl(fifo, runl);
-
- /* Schedule recovery for any engines the channel is on. */
- for_each_set_bit(engn, &engm, fifo->engine_nr) {
- struct gk104_fifo_engine_status status;
-
- gk104_fifo_engine_status(fifo, engn, &status);
- if (!status.chan || status.chan->id != chid)
- continue;
- tu102_fifo_recover_engn(fifo, engn);
+ /* Determine channel group the engine is stuck on, and schedule recovery. */
+ switch (info & 0x0000c000) {
+ case 0x00004000: /* LOAD */
+ cgrp = nvkm_runl_cgrp_get_cgid(runl, info & 0x3fff0000, &flags);
+ break;
+ case 0x00008000: /* SAVE */
+ case 0x0000c000: /* SWITCH */
+ cgrp = nvkm_runl_cgrp_get_cgid(runl, info & 0x00003fff, &flags);
+ break;
+ default:
+ cgrp = NULL;
+ break;
}
-}
-
-static void
-tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn)
-{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const u32 runl = fifo->engine[engn].runl;
- const u32 engm = BIT(engn);
- struct gk104_fifo_engine_status status;
-
- assert_spin_locked(&fifo->base.lock);
- if (fifo->recover.engm & engm)
- return;
- fifo->recover.engm |= engm;
- /* Block channel assignments from changing during recovery. */
- tu102_fifo_recover_runl(fifo, runl);
-
- /* Determine which channel (if any) is currently on the engine. */
- gk104_fifo_engine_status(fifo, engn, &status);
- if (status.chan) {
- /* The channel is not longer viable, kill it. */
- tu102_fifo_recover_chan(&fifo->base, status.chan->id);
+ if (!WARN_ON(!cgrp)) {
+ nvkm_runl_rc_cgrp(cgrp);
+ nvkm_cgrp_put(&cgrp, flags);
}
-
- /* Preempt the runlist */
- nvkm_wr32(device, 0x2638, BIT(runl));
-
- /* Schedule recovery. */
- nvkm_warn(subdev, "engine %d: scheduled for recovery\n", engn);
- schedule_work(&fifo->recover.work);
}
static void
-tu102_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
+tu102_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- const struct nvkm_enum *er, *ee, *ec, *ea;
- struct nvkm_engine *engine = NULL;
- struct nvkm_fifo_chan *chan;
- unsigned long flags;
- const char *en = "";
- char ct[8] = "HUB/";
- int engn;
-
- er = nvkm_enum_find(fifo->func->fault.reason, info->reason);
- ee = nvkm_enum_find(fifo->func->fault.engine, info->engine);
- if (info->hub) {
- ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client);
- } else {
- ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client);
- snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
- }
- ea = nvkm_enum_find(fifo->func->fault.access, info->access);
-
- if (ee && ee->data2) {
- switch (ee->data2) {
- case NVKM_SUBDEV_BAR:
- nvkm_bar_bar1_reset(device);
- break;
- case NVKM_SUBDEV_INSTMEM:
- nvkm_bar_bar2_reset(device);
- break;
- case NVKM_ENGINE_IFB:
- nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
- break;
- default:
- engine = nvkm_device_engine(device, ee->data2, 0);
- break;
- }
- }
-
- if (ee == NULL) {
- struct nvkm_subdev *subdev = nvkm_top_fault(device, info->engine);
- if (subdev) {
- if (subdev->func == &nvkm_engine)
- engine = container_of(subdev, typeof(*engine), subdev);
- en = engine->subdev.name;
+ struct nvkm_device *device = fifo->engine.subdev.device;
+ struct nvkm_runl *runl;
+ struct nvkm_engn *engn;
+ u32 engm = nvkm_rd32(device, 0x002a30);
+ u32 info;
+
+ nvkm_runl_foreach(runl, fifo) {
+ nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) {
+ info = nvkm_rd32(device, 0x003200 + (engn->id * 4));
+ tu102_fifo_intr_ctxsw_timeout_info(engn, info);
}
- } else {
- en = ee->name;
}
- spin_lock_irqsave(&fifo->base.lock, flags);
- chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst);
-
- nvkm_error(subdev,
- "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
- "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
- info->access, ea ? ea->name : "", info->addr,
- info->engine, ee ? ee->name : en,
- info->client, ct, ec ? ec->name : "",
- info->reason, er ? er->name : "", chan ? chan->chid : -1,
- info->inst, chan ? chan->object.client->name : "unknown");
-
- /* Kill the channel that caused the fault. */
- if (chan)
- tu102_fifo_recover_chan(&fifo->base, chan->chid);
-
- /* Channel recovery will probably have already done this for the
- * correct engine(s), but just in case we can't find the channel
- * information...
- */
- for (engn = 0; engn < fifo->engine_nr && engine; engn++) {
- if (fifo->engine[engn].engine == engine) {
- tu102_fifo_recover_engn(fifo, engn);
- break;
- }
- }
-
- spin_unlock_irqrestore(&fifo->base.lock, flags);
-}
-
-static void
-tu102_fifo_intr_ctxsw_timeout(struct gk104_fifo *fifo)
-{
- struct nvkm_device *device = fifo->base.engine.subdev.device;
- unsigned long flags, engm;
- u32 engn;
-
- spin_lock_irqsave(&fifo->base.lock, flags);
-
- engm = nvkm_rd32(device, 0x2a30);
- nvkm_wr32(device, 0x2a30, engm);
-
- for_each_set_bit(engn, &engm, 32)
- tu102_fifo_recover_engn(fifo, engn);
-
- spin_unlock_irqrestore(&fifo->base.lock, flags);
+ nvkm_wr32(device, 0x002a30, engm);
}
static void
-tu102_fifo_intr_sched(struct gk104_fifo *fifo)
+tu102_fifo_intr_sched(struct nvkm_fifo *fifo)
{
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
- struct nvkm_device *device = subdev->device;
- u32 intr = nvkm_rd32(device, 0x00254c);
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
+ u32 intr = nvkm_rd32(subdev->device, 0x00254c);
u32 code = intr & 0x000000ff;
nvkm_error(subdev, "SCHED_ERROR %02x\n", code);
}
-static void
-tu102_fifo_intr(struct nvkm_fifo *base)
+static irqreturn_t
+tu102_fifo_intr(struct nvkm_inth *inth)
{
- struct gk104_fifo *fifo = gk104_fifo(base);
- struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+ struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth);
+ struct nvkm_subdev *subdev = &fifo->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 mask = nvkm_rd32(device, 0x002140);
u32 stat = nvkm_rd32(device, 0x002100) & mask;
@@ -412,17 +226,8 @@ tu102_fifo_intr(struct nvkm_fifo *base)
}
if (stat & 0x20000000) {
- u32 mask = nvkm_rd32(device, 0x0025a0);
-
- while (mask) {
- u32 unit = __ffs(mask);
-
- gk104_fifo_intr_pbdma_0(fifo, unit);
- gk104_fifo_intr_pbdma_1(fifo, unit);
- nvkm_wr32(device, 0x0025a0, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x20000000;
+ if (gf100_fifo_intr_pbdma(fifo))
+ stat &= ~0x20000000;
}
if (stat & 0x40000000) {
@@ -432,46 +237,50 @@ tu102_fifo_intr(struct nvkm_fifo *base)
if (stat & 0x80000000) {
nvkm_wr32(device, 0x002100, 0x80000000);
- gk104_fifo_intr_engine(fifo);
+ nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
stat &= ~0x80000000;
}
if (stat) {
nvkm_error(subdev, "INTR %08x\n", stat);
+ spin_lock(&fifo->lock);
nvkm_mask(device, 0x002140, stat, 0x00000000);
+ spin_unlock(&fifo->lock);
nvkm_wr32(device, 0x002100, stat);
}
+
+ return IRQ_HANDLED;
+}
+
+static void
+tu102_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask)
+{
+ /* Not directly related to PBDMAs, but, enables doorbell to function. */
+ nvkm_mask(fifo->engine.subdev.device, 0xb65000, 0x80000000, 0x80000000);
}
static const struct nvkm_fifo_func
-tu102_fifo_ = {
- .dtor = gk104_fifo_dtor,
- .oneinit = gk104_fifo_oneinit,
- .info = gk104_fifo_info,
+tu102_fifo = {
+ .chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
+ .runq_nr = gm200_fifo_runq_nr,
+ .runl_ctor = gk104_fifo_runl_ctor,
.init = gk104_fifo_init,
- .fini = gk104_fifo_fini,
+ .init_pbdmas = tu102_fifo_init_pbdmas,
.intr = tu102_fifo_intr,
- .fault = tu102_fifo_fault,
- .engine_id = gk104_fifo_engine_id,
- .id_engine = gk104_fifo_id_engine,
- .uevent_init = gk104_fifo_uevent_init,
- .uevent_fini = gk104_fifo_uevent_fini,
- .recover_chan = tu102_fifo_recover_chan,
- .class_get = gk104_fifo_class_get,
- .class_new = gk104_fifo_class_new,
+ .mmu_fault = &tu102_fifo_mmu_fault,
+ .nonstall = &gf100_fifo_nonstall,
+ .runl = &tu102_runl,
+ .runq = &gv100_runq,
+ .engn = &gv100_engn,
+ .engn_ce = &gv100_engn_ce,
+ .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true },
+ .chan = {{ 0, 0, TURING_CHANNEL_GPFIFO_A }, &tu102_chan },
};
int
tu102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fifo **pfifo)
{
- struct gk104_fifo *fifo;
-
- if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
- return -ENOMEM;
- fifo->func = &tu102_fifo;
- INIT_WORK(&fifo->recover.work, tu102_fifo_recover_work);
- *pfifo = &fifo->base;
-
- return nvkm_fifo_ctor(&tu102_fifo_, device, type, inst, 4096, &fifo->base);
+ return nvkm_fifo_new_(&tu102_fifo, device, type, inst, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c
new file mode 100644
index 000000000000..52c594dfb1b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#define nvkm_ucgrp(p) container_of((p), struct nvkm_ucgrp, object)
+#include "priv.h"
+#include "cgrp.h"
+#include "runl.h"
+
+#include <subdev/mmu.h>
+
+#include <nvif/if0021.h>
+
+struct nvkm_ucgrp {
+ struct nvkm_object object;
+ struct nvkm_cgrp *cgrp;
+};
+
+static int
+nvkm_ucgrp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_cgrp *cgrp = nvkm_ucgrp(oclass->parent)->cgrp;
+
+ return nvkm_uchan_new(cgrp->runl->fifo, cgrp, oclass, argv, argc, pobject);
+}
+
+static int
+nvkm_ucgrp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
+{
+ struct nvkm_cgrp *cgrp = nvkm_ucgrp(object)->cgrp;
+ struct nvkm_fifo *fifo = cgrp->runl->fifo;
+ const struct nvkm_fifo_func_chan *chan = &fifo->func->chan;
+ int c = 0;
+
+ /* *_CHANNEL_GPFIFO_* */
+ if (chan->user.oclass) {
+ if (c++ == index) {
+ oclass->base = chan->user;
+ oclass->ctor = nvkm_ucgrp_chan_new;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void *
+nvkm_ucgrp_dtor(struct nvkm_object *object)
+{
+ struct nvkm_ucgrp *ucgrp = nvkm_ucgrp(object);
+
+ nvkm_cgrp_unref(&ucgrp->cgrp);
+ return ucgrp;
+}
+
+static const struct nvkm_object_func
+nvkm_ucgrp = {
+ .dtor = nvkm_ucgrp_dtor,
+ .sclass = nvkm_ucgrp_sclass,
+};
+
+int
+nvkm_ucgrp_new(struct nvkm_fifo *fifo, const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ union nvif_cgrp_args *args = argv;
+ struct nvkm_runl *runl;
+ struct nvkm_vmm *vmm;
+ struct nvkm_ucgrp *ucgrp;
+ int ret;
+
+ if (argc < sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ argc -= sizeof(args->v0);
+
+ if (args->v0.namelen != argc)
+ return -EINVAL;
+
+ /* Lookup objects referenced in args. */
+ runl = nvkm_runl_get(fifo, args->v0.runlist, 0);
+ if (!runl)
+ return -EINVAL;
+
+ vmm = nvkm_uvmm_search(oclass->client, args->v0.vmm);
+ if (IS_ERR(vmm))
+ return PTR_ERR(vmm);
+
+ /* Allocate channel group. */
+ if (!(ucgrp = kzalloc(sizeof(*ucgrp), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ nvkm_object_ctor(&nvkm_ucgrp, oclass, &ucgrp->object);
+ *pobject = &ucgrp->object;
+
+ ret = nvkm_cgrp_new(runl, args->v0.name, vmm, true, &ucgrp->cgrp);
+ if (ret)
+ goto done;
+
+ /* Return channel group info to caller. */
+ args->v0.cgid = ucgrp->cgrp->id;
+
+done:
+ nvkm_vmm_unref(&vmm);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c
new file mode 100644
index 000000000000..1dac95ae7b43
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#define nvkm_uchan(p) container_of((p), struct nvkm_uchan, object)
+#include "priv.h"
+#include "cgrp.h"
+#include "chan.h"
+#include "chid.h"
+#include "runl.h"
+
+#include <core/gpuobj.h>
+#include <core/oproxy.h>
+#include <subdev/mmu.h>
+#include <engine/dma.h>
+
+#include <nvif/if0020.h>
+
+struct nvkm_uchan {
+ struct nvkm_object object;
+ struct nvkm_chan *chan;
+};
+
+static int
+nvkm_uchan_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+ struct nvkm_runl *runl = chan->cgrp->runl;
+ union nvif_chan_event_args *args = argv;
+
+ if (!uevent)
+ return 0;
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+
+ switch (args->v0.type) {
+ case NVIF_CHAN_EVENT_V0_NON_STALL_INTR:
+ return nvkm_uevent_add(uevent, &runl->fifo->nonstall.event, 0,
+ NVKM_FIFO_NONSTALL_EVENT, NULL);
+ case NVIF_CHAN_EVENT_V0_KILLED:
+ return nvkm_uevent_add(uevent, &runl->chid->event, chan->id,
+ NVKM_CHAN_EVENT_ERRORED, NULL);
+ default:
+ break;
+ }
+
+ return -ENOSYS;
+}
+
+struct nvkm_uobj {
+ struct nvkm_oproxy oproxy;
+ struct nvkm_chan *chan;
+ struct nvkm_cctx *cctx;
+ int hash;
+};
+
+static int
+nvkm_uchan_object_fini_1(struct nvkm_oproxy *oproxy, bool suspend)
+{
+ struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
+ struct nvkm_chan *chan = uobj->chan;
+ struct nvkm_cctx *cctx = uobj->cctx;
+ struct nvkm_ectx *ectx = cctx->vctx->ectx;
+
+ if (!ectx->object)
+ return 0;
+
+ /* Unbind engine context from channel, if no longer required. */
+ if (refcount_dec_and_mutex_lock(&cctx->uses, &chan->cgrp->mutex)) {
+ nvkm_chan_cctx_bind(chan, ectx->engn, NULL);
+
+ if (refcount_dec_and_test(&ectx->uses))
+ nvkm_object_fini(ectx->object, false);
+ mutex_unlock(&chan->cgrp->mutex);
+ }
+
+ return 0;
+}
+
+static int
+nvkm_uchan_object_init_0(struct nvkm_oproxy *oproxy)
+{
+ struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
+ struct nvkm_chan *chan = uobj->chan;
+ struct nvkm_cctx *cctx = uobj->cctx;
+ struct nvkm_ectx *ectx = cctx->vctx->ectx;
+ int ret = 0;
+
+ if (!ectx->object)
+ return 0;
+
+ /* Bind engine context to channel, if it hasn't been already. */
+ if (!refcount_inc_not_zero(&cctx->uses)) {
+ mutex_lock(&chan->cgrp->mutex);
+ if (!refcount_inc_not_zero(&cctx->uses)) {
+ if (!refcount_inc_not_zero(&ectx->uses)) {
+ ret = nvkm_object_init(ectx->object);
+ if (ret == 0)
+ refcount_set(&ectx->uses, 1);
+ }
+
+ if (ret == 0) {
+ nvkm_chan_cctx_bind(chan, ectx->engn, cctx);
+ refcount_set(&cctx->uses, 1);
+ }
+ }
+ mutex_unlock(&chan->cgrp->mutex);
+ }
+
+ return ret;
+}
+
+static void
+nvkm_uchan_object_dtor(struct nvkm_oproxy *oproxy)
+{
+ struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
+ struct nvkm_engn *engn;
+
+ if (!uobj->cctx)
+ return;
+
+ engn = uobj->cctx->vctx->ectx->engn;
+ if (engn->func->ramht_del)
+ engn->func->ramht_del(uobj->chan, uobj->hash);
+
+ nvkm_chan_cctx_put(uobj->chan, &uobj->cctx);
+}
+
+static const struct nvkm_oproxy_func
+nvkm_uchan_object = {
+ .dtor[1] = nvkm_uchan_object_dtor,
+ .init[0] = nvkm_uchan_object_init_0,
+ .fini[1] = nvkm_uchan_object_fini_1,
+};
+
+static int
+nvkm_uchan_object_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_chan *chan = nvkm_uchan(oclass->parent)->chan;
+ struct nvkm_cgrp *cgrp = chan->cgrp;
+ struct nvkm_engn *engn;
+ struct nvkm_uobj *uobj;
+ int ret;
+
+ /* Lookup host engine state for target engine. */
+ engn = nvkm_runl_find_engn(engn, cgrp->runl, engn->engine == oclass->engine);
+ if (WARN_ON(!engn))
+ return -EINVAL;
+
+ /* Allocate SW object. */
+ if (!(uobj = kzalloc(sizeof(*uobj), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_oproxy_ctor(&nvkm_uchan_object, oclass, &uobj->oproxy);
+ uobj->chan = chan;
+ *pobject = &uobj->oproxy.base;
+
+ /* Ref. channel context for target engine.*/
+ ret = nvkm_chan_cctx_get(chan, engn, &uobj->cctx, oclass->client);
+ if (ret)
+ return ret;
+
+ /* Allocate HW object. */
+ ret = oclass->base.ctor(&(const struct nvkm_oclass) {
+ .base = oclass->base,
+ .engn = oclass->engn,
+ .handle = oclass->handle,
+ .object = oclass->object,
+ .client = oclass->client,
+ .parent = uobj->cctx->vctx->ectx->object ?: oclass->parent,
+ .engine = engn->engine,
+ }, argv, argc, &uobj->oproxy.object);
+ if (ret)
+ return ret;
+
+ if (engn->func->ramht_add) {
+ uobj->hash = engn->func->ramht_add(engn, uobj->oproxy.object, uobj->chan);
+ if (uobj->hash < 0)
+ return uobj->hash;
+ }
+
+ return 0;
+}
+
+static int
+nvkm_uchan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+ struct nvkm_engn *engn;
+ int ret, runq = 0;
+
+ nvkm_runl_foreach_engn(engn, chan->cgrp->runl) {
+ struct nvkm_engine *engine = engn->engine;
+ int c = 0;
+
+ /* Each runqueue, on runlists with multiple, has its own LCE. */
+ if (engn->runl->func->runqs) {
+ if (engine->subdev.type == NVKM_ENGINE_CE) {
+ if (chan->runq != runq++)
+ continue;
+ }
+ }
+
+ oclass->engine = engine;
+ oclass->base.oclass = 0;
+
+ if (engine->func->fifo.sclass) {
+ ret = engine->func->fifo.sclass(oclass, index);
+ if (oclass->base.oclass) {
+ if (!oclass->base.ctor)
+ oclass->base.ctor = nvkm_object_new;
+ oclass->ctor = nvkm_uchan_object_new;
+ return 0;
+ }
+
+ index -= ret;
+ continue;
+ }
+
+ while (engine->func->sclass[c].oclass) {
+ if (c++ == index) {
+ oclass->base = engine->func->sclass[index];
+ if (!oclass->base.ctor)
+ oclass->base.ctor = nvkm_object_new;
+ oclass->ctor = nvkm_uchan_object_new;
+ return 0;
+ }
+ }
+
+ index -= c;
+ }
+
+ return -EINVAL;
+}
+
+static int
+nvkm_uchan_map(struct nvkm_object *object, void *argv, u32 argc,
+ enum nvkm_object_map *type, u64 *addr, u64 *size)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+ struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
+
+ if (chan->func->userd->bar < 0)
+ return -ENOSYS;
+
+ *type = NVKM_OBJECT_MAP_IO;
+ *addr = device->func->resource_addr(device, chan->func->userd->bar) +
+ chan->func->userd->base + chan->userd.base;
+ *size = chan->func->userd->size;
+ return 0;
+}
+
+static int
+nvkm_uchan_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+
+ nvkm_chan_block(chan);
+ nvkm_chan_remove(chan, true);
+
+ if (chan->func->unbind)
+ chan->func->unbind(chan);
+
+ return 0;
+}
+
+static int
+nvkm_uchan_init(struct nvkm_object *object)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+
+ if (atomic_read(&chan->errored))
+ return 0;
+
+ if (chan->func->bind)
+ chan->func->bind(chan);
+
+ nvkm_chan_allow(chan);
+ nvkm_chan_insert(chan);
+ return 0;
+}
+
+static void *
+nvkm_uchan_dtor(struct nvkm_object *object)
+{
+ struct nvkm_uchan *uchan = nvkm_uchan(object);
+
+ nvkm_chan_del(&uchan->chan);
+ return uchan;
+}
+
+static const struct nvkm_object_func
+nvkm_uchan = {
+ .dtor = nvkm_uchan_dtor,
+ .init = nvkm_uchan_init,
+ .fini = nvkm_uchan_fini,
+ .map = nvkm_uchan_map,
+ .sclass = nvkm_uchan_sclass,
+ .uevent = nvkm_uchan_uevent,
+};
+
+int
+nvkm_uchan_new(struct nvkm_fifo *fifo, struct nvkm_cgrp *cgrp, const struct nvkm_oclass *oclass,
+ void *argv, u32 argc, struct nvkm_object **pobject)
+{
+ union nvif_chan_args *args = argv;
+ struct nvkm_runl *runl;
+ struct nvkm_vmm *vmm = NULL;
+ struct nvkm_dmaobj *ctxdma = NULL;
+ struct nvkm_memory *userd = NULL;
+ struct nvkm_uchan *uchan;
+ struct nvkm_chan *chan;
+ int ret;
+
+ if (argc < sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ argc -= sizeof(args->v0);
+
+ if (args->v0.namelen != argc)
+ return -EINVAL;
+
+ /* Lookup objects referenced in args. */
+ runl = nvkm_runl_get(fifo, args->v0.runlist, 0);
+ if (!runl)
+ return -EINVAL;
+
+ if (args->v0.vmm) {
+ vmm = nvkm_uvmm_search(oclass->client, args->v0.vmm);
+ if (IS_ERR(vmm))
+ return PTR_ERR(vmm);
+ }
+
+ if (args->v0.ctxdma) {
+ ctxdma = nvkm_dmaobj_search(oclass->client, args->v0.ctxdma);
+ if (IS_ERR(ctxdma)) {
+ ret = PTR_ERR(ctxdma);
+ goto done;
+ }
+ }
+
+ if (args->v0.huserd) {
+ userd = nvkm_umem_search(oclass->client, args->v0.huserd);
+ if (IS_ERR(userd)) {
+ ret = PTR_ERR(userd);
+ userd = NULL;
+ goto done;
+ }
+ }
+
+ /* Allocate channel. */
+ if (!(uchan = kzalloc(sizeof(*uchan), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ nvkm_object_ctor(&nvkm_uchan, oclass, &uchan->object);
+ *pobject = &uchan->object;
+
+ ret = nvkm_chan_new_(fifo->func->chan.func, runl, args->v0.runq, cgrp, args->v0.name,
+ args->v0.priv != 0, args->v0.devm, vmm, ctxdma, args->v0.offset,
+ args->v0.length, userd, args->v0.ouserd, &uchan->chan);
+ if (ret)
+ goto done;
+
+ chan = uchan->chan;
+
+ /* Return channel info to caller. */
+ if (chan->func->doorbell_handle)
+ args->v0.token = chan->func->doorbell_handle(chan);
+ else
+ args->v0.token = ~0;
+
+ args->v0.chid = chan->id;
+
+ switch (nvkm_memory_target(chan->inst->memory)) {
+ case NVKM_MEM_TARGET_INST: args->v0.aper = NVIF_CHAN_V0_INST_APER_INST; break;
+ case NVKM_MEM_TARGET_VRAM: args->v0.aper = NVIF_CHAN_V0_INST_APER_VRAM; break;
+ case NVKM_MEM_TARGET_HOST: args->v0.aper = NVIF_CHAN_V0_INST_APER_HOST; break;
+ case NVKM_MEM_TARGET_NCOH: args->v0.aper = NVIF_CHAN_V0_INST_APER_NCOH; break;
+ default:
+ WARN_ON(1);
+ ret = -EFAULT;
+ break;
+ }
+
+ args->v0.inst = nvkm_memory_addr(chan->inst->memory);
+done:
+ nvkm_memory_unref(&userd);
+ nvkm_vmm_unref(&vmm);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
deleted file mode 100644
index 54a3a3092cc0..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NVKM_FIFO_USER_H__
-#define __NVKM_FIFO_USER_H__
-#include "priv.h"
-int gv100_fifo_user_new(const struct nvkm_oclass *, void *, u32,
- struct nvkm_object **);
-int tu102_fifo_user_new(const struct nvkm_oclass *, void *, u32,
- struct nvkm_object **);
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
index 558c86fd8e82..b5418f05ccd8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
@@ -40,6 +40,7 @@ nvkm-y += nvkm/engine/gr/gp108.o
nvkm-y += nvkm/engine/gr/gp10b.o
nvkm-y += nvkm/engine/gr/gv100.o
nvkm-y += nvkm/engine/gr/tu102.o
+nvkm-y += nvkm/engine/gr/ga102.o
nvkm-y += nvkm/engine/gr/ctxnv40.o
nvkm-y += nvkm/engine/gr/ctxnv50.o
@@ -63,3 +64,4 @@ nvkm-y += nvkm/engine/gr/ctxgp104.o
nvkm-y += nvkm/engine/gr/ctxgp107.o
nvkm-y += nvkm/engine/gr/ctxgv100.o
nvkm-y += nvkm/engine/gr/ctxtu102.o
+nvkm-y += nvkm/engine/gr/ctxga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
index 61759f54406e..71b824e6da9d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
@@ -136,6 +136,17 @@ nvkm_gr_oneinit(struct nvkm_engine *engine)
}
static int
+nvkm_gr_reset(struct nvkm_engine *engine)
+{
+ struct nvkm_gr *gr = nvkm_gr(engine);
+
+ if (gr->func->reset)
+ return gr->func->reset(gr);
+
+ return -ENOSYS;
+}
+
+static int
nvkm_gr_init(struct nvkm_engine *engine)
{
struct nvkm_gr *gr = nvkm_gr(engine);
@@ -166,6 +177,7 @@ nvkm_gr = {
.oneinit = nvkm_gr_oneinit,
.init = nvkm_gr_init,
.fini = nvkm_gr_fini,
+ .reset = nvkm_gr_reset,
.intr = nvkm_gr_intr,
.tile = nvkm_gr_tile,
.chsw_load = nvkm_gr_chsw_load,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c
new file mode 100644
index 000000000000..11461adf5036
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "ctxgf100.h"
+
+static void
+ga102_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc);
+
+ nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm);
+}
+
+static void
+ga102_grctx_generate_unkn(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010);
+ nvkm_mask(device, 0x41be08, 0x00000004, 0x00000004);
+}
+
+static void
+ga102_grctx_generate_r419ea8(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x419ea8, nvkm_rd32(device, 0x504728) | 0x08000000);
+}
+
+const struct gf100_grctx_func
+ga102_grctx = {
+ .main = gf100_grctx_generate_main,
+ .unkn = ga102_grctx_generate_unkn,
+ .bundle = gm107_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0x180,
+ .bundle_token_limit = 0x1140,
+ .pagepool = gp100_grctx_generate_pagepool,
+ .pagepool_size = 0x20000,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gv100_grctx_generate_attrib_cb,
+ .attrib = gv100_grctx_generate_attrib,
+ .attrib_nr_max = 0x800,
+ .attrib_nr = 0x4a1,
+ .alpha_nr_max = 0xc00,
+ .alpha_nr = 0x800,
+ .unknown_size = 0x80000,
+ .unknown = tu102_grctx_generate_unknown,
+ .gfxp_nr = 0xd28,
+ .sm_id = ga102_grctx_generate_sm_id,
+ .skip_pd_num_tpc_per_gpc = true,
+ .rop_mapping = gv100_grctx_generate_rop_mapping,
+ .r406500 = gm200_grctx_generate_r406500,
+ .r400088 = gv100_grctx_generate_r400088,
+ .r419ea8 = ga102_grctx_generate_r419ea8,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
index 297915719bf2..cb390e0134a2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
@@ -26,6 +26,7 @@
#include <subdev/fb.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
+#include <engine/fifo.h>
/*******************************************************************************
* PGRAPH context register lists
@@ -990,43 +991,16 @@ gf100_grctx_pack_tpc[] = {
* PGRAPH context implementation
******************************************************************************/
-int
-gf100_grctx_mmio_data(struct gf100_grctx *info, u32 size, u32 align, bool priv)
-{
- if (info->data) {
- info->buffer[info->buffer_nr] = round_up(info->addr, align);
- info->addr = info->buffer[info->buffer_nr] + size;
- info->data->size = size;
- info->data->align = align;
- info->data->priv = priv;
- info->data++;
- return info->buffer_nr++;
- }
- return -1;
-}
-
void
-gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data,
- int shift, int buffer)
+gf100_grctx_patch_wr32(struct gf100_gr_chan *chan, u32 addr, u32 data)
{
- struct nvkm_device *device = info->gr->base.engine.subdev.device;
- if (info->data) {
- if (shift >= 0) {
- info->mmio->addr = addr;
- info->mmio->data = data;
- info->mmio->shift = shift;
- info->mmio->buffer = buffer;
- if (buffer >= 0)
- data |= info->buffer[buffer] >> shift;
- info->mmio++;
- } else
- return;
- } else {
- if (buffer >= 0)
- return;
+ if (unlikely(!chan->mmio)) {
+ nvkm_wr32(chan->gr->base.engine.subdev.device, addr, data);
+ return;
}
- nvkm_wr32(device, addr, data);
+ nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
+ nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
}
void
@@ -1037,56 +1011,60 @@ gf100_grctx_generate_r419cb8(struct gf100_gr *gr)
}
void
-gf100_grctx_generate_bundle(struct gf100_grctx *info)
+gf100_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const int s = 8;
- const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s));
- mmio_refn(info, 0x418808, 0x00000000, s, b);
- mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s));
+ gf100_grctx_patch_wr32(chan, 0x408004, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408008, 0x80000000 | (size >> 8));
+ gf100_grctx_patch_wr32(chan, 0x418808, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x41880c, 0x80000000 | (size >> 8));
}
void
-gf100_grctx_generate_pagepool(struct gf100_grctx *info)
+gf100_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const int s = 8;
- const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
+ gf100_grctx_patch_wr32(chan, 0x40800c, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408010, 0x80000000);
+ gf100_grctx_patch_wr32(chan, 0x419004, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x419008, 0x00000000);
}
void
-gf100_grctx_generate_attrib(struct gf100_grctx *info)
+gf100_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 attrib = grctx->attrib_nr;
- const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max);
- const int s = 12;
- const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false);
int gpc, tpc;
u32 bo = 0;
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (attrib << 16));
+ gf100_grctx_patch_wr32(chan, 0x405830, (attrib << 16));
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) {
const u32 o = TPC_UNIT(gpc, tpc, 0x0520);
- mmio_skip(info, o, (attrib << 16) | ++bo);
- mmio_wr32(info, o, (attrib << 16) | --bo);
+
+ gf100_grctx_patch_wr32(chan, o, (attrib << 16) | bo);
bo += grctx->attrib_nr_max;
}
}
}
void
+gf100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size)
+{
+ gf100_grctx_patch_wr32(chan, 0x418810, 0x80000000 | addr >> 12);
+ gf100_grctx_patch_wr32(chan, 0x419848, 0x10000000 | addr >> 12);
+}
+
+u32
+gf100_grctx_generate_attrib_cb_size(struct gf100_gr *gr)
+{
+ const struct gf100_grctx_func *grctx = gr->func->grctx;
+
+ return 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max) * gr->tpc_total;
+}
+
+void
gf100_grctx_generate_unkn(struct gf100_gr *gr)
{
}
@@ -1361,8 +1339,9 @@ gf100_grctx_generate_floorsweep(struct gf100_gr *gr)
}
void
-gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
+gf100_grctx_generate_main(struct gf100_gr_chan *chan)
{
+ struct gf100_gr *gr = chan->gr;
struct nvkm_device *device = gr->base.engine.subdev.device;
const struct gf100_grctx_func *grctx = gr->func->grctx;
u32 idle_timeout;
@@ -1380,15 +1359,23 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
gf100_gr_mmio(gr, gr->sw_ctx);
}
+ if (gr->func->init_419bd8)
+ gr->func->init_419bd8(gr);
+ if (grctx->r419ea8)
+ grctx->r419ea8(gr);
+
gf100_gr_wait_idle(gr);
idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000);
- grctx->pagepool(info);
- grctx->bundle(info);
- grctx->attrib(info);
+ grctx->pagepool(chan, chan->pagepool->addr);
+ grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size);
+ grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr));
+ grctx->attrib(chan);
if (grctx->patch_ltc)
- grctx->patch_ltc(info);
+ grctx->patch_ltc(chan);
+ if (grctx->unknown_size)
+ grctx->unknown(chan, chan->unknown->addr, grctx->unknown_size);
grctx->unkn(gr);
gf100_grctx_generate_floorsweep(gr);
@@ -1396,12 +1383,23 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
gf100_gr_wait_idle(gr);
if (grctx->r400088) grctx->r400088(gr, false);
+
if (gr->bundle)
gf100_gr_icmd(gr, gr->bundle);
else
gf100_gr_icmd(gr, grctx->icmd);
- if (grctx->sw_veid_bundle_init)
+
+ if (gr->bundle_veid)
+ gf100_gr_icmd(gr, gr->bundle_veid);
+ else
gf100_gr_icmd(gr, grctx->sw_veid_bundle_init);
+
+ if (gr->bundle64)
+ gf100_gr_icmd(gr, gr->bundle64);
+ else
+ if (grctx->sw_bundle64_init)
+ gf100_gr_icmd(gr, grctx->sw_bundle64_init);
+
if (grctx->r400088) grctx->r400088(gr, true);
nvkm_wr32(device, 0x404154, idle_timeout);
@@ -1428,21 +1426,20 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
grctx->r408840(gr);
if (grctx->r419c0c)
grctx->r419c0c(gr);
+
+ gf100_gr_wait_idle(gr);
}
#define CB_RESERVED 0x80000
int
-gf100_grctx_generate(struct gf100_gr *gr)
+gf100_grctx_generate(struct gf100_gr *gr, struct gf100_gr_chan *chan, struct nvkm_gpuobj *inst)
{
const struct gf100_grctx_func *grctx = gr->func->grctx;
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_memory *inst = NULL;
struct nvkm_memory *data = NULL;
- struct nvkm_vmm *vmm = NULL;
struct nvkm_vma *ctx = NULL;
- struct gf100_grctx info;
int ret, i;
u64 addr;
@@ -1457,72 +1454,47 @@ gf100_grctx_generate(struct gf100_gr *gr)
grctx->unkn88c(gr, true);
/* Reset FECS. */
- nvkm_wr32(device, 0x409614, 0x00000070);
- nvkm_usec(device, 10, NVKM_DELAY);
- nvkm_mask(device, 0x409614, 0x00000700, 0x00000700);
- nvkm_usec(device, 10, NVKM_DELAY);
- nvkm_rd32(device, 0x409614);
+ gr->func->fecs.reset(gr);
if (grctx->unkn88c)
grctx->unkn88c(gr, false);
/* NV_PGRAPH_FE_PWR_MODE_AUTO. */
nvkm_wr32(device, 0x404170, 0x00000010);
+ nvkm_msec(device, 2000,
+ if (!(nvkm_rd32(device, 0x404170) & 0x00000010))
+ break;
+ );
/* Init SCC RAM. */
nvkm_wr32(device, 0x40802c, 0x00000001);
- /* Allocate memory to for a "channel", which we'll use to generate
- * the default context values.
- */
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
- 0x1000, 0x1000, true, &inst);
- if (ret)
- goto done;
-
- ret = nvkm_vmm_new(device, 0, 0, NULL, 0, NULL, "grctx", &vmm);
- if (ret)
- goto done;
-
- vmm->debug = subdev->debug;
-
- ret = nvkm_vmm_join(vmm, inst);
- if (ret)
- goto done;
-
+ /* Allocate memory to store context, and dummy global context buffers. */
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
CB_RESERVED + gr->size, 0, true, &data);
if (ret)
goto done;
- ret = nvkm_vmm_get(vmm, 0, nvkm_memory_size(data), &ctx);
+ ret = nvkm_vmm_get(chan->vmm, 0, nvkm_memory_size(data), &ctx);
if (ret)
goto done;
- ret = nvkm_memory_map(data, 0, vmm, ctx, NULL, 0);
+ ret = nvkm_memory_map(data, 0, chan->vmm, ctx, NULL, 0);
if (ret)
goto done;
-
/* Setup context pointer. */
nvkm_kmap(inst);
nvkm_wo32(inst, 0x0210, lower_32_bits(ctx->addr + CB_RESERVED) | 4);
nvkm_wo32(inst, 0x0214, upper_32_bits(ctx->addr + CB_RESERVED));
nvkm_done(inst);
- /* Setup default state for mmio list construction. */
- info.gr = gr;
- info.data = gr->mmio_data;
- info.mmio = gr->mmio_list;
- info.addr = ctx->addr;
- info.buffer_nr = 0;
-
/* Make channel current. */
- addr = nvkm_memory_addr(inst) >> 12;
+ addr = inst->addr >> 12;
if (gr->firmware) {
ret = gf100_gr_fecs_bind_pointer(gr, 0x80000000 | addr);
if (ret)
- goto done;
+ goto done_inst;
nvkm_kmap(data);
nvkm_wo32(data, 0x1c, 1);
@@ -1540,19 +1512,27 @@ gf100_grctx_generate(struct gf100_gr *gr)
);
}
- grctx->main(gr, &info);
+ grctx->main(chan);
- /* Trigger a context unload by unsetting the "next channel valid" bit
- * and faking a context switch interrupt.
- */
- nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000);
- nvkm_wr32(device, 0x409000, 0x00000100);
- if (nvkm_msec(device, 2000,
- if (!(nvkm_rd32(device, 0x409b00) & 0x80000000))
- break;
- ) < 0) {
- ret = -EBUSY;
- goto done;
+ if (!gr->firmware) {
+ /* Trigger a context unload by unsetting the "next channel valid" bit
+ * and faking a context switch interrupt.
+ */
+ nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000);
+ nvkm_wr32(device, 0x409000, 0x00000100);
+ if (nvkm_msec(device, 2000,
+ if (!(nvkm_rd32(device, 0x409b00) & 0x80000000))
+ break;
+ ) < 0) {
+ ret = -EBUSY;
+ goto done_inst;
+ }
+ } else {
+ ret = gf100_gr_fecs_wfi_golden_save(gr, 0x80000000 | addr);
+ if (ret)
+ goto done_inst;
+
+ nvkm_mask(device, 0x409b00, 0x80000000, 0x00000000);
}
gr->data = kmalloc(gr->size, GFP_KERNEL);
@@ -1566,12 +1546,14 @@ gf100_grctx_generate(struct gf100_gr *gr)
ret = -ENOMEM;
}
+done_inst:
+ nvkm_kmap(inst);
+ nvkm_wo32(inst, 0x0210, 0);
+ nvkm_wo32(inst, 0x0214, 0);
+ nvkm_done(inst);
done:
- nvkm_vmm_put(vmm, &ctx);
+ nvkm_vmm_put(chan->vmm, &ctx);
nvkm_memory_unref(&data);
- nvkm_vmm_part(vmm, inst);
- nvkm_vmm_unref(&vmm);
- nvkm_memory_unref(&inst);
return ret;
}
@@ -1590,6 +1572,8 @@ gf100_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf100_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
index 32bbddc0993e..00dbeda7e346 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
@@ -3,27 +3,12 @@
#define __NVKM_GRCTX_NVC0_H__
#include "gf100.h"
-struct gf100_grctx {
- struct gf100_gr *gr;
- struct gf100_gr_data *data;
- struct gf100_gr_mmio *mmio;
- int buffer_nr;
- u64 buffer[4];
- u64 addr;
-};
-
-int gf100_grctx_mmio_data(struct gf100_grctx *, u32 size, u32 align, bool priv);
-void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int);
-
-#define mmio_vram(a,b,c,d) gf100_grctx_mmio_data((a), (b), (c), (d))
-#define mmio_refn(a,b,c,d,e) gf100_grctx_mmio_item((a), (b), (c), (d), (e))
-#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1)
-#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1)
+void gf100_grctx_patch_wr32(struct gf100_gr_chan *, u32 addr, u32 data);
struct gf100_grctx_func {
void (*unkn88c)(struct gf100_gr *, bool on);
/* main context generation function */
- void (*main)(struct gf100_gr *, struct gf100_grctx *);
+ void (*main)(struct gf100_gr_chan *);
/* context-specific modify-on-first-load list generation function */
void (*unkn)(struct gf100_gr *);
/* mmio context data */
@@ -37,23 +22,29 @@ struct gf100_grctx_func {
const struct gf100_gr_pack *icmd;
const struct gf100_gr_pack *mthd;
const struct gf100_gr_pack *sw_veid_bundle_init;
+ const struct gf100_gr_pack *sw_bundle64_init;
/* bundle circular buffer */
- void (*bundle)(struct gf100_grctx *);
+ void (*bundle)(struct gf100_gr_chan *, u64 addr, u32 size);
u32 bundle_size;
u32 bundle_min_gpm_fifo_depth;
u32 bundle_token_limit;
/* pagepool */
- void (*pagepool)(struct gf100_grctx *);
+ void (*pagepool)(struct gf100_gr_chan *, u64 addr);
u32 pagepool_size;
/* attribute(/alpha) circular buffer */
- void (*attrib)(struct gf100_grctx *);
+ u32 (*attrib_cb_size)(struct gf100_gr *);
+ void (*attrib_cb)(struct gf100_gr_chan *, u64 addr, u32 size);
+ void (*attrib)(struct gf100_gr_chan *);
u32 attrib_nr_max;
u32 attrib_nr;
u32 alpha_nr_max;
u32 alpha_nr;
u32 gfxp_nr;
+ /* some other context buffer */
+ void (*unknown)(struct gf100_gr_chan *, u64 addr, u32 size);
+ u32 unknown_size;
/* other patch buffer stuff */
- void (*patch_ltc)(struct gf100_grctx *);
+ void (*patch_ltc)(struct gf100_gr_chan *);
/* floorsweeping */
void (*sm_id)(struct gf100_gr *, int gpc, int tpc, int sm);
void (*tpc_nr)(struct gf100_gr *, int gpc);
@@ -78,14 +69,17 @@ struct gf100_grctx_func {
void (*r419a3c)(struct gf100_gr *);
void (*r408840)(struct gf100_gr *);
void (*r419c0c)(struct gf100_gr *);
+ void (*r419ea8)(struct gf100_gr *);
};
extern const struct gf100_grctx_func gf100_grctx;
-int gf100_grctx_generate(struct gf100_gr *);
-void gf100_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *);
-void gf100_grctx_generate_bundle(struct gf100_grctx *);
-void gf100_grctx_generate_pagepool(struct gf100_grctx *);
-void gf100_grctx_generate_attrib(struct gf100_grctx *);
+int gf100_grctx_generate(struct gf100_gr *, struct gf100_gr_chan *, struct nvkm_gpuobj *inst);
+void gf100_grctx_generate_main(struct gf100_gr_chan *);
+void gf100_grctx_generate_pagepool(struct gf100_gr_chan *, u64);
+void gf100_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32);
+u32 gf100_grctx_generate_attrib_cb_size(struct gf100_gr *);
+void gf100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32);
+void gf100_grctx_generate_attrib(struct gf100_gr_chan *);
void gf100_grctx_generate_unkn(struct gf100_gr *);
void gf100_grctx_generate_floorsweep(struct gf100_gr *);
void gf100_grctx_generate_sm_id(struct gf100_gr *, int, int, int);
@@ -97,14 +91,14 @@ void gf100_grctx_generate_max_ways_evict(struct gf100_gr *);
void gf100_grctx_generate_r419cb8(struct gf100_gr *);
extern const struct gf100_grctx_func gf108_grctx;
-void gf108_grctx_generate_attrib(struct gf100_grctx *);
+void gf108_grctx_generate_attrib(struct gf100_gr_chan *);
void gf108_grctx_generate_unkn(struct gf100_gr *);
extern const struct gf100_grctx_func gf104_grctx;
extern const struct gf100_grctx_func gf110_grctx;
extern const struct gf100_grctx_func gf117_grctx;
-void gf117_grctx_generate_attrib(struct gf100_grctx *);
+void gf117_grctx_generate_attrib(struct gf100_gr_chan *);
void gf117_grctx_generate_rop_mapping(struct gf100_gr *);
void gf117_grctx_generate_dist_skip_table(struct gf100_gr *);
@@ -115,9 +109,9 @@ void gk104_grctx_generate_alpha_beta_tables(struct gf100_gr *);
void gk104_grctx_generate_gpc_tpc_nr(struct gf100_gr *);
extern const struct gf100_grctx_func gk20a_grctx;
-void gk104_grctx_generate_bundle(struct gf100_grctx *);
-void gk104_grctx_generate_pagepool(struct gf100_grctx *);
-void gk104_grctx_generate_patch_ltc(struct gf100_grctx *);
+void gk104_grctx_generate_pagepool(struct gf100_gr_chan *, u64);
+void gk104_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32);
+void gk104_grctx_generate_patch_ltc(struct gf100_gr_chan *);
void gk104_grctx_generate_unkn(struct gf100_gr *);
void gk104_grctx_generate_r418800(struct gf100_gr *);
@@ -128,9 +122,10 @@ extern const struct gf100_grctx_func gk110b_grctx;
extern const struct gf100_grctx_func gk208_grctx;
extern const struct gf100_grctx_func gm107_grctx;
-void gm107_grctx_generate_bundle(struct gf100_grctx *);
-void gm107_grctx_generate_pagepool(struct gf100_grctx *);
-void gm107_grctx_generate_attrib(struct gf100_grctx *);
+void gm107_grctx_generate_pagepool(struct gf100_gr_chan *, u64);
+void gm107_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32);
+void gm107_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32);
+void gm107_grctx_generate_attrib(struct gf100_gr_chan *);
void gm107_grctx_generate_sm_id(struct gf100_gr *, int, int, int);
extern const struct gf100_grctx_func gm200_grctx;
@@ -143,11 +138,13 @@ void gm200_grctx_generate_r419a3c(struct gf100_gr *);
extern const struct gf100_grctx_func gm20b_grctx;
extern const struct gf100_grctx_func gp100_grctx;
-void gp100_grctx_generate_pagepool(struct gf100_grctx *);
+void gp100_grctx_generate_pagepool(struct gf100_gr_chan *, u64);
+void gp100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32);
void gp100_grctx_generate_smid_config(struct gf100_gr *);
extern const struct gf100_grctx_func gp102_grctx;
-void gp102_grctx_generate_attrib(struct gf100_grctx *);
+u32 gp102_grctx_generate_attrib_cb_size(struct gf100_gr *);
+void gp102_grctx_generate_attrib(struct gf100_gr_chan *);
extern const struct gf100_grctx_func gp104_grctx;
@@ -158,11 +155,15 @@ extern const struct gf100_grctx_func gv100_grctx;
extern const struct gf100_grctx_func tu102_grctx;
void gv100_grctx_unkn88c(struct gf100_gr *, bool);
void gv100_grctx_generate_unkn(struct gf100_gr *);
-extern const struct gf100_gr_init gv100_grctx_init_sw_veid_bundle_init_0[];
-void gv100_grctx_generate_attrib(struct gf100_grctx *);
+void gv100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32);
+void gv100_grctx_generate_attrib(struct gf100_gr_chan *);
void gv100_grctx_generate_rop_mapping(struct gf100_gr *);
void gv100_grctx_generate_r400088(struct gf100_gr *, bool);
+void tu102_grctx_generate_unknown(struct gf100_gr_chan *, u64, u32);
+
+extern const struct gf100_grctx_func ga102_grctx;
+
/* context init value lists */
extern const struct gf100_gr_pack gf100_grctx_pack_icmd[];
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
index 7a0564b6e3c7..ba63a3b46518 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
@@ -94,6 +94,8 @@ gf104_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf100_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
index dda2c32e6232..0bc2eab6ad98 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
@@ -733,25 +733,20 @@ gf108_grctx_pack_tpc[] = {
******************************************************************************/
void
-gf108_grctx_generate_attrib(struct gf100_grctx *info)
+gf108_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 beta = grctx->attrib_nr;
- const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max);
- const int s = 12;
- const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false);
const int timeslice_mode = 1;
const int max_batches = 0xffff;
u32 bo = 0;
u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total;
int gpc, tpc;
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (beta << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+ gf100_grctx_patch_wr32(chan, 0x405830, (beta << 16) | alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) {
@@ -759,10 +754,10 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info)
const u32 b = beta;
const u32 t = timeslice_mode;
const u32 o = TPC_UNIT(gpc, tpc, 0x500);
- mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo);
- mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo);
+
+ gf100_grctx_patch_wr32(chan, o + 0x20, (t << 28) | (b << 16) | bo);
bo += grctx->attrib_nr_max;
- mmio_wr32(info, o + 0x44, (a << 16) | ao);
+ gf100_grctx_patch_wr32(chan, o + 0x44, (a << 16) | ao);
ao += grctx->alpha_nr_max;
}
}
@@ -795,6 +790,8 @@ gf108_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf108_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
index f5cca5e6a4f2..64b723b0afb5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
@@ -342,6 +342,8 @@ gf110_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf100_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
index 276c282d19aa..e34c5da2a9ff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
@@ -241,38 +241,34 @@ gf117_grctx_generate_rop_mapping(struct gf100_gr *gr)
}
void
-gf117_grctx_generate_attrib(struct gf100_grctx *info)
+gf117_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 beta = grctx->attrib_nr;
- const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max);
- const int s = 12;
- const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false);
const int timeslice_mode = 1;
const int max_batches = 0xffff;
u32 bo = 0;
u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total;
int gpc, ppc;
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (beta << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+ gf100_grctx_patch_wr32(chan, 0x405830, (beta << 16) | alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) {
const u32 a = alpha * gr->ppc_tpc_nr[gpc][ppc];
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);
+
+ gf100_grctx_patch_wr32(chan, o + 0xc0, (t << 28) | (b << 16) | bo);
bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, o + 0xe4, (a << 16) | ao);
+ gf100_grctx_patch_wr32(chan, o + 0xe4, (a << 16) | ao);
ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc];
}
}
@@ -294,6 +290,8 @@ gf117_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
index 0cfe46366af6..426ad1b8d426 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
@@ -510,6 +510,8 @@ gf119_grctx = {
.bundle_size = 0x1800,
.pagepool = gf100_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf108_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
index 304e9d268bad..94233d0119df 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
@@ -861,43 +861,33 @@ gk104_grctx_generate_r418800(struct gf100_gr *gr)
}
void
-gk104_grctx_generate_patch_ltc(struct gf100_grctx *info)
+gk104_grctx_generate_patch_ltc(struct gf100_gr_chan *chan)
{
- struct nvkm_device *device = info->gr->base.engine.subdev.device;
+ struct nvkm_device *device = chan->gr->base.engine.subdev.device;
u32 data0 = nvkm_rd32(device, 0x17e91c);
u32 data1 = nvkm_rd32(device, 0x17e920);
+
/*XXX: Figure out how to modify this correctly! */
- mmio_wr32(info, 0x17e91c, data0);
- mmio_wr32(info, 0x17e920, data1);
+ gf100_grctx_patch_wr32(chan, 0x17e91c, data0);
+ gf100_grctx_patch_wr32(chan, 0x17e920, data1);
}
void
-gk104_grctx_generate_bundle(struct gf100_grctx *info)
+gk104_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth,
- grctx->bundle_size / 0x20);
+ const struct gf100_grctx_func *grctx = chan->gr->func->grctx;
+ const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, size / 0x20);
const u32 token_limit = grctx->bundle_token_limit;
- const int s = 8;
- const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s));
- mmio_refn(info, 0x418808, 0x00000000, s, b);
- mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s));
- mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+
+ gf100_grctx_generate_bundle(chan, addr, size);
+ gf100_grctx_patch_wr32(chan, 0x4064c8, (state_limit << 16) | token_limit);
}
void
-gk104_grctx_generate_pagepool(struct gf100_grctx *info)
+gk104_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const int s = 8;
- const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
- mmio_wr32(info, 0x4064cc, 0x80000000);
+ gf100_grctx_generate_pagepool(chan, addr);
+ gf100_grctx_patch_wr32(chan, 0x4064cc, 0x80000000);
}
void
@@ -991,6 +981,8 @@ gk104_grctx = {
.bundle_token_limit = 0x600,
.pagepool = gk104_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
index 86547cfc38dc..4391458e1fb2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
@@ -838,6 +838,8 @@ gk110_grctx = {
.bundle_token_limit = 0x7c0,
.pagepool = gk104_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
index ebb947bd1446..7b9a34f9ec3c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
@@ -87,6 +87,8 @@ gk110b_grctx = {
.bundle_token_limit = 0x600,
.pagepool = gk104_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
index 4d40512b5c99..c78d07a8bb7d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
@@ -553,6 +553,8 @@ gk208_grctx = {
.bundle_token_limit = 0x200,
.pagepool = gk104_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x324,
.attrib_nr = 0x218,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
index c0d36bc601f9..ac5fdcb5cd3f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
@@ -25,8 +25,9 @@
#include <subdev/mc.h>
static void
-gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
+gk20a_grctx_generate_main(struct gf100_gr_chan *chan)
{
+ struct gf100_gr *gr = chan->gr;
struct nvkm_device *device = gr->base.engine.subdev.device;
const struct gf100_grctx_func *grctx = gr->func->grctx;
u32 idle_timeout;
@@ -38,7 +39,8 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000);
- grctx->attrib(info);
+ grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr));
+ grctx->attrib(chan);
grctx->unkn(gr);
@@ -60,8 +62,8 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
gf100_gr_wait_idle(gr);
gf100_gr_icmd(gr, gr->bundle);
- grctx->pagepool(info);
- grctx->bundle(info);
+ grctx->pagepool(chan, chan->pagepool->addr);
+ grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size);
}
const struct gf100_grctx_func
@@ -74,6 +76,8 @@ gk20a_grctx = {
.bundle_token_limit = 0x100,
.pagepool = gk104_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gf100_grctx_generate_attrib_cb,
.attrib = gf117_grctx_generate_attrib,
.attrib_nr_max = 0x240,
.attrib_nr = 0x240,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
index 0b3964e6b36e..beac66eb2a80 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
@@ -876,75 +876,70 @@ gm107_grctx_generate_r419e00(struct gf100_gr *gr)
}
void
-gm107_grctx_generate_bundle(struct gf100_grctx *info)
+gm107_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth,
- grctx->bundle_size / 0x20);
+ const struct gf100_grctx_func *grctx = chan->gr->func->grctx;
+ const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, size / 0x20);
const u32 token_limit = grctx->bundle_token_limit;
- const int s = 8;
- const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s));
- mmio_refn(info, 0x418e24, 0x00000000, s, b);
- mmio_wr32(info, 0x418e28, 0x80000000 | (grctx->bundle_size >> s));
- mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+
+ gf100_grctx_patch_wr32(chan, 0x408004, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408008, 0x80000000 | (size >> 8));
+ gf100_grctx_patch_wr32(chan, 0x418e24, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x418e28, 0x80000000 | (size >> 8));
+ gf100_grctx_patch_wr32(chan, 0x4064c8, (state_limit << 16) | token_limit);
}
void
-gm107_grctx_generate_pagepool(struct gf100_grctx *info)
+gm107_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const int s = 8;
- const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
- mmio_wr32(info, 0x4064cc, 0x80000000);
- mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
+ gk104_grctx_generate_pagepool(chan, addr);
+ gf100_grctx_patch_wr32(chan, 0x418e30, 0x80000000);
}
void
-gm107_grctx_generate_attrib(struct gf100_grctx *info)
+gm107_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 attrib = grctx->attrib_nr;
- const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max);
- const int s = 12;
- const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false);
const int max_batches = 0xffff;
u32 bo = 0;
u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total;
int gpc, ppc, n = 0;
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_refn(info, 0x419c2c, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (attrib << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+ gf100_grctx_patch_wr32(chan, 0x405830, (attrib << 16) | alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) {
const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc];
const u32 bs = attrib * gr->ppc_tpc_nr[gpc][ppc];
const u32 u = 0x418ea0 + (n * 0x04);
const u32 o = PPC_UNIT(gpc, ppc, 0);
+
if (!(gr->ppc_mask[gpc] & (1 << ppc)))
continue;
- mmio_wr32(info, o + 0xc0, bs);
- mmio_wr32(info, o + 0xf4, bo);
+
+ gf100_grctx_patch_wr32(chan, o + 0xc0, bs);
+ gf100_grctx_patch_wr32(chan, o + 0xf4, bo);
bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, o + 0xe4, as);
- mmio_wr32(info, o + 0xf8, ao);
+ gf100_grctx_patch_wr32(chan, o + 0xe4, as);
+ gf100_grctx_patch_wr32(chan, o + 0xf8, ao);
ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, u, ((bs / 3) << 16) | bs);
+ gf100_grctx_patch_wr32(chan, u, ((bs / 3) << 16) | bs);
}
}
}
+void
+gm107_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size)
+{
+ gf100_grctx_generate_attrib_cb(chan, addr, size);
+
+ gf100_grctx_patch_wr32(chan, 0x419c2c, 0x10000000 | addr >> 12);
+}
+
static void
gm107_grctx_generate_r406500(struct gf100_gr *gr)
{
@@ -978,6 +973,8 @@ gm107_grctx = {
.bundle_token_limit = 0x2c0,
.pagepool = gm107_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gm107_grctx_generate_attrib_cb,
.attrib = gm107_grctx_generate_attrib,
.attrib_nr_max = 0xff0,
.attrib_nr = 0xaa0,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c
index 013d05a0f0f6..175da8ac656c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c
@@ -87,7 +87,7 @@ gm200_grctx_generate_dist_skip_table(struct gf100_gr *gr)
int gpc, ppc, i;
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) {
u8 ppc_tpcs = gr->ppc_tpc_nr[gpc][ppc];
u8 ppc_tpcm = gr->ppc_tpc_mask[gpc][ppc];
while (ppc_tpcs-- > gr->ppc_tpc_min)
@@ -111,6 +111,8 @@ gm200_grctx = {
.bundle_token_limit = 0x780,
.pagepool = gm107_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gm107_grctx_generate_attrib_cb,
.attrib = gm107_grctx_generate_attrib,
.attrib_nr_max = 0x600,
.attrib_nr = 0x400,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c
index 6b92f8aa18a3..b8edccfada58 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c
@@ -22,8 +22,9 @@
#include "ctxgf100.h"
static void
-gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
+gm20b_grctx_generate_main(struct gf100_gr_chan *chan)
{
+ struct gf100_gr *gr = chan->gr;
struct nvkm_device *device = gr->base.engine.subdev.device;
const struct gf100_grctx_func *grctx = gr->func->grctx;
u32 idle_timeout;
@@ -35,7 +36,8 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000);
- grctx->attrib(info);
+ grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr));
+ grctx->attrib(chan);
grctx->unkn(gr);
@@ -63,8 +65,8 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
gf100_gr_wait_idle(gr);
gf100_gr_icmd(gr, gr->bundle);
- grctx->pagepool(info);
- grctx->bundle(info);
+ grctx->pagepool(chan, chan->pagepool->addr);
+ grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size);
}
const struct gf100_grctx_func
@@ -77,6 +79,8 @@ gm20b_grctx = {
.bundle_token_limit = 0x1c0,
.pagepool = gm107_grctx_generate_pagepool,
.pagepool_size = 0x8000,
+ .attrib_cb_size = gf100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gm107_grctx_generate_attrib_cb,
.attrib = gm107_grctx_generate_attrib,
.attrib_nr_max = 0x600,
.attrib_nr = 0x400,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c
index 0b3326262e12..8485aaeae7a9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c
@@ -30,66 +30,76 @@
******************************************************************************/
void
-gp100_grctx_generate_pagepool(struct gf100_grctx *info)
+gp100_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr)
{
- const struct gf100_grctx_func *grctx = info->gr->func->grctx;
- const int s = 8;
- const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x8007d800);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
+ gf100_grctx_patch_wr32(chan, 0x40800c, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408010, 0x8007d800);
+ gf100_grctx_patch_wr32(chan, 0x419004, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x419008, 0x00000000);
}
static void
-gp100_grctx_generate_attrib(struct gf100_grctx *info)
+gp100_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 attrib = grctx->attrib_nr;
- const int s = 12;
const int max_batches = 0xffff;
u32 size = grctx->alpha_nr_max * gr->tpc_total;
u32 ao = 0;
u32 bo = ao + size;
- int gpc, ppc, b, n = 0;
+ int gpc, ppc, n = 0;
- for (gpc = 0; gpc < gr->gpc_nr; gpc++)
- size += grctx->attrib_nr_max * gr->ppc_nr[gpc] * gr->ppc_tpc_max;
- size = ((size * 0x20) + 128) & ~127;
- b = mmio_vram(info, size, (1 << s), false);
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_refn(info, 0x419c2c, 0x10000000, s, b);
- mmio_refn(info, 0x419b00, 0x00000000, s, b);
- mmio_wr32(info, 0x419b04, 0x80000000 | size >> 7);
- mmio_wr32(info, 0x405830, attrib);
- mmio_wr32(info, 0x40585c, alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+ gf100_grctx_patch_wr32(chan, 0x405830, attrib);
+ gf100_grctx_patch_wr32(chan, 0x40585c, alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) {
const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc];
const u32 bs = attrib * gr->ppc_tpc_max;
const u32 u = 0x418ea0 + (n * 0x04);
const u32 o = PPC_UNIT(gpc, ppc, 0);
+
if (!(gr->ppc_mask[gpc] & (1 << ppc)))
continue;
- mmio_wr32(info, o + 0xc0, bs);
- mmio_wr32(info, o + 0xf4, bo);
- mmio_wr32(info, o + 0xf0, bs);
+
+ gf100_grctx_patch_wr32(chan, o + 0xc0, bs);
+ gf100_grctx_patch_wr32(chan, o + 0xf4, bo);
+ gf100_grctx_patch_wr32(chan, o + 0xf0, bs);
bo += grctx->attrib_nr_max * gr->ppc_tpc_max;
- mmio_wr32(info, o + 0xe4, as);
- mmio_wr32(info, o + 0xf8, ao);
+ gf100_grctx_patch_wr32(chan, o + 0xe4, as);
+ gf100_grctx_patch_wr32(chan, o + 0xf8, ao);
ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, u, bs);
+ gf100_grctx_patch_wr32(chan, u, bs);
}
}
- mmio_wr32(info, 0x418eec, 0x00000000);
- mmio_wr32(info, 0x41befc, 0x00000000);
+ gf100_grctx_patch_wr32(chan, 0x418eec, 0x00000000);
+ gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000000);
+}
+
+void
+gp100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size)
+{
+ gm107_grctx_generate_attrib_cb(chan, addr, size);
+
+ gf100_grctx_patch_wr32(chan, 0x419b00, 0x00000000 | addr >> 12);
+ gf100_grctx_patch_wr32(chan, 0x419b04, 0x80000000 | size >> 7);
+}
+
+static u32
+gp100_grctx_generate_attrib_cb_size(struct gf100_gr *gr)
+{
+ const struct gf100_grctx_func *grctx = gr->func->grctx;
+ u32 size = grctx->alpha_nr_max * gr->tpc_total;
+ int gpc;
+
+ for (gpc = 0; gpc < gr->gpc_nr; gpc++)
+ size += grctx->attrib_nr_max * gr->func->ppc_nr * gr->ppc_tpc_max;
+
+ return ((size * 0x20) + 128) & ~127;
}
void
@@ -123,6 +133,8 @@ gp100_grctx = {
.bundle_token_limit = 0x1080,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gp100_grctx_generate_attrib_cb_size,
+ .attrib_cb = gp100_grctx_generate_attrib_cb,
.attrib = gp100_grctx_generate_attrib,
.attrib_nr_max = 0x660,
.attrib_nr = 0x440,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c
index daee17bf7d0d..7537979a5492 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c
@@ -37,58 +37,62 @@ gp102_grctx_generate_r408840(struct gf100_gr *gr)
}
void
-gp102_grctx_generate_attrib(struct gf100_grctx *info)
+gp102_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 attrib = grctx->attrib_nr;
const u32 gfxp = grctx->gfxp_nr;
- const int s = 12;
const int max_batches = 0xffff;
u32 size = grctx->alpha_nr_max * gr->tpc_total;
u32 ao = 0;
u32 bo = ao + size;
- int gpc, ppc, b, n = 0;
+ int gpc, ppc, n = 0;
- for (gpc = 0; gpc < gr->gpc_nr; gpc++)
- size += grctx->gfxp_nr * gr->ppc_nr[gpc] * gr->ppc_tpc_max;
- size = ((size * 0x20) + 128) & ~127;
- b = mmio_vram(info, size, (1 << s), false);
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_refn(info, 0x419c2c, 0x10000000, s, b);
- mmio_refn(info, 0x419b00, 0x00000000, s, b);
- mmio_wr32(info, 0x419b04, 0x80000000 | size >> 7);
- mmio_wr32(info, 0x405830, attrib);
- mmio_wr32(info, 0x40585c, alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+ gf100_grctx_patch_wr32(chan, 0x405830, attrib);
+ gf100_grctx_patch_wr32(chan, 0x40585c, alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) {
const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc];
const u32 bs = attrib * gr->ppc_tpc_max;
const u32 gs = gfxp * gr->ppc_tpc_max;
const u32 u = 0x418ea0 + (n * 0x04);
const u32 o = PPC_UNIT(gpc, ppc, 0);
const u32 p = GPC_UNIT(gpc, 0xc44 + (ppc * 4));
+
if (!(gr->ppc_mask[gpc] & (1 << ppc)))
continue;
- mmio_wr32(info, o + 0xc0, gs);
- mmio_wr32(info, p, bs);
- mmio_wr32(info, o + 0xf4, bo);
- mmio_wr32(info, o + 0xf0, bs);
+
+ gf100_grctx_patch_wr32(chan, o + 0xc0, gs);
+ gf100_grctx_patch_wr32(chan, p, bs);
+ gf100_grctx_patch_wr32(chan, o + 0xf4, bo);
+ gf100_grctx_patch_wr32(chan, o + 0xf0, bs);
bo += gs;
- mmio_wr32(info, o + 0xe4, as);
- mmio_wr32(info, o + 0xf8, ao);
+ gf100_grctx_patch_wr32(chan, o + 0xe4, as);
+ gf100_grctx_patch_wr32(chan, o + 0xf8, ao);
ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, u, bs);
+ gf100_grctx_patch_wr32(chan, u, bs);
}
}
- mmio_wr32(info, 0x4181e4, 0x00000100);
- mmio_wr32(info, 0x41befc, 0x00000100);
+ gf100_grctx_patch_wr32(chan, 0x4181e4, 0x00000100);
+ gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000100);
+}
+
+u32
+gp102_grctx_generate_attrib_cb_size(struct gf100_gr *gr)
+{
+ const struct gf100_grctx_func *grctx = gr->func->grctx;
+ u32 size = grctx->alpha_nr_max * gr->tpc_total;
+ int gpc;
+
+ for (gpc = 0; gpc < gr->gpc_nr; gpc++)
+ size += grctx->gfxp_nr * gr->func->ppc_nr * gr->ppc_tpc_max;
+
+ return ((size * 0x20) + 127) & ~127;
}
const struct gf100_grctx_func
@@ -101,6 +105,8 @@ gp102_grctx = {
.bundle_token_limit = 0x900,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gp100_grctx_generate_attrib_cb,
.attrib = gp102_grctx_generate_attrib,
.attrib_nr_max = 0x4b0,
.attrib_nr = 0x320,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c
index 3b85e3d326b2..90b5f793e567 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c
@@ -31,6 +31,8 @@ gp104_grctx = {
.bundle_token_limit = 0x900,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gp100_grctx_generate_attrib_cb,
.attrib = gp102_grctx_generate_attrib,
.attrib_nr_max = 0x4b0,
.attrib_nr = 0x320,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c
index 5060c5ee5ce0..d191761a0471 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c
@@ -39,6 +39,8 @@ gp107_grctx = {
.bundle_token_limit = 0x300,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gp100_grctx_generate_attrib_cb,
.attrib = gp102_grctx_generate_attrib,
.attrib_nr_max = 0x15de,
.attrib_nr = 0x540,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c
index 39553d55d3f3..957ea9d6bad4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c
@@ -25,7 +25,7 @@
* PGRAPH context implementation
******************************************************************************/
-const struct gf100_gr_init
+static const struct gf100_gr_init
gv100_grctx_init_sw_veid_bundle_init_0[] = {
{ 0x00001000, 64, 0x00100000, 0x00000008 },
{ 0x00000941, 64, 0x00100000, 0x00000000 },
@@ -59,67 +59,70 @@ gv100_grctx_pack_sw_veid_bundle_init[] = {
};
void
-gv100_grctx_generate_attrib(struct gf100_grctx *info)
+gv100_grctx_generate_attrib(struct gf100_gr_chan *chan)
{
- struct gf100_gr *gr = info->gr;
+ struct gf100_gr *gr = chan->gr;
const struct gf100_grctx_func *grctx = gr->func->grctx;
const u32 alpha = grctx->alpha_nr;
const u32 attrib = grctx->attrib_nr;
const u32 gfxp = grctx->gfxp_nr;
- const int s = 12;
+ const int max_batches = 0xffff;
u32 size = grctx->alpha_nr_max * gr->tpc_total;
u32 ao = 0;
u32 bo = ao + size;
- int gpc, ppc, b, n = 0;
+ int gpc, ppc, n = 0;
- for (gpc = 0; gpc < gr->gpc_nr; gpc++)
- size += grctx->gfxp_nr * gr->ppc_nr[gpc] * gr->ppc_tpc_max;
- size = ((size * 0x20) + 127) & ~127;
- b = mmio_vram(info, size, (1 << s), false);
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_refn(info, 0x419c2c, 0x10000000, s, b);
- mmio_refn(info, 0x419e00, 0x00000000, s, b);
- mmio_wr32(info, 0x419e04, 0x80000000 | size >> 7);
- mmio_wr32(info, 0x405830, attrib);
- mmio_wr32(info, 0x40585c, alpha);
+ gf100_grctx_patch_wr32(chan, 0x405830, attrib);
+ gf100_grctx_patch_wr32(chan, 0x40585c, alpha);
+ gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches);
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) {
const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc];
const u32 bs = attrib * gr->ppc_tpc_max;
const u32 gs = gfxp * gr->ppc_tpc_max;
const u32 u = 0x418ea0 + (n * 0x04);
const u32 o = PPC_UNIT(gpc, ppc, 0);
+
if (!(gr->ppc_mask[gpc] & (1 << ppc)))
continue;
- mmio_wr32(info, o + 0xc0, gs);
- mmio_wr32(info, o + 0xf4, bo);
- mmio_wr32(info, o + 0xf0, bs);
+
+ gf100_grctx_patch_wr32(chan, o + 0xc0, gs);
+ gf100_grctx_patch_wr32(chan, o + 0xf4, bo);
+ gf100_grctx_patch_wr32(chan, o + 0xf0, bs);
bo += gs;
- mmio_wr32(info, o + 0xe4, as);
- mmio_wr32(info, o + 0xf8, ao);
+ gf100_grctx_patch_wr32(chan, o + 0xe4, as);
+ gf100_grctx_patch_wr32(chan, o + 0xf8, ao);
ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, u, bs);
+ gf100_grctx_patch_wr32(chan, u, bs);
}
}
- mmio_wr32(info, 0x4181e4, 0x00000100);
- mmio_wr32(info, 0x41befc, 0x00000100);
+ gf100_grctx_patch_wr32(chan, 0x4181e4, 0x00000100);
+ gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000100);
+}
+
+void
+gv100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size)
+{
+ gm107_grctx_generate_attrib_cb(chan, addr, size);
+
+ gf100_grctx_patch_wr32(chan, 0x419e00, 0x00000000 | addr >> 12);
+ gf100_grctx_patch_wr32(chan, 0x419e04, 0x80000000 | size >> 7);
}
void
gv100_grctx_generate_rop_mapping(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
+ const u32 mapregs = DIV_ROUND_UP(gr->func->gpc_nr * gr->func->tpc_nr, 6);
u32 data;
int i, j;
/* Pack tile map into register format. */
nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) |
gr->screen_tile_row_offset);
- for (i = 0; i < 11; i++) {
+ for (i = 0; i < mapregs; i++) {
for (data = 0, j = 0; j < 6; j++)
data |= (gr->tile[i * 6 + j] & 0x1f) << (j * 5);
nvkm_wr32(device, 0x418b08 + (i * 4), data);
@@ -157,6 +160,9 @@ static void
gv100_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc);
+
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm);
nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), sm);
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), sm);
@@ -198,6 +204,8 @@ gv100_grctx = {
.bundle_token_limit = 0x1680,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gv100_grctx_generate_attrib_cb,
.attrib = gv100_grctx_generate_attrib,
.attrib_nr_max = 0x6c0,
.attrib_nr = 0x480,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c
index 2299ca07d04a..542ab0c78be6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c
@@ -34,6 +34,9 @@ static void
tu102_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc);
+
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm);
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), sm);
}
@@ -47,42 +50,38 @@ tu102_grctx_init_unknown_bundle_init_0[] = {
};
static const struct gf100_gr_pack
-tu102_grctx_pack_sw_veid_bundle_init[] = {
- { gv100_grctx_init_sw_veid_bundle_init_0 },
- { tu102_grctx_init_unknown_bundle_init_0 },
+tu102_grctx_pack_sw_bundle64_init[] = {
+ { tu102_grctx_init_unknown_bundle_init_0, .type = 64 },
{}
};
-static void
-tu102_grctx_generate_attrib(struct gf100_grctx *info)
+void
+tu102_grctx_generate_unknown(struct gf100_gr_chan *chan, u64 addr, u32 size)
{
- const u64 size = 0x80000; /*XXX: educated guess */
- const int s = 8;
- const int b = mmio_vram(info, size, (1 << s), true);
-
- gv100_grctx_generate_attrib(info);
-
- mmio_refn(info, 0x408070, 0x00000000, s, b);
- mmio_wr32(info, 0x408074, size >> s); /*XXX: guess */
- mmio_refn(info, 0x419034, 0x00000000, s, b);
- mmio_wr32(info, 0x408078, 0x00000000);
+ gf100_grctx_patch_wr32(chan, 0x408070, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408074, size >> 8); /*XXX: guess */
+ gf100_grctx_patch_wr32(chan, 0x419034, addr >> 8);
+ gf100_grctx_patch_wr32(chan, 0x408078, 0x00000000);
}
const struct gf100_grctx_func
tu102_grctx = {
- .unkn88c = gv100_grctx_unkn88c,
.main = gf100_grctx_generate_main,
.unkn = gv100_grctx_generate_unkn,
- .sw_veid_bundle_init = tu102_grctx_pack_sw_veid_bundle_init,
+ .sw_bundle64_init = tu102_grctx_pack_sw_bundle64_init,
.bundle = gm107_grctx_generate_bundle,
.bundle_size = 0x3000,
.bundle_min_gpm_fifo_depth = 0x180,
.bundle_token_limit = 0xa80,
.pagepool = gp100_grctx_generate_pagepool,
.pagepool_size = 0x20000,
- .attrib = tu102_grctx_generate_attrib,
+ .attrib_cb_size = gp102_grctx_generate_attrib_cb_size,
+ .attrib_cb = gv100_grctx_generate_attrib_cb,
+ .attrib = gv100_grctx_generate_attrib,
.attrib_nr_max = 0x800,
.attrib_nr = 0x700,
+ .unknown_size = 0x80000,
+ .unknown = tu102_grctx_generate_unknown,
.alpha_nr_max = 0xc00,
.alpha_nr = 0x800,
.gfxp_nr = 0xfa8,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c
new file mode 100644
index 000000000000..a5b5ac2755a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2019 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "gf100.h"
+#include "ctxgf100.h"
+
+#include <core/firmware.h>
+#include <subdev/acr.h>
+#include <subdev/timer.h>
+#include <subdev/vfn.h>
+
+#include <nvfw/flcn.h>
+
+#include <nvif/class.h>
+
+static void
+ga102_gr_zbc_clear_color(struct gf100_gr *gr, int zbc)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+ u32 invalid[] = { 0, 0, 0, 0 }, *color;
+
+ if (gr->zbc_color[zbc].format)
+ color = gr->zbc_color[zbc].l2;
+ else
+ color = invalid;
+
+ nvkm_mask(device, 0x41bcb4, 0x0000001f, zbc);
+ nvkm_wr32(device, 0x41bcec, color[0]);
+ nvkm_wr32(device, 0x41bcf0, color[1]);
+ nvkm_wr32(device, 0x41bcf4, color[2]);
+ nvkm_wr32(device, 0x41bcf8, color[3]);
+}
+
+static const struct gf100_gr_func_zbc
+ga102_gr_zbc = {
+ .clear_color = ga102_gr_zbc_clear_color,
+ .clear_depth = gp100_gr_zbc_clear_depth,
+ .stencil_get = gp102_gr_zbc_stencil_get,
+ .clear_stencil = gp102_gr_zbc_clear_stencil,
+};
+
+static void
+ga102_gr_gpccs_reset(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x41a610, 0x00000000);
+ nvkm_msec(device, 1, NVKM_DELAY);
+ nvkm_wr32(device, 0x41a610, 0x00000001);
+}
+
+static const struct nvkm_acr_lsf_func
+ga102_gr_gpccs_acr = {
+ .flags = NVKM_ACR_LSF_FORCE_PRIV_LOAD,
+ .bl_entry = 0x3400,
+ .bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
+ .bld_write = gp108_gr_acr_bld_write,
+ .bld_patch = gp108_gr_acr_bld_patch,
+};
+
+static void
+ga102_gr_fecs_reset(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409614, 0x00000010);
+ nvkm_wr32(device, 0x41a614, 0x00000020);
+ nvkm_usec(device, 10, NVKM_DELAY);
+ nvkm_wr32(device, 0x409614, 0x00000110);
+ nvkm_wr32(device, 0x41a614, 0x00000a20);
+ nvkm_usec(device, 10, NVKM_DELAY);
+ nvkm_rd32(device, 0x409614);
+ nvkm_rd32(device, 0x41a614);
+}
+
+static const struct nvkm_acr_lsf_func
+ga102_gr_fecs_acr = {
+ .bl_entry = 0x7e00,
+ .bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
+ .bld_write = gp108_gr_acr_bld_write,
+ .bld_patch = gp108_gr_acr_bld_patch,
+};
+
+static void
+ga102_gr_init_rop_exceptions(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x41bcbc, 0x40000000);
+ nvkm_wr32(device, 0x41bc38, 0x40000000);
+ nvkm_wr32(device, 0x41ac94, nvkm_rd32(device, 0x502c94));
+}
+
+static void
+ga102_gr_init_40a790(struct gf100_gr *gr)
+{
+ nvkm_wr32(gr->base.engine.subdev.device, 0x40a790, 0xc0000000);
+}
+
+static void
+ga102_gr_init_gpc_mmu(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x418880, nvkm_rd32(device, 0x100c80) & 0xf8001fff);
+ nvkm_wr32(device, 0x418894, 0x00000000);
+
+ nvkm_wr32(device, 0x4188b4, nvkm_rd32(device, 0x100cc8));
+ nvkm_wr32(device, 0x4188b8, nvkm_rd32(device, 0x100ccc));
+ nvkm_wr32(device, 0x4188b0, nvkm_rd32(device, 0x100cc4));
+}
+
+static struct nvkm_intr *
+ga102_gr_oneinit_intr(struct gf100_gr *gr, enum nvkm_intr_type *pvector)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ *pvector = nvkm_rd32(device, 0x400154) & 0x00000fff;
+ return &device->vfn->intr;
+}
+
+static const struct gf100_gr_func
+ga102_gr = {
+ .oneinit_intr = ga102_gr_oneinit_intr,
+ .oneinit_tiles = gm200_gr_oneinit_tiles,
+ .oneinit_sm_id = gv100_gr_oneinit_sm_id,
+ .init = gf100_gr_init,
+ .init_419bd8 = gv100_gr_init_419bd8,
+ .init_gpc_mmu = ga102_gr_init_gpc_mmu,
+ .init_vsc_stream_master = gk104_gr_init_vsc_stream_master,
+ .init_zcull = tu102_gr_init_zcull,
+ .init_num_active_ltcs = gf100_gr_init_num_active_ltcs,
+ .init_swdx_pes_mask = gp102_gr_init_swdx_pes_mask,
+ .init_fs = tu102_gr_init_fs,
+ .init_fecs_exceptions = tu102_gr_init_fecs_exceptions,
+ .init_40a790 = ga102_gr_init_40a790,
+ .init_ds_hww_esr_2 = gm200_gr_init_ds_hww_esr_2,
+ .init_sked_hww_esr = gk104_gr_init_sked_hww_esr,
+ .init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
+ .init_504430 = gv100_gr_init_504430,
+ .init_shader_exceptions = gv100_gr_init_shader_exceptions,
+ .init_rop_exceptions = ga102_gr_init_rop_exceptions,
+ .init_4188a4 = gv100_gr_init_4188a4,
+ .trap_mp = gv100_gr_trap_mp,
+ .fecs.reset = ga102_gr_fecs_reset,
+ .gpccs.reset = ga102_gr_gpccs_reset,
+ .rops = gm200_gr_rops,
+ .gpc_nr = 7,
+ .tpc_nr = 6,
+ .ppc_nr = 3,
+ .grctx = &ga102_grctx,
+ .zbc = &ga102_gr_zbc,
+ .sclass = {
+ { -1, -1, FERMI_TWOD_A },
+ { -1, -1, KEPLER_INLINE_TO_MEMORY_B },
+ { -1, -1, AMPERE_B, &gf100_fermi },
+ { -1, -1, AMPERE_COMPUTE_B },
+ {}
+ }
+};
+
+MODULE_FIRMWARE("nvidia/ga102/gr/fecs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga102/gr/fecs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga102/gr/gpccs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga102/gr/gpccs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga102/gr/NET_img.bin");
+
+MODULE_FIRMWARE("nvidia/ga103/gr/fecs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga103/gr/fecs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga103/gr/gpccs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga103/gr/gpccs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga103/gr/NET_img.bin");
+
+MODULE_FIRMWARE("nvidia/ga104/gr/fecs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga104/gr/fecs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga104/gr/gpccs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga104/gr/gpccs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga104/gr/NET_img.bin");
+
+MODULE_FIRMWARE("nvidia/ga106/gr/fecs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga106/gr/fecs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga106/gr/gpccs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga106/gr/gpccs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga106/gr/NET_img.bin");
+
+MODULE_FIRMWARE("nvidia/ga107/gr/fecs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga107/gr/fecs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga107/gr/gpccs_bl.bin");
+MODULE_FIRMWARE("nvidia/ga107/gr/gpccs_sig.bin");
+MODULE_FIRMWARE("nvidia/ga107/gr/NET_img.bin");
+
+struct netlist_region {
+ u32 region_id;
+ u32 data_size;
+ u32 data_offset;
+};
+
+struct netlist_image_header {
+ u32 version;
+ u32 regions;
+};
+
+struct netlist_image {
+ struct netlist_image_header header;
+ struct netlist_region regions[];
+};
+
+struct netlist_av64 {
+ u32 addr;
+ u32 data_hi;
+ u32 data_lo;
+};
+
+static int
+ga102_gr_av64_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
+{
+ struct gf100_gr_init *init;
+ struct gf100_gr_pack *pack;
+ int nent;
+ int i;
+
+ nent = (blob->size / sizeof(struct netlist_av64));
+ pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1)));
+ if (!pack)
+ return -ENOMEM;
+
+ init = (void *)(pack + 2);
+ pack[0].init = init;
+ pack[0].type = 64;
+
+ for (i = 0; i < nent; i++) {
+ struct gf100_gr_init *ent = &init[i];
+ struct netlist_av64 *av = &((struct netlist_av64 *)blob->data)[i];
+
+ ent->addr = av->addr;
+ ent->data = ((u64)av->data_hi << 32) | av->data_lo;
+ ent->count = 1;
+ ent->pitch = 1;
+ }
+
+ *ppack = pack;
+ return 0;
+}
+
+static int
+ga102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif)
+{
+ struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+ const struct firmware *fw;
+ const struct netlist_image *net;
+ const struct netlist_region *fecs_inst = NULL;
+ const struct netlist_region *fecs_data = NULL;
+ const struct netlist_region *gpccs_inst = NULL;
+ const struct netlist_region *gpccs_data = NULL;
+ int ret, i;
+
+ ret = nvkm_firmware_get(subdev, "gr/NET_img", 0, &fw);
+ if (ret)
+ return ret;
+
+ net = (const void *)fw->data;
+ nvkm_debug(subdev, "netlist version %d, %d regions\n",
+ net->header.version, net->header.regions);
+
+ for (i = 0; i < net->header.regions; i++) {
+ const struct netlist_region *reg = &net->regions[i];
+ struct nvkm_blob blob = {
+ .data = (void *)fw->data + reg->data_offset,
+ .size = reg->data_size,
+ };
+
+ nvkm_debug(subdev, "\t%2d: %08x %08x\n",
+ reg->region_id, reg->data_offset, reg->data_size);
+
+ switch (reg->region_id) {
+ case 0: fecs_data = reg; break;
+ case 1: fecs_inst = reg; break;
+ case 2: gpccs_data = reg; break;
+ case 3: gpccs_inst = reg; break;
+ case 4: gk20a_gr_av_to_init(&blob, &gr->bundle); break;
+ case 5: gk20a_gr_aiv_to_init(&blob, &gr->sw_ctx); break;
+ case 7: gk20a_gr_av_to_method(&blob, &gr->method); break;
+ case 28: tu102_gr_av_to_init_veid(&blob, &gr->bundle_veid); break;
+ case 34: ga102_gr_av64_to_init(&blob, &gr->bundle64); break;
+ case 48: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx1); break;
+ case 49: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx2); break;
+ case 50: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx3); break;
+ case 51: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx4); break;
+ default:
+ break;
+ }
+ }
+
+ ret = nvkm_acr_lsfw_load_bl_sig_net(subdev, &gr->fecs.falcon, NVKM_ACR_LSF_FECS,
+ "gr/fecs_", ver, fwif->fecs,
+ fw->data + fecs_inst->data_offset,
+ fecs_inst->data_size,
+ fw->data + fecs_data->data_offset,
+ fecs_data->data_size);
+ if (ret)
+ return ret;
+
+ ret = nvkm_acr_lsfw_load_bl_sig_net(subdev, &gr->gpccs.falcon, NVKM_ACR_LSF_GPCCS,
+ "gr/gpccs_", ver, fwif->gpccs,
+ fw->data + gpccs_inst->data_offset,
+ gpccs_inst->data_size,
+ fw->data + gpccs_data->data_offset,
+ gpccs_data->data_size);
+ if (ret)
+ return ret;
+
+ gr->firmware = true;
+
+ nvkm_firmware_put(fw);
+ return 0;
+}
+
+static const struct gf100_gr_fwif
+ga102_gr_fwif[] = {
+ { 0, ga102_gr_load, &ga102_gr, &ga102_gr_fecs_acr, &ga102_gr_gpccs_acr },
+ { -1, gm200_gr_nofw },
+ {}
+};
+
+int
+ga102_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
+{
+ return gf100_gr_new_(ga102_gr_fwif, device, type, inst, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index f16eabf4f642..5f20079c3660 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -67,7 +67,7 @@ gf100_gr_zbc_color_get(struct gf100_gr *gr, int format,
struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc;
int zbc = -ENOSPC, i;
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ for (i = ltc->zbc_color_min; i <= ltc->zbc_color_max; i++) {
if (gr->zbc_color[i].format) {
if (gr->zbc_color[i].format != format)
continue;
@@ -114,7 +114,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format,
struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc;
int zbc = -ENOSPC, i;
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) {
if (gr->zbc_depth[i].format) {
if (gr->zbc_depth[i].format != format)
continue;
@@ -355,15 +355,14 @@ static void *
gf100_gr_chan_dtor(struct nvkm_object *object)
{
struct gf100_gr_chan *chan = gf100_gr_chan(object);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
- nvkm_vmm_put(chan->vmm, &chan->data[i].vma);
- nvkm_memory_unref(&chan->data[i].mem);
- }
nvkm_vmm_put(chan->vmm, &chan->mmio_vma);
nvkm_memory_unref(&chan->mmio);
+
+ nvkm_vmm_put(chan->vmm, &chan->attrib_cb);
+ nvkm_vmm_put(chan->vmm, &chan->unknown);
+ nvkm_vmm_put(chan->vmm, &chan->bundle_cb);
+ nvkm_vmm_put(chan->vmm, &chan->pagepool);
nvkm_vmm_unref(&chan->vmm);
return chan;
}
@@ -380,12 +379,10 @@ gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
struct nvkm_object **pobject)
{
struct gf100_gr *gr = gf100_gr(base);
- struct gf100_gr_data *data = gr->mmio_data;
- struct gf100_gr_mmio *mmio = gr->mmio_list;
struct gf100_gr_chan *chan;
struct gf100_vmm_map_v0 args = { .priv = 1 };
struct nvkm_device *device = gr->base.engine.subdev.device;
- int ret, i;
+ int ret;
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
return -ENOMEM;
@@ -394,63 +391,91 @@ gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
chan->vmm = nvkm_vmm_ref(fifoch->vmm);
*pobject = &chan->object;
- /* allocate memory for a "mmio list" buffer that's used by the HUB
- * fuc to modify some per-context register settings on first load
- * of the context.
- */
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100,
- false, &chan->mmio);
+ /* Map pagepool. */
+ ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->pagepool), &chan->pagepool);
if (ret)
return ret;
- ret = nvkm_vmm_get(fifoch->vmm, 12, 0x1000, &chan->mmio_vma);
+ ret = nvkm_memory_map(gr->pagepool, 0, chan->vmm, chan->pagepool, &args, sizeof(args));
if (ret)
return ret;
- ret = nvkm_memory_map(chan->mmio, 0, fifoch->vmm,
- chan->mmio_vma, &args, sizeof(args));
+ /* Map bundle circular buffer. */
+ ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->bundle_cb), &chan->bundle_cb);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_map(gr->bundle_cb, 0, chan->vmm, chan->bundle_cb, &args, sizeof(args));
+ if (ret)
+ return ret;
+
+ /* Map attribute circular buffer. */
+ ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->attrib_cb), &chan->attrib_cb);
if (ret)
return ret;
- /* allocate buffers referenced by mmio list */
- for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) {
- ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
- data->size, data->align, false,
- &chan->data[i].mem);
+ if (device->card_type < GP100) {
+ ret = nvkm_memory_map(gr->attrib_cb, 0, chan->vmm, chan->attrib_cb, NULL, 0);
if (ret)
return ret;
-
- ret = nvkm_vmm_get(fifoch->vmm, 12,
- nvkm_memory_size(chan->data[i].mem),
- &chan->data[i].vma);
+ } else {
+ ret = nvkm_memory_map(gr->attrib_cb, 0, chan->vmm, chan->attrib_cb,
+ &args, sizeof(args));;
if (ret)
return ret;
+ }
- args.priv = data->priv;
+ /* Map some context buffer of unknown purpose. */
+ if (gr->func->grctx->unknown_size) {
+ ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->unknown), &chan->unknown);
+ if (ret)
+ return ret;
- ret = nvkm_memory_map(chan->data[i].mem, 0, chan->vmm,
- chan->data[i].vma, &args, sizeof(args));
+ ret = nvkm_memory_map(gr->unknown, 0, chan->vmm, chan->unknown,
+ &args, sizeof(args));
if (ret)
return ret;
+ }
- data++;
+ /* Generate golden context image. */
+ mutex_lock(&gr->fecs.mutex);
+ if (gr->data == NULL) {
+ ret = gf100_grctx_generate(gr, chan, fifoch->inst);
+ if (ret) {
+ nvkm_error(&base->engine.subdev, "failed to construct context\n");
+ return ret;
+ }
}
+ mutex_unlock(&gr->fecs.mutex);
- /* finally, fill in the mmio list and point the context at it */
- nvkm_kmap(chan->mmio);
- for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) {
- u32 addr = mmio->addr;
- u32 data = mmio->data;
+ /* allocate memory for a "mmio list" buffer that's used by the HUB
+ * fuc to modify some per-context register settings on first load
+ * of the context.
+ */
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100,
+ false, &chan->mmio);
+ if (ret)
+ return ret;
- if (mmio->buffer >= 0) {
- u64 info = chan->data[mmio->buffer].vma->addr;
- data |= info >> mmio->shift;
- }
+ ret = nvkm_vmm_get(fifoch->vmm, 12, 0x1000, &chan->mmio_vma);
+ if (ret)
+ return ret;
- nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
- nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
- mmio++;
- }
+ ret = nvkm_memory_map(chan->mmio, 0, fifoch->vmm,
+ chan->mmio_vma, &args, sizeof(args));
+ if (ret)
+ return ret;
+
+ /* finally, fill in the mmio list and point the context at it */
+ nvkm_kmap(chan->mmio);
+ gr->func->grctx->pagepool(chan, chan->pagepool->addr);
+ gr->func->grctx->bundle(chan, chan->bundle_cb->addr, gr->func->grctx->bundle_size);
+ gr->func->grctx->attrib_cb(chan, chan->attrib_cb->addr, gr->func->grctx->attrib_cb_size(gr));
+ gr->func->grctx->attrib(chan);
+ if (gr->func->grctx->patch_ltc)
+ gr->func->grctx->patch_ltc(chan);
+ if (gr->func->grctx->unknown_size)
+ gr->func->grctx->unknown(chan, chan->unknown->addr, gr->func->grctx->unknown_size);
nvkm_done(chan->mmio);
return 0;
}
@@ -727,7 +752,7 @@ gf100_gr_fecs_ctrl_ctxsw(struct gf100_gr *gr, u32 mthd)
struct nvkm_device *device = gr->base.engine.subdev.device;
nvkm_wr32(device, 0x409804, 0xffffffff);
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x409500, 0xffffffff);
nvkm_wr32(device, 0x409504, mthd);
nvkm_msec(device, 2000,
@@ -771,12 +796,45 @@ gf100_gr_fecs_stop_ctxsw(struct nvkm_gr *base)
return ret;
}
+static int
+gf100_gr_fecs_halt_pipeline(struct gf100_gr *gr)
+{
+ int ret = 0;
+
+ if (gr->firmware) {
+ mutex_lock(&gr->fecs.mutex);
+ ret = gf100_gr_fecs_ctrl_ctxsw(gr, 0x04);
+ mutex_unlock(&gr->fecs.mutex);
+ }
+
+ return ret;
+}
+
+int
+gf100_gr_fecs_wfi_golden_save(struct gf100_gr *gr, u32 inst)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_mask(device, 0x409800, 0x00000003, 0x00000000);
+ nvkm_wr32(device, 0x409500, inst);
+ nvkm_wr32(device, 0x409504, 0x00000009);
+ nvkm_msec(device, 2000,
+ u32 stat = nvkm_rd32(device, 0x409800);
+ if (stat & 0x00000002)
+ return -EIO;
+ if (stat & 0x00000001)
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
int
gf100_gr_fecs_bind_pointer(struct gf100_gr *gr, u32 inst)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- nvkm_wr32(device, 0x409840, 0x00000030);
+ nvkm_mask(device, 0x409800, 0x00000030, 0x00000000);
nvkm_wr32(device, 0x409500, inst);
nvkm_wr32(device, 0x409504, 0x00000003);
nvkm_msec(device, 2000,
@@ -867,7 +925,7 @@ gf100_gr_fecs_discover_pm_image_size(struct gf100_gr *gr, u32 *psize)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x409500, 0x00000000);
nvkm_wr32(device, 0x409504, 0x00000025);
nvkm_msec(device, 2000,
@@ -883,7 +941,7 @@ gf100_gr_fecs_discover_zcull_image_size(struct gf100_gr *gr, u32 *psize)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x409500, 0x00000000);
nvkm_wr32(device, 0x409504, 0x00000016);
nvkm_msec(device, 2000,
@@ -899,7 +957,7 @@ gf100_gr_fecs_discover_image_size(struct gf100_gr *gr, u32 *psize)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x409500, 0x00000000);
nvkm_wr32(device, 0x409504, 0x00000010);
nvkm_msec(device, 2000,
@@ -915,7 +973,7 @@ gf100_gr_fecs_set_watchdog_timeout(struct gf100_gr *gr, u32 timeout)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x409500, timeout);
nvkm_wr32(device, 0x409504, 0x00000021);
}
@@ -955,7 +1013,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr)
const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc;
- int index, c = ltc->zbc_min, d = ltc->zbc_min, s = ltc->zbc_min;
+ int index, c = ltc->zbc_color_min, d = ltc->zbc_depth_min, s = ltc->zbc_depth_min;
if (!gr->zbc_color[0].format) {
gf100_gr_zbc_color_get(gr, 1, & zero[0], &zero[4]); c++;
@@ -971,13 +1029,13 @@ gf100_gr_zbc_init(struct gf100_gr *gr)
}
}
- for (index = c; index <= ltc->zbc_max; index++)
+ for (index = c; index <= ltc->zbc_color_max; index++)
gr->func->zbc->clear_color(gr, index);
- for (index = d; index <= ltc->zbc_max; index++)
+ for (index = d; index <= ltc->zbc_depth_max; index++)
gr->func->zbc->clear_depth(gr, index);
if (gr->func->zbc->clear_stencil) {
- for (index = s; index <= ltc->zbc_max; index++)
+ for (index = s; index <= ltc->zbc_depth_max; index++)
gr->func->zbc->clear_stencil(gr, index);
}
}
@@ -1003,7 +1061,7 @@ gf100_gr_wait_idle(struct gf100_gr *gr)
nvkm_rd32(device, 0x400700);
gr_enabled = nvkm_rd32(device, 0x200) & 0x1000;
- ctxsw_active = nvkm_rd32(device, 0x2640) & 0x8000;
+ ctxsw_active = nvkm_fifo_ctxsw_in_progress(&gr->base.engine);
gr_busy = nvkm_rd32(device, 0x40060c) & 0x1;
if (!gr_enabled || (!gr_busy && !ctxsw_active))
@@ -1039,7 +1097,7 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p)
struct nvkm_device *device = gr->base.engine.subdev.device;
const struct gf100_gr_pack *pack;
const struct gf100_gr_init *init;
- u32 data = 0;
+ u64 data = 0;
nvkm_wr32(device, 0x400208, 0x80000000);
@@ -1049,6 +1107,8 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p)
if ((pack == p && init == p->init) || data != init->data) {
nvkm_wr32(device, 0x400204, init->data);
+ if (pack->type == 64)
+ nvkm_wr32(device, 0x40020c, upper_32_bits(init->data));
data = init->data;
}
@@ -1542,13 +1602,13 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr)
}
}
-static void
-gf100_gr_intr(struct nvkm_gr *base)
+static irqreturn_t
+gf100_gr_intr(struct nvkm_inth *inth)
{
- struct gf100_gr *gr = gf100_gr(base);
+ struct gf100_gr *gr = container_of(inth, typeof(*gr), base.engine.subdev.inth);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
unsigned long flags;
u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff;
u32 stat = nvkm_rd32(device, 0x400100);
@@ -1561,10 +1621,10 @@ gf100_gr_intr(struct nvkm_gr *base)
const char *name = "unknown";
int chid = -1;
- chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags);
+ chan = nvkm_chan_get_inst(&gr->base.engine, (u64)inst << 12, &flags);
if (chan) {
- name = chan->object.client->name;
- chid = chan->chid;
+ name = chan->name;
+ chid = chan->id;
}
if (device->card_type < NV_E0 || subc < 4)
@@ -1631,7 +1691,8 @@ gf100_gr_intr(struct nvkm_gr *base)
}
nvkm_wr32(device, 0x400500, 0x00010001);
- nvkm_fifo_chan_put(device->fifo, flags, &chan);
+ nvkm_chan_put(&chan, flags);
+ return IRQ_HANDLED;
}
static void
@@ -1721,7 +1782,7 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
nvkm_mc_unk260(device, 1);
/* start both of them running */
- nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409800, 0x00000000);
nvkm_wr32(device, 0x41a10c, 0x00000000);
nvkm_wr32(device, 0x40910c, 0x00000000);
@@ -1763,15 +1824,6 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
return ret;
}
- /* Generate golden context image. */
- if (gr->data == NULL) {
- int ret = gf100_grctx_generate(gr);
- if (ret) {
- nvkm_error(subdev, "failed to construct context\n");
- return ret;
- }
- }
-
return 0;
}
@@ -1823,14 +1875,6 @@ gf100_gr_init_ctxctl_int(struct gf100_gr *gr)
}
gr->size = nvkm_rd32(device, 0x409804);
- if (gr->data == NULL) {
- int ret = gf100_grctx_generate(gr);
- if (ret) {
- nvkm_error(subdev, "failed to construct context\n");
- return ret;
- }
- }
-
return 0;
}
@@ -1847,10 +1891,11 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
return ret;
}
-void
+int
gf100_gr_oneinit_sm_id(struct gf100_gr *gr)
{
int tpc, gpc;
+
for (tpc = 0; tpc < gr->tpc_max; tpc++) {
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
if (tpc < gr->tpc_nr[gpc]) {
@@ -1860,6 +1905,8 @@ gf100_gr_oneinit_sm_id(struct gf100_gr *gr)
}
}
}
+
+ return 0;
}
void
@@ -1944,7 +1991,17 @@ gf100_gr_oneinit(struct nvkm_gr *base)
struct gf100_gr *gr = gf100_gr(base);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- int i, j;
+ struct nvkm_intr *intr = &device->mc->intr;
+ enum nvkm_intr_type intr_type = NVKM_INTR_SUBDEV;
+ int ret, i, j;
+
+ if (gr->func->oneinit_intr)
+ intr = gr->func->oneinit_intr(gr, &intr_type);
+
+ ret = nvkm_inth_add(intr, intr_type, NVKM_INTR_PRIO_NORMAL, &gr->base.engine.subdev,
+ gf100_gr_intr, &gr->base.engine.subdev.inth);
+ if (ret)
+ return ret;
nvkm_pmu_pgob(device->pmu, false);
@@ -1954,12 +2011,14 @@ gf100_gr_oneinit(struct nvkm_gr *base)
gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608));
gr->tpc_max = max(gr->tpc_max, gr->tpc_nr[i]);
gr->tpc_total += gr->tpc_nr[i];
- gr->ppc_nr[i] = gr->func->ppc_nr;
- for (j = 0; j < gr->ppc_nr[i]; j++) {
+ for (j = 0; j < gr->func->ppc_nr; j++) {
gr->ppc_tpc_mask[i][j] =
nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4)));
if (gr->ppc_tpc_mask[i][j] == 0)
continue;
+
+ gr->ppc_nr[i]++;
+
gr->ppc_mask[i] |= (1 << j);
gr->ppc_tpc_nr[i][j] = hweight8(gr->ppc_tpc_mask[i][j]);
if (gr->ppc_tpc_min == 0 ||
@@ -1968,12 +2027,37 @@ gf100_gr_oneinit(struct nvkm_gr *base)
if (gr->ppc_tpc_max < gr->ppc_tpc_nr[i][j])
gr->ppc_tpc_max = gr->ppc_tpc_nr[i][j];
}
+
+ gr->ppc_total += gr->ppc_nr[i];
+ }
+
+ /* Allocate global context buffers. */
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->pagepool_size,
+ 0x100, false, &gr->pagepool);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->bundle_size,
+ 0x100, false, &gr->bundle_cb);
+ if (ret)
+ return ret;
+
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->attrib_cb_size(gr),
+ 0x1000, false, &gr->attrib_cb);
+ if (ret)
+ return ret;
+
+ if (gr->func->grctx->unknown_size) {
+ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->unknown_size,
+ 0x100, false, &gr->unknown);
+ if (ret)
+ return ret;
}
memset(gr->tile, 0xff, sizeof(gr->tile));
gr->func->oneinit_tiles(gr);
- gr->func->oneinit_sm_id(gr);
- return 0;
+
+ return gr->func->oneinit_sm_id(gr);
}
static int
@@ -1983,7 +2067,7 @@ gf100_gr_init_(struct nvkm_gr *base)
struct nvkm_subdev *subdev = &base->engine.subdev;
struct nvkm_device *device = subdev->device;
bool reset = device->chipset == 0x137 || device->chipset == 0x138;
- u32 ret;
+ int ret;
/* On certain GP107/GP108 boards, we trigger a weird issue where
* GR will stop responding to PRI accesses after we've asked the
@@ -2019,7 +2103,12 @@ gf100_gr_init_(struct nvkm_gr *base)
if (ret)
return ret;
- return gr->func->init(gr);
+ ret = gr->func->init(gr);
+ if (ret)
+ return ret;
+
+ nvkm_inth_allow(&subdev->inth);
+ return 0;
}
static int
@@ -2027,6 +2116,9 @@ gf100_gr_fini(struct nvkm_gr *base, bool suspend)
{
struct gf100_gr *gr = gf100_gr(base);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+
+ nvkm_inth_block(&subdev->inth);
+
nvkm_falcon_put(&gr->gpccs.falcon, subdev);
nvkm_falcon_put(&gr->fecs.falcon, subdev);
return 0;
@@ -2039,6 +2131,11 @@ gf100_gr_dtor(struct nvkm_gr *base)
kfree(gr->data);
+ nvkm_memory_unref(&gr->unknown);
+ nvkm_memory_unref(&gr->attrib_cb);
+ nvkm_memory_unref(&gr->bundle_cb);
+ nvkm_memory_unref(&gr->pagepool);
+
nvkm_falcon_dtor(&gr->gpccs.falcon);
nvkm_falcon_dtor(&gr->fecs.falcon);
@@ -2047,81 +2144,27 @@ gf100_gr_dtor(struct nvkm_gr *base)
nvkm_blob_dtor(&gr->gpccs.inst);
nvkm_blob_dtor(&gr->gpccs.data);
+ vfree(gr->bundle64);
+ vfree(gr->bundle_veid);
vfree(gr->bundle);
vfree(gr->method);
vfree(gr->sw_ctx);
vfree(gr->sw_nonctx);
+ vfree(gr->sw_nonctx1);
+ vfree(gr->sw_nonctx2);
+ vfree(gr->sw_nonctx3);
+ vfree(gr->sw_nonctx4);
return gr;
}
-static const struct nvkm_gr_func
-gf100_gr_ = {
- .dtor = gf100_gr_dtor,
- .oneinit = gf100_gr_oneinit,
- .init = gf100_gr_init_,
- .fini = gf100_gr_fini,
- .intr = gf100_gr_intr,
- .units = gf100_gr_units,
- .chan_new = gf100_gr_chan_new,
- .object_get = gf100_gr_object_get,
- .chsw_load = gf100_gr_chsw_load,
- .ctxsw.pause = gf100_gr_fecs_stop_ctxsw,
- .ctxsw.resume = gf100_gr_fecs_start_ctxsw,
- .ctxsw.inst = gf100_gr_ctxsw_inst,
-};
-
static const struct nvkm_falcon_func
gf100_gr_flcn = {
- .fbif = 0x600,
.load_imem = nvkm_falcon_v1_load_imem,
.load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = nvkm_falcon_v1_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
.start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
};
-int
-gf100_gr_new_(const struct gf100_gr_fwif *fwif, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
-{
- struct gf100_gr *gr;
- int ret;
-
- if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
- return -ENOMEM;
- *pgr = &gr->base;
-
- ret = nvkm_gr_ctor(&gf100_gr_, device, type, inst, true, &gr->base);
- if (ret)
- return ret;
-
- fwif = nvkm_firmware_load(&gr->base.engine.subdev, fwif, "Gr", gr);
- if (IS_ERR(fwif))
- return PTR_ERR(fwif);
-
- gr->func = fwif->func;
-
- ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev,
- "fecs", 0x409000, &gr->fecs.falcon);
- if (ret)
- return ret;
-
- mutex_init(&gr->fecs.mutex);
-
- ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev,
- "gpccs", 0x41a000, &gr->gpccs.falcon);
- if (ret)
- return ret;
-
- return 0;
-}
-
void
gf100_gr_init_num_tpc_per_gpc(struct gf100_gr *gr, bool pd, bool ds)
{
@@ -2146,6 +2189,29 @@ gf100_gr_init_400054(struct gf100_gr *gr)
}
void
+gf100_gr_init_exception2(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x40011c, 0xffffffff);
+ nvkm_wr32(device, 0x400134, 0xffffffff);
+}
+
+void
+gf100_gr_init_rop_exceptions(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+ int rop;
+
+ for (rop = 0; rop < gr->rop_nr; rop++) {
+ nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000);
+ nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000);
+ nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+}
+
+void
gf100_gr_init_shader_exceptions(struct gf100_gr *gr, int gpc, int tpc)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
@@ -2252,21 +2318,47 @@ gf100_gr_init_vsc_stream_master(struct gf100_gr *gr)
nvkm_mask(device, TPC_UNIT(0, 0, 0x05c), 0x00000001, 0x00000001);
}
+static int
+gf100_gr_reset(struct nvkm_gr *base)
+{
+ struct nvkm_subdev *subdev = &base->engine.subdev;
+ struct nvkm_device *device = subdev->device;
+ struct gf100_gr *gr = gf100_gr(base);
+
+ nvkm_mask(device, 0x400500, 0x00000001, 0x00000000);
+
+ WARN_ON(gf100_gr_fecs_halt_pipeline(gr));
+
+ subdev->func->fini(subdev, false);
+ nvkm_mc_disable(device, subdev->type, subdev->inst);
+ if (gr->func->gpccs.reset)
+ gr->func->gpccs.reset(gr);
+
+ nvkm_mc_enable(device, subdev->type, subdev->inst);
+ return subdev->func->init(subdev);
+}
+
int
gf100_gr_init(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
- int gpc, tpc, rop;
+ int gpc, tpc;
- if (gr->func->init_419bd8)
- gr->func->init_419bd8(gr);
+ nvkm_mask(device, 0x400500, 0x00010001, 0x00000000);
gr->func->init_gpc_mmu(gr);
- if (gr->sw_nonctx)
+ if (gr->sw_nonctx1) {
+ gf100_gr_mmio(gr, gr->sw_nonctx1);
+ gf100_gr_mmio(gr, gr->sw_nonctx2);
+ gf100_gr_mmio(gr, gr->sw_nonctx3);
+ gf100_gr_mmio(gr, gr->sw_nonctx4);
+ } else
+ if (gr->sw_nonctx) {
gf100_gr_mmio(gr, gr->sw_nonctx);
- else
+ } else {
gf100_gr_mmio(gr, gr->func->mmio);
+ }
gf100_gr_wait_idle(gr);
@@ -2298,6 +2390,10 @@ gf100_gr_init(struct gf100_gr *gr)
nvkm_wr32(device, 0x400124, 0x00000002);
gr->func->init_fecs_exceptions(gr);
+
+ if (gr->func->init_40a790)
+ gr->func->init_40a790(gr);
+
if (gr->func->init_ds_hww_esr_2)
gr->func->init_ds_hww_esr_2(gr);
@@ -2346,19 +2442,14 @@ gf100_gr_init(struct gf100_gr *gr)
nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
}
- for (rop = 0; rop < gr->rop_nr; rop++) {
- nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000);
- nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000);
- nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff);
- nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
+ gr->func->init_rop_exceptions(gr);
nvkm_wr32(device, 0x400108, 0xffffffff);
nvkm_wr32(device, 0x400138, 0xffffffff);
nvkm_wr32(device, 0x400118, 0xffffffff);
nvkm_wr32(device, 0x400130, 0xffffffff);
- nvkm_wr32(device, 0x40011c, 0xffffffff);
- nvkm_wr32(device, 0x400134, 0xffffffff);
+ if (gr->func->init_exception2)
+ gr->func->init_exception2(gr);
if (gr->func->init_400054)
gr->func->init_400054(gr);
@@ -2371,6 +2462,18 @@ gf100_gr_init(struct gf100_gr *gr)
return gf100_gr_init_ctxctl(gr);
}
+void
+gf100_gr_fecs_reset(struct gf100_gr *gr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409614, 0x00000070);
+ nvkm_usec(device, 10, NVKM_DELAY);
+ nvkm_mask(device, 0x409614, 0x00000700, 0x00000700);
+ nvkm_usec(device, 10, NVKM_DELAY);
+ nvkm_rd32(device, 0x409614);
+}
+
#include "fuc/hubgf100.fuc3.h"
struct gf100_gr_ucode
@@ -2391,6 +2494,22 @@ gf100_gr_gpccs_ucode = {
.data.size = sizeof(gf100_grgpc_data),
};
+static const struct nvkm_gr_func
+gf100_gr_ = {
+ .dtor = gf100_gr_dtor,
+ .oneinit = gf100_gr_oneinit,
+ .init = gf100_gr_init_,
+ .fini = gf100_gr_fini,
+ .reset = gf100_gr_reset,
+ .units = gf100_gr_units,
+ .chan_new = gf100_gr_chan_new,
+ .object_get = gf100_gr_object_get,
+ .chsw_load = gf100_gr_chsw_load,
+ .ctxsw.pause = gf100_gr_fecs_stop_ctxsw,
+ .ctxsw.resume = gf100_gr_fecs_start_ctxsw,
+ .ctxsw.inst = gf100_gr_ctxsw_inst,
+};
+
static const struct gf100_gr_func
gf100_gr = {
.oneinit_tiles = gf100_gr_oneinit_tiles,
@@ -2406,10 +2525,13 @@ gf100_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf100_gr_pack_mmio,
.fecs.ucode = &gf100_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf100_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.grctx = &gf100_grctx,
@@ -2483,6 +2605,42 @@ gf100_gr_fwif[] = {
};
int
+gf100_gr_new_(const struct gf100_gr_fwif *fwif, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
+{
+ struct gf100_gr *gr;
+ int ret;
+
+ if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+ return -ENOMEM;
+ *pgr = &gr->base;
+
+ ret = nvkm_gr_ctor(&gf100_gr_, device, type, inst, true, &gr->base);
+ if (ret)
+ return ret;
+
+ fwif = nvkm_firmware_load(&gr->base.engine.subdev, fwif, "Gr", gr);
+ if (IS_ERR(fwif))
+ return PTR_ERR(fwif);
+
+ gr->func = fwif->func;
+
+ ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev,
+ "fecs", 0x409000, &gr->fecs.falcon);
+ if (ret)
+ return ret;
+
+ mutex_init(&gr->fecs.mutex);
+
+ ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev,
+ "gpccs", 0x41a000, &gr->gpccs.falcon);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int
gf100_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)
{
return gf100_gr_new_(gf100_gr_fwif, device, type, inst, pgr);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
index c0038f906135..94ca7ac16acf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -44,19 +44,6 @@ struct nvkm_acr_lsfw;
#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
-struct gf100_gr_data {
- u32 size;
- u32 align;
- bool priv;
-};
-
-struct gf100_gr_mmio {
- u32 addr;
- u32 data;
- u32 shift;
- int buffer;
-};
-
struct gf100_gr_zbc_color {
u32 format;
u32 ds[4];
@@ -101,13 +88,19 @@ struct gf100_gr {
* using hardcoded arrays. To be allocated with vzalloc().
*/
struct gf100_gr_pack *sw_nonctx;
+ struct gf100_gr_pack *sw_nonctx1;
+ struct gf100_gr_pack *sw_nonctx2;
+ struct gf100_gr_pack *sw_nonctx3;
+ struct gf100_gr_pack *sw_nonctx4;
struct gf100_gr_pack *sw_ctx;
struct gf100_gr_pack *bundle;
+ struct gf100_gr_pack *bundle_veid;
+ struct gf100_gr_pack *bundle64;
struct gf100_gr_pack *method;
- struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT];
- struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
- struct gf100_gr_zbc_stencil zbc_stencil[NVKM_LTC_MAX_ZBC_CNT];
+ struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_COLOR_CNT];
+ struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
+ struct gf100_gr_zbc_stencil zbc_stencil[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
u8 rop_nr;
u8 gpc_nr;
@@ -120,6 +113,12 @@ struct gf100_gr {
u8 ppc_tpc_nr[GPC_MAX][4];
u8 ppc_tpc_min;
u8 ppc_tpc_max;
+ u8 ppc_total;
+
+ struct nvkm_memory *pagepool;
+ struct nvkm_memory *bundle_cb;
+ struct nvkm_memory *attrib_cb;
+ struct nvkm_memory *unknown;
u8 screen_tile_row_offset;
u8 tile[TPC_MAX];
@@ -130,8 +129,6 @@ struct gf100_gr {
} sm[TPC_MAX];
u8 sm_nr;
- struct gf100_gr_data mmio_data[4];
- struct gf100_gr_mmio mmio_list[4096/8];
u32 size;
u32 *data;
u32 size_zcull;
@@ -139,6 +136,7 @@ struct gf100_gr {
};
int gf100_gr_fecs_bind_pointer(struct gf100_gr *, u32 inst);
+int gf100_gr_fecs_wfi_golden_save(struct gf100_gr *, u32 inst);
struct gf100_gr_func_zbc {
void (*clear_color)(struct gf100_gr *, int zbc);
@@ -149,8 +147,9 @@ struct gf100_gr_func_zbc {
};
struct gf100_gr_func {
+ struct nvkm_intr *(*oneinit_intr)(struct gf100_gr *, enum nvkm_intr_type *);
void (*oneinit_tiles)(struct gf100_gr *);
- void (*oneinit_sm_id)(struct gf100_gr *);
+ int (*oneinit_sm_id)(struct gf100_gr *);
int (*init)(struct gf100_gr *);
void (*init_419bd8)(struct gf100_gr *);
void (*init_gpc_mmu)(struct gf100_gr *);
@@ -164,6 +163,7 @@ struct gf100_gr_func {
void (*init_swdx_pes_mask)(struct gf100_gr *);
void (*init_fs)(struct gf100_gr *);
void (*init_fecs_exceptions)(struct gf100_gr *);
+ void (*init_40a790)(struct gf100_gr *);
void (*init_ds_hww_esr_2)(struct gf100_gr *);
void (*init_40601c)(struct gf100_gr *);
void (*init_sked_hww_esr)(struct gf100_gr *);
@@ -174,6 +174,8 @@ struct gf100_gr_func {
void (*init_tex_hww_esr)(struct gf100_gr *, int gpc, int tpc);
void (*init_504430)(struct gf100_gr *, int gpc, int tpc);
void (*init_shader_exceptions)(struct gf100_gr *, int gpc, int tpc);
+ void (*init_rop_exceptions)(struct gf100_gr *);
+ void (*init_exception2)(struct gf100_gr *);
void (*init_400054)(struct gf100_gr *);
void (*init_4188a4)(struct gf100_gr *);
void (*trap_mp)(struct gf100_gr *, int gpc, int tpc);
@@ -181,9 +183,11 @@ struct gf100_gr_func {
const struct gf100_gr_pack *mmio;
struct {
struct gf100_gr_ucode *ucode;
+ void (*reset)(struct gf100_gr *);
} fecs;
struct {
struct gf100_gr_ucode *ucode;
+ void (*reset)(struct gf100_gr *);
} gpccs;
int (*rops)(struct gf100_gr *);
int gpc_nr;
@@ -197,7 +201,7 @@ struct gf100_gr_func {
int gf100_gr_rops(struct gf100_gr *);
void gf100_gr_oneinit_tiles(struct gf100_gr *);
-void gf100_gr_oneinit_sm_id(struct gf100_gr *);
+int gf100_gr_oneinit_sm_id(struct gf100_gr *);
int gf100_gr_init(struct gf100_gr *);
void gf100_gr_init_vsc_stream_master(struct gf100_gr *);
void gf100_gr_init_zcull(struct gf100_gr *);
@@ -208,9 +212,12 @@ void gf100_gr_init_419cc0(struct gf100_gr *);
void gf100_gr_init_419eb4(struct gf100_gr *);
void gf100_gr_init_tex_hww_esr(struct gf100_gr *, int, int);
void gf100_gr_init_shader_exceptions(struct gf100_gr *, int, int);
+void gf100_gr_init_rop_exceptions(struct gf100_gr *);
+void gf100_gr_init_exception2(struct gf100_gr *);
void gf100_gr_init_400054(struct gf100_gr *);
void gf100_gr_init_num_tpc_per_gpc(struct gf100_gr *, bool, bool);
extern const struct gf100_gr_func_zbc gf100_gr_zbc;
+void gf100_gr_fecs_reset(struct gf100_gr *);
void gf117_gr_init_zcull(struct gf100_gr *);
@@ -226,9 +233,13 @@ void gm107_gr_init_shader_exceptions(struct gf100_gr *, int, int);
void gm107_gr_init_400054(struct gf100_gr *);
int gk20a_gr_init(struct gf100_gr *);
+int gk20a_gr_av_to_init_(struct nvkm_blob *, u8 count, u32 pitch, struct gf100_gr_pack **);
+int gk20a_gr_av_to_init(struct nvkm_blob *, struct gf100_gr_pack **);
+int gk20a_gr_aiv_to_init(struct nvkm_blob *, struct gf100_gr_pack **);
+int gk20a_gr_av_to_method(struct nvkm_blob *, struct gf100_gr_pack **);
void gm200_gr_oneinit_tiles(struct gf100_gr *);
-void gm200_gr_oneinit_sm_id(struct gf100_gr *);
+int gm200_gr_oneinit_sm_id(struct gf100_gr *);
int gm200_gr_rops(struct gf100_gr *);
void gm200_gr_init_num_active_ltcs(struct gf100_gr *);
void gm200_gr_init_ds_hww_esr_2(struct gf100_gr *);
@@ -242,14 +253,24 @@ extern const struct gf100_gr_func_zbc gp100_gr_zbc;
void gp102_gr_init_swdx_pes_mask(struct gf100_gr *);
extern const struct gf100_gr_func_zbc gp102_gr_zbc;
+int gp102_gr_zbc_stencil_get(struct gf100_gr *, int, const u32, const u32);
+void gp102_gr_zbc_clear_stencil(struct gf100_gr *, int);
extern const struct gf100_gr_func gp107_gr;
+int gv100_gr_oneinit_sm_id(struct gf100_gr *);
+u32 gv100_gr_nonpes_aware_tpc(struct gf100_gr *gr, u32 gpc, u32 tpc);
void gv100_gr_init_419bd8(struct gf100_gr *);
void gv100_gr_init_504430(struct gf100_gr *, int, int);
void gv100_gr_init_shader_exceptions(struct gf100_gr *, int, int);
+void gv100_gr_init_4188a4(struct gf100_gr *);
void gv100_gr_trap_mp(struct gf100_gr *, int, int);
+int tu102_gr_av_to_init_veid(struct nvkm_blob *, struct gf100_gr_pack **);
+void tu102_gr_init_zcull(struct gf100_gr *);
+void tu102_gr_init_fs(struct gf100_gr *);
+void tu102_gr_init_fecs_exceptions(struct gf100_gr *);
+
#define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object)
#include <core/object.h>
@@ -258,14 +279,14 @@ struct gf100_gr_chan {
struct gf100_gr *gr;
struct nvkm_vmm *vmm;
+ struct nvkm_vma *pagepool;
+ struct nvkm_vma *bundle_cb;
+ struct nvkm_vma *attrib_cb;
+ struct nvkm_vma *unknown;
+
struct nvkm_memory *mmio;
struct nvkm_vma *mmio_vma;
int mmio_nr;
-
- struct {
- struct nvkm_memory *mem;
- struct nvkm_vma *vma;
- } data[4];
};
void gf100_gr_ctxctl_debug(struct gf100_gr *);
@@ -279,7 +300,7 @@ struct gf100_gr_init {
u32 addr;
u8 count;
u32 pitch;
- u32 data;
+ u64 data;
};
struct gf100_gr_pack {
@@ -403,6 +424,9 @@ int gf100_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *);
int gf100_gr_nofw(struct gf100_gr *, int, const struct gf100_gr_fwif *);
int gk20a_gr_load_sw(struct gf100_gr *, const char *path, int ver);
+int gk20a_gr_load_net(struct gf100_gr *, const char *, const char *, int,
+ int (*)(struct nvkm_blob *, struct gf100_gr_pack **),
+ struct gf100_gr_pack **);
int gm200_gr_nofw(struct gf100_gr *, int, const struct gf100_gr_fwif *);
int gm200_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *);
@@ -415,6 +439,8 @@ void gm20b_gr_acr_bld_patch(struct nvkm_acr *, u32, s64);
extern const struct nvkm_acr_lsf_func gp108_gr_gpccs_acr;
extern const struct nvkm_acr_lsf_func gp108_gr_fecs_acr;
+void gp108_gr_acr_bld_write(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *);
+void gp108_gr_acr_bld_patch(struct nvkm_acr *, u32, s64);
int gf100_gr_new_(const struct gf100_gr_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_gr **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
index 3acd99c306f2..63bd29c22fe1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
@@ -127,10 +127,13 @@ gf104_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf104_gr_pack_mmio,
.fecs.ucode = &gf100_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf100_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.grctx = &gf104_grctx,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
index ab3760e804b8..495a844f925f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
@@ -125,10 +125,13 @@ gf108_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf108_gr_pack_mmio,
.fecs.ucode = &gf100_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf100_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.grctx = &gf108_grctx,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
index 616e2def1865..70fad235d161 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
@@ -99,10 +99,13 @@ gf110_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf110_gr_pack_mmio,
.fecs.ucode = &gf100_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf100_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.grctx = &gf110_grctx,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
index 669e7536970e..f12728248048 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
@@ -125,7 +125,9 @@ gf117_gr_init_zcull(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
- const u8 tile_nr = ALIGN(gr->tpc_total, 32);
+ /*TODO: fill in litter vals for gf117-gm2xx */
+ const u8 tile_nr = !gr->func->gpc_nr ? ALIGN(gr->tpc_total, 32) :
+ (gr->func->gpc_nr * gr->func->tpc_nr);
u8 bank[GPC_MAX] = {}, gpc, i, j;
u32 data;
@@ -163,10 +165,13 @@ gf117_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf117_gr_pack_mmio,
.fecs.ucode = &gf117_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf117_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 1,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
index 5b09bda8110c..75ceb514c06e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
@@ -190,10 +190,13 @@ gf119_gr = {
.init_419eb4 = gf100_gr_init_419eb4,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gf119_gr_pack_mmio,
.fecs.ucode = &gf100_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gf100_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.grctx = &gf119_grctx,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
index b680eaa0f350..e53ade24ad23 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
@@ -418,7 +418,7 @@ gk104_gr_init_ppc_exceptions(struct gf100_gr *gr)
int gpc, ppc;
for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
- for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) {
+ for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) {
if (!(gr->ppc_mask[gpc] & (1 << ppc)))
continue;
nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
@@ -470,10 +470,13 @@ gk104_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gk104_gr_pack_mmio,
.fecs.ucode = &gk104_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gk104_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 1,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
index 103e06a77e65..c7e1c5dbc6a9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
@@ -366,10 +366,13 @@ gk110_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gk110_gr_pack_mmio,
.fecs.ucode = &gk110_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gk110_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 2,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
index 034d0b11a17d..458abae571bf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
@@ -118,10 +118,13 @@ gk110b_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gk110b_gr_pack_mmio,
.fecs.ucode = &gk110_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gk110_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 2,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
index 116d682f9f96..d3f6b65c21d2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
@@ -176,10 +176,13 @@ gk208_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_shader_exceptions = gf100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gf100_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gk208_gr_pack_mmio,
.fecs.ucode = &gk208_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gk208_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 1,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
index be0b2cefd8e8..035ea213f543 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
@@ -33,47 +33,40 @@ struct gk20a_fw_av
u32 data;
};
-static int
-gk20a_gr_av_to_init(struct gf100_gr *gr, const char *path, const char *name,
- int ver, struct gf100_gr_pack **ppack)
+int
+gk20a_gr_av_to_init_(struct nvkm_blob *blob, u8 count, u32 pitch, struct gf100_gr_pack **ppack)
{
- struct nvkm_subdev *subdev = &gr->base.engine.subdev;
- struct nvkm_blob blob;
struct gf100_gr_init *init;
struct gf100_gr_pack *pack;
int nent;
- int ret;
int i;
- ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob);
- if (ret)
- return ret;
-
- nent = (blob.size / sizeof(struct gk20a_fw_av));
+ nent = (blob->size / sizeof(struct gk20a_fw_av));
pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1)));
- if (!pack) {
- ret = -ENOMEM;
- goto end;
- }
+ if (!pack)
+ return -ENOMEM;
init = (void *)(pack + 2);
pack[0].init = init;
for (i = 0; i < nent; i++) {
struct gf100_gr_init *ent = &init[i];
- struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob.data)[i];
+ struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob->data)[i];
ent->addr = av->addr;
ent->data = av->data;
- ent->count = 1;
- ent->pitch = 1;
+ ent->count = ((ent->addr & 0xffff) != 0xe100) ? count : 1;
+ ent->pitch = pitch;
}
*ppack = pack;
+ return 0;
+}
-end:
- nvkm_blob_dtor(&blob);
- return ret;
+int
+gk20a_gr_av_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
+{
+ return gk20a_gr_av_to_init_(blob, 1, 1, ppack);
}
struct gk20a_fw_aiv
@@ -83,35 +76,25 @@ struct gk20a_fw_aiv
u32 data;
};
-static int
-gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *path, const char *name,
- int ver, struct gf100_gr_pack **ppack)
+int
+gk20a_gr_aiv_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
{
- struct nvkm_subdev *subdev = &gr->base.engine.subdev;
- struct nvkm_blob blob;
struct gf100_gr_init *init;
struct gf100_gr_pack *pack;
int nent;
- int ret;
int i;
- ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob);
- if (ret)
- return ret;
-
- nent = (blob.size / sizeof(struct gk20a_fw_aiv));
+ nent = (blob->size / sizeof(struct gk20a_fw_aiv));
pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1)));
- if (!pack) {
- ret = -ENOMEM;
- goto end;
- }
+ if (!pack)
+ return -ENOMEM;
init = (void *)(pack + 2);
pack[0].init = init;
for (i = 0; i < nent; i++) {
struct gf100_gr_init *ent = &init[i];
- struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)blob.data)[i];
+ struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)blob->data)[i];
ent->addr = av->addr;
ent->data = av->data;
@@ -120,44 +103,30 @@ gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *path, const char *name,
}
*ppack = pack;
-
-end:
- nvkm_blob_dtor(&blob);
- return ret;
+ return 0;
}
-static int
-gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name,
- int ver, struct gf100_gr_pack **ppack)
+int
+gk20a_gr_av_to_method(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
{
- struct nvkm_subdev *subdev = &gr->base.engine.subdev;
- struct nvkm_blob blob;
struct gf100_gr_init *init;
struct gf100_gr_pack *pack;
/* We don't suppose we will initialize more than 16 classes here... */
static const unsigned int max_classes = 16;
u32 classidx = 0, prevclass = 0;
int nent;
- int ret;
int i;
- ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob);
- if (ret)
- return ret;
-
- nent = (blob.size / sizeof(struct gk20a_fw_av));
-
+ nent = (blob->size / sizeof(struct gk20a_fw_av));
pack = vzalloc((sizeof(*pack) * (max_classes + 1)) +
(sizeof(*init) * (nent + max_classes + 1)));
- if (!pack) {
- ret = -ENOMEM;
- goto end;
- }
+ if (!pack)
+ return -ENOMEM;
init = (void *)(pack + max_classes + 1);
for (i = 0; i < nent; i++, init++) {
- struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob.data)[i];
+ struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob->data)[i];
u32 class = av->addr & 0xffff;
u32 addr = (av->addr & 0xffff0000) >> 14;
@@ -169,8 +138,7 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name,
prevclass = class;
if (++classidx >= max_classes) {
vfree(pack);
- ret = -ENOSPC;
- goto end;
+ return -ENOSPC;
}
}
@@ -181,10 +149,7 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name,
}
*ppack = pack;
-
-end:
- nvkm_blob_dtor(&blob);
- return ret;
+ return 0;
}
static int
@@ -294,6 +259,7 @@ gk20a_gr = {
.init_rop_active_fbps = gk104_gr_init_rop_active_fbps,
.trap_mp = gf100_gr_trap_mp,
.set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gf100_gr_rops,
.ppc_nr = 1,
.grctx = &gk20a_grctx,
@@ -308,12 +274,29 @@ gk20a_gr = {
};
int
+gk20a_gr_load_net(struct gf100_gr *gr, const char *path, const char *name, int ver,
+ int (*load)(struct nvkm_blob *, struct gf100_gr_pack **),
+ struct gf100_gr_pack **ppack)
+{
+ struct nvkm_blob blob;
+ int ret;
+
+ ret = nvkm_firmware_load_blob(&gr->base.engine.subdev, path, name, ver, &blob);
+ if (ret)
+ return ret;
+
+ ret = load(&blob, ppack);
+ nvkm_blob_dtor(&blob);
+ return 0;
+}
+
+int
gk20a_gr_load_sw(struct gf100_gr *gr, const char *path, int ver)
{
- if (gk20a_gr_av_to_init(gr, path, "sw_nonctx", ver, &gr->sw_nonctx) ||
- gk20a_gr_aiv_to_init(gr, path, "sw_ctx", ver, &gr->sw_ctx) ||
- gk20a_gr_av_to_init(gr, path, "sw_bundle_init", ver, &gr->bundle) ||
- gk20a_gr_av_to_method(gr, path, "sw_method_init", ver, &gr->method))
+ if (gk20a_gr_load_net(gr, path, "sw_nonctx", ver, gk20a_gr_av_to_init, &gr->sw_nonctx) ||
+ gk20a_gr_load_net(gr, path, "sw_ctx", ver, gk20a_gr_aiv_to_init, &gr->sw_ctx) ||
+ gk20a_gr_load_net(gr, path, "sw_bundle_init", ver, gk20a_gr_av_to_init, &gr->bundle) ||
+ gk20a_gr_load_net(gr, path, "sw_method_init", ver, gk20a_gr_av_to_method, &gr->method))
return -ENOENT;
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
index 310987174cb5..797b828a943b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
@@ -411,10 +411,13 @@ gm107_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gm107_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gm107_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
.mmio = gm107_gr_pack_mmio,
.fecs.ucode = &gm107_gr_fecs_ucode,
+ .fecs.reset = gf100_gr_fecs_reset,
.gpccs.ucode = &gm107_gr_gpccs_ucode,
.rops = gf100_gr_rops,
.ppc_nr = 2,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c
index 385cfd91b266..b5210b31c1b2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c
@@ -148,11 +148,11 @@ gm200_gr_tile_map_2_8[] = {
0, 1, 1, 0, 0, 1, 1, 0,
};
-void
+int
gm200_gr_oneinit_sm_id(struct gf100_gr *gr)
{
/*XXX: There's a different algorithm here I've not yet figured out. */
- gf100_gr_oneinit_sm_id(gr);
+ return gf100_gr_oneinit_sm_id(gr);
}
void
@@ -199,8 +199,11 @@ gm200_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gm107_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_400054 = gm107_gr_init_400054,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.tpc_nr = 4,
.ppc_nr = 2,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
index ec1c46e47e00..458cd1a00d3f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
@@ -123,6 +123,7 @@ gm20b_gr = {
.init_rop_active_fbps = gk104_gr_init_rop_active_fbps,
.trap_mp = gf100_gr_trap_mp,
.set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.ppc_nr = 1,
.grctx = &gm20b_grctx,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c
index 0550dd6f46f1..851e743d2cab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c
@@ -87,7 +87,7 @@ gp100_gr_init_419c9c(struct gf100_gr *gr)
void
gp100_gr_init_fecs_exceptions(struct gf100_gr *gr)
{
- nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x000f0002);
+ nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x000e0002);
}
void
@@ -119,7 +119,10 @@ gp100_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gp100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 6,
.tpc_nr = 5,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c
index 5b001f374be0..0e223b7b5f0e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c
@@ -26,7 +26,7 @@
#include <nvif/class.h>
-static void
+void
gp102_gr_zbc_clear_stencil(struct gf100_gr *gr, int zbc)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
@@ -40,14 +40,14 @@ gp102_gr_zbc_clear_stencil(struct gf100_gr *gr, int zbc)
gr->zbc_stencil[zbc].format << ((znum % 4) * 7));
}
-static int
+int
gp102_gr_zbc_stencil_get(struct gf100_gr *gr, int format,
const u32 ds, const u32 l2)
{
struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc;
int zbc = -ENOSPC, i;
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) {
if (gr->zbc_stencil[i].format) {
if (gr->zbc_stencil[i].format != format)
continue;
@@ -115,7 +115,10 @@ gp102_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gp100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 6,
.tpc_nr = 5,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c
index 2655574ec63b..6802cb9b199f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c
@@ -43,7 +43,10 @@ gp104_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gp100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 6,
.tpc_nr = 5,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c
index adabc04d4f3a..cc2bb0d0a987 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c
@@ -45,7 +45,10 @@ gp107_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gp100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 2,
.tpc_nr = 3,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c
index 7310f0466bb7..311f703439e4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c
@@ -25,7 +25,7 @@
#include <nvfw/flcn.h>
-static void
+void
gp108_gr_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
{
struct flcn_bl_dmem_desc_v2 hdr;
@@ -36,7 +36,7 @@ gp108_gr_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr);
}
-static void
+void
gp108_gr_acr_bld_write(struct nvkm_acr *acr, u32 bld,
struct nvkm_acr_lsfw *lsfw)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c
index e13683b6e7b1..5008881ca079 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c
@@ -55,7 +55,10 @@ gp10b_gr = {
.init_tex_hww_esr = gf100_gr_init_tex_hww_esr,
.init_504430 = gm107_gr_init_504430,
.init_shader_exceptions = gp100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.trap_mp = gf100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 1,
.tpc_nr = 2,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c
index 4d043c1173ea..7f7404a76140 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c
@@ -52,10 +52,11 @@ gv100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc)
gv100_gr_trap_sm(gr, gpc, tpc, 1);
}
-static void
+void
gv100_gr_init_4188a4(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
+
nvkm_mask(device, 0x4188a4, 0x03000000, 0x03000000);
}
@@ -65,7 +66,6 @@ gv100_gr_init_shader_exceptions(struct gf100_gr *gr, int gpc, int tpc)
struct nvkm_device *device = gr->base.engine.subdev.device;
int sm;
for (sm = 0; sm < 0x100; sm += 0x80) {
- nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x728 + sm), 0x0085eb64);
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x610), 0x00000001);
nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x72c + sm), 0x00000004);
}
@@ -85,10 +85,202 @@ gv100_gr_init_419bd8(struct gf100_gr *gr)
nvkm_mask(device, 0x419bd8, 0x00000700, 0x00000000);
}
+u32
+gv100_gr_nonpes_aware_tpc(struct gf100_gr *gr, u32 gpc, u32 tpc)
+{
+ u32 pes, temp, tpc_new = 0;
+
+ for (pes = 0; pes < gr->ppc_nr[gpc]; pes++) {
+ if (gr->ppc_tpc_mask[gpc][pes] & BIT(tpc))
+ break;
+
+ tpc_new += gr->ppc_tpc_nr[gpc][pes];
+ }
+
+ temp = (BIT(tpc) - 1) & gr->ppc_tpc_mask[gpc][pes];
+ temp = hweight32(temp);
+ return tpc_new + temp;
+}
+
+static int
+gv100_gr_scg_estimate_perf(struct gf100_gr *gr, unsigned long *gpc_tpc_mask,
+ u32 disable_gpc, u32 disable_tpc, int *perf)
+{
+ const u32 scale_factor = 512UL; /* Use fx23.9 */
+ const u32 pix_scale = 1024*1024UL; /* Pix perf in [29:20] */
+ const u32 world_scale = 1024UL; /* World performance in [19:10] */
+ const u32 tpc_scale = 1; /* TPC balancing in [9:0] */
+ u32 scg_num_pes = 0;
+ u32 min_scg_gpc_pix_perf = scale_factor; /* Init perf as maximum */
+ u32 average_tpcs = 0; /* Average of # of TPCs per GPC */
+ u32 deviation; /* absolute diff between TPC# and average_tpcs, averaged across GPCs */
+ u32 norm_tpc_deviation; /* deviation/max_tpc_per_gpc */
+ u32 tpc_balance;
+ u32 scg_gpc_pix_perf;
+ u32 scg_world_perf;
+ u32 gpc;
+ u32 pes;
+ int diff;
+ bool tpc_removed_gpc = false;
+ bool tpc_removed_pes = false;
+ u32 max_tpc_gpc = 0;
+ u32 num_tpc_mask;
+ u32 *num_tpc_gpc;
+ int ret = -EINVAL;
+
+ if (!(num_tpc_gpc = kcalloc(gr->gpc_nr, sizeof(*num_tpc_gpc), GFP_KERNEL)))
+ return -ENOMEM;
+
+ /* Calculate pix-perf-reduction-rate per GPC and find bottleneck TPC */
+ for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
+ num_tpc_mask = gpc_tpc_mask[gpc];
+
+ if ((gpc == disable_gpc) && num_tpc_mask & BIT(disable_tpc)) {
+ /* Safety check if a TPC is removed twice */
+ if (WARN_ON(tpc_removed_gpc))
+ goto done;
+
+ /* Remove logical TPC from set */
+ num_tpc_mask &= ~BIT(disable_tpc);
+ tpc_removed_gpc = true;
+ }
+
+ /* track balancing of tpcs across gpcs */
+ num_tpc_gpc[gpc] = hweight32(num_tpc_mask);
+ average_tpcs += num_tpc_gpc[gpc];
+
+ /* save the maximum numer of gpcs */
+ max_tpc_gpc = num_tpc_gpc[gpc] > max_tpc_gpc ? num_tpc_gpc[gpc] : max_tpc_gpc;
+
+ /*
+ * Calculate ratio between TPC count and post-FS and post-SCG
+ *
+ * ratio represents relative throughput of the GPC
+ */
+ scg_gpc_pix_perf = scale_factor * num_tpc_gpc[gpc] / gr->tpc_nr[gpc];
+ if (min_scg_gpc_pix_perf > scg_gpc_pix_perf)
+ min_scg_gpc_pix_perf = scg_gpc_pix_perf;
+
+ /* Calculate # of surviving PES */
+ for (pes = 0; pes < gr->ppc_nr[gpc]; pes++) {
+ /* Count the number of TPC on the set */
+ num_tpc_mask = gr->ppc_tpc_mask[gpc][pes] & gpc_tpc_mask[gpc];
+
+ if ((gpc == disable_gpc) && (num_tpc_mask & BIT(disable_tpc))) {
+ if (WARN_ON(tpc_removed_pes))
+ goto done;
+
+ num_tpc_mask &= ~BIT(disable_tpc);
+ tpc_removed_pes = true;
+ }
+
+ if (hweight32(num_tpc_mask))
+ scg_num_pes++;
+ }
+ }
+
+ if (WARN_ON(!tpc_removed_gpc || !tpc_removed_pes))
+ goto done;
+
+ if (max_tpc_gpc == 0) {
+ *perf = 0;
+ goto done_ok;
+ }
+
+ /* Now calculate perf */
+ scg_world_perf = (scale_factor * scg_num_pes) / gr->ppc_total;
+ deviation = 0;
+ average_tpcs = scale_factor * average_tpcs / gr->gpc_nr;
+ for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
+ diff = average_tpcs - scale_factor * num_tpc_gpc[gpc];
+ if (diff < 0)
+ diff = -diff;
+
+ deviation += diff;
+ }
+
+ deviation /= gr->gpc_nr;
+
+ norm_tpc_deviation = deviation / max_tpc_gpc;
+
+ tpc_balance = scale_factor - norm_tpc_deviation;
+
+ if ((tpc_balance > scale_factor) ||
+ (scg_world_perf > scale_factor) ||
+ (min_scg_gpc_pix_perf > scale_factor) ||
+ (norm_tpc_deviation > scale_factor)) {
+ WARN_ON(1);
+ goto done;
+ }
+
+ *perf = (pix_scale * min_scg_gpc_pix_perf) +
+ (world_scale * scg_world_perf) +
+ (tpc_scale * tpc_balance);
+done_ok:
+ ret = 0;
+done:
+ kfree(num_tpc_gpc);
+ return ret;
+}
+
+int
+gv100_gr_oneinit_sm_id(struct gf100_gr *gr)
+{
+ unsigned long *gpc_tpc_mask;
+ u32 *tpc_table, *gpc_table;
+ u32 gpc, tpc, pes, gtpc;
+ int perf, maxperf, ret = 0;
+
+ gpc_tpc_mask = kcalloc(gr->gpc_nr, sizeof(*gpc_tpc_mask), GFP_KERNEL);
+ gpc_table = kcalloc(gr->tpc_total, sizeof(*gpc_table), GFP_KERNEL);
+ tpc_table = kcalloc(gr->tpc_total, sizeof(*tpc_table), GFP_KERNEL);
+ if (!gpc_table || !tpc_table || !gpc_tpc_mask) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (gpc = 0; gpc < gr->gpc_nr; gpc++) {
+ for (pes = 0; pes < gr->ppc_nr[gpc]; pes++)
+ gpc_tpc_mask[gpc] |= gr->ppc_tpc_mask[gpc][pes];
+ }
+
+ for (gtpc = 0; gtpc < gr->tpc_total; gtpc++) {
+ for (maxperf = -1, gpc = 0; gpc < gr->gpc_nr; gpc++) {
+ for_each_set_bit(tpc, &gpc_tpc_mask[gpc], gr->tpc_nr[gpc]) {
+ ret = gv100_gr_scg_estimate_perf(gr, gpc_tpc_mask, gpc, tpc, &perf);
+ if (ret)
+ goto done;
+
+ /* nvgpu does ">=" here, but this gets us RM's numbers. */
+ if (perf > maxperf) {
+ maxperf = perf;
+ gpc_table[gtpc] = gpc;
+ tpc_table[gtpc] = tpc;
+ }
+ }
+ }
+
+ gpc_tpc_mask[gpc_table[gtpc]] &= ~BIT(tpc_table[gtpc]);
+ }
+
+ /*TODO: build table for sm_per_tpc != 1, don't use yet, but might need later? */
+ for (gtpc = 0; gtpc < gr->tpc_total; gtpc++) {
+ gr->sm[gtpc].gpc = gpc_table[gtpc];
+ gr->sm[gtpc].tpc = tpc_table[gtpc];
+ gr->sm_nr++;
+ }
+
+done:
+ kfree(gpc_table);
+ kfree(tpc_table);
+ kfree(gpc_tpc_mask);
+ return ret;
+}
+
static const struct gf100_gr_func
gv100_gr = {
.oneinit_tiles = gm200_gr_oneinit_tiles,
- .oneinit_sm_id = gm200_gr_oneinit_sm_id,
+ .oneinit_sm_id = gv100_gr_oneinit_sm_id,
.init = gf100_gr_init,
.init_419bd8 = gv100_gr_init_419bd8,
.init_gpc_mmu = gm200_gr_init_gpc_mmu,
@@ -103,11 +295,14 @@ gv100_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_504430 = gv100_gr_init_504430,
.init_shader_exceptions = gv100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
.init_4188a4 = gv100_gr_init_4188a4,
.trap_mp = gv100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 6,
- .tpc_nr = 5,
+ .tpc_nr = 7,
.ppc_nr = 3,
.grctx = &gv100_grctx,
.zbc = &gp102_gr_zbc,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
index 0bc1a238de43..81bd682c2102 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
@@ -1192,7 +1192,7 @@ nv04_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv04_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
index 942450b33bc6..7fe6e58f6bab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
@@ -1011,7 +1011,7 @@ nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv10_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
NV_WRITE_CTX(0x00400e88, 0x08000000);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
index 6bff10cee71b..75434f5de7ad 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
@@ -83,7 +83,7 @@ nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv20_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
@@ -182,7 +182,7 @@ nv20_gr_intr(struct nvkm_gr *base)
struct nv20_gr *gr = nv20_gr(base);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
@@ -196,7 +196,7 @@ nv20_gr_intr(struct nvkm_gr *base)
char msg[128], src[128], sta[128];
unsigned long flags;
- chan = nvkm_fifo_chan_chid(device->fifo, chid, &flags);
+ chan = nvkm_chan_get_chid(&gr->base.engine, chid, &flags);
nvkm_wr32(device, NV03_PGRAPH_INTR, stat);
nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001);
@@ -209,11 +209,11 @@ nv20_gr_intr(struct nvkm_gr *base)
"nstatus %08x [%s] ch %d [%s] subc %d "
"class %04x mthd %04x data %08x\n",
show, msg, nsource, src, nstatus, sta, chid,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->name : "unknown",
subc, class, mthd, data);
}
- nvkm_fifo_chan_put(device->fifo, flags, &chan);
+ nvkm_chan_put(&chan, flags);
}
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
index f3a56f17d94a..94685e4d4f87 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
@@ -29,7 +29,7 @@ nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv25_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
index f268d2642d29..2d6273675291 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
@@ -29,7 +29,7 @@ nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv2a_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
index e5737cdf2fa1..647bd6fede04 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -30,7 +30,7 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv30_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
index 1ab2da8ebf4e..2eae3fe4ef4e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -29,7 +29,7 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv34_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
index 591260f5676b..657d7cdba369 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
@@ -29,7 +29,7 @@ nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv35_gr_chan, oclass, &chan->object);
chan->gr = gr;
- chan->chid = fifoch->chid;
+ chan->chid = fifoch->id;
*pobject = &chan->object;
ret = nvkm_memory_new(gr->base.engine.subdev.device,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
index 67f3535ff97e..d2df097a6cf6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
@@ -275,8 +275,8 @@ nv40_gr_intr(struct nvkm_gr *base)
"nstatus %08x [%s] ch %d [%08x %s] subc %d "
"class %04x mthd %04x data %08x\n",
show, msg, nsource, src, nstatus, sta,
- chan ? chan->fifo->chid : -1, inst << 4,
- chan ? chan->fifo->object.client->name : "unknown",
+ chan ? chan->fifo->id : -1, inst << 4,
+ chan ? chan->fifo->name : "unknown",
subc, class, mthd, data);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
index 563a10097e95..1ba18a8e380f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
@@ -622,7 +622,7 @@ nv50_gr_intr(struct nvkm_gr *base)
struct nv50_gr *gr = nv50_gr(base);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
u32 stat = nvkm_rd32(device, 0x400100);
u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff;
u32 addr = nvkm_rd32(device, 0x400704);
@@ -637,10 +637,10 @@ nv50_gr_intr(struct nvkm_gr *base)
char msg[128];
int chid = -1;
- chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags);
+ chan = nvkm_chan_get_inst(&gr->base.engine, (u64)inst << 12, &flags);
if (chan) {
- name = chan->object.client->name;
- chid = chan->chid;
+ name = chan->name;
+ chid = chan->id;
}
if (show & 0x00100000) {
@@ -672,7 +672,7 @@ nv50_gr_intr(struct nvkm_gr *base)
if (nvkm_rd32(device, 0x400824) & (1 << 31))
nvkm_wr32(device, 0x400824, nvkm_rd32(device, 0x400824) & ~(1 << 31));
- nvkm_fifo_chan_put(device->fifo, flags, &chan);
+ nvkm_chan_put(&chan, flags);
}
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
index 9b2c66e8be90..08d5c96e6458 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
@@ -17,6 +17,7 @@ struct nvkm_gr_func {
int (*oneinit)(struct nvkm_gr *);
int (*init)(struct nvkm_gr *);
int (*fini)(struct nvkm_gr *, bool);
+ int (*reset)(struct nvkm_gr *);
void (*intr)(struct nvkm_gr *);
void (*tile)(struct nvkm_gr *, int region, struct nvkm_fb_tile *);
int (*tlb_flush)(struct nvkm_gr *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
index 1a8a21844e12..3b6c8100a242 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
@@ -24,13 +24,13 @@
#include <nvif/class.h>
-static void
+void
tu102_gr_init_fecs_exceptions(struct gf100_gr *gr)
{
- nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x006f0002);
+ nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x006e0003);
}
-static void
+void
tu102_gr_init_fs(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
@@ -40,20 +40,21 @@ tu102_gr_init_fs(struct gf100_gr *gr)
gk104_grctx_generate_gpc_tpc_nr(gr);
for (sm = 0; sm < gr->sm_nr; sm++) {
- nvkm_wr32(device, GPC_UNIT(gr->sm[sm].gpc, 0x0c10 +
- gr->sm[sm].tpc * 4), sm);
+ int tpc = gv100_gr_nonpes_aware_tpc(gr, gr->sm[sm].gpc, gr->sm[sm].tpc);
+
+ nvkm_wr32(device, GPC_UNIT(gr->sm[sm].gpc, 0x0c10 + tpc * 4), sm);
}
gm200_grctx_generate_dist_skip_table(gr);
gf100_gr_init_num_tpc_per_gpc(gr, true, true);
}
-static void
+void
tu102_gr_init_zcull(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
- const u8 tile_nr = ALIGN(gr->tpc_total, 64);
+ const u8 tile_nr = gr->func->gpc_nr * gr->func->tpc_nr;
u8 bank[GPC_MAX] = {}, gpc, i, j;
u32 data;
@@ -93,7 +94,7 @@ tu102_gr_init_gpc_mmu(struct gf100_gr *gr)
static const struct gf100_gr_func
tu102_gr = {
.oneinit_tiles = gm200_gr_oneinit_tiles,
- .oneinit_sm_id = gm200_gr_oneinit_sm_id,
+ .oneinit_sm_id = gv100_gr_oneinit_sm_id,
.init = gf100_gr_init,
.init_419bd8 = gv100_gr_init_419bd8,
.init_gpc_mmu = tu102_gr_init_gpc_mmu,
@@ -109,10 +110,14 @@ tu102_gr = {
.init_ppc_exceptions = gk104_gr_init_ppc_exceptions,
.init_504430 = gv100_gr_init_504430,
.init_shader_exceptions = gv100_gr_init_shader_exceptions,
+ .init_rop_exceptions = gf100_gr_init_rop_exceptions,
+ .init_exception2 = gf100_gr_init_exception2,
+ .init_4188a4 = gv100_gr_init_4188a4,
.trap_mp = gv100_gr_trap_mp,
+ .fecs.reset = gf100_gr_fecs_reset,
.rops = gm200_gr_rops,
.gpc_nr = 6,
- .tpc_nr = 5,
+ .tpc_nr = 6,
.ppc_nr = 3,
.grctx = &tu102_grctx,
.zbc = &gp102_gr_zbc,
@@ -137,6 +142,7 @@ MODULE_FIRMWARE("nvidia/tu102/gr/sw_ctx.bin");
MODULE_FIRMWARE("nvidia/tu102/gr/sw_nonctx.bin");
MODULE_FIRMWARE("nvidia/tu102/gr/sw_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu102/gr/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/tu102/gr/sw_veid_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu104/gr/fecs_bl.bin");
MODULE_FIRMWARE("nvidia/tu104/gr/fecs_inst.bin");
@@ -150,6 +156,7 @@ MODULE_FIRMWARE("nvidia/tu104/gr/sw_ctx.bin");
MODULE_FIRMWARE("nvidia/tu104/gr/sw_nonctx.bin");
MODULE_FIRMWARE("nvidia/tu104/gr/sw_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu104/gr/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/tu104/gr/sw_veid_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu106/gr/fecs_bl.bin");
MODULE_FIRMWARE("nvidia/tu106/gr/fecs_inst.bin");
@@ -163,6 +170,7 @@ MODULE_FIRMWARE("nvidia/tu106/gr/sw_ctx.bin");
MODULE_FIRMWARE("nvidia/tu106/gr/sw_nonctx.bin");
MODULE_FIRMWARE("nvidia/tu106/gr/sw_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu106/gr/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/tu106/gr/sw_veid_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu117/gr/fecs_bl.bin");
MODULE_FIRMWARE("nvidia/tu117/gr/fecs_inst.bin");
@@ -176,6 +184,7 @@ MODULE_FIRMWARE("nvidia/tu117/gr/sw_ctx.bin");
MODULE_FIRMWARE("nvidia/tu117/gr/sw_nonctx.bin");
MODULE_FIRMWARE("nvidia/tu117/gr/sw_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu117/gr/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/tu117/gr/sw_veid_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu116/gr/fecs_bl.bin");
MODULE_FIRMWARE("nvidia/tu116/gr/fecs_inst.bin");
@@ -189,6 +198,26 @@ MODULE_FIRMWARE("nvidia/tu116/gr/sw_ctx.bin");
MODULE_FIRMWARE("nvidia/tu116/gr/sw_nonctx.bin");
MODULE_FIRMWARE("nvidia/tu116/gr/sw_bundle_init.bin");
MODULE_FIRMWARE("nvidia/tu116/gr/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/tu116/gr/sw_veid_bundle_init.bin");
+
+int
+tu102_gr_av_to_init_veid(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
+{
+ return gk20a_gr_av_to_init_(blob, 64, 0x00100000, ppack);
+}
+
+int
+tu102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif)
+{
+ int ret;
+
+ ret = gm200_gr_load(gr, ver, fwif);
+ if (ret)
+ return ret;
+
+ return gk20a_gr_load_net(gr, "gr/", "sw_veid_bundle_init", ver, tu102_gr_av_to_init_veid,
+ &gr->bundle_veid);
+}
static const struct gf100_gr_fwif
tu102_gr_fwif[] = {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
index b1054db4c1b8..cb0c3991b2ad 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
@@ -213,8 +213,8 @@ nv31_mpeg_intr(struct nvkm_engine *engine)
if (show) {
nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n",
- mpeg->chan ? mpeg->chan->fifo->chid : -1,
- mpeg->chan ? mpeg->chan->object.client->name :
+ mpeg->chan ? mpeg->chan->fifo->id : -1,
+ mpeg->chan ? mpeg->chan->fifo->name :
"unknown", stat, type, mthd, data);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
index 521ce43a2871..0890a279458e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
@@ -182,8 +182,8 @@ nv44_mpeg_intr(struct nvkm_engine *engine)
if (show) {
nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n",
- chan ? chan->fifo->chid : -1, inst << 4,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->fifo->id : -1, inst << 4,
+ chan ? chan->fifo->name : "unknown",
stat, type, mthd, data);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
index 9a0fd9812750..f05e79670d22 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/nvdec/base.o
nvkm-y += nvkm/engine/nvdec/gm107.o
+nvkm-y += nvkm/engine/nvdec/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
index b0181cc5953b..1f6e3b32ba16 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
@@ -37,7 +37,7 @@ nvkm_nvdec = {
int
nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_nvdec **pnvdec)
+ enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_nvdec **pnvdec)
{
struct nvkm_nvdec *nvdec;
int ret;
@@ -57,5 +57,5 @@ nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device,
nvdec->func = fwif->func;
return nvkm_falcon_ctor(nvdec->func->flcn, &nvdec->engine.subdev,
- nvdec->engine.subdev.name, 0, &nvdec->falcon);
+ nvdec->engine.subdev.name, addr, &nvdec->falcon);
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
new file mode 100644
index 000000000000..37d8c3c0f3ab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+static const struct nvkm_falcon_func
+ga102_nvdec_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .addr2 = 0x1c00,
+ .reset_pmc = true,
+ .reset_prep = ga102_flcn_reset_prep,
+ .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing,
+ .imem_dma = &ga102_flcn_dma,
+ .dmem_dma = &ga102_flcn_dma,
+};
+
+static const struct nvkm_nvdec_func
+ga102_nvdec = {
+ .flcn = &ga102_nvdec_flcn,
+};
+
+static int
+ga102_nvdec_nofw(struct nvkm_nvdec *nvdec, int ver, const struct nvkm_nvdec_fwif *fwif)
+{
+ return 0;
+}
+
+static const struct nvkm_nvdec_fwif
+ga102_nvdec_fwif[] = {
+ { -1, ga102_nvdec_nofw, &ga102_nvdec },
+ {}
+};
+
+int
+ga102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_nvdec **pnvdec)
+{
+ return nvkm_nvdec_new_(ga102_nvdec_fwif, device, type, inst, 0x848000, pnvdec);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
index 8c44ce44a6d7..564f7e8960a2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c
@@ -23,18 +23,13 @@
static const struct nvkm_falcon_func
gm107_nvdec_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_pmc = true,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
.debug = 0xd00,
- .fbif = 0x600,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = nvkm_falcon_v1_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
- .start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
};
static const struct nvkm_nvdec_func
@@ -59,5 +54,5 @@ int
gm107_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_nvdec **pnvdec)
{
- return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, pnvdec);
+ return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, 0, pnvdec);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
index 0920f6a887e2..61e1f7aaa509 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
@@ -15,5 +15,5 @@ struct nvkm_nvdec_fwif {
};
int nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *,
- enum nvkm_subdev_type, int, struct nvkm_nvdec **);
+ enum nvkm_subdev_type, int, u32 addr, struct nvkm_nvdec **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
index f44d41bf2034..ad27d8b97569 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c
@@ -24,17 +24,6 @@
static const struct nvkm_falcon_func
gm107_nvenc_flcn = {
- .fbif = 0x800,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = nvkm_falcon_v1_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
- .start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
};
static const struct nvkm_nvenc_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
index 1b87df03c823..c15b2cbf506b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
@@ -40,7 +40,7 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = {
};
static void
-g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan)
+g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_chan *chan)
{
struct nvkm_subdev *subdev = &sec->engine.subdev;
struct nvkm_device *device = subdev->device;
@@ -54,9 +54,9 @@ g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan)
nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] "
"subc %d mthd %04x data %08x\n", ssta,
- en ? en->name : "UNKNOWN", chan ? chan->chid : -1,
+ en ? en->name : "UNKNOWN", chan ? chan->id : -1,
chan ? chan->inst->addr : 0,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->name : "unknown",
subc, mthd, data);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
index 63cd2be3de08..19feadb1f67b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
@@ -3,3 +3,4 @@ nvkm-y += nvkm/engine/sec2/base.o
nvkm-y += nvkm/engine/sec2/gp102.o
nvkm-y += nvkm/engine/sec2/gp108.o
nvkm-y += nvkm/engine/sec2/tu102.o
+nvkm-y += nvkm/engine/sec2/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
index 092c6d0b8e01..f2c60da5d1e8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
@@ -22,53 +22,99 @@
#include "priv.h"
#include <core/firmware.h>
-#include <subdev/top.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
-static void
-nvkm_sec2_recv(struct work_struct *work)
+#include <nvfw/sec2.h>
+
+static int
+nvkm_sec2_finimsg(void *priv, struct nvfw_falcon_msg *hdr)
+{
+ struct nvkm_sec2 *sec2 = priv;
+
+ atomic_set(&sec2->running, 0);
+ return 0;
+}
+
+static int
+nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
{
- struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work);
+ struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+ struct nvkm_subdev *subdev = &sec2->engine.subdev;
+ struct nvkm_falcon *falcon = &sec2->falcon;
+ struct nvkm_falcon_cmdq *cmdq = sec2->cmdq;
+ struct nvfw_falcon_cmd cmd = {
+ .unit_id = sec2->func->unit_unload,
+ .size = sizeof(cmd),
+ };
+ int ret;
- if (!sec2->initmsg_received) {
- int ret = sec2->func->initmsg(sec2);
- if (ret) {
- nvkm_error(&sec2->engine.subdev,
- "error parsing init message: %d\n", ret);
- return;
- }
+ if (!subdev->use.enabled)
+ return 0;
- sec2->initmsg_received = true;
+ if (atomic_read(&sec2->initmsg) == 1) {
+ ret = nvkm_falcon_cmdq_send(cmdq, &cmd, nvkm_sec2_finimsg, sec2,
+ msecs_to_jiffies(1000));
+ WARN_ON(ret);
+
+ nvkm_msec(subdev->device, 2000,
+ if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010)
+ break;
+ );
}
- nvkm_falcon_msgq_recv(sec2->msgq);
+ nvkm_inth_block(&subdev->inth);
+
+ nvkm_falcon_cmdq_fini(cmdq);
+ falcon->func->disable(falcon);
+ nvkm_falcon_put(falcon, subdev);
+ return 0;
}
-static void
-nvkm_sec2_intr(struct nvkm_engine *engine)
+static int
+nvkm_sec2_init(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
- sec2->func->intr(sec2);
+ struct nvkm_subdev *subdev = &sec2->engine.subdev;
+ struct nvkm_falcon *falcon = &sec2->falcon;
+ int ret;
+
+ ret = nvkm_falcon_get(falcon, subdev);
+ if (ret)
+ return ret;
+
+ nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
+ atomic_set(&sec2->initmsg, 0);
+ atomic_set(&sec2->running, 1);
+ nvkm_inth_allow(&subdev->inth);
+
+ nvkm_falcon_start(falcon);
+ return 0;
}
static int
-nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
+nvkm_sec2_oneinit(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
-
- flush_work(&sec2->work);
-
- if (suspend) {
- nvkm_falcon_cmdq_fini(sec2->cmdq);
- sec2->initmsg_received = false;
+ struct nvkm_subdev *subdev = &sec2->engine.subdev;
+ struct nvkm_intr *intr = &sec2->engine.subdev.device->mc->intr;
+ enum nvkm_intr_type type = NVKM_INTR_SUBDEV;
+
+ if (sec2->func->intr_vector) {
+ intr = sec2->func->intr_vector(sec2, &type);
+ if (IS_ERR(intr))
+ return PTR_ERR(intr);
}
- return 0;
+ return nvkm_inth_add(intr, type, NVKM_INTR_PRIO_NORMAL, subdev, sec2->func->intr,
+ &subdev->inth);
}
static void *
nvkm_sec2_dtor(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+
nvkm_falcon_msgq_del(&sec2->msgq);
nvkm_falcon_cmdq_del(&sec2->cmdq);
nvkm_falcon_qmgr_del(&sec2->qmgr);
@@ -79,8 +125,9 @@ nvkm_sec2_dtor(struct nvkm_engine *engine)
static const struct nvkm_engine_func
nvkm_sec2 = {
.dtor = nvkm_sec2_dtor,
+ .oneinit = nvkm_sec2_oneinit,
+ .init = nvkm_sec2_init,
.fini = nvkm_sec2_fini,
- .intr = nvkm_sec2_intr,
};
int
@@ -113,6 +160,5 @@ nvkm_sec2_new_(const struct nvkm_sec2_fwif *fwif, struct nvkm_device *device,
(ret = nvkm_falcon_msgq_new(sec2->qmgr, "msgq", &sec2->msgq)))
return ret;
- INIT_WORK(&sec2->work, nvkm_sec2_recv);
return 0;
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
new file mode 100644
index 000000000000..945abb8156d7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+#include <subdev/acr.h>
+#include <subdev/vfn.h>
+
+#include <nvfw/flcn.h>
+#include <nvfw/sec2.h>
+
+static int
+ga102_sec2_initmsg(struct nvkm_sec2 *sec2)
+{
+ struct nv_sec2_init_msg_v1 msg;
+ int ret, i;
+
+ ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg));
+ if (ret)
+ return ret;
+
+ if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT ||
+ msg.msg_type != NV_SEC2_INIT_MSG_INIT)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) {
+ if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) {
+ nvkm_falcon_msgq_init(sec2->msgq, msg.queue_info[i].index,
+ msg.queue_info[i].offset,
+ msg.queue_info[i].size);
+ } else {
+ nvkm_falcon_cmdq_init(sec2->cmdq, msg.queue_info[i].index,
+ msg.queue_info[i].offset,
+ msg.queue_info[i].size);
+ }
+ }
+
+ return 0;
+}
+
+static struct nvkm_intr *
+ga102_sec2_intr_vector(struct nvkm_sec2 *sec2, enum nvkm_intr_type *pvector)
+{
+ struct nvkm_device *device = sec2->engine.subdev.device;
+ struct nvkm_falcon *falcon = &sec2->falcon;
+ int ret;
+
+ ret = ga102_flcn_select(falcon);
+ if (ret)
+ return ERR_PTR(ret);
+
+ *pvector = nvkm_rd32(device, 0x8403e0) & 0x000000ff;
+ return &device->vfn->intr;
+}
+
+static int
+ga102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nvfw_falcon_msg *hdr)
+{
+ struct nv_sec2_acr_bootstrap_falcon_msg_v1 *msg =
+ container_of(hdr, typeof(*msg), msg.hdr);
+ struct nvkm_subdev *subdev = priv;
+ const char *name = nvkm_acr_lsf_id(msg->falcon_id);
+
+ if (msg->error_code) {
+ nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for falcon %d [%s]: %08x %08x\n",
+ msg->falcon_id, name, msg->error_code, msg->unkn08);
+ return -EINVAL;
+ }
+
+ nvkm_debug(subdev, "%s booted\n", name);
+ return 0;
+}
+
+static int
+ga102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id)
+{
+ struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon);
+ struct nv_sec2_acr_bootstrap_falcon_cmd_v1 cmd = {
+ .cmd.hdr.unit_id = sec2->func->unit_acr,
+ .cmd.hdr.size = sizeof(cmd),
+ .cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON,
+ .flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
+ .falcon_id = id,
+ };
+
+ return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr,
+ ga102_sec2_acr_bootstrap_falcon_callback,
+ &sec2->engine.subdev,
+ msecs_to_jiffies(1000));
+}
+
+static const struct nvkm_acr_lsf_func
+ga102_sec2_acr_0 = {
+ .bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
+ .bld_write = gp102_sec2_acr_bld_write_1,
+ .bld_patch = gp102_sec2_acr_bld_patch_1,
+ .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
+ BIT_ULL(NVKM_ACR_LSF_GPCCS) |
+ BIT_ULL(NVKM_ACR_LSF_SEC2),
+ .bootstrap_falcon = ga102_sec2_acr_bootstrap_falcon,
+};
+
+static const struct nvkm_falcon_func
+ga102_sec2_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .select = ga102_flcn_select,
+ .addr2 = 0x1000,
+ .reset_pmc = true,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_prep = ga102_flcn_reset_prep,
+ .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing,
+ .imem_dma = &ga102_flcn_dma,
+ .dmem_pio = &gm200_flcn_dmem_pio,
+ .dmem_dma = &ga102_flcn_dma,
+ .emem_addr = 0x01000000,
+ .emem_pio = &gp102_flcn_emem_pio,
+ .start = nvkm_falcon_v1_start,
+ .cmdq = { 0xc00, 0xc04, 8 },
+ .msgq = { 0xc80, 0xc84, 8 },
+};
+
+static const struct nvkm_sec2_func
+ga102_sec2 = {
+ .flcn = &ga102_sec2_flcn,
+ .intr_vector = ga102_sec2_intr_vector,
+ .intr = gp102_sec2_intr,
+ .initmsg = ga102_sec2_initmsg,
+ .unit_acr = NV_SEC2_UNIT_V2_ACR,
+ .unit_unload = NV_SEC2_UNIT_V2_UNLOAD,
+};
+
+MODULE_FIRMWARE("nvidia/ga102/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga102/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga103/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga103/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga104/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga104/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga106/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga106/sec2/hs_bl_sig.bin");
+
+MODULE_FIRMWARE("nvidia/ga107/sec2/desc.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/image.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/ga107/sec2/hs_bl_sig.bin");
+
+static int
+ga102_sec2_load(struct nvkm_sec2 *sec2, int ver,
+ const struct nvkm_sec2_fwif *fwif)
+{
+ return nvkm_acr_lsfw_load_sig_image_desc_v2(&sec2->engine.subdev, &sec2->falcon,
+ NVKM_ACR_LSF_SEC2, "sec2/", ver, fwif->acr);
+}
+
+static const struct nvkm_sec2_fwif
+ga102_sec2_fwif[] = {
+ { 0, ga102_sec2_load, &ga102_sec2, &ga102_sec2_acr_0 },
+ { -1, gp102_sec2_nofw, &ga102_sec2 }
+};
+
+int
+ga102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_sec2 **psec2)
+{
+ /* TOP info wasn't updated on Turing to reflect the PRI
+ * address change for some reason. We override it here.
+ */
+ return nvkm_sec2_new_(ga102_sec2_fwif, device, type, inst, 0x840000, psec2);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
index 44e39f5743d5..c64013d10500 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
@@ -74,16 +74,6 @@ gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
msecs_to_jiffies(1000));
}
-static int
-gp102_sec2_acr_boot(struct nvkm_falcon *falcon)
-{
- struct nv_sec2_args args = {};
- nvkm_falcon_load_dmem(falcon, &args,
- falcon->func->emem_addr, sizeof(args), 0);
- nvkm_falcon_start(falcon);
- return 0;
-}
-
static void
gp102_sec2_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
{
@@ -122,7 +112,6 @@ gp102_sec2_acr_0 = {
.bld_size = sizeof(struct loader_config_v1),
.bld_write = gp102_sec2_acr_bld_write,
.bld_patch = gp102_sec2_acr_bld_patch,
- .boot = gp102_sec2_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS) |
BIT_ULL(NVKM_ACR_LSF_SEC2),
@@ -160,89 +149,68 @@ gp102_sec2_initmsg(struct nvkm_sec2 *sec2)
return 0;
}
-void
-gp102_sec2_intr(struct nvkm_sec2 *sec2)
+irqreturn_t
+gp102_sec2_intr(struct nvkm_inth *inth)
{
+ struct nvkm_sec2 *sec2 = container_of(inth, typeof(*sec2), engine.subdev.inth);
struct nvkm_subdev *subdev = &sec2->engine.subdev;
struct nvkm_falcon *falcon = &sec2->falcon;
u32 disp = nvkm_falcon_rd32(falcon, 0x01c);
u32 intr = nvkm_falcon_rd32(falcon, 0x008) & disp & ~(disp >> 16);
if (intr & 0x00000040) {
- schedule_work(&sec2->work);
+ if (unlikely(atomic_read(&sec2->initmsg) == 0)) {
+ int ret = sec2->func->initmsg(sec2);
+
+ if (ret)
+ nvkm_error(subdev, "error parsing init message: %d\n", ret);
+
+ atomic_set(&sec2->initmsg, ret ?: 1);
+ }
+
+ if (atomic_read(&sec2->initmsg) > 0) {
+ if (!nvkm_falcon_msgq_empty(sec2->msgq))
+ nvkm_falcon_msgq_recv(sec2->msgq);
+ }
+
nvkm_falcon_wr32(falcon, 0x004, 0x00000040);
intr &= ~0x00000040;
}
+ if (intr & 0x00000010) {
+ if (atomic_read(&sec2->running)) {
+ FLCN_ERR(falcon, "halted");
+ gm200_flcn_tracepc(falcon);
+ }
+
+ nvkm_falcon_wr32(falcon, 0x004, 0x00000010);
+ intr &= ~0x00000010;
+ }
+
if (intr) {
nvkm_error(subdev, "unhandled intr %08x\n", intr);
nvkm_falcon_wr32(falcon, 0x004, intr);
}
-}
-int
-gp102_sec2_flcn_enable(struct nvkm_falcon *falcon)
-{
- nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001);
- udelay(10);
- nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000);
- return nvkm_falcon_v1_enable(falcon);
-}
-
-void
-gp102_sec2_flcn_bind_context(struct nvkm_falcon *falcon,
- struct nvkm_memory *ctx)
-{
- struct nvkm_device *device = falcon->owner->device;
-
- nvkm_falcon_v1_bind_context(falcon, ctx);
- if (!ctx)
- return;
-
- /* Not sure if this is a WAR for a HW issue, or some additional
- * programming sequence that's needed to properly complete the
- * context switch we trigger above.
- *
- * Fixes unreliability of booting the SEC2 RTOS on Quadro P620,
- * particularly when resuming from suspend.
- *
- * Also removes the need for an odd workaround where we needed
- * to program SEC2's FALCON_CPUCTL_ALIAS_STARTCPU twice before
- * the SEC2 RTOS would begin executing.
- */
- nvkm_msec(device, 10,
- u32 irqstat = nvkm_falcon_rd32(falcon, 0x008);
- u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc);
- if ((irqstat & 0x00000008) &&
- (flcn0dc & 0x00007000) == 0x00005000)
- break;
- );
-
- nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008);
- nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002);
-
- nvkm_msec(device, 10,
- u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc);
- if ((flcn0dc & 0x00007000) == 0x00000000)
- break;
- );
+ return IRQ_HANDLED;
}
static const struct nvkm_falcon_func
gp102_sec2_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_pmc = true,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
.debug = 0x408,
- .fbif = 0x600,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
+ .bind_inst = gm200_flcn_bind_inst,
+ .bind_stat = gm200_flcn_bind_stat,
+ .bind_intr = true,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
.emem_addr = 0x01000000,
- .bind_context = gp102_sec2_flcn_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
+ .emem_pio = &gp102_flcn_emem_pio,
.start = nvkm_falcon_v1_start,
- .enable = gp102_sec2_flcn_enable,
- .disable = nvkm_falcon_v1_disable,
.cmdq = { 0xa00, 0xa04, 8 },
.msgq = { 0xa30, 0xa34, 8 },
};
@@ -250,6 +218,7 @@ gp102_sec2_flcn = {
const struct nvkm_sec2_func
gp102_sec2 = {
.flcn = &gp102_sec2_flcn,
+ .unit_unload = NV_SEC2_UNIT_UNLOAD,
.unit_acr = NV_SEC2_UNIT_ACR,
.intr = gp102_sec2_intr,
.initmsg = gp102_sec2_initmsg,
@@ -268,7 +237,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
-static void
+void
gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust)
{
struct flcn_bl_dmem_desc_v2 hdr;
@@ -279,7 +248,7 @@ gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust)
flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr);
}
-static void
+void
gp102_sec2_acr_bld_write_1(struct nvkm_acr *acr, u32 bld,
struct nvkm_acr_lsfw *lsfw)
{
@@ -304,7 +273,6 @@ gp102_sec2_acr_1 = {
.bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
.bld_write = gp102_sec2_acr_bld_write_1,
.bld_patch = gp102_sec2_acr_bld_patch_1,
- .boot = gp102_sec2_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS) |
BIT_ULL(NVKM_ACR_LSF_SEC2),
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
index af19229e885d..172d2705c199 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
@@ -2,15 +2,18 @@
#ifndef __NVKM_SEC2_PRIV_H__
#define __NVKM_SEC2_PRIV_H__
#include <engine/sec2.h>
+struct nvkm_acr_lsfw;
struct nvkm_sec2_func {
const struct nvkm_falcon_func *flcn;
+ u8 unit_unload;
u8 unit_acr;
- void (*intr)(struct nvkm_sec2 *);
+ struct nvkm_intr *(*intr_vector)(struct nvkm_sec2 *, enum nvkm_intr_type *);
+ irqreturn_t (*intr)(struct nvkm_inth *);
int (*initmsg)(struct nvkm_sec2 *);
};
-void gp102_sec2_intr(struct nvkm_sec2 *);
+irqreturn_t gp102_sec2_intr(struct nvkm_inth *);
int gp102_sec2_initmsg(struct nvkm_sec2 *);
struct nvkm_sec2_fwif {
@@ -24,6 +27,8 @@ int gp102_sec2_nofw(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *);
int gp102_sec2_load(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *);
extern const struct nvkm_sec2_func gp102_sec2;
extern const struct nvkm_acr_lsf_func gp102_sec2_acr_1;
+void gp102_sec2_acr_bld_write_1(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *);
+void gp102_sec2_acr_bld_patch_1(struct nvkm_acr *, u32, s64);
int nvkm_sec2_new_(const struct nvkm_sec2_fwif *, struct nvkm_device *, enum nvkm_subdev_type,
int, u32 addr, struct nvkm_sec2 **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
index f3faeb705575..0afc4b2fa529 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
@@ -22,21 +22,24 @@
#include "priv.h"
#include <subdev/acr.h>
+#include <nvfw/sec2.h>
+
static const struct nvkm_falcon_func
tu102_sec2_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_pmc = true,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
.debug = 0x408,
- .fbif = 0x600,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
+ .bind_inst = gm200_flcn_bind_inst,
+ .bind_stat = gm200_flcn_bind_stat,
+ .bind_intr = true,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
.emem_addr = 0x01000000,
- .bind_context = gp102_sec2_flcn_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
+ .emem_pio = &gp102_flcn_emem_pio,
.start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
.cmdq = { 0xc00, 0xc04, 8 },
.msgq = { 0xc80, 0xc84, 8 },
};
@@ -44,7 +47,8 @@ tu102_sec2_flcn = {
static const struct nvkm_sec2_func
tu102_sec2 = {
.flcn = &tu102_sec2_flcn,
- .unit_acr = 0x07,
+ .unit_unload = NV_SEC2_UNIT_V2_UNLOAD,
+ .unit_acr = NV_SEC2_UNIT_V2_ACR,
.intr = gp102_sec2_intr,
.initmsg = gp102_sec2_initmsg,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c
index 14871d0bd746..a9d464db6974 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c
@@ -35,7 +35,7 @@ nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data)
spin_lock_irqsave(&sw->engine.lock, flags);
list_for_each_entry(chan, &sw->chan, head) {
- if (chan->fifo->chid == chid) {
+ if (chan->fifo->id == chid) {
handled = nvkm_sw_chan_mthd(chan, subc, mthd, data);
list_del(&chan->head);
list_add(&chan->head, &sw->chan);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
index f28967065639..834b8cbed51d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
@@ -23,7 +23,6 @@
*/
#include "chan.h"
-#include <core/notify.h>
#include <engine/fifo.h>
#include <nvif/event.h>
@@ -36,7 +35,7 @@ nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data)
case 0x0000:
return true;
case 0x0500:
- nvkm_event_send(&chan->event, 1, 0, NULL, 0);
+ nvkm_event_ntfy(&chan->event, 0, NVKM_SW_CHAN_EVENT_PAGE_FLIP);
return true;
default:
if (chan->func->mthd)
@@ -46,27 +45,8 @@ nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data)
return false;
}
-static int
-nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- union {
- struct nvif_notify_uevent_req none;
- } *req = data;
- int ret = -ENOSYS;
-
- if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
- notify->size = sizeof(struct nvif_notify_uevent_rep);
- notify->types = 1;
- notify->index = 0;
- }
-
- return ret;
-}
-
static const struct nvkm_event_func
nvkm_sw_chan_event = {
- .ctor = nvkm_sw_chan_event_ctor,
};
static void *
@@ -107,5 +87,5 @@ nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, struct nvkm_sw *sw,
list_add(&chan->head, &sw->chan);
spin_unlock_irqrestore(&sw->engine.lock, flags);
- return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event);
+ return nvkm_event_init(&nvkm_sw_chan_event, &sw->engine.subdev, 1, 1, &chan->event);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h
index 32de53427aa4..67b2e5ea93d9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h
@@ -14,6 +14,7 @@ struct nvkm_sw_chan {
struct nvkm_fifo_chan *fifo;
struct list_head head;
+#define NVKM_SW_CHAN_EVENT_PAGE_FLIP BIT(0)
struct nvkm_event event;
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
index 55abf839f29d..c3cf6f2ff86c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
@@ -36,10 +36,10 @@
******************************************************************************/
static int
-gf100_sw_chan_vblsem_release(struct nvkm_notify *notify)
+gf100_sw_chan_vblsem_release(struct nvkm_event_ntfy *notify, u32 bits)
{
struct nv50_sw_chan *chan =
- container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+ container_of(notify, typeof(*chan), vblank.notify[notify->id]);
struct nvkm_sw *sw = chan->base.sw;
struct nvkm_device *device = sw->engine.subdev.device;
u32 inst = chan->base.fifo->inst->addr >> 12;
@@ -50,7 +50,7 @@ gf100_sw_chan_vblsem_release(struct nvkm_notify *notify)
nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset));
nvkm_wr32(device, 0x060014, chan->vblank.value);
- return NVKM_NOTIFY_DROP;
+ return NVKM_EVENT_DROP;
}
static bool
@@ -73,7 +73,7 @@ gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data)
return true;
case 0x040c:
if (data < device->disp->vblank.index_nr) {
- nvkm_notify_get(&chan->vblank.notify[data]);
+ nvkm_event_ntfy_allow(&chan->vblank.notify[data]);
return true;
}
break;
@@ -120,16 +120,8 @@ gf100_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch,
return ret;
for (i = 0; disp && i < disp->vblank.index_nr; i++) {
- ret = nvkm_notify_init(NULL, &disp->vblank,
- gf100_sw_chan_vblsem_release, false,
- &(struct nvif_notify_head_req_v0) {
- .head = i,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &chan->vblank.notify[i]);
- if (ret)
- return ret;
+ nvkm_event_ntfy_add(&disp->vblank, i, NVKM_DISP_HEAD_EVENT_VBLANK, true,
+ gf100_sw_chan_vblsem_release, &chan->vblank.notify[i]);
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
index 1fdd094c8b7e..9d7a9b7d5be3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
@@ -36,10 +36,10 @@
******************************************************************************/
static int
-nv50_sw_chan_vblsem_release(struct nvkm_notify *notify)
+nv50_sw_chan_vblsem_release(struct nvkm_event_ntfy *notify, u32 bits)
{
struct nv50_sw_chan *chan =
- container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+ container_of(notify, typeof(*chan), vblank.notify[notify->id]);
struct nvkm_sw *sw = chan->base.sw;
struct nvkm_device *device = sw->engine.subdev.device;
@@ -55,7 +55,7 @@ nv50_sw_chan_vblsem_release(struct nvkm_notify *notify)
nvkm_wr32(device, 0x060014, chan->vblank.value);
}
- return NVKM_NOTIFY_DROP;
+ return NVKM_EVENT_DROP;
}
static bool
@@ -70,7 +70,7 @@ nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data)
case 0x0404: chan->vblank.value = data; return true;
case 0x0408:
if (data < device->disp->vblank.index_nr) {
- nvkm_notify_get(&chan->vblank.notify[data]);
+ nvkm_event_ntfy_allow(&chan->vblank.notify[data]);
return true;
}
break;
@@ -85,8 +85,10 @@ nv50_sw_chan_dtor(struct nvkm_sw_chan *base)
{
struct nv50_sw_chan *chan = nv50_sw_chan(base);
int i;
+
for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
- nvkm_notify_fini(&chan->vblank.notify[i]);
+ nvkm_event_ntfy_del(&chan->vblank.notify[i]);
+
return chan;
}
@@ -113,16 +115,8 @@ nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch,
return ret;
for (i = 0; disp && i < disp->vblank.index_nr; i++) {
- ret = nvkm_notify_init(NULL, &disp->vblank,
- nv50_sw_chan_vblsem_release, false,
- &(struct nvif_notify_head_req_v0) {
- .head = i,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &chan->vblank.notify[i]);
- if (ret)
- return ret;
+ nvkm_event_ntfy_add(&disp->vblank, i, NVKM_DISP_HEAD_EVENT_VBLANK, true,
+ nv50_sw_chan_vblsem_release, &chan->vblank.notify[i]);
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
index 6d364d7b406a..b42289ce8826 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
@@ -5,12 +5,12 @@
#include "priv.h"
#include "chan.h"
#include "nvsw.h"
-#include <core/notify.h>
+#include <core/event.h>
struct nv50_sw_chan {
struct nvkm_sw_chan base;
struct {
- struct nvkm_notify notify[4];
+ struct nvkm_event_ntfy notify[4];
u32 ctxdma;
u64 offset;
u32 value;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
index 33dd03fff3c4..f5affa1c8f34 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
@@ -27,33 +27,34 @@
#include <nvif/if0004.h>
static int
-nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+nvkm_nvsw_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
{
- struct nvkm_nvsw *nvsw = nvkm_nvsw(object);
- if (nvsw->func->mthd)
- return nvsw->func->mthd(nvsw, mthd, data, size);
- return -ENODEV;
+ union nv04_nvsw_event_args *args = argv;
+
+ if (!uevent)
+ return 0;
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ return nvkm_uevent_add(uevent, &nvkm_nvsw(object)->chan->event, 0,
+ NVKM_SW_CHAN_EVENT_PAGE_FLIP, NULL);
}
static int
-nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd,
- struct nvkm_event **pevent)
+nvkm_nvsw_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
{
struct nvkm_nvsw *nvsw = nvkm_nvsw(object);
- switch (mthd) {
- case NV04_NVSW_NTFY_UEVENT:
- *pevent = &nvsw->chan->event;
- return 0;
- default:
- break;
- }
- return -EINVAL;
+
+ if (nvsw->func->mthd)
+ return nvsw->func->mthd(nvsw, mthd, data, size);
+
+ return -ENODEV;
}
static const struct nvkm_object_func
nvkm_nvsw_ = {
- .mthd = nvkm_nvsw_mthd_,
- .ntfy = nvkm_nvsw_ntfy_,
+ .mthd = nvkm_nvsw_mthd,
+ .uevent = nvkm_nvsw_uevent,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild
index d79d783904ee..9ffe7b921ccb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild
@@ -1,6 +1,12 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/falcon/base.o
nvkm-y += nvkm/falcon/cmdq.o
+nvkm-y += nvkm/falcon/fw.o
nvkm-y += nvkm/falcon/msgq.o
nvkm-y += nvkm/falcon/qmgr.o
nvkm-y += nvkm/falcon/v1.o
+
+nvkm-y += nvkm/falcon/gm200.o
+nvkm-y += nvkm/falcon/gp102.o
+nvkm-y += nvkm/falcon/ga100.o
+nvkm-y += nvkm/falcon/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
index f3f90c1063dd..235149f73a69 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
@@ -22,119 +22,217 @@
#include "priv.h"
#include <subdev/mc.h>
+#include <subdev/timer.h>
#include <subdev/top.h>
-void
-nvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start,
- u32 size, u16 tag, u8 port, bool secure)
+static const struct nvkm_falcon_func_dma *
+nvkm_falcon_dma(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base)
{
- if (secure && !falcon->secret) {
- nvkm_warn(falcon->user,
- "writing with secure tag on a non-secure falcon!\n");
- return;
+ switch (*mem_type) {
+ case IMEM: return falcon->func->imem_dma;
+ case DMEM: return falcon->func->dmem_dma;
+ default:
+ return NULL;
}
-
- falcon->func->load_imem(falcon, data, start, size, tag, port,
- secure);
}
-void
-nvkm_falcon_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start,
- u32 size, u8 port)
+int
+nvkm_falcon_dma_wr(struct nvkm_falcon *falcon, const u8 *img, u64 dma_addr, u32 dma_base,
+ enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec)
{
- mutex_lock(&falcon->dmem_mutex);
-
- falcon->func->load_dmem(falcon, data, start, size, port);
+ const struct nvkm_falcon_func_dma *dma = nvkm_falcon_dma(falcon, &mem_type, &mem_base);
+ const char *type = nvkm_falcon_mem(mem_type);
+ const int dmalen = 256;
+ u32 dma_start = 0;
+ u32 dst, src, cmd;
+ int ret, i;
+
+ if (WARN_ON(!dma->xfer))
+ return -EINVAL;
+
+ if (mem_type == DMEM) {
+ dma_start = dma_base;
+ dma_addr += dma_base;
+ }
- mutex_unlock(&falcon->dmem_mutex);
-}
+ FLCN_DBG(falcon, "%s %08x <- %08x bytes at %08x (%010llx %08x)",
+ type, mem_base, len, dma_base, dma_addr - dma_base, dma_start);
+ if (WARN_ON(!len || (len & (dmalen - 1))))
+ return -EINVAL;
-void
-nvkm_falcon_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, u8 port,
- void *data)
-{
- mutex_lock(&falcon->dmem_mutex);
+ ret = dma->init(falcon, dma_addr, dmalen, mem_type, sec, &cmd);
+ if (ret)
+ return ret;
- falcon->func->read_dmem(falcon, start, size, port, data);
+ dst = mem_base;
+ src = dma_base;
+ if (len) {
+ while (len >= dmalen) {
+ dma->xfer(falcon, dst, src - dma_start, cmd);
+
+ if (img && nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) {
+ for (i = 0; i < dmalen; i += 4, mem_base += 4) {
+ const int w = 8, x = (i / 4) % w;
+
+ if (x == 0)
+ printk(KERN_INFO "%s %08x <-", type, mem_base);
+ printk(KERN_CONT " %08x", *(u32 *)(img + src + i));
+ if (x == (w - 1) || ((i + 4) == dmalen))
+ printk(KERN_CONT " <- %08x+%08x", dma_base,
+ src + i - dma_base - (x * 4));
+ if (i == (7 * 4))
+ printk(KERN_CONT " *");
+ }
+ }
+
+ if (nvkm_msec(falcon->owner->device, 2000,
+ if (dma->done(falcon))
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+
+ src += dmalen;
+ dst += dmalen;
+ len -= dmalen;
+ }
+ WARN_ON(len);
+ }
- mutex_unlock(&falcon->dmem_mutex);
+ return 0;
}
-void
-nvkm_falcon_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *inst)
+static const struct nvkm_falcon_func_pio *
+nvkm_falcon_pio(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base)
{
- if (!falcon->func->bind_context) {
- nvkm_error(falcon->user,
- "Context binding not supported on this falcon!\n");
- return;
+ switch (*mem_type) {
+ case IMEM:
+ return falcon->func->imem_pio;
+ case DMEM:
+ if (!falcon->func->emem_addr || *mem_base < falcon->func->emem_addr)
+ return falcon->func->dmem_pio;
+
+ *mem_base -= falcon->func->emem_addr;
+ fallthrough;
+ case EMEM:
+ return falcon->func->emem_pio;
+ default:
+ return NULL;
}
-
- falcon->func->bind_context(falcon, inst);
}
-void
-nvkm_falcon_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr)
+int
+nvkm_falcon_pio_rd(struct nvkm_falcon *falcon, u8 port, enum nvkm_falcon_mem mem_type, u32 mem_base,
+ const u8 *img, u32 img_base, int len)
{
- falcon->func->set_start_addr(falcon, start_addr);
-}
+ const struct nvkm_falcon_func_pio *pio = nvkm_falcon_pio(falcon, &mem_type, &mem_base);
+ const char *type = nvkm_falcon_mem(mem_type);
+ int xfer_len;
+
+ if (WARN_ON(!pio || !pio->rd))
+ return -EINVAL;
+
+ FLCN_DBG(falcon, "%s %08x -> %08x bytes at %08x", type, mem_base, len, img_base);
+ if (WARN_ON(!len || (len & (pio->min - 1))))
+ return -EINVAL;
+
+ pio->rd_init(falcon, port, mem_base);
+ do {
+ xfer_len = min(len, pio->max);
+ pio->rd(falcon, port, img, xfer_len);
+
+ if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) {
+ for (img_base = 0; img_base < xfer_len; img_base += 4, mem_base += 4) {
+ if (((img_base / 4) % 8) == 0)
+ printk(KERN_INFO "%s %08x ->", type, mem_base);
+ printk(KERN_CONT " %08x", *(u32 *)(img + img_base));
+ }
+ }
+
+ img += xfer_len;
+ len -= xfer_len;
+ } while (len);
-void
-nvkm_falcon_start(struct nvkm_falcon *falcon)
-{
- falcon->func->start(falcon);
+ return 0;
}
int
-nvkm_falcon_enable(struct nvkm_falcon *falcon)
+nvkm_falcon_pio_wr(struct nvkm_falcon *falcon, const u8 *img, u32 img_base, u8 port,
+ enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec)
{
- struct nvkm_device *device = falcon->owner->device;
- int ret;
-
- nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst);
- ret = falcon->func->enable(falcon);
- if (ret) {
- nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst);
- return ret;
- }
+ const struct nvkm_falcon_func_pio *pio = nvkm_falcon_pio(falcon, &mem_type, &mem_base);
+ const char *type = nvkm_falcon_mem(mem_type);
+ int xfer_len;
+
+ if (WARN_ON(!pio || !pio->wr))
+ return -EINVAL;
+
+ FLCN_DBG(falcon, "%s %08x <- %08x bytes at %08x", type, mem_base, len, img_base);
+ if (WARN_ON(!len || (len & (pio->min - 1))))
+ return -EINVAL;
+
+ pio->wr_init(falcon, port, sec, mem_base);
+ do {
+ xfer_len = min(len, pio->max);
+ pio->wr(falcon, port, img, xfer_len, tag++);
+
+ if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) {
+ for (img_base = 0; img_base < xfer_len; img_base += 4, mem_base += 4) {
+ if (((img_base / 4) % 8) == 0)
+ printk(KERN_INFO "%s %08x <-", type, mem_base);
+ printk(KERN_CONT " %08x", *(u32 *)(img + img_base));
+ if ((img_base / 4) == 7 && mem_type == IMEM)
+ printk(KERN_CONT " %04x", tag - 1);
+ }
+ }
+
+ img += xfer_len;
+ len -= xfer_len;
+ } while (len);
return 0;
}
void
-nvkm_falcon_disable(struct nvkm_falcon *falcon)
+nvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start,
+ u32 size, u16 tag, u8 port, bool secure)
{
- struct nvkm_device *device = falcon->owner->device;
-
- /* already disabled, return or wait_idle will timeout */
- if (!nvkm_mc_enabled(device, falcon->owner->type, falcon->owner->inst))
+ if (secure && !falcon->secret) {
+ nvkm_warn(falcon->user,
+ "writing with secure tag on a non-secure falcon!\n");
return;
+ }
- falcon->func->disable(falcon);
-
- nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst);
+ falcon->func->load_imem(falcon, data, start, size, tag, port,
+ secure);
}
-int
-nvkm_falcon_reset(struct nvkm_falcon *falcon)
+void
+nvkm_falcon_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start,
+ u32 size, u8 port)
{
- if (!falcon->func->reset) {
- nvkm_falcon_disable(falcon);
- return nvkm_falcon_enable(falcon);
- }
+ mutex_lock(&falcon->dmem_mutex);
- return falcon->func->reset(falcon);
+ falcon->func->load_dmem(falcon, data, start, size, port);
+
+ mutex_unlock(&falcon->dmem_mutex);
}
-int
-nvkm_falcon_wait_for_halt(struct nvkm_falcon *falcon, u32 ms)
+void
+nvkm_falcon_start(struct nvkm_falcon *falcon)
{
- return falcon->func->wait_for_halt(falcon, ms);
+ falcon->func->start(falcon);
}
int
-nvkm_falcon_clear_interrupt(struct nvkm_falcon *falcon, u32 mask)
+nvkm_falcon_reset(struct nvkm_falcon *falcon)
{
- return falcon->func->clear_interrupt(falcon, mask);
+ int ret;
+
+ ret = falcon->func->disable(falcon);
+ if (WARN_ON(ret))
+ return ret;
+
+ return nvkm_falcon_enable(falcon);
}
static int
@@ -169,7 +267,7 @@ nvkm_falcon_oneinit(struct nvkm_falcon *falcon)
}
void
-nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user)
+nvkm_falcon_put(struct nvkm_falcon *falcon, struct nvkm_subdev *user)
{
if (unlikely(!falcon))
return;
@@ -183,7 +281,7 @@ nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user)
}
int
-nvkm_falcon_get(struct nvkm_falcon *falcon, const struct nvkm_subdev *user)
+nvkm_falcon_get(struct nvkm_falcon *falcon, struct nvkm_subdev *user)
{
int ret = 0;
@@ -217,6 +315,7 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func,
falcon->owner = subdev;
falcon->name = name;
falcon->addr = addr;
+ falcon->addr2 = func->addr2;
mutex_init(&falcon->mutex);
mutex_init(&falcon->dmem_mutex);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c
index 44cf6a8862e1..211ebe7afac6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c
@@ -51,7 +51,7 @@ static void
nvkm_falcon_cmdq_push(struct nvkm_falcon_cmdq *cmdq, void *data, u32 size)
{
struct nvkm_falcon *falcon = cmdq->qmgr->falcon;
- nvkm_falcon_load_dmem(falcon, data, cmdq->position, size, 0);
+ nvkm_falcon_pio_wr(falcon, data, 0, 0, DMEM, cmdq->position, size, 0, false);
cmdq->position += ALIGN(size, QUEUE_ALIGNMENT);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c
new file mode 100644
index 000000000000..80a480b12174
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <core/memory.h>
+#include <subdev/mmu.h>
+
+#include <nvfw/fw.h>
+#include <nvfw/hs.h>
+
+int
+nvkm_falcon_fw_patch(struct nvkm_falcon_fw *fw)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ u32 sig_base_src = fw->sig_base_prd;
+ u32 src, dst, len, i;
+ int idx = 0;
+
+ FLCNFW_DBG(fw, "patching sigs:%d size:%d", fw->sig_nr, fw->sig_size);
+ if (fw->func->signature) {
+ idx = fw->func->signature(fw, &sig_base_src);
+ if (idx < 0)
+ return idx;
+ }
+
+ src = idx * fw->sig_size;
+ dst = fw->sig_base_img;
+ len = fw->sig_size / 4;
+ FLCNFW_DBG(fw, "patch idx:%d src:%08x dst:%08x", idx, sig_base_src + src, dst);
+ for (i = 0; i < len; i++) {
+ u32 sig = *(u32 *)(fw->sigs + src);
+
+ if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) {
+ if (i % 8 == 0)
+ printk(KERN_INFO "sig -> %08x:", dst);
+ printk(KERN_CONT " %08x", sig);
+ }
+
+ *(u32 *)(fw->fw.img + dst) = sig;
+ src += 4;
+ dst += 4;
+ }
+
+ return 0;
+}
+
+static void
+nvkm_falcon_fw_dtor_sigs(struct nvkm_falcon_fw *fw)
+{
+ kfree(fw->sigs);
+ fw->sigs = NULL;
+}
+
+int
+nvkm_falcon_fw_boot(struct nvkm_falcon_fw *fw, struct nvkm_subdev *user,
+ bool release, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ int ret;
+
+ ret = nvkm_falcon_get(falcon, user);
+ if (ret)
+ return ret;
+
+ if (fw->sigs) {
+ ret = nvkm_falcon_fw_patch(fw);
+ if (ret)
+ goto done;
+
+ nvkm_falcon_fw_dtor_sigs(fw);
+ }
+
+ FLCNFW_DBG(fw, "resetting");
+ fw->func->reset(fw);
+
+ FLCNFW_DBG(fw, "loading");
+ if (fw->func->setup) {
+ ret = fw->func->setup(fw);
+ if (ret)
+ goto done;
+ }
+
+ ret = fw->func->load(fw);
+ if (ret)
+ goto done;
+
+ FLCNFW_DBG(fw, "booting");
+ ret = fw->func->boot(fw, pmbox0, pmbox1, mbox0_ok, irqsclr);
+ if (ret)
+ FLCNFW_ERR(fw, "boot failed: %d", ret);
+ else
+ FLCNFW_DBG(fw, "booted");
+
+done:
+ if (ret || release)
+ nvkm_falcon_put(falcon, user);
+ return ret;
+}
+
+int
+nvkm_falcon_fw_oneinit(struct nvkm_falcon_fw *fw, struct nvkm_falcon *falcon,
+ struct nvkm_vmm *vmm, struct nvkm_memory *inst)
+{
+ int ret;
+
+ fw->falcon = falcon;
+ fw->vmm = nvkm_vmm_ref(vmm);
+ fw->inst = nvkm_memory_ref(inst);
+
+ if (fw->boot) {
+ FLCN_DBG(falcon, "mapping %s fw", fw->fw.name);
+ ret = nvkm_vmm_get(fw->vmm, 12, nvkm_memory_size(&fw->fw.mem.memory), &fw->vma);
+ if (ret) {
+ FLCN_ERR(falcon, "get %d", ret);
+ return ret;
+ }
+
+ ret = nvkm_memory_map(&fw->fw.mem.memory, 0, fw->vmm, fw->vma, NULL, 0);
+ if (ret) {
+ FLCN_ERR(falcon, "map %d", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void
+nvkm_falcon_fw_dtor(struct nvkm_falcon_fw *fw)
+{
+ nvkm_vmm_put(fw->vmm, &fw->vma);
+ nvkm_vmm_unref(&fw->vmm);
+ nvkm_memory_unref(&fw->inst);
+ nvkm_falcon_fw_dtor_sigs(fw);
+ nvkm_firmware_dtor(&fw->fw);
+}
+
+static const struct nvkm_firmware_func
+nvkm_falcon_fw_dma = {
+ .type = NVKM_FIRMWARE_IMG_DMA,
+};
+
+static const struct nvkm_firmware_func
+nvkm_falcon_fw = {
+ .type = NVKM_FIRMWARE_IMG_RAM,
+};
+
+int
+nvkm_falcon_fw_sign(struct nvkm_falcon_fw *fw, u32 sig_base_img, u32 sig_size, const u8 *sigs,
+ int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg)
+{
+ fw->sig_base_prd = sig_base_prd;
+ fw->sig_base_dbg = sig_base_dbg;
+ fw->sig_base_img = sig_base_img;
+ fw->sig_size = sig_size;
+ fw->sig_nr = sig_nr_prd + sig_nr_dbg;
+
+ fw->sigs = kmalloc_array(fw->sig_nr, fw->sig_size, GFP_KERNEL);
+ if (!fw->sigs)
+ return -ENOMEM;
+
+ memcpy(fw->sigs, sigs + sig_base_prd, sig_nr_prd * fw->sig_size);
+ if (sig_nr_dbg)
+ memcpy(fw->sigs + sig_size, sigs + sig_base_dbg, sig_nr_dbg * fw->sig_size);
+
+ return 0;
+}
+
+int
+nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *func, const char *name,
+ struct nvkm_device *device, bool dma, const void *src, u32 len,
+ struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw)
+{
+ const struct nvkm_firmware_func *type = dma ? &nvkm_falcon_fw_dma : &nvkm_falcon_fw;
+ int ret;
+
+ fw->func = func;
+
+ ret = nvkm_firmware_ctor(type, name, device, src, len, &fw->fw);
+ if (ret)
+ return ret;
+
+ return falcon ? nvkm_falcon_fw_oneinit(fw, falcon, NULL, NULL) : 0;
+}
+
+int
+nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *func, const char *name,
+ struct nvkm_subdev *subdev, const char *bl, const char *img, int ver,
+ struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw)
+{
+ const struct firmware *blob;
+ const struct nvfw_bin_hdr *hdr;
+ const struct nvfw_hs_header *hshdr;
+ const struct nvfw_hs_load_header *lhdr;
+ const struct nvfw_bl_desc *desc;
+ u32 loc, sig;
+ int ret;
+
+ ret = nvkm_firmware_load_name(subdev, img, "", ver, &blob);
+ if (ret)
+ return ret;
+
+ hdr = nvfw_bin_hdr(subdev, blob->data);
+ hshdr = nvfw_hs_header(subdev, blob->data + hdr->header_offset);
+
+ ret = nvkm_falcon_fw_ctor(func, name, subdev->device, bl != NULL,
+ blob->data + hdr->data_offset, hdr->data_size, falcon, fw);
+ if (ret)
+ goto done;
+
+ /* Earlier FW releases by NVIDIA for Nouveau's use aren't in NVIDIA's
+ * standard format, and don't have the indirection seen in the 0x10de
+ * case.
+ */
+ switch (hdr->bin_magic) {
+ case 0x000010de:
+ loc = *(u32 *)(blob->data + hshdr->patch_loc);
+ sig = *(u32 *)(blob->data + hshdr->patch_sig);
+ break;
+ case 0x3b1d14f0:
+ loc = hshdr->patch_loc;
+ sig = hshdr->patch_sig;
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = nvkm_falcon_fw_sign(fw, loc, hshdr->sig_prod_size, blob->data,
+ 1, hshdr->sig_prod_offset + sig,
+ 1, hshdr->sig_dbg_offset + sig);
+ if (ret)
+ goto done;
+
+ lhdr = nvfw_hs_load_header(subdev, blob->data + hshdr->hdr_offset);
+
+ fw->nmem_base_img = 0;
+ fw->nmem_base = lhdr->non_sec_code_off;
+ fw->nmem_size = lhdr->non_sec_code_size;
+
+ fw->imem_base_img = lhdr->apps[0];
+ fw->imem_base = ALIGN(lhdr->apps[0], 0x100);
+ fw->imem_size = lhdr->apps[lhdr->num_apps + 0];
+
+ fw->dmem_base_img = lhdr->data_dma_base;
+ fw->dmem_base = 0;
+ fw->dmem_size = lhdr->data_size;
+ fw->dmem_sign = loc - lhdr->data_dma_base;
+
+ if (bl) {
+ nvkm_firmware_put(blob);
+
+ ret = nvkm_firmware_load_name(subdev, bl, "", ver, &blob);
+ if (ret)
+ return ret;
+
+ hdr = nvfw_bin_hdr(subdev, blob->data);
+ desc = nvfw_bl_desc(subdev, blob->data + hdr->header_offset);
+
+ fw->boot_addr = desc->start_tag << 8;
+ fw->boot_size = desc->code_size;
+ fw->boot = kmemdup(blob->data + hdr->data_offset + desc->code_off,
+ fw->boot_size, GFP_KERNEL);
+ if (!fw->boot)
+ ret = -ENOMEM;
+ } else {
+ fw->boot_addr = fw->nmem_base;
+ }
+
+done:
+ if (ret)
+ nvkm_falcon_fw_dtor(fw);
+
+ nvkm_firmware_put(blob);
+ return ret;
+}
+
+int
+nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *func, const char *name,
+ struct nvkm_subdev *subdev, const char *img, int ver,
+ struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw)
+{
+ const struct nvfw_bin_hdr *hdr;
+ const struct nvfw_hs_header_v2 *hshdr;
+ const struct nvfw_hs_load_header_v2 *lhdr;
+ const struct firmware *blob;
+ u32 loc, sig, cnt, *meta;
+ int ret;
+
+ ret = nvkm_firmware_load_name(subdev, img, "", ver, &blob);
+ if (ret)
+ return ret;
+
+ hdr = nvfw_bin_hdr(subdev, blob->data);
+ hshdr = nvfw_hs_header_v2(subdev, blob->data + hdr->header_offset);
+ meta = (u32 *)(blob->data + hshdr->meta_data_offset);
+ loc = *(u32 *)(blob->data + hshdr->patch_loc);
+ sig = *(u32 *)(blob->data + hshdr->patch_sig);
+ cnt = *(u32 *)(blob->data + hshdr->num_sig);
+
+ ret = nvkm_falcon_fw_ctor(func, name, subdev->device, true,
+ blob->data + hdr->data_offset, hdr->data_size, falcon, fw);
+ if (ret)
+ goto done;
+
+ ret = nvkm_falcon_fw_sign(fw, loc, hshdr->sig_prod_size / cnt, blob->data,
+ cnt, hshdr->sig_prod_offset + sig, 0, 0);
+ if (ret)
+ goto done;
+
+ lhdr = nvfw_hs_load_header_v2(subdev, blob->data + hshdr->header_offset);
+
+ fw->imem_base_img = lhdr->app[0].offset;
+ fw->imem_base = 0;
+ fw->imem_size = lhdr->app[0].size;
+
+ fw->dmem_base_img = lhdr->os_data_offset;
+ fw->dmem_base = 0;
+ fw->dmem_size = lhdr->os_data_size;
+ fw->dmem_sign = loc - lhdr->os_data_offset;
+
+ fw->boot_addr = lhdr->app[0].offset;
+
+ fw->fuse_ver = meta[0];
+ fw->engine_id = meta[1];
+ fw->ucode_id = meta[2];
+
+done:
+ if (ret)
+ nvkm_falcon_fw_dtor(fw);
+
+ nvkm_firmware_put(blob);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c
new file mode 100644
index 000000000000..49fd32943916
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+int
+ga100_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *src_base_src)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ struct nvkm_device *device = falcon->owner->device;
+ u32 reg_fuse_version;
+ int idx;
+
+ FLCN_DBG(falcon, "brom: %08x %08x", fw->engine_id, fw->ucode_id);
+ FLCN_DBG(falcon, "fuse_version: %d", fw->fuse_ver);
+
+ if (fw->engine_id & 0x00000001) {
+ reg_fuse_version = nvkm_rd32(device, 0x824140 + (fw->ucode_id - 1) * 4);
+ } else
+ if (fw->engine_id & 0x00000004) {
+ reg_fuse_version = nvkm_rd32(device, 0x824100 + (fw->ucode_id - 1) * 4);
+ } else
+ if (fw->engine_id & 0x00000400) {
+ reg_fuse_version = nvkm_rd32(device, 0x8241c0 + (fw->ucode_id - 1) * 4);
+ } else {
+ WARN_ON(1);
+ return -ENOSYS;
+ }
+
+ FLCN_DBG(falcon, "reg_fuse_version: %08x", reg_fuse_version);
+ if (reg_fuse_version) {
+ reg_fuse_version = fls(reg_fuse_version);
+ FLCN_DBG(falcon, "reg_fuse_version: %d", reg_fuse_version);
+
+ if (WARN_ON(fw->fuse_ver < reg_fuse_version))
+ return -EINVAL;
+
+ idx = fw->fuse_ver - reg_fuse_version;
+ } else {
+ idx = fw->sig_nr - 1;
+ }
+
+ return idx;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c
new file mode 100644
index 000000000000..0ff450fe3590
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+static bool
+ga102_flcn_dma_done(struct nvkm_falcon *falcon)
+{
+ return !!(nvkm_falcon_rd32(falcon, 0x118) & 0x00000002);
+}
+
+static void
+ga102_flcn_dma_xfer(struct nvkm_falcon *falcon, u32 mem_base, u32 dma_base, u32 cmd)
+{
+ nvkm_falcon_wr32(falcon, 0x114, mem_base);
+ nvkm_falcon_wr32(falcon, 0x11c, dma_base);
+ nvkm_falcon_wr32(falcon, 0x118, cmd);
+}
+
+static int
+ga102_flcn_dma_init(struct nvkm_falcon *falcon, u64 dma_addr, int xfer_len,
+ enum nvkm_falcon_mem mem_type, bool sec, u32 *cmd)
+{
+ *cmd = (ilog2(xfer_len) - 2) << 8;
+ if (mem_type == IMEM)
+ *cmd |= 0x00000010;
+ if (sec)
+ *cmd |= 0x00000004;
+
+ nvkm_falcon_wr32(falcon, 0x110, dma_addr >> 8);
+ nvkm_falcon_wr32(falcon, 0x128, 0x00000000);
+ return 0;
+}
+
+const struct nvkm_falcon_func_dma
+ga102_flcn_dma = {
+ .init = ga102_flcn_dma_init,
+ .xfer = ga102_flcn_dma_xfer,
+ .done = ga102_flcn_dma_done,
+};
+
+int
+ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon)
+{
+ nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000);
+
+ if (nvkm_msec(falcon->owner->device, 20,
+ if (!(nvkm_falcon_rd32(falcon, 0x0f4) & 0x00001000))
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int
+ga102_flcn_reset_prep(struct nvkm_falcon *falcon)
+{
+ nvkm_falcon_rd32(falcon, 0x0f4);
+
+ nvkm_usec(falcon->owner->device, 150,
+ if (nvkm_falcon_rd32(falcon, 0x0f4) & 0x80000000)
+ break;
+ _warn = false;
+ );
+
+ return 0;
+}
+
+int
+ga102_flcn_select(struct nvkm_falcon *falcon)
+{
+ if ((nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000010) != 0x00000000) {
+ nvkm_falcon_wr32(falcon, falcon->addr2 + 0x668, 0x00000000);
+ if (nvkm_msec(falcon->owner->device, 10,
+ if (nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000001)
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int
+ga102_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+
+ nvkm_falcon_wr32(falcon, falcon->addr2 + 0x210, fw->dmem_sign);
+ nvkm_falcon_wr32(falcon, falcon->addr2 + 0x19c, fw->engine_id);
+ nvkm_falcon_wr32(falcon, falcon->addr2 + 0x198, fw->ucode_id);
+ nvkm_falcon_wr32(falcon, falcon->addr2 + 0x180, 0x00000001);
+
+ return gm200_flcn_fw_boot(fw, mbox0, mbox1, mbox0_ok, irqsclr);
+}
+
+int
+ga102_flcn_fw_load(struct nvkm_falcon_fw *fw)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ int ret = 0;
+
+ nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080);
+ nvkm_falcon_wr32(falcon, 0x10c, 0x00000000);
+ nvkm_falcon_mask(falcon, 0x600, 0x00010007, (0 << 16) | (1 << 2) | 1);
+
+ ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->imem_base_img,
+ IMEM, fw->imem_base, fw->imem_size, true);
+ if (ret)
+ return ret;
+
+ ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->dmem_base_img,
+ DMEM, fw->dmem_base, fw->dmem_size, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+const struct nvkm_falcon_fw_func
+ga102_flcn_fw = {
+ .signature = ga100_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .load = ga102_flcn_fw_load,
+ .boot = ga102_flcn_fw_boot,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
new file mode 100644
index 000000000000..393ade9f7e6c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <core/memory.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+void
+gm200_flcn_tracepc(struct nvkm_falcon *falcon)
+{
+ u32 sctl = nvkm_falcon_rd32(falcon, 0x240);
+ u32 tidx = nvkm_falcon_rd32(falcon, 0x148);
+ int nr = (tidx & 0x00ff0000) >> 16, sp, ip;
+
+ FLCN_ERR(falcon, "TRACEPC SCTL %08x TIDX %08x", sctl, tidx);
+ for (sp = 0; sp < nr; sp++) {
+ nvkm_falcon_wr32(falcon, 0x148, sp);
+ ip = nvkm_falcon_rd32(falcon, 0x14c);
+ FLCN_ERR(falcon, "TRACEPC: %08x", ip);
+ }
+}
+
+static void
+gm200_flcn_pio_dmem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len)
+{
+ while (len >= 4) {
+ *(u32 *)img = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8));
+ img += 4;
+ len -= 4;
+ }
+}
+
+static void
+gm200_flcn_pio_dmem_rd_init(struct nvkm_falcon *falcon, u8 port, u32 dmem_base)
+{
+ nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), BIT(25) | dmem_base);
+}
+
+static void
+gm200_flcn_pio_dmem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
+{
+ while (len >= 4) {
+ nvkm_falcon_wr32(falcon, 0x1c4 + (port * 8), *(u32 *)img);
+ img += 4;
+ len -= 4;
+ }
+}
+
+static void
+gm200_flcn_pio_dmem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 dmem_base)
+{
+ nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), BIT(24) | dmem_base);
+}
+
+const struct nvkm_falcon_func_pio
+gm200_flcn_dmem_pio = {
+ .min = 4,
+ .max = 0x100,
+ .wr_init = gm200_flcn_pio_dmem_wr_init,
+ .wr = gm200_flcn_pio_dmem_wr,
+ .rd_init = gm200_flcn_pio_dmem_rd_init,
+ .rd = gm200_flcn_pio_dmem_rd,
+};
+
+static void
+gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 imem_base)
+{
+ nvkm_falcon_wr32(falcon, 0x180 + (port * 0x10), (sec ? BIT(28) : 0) | BIT(24) | imem_base);
+}
+
+static void
+gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
+{
+ nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++);
+ while (len >= 4) {
+ nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img);
+ img += 4;
+ len -= 4;
+ }
+}
+
+const struct nvkm_falcon_func_pio
+gm200_flcn_imem_pio = {
+ .min = 0x100,
+ .max = 0x100,
+ .wr_init = gm200_flcn_pio_imem_wr_init,
+ .wr = gm200_flcn_pio_imem_wr,
+};
+
+int
+gm200_flcn_bind_stat(struct nvkm_falcon *falcon, bool intr)
+{
+ if (intr && !(nvkm_falcon_rd32(falcon, 0x008) & 0x00000008))
+ return -1;
+
+ return (nvkm_falcon_rd32(falcon, 0x0dc) & 0x00007000) >> 12;
+}
+
+void
+gm200_flcn_bind_inst(struct nvkm_falcon *falcon, int target, u64 addr)
+{
+ nvkm_falcon_mask(falcon, 0x604, 0x00000007, 0x00000000); /* DMAIDX_VIRT */
+ nvkm_falcon_wr32(falcon, 0x054, (1 << 30) | (target << 28) | (addr >> 12));
+ nvkm_falcon_mask(falcon, 0x090, 0x00010000, 0x00010000);
+ nvkm_falcon_mask(falcon, 0x0a4, 0x00000008, 0x00000008);
+}
+
+int
+gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon)
+{
+ nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000);
+
+ if (nvkm_msec(falcon->owner->device, 10,
+ if (!(nvkm_falcon_rd32(falcon, 0x10c) & 0x00000006))
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int
+gm200_flcn_enable(struct nvkm_falcon *falcon)
+{
+ struct nvkm_device *device = falcon->owner->device;
+ int ret;
+
+ if (falcon->func->reset_eng) {
+ ret = falcon->func->reset_eng(falcon);
+ if (ret)
+ return ret;
+ }
+
+ if (falcon->func->select) {
+ ret = falcon->func->select(falcon);
+ if (ret)
+ return ret;
+ }
+
+ if (falcon->func->reset_pmc)
+ nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst);
+
+ ret = falcon->func->reset_wait_mem_scrubbing(falcon);
+ if (ret)
+ return ret;
+
+ nvkm_falcon_wr32(falcon, 0x084, nvkm_rd32(device, 0x000000));
+ return 0;
+}
+
+int
+gm200_flcn_disable(struct nvkm_falcon *falcon)
+{
+ struct nvkm_device *device = falcon->owner->device;
+ int ret;
+
+ if (falcon->func->select) {
+ ret = falcon->func->select(falcon);
+ if (ret)
+ return ret;
+ }
+
+ nvkm_falcon_mask(falcon, 0x048, 0x00000003, 0x00000000);
+ nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
+
+ if (falcon->func->reset_pmc) {
+ if (falcon->func->reset_prep) {
+ ret = falcon->func->reset_prep(falcon);
+ if (ret)
+ return ret;
+ }
+
+ nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst);
+ }
+
+ if (falcon->func->reset_eng) {
+ ret = falcon->func->reset_eng(falcon);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int
+gm200_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ u32 mbox0, mbox1;
+ int ret = 0;
+
+ nvkm_falcon_wr32(falcon, 0x040, pmbox0 ? *pmbox0 : 0xcafebeef);
+ if (pmbox1)
+ nvkm_falcon_wr32(falcon, 0x044, *pmbox1);
+
+ nvkm_falcon_wr32(falcon, 0x104, fw->boot_addr);
+ nvkm_falcon_wr32(falcon, 0x100, 0x00000002);
+
+ if (nvkm_msec(falcon->owner->device, 2000,
+ if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010)
+ break;
+ ) < 0)
+ ret = -ETIMEDOUT;
+
+ mbox0 = nvkm_falcon_rd32(falcon, 0x040);
+ mbox1 = nvkm_falcon_rd32(falcon, 0x044);
+ if (FLCN_ERRON(falcon, ret || mbox0 != mbox0_ok, "mbox %08x %08x", mbox0, mbox1))
+ ret = ret ?: -EIO;
+
+ if (irqsclr)
+ nvkm_falcon_mask(falcon, 0x004, 0xffffffff, irqsclr);
+
+ return ret;
+}
+
+int
+gm200_flcn_fw_load(struct nvkm_falcon_fw *fw)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ int target, ret;
+
+ if (fw->inst) {
+ nvkm_falcon_mask(falcon, 0x048, 0x00000001, 0x00000001);
+
+ switch (nvkm_memory_target(fw->inst)) {
+ case NVKM_MEM_TARGET_VRAM: target = 0; break;
+ case NVKM_MEM_TARGET_HOST: target = 2; break;
+ case NVKM_MEM_TARGET_NCOH: target = 3; break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ falcon->func->bind_inst(falcon, target, nvkm_memory_addr(fw->inst));
+
+ if (nvkm_msec(falcon->owner->device, 10,
+ if (falcon->func->bind_stat(falcon, falcon->func->bind_intr) == 5)
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+
+ nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008);
+ nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002);
+
+ if (nvkm_msec(falcon->owner->device, 10,
+ if (falcon->func->bind_stat(falcon, false) == 0)
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+ } else {
+ nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080);
+ nvkm_falcon_wr32(falcon, 0x10c, 0x00000000);
+ }
+
+ if (fw->boot) {
+ switch (nvkm_memory_target(&fw->fw.mem.memory)) {
+ case NVKM_MEM_TARGET_VRAM: target = 4; break;
+ case NVKM_MEM_TARGET_HOST: target = 5; break;
+ case NVKM_MEM_TARGET_NCOH: target = 6; break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ ret = nvkm_falcon_pio_wr(falcon, fw->boot, 0, 0,
+ IMEM, falcon->code.limit - fw->boot_size, fw->boot_size,
+ fw->boot_addr >> 8, false);
+ if (ret)
+ return ret;
+
+ return fw->func->load_bld(fw);
+ }
+
+ ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->nmem_base_img, fw->nmem_base_img, 0,
+ IMEM, fw->nmem_base, fw->nmem_size, fw->nmem_base >> 8, false);
+ if (ret)
+ return ret;
+
+ ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->imem_base_img, fw->imem_base_img, 0,
+ IMEM, fw->imem_base, fw->imem_size, fw->imem_base >> 8, true);
+ if (ret)
+ return ret;
+
+ ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->dmem_base_img, fw->dmem_base_img, 0,
+ DMEM, fw->dmem_base, fw->dmem_size, 0, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int
+gm200_flcn_fw_reset(struct nvkm_falcon_fw *fw)
+{
+ return nvkm_falcon_reset(fw->falcon);
+}
+
+int
+gm200_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *sig_base_src)
+{
+ struct nvkm_falcon *falcon = fw->falcon;
+ u32 addr = falcon->func->debug;
+ int ret = 0;
+
+ if (addr) {
+ ret = nvkm_falcon_enable(falcon);
+ if (ret)
+ return ret;
+
+ if (nvkm_falcon_rd32(falcon, addr) & 0x00100000) {
+ *sig_base_src = fw->sig_base_dbg;
+ return 1;
+ }
+ }
+
+ return ret;
+}
+
+const struct nvkm_falcon_fw_func
+gm200_flcn_fw = {
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .load = gm200_flcn_fw_load,
+ .boot = gm200_flcn_fw_boot,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c
new file mode 100644
index 000000000000..c774935f3077
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+static void
+gp102_flcn_pio_emem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len)
+{
+ while (len >= 4) {
+ *(u32 *)img = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8));
+ img += 4;
+ len -= 4;
+ }
+}
+
+static void
+gp102_flcn_pio_emem_rd_init(struct nvkm_falcon *falcon, u8 port, u32 dmem_base)
+{
+ nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), BIT(25) | dmem_base);
+}
+
+static void
+gp102_flcn_pio_emem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
+{
+ while (len >= 4) {
+ nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), *(u32 *)img);
+ img += 4;
+ len -= 4;
+ }
+}
+
+static void
+gp102_flcn_pio_emem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 emem_base)
+{
+ nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), BIT(24) | emem_base);
+}
+
+const struct nvkm_falcon_func_pio
+gp102_flcn_emem_pio = {
+ .min = 4,
+ .max = 0x100,
+ .wr_init = gp102_flcn_pio_emem_wr_init,
+ .wr = gp102_flcn_pio_emem_wr,
+ .rd_init = gp102_flcn_pio_emem_rd_init,
+ .rd = gp102_flcn_pio_emem_rd,
+};
+
+int
+gp102_flcn_reset_eng(struct nvkm_falcon *falcon)
+{
+ int ret;
+
+ if (falcon->func->reset_prep) {
+ ret = falcon->func->reset_prep(falcon);
+ if (ret)
+ return ret;
+ }
+
+ nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001);
+ udelay(10);
+ nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000);
+
+ return falcon->func->reset_wait_mem_scrubbing(falcon);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c
index e74371dffc76..16b246fda666 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c
@@ -25,7 +25,7 @@
static void
nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq)
{
- mutex_lock(&msgq->mutex);
+ spin_lock(&msgq->lock);
msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg);
}
@@ -37,10 +37,10 @@ nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit)
if (commit)
nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position);
- mutex_unlock(&msgq->mutex);
+ spin_unlock(&msgq->lock);
}
-static bool
+bool
nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq)
{
u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg);
@@ -68,7 +68,7 @@ nvkm_falcon_msgq_pop(struct nvkm_falcon_msgq *msgq, void *data, u32 size)
return -EINVAL;
}
- nvkm_falcon_read_dmem(falcon, tail, size, 0, data);
+ nvkm_falcon_pio_rd(falcon, 0, DMEM, tail, data, 0, size);
msgq->position += ALIGN(size, QUEUE_ALIGNMENT);
return 0;
}
@@ -208,6 +208,6 @@ nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name,
msgq->qmgr = qmgr;
msgq->name = name;
- mutex_init(&msgq->mutex);
+ spin_lock_init(&msgq->lock);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h
index 466188752eb0..11a24b9c8569 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h
@@ -2,4 +2,12 @@
#ifndef __NVKM_FALCON_PRIV_H__
#define __NVKM_FALCON_PRIV_H__
#include <core/falcon.h>
+
+static inline int
+nvkm_falcon_enable(struct nvkm_falcon *falcon)
+{
+ if (falcon->func->enable)
+ return falcon->func->enable(falcon);
+ return 0;
+}
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h
index 976cb7b7aa99..79f0da9e749f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h
@@ -73,7 +73,7 @@ struct nvkm_falcon_cmdq {
struct nvkm_falcon_msgq {
struct nvkm_falcon_qmgr *qmgr;
const char *name;
- struct mutex mutex;
+ spinlock_t lock;
u32 head_reg;
u32 tail_reg;
@@ -82,8 +82,7 @@ struct nvkm_falcon_msgq {
u32 position;
};
-#define FLCNQ_PRINTK(t,q,f,a...) \
- FLCN_PRINTK(t, (q)->qmgr->falcon, "%s: "f, (q)->name, ##a)
-#define FLCNQ_DBG(q,f,a...) FLCNQ_PRINTK(debug, (q), f, ##a)
-#define FLCNQ_ERR(q,f,a...) FLCNQ_PRINTK(error, (q), f, ##a)
+#define FLCNQ_PRINTK(q,l,p,f,a...) FLCN_PRINTK((q)->qmgr->falcon, l, p, "%s: "f, (q)->name, ##a)
+#define FLCNQ_DBG(q,f,a...) FLCNQ_PRINTK((q), DEBUG, info, f, ##a)
+#define FLCNQ_ERR(q,f,a...) FLCNQ_PRINTK((q), ERROR, err, f, ##a)
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c
index b0ee4c31414c..dd2ddc54ac60 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c
@@ -64,44 +64,13 @@ nvkm_falcon_v1_load_imem(struct nvkm_falcon *falcon, void *data, u32 start,
nvkm_falcon_wr32(falcon, 0x184 + (port * 16), 0);
}
-static void
-nvkm_falcon_v1_load_emem(struct nvkm_falcon *falcon, void *data, u32 start,
- u32 size, u8 port)
-{
- u8 rem = size % 4;
- int i;
-
- size -= rem;
-
- nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 24));
- for (i = 0; i < size / 4; i++)
- nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), ((u32 *)data)[i]);
-
- /*
- * If size is not a multiple of 4, mask the last word to ensure garbage
- * does not get written
- */
- if (rem) {
- u32 extra = ((u32 *)data)[i];
-
- nvkm_falcon_wr32(falcon, 0xac4 + (port * 8),
- extra & (BIT(rem * 8) - 1));
- }
-}
-
void
nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start,
u32 size, u8 port)
{
- const struct nvkm_falcon_func *func = falcon->func;
u8 rem = size % 4;
int i;
- if (func->emem_addr && start >= func->emem_addr)
- return nvkm_falcon_v1_load_emem(falcon, data,
- start - func->emem_addr, size,
- port);
-
size -= rem;
nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 24));
@@ -120,113 +89,6 @@ nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start,
}
}
-static void
-nvkm_falcon_v1_read_emem(struct nvkm_falcon *falcon, u32 start, u32 size,
- u8 port, void *data)
-{
- u8 rem = size % 4;
- int i;
-
- size -= rem;
-
- nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 25));
- for (i = 0; i < size / 4; i++)
- ((u32 *)data)[i] = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8));
-
- /*
- * If size is not a multiple of 4, mask the last word to ensure garbage
- * does not get read
- */
- if (rem) {
- u32 extra = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8));
-
- for (i = size; i < size + rem; i++) {
- ((u8 *)data)[i] = (u8)(extra & 0xff);
- extra >>= 8;
- }
- }
-}
-
-void
-nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size,
- u8 port, void *data)
-{
- const struct nvkm_falcon_func *func = falcon->func;
- u8 rem = size % 4;
- int i;
-
- if (func->emem_addr && start >= func->emem_addr)
- return nvkm_falcon_v1_read_emem(falcon, start - func->emem_addr,
- size, port, data);
-
- size -= rem;
-
- nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 25));
- for (i = 0; i < size / 4; i++)
- ((u32 *)data)[i] = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8));
-
- /*
- * If size is not a multiple of 4, mask the last word to ensure garbage
- * does not get read
- */
- if (rem) {
- u32 extra = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8));
-
- for (i = size; i < size + rem; i++) {
- ((u8 *)data)[i] = (u8)(extra & 0xff);
- extra >>= 8;
- }
- }
-}
-
-void
-nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx)
-{
- const u32 fbif = falcon->func->fbif;
- u32 inst_loc;
-
- /* disable instance block binding */
- if (ctx == NULL) {
- nvkm_falcon_wr32(falcon, 0x10c, 0x0);
- return;
- }
-
- nvkm_falcon_wr32(falcon, 0x10c, 0x1);
-
- /* setup apertures - virtual */
- nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_UCODE, 0x4);
- nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_VIRT, 0x0);
- /* setup apertures - physical */
- nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_VID, 0x4);
- nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_SYS_COH, 0x5);
- nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_SYS_NCOH, 0x6);
-
- /* Set context */
- switch (nvkm_memory_target(ctx)) {
- case NVKM_MEM_TARGET_VRAM: inst_loc = 0; break;
- case NVKM_MEM_TARGET_HOST: inst_loc = 2; break;
- case NVKM_MEM_TARGET_NCOH: inst_loc = 3; break;
- default:
- WARN_ON(1);
- return;
- }
-
- /* Enable context */
- nvkm_falcon_mask(falcon, 0x048, 0x1, 0x1);
- nvkm_falcon_wr32(falcon, 0x054,
- ((nvkm_memory_addr(ctx) >> 12) & 0xfffffff) |
- (inst_loc << 28) | (1 << 30));
-
- nvkm_falcon_mask(falcon, 0x090, 0x10000, 0x10000);
- nvkm_falcon_mask(falcon, 0x0a4, 0x8, 0x8);
-}
-
-void
-nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr)
-{
- nvkm_falcon_wr32(falcon, 0x104, start_addr);
-}
-
void
nvkm_falcon_v1_start(struct nvkm_falcon *falcon)
{
@@ -237,75 +99,3 @@ nvkm_falcon_v1_start(struct nvkm_falcon *falcon)
else
nvkm_falcon_wr32(falcon, 0x100, 0x2);
}
-
-int
-nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *falcon, u32 ms)
-{
- struct nvkm_device *device = falcon->owner->device;
- int ret;
-
- ret = nvkm_wait_msec(device, ms, falcon->addr + 0x100, 0x10, 0x10);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int
-nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *falcon, u32 mask)
-{
- struct nvkm_device *device = falcon->owner->device;
- int ret;
-
- /* clear interrupt(s) */
- nvkm_falcon_mask(falcon, 0x004, mask, mask);
- /* wait until interrupts are cleared */
- ret = nvkm_wait_msec(device, 10, falcon->addr + 0x008, mask, 0x0);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int
-falcon_v1_wait_idle(struct nvkm_falcon *falcon)
-{
- struct nvkm_device *device = falcon->owner->device;
- int ret;
-
- ret = nvkm_wait_msec(device, 10, falcon->addr + 0x04c, 0xffff, 0x0);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int
-nvkm_falcon_v1_enable(struct nvkm_falcon *falcon)
-{
- struct nvkm_device *device = falcon->owner->device;
- int ret;
-
- ret = nvkm_wait_msec(device, 10, falcon->addr + 0x10c, 0x6, 0x0);
- if (ret < 0) {
- nvkm_error(falcon->user, "Falcon mem scrubbing timeout\n");
- return ret;
- }
-
- ret = falcon_v1_wait_idle(falcon);
- if (ret)
- return ret;
-
- /* enable IRQs */
- nvkm_falcon_wr32(falcon, 0x010, 0xff);
-
- return 0;
-}
-
-void
-nvkm_falcon_v1_disable(struct nvkm_falcon *falcon)
-{
- /* disable IRQs and wait for any previous code to complete */
- nvkm_falcon_wr32(falcon, 0x014, 0xff);
- falcon_v1_wait_idle(falcon);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c
index bef790ad8f2f..83a9c48bc58c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c
+++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c
@@ -45,6 +45,47 @@ wpr_header_v1_dump(struct nvkm_subdev *subdev, const struct wpr_header_v1 *hdr)
nvkm_debug(subdev, "\tstatus : %d\n", hdr->status);
}
+void
+wpr_generic_header_dump(struct nvkm_subdev *subdev, const struct wpr_generic_header *hdr)
+{
+ nvkm_debug(subdev, "wprGenericHeader\n");
+ nvkm_debug(subdev, "\tidentifier : %04x\n", hdr->identifier);
+ nvkm_debug(subdev, "\tversion : %04x\n", hdr->version);
+ nvkm_debug(subdev, "\tsize : %08x\n", hdr->size);
+}
+
+void
+wpr_header_v2_dump(struct nvkm_subdev *subdev, const struct wpr_header_v2 *hdr)
+{
+ wpr_generic_header_dump(subdev, &hdr->hdr);
+ wpr_header_v1_dump(subdev, &hdr->wpr);
+}
+
+void
+lsb_header_v2_dump(struct nvkm_subdev *subdev, struct lsb_header_v2 *hdr)
+{
+ wpr_generic_header_dump(subdev, &hdr->hdr);
+ nvkm_debug(subdev, "lsbHeader\n");
+ nvkm_debug(subdev, "\tucodeOff : 0x%x\n", hdr->ucode_off);
+ nvkm_debug(subdev, "\tucodeSize : 0x%x\n", hdr->ucode_size);
+ nvkm_debug(subdev, "\tdataSize : 0x%x\n", hdr->data_size);
+ nvkm_debug(subdev, "\tblCodeSize : 0x%x\n", hdr->bl_code_size);
+ nvkm_debug(subdev, "\tblImemOff : 0x%x\n", hdr->bl_imem_off);
+ nvkm_debug(subdev, "\tblDataOff : 0x%x\n", hdr->bl_data_off);
+ nvkm_debug(subdev, "\tblDataSize : 0x%x\n", hdr->bl_data_size);
+ nvkm_debug(subdev, "\treserved0 : %08x\n", hdr->rsvd0);
+ nvkm_debug(subdev, "\tappCodeOff : 0x%x\n", hdr->app_code_off);
+ nvkm_debug(subdev, "\tappCodeSize : 0x%x\n", hdr->app_code_size);
+ nvkm_debug(subdev, "\tappDataOff : 0x%x\n", hdr->app_data_off);
+ nvkm_debug(subdev, "\tappDataSize : 0x%x\n", hdr->app_data_size);
+ nvkm_debug(subdev, "\tappImemOffset : 0x%x\n", hdr->app_imem_offset);
+ nvkm_debug(subdev, "\tappDmemOffset : 0x%x\n", hdr->app_dmem_offset);
+ nvkm_debug(subdev, "\tflags : 0x%x\n", hdr->flags);
+ nvkm_debug(subdev, "\tmonitorCodeOff: 0x%x\n", hdr->monitor_code_offset);
+ nvkm_debug(subdev, "\tmonitorDataOff: 0x%x\n", hdr->monitor_data_offset);
+ nvkm_debug(subdev, "\tmanifestOffset: 0x%x\n", hdr->manifest_offset);
+}
+
static void
lsb_header_tail_dump(struct nvkm_subdev *subdev, struct lsb_header_tail *hdr)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c
index 04ed77cb2eba..a7e0583401d0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c
+++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c
@@ -38,6 +38,24 @@ nvfw_hs_header(struct nvkm_subdev *subdev, const void *data)
return hdr;
}
+const struct nvfw_hs_header_v2 *
+nvfw_hs_header_v2(struct nvkm_subdev *subdev, const void *data)
+{
+ const struct nvfw_hs_header_v2 *hdr = data;
+
+ nvkm_debug(subdev, "hsHeader:\n");
+ nvkm_debug(subdev, "\tsigProdOffset : 0x%x\n", hdr->sig_prod_offset);
+ nvkm_debug(subdev, "\tsigProdSize : 0x%x\n", hdr->sig_prod_size);
+ nvkm_debug(subdev, "\tpatchLoc : 0x%x\n", hdr->patch_loc);
+ nvkm_debug(subdev, "\tpatchSig : 0x%x\n", hdr->patch_sig);
+ nvkm_debug(subdev, "\tmetadataOffset : 0x%x\n", hdr->meta_data_offset);
+ nvkm_debug(subdev, "\tmetadataSize : 0x%x\n", hdr->meta_data_size);
+ nvkm_debug(subdev, "\tnumSig : 0x%x\n", hdr->num_sig);
+ nvkm_debug(subdev, "\theaderOffset : 0x%x\n", hdr->header_offset);
+ nvkm_debug(subdev, "\theaderSize : 0x%x\n", hdr->header_size);
+ return hdr;
+}
+
const struct nvfw_hs_load_header *
nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data)
{
@@ -60,3 +78,24 @@ nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data)
return hdr;
}
+
+const struct nvfw_hs_load_header_v2 *
+nvfw_hs_load_header_v2(struct nvkm_subdev *subdev, const void *data)
+{
+ const struct nvfw_hs_load_header_v2 *hdr = data;
+ int i;
+
+ nvkm_debug(subdev, "hsLoadHeader:\n");
+ nvkm_debug(subdev, "\tosCodeOffset : 0x%x\n", hdr->os_code_offset);
+ nvkm_debug(subdev, "\tosCodeSize : 0x%x\n", hdr->os_code_size);
+ nvkm_debug(subdev, "\tosDataOffset : 0x%x\n", hdr->os_data_offset);
+ nvkm_debug(subdev, "\tosDataSize : 0x%x\n", hdr->os_data_size);
+ nvkm_debug(subdev, "\tnumApps : 0x%x\n", hdr->num_apps);
+ for (i = 0; i < hdr->num_apps; i++) {
+ nvkm_debug(subdev,
+ "\tApp[%d] : offset 0x%x size 0x%x\n", i,
+ hdr->app[i].offset, hdr->app[i].size);
+ }
+
+ return hdr;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c
index b847f281ce97..45c3a6c5e088 100644
--- a/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c
+++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c
@@ -106,3 +106,75 @@ nvfw_ls_desc_v1(struct nvkm_subdev *subdev, const void *data)
return hdr;
}
+
+const struct nvfw_ls_desc_v2 *
+nvfw_ls_desc_v2(struct nvkm_subdev *subdev, const void *data)
+{
+ const struct nvfw_ls_desc_v2 *hdr = data;
+ char *date;
+ int i;
+
+ nvkm_debug(subdev, "lsUcodeImgDesc:\n");
+ nvkm_debug(subdev, "\tdescriptorSize : %d\n", hdr->descriptor_size);
+ nvkm_debug(subdev, "\timageSize : %d\n", hdr->image_size);
+ nvkm_debug(subdev, "\ttoolsVersion : 0x%x\n", hdr->tools_version);
+ nvkm_debug(subdev, "\tappVersion : 0x%x\n", hdr->app_version);
+
+ date = kstrndup(hdr->date, sizeof(hdr->date), GFP_KERNEL);
+ nvkm_debug(subdev, "\tdate : %s\n", date);
+ kfree(date);
+
+ nvkm_debug(subdev, "\tsecureBootloader : 0x%x\n", hdr->secure_bootloader);
+ nvkm_debug(subdev, "\tbootloaderStartOffset: 0x%x\n", hdr->bootloader_start_offset);
+ nvkm_debug(subdev, "\tbootloaderSize : 0x%x\n", hdr->bootloader_size);
+ nvkm_debug(subdev, "\tbootloaderImemOffset : 0x%x\n", hdr->bootloader_imem_offset);
+ nvkm_debug(subdev, "\tbootloaderEntryPoint : 0x%x\n", hdr->bootloader_entry_point);
+
+ nvkm_debug(subdev, "\tappStartOffset : 0x%x\n", hdr->app_start_offset);
+ nvkm_debug(subdev, "\tappSize : 0x%x\n", hdr->app_size);
+ nvkm_debug(subdev, "\tappImemOffset : 0x%x\n", hdr->app_imem_offset);
+ nvkm_debug(subdev, "\tappImemEntry : 0x%x\n", hdr->app_imem_entry);
+ nvkm_debug(subdev, "\tappDmemOffset : 0x%x\n", hdr->app_dmem_offset);
+ nvkm_debug(subdev, "\tappResidentCodeOffset: 0x%x\n", hdr->app_resident_code_offset);
+ nvkm_debug(subdev, "\tappResidentCodeSize : 0x%x\n", hdr->app_resident_code_size);
+ nvkm_debug(subdev, "\tappResidentDataOffset: 0x%x\n", hdr->app_resident_data_offset);
+ nvkm_debug(subdev, "\tappResidentDataSize : 0x%x\n", hdr->app_resident_data_size);
+
+ nvkm_debug(subdev, "\tnbImemOverlays : %d\n", hdr->nb_imem_overlays);
+ nvkm_debug(subdev, "\tnbDmemOverlays : %d\n", hdr->nb_dmem_overlays);
+ for (i = 0; i < ARRAY_SIZE(hdr->load_ovl); i++) {
+ nvkm_debug(subdev, "\tloadOvl[%d] : 0x%x %d\n", i,
+ hdr->load_ovl[i].start, hdr->load_ovl[i].size);
+ }
+
+ return hdr;
+}
+
+const struct nvfw_ls_hsbl_bin_hdr *
+nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *subdev, const void *data)
+{
+ const struct nvfw_ls_hsbl_bin_hdr *hdr = data;
+
+ nvkm_debug(subdev, "lsHsblBinHdr:\n");
+ nvkm_debug(subdev, "\tbinMagic : 0x%08x\n", hdr->bin_magic);
+ nvkm_debug(subdev, "\tbinVer : %d\n", hdr->bin_ver);
+ nvkm_debug(subdev, "\tbinSize : %d\n", hdr->bin_size);
+ nvkm_debug(subdev, "\theaderOffset : 0x%x\n", hdr->header_offset);
+ return hdr;
+}
+
+const struct nvfw_ls_hsbl_hdr *
+nvfw_ls_hsbl_hdr(struct nvkm_subdev *subdev, const void *data)
+{
+ const struct nvfw_ls_hsbl_hdr *hdr = data;
+
+ nvkm_debug(subdev, "lsHsblHdr:\n");
+ nvkm_debug(subdev, "\tsigProdOffset : 0x%x\n", hdr->sig_prod_offset);
+ nvkm_debug(subdev, "\tsigProdSize : 0x%x\n", hdr->sig_prod_size);
+ nvkm_debug(subdev, "\tpatchLoc : 0x%x\n", hdr->patch_loc);
+ nvkm_debug(subdev, "\tpatchSig : 0x%x\n", hdr->patch_sig);
+ nvkm_debug(subdev, "\tmetadataOffset : 0x%x\n", hdr->meta_data_offset);
+ nvkm_debug(subdev, "\tmetadataSize : 0x%x\n", hdr->meta_data_size);
+ nvkm_debug(subdev, "\tnumSig : 0x%x\n", hdr->num_sig);
+ return hdr;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
index 2cb24fff7e32..4c2f6fc4ef58 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
@@ -23,4 +23,5 @@ include $(src)/nvkm/subdev/privring/Kbuild
include $(src)/nvkm/subdev/therm/Kbuild
include $(src)/nvkm/subdev/timer/Kbuild
include $(src)/nvkm/subdev/top/Kbuild
+include $(src)/nvkm/subdev/vfn/Kbuild
include $(src)/nvkm/subdev/volt/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild
index 5b9f64a8957f..5731f35b11e1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild
@@ -1,10 +1,12 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/subdev/acr/base.o
-nvkm-y += nvkm/subdev/acr/hsfw.o
nvkm-y += nvkm/subdev/acr/lsfw.o
nvkm-y += nvkm/subdev/acr/gm200.o
nvkm-y += nvkm/subdev/acr/gm20b.o
nvkm-y += nvkm/subdev/acr/gp102.o
nvkm-y += nvkm/subdev/acr/gp108.o
+nvkm-y += nvkm/subdev/acr/gv100.o
nvkm-y += nvkm/subdev/acr/gp10b.o
nvkm-y += nvkm/subdev/acr/tu102.o
+nvkm-y += nvkm/subdev/acr/ga100.o
+nvkm-y += nvkm/subdev/acr/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
index af6cac696d43..795f3a649b12 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
@@ -24,50 +24,63 @@
#include <core/firmware.h>
#include <core/memory.h>
#include <subdev/mmu.h>
+#include <subdev/gsp.h>
+#include <subdev/pmu.h>
+#include <engine/sec2.h>
+#include <engine/nvdec.h>
-static struct nvkm_acr_hsf *
-nvkm_acr_hsf_find(struct nvkm_acr *acr, const char *name)
+static struct nvkm_acr_hsfw *
+nvkm_acr_hsfw_find(struct nvkm_acr *acr, const char *name)
{
- struct nvkm_acr_hsf *hsf;
- list_for_each_entry(hsf, &acr->hsf, head) {
- if (!strcmp(hsf->name, name))
- return hsf;
+ struct nvkm_acr_hsfw *hsfw;
+
+ list_for_each_entry(hsfw, &acr->hsfw, head) {
+ if (!strcmp(hsfw->fw.fw.name, name))
+ return hsfw;
}
+
return NULL;
}
int
-nvkm_acr_hsf_boot(struct nvkm_acr *acr, const char *name)
+nvkm_acr_hsfw_boot(struct nvkm_acr *acr, const char *name)
{
struct nvkm_subdev *subdev = &acr->subdev;
- struct nvkm_acr_hsf *hsf;
- int ret;
+ struct nvkm_acr_hsfw *hsfw;
- hsf = nvkm_acr_hsf_find(acr, name);
- if (!hsf)
+ hsfw = nvkm_acr_hsfw_find(acr, name);
+ if (!hsfw)
return -EINVAL;
- nvkm_debug(subdev, "executing %s binary\n", hsf->name);
- ret = nvkm_falcon_get(hsf->falcon, subdev);
- if (ret)
- return ret;
+ return nvkm_falcon_fw_boot(&hsfw->fw, subdev, true, NULL, NULL,
+ hsfw->boot_mbox0, hsfw->intr_clear);
+}
- ret = hsf->func->boot(acr, hsf);
- nvkm_falcon_put(hsf->falcon, subdev);
- if (ret) {
- nvkm_error(subdev, "%s binary failed\n", hsf->name);
- return ret;
+static struct nvkm_acr_lsf *
+nvkm_acr_rtos(struct nvkm_acr *acr)
+{
+ struct nvkm_acr_lsf *lsf;
+
+ if (acr) {
+ list_for_each_entry(lsf, &acr->lsf, head) {
+ if (lsf->func->bootstrap_falcon)
+ return lsf;
+ }
}
- nvkm_debug(subdev, "%s binary completed successfully\n", hsf->name);
- return 0;
+ return NULL;
}
static void
nvkm_acr_unload(struct nvkm_acr *acr)
{
if (acr->done) {
- nvkm_acr_hsf_boot(acr, "unload");
+ if (acr->rtos) {
+ nvkm_subdev_unref(acr->rtos->falcon->owner);
+ acr->rtos = NULL;
+ }
+
+ nvkm_acr_hsfw_boot(acr, "unload");
acr->done = false;
}
}
@@ -76,7 +89,7 @@ static int
nvkm_acr_load(struct nvkm_acr *acr)
{
struct nvkm_subdev *subdev = &acr->subdev;
- struct nvkm_acr_lsf *lsf;
+ struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr);
u64 start, limit;
int ret;
@@ -100,12 +113,12 @@ nvkm_acr_load(struct nvkm_acr *acr)
acr->done = true;
- list_for_each_entry(lsf, &acr->lsf, head) {
- if (lsf->func->boot) {
- ret = lsf->func->boot(lsf->falcon);
- if (ret)
- break;
- }
+ if (rtos) {
+ ret = nvkm_subdev_ref(rtos->falcon->owner);
+ if (ret)
+ return ret;
+
+ acr->rtos = rtos;
}
return ret;
@@ -118,33 +131,17 @@ nvkm_acr_reload(struct nvkm_acr *acr)
return nvkm_acr_load(acr);
}
-static struct nvkm_acr_lsf *
-nvkm_acr_falcon(struct nvkm_device *device)
-{
- struct nvkm_acr *acr = device->acr;
- struct nvkm_acr_lsf *lsf;
-
- if (acr) {
- list_for_each_entry(lsf, &acr->lsf, head) {
- if (lsf->func->bootstrap_falcon)
- return lsf;
- }
- }
-
- return NULL;
-}
-
int
nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask)
{
- struct nvkm_acr_lsf *acrflcn = nvkm_acr_falcon(device);
struct nvkm_acr *acr = device->acr;
+ struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr);
unsigned long id;
/* If there's no LS FW managing bootstrapping of other LS falcons,
* we depend on the HS firmware being able to do it instead.
*/
- if (!acrflcn) {
+ if (!rtos) {
/* Which isn't possible everywhere... */
if ((mask & acr->func->bootstrap_falcons) == mask) {
int ret = nvkm_acr_reload(acr);
@@ -156,16 +153,14 @@ nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask)
return -ENOSYS;
}
- if ((mask & acrflcn->func->bootstrap_falcons) != mask)
+ if ((mask & rtos->func->bootstrap_falcons) != mask)
return -ENOSYS;
- if (acrflcn->func->bootstrap_multiple_falcons) {
- return acrflcn->func->
- bootstrap_multiple_falcons(acrflcn->falcon, mask);
- }
+ if (rtos->func->bootstrap_multiple_falcons)
+ return rtos->func->bootstrap_multiple_falcons(rtos->falcon, mask);
for_each_set_bit(id, &mask, NVKM_ACR_LSF_NUM) {
- int ret = acrflcn->func->bootstrap_falcon(acrflcn->falcon, id);
+ int ret = rtos->func->bootstrap_falcon(rtos->falcon, id);
if (ret)
return ret;
}
@@ -189,6 +184,9 @@ nvkm_acr_managed_falcon(struct nvkm_device *device, enum nvkm_acr_lsf_id id)
static int
nvkm_acr_fini(struct nvkm_subdev *subdev, bool suspend)
{
+ if (!subdev->use.enabled)
+ return 0;
+
nvkm_acr_unload(nvkm_acr(subdev));
return 0;
}
@@ -196,17 +194,19 @@ nvkm_acr_fini(struct nvkm_subdev *subdev, bool suspend)
static int
nvkm_acr_init(struct nvkm_subdev *subdev)
{
- if (!nvkm_acr_falcon(subdev->device))
+ struct nvkm_acr *acr = nvkm_acr(subdev);
+
+ if (!nvkm_acr_rtos(acr))
return 0;
- return nvkm_acr_load(nvkm_acr(subdev));
+ return nvkm_acr_load(acr);
}
static void
nvkm_acr_cleanup(struct nvkm_acr *acr)
{
nvkm_acr_lsfw_del_all(acr);
- nvkm_acr_hsfw_del_all(acr);
+
nvkm_firmware_put(acr->wpr_fw);
acr->wpr_fw = NULL;
}
@@ -218,7 +218,8 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
struct nvkm_acr *acr = nvkm_acr(subdev);
struct nvkm_acr_hsfw *hsfw;
struct nvkm_acr_lsfw *lsfw, *lsft;
- struct nvkm_acr_lsf *lsf;
+ struct nvkm_acr_lsf *lsf, *rtos;
+ struct nvkm_falcon *falcon;
u32 wpr_size = 0;
u64 falcons;
int ret, i;
@@ -260,10 +261,10 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
}
/* Ensure the falcon that'll provide ACR functions is booted first. */
- lsf = nvkm_acr_falcon(device);
- if (lsf) {
- falcons = lsf->func->bootstrap_falcons;
- list_move(&lsf->head, &acr->lsf);
+ rtos = nvkm_acr_rtos(acr);
+ if (rtos) {
+ falcons = rtos->func->bootstrap_falcons;
+ list_move(&rtos->head, &acr->lsf);
} else {
falcons = acr->func->bootstrap_falcons;
}
@@ -301,7 +302,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
nvkm_wobj(acr->wpr, 0, acr->wpr_fw->data, acr->wpr_fw->size);
if (!acr->wpr_fw || acr->wpr_comp)
- acr->func->wpr_build(acr, nvkm_acr_falcon(device));
+ acr->func->wpr_build(acr, rtos);
acr->func->wpr_patch(acr, (s64)acr->wpr_start - acr->wpr_prev);
if (acr->wpr_fw && acr->wpr_comp) {
@@ -336,8 +337,16 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
/* Load HS firmware blobs into ACR VMM. */
list_for_each_entry(hsfw, &acr->hsfw, head) {
- nvkm_debug(subdev, "loading %s fw\n", hsfw->name);
- ret = hsfw->func->load(acr, hsfw);
+ switch (hsfw->falcon_id) {
+ case NVKM_ACR_HSF_PMU : falcon = &device->pmu->falcon; break;
+ case NVKM_ACR_HSF_SEC2: falcon = &device->sec2->falcon; break;
+ case NVKM_ACR_HSF_GSP : falcon = &device->gsp->falcon; break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ ret = nvkm_falcon_fw_oneinit(&hsfw->fw, falcon, acr->vmm, acr->inst);
if (ret)
return ret;
}
@@ -351,15 +360,13 @@ static void *
nvkm_acr_dtor(struct nvkm_subdev *subdev)
{
struct nvkm_acr *acr = nvkm_acr(subdev);
- struct nvkm_acr_hsf *hsf, *hst;
+ struct nvkm_acr_hsfw *hsfw, *hsft;
struct nvkm_acr_lsf *lsf, *lst;
- list_for_each_entry_safe(hsf, hst, &acr->hsf, head) {
- nvkm_vmm_put(acr->vmm, &hsf->vma);
- nvkm_memory_unref(&hsf->ucode);
- kfree(hsf->imem);
- list_del(&hsf->head);
- kfree(hsf);
+ list_for_each_entry_safe(hsfw, hsft, &acr->hsfw, head) {
+ nvkm_falcon_fw_dtor(&hsfw->fw);
+ list_del(&hsfw->head);
+ kfree(hsfw);
}
nvkm_vmm_part(acr->vmm, acr->inst);
@@ -420,7 +427,6 @@ nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device,
nvkm_subdev_ctor(&nvkm_acr, device, type, inst, &acr->subdev);
INIT_LIST_HEAD(&acr->hsfw);
INIT_LIST_HEAD(&acr->lsfw);
- INIT_LIST_HEAD(&acr->hsf);
INIT_LIST_HEAD(&acr->lsf);
fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c
new file mode 100644
index 000000000000..e3370c1551c0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+void
+ga100_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit)
+{
+ struct nvkm_device *device = acr->subdev.device;
+
+ *start = (u64)(nvkm_rd32(device, 0x1fa81c) & 0xffffff00) << 8;
+ *limit = (u64)(nvkm_rd32(device, 0x1fa820) & 0xffffff00) << 8;
+ *limit = *limit + 0x20000;
+}
+
+int
+ga100_acr_hsfw_ctor(struct nvkm_acr *acr, const char *bl, const char *fw,
+ const char *name, int ver, const struct nvkm_acr_hsf_fwif *fwif)
+{
+ struct nvkm_acr_hsfw *hsfw;
+
+ if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL)))
+ return -ENOMEM;
+
+ hsfw->falcon_id = fwif->falcon_id;
+ hsfw->boot_mbox0 = fwif->boot_mbox0;
+ hsfw->intr_clear = fwif->intr_clear;
+ list_add_tail(&hsfw->head, &acr->hsfw);
+
+ return nvkm_falcon_fw_ctor_hs_v2(fwif->func, name, &acr->subdev, fw, ver, NULL, &hsfw->fw);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c
new file mode 100644
index 000000000000..45dcf493e972
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <nvfw/acr.h>
+
+static int
+ga102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
+{
+ struct wpr_header_v2 hdr;
+ struct lsb_header_v2 *lsb;
+ struct nvkm_acr_lsfw *lsfw;
+ u32 offset = 0;
+
+ lsb = kvmalloc(sizeof(*lsb), GFP_KERNEL);
+ if (!lsb)
+ return -ENOMEM;
+
+ do {
+ nvkm_robj(acr->wpr, offset, &hdr, sizeof(hdr));
+ wpr_header_v2_dump(&acr->subdev, &hdr);
+
+ list_for_each_entry(lsfw, &acr->lsfw, head) {
+ if (lsfw->id != hdr.wpr.falcon_id)
+ continue;
+
+ nvkm_robj(acr->wpr, hdr.wpr.lsb_offset, lsb, sizeof(*lsb));
+ lsb_header_v2_dump(&acr->subdev, lsb);
+
+ lsfw->func->bld_patch(acr, lsb->bl_data_off, adjust);
+ break;
+ }
+
+ offset += sizeof(hdr);
+ } while (hdr.wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID);
+
+ kvfree(lsb);
+ return 0;
+}
+
+static int
+ga102_acr_wpr_build_lsb(struct nvkm_acr *acr, struct nvkm_acr_lsfw *lsfw)
+{
+ struct lsb_header_v2 *hdr;
+ int ret = 0;
+
+ if (WARN_ON(lsfw->sig->size != sizeof(hdr->signature)))
+ return -EINVAL;
+
+ hdr = kvzalloc(sizeof(*hdr), GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr->hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER;
+ hdr->hdr.version = 2;
+ hdr->hdr.size = sizeof(*hdr);
+
+ memcpy(&hdr->signature, lsfw->sig->data, lsfw->sig->size);
+ hdr->ucode_off = lsfw->offset.img;
+ hdr->ucode_size = lsfw->ucode_size;
+ hdr->data_size = lsfw->data_size;
+ hdr->bl_code_size = lsfw->bootloader_size;
+ hdr->bl_imem_off = lsfw->bootloader_imem_offset;
+ hdr->bl_data_off = lsfw->offset.bld;
+ hdr->bl_data_size = lsfw->bl_data_size;
+ hdr->app_code_off = lsfw->app_start_offset + lsfw->app_resident_code_offset;
+ hdr->app_code_size = ALIGN(lsfw->app_resident_code_size, 0x100);
+ hdr->app_data_off = lsfw->app_start_offset + lsfw->app_resident_data_offset;
+ hdr->app_data_size = ALIGN(lsfw->app_resident_data_size, 0x100);
+ hdr->app_imem_offset = lsfw->app_imem_offset;
+ hdr->app_dmem_offset = lsfw->app_dmem_offset;
+ hdr->flags = lsfw->func->flags;
+ hdr->monitor_code_offset = 0;
+ hdr->monitor_data_offset = 0;
+ hdr->manifest_offset = 0;
+
+ if (lsfw->secure_bootloader) {
+ struct nvkm_falcon_fw fw = {
+ .fw.img = hdr->hs_fmc_params.pkc_signature,
+ .fw.name = "LSFW",
+ .func = &(const struct nvkm_falcon_fw_func) {
+ .signature = ga100_flcn_fw_signature,
+ },
+ .sig_size = lsfw->sig_size,
+ .sig_nr = lsfw->sig_nr,
+ .sigs = lsfw->sigs,
+ .fuse_ver = lsfw->fuse_ver,
+ .engine_id = lsfw->engine_id,
+ .ucode_id = lsfw->ucode_id,
+ .falcon = lsfw->falcon,
+
+ };
+
+ ret = nvkm_falcon_get(fw.falcon, &acr->subdev);
+ if (ret == 0) {
+ hdr->hs_fmc_params.hs_fmc = 1;
+ hdr->hs_fmc_params.pkc_algo = 0;
+ hdr->hs_fmc_params.pkc_algo_version = 1;
+ hdr->hs_fmc_params.engid_mask = lsfw->engine_id;
+ hdr->hs_fmc_params.ucode_id = lsfw->ucode_id;
+ hdr->hs_fmc_params.fuse_ver = lsfw->fuse_ver;
+ ret = nvkm_falcon_fw_patch(&fw);
+ nvkm_falcon_put(fw.falcon, &acr->subdev);
+ }
+ }
+
+ nvkm_wobj(acr->wpr, lsfw->offset.lsb, hdr, sizeof(*hdr));
+ kvfree(hdr);
+ return ret;
+}
+
+static int
+ga102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos)
+{
+ struct nvkm_acr_lsfw *lsfw;
+ struct wpr_header_v2 hdr;
+ u32 offset = 0;
+ int ret;
+
+ /*XXX: shared sub-WPR headers, fill terminator for now. */
+ nvkm_wo32(acr->wpr, 0x300, (2 << 16) | WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR);
+ nvkm_wo32(acr->wpr, 0x304, 0x14);
+ nvkm_wo32(acr->wpr, 0x308, 0xffffffff);
+ nvkm_wo32(acr->wpr, 0x30c, 0);
+ nvkm_wo32(acr->wpr, 0x310, 0);
+
+ /* Fill per-LSF structures. */
+ list_for_each_entry(lsfw, &acr->lsfw, head) {
+ struct lsf_signature_v2 *sig = (void *)lsfw->sig->data;
+
+ hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER;
+ hdr.hdr.version = 2;
+ hdr.hdr.size = sizeof(hdr);
+ hdr.wpr.falcon_id = lsfw->id;
+ hdr.wpr.lsb_offset = lsfw->offset.lsb;
+ hdr.wpr.bootstrap_owner = NVKM_ACR_LSF_GSPLITE;
+ hdr.wpr.lazy_bootstrap = 1;
+ hdr.wpr.bin_version = sig->ls_ucode_version;
+ hdr.wpr.status = WPR_HEADER_V1_STATUS_COPY;
+
+ /* Write WPR header. */
+ nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr));
+ offset += sizeof(hdr);
+
+ /* Write LSB header. */
+ ret = ga102_acr_wpr_build_lsb(acr, lsfw);
+ if (ret)
+ return ret;
+
+ /* Write ucode image. */
+ nvkm_wobj(acr->wpr, lsfw->offset.img,
+ lsfw->img.data,
+ lsfw->img.size);
+
+ /* Write bootloader data. */
+ lsfw->func->bld_write(acr, lsfw->offset.bld, lsfw);
+ }
+
+ /* Finalise WPR. */
+ hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER;
+ hdr.hdr.version = 2;
+ hdr.hdr.size = sizeof(hdr);
+ hdr.wpr.falcon_id = WPR_HEADER_V1_FALCON_ID_INVALID;
+ nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr));
+ return 0;
+}
+
+static u32
+ga102_acr_wpr_layout(struct nvkm_acr *acr)
+{
+ struct nvkm_acr_lsfw *lsfw;
+ u32 wpr = 0;
+
+ wpr += 21 /* MAX_LSF */ * sizeof(struct wpr_header_v2);
+ wpr = ALIGN(wpr, 256);
+
+ wpr += 0x100; /* Shared sub-WPR headers. */
+
+ list_for_each_entry(lsfw, &acr->lsfw, head) {
+ wpr = ALIGN(wpr, 256);
+ lsfw->offset.lsb = wpr;
+ wpr += sizeof(struct lsb_header_v2);
+
+ wpr = ALIGN(wpr, 4096);
+ lsfw->offset.img = wpr;
+ wpr += lsfw->img.size;
+
+ wpr = ALIGN(wpr, 256);
+ lsfw->offset.bld = wpr;
+ lsfw->bl_data_size = ALIGN(lsfw->func->bld_size, 256);
+ wpr += lsfw->bl_data_size;
+ }
+
+ return wpr;
+}
+
+static int
+ga102_acr_wpr_parse(struct nvkm_acr *acr)
+{
+ const struct wpr_header_v2 *hdr = (void *)acr->wpr_fw->data;
+
+ while (hdr->wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID) {
+ wpr_header_v2_dump(&acr->subdev, hdr);
+ if (!nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->wpr.falcon_id))
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_unload.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_unload.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_unload_fwif[] = {
+ { 0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_SEC2 },
+ {}
+};
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_asb.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_asb.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_asb_fwif[] = {
+ { 0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_GSP },
+ {}
+};
+
+static const struct nvkm_falcon_fw_func
+ga102_acr_ahesasc_0 = {
+ .signature = ga100_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .setup = gp102_acr_load_setup,
+ .load = ga102_flcn_fw_load,
+ .boot = ga102_flcn_fw_boot,
+};
+
+MODULE_FIRMWARE("nvidia/ga102/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga103/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga104/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga106/acr/ucode_ahesasc.bin");
+MODULE_FIRMWARE("nvidia/ga107/acr/ucode_ahesasc.bin");
+
+static const struct nvkm_acr_hsf_fwif
+ga102_acr_ahesasc_fwif[] = {
+ { 0, ga100_acr_hsfw_ctor, &ga102_acr_ahesasc_0, NVKM_ACR_HSF_SEC2 },
+ {}
+};
+
+static const struct nvkm_acr_func
+ga102_acr = {
+ .ahesasc = ga102_acr_ahesasc_fwif,
+ .asb = ga102_acr_asb_fwif,
+ .unload = ga102_acr_unload_fwif,
+ .wpr_parse = ga102_acr_wpr_parse,
+ .wpr_layout = ga102_acr_wpr_layout,
+ .wpr_alloc = gp102_acr_wpr_alloc,
+ .wpr_patch = ga102_acr_wpr_patch,
+ .wpr_build = ga102_acr_wpr_build,
+ .wpr_check = ga100_acr_wpr_check,
+ .init = tu102_acr_init,
+};
+
+static int
+ga102_acr_load(struct nvkm_acr *acr, int version,
+ const struct nvkm_acr_fwif *fwif)
+{
+ struct nvkm_subdev *subdev = &acr->subdev;
+ const struct nvkm_acr_hsf_fwif *hsfwif;
+
+ hsfwif = nvkm_firmware_load(subdev, fwif->func->ahesasc, "AcrAHESASC",
+ acr, NULL, "acr/ucode_ahesasc", "AHESASC");
+ if (IS_ERR(hsfwif))
+ return PTR_ERR(hsfwif);
+
+ hsfwif = nvkm_firmware_load(subdev, fwif->func->asb, "AcrASB",
+ acr, NULL, "acr/ucode_asb", "ASB");
+ if (IS_ERR(hsfwif))
+ return PTR_ERR(hsfwif);
+
+ hsfwif = nvkm_firmware_load(subdev, fwif->func->unload, "AcrUnload",
+ acr, NULL, "acr/ucode_unload", "unload");
+ if (IS_ERR(hsfwif))
+ return PTR_ERR(hsfwif);
+
+ return 0;
+}
+
+static const struct nvkm_acr_fwif
+ga102_acr_fwif[] = {
+ { 0, ga102_acr_load, &ga102_acr },
+ { -1, gm200_acr_nofw, &gm200_acr },
+ {}
+};
+
+int
+ga102_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_acr **pacr)
+{
+ return nvkm_acr_new_(ga102_acr_fwif, device, type, inst, pacr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
index 82b4c8e1457c..31079c947758 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
@@ -46,7 +46,7 @@ gm200_acr_nofw(struct nvkm_acr *acr, int ver, const struct nvkm_acr_fwif *fwif)
int
gm200_acr_init(struct nvkm_acr *acr)
{
- return nvkm_acr_hsf_boot(acr, "load");
+ return nvkm_acr_hsfw_boot(acr, "load");
}
void
@@ -61,7 +61,7 @@ gm200_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit)
*limit = *limit + 0x20000;
}
-void
+int
gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
{
struct nvkm_subdev *subdev = &acr->subdev;
@@ -86,6 +86,8 @@ gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
}
offset += sizeof(hdr);
} while (hdr.falcon_id != WPR_HEADER_V0_FALCON_ID_INVALID);
+
+ return 0;
}
void
@@ -219,162 +221,50 @@ gm200_acr_wpr_parse(struct nvkm_acr *acr)
return 0;
}
-void
-gm200_acr_hsfw_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
+int
+gm200_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw)
{
struct flcn_bl_dmem_desc_v1 hsdesc = {
.ctx_dma = FALCON_DMAIDX_VIRT,
- .code_dma_base = hsf->vma->addr,
- .non_sec_code_off = hsf->non_sec_addr,
- .non_sec_code_size = hsf->non_sec_size,
- .sec_code_off = hsf->sec_addr,
- .sec_code_size = hsf->sec_size,
+ .code_dma_base = fw->vma->addr,
+ .non_sec_code_off = fw->nmem_base,
+ .non_sec_code_size = fw->nmem_size,
+ .sec_code_off = fw->imem_base,
+ .sec_code_size = fw->imem_size,
.code_entry_point = 0,
- .data_dma_base = hsf->vma->addr + hsf->data_addr,
- .data_size = hsf->data_size,
+ .data_dma_base = fw->vma->addr + fw->dmem_base_img,
+ .data_size = fw->dmem_size,
};
- flcn_bl_dmem_desc_v1_dump(&acr->subdev, &hsdesc);
-
- nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0);
-}
-
-int
-gm200_acr_hsfw_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf,
- u32 intr_clear, u32 mbox0_ok)
-{
- struct nvkm_subdev *subdev = &acr->subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_falcon *falcon = hsf->falcon;
- u32 mbox0, mbox1;
- int ret;
-
- /* Reset falcon. */
- nvkm_falcon_reset(falcon);
- nvkm_falcon_bind_context(falcon, acr->inst);
+ flcn_bl_dmem_desc_v1_dump(fw->falcon->user, &hsdesc);
- /* Load bootloader into IMEM. */
- nvkm_falcon_load_imem(falcon, hsf->imem,
- falcon->code.limit - hsf->imem_size,
- hsf->imem_size,
- hsf->imem_tag,
- 0, false);
-
- /* Load bootloader data into DMEM. */
- hsf->func->bld(acr, hsf);
-
- /* Boot the falcon. */
- nvkm_mc_intr_mask(device, falcon->owner->type, falcon->owner->inst, false);
-
- nvkm_falcon_wr32(falcon, 0x040, 0xdeada5a5);
- nvkm_falcon_set_start_addr(falcon, hsf->imem_tag << 8);
- nvkm_falcon_start(falcon);
- ret = nvkm_falcon_wait_for_halt(falcon, 100);
- if (ret)
- return ret;
-
- /* Check for successful completion. */
- mbox0 = nvkm_falcon_rd32(falcon, 0x040);
- mbox1 = nvkm_falcon_rd32(falcon, 0x044);
- nvkm_debug(subdev, "mailbox %08x %08x\n", mbox0, mbox1);
- if (mbox0 && mbox0 != mbox0_ok)
- return -EIO;
-
- nvkm_falcon_clear_interrupt(falcon, intr_clear);
- nvkm_mc_intr_mask(device, falcon->owner->type, falcon->owner->inst, true);
- return ret;
+ return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0);
}
int
-gm200_acr_hsfw_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw,
- struct nvkm_falcon *falcon)
+gm200_acr_hsfw_ctor(struct nvkm_acr *acr, const char *bl, const char *fw, const char *name, int ver,
+ const struct nvkm_acr_hsf_fwif *fwif)
{
- struct nvkm_subdev *subdev = &acr->subdev;
- struct nvkm_acr_hsf *hsf;
- int ret;
-
- /* Patch the appropriate signature (production/debug) into the FW
- * image, as determined by the mode the falcon is in.
- */
- ret = nvkm_falcon_get(falcon, subdev);
- if (ret)
- return ret;
-
- if (hsfw->sig.patch_loc) {
- if (!falcon->debug) {
- nvkm_debug(subdev, "patching production signature\n");
- memcpy(hsfw->image + hsfw->sig.patch_loc,
- hsfw->sig.prod.data,
- hsfw->sig.prod.size);
- } else {
- nvkm_debug(subdev, "patching debug signature\n");
- memcpy(hsfw->image + hsfw->sig.patch_loc,
- hsfw->sig.dbg.data,
- hsfw->sig.dbg.size);
- }
- }
-
- nvkm_falcon_put(falcon, subdev);
+ struct nvkm_acr_hsfw *hsfw;
- if (!(hsf = kzalloc(sizeof(*hsf), GFP_KERNEL)))
+ if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL)))
return -ENOMEM;
- hsf->func = hsfw->func;
- hsf->name = hsfw->name;
- list_add_tail(&hsf->head, &acr->hsf);
-
- hsf->imem_size = hsfw->imem_size;
- hsf->imem_tag = hsfw->imem_tag;
- hsf->imem = kmemdup(hsfw->imem, hsfw->imem_size, GFP_KERNEL);
- if (!hsf->imem)
- return -ENOMEM;
-
- hsf->non_sec_addr = hsfw->non_sec_addr;
- hsf->non_sec_size = hsfw->non_sec_size;
- hsf->sec_addr = hsfw->sec_addr;
- hsf->sec_size = hsfw->sec_size;
- hsf->data_addr = hsfw->data_addr;
- hsf->data_size = hsfw->data_size;
-
- /* Make the FW image accessible to the HS bootloader. */
- ret = nvkm_memory_new(subdev->device, NVKM_MEM_TARGET_INST,
- hsfw->image_size, 0x1000, false, &hsf->ucode);
- if (ret)
- return ret;
-
- nvkm_kmap(hsf->ucode);
- nvkm_wobj(hsf->ucode, 0, hsfw->image, hsfw->image_size);
- nvkm_done(hsf->ucode);
-
- ret = nvkm_vmm_get(acr->vmm, 12, nvkm_memory_size(hsf->ucode),
- &hsf->vma);
- if (ret)
- return ret;
-
- ret = nvkm_memory_map(hsf->ucode, 0, acr->vmm, hsf->vma, NULL, 0);
- if (ret)
- return ret;
- hsf->falcon = falcon;
- return 0;
-}
+ hsfw->falcon_id = fwif->falcon_id;
+ hsfw->boot_mbox0 = fwif->boot_mbox0;
+ hsfw->intr_clear = fwif->intr_clear;
+ list_add_tail(&hsfw->head, &acr->hsfw);
-int
-gm200_acr_unload_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
-{
- return gm200_acr_hsfw_boot(acr, hsf, 0, 0x1d);
-}
-
-int
-gm200_acr_unload_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
-{
- return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon);
+ return nvkm_falcon_fw_ctor_hs(fwif->func, name, &acr->subdev, bl, fw, ver, NULL, &hsfw->fw);
}
-const struct nvkm_acr_hsf_func
+const struct nvkm_falcon_fw_func
gm200_acr_unload_0 = {
- .load = gm200_acr_unload_load,
- .boot = gm200_acr_unload_boot,
- .bld = gm200_acr_hsfw_bld,
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gm200_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
MODULE_FIRMWARE("nvidia/gm200/acr/ucode_unload.bin");
@@ -384,20 +274,15 @@ MODULE_FIRMWARE("nvidia/gp100/acr/ucode_unload.bin");
static const struct nvkm_acr_hsf_fwif
gm200_acr_unload_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gm200_acr_unload_0 },
+ { 0, gm200_acr_hsfw_ctor, &gm200_acr_unload_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 },
{}
};
-int
-gm200_acr_load_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
-{
- return gm200_acr_hsfw_boot(acr, hsf, 0x10, 0);
-}
-
static int
-gm200_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
+gm200_acr_load_setup(struct nvkm_falcon_fw *fw)
{
- struct flcn_acr_desc *desc = (void *)&hsfw->image[hsfw->data_addr];
+ struct flcn_acr_desc *desc = (void *)&fw->fw.img[fw->dmem_base_img];
+ struct nvkm_acr *acr = fw->falcon->owner->device->acr;
desc->wpr_region_id = 1;
desc->regions.no_regions = 2;
@@ -408,15 +293,17 @@ gm200_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
desc->regions.region_props[0].write_mask = 0xc;
desc->regions.region_props[0].client_mask = 0x2;
flcn_acr_desc_dump(&acr->subdev, desc);
-
- return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon);
+ return 0;
}
-static const struct nvkm_acr_hsf_func
+static const struct nvkm_falcon_fw_func
gm200_acr_load_0 = {
- .load = gm200_acr_load_load,
- .boot = gm200_acr_load_boot,
- .bld = gm200_acr_hsfw_bld,
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .setup = gm200_acr_load_setup,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gm200_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
MODULE_FIRMWARE("nvidia/gm200/acr/bl.bin");
@@ -433,7 +320,7 @@ MODULE_FIRMWARE("nvidia/gp100/acr/ucode_load.bin");
static const struct nvkm_acr_hsf_fwif
gm200_acr_load_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gm200_acr_load_0 },
+ { 0, gm200_acr_hsfw_ctor, &gm200_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c
index 54e996f2f630..ef5fb79128b1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c
@@ -45,43 +45,47 @@ gm20b_acr_wpr_alloc(struct nvkm_acr *acr, u32 wpr_size)
wpr_size, 0, true, &acr->wpr);
}
-static void
-gm20b_acr_load_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
+static int
+gm20b_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw)
{
struct flcn_bl_dmem_desc hsdesc = {
.ctx_dma = FALCON_DMAIDX_VIRT,
- .code_dma_base = hsf->vma->addr >> 8,
- .non_sec_code_off = hsf->non_sec_addr,
- .non_sec_code_size = hsf->non_sec_size,
- .sec_code_off = hsf->sec_addr,
- .sec_code_size = hsf->sec_size,
+ .code_dma_base = fw->vma->addr >> 8,
+ .non_sec_code_off = fw->nmem_base,
+ .non_sec_code_size = fw->nmem_size,
+ .sec_code_off = fw->imem_base,
+ .sec_code_size = fw->imem_size,
.code_entry_point = 0,
- .data_dma_base = (hsf->vma->addr + hsf->data_addr) >> 8,
- .data_size = hsf->data_size,
+ .data_dma_base = (fw->vma->addr + fw->dmem_base_img) >> 8,
+ .data_size = fw->dmem_size,
};
- flcn_bl_dmem_desc_dump(&acr->subdev, &hsdesc);
+ flcn_bl_dmem_desc_dump(fw->falcon->user, &hsdesc);
- nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0);
+ return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0);
}
+
static int
-gm20b_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
+gm20b_acr_load_setup(struct nvkm_falcon_fw *fw)
{
- struct flcn_acr_desc *desc = (void *)&hsfw->image[hsfw->data_addr];
+ struct flcn_acr_desc *desc = (void *)&fw->fw.img[fw->dmem_base_img];
+ struct nvkm_acr *acr = fw->falcon->owner->device->acr;
desc->ucode_blob_base = nvkm_memory_addr(acr->wpr);
desc->ucode_blob_size = nvkm_memory_size(acr->wpr);
flcn_acr_desc_dump(&acr->subdev, desc);
-
- return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon);
+ return 0;
}
-const struct nvkm_acr_hsf_func
+const struct nvkm_falcon_fw_func
gm20b_acr_load_0 = {
- .load = gm20b_acr_load_load,
- .boot = gm200_acr_load_boot,
- .bld = gm20b_acr_load_bld,
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .setup = gm20b_acr_load_setup,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gm20b_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
@@ -91,7 +95,7 @@ MODULE_FIRMWARE("nvidia/gm20b/acr/ucode_load.bin");
static const struct nvkm_acr_hsf_fwif
gm20b_acr_load_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gm20b_acr_load_0 },
+ { 0, gm200_acr_hsfw_ctor, &gm20b_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x10 },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
index fd97a935a380..084f28449e52 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
@@ -29,7 +29,7 @@
#include <nvfw/acr.h>
#include <nvfw/flcn.h>
-void
+int
gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
{
struct wpr_header_v1 hdr;
@@ -54,6 +54,8 @@ gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust)
offset += sizeof(hdr);
} while (hdr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID);
+
+ return 0;
}
int
@@ -187,14 +189,15 @@ MODULE_FIRMWARE("nvidia/gp107/acr/ucode_unload.bin");
static const struct nvkm_acr_hsf_fwif
gp102_acr_unload_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gm200_acr_unload_0 },
+ { 0, gm200_acr_hsfw_ctor, &gm200_acr_unload_0, NVKM_ACR_HSF_PMU, 0x1d, 0x00000010 },
{}
};
int
-gp102_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
+gp102_acr_load_setup(struct nvkm_falcon_fw *fw)
{
- struct flcn_acr_desc_v1 *desc = (void *)&hsfw->image[hsfw->data_addr];
+ struct flcn_acr_desc_v1 *desc = (void *)&fw->fw.img[fw->dmem_base_img];
+ struct nvkm_acr *acr = fw->falcon->owner->device->acr;
desc->wpr_region_id = 1;
desc->regions.no_regions = 2;
@@ -204,19 +207,19 @@ gp102_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
desc->regions.region_props[0].read_mask = 0xf;
desc->regions.region_props[0].write_mask = 0xc;
desc->regions.region_props[0].client_mask = 0x2;
- desc->regions.region_props[0].shadow_mem_start_addr =
- acr->shadow_start >> 8;
+ desc->regions.region_props[0].shadow_mem_start_addr = acr->shadow_start >> 8;
flcn_acr_desc_v1_dump(&acr->subdev, desc);
-
- return gm200_acr_hsfw_load(acr, hsfw,
- &acr->subdev.device->sec2->falcon);
+ return 0;
}
-static const struct nvkm_acr_hsf_func
+static const struct nvkm_falcon_fw_func
gp102_acr_load_0 = {
- .load = gp102_acr_load_load,
- .boot = gm200_acr_load_boot,
- .bld = gm200_acr_hsfw_bld,
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .setup = gp102_acr_load_setup,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gm200_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
MODULE_FIRMWARE("nvidia/gp102/acr/bl.bin");
@@ -233,7 +236,7 @@ MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin");
static const struct nvkm_acr_hsf_fwif
gp102_acr_load_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gp102_acr_load_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp102_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c
index 373d638a2177..6ab9d4959c17 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c
@@ -25,63 +25,62 @@
#include <nvfw/flcn.h>
-void
-gp108_acr_hsfw_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
+int
+gp108_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw)
{
struct flcn_bl_dmem_desc_v2 hsdesc = {
.ctx_dma = FALCON_DMAIDX_VIRT,
- .code_dma_base = hsf->vma->addr,
- .non_sec_code_off = hsf->non_sec_addr,
- .non_sec_code_size = hsf->non_sec_size,
- .sec_code_off = hsf->sec_addr,
- .sec_code_size = hsf->sec_size,
+ .code_dma_base = fw->vma->addr,
+ .non_sec_code_off = fw->nmem_base,
+ .non_sec_code_size = fw->nmem_size,
+ .sec_code_off = fw->imem_base,
+ .sec_code_size = fw->imem_size,
.code_entry_point = 0,
- .data_dma_base = hsf->vma->addr + hsf->data_addr,
- .data_size = hsf->data_size,
+ .data_dma_base = fw->vma->addr + fw->dmem_base_img,
+ .data_size = fw->dmem_size,
.argc = 0,
.argv = 0,
};
- flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hsdesc);
+ flcn_bl_dmem_desc_v2_dump(fw->falcon->user, &hsdesc);
- nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0);
+ return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0);
}
-const struct nvkm_acr_hsf_func
-gp108_acr_unload_0 = {
- .load = gm200_acr_unload_load,
- .boot = gm200_acr_unload_boot,
- .bld = gp108_acr_hsfw_bld,
+const struct nvkm_falcon_fw_func
+gp108_acr_hsfw_0 = {
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gp108_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
MODULE_FIRMWARE("nvidia/gp108/acr/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp108/acr/ucode_unload.bin");
-MODULE_FIRMWARE("nvidia/gv100/acr/unload_bl.bin");
-MODULE_FIRMWARE("nvidia/gv100/acr/ucode_unload.bin");
-
static const struct nvkm_acr_hsf_fwif
gp108_acr_unload_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gp108_acr_unload_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0x1d, 0x00000010 },
{}
};
-static const struct nvkm_acr_hsf_func
+const struct nvkm_falcon_fw_func
gp108_acr_load_0 = {
- .load = gp102_acr_load_load,
- .boot = gm200_acr_load_boot,
- .bld = gp108_acr_hsfw_bld,
+ .signature = gm200_flcn_fw_signature,
+ .reset = gm200_flcn_fw_reset,
+ .setup = gp102_acr_load_setup,
+ .load = gm200_flcn_fw_load,
+ .load_bld = gp108_acr_hsfw_load_bld,
+ .boot = gm200_flcn_fw_boot,
};
MODULE_FIRMWARE("nvidia/gp108/acr/bl.bin");
MODULE_FIRMWARE("nvidia/gp108/acr/ucode_load.bin");
-MODULE_FIRMWARE("nvidia/gv100/acr/bl.bin");
-MODULE_FIRMWARE("nvidia/gv100/acr/ucode_load.bin");
-
static const struct nvkm_acr_hsf_fwif
gp108_acr_load_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gp108_acr_load_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c
index f03ba028867b..a3422ab6deab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c
@@ -28,7 +28,7 @@ MODULE_FIRMWARE("nvidia/gp10b/acr/ucode_load.bin");
static const struct nvkm_acr_hsf_fwif
gp10b_acr_load_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gm20b_acr_load_0 },
+ { 0, gm200_acr_hsfw_ctor, &gm20b_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c
new file mode 100644
index 000000000000..4c5ca6b40027
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+MODULE_FIRMWARE("nvidia/gv100/acr/unload_bl.bin");
+MODULE_FIRMWARE("nvidia/gv100/acr/ucode_unload.bin");
+
+static const struct nvkm_acr_hsf_fwif
+gv100_acr_unload_fwif[] = {
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0, 0x00000000 },
+ {}
+};
+
+MODULE_FIRMWARE("nvidia/gv100/acr/bl.bin");
+MODULE_FIRMWARE("nvidia/gv100/acr/ucode_load.bin");
+
+static const struct nvkm_acr_hsf_fwif
+gv100_acr_load_fwif[] = {
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 },
+ {}
+};
+
+static const struct nvkm_acr_func
+gv100_acr = {
+ .load = gv100_acr_load_fwif,
+ .unload = gv100_acr_unload_fwif,
+ .wpr_parse = gp102_acr_wpr_parse,
+ .wpr_layout = gp102_acr_wpr_layout,
+ .wpr_alloc = gp102_acr_wpr_alloc,
+ .wpr_build = gp102_acr_wpr_build,
+ .wpr_patch = gp102_acr_wpr_patch,
+ .wpr_check = gm200_acr_wpr_check,
+ .init = gm200_acr_init,
+};
+
+static const struct nvkm_acr_fwif
+gv100_acr_fwif[] = {
+ { 0, gp102_acr_load, &gv100_acr },
+ { -1, gm200_acr_nofw, &gm200_acr },
+ {}
+};
+
+int
+gv100_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_acr **pacr)
+{
+ return nvkm_acr_new_(gv100_acr_fwif, device, type, inst, pacr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c
deleted file mode 100644
index a6ea89a5d51a..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2019 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
-
-#include <core/firmware.h>
-
-#include <nvfw/fw.h>
-#include <nvfw/hs.h>
-
-static void
-nvkm_acr_hsfw_del(struct nvkm_acr_hsfw *hsfw)
-{
- list_del(&hsfw->head);
- kfree(hsfw->imem);
- kfree(hsfw->image);
- kfree(hsfw->sig.prod.data);
- kfree(hsfw->sig.dbg.data);
- kfree(hsfw);
-}
-
-void
-nvkm_acr_hsfw_del_all(struct nvkm_acr *acr)
-{
- struct nvkm_acr_hsfw *hsfw, *hsft;
- list_for_each_entry_safe(hsfw, hsft, &acr->hsfw, head) {
- nvkm_acr_hsfw_del(hsfw);
- }
-}
-
-static int
-nvkm_acr_hsfw_load_image(struct nvkm_acr *acr, const char *name, int ver,
- struct nvkm_acr_hsfw *hsfw)
-{
- struct nvkm_subdev *subdev = &acr->subdev;
- const struct firmware *fw;
- const struct nvfw_bin_hdr *hdr;
- const struct nvfw_hs_header *fwhdr;
- const struct nvfw_hs_load_header *lhdr;
- u32 loc, sig;
- int ret;
-
- ret = nvkm_firmware_get(subdev, name, ver, &fw);
- if (ret < 0)
- return ret;
-
- hdr = nvfw_bin_hdr(subdev, fw->data);
- fwhdr = nvfw_hs_header(subdev, fw->data + hdr->header_offset);
-
- /* Earlier FW releases by NVIDIA for Nouveau's use aren't in NVIDIA's
- * standard format, and don't have the indirection seen in the 0x10de
- * case.
- */
- switch (hdr->bin_magic) {
- case 0x000010de:
- loc = *(u32 *)(fw->data + fwhdr->patch_loc);
- sig = *(u32 *)(fw->data + fwhdr->patch_sig);
- break;
- case 0x3b1d14f0:
- loc = fwhdr->patch_loc;
- sig = fwhdr->patch_sig;
- break;
- default:
- ret = -EINVAL;
- goto done;
- }
-
- lhdr = nvfw_hs_load_header(subdev, fw->data + fwhdr->hdr_offset);
-
- if (!(hsfw->image = kmalloc(hdr->data_size, GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
-
- memcpy(hsfw->image, fw->data + hdr->data_offset, hdr->data_size);
- hsfw->image_size = hdr->data_size;
- hsfw->non_sec_addr = lhdr->non_sec_code_off;
- hsfw->non_sec_size = lhdr->non_sec_code_size;
- hsfw->sec_addr = lhdr->apps[0];
- hsfw->sec_size = lhdr->apps[lhdr->num_apps];
- hsfw->data_addr = lhdr->data_dma_base;
- hsfw->data_size = lhdr->data_size;
-
- hsfw->sig.prod.size = fwhdr->sig_prod_size;
- hsfw->sig.prod.data = kmemdup(fw->data + fwhdr->sig_prod_offset + sig,
- hsfw->sig.prod.size, GFP_KERNEL);
- if (!hsfw->sig.prod.data) {
- ret = -ENOMEM;
- goto done;
- }
-
- hsfw->sig.dbg.size = fwhdr->sig_dbg_size;
- hsfw->sig.dbg.data = kmemdup(fw->data + fwhdr->sig_dbg_offset + sig,
- hsfw->sig.dbg.size, GFP_KERNEL);
- if (!hsfw->sig.dbg.data) {
- ret = -ENOMEM;
- goto done;
- }
-
- hsfw->sig.patch_loc = loc;
-done:
- nvkm_firmware_put(fw);
- return ret;
-}
-
-static int
-nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver,
- struct nvkm_acr_hsfw *hsfw)
-{
- struct nvkm_subdev *subdev = &acr->subdev;
- const struct nvfw_bin_hdr *hdr;
- const struct nvfw_bl_desc *desc;
- const struct firmware *fw;
- u8 *data;
- int ret;
-
- ret = nvkm_firmware_get(subdev, name, ver, &fw);
- if (ret)
- return ret;
-
- hdr = nvfw_bin_hdr(subdev, fw->data);
- desc = nvfw_bl_desc(subdev, fw->data + hdr->header_offset);
- data = (void *)fw->data + hdr->data_offset;
-
- hsfw->imem_size = desc->code_size;
- hsfw->imem_tag = desc->start_tag;
- hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL);
- nvkm_firmware_put(fw);
- if (!hsfw->imem)
- return -ENOMEM;
- else
- return 0;
-}
-
-int
-nvkm_acr_hsfw_load(struct nvkm_acr *acr, const char *bl, const char *fw,
- const char *name, int version,
- const struct nvkm_acr_hsf_fwif *fwif)
-{
- struct nvkm_acr_hsfw *hsfw;
- int ret;
-
- if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL)))
- return -ENOMEM;
-
- hsfw->func = fwif->func;
- hsfw->name = name;
- list_add_tail(&hsfw->head, &acr->hsfw);
-
- ret = nvkm_acr_hsfw_load_bl(acr, bl, version, hsfw);
- if (ret)
- goto done;
-
- ret = nvkm_acr_hsfw_load_image(acr, fw, version, hsfw);
-done:
- if (ret)
- nvkm_acr_hsfw_del(hsfw);
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c
index 9b1cf6711ae9..f36a359d4531 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c
@@ -29,6 +29,7 @@ void
nvkm_acr_lsfw_del(struct nvkm_acr_lsfw *lsfw)
{
nvkm_blob_dtor(&lsfw->img);
+ kfree(lsfw->sigs);
nvkm_firmware_put(lsfw->sig);
list_del(&lsfw->head);
kfree(lsfw);
@@ -177,6 +178,75 @@ nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev,
}
int
+nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev,
+ struct nvkm_falcon *falcon,
+ enum nvkm_acr_lsf_id id,
+ const char *path, int ver,
+ const struct nvkm_acr_lsf_func *func)
+{
+ const struct firmware *fw;
+ struct nvkm_acr_lsfw *lsfw;
+ const struct nvfw_ls_desc_v2 *desc;
+ int ret = 0;
+
+ lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, func, &fw);
+ if (IS_ERR(lsfw))
+ return PTR_ERR(lsfw);
+
+ desc = nvfw_ls_desc_v2(subdev, fw->data);
+
+ lsfw->secure_bootloader = desc->secure_bootloader;
+ lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256);
+ lsfw->bootloader_imem_offset = desc->bootloader_imem_offset;
+
+ lsfw->app_size = ALIGN(desc->app_size, 256);
+ lsfw->app_start_offset = desc->app_start_offset;
+ lsfw->app_imem_entry = desc->app_imem_entry;
+ lsfw->app_resident_code_offset = desc->app_resident_code_offset;
+ lsfw->app_resident_code_size = desc->app_resident_code_size;
+ lsfw->app_resident_data_offset = desc->app_resident_data_offset;
+ lsfw->app_resident_data_size = desc->app_resident_data_size;
+ lsfw->app_imem_offset = desc->app_imem_offset;
+ lsfw->app_dmem_offset = desc->app_dmem_offset;
+
+ lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + lsfw->bootloader_size;
+ lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - lsfw->ucode_size;
+
+ nvkm_firmware_put(fw);
+
+ if (lsfw->secure_bootloader) {
+ const struct firmware *hsbl;
+ const struct nvfw_ls_hsbl_bin_hdr *hdr;
+ const struct nvfw_ls_hsbl_hdr *hshdr;
+ u32 loc, sig, cnt, *meta;
+
+ ret = nvkm_firmware_load_name(subdev, path, "hs_bl_sig", ver, &hsbl);
+ if (ret)
+ return ret;
+
+ hdr = nvfw_ls_hsbl_bin_hdr(subdev, hsbl->data);
+ hshdr = nvfw_ls_hsbl_hdr(subdev, hsbl->data + hdr->header_offset);
+ meta = (u32 *)(hsbl->data + hshdr->meta_data_offset);
+ loc = *(u32 *)(hsbl->data + hshdr->patch_loc);
+ sig = *(u32 *)(hsbl->data + hshdr->patch_sig);
+ cnt = *(u32 *)(hsbl->data + hshdr->num_sig);
+
+ lsfw->fuse_ver = meta[0];
+ lsfw->engine_id = meta[1];
+ lsfw->ucode_id = meta[2];
+ lsfw->sig_size = hshdr->sig_prod_size / cnt;
+ lsfw->sig_nr = cnt;
+ lsfw->sigs = kmemdup(hsbl->data + hshdr->sig_prod_offset + sig,
+ lsfw->sig_nr * lsfw->sig_size, GFP_KERNEL);
+ nvkm_firmware_put(hsbl);
+ if (!lsfw->sigs)
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+int
nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *subdev,
struct nvkm_falcon *falcon,
enum nvkm_acr_lsf_id id,
@@ -251,3 +321,78 @@ done:
nvkm_firmware_put(bl);
return ret;
}
+
+int
+nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *subdev,
+ struct nvkm_falcon *falcon,
+ enum nvkm_acr_lsf_id id,
+ const char *path, int ver,
+ const struct nvkm_acr_lsf_func *func,
+ const void *inst_data, u32 inst_size,
+ const void *data_data, u32 data_size)
+{
+ struct nvkm_acr *acr = subdev->device->acr;
+ struct nvkm_acr_lsfw *lsfw;
+ const struct firmware _inst = { .data = inst_data, .size = inst_size };
+ const struct firmware _data = { .data = data_data, .size = data_size };
+ const struct firmware *bl = NULL, *inst = &_inst, *data = &_data;
+ const struct {
+ int bin_magic;
+ int bin_version;
+ int bin_size;
+ int header_offset;
+ int header_size;
+ } *hdr;
+ u32 *bldata;
+ int ret;
+
+ if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id))))
+ return PTR_ERR(lsfw);
+
+ ret = nvkm_firmware_load_name(subdev, path, "bl", ver, &bl);
+ if (ret)
+ goto done;
+
+ hdr = (const void *)bl->data;
+ bldata = (void *)(bl->data + hdr->header_offset);
+
+ ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig);
+ if (ret)
+ goto done;
+
+ lsfw->bootloader_size = ALIGN(hdr->header_size, 256);
+ lsfw->bootloader_imem_offset = func->bl_entry;
+
+ lsfw->app_start_offset = lsfw->bootloader_size;
+ lsfw->app_imem_entry = 0;
+ lsfw->app_resident_code_offset = 0;
+ lsfw->app_resident_code_size = ALIGN(inst->size, 256);
+ lsfw->app_resident_data_offset = lsfw->app_resident_code_size;
+ lsfw->app_resident_data_size = ALIGN(data->size, 256);
+ lsfw->app_imem_offset = 0;
+ lsfw->app_dmem_offset = 0;
+ lsfw->app_size = lsfw->app_resident_code_size + lsfw->app_resident_data_size;
+
+ lsfw->img.size = lsfw->bootloader_size + lsfw->app_size;
+ if (!(lsfw->img.data = kzalloc(lsfw->img.size, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memcpy(lsfw->img.data, bldata, lsfw->bootloader_size);
+ memcpy(lsfw->img.data + lsfw->app_start_offset +
+ lsfw->app_resident_code_offset, inst->data, inst->size);
+ memcpy(lsfw->img.data + lsfw->app_start_offset +
+ lsfw->app_resident_data_offset, data->data, data->size);
+
+ lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) +
+ lsfw->bootloader_size;
+ lsfw->data_size = lsfw->app_size + lsfw->bootloader_size -
+ lsfw->ucode_size;
+
+done:
+ if (ret)
+ nvkm_acr_lsfw_del(lsfw);
+ nvkm_firmware_put(bl);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
index c30b841c9d35..4881c8ba3880 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
@@ -24,7 +24,7 @@ struct nvkm_acr_func {
u32 (*wpr_layout)(struct nvkm_acr *);
int (*wpr_alloc)(struct nvkm_acr *, u32 wpr_size);
int (*wpr_build)(struct nvkm_acr *, struct nvkm_acr_lsf *rtos);
- void (*wpr_patch)(struct nvkm_acr *, s64 adjust);
+ int (*wpr_patch)(struct nvkm_acr *, s64 adjust);
void (*wpr_check)(struct nvkm_acr *, u64 *start, u64 *limit);
int (*init)(struct nvkm_acr *);
void (*fini)(struct nvkm_acr *);
@@ -35,7 +35,7 @@ extern const struct nvkm_acr_func gm200_acr;
int gm200_acr_wpr_parse(struct nvkm_acr *);
u32 gm200_acr_wpr_layout(struct nvkm_acr *);
int gm200_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *);
-void gm200_acr_wpr_patch(struct nvkm_acr *, s64);
+int gm200_acr_wpr_patch(struct nvkm_acr *, s64);
void gm200_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *);
void gm200_acr_wpr_build_lsb_tail(struct nvkm_acr_lsfw *,
struct lsb_header_tail *);
@@ -48,96 +48,60 @@ u32 gp102_acr_wpr_layout(struct nvkm_acr *);
int gp102_acr_wpr_alloc(struct nvkm_acr *, u32 wpr_size);
int gp102_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *);
int gp102_acr_wpr_build_lsb(struct nvkm_acr *, struct nvkm_acr_lsfw *);
-void gp102_acr_wpr_patch(struct nvkm_acr *, s64);
+int gp102_acr_wpr_patch(struct nvkm_acr *, s64);
+
+int tu102_acr_init(struct nvkm_acr *);
+
+void ga100_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *);
struct nvkm_acr_hsfw {
- const struct nvkm_acr_hsf_func *func;
- const char *name;
- struct list_head head;
+ struct nvkm_falcon_fw fw;
+
+ enum nvkm_acr_hsf_id {
+ NVKM_ACR_HSF_PMU,
+ NVKM_ACR_HSF_SEC2,
+ NVKM_ACR_HSF_GSP,
+ } falcon_id;
+ u32 boot_mbox0;
+ u32 intr_clear;
- u32 imem_size;
- u32 imem_tag;
- u32 *imem;
-
- u8 *image;
- u32 image_size;
- u32 non_sec_addr;
- u32 non_sec_size;
- u32 sec_addr;
- u32 sec_size;
- u32 data_addr;
- u32 data_size;
-
- struct {
- struct {
- void *data;
- u32 size;
- } prod, dbg;
- u32 patch_loc;
- } sig;
+ struct list_head head;
};
+int nvkm_acr_hsfw_boot(struct nvkm_acr *, const char *name);
+
struct nvkm_acr_hsf_fwif {
int version;
int (*load)(struct nvkm_acr *, const char *bl, const char *fw,
const char *name, int version,
const struct nvkm_acr_hsf_fwif *);
- const struct nvkm_acr_hsf_func *func;
-};
+ const struct nvkm_falcon_fw_func *func;
-int nvkm_acr_hsfw_load(struct nvkm_acr *, const char *, const char *,
- const char *, int, const struct nvkm_acr_hsf_fwif *);
-void nvkm_acr_hsfw_del_all(struct nvkm_acr *);
-
-struct nvkm_acr_hsf {
- const struct nvkm_acr_hsf_func *func;
- const char *name;
- struct list_head head;
-
- u32 imem_size;
- u32 imem_tag;
- u32 *imem;
-
- u32 non_sec_addr;
- u32 non_sec_size;
- u32 sec_addr;
- u32 sec_size;
- u32 data_addr;
- u32 data_size;
-
- struct nvkm_memory *ucode;
- struct nvkm_vma *vma;
- struct nvkm_falcon *falcon;
+ enum nvkm_acr_hsf_id falcon_id;
+ u32 boot_mbox0;
+ u32 intr_clear;
};
-struct nvkm_acr_hsf_func {
- int (*load)(struct nvkm_acr *, struct nvkm_acr_hsfw *);
- int (*boot)(struct nvkm_acr *, struct nvkm_acr_hsf *);
- void (*bld)(struct nvkm_acr *, struct nvkm_acr_hsf *);
-};
-int gm200_acr_hsfw_load(struct nvkm_acr *, struct nvkm_acr_hsfw *,
- struct nvkm_falcon *);
-int gm200_acr_hsfw_boot(struct nvkm_acr *, struct nvkm_acr_hsf *,
- u32 clear_intr, u32 mbox0_ok);
+int gm200_acr_hsfw_ctor(struct nvkm_acr *, const char *, const char *, const char *, int,
+ const struct nvkm_acr_hsf_fwif *);
+int gm200_acr_hsfw_load_bld(struct nvkm_falcon_fw *);
+extern const struct nvkm_falcon_fw_func gm200_acr_unload_0;
-int gm200_acr_load_boot(struct nvkm_acr *, struct nvkm_acr_hsf *);
+extern const struct nvkm_falcon_fw_func gm20b_acr_load_0;
-extern const struct nvkm_acr_hsf_func gm200_acr_unload_0;
-int gm200_acr_unload_load(struct nvkm_acr *, struct nvkm_acr_hsfw *);
-int gm200_acr_unload_boot(struct nvkm_acr *, struct nvkm_acr_hsf *);
-void gm200_acr_hsfw_bld(struct nvkm_acr *, struct nvkm_acr_hsf *);
+int gp102_acr_load_setup(struct nvkm_falcon_fw *);
-extern const struct nvkm_acr_hsf_func gm20b_acr_load_0;
+extern const struct nvkm_falcon_fw_func gp108_acr_load_0;
-int gp102_acr_load_load(struct nvkm_acr *, struct nvkm_acr_hsfw *);
+extern const struct nvkm_falcon_fw_func gp108_acr_hsfw_0;
+int gp108_acr_hsfw_load_bld(struct nvkm_falcon_fw *);
-extern const struct nvkm_acr_hsf_func gp108_acr_unload_0;
-void gp108_acr_hsfw_bld(struct nvkm_acr *, struct nvkm_acr_hsf *);
+int ga100_acr_hsfw_ctor(struct nvkm_acr *, const char *, const char *, const char *, int,
+ const struct nvkm_acr_hsf_fwif *);
int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, enum nvkm_subdev_type,
int inst, struct nvkm_acr **);
-int nvkm_acr_hsf_boot(struct nvkm_acr *, const char *name);
struct nvkm_acr_lsf {
const struct nvkm_acr_lsf_func *func;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c
index 05a87e77525f..c22d551c0078 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c
@@ -29,14 +29,14 @@
#include <nvfw/acr.h>
-static int
+int
tu102_acr_init(struct nvkm_acr *acr)
{
- int ret = nvkm_acr_hsf_boot(acr, "AHESASC");
+ int ret = nvkm_acr_hsfw_boot(acr, "AHESASC");
if (ret)
return ret;
- return nvkm_acr_hsf_boot(acr, "ASB");
+ return nvkm_acr_hsfw_boot(acr, "ASB");
}
static int
@@ -85,12 +85,6 @@ tu102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos)
}
static int
-tu102_acr_hsfw_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf)
-{
- return gm200_acr_hsfw_boot(acr, hsf, 0, 0);
-}
-
-static int
tu102_acr_hsfw_nofw(struct nvkm_acr *acr, const char *bl, const char *fw,
const char *name, int version,
const struct nvkm_acr_hsf_fwif *fwif)
@@ -115,24 +109,11 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_unload.bin");
static const struct nvkm_acr_hsf_fwif
tu102_acr_unload_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &gp108_acr_unload_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0, 0x00000000 },
{ -1, tu102_acr_hsfw_nofw },
{}
};
-static int
-tu102_acr_asb_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw)
-{
- return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->gsp->falcon);
-}
-
-static const struct nvkm_acr_hsf_func
-tu102_acr_asb_0 = {
- .load = tu102_acr_asb_load,
- .boot = tu102_acr_hsfw_boot,
- .bld = gp108_acr_hsfw_bld,
-};
-
MODULE_FIRMWARE("nvidia/tu102/acr/ucode_asb.bin");
MODULE_FIRMWARE("nvidia/tu104/acr/ucode_asb.bin");
MODULE_FIRMWARE("nvidia/tu106/acr/ucode_asb.bin");
@@ -141,18 +122,11 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_asb.bin");
static const struct nvkm_acr_hsf_fwif
tu102_acr_asb_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &tu102_acr_asb_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_GSP, 0, 0x00000000 },
{ -1, tu102_acr_hsfw_nofw },
{}
};
-static const struct nvkm_acr_hsf_func
-tu102_acr_ahesasc_0 = {
- .load = gp102_acr_load_load,
- .boot = tu102_acr_hsfw_boot,
- .bld = gp108_acr_hsfw_bld,
-};
-
MODULE_FIRMWARE("nvidia/tu102/acr/bl.bin");
MODULE_FIRMWARE("nvidia/tu102/acr/ucode_ahesasc.bin");
@@ -170,7 +144,7 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_ahesasc.bin");
static const struct nvkm_acr_hsf_fwif
tu102_acr_ahesasc_fwif[] = {
- { 0, nvkm_acr_hsfw_load, &tu102_acr_ahesasc_0 },
+ { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000000 },
{ -1, tu102_acr_hsfw_nofw },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
index a308b9bde449..f30718d7e61a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
@@ -26,6 +26,7 @@
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/pmu.h>
+#include <subdev/pmu.h>
#include <subdev/timer.h>
static void
@@ -85,13 +86,18 @@ pmu_load(struct nv50_devinit *init, u8 type, bool post,
struct nvkm_subdev *subdev = &init->base.subdev;
struct nvkm_bios *bios = subdev->device->bios;
struct nvbios_pmuR pmu;
+ int ret;
if (!nvbios_pmuRm(bios, type, &pmu))
return -EINVAL;
- if (!post)
+ if (!post || !subdev->device->pmu)
return 0;
+ ret = nvkm_falcon_reset(&subdev->device->pmu->falcon);
+ if (ret)
+ return ret;
+
pmu_code(init, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
pmu_code(init, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
pmu_data(init, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
index fd54fa504efa..b53ac9a2552f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
@@ -22,7 +22,6 @@
#include "priv.h"
#include <core/memory.h>
-#include <core/notify.h>
static void
nvkm_fault_ntfy_fini(struct nvkm_event *event, int type, int index)
@@ -38,23 +37,8 @@ nvkm_fault_ntfy_init(struct nvkm_event *event, int type, int index)
fault->func->buffer.intr(fault->buffer[index], true);
}
-static int
-nvkm_fault_ntfy_ctor(struct nvkm_object *object, void *argv, u32 argc,
- struct nvkm_notify *notify)
-{
- struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
- if (argc == 0) {
- notify->size = 0;
- notify->types = 1;
- notify->index = buffer->id;
- return 0;
- }
- return -ENOSYS;
-}
-
static const struct nvkm_event_func
nvkm_fault_ntfy = {
- .ctor = nvkm_fault_ntfy_ctor,
.init = nvkm_fault_ntfy_init,
.fini = nvkm_fault_ntfy_fini,
};
@@ -130,8 +114,7 @@ nvkm_fault_oneinit(struct nvkm_subdev *subdev)
}
}
- ret = nvkm_event_init(&nvkm_fault_ntfy, 1, fault->buffer_nr,
- &fault->event);
+ ret = nvkm_event_init(&nvkm_fault_ntfy, subdev, 1, fault->buffer_nr, &fault->event);
if (ret)
return ret;
@@ -146,7 +129,7 @@ nvkm_fault_dtor(struct nvkm_subdev *subdev)
struct nvkm_fault *fault = nvkm_fault(subdev);
int i;
- nvkm_notify_fini(&fault->nrpfb);
+ nvkm_event_ntfy_del(&fault->nrpfb);
nvkm_event_fini(&fault->event);
for (i = 0; i < fault->buffer_nr; i++) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
index 6af7959e02ea..04c7526888bc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
@@ -65,7 +65,7 @@ gp100_fault_buffer_info(struct nvkm_fault_buffer *buffer)
void
gp100_fault_intr(struct nvkm_fault *fault)
{
- nvkm_event_send(&fault->event, 1, 0, NULL, 0);
+ nvkm_event_ntfy(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING);
}
static const struct nvkm_fault_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
index cd9d2ade5ac7..8e34d40e7649 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
@@ -27,10 +27,12 @@
#include <nvif/class.h>
-static void
-gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer)
+void
+gv100_fault_buffer_process(struct work_struct *work)
{
- struct nvkm_device *device = buffer->fault->subdev.device;
+ struct nvkm_fault *fault = container_of(work, typeof(*fault), nrpfb_work);
+ struct nvkm_fault_buffer *buffer = fault->buffer[0];
+ struct nvkm_device *device = fault->subdev.device;
struct nvkm_memory *mem = buffer->mem;
u32 get = nvkm_rd32(device, buffer->get);
u32 put = nvkm_rd32(device, buffer->put);
@@ -115,11 +117,12 @@ gv100_fault_buffer_info(struct nvkm_fault_buffer *buffer)
}
static int
-gv100_fault_ntfy_nrpfb(struct nvkm_notify *notify)
+gv100_fault_ntfy_nrpfb(struct nvkm_event_ntfy *ntfy, u32 bits)
{
- struct nvkm_fault *fault = container_of(notify, typeof(*fault), nrpfb);
- gv100_fault_buffer_process(fault->buffer[0]);
- return NVKM_NOTIFY_KEEP;
+ struct nvkm_fault *fault = container_of(ntfy, typeof(*fault), nrpfb);
+
+ schedule_work(&fault->nrpfb_work);
+ return NVKM_EVENT_KEEP;
}
static void
@@ -163,14 +166,14 @@ gv100_fault_intr(struct nvkm_fault *fault)
if (stat & 0x20000000) {
if (fault->buffer[0]) {
- nvkm_event_send(&fault->event, 1, 0, NULL, 0);
+ nvkm_event_ntfy(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING);
stat &= ~0x20000000;
}
}
if (stat & 0x08000000) {
if (fault->buffer[1]) {
- nvkm_event_send(&fault->event, 1, 1, NULL, 0);
+ nvkm_event_ntfy(&fault->event, 1, NVKM_FAULT_BUFFER_EVENT_PENDING);
stat &= ~0x08000000;
}
}
@@ -183,9 +186,12 @@ gv100_fault_intr(struct nvkm_fault *fault)
static void
gv100_fault_fini(struct nvkm_fault *fault)
{
- nvkm_notify_put(&fault->nrpfb);
+ nvkm_event_ntfy_block(&fault->nrpfb);
+ flush_work(&fault->nrpfb_work);
+
if (fault->buffer[0])
fault->func->buffer.fini(fault->buffer[0]);
+
nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000);
}
@@ -194,15 +200,15 @@ gv100_fault_init(struct nvkm_fault *fault)
{
nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000);
fault->func->buffer.init(fault->buffer[0]);
- nvkm_notify_get(&fault->nrpfb);
+ nvkm_event_ntfy_allow(&fault->nrpfb);
}
int
gv100_fault_oneinit(struct nvkm_fault *fault)
{
- return nvkm_notify_init(&fault->buffer[0]->object, &fault->event,
- gv100_fault_ntfy_nrpfb, true, NULL, 0, 0,
- &fault->nrpfb);
+ nvkm_event_ntfy_add(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING, true,
+ gv100_fault_ntfy_nrpfb, &fault->nrpfb);
+ return 0;
}
static const struct nvkm_fault_func
@@ -231,5 +237,10 @@ int
gv100_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fault **pfault)
{
- return nvkm_fault_new_(&gv100_fault, device, type, inst, pfault);
+ int ret = nvkm_fault_new_(&gv100_fault, device, type, inst, pfault);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
index 36681c347fb5..a5510332c402 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
@@ -16,6 +16,8 @@ struct nvkm_fault_buffer {
u32 put;
struct nvkm_memory *mem;
u64 addr;
+
+ struct nvkm_inth inth;
};
int nvkm_fault_new_(const struct nvkm_fault_func *, struct nvkm_device *, enum nvkm_subdev_type,
@@ -46,6 +48,7 @@ void gp100_fault_buffer_fini(struct nvkm_fault_buffer *);
void gp100_fault_buffer_init(struct nvkm_fault_buffer *);
u64 gp100_fault_buffer_pin(struct nvkm_fault_buffer *);
void gp100_fault_buffer_info(struct nvkm_fault_buffer *);
+void gv100_fault_buffer_process(struct work_struct *);
void gp100_fault_intr(struct nvkm_fault *);
u64 gp10b_fault_buffer_pin(struct nvkm_fault_buffer *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
index 91eb6729c84d..967efaddae28 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
@@ -24,20 +24,27 @@
#include <core/memory.h>
#include <subdev/mc.h>
#include <subdev/mmu.h>
+#include <subdev/vfn.h>
#include <engine/fifo.h>
#include <nvif/class.h>
+static irqreturn_t
+tu102_fault_buffer_notify(struct nvkm_inth *inth)
+{
+ struct nvkm_fault_buffer *buffer = container_of(inth, typeof(*buffer), inth);
+
+ nvkm_event_ntfy(&buffer->fault->event, buffer->id, NVKM_FAULT_BUFFER_EVENT_PENDING);
+ return IRQ_HANDLED;
+}
+
static void
tu102_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
{
- /*XXX: Earlier versions of RM touched the old regs on Turing,
- * which don't appear to actually work anymore, but newer
- * versions of RM don't appear to touch anything at all..
- */
- struct nvkm_device *device = buffer->fault->subdev.device;
-
- nvkm_mc_intr_mask(device, NVKM_SUBDEV_FAULT, 0, enable);
+ if (enable)
+ nvkm_inth_allow(&buffer->inth);
+ else
+ nvkm_inth_block(&buffer->inth);
}
static void
@@ -46,10 +53,6 @@ tu102_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
- /* Disable the fault interrupts */
- nvkm_wr32(device, 0xb81408, 0x1);
- nvkm_wr32(device, 0xb81410, 0x10);
-
nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x00000000);
}
@@ -59,10 +62,6 @@ tu102_fault_buffer_init(struct nvkm_fault_buffer *buffer)
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
- /* Enable the fault interrupts */
- nvkm_wr32(device, 0xb81208, 0x1);
- nvkm_wr32(device, 0xb81210, 0x10);
-
nvkm_mask(device, 0xb83010 + foff, 0xc0000000, 0x40000000);
nvkm_wr32(device, 0xb83004 + foff, upper_32_bits(buffer->addr));
nvkm_wr32(device, 0xb83000 + foff, lower_32_bits(buffer->addr));
@@ -82,9 +81,10 @@ tu102_fault_buffer_info(struct nvkm_fault_buffer *buffer)
buffer->put = 0xb8300c + foff;
}
-static void
-tu102_fault_intr_fault(struct nvkm_fault *fault)
+static irqreturn_t
+tu102_fault_info_fault(struct nvkm_inth *inth)
{
+ struct nvkm_fault *fault = container_of(inth, typeof(*fault), info_fault);
struct nvkm_subdev *subdev = &fault->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_fault_data info;
@@ -106,70 +106,61 @@ tu102_fault_intr_fault(struct nvkm_fault *fault)
info.reason = (info1 & 0x0000001f);
nvkm_fifo_fault(device->fifo, &info);
-}
-
-static void
-tu102_fault_intr(struct nvkm_fault *fault)
-{
- struct nvkm_subdev *subdev = &fault->subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0xb83094);
-
- if (stat & 0x80000000) {
- tu102_fault_intr_fault(fault);
- nvkm_wr32(device, 0xb83094, 0x80000000);
- stat &= ~0x80000000;
- }
- if (stat & 0x00000200) {
- /* Clear the associated interrupt flag */
- nvkm_wr32(device, 0xb81010, 0x10);
-
- if (fault->buffer[0]) {
- nvkm_event_send(&fault->event, 1, 0, NULL, 0);
- stat &= ~0x00000200;
- }
- }
-
- /* Replayable MMU fault */
- if (stat & 0x00000100) {
- /* Clear the associated interrupt flag */
- nvkm_wr32(device, 0xb81008, 0x1);
-
- if (fault->buffer[1]) {
- nvkm_event_send(&fault->event, 1, 1, NULL, 0);
- stat &= ~0x00000100;
- }
- }
-
- if (stat) {
- nvkm_debug(subdev, "intr %08x\n", stat);
- }
+ nvkm_wr32(device, 0xb83094, 0x80000000);
+ return IRQ_HANDLED;
}
static void
tu102_fault_fini(struct nvkm_fault *fault)
{
- nvkm_notify_put(&fault->nrpfb);
+ nvkm_event_ntfy_block(&fault->nrpfb);
+ flush_work(&fault->nrpfb_work);
+
if (fault->buffer[0])
fault->func->buffer.fini(fault->buffer[0]);
- /*XXX: disable priv faults */
+
+ nvkm_inth_block(&fault->info_fault);
}
static void
tu102_fault_init(struct nvkm_fault *fault)
{
- /*XXX: enable priv faults */
+ nvkm_inth_allow(&fault->info_fault);
+
fault->func->buffer.init(fault->buffer[0]);
- nvkm_notify_get(&fault->nrpfb);
+ nvkm_event_ntfy_allow(&fault->nrpfb);
+}
+
+static int
+tu102_fault_oneinit(struct nvkm_fault *fault)
+{
+ struct nvkm_device *device = fault->subdev.device;
+ struct nvkm_intr *intr = &device->vfn->intr;
+ int ret, i;
+
+ ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee0) & 0x0000ffff,
+ NVKM_INTR_PRIO_NORMAL, &fault->subdev, tu102_fault_info_fault,
+ &fault->info_fault);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < fault->buffer_nr; i++) {
+ ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee4 + (i * 4)) >> 16,
+ NVKM_INTR_PRIO_NORMAL, &fault->subdev,
+ tu102_fault_buffer_notify, &fault->buffer[i]->inth);
+ if (ret)
+ return ret;
+ }
+
+ return gv100_fault_oneinit(fault);
}
static const struct nvkm_fault_func
tu102_fault = {
- .oneinit = gv100_fault_oneinit,
+ .oneinit = tu102_fault_oneinit,
.init = tu102_fault_init,
.fini = tu102_fault_fini,
- .intr = tu102_fault_intr,
.buffer.nr = 2,
.buffer.entry_size = 32,
.buffer.info = tu102_fault_buffer_info,
@@ -184,5 +175,10 @@ int
tu102_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fault **pfault)
{
- return nvkm_fault_new_(&tu102_fault, device, type, inst, pfault);
+ int ret = nvkm_fault_new_(&tu102_fault, device, type, inst, pfault);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c
index ac835c9582fd..c123e5893d76 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c
@@ -22,12 +22,28 @@
#include "priv.h"
#include <core/memory.h>
+#include <core/event.h>
#include <subdev/mmu.h>
#include <nvif/clb069.h>
#include <nvif/unpack.h>
static int
+nvkm_ufault_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
+{
+ struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
+ union nvif_clb069_event_args *args = argv;
+
+ if (!uevent)
+ return 0;
+ if (argc != sizeof(args->vn))
+ return -ENOSYS;
+
+ return nvkm_uevent_add(uevent, &buffer->fault->event, buffer->id,
+ NVKM_FAULT_BUFFER_EVENT_PENDING, NULL);
+}
+
+static int
nvkm_ufault_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
@@ -40,18 +56,6 @@ nvkm_ufault_map(struct nvkm_object *object, void *argv, u32 argc,
}
static int
-nvkm_ufault_ntfy(struct nvkm_object *object, u32 type,
- struct nvkm_event **pevent)
-{
- struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
- if (type == NVB069_V0_NTFY_FAULT) {
- *pevent = &buffer->fault->event;
- return 0;
- }
- return -EINVAL;
-}
-
-static int
nvkm_ufault_fini(struct nvkm_object *object, bool suspend)
{
struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
@@ -78,8 +82,8 @@ nvkm_ufault = {
.dtor = nvkm_ufault_dtor,
.init = nvkm_ufault_init,
.fini = nvkm_ufault_fini,
- .ntfy = nvkm_ufault_ntfy,
.map = nvkm_ufault_map,
+ .uevent = nvkm_ufault_uevent,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
index 6faaea948fc4..bac7dcc4c2c1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
@@ -57,6 +57,15 @@ nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile)
}
}
+static void
+nvkm_fb_sysmem_flush_page_init(struct nvkm_device *device)
+{
+ struct nvkm_fb *fb = device->fb;
+
+ if (fb->func->sysmem.flush_page_init)
+ fb->func->sysmem.flush_page_init(fb);
+}
+
int
nvkm_fb_bios_memtype(struct nvkm_bios *bios)
{
@@ -125,12 +134,20 @@ nvkm_fb_oneinit(struct nvkm_subdev *subdev)
return nvkm_mm_init(&fb->tags.mm, 0, 0, tags, 1);
}
-static int
-nvkm_fb_init_scrub_vpr(struct nvkm_fb *fb)
+int
+nvkm_fb_mem_unlock(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
int ret;
+ if (!fb->func->vpr.scrub_required)
+ return 0;
+
+ if (!fb->func->vpr.scrub_required(fb)) {
+ nvkm_debug(subdev, "VPR not locked\n");
+ return 0;
+ }
+
nvkm_debug(subdev, "VPR locked, running scrubber binary\n");
if (!fb->vpr_scrubber.size) {
@@ -168,6 +185,8 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
for (i = 0; i < fb->tile.regions; i++)
fb->func->tile.prog(fb, i, &fb->tile.region[i]);
+ nvkm_fb_sysmem_flush_page_init(subdev->device);
+
if (fb->func->init)
fb->func->init(fb);
@@ -183,13 +202,13 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
if (fb->func->init_unkn)
fb->func->init_unkn(fb);
- if (fb->func->vpr.scrub_required &&
- fb->func->vpr.scrub_required(fb)) {
- ret = nvkm_fb_init_scrub_vpr(fb);
- if (ret)
- return ret;
- }
+ return 0;
+}
+static int
+nvkm_fb_preinit(struct nvkm_subdev *subdev)
+{
+ nvkm_fb_sysmem_flush_page_init(subdev->device);
return 0;
}
@@ -212,20 +231,28 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev)
nvkm_blob_dtor(&fb->vpr_scrubber);
+ if (fb->sysmem.flush_page) {
+ dma_unmap_page(subdev->device->dev, fb->sysmem.flush_page_addr,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(fb->sysmem.flush_page);
+ }
+
if (fb->func->dtor)
return fb->func->dtor(fb);
+
return fb;
}
static const struct nvkm_subdev_func
nvkm_fb = {
.dtor = nvkm_fb_dtor,
+ .preinit = nvkm_fb_preinit,
.oneinit = nvkm_fb_oneinit,
.init = nvkm_fb_init,
.intr = nvkm_fb_intr,
};
-void
+int
nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb *fb)
{
@@ -234,6 +261,19 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
fb->tile.regions = fb->func->tile.regions;
fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", fb->func->default_bigpage);
mutex_init(&fb->tags.mutex);
+
+ if (func->sysmem.flush_page_init) {
+ fb->sysmem.flush_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!fb->sysmem.flush_page)
+ return -ENOMEM;
+
+ fb->sysmem.flush_page_addr = dma_map_page(device->dev, fb->sysmem.flush_page,
+ 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(device->dev, fb->sysmem.flush_page_addr))
+ return -EFAULT;
+ }
+
+ return 0;
}
int
@@ -242,6 +282,5 @@ nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
{
if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL)))
return -ENOMEM;
- nvkm_fb_ctor(func, device, type, inst, *pfb);
- return 0;
+ return nvkm_fb_ctor(func, device, type, inst, *pfb);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
index b47bebfbc26f..5098f219e3e6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
@@ -26,9 +26,10 @@ static const struct nvkm_fb_func
ga100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
- .init = gp100_fb_init,
+ .init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gp100_ram_new,
.default_bigpage = 16,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
index 6ea7908f0563..8b7c8ea5e8a5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
@@ -22,15 +22,42 @@
#include "gf100.h"
#include "ram.h"
+#include <engine/nvdec.h>
+
+static int
+ga102_fb_vpr_scrub(struct nvkm_fb *fb)
+{
+ struct nvkm_falcon_fw fw = {};
+ int ret;
+
+ ret = nvkm_falcon_fw_ctor_hs_v2(&ga102_flcn_fw, "mem-unlock", &fb->subdev, "nvdec/scrubber",
+ 0, &fb->subdev.device->nvdec[0]->falcon, &fw);
+ if (ret)
+ return ret;
+
+ ret = nvkm_falcon_fw_boot(&fw, &fb->subdev, true, NULL, NULL, 0, 0);
+ nvkm_falcon_fw_dtor(&fw);
+ return ret;
+}
+
+static bool
+ga102_fb_vpr_scrub_required(struct nvkm_fb *fb)
+{
+ return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0;
+}
+
static const struct nvkm_fb_func
ga102_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
- .init = gp100_fb_init,
+ .init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = ga102_ram_new,
.default_bigpage = 16,
+ .vpr.scrub_required = ga102_fb_vpr_scrub_required,
+ .vpr.scrub = ga102_fb_vpr_scrub,
};
int
@@ -38,3 +65,9 @@ ga102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, s
{
return gp102_fb_new_(&ga102_fb, device, type, inst, pfb);
}
+
+MODULE_FIRMWARE("nvidia/ga102/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga103/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga104/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga106/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/ga107/nvdec/scrubber.bin");
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
index 9dcc40f9ef79..07db9b397ac1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
@@ -61,14 +61,6 @@ gf100_fb_oneinit(struct nvkm_fb *base)
if (ret)
return ret;
- fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (fb->r100c10_page) {
- fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(device->dev, fb->r100c10))
- return -EFAULT;
- }
-
return 0;
}
@@ -86,14 +78,17 @@ gf100_fb_init_page(struct nvkm_fb *fb)
}
void
+gf100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
+{
+ nvkm_wr32(fb->subdev.device, 0x100c10, fb->sysmem.flush_page_addr >> 8);
+}
+
+void
gf100_fb_init(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
- if (fb->r100c10_page)
- nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
if (base->func->clkgate_pack) {
nvkm_therm_clkgate_init(device->therm,
base->func->clkgate_pack);
@@ -104,13 +99,6 @@ void *
gf100_fb_dtor(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
- struct nvkm_device *device = fb->base.subdev.device;
-
- if (fb->r100c10_page) {
- dma_unmap_page(device->dev, fb->r100c10, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(fb->r100c10_page);
- }
return fb;
}
@@ -136,6 +124,7 @@ gf100_fb = {
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gf100_ram_new,
.default_bigpage = 17,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
index 0cac7b06acc8..77472b558591 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
@@ -6,8 +6,6 @@
struct gf100_fb {
struct nvkm_fb base;
- struct page *r100c10_page;
- dma_addr_t r100c10;
};
int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
@@ -16,7 +14,5 @@ void *gf100_fb_dtor(struct nvkm_fb *);
void gf100_fb_init(struct nvkm_fb *);
void gf100_fb_intr(struct nvkm_fb *);
-void gp100_fb_init(struct nvkm_fb *);
-
void gm200_fb_init(struct nvkm_fb *base);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
index 5acf8d15d06f..fb02092a65eb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
@@ -46,9 +46,6 @@ gm200_fb_init(struct nvkm_fb *base)
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
- if (fb->r100c10_page)
- nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8);
nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8);
nvkm_mask(device, 0x100cc4, 0x00060000,
@@ -62,6 +59,7 @@ gm200_fb = {
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gm200_ram_new,
.default_bigpage = 0 /* per-instance. */,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c
index 86f61a3f2fea..50875af94c18 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c
@@ -30,6 +30,7 @@ gm20b_fb = {
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.default_bigpage = 0 /* per-instance. */,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c
index 09e943edc362..110c08c94849 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c
@@ -44,29 +44,15 @@ gp100_fb_init_remapper(struct nvkm_fb *fb)
nvkm_mask(device, 0x100c14, 0x00040000, 0x00000000);
}
-void
-gp100_fb_init(struct nvkm_fb *base)
-{
- struct gf100_fb *fb = gf100_fb(base);
- struct nvkm_device *device = fb->base.subdev.device;
-
- if (fb->r100c10_page)
- nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
- nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8);
- nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8);
- nvkm_mask(device, 0x100cc4, 0x00060000,
- min(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17);
-}
-
static const struct nvkm_fb_func
gp100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
- .init = gp100_fb_init,
+ .init = gm200_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gp100_ram_new,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c
index 0e78b3d734a0..2658481d575b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c
@@ -24,71 +24,22 @@
#include "gf100.h"
#include "ram.h"
-#include <core/firmware.h>
-#include <core/memory.h>
-#include <nvfw/fw.h>
-#include <nvfw/hs.h>
#include <engine/nvdec.h>
int
gp102_fb_vpr_scrub(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
- struct nvkm_device *device = subdev->device;
- struct nvkm_falcon *falcon = &device->nvdec[0]->falcon;
- struct nvkm_blob *blob = &fb->vpr_scrubber;
- const struct nvfw_bin_hdr *hsbin_hdr;
- const struct nvfw_hs_header *fw_hdr;
- const struct nvfw_hs_load_header *lhdr;
- void *scrub_data;
- u32 patch_loc, patch_sig;
+ struct nvkm_falcon_fw fw = {};
int ret;
- nvkm_falcon_get(falcon, subdev);
-
- hsbin_hdr = nvfw_bin_hdr(subdev, blob->data);
- fw_hdr = nvfw_hs_header(subdev, blob->data + hsbin_hdr->header_offset);
- lhdr = nvfw_hs_load_header(subdev, blob->data + fw_hdr->hdr_offset);
- scrub_data = blob->data + hsbin_hdr->data_offset;
-
- patch_loc = *(u32 *)(blob->data + fw_hdr->patch_loc);
- patch_sig = *(u32 *)(blob->data + fw_hdr->patch_sig);
- if (falcon->debug) {
- memcpy(scrub_data + patch_loc,
- blob->data + fw_hdr->sig_dbg_offset + patch_sig,
- fw_hdr->sig_dbg_size);
- } else {
- memcpy(scrub_data + patch_loc,
- blob->data + fw_hdr->sig_prod_offset + patch_sig,
- fw_hdr->sig_prod_size);
- }
-
- nvkm_falcon_reset(falcon);
- nvkm_falcon_bind_context(falcon, NULL);
-
- nvkm_falcon_load_imem(falcon, scrub_data, lhdr->non_sec_code_off,
- lhdr->non_sec_code_size,
- lhdr->non_sec_code_off >> 8, 0, false);
- nvkm_falcon_load_imem(falcon, scrub_data + lhdr->apps[0],
- ALIGN(lhdr->apps[0], 0x100),
- lhdr->apps[1],
- lhdr->apps[0] >> 8, 0, true);
- nvkm_falcon_load_dmem(falcon, scrub_data + lhdr->data_dma_base, 0,
- lhdr->data_size, 0);
-
- nvkm_falcon_set_start_addr(falcon, 0x0);
- nvkm_falcon_start(falcon);
-
- ret = nvkm_falcon_wait_for_halt(falcon, 500);
- if (ret < 0) {
- ret = -ETIMEDOUT;
- goto end;
- }
+ ret = nvkm_falcon_fw_ctor_hs(&gm200_flcn_fw, "mem-unlock", subdev, NULL,
+ "nvdec/scrubber", 0, &subdev->device->nvdec[0]->falcon, &fw);
+ if (ret)
+ return ret;
- /* put nvdec in clean state - without reset it will remain in HS mode */
- nvkm_falcon_reset(falcon);
-end:
- nvkm_falcon_put(falcon, subdev);
+ ret = nvkm_falcon_fw_boot(&fw, subdev, true, NULL, NULL, 0, 0x00000000);
+ nvkm_falcon_fw_dtor(&fw);
return ret;
}
@@ -104,9 +55,10 @@ static const struct nvkm_fb_func
gp102_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
- .init = gp100_fb_init,
+ .init = gm200_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vpr.scrub_required = gp102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
.ram_new = gp100_ram_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c
index 84c9815a6d48..a04a5f712019 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c
@@ -28,6 +28,7 @@ gp10b_fb = {
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c
index 63daa83ae12d..1f0126437c1a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c
@@ -32,9 +32,10 @@ static const struct nvkm_fb_func
gv100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
- .init = gp100_fb_init,
+ .init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
+ .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vpr.scrub_required = gp102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
.ram_new = gp100_ram_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
index 95fd8f834010..a6efbd913c13 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
@@ -137,8 +137,7 @@ nv50_fb_intr(struct nvkm_fb *base)
struct nv50_fb *fb = nv50_fb(base);
struct nvkm_subdev *subdev = &fb->base.subdev;
struct nvkm_device *device = subdev->device;
- struct nvkm_fifo *fifo = device->fifo;
- struct nvkm_fifo_chan *chan;
+ struct nvkm_chan *chan;
const struct nvkm_enum *en, *re, *cl, *sc;
u32 trap[6], idx, inst;
u8 st0, st1, st2, st3;
@@ -178,35 +177,18 @@ nv50_fb_intr(struct nvkm_fb *base)
else if (en && en->data) sc = nvkm_enum_find(en->data, st3);
else sc = NULL;
- chan = nvkm_fifo_chan_inst(fifo, inst, &flags);
+ chan = nvkm_chan_get_inst(&device->fifo->engine, inst, &flags);
nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] "
"engine %02x [%s] client %02x [%s] "
"subclient %02x [%s] reason %08x [%s]\n",
(trap[5] & 0x00000100) ? "read" : "write",
trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
- chan ? chan->chid : -1, inst,
- chan ? chan->object.client->name : "unknown",
+ chan ? chan->id : -1, inst,
+ chan ? chan->name : "unknown",
st0, en ? en->name : "",
st2, cl ? cl->name : "", st3, sc ? sc->name : "",
st1, re ? re->name : "");
- nvkm_fifo_chan_put(fifo, flags, &chan);
-}
-
-static int
-nv50_fb_oneinit(struct nvkm_fb *base)
-{
- struct nv50_fb *fb = nv50_fb(base);
- struct nvkm_device *device = fb->base.subdev.device;
-
- fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (fb->r100c08_page) {
- fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(device->dev, fb->r100c08))
- return -EFAULT;
- }
-
- return 0;
+ nvkm_chan_put(&chan, flags);
}
static void
@@ -215,12 +197,6 @@ nv50_fb_init(struct nvkm_fb *base)
struct nv50_fb *fb = nv50_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
- /* Not a clue what this is exactly. Without pointing it at a
- * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
- * cause IOMMU "read from address 0" errors (rh#561267)
- */
- nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8);
-
/* This is needed to get meaningful information from 100c90
* on traps. No idea what these values mean exactly. */
nvkm_wr32(device, 0x100c90, fb->func->trap);
@@ -235,17 +211,16 @@ nv50_fb_tags(struct nvkm_fb *base)
return 0;
}
+static void
+nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
+{
+ nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8);
+}
+
static void *
nv50_fb_dtor(struct nvkm_fb *base)
{
struct nv50_fb *fb = nv50_fb(base);
- struct nvkm_device *device = fb->base.subdev.device;
-
- if (fb->r100c08_page) {
- dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(fb->r100c08_page);
- }
return fb;
}
@@ -254,9 +229,9 @@ static const struct nvkm_fb_func
nv50_fb_ = {
.dtor = nv50_fb_dtor,
.tags = nv50_fb_tags,
- .oneinit = nv50_fb_oneinit,
.init = nv50_fb_init,
.intr = nv50_fb_intr,
+ .sysmem.flush_page_init = nv50_fb_sysmem_flush_page_init,
.ram_new = nv50_fb_ram_new,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
index a5e673859a90..4f68bc4513a7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
@@ -7,8 +7,6 @@
struct nv50_fb {
const struct nv50_fb_func *func;
struct nvkm_fb base;
- struct page *r100c08_page;
- dma_addr_t r100c08;
};
struct nv50_fb_func {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
index 3f1be9780c65..ac03eac0f261 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
@@ -16,6 +16,10 @@ struct nvkm_fb_func {
void (*init_unkn)(struct nvkm_fb *);
void (*intr)(struct nvkm_fb *);
+ struct nvkm_fb_func_sysmem {
+ void (*flush_page_init)(struct nvkm_fb *);
+ } sysmem;
+
struct {
bool (*scrub_required)(struct nvkm_fb *);
int (*scrub)(struct nvkm_fb *);
@@ -37,8 +41,8 @@ struct nvkm_fb_func {
const struct nvkm_therm_clkgate_pack *clkgate_pack;
};
-void nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_fb *);
+int nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_fb *);
int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb **);
int nvkm_fb_bios_memtype(struct nvkm_bios *);
@@ -72,6 +76,7 @@ void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
int gf100_fb_oneinit(struct nvkm_fb *);
int gf100_fb_init_page(struct nvkm_fb *);
+void gf100_fb_sysmem_flush_page_init(struct nvkm_fb *);
int gm200_fb_init_page(struct nvkm_fb *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c
index 03b1bdb27770..5c34416cb637 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c
@@ -25,6 +25,7 @@
#include "ram.h"
#include <core/memory.h>
+#include <subdev/instmem.h>
#include <subdev/mmu.h>
struct nvkm_vram {
@@ -35,6 +36,12 @@ struct nvkm_vram {
};
static int
+nvkm_vram_kmap(struct nvkm_memory *memory, struct nvkm_memory **pmemory)
+{
+ return nvkm_instobj_wrap(nvkm_vram(memory)->ram->fb->subdev.device, memory, pmemory);
+}
+
+static int
nvkm_vram_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
struct nvkm_vma *vma, void *argv, u32 argc)
{
@@ -98,6 +105,7 @@ nvkm_vram = {
.addr = nvkm_vram_addr,
.size = nvkm_vram_size,
.map = nvkm_vram_map,
+ .kmap = nvkm_vram_kmap,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
index 048bcc70c3f4..b196baa376dc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
@@ -24,7 +24,6 @@
#include "priv.h"
#include <core/option.h>
-#include <core/notify.h>
static int
nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out)
@@ -123,23 +122,8 @@ nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index)
gpio->func->intr_mask(gpio, type, 1 << index, 1 << index);
}
-static int
-nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_gpio_ntfy_req *req = data;
- if (!WARN_ON(size != sizeof(*req))) {
- notify->size = sizeof(struct nvkm_gpio_ntfy_rep);
- notify->types = req->mask;
- notify->index = req->line;
- return 0;
- }
- return -EINVAL;
-}
-
static const struct nvkm_event_func
nvkm_gpio_intr_func = {
- .ctor = nvkm_gpio_intr_ctor,
.init = nvkm_gpio_intr_init,
.fini = nvkm_gpio_intr_fini,
};
@@ -153,11 +137,9 @@ nvkm_gpio_intr(struct nvkm_subdev *subdev)
gpio->func->intr_stat(gpio, &hi, &lo);
for (i = 0; (hi | lo) && i < gpio->func->lines; i++) {
- struct nvkm_gpio_ntfy_rep rep = {
- .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
- (NVKM_GPIO_LO * !!(lo & (1 << i))),
- };
- nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
+ u32 mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
+ (NVKM_GPIO_LO * !!(lo & (1 << i)));
+ nvkm_event_ntfy(&gpio->event, i, mask);
}
}
@@ -251,6 +233,5 @@ nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device,
nvkm_subdev_ctor(&nvkm_gpio, device, type, inst, &gpio->subdev);
gpio->func = func;
- return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines,
- &gpio->event);
+ return nvkm_event_init(&nvkm_gpio_intr_func, &gpio->subdev, 2, func->lines, &gpio->event);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
index 67cc3b320169..7f61a1ed158b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/subdev/gsp/base.o
nvkm-y += nvkm/subdev/gsp/gv100.o
+nvkm-y += nvkm/subdev/gsp/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
index 22574886b819..591ac95c2669 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
@@ -53,5 +53,7 @@ nvkm_gsp_new_(const struct nvkm_gsp_fwif *fwif, struct nvkm_device *device,
if (IS_ERR(fwif))
return PTR_ERR(fwif);
- return nvkm_falcon_ctor(fwif->flcn, &gsp->subdev, gsp->subdev.name, 0, &gsp->falcon);
+ gsp->func = fwif->func;
+
+ return nvkm_falcon_ctor(gsp->func->flcn, &gsp->subdev, gsp->subdev.name, 0, &gsp->falcon);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c
new file mode 100644
index 000000000000..525267412c3e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+static const struct nvkm_falcon_func
+ga102_gsp_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .select = ga102_flcn_select,
+ .addr2 = 0x1000,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_prep = ga102_flcn_reset_prep,
+ .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing,
+ .imem_dma = &ga102_flcn_dma,
+ .dmem_dma = &ga102_flcn_dma,
+};
+
+static const struct nvkm_gsp_func
+ga102_gsp = {
+ .flcn = &ga102_gsp_flcn,
+};
+
+static int
+ga102_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
+{
+ return 0;
+}
+
+struct nvkm_gsp_fwif
+ga102_gsps[] = {
+ { -1, ga102_gsp_nofw, &ga102_gsp },
+ {}
+};
+
+int
+ga102_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_gsp **pgsp)
+{
+ return nvkm_gsp_new_(ga102_gsps, device, type, inst, pgsp);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c
index 6c4ef62a746a..da6a809cd317 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c
@@ -23,17 +23,20 @@
static const struct nvkm_falcon_func
gv100_gsp_flcn = {
- .fbif = 0x600,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = gp102_sec2_flcn_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
- .start = nvkm_falcon_v1_start,
- .enable = gp102_sec2_flcn_enable,
- .disable = nvkm_falcon_v1_disable,
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
+ .bind_inst = gm200_flcn_bind_inst,
+ .bind_stat = gm200_flcn_bind_stat,
+ .bind_intr = true,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
+};
+
+static const struct nvkm_gsp_func
+gv100_gsp = {
+ .flcn = &gv100_gsp_flcn,
};
static int
@@ -43,8 +46,8 @@ gv100_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
}
static struct nvkm_gsp_fwif
-gv100_gsp[] = {
- { -1, gv100_gsp_nofw, &gv100_gsp_flcn },
+gv100_gsps[] = {
+ { -1, gv100_gsp_nofw, &gv100_gsp },
{}
};
@@ -52,5 +55,5 @@ int
gv100_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gsp **pgsp)
{
- return nvkm_gsp_new_(gv100_gsp, device, type, inst, pgsp);
+ return nvkm_gsp_new_(gv100_gsps, device, type, inst, pgsp);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
index 19381ddd38d4..89749a40203c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
@@ -4,10 +4,14 @@
#include <subdev/gsp.h>
enum nvkm_acr_lsf_id;
+struct nvkm_gsp_func {
+ const struct nvkm_falcon_func *flcn;
+};
+
struct nvkm_gsp_fwif {
int version;
int (*load)(struct nvkm_gsp *, int ver, const struct nvkm_gsp_fwif *);
- const struct nvkm_falcon_func *flcn;
+ const struct nvkm_gsp_func *func;
};
int nvkm_gsp_new_(const struct nvkm_gsp_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
index cb5cb533d91c..976539de4220 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
@@ -26,7 +26,6 @@
#include "bus.h"
#include "pad.h"
-#include <core/notify.h>
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@@ -104,23 +103,8 @@ nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id)
i2c->func->aux_mask(i2c, type, aux->intr, aux->intr);
}
-static int
-nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_i2c_ntfy_req *req = data;
- if (!WARN_ON(size != sizeof(*req))) {
- notify->size = sizeof(struct nvkm_i2c_ntfy_rep);
- notify->types = req->mask;
- notify->index = req->port;
- return 0;
- }
- return -EINVAL;
-}
-
static const struct nvkm_event_func
nvkm_i2c_intr_func = {
- .ctor = nvkm_i2c_intr_ctor,
.init = nvkm_i2c_intr_init,
.fini = nvkm_i2c_intr_fini,
};
@@ -145,13 +129,8 @@ nvkm_i2c_intr(struct nvkm_subdev *subdev)
if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG;
if (rq & aux->intr) mask |= NVKM_I2C_IRQ;
if (tx & aux->intr) mask |= NVKM_I2C_DONE;
- if (mask) {
- struct nvkm_i2c_ntfy_rep rep = {
- .mask = mask,
- };
- nvkm_event_send(&i2c->event, rep.mask, aux->id,
- &rep, sizeof(rep));
- }
+ if (mask)
+ nvkm_event_ntfy(&i2c->event, aux->id, mask);
}
}
@@ -427,5 +406,5 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
}
}
- return nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event);
+ return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, i, &i2c->event);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
index cd8163a52bb6..e0e4f97be029 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
@@ -90,6 +90,18 @@ nvkm_instobj_ctor(const struct nvkm_memory_func *func,
}
int
+nvkm_instobj_wrap(struct nvkm_device *device,
+ struct nvkm_memory *memory, struct nvkm_memory **pmemory)
+{
+ struct nvkm_instmem *imem = device->imem;
+
+ if (!imem->func->memory_wrap)
+ return -ENOSYS;
+
+ return imem->func->memory_wrap(imem, memory, pmemory);
+}
+
+int
nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
struct nvkm_memory **pmemory)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
index c51bac76174c..4b2d7465d22f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
@@ -348,13 +348,11 @@ nv50_instobj_func = {
};
static int
-nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero,
- struct nvkm_memory **pmemory)
+nv50_instobj_wrap(struct nvkm_instmem *base,
+ struct nvkm_memory *memory, struct nvkm_memory **pmemory)
{
struct nv50_instmem *imem = nv50_instmem(base);
struct nv50_instobj *iobj;
- struct nvkm_device *device = imem->base.subdev.device;
- u8 page = max(order_base_2(align), 12);
if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL)))
return -ENOMEM;
@@ -365,7 +363,25 @@ nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero,
refcount_set(&iobj->maps, 0);
INIT_LIST_HEAD(&iobj->lru);
- return nvkm_ram_get(device, 0, 1, page, size, true, true, &iobj->ram);
+ iobj->ram = nvkm_memory_ref(memory);
+ return 0;
+}
+
+static int
+nv50_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
+ struct nvkm_memory **pmemory)
+{
+ u8 page = max(order_base_2(align), 12);
+ struct nvkm_memory *ram;
+ int ret;
+
+ ret = nvkm_ram_get(imem->subdev.device, 0, 1, page, size, true, true, &ram);
+ if (ret)
+ return ret;
+
+ ret = nv50_instobj_wrap(imem, ram, pmemory);
+ nvkm_memory_unref(&ram);
+ return ret;
}
/******************************************************************************
@@ -382,6 +398,7 @@ static const struct nvkm_instmem_func
nv50_instmem = {
.fini = nv50_instmem_fini,
.memory_new = nv50_instobj_new,
+ .memory_wrap = nv50_instobj_wrap,
.zero = false,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
index 56c15e30a5dd..fe92986a3885 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
@@ -12,6 +12,7 @@ struct nvkm_instmem_func {
void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data);
int (*memory_new)(struct nvkm_instmem *, u32 size, u32 align,
bool zero, struct nvkm_memory **);
+ int (*memory_wrap)(struct nvkm_instmem *, struct nvkm_memory *, struct nvkm_memory **);
bool zero;
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
index 728d75010847..0d8a915d727e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
@@ -7,3 +7,4 @@ nvkm-y += nvkm/subdev/ltc/gm200.o
nvkm-y += nvkm/subdev/ltc/gp100.o
nvkm-y += nvkm/subdev/ltc/gp102.o
nvkm-y += nvkm/subdev/ltc/gp10b.o
+nvkm-y += nvkm/subdev/ltc/ga102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
index fa683c190795..f742a7b7b175 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
@@ -97,8 +97,10 @@ nvkm_ltc_init(struct nvkm_subdev *subdev)
struct nvkm_ltc *ltc = nvkm_ltc(subdev);
int i;
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ for (i = ltc->zbc_color_min; i <= ltc->zbc_color_max; i++)
ltc->func->zbc_clear_color(ltc, i, ltc->zbc_color[i]);
+
+ for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) {
ltc->func->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]);
if (ltc->func->zbc_clear_stencil)
ltc->func->zbc_clear_stencil(ltc, i, ltc->zbc_stencil[i]);
@@ -137,7 +139,9 @@ nvkm_ltc_new_(const struct nvkm_ltc_func *func, struct nvkm_device *device,
nvkm_subdev_ctor(&nvkm_ltc, device, type, inst, &ltc->subdev);
ltc->func = func;
mutex_init(&ltc->mutex);
- ltc->zbc_min = 1; /* reserve 0 for disabled */
- ltc->zbc_max = min(func->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1;
+ ltc->zbc_color_min = 1; /* reserve 0 for disabled */
+ ltc->zbc_color_max = min(func->zbc_color, NVKM_LTC_MAX_ZBC_COLOR_CNT) - 1;
+ ltc->zbc_depth_min = 1; /* reserve 0 for disabled */
+ ltc->zbc_depth_max = min(func->zbc_depth, NVKM_LTC_MAX_ZBC_DEPTH_CNT) - 1;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c
new file mode 100644
index 000000000000..159d9f8c95f3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+static void
+ga102_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4])
+{
+ struct nvkm_device *device = ltc->subdev.device;
+
+ nvkm_mask(device, 0x17e338, 0x0000001f, i);
+ nvkm_wr32(device, 0x17e33c, color[0]);
+ nvkm_wr32(device, 0x17e340, color[1]);
+ nvkm_wr32(device, 0x17e344, color[2]);
+ nvkm_wr32(device, 0x17e348, color[3]);
+}
+
+static const struct nvkm_ltc_func
+ga102_ltc = {
+ .oneinit = gp100_ltc_oneinit,
+ .init = gp100_ltc_init,
+ .intr = gp100_ltc_intr,
+ .cbc_clear = gm107_ltc_cbc_clear,
+ .cbc_wait = gm107_ltc_cbc_wait,
+ .zbc_color = 31,
+ .zbc_depth = 16,
+ .zbc_clear_color = ga102_ltc_zbc_clear_color,
+ .zbc_clear_depth = gm107_ltc_zbc_clear_depth,
+ .zbc_clear_stencil = gp102_ltc_zbc_clear_stencil,
+ .invalidate = gf100_ltc_invalidate,
+ .flush = gf100_ltc_flush,
+};
+
+int
+ga102_ltc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_ltc **pltc)
+{
+ return nvkm_ltc_new_(&ga102_ltc, device, type, inst, pltc);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
index fd8aeafc812d..de71ba3c9292 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
@@ -241,7 +241,8 @@ gf100_ltc = {
.intr = gf100_ltc_intr,
.cbc_clear = gf100_ltc_cbc_clear,
.cbc_wait = gf100_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gf100_ltc_zbc_clear_color,
.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
.invalidate = gf100_ltc_invalidate,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
index 94aa09244d67..5d61e3c6ff59 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
@@ -42,7 +42,8 @@ gk104_ltc = {
.intr = gf100_ltc_intr,
.cbc_clear = gf100_ltc_cbc_clear,
.cbc_wait = gf100_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gf100_ltc_zbc_clear_color,
.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
.invalidate = gf100_ltc_invalidate,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
index 54d1d65d5a85..18685d849657 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
@@ -137,7 +137,8 @@ gm107_ltc = {
.intr = gm107_ltc_intr,
.cbc_clear = gm107_ltc_cbc_clear,
.cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gm107_ltc_zbc_clear_color,
.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
.invalidate = gf100_ltc_invalidate,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c
index 8cfdbbdd8e8d..7a9464b9def5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c
@@ -49,7 +49,8 @@ gm200_ltc = {
.intr = gm107_ltc_intr,
.cbc_clear = gm107_ltc_cbc_clear,
.cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gm107_ltc_zbc_clear_color,
.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
.invalidate = gf100_ltc_invalidate,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c
index a4a6cd9b435a..1a17a451754c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c
@@ -61,7 +61,8 @@ gp100_ltc = {
.intr = gp100_ltc_intr,
.cbc_clear = gm107_ltc_cbc_clear,
.cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gm107_ltc_zbc_clear_color,
.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
.invalidate = gf100_ltc_invalidate,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c
index ff05d617e7f4..265a05fd5f6b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c
@@ -36,7 +36,8 @@ gp102_ltc = {
.intr = gp100_ltc_intr,
.cbc_clear = gm107_ltc_cbc_clear,
.cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gm107_ltc_zbc_clear_color,
.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
.zbc_clear_stencil = gp102_ltc_zbc_clear_stencil,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
index dfebd796cb4b..e7e8fdf3adab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
@@ -50,7 +50,8 @@ gp10b_ltc = {
.intr = gp100_ltc_intr,
.cbc_clear = gm107_ltc_cbc_clear,
.cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
+ .zbc_color = 16,
+ .zbc_depth = 16,
.zbc_clear_color = gm107_ltc_zbc_clear_color,
.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
.zbc_clear_stencil = gp102_ltc_zbc_clear_stencil,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
index 2bebe139005d..134e90c9e861 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
@@ -16,7 +16,8 @@ struct nvkm_ltc_func {
void (*cbc_clear)(struct nvkm_ltc *, u32 start, u32 limit);
void (*cbc_wait)(struct nvkm_ltc *);
- int zbc;
+ int zbc_color;
+ int zbc_depth;
void (*zbc_clear_color)(struct nvkm_ltc *, int, const u32[4]);
void (*zbc_clear_depth)(struct nvkm_ltc *, int, const u32);
void (*zbc_clear_stencil)(struct nvkm_ltc *, int, const u32);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
index ac2b34e9ac6a..2a3255ced8b7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
@@ -13,5 +13,4 @@ nvkm-y += nvkm/subdev/mc/gk104.o
nvkm-y += nvkm/subdev/mc/gk20a.o
nvkm-y += nvkm/subdev/mc/gp100.o
nvkm-y += nvkm/subdev/mc/gp10b.o
-nvkm-y += nvkm/subdev/mc/tu102.o
nvkm-y += nvkm/subdev/mc/ga100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
index 21c4af3f81d5..c85600ba69f9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
@@ -37,84 +37,14 @@ nvkm_mc_unk260(struct nvkm_device *device, u32 data)
void
nvkm_mc_intr_mask(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, bool en)
{
- struct nvkm_mc *mc = device->mc;
- const struct nvkm_mc_map *map;
- if (likely(mc) && mc->func->intr_mask) {
- u32 mask = nvkm_top_intr_mask(device, type, inst);
- for (map = mc->func->intr; !mask && map->stat; map++) {
- if (map->type == type && map->inst == inst)
- mask = map->stat;
- }
- mc->func->intr_mask(mc, mask, en ? mask : 0);
- }
-}
-
-void
-nvkm_mc_intr_unarm(struct nvkm_device *device)
-{
- struct nvkm_mc *mc = device->mc;
- if (likely(mc))
- mc->func->intr_unarm(mc);
-}
-
-void
-nvkm_mc_intr_rearm(struct nvkm_device *device)
-{
- struct nvkm_mc *mc = device->mc;
- if (likely(mc))
- mc->func->intr_rearm(mc);
-}
-
-static u32
-nvkm_mc_intr_stat(struct nvkm_mc *mc)
-{
- u32 intr = mc->func->intr_stat(mc);
- if (WARN_ON_ONCE(intr == 0xffffffff))
- intr = 0; /* likely fallen off the bus */
- return intr;
-}
-
-void
-nvkm_mc_intr(struct nvkm_device *device, bool *handled)
-{
- struct nvkm_mc *mc = device->mc;
- struct nvkm_top *top = device->top;
- struct nvkm_top_device *tdev;
- struct nvkm_subdev *subdev;
- const struct nvkm_mc_map *map;
- u32 stat, intr;
-
- if (unlikely(!mc))
- return;
-
- stat = intr = nvkm_mc_intr_stat(mc);
-
- if (top) {
- list_for_each_entry(tdev, &top->device, head) {
- if (tdev->intr >= 0 && (stat & BIT(tdev->intr))) {
- subdev = nvkm_device_subdev(device, tdev->type, tdev->inst);
- if (subdev) {
- nvkm_subdev_intr(subdev);
- stat &= ~BIT(tdev->intr);
- if (!stat)
- break;
- }
- }
- }
- }
+ struct nvkm_subdev *subdev = nvkm_device_subdev(device, type, inst);
- for (map = mc->func->intr; map->stat; map++) {
- if (intr & map->stat) {
- subdev = nvkm_device_subdev(device, map->type, map->inst);
- if (subdev)
- nvkm_subdev_intr(subdev);
- stat &= ~map->stat;
- }
+ if (subdev) {
+ if (en)
+ nvkm_intr_allow(subdev, NVKM_INTR_SUBDEV);
+ else
+ nvkm_intr_block(subdev, NVKM_INTR_SUBDEV);
}
-
- if (stat)
- nvkm_error(&mc->subdev, "intr %08x\n", stat);
- *handled = intr != 0;
}
static u32
@@ -143,9 +73,8 @@ nvkm_mc_reset(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
{
u64 pmc_enable = nvkm_mc_reset_mask(device, true, type, inst);
if (pmc_enable) {
- nvkm_mask(device, 0x000200, pmc_enable, 0x00000000);
- nvkm_mask(device, 0x000200, pmc_enable, pmc_enable);
- nvkm_rd32(device, 0x000200);
+ device->mc->func->device->disable(device->mc, pmc_enable);
+ device->mc->func->device->enable(device->mc, pmc_enable);
}
}
@@ -154,17 +83,15 @@ nvkm_mc_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst
{
u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
if (pmc_enable)
- nvkm_mask(device, 0x000200, pmc_enable, 0x00000000);
+ device->mc->func->device->disable(device->mc, pmc_enable);
}
void
nvkm_mc_enable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
{
u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
- if (pmc_enable) {
- nvkm_mask(device, 0x000200, pmc_enable, pmc_enable);
- nvkm_rd32(device, 0x000200);
- }
+ if (pmc_enable)
+ device->mc->func->device->enable(device->mc, pmc_enable);
}
bool
@@ -172,16 +99,7 @@ nvkm_mc_enabled(struct nvkm_device *device, enum nvkm_subdev_type type, int inst
{
u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
- return (pmc_enable != 0) &&
- ((nvkm_rd32(device, 0x000200) & pmc_enable) == pmc_enable);
-}
-
-
-static int
-nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend)
-{
- nvkm_mc_intr_unarm(subdev->device);
- return 0;
+ return (pmc_enable != 0) && device->mc->func->device->enabled(device->mc, pmc_enable);
}
static int
@@ -190,7 +108,6 @@ nvkm_mc_init(struct nvkm_subdev *subdev)
struct nvkm_mc *mc = nvkm_mc(subdev);
if (mc->func->init)
mc->func->init(mc);
- nvkm_mc_intr_rearm(subdev->device);
return 0;
}
@@ -204,24 +121,27 @@ static const struct nvkm_subdev_func
nvkm_mc = {
.dtor = nvkm_mc_dtor,
.init = nvkm_mc_init,
- .fini = nvkm_mc_fini,
};
-void
-nvkm_mc_ctor(const struct nvkm_mc_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_mc *mc)
-{
- nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev);
- mc->func = func;
-}
-
int
nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
{
struct nvkm_mc *mc;
+ int ret;
+
if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL)))
return -ENOMEM;
- nvkm_mc_ctor(func, device, type, inst, *pmc);
+
+ nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev);
+ mc->func = func;
+
+ if (mc->func->intr) {
+ ret = nvkm_intr_add(mc->func->intr, mc->func->intrs, &mc->subdev,
+ mc->func->intr_nonstall ? 2 : 1, &mc->intr);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c
index 4cfc1c984006..f4ee99137b1f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c
@@ -34,30 +34,29 @@ g84_mc_reset[] = {
{}
};
-static const struct nvkm_mc_map
-g84_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00020000, NVKM_ENGINE_VP },
- { 0x00008000, NVKM_ENGINE_BSP },
- { 0x00004000, NVKM_ENGINE_CIPHER },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000001, NVKM_ENGINE_MPEG },
- { 0x0002d101, NVKM_SUBDEV_FB },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+static const struct nvkm_intr_data
+g84_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_VP , 0, 0, 0x00020000, true },
+ { NVKM_ENGINE_BSP , 0, 0, 0x00008000, true },
+ { NVKM_ENGINE_CIPHER, 0, 0, 0x00004000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x0002d101, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
{},
};
static const struct nvkm_mc_func
g84_mc = {
.init = nv50_mc_init,
- .intr = g84_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = g84_mc_intrs,
+ .device = &nv04_mc_device,
.reset = g84_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
index b7e58d75d894..f42684809f08 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
@@ -34,30 +34,29 @@ g98_mc_reset[] = {
{}
};
-static const struct nvkm_mc_map
-g98_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00020000, NVKM_ENGINE_MSPDEC },
- { 0x00008000, NVKM_ENGINE_MSVLD },
- { 0x00004000, NVKM_ENGINE_SEC },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000001, NVKM_ENGINE_MSPPP },
- { 0x0002d101, NVKM_SUBDEV_FB },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+static const struct nvkm_intr_data
+g98_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_MSPDEC, 0, 0, 0x00020000, true },
+ { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true },
+ { NVKM_ENGINE_SEC , 0, 0, 0x00004000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x0002d101, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
{},
};
static const struct nvkm_mc_func
g98_mc = {
.init = nv50_mc_init,
- .intr = g98_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = g98_mc_intrs,
+ .device = &nv04_mc_device,
.reset = g98_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c
index 4105175dfccd..1e2eabec1a76 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c
@@ -22,49 +22,51 @@
#include "priv.h"
static void
-ga100_mc_intr_unarm(struct nvkm_mc *mc)
+ga100_mc_device_disable(struct nvkm_mc *mc, u32 mask)
{
- nvkm_wr32(mc->subdev.device, 0xb81610, 0x00000004);
-}
+ struct nvkm_device *device = mc->subdev.device;
-static void
-ga100_mc_intr_rearm(struct nvkm_mc *mc)
-{
- nvkm_wr32(mc->subdev.device, 0xb81608, 0x00000004);
+ nvkm_mask(device, 0x000600, mask, 0x00000000);
+ nvkm_rd32(device, 0x000600);
+ nvkm_rd32(device, 0x000600);
}
static void
-ga100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 intr)
+ga100_mc_device_enable(struct nvkm_mc *mc, u32 mask)
{
- nvkm_wr32(mc->subdev.device, 0xb81210, mask & intr );
- nvkm_wr32(mc->subdev.device, 0xb81410, mask & ~(mask & intr));
+ struct nvkm_device *device = mc->subdev.device;
+
+ nvkm_mask(device, 0x000600, mask, mask);
+ nvkm_rd32(device, 0x000600);
+ nvkm_rd32(device, 0x000600);
}
-static u32
-ga100_mc_intr_stat(struct nvkm_mc *mc)
+static bool
+ga100_mc_device_enabled(struct nvkm_mc *mc, u32 mask)
{
- u32 intr_top = nvkm_rd32(mc->subdev.device, 0xb81600), intr = 0x00000000;
- if (intr_top & 0x00000004)
- intr = nvkm_mask(mc->subdev.device, 0xb81010, 0x00000000, 0x00000000);
- return intr;
+ return (nvkm_rd32(mc->subdev.device, 0x000600) & mask) == mask;
}
+const struct nvkm_mc_device_func
+ga100_mc_device = {
+ .enabled = ga100_mc_device_enabled,
+ .enable = ga100_mc_device_enable,
+ .disable = ga100_mc_device_disable,
+};
+
static void
ga100_mc_init(struct nvkm_mc *mc)
{
- nv50_mc_init(mc);
- nvkm_wr32(mc->subdev.device, 0xb81210, 0xffffffff);
+ struct nvkm_device *device = mc->subdev.device;
+
+ nvkm_wr32(device, 0x000200, 0xffffffff);
+ nvkm_wr32(device, 0x000600, 0xffffffff);
}
static const struct nvkm_mc_func
ga100_mc = {
.init = ga100_mc_init,
- .intr = gp100_mc_intr,
- .intr_unarm = ga100_mc_intr_unarm,
- .intr_rearm = ga100_mc_intr_rearm,
- .intr_mask = ga100_mc_intr_mask,
- .intr_stat = ga100_mc_intr_stat,
- .reset = gk104_mc_reset,
+ .device = &ga100_mc_device,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
index 3a589c6f7fad..ab1eaa37123a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
@@ -36,64 +36,29 @@ gf100_mc_reset[] = {
{}
};
-static const struct nvkm_mc_map
-gf100_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00020000, NVKM_ENGINE_MSPDEC },
- { 0x00008000, NVKM_ENGINE_MSVLD },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000040, NVKM_ENGINE_CE, 1 },
- { 0x00000020, NVKM_ENGINE_CE, 0 },
- { 0x00000001, NVKM_ENGINE_MSPPP },
- { 0x40000000, NVKM_SUBDEV_PRIVRING },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x08000000, NVKM_SUBDEV_FB },
- { 0x02000000, NVKM_SUBDEV_LTC },
- { 0x01000000, NVKM_SUBDEV_PMU },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
- { 0x00040000, NVKM_SUBDEV_THERM },
- { 0x00002000, NVKM_SUBDEV_FB },
+static const struct nvkm_intr_data
+gf100_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_MSPDEC , 0, 0, 0x00020000, true },
+ { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000 },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_CE , 1, 0, 0x00000040, true },
+ { NVKM_ENGINE_CE , 0, 0, 0x00000020, true },
+ { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true },
+ { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true },
+ { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
+ { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true },
{},
};
void
-gf100_mc_intr_unarm(struct nvkm_mc *mc)
-{
- struct nvkm_device *device = mc->subdev.device;
- nvkm_wr32(device, 0x000140, 0x00000000);
- nvkm_wr32(device, 0x000144, 0x00000000);
- nvkm_rd32(device, 0x000140);
-}
-
-void
-gf100_mc_intr_rearm(struct nvkm_mc *mc)
-{
- struct nvkm_device *device = mc->subdev.device;
- nvkm_wr32(device, 0x000140, 0x00000001);
- nvkm_wr32(device, 0x000144, 0x00000001);
-}
-
-u32
-gf100_mc_intr_stat(struct nvkm_mc *mc)
-{
- struct nvkm_device *device = mc->subdev.device;
- u32 intr0 = nvkm_rd32(device, 0x000100);
- u32 intr1 = nvkm_rd32(device, 0x000104);
- return intr0 | intr1;
-}
-
-void
-gf100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat)
-{
- struct nvkm_device *device = mc->subdev.device;
- nvkm_mask(device, 0x000640, mask, stat);
- nvkm_mask(device, 0x000644, mask, stat);
-}
-
-void
gf100_mc_unk260(struct nvkm_mc *mc, u32 data)
{
nvkm_wr32(mc->subdev.device, 0x000260, data);
@@ -102,12 +67,11 @@ gf100_mc_unk260(struct nvkm_mc *mc, u32 data)
static const struct nvkm_mc_func
gf100_mc = {
.init = nv50_mc_init,
- .intr = gf100_mc_intr,
- .intr_unarm = gf100_mc_intr_unarm,
- .intr_rearm = gf100_mc_intr_rearm,
- .intr_mask = gf100_mc_intr_mask,
- .intr_stat = gf100_mc_intr_stat,
+ .intr = &gt215_mc_intr,
+ .intrs = gf100_mc_intrs,
+ .intr_nonstall = true,
.reset = gf100_mc_reset,
+ .device = &nv04_mc_device,
.unk260 = gf100_mc_unk260,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c
index d9b9067fa93f..66829586a124 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c
@@ -30,32 +30,32 @@ gk104_mc_reset[] = {
{}
};
-const struct nvkm_mc_map
-gk104_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x40000000, NVKM_SUBDEV_PRIVRING },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x08000000, NVKM_SUBDEV_FB },
- { 0x02000000, NVKM_SUBDEV_LTC },
- { 0x01000000, NVKM_SUBDEV_PMU },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
- { 0x00040000, NVKM_SUBDEV_THERM },
- { 0x00002000, NVKM_SUBDEV_FB },
+const struct nvkm_intr_data
+gk104_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true },
+ { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true },
+ { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
+ { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true },
+ { NVKM_SUBDEV_TOP , 0, 0, 0x00001000 },
+ { NVKM_SUBDEV_TOP , 0, 0, 0xffffefff, true },
{},
};
static const struct nvkm_mc_func
gk104_mc = {
.init = nv50_mc_init,
- .intr = gk104_mc_intr,
- .intr_unarm = gf100_mc_intr_unarm,
- .intr_rearm = gf100_mc_intr_rearm,
- .intr_mask = gf100_mc_intr_mask,
- .intr_stat = gf100_mc_intr_stat,
+ .intr = &gt215_mc_intr,
+ .intrs = gk104_mc_intrs,
+ .intr_nonstall = true,
.reset = gk104_mc_reset,
+ .device = &nv04_mc_device,
.unk260 = gf100_mc_unk260,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
index 03590292749a..d98a6563a411 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
@@ -26,11 +26,10 @@
static const struct nvkm_mc_func
gk20a_mc = {
.init = nv50_mc_init,
- .intr = gk104_mc_intr,
- .intr_unarm = gf100_mc_intr_unarm,
- .intr_rearm = gf100_mc_intr_rearm,
- .intr_mask = gf100_mc_intr_mask,
- .intr_stat = gf100_mc_intr_stat,
+ .intr = &gt215_mc_intr,
+ .intrs = gk104_mc_intrs,
+ .intr_nonstall = true,
+ .device = &nv04_mc_device,
.reset = gk104_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c
index 5fd1a0595c33..eb2ab03f4360 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c
@@ -21,108 +21,82 @@
*
* Authors: Ben Skeggs
*/
-#define gp100_mc(p) container_of((p), struct gp100_mc, base)
#include "priv.h"
-struct gp100_mc {
- struct nvkm_mc base;
- spinlock_t lock;
- bool intr;
- u32 mask;
+const struct nvkm_intr_data
+gp100_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_SUBDEV_FAULT , 0, 0, 0x00000200, true },
+ { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true },
+ { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true },
+ { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
+ { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true },
+ { NVKM_SUBDEV_TOP , 0, 0, 0x00009000 },
+ { NVKM_SUBDEV_TOP , 0, 0, 0xffff6fff, true },
+ {},
};
static void
-gp100_mc_intr_update(struct gp100_mc *mc)
+gp100_mc_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask)
{
- struct nvkm_device *device = mc->base.subdev.device;
- u32 mask = mc->intr ? mc->mask : 0, i;
- for (i = 0; i < 2; i++) {
- nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask);
- nvkm_wr32(device, 0x000160 + (i * 0x04), mask);
- }
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+
+ nvkm_wr32(mc->subdev.device, 0x000160 + (leaf * 4), mask);
}
-void
-gp100_mc_intr_unarm(struct nvkm_mc *base)
+static void
+gp100_mc_intr_block(struct nvkm_intr *intr, int leaf, u32 mask)
{
- struct gp100_mc *mc = gp100_mc(base);
- unsigned long flags;
- spin_lock_irqsave(&mc->lock, flags);
- mc->intr = false;
- gp100_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+
+ nvkm_wr32(mc->subdev.device, 0x000180 + (leaf * 4), mask);
}
-void
-gp100_mc_intr_rearm(struct nvkm_mc *base)
+static void
+gp100_mc_intr_rearm(struct nvkm_intr *intr)
{
- struct gp100_mc *mc = gp100_mc(base);
- unsigned long flags;
- spin_lock_irqsave(&mc->lock, flags);
- mc->intr = true;
- gp100_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
+ int i;
+
+ for (i = 0; i < intr->leaves; i++)
+ intr->func->allow(intr, i, intr->mask[i]);
}
-void
-gp100_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr)
+static void
+gp100_mc_intr_unarm(struct nvkm_intr *intr)
{
- struct gp100_mc *mc = gp100_mc(base);
- unsigned long flags;
- spin_lock_irqsave(&mc->lock, flags);
- mc->mask = (mc->mask & ~mask) | intr;
- gp100_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
+ int i;
+
+ for (i = 0; i < intr->leaves; i++)
+ intr->func->block(intr, i, 0xffffffff);
}
-const struct nvkm_mc_map
-gp100_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000200, NVKM_SUBDEV_FAULT },
- { 0x40000000, NVKM_SUBDEV_PRIVRING },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x08000000, NVKM_SUBDEV_FB },
- { 0x02000000, NVKM_SUBDEV_LTC },
- { 0x01000000, NVKM_SUBDEV_PMU },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
- { 0x00040000, NVKM_SUBDEV_THERM },
- { 0x00002000, NVKM_SUBDEV_FB },
- {},
+const struct nvkm_intr_func
+gp100_mc_intr = {
+ .pending = nv04_mc_intr_pending,
+ .unarm = gp100_mc_intr_unarm,
+ .rearm = gp100_mc_intr_rearm,
+ .block = gp100_mc_intr_block,
+ .allow = gp100_mc_intr_allow,
};
static const struct nvkm_mc_func
gp100_mc = {
.init = nv50_mc_init,
- .intr = gp100_mc_intr,
- .intr_unarm = gp100_mc_intr_unarm,
- .intr_rearm = gp100_mc_intr_rearm,
- .intr_mask = gp100_mc_intr_mask,
- .intr_stat = gf100_mc_intr_stat,
+ .intr = &gp100_mc_intr,
+ .intrs = gp100_mc_intrs,
+ .intr_nonstall = true,
+ .device = &nv04_mc_device,
.reset = gk104_mc_reset,
};
int
-gp100_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
-{
- struct gp100_mc *mc;
-
- if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL)))
- return -ENOMEM;
- nvkm_mc_ctor(func, device, type, inst, &mc->base);
- *pmc = &mc->base;
-
- spin_lock_init(&mc->lock);
- mc->intr = false;
- mc->mask = 0x7fffffff;
- return 0;
-}
-
-int
gp100_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
{
- return gp100_mc_new_(&gp100_mc, device, type, inst, pmc);
+ return nvkm_mc_new_(&gp100_mc, device, type, inst, pmc);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c
index dd581d030ced..9bed9c5ea5d3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c
@@ -34,16 +34,15 @@ gp10b_mc_init(struct nvkm_mc *mc)
static const struct nvkm_mc_func
gp10b_mc = {
.init = gp10b_mc_init,
- .intr = gp100_mc_intr,
- .intr_unarm = gp100_mc_intr_unarm,
- .intr_rearm = gp100_mc_intr_rearm,
- .intr_mask = gp100_mc_intr_mask,
- .intr_stat = gf100_mc_intr_stat,
+ .intr = &gp100_mc_intr,
+ .intrs = gp100_mc_intrs,
+ .intr_nonstall = true,
+ .device = &nv04_mc_device,
.reset = gk104_mc_reset,
};
int
gp10b_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
{
- return gp100_mc_new_(&gp10b_mc, device, type, inst, pmc);
+ return nvkm_mc_new_(&gp10b_mc, device, type, inst, pmc);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c
index 1b4d43531dba..3d61836e42a3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c
@@ -34,39 +34,56 @@ gt215_mc_reset[] = {
{}
};
-static const struct nvkm_mc_map
-gt215_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00400000, NVKM_ENGINE_CE, 0 },
- { 0x00020000, NVKM_ENGINE_MSPDEC },
- { 0x00008000, NVKM_ENGINE_MSVLD },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000001, NVKM_ENGINE_MSPPP },
- { 0x00429101, NVKM_SUBDEV_FB },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
- { 0x00080000, NVKM_SUBDEV_THERM },
- { 0x00040000, NVKM_SUBDEV_PMU },
+static const struct nvkm_intr_data
+gt215_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_CE , 0, 0, 0x00400000, true },
+ { NVKM_ENGINE_MSPDEC, 0, 0, 0x00020000, true },
+ { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x00429101, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true },
+ { NVKM_SUBDEV_THERM , 0, 0, 0x00080000, true },
+ { NVKM_SUBDEV_PMU , 0, 0, 0x00040000, true },
{},
};
static void
-gt215_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat)
+gt215_mc_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+
+ nvkm_mask(mc->subdev.device, 0x000640 + (leaf * 4), mask, mask);
+}
+
+static void
+gt215_mc_intr_block(struct nvkm_intr *intr, int leaf, u32 mask)
{
- nvkm_mask(mc->subdev.device, 0x000640, mask, stat);
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+
+ nvkm_mask(mc->subdev.device, 0x000640 + (leaf * 4), mask, 0);
}
+const struct nvkm_intr_func
+gt215_mc_intr = {
+ .pending = nv04_mc_intr_pending,
+ .unarm = nv04_mc_intr_unarm,
+ .rearm = nv04_mc_intr_rearm,
+ .block = gt215_mc_intr_block,
+ .allow = gt215_mc_intr_allow,
+};
+
static const struct nvkm_mc_func
gt215_mc = {
.init = nv50_mc_init,
- .intr = gt215_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_mask = gt215_mc_intr_mask,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = gt215_mc_intrs,
+ .device = &nv04_mc_device,
.reset = gt215_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
index bc0d09bafa99..8482a5550e5f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
@@ -30,37 +30,89 @@ nv04_mc_reset[] = {
{}
};
-static const struct nvkm_mc_map
-nv04_mc_intr[] = {
- { 0x01010000, NVKM_ENGINE_DISP },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+static void
+nv04_mc_device_disable(struct nvkm_mc *mc, u32 mask)
+{
+ nvkm_mask(mc->subdev.device, 0x000200, mask, 0x00000000);
+}
+
+static void
+nv04_mc_device_enable(struct nvkm_mc *mc, u32 mask)
+{
+ struct nvkm_device *device = mc->subdev.device;
+
+ nvkm_mask(device, 0x000200, mask, mask);
+ nvkm_rd32(device, 0x000200);
+}
+
+static bool
+nv04_mc_device_enabled(struct nvkm_mc *mc, u32 mask)
+{
+ return (nvkm_rd32(mc->subdev.device, 0x000200) & mask) == mask;
+}
+
+const struct nvkm_mc_device_func
+nv04_mc_device = {
+ .enabled = nv04_mc_device_enabled,
+ .enable = nv04_mc_device_enable,
+ .disable = nv04_mc_device_disable,
+};
+
+static const struct nvkm_intr_data
+nv04_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x01010000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true },
{}
};
void
-nv04_mc_intr_unarm(struct nvkm_mc *mc)
+nv04_mc_intr_rearm(struct nvkm_intr *intr)
{
- struct nvkm_device *device = mc->subdev.device;
- nvkm_wr32(device, 0x000140, 0x00000000);
- nvkm_rd32(device, 0x000140);
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+ int leaf;
+
+ for (leaf = 0; leaf < intr->leaves; leaf++)
+ nvkm_wr32(mc->subdev.device, 0x000140 + (leaf * 4), 0x00000001);
}
void
-nv04_mc_intr_rearm(struct nvkm_mc *mc)
+nv04_mc_intr_unarm(struct nvkm_intr *intr)
{
- struct nvkm_device *device = mc->subdev.device;
- nvkm_wr32(device, 0x000140, 0x00000001);
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+ int leaf;
+
+ for (leaf = 0; leaf < intr->leaves; leaf++)
+ nvkm_wr32(mc->subdev.device, 0x000140 + (leaf * 4), 0x00000000);
+
+ nvkm_rd32(mc->subdev.device, 0x000140);
}
-u32
-nv04_mc_intr_stat(struct nvkm_mc *mc)
+bool
+nv04_mc_intr_pending(struct nvkm_intr *intr)
{
- return nvkm_rd32(mc->subdev.device, 0x000100);
+ struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr);
+ bool pending = false;
+ int leaf;
+
+ for (leaf = 0; leaf < intr->leaves; leaf++) {
+ intr->stat[leaf] = nvkm_rd32(mc->subdev.device, 0x000100 + (leaf * 4));
+ if (intr->stat[leaf])
+ pending = true;
+ }
+
+ return pending;
}
+const struct nvkm_intr_func
+nv04_mc_intr = {
+ .pending = nv04_mc_intr_pending,
+ .unarm = nv04_mc_intr_unarm,
+ .rearm = nv04_mc_intr_rearm,
+};
+
void
nv04_mc_init(struct nvkm_mc *mc)
{
@@ -72,10 +124,9 @@ nv04_mc_init(struct nvkm_mc *mc)
static const struct nvkm_mc_func
nv04_mc = {
.init = nv04_mc_init,
- .intr = nv04_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = nv04_mc_intrs,
+ .device = &nv04_mc_device,
.reset = nv04_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c
index ab59ca1ee068..6d6278f434a4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c
@@ -23,23 +23,22 @@
*/
#include "priv.h"
-static const struct nvkm_mc_map
-nv11_mc_intr[] = {
- { 0x03010000, NVKM_ENGINE_DISP },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+static const struct nvkm_intr_data
+nv11_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x03010000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true },
{}
};
static const struct nvkm_mc_func
nv11_mc = {
.init = nv04_mc_init,
- .intr = nv11_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = nv11_mc_intrs,
+ .device = &nv04_mc_device,
.reset = nv04_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c
index 03d756e26e57..dbad7c111ceb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c
@@ -31,24 +31,23 @@ nv17_mc_reset[] = {
{}
};
-const struct nvkm_mc_map
-nv17_mc_intr[] = {
- { 0x03010000, NVKM_ENGINE_DISP },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000001, NVKM_ENGINE_MPEG },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+const struct nvkm_intr_data
+nv17_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x03010000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true },
{}
};
static const struct nvkm_mc_func
nv17_mc = {
.init = nv04_mc_init,
- .intr = nv17_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = nv17_mc_intrs,
+ .device = &nv04_mc_device,
.reset = nv17_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
index 95f65766e8b0..649a9fcc0a2f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
@@ -40,10 +40,9 @@ nv44_mc_init(struct nvkm_mc *mc)
static const struct nvkm_mc_func
nv44_mc = {
.init = nv44_mc_init,
- .intr = nv17_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = nv17_mc_intrs,
+ .device = &nv04_mc_device,
.reset = nv17_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
index fce3613cdfa5..d41099d35690 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
@@ -23,17 +23,17 @@
*/
#include "priv.h"
-static const struct nvkm_mc_map
-nv50_mc_intr[] = {
- { 0x04000000, NVKM_ENGINE_DISP },
- { 0x00001000, NVKM_ENGINE_GR },
- { 0x00000100, NVKM_ENGINE_FIFO },
- { 0x00000001, NVKM_ENGINE_MPEG },
- { 0x00001101, NVKM_SUBDEV_FB },
- { 0x10000000, NVKM_SUBDEV_BUS },
- { 0x00200000, NVKM_SUBDEV_GPIO },
- { 0x00200000, NVKM_SUBDEV_I2C },
- { 0x00100000, NVKM_SUBDEV_TIMER },
+static const struct nvkm_intr_data
+nv50_mc_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true },
+ { NVKM_ENGINE_GR , 0, 0, 0x00001000, true },
+ { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 },
+ { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true },
+ { NVKM_SUBDEV_FB , 0, 0, 0x00001101, true },
+ { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true },
+ { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true },
{},
};
@@ -47,10 +47,9 @@ nv50_mc_init(struct nvkm_mc *mc)
static const struct nvkm_mc_func
nv50_mc = {
.init = nv50_mc_init,
- .intr = nv50_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_stat = nv04_mc_intr_stat,
+ .intr = &nv04_mc_intr,
+ .intrs = nv50_mc_intrs,
+ .device = &nv04_mc_device,
.reset = nv17_mc_reset,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
index c8bcabb98f99..7f38d54b4bc2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
@@ -4,8 +4,6 @@
#define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev)
#include <subdev/mc.h>
-void nvkm_mc_ctor(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
- struct nvkm_mc *);
int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_mc **);
@@ -18,46 +16,44 @@ struct nvkm_mc_map {
struct nvkm_mc_func {
void (*init)(struct nvkm_mc *);
- const struct nvkm_mc_map *intr;
- /* disable reporting of interrupts to host */
- void (*intr_unarm)(struct nvkm_mc *);
- /* enable reporting of interrupts to host */
- void (*intr_rearm)(struct nvkm_mc *);
- /* (un)mask delivery of specific interrupts */
- void (*intr_mask)(struct nvkm_mc *, u32 mask, u32 stat);
- /* retrieve pending interrupt mask (NV_PMC_INTR) */
- u32 (*intr_stat)(struct nvkm_mc *);
+
+ const struct nvkm_intr_func *intr;
+ const struct nvkm_intr_data *intrs;
+ bool intr_nonstall;
+
+ const struct nvkm_mc_device_func {
+ bool (*enabled)(struct nvkm_mc *, u32 mask);
+ void (*enable)(struct nvkm_mc *, u32 mask);
+ void (*disable)(struct nvkm_mc *, u32 mask);
+ } *device;
+
const struct nvkm_mc_map *reset;
+
void (*unk260)(struct nvkm_mc *, u32);
};
void nv04_mc_init(struct nvkm_mc *);
-void nv04_mc_intr_unarm(struct nvkm_mc *);
-void nv04_mc_intr_rearm(struct nvkm_mc *);
-u32 nv04_mc_intr_stat(struct nvkm_mc *);
+extern const struct nvkm_intr_func nv04_mc_intr;
+bool nv04_mc_intr_pending(struct nvkm_intr *);
+void nv04_mc_intr_unarm(struct nvkm_intr *);
+void nv04_mc_intr_rearm(struct nvkm_intr *);
+extern const struct nvkm_mc_device_func nv04_mc_device;
extern const struct nvkm_mc_map nv04_mc_reset[];
-extern const struct nvkm_mc_map nv17_mc_intr[];
+extern const struct nvkm_intr_data nv17_mc_intrs[];
extern const struct nvkm_mc_map nv17_mc_reset[];
void nv44_mc_init(struct nvkm_mc *);
void nv50_mc_init(struct nvkm_mc *);
-void gk104_mc_init(struct nvkm_mc *);
-void gf100_mc_intr_unarm(struct nvkm_mc *);
-void gf100_mc_intr_rearm(struct nvkm_mc *);
-void gf100_mc_intr_mask(struct nvkm_mc *, u32, u32);
-u32 gf100_mc_intr_stat(struct nvkm_mc *);
+extern const struct nvkm_intr_func gt215_mc_intr;
void gf100_mc_unk260(struct nvkm_mc *, u32);
-void gp100_mc_intr_unarm(struct nvkm_mc *);
-void gp100_mc_intr_rearm(struct nvkm_mc *);
-void gp100_mc_intr_mask(struct nvkm_mc *, u32, u32);
-int gp100_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
- struct nvkm_mc **);
-extern const struct nvkm_mc_map gk104_mc_intr[];
+void gk104_mc_init(struct nvkm_mc *);
+extern const struct nvkm_intr_data gk104_mc_intrs[];
extern const struct nvkm_mc_map gk104_mc_reset[];
-extern const struct nvkm_mc_map gp100_mc_intr[];
+extern const struct nvkm_intr_func gp100_mc_intr;
+extern const struct nvkm_intr_data gp100_mc_intrs[];
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c
deleted file mode 100644
index a96084b34a78..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2018 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- */
-#define tu102_mc(p) container_of((p), struct tu102_mc, base)
-#include "priv.h"
-
-struct tu102_mc {
- struct nvkm_mc base;
- spinlock_t lock;
- bool intr;
- u32 mask;
-};
-
-static void
-tu102_mc_intr_update(struct tu102_mc *mc)
-{
- struct nvkm_device *device = mc->base.subdev.device;
- u32 mask = mc->intr ? mc->mask : 0, i;
-
- for (i = 0; i < 2; i++) {
- nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask);
- nvkm_wr32(device, 0x000160 + (i * 0x04), mask);
- }
-
- if (mask & 0x00000200)
- nvkm_wr32(device, 0xb81608, 0x6);
- else
- nvkm_wr32(device, 0xb81610, 0x6);
-}
-
-static void
-tu102_mc_intr_unarm(struct nvkm_mc *base)
-{
- struct tu102_mc *mc = tu102_mc(base);
- unsigned long flags;
-
- spin_lock_irqsave(&mc->lock, flags);
- mc->intr = false;
- tu102_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
-}
-
-static void
-tu102_mc_intr_rearm(struct nvkm_mc *base)
-{
- struct tu102_mc *mc = tu102_mc(base);
- unsigned long flags;
-
- spin_lock_irqsave(&mc->lock, flags);
- mc->intr = true;
- tu102_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
-}
-
-static void
-tu102_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr)
-{
- struct tu102_mc *mc = tu102_mc(base);
- unsigned long flags;
-
- spin_lock_irqsave(&mc->lock, flags);
- mc->mask = (mc->mask & ~mask) | intr;
- tu102_mc_intr_update(mc);
- spin_unlock_irqrestore(&mc->lock, flags);
-}
-
-static u32
-tu102_mc_intr_stat(struct nvkm_mc *mc)
-{
- struct nvkm_device *device = mc->subdev.device;
- u32 intr0 = nvkm_rd32(device, 0x000100);
- u32 intr1 = nvkm_rd32(device, 0x000104);
- u32 intr_top = nvkm_rd32(device, 0xb81600);
-
- /* Turing and above route the MMU fault interrupts via a different
- * interrupt tree with different control registers. For the moment remap
- * them back to the old PMC vector.
- */
- if (intr_top & 0x00000006)
- intr0 |= 0x00000200;
-
- return intr0 | intr1;
-}
-
-
-static const struct nvkm_mc_func
-tu102_mc = {
- .init = nv50_mc_init,
- .intr = gp100_mc_intr,
- .intr_unarm = tu102_mc_intr_unarm,
- .intr_rearm = tu102_mc_intr_rearm,
- .intr_mask = tu102_mc_intr_mask,
- .intr_stat = tu102_mc_intr_stat,
- .reset = gk104_mc_reset,
-};
-
-static int
-tu102_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
- enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
-{
- struct tu102_mc *mc;
-
- if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL)))
- return -ENOMEM;
- nvkm_mc_ctor(func, device, type, inst, &mc->base);
- *pmc = &mc->base;
-
- spin_lock_init(&mc->lock);
- mc->intr = false;
- mc->mask = 0x7fffffff;
- return 0;
-}
-
-int
-tu102_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
-{
- return tu102_mc_new_(&tu102_mc, device, type, inst, pmc);
-}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
index 186b4e63e559..524cd3c0e3fe 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
@@ -39,7 +39,7 @@ nvkm_uvmm_search(struct nvkm_client *client, u64 handle)
if (IS_ERR(object))
return (void *)object;
- return nvkm_uvmm(object)->vmm;
+ return nvkm_vmm_ref(nvkm_uvmm(object)->vmm);
}
static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
index a7d42ea8ba28..5a0de45d36ce 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
@@ -26,7 +26,15 @@
#include <core/option.h>
#include <core/pci.h>
-#include <subdev/mc.h>
+
+void
+nvkm_pci_msi_rearm(struct nvkm_device *device)
+{
+ struct nvkm_pci *pci = device->pci;
+
+ if (pci && pci->msi)
+ pci->func->msi_rearm(pci);
+}
u32
nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr)
@@ -65,24 +73,6 @@ nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow)
nvkm_pci_wr32(pci, 0x0050, data);
}
-static irqreturn_t
-nvkm_pci_intr(int irq, void *arg)
-{
- struct nvkm_pci *pci = arg;
- struct nvkm_device *device = pci->subdev.device;
- bool handled = false;
-
- if (pci->irq < 0)
- return IRQ_HANDLED;
-
- nvkm_mc_intr_unarm(device);
- if (pci->msi)
- pci->func->msi_rearm(pci);
- nvkm_mc_intr(device, &handled);
- nvkm_mc_intr_rearm(device);
- return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
static int
nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend)
{
@@ -107,7 +97,6 @@ static int
nvkm_pci_oneinit(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
- struct pci_dev *pdev = pci->pdev;
int ret;
if (pci_is_pcie(pci->pdev)) {
@@ -116,11 +105,6 @@ nvkm_pci_oneinit(struct nvkm_subdev *subdev)
return ret;
}
- ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci);
- if (ret)
- return ret;
-
- pci->irq = pdev->irq;
return 0;
}
@@ -157,15 +141,6 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev)
nvkm_agp_dtor(pci);
- if (pci->irq >= 0) {
- /* freq_irq() will call the handler, we use pci->irq == -1
- * to signal that it's been torn down and should be a noop.
- */
- int irq = pci->irq;
- pci->irq = -1;
- free_irq(irq, pci);
- }
-
if (pci->msi)
pci_disable_msi(pci->pdev);
@@ -192,7 +167,6 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
nvkm_subdev_ctor(&nvkm_pci_func, device, type, inst, &pci->subdev);
pci->func = func;
pci->pdev = device->func->pci(device)->pdev;
- pci->irq = -1;
pci->pcie.speed = -1;
pci->pcie.width = -1;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
index 455e95a89259..8f2f50ad4ded 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
@@ -81,43 +81,12 @@ nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend)
{
struct nvkm_pmu *pmu = nvkm_pmu(subdev);
+ if (!subdev->use.enabled)
+ return 0;
+
if (pmu->func->fini)
pmu->func->fini(pmu);
- flush_work(&pmu->recv.work);
-
- reinit_completion(&pmu->wpr_ready);
-
- nvkm_falcon_cmdq_fini(pmu->lpq);
- nvkm_falcon_cmdq_fini(pmu->hpq);
- pmu->initmsg_received = false;
- return 0;
-}
-
-static void
-nvkm_pmu_reset(struct nvkm_pmu *pmu)
-{
- struct nvkm_device *device = pmu->subdev.device;
-
- if (!pmu->func->enabled(pmu))
- return;
-
- /* Reset. */
- if (pmu->func->reset)
- pmu->func->reset(pmu);
-
- /* Wait for IMEM/DMEM scrubbing to be complete. */
- nvkm_msec(device, 2000,
- if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006))
- break;
- );
-}
-
-static int
-nvkm_pmu_preinit(struct nvkm_subdev *subdev)
-{
- struct nvkm_pmu *pmu = nvkm_pmu(subdev);
- nvkm_pmu_reset(pmu);
return 0;
}
@@ -125,22 +94,10 @@ static int
nvkm_pmu_init(struct nvkm_subdev *subdev)
{
struct nvkm_pmu *pmu = nvkm_pmu(subdev);
- struct nvkm_device *device = pmu->subdev.device;
if (!pmu->func->init)
return 0;
- if (pmu->func->enabled(pmu)) {
- /* Inhibit interrupts, and wait for idle. */
- nvkm_wr32(device, 0x10a014, 0x0000ffff);
- nvkm_msec(device, 2000,
- if (!nvkm_rd32(device, 0x10a04c))
- break;
- );
-
- nvkm_pmu_reset(pmu);
- }
-
return pmu->func->init(pmu);
}
@@ -160,7 +117,6 @@ nvkm_pmu_dtor(struct nvkm_subdev *subdev)
static const struct nvkm_subdev_func
nvkm_pmu = {
.dtor = nvkm_pmu_dtor,
- .preinit = nvkm_pmu_preinit,
.init = nvkm_pmu_init,
.fini = nvkm_pmu_fini,
.intr = nvkm_pmu_intr,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
index a67a42e73f08..b5e52b35f5d0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
@@ -197,7 +197,6 @@ gk20a_dvfs_data= {
static const struct nvkm_pmu_func
gk20a_pmu = {
.flcn = &gt215_pmu_flcn,
- .enabled = gf100_pmu_enabled,
.init = gk20a_pmu_init,
.fini = gk20a_pmu_fini,
.reset = gf100_pmu_reset,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c
index 40439e329aa9..7359991f94c2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c
@@ -24,30 +24,36 @@
#include "priv.h"
static int
-gm200_pmu_flcn_reset(struct nvkm_falcon *falcon)
+gm200_pmu_flcn_bind_stat(struct nvkm_falcon *falcon, bool intr)
{
- struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon);
+ nvkm_falcon_wr32(falcon, 0x200, 0x0000030e);
+ return (nvkm_falcon_rd32(falcon, 0x20c) & 0x00007000) >> 12;
+}
- nvkm_falcon_wr32(falcon, 0x014, 0x0000ffff);
- pmu->func->reset(pmu);
- return nvkm_falcon_enable(falcon);
+void
+gm200_pmu_flcn_bind_inst(struct nvkm_falcon *falcon, int target, u64 addr)
+{
+ nvkm_falcon_wr32(falcon, 0xe00, 4); /* DMAIDX_UCODE */
+ nvkm_falcon_wr32(falcon, 0xe04, 0); /* DMAIDX_VIRT */
+ nvkm_falcon_wr32(falcon, 0xe08, 4); /* DMAIDX_PHYS_VID */
+ nvkm_falcon_wr32(falcon, 0xe0c, 5); /* DMAIDX_PHYS_SYS_COH */
+ nvkm_falcon_wr32(falcon, 0xe10, 6); /* DMAIDX_PHYS_SYS_NCOH */
+ nvkm_falcon_mask(falcon, 0x090, 0x00010000, 0x00010000);
+ nvkm_falcon_wr32(falcon, 0x480, (1 << 30) | (target << 28) | (addr >> 12));
}
const struct nvkm_falcon_func
gm200_pmu_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_pmc = true,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
.debug = 0xc08,
- .fbif = 0xe00,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = nvkm_falcon_v1_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
+ .bind_inst = gm200_pmu_flcn_bind_inst,
+ .bind_stat = gm200_pmu_flcn_bind_stat,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
.start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
- .reset = gm200_pmu_flcn_reset,
.cmdq = { 0x4a0, 0x4b0, 4 },
.msgq = { 0x4c8, 0x4cc, 0 },
};
@@ -55,11 +61,9 @@ gm200_pmu_flcn = {
static const struct nvkm_pmu_func
gm200_pmu = {
.flcn = &gm200_pmu_flcn,
- .enabled = gf100_pmu_enabled,
.reset = gf100_pmu_reset,
};
-
int
gm200_pmu_nofw(struct nvkm_pmu *pmu, int ver, const struct nvkm_pmu_fwif *fwif)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
index 612310d5d481..a72403777329 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
@@ -62,16 +62,6 @@ gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
return ret;
}
-int
-gm20b_pmu_acr_boot(struct nvkm_falcon *falcon)
-{
- struct nv_pmu_args args = { .secure_mode = true };
- const u32 addr_args = falcon->data.limit - sizeof(struct nv_pmu_args);
- nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0);
- nvkm_falcon_start(falcon);
- return 0;
-}
-
void
gm20b_pmu_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
{
@@ -125,7 +115,6 @@ gm20b_pmu_acr = {
.bld_size = sizeof(struct loader_config),
.bld_write = gm20b_pmu_acr_bld_write,
.bld_patch = gm20b_pmu_acr_bld_patch,
- .boot = gm20b_pmu_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) |
BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS),
@@ -166,7 +155,7 @@ gm20b_pmu_acr_init_wpr(struct nvkm_pmu *pmu)
gm20b_pmu_acr_init_wpr_callback, pmu, 0);
}
-int
+static int
gm20b_pmu_initmsg(struct nvkm_pmu *pmu)
{
struct nv_pmu_init_msg msg;
@@ -192,14 +181,13 @@ gm20b_pmu_initmsg(struct nvkm_pmu *pmu)
return gm20b_pmu_acr_init_wpr(pmu);
}
-void
+static void
gm20b_pmu_recv(struct nvkm_pmu *pmu)
{
if (!pmu->initmsg_received) {
int ret = pmu->func->initmsg(pmu);
if (ret) {
- nvkm_error(&pmu->subdev,
- "error parsing init message: %d\n", ret);
+ nvkm_error(&pmu->subdev, "error parsing init message: %d\n", ret);
return;
}
@@ -209,10 +197,44 @@ gm20b_pmu_recv(struct nvkm_pmu *pmu)
nvkm_falcon_msgq_recv(pmu->msgq);
}
-static const struct nvkm_pmu_func
+static void
+gm20b_pmu_fini(struct nvkm_pmu *pmu)
+{
+ /*TODO: shutdown RTOS. */
+
+ flush_work(&pmu->recv.work);
+ nvkm_falcon_cmdq_fini(pmu->lpq);
+ nvkm_falcon_cmdq_fini(pmu->hpq);
+
+ reinit_completion(&pmu->wpr_ready);
+
+ nvkm_falcon_put(&pmu->falcon, &pmu->subdev);
+}
+
+static int
+gm20b_pmu_init(struct nvkm_pmu *pmu)
+{
+ struct nvkm_falcon *falcon = &pmu->falcon;
+ struct nv_pmu_args args = { .secure_mode = true };
+ u32 addr_args = falcon->data.limit - sizeof(args);
+ int ret;
+
+ ret = nvkm_falcon_get(&pmu->falcon, &pmu->subdev);
+ if (ret)
+ return ret;
+
+ pmu->initmsg_received = false;
+
+ nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0);
+ nvkm_falcon_start(falcon);
+ return 0;
+}
+
+const struct nvkm_pmu_func
gm20b_pmu = {
.flcn = &gm200_pmu_flcn,
- .enabled = gf100_pmu_enabled,
+ .init = gm20b_pmu_init,
+ .fini = gm20b_pmu_fini,
.intr = gt215_pmu_intr,
.recv = gm20b_pmu_recv,
.initmsg = gm20b_pmu_initmsg,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c
index 1a6f9c3af5ec..cd3148360996 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c
@@ -23,25 +23,25 @@
*/
#include "priv.h"
-void
-gp102_pmu_reset(struct nvkm_pmu *pmu)
-{
- struct nvkm_device *device = pmu->subdev.device;
- nvkm_mask(device, 0x10a3c0, 0x00000001, 0x00000001);
- nvkm_mask(device, 0x10a3c0, 0x00000001, 0x00000000);
-}
-
-static bool
-gp102_pmu_enabled(struct nvkm_pmu *pmu)
-{
- return !(nvkm_rd32(pmu->subdev.device, 0x10a3c0) & 0x00000001);
-}
+static const struct nvkm_falcon_func
+gp102_pmu_flcn = {
+ .disable = gm200_flcn_disable,
+ .enable = gm200_flcn_enable,
+ .reset_eng = gp102_flcn_reset_eng,
+ .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing,
+ .debug = 0xc08,
+ .bind_inst = gm200_pmu_flcn_bind_inst,
+ .bind_stat = gm200_flcn_bind_stat,
+ .imem_pio = &gm200_flcn_imem_pio,
+ .dmem_pio = &gm200_flcn_dmem_pio,
+ .start = nvkm_falcon_v1_start,
+ .cmdq = { 0x4a0, 0x4b0, 4 },
+ .msgq = { 0x4c8, 0x4cc, 0 },
+};
static const struct nvkm_pmu_func
gp102_pmu = {
- .flcn = &gm200_pmu_flcn,
- .enabled = gp102_pmu_enabled,
- .reset = gp102_pmu_reset,
+ .flcn = &gp102_pmu_flcn,
};
static const struct nvkm_pmu_fwif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
index 94cfb1791af6..a6f410ba60bc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
@@ -68,7 +68,6 @@ gp10b_pmu_acr = {
.bld_size = sizeof(struct loader_config),
.bld_write = gm20b_pmu_acr_bld_write,
.bld_patch = gm20b_pmu_acr_bld_patch,
- .boot = gm20b_pmu_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) |
BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS),
@@ -76,16 +75,6 @@ gp10b_pmu_acr = {
.bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons,
};
-static const struct nvkm_pmu_func
-gp10b_pmu = {
- .flcn = &gm200_pmu_flcn,
- .enabled = gf100_pmu_enabled,
- .intr = gt215_pmu_intr,
- .recv = gm20b_pmu_recv,
- .initmsg = gm20b_pmu_initmsg,
- .reset = gp102_pmu_reset,
-};
-
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
MODULE_FIRMWARE("nvidia/gp10b/pmu/desc.bin");
MODULE_FIRMWARE("nvidia/gp10b/pmu/image.bin");
@@ -94,8 +83,8 @@ MODULE_FIRMWARE("nvidia/gp10b/pmu/sig.bin");
static const struct nvkm_pmu_fwif
gp10b_pmu_fwif[] = {
- { 0, gm20b_pmu_load, &gp10b_pmu, &gp10b_pmu_acr },
- { -1, gm200_pmu_nofw, &gp10b_pmu },
+ { 0, gm20b_pmu_load, &gm20b_pmu, &gp10b_pmu_acr },
+ { -1, gm200_pmu_nofw, &gm20b_pmu },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
index b0407b86bc10..32cee21ed858 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
@@ -178,12 +178,14 @@ void
gt215_pmu_fini(struct nvkm_pmu *pmu)
{
nvkm_wr32(pmu->subdev.device, 0x10a014, 0x00000060);
+ flush_work(&pmu->recv.work);
}
static void
gt215_pmu_reset(struct nvkm_pmu *pmu)
{
struct nvkm_device *device = pmu->subdev.device;
+
nvkm_mask(device, 0x022210, 0x00000001, 0x00000000);
nvkm_mask(device, 0x022210, 0x00000001, 0x00000001);
nvkm_rd32(device, 0x022210);
@@ -201,6 +203,23 @@ gt215_pmu_init(struct nvkm_pmu *pmu)
struct nvkm_device *device = pmu->subdev.device;
int i;
+ /* Inhibit interrupts, and wait for idle. */
+ if (pmu->func->enabled(pmu)) {
+ nvkm_wr32(device, 0x10a014, 0x0000ffff);
+ nvkm_msec(device, 2000,
+ if (!nvkm_rd32(device, 0x10a04c))
+ break;
+ );
+ }
+
+ pmu->func->reset(pmu);
+
+ /* Wait for IMEM/DMEM scrubbing to be complete. */
+ nvkm_msec(device, 2000,
+ if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006))
+ break;
+ );
+
/* upload data segment */
nvkm_wr32(device, 0x10a1c0, 0x01000000);
for (i = 0; i < pmu->func->data.size / 4; i++)
@@ -243,20 +262,6 @@ gt215_pmu_init(struct nvkm_pmu *pmu)
const struct nvkm_falcon_func
gt215_pmu_flcn = {
- .debug = 0xc08,
- .fbif = 0xe00,
- .load_imem = nvkm_falcon_v1_load_imem,
- .load_dmem = nvkm_falcon_v1_load_dmem,
- .read_dmem = nvkm_falcon_v1_read_dmem,
- .bind_context = nvkm_falcon_v1_bind_context,
- .wait_for_halt = nvkm_falcon_v1_wait_for_halt,
- .clear_interrupt = nvkm_falcon_v1_clear_interrupt,
- .set_start_addr = nvkm_falcon_v1_set_start_addr,
- .start = nvkm_falcon_v1_start,
- .enable = nvkm_falcon_v1_enable,
- .disable = nvkm_falcon_v1_disable,
- .cmdq = { 0x4a0, 0x4b0, 4 },
- .msgq = { 0x4c8, 0x4cc, 0 },
};
static const struct nvkm_pmu_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
index 21abf31f4442..2d0a8fa6f196 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
@@ -46,13 +46,12 @@ void gp102_pmu_reset(struct nvkm_pmu *pmu);
void gk110_pmu_pgob(struct nvkm_pmu *, bool);
extern const struct nvkm_falcon_func gm200_pmu_flcn;
+void gm200_pmu_flcn_bind_inst(struct nvkm_falcon *, int, u64);
+extern const struct nvkm_pmu_func gm20b_pmu;
void gm20b_pmu_acr_bld_patch(struct nvkm_acr *, u32, s64);
void gm20b_pmu_acr_bld_write(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *);
-int gm20b_pmu_acr_boot(struct nvkm_falcon *);
int gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
-void gm20b_pmu_recv(struct nvkm_pmu *);
-int gm20b_pmu_initmsg(struct nvkm_pmu *);
struct nvkm_pmu_fwif {
int version;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
index 28d0789f50fe..eb348dfc1d7a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
@@ -117,11 +117,15 @@ nvkm_top_fault(struct nvkm_device *device, int fault)
return NULL;
}
-static int
-nvkm_top_oneinit(struct nvkm_subdev *subdev)
+int
+nvkm_top_parse(struct nvkm_device *device)
{
- struct nvkm_top *top = nvkm_top(subdev);
- return top->func->oneinit(top);
+ struct nvkm_top *top = device->top;
+
+ if (!top || !list_empty(&top->device))
+ return 0;
+
+ return top->func->parse(top);
}
static void *
@@ -141,7 +145,6 @@ nvkm_top_dtor(struct nvkm_subdev *subdev)
static const struct nvkm_subdev_func
nvkm_top = {
.dtor = nvkm_top_dtor,
- .oneinit = nvkm_top_oneinit,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c
index c982d834c8d9..84790cf52b90 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c
@@ -22,7 +22,7 @@
#include "priv.h"
static int
-ga100_top_oneinit(struct nvkm_top *top)
+ga100_top_parse(struct nvkm_top *top)
{
struct nvkm_subdev *subdev = &top->subdev;
struct nvkm_device *device = subdev->device;
@@ -97,7 +97,7 @@ ga100_top_oneinit(struct nvkm_top *top)
static const struct nvkm_top_func
ga100_top = {
- .oneinit = ga100_top_oneinit,
+ .parse = ga100_top_parse,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
index 4dcad97bd505..2bbba8244cbf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
@@ -24,7 +24,7 @@
#include "priv.h"
static int
-gk104_top_oneinit(struct nvkm_top *top)
+gk104_top_parse(struct nvkm_top *top)
{
struct nvkm_subdev *subdev = &top->subdev;
struct nvkm_device *device = subdev->device;
@@ -108,7 +108,7 @@ gk104_top_oneinit(struct nvkm_top *top)
static const struct nvkm_top_func
gk104_top = {
- .oneinit = gk104_top_oneinit,
+ .parse = gk104_top_parse,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h
index 8e103a836705..532be91d8fd9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h
@@ -5,7 +5,7 @@
#include <subdev/top.h>
struct nvkm_top_func {
- int (*oneinit)(struct nvkm_top *);
+ int (*parse)(struct nvkm_top *);
};
int nvkm_top_new_(const struct nvkm_top_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild
new file mode 100644
index 000000000000..23cd21b40a25
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: MIT
+nvkm-y += nvkm/subdev/vfn/base.o
+nvkm-y += nvkm/subdev/vfn/uvfn.o
+nvkm-y += nvkm/subdev/vfn/gv100.o
+nvkm-y += nvkm/subdev/vfn/tu102.o
+nvkm-y += nvkm/subdev/vfn/ga100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c
index 9acaec5c271e..62e81d551f44 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Red Hat Inc.
+ * Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -18,45 +18,43 @@
* 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.
- *
- * Authors: Ben Skeggs
*/
#include "priv.h"
-#include "head.h"
-#include <core/client.h>
+static void *
+nvkm_vfn_dtor(struct nvkm_subdev *subdev)
+{
+ return nvkm_vfn(subdev);
+}
-#include <nvif/cl0046.h>
-#include <nvif/unpack.h>
+static const struct nvkm_subdev_func
+nvkm_vfn = {
+ .dtor = nvkm_vfn_dtor,
+};
int
-nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+nvkm_vfn_new_(const struct nvkm_vfn_func *func, struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_vfn **pvfn)
{
- struct nvkm_disp *disp = nvkm_disp(object->engine);
- union {
- struct nv04_disp_mthd_v0 v0;
- } *args = data;
- struct nvkm_head *head;
- int id, ret = -ENOSYS;
+ struct nvkm_vfn *vfn;
+ int ret;
- nvif_ioctl(object, "disp mthd size %d\n", size);
- if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
- nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
- args->v0.version, args->v0.method, args->v0.head);
- mthd = args->v0.method;
- id = args->v0.head;
- } else
- return ret;
+ if (!(vfn = *pvfn = kzalloc(sizeof(*vfn), GFP_KERNEL)))
+ return -ENOMEM;
- if (!(head = nvkm_head_find(disp, id)))
- return -ENXIO;
+ nvkm_subdev_ctor(&nvkm_vfn, device, type, inst, &vfn->subdev);
+ vfn->func = func;
+ vfn->addr.priv = addr;
+ vfn->addr.user = vfn->addr.priv + func->user.addr;
- switch (mthd) {
- case NV04_DISP_SCANOUTPOS:
- return nvkm_head_mthd_scanoutpos(object, head, data, size);
- default:
- break;
+ if (vfn->func->intr) {
+ ret = nvkm_intr_add(vfn->func->intr, vfn->func->intrs,
+ &vfn->subdev, 8, &vfn->intr);
+ if (ret)
+ return ret;
}
- return -EINVAL;
+ vfn->user.ctor = nvkm_uvfn_new;
+ vfn->user.base = func->user.base;
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c
new file mode 100644
index 000000000000..fd5c6931322d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <nvif/class.h>
+
+static const struct nvkm_intr_data
+ga100_vfn_intrs[] = {
+ { NVKM_ENGINE_DISP , 0, 4, 0x04000000, true },
+ { NVKM_SUBDEV_GPIO , 0, 4, 0x00200000, true },
+ { NVKM_SUBDEV_I2C , 0, 4, 0x00200000, true },
+ { NVKM_SUBDEV_PRIVRING, 0, 4, 0x40000000, true },
+ {}
+};
+
+static const struct nvkm_vfn_func
+ga100_vfn = {
+ .intr = &tu102_vfn_intr,
+ .intrs = ga100_vfn_intrs,
+ .user = { 0x030000, 0x010000, { -1, -1, AMPERE_USERMODE_A } },
+};
+
+int
+ga100_vfn_new(struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn)
+{
+ return nvkm_vfn_new_(&ga100_vfn, device, type, inst, 0xb80000, pvfn);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c
index 217268f8ccad..ddd39d714c4a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Red Hat Inc.
+ * Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -19,27 +19,18 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "user.h"
+#include "priv.h"
-static int
-tu102_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
- enum nvkm_object_map *type, u64 *addr, u64 *size)
-{
- struct nvkm_device *device = object->engine->subdev.device;
- *addr = 0xbb0000 + device->func->resource_addr(device, 0);
- *size = 0x010000;
- *type = NVKM_OBJECT_MAP_IO;
- return 0;
-}
+#include <nvif/class.h>
-static const struct nvkm_object_func
-tu102_fifo_user = {
- .map = tu102_fifo_user_map,
+static const struct nvkm_vfn_func
+gv100_vfn = {
+ .user = { 0x810000, 0x010000, { -1, -1, VOLTA_USERMODE_A } },
};
int
-tu102_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
- struct nvkm_object **pobject)
+gv100_vfn_new(struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn)
{
- return nvkm_object_new_(&tu102_fifo_user, oclass, argv, argc, pobject);
+ return nvkm_vfn_new_(&gv100_vfn, device, type, inst, 0, pvfn);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h
new file mode 100644
index 000000000000..96d53c02041b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_VFN_PRIV_H__
+#define __NVKM_VFN_PRIV_H__
+#define nvkm_vfn(p) container_of((p), struct nvkm_vfn, subdev)
+#include <subdev/vfn.h>
+
+struct nvkm_vfn_func {
+ const struct nvkm_intr_func *intr;
+ const struct nvkm_intr_data *intrs;
+
+ struct {
+ u32 addr;
+ u32 size;
+ const struct nvkm_sclass base;
+ } user;
+};
+
+int nvkm_vfn_new_(const struct nvkm_vfn_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
+ u32 addr, struct nvkm_vfn **);
+
+extern const struct nvkm_intr_func tu102_vfn_intr;
+
+int nvkm_uvfn_new(struct nvkm_device *, const struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c
new file mode 100644
index 000000000000..3d063fb5e136
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "priv.h"
+
+#include <nvif/class.h>
+
+static void
+tu102_vfn_intr_reset(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+
+ nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1000 + (leaf * 4), mask);
+}
+
+static void
+tu102_vfn_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+
+ nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1200 + (leaf * 4), mask);
+}
+
+static void
+tu102_vfn_intr_block(struct nvkm_intr *intr, int leaf, u32 mask)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+
+ nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1400 + (leaf * 4), mask);
+}
+
+static void
+tu102_vfn_intr_rearm(struct nvkm_intr *intr)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+
+ nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1608, 0x0000000f);
+}
+
+static void
+tu102_vfn_intr_unarm(struct nvkm_intr *intr)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+
+ nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1610, 0x0000000f);
+}
+
+static bool
+tu102_vfn_intr_pending(struct nvkm_intr *intr)
+{
+ struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr);
+ struct nvkm_device *device = vfn->subdev.device;
+ u32 intr_top = nvkm_rd32(device, vfn->addr.priv + 0x1600);
+ int pending = 0, leaf;
+
+ for (leaf = 0; leaf < 8; leaf++) {
+ if (intr_top & BIT(leaf / 2)) {
+ intr->stat[leaf] = nvkm_rd32(device, vfn->addr.priv + 0x1000 + (leaf * 4));
+ if (intr->stat[leaf])
+ pending++;
+ } else {
+ intr->stat[leaf] = 0;
+ }
+ }
+
+ return pending != 0;
+}
+
+const struct nvkm_intr_func
+tu102_vfn_intr = {
+ .pending = tu102_vfn_intr_pending,
+ .unarm = tu102_vfn_intr_unarm,
+ .rearm = tu102_vfn_intr_rearm,
+ .block = tu102_vfn_intr_block,
+ .allow = tu102_vfn_intr_allow,
+ .reset = tu102_vfn_intr_reset,
+};
+
+static const struct nvkm_vfn_func
+tu102_vfn = {
+ .intr = &tu102_vfn_intr,
+ .user = { 0x030000, 0x010000, { -1, -1, TURING_USERMODE_A } },
+};
+
+int
+tu102_vfn_new(struct nvkm_device *device,
+ enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn)
+{
+ return nvkm_vfn_new_(&tu102_vfn, device, type, inst, 0xb80000, pvfn);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c
new file mode 100644
index 000000000000..c5460a14c541
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#define nvkm_uvfn(p) container_of((p), struct nvkm_uvfn, object)
+#include "priv.h"
+
+#include <core/object.h>
+
+struct nvkm_uvfn {
+ struct nvkm_object object;
+ struct nvkm_vfn *vfn;
+};
+
+static int
+nvkm_uvfn_map(struct nvkm_object *object, void *argv, u32 argc,
+ enum nvkm_object_map *type, u64 *addr, u64 *size)
+{
+ struct nvkm_vfn *vfn = nvkm_uvfn(object)->vfn;
+ struct nvkm_device *device = vfn->subdev.device;
+
+ *addr = device->func->resource_addr(device, 0) + vfn->addr.user;
+ *size = vfn->func->user.size;
+ *type = NVKM_OBJECT_MAP_IO;
+ return 0;
+}
+
+static const struct nvkm_object_func
+nvkm_uvfn = {
+ .map = nvkm_uvfn_map,
+};
+
+int
+nvkm_uvfn_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
+ void *argv, u32 argc, struct nvkm_object **pobject)
+{
+ struct nvkm_uvfn *uvfn;
+
+ if (argc != 0)
+ return -ENOSYS;
+
+ if (!(uvfn = kzalloc(sizeof(*uvfn), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_object_ctor(&nvkm_uvfn, oclass, &uvfn->object);
+ uvfn->vfn = device->vfn;
+
+ *pobject = &uvfn->object;
+ return 0;
+}
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 40706c5aad7b..98d8758048fc 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -38,7 +38,7 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi);
static void pan_worker(struct work_struct *work)
{
struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
- struct fb_info *fbi = fbdev->base.fbdev;
+ struct fb_info *fbi = fbdev->base.info;
int npages;
/* DMM roll shifts in 4K pages: */
@@ -161,7 +161,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
goto fail;
}
- fbi = drm_fb_helper_alloc_fbi(helper);
+ fbi = drm_fb_helper_alloc_info(helper);
if (IS_ERR(fbi)) {
dev_err(dev->dev, "failed to allocate fb info\n");
ret = PTR_ERR(fbi);
@@ -177,8 +177,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
drm_fb_helper_fill_info(fbi, helper, sizes);
- dev->mode_config.fb_base = dma_addr;
-
fbi->screen_buffer = omap_gem_vaddr(fbdev->bo);
fbi->screen_size = fbdev->bo->size;
fbi->fix.smem_start = dma_addr;
@@ -274,7 +272,7 @@ void omap_fbdev_fini(struct drm_device *dev)
if (!helper)
return;
- drm_fb_helper_unregister_fbi(helper);
+ drm_fb_helper_unregister_info(helper);
drm_fb_helper_fini(helper);
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
index 393f82e26927..3abc47521b2c 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
@@ -66,6 +66,8 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
struct drm_gem_object *obj = buffer->priv;
int ret = 0;
+ dma_resv_assert_held(buffer->resv);
+
ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma);
if (ret < 0)
return ret;
@@ -125,7 +127,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
get_dma_buf(dma_buf);
- sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
+ sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto fail_detach;
@@ -142,7 +144,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
return obj;
fail_unmap:
- dma_buf_unmap_attachment(attach, sgt, DMA_TO_DEVICE);
+ dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_TO_DEVICE);
fail_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index a582ddd583c2..737edcdf9eef 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -203,6 +203,16 @@ config DRM_PANEL_INNOLUX_P079ZCA
24 bit RGB per pixel. It provides a MIPI DSI interface to
the host and has a built-in LED backlight.
+config DRM_PANEL_JADARD_JD9365DA_H3
+ tristate "Jadard JD9365DA-H3 WXGA DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Jadard JD9365DA-H3
+ WXGA MIPI DSI panel. The panel support TFT dot matrix LCD with
+ 800RGBx1280 dots at maximum.
+
config DRM_PANEL_JDI_LT070ME05000
tristate "JDI LT070ME05000 WUXGA DSI panel"
depends on OF
@@ -296,6 +306,15 @@ config DRM_PANEL_NEC_NL8048HL11
panel (found on the Zoom2/3/3630 SDP boards). To compile this driver
as a module, choose M here.
+config DRM_PANEL_NEWVISION_NV3051D
+ tristate "NewVision NV3051D DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ This driver supports the NV3051D based panel found on the Anbernic
+ RG353P and RG353V.
+
config DRM_PANEL_NEWVISION_NV3052C
tristate "NewVision NV3052C RGB/SPI panel"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 34e717382dbb..f8f9d9f6a307 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
+obj-$(CONFIG_DRM_PANEL_JADARD_JD9365DA_H3) += panel-jadard-jd9365da-h3.o
obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
+obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 4b39d1dd9140..5cb8dc2ebe18 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1883,8 +1883,10 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
+ EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"),
+ EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
index 39dc40cf681f..384a724f2822 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
@@ -18,6 +18,7 @@
* Copyright 2018 David Lechner <david@lechnology.com>
*/
+#include <linux/backlight.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -30,7 +31,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
new file mode 100644
index 000000000000..48c1702a863b
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Radxa Limited
+ * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd.
+ *
+ * Author:
+ * - Jagan Teki <jagan@amarulasolutions.com>
+ * - Stephen Chen <stephen@radxa.com>
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#define JD9365DA_INIT_CMD_LEN 2
+
+struct jadard_init_cmd {
+ u8 data[JD9365DA_INIT_CMD_LEN];
+};
+
+struct jadard_panel_desc {
+ const struct drm_display_mode mode;
+ unsigned int lanes;
+ enum mipi_dsi_pixel_format format;
+ const struct jadard_init_cmd *init_cmds;
+ u32 num_init_cmds;
+};
+
+struct jadard {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ const struct jadard_panel_desc *desc;
+
+ struct regulator *vdd;
+ struct regulator *vccio;
+ struct gpio_desc *reset;
+};
+
+static inline struct jadard *panel_to_jadard(struct drm_panel *panel)
+{
+ return container_of(panel, struct jadard, panel);
+}
+
+static int jadard_enable(struct drm_panel *panel)
+{
+ struct device *dev = panel->dev;
+ struct jadard *jadard = panel_to_jadard(panel);
+ const struct jadard_panel_desc *desc = jadard->desc;
+ struct mipi_dsi_device *dsi = jadard->dsi;
+ unsigned int i;
+ int err;
+
+ msleep(10);
+
+ for (i = 0; i < desc->num_init_cmds; i++) {
+ const struct jadard_init_cmd *cmd = &desc->init_cmds[i];
+
+ err = mipi_dsi_dcs_write_buffer(dsi, cmd->data, JD9365DA_INIT_CMD_LEN);
+ if (err < 0)
+ return err;
+ }
+
+ msleep(120);
+
+ err = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (err < 0)
+ DRM_DEV_ERROR(dev, "failed to exit sleep mode ret = %d\n", err);
+
+ err = mipi_dsi_dcs_set_display_on(dsi);
+ if (err < 0)
+ DRM_DEV_ERROR(dev, "failed to set display on ret = %d\n", err);
+
+ return 0;
+}
+
+static int jadard_disable(struct drm_panel *panel)
+{
+ struct device *dev = panel->dev;
+ struct jadard *jadard = panel_to_jadard(panel);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(jadard->dsi);
+ if (ret < 0)
+ DRM_DEV_ERROR(dev, "failed to set display off: %d\n", ret);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(jadard->dsi);
+ if (ret < 0)
+ DRM_DEV_ERROR(dev, "failed to enter sleep mode: %d\n", ret);
+
+ return 0;
+}
+
+static int jadard_prepare(struct drm_panel *panel)
+{
+ struct jadard *jadard = panel_to_jadard(panel);
+ int ret;
+
+ ret = regulator_enable(jadard->vccio);
+ if (ret)
+ return ret;
+
+ ret = regulator_enable(jadard->vdd);
+ if (ret)
+ return ret;
+
+ gpiod_set_value(jadard->reset, 1);
+ msleep(5);
+
+ gpiod_set_value(jadard->reset, 0);
+ msleep(10);
+
+ gpiod_set_value(jadard->reset, 1);
+ msleep(120);
+
+ return 0;
+}
+
+static int jadard_unprepare(struct drm_panel *panel)
+{
+ struct jadard *jadard = panel_to_jadard(panel);
+
+ gpiod_set_value(jadard->reset, 1);
+ msleep(120);
+
+ regulator_disable(jadard->vdd);
+ regulator_disable(jadard->vccio);
+
+ return 0;
+}
+
+static int jadard_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct jadard *jadard = panel_to_jadard(panel);
+ const struct drm_display_mode *desc_mode = &jadard->desc->mode;
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, desc_mode);
+ if (!mode) {
+ DRM_DEV_ERROR(&jadard->dsi->dev, "failed to add mode %ux%ux@%u\n",
+ desc_mode->hdisplay, desc_mode->vdisplay,
+ drm_mode_vrefresh(desc_mode));
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs jadard_funcs = {
+ .disable = jadard_disable,
+ .unprepare = jadard_unprepare,
+ .prepare = jadard_prepare,
+ .enable = jadard_enable,
+ .get_modes = jadard_get_modes,
+};
+
+static const struct jadard_init_cmd cz101b4001_init_cmds[] = {
+ { .data = { 0xE0, 0x00 } },
+ { .data = { 0xE1, 0x93 } },
+ { .data = { 0xE2, 0x65 } },
+ { .data = { 0xE3, 0xF8 } },
+ { .data = { 0x80, 0x03 } },
+ { .data = { 0xE0, 0x01 } },
+ { .data = { 0x00, 0x00 } },
+ { .data = { 0x01, 0x3B } },
+ { .data = { 0x0C, 0x74 } },
+ { .data = { 0x17, 0x00 } },
+ { .data = { 0x18, 0xAF } },
+ { .data = { 0x19, 0x00 } },
+ { .data = { 0x1A, 0x00 } },
+ { .data = { 0x1B, 0xAF } },
+ { .data = { 0x1C, 0x00 } },
+ { .data = { 0x35, 0x26 } },
+ { .data = { 0x37, 0x09 } },
+ { .data = { 0x38, 0x04 } },
+ { .data = { 0x39, 0x00 } },
+ { .data = { 0x3A, 0x01 } },
+ { .data = { 0x3C, 0x78 } },
+ { .data = { 0x3D, 0xFF } },
+ { .data = { 0x3E, 0xFF } },
+ { .data = { 0x3F, 0x7F } },
+ { .data = { 0x40, 0x06 } },
+ { .data = { 0x41, 0xA0 } },
+ { .data = { 0x42, 0x81 } },
+ { .data = { 0x43, 0x14 } },
+ { .data = { 0x44, 0x23 } },
+ { .data = { 0x45, 0x28 } },
+ { .data = { 0x55, 0x02 } },
+ { .data = { 0x57, 0x69 } },
+ { .data = { 0x59, 0x0A } },
+ { .data = { 0x5A, 0x2A } },
+ { .data = { 0x5B, 0x17 } },
+ { .data = { 0x5D, 0x7F } },
+ { .data = { 0x5E, 0x6B } },
+ { .data = { 0x5F, 0x5C } },
+ { .data = { 0x60, 0x4F } },
+ { .data = { 0x61, 0x4D } },
+ { .data = { 0x62, 0x3F } },
+ { .data = { 0x63, 0x42 } },
+ { .data = { 0x64, 0x2B } },
+ { .data = { 0x65, 0x44 } },
+ { .data = { 0x66, 0x43 } },
+ { .data = { 0x67, 0x43 } },
+ { .data = { 0x68, 0x63 } },
+ { .data = { 0x69, 0x52 } },
+ { .data = { 0x6A, 0x5A } },
+ { .data = { 0x6B, 0x4F } },
+ { .data = { 0x6C, 0x4E } },
+ { .data = { 0x6D, 0x20 } },
+ { .data = { 0x6E, 0x0F } },
+ { .data = { 0x6F, 0x00 } },
+ { .data = { 0x70, 0x7F } },
+ { .data = { 0x71, 0x6B } },
+ { .data = { 0x72, 0x5C } },
+ { .data = { 0x73, 0x4F } },
+ { .data = { 0x74, 0x4D } },
+ { .data = { 0x75, 0x3F } },
+ { .data = { 0x76, 0x42 } },
+ { .data = { 0x77, 0x2B } },
+ { .data = { 0x78, 0x44 } },
+ { .data = { 0x79, 0x43 } },
+ { .data = { 0x7A, 0x43 } },
+ { .data = { 0x7B, 0x63 } },
+ { .data = { 0x7C, 0x52 } },
+ { .data = { 0x7D, 0x5A } },
+ { .data = { 0x7E, 0x4F } },
+ { .data = { 0x7F, 0x4E } },
+ { .data = { 0x80, 0x20 } },
+ { .data = { 0x81, 0x0F } },
+ { .data = { 0x82, 0x00 } },
+ { .data = { 0xE0, 0x02 } },
+ { .data = { 0x00, 0x02 } },
+ { .data = { 0x01, 0x02 } },
+ { .data = { 0x02, 0x00 } },
+ { .data = { 0x03, 0x00 } },
+ { .data = { 0x04, 0x1E } },
+ { .data = { 0x05, 0x1E } },
+ { .data = { 0x06, 0x1F } },
+ { .data = { 0x07, 0x1F } },
+ { .data = { 0x08, 0x1F } },
+ { .data = { 0x09, 0x17 } },
+ { .data = { 0x0A, 0x17 } },
+ { .data = { 0x0B, 0x37 } },
+ { .data = { 0x0C, 0x37 } },
+ { .data = { 0x0D, 0x47 } },
+ { .data = { 0x0E, 0x47 } },
+ { .data = { 0x0F, 0x45 } },
+ { .data = { 0x10, 0x45 } },
+ { .data = { 0x11, 0x4B } },
+ { .data = { 0x12, 0x4B } },
+ { .data = { 0x13, 0x49 } },
+ { .data = { 0x14, 0x49 } },
+ { .data = { 0x15, 0x1F } },
+ { .data = { 0x16, 0x01 } },
+ { .data = { 0x17, 0x01 } },
+ { .data = { 0x18, 0x00 } },
+ { .data = { 0x19, 0x00 } },
+ { .data = { 0x1A, 0x1E } },
+ { .data = { 0x1B, 0x1E } },
+ { .data = { 0x1C, 0x1F } },
+ { .data = { 0x1D, 0x1F } },
+ { .data = { 0x1E, 0x1F } },
+ { .data = { 0x1F, 0x17 } },
+ { .data = { 0x20, 0x17 } },
+ { .data = { 0x21, 0x37 } },
+ { .data = { 0x22, 0x37 } },
+ { .data = { 0x23, 0x46 } },
+ { .data = { 0x24, 0x46 } },
+ { .data = { 0x25, 0x44 } },
+ { .data = { 0x26, 0x44 } },
+ { .data = { 0x27, 0x4A } },
+ { .data = { 0x28, 0x4A } },
+ { .data = { 0x29, 0x48 } },
+ { .data = { 0x2A, 0x48 } },
+ { .data = { 0x2B, 0x1F } },
+ { .data = { 0x2C, 0x01 } },
+ { .data = { 0x2D, 0x01 } },
+ { .data = { 0x2E, 0x00 } },
+ { .data = { 0x2F, 0x00 } },
+ { .data = { 0x30, 0x1F } },
+ { .data = { 0x31, 0x1F } },
+ { .data = { 0x32, 0x1E } },
+ { .data = { 0x33, 0x1E } },
+ { .data = { 0x34, 0x1F } },
+ { .data = { 0x35, 0x17 } },
+ { .data = { 0x36, 0x17 } },
+ { .data = { 0x37, 0x37 } },
+ { .data = { 0x38, 0x37 } },
+ { .data = { 0x39, 0x08 } },
+ { .data = { 0x3A, 0x08 } },
+ { .data = { 0x3B, 0x0A } },
+ { .data = { 0x3C, 0x0A } },
+ { .data = { 0x3D, 0x04 } },
+ { .data = { 0x3E, 0x04 } },
+ { .data = { 0x3F, 0x06 } },
+ { .data = { 0x40, 0x06 } },
+ { .data = { 0x41, 0x1F } },
+ { .data = { 0x42, 0x02 } },
+ { .data = { 0x43, 0x02 } },
+ { .data = { 0x44, 0x00 } },
+ { .data = { 0x45, 0x00 } },
+ { .data = { 0x46, 0x1F } },
+ { .data = { 0x47, 0x1F } },
+ { .data = { 0x48, 0x1E } },
+ { .data = { 0x49, 0x1E } },
+ { .data = { 0x4A, 0x1F } },
+ { .data = { 0x4B, 0x17 } },
+ { .data = { 0x4C, 0x17 } },
+ { .data = { 0x4D, 0x37 } },
+ { .data = { 0x4E, 0x37 } },
+ { .data = { 0x4F, 0x09 } },
+ { .data = { 0x50, 0x09 } },
+ { .data = { 0x51, 0x0B } },
+ { .data = { 0x52, 0x0B } },
+ { .data = { 0x53, 0x05 } },
+ { .data = { 0x54, 0x05 } },
+ { .data = { 0x55, 0x07 } },
+ { .data = { 0x56, 0x07 } },
+ { .data = { 0x57, 0x1F } },
+ { .data = { 0x58, 0x40 } },
+ { .data = { 0x5B, 0x30 } },
+ { .data = { 0x5C, 0x16 } },
+ { .data = { 0x5D, 0x34 } },
+ { .data = { 0x5E, 0x05 } },
+ { .data = { 0x5F, 0x02 } },
+ { .data = { 0x63, 0x00 } },
+ { .data = { 0x64, 0x6A } },
+ { .data = { 0x67, 0x73 } },
+ { .data = { 0x68, 0x1D } },
+ { .data = { 0x69, 0x08 } },
+ { .data = { 0x6A, 0x6A } },
+ { .data = { 0x6B, 0x08 } },
+ { .data = { 0x6C, 0x00 } },
+ { .data = { 0x6D, 0x00 } },
+ { .data = { 0x6E, 0x00 } },
+ { .data = { 0x6F, 0x88 } },
+ { .data = { 0x75, 0xFF } },
+ { .data = { 0x77, 0xDD } },
+ { .data = { 0x78, 0x3F } },
+ { .data = { 0x79, 0x15 } },
+ { .data = { 0x7A, 0x17 } },
+ { .data = { 0x7D, 0x14 } },
+ { .data = { 0x7E, 0x82 } },
+ { .data = { 0xE0, 0x04 } },
+ { .data = { 0x00, 0x0E } },
+ { .data = { 0x02, 0xB3 } },
+ { .data = { 0x09, 0x61 } },
+ { .data = { 0x0E, 0x48 } },
+ { .data = { 0xE0, 0x00 } },
+ { .data = { 0xE6, 0x02 } },
+ { .data = { 0xE7, 0x0C } },
+};
+
+static const struct jadard_panel_desc cz101b4001_desc = {
+ .mode = {
+ .clock = 70000,
+
+ .hdisplay = 800,
+ .hsync_start = 800 + 40,
+ .hsync_end = 800 + 40 + 18,
+ .htotal = 800 + 40 + 18 + 20,
+
+ .vdisplay = 1280,
+ .vsync_start = 1280 + 20,
+ .vsync_end = 1280 + 20 + 4,
+ .vtotal = 1280 + 20 + 4 + 20,
+
+ .width_mm = 62,
+ .height_mm = 110,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ },
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB888,
+ .init_cmds = cz101b4001_init_cmds,
+ .num_init_cmds = ARRAY_SIZE(cz101b4001_init_cmds),
+};
+
+static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct jadard_panel_desc *desc;
+ struct jadard *jadard;
+ int ret;
+
+ jadard = devm_kzalloc(&dsi->dev, sizeof(*jadard), GFP_KERNEL);
+ if (!jadard)
+ return -ENOMEM;
+
+ desc = of_device_get_match_data(dev);
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_NO_EOT_PACKET;
+ dsi->format = desc->format;
+ dsi->lanes = desc->lanes;
+
+ jadard->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(jadard->reset)) {
+ DRM_DEV_ERROR(&dsi->dev, "failed to get our reset GPIO\n");
+ return PTR_ERR(jadard->reset);
+ }
+
+ jadard->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(jadard->vdd)) {
+ DRM_DEV_ERROR(&dsi->dev, "failed to get vdd regulator\n");
+ return PTR_ERR(jadard->vdd);
+ }
+
+ jadard->vccio = devm_regulator_get(dev, "vccio");
+ if (IS_ERR(jadard->vccio)) {
+ DRM_DEV_ERROR(&dsi->dev, "failed to get vccio regulator\n");
+ return PTR_ERR(jadard->vccio);
+ }
+
+ drm_panel_init(&jadard->panel, dev, &jadard_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&jadard->panel);
+ if (ret)
+ return ret;
+
+ drm_panel_add(&jadard->panel);
+
+ mipi_dsi_set_drvdata(dsi, jadard);
+ jadard->dsi = dsi;
+ jadard->desc = desc;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0)
+ drm_panel_remove(&jadard->panel);
+
+ return ret;
+}
+
+static void jadard_dsi_remove(struct mipi_dsi_device *dsi)
+{
+ struct jadard *jadard = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&jadard->panel);
+}
+
+static const struct of_device_id jadard_of_match[] = {
+ { .compatible = "chongzhou,cz101b4001", .data = &cz101b4001_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jadard_of_match);
+
+static struct mipi_dsi_driver jadard_driver = {
+ .probe = jadard_dsi_probe,
+ .remove = jadard_dsi_remove,
+ .driver = {
+ .name = "jadard-jd9365da",
+ .of_match_table = jadard_of_match,
+ },
+};
+module_mipi_dsi_driver(jadard_driver);
+
+MODULE_AUTHOR("Jagan Teki <jagan@edgeble.ai>");
+MODULE_AUTHOR("Stephen Chen <stephen@radxa.com>");
+MODULE_DESCRIPTION("Jadard JD9365DA-H3 WXGA DSI panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
new file mode 100644
index 000000000000..a07958038ffd
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NV3051D MIPI-DSI panel driver for Anbernic RG353x
+ * Copyright (C) 2022 Chris Morgan
+ *
+ * based on
+ *
+ * Elida kd35t133 3.5" MIPI-DSI panel driver
+ * Copyright (C) Theobroma Systems 2020
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/display_timing.h>
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct nv3051d_panel_info {
+ const struct drm_display_mode *display_modes;
+ unsigned int num_modes;
+ u16 width_mm, height_mm;
+ u32 bus_flags;
+};
+
+struct panel_nv3051d {
+ struct device *dev;
+ struct drm_panel panel;
+ struct gpio_desc *reset_gpio;
+ const struct nv3051d_panel_info *panel_info;
+ struct regulator *vdd;
+};
+
+static inline struct panel_nv3051d *panel_to_panelnv3051d(struct drm_panel *panel)
+{
+ return container_of(panel, struct panel_nv3051d, panel);
+}
+
+static int panel_nv3051d_init_sequence(struct panel_nv3051d *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+ /*
+ * Init sequence was supplied by device vendor with no
+ * documentation.
+ */
+
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xE3, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x03, 0x40);
+ mipi_dsi_dcs_write_seq(dsi, 0x04, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x05, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, 0x24, 0x12);
+ mipi_dsi_dcs_write_seq(dsi, 0x25, 0x1E);
+ mipi_dsi_dcs_write_seq(dsi, 0x26, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0x27, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0x28, 0x57);
+ mipi_dsi_dcs_write_seq(dsi, 0x29, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x2A, 0xDF);
+ mipi_dsi_dcs_write_seq(dsi, 0x38, 0x9C);
+ mipi_dsi_dcs_write_seq(dsi, 0x39, 0xA7);
+ mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x53);
+ mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x49, 0x3C);
+ mipi_dsi_dcs_write_seq(dsi, 0x59, 0xFE);
+ mipi_dsi_dcs_write_seq(dsi, 0x5C, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x91, 0x77);
+ mipi_dsi_dcs_write_seq(dsi, 0x92, 0x77);
+ mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x55);
+ mipi_dsi_dcs_write_seq(dsi, 0xA1, 0x50);
+ mipi_dsi_dcs_write_seq(dsi, 0xA4, 0x9C);
+ mipi_dsi_dcs_write_seq(dsi, 0xA7, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0xA8, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xA9, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xAA, 0xFC);
+ mipi_dsi_dcs_write_seq(dsi, 0xAB, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0xAC, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xAD, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xAE, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xAF, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x26);
+ mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33);
+ mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x26);
+ mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x26);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0xD1, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x29);
+ mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x2B);
+ mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C);
+ mipi_dsi_dcs_write_seq(dsi, 0xD2, 0x0A);
+ mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0xD3, 0x28);
+ mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0xD6, 0x0D);
+ mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x32);
+ mipi_dsi_dcs_write_seq(dsi, 0xD7, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xE1, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x0A);
+ mipi_dsi_dcs_write_seq(dsi, 0xD8, 0x0A);
+ mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xD9, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xBD, 0x13);
+ mipi_dsi_dcs_write_seq(dsi, 0xDD, 0x13);
+ mipi_dsi_dcs_write_seq(dsi, 0xBC, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0xDC, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0xBB, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xDB, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xDA, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xBE, 0x18);
+ mipi_dsi_dcs_write_seq(dsi, 0xDE, 0x18);
+ mipi_dsi_dcs_write_seq(dsi, 0xBF, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xDF, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xC0, 0x17);
+ mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x17);
+ mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x3B);
+ mipi_dsi_dcs_write_seq(dsi, 0xD5, 0x3C);
+ mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x0B);
+ mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0C);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, 0x00, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x01, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x02, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x03, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x04, 0x61);
+ mipi_dsi_dcs_write_seq(dsi, 0x05, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0x06, 0xC7);
+ mipi_dsi_dcs_write_seq(dsi, 0x07, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x08, 0x82);
+ mipi_dsi_dcs_write_seq(dsi, 0x09, 0x83);
+ mipi_dsi_dcs_write_seq(dsi, 0x30, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x31, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x32, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x33, 0x2A);
+ mipi_dsi_dcs_write_seq(dsi, 0x34, 0x61);
+ mipi_dsi_dcs_write_seq(dsi, 0x35, 0xC5);
+ mipi_dsi_dcs_write_seq(dsi, 0x36, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0x37, 0x23);
+ mipi_dsi_dcs_write_seq(dsi, 0x40, 0x82);
+ mipi_dsi_dcs_write_seq(dsi, 0x41, 0x83);
+ mipi_dsi_dcs_write_seq(dsi, 0x42, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0x43, 0x81);
+ mipi_dsi_dcs_write_seq(dsi, 0x44, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0x45, 0xF2);
+ mipi_dsi_dcs_write_seq(dsi, 0x46, 0xF1);
+ mipi_dsi_dcs_write_seq(dsi, 0x47, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0x48, 0xF4);
+ mipi_dsi_dcs_write_seq(dsi, 0x49, 0xF3);
+ mipi_dsi_dcs_write_seq(dsi, 0x50, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0x51, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x52, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0x53, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, 0x54, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0x55, 0xF6);
+ mipi_dsi_dcs_write_seq(dsi, 0x56, 0xF5);
+ mipi_dsi_dcs_write_seq(dsi, 0x57, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0x58, 0xF8);
+ mipi_dsi_dcs_write_seq(dsi, 0x59, 0xF7);
+ mipi_dsi_dcs_write_seq(dsi, 0x7E, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0x7F, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x5A);
+ mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x05);
+ mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xC7, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xCA, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0xCB, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0xCC, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0xCE, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xCF, 0x05);
+ mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0x84, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0x85, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0x86, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0x87, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05);
+ mipi_dsi_dcs_write_seq(dsi, 0x89, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0x8A, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x97, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0x9A, 0x0E);
+ mipi_dsi_dcs_write_seq(dsi, 0x9B, 0x0F);
+ mipi_dsi_dcs_write_seq(dsi, 0x9C, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0x9D, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0x9E, 0x05);
+ mipi_dsi_dcs_write_seq(dsi, 0x9F, 0x06);
+ mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0x01, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x02, 0xDA);
+ mipi_dsi_dcs_write_seq(dsi, 0x03, 0xBA);
+ mipi_dsi_dcs_write_seq(dsi, 0x04, 0xA8);
+ mipi_dsi_dcs_write_seq(dsi, 0x05, 0x9A);
+ mipi_dsi_dcs_write_seq(dsi, 0x06, 0x70);
+ mipi_dsi_dcs_write_seq(dsi, 0x07, 0xFF);
+ mipi_dsi_dcs_write_seq(dsi, 0x08, 0x91);
+ mipi_dsi_dcs_write_seq(dsi, 0x09, 0x90);
+ mipi_dsi_dcs_write_seq(dsi, 0x0A, 0xFF);
+ mipi_dsi_dcs_write_seq(dsi, 0x0B, 0x8F);
+ mipi_dsi_dcs_write_seq(dsi, 0x0C, 0x60);
+ mipi_dsi_dcs_write_seq(dsi, 0x0D, 0x58);
+ mipi_dsi_dcs_write_seq(dsi, 0x0E, 0x48);
+ mipi_dsi_dcs_write_seq(dsi, 0x0F, 0x38);
+ mipi_dsi_dcs_write_seq(dsi, 0x10, 0x2B);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
+ mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x36, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x70);
+
+ dev_dbg(ctx->dev, "Panel init sequence done\n");
+
+ return 0;
+}
+
+static int panel_nv3051d_unprepare(struct drm_panel *panel)
+{
+ struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0)
+ dev_err(ctx->dev, "failed to set display off: %d\n", ret);
+
+ msleep(20);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(10000, 15000);
+
+ regulator_disable(ctx->vdd);
+
+ return 0;
+}
+
+static int panel_nv3051d_prepare(struct drm_panel *panel)
+{
+ struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ dev_dbg(ctx->dev, "Resetting the panel\n");
+ ret = regulator_enable(ctx->vdd);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(2000, 3000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ msleep(150);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(20);
+
+ ret = panel_nv3051d_init_sequence(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
+ goto disable_vdd;
+ }
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ goto disable_vdd;
+ }
+
+ msleep(200);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
+ goto disable_vdd;
+ }
+
+ usleep_range(10000, 15000);
+
+ return 0;
+
+disable_vdd:
+ regulator_disable(ctx->vdd);
+ return ret;
+}
+
+static int panel_nv3051d_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct panel_nv3051d *ctx = panel_to_panelnv3051d(panel);
+ const struct nv3051d_panel_info *panel_info = ctx->panel_info;
+ struct drm_display_mode *mode;
+ unsigned int i;
+
+ for (i = 0; i < panel_info->num_modes; i++) {
+ mode = drm_mode_duplicate(connector->dev,
+ &panel_info->display_modes[i]);
+ if (!mode)
+ return -ENOMEM;
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (panel_info->num_modes == 1)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.bpc = 8;
+ connector->display_info.width_mm = panel_info->width_mm;
+ connector->display_info.height_mm = panel_info->height_mm;
+ connector->display_info.bus_flags = panel_info->bus_flags;
+
+ return panel_info->num_modes;
+}
+
+static const struct drm_panel_funcs panel_nv3051d_funcs = {
+ .unprepare = panel_nv3051d_unprepare,
+ .prepare = panel_nv3051d_prepare,
+ .get_modes = panel_nv3051d_get_modes,
+};
+
+static int panel_nv3051d_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct panel_nv3051d *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = dev;
+
+ ctx->panel_info = of_device_get_match_data(dev);
+ if (!ctx->panel_info)
+ return -EINVAL;
+
+ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_err(dev, "cannot get reset gpio\n");
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ ctx->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(ctx->vdd)) {
+ ret = PTR_ERR(ctx->vdd);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to request vdd regulator: %d\n", ret);
+ return ret;
+ }
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
+
+ drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return ret;
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void panel_nv3051d_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = drm_panel_unprepare(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
+
+ ret = drm_panel_disable(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
+}
+
+static void panel_nv3051d_remove(struct mipi_dsi_device *dsi)
+{
+ struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ panel_nv3051d_shutdown(dsi);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct drm_display_mode nv3051d_rgxx3_modes[] = {
+ { /* 120hz */
+ .hdisplay = 640,
+ .hsync_start = 640 + 40,
+ .hsync_end = 640 + 40 + 2,
+ .htotal = 640 + 40 + 2 + 80,
+ .vdisplay = 480,
+ .vsync_start = 480 + 18,
+ .vsync_end = 480 + 18 + 2,
+ .vtotal = 480 + 18 + 2 + 28,
+ .clock = 48300,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+ { /* 100hz */
+ .hdisplay = 640,
+ .hsync_start = 640 + 40,
+ .hsync_end = 640 + 40 + 2,
+ .htotal = 640 + 40 + 2 + 80,
+ .vdisplay = 480,
+ .vsync_start = 480 + 18,
+ .vsync_end = 480 + 18 + 2,
+ .vtotal = 480 + 18 + 2 + 28,
+ .clock = 40250,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+ { /* 60hz */
+ .hdisplay = 640,
+ .hsync_start = 640 + 40,
+ .hsync_end = 640 + 40 + 2,
+ .htotal = 640 + 40 + 2 + 80,
+ .vdisplay = 480,
+ .vsync_start = 480 + 18,
+ .vsync_end = 480 + 18 + 2,
+ .vtotal = 480 + 18 + 2 + 28,
+ .clock = 24150,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+};
+
+static const struct nv3051d_panel_info nv3051d_rgxx3_info = {
+ .display_modes = nv3051d_rgxx3_modes,
+ .num_modes = ARRAY_SIZE(nv3051d_rgxx3_modes),
+ .width_mm = 70,
+ .height_mm = 57,
+ .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+};
+
+static const struct of_device_id newvision_nv3051d_of_match[] = {
+ { .compatible = "newvision,nv3051d", .data = &nv3051d_rgxx3_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, newvision_nv3051d_of_match);
+
+static struct mipi_dsi_driver newvision_nv3051d_driver = {
+ .driver = {
+ .name = "panel-newvision-nv3051d",
+ .of_match_table = newvision_nv3051d_of_match,
+ },
+ .probe = panel_nv3051d_probe,
+ .remove = panel_nv3051d_remove,
+ .shutdown = panel_nv3051d_shutdown,
+};
+module_mipi_dsi_driver(newvision_nv3051d_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Newvision NV3051D based MIPI DSI panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-samsung-db7430.c b/drivers/gpu/drm/panel/panel-samsung-db7430.c
index 04640c5256a8..117b26845083 100644
--- a/drivers/gpu/drm/panel/panel-samsung-db7430.c
+++ b/drivers/gpu/drm/panel/panel-samsung-db7430.c
@@ -331,9 +331,16 @@ static const struct of_device_id db7430_match[] = {
};
MODULE_DEVICE_TABLE(of, db7430_match);
+static const struct spi_device_id db7430_ids[] = {
+ { "lms397kf04" },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, db7430_ids);
+
static struct spi_driver db7430_driver = {
.probe = db7430_probe,
.remove = db7430_remove,
+ .id_table = db7430_ids,
.driver = {
.name = "db7430-panel",
.of_match_table = db7430_match,
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 2944228a8e2c..8a3b685c2fcc 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2500,6 +2500,7 @@ static const struct display_timing logictechno_lt161010_2nh_timing = {
static const struct panel_desc logictechno_lt161010_2nh = {
.timings = &logictechno_lt161010_2nh_timing,
.num_timings = 1,
+ .bpc = 6,
.size = {
.width = 154,
.height = 86,
@@ -2529,6 +2530,7 @@ static const struct display_timing logictechno_lt170410_2whc_timing = {
static const struct panel_desc logictechno_lt170410_2whc = {
.timings = &logictechno_lt170410_2whc_timing,
.num_timings = 1,
+ .bpc = 8,
.size = {
.width = 217,
.height = 136,
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
index c481daa4bbce..0b8cf65172ff 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
@@ -19,6 +19,9 @@
/* Command2 BKx selection command */
#define DSI_CMD2BKX_SEL 0xFF
+#define DSI_CMD1 0
+#define DSI_CMD2 BIT(4)
+#define DSI_CMD2BK_MASK GENMASK(3, 0)
/* Command2, BK0 commands */
#define DSI_CMD2_BK0_PVGAMCTRL 0xB0 /* Positive Voltage Gamma Control */
@@ -39,21 +42,6 @@
#define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */
#define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */
-/*
- * Command2 with BK function selection.
- *
- * BIT[4].....CN2
- * BIT[1:0]...BKXSEL
- * 1:00 = CMD2BK0, Command2 BK0
- * 1:01 = CMD2BK1, Command2 BK1
- * 1:11 = CMD2BK3, Command2 BK3
- * 0:00 = Command2 disable
- */
-#define DSI_CMD2BK0_SEL 0x10
-#define DSI_CMD2BK1_SEL 0x11
-#define DSI_CMD2BK3_SEL 0x13
-#define DSI_CMD2BKX_SEL_NONE 0x00
-
/* Command2, BK0 bytes */
#define DSI_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6)
#define DSI_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0)
@@ -191,6 +179,18 @@ static u8 st7701_vgls_map(struct st7701 *st7701)
return 0;
}
+static void st7701_switch_cmd_bkx(struct st7701 *st7701, bool cmd2, u8 bkx)
+{
+ u8 val;
+
+ if (cmd2)
+ val = DSI_CMD2 | FIELD_PREP(DSI_CMD2BK_MASK, bkx);
+ else
+ val = DSI_CMD1;
+
+ ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val);
+}
+
static void st7701_init_sequence(struct st7701 *st7701)
{
const struct st7701_panel_desc *desc = st7701->desc;
@@ -208,8 +208,8 @@ static void st7701_init_sequence(struct st7701 *st7701)
msleep(st7701->sleep_delay);
/* Command2, BK0 */
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK0_SEL);
+ st7701_switch_cmd_bkx(st7701, true, 0);
+
mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_PVGAMCTRL,
desc->pv_gamma, ARRAY_SIZE(desc->pv_gamma));
mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_NVGAMCTRL,
@@ -244,11 +244,10 @@ static void st7701_init_sequence(struct st7701 *st7701)
DSI_CMD2_BK0_INVSEL_ONES_MASK |
FIELD_PREP(DSI_CMD2_BK0_INVSEL_NLINV_MASK, desc->nlinv),
FIELD_PREP(DSI_CMD2_BK0_INVSEL_RTNI_MASK,
- DIV_ROUND_UP(mode->htotal, 16)));
+ (clamp((u32)mode->htotal, 512U, 1008U) - 512) / 16));
/* Command2, BK1 */
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL);
+ st7701_switch_cmd_bkx(st7701, true, 1);
/* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */
ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS,
@@ -373,33 +372,27 @@ static void dmt028vghmcmi_1a_gip_sequence(struct st7701 *st7701)
0x08, 0x08, 0x08, 0x40,
0x3F, 0x64);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+ st7701_switch_cmd_bkx(st7701, false, 0);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL);
+ st7701_switch_cmd_bkx(st7701, true, 3);
ST7701_DSI(st7701, 0xE6, 0x7C);
ST7701_DSI(st7701, 0xE8, 0x00, 0x0E);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+ st7701_switch_cmd_bkx(st7701, false, 0);
ST7701_DSI(st7701, 0x11);
msleep(120);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL);
+ st7701_switch_cmd_bkx(st7701, true, 3);
ST7701_DSI(st7701, 0xE8, 0x00, 0x0C);
msleep(10);
ST7701_DSI(st7701, 0xE8, 0x00, 0x00);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+ st7701_switch_cmd_bkx(st7701, false, 0);
ST7701_DSI(st7701, 0x11);
msleep(120);
ST7701_DSI(st7701, 0xE8, 0x00, 0x00);
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+ st7701_switch_cmd_bkx(st7701, false, 0);
ST7701_DSI(st7701, 0x3A, 0x70);
}
@@ -426,8 +419,7 @@ static int st7701_prepare(struct drm_panel *panel)
st7701->desc->gip_sequence(st7701);
/* Disable Command2 */
- ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
- 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+ st7701_switch_cmd_bkx(st7701, false, 0);
return 0;
}
@@ -762,7 +754,15 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
st7701->dsi = dsi;
st7701->desc = desc;
- return mipi_dsi_attach(dsi);
+ ret = mipi_dsi_attach(dsi);
+ if (ret)
+ goto err_attach;
+
+ return 0;
+
+err_attach:
+ drm_panel_remove(&st7701->panel);
+ return ret;
}
static void st7701_dsi_remove(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c
index 0b1f5a11a055..845304435e23 100644
--- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c
+++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c
@@ -463,9 +463,16 @@ static const struct of_device_id tpg110_match[] = {
};
MODULE_DEVICE_TABLE(of, tpg110_match);
+static const struct spi_device_id tpg110_ids[] = {
+ { "tpg110" },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, tpg110_ids);
+
static struct spi_driver tpg110_driver = {
.probe = tpg110_probe,
.remove = tpg110_remove,
+ .id_table = tpg110_ids,
.driver = {
.name = "tpo-tpg110-panel",
.of_match_table = tpg110_match,
diff --git a/drivers/gpu/drm/panel/panel-widechips-ws2401.c b/drivers/gpu/drm/panel/panel-widechips-ws2401.c
index 236f3cb2b594..2591ff8f0d4e 100644
--- a/drivers/gpu/drm/panel/panel-widechips-ws2401.c
+++ b/drivers/gpu/drm/panel/panel-widechips-ws2401.c
@@ -425,9 +425,16 @@ static const struct of_device_id ws2401_match[] = {
};
MODULE_DEVICE_TABLE(of, ws2401_match);
+static const struct spi_device_id ws2401_ids[] = {
+ { "lms380kf01" },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, ws2401_ids);
+
static struct spi_driver ws2401_driver = {
.probe = ws2401_probe,
.remove = ws2401_remove,
+ .id_table = ws2401_ids,
.driver = {
.name = "ws2401-panel",
.of_match_table = ws2401_match,
diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c
index 6bd0634e2d58..e7942ac449c6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_dump.c
+++ b/drivers/gpu/drm/panfrost/panfrost_dump.c
@@ -209,7 +209,7 @@ void panfrost_core_dump(struct panfrost_job *job)
goto dump_header;
}
- ret = drm_gem_shmem_vmap(&bo->base, &map);
+ ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
if (ret) {
dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n");
iter.hdr->bomap.valid = 0;
@@ -236,7 +236,7 @@ void panfrost_core_dump(struct panfrost_job *job)
vaddr = map.vaddr;
memcpy(iter.data, vaddr, bo->base.base.size);
- drm_gem_shmem_vunmap(&bo->base, &map);
+ drm_gem_vunmap_unlocked(&bo->base.base, &map);
iter.hdr->bomap.valid = 1;
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index e246d914e7f6..4e83a1891f3e 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -250,13 +250,22 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
static size_t get_pgsize(u64 addr, size_t size, size_t *count)
{
+ /*
+ * io-pgtable only operates on multiple pages within a single table
+ * entry, so we need to split at boundaries of the table size, i.e.
+ * the next block size up. The distance from address A to the next
+ * boundary of block size B is logically B - A % B, but in unsigned
+ * two's complement where B is a power of two we get the equivalence
+ * B - A % B == (B - A) % B == (n * B - A) % B, and choose n = 0 :)
+ */
size_t blk_offset = -addr % SZ_2M;
if (blk_offset || size < SZ_2M) {
*count = min_not_zero(blk_offset, size) / SZ_4K;
return SZ_4K;
}
- *count = size / SZ_2M;
+ blk_offset = -addr % SZ_1G ?: SZ_1G;
+ *count = min(blk_offset, size) / SZ_2M;
return SZ_2M;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index bc0df93f7f21..ba9b6e2b2636 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -106,7 +106,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
goto err_close_bo;
}
- ret = drm_gem_shmem_vmap(bo, &map);
+ ret = drm_gem_vmap_unlocked(&bo->base, &map);
if (ret)
goto err_put_mapping;
perfcnt->buf = map.vaddr;
@@ -165,7 +165,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
return 0;
err_vunmap:
- drm_gem_shmem_vunmap(bo, &map);
+ drm_gem_vunmap_unlocked(&bo->base, &map);
err_put_mapping:
panfrost_gem_mapping_put(perfcnt->mapping);
err_close_bo:
@@ -195,7 +195,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
perfcnt->user = NULL;
- drm_gem_shmem_vunmap(&perfcnt->mapping->obj->base, &map);
+ drm_gem_vunmap_unlocked(&perfcnt->mapping->obj->base.base, &map);
perfcnt->buf = NULL;
panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index eb25eedb5ee0..00deba0b7271 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -48,7 +48,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index a152a7c6db21..6492a70e3c39 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -1261,8 +1261,6 @@ int qxl_modeset_init(struct qxl_device *qdev)
qdev->ddev.mode_config.max_width = 8192;
qdev->ddev.mode_config.max_height = 8192;
- qdev->ddev.mode_config.fb_base = qdev->vram_base;
-
drm_mode_create_suggested_offset_properties(&qdev->ddev);
qxl_mode_create_hotplug_mode_update_property(qdev);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 3044ca948ce2..a3b83f89e061 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -37,6 +37,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 432758ad39a3..76f060810f63 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -38,7 +38,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_gem.h>
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 695d9308d1f0..06a58dad5f5c 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -168,9 +168,16 @@ int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map)
bo->map_count++;
goto out;
}
- r = ttm_bo_vmap(&bo->tbo, &bo->map);
+
+ r = __qxl_bo_pin(bo);
if (r)
return r;
+
+ r = ttm_bo_vmap(&bo->tbo, &bo->map);
+ if (r) {
+ __qxl_bo_unpin(bo);
+ return r;
+ }
bo->map_count = 1;
/* TODO: Remove kptr in favor of map everywhere. */
@@ -192,12 +199,6 @@ int qxl_bo_vmap(struct qxl_bo *bo, struct iosys_map *map)
if (r)
return r;
- r = __qxl_bo_pin(bo);
- if (r) {
- qxl_bo_unreserve(bo);
- return r;
- }
-
r = qxl_bo_vmap_locked(bo, map);
qxl_bo_unreserve(bo);
return r;
@@ -247,6 +248,7 @@ void qxl_bo_vunmap_locked(struct qxl_bo *bo)
return;
bo->kptr = NULL;
ttm_bo_vunmap(&bo->tbo, &bo->map);
+ __qxl_bo_unpin(bo);
}
int qxl_bo_vunmap(struct qxl_bo *bo)
@@ -258,7 +260,6 @@ int qxl_bo_vunmap(struct qxl_bo *bo)
return r;
qxl_bo_vunmap_locked(bo);
- __qxl_bo_unpin(bo);
qxl_bo_unreserve(bo);
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
index 142d01415acb..9169c26357d3 100644
--- a/drivers/gpu/drm/qxl/qxl_prime.c
+++ b/drivers/gpu/drm/qxl/qxl_prime.c
@@ -59,7 +59,7 @@ int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
struct qxl_bo *bo = gem_to_qxl_bo(obj);
int ret;
- ret = qxl_bo_vmap(bo, map);
+ ret = qxl_bo_vmap_locked(bo, map);
if (ret < 0)
return ret;
@@ -71,5 +71,5 @@ void qxl_gem_prime_vunmap(struct drm_gem_object *obj,
{
struct qxl_bo *bo = gem_to_qxl_bo(obj);
- qxl_bo_vunmap(bo);
+ qxl_bo_vunmap_locked(bo);
}
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 52819e7f1fca..97a277f9a25e 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,4 +1,34 @@
# SPDX-License-Identifier: MIT
+
+config DRM_RADEON
+ tristate "ATI Radeon"
+ depends on DRM && PCI && MMU
+ depends on AGP || !AGP
+ select FW_LOADER
+ select DRM_DISPLAY_DP_HELPER
+ select DRM_DISPLAY_HELPER
+ select DRM_KMS_HELPER
+ select DRM_TTM
+ select DRM_TTM_HELPER
+ select SND_HDA_COMPONENT if SND_HDA_CORE
+ select POWER_SUPPLY
+ select HWMON
+ select BACKLIGHT_CLASS_DEVICE
+ select INTERVAL_TREE
+ # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
+ # ACPI_VIDEO's dependencies must also be selected.
+ select INPUT if ACPI
+ select ACPI_VIDEO if ACPI
+ # On x86 ACPI_VIDEO also needs ACPI_WMI
+ select X86_PLATFORM_DEVICES if ACPI && X86
+ select ACPI_WMI if ACPI && X86
+ help
+ Choose this option if you have an ATI Radeon graphics card. There
+ are both PCI and AGP versions. You don't need to choose this to
+ run the Radeon in plain VGA mode.
+
+ If M is selected, the module will be called radeon.
+
config DRM_RADEON_USERPTR
bool "Always enable userptr support"
depends on DRM_RADEON
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index da35a970fcc0..235e59b547a1 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -3615,7 +3615,7 @@ typedef struct _ATOM_FAKE_EDID_PATCH_RECORD
{
UCHAR ucRecordType;
UCHAR ucFakeEDIDLength;
- UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements.
+ UCHAR ucFakeEDIDString[]; // This actually has ucFakeEdidLength elements.
} ATOM_FAKE_EDID_PATCH_RECORD;
typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 166c18d62f6d..2e7161acd443 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -79,6 +79,7 @@
#include <drm/ttm/ttm_execbuf_util.h>
#include <drm/drm_gem.h>
+#include <drm/drm_audio_component.h>
#include "radeon_family.h"
#include "radeon_mode.h"
@@ -1796,6 +1797,9 @@ struct r600_audio {
struct radeon_audio_funcs *hdmi_funcs;
struct radeon_audio_funcs *dp_funcs;
struct radeon_audio_basic_funcs *funcs;
+ struct drm_audio_component *component;
+ bool component_registered;
+ struct mutex component_mutex;
};
/*
@@ -2994,6 +2998,10 @@ void radeon_irq_kms_set_irq_n_enabled(struct radeon_device *rdev,
bool enable, const char *name,
unsigned n);
+/* Audio component binding */
+void radeon_audio_component_init(struct radeon_device *rdev);
+void radeon_audio_component_fini(struct radeon_device *rdev);
+
#include "radeon_object.h"
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 204127bad89c..4ad5a328d920 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1727,8 +1727,11 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
}
}
record += fake_edid_record->ucFakeEDIDLength ?
- fake_edid_record->ucFakeEDIDLength + 2 :
- sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
+ struct_size(fake_edid_record,
+ ucFakeEDIDString,
+ fake_edid_record->ucFakeEDIDLength) :
+ /* empty fake edid record must be 3 bytes long */
+ sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
break;
case LCD_PANEL_RESOLUTION_RECORD_TYPE:
panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c
index 7c5e80d03fc9..d6ccaf24ee0c 100644
--- a/drivers/gpu/drm/radeon/radeon_audio.c
+++ b/drivers/gpu/drm/radeon/radeon_audio.c
@@ -23,6 +23,7 @@
*/
#include <linux/gcd.h>
+#include <linux/component.h>
#include <drm/drm_crtc.h>
#include "dce6_afmt.h"
@@ -180,6 +181,8 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
.dpms = evergreen_dp_enable,
};
+static void radeon_audio_component_notify(struct radeon_device *rdev, int port);
+
static void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask)
{
@@ -207,6 +210,8 @@ static void radeon_audio_enable(struct radeon_device *rdev,
if (rdev->audio.funcs->enable)
rdev->audio.funcs->enable(rdev, pin, enable_mask);
+
+ radeon_audio_component_notify(rdev, pin->id);
}
static void radeon_audio_interface_init(struct radeon_device *rdev)
@@ -721,3 +726,115 @@ unsigned int radeon_audio_decode_dfs_div(unsigned int div)
else
return 0;
}
+
+/*
+ * Audio component support
+ */
+static void radeon_audio_component_notify(struct radeon_device *rdev, int port)
+{
+ struct drm_audio_component *acomp;
+
+ mutex_lock(&rdev->audio.component_mutex);
+ acomp = rdev->audio.component;
+ if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
+ acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+ port, -1);
+ mutex_unlock(&rdev->audio.component_mutex);
+}
+
+static int radeon_audio_component_get_eld(struct device *kdev, int port,
+ int pipe, bool *enabled,
+ unsigned char *buf, int max_bytes)
+{
+ struct drm_device *dev = dev_get_drvdata(kdev);
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_encoder *encoder;
+ struct radeon_encoder *radeon_encoder;
+ struct radeon_encoder_atom_dig *dig;
+ struct drm_connector *connector;
+ int ret = 0;
+
+ *enabled = false;
+ if (!rdev->audio.enabled || !rdev->mode_info.mode_config_initialized)
+ return 0;
+
+ list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
+ if (!radeon_encoder_is_digital(encoder))
+ continue;
+ radeon_encoder = to_radeon_encoder(encoder);
+ dig = radeon_encoder->enc_priv;
+ if (!dig->pin || dig->pin->id != port)
+ continue;
+ connector = radeon_get_connector_for_encoder(encoder);
+ if (!connector)
+ continue;
+ *enabled = true;
+ ret = drm_eld_size(connector->eld);
+ memcpy(buf, connector->eld, min(max_bytes, ret));
+ break;
+ }
+
+ return ret;
+}
+
+static const struct drm_audio_component_ops radeon_audio_component_ops = {
+ .get_eld = radeon_audio_component_get_eld,
+};
+
+static int radeon_audio_component_bind(struct device *kdev,
+ struct device *hda_kdev, void *data)
+{
+ struct drm_device *dev = dev_get_drvdata(kdev);
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_audio_component *acomp = data;
+
+ if (WARN_ON(!device_link_add(hda_kdev, kdev, DL_FLAG_STATELESS)))
+ return -ENOMEM;
+
+ mutex_lock(&rdev->audio.component_mutex);
+ acomp->ops = &radeon_audio_component_ops;
+ acomp->dev = kdev;
+ rdev->audio.component = acomp;
+ mutex_unlock(&rdev->audio.component_mutex);
+
+ return 0;
+}
+
+static void radeon_audio_component_unbind(struct device *kdev,
+ struct device *hda_kdev, void *data)
+{
+ struct drm_device *dev = dev_get_drvdata(kdev);
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_audio_component *acomp = data;
+
+ device_link_remove(hda_kdev, kdev);
+
+ mutex_lock(&rdev->audio.component_mutex);
+ rdev->audio.component = NULL;
+ acomp->ops = NULL;
+ acomp->dev = NULL;
+ mutex_unlock(&rdev->audio.component_mutex);
+}
+
+static const struct component_ops radeon_audio_component_bind_ops = {
+ .bind = radeon_audio_component_bind,
+ .unbind = radeon_audio_component_unbind,
+};
+
+void radeon_audio_component_init(struct radeon_device *rdev)
+{
+ if (rdev->audio.component_registered ||
+ !radeon_audio || !radeon_audio_chipset_supported(rdev))
+ return;
+
+ if (!component_add(rdev->dev, &radeon_audio_component_bind_ops))
+ rdev->audio.component_registered = true;
+}
+
+void radeon_audio_component_fini(struct radeon_device *rdev)
+{
+ if (rdev->audio.component_registered) {
+ component_del(rdev->dev, &radeon_audio_component_bind_ops);
+ rdev->audio.component_registered = false;
+ }
+}
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 33121655d50b..63bdc9f6fc24 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -227,6 +227,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
if (!found)
return false;
+ pci_dev_put(pdev);
rdev->bios = kmalloc(size, GFP_KERNEL);
if (!rdev->bios) {
@@ -612,13 +613,14 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
acpi_size tbl_size;
UEFI_ACPI_VFCT *vfct;
unsigned offset;
+ bool r = false;
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
- return false;
+ goto out;
}
vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -631,13 +633,13 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
offset += sizeof(VFCT_IMAGE_HEADER);
if (offset > tbl_size) {
DRM_ERROR("ACPI VFCT image header truncated\n");
- return false;
+ goto out;
}
offset += vhdr->ImageLength;
if (offset > tbl_size) {
DRM_ERROR("ACPI VFCT image truncated\n");
- return false;
+ goto out;
}
if (vhdr->ImageLength &&
@@ -649,15 +651,18 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
rdev->bios = kmemdup(&vbios->VbiosContent,
vhdr->ImageLength,
GFP_KERNEL);
+ if (rdev->bios)
+ r = true;
- if (!rdev->bios)
- return false;
- return true;
+ goto out;
}
}
DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
- return false;
+
+out:
+ acpi_put_table(hdr);
+ return r;
}
#else
static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 446f7bae54c4..46a27ebf4588 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -400,8 +400,11 @@ static int cmp_size_smaller_first(void *priv, const struct list_head *a,
struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head);
/* Sort A before B if A is smaller. */
- return (int)la->robj->tbo.resource->num_pages -
- (int)lb->robj->tbo.resource->num_pages;
+ if (la->robj->tbo.base.size > lb->robj->tbo.base.size)
+ return 1;
+ if (la->robj->tbo.base.size < lb->robj->tbo.base.size)
+ return -1;
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a556b6be1137..6344454a7721 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1207,7 +1207,7 @@ static void radeon_check_arguments(struct radeon_device *rdev)
* @pdev: pci dev pointer
* @state: vga_switcheroo state
*
- * Callback for the switcheroo driver. Suspends or resumes the
+ * Callback for the switcheroo driver. Suspends or resumes
* the asics before or after it is powered up using ACPI methods.
*/
static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
@@ -1312,6 +1312,7 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->gpu_clock_mutex);
mutex_init(&rdev->srbm_mutex);
+ mutex_init(&rdev->audio.component_mutex);
init_rwsem(&rdev->pm.mclk_lock);
init_rwsem(&rdev->exclusive_lock);
init_waitqueue_head(&rdev->irq.vblank_queue);
@@ -1451,6 +1452,8 @@ int radeon_device_init(struct radeon_device *rdev,
goto failed;
}
+ radeon_audio_component_init(rdev);
+
r = radeon_ib_ring_tests(rdev);
if (r)
DRM_ERROR("ib ring test failed (%d).\n", r);
@@ -1513,6 +1516,7 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->shutdown = true;
/* evict vram memory */
radeon_bo_evict_vram(rdev);
+ radeon_audio_component_fini(rdev);
radeon_fini(rdev);
if (!pci_is_thunderbolt_attached(rdev->pdev))
vga_switcheroo_unregister_client(rdev->pdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index ca5598ae8bfc..9bed1a6cb163 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1604,8 +1604,6 @@ int radeon_modeset_init(struct radeon_device *rdev)
rdev->ddev->mode_config.fb_modifiers_not_supported = true;
- rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
-
ret = radeon_modeset_create_props(rdev);
if (ret) {
return ret;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 6ccea51d4072..c1710ed1cab8 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -80,6 +80,8 @@ static const struct fb_ops radeonfb_ops = {
DRM_FB_HELPER_DEFAULT_OPS,
.fb_open = radeonfb_open,
.fb_release = radeonfb_release,
+ .fb_read = drm_fb_helper_cfb_read,
+ .fb_write = drm_fb_helper_cfb_write,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
@@ -243,7 +245,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
rbo = gem_to_radeon_bo(gobj);
/* okay we have an object now allocate the framebuffer */
- info = drm_fb_helper_alloc_fbi(helper);
+ info = drm_fb_helper_alloc_info(helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto out;
@@ -276,7 +278,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
drm_fb_helper_fill_info(info, &rfbdev->helper, sizes);
/* setup aperture base/size for vesafb takeover */
- info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
+ info->apertures->ranges[0].base = rdev->mc.aper_base;
info->apertures->ranges[0].size = rdev->mc.aper_size;
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
@@ -309,7 +311,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
{
struct drm_framebuffer *fb = &rfbdev->fb;
- drm_fb_helper_unregister_fbi(&rfbdev->helper);
+ drm_fb_helper_unregister_info(&rfbdev->helper);
if (fb->obj[0]) {
radeonfb_destroy_pinned_object(fb->obj[0]);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 00c33b24d5d3..10c0fbd9d2b4 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -232,7 +232,7 @@ int radeon_bo_kmap(struct radeon_bo *bo, void **ptr)
}
return 0;
}
- r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap);
+ r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap);
if (r) {
return r;
}
@@ -737,7 +737,7 @@ vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
if (bo->resource->mem_type != TTM_PL_VRAM)
return 0;
- size = bo->resource->num_pages << PAGE_SHIFT;
+ size = bo->resource->size;
offset = bo->resource->start << PAGE_SHIFT;
if ((offset + size) <= rdev->mc.visible_vram_size)
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h
index c9fed5f2b870..22676617e1a5 100644
--- a/drivers/gpu/drm/radeon/radeon_trace.h
+++ b/drivers/gpu/drm/radeon/radeon_trace.h
@@ -22,7 +22,7 @@ TRACE_EVENT(radeon_bo_create,
TP_fast_assign(
__entry->bo = bo;
- __entry->pages = bo->tbo.resource->num_pages;
+ __entry->pages = PFN_UP(bo->tbo.resource->size);
),
TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages)
);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index d33fec488713..30402b5ce4c5 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -181,7 +181,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
- num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
+ num_pages = PFN_UP(new_mem->size) * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->base.resv);
if (IS_ERR(fence))
return PTR_ERR(fence);
@@ -268,7 +268,7 @@ out:
static int radeon_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem)
{
struct radeon_device *rdev = radeon_get_rdev(bdev);
- size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
+ size_t bus_size = (size_t)mem->size;
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
@@ -869,11 +869,11 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
page = rdev->gart.pages[p];
if (page) {
- ptr = kmap(page);
+ ptr = kmap_local_page(page);
ptr += off;
r = copy_to_user(buf, ptr, cur_size);
- kunmap(rdev->gart.pages[p]);
+ kunmap_local(ptr);
} else
r = clear_user(buf, cur_size);
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index c959e8c6be7d..b2bddbeca878 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -41,15 +41,26 @@ config DRM_RCAR_LVDS
depends on DRM_RCAR_USE_LVDS
select DRM_KMS_HELPER
select DRM_PANEL
- select OF_FLATTREE
- select OF_OVERLAY
+
+config DRM_RCAR_USE_MIPI_DSI
+ bool "R-Car DU MIPI DSI Encoder Support"
+ depends on DRM_BRIDGE && OF
+ default DRM_RCAR_DU
+ help
+ Enable support for the R-Car Display Unit embedded MIPI DSI encoders.
config DRM_RCAR_MIPI_DSI
- tristate "R-Car DU MIPI DSI Encoder Support"
+ def_tristate DRM_RCAR_DU
+ depends on DRM_RCAR_USE_MIPI_DSI
+ select DRM_MIPI_DSI
+
+config DRM_RZG2L_MIPI_DSI
+ tristate "RZ/G2L MIPI DSI Encoder Support"
depends on DRM && DRM_BRIDGE && OF
+ depends on ARCH_RENESAS || COMPILE_TEST
select DRM_MIPI_DSI
help
- Enable support for the R-Car Display Unit embedded MIPI DSI encoders.
+ Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
config DRM_RCAR_VSP
bool "R-Car DU VSP Compositor Support" if ARM
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 6f132325c8b7..b8f2c82651d9 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -14,3 +14,5 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o
obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o
obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o
+
+obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index a2776f1d6f2c..d003e8d9e7a2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -20,7 +20,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c
new file mode 100644
index 000000000000..aa95b85a2964
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c
@@ -0,0 +1,816 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L MIPI DSI Encoder Driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include "rzg2l_mipi_dsi_regs.h"
+
+struct rzg2l_mipi_dsi {
+ struct device *dev;
+ void __iomem *mmio;
+
+ struct reset_control *rstc;
+ struct reset_control *arstc;
+ struct reset_control *prstc;
+
+ struct mipi_dsi_host host;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+
+ struct clk *vclk;
+
+ enum mipi_dsi_pixel_format format;
+ unsigned int num_data_lanes;
+ unsigned int lanes;
+ unsigned long mode_flags;
+};
+
+static inline struct rzg2l_mipi_dsi *
+bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct rzg2l_mipi_dsi, bridge);
+}
+
+static inline struct rzg2l_mipi_dsi *
+host_to_rzg2l_mipi_dsi(struct mipi_dsi_host *host)
+{
+ return container_of(host, struct rzg2l_mipi_dsi, host);
+}
+
+struct rzg2l_mipi_dsi_timings {
+ unsigned long hsfreq_max;
+ u32 t_init;
+ u32 tclk_prepare;
+ u32 ths_prepare;
+ u32 tclk_zero;
+ u32 tclk_pre;
+ u32 tclk_post;
+ u32 tclk_trail;
+ u32 ths_zero;
+ u32 ths_trail;
+ u32 ths_exit;
+ u32 tlpx;
+};
+
+static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
+ {
+ .hsfreq_max = 80000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 13,
+ .tclk_zero = 33,
+ .tclk_pre = 24,
+ .tclk_post = 94,
+ .tclk_trail = 10,
+ .ths_zero = 23,
+ .ths_trail = 17,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+ {
+ .hsfreq_max = 125000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 12,
+ .tclk_zero = 33,
+ .tclk_pre = 15,
+ .tclk_post = 94,
+ .tclk_trail = 10,
+ .ths_zero = 23,
+ .ths_trail = 17,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+ {
+ .hsfreq_max = 250000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 12,
+ .tclk_zero = 33,
+ .tclk_pre = 13,
+ .tclk_post = 94,
+ .tclk_trail = 10,
+ .ths_zero = 23,
+ .ths_trail = 16,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+ {
+ .hsfreq_max = 360000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 10,
+ .tclk_zero = 33,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 7,
+ .ths_zero = 16,
+ .ths_trail = 9,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+ {
+ .hsfreq_max = 720000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 9,
+ .tclk_zero = 33,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 7,
+ .ths_zero = 16,
+ .ths_trail = 9,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+ {
+ .hsfreq_max = 1500000,
+ .t_init = 79801,
+ .tclk_prepare = 8,
+ .ths_prepare = 9,
+ .tclk_zero = 33,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 7,
+ .ths_zero = 16,
+ .ths_trail = 9,
+ .ths_exit = 13,
+ .tlpx = 6,
+ },
+};
+
+static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
+{
+ iowrite32(data, dsi->mmio + reg);
+}
+
+static void rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
+{
+ iowrite32(data, dsi->mmio + LINK_REG_OFFSET + reg);
+}
+
+static u32 rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
+{
+ return ioread32(dsi->mmio + reg);
+}
+
+static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
+{
+ return ioread32(dsi->mmio + LINK_REG_OFFSET + reg);
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware Setup
+ */
+
+static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+ unsigned long hsfreq)
+{
+ const struct rzg2l_mipi_dsi_timings *dphy_timings;
+ unsigned int i;
+ u32 dphyctrl0;
+ u32 dphytim0;
+ u32 dphytim1;
+ u32 dphytim2;
+ u32 dphytim3;
+ int ret;
+
+ /* All DSI global operation timings are set with recommended setting */
+ for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) {
+ dphy_timings = &rzg2l_mipi_dsi_global_timings[i];
+ if (hsfreq <= dphy_timings->hsfreq_max)
+ break;
+ }
+
+ /* Initializing DPHY before accessing LINK */
+ dphyctrl0 = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN |
+ DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR;
+
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
+ usleep_range(20, 30);
+
+ dphyctrl0 |= DSIDPHYCTRL0_EN_LDO1200;
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
+ usleep_range(10, 20);
+
+ dphytim0 = DSIDPHYTIM0_TCLK_MISS(0) |
+ DSIDPHYTIM0_T_INIT(dphy_timings->t_init);
+ dphytim1 = DSIDPHYTIM1_THS_PREPARE(dphy_timings->ths_prepare) |
+ DSIDPHYTIM1_TCLK_PREPARE(dphy_timings->tclk_prepare) |
+ DSIDPHYTIM1_THS_SETTLE(0) |
+ DSIDPHYTIM1_TCLK_SETTLE(0);
+ dphytim2 = DSIDPHYTIM2_TCLK_TRAIL(dphy_timings->tclk_trail) |
+ DSIDPHYTIM2_TCLK_POST(dphy_timings->tclk_post) |
+ DSIDPHYTIM2_TCLK_PRE(dphy_timings->tclk_pre) |
+ DSIDPHYTIM2_TCLK_ZERO(dphy_timings->tclk_zero);
+ dphytim3 = DSIDPHYTIM3_TLPX(dphy_timings->tlpx) |
+ DSIDPHYTIM3_THS_EXIT(dphy_timings->ths_exit) |
+ DSIDPHYTIM3_THS_TRAIL(dphy_timings->ths_trail) |
+ DSIDPHYTIM3_THS_ZERO(dphy_timings->ths_zero);
+
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM0, dphytim0);
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM1, dphytim1);
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM2, dphytim2);
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM3, dphytim3);
+
+ ret = reset_control_deassert(dsi->rstc);
+ if (ret < 0)
+ return ret;
+
+ udelay(1);
+
+ return 0;
+}
+
+static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
+{
+ u32 dphyctrl0;
+
+ dphyctrl0 = rzg2l_mipi_dsi_phy_read(dsi, DSIDPHYCTRL0);
+
+ dphyctrl0 &= ~(DSIDPHYCTRL0_EN_LDO1200 | DSIDPHYCTRL0_EN_BGR);
+ rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
+
+ reset_control_assert(dsi->rstc);
+}
+
+static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
+ const struct drm_display_mode *mode)
+{
+ unsigned long hsfreq;
+ unsigned int bpp;
+ u32 txsetr;
+ u32 clstptsetr;
+ u32 lptrnstsetr;
+ u32 clkkpt;
+ u32 clkbfht;
+ u32 clkstpt;
+ u32 golpbkt;
+ int ret;
+
+ /*
+ * Relationship between hsclk and vclk must follow
+ * vclk * bpp = hsclk * 8 * lanes
+ * where vclk: video clock (Hz)
+ * bpp: video pixel bit depth
+ * hsclk: DSI HS Byte clock frequency (Hz)
+ * lanes: number of data lanes
+ *
+ * hsclk(bit) = hsclk(byte) * 8
+ */
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes);
+
+ ret = pm_runtime_resume_and_get(dsi->dev);
+ if (ret < 0)
+ return ret;
+
+ clk_set_rate(dsi->vclk, mode->clock * 1000);
+
+ ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq);
+ if (ret < 0)
+ goto err_phy;
+
+ /* Enable Data lanes and Clock lanes */
+ txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN;
+ rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr);
+
+ /*
+ * Global timings characteristic depends on high speed Clock Frequency
+ * Currently MIPI DSI-IF just supports maximum FHD@60 with:
+ * - videoclock = 148.5 (MHz)
+ * - bpp: maximum 24bpp
+ * - data lanes: maximum 4 lanes
+ * Therefore maximum hsclk will be 891 Mbps.
+ */
+ if (hsfreq > 445500) {
+ clkkpt = 12;
+ clkbfht = 15;
+ clkstpt = 48;
+ golpbkt = 75;
+ } else if (hsfreq > 250000) {
+ clkkpt = 7;
+ clkbfht = 8;
+ clkstpt = 27;
+ golpbkt = 40;
+ } else {
+ clkkpt = 8;
+ clkbfht = 6;
+ clkstpt = 24;
+ golpbkt = 29;
+ }
+
+ clstptsetr = CLSTPTSETR_CLKKPT(clkkpt) | CLSTPTSETR_CLKBFHT(clkbfht) |
+ CLSTPTSETR_CLKSTPT(clkstpt);
+ rzg2l_mipi_dsi_link_write(dsi, CLSTPTSETR, clstptsetr);
+
+ lptrnstsetr = LPTRNSTSETR_GOLPBKT(golpbkt);
+ rzg2l_mipi_dsi_link_write(dsi, LPTRNSTSETR, lptrnstsetr);
+
+ return 0;
+
+err_phy:
+ rzg2l_mipi_dsi_dphy_exit(dsi);
+ pm_runtime_put(dsi->dev);
+
+ return ret;
+}
+
+static void rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi *dsi)
+{
+ rzg2l_mipi_dsi_dphy_exit(dsi);
+ pm_runtime_put(dsi->dev);
+}
+
+static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
+ const struct drm_display_mode *mode)
+{
+ u32 vich1ppsetr;
+ u32 vich1vssetr;
+ u32 vich1vpsetr;
+ u32 vich1hssetr;
+ u32 vich1hpsetr;
+ int dsi_format;
+ u32 delay[2];
+ u8 index;
+
+ /* Configuration for Pixel Packet */
+ dsi_format = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ switch (dsi_format) {
+ case 24:
+ vich1ppsetr = VICH1PPSETR_DT_RGB24;
+ break;
+ case 18:
+ vich1ppsetr = VICH1PPSETR_DT_RGB18;
+ break;
+ }
+
+ if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) &&
+ !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST))
+ vich1ppsetr |= VICH1PPSETR_TXESYNC_PULSE;
+
+ rzg2l_mipi_dsi_link_write(dsi, VICH1PPSETR, vich1ppsetr);
+
+ /* Configuration for Video Parameters */
+ vich1vssetr = VICH1VSSETR_VACTIVE(mode->vdisplay) |
+ VICH1VSSETR_VSA(mode->vsync_end - mode->vsync_start);
+ vich1vssetr |= (mode->flags & DRM_MODE_FLAG_PVSYNC) ?
+ VICH1VSSETR_VSPOL_HIGH : VICH1VSSETR_VSPOL_LOW;
+
+ vich1vpsetr = VICH1VPSETR_VFP(mode->vsync_start - mode->vdisplay) |
+ VICH1VPSETR_VBP(mode->vtotal - mode->vsync_end);
+
+ vich1hssetr = VICH1HSSETR_HACTIVE(mode->hdisplay) |
+ VICH1HSSETR_HSA(mode->hsync_end - mode->hsync_start);
+ vich1hssetr |= (mode->flags & DRM_MODE_FLAG_PHSYNC) ?
+ VICH1HSSETR_HSPOL_HIGH : VICH1HSSETR_HSPOL_LOW;
+
+ vich1hpsetr = VICH1HPSETR_HFP(mode->hsync_start - mode->hdisplay) |
+ VICH1HPSETR_HBP(mode->htotal - mode->hsync_end);
+
+ rzg2l_mipi_dsi_link_write(dsi, VICH1VSSETR, vich1vssetr);
+ rzg2l_mipi_dsi_link_write(dsi, VICH1VPSETR, vich1vpsetr);
+ rzg2l_mipi_dsi_link_write(dsi, VICH1HSSETR, vich1hssetr);
+ rzg2l_mipi_dsi_link_write(dsi, VICH1HPSETR, vich1hpsetr);
+
+ /*
+ * Configuration for Delay Value
+ * Delay value based on 2 ranges of video clock.
+ * 74.25MHz is videoclock of HD@60p or FHD@30p
+ */
+ if (mode->clock > 74250) {
+ delay[0] = 231;
+ delay[1] = 216;
+ } else {
+ delay[0] = 220;
+ delay[1] = 212;
+ }
+
+ if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+ index = 0;
+ else
+ index = 1;
+
+ rzg2l_mipi_dsi_link_write(dsi, VICH1SET1R,
+ VICH1SET1R_DLY(delay[index]));
+}
+
+static int rzg2l_mipi_dsi_start_hs_clock(struct rzg2l_mipi_dsi *dsi)
+{
+ bool is_clk_cont;
+ u32 hsclksetr;
+ u32 status;
+ int ret;
+
+ is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS);
+
+ /* Start HS clock */
+ hsclksetr = HSCLKSETR_HSCLKRUN_HS | (is_clk_cont ?
+ HSCLKSETR_HSCLKMODE_CONT :
+ HSCLKSETR_HSCLKMODE_NON_CONT);
+ rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR, hsclksetr);
+
+ if (is_clk_cont) {
+ ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
+ status & PLSR_CLLP2HS,
+ 2000, 20000, false, dsi, PLSR);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to start HS clock\n");
+ return ret;
+ }
+ }
+
+ dev_dbg(dsi->dev, "Start High Speed Clock with %s clock mode",
+ is_clk_cont ? "continuous" : "non-continuous");
+
+ return 0;
+}
+
+static int rzg2l_mipi_dsi_stop_hs_clock(struct rzg2l_mipi_dsi *dsi)
+{
+ bool is_clk_cont;
+ u32 status;
+ int ret;
+
+ is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS);
+
+ /* Stop HS clock */
+ rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR,
+ is_clk_cont ? HSCLKSETR_HSCLKMODE_CONT :
+ HSCLKSETR_HSCLKMODE_NON_CONT);
+
+ if (is_clk_cont) {
+ ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
+ status & PLSR_CLHS2LP,
+ 2000, 20000, false, dsi, PLSR);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to stop HS clock\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rzg2l_mipi_dsi_start_video(struct rzg2l_mipi_dsi *dsi)
+{
+ u32 vich1set0r;
+ u32 status;
+ int ret;
+
+ /* Configuration for Blanking sequence and start video input*/
+ vich1set0r = VICH1SET0R_HFPNOLP | VICH1SET0R_HBPNOLP |
+ VICH1SET0R_HSANOLP | VICH1SET0R_VSTART;
+ rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, vich1set0r);
+
+ ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
+ status & VICH1SR_VIRDY,
+ 2000, 20000, false, dsi, VICH1SR);
+ if (ret < 0)
+ dev_err(dsi->dev, "Failed to start video signal input\n");
+
+ return ret;
+}
+
+static int rzg2l_mipi_dsi_stop_video(struct rzg2l_mipi_dsi *dsi)
+{
+ u32 status;
+ int ret;
+
+ rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, VICH1SET0R_VSTPAFT);
+ ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
+ (status & VICH1SR_STOP) && (!(status & VICH1SR_RUNNING)),
+ 2000, 20000, false, dsi, VICH1SR);
+ if (ret < 0)
+ goto err;
+
+ ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
+ !(status & LINKSR_HSBUSY),
+ 2000, 20000, false, dsi, LINKSR);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_err(dsi->dev, "Failed to stop video signal input\n");
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Bridge
+ */
+
+static int rzg2l_mipi_dsi_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+
+ return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge,
+ flags);
+}
+
+static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct drm_atomic_state *state = old_bridge_state->base.state;
+ struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+ const struct drm_display_mode *mode;
+ struct drm_connector *connector;
+ struct drm_crtc *crtc;
+ int ret;
+
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
+ mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode;
+
+ ret = rzg2l_mipi_dsi_startup(dsi, mode);
+ if (ret < 0)
+ return;
+
+ rzg2l_mipi_dsi_set_display_timing(dsi, mode);
+
+ ret = rzg2l_mipi_dsi_start_hs_clock(dsi);
+ if (ret < 0)
+ goto err_stop;
+
+ ret = rzg2l_mipi_dsi_start_video(dsi);
+ if (ret < 0)
+ goto err_stop_clock;
+
+ return;
+
+err_stop_clock:
+ rzg2l_mipi_dsi_stop_hs_clock(dsi);
+err_stop:
+ rzg2l_mipi_dsi_stop(dsi);
+}
+
+static void rzg2l_mipi_dsi_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+
+ rzg2l_mipi_dsi_stop_video(dsi);
+ rzg2l_mipi_dsi_stop_hs_clock(dsi);
+ rzg2l_mipi_dsi_stop(dsi);
+}
+
+static enum drm_mode_status
+rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ if (mode->clock > 148500)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static const struct drm_bridge_funcs rzg2l_mipi_dsi_bridge_ops = {
+ .attach = rzg2l_mipi_dsi_attach,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_enable = rzg2l_mipi_dsi_atomic_enable,
+ .atomic_disable = rzg2l_mipi_dsi_atomic_disable,
+ .mode_valid = rzg2l_mipi_dsi_bridge_mode_valid,
+};
+
+/* -----------------------------------------------------------------------------
+ * Host setting
+ */
+
+static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
+ int ret;
+
+ if (device->lanes > dsi->num_data_lanes) {
+ dev_err(dsi->dev,
+ "Number of lines of device (%u) exceeds host (%u)\n",
+ device->lanes, dsi->num_data_lanes);
+ return -EINVAL;
+ }
+
+ switch (mipi_dsi_pixel_format_to_bpp(device->format)) {
+ case 24:
+ case 18:
+ break;
+ default:
+ dev_err(dsi->dev, "Unsupported format 0x%04x\n", device->format);
+ return -EINVAL;
+ }
+
+ dsi->lanes = device->lanes;
+ dsi->format = device->format;
+ dsi->mode_flags = device->mode_flags;
+
+ dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node,
+ 1, 0);
+ if (IS_ERR(dsi->next_bridge)) {
+ ret = PTR_ERR(dsi->next_bridge);
+ dev_err(dsi->dev, "failed to get next bridge: %d\n", ret);
+ return ret;
+ }
+
+ drm_bridge_add(&dsi->bridge);
+
+ return 0;
+}
+
+static int rzg2l_mipi_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
+
+ drm_bridge_remove(&dsi->bridge);
+
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops rzg2l_mipi_dsi_host_ops = {
+ .attach = rzg2l_mipi_dsi_host_attach,
+ .detach = rzg2l_mipi_dsi_host_detach,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int __maybe_unused rzg2l_mipi_pm_runtime_suspend(struct device *dev)
+{
+ struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+ reset_control_assert(dsi->prstc);
+ reset_control_assert(dsi->arstc);
+
+ return 0;
+}
+
+static int __maybe_unused rzg2l_mipi_pm_runtime_resume(struct device *dev)
+{
+ struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(dsi->arstc);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_control_deassert(dsi->prstc);
+ if (ret < 0)
+ reset_control_assert(dsi->arstc);
+
+ return ret;
+}
+
+static const struct dev_pm_ops rzg2l_mipi_pm_ops = {
+ SET_RUNTIME_PM_OPS(rzg2l_mipi_pm_runtime_suspend, rzg2l_mipi_pm_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
+{
+ unsigned int num_data_lanes;
+ struct rzg2l_mipi_dsi *dsi;
+ u32 txsetr;
+ int ret;
+
+ dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, dsi);
+ dsi->dev = &pdev->dev;
+
+ ret = drm_of_get_data_lanes_count_ep(dsi->dev->of_node, 1, 0, 1, 4);
+ if (ret < 0)
+ return dev_err_probe(dsi->dev, ret,
+ "missing or invalid data-lanes property\n");
+
+ num_data_lanes = ret;
+
+ dsi->mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dsi->mmio))
+ return PTR_ERR(dsi->mmio);
+
+ dsi->vclk = devm_clk_get(dsi->dev, "vclk");
+ if (IS_ERR(dsi->vclk))
+ return PTR_ERR(dsi->vclk);
+
+ dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst");
+ if (IS_ERR(dsi->rstc))
+ return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
+ "failed to get rst\n");
+
+ dsi->arstc = devm_reset_control_get_exclusive(dsi->dev, "arst");
+ if (IS_ERR(dsi->arstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dsi->arstc),
+ "failed to get arst\n");
+
+ dsi->prstc = devm_reset_control_get_exclusive(dsi->dev, "prst");
+ if (IS_ERR(dsi->prstc))
+ return dev_err_probe(dsi->dev, PTR_ERR(dsi->prstc),
+ "failed to get prst\n");
+
+ platform_set_drvdata(pdev, dsi);
+
+ pm_runtime_enable(dsi->dev);
+
+ ret = pm_runtime_resume_and_get(dsi->dev);
+ if (ret < 0)
+ goto err_pm_disable;
+
+ /*
+ * TXSETR register can be read only after DPHY init. But during probe
+ * mode->clock and format are not available. So initialize DPHY with
+ * timing parameters for 80Mbps.
+ */
+ ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000);
+ if (ret < 0)
+ goto err_phy;
+
+ txsetr = rzg2l_mipi_dsi_link_read(dsi, TXSETR);
+ dsi->num_data_lanes = min(((txsetr >> 16) & 3) + 1, num_data_lanes);
+ rzg2l_mipi_dsi_dphy_exit(dsi);
+ pm_runtime_put(dsi->dev);
+
+ /* Initialize the DRM bridge. */
+ dsi->bridge.funcs = &rzg2l_mipi_dsi_bridge_ops;
+ dsi->bridge.of_node = dsi->dev->of_node;
+
+ /* Init host device */
+ dsi->host.dev = dsi->dev;
+ dsi->host.ops = &rzg2l_mipi_dsi_host_ops;
+ ret = mipi_dsi_host_register(&dsi->host);
+ if (ret < 0)
+ goto err_pm_disable;
+
+ return 0;
+
+err_phy:
+ rzg2l_mipi_dsi_dphy_exit(dsi);
+ pm_runtime_put(dsi->dev);
+err_pm_disable:
+ pm_runtime_disable(dsi->dev);
+ return ret;
+}
+
+static int rzg2l_mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev);
+
+ mipi_dsi_host_unregister(&dsi->host);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
+ { .compatible = "renesas,rzg2l-mipi-dsi" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rzg2l_mipi_dsi_of_table);
+
+static struct platform_driver rzg2l_mipi_dsi_platform_driver = {
+ .probe = rzg2l_mipi_dsi_probe,
+ .remove = rzg2l_mipi_dsi_remove,
+ .driver = {
+ .name = "rzg2l-mipi-dsi",
+ .pm = &rzg2l_mipi_pm_ops,
+ .of_match_table = rzg2l_mipi_dsi_of_table,
+ },
+};
+
+module_platform_driver(rzg2l_mipi_dsi_platform_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L MIPI DSI Encoder Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h
new file mode 100644
index 000000000000..1dbc16ec64a4
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi_regs.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RZ/G2L MIPI DSI Interface Registers Definitions
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#ifndef __RZG2L_MIPI_DSI_REGS_H__
+#define __RZG2L_MIPI_DSI_REGS_H__
+
+#include <linux/bits.h>
+
+/* DPHY Registers */
+#define DSIDPHYCTRL0 0x00
+#define DSIDPHYCTRL0_CAL_EN_HSRX_OFS BIT(16)
+#define DSIDPHYCTRL0_CMN_MASTER_EN BIT(8)
+#define DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 BIT(2)
+#define DSIDPHYCTRL0_EN_LDO1200 BIT(1)
+#define DSIDPHYCTRL0_EN_BGR BIT(0)
+
+#define DSIDPHYTIM0 0x04
+#define DSIDPHYTIM0_TCLK_MISS(x) ((x) << 24)
+#define DSIDPHYTIM0_T_INIT(x) ((x) << 0)
+
+#define DSIDPHYTIM1 0x08
+#define DSIDPHYTIM1_THS_PREPARE(x) ((x) << 24)
+#define DSIDPHYTIM1_TCLK_PREPARE(x) ((x) << 16)
+#define DSIDPHYTIM1_THS_SETTLE(x) ((x) << 8)
+#define DSIDPHYTIM1_TCLK_SETTLE(x) ((x) << 0)
+
+#define DSIDPHYTIM2 0x0c
+#define DSIDPHYTIM2_TCLK_TRAIL(x) ((x) << 24)
+#define DSIDPHYTIM2_TCLK_POST(x) ((x) << 16)
+#define DSIDPHYTIM2_TCLK_PRE(x) ((x) << 8)
+#define DSIDPHYTIM2_TCLK_ZERO(x) ((x) << 0)
+
+#define DSIDPHYTIM3 0x10
+#define DSIDPHYTIM3_TLPX(x) ((x) << 24)
+#define DSIDPHYTIM3_THS_EXIT(x) ((x) << 16)
+#define DSIDPHYTIM3_THS_TRAIL(x) ((x) << 8)
+#define DSIDPHYTIM3_THS_ZERO(x) ((x) << 0)
+
+/* --------------------------------------------------------*/
+/* Link Registers */
+#define LINK_REG_OFFSET 0x10000
+
+/* Link Status Register */
+#define LINKSR 0x10
+#define LINKSR_LPBUSY BIT(13)
+#define LINKSR_HSBUSY BIT(12)
+#define LINKSR_VICHRUN1 BIT(8)
+#define LINKSR_SQCHRUN1 BIT(4)
+#define LINKSR_SQCHRUN0 BIT(0)
+
+/* Tx Set Register */
+#define TXSETR 0x100
+#define TXSETR_NUMLANECAP (0x3 << 16)
+#define TXSETR_DLEN (1 << 9)
+#define TXSETR_CLEN (1 << 8)
+#define TXSETR_NUMLANEUSE(x) (((x) & 0x3) << 0)
+
+/* HS Clock Set Register */
+#define HSCLKSETR 0x104
+#define HSCLKSETR_HSCLKMODE_CONT (1 << 1)
+#define HSCLKSETR_HSCLKMODE_NON_CONT (0 << 1)
+#define HSCLKSETR_HSCLKRUN_HS (1 << 0)
+#define HSCLKSETR_HSCLKRUN_LP (0 << 0)
+
+/* Reset Control Register */
+#define RSTCR 0x110
+#define RSTCR_SWRST BIT(0)
+#define RSTCR_FCETXSTP BIT(16)
+
+/* Reset Status Register */
+#define RSTSR 0x114
+#define RSTSR_DL0DIR (1 << 15)
+#define RSTSR_DLSTPST (0xf << 8)
+#define RSTSR_SWRSTV1 (1 << 4)
+#define RSTSR_SWRSTIB (1 << 3)
+#define RSTSR_SWRSTAPB (1 << 2)
+#define RSTSR_SWRSTLP (1 << 1)
+#define RSTSR_SWRSTHS (1 << 0)
+
+/* Clock Lane Stop Time Set Register */
+#define CLSTPTSETR 0x314
+#define CLSTPTSETR_CLKKPT(x) ((x) << 24)
+#define CLSTPTSETR_CLKBFHT(x) ((x) << 16)
+#define CLSTPTSETR_CLKSTPT(x) ((x) << 2)
+
+/* LP Transition Time Set Register */
+#define LPTRNSTSETR 0x318
+#define LPTRNSTSETR_GOLPBKT(x) ((x) << 0)
+
+/* Physical Lane Status Register */
+#define PLSR 0x320
+#define PLSR_CLHS2LP BIT(27)
+#define PLSR_CLLP2HS BIT(26)
+
+/* Video-Input Channel 1 Set 0 Register */
+#define VICH1SET0R 0x400
+#define VICH1SET0R_VSEN BIT(12)
+#define VICH1SET0R_HFPNOLP BIT(10)
+#define VICH1SET0R_HBPNOLP BIT(9)
+#define VICH1SET0R_HSANOLP BIT(8)
+#define VICH1SET0R_VSTPAFT BIT(1)
+#define VICH1SET0R_VSTART BIT(0)
+
+/* Video-Input Channel 1 Set 1 Register */
+#define VICH1SET1R 0x404
+#define VICH1SET1R_DLY(x) (((x) & 0xfff) << 2)
+
+/* Video-Input Channel 1 Status Register */
+#define VICH1SR 0x410
+#define VICH1SR_VIRDY BIT(3)
+#define VICH1SR_RUNNING BIT(2)
+#define VICH1SR_STOP BIT(1)
+#define VICH1SR_START BIT(0)
+
+/* Video-Input Channel 1 Pixel Packet Set Register */
+#define VICH1PPSETR 0x420
+#define VICH1PPSETR_DT_RGB18 (0x1e << 16)
+#define VICH1PPSETR_DT_RGB18_LS (0x2e << 16)
+#define VICH1PPSETR_DT_RGB24 (0x3e << 16)
+#define VICH1PPSETR_TXESYNC_PULSE (1 << 15)
+#define VICH1PPSETR_VC(x) ((x) << 22)
+
+/* Video-Input Channel 1 Vertical Size Set Register */
+#define VICH1VSSETR 0x428
+#define VICH1VSSETR_VACTIVE(x) (((x) & 0x7fff) << 16)
+#define VICH1VSSETR_VSPOL_LOW (1 << 15)
+#define VICH1VSSETR_VSPOL_HIGH (0 << 15)
+#define VICH1VSSETR_VSA(x) (((x) & 0xfff) << 0)
+
+/* Video-Input Channel 1 Vertical Porch Set Register */
+#define VICH1VPSETR 0x42c
+#define VICH1VPSETR_VFP(x) (((x) & 0x1fff) << 16)
+#define VICH1VPSETR_VBP(x) (((x) & 0x1fff) << 0)
+
+/* Video-Input Channel 1 Horizontal Size Set Register */
+#define VICH1HSSETR 0x430
+#define VICH1HSSETR_HACTIVE(x) (((x) & 0x7fff) << 16)
+#define VICH1HSSETR_HSPOL_LOW (1 << 15)
+#define VICH1HSSETR_HSPOL_HIGH (0 << 15)
+#define VICH1HSSETR_HSA(x) (((x) & 0xfff) << 0)
+
+/* Video-Input Channel 1 Horizontal Porch Set Register */
+#define VICH1HPSETR 0x434
+#define VICH1HPSETR_HFP(x) (((x) & 0x1fff) << 16)
+#define VICH1HPSETR_HBP(x) (((x) & 0x1fff) << 0)
+
+#endif /* __RZG2L_MIPI_DSI_REGS_H__ */
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 518ee13b1d6f..8526dda91931 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -571,7 +571,7 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
- memcpy(&dp->mode, adjusted, sizeof(*mode));
+ drm_mode_copy(&dp->mode, adjusted);
}
static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index f4df9820b295..7901c3babc8c 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -364,12 +364,6 @@ static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg)
return readl(dsi->base + reg);
}
-static inline void dsi_update_bits(struct dw_mipi_dsi_rockchip *dsi, u32 reg,
- u32 mask, u32 val)
-{
- dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
-}
-
static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi,
u8 test_code,
u8 test_data)
@@ -1221,7 +1215,7 @@ static int dw_mipi_dsi_dphy_power_on(struct phy *phy)
return i;
}
- ret = pm_runtime_get_sync(dsi->dev);
+ ret = pm_runtime_resume_and_get(dsi->dev);
if (ret < 0) {
DRM_DEV_ERROR(dsi->dev, "failed to enable device: %d\n", ret);
return ret;
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 87b2243ea23e..f51774866f41 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -499,7 +499,7 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
inno_hdmi_setup(hdmi, adj_mode);
/* Store the display mode for plugin/DPMS poweron events */
- memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
+ drm_mode_copy(&hdmi->previous_mode, adj_mode);
}
static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index cf2cf51091a3..90145ad96984 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -395,7 +395,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
/* Store the display mode for plugin/DPMS poweron events. */
- memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
+ drm_mode_copy(&hdmi->previous_mode, adj_mode);
}
static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 813f9f8c8698..6e0788d14c10 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -17,7 +17,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 1641440837af..aeb03a57240f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -9,10 +9,10 @@
#ifndef _ROCKCHIP_DRM_DRV_H
#define _ROCKCHIP_DRM_DRV_H
-#include <drm/drm_fb_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem.h>
+#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 092bf863110b..cfe8b793d344 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -9,7 +9,6 @@
#include <drm/drm.h>
#include <drm/drm_atomic.h>
#include <drm/drm_damage_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -25,35 +24,6 @@ static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
.dirty = drm_atomic_helper_dirtyfb,
};
-static struct drm_framebuffer *
-rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object **obj, unsigned int num_planes)
-{
- struct drm_framebuffer *fb;
- int ret;
- int i;
-
- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
- if (!fb)
- return ERR_PTR(-ENOMEM);
-
- drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
-
- for (i = 0; i < num_planes; i++)
- fb->obj[i] = obj[i];
-
- ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs);
- if (ret) {
- DRM_DEV_ERROR(dev->dev,
- "Failed to initialize framebuffer: %d\n",
- ret);
- kfree(fb);
- return ERR_PTR(ret);
- }
-
- return fb;
-}
-
static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
@@ -101,25 +71,10 @@ rockchip_fb_create(struct drm_device *dev, struct drm_file *file,
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
-struct drm_framebuffer *
-rockchip_drm_framebuffer_init(struct drm_device *dev,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj)
-{
- struct drm_framebuffer *fb;
-
- fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1);
- if (IS_ERR(fb))
- return ERR_CAST(fb);
-
- return fb;
-}
-
void rockchip_drm_mode_config_init(struct drm_device *dev)
{
dev->mode_config.min_width = 0;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
index 1a696521096d..bae4e079dfb1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -7,11 +7,5 @@
#ifndef _ROCKCHIP_DRM_FB_H
#define _ROCKCHIP_DRM_FB_H
-struct drm_framebuffer *
-rockchip_drm_framebuffer_init(struct drm_device *dev,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj);
-void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb);
-
void rockchip_drm_mode_config_init(struct drm_device *dev);
#endif /* _ROCKCHIP_DRM_FB_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index da8a69953706..6edb7c52cb3d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -9,6 +9,7 @@
#include <linux/vmalloc.h>
#include <drm/drm.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_prime.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c356de5dd220..fa1f4ee6d195 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -602,7 +602,7 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
struct vop *vop = to_vop(crtc);
int ret, i;
- ret = pm_runtime_get_sync(vop->dev);
+ ret = pm_runtime_resume_and_get(vop->dev);
if (ret < 0) {
DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret);
return ret;
@@ -1983,7 +1983,7 @@ static int vop_initial(struct vop *vop)
return PTR_ERR(vop->dclk);
}
- ret = pm_runtime_get_sync(vop->dev);
+ ret = pm_runtime_resume_and_get(vop->dev);
if (ret < 0) {
DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret);
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 105a548d0abe..8cecf81a5ae0 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -822,7 +822,7 @@ static void vop2_enable(struct vop2 *vop2)
{
int ret;
- ret = pm_runtime_get_sync(vop2->dev);
+ ret = pm_runtime_resume_and_get(vop2->dev);
if (ret < 0) {
drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
return;
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 5a284332ec49..68f6ebb33460 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -152,7 +152,7 @@ static int rk3288_lvds_poweron(struct rockchip_lvds *lvds)
DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret);
return ret;
}
- ret = pm_runtime_get_sync(lvds->dev);
+ ret = pm_runtime_resume_and_get(lvds->dev);
if (ret < 0) {
DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
clk_disable(lvds->pclk);
@@ -336,16 +336,20 @@ static int px30_lvds_poweron(struct rockchip_lvds *lvds)
{
int ret;
- ret = pm_runtime_get_sync(lvds->dev);
+ ret = pm_runtime_resume_and_get(lvds->dev);
if (ret < 0) {
DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
return ret;
}
/* Enable LVDS mode */
- return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
+ ret = regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1),
PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1));
+ if (ret)
+ pm_runtime_put(lvds->dev);
+
+ return ret;
}
static void px30_lvds_poweroff(struct rockchip_lvds *lvds)
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
index 9bf0637bf8e2..9d30aa73b542 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -188,7 +188,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = {
.base = 0x1800,
.layer_sel_id = 2,
.supported_rotations = DRM_MODE_REFLECT_Y,
- .type = DRM_PLANE_TYPE_OVERLAY,
+ .type = DRM_PLANE_TYPE_PRIMARY,
.max_upscale_factor = 8,
.max_downscale_factor = 8,
.dly = { 20, 47, 41 },
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index 4b913dbb7d7b..fe09e5be79bd 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -73,6 +73,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity,
entity->priority = priority;
entity->sched_list = num_sched_list > 1 ? sched_list : NULL;
entity->last_scheduled = NULL;
+ RB_CLEAR_NODE(&entity->rb_tree_node);
if(num_sched_list)
entity->rq = &sched_list[0]->sched_rq[entity->priority];
@@ -139,6 +140,73 @@ bool drm_sched_entity_is_ready(struct drm_sched_entity *entity)
return true;
}
+static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
+{
+ struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
+
+ drm_sched_fence_finished(job->s_fence);
+ WARN_ON(job->s_fence->parent);
+ job->sched->ops->free_job(job);
+}
+
+/* Signal the scheduler finished fence when the entity in question is killed. */
+static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
+ struct dma_fence_cb *cb)
+{
+ struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
+ finish_cb);
+ int r;
+
+ dma_fence_put(f);
+
+ /* Wait for all dependencies to avoid data corruptions */
+ while (!xa_empty(&job->dependencies)) {
+ f = xa_erase(&job->dependencies, job->last_dependency++);
+ r = dma_fence_add_callback(f, &job->finish_cb,
+ drm_sched_entity_kill_jobs_cb);
+ if (!r)
+ return;
+
+ dma_fence_put(f);
+ }
+
+ INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
+ schedule_work(&job->work);
+}
+
+/* Remove the entity from the scheduler and kill all pending jobs */
+static void drm_sched_entity_kill(struct drm_sched_entity *entity)
+{
+ struct drm_sched_job *job;
+ struct dma_fence *prev;
+
+ if (!entity->rq)
+ return;
+
+ spin_lock(&entity->rq_lock);
+ entity->stopped = true;
+ drm_sched_rq_remove_entity(entity->rq, entity);
+ spin_unlock(&entity->rq_lock);
+
+ /* Make sure this entity is not used by the scheduler at the moment */
+ wait_for_completion(&entity->entity_idle);
+
+ prev = dma_fence_get(entity->last_scheduled);
+ while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) {
+ struct drm_sched_fence *s_fence = job->s_fence;
+
+ dma_fence_set_error(&s_fence->finished, -ESRCH);
+
+ dma_fence_get(&s_fence->finished);
+ if (!prev || dma_fence_add_callback(prev, &job->finish_cb,
+ drm_sched_entity_kill_jobs_cb))
+ drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
+
+ prev = &s_fence->finished;
+ }
+ dma_fence_put(prev);
+}
+
/**
* drm_sched_entity_flush - Flush a context entity
*
@@ -179,91 +247,13 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)
/* For killed process disable any more IBs enqueue right now */
last_user = cmpxchg(&entity->last_user, current->group_leader, NULL);
if ((!last_user || last_user == current->group_leader) &&
- (current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) {
- spin_lock(&entity->rq_lock);
- entity->stopped = true;
- drm_sched_rq_remove_entity(entity->rq, entity);
- spin_unlock(&entity->rq_lock);
- }
+ (current->flags & PF_EXITING) && (current->exit_code == SIGKILL))
+ drm_sched_entity_kill(entity);
return ret;
}
EXPORT_SYMBOL(drm_sched_entity_flush);
-static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
-{
- struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
-
- drm_sched_fence_finished(job->s_fence);
- WARN_ON(job->s_fence->parent);
- job->sched->ops->free_job(job);
-}
-
-
-/* Signal the scheduler finished fence when the entity in question is killed. */
-static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
- struct dma_fence_cb *cb)
-{
- struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
- finish_cb);
-
- dma_fence_put(f);
- INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
- schedule_work(&job->work);
-}
-
-static struct dma_fence *
-drm_sched_job_dependency(struct drm_sched_job *job,
- struct drm_sched_entity *entity)
-{
- if (!xa_empty(&job->dependencies))
- return xa_erase(&job->dependencies, job->last_dependency++);
-
- if (job->sched->ops->dependency)
- return job->sched->ops->dependency(job, entity);
-
- return NULL;
-}
-
-static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity)
-{
- struct drm_sched_job *job;
- struct dma_fence *f;
- int r;
-
- while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) {
- struct drm_sched_fence *s_fence = job->s_fence;
-
- /* Wait for all dependencies to avoid data corruptions */
- while ((f = drm_sched_job_dependency(job, entity))) {
- dma_fence_wait(f, false);
- dma_fence_put(f);
- }
-
- drm_sched_fence_scheduled(s_fence);
- dma_fence_set_error(&s_fence->finished, -ESRCH);
-
- /*
- * When pipe is hanged by older entity, new entity might
- * not even have chance to submit it's first job to HW
- * and so entity->last_scheduled will remain NULL
- */
- if (!entity->last_scheduled) {
- drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
- continue;
- }
-
- dma_fence_get(entity->last_scheduled);
- r = dma_fence_add_callback(entity->last_scheduled,
- &job->finish_cb,
- drm_sched_entity_kill_jobs_cb);
- if (r == -ENOENT)
- drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
- else if (r)
- DRM_ERROR("fence add callback failed (%d)\n", r);
- }
-}
-
/**
* drm_sched_entity_fini - Destroy a context entity
*
@@ -277,33 +267,17 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity)
*/
void drm_sched_entity_fini(struct drm_sched_entity *entity)
{
- struct drm_gpu_scheduler *sched = NULL;
-
- if (entity->rq) {
- sched = entity->rq->sched;
- drm_sched_rq_remove_entity(entity->rq, entity);
- }
-
- /* Consumption of existing IBs wasn't completed. Forcefully
- * remove them here.
+ /*
+ * If consumption of existing IBs wasn't completed. Forcefully remove
+ * them here. Also makes sure that the scheduler won't touch this entity
+ * any more.
*/
- if (spsc_queue_count(&entity->job_queue)) {
- if (sched) {
- /*
- * Wait for thread to idle to make sure it isn't processing
- * this entity.
- */
- wait_for_completion(&entity->entity_idle);
+ drm_sched_entity_kill(entity);
- }
- if (entity->dependency) {
- dma_fence_remove_callback(entity->dependency,
- &entity->cb);
- dma_fence_put(entity->dependency);
- entity->dependency = NULL;
- }
-
- drm_sched_entity_kill_jobs(entity);
+ if (entity->dependency) {
+ dma_fence_remove_callback(entity->dependency, &entity->cb);
+ dma_fence_put(entity->dependency);
+ entity->dependency = NULL;
}
dma_fence_put(entity->last_scheduled);
@@ -416,6 +390,19 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity)
return false;
}
+static struct dma_fence *
+drm_sched_job_dependency(struct drm_sched_job *job,
+ struct drm_sched_entity *entity)
+{
+ if (!xa_empty(&job->dependencies))
+ return xa_erase(&job->dependencies, job->last_dependency++);
+
+ if (job->sched->ops->prepare_job)
+ return job->sched->ops->prepare_job(job, entity);
+
+ return NULL;
+}
+
struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
{
struct drm_sched_job *sched_job;
@@ -448,6 +435,19 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
smp_wmb();
spsc_queue_pop(&entity->job_queue);
+
+ /*
+ * Update the entity's location in the min heap according to
+ * the timestamp of the next job, if any.
+ */
+ if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) {
+ struct drm_sched_job *next;
+
+ next = to_drm_sched_job(spsc_queue_peek(&entity->job_queue));
+ if (next)
+ drm_sched_rq_update_fifo(entity, next->submit_ts);
+ }
+
return sched_job;
}
@@ -512,6 +512,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
atomic_inc(entity->rq->sched->score);
WRITE_ONCE(entity->last_user, current->group_leader);
first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
+ sched_job->submit_ts = ktime_get();
/* first job wakes up scheduler */
if (first) {
@@ -523,8 +524,13 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
DRM_ERROR("Trying to push to a killed entity\n");
return;
}
+
drm_sched_rq_add_entity(entity->rq, entity);
spin_unlock(&entity->rq_lock);
+
+ if (drm_sched_policy == DRM_SCHED_POLICY_FIFO)
+ drm_sched_rq_update_fifo(entity, sched_job->submit_ts);
+
drm_sched_wakeup(entity->rq->sched);
}
}
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index e5a4ecde0063..31f3a1267be4 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -62,6 +62,55 @@
#define to_drm_sched_job(sched_job) \
container_of((sched_job), struct drm_sched_job, queue_node)
+int drm_sched_policy = DRM_SCHED_POLICY_FIFO;
+
+/**
+ * DOC: sched_policy (int)
+ * Used to override default entities scheduling policy in a run queue.
+ */
+MODULE_PARM_DESC(sched_policy, "Specify the scheduling policy for entities on a run-queue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin, " __stringify(DRM_SCHED_POLICY_FIFO) " = FIFO (default).");
+module_param_named(sched_policy, drm_sched_policy, int, 0444);
+
+static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a,
+ const struct rb_node *b)
+{
+ struct drm_sched_entity *ent_a = rb_entry((a), struct drm_sched_entity, rb_tree_node);
+ struct drm_sched_entity *ent_b = rb_entry((b), struct drm_sched_entity, rb_tree_node);
+
+ return ktime_before(ent_a->oldest_job_waiting, ent_b->oldest_job_waiting);
+}
+
+static inline void drm_sched_rq_remove_fifo_locked(struct drm_sched_entity *entity)
+{
+ struct drm_sched_rq *rq = entity->rq;
+
+ if (!RB_EMPTY_NODE(&entity->rb_tree_node)) {
+ rb_erase_cached(&entity->rb_tree_node, &rq->rb_tree_root);
+ RB_CLEAR_NODE(&entity->rb_tree_node);
+ }
+}
+
+void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts)
+{
+ /*
+ * Both locks need to be grabbed, one to protect from entity->rq change
+ * for entity from within concurrent drm_sched_entity_select_rq and the
+ * other to update the rb tree structure.
+ */
+ spin_lock(&entity->rq_lock);
+ spin_lock(&entity->rq->lock);
+
+ drm_sched_rq_remove_fifo_locked(entity);
+
+ entity->oldest_job_waiting = ts;
+
+ rb_add_cached(&entity->rb_tree_node, &entity->rq->rb_tree_root,
+ drm_sched_entity_compare_before);
+
+ spin_unlock(&entity->rq->lock);
+ spin_unlock(&entity->rq_lock);
+}
+
/**
* drm_sched_rq_init - initialize a given run queue struct
*
@@ -75,6 +124,7 @@ static void drm_sched_rq_init(struct drm_gpu_scheduler *sched,
{
spin_lock_init(&rq->lock);
INIT_LIST_HEAD(&rq->entities);
+ rq->rb_tree_root = RB_ROOT_CACHED;
rq->current_entity = NULL;
rq->sched = sched;
}
@@ -92,9 +142,12 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq,
{
if (!list_empty(&entity->list))
return;
+
spin_lock(&rq->lock);
+
atomic_inc(rq->sched->score);
list_add_tail(&entity->list, &rq->entities);
+
spin_unlock(&rq->lock);
}
@@ -111,23 +164,30 @@ void drm_sched_rq_remove_entity(struct drm_sched_rq *rq,
{
if (list_empty(&entity->list))
return;
+
spin_lock(&rq->lock);
+
atomic_dec(rq->sched->score);
list_del_init(&entity->list);
+
if (rq->current_entity == entity)
rq->current_entity = NULL;
+
+ if (drm_sched_policy == DRM_SCHED_POLICY_FIFO)
+ drm_sched_rq_remove_fifo_locked(entity);
+
spin_unlock(&rq->lock);
}
/**
- * drm_sched_rq_select_entity - Select an entity which could provide a job to run
+ * drm_sched_rq_select_entity_rr - Select an entity which could provide a job to run
*
* @rq: scheduler run queue to check.
*
* Try to find a ready entity, returns NULL if none found.
*/
static struct drm_sched_entity *
-drm_sched_rq_select_entity(struct drm_sched_rq *rq)
+drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq)
{
struct drm_sched_entity *entity;
@@ -164,6 +224,34 @@ drm_sched_rq_select_entity(struct drm_sched_rq *rq)
}
/**
+ * drm_sched_rq_select_entity_fifo - Select an entity which provides a job to run
+ *
+ * @rq: scheduler run queue to check.
+ *
+ * Find oldest waiting ready entity, returns NULL if none found.
+ */
+static struct drm_sched_entity *
+drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq)
+{
+ struct rb_node *rb;
+
+ spin_lock(&rq->lock);
+ for (rb = rb_first_cached(&rq->rb_tree_root); rb; rb = rb_next(rb)) {
+ struct drm_sched_entity *entity;
+
+ entity = rb_entry(rb, struct drm_sched_entity, rb_tree_node);
+ if (drm_sched_entity_is_ready(entity)) {
+ rq->current_entity = entity;
+ reinit_completion(&entity->entity_idle);
+ break;
+ }
+ }
+ spin_unlock(&rq->lock);
+
+ return rb ? rb_entry(rb, struct drm_sched_entity, rb_tree_node) : NULL;
+}
+
+/**
* drm_sched_job_done - complete a job
* @s_job: pointer to the job which is done
*
@@ -198,32 +286,6 @@ static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb)
}
/**
- * drm_sched_dependency_optimized - test if the dependency can be optimized
- *
- * @fence: the dependency fence
- * @entity: the entity which depends on the above fence
- *
- * Returns true if the dependency can be optimized and false otherwise
- */
-bool drm_sched_dependency_optimized(struct dma_fence* fence,
- struct drm_sched_entity *entity)
-{
- struct drm_gpu_scheduler *sched = entity->rq->sched;
- struct drm_sched_fence *s_fence;
-
- if (!fence || dma_fence_is_signaled(fence))
- return false;
- if (fence->context == entity->fence_context)
- return true;
- s_fence = to_drm_sched_fence(fence);
- if (s_fence && s_fence->sched == sched)
- return true;
-
- return false;
-}
-EXPORT_SYMBOL(drm_sched_dependency_optimized);
-
-/**
* drm_sched_start_timeout - start timeout for reset worker
*
* @sched: scheduler instance to start the worker for
@@ -355,27 +417,6 @@ static void drm_sched_job_timedout(struct work_struct *work)
}
}
- /**
- * drm_sched_increase_karma - Update sched_entity guilty flag
- *
- * @bad: The job guilty of time out
- *
- * Increment on every hang caused by the 'bad' job. If this exceeds the hang
- * limit of the scheduler then the respective sched entity is marked guilty and
- * jobs from it will not be scheduled further
- */
-void drm_sched_increase_karma(struct drm_sched_job *bad)
-{
- drm_sched_increase_karma_ext(bad, 1);
-}
-EXPORT_SYMBOL(drm_sched_increase_karma);
-
-void drm_sched_reset_karma(struct drm_sched_job *bad)
-{
- drm_sched_increase_karma_ext(bad, 0);
-}
-EXPORT_SYMBOL(drm_sched_reset_karma);
-
/**
* drm_sched_stop - stop the scheduler
*
@@ -517,31 +558,14 @@ EXPORT_SYMBOL(drm_sched_start);
*/
void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
{
- drm_sched_resubmit_jobs_ext(sched, INT_MAX);
-}
-EXPORT_SYMBOL(drm_sched_resubmit_jobs);
-
-/**
- * drm_sched_resubmit_jobs_ext - helper to relunch certain number of jobs from mirror ring list
- *
- * @sched: scheduler instance
- * @max: job numbers to relaunch
- *
- */
-void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max)
-{
struct drm_sched_job *s_job, *tmp;
uint64_t guilty_context;
bool found_guilty = false;
struct dma_fence *fence;
- int i = 0;
list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
struct drm_sched_fence *s_fence = s_job->s_fence;
- if (i >= max)
- break;
-
if (!found_guilty && atomic_read(&s_job->karma) > sched->hang_limit) {
found_guilty = true;
guilty_context = s_job->s_fence->scheduled.context;
@@ -551,7 +575,6 @@ void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max)
dma_fence_set_error(&s_fence->finished, -ECANCELED);
fence = sched->ops->run_job(s_job);
- i++;
if (IS_ERR_OR_NULL(fence)) {
if (IS_ERR(fence))
@@ -567,7 +590,7 @@ void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max)
}
}
}
-EXPORT_SYMBOL(drm_sched_resubmit_jobs_ext);
+EXPORT_SYMBOL(drm_sched_resubmit_jobs);
/**
* drm_sched_job_init - init a scheduler job
@@ -685,32 +708,28 @@ int drm_sched_job_add_dependency(struct drm_sched_job *job,
EXPORT_SYMBOL(drm_sched_job_add_dependency);
/**
- * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job
- * dependencies
+ * drm_sched_job_add_resv_dependencies - add all fences from the resv to the job
* @job: scheduler job to add the dependencies to
- * @obj: the gem object to add new dependencies from.
- * @write: whether the job might write the object (so we need to depend on
- * shared fences in the reservation object).
+ * @resv: the dma_resv object to get the fences from
+ * @usage: the dma_resv_usage to use to filter the fences
*
- * This should be called after drm_gem_lock_reservations() on your array of
- * GEM objects used in the job but before updating the reservations with your
- * own fences.
+ * This adds all fences matching the given usage from @resv to @job.
+ * Must be called with the @resv lock held.
*
* Returns:
* 0 on success, or an error on failing to expand the array.
*/
-int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
- struct drm_gem_object *obj,
- bool write)
+int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job,
+ struct dma_resv *resv,
+ enum dma_resv_usage usage)
{
struct dma_resv_iter cursor;
struct dma_fence *fence;
int ret;
- dma_resv_assert_held(obj->resv);
+ dma_resv_assert_held(resv);
- dma_resv_for_each_fence(&cursor, obj->resv, dma_resv_usage_rw(write),
- fence) {
+ dma_resv_for_each_fence(&cursor, resv, usage, fence) {
/* Make sure to grab an additional ref on the added fence */
dma_fence_get(fence);
ret = drm_sched_job_add_dependency(job, fence);
@@ -721,8 +740,31 @@ int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
}
return 0;
}
-EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies);
+EXPORT_SYMBOL(drm_sched_job_add_resv_dependencies);
+/**
+ * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job
+ * dependencies
+ * @job: scheduler job to add the dependencies to
+ * @obj: the gem object to add new dependencies from.
+ * @write: whether the job might write the object (so we need to depend on
+ * shared fences in the reservation object).
+ *
+ * This should be called after drm_gem_lock_reservations() on your array of
+ * GEM objects used in the job but before updating the reservations with your
+ * own fences.
+ *
+ * Returns:
+ * 0 on success, or an error on failing to expand the array.
+ */
+int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
+ struct drm_gem_object *obj,
+ bool write)
+{
+ return drm_sched_job_add_resv_dependencies(job, obj->resv,
+ dma_resv_usage_rw(write));
+}
+EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies);
/**
* drm_sched_job_cleanup - clean up scheduler job resources
@@ -803,7 +845,9 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched)
/* Kernel run queue has higher priority than normal run queue*/
for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
- entity = drm_sched_rq_select_entity(&sched->sched_rq[i]);
+ entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ?
+ drm_sched_rq_select_entity_fifo(&sched->sched_rq[i]) :
+ drm_sched_rq_select_entity_rr(&sched->sched_rq[i]);
if (entity)
break;
}
@@ -1082,13 +1126,15 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
EXPORT_SYMBOL(drm_sched_fini);
/**
- * drm_sched_increase_karma_ext - Update sched_entity guilty flag
+ * drm_sched_increase_karma - Update sched_entity guilty flag
*
* @bad: The job guilty of time out
- * @type: type for increase/reset karma
*
+ * Increment on every hang caused by the 'bad' job. If this exceeds the hang
+ * limit of the scheduler then the respective sched entity is marked guilty and
+ * jobs from it will not be scheduled further
*/
-void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type)
+void drm_sched_increase_karma(struct drm_sched_job *bad)
{
int i;
struct drm_sched_entity *tmp;
@@ -1100,10 +1146,7 @@ void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type)
* corrupt but keep in mind that kernel jobs always considered good.
*/
if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
- if (type == 0)
- atomic_set(&bad->karma, 0);
- else if (type == 1)
- atomic_inc(&bad->karma);
+ atomic_inc(&bad->karma);
for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL;
i++) {
@@ -1114,7 +1157,7 @@ void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type)
if (bad->s_fence->scheduled.context ==
entity->fence_context) {
if (entity->guilty)
- atomic_set(entity->guilty, type);
+ atomic_set(entity->guilty, 1);
break;
}
}
@@ -1124,4 +1167,4 @@ void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type)
}
}
}
-EXPORT_SYMBOL(drm_sched_increase_karma_ext);
+EXPORT_SYMBOL(drm_sched_increase_karma);
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index bc41a5ae810a..53464afc2b9a 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -20,9 +20,10 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -578,21 +579,24 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_atomic_helper_damage_iter iter;
struct drm_device *drm = plane->dev;
- struct drm_rect src_clip, dst_clip;
+ struct drm_rect dst_clip;
+ struct drm_rect damage;
int idx;
- if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
+ if (!drm_dev_enter(drm, &idx))
return;
- dst_clip = plane_state->dst;
- if (!drm_rect_intersect(&dst_clip, &src_clip))
- return;
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ dst_clip = plane_state->dst;
- if (!drm_dev_enter(drm, &idx))
- return;
+ if (!drm_rect_intersect(&dst_clip, &damage))
+ continue;
- ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
+ ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
+ }
drm_dev_exit(idx);
}
@@ -642,19 +646,6 @@ static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc
return MODE_OK;
}
-static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *new_state)
-{
- struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
- int ret;
-
- ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false);
- if (ret)
- return ret;
-
- return drm_atomic_add_affected_planes(new_state, crtc);
-}
-
/*
* The CRTC is always enabled. Screen updates are performed by
* the primary plane's atomic_update function. Disabling clears
@@ -662,7 +653,7 @@ static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc,
*/
static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = {
.mode_valid = ssd130x_crtc_helper_mode_valid,
- .atomic_check = ssd130x_crtc_helper_atomic_check,
+ .atomic_check = drm_crtc_helper_atomic_check,
};
static void ssd130x_crtc_reset(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 7abf010a3293..ef6a4e63198f 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -14,7 +14,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index b6ee8a82e656..f3a5616b7daf 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -288,7 +288,7 @@ static void sti_dvo_set_mode(struct drm_bridge *bridge,
DRM_DEBUG_DRIVER("\n");
- memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
+ drm_mode_copy(&dvo->mode, mode);
/* According to the path used (main or aux), the dvo clocks should
* have a different parent clock. */
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 03cc401ed593..ec6656b9ee7c 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -524,7 +524,7 @@ static void sti_hda_set_mode(struct drm_bridge *bridge,
DRM_DEBUG_DRIVER("\n");
- memcpy(&hda->mode, mode, sizeof(struct drm_display_mode));
+ drm_mode_copy(&hda->mode, mode);
if (!hda_get_mode_idx(hda->mode, &mode_idx)) {
DRM_ERROR("Undefined mode\n");
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index cb82622877d2..fcc2194869d6 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -941,7 +941,7 @@ static void sti_hdmi_set_mode(struct drm_bridge *bridge,
DRM_DEBUG_DRIVER("\n");
/* Copy the drm display mode in the connector local structure */
- memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
+ drm_mode_copy(&hdmi->mode, mode);
/* Update clock framerate according to the selected mode */
ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index d7914f5122df..50410bd99dfe 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -18,7 +18,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index d06ffd99d86e..cc94efbbf2d4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -17,7 +17,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 34234a144e87..760ff05eabf4 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -1101,12 +1101,16 @@ static const struct component_ops sun6i_dsi_ops = {
static int sun6i_dsi_probe(struct platform_device *pdev)
{
+ const struct sun6i_dsi_variant *variant;
struct device *dev = &pdev->dev;
- const char *bus_clk_name = NULL;
struct sun6i_dsi *dsi;
void __iomem *base;
int ret;
+ variant = device_get_match_data(dev);
+ if (!variant)
+ return -EINVAL;
+
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
if (!dsi)
return -ENOMEM;
@@ -1114,10 +1118,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
dsi->dev = dev;
dsi->host.ops = &sun6i_dsi_host_ops;
dsi->host.dev = dev;
-
- if (of_device_is_compatible(dev->of_node,
- "allwinner,sun6i-a31-mipi-dsi"))
- bus_clk_name = "bus";
+ dsi->variant = variant;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
@@ -1142,7 +1143,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
return PTR_ERR(dsi->regs);
}
- dsi->bus_clk = devm_clk_get(dev, bus_clk_name);
+ dsi->bus_clk = devm_clk_get(dev, variant->has_mod_clk ? "bus" : NULL);
if (IS_ERR(dsi->bus_clk))
return dev_err_probe(dev, PTR_ERR(dsi->bus_clk),
"Couldn't get the DSI bus clock\n");
@@ -1151,21 +1152,21 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (of_device_is_compatible(dev->of_node,
- "allwinner,sun6i-a31-mipi-dsi")) {
+ if (variant->has_mod_clk) {
dsi->mod_clk = devm_clk_get(dev, "mod");
if (IS_ERR(dsi->mod_clk)) {
dev_err(dev, "Couldn't get the DSI mod clock\n");
ret = PTR_ERR(dsi->mod_clk);
goto err_attach_clk;
}
- }
- /*
- * In order to operate properly, that clock seems to be always
- * set to 297MHz.
- */
- clk_set_rate_exclusive(dsi->mod_clk, 297000000);
+ /*
+ * In order to operate properly, the module clock on the
+ * A31 variant always seems to be set to 297MHz.
+ */
+ if (variant->set_mod_clk)
+ clk_set_rate_exclusive(dsi->mod_clk, 297000000);
+ }
dsi->dphy = devm_phy_get(dev, "dphy");
if (IS_ERR(dsi->dphy)) {
@@ -1191,7 +1192,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
err_remove_dsi_host:
mipi_dsi_host_unregister(&dsi->host);
err_unprotect_clk:
- clk_rate_exclusive_put(dsi->mod_clk);
+ if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk)
+ clk_rate_exclusive_put(dsi->mod_clk);
err_attach_clk:
regmap_mmio_detach_clk(dsi->regs);
@@ -1205,16 +1207,39 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
component_del(&pdev->dev, &sun6i_dsi_ops);
mipi_dsi_host_unregister(&dsi->host);
- clk_rate_exclusive_put(dsi->mod_clk);
+ if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk)
+ clk_rate_exclusive_put(dsi->mod_clk);
regmap_mmio_detach_clk(dsi->regs);
return 0;
}
+static const struct sun6i_dsi_variant sun6i_a31_mipi_dsi_variant = {
+ .has_mod_clk = true,
+ .set_mod_clk = true,
+};
+
+static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = {
+};
+
+static const struct sun6i_dsi_variant sun50i_a100_mipi_dsi_variant = {
+ .has_mod_clk = true,
+};
+
static const struct of_device_id sun6i_dsi_of_table[] = {
- { .compatible = "allwinner,sun6i-a31-mipi-dsi" },
- { .compatible = "allwinner,sun50i-a64-mipi-dsi" },
+ {
+ .compatible = "allwinner,sun6i-a31-mipi-dsi",
+ .data = &sun6i_a31_mipi_dsi_variant,
+ },
+ {
+ .compatible = "allwinner,sun50i-a64-mipi-dsi",
+ .data = &sun50i_a64_mipi_dsi_variant,
+ },
+ {
+ .compatible = "allwinner,sun50i-a100-mipi-dsi",
+ .data = &sun50i_a100_mipi_dsi_variant,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index c863900ae3b4..f1ddefe0f554 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -15,6 +15,11 @@
#define SUN6I_DSI_TCON_DIV 4
+struct sun6i_dsi_variant {
+ bool has_mod_clk;
+ bool set_mod_clk;
+};
+
struct sun6i_dsi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -31,6 +36,8 @@ struct sun6i_dsi {
struct mipi_dsi_device *device;
struct drm_device *drm;
struct drm_panel *panel;
+
+ const struct sun6i_dsi_variant *variant;
};
static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index df6cc986aeba..bb0d2c144b55 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -24,7 +24,8 @@ tegra-drm-y := \
gr3d.o \
falcon.o \
vic.o \
- nvdec.o
+ nvdec.o \
+ riscv.o
tegra-drm-y += trace.o
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index bd0f60704467..a67453cee883 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -3205,8 +3205,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
usleep_range(2000, 4000);
err = reset_control_assert(dc->rst);
- if (err < 0)
+ if (err < 0) {
+ clk_disable_unprepare(dc->clk);
return err;
+ }
usleep_range(2000, 4000);
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 6748ec1e0005..7bd2e65c2a16 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1093,6 +1093,10 @@ static bool host1x_drm_wants_iommu(struct host1x_device *dev)
struct host1x *host1x = dev_get_drvdata(dev->dev.parent);
struct iommu_domain *domain;
+ /* Our IOMMU usage policy doesn't currently play well with GART */
+ if (of_machine_is_compatible("nvidia,tegra20"))
+ return false;
+
/*
* If the Tegra DRM clients are backed by an IOMMU, push buffers are
* likely to be allocated beyond the 32-bit boundary if sufficient
@@ -1382,6 +1386,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra194-vic", },
{ .compatible = "nvidia,tegra194-nvdec", },
{ .compatible = "nvidia,tegra234-vic", },
+ { .compatible = "nvidia,tegra234-nvdec", },
{ /* sentinel */ }
};
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 9291209154a7..a900300ae5bd 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -206,6 +206,8 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static const struct fb_ops tegra_fb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_read = drm_fb_helper_sys_read,
+ .fb_write = drm_fb_helper_sys_write,
.fb_fillrect = drm_fb_helper_sys_fillrect,
.fb_copyarea = drm_fb_helper_sys_copyarea,
.fb_imageblit = drm_fb_helper_sys_imageblit,
@@ -243,7 +245,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
if (IS_ERR(bo))
return PTR_ERR(bo);
- info = drm_fb_helper_alloc_fbi(helper);
+ info = drm_fb_helper_alloc_info(helper);
if (IS_ERR(info)) {
dev_err(drm->dev, "failed to allocate framebuffer info\n");
drm_gem_object_put(&bo->gem);
@@ -261,7 +263,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
fb = fbdev->fb;
helper->fb = fb;
- helper->fbdev = info;
+ helper->info = info;
info->fbops = &tegra_fb_ops;
@@ -280,7 +282,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
}
}
- drm->mode_config.fb_base = (resource_size_t)bo->iova;
info->screen_base = (void __iomem *)bo->vaddr + offset;
info->screen_size = size;
info->fix.smem_start = (unsigned long)(bo->iova + offset);
@@ -348,7 +349,7 @@ fini:
static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
{
- drm_fb_helper_unregister_fbi(&fbdev->base);
+ drm_fb_helper_unregister_info(&fbdev->base);
if (fbdev->fb) {
struct tegra_bo *bo = tegra_fb_get_plane(fbdev->fb, 0);
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 81991090adcc..979e7bc902f6 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -84,7 +84,7 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_
goto free;
}
- map->sgt = dma_buf_map_attachment(map->attach, direction);
+ map->sgt = dma_buf_map_attachment_unlocked(map->attach, direction);
if (IS_ERR(map->sgt)) {
dma_buf_detach(buf, map->attach);
err = PTR_ERR(map->sgt);
@@ -160,7 +160,8 @@ free:
static void tegra_bo_unpin(struct host1x_bo_mapping *map)
{
if (map->attach) {
- dma_buf_unmap_attachment(map->attach, map->sgt, map->direction);
+ dma_buf_unmap_attachment_unlocked(map->attach, map->sgt,
+ map->direction);
dma_buf_detach(map->attach->dmabuf, map->attach);
} else {
dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0);
@@ -181,7 +182,7 @@ static void *tegra_bo_mmap(struct host1x_bo *bo)
if (obj->vaddr) {
return obj->vaddr;
} else if (obj->gem.import_attach) {
- ret = dma_buf_vmap(obj->gem.import_attach->dmabuf, &map);
+ ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map);
return ret ? NULL : map.vaddr;
} else {
return vmap(obj->pages, obj->num_pages, VM_MAP,
@@ -197,7 +198,7 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr)
if (obj->vaddr)
return;
else if (obj->gem.import_attach)
- dma_buf_vunmap(obj->gem.import_attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map);
else
vunmap(addr);
}
@@ -461,7 +462,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
get_dma_buf(buf);
- bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
+ bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE);
if (IS_ERR(bo->sgt)) {
err = PTR_ERR(bo->sgt);
goto detach;
@@ -479,7 +480,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
detach:
if (!IS_ERR_OR_NULL(bo->sgt))
- dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE);
+ dma_buf_unmap_attachment_unlocked(attach, bo->sgt, DMA_TO_DEVICE);
dma_buf_detach(buf, attach);
dma_buf_put(buf);
@@ -508,8 +509,8 @@ void tegra_bo_free_object(struct drm_gem_object *gem)
tegra_bo_iommu_unmap(tegra, bo);
if (gem->import_attach) {
- dma_buf_unmap_attachment(gem->import_attach, bo->sgt,
- DMA_TO_DEVICE);
+ dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt,
+ DMA_TO_DEVICE);
drm_prime_gem_destroy(gem, NULL);
} else {
tegra_bo_free(gem->dev, bo);
@@ -693,6 +694,8 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
struct drm_gem_object *gem = buf->priv;
int err;
+ dma_resv_assert_held(buf->resv);
+
err = drm_gem_mmap_obj(gem, gem->size, vma);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index bf240767dad9..40ec3e6cf204 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -867,14 +867,7 @@ static int tegra_hdmi_reconfigure_audio(struct tegra_hdmi *hdmi)
static bool tegra_output_is_hdmi(struct tegra_output *output)
{
- struct edid *edid;
-
- if (!output->connector.edid_blob_ptr)
- return false;
-
- edid = (struct edid *)output->connector.edid_blob_ptr->data;
-
- return drm_detect_hdmi_monitor(edid);
+ return output->connector.display_info.is_hdmi;
}
static enum drm_connector_status
diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c
index 276fe0472730..10fd21517281 100644
--- a/drivers/gpu/drm/tegra/nvdec.c
+++ b/drivers/gpu/drm/tegra/nvdec.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2021, NVIDIA Corporation.
+ * Copyright (c) 2015-2022, NVIDIA Corporation.
*/
#include <linux/clk.h>
@@ -8,6 +8,7 @@
#include <linux/dma-mapping.h>
#include <linux/host1x.h>
#include <linux/iommu.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -16,18 +17,22 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <soc/tegra/pmc.h>
+#include <soc/tegra/mc.h>
#include "drm.h"
#include "falcon.h"
+#include "riscv.h"
#include "vic.h"
+#define NVDEC_FALCON_DEBUGINFO 0x1094
#define NVDEC_TFBIF_TRANSCFG 0x2c44
struct nvdec_config {
const char *firmware;
unsigned int version;
bool supports_sid;
+ bool has_riscv;
+ bool has_extra_clocks;
};
struct nvdec {
@@ -37,10 +42,16 @@ struct nvdec {
struct tegra_drm_client client;
struct host1x_channel *channel;
struct device *dev;
- struct clk *clk;
+ struct clk_bulk_data clks[3];
+ unsigned int num_clks;
+ struct reset_control *reset;
/* Platform configuration */
const struct nvdec_config *config;
+
+ /* RISC-V specific data */
+ struct tegra_drm_riscv riscv;
+ phys_addr_t carveout_base;
};
static inline struct nvdec *to_nvdec(struct tegra_drm_client *client)
@@ -54,7 +65,7 @@ static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
writel(value, nvdec->regs + offset);
}
-static int nvdec_boot(struct nvdec *nvdec)
+static int nvdec_boot_falcon(struct nvdec *nvdec)
{
#ifdef CONFIG_IOMMU_API
struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev);
@@ -90,6 +101,64 @@ static int nvdec_boot(struct nvdec *nvdec)
return 0;
}
+static int nvdec_wait_debuginfo(struct nvdec *nvdec, const char *phase)
+{
+ int err;
+ u32 val;
+
+ err = readl_poll_timeout(nvdec->regs + NVDEC_FALCON_DEBUGINFO, val, val == 0x0, 10, 100000);
+ if (err) {
+ dev_err(nvdec->dev, "failed to boot %s, debuginfo=0x%x\n", phase, val);
+ return err;
+ }
+
+ return 0;
+}
+
+static int nvdec_boot_riscv(struct nvdec *nvdec)
+{
+ int err;
+
+ err = reset_control_acquire(nvdec->reset);
+ if (err)
+ return err;
+
+ nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO);
+
+ err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1,
+ &nvdec->riscv.bl_desc);
+ if (err) {
+ dev_err(nvdec->dev, "failed to execute bootloader\n");
+ goto release_reset;
+ }
+
+ err = nvdec_wait_debuginfo(nvdec, "bootloader");
+ if (err)
+ goto release_reset;
+
+ err = reset_control_reset(nvdec->reset);
+ if (err)
+ goto release_reset;
+
+ nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO);
+
+ err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1,
+ &nvdec->riscv.os_desc);
+ if (err) {
+ dev_err(nvdec->dev, "failed to execute firmware\n");
+ goto release_reset;
+ }
+
+ err = nvdec_wait_debuginfo(nvdec, "firmware");
+ if (err)
+ goto release_reset;
+
+release_reset:
+ reset_control_release(nvdec->reset);
+
+ return err;
+}
+
static int nvdec_init(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
@@ -189,7 +258,7 @@ static const struct host1x_client_ops nvdec_client_ops = {
.exit = nvdec_exit,
};
-static int nvdec_load_firmware(struct nvdec *nvdec)
+static int nvdec_load_falcon_firmware(struct nvdec *nvdec)
{
struct host1x_client *client = &nvdec->client.base;
struct tegra_drm *tegra = nvdec->client.drm;
@@ -252,30 +321,35 @@ cleanup:
return err;
}
-
static __maybe_unused int nvdec_runtime_resume(struct device *dev)
{
struct nvdec *nvdec = dev_get_drvdata(dev);
int err;
- err = clk_prepare_enable(nvdec->clk);
+ err = clk_bulk_prepare_enable(nvdec->num_clks, nvdec->clks);
if (err < 0)
return err;
usleep_range(10, 20);
- err = nvdec_load_firmware(nvdec);
- if (err < 0)
- goto disable;
+ if (nvdec->config->has_riscv) {
+ err = nvdec_boot_riscv(nvdec);
+ if (err < 0)
+ goto disable;
+ } else {
+ err = nvdec_load_falcon_firmware(nvdec);
+ if (err < 0)
+ goto disable;
- err = nvdec_boot(nvdec);
- if (err < 0)
- goto disable;
+ err = nvdec_boot_falcon(nvdec);
+ if (err < 0)
+ goto disable;
+ }
return 0;
disable:
- clk_disable_unprepare(nvdec->clk);
+ clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
return err;
}
@@ -285,7 +359,7 @@ static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
host1x_channel_stop(nvdec->channel);
- clk_disable_unprepare(nvdec->clk);
+ clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
return 0;
}
@@ -346,10 +420,18 @@ static const struct nvdec_config nvdec_t194_config = {
.supports_sid = true,
};
+static const struct nvdec_config nvdec_t234_config = {
+ .version = 0x23,
+ .supports_sid = true,
+ .has_riscv = true,
+ .has_extra_clocks = true,
+};
+
static const struct of_device_id tegra_nvdec_of_match[] = {
{ .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config },
{ .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config },
{ .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config },
+ { .compatible = "nvidia,tegra234-nvdec", .data = &nvdec_t234_config },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match);
@@ -383,13 +465,22 @@ static int nvdec_probe(struct platform_device *pdev)
if (IS_ERR(nvdec->regs))
return PTR_ERR(nvdec->regs);
- nvdec->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(nvdec->clk)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- return PTR_ERR(nvdec->clk);
+ nvdec->clks[0].id = "nvdec";
+ nvdec->num_clks = 1;
+
+ if (nvdec->config->has_extra_clocks) {
+ nvdec->num_clks = 3;
+ nvdec->clks[1].id = "fuse";
+ nvdec->clks[2].id = "tsec_pka";
}
- err = clk_set_rate(nvdec->clk, ULONG_MAX);
+ err = devm_clk_bulk_get(dev, nvdec->num_clks, nvdec->clks);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get clock(s)\n");
+ return err;
+ }
+
+ err = clk_set_rate(nvdec->clks[0].clk, ULONG_MAX);
if (err < 0) {
dev_err(&pdev->dev, "failed to set clock rate\n");
return err;
@@ -399,12 +490,42 @@ static int nvdec_probe(struct platform_device *pdev)
if (err < 0)
host_class = HOST1X_CLASS_NVDEC;
- nvdec->falcon.dev = dev;
- nvdec->falcon.regs = nvdec->regs;
+ if (nvdec->config->has_riscv) {
+ struct tegra_mc *mc;
- err = falcon_init(&nvdec->falcon);
- if (err < 0)
- return err;
+ mc = devm_tegra_memory_controller_get(dev);
+ if (IS_ERR(mc)) {
+ dev_err_probe(dev, PTR_ERR(mc),
+ "failed to get memory controller handle\n");
+ return PTR_ERR(mc);
+ }
+
+ err = tegra_mc_get_carveout_info(mc, 1, &nvdec->carveout_base, NULL);
+ if (err) {
+ dev_err(dev, "failed to get carveout info: %d\n", err);
+ return err;
+ }
+
+ nvdec->reset = devm_reset_control_get_exclusive_released(dev, "nvdec");
+ if (IS_ERR(nvdec->reset)) {
+ dev_err_probe(dev, PTR_ERR(nvdec->reset), "failed to get reset\n");
+ return PTR_ERR(nvdec->reset);
+ }
+
+ nvdec->riscv.dev = dev;
+ nvdec->riscv.regs = nvdec->regs;
+
+ err = tegra_drm_riscv_read_descriptors(&nvdec->riscv);
+ if (err < 0)
+ return err;
+ } else {
+ nvdec->falcon.dev = dev;
+ nvdec->falcon.regs = nvdec->regs;
+
+ err = falcon_init(&nvdec->falcon);
+ if (err < 0)
+ return err;
+ }
platform_set_drvdata(pdev, nvdec);
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 47d26b5d9945..a8925dcd7edd 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -133,11 +133,11 @@ int tegra_output_probe(struct tegra_output *output)
}
}
- output->hpd_gpio = devm_gpiod_get_from_of_node(output->dev,
- output->of_node,
- "nvidia,hpd-gpio", 0,
- GPIOD_IN,
- "HDMI hotplug detect");
+ output->hpd_gpio = devm_fwnode_gpiod_get(output->dev,
+ of_fwnode_handle(output->of_node),
+ "nvidia,hpd",
+ GPIOD_IN,
+ "HDMI hotplug detect");
if (IS_ERR(output->hpd_gpio)) {
if (PTR_ERR(output->hpd_gpio) != -ENOENT)
return PTR_ERR(output->hpd_gpio);
diff --git a/drivers/gpu/drm/tegra/riscv.c b/drivers/gpu/drm/tegra/riscv.c
new file mode 100644
index 000000000000..6580416408f8
--- /dev/null
+++ b/drivers/gpu/drm/tegra/riscv.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, NVIDIA Corporation.
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+
+#include "riscv.h"
+
+#define RISCV_CPUCTL 0x4388
+#define RISCV_CPUCTL_STARTCPU_TRUE (1 << 0)
+#define RISCV_BR_RETCODE 0x465c
+#define RISCV_BR_RETCODE_RESULT_V(x) ((x) & 0x3)
+#define RISCV_BR_RETCODE_RESULT_PASS_V 3
+#define RISCV_BCR_CTRL 0x4668
+#define RISCV_BCR_CTRL_CORE_SELECT_RISCV (1 << 4)
+#define RISCV_BCR_DMACFG 0x466c
+#define RISCV_BCR_DMACFG_TARGET_LOCAL_FB (0 << 0)
+#define RISCV_BCR_DMACFG_LOCK_LOCKED (1 << 31)
+#define RISCV_BCR_DMAADDR_PKCPARAM_LO 0x4670
+#define RISCV_BCR_DMAADDR_PKCPARAM_HI 0x4674
+#define RISCV_BCR_DMAADDR_FMCCODE_LO 0x4678
+#define RISCV_BCR_DMAADDR_FMCCODE_HI 0x467c
+#define RISCV_BCR_DMAADDR_FMCDATA_LO 0x4680
+#define RISCV_BCR_DMAADDR_FMCDATA_HI 0x4684
+#define RISCV_BCR_DMACFG_SEC 0x4694
+#define RISCV_BCR_DMACFG_SEC_GSCID(v) ((v) << 16)
+
+static void riscv_writel(struct tegra_drm_riscv *riscv, u32 value, u32 offset)
+{
+ writel(value, riscv->regs + offset);
+}
+
+int tegra_drm_riscv_read_descriptors(struct tegra_drm_riscv *riscv)
+{
+ struct tegra_drm_riscv_descriptor *bl = &riscv->bl_desc;
+ struct tegra_drm_riscv_descriptor *os = &riscv->os_desc;
+ const struct device_node *np = riscv->dev->of_node;
+ int err;
+
+#define READ_PROP(name, location) \
+ err = of_property_read_u32(np, name, location); \
+ if (err) { \
+ dev_err(riscv->dev, "failed to read " name ": %d\n", err); \
+ return err; \
+ }
+
+ READ_PROP("nvidia,bl-manifest-offset", &bl->manifest_offset);
+ READ_PROP("nvidia,bl-code-offset", &bl->code_offset);
+ READ_PROP("nvidia,bl-data-offset", &bl->data_offset);
+ READ_PROP("nvidia,os-manifest-offset", &os->manifest_offset);
+ READ_PROP("nvidia,os-code-offset", &os->code_offset);
+ READ_PROP("nvidia,os-data-offset", &os->data_offset);
+#undef READ_PROP
+
+ if (bl->manifest_offset == 0 && bl->code_offset == 0 &&
+ bl->data_offset == 0 && os->manifest_offset == 0 &&
+ os->code_offset == 0 && os->data_offset == 0) {
+ dev_err(riscv->dev, "descriptors not available\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int tegra_drm_riscv_boot_bootrom(struct tegra_drm_riscv *riscv, phys_addr_t image_address,
+ u32 gscid, const struct tegra_drm_riscv_descriptor *desc)
+{
+ phys_addr_t addr;
+ int err;
+ u32 val;
+
+ riscv_writel(riscv, RISCV_BCR_CTRL_CORE_SELECT_RISCV, RISCV_BCR_CTRL);
+
+ addr = image_address + desc->manifest_offset;
+ riscv_writel(riscv, lower_32_bits(addr >> 8), RISCV_BCR_DMAADDR_PKCPARAM_LO);
+ riscv_writel(riscv, upper_32_bits(addr >> 8), RISCV_BCR_DMAADDR_PKCPARAM_HI);
+
+ addr = image_address + desc->code_offset;
+ riscv_writel(riscv, lower_32_bits(addr >> 8), RISCV_BCR_DMAADDR_FMCCODE_LO);
+ riscv_writel(riscv, upper_32_bits(addr >> 8), RISCV_BCR_DMAADDR_FMCCODE_HI);
+
+ addr = image_address + desc->data_offset;
+ riscv_writel(riscv, lower_32_bits(addr >> 8), RISCV_BCR_DMAADDR_FMCDATA_LO);
+ riscv_writel(riscv, upper_32_bits(addr >> 8), RISCV_BCR_DMAADDR_FMCDATA_HI);
+
+ riscv_writel(riscv, RISCV_BCR_DMACFG_SEC_GSCID(gscid), RISCV_BCR_DMACFG_SEC);
+ riscv_writel(riscv,
+ RISCV_BCR_DMACFG_TARGET_LOCAL_FB | RISCV_BCR_DMACFG_LOCK_LOCKED, RISCV_BCR_DMACFG);
+
+ riscv_writel(riscv, RISCV_CPUCTL_STARTCPU_TRUE, RISCV_CPUCTL);
+
+ err = readl_poll_timeout(
+ riscv->regs + RISCV_BR_RETCODE, val,
+ RISCV_BR_RETCODE_RESULT_V(val) == RISCV_BR_RETCODE_RESULT_PASS_V,
+ 10, 100000);
+ if (err) {
+ dev_err(riscv->dev, "error during bootrom execution. BR_RETCODE=%d\n", val);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/tegra/riscv.h b/drivers/gpu/drm/tegra/riscv.h
new file mode 100644
index 000000000000..bbeb2db078b6
--- /dev/null
+++ b/drivers/gpu/drm/tegra/riscv.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, NVIDIA Corporation.
+ */
+
+#ifndef DRM_TEGRA_RISCV_H
+#define DRM_TEGRA_RISCV_H
+
+struct tegra_drm_riscv_descriptor {
+ u32 manifest_offset;
+ u32 code_offset;
+ u32 code_size;
+ u32 data_offset;
+ u32 data_size;
+};
+
+struct tegra_drm_riscv {
+ /* User initializes */
+ struct device *dev;
+ void __iomem *regs;
+
+ struct tegra_drm_riscv_descriptor bl_desc;
+ struct tegra_drm_riscv_descriptor os_desc;
+};
+
+int tegra_drm_riscv_read_descriptors(struct tegra_drm_riscv *riscv);
+int tegra_drm_riscv_boot_bootrom(struct tegra_drm_riscv *riscv, phys_addr_t image_address,
+ u32 gscid, const struct tegra_drm_riscv_descriptor *desc);
+
+#endif
diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c
index b24738bdf3df..066f88564169 100644
--- a/drivers/gpu/drm/tegra/submit.c
+++ b/drivers/gpu/drm/tegra/submit.c
@@ -133,7 +133,7 @@ static void gather_bo_munmap(struct host1x_bo *host_bo, void *addr)
{
}
-const struct host1x_bo_ops gather_bo_ops = {
+static const struct host1x_bo_ops gather_bo_ops = {
.get = gather_bo_get,
.put = gather_bo_put,
.pin = gather_bo_pin,
@@ -169,14 +169,9 @@ static void *alloc_copy_user_array(void __user *from, size_t count, size_t size)
if (copy_len > 0x4000)
return ERR_PTR(-E2BIG);
- data = kvmalloc(copy_len, GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
-
- if (copy_from_user(data, from, copy_len)) {
- kvfree(data);
- return ERR_PTR(-EFAULT);
- }
+ data = vmemdup_user(from, copy_len);
+ if (IS_ERR(data))
+ return ERR_CAST(data);
return data;
}
diff --git a/drivers/gpu/drm/tegra/uapi.c b/drivers/gpu/drm/tegra/uapi.c
index a98239cb0e29..5adab6b22916 100644
--- a/drivers/gpu/drm/tegra/uapi.c
+++ b/drivers/gpu/drm/tegra/uapi.c
@@ -116,7 +116,7 @@ int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data, struct drm_
if (supported)
context->memory_context = host1x_memory_context_alloc(
- host, get_task_pid(current, PIDTYPE_TGID));
+ host, client->base.dev, get_task_pid(current, PIDTYPE_TGID));
if (IS_ERR(context->memory_context)) {
if (PTR_ERR(context->memory_context) != -EOPNOTSUPP) {
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 91b70f7d2769..b29ef1085cad 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -1,5 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \
- drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \
- drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o
+obj-$(CONFIG_DRM_KUNIT_TEST) += \
+ drm_buddy_test.o \
+ drm_cmdline_parser_test.o \
+ drm_damage_helper_test.o \
+ drm_dp_mst_helper_test.o \
+ drm_format_helper_test.o \
+ drm_format_test.o \
+ drm_framebuffer_test.o \
+ drm_kunit_helpers.o \
+ drm_mm_test.o \
+ drm_plane_helper_test.o \
+ drm_rect_test.o
diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c
index 62f69589a72d..f8ee714df396 100644
--- a/drivers/gpu/drm/tests/drm_buddy_test.c
+++ b/drivers/gpu/drm/tests/drm_buddy_test.c
@@ -726,11 +726,13 @@ static void drm_test_buddy_alloc_limit(struct kunit *test)
drm_buddy_fini(&mm);
}
-static int drm_buddy_init_test(struct kunit *test)
+static int drm_buddy_suite_init(struct kunit_suite *suite)
{
while (!random_seed)
random_seed = get_random_u32();
+ kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n", random_seed);
+
return 0;
}
@@ -746,7 +748,7 @@ static struct kunit_case drm_buddy_tests[] = {
static struct kunit_suite drm_buddy_test_suite = {
.name = "drm_buddy",
- .init = drm_buddy_init_test,
+ .suite_init = drm_buddy_suite_init,
.test_cases = drm_buddy_tests,
};
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
new file mode 100644
index 000000000000..362a5fbd82f5
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Maxime Ripard <mripard@kernel.org>
+ */
+
+#include <kunit/test.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include "drm_kunit_helpers.h"
+
+struct drm_client_modeset_test_priv {
+ struct drm_device *drm;
+ struct drm_connector connector;
+};
+
+static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
+{
+ return drm_add_modes_noedid(connector, 1920, 1200);
+}
+
+static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
+ .get_modes = drm_client_modeset_connector_get_modes,
+};
+
+static const struct drm_connector_funcs drm_client_modeset_connector_funcs = {
+};
+
+static int drm_client_modeset_test_init(struct kunit *test)
+{
+ struct drm_client_modeset_test_priv *priv;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ test->priv = priv;
+
+ priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-client-modeset-test");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
+
+ ret = drmm_connector_init(priv->drm, &priv->connector,
+ &drm_client_modeset_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
+
+ return 0;
+}
+
+static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
+{
+ struct drm_client_modeset_test_priv *priv = test->priv;
+ struct drm_device *drm = priv->drm;
+ struct drm_connector *connector = &priv->connector;
+ struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+ struct drm_display_mode *expected_mode, *mode;
+ const char *cmdline = "1920x1080@60";
+ int ret;
+
+ expected_mode = drm_mode_find_dmt(priv->drm, 1920, 1080, 60, false);
+ KUNIT_ASSERT_NOT_NULL(test, expected_mode);
+
+ KUNIT_ASSERT_TRUE(test,
+ drm_mode_parse_command_line_for_connector(cmdline,
+ connector,
+ cmdline_mode));
+
+ mutex_lock(&drm->mode_config.mutex);
+ ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+ mutex_unlock(&drm->mode_config.mutex);
+ KUNIT_ASSERT_GT(test, ret, 0);
+
+ mode = drm_connector_pick_cmdline_mode(connector);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
+}
+
+static struct kunit_case drm_test_pick_cmdline_tests[] = {
+ KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
+ {}
+};
+
+static struct kunit_suite drm_test_pick_cmdline_test_suite = {
+ .name = "drm_test_pick_cmdline",
+ .init = drm_client_modeset_test_init,
+ .test_cases = drm_test_pick_cmdline_tests
+};
+
+kunit_test_suite(drm_test_pick_cmdline_test_suite);
diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c
index 65c9d225b558..545beea33e8c 100644
--- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c
@@ -5,44 +5,280 @@
* Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
*/
-#define PREFIX_STR "[drm_dp_mst_helper]"
-
#include <kunit/test.h>
-#include <linux/random.h>
-
#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_print.h>
#include "../display/drm_dp_mst_topology_internal.h"
+struct drm_dp_mst_calc_pbn_mode_test {
+ const int clock;
+ const int bpp;
+ const bool dsc;
+ const int expected;
+};
+
+static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = {
+ {
+ .clock = 154000,
+ .bpp = 30,
+ .dsc = false,
+ .expected = 689
+ },
+ {
+ .clock = 234000,
+ .bpp = 30,
+ .dsc = false,
+ .expected = 1047
+ },
+ {
+ .clock = 297000,
+ .bpp = 24,
+ .dsc = false,
+ .expected = 1063
+ },
+ {
+ .clock = 332880,
+ .bpp = 24,
+ .dsc = true,
+ .expected = 50
+ },
+ {
+ .clock = 324540,
+ .bpp = 24,
+ .dsc = true,
+ .expected = 49
+ },
+};
+
static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test)
{
- int pbn, i;
- const struct {
- int rate;
- int bpp;
- int expected;
- bool dsc;
- } test_params[] = {
- { 154000, 30, 689, false },
- { 234000, 30, 1047, false },
- { 297000, 24, 1063, false },
- { 332880, 24, 50, true },
- { 324540, 24, 49, true },
- };
+ const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value;
- for (i = 0; i < ARRAY_SIZE(test_params); i++) {
- pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
- test_params[i].bpp,
- test_params[i].dsc);
- KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected,
- "Expected PBN %d for clock %d bpp %d, got %d\n",
- test_params[i].expected, test_params[i].rate,
- test_params[i].bpp, pbn);
- }
+ KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp, params->dsc),
+ params->expected);
}
+static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc)
+{
+ sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled");
+}
+
+KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases,
+ dp_mst_calc_pbn_mode_desc);
+
+static u8 data[] = { 0xff, 0x00, 0xdd };
+
+struct drm_dp_mst_sideband_msg_req_test {
+ const char *desc;
+ const struct drm_dp_sideband_msg_req_body in;
+};
+
+static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = {
+ {
+ .desc = "DP_ENUM_PATH_RESOURCES with port number",
+ .in = {
+ .req_type = DP_ENUM_PATH_RESOURCES,
+ .u.port_num.port_number = 5,
+ },
+ },
+ {
+ .desc = "DP_POWER_UP_PHY with port number",
+ .in = {
+ .req_type = DP_POWER_UP_PHY,
+ .u.port_num.port_number = 5,
+ },
+ },
+ {
+ .desc = "DP_POWER_DOWN_PHY with port number",
+ .in = {
+ .req_type = DP_POWER_DOWN_PHY,
+ .u.port_num.port_number = 5,
+ },
+ },
+ {
+ .desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks",
+ .in = {
+ .req_type = DP_ALLOCATE_PAYLOAD,
+ .u.allocate_payload.number_sdp_streams = 3,
+ .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
+ },
+ },
+ {
+ .desc = "DP_ALLOCATE_PAYLOAD with port number",
+ .in = {
+ .req_type = DP_ALLOCATE_PAYLOAD,
+ .u.allocate_payload.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_ALLOCATE_PAYLOAD with VCPI",
+ .in = {
+ .req_type = DP_ALLOCATE_PAYLOAD,
+ .u.allocate_payload.vcpi = 0x7f,
+ },
+ },
+ {
+ .desc = "DP_ALLOCATE_PAYLOAD with PBN",
+ .in = {
+ .req_type = DP_ALLOCATE_PAYLOAD,
+ .u.allocate_payload.pbn = U16_MAX,
+ },
+ },
+ {
+ .desc = "DP_QUERY_PAYLOAD with port number",
+ .in = {
+ .req_type = DP_QUERY_PAYLOAD,
+ .u.query_payload.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_QUERY_PAYLOAD with VCPI",
+ .in = {
+ .req_type = DP_QUERY_PAYLOAD,
+ .u.query_payload.vcpi = 0x7f,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_READ with port number",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_READ,
+ .u.dpcd_read.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_READ with DPCD address",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_READ,
+ .u.dpcd_read.dpcd_address = 0xfedcb,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_READ with max number of bytes",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_READ,
+ .u.dpcd_read.num_bytes = U8_MAX,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_WRITE with port number",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_WRITE,
+ .u.dpcd_write.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_WRITE with DPCD address",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_WRITE,
+ .u.dpcd_write.dpcd_address = 0xfedcb,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_DPCD_WRITE with data array",
+ .in = {
+ .req_type = DP_REMOTE_DPCD_WRITE,
+ .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
+ .u.dpcd_write.bytes = data,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_READ with port number",
+ .in = {
+ .req_type = DP_REMOTE_I2C_READ,
+ .u.i2c_read.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_READ with I2C device ID",
+ .in = {
+ .req_type = DP_REMOTE_I2C_READ,
+ .u.i2c_read.read_i2c_device_id = 0x7f,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_READ with transactions array",
+ .in = {
+ .req_type = DP_REMOTE_I2C_READ,
+ .u.i2c_read.num_transactions = 3,
+ .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
+ .u.i2c_read.transactions = {
+ { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f,
+ .i2c_transaction_delay = 0xf, },
+ { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e,
+ .i2c_transaction_delay = 0xe, },
+ { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d,
+ .i2c_transaction_delay = 0xd, },
+ },
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_WRITE with port number",
+ .in = {
+ .req_type = DP_REMOTE_I2C_WRITE,
+ .u.i2c_write.port_number = 0xf,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_WRITE with I2C device ID",
+ .in = {
+ .req_type = DP_REMOTE_I2C_WRITE,
+ .u.i2c_write.write_i2c_device_id = 0x7f,
+ },
+ },
+ {
+ .desc = "DP_REMOTE_I2C_WRITE with data array",
+ .in = {
+ .req_type = DP_REMOTE_I2C_WRITE,
+ .u.i2c_write.num_bytes = ARRAY_SIZE(data),
+ .u.i2c_write.bytes = data,
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.stream_id = 1,
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with client ID",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 },
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with stream event",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.stream_event = 3,
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.valid_stream_event = 0,
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.stream_behavior = 3,
+ },
+ },
+ {
+ .desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior",
+ .in = {
+ .req_type = DP_QUERY_STREAM_ENC_STATUS,
+ .u.enc_status.valid_stream_behavior = 1,
+ }
+ },
+};
+
static bool
sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
const struct drm_dp_sideband_msg_req_body *out)
@@ -118,41 +354,41 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
return true;
}
-static bool
-sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
+static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf)
{
+ struct kunit *test = p->arg;
+
+ kunit_err(test, "%pV", vaf);
+}
+
+static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
+{
+ const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value;
+ const struct drm_dp_sideband_msg_req_body *in = &params->in;
struct drm_dp_sideband_msg_req_body *out;
- struct drm_printer p = drm_err_printer(PREFIX_STR);
struct drm_dp_sideband_msg_tx *txmsg;
- int i, ret;
- bool result = true;
+ struct drm_printer p = {
+ .printfn = drm_test_dp_mst_msg_printf,
+ .arg = test
+ };
+ int i;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return false;
+ out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, out);
- txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
- if (!txmsg) {
- kfree(out);
- return false;
- }
+ txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, txmsg);
drm_dp_encode_sideband_req(in, txmsg);
- ret = drm_dp_decode_sideband_req(txmsg, out);
- if (ret < 0) {
- drm_printf(&p, "Failed to decode sideband request: %d\n",
- ret);
- result = false;
- goto out;
- }
+ KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0,
+ "Failed to decode sideband request");
if (!sideband_msg_req_equal(in, out)) {
- drm_printf(&p, "Encode/decode failed, expected:\n");
+ KUNIT_FAIL(test, "Encode/decode failed");
+ kunit_err(test, "Expected:");
drm_dp_dump_sideband_msg_req_body(in, 1, &p);
- drm_printf(&p, "Got:\n");
+ kunit_err(test, "Got:");
drm_dp_dump_sideband_msg_req_body(out, 1, &p);
- result = false;
- goto out;
}
switch (in->req_type) {
@@ -167,112 +403,21 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
kfree(out->u.i2c_write.bytes);
break;
}
-
- /* Clear everything but the req_type for the input */
- memset(&in->u, 0, sizeof(in->u));
-
-out:
- kfree(out);
- kfree(txmsg);
- return result;
}
-static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
+static void
+drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc)
{
- struct drm_dp_sideband_msg_req_body in = { 0 };
- u8 data[] = { 0xff, 0x0, 0xdd };
- int i;
-
- in.req_type = DP_ENUM_PATH_RESOURCES;
- in.u.port_num.port_number = 5;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_POWER_UP_PHY;
- in.u.port_num.port_number = 5;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_POWER_DOWN_PHY;
- in.u.port_num.port_number = 5;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_ALLOCATE_PAYLOAD;
- in.u.allocate_payload.number_sdp_streams = 3;
- for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
- in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.allocate_payload.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.allocate_payload.vcpi = 0x7f;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.allocate_payload.pbn = U16_MAX;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_QUERY_PAYLOAD;
- in.u.query_payload.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.query_payload.vcpi = 0x7f;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_REMOTE_DPCD_READ;
- in.u.dpcd_read.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.dpcd_read.dpcd_address = 0xfedcb;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.dpcd_read.num_bytes = U8_MAX;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_REMOTE_DPCD_WRITE;
- in.u.dpcd_write.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.dpcd_write.dpcd_address = 0xfedcb;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
- in.u.dpcd_write.bytes = data;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_REMOTE_I2C_READ;
- in.u.i2c_read.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.i2c_read.read_i2c_device_id = 0x7f;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.i2c_read.num_transactions = 3;
- in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
- for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
- in.u.i2c_read.transactions[i].bytes = data;
- in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
- in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
- in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
- }
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_REMOTE_I2C_WRITE;
- in.u.i2c_write.port_number = 0xf;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.i2c_write.write_i2c_device_id = 0x7f;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
- in.u.i2c_write.bytes = data;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
-
- in.req_type = DP_QUERY_STREAM_ENC_STATUS;
- in.u.enc_status.stream_id = 1;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- get_random_bytes(in.u.enc_status.client_id,
- sizeof(in.u.enc_status.client_id));
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.enc_status.stream_event = 3;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.enc_status.valid_stream_event = 0;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.enc_status.stream_behavior = 3;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
- in.u.enc_status.valid_stream_behavior = 1;
- KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
+ strcpy(desc, t->desc);
}
+KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
+ drm_dp_mst_sideband_msg_req_desc);
+
static struct kunit_case drm_dp_mst_helper_tests[] = {
- KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode),
- KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode),
+ KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params),
+ KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode,
+ drm_dp_mst_sideband_msg_req_gen_params),
{ }
};
diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
index 2191e57f2297..567c71f95edc 100644
--- a/drivers/gpu/drm/tests/drm_format_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
@@ -315,7 +315,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, &params->clip);
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
@@ -345,7 +345,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, &params->clip);
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
@@ -375,10 +375,10 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, false);
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, true);
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
}
static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
@@ -408,7 +408,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
@@ -439,7 +439,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32));
- KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
static struct kunit_case drm_format_helper_test_cases[] = {
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
new file mode 100644
index 000000000000..f1662091f250
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+
+#include <kunit/resource.h>
+
+#include <linux/device.h>
+
+#include "drm_kunit_helpers.h"
+
+struct kunit_dev {
+ struct drm_device base;
+};
+
+static const struct drm_mode_config_funcs drm_mode_config_funcs = {
+};
+
+static int dev_init(struct kunit_resource *res, void *ptr)
+{
+ char *name = ptr;
+ struct device *dev;
+
+ dev = root_device_register(name);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ res->data = dev;
+ return 0;
+}
+
+static void dev_free(struct kunit_resource *res)
+{
+ struct device *dev = res->data;
+
+ root_device_unregister(dev);
+}
+
+struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name)
+{
+ struct kunit_dev *kdev;
+ struct drm_device *drm;
+ struct drm_driver *driver;
+ struct device *dev;
+ int ret;
+
+ dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, name);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
+ if (!driver)
+ return ERR_PTR(-ENOMEM);
+
+ driver->driver_features = features;
+ kdev = devm_drm_dev_alloc(dev, driver, struct kunit_dev, base);
+ if (IS_ERR(kdev))
+ return ERR_CAST(kdev);
+
+ drm = &kdev->base;
+ drm->mode_config.funcs = &drm_mode_config_funcs;
+
+ ret = drmm_mode_config_init(drm);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return drm;
+}
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.h b/drivers/gpu/drm/tests/drm_kunit_helpers.h
new file mode 100644
index 000000000000..20ab6eec4c89
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef DRM_KUNIT_HELPERS_H_
+#define DRM_KUNIT_HELPERS_H_
+
+struct drm_device;
+struct kunit;
+
+struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name);
+
+#endif // DRM_KUNIT_HELPERS_H_
diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c
index c4b66eeae203..89f12d3b4a21 100644
--- a/drivers/gpu/drm/tests/drm_mm_test.c
+++ b/drivers/gpu/drm/tests/drm_mm_test.c
@@ -2209,11 +2209,15 @@ err_nodes:
vfree(nodes);
}
-static int drm_mm_init_test(struct kunit *test)
+static int drm_mm_suite_init(struct kunit_suite *suite)
{
while (!random_seed)
random_seed = get_random_u32();
+ kunit_info(suite,
+ "Testing DRM range manager, with random_seed=0x%x max_iterations=%u max_prime=%u\n",
+ random_seed, max_iterations, max_prime);
+
return 0;
}
@@ -2246,7 +2250,7 @@ static struct kunit_case drm_mm_tests[] = {
static struct kunit_suite drm_mm_test_suite = {
.name = "drm_mm",
- .init = drm_mm_init_test,
+ .suite_init = drm_mm_suite_init,
.test_cases = drm_mm_tests,
};
diff --git a/drivers/gpu/drm/tests/drm_plane_helper_test.c b/drivers/gpu/drm/tests/drm_plane_helper_test.c
index ec71af791f1f..0f392146b233 100644
--- a/drivers/gpu/drm/tests/drm_plane_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_plane_helper_test.c
@@ -10,225 +10,306 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_modes.h>
+#include <drm/drm_rect.h>
-static void set_src(struct drm_plane_state *plane_state,
- unsigned int src_x, unsigned int src_y,
- unsigned int src_w, unsigned int src_h)
+static const struct drm_crtc_state crtc_state = {
+ .crtc = ZERO_SIZE_PTR,
+ .enable = true,
+ .active = true,
+ .mode = {
+ DRM_MODE("1024x768", 0, 65000, 1024, 1048,
+ 1184, 1344, 0, 768, 771, 777, 806, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+ },
+};
+
+struct drm_check_plane_state_test {
+ const char *name;
+ const char *msg;
+ struct {
+ unsigned int x;
+ unsigned int y;
+ unsigned int w;
+ unsigned int h;
+ } src, src_expected;
+ struct {
+ int x;
+ int y;
+ unsigned int w;
+ unsigned int h;
+ } crtc, crtc_expected;
+ unsigned int rotation;
+ int min_scale;
+ int max_scale;
+ bool can_position;
+};
+
+static int drm_plane_helper_init(struct kunit *test)
{
- plane_state->src_x = src_x;
- plane_state->src_y = src_y;
- plane_state->src_w = src_w;
- plane_state->src_h = src_h;
+ const struct drm_check_plane_state_test *params = test->param_value;
+ struct drm_plane *plane;
+ struct drm_framebuffer *fb;
+ struct drm_plane_state *mock;
+
+ plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+
+ fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fb);
+ fb->width = 2048;
+ fb->height = 2048;
+
+ mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mock);
+ mock->plane = plane;
+ mock->crtc = ZERO_SIZE_PTR;
+ mock->fb = fb;
+ mock->rotation = params->rotation;
+ mock->src_x = params->src.x;
+ mock->src_y = params->src.y;
+ mock->src_w = params->src.w;
+ mock->src_h = params->src.h;
+ mock->crtc_x = params->crtc.x;
+ mock->crtc_y = params->crtc.y;
+ mock->crtc_w = params->crtc.w;
+ mock->crtc_h = params->crtc.h;
+
+ test->priv = mock;
+
+ return 0;
}
-static bool check_src_eq(struct drm_plane_state *plane_state,
+static void check_src_eq(struct kunit *test, struct drm_plane_state *plane_state,
unsigned int src_x, unsigned int src_y,
unsigned int src_w, unsigned int src_h)
{
- if (plane_state->src.x1 < 0) {
- pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
- drm_rect_debug_print("src: ", &plane_state->src, true);
- return false;
- }
- if (plane_state->src.y1 < 0) {
- pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
- drm_rect_debug_print("src: ", &plane_state->src, true);
- return false;
- }
-
- if (plane_state->src.x1 != src_x ||
- plane_state->src.y1 != src_y ||
- drm_rect_width(&plane_state->src) != src_w ||
- drm_rect_height(&plane_state->src) != src_h) {
- drm_rect_debug_print("src: ", &plane_state->src, true);
- return false;
- }
-
- return true;
-}
+ struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h);
-static void set_crtc(struct drm_plane_state *plane_state,
- int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h)
-{
- plane_state->crtc_x = crtc_x;
- plane_state->crtc_y = crtc_y;
- plane_state->crtc_w = crtc_w;
- plane_state->crtc_h = crtc_h;
+ KUNIT_ASSERT_GE_MSG(test, plane_state->src.x1, 0,
+ "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+ plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src));
+
+ KUNIT_ASSERT_GE_MSG(test, plane_state->src.y1, 0,
+ "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+ plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src));
+
+ KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->src, &expected),
+ "dst: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT,
+ DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected));
}
-static bool check_crtc_eq(struct drm_plane_state *plane_state,
+static void check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h)
{
- if (plane_state->dst.x1 != crtc_x ||
- plane_state->dst.y1 != crtc_y ||
- drm_rect_width(&plane_state->dst) != crtc_w ||
- drm_rect_height(&plane_state->dst) != crtc_h) {
- drm_rect_debug_print("dst: ", &plane_state->dst, false);
-
- return false;
- }
+ struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h);
- return true;
+ KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->dst, &expected),
+ "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT,
+ DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected));
}
static void drm_test_check_plane_state(struct kunit *test)
{
- int ret;
-
- static const struct drm_crtc_state crtc_state = {
- .crtc = ZERO_SIZE_PTR,
- .enable = true,
- .active = true,
- .mode = {
- DRM_MODE("1024x768", 0, 65000, 1024, 1048, 1184, 1344, 0, 768, 771,
- 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
- },
- };
- static struct drm_plane plane = {
- .dev = NULL
- };
- static struct drm_framebuffer fb = {
- .width = 2048,
- .height = 2048
- };
- static struct drm_plane_state plane_state = {
- .plane = &plane,
- .crtc = ZERO_SIZE_PTR,
- .fb = &fb,
- .rotation = DRM_MODE_ROTATE_0
- };
-
- /* Simple clipping, no scaling. */
- set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
- set_crtc(&plane_state, 0, 0, fb.width, fb.height);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
- /* Rotated clipping + reflection, no scaling. */
- plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
- plane_state.rotation = DRM_MODE_ROTATE_0;
-
- /* Check whether positioning works correctly. */
- set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
- set_crtc(&plane_state, 0, 0, 1023, 767);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_TRUE_MSG(test, ret,
- "Should not be able to position on the crtc with can_position=false\n");
-
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- true, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1023, 767));
-
- /* Simple scaling tests. */
- set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
- set_crtc(&plane_state, 0, 0, 1024, 768);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- 0x8001,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_TRUE_MSG(test, ret, "Upscaling out of range should fail.\n");
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- 0x8000,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
- set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- 0x1ffff, false, false);
- KUNIT_EXPECT_TRUE_MSG(test, ret, "Downscaling out of range should fail.\n");
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- 0x20000, false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
- /* Testing rounding errors. */
- set_src(&plane_state, 0, 0, 0x40001, 0x40001);
- set_crtc(&plane_state, 1022, 766, 4, 4);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- 0x10001,
- true, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
- set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
- set_crtc(&plane_state, -2, -2, 1028, 772);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- DRM_PLANE_NO_SCALING,
- 0x10001,
- false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x40002, 0x40002,
- 1024 << 16, 768 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
- set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
- set_crtc(&plane_state, 1022, 766, 4, 4);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- 0xffff,
- DRM_PLANE_NO_SCALING,
- true, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- /* Should not be rounded to 0x20001, which would be upscaling. */
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
- set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
- set_crtc(&plane_state, -2, -2, 1028, 772);
- ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
- 0xffff,
- DRM_PLANE_NO_SCALING,
- false, false);
- KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple");
- KUNIT_EXPECT_TRUE(test, plane_state.visible);
- KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x3fffe, 0x3fffe,
- 1024 << 16, 768 << 16));
- KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+ const struct drm_check_plane_state_test *params = test->param_value;
+ struct drm_plane_state *plane_state = test->priv;
+
+ KUNIT_ASSERT_EQ_MSG(test,
+ drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+ params->min_scale,
+ params->max_scale,
+ params->can_position, false),
+ 0, params->msg);
+ KUNIT_EXPECT_TRUE(test, plane_state->visible);
+ check_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y,
+ params->src_expected.w, params->src_expected.h);
+ check_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y,
+ params->crtc_expected.w, params->crtc_expected.h);
+}
+
+static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,
+ char *desc)
+{
+ sprintf(desc, "%s", t->name);
+}
+
+static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {
+ {
+ .name = "clipping_simple",
+ .msg = "Simple clipping check should pass",
+ .src = { 0, 0,
+ 2048 << 16,
+ 2048 << 16 },
+ .crtc = { 0, 0, 2048, 2048 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ .src_expected = { 0, 0, 1024 << 16, 768 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+ {
+ .name = "clipping_rotate_reflect",
+ .msg = "Rotated clipping check should pass",
+ .src = { 0, 0,
+ 2048 << 16,
+ 2048 << 16 },
+ .crtc = { 0, 0, 2048, 2048 },
+ .rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ .src_expected = { 0, 0, 768 << 16, 1024 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+ {
+ .name = "positioning_simple",
+ .msg = "Simple positioning should work",
+ .src = { 0, 0, 1023 << 16, 767 << 16 },
+ .crtc = { 0, 0, 1023, 767 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = true,
+ .src_expected = { 0, 0, 1023 << 16, 767 << 16 },
+ .crtc_expected = { 0, 0, 1023, 767 },
+ },
+ {
+ .name = "upscaling",
+ .msg = "Upscaling exactly 2x should work",
+ .src = { 0, 0, 512 << 16, 384 << 16 },
+ .crtc = { 0, 0, 1024, 768 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = 0x8000,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ .src_expected = { 0, 0, 512 << 16, 384 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+ {
+ .name = "downscaling",
+ .msg = "Should succeed with exact scaling limit",
+ .src = { 0, 0, 2048 << 16, 1536 << 16 },
+ .crtc = { 0, 0, 1024, 768 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = 0x20000,
+ .can_position = false,
+ .src_expected = { 0, 0, 2048 << 16, 1536 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+ {
+ .name = "rounding1",
+ .msg = "Should succeed by clipping to exact multiple",
+ .src = { 0, 0, 0x40001, 0x40001 },
+ .crtc = { 1022, 766, 4, 4 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = 0x10001,
+ .can_position = true,
+ .src_expected = { 0, 0, 2 << 16, 2 << 16 },
+ .crtc_expected = { 1022, 766, 2, 2 },
+ },
+ {
+ .name = "rounding2",
+ .msg = "Should succeed by clipping to exact multiple",
+ .src = { 0x20001, 0x20001, 0x4040001, 0x3040001 },
+ .crtc = { -2, -2, 1028, 772 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = 0x10001,
+ .can_position = false,
+ .src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+ {
+ .name = "rounding3",
+ .msg = "Should succeed by clipping to exact multiple",
+ .src = { 0, 0, 0x3ffff, 0x3ffff },
+ .crtc = { 1022, 766, 4, 4 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = 0xffff,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = true,
+ /* Should not be rounded to 0x20001, which would be upscaling. */
+ .src_expected = { 0, 0, 2 << 16, 2 << 16 },
+ .crtc_expected = { 1022, 766, 2, 2 },
+ },
+ {
+ .name = "rounding4",
+ .msg = "Should succeed by clipping to exact multiple",
+ .src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff },
+ .crtc = { -2, -2, 1028, 772 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = 0xffff,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ .src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 },
+ .crtc_expected = { 0, 0, 1024, 768 },
+ },
+};
+
+KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);
+
+static void drm_test_check_invalid_plane_state(struct kunit *test)
+{
+ const struct drm_check_plane_state_test *params = test->param_value;
+ struct drm_plane_state *plane_state = test->priv;
+
+ KUNIT_ASSERT_LT_MSG(test,
+ drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+ params->min_scale,
+ params->max_scale,
+ params->can_position, false),
+ 0, params->msg);
}
+static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {
+ {
+ .name = "positioning_invalid",
+ .msg = "Should not be able to position on the crtc with can_position=false",
+ .src = { 0, 0, 1023 << 16, 767 << 16 },
+ .crtc = { 0, 0, 1023, 767 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ },
+ {
+ .name = "upscaling_invalid",
+ .msg = "Upscaling out of range should fail",
+ .src = { 0, 0, 512 << 16, 384 << 16 },
+ .crtc = { 0, 0, 1024, 768 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = 0x8001,
+ .max_scale = DRM_PLANE_NO_SCALING,
+ .can_position = false,
+ },
+ {
+ .name = "downscaling_invalid",
+ .msg = "Downscaling out of range should fail",
+ .src = { 0, 0, 2048 << 16, 1536 << 16 },
+ .crtc = { 0, 0, 1024, 768 },
+ .rotation = DRM_MODE_ROTATE_0,
+ .min_scale = DRM_PLANE_NO_SCALING,
+ .max_scale = 0x1ffff,
+ .can_position = false,
+ },
+};
+
+KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,
+ drm_check_plane_state_desc);
+
static struct kunit_case drm_plane_helper_test[] = {
- KUNIT_CASE(drm_test_check_plane_state),
+ KUNIT_CASE_PARAM(drm_test_check_plane_state, drm_check_plane_state_gen_params),
+ KUNIT_CASE_PARAM(drm_test_check_invalid_plane_state,
+ drm_check_invalid_plane_state_gen_params),
{}
};
static struct kunit_suite drm_plane_helper_test_suite = {
.name = "drm_plane_helper",
+ .init = drm_plane_helper_init,
.test_cases = drm_plane_helper_test,
};
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
index 15cd9b91b7e2..07d94b1e8089 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.c
+++ b/drivers/gpu/drm/tidss/tidss_drv.c
@@ -14,7 +14,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index afb2879980c6..345bcc3011e4 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -10,7 +10,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index f72755b8ea14..80615ecdae0b 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 565957264875..f6889f649bc1 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -51,6 +51,19 @@ config DRM_GM12U320
This is a KMS driver for projectors which use the GM12U320 chipset
for video transfer over USB2/3, such as the Acer C120 mini projector.
+config DRM_OFDRM
+ tristate "Open Firmware display driver"
+ depends on DRM && MMU && OF && (PPC || COMPILE_TEST)
+ select APERTURE_HELPERS
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ help
+ DRM driver for Open Firmware framebuffers.
+
+ This driver assumes that the display hardware has been initialized
+ by the Open Firmware before the kernel boots. Scanout buffer, size,
+ and display format must be provided via device tree.
+
config DRM_PANEL_MIPI_DBI
tristate "DRM support for MIPI DBI compatible panels"
depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index 1d9d6227e7ab..76dde89a044b 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
obj-$(CONFIG_DRM_BOCHS) += bochs.o
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
+obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c
index bb302a3fd6b5..611bbee15071 100644
--- a/drivers/gpu/drm/tiny/arcpgu.c
+++ b/drivers/gpu/drm/tiny/arcpgu.c
@@ -12,7 +12,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index a51262289aef..024346054c70 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -7,7 +7,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -543,7 +543,6 @@ static int bochs_kms_init(struct bochs_device *bochs)
bochs->dev->mode_config.max_width = 8192;
bochs->dev->mode_config.max_height = 8192;
- bochs->dev->mode_config.fb_base = bochs->fb_base;
bochs->dev->mode_config.preferred_depth = 24;
bochs->dev->mode_config.prefer_shadow = 0;
bochs->dev->mode_config.prefer_shadow_fbdev = 1;
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index 354d5e854a6f..678c2ef1cae7 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -30,7 +30,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c
index 7441d992a5d7..130fd07a967d 100644
--- a/drivers/gpu/drm/tiny/gm12u320.c
+++ b/drivers/gpu/drm/tiny/gm12u320.c
@@ -12,7 +12,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c
index 48c24aa8c28a..9f634f720817 100644
--- a/drivers/gpu/drm/tiny/hx8357d.c
+++ b/drivers/gpu/drm/tiny/hx8357d.c
@@ -18,7 +18,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c
index 9a1a5943bee0..ca0451f79962 100644
--- a/drivers/gpu/drm/tiny/ili9163.c
+++ b/drivers/gpu/drm/tiny/ili9163.c
@@ -9,7 +9,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_mipi_dbi.h>
diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c
index a79da2b4af64..815bab285823 100644
--- a/drivers/gpu/drm/tiny/ili9225.c
+++ b/drivers/gpu/drm/tiny/ili9225.c
@@ -20,7 +20,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c
index 69b265e78096..420f6005a956 100644
--- a/drivers/gpu/drm/tiny/ili9341.c
+++ b/drivers/gpu/drm/tiny/ili9341.c
@@ -17,7 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c
index c80028bb1d11..1bb847466b10 100644
--- a/drivers/gpu/drm/tiny/ili9486.c
+++ b/drivers/gpu/drm/tiny/ili9486.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c
index bc522fb3d94d..47df2b5a3048 100644
--- a/drivers/gpu/drm/tiny/mi0283qt.c
+++ b/drivers/gpu/drm/tiny/mi0283qt.c
@@ -15,7 +15,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
new file mode 100644
index 000000000000..dc9e4d71b12a
--- /dev/null
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -0,0 +1,1429 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/of_address.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define DRIVER_NAME "ofdrm"
+#define DRIVER_DESC "DRM driver for OF platform devices"
+#define DRIVER_DATE "20220501"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+#define PCI_VENDOR_ID_ATI_R520 0x7100
+#define PCI_VENDOR_ID_ATI_R600 0x9400
+
+#define OFDRM_GAMMA_LUT_SIZE 256
+
+/* Definitions used by the Avivo palette */
+#define AVIVO_DC_LUT_RW_SELECT 0x6480
+#define AVIVO_DC_LUT_RW_MODE 0x6484
+#define AVIVO_DC_LUT_RW_INDEX 0x6488
+#define AVIVO_DC_LUT_SEQ_COLOR 0x648c
+#define AVIVO_DC_LUT_PWL_DATA 0x6490
+#define AVIVO_DC_LUT_30_COLOR 0x6494
+#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
+#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
+#define AVIVO_DC_LUT_AUTOFILL 0x64a0
+#define AVIVO_DC_LUTA_CONTROL 0x64c0
+#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
+#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
+#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
+#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
+#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
+#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
+#define AVIVO_DC_LUTB_CONTROL 0x6cc0
+#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
+#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
+#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
+#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
+#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
+#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
+
+enum ofdrm_model {
+ OFDRM_MODEL_UNKNOWN,
+ OFDRM_MODEL_MACH64, /* ATI Mach64 */
+ OFDRM_MODEL_RAGE128, /* ATI Rage128 */
+ OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */
+ OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */
+ OFDRM_MODEL_RADEON, /* ATI Radeon */
+ OFDRM_MODEL_GXT2000, /* IBM GXT2000 */
+ OFDRM_MODEL_AVIVO, /* ATI R5xx */
+ OFDRM_MODEL_QEMU, /* QEMU VGA */
+};
+
+/*
+ * Helpers for display nodes
+ */
+
+static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value)
+{
+ if (value > INT_MAX) {
+ drm_err(dev, "invalid framebuffer %s of %u\n", name, value);
+ return -EINVAL;
+ }
+ return (int)value;
+}
+
+static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value)
+{
+ if (!value) {
+ drm_err(dev, "invalid framebuffer %s of %u\n", name, value);
+ return -EINVAL;
+ }
+ return display_get_validated_int(dev, name, value);
+}
+
+static const struct drm_format_info *display_get_validated_format(struct drm_device *dev,
+ u32 depth, bool big_endian)
+{
+ const struct drm_format_info *info;
+ u32 format;
+
+ switch (depth) {
+ case 8:
+ format = drm_mode_legacy_fb_format(8, 8);
+ break;
+ case 15:
+ case 16:
+ format = drm_mode_legacy_fb_format(16, depth);
+ break;
+ case 32:
+ format = drm_mode_legacy_fb_format(32, 24);
+ break;
+ default:
+ drm_err(dev, "unsupported framebuffer depth %u\n", depth);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * DRM formats assume little-endian byte order. Update the format
+ * if the scanout buffer uses big-endian ordering.
+ */
+ if (big_endian) {
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ format = DRM_FORMAT_BGRX8888;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ format = DRM_FORMAT_BGRA8888;
+ break;
+ case DRM_FORMAT_RGB565:
+ format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN;
+ break;
+ case DRM_FORMAT_XRGB1555:
+ format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ info = drm_format_info(format);
+ if (!info) {
+ drm_err(dev, "cannot find framebuffer format for depth %u\n", depth);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return info;
+}
+
+static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node,
+ const char *name, u32 *value)
+{
+ int ret = of_property_read_u32(of_node, name, value);
+
+ if (ret)
+ drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret);
+ return ret;
+}
+
+static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node)
+{
+ bool big_endian;
+
+#ifdef __BIG_ENDIAN
+ big_endian = true;
+ if (of_get_property(of_node, "little-endian", NULL))
+ big_endian = false;
+#else
+ big_endian = false;
+ if (of_get_property(of_node, "big-endian", NULL))
+ big_endian = true;
+#endif
+
+ return big_endian;
+}
+
+static int display_get_width_of(struct drm_device *dev, struct device_node *of_node)
+{
+ u32 width;
+ int ret = display_read_u32_of(dev, of_node, "width", &width);
+
+ if (ret)
+ return ret;
+ return display_get_validated_int0(dev, "width", width);
+}
+
+static int display_get_height_of(struct drm_device *dev, struct device_node *of_node)
+{
+ u32 height;
+ int ret = display_read_u32_of(dev, of_node, "height", &height);
+
+ if (ret)
+ return ret;
+ return display_get_validated_int0(dev, "height", height);
+}
+
+static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node)
+{
+ u32 depth;
+ int ret = display_read_u32_of(dev, of_node, "depth", &depth);
+
+ if (ret)
+ return ret;
+ return display_get_validated_int0(dev, "depth", depth);
+}
+
+static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node)
+{
+ u32 linebytes;
+ int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes);
+
+ if (ret)
+ return ret;
+ return display_get_validated_int(dev, "linebytes", linebytes);
+}
+
+static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node)
+{
+ u32 address;
+ int ret;
+
+ /*
+ * Not all devices provide an address property, it's not
+ * a bug if this fails. The driver will try to find the
+ * framebuffer base address from the device's memory regions.
+ */
+ ret = of_property_read_u32(of_node, "address", &address);
+ if (ret)
+ return OF_BAD_ADDR;
+
+ return address;
+}
+
+static bool is_avivo(u32 vendor, u32 device)
+{
+ /* This will match most R5xx */
+ return (vendor == PCI_VENDOR_ID_ATI) &&
+ ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) ||
+ (PCI_VENDOR_ID_ATI_R600 >= 0x9400));
+}
+
+static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node)
+{
+ enum ofdrm_model model = OFDRM_MODEL_UNKNOWN;
+
+ if (of_node_name_prefix(of_node, "ATY,Rage128")) {
+ model = OFDRM_MODEL_RAGE128;
+ } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") ||
+ of_node_name_prefix(of_node, "ATY,RageM3p12A")) {
+ model = OFDRM_MODEL_RAGE_M3A;
+ } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) {
+ model = OFDRM_MODEL_RAGE_M3B;
+ } else if (of_node_name_prefix(of_node, "ATY,Rage6")) {
+ model = OFDRM_MODEL_RADEON;
+ } else if (of_node_name_prefix(of_node, "ATY,")) {
+ return OFDRM_MODEL_MACH64;
+ } else if (of_device_is_compatible(of_node, "pci1014,b7") ||
+ of_device_is_compatible(of_node, "pci1014,21c")) {
+ model = OFDRM_MODEL_GXT2000;
+ } else if (of_node_name_prefix(of_node, "vga,Display-")) {
+ struct device_node *of_parent;
+ const __be32 *vendor_p, *device_p;
+
+ /* Look for AVIVO initialized by SLOF */
+ of_parent = of_get_parent(of_node);
+ vendor_p = of_get_property(of_parent, "vendor-id", NULL);
+ device_p = of_get_property(of_parent, "device-id", NULL);
+ if (vendor_p && device_p) {
+ u32 vendor = be32_to_cpup(vendor_p);
+ u32 device = be32_to_cpup(device_p);
+
+ if (is_avivo(vendor, device))
+ model = OFDRM_MODEL_AVIVO;
+ }
+ of_node_put(of_parent);
+ } else if (of_device_is_compatible(of_node, "qemu,std-vga")) {
+ model = OFDRM_MODEL_QEMU;
+ }
+
+ return model;
+}
+
+/*
+ * Open Firmware display device
+ */
+
+struct ofdrm_device;
+
+struct ofdrm_device_funcs {
+ void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_bas);
+ void (*cmap_write)(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b);
+};
+
+struct ofdrm_device {
+ struct drm_device dev;
+ struct platform_device *pdev;
+
+ const struct ofdrm_device_funcs *funcs;
+
+ /* firmware-buffer settings */
+ struct iosys_map screen_base;
+ struct drm_display_mode mode;
+ const struct drm_format_info *format;
+ unsigned int pitch;
+
+ /* colormap */
+ void __iomem *cmap_base;
+
+ /* modesetting */
+ uint32_t formats[8];
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev)
+{
+ return container_of(dev, struct ofdrm_device, dev);
+}
+
+/*
+ * Hardware
+ */
+
+#if defined(CONFIG_PCI)
+static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node)
+{
+ const __be32 *vendor_p, *device_p;
+ u32 vendor, device;
+ struct pci_dev *pcidev;
+
+ vendor_p = of_get_property(of_node, "vendor-id", NULL);
+ if (!vendor_p)
+ return ERR_PTR(-ENODEV);
+ vendor = be32_to_cpup(vendor_p);
+
+ device_p = of_get_property(of_node, "device-id", NULL);
+ if (!device_p)
+ return ERR_PTR(-ENODEV);
+ device = be32_to_cpup(device_p);
+
+ pcidev = pci_get_device(vendor, device, NULL);
+ if (!pcidev)
+ return ERR_PTR(-ENODEV);
+
+ return pcidev;
+}
+
+static void ofdrm_pci_release(void *data)
+{
+ struct pci_dev *pcidev = data;
+
+ pci_disable_device(pcidev);
+}
+
+static int ofdrm_device_init_pci(struct ofdrm_device *odev)
+{
+ struct drm_device *dev = &odev->dev;
+ struct platform_device *pdev = to_platform_device(dev->dev);
+ struct device_node *of_node = pdev->dev.of_node;
+ struct pci_dev *pcidev;
+ int ret;
+
+ /*
+ * Never use pcim_ or other managed helpers on the returned PCI
+ * device. Otherwise, probing the native driver will fail for
+ * resource conflicts. PCI-device management has to be tied to
+ * the lifetime of the platform device until the native driver
+ * takes over.
+ */
+ pcidev = display_get_pci_dev_of(dev, of_node);
+ if (IS_ERR(pcidev))
+ return 0; /* no PCI device found; ignore the error */
+
+ ret = pci_enable_device(pcidev);
+ if (ret) {
+ drm_err(dev, "pci_enable_device(%s) failed: %d\n",
+ dev_name(&pcidev->dev), ret);
+ return ret;
+ }
+ ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#else
+static int ofdrm_device_init_pci(struct ofdrm_device *odev)
+{
+ return 0;
+}
+#endif
+
+/*
+ * OF display settings
+ */
+
+static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev,
+ struct resource *fb_res)
+{
+ struct platform_device *pdev = to_platform_device(odev->dev.dev);
+ struct resource *res, *max_res = NULL;
+ u32 i;
+
+ for (i = 0; pdev->num_resources; ++i) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ break; /* all resources processed */
+ if (resource_size(res) < resource_size(fb_res))
+ continue; /* resource too small */
+ if (fb_res->start && resource_contains(res, fb_res))
+ return res; /* resource contains framebuffer */
+ if (!max_res || resource_size(res) > resource_size(max_res))
+ max_res = res; /* store largest resource as fallback */
+ }
+
+ return max_res;
+}
+
+/*
+ * Colormap / Palette
+ */
+
+static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node,
+ int bar_no, unsigned long offset, unsigned long size)
+{
+ struct drm_device *dev = &odev->dev;
+ const __be32 *addr_p;
+ u64 max_size, address;
+ unsigned int flags;
+ void __iomem *mem;
+
+ addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags);
+ if (!addr_p)
+ addr_p = of_get_address(of_node, bar_no, &max_size, &flags);
+ if (!addr_p)
+ return IOMEM_ERR_PTR(-ENODEV);
+
+ if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+ return IOMEM_ERR_PTR(-ENODEV);
+
+ if ((offset + size) >= max_size)
+ return IOMEM_ERR_PTR(-ENODEV);
+
+ address = of_translate_address(of_node, addr_p);
+ if (address == OF_BAD_ADDR)
+ return IOMEM_ERR_PTR(-ENODEV);
+
+ mem = devm_ioremap(dev->dev, address + offset, size);
+ if (!mem)
+ return IOMEM_ERR_PTR(-ENOMEM);
+
+ return mem;
+}
+
+static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ struct drm_device *dev = &odev->dev;
+ u64 address;
+ void __iomem *cmap_base;
+
+ address = fb_base & 0xff000000ul;
+ address += 0x7ff000;
+
+ cmap_base = devm_ioremap(dev->dev, address, 0x1000);
+ if (!cmap_base)
+ return IOMEM_ERR_PTR(-ENOMEM);
+
+ return cmap_base;
+}
+
+static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *addr = odev->cmap_base + 0xcc0;
+ void __iomem *data = odev->cmap_base + 0xcc0 + 1;
+
+ writeb(index, addr);
+ writeb(r, data);
+ writeb(g, data);
+ writeb(b, data);
+}
+
+static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
+}
+
+static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *addr = odev->cmap_base + 0xb0;
+ void __iomem *data = odev->cmap_base + 0xb4;
+ u32 color = (r << 16) | (g << 8) | b;
+
+ writeb(index, addr);
+ writel(color, data);
+}
+
+static void __iomem *ofdrm_rage_m3a_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
+}
+
+static void ofdrm_rage_m3a_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *dac_ctl = odev->cmap_base + 0x58;
+ void __iomem *addr = odev->cmap_base + 0xb0;
+ void __iomem *data = odev->cmap_base + 0xb4;
+ u32 color = (r << 16) | (g << 8) | b;
+ u32 val;
+
+ /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
+ val = readl(dac_ctl);
+ val &= ~0x20;
+ writel(val, dac_ctl);
+
+ /* Set color at palette index */
+ writeb(index, addr);
+ writel(color, data);
+}
+
+static void __iomem *ofdrm_rage_m3b_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
+}
+
+static void ofdrm_rage_m3b_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *dac_ctl = odev->cmap_base + 0x58;
+ void __iomem *addr = odev->cmap_base + 0xb0;
+ void __iomem *data = odev->cmap_base + 0xb4;
+ u32 color = (r << 16) | (g << 8) | b;
+ u32 val;
+
+ /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
+ val = readl(dac_ctl);
+ val |= 0x20;
+ writel(val, dac_ctl);
+
+ /* Set color at palette index */
+ writeb(index, addr);
+ writel(color, data);
+}
+
+static void __iomem *ofdrm_radeon_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ return get_cmap_address_of(odev, of_node, 1, 0, 0x1fff);
+}
+
+static void __iomem *ofdrm_gxt2000_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ return get_cmap_address_of(odev, of_node, 0, 0x6000, 0x1000);
+}
+
+static void ofdrm_gxt2000_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *data = ((unsigned int __iomem *)odev->cmap_base) + index;
+ u32 color = (r << 16) | (g << 8) | b;
+
+ writel(color, data);
+}
+
+static void __iomem *ofdrm_avivo_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ struct device_node *of_parent;
+ void __iomem *cmap_base;
+
+ of_parent = of_get_parent(of_node);
+ cmap_base = get_cmap_address_of(odev, of_parent, 0, 0, 0x10000);
+ of_node_put(of_parent);
+
+ return cmap_base;
+}
+
+static void ofdrm_avivo_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *lutsel = odev->cmap_base + AVIVO_DC_LUT_RW_SELECT;
+ void __iomem *addr = odev->cmap_base + AVIVO_DC_LUT_RW_INDEX;
+ void __iomem *data = odev->cmap_base + AVIVO_DC_LUT_30_COLOR;
+ u32 color = (r << 22) | (g << 12) | (b << 2);
+
+ /* Write to both LUTs for now */
+
+ writel(1, lutsel);
+ writeb(index, addr);
+ writel(color, data);
+
+ writel(0, lutsel);
+ writeb(index, addr);
+ writel(color, data);
+}
+
+static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev,
+ struct device_node *of_node,
+ u64 fb_base)
+{
+ static const __be32 io_of_addr[3] = {
+ cpu_to_be32(0x01000000),
+ cpu_to_be32(0x00),
+ cpu_to_be32(0x00),
+ };
+
+ struct drm_device *dev = &odev->dev;
+ u64 address;
+ void __iomem *cmap_base;
+
+ address = of_translate_address(of_node, io_of_addr);
+ if (address == OF_BAD_ADDR)
+ return IOMEM_ERR_PTR(-ENODEV);
+
+ cmap_base = devm_ioremap(dev->dev, address + 0x3c8, 2);
+ if (!cmap_base)
+ return IOMEM_ERR_PTR(-ENOMEM);
+
+ return cmap_base;
+}
+
+static void ofdrm_qemu_cmap_write(struct ofdrm_device *odev, unsigned char index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ void __iomem *addr = odev->cmap_base;
+ void __iomem *data = odev->cmap_base + 1;
+
+ writeb(index, addr);
+ writeb(r, data);
+ writeb(g, data);
+ writeb(b, data);
+}
+
+static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev,
+ const struct drm_format_info *format)
+{
+ struct drm_device *dev = &odev->dev;
+ int i;
+
+ switch (format->format) {
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN:
+ /* Use better interpolation, to take 32 values from 0 to 255 */
+ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) {
+ unsigned char r = i * 8 + i / 4;
+ unsigned char g = i * 4 + i / 16;
+ unsigned char b = i * 8 + i / 4;
+
+ odev->funcs->cmap_write(odev, i, r, g, b);
+ }
+ /* Green has one more bit, so add padding with 0 for red and blue. */
+ for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) {
+ unsigned char r = 0;
+ unsigned char g = i * 4 + i / 16;
+ unsigned char b = 0;
+
+ odev->funcs->cmap_write(odev, i, r, g, b);
+ }
+ break;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_BGRX8888:
+ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++)
+ odev->funcs->cmap_write(odev, i, i, i, i);
+ break;
+ default:
+ drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
+}
+
+static void ofdrm_device_set_gamma(struct ofdrm_device *odev,
+ const struct drm_format_info *format,
+ struct drm_color_lut *lut)
+{
+ struct drm_device *dev = &odev->dev;
+ int i;
+
+ switch (format->format) {
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN:
+ /* Use better interpolation, to take 32 values from lut[0] to lut[255] */
+ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) {
+ unsigned char r = lut[i * 8 + i / 4].red >> 8;
+ unsigned char g = lut[i * 4 + i / 16].green >> 8;
+ unsigned char b = lut[i * 8 + i / 4].blue >> 8;
+
+ odev->funcs->cmap_write(odev, i, r, g, b);
+ }
+ /* Green has one more bit, so add padding with 0 for red and blue. */
+ for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) {
+ unsigned char r = 0;
+ unsigned char g = lut[i * 4 + i / 16].green >> 8;
+ unsigned char b = 0;
+
+ odev->funcs->cmap_write(odev, i, r, g, b);
+ }
+ break;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_BGRX8888:
+ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) {
+ unsigned char r = lut[i].red >> 8;
+ unsigned char g = lut[i].green >> 8;
+ unsigned char b = lut[i].blue >> 8;
+
+ odev->funcs->cmap_write(odev, i, r, g, b);
+ }
+ break;
+ default:
+ drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
+}
+
+/*
+ * Modesetting
+ */
+
+struct ofdrm_crtc_state {
+ struct drm_crtc_state base;
+
+ /* Primary-plane format; required for color mgmt. */
+ const struct drm_format_info *format;
+};
+
+static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base)
+{
+ return container_of(base, struct ofdrm_crtc_state, base);
+}
+
+static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state)
+{
+ __drm_atomic_helper_crtc_destroy_state(&ofdrm_crtc_state->base);
+ kfree(ofdrm_crtc_state);
+}
+
+/*
+ * Support all formats of OF display and maybe more; in order
+ * of preference. The display's update function will do any
+ * conversion necessary.
+ *
+ * TODO: Add blit helpers for remaining formats and uncomment
+ * constants.
+ */
+static const uint32_t ofdrm_primary_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB565,
+ //DRM_FORMAT_XRGB1555,
+ //DRM_FORMAT_C8,
+ /* Big-endian formats below */
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN,
+};
+
+static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state)
+{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
+ struct drm_framebuffer *new_fb = new_plane_state->fb;
+ struct drm_crtc *new_crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_state = NULL;
+ struct ofdrm_crtc_state *new_ofdrm_crtc_state;
+ int ret;
+
+ if (new_crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
+
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+ if (ret)
+ return ret;
+ else if (!new_plane_state->visible)
+ return 0;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
+
+ new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state);
+ new_ofdrm_crtc_state->format = new_fb->format;
+
+ return 0;
+}
+
+static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ unsigned int dst_pitch = odev->pitch;
+ const struct drm_format_info *dst_format = odev->format;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_rect damage;
+ int ret, idx;
+
+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
+ if (ret)
+ return;
+
+ if (!drm_dev_enter(dev, &idx))
+ goto out_drm_gem_fb_end_cpu_access;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ struct iosys_map dst = odev->screen_base;
+ struct drm_rect dst_clip = plane_state->dst;
+
+ if (!drm_rect_intersect(&dst_clip, &damage))
+ continue;
+
+ iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
+ drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
+ &damage);
+ }
+
+ drm_dev_exit(idx);
+out_drm_gem_fb_end_cpu_access:
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+}
+
+static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
+ struct iosys_map dst = odev->screen_base;
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
+ unsigned int dst_pitch = odev->pitch;
+ const struct drm_format_info *dst_format = odev->format;
+ struct drm_rect dst_clip;
+ unsigned long lines, linepixels, i;
+ int idx;
+
+ drm_rect_init(&dst_clip,
+ plane_state->src_x >> 16, plane_state->src_y >> 16,
+ plane_state->src_w >> 16, plane_state->src_h >> 16);
+
+ lines = drm_rect_height(&dst_clip);
+ linepixels = drm_rect_width(&dst_clip);
+
+ if (!drm_dev_enter(dev, &idx))
+ return;
+
+ /* Clear buffer to black if disabled */
+ dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip);
+ for (i = 0; i < lines; ++i) {
+ memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]);
+ dst_vmap += dst_pitch;
+ }
+
+ drm_dev_exit(idx);
+}
+
+static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = {
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
+ .atomic_check = ofdrm_primary_plane_helper_atomic_check,
+ .atomic_update = ofdrm_primary_plane_helper_atomic_update,
+ .atomic_disable = ofdrm_primary_plane_helper_atomic_disable,
+};
+
+static const struct drm_plane_funcs ofdrm_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ DRM_GEM_SHADOW_PLANE_FUNCS,
+};
+
+static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
+
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &odev->mode);
+}
+
+static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const size_t gamma_lut_length = OFDRM_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut);
+
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ int ret;
+
+ if (!new_crtc_state->enable)
+ return 0;
+
+ ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
+ if (ret)
+ return ret;
+
+ if (new_crtc_state->color_mgmt_changed) {
+ struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut;
+
+ if (gamma_lut && (gamma_lut->length != gamma_lut_length)) {
+ drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+ struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ struct ofdrm_crtc_state *ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state);
+
+ if (crtc_state->enable && crtc_state->color_mgmt_changed) {
+ const struct drm_format_info *format = ofdrm_crtc_state->format;
+
+ if (crtc_state->gamma_lut)
+ ofdrm_device_set_gamma(odev, format, crtc_state->gamma_lut->data);
+ else
+ ofdrm_device_set_gamma_linear(odev, format);
+ }
+}
+
+/*
+ * The CRTC is always enabled. Screen updates are performed by
+ * the primary plane's atomic_update function. Disabling clears
+ * the screen in the primary plane's atomic_disable function.
+ */
+static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = {
+ .mode_valid = ofdrm_crtc_helper_mode_valid,
+ .atomic_check = ofdrm_crtc_helper_atomic_check,
+ .atomic_flush = ofdrm_crtc_helper_atomic_flush,
+};
+
+static void ofdrm_crtc_reset(struct drm_crtc *crtc)
+{
+ struct ofdrm_crtc_state *ofdrm_crtc_state =
+ kzalloc(sizeof(*ofdrm_crtc_state), GFP_KERNEL);
+
+ if (crtc->state)
+ ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc->state));
+
+ if (ofdrm_crtc_state)
+ __drm_atomic_helper_crtc_reset(crtc, &ofdrm_crtc_state->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
+}
+
+static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct ofdrm_crtc_state *new_ofdrm_crtc_state;
+ struct ofdrm_crtc_state *ofdrm_crtc_state;
+
+ if (drm_WARN_ON(dev, !crtc_state))
+ return NULL;
+
+ new_ofdrm_crtc_state = kzalloc(sizeof(*new_ofdrm_crtc_state), GFP_KERNEL);
+ if (!new_ofdrm_crtc_state)
+ return NULL;
+
+ ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state);
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base);
+ new_ofdrm_crtc_state->format = ofdrm_crtc_state->format;
+
+ return &new_ofdrm_crtc_state->base;
+}
+
+static void ofdrm_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc_state));
+}
+
+static const struct drm_crtc_funcs ofdrm_crtc_funcs = {
+ .reset = ofdrm_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = ofdrm_crtc_atomic_duplicate_state,
+ .atomic_destroy_state = ofdrm_crtc_atomic_destroy_state,
+};
+
+static int ofdrm_connector_helper_get_modes(struct drm_connector *connector)
+{
+ struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev);
+
+ return drm_connector_helper_get_modes_fixed(connector, &odev->mode);
+}
+
+static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = {
+ .get_modes = ofdrm_connector_helper_get_modes,
+};
+
+static const struct drm_connector_funcs ofdrm_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create_with_dirty,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+/*
+ * Init / Cleanup
+ */
+
+static const struct ofdrm_device_funcs ofdrm_unknown_device_funcs = {
+};
+
+static const struct ofdrm_device_funcs ofdrm_mach64_device_funcs = {
+ .cmap_ioremap = ofdrm_mach64_cmap_ioremap,
+ .cmap_write = ofdrm_mach64_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_rage128_device_funcs = {
+ .cmap_ioremap = ofdrm_rage128_cmap_ioremap,
+ .cmap_write = ofdrm_rage128_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_rage_m3a_device_funcs = {
+ .cmap_ioremap = ofdrm_rage_m3a_cmap_ioremap,
+ .cmap_write = ofdrm_rage_m3a_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_rage_m3b_device_funcs = {
+ .cmap_ioremap = ofdrm_rage_m3b_cmap_ioremap,
+ .cmap_write = ofdrm_rage_m3b_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_radeon_device_funcs = {
+ .cmap_ioremap = ofdrm_radeon_cmap_ioremap,
+ .cmap_write = ofdrm_rage128_cmap_write, /* same as Rage128 */
+};
+
+static const struct ofdrm_device_funcs ofdrm_gxt2000_device_funcs = {
+ .cmap_ioremap = ofdrm_gxt2000_cmap_ioremap,
+ .cmap_write = ofdrm_gxt2000_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_avivo_device_funcs = {
+ .cmap_ioremap = ofdrm_avivo_cmap_ioremap,
+ .cmap_write = ofdrm_avivo_cmap_write,
+};
+
+static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = {
+ .cmap_ioremap = ofdrm_qemu_cmap_ioremap,
+ .cmap_write = ofdrm_qemu_cmap_write,
+};
+
+static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height)
+{
+ /*
+ * Assume a monitor resolution of 96 dpi to
+ * get a somewhat reasonable screen size.
+ */
+ const struct drm_display_mode mode = {
+ DRM_MODE_INIT(60, width, height,
+ DRM_MODE_RES_MM(width, 96ul),
+ DRM_MODE_RES_MM(height, 96ul))
+ };
+
+ return mode;
+}
+
+static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
+ struct platform_device *pdev)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ struct ofdrm_device *odev;
+ struct drm_device *dev;
+ enum ofdrm_model model;
+ bool big_endian;
+ int width, height, depth, linebytes;
+ const struct drm_format_info *format;
+ u64 address;
+ resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize;
+ struct resource *res, *mem;
+ void __iomem *screen_base;
+ struct drm_plane *primary_plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ unsigned long max_width, max_height;
+ size_t nformats;
+ int ret;
+
+ odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, dev);
+ if (IS_ERR(odev))
+ return ERR_CAST(odev);
+ dev = &odev->dev;
+ platform_set_drvdata(pdev, dev);
+
+ ret = ofdrm_device_init_pci(odev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /*
+ * OF display-node settings
+ */
+
+ model = display_get_model_of(dev, of_node);
+ drm_dbg(dev, "detected model %d\n", model);
+
+ switch (model) {
+ case OFDRM_MODEL_UNKNOWN:
+ odev->funcs = &ofdrm_unknown_device_funcs;
+ break;
+ case OFDRM_MODEL_MACH64:
+ odev->funcs = &ofdrm_mach64_device_funcs;
+ break;
+ case OFDRM_MODEL_RAGE128:
+ odev->funcs = &ofdrm_rage128_device_funcs;
+ break;
+ case OFDRM_MODEL_RAGE_M3A:
+ odev->funcs = &ofdrm_rage_m3a_device_funcs;
+ break;
+ case OFDRM_MODEL_RAGE_M3B:
+ odev->funcs = &ofdrm_rage_m3b_device_funcs;
+ break;
+ case OFDRM_MODEL_RADEON:
+ odev->funcs = &ofdrm_radeon_device_funcs;
+ break;
+ case OFDRM_MODEL_GXT2000:
+ odev->funcs = &ofdrm_gxt2000_device_funcs;
+ break;
+ case OFDRM_MODEL_AVIVO:
+ odev->funcs = &ofdrm_avivo_device_funcs;
+ break;
+ case OFDRM_MODEL_QEMU:
+ odev->funcs = &ofdrm_qemu_device_funcs;
+ break;
+ }
+
+ big_endian = display_get_big_endian_of(dev, of_node);
+
+ width = display_get_width_of(dev, of_node);
+ if (width < 0)
+ return ERR_PTR(width);
+ height = display_get_height_of(dev, of_node);
+ if (height < 0)
+ return ERR_PTR(height);
+ depth = display_get_depth_of(dev, of_node);
+ if (depth < 0)
+ return ERR_PTR(depth);
+ linebytes = display_get_linebytes_of(dev, of_node);
+ if (linebytes < 0)
+ return ERR_PTR(linebytes);
+
+ format = display_get_validated_format(dev, depth, big_endian);
+ if (IS_ERR(format))
+ return ERR_CAST(format);
+ if (!linebytes) {
+ linebytes = drm_format_info_min_pitch(format, 0, width);
+ if (drm_WARN_ON(dev, !linebytes))
+ return ERR_PTR(-EINVAL);
+ }
+
+ fb_size = linebytes * height;
+
+ /*
+ * Try to figure out the address of the framebuffer. Unfortunately, Open
+ * Firmware doesn't provide a standard way to do so. All we can do is a
+ * dodgy heuristic that happens to work in practice.
+ *
+ * On most machines, the "address" property contains what we need, though
+ * not on Matrox cards found in IBM machines. What appears to give good
+ * results is to go through the PCI ranges and pick one that encloses the
+ * "address" property. If none match, we pick the largest.
+ */
+ address = display_get_address_of(dev, of_node);
+ if (address != OF_BAD_ADDR) {
+ struct resource fb_res = DEFINE_RES_MEM(address, fb_size);
+
+ res = ofdrm_find_fb_resource(odev, &fb_res);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+ if (resource_contains(res, &fb_res))
+ fb_base = address;
+ else
+ fb_base = res->start;
+ } else {
+ struct resource fb_res = DEFINE_RES_MEM(0u, fb_size);
+
+ res = ofdrm_find_fb_resource(odev, &fb_res);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+ fb_base = res->start;
+ }
+
+ /*
+ * I/O resources
+ */
+
+ fb_pgbase = round_down(fb_base, PAGE_SIZE);
+ fb_pgsize = fb_base - fb_pgbase + round_up(fb_size, PAGE_SIZE);
+
+ ret = devm_aperture_acquire_from_firmware(dev, fb_pgbase, fb_pgsize);
+ if (ret) {
+ drm_err(dev, "could not acquire memory range %pr: error %d\n", &res, ret);
+ return ERR_PTR(ret);
+ }
+
+ mem = devm_request_mem_region(&pdev->dev, fb_pgbase, fb_pgsize, drv->name);
+ if (!mem) {
+ drm_warn(dev, "could not acquire memory region %pr\n", &res);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!screen_base)
+ return ERR_PTR(-ENOMEM);
+
+ if (odev->funcs->cmap_ioremap) {
+ void __iomem *cmap_base = odev->funcs->cmap_ioremap(odev, of_node, fb_base);
+
+ if (IS_ERR(cmap_base)) {
+ /* Don't fail; continue without colormap */
+ drm_warn(dev, "could not find colormap: error %ld\n", PTR_ERR(cmap_base));
+ } else {
+ odev->cmap_base = cmap_base;
+ }
+ }
+
+ /*
+ * Firmware framebuffer
+ */
+
+ iosys_map_set_vaddr_iomem(&odev->screen_base, screen_base);
+ odev->mode = ofdrm_mode(width, height);
+ odev->format = format;
+ odev->pitch = linebytes;
+
+ drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&odev->mode));
+ drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
+ &format->format, width, height, linebytes);
+
+ /*
+ * Mode-setting pipeline
+ */
+
+ ret = drmm_mode_config_init(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH);
+ max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT);
+
+ dev->mode_config.min_width = width;
+ dev->mode_config.max_width = max_width;
+ dev->mode_config.min_height = height;
+ dev->mode_config.max_height = max_height;
+ dev->mode_config.funcs = &ofdrm_mode_config_funcs;
+ switch (depth) {
+ case 32:
+ dev->mode_config.preferred_depth = 24;
+ break;
+ default:
+ dev->mode_config.preferred_depth = depth;
+ break;
+ }
+ dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
+
+ /* Primary plane */
+
+ nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
+ ofdrm_primary_plane_formats,
+ ARRAY_SIZE(ofdrm_primary_plane_formats),
+ odev->formats, ARRAY_SIZE(odev->formats));
+
+ primary_plane = &odev->primary_plane;
+ ret = drm_universal_plane_init(dev, primary_plane, 0, &ofdrm_primary_plane_funcs,
+ odev->formats, nformats,
+ ofdrm_primary_plane_format_modifiers,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_plane_helper_add(primary_plane, &ofdrm_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ /* CRTC */
+
+ crtc = &odev->crtc;
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &ofdrm_crtc_funcs, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs);
+
+ if (odev->cmap_base) {
+ drm_mode_crtc_set_gamma_size(crtc, OFDRM_GAMMA_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, OFDRM_GAMMA_LUT_SIZE);
+ }
+
+ /* Encoder */
+
+ encoder = &odev->encoder;
+ ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
+ if (ret)
+ return ERR_PTR(ret);
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ /* Connector */
+
+ connector = &odev->connector;
+ ret = drm_connector_init(dev, connector, &ofdrm_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs);
+ drm_connector_set_panel_orientation_with_quirk(connector,
+ DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+ width, height);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
+ return odev;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(ofdrm_fops);
+
+static struct drm_driver ofdrm_driver = {
+ DRM_GEM_SHMEM_DRIVER_OPS,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+ .fops = &ofdrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int ofdrm_probe(struct platform_device *pdev)
+{
+ struct ofdrm_device *odev;
+ struct drm_device *dev;
+ int ret;
+
+ odev = ofdrm_device_create(&ofdrm_driver, pdev);
+ if (IS_ERR(odev))
+ return PTR_ERR(odev);
+ dev = &odev->dev;
+
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+ return ret;
+
+ /*
+ * FIXME: 24-bit color depth does not work reliably with a 32-bpp
+ * value. Force the bpp value of the scanout buffer's format.
+ */
+ drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0));
+
+ return 0;
+}
+
+static int ofdrm_remove(struct platform_device *pdev)
+{
+ struct drm_device *dev = platform_get_drvdata(pdev);
+
+ drm_dev_unplug(dev);
+
+ return 0;
+}
+
+static const struct of_device_id ofdrm_of_match_display[] = {
+ { .compatible = "display", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ofdrm_of_match_display);
+
+static struct platform_driver ofdrm_platform_driver = {
+ .driver = {
+ .name = "of-display",
+ .of_match_table = ofdrm_of_match_display,
+ },
+ .probe = ofdrm_probe,
+ .remove = ofdrm_remove,
+};
+
+module_platform_driver(ofdrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
index 955a61d628e7..03a7d569cd56 100644
--- a/drivers/gpu/drm/tiny/panel-mipi-dbi.c
+++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c
index e62f4d16b2c6..c2677d081a7b 100644
--- a/drivers/gpu/drm/tiny/repaper.c
+++ b/drivers/gpu/drm/tiny/repaper.c
@@ -26,7 +26,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 18489779fb8a..162eb44dcba8 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -11,10 +11,11 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_connector.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -545,19 +546,6 @@ static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *cr
return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode);
}
-static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *new_state)
-{
- struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
- int ret;
-
- ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false);
- if (ret)
- return ret;
-
- return drm_atomic_add_affected_planes(new_state, crtc);
-}
-
/*
* The CRTC is always enabled. Screen updates are performed by
* the primary plane's atomic_update function. Disabling clears
@@ -565,7 +553,7 @@ static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
*/
static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = {
.mode_valid = simpledrm_crtc_helper_mode_valid,
- .atomic_check = simpledrm_crtc_helper_atomic_check,
+ .atomic_check = drm_crtc_helper_atomic_check,
};
static const struct drm_crtc_funcs simpledrm_crtc_funcs = {
diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c
index b6f620b902e6..ce57fa9917e5 100644
--- a/drivers/gpu/drm/tiny/st7586.c
+++ b/drivers/gpu/drm/tiny/st7586.c
@@ -16,7 +16,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c
index c36ba08acda1..15d9cf283c66 100644
--- a/drivers/gpu/drm/tiny/st7735r.c
+++ b/drivers/gpu/drm/tiny/st7735r.c
@@ -18,7 +18,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 7c8e8be774f1..c3f4b33136e5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -51,9 +51,6 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
struct ttm_resource_manager *man;
int i, mem_type;
- drm_printf(&p, "No space for %p (%lu pages, %zuK, %zuM)\n",
- bo, bo->resource->num_pages, bo->base.size >> 10,
- bo->base.size >> 20);
for (i = 0; i < placement->num_placement; i++) {
mem_type = placement->placement[i].mem_type;
drm_printf(&p, " placement[%d]=0x%08X (%d)\n",
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index fa04e62202c1..ba3aa0a0fc43 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -173,7 +173,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
clear = src_iter->ops->maps_tt && (!ttm || !ttm_tt_is_populated(ttm));
if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC)))
- ttm_move_memcpy(clear, dst_mem->num_pages, dst_iter, src_iter);
+ ttm_move_memcpy(clear, ttm->num_pages, dst_iter, src_iter);
if (!src_iter->ops->maps_tt)
ttm_kmap_iter_linear_io_fini(&_src_iter.io, bdev, src_mem);
@@ -357,9 +357,9 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
map->virtual = NULL;
map->bo = bo;
- if (num_pages > bo->resource->num_pages)
+ if (num_pages > PFN_UP(bo->resource->size))
return -EINVAL;
- if ((start_page + num_pages) > bo->resource->num_pages)
+ if ((start_page + num_pages) > PFN_UP(bo->resource->size))
return -EINVAL;
ret = ttm_mem_io_reserve(bo->bdev, bo->resource);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 38119311284d..5a3e4b891377 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -217,7 +217,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
page_last = vma_pages(vma) + vma->vm_pgoff -
drm_vma_node_start(&bo->base.vma_node);
- if (unlikely(page_offset >= bo->resource->num_pages))
+ if (unlikely(page_offset >= PFN_UP(bo->base.size)))
return VM_FAULT_SIGBUS;
prot = ttm_io_prot(bo, bo->resource, prot);
@@ -412,7 +412,7 @@ int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
<< PAGE_SHIFT);
int ret;
- if (len < 1 || (offset + len) >> PAGE_SHIFT > bo->resource->num_pages)
+ if (len < 1 || (offset + len) > bo->base.size)
return -EIO;
ret = ttm_bo_reserve(bo, true, false, NULL);
diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index 21b61631f73a..9f6764bf3b15 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -344,6 +344,28 @@ static unsigned int ttm_pool_page_order(struct ttm_pool *pool, struct page *p)
return p->private;
}
+/* Called when we got a page, either from a pool or newly allocated */
+static int ttm_pool_page_allocated(struct ttm_pool *pool, unsigned int order,
+ struct page *p, dma_addr_t **dma_addr,
+ unsigned long *num_pages,
+ struct page ***pages)
+{
+ unsigned int i;
+ int r;
+
+ if (*dma_addr) {
+ r = ttm_pool_map(pool, order, p, dma_addr);
+ if (r)
+ return r;
+ }
+
+ *num_pages -= 1 << order;
+ for (i = 1 << order; i; --i, ++(*pages), ++p)
+ **pages = p;
+
+ return 0;
+}
+
/**
* ttm_pool_alloc - Fill a ttm_tt object
*
@@ -385,45 +407,57 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt,
for (order = min_t(unsigned int, MAX_ORDER - 1, __fls(num_pages));
num_pages;
order = min_t(unsigned int, order, __fls(num_pages))) {
- bool apply_caching = false;
struct ttm_pool_type *pt;
pt = ttm_pool_select_type(pool, tt->caching, order);
p = pt ? ttm_pool_type_take(pt) : NULL;
if (p) {
- apply_caching = true;
- } else {
- p = ttm_pool_alloc_page(pool, gfp_flags, order);
- if (p && PageHighMem(p))
- apply_caching = true;
- }
-
- if (!p) {
- if (order) {
- --order;
- continue;
- }
- r = -ENOMEM;
- goto error_free_all;
- }
-
- if (apply_caching) {
r = ttm_pool_apply_caching(caching, pages,
tt->caching);
if (r)
goto error_free_page;
- caching = pages + (1 << order);
+
+ do {
+ r = ttm_pool_page_allocated(pool, order, p,
+ &dma_addr,
+ &num_pages,
+ &pages);
+ if (r)
+ goto error_free_page;
+
+ if (num_pages < (1 << order))
+ break;
+
+ p = ttm_pool_type_take(pt);
+ } while (p);
+ caching = pages;
}
- if (dma_addr) {
- r = ttm_pool_map(pool, order, p, &dma_addr);
+ while (num_pages >= (1 << order) &&
+ (p = ttm_pool_alloc_page(pool, gfp_flags, order))) {
+
+ if (PageHighMem(p)) {
+ r = ttm_pool_apply_caching(caching, pages,
+ tt->caching);
+ if (r)
+ goto error_free_page;
+ }
+ r = ttm_pool_page_allocated(pool, order, p, &dma_addr,
+ &num_pages, &pages);
if (r)
goto error_free_page;
+ if (PageHighMem(p))
+ caching = pages;
}
- num_pages -= 1 << order;
- for (i = 1 << order; i; --i)
- *(pages++) = p++;
+ if (!p) {
+ if (order) {
+ --order;
+ continue;
+ }
+ r = -ENOMEM;
+ goto error_free_all;
+ }
}
r = ttm_pool_apply_caching(caching, pages, tt->caching);
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index 4cfef2b3514d..0a8bc0b7f380 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -83,7 +83,7 @@ static int ttm_range_man_alloc(struct ttm_resource_manager *man,
spin_lock(&rman->lock);
ret = drm_mm_insert_node_in_range(mm, &node->mm_nodes[0],
- node->base.num_pages,
+ PFN_UP(node->base.size),
bo->page_alignment, 0,
place->fpfn, lpfn, mode);
spin_unlock(&rman->lock);
@@ -229,7 +229,6 @@ int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
return ret;
spin_lock(&rman->lock);
- drm_mm_clean(mm);
drm_mm_takedown(mm);
spin_unlock(&rman->lock);
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index a729c32a1e48..328391bb1d87 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -177,7 +177,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo,
struct ttm_resource_manager *man;
res->start = 0;
- res->num_pages = PFN_UP(bo->base.size);
+ res->size = bo->base.size;
res->mem_type = place->mem_type;
res->placement = place->flags;
res->bus.addr = NULL;
@@ -192,7 +192,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo,
list_add_tail(&res->lru, &bo->bdev->pinned);
else
list_add_tail(&res->lru, &man->lru[bo->priority]);
- man->usage += res->num_pages << PAGE_SHIFT;
+ man->usage += res->size;
spin_unlock(&bo->bdev->lru_lock);
}
EXPORT_SYMBOL(ttm_resource_init);
@@ -214,7 +214,7 @@ void ttm_resource_fini(struct ttm_resource_manager *man,
spin_lock(&bdev->lru_lock);
list_del_init(&res->lru);
- man->usage -= res->num_pages << PAGE_SHIFT;
+ man->usage -= res->size;
spin_unlock(&bdev->lru_lock);
}
EXPORT_SYMBOL(ttm_resource_fini);
@@ -665,17 +665,15 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io,
iosys_map_set_vaddr(&iter_io->dmap, mem->bus.addr);
iter_io->needs_unmap = false;
} else {
- size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
-
iter_io->needs_unmap = true;
memset(&iter_io->dmap, 0, sizeof(iter_io->dmap));
if (mem->bus.caching == ttm_write_combined)
iosys_map_set_vaddr_iomem(&iter_io->dmap,
ioremap_wc(mem->bus.offset,
- bus_size));
+ mem->size));
else if (mem->bus.caching == ttm_cached)
iosys_map_set_vaddr(&iter_io->dmap,
- memremap(mem->bus.offset, bus_size,
+ memremap(mem->bus.offset, mem->size,
MEMREMAP_WB |
MEMREMAP_WT |
MEMREMAP_WC));
@@ -684,7 +682,7 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io,
if (iosys_map_is_null(&iter_io->dmap))
iosys_map_set_vaddr_iomem(&iter_io->dmap,
ioremap(mem->bus.offset,
- bus_size));
+ mem->size));
if (iosys_map_is_null(&iter_io->dmap)) {
ret = -ENOMEM;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 04db72e3fa9c..0d05c386d303 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -32,6 +32,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
@@ -39,7 +40,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile
index 24d61f61d7db..3f6db179455d 100644
--- a/drivers/gpu/drm/udl/Makefile
+++ b/drivers/gpu/drm/udl/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_main.o udl_transfer.o
+udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o
obj-$(CONFIG_DRM_UDL) := udl.o
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
deleted file mode 100644
index fade4c7adbf7..000000000000
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ /dev/null
@@ -1,139 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2012 Red Hat
- * based in parts on udlfb.c:
- * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
- * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
- * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
- */
-
-#include <drm/drm_atomic_state_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_probe_helper.h>
-
-#include "udl_connector.h"
-#include "udl_drv.h"
-
-static int udl_get_edid_block(void *data, u8 *buf, unsigned int block,
- size_t len)
-{
- int ret, i;
- u8 *read_buff;
- struct udl_device *udl = data;
- struct usb_device *udev = udl_to_usb_device(udl);
-
- read_buff = kmalloc(2, GFP_KERNEL);
- if (!read_buff)
- return -1;
-
- for (i = 0; i < len; i++) {
- int bval = (i + block * EDID_LENGTH) << 8;
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0x02, (0x80 | (0x02 << 5)), bval,
- 0xA1, read_buff, 2, 1000);
- if (ret < 1) {
- DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
- kfree(read_buff);
- return -1;
- }
- buf[i] = read_buff[1];
- }
-
- kfree(read_buff);
- return 0;
-}
-
-static int udl_get_modes(struct drm_connector *connector)
-{
- struct udl_drm_connector *udl_connector =
- container_of(connector,
- struct udl_drm_connector,
- connector);
-
- drm_connector_update_edid_property(connector, udl_connector->edid);
- if (udl_connector->edid)
- return drm_add_edid_modes(connector, udl_connector->edid);
- return 0;
-}
-
-static enum drm_mode_status udl_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct udl_device *udl = to_udl(connector->dev);
- if (!udl->sku_pixel_limit)
- return 0;
-
- if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit)
- return MODE_VIRTUAL_Y;
-
- return 0;
-}
-
-static enum drm_connector_status
-udl_detect(struct drm_connector *connector, bool force)
-{
- struct udl_device *udl = to_udl(connector->dev);
- struct udl_drm_connector *udl_connector =
- container_of(connector,
- struct udl_drm_connector,
- connector);
-
- /* cleanup previous edid */
- if (udl_connector->edid != NULL) {
- kfree(udl_connector->edid);
- udl_connector->edid = NULL;
- }
-
- udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl);
- if (!udl_connector->edid)
- return connector_status_disconnected;
-
- return connector_status_connected;
-}
-
-static void udl_connector_destroy(struct drm_connector *connector)
-{
- struct udl_drm_connector *udl_connector =
- container_of(connector,
- struct udl_drm_connector,
- connector);
-
- drm_connector_cleanup(connector);
- kfree(udl_connector->edid);
- kfree(connector);
-}
-
-static const struct drm_connector_helper_funcs udl_connector_helper_funcs = {
- .get_modes = udl_get_modes,
- .mode_valid = udl_mode_valid,
-};
-
-static const struct drm_connector_funcs udl_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .detect = udl_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = udl_connector_destroy,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-struct drm_connector *udl_connector_init(struct drm_device *dev)
-{
- struct udl_drm_connector *udl_connector;
- struct drm_connector *connector;
-
- udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL);
- if (!udl_connector)
- return ERR_PTR(-ENOMEM);
-
- connector = &udl_connector->connector;
- drm_connector_init(dev, connector, &udl_connector_funcs,
- DRM_MODE_CONNECTOR_VGA);
- drm_connector_helper_add(connector, &udl_connector_helper_funcs);
-
- connector->polled = DRM_CONNECTOR_POLL_HPD |
- DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
-
- return connector;
-}
diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h
deleted file mode 100644
index 7f2d392df173..000000000000
--- a/drivers/gpu/drm/udl/udl_connector.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __UDL_CONNECTOR_H__
-#define __UDL_CONNECTOR_H__
-
-#include <drm/drm_crtc.h>
-
-struct edid;
-
-struct udl_drm_connector {
- struct drm_connector connector;
- /* last udl_detect edid */
- struct edid *edid;
-};
-
-
-#endif //__UDL_CONNECTOR_H__
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 91effdcefb6d..e81352126a0f 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -7,7 +7,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index b4cc7cc568c7..282ebd6c02fd 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -14,10 +14,13 @@
#include <linux/mm_types.h>
#include <linux/usb.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
-#include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_plane.h>
struct drm_mode_create_dumb;
@@ -46,21 +49,31 @@ struct urb_list {
size_t size;
};
+struct udl_connector {
+ struct drm_connector connector;
+ /* last udl_detect edid */
+ struct edid *edid;
+};
+
+static inline struct udl_connector *to_udl_connector(struct drm_connector *connector)
+{
+ return container_of(connector, struct udl_connector, connector);
+}
+
struct udl_device {
struct drm_device drm;
struct device *dev;
struct device *dmadev;
- struct drm_simple_display_pipe display_pipe;
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
struct mutex gem_lock;
int sku_pixel_limit;
struct urb_list urbs;
-
- char mode_buf[1024];
- uint32_t mode_buf_len;
};
#define to_udl(x) container_of(x, struct udl_device, drm)
@@ -89,23 +102,4 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
int udl_drop_usb(struct drm_device *dev);
int udl_select_std_channel(struct udl_device *udl);
-#define CMD_WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */
-#define CMD_WRITE_RL8 "\xAF\x61" /**< 8 bit run length command. */
-#define CMD_WRITE_COPY8 "\xAF\x62" /**< 8 bit copy command. */
-#define CMD_WRITE_RLX8 "\xAF\x63" /**< 8 bit extended run length command. */
-
-#define CMD_WRITE_RAW16 "\xAF\x68" /**< 16 bit raw write command. */
-#define CMD_WRITE_RL16 "\xAF\x69" /**< 16 bit run length command. */
-#define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */
-#define CMD_WRITE_RLX16 "\xAF\x6B" /**< 16 bit extended run length command. */
-
-/* On/Off for driving the DisplayLink framebuffer to the display */
-#define UDL_REG_BLANK_MODE 0x1f
-
-#define UDL_BLANK_MODE_ON 0x00 /* hsync and vsync on, visible */
-#define UDL_BLANK_MODE_BLANKED 0x01 /* hsync and vsync on, blanked */
-#define UDL_BLANK_MODE_VSYNC_OFF 0x03 /* vsync off, blanked */
-#define UDL_BLANK_MODE_HSYNC_OFF 0x05 /* hsync off, blanked */
-#define UDL_BLANK_MODE_POWERDOWN 0x07 /* powered off; requires modeset */
-
#endif
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index ec6876f449f3..4b79d44752c9 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -8,70 +8,91 @@
* Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
*/
+#include <linux/bitfield.h>
+
+#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "udl_drv.h"
-
-#define UDL_COLOR_DEPTH_16BPP 0
+#include "udl_proto.h"
/*
- * All DisplayLink bulk operations start with 0xAF, followed by specific code
- * All operations are written to buffers which then later get sent to device
+ * All DisplayLink bulk operations start with 0xaf (UDL_MSG_BULK), followed by
+ * a specific command code. All operations are written to a command buffer, which
+ * the driver sends to the device.
*/
static char *udl_set_register(char *buf, u8 reg, u8 val)
{
- *buf++ = 0xAF;
- *buf++ = 0x20;
+ *buf++ = UDL_MSG_BULK;
+ *buf++ = UDL_CMD_WRITEREG;
*buf++ = reg;
*buf++ = val;
+
return buf;
}
static char *udl_vidreg_lock(char *buf)
{
- return udl_set_register(buf, 0xFF, 0x00);
+ return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_LOCK);
}
static char *udl_vidreg_unlock(char *buf)
{
- return udl_set_register(buf, 0xFF, 0xFF);
+ return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_UNLOCK);
}
static char *udl_set_blank_mode(char *buf, u8 mode)
{
- return udl_set_register(buf, UDL_REG_BLANK_MODE, mode);
+ return udl_set_register(buf, UDL_REG_BLANKMODE, mode);
}
static char *udl_set_color_depth(char *buf, u8 selection)
{
- return udl_set_register(buf, 0x00, selection);
+ return udl_set_register(buf, UDL_REG_COLORDEPTH, selection);
}
-static char *udl_set_base16bpp(char *wrptr, u32 base)
+static char *udl_set_base16bpp(char *buf, u32 base)
{
- /* the base pointer is 16 bits wide, 0x20 is hi byte. */
- wrptr = udl_set_register(wrptr, 0x20, base >> 16);
- wrptr = udl_set_register(wrptr, 0x21, base >> 8);
- return udl_set_register(wrptr, 0x22, base);
+ /* the base pointer is 24 bits wide, 0x20 is hi byte. */
+ u8 reg20 = FIELD_GET(UDL_BASE_ADDR2_MASK, base);
+ u8 reg21 = FIELD_GET(UDL_BASE_ADDR1_MASK, base);
+ u8 reg22 = FIELD_GET(UDL_BASE_ADDR0_MASK, base);
+
+ buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR2, reg20);
+ buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR1, reg21);
+ buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR0, reg22);
+
+ return buf;
}
/*
* DisplayLink HW has separate 16bpp and 8bpp framebuffers.
* In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
*/
-static char *udl_set_base8bpp(char *wrptr, u32 base)
+static char *udl_set_base8bpp(char *buf, u32 base)
{
- wrptr = udl_set_register(wrptr, 0x26, base >> 16);
- wrptr = udl_set_register(wrptr, 0x27, base >> 8);
- return udl_set_register(wrptr, 0x28, base);
+ /* the base pointer is 24 bits wide, 0x26 is hi byte. */
+ u8 reg26 = FIELD_GET(UDL_BASE_ADDR2_MASK, base);
+ u8 reg27 = FIELD_GET(UDL_BASE_ADDR1_MASK, base);
+ u8 reg28 = FIELD_GET(UDL_BASE_ADDR0_MASK, base);
+
+ buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR2, reg26);
+ buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR1, reg27);
+ buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR0, reg28);
+
+ return buf;
}
static char *udl_set_register_16(char *wrptr, u8 reg, u16 value)
@@ -122,84 +143,46 @@ static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
}
/*
- * This takes a standard fbdev screeninfo struct and all of its monitor mode
- * details and converts them into the DisplayLink equivalent register commands.
- ERR(vreg(dev, 0x00, (color_depth == 16) ? 0 : 1));
- ERR(vreg_lfsr16(dev, 0x01, xDisplayStart));
- ERR(vreg_lfsr16(dev, 0x03, xDisplayEnd));
- ERR(vreg_lfsr16(dev, 0x05, yDisplayStart));
- ERR(vreg_lfsr16(dev, 0x07, yDisplayEnd));
- ERR(vreg_lfsr16(dev, 0x09, xEndCount));
- ERR(vreg_lfsr16(dev, 0x0B, hSyncStart));
- ERR(vreg_lfsr16(dev, 0x0D, hSyncEnd));
- ERR(vreg_big_endian(dev, 0x0F, hPixels));
- ERR(vreg_lfsr16(dev, 0x11, yEndCount));
- ERR(vreg_lfsr16(dev, 0x13, vSyncStart));
- ERR(vreg_lfsr16(dev, 0x15, vSyncEnd));
- ERR(vreg_big_endian(dev, 0x17, vPixels));
- ERR(vreg_little_endian(dev, 0x1B, pixelClock5KHz));
-
- ERR(vreg(dev, 0x1F, 0));
-
- ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK)));
+ * Takes a DRM display mode and converts it into the DisplayLink
+ * equivalent register commands.
*/
-static char *udl_set_vid_cmds(char *wrptr, struct drm_display_mode *mode)
+static char *udl_set_display_mode(char *buf, struct drm_display_mode *mode)
{
- u16 xds, yds;
- u16 xde, yde;
- u16 yec;
-
- /* x display start */
- xds = mode->crtc_htotal - mode->crtc_hsync_start;
- wrptr = udl_set_register_lfsr16(wrptr, 0x01, xds);
- /* x display end */
- xde = xds + mode->crtc_hdisplay;
- wrptr = udl_set_register_lfsr16(wrptr, 0x03, xde);
-
- /* y display start */
- yds = mode->crtc_vtotal - mode->crtc_vsync_start;
- wrptr = udl_set_register_lfsr16(wrptr, 0x05, yds);
- /* y display end */
- yde = yds + mode->crtc_vdisplay;
- wrptr = udl_set_register_lfsr16(wrptr, 0x07, yde);
-
- /* x end count is active + blanking - 1 */
- wrptr = udl_set_register_lfsr16(wrptr, 0x09,
- mode->crtc_htotal - 1);
+ u16 reg01 = mode->crtc_htotal - mode->crtc_hsync_start;
+ u16 reg03 = reg01 + mode->crtc_hdisplay;
+ u16 reg05 = mode->crtc_vtotal - mode->crtc_vsync_start;
+ u16 reg07 = reg05 + mode->crtc_vdisplay;
+ u16 reg09 = mode->crtc_htotal - 1;
+ u16 reg0b = 1; /* libdlo hardcodes hsync start to 1 */
+ u16 reg0d = mode->crtc_hsync_end - mode->crtc_hsync_start + 1;
+ u16 reg0f = mode->hdisplay;
+ u16 reg11 = mode->crtc_vtotal;
+ u16 reg13 = 0; /* libdlo hardcodes vsync start to 0 */
+ u16 reg15 = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ u16 reg17 = mode->crtc_vdisplay;
+ u16 reg1b = mode->clock / 5;
+
+ buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYSTART, reg01);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYEND, reg03);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYSTART, reg05);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYEND, reg07);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_XENDCOUNT, reg09);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCSTART, reg0b);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCEND, reg0d);
+ buf = udl_set_register_16(buf, UDL_REG_HPIXELS, reg0f);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_YENDCOUNT, reg11);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCSTART, reg13);
+ buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCEND, reg15);
+ buf = udl_set_register_16(buf, UDL_REG_VPIXELS, reg17);
+ buf = udl_set_register_16be(buf, UDL_REG_PIXELCLOCK5KHZ, reg1b);
- /* libdlo hardcodes hsync start to 1 */
- wrptr = udl_set_register_lfsr16(wrptr, 0x0B, 1);
-
- /* hsync end is width of sync pulse + 1 */
- wrptr = udl_set_register_lfsr16(wrptr, 0x0D,
- mode->crtc_hsync_end - mode->crtc_hsync_start + 1);
-
- /* hpixels is active pixels */
- wrptr = udl_set_register_16(wrptr, 0x0F, mode->hdisplay);
-
- /* yendcount is vertical active + vertical blanking */
- yec = mode->crtc_vtotal;
- wrptr = udl_set_register_lfsr16(wrptr, 0x11, yec);
-
- /* libdlo hardcodes vsync start to 0 */
- wrptr = udl_set_register_lfsr16(wrptr, 0x13, 0);
-
- /* vsync end is width of vsync pulse */
- wrptr = udl_set_register_lfsr16(wrptr, 0x15, mode->crtc_vsync_end - mode->crtc_vsync_start);
-
- /* vpixels is active pixels */
- wrptr = udl_set_register_16(wrptr, 0x17, mode->crtc_vdisplay);
-
- wrptr = udl_set_register_16be(wrptr, 0x1B,
- mode->clock / 5);
-
- return wrptr;
+ return buf;
}
static char *udl_dummy_render(char *wrptr)
{
- *wrptr++ = 0xAF;
- *wrptr++ = 0x6A; /* copy */
+ *wrptr++ = UDL_MSG_BULK;
+ *wrptr++ = UDL_CMD_WRITECOPY16;
*wrptr++ = 0x00; /* from addr */
*wrptr++ = 0x00;
*wrptr++ = 0x00;
@@ -210,31 +193,6 @@ static char *udl_dummy_render(char *wrptr)
return wrptr;
}
-static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct udl_device *udl = to_udl(dev);
- struct urb *urb;
- char *buf;
- int retval;
-
- if (udl->mode_buf_len == 0) {
- DRM_ERROR("No mode set\n");
- return -EINVAL;
- }
-
- urb = udl_get_urb(dev);
- if (!urb)
- return -ENOMEM;
-
- buf = (char *)urb->transfer_buffer;
-
- memcpy(buf, udl->mode_buf, udl->mode_buf_len);
- retval = udl_submit_urb(dev, urb, udl->mode_buf_len);
- DRM_DEBUG("write mode info %d\n", udl->mode_buf_len);
- return retval;
-}
-
static long udl_log_cpp(unsigned int cpp)
{
if (WARN_ON(!is_power_of_2(cpp)))
@@ -258,15 +216,9 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
return ret;
log_bpp = ret;
- ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
- if (ret)
- return ret;
-
urb = udl_get_urb(dev);
- if (!urb) {
- ret = -ENOMEM;
- goto out_drm_gem_fb_end_cpu_access;
- }
+ if (!urb)
+ return -ENOMEM;
cmd = urb->transfer_buffer;
for (i = clip->y1; i < clip->y2; i++) {
@@ -278,145 +230,339 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
&cmd, byte_offset, dev_byte_offset,
byte_width);
if (ret)
- goto out_drm_gem_fb_end_cpu_access;
+ return ret;
}
if (cmd > (char *)urb->transfer_buffer) {
/* Send partial buffer remaining before exiting */
int len;
if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length)
- *cmd++ = 0xAF;
+ *cmd++ = UDL_MSG_BULK;
len = cmd - (char *)urb->transfer_buffer;
ret = udl_submit_urb(dev, urb, len);
} else {
udl_urb_completion(urb);
}
- ret = 0;
-
-out_drm_gem_fb_end_cpu_access:
- drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
- return ret;
+ return 0;
}
/*
- * Simple display pipeline
+ * Primary plane
*/
-static const uint32_t udl_simple_display_pipe_formats[] = {
+static const uint32_t udl_primary_plane_formats[] = {
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
};
-static enum drm_mode_status
-udl_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
- const struct drm_display_mode *mode)
+static const uint64_t udl_primary_plane_fmtmods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
- return MODE_OK;
+ struct drm_device *dev = plane->dev;
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_rect damage;
+ int ret, idx;
+
+ if (!fb)
+ return; /* no framebuffer; plane is disabled */
+
+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
+ if (ret)
+ return;
+
+ if (!drm_dev_enter(dev, &idx))
+ goto out_drm_gem_fb_end_cpu_access;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ udl_handle_damage(fb, &shadow_plane_state->data[0], &damage);
+ }
+
+ drm_dev_exit(idx);
+
+out_drm_gem_fb_end_cpu_access:
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+}
+
+static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = {
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
+ .atomic_check = drm_plane_helper_atomic_check,
+ .atomic_update = udl_primary_plane_helper_atomic_update,
+};
+
+static const struct drm_plane_funcs udl_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ DRM_GEM_SHADOW_PLANE_FUNCS,
+};
+
+/*
+ * CRTC
+ */
+
+static int udl_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+ if (!new_crtc_state->enable)
+ return 0;
+
+ return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
}
-static void
-udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *dev = crtc->dev;
- struct drm_framebuffer *fb = plane_state->fb;
- struct udl_device *udl = to_udl(dev);
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
struct drm_display_mode *mode = &crtc_state->mode;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_rect clip = DRM_RECT_INIT(0, 0, fb->width, fb->height);
+ struct urb *urb;
char *buf;
- char *wrptr;
- int color_depth = UDL_COLOR_DEPTH_16BPP;
+ int idx;
- buf = (char *)udl->mode_buf;
+ if (!drm_dev_enter(dev, &idx))
+ return;
- /* This first section has to do with setting the base address on the
- * controller associated with the display. There are 2 base
- * pointers, currently, we only use the 16 bpp segment.
- */
- wrptr = udl_vidreg_lock(buf);
- wrptr = udl_set_color_depth(wrptr, color_depth);
+ urb = udl_get_urb(dev);
+ if (!urb)
+ goto out;
+
+ buf = (char *)urb->transfer_buffer;
+ buf = udl_vidreg_lock(buf);
+ buf = udl_set_color_depth(buf, UDL_COLORDEPTH_16BPP);
/* set base for 16bpp segment to 0 */
- wrptr = udl_set_base16bpp(wrptr, 0);
+ buf = udl_set_base16bpp(buf, 0);
/* set base for 8bpp segment to end of fb */
- wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay);
-
- wrptr = udl_set_vid_cmds(wrptr, mode);
- wrptr = udl_set_blank_mode(wrptr, UDL_BLANK_MODE_ON);
- wrptr = udl_vidreg_unlock(wrptr);
-
- wrptr = udl_dummy_render(wrptr);
-
- udl->mode_buf_len = wrptr - buf;
+ buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay);
+ buf = udl_set_display_mode(buf, mode);
+ buf = udl_set_blank_mode(buf, UDL_BLANKMODE_ON);
+ buf = udl_vidreg_unlock(buf);
+ buf = udl_dummy_render(buf);
- udl_handle_damage(fb, &shadow_plane_state->data[0], &clip);
+ udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
- /* enable display */
- udl_crtc_write_mode_to_hw(crtc);
+out:
+ drm_dev_exit(idx);
}
-static void
-udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *dev = crtc->dev;
struct urb *urb;
char *buf;
+ int idx;
+
+ if (!drm_dev_enter(dev, &idx))
+ return;
urb = udl_get_urb(dev);
if (!urb)
- return;
+ goto out;
buf = (char *)urb->transfer_buffer;
buf = udl_vidreg_lock(buf);
- buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_POWERDOWN);
+ buf = udl_set_blank_mode(buf, UDL_BLANKMODE_POWERDOWN);
buf = udl_vidreg_unlock(buf);
buf = udl_dummy_render(buf);
udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
+
+out:
+ drm_dev_exit(idx);
+}
+
+static const struct drm_crtc_helper_funcs udl_crtc_helper_funcs = {
+ .atomic_check = udl_crtc_helper_atomic_check,
+ .atomic_enable = udl_crtc_helper_atomic_enable,
+ .atomic_disable = udl_crtc_helper_atomic_disable,
+};
+
+static const struct drm_crtc_funcs udl_crtc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+/*
+ * Encoder
+ */
+
+static const struct drm_encoder_funcs udl_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+/*
+ * Connector
+ */
+
+static int udl_connector_helper_get_modes(struct drm_connector *connector)
+{
+ struct udl_connector *udl_connector = to_udl_connector(connector);
+
+ drm_connector_update_edid_property(connector, udl_connector->edid);
+ if (udl_connector->edid)
+ return drm_add_edid_modes(connector, udl_connector->edid);
+
+ return 0;
}
-static void
-udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_plane_state)
+static const struct drm_connector_helper_funcs udl_connector_helper_funcs = {
+ .get_modes = udl_connector_helper_get_modes,
+};
+
+static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
{
- struct drm_plane_state *state = pipe->plane.state;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
- struct drm_framebuffer *fb = state->fb;
- struct drm_rect rect;
+ struct udl_device *udl = data;
+ struct drm_device *dev = &udl->drm;
+ struct usb_device *udev = udl_to_usb_device(udl);
+ u8 *read_buff;
+ int ret;
+ size_t i;
- if (!fb)
- return;
+ read_buff = kmalloc(2, GFP_KERNEL);
+ if (!read_buff)
+ return -ENOMEM;
+
+ for (i = 0; i < len; i++) {
+ int bval = (i + block * EDID_LENGTH) << 8;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ 0x02, (0x80 | (0x02 << 5)), bval,
+ 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT);
+ if (ret < 0) {
+ drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret);
+ goto err_kfree;
+ } else if (ret < 1) {
+ ret = -EIO;
+ drm_err(dev, "Read EDID byte %zu failed\n", i);
+ goto err_kfree;
+ }
+
+ buf[i] = read_buff[1];
+ }
+
+ kfree(read_buff);
+
+ return 0;
+
+err_kfree:
+ kfree(read_buff);
+ return ret;
+}
+
+static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct drm_device *dev = connector->dev;
+ struct udl_device *udl = to_udl(dev);
+ struct udl_connector *udl_connector = to_udl_connector(connector);
+ enum drm_connector_status status = connector_status_disconnected;
+ int idx;
+
+ /* cleanup previous EDID */
+ kfree(udl_connector->edid);
+ udl_connector->edid = NULL;
+
+ if (!drm_dev_enter(dev, &idx))
+ return connector_status_disconnected;
+
+ udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl);
+ if (udl_connector->edid)
+ status = connector_status_connected;
+
+ drm_dev_exit(idx);
+
+ return status;
+}
- if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect))
- udl_handle_damage(fb, &shadow_plane_state->data[0], &rect);
+static void udl_connector_destroy(struct drm_connector *connector)
+{
+ struct udl_connector *udl_connector = to_udl_connector(connector);
+
+ drm_connector_cleanup(connector);
+ kfree(udl_connector->edid);
+ kfree(udl_connector);
}
-static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = {
- .mode_valid = udl_simple_display_pipe_mode_valid,
- .enable = udl_simple_display_pipe_enable,
- .disable = udl_simple_display_pipe_disable,
- .update = udl_simple_display_pipe_update,
- DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
+static const struct drm_connector_funcs udl_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = udl_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = udl_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
+struct drm_connector *udl_connector_init(struct drm_device *dev)
+{
+ struct udl_connector *udl_connector;
+ struct drm_connector *connector;
+ int ret;
+
+ udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL);
+ if (!udl_connector)
+ return ERR_PTR(-ENOMEM);
+
+ connector = &udl_connector->connector;
+ ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+ if (ret)
+ goto err_kfree;
+
+ drm_connector_helper_add(connector, &udl_connector_helper_funcs);
+
+ connector->polled = DRM_CONNECTOR_POLL_HPD |
+ DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT;
+
+ return connector;
+
+err_kfree:
+ kfree(udl_connector);
+ return ERR_PTR(ret);
+}
+
/*
* Modesetting
*/
-static const struct drm_mode_config_funcs udl_mode_funcs = {
+static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev,
+ const struct drm_display_mode *mode)
+{
+ struct udl_device *udl = to_udl(dev);
+
+ if (udl->sku_pixel_limit) {
+ if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit)
+ return MODE_MEM;
+ }
+
+ return MODE_OK;
+}
+
+static const struct drm_mode_config_funcs udl_mode_config_funcs = {
.fb_create = drm_gem_fb_create_with_dirty,
+ .mode_valid = udl_mode_config_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
int udl_modeset_init(struct drm_device *dev)
{
- size_t format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
struct udl_device *udl = to_udl(dev);
+ struct drm_plane *primary_plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
struct drm_connector *connector;
int ret;
@@ -426,28 +572,42 @@ int udl_modeset_init(struct drm_device *dev)
dev->mode_config.min_width = 640;
dev->mode_config.min_height = 480;
-
dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;
-
- dev->mode_config.prefer_shadow = 0;
dev->mode_config.preferred_depth = 16;
+ dev->mode_config.funcs = &udl_mode_config_funcs;
+
+ primary_plane = &udl->primary_plane;
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &udl_primary_plane_funcs,
+ udl_primary_plane_formats,
+ ARRAY_SIZE(udl_primary_plane_formats),
+ udl_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ret;
+ drm_plane_helper_add(primary_plane, &udl_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
- dev->mode_config.funcs = &udl_mode_funcs;
+ crtc = &udl->crtc;
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &udl_crtc_funcs, NULL);
+ if (ret)
+ return ret;
+ drm_crtc_helper_add(crtc, &udl_crtc_helper_funcs);
+
+ encoder = &udl->encoder;
+ ret = drm_encoder_init(dev, encoder, &udl_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL);
+ if (ret)
+ return ret;
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
connector = udl_connector_init(dev);
if (IS_ERR(connector))
return PTR_ERR(connector);
-
- format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
-
- ret = drm_simple_display_pipe_init(dev, &udl->display_pipe,
- &udl_simple_display_pipe_funcs,
- udl_simple_display_pipe_formats,
- format_count, NULL, connector);
+ ret = drm_connector_attach_encoder(connector, encoder);
if (ret)
return ret;
- drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane);
drm_mode_config_reset(dev);
diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h
new file mode 100644
index 000000000000..c92d2109584c
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_proto.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef UDL_PROTO_H
+#define UDL_PROTO_H
+
+#include <linux/bits.h>
+
+#define UDL_MSG_BULK 0xaf
+
+/* Register access */
+#define UDL_CMD_WRITEREG 0x20 /* See register constants below */
+
+/* Framebuffer access */
+#define UDL_CMD_WRITERAW8 0x60 /* 8 bit raw write command. */
+#define UDL_CMD_WRITERL8 0x61 /* 8 bit run length command. */
+#define UDL_CMD_WRITECOPY8 0x62 /* 8 bit copy command. */
+#define UDL_CMD_WRITERLX8 0x63 /* 8 bit extended run length command. */
+#define UDL_CMD_WRITERAW16 0x68 /* 16 bit raw write command. */
+#define UDL_CMD_WRITERL16 0x69 /* 16 bit run length command. */
+#define UDL_CMD_WRITECOPY16 0x6a /* 16 bit copy command. */
+#define UDL_CMD_WRITERLX16 0x6b /* 16 bit extended run length command. */
+
+/* Color depth */
+#define UDL_REG_COLORDEPTH 0x00
+#define UDL_COLORDEPTH_16BPP 0
+#define UDL_COLORDEPTH_24BPP 1
+
+/* Display-mode settings */
+#define UDL_REG_XDISPLAYSTART 0x01
+#define UDL_REG_XDISPLAYEND 0x03
+#define UDL_REG_YDISPLAYSTART 0x05
+#define UDL_REG_YDISPLAYEND 0x07
+#define UDL_REG_XENDCOUNT 0x09
+#define UDL_REG_HSYNCSTART 0x0b
+#define UDL_REG_HSYNCEND 0x0d
+#define UDL_REG_HPIXELS 0x0f
+#define UDL_REG_YENDCOUNT 0x11
+#define UDL_REG_VSYNCSTART 0x13
+#define UDL_REG_VSYNCEND 0x15
+#define UDL_REG_VPIXELS 0x17
+#define UDL_REG_PIXELCLOCK5KHZ 0x1b
+
+/* On/Off for driving the DisplayLink framebuffer to the display */
+#define UDL_REG_BLANKMODE 0x1f
+#define UDL_BLANKMODE_ON 0x00 /* hsync and vsync on, visible */
+#define UDL_BLANKMODE_BLANKED 0x01 /* hsync and vsync on, blanked */
+#define UDL_BLANKMODE_VSYNC_OFF 0x03 /* vsync off, blanked */
+#define UDL_BLANKMODE_HSYNC_OFF 0x05 /* hsync off, blanked */
+#define UDL_BLANKMODE_POWERDOWN 0x07 /* powered off; requires modeset */
+
+/* Framebuffer address */
+#define UDL_REG_BASE16BPP_ADDR2 0x20
+#define UDL_REG_BASE16BPP_ADDR1 0x21
+#define UDL_REG_BASE16BPP_ADDR0 0x22
+#define UDL_REG_BASE8BPP_ADDR2 0x26
+#define UDL_REG_BASE8BPP_ADDR1 0x27
+#define UDL_REG_BASE8BPP_ADDR0 0x28
+
+#define UDL_BASE_ADDR0_MASK GENMASK(7, 0)
+#define UDL_BASE_ADDR1_MASK GENMASK(15, 8)
+#define UDL_BASE_ADDR2_MASK GENMASK(23, 16)
+
+/* Lock/unlock video registers */
+#define UDL_REG_VIDREG 0xff
+#define UDL_VIDREG_LOCK 0x00
+#define UDL_VIDREG_UNLOCK 0xff
+
+#endif
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
index b57844632dbd..5ff1037a3453 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -10,6 +10,7 @@
#include <asm/unaligned.h>
#include "udl_drv.h"
+#include "udl_proto.h"
#define MAX_CMD_PIXELS 255
@@ -89,8 +90,8 @@ static void udl_compress_hline16(
const u8 *cmd_pixel_start, *cmd_pixel_end = NULL;
uint16_t pixel_val16;
- *cmd++ = 0xaf;
- *cmd++ = 0x6b;
+ *cmd++ = UDL_MSG_BULK;
+ *cmd++ = UDL_CMD_WRITERLX16;
*cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF);
*cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF);
*cmd++ = (uint8_t) ((dev_addr) & 0xFF);
@@ -152,7 +153,7 @@ static void udl_compress_hline16(
if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
/* Fill leftover bytes with no-ops */
if (cmd_buffer_end > cmd)
- memset(cmd, 0xAF, cmd_buffer_end - cmd);
+ memset(cmd, UDL_MSG_BULK, cmd_buffer_end - cmd);
cmd = (uint8_t *) cmd_buffer_end;
}
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index e8c975b81585..478f1f0f60de 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -22,7 +22,6 @@
#include <linux/reset.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <uapi/drm/v3d_drm.h>
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index b8980440d137..96af1cb5202a 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -10,6 +10,7 @@
#include <linux/sched/signal.h>
#include <linux/uaccess.h>
+#include <drm/drm_managed.h>
#include <drm/drm_syncobj.h>
#include <uapi/drm/v3d_drm.h>
@@ -1075,10 +1076,18 @@ v3d_gem_init(struct drm_device *dev)
spin_lock_init(&v3d->mm_lock);
spin_lock_init(&v3d->job_lock);
- mutex_init(&v3d->bo_lock);
- mutex_init(&v3d->reset_lock);
- mutex_init(&v3d->sched_lock);
- mutex_init(&v3d->cache_clean_lock);
+ ret = drmm_mutex_init(dev, &v3d->bo_lock);
+ if (ret)
+ return ret;
+ ret = drmm_mutex_init(dev, &v3d->reset_lock);
+ if (ret)
+ return ret;
+ ret = drmm_mutex_init(dev, &v3d->sched_lock);
+ if (ret)
+ return ret;
+ ret = drmm_mutex_init(dev, &v3d->cache_clean_lock);
+ if (ret)
+ return ret;
/* Note: We don't allocate address 0. Various bits of HW
* treat 0 as special, such as the occlusion query counters
diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c b/drivers/gpu/drm/v3d/v3d_perfmon.c
index 48aaaa972c49..e1be7368b87d 100644
--- a/drivers/gpu/drm/v3d/v3d_perfmon.c
+++ b/drivers/gpu/drm/v3d/v3d_perfmon.c
@@ -17,8 +17,10 @@ void v3d_perfmon_get(struct v3d_perfmon *perfmon)
void v3d_perfmon_put(struct v3d_perfmon *perfmon)
{
- if (perfmon && refcount_dec_and_test(&perfmon->refcnt))
+ if (perfmon && refcount_dec_and_test(&perfmon->refcnt)) {
+ mutex_destroy(&perfmon->lock);
kfree(perfmon);
+ }
}
void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon)
@@ -113,6 +115,7 @@ void v3d_perfmon_close_file(struct v3d_file_priv *v3d_priv)
idr_for_each(&v3d_priv->perfmon.idr, v3d_perfmon_idr_del, NULL);
idr_destroy(&v3d_priv->perfmon.idr);
mutex_unlock(&v3d_priv->perfmon.lock);
+ mutex_destroy(&v3d_priv->perfmon.lock);
}
int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data,
@@ -154,6 +157,7 @@ int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data,
mutex_unlock(&v3d_priv->perfmon.lock);
if (ret < 0) {
+ mutex_destroy(&perfmon->lock);
kfree(perfmon);
return ret;
}
diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index f4f2bd79a7cb..b450f449a3ab 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -14,7 +14,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
@@ -178,8 +178,6 @@ static const struct drm_driver driver = {
.driver_features =
DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
- .lastclose = drm_fb_helper_lastclose,
-
.fops = &vbox_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c b/drivers/gpu/drm/vboxvideo/vbox_main.c
index c9e8b3a63c62..3b83e550f4df 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -11,7 +11,6 @@
#include <linux/pci.h>
#include <linux/vbox_err.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 231add8b8e12..43d9b3a6a352 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -736,12 +736,12 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
struct vc4_bo *bo = to_vc4_bo(obj);
if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
- DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n");
+ DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
return -EINVAL;
}
if (bo->madv != VC4_MADV_WILLNEED) {
- DRM_DEBUG("mmaping of %s BO not allowed\n",
+ DRM_DEBUG("mmapping of %s BO not allowed\n",
bo->madv == VC4_MADV_DONTNEED ?
"purgeable" : "purged");
return -EINVAL;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 2027063fdc30..5990d8f8c363 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -33,7 +33,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_vblank.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
@@ -476,7 +476,12 @@ static int __init vc4_drm_register(void)
if (ret)
return ret;
- return platform_driver_register(&vc4_platform_driver);
+ ret = platform_driver_register(&vc4_platform_driver);
+ if (ret)
+ platform_unregister_drivers(component_drivers,
+ ARRAY_SIZE(component_drivers));
+
+ return ret;
}
static void __exit vc4_drm_unregister(void)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 418a8242691f..515228682e8e 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -326,6 +326,8 @@ struct vc4_hvs {
struct clk *core_clk;
+ unsigned long max_core_rate;
+
/* Memory manager for CRTCs to allocate space in the display
* list. Units are dwords.
*/
@@ -337,6 +339,20 @@ struct vc4_hvs {
struct drm_mm_node mitchell_netravali_filter;
struct debugfs_regset32 regset;
+
+ /*
+ * Even if HDMI0 on the RPi4 can output modes requiring a pixel
+ * rate higher than 297MHz, it needs some adjustments in the
+ * config.txt file to be able to do so and thus won't always be
+ * available.
+ */
+ bool vc5_hdmi_enable_hdmi_20;
+
+ /*
+ * 4096x2160@60 requires a core overclock to work, so register
+ * whether that is sufficient.
+ */
+ bool vc5_hdmi_enable_4096by2160;
};
struct vc4_plane {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 596e311d6e58..12a00d644b61 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -124,9 +124,8 @@ static unsigned long long
vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
unsigned int bpc, enum vc4_hdmi_output_format fmt);
-static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder)
+static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
lockdep_assert_held(&vc4_hdmi->mutex);
@@ -319,9 +318,8 @@ out:
static int vc4_hdmi_reset_link(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx)
{
- struct drm_device *drm = connector->dev;
- struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
+ struct drm_device *drm;
+ struct vc4_hdmi *vc4_hdmi;
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
@@ -332,6 +330,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
if (!connector)
return 0;
+ drm = connector->dev;
ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
if (ret)
return ret;
@@ -349,27 +348,41 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
if (!crtc_state->active)
return 0;
- if (!vc4_hdmi_supports_scrambling(encoder))
+ vc4_hdmi = connector_to_vc4_hdmi(connector);
+ mutex_lock(&vc4_hdmi->mutex);
+
+ if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
+ mutex_unlock(&vc4_hdmi->mutex);
return 0;
+ }
scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format);
- if (!scrambling_needed)
+ if (!scrambling_needed) {
+ mutex_unlock(&vc4_hdmi->mutex);
return 0;
+ }
if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done))
+ !try_wait_for_completion(&conn_state->commit->hw_done)) {
+ mutex_unlock(&vc4_hdmi->mutex);
return 0;
+ }
ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
drm_err(drm, "Failed to read TMDS config: %d\n", ret);
+ mutex_unlock(&vc4_hdmi->mutex);
return 0;
}
- if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed)
+ if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
+ mutex_unlock(&vc4_hdmi->mutex);
return 0;
+ }
+
+ mutex_unlock(&vc4_hdmi->mutex);
/*
* HDMI 2.0 says that one should not send scrambled data
@@ -397,9 +410,8 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
* .adap_enable, which leads to that funtion being called with
* our mutex held.
*
- * A similar situation occurs with
- * drm_atomic_helper_connector_hdmi_reset_link() that will call
- * into our KMS hooks if the scrambling was enabled.
+ * A similar situation occurs with vc4_hdmi_reset_link() that
+ * will call into our KMS hooks if the scrambling was enabled.
*
* Concurrency isn't an issue at the moment since we don't share
* any state with any of the other frameworks so we can ignore
@@ -459,6 +471,7 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+ struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
int ret = 0;
struct edid *edid;
@@ -482,7 +495,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
- if (vc4_hdmi->disable_4kp60) {
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
@@ -542,7 +555,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
new_state->base.max_bpc = 8;
new_state->base.max_requested_bpc = 8;
new_state->output_format = VC4_HDMI_OUTPUT_RGB;
- drm_atomic_helper_connector_tv_reset(connector);
+ drm_atomic_helper_connector_tv_margins_reset(connector);
}
static struct drm_connector_state *
@@ -866,7 +879,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
lockdep_assert_held(&vc4_hdmi->mutex);
- if (!vc4_hdmi_supports_scrambling(encoder))
+ if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
return;
if (!vc4_hdmi_mode_needs_scrambling(mode,
@@ -1752,15 +1765,23 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi,
static enum drm_mode_status
vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi,
+ const struct drm_display_mode *mode,
unsigned long long clock)
{
const struct drm_connector *connector = &vc4_hdmi->connector;
const struct drm_display_info *info = &connector->display_info;
+ struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ return MODE_CLOCK_HIGH;
+
+ /* 4096x2160@60 is not reliable without overclocking core */
+ if (!vc4->hvs->vc5_hdmi_enable_4096by2160 &&
+ mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
+ drm_mode_vrefresh(mode) >= 50)
return MODE_CLOCK_HIGH;
if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000))
@@ -1797,7 +1818,7 @@ vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi,
unsigned long long clock;
clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
- if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK)
+ if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, clock) != MODE_OK)
return -EINVAL;
vc4_state->tmds_char_rate = clock;
@@ -1960,7 +1981,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
(mode->hsync_end % 2) || (mode->htotal % 2)))
return MODE_H_ILLEGAL;
- return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000);
+ return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, mode->clock * 1000);
}
static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
@@ -3160,9 +3181,16 @@ static int vc4_hdmi_init_resources(struct drm_device *drm,
DRM_ERROR("Failed to get HDMI state machine clock\n");
return PTR_ERR(vc4_hdmi->hsm_clock);
}
+
vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock;
vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock;
+ vc4_hdmi->hsm_rpm_clock = devm_clk_get(dev, "hdmi");
+ if (IS_ERR(vc4_hdmi->hsm_rpm_clock)) {
+ DRM_ERROR("Failed to get HDMI state machine clock\n");
+ return PTR_ERR(vc4_hdmi->hsm_rpm_clock);
+ }
+
return 0;
}
@@ -3245,6 +3273,12 @@ static int vc5_hdmi_init_resources(struct drm_device *drm,
return PTR_ERR(vc4_hdmi->hsm_clock);
}
+ vc4_hdmi->hsm_rpm_clock = devm_clk_get(dev, "hdmi");
+ if (IS_ERR(vc4_hdmi->hsm_rpm_clock)) {
+ DRM_ERROR("Failed to get HDMI state machine clock\n");
+ return PTR_ERR(vc4_hdmi->hsm_rpm_clock);
+ }
+
vc4_hdmi->pixel_bvb_clock = devm_clk_get(dev, "bvb");
if (IS_ERR(vc4_hdmi->pixel_bvb_clock)) {
DRM_ERROR("Failed to get pixel bvb clock\n");
@@ -3308,7 +3342,7 @@ static int vc4_hdmi_runtime_suspend(struct device *dev)
{
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
+ clk_disable_unprepare(vc4_hdmi->hsm_rpm_clock);
return 0;
}
@@ -3326,11 +3360,11 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
* its frequency while the power domain is active so that it
* keeps its rate.
*/
- ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
+ ret = clk_set_min_rate(vc4_hdmi->hsm_rpm_clock, HSM_MIN_CLOCK_FREQ);
if (ret)
return ret;
- ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+ ret = clk_prepare_enable(vc4_hdmi->hsm_rpm_clock);
if (ret)
return ret;
@@ -3343,7 +3377,7 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
* case, it will lead to a silent CPU stall. Let's make sure we
* prevent such a case.
*/
- rate = clk_get_rate(vc4_hdmi->hsm_clock);
+ rate = clk_get_rate(vc4_hdmi->hsm_rpm_clock);
if (!rate) {
ret = -EINVAL;
goto err_disable_clk;
@@ -3456,14 +3490,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->disable_wifi_frequencies =
of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");
- if (variant->max_pixel_clock == 600000000) {
- struct vc4_dev *vc4 = to_vc4_dev(drm);
- long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000);
-
- if (max_rate < 550000000)
- vc4_hdmi->disable_4kp60 = true;
- }
-
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index db823efb2563..dc3ccd8002a0 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -156,14 +156,6 @@ struct vc4_hdmi {
*/
bool disable_wifi_frequencies;
- /*
- * Even if HDMI0 on the RPi4 can output modes requiring a pixel
- * rate higher than 297MHz, it needs some adjustments in the
- * config.txt file to be able to do so and thus won't always be
- * available.
- */
- bool disable_4kp60;
-
struct cec_adapter *cec_adap;
struct cec_msg cec_rx_msg;
bool cec_tx_ok;
@@ -172,6 +164,7 @@ struct vc4_hdmi {
struct clk *cec_clock;
struct clk *pixel_clock;
struct clk *hsm_clock;
+ struct clk *hsm_rpm_clock;
struct clk *audio_clock;
struct clk *pixel_bvb_clock;
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index 4ac9f5a2d5f9..c4453a5ae163 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -28,6 +28,8 @@
#include <drm/drm_drv.h>
#include <drm/drm_vblank.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -791,12 +793,36 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
hvs->regset.nregs = ARRAY_SIZE(hvs_regs);
if (vc4->is_vc5) {
+ struct rpi_firmware *firmware;
+ struct device_node *node;
+ unsigned int max_rate;
+
+ node = rpi_firmware_find_node();
+ if (!node)
+ return -EINVAL;
+
+ firmware = rpi_firmware_get(node);
+ of_node_put(node);
+ if (!firmware)
+ return -EPROBE_DEFER;
+
hvs->core_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hvs->core_clk)) {
dev_err(&pdev->dev, "Couldn't get core clock\n");
return PTR_ERR(hvs->core_clk);
}
+ max_rate = rpi_firmware_clk_get_max_rate(firmware,
+ RPI_FIRMWARE_CORE_CLK_ID);
+ rpi_firmware_put(firmware);
+ if (max_rate >= 550000000)
+ hvs->vc5_hdmi_enable_hdmi_20 = true;
+
+ if (max_rate >= 600000000)
+ hvs->vc5_hdmi_enable_4096by2160 = true;
+
+ hvs->max_core_rate = max_rate;
+
ret = clk_prepare_enable(hvs->core_clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable the core clock\n");
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 4419e810103d..8fbeecdf2ec4 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -197,8 +197,8 @@ vc4_hvs_get_new_global_state(struct drm_atomic_state *state)
struct drm_private_state *priv_state;
priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels);
- if (IS_ERR(priv_state))
- return ERR_CAST(priv_state);
+ if (!priv_state)
+ return ERR_PTR(-EINVAL);
return to_vc4_hvs_state(priv_state);
}
@@ -210,8 +210,8 @@ vc4_hvs_get_old_global_state(struct drm_atomic_state *state)
struct drm_private_state *priv_state;
priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels);
- if (IS_ERR(priv_state))
- return ERR_CAST(priv_state);
+ if (!priv_state)
+ return ERR_PTR(-EINVAL);
return to_vc4_hvs_state(priv_state);
}
@@ -396,8 +396,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
if (vc4->is_vc5) {
unsigned long state_rate = max(old_hvs_state->core_clock_rate,
new_hvs_state->core_clock_rate);
- unsigned long core_rate = max_t(unsigned long,
- 500000000, state_rate);
+ unsigned long core_rate = clamp_t(unsigned long, state_rate,
+ 500000000, hvs->max_core_rate);
drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate);
@@ -431,14 +431,17 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_cleanup_planes(dev, state);
if (vc4->is_vc5) {
- drm_dbg(dev, "Running the core clock at %lu Hz\n",
- new_hvs_state->core_clock_rate);
+ unsigned long core_rate = min_t(unsigned long,
+ hvs->max_core_rate,
+ new_hvs_state->core_clock_rate);
+
+ drm_dbg(dev, "Running the core clock at %lu Hz\n", core_rate);
/*
* Request a clock rate based on the current HVS
* requirements.
*/
- WARN_ON(clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate));
+ WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate));
drm_dbg(dev, "Core clock actual rate: %lu Hz\n",
clk_get_rate(hvs->core_clk));
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 0b3333865702..92c07e31d632 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -69,6 +69,7 @@
#define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
#define VEC_CONFIG0_NTSC_STD 0
#define VEC_CONFIG0_PAL_BDGHI_STD 1
+#define VEC_CONFIG0_PAL_M_STD 2
#define VEC_CONFIG0_PAL_N_STD 3
#define VEC_SCHPH 0x108
@@ -255,10 +256,9 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
[VC4_VEC_TV_MODE_PAL_M] = {
- .mode = &pal_mode,
- .config0 = VEC_CONFIG0_PAL_BDGHI_STD,
- .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
- .custom_freq = 0x223b61d1,
+ .mode = &ntsc_mode,
+ .config0 = VEC_CONFIG0_PAL_M_STD,
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
};
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index 0035affc3e59..ae97b98750b6 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -35,6 +35,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include "virtgpu_drv.h"
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 9b98470593b0..b7a64c7dcc2c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -35,7 +35,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 0ffe5f0e33f7..293dbca50c31 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -17,7 +17,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_ioctl.h>
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig
index a4fabe208d9f..faddae3d6ac2 100644
--- a/drivers/gpu/drm/vmwgfx/Kconfig
+++ b/drivers/gpu/drm/vmwgfx/Kconfig
@@ -16,13 +16,6 @@ config DRM_VMWGFX
virtual hardware.
The compiled module will be called "vmwgfx.ko".
-config DRM_VMWGFX_FBCON
- depends on DRM_VMWGFX && DRM_FBDEV_EMULATION
- bool "Enable framebuffer console under vmwgfx by default"
- help
- Choose this option if you are shipping a new vmwgfx
- userspace driver that supports using the kernel driver.
-
config DRM_VMWGFX_MKSSTATS
bool "Enable mksGuestStats instrumentation of vmwgfx by default"
depends on DRM_VMWGFX
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
index eee73b9aa404..2a644f035597 100644
--- a/drivers/gpu/drm/vmwgfx/Makefile
+++ b/drivers/gpu/drm/vmwgfx/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \
+vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \
vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \
@@ -12,6 +12,4 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d
vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \
vmwgfx_gem.o
-vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o
-
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c
index 26a55fef1ab5..932b125ebf3d 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.c
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.c
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -44,16 +44,20 @@
#define pr_fmt(fmt) "[TTM] " fmt
+#include "ttm_object.h"
+#include "vmwgfx_drv.h"
+
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/module.h>
-#include "ttm_object.h"
-#include "vmwgfx_drv.h"
+#include <linux/hashtable.h>
MODULE_IMPORT_NS(DMA_BUF);
+#define VMW_TTM_OBJECT_REF_HT_ORDER 10
+
/**
* struct ttm_object_file
*
@@ -74,16 +78,14 @@ struct ttm_object_file {
struct ttm_object_device *tdev;
spinlock_t lock;
struct list_head ref_list;
- struct vmwgfx_open_hash ref_hash;
+ DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER);
struct kref refcount;
};
/*
* struct ttm_object_device
*
- * @object_lock: lock that protects the object_hash hash table.
- *
- * @object_hash: hash table for fast lookup of object global names.
+ * @object_lock: lock that protects idr.
*
* @object_count: Per device object count.
*
@@ -92,7 +94,6 @@ struct ttm_object_file {
struct ttm_object_device {
spinlock_t object_lock;
- struct vmwgfx_open_hash object_hash;
atomic_t object_count;
struct dma_buf_ops ops;
void (*dmabuf_release)(struct dma_buf *dma_buf);
@@ -138,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile)
return tfile;
}
+static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile,
+ uint64_t key,
+ struct vmwgfx_hash_item **p_hash)
+{
+ struct vmwgfx_hash_item *hash;
+
+ hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) {
+ if (hash->key == key) {
+ *p_hash = hash;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int ttm_tfile_find_ref(struct ttm_object_file *tfile,
+ uint64_t key,
+ struct vmwgfx_hash_item **p_hash)
+{
+ struct vmwgfx_hash_item *hash;
+
+ hash_for_each_possible(tfile->ref_hash, hash, head, key) {
+ if (hash->key == key) {
+ *p_hash = hash;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
static void ttm_object_file_destroy(struct kref *kref)
{
struct ttm_object_file *tfile =
@@ -240,37 +271,35 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
* Return: A pointer to the object if successful or NULL otherwise.
*/
struct ttm_base_object *
-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
+ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key)
{
struct vmwgfx_hash_item *hash;
- struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret;
rcu_read_lock();
- ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
+ ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
if (ret) {
rcu_read_unlock();
return NULL;
}
__release(RCU);
- return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
+ return hlist_entry(hash, struct ttm_ref_object, hash)->obj;
}
EXPORT_SYMBOL(ttm_base_object_noref_lookup);
struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
- uint32_t key)
+ uint64_t key)
{
struct ttm_base_object *base = NULL;
struct vmwgfx_hash_item *hash;
- struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret;
rcu_read_lock();
- ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
+ ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
if (likely(ret == 0)) {
- base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
+ base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
if (!kref_get_unless_zero(&base->refcount))
base = NULL;
}
@@ -280,7 +309,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
}
struct ttm_base_object *
-ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
+ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key)
{
struct ttm_base_object *base;
@@ -299,7 +328,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
bool *existed,
bool require_existed)
{
- struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash;
int ret = -EINVAL;
@@ -312,10 +340,10 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
while (ret == -EINVAL) {
rcu_read_lock();
- ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash);
+ ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash);
if (ret == 0) {
- ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
+ ref = hlist_entry(hash, struct ttm_ref_object, hash);
if (kref_get_unless_zero(&ref->kref)) {
rcu_read_unlock();
break;
@@ -337,21 +365,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
kref_init(&ref->kref);
spin_lock(&tfile->lock);
- ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash);
-
- if (likely(ret == 0)) {
- list_add_tail(&ref->head, &tfile->ref_list);
- kref_get(&base->refcount);
- spin_unlock(&tfile->lock);
- if (existed != NULL)
- *existed = false;
- break;
- }
+ hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key);
+ ret = 0;
+ list_add_tail(&ref->head, &tfile->ref_list);
+ kref_get(&base->refcount);
spin_unlock(&tfile->lock);
- BUG_ON(ret != -EINVAL);
-
- kfree(ref);
+ if (existed != NULL)
+ *existed = false;
}
return ret;
@@ -363,10 +384,8 @@ ttm_ref_object_release(struct kref *kref)
struct ttm_ref_object *ref =
container_of(kref, struct ttm_ref_object, kref);
struct ttm_object_file *tfile = ref->tfile;
- struct vmwgfx_open_hash *ht;
- ht = &tfile->ref_hash;
- (void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
+ hash_del_rcu(&ref->hash.head);
list_del(&ref->head);
spin_unlock(&tfile->lock);
@@ -378,18 +397,17 @@ ttm_ref_object_release(struct kref *kref)
int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
unsigned long key)
{
- struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash;
int ret;
spin_lock(&tfile->lock);
- ret = vmwgfx_ht_find_item(ht, key, &hash);
+ ret = ttm_tfile_find_ref(tfile, key, &hash);
if (unlikely(ret != 0)) {
spin_unlock(&tfile->lock);
return -EINVAL;
}
- ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
+ ref = hlist_entry(hash, struct ttm_ref_object, hash);
kref_put(&ref->kref, ttm_ref_object_release);
spin_unlock(&tfile->lock);
return 0;
@@ -416,16 +434,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
}
spin_unlock(&tfile->lock);
- vmwgfx_ht_remove(&tfile->ref_hash);
ttm_object_file_unref(&tfile);
}
-struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
- unsigned int hash_order)
+struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev)
{
struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
- int ret;
if (unlikely(tfile == NULL))
return NULL;
@@ -435,34 +450,21 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
kref_init(&tfile->refcount);
INIT_LIST_HEAD(&tfile->ref_list);
- ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order);
- if (ret)
- goto out_err;
+ hash_init(tfile->ref_hash);
return tfile;
-out_err:
- vmwgfx_ht_remove(&tfile->ref_hash);
-
- kfree(tfile);
-
- return NULL;
}
struct ttm_object_device *
-ttm_object_device_init(unsigned int hash_order,
- const struct dma_buf_ops *ops)
+ttm_object_device_init(const struct dma_buf_ops *ops)
{
struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
- int ret;
if (unlikely(tdev == NULL))
return NULL;
spin_lock_init(&tdev->object_lock);
atomic_set(&tdev->object_count, 0);
- ret = vmwgfx_ht_create(&tdev->object_hash, hash_order);
- if (ret != 0)
- goto out_no_object_hash;
/*
* Our base is at VMWGFX_NUM_MOB + 1 because we want to create
@@ -477,10 +479,6 @@ ttm_object_device_init(unsigned int hash_order,
tdev->dmabuf_release = tdev->ops.release;
tdev->ops.release = ttm_prime_dmabuf_release;
return tdev;
-
-out_no_object_hash:
- kfree(tdev);
- return NULL;
}
void ttm_object_device_release(struct ttm_object_device **p_tdev)
@@ -491,7 +489,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev)
WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
idr_destroy(&tdev->idr);
- vmwgfx_ht_remove(&tdev->object_hash);
kfree(tdev);
}
diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h
index 1a2fa0f83f5f..f0ebbe340ad6 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.h
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.h
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -42,8 +42,6 @@
#include <linux/list.h>
#include <linux/rcupdate.h>
-#include "vmwgfx_hashtab.h"
-
/**
* enum ttm_object_type
*
@@ -104,7 +102,7 @@ struct ttm_base_object {
struct ttm_object_file *tfile;
struct kref refcount;
void (*refcount_release) (struct ttm_base_object **base);
- u32 handle;
+ u64 handle;
enum ttm_object_type object_type;
u32 shareable;
};
@@ -164,7 +162,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
*/
extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
- *tfile, uint32_t key);
+ *tfile, uint64_t key);
/**
* ttm_base_object_lookup_for_ref
@@ -178,7 +176,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
*/
extern struct ttm_base_object *
-ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key);
+ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key);
/**
* ttm_base_object_unref
@@ -237,14 +235,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
* ttm_object_file_init - initialize a struct ttm_object file
*
* @tdev: A struct ttm_object device this file is initialized on.
- * @hash_order: Order of the hash table used to hold the reference objects.
*
* This is typically called by the file_ops::open function.
*/
extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device
- *tdev,
- unsigned int hash_order);
+ *tdev);
/**
* ttm_object_file_release - release data held by a ttm_object_file
@@ -262,7 +258,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
/**
* ttm_object device init - initialize a struct ttm_object_device
*
- * @hash_order: Order of hash table used to hash the base objects.
* @ops: DMA buf ops for prime objects of this device.
*
* This function is typically called on device initialization to prepare
@@ -270,8 +265,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
*/
extern struct ttm_object_device *
-ttm_object_device_init(unsigned int hash_order,
- const struct dma_buf_ops *ops);
+ttm_object_device_init(const struct dma_buf_ops *ops);
/**
* ttm_object_device_release - release data held by a ttm_object_device
@@ -314,7 +308,7 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
kfree_rcu(__obj, __prime.base.rhead)
struct ttm_base_object *
-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key);
+ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key);
/**
* ttm_base_object_noref_release - release a base object pointer looked up
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
index 09fe20e918f9..c52c7bf1485b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
@@ -483,8 +483,8 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst,
d.src_addr = NULL;
d.dst_pages = dst->ttm->pages;
d.src_pages = src->ttm->pages;
- d.dst_num_pages = dst->resource->num_pages;
- d.src_num_pages = src->resource->num_pages;
+ d.dst_num_pages = PFN_UP(dst->resource->size);
+ d.src_num_pages = PFN_UP(src->resource->size);
d.dst_prot = ttm_io_prot(dst, dst->resource, PAGE_KERNEL);
d.src_prot = ttm_io_prot(src, src->resource, PAGE_KERNEL);
d.diff = diff;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 822251aaab0a..321c551784a1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -194,7 +194,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv,
int ret = 0;
place = vmw_vram_placement.placement[0];
- place.lpfn = bo->resource->num_pages;
+ place.lpfn = PFN_UP(bo->resource->size);
placement.num_placement = 1;
placement.placement = &place;
placement.num_busy_placement = 1;
@@ -211,7 +211,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv,
* that situation.
*/
if (bo->resource->mem_type == TTM_PL_VRAM &&
- bo->resource->start < bo->resource->num_pages &&
+ bo->resource->start < PFN_UP(bo->resource->size) &&
bo->resource->start > 0 &&
buf->base.pin_count == 0) {
ctx.interruptible = false;
@@ -352,7 +352,7 @@ void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo)
if (virtual)
return virtual;
- ret = ttm_bo_kmap(bo, 0, bo->resource->num_pages, &vbo->map);
+ ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map);
if (ret)
DRM_ERROR("Buffer object map failed: %d.\n", ret);
@@ -807,9 +807,23 @@ int vmw_dumb_create(struct drm_file *file_priv,
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_buffer_object *vbo;
+ int cpp = DIV_ROUND_UP(args->bpp, 8);
int ret;
- args->pitch = args->width * ((args->bpp + 7) / 8);
+ switch (cpp) {
+ case 1: /* DRM_FORMAT_C8 */
+ case 2: /* DRM_FORMAT_RGB565 */
+ case 4: /* DRM_FORMAT_XRGB8888 */
+ break;
+ default:
+ /*
+ * Dumb buffers don't allow anything else.
+ * This is tested via IGT's dumb_buffers
+ */
+ return -EINVAL;
+ }
+
+ args->pitch = args->width * cpp;
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);
ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
index 82ef58ccdd42..47bc0b411055 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -28,6 +28,8 @@
#include "vmwgfx_drv.h"
#include "vmwgfx_resource_priv.h"
+#include <linux/hashtable.h>
+
#define VMW_CMDBUF_RES_MAN_HT_ORDER 12
/**
@@ -59,7 +61,7 @@ struct vmw_cmdbuf_res {
* @resources and @list are protected by the cmdbuf mutex for now.
*/
struct vmw_cmdbuf_res_manager {
- struct vmwgfx_open_hash resources;
+ DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
struct list_head list;
struct vmw_private *dev_priv;
};
@@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
u32 user_key)
{
struct vmwgfx_hash_item *hash;
- int ret;
unsigned long key = user_key | (res_type << 24);
- ret = vmwgfx_ht_find_item(&man->resources, key, &hash);
- if (unlikely(ret != 0))
- return ERR_PTR(ret);
-
- return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res;
+ hash_for_each_possible_rcu(man->resources, hash, head, key) {
+ if (hash->key == key)
+ return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res;
+ }
+ return ERR_PTR(-EINVAL);
}
/**
@@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
struct vmw_cmdbuf_res *entry)
{
list_del(&entry->head);
- WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash));
+ hash_del_rcu(&entry->hash.head);
vmw_resource_unreference(&entry->res);
kfree(entry);
}
@@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list)
void vmw_cmdbuf_res_revert(struct list_head *list)
{
struct vmw_cmdbuf_res *entry, *next;
- int ret;
list_for_each_entry_safe(entry, next, list, head) {
switch (entry->state) {
@@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list)
vmw_cmdbuf_res_free(entry->man, entry);
break;
case VMW_CMDBUF_RES_DEL:
- ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash);
- BUG_ON(ret);
+ hash_add_rcu(entry->man->resources, &entry->hash.head,
+ entry->hash.key);
list_move_tail(&entry->head, &entry->man->list);
entry->state = VMW_CMDBUF_RES_COMMITTED;
break;
@@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
struct list_head *list)
{
struct vmw_cmdbuf_res *cres;
- int ret;
cres = kzalloc(sizeof(*cres), GFP_KERNEL);
if (unlikely(!cres))
return -ENOMEM;
cres->hash.key = user_key | (res_type << 24);
- ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash);
- if (unlikely(ret != 0)) {
- kfree(cres);
- goto out_invalid_key;
- }
+ hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key);
cres->state = VMW_CMDBUF_RES_ADD;
cres->res = vmw_resource_reference(res);
cres->man = man;
list_add_tail(&cres->head, list);
-out_invalid_key:
- return ret;
+ return 0;
}
/**
@@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
struct list_head *list,
struct vmw_resource **res_p)
{
- struct vmw_cmdbuf_res *entry;
+ struct vmw_cmdbuf_res *entry = NULL;
struct vmwgfx_hash_item *hash;
- int ret;
+ unsigned long key = user_key | (res_type << 24);
- ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24),
- &hash);
- if (likely(ret != 0))
+ hash_for_each_possible_rcu(man->resources, hash, head, key) {
+ if (hash->key == key) {
+ entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash);
+ break;
+ }
+ }
+ if (unlikely(!entry))
return -EINVAL;
- entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
-
switch (entry->state) {
case VMW_CMDBUF_RES_ADD:
vmw_cmdbuf_res_free(man, entry);
*res_p = NULL;
break;
case VMW_CMDBUF_RES_COMMITTED:
- (void) vmwgfx_ht_remove_item(&man->resources, &entry->hash);
+ hash_del_rcu(&entry->hash.head);
list_del(&entry->head);
entry->state = VMW_CMDBUF_RES_DEL;
list_add_tail(&entry->head, list);
@@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager *
vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
{
struct vmw_cmdbuf_res_manager *man;
- int ret;
man = kzalloc(sizeof(*man), GFP_KERNEL);
if (!man)
@@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
man->dev_priv = dev_priv;
INIT_LIST_HEAD(&man->list);
- ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
- if (ret == 0)
- return man;
-
- kfree(man);
- return ERR_PTR(ret);
+ hash_init(man->resources);
+ return man;
}
/**
@@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
list_for_each_entry_safe(entry, next, &man->list, head)
vmw_cmdbuf_res_free(man, entry);
- vmwgfx_ht_remove(&man->resources);
kfree(man);
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
index 79b30dc9d825..b78a10312fad 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
@@ -33,6 +33,7 @@
#include <drm/ttm/ttm_placement.h>
#include "vmwgfx_drv.h"
+#include "vmwgfx_mksstat.h"
#include "vmwgfx_resource_priv.h"
#include "vmwgfx_so.h"
@@ -72,12 +73,24 @@ struct vmw_cotable_info {
bool);
};
+
+/*
+ * Getting the initial size right is difficult because it all depends
+ * on what the userspace is doing. The sizes will be aligned up to
+ * a PAGE_SIZE so we just want to make sure that for majority of apps
+ * the initial number of entries doesn't require an immediate resize.
+ * For all cotables except SVGACOTableDXElementLayoutEntry and
+ * SVGACOTableDXBlendStateEntry the initial number of entries fits
+ * within the PAGE_SIZE. For SVGACOTableDXElementLayoutEntry and
+ * SVGACOTableDXBlendStateEntry we want to reserve two pages,
+ * because that's what all apps will require initially.
+ */
static const struct vmw_cotable_info co_info[] = {
{1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
- {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
- {1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
+ {PAGE_SIZE/sizeof(SVGACOTableDXElementLayoutEntry) + 1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
+ {PAGE_SIZE/sizeof(SVGACOTableDXBlendStateEntry) + 1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
{1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
{1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
{1, sizeof(SVGACOTableDXSamplerEntry), NULL},
@@ -395,9 +408,12 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
int ret;
size_t i;
+ MKS_STAT_TIME_DECL(MKSSTAT_KERN_COTABLE_RESIZE);
+ MKS_STAT_TIME_PUSH(MKSSTAT_KERN_COTABLE_RESIZE);
+
ret = vmw_cotable_readback(res);
if (ret)
- return ret;
+ goto out_done;
cur_size_read_back = vcotbl->size_read_back;
vcotbl->size_read_back = old_size_read_back;
@@ -411,7 +427,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
true, true, vmw_bo_bo_free, &buf);
if (ret) {
DRM_ERROR("Failed initializing new cotable MOB.\n");
- return ret;
+ goto out_done;
}
bo = &buf->base;
@@ -427,7 +443,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
* Do a page by page copy of COTables. This eliminates slow vmap()s.
* This should really be a TTM utility.
*/
- for (i = 0; i < old_bo->resource->num_pages; ++i) {
+ for (i = 0; i < PFN_UP(old_bo->resource->size); ++i) {
bool dummy;
ret = ttm_bo_kmap(old_bo, i, 1, &old_map);
@@ -485,6 +501,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
/* Release the pin acquired in vmw_bo_init */
ttm_bo_unpin(bo);
+ MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
+
return 0;
out_map_new:
@@ -494,6 +512,9 @@ out_wait:
ttm_bo_unreserve(bo);
vmw_bo_unreference(&buf);
+out_done:
+ MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
+
return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index d7bd5eb1d3ac..bd02cb0e6837 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -25,13 +25,17 @@
*
**************************************************************************/
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/cc_platform.h>
+
+#include "vmwgfx_drv.h"
+
+#include "vmwgfx_devcaps.h"
+#include "vmwgfx_mksstat.h"
+#include "vmwgfx_binding.h"
+#include "ttm_object.h"
#include <drm/drm_aperture.h>
#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_module.h>
@@ -41,17 +45,14 @@
#include <drm/ttm/ttm_placement.h>
#include <generated/utsrelease.h>
-#include "ttm_object.h"
-#include "vmwgfx_binding.h"
-#include "vmwgfx_devcaps.h"
-#include "vmwgfx_drv.h"
-#include "vmwgfx_mksstat.h"
+#include <linux/cc_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/version.h>
#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
-#define VMW_MIN_INITIAL_WIDTH 800
-#define VMW_MIN_INITIAL_HEIGHT 600
-
/*
* Fully encoded drm commands. Might move to vmw_drm.h
*/
@@ -262,7 +263,6 @@ static const struct pci_device_id vmw_pci_id_list[] = {
};
MODULE_DEVICE_TABLE(pci, vmw_pci_id_list);
-static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON);
static int vmw_restrict_iommu;
static int vmw_force_coherent;
static int vmw_restrict_dma_mask;
@@ -272,8 +272,6 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
void *ptr);
-MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
-module_param_named(enable_fbdev, enable_fbdev, int, 0600);
MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
@@ -623,8 +621,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
width = vmw_read(dev_priv, SVGA_REG_WIDTH);
height = vmw_read(dev_priv, SVGA_REG_HEIGHT);
- width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH);
- height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT);
+ width = max_t(uint32_t, width, VMWGFX_MIN_INITIAL_WIDTH);
+ height = max_t(uint32_t, height, VMWGFX_MIN_INITIAL_HEIGHT);
if (width > dev_priv->fb_max_width ||
height > dev_priv->fb_max_height) {
@@ -633,8 +631,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
* This is a host error and shouldn't occur.
*/
- width = VMW_MIN_INITIAL_WIDTH;
- height = VMW_MIN_INITIAL_HEIGHT;
+ width = VMWGFX_MIN_INITIAL_WIDTH;
+ height = VMWGFX_MIN_INITIAL_HEIGHT;
}
dev_priv->initial_width = width;
@@ -806,6 +804,43 @@ static int vmw_detect_version(struct vmw_private *dev)
return 0;
}
+static void vmw_write_driver_id(struct vmw_private *dev)
+{
+ if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) {
+ vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
+ SVGA_REG_GUEST_DRIVER_ID_LINUX);
+
+ vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1,
+ LINUX_VERSION_MAJOR << 24 |
+ LINUX_VERSION_PATCHLEVEL << 16 |
+ LINUX_VERSION_SUBLEVEL);
+ vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2,
+ VMWGFX_DRIVER_MAJOR << 24 |
+ VMWGFX_DRIVER_MINOR << 16 |
+ VMWGFX_DRIVER_PATCHLEVEL);
+ vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0);
+
+ vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
+ SVGA_REG_GUEST_DRIVER_ID_SUBMIT);
+ }
+}
+
+static void vmw_sw_context_init(struct vmw_private *dev_priv)
+{
+ struct vmw_sw_context *sw_context = &dev_priv->ctx;
+
+ hash_init(sw_context->res_ht);
+}
+
+static void vmw_sw_context_fini(struct vmw_private *dev_priv)
+{
+ struct vmw_sw_context *sw_context = &dev_priv->ctx;
+
+ vfree(sw_context->cmd_bounce);
+ if (sw_context->staged_bindings)
+ vmw_binding_state_free(sw_context->staged_bindings);
+}
+
static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
{
int ret;
@@ -815,6 +850,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->drm.dev_private = dev_priv;
+ vmw_sw_context_init(dev_priv);
+
mutex_init(&dev_priv->cmdbuf_mutex);
mutex_init(&dev_priv->binding_mutex);
spin_lock_init(&dev_priv->resource_lock);
@@ -844,9 +881,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->assume_16bpp = !!vmw_assume_16bpp;
- dev_priv->enable_fb = enable_fbdev;
-
-
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
vmw_print_bitmap(&dev_priv->drm, "Capabilities",
dev_priv->capabilities,
@@ -970,7 +1004,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
goto out_err0;
}
- dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops);
+ dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops);
if (unlikely(dev_priv->tdev == NULL)) {
drm_err(&dev_priv->drm,
@@ -1091,12 +1125,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)",
VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE);
-
- if (dev_priv->enable_fb) {
- vmw_fifo_resource_inc(dev_priv);
- vmw_svga_enable(dev_priv);
- vmw_fb_init(dev_priv);
- }
+ vmw_write_driver_id(dev_priv);
dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
register_pm_notifier(&dev_priv->pm_nb);
@@ -1143,15 +1172,10 @@ static void vmw_driver_unload(struct drm_device *dev)
unregister_pm_notifier(&dev_priv->pm_nb);
- if (dev_priv->ctx.res_ht_initialized)
- vmwgfx_ht_remove(&dev_priv->ctx.res_ht);
- vfree(dev_priv->ctx.cmd_bounce);
- if (dev_priv->enable_fb) {
- vmw_fb_off(dev_priv);
- vmw_fb_close(dev_priv);
- vmw_fifo_resource_dec(dev_priv);
- vmw_svga_disable(dev_priv);
- }
+ vmw_sw_context_fini(dev_priv);
+ vmw_fifo_resource_dec(dev_priv);
+
+ vmw_svga_disable(dev_priv);
vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv);
@@ -1173,8 +1197,6 @@ static void vmw_driver_unload(struct drm_device *dev)
vmw_irq_uninstall(&dev_priv->drm);
ttm_object_device_release(&dev_priv->tdev);
- if (dev_priv->ctx.staged_bindings)
- vmw_binding_state_free(dev_priv->ctx.staged_bindings);
for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]);
@@ -1203,7 +1225,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
if (unlikely(!vmw_fp))
return ret;
- vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
+ vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev);
if (unlikely(vmw_fp->tfile == NULL))
goto out_no_tfile;
@@ -1291,8 +1313,6 @@ static void vmw_master_drop(struct drm_device *dev,
struct vmw_private *dev_priv = vmw_priv(dev);
vmw_kms_legacy_hotspot_clear(dev_priv);
- if (!dev_priv->enable_fb)
- vmw_svga_disable(dev_priv);
}
/**
@@ -1485,25 +1505,19 @@ static int vmw_pm_freeze(struct device *kdev)
DRM_ERROR("Failed to freeze modesetting.\n");
return ret;
}
- if (dev_priv->enable_fb)
- vmw_fb_off(dev_priv);
vmw_execbuf_release_pinned_bo(dev_priv);
vmw_resource_evict_all(dev_priv);
vmw_release_device_early(dev_priv);
while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0);
- if (dev_priv->enable_fb)
- vmw_fifo_resource_dec(dev_priv);
+ vmw_fifo_resource_dec(dev_priv);
if (atomic_read(&dev_priv->num_fifo_resources) != 0) {
DRM_ERROR("Can't hibernate while 3D resources are active.\n");
- if (dev_priv->enable_fb)
- vmw_fifo_resource_inc(dev_priv);
+ vmw_fifo_resource_inc(dev_priv);
WARN_ON(vmw_request_device_late(dev_priv));
dev_priv->suspend_locked = false;
if (dev_priv->suspend_state)
vmw_kms_resume(dev);
- if (dev_priv->enable_fb)
- vmw_fb_on(dev_priv);
return -EBUSY;
}
@@ -1523,24 +1537,19 @@ static int vmw_pm_restore(struct device *kdev)
vmw_detect_version(dev_priv);
- if (dev_priv->enable_fb)
- vmw_fifo_resource_inc(dev_priv);
+ vmw_fifo_resource_inc(dev_priv);
ret = vmw_request_device(dev_priv);
if (ret)
return ret;
- if (dev_priv->enable_fb)
- __vmw_svga_enable(dev_priv);
+ __vmw_svga_enable(dev_priv);
vmw_fence_fifo_up(dev_priv->fman);
dev_priv->suspend_locked = false;
if (dev_priv->suspend_state)
vmw_kms_resume(&dev_priv->drm);
- if (dev_priv->enable_fb)
- vmw_fb_on(dev_priv);
-
return 0;
}
@@ -1631,6 +1640,10 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_unload;
+ vmw_fifo_resource_inc(vmw);
+ vmw_svga_enable(vmw);
+ drm_fbdev_generic_setup(&vmw->drm, 0);
+
vmw_debugfs_gem_init(vmw);
vmw_debugfs_resource_managers_init(vmw);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 09e2d738aa87..b062b020b378 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -30,6 +30,7 @@
#include <linux/suspend.h>
#include <linux/sync_file.h>
+#include <linux/hashtable.h>
#include <drm/drm_auth.h>
#include <drm/drm_device.h>
@@ -42,7 +43,6 @@
#include "ttm_object.h"
#include "vmwgfx_fence.h"
-#include "vmwgfx_hashtab.h"
#include "vmwgfx_reg.h"
#include "vmwgfx_validation.h"
@@ -62,6 +62,9 @@
#define VMWGFX_MAX_DISPLAYS 16
#define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768
+#define VMWGFX_MIN_INITIAL_WIDTH 1280
+#define VMWGFX_MIN_INITIAL_HEIGHT 800
+
#define VMWGFX_PCI_ID_SVGA2 0x0405
#define VMWGFX_PCI_ID_SVGA3 0x0406
@@ -93,6 +96,11 @@
#define VMW_RES_STREAM ttm_driver_type2
#define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4
+#define VMW_RES_HT_ORDER 12
+
+#define VMW_CURSOR_SNOOP_FORMAT SVGA3D_A8R8G8B8
+#define VMW_CURSOR_SNOOP_WIDTH 64
+#define VMW_CURSOR_SNOOP_HEIGHT 64
#define MKSSTAT_CAPACITY_LOG2 5U
#define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)
@@ -102,6 +110,11 @@ struct vmw_fpriv {
bool gb_aware; /* user-space is guest-backed aware */
};
+struct vmwgfx_hash_item {
+ struct hlist_node head;
+ unsigned long key;
+};
+
/**
* struct vmw_buffer_object - TTM buffer object with vmwgfx additions
* @base: The TTM buffer object
@@ -425,8 +438,7 @@ struct vmw_ctx_validation_info;
* @ctx: The validation context
*/
struct vmw_sw_context{
- struct vmwgfx_open_hash res_ht;
- bool res_ht_initialized;
+ DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER);
bool kernel;
struct vmw_fpriv *fp;
struct drm_file *filp;
@@ -546,7 +558,6 @@ struct vmw_private {
* Framebuffer info.
*/
- void *fb_info;
enum vmw_display_unit_type active_display_unit;
struct vmw_legacy_display *ldu_priv;
struct vmw_overlay *overlay_priv;
@@ -605,8 +616,6 @@ struct vmw_private {
struct mutex cmdbuf_mutex;
struct mutex binding_mutex;
- bool enable_fb;
-
/**
* PM management.
*/
@@ -1184,35 +1193,6 @@ extern void vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag,
extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
u32 flag, int *waiter_count);
-
-/**
- * Kernel framebuffer - vmwgfx_fb.c
- */
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-int vmw_fb_init(struct vmw_private *vmw_priv);
-int vmw_fb_close(struct vmw_private *dev_priv);
-int vmw_fb_off(struct vmw_private *vmw_priv);
-int vmw_fb_on(struct vmw_private *vmw_priv);
-#else
-static inline int vmw_fb_init(struct vmw_private *vmw_priv)
-{
- return 0;
-}
-static inline int vmw_fb_close(struct vmw_private *dev_priv)
-{
- return 0;
-}
-static inline int vmw_fb_off(struct vmw_private *vmw_priv)
-{
- return 0;
-}
-static inline int vmw_fb_on(struct vmw_private *vmw_priv)
-{
- return 0;
-}
-#endif
-
/**
* Kernel modesetting - vmwgfx_kms.c
*/
@@ -1232,9 +1212,6 @@ int vmw_kms_write_svga(struct vmw_private *vmw_priv,
bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
uint32_t pitch,
uint32_t height);
-u32 vmw_get_vblank_counter(struct drm_crtc *crtc);
-int vmw_enable_vblank(struct drm_crtc *crtc);
-void vmw_disable_vblank(struct drm_crtc *crtc);
int vmw_kms_present(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *vfb,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index f085dbd4736d..a5379f6fb5ab 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -25,6 +25,7 @@
*
**************************************************************************/
#include <linux/sync_file.h>
+#include <linux/hashtable.h>
#include "vmwgfx_drv.h"
#include "vmwgfx_reg.h"
@@ -34,7 +35,6 @@
#include "vmwgfx_binding.h"
#include "vmwgfx_mksstat.h"
-#define VMW_RES_HT_ORDER 12
/*
* Helper macro to get dx_ctx_node if available otherwise print an error
@@ -1047,7 +1047,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
if (unlikely(new_query_bo != sw_context->cur_query_bo)) {
- if (unlikely(new_query_bo->base.resource->num_pages > 4)) {
+ if (unlikely(PFN_UP(new_query_bo->base.resource->size) > 4)) {
VMW_DEBUG_USER("Query buffer too large.\n");
return -EINVAL;
}
@@ -3869,7 +3869,6 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
* @fence: Pointer to the fenc object.
* @fence_handle: User-space fence handle.
* @out_fence_fd: exported file descriptor for the fence. -1 if not used
- * @sync_file: Only used to clean up in case of an error in this function.
*
* This function copies fence information to user-space. If copying fails, the
* user-space struct drm_vmw_fence_rep::error member is hopefully left
@@ -4101,7 +4100,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
int ret;
int32_t out_fence_fd = -1;
struct sync_file *sync_file = NULL;
- DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1);
+ DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
@@ -4164,14 +4163,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (sw_context->staged_bindings)
vmw_binding_state_reset(sw_context->staged_bindings);
- if (!sw_context->res_ht_initialized) {
- ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
- if (unlikely(ret != 0))
- goto out_unlock;
-
- sw_context->res_ht_initialized = true;
- }
-
INIT_LIST_HEAD(&sw_context->staged_cmd_res);
sw_context->ctx = &val_ctx;
ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
deleted file mode 100644
index 5b85b477e4c6..000000000000
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2007 David Airlie
- * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#include <linux/fb.h>
-#include <linux/pci.h>
-
-#include <drm/drm_fourcc.h>
-#include <drm/ttm/ttm_placement.h>
-
-#include "vmwgfx_drv.h"
-#include "vmwgfx_kms.h"
-
-#define VMW_DIRTY_DELAY (HZ / 30)
-
-struct vmw_fb_par {
- struct vmw_private *vmw_priv;
-
- void *vmalloc;
-
- struct mutex bo_mutex;
- struct vmw_buffer_object *vmw_bo;
- unsigned bo_size;
- struct drm_framebuffer *set_fb;
- struct drm_display_mode *set_mode;
- u32 fb_x;
- u32 fb_y;
- bool bo_iowrite;
-
- u32 pseudo_palette[17];
-
- unsigned max_width;
- unsigned max_height;
-
- struct {
- spinlock_t lock;
- bool active;
- unsigned x1;
- unsigned y1;
- unsigned x2;
- unsigned y2;
- } dirty;
-
- struct drm_crtc *crtc;
- struct drm_connector *con;
- struct delayed_work local_work;
-};
-
-static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
-{
- struct vmw_fb_par *par = info->par;
- u32 *pal = par->pseudo_palette;
-
- if (regno > 15) {
- DRM_ERROR("Bad regno %u.\n", regno);
- return 1;
- }
-
- switch (par->set_fb->format->depth) {
- case 24:
- case 32:
- pal[regno] = ((red & 0xff00) << 8) |
- (green & 0xff00) |
- ((blue & 0xff00) >> 8);
- break;
- default:
- DRM_ERROR("Bad depth %u, bpp %u.\n",
- par->set_fb->format->depth,
- par->set_fb->format->cpp[0] * 8);
- return 1;
- }
-
- return 0;
-}
-
-static int vmw_fb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- int depth = var->bits_per_pixel;
- struct vmw_fb_par *par = info->par;
- struct vmw_private *vmw_priv = par->vmw_priv;
-
- switch (var->bits_per_pixel) {
- case 32:
- depth = (var->transp.length > 0) ? 32 : 24;
- break;
- default:
- DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
- return -EINVAL;
- }
-
- switch (depth) {
- case 24:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 0;
- var->transp.offset = 0;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 8;
- var->transp.offset = 24;
- break;
- default:
- DRM_ERROR("Bad depth %u.\n", depth);
- return -EINVAL;
- }
-
- if ((var->xoffset + var->xres) > par->max_width ||
- (var->yoffset + var->yres) > par->max_height) {
- DRM_ERROR("Requested geom can not fit in framebuffer\n");
- return -EINVAL;
- }
-
- if (!vmw_kms_validate_mode_vram(vmw_priv,
- var->xres * var->bits_per_pixel/8,
- var->yoffset + var->yres)) {
- DRM_ERROR("Requested geom can not fit in framebuffer\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vmw_fb_blank(int blank, struct fb_info *info)
-{
- return 0;
-}
-
-/**
- * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer
- *
- * @work: The struct work_struct associated with this task.
- *
- * This function flushes the dirty regions of the vmalloc framebuffer to the
- * kms framebuffer, and if the kms framebuffer is visible, also updated the
- * corresponding displays. Note that this function runs even if the kms
- * framebuffer is not bound to a crtc and thus not visible, but it's turned
- * off during hibernation using the par->dirty.active bool.
- */
-static void vmw_fb_dirty_flush(struct work_struct *work)
-{
- struct vmw_fb_par *par = container_of(work, struct vmw_fb_par,
- local_work.work);
- struct vmw_private *vmw_priv = par->vmw_priv;
- struct fb_info *info = vmw_priv->fb_info;
- unsigned long irq_flags;
- s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0;
- u32 cpp, max_x, max_y;
- struct drm_clip_rect clip;
- struct drm_framebuffer *cur_fb;
- u8 *src_ptr, *dst_ptr;
- struct vmw_buffer_object *vbo = par->vmw_bo;
- void *virtual;
-
- if (!READ_ONCE(par->dirty.active))
- return;
-
- mutex_lock(&par->bo_mutex);
- cur_fb = par->set_fb;
- if (!cur_fb)
- goto out_unlock;
-
- (void) ttm_bo_reserve(&vbo->base, false, false, NULL);
- virtual = vmw_bo_map_and_cache(vbo);
- if (!virtual)
- goto out_unreserve;
-
- spin_lock_irqsave(&par->dirty.lock, irq_flags);
- if (!par->dirty.active) {
- spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
- goto out_unreserve;
- }
-
- /*
- * Handle panning when copying from vmalloc to framebuffer.
- * Clip dirty area to framebuffer.
- */
- cpp = cur_fb->format->cpp[0];
- max_x = par->fb_x + cur_fb->width;
- max_y = par->fb_y + cur_fb->height;
-
- dst_x1 = par->dirty.x1 - par->fb_x;
- dst_y1 = par->dirty.y1 - par->fb_y;
- dst_x1 = max_t(s32, dst_x1, 0);
- dst_y1 = max_t(s32, dst_y1, 0);
-
- dst_x2 = par->dirty.x2 - par->fb_x;
- dst_y2 = par->dirty.y2 - par->fb_y;
- dst_x2 = min_t(s32, dst_x2, max_x);
- dst_y2 = min_t(s32, dst_y2, max_y);
- w = dst_x2 - dst_x1;
- h = dst_y2 - dst_y1;
- w = max_t(s32, 0, w);
- h = max_t(s32, 0, h);
-
- par->dirty.x1 = par->dirty.x2 = 0;
- par->dirty.y1 = par->dirty.y2 = 0;
- spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
-
- if (w && h) {
- dst_ptr = (u8 *)virtual +
- (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp);
- src_ptr = (u8 *)par->vmalloc +
- ((dst_y1 + par->fb_y) * info->fix.line_length +
- (dst_x1 + par->fb_x) * cpp);
-
- while (h-- > 0) {
- memcpy(dst_ptr, src_ptr, w*cpp);
- dst_ptr += par->set_fb->pitches[0];
- src_ptr += info->fix.line_length;
- }
-
- clip.x1 = dst_x1;
- clip.x2 = dst_x2;
- clip.y1 = dst_y1;
- clip.y2 = dst_y2;
- }
-
-out_unreserve:
- ttm_bo_unreserve(&vbo->base);
- if (w && h) {
- WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0,
- &clip, 1));
- vmw_cmd_flush(vmw_priv, false);
- }
-out_unlock:
- mutex_unlock(&par->bo_mutex);
-}
-
-static void vmw_fb_dirty_mark(struct vmw_fb_par *par,
- unsigned x1, unsigned y1,
- unsigned width, unsigned height)
-{
- unsigned long flags;
- unsigned x2 = x1 + width;
- unsigned y2 = y1 + height;
-
- spin_lock_irqsave(&par->dirty.lock, flags);
- if (par->dirty.x1 == par->dirty.x2) {
- par->dirty.x1 = x1;
- par->dirty.y1 = y1;
- par->dirty.x2 = x2;
- par->dirty.y2 = y2;
- /* if we are active start the dirty work
- * we share the work with the defio system */
- if (par->dirty.active)
- schedule_delayed_work(&par->local_work,
- VMW_DIRTY_DELAY);
- } else {
- if (x1 < par->dirty.x1)
- par->dirty.x1 = x1;
- if (y1 < par->dirty.y1)
- par->dirty.y1 = y1;
- if (x2 > par->dirty.x2)
- par->dirty.x2 = x2;
- if (y2 > par->dirty.y2)
- par->dirty.y2 = y2;
- }
- spin_unlock_irqrestore(&par->dirty.lock, flags);
-}
-
-static int vmw_fb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- struct vmw_fb_par *par = info->par;
-
- if ((var->xoffset + var->xres) > var->xres_virtual ||
- (var->yoffset + var->yres) > var->yres_virtual) {
- DRM_ERROR("Requested panning can not fit in framebuffer\n");
- return -EINVAL;
- }
-
- mutex_lock(&par->bo_mutex);
- par->fb_x = var->xoffset;
- par->fb_y = var->yoffset;
- if (par->set_fb)
- vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width,
- par->set_fb->height);
- mutex_unlock(&par->bo_mutex);
-
- return 0;
-}
-
-static void vmw_deferred_io(struct fb_info *info, struct list_head *pagereflist)
-{
- struct vmw_fb_par *par = info->par;
- unsigned long start, end, min, max;
- unsigned long flags;
- struct fb_deferred_io_pageref *pageref;
- int y1, y2;
-
- min = ULONG_MAX;
- max = 0;
- list_for_each_entry(pageref, pagereflist, list) {
- start = pageref->offset;
- end = start + PAGE_SIZE - 1;
- min = min(min, start);
- max = max(max, end);
- }
-
- if (min < max) {
- y1 = min / info->fix.line_length;
- y2 = (max / info->fix.line_length) + 1;
-
- spin_lock_irqsave(&par->dirty.lock, flags);
- par->dirty.x1 = 0;
- par->dirty.y1 = y1;
- par->dirty.x2 = info->var.xres;
- par->dirty.y2 = y2;
- spin_unlock_irqrestore(&par->dirty.lock, flags);
-
- /*
- * Since we've already waited on this work once, try to
- * execute asap.
- */
- cancel_delayed_work(&par->local_work);
- schedule_delayed_work(&par->local_work, 0);
- }
-};
-
-static struct fb_deferred_io vmw_defio = {
- .delay = VMW_DIRTY_DELAY,
- .deferred_io = vmw_deferred_io,
-};
-
-/*
- * Draw code
- */
-
-static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
- cfb_fillrect(info, rect);
- vmw_fb_dirty_mark(info->par, rect->dx, rect->dy,
- rect->width, rect->height);
-}
-
-static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
-{
- cfb_copyarea(info, region);
- vmw_fb_dirty_mark(info->par, region->dx, region->dy,
- region->width, region->height);
-}
-
-static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
- cfb_imageblit(info, image);
- vmw_fb_dirty_mark(info->par, image->dx, image->dy,
- image->width, image->height);
-}
-
-/*
- * Bring up code
- */
-
-static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
- size_t size, struct vmw_buffer_object **out)
-{
- struct vmw_buffer_object *vmw_bo;
- int ret;
-
- ret = vmw_bo_create(vmw_priv, size,
- &vmw_sys_placement,
- false, false,
- &vmw_bo_bo_free, &vmw_bo);
- if (unlikely(ret != 0))
- return ret;
-
- *out = vmw_bo;
-
- return ret;
-}
-
-static int vmw_fb_compute_depth(struct fb_var_screeninfo *var,
- int *depth)
-{
- switch (var->bits_per_pixel) {
- case 32:
- *depth = (var->transp.length > 0) ? 32 : 24;
- break;
- default:
- DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vmwgfx_set_config_internal(struct drm_mode_set *set)
-{
- struct drm_crtc *crtc = set->crtc;
- struct drm_modeset_acquire_ctx ctx;
- int ret;
-
- drm_modeset_acquire_init(&ctx, 0);
-
-restart:
- ret = crtc->funcs->set_config(set, &ctx);
-
- if (ret == -EDEADLK) {
- drm_modeset_backoff(&ctx);
- goto restart;
- }
-
- drm_modeset_drop_locks(&ctx);
- drm_modeset_acquire_fini(&ctx);
-
- return ret;
-}
-
-static int vmw_fb_kms_detach(struct vmw_fb_par *par,
- bool detach_bo,
- bool unref_bo)
-{
- struct drm_framebuffer *cur_fb = par->set_fb;
- int ret;
-
- /* Detach the KMS framebuffer from crtcs */
- if (par->set_mode) {
- struct drm_mode_set set;
-
- set.crtc = par->crtc;
- set.x = 0;
- set.y = 0;
- set.mode = NULL;
- set.fb = NULL;
- set.num_connectors = 0;
- set.connectors = &par->con;
- ret = vmwgfx_set_config_internal(&set);
- if (ret) {
- DRM_ERROR("Could not unset a mode.\n");
- return ret;
- }
- drm_mode_destroy(&par->vmw_priv->drm, par->set_mode);
- par->set_mode = NULL;
- }
-
- if (cur_fb) {
- drm_framebuffer_put(cur_fb);
- par->set_fb = NULL;
- }
-
- if (par->vmw_bo && detach_bo && unref_bo)
- vmw_bo_unreference(&par->vmw_bo);
-
- return 0;
-}
-
-static int vmw_fb_kms_framebuffer(struct fb_info *info)
-{
- struct drm_mode_fb_cmd2 mode_cmd = {0};
- struct vmw_fb_par *par = info->par;
- struct fb_var_screeninfo *var = &info->var;
- struct drm_framebuffer *cur_fb;
- struct vmw_framebuffer *vfb;
- int ret = 0, depth;
- size_t new_bo_size;
-
- ret = vmw_fb_compute_depth(var, &depth);
- if (ret)
- return ret;
-
- mode_cmd.width = var->xres;
- mode_cmd.height = var->yres;
- mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width;
- mode_cmd.pixel_format =
- drm_mode_legacy_fb_format(var->bits_per_pixel, depth);
-
- cur_fb = par->set_fb;
- if (cur_fb && cur_fb->width == mode_cmd.width &&
- cur_fb->height == mode_cmd.height &&
- cur_fb->format->format == mode_cmd.pixel_format &&
- cur_fb->pitches[0] == mode_cmd.pitches[0])
- return 0;
-
- /* Need new buffer object ? */
- new_bo_size = (size_t) mode_cmd.pitches[0] * (size_t) mode_cmd.height;
- ret = vmw_fb_kms_detach(par,
- par->bo_size < new_bo_size ||
- par->bo_size > 2*new_bo_size,
- true);
- if (ret)
- return ret;
-
- if (!par->vmw_bo) {
- ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size,
- &par->vmw_bo);
- if (ret) {
- DRM_ERROR("Failed creating a buffer object for "
- "fbdev.\n");
- return ret;
- }
- par->bo_size = new_bo_size;
- }
-
- vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL,
- true, &mode_cmd);
- if (IS_ERR(vfb))
- return PTR_ERR(vfb);
-
- par->set_fb = &vfb->base;
-
- return 0;
-}
-
-static int vmw_fb_set_par(struct fb_info *info)
-{
- struct vmw_fb_par *par = info->par;
- struct vmw_private *vmw_priv = par->vmw_priv;
- struct drm_mode_set set;
- struct fb_var_screeninfo *var = &info->var;
- struct drm_display_mode new_mode = { DRM_MODE("fb_mode",
- DRM_MODE_TYPE_DRIVER,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
- };
- struct drm_display_mode *mode;
- int ret;
-
- mode = drm_mode_duplicate(&vmw_priv->drm, &new_mode);
- if (!mode) {
- DRM_ERROR("Could not create new fb mode.\n");
- return -ENOMEM;
- }
-
- mode->hdisplay = var->xres;
- mode->vdisplay = var->yres;
- vmw_guess_mode_timing(mode);
-
- if (!vmw_kms_validate_mode_vram(vmw_priv,
- mode->hdisplay *
- DIV_ROUND_UP(var->bits_per_pixel, 8),
- mode->vdisplay)) {
- drm_mode_destroy(&vmw_priv->drm, mode);
- return -EINVAL;
- }
-
- mutex_lock(&par->bo_mutex);
- ret = vmw_fb_kms_framebuffer(info);
- if (ret)
- goto out_unlock;
-
- par->fb_x = var->xoffset;
- par->fb_y = var->yoffset;
-
- set.crtc = par->crtc;
- set.x = 0;
- set.y = 0;
- set.mode = mode;
- set.fb = par->set_fb;
- set.num_connectors = 1;
- set.connectors = &par->con;
-
- ret = vmwgfx_set_config_internal(&set);
- if (ret)
- goto out_unlock;
-
- vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
- par->set_fb->width, par->set_fb->height);
-
- /* If there already was stuff dirty we wont
- * schedule a new work, so lets do it now */
-
- schedule_delayed_work(&par->local_work, 0);
-
-out_unlock:
- if (par->set_mode)
- drm_mode_destroy(&vmw_priv->drm, par->set_mode);
- par->set_mode = mode;
-
- mutex_unlock(&par->bo_mutex);
-
- return ret;
-}
-
-
-static const struct fb_ops vmw_fb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = vmw_fb_check_var,
- .fb_set_par = vmw_fb_set_par,
- .fb_setcolreg = vmw_fb_setcolreg,
- .fb_fillrect = vmw_fb_fillrect,
- .fb_copyarea = vmw_fb_copyarea,
- .fb_imageblit = vmw_fb_imageblit,
- .fb_pan_display = vmw_fb_pan_display,
- .fb_blank = vmw_fb_blank,
- .fb_mmap = fb_deferred_io_mmap,
-};
-
-int vmw_fb_init(struct vmw_private *vmw_priv)
-{
- struct device *device = vmw_priv->drm.dev;
- struct vmw_fb_par *par;
- struct fb_info *info;
- unsigned fb_width, fb_height;
- unsigned int fb_bpp, fb_pitch, fb_size;
- struct drm_display_mode *init_mode;
- int ret;
-
- fb_bpp = 32;
-
- /* XXX As shouldn't these be as well. */
- fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
- fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
-
- fb_pitch = fb_width * fb_bpp / 8;
- fb_size = fb_pitch * fb_height;
-
- info = framebuffer_alloc(sizeof(*par), device);
- if (!info)
- return -ENOMEM;
-
- /*
- * Par
- */
- vmw_priv->fb_info = info;
- par = info->par;
- memset(par, 0, sizeof(*par));
- INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush);
- par->vmw_priv = vmw_priv;
- par->vmalloc = NULL;
- par->max_width = fb_width;
- par->max_height = fb_height;
-
- ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width,
- par->max_height, &par->con,
- &par->crtc, &init_mode);
- if (ret)
- goto err_kms;
-
- info->var.xres = init_mode->hdisplay;
- info->var.yres = init_mode->vdisplay;
-
- /*
- * Create buffers and alloc memory
- */
- par->vmalloc = vzalloc(fb_size);
- if (unlikely(par->vmalloc == NULL)) {
- ret = -ENOMEM;
- goto err_free;
- }
-
- /*
- * Fixed and var
- */
- strcpy(info->fix.id, "svgadrmfb");
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.type_aux = 0;
- info->fix.xpanstep = 1; /* doing it in hw */
- info->fix.ypanstep = 1; /* doing it in hw */
- info->fix.ywrapstep = 0;
- info->fix.accel = FB_ACCEL_NONE;
- info->fix.line_length = fb_pitch;
-
- info->fix.smem_start = 0;
- info->fix.smem_len = fb_size;
-
- info->pseudo_palette = par->pseudo_palette;
- info->screen_base = (char __iomem *)par->vmalloc;
- info->screen_size = fb_size;
-
- info->fbops = &vmw_fb_ops;
-
- /* 24 depth per default */
- info->var.red.offset = 16;
- info->var.green.offset = 8;
- info->var.blue.offset = 0;
- info->var.red.length = 8;
- info->var.green.length = 8;
- info->var.blue.length = 8;
- info->var.transp.offset = 0;
- info->var.transp.length = 0;
-
- info->var.xres_virtual = fb_width;
- info->var.yres_virtual = fb_height;
- info->var.bits_per_pixel = fb_bpp;
- info->var.xoffset = 0;
- info->var.yoffset = 0;
- info->var.activate = FB_ACTIVATE_NOW;
- info->var.height = -1;
- info->var.width = -1;
-
- /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- ret = -ENOMEM;
- goto err_aper;
- }
- info->apertures->ranges[0].base = vmw_priv->vram_start;
- info->apertures->ranges[0].size = vmw_priv->vram_size;
-
- /*
- * Dirty & Deferred IO
- */
- par->dirty.x1 = par->dirty.x2 = 0;
- par->dirty.y1 = par->dirty.y2 = 0;
- par->dirty.active = true;
- spin_lock_init(&par->dirty.lock);
- mutex_init(&par->bo_mutex);
- info->fbdefio = &vmw_defio;
- fb_deferred_io_init(info);
-
- ret = register_framebuffer(info);
- if (unlikely(ret != 0))
- goto err_defio;
-
- vmw_fb_set_par(info);
-
- return 0;
-
-err_defio:
- fb_deferred_io_cleanup(info);
-err_aper:
-err_free:
- vfree(par->vmalloc);
-err_kms:
- framebuffer_release(info);
- vmw_priv->fb_info = NULL;
-
- return ret;
-}
-
-int vmw_fb_close(struct vmw_private *vmw_priv)
-{
- struct fb_info *info;
- struct vmw_fb_par *par;
-
- if (!vmw_priv->fb_info)
- return 0;
-
- info = vmw_priv->fb_info;
- par = info->par;
-
- /* ??? order */
- fb_deferred_io_cleanup(info);
- cancel_delayed_work_sync(&par->local_work);
- unregister_framebuffer(info);
-
- mutex_lock(&par->bo_mutex);
- (void) vmw_fb_kms_detach(par, true, true);
- mutex_unlock(&par->bo_mutex);
-
- vfree(par->vmalloc);
- framebuffer_release(info);
-
- return 0;
-}
-
-int vmw_fb_off(struct vmw_private *vmw_priv)
-{
- struct fb_info *info;
- struct vmw_fb_par *par;
- unsigned long flags;
-
- if (!vmw_priv->fb_info)
- return -EINVAL;
-
- info = vmw_priv->fb_info;
- par = info->par;
-
- spin_lock_irqsave(&par->dirty.lock, flags);
- par->dirty.active = false;
- spin_unlock_irqrestore(&par->dirty.lock, flags);
-
- flush_delayed_work(&info->deferred_work);
- flush_delayed_work(&par->local_work);
-
- return 0;
-}
-
-int vmw_fb_on(struct vmw_private *vmw_priv)
-{
- struct fb_info *info;
- struct vmw_fb_par *par;
- unsigned long flags;
-
- if (!vmw_priv->fb_info)
- return -EINVAL;
-
- info = vmw_priv->fb_info;
- par = info->par;
-
- spin_lock_irqsave(&par->dirty.lock, flags);
- par->dirty.active = true;
- spin_unlock_irqrestore(&par->dirty.lock, flags);
-
- /*
- * Need to reschedule a dirty update, because otherwise that's
- * only done in dirty_mark() if the previous coalesced
- * dirty region was empty.
- */
- schedule_delayed_work(&par->local_work, 0);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
index 60e3cc537f36..abd5e3323ebf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
@@ -71,7 +71,7 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
spin_lock(&gman->lock);
if (gman->max_gmr_pages > 0) {
- gman->used_gmr_pages += (*res)->num_pages;
+ gman->used_gmr_pages += PFN_UP((*res)->size);
/*
* Because the graphics memory is a soft limit we can try to
* expand it instead of letting the userspace apps crash.
@@ -114,7 +114,7 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
return 0;
nospace:
- gman->used_gmr_pages -= (*res)->num_pages;
+ gman->used_gmr_pages -= PFN_UP((*res)->size);
spin_unlock(&gman->lock);
ida_free(&gman->gmr_ida, id);
ttm_resource_fini(man, *res);
@@ -129,7 +129,7 @@ static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man,
ida_free(&gman->gmr_ida, res->start);
spin_lock(&gman->lock);
- gman->used_gmr_pages -= res->num_pages;
+ gman->used_gmr_pages -= PFN_UP(res->size);
spin_unlock(&gman->lock);
ttm_resource_fini(man, res);
kfree(res);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c
deleted file mode 100644
index 06aebc12774e..000000000000
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
- * All Rights Reserved.
- *
- * 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- */
-
-/*
- * Simple open hash tab implementation.
- *
- * Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- */
-
-#include <linux/export.h>
-#include <linux/hash.h>
-#include <linux/mm.h>
-#include <linux/rculist.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <drm/drm_print.h>
-
-#include "vmwgfx_hashtab.h"
-
-int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order)
-{
- unsigned int size = 1 << order;
-
- ht->order = order;
- ht->table = NULL;
- if (size <= PAGE_SIZE / sizeof(*ht->table))
- ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
- else
- ht->table = vzalloc(array_size(size, sizeof(*ht->table)));
- if (!ht->table) {
- DRM_ERROR("Out of memory for hash table\n");
- return -ENOMEM;
- }
- return 0;
-}
-
-void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key)
-{
- struct vmwgfx_hash_item *entry;
- struct hlist_head *h_list;
- unsigned int hashed_key;
- int count = 0;
-
- hashed_key = hash_long(key, ht->order);
- DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
- h_list = &ht->table[hashed_key];
- hlist_for_each_entry(entry, h_list, head)
- DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
-}
-
-static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key)
-{
- struct vmwgfx_hash_item *entry;
- struct hlist_head *h_list;
- unsigned int hashed_key;
-
- hashed_key = hash_long(key, ht->order);
- h_list = &ht->table[hashed_key];
- hlist_for_each_entry(entry, h_list, head) {
- if (entry->key == key)
- return &entry->head;
- if (entry->key > key)
- break;
- }
- return NULL;
-}
-
-static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key)
-{
- struct vmwgfx_hash_item *entry;
- struct hlist_head *h_list;
- unsigned int hashed_key;
-
- hashed_key = hash_long(key, ht->order);
- h_list = &ht->table[hashed_key];
- hlist_for_each_entry_rcu(entry, h_list, head) {
- if (entry->key == key)
- return &entry->head;
- if (entry->key > key)
- break;
- }
- return NULL;
-}
-
-int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
-{
- struct vmwgfx_hash_item *entry;
- struct hlist_head *h_list;
- struct hlist_node *parent;
- unsigned int hashed_key;
- unsigned long key = item->key;
-
- hashed_key = hash_long(key, ht->order);
- h_list = &ht->table[hashed_key];
- parent = NULL;
- hlist_for_each_entry(entry, h_list, head) {
- if (entry->key == key)
- return -EINVAL;
- if (entry->key > key)
- break;
- parent = &entry->head;
- }
- if (parent)
- hlist_add_behind_rcu(&item->head, parent);
- else
- hlist_add_head_rcu(&item->head, h_list);
- return 0;
-}
-
-/*
- * Just insert an item and return any "bits" bit key that hasn't been
- * used before.
- */
-int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
- unsigned long seed, int bits, int shift,
- unsigned long add)
-{
- int ret;
- unsigned long mask = (1UL << bits) - 1;
- unsigned long first, unshifted_key;
-
- unshifted_key = hash_long(seed, bits);
- first = unshifted_key;
- do {
- item->key = (unshifted_key << shift) + add;
- ret = vmwgfx_ht_insert_item(ht, item);
- if (ret)
- unshifted_key = (unshifted_key + 1) & mask;
- } while (ret && (unshifted_key != first));
-
- if (ret) {
- DRM_ERROR("Available key bit space exhausted\n");
- return -EINVAL;
- }
- return 0;
-}
-
-int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
- struct vmwgfx_hash_item **item)
-{
- struct hlist_node *list;
-
- list = vmwgfx_ht_find_key_rcu(ht, key);
- if (!list)
- return -EINVAL;
-
- *item = hlist_entry(list, struct vmwgfx_hash_item, head);
- return 0;
-}
-
-int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key)
-{
- struct hlist_node *list;
-
- list = vmwgfx_ht_find_key(ht, key);
- if (list) {
- hlist_del_init_rcu(list);
- return 0;
- }
- return -EINVAL;
-}
-
-int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
-{
- hlist_del_init_rcu(&item->head);
- return 0;
-}
-
-void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht)
-{
- if (ht->table) {
- kvfree(ht->table);
- ht->table = NULL;
- }
-}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h
deleted file mode 100644
index a9ce12922e21..000000000000
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
- * All Rights Reserved.
- *
- * 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- */
-
-/*
- * Simple open hash tab implementation.
- *
- * Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- */
-
-/*
- * TODO: Replace this hashtable with Linux' generic implementation
- * from <linux/hashtable.h>.
- */
-
-#ifndef VMWGFX_HASHTAB_H
-#define VMWGFX_HASHTAB_H
-
-#include <linux/list.h>
-
-#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
-
-struct vmwgfx_hash_item {
- struct hlist_node head;
- unsigned long key;
-};
-
-struct vmwgfx_open_hash {
- struct hlist_head *table;
- u8 order;
-};
-
-int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order);
-int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
-int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
- unsigned long seed, int bits, int shift,
- unsigned long add);
-int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
- struct vmwgfx_hash_item **item);
-
-void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key);
-int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key);
-int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
-void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht);
-
-/*
- * RCU-safe interface
- *
- * The user of this API needs to make sure that two or more instances of the
- * hash table manipulation functions are never run simultaneously.
- * The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously
- * with any of the manipulation functions as long as it's called from within
- * an RCU read-locked section.
- */
-#define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item
-#define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please
-#define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key
-#define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item
-#define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item
-
-#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 214829c32ed8..257f090071f1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -25,15 +25,15 @@
*
**************************************************************************/
+#include "vmwgfx_kms.h"
+#include "vmw_surface_cache.h"
+
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_rect.h>
#include <drm/drm_sysfs.h>
-#include <drm/drm_vblank.h>
-
-#include "vmwgfx_kms.h"
void vmw_du_cleanup(struct vmw_display_unit *du)
{
@@ -52,9 +52,9 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
* Display Unit Cursor functions
*/
+static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps);
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
- struct ttm_buffer_object *bo,
- struct ttm_bo_kmap_obj *map,
+ struct vmw_plane_state *vps,
u32 *image, u32 width, u32 height,
u32 hotspotX, u32 hotspotY);
@@ -63,23 +63,23 @@ struct vmw_svga_fifo_cmd_define_cursor {
SVGAFifoCmdDefineAlphaCursor cursor;
};
-static void vmw_cursor_update_image(struct vmw_private *dev_priv,
- struct ttm_buffer_object *cm_bo,
- struct ttm_bo_kmap_obj *cm_map,
- u32 *image, u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
+/**
+ * vmw_send_define_cursor_cmd - queue a define cursor command
+ * @dev_priv: the private driver struct
+ * @image: buffer which holds the cursor image
+ * @width: width of the mouse cursor image
+ * @height: height of the mouse cursor image
+ * @hotspotX: the horizontal position of mouse hotspot
+ * @hotspotY: the vertical position of mouse hotspot
+ */
+static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
{
struct vmw_svga_fifo_cmd_define_cursor *cmd;
const u32 image_size = width * height * sizeof(*image);
const u32 cmd_size = sizeof(*cmd) + image_size;
- if (cm_bo != NULL) {
- vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image,
- width, height,
- hotspotX, hotspotY);
- return;
- }
-
/* Try to reserve fifocmd space and swallow any failures;
such reservations cannot be left unconsumed for long
under the risk of clogging other fifocmd users, so
@@ -87,7 +87,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv,
other fallible KMS-atomic resources at prepare_fb */
cmd = VMW_CMD_RESERVE(dev_priv, cmd_size);
- if (unlikely(cmd == NULL))
+ if (unlikely(!cmd))
return;
memset(cmd, 0, sizeof(*cmd));
@@ -105,11 +105,39 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv,
}
/**
+ * vmw_cursor_update_image - update the cursor image on the provided plane
+ * @dev_priv: the private driver struct
+ * @vps: the plane state of the cursor plane
+ * @image: buffer which holds the cursor image
+ * @width: width of the mouse cursor image
+ * @height: height of the mouse cursor image
+ * @hotspotX: the horizontal position of mouse hotspot
+ * @hotspotY: the vertical position of mouse hotspot
+ */
+static void vmw_cursor_update_image(struct vmw_private *dev_priv,
+ struct vmw_plane_state *vps,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
+{
+ if (vps->cursor.bo)
+ vmw_cursor_update_mob(dev_priv, vps, image,
+ vps->base.crtc_w, vps->base.crtc_h,
+ hotspotX, hotspotY);
+
+ else
+ vmw_send_define_cursor_cmd(dev_priv, image, width, height,
+ hotspotX, hotspotY);
+}
+
+
+/**
* vmw_cursor_update_mob - Update cursor vis CursorMob mechanism
*
+ * Called from inside vmw_du_cursor_plane_atomic_update to actually
+ * make the cursor-image live.
+ *
* @dev_priv: device to work with
- * @bo: BO for the MOB
- * @map: kmap obj for the BO
+ * @vps: the plane state of the cursor plane
* @image: cursor source data to fill the MOB with
* @width: source data width
* @height: source data height
@@ -117,8 +145,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv,
* @hotspotY: cursor hotspot Y
*/
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
- struct ttm_buffer_object *bo,
- struct ttm_bo_kmap_obj *map,
+ struct vmw_plane_state *vps,
u32 *image, u32 width, u32 height,
u32 hotspotX, u32 hotspotY)
{
@@ -127,11 +154,11 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
const u32 image_size = width * height * sizeof(*image);
bool dummy;
- BUG_ON(!image);
-
- header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy);
+ header = ttm_kmap_obj_virtual(&vps->cursor.map, &dummy);
alpha_header = &header->header.alphaHeader;
+ memset(header, 0, sizeof(*header));
+
header->type = SVGA_ALPHA_CURSOR;
header->sizeInBytes = image_size;
@@ -141,100 +168,159 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
alpha_header->height = height;
memcpy(header + 1, image, image_size);
-
- vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start);
+ vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID,
+ vps->cursor.bo->resource->start);
}
-void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp)
-{
- size_t i;
- for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) {
- if (vcp->cursor_mob[i] != NULL) {
- ttm_bo_unpin(vcp->cursor_mob[i]);
- ttm_bo_put(vcp->cursor_mob[i]);
- kfree(vcp->cursor_mob[i]);
- vcp->cursor_mob[i] = NULL;
- }
- }
+static u32 vmw_du_cursor_mob_size(u32 w, u32 h)
+{
+ return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader);
}
-#define CURSOR_MOB_SIZE(dimension) \
- ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader))
+/**
+ * vmw_du_cursor_plane_acquire_image -- Acquire the image data
+ * @vps: cursor plane state
+ */
+static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps)
+{
+ bool dummy;
+ if (vps->surf) {
+ if (vps->surf_mapped)
+ return vmw_bo_map_and_cache(vps->surf->res.backup);
+ return vps->surf->snooper.image;
+ } else if (vps->bo)
+ return ttm_kmap_obj_virtual(&vps->bo->map, &dummy);
+ return NULL;
+}
-int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor)
+static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps,
+ struct vmw_plane_state *new_vps)
{
- struct vmw_private *dev_priv = cursor->base.dev->dev_private;
- uint32_t cursor_max_dim, mob_max_size;
- int ret = 0;
- size_t i;
+ void *old_image;
+ void *new_image;
+ u32 size;
+ bool changed;
- if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
- return -ENOSYS;
+ if (old_vps->base.crtc_w != new_vps->base.crtc_w ||
+ old_vps->base.crtc_h != new_vps->base.crtc_h)
+ return true;
- mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
- cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
+ if (old_vps->cursor.hotspot_x != new_vps->cursor.hotspot_x ||
+ old_vps->cursor.hotspot_y != new_vps->cursor.hotspot_y)
+ return true;
- if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size)
- cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */
+ size = new_vps->base.crtc_w * new_vps->base.crtc_h * sizeof(u32);
- for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) {
- struct ttm_buffer_object **const bo = &cursor->cursor_mob[i];
+ old_image = vmw_du_cursor_plane_acquire_image(old_vps);
+ new_image = vmw_du_cursor_plane_acquire_image(new_vps);
- ret = vmw_bo_create_kernel(dev_priv,
- CURSOR_MOB_SIZE(cursor_max_dim),
- &vmw_mob_placement, bo);
+ changed = false;
+ if (old_image && new_image)
+ changed = memcmp(old_image, new_image, size) != 0;
- if (ret != 0)
- goto teardown;
+ return changed;
+}
- if ((*bo)->resource->mem_type != VMW_PL_MOB) {
- DRM_ERROR("Obtained buffer object is not a MOB.\n");
- ret = -ENOSYS;
- goto teardown;
- }
+static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo)
+{
+ if (!(*bo))
+ return;
- /* Fence the mob creation so we are guarateed to have the mob */
- ret = ttm_bo_reserve(*bo, false, false, NULL);
+ ttm_bo_unpin(*bo);
+ ttm_bo_put(*bo);
+ kfree(*bo);
+ *bo = NULL;
+}
- if (ret != 0)
- goto teardown;
+static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp,
+ struct vmw_plane_state *vps)
+{
+ u32 i;
- vmw_bo_fence_single(*bo, NULL);
+ if (!vps->cursor.bo)
+ return;
- ttm_bo_unreserve(*bo);
+ vmw_du_cursor_plane_unmap_cm(vps);
- drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n",
- (*bo)->resource->start, cursor_max_dim);
+ /* Look for a free slot to return this mob to the cache. */
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
+ if (!vcp->cursor_mobs[i]) {
+ vcp->cursor_mobs[i] = vps->cursor.bo;
+ vps->cursor.bo = NULL;
+ return;
+ }
}
- return 0;
-
-teardown:
- vmw_du_destroy_cursor_mob_array(cursor);
+ /* Cache is full: See if this mob is bigger than an existing mob. */
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
+ if (vcp->cursor_mobs[i]->base.size <
+ vps->cursor.bo->base.size) {
+ vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]);
+ vcp->cursor_mobs[i] = vps->cursor.bo;
+ vps->cursor.bo = NULL;
+ return;
+ }
+ }
- return ret;
+ /* Destroy it if it's not worth caching. */
+ vmw_du_destroy_cursor_mob(&vps->cursor.bo);
}
-#undef CURSOR_MOB_SIZE
-
-static void vmw_cursor_update_bo(struct vmw_private *dev_priv,
- struct ttm_buffer_object *cm_bo,
- struct ttm_bo_kmap_obj *cm_map,
- struct vmw_buffer_object *bo,
- u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
+static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp,
+ struct vmw_plane_state *vps)
{
- void *virtual;
- bool dummy;
+ struct vmw_private *dev_priv = vcp->base.dev->dev_private;
+ u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
+ u32 i;
+ u32 cursor_max_dim, mob_max_size;
+ int ret;
+
+ if (!dev_priv->has_mob ||
+ (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
+ return -EINVAL;
+
+ mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
+ cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
+
+ if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim ||
+ vps->base.crtc_h > cursor_max_dim)
+ return -EINVAL;
- virtual = ttm_kmap_obj_virtual(&bo->map, &dummy);
- if (virtual) {
- vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual,
- width, height,
- hotspotX, hotspotY);
- atomic_dec(&bo->base_mapped_count);
+ if (vps->cursor.bo) {
+ if (vps->cursor.bo->base.size >= size)
+ return 0;
+ vmw_du_put_cursor_mob(vcp, vps);
+ }
+
+ /* Look for an unused mob in the cache. */
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
+ if (vcp->cursor_mobs[i] &&
+ vcp->cursor_mobs[i]->base.size >= size) {
+ vps->cursor.bo = vcp->cursor_mobs[i];
+ vcp->cursor_mobs[i] = NULL;
+ return 0;
+ }
}
+ /* Create a new mob if we can't find an existing one. */
+ ret = vmw_bo_create_kernel(dev_priv, size, &vmw_mob_placement,
+ &vps->cursor.bo);
+
+ if (ret != 0)
+ return ret;
+
+ /* Fence the mob creation so we are guarateed to have the mob */
+ ret = ttm_bo_reserve(vps->cursor.bo, false, false, NULL);
+ if (ret != 0)
+ goto teardown;
+
+ vmw_bo_fence_single(vps->cursor.bo, NULL);
+ ttm_bo_unreserve(vps->cursor.bo);
+ return 0;
+
+teardown:
+ vmw_du_destroy_cursor_mob(&vps->cursor.bo);
+ return ret;
}
@@ -266,7 +352,6 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv,
spin_unlock(&dev_priv->cursor_lock);
}
-
void vmw_kms_cursor_snoop(struct vmw_surface *srf,
struct ttm_object_file *tfile,
struct ttm_buffer_object *bo,
@@ -284,10 +369,13 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
SVGA3dCmdSurfaceDMA dma;
} *cmd;
int i, ret;
+ const struct SVGA3dSurfaceDesc *desc =
+ vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
+ const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock;
cmd = container_of(header, struct vmw_dma_cmd, header);
- /* No snooper installed */
+ /* No snooper installed, nothing to copy */
if (!srf->snooper.image)
return;
@@ -308,7 +396,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
if (cmd->dma.guest.ptr.offset % PAGE_SIZE ||
box->x != 0 || box->y != 0 || box->z != 0 ||
box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
- box->d != 1 || box_count != 1) {
+ box->d != 1 || box_count != 1 ||
+ box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) {
/* TODO handle none page aligned offsets */
/* TODO handle more dst & src != 0 */
/* TODO handle more then one copy */
@@ -322,7 +411,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
}
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
- kmap_num = (64*64*4) >> PAGE_SHIFT;
+ kmap_num = (VMW_CURSOR_SNOOP_HEIGHT*image_pitch) >> PAGE_SHIFT;
ret = ttm_bo_reserve(bo, true, false, NULL);
if (unlikely(ret != 0)) {
@@ -336,14 +425,15 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
virtual = ttm_kmap_obj_virtual(&map, &dummy);
- if (box->w == 64 && cmd->dma.guest.pitch == 64*4) {
- memcpy(srf->snooper.image, virtual, 64*64*4);
+ if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) {
+ memcpy(srf->snooper.image, virtual,
+ VMW_CURSOR_SNOOP_HEIGHT*image_pitch);
} else {
/* Image is unsigned pointer. */
for (i = 0; i < box->h; i++)
- memcpy(srf->snooper.image + i * 64,
+ memcpy(srf->snooper.image + i * image_pitch,
virtual + i * cmd->dma.guest.pitch,
- box->w * 4);
+ box->w * desc->pitchBytesPerBlock);
}
srf->snooper.age++;
@@ -387,15 +477,17 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
du = vmw_crtc_to_du(crtc);
if (!du->cursor_surface ||
- du->cursor_age == du->cursor_surface->snooper.age)
+ du->cursor_age == du->cursor_surface->snooper.age ||
+ !du->cursor_surface->snooper.image)
continue;
du->cursor_age = du->cursor_surface->snooper.age;
- vmw_cursor_update_image(dev_priv, NULL, NULL,
- du->cursor_surface->snooper.image,
- 64, 64,
- du->hotspot_x + du->core_hotspot_x,
- du->hotspot_y + du->core_hotspot_y);
+ vmw_send_define_cursor_cmd(dev_priv,
+ du->cursor_surface->snooper.image,
+ VMW_CURSOR_SNOOP_WIDTH,
+ VMW_CURSOR_SNOOP_HEIGHT,
+ du->hotspot_x + du->core_hotspot_x,
+ du->hotspot_y + du->core_hotspot_y);
}
mutex_unlock(&dev->mode_config.mutex);
@@ -404,8 +496,14 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
{
+ struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
+ u32 i;
+
vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
- vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane));
+
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++)
+ vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]);
+
drm_plane_cleanup(plane);
}
@@ -463,6 +561,87 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane,
/**
+ * vmw_du_cursor_plane_map_cm - Maps the cursor mobs.
+ *
+ * @vps: plane_state
+ *
+ * Returns 0 on success
+ */
+
+static int
+vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps)
+{
+ int ret;
+ u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
+ struct ttm_buffer_object *bo = vps->cursor.bo;
+
+ if (!bo)
+ return -EINVAL;
+
+ if (bo->base.size < size)
+ return -EINVAL;
+
+ if (vps->cursor.mapped)
+ return 0;
+
+ ret = ttm_bo_reserve(bo, false, false, NULL);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+
+ ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vps->cursor.map);
+
+ /*
+ * We just want to try to get mob bind to finish
+ * so that the first write to SVGA_REG_CURSOR_MOBID
+ * is done with a buffer that the device has already
+ * seen
+ */
+ (void) ttm_bo_wait(bo, false, false);
+
+ ttm_bo_unreserve(bo);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+
+ vps->cursor.mapped = true;
+
+ return 0;
+}
+
+
+/**
+ * vmw_du_cursor_plane_unmap_cm - Unmaps the cursor mobs.
+ *
+ * @vps: state of the cursor plane
+ *
+ * Returns 0 on success
+ */
+
+static int
+vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps)
+{
+ int ret = 0;
+ struct ttm_buffer_object *bo = vps->cursor.bo;
+
+ if (!vps->cursor.mapped)
+ return 0;
+
+ if (!bo)
+ return 0;
+
+ ret = ttm_bo_reserve(bo, true, false, NULL);
+ if (likely(ret == 0)) {
+ ttm_bo_kunmap(&vps->cursor.map);
+ ttm_bo_unreserve(bo);
+ vps->cursor.mapped = false;
+ }
+
+ return ret;
+}
+
+
+/**
* vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface
*
* @plane: cursor plane
@@ -476,10 +655,16 @@ void
vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
+ struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
bool dummy;
- if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
+ if (vps->surf_mapped) {
+ vmw_bo_unmap(vps->surf->res.backup);
+ vps->surf_mapped = false;
+ }
+
+ if (vps->bo && ttm_kmap_obj_virtual(&vps->bo->map, &dummy)) {
const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
if (likely(ret == 0)) {
@@ -489,14 +674,8 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
}
}
- if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) {
- const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL);
-
- if (likely(ret == 0)) {
- ttm_bo_kunmap(&vps->cm_map);
- ttm_bo_unreserve(vps->cm_bo);
- }
- }
+ vmw_du_cursor_plane_unmap_cm(vps);
+ vmw_du_put_cursor_mob(vcp, vps);
vmw_du_plane_unpin_surf(vps, false);
@@ -511,6 +690,7 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
}
}
+
/**
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
*
@@ -526,8 +706,6 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_framebuffer *fb = new_state->fb;
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
- struct ttm_buffer_object *cm_bo = NULL;
- bool dummy;
int ret = 0;
if (vps->surf) {
@@ -550,13 +728,14 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
}
}
- vps->cm_bo = NULL;
-
- if (vps->surf == NULL && vps->bo != NULL) {
+ if (!vps->surf && vps->bo) {
const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
- /* Not using vmw_bo_map_and_cache() helper here as we need to reserve
- the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */
+ /*
+ * Not using vmw_bo_map_and_cache() helper here as we need to
+ * reserve the ttm_buffer_object first which
+ * vmw_bo_map_and_cache() omits.
+ */
ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
if (unlikely(ret != 0))
@@ -571,69 +750,24 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
if (unlikely(ret != 0))
return -ENOMEM;
+ } else if (vps->surf && !vps->bo && vps->surf->res.backup) {
+
+ WARN_ON(vps->surf->snooper.image);
+ ret = ttm_bo_reserve(&vps->surf->res.backup->base, true, false,
+ NULL);
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+ vmw_bo_map_and_cache(vps->surf->res.backup);
+ ttm_bo_unreserve(&vps->surf->res.backup->base);
+ vps->surf_mapped = true;
}
if (vps->surf || vps->bo) {
- unsigned cursor_mob_idx = vps->cursor_mob_idx;
-
- /* Lazily set up cursor MOBs just once -- no reattempts. */
- if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL)
- if (vmw_du_create_cursor_mob_array(vcp) != 0)
- vps->cursor_mob_idx = cursor_mob_idx = -1U;
-
- if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) {
- const u32 size = sizeof(SVGAGBCursorHeader) +
- new_state->crtc_w * new_state->crtc_h * sizeof(u32);
-
- cm_bo = vcp->cursor_mob[cursor_mob_idx];
-
- if (cm_bo->resource->num_pages * PAGE_SIZE < size) {
- ret = -EINVAL;
- goto error_bo_unmap;
- }
-
- ret = ttm_bo_reserve(cm_bo, false, false, NULL);
-
- if (unlikely(ret != 0)) {
- ret = -ENOMEM;
- goto error_bo_unmap;
- }
-
- ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map);
-
- /*
- * We just want to try to get mob bind to finish
- * so that the first write to SVGA_REG_CURSOR_MOBID
- * is done with a buffer that the device has already
- * seen
- */
- (void) ttm_bo_wait(cm_bo, false, false);
-
- ttm_bo_unreserve(cm_bo);
-
- if (unlikely(ret != 0)) {
- ret = -ENOMEM;
- goto error_bo_unmap;
- }
-
- vps->cursor_mob_idx = cursor_mob_idx ^ 1;
- vps->cm_bo = cm_bo;
- }
+ vmw_du_get_cursor_mob(vcp, vps);
+ vmw_du_cursor_plane_map_cm(vps);
}
return 0;
-
-error_bo_unmap:
- if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
- const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
- if (likely(ret == 0)) {
- atomic_dec(&vps->bo->base_mapped_count);
- ttm_bo_kunmap(&vps->bo->map);
- ttm_bo_unreserve(&vps->bo->base);
- }
- }
-
- return ret;
}
@@ -649,7 +783,9 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
+ struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state);
s32 hotspot_x, hotspot_y;
+ bool dummy;
hotspot_x = du->hotspot_x;
hotspot_y = du->hotspot_y;
@@ -662,23 +798,38 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
du->cursor_surface = vps->surf;
du->cursor_bo = vps->bo;
+ if (!vps->surf && !vps->bo) {
+ vmw_cursor_update_position(dev_priv, false, 0, 0);
+ return;
+ }
+
+ vps->cursor.hotspot_x = hotspot_x;
+ vps->cursor.hotspot_y = hotspot_y;
+
if (vps->surf) {
du->cursor_age = du->cursor_surface->snooper.age;
+ }
- vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map,
- vps->surf->snooper.image,
- new_state->crtc_w,
- new_state->crtc_h,
- hotspot_x, hotspot_y);
- } else if (vps->bo) {
- vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map,
- vps->bo,
- new_state->crtc_w,
- new_state->crtc_h,
- hotspot_x, hotspot_y);
+ if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) {
+ /*
+ * If it hasn't changed, avoid making the device do extra
+ * work by keeping the old cursor active.
+ */
+ struct vmw_cursor_plane_state tmp = old_vps->cursor;
+ old_vps->cursor = vps->cursor;
+ vps->cursor = tmp;
} else {
- vmw_cursor_update_position(dev_priv, false, 0, 0);
- return;
+ void *image = vmw_du_cursor_plane_acquire_image(vps);
+ if (image)
+ vmw_cursor_update_image(dev_priv, vps, image,
+ new_state->crtc_w,
+ new_state->crtc_h,
+ hotspot_x, hotspot_y);
+ }
+
+ if (vps->bo) {
+ if (ttm_kmap_obj_virtual(&vps->bo->map, &dummy))
+ atomic_dec(&vps->bo->base_mapped_count);
}
du->cursor_x = new_state->crtc_x + du->set_gui_x;
@@ -778,12 +929,16 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
}
- if (!vmw_framebuffer_to_vfb(fb)->bo)
+ if (!vmw_framebuffer_to_vfb(fb)->bo) {
surface = vmw_framebuffer_to_vfbs(fb)->surface;
- if (surface && !surface->snooper.image) {
- DRM_ERROR("surface not suitable for cursor\n");
- return -EINVAL;
+ WARN_ON(!surface);
+
+ if (!surface ||
+ (!surface->snooper.image && !surface->res.backup)) {
+ DRM_ERROR("surface not suitable for cursor\n");
+ return -EINVAL;
+ }
}
return 0;
@@ -831,15 +986,6 @@ void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
- struct drm_pending_vblank_event *event = crtc->state->event;
-
- if (event) {
- crtc->state->event = NULL;
-
- spin_lock_irq(&crtc->dev->event_lock);
- drm_crtc_send_vblank_event(crtc, event);
- spin_unlock_irq(&crtc->dev->event_lock);
- }
}
@@ -943,6 +1089,8 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
vps->pinned = 0;
vps->cpp = 0;
+ memset(&vps->cursor, 0, sizeof(vps->cursor));
+
/* Each ref counted resource needs to be acquired again */
if (vps->surf)
(void) vmw_surface_reference(vps->surf);
@@ -997,7 +1145,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane,
{
struct vmw_plane_state *vps = vmw_plane_state_to_vps(state);
-
/* Should have been freed by cleanup_fb */
if (vps->surf)
vmw_surface_unreference(&vps->surf);
@@ -1664,7 +1811,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
if (IS_ERR(vfb)) {
ret = PTR_ERR(vfb);
goto err_out;
- }
+ }
err_out:
/* vmw_user_lookup_handle takes one ref so does new_fb */
@@ -2052,6 +2199,8 @@ int vmw_kms_init(struct vmw_private *dev_priv)
dev->mode_config.min_height = 1;
dev->mode_config.max_width = dev_priv->texture_max_width;
dev->mode_config.max_height = dev_priv->texture_max_height;
+ dev->mode_config.preferred_depth = dev_priv->assume_16bpp ? 16 : 32;
+ dev->mode_config.prefer_shadow_fbdev = !dev_priv->has_mob;
drm_mode_create_suggested_offset_properties(dev);
vmw_kms_create_hotplug_mode_update_property(dev_priv);
@@ -2093,7 +2242,6 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
struct drm_crtc *crtc;
int ret = 0;
-
mutex_lock(&dev->mode_config.mutex);
if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) {
@@ -2155,30 +2303,6 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
dev_priv->max_primary_mem : dev_priv->vram_size);
}
-
-/*
- * Function called by DRM code called with vbl_lock held.
- */
-u32 vmw_get_vblank_counter(struct drm_crtc *crtc)
-{
- return 0;
-}
-
-/*
- * Function called by DRM code called with vbl_lock held.
- */
-int vmw_enable_vblank(struct drm_crtc *crtc)
-{
- return -EINVAL;
-}
-
-/*
- * Function called by DRM code called with vbl_lock held.
- */
-void vmw_disable_vblank(struct drm_crtc *crtc)
-{
-}
-
/**
* vmw_du_update_layout - Update the display unit with topology from resolution
* plugin and generate DRM uevent
@@ -2207,7 +2331,7 @@ retry:
if (ret == -EDEADLK) {
drm_modeset_backoff(&ctx);
goto retry;
- }
+ }
goto out_fini;
}
}
@@ -2222,8 +2346,8 @@ retry:
du->gui_x = rects[du->unit].x1;
du->gui_y = rects[du->unit].y1;
} else {
- du->pref_width = 800;
- du->pref_height = 600;
+ du->pref_width = VMWGFX_MIN_INITIAL_WIDTH;
+ du->pref_height = VMWGFX_MIN_INITIAL_HEIGHT;
du->pref_active = false;
du->gui_x = 0;
du->gui_y = 0;
@@ -2250,13 +2374,13 @@ retry:
}
con->status = vmw_du_connector_detect(con, true);
}
-
- drm_sysfs_hotplug_event(dev);
out_fini:
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
mutex_unlock(&dev->mode_config.mutex);
+ drm_sysfs_hotplug_event(dev);
+
return 0;
}
@@ -2536,10 +2660,9 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
int ret, i;
if (!arg->num_outputs) {
- struct drm_rect def_rect = {0, 0, 800, 600};
- VMW_DEBUG_KMS("Default layout x1 = %d y1 = %d x2 = %d y2 = %d\n",
- def_rect.x1, def_rect.y1,
- def_rect.x2, def_rect.y2);
+ struct drm_rect def_rect = {0, 0,
+ VMWGFX_MIN_INITIAL_WIDTH,
+ VMWGFX_MIN_INITIAL_HEIGHT};
vmw_du_update_layout(dev_priv, 1, &def_rect);
return 0;
}
@@ -2834,68 +2957,6 @@ int vmw_kms_update_proxy(struct vmw_resource *res,
return 0;
}
-int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
- unsigned unit,
- u32 max_width,
- u32 max_height,
- struct drm_connector **p_con,
- struct drm_crtc **p_crtc,
- struct drm_display_mode **p_mode)
-{
- struct drm_connector *con;
- struct vmw_display_unit *du;
- struct drm_display_mode *mode;
- int i = 0;
- int ret = 0;
-
- mutex_lock(&dev_priv->drm.mode_config.mutex);
- list_for_each_entry(con, &dev_priv->drm.mode_config.connector_list,
- head) {
- if (i == unit)
- break;
-
- ++i;
- }
-
- if (&con->head == &dev_priv->drm.mode_config.connector_list) {
- DRM_ERROR("Could not find initial display unit.\n");
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (list_empty(&con->modes))
- (void) vmw_du_connector_fill_modes(con, max_width, max_height);
-
- if (list_empty(&con->modes)) {
- DRM_ERROR("Could not find initial display mode.\n");
- ret = -EINVAL;
- goto out_unlock;
- }
-
- du = vmw_connector_to_du(con);
- *p_con = con;
- *p_crtc = &du->crtc;
-
- list_for_each_entry(mode, &con->modes, head) {
- if (mode->type & DRM_MODE_TYPE_PREFERRED)
- break;
- }
-
- if (&mode->head == &con->modes) {
- WARN_ONCE(true, "Could not find initial preferred mode.\n");
- *p_mode = list_first_entry(&con->modes,
- struct drm_display_mode,
- head);
- } else {
- *p_mode = mode;
- }
-
- out_unlock:
- mutex_unlock(&dev_priv->drm.mode_config.mutex);
-
- return ret;
-}
-
/**
* vmw_kms_create_implicit_placement_property - Set up the implicit placement
* property.
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 85f86faa3243..4d6e7b555db7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -272,6 +272,14 @@ struct vmw_crtc_state {
struct drm_crtc_state base;
};
+struct vmw_cursor_plane_state {
+ struct ttm_buffer_object *bo;
+ struct ttm_bo_kmap_obj map;
+ bool mapped;
+ s32 hotspot_x;
+ s32 hotspot_y;
+};
+
/**
* Derived class for plane state object
*
@@ -295,13 +303,8 @@ struct vmw_plane_state {
/* For CPU Blit */
unsigned int cpp;
- /* CursorMob flipping index; -1 if cursor mobs not used */
- unsigned int cursor_mob_idx;
- /* Currently-active CursorMob */
- struct ttm_buffer_object *cm_bo;
- /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update
- IFF currently-active CursorMob above is valid */
- struct ttm_bo_kmap_obj cm_map;
+ bool surf_mapped;
+ struct vmw_cursor_plane_state cursor;
};
@@ -338,11 +341,12 @@ struct vmw_connector_state {
* Derived class for cursor plane object
*
* @base DRM plane object
- * @cursor_mob array of two MOBs for CursorMob flipping
+ * @cursor.cursor_mobs Cursor mobs available for re-use
*/
struct vmw_cursor_plane {
struct drm_plane base;
- struct ttm_buffer_object *cursor_mob[2];
+
+ struct ttm_buffer_object *cursor_mobs[3];
};
/**
@@ -458,13 +462,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_surface *surface,
bool only_2d,
const struct drm_mode_fb_cmd2 *mode_cmd);
-int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
- unsigned unit,
- u32 max_width,
- u32 max_height,
- struct drm_connector **p_con,
- struct drm_crtc **p_crtc,
- struct drm_display_mode **p_mode);
void vmw_guess_mode_timing(struct drm_display_mode *mode);
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
@@ -472,8 +469,6 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
/* Universal Plane Helpers */
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
-int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp);
-void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
/* Atomic Helpers */
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index b8761f16dd78..a56e5d0ca3c6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -28,7 +28,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
-#include <drm/drm_vblank.h>
#include "vmwgfx_kms.h"
@@ -235,9 +234,6 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
.atomic_destroy_state = vmw_du_crtc_destroy_state,
.set_config = drm_atomic_helper_set_config,
- .get_vblank_counter = vmw_get_vblank_counter,
- .enable_vblank = vmw_enable_vblank,
- .disable_vblank = vmw_disable_vblank,
};
@@ -507,10 +503,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL;
- ret = drm_vblank_init(dev, num_display_units);
- if (ret != 0)
- goto err_free;
-
vmw_kms_create_implicit_placement_property(dev_priv);
for (i = 0; i < num_display_units; ++i) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h b/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h
index 0509f55f07b4..ede74c7fdbbf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h
@@ -29,6 +29,7 @@
#define _VMWGFX_MKSSTAT_H_
#include <asm/page.h>
+#include <linux/kconfig.h>
/* Reservation marker for mksstat pid's */
#define MKSSTAT_PID_RESERVED -1
@@ -41,6 +42,7 @@
typedef enum {
MKSSTAT_KERN_EXECBUF, /* vmw_execbuf_ioctl */
+ MKSSTAT_KERN_COTABLE_RESIZE,
MKSSTAT_KERN_COUNT /* Reserved entry; always last */
} mksstat_kern_stats_t;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
index 089046fa21be..e76976a95a1e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
@@ -85,7 +85,14 @@ struct rpc_channel {
u32 cookie_low;
};
-
+#if IS_ENABLED(CONFIG_DRM_VMWGFX_MKSSTATS)
+/* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */
+static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] =
+{
+ { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" },
+ { "vmw_cotable_resize", "vmw_cotable_resize" },
+};
+#endif
/**
* vmw_open_channel
@@ -695,12 +702,6 @@ static inline void hypervisor_ppn_remove(PPN64 pfn)
/* Header to the text description of mksGuestStat instance descriptor */
#define MKSSTAT_KERNEL_DESCRIPTION "vmwgfx"
-/* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */
-static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] =
-{
- { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" },
-};
-
/**
* mksstat_init_record: Initializes an MKSGuestStatCounter-based record
* for the respective mksGuestStat index.
@@ -786,6 +787,7 @@ static int mksstat_init_kern_id(struct page **ppage)
/* Set up all kernel-internal counters and corresponding structures */
pstrs_acc = pstrs;
pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_EXECBUF, pstat, pinfo, pstrs_acc);
+ pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_COTABLE_RESIZE, pstat, pinfo, pstrs_acc);
/* Add new counters above, in their order of appearance in mksstat_kern_stats_t */
@@ -1014,8 +1016,6 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
struct vmw_private *const dev_priv = vmw_priv(dev);
- struct page *page;
- MKSGuestStatInstanceDescriptor *pdesc;
const size_t num_pages_stat = PFN_UP(arg->stat_len);
const size_t num_pages_info = PFN_UP(arg->info_len);
const size_t num_pages_strs = PFN_UP(arg->strs_len);
@@ -1023,10 +1023,13 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
long nr_pinned_stat;
long nr_pinned_info;
long nr_pinned_strs;
- struct page *pages_stat[ARRAY_SIZE(pdesc->statPPNs)];
- struct page *pages_info[ARRAY_SIZE(pdesc->infoPPNs)];
- struct page *pages_strs[ARRAY_SIZE(pdesc->strsPPNs)];
+ MKSGuestStatInstanceDescriptor *pdesc;
+ struct page *page = NULL;
+ struct page **pages_stat = NULL;
+ struct page **pages_info = NULL;
+ struct page **pages_strs = NULL;
size_t i, slot;
+ int ret_err = -ENOMEM;
arg->id = -1;
@@ -1054,13 +1057,23 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
BUG_ON(dev_priv->mksstat_user_pages[slot]);
+ /* Allocate statically-sized temp arrays for pages -- too big to keep in frame */
+ pages_stat = (struct page **)kmalloc_array(
+ ARRAY_SIZE(pdesc->statPPNs) +
+ ARRAY_SIZE(pdesc->infoPPNs) +
+ ARRAY_SIZE(pdesc->strsPPNs), sizeof(*pages_stat), GFP_KERNEL);
+
+ if (!pages_stat)
+ goto err_nomem;
+
+ pages_info = pages_stat + ARRAY_SIZE(pdesc->statPPNs);
+ pages_strs = pages_info + ARRAY_SIZE(pdesc->infoPPNs);
+
/* Allocate a page for the instance descriptor */
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!page) {
- atomic_set(&dev_priv->mksstat_user_pids[slot], 0);
- return -ENOMEM;
- }
+ if (!page)
+ goto err_nomem;
/* Set up the instance descriptor */
pdesc = page_address(page);
@@ -1075,9 +1088,8 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
ARRAY_SIZE(pdesc->description) - 1);
if (desc_len < 0) {
- atomic_set(&dev_priv->mksstat_user_pids[slot], 0);
- __free_page(page);
- return -EFAULT;
+ ret_err = -EFAULT;
+ goto err_nomem;
}
reset_ppn_array(pdesc->statPPNs, ARRAY_SIZE(pdesc->statPPNs));
@@ -1085,21 +1097,21 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
reset_ppn_array(pdesc->strsPPNs, ARRAY_SIZE(pdesc->strsPPNs));
/* Pin mksGuestStat user pages and store those in the instance descriptor */
- nr_pinned_stat = pin_user_pages(arg->stat, num_pages_stat, FOLL_LONGTERM, pages_stat, NULL);
+ nr_pinned_stat = pin_user_pages_fast(arg->stat, num_pages_stat, FOLL_LONGTERM, pages_stat);
if (num_pages_stat != nr_pinned_stat)
goto err_pin_stat;
for (i = 0; i < num_pages_stat; ++i)
pdesc->statPPNs[i] = page_to_pfn(pages_stat[i]);
- nr_pinned_info = pin_user_pages(arg->info, num_pages_info, FOLL_LONGTERM, pages_info, NULL);
+ nr_pinned_info = pin_user_pages_fast(arg->info, num_pages_info, FOLL_LONGTERM, pages_info);
if (num_pages_info != nr_pinned_info)
goto err_pin_info;
for (i = 0; i < num_pages_info; ++i)
pdesc->infoPPNs[i] = page_to_pfn(pages_info[i]);
- nr_pinned_strs = pin_user_pages(arg->strs, num_pages_strs, FOLL_LONGTERM, pages_strs, NULL);
+ nr_pinned_strs = pin_user_pages_fast(arg->strs, num_pages_strs, FOLL_LONGTERM, pages_strs);
if (num_pages_strs != nr_pinned_strs)
goto err_pin_strs;
@@ -1118,6 +1130,7 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
DRM_DEV_INFO(dev->dev, "pid=%d arg.description='%.*s' id=%zu\n", current->pid, (int)desc_len, pdesc->description, slot);
+ kfree(pages_stat);
return 0;
err_pin_strs:
@@ -1132,9 +1145,13 @@ err_pin_stat:
if (nr_pinned_stat > 0)
unpin_user_pages(pages_stat, nr_pinned_stat);
+err_nomem:
atomic_set(&dev_priv->mksstat_user_pids[slot], 0);
- __free_page(page);
- return -ENOMEM;
+ if (page)
+ __free_page(page);
+ kfree(pages_stat);
+
+ return ret_err;
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
index 7bc99b1279f7..f41f041559f4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
@@ -230,7 +230,7 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
int vmw_bo_dirty_add(struct vmw_buffer_object *vbo)
{
struct vmw_bo_dirty *dirty = vbo->dirty;
- pgoff_t num_pages = vbo->base.resource->num_pages;
+ pgoff_t num_pages = PFN_UP(vbo->base.resource->size);
size_t size;
int ret;
@@ -395,7 +395,7 @@ vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf)
return ret;
page_offset = vmf->pgoff - drm_vma_node_start(&bo->base.vma_node);
- if (unlikely(page_offset >= bo->resource->num_pages)) {
+ if (unlikely(page_offset >= PFN_UP(bo->resource->size))) {
ret = VM_FAULT_SIGBUS;
goto out_unlock;
}
@@ -438,7 +438,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
page_offset = vmf->pgoff -
drm_vma_node_start(&bo->base.vma_node);
- if (page_offset >= bo->resource->num_pages ||
+ if (page_offset >= PFN_UP(bo->resource->size) ||
vmw_resources_clean(vbo, page_offset,
page_offset + PAGE_SIZE,
&allowed_prefault)) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index ecd3c2fc978b..e1f36a09c59c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -29,7 +29,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
-#include <drm/drm_vblank.h>
#include "vmwgfx_kms.h"
@@ -320,9 +319,6 @@ static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.atomic_destroy_state = vmw_du_crtc_destroy_state,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
- .get_vblank_counter = vmw_get_vblank_counter,
- .enable_vblank = vmw_enable_vblank,
- .disable_vblank = vmw_disable_vblank,
};
/*
@@ -730,7 +726,6 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_crtc *crtc = new_state->crtc;
- struct drm_pending_vblank_event *event = NULL;
struct vmw_fence_obj *fence = NULL;
int ret;
@@ -754,24 +749,6 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
return;
}
- /* For error case vblank event is send from vmw_du_crtc_atomic_flush */
- event = crtc->state->event;
- if (event && fence) {
- struct drm_file *file_priv = event->base.file_priv;
-
- ret = vmw_event_fence_action_queue(file_priv,
- fence,
- &event->base,
- &event->event.vbl.tv_sec,
- &event->event.vbl.tv_usec,
- true);
-
- if (unlikely(ret != 0))
- DRM_ERROR("Failed to queue event on fence.\n");
- else
- crtc->state->event = NULL;
- }
-
if (fence)
vmw_fence_obj_unreference(&fence);
}
@@ -947,18 +924,16 @@ err_free:
int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
- int i, ret;
+ int i;
+
+ /* Screen objects won't work if GMR's aren't available */
+ if (!dev_priv->has_gmr)
+ return -ENOSYS;
if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
return -ENOSYS;
}
- ret = -ENOMEM;
-
- ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
- if (unlikely(ret != 0))
- return ret;
-
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
vmw_sou_init(dev_priv, i);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 8650c3aea8f0..0090abe89254 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -29,7 +29,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
-#include <drm/drm_vblank.h>
#include "vmwgfx_kms.h"
#include "vmw_surface_cache.h"
@@ -925,9 +924,6 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
.atomic_destroy_state = vmw_du_crtc_destroy_state,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
- .get_vblank_counter = vmw_get_vblank_counter,
- .enable_vblank = vmw_enable_vblank,
- .disable_vblank = vmw_disable_vblank,
};
@@ -1591,7 +1587,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
struct drm_crtc *crtc = new_state->crtc;
struct vmw_screen_target_display_unit *stdu;
- struct drm_pending_vblank_event *event;
struct vmw_fence_obj *fence = NULL;
struct vmw_private *dev_priv;
int ret;
@@ -1640,23 +1635,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
return;
}
- /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */
- event = crtc->state->event;
- if (event && fence) {
- struct drm_file *file_priv = event->base.file_priv;
-
- ret = vmw_event_fence_action_queue(file_priv,
- fence,
- &event->base,
- &event->event.vbl.tv_sec,
- &event->event.vbl.tv_usec,
- true);
- if (ret)
- DRM_ERROR("Failed to queue event on fence.\n");
- else
- crtc->state->event = NULL;
- }
-
if (fence)
vmw_fence_obj_unreference(&fence);
}
@@ -1883,10 +1861,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
return -ENOSYS;
- ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
- if (unlikely(ret != 0))
- return ret;
-
dev_priv->active_display_unit = vmw_du_screen_target;
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index ace7ca150b03..3bc63ae768f3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -815,11 +815,15 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
res->backup_size = cur_bo_offset;
if (metadata->scanout &&
metadata->num_sizes == 1 &&
- metadata->sizes[0].width == 64 &&
- metadata->sizes[0].height == 64 &&
- metadata->format == SVGA3D_A8R8G8B8) {
-
- srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL);
+ metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH &&
+ metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT &&
+ metadata->format == VMW_CURSOR_SNOOP_FORMAT) {
+ const struct SVGA3dSurfaceDesc *desc =
+ vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
+ const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH *
+ VMW_CURSOR_SNOOP_HEIGHT *
+ desc->pitchBytesPerBlock;
+ srf->snooper.image = kzalloc(cursor_size_bytes, GFP_KERNEL);
if (!srf->snooper.image) {
DRM_ERROR("Failed to allocate cursor_image\n");
ret = -ENOMEM;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
index f46891012be3..f5c4a40fb16d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -180,11 +180,16 @@ vmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
if (!ctx->merge_dups)
return NULL;
- if (ctx->ht) {
+ if (ctx->sw_context) {
struct vmwgfx_hash_item *hash;
+ unsigned long key = (unsigned long) vbo;
- if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash))
- bo_node = container_of(hash, typeof(*bo_node), hash);
+ hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
+ if (hash->key == key) {
+ bo_node = container_of(hash, typeof(*bo_node), hash);
+ break;
+ }
+ }
} else {
struct vmw_validation_bo_node *entry;
@@ -217,11 +222,16 @@ vmw_validation_find_res_dup(struct vmw_validation_context *ctx,
if (!ctx->merge_dups)
return NULL;
- if (ctx->ht) {
+ if (ctx->sw_context) {
struct vmwgfx_hash_item *hash;
+ unsigned long key = (unsigned long) res;
- if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash))
- res_node = container_of(hash, typeof(*res_node), hash);
+ hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
+ if (hash->key == key) {
+ res_node = container_of(hash, typeof(*res_node), hash);
+ break;
+ }
+ }
} else {
struct vmw_validation_res_node *entry;
@@ -269,20 +279,15 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx,
}
} else {
struct ttm_validate_buffer *val_buf;
- int ret;
bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
if (!bo_node)
return -ENOMEM;
- if (ctx->ht) {
+ if (ctx->sw_context) {
bo_node->hash.key = (unsigned long) vbo;
- ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash);
- if (ret) {
- DRM_ERROR("Failed to initialize a buffer "
- "validation entry.\n");
- return ret;
- }
+ hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head,
+ bo_node->hash.key);
}
val_buf = &bo_node->base;
val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
@@ -316,7 +321,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
bool *first_usage)
{
struct vmw_validation_res_node *node;
- int ret;
node = vmw_validation_find_res_dup(ctx, res);
if (node) {
@@ -330,14 +334,9 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
return -ENOMEM;
}
- if (ctx->ht) {
+ if (ctx->sw_context) {
node->hash.key = (unsigned long) res;
- ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash);
- if (ret) {
- DRM_ERROR("Failed to initialize a resource validation "
- "entry.\n");
- return ret;
- }
+ hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key);
}
node->res = vmw_resource_reference_unless_doomed(res);
if (!node->res)
@@ -681,19 +680,19 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx)
struct vmw_validation_bo_node *entry;
struct vmw_validation_res_node *val;
- if (!ctx->ht)
+ if (!ctx->sw_context)
return;
list_for_each_entry(entry, &ctx->bo_list, base.head)
- (void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash);
+ hash_del_rcu(&entry->hash.head);
list_for_each_entry(val, &ctx->resource_list, head)
- (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
+ hash_del_rcu(&val->hash.head);
list_for_each_entry(val, &ctx->resource_ctx_list, head)
- (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
+ hash_del_rcu(&entry->hash.head);
- ctx->ht = NULL;
+ ctx->sw_context = NULL;
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
index f21df053882b..ab9ec226f433 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -29,12 +29,11 @@
#define _VMWGFX_VALIDATION_H_
#include <linux/list.h>
+#include <linux/hashtable.h>
#include <linux/ww_mutex.h>
#include <drm/ttm/ttm_execbuf_util.h>
-#include "vmwgfx_hashtab.h"
-
#define VMW_RES_DIRTY_NONE 0
#define VMW_RES_DIRTY_SET BIT(0)
#define VMW_RES_DIRTY_CLEAR BIT(1)
@@ -59,7 +58,7 @@
* @total_mem: Amount of reserved memory.
*/
struct vmw_validation_context {
- struct vmwgfx_open_hash *ht;
+ struct vmw_sw_context *sw_context;
struct list_head resource_list;
struct list_head resource_ctx_list;
struct list_head bo_list;
@@ -82,16 +81,16 @@ struct vmw_fence_obj;
/**
* DECLARE_VAL_CONTEXT - Declare a validation context with initialization
* @_name: The name of the variable
- * @_ht: The hash table used to find dups or NULL if none
+ * @_sw_context: Contains the hash table used to find dups or NULL if none
* @_merge_dups: Whether to merge duplicate buffer object- or resource
* entries. If set to true, ideally a hash table pointer should be supplied
* as well unless the number of resources and buffer objects per validation
* is known to be very small
*/
#endif
-#define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups) \
+#define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups) \
struct vmw_validation_context _name = \
- { .ht = _ht, \
+ { .sw_context = _sw_context, \
.resource_list = LIST_HEAD_INIT((_name).resource_list), \
.resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \
.bo_list = LIST_HEAD_INIT((_name).bo_list), \
@@ -115,19 +114,6 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx)
}
/**
- * vmw_validation_set_ht - Register a hash table for duplicate finding
- * @ctx: The validation context
- * @ht: Pointer to a hash table to use for duplicate finding
- * This function is intended to be used if the hash table wasn't
- * available at validation context declaration time
- */
-static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx,
- struct vmwgfx_open_hash *ht)
-{
- ctx->ht = ht;
-}
-
-/**
* vmw_validation_bo_reserve - Reserve buffer objects registered with a
* validation context
* @ctx: The validation context
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
index e31554d7139f..4c95ebcdcc2d 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -12,7 +12,6 @@
#include <linux/scatterlist.h>
#include <linux/shmem_fs.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_prime.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/xlnx/Makefile b/drivers/gpu/drm/xlnx/Makefile
index 51c24b72217b..ea1422a39502 100644
--- a/drivers/gpu/drm/xlnx/Makefile
+++ b/drivers/gpu/drm/xlnx/Makefile
@@ -1,2 +1,2 @@
-zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o
+zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o zynqmp_kms.o
obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index bbb365f2d087..3b87eebddc97 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -9,29 +9,19 @@
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_atomic_uapi.h>
-#include <drm/drm_blend.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_device.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
-#include <drm/drm_managed.h>
#include <drm/drm_plane.h>
-#include <drm/drm_vblank.h>
#include <linux/clk.h>
-#include <linux/delay.h>
#include <linux/dma/xilinx_dpdma.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/spinlock.h>
+#include <linux/slab.h>
#include "zynqmp_disp.h"
#include "zynqmp_disp_regs.h"
@@ -72,46 +62,23 @@
#define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS 4
#define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS 6
-#define ZYNQMP_DISP_NUM_LAYERS 2
#define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
/**
* struct zynqmp_disp_format - Display subsystem format information
* @drm_fmt: DRM format (4CC)
* @buf_fmt: AV buffer format
- * @bus_fmt: Media bus formats (live formats)
* @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
* @sf: Scaling factors for color components
*/
struct zynqmp_disp_format {
u32 drm_fmt;
u32 buf_fmt;
- u32 bus_fmt;
bool swap;
const u32 *sf;
};
/**
- * enum zynqmp_disp_layer_id - Layer identifier
- * @ZYNQMP_DISP_LAYER_VID: Video layer
- * @ZYNQMP_DISP_LAYER_GFX: Graphics layer
- */
-enum zynqmp_disp_layer_id {
- ZYNQMP_DISP_LAYER_VID,
- ZYNQMP_DISP_LAYER_GFX
-};
-
-/**
- * enum zynqmp_disp_layer_mode - Layer mode
- * @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode
- * @ZYNQMP_DISP_LAYER_LIVE: live (stream) mode
- */
-enum zynqmp_disp_layer_mode {
- ZYNQMP_DISP_LAYER_NONLIVE,
- ZYNQMP_DISP_LAYER_LIVE
-};
-
-/**
* struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer
* @chan: DMA channel
* @xt: Interleaved DMA descriptor template
@@ -136,8 +103,7 @@ struct zynqmp_disp_layer_info {
};
/**
- * struct zynqmp_disp_layer - Display layer (DRM plane)
- * @plane: DRM plane
+ * struct zynqmp_disp_layer - Display layer
* @id: Layer ID
* @disp: Back pointer to struct zynqmp_disp
* @info: Static layer information
@@ -147,8 +113,7 @@ struct zynqmp_disp_layer_info {
* @mode: Current operation mode
*/
struct zynqmp_disp_layer {
- struct drm_plane plane;
- enum zynqmp_disp_layer_id id;
+ enum zynqmp_dpsub_layer_id id;
struct zynqmp_disp *disp;
const struct zynqmp_disp_layer_info *info;
@@ -156,32 +121,22 @@ struct zynqmp_disp_layer {
const struct zynqmp_disp_format *disp_fmt;
const struct drm_format_info *drm_fmt;
- enum zynqmp_disp_layer_mode mode;
+ enum zynqmp_dpsub_layer_mode mode;
};
/**
* struct zynqmp_disp - Display controller
* @dev: Device structure
- * @drm: DRM core
* @dpsub: Display subsystem
- * @crtc: DRM CRTC
* @blend.base: Register I/O base address for the blender
* @avbuf.base: Register I/O base address for the audio/video buffer manager
* @audio.base: Registers I/O base address for the audio mixer
- * @audio.clk: Audio clock
- * @audio.clk_from_ps: True of the audio clock comes from PS, false from PL
* @layers: Layers (planes)
- * @event: Pending vblank event request
- * @pclk: Pixel clock
- * @pclk_from_ps: True of the video clock comes from PS, false from PL
*/
struct zynqmp_disp {
struct device *dev;
- struct drm_device *drm;
struct zynqmp_dpsub *dpsub;
- struct drm_crtc crtc;
-
struct {
void __iomem *base;
} blend;
@@ -190,16 +145,9 @@ struct zynqmp_disp {
} avbuf;
struct {
void __iomem *base;
- struct clk *clk;
- bool clk_from_ps;
} audio;
- struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS];
-
- struct drm_pending_vblank_event *event;
-
- struct clk *pclk;
- bool pclk_from_ps;
+ struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS];
};
/* -----------------------------------------------------------------------------
@@ -416,14 +364,9 @@ static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)
writel(val, disp->avbuf.base + reg);
}
-static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer)
-{
- return layer->id == ZYNQMP_DISP_LAYER_GFX;
-}
-
static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)
{
- return layer->id == ZYNQMP_DISP_LAYER_VID;
+ return layer->id == ZYNQMP_DPSUB_LAYER_VID;
}
/**
@@ -566,27 +509,25 @@ static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp)
* zynqmp_disp_avbuf_enable_video - Enable a video layer
* @disp: Display controller
* @layer: The layer
- * @mode: Operating mode of layer
*
* Enable the video/graphics buffer for @layer.
*/
static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp,
- struct zynqmp_disp_layer *layer,
- enum zynqmp_disp_layer_mode mode)
+ struct zynqmp_disp_layer *layer)
{
u32 val;
val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
if (zynqmp_disp_layer_is_video(layer)) {
val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;
- if (mode == ZYNQMP_DISP_LAYER_NONLIVE)
+ if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)
val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM;
else
val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE;
} else {
val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;
val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;
- if (mode == ZYNQMP_DISP_LAYER_NONLIVE)
+ if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)
val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;
else
val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE;
@@ -758,8 +699,8 @@ static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp,
* @enable: True to enable global alpha blending
* @alpha: Global alpha value (ignored if @enabled is false)
*/
-static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,
- bool enable, u32 alpha)
+void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,
+ bool enable, u32 alpha)
{
zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,
ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) |
@@ -902,80 +843,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
}
-static void zynqmp_disp_audio_init(struct zynqmp_disp *disp)
-{
- /* Try the live PL audio clock. */
- disp->audio.clk = devm_clk_get(disp->dev, "dp_live_audio_aclk");
- if (!IS_ERR(disp->audio.clk)) {
- disp->audio.clk_from_ps = false;
- return;
- }
-
- /* If the live PL audio clock is not valid, fall back to PS clock. */
- disp->audio.clk = devm_clk_get(disp->dev, "dp_aud_clk");
- if (!IS_ERR(disp->audio.clk)) {
- disp->audio.clk_from_ps = true;
- return;
- }
-
- dev_err(disp->dev, "audio disabled due to missing clock\n");
-}
-
-/* -----------------------------------------------------------------------------
- * ZynqMP Display external functions for zynqmp_dp
- */
-
-/**
- * zynqmp_disp_handle_vblank - Handle the vblank event
- * @disp: Display controller
- *
- * This function handles the vblank interrupt, and sends an event to
- * CRTC object. This will be called by the DP vblank interrupt handler.
- */
-void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp)
-{
- struct drm_crtc *crtc = &disp->crtc;
-
- drm_crtc_handle_vblank(crtc);
-}
-
-/**
- * zynqmp_disp_audio_enabled - If the audio is enabled
- * @disp: Display controller
- *
- * Return if the audio is enabled depending on the audio clock.
- *
- * Return: true if audio is enabled, or false.
- */
-bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp)
-{
- return !!disp->audio.clk;
-}
-
-/**
- * zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate
- * @disp: Display controller
- *
- * Return: the current audio clock rate.
- */
-unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp)
-{
- if (zynqmp_disp_audio_enabled(disp))
- return 0;
- return clk_get_rate(disp->audio.clk);
-}
-
-/**
- * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
- * @disp: Display controller
- *
- * Return: the crtc mask of the zyqnmp_disp CRTC.
- */
-uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp)
-{
- return drm_crtc_mask(&disp->crtc);
-}
-
/* -----------------------------------------------------------------------------
* ZynqMP Display Layer & DRM Plane
*/
@@ -1006,19 +873,46 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,
}
/**
+ * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer
+ * @layer: The layer
+ * @num_formats: Pointer to the returned number of formats
+ *
+ * Return: A newly allocated u32 array that stores all the DRM formats
+ * supported by the layer. The number of formats in the array is returned
+ * through the num_formats argument.
+ */
+u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
+ unsigned int *num_formats)
+{
+ unsigned int i;
+ u32 *formats;
+
+ formats = kcalloc(layer->info->num_formats, sizeof(*formats),
+ GFP_KERNEL);
+ if (!formats)
+ return NULL;
+
+ for (i = 0; i < layer->info->num_formats; ++i)
+ formats[i] = layer->info->formats[i].drm_fmt;
+
+ *num_formats = layer->info->num_formats;
+ return formats;
+}
+
+/**
* zynqmp_disp_layer_enable - Enable a layer
* @layer: The layer
+ * @mode: Operating mode of layer
*
* Enable the @layer in the audio/video buffer manager and the blender. DMA
* channels are started separately by zynqmp_disp_layer_update().
*/
-static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
+ enum zynqmp_dpsub_layer_mode mode)
{
- zynqmp_disp_avbuf_enable_video(layer->disp, layer,
- ZYNQMP_DISP_LAYER_NONLIVE);
+ layer->mode = mode;
+ zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
-
- layer->mode = ZYNQMP_DISP_LAYER_NONLIVE;
}
/**
@@ -1028,12 +922,14 @@ static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
* Disable the layer by stopping its DMA channels and disabling it in the
* audio/video buffer manager and the blender.
*/
-static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)
+void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)
{
unsigned int i;
- for (i = 0; i < layer->drm_fmt->num_planes; i++)
- dmaengine_terminate_sync(layer->dmas[i].chan);
+ if (layer->disp->dpsub->dma_enabled) {
+ for (i = 0; i < layer->drm_fmt->num_planes; i++)
+ dmaengine_terminate_sync(layer->dmas[i].chan);
+ }
zynqmp_disp_avbuf_disable_video(layer->disp, layer);
zynqmp_disp_blend_layer_disable(layer->disp, layer);
@@ -1042,15 +938,13 @@ static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)
/**
* zynqmp_disp_layer_set_format - Set the layer format
* @layer: The layer
- * @state: The plane state
+ * @info: The format info
*
- * Set the format for @layer based on @state->fb->format. The layer must be
- * disabled.
+ * Set the format for @layer to @info. The layer must be disabled.
*/
-static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
- struct drm_plane_state *state)
+void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
+ const struct drm_format_info *info)
{
- const struct drm_format_info *info = state->fb->format;
unsigned int i;
layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);
@@ -1058,6 +952,9 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
+ if (!layer->disp->dpsub->dma_enabled)
+ return;
+
/*
* Set pconfig for each DMA channel to indicate they're part of a
* video group.
@@ -1087,13 +984,16 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
*
* Return: 0 on success, or the DMA descriptor failure error otherwise
*/
-static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
- struct drm_plane_state *state)
+int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
+ struct drm_plane_state *state)
{
const struct drm_format_info *info = layer->drm_fmt;
unsigned int i;
- for (i = 0; i < layer->drm_fmt->num_planes; i++) {
+ if (!layer->disp->dpsub->dma_enabled)
+ return 0;
+
+ for (i = 0; i < info->num_planes; i++) {
unsigned int width = state->crtc_w / (i ? info->hsub : 1);
unsigned int height = state->crtc_h / (i ? info->vsub : 1);
struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
@@ -1128,143 +1028,6 @@ static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
return 0;
}
-static inline struct zynqmp_disp_layer *plane_to_layer(struct drm_plane *plane)
-{
- return container_of(plane, struct zynqmp_disp_layer, plane);
-}
-
-static int
-zynqmp_disp_plane_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
- plane);
- struct drm_crtc_state *crtc_state;
-
- if (!new_plane_state->crtc)
- return 0;
-
- crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
-
- return drm_atomic_helper_check_plane_state(new_plane_state,
- crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
-}
-
-static void
-zynqmp_disp_plane_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
- plane);
- struct zynqmp_disp_layer *layer = plane_to_layer(plane);
-
- if (!old_state->fb)
- return;
-
- zynqmp_disp_layer_disable(layer);
-
- if (zynqmp_disp_layer_is_gfx(layer))
- zynqmp_disp_blend_set_global_alpha(layer->disp, false,
- plane->state->alpha >> 8);
-}
-
-static void
-zynqmp_disp_plane_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
- struct zynqmp_disp_layer *layer = plane_to_layer(plane);
- bool format_changed = false;
-
- if (!old_state->fb ||
- old_state->fb->format->format != new_state->fb->format->format)
- format_changed = true;
-
- /*
- * If the format has changed (including going from a previously
- * disabled state to any format), reconfigure the format. Disable the
- * plane first if needed.
- */
- if (format_changed) {
- if (old_state->fb)
- zynqmp_disp_layer_disable(layer);
-
- zynqmp_disp_layer_set_format(layer, new_state);
- }
-
- zynqmp_disp_layer_update(layer, new_state);
-
- if (zynqmp_disp_layer_is_gfx(layer))
- zynqmp_disp_blend_set_global_alpha(layer->disp, true,
- plane->state->alpha >> 8);
-
- /* Enable or re-enable the plane is the format has changed. */
- if (format_changed)
- zynqmp_disp_layer_enable(layer);
-}
-
-static const struct drm_plane_helper_funcs zynqmp_disp_plane_helper_funcs = {
- .atomic_check = zynqmp_disp_plane_atomic_check,
- .atomic_update = zynqmp_disp_plane_atomic_update,
- .atomic_disable = zynqmp_disp_plane_atomic_disable,
-};
-
-static const struct drm_plane_funcs zynqmp_disp_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int zynqmp_disp_create_planes(struct zynqmp_disp *disp)
-{
- unsigned int i, j;
- int ret;
-
- for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) {
- struct zynqmp_disp_layer *layer = &disp->layers[i];
- enum drm_plane_type type;
- u32 *drm_formats;
-
- drm_formats = drmm_kcalloc(disp->drm, sizeof(*drm_formats),
- layer->info->num_formats,
- GFP_KERNEL);
- if (!drm_formats)
- return -ENOMEM;
-
- for (j = 0; j < layer->info->num_formats; ++j)
- drm_formats[j] = layer->info->formats[j].drm_fmt;
-
- /* Graphics layer is primary, and video layer is overlay. */
- type = zynqmp_disp_layer_is_video(layer)
- ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
- ret = drm_universal_plane_init(disp->drm, &layer->plane, 0,
- &zynqmp_disp_plane_funcs,
- drm_formats,
- layer->info->num_formats,
- NULL, type, NULL);
- if (ret)
- return ret;
-
- drm_plane_helper_add(&layer->plane,
- &zynqmp_disp_plane_helper_funcs);
-
- drm_plane_create_zpos_immutable_property(&layer->plane, i);
- if (zynqmp_disp_layer_is_gfx(layer))
- drm_plane_create_alpha_property(&layer->plane);
- }
-
- return 0;
-}
-
/**
* zynqmp_disp_layer_release_dma - Release DMA channels for a layer
* @disp: Display controller
@@ -1277,7 +1040,7 @@ static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp,
{
unsigned int i;
- if (!layer->info)
+ if (!layer->info || !disp->dpsub->dma_enabled)
return;
for (i = 0; i < layer->info->num_channels; i++) {
@@ -1300,7 +1063,7 @@ static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp)
{
unsigned int i;
- for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++)
+ for (i = 0; i < ARRAY_SIZE(disp->layers); i++)
zynqmp_disp_layer_release_dma(disp, &disp->layers[i]);
}
@@ -1320,6 +1083,9 @@ static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,
unsigned int i;
int ret;
+ if (!disp->dpsub->dma_enabled)
+ return 0;
+
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
char dma_channel_name[16];
@@ -1347,12 +1113,12 @@ static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,
static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
{
static const struct zynqmp_disp_layer_info layer_info[] = {
- [ZYNQMP_DISP_LAYER_VID] = {
+ [ZYNQMP_DPSUB_LAYER_VID] = {
.formats = avbuf_vid_fmts,
.num_formats = ARRAY_SIZE(avbuf_vid_fmts),
.num_channels = 3,
},
- [ZYNQMP_DISP_LAYER_GFX] = {
+ [ZYNQMP_DPSUB_LAYER_GFX] = {
.formats = avbuf_gfx_fmts,
.num_formats = ARRAY_SIZE(avbuf_gfx_fmts),
.num_channels = 1,
@@ -1362,7 +1128,7 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
unsigned int i;
int ret;
- for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) {
+ for (i = 0; i < ARRAY_SIZE(disp->layers); i++) {
struct zynqmp_disp_layer *layer = &disp->layers[i];
layer->id = i;
@@ -1372,6 +1138,8 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
ret = zynqmp_disp_layer_request_dma(disp, layer);
if (ret)
goto err;
+
+ disp->dpsub->layers[i] = layer;
}
return 0;
@@ -1382,19 +1150,23 @@ err:
}
/* -----------------------------------------------------------------------------
- * ZynqMP Display & DRM CRTC
+ * ZynqMP Display
*/
/**
* zynqmp_disp_enable - Enable the display controller
* @disp: Display controller
*/
-static void zynqmp_disp_enable(struct zynqmp_disp *disp)
+void zynqmp_disp_enable(struct zynqmp_disp *disp)
{
+ zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);
+ zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);
+
zynqmp_disp_avbuf_enable(disp);
/* Choose clock source based on the DT clock handle. */
- zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps,
- disp->audio.clk_from_ps, true);
+ zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,
+ disp->dpsub->aud_clk_from_ps,
+ true);
zynqmp_disp_avbuf_enable_channels(disp);
zynqmp_disp_avbuf_enable_audio(disp);
@@ -1405,7 +1177,7 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp)
* zynqmp_disp_disable - Disable the display controller
* @disp: Display controller
*/
-static void zynqmp_disp_disable(struct zynqmp_disp *disp)
+void zynqmp_disp_disable(struct zynqmp_disp *disp)
{
zynqmp_disp_audio_disable(disp);
@@ -1414,27 +1186,27 @@ static void zynqmp_disp_disable(struct zynqmp_disp *disp)
zynqmp_disp_avbuf_disable(disp);
}
-static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc)
-{
- return container_of(crtc, struct zynqmp_disp, crtc);
-}
-
-static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc,
- struct drm_display_mode *adjusted_mode)
+/**
+ * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate
+ * @disp: Display controller
+ * @mode_clock: The pixel clock rate, in Hz
+ *
+ * Return: 0 on success, or a negative error clock otherwise
+ */
+int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
+ unsigned long mode_clock)
{
- struct zynqmp_disp *disp = crtc_to_disp(crtc);
- unsigned long mode_clock = adjusted_mode->clock * 1000;
unsigned long rate;
long diff;
int ret;
- ret = clk_set_rate(disp->pclk, mode_clock);
+ ret = clk_set_rate(disp->dpsub->vid_clk, mode_clock);
if (ret) {
- dev_err(disp->dev, "failed to set a pixel clock\n");
+ dev_err(disp->dev, "failed to set the video clock\n");
return ret;
}
- rate = clk_get_rate(disp->pclk);
+ rate = clk_get_rate(disp->dpsub->vid_clk);
diff = rate - mode_clock;
if (abs(diff) > mode_clock / 20)
dev_info(disp->dev,
@@ -1448,245 +1220,63 @@ static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc,
return 0;
}
-static void
-zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- struct zynqmp_disp *disp = crtc_to_disp(crtc);
- struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
- int ret, vrefresh;
-
- pm_runtime_get_sync(disp->dev);
-
- zynqmp_disp_crtc_setup_clock(crtc, adjusted_mode);
-
- ret = clk_prepare_enable(disp->pclk);
- if (ret) {
- dev_err(disp->dev, "failed to enable a pixel clock\n");
- pm_runtime_put_sync(disp->dev);
- return;
- }
-
- zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);
- zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);
-
- zynqmp_disp_enable(disp);
-
- /* Delay of 3 vblank intervals for timing gen to be stable */
- vrefresh = (adjusted_mode->clock * 1000) /
- (adjusted_mode->vtotal * adjusted_mode->htotal);
- msleep(3 * 1000 / vrefresh);
-}
-
-static void
-zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- struct zynqmp_disp *disp = crtc_to_disp(crtc);
- struct drm_plane_state *old_plane_state;
-
- /*
- * Disable the plane if active. The old plane state can be NULL in the
- * .shutdown() path if the plane is already disabled, skip
- * zynqmp_disp_plane_atomic_disable() in that case.
- */
- old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
- if (old_plane_state)
- zynqmp_disp_plane_atomic_disable(crtc->primary, state);
-
- zynqmp_disp_disable(disp);
-
- drm_crtc_vblank_off(&disp->crtc);
-
- spin_lock_irq(&crtc->dev->event_lock);
- if (crtc->state->event) {
- drm_crtc_send_vblank_event(crtc, crtc->state->event);
- crtc->state->event = NULL;
- }
- spin_unlock_irq(&crtc->dev->event_lock);
-
- clk_disable_unprepare(disp->pclk);
- pm_runtime_put_sync(disp->dev);
-}
-
-static int zynqmp_disp_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- return drm_atomic_add_affected_planes(state, crtc);
-}
-
-static void
-zynqmp_disp_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- drm_crtc_vblank_on(crtc);
-}
-
-static void
-zynqmp_disp_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- if (crtc->state->event) {
- struct drm_pending_vblank_event *event;
-
- /* Consume the flip_done event from atomic helper. */
- event = crtc->state->event;
- crtc->state->event = NULL;
-
- event->pipe = drm_crtc_index(crtc);
-
- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-
- spin_lock_irq(&crtc->dev->event_lock);
- drm_crtc_arm_vblank_event(crtc, event);
- spin_unlock_irq(&crtc->dev->event_lock);
- }
-}
-
-static const struct drm_crtc_helper_funcs zynqmp_disp_crtc_helper_funcs = {
- .atomic_enable = zynqmp_disp_crtc_atomic_enable,
- .atomic_disable = zynqmp_disp_crtc_atomic_disable,
- .atomic_check = zynqmp_disp_crtc_atomic_check,
- .atomic_begin = zynqmp_disp_crtc_atomic_begin,
- .atomic_flush = zynqmp_disp_crtc_atomic_flush,
-};
-
-static int zynqmp_disp_crtc_enable_vblank(struct drm_crtc *crtc)
-{
- struct zynqmp_disp *disp = crtc_to_disp(crtc);
-
- zynqmp_dp_enable_vblank(disp->dpsub->dp);
-
- return 0;
-}
-
-static void zynqmp_disp_crtc_disable_vblank(struct drm_crtc *crtc)
-{
- struct zynqmp_disp *disp = crtc_to_disp(crtc);
-
- zynqmp_dp_disable_vblank(disp->dpsub->dp);
-}
-
-static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = {
- .destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .reset = drm_atomic_helper_crtc_reset,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
- .enable_vblank = zynqmp_disp_crtc_enable_vblank,
- .disable_vblank = zynqmp_disp_crtc_disable_vblank,
-};
-
-static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp)
-{
- struct drm_plane *plane = &disp->layers[ZYNQMP_DISP_LAYER_GFX].plane;
- int ret;
-
- ret = drm_crtc_init_with_planes(disp->drm, &disp->crtc, plane,
- NULL, &zynqmp_disp_crtc_funcs, NULL);
- if (ret < 0)
- return ret;
-
- drm_crtc_helper_add(&disp->crtc, &zynqmp_disp_crtc_helper_funcs);
-
- /* Start with vertical blanking interrupt reporting disabled. */
- drm_crtc_vblank_off(&disp->crtc);
-
- return 0;
-}
-
-static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp)
-{
- u32 possible_crtcs = drm_crtc_mask(&disp->crtc);
- unsigned int i;
-
- for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++)
- disp->layers[i].plane.possible_crtcs = possible_crtcs;
-}
-
/* -----------------------------------------------------------------------------
* Initialization & Cleanup
*/
-int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub)
-{
- struct zynqmp_disp *disp = dpsub->disp;
- int ret;
-
- ret = zynqmp_disp_create_planes(disp);
- if (ret)
- return ret;
-
- ret = zynqmp_disp_create_crtc(disp);
- if (ret < 0)
- return ret;
-
- zynqmp_disp_map_crtc_to_plane(disp);
-
- return 0;
-}
-
-int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
+int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub)
{
struct platform_device *pdev = to_platform_device(dpsub->dev);
struct zynqmp_disp *disp;
- struct zynqmp_disp_layer *layer;
struct resource *res;
int ret;
- disp = drmm_kzalloc(drm, sizeof(*disp), GFP_KERNEL);
+ disp = kzalloc(sizeof(*disp), GFP_KERNEL);
if (!disp)
return -ENOMEM;
disp->dev = &pdev->dev;
disp->dpsub = dpsub;
- disp->drm = drm;
-
- dpsub->disp = disp;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend");
disp->blend.base = devm_ioremap_resource(disp->dev, res);
- if (IS_ERR(disp->blend.base))
- return PTR_ERR(disp->blend.base);
+ if (IS_ERR(disp->blend.base)) {
+ ret = PTR_ERR(disp->blend.base);
+ goto error;
+ }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf");
disp->avbuf.base = devm_ioremap_resource(disp->dev, res);
- if (IS_ERR(disp->avbuf.base))
- return PTR_ERR(disp->avbuf.base);
+ if (IS_ERR(disp->avbuf.base)) {
+ ret = PTR_ERR(disp->avbuf.base);
+ goto error;
+ }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
disp->audio.base = devm_ioremap_resource(disp->dev, res);
- if (IS_ERR(disp->audio.base))
- return PTR_ERR(disp->audio.base);
-
- /* Try the live PL video clock */
- disp->pclk = devm_clk_get(disp->dev, "dp_live_video_in_clk");
- if (!IS_ERR(disp->pclk))
- disp->pclk_from_ps = false;
- else if (PTR_ERR(disp->pclk) == -EPROBE_DEFER)
- return PTR_ERR(disp->pclk);
-
- /* If the live PL video clock is not valid, fall back to PS clock */
- if (IS_ERR_OR_NULL(disp->pclk)) {
- disp->pclk = devm_clk_get(disp->dev, "dp_vtc_pixel_clk_in");
- if (IS_ERR(disp->pclk)) {
- dev_err(disp->dev, "failed to init any video clock\n");
- return PTR_ERR(disp->pclk);
- }
- disp->pclk_from_ps = true;
+ if (IS_ERR(disp->audio.base)) {
+ ret = PTR_ERR(disp->audio.base);
+ goto error;
}
- zynqmp_disp_audio_init(disp);
-
ret = zynqmp_disp_create_layers(disp);
if (ret)
- return ret;
+ goto error;
+
+ if (disp->dpsub->dma_enabled) {
+ struct zynqmp_disp_layer *layer;
- layer = &disp->layers[ZYNQMP_DISP_LAYER_VID];
- dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
+ layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];
+ dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
+ }
+
+ dpsub->disp = disp;
return 0;
+
+error:
+ kfree(disp);
+ return ret;
}
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index f402901afb23..123cffac08be 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -25,18 +25,52 @@
#define ZYNQMP_DISP_MAX_DMA_BIT 44
struct device;
-struct drm_device;
+struct drm_format_info;
+struct drm_plane_state;
struct platform_device;
struct zynqmp_disp;
+struct zynqmp_disp_layer;
struct zynqmp_dpsub;
-void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp);
-bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp);
-unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp);
-uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp);
+/**
+ * enum zynqmp_dpsub_layer_id - Layer identifier
+ * @ZYNQMP_DPSUB_LAYER_VID: Video layer
+ * @ZYNQMP_DPSUB_LAYER_GFX: Graphics layer
+ */
+enum zynqmp_dpsub_layer_id {
+ ZYNQMP_DPSUB_LAYER_VID,
+ ZYNQMP_DPSUB_LAYER_GFX,
+};
+
+/**
+ * enum zynqmp_dpsub_layer_mode - Layer mode
+ * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
+ * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
+ */
+enum zynqmp_dpsub_layer_mode {
+ ZYNQMP_DPSUB_LAYER_NONLIVE,
+ ZYNQMP_DPSUB_LAYER_LIVE,
+};
+
+void zynqmp_disp_enable(struct zynqmp_disp *disp);
+void zynqmp_disp_disable(struct zynqmp_disp *disp);
+int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
+ unsigned long mode_clock);
+
+void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,
+ bool enable, u32 alpha);
+
+u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
+ unsigned int *num_formats);
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
+ enum zynqmp_dpsub_layer_mode mode);
+void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
+void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
+ const struct drm_format_info *info);
+int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
+ struct drm_plane_state *state);
-int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub);
-int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
+int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub);
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DISP_H_ */
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index d14612b34796..0a7b466446fb 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -11,16 +11,12 @@
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
-#include <drm/drm_encoder.h>
-#include <drm/drm_managed.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -31,10 +27,12 @@
#include <linux/pm_runtime.h>
#include <linux/phy/phy.h>
#include <linux/reset.h>
+#include <linux/slab.h>
#include "zynqmp_disp.h"
#include "zynqmp_dp.h"
#include "zynqmp_dpsub.h"
+#include "zynqmp_kms.h"
static uint zynqmp_dp_aux_timeout_ms = 50;
module_param_named(aux_timeout_ms, zynqmp_dp_aux_timeout_ms, uint, 0444);
@@ -277,14 +275,13 @@ struct zynqmp_dp_config {
/**
* struct zynqmp_dp - Xilinx DisplayPort core
- * @encoder: the drm encoder structure
- * @connector: the drm connector structure
* @dev: device structure
* @dpsub: Display subsystem
- * @drm: DRM core
* @iomem: device I/O memory for register access
* @reset: reset controller
* @irq: irq
+ * @bridge: DRM bridge for the DP encoder
+ * @next_bridge: The downstream bridge
* @config: IP core configuration from DTS
* @aux: aux channel
* @phy: PHY handles for DP lanes
@@ -298,15 +295,15 @@ struct zynqmp_dp_config {
* @train_set: set of training data
*/
struct zynqmp_dp {
- struct drm_encoder encoder;
- struct drm_connector connector;
struct device *dev;
struct zynqmp_dpsub *dpsub;
- struct drm_device *drm;
void __iomem *iomem;
struct reset_control *reset;
int irq;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+
struct zynqmp_dp_config config;
struct drm_dp_aux aux;
struct phy *phy[ZYNQMP_DP_MAX_LANES];
@@ -321,14 +318,9 @@ struct zynqmp_dp {
u8 train_set[ZYNQMP_DP_MAX_LANES];
};
-static inline struct zynqmp_dp *encoder_to_dp(struct drm_encoder *encoder)
-{
- return container_of(encoder, struct zynqmp_dp, encoder);
-}
-
-static inline struct zynqmp_dp *connector_to_dp(struct drm_connector *connector)
+static inline struct zynqmp_dp *bridge_to_dp(struct drm_bridge *bridge)
{
- return container_of(connector, struct zynqmp_dp, connector);
+ return container_of(bridge, struct zynqmp_dp, bridge);
}
static void zynqmp_dp_write(struct zynqmp_dp *dp, int offset, u32 val)
@@ -1064,7 +1056,7 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp)
dp->aux.name = "ZynqMP DP AUX";
dp->aux.dev = dp->dev;
- dp->aux.drm_dev = dp->drm;
+ dp->aux.drm_dev = dp->bridge.dev;
dp->aux.transfer = zynqmp_dp_aux_transfer;
return drm_dp_aux_register(&dp->aux);
@@ -1101,6 +1093,7 @@ static void zynqmp_dp_update_misc(struct zynqmp_dp *dp)
/**
* zynqmp_dp_set_format - Set the input format
* @dp: DisplayPort IP core structure
+ * @info: Display info
* @format: input format
* @bpc: bits per component
*
@@ -1109,10 +1102,10 @@ static void zynqmp_dp_update_misc(struct zynqmp_dp *dp)
* Return: 0 on success, or -EINVAL.
*/
static int zynqmp_dp_set_format(struct zynqmp_dp *dp,
+ const struct drm_display_info *info,
enum zynqmp_dpsub_format format,
unsigned int bpc)
{
- static const struct drm_display_info *display;
struct zynqmp_dp_config *config = &dp->config;
unsigned int num_colors;
@@ -1145,12 +1138,11 @@ static int zynqmp_dp_set_format(struct zynqmp_dp *dp,
return -EINVAL;
}
- display = &dp->connector.display_info;
- if (display->bpc && bpc > display->bpc) {
+ if (info && info->bpc && bpc > info->bpc) {
dev_warn(dp->dev,
"downgrading requested %ubpc to display limit %ubpc\n",
- bpc, display->bpc);
- bpc = display->bpc;
+ bpc, info->bpc);
+ bpc = info->bpc;
}
config->misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_BPC_MASK;
@@ -1195,7 +1187,7 @@ static int zynqmp_dp_set_format(struct zynqmp_dp *dp,
*/
static void
zynqmp_dp_encoder_mode_set_transfer_unit(struct zynqmp_dp *dp,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
u32 tu = ZYNQMP_DP_MSA_TRANSFER_UNIT_SIZE_TU_SIZE_DEF;
u32 bw, vid_kbytes, avg_bytes_per_tu, init_wait;
@@ -1255,12 +1247,12 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_VSTART,
mode->vtotal - mode->vsync_start);
- /* In synchronous mode, set the diviers */
+ /* In synchronous mode, set the dividers */
if (dp->config.misc0 & ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK) {
reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_N_VID, reg);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock);
- rate = zynqmp_disp_get_audio_clk_rate(dp->dpsub->disp);
+ rate = zynqmp_dpsub_get_audio_clk_rate(dp->dpsub);
if (rate) {
dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, reg);
@@ -1269,7 +1261,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
}
/* Only 2 channel audio is supported now */
- if (zynqmp_disp_audio_enabled(dp->dpsub->disp))
+ if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1);
zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1);
@@ -1281,97 +1273,115 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
}
/* -----------------------------------------------------------------------------
- * DRM Connector
+ * DISP Configuration
*/
-static enum drm_connector_status
-zynqmp_dp_connector_detect(struct drm_connector *connector, bool force)
+static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
+ struct drm_bridge_state *old_bridge_state)
{
- struct zynqmp_dp *dp = connector_to_dp(connector);
- struct zynqmp_dp_link_config *link_config = &dp->link_config;
- u32 state, i;
- int ret;
+ enum zynqmp_dpsub_layer_id layer_id;
+ struct zynqmp_disp_layer *layer;
+ const struct drm_format_info *info;
+
+ if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
+ layer_id = ZYNQMP_DPSUB_LAYER_VID;
+ else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
+ layer_id = ZYNQMP_DPSUB_LAYER_GFX;
+ else
+ return;
- /*
- * This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to
- * get the HPD signal with some monitors.
- */
- for (i = 0; i < 10; i++) {
- state = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE);
- if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD)
- break;
- msleep(100);
- }
+ layer = dp->dpsub->layers[layer_id];
- if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD) {
- ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd,
- sizeof(dp->dpcd));
- if (ret < 0) {
- dev_dbg(dp->dev, "DPCD read failed");
- goto disconnected;
- }
+ /* TODO: Make the format configurable. */
+ info = drm_format_info(DRM_FORMAT_YUV422);
+ zynqmp_disp_layer_set_format(layer, info);
+ zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE);
- link_config->max_rate = min_t(int,
- drm_dp_max_link_rate(dp->dpcd),
- DP_HIGH_BIT_RATE2);
- link_config->max_lanes = min_t(u8,
- drm_dp_max_lane_count(dp->dpcd),
- dp->num_lanes);
+ if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
+ zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
+ else
+ zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, false, 0);
- dp->status = connector_status_connected;
- return connector_status_connected;
- }
+ zynqmp_disp_enable(dp->dpsub->disp);
+}
-disconnected:
- dp->status = connector_status_disconnected;
- return connector_status_disconnected;
+static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct zynqmp_disp_layer *layer;
+
+ if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
+ layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID];
+ else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
+ layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX];
+ else
+ return;
+
+ zynqmp_disp_disable(dp->dpsub->disp);
+ zynqmp_disp_layer_disable(layer);
}
-static int zynqmp_dp_connector_get_modes(struct drm_connector *connector)
+/* -----------------------------------------------------------------------------
+ * DRM Bridge
+ */
+
+static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
- struct zynqmp_dp *dp = connector_to_dp(connector);
- struct edid *edid;
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
int ret;
- edid = drm_get_edid(connector, &dp->aux.ddc);
- if (!edid)
- return 0;
+ /* Initialize and register the AUX adapter. */
+ ret = zynqmp_dp_aux_init(dp);
+ if (ret) {
+ dev_err(dp->dev, "failed to initialize DP aux\n");
+ return ret;
+ }
- drm_connector_update_edid_property(connector, edid);
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
+ if (dp->next_bridge) {
+ ret = drm_bridge_attach(bridge->encoder, dp->next_bridge,
+ bridge, flags);
+ if (ret < 0)
+ goto error;
+ }
+ /* Now that initialisation is complete, enable interrupts. */
+ zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_ALL);
+
+ return 0;
+
+error:
+ zynqmp_dp_aux_cleanup(dp);
return ret;
}
-static struct drm_encoder *
-zynqmp_dp_connector_best_encoder(struct drm_connector *connector)
+static void zynqmp_dp_bridge_detach(struct drm_bridge *bridge)
{
- struct zynqmp_dp *dp = connector_to_dp(connector);
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
- return &dp->encoder;
+ zynqmp_dp_aux_cleanup(dp);
}
-static int zynqmp_dp_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
+static enum drm_mode_status
+zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
{
- struct zynqmp_dp *dp = connector_to_dp(connector);
- u8 max_lanes = dp->link_config.max_lanes;
- u8 bpp = dp->config.bpp;
- int max_rate = dp->link_config.max_rate;
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
int rate;
if (mode->clock > ZYNQMP_MAX_FREQ) {
- dev_dbg(dp->dev, "filtered the mode, %s,for high pixel rate\n",
+ dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n",
mode->name);
drm_mode_debug_printmodeline(mode);
return MODE_CLOCK_HIGH;
}
/* Check with link rate and lane count */
- rate = zynqmp_dp_max_rate(max_rate, max_lanes, bpp);
+ rate = zynqmp_dp_max_rate(dp->link_config.max_rate,
+ dp->link_config.max_lanes, dp->config.bpp);
if (mode->clock > rate) {
- dev_dbg(dp->dev, "filtered the mode, %s,for high pixel rate\n",
+ dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n",
mode->name);
drm_mode_debug_printmodeline(mode);
return MODE_CLOCK_HIGH;
@@ -1380,36 +1390,62 @@ static int zynqmp_dp_connector_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-static const struct drm_connector_funcs zynqmp_dp_connector_funcs = {
- .detect = zynqmp_dp_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- .reset = drm_atomic_helper_connector_reset,
-};
-
-static const struct drm_connector_helper_funcs
-zynqmp_dp_connector_helper_funcs = {
- .get_modes = zynqmp_dp_connector_get_modes,
- .best_encoder = zynqmp_dp_connector_best_encoder,
- .mode_valid = zynqmp_dp_connector_mode_valid,
-};
-
-/* -----------------------------------------------------------------------------
- * DRM Encoder
- */
-
-static void zynqmp_dp_encoder_enable(struct drm_encoder *encoder)
+static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct zynqmp_dp *dp = encoder_to_dp(encoder);
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
+ struct drm_atomic_state *state = old_bridge_state->base.state;
+ const struct drm_crtc_state *crtc_state;
+ const struct drm_display_mode *adjusted_mode;
+ const struct drm_display_mode *mode;
+ struct drm_connector *connector;
+ struct drm_crtc *crtc;
unsigned int i;
- int ret = 0;
+ int rate;
+ int ret;
pm_runtime_get_sync(dp->dev);
+
+ zynqmp_dp_disp_enable(dp, old_bridge_state);
+
+ /*
+ * Retrieve the CRTC mode and adjusted mode. This requires a little
+ * dance to go from the bridge to the encoder, to the connector and to
+ * the CRTC.
+ */
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ adjusted_mode = &crtc_state->adjusted_mode;
+ mode = &crtc_state->mode;
+
+ zynqmp_dp_set_format(dp, &connector->display_info,
+ ZYNQMP_DPSUB_FORMAT_RGB, 8);
+
+ /* Check again as bpp or format might have been changed */
+ rate = zynqmp_dp_max_rate(dp->link_config.max_rate,
+ dp->link_config.max_lanes, dp->config.bpp);
+ if (mode->clock > rate) {
+ dev_err(dp->dev, "mode %s has too high pixel rate\n",
+ mode->name);
+ drm_mode_debug_printmodeline(mode);
+ }
+
+ /* Configure the mode */
+ ret = zynqmp_dp_mode_configure(dp, adjusted_mode->clock, 0);
+ if (ret < 0) {
+ pm_runtime_put_sync(dp->dev);
+ return;
+ }
+
+ zynqmp_dp_encoder_mode_set_transfer_unit(dp, adjusted_mode);
+ zynqmp_dp_encoder_mode_set_stream(dp, adjusted_mode);
+
+ /* Enable the encoder */
dp->enabled = true;
zynqmp_dp_update_misc(dp);
- if (zynqmp_disp_audio_enabled(dp->dpsub->disp))
+ if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0);
if (dp->status == connector_status_connected) {
@@ -1432,9 +1468,10 @@ static void zynqmp_dp_encoder_enable(struct drm_encoder *encoder)
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1);
}
-static void zynqmp_dp_encoder_disable(struct drm_encoder *encoder)
+static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct zynqmp_dp *dp = encoder_to_dp(encoder);
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
dp->enabled = false;
cancel_delayed_work(&dp->hpd_work);
@@ -1442,49 +1479,22 @@ static void zynqmp_dp_encoder_disable(struct drm_encoder *encoder)
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
- if (zynqmp_disp_audio_enabled(dp->dpsub->disp))
+ if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
- pm_runtime_put_sync(dp->dev);
-}
-
-static void
-zynqmp_dp_encoder_atomic_mode_set(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *connector_state)
-{
- struct zynqmp_dp *dp = encoder_to_dp(encoder);
- struct drm_display_mode *mode = &crtc_state->mode;
- struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
- u8 max_lanes = dp->link_config.max_lanes;
- u8 bpp = dp->config.bpp;
- int rate, max_rate = dp->link_config.max_rate;
- int ret;
- zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8);
+ zynqmp_dp_disp_disable(dp, old_bridge_state);
- /* Check again as bpp or format might have been chagned */
- rate = zynqmp_dp_max_rate(max_rate, max_lanes, bpp);
- if (mode->clock > rate) {
- dev_err(dp->dev, "the mode, %s,has too high pixel rate\n",
- mode->name);
- drm_mode_debug_printmodeline(mode);
- }
-
- ret = zynqmp_dp_mode_configure(dp, adjusted_mode->clock, 0);
- if (ret < 0)
- return;
-
- zynqmp_dp_encoder_mode_set_transfer_unit(dp, adjusted_mode);
- zynqmp_dp_encoder_mode_set_stream(dp, adjusted_mode);
+ pm_runtime_put_sync(dp->dev);
}
#define ZYNQMP_DP_MIN_H_BACKPORCH 20
-static int
-zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
+static int zynqmp_dp_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
struct drm_display_mode *mode = &crtc_state->mode;
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
int diff = mode->htotal - mode->hsync_end;
@@ -1497,7 +1507,7 @@ zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder,
int vrefresh = (adjusted_mode->clock * 1000) /
(adjusted_mode->vtotal * adjusted_mode->htotal);
- dev_dbg(encoder->dev->dev, "hbackporch adjusted: %d to %d",
+ dev_dbg(dp->dev, "hbackporch adjusted: %d to %d",
diff, ZYNQMP_DP_MIN_H_BACKPORCH - diff);
diff = ZYNQMP_DP_MIN_H_BACKPORCH - diff;
adjusted_mode->htotal += diff;
@@ -1508,11 +1518,68 @@ zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder,
return 0;
}
-static const struct drm_encoder_helper_funcs zynqmp_dp_encoder_helper_funcs = {
- .enable = zynqmp_dp_encoder_enable,
- .disable = zynqmp_dp_encoder_disable,
- .atomic_mode_set = zynqmp_dp_encoder_atomic_mode_set,
- .atomic_check = zynqmp_dp_encoder_atomic_check,
+static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge)
+{
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
+ struct zynqmp_dp_link_config *link_config = &dp->link_config;
+ u32 state, i;
+ int ret;
+
+ /*
+ * This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to
+ * get the HPD signal with some monitors.
+ */
+ for (i = 0; i < 10; i++) {
+ state = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE);
+ if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD)
+ break;
+ msleep(100);
+ }
+
+ if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD) {
+ ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd,
+ sizeof(dp->dpcd));
+ if (ret < 0) {
+ dev_dbg(dp->dev, "DPCD read failed");
+ goto disconnected;
+ }
+
+ link_config->max_rate = min_t(int,
+ drm_dp_max_link_rate(dp->dpcd),
+ DP_HIGH_BIT_RATE2);
+ link_config->max_lanes = min_t(u8,
+ drm_dp_max_lane_count(dp->dpcd),
+ dp->num_lanes);
+
+ dp->status = connector_status_connected;
+ return connector_status_connected;
+ }
+
+disconnected:
+ dp->status = connector_status_disconnected;
+ return connector_status_disconnected;
+}
+
+static struct edid *zynqmp_dp_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct zynqmp_dp *dp = bridge_to_dp(bridge);
+
+ return drm_get_edid(connector, &dp->aux.ddc);
+}
+
+static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = {
+ .attach = zynqmp_dp_bridge_attach,
+ .detach = zynqmp_dp_bridge_detach,
+ .mode_valid = zynqmp_dp_bridge_mode_valid,
+ .atomic_enable = zynqmp_dp_bridge_atomic_enable,
+ .atomic_disable = zynqmp_dp_bridge_atomic_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_check = zynqmp_dp_bridge_atomic_check,
+ .detect = zynqmp_dp_bridge_detect,
+ .get_edid = zynqmp_dp_bridge_get_edid,
};
/* -----------------------------------------------------------------------------
@@ -1543,12 +1610,12 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp)
static void zynqmp_dp_hpd_work_func(struct work_struct *work)
{
- struct zynqmp_dp *dp;
-
- dp = container_of(work, struct zynqmp_dp, hpd_work.work);
+ struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp,
+ hpd_work.work);
+ enum drm_connector_status status;
- if (dp->drm)
- drm_helper_hpd_irq_event(dp->drm);
+ status = zynqmp_dp_bridge_detect(&dp->bridge);
+ drm_bridge_hpd_notify(&dp->bridge, status);
}
static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
@@ -1570,7 +1637,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
if (status & ZYNQMP_DP_INT_VBLANK_START)
- zynqmp_disp_handle_vblank(dp->dpsub->disp);
+ zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
if (status & ZYNQMP_DP_INT_HPD_EVENT)
schedule_delayed_work(&dp->hpd_work, 0);
@@ -1599,94 +1666,76 @@ handled:
* Initialization & Cleanup
*/
-int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub)
-{
- struct zynqmp_dp *dp = dpsub->dp;
- struct drm_encoder *encoder = &dp->encoder;
- struct drm_connector *connector = &dp->connector;
- int ret;
-
- dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK;
- zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8);
-
- /* Create the DRM encoder and connector. */
- encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp);
- drm_simple_encoder_init(dp->drm, encoder, DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(encoder, &zynqmp_dp_encoder_helper_funcs);
-
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(encoder->dev, connector,
- &zynqmp_dp_connector_funcs,
- DRM_MODE_CONNECTOR_DisplayPort);
- if (ret) {
- dev_err(dp->dev, "failed to create the DRM connector\n");
- return ret;
- }
-
- drm_connector_helper_add(connector, &zynqmp_dp_connector_helper_funcs);
- drm_connector_register(connector);
- drm_connector_attach_encoder(connector, encoder);
-
- /* Initialize and register the AUX adapter. */
- ret = zynqmp_dp_aux_init(dp);
- if (ret) {
- dev_err(dp->dev, "failed to initialize DP aux\n");
- return ret;
- }
-
- /* Now that initialisation is complete, enable interrupts. */
- zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_ALL);
-
- return 0;
-}
-
-int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
+int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
{
struct platform_device *pdev = to_platform_device(dpsub->dev);
+ struct drm_bridge *bridge;
struct zynqmp_dp *dp;
struct resource *res;
int ret;
- dp = drmm_kzalloc(drm, sizeof(*dp), GFP_KERNEL);
+ dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (!dp)
return -ENOMEM;
dp->dev = &pdev->dev;
dp->dpsub = dpsub;
dp->status = connector_status_disconnected;
- dp->drm = drm;
INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
- dpsub->dp = dp;
-
/* Acquire all resources (IOMEM, IRQ and PHYs). */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp");
dp->iomem = devm_ioremap_resource(dp->dev, res);
- if (IS_ERR(dp->iomem))
- return PTR_ERR(dp->iomem);
+ if (IS_ERR(dp->iomem)) {
+ ret = PTR_ERR(dp->iomem);
+ goto err_free;
+ }
dp->irq = platform_get_irq(pdev, 0);
- if (dp->irq < 0)
- return dp->irq;
+ if (dp->irq < 0) {
+ ret = dp->irq;
+ goto err_free;
+ }
dp->reset = devm_reset_control_get(dp->dev, NULL);
if (IS_ERR(dp->reset)) {
if (PTR_ERR(dp->reset) != -EPROBE_DEFER)
dev_err(dp->dev, "failed to get reset: %ld\n",
PTR_ERR(dp->reset));
- return PTR_ERR(dp->reset);
+ ret = PTR_ERR(dp->reset);
+ goto err_free;
}
ret = zynqmp_dp_reset(dp, false);
if (ret < 0)
- return ret;
+ goto err_free;
ret = zynqmp_dp_phy_probe(dp);
if (ret)
goto err_reset;
+ /* Initialize the bridge. */
+ bridge = &dp->bridge;
+ bridge->funcs = &zynqmp_dp_bridge_funcs;
+ bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
+ | DRM_BRIDGE_OP_HPD;
+ bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+ dpsub->bridge = bridge;
+
+ /*
+ * Acquire the next bridge in the chain. Ignore errors caused by port@5
+ * not being connected for backward-compatibility with older DTs.
+ */
+ ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 5, 0, NULL,
+ &dp->next_bridge);
+ if (ret < 0 && ret != -ENODEV)
+ goto err_reset;
+
/* Initialize the hardware. */
+ dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK;
+ zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8);
+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
zynqmp_dp_set(dp, ZYNQMP_DP_PHY_RESET, ZYNQMP_DP_PHY_RESET_ALL_RESET);
@@ -1710,6 +1759,8 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
if (ret < 0)
goto err_phy_exit;
+ dpsub->dp = dp;
+
dev_dbg(dp->dev, "ZynqMP DisplayPort Tx probed with %u lanes\n",
dp->num_lanes);
@@ -1719,7 +1770,8 @@ err_phy_exit:
zynqmp_dp_phy_exit(dp);
err_reset:
zynqmp_dp_reset(dp, true);
-
+err_free:
+ kfree(dp);
return ret;
}
@@ -1731,7 +1783,6 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub)
disable_irq(dp->irq);
cancel_delayed_work_sync(&dp->hpd_work);
- zynqmp_dp_aux_cleanup(dp);
zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0);
zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.h b/drivers/gpu/drm/xlnx/zynqmp_dp.h
index 4507740093f6..f077d7fbd0ad 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.h
@@ -12,7 +12,6 @@
#ifndef _ZYNQMP_DP_H_
#define _ZYNQMP_DP_H_
-struct drm_device;
struct platform_device;
struct zynqmp_dp;
struct zynqmp_dpsub;
@@ -20,8 +19,7 @@ struct zynqmp_dpsub;
void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp);
void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp);
-int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub);
-int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
+int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub);
void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DP_H_ */
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
index 1de2d927c32b..bab862484d42 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
@@ -12,191 +12,217 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/of_graph.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_device.h>
-#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fourcc.h>
-#include <drm/drm_gem_dma_helper.h>
-#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_managed.h>
-#include <drm/drm_mode_config.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_vblank.h>
#include "zynqmp_disp.h"
#include "zynqmp_dp.h"
#include "zynqmp_dpsub.h"
+#include "zynqmp_kms.h"
/* -----------------------------------------------------------------------------
- * Dumb Buffer & Framebuffer Allocation
+ * Power Management
*/
-static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
- struct drm_device *drm,
- struct drm_mode_create_dumb *args)
+static int __maybe_unused zynqmp_dpsub_suspend(struct device *dev)
{
- struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
- unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+ struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
- /* Enforce the alignment constraints of the DMA engine. */
- args->pitch = ALIGN(pitch, dpsub->dma_align);
+ if (!dpsub->drm)
+ return 0;
- return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
+ return drm_mode_config_helper_suspend(&dpsub->drm->dev);
}
-static struct drm_framebuffer *
-zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv,
- const struct drm_mode_fb_cmd2 *mode_cmd)
+static int __maybe_unused zynqmp_dpsub_resume(struct device *dev)
{
- struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
- struct drm_mode_fb_cmd2 cmd = *mode_cmd;
- unsigned int i;
+ struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
- /* Enforce the alignment constraints of the DMA engine. */
- for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
- cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
+ if (!dpsub->drm)
+ return 0;
- return drm_gem_fb_create(drm, file_priv, &cmd);
+ return drm_mode_config_helper_resume(&dpsub->drm->dev);
}
-static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = {
- .fb_create = zynqmp_dpsub_fb_create,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
+static const struct dev_pm_ops zynqmp_dpsub_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume)
};
/* -----------------------------------------------------------------------------
- * DRM/KMS Driver
+ * DPSUB Configuration
*/
-DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops);
-
-static const struct drm_driver zynqmp_dpsub_drm_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM |
- DRIVER_ATOMIC,
-
- DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create),
+/**
+ * zynqmp_dpsub_audio_enabled - If the audio is enabled
+ * @dpsub: DisplayPort subsystem
+ *
+ * Return if the audio is enabled depending on the audio clock.
+ *
+ * Return: true if audio is enabled, or false.
+ */
+bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub)
+{
+ return !!dpsub->aud_clk;
+}
- .fops = &zynqmp_dpsub_drm_fops,
+/**
+ * zynqmp_dpsub_get_audio_clk_rate - Get the current audio clock rate
+ * @dpsub: DisplayPort subsystem
+ *
+ * Return: the current audio clock rate.
+ */
+unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub)
+{
+ if (zynqmp_dpsub_audio_enabled(dpsub))
+ return 0;
+ return clk_get_rate(dpsub->aud_clk);
+}
- .name = "zynqmp-dpsub",
- .desc = "Xilinx DisplayPort Subsystem Driver",
- .date = "20130509",
- .major = 1,
- .minor = 0,
-};
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
-static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
+static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
{
- struct drm_device *drm = &dpsub->drm;
int ret;
- /* Initialize mode config, vblank and the KMS poll helper. */
- ret = drmm_mode_config_init(drm);
- if (ret < 0)
- return ret;
-
- drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
- drm->mode_config.min_width = 0;
- drm->mode_config.min_height = 0;
- drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
- drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
+ dpsub->apb_clk = devm_clk_get(dpsub->dev, "dp_apb_clk");
+ if (IS_ERR(dpsub->apb_clk))
+ return PTR_ERR(dpsub->apb_clk);
- ret = drm_vblank_init(drm, 1);
- if (ret)
+ ret = clk_prepare_enable(dpsub->apb_clk);
+ if (ret) {
+ dev_err(dpsub->dev, "failed to enable the APB clock\n");
return ret;
-
- drm_kms_helper_poll_init(drm);
+ }
/*
- * Initialize the DISP and DP components. This will creates planes,
- * CRTC, encoder and connector. The DISP should be initialized first as
- * the DP encoder needs the CRTC.
+ * Try the live PL video clock, and fall back to the PS clock if the
+ * live PL video clock isn't valid.
*/
- ret = zynqmp_disp_drm_init(dpsub);
- if (ret)
- goto err_poll_fini;
-
- ret = zynqmp_dp_drm_init(dpsub);
- if (ret)
- goto err_poll_fini;
-
- /* Reset all components and register the DRM device. */
- drm_mode_config_reset(drm);
+ dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_live_video_in_clk");
+ if (!IS_ERR(dpsub->vid_clk))
+ dpsub->vid_clk_from_ps = false;
+ else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER)
+ return PTR_ERR(dpsub->vid_clk);
+
+ if (IS_ERR_OR_NULL(dpsub->vid_clk)) {
+ dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in");
+ if (IS_ERR(dpsub->vid_clk)) {
+ dev_err(dpsub->dev, "failed to init any video clock\n");
+ return PTR_ERR(dpsub->vid_clk);
+ }
+ dpsub->vid_clk_from_ps = true;
+ }
- ret = drm_dev_register(drm, 0);
- if (ret < 0)
- goto err_poll_fini;
+ /*
+ * Try the live PL audio clock, and fall back to the PS clock if the
+ * live PL audio clock isn't valid. Missing audio clock disables audio
+ * but isn't an error.
+ */
+ dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_live_audio_aclk");
+ if (!IS_ERR(dpsub->aud_clk)) {
+ dpsub->aud_clk_from_ps = false;
+ return 0;
+ }
- /* Initialize fbdev generic emulation. */
- drm_fbdev_generic_setup(drm, 24);
+ dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_aud_clk");
+ if (!IS_ERR(dpsub->aud_clk)) {
+ dpsub->aud_clk_from_ps = true;
+ return 0;
+ }
+ dev_info(dpsub->dev, "audio disabled due to missing clock\n");
return 0;
-
-err_poll_fini:
- drm_kms_helper_poll_fini(drm);
- return ret;
}
-/* -----------------------------------------------------------------------------
- * Power Management
- */
-
-static int __maybe_unused zynqmp_dpsub_suspend(struct device *dev)
+static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub)
{
- struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
+ struct device_node *np;
+ unsigned int i;
- return drm_mode_config_helper_suspend(&dpsub->drm);
-}
+ /*
+ * For backward compatibility with old device trees that don't contain
+ * ports, consider that only the DP output port is connected if no
+ * ports child no exists.
+ */
+ np = of_get_child_by_name(dpsub->dev->of_node, "ports");
+ of_node_put(np);
+ if (!np) {
+ dev_warn(dpsub->dev, "missing ports, update DT bindings\n");
+ dpsub->connected_ports = BIT(ZYNQMP_DPSUB_PORT_OUT_DP);
+ dpsub->dma_enabled = true;
+ return 0;
+ }
-static int __maybe_unused zynqmp_dpsub_resume(struct device *dev)
-{
- struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
+ /* Check which ports are connected. */
+ for (i = 0; i < ZYNQMP_DPSUB_NUM_PORTS; ++i) {
+ struct device_node *np;
- return drm_mode_config_helper_resume(&dpsub->drm);
-}
+ np = of_graph_get_remote_node(dpsub->dev->of_node, i, -1);
+ if (np) {
+ dpsub->connected_ports |= BIT(i);
+ of_node_put(np);
+ }
+ }
-static const struct dev_pm_ops zynqmp_dpsub_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume)
-};
+ /* Sanity checks. */
+ if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) &&
+ (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) {
+ dev_err(dpsub->dev, "only one live video input is supported\n");
+ return -EINVAL;
+ }
-/* -----------------------------------------------------------------------------
- * Probe & Remove
- */
+ if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) ||
+ (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) {
+ if (dpsub->vid_clk_from_ps) {
+ dev_err(dpsub->dev,
+ "live video input requires PL clock\n");
+ return -EINVAL;
+ }
+ } else {
+ dpsub->dma_enabled = true;
+ }
-static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
-{
- int ret;
+ if (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_AUDIO))
+ dev_warn(dpsub->dev, "live audio unsupported, ignoring\n");
- dpsub->apb_clk = devm_clk_get(dpsub->dev, "dp_apb_clk");
- if (IS_ERR(dpsub->apb_clk))
- return PTR_ERR(dpsub->apb_clk);
+ if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_VIDEO)) ||
+ (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_AUDIO)))
+ dev_warn(dpsub->dev, "output to PL unsupported, ignoring\n");
- ret = clk_prepare_enable(dpsub->apb_clk);
- if (ret) {
- dev_err(dpsub->dev, "failed to enable the APB clock\n");
- return ret;
+ if (!(dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_DP))) {
+ dev_err(dpsub->dev, "DP output port not connected\n");
+ return -EINVAL;
}
return 0;
}
+void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub)
+{
+ kfree(dpsub->disp);
+ kfree(dpsub->dp);
+ kfree(dpsub);
+}
+
static int zynqmp_dpsub_probe(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub;
int ret;
/* Allocate private data. */
- dpsub = devm_drm_dev_alloc(&pdev->dev, &zynqmp_dpsub_drm_driver,
- struct zynqmp_dpsub, drm);
- if (IS_ERR(dpsub))
- return PTR_ERR(dpsub);
+ dpsub = kzalloc(sizeof(*dpsub), GFP_KERNEL);
+ if (!dpsub)
+ return -ENOMEM;
dpsub->dev = &pdev->dev;
platform_set_drvdata(pdev, dpsub);
@@ -210,23 +236,31 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
if (ret < 0)
goto err_mem;
+ ret = zynqmp_dpsub_parse_dt(dpsub);
+ if (ret < 0)
+ goto err_mem;
+
pm_runtime_enable(&pdev->dev);
/*
* DP should be probed first so that the zynqmp_disp can set the output
* format accordingly.
*/
- ret = zynqmp_dp_probe(dpsub, &dpsub->drm);
+ ret = zynqmp_dp_probe(dpsub);
if (ret)
goto err_pm;
- ret = zynqmp_disp_probe(dpsub, &dpsub->drm);
+ ret = zynqmp_disp_probe(dpsub);
if (ret)
goto err_dp;
- ret = zynqmp_dpsub_drm_init(dpsub);
- if (ret)
- goto err_disp;
+ if (dpsub->dma_enabled) {
+ ret = zynqmp_dpsub_drm_init(dpsub);
+ if (ret)
+ goto err_disp;
+ } else {
+ drm_bridge_add(dpsub->bridge);
+ }
dev_info(&pdev->dev, "ZynqMP DisplayPort Subsystem driver probed");
@@ -241,17 +275,19 @@ err_pm:
clk_disable_unprepare(dpsub->apb_clk);
err_mem:
of_reserved_mem_device_release(&pdev->dev);
+ if (!dpsub->drm)
+ zynqmp_dpsub_release(dpsub);
return ret;
}
static int zynqmp_dpsub_remove(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
- struct drm_device *drm = &dpsub->drm;
- drm_dev_unregister(drm);
- drm_atomic_helper_shutdown(drm);
- drm_kms_helper_poll_fini(drm);
+ if (dpsub->drm)
+ zynqmp_dpsub_drm_cleanup(dpsub);
+ else
+ drm_bridge_remove(dpsub->bridge);
zynqmp_disp_remove(dpsub);
zynqmp_dp_remove(dpsub);
@@ -260,6 +296,9 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev)
clk_disable_unprepare(dpsub->apb_clk);
of_reserved_mem_device_release(&pdev->dev);
+ if (!dpsub->drm)
+ zynqmp_dpsub_release(dpsub);
+
return 0;
}
@@ -267,7 +306,10 @@ static void zynqmp_dpsub_shutdown(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
- drm_atomic_helper_shutdown(&dpsub->drm);
+ if (!dpsub->drm)
+ return;
+
+ drm_atomic_helper_shutdown(&dpsub->drm->dev);
}
static const struct of_device_id zynqmp_dpsub_of_match[] = {
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h
index c04026d82639..09ea01878f2a 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h
@@ -14,9 +14,23 @@
struct clk;
struct device;
-struct drm_device;
+struct drm_bridge;
struct zynqmp_disp;
+struct zynqmp_disp_layer;
struct zynqmp_dp;
+struct zynqmp_dpsub_drm;
+
+#define ZYNQMP_DPSUB_NUM_LAYERS 2
+
+enum zynqmp_dpsub_port {
+ ZYNQMP_DPSUB_PORT_LIVE_VIDEO,
+ ZYNQMP_DPSUB_PORT_LIVE_GFX,
+ ZYNQMP_DPSUB_PORT_LIVE_AUDIO,
+ ZYNQMP_DPSUB_PORT_OUT_VIDEO,
+ ZYNQMP_DPSUB_PORT_OUT_AUDIO,
+ ZYNQMP_DPSUB_PORT_OUT_DP,
+ ZYNQMP_DPSUB_NUM_PORTS,
+};
enum zynqmp_dpsub_format {
ZYNQMP_DPSUB_FORMAT_RGB,
@@ -27,28 +41,46 @@ enum zynqmp_dpsub_format {
/**
* struct zynqmp_dpsub - ZynqMP DisplayPort Subsystem
- * @drm: The DRM/KMS device
* @dev: The physical device
* @apb_clk: The APB clock
+ * @vid_clk: Video clock
+ * @vid_clk_from_ps: True of the video clock comes from PS, false from PL
+ * @aud_clk: Audio clock
+ * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL
+ * @connected_ports: Bitmask of connected ports in the device tree
+ * @dma_enabled: True if the DMA interface is enabled, false if the DPSUB is
+ * driven by the live input
+ * @drm: The DRM/KMS device data
+ * @bridge: The DP encoder bridge
* @disp: The display controller
* @dp: The DisplayPort controller
* @dma_align: DMA alignment constraint (must be a power of 2)
*/
struct zynqmp_dpsub {
- struct drm_device drm;
struct device *dev;
struct clk *apb_clk;
+ struct clk *vid_clk;
+ bool vid_clk_from_ps;
+ struct clk *aud_clk;
+ bool aud_clk_from_ps;
+
+ unsigned int connected_ports;
+ bool dma_enabled;
+
+ struct zynqmp_dpsub_drm *drm;
+ struct drm_bridge *bridge;
struct zynqmp_disp *disp;
+ struct zynqmp_disp_layer *layers[ZYNQMP_DPSUB_NUM_LAYERS];
struct zynqmp_dp *dp;
unsigned int dma_align;
};
-static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm)
-{
- return container_of(drm, struct zynqmp_dpsub, drm);
-}
+bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub);
+unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub);
+
+void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DPSUB_H_ */
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
new file mode 100644
index 000000000000..776ef5480206
--- /dev/null
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ZynqMP DisplayPort Subsystem - KMS API
+ *
+ * Copyright (C) 2017 - 2021 Xilinx, Inc.
+ *
+ * Authors:
+ * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
+ * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_mode_config.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_vblank.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+
+#include "zynqmp_disp.h"
+#include "zynqmp_dp.h"
+#include "zynqmp_dpsub.h"
+#include "zynqmp_kms.h"
+
+static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm)
+{
+ return container_of(drm, struct zynqmp_dpsub_drm, dev)->dpsub;
+}
+
+/* -----------------------------------------------------------------------------
+ * DRM Planes
+ */
+
+static int zynqmp_dpsub_plane_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+ plane);
+ struct drm_crtc_state *crtc_state;
+
+ if (!new_plane_state->crtc)
+ return 0;
+
+ crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ return drm_atomic_helper_check_plane_state(new_plane_state,
+ crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+}
+
+static void zynqmp_dpsub_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+ plane);
+ struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev);
+ struct zynqmp_disp_layer *layer = dpsub->layers[plane->index];
+
+ if (!old_state->fb)
+ return;
+
+ zynqmp_disp_layer_disable(layer);
+
+ if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
+ zynqmp_disp_blend_set_global_alpha(dpsub->disp, false,
+ plane->state->alpha >> 8);
+}
+
+static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+ struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev);
+ struct zynqmp_disp_layer *layer = dpsub->layers[plane->index];
+ bool format_changed = false;
+
+ if (!old_state->fb ||
+ old_state->fb->format->format != new_state->fb->format->format)
+ format_changed = true;
+
+ /*
+ * If the format has changed (including going from a previously
+ * disabled state to any format), reconfigure the format. Disable the
+ * plane first if needed.
+ */
+ if (format_changed) {
+ if (old_state->fb)
+ zynqmp_disp_layer_disable(layer);
+
+ zynqmp_disp_layer_set_format(layer, new_state->fb->format);
+ }
+
+ zynqmp_disp_layer_update(layer, new_state);
+
+ if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
+ zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
+ plane->state->alpha >> 8);
+
+ /* Enable or re-enable the plane if the format has changed. */
+ if (format_changed)
+ zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_NONLIVE);
+}
+
+static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = {
+ .atomic_check = zynqmp_dpsub_plane_atomic_check,
+ .atomic_update = zynqmp_dpsub_plane_atomic_update,
+ .atomic_disable = zynqmp_dpsub_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs zynqmp_dpsub_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++) {
+ struct zynqmp_disp_layer *layer = dpsub->layers[i];
+ struct drm_plane *plane = &dpsub->drm->planes[i];
+ enum drm_plane_type type;
+ unsigned int num_formats;
+ u32 *formats;
+
+ formats = zynqmp_disp_layer_drm_formats(layer, &num_formats);
+ if (!formats)
+ return -ENOMEM;
+
+ /* Graphics layer is primary, and video layer is overlay. */
+ type = i == ZYNQMP_DPSUB_LAYER_VID
+ ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
+ ret = drm_universal_plane_init(&dpsub->drm->dev, plane, 0,
+ &zynqmp_dpsub_plane_funcs,
+ formats, num_formats,
+ NULL, type, NULL);
+ kfree(formats);
+ if (ret)
+ return ret;
+
+ drm_plane_helper_add(plane, &zynqmp_dpsub_plane_helper_funcs);
+
+ drm_plane_create_zpos_immutable_property(plane, i);
+ if (i == ZYNQMP_DPSUB_LAYER_GFX)
+ drm_plane_create_alpha_property(plane);
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * DRM CRTC
+ */
+
+static inline struct zynqmp_dpsub *crtc_to_dpsub(struct drm_crtc *crtc)
+{
+ return container_of(crtc, struct zynqmp_dpsub_drm, crtc)->dpsub;
+}
+
+static void zynqmp_dpsub_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+ int ret, vrefresh;
+
+ pm_runtime_get_sync(dpsub->dev);
+
+ zynqmp_disp_setup_clock(dpsub->disp, adjusted_mode->clock * 1000);
+
+ ret = clk_prepare_enable(dpsub->vid_clk);
+ if (ret) {
+ dev_err(dpsub->dev, "failed to enable a pixel clock\n");
+ pm_runtime_put_sync(dpsub->dev);
+ return;
+ }
+
+ zynqmp_disp_enable(dpsub->disp);
+
+ /* Delay of 3 vblank intervals for timing gen to be stable */
+ vrefresh = (adjusted_mode->clock * 1000) /
+ (adjusted_mode->vtotal * adjusted_mode->htotal);
+ msleep(3 * 1000 / vrefresh);
+}
+
+static void zynqmp_dpsub_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
+ struct drm_plane_state *old_plane_state;
+
+ /*
+ * Disable the plane if active. The old plane state can be NULL in the
+ * .shutdown() path if the plane is already disabled, skip
+ * zynqmp_disp_plane_atomic_disable() in that case.
+ */
+ old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
+ if (old_plane_state)
+ zynqmp_dpsub_plane_atomic_disable(crtc->primary, state);
+
+ zynqmp_disp_disable(dpsub->disp);
+
+ drm_crtc_vblank_off(crtc);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ clk_disable_unprepare(dpsub->vid_clk);
+ pm_runtime_put_sync(dpsub->dev);
+}
+
+static int zynqmp_dpsub_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ return drm_atomic_add_affected_planes(state, crtc);
+}
+
+static void zynqmp_dpsub_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ drm_crtc_vblank_on(crtc);
+}
+
+static void zynqmp_dpsub_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ if (crtc->state->event) {
+ struct drm_pending_vblank_event *event;
+
+ /* Consume the flip_done event from atomic helper. */
+ event = crtc->state->event;
+ crtc->state->event = NULL;
+
+ event->pipe = drm_crtc_index(crtc);
+
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_arm_vblank_event(crtc, event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+ }
+}
+
+static const struct drm_crtc_helper_funcs zynqmp_dpsub_crtc_helper_funcs = {
+ .atomic_enable = zynqmp_dpsub_crtc_atomic_enable,
+ .atomic_disable = zynqmp_dpsub_crtc_atomic_disable,
+ .atomic_check = zynqmp_dpsub_crtc_atomic_check,
+ .atomic_begin = zynqmp_dpsub_crtc_atomic_begin,
+ .atomic_flush = zynqmp_dpsub_crtc_atomic_flush,
+};
+
+static int zynqmp_dpsub_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
+
+ zynqmp_dp_enable_vblank(dpsub->dp);
+
+ return 0;
+}
+
+static void zynqmp_dpsub_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+ struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
+
+ zynqmp_dp_disable_vblank(dpsub->dp);
+}
+
+static const struct drm_crtc_funcs zynqmp_dpsub_crtc_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = zynqmp_dpsub_crtc_enable_vblank,
+ .disable_vblank = zynqmp_dpsub_crtc_disable_vblank,
+};
+
+static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub)
+{
+ struct drm_plane *plane = &dpsub->drm->planes[ZYNQMP_DPSUB_LAYER_GFX];
+ struct drm_crtc *crtc = &dpsub->drm->crtc;
+ int ret;
+
+ ret = drm_crtc_init_with_planes(&dpsub->drm->dev, crtc, plane,
+ NULL, &zynqmp_dpsub_crtc_funcs, NULL);
+ if (ret < 0)
+ return ret;
+
+ drm_crtc_helper_add(crtc, &zynqmp_dpsub_crtc_helper_funcs);
+
+ /* Start with vertical blanking interrupt reporting disabled. */
+ drm_crtc_vblank_off(crtc);
+
+ return 0;
+}
+
+static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub)
+{
+ u32 possible_crtcs = drm_crtc_mask(&dpsub->drm->crtc);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++)
+ dpsub->drm->planes[i].possible_crtcs = possible_crtcs;
+}
+
+/**
+ * zynqmp_dpsub_drm_handle_vblank - Handle the vblank event
+ * @dpsub: DisplayPort subsystem
+ *
+ * This function handles the vblank interrupt, and sends an event to
+ * CRTC object. This will be called by the DP vblank interrupt handler.
+ */
+void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub)
+{
+ drm_crtc_handle_vblank(&dpsub->drm->crtc);
+}
+
+/* -----------------------------------------------------------------------------
+ * Dumb Buffer & Framebuffer Allocation
+ */
+
+static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
+ struct drm_device *drm,
+ struct drm_mode_create_dumb *args)
+{
+ struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
+ unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+ /* Enforce the alignment constraints of the DMA engine. */
+ args->pitch = ALIGN(pitch, dpsub->dma_align);
+
+ return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
+}
+
+static struct drm_framebuffer *
+zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
+ struct drm_mode_fb_cmd2 cmd = *mode_cmd;
+ unsigned int i;
+
+ /* Enforce the alignment constraints of the DMA engine. */
+ for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
+ cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
+
+ return drm_gem_fb_create(drm, file_priv, &cmd);
+}
+
+static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = {
+ .fb_create = zynqmp_dpsub_fb_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+/* -----------------------------------------------------------------------------
+ * DRM/KMS Driver
+ */
+
+DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops);
+
+static const struct drm_driver zynqmp_dpsub_drm_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM |
+ DRIVER_ATOMIC,
+
+ DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create),
+
+ .fops = &zynqmp_dpsub_drm_fops,
+
+ .name = "zynqmp-dpsub",
+ .desc = "Xilinx DisplayPort Subsystem Driver",
+ .date = "20130509",
+ .major = 1,
+ .minor = 0,
+};
+
+static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
+{
+ struct drm_encoder *encoder = &dpsub->drm->encoder;
+ struct drm_connector *connector;
+ int ret;
+
+ /* Create the planes and the CRTC. */
+ ret = zynqmp_dpsub_create_planes(dpsub);
+ if (ret)
+ return ret;
+
+ ret = zynqmp_dpsub_create_crtc(dpsub);
+ if (ret < 0)
+ return ret;
+
+ zynqmp_dpsub_map_crtc_to_plane(dpsub);
+
+ /* Create the encoder and attach the bridge. */
+ encoder->possible_crtcs |= drm_crtc_mask(&dpsub->drm->crtc);
+ drm_simple_encoder_init(&dpsub->drm->dev, encoder, DRM_MODE_ENCODER_NONE);
+
+ ret = drm_bridge_attach(encoder, dpsub->bridge, NULL,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret) {
+ dev_err(dpsub->dev, "failed to attach bridge to encoder\n");
+ return ret;
+ }
+
+ /* Create the connector for the chain of bridges. */
+ connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder);
+ if (IS_ERR(connector)) {
+ dev_err(dpsub->dev, "failed to created connector\n");
+ return PTR_ERR(connector);
+ }
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret < 0) {
+ dev_err(dpsub->dev, "failed to attach connector to encoder\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void zynqmp_dpsub_drm_release(struct drm_device *drm, void *res)
+{
+ struct zynqmp_dpsub_drm *dpdrm = res;
+
+ zynqmp_dpsub_release(dpdrm->dpsub);
+}
+
+int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
+{
+ struct zynqmp_dpsub_drm *dpdrm;
+ struct drm_device *drm;
+ int ret;
+
+ /*
+ * Allocate the drm_device and immediately add a cleanup action to
+ * release the zynqmp_dpsub instance. If any of those operations fail,
+ * dpsub->drm will remain NULL, which tells the caller that it must
+ * cleanup manually.
+ */
+ dpdrm = devm_drm_dev_alloc(dpsub->dev, &zynqmp_dpsub_drm_driver,
+ struct zynqmp_dpsub_drm, dev);
+ if (IS_ERR(dpdrm))
+ return PTR_ERR(dpdrm);
+
+ dpdrm->dpsub = dpsub;
+ drm = &dpdrm->dev;
+
+ ret = drmm_add_action(drm, zynqmp_dpsub_drm_release, dpdrm);
+ if (ret < 0)
+ return ret;
+
+ dpsub->drm = dpdrm;
+
+ /* Initialize mode config, vblank and the KMS poll helper. */
+ ret = drmm_mode_config_init(drm);
+ if (ret < 0)
+ return ret;
+
+ drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
+ drm->mode_config.min_width = 0;
+ drm->mode_config.min_height = 0;
+ drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
+ drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
+
+ ret = drm_vblank_init(drm, 1);
+ if (ret)
+ return ret;
+
+ drm_kms_helper_poll_init(drm);
+
+ ret = zynqmp_dpsub_kms_init(dpsub);
+ if (ret < 0)
+ goto err_poll_fini;
+
+ /* Reset all components and register the DRM device. */
+ drm_mode_config_reset(drm);
+
+ ret = drm_dev_register(drm, 0);
+ if (ret < 0)
+ goto err_poll_fini;
+
+ /* Initialize fbdev generic emulation. */
+ drm_fbdev_generic_setup(drm, 24);
+
+ return 0;
+
+err_poll_fini:
+ drm_kms_helper_poll_fini(drm);
+ return ret;
+}
+
+void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub)
+{
+ struct drm_device *drm = &dpsub->drm->dev;
+
+ drm_dev_unregister(drm);
+ drm_atomic_helper_shutdown(drm);
+ drm_kms_helper_poll_fini(drm);
+}
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h
new file mode 100644
index 000000000000..01be96b00e3f
--- /dev/null
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ZynqMP DisplayPort Subsystem - KMS API
+ *
+ * Copyright (C) 2017 - 2021 Xilinx, Inc.
+ *
+ * Authors:
+ * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
+ * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#ifndef _ZYNQMP_KMS_H_
+#define _ZYNQMP_KMS_H_
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_plane.h>
+
+#include "zynqmp_dpsub.h"
+
+struct zynqmp_dpsub;
+
+/**
+ * struct zynqmp_dpsub - ZynqMP DisplayPort Subsystem DRM/KMS data
+ * @dpsub: Backpointer to the DisplayPort subsystem
+ * @drm: The DRM/KMS device
+ * @planes: The DRM planes
+ * @crtc: The DRM CRTC
+ * @encoder: The dummy DRM encoder
+ */
+struct zynqmp_dpsub_drm {
+ struct zynqmp_dpsub *dpsub;
+
+ struct drm_device dev;
+ struct drm_plane planes[ZYNQMP_DPSUB_NUM_LAYERS];
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+};
+
+void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub);
+
+int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub);
+void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub);
+
+#endif /* _ZYNQMP_KMS_H_ */
diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c
index b08cf11f9a66..c8e7994c2c9c 100644
--- a/drivers/gpu/host1x/context.c
+++ b/drivers/gpu/host1x/context.c
@@ -104,6 +104,7 @@ void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl)
}
struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
+ struct device *dev,
struct pid *pid)
{
struct host1x_memory_context_list *cdl = &host1x->context_list;
@@ -118,6 +119,9 @@ struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
for (i = 0; i < cdl->len; i++) {
struct host1x_memory_context *cd = &cdl->devs[i];
+ if (cd->dev.iommu->iommu_dev != dev->iommu->iommu_dev)
+ continue;
+
if (cd->owner == pid) {
refcount_inc(&cd->ref);
mutex_unlock(&cdl->lock);
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c
index 34c2e36d09e9..6649b04b7131 100644
--- a/drivers/gpu/host1x/debug.c
+++ b/drivers/gpu/host1x/debug.c
@@ -140,7 +140,7 @@ static void show_all(struct host1x *m, struct output *o, bool show_fifo)
}
}
-static int host1x_debug_show_all(struct seq_file *s, void *unused)
+static int host1x_debug_all_show(struct seq_file *s, void *unused)
{
struct output o = {
.fn = write_to_seqfile,
@@ -151,6 +151,7 @@ static int host1x_debug_show_all(struct seq_file *s, void *unused)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(host1x_debug_all);
static int host1x_debug_show(struct seq_file *s, void *unused)
{
@@ -163,30 +164,7 @@ static int host1x_debug_show(struct seq_file *s, void *unused)
return 0;
}
-
-static int host1x_debug_open_all(struct inode *inode, struct file *file)
-{
- return single_open(file, host1x_debug_show_all, inode->i_private);
-}
-
-static const struct file_operations host1x_debug_all_fops = {
- .open = host1x_debug_open_all,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int host1x_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, host1x_debug_show, inode->i_private);
-}
-
-static const struct file_operations host1x_debug_fops = {
- .open = host1x_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(host1x_debug);
static void host1x_debugfs_init(struct host1x *host1x)
{
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 0cd3f97e7e49..f31039aca03c 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -225,6 +225,18 @@ static const struct host1x_sid_entry tegra234_sid_table[] = {
.offset = 0x34,
.limit = 0x34
},
+ {
+ /* NVDEC channel */
+ .base = 0x17c8,
+ .offset = 0x30,
+ .limit = 0x30,
+ },
+ {
+ /* NVDEC MMIO */
+ .base = 0x1698,
+ .offset = 0x34,
+ .limit = 0x34,
+ },
};
static const struct host1x_info host1x08_info = {
@@ -292,6 +304,10 @@ static void host1x_setup_virtualization_tables(struct host1x *host)
static bool host1x_wants_iommu(struct host1x *host1x)
{
+ /* Our IOMMU usage policy doesn't currently play well with GART */
+ if (of_machine_is_compatible("nvidia,tegra20"))
+ return false;
+
/*
* If we support addressing a maximum of 32 bits of physical memory
* and if the host1x firewall is enabled, there's no need to enable
diff --git a/drivers/gpu/host1x/fence.c b/drivers/gpu/host1x/fence.c
index ecab72882192..df428bcbae69 100644
--- a/drivers/gpu/host1x/fence.c
+++ b/drivers/gpu/host1x/fence.c
@@ -99,7 +99,7 @@ static void host1x_syncpt_fence_release(struct dma_fence *f)
dma_fence_free(f);
}
-const struct dma_fence_ops host1x_syncpt_fence_ops = {
+static const struct dma_fence_ops host1x_syncpt_fence_ops = {
.get_driver_name = host1x_syncpt_fence_get_driver_name,
.get_timeline_name = host1x_syncpt_fence_get_timeline_name,
.enable_signaling = host1x_syncpt_fence_enable_signaling,
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index b59c3dafa6a4..f99752b998f3 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -219,14 +219,13 @@ static void asus_report_tool_width(struct asus_drvdata *drvdat)
{
struct input_mt *mt = drvdat->input->mt;
struct input_mt_slot *oldest;
- int oldid, count, i;
+ int oldid, i;
if (drvdat->tp->contact_size < 5)
return;
oldest = NULL;
oldid = mt->trkid;
- count = 0;
for (i = 0; i < mt->num_slots; ++i) {
struct input_mt_slot *ps = &mt->slots[i];
@@ -238,7 +237,6 @@ static void asus_report_tool_width(struct asus_drvdata *drvdat)
oldest = ps;
oldid = id;
}
- count++;
}
if (oldest) {
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 9c1d31f63f85..bd47628da6be 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1315,6 +1315,9 @@ static s32 snto32(__u32 value, unsigned n)
if (!value || !n)
return 0;
+ if (n > 32)
+ n = 32;
+
switch (n) {
case 8: return ((__s8)value);
case 16: return ((__s16)value);
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index e0bc73124196..ab57b49a44ed 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -499,7 +499,7 @@ static int mousevsc_probe(struct hv_device *device,
ret = hid_add_device(hid_dev);
if (ret)
- goto probe_err1;
+ goto probe_err2;
ret = hid_parse(hid_dev);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index dad953f66996..8f58c3c1bec3 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -274,6 +274,7 @@
#define USB_DEVICE_ID_CH_AXIS_295 0x001c
#define USB_VENDOR_ID_CHERRY 0x046a
+#define USB_DEVICE_ID_CHERRY_MOUSE_000C 0x000c
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
#define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027
@@ -917,6 +918,7 @@
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
#define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb
#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS 0x02e0
+#define USB_DEVICE_ID_MS_MOUSE_0783 0x0783
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -1215,6 +1217,7 @@
#define USB_DEVICE_ID_SYNAPTICS_DELL_K15A 0x6e21
#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4
#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5
+#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017 0x73f6
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7
#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047
@@ -1381,6 +1384,7 @@
#define USB_VENDOR_ID_PRIMAX 0x0461
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
+#define USB_DEVICE_ID_PRIMAX_MOUSE_4E2A 0x4e2a
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c
index 430fa4f52ed3..75ebfcf31889 100644
--- a/drivers/hid/hid-ite.c
+++ b/drivers/hid/hid-ite.c
@@ -121,6 +121,11 @@ static const struct hid_device_id ite_devices[] = {
USB_VENDOR_ID_SYNAPTICS,
USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003),
.driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
+ /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+ USB_VENDOR_ID_SYNAPTICS,
+ USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017),
+ .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
{ }
};
MODULE_DEVICE_TABLE(hid, ite_devices);
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 5e6a0cef2a06..e3fcf1353fb3 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -872,6 +872,12 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att
return -ENOMEM;
i = strlen(lbuf);
+
+ if (i == 0) {
+ kfree(lbuf);
+ return -EINVAL;
+ }
+
if (lbuf[i-1] == '\n') {
if (i == 1) {
kfree(lbuf);
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 71a9c258a20b..8a2aac18dcc5 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4269,21 +4269,6 @@ static void hidpp_remove(struct hid_device *hdev)
mutex_destroy(&hidpp->send_mutex);
}
-static const struct hid_device_id unhandled_hidpp_devices[] = {
- /* Logitech Harmony Adapter for PS3, handled in hid-sony */
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
- /* Handled in hid-generic */
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD) },
- {}
-};
-
-static bool hidpp_match(struct hid_device *hdev,
- bool ignore_special_driver)
-{
- /* Refuse to handle devices handled by other HID drivers */
- return !hid_match_id(hdev, unhandled_hidpp_devices);
-}
-
#define LDJ_DEVICE(product) \
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
USB_VENDOR_ID_LOGITECH, (product))
@@ -4367,9 +4352,15 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* MX5500 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
-
- { /* And try to enable HID++ for all the Logitech Bluetooth devices */
- HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_ANY, USB_VENDOR_ID_LOGITECH, HID_ANY_ID) },
+ { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
+ { /* MX Master mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012) },
+ { /* MX Ergo trackball over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) },
+ { /* MX Master 3 mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
{}
};
@@ -4383,7 +4374,6 @@ static const struct hid_usage_id hidpp_usages[] = {
static struct hid_driver hidpp_driver = {
.name = "logitech-hidpp-device",
.id_table = hidpp_devices,
- .match = hidpp_match,
.report_fixup = hidpp_report_fixup,
.probe = hidpp_probe,
.remove = hidpp_remove,
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 50e1c717fc0a..0e9702c7f7d6 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -54,6 +54,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_MOUSE_000C), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS },
@@ -122,6 +123,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_MOUSE_0783), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE3_COVER), HID_QUIRK_NO_INIT_REPORTS },
@@ -146,6 +148,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4E2A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 0fbc408c2607..7fa6fe04f1b2 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -192,6 +192,7 @@ static int uclogic_probe(struct hid_device *hdev,
* than the pen, so use QUIRK_MULTI_INPUT for all tablets.
*/
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+ hdev->quirks |= HID_QUIRK_HIDINPUT_FORCE;
/* Allocate and assign driver data */
drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c
index 4bd54c4fb5b0..6b73eb0df6bd 100644
--- a/drivers/hid/hid-uclogic-rdesc.c
+++ b/drivers/hid/hid-uclogic-rdesc.c
@@ -1193,7 +1193,7 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
p[sizeof(btn_head)] < param_num) {
v = param_list[p[sizeof(btn_head)]];
put_unaligned((__u8)0x2A, p); /* Usage Maximum */
- put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1);
+ put_unaligned((__force u16)cpu_to_le16(v), (s16 *)(p + 1));
p += sizeof(btn_head) + 1;
} else {
p++;
diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index 5273ee2bb134..d65abe65ce73 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -66,6 +66,6 @@ endmenu
config I2C_HID_CORE
tristate
- default y if I2C_HID_ACPI=y || I2C_HID_OF=y || I2C_HID_OF_GOODIX=y
- default m if I2C_HID_ACPI=m || I2C_HID_OF=m || I2C_HID_OF_GOODIX=m
+ default y if I2C_HID_ACPI=y || I2C_HID_OF=y || I2C_HID_OF_ELAN=y || I2C_HID_OF_GOODIX=y
+ default m if I2C_HID_ACPI=m || I2C_HID_OF=m || I2C_HID_OF_ELAN=m || I2C_HID_OF_GOODIX=m
select HID
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 77486962a773..0f3d57b42684 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -2520,11 +2520,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
int id = wacom_wac->id[0];
- if (wacom_wac->features.quirks & WACOM_QUIRK_PEN_BUTTON3 &&
- wacom_wac->hid_data.barrelswitch & wacom_wac->hid_data.barrelswitch2) {
- wacom_wac->hid_data.barrelswitch = 0;
- wacom_wac->hid_data.barrelswitch2 = 0;
- wacom_wac->hid_data.barrelswitch3 = 1;
+ if (wacom_wac->features.quirks & WACOM_QUIRK_PEN_BUTTON3) {
+ int sw_state = wacom_wac->hid_data.barrelswitch |
+ (wacom_wac->hid_data.barrelswitch2 << 1);
+ wacom_wac->hid_data.barrelswitch = sw_state == 1;
+ wacom_wac->hid_data.barrelswitch2 = sw_state == 2;
+ wacom_wac->hid_data.barrelswitch3 = sw_state == 3;
}
input_report_key(input, BTN_STYLUS, wacom_wac->hid_data.barrelswitch);
input_report_key(input, BTN_STYLUS2, wacom_wac->hid_data.barrelswitch2);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 5b120402d405..cc23b90cae02 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -533,13 +533,17 @@ static void vmbus_add_channel_work(struct work_struct *work)
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
+ *
+ * If vmbus_device_register() fails, the 'device_obj' is freed in
+ * vmbus_device_release() as called by device_unregister() in the
+ * error path of vmbus_device_register(). In the outside error
+ * path, there's no need to free it.
*/
ret = vmbus_device_register(newchannel->device_obj);
if (ret != 0) {
pr_err("unable to add child device object (relid %d)\n",
newchannel->offermsg.child_relid);
- kfree(newchannel->device_obj);
goto err_deq_chan;
}
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index fdf6decacf06..cbe43e2567a7 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -469,12 +469,16 @@ static bool do_hot_add;
* the specified number of seconds.
*/
static uint pressure_report_delay = 45;
+extern unsigned int page_reporting_order;
+#define HV_MAX_FAILURES 2
/*
* The last time we posted a pressure report to host.
*/
static unsigned long last_post_time;
+static int hv_hypercall_multi_failure;
+
module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
@@ -579,6 +583,10 @@ static struct hv_dynmem_device dm_device;
static void post_status(struct hv_dynmem_device *dm);
+static void enable_page_reporting(void);
+
+static void disable_page_reporting(void);
+
#ifdef CONFIG_MEMORY_HOTPLUG
static inline bool has_pfn_is_backed(struct hv_hotadd_state *has,
unsigned long pfn)
@@ -905,7 +913,7 @@ static unsigned long handle_pg_range(unsigned long pg_start,
* We have some residual hot add range
* that needs to be hot added; hot add
* it now. Hot add a multiple of
- * of HA_CHUNK that fully covers the pages
+ * HA_CHUNK that fully covers the pages
* we have.
*/
size = (has->end_pfn - has->ha_end_pfn);
@@ -1418,6 +1426,18 @@ static int dm_thread_func(void *dm_dev)
*/
reinit_completion(&dm_device.config_event);
post_status(dm);
+ /*
+ * disable free page reporting if multiple hypercall
+ * failure flag set. It is not done in the page_reporting
+ * callback context as that causes a deadlock between
+ * page_reporting_process() and page_reporting_unregister()
+ */
+ if (hv_hypercall_multi_failure >= HV_MAX_FAILURES) {
+ pr_err("Multiple failures in cold memory discard hypercall, disabling page reporting\n");
+ disable_page_reporting();
+ /* Reset the flag after disabling reporting */
+ hv_hypercall_multi_failure = 0;
+ }
}
return 0;
@@ -1593,20 +1613,20 @@ static void balloon_onchannelcallback(void *context)
}
-/* Hyper-V only supports reporting 2MB pages or higher */
-#define HV_MIN_PAGE_REPORTING_ORDER 9
-#define HV_MIN_PAGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << HV_MIN_PAGE_REPORTING_ORDER)
+#define HV_LARGE_REPORTING_ORDER 9
+#define HV_LARGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << \
+ HV_LARGE_REPORTING_ORDER)
static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info,
struct scatterlist *sgl, unsigned int nents)
{
unsigned long flags;
struct hv_memory_hint *hint;
- int i;
+ int i, order;
u64 status;
struct scatterlist *sg;
WARN_ON_ONCE(nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES);
- WARN_ON_ONCE(sgl->length < HV_MIN_PAGE_REPORTING_LEN);
+ WARN_ON_ONCE(sgl->length < (HV_HYP_PAGE_SIZE << page_reporting_order));
local_irq_save(flags);
hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg);
if (!hint) {
@@ -1621,21 +1641,53 @@ static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info,
range = &hint->ranges[i];
range->address_space = 0;
- /* page reporting only reports 2MB pages or higher */
- range->page.largepage = 1;
- range->page.additional_pages =
- (sg->length / HV_MIN_PAGE_REPORTING_LEN) - 1;
- range->page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB;
- range->base_large_pfn =
- page_to_hvpfn(sg_page(sg)) >> HV_MIN_PAGE_REPORTING_ORDER;
+ order = get_order(sg->length);
+ /*
+ * Hyper-V expects the additional_pages field in the units
+ * of one of these 3 sizes, 4Kbytes, 2Mbytes or 1Gbytes.
+ * This is dictated by the values of the fields page.largesize
+ * and page_size.
+ * This code however, only uses 4Kbytes and 2Mbytes units
+ * and not 1Gbytes unit.
+ */
+
+ /* page reporting for pages 2MB or higher */
+ if (order >= HV_LARGE_REPORTING_ORDER ) {
+ range->page.largepage = 1;
+ range->page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB;
+ range->base_large_pfn = page_to_hvpfn(
+ sg_page(sg)) >> HV_LARGE_REPORTING_ORDER;
+ range->page.additional_pages =
+ (sg->length / HV_LARGE_REPORTING_LEN) - 1;
+ } else {
+ /* Page reporting for pages below 2MB */
+ range->page.basepfn = page_to_hvpfn(sg_page(sg));
+ range->page.largepage = false;
+ range->page.additional_pages =
+ (sg->length / HV_HYP_PAGE_SIZE) - 1;
+ }
+
}
status = hv_do_rep_hypercall(HV_EXT_CALL_MEMORY_HEAT_HINT, nents, 0,
hint, NULL);
local_irq_restore(flags);
- if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) {
+ if (!hv_result_success(status)) {
+
pr_err("Cold memory discard hypercall failed with status %llx\n",
- status);
+ status);
+ if (hv_hypercall_multi_failure > 0)
+ hv_hypercall_multi_failure++;
+
+ if (hv_result(status) == HV_STATUS_INVALID_PARAMETER) {
+ pr_err("Underlying Hyper-V does not support order less than 9. Hypercall failed\n");
+ pr_err("Defaulting to page_reporting_order %d\n",
+ pageblock_order);
+ page_reporting_order = pageblock_order;
+ hv_hypercall_multi_failure++;
+ return -EINVAL;
+ }
+
return -EINVAL;
}
@@ -1646,12 +1698,6 @@ static void enable_page_reporting(void)
{
int ret;
- /* Essentially, validating 'PAGE_REPORTING_MIN_ORDER' is big enough. */
- if (pageblock_order < HV_MIN_PAGE_REPORTING_ORDER) {
- pr_debug("Cold memory discard is only supported on 2MB pages and above\n");
- return;
- }
-
if (!hv_query_ext_cap(HV_EXT_CAPABILITY_MEMORY_COLD_DISCARD_HINT)) {
pr_debug("Cold memory discard hint not supported by Hyper-V\n");
return;
@@ -1659,12 +1705,18 @@ static void enable_page_reporting(void)
BUILD_BUG_ON(PAGE_REPORTING_CAPACITY > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES);
dm_device.pr_dev_info.report = hv_free_page_report;
+ /*
+ * We let the page_reporting_order parameter decide the order
+ * in the page_reporting code
+ */
+ dm_device.pr_dev_info.order = 0;
ret = page_reporting_register(&dm_device.pr_dev_info);
if (ret < 0) {
dm_device.pr_dev_info.report = NULL;
pr_err("Failed to enable cold memory discard: %d\n", ret);
} else {
- pr_info("Cold memory discard hint enabled\n");
+ pr_info("Cold memory discard hint enabled with order %d\n",
+ page_reporting_order);
}
}
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 59a4aa86d1f3..c6692fd5ab15 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -280,6 +280,19 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
ring_info->pkt_buffer_size = 0;
}
+/*
+ * Check if the ring buffer spinlock is available to take or not; used on
+ * atomic contexts, like panic path (see the Hyper-V framebuffer driver).
+ */
+
+bool hv_ringbuffer_spinlock_busy(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rinfo = &channel->outbound;
+
+ return spin_is_locked(&rinfo->ring_lock);
+}
+EXPORT_SYMBOL_GPL(hv_ringbuffer_spinlock_busy);
+
/* Write to the ring buffer. */
int hv_ringbuffer_write(struct vmbus_channel *channel,
const struct kvec *kv_list, u32 kv_count,
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 8b2e413bf19c..3146710d4ac6 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -25,7 +25,6 @@
#include <linux/sched/task_stack.h>
#include <linux/delay.h>
-#include <linux/notifier.h>
#include <linux/panic_notifier.h>
#include <linux/ptrace.h>
#include <linux/screen_info.h>
@@ -37,6 +36,7 @@
#include <linux/dma-map-ops.h>
#include <linux/pci.h>
#include <clocksource/hyperv_timer.h>
+#include <asm/mshyperv.h>
#include "hyperv_vmbus.h"
struct vmbus_dynid {
@@ -68,53 +68,74 @@ static int hyperv_report_reg(void)
return !sysctl_record_panic_msg || !hv_panic_page;
}
-static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
+/*
+ * The panic notifier below is responsible solely for unloading the
+ * vmbus connection, which is necessary in a panic event.
+ *
+ * Notice an intrincate relation of this notifier with Hyper-V
+ * framebuffer panic notifier exists - we need vmbus connection alive
+ * there in order to succeed, so we need to order both with each other
+ * [see hvfb_on_panic()] - this is done using notifiers' priorities.
+ */
+static int hv_panic_vmbus_unload(struct notifier_block *nb, unsigned long val,
void *args)
{
- struct pt_regs *regs;
-
vmbus_initiate_unload(true);
-
- /*
- * Hyper-V should be notified only once about a panic. If we will be
- * doing hv_kmsg_dump() with kmsg data later, don't do the notification
- * here.
- */
- if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
- && hyperv_report_reg()) {
- regs = current_pt_regs();
- hyperv_report_panic(regs, val, false);
- }
return NOTIFY_DONE;
}
+static struct notifier_block hyperv_panic_vmbus_unload_block = {
+ .notifier_call = hv_panic_vmbus_unload,
+ .priority = INT_MIN + 1, /* almost the latest one to execute */
+};
+
+static int hv_die_panic_notify_crash(struct notifier_block *self,
+ unsigned long val, void *args);
+
+static struct notifier_block hyperv_die_report_block = {
+ .notifier_call = hv_die_panic_notify_crash,
+};
+static struct notifier_block hyperv_panic_report_block = {
+ .notifier_call = hv_die_panic_notify_crash,
+};
-static int hyperv_die_event(struct notifier_block *nb, unsigned long val,
- void *args)
+/*
+ * The following callback works both as die and panic notifier; its
+ * goal is to provide panic information to the hypervisor unless the
+ * kmsg dumper is used [see hv_kmsg_dump()], which provides more
+ * information but isn't always available.
+ *
+ * Notice that both the panic/die report notifiers are registered only
+ * if we have the capability HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE set.
+ */
+static int hv_die_panic_notify_crash(struct notifier_block *self,
+ unsigned long val, void *args)
{
- struct die_args *die = args;
- struct pt_regs *regs = die->regs;
+ struct pt_regs *regs;
+ bool is_die;
+
+ /* Don't notify Hyper-V unless we have a die oops event or panic. */
+ if (self == &hyperv_panic_report_block) {
+ is_die = false;
+ regs = current_pt_regs();
+ } else { /* die event */
+ if (val != DIE_OOPS)
+ return NOTIFY_DONE;
- /* Don't notify Hyper-V if the die event is other than oops */
- if (val != DIE_OOPS)
- return NOTIFY_DONE;
+ is_die = true;
+ regs = ((struct die_args *)args)->regs;
+ }
/*
- * Hyper-V should be notified only once about a panic. If we will be
- * doing hv_kmsg_dump() with kmsg data later, don't do the notification
- * here.
+ * Hyper-V should be notified only once about a panic/die. If we will
+ * be calling hv_kmsg_dump() later with kmsg data, don't do the
+ * notification here.
*/
if (hyperv_report_reg())
- hyperv_report_panic(regs, val, true);
+ hyperv_report_panic(regs, val, is_die);
+
return NOTIFY_DONE;
}
-static struct notifier_block hyperv_die_block = {
- .notifier_call = hyperv_die_event,
-};
-static struct notifier_block hyperv_panic_block = {
- .notifier_call = hyperv_panic_event,
-};
-
static const char *fb_mmio_name = "fb_range";
static struct resource *fb_mmio;
static struct resource *hyperv_mmio;
@@ -1538,16 +1559,17 @@ static int vmbus_bus_init(void)
if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG)
hv_kmsg_dump_register();
- register_die_notifier(&hyperv_die_block);
+ register_die_notifier(&hyperv_die_report_block);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &hyperv_panic_report_block);
}
/*
- * Always register the panic notifier because we need to unload
- * the VMbus channel connection to prevent any VMbus
- * activity after the VM panics.
+ * Always register the vmbus unload panic notifier because we
+ * need to shut the VMbus channel connection on panic.
*/
atomic_notifier_chain_register(&panic_notifier_list,
- &hyperv_panic_block);
+ &hyperv_panic_vmbus_unload_block);
vmbus_request_offers();
@@ -2082,6 +2104,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
ret = device_register(&child_device_obj->device);
if (ret) {
pr_err("Unable to register child device\n");
+ put_device(&child_device_obj->device);
return ret;
}
@@ -2239,7 +2262,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
return AE_OK;
}
-static int vmbus_acpi_remove(struct acpi_device *device)
+static void vmbus_acpi_remove(struct acpi_device *device)
{
struct resource *cur_res;
struct resource *next_res;
@@ -2256,8 +2279,6 @@ static int vmbus_acpi_remove(struct acpi_device *device)
kfree(cur_res);
}
}
-
- return 0;
}
static void vmbus_reserve_fb(void)
@@ -2799,15 +2820,17 @@ static void __exit vmbus_exit(void)
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
kmsg_dump_unregister(&hv_kmsg_dumper);
- unregister_die_notifier(&hyperv_die_block);
+ unregister_die_notifier(&hyperv_die_report_block);
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &hyperv_panic_report_block);
}
/*
- * The panic notifier is always registered, hence we should
+ * The vmbus panic notifier is always registered, hence we should
* also unconditionally unregister it here as well.
*/
atomic_notifier_chain_unregister(&panic_notifier_list,
- &hyperv_panic_block);
+ &hyperv_panic_vmbus_unload_block);
free_page((unsigned long)hv_panic_page);
unregister_sysctl_table(hv_ctl_table_hdr);
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 0962c12eba5a..fa28d447f0df 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -910,12 +910,12 @@ exit:
return res;
}
-static int acpi_power_meter_remove(struct acpi_device *device)
+static void acpi_power_meter_remove(struct acpi_device *device)
{
struct acpi_power_meter_resource *resource;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
resource = acpi_driver_data(device);
hwmon_device_unregister(resource->hwmon_dev);
@@ -924,7 +924,6 @@ static int acpi_power_meter_remove(struct acpi_device *device)
free_capabilities(resource);
kfree(resource);
- return 0;
}
static int acpi_power_meter_resume(struct device *dev)
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 81e688975c6a..a901e4e33d81 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -938,6 +938,8 @@ static int asus_ec_probe(struct platform_device *pdev)
ec_data->nr_sensors = hweight_long(ec_data->board_info->sensors);
ec_data->sensors = devm_kcalloc(dev, ec_data->nr_sensors,
sizeof(struct ec_sensor), GFP_KERNEL);
+ if (!ec_data->sensors)
+ return -ENOMEM;
status = setup_lock_data(dev);
if (status) {
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index ff64a39d56de..d778a2aaefec 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -187,7 +187,7 @@ struct atk_acpi_input_buf {
};
static int atk_add(struct acpi_device *device);
-static int atk_remove(struct acpi_device *device);
+static void atk_remove(struct acpi_device *device);
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
@@ -1344,7 +1344,7 @@ out:
return err;
}
-static int atk_remove(struct acpi_device *device)
+static void atk_remove(struct acpi_device *device)
{
struct atk_data *data = device->driver_data;
dev_dbg(&device->dev, "removing...\n");
@@ -1359,8 +1359,6 @@ static int atk_remove(struct acpi_device *device)
if (atk_ec_ctl(data, 0))
dev_err(&device->dev, "Failed to disable EC\n");
}
-
- return 0;
}
static int __init atk0110_init(void)
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 8bf32c6c85d9..9bee4d33fbdf 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -242,10 +242,13 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
*/
if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) {
for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) {
- if (host_bridge->device == tjmax_pci_table[i].device)
+ if (host_bridge->device == tjmax_pci_table[i].device) {
+ pci_dev_put(host_bridge);
return tjmax_pci_table[i].tjmax;
+ }
}
}
+ pci_dev_put(host_bridge);
for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {
if (strstr(c->x86_model_id, tjmax_table[i].id))
@@ -533,6 +536,10 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx)
{
struct temp_data *tdata = pdata->core_data[indx];
+ /* if we errored on add then this is already gone */
+ if (!tdata)
+ return;
+
/* Remove the sysfs attributes */
sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c
index 05f68e9c9477..23b9f94fe0a9 100644
--- a/drivers/hwmon/i5500_temp.c
+++ b/drivers/hwmon/i5500_temp.c
@@ -117,7 +117,7 @@ static int i5500_temp_probe(struct pci_dev *pdev,
u32 tstimer;
s8 tsfsc;
- err = pci_enable_device(pdev);
+ err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Failed to enable device\n");
return err;
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index f6ec165c0fa8..1837cccd993c 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -502,6 +502,7 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
return;
out_register:
+ list_del(&data->list);
hwmon_device_unregister(data->hwmon_dev);
out_user:
ipmi_destroy_user(data->user);
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index 2a57f4b60c29..e06186986444 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -228,7 +228,7 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
* Shunt Voltage Sum register has 14-bit value with 1-bit shift
* Other Shunt Voltage registers have 12 bits with 3-bit shift
*/
- if (reg == INA3221_SHUNT_SUM)
+ if (reg == INA3221_SHUNT_SUM || reg == INA3221_CRIT_SUM)
*val = sign_extend32(regval >> 1, 14);
else
*val = sign_extend32(regval >> 3, 12);
@@ -465,7 +465,7 @@ static int ina3221_write_curr(struct device *dev, u32 attr,
* SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV
* SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV
*/
- if (reg == INA3221_SHUNT_SUM)
+ if (reg == INA3221_SHUNT_SUM || reg == INA3221_CRIT_SUM)
regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe;
else
regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c
index 7404e974762f..2dbbbac9de09 100644
--- a/drivers/hwmon/ltc2947-core.c
+++ b/drivers/hwmon/ltc2947-core.c
@@ -396,7 +396,7 @@ static int ltc2947_read_temp(struct device *dev, const u32 attr, long *val,
return ret;
/* in milidegrees celcius, temp is given by: */
- *val = (__val * 204) + 550;
+ *val = (__val * 204) + 5500;
return 0;
}
diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c
index 80ea45b3a815..9cf186362ae2 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -22,6 +22,7 @@
struct qcom_hwspinlock_of_data {
u32 offset;
u32 stride;
+ const struct regmap_config *regmap_config;
};
static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
@@ -73,15 +74,42 @@ static const struct qcom_hwspinlock_of_data of_sfpb_mutex = {
.stride = 0x4,
};
-/* All modern platform has offset 0 and stride of 4k */
+static const struct regmap_config tcsr_msm8226_mutex_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1000,
+ .fast_io = true,
+};
+
+static const struct qcom_hwspinlock_of_data of_msm8226_tcsr_mutex = {
+ .offset = 0,
+ .stride = 0x80,
+ .regmap_config = &tcsr_msm8226_mutex_config,
+};
+
+static const struct regmap_config tcsr_mutex_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x20000,
+ .fast_io = true,
+};
+
static const struct qcom_hwspinlock_of_data of_tcsr_mutex = {
.offset = 0,
.stride = 0x1000,
+ .regmap_config = &tcsr_mutex_config,
};
static const struct of_device_id qcom_hwspinlock_of_match[] = {
{ .compatible = "qcom,sfpb-mutex", .data = &of_sfpb_mutex },
{ .compatible = "qcom,tcsr-mutex", .data = &of_tcsr_mutex },
+ { .compatible = "qcom,apq8084-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,ipq6018-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8226-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8974-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8994-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
@@ -117,14 +145,6 @@ static struct regmap *qcom_hwspinlock_probe_syscon(struct platform_device *pdev,
return regmap;
}
-static const struct regmap_config tcsr_mutex_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = 0x40000,
- .fast_io = true,
-};
-
static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev,
u32 *offset, u32 *stride)
{
@@ -133,6 +153,8 @@ static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev,
void __iomem *base;
data = of_device_get_match_data(dev);
+ if (!data->regmap_config)
+ return ERR_PTR(-EINVAL);
*offset = data->offset;
*stride = data->stride;
@@ -141,7 +163,7 @@ static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev,
if (IS_ERR(base))
return ERR_CAST(base);
- return devm_regmap_init_mmio(dev, base, &tcsr_mutex_config);
+ return devm_regmap_init_mmio(dev, base, data->regmap_config);
}
static int qcom_hwspinlock_probe(struct platform_device *pdev)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index fe0cd205502d..f58943cb1341 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -852,7 +852,8 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
- i2c_recover_bus(adap);
+ if (id->adap.bus_recovery_info)
+ i2c_recover_bus(adap);
goto out;
}
@@ -1263,8 +1264,13 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->rinfo.pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(id->rinfo.pinctrl)) {
+ int err = PTR_ERR(id->rinfo.pinctrl);
+
dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
- return PTR_ERR(id->rinfo.pinctrl);
+ if (err != -ENODEV)
+ return err;
+ } else {
+ id->adap.bus_recovery_info = &id->rinfo;
}
id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem);
@@ -1283,7 +1289,6 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->adap.retries = 3; /* Default retry value. */
id->adap.algo_data = id;
id->adap.dev.parent = &pdev->dev;
- id->adap.bus_recovery_info = &id->rinfo;
init_completion(&id->xfer_done);
snprintf(id->adap.name, sizeof(id->adap.name),
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 3082183bd66a..fc70920c4dda 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1132,7 +1132,8 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
int i, result;
unsigned int temp;
int block_data = msgs->flags & I2C_M_RECV_LEN;
- int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data;
+ int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE &&
+ msgs->len >= DMA_THRESHOLD && !block_data;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
@@ -1298,7 +1299,8 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic);
} else {
if (!atomic &&
- i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
+ i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD &&
+ msgs[i].flags & I2C_M_DMA_SAFE)
result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
else
result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c
index 0c365b57d957..83457359ec45 100644
--- a/drivers/i2c/busses/i2c-npcm7xx.c
+++ b/drivers/i2c/busses/i2c-npcm7xx.c
@@ -2393,8 +2393,17 @@ static struct platform_driver npcm_i2c_bus_driver = {
static int __init npcm_i2c_init(void)
{
+ int ret;
+
npcm_i2c_debugfs_dir = debugfs_create_dir("npcm_i2c", NULL);
- return platform_driver_register(&npcm_i2c_bus_driver);
+
+ ret = platform_driver_register(&npcm_i2c_bus_driver);
+ if (ret) {
+ debugfs_remove_recursive(npcm_i2c_debugfs_dir);
+ return ret;
+ }
+
+ return 0;
}
module_init(npcm_i2c_init);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 84a77512614d..8fce98bb77ff 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -626,7 +626,6 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n",
gi2c->cur->flags, gi2c->cur->addr);
gi2c->err = -ETIMEDOUT;
- goto err;
}
if (gi2c->err) {
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 9aa7b9d9a485..13fafb74bab8 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -467,6 +467,7 @@ static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
+ bool do_power_on;
int status;
if (!client)
@@ -545,8 +546,8 @@ static int i2c_device_probe(struct device *dev)
if (status < 0)
goto err_clear_wakeup_irq;
- status = dev_pm_domain_attach(&client->dev,
- !i2c_acpi_waive_d0_probe(dev));
+ do_power_on = !i2c_acpi_waive_d0_probe(dev);
+ status = dev_pm_domain_attach(&client->dev, do_power_on);
if (status)
goto err_clear_wakeup_irq;
@@ -585,7 +586,7 @@ static int i2c_device_probe(struct device *dev)
err_release_driver_resources:
devres_release_group(&client->dev, client->devres_group_id);
err_detach_pm_domain:
- dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
+ dev_pm_domain_detach(&client->dev, do_power_on);
err_clear_wakeup_irq:
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
@@ -610,7 +611,7 @@ static void i2c_device_remove(struct device *dev)
devres_release_group(&client->dev, client->devres_group_id);
- dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
+ dev_pm_domain_detach(&client->dev, true);
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index ad8fce3e08cd..6e4d10a7cd32 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -805,8 +805,10 @@ static int bma400_get_steps_reg(struct bma400_data *data, int *val)
ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
steps_raw, BMA400_STEP_RAW_LEN);
- if (ret)
+ if (ret) {
+ kfree(steps_raw);
return ret;
+ }
*val = get_unaligned_le24(steps_raw);
kfree(steps_raw);
return IIO_VAL_INT;
@@ -869,18 +871,6 @@ static int bma400_init(struct bma400_data *data)
unsigned int val;
int ret;
- /* Try to read chip_id register. It must return 0x90. */
- ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
- if (ret) {
- dev_err(data->dev, "Failed to read chip id register\n");
- return ret;
- }
-
- if (val != BMA400_ID_REG_VAL) {
- dev_err(data->dev, "Chip ID mismatch\n");
- return -ENODEV;
- }
-
data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
ret = devm_regulator_bulk_get(data->dev,
@@ -906,6 +896,18 @@ static int bma400_init(struct bma400_data *data)
if (ret)
return ret;
+ /* Try to read chip_id register. It must return 0x90. */
+ ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
+ if (ret) {
+ dev_err(data->dev, "Failed to read chip id register\n");
+ return ret;
+ }
+
+ if (val != BMA400_ID_REG_VAL) {
+ dev_err(data->dev, "Chip ID mismatch\n");
+ return -ENODEV;
+ }
+
ret = bma400_get_power_mode(data);
if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode\n");
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 9341e0e0eb55..998e8bcc06e1 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -202,6 +202,8 @@ static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
((scu_otp) &
(data->model_data->trim_locate->field)) >>
__ffs(data->model_data->trim_locate->field);
+ if (!trimming_val)
+ trimming_val = 0x8;
}
dev_dbg(data->dev,
"trimming val = %d, offset = %08x, fields = %08x\n",
@@ -563,12 +565,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (of_find_property(data->dev->of_node, "aspeed,trim-data-valid",
- NULL)) {
- ret = aspeed_adc_set_trim_data(indio_dev);
- if (ret)
- return ret;
- }
+ ret = aspeed_adc_set_trim_data(indio_dev);
+ if (ret)
+ return ret;
if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
NULL)) {
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 33e251552214..870f4cb60923 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2307,11 +2307,9 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
clb->p6 = buf[AT91_ADC_TS_CLB_IDX_P6];
/*
- * We prepare here the conversion to milli and also add constant
- * factor (5 degrees Celsius) to p1 here to avoid doing it on
- * hotpath.
+ * We prepare here the conversion to milli to avoid doing it on hotpath.
*/
- clb->p1 = clb->p1 * 1000 + 5000;
+ clb->p1 = clb->p1 * 1000;
free_buf:
kfree(buf);
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 532daaa6f943..366e252ebeb0 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -634,8 +634,10 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
trig->ops = &at91_adc_trigger_ops;
ret = iio_trigger_register(trig);
- if (ret)
+ if (ret) {
+ iio_trigger_free(trig);
return NULL;
+ }
return trig;
}
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 30a31f185d08..88e947f300cf 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -57,7 +57,8 @@ static struct iio_map mp2629_adc_maps[] = {
MP2629_MAP(SYSTEM_VOLT, "system-volt"),
MP2629_MAP(INPUT_VOLT, "input-volt"),
MP2629_MAP(BATT_CURRENT, "batt-current"),
- MP2629_MAP(INPUT_CURRENT, "input-current")
+ MP2629_MAP(INPUT_CURRENT, "input-current"),
+ { }
};
static int mp2629_read_raw(struct iio_dev *indio_dev,
@@ -74,7 +75,7 @@ static int mp2629_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
- if (chan->address == MP2629_INPUT_VOLT)
+ if (chan->channel == MP2629_INPUT_VOLT)
rval &= GENMASK(6, 0);
*val = rval;
return IIO_VAL_INT;
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 3bb4028c5d74..df3bc5c3d378 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -245,14 +245,14 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct afe4403_data *afe = iio_priv(indio_dev);
- unsigned int reg = afe4403_channel_values[chan->address];
- unsigned int field = afe4403_channel_leds[chan->address];
+ unsigned int reg, field;
int ret;
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ reg = afe4403_channel_values[chan->address];
ret = afe4403_read(afe, reg, val);
if (ret)
return ret;
@@ -262,6 +262,7 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ field = afe4403_channel_leds[chan->address];
ret = regmap_field_read(afe->fields[field], val);
if (ret)
return ret;
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 8fca787b2524..836da31b7e30 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -250,20 +250,20 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct afe4404_data *afe = iio_priv(indio_dev);
- unsigned int value_reg = afe4404_channel_values[chan->address];
- unsigned int led_field = afe4404_channel_leds[chan->address];
- unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
+ unsigned int value_reg, led_field, offdac_field;
int ret;
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ value_reg = afe4404_channel_values[chan->address];
ret = regmap_read(afe->regmap, value_reg, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
+ offdac_field = afe4404_channel_offdacs[chan->address];
ret = regmap_field_read(afe->fields[offdac_field], val);
if (ret)
return ret;
@@ -273,6 +273,7 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ led_field = afe4404_channel_leds[chan->address];
ret = regmap_field_read(afe->fields[led_field], val);
if (ret)
return ret;
@@ -295,19 +296,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct afe4404_data *afe = iio_priv(indio_dev);
- unsigned int led_field = afe4404_channel_leds[chan->address];
- unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
+ unsigned int led_field, offdac_field;
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_OFFSET:
+ offdac_field = afe4404_channel_offdacs[chan->address];
return regmap_field_write(afe->fields[offdac_field], val);
}
break;
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ led_field = afe4404_channel_leds[chan->address];
return regmap_field_write(afe->fields[led_field], val);
}
break;
diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c
index 307557a609e3..52744dd98e65 100644
--- a/drivers/iio/imu/bno055/bno055.c
+++ b/drivers/iio/imu/bno055/bno055.c
@@ -632,7 +632,7 @@ static int bno055_set_regmask(struct bno055_priv *priv, int val, int val2,
return -EINVAL;
}
delta = abs(tbl_val - req_val);
- if (delta < best_delta || first) {
+ if (first || delta < best_delta) {
best_delta = delta;
hwval = i;
first = false;
diff --git a/drivers/iio/industrialio-sw-trigger.c b/drivers/iio/industrialio-sw-trigger.c
index 994f03a71520..d86a3305d9e8 100644
--- a/drivers/iio/industrialio-sw-trigger.c
+++ b/drivers/iio/industrialio-sw-trigger.c
@@ -58,8 +58,12 @@ int iio_register_sw_trigger_type(struct iio_sw_trigger_type *t)
t->group = configfs_register_default_group(iio_triggers_group, t->name,
&iio_trigger_type_group_type);
- if (IS_ERR(t->group))
+ if (IS_ERR(t->group)) {
+ mutex_lock(&iio_trigger_types_lock);
+ list_del(&t->list);
+ mutex_unlock(&iio_trigger_types_lock);
ret = PTR_ERR(t->group);
+ }
return ret;
}
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 7cf6e8490123..0d4447df7200 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -293,6 +293,8 @@ config RPR0521
tristate "ROHM RPR0521 ALS and proximity sensor driver"
depends on I2C
select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build support for ROHM's RPR0521
ambient light and proximity sensor device.
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index b62c139baf41..38d4c7644bef 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -54,9 +54,6 @@
#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT 2
#define APDS9960_REG_CONFIG_2 0x90
-#define APDS9960_REG_CONFIG_2_GGAIN_MASK 0x60
-#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT 5
-
#define APDS9960_REG_ID 0x92
#define APDS9960_REG_STATUS 0x93
@@ -77,6 +74,9 @@
#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT 6
#define APDS9960_REG_GCONF_2 0xa3
+#define APDS9960_REG_GCONF_2_GGAIN_MASK 0x60
+#define APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT 5
+
#define APDS9960_REG_GOFFSET_U 0xa4
#define APDS9960_REG_GOFFSET_D 0xa5
#define APDS9960_REG_GPULSE 0xa6
@@ -396,9 +396,9 @@ static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
}
ret = regmap_update_bits(data->regmap,
- APDS9960_REG_CONFIG_2,
- APDS9960_REG_CONFIG_2_GGAIN_MASK,
- idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
+ APDS9960_REG_GCONF_2,
+ APDS9960_REG_GCONF_2_GGAIN_MASK,
+ idx << APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT);
if (!ret)
data->pxs_gain = idx;
mutex_unlock(&data->lock);
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h
index cbc9349c342a..550b75b7186f 100644
--- a/drivers/iio/pressure/ms5611.h
+++ b/drivers/iio/pressure/ms5611.h
@@ -25,13 +25,6 @@ enum {
MS5607,
};
-struct ms5611_chip_info {
- u16 prom[MS5611_PROM_WORDS_NB];
-
- int (*temp_and_pressure_compensate)(struct ms5611_chip_info *chip_info,
- s32 *temp, s32 *pressure);
-};
-
/*
* OverSampling Rate descriptor.
* Warning: cmd MUST be kept aligned on a word boundary (see
@@ -50,12 +43,15 @@ struct ms5611_state {
const struct ms5611_osr *pressure_osr;
const struct ms5611_osr *temp_osr;
+ u16 prom[MS5611_PROM_WORDS_NB];
+
int (*reset)(struct ms5611_state *st);
int (*read_prom_word)(struct ms5611_state *st, int index, u16 *word);
int (*read_adc_temp_and_pressure)(struct ms5611_state *st,
s32 *temp, s32 *pressure);
- struct ms5611_chip_info *chip_info;
+ int (*compensate_temp_and_pressure)(struct ms5611_state *st, s32 *temp,
+ s32 *pressure);
struct regulator *vdd;
};
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index 717521de66c4..c564a1d6cafe 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -85,7 +85,7 @@ static int ms5611_read_prom(struct iio_dev *indio_dev)
struct ms5611_state *st = iio_priv(indio_dev);
for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
- ret = st->read_prom_word(st, i, &st->chip_info->prom[i]);
+ ret = st->read_prom_word(st, i, &st->prom[i]);
if (ret < 0) {
dev_err(&indio_dev->dev,
"failed to read prom at %d\n", i);
@@ -93,7 +93,7 @@ static int ms5611_read_prom(struct iio_dev *indio_dev)
}
}
- if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) {
+ if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
dev_err(&indio_dev->dev, "PROM integrity check failed\n");
return -ENODEV;
}
@@ -114,21 +114,20 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
return ret;
}
- return st->chip_info->temp_and_pressure_compensate(st->chip_info,
- temp, pressure);
+ return st->compensate_temp_and_pressure(st, temp, pressure);
}
-static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
+static int ms5611_temp_and_pressure_compensate(struct ms5611_state *st,
s32 *temp, s32 *pressure)
{
s32 t = *temp, p = *pressure;
s64 off, sens, dt;
- dt = t - (chip_info->prom[5] << 8);
- off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7);
- sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8);
+ dt = t - (st->prom[5] << 8);
+ off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
+ sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
- t = 2000 + ((chip_info->prom[6] * dt) >> 23);
+ t = 2000 + ((st->prom[6] * dt) >> 23);
if (t < 2000) {
s64 off2, sens2, t2;
@@ -154,17 +153,17 @@ static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_inf
return 0;
}
-static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
+static int ms5607_temp_and_pressure_compensate(struct ms5611_state *st,
s32 *temp, s32 *pressure)
{
s32 t = *temp, p = *pressure;
s64 off, sens, dt;
- dt = t - (chip_info->prom[5] << 8);
- off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6);
- sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7);
+ dt = t - (st->prom[5] << 8);
+ off = ((s64)st->prom[2] << 17) + ((st->prom[4] * dt) >> 6);
+ sens = ((s64)st->prom[1] << 16) + ((st->prom[3] * dt) >> 7);
- t = 2000 + ((chip_info->prom[6] * dt) >> 23);
+ t = 2000 + ((st->prom[6] * dt) >> 23);
if (t < 2000) {
s64 off2, sens2, t2, tmp;
@@ -342,15 +341,6 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
static const unsigned long ms5611_scan_masks[] = {0x3, 0};
-static struct ms5611_chip_info chip_info_tbl[] = {
- [MS5611] = {
- .temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
- },
- [MS5607] = {
- .temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate,
- }
-};
-
static const struct iio_chan_spec ms5611_channels[] = {
{
.type = IIO_PRESSURE,
@@ -433,7 +423,20 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
struct ms5611_state *st = iio_priv(indio_dev);
mutex_init(&st->lock);
- st->chip_info = &chip_info_tbl[type];
+
+ switch (type) {
+ case MS5611:
+ st->compensate_temp_and_pressure =
+ ms5611_temp_and_pressure_compensate;
+ break;
+ case MS5607:
+ st->compensate_temp_and_pressure =
+ ms5607_temp_and_pressure_compensate;
+ break;
+ default:
+ return -EINVAL;
+ }
+
st->temp_osr =
&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
st->pressure_osr =
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index 432e912096f4..a0a7205c9c3a 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -91,7 +91,7 @@ static int ms5611_spi_probe(struct spi_device *spi)
spi_set_drvdata(spi, indio_dev);
spi->mode = SPI_MODE_0;
- spi->max_speed_hz = 20000000;
+ spi->max_speed_hz = min(spi->max_speed_hz, 20000000U);
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0)
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index d6c5e9644738..6b05eed41612 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -203,9 +203,13 @@ static int iio_sysfs_trigger_remove(int id)
static int __init iio_sysfs_trig_init(void)
{
+ int ret;
device_initialize(&iio_sysfs_trig_dev);
dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
- return device_add(&iio_sysfs_trig_dev);
+ ret = device_add(&iio_sysfs_trig_dev);
+ if (ret)
+ put_device(&iio_sysfs_trig_dev);
+ return ret;
}
module_init(iio_sysfs_trig_init);
diff --git a/drivers/infiniband/core/cm_trace.h b/drivers/infiniband/core/cm_trace.h
index e9d282679ef1..944d9071245d 100644
--- a/drivers/infiniband/core/cm_trace.h
+++ b/drivers/infiniband/core/cm_trace.h
@@ -16,7 +16,7 @@
#include <linux/tracepoint.h>
#include <rdma/ib_cm.h>
-#include <trace/events/rdma.h>
+#include <trace/misc/rdma.h>
/*
* enum ib_cm_state, from include/rdma/ib_cm.h
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 26d1772179b8..aacd6254df77 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3807,7 +3807,7 @@ static int cma_alloc_any_port(enum rdma_ucm_port_space ps,
inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1;
- rover = prandom_u32_max(remaining) + low;
+ rover = get_random_u32_inclusive(low, remaining + low - 1);
retry:
if (last_used_port != rover) {
struct rdma_bind_list *bind_list;
diff --git a/drivers/infiniband/core/cma_trace.h b/drivers/infiniband/core/cma_trace.h
index e45264267bcc..47f3c6e4be89 100644
--- a/drivers/infiniband/core/cma_trace.h
+++ b/drivers/infiniband/core/cma_trace.h
@@ -15,7 +15,7 @@
#define _TRACE_RDMA_CMA_H
#include <linux/tracepoint.h>
-#include <trace/events/rdma.h>
+#include <trace/misc/rdma.h>
DECLARE_EVENT_CLASS(cma_fsm_class,
diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
index 04c04e6d24c3..43b26bc12288 100644
--- a/drivers/infiniband/core/umem_dmabuf.c
+++ b/drivers/infiniband/core/umem_dmabuf.c
@@ -26,7 +26,8 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
if (umem_dmabuf->sgt)
goto wait_fence;
- sgt = dma_buf_map_attachment(umem_dmabuf->attach, DMA_BIDIRECTIONAL);
+ sgt = dma_buf_map_attachment_unlocked(umem_dmabuf->attach,
+ DMA_BIDIRECTIONAL);
if (IS_ERR(sgt))
return PTR_ERR(sgt);
@@ -102,8 +103,8 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf)
umem_dmabuf->last_sg_trim = 0;
}
- dma_buf_unmap_attachment(umem_dmabuf->attach, umem_dmabuf->sgt,
- DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(umem_dmabuf->attach, umem_dmabuf->sgt,
+ DMA_BIDIRECTIONAL);
umem_dmabuf->sgt = NULL;
}
diff --git a/drivers/infiniband/hw/cxgb4/id_table.c b/drivers/infiniband/hw/cxgb4/id_table.c
index 280d61466855..e2188b335e76 100644
--- a/drivers/infiniband/hw/cxgb4/id_table.c
+++ b/drivers/infiniband/hw/cxgb4/id_table.c
@@ -54,7 +54,7 @@ u32 c4iw_id_alloc(struct c4iw_id_table *alloc)
if (obj < alloc->max) {
if (alloc->flags & C4IW_ID_TABLE_F_RANDOM)
- alloc->last += prandom_u32_max(RANDOM_SKIP);
+ alloc->last += get_random_u32_below(RANDOM_SKIP);
else
alloc->last = obj + 1;
if (alloc->last >= alloc->max)
@@ -85,7 +85,7 @@ int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,
alloc->start = start;
alloc->flags = flags;
if (flags & C4IW_ID_TABLE_F_RANDOM)
- alloc->last = prandom_u32_max(RANDOM_SKIP);
+ alloc->last = get_random_u32_below(RANDOM_SKIP);
else
alloc->last = 0;
alloc->max = num;
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index 436372b31431..24c0f0d257fc 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -1761,17 +1761,11 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
unsigned amt;
if (!rcd->rcvhdrq) {
- gfp_t gfp_flags;
-
amt = rcvhdrq_size(rcd);
- if (rcd->ctxt < dd->first_dyn_alloc_ctxt || rcd->is_vnic)
- gfp_flags = GFP_KERNEL;
- else
- gfp_flags = GFP_USER;
rcd->rcvhdrq = dma_alloc_coherent(&dd->pcidev->dev, amt,
&rcd->rcvhdrq_dma,
- gfp_flags | __GFP_COMP);
+ GFP_KERNEL);
if (!rcd->rcvhdrq) {
dd_dev_err(dd,
@@ -1785,7 +1779,7 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(&dd->pcidev->dev,
PAGE_SIZE,
&rcd->rcvhdrqtailaddr_dma,
- gfp_flags);
+ GFP_KERNEL);
if (!rcd->rcvhdrtail_kvaddr)
goto bail_free;
}
@@ -1821,20 +1815,11 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
{
struct hfi1_devdata *dd = rcd->dd;
u32 max_entries, egrtop, alloced_bytes = 0;
- gfp_t gfp_flags;
u16 order, idx = 0;
int ret = 0;
u16 round_mtu = roundup_pow_of_two(hfi1_max_mtu);
/*
- * GFP_USER, but without GFP_FS, so buffer cache can be
- * coalesced (we hope); otherwise, even at order 4,
- * heavy filesystem activity makes these fail, and we can
- * use compound pages.
- */
- gfp_flags = __GFP_RECLAIM | __GFP_IO | __GFP_COMP;
-
- /*
* The minimum size of the eager buffers is a groups of MTU-sized
* buffers.
* The global eager_buffer_size parameter is checked against the
@@ -1864,7 +1849,7 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
dma_alloc_coherent(&dd->pcidev->dev,
rcd->egrbufs.rcvtid_size,
&rcd->egrbufs.buffers[idx].dma,
- gfp_flags);
+ GFP_KERNEL);
if (rcd->egrbufs.buffers[idx].addr) {
rcd->egrbufs.buffers[idx].len =
rcd->egrbufs.rcvtid_size;
diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c
index 480c062dd04f..e77fcc74f15c 100644
--- a/drivers/infiniband/hw/hns/hns_roce_ah.c
+++ b/drivers/infiniband/hw/hns/hns_roce_ah.c
@@ -41,9 +41,8 @@ static inline u16 get_ah_udp_sport(const struct rdma_ah_attr *ah_attr)
u16 sport;
if (!fl)
- sport = prandom_u32_max(IB_ROCE_UDP_ENCAP_VALID_PORT_MAX + 1 -
- IB_ROCE_UDP_ENCAP_VALID_PORT_MIN) +
- IB_ROCE_UDP_ENCAP_VALID_PORT_MIN;
+ sport = get_random_u32_inclusive(IB_ROCE_UDP_ENCAP_VALID_PORT_MIN,
+ IB_ROCE_UDP_ENCAP_VALID_PORT_MAX);
else
sport = rdma_flow_label_to_udp_sport(fl);
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index aea571943768..07386117f21a 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -2075,7 +2075,7 @@ static void alloc_dummy_hdrq(struct qib_devdata *dd)
dd->cspec->dummy_hdrq = dma_alloc_coherent(&dd->pcidev->dev,
dd->rcd[0]->rcvhdrq_size,
&dd->cspec->dummy_hdrq_phys,
- GFP_ATOMIC | __GFP_COMP);
+ GFP_ATOMIC);
if (!dd->cspec->dummy_hdrq) {
qib_devinfo(dd->pcidev, "Couldn't allocate dummy hdrq\n");
/* fallback to just 0'ing */
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 45211008449f..33667becd52b 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -1546,18 +1546,14 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
if (!rcd->rcvhdrq) {
dma_addr_t phys_hdrqtail;
- gfp_t gfp_flags;
amt = ALIGN(dd->rcvhdrcnt * dd->rcvhdrentsize *
sizeof(u32), PAGE_SIZE);
- gfp_flags = (rcd->ctxt >= dd->first_user_ctxt) ?
- GFP_USER : GFP_KERNEL;
old_node_id = dev_to_node(&dd->pcidev->dev);
set_dev_node(&dd->pcidev->dev, rcd->node_id);
- rcd->rcvhdrq = dma_alloc_coherent(
- &dd->pcidev->dev, amt, &rcd->rcvhdrq_phys,
- gfp_flags | __GFP_COMP);
+ rcd->rcvhdrq = dma_alloc_coherent(&dd->pcidev->dev, amt,
+ &rcd->rcvhdrq_phys, GFP_KERNEL);
set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvhdrq) {
@@ -1577,7 +1573,7 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
set_dev_node(&dd->pcidev->dev, rcd->node_id);
rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(
&dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail,
- gfp_flags);
+ GFP_KERNEL);
set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvhdrtail_kvaddr)
goto bail_free;
@@ -1621,17 +1617,8 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
struct qib_devdata *dd = rcd->dd;
unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
size_t size;
- gfp_t gfp_flags;
int old_node_id;
- /*
- * GFP_USER, but without GFP_FS, so buffer cache can be
- * coalesced (we hope); otherwise, even at order 4,
- * heavy filesystem activity makes these fail, and we can
- * use compound pages.
- */
- gfp_flags = __GFP_RECLAIM | __GFP_IO | __GFP_COMP;
-
egrcnt = rcd->rcvegrcnt;
egroff = rcd->rcvegr_tid_base;
egrsize = dd->rcvegrbufsize;
@@ -1663,7 +1650,7 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
rcd->rcvegrbuf[e] =
dma_alloc_coherent(&dd->pcidev->dev, size,
&rcd->rcvegrbuf_phys[e],
- gfp_flags);
+ GFP_KERNEL);
set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvegrbuf[e])
goto bail_rcvegrbuf_phys;
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index 8546b8816524..205fd44a4727 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -966,7 +966,7 @@ static void rtrs_clt_init_req(struct rtrs_clt_io_req *req,
refcount_set(&req->ref, 1);
req->mp_policy = clt_path->clt->mp_policy;
- iov_iter_kvec(&iter, READ, vec, 1, usr_len);
+ iov_iter_kvec(&iter, ITER_SOURCE, vec, 1, usr_len);
len = _copy_from_iter(req->iu->buf, usr_len, &iter);
WARN_ON(len != usr_len);
@@ -1517,7 +1517,7 @@ static void rtrs_clt_err_recovery_work(struct work_struct *work)
rtrs_clt_stop_and_destroy_conns(clt_path);
queue_delayed_work(rtrs_wq, &clt_path->reconnect_dwork,
msecs_to_jiffies(delay_ms +
- prandom_u32_max(RTRS_RECONNECT_SEED)));
+ get_random_u32_below(RTRS_RECONNECT_SEED)));
}
static struct rtrs_clt_path *alloc_path(struct rtrs_clt_sess *clt,
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index b86de1312512..84b87526b7ba 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -273,22 +273,22 @@ int iforce_init_device(struct device *parent, u16 bustype,
* Get device info.
*/
- if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
+ if (!iforce_get_id_packet(iforce, 'M', buf, &len) && len >= 3)
input_dev->id.vendor = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
- if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
+ if (!iforce_get_id_packet(iforce, 'P', buf, &len) && len >= 3)
input_dev->id.product = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
- if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
+ if (!iforce_get_id_packet(iforce, 'B', buf, &len) && len >= 3)
iforce->device_memory.end = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
- if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
+ if (!iforce_get_id_packet(iforce, 'N', buf, &len) && len >= 2)
ff_effects = buf[1];
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 0e77c40e1966..3c9bbd04e143 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -106,7 +106,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
return err;
}
-static int atlas_acpi_button_remove(struct acpi_device *device)
+static void atlas_acpi_button_remove(struct acpi_device *device)
{
acpi_status status;
@@ -116,8 +116,6 @@ static int atlas_acpi_button_remove(struct acpi_device *device)
pr_err("error removing addr spc handler\n");
input_unregister_device(input_dev);
-
- return 0;
}
static const struct acpi_device_id atlas_device_ids[] = {
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 480476121c01..09489380afda 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -18,6 +18,10 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
+static bool use_low_level_irq;
+module_param(use_low_level_irq, bool, 0444);
+MODULE_PARM_DESC(use_low_level_irq, "Use low-level triggered IRQ instead of edge triggered");
+
struct soc_button_info {
const char *name;
int acpi_index;
@@ -74,6 +78,13 @@ static const struct dmi_system_id dmi_use_low_level_irq[] = {
},
},
{
+ /* Acer Switch V 10 SW5-017, same issue as Acer Switch 10 SW5-012. */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
+ },
+ },
+ {
/*
* Acer One S1003. _LID method messes with power-button GPIO
* IRQ settings, leading to a non working power-button.
@@ -164,7 +175,8 @@ soc_button_device_create(struct platform_device *pdev,
}
/* See dmi_use_low_level_irq[] comment */
- if (!autorepeat && dmi_check_system(dmi_use_low_level_irq)) {
+ if (!autorepeat && (use_low_level_irq ||
+ dmi_check_system(dmi_use_low_level_irq))) {
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
gpio_keys[n_buttons].irq = irq;
gpio_keys[n_buttons].gpio = -ENOENT;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index fa021af8506e..b0f776448a1c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -192,6 +192,7 @@ static const char * const smbus_pnp_ids[] = {
"SYN3221", /* HP 15-ay000 */
"SYN323d", /* HP Spectre X360 13-w013dx */
"SYN3257", /* HP Envy 13-ad105ng */
+ "SYN3286", /* HP Laptop 15-da3001TU */
NULL
};
diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
index 0778dc03cd9e..46f8a694291e 100644
--- a/drivers/input/serio/i8042-acpipnpio.h
+++ b/drivers/input/serio/i8042-acpipnpio.h
@@ -115,18 +115,18 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_NEVER)
},
{
- /* ASUS ZenBook UX425UA */
+ /* ASUS ZenBook UX425UA/QA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425"),
},
.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
},
{
- /* ASUS ZenBook UM325UA */
+ /* ASUS ZenBook UM325UA/QA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325"),
},
.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
},
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index f9486495baef..6dac7c1853a5 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1543,8 +1543,6 @@ static int i8042_probe(struct platform_device *dev)
{
int error;
- i8042_platform_device = dev;
-
if (i8042_reset == I8042_RESET_ALWAYS) {
error = i8042_controller_selftest();
if (error)
@@ -1582,7 +1580,6 @@ static int i8042_probe(struct platform_device *dev)
i8042_free_aux_ports(); /* in case KBD failed but AUX not */
i8042_free_irqs();
i8042_controller_reset(false);
- i8042_platform_device = NULL;
return error;
}
@@ -1592,7 +1589,6 @@ static int i8042_remove(struct platform_device *dev)
i8042_unregister_ports();
i8042_free_irqs();
i8042_controller_reset(false);
- i8042_platform_device = NULL;
return 0;
}
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index a33cc7950cf5..c281e49826c2 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1158,6 +1158,7 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+retry_read_config:
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
@@ -1165,6 +1166,16 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
+ if (!ts->reset_controller_at_probe &&
+ ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
+ dev_info(&ts->client->dev, "Config not set, resetting controller\n");
+ /* Retry after a controller reset */
+ ts->reset_controller_at_probe = true;
+ error = goodix_reset(ts);
+ if (error)
+ return error;
+ goto retry_read_config;
+ }
dev_err(&ts->client->dev,
"Invalid config (%d, %d, %d), using defaults\n",
ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index 3a4952935366..3d9c5758d8a4 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -211,12 +211,14 @@ static int raydium_i2c_send(struct i2c_client *client,
error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer));
if (likely(!error))
- return 0;
+ goto out;
msleep(RM_RETRY_DELAY_MS);
} while (++tries < RM_MAX_RETRIES);
dev_err(&client->dev, "%s failed: %d\n", __func__, error);
+out:
+ kfree(tx_buf);
return error;
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dc5f7a156ff5..453da65262af 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -389,7 +389,7 @@ config ARM_SMMU_V3
depends on ARM64
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
help
Support for implementations of the ARM System MMU architecture
version 3 providing translation support to a PCIe root complex.
@@ -474,13 +474,13 @@ config QCOM_IOMMU
Support for IOMMU on certain Qualcomm SoCs.
config HYPERV_IOMMU
- bool "Hyper-V x2APIC IRQ Handling"
+ bool "Hyper-V IRQ Handling"
depends on HYPERV && X86
select IOMMU_API
default HYPERV
help
- Stub IOMMU driver to handle IRQs as to allow Hyper-V Linux
- guests to run with x2APIC mode enabled.
+ Stub IOMMU driver to handle IRQs to support Hyper-V Linux
+ guest and root partitions.
config VIRTIO_IOMMU
tristate "Virtio IOMMU driver"
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 1d0a70c85333..3d684190b4d5 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -734,7 +734,6 @@ struct amd_iommu {
u8 max_counters;
#ifdef CONFIG_IRQ_REMAP
struct irq_domain *ir_domain;
- struct irq_domain *msi_domain;
struct amd_irte_ops *irte_ops;
#endif
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index d3b39d0416fa..4d28967f910d 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -812,10 +812,10 @@ static void
amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu)
{
if (!irq_remapping_enabled || !dev_is_pci(dev) ||
- pci_dev_has_special_msi_domain(to_pci_dev(dev)))
+ !pci_dev_has_default_msi_parent_domain(to_pci_dev(dev)))
return;
- dev_set_msi_domain(dev, iommu->msi_domain);
+ dev_set_msi_domain(dev, iommu->ir_domain);
}
#else /* CONFIG_IRQ_REMAP */
@@ -3294,17 +3294,9 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
if (!info)
return -EINVAL;
- if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI &&
- info->type != X86_IRQ_ALLOC_TYPE_PCI_MSIX)
+ if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI)
return -EINVAL;
- /*
- * With IRQ remapping enabled, don't need contiguous CPU vectors
- * to support multiple MSI interrupts.
- */
- if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
- info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
-
sbdf = get_devid(info);
if (sbdf < 0)
return -EINVAL;
@@ -3656,6 +3648,21 @@ static struct irq_chip amd_ir_chip = {
.irq_compose_msi_msg = ir_compose_msi_msg,
};
+static const struct msi_parent_ops amdvi_msi_parent_ops = {
+ .supported_flags = X86_VECTOR_MSI_FLAGS_SUPPORTED |
+ MSI_FLAG_MULTI_PCI_MSI |
+ MSI_FLAG_PCI_IMS,
+ .prefix = "IR-",
+ .init_dev_msi_info = msi_parent_init_dev_msi_info,
+};
+
+static const struct msi_parent_ops virt_amdvi_msi_parent_ops = {
+ .supported_flags = X86_VECTOR_MSI_FLAGS_SUPPORTED |
+ MSI_FLAG_MULTI_PCI_MSI,
+ .prefix = "vIR-",
+ .init_dev_msi_info = msi_parent_init_dev_msi_info,
+};
+
int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
{
struct fwnode_handle *fn;
@@ -3663,16 +3670,21 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
fn = irq_domain_alloc_named_id_fwnode("AMD-IR", iommu->index);
if (!fn)
return -ENOMEM;
- iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, iommu);
+ iommu->ir_domain = irq_domain_create_hierarchy(arch_get_ir_parent_domain(), 0, 0,
+ fn, &amd_ir_domain_ops, iommu);
if (!iommu->ir_domain) {
irq_domain_free_fwnode(fn);
return -ENOMEM;
}
- iommu->ir_domain->parent = arch_get_ir_parent_domain();
- iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
- "AMD-IR-MSI",
- iommu->index);
+ irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_AMDVI);
+ iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+
+ if (amd_iommu_np_cache)
+ iommu->ir_domain->msi_parent_ops = &virt_amdvi_msi_parent_ops;
+ else
+ iommu->ir_domain->msi_parent_ops = &amdvi_msi_parent_ops;
+
return 0;
}
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 9297b741f5e8..f798c44e0903 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -744,9 +744,6 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
/* IOMMU can map any pages, so himem can also be used here */
gfp |= __GFP_NOWARN | __GFP_HIGHMEM;
- /* It makes no sense to muck about with huge pages */
- gfp &= ~__GFP_COMP;
-
while (count) {
struct page *page = NULL;
unsigned int order_size;
diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c
index e190bb8c225c..8302db7f783e 100644
--- a/drivers/iommu/hyperv-iommu.c
+++ b/drivers/iommu/hyperv-iommu.c
@@ -122,9 +122,12 @@ static int __init hyperv_prepare_irq_remapping(void)
const char *name;
const struct irq_domain_ops *ops;
+ /*
+ * For a Hyper-V root partition, ms_hyperv_msi_ext_dest_id()
+ * will always return false.
+ */
if (!hypervisor_is_type(X86_HYPER_MS_HYPERV) ||
- x86_init.hyper.msi_ext_dest_id() ||
- !x2apic_supported())
+ x86_init.hyper.msi_ext_dest_id())
return -ENODEV;
if (hv_root_partition) {
@@ -170,7 +173,9 @@ static int __init hyperv_prepare_irq_remapping(void)
static int __init hyperv_enable_irq_remapping(void)
{
- return IRQ_REMAP_X2APIC_MODE;
+ if (x2apic_supported())
+ return IRQ_REMAP_X2APIC_MODE;
+ return IRQ_REMAP_XAPIC_MODE;
}
struct irq_remap_ops hyperv_irq_remap_ops = {
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 5a8f780e7ffd..bc94059a5b87 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -820,6 +820,7 @@ int __init dmar_dev_scope_init(void)
info = dmar_alloc_pci_notify_info(dev,
BUS_NOTIFY_ADD_DEVICE);
if (!info) {
+ pci_dev_put(dev);
return dmar_dev_scope_status;
} else {
dmar_pci_bus_add_dev(info);
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 48cdcd0a5cf3..644ca49e8cf8 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -959,11 +959,9 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
- if (domain_use_first_level(domain)) {
- pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US;
- if (iommu_is_dma_domain(&domain->domain))
- pteval |= DMA_FL_PTE_ACCESS;
- }
+ if (domain_use_first_level(domain))
+ pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
+
if (cmpxchg64(&pte->val, 0ULL, pteval))
/* Someone else set it while we were thinking; use theirs. */
free_pgtable_page(tmp_page);
@@ -1398,6 +1396,24 @@ static void domain_update_iotlb(struct dmar_domain *domain)
spin_unlock_irqrestore(&domain->lock, flags);
}
+/*
+ * The extra devTLB flush quirk impacts those QAT devices with PCI device
+ * IDs ranging from 0x4940 to 0x4943. It is exempted from risky_device()
+ * check because it applies only to the built-in QAT devices and it doesn't
+ * grant additional privileges.
+ */
+#define BUGGY_QAT_DEVID_MASK 0x4940
+static bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev)
+{
+ if (pdev->vendor != PCI_VENDOR_ID_INTEL)
+ return false;
+
+ if ((pdev->device & 0xfffc) != BUGGY_QAT_DEVID_MASK)
+ return false;
+
+ return true;
+}
+
static void iommu_enable_pci_caps(struct device_domain_info *info)
{
struct pci_dev *pdev;
@@ -1480,6 +1496,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
qdep = info->ats_qdep;
qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
qdep, addr, mask);
+ quirk_extra_dev_tlb_flush(info, addr, mask, PASID_RID2PASID, qdep);
}
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
@@ -3856,8 +3873,10 @@ static inline bool has_external_pci(void)
struct pci_dev *pdev = NULL;
for_each_pci_dev(pdev)
- if (pdev->external_facing)
+ if (pdev->external_facing) {
+ pci_dev_put(pdev);
return true;
+ }
return false;
}
@@ -4492,9 +4511,10 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
if (dev_is_pci(dev)) {
if (ecap_dev_iotlb_support(iommu->ecap) &&
pci_ats_supported(pdev) &&
- dmar_ats_supported(pdev, iommu))
+ dmar_ats_supported(pdev, iommu)) {
info->ats_supported = 1;
-
+ info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev);
+ }
if (sm_supported(iommu)) {
if (pasid_supported(iommu)) {
int features = pci_pasid_features(pdev);
@@ -4933,3 +4953,48 @@ static void __init check_tylersburg_isoch(void)
pr_warn("Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
vtisochctrl);
}
+
+/*
+ * Here we deal with a device TLB defect where device may inadvertently issue ATS
+ * invalidation completion before posted writes initiated with translated address
+ * that utilized translations matching the invalidation address range, violating
+ * the invalidation completion ordering.
+ * Therefore, any use cases that cannot guarantee DMA is stopped before unmap is
+ * vulnerable to this defect. In other words, any dTLB invalidation initiated not
+ * under the control of the trusted/privileged host device driver must use this
+ * quirk.
+ * Device TLBs are invalidated under the following six conditions:
+ * 1. Device driver does DMA API unmap IOVA
+ * 2. Device driver unbind a PASID from a process, sva_unbind_device()
+ * 3. PASID is torn down, after PASID cache is flushed. e.g. process
+ * exit_mmap() due to crash
+ * 4. Under SVA usage, called by mmu_notifier.invalidate_range() where
+ * VM has to free pages that were unmapped
+ * 5. Userspace driver unmaps a DMA buffer
+ * 6. Cache invalidation in vSVA usage (upcoming)
+ *
+ * For #1 and #2, device drivers are responsible for stopping DMA traffic
+ * before unmap/unbind. For #3, iommu driver gets mmu_notifier to
+ * invalidate TLB the same way as normal user unmap which will use this quirk.
+ * The dTLB invalidation after PASID cache flush does not need this quirk.
+ *
+ * As a reminder, #6 will *NEED* this quirk as we enable nested translation.
+ */
+void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
+ unsigned long address, unsigned long mask,
+ u32 pasid, u16 qdep)
+{
+ u16 sid;
+
+ if (likely(!info->dtlb_extra_inval))
+ return;
+
+ sid = PCI_DEVID(info->bus, info->devfn);
+ if (pasid == PASID_RID2PASID) {
+ qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+ qdep, address, mask);
+ } else {
+ qi_flush_dev_iotlb_pasid(info->iommu, sid, info->pfsid,
+ pasid, qdep, address, mask);
+ }
+}
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 92023dff9513..b3d82d7093e6 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -600,7 +600,6 @@ struct intel_iommu {
#ifdef CONFIG_IRQ_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
struct irq_domain *ir_domain;
- struct irq_domain *ir_msi_domain;
#endif
struct iommu_device iommu; /* IOMMU core code handle */
int node;
@@ -623,6 +622,7 @@ struct device_domain_info {
u8 pri_enabled:1;
u8 ats_supported:1;
u8 ats_enabled:1;
+ u8 dtlb_extra_inval:1; /* Quirk for devices need extra flush */
u8 ats_qdep;
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
struct intel_iommu *iommu; /* IOMMU used by this device */
@@ -728,6 +728,9 @@ void qi_flush_piotlb(struct intel_iommu *iommu, u16 did, u32 pasid, u64 addr,
void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
u32 pasid, u16 qdep, u64 addr,
unsigned int size_order);
+void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
+ unsigned long address, unsigned long pages,
+ u32 pasid, u16 qdep);
void qi_flush_pasid_cache(struct intel_iommu *iommu, u16 did, u64 granu,
u32 pasid);
diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c
index 5962bb5027d0..a723f53ba472 100644
--- a/drivers/iommu/intel/irq_remapping.c
+++ b/drivers/iommu/intel/irq_remapping.c
@@ -82,6 +82,7 @@ static const struct irq_domain_ops intel_ir_domain_ops;
static void iommu_disable_irq_remapping(struct intel_iommu *iommu);
static int __init parse_ioapics_under_ir(void);
+static const struct msi_parent_ops dmar_msi_parent_ops, virt_dmar_msi_parent_ops;
static bool ir_pre_enabled(struct intel_iommu *iommu)
{
@@ -230,7 +231,7 @@ static struct irq_domain *map_dev_to_ir(struct pci_dev *dev)
{
struct dmar_drhd_unit *drhd = dmar_find_matched_drhd_unit(dev);
- return drhd ? drhd->iommu->ir_msi_domain : NULL;
+ return drhd ? drhd->iommu->ir_domain : NULL;
}
static int clear_entries(struct irq_2_iommu *irq_iommu)
@@ -573,10 +574,14 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
goto out_free_fwnode;
}
- iommu->ir_msi_domain =
- arch_create_remap_msi_irq_domain(iommu->ir_domain,
- "INTEL-IR-MSI",
- iommu->seq_id);
+
+ irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_DMAR);
+ iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+
+ if (cap_caching_mode(iommu->cap))
+ iommu->ir_domain->msi_parent_ops = &virt_dmar_msi_parent_ops;
+ else
+ iommu->ir_domain->msi_parent_ops = &dmar_msi_parent_ops;
ir_table->base = page_address(pages);
ir_table->bitmap = bitmap;
@@ -620,9 +625,6 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
return 0;
out_free_ir_domain:
- if (iommu->ir_msi_domain)
- irq_domain_remove(iommu->ir_msi_domain);
- iommu->ir_msi_domain = NULL;
irq_domain_remove(iommu->ir_domain);
iommu->ir_domain = NULL;
out_free_fwnode:
@@ -644,13 +646,6 @@ static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
struct fwnode_handle *fn;
if (iommu && iommu->ir_table) {
- if (iommu->ir_msi_domain) {
- fn = iommu->ir_msi_domain->fwnode;
-
- irq_domain_remove(iommu->ir_msi_domain);
- irq_domain_free_fwnode(fn);
- iommu->ir_msi_domain = NULL;
- }
if (iommu->ir_domain) {
fn = iommu->ir_domain->fwnode;
@@ -1107,7 +1102,7 @@ error:
*/
void intel_irq_remap_add_device(struct dmar_pci_notify_info *info)
{
- if (!irq_remapping_enabled || pci_dev_has_special_msi_domain(info->dev))
+ if (!irq_remapping_enabled || !pci_dev_has_default_msi_parent_domain(info->dev))
return;
dev_set_msi_domain(&info->dev->dev, map_dev_to_ir(info->dev));
@@ -1334,17 +1329,9 @@ static int intel_irq_remapping_alloc(struct irq_domain *domain,
if (!info || !iommu)
return -EINVAL;
- if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI &&
- info->type != X86_IRQ_ALLOC_TYPE_PCI_MSIX)
+ if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI)
return -EINVAL;
- /*
- * With IRQ remapping enabled, don't need contiguous CPU vectors
- * to support multiple MSI interrupts.
- */
- if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
- info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
-
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
if (ret < 0)
return ret;
@@ -1445,6 +1432,21 @@ static const struct irq_domain_ops intel_ir_domain_ops = {
.deactivate = intel_irq_remapping_deactivate,
};
+static const struct msi_parent_ops dmar_msi_parent_ops = {
+ .supported_flags = X86_VECTOR_MSI_FLAGS_SUPPORTED |
+ MSI_FLAG_MULTI_PCI_MSI |
+ MSI_FLAG_PCI_IMS,
+ .prefix = "IR-",
+ .init_dev_msi_info = msi_parent_init_dev_msi_info,
+};
+
+static const struct msi_parent_ops virt_dmar_msi_parent_ops = {
+ .supported_flags = X86_VECTOR_MSI_FLAGS_SUPPORTED |
+ MSI_FLAG_MULTI_PCI_MSI,
+ .prefix = "vIR-",
+ .init_dev_msi_info = msi_parent_init_dev_msi_info,
+};
+
/*
* Support of Interrupt Remapping Unit Hotplug
*/
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
index c30ddac40ee5..e13d7e5273e1 100644
--- a/drivers/iommu/intel/pasid.c
+++ b/drivers/iommu/intel/pasid.c
@@ -642,7 +642,7 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu,
* Since it is a second level only translation setup, we should
* set SRE bit as well (addresses are expected to be GPAs).
*/
- if (pasid != PASID_RID2PASID)
+ if (pasid != PASID_RID2PASID && ecap_srs(iommu->ecap))
pasid_set_sre(pte);
pasid_set_present(pte);
spin_unlock(&iommu->lock);
@@ -685,7 +685,8 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
* We should set SRE bit as well since the addresses are expected
* to be GPAs.
*/
- pasid_set_sre(pte);
+ if (ecap_srs(iommu->ecap))
+ pasid_set_sre(pte);
pasid_set_present(pte);
spin_unlock(&iommu->lock);
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 7d08eb034f2d..03b25358946c 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -184,10 +184,13 @@ static void __flush_svm_range_dev(struct intel_svm *svm,
return;
qi_flush_piotlb(sdev->iommu, sdev->did, svm->pasid, address, pages, ih);
- if (info->ats_enabled)
+ if (info->ats_enabled) {
qi_flush_dev_iotlb_pasid(sdev->iommu, sdev->sid, info->pfsid,
svm->pasid, sdev->qdep, address,
order_base_2(pages));
+ quirk_extra_dev_tlb_flush(info, address, order_base_2(pages),
+ svm->pasid, sdev->qdep);
+ }
}
static void intel_flush_svm_range_dev(struct intel_svm *svm,
@@ -745,12 +748,16 @@ bad_req:
* If prq is to be handled outside iommu driver via receiver of
* the fault notifiers, we skip the page response here.
*/
- if (!pdev || intel_svm_prq_report(iommu, &pdev->dev, req))
- handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
+ if (!pdev)
+ goto bad_req;
- trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1,
- req->priv_data[0], req->priv_data[1],
- iommu->prq_seq_number++);
+ if (intel_svm_prq_report(iommu, &pdev->dev, req))
+ handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
+ else
+ trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1,
+ req->priv_data[0], req->priv_data[1],
+ iommu->prq_seq_number++);
+ pci_dev_put(pdev);
prq_advance:
head = (head + sizeof(*req)) & PRQ_RING_MASK;
}
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5696314ae69e..00d98f08732f 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -9,7 +9,6 @@
#include <linux/iommu.h>
#include <linux/limits.h>
#include <linux/module.h>
-#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_iommu.h>
#include <linux/of_pci.h>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7ef9f5e696d3..d07568a2c539 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -38,7 +38,7 @@ config ARM_GIC_V3
config ARM_GIC_V3_ITS
bool
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
default ARM_GIC_V3
config ARM_GIC_V3_ITS_PCI
@@ -86,7 +86,7 @@ config ALPINE_MSI
config AL_FIC
bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
- depends on OF || COMPILE_TEST
+ depends on OF
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
help
@@ -375,7 +375,7 @@ config MVEBU_ICU
config MVEBU_ODMI
bool
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
config MVEBU_PIC
bool
@@ -488,7 +488,7 @@ config IMX_MU_MSI
default m if ARCH_MXC
select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
help
Provide a driver for the i.MX Messaging Unit block used as a
CPU-to-CPU MSI controller. This requires a specially crafted DT
@@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+ select LOONGSON_HTVEC
select LOONGSON_LIOINTC
select LOONGSON_EIOINTC
select LOONGSON_PCH_PIC
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index 1c2813ad8bbe..ae3437f03e6c 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -248,14 +248,14 @@ struct aic_info {
bool fast_ipi;
};
-static const struct aic_info aic1_info = {
+static const struct aic_info aic1_info __initconst = {
.version = 1,
.event = AIC_EVENT,
.target_cpu = AIC_TARGET_CPU,
};
-static const struct aic_info aic1_fipi_info = {
+static const struct aic_info aic1_fipi_info __initconst = {
.version = 1,
.event = AIC_EVENT,
@@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = {
.fast_ipi = true,
};
-static const struct aic_info aic2_info = {
+static const struct aic_info aic2_info __initconst = {
.version = 2,
.irq_cfg = AIC2_IRQ_CFG,
diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c
index b60e1853593f..3989d16f997b 100644
--- a/drivers/irqchip/irq-gic-pm.c
+++ b/drivers/irqchip/irq-gic-pm.c
@@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
goto rpm_disable;
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 6e1ac330d7a6..f4d7eeb13951 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/arm-gic-common.h>
/*
* MSI_TYPER:
@@ -262,7 +263,7 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
.chip = &gicv2m_pmsi_irq_chip,
};
-static void gicv2m_teardown(void)
+static void __init gicv2m_teardown(void)
{
struct v2m_data *v2m, *tmp;
@@ -277,7 +278,7 @@ static void gicv2m_teardown(void)
}
}
-static int gicv2m_allocate_domains(struct irq_domain *parent)
+static __init int gicv2m_allocate_domains(struct irq_domain *parent)
{
struct irq_domain *inner_domain, *pci_domain, *plat_domain;
struct v2m_data *v2m;
@@ -404,7 +405,7 @@ err_free_v2m:
return ret;
}
-static const struct of_device_id gicv2m_device_id[] = {
+static __initconst struct of_device_id gicv2m_device_id[] = {
{ .compatible = "arm,gic-v2m-frame", },
{},
};
@@ -454,7 +455,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
#ifdef CONFIG_ACPI
static int acpi_num_msi;
-static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
{
struct v2m_data *data;
@@ -469,7 +470,7 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
return data->fwnode;
}
-static bool acpi_check_amazon_graviton_quirks(void)
+static __init bool acpi_check_amazon_graviton_quirks(void)
{
static struct acpi_table_madt *madt;
acpi_status status;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 34d58567b78d..997104d4338e 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
+#include <linux/kstrtox.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -1171,7 +1172,7 @@ static bool gicv3_nolpi;
static int __init gicv3_nolpi_cfg(char *buf)
{
- return strtobool(buf, &gicv3_nolpi);
+ return kstrtobool(buf, &gicv3_nolpi);
}
early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4c7bae0ec8f9..210bc2f4d555 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -19,6 +19,7 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/list.h>
@@ -401,8 +402,8 @@ static void gic_irq_print_chip(struct irq_data *d, struct seq_file *p)
{
struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
- if (gic->domain->dev)
- seq_printf(p, gic->domain->dev->of_node->name);
+ if (gic->domain->pm_dev)
+ seq_printf(p, gic->domain->pm_dev->of_node->name);
else
seq_printf(p, "GIC-%d", (int)(gic - &gic_data[0]));
}
@@ -1332,7 +1333,7 @@ static bool gicv2_force_probe;
static int __init gicv2_force_probe_cfg(char *buf)
{
- return strtobool(buf, &gicv2_force_probe);
+ return kstrtobool(buf, &gicv2_force_probe);
}
early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg);
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 741612ba6a52..9d8f2c406043 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -92,18 +92,34 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static int __init
-liointc_parse_madt(union acpi_subtable_headers *header,
- const unsigned long end)
+#ifdef CONFIG_OF
+static int __init cpuintc_of_init(struct device_node *of_node,
+ struct device_node *parent)
+{
+ cpuintc_handle = of_node_to_fwnode(of_node);
+
+ irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM,
+ &loongarch_cpu_intc_irq_domain_ops, NULL);
+ if (!irq_domain)
+ panic("Failed to add irqdomain for loongarch CPU");
+
+ set_handle_irq(&handle_cpu_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", cpuintc_of_init);
+#endif
+
+static int __init liointc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
{
struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header;
return liointc_acpi_init(irq_domain, liointc_entry);
}
-static int __init
-eiointc_parse_madt(union acpi_subtable_headers *header,
- const unsigned long end)
+static int __init eiointc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
{
struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header;
@@ -112,16 +128,24 @@ eiointc_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void)
{
- acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC,
- liointc_parse_madt, 0);
- acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
- eiointc_parse_madt, 0);
+ int r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, liointc_parse_madt, 0);
+ if (r < 0)
+ return r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, eiointc_parse_madt, 0);
+ if (r < 0)
+ return r;
+
return 0;
}
static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
+ int ret;
+
if (irq_domain)
return 0;
@@ -139,9 +163,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
set_handle_irq(&handle_cpu_irq);
acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
- acpi_cascade_irqdomain_init();
+ ret = acpi_cascade_irqdomain_init();
- return 0;
+ return ret;
}
IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC,
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index 16e9af8d8b1e..d15fd38c1756 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -17,6 +17,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/syscore_ops.h>
#define EIOINTC_REG_NODEMAP 0x14a0
#define EIOINTC_REG_IPMAP 0x14c0
@@ -301,9 +302,39 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group
return NULL;
}
-static int __init
-pch_pic_parse_madt(union acpi_subtable_headers *header,
- const unsigned long end)
+static int eiointc_suspend(void)
+{
+ return 0;
+}
+
+static void eiointc_resume(void)
+{
+ int i, j;
+ struct irq_desc *desc;
+ struct irq_data *irq_data;
+
+ eiointc_router_init(0);
+
+ for (i = 0; i < nr_pics; i++) {
+ for (j = 0; j < VEC_COUNT; j++) {
+ desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j);
+ if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
+ raw_spin_lock(&desc->lock);
+ irq_data = &desc->irq_data;
+ eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
+ raw_spin_unlock(&desc->lock);
+ }
+ }
+ }
+}
+
+static struct syscore_ops eiointc_syscore_ops = {
+ .suspend = eiointc_suspend,
+ .resume = eiointc_resume,
+};
+
+static int __init pch_pic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
{
struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
unsigned int node = (pchpic_entry->address >> 44) & 0xf;
@@ -315,9 +346,8 @@ pch_pic_parse_madt(union acpi_subtable_headers *header,
return -EINVAL;
}
-static int __init
-pch_msi_parse_madt(union acpi_subtable_headers *header,
- const unsigned long end)
+static int __init pch_msi_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
{
struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group);
@@ -330,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void)
{
- acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
- pch_pic_parse_madt, 0);
- acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
- pch_msi_parse_madt, 1);
+ int r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0);
+ if (r < 0)
+ return r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1);
+ if (r < 0)
+ return r;
+
return 0;
}
int __init eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc)
{
- int i, parent_irq;
+ int i, ret, parent_irq;
unsigned long node_map;
struct eiointc_priv *priv;
@@ -380,15 +416,16 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
+ register_syscore_ops(&eiointc_syscore_ops);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
"irqchip/loongarch/intc:starting",
eiointc_router_init, NULL);
acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group);
acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group);
- acpi_cascade_irqdomain_init();
+ ret = acpi_cascade_irqdomain_init();
- return 0;
+ return ret;
out_free_handle:
irq_domain_free_fwnode(priv->domain_handle);
diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index 60a335d7e64e..fc8bf1f5d41b 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -16,11 +16,11 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/syscore_ops.h>
/* Registers */
#define HTVEC_EN_OFF 0x20
#define HTVEC_MAX_PARENT_IRQ 8
-
#define VEC_COUNT_PER_REG 32
#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
@@ -30,8 +30,11 @@ struct htvec {
void __iomem *base;
struct irq_domain *htvec_domain;
raw_spinlock_t htvec_lock;
+ u32 saved_vec_en[HTVEC_MAX_PARENT_IRQ];
};
+static struct htvec *htvec_priv;
+
static void htvec_irq_dispatch(struct irq_desc *desc)
{
int i;
@@ -155,64 +158,169 @@ static void htvec_reset(struct htvec *priv)
}
}
-static int htvec_of_init(struct device_node *node,
- struct device_node *parent)
+static int htvec_suspend(void)
+{
+ int i;
+
+ for (i = 0; i < htvec_priv->num_parents; i++)
+ htvec_priv->saved_vec_en[i] = readl(htvec_priv->base + HTVEC_EN_OFF + 4 * i);
+
+ return 0;
+}
+
+static void htvec_resume(void)
{
+ int i;
+
+ for (i = 0; i < htvec_priv->num_parents; i++)
+ writel(htvec_priv->saved_vec_en[i], htvec_priv->base + HTVEC_EN_OFF + 4 * i);
+}
+
+static struct syscore_ops htvec_syscore_ops = {
+ .suspend = htvec_suspend,
+ .resume = htvec_resume,
+};
+
+static int htvec_init(phys_addr_t addr, unsigned long size,
+ int num_parents, int parent_irq[], struct fwnode_handle *domain_handle)
+{
+ int i;
struct htvec *priv;
- int err, parent_irq[8], i;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->num_parents = num_parents;
+ priv->base = ioremap(addr, size);
raw_spin_lock_init(&priv->htvec_lock);
- priv->base = of_iomap(node, 0);
- if (!priv->base) {
- err = -ENOMEM;
- goto free_priv;
- }
-
- /* Interrupt may come from any of the 8 interrupt lines */
- for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
- parent_irq[i] = irq_of_parse_and_map(node, i);
- if (parent_irq[i] <= 0)
- break;
- priv->num_parents++;
- }
-
- if (!priv->num_parents) {
- pr_err("Failed to get parent irqs\n");
- err = -ENODEV;
- goto iounmap_base;
- }
-
- priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+ /* Setup IRQ domain */
+ priv->htvec_domain = irq_domain_create_linear(domain_handle,
(VEC_COUNT_PER_REG * priv->num_parents),
&htvec_domain_ops, priv);
if (!priv->htvec_domain) {
- pr_err("Failed to create IRQ domain\n");
- err = -ENOMEM;
- goto irq_dispose;
+ pr_err("loongson-htvec: cannot add IRQ domain\n");
+ goto iounmap_base;
}
htvec_reset(priv);
- for (i = 0; i < priv->num_parents; i++)
+ for (i = 0; i < priv->num_parents; i++) {
irq_set_chained_handler_and_data(parent_irq[i],
htvec_irq_dispatch, priv);
+ }
+
+ htvec_priv = priv;
+
+ register_syscore_ops(&htvec_syscore_ops);
return 0;
-irq_dispose:
- for (; i > 0; i--)
- irq_dispose_mapping(parent_irq[i - 1]);
iounmap_base:
iounmap(priv->base);
-free_priv:
kfree(priv);
- return err;
+ return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int htvec_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ int i, err;
+ int parent_irq[8];
+ int num_parents = 0;
+ struct resource res;
+
+ if (of_address_to_resource(node, 0, &res))
+ return -EINVAL;
+
+ /* Interrupt may come from any of the 8 interrupt lines */
+ for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
+ parent_irq[i] = irq_of_parse_and_map(node, i);
+ if (parent_irq[i] <= 0)
+ break;
+
+ num_parents++;
+ }
+
+ err = htvec_init(res.start, resource_size(&res),
+ num_parents, parent_irq, of_node_to_fwnode(node));
+ if (err < 0)
+ return err;
+
+ return 0;
}
IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+static int __init pch_pic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
+
+ return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry);
+}
+
+static int __init pch_msi_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
+
+ return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ int r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0);
+ if (r < 0)
+ return r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int __init htvec_acpi_init(struct irq_domain *parent,
+ struct acpi_madt_ht_pic *acpi_htvec)
+{
+ int i, ret;
+ int num_parents, parent_irq[8];
+ struct fwnode_handle *domain_handle;
+
+ if (!acpi_htvec)
+ return -EINVAL;
+
+ num_parents = HTVEC_MAX_PARENT_IRQ;
+
+ domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address);
+ if (!domain_handle) {
+ pr_err("Unable to allocate domain handle\n");
+ return -ENOMEM;
+ }
+
+ /* Interrupt may come from any of the 8 interrupt lines */
+ for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++)
+ parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]);
+
+ ret = htvec_init(acpi_htvec->address, acpi_htvec->size,
+ num_parents, parent_irq, domain_handle);
+
+ if (ret == 0)
+ ret = acpi_cascade_irqdomain_init();
+ else
+ irq_domain_free_fwnode(domain_handle);
+
+ return ret;
+}
+
+#endif
diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 0da8716f8f24..85b754f7f4e6 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -167,7 +167,12 @@ static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
if (WARN_ON(intsize < 1))
return -EINVAL;
*out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;
- *out_type = IRQ_TYPE_NONE;
+
+ if (intsize > 1)
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ else
+ *out_type = IRQ_TYPE_NONE;
+
return 0;
}
@@ -207,10 +212,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
"reg-names", core_reg_names[i]);
if (index < 0)
- goto out_iounmap;
+ continue;
priv->core_isr[i] = of_iomap(node, index);
}
+
+ if (!priv->core_isr[0])
+ goto out_iounmap;
}
/* Setup IRQ domain */
@@ -349,6 +357,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);
#endif
#ifdef CONFIG_ACPI
+static int __init htintc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_ht_pic *htintc_entry = (struct acpi_madt_ht_pic *)header;
+ struct irq_domain *parent = irq_find_matching_fwnode(liointc_handle, DOMAIN_BUS_ANY);
+
+ return htvec_acpi_init(parent, htintc_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ int r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_HT_PIC, htintc_parse_madt, 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)
{
int ret;
@@ -365,9 +393,12 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic
pr_err("Unable to allocate domain handle\n");
return -ENOMEM;
}
+
ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
1, domain_handle, NULL);
- if (ret)
+ if (ret == 0)
+ ret = acpi_cascade_irqdomain_init();
+ else
irq_domain_free_fwnode(domain_handle);
return ret;
diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c
index bf2324910a75..9b35492fb6be 100644
--- a/drivers/irqchip/irq-loongson-pch-lpc.c
+++ b/drivers/irqchip/irq-loongson-pch-lpc.c
@@ -13,6 +13,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/syscore_ops.h>
/* Registers */
#define LPC_INT_CTL 0x00
@@ -34,6 +35,7 @@ struct pch_lpc {
u32 saved_reg_pol;
};
+static struct pch_lpc *pch_lpc_priv;
struct fwnode_handle *pch_lpc_handle;
static void lpc_irq_ack(struct irq_data *d)
@@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv)
(readl(priv->base + LPC_INT_STS) == 0xffffffff);
}
+static int pch_lpc_suspend(void)
+{
+ pch_lpc_priv->saved_reg_ctl = readl(pch_lpc_priv->base + LPC_INT_CTL);
+ pch_lpc_priv->saved_reg_ena = readl(pch_lpc_priv->base + LPC_INT_ENA);
+ pch_lpc_priv->saved_reg_pol = readl(pch_lpc_priv->base + LPC_INT_POL);
+ return 0;
+}
+
+static void pch_lpc_resume(void)
+{
+ writel(pch_lpc_priv->saved_reg_ctl, pch_lpc_priv->base + LPC_INT_CTL);
+ writel(pch_lpc_priv->saved_reg_ena, pch_lpc_priv->base + LPC_INT_ENA);
+ writel(pch_lpc_priv->saved_reg_pol, pch_lpc_priv->base + LPC_INT_POL);
+}
+
+static struct syscore_ops pch_lpc_syscore_ops = {
+ .suspend = pch_lpc_suspend,
+ .resume = pch_lpc_resume,
+};
+
int __init pch_lpc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lpc_pic *acpi_pchlpc)
{
@@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent,
parent_irq = irq_create_fwspec_mapping(&fwspec);
irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv);
+ pch_lpc_priv = priv;
pch_lpc_handle = irq_handle;
+ register_syscore_ops(&pch_lpc_syscore_ops);
+
return 0;
free_irq_handle:
diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
index c01b9c257005..437f1af693d0 100644
--- a/drivers/irqchip/irq-loongson-pch-pic.c
+++ b/drivers/irqchip/irq-loongson-pch-pic.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/syscore_ops.h>
/* Registers */
#define PCH_PIC_MASK 0x20
@@ -42,6 +43,9 @@ struct pch_pic {
raw_spinlock_t pic_lock;
u32 vec_count;
u32 gsi_base;
+ u32 saved_vec_en[PIC_REG_COUNT];
+ u32 saved_vec_pol[PIC_REG_COUNT];
+ u32 saved_vec_edge[PIC_REG_COUNT];
};
static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
@@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = {
.irq_ack = pch_pic_ack_irq,
.irq_set_affinity = irq_chip_set_affinity_parent,
.irq_set_type = pch_pic_set_type,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
};
static int pch_pic_domain_translate(struct irq_domain *d,
@@ -155,15 +160,21 @@ static int pch_pic_domain_translate(struct irq_domain *d,
struct pch_pic *priv = d->host_data;
struct device_node *of_node = to_of_node(fwspec->fwnode);
- if (fwspec->param_count < 1)
- return -EINVAL;
-
if (of_node) {
+ if (fwspec->param_count < 2)
+ return -EINVAL;
+
*hwirq = fwspec->param[0] + priv->ht_vec_base;
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
} else {
+ if (fwspec->param_count < 1)
+ return -EINVAL;
+
*hwirq = fwspec->param[0] - priv->gsi_base;
- *type = IRQ_TYPE_NONE;
+ if (fwspec->param_count > 1)
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+ else
+ *type = IRQ_TYPE_NONE;
}
return 0;
@@ -228,6 +239,46 @@ static void pch_pic_reset(struct pch_pic *priv)
}
}
+static int pch_pic_suspend(void)
+{
+ int i, j;
+
+ for (i = 0; i < nr_pics; i++) {
+ for (j = 0; j < PIC_REG_COUNT; j++) {
+ pch_pic_priv[i]->saved_vec_pol[j] =
+ readl(pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j);
+ pch_pic_priv[i]->saved_vec_edge[j] =
+ readl(pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j);
+ pch_pic_priv[i]->saved_vec_en[j] =
+ readl(pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j);
+ }
+ }
+
+ return 0;
+}
+
+static void pch_pic_resume(void)
+{
+ int i, j;
+
+ for (i = 0; i < nr_pics; i++) {
+ pch_pic_reset(pch_pic_priv[i]);
+ for (j = 0; j < PIC_REG_COUNT; j++) {
+ writel(pch_pic_priv[i]->saved_vec_pol[j],
+ pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j);
+ writel(pch_pic_priv[i]->saved_vec_edge[j],
+ pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j);
+ writel(pch_pic_priv[i]->saved_vec_en[j],
+ pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j);
+ }
+ }
+}
+
+static struct syscore_ops pch_pic_syscore_ops = {
+ .suspend = pch_pic_suspend,
+ .resume = pch_pic_resume,
+};
+
static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
u32 gsi_base)
@@ -260,6 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
pch_pic_handle[nr_pics] = domain_handle;
pch_pic_priv[nr_pics++] = priv;
+ register_syscore_ops(&pch_pic_syscore_ops);
+
return 0;
iounmap_base:
@@ -325,9 +378,8 @@ int find_pch_pic(u32 gsi)
return -1;
}
-static int __init
-pch_lpc_parse_madt(union acpi_subtable_headers *header,
- const unsigned long end)
+static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
{
struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
@@ -336,8 +388,12 @@ pch_lpc_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void)
{
- acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
- pch_lpc_parse_madt, 0);
+ int r;
+
+ r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -364,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent,
}
if (acpi_pchpic->id == 0)
- acpi_cascade_irqdomain_init();
+ ret = acpi_cascade_irqdomain_init();
return ret;
}
diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index d8d48b1f7c29..139f26b0a6ef 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
if (ret)
goto err_parse_map;
- priv->big_endian = of_device_is_big_endian(parent);
+ priv->big_endian = of_device_is_big_endian(node->parent);
priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||
of_device_is_compatible(node, "fsl,ls1043a-extirq");
raw_spin_lock_init(&priv->lock);
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 1ba0f1555c80..1a6a7a672ad7 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -494,7 +494,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
/*
- * If adding support for more per-cpu interrupts, keep the the
+ * If adding support for more per-cpu interrupts, keep the
* array in gic_all_vpes_irq_cpu_online() in sync.
*/
switch (intr) {
diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c
index 9bca0918078e..76bc0283e3b9 100644
--- a/drivers/irqchip/irq-mtk-cirq.c
+++ b/drivers/irqchip/irq-mtk-cirq.c
@@ -15,14 +15,41 @@
#include <linux/slab.h>
#include <linux/syscore_ops.h>
-#define CIRQ_ACK 0x40
-#define CIRQ_MASK_SET 0xc0
-#define CIRQ_MASK_CLR 0x100
-#define CIRQ_SENS_SET 0x180
-#define CIRQ_SENS_CLR 0x1c0
-#define CIRQ_POL_SET 0x240
-#define CIRQ_POL_CLR 0x280
-#define CIRQ_CONTROL 0x300
+enum mtk_cirq_regoffs_index {
+ CIRQ_STA,
+ CIRQ_ACK,
+ CIRQ_MASK_SET,
+ CIRQ_MASK_CLR,
+ CIRQ_SENS_SET,
+ CIRQ_SENS_CLR,
+ CIRQ_POL_SET,
+ CIRQ_POL_CLR,
+ CIRQ_CONTROL
+};
+
+static const u32 mtk_cirq_regoffs_v1[] = {
+ [CIRQ_STA] = 0x0,
+ [CIRQ_ACK] = 0x40,
+ [CIRQ_MASK_SET] = 0xc0,
+ [CIRQ_MASK_CLR] = 0x100,
+ [CIRQ_SENS_SET] = 0x180,
+ [CIRQ_SENS_CLR] = 0x1c0,
+ [CIRQ_POL_SET] = 0x240,
+ [CIRQ_POL_CLR] = 0x280,
+ [CIRQ_CONTROL] = 0x300,
+};
+
+static const u32 mtk_cirq_regoffs_v2[] = {
+ [CIRQ_STA] = 0x0,
+ [CIRQ_ACK] = 0x80,
+ [CIRQ_MASK_SET] = 0x180,
+ [CIRQ_MASK_CLR] = 0x200,
+ [CIRQ_SENS_SET] = 0x300,
+ [CIRQ_SENS_CLR] = 0x380,
+ [CIRQ_POL_SET] = 0x480,
+ [CIRQ_POL_CLR] = 0x500,
+ [CIRQ_CONTROL] = 0x600,
+};
#define CIRQ_EN 0x1
#define CIRQ_EDGE 0x2
@@ -32,18 +59,32 @@ struct mtk_cirq_chip_data {
void __iomem *base;
unsigned int ext_irq_start;
unsigned int ext_irq_end;
+ const u32 *offsets;
struct irq_domain *domain;
};
static struct mtk_cirq_chip_data *cirq_data;
-static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset)
+static void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data,
+ enum mtk_cirq_regoffs_index idx)
+{
+ return chip_data->base + chip_data->offsets[idx];
+}
+
+static void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data,
+ enum mtk_cirq_regoffs_index idx,
+ unsigned int cirq_num)
+{
+ return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4;
+}
+
+static void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx)
{
struct mtk_cirq_chip_data *chip_data = data->chip_data;
unsigned int cirq_num = data->hwirq;
u32 mask = 1 << (cirq_num % 32);
- writel_relaxed(mask, chip_data->base + offset + (cirq_num / 32) * 4);
+ writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num));
}
static void mtk_cirq_mask(struct irq_data *data)
@@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = {
#ifdef CONFIG_PM_SLEEP
static int mtk_cirq_suspend(void)
{
+ void __iomem *reg;
u32 value, mask;
unsigned int irq, hwirq_num;
bool pending, masked;
@@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void)
continue;
}
+ reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);
mask = 1 << (i % 32);
- writel_relaxed(mask, cirq_data->base + CIRQ_ACK + (i / 32) * 4);
+ writel_relaxed(mask, reg);
}
/* set edge_only mode, record edge-triggerd interrupts */
/* enable cirq */
- value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
+ reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
+ value = readl_relaxed(reg);
value |= (CIRQ_EDGE | CIRQ_EN);
- writel_relaxed(value, cirq_data->base + CIRQ_CONTROL);
+ writel_relaxed(value, reg);
return 0;
}
static void mtk_cirq_resume(void)
{
+ void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
u32 value;
/* flush recorded interrupts, will send signals to parent controller */
- value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
- writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL);
+ value = readl_relaxed(reg);
+ writel_relaxed(value | CIRQ_FLUSH, reg);
/* disable cirq */
- value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
+ value = readl_relaxed(reg);
value &= ~(CIRQ_EDGE | CIRQ_EN);
- writel_relaxed(value, cirq_data->base + CIRQ_CONTROL);
+ writel_relaxed(value, reg);
}
static struct syscore_ops mtk_cirq_syscore_ops = {
@@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void)
static inline void mtk_cirq_syscore_init(void) {}
#endif
+static const struct of_device_id mtk_cirq_of_match[] = {
+ { .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 },
+ { .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 },
+ { .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 },
+ { .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 },
+ { /* sentinel */ }
+};
+
static int __init mtk_cirq_of_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *domain, *domain_parent;
+ const struct of_device_id *match;
unsigned int irq_num;
int ret;
@@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node,
if (ret)
goto out_unmap;
+ match = of_match_node(mtk_cirq_of_match, node);
+ if (!match) {
+ ret = -ENODEV;
+ goto out_unmap;
+ }
+ cirq_data->offsets = match->data;
+
irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;
domain = irq_domain_add_hierarchy(domain_parent, 0,
irq_num, node,
diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 497da344717c..3c77acc7ec6a 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -151,9 +151,9 @@ static int
mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
unsigned long *hwirq, unsigned int *type)
{
- struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
- struct mvebu_icu *icu = platform_msi_get_host_data(d);
unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2;
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
+ struct mvebu_icu *icu = msi_data->icu;
/* Check the count of the parameters in dt */
if (WARN_ON(fwspec->param_count != param_count)) {
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 2f4784860df5..ff47bd0dec45 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = {
.irq_set_affinity = plic_set_affinity,
#endif
.irq_set_type = plic_irq_set_type,
- .flags = IRQCHIP_AFFINITY_PRE_STARTUP,
+ .flags = IRQCHIP_SKIP_SET_WAKE |
+ IRQCHIP_AFFINITY_PRE_STARTUP,
};
static struct irq_chip plic_chip = {
@@ -201,7 +202,8 @@ static struct irq_chip plic_chip = {
.irq_set_affinity = plic_set_affinity,
#endif
.irq_set_type = plic_irq_set_type,
- .flags = IRQCHIP_AFFINITY_PRE_STARTUP,
+ .flags = IRQCHIP_SKIP_SET_WAKE |
+ IRQCHIP_AFFINITY_PRE_STARTUP,
};
static int plic_irq_set_type(struct irq_data *d, unsigned int type)
diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c
index fbb354413ffa..f2172240172c 100644
--- a/drivers/irqchip/irq-sl28cpld.c
+++ b/drivers/irqchip/irq-sl28cpld.c
@@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev)
irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
irqchip->chip.num_regs = 1;
irqchip->chip.status_base = base + INTC_IP;
- irqchip->chip.mask_base = base + INTC_IE;
- irqchip->chip.mask_invert = true;
+ irqchip->chip.unmask_base = base + INTC_IE;
irqchip->chip.ack_base = base + INTC_IP;
return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c
index 801551e46a7b..1b83512b29c6 100644
--- a/drivers/irqchip/irq-st.c
+++ b/drivers/irqchip/irq-st.c
@@ -153,18 +153,13 @@ static int st_irq_syscfg_enable(struct platform_device *pdev)
static int st_irq_syscfg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *match;
struct st_irq_syscfg *ddata;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
- match = of_match_device(st_irq_syscfg_match, &pdev->dev);
- if (!match)
- return -ENODEV;
-
- ddata->syscfg = (unsigned int)match->data;
+ ddata->syscfg = (unsigned int) device_get_match_data(&pdev->dev);
ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(ddata->regmap)) {
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index 5fdbb4358dd0..a6ecc53d055c 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -168,7 +168,7 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
/**
* ti_sci_inta_xlate_irq() - Translate hwirq to parent's hwirq.
* @inta: IRQ domain corresponding to Interrupt Aggregator
- * @irq: Hardware irq corresponding to the above irq domain
+ * @vint_id: Hardware irq corresponding to the above irq domain
*
* Return parent irq number if translation is available else -ENOENT.
*/
diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c
index 0dcbeb1a05a1..91df62a64cd9 100644
--- a/drivers/irqchip/irq-wpcm450-aic.c
+++ b/drivers/irqchip/irq-wpcm450-aic.c
@@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node,
aic->regs = of_iomap(node, 0);
if (!aic->regs) {
pr_err("Failed to map WPCM450 AIC registers\n");
+ kfree(aic);
return -ENOMEM;
}
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index 7ea0100f218a..90ee56d07a6e 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -222,7 +222,7 @@ mISDN_register_device(struct mISDNdevice *dev,
err = get_free_devid();
if (err < 0)
- goto error1;
+ return err;
dev->id = err;
device_initialize(&dev->dev);
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index c3b2c99b5cd5..cfbcd9e973c2 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -77,6 +77,7 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
if (!entry)
return -ENOMEM;
+ INIT_LIST_HEAD(&entry->list);
entry->elem = elem;
entry->dev.class = elements_class;
@@ -107,7 +108,7 @@ err2:
device_unregister(&entry->dev);
return ret;
err1:
- kfree(entry);
+ put_device(&entry->dev);
return ret;
}
EXPORT_SYMBOL(mISDN_dsp_element_register);
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index a77195e378b7..c24771336f61 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -706,7 +706,7 @@ l1oip_socket_thread(void *data)
printk(KERN_DEBUG "%s: socket created and open\n",
__func__);
while (!signal_pending(current)) {
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, recvbuf_size);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, recvbuf_size);
recvlen = sock_recvmsg(socket, &msg, 0);
if (recvlen > 0) {
l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 05d6fae800e3..d7af896cbd7b 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -223,7 +223,7 @@ config BCM_FLEXRM_MBOX
tristate "Broadcom FlexRM Mailbox"
depends on ARM64
depends on ARCH_BCM_IPROC || COMPILE_TEST
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
default m if ARCH_BCM_IPROC
help
Mailbox implementation of the Broadcom FlexRM ring manager,
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 3c2bc0ca454c..105d46c9801b 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -743,6 +743,7 @@ static int __init pcc_init(void)
if (IS_ERR(pcc_pdev)) {
pr_debug("Err creating PCC platform bundle\n");
+ pcc_chan_count = 0;
return PTR_ERR(pcc_pdev);
}
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 99499d1f6e66..9f32901fdad1 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -160,7 +160,7 @@ static void read_moving(struct cache_set *c)
moving_init(io);
bio = &io->bio.bio;
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ bio->bi_opf = REQ_OP_READ;
bio->bi_end_io = read_moving_endio;
if (bch_bio_alloc_pages(bio, GFP_KERNEL))
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 3427555b0cca..67a2e29e0b40 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -244,7 +244,7 @@ static void bch_data_insert_start(struct closure *cl)
trace_bcache_cache_insert(k);
bch_keylist_push(&op->insert_keys);
- bio_set_op_attrs(n, REQ_OP_WRITE, 0);
+ n->bi_opf = REQ_OP_WRITE;
bch_submit_bbio(n, op->c, k, 0);
} while (n != bio);
@@ -401,7 +401,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
}
if (bypass_torture_test(dc)) {
- if (prandom_u32_max(4) == 3)
+ if (get_random_u32_below(4) == 3)
goto skip;
else
goto rescale;
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 0285b676e983..d4a5fc0650bb 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -434,7 +434,7 @@ static void write_dirty(struct closure *cl)
*/
if (KEY_DIRTY(&w->key)) {
dirty_init(w);
- bio_set_op_attrs(&io->bio, REQ_OP_WRITE, 0);
+ io->bio.bi_opf = REQ_OP_WRITE;
io->bio.bi_iter.bi_sector = KEY_START(&w->key);
bio_set_dev(&io->bio, io->dc->bdev);
io->bio.bi_end_io = dirty_endio;
@@ -547,7 +547,7 @@ static void read_dirty(struct cached_dev *dc)
io->sequence = sequence++;
dirty_init(w);
- bio_set_op_attrs(&io->bio, REQ_OP_READ, 0);
+ io->bio.bi_opf = REQ_OP_READ;
io->bio.bi_iter.bi_sector = PTR_OFFSET(&w->key, 0);
bio_set_dev(&io->bio, dc->disk.c->cache->bdev);
io->bio.bi_end_io = read_dirty_endio;
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 9c5ef818ca36..bb786c39545e 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1858,6 +1858,8 @@ bad:
dm_io_client_destroy(c->dm_io);
bad_dm_io:
mutex_destroy(&c->lock);
+ if (c->no_sleep)
+ static_branch_dec(&no_sleep_enabled);
kfree(c);
bad_client:
return ERR_PTR(r);
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index ab13b7380265..83a5975bcc72 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -551,11 +551,13 @@ static int __create_persistent_data_objects(struct dm_cache_metadata *cmd,
return r;
}
-static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd)
+static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd,
+ bool destroy_bm)
{
dm_sm_destroy(cmd->metadata_sm);
dm_tm_destroy(cmd->tm);
- dm_block_manager_destroy(cmd->bm);
+ if (destroy_bm)
+ dm_block_manager_destroy(cmd->bm);
}
typedef unsigned long (*flags_mutator)(unsigned long);
@@ -826,7 +828,7 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
cmd2 = lookup(bdev);
if (cmd2) {
mutex_unlock(&table_lock);
- __destroy_persistent_data_objects(cmd);
+ __destroy_persistent_data_objects(cmd, true);
kfree(cmd);
return cmd2;
}
@@ -874,7 +876,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
mutex_unlock(&table_lock);
if (!cmd->fail_io)
- __destroy_persistent_data_objects(cmd);
+ __destroy_persistent_data_objects(cmd, true);
kfree(cmd);
}
}
@@ -1807,14 +1809,52 @@ int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
{
- int r;
+ int r = -EINVAL;
+ struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
+
+ /* fail_io is double-checked with cmd->root_lock held below */
+ if (unlikely(cmd->fail_io))
+ return r;
+
+ /*
+ * Replacement block manager (new_bm) is created and old_bm destroyed outside of
+ * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
+ * shrinker associated with the block manager's bufio client vs cmd root_lock).
+ * - must take shrinker_rwsem without holding cmd->root_lock
+ */
+ new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
+ CACHE_MAX_CONCURRENT_LOCKS);
WRITE_LOCK(cmd);
- __destroy_persistent_data_objects(cmd);
- r = __create_persistent_data_objects(cmd, false);
+ if (cmd->fail_io) {
+ WRITE_UNLOCK(cmd);
+ goto out;
+ }
+
+ __destroy_persistent_data_objects(cmd, false);
+ old_bm = cmd->bm;
+ if (IS_ERR(new_bm)) {
+ DMERR("could not create block manager during abort");
+ cmd->bm = NULL;
+ r = PTR_ERR(new_bm);
+ goto out_unlock;
+ }
+
+ cmd->bm = new_bm;
+ r = __open_or_format_metadata(cmd, false);
+ if (r) {
+ cmd->bm = NULL;
+ goto out_unlock;
+ }
+ new_bm = NULL;
+out_unlock:
if (r)
cmd->fail_io = true;
WRITE_UNLOCK(cmd);
+ dm_block_manager_destroy(old_bm);
+out:
+ if (new_bm && !IS_ERR(new_bm))
+ dm_block_manager_destroy(new_bm);
return r;
}
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 54a8d5c9a44e..5e92fac90b67 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -907,16 +907,16 @@ static void abort_transaction(struct cache *cache)
if (get_cache_mode(cache) >= CM_READ_ONLY)
return;
- if (dm_cache_metadata_set_needs_check(cache->cmd)) {
- DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
- set_cache_mode(cache, CM_FAIL);
- }
-
DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
if (dm_cache_metadata_abort(cache->cmd)) {
DMERR("%s: failed to abort metadata transaction", dev_name);
set_cache_mode(cache, CM_FAIL);
}
+
+ if (dm_cache_metadata_set_needs_check(cache->cmd)) {
+ DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+ set_cache_mode(cache, CM_FAIL);
+ }
}
static void metadata_operation_failed(struct cache *cache, const char *op, int r)
@@ -1887,6 +1887,7 @@ static void destroy(struct cache *cache)
if (cache->prison)
dm_bio_prison_destroy_v2(cache->prison);
+ cancel_delayed_work_sync(&cache->waker);
if (cache->wq)
destroy_workqueue(cache->wq);
diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c
index 2f1cc66d2641..29e0b85eeaf0 100644
--- a/drivers/md/dm-clone-target.c
+++ b/drivers/md/dm-clone-target.c
@@ -1958,6 +1958,7 @@ static void clone_dtr(struct dm_target *ti)
mempool_exit(&clone->hydration_pool);
dm_kcopyd_client_destroy(clone->kcopyd_client);
+ cancel_delayed_work_sync(&clone->waker);
destroy_workqueue(clone->wq);
hash_table_exit(clone);
dm_clone_metadata_close(clone->cmd);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 159c6806c19b..2653516bcdef 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -3630,6 +3630,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
limits->physical_block_size =
max_t(unsigned, limits->physical_block_size, cc->sector_size);
limits->io_min = max_t(unsigned, limits->io_min, cc->sector_size);
+ limits->dma_alignment = limits->logical_block_size - 1;
}
static struct target_type crypt_target = {
diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c
index b0c45c6ebe0b..dc4381d68313 100644
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -8,6 +8,7 @@
*/
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/device-mapper.h>
#include <linux/init.h>
@@ -18,12 +19,17 @@
#define DM_MAX_DEVICES 256
#define DM_MAX_TARGETS 256
#define DM_MAX_STR_SIZE 4096
+#define DM_MAX_WAITFOR 256
static char *create;
+static char *waitfor[DM_MAX_WAITFOR];
+
/*
* Format: dm-mod.create=<name>,<uuid>,<minor>,<flags>,<table>[,<table>+][;<name>,<uuid>,<minor>,<flags>,<table>[,<table>+]+]
* Table format: <start_sector> <num_sectors> <target_type> <target_args>
+ * Block devices to wait for to become available before setting up tables:
+ * dm-mod.waitfor=<device1>[,..,<deviceN>]
*
* See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..." format
* details.
@@ -266,7 +272,7 @@ static int __init dm_init_init(void)
struct dm_device *dev;
LIST_HEAD(devices);
char *str;
- int r;
+ int i, r;
if (!create)
return 0;
@@ -286,6 +292,17 @@ static int __init dm_init_init(void)
DMINFO("waiting for all devices to be available before creating mapped devices");
wait_for_device_probe();
+ for (i = 0; i < ARRAY_SIZE(waitfor); i++) {
+ if (waitfor[i]) {
+ DMINFO("waiting for device %s ...", waitfor[i]);
+ while (!dm_get_dev_t(waitfor[i]))
+ msleep(5);
+ }
+ }
+
+ if (waitfor[0])
+ DMINFO("all devices available");
+
list_for_each_entry(dev, &devices, list) {
if (dm_early_create(&dev->dmi, dev->table,
dev->target_args_array))
@@ -301,3 +318,6 @@ late_initcall(dm_init_init);
module_param(create, charp, 0);
MODULE_PARM_DESC(create, "Create a mapped device in early boot");
+
+module_param_array(waitfor, charp, NULL, 0);
+MODULE_PARM_DESC(waitfor, "Devices to wait for before setting up tables");
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index aaf2472df6e5..1388ee35571e 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -263,6 +263,7 @@ struct dm_integrity_c {
struct completion crypto_backoff;
+ bool wrote_to_journal;
bool journal_uptodate;
bool just_formatted;
bool recalculate_flag;
@@ -2375,6 +2376,8 @@ static void integrity_commit(struct work_struct *w)
if (!commit_sections)
goto release_flush_bios;
+ ic->wrote_to_journal = true;
+
i = commit_start;
for (n = 0; n < commit_sections; n++) {
for (j = 0; j < ic->journal_section_entries; j++) {
@@ -2591,10 +2594,6 @@ static void integrity_writer(struct work_struct *w)
unsigned prev_free_sectors;
- /* the following test is not needed, but it tests the replay code */
- if (unlikely(dm_post_suspending(ic->ti)) && !ic->meta_dev)
- return;
-
spin_lock_irq(&ic->endio_wait.lock);
write_start = ic->committed_section;
write_sections = ic->n_committed_sections;
@@ -3101,10 +3100,17 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
drain_workqueue(ic->commit_wq);
if (ic->mode == 'J') {
- if (ic->meta_dev)
- queue_work(ic->writer_wq, &ic->writer_work);
+ queue_work(ic->writer_wq, &ic->writer_work);
drain_workqueue(ic->writer_wq);
dm_integrity_flush_buffers(ic, true);
+ if (ic->wrote_to_journal) {
+ init_journal(ic, ic->free_section,
+ ic->journal_sections - ic->free_section, ic->commit_seq);
+ if (ic->free_section) {
+ init_journal(ic, 0, ic->free_section,
+ next_commit_seq(ic->commit_seq));
+ }
+ }
}
if (ic->mode == 'B') {
@@ -3132,6 +3138,8 @@ static void dm_integrity_resume(struct dm_target *ti)
DEBUG_print("resume\n");
+ ic->wrote_to_journal = false;
+
if (ic->provided_data_sectors != old_provided_data_sectors) {
if (ic->provided_data_sectors > old_provided_data_sectors &&
ic->mode == 'B' &&
@@ -3370,6 +3378,7 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim
limits->logical_block_size = ic->sectors_per_block << SECTOR_SHIFT;
limits->physical_block_size = ic->sectors_per_block << SECTOR_SHIFT;
blk_limits_io_min(limits, ic->sectors_per_block << SECTOR_SHIFT);
+ limits->dma_alignment = limits->logical_block_size - 1;
}
}
@@ -4549,6 +4558,8 @@ static void dm_integrity_dtr(struct dm_target *ti)
BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
BUG_ON(!list_empty(&ic->wait_list));
+ if (ic->mode == 'B')
+ cancel_delayed_work_sync(&ic->bitmap_flush_work);
if (ic->metadata_wq)
destroy_workqueue(ic->metadata_wq);
if (ic->wait_wq)
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 6b3f867d0b70..36fc6ae4737a 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -655,7 +655,7 @@ static void list_version_get_needed(struct target_type *tt, void *needed_param)
size_t *needed = needed_param;
*needed += sizeof(struct dm_target_versions);
- *needed += strlen(tt->name);
+ *needed += strlen(tt->name) + 1;
*needed += ALIGN_MASK;
}
@@ -681,7 +681,7 @@ static void list_version_get_info(struct target_type *tt, void *param)
strcpy(info->vers->name, tt->name);
info->old_vers = info->vers;
- info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1);
+ info->vers = align_ptr((void *)(info->vers + 1) + strlen(tt->name) + 1);
}
static int __list_versions(struct dm_ioctl *param, size_t param_size, const char *name)
@@ -720,7 +720,7 @@ static int __list_versions(struct dm_ioctl *param, size_t param_size, const char
iter_info.old_vers = NULL;
iter_info.vers = vers;
iter_info.flags = 0;
- iter_info.end = (char *)vers+len;
+ iter_info.end = (char *)vers + needed;
/*
* Now loop through filling out the names & versions.
@@ -1788,8 +1788,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
{DM_TARGET_MSG_CMD, 0, target_message},
{DM_DEV_SET_GEOMETRY_CMD, 0, dev_set_geometry},
- {DM_DEV_ARM_POLL, IOCTL_FLAGS_NO_PARAMS, dev_arm_poll},
- {DM_GET_TARGET_VERSION, 0, get_target_version},
+ {DM_DEV_ARM_POLL_CMD, IOCTL_FLAGS_NO_PARAMS, dev_arm_poll},
+ {DM_GET_TARGET_VERSION_CMD, 0, get_target_version},
};
if (unlikely(cmd >= ARRAY_SIZE(_ioctls)))
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 20fd688f72e7..178e13a5b059 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -875,6 +875,7 @@ static void log_writes_io_hints(struct dm_target *ti, struct queue_limits *limit
limits->logical_block_size = bdev_logical_block_size(lc->dev->bdev);
limits->physical_block_size = bdev_physical_block_size(lc->dev->bdev);
limits->io_min = limits->physical_block_size;
+ limits->dma_alignment = limits->logical_block_size - 1;
}
#if IS_ENABLED(CONFIG_FS_DAX)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 078da18bb86d..8541d5688f3a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1215,7 +1215,7 @@ static int dm_keyslot_evict_callback(struct dm_target *ti, struct dm_dev *dev,
struct dm_keyslot_evict_args *args = data;
int err;
- err = blk_crypto_evict_key(bdev_get_queue(dev->bdev), args->key);
+ err = blk_crypto_evict_key(dev->bdev, args->key);
if (!args->err)
args->err = err;
/* Always try to evict the key from all devices. */
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index a27395c8621f..6bcc4c4786d8 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -724,6 +724,15 @@ static int __open_metadata(struct dm_pool_metadata *pmd)
goto bad_cleanup_data_sm;
}
+ /*
+ * For pool metadata opening process, root setting is redundant
+ * because it will be set again in __begin_transaction(). But dm
+ * pool aborting process really needs to get last transaction's
+ * root to avoid accessing broken btree.
+ */
+ pmd->root = le64_to_cpu(disk_super->data_mapping_root);
+ pmd->details_root = le64_to_cpu(disk_super->device_details_root);
+
__setup_btree_details(pmd);
dm_bm_unlock(sblock);
@@ -776,13 +785,15 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
return r;
}
-static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd)
+static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd,
+ bool destroy_bm)
{
dm_sm_destroy(pmd->data_sm);
dm_sm_destroy(pmd->metadata_sm);
dm_tm_destroy(pmd->nb_tm);
dm_tm_destroy(pmd->tm);
- dm_block_manager_destroy(pmd->bm);
+ if (destroy_bm)
+ dm_block_manager_destroy(pmd->bm);
}
static int __begin_transaction(struct dm_pool_metadata *pmd)
@@ -989,7 +1000,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
}
pmd_write_unlock(pmd);
if (!pmd->fail_io)
- __destroy_persistent_data_objects(pmd);
+ __destroy_persistent_data_objects(pmd, true);
kfree(pmd);
return 0;
@@ -1860,19 +1871,52 @@ static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd)
int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
{
int r = -EINVAL;
+ struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
+
+ /* fail_io is double-checked with pmd->root_lock held below */
+ if (unlikely(pmd->fail_io))
+ return r;
+
+ /*
+ * Replacement block manager (new_bm) is created and old_bm destroyed outside of
+ * pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
+ * shrinker associated with the block manager's bufio client vs pmd root_lock).
+ * - must take shrinker_rwsem without holding pmd->root_lock
+ */
+ new_bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
+ THIN_MAX_CONCURRENT_LOCKS);
pmd_write_lock(pmd);
- if (pmd->fail_io)
+ if (pmd->fail_io) {
+ pmd_write_unlock(pmd);
goto out;
+ }
__set_abort_with_changes_flags(pmd);
- __destroy_persistent_data_objects(pmd);
- r = __create_persistent_data_objects(pmd, false);
+ __destroy_persistent_data_objects(pmd, false);
+ old_bm = pmd->bm;
+ if (IS_ERR(new_bm)) {
+ DMERR("could not create block manager during abort");
+ pmd->bm = NULL;
+ r = PTR_ERR(new_bm);
+ goto out_unlock;
+ }
+
+ pmd->bm = new_bm;
+ r = __open_or_format_metadata(pmd, false);
+ if (r) {
+ pmd->bm = NULL;
+ goto out_unlock;
+ }
+ new_bm = NULL;
+out_unlock:
if (r)
pmd->fail_io = true;
-
-out:
pmd_write_unlock(pmd);
+ dm_block_manager_destroy(old_bm);
+out:
+ if (new_bm && !IS_ERR(new_bm))
+ dm_block_manager_destroy(new_bm);
return r;
}
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index e76c96c760a9..64cfcf46881d 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -410,7 +410,7 @@ static void end_discard(struct discard_op *op, int r)
* need to wait for the chain to complete.
*/
bio_chain(op->bio, op->parent_bio);
- bio_set_op_attrs(op->bio, REQ_OP_DISCARD, 0);
+ op->bio->bi_opf = REQ_OP_DISCARD;
submit_bio(op->bio);
}
@@ -2889,6 +2889,8 @@ static void __pool_destroy(struct pool *pool)
dm_bio_prison_destroy(pool->prison);
dm_kcopyd_client_destroy(pool->copier);
+ cancel_delayed_work_sync(&pool->waker);
+ cancel_delayed_work_sync(&pool->no_space_timeout);
if (pool->wq)
destroy_workqueue(pool->wq);
@@ -3540,20 +3542,28 @@ static int pool_preresume(struct dm_target *ti)
*/
r = bind_control_target(pool, ti);
if (r)
- return r;
+ goto out;
r = maybe_resize_data_dev(ti, &need_commit1);
if (r)
- return r;
+ goto out;
r = maybe_resize_metadata_dev(ti, &need_commit2);
if (r)
- return r;
+ goto out;
if (need_commit1 || need_commit2)
(void) commit(pool);
+out:
+ /*
+ * When a thin-pool is PM_FAIL, it cannot be rebuilt if
+ * bio is in deferred list. Therefore need to return 0
+ * to allow pool_resume() to flush IO.
+ */
+ if (r && get_pool_mode(pool) == PM_FAIL)
+ r = 0;
- return 0;
+ return r;
}
static void pool_suspend_active_thins(struct pool *pool)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 95a1ee3d314e..e1ea3a7bd9d9 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -732,28 +732,48 @@ static char *_dm_claim_ptr = "I belong to device-mapper";
/*
* Open a table device so we can use it as a map destination.
*/
-static int open_table_device(struct table_device *td, dev_t dev,
- struct mapped_device *md)
+static struct table_device *open_table_device(struct mapped_device *md,
+ dev_t dev, fmode_t mode)
{
+ struct table_device *td;
struct block_device *bdev;
u64 part_off;
int r;
- BUG_ON(td->dm_dev.bdev);
+ td = kmalloc_node(sizeof(*td), GFP_KERNEL, md->numa_node_id);
+ if (!td)
+ return ERR_PTR(-ENOMEM);
+ refcount_set(&td->count, 1);
- bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr);
- if (IS_ERR(bdev))
- return PTR_ERR(bdev);
+ bdev = blkdev_get_by_dev(dev, mode | FMODE_EXCL, _dm_claim_ptr);
+ if (IS_ERR(bdev)) {
+ r = PTR_ERR(bdev);
+ goto out_free_td;
+ }
- r = bd_link_disk_holder(bdev, dm_disk(md));
- if (r) {
- blkdev_put(bdev, td->dm_dev.mode | FMODE_EXCL);
- return r;
+ /*
+ * We can be called before the dm disk is added. In that case we can't
+ * register the holder relation here. It will be done once add_disk was
+ * called.
+ */
+ if (md->disk->slave_dir) {
+ r = bd_link_disk_holder(bdev, md->disk);
+ if (r)
+ goto out_blkdev_put;
}
+ td->dm_dev.mode = mode;
td->dm_dev.bdev = bdev;
td->dm_dev.dax_dev = fs_dax_get_by_bdev(bdev, &part_off, NULL, NULL);
- return 0;
+ format_dev_t(td->dm_dev.name, dev);
+ list_add(&td->list, &md->table_devices);
+ return td;
+
+out_blkdev_put:
+ blkdev_put(bdev, mode | FMODE_EXCL);
+out_free_td:
+ kfree(td);
+ return ERR_PTR(r);
}
/*
@@ -761,14 +781,12 @@ static int open_table_device(struct table_device *td, dev_t dev,
*/
static void close_table_device(struct table_device *td, struct mapped_device *md)
{
- if (!td->dm_dev.bdev)
- return;
-
- bd_unlink_disk_holder(td->dm_dev.bdev, dm_disk(md));
+ if (md->disk->slave_dir)
+ bd_unlink_disk_holder(td->dm_dev.bdev, md->disk);
blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL);
put_dax(td->dm_dev.dax_dev);
- td->dm_dev.bdev = NULL;
- td->dm_dev.dax_dev = NULL;
+ list_del(&td->list);
+ kfree(td);
}
static struct table_device *find_table_device(struct list_head *l, dev_t dev,
@@ -786,31 +804,16 @@ static struct table_device *find_table_device(struct list_head *l, dev_t dev,
int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode,
struct dm_dev **result)
{
- int r;
struct table_device *td;
mutex_lock(&md->table_devices_lock);
td = find_table_device(&md->table_devices, dev, mode);
if (!td) {
- td = kmalloc_node(sizeof(*td), GFP_KERNEL, md->numa_node_id);
- if (!td) {
+ td = open_table_device(md, dev, mode);
+ if (IS_ERR(td)) {
mutex_unlock(&md->table_devices_lock);
- return -ENOMEM;
+ return PTR_ERR(td);
}
-
- td->dm_dev.mode = mode;
- td->dm_dev.bdev = NULL;
-
- if ((r = open_table_device(td, dev, md))) {
- mutex_unlock(&md->table_devices_lock);
- kfree(td);
- return r;
- }
-
- format_dev_t(td->dm_dev.name, dev);
-
- refcount_set(&td->count, 1);
- list_add(&td->list, &md->table_devices);
} else {
refcount_inc(&td->count);
}
@@ -825,27 +828,11 @@ void dm_put_table_device(struct mapped_device *md, struct dm_dev *d)
struct table_device *td = container_of(d, struct table_device, dm_dev);
mutex_lock(&md->table_devices_lock);
- if (refcount_dec_and_test(&td->count)) {
+ if (refcount_dec_and_test(&td->count))
close_table_device(td, md);
- list_del(&td->list);
- kfree(td);
- }
mutex_unlock(&md->table_devices_lock);
}
-static void free_table_devices(struct list_head *devices)
-{
- struct list_head *tmp, *next;
-
- list_for_each_safe(tmp, next, devices) {
- struct table_device *td = list_entry(tmp, struct table_device, list);
-
- DMWARN("dm_destroy: %s still exists with %d references",
- td->dm_dev.name, refcount_read(&td->count));
- kfree(td);
- }
-}
-
/*
* Get the geometry associated with a dm device
*/
@@ -1972,8 +1959,21 @@ static void cleanup_mapped_device(struct mapped_device *md)
md->disk->private_data = NULL;
spin_unlock(&_minor_lock);
if (dm_get_md_type(md) != DM_TYPE_NONE) {
+ struct table_device *td;
+
dm_sysfs_exit(md);
+ list_for_each_entry(td, &md->table_devices, list) {
+ bd_unlink_disk_holder(td->dm_dev.bdev,
+ md->disk);
+ }
+
+ /*
+ * Hold lock to make sure del_gendisk() won't concurrent
+ * with open/close_table_device().
+ */
+ mutex_lock(&md->table_devices_lock);
del_gendisk(md->disk);
+ mutex_unlock(&md->table_devices_lock);
}
dm_queue_destroy_crypto_profile(md->queue);
put_disk(md->disk);
@@ -2122,7 +2122,7 @@ static void free_dev(struct mapped_device *md)
cleanup_mapped_device(md);
- free_table_devices(&md->table_devices);
+ WARN_ON_ONCE(!list_empty(&md->table_devices));
dm_stats_cleanup(&md->stats);
free_minor(minor);
@@ -2305,6 +2305,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
{
enum dm_queue_mode type = dm_table_get_type(t);
struct queue_limits limits;
+ struct table_device *td;
int r;
switch (type) {
@@ -2333,17 +2334,40 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
if (r)
return r;
+ /*
+ * Hold lock to make sure add_disk() and del_gendisk() won't concurrent
+ * with open_table_device() and close_table_device().
+ */
+ mutex_lock(&md->table_devices_lock);
r = add_disk(md->disk);
+ mutex_unlock(&md->table_devices_lock);
if (r)
return r;
- r = dm_sysfs_init(md);
- if (r) {
- del_gendisk(md->disk);
- return r;
+ /*
+ * Register the holder relationship for devices added before the disk
+ * was live.
+ */
+ list_for_each_entry(td, &md->table_devices, list) {
+ r = bd_link_disk_holder(td->dm_dev.bdev, md->disk);
+ if (r)
+ goto out_undo_holders;
}
+
+ r = dm_sysfs_init(md);
+ if (r)
+ goto out_undo_holders;
+
md->type = type;
return 0;
+
+out_undo_holders:
+ list_for_each_entry_continue_reverse(td, &md->table_devices, list)
+ bd_unlink_disk_holder(td->dm_dev.bdev, md->disk);
+ mutex_lock(&md->table_devices_lock);
+ del_gendisk(md->disk);
+ mutex_unlock(&md->table_devices_lock);
+ return r;
}
struct mapped_device *dm_get_md(dev_t dev)
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index bf6dffadbe6f..e7cc6ba1b657 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -486,7 +486,7 @@ void md_bitmap_print_sb(struct bitmap *bitmap)
sb = kmap_atomic(bitmap->storage.sb_page);
pr_debug("%s: bitmap file superblock:\n", bmname(bitmap));
pr_debug(" magic: %08x\n", le32_to_cpu(sb->magic));
- pr_debug(" version: %d\n", le32_to_cpu(sb->version));
+ pr_debug(" version: %u\n", le32_to_cpu(sb->version));
pr_debug(" uuid: %08x.%08x.%08x.%08x\n",
le32_to_cpu(*(__le32 *)(sb->uuid+0)),
le32_to_cpu(*(__le32 *)(sb->uuid+4)),
@@ -497,11 +497,11 @@ void md_bitmap_print_sb(struct bitmap *bitmap)
pr_debug("events cleared: %llu\n",
(unsigned long long) le64_to_cpu(sb->events_cleared));
pr_debug(" state: %08x\n", le32_to_cpu(sb->state));
- pr_debug(" chunksize: %d B\n", le32_to_cpu(sb->chunksize));
- pr_debug(" daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
+ pr_debug(" chunksize: %u B\n", le32_to_cpu(sb->chunksize));
+ pr_debug(" daemon sleep: %us\n", le32_to_cpu(sb->daemon_sleep));
pr_debug(" sync size: %llu KB\n",
(unsigned long long)le64_to_cpu(sb->sync_size)/2);
- pr_debug("max write behind: %d\n", le32_to_cpu(sb->write_behind));
+ pr_debug("max write behind: %u\n", le32_to_cpu(sb->write_behind));
kunmap_atomic(sb);
}
@@ -2105,7 +2105,8 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
bytes = DIV_ROUND_UP(chunks, 8);
if (!bitmap->mddev->bitmap_info.external)
bytes += sizeof(bitmap_super_t);
- } while (bytes > (space << 9));
+ } while (bytes > (space << 9) && (chunkshift + BITMAP_BLOCK_SHIFT) <
+ (BITS_PER_BYTE * sizeof(((bitmap_super_t *)0)->chunksize) - 1));
} else
chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
@@ -2150,7 +2151,7 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
bitmap->counts.missing_pages = pages;
bitmap->counts.chunkshift = chunkshift;
bitmap->counts.chunks = chunks;
- bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
+ bitmap->mddev->bitmap_info.chunksize = 1UL << (chunkshift +
BITMAP_BLOCK_SHIFT);
blocks = min(old_counts.chunks << old_counts.chunkshift,
@@ -2176,8 +2177,8 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
bitmap->counts.missing_pages = old_counts.pages;
bitmap->counts.chunkshift = old_counts.chunkshift;
bitmap->counts.chunks = old_counts.chunks;
- bitmap->mddev->bitmap_info.chunksize = 1 << (old_counts.chunkshift +
- BITMAP_BLOCK_SHIFT);
+ bitmap->mddev->bitmap_info.chunksize =
+ 1UL << (old_counts.chunkshift + BITMAP_BLOCK_SHIFT);
blocks = old_counts.chunks << old_counts.chunkshift;
pr_warn("Could not pre-allocate in-memory bitmap for cluster raid\n");
break;
@@ -2195,20 +2196,23 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
if (set) {
bmc_new = md_bitmap_get_counter(&bitmap->counts, block, &new_blocks, 1);
- if (*bmc_new == 0) {
- /* need to set on-disk bits too. */
- sector_t end = block + new_blocks;
- sector_t start = block >> chunkshift;
- start <<= chunkshift;
- while (start < end) {
- md_bitmap_file_set_bit(bitmap, block);
- start += 1 << chunkshift;
+ if (bmc_new) {
+ if (*bmc_new == 0) {
+ /* need to set on-disk bits too. */
+ sector_t end = block + new_blocks;
+ sector_t start = block >> chunkshift;
+
+ start <<= chunkshift;
+ while (start < end) {
+ md_bitmap_file_set_bit(bitmap, block);
+ start += 1 << chunkshift;
+ }
+ *bmc_new = 2;
+ md_bitmap_count_page(&bitmap->counts, block, 1);
+ md_bitmap_set_pending(&bitmap->counts, block);
}
- *bmc_new = 2;
- md_bitmap_count_page(&bitmap->counts, block, 1);
- md_bitmap_set_pending(&bitmap->counts, block);
+ *bmc_new |= NEEDED_MASK;
}
- *bmc_new |= NEEDED_MASK;
if (new_blocks < old_blocks)
old_blocks = new_blocks;
}
@@ -2534,6 +2538,9 @@ chunksize_store(struct mddev *mddev, const char *buf, size_t len)
if (csize < 512 ||
!is_power_of_2(csize))
return -EINVAL;
+ if (BITS_PER_LONG > 32 && csize >= (1ULL << (BITS_PER_BYTE *
+ sizeof(((bitmap_super_t *)0)->chunksize))))
+ return -EOVERFLOW;
mddev->bitmap_info.chunksize = csize;
return len;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index a467b492d4ad..775f1dde190a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -93,6 +93,18 @@ static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *this);
static void mddev_detach(struct mddev *mddev);
+enum md_ro_state {
+ MD_RDWR,
+ MD_RDONLY,
+ MD_AUTO_READ,
+ MD_MAX_STATE
+};
+
+static bool md_is_rdwr(struct mddev *mddev)
+{
+ return (mddev->ro == MD_RDWR);
+}
+
/*
* Default number of read corrections we'll attempt on an rdev
* before ejecting it from the array. We divide the read error
@@ -444,7 +456,7 @@ static void md_submit_bio(struct bio *bio)
bio = bio_split_to_limits(bio);
- if (mddev->ro == 1 && unlikely(rw == WRITE)) {
+ if (mddev->ro == MD_RDONLY && unlikely(rw == WRITE)) {
if (bio_sectors(bio) != 0)
bio->bi_status = BLK_STS_IOERR;
bio_endio(bio);
@@ -509,13 +521,14 @@ static void md_end_flush(struct bio *bio)
struct md_rdev *rdev = bio->bi_private;
struct mddev *mddev = rdev->mddev;
+ bio_put(bio);
+
rdev_dec_pending(rdev, mddev);
if (atomic_dec_and_test(&mddev->flush_pending)) {
/* The pre-request flush has finished */
queue_work(md_wq, &mddev->flush_work);
}
- bio_put(bio);
}
static void md_submit_flush_data(struct work_struct *ws);
@@ -913,10 +926,12 @@ static void super_written(struct bio *bio)
} else
clear_bit(LastDev, &rdev->flags);
+ bio_put(bio);
+
+ rdev_dec_pending(rdev, mddev);
+
if (atomic_dec_and_test(&mddev->pending_writes))
wake_up(&mddev->sb_wait);
- rdev_dec_pending(rdev, mddev);
- bio_put(bio);
}
void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
@@ -2453,7 +2468,22 @@ static void rdev_delayed_delete(struct work_struct *ws)
kobject_put(&rdev->kobj);
}
-static void unbind_rdev_from_array(struct md_rdev *rdev)
+void md_autodetect_dev(dev_t dev);
+
+static void export_rdev(struct md_rdev *rdev)
+{
+ pr_debug("md: export_rdev(%pg)\n", rdev->bdev);
+ md_rdev_clear(rdev);
+#ifndef MODULE
+ if (test_bit(AutoDetected, &rdev->flags))
+ md_autodetect_dev(rdev->bdev->bd_dev);
+#endif
+ blkdev_put(rdev->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+ rdev->bdev = NULL;
+ kobject_put(&rdev->kobj);
+}
+
+static void md_kick_rdev_from_array(struct md_rdev *rdev)
{
bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
@@ -2476,56 +2506,8 @@ static void unbind_rdev_from_array(struct md_rdev *rdev)
INIT_WORK(&rdev->del_work, rdev_delayed_delete);
kobject_get(&rdev->kobj);
queue_work(md_rdev_misc_wq, &rdev->del_work);
-}
-
-/*
- * prevent the device from being mounted, repartitioned or
- * otherwise reused by a RAID array (or any other kernel
- * subsystem), by bd_claiming the device.
- */
-static int lock_rdev(struct md_rdev *rdev, dev_t dev, int shared)
-{
- int err = 0;
- struct block_device *bdev;
-
- bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
- shared ? (struct md_rdev *)lock_rdev : rdev);
- if (IS_ERR(bdev)) {
- pr_warn("md: could not open device unknown-block(%u,%u).\n",
- MAJOR(dev), MINOR(dev));
- return PTR_ERR(bdev);
- }
- rdev->bdev = bdev;
- return err;
-}
-
-static void unlock_rdev(struct md_rdev *rdev)
-{
- struct block_device *bdev = rdev->bdev;
- rdev->bdev = NULL;
- blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
-}
-
-void md_autodetect_dev(dev_t dev);
-
-static void export_rdev(struct md_rdev *rdev)
-{
- pr_debug("md: export_rdev(%pg)\n", rdev->bdev);
- md_rdev_clear(rdev);
-#ifndef MODULE
- if (test_bit(AutoDetected, &rdev->flags))
- md_autodetect_dev(rdev->bdev->bd_dev);
-#endif
- unlock_rdev(rdev);
- kobject_put(&rdev->kobj);
-}
-
-void md_kick_rdev_from_array(struct md_rdev *rdev)
-{
- unbind_rdev_from_array(rdev);
export_rdev(rdev);
}
-EXPORT_SYMBOL_GPL(md_kick_rdev_from_array);
static void export_array(struct mddev *mddev)
{
@@ -2639,7 +2621,7 @@ void md_update_sb(struct mddev *mddev, int force_change)
int any_badblocks_changed = 0;
int ret = -1;
- if (mddev->ro) {
+ if (!md_is_rdwr(mddev)) {
if (force_change)
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
return;
@@ -3660,9 +3642,10 @@ EXPORT_SYMBOL_GPL(md_rdev_init);
*/
static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
{
- int err;
+ static struct md_rdev *claim_rdev; /* just for claiming the bdev */
struct md_rdev *rdev;
sector_t size;
+ int err;
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
if (!rdev)
@@ -3670,14 +3653,20 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
err = md_rdev_init(rdev);
if (err)
- goto abort_free;
+ goto out_free_rdev;
err = alloc_disk_sb(rdev);
if (err)
- goto abort_free;
+ goto out_clear_rdev;
- err = lock_rdev(rdev, newdev, super_format == -2);
- if (err)
- goto abort_free;
+ rdev->bdev = blkdev_get_by_dev(newdev,
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL,
+ super_format == -2 ? claim_rdev : rdev);
+ if (IS_ERR(rdev->bdev)) {
+ pr_warn("md: could not open device unknown-block(%u,%u).\n",
+ MAJOR(newdev), MINOR(newdev));
+ err = PTR_ERR(rdev->bdev);
+ goto out_clear_rdev;
+ }
kobject_init(&rdev->kobj, &rdev_ktype);
@@ -3686,7 +3675,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
pr_warn("md: %pg has zero or unknown size, marking faulty!\n",
rdev->bdev);
err = -EINVAL;
- goto abort_free;
+ goto out_blkdev_put;
}
if (super_format >= 0) {
@@ -3696,21 +3685,22 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
pr_warn("md: %pg does not have a valid v%d.%d superblock, not importing!\n",
rdev->bdev,
super_format, super_minor);
- goto abort_free;
+ goto out_blkdev_put;
}
if (err < 0) {
pr_warn("md: could not read %pg's sb, not importing!\n",
rdev->bdev);
- goto abort_free;
+ goto out_blkdev_put;
}
}
return rdev;
-abort_free:
- if (rdev->bdev)
- unlock_rdev(rdev);
+out_blkdev_put:
+ blkdev_put(rdev->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+out_clear_rdev:
md_rdev_clear(rdev);
+out_free_rdev:
kfree(rdev);
return ERR_PTR(err);
}
@@ -3901,7 +3891,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
goto out_unlock;
}
rv = -EROFS;
- if (mddev->ro)
+ if (!md_is_rdwr(mddev))
goto out_unlock;
/* request to change the personality. Need to ensure:
@@ -4107,7 +4097,7 @@ layout_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->pers) {
if (mddev->pers->check_reshape == NULL)
err = -EBUSY;
- else if (mddev->ro)
+ else if (!md_is_rdwr(mddev))
err = -EROFS;
else {
mddev->new_layout = n;
@@ -4216,7 +4206,7 @@ chunk_size_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->pers) {
if (mddev->pers->check_reshape == NULL)
err = -EBUSY;
- else if (mddev->ro)
+ else if (!md_is_rdwr(mddev))
err = -EROFS;
else {
mddev->new_chunk_sectors = n >> 9;
@@ -4339,13 +4329,13 @@ array_state_show(struct mddev *mddev, char *page)
if (mddev->pers && !test_bit(MD_NOT_READY, &mddev->flags)) {
switch(mddev->ro) {
- case 1:
+ case MD_RDONLY:
st = readonly;
break;
- case 2:
+ case MD_AUTO_READ:
st = read_auto;
break;
- case 0:
+ case MD_RDWR:
spin_lock(&mddev->lock);
if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags))
st = write_pending;
@@ -4381,7 +4371,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
int err = 0;
enum array_state st = match_word(buf, array_states);
- if (mddev->pers && (st == active || st == clean) && mddev->ro != 1) {
+ if (mddev->pers && (st == active || st == clean) &&
+ mddev->ro != MD_RDONLY) {
/* don't take reconfig_mutex when toggling between
* clean and active
*/
@@ -4425,23 +4416,23 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->pers)
err = md_set_readonly(mddev, NULL);
else {
- mddev->ro = 1;
+ mddev->ro = MD_RDONLY;
set_disk_ro(mddev->gendisk, 1);
err = do_md_run(mddev);
}
break;
case read_auto:
if (mddev->pers) {
- if (mddev->ro == 0)
+ if (md_is_rdwr(mddev))
err = md_set_readonly(mddev, NULL);
- else if (mddev->ro == 1)
+ else if (mddev->ro == MD_RDONLY)
err = restart_array(mddev);
if (err == 0) {
- mddev->ro = 2;
+ mddev->ro = MD_AUTO_READ;
set_disk_ro(mddev->gendisk, 0);
}
} else {
- mddev->ro = 2;
+ mddev->ro = MD_AUTO_READ;
err = do_md_run(mddev);
}
break;
@@ -4466,7 +4457,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
wake_up(&mddev->sb_wait);
err = 0;
} else {
- mddev->ro = 0;
+ mddev->ro = MD_RDWR;
set_disk_ro(mddev->gendisk, 0);
err = do_md_run(mddev);
}
@@ -4765,7 +4756,7 @@ action_show(struct mddev *mddev, char *page)
if (test_bit(MD_RECOVERY_FROZEN, &recovery))
type = "frozen";
else if (test_bit(MD_RECOVERY_RUNNING, &recovery) ||
- (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &recovery))) {
+ (md_is_rdwr(mddev) && test_bit(MD_RECOVERY_NEEDED, &recovery))) {
if (test_bit(MD_RECOVERY_RESHAPE, &recovery))
type = "reshape";
else if (test_bit(MD_RECOVERY_SYNC, &recovery)) {
@@ -4851,11 +4842,11 @@ action_store(struct mddev *mddev, const char *page, size_t len)
set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
}
- if (mddev->ro == 2) {
+ if (mddev->ro == MD_AUTO_READ) {
/* A write to sync_action is enough to justify
* canceling read-auto mode
*/
- mddev->ro = 0;
+ mddev->ro = MD_RDWR;
md_wakeup_thread(mddev->sync_thread);
}
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -5083,8 +5074,7 @@ max_sync_store(struct mddev *mddev, const char *buf, size_t len)
goto out_unlock;
err = -EBUSY;
- if (max < mddev->resync_max &&
- mddev->ro == 0 &&
+ if (max < mddev->resync_max && md_is_rdwr(mddev) &&
test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
goto out_unlock;
@@ -5813,8 +5803,8 @@ int md_run(struct mddev *mddev)
continue;
sync_blockdev(rdev->bdev);
invalidate_bdev(rdev->bdev);
- if (mddev->ro != 1 && rdev_read_only(rdev)) {
- mddev->ro = 1;
+ if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
+ mddev->ro = MD_RDONLY;
if (mddev->gendisk)
set_disk_ro(mddev->gendisk, 1);
}
@@ -5917,8 +5907,8 @@ int md_run(struct mddev *mddev)
mddev->ok_start_degraded = start_dirty_degraded;
- if (start_readonly && mddev->ro == 0)
- mddev->ro = 2; /* read-only, but switch on first write */
+ if (start_readonly && md_is_rdwr(mddev))
+ mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
err = pers->run(mddev);
if (err)
@@ -5996,8 +5986,8 @@ int md_run(struct mddev *mddev)
mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
- } else if (mddev->ro == 2) /* auto-readonly not meaningful */
- mddev->ro = 0;
+ } else if (mddev->ro == MD_AUTO_READ)
+ mddev->ro = MD_RDWR;
atomic_set(&mddev->max_corr_read_errors,
MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
@@ -6015,7 +6005,7 @@ int md_run(struct mddev *mddev)
if (rdev->raid_disk >= 0)
sysfs_link_rdev(mddev, rdev); /* failure here is OK */
- if (mddev->degraded && !mddev->ro)
+ if (mddev->degraded && md_is_rdwr(mddev))
/* This ensures that recovering status is reported immediately
* via sysfs - until a lack of spares is confirmed.
*/
@@ -6105,7 +6095,7 @@ static int restart_array(struct mddev *mddev)
return -ENXIO;
if (!mddev->pers)
return -EINVAL;
- if (!mddev->ro)
+ if (md_is_rdwr(mddev))
return -EBUSY;
rcu_read_lock();
@@ -6124,7 +6114,7 @@ static int restart_array(struct mddev *mddev)
return -EROFS;
mddev->safemode = 0;
- mddev->ro = 0;
+ mddev->ro = MD_RDWR;
set_disk_ro(disk, 0);
pr_debug("md: %s switched to read-write mode.\n", mdname(mddev));
/* Kick recovery or resync if necessary */
@@ -6151,7 +6141,7 @@ static void md_clean(struct mddev *mddev)
mddev->clevel[0] = 0;
mddev->flags = 0;
mddev->sb_flags = 0;
- mddev->ro = 0;
+ mddev->ro = MD_RDWR;
mddev->metadata_type[0] = 0;
mddev->chunk_sectors = 0;
mddev->ctime = mddev->utime = 0;
@@ -6203,7 +6193,7 @@ static void __md_stop_writes(struct mddev *mddev)
}
md_bitmap_flush(mddev);
- if (mddev->ro == 0 &&
+ if (md_is_rdwr(mddev) &&
((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
mddev->sb_flags)) {
/* mark array as shutdown cleanly */
@@ -6312,9 +6302,9 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
__md_stop_writes(mddev);
err = -ENXIO;
- if (mddev->ro==1)
+ if (mddev->ro == MD_RDONLY)
goto out;
- mddev->ro = 1;
+ mddev->ro = MD_RDONLY;
set_disk_ro(mddev->gendisk, 1);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -6371,7 +6361,7 @@ static int do_md_stop(struct mddev *mddev, int mode,
return -EBUSY;
}
if (mddev->pers) {
- if (mddev->ro)
+ if (!md_is_rdwr(mddev))
set_disk_ro(disk, 0);
__md_stop_writes(mddev);
@@ -6388,8 +6378,8 @@ static int do_md_stop(struct mddev *mddev, int mode,
mutex_unlock(&mddev->open_mutex);
mddev->changed = 1;
- if (mddev->ro)
- mddev->ro = 0;
+ if (!md_is_rdwr(mddev))
+ mddev->ro = MD_RDWR;
} else
mutex_unlock(&mddev->open_mutex);
/*
@@ -7204,7 +7194,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
mddev->sync_thread)
return -EBUSY;
- if (mddev->ro)
+ if (!md_is_rdwr(mddev))
return -EROFS;
rdev_for_each(rdev, mddev) {
@@ -7234,7 +7224,7 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
/* change the number of raid disks */
if (mddev->pers->check_reshape == NULL)
return -EINVAL;
- if (mddev->ro)
+ if (!md_is_rdwr(mddev))
return -EROFS;
if (raid_disks <= 0 ||
(mddev->max_disks && raid_disks >= mddev->max_disks))
@@ -7464,6 +7454,40 @@ static inline bool md_ioctl_valid(unsigned int cmd)
}
}
+static int __md_set_array_info(struct mddev *mddev, void __user *argp)
+{
+ mdu_array_info_t info;
+ int err;
+
+ if (!argp)
+ memset(&info, 0, sizeof(info));
+ else if (copy_from_user(&info, argp, sizeof(info)))
+ return -EFAULT;
+
+ if (mddev->pers) {
+ err = update_array_info(mddev, &info);
+ if (err)
+ pr_warn("md: couldn't update array info. %d\n", err);
+ return err;
+ }
+
+ if (!list_empty(&mddev->disks)) {
+ pr_warn("md: array %s already has disks!\n", mdname(mddev));
+ return -EBUSY;
+ }
+
+ if (mddev->raid_disks) {
+ pr_warn("md: array %s already initialised!\n", mdname(mddev));
+ return -EBUSY;
+ }
+
+ err = md_set_array_info(mddev, &info);
+ if (err)
+ pr_warn("md: couldn't set array info. %d\n", err);
+
+ return err;
+}
+
static int md_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
@@ -7569,36 +7593,7 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
}
if (cmd == SET_ARRAY_INFO) {
- mdu_array_info_t info;
- if (!arg)
- memset(&info, 0, sizeof(info));
- else if (copy_from_user(&info, argp, sizeof(info))) {
- err = -EFAULT;
- goto unlock;
- }
- if (mddev->pers) {
- err = update_array_info(mddev, &info);
- if (err) {
- pr_warn("md: couldn't update array info. %d\n", err);
- goto unlock;
- }
- goto unlock;
- }
- if (!list_empty(&mddev->disks)) {
- pr_warn("md: array %s already has disks!\n", mdname(mddev));
- err = -EBUSY;
- goto unlock;
- }
- if (mddev->raid_disks) {
- pr_warn("md: array %s already initialised!\n", mdname(mddev));
- err = -EBUSY;
- goto unlock;
- }
- err = md_set_array_info(mddev, &info);
- if (err) {
- pr_warn("md: couldn't set array info. %d\n", err);
- goto unlock;
- }
+ err = __md_set_array_info(mddev, argp);
goto unlock;
}
@@ -7658,26 +7653,25 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
* The remaining ioctls are changing the state of the
* superblock, so we do not allow them on read-only arrays.
*/
- if (mddev->ro && mddev->pers) {
- if (mddev->ro == 2) {
- mddev->ro = 0;
- sysfs_notify_dirent_safe(mddev->sysfs_state);
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- /* mddev_unlock will wake thread */
- /* If a device failed while we were read-only, we
- * need to make sure the metadata is updated now.
- */
- if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
- mddev_unlock(mddev);
- wait_event(mddev->sb_wait,
- !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
- !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
- mddev_lock_nointr(mddev);
- }
- } else {
+ if (!md_is_rdwr(mddev) && mddev->pers) {
+ if (mddev->ro != MD_AUTO_READ) {
err = -EROFS;
goto unlock;
}
+ mddev->ro = MD_RDWR;
+ sysfs_notify_dirent_safe(mddev->sysfs_state);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ /* mddev_unlock will wake thread */
+ /* If a device failed while we were read-only, we
+ * need to make sure the metadata is updated now.
+ */
+ if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
+ mddev_unlock(mddev);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
+ !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
+ mddev_lock_nointr(mddev);
+ }
}
switch (cmd) {
@@ -7763,11 +7757,11 @@ static int md_set_read_only(struct block_device *bdev, bool ro)
* Transitioning to read-auto need only happen for arrays that call
* md_write_start and which are not ready for writes yet.
*/
- if (!ro && mddev->ro == 1 && mddev->pers) {
+ if (!ro && mddev->ro == MD_RDONLY && mddev->pers) {
err = restart_array(mddev);
if (err)
goto out_unlock;
- mddev->ro = 2;
+ mddev->ro = MD_AUTO_READ;
}
out_unlock:
@@ -8241,9 +8235,9 @@ static int md_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s : %sactive", mdname(mddev),
mddev->pers ? "" : "in");
if (mddev->pers) {
- if (mddev->ro==1)
+ if (mddev->ro == MD_RDONLY)
seq_printf(seq, " (read-only)");
- if (mddev->ro==2)
+ if (mddev->ro == MD_AUTO_READ)
seq_printf(seq, " (auto-read-only)");
seq_printf(seq, " %s", mddev->pers->name);
}
@@ -8502,10 +8496,10 @@ bool md_write_start(struct mddev *mddev, struct bio *bi)
if (bio_data_dir(bi) != WRITE)
return true;
- BUG_ON(mddev->ro == 1);
- if (mddev->ro == 2) {
+ BUG_ON(mddev->ro == MD_RDONLY);
+ if (mddev->ro == MD_AUTO_READ) {
/* need to switch to read/write */
- mddev->ro = 0;
+ mddev->ro = MD_RDWR;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread);
@@ -8556,7 +8550,7 @@ void md_write_inc(struct mddev *mddev, struct bio *bi)
{
if (bio_data_dir(bi) != WRITE)
return;
- WARN_ON_ONCE(mddev->in_sync || mddev->ro);
+ WARN_ON_ONCE(mddev->in_sync || !md_is_rdwr(mddev));
percpu_ref_get(&mddev->writes_pending);
}
EXPORT_SYMBOL(md_write_inc);
@@ -8661,7 +8655,7 @@ void md_allow_write(struct mddev *mddev)
{
if (!mddev->pers)
return;
- if (mddev->ro)
+ if (!md_is_rdwr(mddev))
return;
if (!mddev->pers->sync_request)
return;
@@ -8709,7 +8703,7 @@ void md_do_sync(struct md_thread *thread)
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
test_bit(MD_RECOVERY_WAIT, &mddev->recovery))
return;
- if (mddev->ro) {/* never try to sync a read-only array */
+ if (!md_is_rdwr(mddev)) {/* never try to sync a read-only array */
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
return;
}
@@ -9178,9 +9172,9 @@ static int remove_and_add_spares(struct mddev *mddev,
if (test_bit(Faulty, &rdev->flags))
continue;
if (!test_bit(Journal, &rdev->flags)) {
- if (mddev->ro &&
- ! (rdev->saved_raid_disk >= 0 &&
- !test_bit(Bitmap_sync, &rdev->flags)))
+ if (!md_is_rdwr(mddev) &&
+ !(rdev->saved_raid_disk >= 0 &&
+ !test_bit(Bitmap_sync, &rdev->flags)))
continue;
rdev->recovery_offset = 0;
@@ -9278,7 +9272,8 @@ void md_check_recovery(struct mddev *mddev)
flush_signals(current);
}
- if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+ if (!md_is_rdwr(mddev) &&
+ !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
return;
if ( ! (
(mddev->sb_flags & ~ (1<<MD_SB_CHANGE_PENDING)) ||
@@ -9297,7 +9292,7 @@ void md_check_recovery(struct mddev *mddev)
if (!mddev->external && mddev->safemode == 1)
mddev->safemode = 0;
- if (mddev->ro) {
+ if (!md_is_rdwr(mddev)) {
struct md_rdev *rdev;
if (!mddev->external && mddev->in_sync)
/* 'Blocked' flag not needed as failed devices
diff --git a/drivers/md/md.h b/drivers/md/md.h
index b4e2d8b87b61..554a9026669a 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -782,7 +782,6 @@ extern void mddev_resume(struct mddev *mddev);
extern void md_reload_sb(struct mddev *mddev, int raid_disk);
extern void md_update_sb(struct mddev *mddev, int force);
-extern void md_kick_rdev_from_array(struct md_rdev * rdev);
extern void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
bool is_suspend);
extern void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 857c49399c28..b536befd8898 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -398,7 +398,6 @@ static int raid0_run(struct mddev *mddev)
blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
blk_queue_max_write_zeroes_sectors(mddev->queue, mddev->chunk_sectors);
- blk_queue_max_discard_sectors(mddev->queue, UINT_MAX);
blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
blk_queue_io_opt(mddev->queue,
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 05d8438cfec8..68a9e2d9985b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1321,7 +1321,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
read_bio->bi_iter.bi_sector = r1_bio->sector +
mirror->rdev->data_offset;
read_bio->bi_end_io = raid1_end_read_request;
- bio_set_op_attrs(read_bio, op, do_sync);
+ read_bio->bi_opf = op | do_sync;
if (test_bit(FailFast, &mirror->rdev->flags) &&
test_bit(R1BIO_FailFast, &r1_bio->state))
read_bio->bi_opf |= MD_FAILFAST;
@@ -2254,7 +2254,7 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
continue;
}
- bio_set_op_attrs(wbio, REQ_OP_WRITE, 0);
+ wbio->bi_opf = REQ_OP_WRITE;
if (test_bit(FailFast, &conf->mirrors[i].rdev->flags))
wbio->bi_opf |= MD_FAILFAST;
@@ -2419,7 +2419,7 @@ static int narrow_write_error(struct r1bio *r1_bio, int i)
GFP_NOIO, &mddev->bio_set);
}
- bio_set_op_attrs(wbio, REQ_OP_WRITE, 0);
+ wbio->bi_opf = REQ_OP_WRITE;
wbio->bi_iter.bi_sector = r1_bio->sector;
wbio->bi_iter.bi_size = r1_bio->sectors << 9;
@@ -2770,7 +2770,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
if (i < conf->raid_disks)
still_degraded = 1;
} else if (!test_bit(In_sync, &rdev->flags)) {
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ bio->bi_opf = REQ_OP_WRITE;
bio->bi_end_io = end_sync_write;
write_targets ++;
} else {
@@ -2797,7 +2797,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
if (disk < 0)
disk = i;
}
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ bio->bi_opf = REQ_OP_READ;
bio->bi_end_io = end_sync_read;
read_targets++;
} else if (!test_bit(WriteErrorSeen, &rdev->flags) &&
@@ -2809,7 +2809,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
* if we are doing resync or repair. Otherwise, leave
* this device alone for this sync request.
*/
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ bio->bi_opf = REQ_OP_WRITE;
bio->bi_end_io = end_sync_write;
write_targets++;
}
@@ -3159,6 +3159,7 @@ static int raid1_run(struct mddev *mddev)
* RAID1 needs at least one disk in active
*/
if (conf->raid_disks - mddev->degraded < 1) {
+ md_unregister_thread(&conf->thread);
ret = -EINVAL;
goto abort;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 3aa8b6e11d58..6c66357f92f5 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1254,7 +1254,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
choose_data_offset(r10_bio, rdev);
read_bio->bi_end_io = raid10_end_read_request;
- bio_set_op_attrs(read_bio, op, do_sync);
+ read_bio->bi_opf = op | do_sync;
if (test_bit(FailFast, &rdev->flags) &&
test_bit(R10BIO_FailFast, &r10_bio->state))
read_bio->bi_opf |= MD_FAILFAST;
@@ -1301,7 +1301,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
mbio->bi_iter.bi_sector = (r10_bio->devs[n_copy].addr +
choose_data_offset(r10_bio, rdev));
mbio->bi_end_io = raid10_end_write_request;
- bio_set_op_attrs(mbio, op, do_sync | do_fua);
+ mbio->bi_opf = op | do_sync | do_fua;
if (!replacement && test_bit(FailFast,
&conf->mirrors[devnum].rdev->flags)
&& enough(conf, devnum))
@@ -2933,7 +2933,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i)
wsector = r10_bio->devs[i].addr + (sector - r10_bio->sector);
wbio->bi_iter.bi_sector = wsector +
choose_data_offset(r10_bio, rdev);
- bio_set_op_attrs(wbio, REQ_OP_WRITE, 0);
+ wbio->bi_opf = REQ_OP_WRITE;
if (submit_bio_wait(wbio) < 0)
/* Failure! */
@@ -3542,7 +3542,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio->bi_next = biolist;
biolist = bio;
bio->bi_end_io = end_sync_read;
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ bio->bi_opf = REQ_OP_READ;
if (test_bit(FailFast, &rdev->flags))
bio->bi_opf |= MD_FAILFAST;
from_addr = r10_bio->devs[j].addr;
@@ -3567,7 +3567,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio->bi_next = biolist;
biolist = bio;
bio->bi_end_io = end_sync_write;
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ bio->bi_opf = REQ_OP_WRITE;
bio->bi_iter.bi_sector = to_addr
+ mrdev->data_offset;
bio_set_dev(bio, mrdev->bdev);
@@ -3588,7 +3588,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio->bi_next = biolist;
biolist = bio;
bio->bi_end_io = end_sync_write;
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ bio->bi_opf = REQ_OP_WRITE;
bio->bi_iter.bi_sector = to_addr +
mreplace->data_offset;
bio_set_dev(bio, mreplace->bdev);
@@ -3742,7 +3742,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio->bi_next = biolist;
biolist = bio;
bio->bi_end_io = end_sync_read;
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ bio->bi_opf = REQ_OP_READ;
if (test_bit(FailFast, &rdev->flags))
bio->bi_opf |= MD_FAILFAST;
bio->bi_iter.bi_sector = sector + rdev->data_offset;
@@ -3764,7 +3764,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio->bi_next = biolist;
biolist = bio;
bio->bi_end_io = end_sync_write;
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ bio->bi_opf = REQ_OP_WRITE;
if (test_bit(FailFast, &rdev->flags))
bio->bi_opf |= MD_FAILFAST;
bio->bi_iter.bi_sector = sector + rdev->data_offset;
@@ -4145,8 +4145,6 @@ static int raid10_run(struct mddev *mddev)
conf->thread = NULL;
if (mddev->queue) {
- blk_queue_max_discard_sectors(mddev->queue,
- UINT_MAX);
blk_queue_max_write_zeroes_sectors(mddev->queue, 0);
blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
raid10_set_io_opt(conf);
@@ -4972,7 +4970,7 @@ read_more:
b->bi_iter.bi_sector = r10_bio->devs[s/2].addr +
rdev2->new_data_offset;
b->bi_end_io = end_reshape_write;
- bio_set_op_attrs(b, REQ_OP_WRITE, 0);
+ b->bi_opf = REQ_OP_WRITE;
b->bi_next = blist;
blist = b;
}
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
index 832d8566e165..46182b955aef 100644
--- a/drivers/md/raid5-cache.c
+++ b/drivers/md/raid5-cache.c
@@ -1565,11 +1565,12 @@ void r5l_wake_reclaim(struct r5l_log *log, sector_t space)
if (!log)
return;
+
+ target = READ_ONCE(log->reclaim_target);
do {
- target = log->reclaim_target;
if (new < target)
return;
- } while (cmpxchg(&log->reclaim_target, target, new) != target);
+ } while (!try_cmpxchg(&log->reclaim_target, &target, new));
md_wakeup_thread(log->reclaim_thread);
}
@@ -3061,7 +3062,6 @@ void r5c_update_on_rdev_error(struct mddev *mddev, struct md_rdev *rdev)
int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
{
- struct request_queue *q = bdev_get_queue(rdev->bdev);
struct r5l_log *log;
int ret;
@@ -3090,9 +3090,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
if (!log)
return -ENOMEM;
log->rdev = rdev;
-
- log->need_cache_flush = test_bit(QUEUE_FLAG_WC, &q->queue_flags) != 0;
-
+ log->need_cache_flush = bdev_write_cache(rdev->bdev);
log->uuid_checksum = crc32c_le(~0, rdev->mddev->uuid,
sizeof(rdev->mddev->uuid));
diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c
index 31b9157bc9ae..e495939bb3e0 100644
--- a/drivers/md/raid5-ppl.c
+++ b/drivers/md/raid5-ppl.c
@@ -1301,8 +1301,6 @@ static int ppl_validate_rdev(struct md_rdev *rdev)
static void ppl_init_child_log(struct ppl_log *log, struct md_rdev *rdev)
{
- struct request_queue *q;
-
if ((rdev->ppl.size << 9) >= (PPL_SPACE_SIZE +
PPL_HEADER_SIZE) * 2) {
log->use_multippl = true;
@@ -1316,8 +1314,7 @@ static void ppl_init_child_log(struct ppl_log *log, struct md_rdev *rdev)
}
log->next_io_sector = rdev->ppl.sector;
- q = bdev_get_queue(rdev->bdev);
- if (test_bit(QUEUE_FLAG_WC, &q->queue_flags))
+ if (bdev_write_cache(rdev->bdev))
log->wb_cache_on = true;
}
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 283b78b5766e..6abc9302cd84 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -182,7 +182,7 @@ config MEDIA_CONTROLLER
#
config DVB_CORE
- tristate
+ tristate "DVB Core"
depends on MEDIA_DIGITAL_TV_SUPPORT
depends on (I2C || I2C=n)
default MEDIA_DIGITAL_TV_SUPPORT
diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c
index 40db7911b437..7b2db46a5722 100644
--- a/drivers/media/cec/platform/stm32/stm32-cec.c
+++ b/drivers/media/cec/platform/stm32/stm32-cec.c
@@ -288,12 +288,9 @@ static int stm32_cec_probe(struct platform_device *pdev)
return ret;
cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
- if (IS_ERR(cec->clk_cec)) {
- if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Cannot get cec clock\n");
-
- return PTR_ERR(cec->clk_cec);
- }
+ if (IS_ERR(cec->clk_cec))
+ return dev_err_probe(&pdev->dev, PTR_ERR(cec->clk_cec),
+ "Cannot get cec clock\n");
ret = clk_prepare(cec->clk_cec);
if (ret) {
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 303d02b1d71c..a366566f22c3 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -872,7 +872,7 @@ static void precalculate_color(struct tpg_data *tpg, int k)
} else if (tpg->pattern == TPG_PAT_NOISE) {
r = g = b = get_random_u8();
} else if (k == TPG_COLOR_RANDOM) {
- r = g = b = tpg->qual_offset + prandom_u32_max(196);
+ r = g = b = tpg->qual_offset + get_random_u32_below(196);
} else if (k >= TPG_COLOR_RAMP) {
r = g = b = k - TPG_COLOR_RAMP;
}
@@ -2286,7 +2286,7 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg,
params->wss_width = tpg->crop.width;
params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
params->wss_random_offset =
- params->twopixsize * prandom_u32_max(tpg->src_width / 2);
+ params->twopixsize * get_random_u32_below(tpg->src_width / 2);
if (tpg->crop.left < tpg->border.left) {
left_pillar_width = tpg->border.left - tpg->crop.left;
@@ -2495,9 +2495,9 @@ static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
linestart_newer = tpg->black_line[p];
} else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
linestart_older = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
+ twopixsize * get_random_u32_below(tpg->src_width / 2);
linestart_newer = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
+ twopixsize * get_random_u32_below(tpg->src_width / 2);
} else {
unsigned frame_line_old =
(frame_line + mv_vert_old) % tpg->src_height;
diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c
index 542dde9d2609..89eebc3341b8 100644
--- a/drivers/media/common/videobuf2/frame_vector.c
+++ b/drivers/media/common/videobuf2/frame_vector.c
@@ -14,6 +14,7 @@
* get_vaddr_frames() - map virtual addresses to pfns
* @start: starting user address
* @nr_frames: number of pages / pfns from start to map
+ * @write: the mapped address has write permission
* @vec: structure which receives pages / pfns of the addresses mapped.
* It should have space for at least nr_frames entries.
*
@@ -32,14 +33,11 @@
*
* This function takes care of grabbing mmap_lock as necessary.
*/
-int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
+int get_vaddr_frames(unsigned long start, unsigned int nr_frames, bool write,
struct frame_vector *vec)
{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- int ret_pin_user_pages_fast = 0;
- int ret = 0;
- int err;
+ int ret;
+ unsigned int gup_flags = FOLL_FORCE | FOLL_LONGTERM;
if (nr_frames == 0)
return 0;
@@ -49,60 +47,22 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
start = untagged_addr(start);
- ret = pin_user_pages_fast(start, nr_frames,
- FOLL_FORCE | FOLL_WRITE | FOLL_LONGTERM,
+ if (write)
+ gup_flags |= FOLL_WRITE;
+
+ ret = pin_user_pages_fast(start, nr_frames, gup_flags,
(struct page **)(vec->ptrs));
- if (ret > 0) {
- vec->got_ref = true;
- vec->is_pfns = false;
- goto out_unlocked;
- }
- ret_pin_user_pages_fast = ret;
-
- mmap_read_lock(mm);
- vec->got_ref = false;
- vec->is_pfns = true;
- ret = 0;
- do {
- unsigned long *nums = frame_vector_pfns(vec);
-
- vma = vma_lookup(mm, start);
- if (!vma)
- break;
-
- while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) {
- err = follow_pfn(vma, start, &nums[ret]);
- if (err) {
- if (ret)
- goto out;
- // If follow_pfn() returns -EINVAL, then this
- // is not an IO mapping or a raw PFN mapping.
- // In that case, return the original error from
- // pin_user_pages_fast(). Otherwise this
- // function would return -EINVAL when
- // pin_user_pages_fast() returned -ENOMEM,
- // which makes debugging hard.
- if (err == -EINVAL && ret_pin_user_pages_fast)
- ret = ret_pin_user_pages_fast;
- else
- ret = err;
- goto out;
- }
- start += PAGE_SIZE;
- ret++;
- }
- /* Bail out if VMA doesn't completely cover the tail page. */
- if (start < vma->vm_end)
- break;
- } while (ret < nr_frames);
-out:
- mmap_read_unlock(mm);
-out_unlocked:
- if (!ret)
- ret = -EFAULT;
- if (ret > 0)
- vec->nr_frames = ret;
- return ret;
+ vec->got_ref = true;
+ vec->is_pfns = false;
+ vec->nr_frames = ret;
+
+ if (likely(ret > 0))
+ return ret;
+
+ /* This used to (racily) return non-refcounted pfns. Let people know */
+ WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping");
+ vec->nr_frames = 0;
+ return ret ? ret : -EFAULT;
}
EXPORT_SYMBOL(get_vaddr_frames);
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index ab9697f3b5f1..fc3758a5bc1c 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -544,6 +544,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
*/
if (q->num_buffers) {
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
+ q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||
q->cnt_wait_prepare != q->cnt_wait_finish;
if (unbalanced || debug) {
@@ -552,14 +553,18 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
pr_info(" setup: %u start_streaming: %u stop_streaming: %u\n",
q->cnt_queue_setup, q->cnt_start_streaming,
q->cnt_stop_streaming);
+ pr_info(" prepare_streaming: %u unprepare_streaming: %u\n",
+ q->cnt_prepare_streaming, q->cnt_unprepare_streaming);
pr_info(" wait_prepare: %u wait_finish: %u\n",
q->cnt_wait_prepare, q->cnt_wait_finish);
}
q->cnt_queue_setup = 0;
q->cnt_wait_prepare = 0;
q->cnt_wait_finish = 0;
+ q->cnt_prepare_streaming = 0;
q->cnt_start_streaming = 0;
q->cnt_stop_streaming = 0;
+ q->cnt_unprepare_streaming = 0;
}
for (buffer = 0; buffer < q->num_buffers; ++buffer) {
struct vb2_buffer *vb = q->bufs[buffer];
@@ -813,7 +818,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
num_buffers = max_t(unsigned int, *count, q->min_buffers_needed);
num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
+ /*
+ * Set this now to ensure that drivers see the correct q->memory value
+ * in the queue_setup op.
+ */
+ mutex_lock(&q->mmap_lock);
q->memory = memory;
+ mutex_unlock(&q->mmap_lock);
set_queue_coherency(q, non_coherent_mem);
/*
@@ -823,22 +834,27 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
plane_sizes, q->alloc_devs);
if (ret)
- return ret;
+ goto error;
/* Check that driver has set sane values */
- if (WARN_ON(!num_planes))
- return -EINVAL;
+ if (WARN_ON(!num_planes)) {
+ ret = -EINVAL;
+ goto error;
+ }
for (i = 0; i < num_planes; i++)
- if (WARN_ON(!plane_sizes[i]))
- return -EINVAL;
+ if (WARN_ON(!plane_sizes[i])) {
+ ret = -EINVAL;
+ goto error;
+ }
/* Finally, allocate buffers and video memory */
allocated_buffers =
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
if (allocated_buffers == 0) {
dprintk(q, 1, "memory allocation failed\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto error;
}
/*
@@ -879,7 +895,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) {
/*
* Note: __vb2_queue_free() will subtract 'allocated_buffers'
- * from q->num_buffers.
+ * from q->num_buffers and it will reset q->memory to
+ * VB2_MEMORY_UNKNOWN.
*/
__vb2_queue_free(q, allocated_buffers);
mutex_unlock(&q->mmap_lock);
@@ -895,6 +912,12 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
q->waiting_for_buffers = !q->is_output;
return 0;
+
+error:
+ mutex_lock(&q->mmap_lock);
+ q->memory = VB2_MEMORY_UNKNOWN;
+ mutex_unlock(&q->mmap_lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
@@ -906,6 +929,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int num_planes = 0, num_buffers, allocated_buffers;
unsigned plane_sizes[VB2_MAX_PLANES] = { };
bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
+ bool no_previous_buffers = !q->num_buffers;
int ret;
if (q->num_buffers == VB2_MAX_FRAME) {
@@ -913,13 +937,19 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
return -ENOBUFS;
}
- if (!q->num_buffers) {
+ if (no_previous_buffers) {
if (q->waiting_in_dqbuf && *count) {
dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n");
return -EBUSY;
}
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
+ /*
+ * Set this now to ensure that drivers see the correct q->memory
+ * value in the queue_setup op.
+ */
+ mutex_lock(&q->mmap_lock);
q->memory = memory;
+ mutex_unlock(&q->mmap_lock);
q->waiting_for_buffers = !q->is_output;
set_queue_coherency(q, non_coherent_mem);
} else {
@@ -945,14 +975,15 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
ret = call_qop(q, queue_setup, q, &num_buffers,
&num_planes, plane_sizes, q->alloc_devs);
if (ret)
- return ret;
+ goto error;
/* Finally, allocate buffers and video memory */
allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
num_planes, plane_sizes);
if (allocated_buffers == 0) {
dprintk(q, 1, "memory allocation failed\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto error;
}
/*
@@ -983,7 +1014,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) {
/*
* Note: __vb2_queue_free() will subtract 'allocated_buffers'
- * from q->num_buffers.
+ * from q->num_buffers and it will reset q->memory to
+ * VB2_MEMORY_UNKNOWN.
*/
__vb2_queue_free(q, allocated_buffers);
mutex_unlock(&q->mmap_lock);
@@ -998,6 +1030,14 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
*count = allocated_buffers;
return 0;
+
+error:
+ if (no_previous_buffers) {
+ mutex_lock(&q->mmap_lock);
+ q->memory = VB2_MEMORY_UNKNOWN;
+ mutex_unlock(&q->mmap_lock);
+ }
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_core_create_bufs);
@@ -1991,6 +2031,9 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
if (q->start_streaming_called)
call_void_qop(q, stop_streaming, q);
+ if (q->streaming)
+ call_void_qop(q, unprepare_streaming, q);
+
/*
* If you see this warning, then the driver isn't cleaning up properly
* in stop_streaming(). See the stop_streaming() documentation in
@@ -2102,23 +2145,29 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
return -EINVAL;
}
+ ret = call_qop(q, prepare_streaming, q);
+ if (ret)
+ return ret;
+
+ q->streaming = 1;
+
/*
* Tell driver to start streaming provided sufficient buffers
* are available.
*/
if (q->queued_count >= q->min_buffers_needed) {
- ret = v4l_vb2q_enable_media_source(q);
- if (ret)
- return ret;
ret = vb2_start_streaming(q);
if (ret)
- return ret;
+ goto unprepare;
}
- q->streaming = 1;
-
dprintk(q, 3, "successful\n");
return 0;
+
+unprepare:
+ call_void_qop(q, unprepare_streaming, q);
+ q->streaming = 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_core_streamon);
@@ -2165,6 +2214,22 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
unsigned int buffer, plane;
/*
+ * Sanity checks to ensure the lock is held, MEMORY_MMAP is
+ * used and fileio isn't active.
+ */
+ lockdep_assert_held(&q->mmap_lock);
+
+ if (q->memory != VB2_MEMORY_MMAP) {
+ dprintk(q, 1, "queue is not currently set up for mmap\n");
+ return -EINVAL;
+ }
+
+ if (vb2_fileio_is_active(q)) {
+ dprintk(q, 1, "file io in progress\n");
+ return -EBUSY;
+ }
+
+ /*
* Go over all buffers and their planes, comparing the given offset
* with an offset assigned to each plane. If a match is found,
* return its buffer and plane numbers.
@@ -2265,11 +2330,6 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
int ret;
unsigned long length;
- if (q->memory != VB2_MEMORY_MMAP) {
- dprintk(q, 1, "queue is not currently set up for mmap\n");
- return -EINVAL;
- }
-
/*
* Check memory area access mode.
*/
@@ -2291,14 +2351,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
mutex_lock(&q->mmap_lock);
- if (vb2_fileio_is_active(q)) {
- dprintk(q, 1, "mmap: file io in progress\n");
- ret = -EBUSY;
- goto unlock;
- }
-
/*
- * Find the plane corresponding to the offset passed by userspace.
+ * Find the plane corresponding to the offset passed by userspace. This
+ * will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
ret = __find_plane_by_offset(q, off, &buffer, &plane);
if (ret)
@@ -2351,22 +2406,25 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
void *vaddr;
int ret;
- if (q->memory != VB2_MEMORY_MMAP) {
- dprintk(q, 1, "queue is not currently set up for mmap\n");
- return -EINVAL;
- }
+ mutex_lock(&q->mmap_lock);
/*
- * Find the plane corresponding to the offset passed by userspace.
+ * Find the plane corresponding to the offset passed by userspace. This
+ * will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
ret = __find_plane_by_offset(q, off, &buffer, &plane);
if (ret)
- return ret;
+ goto unlock;
vb = q->bufs[buffer];
vaddr = vb2_plane_vaddr(vb, plane);
+ mutex_unlock(&q->mmap_lock);
return vaddr ? (unsigned long)vaddr : -EINVAL;
+
+unlock:
+ mutex_unlock(&q->mmap_lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
#endif
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index 678b359717c4..5f1175f8b349 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -11,6 +11,7 @@
*/
#include <linux/dma-buf.h>
+#include <linux/dma-resv.h>
#include <linux/module.h>
#include <linux/refcount.h>
#include <linux/scatterlist.h>
@@ -101,7 +102,7 @@ static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv)
if (buf->db_attach) {
struct iosys_map map;
- if (!dma_buf_vmap(buf->db_attach->dmabuf, &map))
+ if (!dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map))
buf->vaddr = map.vaddr;
return buf->vaddr;
@@ -382,18 +383,12 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
struct vb2_dc_attachment *attach = db_attach->priv;
- /* stealing dmabuf mutex to serialize map/unmap operations */
- struct mutex *lock = &db_attach->dmabuf->lock;
struct sg_table *sgt;
- mutex_lock(lock);
-
sgt = &attach->sgt;
/* return previously mapped sg table */
- if (attach->dma_dir == dma_dir) {
- mutex_unlock(lock);
+ if (attach->dma_dir == dma_dir)
return sgt;
- }
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
@@ -409,14 +404,11 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
if (dma_map_sgtable(db_attach->dev, sgt, dma_dir,
DMA_ATTR_SKIP_CPU_SYNC)) {
pr_err("failed to map scatterlist\n");
- mutex_unlock(lock);
return ERR_PTR(-EIO);
}
attach->dma_dir = dma_dir;
- mutex_unlock(lock);
-
return sgt;
}
@@ -464,6 +456,8 @@ static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct iosys_map *map)
static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf,
struct vm_area_struct *vma)
{
+ dma_resv_assert_held(dbuf->resv);
+
return vb2_dc_mmap(dbuf->priv, vma);
}
@@ -603,7 +597,8 @@ static void *vb2_dc_get_userptr(struct vb2_buffer *vb, struct device *dev,
buf->vb = vb;
offset = lower_32_bits(offset_in_page(vaddr));
- vec = vb2_create_framevec(vaddr, size);
+ vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE ||
+ buf->dma_dir == DMA_BIDIRECTIONAL);
if (IS_ERR(vec)) {
ret = PTR_ERR(vec);
goto fail_buf;
@@ -711,7 +706,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv)
}
/* get the associated scatterlist for this buffer */
- sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
+ sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir);
if (IS_ERR(sgt)) {
pr_err("Error getting dmabuf scatterlist\n");
return -EINVAL;
@@ -722,7 +717,8 @@ static int vb2_dc_map_dmabuf(void *mem_priv)
if (contig_size < buf->size) {
pr_err("contiguous chunk is too small %lu/%lu\n",
contig_size, buf->size);
- dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);
+ dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt,
+ buf->dma_dir);
return -EFAULT;
}
@@ -750,10 +746,10 @@ static void vb2_dc_unmap_dmabuf(void *mem_priv)
}
if (buf->vaddr) {
- dma_buf_vunmap(buf->db_attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map);
buf->vaddr = NULL;
}
- dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);
+ dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir);
buf->dma_addr = 0;
buf->dma_sgt = NULL;
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index fa69158a65b1..183037fb1273 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -10,6 +10,7 @@
* the Free Software Foundation.
*/
+#include <linux/dma-resv.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/refcount.h>
@@ -241,7 +242,9 @@ static void *vb2_dma_sg_get_userptr(struct vb2_buffer *vb, struct device *dev,
buf->size = size;
buf->dma_sgt = &buf->sg_table;
buf->vb = vb;
- vec = vb2_create_framevec(vaddr, size);
+ vec = vb2_create_framevec(vaddr, size,
+ buf->dma_dir == DMA_FROM_DEVICE ||
+ buf->dma_dir == DMA_BIDIRECTIONAL);
if (IS_ERR(vec))
goto userptr_fail_pfnvec;
buf->vec = vec;
@@ -309,7 +312,7 @@ static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv)
if (!buf->vaddr) {
if (buf->db_attach) {
- ret = dma_buf_vmap(buf->db_attach->dmabuf, &map);
+ ret = dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map);
buf->vaddr = ret ? NULL : map.vaddr;
} else {
buf->vaddr = vm_map_ram(buf->pages, buf->num_pages, -1);
@@ -424,18 +427,12 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map(
struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
struct vb2_dma_sg_attachment *attach = db_attach->priv;
- /* stealing dmabuf mutex to serialize map/unmap operations */
- struct mutex *lock = &db_attach->dmabuf->lock;
struct sg_table *sgt;
- mutex_lock(lock);
-
sgt = &attach->sgt;
/* return previously mapped sg table */
- if (attach->dma_dir == dma_dir) {
- mutex_unlock(lock);
+ if (attach->dma_dir == dma_dir)
return sgt;
- }
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
@@ -446,14 +443,11 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map(
/* mapping to the client with new direction */
if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
pr_err("failed to map scatterlist\n");
- mutex_unlock(lock);
return ERR_PTR(-EIO);
}
attach->dma_dir = dma_dir;
- mutex_unlock(lock);
-
return sgt;
}
@@ -504,6 +498,8 @@ static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf,
struct vm_area_struct *vma)
{
+ dma_resv_assert_held(dbuf->resv);
+
return vb2_dma_sg_mmap(dbuf->priv, vma);
}
@@ -565,7 +561,7 @@ static int vb2_dma_sg_map_dmabuf(void *mem_priv)
}
/* get the associated scatterlist for this buffer */
- sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
+ sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir);
if (IS_ERR(sgt)) {
pr_err("Error getting dmabuf scatterlist\n");
return -EINVAL;
@@ -594,10 +590,10 @@ static void vb2_dma_sg_unmap_dmabuf(void *mem_priv)
}
if (buf->vaddr) {
- dma_buf_vunmap(buf->db_attach->dmabuf, &map);
+ dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map);
buf->vaddr = NULL;
}
- dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);
+ dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir);
buf->dma_sgt = NULL;
}
diff --git a/drivers/media/common/videobuf2/videobuf2-memops.c b/drivers/media/common/videobuf2/videobuf2-memops.c
index 9dd6c27162f4..f9a4ec44422e 100644
--- a/drivers/media/common/videobuf2/videobuf2-memops.c
+++ b/drivers/media/common/videobuf2/videobuf2-memops.c
@@ -26,6 +26,7 @@
* vb2_create_framevec() - map virtual addresses to pfns
* @start: Virtual user address where we start mapping
* @length: Length of a range to map
+ * @write: Should we map for writing into the area
*
* This function allocates and fills in a vector with pfns corresponding to
* virtual address range passed in arguments. If pfns have corresponding pages,
@@ -34,7 +35,8 @@
* failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
*/
struct frame_vector *vb2_create_framevec(unsigned long start,
- unsigned long length)
+ unsigned long length,
+ bool write)
{
int ret;
unsigned long first, last;
@@ -47,7 +49,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
vec = frame_vector_create(nr);
if (!vec)
return ERR_PTR(-ENOMEM);
- ret = get_vaddr_frames(start & PAGE_MASK, nr, vec);
+ ret = get_vaddr_frames(start & PAGE_MASK, nr, write, vec);
if (ret < 0)
goto out_destroy;
/* We accept only complete set of PFNs */
diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
index 948152f1596b..959b45beb1f3 100644
--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
@@ -10,6 +10,7 @@
* the Free Software Foundation.
*/
+#include <linux/dma-resv.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mm.h>
@@ -85,7 +86,9 @@ static void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev,
buf->dma_dir = vb->vb2_queue->dma_dir;
offset = vaddr & ~PAGE_MASK;
buf->size = size;
- vec = vb2_create_framevec(vaddr, size);
+ vec = vb2_create_framevec(vaddr, size,
+ buf->dma_dir == DMA_FROM_DEVICE ||
+ buf->dma_dir == DMA_BIDIRECTIONAL);
if (IS_ERR(vec)) {
ret = PTR_ERR(vec);
goto fail_pfnvec_create;
@@ -267,18 +270,12 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map(
struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
struct vb2_vmalloc_attachment *attach = db_attach->priv;
- /* stealing dmabuf mutex to serialize map/unmap operations */
- struct mutex *lock = &db_attach->dmabuf->lock;
struct sg_table *sgt;
- mutex_lock(lock);
-
sgt = &attach->sgt;
/* return previously mapped sg table */
- if (attach->dma_dir == dma_dir) {
- mutex_unlock(lock);
+ if (attach->dma_dir == dma_dir)
return sgt;
- }
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
@@ -289,14 +286,11 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map(
/* mapping to the client with new direction */
if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
pr_err("failed to map scatterlist\n");
- mutex_unlock(lock);
return ERR_PTR(-EIO);
}
attach->dma_dir = dma_dir;
- mutex_unlock(lock);
-
return sgt;
}
@@ -325,6 +319,8 @@ static int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf,
static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf,
struct vm_area_struct *vma)
{
+ dma_resv_assert_held(dbuf->resv);
+
return vb2_vmalloc_mmap(dbuf->priv, vma);
}
@@ -376,7 +372,7 @@ static int vb2_vmalloc_map_dmabuf(void *mem_priv)
struct iosys_map map;
int ret;
- ret = dma_buf_vmap(buf->dbuf, &map);
+ ret = dma_buf_vmap_unlocked(buf->dbuf, &map);
if (ret)
return -EFAULT;
buf->vaddr = map.vaddr;
@@ -389,7 +385,7 @@ static void vb2_vmalloc_unmap_dmabuf(void *mem_priv)
struct vb2_vmalloc_buf *buf = mem_priv;
struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
- dma_buf_vunmap(buf->dbuf, &map);
+ dma_buf_vunmap_unlocked(buf->dbuf, &map);
buf->vaddr = NULL;
}
@@ -399,7 +395,7 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv)
struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
if (buf->vaddr)
- dma_buf_vunmap(buf->dbuf, &map);
+ dma_buf_vunmap_unlocked(buf->dbuf, &map);
kfree(buf);
}
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index f6ee678107d3..9ce5f010de3f 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -790,6 +790,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
@@ -1448,7 +1453,10 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ mutex_lock(&dmxdev->mutex);
dmxdev->exit = 1;
+ mutex_unlock(&dmxdev->mutex);
+
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users == 1);
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 15a08d8c69ef..c2d2792227f8 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -157,7 +157,7 @@ static void dvb_ca_private_free(struct dvb_ca_private *ca)
{
unsigned int i;
- dvb_free_device(ca->dvbdev);
+ dvb_device_put(ca->dvbdev);
for (i = 0; i < ca->slot_count; i++)
vfree(ca->slot_info[i].rx_buffer.data);
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 83cc32ad7e12..398c86279b5b 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -233,7 +233,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
{
struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec;
- u16 limit, seclen, n;
+ u16 limit, seclen;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0;
@@ -262,7 +262,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp;
- for (n = 0; sec->secbufp + 2 < limit; n++) {
+ while (sec->secbufp + 2 < limit) {
seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 48e735cdbe6b..cc0a789f09ae 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -136,7 +136,7 @@ static void __dvb_frontend_free(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
if (fepriv)
- dvb_free_device(fepriv->dvbdev);
+ dvb_device_put(fepriv->dvbdev);
dvb_frontend_invoke_release(fe, fe->ops.release);
@@ -918,6 +918,7 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
/* If the standard is for satellite, convert frequencies to kHz */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -943,6 +944,7 @@ static u32 dvb_frontend_get_stepsize(struct dvb_frontend *fe)
u32 step = max(fe_step, tuner_step);
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -974,6 +976,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
/* range check: symbol rate */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -1040,6 +1043,10 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
c->scrambling_sequence_index = 0;/* default sequence */
switch (c->delivery_system) {
+ case SYS_DSS:
+ c->modulation = QPSK;
+ c->rolloff = ROLLOFF_20;
+ break;
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -1821,6 +1828,7 @@ static void prepare_tuning_algo_parameters(struct dvb_frontend *fe)
} else {
/* default values */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_ISDBS:
@@ -2288,6 +2296,9 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
case SYS_DVBC_ANNEX_C:
rolloff = 113;
break;
+ case SYS_DSS:
+ rolloff = 120;
+ break;
case SYS_DVBS:
case SYS_TURBO:
case SYS_ISDBS:
@@ -2754,7 +2765,17 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV;
- if (adapter->mfe_shared) {
+ if (adapter->mfe_shared == 2) {
+ mutex_lock(&adapter->mfe_lock);
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (adapter->mfe_dvbdev &&
+ !adapter->mfe_dvbdev->writers) {
+ mutex_unlock(&adapter->mfe_lock);
+ return -EBUSY;
+ }
+ adapter->mfe_dvbdev = dvbdev;
+ }
+ } else if (adapter->mfe_shared) {
mutex_lock(&adapter->mfe_lock);
if (!adapter->mfe_dvbdev)
@@ -2986,6 +3007,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
.name = fe->ops.info.name,
#endif
};
+ int ret;
dev_dbg(dvb->device, "%s:\n", __func__);
@@ -3019,8 +3041,13 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
"DVB: registering adapter %i frontend %i (%s)...\n",
fe->dvb->num, fe->id, fe->ops.info.name);
- dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+ ret = dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND, 0);
+ if (ret) {
+ dvb_frontend_put(fe);
+ mutex_unlock(&frontend_mutex);
+ return ret;
+ }
/*
* Initialize the cache to the proper values according with the
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index d1d471af0636..7d4558de8e83 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -335,7 +335,9 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
- consumed = (idx - rbuf->pread) % rbuf->size;
+ consumed = (idx - rbuf->pread);
+ if (consumed < 0)
+ consumed += rbuf->size;
while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 675d877a67b2..2a857cf70c94 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -97,7 +97,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
new_fops = fops_get(dvbdev->fops);
if (!new_fops)
goto fail;
- file->private_data = dvbdev;
+ file->private_data = dvb_device_get(dvbdev);
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode, file);
@@ -161,6 +161,9 @@ int dvb_generic_release(struct inode *inode, struct file *file)
}
dvbdev->users++;
+
+ dvb_device_put(dvbdev);
+
return 0;
}
EXPORT_SYMBOL(dvb_generic_release);
@@ -243,7 +246,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
const char *name, int npads)
{
- int i, ret = 0;
+ int i;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
@@ -260,6 +263,7 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
+ int ret;
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
@@ -332,6 +336,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
GFP_KERNEL);
if (!dvbdev->pads) {
kfree(dvbdev->entity);
+ dvbdev->entity = NULL;
return -ENOMEM;
}
}
@@ -478,6 +483,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
}
memcpy(dvbdev, template, sizeof(struct dvb_device));
+ kref_init(&dvbdev->ref);
dvbdev->type = type;
dvbdev->id = id;
dvbdev->adapter = adap;
@@ -508,7 +514,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
#endif
dvbdev->minor = minor;
- dvb_minors[minor] = dvbdev;
+ dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem);
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
@@ -553,6 +559,7 @@ void dvb_remove_device(struct dvb_device *dvbdev)
down_write(&minor_rwsem);
dvb_minors[dvbdev->minor] = NULL;
+ dvb_device_put(dvbdev);
up_write(&minor_rwsem);
dvb_media_device_free(dvbdev);
@@ -564,21 +571,34 @@ void dvb_remove_device(struct dvb_device *dvbdev)
EXPORT_SYMBOL(dvb_remove_device);
-void dvb_free_device(struct dvb_device *dvbdev)
+static void dvb_free_device(struct kref *ref)
{
- if (!dvbdev)
- return;
+ struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
kfree (dvbdev->fops);
kfree (dvbdev);
}
-EXPORT_SYMBOL(dvb_free_device);
+
+
+struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
+{
+ kref_get(&dvbdev->ref);
+ return dvbdev;
+}
+EXPORT_SYMBOL(dvb_device_get);
+
+
+void dvb_device_put(struct dvb_device *dvbdev)
+{
+ if (dvbdev)
+ kref_put(&dvbdev->ref, dvb_free_device);
+}
void dvb_unregister_device(struct dvb_device *dvbdev)
{
dvb_remove_device(dvbdev);
- dvb_free_device(dvbdev);
+ dvb_device_put(dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c
index ba38783b2b4f..cca7cbdd4c7c 100644
--- a/drivers/media/dvb-frontends/a8293.c
+++ b/drivers/media/dvb-frontends/a8293.c
@@ -7,20 +7,148 @@
#include "a8293.h"
+#define A8293_FLAG_ODT 0x10
+
struct a8293_dev {
struct i2c_client *client;
u8 reg[2];
+ int volt_slew_nanos_per_mv;
};
-static int a8293_set_voltage(struct dvb_frontend *fe,
- enum fe_sec_voltage fe_sec_voltage)
+/*
+ * When increasing voltage, do so in minimal steps over time, minimizing
+ * risk of vIN undervoltage.
+ */
+
+static int a8293_set_voltage_slew(struct a8293_dev *dev,
+ struct i2c_client *client,
+ enum fe_sec_voltage fe_sec_voltage,
+ int min_nanos_per_mv)
+{
+ int ret;
+ u8 reg0, reg1;
+ int new_volt_idx;
+ const int idx_to_mv[] = {
+ 0, 12709, 13042, 13375, 14042, 15042, 18042, 18709, 19042
+ };
+ const u8 idx_to_reg[] = {
+ 0x00, 0x20, 0x21, 0x22, 0x24, 0x27, 0x28, 0x2A, 0x2B
+ };
+ int this_volt_idx;
+ u8 status;
+ int prev_volt_idx;
+
+ dev_dbg(&client->dev, "set_voltage_slew fe_sec_voltage=%d\n",
+ fe_sec_voltage);
+
+ /* Read status register to clear any stale faults. */
+ ret = i2c_master_recv(client, &status, 1);
+ if (ret < 0)
+ goto err;
+
+ /* Determine previous voltage */
+ switch (dev->reg[0] & 0x2F) {
+ case 0x00:
+ prev_volt_idx = 0;
+ break;
+ case 0x20:
+ prev_volt_idx = 1;
+ break;
+ case 0x21:
+ prev_volt_idx = 2;
+ break;
+ case 0x22:
+ prev_volt_idx = 3;
+ break;
+ case 0x24:
+ prev_volt_idx = 4;
+ break;
+ case 0x27:
+ prev_volt_idx = 5;
+ break;
+ case 0x28:
+ prev_volt_idx = 6;
+ break;
+ case 0x2A:
+ prev_volt_idx = 7;
+ break;
+ case 0x2B:
+ prev_volt_idx = 8;
+ break;
+ default:
+ prev_volt_idx = 0;
+ }
+
+ /* Determine new voltage */
+ switch (fe_sec_voltage) {
+ case SEC_VOLTAGE_OFF:
+ new_volt_idx = 0;
+ break;
+ case SEC_VOLTAGE_13:
+ new_volt_idx = 2;
+ break;
+ case SEC_VOLTAGE_18:
+ new_volt_idx = 6;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Slew to new voltage if new voltage is greater than current voltage */
+ this_volt_idx = prev_volt_idx;
+ if (this_volt_idx < new_volt_idx) {
+ while (this_volt_idx < new_volt_idx) {
+ int delta_mv = idx_to_mv[this_volt_idx+1] - idx_to_mv[this_volt_idx];
+ int min_wait_time = delta_mv * min_nanos_per_mv;
+
+ reg0 = idx_to_reg[this_volt_idx+1];
+ reg0 |= A8293_FLAG_ODT;
+
+ ret = i2c_master_send(client, &reg0, 1);
+ if (ret < 0)
+ goto err;
+ dev->reg[0] = reg0;
+ this_volt_idx++;
+ usleep_range(min_wait_time, min_wait_time * 2);
+ }
+ } else { /* Else just set the voltage */
+ reg0 = idx_to_reg[new_volt_idx];
+ reg0 |= A8293_FLAG_ODT;
+ ret = i2c_master_send(client, &reg0, 1);
+ if (ret < 0)
+ goto err;
+ dev->reg[0] = reg0;
+ }
+
+ /* TMODE=0, TGATE=1 */
+ reg1 = 0x82;
+ if (reg1 != dev->reg[1]) {
+ ret = i2c_master_send(client, &reg1, 1);
+ if (ret < 0)
+ goto err;
+ dev->reg[1] = reg1;
+ }
+
+ usleep_range(1500, 5000);
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+
+static int a8293_set_voltage_noslew(struct dvb_frontend *fe,
+ enum fe_sec_voltage fe_sec_voltage)
{
struct a8293_dev *dev = fe->sec_priv;
struct i2c_client *client = dev->client;
int ret;
u8 reg0, reg1;
- dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage);
+ dev_dbg(&client->dev, "set_voltage_noslew fe_sec_voltage=%d\n",
+ fe_sec_voltage);
switch (fe_sec_voltage) {
case SEC_VOLTAGE_OFF:
@@ -62,8 +190,27 @@ err:
return ret;
}
-static int a8293_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int a8293_set_voltage(struct dvb_frontend *fe,
+ enum fe_sec_voltage fe_sec_voltage)
+{
+ struct a8293_dev *dev = fe->sec_priv;
+ struct i2c_client *client = dev->client;
+ int volt_slew_nanos_per_mv = dev->volt_slew_nanos_per_mv;
+
+ dev_dbg(&client->dev, "set_voltage volt_slew_nanos_per_mv=%d\n",
+ volt_slew_nanos_per_mv);
+
+ /* Use slew version if slew rate is set to a sane value */
+ if (volt_slew_nanos_per_mv > 0 && volt_slew_nanos_per_mv < 1600)
+ a8293_set_voltage_slew(dev, client, fe_sec_voltage,
+ volt_slew_nanos_per_mv);
+ else
+ a8293_set_voltage_noslew(fe, fe_sec_voltage);
+
+ return 0;
+}
+
+static int a8293_probe(struct i2c_client *client)
{
struct a8293_dev *dev;
struct a8293_platform_data *pdata = client->dev.platform_data;
@@ -78,6 +225,7 @@ static int a8293_probe(struct i2c_client *client,
}
dev->client = client;
+ dev->volt_slew_nanos_per_mv = pdata->volt_slew_nanos_per_mv;
/* check if the SEC is there */
ret = i2c_master_recv(client, buf, 2);
@@ -118,7 +266,7 @@ static struct i2c_driver a8293_driver = {
.name = "a8293",
.suppress_bind_attrs = true,
},
- .probe = a8293_probe,
+ .probe_new = a8293_probe,
.remove = a8293_remove,
.id_table = a8293_id_table,
};
diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h
index 8c09635ef8a4..7fbac9735f7b 100644
--- a/drivers/media/dvb-frontends/a8293.h
+++ b/drivers/media/dvb-frontends/a8293.h
@@ -18,9 +18,12 @@
/**
* struct a8293_platform_data - Platform data for the a8293 driver
* @dvb_frontend: DVB frontend.
+ * @volt_slew_nanos_per_mv: Slew rate when increasing LNB voltage,
+ * in nanoseconds per millivolt.
*/
struct a8293_platform_data {
struct dvb_frontend *dvb_frontend;
+ int volt_slew_nanos_per_mv;
};
#endif /* A8293_H */
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index d85929582c3f..206758a73ae2 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -1430,8 +1430,7 @@ err:
return ret;
}
-static int af9013_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int af9013_probe(struct i2c_client *client)
{
struct af9013_state *state;
struct af9013_platform_data *pdata = client->dev.platform_data;
@@ -1564,7 +1563,7 @@ static struct i2c_driver af9013_driver = {
.name = "af9013",
.suppress_bind_attrs = true,
},
- .probe = af9013_probe,
+ .probe_new = af9013_probe,
.remove = af9013_remove,
.id_table = af9013_id_table,
};
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 808da7a9ffe7..a30773f62006 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -1049,8 +1049,7 @@ static const struct dvb_frontend_ops af9033_ops = {
.i2c_gate_ctrl = af9033_i2c_gate_ctrl,
};
-static int af9033_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int af9033_probe(struct i2c_client *client)
{
struct af9033_config *cfg = client->dev.platform_data;
struct af9033_dev *dev;
@@ -1184,7 +1183,7 @@ static struct i2c_driver af9033_driver = {
.name = "af9033",
.suppress_bind_attrs = true,
},
- .probe = af9033_probe,
+ .probe_new = af9033_probe,
.remove = af9033_remove,
.id_table = af9033_id_table,
};
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index e4f99bd468cb..0f748cf46089 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -669,8 +669,7 @@ static const struct v4l2_ctrl_ops au8522_ctrl_ops = {
/* ----------------------------------------------------------------------- */
-static int au8522_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int au8522_probe(struct i2c_client *client)
{
struct au8522_state *state;
struct v4l2_ctrl_handler *hdl;
@@ -777,7 +776,7 @@ static struct i2c_driver au8522_driver = {
.driver = {
.name = "au8522",
},
- .probe = au8522_probe,
+ .probe_new = au8522_probe,
.remove = au8522_remove,
.id_table = au8522_id,
};
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index da0ff7b44da4..68b92b4419cf 100644
--- a/drivers/media/dvb-frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -649,6 +649,7 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
err("firmware download failed: %d\n",ret);
+ release_firmware(fw);
return ret;
}
i += 4 + len;
diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c
index fbc666fa04ec..c0967ad95220 100644
--- a/drivers/media/dvb-frontends/cxd2099.c
+++ b/drivers/media/dvb-frontends/cxd2099.c
@@ -598,8 +598,7 @@ static const struct dvb_ca_en50221 en_templ = {
.write_data = write_data,
};
-static int cxd2099_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cxd2099_probe(struct i2c_client *client)
{
struct cxd *ci;
struct cxd2099_cfg *cfg = client->dev.platform_data;
@@ -682,7 +681,7 @@ static struct i2c_driver cxd2099_driver = {
.driver = {
.name = "cxd2099",
},
- .probe = cxd2099_probe,
+ .probe_new = cxd2099_probe,
.remove = cxd2099_remove,
.id_table = cxd2099_id,
};
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 5d98222f9df0..47aa40967171 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -547,8 +547,7 @@ static struct dvb_frontend *cxd2820r_get_dvb_frontend(struct i2c_client *client)
return &priv->fe;
}
-static int cxd2820r_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cxd2820r_probe(struct i2c_client *client)
{
struct cxd2820r_platform_data *pdata = client->dev.platform_data;
struct cxd2820r_priv *priv;
@@ -629,7 +628,7 @@ static int cxd2820r_probe(struct i2c_client *client,
/*
* Chip has two I2C addresses for different register banks. We register
- * one dummy I2C client in in order to get own I2C client for each
+ * one dummy I2C client in order to get own I2C client for each
* register bank.
*/
priv->client[1] = i2c_new_dummy_device(client->adapter, client->addr | (1 << 1));
@@ -734,7 +733,7 @@ static struct i2c_driver cxd2820r_driver = {
.name = "cxd2820r",
.suppress_bind_attrs = true,
},
- .probe = cxd2820r_probe,
+ .probe_new = cxd2820r_probe,
.remove = cxd2820r_remove,
.id_table = cxd2820r_id_table,
};
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
index 09c42bcef971..9b4d9cf8563d 100644
--- a/drivers/media/dvb-frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
@@ -52,8 +52,6 @@ struct cxd2820r_priv {
/* cxd2820r_core.c */
-extern int cxd2820r_debug;
-
int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio);
int cxd2820r_wr_reg_val_mask_tab(struct cxd2820r_priv *priv,
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h
index 739dc5590fa4..9df34c10d22b 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h
+++ b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h
@@ -234,8 +234,6 @@
/*-------- Public API functions ----------------------------------------------*/
-extern struct drx_access_func drx_dap_fasi_funct_g;
-
#define DRXDAP_FASI_RMW 0x10000000
#define DRXDAP_FASI_BROADCAST 0x20000000
#define DRXDAP_FASI_CLEARCRC 0x80000000
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index bf9e4ef35684..1dff59ca21a1 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -2347,6 +2347,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16
do {
nr_retries++;
if (nr_retries > DRXJ_MAX_RETRIES) {
+ rc = -ETIMEDOUT;
pr_err("timeout\n");
goto rw_error;
}
diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c
index 8c1310c6b0bc..e4bbf6a51a2b 100644
--- a/drivers/media/dvb-frontends/helene.c
+++ b/drivers/media/dvb-frontends/helene.c
@@ -1063,8 +1063,7 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe,
}
EXPORT_SYMBOL(helene_attach);
-static int helene_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int helene_probe(struct i2c_client *client)
{
struct helene_config *config = client->dev.platform_data;
struct dvb_frontend *fe = config->fe;
@@ -1111,7 +1110,7 @@ static struct i2c_driver helene_driver = {
.driver = {
.name = "helene",
},
- .probe = helene_probe,
+ .probe_new = helene_probe,
.id_table = helene_id,
};
module_i2c_driver(helene_driver);
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index 424311afb2bf..6bf723b5ffad 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -2169,8 +2169,7 @@ static int lgdt3306a_deselect(struct i2c_mux_core *muxc, u32 chan)
return lgdt3306a_i2c_gate_ctrl(&state->frontend, 0);
}
-static int lgdt3306a_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lgdt3306a_probe(struct i2c_client *client)
{
struct lgdt3306a_config *config;
struct lgdt3306a_state *state;
@@ -2250,7 +2249,7 @@ static struct i2c_driver lgdt3306a_driver = {
.name = "lgdt3306a",
.suppress_bind_attrs = true,
},
- .probe = lgdt3306a_probe,
+ .probe_new = lgdt3306a_probe,
.remove = lgdt3306a_remove,
.id_table = lgdt3306a_id_table,
};
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index ea9ae22fd201..1d6932d8e497 100644
--- a/drivers/media/dvb-frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -857,8 +857,7 @@ static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client)
static const struct dvb_frontend_ops lgdt3302_ops;
static const struct dvb_frontend_ops lgdt3303_ops;
-static int lgdt330x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lgdt330x_probe(struct i2c_client *client)
{
struct lgdt330x_state *state = NULL;
u8 buf[1];
@@ -994,7 +993,7 @@ static struct i2c_driver lgdt330x_driver = {
.name = "lgdt330x",
.suppress_bind_attrs = true,
},
- .probe = lgdt330x_probe,
+ .probe_new = lgdt330x_probe,
.remove = lgdt330x_remove,
.id_table = lgdt330x_id_table,
};
diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c
index 2b01cc678f7e..4a71f1c6371a 100644
--- a/drivers/media/dvb-frontends/mn88472.c
+++ b/drivers/media/dvb-frontends/mn88472.c
@@ -572,8 +572,7 @@ static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client)
return &dev->fe;
}
-static int mn88472_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mn88472_probe(struct i2c_client *client)
{
struct mn88472_config *pdata = client->dev.platform_data;
struct mn88472_dev *dev;
@@ -719,7 +718,7 @@ static struct i2c_driver mn88472_driver = {
.name = "mn88472",
.suppress_bind_attrs = true,
},
- .probe = mn88472_probe,
+ .probe_new = mn88472_probe,
.remove = mn88472_remove,
.id_table = mn88472_id_table,
};
diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c
index f0ecf5910c02..205b14ae584e 100644
--- a/drivers/media/dvb-frontends/mn88473.c
+++ b/drivers/media/dvb-frontends/mn88473.c
@@ -606,8 +606,7 @@ static const struct dvb_frontend_ops mn88473_ops = {
.read_status = mn88473_read_status,
};
-static int mn88473_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mn88473_probe(struct i2c_client *client)
{
struct mn88473_config *config = client->dev.platform_data;
struct mn88473_dev *dev;
@@ -754,7 +753,7 @@ static struct i2c_driver mn88473_driver = {
.name = "mn88473",
.suppress_bind_attrs = true,
},
- .probe = mn88473_probe,
+ .probe_new = mn88473_probe,
.remove = mn88473_remove,
.id_table = mn88473_id_table,
};
diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c
index 934d1c0b214a..4ebbcf05cc09 100644
--- a/drivers/media/dvb-frontends/mxl5xx.c
+++ b/drivers/media/dvb-frontends/mxl5xx.c
@@ -1644,8 +1644,6 @@ static int validate_sku(struct mxl *state)
default:
return -1;
}
- } else {
-
}
return -1;
}
diff --git a/drivers/media/dvb-frontends/mxl692.c b/drivers/media/dvb-frontends/mxl692.c
index 129630cbffff..9858e11943a0 100644
--- a/drivers/media/dvb-frontends/mxl692.c
+++ b/drivers/media/dvb-frontends/mxl692.c
@@ -1308,8 +1308,7 @@ static const struct dvb_frontend_ops mxl692_ops = {
.read_snr = mxl692_read_snr,
};
-static int mxl692_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mxl692_probe(struct i2c_client *client)
{
struct mxl692_config *config = client->dev.platform_data;
struct mxl692_dev *dev;
@@ -1356,7 +1355,7 @@ static struct i2c_driver mxl692_driver = {
.driver = {
.name = "mxl692",
},
- .probe = mxl692_probe,
+ .probe_new = mxl692_probe,
.remove = mxl692_remove,
.id_table = mxl692_id_table,
};
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index e0fbf41316ae..db3254950147 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -768,8 +768,7 @@ static int rtl2830_regmap_gather_write(void *context, const void *reg,
return 0;
}
-static int rtl2830_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int rtl2830_probe(struct i2c_client *client)
{
struct rtl2830_platform_data *pdata = client->dev.platform_data;
struct rtl2830_dev *dev;
@@ -887,7 +886,7 @@ static struct i2c_driver rtl2830_driver = {
.name = "rtl2830",
.suppress_bind_attrs = true,
},
- .probe = rtl2830_probe,
+ .probe_new = rtl2830_probe,
.remove = rtl2830_remove,
.id_table = rtl2830_id_table,
};
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 4fa884eda5d5..900d4db8b922 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1021,8 +1021,7 @@ err:
return ret;
}
-static int rtl2832_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int rtl2832_probe(struct i2c_client *client)
{
struct rtl2832_platform_data *pdata = client->dev.platform_data;
struct i2c_adapter *i2c = client->adapter;
@@ -1136,7 +1135,7 @@ static struct i2c_driver rtl2832_driver = {
.name = "rtl2832",
.suppress_bind_attrs = true,
},
- .probe = rtl2832_probe,
+ .probe_new = rtl2832_probe,
.remove = rtl2832_remove,
.id_table = rtl2832_id_table,
};
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 86b0d59169dd..cc07e965c34c 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -1144,8 +1144,7 @@ static const struct dvb_frontend_ops si2165_ops = {
.read_ber = si2165_read_ber,
};
-static int si2165_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si2165_probe(struct i2c_client *client)
{
struct si2165_state *state = NULL;
struct si2165_platform_data *pdata = client->dev.platform_data;
@@ -1293,7 +1292,7 @@ static struct i2c_driver si2165_driver = {
.driver = {
.name = "si2165",
},
- .probe = si2165_probe,
+ .probe_new = si2165_probe,
.remove = si2165_remove,
.id_table = si2165_id_table,
};
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 8157df4570d1..2a0e108c5eb0 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -672,8 +672,7 @@ static const struct dvb_frontend_ops si2168_ops = {
.read_status = si2168_read_status,
};
-static int si2168_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si2168_probe(struct i2c_client *client)
{
struct si2168_config *config = client->dev.platform_data;
struct si2168_dev *dev;
@@ -799,7 +798,7 @@ static struct i2c_driver si2168_driver = {
.name = "si2168",
.suppress_bind_attrs = true,
},
- .probe = si2168_probe,
+ .probe_new = si2168_probe,
.remove = si2168_remove,
.id_table = si2168_id_table,
};
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
index 27e7037e130e..3395f6b5b948 100644
--- a/drivers/media/dvb-frontends/sp2.c
+++ b/drivers/media/dvb-frontends/sp2.c
@@ -363,8 +363,7 @@ static int sp2_exit(struct i2c_client *client)
return 0;
}
-static int sp2_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sp2_probe(struct i2c_client *client)
{
struct sp2_config *cfg = client->dev.platform_data;
struct sp2 *s;
@@ -417,7 +416,7 @@ static struct i2c_driver sp2_driver = {
.driver = {
.name = "sp2",
},
- .probe = sp2_probe,
+ .probe_new = sp2_probe,
.remove = sp2_remove,
.id_table = sp2_id,
};
diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c
index 3d54a0ec86af..3ae1f3a2f142 100644
--- a/drivers/media/dvb-frontends/stv0288.c
+++ b/drivers/media/dvb-frontends/stv0288.c
@@ -440,9 +440,8 @@ static int stv0288_set_frontend(struct dvb_frontend *fe)
struct stv0288_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- char tm;
- unsigned char tda[3];
- u8 reg, time_out = 0;
+ u8 tda[3], reg, time_out = 0;
+ s8 tm;
dprintk("%s : FE_SET_FRONTEND\n", __func__);
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 0a600c1d7d1b..9bde0ad6f26e 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -4990,8 +4990,7 @@ static struct dvb_frontend *stv090x_get_dvb_frontend(struct i2c_client *client)
return &state->frontend;
}
-static int stv090x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int stv090x_probe(struct i2c_client *client)
{
int ret = 0;
struct stv090x_config *config = client->dev.platform_data;
@@ -5085,7 +5084,7 @@ static struct i2c_driver stv090x_driver = {
.name = "stv090x",
.suppress_bind_attrs = true,
},
- .probe = stv090x_probe,
+ .probe_new = stv090x_probe,
.remove = stv090x_remove,
.id_table = stv090x_id_table,
};
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index fbc4dbd62151..b2f456116c60 100644
--- a/drivers/media/dvb-frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -406,8 +406,7 @@ static struct stv6110x_devctl *stv6110x_get_devctl(struct i2c_client *client)
return stv6110x->devctl;
}
-static int stv6110x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int stv6110x_probe(struct i2c_client *client)
{
struct stv6110x_config *config = client->dev.platform_data;
@@ -481,7 +480,7 @@ static struct i2c_driver stv6110x_driver = {
.name = "stv6110x",
.suppress_bind_attrs = true,
},
- .probe = stv6110x_probe,
+ .probe_new = stv6110x_probe,
.remove = stv6110x_remove,
.id_table = stv6110x_id_table,
};
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index d1098ef20a8b..c8e5617d08c0 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -1145,8 +1145,7 @@ static struct dvb_frontend *tda10071_get_dvb_frontend(struct i2c_client *client)
return &dev->fe;
}
-static int tda10071_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda10071_probe(struct i2c_client *client)
{
struct tda10071_dev *dev;
struct tda10071_platform_data *pdata = client->dev.platform_data;
@@ -1241,7 +1240,7 @@ static struct i2c_driver tda10071_driver = {
.name = "tda10071",
.suppress_bind_attrs = true,
},
- .probe = tda10071_probe,
+ .probe_new = tda10071_probe,
.remove = tda10071_remove,
.id_table = tda10071_id_table,
};
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index 02338256b974..c28fee7509cd 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -550,8 +550,7 @@ static void ts2020_regmap_unlock(void *__dev)
mutex_unlock(&dev->regmap_mutex);
}
-static int ts2020_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ts2020_probe(struct i2c_client *client)
{
struct ts2020_config *pdata = client->dev.platform_data;
struct dvb_frontend *fe = pdata->fe;
@@ -721,7 +720,7 @@ static struct i2c_driver ts2020_driver = {
.driver = {
.name = "ts2020",
},
- .probe = ts2020_probe,
+ .probe_new = ts2020_probe,
.remove = ts2020_remove,
.id_table = ts2020_id_table,
};
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 7806d4b81716..833241897d63 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -364,6 +364,19 @@ config VIDEO_OV08D10
To compile this driver as a module, choose M here: the
module will be called ov08d10.
+config VIDEO_OV08X40
+ tristate "OmniVision OV08X40 sensor support"
+ depends on VIDEO_DEV && I2C
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OV08X40 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov08x40.
+
config VIDEO_OV13858
tristate "OmniVision OV13858 sensor support"
depends on I2C && VIDEO_DEV
@@ -445,6 +458,19 @@ config VIDEO_OV2740
To compile this driver as a module, choose M here: the
module will be called ov2740.
+config VIDEO_OV4689
+ tristate "OmniVision OV4689 sensor support"
+ depends on GPIOLIB && VIDEO_DEV && I2C
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV4689 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov4689.
+
config VIDEO_OV5640
tristate "OmniVision OV5640 sensor support"
depends on OF
@@ -725,16 +751,6 @@ config VIDEO_S5C73M3
This is a V4L2 sensor driver for Samsung S5C73M3
8 Mpixel camera.
-config VIDEO_S5K4ECGX
- tristate "Samsung S5K4ECGX sensor support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- select CRC32
- help
- This is a V4L2 sensor driver for Samsung S5K4ECGX 5M
- camera sensor with an embedded SoC image signal processor.
-
config VIDEO_S5K5BAF
tristate "Samsung S5K5BAF sensor support"
depends on I2C && VIDEO_DEV
@@ -769,6 +785,16 @@ config VIDEO_SR030PC30
help
This driver supports SR030PC30 VGA camera from Siliconfile
+config VIDEO_ST_VGXY61
+ tristate "ST VGXY61 sensor support"
+ depends on OF && GPIOLIB && VIDEO_DEV && I2C
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the ST VGXY61
+ camera sensor.
+
config VIDEO_VS6624
tristate "ST VS6624 sensor support"
depends on VIDEO_DEV && I2C
@@ -1272,6 +1298,22 @@ config VIDEO_TC358743_CEC
When selected the tc358743 will support the optional
HDMI CEC feature.
+config VIDEO_TC358746
+ tristate "Toshiba TC358746 parallel-CSI2 bridge"
+ depends on VIDEO_DEV && PM && I2C
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select GENERIC_PHY_MIPI_DPHY
+ select REGMAP_I2C
+ help
+ Support for the Toshiba TC358746 parallel to MIPI CSI-2 bridge.
+ The bridge can work in both directions but currently only the
+ parallel-in / csi-out path is supported.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tc358746.
+
config VIDEO_TVP514X
tristate "Texas Instruments TVP514x video decoder"
depends on VIDEO_DEV && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 0a2933103dd9..4d6c052bb5a7 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o
obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o
+obj-$(CONFIG_VIDEO_OV08X40) += ov08x40.o
obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o
obj-$(CONFIG_VIDEO_OV2640) += ov2640.o
@@ -79,6 +80,7 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_OV2680) += ov2680.o
obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
obj-$(CONFIG_VIDEO_OV2740) += ov2740.o
+obj-$(CONFIG_VIDEO_OV4689) += ov4689.o
obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
@@ -103,7 +105,6 @@ obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o
obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o
obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
-obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o
obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o
obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
@@ -117,7 +118,9 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
+obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
+obj-$(CONFIG_VIDEO_TC358746) += tc358746.o
obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c
index 516de278cc49..44c26af49071 100644
--- a/drivers/media/i2c/ad5820.c
+++ b/drivers/media/i2c/ad5820.c
@@ -290,8 +290,7 @@ static int __maybe_unused ad5820_resume(struct device *dev)
return ad5820_power_on(coil, true);
}
-static int ad5820_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int ad5820_probe(struct i2c_client *client)
{
struct ad5820_device *coil;
int ret;
@@ -301,21 +300,15 @@ static int ad5820_probe(struct i2c_client *client,
return -ENOMEM;
coil->vana = devm_regulator_get(&client->dev, "VANA");
- if (IS_ERR(coil->vana)) {
- ret = PTR_ERR(coil->vana);
- if (ret != -EPROBE_DEFER)
- dev_err(&client->dev, "could not get regulator for vana\n");
- return ret;
- }
+ if (IS_ERR(coil->vana))
+ return dev_err_probe(&client->dev, PTR_ERR(coil->vana),
+ "could not get regulator for vana\n");
coil->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
GPIOD_OUT_LOW);
- if (IS_ERR(coil->enable_gpio)) {
- ret = PTR_ERR(coil->enable_gpio);
- if (ret != -EPROBE_DEFER)
- dev_err(&client->dev, "could not get enable gpio\n");
- return ret;
- }
+ if (IS_ERR(coil->enable_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(coil->enable_gpio),
+ "could not get enable gpio\n");
mutex_init(&coil->power_lock);
@@ -327,18 +320,18 @@ static int ad5820_probe(struct i2c_client *client,
ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL);
if (ret < 0)
- goto cleanup2;
+ goto clean_mutex;
ret = v4l2_async_register_subdev(&coil->subdev);
if (ret < 0)
- goto cleanup;
+ goto clean_entity;
return ret;
-cleanup2:
- mutex_destroy(&coil->power_lock);
-cleanup:
+clean_entity:
media_entity_cleanup(&coil->subdev.entity);
+clean_mutex:
+ mutex_destroy(&coil->power_lock);
return ret;
}
@@ -377,7 +370,7 @@ static struct i2c_driver ad5820_i2c_driver = {
.pm = &ad5820_pm,
.of_match_table = ad5820_of_table,
},
- .probe = ad5820_probe,
+ .probe_new = ad5820_probe,
.remove = ad5820_remove,
.id_table = ad5820_id_table,
};
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 4a255a492918..ad17097a2d25 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -1080,7 +1080,7 @@ static void ad9389b_init_setup(struct v4l2_subdev *sd)
ad9389b_set_isr(sd, false);
}
-static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ad9389b_probe(struct i2c_client *client)
{
const struct v4l2_dv_timings dv1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
struct ad9389b_state *state;
@@ -1207,7 +1207,7 @@ static struct i2c_driver ad9389b_driver = {
.driver = {
.name = "ad9389b",
},
- .probe = ad9389b_probe,
+ .probe_new = ad9389b_probe,
.remove = ad9389b_remove,
.id_table = ad9389b_id,
};
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index 1f353157df07..a61a77de6eee 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -463,8 +463,7 @@ err:
}
-static int adp1653_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int adp1653_probe(struct i2c_client *client)
{
struct adp1653_flash *flash;
int ret;
@@ -536,7 +535,7 @@ static struct i2c_driver adp1653_i2c_driver = {
.name = ADP1653_NAME,
.pm = &adp1653_pm_ops,
},
- .probe = adp1653_probe,
+ .probe_new = adp1653_probe,
.remove = adp1653_remove,
.id_table = adp1653_id_table,
};
diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c
index 61a2f87d3c62..aa0f80e299b3 100644
--- a/drivers/media/i2c/adv7170.c
+++ b/drivers/media/i2c/adv7170.c
@@ -334,8 +334,7 @@ static const struct v4l2_subdev_ops adv7170_ops = {
/* ----------------------------------------------------------------------- */
-static int adv7170_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7170_probe(struct i2c_client *client)
{
struct adv7170 *encoder;
struct v4l2_subdev *sd;
@@ -388,7 +387,7 @@ static struct i2c_driver adv7170_driver = {
.driver = {
.name = "adv7170",
},
- .probe = adv7170_probe,
+ .probe_new = adv7170_probe,
.remove = adv7170_remove,
.id_table = adv7170_id,
};
diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c
index b58689728243..d9bea2b9ec33 100644
--- a/drivers/media/i2c/adv7175.c
+++ b/drivers/media/i2c/adv7175.c
@@ -389,8 +389,7 @@ static const struct v4l2_subdev_ops adv7175_ops = {
/* ----------------------------------------------------------------------- */
-static int adv7175_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7175_probe(struct i2c_client *client)
{
int i;
struct adv7175 *encoder;
@@ -443,7 +442,7 @@ static struct i2c_driver adv7175_driver = {
.driver = {
.name = "adv7175",
},
- .probe = adv7175_probe,
+ .probe_new = adv7175_probe,
.remove = adv7175_remove,
.id_table = adv7175_id,
};
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index 313c706e8335..98b63d79d33d 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -521,8 +521,7 @@ static const struct v4l2_subdev_ops adv7183_ops = {
.pad = &adv7183_pad_ops,
};
-static int adv7183_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7183_probe(struct i2c_client *client)
{
struct adv7183 *decoder;
struct v4l2_subdev *sd;
@@ -632,7 +631,7 @@ static struct i2c_driver adv7183_driver = {
.driver = {
.name = "adv7183",
},
- .probe = adv7183_probe,
+ .probe_new = adv7183_probe,
.remove = adv7183_remove,
.id_table = adv7183_id,
};
diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c
index fb5fefa83b18..61e916cbe651 100644
--- a/drivers/media/i2c/adv7393.c
+++ b/drivers/media/i2c/adv7393.c
@@ -381,8 +381,7 @@ static int adv7393_initialize(struct v4l2_subdev *sd)
return err;
}
-static int adv7393_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7393_probe(struct i2c_client *client)
{
struct adv7393_state *state;
int err;
@@ -456,7 +455,7 @@ static struct i2c_driver adv7393_driver = {
.driver = {
.name = "adv7393",
},
- .probe = adv7393_probe,
+ .probe_new = adv7393_probe,
.remove = adv7393_remove,
.id_table = adv7393_id,
};
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 02eabe10ab97..00095c7762c2 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -521,6 +521,10 @@ int adv748x_afe_init(struct adv748x_afe *afe)
}
}
+ adv748x_afe_s_input(afe, afe->input);
+
+ adv_dbg(state, "AFE Default input set to %d\n", afe->input);
+
/* Entity pads and sinks are 0-indexed to match the pads */
for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++)
afe->pads[i].flags = MEDIA_PAD_FL_SINK;
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index d75eb3d8be5a..6f90f78f58cf 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -428,9 +428,6 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
const struct v4l2_subdev_ops *ops, u32 function,
const char *ident);
-int adv748x_register_subdevs(struct adv748x_state *state,
- struct v4l2_device *v4l2_dev);
-
int adv748x_tx_power(struct adv748x_csi2 *tx, bool on);
int adv748x_afe_init(struct adv748x_afe *afe);
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index 0d5ce69f12e7..3999fa524cab 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -1763,7 +1763,7 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
adv7511_cec_write(sd, 0x4e, ratio << 2);
}
-static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int adv7511_probe(struct i2c_client *client)
{
struct adv7511_state *state;
struct adv7511_platform_data *pdata = client->dev.platform_data;
@@ -1957,7 +1957,7 @@ static struct i2c_driver adv7511_driver = {
.driver = {
.name = "adv7511-v4l2",
},
- .probe = adv7511_probe,
+ .probe_new = adv7511_probe,
.remove = adv7511_remove,
.id_table = adv7511_id,
};
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 7731cc1887e6..cb8655574119 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -3441,8 +3441,7 @@ static int adv7842_register_clients(struct v4l2_subdev *sd)
return 0;
}
-static int adv7842_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7842_probe(struct i2c_client *client)
{
struct adv7842_state *state;
static const struct v4l2_dv_timings cea640x480 =
@@ -3620,7 +3619,7 @@ static struct i2c_driver adv7842_driver = {
.driver = {
.name = "adv7842",
},
- .probe = adv7842_probe,
+ .probe_new = adv7842_probe,
.remove = adv7842_remove,
.id_table = adv7842_id,
};
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index 0370ad6b6811..7c9ab76e2448 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -226,8 +226,7 @@ static const struct v4l2_subdev_ops ak881x_subdev_ops = {
.pad = &ak881x_subdev_pad_ops,
};
-static int ak881x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int ak881x_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct ak881x *ak881x;
@@ -315,7 +314,7 @@ static struct i2c_driver ak881x_i2c_driver = {
.driver = {
.name = "ak881x",
},
- .probe = ak881x_probe,
+ .probe_new = ak881x_probe,
.remove = ak881x_remove,
.id_table = ak881x_id,
};
diff --git a/drivers/media/i2c/aptina-pll.c b/drivers/media/i2c/aptina-pll.c
index 1423c04a1c90..b1f89bbf9d47 100644
--- a/drivers/media/i2c/aptina-pll.c
+++ b/drivers/media/i2c/aptina-pll.c
@@ -8,7 +8,6 @@
#include <linux/device.h>
#include <linux/gcd.h>
#include <linux/kernel.h>
-#include <linux/lcm.h>
#include <linux/module.h>
#include "aptina-pll.h"
diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c
index e408049f6312..77f597571167 100644
--- a/drivers/media/i2c/ar0521.c
+++ b/drivers/media/i2c/ar0521.c
@@ -14,26 +14,39 @@
#include <media/v4l2-subdev.h>
/* External clock (extclk) frequencies */
-#define AR0521_EXTCLK_MIN (10 * 1000 * 1000)
-#define AR0521_EXTCLK_MAX (48 * 1000 * 1000)
+#define AR0521_EXTCLK_MIN (10 * 1000 * 1000)
+#define AR0521_EXTCLK_MAX (48 * 1000 * 1000)
/* PLL and PLL2 */
-#define AR0521_PLL_MIN (320 * 1000 * 1000)
-#define AR0521_PLL_MAX (1280 * 1000 * 1000)
-
-/* Effective pixel clocks, the registers may be DDR */
-#define AR0521_PIXEL_CLOCK_RATE (184 * 1000 * 1000)
-#define AR0521_PIXEL_CLOCK_MIN (168 * 1000 * 1000)
-#define AR0521_PIXEL_CLOCK_MAX (414 * 1000 * 1000)
-
-#define AR0521_WIDTH_MIN 8u
-#define AR0521_WIDTH_MAX 2608u
-#define AR0521_HEIGHT_MIN 8u
-#define AR0521_HEIGHT_MAX 1958u
-
-#define AR0521_WIDTH_BLANKING_MIN 572u
-#define AR0521_HEIGHT_BLANKING_MIN 38u /* must be even */
-#define AR0521_TOTAL_WIDTH_MIN 2968u
+#define AR0521_PLL_MIN (320 * 1000 * 1000)
+#define AR0521_PLL_MAX (1280 * 1000 * 1000)
+
+/* Effective pixel sample rate on the pixel array. */
+#define AR0521_PIXEL_CLOCK_RATE (184 * 1000 * 1000)
+#define AR0521_PIXEL_CLOCK_MIN (168 * 1000 * 1000)
+#define AR0521_PIXEL_CLOCK_MAX (414 * 1000 * 1000)
+
+#define AR0521_NATIVE_WIDTH 2604u
+#define AR0521_NATIVE_HEIGHT 1964u
+#define AR0521_MIN_X_ADDR_START 0u
+#define AR0521_MIN_Y_ADDR_START 0u
+#define AR0521_MAX_X_ADDR_END 2603u
+#define AR0521_MAX_Y_ADDR_END 1955u
+
+#define AR0521_WIDTH_MIN 8u
+#define AR0521_WIDTH_MAX 2592u
+#define AR0521_HEIGHT_MIN 8u
+#define AR0521_HEIGHT_MAX 1944u
+
+#define AR0521_WIDTH_BLANKING_MIN 572u
+#define AR0521_HEIGHT_BLANKING_MIN 38u /* must be even */
+#define AR0521_TOTAL_HEIGHT_MAX 65535u /* max_frame_length_lines */
+#define AR0521_TOTAL_WIDTH_MAX 65532u /* max_line_length_pck */
+
+#define AR0521_ANA_GAIN_MIN 0x00
+#define AR0521_ANA_GAIN_MAX 0x3f
+#define AR0521_ANA_GAIN_STEP 0x01
+#define AR0521_ANA_GAIN_DEFAULT 0x00
/* AR0521 registers */
#define AR0521_REG_VT_PIX_CLK_DIV 0x0300
@@ -50,6 +63,8 @@
#define AR0521_REG_RESET_RESTART BIT(1)
#define AR0521_REG_RESET_INIT BIT(0)
+#define AR0521_REG_ANA_GAIN_CODE_GLOBAL 0x3028
+
#define AR0521_REG_GREEN1_GAIN 0x3056
#define AR0521_REG_BLUE_GAIN 0x3058
#define AR0521_REG_RED_GAIN 0x305A
@@ -75,6 +90,10 @@ static const char * const ar0521_supply_names[] = {
"vaa", /* Analog (2.7V) supply */
};
+static const s64 ar0521_link_frequencies[] = {
+ 184000000,
+};
+
struct ar0521_ctrls {
struct v4l2_ctrl_handler handler;
struct {
@@ -107,12 +126,14 @@ struct ar0521_dev {
struct v4l2_mbus_framefmt fmt;
struct ar0521_ctrls ctrls;
unsigned int lane_count;
- u16 total_width;
- u16 total_height;
- u16 pll_pre;
- u16 pll_mult;
- u16 pll_pre2;
- u16 pll_mult2;
+ struct {
+ u16 pre;
+ u16 mult;
+ u16 pre2;
+ u16 mult2;
+ u16 vt_pix;
+ } pll;
+
bool streaming;
};
@@ -137,6 +158,16 @@ static u32 div64_round_up(u64 v, u32 d)
return div_u64(v + d - 1, d);
}
+static int ar0521_code_to_bpp(struct ar0521_dev *sensor)
+{
+ switch (sensor->fmt.code) {
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ return 8;
+ }
+
+ return -EINVAL;
+}
+
/* Data must be BE16, the first value is the register address */
static int ar0521_write_regs(struct ar0521_dev *sensor, const __be16 *data,
unsigned int count)
@@ -169,13 +200,17 @@ static int ar0521_write_reg(struct ar0521_dev *sensor, u16 reg, u16 val)
static int ar0521_set_geometry(struct ar0521_dev *sensor)
{
+ /* Center the image in the visible output window. */
+ u16 x = clamp((AR0521_WIDTH_MAX - sensor->fmt.width) / 2,
+ AR0521_MIN_X_ADDR_START, AR0521_MAX_X_ADDR_END);
+ u16 y = clamp(((AR0521_HEIGHT_MAX - sensor->fmt.height) / 2) & ~1,
+ AR0521_MIN_Y_ADDR_START, AR0521_MAX_Y_ADDR_END);
+
/* All dimensions are unsigned 12-bit integers */
- u16 x = (AR0521_WIDTH_MAX - sensor->fmt.width) / 2;
- u16 y = ((AR0521_HEIGHT_MAX - sensor->fmt.height) / 2) & ~1;
__be16 regs[] = {
be(AR0521_REG_FRAME_LENGTH_LINES),
- be(sensor->total_height),
- be(sensor->total_width),
+ be(sensor->fmt.height + sensor->ctrls.vblank->val),
+ be(sensor->fmt.width + sensor->ctrls.hblank->val),
be(x),
be(y),
be(x + sensor->fmt.width - 1),
@@ -208,8 +243,7 @@ static int ar0521_set_gains(struct ar0521_dev *sensor)
return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs));
}
-static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr,
- u16 *mult_ptr)
+static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult_ptr)
{
u16 pre = 1, mult = 1, new_pre;
u32 pll = AR0521_PLL_MAX + 1;
@@ -244,69 +278,84 @@ static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr,
return pll;
}
-#define DIV 4
-static void ar0521_calc_mode(struct ar0521_dev *sensor)
+static void ar0521_calc_pll(struct ar0521_dev *sensor)
{
- unsigned int speed_mod = 4 / sensor->lane_count; /* 1 with 4 DDR lanes */
- u16 total_width = max(sensor->fmt.width + AR0521_WIDTH_BLANKING_MIN,
- AR0521_TOTAL_WIDTH_MIN);
- u16 total_height = sensor->fmt.height + AR0521_HEIGHT_BLANKING_MIN;
-
- /* Calculate approximate pixel clock first */
- u64 pix_clk = AR0521_PIXEL_CLOCK_RATE;
-
- /* PLL1 drives pixel clock - dual rate */
- pix_clk = calc_pll(sensor, 1, pix_clk * (DIV / 2), &sensor->pll_pre,
- &sensor->pll_mult);
- pix_clk = div64_round(pix_clk, (DIV / 2));
- calc_pll(sensor, 2, pix_clk * (DIV / 2) * speed_mod, &sensor->pll_pre2,
- &sensor->pll_mult2);
-
- sensor->total_width = total_width;
- sensor->total_height = total_height;
+ unsigned int pixel_clock;
+ u16 pre, mult;
+ u32 vco;
+ int bpp;
+
+ /*
+ * PLL1 and PLL2 are computed equally even if the application note
+ * suggests a slower PLL1 clock. Maintain pll1 and pll2 divider and
+ * multiplier separated to later specialize the calculation procedure.
+ *
+ * PLL1:
+ * - mclk -> / pre_div1 * pre_mul1 = VCO1 = COUNTER_CLOCK
+ *
+ * PLL2:
+ * - mclk -> / pre_div * pre_mul = VCO
+ *
+ * VCO -> / vt_pix = PIXEL_CLOCK
+ * VCO -> / vt_pix / 2 = WORD_CLOCK
+ * VCO -> / op_sys = SERIAL_CLOCK
+ *
+ * With:
+ * - vt_pix = bpp / 2
+ * - WORD_CLOCK = PIXEL_CLOCK / 2
+ * - SERIAL_CLOCK = MIPI data rate (Mbps / lane) = WORD_CLOCK * bpp
+ * NOTE: this implies the MIPI clock is divided internally by 2
+ * to account for DDR.
+ *
+ * As op_sys_div is fixed to 1:
+ *
+ * SERIAL_CLOCK = VCO
+ * VCO = 2 * MIPI_CLK
+ * VCO = PIXEL_CLOCK * bpp / 2
+ *
+ * In the clock tree:
+ * MIPI_CLK = PIXEL_CLOCK * bpp / 2 / 2
+ *
+ * Generic pixel_rate to bus clock frequencey equation:
+ * MIPI_CLK = V4L2_CID_PIXEL_RATE * bpp / lanes / 2
+ *
+ * From which we derive the PIXEL_CLOCK to use in the clock tree:
+ * PIXEL_CLOCK = V4L2_CID_PIXEL_RATE * 2 / lanes
+ *
+ * Documented clock ranges:
+ * WORD_CLOCK = (35MHz - 120 MHz)
+ * PIXEL_CLOCK = (84MHz - 207MHz)
+ * VCO = (320MHz - 1280MHz)
+ *
+ * TODO: in case we have less data lanes we have to reduce the desired
+ * VCO not to exceed the limits specified by the datasheet and
+ * consequentially reduce the obtained pixel clock.
+ */
+ pixel_clock = AR0521_PIXEL_CLOCK_RATE * 2 / sensor->lane_count;
+ bpp = ar0521_code_to_bpp(sensor);
+ sensor->pll.vt_pix = bpp / 2;
+ vco = pixel_clock * sensor->pll.vt_pix;
+
+ calc_pll(sensor, vco, &pre, &mult);
+
+ sensor->pll.pre = sensor->pll.pre2 = pre;
+ sensor->pll.mult = sensor->pll.mult2 = mult;
}
-static int ar0521_write_mode(struct ar0521_dev *sensor)
+static int ar0521_pll_config(struct ar0521_dev *sensor)
{
__be16 pll_regs[] = {
be(AR0521_REG_VT_PIX_CLK_DIV),
- /* 0x300 */ be(4), /* vt_pix_clk_div = number of bits / 2 */
+ /* 0x300 */ be(sensor->pll.vt_pix), /* vt_pix_clk_div = bpp / 2 */
/* 0x302 */ be(1), /* vt_sys_clk_div */
- /* 0x304 */ be((sensor->pll_pre2 << 8) | sensor->pll_pre),
- /* 0x306 */ be((sensor->pll_mult2 << 8) | sensor->pll_mult),
- /* 0x308 */ be(8), /* op_pix_clk_div = 2 * vt_pix_clk_div */
+ /* 0x304 */ be((sensor->pll.pre2 << 8) | sensor->pll.pre),
+ /* 0x306 */ be((sensor->pll.mult2 << 8) | sensor->pll.mult),
+ /* 0x308 */ be(sensor->pll.vt_pix * 2), /* op_pix_clk_div = 2 * vt_pix_clk_div */
/* 0x30A */ be(1) /* op_sys_clk_div */
};
- int ret;
-
- /* Stop streaming for just a moment */
- ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
- AR0521_REG_RESET_DEFAULTS);
- if (ret)
- return ret;
- ret = ar0521_set_geometry(sensor);
- if (ret)
- return ret;
-
- ret = ar0521_write_regs(sensor, pll_regs, ARRAY_SIZE(pll_regs));
- if (ret)
- return ret;
-
- ret = ar0521_write_reg(sensor, AR0521_REG_COARSE_INTEGRATION_TIME,
- sensor->ctrls.exposure->val);
- if (ret)
- return ret;
-
- ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
- AR0521_REG_RESET_DEFAULTS |
- AR0521_REG_RESET_STREAM);
- if (ret)
- return ret;
-
- ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE,
- sensor->ctrls.test_pattern->val);
- return ret;
+ ar0521_calc_pll(sensor);
+ return ar0521_write_regs(sensor, pll_regs, ARRAY_SIZE(pll_regs));
}
static int ar0521_set_stream(struct ar0521_dev *sensor, bool on)
@@ -318,12 +367,21 @@ static int ar0521_set_stream(struct ar0521_dev *sensor, bool on)
if (ret < 0)
return ret;
- ar0521_calc_mode(sensor);
- ret = ar0521_write_mode(sensor);
+ /* Stop streaming for just a moment */
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS);
+ if (ret)
+ return ret;
+
+ ret = ar0521_set_geometry(sensor);
+ if (ret)
+ return ret;
+
+ ret = ar0521_pll_config(sensor);
if (ret)
goto err;
- ret = ar0521_set_gains(sensor);
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
if (ret)
goto err;
@@ -406,6 +464,8 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
{
struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int max_vblank, max_hblank, exposure_max;
+ int ret;
ar0521_adj_fmt(&format->format);
@@ -416,33 +476,73 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd,
fmt = v4l2_subdev_get_try_format(sd, sd_state, 0 /* pad */);
*fmt = format->format;
- } else {
- sensor->fmt = format->format;
- ar0521_calc_mode(sensor);
+
+ mutex_unlock(&sensor->lock);
+
+ return 0;
}
+ sensor->fmt = format->format;
+ ar0521_calc_pll(sensor);
+
+ /*
+ * Update the exposure and blankings limits. Blankings are also reset
+ * to the minimum.
+ */
+ max_hblank = AR0521_TOTAL_WIDTH_MAX - sensor->fmt.width;
+ ret = __v4l2_ctrl_modify_range(sensor->ctrls.hblank,
+ sensor->ctrls.hblank->minimum,
+ max_hblank, sensor->ctrls.hblank->step,
+ sensor->ctrls.hblank->minimum);
+ if (ret)
+ goto unlock;
+
+ ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.hblank,
+ sensor->ctrls.hblank->minimum);
+ if (ret)
+ goto unlock;
+
+ max_vblank = AR0521_TOTAL_HEIGHT_MAX - sensor->fmt.height;
+ ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank,
+ sensor->ctrls.vblank->minimum,
+ max_vblank, sensor->ctrls.vblank->step,
+ sensor->ctrls.vblank->minimum);
+ if (ret)
+ goto unlock;
+
+ ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank,
+ sensor->ctrls.vblank->minimum);
+ if (ret)
+ goto unlock;
+
+ exposure_max = sensor->fmt.height + AR0521_HEIGHT_BLANKING_MIN - 4;
+ ret = __v4l2_ctrl_modify_range(sensor->ctrls.exposure,
+ sensor->ctrls.exposure->minimum,
+ exposure_max,
+ sensor->ctrls.exposure->step,
+ sensor->ctrls.exposure->default_value);
+unlock:
mutex_unlock(&sensor->lock);
- return 0;
+
+ return ret;
}
static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int exp_max;
int ret;
/* v4l2_ctrl_lock() locks our own mutex */
switch (ctrl->id) {
- case V4L2_CID_HBLANK:
case V4L2_CID_VBLANK:
- sensor->total_width = sensor->fmt.width +
- sensor->ctrls.hblank->val;
- sensor->total_height = sensor->fmt.width +
- sensor->ctrls.vblank->val;
- break;
- default:
- ret = -EINVAL;
+ exp_max = sensor->fmt.height + ctrl->val - 4;
+ __v4l2_ctrl_modify_range(sensor->ctrls.exposure,
+ sensor->ctrls.exposure->minimum,
+ exp_max, sensor->ctrls.exposure->step,
+ sensor->ctrls.exposure->default_value);
break;
}
@@ -455,6 +555,10 @@ static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_VBLANK:
ret = ar0521_set_geometry(sensor);
break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ar0521_write_reg(sensor, AR0521_REG_ANA_GAIN_CODE_GLOBAL,
+ ctrl->val);
+ break;
case V4L2_CID_GAIN:
case V4L2_CID_RED_BALANCE:
case V4L2_CID_BLUE_BALANCE:
@@ -469,6 +573,11 @@ static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl)
ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE,
ctrl->val);
break;
+ default:
+ dev_err(&sensor->i2c_client->dev,
+ "Unsupported control %x\n", ctrl->id);
+ ret = -EINVAL;
+ break;
}
pm_runtime_put(&sensor->i2c_client->dev);
@@ -491,6 +600,8 @@ static int ar0521_init_controls(struct ar0521_dev *sensor)
const struct v4l2_ctrl_ops *ops = &ar0521_ctrl_ops;
struct ar0521_ctrls *ctrls = &sensor->ctrls;
struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int max_vblank, max_hblank, exposure_max;
+ struct v4l2_ctrl *link_freq;
int ret;
v4l2_ctrl_handler_init(hdl, 32);
@@ -498,6 +609,11 @@ static int ar0521_init_controls(struct ar0521_dev *sensor)
/* We can use our own mutex for the ctrl lock */
hdl->lock = &sensor->lock;
+ /* Analog gain */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
+ AR0521_ANA_GAIN_MIN, AR0521_ANA_GAIN_MAX,
+ AR0521_ANA_GAIN_STEP, AR0521_ANA_GAIN_DEFAULT);
+
/* Manual gain */
ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 511, 1, 0);
ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
@@ -506,11 +622,17 @@ static int ar0521_init_controls(struct ar0521_dev *sensor)
-512, 511, 1, 0);
v4l2_ctrl_cluster(3, &ctrls->gain);
+ /* Initialize blanking limits using the default 2592x1944 format. */
+ max_hblank = AR0521_TOTAL_WIDTH_MAX - AR0521_WIDTH_MAX;
ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
- AR0521_WIDTH_BLANKING_MIN, 4094, 1,
+ AR0521_WIDTH_BLANKING_MIN,
+ max_hblank, 1,
AR0521_WIDTH_BLANKING_MIN);
+
+ max_vblank = AR0521_TOTAL_HEIGHT_MAX - AR0521_HEIGHT_MAX;
ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
- AR0521_HEIGHT_BLANKING_MIN, 4094, 2,
+ AR0521_HEIGHT_BLANKING_MIN,
+ max_vblank, 2,
AR0521_HEIGHT_BLANKING_MIN);
v4l2_ctrl_cluster(2, &ctrls->hblank);
@@ -520,9 +642,16 @@ static int ar0521_init_controls(struct ar0521_dev *sensor)
AR0521_PIXEL_CLOCK_MAX, 1,
AR0521_PIXEL_CLOCK_RATE);
- /* Manual exposure time */
+ /* Manual exposure time: max exposure time = visible + blank - 4 */
+ exposure_max = AR0521_HEIGHT_MAX + AR0521_HEIGHT_BLANKING_MIN - 4;
ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0,
- 65535, 1, 360);
+ exposure_max, 1, 0x70);
+
+ link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(ar0521_link_frequencies) - 1,
+ 0, ar0521_link_frequencies);
+ if (link_freq)
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ctrls->test_pattern = v4l2_ctrl_new_std_menu_items(hdl, ops,
V4L2_CID_TEST_PATTERN,
@@ -799,6 +928,24 @@ static int ar0521_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
+static int ar0521_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index)
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SGRBG8_1X8)
+ return -EINVAL;
+
+ fse->min_width = AR0521_WIDTH_MIN;
+ fse->max_width = AR0521_WIDTH_MAX;
+ fse->min_height = AR0521_HEIGHT_MIN;
+ fse->max_height = AR0521_HEIGHT_MAX;
+
+ return 0;
+}
+
static int ar0521_pre_streamon(struct v4l2_subdev *sd, u32 flags)
{
struct ar0521_dev *sensor = to_ar0521_dev(sd);
@@ -865,6 +1012,7 @@ static const struct v4l2_subdev_video_ops ar0521_video_ops = {
static const struct v4l2_subdev_pad_ops ar0521_pad_ops = {
.enum_mbus_code = ar0521_enum_mbus_code,
+ .enum_frame_size = ar0521_enum_frame_size,
.get_fmt = ar0521_get_fmt,
.set_fmt = ar0521_set_fmt,
};
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
index 4d9bb6eb7d65..39f8a5361166 100644
--- a/drivers/media/i2c/bt819.c
+++ b/drivers/media/i2c/bt819.c
@@ -380,8 +380,7 @@ static const struct v4l2_subdev_ops bt819_ops = {
/* ----------------------------------------------------------------------- */
-static int bt819_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bt819_probe(struct i2c_client *client)
{
int i, ver;
struct bt819 *decoder;
@@ -469,7 +468,7 @@ static struct i2c_driver bt819_driver = {
.driver = {
.name = "bt819",
},
- .probe = bt819_probe,
+ .probe_new = bt819_probe,
.remove = bt819_remove,
.id_table = bt819_id,
};
diff --git a/drivers/media/i2c/bt856.c b/drivers/media/i2c/bt856.c
index 70443ef1ac46..d1d397b15b85 100644
--- a/drivers/media/i2c/bt856.c
+++ b/drivers/media/i2c/bt856.c
@@ -181,8 +181,7 @@ static const struct v4l2_subdev_ops bt856_ops = {
/* ----------------------------------------------------------------------- */
-static int bt856_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bt856_probe(struct i2c_client *client)
{
struct bt856 *encoder;
struct v4l2_subdev *sd;
@@ -240,7 +239,7 @@ static struct i2c_driver bt856_driver = {
.driver = {
.name = "bt856",
},
- .probe = bt856_probe,
+ .probe_new = bt856_probe,
.remove = bt856_remove,
.id_table = bt856_id,
};
diff --git a/drivers/media/i2c/bt866.c b/drivers/media/i2c/bt866.c
index c2508cbafd02..d632d9a07f04 100644
--- a/drivers/media/i2c/bt866.c
+++ b/drivers/media/i2c/bt866.c
@@ -173,8 +173,7 @@ static const struct v4l2_subdev_ops bt866_ops = {
.video = &bt866_video_ops,
};
-static int bt866_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bt866_probe(struct i2c_client *client)
{
struct bt866 *encoder;
struct v4l2_subdev *sd;
@@ -207,7 +206,7 @@ static struct i2c_driver bt866_driver = {
.driver = {
.name = "bt866",
},
- .probe = bt866_probe,
+ .probe_new = bt866_probe,
.remove = bt866_remove,
.id_table = bt866_id,
};
diff --git a/drivers/media/i2c/cs3308.c b/drivers/media/i2c/cs3308.c
index d901a59883a9..a0b66c04fe25 100644
--- a/drivers/media/i2c/cs3308.c
+++ b/drivers/media/i2c/cs3308.c
@@ -64,8 +64,7 @@ static const struct v4l2_subdev_ops cs3308_ops = {
/* ----------------------------------------------------------------------- */
-static int cs3308_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cs3308_probe(struct i2c_client *client)
{
struct v4l2_subdev *sd;
unsigned i;
@@ -119,7 +118,7 @@ static struct i2c_driver cs3308_driver = {
.driver = {
.name = "cs3308",
},
- .probe = cs3308_probe,
+ .probe_new = cs3308_probe,
.remove = cs3308_remove,
.id_table = cs3308_id,
};
diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c
index 591b1e7b24ee..ac4b5632fc46 100644
--- a/drivers/media/i2c/cs5345.c
+++ b/drivers/media/i2c/cs5345.c
@@ -136,8 +136,7 @@ static const struct v4l2_subdev_ops cs5345_ops = {
/* ----------------------------------------------------------------------- */
-static int cs5345_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cs5345_probe(struct i2c_client *client)
{
struct cs5345_state *state;
struct v4l2_subdev *sd;
@@ -199,7 +198,7 @@ static struct i2c_driver cs5345_driver = {
.driver = {
.name = "cs5345",
},
- .probe = cs5345_probe,
+ .probe_new = cs5345_probe,
.remove = cs5345_remove,
.id_table = cs5345_id,
};
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index f1a978af82ef..46cf422270b2 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -5825,8 +5825,7 @@ static u32 get_cx2388x_ident(struct i2c_client *client)
return ret;
}
-static int cx25840_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int cx25840_probe(struct i2c_client *client)
{
struct cx25840_state *state;
struct v4l2_subdev *sd;
@@ -6046,7 +6045,7 @@ static struct i2c_driver cx25840_driver = {
.driver = {
.name = "cx25840",
},
- .probe = cx25840_probe,
+ .probe_new = cx25840_probe,
.remove = cx25840_remove,
.id_table = cx25840_id,
};
diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c
index 0f47ef015a1d..83a3ee275bbe 100644
--- a/drivers/media/i2c/dw9768.c
+++ b/drivers/media/i2c/dw9768.c
@@ -414,6 +414,7 @@ static int dw9768_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct dw9768 *dw9768;
+ bool full_power;
unsigned int i;
int ret;
@@ -469,13 +470,23 @@ static int dw9768_probe(struct i2c_client *client)
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
+ /*
+ * Figure out whether we're going to power up the device here. Generally
+ * this is done if CONFIG_PM is disabled in a DT system or the device is
+ * to be powered on in an ACPI system. Similarly for power off in
+ * remove.
+ */
pm_runtime_enable(dev);
- if (!pm_runtime_enabled(dev)) {
+ full_power = (is_acpi_node(dev_fwnode(dev)) &&
+ acpi_dev_state_d0(dev)) ||
+ (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev));
+ if (full_power) {
ret = dw9768_runtime_resume(dev);
if (ret < 0) {
dev_err(dev, "failed to power on: %d\n", ret);
goto err_clean_entity;
}
+ pm_runtime_set_active(dev);
}
ret = v4l2_async_register_subdev(&dw9768->sd);
@@ -484,14 +495,17 @@ static int dw9768_probe(struct i2c_client *client)
goto err_power_off;
}
+ pm_runtime_idle(dev);
+
return 0;
err_power_off:
- if (pm_runtime_enabled(dev))
- pm_runtime_disable(dev);
- else
+ if (full_power) {
dw9768_runtime_suspend(dev);
+ pm_runtime_set_suspended(dev);
+ }
err_clean_entity:
+ pm_runtime_disable(dev);
media_entity_cleanup(&dw9768->sd.entity);
err_free_handler:
v4l2_ctrl_handler_free(&dw9768->ctrls);
@@ -503,14 +517,17 @@ static void dw9768_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct dw9768 *dw9768 = sd_to_dw9768(sd);
+ struct device *dev = &client->dev;
v4l2_async_unregister_subdev(&dw9768->sd);
v4l2_ctrl_handler_free(&dw9768->ctrls);
media_entity_cleanup(&dw9768->sd.entity);
- pm_runtime_disable(&client->dev);
- if (!pm_runtime_status_suspended(&client->dev))
- dw9768_runtime_suspend(&client->dev);
- pm_runtime_set_suspended(&client->dev);
+ if ((is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) ||
+ (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev))) {
+ dw9768_runtime_suspend(dev);
+ pm_runtime_set_suspended(dev);
+ }
+ pm_runtime_disable(dev);
}
static const struct of_device_id dw9768_of_table[] = {
diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c
index c5b69823f257..7c61873b7198 100644
--- a/drivers/media/i2c/hi846.c
+++ b/drivers/media/i2c/hi846.c
@@ -2008,22 +2008,24 @@ static int hi846_parse_dt(struct hi846 *hi846, struct device *dev)
bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
dev_err(dev, "number of CSI2 data lanes %d is not supported",
bus_cfg.bus.mipi_csi2.num_data_lanes);
- v4l2_fwnode_endpoint_free(&bus_cfg);
- return -EINVAL;
+ ret = -EINVAL;
+ goto check_hwcfg_error;
}
hi846->nr_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
if (!bus_cfg.nr_of_link_frequencies) {
dev_err(dev, "link-frequency property not found in DT\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto check_hwcfg_error;
}
/* Check that link frequences for all the modes are in device tree */
fq = hi846_check_link_freqs(hi846, &bus_cfg);
if (fq) {
dev_err(dev, "Link frequency of %lld is not supported\n", fq);
- return -EINVAL;
+ ret = -EINVAL;
+ goto check_hwcfg_error;
}
v4l2_fwnode_endpoint_free(&bus_cfg);
@@ -2044,6 +2046,10 @@ static int hi846_parse_dt(struct hi846 *hi846, struct device *dev)
}
return 0;
+
+check_hwcfg_error:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ return ret;
}
static int hi846_probe(struct i2c_client *client)
diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c
index a0e17bb9d4ca..64c70ebf9869 100644
--- a/drivers/media/i2c/imx208.c
+++ b/drivers/media/i2c/imx208.c
@@ -937,8 +937,12 @@ static int imx208_init_controls(struct imx208 *imx208)
imx208->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx208->hflip)
+ imx208->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
imx208->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx208->vflip)
+ imx208->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
IMX208_ANA_GAIN_MIN, IMX208_ANA_GAIN_MAX,
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index a00761b1e18c..9219f3c9594b 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -2060,9 +2060,8 @@ static int imx274_probe(struct i2c_client *client)
imx274->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(imx274->reset_gpio)) {
- if (PTR_ERR(imx274->reset_gpio) != -EPROBE_DEFER)
- dev_err(dev, "Reset GPIO not setup in DT");
- ret = PTR_ERR(imx274->reset_gpio);
+ ret = dev_err_probe(dev, PTR_ERR(imx274->reset_gpio),
+ "Reset GPIO not setup in DT\n");
goto err_me;
}
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 1ce64dcdf7f0..218ded13fd80 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -22,22 +22,135 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define IMX290_STANDBY 0x3000
-#define IMX290_REGHOLD 0x3001
-#define IMX290_XMSTA 0x3002
-#define IMX290_FR_FDG_SEL 0x3009
-#define IMX290_BLKLEVEL_LOW 0x300a
-#define IMX290_BLKLEVEL_HIGH 0x300b
-#define IMX290_GAIN 0x3014
-#define IMX290_HMAX_LOW 0x301c
-#define IMX290_HMAX_HIGH 0x301d
-#define IMX290_PGCTRL 0x308c
-#define IMX290_PHY_LANE_NUM 0x3407
-#define IMX290_CSI_LANE_MODE 0x3443
-
-#define IMX290_PGCTRL_REGEN BIT(0)
-#define IMX290_PGCTRL_THRU BIT(1)
-#define IMX290_PGCTRL_MODE(n) ((n) << 4)
+#define IMX290_REG_SIZE_SHIFT 16
+#define IMX290_REG_ADDR_MASK 0xffff
+#define IMX290_REG_8BIT(n) ((1U << IMX290_REG_SIZE_SHIFT) | (n))
+#define IMX290_REG_16BIT(n) ((2U << IMX290_REG_SIZE_SHIFT) | (n))
+#define IMX290_REG_24BIT(n) ((3U << IMX290_REG_SIZE_SHIFT) | (n))
+
+#define IMX290_STANDBY IMX290_REG_8BIT(0x3000)
+#define IMX290_REGHOLD IMX290_REG_8BIT(0x3001)
+#define IMX290_XMSTA IMX290_REG_8BIT(0x3002)
+#define IMX290_ADBIT IMX290_REG_8BIT(0x3005)
+#define IMX290_ADBIT_10BIT (0 << 0)
+#define IMX290_ADBIT_12BIT (1 << 0)
+#define IMX290_CTRL_07 IMX290_REG_8BIT(0x3007)
+#define IMX290_VREVERSE BIT(0)
+#define IMX290_HREVERSE BIT(1)
+#define IMX290_WINMODE_1080P (0 << 4)
+#define IMX290_WINMODE_720P (1 << 4)
+#define IMX290_WINMODE_CROP (4 << 4)
+#define IMX290_FR_FDG_SEL IMX290_REG_8BIT(0x3009)
+#define IMX290_BLKLEVEL IMX290_REG_16BIT(0x300a)
+#define IMX290_GAIN IMX290_REG_8BIT(0x3014)
+#define IMX290_VMAX IMX290_REG_24BIT(0x3018)
+#define IMX290_HMAX IMX290_REG_16BIT(0x301c)
+#define IMX290_SHS1 IMX290_REG_24BIT(0x3020)
+#define IMX290_WINWV_OB IMX290_REG_8BIT(0x303a)
+#define IMX290_WINPV IMX290_REG_16BIT(0x303c)
+#define IMX290_WINWV IMX290_REG_16BIT(0x303e)
+#define IMX290_WINPH IMX290_REG_16BIT(0x3040)
+#define IMX290_WINWH IMX290_REG_16BIT(0x3042)
+#define IMX290_OUT_CTRL IMX290_REG_8BIT(0x3046)
+#define IMX290_ODBIT_10BIT (0 << 0)
+#define IMX290_ODBIT_12BIT (1 << 0)
+#define IMX290_OPORTSEL_PARALLEL (0x0 << 4)
+#define IMX290_OPORTSEL_LVDS_2CH (0xd << 4)
+#define IMX290_OPORTSEL_LVDS_4CH (0xe << 4)
+#define IMX290_OPORTSEL_LVDS_8CH (0xf << 4)
+#define IMX290_XSOUTSEL IMX290_REG_8BIT(0x304b)
+#define IMX290_XSOUTSEL_XVSOUTSEL_HIGH (0 << 0)
+#define IMX290_XSOUTSEL_XVSOUTSEL_VSYNC (2 << 0)
+#define IMX290_XSOUTSEL_XHSOUTSEL_HIGH (0 << 2)
+#define IMX290_XSOUTSEL_XHSOUTSEL_HSYNC (2 << 2)
+#define IMX290_INCKSEL1 IMX290_REG_8BIT(0x305c)
+#define IMX290_INCKSEL2 IMX290_REG_8BIT(0x305d)
+#define IMX290_INCKSEL3 IMX290_REG_8BIT(0x305e)
+#define IMX290_INCKSEL4 IMX290_REG_8BIT(0x305f)
+#define IMX290_PGCTRL IMX290_REG_8BIT(0x308c)
+#define IMX290_ADBIT1 IMX290_REG_8BIT(0x3129)
+#define IMX290_ADBIT1_10BIT 0x1d
+#define IMX290_ADBIT1_12BIT 0x00
+#define IMX290_INCKSEL5 IMX290_REG_8BIT(0x315e)
+#define IMX290_INCKSEL6 IMX290_REG_8BIT(0x3164)
+#define IMX290_ADBIT2 IMX290_REG_8BIT(0x317c)
+#define IMX290_ADBIT2_10BIT 0x12
+#define IMX290_ADBIT2_12BIT 0x00
+#define IMX290_CHIP_ID IMX290_REG_16BIT(0x319a)
+#define IMX290_ADBIT3 IMX290_REG_8BIT(0x31ec)
+#define IMX290_ADBIT3_10BIT 0x37
+#define IMX290_ADBIT3_12BIT 0x0e
+#define IMX290_REPETITION IMX290_REG_8BIT(0x3405)
+#define IMX290_PHY_LANE_NUM IMX290_REG_8BIT(0x3407)
+#define IMX290_OPB_SIZE_V IMX290_REG_8BIT(0x3414)
+#define IMX290_Y_OUT_SIZE IMX290_REG_16BIT(0x3418)
+#define IMX290_CSI_DT_FMT IMX290_REG_16BIT(0x3441)
+#define IMX290_CSI_DT_FMT_RAW10 0x0a0a
+#define IMX290_CSI_DT_FMT_RAW12 0x0c0c
+#define IMX290_CSI_LANE_MODE IMX290_REG_8BIT(0x3443)
+#define IMX290_EXTCK_FREQ IMX290_REG_16BIT(0x3444)
+#define IMX290_TCLKPOST IMX290_REG_16BIT(0x3446)
+#define IMX290_THSZERO IMX290_REG_16BIT(0x3448)
+#define IMX290_THSPREPARE IMX290_REG_16BIT(0x344a)
+#define IMX290_TCLKTRAIL IMX290_REG_16BIT(0x344c)
+#define IMX290_THSTRAIL IMX290_REG_16BIT(0x344e)
+#define IMX290_TCLKZERO IMX290_REG_16BIT(0x3450)
+#define IMX290_TCLKPREPARE IMX290_REG_16BIT(0x3452)
+#define IMX290_TLPX IMX290_REG_16BIT(0x3454)
+#define IMX290_X_OUT_SIZE IMX290_REG_16BIT(0x3472)
+
+#define IMX290_PGCTRL_REGEN BIT(0)
+#define IMX290_PGCTRL_THRU BIT(1)
+#define IMX290_PGCTRL_MODE(n) ((n) << 4)
+
+#define IMX290_VMAX_DEFAULT 1125
+
+
+/*
+ * The IMX290 pixel array is organized as follows:
+ *
+ * +------------------------------------+
+ * | Optical Black | } Vertical effective optical black (10)
+ * +---+------------------------------------+---+
+ * | | | | } Effective top margin (8)
+ * | | +----------------------------+ | | \
+ * | | | | | | |
+ * | | | | | | |
+ * | | | | | | |
+ * | | | Recording Pixel Area | | | | Recommended height (1080)
+ * | | | | | | |
+ * | | | | | | |
+ * | | | | | | |
+ * | | +----------------------------+ | | /
+ * | | | | } Effective bottom margin (9)
+ * +---+------------------------------------+---+
+ * <-> <-> <--------------------------> <-> <->
+ * \---- Ignored right margin (4)
+ * \-------- Effective right margin (9)
+ * \------------------------- Recommended width (1920)
+ * \----------------------------------------- Effective left margin (8)
+ * \--------------------------------------------- Ignored left margin (4)
+ *
+ * The optical black lines are output over CSI-2 with a separate data type.
+ *
+ * The pixel array is meant to have 1920x1080 usable pixels after image
+ * processing in an ISP. It has 8 (9) extra active pixels usable for color
+ * processing in the ISP on the top and left (bottom and right) sides of the
+ * image. In addition, 4 additional pixels are present on the left and right
+ * sides of the image, documented as "ignored area".
+ *
+ * As far as is understood, all pixels of the pixel array (ignored area, color
+ * processing margins and recording area) can be output by the sensor.
+ */
+
+#define IMX290_PIXEL_ARRAY_WIDTH 1945
+#define IMX290_PIXEL_ARRAY_HEIGHT 1097
+#define IMX920_PIXEL_ARRAY_MARGIN_LEFT 12
+#define IMX920_PIXEL_ARRAY_MARGIN_RIGHT 13
+#define IMX920_PIXEL_ARRAY_MARGIN_TOP 8
+#define IMX920_PIXEL_ARRAY_MARGIN_BOTTOM 9
+#define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920
+#define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080
static const char * const imx290_supply_name[] = {
"vdda",
@@ -48,8 +161,8 @@ static const char * const imx290_supply_name[] = {
#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name)
struct imx290_regval {
- u16 reg;
- u8 val;
+ u32 reg;
+ u32 val;
};
struct imx290_mode {
@@ -80,6 +193,8 @@ struct imx290 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
struct mutex lock;
};
@@ -97,7 +212,6 @@ static const struct imx290_pixfmt imx290_formats[] = {
static const struct regmap_config imx290_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
};
static const char * const imx290_test_pattern_menu[] = {
@@ -112,163 +226,129 @@ static const char * const imx290_test_pattern_menu[] = {
};
static const struct imx290_regval imx290_global_init_settings[] = {
- { 0x3007, 0x00 },
- { 0x3018, 0x65 },
- { 0x3019, 0x04 },
- { 0x301a, 0x00 },
- { 0x3444, 0x20 },
- { 0x3445, 0x25 },
- { 0x303a, 0x0c },
- { 0x3040, 0x00 },
- { 0x3041, 0x00 },
- { 0x303c, 0x00 },
- { 0x303d, 0x00 },
- { 0x3042, 0x9c },
- { 0x3043, 0x07 },
- { 0x303e, 0x49 },
- { 0x303f, 0x04 },
- { 0x304b, 0x0a },
- { 0x300f, 0x00 },
- { 0x3010, 0x21 },
- { 0x3012, 0x64 },
- { 0x3016, 0x09 },
- { 0x3070, 0x02 },
- { 0x3071, 0x11 },
- { 0x309b, 0x10 },
- { 0x309c, 0x22 },
- { 0x30a2, 0x02 },
- { 0x30a6, 0x20 },
- { 0x30a8, 0x20 },
- { 0x30aa, 0x20 },
- { 0x30ac, 0x20 },
- { 0x30b0, 0x43 },
- { 0x3119, 0x9e },
- { 0x311c, 0x1e },
- { 0x311e, 0x08 },
- { 0x3128, 0x05 },
- { 0x313d, 0x83 },
- { 0x3150, 0x03 },
- { 0x317e, 0x00 },
- { 0x32b8, 0x50 },
- { 0x32b9, 0x10 },
- { 0x32ba, 0x00 },
- { 0x32bb, 0x04 },
- { 0x32c8, 0x50 },
- { 0x32c9, 0x10 },
- { 0x32ca, 0x00 },
- { 0x32cb, 0x04 },
- { 0x332c, 0xd3 },
- { 0x332d, 0x10 },
- { 0x332e, 0x0d },
- { 0x3358, 0x06 },
- { 0x3359, 0xe1 },
- { 0x335a, 0x11 },
- { 0x3360, 0x1e },
- { 0x3361, 0x61 },
- { 0x3362, 0x10 },
- { 0x33b0, 0x50 },
- { 0x33b2, 0x1a },
- { 0x33b3, 0x04 },
+ { IMX290_CTRL_07, IMX290_WINMODE_1080P },
+ { IMX290_VMAX, IMX290_VMAX_DEFAULT },
+ { IMX290_EXTCK_FREQ, 0x2520 },
+ { IMX290_WINWV_OB, 12 },
+ { IMX290_WINPH, 0 },
+ { IMX290_WINPV, 0 },
+ { IMX290_WINWH, 1948 },
+ { IMX290_WINWV, 1097 },
+ { IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC |
+ IMX290_XSOUTSEL_XHSOUTSEL_HSYNC },
+ { IMX290_REG_8BIT(0x300f), 0x00 },
+ { IMX290_REG_8BIT(0x3010), 0x21 },
+ { IMX290_REG_8BIT(0x3012), 0x64 },
+ { IMX290_REG_8BIT(0x3013), 0x00 },
+ { IMX290_REG_8BIT(0x3016), 0x09 },
+ { IMX290_REG_8BIT(0x3070), 0x02 },
+ { IMX290_REG_8BIT(0x3071), 0x11 },
+ { IMX290_REG_8BIT(0x309b), 0x10 },
+ { IMX290_REG_8BIT(0x309c), 0x22 },
+ { IMX290_REG_8BIT(0x30a2), 0x02 },
+ { IMX290_REG_8BIT(0x30a6), 0x20 },
+ { IMX290_REG_8BIT(0x30a8), 0x20 },
+ { IMX290_REG_8BIT(0x30aa), 0x20 },
+ { IMX290_REG_8BIT(0x30ac), 0x20 },
+ { IMX290_REG_8BIT(0x30b0), 0x43 },
+ { IMX290_REG_8BIT(0x3119), 0x9e },
+ { IMX290_REG_8BIT(0x311c), 0x1e },
+ { IMX290_REG_8BIT(0x311e), 0x08 },
+ { IMX290_REG_8BIT(0x3128), 0x05 },
+ { IMX290_REG_8BIT(0x313d), 0x83 },
+ { IMX290_REG_8BIT(0x3150), 0x03 },
+ { IMX290_REG_8BIT(0x317e), 0x00 },
+ { IMX290_REG_8BIT(0x32b8), 0x50 },
+ { IMX290_REG_8BIT(0x32b9), 0x10 },
+ { IMX290_REG_8BIT(0x32ba), 0x00 },
+ { IMX290_REG_8BIT(0x32bb), 0x04 },
+ { IMX290_REG_8BIT(0x32c8), 0x50 },
+ { IMX290_REG_8BIT(0x32c9), 0x10 },
+ { IMX290_REG_8BIT(0x32ca), 0x00 },
+ { IMX290_REG_8BIT(0x32cb), 0x04 },
+ { IMX290_REG_8BIT(0x332c), 0xd3 },
+ { IMX290_REG_8BIT(0x332d), 0x10 },
+ { IMX290_REG_8BIT(0x332e), 0x0d },
+ { IMX290_REG_8BIT(0x3358), 0x06 },
+ { IMX290_REG_8BIT(0x3359), 0xe1 },
+ { IMX290_REG_8BIT(0x335a), 0x11 },
+ { IMX290_REG_8BIT(0x3360), 0x1e },
+ { IMX290_REG_8BIT(0x3361), 0x61 },
+ { IMX290_REG_8BIT(0x3362), 0x10 },
+ { IMX290_REG_8BIT(0x33b0), 0x50 },
+ { IMX290_REG_8BIT(0x33b2), 0x1a },
+ { IMX290_REG_8BIT(0x33b3), 0x04 },
+ { IMX290_REG_8BIT(0x3480), 0x49 },
};
static const struct imx290_regval imx290_1080p_settings[] = {
/* mode settings */
- { 0x3007, 0x00 },
- { 0x303a, 0x0c },
- { 0x3414, 0x0a },
- { 0x3472, 0x80 },
- { 0x3473, 0x07 },
- { 0x3418, 0x38 },
- { 0x3419, 0x04 },
- { 0x3012, 0x64 },
- { 0x3013, 0x00 },
- { 0x305c, 0x18 },
- { 0x305d, 0x03 },
- { 0x305e, 0x20 },
- { 0x305f, 0x01 },
- { 0x315e, 0x1a },
- { 0x3164, 0x1a },
- { 0x3480, 0x49 },
+ { IMX290_CTRL_07, IMX290_WINMODE_1080P },
+ { IMX290_WINWV_OB, 12 },
+ { IMX290_OPB_SIZE_V, 10 },
+ { IMX290_X_OUT_SIZE, 1920 },
+ { IMX290_Y_OUT_SIZE, 1080 },
+ { IMX290_INCKSEL1, 0x18 },
+ { IMX290_INCKSEL2, 0x03 },
+ { IMX290_INCKSEL3, 0x20 },
+ { IMX290_INCKSEL4, 0x01 },
+ { IMX290_INCKSEL5, 0x1a },
+ { IMX290_INCKSEL6, 0x1a },
/* data rate settings */
- { 0x3405, 0x10 },
- { 0x3446, 0x57 },
- { 0x3447, 0x00 },
- { 0x3448, 0x37 },
- { 0x3449, 0x00 },
- { 0x344a, 0x1f },
- { 0x344b, 0x00 },
- { 0x344c, 0x1f },
- { 0x344d, 0x00 },
- { 0x344e, 0x1f },
- { 0x344f, 0x00 },
- { 0x3450, 0x77 },
- { 0x3451, 0x00 },
- { 0x3452, 0x1f },
- { 0x3453, 0x00 },
- { 0x3454, 0x17 },
- { 0x3455, 0x00 },
+ { IMX290_REPETITION, 0x10 },
+ { IMX290_TCLKPOST, 87 },
+ { IMX290_THSZERO, 55 },
+ { IMX290_THSPREPARE, 31 },
+ { IMX290_TCLKTRAIL, 31 },
+ { IMX290_THSTRAIL, 31 },
+ { IMX290_TCLKZERO, 119 },
+ { IMX290_TCLKPREPARE, 31 },
+ { IMX290_TLPX, 23 },
};
static const struct imx290_regval imx290_720p_settings[] = {
/* mode settings */
- { 0x3007, 0x10 },
- { 0x303a, 0x06 },
- { 0x3414, 0x04 },
- { 0x3472, 0x00 },
- { 0x3473, 0x05 },
- { 0x3418, 0xd0 },
- { 0x3419, 0x02 },
- { 0x3012, 0x64 },
- { 0x3013, 0x00 },
- { 0x305c, 0x20 },
- { 0x305d, 0x00 },
- { 0x305e, 0x20 },
- { 0x305f, 0x01 },
- { 0x315e, 0x1a },
- { 0x3164, 0x1a },
- { 0x3480, 0x49 },
+ { IMX290_CTRL_07, IMX290_WINMODE_720P },
+ { IMX290_WINWV_OB, 6 },
+ { IMX290_OPB_SIZE_V, 4 },
+ { IMX290_X_OUT_SIZE, 1280 },
+ { IMX290_Y_OUT_SIZE, 720 },
+ { IMX290_INCKSEL1, 0x20 },
+ { IMX290_INCKSEL2, 0x00 },
+ { IMX290_INCKSEL3, 0x20 },
+ { IMX290_INCKSEL4, 0x01 },
+ { IMX290_INCKSEL5, 0x1a },
+ { IMX290_INCKSEL6, 0x1a },
/* data rate settings */
- { 0x3405, 0x10 },
- { 0x3446, 0x4f },
- { 0x3447, 0x00 },
- { 0x3448, 0x2f },
- { 0x3449, 0x00 },
- { 0x344a, 0x17 },
- { 0x344b, 0x00 },
- { 0x344c, 0x17 },
- { 0x344d, 0x00 },
- { 0x344e, 0x17 },
- { 0x344f, 0x00 },
- { 0x3450, 0x57 },
- { 0x3451, 0x00 },
- { 0x3452, 0x17 },
- { 0x3453, 0x00 },
- { 0x3454, 0x17 },
- { 0x3455, 0x00 },
+ { IMX290_REPETITION, 0x10 },
+ { IMX290_TCLKPOST, 79 },
+ { IMX290_THSZERO, 47 },
+ { IMX290_THSPREPARE, 23 },
+ { IMX290_TCLKTRAIL, 23 },
+ { IMX290_THSTRAIL, 23 },
+ { IMX290_TCLKZERO, 87 },
+ { IMX290_TCLKPREPARE, 23 },
+ { IMX290_TLPX, 23 },
};
static const struct imx290_regval imx290_10bit_settings[] = {
- { 0x3005, 0x00},
- { 0x3046, 0x00},
- { 0x3129, 0x1d},
- { 0x317c, 0x12},
- { 0x31ec, 0x37},
- { 0x3441, 0x0a},
- { 0x3442, 0x0a},
- { 0x300a, 0x3c},
- { 0x300b, 0x00},
+ { IMX290_ADBIT, IMX290_ADBIT_10BIT },
+ { IMX290_OUT_CTRL, IMX290_ODBIT_10BIT },
+ { IMX290_ADBIT1, IMX290_ADBIT1_10BIT },
+ { IMX290_ADBIT2, IMX290_ADBIT2_10BIT },
+ { IMX290_ADBIT3, IMX290_ADBIT3_10BIT },
+ { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 },
+ { IMX290_BLKLEVEL, 60 },
};
static const struct imx290_regval imx290_12bit_settings[] = {
- { 0x3005, 0x01 },
- { 0x3046, 0x01 },
- { 0x3129, 0x00 },
- { 0x317c, 0x00 },
- { 0x31ec, 0x0e },
- { 0x3441, 0x0c },
- { 0x3442, 0x0c },
- { 0x300a, 0xf0 },
- { 0x300b, 0x00 },
+ { IMX290_ADBIT, IMX290_ADBIT_12BIT },
+ { IMX290_OUT_CTRL, IMX290_ODBIT_12BIT },
+ { IMX290_ADBIT1, IMX290_ADBIT1_12BIT },
+ { IMX290_ADBIT2, IMX290_ADBIT2_12BIT },
+ { IMX290_ADBIT3, IMX290_ADBIT3_12BIT },
+ { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 },
+ { IMX290_BLKLEVEL, 240 },
};
/* supported link frequencies */
@@ -308,7 +388,7 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
{
.width = 1920,
.height = 1080,
- .hmax = 0x1130,
+ .hmax = 4400,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
@@ -316,7 +396,7 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
{
.width = 1280,
.height = 720,
- .hmax = 0x19c8,
+ .hmax = 6600,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
@@ -327,7 +407,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
{
.width = 1920,
.height = 1080,
- .hmax = 0x0898,
+ .hmax = 2200,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
@@ -335,7 +415,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
{
.width = 1280,
.height = 720,
- .hmax = 0x0ce4,
+ .hmax = 3300,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
@@ -363,30 +443,40 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
return container_of(_sd, struct imx290, sd);
}
-static inline int __always_unused imx290_read_reg(struct imx290 *imx290, u16 addr, u8 *value)
+static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value)
{
- unsigned int regval;
+ u8 data[3] = { 0, 0, 0 };
int ret;
- ret = regmap_read(imx290->regmap, addr, &regval);
- if (ret) {
- dev_err(imx290->dev, "I2C read failed for addr: %x\n", addr);
+ ret = regmap_raw_read(imx290->regmap, addr & IMX290_REG_ADDR_MASK,
+ data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
+ if (ret < 0) {
+ dev_err(imx290->dev, "%u-bit read from 0x%04x failed: %d\n",
+ ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX290_REG_ADDR_MASK, ret);
return ret;
}
- *value = regval & 0xff;
-
+ *value = (data[2] << 16) | (data[1] << 8) | data[0];
return 0;
}
-static int imx290_write_reg(struct imx290 *imx290, u16 addr, u8 value)
+static int imx290_write(struct imx290 *imx290, u32 addr, u32 value, int *err)
{
+ u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
int ret;
- ret = regmap_write(imx290->regmap, addr, value);
- if (ret) {
- dev_err(imx290->dev, "I2C write failed for addr: %x\n", addr);
- return ret;
+ if (err && *err)
+ return *err;
+
+ ret = regmap_raw_write(imx290->regmap, addr & IMX290_REG_ADDR_MASK,
+ data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
+ if (ret < 0) {
+ dev_err(imx290->dev, "%u-bit write to 0x%04x failed: %d\n",
+ ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX290_REG_ADDR_MASK, ret);
+ if (err)
+ *err = ret;
}
return ret;
@@ -400,7 +490,7 @@ static int imx290_set_register_array(struct imx290 *imx290,
int ret;
for (i = 0; i < num_settings; ++i, ++settings) {
- ret = imx290_write_reg(imx290, settings->reg, settings->val);
+ ret = imx290_write(imx290, settings->reg, settings->val, NULL);
if (ret < 0)
return ret;
}
@@ -411,59 +501,16 @@ static int imx290_set_register_array(struct imx290 *imx290,
return 0;
}
-static int imx290_write_buffered_reg(struct imx290 *imx290, u16 address_low,
- u8 nr_regs, u32 value)
-{
- unsigned int i;
- int ret;
-
- ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x01);
- if (ret) {
- dev_err(imx290->dev, "Error setting hold register\n");
- return ret;
- }
-
- for (i = 0; i < nr_regs; i++) {
- ret = imx290_write_reg(imx290, address_low + i,
- (u8)(value >> (i * 8)));
- if (ret) {
- dev_err(imx290->dev, "Error writing buffered registers\n");
- return ret;
- }
- }
-
- ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x00);
- if (ret) {
- dev_err(imx290->dev, "Error setting hold register\n");
- return ret;
- }
-
- return ret;
-}
-
-static int imx290_set_gain(struct imx290 *imx290, u32 value)
-{
- int ret;
-
- ret = imx290_write_buffered_reg(imx290, IMX290_GAIN, 1, value);
- if (ret)
- dev_err(imx290->dev, "Unable to write gain\n");
-
- return ret;
-}
-
/* Stop streaming */
static int imx290_stop_streaming(struct imx290 *imx290)
{
- int ret;
+ int ret = 0;
- ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x01);
- if (ret < 0)
- return ret;
+ imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
msleep(30);
- return imx290_write_reg(imx290, IMX290_XMSTA, 0x01);
+ return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
}
static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
@@ -477,28 +524,32 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
return 0;
switch (ctrl->id) {
- case V4L2_CID_GAIN:
- ret = imx290_set_gain(imx290, ctrl->val);
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_EXPOSURE:
+ ret = imx290_write(imx290, IMX290_SHS1,
+ IMX290_VMAX_DEFAULT - ctrl->val - 1, NULL);
break;
+
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
- imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
- imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00);
+ imx290_write(imx290, IMX290_BLKLEVEL, 0, &ret);
usleep_range(10000, 11000);
- imx290_write_reg(imx290, IMX290_PGCTRL,
- (u8)(IMX290_PGCTRL_REGEN |
- IMX290_PGCTRL_THRU |
- IMX290_PGCTRL_MODE(ctrl->val)));
+ imx290_write(imx290, IMX290_PGCTRL,
+ (u8)(IMX290_PGCTRL_REGEN |
+ IMX290_PGCTRL_THRU |
+ IMX290_PGCTRL_MODE(ctrl->val)), &ret);
} else {
- imx290_write_reg(imx290, IMX290_PGCTRL, 0x00);
+ imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret);
usleep_range(10000, 11000);
if (imx290->bpp == 10)
- imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW,
- 0x3c);
+ imx290_write(imx290, IMX290_BLKLEVEL, 0x3c,
+ &ret);
else /* 12 bits per pixel */
- imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW,
- 0xf0);
- imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00);
+ imx290_write(imx290, IMX290_BLKLEVEL, 0xf0,
+ &ret);
}
break;
default:
@@ -515,6 +566,16 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
.s_ctrl = imx290_set_ctrl,
};
+static struct v4l2_mbus_framefmt *
+imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state,
+ u32 which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return &imx290->current_format;
+ else
+ return v4l2_subdev_get_try_format(&imx290->sd, state, 0);
+}
+
static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -558,12 +619,7 @@ static int imx290_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&imx290->lock);
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- framefmt = v4l2_subdev_get_try_format(&imx290->sd, sd_state,
- fmt->pad);
- else
- framefmt = &imx290->current_format;
-
+ framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which);
fmt->format = *framefmt;
mutex_unlock(&imx290->lock);
@@ -623,10 +679,9 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.code = imx290_formats[i].code;
fmt->format.field = V4L2_FIELD_NONE;
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- format = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
- } else {
- format = &imx290->current_format;
+ format = imx290_get_pad_format(imx290, sd_state, fmt->which);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
imx290->current_mode = mode;
imx290->bpp = imx290_formats[i].bpp;
@@ -636,6 +691,20 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
if (imx290->pixel_rate)
__v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
imx290_calc_pixel_rate(imx290));
+
+ if (imx290->hblank) {
+ unsigned int hblank = mode->hmax - mode->width;
+
+ __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank,
+ 1, hblank);
+ }
+
+ if (imx290->vblank) {
+ unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height;
+
+ __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank,
+ 1, vblank);
+ }
}
*format = fmt->format;
@@ -645,6 +714,52 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
return 0;
}
+static int imx290_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct imx290 *imx290 = to_imx290(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ format = imx290_get_pad_format(imx290, sd_state, sel->which);
+
+ mutex_lock(&imx290->lock);
+
+ sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP
+ + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2;
+ sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT
+ + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2;
+ sel->r.width = format->width;
+ sel->r.height = format->height;
+
+ mutex_unlock(&imx290->lock);
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX290_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX290_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP;
+ sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT;
+ sel->r.width = IMX290_PIXEL_ARRAY_RECORDING_WIDTH;
+ sel->r.height = IMX290_PIXEL_ARRAY_RECORDING_HEIGHT;
+
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state)
{
@@ -690,25 +805,6 @@ static int imx290_write_current_format(struct imx290 *imx290)
return 0;
}
-static int imx290_set_hmax(struct imx290 *imx290, u32 val)
-{
- int ret;
-
- ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff));
- if (ret) {
- dev_err(imx290->dev, "Error setting HMAX register\n");
- return ret;
- }
-
- ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff));
- if (ret) {
- dev_err(imx290->dev, "Error setting HMAX register\n");
- return ret;
- }
-
- return 0;
-}
-
/* Start streaming */
static int imx290_start_streaming(struct imx290 *imx290)
{
@@ -737,8 +833,10 @@ static int imx290_start_streaming(struct imx290 *imx290)
dev_err(imx290->dev, "Could not set current mode\n");
return ret;
}
- ret = imx290_set_hmax(imx290, imx290->current_mode->hmax);
- if (ret < 0)
+
+ ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
+ NULL);
+ if (ret)
return ret;
/* Apply customized values from user */
@@ -748,14 +846,12 @@ static int imx290_start_streaming(struct imx290 *imx290)
return ret;
}
- ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x00);
- if (ret < 0)
- return ret;
+ imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
msleep(30);
/* Start streaming */
- return imx290_write_reg(imx290, IMX290_XMSTA, 0x00);
+ return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
}
static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
@@ -788,10 +884,10 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
{
unsigned int i;
- for (i = 0; i < IMX290_NUM_SUPPLIES; i++)
+ for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
imx290->supplies[i].supply = imx290_supply_name[i];
- return devm_regulator_bulk_get(dev, IMX290_NUM_SUPPLIES,
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
imx290->supplies);
}
@@ -814,27 +910,13 @@ static int imx290_set_data_lanes(struct imx290 *imx290)
* validated in probe itself
*/
dev_err(imx290->dev, "Lane configuration not supported\n");
- ret = -EINVAL;
- goto exit;
- }
-
- ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval);
- if (ret) {
- dev_err(imx290->dev, "Error setting Physical Lane number register\n");
- goto exit;
- }
-
- ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval);
- if (ret) {
- dev_err(imx290->dev, "Error setting CSI Lane mode register\n");
- goto exit;
+ return -EINVAL;
}
- ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel);
- if (ret)
- dev_err(imx290->dev, "Error setting FR/FDG SEL register\n");
+ imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret);
+ imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret);
+ imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
-exit:
return ret;
}
@@ -850,7 +932,8 @@ static int imx290_power_on(struct device *dev)
return ret;
}
- ret = regulator_bulk_enable(IMX290_NUM_SUPPLIES, imx290->supplies);
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies),
+ imx290->supplies);
if (ret) {
dev_err(dev, "Failed to enable regulators\n");
clk_disable_unprepare(imx290->xclk);
@@ -874,7 +957,7 @@ static int imx290_power_off(struct device *dev)
clk_disable_unprepare(imx290->xclk);
gpiod_set_value_cansleep(imx290->rst_gpio, 1);
- regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies);
+ regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies);
return 0;
}
@@ -893,6 +976,7 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
.enum_frame_size = imx290_enum_frame_size,
.get_fmt = imx290_get_fmt,
.set_fmt = imx290_set_fmt,
+ .get_selection = imx290_get_selection,
};
static const struct v4l2_subdev_ops imx290_subdev_ops = {
@@ -904,6 +988,85 @@ static const struct media_entity_operations imx290_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
+static int imx290_ctrl_init(struct imx290 *imx290)
+{
+ struct v4l2_fwnode_device_properties props;
+ unsigned int blank;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(imx290->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&imx290->ctrls, 9);
+ imx290->ctrls.lock = &imx290->lock;
+
+ /*
+ * The sensor has an analog gain and a digital gain, both controlled
+ * through a single gain value, expressed in 0.3dB increments. Values
+ * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
+ * up to 72.0dB (240) add further digital gain. Limit the range to
+ * analog gain only, support for digital gain can be added separately
+ * if needed.
+ *
+ * The IMX327 and IMX462 are largely compatible with the IMX290, but
+ * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
+ * gain. When support for those sensors gets added to the driver, the
+ * gain control should be adjusted accordingly.
+ */
+ v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
+
+ v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
+ IMX290_VMAX_DEFAULT - 2);
+
+ imx290->link_freq =
+ v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ imx290_link_freqs_num(imx290) - 1, 0,
+ imx290_link_freqs_ptr(imx290));
+ if (imx290->link_freq)
+ imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ 1, INT_MAX, 1,
+ imx290_calc_pixel_rate(imx290));
+
+ v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx290_test_pattern_menu) - 1,
+ 0, 0, imx290_test_pattern_menu);
+
+ blank = imx290->current_mode->hmax - imx290->current_mode->width;
+ imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_HBLANK, blank, blank, 1,
+ blank);
+ if (imx290->hblank)
+ imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height;
+ imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_VBLANK, blank, blank, 1,
+ blank);
+ if (imx290->vblank)
+ imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
+ &props);
+
+ imx290->sd.ctrl_handler = &imx290->ctrls;
+
+ if (imx290->ctrls.error) {
+ ret = imx290->ctrls.error;
+ v4l2_ctrl_handler_free(&imx290->ctrls);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* Returns 0 if all link frequencies used by the driver for the given number
* of MIPI data lanes are mentioned in the device tree, or the value of the
@@ -1042,36 +1205,10 @@ static int imx290_probe(struct i2c_client *client)
*/
imx290_entity_init_cfg(&imx290->sd, NULL);
- v4l2_ctrl_handler_init(&imx290->ctrls, 4);
-
- v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_GAIN, 0, 72, 1, 0);
-
- imx290->link_freq =
- v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_LINK_FREQ,
- imx290_link_freqs_num(imx290) - 1, 0,
- imx290_link_freqs_ptr(imx290));
- if (imx290->link_freq)
- imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_PIXEL_RATE,
- 1, INT_MAX, 1,
- imx290_calc_pixel_rate(imx290));
-
- v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(imx290_test_pattern_menu) - 1,
- 0, 0, imx290_test_pattern_menu);
-
- imx290->sd.ctrl_handler = &imx290->ctrls;
-
- if (imx290->ctrls.error) {
- dev_err(dev, "Control initialization error %d\n",
- imx290->ctrls.error);
- ret = imx290->ctrls.error;
- goto free_ctrl;
+ ret = imx290_ctrl_init(imx290);
+ if (ret < 0) {
+ dev_err(dev, "Control initialization error %d\n", ret);
+ goto free_mutex;
}
v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
@@ -1112,6 +1249,7 @@ free_entity:
media_entity_cleanup(&imx290->sd.entity);
free_ctrl:
v4l2_ctrl_handler_free(&imx290->ctrls);
+free_mutex:
mutex_destroy(&imx290->lock);
free_err:
v4l2_fwnode_endpoint_free(&ep);
diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c
index 245a18fb40ad..45b1b61b2880 100644
--- a/drivers/media/i2c/imx319.c
+++ b/drivers/media/i2c/imx319.c
@@ -2328,8 +2328,12 @@ static int imx319_init_controls(struct imx319 *imx319)
imx319->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx319->hflip)
+ imx319->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
imx319->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx319->vflip)
+ imx319->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
IMX319_ANA_GAIN_MIN, IMX319_ANA_GAIN_MAX,
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index b46178681c05..25d4dbb6041e 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1617,8 +1617,12 @@ static int imx355_init_controls(struct imx355 *imx355)
imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx355->hflip)
+ imx355->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx355->vflip)
+ imx355->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX,
diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c
index 7f6d29e0e7c4..e1e986dc8856 100644
--- a/drivers/media/i2c/imx412.c
+++ b/drivers/media/i2c/imx412.c
@@ -1172,6 +1172,7 @@ static int imx412_init_controls(struct imx412 *imx412)
static int imx412_probe(struct i2c_client *client)
{
struct imx412 *imx412;
+ const char *name;
int ret;
imx412 = devm_kzalloc(&client->dev, sizeof(*imx412), GFP_KERNEL);
@@ -1179,6 +1180,9 @@ static int imx412_probe(struct i2c_client *client)
return -ENOMEM;
imx412->dev = &client->dev;
+ name = device_get_match_data(&client->dev);
+ if (!name)
+ return -ENODEV;
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops);
@@ -1218,6 +1222,8 @@ static int imx412_probe(struct i2c_client *client)
imx412->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx412->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ v4l2_i2c_subdev_set_name(&imx412->sd, client, name, NULL);
+
/* Initialize source pad */
imx412->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&imx412->sd.entity, 1, &imx412->pad);
@@ -1279,7 +1285,8 @@ static const struct dev_pm_ops imx412_pm_ops = {
};
static const struct of_device_id imx412_of_match[] = {
- { .compatible = "sony,imx412" },
+ { .compatible = "sony,imx412", .data = "imx412" },
+ { .compatible = "sony,imx577", .data = "imx577" },
{ }
};
diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c
index 20f548a8a054..ae7af2cc94f5 100644
--- a/drivers/media/i2c/isl7998x.c
+++ b/drivers/media/i2c/isl7998x.c
@@ -665,7 +665,7 @@ static int isl7998x_set_standard(struct isl7998x *isl7998x, v4l2_std_id norm)
static int isl7998x_init(struct isl7998x *isl7998x)
{
const unsigned int lanes = isl7998x->nr_mipi_lanes;
- const u32 isl7998x_video_in_chan_map[] = { 0x00, 0x11, 0x02, 0x02 };
+ static const u32 isl7998x_video_in_chan_map[] = { 0x00, 0x11, 0x02, 0x02 };
const struct reg_sequence isl7998x_init_seq_custom[] = {
{ ISL7998X_REG_P0_VIDEO_IN_CHAN_CTL,
isl7998x_video_in_chan_map[isl7998x->nr_inputs - 1] },
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
index 215d9a43b0b9..0d86f2db7ad2 100644
--- a/drivers/media/i2c/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
@@ -650,7 +650,7 @@ static const struct v4l2_subdev_ops ks0127_ops = {
/* ----------------------------------------------------------------------- */
-static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ks0127_probe(struct i2c_client *client)
{
struct ks0127 *ks;
struct v4l2_subdev *sd;
@@ -696,7 +696,7 @@ static struct i2c_driver ks0127_driver = {
.driver = {
.name = "ks0127",
},
- .probe = ks0127_probe,
+ .probe_new = ks0127_probe,
.remove = ks0127_remove,
.id_table = ks0127_id,
};
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index edad3138cb07..5ef613604be7 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -391,8 +391,7 @@ static int lm3560_init_device(struct lm3560_flash *flash)
return rval;
}
-static int lm3560_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int lm3560_probe(struct i2c_client *client)
{
struct lm3560_flash *flash;
struct lm3560_platform_data *pdata = dev_get_platdata(&client->dev);
@@ -468,7 +467,7 @@ static struct i2c_driver lm3560_i2c_driver = {
.name = LM3560_NAME,
.pm = NULL,
},
- .probe = lm3560_probe,
+ .probe_new = lm3560_probe,
.remove = lm3560_remove,
.id_table = lm3560_id_table,
};
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
index 0aaa963917d8..2a0cf74d2bed 100644
--- a/drivers/media/i2c/lm3646.c
+++ b/drivers/media/i2c/lm3646.c
@@ -334,8 +334,7 @@ static int lm3646_init_device(struct lm3646_flash *flash)
return regmap_read(flash->regmap, REG_FLAG, &reg_val);
}
-static int lm3646_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int lm3646_probe(struct i2c_client *client)
{
struct lm3646_flash *flash;
struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev);
@@ -397,7 +396,7 @@ static struct i2c_driver lm3646_i2c_driver = {
.driver = {
.name = LM3646_NAME,
},
- .probe = lm3646_probe,
+ .probe_new = lm3646_probe,
.remove = lm3646_remove,
.id_table = lm3646_id_table,
};
diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c
index 2ab91b993c33..0e6507ab7e08 100644
--- a/drivers/media/i2c/m52790.c
+++ b/drivers/media/i2c/m52790.c
@@ -129,8 +129,7 @@ static const struct v4l2_subdev_ops m52790_ops = {
/* i2c implementation */
-static int m52790_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m52790_probe(struct i2c_client *client)
{
struct m52790_state *state;
struct v4l2_subdev *sd;
@@ -173,7 +172,7 @@ static struct i2c_driver m52790_driver = {
.driver = {
.name = "m52790",
},
- .probe = m52790_probe,
+ .probe_new = m52790_probe,
.remove = m52790_remove,
.id_table = m52790_id,
};
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 2201d2a26353..2b01873ba0db 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -939,8 +939,7 @@ static irqreturn_t m5mols_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int m5mols_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m5mols_probe(struct i2c_client *client)
{
const struct m5mols_platform_data *pdata = client->dev.platform_data;
struct m5mols_info *info;
@@ -1039,7 +1038,7 @@ static struct i2c_driver m5mols_i2c_driver = {
.driver = {
.name = MODULE_NAME,
},
- .probe = m5mols_probe,
+ .probe_new = m5mols_probe,
.remove = m5mols_remove,
.id_table = m5mols_id,
};
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index 49ec59b0ca43..dbd2f0bd3651 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -359,8 +359,7 @@ static int ml86v7667_init(struct ml86v7667_priv *priv)
return ret;
}
-static int ml86v7667_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int ml86v7667_probe(struct i2c_client *client)
{
struct ml86v7667_priv *priv;
int ret;
@@ -434,7 +433,7 @@ static struct i2c_driver ml86v7667_i2c_driver = {
.driver = {
.name = DRV_NAME,
},
- .probe = ml86v7667_probe,
+ .probe_new = ml86v7667_probe,
.remove = ml86v7667_remove,
.id_table = ml86v7667_id,
};
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 76b8c9c08c82..958cfdd73d57 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -701,8 +701,7 @@ static const struct v4l2_subdev_ops mt9m032_ops = {
* Driver initialization and probing
*/
-static int mt9m032_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int mt9m032_probe(struct i2c_client *client)
{
struct mt9m032_platform_data *pdata = client->dev.platform_data;
struct i2c_adapter *adapter = client->adapter;
@@ -880,7 +879,7 @@ static struct i2c_driver mt9m032_i2c_driver = {
.driver = {
.name = MT9M032_NAME,
},
- .probe = mt9m032_probe,
+ .probe_new = mt9m032_probe,
.remove = mt9m032_remove,
.id_table = mt9m032_id_table,
};
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 45f7b5e52bc3..4ffc2f6e7db4 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -307,6 +307,7 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
static int mt9p031_power_on(struct mt9p031 *mt9p031)
{
+ unsigned long rate, delay;
int ret;
/* Ensure RESET_BAR is active */
@@ -334,7 +335,12 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
/* Now RESET_BAR must be high */
if (mt9p031->reset) {
gpiod_set_value(mt9p031->reset, 0);
- usleep_range(1000, 2000);
+ /* Wait 850000 EXTCLK cycles before de-asserting reset. */
+ rate = clk_get_rate(mt9p031->clk);
+ if (!rate)
+ rate = 6000000; /* Slowest supported clock, 6 MHz */
+ delay = DIV_ROUND_UP(850000 * 1000, rate);
+ msleep(delay);
}
return 0;
@@ -702,7 +708,6 @@ static int mt9p031_init_cfg(struct v4l2_subdev *subdev,
V4L2_SUBDEV_FORMAT_TRY;
crop = __mt9p031_get_pad_crop(mt9p031, sd_state, 0, which);
- v4l2_subdev_get_try_crop(subdev, sd_state, 0);
crop->left = MT9P031_COLUMN_START_DEF;
crop->top = MT9P031_ROW_START_DEF;
crop->width = MT9P031_WINDOW_WIDTH_DEF;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index d5abe4a7ef07..c635ed11388a 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -856,8 +856,7 @@ static const struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
.close = mt9t001_close,
};
-static int mt9t001_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int mt9t001_probe(struct i2c_client *client)
{
struct mt9t001_platform_data *pdata = client->dev.platform_data;
struct mt9t001 *mt9t001;
@@ -981,7 +980,7 @@ static struct i2c_driver mt9t001_driver = {
.driver = {
.name = "mt9t001",
},
- .probe = mt9t001_probe,
+ .probe_new = mt9t001_probe,
.remove = mt9t001_remove,
.id_table = mt9t001_id,
};
diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c
index ad564095d0cf..a82f056787b8 100644
--- a/drivers/media/i2c/mt9t112.c
+++ b/drivers/media/i2c/mt9t112.c
@@ -1060,8 +1060,7 @@ done:
return ret;
}
-static int mt9t112_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int mt9t112_probe(struct i2c_client *client)
{
struct mt9t112_priv *priv;
int ret;
@@ -1120,7 +1119,7 @@ static struct i2c_driver mt9t112_i2c_driver = {
.driver = {
.name = "mt9t112",
},
- .probe = mt9t112_probe,
+ .probe_new = mt9t112_probe,
.remove = mt9t112_remove,
.id_table = mt9t112_id,
};
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 9952ce06ebb2..c54c7fbf0963 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -478,8 +478,7 @@ static const struct v4l2_subdev_ops mt9v011_ops = {
I2C Client & Driver
****************************************************************************/
-static int mt9v011_probe(struct i2c_client *c,
- const struct i2c_device_id *id)
+static int mt9v011_probe(struct i2c_client *c)
{
u16 version;
struct mt9v011 *core;
@@ -586,7 +585,7 @@ static struct i2c_driver mt9v011_driver = {
.driver = {
.name = "mt9v011",
},
- .probe = mt9v011_probe,
+ .probe_new = mt9v011_probe,
.remove = mt9v011_remove,
.id_table = mt9v011_id,
};
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index ecaf5e9057f1..144bef2835f7 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -702,8 +702,7 @@ static int noon010_detect(struct i2c_client *client, struct noon010_info *info)
return ret == NOON010PC30_ID ? 0 : -ENODEV;
}
-static int noon010_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int noon010_probe(struct i2c_client *client)
{
struct noon010_info *info;
struct v4l2_subdev *sd;
@@ -810,7 +809,7 @@ static struct i2c_driver noon010_i2c_driver = {
.driver = {
.name = MODULE_NAME
},
- .probe = noon010_probe,
+ .probe_new = noon010_probe,
.remove = noon010_remove,
.id_table = noon010_id,
};
diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c
index c1703596c3dc..a39e086a51c5 100644
--- a/drivers/media/i2c/ov08d10.c
+++ b/drivers/media/i2c/ov08d10.c
@@ -990,8 +990,13 @@ static int ov08d10_init_controls(struct ov08d10 *ov08d10)
ov08d10->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov08d10_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (ov08d10->hflip)
+ ov08d10->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
ov08d10->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov08d10_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (ov08d10->vflip)
+ ov08d10->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
if (ctrl_hdlr->error)
return ctrl_hdlr->error;
diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c
new file mode 100644
index 000000000000..72ae7fba94eb
--- /dev/null
+++ b/drivers/media/i2c/ov08x40.c
@@ -0,0 +1,3325 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022 Intel Corporation.
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define OV08X40_REG_VALUE_08BIT 1
+#define OV08X40_REG_VALUE_16BIT 2
+#define OV08X40_REG_VALUE_24BIT 3
+
+#define OV08X40_REG_MODE_SELECT 0x0100
+#define OV08X40_MODE_STANDBY 0x00
+#define OV08X40_MODE_STREAMING 0x01
+
+#define OV08X40_REG_AO_STANDBY 0x1000
+#define OV08X40_AO_STREAMING 0x04
+
+#define OV08X40_REG_MS_SELECT 0x1001
+#define OV08X40_MS_STANDBY 0x00
+#define OV08X40_MS_STREAMING 0x04
+
+#define OV08X40_REG_SOFTWARE_RST 0x0103
+#define OV08X40_SOFTWARE_RST 0x01
+
+/* Chip ID */
+#define OV08X40_REG_CHIP_ID 0x300a
+#define OV08X40_CHIP_ID 0x560858
+
+/* V_TIMING internal */
+#define OV08X40_REG_VTS 0x380e
+#define OV08X40_VTS_30FPS 0x1388
+#define OV08X40_VTS_BIN_30FPS 0x115c
+#define OV08X40_VTS_MAX 0x7fff
+
+/* H TIMING internal */
+#define OV08X40_REG_HTS 0x380c
+#define OV08X40_HTS_30FPS 0x0280
+
+/* Exposure control */
+#define OV08X40_REG_EXPOSURE 0x3500
+#define OV08X40_EXPOSURE_MAX_MARGIN 31
+#define OV08X40_EXPOSURE_MIN 1
+#define OV08X40_EXPOSURE_STEP 1
+#define OV08X40_EXPOSURE_DEFAULT 0x40
+
+/* Short Exposure control */
+#define OV08X40_REG_SHORT_EXPOSURE 0x3540
+
+/* Analog gain control */
+#define OV08X40_REG_ANALOG_GAIN 0x3508
+#define OV08X40_ANA_GAIN_MIN 0x80
+#define OV08X40_ANA_GAIN_MAX 0x07c0
+#define OV08X40_ANA_GAIN_STEP 1
+#define OV08X40_ANA_GAIN_DEFAULT 0x80
+
+/* Digital gain control */
+#define OV08X40_REG_DGTL_GAIN_H 0x350a
+#define OV08X40_REG_DGTL_GAIN_M 0x350b
+#define OV08X40_REG_DGTL_GAIN_L 0x350c
+
+#define OV08X40_DGTL_GAIN_MIN 1024 /* Min = 1 X */
+#define OV08X40_DGTL_GAIN_MAX (4096 - 1) /* Max = 4 X */
+#define OV08X40_DGTL_GAIN_DEFAULT 2560 /* Default gain = 2.5 X */
+#define OV08X40_DGTL_GAIN_STEP 1 /* Each step = 1/1024 */
+
+#define OV08X40_DGTL_GAIN_L_SHIFT 6
+#define OV08X40_DGTL_GAIN_L_MASK 0x3
+#define OV08X40_DGTL_GAIN_M_SHIFT 2
+#define OV08X40_DGTL_GAIN_M_MASK 0xff
+#define OV08X40_DGTL_GAIN_H_SHIFT 10
+#define OV08X40_DGTL_GAIN_H_MASK 0x1F
+
+/* Test Pattern Control */
+#define OV08X40_REG_TEST_PATTERN 0x50C1
+#define OV08X40_REG_ISP 0x5000
+#define OV08X40_REG_SHORT_TEST_PATTERN 0x53C1
+#define OV08X40_TEST_PATTERN_ENABLE BIT(0)
+#define OV08X40_TEST_PATTERN_MASK 0xcf
+#define OV08X40_TEST_PATTERN_BAR_SHIFT 4
+
+/* Flip Control */
+#define OV08X40_REG_VFLIP 0x3820
+#define OV08X40_REG_MIRROR 0x3821
+
+/* Horizontal Window Offset */
+#define OV08X40_REG_H_WIN_OFFSET 0x3811
+
+/* Vertical Window Offset */
+#define OV08X40_REG_V_WIN_OFFSET 0x3813
+
+enum {
+ OV08X40_LINK_FREQ_400MHZ_INDEX,
+};
+
+struct ov08x40_reg {
+ u16 address;
+ u8 val;
+};
+
+struct ov08x40_reg_list {
+ u32 num_of_regs;
+ const struct ov08x40_reg *regs;
+};
+
+/* Link frequency config */
+struct ov08x40_link_freq_config {
+ u32 pixels_per_line;
+
+ /* registers for this link frequency */
+ struct ov08x40_reg_list reg_list;
+};
+
+/* Mode : resolution and related config&values */
+struct ov08x40_mode {
+ /* Frame width */
+ u32 width;
+ /* Frame height */
+ u32 height;
+
+ u32 lanes;
+ /* V-timing */
+ u32 vts_def;
+ u32 vts_min;
+
+ /* Index of Link frequency config to be used */
+ u32 link_freq_index;
+ /* Default register values */
+ struct ov08x40_reg_list reg_list;
+};
+
+static const struct ov08x40_reg mipi_data_rate_800mbps[] = {
+ {0x0103, 0x01},
+ {0x1000, 0x00},
+ {0x1601, 0xd0},
+ {0x1001, 0x04},
+ {0x5004, 0x53},
+ {0x5110, 0x00},
+ {0x5111, 0x14},
+ {0x5112, 0x01},
+ {0x5113, 0x7b},
+ {0x5114, 0x00},
+ {0x5152, 0xa3},
+ {0x5a52, 0x1f},
+ {0x5a1a, 0x0e},
+ {0x5a1b, 0x10},
+ {0x5a1f, 0x0e},
+ {0x5a27, 0x0e},
+ {0x6002, 0x2e},
+};
+
+static const struct ov08x40_reg mode_3856x2416_regs[] = {
+ {0x5000, 0x5d},
+ {0x5001, 0x20},
+ {0x5008, 0xb0},
+ {0x50c1, 0x00},
+ {0x53c1, 0x00},
+ {0x5f40, 0x00},
+ {0x5f41, 0x40},
+ {0x0300, 0x3a},
+ {0x0301, 0xc8},
+ {0x0302, 0x31},
+ {0x0303, 0x03},
+ {0x0304, 0x01},
+ {0x0305, 0xa1},
+ {0x0306, 0x04},
+ {0x0307, 0x01},
+ {0x0308, 0x03},
+ {0x0309, 0x03},
+ {0x0310, 0x0a},
+ {0x0311, 0x02},
+ {0x0312, 0x01},
+ {0x0313, 0x08},
+ {0x0314, 0x66},
+ {0x0315, 0x00},
+ {0x0316, 0x34},
+ {0x0320, 0x02},
+ {0x0321, 0x03},
+ {0x0323, 0x05},
+ {0x0324, 0x01},
+ {0x0325, 0xb8},
+ {0x0326, 0x4a},
+ {0x0327, 0x04},
+ {0x0329, 0x00},
+ {0x032a, 0x05},
+ {0x032b, 0x00},
+ {0x032c, 0x00},
+ {0x032d, 0x00},
+ {0x032e, 0x02},
+ {0x032f, 0xa0},
+ {0x0350, 0x00},
+ {0x0360, 0x01},
+ {0x1216, 0x60},
+ {0x1217, 0x5b},
+ {0x1218, 0x00},
+ {0x1220, 0x24},
+ {0x198a, 0x00},
+ {0x198b, 0x01},
+ {0x198e, 0x00},
+ {0x198f, 0x01},
+ {0x3009, 0x04},
+ {0x3012, 0x41},
+ {0x3015, 0x00},
+ {0x3016, 0xb0},
+ {0x3017, 0xf0},
+ {0x3018, 0xf0},
+ {0x3019, 0xd2},
+ {0x301a, 0xb0},
+ {0x301c, 0x81},
+ {0x301d, 0x02},
+ {0x301e, 0x80},
+ {0x3022, 0xf0},
+ {0x3025, 0x89},
+ {0x3030, 0x03},
+ {0x3044, 0xc2},
+ {0x3050, 0x35},
+ {0x3051, 0x60},
+ {0x3052, 0x25},
+ {0x3053, 0x00},
+ {0x3054, 0x00},
+ {0x3055, 0x02},
+ {0x3056, 0x80},
+ {0x3057, 0x80},
+ {0x3058, 0x80},
+ {0x3059, 0x00},
+ {0x3107, 0x86},
+ {0x3400, 0x1c},
+ {0x3401, 0x80},
+ {0x3402, 0x8c},
+ {0x3419, 0x13},
+ {0x341a, 0x89},
+ {0x341b, 0x30},
+ {0x3420, 0x00},
+ {0x3421, 0x00},
+ {0x3422, 0x00},
+ {0x3423, 0x00},
+ {0x3424, 0x00},
+ {0x3425, 0x00},
+ {0x3426, 0x00},
+ {0x3427, 0x00},
+ {0x3428, 0x0f},
+ {0x3429, 0x00},
+ {0x342a, 0x00},
+ {0x342b, 0x00},
+ {0x342c, 0x00},
+ {0x342d, 0x00},
+ {0x342e, 0x00},
+ {0x342f, 0x11},
+ {0x3430, 0x11},
+ {0x3431, 0x10},
+ {0x3432, 0x00},
+ {0x3433, 0x00},
+ {0x3434, 0x00},
+ {0x3435, 0x00},
+ {0x3436, 0x00},
+ {0x3437, 0x00},
+ {0x3442, 0x02},
+ {0x3443, 0x02},
+ {0x3444, 0x07},
+ {0x3450, 0x00},
+ {0x3451, 0x00},
+ {0x3452, 0x18},
+ {0x3453, 0x18},
+ {0x3454, 0x00},
+ {0x3455, 0x80},
+ {0x3456, 0x08},
+ {0x3500, 0x00},
+ {0x3501, 0x02},
+ {0x3502, 0x00},
+ {0x3504, 0x4c},
+ {0x3506, 0x30},
+ {0x3507, 0x00},
+ {0x3508, 0x01},
+ {0x3509, 0x00},
+ {0x350a, 0x01},
+ {0x350b, 0x00},
+ {0x350c, 0x00},
+ {0x3540, 0x00},
+ {0x3541, 0x01},
+ {0x3542, 0x00},
+ {0x3544, 0x4c},
+ {0x3546, 0x30},
+ {0x3547, 0x00},
+ {0x3548, 0x01},
+ {0x3549, 0x00},
+ {0x354a, 0x01},
+ {0x354b, 0x00},
+ {0x354c, 0x00},
+ {0x3688, 0x02},
+ {0x368a, 0x2e},
+ {0x368e, 0x71},
+ {0x3696, 0xd1},
+ {0x3699, 0x00},
+ {0x369a, 0x00},
+ {0x36a4, 0x00},
+ {0x36a6, 0x00},
+ {0x3711, 0x00},
+ {0x3712, 0x51},
+ {0x3713, 0x00},
+ {0x3714, 0x24},
+ {0x3716, 0x00},
+ {0x3718, 0x07},
+ {0x371a, 0x1c},
+ {0x371b, 0x00},
+ {0x3720, 0x08},
+ {0x3725, 0x32},
+ {0x3727, 0x05},
+ {0x3760, 0x02},
+ {0x3761, 0x17},
+ {0x3762, 0x02},
+ {0x3763, 0x02},
+ {0x3764, 0x02},
+ {0x3765, 0x2c},
+ {0x3766, 0x04},
+ {0x3767, 0x2c},
+ {0x3768, 0x02},
+ {0x3769, 0x00},
+ {0x376b, 0x20},
+ {0x376e, 0x03},
+ {0x37b0, 0x00},
+ {0x37b1, 0xab},
+ {0x37b2, 0x01},
+ {0x37b3, 0x82},
+ {0x37b4, 0x00},
+ {0x37b5, 0xe4},
+ {0x37b6, 0x01},
+ {0x37b7, 0xee},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0f},
+ {0x3805, 0x1f},
+ {0x3806, 0x09},
+ {0x3807, 0x7f},
+ {0x3808, 0x0f},
+ {0x3809, 0x10},
+ {0x380a, 0x09},
+ {0x380b, 0x70},
+ {0x380c, 0x02},
+ {0x380d, 0x80},
+ {0x380e, 0x13},
+ {0x380f, 0x88},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x07},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3820, 0x00},
+ {0x3821, 0x04},
+ {0x3822, 0x00},
+ {0x3823, 0x04},
+ {0x3828, 0x0f},
+ {0x382a, 0x80},
+ {0x382e, 0x41},
+ {0x3837, 0x08},
+ {0x383a, 0x81},
+ {0x383b, 0x81},
+ {0x383c, 0x11},
+ {0x383d, 0x11},
+ {0x383e, 0x00},
+ {0x383f, 0x38},
+ {0x3840, 0x00},
+ {0x3847, 0x00},
+ {0x384a, 0x00},
+ {0x384c, 0x02},
+ {0x384d, 0x80},
+ {0x3856, 0x50},
+ {0x3857, 0x30},
+ {0x3858, 0x80},
+ {0x3859, 0x40},
+ {0x3860, 0x00},
+ {0x3888, 0x00},
+ {0x3889, 0x00},
+ {0x388a, 0x00},
+ {0x388b, 0x00},
+ {0x388c, 0x00},
+ {0x388d, 0x00},
+ {0x388e, 0x00},
+ {0x388f, 0x00},
+ {0x3894, 0x00},
+ {0x3895, 0x00},
+ {0x3c84, 0x00},
+ {0x3d85, 0x8b},
+ {0x3daa, 0x80},
+ {0x3dab, 0x14},
+ {0x3dac, 0x80},
+ {0x3dad, 0xc8},
+ {0x3dae, 0x81},
+ {0x3daf, 0x7b},
+ {0x3f00, 0x10},
+ {0x3f01, 0x11},
+ {0x3f06, 0x0d},
+ {0x3f07, 0x0b},
+ {0x3f08, 0x0d},
+ {0x3f09, 0x0b},
+ {0x3f0a, 0x01},
+ {0x3f0b, 0x11},
+ {0x3f0c, 0x33},
+ {0x4001, 0x07},
+ {0x4007, 0x20},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x08},
+ {0x400c, 0x00},
+ {0x400d, 0x08},
+ {0x400e, 0x14},
+ {0x4010, 0xf4},
+ {0x4011, 0x03},
+ {0x4012, 0x55},
+ {0x4015, 0x00},
+ {0x4016, 0x2d},
+ {0x4017, 0x00},
+ {0x4018, 0x0f},
+ {0x401b, 0x08},
+ {0x401c, 0x00},
+ {0x401d, 0x10},
+ {0x401e, 0x02},
+ {0x401f, 0x00},
+ {0x4050, 0x06},
+ {0x4051, 0xff},
+ {0x4052, 0xff},
+ {0x4053, 0xff},
+ {0x4054, 0xff},
+ {0x4055, 0xff},
+ {0x4056, 0xff},
+ {0x4057, 0x7f},
+ {0x4058, 0x00},
+ {0x4059, 0x00},
+ {0x405a, 0x00},
+ {0x405b, 0x00},
+ {0x405c, 0x07},
+ {0x405d, 0xff},
+ {0x405e, 0x07},
+ {0x405f, 0xff},
+ {0x4080, 0x78},
+ {0x4081, 0x78},
+ {0x4082, 0x78},
+ {0x4083, 0x78},
+ {0x4019, 0x00},
+ {0x401a, 0x40},
+ {0x4020, 0x04},
+ {0x4021, 0x00},
+ {0x4022, 0x04},
+ {0x4023, 0x00},
+ {0x4024, 0x04},
+ {0x4025, 0x00},
+ {0x4026, 0x04},
+ {0x4027, 0x00},
+ {0x4030, 0x00},
+ {0x4031, 0x00},
+ {0x4032, 0x00},
+ {0x4033, 0x00},
+ {0x4034, 0x00},
+ {0x4035, 0x00},
+ {0x4036, 0x00},
+ {0x4037, 0x00},
+ {0x4040, 0x00},
+ {0x4041, 0x80},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4060, 0x00},
+ {0x4061, 0x00},
+ {0x4062, 0x00},
+ {0x4063, 0x00},
+ {0x4064, 0x00},
+ {0x4065, 0x00},
+ {0x4066, 0x00},
+ {0x4067, 0x00},
+ {0x4068, 0x00},
+ {0x4069, 0x00},
+ {0x406a, 0x00},
+ {0x406b, 0x00},
+ {0x406c, 0x00},
+ {0x406d, 0x00},
+ {0x406e, 0x00},
+ {0x406f, 0x00},
+ {0x4070, 0x00},
+ {0x4071, 0x00},
+ {0x4072, 0x00},
+ {0x4073, 0x00},
+ {0x4074, 0x00},
+ {0x4075, 0x00},
+ {0x4076, 0x00},
+ {0x4077, 0x00},
+ {0x4078, 0x00},
+ {0x4079, 0x00},
+ {0x407a, 0x00},
+ {0x407b, 0x00},
+ {0x407c, 0x00},
+ {0x407d, 0x00},
+ {0x407e, 0x00},
+ {0x407f, 0x00},
+ {0x40e0, 0x00},
+ {0x40e1, 0x00},
+ {0x40e2, 0x00},
+ {0x40e3, 0x00},
+ {0x40e4, 0x00},
+ {0x40e5, 0x00},
+ {0x40e6, 0x00},
+ {0x40e7, 0x00},
+ {0x40e8, 0x00},
+ {0x40e9, 0x80},
+ {0x40ea, 0x00},
+ {0x40eb, 0x80},
+ {0x40ec, 0x00},
+ {0x40ed, 0x80},
+ {0x40ee, 0x00},
+ {0x40ef, 0x80},
+ {0x40f0, 0x02},
+ {0x40f1, 0x04},
+ {0x4300, 0x00},
+ {0x4301, 0x00},
+ {0x4302, 0x00},
+ {0x4303, 0x00},
+ {0x4304, 0x00},
+ {0x4305, 0x00},
+ {0x4306, 0x00},
+ {0x4307, 0x00},
+ {0x4308, 0x00},
+ {0x4309, 0x00},
+ {0x430a, 0x00},
+ {0x430b, 0xff},
+ {0x430c, 0xff},
+ {0x430d, 0x00},
+ {0x430e, 0x00},
+ {0x4315, 0x00},
+ {0x4316, 0x00},
+ {0x4317, 0x00},
+ {0x4318, 0x00},
+ {0x4319, 0x00},
+ {0x431a, 0x00},
+ {0x431b, 0x00},
+ {0x431c, 0x00},
+ {0x4500, 0x07},
+ {0x4501, 0x00},
+ {0x4502, 0x00},
+ {0x4503, 0x0f},
+ {0x4504, 0x80},
+ {0x4506, 0x01},
+ {0x4509, 0x05},
+ {0x450c, 0x00},
+ {0x450d, 0x20},
+ {0x450e, 0x00},
+ {0x450f, 0x00},
+ {0x4510, 0x00},
+ {0x4523, 0x00},
+ {0x4526, 0x00},
+ {0x4542, 0x00},
+ {0x4543, 0x00},
+ {0x4544, 0x00},
+ {0x4545, 0x00},
+ {0x4546, 0x00},
+ {0x4547, 0x10},
+ {0x4602, 0x00},
+ {0x4603, 0x15},
+ {0x460b, 0x07},
+ {0x4680, 0x11},
+ {0x4686, 0x00},
+ {0x4687, 0x00},
+ {0x4700, 0x00},
+ {0x4800, 0x64},
+ {0x4806, 0x40},
+ {0x480b, 0x10},
+ {0x480c, 0x80},
+ {0x480f, 0x32},
+ {0x4813, 0xe4},
+ {0x4837, 0x14},
+ {0x4850, 0x42},
+ {0x4884, 0x04},
+ {0x4c00, 0xf8},
+ {0x4c01, 0x44},
+ {0x4c03, 0x00},
+ {0x4d00, 0x00},
+ {0x4d01, 0x16},
+ {0x4d04, 0x10},
+ {0x4d05, 0x00},
+ {0x4d06, 0x0c},
+ {0x4d07, 0x00},
+ {0x3d84, 0x04},
+ {0x3680, 0xa4},
+ {0x3682, 0x80},
+ {0x3601, 0x40},
+ {0x3602, 0x90},
+ {0x3608, 0x0a},
+ {0x3938, 0x09},
+ {0x3a74, 0x84},
+ {0x3a99, 0x84},
+ {0x3ab9, 0xa6},
+ {0x3aba, 0xba},
+ {0x3b12, 0x84},
+ {0x3b14, 0xbb},
+ {0x3b15, 0xbf},
+ {0x3a29, 0x26},
+ {0x3a1f, 0x8a},
+ {0x3a22, 0x91},
+ {0x3a25, 0x96},
+ {0x3a28, 0xb4},
+ {0x3a2b, 0xba},
+ {0x3a2e, 0xbf},
+ {0x3a31, 0xc1},
+ {0x3a20, 0x00},
+ {0x3939, 0x9d},
+ {0x3902, 0x0e},
+ {0x3903, 0x0e},
+ {0x3904, 0x0e},
+ {0x3905, 0x0e},
+ {0x3906, 0x07},
+ {0x3907, 0x0d},
+ {0x3908, 0x11},
+ {0x3909, 0x12},
+ {0x360f, 0x99},
+ {0x390c, 0x33},
+ {0x390d, 0x66},
+ {0x390e, 0xaa},
+ {0x3911, 0x90},
+ {0x3913, 0x90},
+ {0x3915, 0x90},
+ {0x3917, 0x90},
+ {0x3b3f, 0x9d},
+ {0x3b45, 0x9d},
+ {0x3b1b, 0xc9},
+ {0x3b21, 0xc9},
+ {0x3440, 0xa4},
+ {0x3a23, 0x15},
+ {0x3a26, 0x1d},
+ {0x3a2c, 0x4a},
+ {0x3a2f, 0x18},
+ {0x3a32, 0x55},
+ {0x3b0a, 0x01},
+ {0x3b0b, 0x00},
+ {0x3b0e, 0x01},
+ {0x3b0f, 0x00},
+ {0x392c, 0x02},
+ {0x392d, 0x02},
+ {0x392e, 0x04},
+ {0x392f, 0x03},
+ {0x3930, 0x08},
+ {0x3931, 0x07},
+ {0x3932, 0x10},
+ {0x3933, 0x0c},
+ {0x3609, 0x08},
+ {0x3921, 0x0f},
+ {0x3928, 0x15},
+ {0x3929, 0x2a},
+ {0x392a, 0x54},
+ {0x392b, 0xa8},
+ {0x3426, 0x10},
+ {0x3407, 0x01},
+ {0x3404, 0x01},
+ {0x3500, 0x00},
+ {0x3501, 0x10},
+ {0x3502, 0x10},
+ {0x3508, 0x0f},
+ {0x3509, 0x80},
+ {0x5a80, 0x75},
+ {0x5a81, 0x75},
+ {0x5a82, 0x75},
+ {0x5a83, 0x75},
+ {0x5a84, 0x75},
+ {0x5a85, 0x75},
+ {0x5a86, 0x75},
+ {0x5a87, 0x75},
+ {0x5a88, 0x75},
+ {0x5a89, 0x75},
+ {0x5a8a, 0x75},
+ {0x5a8b, 0x75},
+ {0x5a8c, 0x75},
+ {0x5a8d, 0x75},
+ {0x5a8e, 0x75},
+ {0x5a8f, 0x75},
+ {0x5a90, 0x75},
+ {0x5a91, 0x75},
+ {0x5a92, 0x75},
+ {0x5a93, 0x75},
+ {0x5a94, 0x75},
+ {0x5a95, 0x75},
+ {0x5a96, 0x75},
+ {0x5a97, 0x75},
+ {0x5a98, 0x75},
+ {0x5a99, 0x75},
+ {0x5a9a, 0x75},
+ {0x5a9b, 0x75},
+ {0x5a9c, 0x75},
+ {0x5a9d, 0x75},
+ {0x5a9e, 0x75},
+ {0x5a9f, 0x75},
+ {0x5aa0, 0x75},
+ {0x5aa1, 0x75},
+ {0x5aa2, 0x75},
+ {0x5aa3, 0x75},
+ {0x5aa4, 0x75},
+ {0x5aa5, 0x75},
+ {0x5aa6, 0x75},
+ {0x5aa7, 0x75},
+ {0x5aa8, 0x75},
+ {0x5aa9, 0x75},
+ {0x5aaa, 0x75},
+ {0x5aab, 0x75},
+ {0x5aac, 0x75},
+ {0x5aad, 0x75},
+ {0x5aae, 0x75},
+ {0x5aaf, 0x75},
+ {0x5ab0, 0x75},
+ {0x5ab1, 0x75},
+ {0x5ab2, 0x75},
+ {0x5ab3, 0x75},
+ {0x5ab4, 0x75},
+ {0x5ab5, 0x75},
+ {0x5ab6, 0x75},
+ {0x5ab7, 0x75},
+ {0x5ab8, 0x75},
+ {0x5ab9, 0x75},
+ {0x5aba, 0x75},
+ {0x5abb, 0x75},
+ {0x5abc, 0x75},
+ {0x5abd, 0x75},
+ {0x5abe, 0x75},
+ {0x5abf, 0x75},
+ {0x5ac0, 0x75},
+ {0x5ac1, 0x75},
+ {0x5ac2, 0x75},
+ {0x5ac3, 0x75},
+ {0x5ac4, 0x75},
+ {0x5ac5, 0x75},
+ {0x5ac6, 0x75},
+ {0x5ac7, 0x75},
+ {0x5ac8, 0x75},
+ {0x5ac9, 0x75},
+ {0x5aca, 0x75},
+ {0x5acb, 0x75},
+ {0x5acc, 0x75},
+ {0x5acd, 0x75},
+ {0x5ace, 0x75},
+ {0x5acf, 0x75},
+ {0x5ad0, 0x75},
+ {0x5ad1, 0x75},
+ {0x5ad2, 0x75},
+ {0x5ad3, 0x75},
+ {0x5ad4, 0x75},
+ {0x5ad5, 0x75},
+ {0x5ad6, 0x75},
+ {0x5ad7, 0x75},
+ {0x5ad8, 0x75},
+ {0x5ad9, 0x75},
+ {0x5ada, 0x75},
+ {0x5adb, 0x75},
+ {0x5adc, 0x75},
+ {0x5add, 0x75},
+ {0x5ade, 0x75},
+ {0x5adf, 0x75},
+ {0x5ae0, 0x75},
+ {0x5ae1, 0x75},
+ {0x5ae2, 0x75},
+ {0x5ae3, 0x75},
+ {0x5ae4, 0x75},
+ {0x5ae5, 0x75},
+ {0x5ae6, 0x75},
+ {0x5ae7, 0x75},
+ {0x5ae8, 0x75},
+ {0x5ae9, 0x75},
+ {0x5aea, 0x75},
+ {0x5aeb, 0x75},
+ {0x5aec, 0x75},
+ {0x5aed, 0x75},
+ {0x5aee, 0x75},
+ {0x5aef, 0x75},
+ {0x5af0, 0x75},
+ {0x5af1, 0x75},
+ {0x5af2, 0x75},
+ {0x5af3, 0x75},
+ {0x5af4, 0x75},
+ {0x5af5, 0x75},
+ {0x5af6, 0x75},
+ {0x5af7, 0x75},
+ {0x5af8, 0x75},
+ {0x5af9, 0x75},
+ {0x5afa, 0x75},
+ {0x5afb, 0x75},
+ {0x5afc, 0x75},
+ {0x5afd, 0x75},
+ {0x5afe, 0x75},
+ {0x5aff, 0x75},
+ {0x5b00, 0x75},
+ {0x5b01, 0x75},
+ {0x5b02, 0x75},
+ {0x5b03, 0x75},
+ {0x5b04, 0x75},
+ {0x5b05, 0x75},
+ {0x5b06, 0x75},
+ {0x5b07, 0x75},
+ {0x5b08, 0x75},
+ {0x5b09, 0x75},
+ {0x5b0a, 0x75},
+ {0x5b0b, 0x75},
+ {0x5b0c, 0x75},
+ {0x5b0d, 0x75},
+ {0x5b0e, 0x75},
+ {0x5b0f, 0x75},
+ {0x5b10, 0x75},
+ {0x5b11, 0x75},
+ {0x5b12, 0x75},
+ {0x5b13, 0x75},
+ {0x5b14, 0x75},
+ {0x5b15, 0x75},
+ {0x5b16, 0x75},
+ {0x5b17, 0x75},
+ {0x5b18, 0x75},
+ {0x5b19, 0x75},
+ {0x5b1a, 0x75},
+ {0x5b1b, 0x75},
+ {0x5b1c, 0x75},
+ {0x5b1d, 0x75},
+ {0x5b1e, 0x75},
+ {0x5b1f, 0x75},
+ {0x5b20, 0x75},
+ {0x5b21, 0x75},
+ {0x5b22, 0x75},
+ {0x5b23, 0x75},
+ {0x5b24, 0x75},
+ {0x5b25, 0x75},
+ {0x5b26, 0x75},
+ {0x5b27, 0x75},
+ {0x5b28, 0x75},
+ {0x5b29, 0x75},
+ {0x5b2a, 0x75},
+ {0x5b2b, 0x75},
+ {0x5b2c, 0x75},
+ {0x5b2d, 0x75},
+ {0x5b2e, 0x75},
+ {0x5b2f, 0x75},
+ {0x5b30, 0x75},
+ {0x5b31, 0x75},
+ {0x5b32, 0x75},
+ {0x5b33, 0x75},
+ {0x5b34, 0x75},
+ {0x5b35, 0x75},
+ {0x5b36, 0x75},
+ {0x5b37, 0x75},
+ {0x5b38, 0x75},
+ {0x5b39, 0x75},
+ {0x5b3a, 0x75},
+ {0x5b3b, 0x75},
+ {0x5b3c, 0x75},
+ {0x5b3d, 0x75},
+ {0x5b3e, 0x75},
+ {0x5b3f, 0x75},
+ {0x5b40, 0x75},
+ {0x5b41, 0x75},
+ {0x5b42, 0x75},
+ {0x5b43, 0x75},
+ {0x5b44, 0x75},
+ {0x5b45, 0x75},
+ {0x5b46, 0x75},
+ {0x5b47, 0x75},
+ {0x5b48, 0x75},
+ {0x5b49, 0x75},
+ {0x5b4a, 0x75},
+ {0x5b4b, 0x75},
+ {0x5b4c, 0x75},
+ {0x5b4d, 0x75},
+ {0x5b4e, 0x75},
+ {0x5b4f, 0x75},
+ {0x5b50, 0x75},
+ {0x5b51, 0x75},
+ {0x5b52, 0x75},
+ {0x5b53, 0x75},
+ {0x5b54, 0x75},
+ {0x5b55, 0x75},
+ {0x5b56, 0x75},
+ {0x5b57, 0x75},
+ {0x5b58, 0x75},
+ {0x5b59, 0x75},
+ {0x5b5a, 0x75},
+ {0x5b5b, 0x75},
+ {0x5b5c, 0x75},
+ {0x5b5d, 0x75},
+ {0x5b5e, 0x75},
+ {0x5b5f, 0x75},
+ {0x5b60, 0x75},
+ {0x5b61, 0x75},
+ {0x5b62, 0x75},
+ {0x5b63, 0x75},
+ {0x5b64, 0x75},
+ {0x5b65, 0x75},
+ {0x5b66, 0x75},
+ {0x5b67, 0x75},
+ {0x5b68, 0x75},
+ {0x5b69, 0x75},
+ {0x5b6a, 0x75},
+ {0x5b6b, 0x75},
+ {0x5b6c, 0x75},
+ {0x5b6d, 0x75},
+ {0x5b6e, 0x75},
+ {0x5b6f, 0x75},
+ {0x5b70, 0x75},
+ {0x5b71, 0x75},
+ {0x5b72, 0x75},
+ {0x5b73, 0x75},
+ {0x5b74, 0x75},
+ {0x5b75, 0x75},
+ {0x5b76, 0x75},
+ {0x5b77, 0x75},
+ {0x5b78, 0x75},
+ {0x5b79, 0x75},
+ {0x5b7a, 0x75},
+ {0x5b7b, 0x75},
+ {0x5b7c, 0x75},
+ {0x5b7d, 0x75},
+ {0x5b7e, 0x75},
+ {0x5b7f, 0x75},
+ {0x5b80, 0x75},
+ {0x5b81, 0x75},
+ {0x5b82, 0x75},
+ {0x5b83, 0x75},
+ {0x5b84, 0x75},
+ {0x5b85, 0x75},
+ {0x5b86, 0x75},
+ {0x5b87, 0x75},
+ {0x5b88, 0x75},
+ {0x5b89, 0x75},
+ {0x5b8a, 0x75},
+ {0x5b8b, 0x75},
+ {0x5b8c, 0x75},
+ {0x5b8d, 0x75},
+ {0x5b8e, 0x75},
+ {0x5b8f, 0x75},
+ {0x5b90, 0x75},
+ {0x5b91, 0x75},
+ {0x5b92, 0x75},
+ {0x5b93, 0x75},
+ {0x5b94, 0x75},
+ {0x5b95, 0x75},
+ {0x5b96, 0x75},
+ {0x5b97, 0x75},
+ {0x5b98, 0x75},
+ {0x5b99, 0x75},
+ {0x5b9a, 0x75},
+ {0x5b9b, 0x75},
+ {0x5b9c, 0x75},
+ {0x5b9d, 0x75},
+ {0x5b9e, 0x75},
+ {0x5b9f, 0x75},
+ {0x5bc0, 0x75},
+ {0x5bc1, 0x75},
+ {0x5bc2, 0x75},
+ {0x5bc3, 0x75},
+ {0x5bc4, 0x75},
+ {0x5bc5, 0x75},
+ {0x5bc6, 0x75},
+ {0x5bc7, 0x75},
+ {0x5bc8, 0x75},
+ {0x5bc9, 0x75},
+ {0x5bca, 0x75},
+ {0x5bcb, 0x75},
+ {0x5bcc, 0x75},
+ {0x5bcd, 0x75},
+ {0x5bce, 0x75},
+ {0x5bcf, 0x75},
+ {0x5bd0, 0x75},
+ {0x5bd1, 0x75},
+ {0x5bd2, 0x75},
+ {0x5bd3, 0x75},
+ {0x5bd4, 0x75},
+ {0x5bd5, 0x75},
+ {0x5bd6, 0x75},
+ {0x5bd7, 0x75},
+ {0x5bd8, 0x75},
+ {0x5bd9, 0x75},
+ {0x5bda, 0x75},
+ {0x5bdb, 0x75},
+ {0x5bdc, 0x75},
+ {0x5bdd, 0x75},
+ {0x5bde, 0x75},
+ {0x5bdf, 0x75},
+ {0x5be0, 0x75},
+ {0x5be1, 0x75},
+ {0x5be2, 0x75},
+ {0x5be3, 0x75},
+ {0x5be4, 0x75},
+ {0x5be5, 0x75},
+ {0x5be6, 0x75},
+ {0x5be7, 0x75},
+ {0x5be8, 0x75},
+ {0x5be9, 0x75},
+ {0x5bea, 0x75},
+ {0x5beb, 0x75},
+ {0x5bec, 0x75},
+ {0x5bed, 0x75},
+ {0x5bee, 0x75},
+ {0x5bef, 0x75},
+ {0x5bf0, 0x75},
+ {0x5bf1, 0x75},
+ {0x5bf2, 0x75},
+ {0x5bf3, 0x75},
+ {0x5bf4, 0x75},
+ {0x5bf5, 0x75},
+ {0x5bf6, 0x75},
+ {0x5bf7, 0x75},
+ {0x5bf8, 0x75},
+ {0x5bf9, 0x75},
+ {0x5bfa, 0x75},
+ {0x5bfb, 0x75},
+ {0x5bfc, 0x75},
+ {0x5bfd, 0x75},
+ {0x5bfe, 0x75},
+ {0x5bff, 0x75},
+ {0x5c00, 0x75},
+ {0x5c01, 0x75},
+ {0x5c02, 0x75},
+ {0x5c03, 0x75},
+ {0x5c04, 0x75},
+ {0x5c05, 0x75},
+ {0x5c06, 0x75},
+ {0x5c07, 0x75},
+ {0x5c08, 0x75},
+ {0x5c09, 0x75},
+ {0x5c0a, 0x75},
+ {0x5c0b, 0x75},
+ {0x5c0c, 0x75},
+ {0x5c0d, 0x75},
+ {0x5c0e, 0x75},
+ {0x5c0f, 0x75},
+ {0x5c10, 0x75},
+ {0x5c11, 0x75},
+ {0x5c12, 0x75},
+ {0x5c13, 0x75},
+ {0x5c14, 0x75},
+ {0x5c15, 0x75},
+ {0x5c16, 0x75},
+ {0x5c17, 0x75},
+ {0x5c18, 0x75},
+ {0x5c19, 0x75},
+ {0x5c1a, 0x75},
+ {0x5c1b, 0x75},
+ {0x5c1c, 0x75},
+ {0x5c1d, 0x75},
+ {0x5c1e, 0x75},
+ {0x5c1f, 0x75},
+ {0x5c20, 0x75},
+ {0x5c21, 0x75},
+ {0x5c22, 0x75},
+ {0x5c23, 0x75},
+ {0x5c24, 0x75},
+ {0x5c25, 0x75},
+ {0x5c26, 0x75},
+ {0x5c27, 0x75},
+ {0x5c28, 0x75},
+ {0x5c29, 0x75},
+ {0x5c2a, 0x75},
+ {0x5c2b, 0x75},
+ {0x5c2c, 0x75},
+ {0x5c2d, 0x75},
+ {0x5c2e, 0x75},
+ {0x5c2f, 0x75},
+ {0x5c30, 0x75},
+ {0x5c31, 0x75},
+ {0x5c32, 0x75},
+ {0x5c33, 0x75},
+ {0x5c34, 0x75},
+ {0x5c35, 0x75},
+ {0x5c36, 0x75},
+ {0x5c37, 0x75},
+ {0x5c38, 0x75},
+ {0x5c39, 0x75},
+ {0x5c3a, 0x75},
+ {0x5c3b, 0x75},
+ {0x5c3c, 0x75},
+ {0x5c3d, 0x75},
+ {0x5c3e, 0x75},
+ {0x5c3f, 0x75},
+ {0x5c40, 0x75},
+ {0x5c41, 0x75},
+ {0x5c42, 0x75},
+ {0x5c43, 0x75},
+ {0x5c44, 0x75},
+ {0x5c45, 0x75},
+ {0x5c46, 0x75},
+ {0x5c47, 0x75},
+ {0x5c48, 0x75},
+ {0x5c49, 0x75},
+ {0x5c4a, 0x75},
+ {0x5c4b, 0x75},
+ {0x5c4c, 0x75},
+ {0x5c4d, 0x75},
+ {0x5c4e, 0x75},
+ {0x5c4f, 0x75},
+ {0x5c50, 0x75},
+ {0x5c51, 0x75},
+ {0x5c52, 0x75},
+ {0x5c53, 0x75},
+ {0x5c54, 0x75},
+ {0x5c55, 0x75},
+ {0x5c56, 0x75},
+ {0x5c57, 0x75},
+ {0x5c58, 0x75},
+ {0x5c59, 0x75},
+ {0x5c5a, 0x75},
+ {0x5c5b, 0x75},
+ {0x5c5c, 0x75},
+ {0x5c5d, 0x75},
+ {0x5c5e, 0x75},
+ {0x5c5f, 0x75},
+ {0x5c60, 0x75},
+ {0x5c61, 0x75},
+ {0x5c62, 0x75},
+ {0x5c63, 0x75},
+ {0x5c64, 0x75},
+ {0x5c65, 0x75},
+ {0x5c66, 0x75},
+ {0x5c67, 0x75},
+ {0x5c68, 0x75},
+ {0x5c69, 0x75},
+ {0x5c6a, 0x75},
+ {0x5c6b, 0x75},
+ {0x5c6c, 0x75},
+ {0x5c6d, 0x75},
+ {0x5c6e, 0x75},
+ {0x5c6f, 0x75},
+ {0x5c70, 0x75},
+ {0x5c71, 0x75},
+ {0x5c72, 0x75},
+ {0x5c73, 0x75},
+ {0x5c74, 0x75},
+ {0x5c75, 0x75},
+ {0x5c76, 0x75},
+ {0x5c77, 0x75},
+ {0x5c78, 0x75},
+ {0x5c79, 0x75},
+ {0x5c7a, 0x75},
+ {0x5c7b, 0x75},
+ {0x5c7c, 0x75},
+ {0x5c7d, 0x75},
+ {0x5c7e, 0x75},
+ {0x5c7f, 0x75},
+ {0x5c80, 0x75},
+ {0x5c81, 0x75},
+ {0x5c82, 0x75},
+ {0x5c83, 0x75},
+ {0x5c84, 0x75},
+ {0x5c85, 0x75},
+ {0x5c86, 0x75},
+ {0x5c87, 0x75},
+ {0x5c88, 0x75},
+ {0x5c89, 0x75},
+ {0x5c8a, 0x75},
+ {0x5c8b, 0x75},
+ {0x5c8c, 0x75},
+ {0x5c8d, 0x75},
+ {0x5c8e, 0x75},
+ {0x5c8f, 0x75},
+ {0x5c90, 0x75},
+ {0x5c91, 0x75},
+ {0x5c92, 0x75},
+ {0x5c93, 0x75},
+ {0x5c94, 0x75},
+ {0x5c95, 0x75},
+ {0x5c96, 0x75},
+ {0x5c97, 0x75},
+ {0x5c98, 0x75},
+ {0x5c99, 0x75},
+ {0x5c9a, 0x75},
+ {0x5c9b, 0x75},
+ {0x5c9c, 0x75},
+ {0x5c9d, 0x75},
+ {0x5c9e, 0x75},
+ {0x5c9f, 0x75},
+ {0x5ca0, 0x75},
+ {0x5ca1, 0x75},
+ {0x5ca2, 0x75},
+ {0x5ca3, 0x75},
+ {0x5ca4, 0x75},
+ {0x5ca5, 0x75},
+ {0x5ca6, 0x75},
+ {0x5ca7, 0x75},
+ {0x5ca8, 0x75},
+ {0x5ca9, 0x75},
+ {0x5caa, 0x75},
+ {0x5cab, 0x75},
+ {0x5cac, 0x75},
+ {0x5cad, 0x75},
+ {0x5cae, 0x75},
+ {0x5caf, 0x75},
+ {0x5cb0, 0x75},
+ {0x5cb1, 0x75},
+ {0x5cb2, 0x75},
+ {0x5cb3, 0x75},
+ {0x5cb4, 0x75},
+ {0x5cb5, 0x75},
+ {0x5cb6, 0x75},
+ {0x5cb7, 0x75},
+ {0x5cb8, 0x75},
+ {0x5cb9, 0x75},
+ {0x5cba, 0x75},
+ {0x5cbb, 0x75},
+ {0x5cbc, 0x75},
+ {0x5cbd, 0x75},
+ {0x5cbe, 0x75},
+ {0x5cbf, 0x75},
+ {0x5cc0, 0x75},
+ {0x5cc1, 0x75},
+ {0x5cc2, 0x75},
+ {0x5cc3, 0x75},
+ {0x5cc4, 0x75},
+ {0x5cc5, 0x75},
+ {0x5cc6, 0x75},
+ {0x5cc7, 0x75},
+ {0x5cc8, 0x75},
+ {0x5cc9, 0x75},
+ {0x5cca, 0x75},
+ {0x5ccb, 0x75},
+ {0x5ccc, 0x75},
+ {0x5ccd, 0x75},
+ {0x5cce, 0x75},
+ {0x5ccf, 0x75},
+ {0x5cd0, 0x75},
+ {0x5cd1, 0x75},
+ {0x5cd2, 0x75},
+ {0x5cd3, 0x75},
+ {0x5cd4, 0x75},
+ {0x5cd5, 0x75},
+ {0x5cd6, 0x75},
+ {0x5cd7, 0x75},
+ {0x5cd8, 0x75},
+ {0x5cd9, 0x75},
+ {0x5cda, 0x75},
+ {0x5cdb, 0x75},
+ {0x5cdc, 0x75},
+ {0x5cdd, 0x75},
+ {0x5cde, 0x75},
+ {0x5cdf, 0x75},
+ {0x5ce0, 0x75},
+ {0x5ce1, 0x75},
+ {0x5ce2, 0x75},
+ {0x5ce3, 0x75},
+ {0x5ce4, 0x75},
+ {0x5ce5, 0x75},
+ {0x5ce6, 0x75},
+ {0x5ce7, 0x75},
+ {0x5ce8, 0x75},
+ {0x5ce9, 0x75},
+ {0x5cea, 0x75},
+ {0x5ceb, 0x75},
+ {0x5cec, 0x75},
+ {0x5ced, 0x75},
+ {0x5cee, 0x75},
+ {0x5cef, 0x75},
+ {0x5cf0, 0x75},
+ {0x5cf1, 0x75},
+ {0x5cf2, 0x75},
+ {0x5cf3, 0x75},
+ {0x5cf4, 0x75},
+ {0x5cf5, 0x75},
+ {0x5cf6, 0x75},
+ {0x5cf7, 0x75},
+ {0x5cf8, 0x75},
+ {0x5cf9, 0x75},
+ {0x5cfa, 0x75},
+ {0x5cfb, 0x75},
+ {0x5cfc, 0x75},
+ {0x5cfd, 0x75},
+ {0x5cfe, 0x75},
+ {0x5cff, 0x75},
+ {0x5d00, 0x75},
+ {0x5d01, 0x75},
+ {0x5d02, 0x75},
+ {0x5d03, 0x75},
+ {0x5d04, 0x75},
+ {0x5d05, 0x75},
+ {0x5d06, 0x75},
+ {0x5d07, 0x75},
+ {0x5d08, 0x75},
+ {0x5d09, 0x75},
+ {0x5d0a, 0x75},
+ {0x5d0b, 0x75},
+ {0x5d0c, 0x75},
+ {0x5d0d, 0x75},
+ {0x5d0e, 0x75},
+ {0x5d0f, 0x75},
+ {0x5d10, 0x75},
+ {0x5d11, 0x75},
+ {0x5d12, 0x75},
+ {0x5d13, 0x75},
+ {0x5d14, 0x75},
+ {0x5d15, 0x75},
+ {0x5d16, 0x75},
+ {0x5d17, 0x75},
+ {0x5d18, 0x75},
+ {0x5d19, 0x75},
+ {0x5d1a, 0x75},
+ {0x5d1b, 0x75},
+ {0x5d1c, 0x75},
+ {0x5d1d, 0x75},
+ {0x5d1e, 0x75},
+ {0x5d1f, 0x75},
+ {0x5d20, 0x75},
+ {0x5d21, 0x75},
+ {0x5d22, 0x75},
+ {0x5d23, 0x75},
+ {0x5d24, 0x75},
+ {0x5d25, 0x75},
+ {0x5d26, 0x75},
+ {0x5d27, 0x75},
+ {0x5d28, 0x75},
+ {0x5d29, 0x75},
+ {0x5d2a, 0x75},
+ {0x5d2b, 0x75},
+ {0x5d2c, 0x75},
+ {0x5d2d, 0x75},
+ {0x5d2e, 0x75},
+ {0x5d2f, 0x75},
+ {0x5d30, 0x75},
+ {0x5d31, 0x75},
+ {0x5d32, 0x75},
+ {0x5d33, 0x75},
+ {0x5d34, 0x75},
+ {0x5d35, 0x75},
+ {0x5d36, 0x75},
+ {0x5d37, 0x75},
+ {0x5d38, 0x75},
+ {0x5d39, 0x75},
+ {0x5d3a, 0x75},
+ {0x5d3b, 0x75},
+ {0x5d3c, 0x75},
+ {0x5d3d, 0x75},
+ {0x5d3e, 0x75},
+ {0x5d3f, 0x75},
+ {0x5d40, 0x75},
+ {0x5d41, 0x75},
+ {0x5d42, 0x75},
+ {0x5d43, 0x75},
+ {0x5d44, 0x75},
+ {0x5d45, 0x75},
+ {0x5d46, 0x75},
+ {0x5d47, 0x75},
+ {0x5d48, 0x75},
+ {0x5d49, 0x75},
+ {0x5d4a, 0x75},
+ {0x5d4b, 0x75},
+ {0x5d4c, 0x75},
+ {0x5d4d, 0x75},
+ {0x5d4e, 0x75},
+ {0x5d4f, 0x75},
+ {0x5d50, 0x75},
+ {0x5d51, 0x75},
+ {0x5d52, 0x75},
+ {0x5d53, 0x75},
+ {0x5d54, 0x75},
+ {0x5d55, 0x75},
+ {0x5d56, 0x75},
+ {0x5d57, 0x75},
+ {0x5d58, 0x75},
+ {0x5d59, 0x75},
+ {0x5d5a, 0x75},
+ {0x5d5b, 0x75},
+ {0x5d5c, 0x75},
+ {0x5d5d, 0x75},
+ {0x5d5e, 0x75},
+ {0x5d5f, 0x75},
+ {0x5d60, 0x75},
+ {0x5d61, 0x75},
+ {0x5d62, 0x75},
+ {0x5d63, 0x75},
+ {0x5d64, 0x75},
+ {0x5d65, 0x75},
+ {0x5d66, 0x75},
+ {0x5d67, 0x75},
+ {0x5d68, 0x75},
+ {0x5d69, 0x75},
+ {0x5d6a, 0x75},
+ {0x5d6b, 0x75},
+ {0x5d6c, 0x75},
+ {0x5d6d, 0x75},
+ {0x5d6e, 0x75},
+ {0x5d6f, 0x75},
+ {0x5d70, 0x75},
+ {0x5d71, 0x75},
+ {0x5d72, 0x75},
+ {0x5d73, 0x75},
+ {0x5d74, 0x75},
+ {0x5d75, 0x75},
+ {0x5d76, 0x75},
+ {0x5d77, 0x75},
+ {0x5d78, 0x75},
+ {0x5d79, 0x75},
+ {0x5d7a, 0x75},
+ {0x5d7b, 0x75},
+ {0x5d7c, 0x75},
+ {0x5d7d, 0x75},
+ {0x5d7e, 0x75},
+ {0x5d7f, 0x75},
+ {0x5d80, 0x75},
+ {0x5d81, 0x75},
+ {0x5d82, 0x75},
+ {0x5d83, 0x75},
+ {0x5d84, 0x75},
+ {0x5d85, 0x75},
+ {0x5d86, 0x75},
+ {0x5d87, 0x75},
+ {0x5d88, 0x75},
+ {0x5d89, 0x75},
+ {0x5d8a, 0x75},
+ {0x5d8b, 0x75},
+ {0x5d8c, 0x75},
+ {0x5d8d, 0x75},
+ {0x5d8e, 0x75},
+ {0x5d8f, 0x75},
+ {0x5d90, 0x75},
+ {0x5d91, 0x75},
+ {0x5d92, 0x75},
+ {0x5d93, 0x75},
+ {0x5d94, 0x75},
+ {0x5d95, 0x75},
+ {0x5d96, 0x75},
+ {0x5d97, 0x75},
+ {0x5d98, 0x75},
+ {0x5d99, 0x75},
+ {0x5d9a, 0x75},
+ {0x5d9b, 0x75},
+ {0x5d9c, 0x75},
+ {0x5d9d, 0x75},
+ {0x5d9e, 0x75},
+ {0x5d9f, 0x75},
+ {0x5da0, 0x75},
+ {0x5da1, 0x75},
+ {0x5da2, 0x75},
+ {0x5da3, 0x75},
+ {0x5da4, 0x75},
+ {0x5da5, 0x75},
+ {0x5da6, 0x75},
+ {0x5da7, 0x75},
+ {0x5da8, 0x75},
+ {0x5da9, 0x75},
+ {0x5daa, 0x75},
+ {0x5dab, 0x75},
+ {0x5dac, 0x75},
+ {0x5dad, 0x75},
+ {0x5dae, 0x75},
+ {0x5daf, 0x75},
+ {0x5db0, 0x75},
+ {0x5db1, 0x75},
+ {0x5db2, 0x75},
+ {0x5db3, 0x75},
+ {0x5db4, 0x75},
+ {0x5db5, 0x75},
+ {0x5db6, 0x75},
+ {0x5db7, 0x75},
+ {0x5db8, 0x75},
+ {0x5db9, 0x75},
+ {0x5dba, 0x75},
+ {0x5dbb, 0x75},
+ {0x5dbc, 0x75},
+ {0x5dbd, 0x75},
+ {0x5dbe, 0x75},
+ {0x5dbf, 0x75},
+ {0x5dc0, 0x75},
+ {0x5dc1, 0x75},
+ {0x5dc2, 0x75},
+ {0x5dc3, 0x75},
+ {0x5dc4, 0x75},
+ {0x5dc5, 0x75},
+ {0x5dc6, 0x75},
+ {0x5dc7, 0x75},
+ {0x5dc8, 0x75},
+ {0x5dc9, 0x75},
+ {0x5dca, 0x75},
+ {0x5dcb, 0x75},
+ {0x5dcc, 0x75},
+ {0x5dcd, 0x75},
+ {0x5dce, 0x75},
+ {0x5dcf, 0x75},
+ {0x5dd0, 0x75},
+ {0x5dd1, 0x75},
+ {0x5dd2, 0x75},
+ {0x5dd3, 0x75},
+ {0x5dd4, 0x75},
+ {0x5dd5, 0x75},
+ {0x5dd6, 0x75},
+ {0x5dd7, 0x75},
+ {0x5dd8, 0x75},
+ {0x5dd9, 0x75},
+ {0x5dda, 0x75},
+ {0x5ddb, 0x75},
+ {0x5ddc, 0x75},
+ {0x5ddd, 0x75},
+ {0x5dde, 0x75},
+ {0x5ddf, 0x75},
+ {0x5de0, 0x75},
+ {0x5de1, 0x75},
+ {0x5de2, 0x75},
+ {0x5de3, 0x75},
+ {0x5de4, 0x75},
+ {0x5de5, 0x75},
+ {0x5de6, 0x75},
+ {0x5de7, 0x75},
+ {0x5de8, 0x75},
+ {0x5de9, 0x75},
+ {0x5dea, 0x75},
+ {0x5deb, 0x75},
+ {0x5dec, 0x75},
+ {0x5ded, 0x75},
+ {0x5dee, 0x75},
+ {0x5def, 0x75},
+ {0x5df0, 0x75},
+ {0x5df1, 0x75},
+ {0x5df2, 0x75},
+ {0x5df3, 0x75},
+ {0x5df4, 0x75},
+ {0x5df5, 0x75},
+ {0x5df6, 0x75},
+ {0x5df7, 0x75},
+ {0x5df8, 0x75},
+ {0x5df9, 0x75},
+ {0x5dfa, 0x75},
+ {0x5dfb, 0x75},
+ {0x5dfc, 0x75},
+ {0x5dfd, 0x75},
+ {0x5dfe, 0x75},
+ {0x5dff, 0x75},
+ {0x5e00, 0x75},
+ {0x5e01, 0x75},
+ {0x5e02, 0x75},
+ {0x5e03, 0x75},
+ {0x5e04, 0x75},
+ {0x5e05, 0x75},
+ {0x5e06, 0x75},
+ {0x5e07, 0x75},
+ {0x5e08, 0x75},
+ {0x5e09, 0x75},
+ {0x5e0a, 0x75},
+ {0x5e0b, 0x75},
+ {0x5e0c, 0x75},
+ {0x5e0d, 0x75},
+ {0x5e0e, 0x75},
+ {0x5e0f, 0x75},
+ {0x5e10, 0x75},
+ {0x5e11, 0x75},
+ {0x5e12, 0x75},
+ {0x5e13, 0x75},
+ {0x5e14, 0x75},
+ {0x5e15, 0x75},
+ {0x5e16, 0x75},
+ {0x5e17, 0x75},
+ {0x5e18, 0x75},
+ {0x5e19, 0x75},
+ {0x5e1a, 0x75},
+ {0x5e1b, 0x75},
+ {0x5e1c, 0x75},
+ {0x5e1d, 0x75},
+ {0x5e1e, 0x75},
+ {0x5e1f, 0x75},
+ {0x5e20, 0x75},
+ {0x5e21, 0x75},
+ {0x5e22, 0x75},
+ {0x5e23, 0x75},
+ {0x5e24, 0x75},
+ {0x5e25, 0x75},
+ {0x5e26, 0x75},
+ {0x5e27, 0x75},
+ {0x5e28, 0x75},
+ {0x5e29, 0x75},
+ {0x5e2a, 0x75},
+ {0x5e2b, 0x75},
+ {0x5e2c, 0x75},
+ {0x5e2d, 0x75},
+ {0x5e2e, 0x75},
+ {0x5e2f, 0x75},
+ {0x5e30, 0x75},
+ {0x5e31, 0x75},
+ {0x5e32, 0x75},
+ {0x5e33, 0x75},
+ {0x5e34, 0x75},
+ {0x5e35, 0x75},
+ {0x5e36, 0x75},
+ {0x5e37, 0x75},
+ {0x5e38, 0x75},
+ {0x5e39, 0x75},
+ {0x5e3a, 0x75},
+ {0x5e3b, 0x75},
+ {0x5e3c, 0x75},
+ {0x5e3d, 0x75},
+ {0x5e3e, 0x75},
+ {0x5e3f, 0x75},
+ {0x5e40, 0x75},
+ {0x5e41, 0x75},
+ {0x5e42, 0x75},
+ {0x5e43, 0x75},
+ {0x5e44, 0x75},
+ {0x5e45, 0x75},
+ {0x5e46, 0x75},
+ {0x5e47, 0x75},
+ {0x5e48, 0x75},
+ {0x5e49, 0x75},
+ {0x5e4a, 0x75},
+ {0x5e4b, 0x75},
+ {0x5e4c, 0x75},
+ {0x5e4d, 0x75},
+ {0x5e4e, 0x75},
+ {0x5e4f, 0x75},
+ {0x5e50, 0x75},
+ {0x5e51, 0x75},
+ {0x5e52, 0x75},
+ {0x5e53, 0x75},
+ {0x5e54, 0x75},
+ {0x5e55, 0x75},
+ {0x5e56, 0x75},
+ {0x5e57, 0x75},
+ {0x5e58, 0x75},
+ {0x5e59, 0x75},
+ {0x5e5a, 0x75},
+ {0x5e5b, 0x75},
+ {0x5e5c, 0x75},
+ {0x5e5d, 0x75},
+ {0x5e5e, 0x75},
+ {0x5e5f, 0x75},
+ {0x5e60, 0x75},
+ {0x5e61, 0x75},
+ {0x5e62, 0x75},
+ {0x5e63, 0x75},
+ {0x5e64, 0x75},
+ {0x5e65, 0x75},
+ {0x5e66, 0x75},
+ {0x5e67, 0x75},
+ {0x5e68, 0x75},
+ {0x5e69, 0x75},
+ {0x5e6a, 0x75},
+ {0x5e6b, 0x75},
+ {0x5e6c, 0x75},
+ {0x5e6d, 0x75},
+ {0x5e6e, 0x75},
+ {0x5e6f, 0x75},
+ {0x5e70, 0x75},
+ {0x5e71, 0x75},
+ {0x5e72, 0x75},
+ {0x5e73, 0x75},
+ {0x5e74, 0x75},
+ {0x5e75, 0x75},
+ {0x5e76, 0x75},
+ {0x5e77, 0x75},
+ {0x5e78, 0x75},
+ {0x5e79, 0x75},
+ {0x5e7a, 0x75},
+ {0x5e7b, 0x75},
+ {0x5e7c, 0x75},
+ {0x5e7d, 0x75},
+ {0x5e7e, 0x75},
+ {0x5e7f, 0x75},
+ {0x5e80, 0x75},
+ {0x5e81, 0x75},
+ {0x5e82, 0x75},
+ {0x5e83, 0x75},
+ {0x5e84, 0x75},
+ {0x5e85, 0x75},
+ {0x5e86, 0x75},
+ {0x5e87, 0x75},
+ {0x5e88, 0x75},
+ {0x5e89, 0x75},
+ {0x5e8a, 0x75},
+ {0x5e8b, 0x75},
+ {0x5e8c, 0x75},
+ {0x5e8d, 0x75},
+ {0x5e8e, 0x75},
+ {0x5e8f, 0x75},
+ {0x5e90, 0x75},
+ {0x5e91, 0x75},
+ {0x5e92, 0x75},
+ {0x5e93, 0x75},
+ {0x5e94, 0x75},
+ {0x5e95, 0x75},
+ {0x5e96, 0x75},
+ {0x5e97, 0x75},
+ {0x5e98, 0x75},
+ {0x5e99, 0x75},
+ {0x5e9a, 0x75},
+ {0x5e9b, 0x75},
+ {0x5e9c, 0x75},
+ {0x5e9d, 0x75},
+ {0x5e9e, 0x75},
+ {0x5e9f, 0x75},
+ {0x5ea0, 0x75},
+ {0x5ea1, 0x75},
+ {0x5ea2, 0x75},
+ {0x5ea3, 0x75},
+ {0x5ea4, 0x75},
+ {0x5ea5, 0x75},
+ {0x5ea6, 0x75},
+ {0x5ea7, 0x75},
+ {0x5ea8, 0x75},
+ {0x5ea9, 0x75},
+ {0x5eaa, 0x75},
+ {0x5eab, 0x75},
+ {0x5eac, 0x75},
+ {0x5ead, 0x75},
+ {0x5eae, 0x75},
+ {0x5eaf, 0x75},
+ {0x5eb0, 0x75},
+ {0x5eb1, 0x75},
+ {0x5eb2, 0x75},
+ {0x5eb3, 0x75},
+ {0x5eb4, 0x75},
+ {0x5eb5, 0x75},
+ {0x5eb6, 0x75},
+ {0x5eb7, 0x75},
+ {0x5eb8, 0x75},
+ {0x5eb9, 0x75},
+ {0x5eba, 0x75},
+ {0x5ebb, 0x75},
+ {0x5ebc, 0x75},
+ {0x5ebd, 0x75},
+ {0x5ebe, 0x75},
+ {0x5ebf, 0x75},
+ {0x5ec0, 0x75},
+ {0x5ec1, 0x75},
+ {0x5ec2, 0x75},
+ {0x5ec3, 0x75},
+ {0x5ec4, 0x75},
+ {0x5ec5, 0x75},
+ {0x5ec6, 0x75},
+ {0x5ec7, 0x75},
+ {0x5ec8, 0x75},
+ {0x5ec9, 0x75},
+ {0x5eca, 0x75},
+ {0x5ecb, 0x75},
+ {0x5ecc, 0x75},
+ {0x5ecd, 0x75},
+ {0x5ece, 0x75},
+ {0x5ecf, 0x75},
+ {0x5ed0, 0x75},
+ {0x5ed1, 0x75},
+ {0x5ed2, 0x75},
+ {0x5ed3, 0x75},
+ {0x5ed4, 0x75},
+ {0x5ed5, 0x75},
+ {0x5ed6, 0x75},
+ {0x5ed7, 0x75},
+ {0x5ed8, 0x75},
+ {0x5ed9, 0x75},
+ {0x5eda, 0x75},
+ {0x5edb, 0x75},
+ {0x5edc, 0x75},
+ {0x5edd, 0x75},
+ {0x5ede, 0x75},
+ {0x5edf, 0x75},
+ {0x5ee0, 0x75},
+ {0x5ee1, 0x75},
+ {0x5ee2, 0x75},
+ {0x5ee3, 0x75},
+ {0x5ee4, 0x75},
+ {0x5ee5, 0x75},
+ {0x5ee6, 0x75},
+ {0x5ee7, 0x75},
+ {0x5ee8, 0x75},
+ {0x5ee9, 0x75},
+ {0x5eea, 0x75},
+ {0x5eeb, 0x75},
+ {0x5eec, 0x75},
+ {0x5eed, 0x75},
+ {0x5eee, 0x75},
+ {0x5eef, 0x75},
+ {0x5ef0, 0x75},
+ {0x5ef1, 0x75},
+ {0x5ef2, 0x75},
+ {0x5ef3, 0x75},
+ {0x5ef4, 0x75},
+ {0x5ef5, 0x75},
+ {0x5ef6, 0x75},
+ {0x5ef7, 0x75},
+ {0x5ef8, 0x75},
+ {0x5ef9, 0x75},
+ {0x5efa, 0x75},
+ {0x5efb, 0x75},
+ {0x5efc, 0x75},
+ {0x5efd, 0x75},
+ {0x5efe, 0x75},
+ {0x5eff, 0x75},
+ {0x5f00, 0x75},
+ {0x5f01, 0x75},
+ {0x5f02, 0x75},
+ {0x5f03, 0x75},
+ {0x5f04, 0x75},
+ {0x5f05, 0x75},
+ {0x5f06, 0x75},
+ {0x5f07, 0x75},
+ {0x5f08, 0x75},
+ {0x5f09, 0x75},
+ {0x5f0a, 0x75},
+ {0x5f0b, 0x75},
+ {0x5f0c, 0x75},
+ {0x5f0d, 0x75},
+ {0x5f0e, 0x75},
+ {0x5f0f, 0x75},
+ {0x5f10, 0x75},
+ {0x5f11, 0x75},
+ {0x5f12, 0x75},
+ {0x5f13, 0x75},
+ {0x5f14, 0x75},
+ {0x5f15, 0x75},
+ {0x5f16, 0x75},
+ {0x5f17, 0x75},
+ {0x5f18, 0x75},
+ {0x5f19, 0x75},
+ {0x5f1a, 0x75},
+ {0x5f1b, 0x75},
+ {0x5f1c, 0x75},
+ {0x5f1d, 0x75},
+ {0x5f1e, 0x75},
+ {0x5f1f, 0x75},
+};
+
+static const struct ov08x40_reg mode_1928x1208_regs[] = {
+ {0x5000, 0x55},
+ {0x5001, 0x00},
+ {0x5008, 0xb0},
+ {0x50c1, 0x00},
+ {0x53c1, 0x00},
+ {0x5f40, 0x00},
+ {0x5f41, 0x40},
+ {0x0300, 0x3a},
+ {0x0301, 0xc8},
+ {0x0302, 0x31},
+ {0x0303, 0x03},
+ {0x0304, 0x01},
+ {0x0305, 0xa1},
+ {0x0306, 0x04},
+ {0x0307, 0x01},
+ {0x0308, 0x03},
+ {0x0309, 0x03},
+ {0x0310, 0x0a},
+ {0x0311, 0x02},
+ {0x0312, 0x01},
+ {0x0313, 0x08},
+ {0x0314, 0x66},
+ {0x0315, 0x00},
+ {0x0316, 0x34},
+ {0x0320, 0x02},
+ {0x0321, 0x03},
+ {0x0323, 0x05},
+ {0x0324, 0x01},
+ {0x0325, 0xb8},
+ {0x0326, 0x4a},
+ {0x0327, 0x04},
+ {0x0329, 0x00},
+ {0x032a, 0x05},
+ {0x032b, 0x00},
+ {0x032c, 0x00},
+ {0x032d, 0x00},
+ {0x032e, 0x02},
+ {0x032f, 0xa0},
+ {0x0350, 0x00},
+ {0x0360, 0x01},
+ {0x1216, 0x60},
+ {0x1217, 0x5b},
+ {0x1218, 0x00},
+ {0x1220, 0x24},
+ {0x198a, 0x00},
+ {0x198b, 0x01},
+ {0x198e, 0x00},
+ {0x198f, 0x01},
+ {0x3009, 0x04},
+ {0x3012, 0x41},
+ {0x3015, 0x00},
+ {0x3016, 0xb0},
+ {0x3017, 0xf0},
+ {0x3018, 0xf0},
+ {0x3019, 0xd2},
+ {0x301a, 0xb0},
+ {0x301c, 0x81},
+ {0x301d, 0x02},
+ {0x301e, 0x80},
+ {0x3022, 0xf0},
+ {0x3025, 0x89},
+ {0x3030, 0x03},
+ {0x3044, 0xc2},
+ {0x3050, 0x35},
+ {0x3051, 0x60},
+ {0x3052, 0x25},
+ {0x3053, 0x00},
+ {0x3054, 0x00},
+ {0x3055, 0x02},
+ {0x3056, 0x80},
+ {0x3057, 0x80},
+ {0x3058, 0x80},
+ {0x3059, 0x00},
+ {0x3107, 0x86},
+ {0x3400, 0x1c},
+ {0x3401, 0x80},
+ {0x3402, 0x8c},
+ {0x3419, 0x08},
+ {0x341a, 0xaf},
+ {0x341b, 0x30},
+ {0x3420, 0x00},
+ {0x3421, 0x00},
+ {0x3422, 0x00},
+ {0x3423, 0x00},
+ {0x3424, 0x00},
+ {0x3425, 0x00},
+ {0x3426, 0x00},
+ {0x3427, 0x00},
+ {0x3428, 0x0f},
+ {0x3429, 0x00},
+ {0x342a, 0x00},
+ {0x342b, 0x00},
+ {0x342c, 0x00},
+ {0x342d, 0x00},
+ {0x342e, 0x00},
+ {0x342f, 0x11},
+ {0x3430, 0x11},
+ {0x3431, 0x10},
+ {0x3432, 0x00},
+ {0x3433, 0x00},
+ {0x3434, 0x00},
+ {0x3435, 0x00},
+ {0x3436, 0x00},
+ {0x3437, 0x00},
+ {0x3442, 0x02},
+ {0x3443, 0x02},
+ {0x3444, 0x07},
+ {0x3450, 0x00},
+ {0x3451, 0x00},
+ {0x3452, 0x18},
+ {0x3453, 0x18},
+ {0x3454, 0x00},
+ {0x3455, 0x80},
+ {0x3456, 0x08},
+ {0x3500, 0x00},
+ {0x3501, 0x02},
+ {0x3502, 0x00},
+ {0x3504, 0x4c},
+ {0x3506, 0x30},
+ {0x3507, 0x00},
+ {0x3508, 0x01},
+ {0x3509, 0x00},
+ {0x350a, 0x01},
+ {0x350b, 0x00},
+ {0x350c, 0x00},
+ {0x3540, 0x00},
+ {0x3541, 0x01},
+ {0x3542, 0x00},
+ {0x3544, 0x4c},
+ {0x3546, 0x30},
+ {0x3547, 0x00},
+ {0x3548, 0x01},
+ {0x3549, 0x00},
+ {0x354a, 0x01},
+ {0x354b, 0x00},
+ {0x354c, 0x00},
+ {0x3688, 0x02},
+ {0x368a, 0x2e},
+ {0x368e, 0x71},
+ {0x3696, 0xd1},
+ {0x3699, 0x00},
+ {0x369a, 0x00},
+ {0x36a4, 0x00},
+ {0x36a6, 0x00},
+ {0x3711, 0x00},
+ {0x3712, 0x50},
+ {0x3713, 0x00},
+ {0x3714, 0x21},
+ {0x3716, 0x00},
+ {0x3718, 0x07},
+ {0x371a, 0x1c},
+ {0x371b, 0x00},
+ {0x3720, 0x08},
+ {0x3725, 0x32},
+ {0x3727, 0x05},
+ {0x3760, 0x02},
+ {0x3761, 0x28},
+ {0x3762, 0x02},
+ {0x3763, 0x02},
+ {0x3764, 0x02},
+ {0x3765, 0x2c},
+ {0x3766, 0x04},
+ {0x3767, 0x2c},
+ {0x3768, 0x02},
+ {0x3769, 0x00},
+ {0x376b, 0x20},
+ {0x376e, 0x07},
+ {0x37b0, 0x01},
+ {0x37b1, 0x0f},
+ {0x37b2, 0x01},
+ {0x37b3, 0xd6},
+ {0x37b4, 0x01},
+ {0x37b5, 0x48},
+ {0x37b6, 0x02},
+ {0x37b7, 0x40},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0f},
+ {0x3805, 0x1f},
+ {0x3806, 0x09},
+ {0x3807, 0x7f},
+ {0x3808, 0x07},
+ {0x3809, 0x88},
+ {0x380a, 0x04},
+ {0x380b, 0xb8},
+ {0x380c, 0x02},
+ {0x380d, 0xd0},
+ {0x380e, 0x11},
+ {0x380f, 0x5c},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x03},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3820, 0x02},
+ {0x3821, 0x14},
+ {0x3822, 0x00},
+ {0x3823, 0x04},
+ {0x3828, 0x0f},
+ {0x382a, 0x80},
+ {0x382e, 0x41},
+ {0x3837, 0x08},
+ {0x383a, 0x81},
+ {0x383b, 0x81},
+ {0x383c, 0x11},
+ {0x383d, 0x11},
+ {0x383e, 0x00},
+ {0x383f, 0x38},
+ {0x3840, 0x00},
+ {0x3847, 0x00},
+ {0x384a, 0x00},
+ {0x384c, 0x02},
+ {0x384d, 0xd0},
+ {0x3856, 0x50},
+ {0x3857, 0x30},
+ {0x3858, 0x80},
+ {0x3859, 0x40},
+ {0x3860, 0x00},
+ {0x3888, 0x00},
+ {0x3889, 0x00},
+ {0x388a, 0x00},
+ {0x388b, 0x00},
+ {0x388c, 0x00},
+ {0x388d, 0x00},
+ {0x388e, 0x00},
+ {0x388f, 0x00},
+ {0x3894, 0x00},
+ {0x3895, 0x00},
+ {0x3c84, 0x00},
+ {0x3d85, 0x8b},
+ {0x3daa, 0x80},
+ {0x3dab, 0x14},
+ {0x3dac, 0x80},
+ {0x3dad, 0xc8},
+ {0x3dae, 0x81},
+ {0x3daf, 0x7b},
+ {0x3f00, 0x10},
+ {0x3f01, 0x11},
+ {0x3f06, 0x0d},
+ {0x3f07, 0x0b},
+ {0x3f08, 0x0d},
+ {0x3f09, 0x0b},
+ {0x3f0a, 0x01},
+ {0x3f0b, 0x11},
+ {0x3f0c, 0x33},
+ {0x4001, 0x07},
+ {0x4007, 0x20},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x04},
+ {0x400c, 0x00},
+ {0x400d, 0x04},
+ {0x400e, 0x14},
+ {0x4010, 0xf4},
+ {0x4011, 0x03},
+ {0x4012, 0x55},
+ {0x4015, 0x00},
+ {0x4016, 0x27},
+ {0x4017, 0x00},
+ {0x4018, 0x0f},
+ {0x401b, 0x08},
+ {0x401c, 0x00},
+ {0x401d, 0x10},
+ {0x401e, 0x02},
+ {0x401f, 0x00},
+ {0x4050, 0x06},
+ {0x4051, 0xff},
+ {0x4052, 0xff},
+ {0x4053, 0xff},
+ {0x4054, 0xff},
+ {0x4055, 0xff},
+ {0x4056, 0xff},
+ {0x4057, 0x7f},
+ {0x4058, 0x00},
+ {0x4059, 0x00},
+ {0x405a, 0x00},
+ {0x405b, 0x00},
+ {0x405c, 0x07},
+ {0x405d, 0xff},
+ {0x405e, 0x07},
+ {0x405f, 0xff},
+ {0x4080, 0x78},
+ {0x4081, 0x78},
+ {0x4082, 0x78},
+ {0x4083, 0x78},
+ {0x4019, 0x00},
+ {0x401a, 0x40},
+ {0x4020, 0x04},
+ {0x4021, 0x00},
+ {0x4022, 0x04},
+ {0x4023, 0x00},
+ {0x4024, 0x04},
+ {0x4025, 0x00},
+ {0x4026, 0x04},
+ {0x4027, 0x00},
+ {0x4030, 0x00},
+ {0x4031, 0x00},
+ {0x4032, 0x00},
+ {0x4033, 0x00},
+ {0x4034, 0x00},
+ {0x4035, 0x00},
+ {0x4036, 0x00},
+ {0x4037, 0x00},
+ {0x4040, 0x00},
+ {0x4041, 0x80},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4060, 0x00},
+ {0x4061, 0x00},
+ {0x4062, 0x00},
+ {0x4063, 0x00},
+ {0x4064, 0x00},
+ {0x4065, 0x00},
+ {0x4066, 0x00},
+ {0x4067, 0x00},
+ {0x4068, 0x00},
+ {0x4069, 0x00},
+ {0x406a, 0x00},
+ {0x406b, 0x00},
+ {0x406c, 0x00},
+ {0x406d, 0x00},
+ {0x406e, 0x00},
+ {0x406f, 0x00},
+ {0x4070, 0x00},
+ {0x4071, 0x00},
+ {0x4072, 0x00},
+ {0x4073, 0x00},
+ {0x4074, 0x00},
+ {0x4075, 0x00},
+ {0x4076, 0x00},
+ {0x4077, 0x00},
+ {0x4078, 0x00},
+ {0x4079, 0x00},
+ {0x407a, 0x00},
+ {0x407b, 0x00},
+ {0x407c, 0x00},
+ {0x407d, 0x00},
+ {0x407e, 0x00},
+ {0x407f, 0x00},
+ {0x40e0, 0x00},
+ {0x40e1, 0x00},
+ {0x40e2, 0x00},
+ {0x40e3, 0x00},
+ {0x40e4, 0x00},
+ {0x40e5, 0x00},
+ {0x40e6, 0x00},
+ {0x40e7, 0x00},
+ {0x40e8, 0x00},
+ {0x40e9, 0x80},
+ {0x40ea, 0x00},
+ {0x40eb, 0x80},
+ {0x40ec, 0x00},
+ {0x40ed, 0x80},
+ {0x40ee, 0x00},
+ {0x40ef, 0x80},
+ {0x40f0, 0x02},
+ {0x40f1, 0x04},
+ {0x4300, 0x00},
+ {0x4301, 0x00},
+ {0x4302, 0x00},
+ {0x4303, 0x00},
+ {0x4304, 0x00},
+ {0x4305, 0x00},
+ {0x4306, 0x00},
+ {0x4307, 0x00},
+ {0x4308, 0x00},
+ {0x4309, 0x00},
+ {0x430a, 0x00},
+ {0x430b, 0xff},
+ {0x430c, 0xff},
+ {0x430d, 0x00},
+ {0x430e, 0x00},
+ {0x4315, 0x00},
+ {0x4316, 0x00},
+ {0x4317, 0x00},
+ {0x4318, 0x00},
+ {0x4319, 0x00},
+ {0x431a, 0x00},
+ {0x431b, 0x00},
+ {0x431c, 0x00},
+ {0x4500, 0x07},
+ {0x4501, 0x10},
+ {0x4502, 0x00},
+ {0x4503, 0x0f},
+ {0x4504, 0x80},
+ {0x4506, 0x01},
+ {0x4509, 0x05},
+ {0x450c, 0x00},
+ {0x450d, 0x20},
+ {0x450e, 0x00},
+ {0x450f, 0x00},
+ {0x4510, 0x00},
+ {0x4523, 0x00},
+ {0x4526, 0x00},
+ {0x4542, 0x00},
+ {0x4543, 0x00},
+ {0x4544, 0x00},
+ {0x4545, 0x00},
+ {0x4546, 0x00},
+ {0x4547, 0x10},
+ {0x4602, 0x00},
+ {0x4603, 0x15},
+ {0x460b, 0x07},
+ {0x4680, 0x11},
+ {0x4686, 0x00},
+ {0x4687, 0x00},
+ {0x4700, 0x00},
+ {0x4800, 0x64},
+ {0x4806, 0x40},
+ {0x480b, 0x10},
+ {0x480c, 0x80},
+ {0x480f, 0x32},
+ {0x4813, 0xe4},
+ {0x4837, 0x14},
+ {0x4850, 0x42},
+ {0x4884, 0x04},
+ {0x4c00, 0xf8},
+ {0x4c01, 0x44},
+ {0x4c03, 0x00},
+ {0x4d00, 0x00},
+ {0x4d01, 0x16},
+ {0x4d04, 0x10},
+ {0x4d05, 0x00},
+ {0x4d06, 0x0c},
+ {0x4d07, 0x00},
+ {0x3d84, 0x04},
+ {0x3680, 0xa4},
+ {0x3682, 0x80},
+ {0x3601, 0x40},
+ {0x3602, 0x90},
+ {0x3608, 0x0a},
+ {0x3938, 0x09},
+ {0x3a74, 0x84},
+ {0x3a99, 0x84},
+ {0x3ab9, 0xa6},
+ {0x3aba, 0xba},
+ {0x3b12, 0x84},
+ {0x3b14, 0xbb},
+ {0x3b15, 0xbf},
+ {0x3a29, 0x26},
+ {0x3a1f, 0x8a},
+ {0x3a22, 0x91},
+ {0x3a25, 0x96},
+ {0x3a28, 0xb4},
+ {0x3a2b, 0xba},
+ {0x3a2e, 0xbf},
+ {0x3a31, 0xc1},
+ {0x3a20, 0x05},
+ {0x3939, 0x6b},
+ {0x3902, 0x10},
+ {0x3903, 0x10},
+ {0x3904, 0x10},
+ {0x3905, 0x10},
+ {0x3906, 0x01},
+ {0x3907, 0x0b},
+ {0x3908, 0x10},
+ {0x3909, 0x13},
+ {0x360f, 0x99},
+ {0x390b, 0x11},
+ {0x390c, 0x21},
+ {0x390d, 0x32},
+ {0x390e, 0x76},
+ {0x3911, 0x90},
+ {0x3913, 0x90},
+ {0x3b3f, 0x9d},
+ {0x3b45, 0x9d},
+ {0x3b1b, 0xc9},
+ {0x3b21, 0xc9},
+ {0x3a1a, 0x1c},
+ {0x3a23, 0x15},
+ {0x3a26, 0x17},
+ {0x3a2c, 0x50},
+ {0x3a2f, 0x18},
+ {0x3a32, 0x4f},
+ {0x3ace, 0x01},
+ {0x3ad2, 0x01},
+ {0x3ad6, 0x01},
+ {0x3ada, 0x01},
+ {0x3ade, 0x01},
+ {0x3ae2, 0x01},
+ {0x3aee, 0x01},
+ {0x3af2, 0x01},
+ {0x3af6, 0x01},
+ {0x3afa, 0x01},
+ {0x3afe, 0x01},
+ {0x3b02, 0x01},
+ {0x3b06, 0x01},
+ {0x3b0a, 0x01},
+ {0x3b0b, 0x00},
+ {0x3b0e, 0x01},
+ {0x3b0f, 0x00},
+ {0x392c, 0x02},
+ {0x392d, 0x01},
+ {0x392e, 0x04},
+ {0x392f, 0x03},
+ {0x3930, 0x09},
+ {0x3931, 0x07},
+ {0x3932, 0x10},
+ {0x3933, 0x0d},
+ {0x3609, 0x08},
+ {0x3921, 0x0f},
+ {0x3928, 0x15},
+ {0x3929, 0x2a},
+ {0x392a, 0x52},
+ {0x392b, 0xa3},
+ {0x340b, 0x1b},
+ {0x3426, 0x10},
+ {0x3407, 0x01},
+ {0x3404, 0x01},
+ {0x3500, 0x00},
+ {0x3501, 0x08},
+ {0x3502, 0x10},
+ {0x3508, 0x04},
+ {0x3509, 0x00},
+};
+
+static const char * const ov08x40_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+ "Vertical Color Bar Type 2",
+ "Vertical Color Bar Type 3",
+ "Vertical Color Bar Type 4"
+};
+
+/* Configurations for supported link frequencies */
+#define OV08X40_LINK_FREQ_400MHZ 400000000ULL
+
+#define OV08X40_EXT_CLK 19200000
+#define OV08X40_DATA_LANES 4
+
+/*
+ * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
+ * data rate => double data rate; number of lanes => 4; bits per pixel => 10
+ */
+static u64 link_freq_to_pixel_rate(u64 f)
+{
+ f *= 2 * OV08X40_DATA_LANES;
+ do_div(f, 10);
+
+ return f;
+}
+
+/* Menu items for LINK_FREQ V4L2 control */
+static const s64 link_freq_menu_items[] = {
+ OV08X40_LINK_FREQ_400MHZ,
+};
+
+/* Link frequency configs */
+static const struct ov08x40_link_freq_config link_freq_configs[] = {
+ [OV08X40_LINK_FREQ_400MHZ_INDEX] = {
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_800mbps),
+ .regs = mipi_data_rate_800mbps,
+ }
+ },
+};
+
+/* Mode configs */
+static const struct ov08x40_mode supported_modes[] = {
+ {
+ .width = 3856,
+ .height = 2416,
+ .vts_def = OV08X40_VTS_30FPS,
+ .vts_min = OV08X40_VTS_30FPS,
+ .lanes = 4,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3856x2416_regs),
+ .regs = mode_3856x2416_regs,
+ },
+ .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX,
+ },
+ {
+ .width = 1928,
+ .height = 1208,
+ .vts_def = OV08X40_VTS_BIN_30FPS,
+ .vts_min = OV08X40_VTS_BIN_30FPS,
+ .lanes = 4,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1928x1208_regs),
+ .regs = mode_1928x1208_regs,
+ },
+ .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX,
+ },
+};
+
+struct ov08x40 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* V4L2 Controls */
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *exposure;
+
+ /* Current mode */
+ const struct ov08x40_mode *cur_mode;
+
+ /* Mutex for serialized access */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+#define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd)
+
+/* Read registers up to 4 at a time */
+static int ov08x40_read_reg(struct ov08x40 *ov08x,
+ u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ struct i2c_msg msgs[2];
+ u8 *data_be_p;
+ int ret;
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
+
+ if (len > 4)
+ return -EINVAL;
+
+ data_be_p = (u8 *)&data_be;
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+/* Write registers up to 4 at a time */
+static int ov08x40_write_reg(struct ov08x40 *ov08x,
+ u16 reg, u32 len, u32 __val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ int buf_i, val_i;
+ u8 buf[6], *val_p;
+ __be32 val;
+
+ if (len > 4)
+ return -EINVAL;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ val = cpu_to_be32(__val);
+ val_p = (u8 *)&val;
+ buf_i = 2;
+ val_i = 4 - len;
+
+ while (val_i < 4)
+ buf[buf_i++] = val_p[val_i++];
+
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+/* Write a list of registers */
+static int ov08x40_write_regs(struct ov08x40 *ov08x,
+ const struct ov08x40_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ int ret;
+ u32 i;
+
+ for (i = 0; i < len; i++) {
+ ret = ov08x40_write_reg(ov08x, regs[i].address, 1,
+ regs[i].val);
+
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "Failed to write reg 0x%4.4x. error = %d\n",
+ regs[i].address, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ov08x40_write_reg_list(struct ov08x40 *ov08x,
+ const struct ov08x40_reg_list *r_list)
+{
+ return ov08x40_write_regs(ov08x, r_list->regs, r_list->num_of_regs);
+}
+
+static int ov08x40_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ const struct ov08x40_mode *default_mode = &supported_modes[0];
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
+
+ mutex_lock(&ov08x->mutex);
+
+ /* Initialize try_fmt */
+ try_fmt->width = default_mode->width;
+ try_fmt->height = default_mode->height;
+ try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ /* No crop or compose */
+ mutex_unlock(&ov08x->mutex);
+
+ return 0;
+}
+
+static int ov08x40_update_digital_gain(struct ov08x40 *ov08x, u32 d_gain)
+{
+ int ret;
+ u32 val;
+
+ /*
+ * 0x350C[1:0], 0x350B[7:0], 0x350A[4:0]
+ */
+
+ val = (d_gain & OV08X40_DGTL_GAIN_L_MASK) << OV08X40_DGTL_GAIN_L_SHIFT;
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_L,
+ OV08X40_REG_VALUE_08BIT, val);
+ if (ret)
+ return ret;
+
+ val = (d_gain >> OV08X40_DGTL_GAIN_M_SHIFT) & OV08X40_DGTL_GAIN_M_MASK;
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_M,
+ OV08X40_REG_VALUE_08BIT, val);
+ if (ret)
+ return ret;
+
+ val = (d_gain >> OV08X40_DGTL_GAIN_H_SHIFT) & OV08X40_DGTL_GAIN_H_MASK;
+
+ return ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_H,
+ OV08X40_REG_VALUE_08BIT, val);
+}
+
+static int ov08x40_enable_test_pattern(struct ov08x40 *ov08x, u32 pattern)
+{
+ int ret;
+ u32 val;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_TEST_PATTERN,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ if (pattern) {
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_ISP,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_ISP,
+ OV08X40_REG_VALUE_08BIT,
+ val | BIT(1));
+ if (ret)
+ return ret;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_SHORT_TEST_PATTERN,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_SHORT_TEST_PATTERN,
+ OV08X40_REG_VALUE_08BIT,
+ val | BIT(0));
+ if (ret)
+ return ret;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_TEST_PATTERN,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ val &= OV08X40_TEST_PATTERN_MASK;
+ val |= ((pattern - 1) << OV08X40_TEST_PATTERN_BAR_SHIFT) |
+ OV08X40_TEST_PATTERN_ENABLE;
+ } else {
+ val &= ~OV08X40_TEST_PATTERN_ENABLE;
+ }
+
+ return ov08x40_write_reg(ov08x, OV08X40_REG_TEST_PATTERN,
+ OV08X40_REG_VALUE_08BIT, val);
+}
+
+static int ov08x40_set_ctrl_hflip(struct ov08x40 *ov08x, u32 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_MIRROR,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov08x40_write_reg(ov08x, OV08X40_REG_MIRROR,
+ OV08X40_REG_VALUE_08BIT,
+ ctrl_val ? val | BIT(2) : val & ~BIT(2));
+}
+
+static int ov08x40_set_ctrl_vflip(struct ov08x40 *ov08x, u32 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_VFLIP,
+ OV08X40_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov08x40_write_reg(ov08x, OV08X40_REG_VFLIP,
+ OV08X40_REG_VALUE_08BIT,
+ ctrl_val ? val | BIT(2) : val & ~BIT(2));
+}
+
+static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov08x40 *ov08x = container_of(ctrl->handler,
+ struct ov08x40, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ s64 max;
+ int ret = 0;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max = ov08x->cur_mode->height + ctrl->val - OV08X40_EXPOSURE_MAX_MARGIN;
+ __v4l2_ctrl_modify_range(ov08x->exposure,
+ ov08x->exposure->minimum,
+ max, ov08x->exposure->step, max);
+ break;
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_ANALOG_GAIN,
+ OV08X40_REG_VALUE_16BIT,
+ ctrl->val << 1);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = ov08x40_update_digital_gain(ov08x, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_EXPOSURE,
+ OV08X40_REG_VALUE_24BIT,
+ ctrl->val);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_VTS,
+ OV08X40_REG_VALUE_16BIT,
+ ov08x->cur_mode->height
+ + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov08x40_enable_test_pattern(ov08x, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ov08x40_set_ctrl_hflip(ov08x, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ ov08x40_set_ctrl_vflip(ov08x, ctrl->val);
+ break;
+ default:
+ dev_info(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov08x40_ctrl_ops = {
+ .s_ctrl = ov08x40_set_ctrl,
+};
+
+static int ov08x40_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ /* Only one bayer order(GRBG) is supported */
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+ return 0;
+}
+
+static int ov08x40_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static void ov08x40_update_pad_format(const struct ov08x40_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *framefmt;
+ struct v4l2_subdev *sd = &ov08x->sd;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ fmt->format = *framefmt;
+ } else {
+ ov08x40_update_pad_format(ov08x->cur_mode, fmt);
+ }
+
+ return 0;
+}
+
+static int ov08x40_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ int ret;
+
+ mutex_lock(&ov08x->mutex);
+ ret = ov08x40_do_get_pad_format(ov08x, sd_state, fmt);
+ mutex_unlock(&ov08x->mutex);
+
+ return ret;
+}
+
+static int
+ov08x40_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ const struct ov08x40_mode *mode;
+ struct v4l2_mbus_framefmt *framefmt;
+ s32 vblank_def;
+ s32 vblank_min;
+ s64 h_blank;
+ s64 pixel_rate;
+ s64 link_freq;
+
+ mutex_lock(&ov08x->mutex);
+
+ /* Only one raw bayer(GRBG) order is supported */
+ if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10)
+ fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+ ov08x40_update_pad_format(mode, fmt);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ *framefmt = fmt->format;
+ } else {
+ ov08x->cur_mode = mode;
+ __v4l2_ctrl_s_ctrl(ov08x->link_freq, mode->link_freq_index);
+ link_freq = link_freq_menu_items[mode->link_freq_index];
+ pixel_rate = link_freq_to_pixel_rate(link_freq);
+ __v4l2_ctrl_s_ctrl_int64(ov08x->pixel_rate, pixel_rate);
+
+ /* Update limits and set FPS to default */
+ vblank_def = ov08x->cur_mode->vts_def -
+ ov08x->cur_mode->height;
+ vblank_min = ov08x->cur_mode->vts_min -
+ ov08x->cur_mode->height;
+ __v4l2_ctrl_modify_range(ov08x->vblank, vblank_min,
+ OV08X40_VTS_MAX
+ - ov08x->cur_mode->height,
+ 1,
+ vblank_def);
+ __v4l2_ctrl_s_ctrl(ov08x->vblank, vblank_def);
+ h_blank =
+ link_freq_configs[mode->link_freq_index].pixels_per_line
+ - ov08x->cur_mode->width;
+ __v4l2_ctrl_modify_range(ov08x->hblank, h_blank,
+ h_blank, 1, h_blank);
+ }
+
+ mutex_unlock(&ov08x->mutex);
+
+ return 0;
+}
+
+static int ov08x40_start_streaming(struct ov08x40 *ov08x)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ const struct ov08x40_reg_list *reg_list;
+ int ret, link_freq_index;
+
+ /* Get out of from software reset */
+ ret = ov08x40_write_reg(ov08x, OV08X40_REG_SOFTWARE_RST,
+ OV08X40_REG_VALUE_08BIT, OV08X40_SOFTWARE_RST);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set powerup registers\n",
+ __func__);
+ return ret;
+ }
+
+ link_freq_index = ov08x->cur_mode->link_freq_index;
+ reg_list = &link_freq_configs[link_freq_index].reg_list;
+
+ ret = ov08x40_write_reg_list(ov08x, reg_list);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set plls\n", __func__);
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &ov08x->cur_mode->reg_list;
+ ret = ov08x40_write_reg_list(ov08x, reg_list);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ return ret;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(ov08x->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ return ov08x40_write_reg(ov08x, OV08X40_REG_MODE_SELECT,
+ OV08X40_REG_VALUE_08BIT,
+ OV08X40_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static int ov08x40_stop_streaming(struct ov08x40 *ov08x)
+{
+ return ov08x40_write_reg(ov08x, OV08X40_REG_MODE_SELECT,
+ OV08X40_REG_VALUE_08BIT, OV08X40_MODE_STANDBY);
+}
+
+static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&ov08x->mutex);
+ if (ov08x->streaming == enable) {
+ mutex_unlock(&ov08x->mutex);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ goto err_unlock;
+
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = ov08x40_start_streaming(ov08x);
+ if (ret)
+ goto err_rpm_put;
+ } else {
+ ov08x40_stop_streaming(ov08x);
+ pm_runtime_put(&client->dev);
+ }
+
+ ov08x->streaming = enable;
+ mutex_unlock(&ov08x->mutex);
+
+ return ret;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+err_unlock:
+ mutex_unlock(&ov08x->mutex);
+
+ return ret;
+}
+
+static int __maybe_unused ov08x40_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+
+ if (ov08x->streaming)
+ ov08x40_stop_streaming(ov08x);
+
+ return 0;
+}
+
+static int __maybe_unused ov08x40_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ int ret;
+
+ if (ov08x->streaming) {
+ ret = ov08x40_start_streaming(ov08x);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ ov08x40_stop_streaming(ov08x);
+ ov08x->streaming = false;
+ return ret;
+}
+
+/* Verify chip ID */
+static int ov08x40_identify_module(struct ov08x40 *ov08x)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ int ret;
+ u32 val;
+
+ ret = ov08x40_read_reg(ov08x, OV08X40_REG_CHIP_ID,
+ OV08X40_REG_VALUE_24BIT, &val);
+ if (ret)
+ return ret;
+
+ if (val != OV08X40_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ OV08X40_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov08x40_video_ops = {
+ .s_stream = ov08x40_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov08x40_pad_ops = {
+ .enum_mbus_code = ov08x40_enum_mbus_code,
+ .get_fmt = ov08x40_get_pad_format,
+ .set_fmt = ov08x40_set_pad_format,
+ .enum_frame_size = ov08x40_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops ov08x40_subdev_ops = {
+ .video = &ov08x40_video_ops,
+ .pad = &ov08x40_pad_ops,
+};
+
+static const struct media_entity_operations ov08x40_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops ov08x40_internal_ops = {
+ .open = ov08x40_open,
+};
+
+static int ov08x40_init_controls(struct ov08x40 *ov08x)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ s64 exposure_max;
+ s64 vblank_def;
+ s64 vblank_min;
+ s64 hblank;
+ s64 pixel_rate_min;
+ s64 pixel_rate_max;
+ const struct ov08x40_mode *mode;
+ u32 max;
+ int ret;
+
+ ctrl_hdlr = &ov08x->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
+ if (ret)
+ return ret;
+
+ mutex_init(&ov08x->mutex);
+ ctrl_hdlr->lock = &ov08x->mutex;
+ max = ARRAY_SIZE(link_freq_menu_items) - 1;
+ ov08x->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &ov08x40_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ max,
+ 0,
+ link_freq_menu_items);
+ if (ov08x->link_freq)
+ ov08x->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
+ pixel_rate_min = 0;
+ /* By default, PIXEL_RATE is read only */
+ ov08x->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ pixel_rate_min, pixel_rate_max,
+ 1, pixel_rate_max);
+
+ mode = ov08x->cur_mode;
+ vblank_def = mode->vts_def - mode->height;
+ vblank_min = mode->vts_min - mode->height;
+ ov08x->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_VBLANK,
+ vblank_min,
+ OV08X40_VTS_MAX - mode->height, 1,
+ vblank_def);
+
+ hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
+ mode->width;
+ ov08x->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_HBLANK,
+ hblank, hblank, 1, hblank);
+ if (ov08x->hblank)
+ ov08x->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ exposure_max = mode->vts_def - OV08X40_EXPOSURE_MAX_MARGIN;
+ ov08x->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ OV08X40_EXPOSURE_MIN,
+ exposure_max, OV08X40_EXPOSURE_STEP,
+ exposure_max);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ OV08X40_ANA_GAIN_MIN, OV08X40_ANA_GAIN_MAX,
+ OV08X40_ANA_GAIN_STEP, OV08X40_ANA_GAIN_DEFAULT);
+
+ /* Digital gain */
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ OV08X40_DGTL_GAIN_MIN, OV08X40_DGTL_GAIN_MAX,
+ OV08X40_DGTL_GAIN_STEP, OV08X40_DGTL_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov08x40_test_pattern_menu) - 1,
+ 0, 0, ov08x40_test_pattern_menu);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ goto error;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov08x40_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
+
+ ov08x->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ mutex_destroy(&ov08x->mutex);
+
+ return ret;
+}
+
+static void ov08x40_free_controls(struct ov08x40 *ov08x)
+{
+ v4l2_ctrl_handler_free(ov08x->sd.ctrl_handler);
+ mutex_destroy(&ov08x->mutex);
+}
+
+static int ov08x40_check_hwcfg(struct device *dev)
+{
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ unsigned int i, j;
+ int ret;
+ u32 ext_clk;
+
+ if (!fwnode)
+ return -ENXIO;
+
+ ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
+ &ext_clk);
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ return ret;
+ }
+
+ if (ext_clk != OV08X40_EXT_CLK) {
+ dev_err(dev, "external clock %d is not supported",
+ ext_clk);
+ return -EINVAL;
+ }
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return -ENXIO;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return ret;
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV08X40_DATA_LANES) {
+ dev_err(dev, "number of CSI2 data lanes %d is not supported",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ if (!bus_cfg.nr_of_link_frequencies) {
+ dev_err(dev, "no link frequencies defined");
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
+ for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
+ if (link_freq_menu_items[i] ==
+ bus_cfg.link_frequencies[j])
+ break;
+ }
+
+ if (j == bus_cfg.nr_of_link_frequencies) {
+ dev_err(dev, "no link frequency %lld supported",
+ link_freq_menu_items[i]);
+ ret = -EINVAL;
+ goto out_err;
+ }
+ }
+
+out_err:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int ov08x40_probe(struct i2c_client *client)
+{
+ struct ov08x40 *ov08x;
+ int ret;
+
+ /* Check HW config */
+ ret = ov08x40_check_hwcfg(&client->dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to check hwcfg: %d", ret);
+ return ret;
+ }
+
+ ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL);
+ if (!ov08x)
+ return -ENOMEM;
+
+ /* Initialize subdev */
+ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops);
+
+ /* Check module identity */
+ ret = ov08x40_identify_module(ov08x);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d\n", ret);
+ return ret;
+ }
+
+ /* Set default mode to max resolution */
+ ov08x->cur_mode = &supported_modes[0];
+
+ ret = ov08x40_init_controls(ov08x);
+ if (ret)
+ return ret;
+
+ /* Initialize subdev */
+ ov08x->sd.internal_ops = &ov08x40_internal_ops;
+ ov08x->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ov08x->sd.entity.ops = &ov08x40_subdev_entity_ops;
+ ov08x->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ ov08x->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&ov08x->sd.entity, 1, &ov08x->pad);
+ if (ret) {
+ dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&ov08x->sd);
+ if (ret < 0)
+ goto error_media_entity;
+
+ /*
+ * Device is already turned on by i2c-core with ACPI domain PM.
+ * Enable runtime PM and turn off the device.
+ */
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_idle(&client->dev);
+
+ return 0;
+
+error_media_entity:
+ media_entity_cleanup(&ov08x->sd.entity);
+
+error_handler_free:
+ ov08x40_free_controls(ov08x);
+
+ return ret;
+}
+
+static void ov08x40_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ ov08x40_free_controls(ov08x);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct dev_pm_ops ov08x40_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ov08x40_suspend, ov08x40_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ov08x40_acpi_ids[] = {
+ {"OVTI08F4"},
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids);
+#endif
+
+static struct i2c_driver ov08x40_i2c_driver = {
+ .driver = {
+ .name = "ov08x40",
+ .pm = &ov08x40_pm_ops,
+ .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids),
+ },
+ .probe_new = ov08x40_probe,
+ .remove = ov08x40_remove,
+};
+
+module_i2c_driver(ov08x40_i2c_driver);
+
+MODULE_AUTHOR("Jason Chen <jason.z.chen@intel.com>");
+MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
+MODULE_DESCRIPTION("OmniVision OV08X40 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index e618b613e078..69a7a2c590db 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1698,8 +1698,7 @@ static void ov13858_free_controls(struct ov13858 *ov13858)
mutex_destroy(&ov13858->mutex);
}
-static int ov13858_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int ov13858_probe(struct i2c_client *client)
{
struct ov13858 *ov13858;
int ret;
@@ -1807,7 +1806,7 @@ static struct i2c_driver ov13858_i2c_driver = {
.pm = &ov13858_pm_ops,
.acpi_match_table = ACPI_PTR(ov13858_acpi_ids),
},
- .probe = ov13858_probe,
+ .probe_new = ov13858_probe,
.remove = ov13858_remove,
.id_table = ov13858_id_table,
};
diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c
index 29ed0ef8c033..39d56838a4ef 100644
--- a/drivers/media/i2c/ov2640.c
+++ b/drivers/media/i2c/ov2640.c
@@ -16,9 +16,7 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_gpio.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index de66d3395a4d..54153bf66bdd 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -967,6 +967,8 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index 5d74ad479214..f3731f932a94 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -77,7 +77,6 @@
#define OV2740_REG_OTP_CUSTOMER 0x7010
struct nvm_data {
- struct i2c_client *client;
struct nvmem_device *nvmem;
struct regmap *regmap;
char *nvm_buffer;
@@ -379,7 +378,7 @@ static int ov2740_read_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 *val)
struct i2c_msg msgs[2];
u8 addr_buf[2];
u8 data_buf[4] = {0};
- int ret = 0;
+ int ret;
if (len > sizeof(data_buf))
return -EINVAL;
@@ -407,7 +406,7 @@ static int ov2740_write_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
u8 buf[6];
- int ret = 0;
+ int ret;
if (len > 4)
return -EINVAL;
@@ -427,14 +426,14 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740,
{
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
unsigned int i;
- int ret = 0;
+ int ret;
for (i = 0; i < r_list->num_of_regs; i++) {
ret = ov2740_write_reg(ov2740, r_list->regs[i].address, 1,
r_list->regs[i].val);
if (ret) {
dev_err_ratelimited(&client->dev,
- "write reg 0x%4.4x return err = %d",
+ "write reg 0x%4.4x return err = %d\n",
r_list->regs[i].address, ret);
return ret;
}
@@ -457,7 +456,7 @@ static int ov2740_identify_module(struct ov2740 *ov2740)
return ret;
if (val != OV2740_CHIP_ID) {
- dev_err(&client->dev, "chip id mismatch: %x!=%x",
+ dev_err(&client->dev, "chip id mismatch: %x != %x\n",
OV2740_CHIP_ID, val);
return -ENXIO;
}
@@ -469,7 +468,7 @@ static int ov2740_identify_module(struct ov2740 *ov2740)
static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain)
{
- int ret = 0;
+ int ret;
ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1,
OV2740_GROUP_HOLD_START);
@@ -513,7 +512,7 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl)
struct ov2740, ctrl_handler);
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
s64 exposure_max;
- int ret = 0;
+ int ret;
/* Propagate change of current control to all related controls */
if (ctrl->id == V4L2_CID_VBLANK) {
@@ -576,7 +575,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
s64 exposure_max, h_blank, pixel_rate;
u32 vblank_min, vblank_max, vblank_default;
int size;
- int ret = 0;
+ int ret;
ctrl_hdlr = &ov2740->ctrl_handler;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
@@ -649,34 +648,28 @@ static void ov2740_update_pad_format(const struct ov2740_mode *mode,
static int ov2740_load_otp_data(struct nvm_data *nvm)
{
- struct i2c_client *client;
- struct ov2740 *ov2740;
+ struct device *dev = regmap_get_device(nvm->regmap);
+ struct ov2740 *ov2740 = to_ov2740(dev_get_drvdata(dev));
u32 isp_ctrl00 = 0;
u32 isp_ctrl01 = 0;
int ret;
- if (!nvm)
- return -EINVAL;
-
if (nvm->nvm_buffer)
return 0;
- client = nvm->client;
- ov2740 = to_ov2740(i2c_get_clientdata(client));
-
nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
if (!nvm->nvm_buffer)
return -ENOMEM;
ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00);
if (ret) {
- dev_err(&client->dev, "failed to read ISP CTRL00\n");
+ dev_err(dev, "failed to read ISP CTRL00\n");
goto err;
}
ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01);
if (ret) {
- dev_err(&client->dev, "failed to read ISP CTRL01\n");
+ dev_err(dev, "failed to read ISP CTRL01\n");
goto err;
}
@@ -684,7 +677,7 @@ static int ov2740_load_otp_data(struct nvm_data *nvm)
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1,
isp_ctrl00 & ~BIT(5));
if (ret) {
- dev_err(&client->dev, "failed to set ISP CTRL00\n");
+ dev_err(dev, "failed to set ISP CTRL00\n");
goto err;
}
@@ -692,14 +685,14 @@ static int ov2740_load_otp_data(struct nvm_data *nvm)
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1,
isp_ctrl01 & ~BIT(7));
if (ret) {
- dev_err(&client->dev, "failed to set ISP CTRL01\n");
+ dev_err(dev, "failed to set ISP CTRL01\n");
goto err;
}
ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STREAMING);
if (ret) {
- dev_err(&client->dev, "failed to set streaming mode\n");
+ dev_err(dev, "failed to set streaming mode\n");
goto err;
}
@@ -712,26 +705,26 @@ static int ov2740_load_otp_data(struct nvm_data *nvm)
ret = regmap_bulk_read(nvm->regmap, OV2740_REG_OTP_CUSTOMER,
nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE);
if (ret) {
- dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret);
+ dev_err(dev, "failed to read OTP data, ret %d\n", ret);
goto err;
}
ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STANDBY);
if (ret) {
- dev_err(&client->dev, "failed to set streaming mode\n");
+ dev_err(dev, "failed to set streaming mode\n");
goto err;
}
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01);
if (ret) {
- dev_err(&client->dev, "failed to set ISP CTRL01\n");
+ dev_err(dev, "failed to set ISP CTRL01\n");
goto err;
}
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00);
if (ret) {
- dev_err(&client->dev, "failed to set ISP CTRL00\n");
+ dev_err(dev, "failed to set ISP CTRL00\n");
goto err;
}
@@ -746,29 +739,29 @@ err:
static int ov2740_start_streaming(struct ov2740 *ov2740)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
- struct nvm_data *nvm = ov2740->nvm;
const struct ov2740_reg_list *reg_list;
int link_freq_index;
- int ret = 0;
+ int ret;
ret = ov2740_identify_module(ov2740);
if (ret)
return ret;
- ov2740_load_otp_data(nvm);
+ if (ov2740->nvm)
+ ov2740_load_otp_data(ov2740->nvm);
link_freq_index = ov2740->cur_mode->link_freq_index;
reg_list = &link_freq_configs[link_freq_index].reg_list;
ret = ov2740_write_reg_list(ov2740, reg_list);
if (ret) {
- dev_err(&client->dev, "failed to set plls");
+ dev_err(&client->dev, "failed to set plls\n");
return ret;
}
reg_list = &ov2740->cur_mode->reg_list;
ret = ov2740_write_reg_list(ov2740, reg_list);
if (ret) {
- dev_err(&client->dev, "failed to set mode");
+ dev_err(&client->dev, "failed to set mode\n");
return ret;
}
@@ -779,7 +772,7 @@ static int ov2740_start_streaming(struct ov2740 *ov2740)
ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STREAMING);
if (ret)
- dev_err(&client->dev, "failed to start streaming");
+ dev_err(&client->dev, "failed to start streaming\n");
return ret;
}
@@ -790,7 +783,7 @@ static void ov2740_stop_streaming(struct ov2740 *ov2740)
if (ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STANDBY))
- dev_err(&client->dev, "failed to stop streaming");
+ dev_err(&client->dev, "failed to stop streaming\n");
}
static int ov2740_set_stream(struct v4l2_subdev *sd, int enable)
@@ -827,7 +820,7 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
-static int __maybe_unused ov2740_suspend(struct device *dev)
+static int ov2740_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct ov2740 *ov2740 = to_ov2740(sd);
@@ -841,7 +834,7 @@ static int __maybe_unused ov2740_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ov2740_resume(struct device *dev)
+static int ov2740_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct ov2740 *ov2740 = to_ov2740(sd);
@@ -998,17 +991,14 @@ static int ov2740_check_hwcfg(struct device *dev)
int ret;
unsigned int i, j;
- if (!fwnode)
- return -ENXIO;
-
ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
if (ret)
return ret;
- if (mclk != OV2740_MCLK) {
- dev_err(dev, "external clock %d is not supported", mclk);
- return -EINVAL;
- }
+ if (mclk != OV2740_MCLK)
+ return dev_err_probe(dev, -EINVAL,
+ "external clock %d is not supported\n",
+ mclk);
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
@@ -1020,15 +1010,14 @@ static int ov2740_check_hwcfg(struct device *dev)
return ret;
if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV2740_DATA_LANES) {
- dev_err(dev, "number of CSI2 data lanes %d is not supported",
- bus_cfg.bus.mipi_csi2.num_data_lanes);
- ret = -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL,
+ "number of CSI2 data lanes %d is not supported\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
goto check_hwcfg_error;
}
if (!bus_cfg.nr_of_link_frequencies) {
- dev_err(dev, "no link frequencies defined");
- ret = -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL, "no link frequencies defined\n");
goto check_hwcfg_error;
}
@@ -1040,9 +1029,9 @@ static int ov2740_check_hwcfg(struct device *dev)
}
if (j == bus_cfg.nr_of_link_frequencies) {
- dev_err(dev, "no link frequency %lld supported",
- link_freq_menu_items[i]);
- ret = -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL,
+ "no link frequency %lld supported\n",
+ link_freq_menu_items[i]);
goto check_hwcfg_error;
}
}
@@ -1069,9 +1058,8 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
size_t count)
{
struct nvm_data *nvm = priv;
- struct v4l2_subdev *sd = i2c_get_clientdata(nvm->client);
- struct device *dev = &nvm->client->dev;
- struct ov2740 *ov2740 = to_ov2740(sd);
+ struct device *dev = regmap_get_device(nvm->regmap);
+ struct ov2740 *ov2740 = to_ov2740(dev_get_drvdata(dev));
int ret = 0;
mutex_lock(&ov2740->mutex);
@@ -1104,7 +1092,6 @@ static int ov2740_register_nvmem(struct i2c_client *client,
struct nvmem_config nvmem_config = { };
struct regmap *regmap;
struct device *dev = &client->dev;
- int ret;
nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL);
if (!nvm)
@@ -1118,7 +1105,6 @@ static int ov2740_register_nvmem(struct i2c_client *client,
return PTR_ERR(regmap);
nvm->regmap = regmap;
- nvm->client = client;
nvmem_config.name = dev_name(dev);
nvmem_config.dev = dev;
@@ -1135,26 +1121,23 @@ static int ov2740_register_nvmem(struct i2c_client *client,
nvmem_config.size = CUSTOMER_USE_OTP_SIZE;
nvm->nvmem = devm_nvmem_register(dev, &nvmem_config);
+ if (IS_ERR(nvm->nvmem))
+ return PTR_ERR(nvm->nvmem);
- ret = PTR_ERR_OR_ZERO(nvm->nvmem);
- if (!ret)
- ov2740->nvm = nvm;
-
- return ret;
+ ov2740->nvm = nvm;
+ return 0;
}
static int ov2740_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct ov2740 *ov2740;
- int ret = 0;
bool full_power;
+ int ret;
ret = ov2740_check_hwcfg(&client->dev);
- if (ret) {
- dev_err(&client->dev, "failed to check HW configuration: %d",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to check HW configuration\n");
ov2740 = devm_kzalloc(&client->dev, sizeof(*ov2740), GFP_KERNEL);
if (!ov2740)
@@ -1164,17 +1147,15 @@ static int ov2740_probe(struct i2c_client *client)
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
ret = ov2740_identify_module(ov2740);
- if (ret) {
- dev_err(&client->dev, "failed to find sensor: %d", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to find sensor\n");
}
mutex_init(&ov2740->mutex);
ov2740->cur_mode = &supported_modes[0];
ret = ov2740_init_controls(ov2740);
if (ret) {
- dev_err(&client->dev, "failed to init controls: %d", ret);
+ dev_err_probe(dev, ret, "failed to init controls\n");
goto probe_error_v4l2_ctrl_handler_free;
}
@@ -1185,14 +1166,13 @@ static int ov2740_probe(struct i2c_client *client)
ov2740->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&ov2740->sd.entity, 1, &ov2740->pad);
if (ret) {
- dev_err(&client->dev, "failed to init entity pads: %d", ret);
+ dev_err_probe(dev, ret, "failed to init entity pads\n");
goto probe_error_v4l2_ctrl_handler_free;
}
ret = v4l2_async_register_subdev_sensor(&ov2740->sd);
if (ret < 0) {
- dev_err(&client->dev, "failed to register V4L2 subdev: %d",
- ret);
+ dev_err_probe(dev, ret, "failed to register V4L2 subdev\n");
goto probe_error_media_entity_cleanup;
}
@@ -1218,9 +1198,7 @@ probe_error_v4l2_ctrl_handler_free:
return ret;
}
-static const struct dev_pm_ops ov2740_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ov2740_suspend, ov2740_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(ov2740_pm_ops, ov2740_suspend, ov2740_resume);
static const struct acpi_device_id ov2740_acpi_ids[] = {
{"INT3474"},
@@ -1232,7 +1210,7 @@ MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids);
static struct i2c_driver ov2740_i2c_driver = {
.driver = {
.name = "ov2740",
- .pm = &ov2740_pm_ops,
+ .pm = pm_sleep_ptr(&ov2740_pm_ops),
.acpi_match_table = ov2740_acpi_ids,
},
.probe_new = ov2740_probe,
diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c
new file mode 100644
index 000000000000..c602e507d42b
--- /dev/null
+++ b/drivers/media/i2c/ov4689.c
@@ -0,0 +1,1018 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ov4689 driver
+ *
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2022 Mikhail Rudenko
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-fwnode.h>
+
+#define CHIP_ID 0x004688
+#define OV4689_REG_CHIP_ID 0x300a
+
+#define OV4689_XVCLK_FREQ 24000000
+
+#define OV4689_REG_CTRL_MODE 0x0100
+#define OV4689_MODE_SW_STANDBY 0x0
+#define OV4689_MODE_STREAMING BIT(0)
+
+#define OV4689_REG_EXPOSURE 0x3500
+#define OV4689_EXPOSURE_MIN 4
+#define OV4689_EXPOSURE_STEP 1
+#define OV4689_VTS_MAX 0x7fff
+
+#define OV4689_REG_GAIN_H 0x3508
+#define OV4689_REG_GAIN_L 0x3509
+#define OV4689_GAIN_H_MASK 0x07
+#define OV4689_GAIN_H_SHIFT 8
+#define OV4689_GAIN_L_MASK 0xff
+#define OV4689_GAIN_STEP 1
+#define OV4689_GAIN_DEFAULT 0x80
+
+#define OV4689_REG_TEST_PATTERN 0x5040
+#define OV4689_TEST_PATTERN_ENABLE 0x80
+#define OV4689_TEST_PATTERN_DISABLE 0x0
+
+#define OV4689_REG_VTS 0x380e
+
+#define REG_NULL 0xFFFF
+
+#define OV4689_REG_VALUE_08BIT 1
+#define OV4689_REG_VALUE_16BIT 2
+#define OV4689_REG_VALUE_24BIT 3
+
+#define OV4689_LANES 4
+
+static const char *const ov4689_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+struct regval {
+ u16 addr;
+ u8 val;
+};
+
+enum ov4689_mode_id {
+ OV4689_MODE_2688_1520 = 0,
+ OV4689_NUM_MODES,
+};
+
+struct ov4689_mode {
+ enum ov4689_mode_id id;
+ u32 width;
+ u32 height;
+ u32 max_fps;
+ u32 hts_def;
+ u32 vts_def;
+ u32 exp_def;
+ u32 pixel_rate;
+ u32 sensor_width;
+ u32 sensor_height;
+ u32 crop_top;
+ u32 crop_left;
+ const struct regval *reg_list;
+};
+
+struct ov4689 {
+ struct i2c_client *client;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *pwdn_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ov4689_supply_names)];
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ u32 clock_rate;
+
+ struct mutex mutex; /* lock to protect streaming, ctrls and cur_mode */
+ bool streaming;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+
+ const struct ov4689_mode *cur_mode;
+};
+
+#define to_ov4689(sd) container_of(sd, struct ov4689, subdev)
+
+struct ov4689_gain_range {
+ u32 logical_min;
+ u32 logical_max;
+ u32 offset;
+ u32 divider;
+ u32 physical_min;
+ u32 physical_max;
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 30fps
+ * mipi_datarate per lane 1008Mbps
+ */
+static const struct regval ov4689_2688x1520_regs[] = {
+ {0x0103, 0x01}, {0x3638, 0x00}, {0x0300, 0x00},
+ {0x0302, 0x2a}, {0x0303, 0x00}, {0x0304, 0x03},
+ {0x030b, 0x00}, {0x030d, 0x1e}, {0x030e, 0x04},
+ {0x030f, 0x01}, {0x0312, 0x01}, {0x031e, 0x00},
+ {0x3000, 0x20}, {0x3002, 0x00}, {0x3018, 0x72},
+ {0x3020, 0x93}, {0x3021, 0x03}, {0x3022, 0x01},
+ {0x3031, 0x0a}, {0x303f, 0x0c}, {0x3305, 0xf1},
+ {0x3307, 0x04}, {0x3309, 0x29}, {0x3500, 0x00},
+ {0x3501, 0x60}, {0x3502, 0x00}, {0x3503, 0x04},
+ {0x3504, 0x00}, {0x3505, 0x00}, {0x3506, 0x00},
+ {0x3507, 0x00}, {0x3508, 0x00}, {0x3509, 0x80},
+ {0x350a, 0x00}, {0x350b, 0x00}, {0x350c, 0x00},
+ {0x350d, 0x00}, {0x350e, 0x00}, {0x350f, 0x80},
+ {0x3510, 0x00}, {0x3511, 0x00}, {0x3512, 0x00},
+ {0x3513, 0x00}, {0x3514, 0x00}, {0x3515, 0x80},
+ {0x3516, 0x00}, {0x3517, 0x00}, {0x3518, 0x00},
+ {0x3519, 0x00}, {0x351a, 0x00}, {0x351b, 0x80},
+ {0x351c, 0x00}, {0x351d, 0x00}, {0x351e, 0x00},
+ {0x351f, 0x00}, {0x3520, 0x00}, {0x3521, 0x80},
+ {0x3522, 0x08}, {0x3524, 0x08}, {0x3526, 0x08},
+ {0x3528, 0x08}, {0x352a, 0x08}, {0x3602, 0x00},
+ {0x3603, 0x40}, {0x3604, 0x02}, {0x3605, 0x00},
+ {0x3606, 0x00}, {0x3607, 0x00}, {0x3609, 0x12},
+ {0x360a, 0x40}, {0x360c, 0x08}, {0x360f, 0xe5},
+ {0x3608, 0x8f}, {0x3611, 0x00}, {0x3613, 0xf7},
+ {0x3616, 0x58}, {0x3619, 0x99}, {0x361b, 0x60},
+ {0x361c, 0x7a}, {0x361e, 0x79}, {0x361f, 0x02},
+ {0x3632, 0x00}, {0x3633, 0x10}, {0x3634, 0x10},
+ {0x3635, 0x10}, {0x3636, 0x15}, {0x3646, 0x86},
+ {0x364a, 0x0b}, {0x3700, 0x17}, {0x3701, 0x22},
+ {0x3703, 0x10}, {0x370a, 0x37}, {0x3705, 0x00},
+ {0x3706, 0x63}, {0x3709, 0x3c}, {0x370b, 0x01},
+ {0x370c, 0x30}, {0x3710, 0x24}, {0x3711, 0x0c},
+ {0x3716, 0x00}, {0x3720, 0x28}, {0x3729, 0x7b},
+ {0x372a, 0x84}, {0x372b, 0xbd}, {0x372c, 0xbc},
+ {0x372e, 0x52}, {0x373c, 0x0e}, {0x373e, 0x33},
+ {0x3743, 0x10}, {0x3744, 0x88}, {0x3745, 0xc0},
+ {0x374a, 0x43}, {0x374c, 0x00}, {0x374e, 0x23},
+ {0x3751, 0x7b}, {0x3752, 0x84}, {0x3753, 0xbd},
+ {0x3754, 0xbc}, {0x3756, 0x52}, {0x375c, 0x00},
+ {0x3760, 0x00}, {0x3761, 0x00}, {0x3762, 0x00},
+ {0x3763, 0x00}, {0x3764, 0x00}, {0x3767, 0x04},
+ {0x3768, 0x04}, {0x3769, 0x08}, {0x376a, 0x08},
+ {0x376b, 0x20}, {0x376c, 0x00}, {0x376d, 0x00},
+ {0x376e, 0x00}, {0x3773, 0x00}, {0x3774, 0x51},
+ {0x3776, 0xbd}, {0x3777, 0xbd}, {0x3781, 0x18},
+ {0x3783, 0x25}, {0x3798, 0x1b}, {0x3800, 0x00},
+ {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x04},
+ {0x3804, 0x0a}, {0x3805, 0x97}, {0x3806, 0x05},
+ {0x3807, 0xfb}, {0x3808, 0x0a}, {0x3809, 0x80},
+ {0x380a, 0x05}, {0x380b, 0xf0}, {0x380c, 0x0a},
+ {0x380d, 0x0e}, {0x380e, 0x06}, {0x380f, 0x12},
+ {0x3810, 0x00}, {0x3811, 0x08}, {0x3812, 0x00},
+ {0x3813, 0x04}, {0x3814, 0x01}, {0x3815, 0x01},
+ {0x3819, 0x01}, {0x3820, 0x00}, {0x3821, 0x06},
+ {0x3829, 0x00}, {0x382a, 0x01}, {0x382b, 0x01},
+ {0x382d, 0x7f}, {0x3830, 0x04}, {0x3836, 0x01},
+ {0x3837, 0x00}, {0x3841, 0x02}, {0x3846, 0x08},
+ {0x3847, 0x07}, {0x3d85, 0x36}, {0x3d8c, 0x71},
+ {0x3d8d, 0xcb}, {0x3f0a, 0x00}, {0x4000, 0xf1},
+ {0x4001, 0x40}, {0x4002, 0x04}, {0x4003, 0x14},
+ {0x400e, 0x00}, {0x4011, 0x00}, {0x401a, 0x00},
+ {0x401b, 0x00}, {0x401c, 0x00}, {0x401d, 0x00},
+ {0x401f, 0x00}, {0x4020, 0x00}, {0x4021, 0x10},
+ {0x4022, 0x07}, {0x4023, 0xcf}, {0x4024, 0x09},
+ {0x4025, 0x60}, {0x4026, 0x09}, {0x4027, 0x6f},
+ {0x4028, 0x00}, {0x4029, 0x02}, {0x402a, 0x06},
+ {0x402b, 0x04}, {0x402c, 0x02}, {0x402d, 0x02},
+ {0x402e, 0x0e}, {0x402f, 0x04}, {0x4302, 0xff},
+ {0x4303, 0xff}, {0x4304, 0x00}, {0x4305, 0x00},
+ {0x4306, 0x00}, {0x4308, 0x02}, {0x4500, 0x6c},
+ {0x4501, 0xc4}, {0x4502, 0x40}, {0x4503, 0x01},
+ {0x4601, 0xa7}, {0x4800, 0x04}, {0x4813, 0x08},
+ {0x481f, 0x40}, {0x4829, 0x78}, {0x4837, 0x10},
+ {0x4b00, 0x2a}, {0x4b0d, 0x00}, {0x4d00, 0x04},
+ {0x4d01, 0x42}, {0x4d02, 0xd1}, {0x4d03, 0x93},
+ {0x4d04, 0xf5}, {0x4d05, 0xc1}, {0x5000, 0xf3},
+ {0x5001, 0x11}, {0x5004, 0x00}, {0x500a, 0x00},
+ {0x500b, 0x00}, {0x5032, 0x00}, {0x5040, 0x00},
+ {0x5050, 0x0c}, {0x5500, 0x00}, {0x5501, 0x10},
+ {0x5502, 0x01}, {0x5503, 0x0f}, {0x8000, 0x00},
+ {0x8001, 0x00}, {0x8002, 0x00}, {0x8003, 0x00},
+ {0x8004, 0x00}, {0x8005, 0x00}, {0x8006, 0x00},
+ {0x8007, 0x00}, {0x8008, 0x00}, {0x3638, 0x00},
+ {REG_NULL, 0x00},
+};
+
+static const struct ov4689_mode supported_modes[] = {
+ {
+ .id = OV4689_MODE_2688_1520,
+ .width = 2688,
+ .height = 1520,
+ .sensor_width = 2720,
+ .sensor_height = 1536,
+ .crop_top = 8,
+ .crop_left = 16,
+ .max_fps = 30,
+ .exp_def = 1536,
+ .hts_def = 4 * 2574,
+ .vts_def = 1554,
+ .pixel_rate = 480000000,
+ .reg_list = ov4689_2688x1520_regs,
+ },
+};
+
+static const u64 link_freq_menu_items[] = { 504000000 };
+
+static const char *const ov4689_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+ "Vertical Color Bar Type 2",
+ "Vertical Color Bar Type 3",
+ "Vertical Color Bar Type 4"
+};
+
+/*
+ * These coefficients are based on those used in Rockchip's camera
+ * engine, with minor tweaks for continuity.
+ */
+static const struct ov4689_gain_range ov4689_gain_ranges[] = {
+ {
+ .logical_min = 0,
+ .logical_max = 255,
+ .offset = 0,
+ .divider = 1,
+ .physical_min = 0,
+ .physical_max = 255,
+ },
+ {
+ .logical_min = 256,
+ .logical_max = 511,
+ .offset = 252,
+ .divider = 2,
+ .physical_min = 376,
+ .physical_max = 504,
+ },
+ {
+ .logical_min = 512,
+ .logical_max = 1023,
+ .offset = 758,
+ .divider = 4,
+ .physical_min = 884,
+ .physical_max = 1012,
+ },
+ {
+ .logical_min = 1024,
+ .logical_max = 2047,
+ .offset = 1788,
+ .divider = 8,
+ .physical_min = 1912,
+ .physical_max = 2047,
+ },
+};
+
+/* Write registers up to 4 at a time */
+static int ov4689_write_reg(struct i2c_client *client, u16 reg, u32 len,
+ u32 val)
+{
+ u32 buf_i, val_i;
+ __be32 val_be;
+ u8 *val_p;
+ u8 buf[6];
+
+ if (len > 4)
+ return -EINVAL;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ val_be = cpu_to_be32(val);
+ val_p = (u8 *)&val_be;
+ buf_i = 2;
+ val_i = 4 - len;
+
+ while (val_i < 4)
+ buf[buf_i++] = val_p[val_i++];
+
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int ov4689_write_array(struct i2c_client *client,
+ const struct regval *regs)
+{
+ int ret = 0;
+ u32 i;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+ ret = ov4689_write_reg(client, regs[i].addr,
+ OV4689_REG_VALUE_08BIT, regs[i].val);
+
+ return ret;
+}
+
+/* Read registers up to 4 at a time */
+static int ov4689_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
+ u32 *val)
+{
+ __be16 reg_addr_be = cpu_to_be16(reg);
+ struct i2c_msg msgs[2];
+ __be32 data_be = 0;
+ u8 *data_be_p;
+ int ret;
+
+ if (len > 4 || !len)
+ return -EINVAL;
+
+ data_be_p = (u8 *)&data_be;
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+static void ov4689_fill_fmt(const struct ov4689_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int ov4689_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+ struct ov4689 *ov4689 = to_ov4689(sd);
+
+ /* only one mode supported for now */
+ ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt);
+
+ return 0;
+}
+
+static int ov4689_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+ struct ov4689 *ov4689 = to_ov4689(sd);
+
+ /* only one mode supported for now */
+ ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt);
+
+ return 0;
+}
+
+static int ov4689_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov4689_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = supported_modes[fse->index].width;
+ fse->max_height = supported_modes[fse->index].height;
+ fse->min_height = supported_modes[fse->index].height;
+
+ return 0;
+}
+
+static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern)
+{
+ u32 val;
+
+ if (pattern)
+ val = (pattern - 1) | OV4689_TEST_PATTERN_ENABLE;
+ else
+ val = OV4689_TEST_PATTERN_DISABLE;
+
+ return ov4689_write_reg(ov4689->client, OV4689_REG_TEST_PATTERN,
+ OV4689_REG_VALUE_08BIT, val);
+}
+
+static int ov4689_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ const struct ov4689_mode *mode = to_ov4689(sd)->cur_mode;
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = mode->sensor_width;
+ sel->r.height = mode->sensor_height;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = mode->crop_top;
+ sel->r.left = mode->crop_left;
+ sel->r.width = mode->width;
+ sel->r.height = mode->height;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int ov4689_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct ov4689 *ov4689 = to_ov4689(sd);
+ struct i2c_client *client = ov4689->client;
+ int ret = 0;
+
+ mutex_lock(&ov4689->mutex);
+
+ on = !!on;
+ if (on == ov4689->streaming)
+ goto unlock_and_return;
+
+ if (on) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ goto unlock_and_return;
+
+ ret = ov4689_write_array(ov4689->client,
+ ov4689->cur_mode->reg_list);
+ if (ret) {
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+
+ ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler);
+ if (ret) {
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+
+ ret = ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,
+ OV4689_REG_VALUE_08BIT,
+ OV4689_MODE_STREAMING);
+ if (ret) {
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,
+ OV4689_REG_VALUE_08BIT,
+ OV4689_MODE_SW_STANDBY);
+ pm_runtime_put(&client->dev);
+ }
+
+ ov4689->streaming = on;
+
+unlock_and_return:
+ mutex_unlock(&ov4689->mutex);
+
+ return ret;
+}
+
+/* Calculate the delay in us by clock rate and clock cycles */
+static inline u32 ov4689_cal_delay(struct ov4689 *ov4689, u32 cycles)
+{
+ return DIV_ROUND_UP(cycles * 1000,
+ DIV_ROUND_UP(ov4689->clock_rate, 1000));
+}
+
+static int __maybe_unused ov4689_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov4689 *ov4689 = to_ov4689(sd);
+ u32 delay_us;
+ int ret;
+
+ ret = clk_prepare_enable(ov4689->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov4689->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ov4689_supply_names),
+ ov4689->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ gpiod_set_value_cansleep(ov4689->reset_gpio, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(ov4689->pwdn_gpio, 0);
+
+ /* 8192 cycles prior to first SCCB transaction */
+ delay_us = ov4689_cal_delay(ov4689, 8192);
+ usleep_range(delay_us, delay_us * 2);
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(ov4689->xvclk);
+
+ return ret;
+}
+
+static int __maybe_unused ov4689_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov4689 *ov4689 = to_ov4689(sd);
+
+ gpiod_set_value_cansleep(ov4689->pwdn_gpio, 1);
+ clk_disable_unprepare(ov4689->xvclk);
+ gpiod_set_value_cansleep(ov4689->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ov4689_supply_names),
+ ov4689->supplies);
+ return 0;
+}
+
+static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct ov4689 *ov4689 = to_ov4689(sd);
+ struct v4l2_mbus_framefmt *try_fmt;
+
+ mutex_lock(&ov4689->mutex);
+
+ try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
+ /* Initialize try_fmt */
+ ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt);
+
+ mutex_unlock(&ov4689->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ov4689_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL)
+};
+
+static const struct v4l2_subdev_internal_ops ov4689_internal_ops = {
+ .open = ov4689_open,
+};
+
+static const struct v4l2_subdev_video_ops ov4689_video_ops = {
+ .s_stream = ov4689_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {
+ .enum_mbus_code = ov4689_enum_mbus_code,
+ .enum_frame_size = ov4689_enum_frame_sizes,
+ .get_fmt = ov4689_get_fmt,
+ .set_fmt = ov4689_set_fmt,
+ .get_selection = ov4689_get_selection,
+};
+
+static const struct v4l2_subdev_ops ov4689_subdev_ops = {
+ .video = &ov4689_video_ops,
+ .pad = &ov4689_pad_ops,
+};
+
+/*
+ * Map userspace (logical) gain to sensor (physical) gain using
+ * ov4689_gain_ranges table.
+ */
+static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result)
+{
+ const struct device *dev = &ov4689->client->dev;
+ const struct ov4689_gain_range *range;
+ unsigned int n;
+
+ for (n = 0; n < ARRAY_SIZE(ov4689_gain_ranges); n++) {
+ if (logical_gain >= ov4689_gain_ranges[n].logical_min &&
+ logical_gain <= ov4689_gain_ranges[n].logical_max)
+ break;
+ }
+
+ if (n == ARRAY_SIZE(ov4689_gain_ranges)) {
+ dev_warn_ratelimited(dev, "no mapping found for gain %d\n",
+ logical_gain);
+ return -EINVAL;
+ }
+
+ range = &ov4689_gain_ranges[n];
+
+ *result = clamp(range->offset + (logical_gain) / range->divider,
+ range->physical_min, range->physical_max);
+ return 0;
+}
+
+static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov4689 *ov4689 =
+ container_of(ctrl->handler, struct ov4689, ctrl_handler);
+ struct i2c_client *client = ov4689->client;
+ int sensor_gain;
+ s64 max_expo;
+ int ret;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max_expo = ov4689->cur_mode->height + ctrl->val - 4;
+ __v4l2_ctrl_modify_range(ov4689->exposure,
+ ov4689->exposure->minimum, max_expo,
+ ov4689->exposure->step,
+ ov4689->exposure->default_value);
+ break;
+ }
+
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* 4 least significant bits of expsoure are fractional part */
+ ret = ov4689_write_reg(ov4689->client, OV4689_REG_EXPOSURE,
+ OV4689_REG_VALUE_24BIT, ctrl->val << 4);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain);
+
+ ret = ret ?:
+ ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_H,
+ OV4689_REG_VALUE_08BIT,
+ (sensor_gain >> OV4689_GAIN_H_SHIFT) &
+ OV4689_GAIN_H_MASK);
+ ret = ret ?:
+ ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_L,
+ OV4689_REG_VALUE_08BIT,
+ sensor_gain & OV4689_GAIN_L_MASK);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov4689_write_reg(ov4689->client, OV4689_REG_VTS,
+ OV4689_REG_VALUE_16BIT,
+ ctrl->val + ov4689->cur_mode->height);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov4689_enable_test_pattern(ov4689, ctrl->val);
+ break;
+ default:
+ dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+ __func__, ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov4689_ctrl_ops = {
+ .s_ctrl = ov4689_set_ctrl,
+};
+
+static int ov4689_initialize_controls(struct ov4689 *ov4689)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov4689->subdev);
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *handler;
+ const struct ov4689_mode *mode;
+ s64 exposure_max, vblank_def;
+ struct v4l2_ctrl *ctrl;
+ s64 h_blank_def;
+ int ret;
+
+ handler = &ov4689->ctrl_handler;
+ mode = ov4689->cur_mode;
+ ret = v4l2_ctrl_handler_init(handler, 10);
+ if (ret)
+ return ret;
+ handler->lock = &ov4689->mutex;
+
+ ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0,
+ link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0,
+ mode->pixel_rate, 1, mode->pixel_rate);
+
+ h_blank_def = mode->hts_def - mode->width;
+ ctrl = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank_def,
+ h_blank_def, 1, h_blank_def);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank_def = mode->vts_def - mode->height;
+ v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK,
+ vblank_def, OV4689_VTS_MAX - mode->height, 1,
+ vblank_def);
+
+ exposure_max = mode->vts_def - 4;
+ ov4689->exposure =
+ v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_EXPOSURE,
+ OV4689_EXPOSURE_MIN, exposure_max,
+ OV4689_EXPOSURE_STEP, mode->exp_def);
+
+ v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ ov4689_gain_ranges[0].logical_min,
+ ov4689_gain_ranges[ARRAY_SIZE(ov4689_gain_ranges) - 1]
+ .logical_max,
+ OV4689_GAIN_STEP, OV4689_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(handler, &ov4689_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov4689_test_pattern_menu) - 1,
+ 0, 0, ov4689_test_pattern_menu);
+
+ if (handler->error) {
+ ret = handler->error;
+ dev_err(&ov4689->client->dev, "Failed to init controls(%d)\n",
+ ret);
+ goto err_free_handler;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto err_free_handler;
+
+ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov4689_ctrl_ops,
+ &props);
+ if (ret)
+ goto err_free_handler;
+
+ ov4689->subdev.ctrl_handler = handler;
+
+ return 0;
+
+err_free_handler:
+ v4l2_ctrl_handler_free(handler);
+
+ return ret;
+}
+
+static int ov4689_check_sensor_id(struct ov4689 *ov4689,
+ struct i2c_client *client)
+{
+ struct device *dev = &ov4689->client->dev;
+ u32 id = 0;
+ int ret;
+
+ ret = ov4689_read_reg(client, OV4689_REG_CHIP_ID,
+ OV4689_REG_VALUE_16BIT, &id);
+ if (ret) {
+ dev_err(dev, "Cannot read sensor ID\n");
+ return ret;
+ }
+
+ if (id != CHIP_ID) {
+ dev_err(dev, "Unexpected sensor ID %06x, expected %06x\n",
+ id, CHIP_ID);
+ return -ENODEV;
+ }
+
+ dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
+
+ return 0;
+}
+
+static int ov4689_configure_regulators(struct ov4689 *ov4689)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++)
+ ov4689->supplies[i].supply = ov4689_supply_names[i];
+
+ return devm_regulator_bulk_get(&ov4689->client->dev,
+ ARRAY_SIZE(ov4689_supply_names),
+ ov4689->supplies);
+}
+
+static u64 ov4689_check_link_frequency(struct v4l2_fwnode_endpoint *ep)
+{
+ const u64 *freqs = link_freq_menu_items;
+ unsigned int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
+ for (j = 0; j < ep->nr_of_link_frequencies; j++)
+ if (freqs[i] == ep->link_frequencies[j])
+ return freqs[i];
+ }
+
+ return 0;
+}
+
+static int ov4689_check_hwcfg(struct device *dev)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *endpoint;
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!endpoint)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
+ fwnode_handle_put(endpoint);
+ if (ret)
+ return ret;
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV4689_LANES) {
+ dev_err(dev, "Only a 4-lane CSI2 config is supported");
+ ret = -EINVAL;
+ goto out_free_bus_cfg;
+ }
+
+ if (!ov4689_check_link_frequency(&bus_cfg)) {
+ dev_err(dev, "No supported link frequency found\n");
+ ret = -EINVAL;
+ }
+
+out_free_bus_cfg:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int ov4689_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd;
+ struct ov4689 *ov4689;
+ int ret;
+
+ ret = ov4689_check_hwcfg(dev);
+ if (ret)
+ return ret;
+
+ ov4689 = devm_kzalloc(dev, sizeof(*ov4689), GFP_KERNEL);
+ if (!ov4689)
+ return -ENOMEM;
+
+ ov4689->client = client;
+ ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520];
+
+ ov4689->xvclk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(ov4689->xvclk))
+ return dev_err_probe(dev, PTR_ERR(ov4689->xvclk),
+ "Failed to get external clock\n");
+
+ if (!ov4689->xvclk) {
+ dev_dbg(dev,
+ "No clock provided, using clock-frequency property\n");
+ device_property_read_u32(dev, "clock-frequency",
+ &ov4689->clock_rate);
+ } else {
+ ov4689->clock_rate = clk_get_rate(ov4689->xvclk);
+ }
+
+ if (ov4689->clock_rate != OV4689_XVCLK_FREQ) {
+ dev_err(dev,
+ "External clock rate mismatch: got %d Hz, expected %d Hz\n",
+ ov4689->clock_rate, OV4689_XVCLK_FREQ);
+ return -EINVAL;
+ }
+
+ ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov4689->reset_gpio)) {
+ dev_err(dev, "Failed to get reset-gpios\n");
+ return PTR_ERR(ov4689->reset_gpio);
+ }
+
+ ov4689->pwdn_gpio = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_LOW);
+ if (IS_ERR(ov4689->pwdn_gpio)) {
+ dev_err(dev, "Failed to get pwdn-gpios\n");
+ return PTR_ERR(ov4689->pwdn_gpio);
+ }
+
+ ret = ov4689_configure_regulators(ov4689);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get power regulators\n");
+
+ mutex_init(&ov4689->mutex);
+
+ sd = &ov4689->subdev;
+ v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops);
+ ret = ov4689_initialize_controls(ov4689);
+ if (ret)
+ goto err_destroy_mutex;
+
+ ret = ov4689_power_on(dev);
+ if (ret)
+ goto err_free_handler;
+
+ ret = ov4689_check_sensor_id(ov4689, client);
+ if (ret)
+ goto err_power_off;
+
+ sd->internal_ops = &ov4689_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad);
+ if (ret < 0)
+ goto err_power_off;
+
+ ret = v4l2_async_register_subdev_sensor(sd);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_clean_entity;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+err_clean_entity:
+ media_entity_cleanup(&sd->entity);
+err_power_off:
+ ov4689_power_off(dev);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
+err_destroy_mutex:
+ mutex_destroy(&ov4689->mutex);
+
+ return ret;
+}
+
+static void ov4689_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov4689 *ov4689 = to_ov4689(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+
+ v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
+ mutex_destroy(&ov4689->mutex);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov4689_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id ov4689_of_match[] = {
+ { .compatible = "ovti,ov4689" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ov4689_of_match);
+
+static struct i2c_driver ov4689_i2c_driver = {
+ .driver = {
+ .name = "ov4689",
+ .pm = &ov4689_pm_ops,
+ .of_match_table = ov4689_of_match,
+ },
+ .probe_new = ov4689_probe,
+ .remove = ov4689_remove,
+};
+
+module_i2c_driver(ov4689_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision ov4689 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 2d740397a5d4..e0f908af581b 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -2715,20 +2715,20 @@ static int ov5640_sensor_resume(struct device *dev)
static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
struct v4l2_fract *fi,
- u32 width, u32 height)
+ const struct ov5640_mode_info *mode_info)
{
- const struct ov5640_mode_info *mode;
+ const struct ov5640_mode_info *mode = mode_info;
enum ov5640_frame_rate rate = OV5640_15_FPS;
int minfps, maxfps, best_fps, fps;
int i;
minfps = ov5640_framerates[OV5640_15_FPS];
- maxfps = ov5640_framerates[OV5640_60_FPS];
+ maxfps = ov5640_framerates[mode->max_fps];
if (fi->numerator == 0) {
fi->denominator = maxfps;
fi->numerator = 1;
- rate = OV5640_60_FPS;
+ rate = mode->max_fps;
goto find_mode;
}
@@ -2749,7 +2749,7 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
fi->denominator = best_fps;
find_mode:
- mode = ov5640_find_mode(sensor, width, height, false);
+ mode = ov5640_find_mode(sensor, mode->width, mode->height, false);
return mode ? rate : -EINVAL;
}
@@ -3554,6 +3554,7 @@ static int ov5640_enum_frame_interval(
struct v4l2_subdev_frame_interval_enum *fie)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ const struct ov5640_mode_info *mode;
struct v4l2_fract tpf;
int ret;
@@ -3562,11 +3563,14 @@ static int ov5640_enum_frame_interval(
if (fie->index >= OV5640_NUM_FRAMERATES)
return -EINVAL;
+ mode = ov5640_find_mode(sensor, fie->width, fie->height, false);
+ if (!mode)
+ return -EINVAL;
+
tpf.numerator = 1;
tpf.denominator = ov5640_framerates[fie->index];
- ret = ov5640_try_frame_interval(sensor, &tpf,
- fie->width, fie->height);
+ ret = ov5640_try_frame_interval(sensor, &tpf, mode);
if (ret < 0)
return -EINVAL;
@@ -3605,9 +3609,7 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
mode = sensor->current_mode;
- frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
- mode->width,
- mode->height);
+ frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode);
if (frame_rate < 0) {
/* Always return a valid frame interval value */
fi->interval = sensor->frame_interval;
@@ -3817,7 +3819,8 @@ static int ov5640_probe(struct i2c_client *client)
sensor->current_mode =
&ov5640_mode_data[OV5640_MODE_VGA_640_480];
sensor->last_mode = sensor->current_mode;
- sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
+ sensor->current_link_freq =
+ ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ];
sensor->ae_target = 52;
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index 81e4e87e1821..c8999fc4f26f 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -14,9 +14,6 @@
* https://www.mail-archive.com/linux-media%40vger.kernel.org/msg92671.html
*/
-/*
- */
-
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -27,6 +24,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -108,7 +106,6 @@ struct ov5645 {
u8 timing_tc_reg21;
struct mutex power_lock; /* lock to protect power state */
- int power_count;
struct gpio_desc *enable_gpio;
struct gpio_desc *rst_gpio;
@@ -635,8 +632,24 @@ static int ov5645_set_register_array(struct ov5645 *ov5645,
return 0;
}
-static int ov5645_set_power_on(struct ov5645 *ov5645)
+static int ov5645_set_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5645 *ov5645 = to_ov5645(sd);
+
+ ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x58);
+ gpiod_set_value_cansleep(ov5645->rst_gpio, 1);
+ gpiod_set_value_cansleep(ov5645->enable_gpio, 0);
+ clk_disable_unprepare(ov5645->xclk);
+ regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies);
+
+ return 0;
+}
+
+static int ov5645_set_power_on(struct device *dev)
{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5645 *ov5645 = to_ov5645(sd);
int ret;
ret = regulator_bulk_enable(OV5645_NUM_SUPPLIES, ov5645->supplies);
@@ -658,57 +671,19 @@ static int ov5645_set_power_on(struct ov5645 *ov5645)
msleep(20);
- return 0;
-}
-
-static void ov5645_set_power_off(struct ov5645 *ov5645)
-{
- gpiod_set_value_cansleep(ov5645->rst_gpio, 1);
- gpiod_set_value_cansleep(ov5645->enable_gpio, 0);
- clk_disable_unprepare(ov5645->xclk);
- regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies);
-}
-
-static int ov5645_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ov5645 *ov5645 = to_ov5645(sd);
- int ret = 0;
-
- mutex_lock(&ov5645->power_lock);
-
- /* If the power count is modified from 0 to != 0 or from != 0 to 0,
- * update the power state.
- */
- if (ov5645->power_count == !on) {
- if (on) {
- ret = ov5645_set_power_on(ov5645);
- if (ret < 0)
- goto exit;
-
- ret = ov5645_set_register_array(ov5645,
- ov5645_global_init_setting,
+ ret = ov5645_set_register_array(ov5645, ov5645_global_init_setting,
ARRAY_SIZE(ov5645_global_init_setting));
- if (ret < 0) {
- dev_err(ov5645->dev,
- "could not set init registers\n");
- ov5645_set_power_off(ov5645);
- goto exit;
- }
-
- usleep_range(500, 1000);
- } else {
- ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x58);
- ov5645_set_power_off(ov5645);
- }
+ if (ret < 0) {
+ dev_err(ov5645->dev, "could not set init registers\n");
+ goto exit;
}
- /* Update the power count. */
- ov5645->power_count += on ? 1 : -1;
- WARN_ON(ov5645->power_count < 0);
+ usleep_range(500, 1000);
-exit:
- mutex_unlock(&ov5645->power_lock);
+ return 0;
+exit:
+ ov5645_set_power_off(dev);
return ret;
}
@@ -795,7 +770,7 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
int ret;
mutex_lock(&ov5645->power_lock);
- if (!ov5645->power_count) {
+ if (!pm_runtime_get_if_in_use(ov5645->dev)) {
mutex_unlock(&ov5645->power_lock);
return 0;
}
@@ -827,6 +802,8 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
+ pm_runtime_mark_last_busy(ov5645->dev);
+ pm_runtime_put_autosuspend(ov5645->dev);
mutex_unlock(&ov5645->power_lock);
return ret;
@@ -991,6 +968,10 @@ static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable)
int ret;
if (enable) {
+ ret = pm_runtime_resume_and_get(ov5645->dev);
+ if (ret < 0)
+ return ret;
+
ret = ov5645_set_register_array(ov5645,
ov5645->current_mode->data,
ov5645->current_mode->data_size);
@@ -998,39 +979,44 @@ static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable)
dev_err(ov5645->dev, "could not set mode %dx%d\n",
ov5645->current_mode->width,
ov5645->current_mode->height);
- return ret;
+ goto err_rpm_put;
}
ret = v4l2_ctrl_handler_setup(&ov5645->ctrls);
if (ret < 0) {
dev_err(ov5645->dev, "could not sync v4l2 controls\n");
- return ret;
+ goto err_rpm_put;
}
ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45);
if (ret < 0)
- return ret;
+ goto err_rpm_put;
ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
OV5645_SYSTEM_CTRL0_START);
if (ret < 0)
- return ret;
+ goto err_rpm_put;
} else {
ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40);
if (ret < 0)
- return ret;
+ goto stream_off_rpm_put;
ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
OV5645_SYSTEM_CTRL0_STOP);
- if (ret < 0)
- return ret;
+
+ goto stream_off_rpm_put;
}
return 0;
-}
-static const struct v4l2_subdev_core_ops ov5645_core_ops = {
- .s_power = ov5645_s_power,
-};
+err_rpm_put:
+ pm_runtime_put_sync(ov5645->dev);
+ return ret;
+
+stream_off_rpm_put:
+ pm_runtime_mark_last_busy(ov5645->dev);
+ pm_runtime_put_autosuspend(ov5645->dev);
+ return ret;
+}
static const struct v4l2_subdev_video_ops ov5645_video_ops = {
.s_stream = ov5645_s_stream,
@@ -1046,7 +1032,6 @@ static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = {
};
static const struct v4l2_subdev_ops ov5645_subdev_ops = {
- .core = &ov5645_core_ops,
.video = &ov5645_video_ops,
.pad = &ov5645_subdev_pad_ops,
};
@@ -1090,7 +1075,7 @@ static int ov5645_probe(struct i2c_client *client)
}
/* get system clock (xclk) */
- ov5645->xclk = devm_clk_get(dev, "xclk");
+ ov5645->xclk = devm_clk_get(dev, NULL);
if (IS_ERR(ov5645->xclk)) {
dev_err(dev, "could not get xclk");
return PTR_ERR(ov5645->xclk);
@@ -1188,11 +1173,9 @@ static int ov5645_probe(struct i2c_client *client)
goto free_ctrl;
}
- ret = ov5645_s_power(&ov5645->sd, true);
- if (ret < 0) {
- dev_err(dev, "could not power up OV5645\n");
+ ret = ov5645_set_power_on(dev);
+ if (ret)
goto free_entity;
- }
ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high);
if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) {
@@ -1233,20 +1216,30 @@ static int ov5645_probe(struct i2c_client *client)
goto power_down;
}
- ov5645_s_power(&ov5645->sd, false);
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+
+ ov5645_entity_init_cfg(&ov5645->sd, NULL);
ret = v4l2_async_register_subdev(&ov5645->sd);
if (ret < 0) {
dev_err(dev, "could not register v4l2 device\n");
- goto free_entity;
+ goto err_pm_runtime;
}
- ov5645_entity_init_cfg(&ov5645->sd, NULL);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return 0;
+err_pm_runtime:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
power_down:
- ov5645_s_power(&ov5645->sd, false);
+ ov5645_set_power_off(dev);
free_entity:
media_entity_cleanup(&ov5645->sd.entity);
free_ctrl:
@@ -1264,6 +1257,10 @@ static void ov5645_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(&ov5645->sd);
media_entity_cleanup(&ov5645->sd.entity);
v4l2_ctrl_handler_free(&ov5645->ctrls);
+ pm_runtime_disable(ov5645->dev);
+ if (!pm_runtime_status_suspended(ov5645->dev))
+ ov5645_set_power_off(ov5645->dev);
+ pm_runtime_set_suspended(ov5645->dev);
mutex_destroy(&ov5645->power_lock);
}
@@ -1279,10 +1276,15 @@ static const struct of_device_id ov5645_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ov5645_of_match);
+static const struct dev_pm_ops ov5645_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov5645_set_power_off, ov5645_set_power_on, NULL)
+};
+
static struct i2c_driver ov5645_i2c_driver = {
.driver = {
.of_match_table = ov5645_of_match,
.name = "ov5645",
+ .pm = &ov5645_pm_ops,
},
.probe_new = ov5645_probe,
.remove = ov5645_remove,
diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
index 84604ea7bdf9..17465fcf28e3 100644
--- a/drivers/media/i2c/ov5648.c
+++ b/drivers/media/i2c/ov5648.c
@@ -2597,6 +2597,7 @@ static void ov5648_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&sensor->ctrls.handler);
mutex_destroy(&sensor->mutex);
media_entity_cleanup(&subdev->entity);
+ v4l2_fwnode_endpoint_free(&sensor->endpoint);
}
static const struct dev_pm_ops ov5648_pm_ops = {
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index a97ec132ba3a..e3c3bed69ad6 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -156,6 +156,7 @@ struct ov5693_device {
struct gpio_desc *reset;
struct gpio_desc *powerdown;
+ struct gpio_desc *privacy_led;
struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
struct clk *xvclk;
@@ -789,6 +790,7 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
{
+ gpiod_set_value_cansleep(ov5693->privacy_led, 0);
gpiod_set_value_cansleep(ov5693->reset, 1);
gpiod_set_value_cansleep(ov5693->powerdown, 1);
@@ -818,6 +820,7 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
gpiod_set_value_cansleep(ov5693->powerdown, 0);
gpiod_set_value_cansleep(ov5693->reset, 0);
+ gpiod_set_value_cansleep(ov5693->privacy_led, 1);
usleep_range(5000, 7500);
@@ -1325,6 +1328,13 @@ static int ov5693_configure_gpios(struct ov5693_device *ov5693)
return PTR_ERR(ov5693->powerdown);
}
+ ov5693->privacy_led = devm_gpiod_get_optional(ov5693->dev, "privacy-led",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov5693->privacy_led)) {
+ dev_err(ov5693->dev, "Error fetching privacy-led GPIO\n");
+ return PTR_ERR(ov5693->privacy_led);
+ }
+
return 0;
}
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 18f041e985b7..4c0ea2ae671b 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -1025,8 +1025,7 @@ static const struct v4l2_subdev_internal_ops ov6650_internal_ops = {
/*
* i2c_driver function
*/
-static int ov6650_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int ov6650_probe(struct i2c_client *client)
{
struct ov6650 *priv;
int ret;
@@ -1114,7 +1113,7 @@ static struct i2c_driver ov6650_i2c_driver = {
.driver = {
.name = "ov6650",
},
- .probe = ov6650_probe,
+ .probe_new = ov6650_probe,
.remove = ov6650_remove,
.id_table = ov6650_id,
};
diff --git a/drivers/media/i2c/ov7640.c b/drivers/media/i2c/ov7640.c
index 5e2d67f0f9f2..e6751d5cc64b 100644
--- a/drivers/media/i2c/ov7640.c
+++ b/drivers/media/i2c/ov7640.c
@@ -42,8 +42,7 @@ static int write_regs(struct i2c_client *client,
static const struct v4l2_subdev_ops ov7640_ops;
-static int ov7640_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ov7640_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct v4l2_subdev *sd;
@@ -87,7 +86,7 @@ static struct i2c_driver ov7640_driver = {
.driver = {
.name = "ov7640",
},
- .probe = ov7640_probe,
+ .probe_new = ov7640_probe,
.remove = ov7640_remove,
.id_table = ov7640_id,
};
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 4b9b156b53c7..11d3bef65d43 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -15,7 +15,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index efa18d026ac3..cf8384e09413 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -2110,17 +2110,18 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
-static int __ov8856_power_on(struct ov8856 *ov8856)
+static int ov8856_power_on(struct device *dev)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov8856 *ov8856 = to_ov8856(sd);
int ret;
- if (is_acpi_node(dev_fwnode(&client->dev)))
+ if (is_acpi_node(dev_fwnode(dev)))
return 0;
ret = clk_prepare_enable(ov8856->xvclk);
if (ret < 0) {
- dev_err(&client->dev, "failed to enable xvclk\n");
+ dev_err(dev, "failed to enable xvclk\n");
return ret;
}
@@ -2132,7 +2133,7 @@ static int __ov8856_power_on(struct ov8856 *ov8856)
ret = regulator_bulk_enable(ARRAY_SIZE(ov8856_supply_names),
ov8856->supplies);
if (ret < 0) {
- dev_err(&client->dev, "failed to enable regulators\n");
+ dev_err(dev, "failed to enable regulators\n");
goto disable_clk;
}
@@ -2148,17 +2149,20 @@ disable_clk:
return ret;
}
-static void __ov8856_power_off(struct ov8856 *ov8856)
+static int ov8856_power_off(struct device *dev)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov8856 *ov8856 = to_ov8856(sd);
- if (is_acpi_node(dev_fwnode(&client->dev)))
- return;
+ if (is_acpi_node(dev_fwnode(dev)))
+ return 0;
gpiod_set_value_cansleep(ov8856->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ov8856_supply_names),
ov8856->supplies);
clk_disable_unprepare(ov8856->xvclk);
+
+ return 0;
}
static int __maybe_unused ov8856_suspend(struct device *dev)
@@ -2170,7 +2174,7 @@ static int __maybe_unused ov8856_suspend(struct device *dev)
if (ov8856->streaming)
ov8856_stop_streaming(ov8856);
- __ov8856_power_off(ov8856);
+ ov8856_power_off(dev);
mutex_unlock(&ov8856->mutex);
return 0;
@@ -2184,7 +2188,7 @@ static int __maybe_unused ov8856_resume(struct device *dev)
mutex_lock(&ov8856->mutex);
- __ov8856_power_on(ov8856);
+ ov8856_power_on(dev);
if (ov8856->streaming) {
ret = ov8856_start_streaming(ov8856);
if (ret) {
@@ -2451,7 +2455,7 @@ static void ov8856_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
mutex_destroy(&ov8856->mutex);
- __ov8856_power_off(ov8856);
+ ov8856_power_off(&client->dev);
}
static int ov8856_probe(struct i2c_client *client)
@@ -2475,7 +2479,7 @@ static int ov8856_probe(struct i2c_client *client)
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
- ret = __ov8856_power_on(ov8856);
+ ret = ov8856_power_on(&client->dev);
if (ret) {
dev_err(&client->dev, "failed to power on\n");
return ret;
@@ -2531,13 +2535,14 @@ probe_error_v4l2_ctrl_handler_free:
mutex_destroy(&ov8856->mutex);
probe_power_off:
- __ov8856_power_off(ov8856);
+ ov8856_power_off(&client->dev);
return ret;
}
static const struct dev_pm_ops ov8856_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov8856_suspend, ov8856_resume)
+ SET_RUNTIME_PM_OPS(ov8856_power_off, ov8856_power_on, NULL)
};
#ifdef CONFIG_ACPI
diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c
index df144a2f6eda..37a55d53af56 100644
--- a/drivers/media/i2c/ov9282.c
+++ b/drivers/media/i2c/ov9282.c
@@ -11,8 +11,10 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
@@ -21,6 +23,13 @@
#define OV9282_MODE_STANDBY 0x00
#define OV9282_MODE_STREAMING 0x01
+#define OV9282_REG_PLL_CTRL_0D 0x030d
+#define OV9282_PLL_CTRL_0D_RAW8 0x60
+#define OV9282_PLL_CTRL_0D_RAW10 0x50
+
+#define OV9282_REG_TIMING_HTS 0x380c
+#define OV9282_TIMING_HTS_MAX 0x7fff
+
/* Lines per frame */
#define OV9282_REG_LPFR 0x380e
@@ -45,6 +54,17 @@
/* Group hold register */
#define OV9282_REG_HOLD 0x3308
+#define OV9282_REG_ANA_CORE_2 0x3662
+#define OV9282_ANA_CORE2_RAW8 0x07
+#define OV9282_ANA_CORE2_RAW10 0x05
+
+#define OV9282_REG_TIMING_FORMAT_1 0x3820
+#define OV9282_REG_TIMING_FORMAT_2 0x3821
+#define OV9282_FLIP_BIT BIT(2)
+
+#define OV9282_REG_MIPI_CTRL00 0x4800
+#define OV9282_GATED_CLOCK BIT(5)
+
/* Input clock rate */
#define OV9282_INCLK_RATE 24000000
@@ -52,9 +72,34 @@
#define OV9282_LINK_FREQ 400000000
#define OV9282_NUM_DATA_LANES 2
+/* Pixel rate */
+#define OV9282_PIXEL_RATE_10BIT (OV9282_LINK_FREQ * 2 * \
+ OV9282_NUM_DATA_LANES / 10)
+#define OV9282_PIXEL_RATE_8BIT (OV9282_LINK_FREQ * 2 * \
+ OV9282_NUM_DATA_LANES / 8)
+
+/*
+ * OV9282 native and active pixel array size.
+ * 8 dummy rows/columns on each edge of a 1280x800 active array
+ */
+#define OV9282_NATIVE_WIDTH 1296U
+#define OV9282_NATIVE_HEIGHT 816U
+#define OV9282_PIXEL_ARRAY_LEFT 8U
+#define OV9282_PIXEL_ARRAY_TOP 8U
+#define OV9282_PIXEL_ARRAY_WIDTH 1280U
+#define OV9282_PIXEL_ARRAY_HEIGHT 800U
+
#define OV9282_REG_MIN 0x00
#define OV9282_REG_MAX 0xfffff
+static const char * const ov9282_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV9282_NUM_SUPPLIES ARRAY_SIZE(ov9282_supply_names)
+
/**
* struct ov9282_reg - ov9282 sensor register
* @address: Register address
@@ -79,25 +124,24 @@ struct ov9282_reg_list {
* struct ov9282_mode - ov9282 sensor mode structure
* @width: Frame width
* @height: Frame height
- * @code: Format code
- * @hblank: Horizontal blanking in lines
+ * @hblank_min: Minimum horizontal blanking in lines for non-continuous[0] and
+ * continuous[1] clock modes
* @vblank: Vertical blanking in lines
* @vblank_min: Minimum vertical blanking in lines
* @vblank_max: Maximum vertical blanking in lines
- * @pclk: Sensor pixel clock
* @link_freq_idx: Link frequency index
+ * @crop: on-sensor cropping for this mode
* @reg_list: Register list for sensor mode
*/
struct ov9282_mode {
u32 width;
u32 height;
- u32 code;
- u32 hblank;
+ u32 hblank_min[2];
u32 vblank;
u32 vblank_min;
u32 vblank_max;
- u64 pclk;
u32 link_freq_idx;
+ struct v4l2_rect crop;
struct ov9282_reg_list reg_list;
};
@@ -109,15 +153,18 @@ struct ov9282_mode {
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
* @inclk: Sensor input clock
+ * @supplies: Regulator supplies for the sensor
* @ctrl_handler: V4L2 control handler
* @link_freq_ctrl: Pointer to link frequency control
- * @pclk_ctrl: Pointer to pixel clock control
* @hblank_ctrl: Pointer to horizontal blanking control
* @vblank_ctrl: Pointer to vertical blanking control
* @exp_ctrl: Pointer to exposure control
* @again_ctrl: Pointer to analog gain control
+ * @pixel_rate: Pointer to pixel rate control
* @vblank: Vertical blanking in lines
+ * @noncontinuous_clock: Selection of CSI2 noncontinuous clock mode
* @cur_mode: Pointer to current selected sensor mode
+ * @code: Mbus code currently selected
* @mutex: Mutex for serializing sensor controls
* @streaming: Flag indicating streaming state
*/
@@ -128,17 +175,20 @@ struct ov9282 {
struct media_pad pad;
struct gpio_desc *reset_gpio;
struct clk *inclk;
+ struct regulator_bulk_data supplies[OV9282_NUM_SUPPLIES];
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *link_freq_ctrl;
- struct v4l2_ctrl *pclk_ctrl;
struct v4l2_ctrl *hblank_ctrl;
struct v4l2_ctrl *vblank_ctrl;
struct {
struct v4l2_ctrl *exp_ctrl;
struct v4l2_ctrl *again_ctrl;
};
+ struct v4l2_ctrl *pixel_rate;
u32 vblank;
+ bool noncontinuous_clock;
const struct ov9282_mode *cur_mode;
+ u32 code;
struct mutex mutex;
bool streaming;
};
@@ -147,10 +197,15 @@ static const s64 link_freq[] = {
OV9282_LINK_FREQ,
};
-/* Sensor mode registers */
-static const struct ov9282_reg mode_1280x720_regs[] = {
+/*
+ * Common registers
+ *
+ * Note: Do NOT include a software reset (0x0103, 0x01) in any of these
+ * register arrays as some settings are written as part of ov9282_power_on,
+ * and the reset will clear them.
+ */
+static const struct ov9282_reg common_regs[] = {
{0x0302, 0x32},
- {0x030d, 0x50},
{0x030e, 0x02},
{0x3001, 0x00},
{0x3004, 0x00},
@@ -163,14 +218,10 @@ static const struct ov9282_reg mode_1280x720_regs[] = {
{0x3030, 0x10},
{0x3039, 0x32},
{0x303a, 0x00},
- {0x3500, 0x00},
- {0x3501, 0x5f},
- {0x3502, 0x1e},
{0x3503, 0x08},
{0x3505, 0x8c},
{0x3507, 0x03},
{0x3508, 0x00},
- {0x3509, 0x10},
{0x3610, 0x80},
{0x3611, 0xa0},
{0x3620, 0x6e},
@@ -183,13 +234,85 @@ static const struct ov9282_reg mode_1280x720_regs[] = {
{0x372d, 0x22},
{0x3731, 0x80},
{0x3732, 0x30},
- {0x3778, 0x00},
{0x377d, 0x22},
{0x3788, 0x02},
{0x3789, 0xa4},
{0x378a, 0x00},
{0x378b, 0x4a},
{0x3799, 0x20},
+ {0x3881, 0x42},
+ {0x38a8, 0x02},
+ {0x38a9, 0x80},
+ {0x38b1, 0x00},
+ {0x38c4, 0x00},
+ {0x38c5, 0xc0},
+ {0x38c6, 0x04},
+ {0x38c7, 0x80},
+ {0x3920, 0xff},
+ {0x4010, 0x40},
+ {0x4043, 0x40},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4501, 0x00},
+ {0x450a, 0x08},
+ {0x4601, 0x04},
+ {0x470f, 0x00},
+ {0x4f07, 0x00},
+ {0x5000, 0x9f},
+ {0x5001, 0x00},
+ {0x5e00, 0x00},
+ {0x5d00, 0x07},
+ {0x5d01, 0x00},
+ {0x0101, 0x01},
+ {0x1000, 0x03},
+ {0x5a08, 0x84},
+};
+
+static struct ov9282_reg_list common_regs_list = {
+ .num_of_regs = ARRAY_SIZE(common_regs),
+ .regs = common_regs,
+};
+
+#define MODE_1280_800 0
+#define MODE_1280_720 1
+#define MODE_640_400 2
+
+#define DEFAULT_MODE MODE_1280_720
+
+/* Sensor mode registers */
+static const struct ov9282_reg mode_1280x800_regs[] = {
+ {0x3778, 0x00},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x05},
+ {0x3805, 0x0f},
+ {0x3806, 0x03},
+ {0x3807, 0x2f},
+ {0x3808, 0x05},
+ {0x3809, 0x00},
+ {0x380a, 0x03},
+ {0x380b, 0x20},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x08},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3820, 0x40},
+ {0x3821, 0x00},
+ {0x4003, 0x40},
+ {0x4008, 0x04},
+ {0x4009, 0x0b},
+ {0x400c, 0x00},
+ {0x400d, 0x07},
+ {0x4507, 0x00},
+ {0x4509, 0x00},
+};
+
+static const struct ov9282_reg mode_1280x720_regs[] = {
+ {0x3778, 0x00},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
@@ -202,10 +325,6 @@ static const struct ov9282_reg mode_1280x720_regs[] = {
{0x3809, 0x00},
{0x380a, 0x02},
{0x380b, 0xd0},
- {0x380c, 0x05},
- {0x380d, 0xfa},
- {0x380e, 0x06},
- {0x380f, 0xce},
{0x3810, 0x00},
{0x3811, 0x08},
{0x3812, 0x00},
@@ -214,56 +333,107 @@ static const struct ov9282_reg mode_1280x720_regs[] = {
{0x3815, 0x11},
{0x3820, 0x3c},
{0x3821, 0x84},
- {0x3881, 0x42},
- {0x38a8, 0x02},
- {0x38a9, 0x80},
- {0x38b1, 0x00},
- {0x38c4, 0x00},
- {0x38c5, 0xc0},
- {0x38c6, 0x04},
- {0x38c7, 0x80},
- {0x3920, 0xff},
{0x4003, 0x40},
{0x4008, 0x02},
{0x4009, 0x05},
{0x400c, 0x00},
{0x400d, 0x03},
- {0x4010, 0x40},
- {0x4043, 0x40},
- {0x4307, 0x30},
- {0x4317, 0x00},
- {0x4501, 0x00},
{0x4507, 0x00},
{0x4509, 0x80},
- {0x450a, 0x08},
- {0x4601, 0x04},
- {0x470f, 0x00},
- {0x4f07, 0x00},
- {0x4800, 0x20},
- {0x5000, 0x9f},
- {0x5001, 0x00},
- {0x5e00, 0x00},
- {0x5d00, 0x07},
- {0x5d01, 0x00},
- {0x0101, 0x01},
- {0x1000, 0x03},
- {0x5a08, 0x84},
+};
+
+static const struct ov9282_reg mode_640x400_regs[] = {
+ {0x3778, 0x10},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x05},
+ {0x3805, 0x0f},
+ {0x3806, 0x03},
+ {0x3807, 0x2f},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0x90},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x04},
+ {0x3814, 0x31},
+ {0x3815, 0x22},
+ {0x3820, 0x60},
+ {0x3821, 0x01},
+ {0x4008, 0x02},
+ {0x4009, 0x05},
+ {0x400c, 0x00},
+ {0x400d, 0x03},
+ {0x4507, 0x03},
+ {0x4509, 0x80},
};
/* Supported sensor mode configurations */
-static const struct ov9282_mode supported_mode = {
- .width = 1280,
- .height = 720,
- .hblank = 250,
- .vblank = 1022,
- .vblank_min = 151,
- .vblank_max = 51540,
- .pclk = 160000000,
- .link_freq_idx = 0,
- .code = MEDIA_BUS_FMT_Y10_1X10,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
- .regs = mode_1280x720_regs,
+static const struct ov9282_mode supported_modes[] = {
+ [MODE_1280_800] = {
+ .width = 1280,
+ .height = 800,
+ .hblank_min = { 250, 176 },
+ .vblank = 1022,
+ .vblank_min = 110,
+ .vblank_max = 51540,
+ .link_freq_idx = 0,
+ .crop = {
+ .left = OV9282_PIXEL_ARRAY_LEFT,
+ .top = OV9282_PIXEL_ARRAY_TOP,
+ .width = 1280,
+ .height = 800
+ },
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280x800_regs),
+ .regs = mode_1280x800_regs,
+ },
+ },
+ [MODE_1280_720] = {
+ .width = 1280,
+ .height = 720,
+ .hblank_min = { 250, 176 },
+ .vblank = 1022,
+ .vblank_min = 41,
+ .vblank_max = 51540,
+ .link_freq_idx = 0,
+ .crop = {
+ /*
+ * Note that this mode takes the top 720 lines from the
+ * 800 of the sensor. It does not take a middle crop.
+ */
+ .left = OV9282_PIXEL_ARRAY_LEFT,
+ .top = OV9282_PIXEL_ARRAY_TOP,
+ .width = 1280,
+ .height = 720
+ },
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
+ .regs = mode_1280x720_regs,
+ },
+ },
+ [MODE_640_400] = {
+ .width = 640,
+ .height = 400,
+ .hblank_min = { 890, 816 },
+ .vblank = 1022,
+ .vblank_min = 22,
+ .vblank_max = 51540,
+ .link_freq_idx = 0,
+ .crop = {
+ .left = OV9282_PIXEL_ARRAY_LEFT,
+ .top = OV9282_PIXEL_ARRAY_TOP,
+ .width = 1280,
+ .height = 800
+ },
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_640x400_regs),
+ .regs = mode_640x400_regs,
+ },
},
};
@@ -373,19 +543,33 @@ static int ov9282_write_regs(struct ov9282 *ov9282,
* ov9282_update_controls() - Update control ranges based on streaming mode
* @ov9282: pointer to ov9282 device
* @mode: pointer to ov9282_mode sensor mode
+ * @fmt: pointer to the requested mode
*
* Return: 0 if successful, error code otherwise.
*/
static int ov9282_update_controls(struct ov9282 *ov9282,
- const struct ov9282_mode *mode)
+ const struct ov9282_mode *mode,
+ const struct v4l2_subdev_format *fmt)
{
+ u32 hblank_min;
+ s64 pixel_rate;
int ret;
ret = __v4l2_ctrl_s_ctrl(ov9282->link_freq_ctrl, mode->link_freq_idx);
if (ret)
return ret;
- ret = __v4l2_ctrl_s_ctrl(ov9282->hblank_ctrl, mode->hblank);
+ pixel_rate = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10) ?
+ OV9282_PIXEL_RATE_10BIT : OV9282_PIXEL_RATE_8BIT;
+ ret = __v4l2_ctrl_modify_range(ov9282->pixel_rate, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+ if (ret)
+ return ret;
+
+ hblank_min = mode->hblank_min[ov9282->noncontinuous_clock ? 0 : 1];
+ ret = __v4l2_ctrl_modify_range(ov9282->hblank_ctrl, hblank_min,
+ OV9282_TIMING_HTS_MAX - mode->width, 1,
+ hblank_min);
if (ret)
return ret;
@@ -403,22 +587,15 @@ static int ov9282_update_controls(struct ov9282 *ov9282,
*/
static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain)
{
- u32 lpfr;
int ret;
- lpfr = ov9282->vblank + ov9282->cur_mode->height;
-
- dev_dbg(ov9282->dev, "Set exp %u, analog gain %u, lpfr %u",
- exposure, gain, lpfr);
+ dev_dbg(ov9282->dev, "Set exp %u, analog gain %u",
+ exposure, gain);
ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1);
if (ret)
return ret;
- ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr);
- if (ret)
- goto error_release_group_hold;
-
ret = ov9282_write_reg(ov9282, OV9282_REG_EXPOSURE, 3, exposure << 4);
if (ret)
goto error_release_group_hold;
@@ -431,6 +608,40 @@ error_release_group_hold:
return ret;
}
+static int ov9282_set_ctrl_hflip(struct ov9282 *ov9282, int value)
+{
+ u32 current_val;
+ int ret = ov9282_read_reg(ov9282, OV9282_REG_TIMING_FORMAT_2, 1,
+ &current_val);
+ if (ret)
+ return ret;
+
+ if (value)
+ current_val |= OV9282_FLIP_BIT;
+ else
+ current_val &= ~OV9282_FLIP_BIT;
+
+ return ov9282_write_reg(ov9282, OV9282_REG_TIMING_FORMAT_2, 1,
+ current_val);
+}
+
+static int ov9282_set_ctrl_vflip(struct ov9282 *ov9282, int value)
+{
+ u32 current_val;
+ int ret = ov9282_read_reg(ov9282, OV9282_REG_TIMING_FORMAT_1, 1,
+ &current_val);
+ if (ret)
+ return ret;
+
+ if (value)
+ current_val |= OV9282_FLIP_BIT;
+ else
+ current_val &= ~OV9282_FLIP_BIT;
+
+ return ov9282_write_reg(ov9282, OV9282_REG_TIMING_FORMAT_1, 1,
+ current_val);
+}
+
/**
* ov9282_set_ctrl() - Set subdevice control
* @ctrl: pointer to v4l2_ctrl structure
@@ -449,6 +660,7 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct ov9282, ctrl_handler);
u32 analog_gain;
u32 exposure;
+ u32 lpfr;
int ret;
switch (ctrl->id) {
@@ -466,11 +678,14 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
OV9282_EXPOSURE_OFFSET,
1, OV9282_EXPOSURE_DEFAULT);
break;
- case V4L2_CID_EXPOSURE:
- /* Set controls only if sensor is in power on state */
- if (!pm_runtime_get_if_in_use(ov9282->dev))
- return 0;
+ }
+
+ /* Set controls only if sensor is in power on state */
+ if (!pm_runtime_get_if_in_use(ov9282->dev))
+ return 0;
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
exposure = ctrl->val;
analog_gain = ov9282->again_ctrl->val;
@@ -478,15 +693,28 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
exposure, analog_gain);
ret = ov9282_update_exp_gain(ov9282, exposure, analog_gain);
-
- pm_runtime_put(ov9282->dev);
-
+ break;
+ case V4L2_CID_VBLANK:
+ lpfr = ov9282->vblank + ov9282->cur_mode->height;
+ ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = ov9282_set_ctrl_hflip(ov9282, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ ret = ov9282_set_ctrl_vflip(ov9282, ctrl->val);
+ break;
+ case V4L2_CID_HBLANK:
+ ret = ov9282_write_reg(ov9282, OV9282_REG_TIMING_HTS, 2,
+ (ctrl->val + ov9282->cur_mode->width) >> 1);
break;
default:
dev_err(ov9282->dev, "Invalid control %d", ctrl->id);
ret = -EINVAL;
}
+ pm_runtime_put(ov9282->dev);
+
return ret;
}
@@ -507,10 +735,16 @@ static int ov9282_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index > 0)
+ switch (code->index) {
+ case 0:
+ code->code = MEDIA_BUS_FMT_Y10_1X10;
+ break;
+ case 1:
+ code->code = MEDIA_BUS_FMT_Y8_1X8;
+ break;
+ default:
return -EINVAL;
-
- code->code = supported_mode.code;
+ }
return 0;
}
@@ -527,15 +761,16 @@ static int ov9282_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fsize)
{
- if (fsize->index > 0)
+ if (fsize->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- if (fsize->code != supported_mode.code)
+ if (fsize->code != MEDIA_BUS_FMT_Y10_1X10 &&
+ fsize->code != MEDIA_BUS_FMT_Y8_1X8)
return -EINVAL;
- fsize->min_width = supported_mode.width;
+ fsize->min_width = supported_modes[fsize->index].width;
fsize->max_width = fsize->min_width;
- fsize->min_height = supported_mode.height;
+ fsize->min_height = supported_modes[fsize->index].height;
fsize->max_height = fsize->min_height;
return 0;
@@ -546,15 +781,17 @@ static int ov9282_enum_frame_size(struct v4l2_subdev *sd,
* from selected sensor mode
* @ov9282: pointer to ov9282 device
* @mode: pointer to ov9282_mode sensor mode
+ * @code: mbus code to be stored
* @fmt: V4L2 sub-device format need to be filled
*/
static void ov9282_fill_pad_format(struct ov9282 *ov9282,
const struct ov9282_mode *mode,
+ u32 code,
struct v4l2_subdev_format *fmt)
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = mode->code;
+ fmt->format.code = code;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
@@ -584,7 +821,8 @@ static int ov9282_get_pad_format(struct v4l2_subdev *sd,
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
- ov9282_fill_pad_format(ov9282, ov9282->cur_mode, fmt);
+ ov9282_fill_pad_format(ov9282, ov9282->cur_mode, ov9282->code,
+ fmt);
}
mutex_unlock(&ov9282->mutex);
@@ -606,12 +844,22 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd,
{
struct ov9282 *ov9282 = to_ov9282(sd);
const struct ov9282_mode *mode;
+ u32 code;
int ret = 0;
mutex_lock(&ov9282->mutex);
- mode = &supported_mode;
- ov9282_fill_pad_format(ov9282, mode, fmt);
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ fmt->format.width,
+ fmt->format.height);
+ if (fmt->format.code == MEDIA_BUS_FMT_Y8_1X8)
+ code = MEDIA_BUS_FMT_Y8_1X8;
+ else
+ code = MEDIA_BUS_FMT_Y10_1X10;
+
+ ov9282_fill_pad_format(ov9282, mode, code, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
@@ -619,9 +867,11 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd,
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
- ret = ov9282_update_controls(ov9282, mode);
- if (!ret)
+ ret = ov9282_update_controls(ov9282, mode, fmt);
+ if (!ret) {
ov9282->cur_mode = mode;
+ ov9282->code = code;
+ }
}
mutex_unlock(&ov9282->mutex);
@@ -643,11 +893,64 @@ static int ov9282_init_pad_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_format fmt = { 0 };
fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- ov9282_fill_pad_format(ov9282, &supported_mode, &fmt);
+ ov9282_fill_pad_format(ov9282, &supported_modes[DEFAULT_MODE],
+ ov9282->code, &fmt);
return ov9282_set_pad_format(sd, sd_state, &fmt);
}
+static const struct v4l2_rect *
+__ov9282_get_pad_crop(struct ov9282 *ov9282,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&ov9282->sd, sd_state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &ov9282->cur_mode->crop;
+ }
+
+ return NULL;
+}
+
+static int ov9282_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct ov9282 *ov9282 = to_ov9282(sd);
+
+ mutex_lock(&ov9282->mutex);
+ sel->r = *__ov9282_get_pad_crop(ov9282, sd_state, sel->pad,
+ sel->which);
+ mutex_unlock(&ov9282->mutex);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV9282_NATIVE_WIDTH;
+ sel->r.height = OV9282_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = OV9282_PIXEL_ARRAY_TOP;
+ sel->r.left = OV9282_PIXEL_ARRAY_LEFT;
+ sel->r.width = OV9282_PIXEL_ARRAY_WIDTH;
+ sel->r.height = OV9282_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
/**
* ov9282_start_streaming() - Start sensor stream
* @ov9282: pointer to ov9282 device
@@ -656,9 +959,34 @@ static int ov9282_init_pad_cfg(struct v4l2_subdev *sd,
*/
static int ov9282_start_streaming(struct ov9282 *ov9282)
{
+ const struct ov9282_reg bitdepth_regs[2][2] = {
+ {
+ {OV9282_REG_PLL_CTRL_0D, OV9282_PLL_CTRL_0D_RAW10},
+ {OV9282_REG_ANA_CORE_2, OV9282_ANA_CORE2_RAW10},
+ }, {
+ {OV9282_REG_PLL_CTRL_0D, OV9282_PLL_CTRL_0D_RAW8},
+ {OV9282_REG_ANA_CORE_2, OV9282_ANA_CORE2_RAW8},
+ }
+ };
const struct ov9282_reg_list *reg_list;
+ int bitdepth_index;
int ret;
+ /* Write common registers */
+ ret = ov9282_write_regs(ov9282, common_regs_list.regs,
+ common_regs_list.num_of_regs);
+ if (ret) {
+ dev_err(ov9282->dev, "fail to write common registers");
+ return ret;
+ }
+
+ bitdepth_index = ov9282->code == MEDIA_BUS_FMT_Y10_1X10 ? 0 : 1;
+ ret = ov9282_write_regs(ov9282, bitdepth_regs[bitdepth_index], 2);
+ if (ret) {
+ dev_err(ov9282->dev, "fail to write bitdepth regs");
+ return ret;
+ }
+
/* Write sensor mode registers */
reg_list = &ov9282->cur_mode->reg_list;
ret = ov9282_write_regs(ov9282, reg_list->regs, reg_list->num_of_regs);
@@ -767,6 +1095,18 @@ static int ov9282_detect(struct ov9282 *ov9282)
return 0;
}
+static int ov9282_configure_regulators(struct ov9282 *ov9282)
+{
+ unsigned int i;
+
+ for (i = 0; i < OV9282_NUM_SUPPLIES; i++)
+ ov9282->supplies[i].supply = ov9282_supply_names[i];
+
+ return devm_regulator_bulk_get(ov9282->dev,
+ OV9282_NUM_SUPPLIES,
+ ov9282->supplies);
+}
+
/**
* ov9282_parse_hw_config() - Parse HW configuration and check if supported
* @ov9282: pointer to ov9282 device
@@ -803,6 +1143,12 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282)
return PTR_ERR(ov9282->inclk);
}
+ ret = ov9282_configure_regulators(ov9282);
+ if (ret) {
+ dev_err(ov9282->dev, "Failed to get power regulators\n");
+ return ret;
+ }
+
rate = clk_get_rate(ov9282->inclk);
if (rate != OV9282_INCLK_RATE) {
dev_err(ov9282->dev, "inclk frequency mismatch");
@@ -818,6 +1164,9 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282)
if (ret)
return ret;
+ ov9282->noncontinuous_clock =
+ bus_cfg.bus.mipi_csi2.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
+
if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV9282_NUM_DATA_LANES) {
dev_err(ov9282->dev,
"number of CSI2 data lanes %d is not supported",
@@ -845,6 +1194,11 @@ done_endpoint_free:
}
/* V4l2 subdevice ops */
+static const struct v4l2_subdev_core_ops ov9282_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops ov9282_video_ops = {
.s_stream = ov9282_set_stream,
};
@@ -855,9 +1209,11 @@ static const struct v4l2_subdev_pad_ops ov9282_pad_ops = {
.enum_frame_size = ov9282_enum_frame_size,
.get_fmt = ov9282_get_pad_format,
.set_fmt = ov9282_set_pad_format,
+ .get_selection = ov9282_get_selection,
};
static const struct v4l2_subdev_ops ov9282_subdev_ops = {
+ .core = &ov9282_core_ops,
.video = &ov9282_video_ops,
.pad = &ov9282_pad_ops,
};
@@ -874,6 +1230,12 @@ static int ov9282_power_on(struct device *dev)
struct ov9282 *ov9282 = to_ov9282(sd);
int ret;
+ ret = regulator_bulk_enable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ return ret;
+ }
+
usleep_range(400, 600);
gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
@@ -886,11 +1248,23 @@ static int ov9282_power_on(struct device *dev)
usleep_range(400, 600);
+ ret = ov9282_write_reg(ov9282, OV9282_REG_MIPI_CTRL00, 1,
+ ov9282->noncontinuous_clock ?
+ OV9282_GATED_CLOCK : 0);
+ if (ret) {
+ dev_err(ov9282->dev, "fail to write MIPI_CTRL00");
+ goto error_clk;
+ }
+
return 0;
+error_clk:
+ clk_disable_unprepare(ov9282->inclk);
error_reset:
gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
+ regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
return ret;
}
@@ -909,6 +1283,8 @@ static int ov9282_power_off(struct device *dev)
clk_disable_unprepare(ov9282->inclk);
+ regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
return 0;
}
@@ -922,10 +1298,12 @@ static int ov9282_init_controls(struct ov9282 *ov9282)
{
struct v4l2_ctrl_handler *ctrl_hdlr = &ov9282->ctrl_handler;
const struct ov9282_mode *mode = ov9282->cur_mode;
+ struct v4l2_fwnode_device_properties props;
+ u32 hblank_min;
u32 lpfr;
int ret;
- ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6);
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
if (ret)
return ret;
@@ -959,12 +1337,18 @@ static int ov9282_init_controls(struct ov9282 *ov9282)
mode->vblank_max,
1, mode->vblank);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 1);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 1);
+
/* Read only controls */
- ov9282->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
- &ov9282_ctrl_ops,
- V4L2_CID_PIXEL_RATE,
- mode->pclk, mode->pclk,
- 1, mode->pclk);
+ ov9282->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ OV9282_PIXEL_RATE_10BIT,
+ OV9282_PIXEL_RATE_10BIT, 1,
+ OV9282_PIXEL_RATE_10BIT);
ov9282->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr,
&ov9282_ctrl_ops,
@@ -976,16 +1360,22 @@ static int ov9282_init_controls(struct ov9282 *ov9282)
if (ov9282->link_freq_ctrl)
ov9282->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ hblank_min = mode->hblank_min[ov9282->noncontinuous_clock ? 0 : 1];
ov9282->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
&ov9282_ctrl_ops,
V4L2_CID_HBLANK,
- OV9282_REG_MIN,
- OV9282_REG_MAX,
- 1, mode->hblank);
- if (ov9282->hblank_ctrl)
- ov9282->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ hblank_min,
+ OV9282_TIMING_HTS_MAX - mode->width,
+ 1, hblank_min);
+
+ ret = v4l2_fwnode_device_parse(ov9282->dev, &props);
+ if (!ret) {
+ /* Failure sets ctrl_hdlr->error, which we check afterwards anyway */
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov9282_ctrl_ops,
+ &props);
+ }
- if (ctrl_hdlr->error) {
+ if (ctrl_hdlr->error || ret) {
dev_err(ov9282->dev, "control init failed: %d",
ctrl_hdlr->error);
v4l2_ctrl_handler_free(ctrl_hdlr);
@@ -1016,6 +1406,8 @@ static int ov9282_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops);
+ v4l2_i2c_subdev_set_name(&ov9282->sd, client,
+ device_get_match_data(ov9282->dev), NULL);
ret = ov9282_parse_hw_config(ov9282);
if (ret) {
@@ -1038,8 +1430,9 @@ static int ov9282_probe(struct i2c_client *client)
goto error_power_off;
}
- /* Set default mode to max resolution */
- ov9282->cur_mode = &supported_mode;
+ /* Set default mode to first mode */
+ ov9282->cur_mode = &supported_modes[DEFAULT_MODE];
+ ov9282->code = MEDIA_BUS_FMT_Y10_1X10;
ov9282->vblank = ov9282->cur_mode->vblank;
ret = ov9282_init_controls(ov9282);
@@ -1049,7 +1442,8 @@ static int ov9282_probe(struct i2c_client *client)
}
/* Initialize subdev */
- ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
ov9282->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
/* Initialize source pad */
@@ -1113,7 +1507,8 @@ static const struct dev_pm_ops ov9282_pm_ops = {
};
static const struct of_device_id ov9282_of_match[] = {
- { .compatible = "ovti,ov9282" },
+ { .compatible = "ovti,ov9281", .data = "ov9281" },
+ { .compatible = "ovti,ov9282", .data = "ov9282" },
{ }
};
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index 8b80be33c5f4..a80fa59bf2ae 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -682,8 +682,7 @@ static const struct v4l2_subdev_ops ov9640_subdev_ops = {
/*
* i2c_driver function
*/
-static int ov9640_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int ov9640_probe(struct i2c_client *client)
{
struct ov9640_priv *priv;
int ret;
@@ -763,7 +762,7 @@ static struct i2c_driver ov9640_i2c_driver = {
.driver = {
.name = "ov9640",
},
- .probe = ov9640_probe,
+ .probe_new = ov9640_probe,
.remove = ov9640_remove,
.id_table = ov9640_id,
};
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 4d458993e6d6..7e7cb1e4520e 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -10,7 +10,6 @@
*/
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
@@ -30,7 +29,6 @@
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/i2c/ov9650.h>
static int debug;
module_param(debug, int, 0644);
@@ -1402,38 +1400,6 @@ static const struct v4l2_subdev_ops ov965x_subdev_ops = {
.video = &ov965x_video_ops,
};
-/*
- * Reset and power down GPIOs configuration
- */
-static int ov965x_configure_gpios_pdata(struct ov965x *ov965x,
- const struct ov9650_platform_data *pdata)
-{
- int ret, i;
- int gpios[NUM_GPIOS];
- struct device *dev = regmap_get_device(ov965x->regmap);
-
- gpios[GPIO_PWDN] = pdata->gpio_pwdn;
- gpios[GPIO_RST] = pdata->gpio_reset;
-
- for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) {
- int gpio = gpios[i];
-
- if (!gpio_is_valid(gpio))
- continue;
- ret = devm_gpio_request_one(dev, gpio,
- GPIOF_OUT_INIT_HIGH, "OV965X");
- if (ret < 0)
- return ret;
- v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio);
-
- gpio_set_value_cansleep(gpio, 1);
- gpio_export(gpio, 0);
- ov965x->gpios[i] = gpio_to_desc(gpio);
- }
-
- return 0;
-}
-
static int ov965x_configure_gpios(struct ov965x *ov965x)
{
struct device *dev = regmap_get_device(ov965x->regmap);
@@ -1493,7 +1459,6 @@ out:
static int ov965x_probe(struct i2c_client *client)
{
- const struct ov9650_platform_data *pdata = client->dev.platform_data;
struct v4l2_subdev *sd;
struct ov965x *ov965x;
int ret;
@@ -1513,17 +1478,7 @@ static int ov965x_probe(struct i2c_client *client)
return PTR_ERR(ov965x->regmap);
}
- if (pdata) {
- if (pdata->mclk_frequency == 0) {
- dev_err(&client->dev, "MCLK frequency not specified\n");
- return -EINVAL;
- }
- ov965x->mclk_frequency = pdata->mclk_frequency;
-
- ret = ov965x_configure_gpios_pdata(ov965x, pdata);
- if (ret < 0)
- return ret;
- } else if (dev_fwnode(&client->dev)) {
+ if (dev_fwnode(&client->dev)) {
ov965x->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(ov965x->clk))
return PTR_ERR(ov965x->clk);
@@ -1534,7 +1489,7 @@ static int ov965x_probe(struct i2c_client *client)
return ret;
} else {
dev_err(&client->dev,
- "Neither platform data nor device property specified\n");
+ "No device properties specified\n");
return -EINVAL;
}
diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c
index 1c3502f34cd3..9db5473daba0 100644
--- a/drivers/media/i2c/rj54n1cb0c.c
+++ b/drivers/media/i2c/rj54n1cb0c.c
@@ -1297,8 +1297,7 @@ done:
return ret;
}
-static int rj54n1_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int rj54n1_probe(struct i2c_client *client)
{
struct rj54n1 *rj54n1;
struct i2c_adapter *adapter = client->adapter;
@@ -1422,7 +1421,7 @@ static struct i2c_driver rj54n1_i2c_driver = {
.driver = {
.name = "rj54n1cb0c",
},
- .probe = rj54n1_probe,
+ .probe_new = rj54n1_probe,
.remove = rj54n1_remove,
.id_table = rj54n1_id,
};
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index d96ba58ce1e5..59b03b0860d5 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -10,12 +10,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/media.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
@@ -1347,24 +1346,6 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
return 0;
}
-static int s5c73m3_gpio_set_value(struct s5c73m3 *priv, int id, u32 val)
-{
- if (!gpio_is_valid(priv->gpio[id].gpio))
- return 0;
- gpio_set_value(priv->gpio[id].gpio, !!val);
- return 1;
-}
-
-static int s5c73m3_gpio_assert(struct s5c73m3 *priv, int id)
-{
- return s5c73m3_gpio_set_value(priv, id, priv->gpio[id].level);
-}
-
-static int s5c73m3_gpio_deassert(struct s5c73m3 *priv, int id)
-{
- return s5c73m3_gpio_set_value(priv, id, !priv->gpio[id].level);
-}
-
static int __s5c73m3_power_on(struct s5c73m3 *state)
{
int i, ret;
@@ -1386,10 +1367,9 @@ static int __s5c73m3_power_on(struct s5c73m3 *state)
v4l2_dbg(1, s5c73m3_dbg, &state->oif_sd, "clock frequency: %ld\n",
clk_get_rate(state->clock));
- s5c73m3_gpio_deassert(state, STBY);
+ gpiod_set_value(state->stby, 0);
usleep_range(100, 200);
-
- s5c73m3_gpio_deassert(state, RSET);
+ gpiod_set_value(state->reset, 0);
usleep_range(50, 100);
return 0;
@@ -1404,11 +1384,10 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
{
int i, ret;
- if (s5c73m3_gpio_assert(state, RSET))
- usleep_range(10, 50);
-
- if (s5c73m3_gpio_assert(state, STBY))
- usleep_range(100, 200);
+ gpiod_set_value(state->reset, 1);
+ usleep_range(10, 50);
+ gpiod_set_value(state->stby, 1);
+ usleep_range(100, 200);
clk_disable_unprepare(state->clock);
@@ -1543,58 +1522,10 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
.video = &s5c73m3_oif_video_ops,
};
-static int s5c73m3_configure_gpios(struct s5c73m3 *state)
-{
- static const char * const gpio_names[] = {
- "S5C73M3_STBY", "S5C73M3_RST"
- };
- struct i2c_client *c = state->i2c_client;
- struct s5c73m3_gpio *g = state->gpio;
- int ret, i;
-
- for (i = 0; i < GPIO_NUM; ++i) {
- unsigned int flags = GPIOF_DIR_OUT;
- if (g[i].level)
- flags |= GPIOF_INIT_HIGH;
- ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags,
- gpio_names[i]);
- if (ret) {
- v4l2_err(c, "failed to request gpio %s\n",
- gpio_names[i]);
- return ret;
- }
- }
- return 0;
-}
-
-static int s5c73m3_parse_gpios(struct s5c73m3 *state)
-{
- static const char * const prop_names[] = {
- "standby-gpios", "xshutdown-gpios",
- };
- struct device *dev = &state->i2c_client->dev;
- struct device_node *node = dev->of_node;
- int ret, i;
-
- for (i = 0; i < GPIO_NUM; ++i) {
- enum of_gpio_flags of_flags;
-
- ret = of_get_named_gpio_flags(node, prop_names[i],
- 0, &of_flags);
- if (ret < 0) {
- dev_err(dev, "failed to parse %s DT property\n",
- prop_names[i]);
- return -EINVAL;
- }
- state->gpio[i].gpio = ret;
- state->gpio[i].level = !(of_flags & OF_GPIO_ACTIVE_LOW);
- }
- return 0;
-}
-
static int s5c73m3_get_platform_data(struct s5c73m3 *state)
{
- struct device *dev = &state->i2c_client->dev;
+ struct i2c_client *c = state->i2c_client;
+ struct device *dev = &c->dev;
const struct s5c73m3_platform_data *pdata = dev->platform_data;
struct device_node *node = dev->of_node;
struct device_node *node_ep;
@@ -1608,8 +1539,6 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
}
state->mclk_frequency = pdata->mclk_frequency;
- state->gpio[STBY] = pdata->gpio_stby;
- state->gpio[RSET] = pdata->gpio_reset;
return 0;
}
@@ -1624,9 +1553,17 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
state->mclk_frequency);
}
- ret = s5c73m3_parse_gpios(state);
- if (ret < 0)
- return -EINVAL;
+ /* Request GPIO lines asserted */
+ state->stby = devm_gpiod_get(dev, "standby", GPIOD_OUT_HIGH);
+ if (IS_ERR(state->stby))
+ return dev_err_probe(dev, PTR_ERR(state->stby),
+ "failed to request gpio S5C73M3_STBY\n");
+ gpiod_set_consumer_name(state->stby, "S5C73M3_STBY");
+ state->reset = devm_gpiod_get(dev, "xshutdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(state->reset))
+ return dev_err_probe(dev, PTR_ERR(state->reset),
+ "failed to request gpio S5C73M3_RST\n");
+ gpiod_set_consumer_name(state->reset, "S5C73M3_RST");
node_ep = of_graph_get_next_endpoint(node, NULL);
if (!node_ep) {
@@ -1708,10 +1645,6 @@ static int s5c73m3_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- ret = s5c73m3_configure_gpios(state);
- if (ret)
- goto out_err;
-
for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++)
state->supplies[i].supply = s5c73m3_supply_names[i];
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index 141ad0ba7f5a..e3543ae384ed 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -10,7 +10,6 @@
#include <linux/sizes.h>
#include <linux/delay.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/media.h>
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index c3fcfdd3ea66..1fc7df41c5ee 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
@@ -351,12 +352,6 @@ struct s5c73m3_ctrls {
struct v4l2_ctrl *scene_mode;
};
-enum s5c73m3_gpio_id {
- STBY,
- RSET,
- GPIO_NUM,
-};
-
enum s5c73m3_resolution_types {
RES_ISP,
RES_JPEG,
@@ -383,7 +378,8 @@ struct s5c73m3 {
u32 i2c_read_address;
struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES];
- struct s5c73m3_gpio gpio[GPIO_NUM];
+ struct gpio_desc *stby;
+ struct gpio_desc *reset;
struct clk *clock;
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
deleted file mode 100644
index 3dddcd9dd351..000000000000
--- a/drivers/media/i2c/s5k4ecgx.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for Samsung S5K4ECGX 1/4" 5Mp CMOS Image Sensor SoC
- * with an Embedded Image Signal Processor.
- *
- * Copyright (C) 2012, Linaro, Sangwook Lee <sangwook.lee@linaro.org>
- * Copyright (C) 2012, Insignal Co,. Ltd, Homin Lee <suapapa@insignal.co.kr>
- *
- * Based on s5k6aa and noon010pc30 driver
- * Copyright (C) 2011, Samsung Electronics Co., Ltd.
- */
-
-#include <linux/clk.h>
-#include <linux/crc32.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-
-#include <media/media-entity.h>
-#include <media/i2c/s5k4ecgx.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-mediabus.h>
-#include <media/v4l2-subdev.h>
-
-static int debug;
-module_param(debug, int, 0644);
-
-#define S5K4ECGX_DRIVER_NAME "s5k4ecgx"
-#define S5K4ECGX_FIRMWARE "s5k4ecgx.bin"
-
-/* Firmware revision information */
-#define REG_FW_REVISION 0x700001a6
-#define REG_FW_VERSION 0x700001a4
-#define S5K4ECGX_REVISION_1_1 0x11
-#define S5K4ECGX_FW_VERSION 0x4ec0
-
-/* General purpose parameters */
-#define REG_USER_BRIGHTNESS 0x7000022c
-#define REG_USER_CONTRAST 0x7000022e
-#define REG_USER_SATURATION 0x70000230
-
-#define REG_G_ENABLE_PREV 0x7000023e
-#define REG_G_ENABLE_PREV_CHG 0x70000240
-#define REG_G_NEW_CFG_SYNC 0x7000024a
-#define REG_G_PREV_IN_WIDTH 0x70000250
-#define REG_G_PREV_IN_HEIGHT 0x70000252
-#define REG_G_PREV_IN_XOFFS 0x70000254
-#define REG_G_PREV_IN_YOFFS 0x70000256
-#define REG_G_CAP_IN_WIDTH 0x70000258
-#define REG_G_CAP_IN_HEIGHT 0x7000025a
-#define REG_G_CAP_IN_XOFFS 0x7000025c
-#define REG_G_CAP_IN_YOFFS 0x7000025e
-#define REG_G_INPUTS_CHANGE_REQ 0x70000262
-#define REG_G_ACTIVE_PREV_CFG 0x70000266
-#define REG_G_PREV_CFG_CHG 0x70000268
-#define REG_G_PREV_OPEN_AFTER_CH 0x7000026a
-
-/* Preview context register sets. n = 0...4. */
-#define PREG(n, x) ((n) * 0x30 + (x))
-#define REG_P_OUT_WIDTH(n) PREG(n, 0x700002a6)
-#define REG_P_OUT_HEIGHT(n) PREG(n, 0x700002a8)
-#define REG_P_FMT(n) PREG(n, 0x700002aa)
-#define REG_P_PVI_MASK(n) PREG(n, 0x700002b4)
-#define REG_P_FR_TIME_TYPE(n) PREG(n, 0x700002be)
-#define FR_TIME_DYNAMIC 0
-#define FR_TIME_FIXED 1
-#define FR_TIME_FIXED_ACCURATE 2
-#define REG_P_FR_TIME_Q_TYPE(n) PREG(n, 0x700002c0)
-#define FR_TIME_Q_DYNAMIC 0
-#define FR_TIME_Q_BEST_FRRATE 1
-#define FR_TIME_Q_BEST_QUALITY 2
-
-/* Frame period in 0.1 ms units */
-#define REG_P_MAX_FR_TIME(n) PREG(n, 0x700002c2)
-#define REG_P_MIN_FR_TIME(n) PREG(n, 0x700002c4)
-#define US_TO_FR_TIME(__t) ((__t) / 100)
-#define REG_P_PREV_MIRROR(n) PREG(n, 0x700002d0)
-#define REG_P_CAP_MIRROR(n) PREG(n, 0x700002d2)
-
-#define REG_G_PREVZOOM_IN_WIDTH 0x70000494
-#define REG_G_PREVZOOM_IN_HEIGHT 0x70000496
-#define REG_G_PREVZOOM_IN_XOFFS 0x70000498
-#define REG_G_PREVZOOM_IN_YOFFS 0x7000049a
-#define REG_G_CAPZOOM_IN_WIDTH 0x7000049c
-#define REG_G_CAPZOOM_IN_HEIGHT 0x7000049e
-#define REG_G_CAPZOOM_IN_XOFFS 0x700004a0
-#define REG_G_CAPZOOM_IN_YOFFS 0x700004a2
-
-/* n = 0...4 */
-#define REG_USER_SHARPNESS(n) (0x70000a28 + (n) * 0xb6)
-
-/* Reduce sharpness range for user space API */
-#define SHARPNESS_DIV 8208
-#define TOK_TERM 0xffffffff
-
-/*
- * FIXME: This is copied from s5k6aa, because of no information
- * in the S5K4ECGX datasheet.
- * H/W register Interface (0xd0000000 - 0xd0000fff)
- */
-#define AHB_MSB_ADDR_PTR 0xfcfc
-#define GEN_REG_OFFSH 0xd000
-#define REG_CMDWR_ADDRH 0x0028
-#define REG_CMDWR_ADDRL 0x002a
-#define REG_CMDRD_ADDRH 0x002c
-#define REG_CMDRD_ADDRL 0x002e
-#define REG_CMDBUF0_ADDR 0x0f12
-
-struct s5k4ecgx_frmsize {
- struct v4l2_frmsize_discrete size;
- /* Fixed sensor matrix crop rectangle */
- struct v4l2_rect input_window;
-};
-
-struct regval_list {
- u32 addr;
- u16 val;
-};
-
-/*
- * TODO: currently only preview is supported and snapshot (capture)
- * is not implemented yet
- */
-static const struct s5k4ecgx_frmsize s5k4ecgx_prev_sizes[] = {
- {
- .size = { 176, 144 },
- .input_window = { 0x00, 0x00, 0x928, 0x780 },
- }, {
- .size = { 352, 288 },
- .input_window = { 0x00, 0x00, 0x928, 0x780 },
- }, {
- .size = { 640, 480 },
- .input_window = { 0x00, 0x00, 0xa00, 0x780 },
- }, {
- .size = { 720, 480 },
- .input_window = { 0x00, 0x00, 0xa00, 0x6a8 },
- }
-};
-
-#define S5K4ECGX_NUM_PREV ARRAY_SIZE(s5k4ecgx_prev_sizes)
-
-struct s5k4ecgx_pixfmt {
- u32 code;
- u32 colorspace;
- /* REG_TC_PCFG_Format register value */
- u16 reg_p_format;
-};
-
-/* By default value, output from sensor will be YUV422 0-255 */
-static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
-};
-
-static const char * const s5k4ecgx_supply_names[] = {
- /*
- * Usually 2.8V is used for analog power (vdda)
- * and digital IO (vddio, vdddcore)
- */
- "vdda",
- "vddio",
- "vddcore",
- "vddreg", /* The internal s5k4ecgx regulator's supply (1.8V) */
-};
-
-#define S5K4ECGX_NUM_SUPPLIES ARRAY_SIZE(s5k4ecgx_supply_names)
-
-enum s5k4ecgx_gpio_id {
- STBY,
- RSET,
- GPIO_NUM,
-};
-
-struct s5k4ecgx {
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_ctrl_handler handler;
-
- struct s5k4ecgx_platform_data *pdata;
- const struct s5k4ecgx_pixfmt *curr_pixfmt;
- const struct s5k4ecgx_frmsize *curr_frmsize;
- struct mutex lock;
- u8 streaming;
- u8 set_params;
-
- struct regulator_bulk_data supplies[S5K4ECGX_NUM_SUPPLIES];
- struct s5k4ecgx_gpio gpio[GPIO_NUM];
-};
-
-static inline struct s5k4ecgx *to_s5k4ecgx(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct s5k4ecgx, sd);
-}
-
-static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
-{
- u8 wbuf[2] = { addr >> 8, addr & 0xff };
- struct i2c_msg msg[2];
- u8 rbuf[2];
- int ret;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 2;
- msg[0].buf = wbuf;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 2;
- msg[1].buf = rbuf;
-
- ret = i2c_transfer(client->adapter, msg, 2);
- *val = be16_to_cpu(*((__be16 *)rbuf));
-
- v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
-
- return ret == 2 ? 0 : ret;
-}
-
-static int s5k4ecgx_i2c_write(struct i2c_client *client, u16 addr, u16 val)
-{
- u8 buf[4] = { addr >> 8, addr & 0xff, val >> 8, val & 0xff };
-
- int ret = i2c_master_send(client, buf, 4);
- v4l2_dbg(4, debug, client, "i2c_write: 0x%04x : 0x%04x\n", addr, val);
-
- return ret == 4 ? 0 : ret;
-}
-
-static int s5k4ecgx_write(struct i2c_client *client, u32 addr, u16 val)
-{
- u16 high = addr >> 16, low = addr & 0xffff;
- int ret;
-
- v4l2_dbg(3, debug, client, "write: 0x%08x : 0x%04x\n", addr, val);
-
- ret = s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRH, high);
- if (!ret)
- ret = s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRL, low);
- if (!ret)
- ret = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, val);
-
- return ret;
-}
-
-static int s5k4ecgx_read(struct i2c_client *client, u32 addr, u16 *val)
-{
- u16 high = addr >> 16, low = addr & 0xffff;
- int ret;
-
- ret = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRH, high);
- if (!ret)
- ret = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRL, low);
- if (!ret)
- ret = s5k4ecgx_i2c_read(client, REG_CMDBUF0_ADDR, val);
-
- return ret;
-}
-
-static int s5k4ecgx_read_fw_ver(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u16 hw_rev, fw_ver = 0;
- int ret;
-
- ret = s5k4ecgx_read(client, REG_FW_VERSION, &fw_ver);
- if (ret < 0 || fw_ver != S5K4ECGX_FW_VERSION) {
- v4l2_err(sd, "FW version check failed!\n");
- return -ENODEV;
- }
-
- ret = s5k4ecgx_read(client, REG_FW_REVISION, &hw_rev);
- if (ret < 0)
- return ret;
-
- v4l2_info(sd, "chip found FW ver: 0x%x, HW rev: 0x%x\n",
- fw_ver, hw_rev);
- return 0;
-}
-
-static int s5k4ecgx_set_ahb_address(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- /* Set APB peripherals start address */
- ret = s5k4ecgx_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
- if (ret < 0)
- return ret;
- /*
- * FIXME: This is copied from s5k6aa, because of no information
- * in s5k4ecgx's datasheet.
- * sw_reset is activated to put device into idle status
- */
- ret = s5k4ecgx_i2c_write(client, 0x0010, 0x0001);
- if (ret < 0)
- return ret;
-
- ret = s5k4ecgx_i2c_write(client, 0x1030, 0x0000);
- if (ret < 0)
- return ret;
- /* Halt ARM CPU */
- return s5k4ecgx_i2c_write(client, 0x0014, 0x0001);
-}
-
-#define FW_CRC_SIZE 4
-/* Register address, value are 4, 2 bytes */
-#define FW_RECORD_SIZE 6
-/*
- * The firmware has following format:
- * < total number of records (4 bytes + 2 bytes padding) N >,
- * < record 0 >, ..., < record N - 1 >, < CRC32-CCITT (4-bytes) >,
- * where "record" is a 4-byte register address followed by 2-byte
- * register value (little endian).
- * The firmware generator can be found in following git repository:
- * git://git.linaro.org/people/sangwook/fimc-v4l2-app.git
- */
-static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct firmware *fw;
- const u8 *ptr;
- int err, i, regs_num;
- u32 addr, crc, crc_file, addr_inc = 0;
- u16 val;
-
- err = request_firmware(&fw, S5K4ECGX_FIRMWARE, sd->v4l2_dev->dev);
- if (err) {
- v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE);
- return err;
- }
- regs_num = get_unaligned_le32(fw->data);
-
- v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n",
- S5K4ECGX_FIRMWARE, fw->size, regs_num);
-
- regs_num++; /* Add header */
- if (fw->size != regs_num * FW_RECORD_SIZE + FW_CRC_SIZE) {
- err = -EINVAL;
- goto fw_out;
- }
- crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE);
- crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE);
- if (crc != crc_file) {
- v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
- err = -EINVAL;
- goto fw_out;
- }
- ptr = fw->data + FW_RECORD_SIZE;
- for (i = 1; i < regs_num; i++) {
- addr = get_unaligned_le32(ptr);
- ptr += sizeof(u32);
- val = get_unaligned_le16(ptr);
- ptr += sizeof(u16);
- if (addr - addr_inc != 2)
- err = s5k4ecgx_write(client, addr, val);
- else
- err = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, val);
- if (err)
- break;
- addr_inc = addr;
- }
-fw_out:
- release_firmware(fw);
- return err;
-}
-
-/* Set preview and capture input window */
-static int s5k4ecgx_set_input_window(struct i2c_client *c,
- const struct v4l2_rect *r)
-{
- int ret;
-
- ret = s5k4ecgx_write(c, REG_G_PREV_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREV_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREV_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREV_IN_YOFFS, r->top);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAP_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAP_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAP_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAP_IN_YOFFS, r->top);
-
- return ret;
-}
-
-/* Set preview and capture zoom input window */
-static int s5k4ecgx_set_zoom_window(struct i2c_client *c,
- const struct v4l2_rect *r)
-{
- int ret;
-
- ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_YOFFS, r->top);
-
- return ret;
-}
-
-static int s5k4ecgx_set_output_framefmt(struct s5k4ecgx *priv)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
- int ret;
-
- ret = s5k4ecgx_write(client, REG_P_OUT_WIDTH(0),
- priv->curr_frmsize->size.width);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_OUT_HEIGHT(0),
- priv->curr_frmsize->size.height);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_FMT(0),
- priv->curr_pixfmt->reg_p_format);
- return ret;
-}
-
-static int s5k4ecgx_init_sensor(struct v4l2_subdev *sd)
-{
- int ret;
-
- ret = s5k4ecgx_set_ahb_address(sd);
-
- /* The delay is from manufacturer's settings */
- msleep(100);
-
- if (!ret)
- ret = s5k4ecgx_load_firmware(sd);
- if (ret)
- v4l2_err(sd, "Failed to write initial settings\n");
-
- return ret;
-}
-
-static int s5k4ecgx_gpio_set_value(struct s5k4ecgx *priv, int id, u32 val)
-{
- if (!gpio_is_valid(priv->gpio[id].gpio))
- return 0;
- gpio_set_value(priv->gpio[id].gpio, val);
-
- return 1;
-}
-
-static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
-{
- int ret;
-
- ret = regulator_bulk_enable(S5K4ECGX_NUM_SUPPLIES, priv->supplies);
- if (ret)
- return ret;
- usleep_range(30, 50);
-
- /* The polarity of STBY is controlled by TSP */
- if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level))
- usleep_range(30, 50);
-
- if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level))
- usleep_range(30, 50);
-
- return 0;
-}
-
-static int __s5k4ecgx_power_off(struct s5k4ecgx *priv)
-{
- if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level))
- usleep_range(30, 50);
-
- if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level))
- usleep_range(30, 50);
-
- priv->streaming = 0;
-
- return regulator_bulk_disable(S5K4ECGX_NUM_SUPPLIES, priv->supplies);
-}
-
-/* Find nearest matching image pixel size. */
-static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf,
- const struct s5k4ecgx_frmsize **size)
-{
- unsigned int min_err = ~0;
- int i = ARRAY_SIZE(s5k4ecgx_prev_sizes);
- const struct s5k4ecgx_frmsize *fsize = &s5k4ecgx_prev_sizes[0],
- *match = NULL;
-
- while (i--) {
- int err = abs(fsize->size.width - mf->width)
- + abs(fsize->size.height - mf->height);
- if (err < min_err) {
- min_err = err;
- match = fsize;
- }
- fsize++;
- }
- if (match) {
- mf->width = match->size.width;
- mf->height = match->size.height;
- if (size)
- *size = match;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
- return -EINVAL;
- code->code = s5k4ecgx_formats[code->index].code;
-
- return 0;
-}
-
-static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
- struct v4l2_mbus_framefmt *mf;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (sd_state) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- fmt->format = *mf;
- }
- return 0;
- }
-
- mf = &fmt->format;
-
- mutex_lock(&priv->lock);
- mf->width = priv->curr_frmsize->size.width;
- mf->height = priv->curr_frmsize->size.height;
- mf->code = priv->curr_pixfmt->code;
- mf->colorspace = priv->curr_pixfmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- int i = ARRAY_SIZE(s5k4ecgx_formats);
-
- while (--i)
- if (mf->code == s5k4ecgx_formats[i].code)
- break;
- mf->code = s5k4ecgx_formats[i].code;
-
- return &s5k4ecgx_formats[i];
-}
-
-static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
- const struct s5k4ecgx_frmsize *fsize = NULL;
- const struct s5k4ecgx_pixfmt *pf;
- struct v4l2_mbus_framefmt *mf;
- int ret = 0;
-
- pf = s5k4ecgx_try_fmt(sd, &fmt->format);
- s5k4ecgx_try_frame_size(&fmt->format, &fsize);
- fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
- fmt->format.field = V4L2_FIELD_NONE;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (sd_state) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- *mf = fmt->format;
- }
- return 0;
- }
-
- mutex_lock(&priv->lock);
- if (!priv->streaming) {
- priv->curr_frmsize = fsize;
- priv->curr_pixfmt = pf;
- priv->set_params = 1;
- } else {
- ret = -EBUSY;
- }
- mutex_unlock(&priv->lock);
-
- return ret;
-}
-
-static const struct v4l2_subdev_pad_ops s5k4ecgx_pad_ops = {
- .enum_mbus_code = s5k4ecgx_enum_mbus_code,
- .get_fmt = s5k4ecgx_get_fmt,
- .set_fmt = s5k4ecgx_set_fmt,
-};
-
-/*
- * V4L2 subdev controls
- */
-static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = &container_of(ctrl->handler, struct s5k4ecgx,
- handler)->sd;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
- unsigned int i;
- int err = 0;
-
- v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
-
- mutex_lock(&priv->lock);
- switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- err = s5k4ecgx_write(client, REG_USER_CONTRAST, ctrl->val);
- break;
-
- case V4L2_CID_SATURATION:
- err = s5k4ecgx_write(client, REG_USER_SATURATION, ctrl->val);
- break;
-
- case V4L2_CID_SHARPNESS:
- /* TODO: Revisit, is this setting for all presets ? */
- for (i = 0; i < 4 && !err; i++)
- err = s5k4ecgx_write(client, REG_USER_SHARPNESS(i),
- ctrl->val * SHARPNESS_DIV);
- break;
-
- case V4L2_CID_BRIGHTNESS:
- err = s5k4ecgx_write(client, REG_USER_BRIGHTNESS, ctrl->val);
- break;
- }
- mutex_unlock(&priv->lock);
- if (err < 0)
- v4l2_err(sd, "Failed to write s_ctrl err %d\n", err);
-
- return err;
-}
-
-static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = {
- .s_ctrl = s5k4ecgx_s_ctrl,
-};
-
-/*
- * Reading s5k4ecgx version information
- */
-static int s5k4ecgx_registered(struct v4l2_subdev *sd)
-{
- int ret;
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
-
- mutex_lock(&priv->lock);
- ret = __s5k4ecgx_power_on(priv);
- if (!ret) {
- ret = s5k4ecgx_read_fw_ver(sd);
- __s5k4ecgx_power_off(priv);
- }
- mutex_unlock(&priv->lock);
-
- return ret;
-}
-
-/*
- * V4L2 subdev internal operations
- */
-static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
-
- mf->width = s5k4ecgx_prev_sizes[0].size.width;
- mf->height = s5k4ecgx_prev_sizes[0].size.height;
- mf->code = s5k4ecgx_formats[0].code;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static const struct v4l2_subdev_internal_ops s5k4ecgx_subdev_internal_ops = {
- .registered = s5k4ecgx_registered,
- .open = s5k4ecgx_open,
-};
-
-static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int on)
-{
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
- int ret;
-
- v4l2_dbg(1, debug, sd, "Switching %s\n", on ? "on" : "off");
-
- if (on) {
- ret = __s5k4ecgx_power_on(priv);
- if (ret < 0)
- return ret;
- /* Time to stabilize sensor */
- msleep(100);
- ret = s5k4ecgx_init_sensor(sd);
- if (ret < 0)
- __s5k4ecgx_power_off(priv);
- else
- priv->set_params = 1;
- } else {
- ret = __s5k4ecgx_power_off(priv);
- }
-
- return ret;
-}
-
-static int s5k4ecgx_log_status(struct v4l2_subdev *sd)
-{
- v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
-
- return 0;
-}
-
-static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = {
- .s_power = s5k4ecgx_s_power,
- .log_status = s5k4ecgx_log_status,
-};
-
-static int __s5k4ecgx_s_params(struct s5k4ecgx *priv)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
- const struct v4l2_rect *crop_rect = &priv->curr_frmsize->input_window;
- int ret;
-
- ret = s5k4ecgx_set_input_window(client, crop_rect);
- if (!ret)
- ret = s5k4ecgx_set_zoom_window(client, crop_rect);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_G_INPUTS_CHANGE_REQ, 1);
- if (!ret)
- ret = s5k4ecgx_write(client, 0x70000a1e, 0x28);
- if (!ret)
- ret = s5k4ecgx_write(client, 0x70000ad4, 0x3c);
- if (!ret)
- ret = s5k4ecgx_set_output_framefmt(priv);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_PVI_MASK(0), 0x52);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_FR_TIME_TYPE(0),
- FR_TIME_DYNAMIC);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_FR_TIME_Q_TYPE(0),
- FR_TIME_Q_BEST_FRRATE);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_MIN_FR_TIME(0),
- US_TO_FR_TIME(33300));
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_MAX_FR_TIME(0),
- US_TO_FR_TIME(66600));
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_PREV_MIRROR(0), 0);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_P_CAP_MIRROR(0), 0);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_G_ACTIVE_PREV_CFG, 0);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_G_PREV_OPEN_AFTER_CH, 1);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_G_NEW_CFG_SYNC, 1);
- if (!ret)
- ret = s5k4ecgx_write(client, REG_G_PREV_CFG_CHG, 1);
-
- return ret;
-}
-
-static int __s5k4ecgx_s_stream(struct s5k4ecgx *priv, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
- int ret;
-
- if (on && priv->set_params) {
- ret = __s5k4ecgx_s_params(priv);
- if (ret < 0)
- return ret;
- priv->set_params = 0;
- }
- /*
- * This enables/disables preview stream only. Capture requests
- * are not supported yet.
- */
- ret = s5k4ecgx_write(client, REG_G_ENABLE_PREV, on);
- if (ret < 0)
- return ret;
- return s5k4ecgx_write(client, REG_G_ENABLE_PREV_CHG, 1);
-}
-
-static int s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
-{
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
- int ret = 0;
-
- v4l2_dbg(1, debug, sd, "Turn streaming %s\n", on ? "on" : "off");
-
- mutex_lock(&priv->lock);
-
- if (priv->streaming == !on) {
- ret = __s5k4ecgx_s_stream(priv, on);
- if (!ret)
- priv->streaming = on & 1;
- }
-
- mutex_unlock(&priv->lock);
- return ret;
-}
-
-static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = {
- .s_stream = s5k4ecgx_s_stream,
-};
-
-static const struct v4l2_subdev_ops s5k4ecgx_ops = {
- .core = &s5k4ecgx_core_ops,
- .pad = &s5k4ecgx_pad_ops,
- .video = &s5k4ecgx_video_ops,
-};
-
-/*
- * GPIO setup
- */
-static int s5k4ecgx_config_gpio(int nr, int val, const char *name)
-{
- unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- int ret;
-
- if (!gpio_is_valid(nr))
- return 0;
- ret = gpio_request_one(nr, flags, name);
- if (!ret)
- gpio_export(nr, 0);
-
- return ret;
-}
-
-static void s5k4ecgx_free_gpios(struct s5k4ecgx *priv)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->gpio); i++) {
- if (!gpio_is_valid(priv->gpio[i].gpio))
- continue;
- gpio_free(priv->gpio[i].gpio);
- priv->gpio[i].gpio = -EINVAL;
- }
-}
-
-static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
- const struct s5k4ecgx_platform_data *pdata)
-{
- const struct s5k4ecgx_gpio *gpio = &pdata->gpio_stby;
- int ret;
-
- priv->gpio[STBY].gpio = -EINVAL;
- priv->gpio[RSET].gpio = -EINVAL;
-
- ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY");
-
- if (ret) {
- s5k4ecgx_free_gpios(priv);
- return ret;
- }
- priv->gpio[STBY] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
-
- gpio = &pdata->gpio_reset;
-
- ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_RST");
- if (ret) {
- s5k4ecgx_free_gpios(priv);
- return ret;
- }
- priv->gpio[RSET] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
-
- return 0;
-}
-
-static int s5k4ecgx_init_v4l2_ctrls(struct s5k4ecgx *priv)
-{
- const struct v4l2_ctrl_ops *ops = &s5k4ecgx_ctrl_ops;
- struct v4l2_ctrl_handler *hdl = &priv->handler;
- int ret;
-
- ret = v4l2_ctrl_handler_init(hdl, 4);
- if (ret)
- return ret;
-
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
-
- /* Sharpness default is 24612, and then (24612/SHARPNESS_DIV) = 2 */
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704/SHARPNESS_DIV,
- 24612/SHARPNESS_DIV, 1, 2);
- if (hdl->error) {
- ret = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return ret;
- }
- priv->sd.ctrl_handler = hdl;
-
- return 0;
-};
-
-static int s5k4ecgx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct s5k4ecgx_platform_data *pdata = client->dev.platform_data;
- struct v4l2_subdev *sd;
- struct s5k4ecgx *priv;
- int ret, i;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "platform data is missing!\n");
- return -EINVAL;
- }
-
- priv = devm_kzalloc(&client->dev, sizeof(struct s5k4ecgx), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- mutex_init(&priv->lock);
- priv->streaming = 0;
-
- sd = &priv->sd;
- /* Registering subdev */
- v4l2_i2c_subdev_init(sd, client, &s5k4ecgx_ops);
- /* Static name; NEVER use in new drivers! */
- strscpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
-
- sd->internal_ops = &s5k4ecgx_subdev_internal_ops;
- /* Support v4l2 sub-device user space API */
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- priv->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
- if (ret)
- return ret;
-
- ret = s5k4ecgx_config_gpios(priv, pdata);
- if (ret) {
- dev_err(&client->dev, "Failed to set gpios\n");
- goto out_err1;
- }
- for (i = 0; i < S5K4ECGX_NUM_SUPPLIES; i++)
- priv->supplies[i].supply = s5k4ecgx_supply_names[i];
-
- ret = devm_regulator_bulk_get(&client->dev, S5K4ECGX_NUM_SUPPLIES,
- priv->supplies);
- if (ret) {
- dev_err(&client->dev, "Failed to get regulators\n");
- goto out_err2;
- }
- ret = s5k4ecgx_init_v4l2_ctrls(priv);
- if (ret)
- goto out_err2;
-
- priv->curr_pixfmt = &s5k4ecgx_formats[0];
- priv->curr_frmsize = &s5k4ecgx_prev_sizes[0];
-
- return 0;
-
-out_err2:
- s5k4ecgx_free_gpios(priv);
-out_err1:
- media_entity_cleanup(&priv->sd.entity);
-
- return ret;
-}
-
-static void s5k4ecgx_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct s5k4ecgx *priv = to_s5k4ecgx(sd);
-
- mutex_destroy(&priv->lock);
- s5k4ecgx_free_gpios(priv);
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(&priv->handler);
- media_entity_cleanup(&sd->entity);
-}
-
-static const struct i2c_device_id s5k4ecgx_id[] = {
- { S5K4ECGX_DRIVER_NAME, 0 },
- {}
-};
-MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id);
-
-static struct i2c_driver v4l2_i2c_driver = {
- .driver = {
- .name = S5K4ECGX_DRIVER_NAME,
- },
- .probe = s5k4ecgx_probe,
- .remove = s5k4ecgx_remove,
- .id_table = s5k4ecgx_id,
-};
-
-module_i2c_driver(v4l2_i2c_driver);
-
-MODULE_DESCRIPTION("Samsung S5K4ECGX 5MP SOC camera");
-MODULE_AUTHOR("Sangwook Lee <sangwook.lee@linaro.org>");
-MODULE_AUTHOR("Seok-Young Jang <quartz.jang@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(S5K4ECGX_FIRMWARE);
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 5c2253ab3b6f..960fbf6428ea 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -13,11 +13,10 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/media.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -228,11 +227,6 @@ static const char * const s5k5baf_supply_names[] = {
};
#define S5K5BAF_NUM_SUPPLIES ARRAY_SIZE(s5k5baf_supply_names)
-struct s5k5baf_gpio {
- int gpio;
- int level;
-};
-
enum s5k5baf_gpio_id {
STBY,
RSET,
@@ -284,7 +278,7 @@ struct s5k5baf_fw {
};
struct s5k5baf {
- struct s5k5baf_gpio gpios[NUM_GPIOS];
+ struct gpio_desc *gpios[NUM_GPIOS];
enum v4l2_mbus_type bus_type;
u8 nlanes;
struct regulator_bulk_data supplies[S5K5BAF_NUM_SUPPLIES];
@@ -936,16 +930,12 @@ static void s5k5baf_hw_set_test_pattern(struct s5k5baf *state, int id)
static void s5k5baf_gpio_assert(struct s5k5baf *state, int id)
{
- struct s5k5baf_gpio *gpio = &state->gpios[id];
-
- gpio_set_value(gpio->gpio, gpio->level);
+ gpiod_set_value_cansleep(state->gpios[id], 1);
}
static void s5k5baf_gpio_deassert(struct s5k5baf *state, int id)
{
- struct s5k5baf_gpio *gpio = &state->gpios[id];
-
- gpio_set_value(gpio->gpio, !gpio->level);
+ gpiod_set_value_cansleep(state->gpios[id], 0);
}
static int s5k5baf_power_on(struct s5k5baf *state)
@@ -1799,44 +1789,30 @@ static const struct v4l2_subdev_ops s5k5baf_subdev_ops = {
static int s5k5baf_configure_gpios(struct s5k5baf *state)
{
- static const char * const name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
+ static const char * const name[] = { "stbyn", "rstn" };
+ static const char * const label[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
- struct s5k5baf_gpio *g = state->gpios;
+ struct gpio_desc *gpio;
int ret, i;
for (i = 0; i < NUM_GPIOS; ++i) {
- int flags = GPIOF_DIR_OUT;
- if (g[i].level)
- flags |= GPIOF_INIT_HIGH;
- ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags, name[i]);
- if (ret < 0) {
- v4l2_err(c, "failed to request gpio %s\n", name[i]);
+ gpio = devm_gpiod_get(&c->dev, name[i], GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(gpio);
+ if (ret) {
+ v4l2_err(c, "failed to request gpio %s: %d\n",
+ name[i], ret);
return ret;
}
- }
- return 0;
-}
-
-static int s5k5baf_parse_gpios(struct s5k5baf_gpio *gpios, struct device *dev)
-{
- static const char * const names[] = {
- "stbyn-gpios",
- "rstn-gpios",
- };
- struct device_node *node = dev->of_node;
- enum of_gpio_flags flags;
- int ret, i;
- for (i = 0; i < NUM_GPIOS; ++i) {
- ret = of_get_named_gpio_flags(node, names[i], 0, &flags);
- if (ret < 0) {
- dev_err(dev, "no %s GPIO pin provided\n", names[i]);
+ ret = gpiod_set_consumer_name(gpio, label[i]);
+ if (ret) {
+ v4l2_err(c, "failed to set up name for gpio %s: %d\n",
+ name[i], ret);
return ret;
}
- gpios[i].gpio = ret;
- gpios[i].level = !(flags & OF_GPIO_ACTIVE_LOW);
- }
+ state->gpios[i] = gpio;
+ }
return 0;
}
@@ -1860,10 +1836,6 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
state->mclk_frequency);
}
- ret = s5k5baf_parse_gpios(state->gpios, dev);
- if (ret < 0)
- return ret;
-
node_ep = of_graph_get_next_endpoint(node, NULL);
if (!node_ep) {
dev_err(dev, "no endpoint defined at node %pOF\n", node);
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index a4efd6d10b43..ef6673b10580 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -9,12 +9,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -59,7 +59,7 @@ struct s5k6a3 {
struct v4l2_subdev subdev;
struct media_pad pad;
struct regulator_bulk_data supplies[S5K6A3_NUM_SUPPLIES];
- int gpio_reset;
+ struct gpio_desc *gpio_reset;
struct mutex lock;
struct v4l2_mbus_framefmt format;
struct clk *clock;
@@ -216,11 +216,11 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
goto error_clk;
}
- gpio_set_value(sensor->gpio_reset, 1);
+ gpiod_set_value_cansleep(sensor->gpio_reset, 0);
usleep_range(600, 800);
- gpio_set_value(sensor->gpio_reset, 0);
+ gpiod_set_value_cansleep(sensor->gpio_reset, 1);
usleep_range(600, 800);
- gpio_set_value(sensor->gpio_reset, 1);
+ gpiod_set_value_cansleep(sensor->gpio_reset, 0);
/* Delay needed for the sensor initialization */
msleep(20);
@@ -240,7 +240,7 @@ static int __s5k6a3_power_off(struct s5k6a3 *sensor)
{
int i;
- gpio_set_value(sensor->gpio_reset, 0);
+ gpiod_set_value_cansleep(sensor->gpio_reset, 1);
for (i = S5K6A3_NUM_SUPPLIES - 1; i >= 0; i--)
regulator_disable(sensor->supplies[i].consumer);
@@ -285,32 +285,24 @@ static int s5k6a3_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct s5k6a3 *sensor;
struct v4l2_subdev *sd;
- int gpio, i, ret;
+ int i, ret;
sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
mutex_init(&sensor->lock);
- sensor->gpio_reset = -EINVAL;
- sensor->clock = ERR_PTR(-EINVAL);
sensor->dev = dev;
sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME);
if (IS_ERR(sensor->clock))
return PTR_ERR(sensor->clock);
- gpio = of_get_gpio_flags(dev->of_node, 0, NULL);
- if (!gpio_is_valid(gpio))
- return gpio;
-
- ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW,
- S5K6A3_DRV_NAME);
- if (ret < 0)
+ sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(sensor->gpio_reset);
+ if (ret)
return ret;
- sensor->gpio_reset = gpio;
-
if (of_property_read_u32(dev->of_node, "clock-frequency",
&sensor->clock_frequency)) {
sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 059211788a65..5996153371fc 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -1544,8 +1544,7 @@ static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
return 0;
}
-static int s5k6aa_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int s5k6aa_probe(struct i2c_client *client)
{
const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
struct v4l2_subdev *sd;
@@ -1641,7 +1640,7 @@ static struct i2c_driver s5k6aa_i2c_driver = {
.driver = {
.name = DRIVER_NAME
},
- .probe = s5k6aa_probe,
+ .probe_new = s5k6aa_probe,
.remove = s5k6aa_remove,
.id_table = s5k6aa_id,
};
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
index d6a51beabd02..8752f7cff611 100644
--- a/drivers/media/i2c/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
@@ -448,8 +448,7 @@ static const struct v4l2_subdev_ops saa6588_ops = {
/* ---------------------------------------------------------------------- */
-static int saa6588_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa6588_probe(struct i2c_client *client)
{
struct saa6588 *s;
struct v4l2_subdev *sd;
@@ -506,7 +505,7 @@ static struct i2c_driver saa6588_driver = {
.driver = {
.name = "saa6588",
},
- .probe = saa6588_probe,
+ .probe_new = saa6588_probe,
.remove = saa6588_remove,
.id_table = saa6588_id,
};
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 5928cc6f4595..892d64fe6e81 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -659,8 +659,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = {
.pad = &saa6752hs_pad_ops,
};
-static int saa6752hs_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa6752hs_probe(struct i2c_client *client)
{
struct saa6752hs_state *h;
struct v4l2_subdev *sd;
@@ -782,7 +781,7 @@ static struct i2c_driver saa6752hs_driver = {
.driver = {
.name = "saa6752hs",
},
- .probe = saa6752hs_probe,
+ .probe_new = saa6752hs_probe,
.remove = saa6752hs_remove,
.id_table = saa6752hs_id,
};
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
index 5067525d8b11..b58e71517376 100644
--- a/drivers/media/i2c/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
@@ -358,8 +358,7 @@ static const struct v4l2_subdev_ops saa7110_ops = {
/* ----------------------------------------------------------------------- */
-static int saa7110_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa7110_probe(struct i2c_client *client)
{
struct saa7110 *decoder;
struct v4l2_subdev *sd;
@@ -449,7 +448,7 @@ static struct i2c_driver saa7110_driver = {
.driver = {
.name = "saa7110",
},
- .probe = saa7110_probe,
+ .probe_new = saa7110_probe,
.remove = saa7110_remove,
.id_table = saa7110_id,
};
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index 4f3d1b432a4e..df01059076fa 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -1228,8 +1228,7 @@ static const struct v4l2_subdev_ops saa717x_ops = {
/* i2c implementation */
/* ----------------------------------------------------------------------- */
-static int saa717x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int saa717x_probe(struct i2c_client *client)
{
struct saa717x_state *decoder;
struct v4l2_ctrl_handler *hdl;
@@ -1344,7 +1343,7 @@ static struct i2c_driver saa717x_driver = {
.driver = {
.name = "saa717x",
},
- .probe = saa717x_probe,
+ .probe_new = saa717x_probe,
.remove = saa717x_remove,
.id_table = saa717x_id,
};
diff --git a/drivers/media/i2c/saa7185.c b/drivers/media/i2c/saa7185.c
index 266462325d30..c78f2e95ba37 100644
--- a/drivers/media/i2c/saa7185.c
+++ b/drivers/media/i2c/saa7185.c
@@ -290,8 +290,7 @@ static const struct v4l2_subdev_ops saa7185_ops = {
/* ----------------------------------------------------------------------- */
-static int saa7185_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa7185_probe(struct i2c_client *client)
{
int i;
struct saa7185 *encoder;
@@ -344,7 +343,7 @@ static struct i2c_driver saa7185_driver = {
.driver = {
.name = "saa7185",
},
- .probe = saa7185_probe,
+ .probe_new = saa7185_probe,
.remove = saa7185_remove,
.id_table = saa7185_id,
};
diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c
index 927a9ec41463..eef6c8a7c9c9 100644
--- a/drivers/media/i2c/sony-btf-mpx.c
+++ b/drivers/media/i2c/sony-btf-mpx.c
@@ -331,8 +331,7 @@ static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
/* --------------------------------------------------------------------------*/
-static int sony_btf_mpx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sony_btf_mpx_probe(struct i2c_client *client)
{
struct sony_btf_mpx *t;
struct v4l2_subdev *sd;
@@ -376,7 +375,7 @@ static struct i2c_driver sony_btf_mpx_driver = {
.driver = {
.name = "sony-btf-mpx",
},
- .probe = sony_btf_mpx_probe,
+ .probe_new = sony_btf_mpx_probe,
.remove = sony_btf_mpx_remove,
.id_table = sony_btf_mpx_id,
};
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index ff18693beb5c..a83c8bf1c5dd 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -675,8 +675,7 @@ static int sr030pc30_detect(struct i2c_client *client)
}
-static int sr030pc30_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sr030pc30_probe(struct i2c_client *client)
{
struct sr030pc30_info *info;
struct v4l2_subdev *sd;
@@ -751,7 +750,7 @@ static struct i2c_driver sr030pc30_i2c_driver = {
.driver = {
.name = MODULE_NAME
},
- .probe = sr030pc30_probe,
+ .probe_new = sr030pc30_probe,
.remove = sr030pc30_remove,
.id_table = sr030pc30_id,
};
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c
new file mode 100644
index 000000000000..826baf4e064d
--- /dev/null
+++ b/drivers/media/i2c/st-vgxy61.c
@@ -0,0 +1,1963 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for VGXY61 global shutter sensor family driver
+ *
+ * Copyright (C) 2022 STMicroelectronics SA
+ */
+
+#include <asm-generic/unaligned.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define VGXY61_REG_8BIT(n) ((1 << 16) | (n))
+#define VGXY61_REG_16BIT(n) ((2 << 16) | (n))
+#define VGXY61_REG_32BIT(n) ((4 << 16) | (n))
+#define VGXY61_REG_SIZE_SHIFT 16
+#define VGXY61_REG_ADDR_MASK 0xffff
+
+#define VGXY61_REG_MODEL_ID VGXY61_REG_16BIT(0x0000)
+#define VG5661_MODEL_ID 0x5661
+#define VG5761_MODEL_ID 0x5761
+#define VGXY61_REG_REVISION VGXY61_REG_16BIT(0x0002)
+#define VGXY61_REG_FWPATCH_REVISION VGXY61_REG_16BIT(0x0014)
+#define VGXY61_REG_FWPATCH_START_ADDR VGXY61_REG_8BIT(0x2000)
+#define VGXY61_REG_SYSTEM_FSM VGXY61_REG_8BIT(0x0020)
+#define VGXY61_SYSTEM_FSM_SW_STBY 0x03
+#define VGXY61_SYSTEM_FSM_STREAMING 0x04
+#define VGXY61_REG_NVM VGXY61_REG_8BIT(0x0023)
+#define VGXY61_NVM_OK 0x04
+#define VGXY61_REG_STBY VGXY61_REG_8BIT(0x0201)
+#define VGXY61_STBY_NO_REQ 0
+#define VGXY61_STBY_REQ_TMP_READ BIT(2)
+#define VGXY61_REG_STREAMING VGXY61_REG_8BIT(0x0202)
+#define VGXY61_STREAMING_NO_REQ 0
+#define VGXY61_STREAMING_REQ_STOP BIT(0)
+#define VGXY61_STREAMING_REQ_START BIT(1)
+#define VGXY61_REG_EXT_CLOCK VGXY61_REG_32BIT(0x0220)
+#define VGXY61_REG_CLK_PLL_PREDIV VGXY61_REG_8BIT(0x0224)
+#define VGXY61_REG_CLK_SYS_PLL_MULT VGXY61_REG_8BIT(0x0225)
+#define VGXY61_REG_GPIO_0_CTRL VGXY61_REG_8BIT(0x0236)
+#define VGXY61_REG_GPIO_1_CTRL VGXY61_REG_8BIT(0x0237)
+#define VGXY61_REG_GPIO_2_CTRL VGXY61_REG_8BIT(0x0238)
+#define VGXY61_REG_GPIO_3_CTRL VGXY61_REG_8BIT(0x0239)
+#define VGXY61_REG_SIGNALS_POLARITY_CTRL VGXY61_REG_8BIT(0x023b)
+#define VGXY61_REG_LINE_LENGTH VGXY61_REG_16BIT(0x0300)
+#define VGXY61_REG_ORIENTATION VGXY61_REG_8BIT(0x0302)
+#define VGXY61_REG_VT_CTRL VGXY61_REG_8BIT(0x0304)
+#define VGXY61_REG_FORMAT_CTRL VGXY61_REG_8BIT(0x0305)
+#define VGXY61_REG_OIF_CTRL VGXY61_REG_16BIT(0x0306)
+#define VGXY61_REG_OIF_ROI0_CTRL VGXY61_REG_8BIT(0x030a)
+#define VGXY61_REG_ROI0_START_H VGXY61_REG_16BIT(0x0400)
+#define VGXY61_REG_ROI0_START_V VGXY61_REG_16BIT(0x0402)
+#define VGXY61_REG_ROI0_END_H VGXY61_REG_16BIT(0x0404)
+#define VGXY61_REG_ROI0_END_V VGXY61_REG_16BIT(0x0406)
+#define VGXY61_REG_PATGEN_CTRL VGXY61_REG_32BIT(0x0440)
+#define VGXY61_PATGEN_LONG_ENABLE BIT(16)
+#define VGXY61_PATGEN_SHORT_ENABLE BIT(0)
+#define VGXY61_PATGEN_LONG_TYPE_SHIFT 18
+#define VGXY61_PATGEN_SHORT_TYPE_SHIFT 4
+#define VGXY61_REG_FRAME_CONTENT_CTRL VGXY61_REG_8BIT(0x0478)
+#define VGXY61_REG_COARSE_EXPOSURE_LONG VGXY61_REG_16BIT(0x0500)
+#define VGXY61_REG_COARSE_EXPOSURE_SHORT VGXY61_REG_16BIT(0x0504)
+#define VGXY61_REG_ANALOG_GAIN VGXY61_REG_8BIT(0x0508)
+#define VGXY61_REG_DIGITAL_GAIN_LONG VGXY61_REG_16BIT(0x050a)
+#define VGXY61_REG_DIGITAL_GAIN_SHORT VGXY61_REG_16BIT(0x0512)
+#define VGXY61_REG_FRAME_LENGTH VGXY61_REG_16BIT(0x051a)
+#define VGXY61_REG_SIGNALS_CTRL VGXY61_REG_16BIT(0x0522)
+#define VGXY61_SIGNALS_GPIO_ID_SHIFT 4
+#define VGXY61_REG_READOUT_CTRL VGXY61_REG_8BIT(0x0530)
+#define VGXY61_REG_HDR_CTRL VGXY61_REG_8BIT(0x0532)
+#define VGXY61_REG_PATGEN_LONG_DATA_GR VGXY61_REG_16BIT(0x092c)
+#define VGXY61_REG_PATGEN_LONG_DATA_R VGXY61_REG_16BIT(0x092e)
+#define VGXY61_REG_PATGEN_LONG_DATA_B VGXY61_REG_16BIT(0x0930)
+#define VGXY61_REG_PATGEN_LONG_DATA_GB VGXY61_REG_16BIT(0x0932)
+#define VGXY61_REG_PATGEN_SHORT_DATA_GR VGXY61_REG_16BIT(0x0950)
+#define VGXY61_REG_PATGEN_SHORT_DATA_R VGXY61_REG_16BIT(0x0952)
+#define VGXY61_REG_PATGEN_SHORT_DATA_B VGXY61_REG_16BIT(0x0954)
+#define VGXY61_REG_PATGEN_SHORT_DATA_GB VGXY61_REG_16BIT(0x0956)
+#define VGXY61_REG_BYPASS_CTRL VGXY61_REG_8BIT(0x0a60)
+
+#define VGX661_WIDTH 1464
+#define VGX661_HEIGHT 1104
+#define VGX761_WIDTH 1944
+#define VGX761_HEIGHT 1204
+#define VGX661_DEFAULT_MODE 1
+#define VGX761_DEFAULT_MODE 1
+#define VGX661_SHORT_ROT_TERM 93
+#define VGX761_SHORT_ROT_TERM 90
+#define VGXY61_EXPOS_ROT_TERM 66
+#define VGXY61_WRITE_MULTIPLE_CHUNK_MAX 16
+#define VGXY61_NB_GPIOS 4
+#define VGXY61_NB_POLARITIES 5
+#define VGXY61_FRAME_LENGTH_DEF 1313
+#define VGXY61_MIN_FRAME_LENGTH 1288
+#define VGXY61_MIN_EXPOSURE 10
+#define VGXY61_HDR_LINEAR_RATIO 10
+#define VGXY61_TIMEOUT_MS 500
+#define VGXY61_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8
+
+#define VGXY61_FWPATCH_REVISION_MAJOR 2
+#define VGXY61_FWPATCH_REVISION_MINOR 0
+#define VGXY61_FWPATCH_REVISION_MICRO 5
+
+static const u8 patch_array[] = {
+ 0xbf, 0x00, 0x05, 0x20, 0x06, 0x01, 0xe0, 0xe0, 0x04, 0x80, 0xe6, 0x45,
+ 0xed, 0x6f, 0xfe, 0xff, 0x14, 0x80, 0x1f, 0x84, 0x10, 0x42, 0x05, 0x7c,
+ 0x01, 0xc4, 0x1e, 0x80, 0xb6, 0x42, 0x00, 0xe0, 0x1e, 0x82, 0x1e, 0xc0,
+ 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x86, 0x0d, 0x70, 0xe1,
+ 0x04, 0x98, 0x15, 0x00, 0x28, 0xe0, 0x14, 0x02, 0x08, 0xfc, 0x15, 0x40,
+ 0x28, 0xe0, 0x98, 0x58, 0xe0, 0xef, 0x04, 0x98, 0x0e, 0x04, 0x00, 0xf0,
+ 0x15, 0x00, 0x28, 0xe0, 0x19, 0xc8, 0x15, 0x40, 0x28, 0xe0, 0xc6, 0x41,
+ 0xfc, 0xe0, 0x14, 0x80, 0x1f, 0x84, 0x14, 0x02, 0xa0, 0xfc, 0x1e, 0x80,
+ 0x14, 0x80, 0x14, 0x02, 0x80, 0xfb, 0x14, 0x02, 0xe0, 0xfc, 0x1e, 0x80,
+ 0x14, 0xc0, 0x1f, 0x84, 0x14, 0x02, 0xa4, 0xfc, 0x1e, 0xc0, 0x14, 0xc0,
+ 0x14, 0x02, 0x80, 0xfb, 0x14, 0x02, 0xe4, 0xfc, 0x1e, 0xc0, 0x0c, 0x0c,
+ 0x00, 0xf2, 0x93, 0xdd, 0x86, 0x00, 0xf8, 0xe0, 0x04, 0x80, 0xc6, 0x03,
+ 0x70, 0xe1, 0x0e, 0x84, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa,
+ 0x6b, 0x80, 0x06, 0x40, 0x6c, 0xe1, 0x04, 0x80, 0x09, 0x00, 0xe0, 0xe0,
+ 0x0b, 0xa1, 0x95, 0x84, 0x05, 0x0c, 0x1c, 0xe0, 0x86, 0x02, 0xf9, 0x60,
+ 0xe0, 0xcf, 0x78, 0x6e, 0x80, 0xef, 0x25, 0x0c, 0x18, 0xe0, 0x05, 0x4c,
+ 0x1c, 0xe0, 0x86, 0x02, 0xf9, 0x60, 0xe0, 0xcf, 0x0b, 0x84, 0xd8, 0x6d,
+ 0x80, 0xef, 0x05, 0x4c, 0x18, 0xe0, 0x04, 0xd8, 0x0b, 0xa5, 0x95, 0x84,
+ 0x05, 0x0c, 0x2c, 0xe0, 0x06, 0x02, 0x01, 0x60, 0xe0, 0xce, 0x18, 0x6d,
+ 0x80, 0xef, 0x25, 0x0c, 0x30, 0xe0, 0x05, 0x4c, 0x2c, 0xe0, 0x06, 0x02,
+ 0x01, 0x60, 0xe0, 0xce, 0x0b, 0x84, 0x78, 0x6c, 0x80, 0xef, 0x05, 0x4c,
+ 0x30, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x46, 0x01, 0x70, 0xe1,
+ 0x08, 0x80, 0x0b, 0xa1, 0x08, 0x5c, 0x00, 0xda, 0x06, 0x01, 0x68, 0xe1,
+ 0x04, 0x80, 0x4a, 0x40, 0x84, 0xe0, 0x08, 0x5c, 0x00, 0x9a, 0x06, 0x01,
+ 0xe0, 0xe0, 0x04, 0x80, 0x15, 0x00, 0x60, 0xe0, 0x19, 0xc4, 0x15, 0x40,
+ 0x60, 0xe0, 0x15, 0x00, 0x78, 0xe0, 0x19, 0xc4, 0x15, 0x40, 0x78, 0xe0,
+ 0x93, 0xdd, 0xc3, 0xc1, 0x46, 0x01, 0x70, 0xe1, 0x08, 0x80, 0x0b, 0xa1,
+ 0x08, 0x5c, 0x00, 0xda, 0x06, 0x01, 0x68, 0xe1, 0x04, 0x80, 0x4a, 0x40,
+ 0x84, 0xe0, 0x08, 0x5c, 0x00, 0x9a, 0x06, 0x01, 0xe0, 0xe0, 0x14, 0x80,
+ 0x25, 0x02, 0x54, 0xe0, 0x29, 0xc4, 0x25, 0x42, 0x54, 0xe0, 0x24, 0x80,
+ 0x35, 0x04, 0x6c, 0xe0, 0x39, 0xc4, 0x35, 0x44, 0x6c, 0xe0, 0x25, 0x02,
+ 0x64, 0xe0, 0x29, 0xc4, 0x25, 0x42, 0x64, 0xe0, 0x04, 0x80, 0x15, 0x00,
+ 0x7c, 0xe0, 0x19, 0xc4, 0x15, 0x40, 0x7c, 0xe0, 0x93, 0xdd, 0xc3, 0xc1,
+ 0x4c, 0x04, 0x7c, 0xfa, 0x86, 0x40, 0x98, 0xe0, 0x14, 0x80, 0x1b, 0xa1,
+ 0x06, 0x00, 0x00, 0xc0, 0x08, 0x42, 0x38, 0xdc, 0x08, 0x64, 0xa0, 0xef,
+ 0x86, 0x42, 0x3c, 0xe0, 0x68, 0x49, 0x80, 0xef, 0x6b, 0x80, 0x78, 0x53,
+ 0xc8, 0xef, 0xc6, 0x54, 0x6c, 0xe1, 0x7b, 0x80, 0xb5, 0x14, 0x0c, 0xf8,
+ 0x05, 0x14, 0x14, 0xf8, 0x1a, 0xac, 0x8a, 0x80, 0x0b, 0x90, 0x38, 0x55,
+ 0x80, 0xef, 0x1a, 0xae, 0x17, 0xc2, 0x03, 0x82, 0x88, 0x65, 0x80, 0xef,
+ 0x1b, 0x80, 0x0b, 0x8e, 0x68, 0x65, 0x80, 0xef, 0x9b, 0x80, 0x0b, 0x8c,
+ 0x08, 0x65, 0x80, 0xef, 0x6b, 0x80, 0x0b, 0x92, 0x1b, 0x8c, 0x98, 0x64,
+ 0x80, 0xef, 0x1a, 0xec, 0x9b, 0x80, 0x0b, 0x90, 0x95, 0x54, 0x10, 0xe0,
+ 0xa8, 0x53, 0x80, 0xef, 0x1a, 0xee, 0x17, 0xc2, 0x03, 0x82, 0xf8, 0x63,
+ 0x80, 0xef, 0x1b, 0x80, 0x0b, 0x8e, 0xd8, 0x63, 0x80, 0xef, 0x1b, 0x8c,
+ 0x68, 0x63, 0x80, 0xef, 0x6b, 0x80, 0x0b, 0x92, 0x65, 0x54, 0x14, 0xe0,
+ 0x08, 0x65, 0x84, 0xef, 0x68, 0x63, 0x80, 0xef, 0x7b, 0x80, 0x0b, 0x8c,
+ 0xa8, 0x64, 0x84, 0xef, 0x08, 0x63, 0x80, 0xef, 0x14, 0xe8, 0x46, 0x44,
+ 0x94, 0xe1, 0x24, 0x88, 0x4a, 0x4e, 0x04, 0xe0, 0x14, 0xea, 0x1a, 0x04,
+ 0x08, 0xe0, 0x0a, 0x40, 0x84, 0xed, 0x0c, 0x04, 0x00, 0xe2, 0x4a, 0x40,
+ 0x04, 0xe0, 0x19, 0x16, 0xc0, 0xe0, 0x0a, 0x40, 0x84, 0xed, 0x21, 0x54,
+ 0x60, 0xe0, 0x0c, 0x04, 0x00, 0xe2, 0x1b, 0xa5, 0x0e, 0xea, 0x01, 0x89,
+ 0x21, 0x54, 0x64, 0xe0, 0x7e, 0xe8, 0x65, 0x82, 0x1b, 0xa7, 0x26, 0x00,
+ 0x00, 0x80, 0xa5, 0x82, 0x1b, 0xa9, 0x65, 0x82, 0x1b, 0xa3, 0x01, 0x85,
+ 0x16, 0x00, 0x00, 0xc0, 0x01, 0x54, 0x04, 0xf8, 0x06, 0xaa, 0x01, 0x83,
+ 0x06, 0xa8, 0x65, 0x81, 0x06, 0xa8, 0x01, 0x54, 0x04, 0xf8, 0x01, 0x83,
+ 0x06, 0xaa, 0x09, 0x14, 0x18, 0xf8, 0x0b, 0xa1, 0x05, 0x84, 0xc6, 0x42,
+ 0xd4, 0xe0, 0x14, 0x84, 0x01, 0x83, 0x01, 0x54, 0x60, 0xe0, 0x01, 0x54,
+ 0x64, 0xe0, 0x0b, 0x02, 0x90, 0xe0, 0x10, 0x02, 0x90, 0xe5, 0x01, 0x54,
+ 0x88, 0xe0, 0xb5, 0x81, 0xc6, 0x40, 0xd4, 0xe0, 0x14, 0x80, 0x0b, 0x02,
+ 0xe0, 0xe4, 0x10, 0x02, 0x31, 0x66, 0x02, 0xc0, 0x01, 0x54, 0x88, 0xe0,
+ 0x1a, 0x84, 0x29, 0x14, 0x10, 0xe0, 0x1c, 0xaa, 0x2b, 0xa1, 0xf5, 0x82,
+ 0x25, 0x14, 0x10, 0xf8, 0x2b, 0x04, 0xa8, 0xe0, 0x20, 0x44, 0x0d, 0x70,
+ 0x03, 0xc0, 0x2b, 0xa1, 0x04, 0x00, 0x80, 0x9a, 0x02, 0x40, 0x84, 0x90,
+ 0x03, 0x54, 0x04, 0x80, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x00, 0x00,
+ 0x02, 0xa9, 0x00, 0x00, 0x64, 0x4a, 0x40, 0x00, 0x08, 0x2d, 0x58, 0xe0,
+ 0xa8, 0x98, 0x40, 0x00, 0x28, 0x07, 0x34, 0xe0, 0x05, 0xb9, 0x00, 0x00,
+ 0x28, 0x00, 0x41, 0x05, 0x88, 0x00, 0x41, 0x3c, 0x98, 0x00, 0x41, 0x52,
+ 0x04, 0x01, 0x41, 0x79, 0x3c, 0x01, 0x41, 0x6a, 0x3d, 0xfe, 0x00, 0x00,
+};
+
+static const char * const vgxy61_test_pattern_menu[] = {
+ "Disabled",
+ "Solid",
+ "Colorbar",
+ "Gradbar",
+ "Hgrey",
+ "Vgrey",
+ "Dgrey",
+ "PN28",
+};
+
+static const char * const vgxy61_hdr_mode_menu[] = {
+ "HDR linearize",
+ "HDR substraction",
+ "No HDR",
+};
+
+static const char * const vgxy61_supply_name[] = {
+ "VCORE",
+ "VDDIO",
+ "VANA",
+};
+
+static const s64 link_freq[] = {
+ /*
+ * MIPI output freq is 804Mhz / 2, as it uses both rising edge and
+ * falling edges to send data
+ */
+ 402000000ULL
+};
+
+enum vgxy61_bin_mode {
+ VGXY61_BIN_MODE_NORMAL,
+ VGXY61_BIN_MODE_DIGITAL_X2,
+ VGXY61_BIN_MODE_DIGITAL_X4,
+};
+
+enum vgxy61_hdr_mode {
+ VGXY61_HDR_LINEAR,
+ VGXY61_HDR_SUB,
+ VGXY61_NO_HDR,
+};
+
+enum vgxy61_strobe_mode {
+ VGXY61_STROBE_DISABLED,
+ VGXY61_STROBE_LONG,
+ VGXY61_STROBE_ENABLED,
+};
+
+struct vgxy61_mode_info {
+ u32 width;
+ u32 height;
+ enum vgxy61_bin_mode bin_mode;
+ struct v4l2_rect crop;
+};
+
+struct vgxy61_fmt_desc {
+ u32 code;
+ u8 bpp;
+ u8 data_type;
+};
+
+static const struct vgxy61_fmt_desc vgxy61_supported_codes[] = {
+ {
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .bpp = 8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ },
+ {
+ .code = MEDIA_BUS_FMT_Y10_1X10,
+ .bpp = 10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_Y12_1X12,
+ .bpp = 12,
+ .data_type = MIPI_CSI2_DT_RAW12,
+ },
+ {
+ .code = MEDIA_BUS_FMT_Y14_1X14,
+ .bpp = 14,
+ .data_type = MIPI_CSI2_DT_RAW14,
+ },
+ {
+ .code = MEDIA_BUS_FMT_Y16_1X16,
+ .bpp = 16,
+ .data_type = MIPI_CSI2_DT_RAW16,
+ },
+};
+
+static const struct vgxy61_mode_info vgx661_mode_data[] = {
+ {
+ .width = VGX661_WIDTH,
+ .height = VGX661_HEIGHT,
+ .bin_mode = VGXY61_BIN_MODE_NORMAL,
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = VGX661_WIDTH,
+ .height = VGX661_HEIGHT,
+ },
+ },
+ {
+ .width = 1280,
+ .height = 720,
+ .bin_mode = VGXY61_BIN_MODE_NORMAL,
+ .crop = {
+ .left = 92,
+ .top = 192,
+ .width = 1280,
+ .height = 720,
+ },
+ },
+ {
+ .width = 640,
+ .height = 480,
+ .bin_mode = VGXY61_BIN_MODE_DIGITAL_X2,
+ .crop = {
+ .left = 92,
+ .top = 72,
+ .width = 1280,
+ .height = 960,
+ },
+ },
+ {
+ .width = 320,
+ .height = 240,
+ .bin_mode = VGXY61_BIN_MODE_DIGITAL_X4,
+ .crop = {
+ .left = 92,
+ .top = 72,
+ .width = 1280,
+ .height = 960,
+ },
+ },
+};
+
+static const struct vgxy61_mode_info vgx761_mode_data[] = {
+ {
+ .width = VGX761_WIDTH,
+ .height = VGX761_HEIGHT,
+ .bin_mode = VGXY61_BIN_MODE_NORMAL,
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = VGX761_WIDTH,
+ .height = VGX761_HEIGHT,
+ },
+ },
+ {
+ .width = 1920,
+ .height = 1080,
+ .bin_mode = VGXY61_BIN_MODE_NORMAL,
+ .crop = {
+ .left = 12,
+ .top = 62,
+ .width = 1920,
+ .height = 1080,
+ },
+ },
+ {
+ .width = 1280,
+ .height = 720,
+ .bin_mode = VGXY61_BIN_MODE_NORMAL,
+ .crop = {
+ .left = 332,
+ .top = 242,
+ .width = 1280,
+ .height = 720,
+ },
+ },
+ {
+ .width = 640,
+ .height = 480,
+ .bin_mode = VGXY61_BIN_MODE_DIGITAL_X2,
+ .crop = {
+ .left = 332,
+ .top = 122,
+ .width = 1280,
+ .height = 960,
+ },
+ },
+ {
+ .width = 320,
+ .height = 240,
+ .bin_mode = VGXY61_BIN_MODE_DIGITAL_X4,
+ .crop = {
+ .left = 332,
+ .top = 122,
+ .width = 1280,
+ .height = 960,
+ },
+ },
+};
+
+struct vgxy61_dev {
+ struct i2c_client *i2c_client;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(vgxy61_supply_name)];
+ struct gpio_desc *reset_gpio;
+ struct clk *xclk;
+ u32 clk_freq;
+ u16 id;
+ u16 sensor_width;
+ u16 sensor_height;
+ u16 oif_ctrl;
+ unsigned int nb_of_lane;
+ u32 data_rate_in_mbps;
+ u32 pclk;
+ u16 line_length;
+ u16 rot_term;
+ bool gpios_polarity;
+ /* Lock to protect all members below */
+ struct mutex lock;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *pixel_rate_ctrl;
+ struct v4l2_ctrl *expo_ctrl;
+ struct v4l2_ctrl *vblank_ctrl;
+ struct v4l2_ctrl *vflip_ctrl;
+ struct v4l2_ctrl *hflip_ctrl;
+ bool streaming;
+ struct v4l2_mbus_framefmt fmt;
+ const struct vgxy61_mode_info *sensor_modes;
+ unsigned int sensor_modes_nb;
+ const struct vgxy61_mode_info *default_mode;
+ const struct vgxy61_mode_info *current_mode;
+ bool hflip;
+ bool vflip;
+ enum vgxy61_hdr_mode hdr;
+ u16 expo_long;
+ u16 expo_short;
+ u16 expo_max;
+ u16 expo_min;
+ u16 vblank;
+ u16 vblank_min;
+ u16 frame_length;
+ u16 digital_gain;
+ u8 analog_gain;
+ enum vgxy61_strobe_mode strobe_mode;
+ u32 pattern;
+};
+
+static u8 get_bpp_by_code(__u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vgxy61_supported_codes); i++) {
+ if (vgxy61_supported_codes[i].code == code)
+ return vgxy61_supported_codes[i].bpp;
+ }
+ /* Should never happen */
+ WARN(1, "Unsupported code %d. default to 8 bpp", code);
+ return 8;
+}
+
+static u8 get_data_type_by_code(__u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vgxy61_supported_codes); i++) {
+ if (vgxy61_supported_codes[i].code == code)
+ return vgxy61_supported_codes[i].data_type;
+ }
+ /* Should never happen */
+ WARN(1, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type",
+ code);
+ return MIPI_CSI2_DT_RAW8;
+}
+
+static void compute_pll_parameters_by_freq(u32 freq, u8 *prediv, u8 *mult)
+{
+ const unsigned int predivs[] = {1, 2, 4};
+ unsigned int i;
+
+ /*
+ * Freq range is [6Mhz-27Mhz] already checked.
+ * Output of divider should be in [6Mhz-12Mhz[.
+ */
+ for (i = 0; i < ARRAY_SIZE(predivs); i++) {
+ *prediv = predivs[i];
+ if (freq / *prediv < 12 * HZ_PER_MHZ)
+ break;
+ }
+ WARN_ON(i == ARRAY_SIZE(predivs));
+
+ /*
+ * Target freq is 804Mhz. Don't change this as it will impact image
+ * quality.
+ */
+ *mult = ((804 * HZ_PER_MHZ) * (*prediv) + freq / 2) / freq;
+}
+
+static s32 get_pixel_rate(struct vgxy61_dev *sensor)
+{
+ return div64_u64((u64)sensor->data_rate_in_mbps * sensor->nb_of_lane,
+ get_bpp_by_code(sensor->fmt.code));
+}
+
+static inline struct vgxy61_dev *to_vgxy61_dev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct vgxy61_dev, sd);
+}
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct vgxy61_dev,
+ ctrl_handler)->sd;
+}
+
+static unsigned int get_chunk_size(struct vgxy61_dev *sensor)
+{
+ struct i2c_adapter *adapter = sensor->i2c_client->adapter;
+ int max_write_len = VGXY61_WRITE_MULTIPLE_CHUNK_MAX;
+
+ if (adapter->quirks && adapter->quirks->max_write_len)
+ max_write_len = adapter->quirks->max_write_len - 2;
+
+ max_write_len = min(max_write_len, VGXY61_WRITE_MULTIPLE_CHUNK_MAX);
+
+ return max(max_write_len, 1);
+}
+
+static int vgxy61_read_multiple(struct vgxy61_dev *sensor, u32 reg,
+ unsigned int len)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ u8 val[sizeof(u32)] = {0};
+ int ret;
+
+ if (len > sizeof(u32))
+ return -EINVAL;
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags;
+ msg[0].buf = buf;
+ msg[0].len = sizeof(buf);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].buf = val;
+ msg[1].len = len;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n",
+ __func__, client->addr, reg, ret);
+ return ret;
+ }
+
+ return get_unaligned_le32(val);
+}
+
+static inline int vgxy61_read_reg(struct vgxy61_dev *sensor, u32 reg)
+{
+ return vgxy61_read_multiple(sensor, reg & VGXY61_REG_ADDR_MASK,
+ (reg >> VGXY61_REG_SIZE_SHIFT) & 7);
+}
+
+static int vgxy61_write_multiple(struct vgxy61_dev *sensor, u32 reg,
+ const u8 *data, unsigned int len, int *err)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ struct i2c_msg msg;
+ u8 buf[VGXY61_WRITE_MULTIPLE_CHUNK_MAX + 2];
+ unsigned int i;
+ int ret;
+
+ if (err && *err)
+ return *err;
+
+ if (len > VGXY61_WRITE_MULTIPLE_CHUNK_MAX)
+ return -EINVAL;
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ for (i = 0; i < len; i++)
+ buf[i + 2] = data[i];
+
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.buf = buf;
+ msg.len = len + 2;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n",
+ __func__, reg, ret);
+ if (err)
+ *err = ret;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vgxy61_write_array(struct vgxy61_dev *sensor, u32 reg,
+ unsigned int nb, const u8 *array)
+{
+ const unsigned int chunk_size = get_chunk_size(sensor);
+ int ret;
+ unsigned int sz;
+
+ while (nb) {
+ sz = min(nb, chunk_size);
+ ret = vgxy61_write_multiple(sensor, reg, array, sz, NULL);
+ if (ret < 0)
+ return ret;
+ nb -= sz;
+ reg += sz;
+ array += sz;
+ }
+
+ return 0;
+}
+
+static inline int vgxy61_write_reg(struct vgxy61_dev *sensor, u32 reg, u32 val,
+ int *err)
+{
+ return vgxy61_write_multiple(sensor, reg & VGXY61_REG_ADDR_MASK,
+ (u8 *)&val,
+ (reg >> VGXY61_REG_SIZE_SHIFT) & 7, err);
+}
+
+static int vgxy61_poll_reg(struct vgxy61_dev *sensor, u32 reg, u8 poll_val,
+ unsigned int timeout_ms)
+{
+ const unsigned int loop_delay_ms = 10;
+ int ret;
+
+ return read_poll_timeout(vgxy61_read_reg, ret,
+ ((ret < 0) || (ret == poll_val)),
+ loop_delay_ms * 1000, timeout_ms * 1000,
+ false, sensor, reg);
+}
+
+static int vgxy61_wait_state(struct vgxy61_dev *sensor, int state,
+ unsigned int timeout_ms)
+{
+ return vgxy61_poll_reg(sensor, VGXY61_REG_SYSTEM_FSM, state,
+ timeout_ms);
+}
+
+static int vgxy61_check_bw(struct vgxy61_dev *sensor)
+{
+ /*
+ * Simplification of time needed to send short packets and for the MIPI
+ * to add transition times (EoT, LPS, and SoT packet delimiters) needed
+ * by the protocol to go in low power between 2 packets of data. This
+ * is a mipi IP constant for the sensor.
+ */
+ const unsigned int mipi_margin = 1056;
+ unsigned int binning_scale = sensor->current_mode->crop.height /
+ sensor->current_mode->height;
+ u8 bpp = get_bpp_by_code(sensor->fmt.code);
+ unsigned int max_bit_per_line;
+ unsigned int bit_per_line;
+ u64 line_rate;
+
+ line_rate = sensor->nb_of_lane * (u64)sensor->data_rate_in_mbps *
+ sensor->line_length;
+ max_bit_per_line = div64_u64(line_rate, sensor->pclk) - mipi_margin;
+ bit_per_line = (bpp * sensor->current_mode->width) / binning_scale;
+
+ return bit_per_line > max_bit_per_line ? -EINVAL : 0;
+}
+
+static int vgxy61_apply_exposure(struct vgxy61_dev *sensor)
+{
+ int ret = 0;
+
+ /* We first set expo to zero to avoid forbidden parameters couple */
+ vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT, 0, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_LONG,
+ sensor->expo_long, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT,
+ sensor->expo_short, &ret);
+
+ return ret;
+}
+
+static int vgxy61_get_regulators(struct vgxy61_dev *sensor)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vgxy61_supply_name); i++)
+ sensor->supplies[i].supply = vgxy61_supply_name[i];
+
+ return devm_regulator_bulk_get(&sensor->i2c_client->dev,
+ ARRAY_SIZE(vgxy61_supply_name),
+ sensor->supplies);
+}
+
+static int vgxy61_apply_reset(struct vgxy61_dev *sensor)
+{
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ usleep_range(5000, 10000);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
+ usleep_range(5000, 10000);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ usleep_range(40000, 100000);
+ return vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
+ VGXY61_TIMEOUT_MS);
+}
+
+static void vgxy61_fill_framefmt(struct vgxy61_dev *sensor,
+ const struct vgxy61_mode_info *mode,
+ struct v4l2_mbus_framefmt *fmt, u32 code)
+{
+ fmt->code = code;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->colorspace = V4L2_COLORSPACE_RAW;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int vgxy61_try_fmt_internal(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt,
+ const struct vgxy61_mode_info **new_mode)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ const struct vgxy61_mode_info *mode = sensor->sensor_modes;
+ unsigned int index;
+
+ for (index = 0; index < ARRAY_SIZE(vgxy61_supported_codes); index++) {
+ if (vgxy61_supported_codes[index].code == fmt->code)
+ break;
+ }
+ if (index == ARRAY_SIZE(vgxy61_supported_codes))
+ index = 0;
+
+ mode = v4l2_find_nearest_size(sensor->sensor_modes,
+ sensor->sensor_modes_nb, width, height,
+ fmt->width, fmt->height);
+ if (new_mode)
+ *new_mode = mode;
+
+ vgxy61_fill_framefmt(sensor, mode, fmt,
+ vgxy61_supported_codes[index].code);
+
+ return 0;
+}
+
+static int vgxy61_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = sensor->current_mode->crop;
+ return 0;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = sensor->sensor_width;
+ sel->r.height = sensor->sensor_height;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int vgxy61_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(vgxy61_supported_codes))
+ return -EINVAL;
+
+ code->code = vgxy61_supported_codes[code->index].code;
+
+ return 0;
+}
+
+static int vgxy61_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ struct v4l2_mbus_framefmt *fmt;
+
+ mutex_lock(&sensor->lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
+ format->pad);
+ else
+ fmt = &sensor->fmt;
+
+ format->format = *fmt;
+
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+
+static u16 vgxy61_get_vblank_min(struct vgxy61_dev *sensor,
+ enum vgxy61_hdr_mode hdr)
+{
+ u16 min_vblank = VGXY61_MIN_FRAME_LENGTH -
+ sensor->current_mode->crop.height;
+ /* Ensure the first rule of thumb can't be negative */
+ u16 min_vblank_hdr = VGXY61_MIN_EXPOSURE + sensor->rot_term + 1;
+
+ if (hdr != VGXY61_NO_HDR)
+ return max(min_vblank, min_vblank_hdr);
+ return min_vblank;
+}
+
+static int vgxy61_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+
+ if (fse->index >= sensor->sensor_modes_nb)
+ return -EINVAL;
+
+ fse->min_width = sensor->sensor_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = sensor->sensor_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int vgxy61_update_analog_gain(struct vgxy61_dev *sensor, u32 target)
+{
+ sensor->analog_gain = target;
+
+ if (sensor->streaming)
+ return vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN, target,
+ NULL);
+ return 0;
+}
+
+static int vgxy61_apply_digital_gain(struct vgxy61_dev *sensor,
+ u32 digital_gain)
+{
+ int ret = 0;
+
+ /*
+ * For a monochrome version, configuring DIGITAL_GAIN_LONG_CH0 and
+ * DIGITAL_GAIN_SHORT_CH0 is enough to configure the gain of all
+ * four sub pixels.
+ */
+ vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_LONG, digital_gain,
+ &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_SHORT, digital_gain,
+ &ret);
+
+ return ret;
+}
+
+static int vgxy61_update_digital_gain(struct vgxy61_dev *sensor, u32 target)
+{
+ sensor->digital_gain = target;
+
+ if (sensor->streaming)
+ return vgxy61_apply_digital_gain(sensor, sensor->digital_gain);
+ return 0;
+}
+
+static int vgxy61_apply_patgen(struct vgxy61_dev *sensor, u32 index)
+{
+ static const u8 index2val[] = {
+ 0x0, 0x1, 0x2, 0x3, 0x10, 0x11, 0x12, 0x13
+ };
+ u32 pattern = index2val[index];
+ u32 reg = (pattern << VGXY61_PATGEN_LONG_TYPE_SHIFT) |
+ (pattern << VGXY61_PATGEN_SHORT_TYPE_SHIFT);
+
+ if (pattern)
+ reg |= VGXY61_PATGEN_LONG_ENABLE | VGXY61_PATGEN_SHORT_ENABLE;
+ return vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_CTRL, reg, NULL);
+}
+
+static int vgxy61_update_patgen(struct vgxy61_dev *sensor, u32 pattern)
+{
+ sensor->pattern = pattern;
+
+ if (sensor->streaming)
+ return vgxy61_apply_patgen(sensor, sensor->pattern);
+ return 0;
+}
+
+static int vgxy61_apply_gpiox_strobe_mode(struct vgxy61_dev *sensor,
+ enum vgxy61_strobe_mode mode,
+ unsigned int idx)
+{
+ static const u8 index2val[] = {0x0, 0x1, 0x3};
+ int reg;
+
+ reg = vgxy61_read_reg(sensor, VGXY61_REG_SIGNALS_CTRL);
+ if (reg < 0)
+ return reg;
+ reg &= ~(0xf << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT));
+ reg |= index2val[mode] << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT);
+
+ return vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_CTRL, reg, NULL);
+}
+
+static int vgxy61_update_gpios_strobe_mode(struct vgxy61_dev *sensor,
+ enum vgxy61_hdr_mode hdr)
+{
+ unsigned int i;
+ int ret;
+
+ switch (hdr) {
+ case VGXY61_HDR_LINEAR:
+ sensor->strobe_mode = VGXY61_STROBE_ENABLED;
+ break;
+ case VGXY61_HDR_SUB:
+ case VGXY61_NO_HDR:
+ sensor->strobe_mode = VGXY61_STROBE_LONG;
+ break;
+ default:
+ /* Should never happen */
+ WARN_ON(true);
+ break;
+ }
+
+ if (!sensor->streaming)
+ return 0;
+
+ for (i = 0; i < VGXY61_NB_GPIOS; i++) {
+ ret = vgxy61_apply_gpiox_strobe_mode(sensor,
+ sensor->strobe_mode,
+ i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vgxy61_update_gpios_strobe_polarity(struct vgxy61_dev *sensor,
+ bool polarity)
+{
+ int ret = 0;
+
+ if (sensor->streaming)
+ return -EBUSY;
+
+ vgxy61_write_reg(sensor, VGXY61_REG_GPIO_0_CTRL, polarity << 1, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_GPIO_1_CTRL, polarity << 1, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_GPIO_2_CTRL, polarity << 1, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_GPIO_3_CTRL, polarity << 1, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_POLARITY_CTRL, polarity,
+ &ret);
+
+ return ret;
+}
+
+static u32 vgxy61_get_expo_long_max(struct vgxy61_dev *sensor,
+ unsigned int short_expo_ratio)
+{
+ u32 first_rot_max_expo, second_rot_max_expo, third_rot_max_expo;
+
+ /* Apply sensor's rules of thumb */
+ /*
+ * Short exposure + height must be less than frame length to avoid bad
+ * pixel line at the botom of the image
+ */
+ first_rot_max_expo =
+ ((sensor->frame_length - sensor->current_mode->crop.height -
+ sensor->rot_term) * short_expo_ratio) - 1;
+
+ /*
+ * Total exposition time must be less than frame length to avoid sensor
+ * crash
+ */
+ second_rot_max_expo =
+ (((sensor->frame_length - VGXY61_EXPOS_ROT_TERM) *
+ short_expo_ratio) / (short_expo_ratio + 1)) - 1;
+
+ /*
+ * Short exposure times 71 must be less than frame length to avoid
+ * sensor crash
+ */
+ third_rot_max_expo = (sensor->frame_length / 71) * short_expo_ratio;
+
+ /* Take the minimum from all rules */
+ return min(min(first_rot_max_expo, second_rot_max_expo),
+ third_rot_max_expo);
+}
+
+static int vgxy61_update_exposure(struct vgxy61_dev *sensor, u16 new_expo_long,
+ enum vgxy61_hdr_mode hdr)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ u16 new_expo_short = 0;
+ u16 expo_short_max = 0;
+ u16 expo_long_min = VGXY61_MIN_EXPOSURE;
+ u16 expo_long_max = 0;
+
+ /* Compute short exposure according to hdr mode and long exposure */
+ switch (hdr) {
+ case VGXY61_HDR_LINEAR:
+ /*
+ * Take ratio into account for minimal exposures in
+ * VGXY61_HDR_LINEAR
+ */
+ expo_long_min = VGXY61_MIN_EXPOSURE * VGXY61_HDR_LINEAR_RATIO;
+ new_expo_long = max(expo_long_min, new_expo_long);
+
+ expo_long_max =
+ vgxy61_get_expo_long_max(sensor,
+ VGXY61_HDR_LINEAR_RATIO);
+ expo_short_max = (expo_long_max +
+ (VGXY61_HDR_LINEAR_RATIO / 2)) /
+ VGXY61_HDR_LINEAR_RATIO;
+ new_expo_short = (new_expo_long +
+ (VGXY61_HDR_LINEAR_RATIO / 2)) /
+ VGXY61_HDR_LINEAR_RATIO;
+ break;
+ case VGXY61_HDR_SUB:
+ new_expo_long = max(expo_long_min, new_expo_long);
+
+ expo_long_max = vgxy61_get_expo_long_max(sensor, 1);
+ /* Short and long are the same in VGXY61_HDR_SUB */
+ expo_short_max = expo_long_max;
+ new_expo_short = new_expo_long;
+ break;
+ case VGXY61_NO_HDR:
+ new_expo_long = max(expo_long_min, new_expo_long);
+
+ /*
+ * As short expo is 0 here, only the second rule of thumb
+ * applies, see vgxy61_get_expo_long_max for more
+ */
+ expo_long_max = sensor->frame_length - VGXY61_EXPOS_ROT_TERM;
+ break;
+ default:
+ /* Should never happen */
+ WARN_ON(true);
+ break;
+ }
+
+ /* If this happens, something is wrong with formulas */
+ WARN_ON(expo_long_min > expo_long_max);
+
+ if (new_expo_long > expo_long_max) {
+ dev_warn(&client->dev, "Exposure %d too high, clamping to %d\n",
+ new_expo_long, expo_long_max);
+ new_expo_long = expo_long_max;
+ new_expo_short = expo_short_max;
+ }
+
+ sensor->expo_long = new_expo_long;
+ sensor->expo_short = new_expo_short;
+ sensor->expo_max = expo_long_max;
+ sensor->expo_min = expo_long_min;
+
+ if (sensor->streaming)
+ return vgxy61_apply_exposure(sensor);
+ return 0;
+}
+
+static int vgxy61_apply_framelength(struct vgxy61_dev *sensor)
+{
+ return vgxy61_write_reg(sensor, VGXY61_REG_FRAME_LENGTH,
+ sensor->frame_length, NULL);
+}
+
+static int vgxy61_update_vblank(struct vgxy61_dev *sensor, u16 vblank,
+ enum vgxy61_hdr_mode hdr)
+{
+ int ret;
+
+ sensor->vblank_min = vgxy61_get_vblank_min(sensor, hdr);
+ sensor->vblank = max(sensor->vblank_min, vblank);
+ sensor->frame_length = sensor->current_mode->crop.height +
+ sensor->vblank;
+
+ /* Update exposure according to vblank */
+ ret = vgxy61_update_exposure(sensor, sensor->expo_long, hdr);
+ if (ret)
+ return ret;
+
+ if (sensor->streaming)
+ return vgxy61_apply_framelength(sensor);
+ return 0;
+}
+
+static int vgxy61_apply_hdr(struct vgxy61_dev *sensor,
+ enum vgxy61_hdr_mode index)
+{
+ static const u8 index2val[] = {0x1, 0x4, 0xa};
+
+ return vgxy61_write_reg(sensor, VGXY61_REG_HDR_CTRL, index2val[index],
+ NULL);
+}
+
+static int vgxy61_update_hdr(struct vgxy61_dev *sensor,
+ enum vgxy61_hdr_mode index)
+{
+ int ret;
+
+ /*
+ * vblank and short exposure change according to HDR mode, do it first
+ * as it can violate sensors 'rule of thumbs' and therefore will require
+ * to change the long exposure.
+ */
+ ret = vgxy61_update_vblank(sensor, sensor->vblank, index);
+ if (ret)
+ return ret;
+
+ /* Update strobe mode according to HDR */
+ ret = vgxy61_update_gpios_strobe_mode(sensor, index);
+ if (ret)
+ return ret;
+
+ sensor->hdr = index;
+
+ if (sensor->streaming)
+ return vgxy61_apply_hdr(sensor, sensor->hdr);
+ return 0;
+}
+
+static int vgxy61_apply_settings(struct vgxy61_dev *sensor)
+{
+ int ret;
+ unsigned int i;
+
+ ret = vgxy61_apply_hdr(sensor, sensor->hdr);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_apply_framelength(sensor);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_apply_exposure(sensor);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN,
+ sensor->analog_gain, NULL);
+ if (ret)
+ return ret;
+ ret = vgxy61_apply_digital_gain(sensor, sensor->digital_gain);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_write_reg(sensor, VGXY61_REG_ORIENTATION,
+ sensor->hflip | (sensor->vflip << 1), NULL);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_apply_patgen(sensor, sensor->pattern);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < VGXY61_NB_GPIOS; i++) {
+ ret = vgxy61_apply_gpiox_strobe_mode(sensor,
+ sensor->strobe_mode, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vgxy61_stream_enable(struct vgxy61_dev *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
+ const struct v4l2_rect *crop = &sensor->current_mode->crop;
+ int ret = 0;
+
+ ret = vgxy61_check_bw(sensor);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_autosuspend(&client->dev);
+ return ret;
+ }
+
+ /* pm_runtime_get_sync() can return 1 as a valid return code */
+ ret = 0;
+
+ vgxy61_write_reg(sensor, VGXY61_REG_FORMAT_CTRL,
+ get_bpp_by_code(sensor->fmt.code), &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_OIF_ROI0_CTRL,
+ get_data_type_by_code(sensor->fmt.code), &ret);
+
+ vgxy61_write_reg(sensor, VGXY61_REG_READOUT_CTRL,
+ sensor->current_mode->bin_mode, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_H, crop->left, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_H,
+ crop->left + crop->width - 1, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_V, crop->top, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_V,
+ crop->top + crop->height - 1, &ret);
+ if (ret)
+ goto err_rpm_put;
+
+ ret = vgxy61_apply_settings(sensor);
+ if (ret)
+ goto err_rpm_put;
+
+ ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING,
+ VGXY61_STREAMING_REQ_START, NULL);
+ if (ret)
+ goto err_rpm_put;
+
+ ret = vgxy61_poll_reg(sensor, VGXY61_REG_STREAMING,
+ VGXY61_STREAMING_NO_REQ, VGXY61_TIMEOUT_MS);
+ if (ret)
+ goto err_rpm_put;
+
+ ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_STREAMING,
+ VGXY61_TIMEOUT_MS);
+ if (ret)
+ goto err_rpm_put;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(sensor->vflip_ctrl, true);
+ __v4l2_ctrl_grab(sensor->hflip_ctrl, true);
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+ return ret;
+}
+
+static int vgxy61_stream_disable(struct vgxy61_dev *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
+ int ret;
+
+ ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING,
+ VGXY61_STREAMING_REQ_STOP, NULL);
+ if (ret)
+ goto err_str_dis;
+
+ ret = vgxy61_poll_reg(sensor, VGXY61_REG_STREAMING,
+ VGXY61_STREAMING_NO_REQ, 2000);
+ if (ret)
+ goto err_str_dis;
+
+ ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
+ VGXY61_TIMEOUT_MS);
+ if (ret)
+ goto err_str_dis;
+
+ __v4l2_ctrl_grab(sensor->vflip_ctrl, false);
+ __v4l2_ctrl_grab(sensor->hflip_ctrl, false);
+
+err_str_dis:
+ if (ret)
+ WARN(1, "Can't disable stream");
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static int vgxy61_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ int ret = 0;
+
+ mutex_lock(&sensor->lock);
+
+ ret = enable ? vgxy61_stream_enable(sensor) :
+ vgxy61_stream_disable(sensor);
+ if (!ret)
+ sensor->streaming = enable;
+
+ mutex_unlock(&sensor->lock);
+
+ return ret;
+}
+
+static int vgxy61_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ const struct vgxy61_mode_info *new_mode;
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+
+ mutex_lock(&sensor->lock);
+
+ if (sensor->streaming) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = vgxy61_try_fmt_internal(sd, &format->format, &new_mode);
+ if (ret)
+ goto out;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ *fmt = format->format;
+ } else if (sensor->current_mode != new_mode ||
+ sensor->fmt.code != format->format.code) {
+ fmt = &sensor->fmt;
+ *fmt = format->format;
+
+ sensor->current_mode = new_mode;
+
+ /* Reset vblank and framelength to default */
+ ret = vgxy61_update_vblank(sensor,
+ VGXY61_FRAME_LENGTH_DEF -
+ new_mode->crop.height,
+ sensor->hdr);
+
+ /* Update controls to reflect new mode */
+ __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl,
+ get_pixel_rate(sensor));
+ __v4l2_ctrl_modify_range(sensor->vblank_ctrl,
+ sensor->vblank_min,
+ 0xffff - new_mode->crop.height,
+ 1, sensor->vblank);
+ __v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, sensor->vblank);
+ __v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
+ sensor->expo_max, 1,
+ sensor->expo_long);
+ }
+
+out:
+ mutex_unlock(&sensor->lock);
+
+ return ret;
+}
+
+static int vgxy61_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ struct v4l2_subdev_format fmt = { 0 };
+
+ sensor->current_mode = sensor->default_mode;
+ vgxy61_fill_framefmt(sensor, sensor->current_mode, &fmt.format,
+ VGXY61_MEDIA_BUS_FMT_DEF);
+
+ return vgxy61_set_fmt(sd, sd_state, &fmt);
+}
+
+static int vgxy61_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ const struct vgxy61_mode_info *cur_mode = sensor->current_mode;
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = vgxy61_update_exposure(sensor, ctrl->val, sensor->hdr);
+ ctrl->val = sensor->expo_long;
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = vgxy61_update_analog_gain(sensor, ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = vgxy61_update_digital_gain(sensor, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ if (sensor->streaming) {
+ ret = -EBUSY;
+ break;
+ }
+ if (ctrl->id == V4L2_CID_VFLIP)
+ sensor->vflip = ctrl->val;
+ if (ctrl->id == V4L2_CID_HFLIP)
+ sensor->hflip = ctrl->val;
+ ret = 0;
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = vgxy61_update_patgen(sensor, ctrl->val);
+ break;
+ case V4L2_CID_HDR_SENSOR_MODE:
+ ret = vgxy61_update_hdr(sensor, ctrl->val);
+ /* Update vblank and exposure controls to match new hdr */
+ __v4l2_ctrl_modify_range(sensor->vblank_ctrl,
+ sensor->vblank_min,
+ 0xffff - cur_mode->crop.height,
+ 1, sensor->vblank);
+ __v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
+ sensor->expo_max, 1,
+ sensor->expo_long);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = vgxy61_update_vblank(sensor, ctrl->val, sensor->hdr);
+ /* Update exposure control to match new vblank */
+ __v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
+ sensor->expo_max, 1,
+ sensor->expo_long);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops vgxy61_ctrl_ops = {
+ .s_ctrl = vgxy61_s_ctrl,
+};
+
+static int vgxy61_init_controls(struct vgxy61_dev *sensor)
+{
+ const struct v4l2_ctrl_ops *ops = &vgxy61_ctrl_ops;
+ struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler;
+ const struct vgxy61_mode_info *cur_mode = sensor->current_mode;
+ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 16);
+ /* We can use our own mutex for the ctrl lock */
+ hdl->lock = &sensor->lock;
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 0x1c, 1,
+ sensor->analog_gain);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, 0, 0xfff, 1,
+ sensor->digital_gain);
+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(vgxy61_test_pattern_menu) - 1,
+ 0, 0, vgxy61_test_pattern_menu);
+ ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, 0,
+ sensor->line_length, 1,
+ sensor->line_length - cur_mode->width);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq) - 1, 0, link_freq);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_HDR_SENSOR_MODE,
+ ARRAY_SIZE(vgxy61_hdr_mode_menu) - 1, 0,
+ VGXY61_NO_HDR, vgxy61_hdr_mode_menu);
+
+ /*
+ * Keep a pointer to these controls as we need to update them when
+ * setting the format
+ */
+ sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_PIXEL_RATE, 1,
+ INT_MAX, 1,
+ get_pixel_rate(sensor));
+ if (sensor->pixel_rate_ctrl)
+ sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ sensor->expo_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+ sensor->expo_min,
+ sensor->expo_max, 1,
+ sensor->expo_long);
+ sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
+ sensor->vblank_min,
+ 0xffff - cur_mode->crop.height,
+ 1, sensor->vblank);
+ sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
+ 0, 1, 1, sensor->vflip);
+ sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
+ 0, 1, 1, sensor->hflip);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ goto free_ctrls;
+ }
+
+ sensor->sd.ctrl_handler = hdl;
+ return 0;
+
+free_ctrls:
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops vgxy61_video_ops = {
+ .s_stream = vgxy61_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = {
+ .init_cfg = vgxy61_init_cfg,
+ .enum_mbus_code = vgxy61_enum_mbus_code,
+ .get_fmt = vgxy61_get_fmt,
+ .set_fmt = vgxy61_set_fmt,
+ .get_selection = vgxy61_get_selection,
+ .enum_frame_size = vgxy61_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops vgxy61_subdev_ops = {
+ .video = &vgxy61_video_ops,
+ .pad = &vgxy61_pad_ops,
+};
+
+static const struct media_entity_operations vgxy61_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int vgxy61_tx_from_ep(struct vgxy61_dev *sensor,
+ struct fwnode_handle *handle)
+{
+ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
+ struct i2c_client *client = sensor->i2c_client;
+ u32 log2phy[VGXY61_NB_POLARITIES] = {~0, ~0, ~0, ~0, ~0};
+ u32 phy2log[VGXY61_NB_POLARITIES] = {~0, ~0, ~0, ~0, ~0};
+ int polarities[VGXY61_NB_POLARITIES] = {0, 0, 0, 0, 0};
+ int l_nb;
+ unsigned int p, l, i;
+ int ret;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ep);
+ if (ret)
+ return -EINVAL;
+
+ l_nb = ep.bus.mipi_csi2.num_data_lanes;
+ if (l_nb != 1 && l_nb != 2 && l_nb != 4) {
+ dev_err(&client->dev, "invalid data lane number %d\n", l_nb);
+ goto error_ep;
+ }
+
+ /* Build log2phy, phy2log and polarities from ep info */
+ log2phy[0] = ep.bus.mipi_csi2.clock_lane;
+ phy2log[log2phy[0]] = 0;
+ for (l = 1; l < l_nb + 1; l++) {
+ log2phy[l] = ep.bus.mipi_csi2.data_lanes[l - 1];
+ phy2log[log2phy[l]] = l;
+ }
+ /*
+ * Then fill remaining slots for every physical slot to have something
+ * valid for hardware stuff.
+ */
+ for (p = 0; p < VGXY61_NB_POLARITIES; p++) {
+ if (phy2log[p] != ~0)
+ continue;
+ phy2log[p] = l;
+ log2phy[l] = p;
+ l++;
+ }
+ for (l = 0; l < l_nb + 1; l++)
+ polarities[l] = ep.bus.mipi_csi2.lane_polarities[l];
+
+ if (log2phy[0] != 0) {
+ dev_err(&client->dev, "clk lane must be map to physical lane 0\n");
+ goto error_ep;
+ }
+ sensor->oif_ctrl = (polarities[4] << 15) + ((phy2log[4] - 1) << 13) +
+ (polarities[3] << 12) + ((phy2log[3] - 1) << 10) +
+ (polarities[2] << 9) + ((phy2log[2] - 1) << 7) +
+ (polarities[1] << 6) + ((phy2log[1] - 1) << 4) +
+ (polarities[0] << 3) +
+ l_nb;
+ sensor->nb_of_lane = l_nb;
+
+ dev_dbg(&client->dev, "tx uses %d lanes", l_nb);
+ for (i = 0; i < 5; i++) {
+ dev_dbg(&client->dev, "log2phy[%d] = %d\n", i, log2phy[i]);
+ dev_dbg(&client->dev, "phy2log[%d] = %d\n", i, phy2log[i]);
+ dev_dbg(&client->dev, "polarity[%d] = %d\n", i, polarities[i]);
+ }
+ dev_dbg(&client->dev, "oif_ctrl = 0x%04x\n", sensor->oif_ctrl);
+
+ v4l2_fwnode_endpoint_free(&ep);
+
+ return 0;
+
+error_ep:
+ v4l2_fwnode_endpoint_free(&ep);
+
+ return -EINVAL;
+}
+
+static int vgxy61_configure(struct vgxy61_dev *sensor)
+{
+ u32 sensor_freq;
+ u8 prediv, mult;
+ int line_length;
+ int ret = 0;
+
+ compute_pll_parameters_by_freq(sensor->clk_freq, &prediv, &mult);
+ sensor_freq = (mult * sensor->clk_freq) / prediv;
+ /* Frequency to data rate is 1:1 ratio for MIPI */
+ sensor->data_rate_in_mbps = sensor_freq;
+ /* Video timing ISP path (pixel clock) requires 804/5 mhz = 160 mhz */
+ sensor->pclk = sensor_freq / 5;
+
+ line_length = vgxy61_read_reg(sensor, VGXY61_REG_LINE_LENGTH);
+ if (line_length < 0)
+ return line_length;
+ sensor->line_length = line_length;
+ vgxy61_write_reg(sensor, VGXY61_REG_EXT_CLOCK, sensor->clk_freq, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_CLK_PLL_PREDIV, prediv, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_CLK_SYS_PLL_MULT, mult, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_OIF_CTRL, sensor->oif_ctrl, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_FRAME_CONTENT_CTRL, 0, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_BYPASS_CTRL, 4, &ret);
+ if (ret)
+ return ret;
+ vgxy61_update_gpios_strobe_polarity(sensor, sensor->gpios_polarity);
+ /* Set pattern generator solid to middle value */
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GR, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_R, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_B, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GB, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GR, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_R, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_B, 0x800, &ret);
+ vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GB, 0x800, &ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int vgxy61_patch(struct vgxy61_dev *sensor)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ int patch, ret;
+
+ ret = vgxy61_write_array(sensor, VGXY61_REG_FWPATCH_START_ADDR,
+ sizeof(patch_array), patch_array);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_write_reg(sensor, VGXY61_REG_STBY, 0x10, NULL);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_poll_reg(sensor, VGXY61_REG_STBY, 0, VGXY61_TIMEOUT_MS);
+ if (ret)
+ return ret;
+
+ patch = vgxy61_read_reg(sensor, VGXY61_REG_FWPATCH_REVISION);
+ if (patch < 0)
+ return patch;
+
+ if (patch != (VGXY61_FWPATCH_REVISION_MAJOR << 12) +
+ (VGXY61_FWPATCH_REVISION_MINOR << 8) +
+ VGXY61_FWPATCH_REVISION_MICRO) {
+ dev_err(&client->dev, "bad patch version expected %d.%d.%d got %d.%d.%d\n",
+ VGXY61_FWPATCH_REVISION_MAJOR,
+ VGXY61_FWPATCH_REVISION_MINOR,
+ VGXY61_FWPATCH_REVISION_MICRO,
+ patch >> 12, (patch >> 8) & 0x0f, patch & 0xff);
+ return -ENODEV;
+ }
+ dev_dbg(&client->dev, "patch %d.%d.%d applied\n",
+ patch >> 12, (patch >> 8) & 0x0f, patch & 0xff);
+
+ return 0;
+}
+
+static int vgxy61_detect_cut_version(struct vgxy61_dev *sensor)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ int device_rev;
+
+ device_rev = vgxy61_read_reg(sensor, VGXY61_REG_REVISION);
+ if (device_rev < 0)
+ return device_rev;
+
+ switch (device_rev >> 8) {
+ case 0xA:
+ dev_dbg(&client->dev, "Cut1 detected\n");
+ dev_err(&client->dev, "Cut1 not supported by this driver\n");
+ return -ENODEV;
+ case 0xB:
+ dev_dbg(&client->dev, "Cut2 detected\n");
+ return 0;
+ case 0xC:
+ dev_dbg(&client->dev, "Cut3 detected\n");
+ return 0;
+ default:
+ dev_err(&client->dev, "Unable to detect cut version\n");
+ return -ENODEV;
+ }
+}
+
+static int vgxy61_detect(struct vgxy61_dev *sensor)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ int id = 0;
+ int ret, st;
+
+ id = vgxy61_read_reg(sensor, VGXY61_REG_MODEL_ID);
+ if (id < 0)
+ return id;
+ if (id != VG5661_MODEL_ID && id != VG5761_MODEL_ID) {
+ dev_warn(&client->dev, "Unsupported sensor id %x\n", id);
+ return -ENODEV;
+ }
+ dev_dbg(&client->dev, "detected sensor id = 0x%04x\n", id);
+ sensor->id = id;
+
+ ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
+ VGXY61_TIMEOUT_MS);
+ if (ret)
+ return ret;
+
+ st = vgxy61_read_reg(sensor, VGXY61_REG_NVM);
+ if (st < 0)
+ return st;
+ if (st != VGXY61_NVM_OK)
+ dev_warn(&client->dev, "Bad nvm state got %d\n", st);
+
+ ret = vgxy61_detect_cut_version(sensor);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* Power/clock management functions */
+static int vgxy61_power_on(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(vgxy61_supply_name),
+ sensor->supplies);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable regulators %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(sensor->xclk);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable clock %d\n", ret);
+ goto disable_bulk;
+ }
+
+ if (sensor->reset_gpio) {
+ ret = vgxy61_apply_reset(sensor);
+ if (ret) {
+ dev_err(&client->dev, "sensor reset failed %d\n", ret);
+ goto disable_clock;
+ }
+ }
+
+ ret = vgxy61_patch(sensor);
+ if (ret) {
+ dev_err(&client->dev, "sensor patch failed %d\n", ret);
+ goto disable_clock;
+ }
+
+ ret = vgxy61_configure(sensor);
+ if (ret) {
+ dev_err(&client->dev, "sensor configuration failed %d\n", ret);
+ goto disable_clock;
+ }
+
+ return 0;
+
+disable_clock:
+ clk_disable_unprepare(sensor->xclk);
+disable_bulk:
+ regulator_bulk_disable(ARRAY_SIZE(vgxy61_supply_name),
+ sensor->supplies);
+
+ return ret;
+}
+
+static int vgxy61_power_off(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+
+ clk_disable_unprepare(sensor->xclk);
+ regulator_bulk_disable(ARRAY_SIZE(vgxy61_supply_name),
+ sensor->supplies);
+ return 0;
+}
+
+static void vgxy61_fill_sensor_param(struct vgxy61_dev *sensor)
+{
+ if (sensor->id == VG5761_MODEL_ID) {
+ sensor->sensor_width = VGX761_WIDTH;
+ sensor->sensor_height = VGX761_HEIGHT;
+ sensor->sensor_modes = vgx761_mode_data;
+ sensor->sensor_modes_nb = ARRAY_SIZE(vgx761_mode_data);
+ sensor->default_mode = &vgx761_mode_data[VGX761_DEFAULT_MODE];
+ sensor->rot_term = VGX761_SHORT_ROT_TERM;
+ } else if (sensor->id == VG5661_MODEL_ID) {
+ sensor->sensor_width = VGX661_WIDTH;
+ sensor->sensor_height = VGX661_HEIGHT;
+ sensor->sensor_modes = vgx661_mode_data;
+ sensor->sensor_modes_nb = ARRAY_SIZE(vgx661_mode_data);
+ sensor->default_mode = &vgx661_mode_data[VGX661_DEFAULT_MODE];
+ sensor->rot_term = VGX661_SHORT_ROT_TERM;
+ } else {
+ /* Should never happen */
+ WARN_ON(true);
+ }
+ sensor->current_mode = sensor->default_mode;
+}
+
+static int vgxy61_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct fwnode_handle *handle;
+ struct vgxy61_dev *sensor;
+ int ret;
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->i2c_client = client;
+ sensor->streaming = false;
+ sensor->hdr = VGXY61_NO_HDR;
+ sensor->expo_long = 200;
+ sensor->expo_short = 0;
+ sensor->hflip = false;
+ sensor->vflip = false;
+ sensor->analog_gain = 0;
+ sensor->digital_gain = 256;
+
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
+ if (!handle) {
+ dev_err(dev, "handle node not found\n");
+ return -EINVAL;
+ }
+
+ ret = vgxy61_tx_from_ep(sensor, handle);
+ fwnode_handle_put(handle);
+ if (ret) {
+ dev_err(dev, "Failed to parse handle %d\n", ret);
+ return ret;
+ }
+
+ sensor->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(sensor->xclk)) {
+ dev_err(dev, "failed to get xclk\n");
+ return PTR_ERR(sensor->xclk);
+ }
+ sensor->clk_freq = clk_get_rate(sensor->xclk);
+ if (sensor->clk_freq < 6 * HZ_PER_MHZ ||
+ sensor->clk_freq > 27 * HZ_PER_MHZ) {
+ dev_err(dev, "Only 6Mhz-27Mhz clock range supported. provide %lu MHz\n",
+ sensor->clk_freq / HZ_PER_MHZ);
+ return -EINVAL;
+ }
+ sensor->gpios_polarity =
+ device_property_read_bool(dev, "st,strobe-gpios-polarity");
+
+ v4l2_i2c_subdev_init(&sensor->sd, client, &vgxy61_subdev_ops);
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->sd.entity.ops = &vgxy61_subdev_entity_ops;
+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+
+ ret = vgxy61_get_regulators(sensor);
+ if (ret) {
+ dev_err(&client->dev, "failed to get regulators %d\n", ret);
+ return ret;
+ }
+
+ ret = vgxy61_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = vgxy61_detect(sensor);
+ if (ret) {
+ dev_err(&client->dev, "sensor detect failed %d\n", ret);
+ return ret;
+ }
+
+ vgxy61_fill_sensor_param(sensor);
+ vgxy61_fill_framefmt(sensor, sensor->current_mode, &sensor->fmt,
+ VGXY61_MEDIA_BUS_FMT_DEF);
+
+ ret = vgxy61_update_hdr(sensor, sensor->hdr);
+ if (ret)
+ return ret;
+
+ mutex_init(&sensor->lock);
+
+ ret = vgxy61_init_controls(sensor);
+ if (ret) {
+ dev_err(&client->dev, "controls initialization failed %d\n",
+ ret);
+ goto error_power_off;
+ }
+
+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+ if (ret) {
+ dev_err(&client->dev, "pads init failed %d\n", ret);
+ goto error_handler_free;
+ }
+
+ /* Enable runtime PM and turn off the device */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ ret = v4l2_async_register_subdev(&sensor->sd);
+ if (ret) {
+ dev_err(&client->dev, "async subdev register failed %d\n", ret);
+ goto error_pm_runtime;
+ }
+
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ dev_dbg(&client->dev, "vgxy61 probe successfully\n");
+
+ return 0;
+
+error_pm_runtime:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ media_entity_cleanup(&sensor->sd.entity);
+error_handler_free:
+ v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
+ mutex_destroy(&sensor->lock);
+error_power_off:
+ vgxy61_power_off(dev);
+
+ return ret;
+}
+
+static void vgxy61_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
+
+ v4l2_async_unregister_subdev(&sensor->sd);
+ mutex_destroy(&sensor->lock);
+ media_entity_cleanup(&sensor->sd.entity);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ vgxy61_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id vgxy61_dt_ids[] = {
+ { .compatible = "st,st-vgxy61" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vgxy61_dt_ids);
+
+static const struct dev_pm_ops vgxy61_pm_ops = {
+ SET_RUNTIME_PM_OPS(vgxy61_power_off, vgxy61_power_on, NULL)
+};
+
+static struct i2c_driver vgxy61_i2c_driver = {
+ .driver = {
+ .name = "st-vgxy61",
+ .of_match_table = vgxy61_dt_ids,
+ .pm = &vgxy61_pm_ops,
+ },
+ .probe_new = vgxy61_probe,
+ .remove = vgxy61_remove,
+};
+
+module_i2c_driver(vgxy61_i2c_driver);
+
+MODULE_AUTHOR("Benjamin Mugnier <benjamin.mugnier@foss.st.com>");
+MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>");
+MODULE_AUTHOR("Sylvain Petinot <sylvain.petinot@foss.st.com>");
+MODULE_DESCRIPTION("VGXY61 camera subdev driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 200841c1f5cf..9197fa0b1bc2 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1891,12 +1891,9 @@ static int tc358743_probe_of(struct tc358743_state *state)
int ret;
refclk = devm_clk_get(dev, "refclk");
- if (IS_ERR(refclk)) {
- if (PTR_ERR(refclk) != -EPROBE_DEFER)
- dev_err(dev, "failed to get refclk: %ld\n",
- PTR_ERR(refclk));
- return PTR_ERR(refclk);
- }
+ if (IS_ERR(refclk))
+ return dev_err_probe(dev, PTR_ERR(refclk),
+ "failed to get refclk\n");
ep = of_graph_get_next_endpoint(dev->of_node, NULL);
if (!ep) {
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
new file mode 100644
index 000000000000..d1f552bd81d4
--- /dev/null
+++ b/drivers/media/i2c/tc358746.c
@@ -0,0 +1,1694 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * TC358746 - Parallel <-> CSI-2 Bridge
+ *
+ * Copyright 2022 Marco Felsch <kernel@pengutronix.de>
+ *
+ * Notes:
+ * - Currently only 'Parallel-in -> CSI-out' mode is supported!
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/property.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+
+/* 16-bit registers */
+#define CHIPID_REG 0x0000
+#define CHIPID GENMASK(15, 8)
+
+#define SYSCTL_REG 0x0002
+#define SRESET BIT(0)
+
+#define CONFCTL_REG 0x0004
+#define PDATAF_MASK GENMASK(9, 8)
+#define PDATAF_MODE0 0
+#define PDATAF_MODE1 1
+#define PDATAF_MODE2 2
+#define PDATAF(val) FIELD_PREP(PDATAF_MASK, (val))
+#define PPEN BIT(6)
+#define DATALANE_MASK GENMASK(1, 0)
+
+#define FIFOCTL_REG 0x0006
+#define DATAFMT_REG 0x0008
+#define PDFMT(val) FIELD_PREP(GENMASK(7, 4), (val))
+
+#define MCLKCTL_REG 0x000c
+#define MCLK_HIGH_MASK GENMASK(15, 8)
+#define MCLK_LOW_MASK GENMASK(7, 0)
+#define MCLK_HIGH(val) FIELD_PREP(MCLK_HIGH_MASK, (val))
+#define MCLK_LOW(val) FIELD_PREP(MCLK_LOW_MASK, (val))
+
+#define PLLCTL0_REG 0x0016
+#define PLL_PRD_MASK GENMASK(15, 12)
+#define PLL_PRD(val) FIELD_PREP(PLL_PRD_MASK, (val))
+#define PLL_FBD_MASK GENMASK(8, 0)
+#define PLL_FBD(val) FIELD_PREP(PLL_FBD_MASK, (val))
+
+#define PLLCTL1_REG 0x0018
+#define PLL_FRS_MASK GENMASK(11, 10)
+#define PLL_FRS(val) FIELD_PREP(PLL_FRS_MASK, (val))
+#define CKEN BIT(4)
+#define RESETB BIT(1)
+#define PLL_EN BIT(0)
+
+#define CLKCTL_REG 0x0020
+#define MCLKDIV_MASK GENMASK(3, 2)
+#define MCLKDIV(val) FIELD_PREP(MCLKDIV_MASK, (val))
+#define MCLKDIV_8 0
+#define MCLKDIV_4 1
+#define MCLKDIV_2 2
+
+#define WORDCNT_REG 0x0022
+#define PP_MISC_REG 0x0032
+#define FRMSTOP BIT(15)
+#define RSTPTR BIT(14)
+
+/* 32-bit registers */
+#define CLW_DPHYCONTTX_REG 0x0100
+#define CLW_CNTRL_REG 0x0140
+#define D0W_CNTRL_REG 0x0144
+#define LANEDISABLE BIT(0)
+
+#define STARTCNTRL_REG 0x0204
+#define START BIT(0)
+
+#define LINEINITCNT_REG 0x0210
+#define LPTXTIMECNT_REG 0x0214
+#define TCLK_HEADERCNT_REG 0x0218
+#define TCLK_ZEROCNT(val) FIELD_PREP(GENMASK(15, 8), (val))
+#define TCLK_PREPARECNT(val) FIELD_PREP(GENMASK(6, 0), (val))
+
+#define TCLK_TRAILCNT_REG 0x021C
+#define THS_HEADERCNT_REG 0x0220
+#define THS_ZEROCNT(val) FIELD_PREP(GENMASK(14, 8), (val))
+#define THS_PREPARECNT(val) FIELD_PREP(GENMASK(6, 0), (val))
+
+#define TWAKEUP_REG 0x0224
+#define TCLK_POSTCNT_REG 0x0228
+#define THS_TRAILCNT_REG 0x022C
+#define HSTXVREGEN_REG 0x0234
+#define TXOPTIONCNTRL_REG 0x0238
+#define CSI_CONTROL_REG 0x040C
+#define CSI_MODE BIT(15)
+#define TXHSMD BIT(7)
+#define NOL(val) FIELD_PREP(GENMASK(2, 1), (val))
+
+#define CSI_CONFW_REG 0x0500
+#define MODE(val) FIELD_PREP(GENMASK(31, 29), (val))
+#define MODE_SET 0x5
+#define ADDRESS(val) FIELD_PREP(GENMASK(28, 24), (val))
+#define CSI_CONTROL_ADDRESS 0x3
+#define DATA(val) FIELD_PREP(GENMASK(15, 0), (val))
+
+#define CSI_START_REG 0x0518
+#define STRT BIT(0)
+
+static const struct v4l2_mbus_framefmt tc358746_def_fmt = {
+ .width = 640,
+ .height = 480,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_DEFAULT,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+};
+
+static const char * const tc358746_supplies[] = {
+ "vddc", "vddio", "vddmipi"
+};
+
+enum {
+ TC358746_SINK,
+ TC358746_SOURCE,
+ TC358746_NR_PADS
+};
+
+struct tc358746 {
+ struct v4l2_subdev sd;
+ struct media_pad pads[TC358746_NR_PADS];
+ struct v4l2_async_notifier notifier;
+ struct v4l2_fwnode_endpoint csi_vep;
+
+ struct v4l2_ctrl_handler ctrl_hdl;
+
+ struct regmap *regmap;
+ struct clk *refclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(tc358746_supplies)];
+
+ struct clk_hw mclk_hw;
+ unsigned long mclk_rate;
+ u8 mclk_prediv;
+ u16 mclk_postdiv;
+
+ unsigned long pll_rate;
+ u8 pll_post_div;
+ u16 pll_pre_div;
+ u16 pll_mul;
+
+#define TC358746_VB_MAX_SIZE (511 * 32)
+#define TC358746_VB_DEFAULT_SIZE (1 * 32)
+ unsigned int vb_size; /* Video buffer size in bits */
+
+ struct phy_configure_opts_mipi_dphy dphy_cfg;
+};
+
+static inline struct tc358746 *to_tc358746(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tc358746, sd);
+}
+
+static inline struct tc358746 *clk_hw_to_tc358746(struct clk_hw *hw)
+{
+ return container_of(hw, struct tc358746, mclk_hw);
+}
+
+struct tc358746_format {
+ u32 code;
+ bool csi_format;
+ unsigned char bus_width;
+ unsigned char bpp;
+ /* Register values */
+ u8 pdformat; /* Peripheral Data Format */
+ u8 pdataf; /* Parallel Data Format Option */
+};
+
+enum {
+ PDFORMAT_RAW8 = 0,
+ PDFORMAT_RAW10,
+ PDFORMAT_RAW12,
+ PDFORMAT_RGB888,
+ PDFORMAT_RGB666,
+ PDFORMAT_RGB565,
+ PDFORMAT_YUV422_8BIT,
+ /* RESERVED = 7 */
+ PDFORMAT_RAW14 = 8,
+ PDFORMAT_YUV422_10BIT,
+ PDFORMAT_YUV444,
+};
+
+/* Check tc358746_src_mbus_code() if you add new formats */
+static const struct tc358746_format tc358746_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .bus_width = 8,
+ .bpp = 16,
+ .pdformat = PDFORMAT_YUV422_8BIT,
+ .pdataf = PDATAF_MODE0,
+ }, {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .csi_format = true,
+ .bus_width = 16,
+ .bpp = 16,
+ .pdformat = PDFORMAT_YUV422_8BIT,
+ .pdataf = PDATAF_MODE1,
+ }, {
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .csi_format = true,
+ .bus_width = 16,
+ .bpp = 16,
+ .pdformat = PDFORMAT_YUV422_8BIT,
+ .pdataf = PDATAF_MODE2,
+ }, {
+ .code = MEDIA_BUS_FMT_UYVY10_2X10,
+ .bus_width = 10,
+ .bpp = 20,
+ .pdformat = PDFORMAT_YUV422_10BIT,
+ .pdataf = PDATAF_MODE0, /* don't care */
+ }
+};
+
+/* Get n-th format for pad */
+static const struct tc358746_format *
+tc358746_get_format_by_idx(unsigned int pad, unsigned int index)
+{
+ unsigned int idx = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++) {
+ const struct tc358746_format *fmt = &tc358746_formats[i];
+
+ if ((pad == TC358746_SOURCE && fmt->csi_format) ||
+ (pad == TC358746_SINK)) {
+ if (idx == index)
+ return fmt;
+ idx++;
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static const struct tc358746_format *
+tc358746_get_format_by_code(unsigned int pad, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++) {
+ const struct tc358746_format *fmt = &tc358746_formats[i];
+
+ if (pad == TC358746_SINK && fmt->code == code)
+ return fmt;
+
+ if (pad == TC358746_SOURCE && !fmt->csi_format)
+ continue;
+
+ if (fmt->code == code)
+ return fmt;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static u32 tc358746_src_mbus_code(u32 code)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ return MEDIA_BUS_FMT_UYVY8_1X16;
+ case MEDIA_BUS_FMT_UYVY10_2X10:
+ return MEDIA_BUS_FMT_UYVY10_1X20;
+ default:
+ return code;
+ }
+}
+
+static bool tc358746_valid_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CHIPID_REG ... CSI_START_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config tc358746_regmap_config = {
+ .name = "tc358746",
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = CSI_START_REG,
+ .writeable_reg = tc358746_valid_reg,
+ .readable_reg = tc358746_valid_reg,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int tc358746_write(struct tc358746 *tc358746, u32 reg, u32 val)
+{
+ size_t count;
+ int err;
+
+ /* 32-bit registers starting from CLW_DPHYCONTTX */
+ count = reg < CLW_DPHYCONTTX_REG ? 1 : 2;
+
+ err = regmap_bulk_write(tc358746->regmap, reg, &val, count);
+ if (err)
+ dev_err(tc358746->sd.dev,
+ "Failed to write reg:0x%04x err:%d\n", reg, err);
+
+ return err;
+}
+
+static int tc358746_read(struct tc358746 *tc358746, u32 reg, u32 *val)
+{
+ size_t count;
+ int err;
+
+ /* 32-bit registers starting from CLW_DPHYCONTTX */
+ count = reg < CLW_DPHYCONTTX_REG ? 1 : 2;
+ *val = 0;
+
+ err = regmap_bulk_read(tc358746->regmap, reg, val, count);
+ if (err)
+ dev_err(tc358746->sd.dev,
+ "Failed to read reg:0x%04x err:%d\n", reg, err);
+
+ return err;
+}
+
+static int
+tc358746_update_bits(struct tc358746 *tc358746, u32 reg, u32 mask, u32 val)
+{
+ u32 tmp, orig;
+ int err;
+
+ err = tc358746_read(tc358746, reg, &orig);
+ if (err)
+ return err;
+
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+
+ return tc358746_write(tc358746, reg, tmp);
+}
+
+static int tc358746_set_bits(struct tc358746 *tc358746, u32 reg, u32 bits)
+{
+ return tc358746_update_bits(tc358746, reg, bits, bits);
+}
+
+static int tc358746_clear_bits(struct tc358746 *tc358746, u32 reg, u32 bits)
+{
+ return tc358746_update_bits(tc358746, reg, bits, 0);
+}
+
+static int tc358746_sw_reset(struct tc358746 *tc358746)
+{
+ int err;
+
+ err = tc358746_set_bits(tc358746, SYSCTL_REG, SRESET);
+ if (err)
+ return err;
+
+ fsleep(10);
+
+ return tc358746_clear_bits(tc358746, SYSCTL_REG, SRESET);
+}
+
+static int
+tc358746_apply_pll_config(struct tc358746 *tc358746)
+{
+ u8 post = tc358746->pll_post_div;
+ u16 pre = tc358746->pll_pre_div;
+ u16 mul = tc358746->pll_mul;
+ u32 val, mask;
+ int err;
+
+ err = tc358746_read(tc358746, PLLCTL1_REG, &val);
+ if (err)
+ return err;
+
+ /* Don't touch the PLL if running */
+ if (FIELD_GET(PLL_EN, val) == 1)
+ return 0;
+
+ /* Pre-div and Multiplicator have a internal +1 logic */
+ val = PLL_PRD(pre - 1) | PLL_FBD(mul - 1);
+ mask = PLL_PRD_MASK | PLL_FBD_MASK;
+ err = tc358746_update_bits(tc358746, PLLCTL0_REG, mask, val);
+ if (err)
+ return err;
+
+ val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN;
+ mask = PLL_FRS_MASK | RESETB | PLL_EN;
+ tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val);
+ if (err)
+ return err;
+
+ fsleep(1000);
+
+ return tc358746_set_bits(tc358746, PLLCTL1_REG, CKEN);
+}
+
+static int tc358746_apply_misc_config(struct tc358746 *tc358746)
+{
+ const struct v4l2_mbus_framefmt *mbusfmt;
+ struct v4l2_subdev *sd = &tc358746->sd;
+ struct v4l2_subdev_state *sink_state;
+ const struct tc358746_format *fmt;
+ struct device *dev = sd->dev;
+ u32 val;
+ int err;
+
+ sink_state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK);
+ fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code);
+
+ /* Self defined CSI user data type id's are not supported yet */
+ val = PDFMT(fmt->pdformat);
+ dev_dbg(dev, "DATAFMT: 0x%x\n", val);
+ err = tc358746_write(tc358746, DATAFMT_REG, val);
+ if (err)
+ goto out;
+
+ val = PDATAF(fmt->pdataf);
+ dev_dbg(dev, "CONFCTL[PDATAF]: 0x%x\n", fmt->pdataf);
+ err = tc358746_update_bits(tc358746, CONFCTL_REG, PDATAF_MASK, val);
+ if (err)
+ goto out;
+
+ val = tc358746->vb_size / 32;
+ dev_dbg(dev, "FIFOCTL: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, FIFOCTL_REG, val);
+ if (err)
+ goto out;
+
+ /* Total number of bytes for each line/width */
+ val = mbusfmt->width * fmt->bpp / 8;
+ dev_dbg(dev, "WORDCNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, WORDCNT_REG, val);
+
+out:
+ v4l2_subdev_unlock_state(sink_state);
+
+ return err;
+}
+
+/* Use MHz as base so the div needs no u64 */
+static u32 tc358746_cfg_to_cnt(unsigned int cfg_val,
+ unsigned int clk_mhz,
+ unsigned int time_base)
+{
+ return DIV_ROUND_UP(cfg_val * clk_mhz, time_base);
+}
+
+static u32 tc358746_ps_to_cnt(unsigned int cfg_val,
+ unsigned int clk_mhz)
+{
+ return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC);
+}
+
+static u32 tc358746_us_to_cnt(unsigned int cfg_val,
+ unsigned int clk_mhz)
+{
+ return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1);
+}
+
+static int tc358746_apply_dphy_config(struct tc358746 *tc358746)
+{
+ struct phy_configure_opts_mipi_dphy *cfg = &tc358746->dphy_cfg;
+ bool non_cont_clk = !!(tc358746->csi_vep.bus.mipi_csi2.flags &
+ V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK);
+ struct device *dev = tc358746->sd.dev;
+ unsigned long hs_byte_clk, hf_clk;
+ u32 val, val2, lptxcnt;
+ int err;
+
+ /* The hs_byte_clk is also called SYSCLK in the excel sheet */
+ hs_byte_clk = cfg->hs_clk_rate / 8;
+ hs_byte_clk /= HZ_PER_MHZ;
+ hf_clk = hs_byte_clk / 2;
+
+ val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1;
+ dev_dbg(dev, "LINEINITCNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, LINEINITCNT_REG, val);
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->lpx, hs_byte_clk) - 1;
+ lptxcnt = val;
+ dev_dbg(dev, "LPTXTIMECNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, LPTXTIMECNT_REG, val);
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->clk_prepare, hs_byte_clk) - 1;
+ val2 = tc358746_ps_to_cnt(cfg->clk_zero, hs_byte_clk) - 1;
+ dev_dbg(dev, "TCLK_PREPARECNT: %u (0x%x)\n", val, val);
+ dev_dbg(dev, "TCLK_ZEROCNT: %u (0x%x)\n", val2, val2);
+ dev_dbg(dev, "TCLK_HEADERCNT: 0x%x\n",
+ (u32)(TCLK_PREPARECNT(val) | TCLK_ZEROCNT(val2)));
+ err = tc358746_write(tc358746, TCLK_HEADERCNT_REG,
+ TCLK_PREPARECNT(val) | TCLK_ZEROCNT(val2));
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->clk_trail, hs_byte_clk);
+ dev_dbg(dev, "TCLK_TRAILCNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, TCLK_TRAILCNT_REG, val);
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->hs_prepare, hs_byte_clk) - 1;
+ val2 = tc358746_ps_to_cnt(cfg->hs_zero, hs_byte_clk) - 1;
+ dev_dbg(dev, "THS_PREPARECNT: %u (0x%x)\n", val, val);
+ dev_dbg(dev, "THS_ZEROCNT: %u (0x%x)\n", val2, val2);
+ dev_dbg(dev, "THS_HEADERCNT: 0x%x\n",
+ (u32)(THS_PREPARECNT(val) | THS_ZEROCNT(val2)));
+ err = tc358746_write(tc358746, THS_HEADERCNT_REG,
+ THS_PREPARECNT(val) | THS_ZEROCNT(val2));
+ if (err)
+ return err;
+
+ /* TWAKEUP > 1ms in lptxcnt steps */
+ val = tc358746_us_to_cnt(cfg->wakeup, hs_byte_clk);
+ val = val / (lptxcnt + 1) - 1;
+ dev_dbg(dev, "TWAKEUP: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, TWAKEUP_REG, val);
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->clk_post, hs_byte_clk);
+ dev_dbg(dev, "TCLK_POSTCNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, TCLK_POSTCNT_REG, val);
+ if (err)
+ return err;
+
+ val = tc358746_ps_to_cnt(cfg->hs_trail, hs_byte_clk);
+ dev_dbg(dev, "THS_TRAILCNT: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, THS_TRAILCNT_REG, val);
+ if (err)
+ return err;
+
+ dev_dbg(dev, "CONTCLKMODE: %u", non_cont_clk ? 0 : 1);
+
+ return tc358746_write(tc358746, TXOPTIONCNTRL_REG, non_cont_clk ? 0 : 1);
+}
+
+#define MAX_DATA_LANES 4
+
+static int tc358746_enable_csi_lanes(struct tc358746 *tc358746, int enable)
+{
+ unsigned int lanes = tc358746->dphy_cfg.lanes;
+ unsigned int lane;
+ u32 reg, val;
+ int err;
+
+ err = tc358746_update_bits(tc358746, CONFCTL_REG, DATALANE_MASK,
+ lanes - 1);
+ if (err)
+ return err;
+
+ /* Clock lane */
+ val = enable ? 0 : LANEDISABLE;
+ dev_dbg(tc358746->sd.dev, "CLW_CNTRL: 0x%x\n", val);
+ err = tc358746_write(tc358746, CLW_CNTRL_REG, val);
+ if (err)
+ return err;
+
+ for (lane = 0; lane < MAX_DATA_LANES; lane++) {
+ /* Data lanes */
+ reg = D0W_CNTRL_REG + lane * 0x4;
+ val = (enable && lane < lanes) ? 0 : LANEDISABLE;
+
+ dev_dbg(tc358746->sd.dev, "D%uW_CNTRL: 0x%x\n", lane, val);
+ err = tc358746_write(tc358746, reg, val);
+ if (err)
+ return err;
+ }
+
+ val = 0;
+ if (enable) {
+ /* Clock lane */
+ val |= BIT(0);
+
+ /* Data lanes */
+ for (lane = 1; lane <= lanes; lane++)
+ val |= BIT(lane);
+ }
+
+ dev_dbg(tc358746->sd.dev, "HSTXVREGEN: 0x%x\n", val);
+
+ return tc358746_write(tc358746, HSTXVREGEN_REG, val);
+}
+
+static int tc358746_enable_csi_module(struct tc358746 *tc358746, int enable)
+{
+ unsigned int lanes = tc358746->dphy_cfg.lanes;
+ int err;
+
+ /*
+ * START and STRT are only reseted/disabled by sw reset. This is
+ * required to put the lane state back into LP-11 state. The sw reset
+ * don't reset register values.
+ */
+ if (!enable)
+ return tc358746_sw_reset(tc358746);
+
+ err = tc358746_write(tc358746, STARTCNTRL_REG, START);
+ if (err)
+ return err;
+
+ err = tc358746_write(tc358746, CSI_START_REG, STRT);
+ if (err)
+ return err;
+
+ /* CSI_CONTROL_REG is only indirect accessible */
+ return tc358746_write(tc358746, CSI_CONFW_REG,
+ MODE(MODE_SET) |
+ ADDRESS(CSI_CONTROL_ADDRESS) |
+ DATA(CSI_MODE | TXHSMD | NOL(lanes - 1)));
+}
+
+static int tc358746_enable_parallel_port(struct tc358746 *tc358746, int enable)
+{
+ int err;
+
+ if (enable) {
+ err = tc358746_write(tc358746, PP_MISC_REG, 0);
+ if (err)
+ return err;
+
+ return tc358746_set_bits(tc358746, CONFCTL_REG, PPEN);
+ }
+
+ err = tc358746_set_bits(tc358746, PP_MISC_REG, FRMSTOP);
+ if (err)
+ return err;
+
+ err = tc358746_clear_bits(tc358746, CONFCTL_REG, PPEN);
+ if (err)
+ return err;
+
+ return tc358746_set_bits(tc358746, PP_MISC_REG, RSTPTR);
+}
+
+static inline struct v4l2_subdev *tc358746_get_remote_sd(struct media_pad *pad)
+{
+ pad = media_pad_remote_pad_first(pad);
+ if (!pad)
+ return NULL;
+
+ return media_entity_to_v4l2_subdev(pad->entity);
+}
+
+static int tc358746_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct tc358746 *tc358746 = to_tc358746(sd);
+ struct v4l2_subdev *src;
+ int err;
+
+ dev_dbg(sd->dev, "%sable\n", enable ? "en" : "dis");
+
+ src = tc358746_get_remote_sd(&tc358746->pads[TC358746_SINK]);
+ if (!src)
+ return -EPIPE;
+
+ if (enable) {
+ err = pm_runtime_resume_and_get(sd->dev);
+ if (err)
+ return err;
+
+ err = tc358746_apply_dphy_config(tc358746);
+ if (err)
+ goto err_out;
+
+ err = tc358746_apply_misc_config(tc358746);
+ if (err)
+ goto err_out;
+
+ err = tc358746_enable_csi_lanes(tc358746, 1);
+ if (err)
+ goto err_out;
+
+ err = tc358746_enable_csi_module(tc358746, 1);
+ if (err)
+ goto err_out;
+
+ err = tc358746_enable_parallel_port(tc358746, 1);
+ if (err)
+ goto err_out;
+
+ err = v4l2_subdev_call(src, video, s_stream, 1);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_sync_autosuspend(sd->dev);
+
+ return err;
+ }
+
+ /*
+ * The lanes must be disabled first (before the csi module) so the
+ * LP-11 state is entered correctly.
+ */
+ err = tc358746_enable_csi_lanes(tc358746, 0);
+ if (err)
+ return err;
+
+ err = tc358746_enable_csi_module(tc358746, 0);
+ if (err)
+ return err;
+
+ err = tc358746_enable_parallel_port(tc358746, 0);
+ if (err)
+ return err;
+
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_sync_autosuspend(sd->dev);
+
+ return v4l2_subdev_call(src, video, s_stream, 0);
+}
+
+static int tc358746_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SINK);
+ *fmt = tc358746_def_fmt;
+
+ fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SOURCE);
+ *fmt = tc358746_def_fmt;
+ fmt->code = tc358746_src_mbus_code(tc358746_def_fmt.code);
+
+ return 0;
+}
+
+static int tc358746_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ const struct tc358746_format *fmt;
+
+ fmt = tc358746_get_format_by_idx(code->pad, code->index);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ code->code = fmt->code;
+
+ return 0;
+}
+
+static int tc358746_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
+ const struct tc358746_format *fmt;
+
+ /* Source follows the sink */
+ if (format->pad == TC358746_SOURCE)
+ return v4l2_subdev_get_fmt(sd, sd_state, format);
+
+ sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK);
+
+ fmt = tc358746_get_format_by_code(format->pad, format->format.code);
+ if (IS_ERR(fmt))
+ fmt = tc358746_get_format_by_code(format->pad, tc358746_def_fmt.code);
+
+ format->format.code = fmt->code;
+ format->format.field = V4L2_FIELD_NONE;
+
+ dev_dbg(sd->dev, "Update format: %ux%u code:0x%x -> %ux%u code:0x%x",
+ sink_fmt->width, sink_fmt->height, sink_fmt->code,
+ format->format.width, format->format.height, format->format.code);
+
+ *sink_fmt = format->format;
+
+ src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SOURCE);
+ *src_fmt = *sink_fmt;
+ src_fmt->code = tc358746_src_mbus_code(sink_fmt->code);
+
+ return 0;
+}
+
+static unsigned long tc358746_find_pll_settings(struct tc358746 *tc358746,
+ unsigned long refclk,
+ unsigned long fout)
+
+{
+ struct device *dev = tc358746->sd.dev;
+ unsigned long best_freq = 0;
+ u32 min_delta = 0xffffffff;
+ u16 prediv_max = 17;
+ u16 prediv_min = 1;
+ u16 m_best, mul;
+ u16 p_best, p;
+ u8 postdiv;
+
+ if (fout > 1000 * HZ_PER_MHZ) {
+ dev_err(dev, "HS-Clock above 1 Ghz are not supported\n");
+ return 0;
+ }
+
+ if (fout >= 500 * HZ_PER_MHZ)
+ postdiv = 1;
+ else if (fout >= 250 * HZ_PER_MHZ)
+ postdiv = 2;
+ else if (fout >= 125 * HZ_PER_MHZ)
+ postdiv = 4;
+ else
+ postdiv = 8;
+
+ for (p = prediv_min; p <= prediv_max; p++) {
+ unsigned long delta, fin;
+ u64 tmp;
+
+ fin = DIV_ROUND_CLOSEST(refclk, p);
+ if (fin < 4 * HZ_PER_MHZ || fin > 40 * HZ_PER_MHZ)
+ continue;
+
+ tmp = fout * p * postdiv;
+ do_div(tmp, fin);
+ mul = tmp;
+ if (mul > 511)
+ continue;
+
+ tmp = mul * fin;
+ do_div(tmp, p * postdiv);
+
+ delta = abs(fout - tmp);
+ if (delta < min_delta) {
+ p_best = p;
+ m_best = mul;
+ min_delta = delta;
+ best_freq = tmp;
+ };
+
+ if (delta == 0)
+ break;
+ };
+
+ if (!best_freq) {
+ dev_err(dev, "Failed find PLL frequency\n");
+ return 0;
+ }
+
+ tc358746->pll_post_div = postdiv;
+ tc358746->pll_pre_div = p_best;
+ tc358746->pll_mul = m_best;
+
+ if (best_freq != fout)
+ dev_warn(dev, "Request PLL freq:%lu, found PLL freq:%lu\n",
+ fout, best_freq);
+
+ dev_dbg(dev, "Found PLL settings: freq:%lu prediv:%u multi:%u postdiv:%u\n",
+ best_freq, p_best, m_best, postdiv);
+
+ return best_freq;
+}
+
+#define TC358746_PRECISION 10
+
+static int
+tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ struct tc358746 *tc358746 = to_tc358746(sd);
+ unsigned long csi_bitrate, source_bitrate;
+ struct v4l2_subdev_state *sink_state;
+ struct v4l2_mbus_framefmt *mbusfmt;
+ const struct tc358746_format *fmt;
+ unsigned int fifo_sz, tmp, n;
+ struct v4l2_subdev *source;
+ s64 source_link_freq;
+ int err;
+
+ err = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt);
+ if (err)
+ return err;
+
+ sink_state = v4l2_subdev_lock_and_get_active_state(sd);
+ mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK);
+
+ /* Check the FIFO settings */
+ fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code);
+
+ source = media_entity_to_v4l2_subdev(link->source->entity);
+ source_link_freq = v4l2_get_link_freq(source->ctrl_handler, 0, 0);
+ if (source_link_freq <= 0) {
+ dev_err(tc358746->sd.dev,
+ "Failed to query or invalid source link frequency\n");
+ v4l2_subdev_unlock_state(sink_state);
+ /* Return -EINVAL in case of source_link_freq is 0 */
+ return source_link_freq ? : -EINVAL;
+ }
+ source_bitrate = source_link_freq * fmt->bus_width;
+
+ csi_bitrate = tc358746->dphy_cfg.lanes * tc358746->pll_rate;
+
+ dev_dbg(tc358746->sd.dev,
+ "Fifo settings params: source-bitrate:%lu csi-bitrate:%lu",
+ source_bitrate, csi_bitrate);
+
+ /* Avoid possible FIFO overflows */
+ if (csi_bitrate < source_bitrate) {
+ v4l2_subdev_unlock_state(sink_state);
+ return -EINVAL;
+ }
+
+ /* Best case */
+ if (csi_bitrate == source_bitrate) {
+ fifo_sz = TC358746_VB_DEFAULT_SIZE;
+ tc358746->vb_size = TC358746_VB_DEFAULT_SIZE;
+ goto out;
+ }
+
+ /*
+ * Avoid possible FIFO underflow in case of
+ * csi_bitrate > source_bitrate. For such case the chip has a internal
+ * fifo which can be used to delay the line output.
+ *
+ * Fifo size calculation (excluding precision):
+ *
+ * fifo-sz, image-width - in bits
+ * sbr - source_bitrate in bits/s
+ * csir - csi_bitrate in bits/s
+ *
+ * image-width / csir >= (image-width - fifo-sz) / sbr
+ * image-width * sbr / csir >= image-width - fifo-sz
+ * fifo-sz >= image-width - image-width * sbr / csir; with n = csir/sbr
+ * fifo-sz >= image-width - image-width / n
+ */
+
+ source_bitrate /= TC358746_PRECISION;
+ n = csi_bitrate / source_bitrate;
+ tmp = (mbusfmt->width * TC358746_PRECISION) / n;
+ fifo_sz = mbusfmt->width - tmp;
+ fifo_sz *= fmt->bpp;
+ tc358746->vb_size = round_up(fifo_sz, 32);
+
+out:
+ dev_dbg(tc358746->sd.dev,
+ "Found FIFO size[bits]:%u -> aligned to size[bits]:%u\n",
+ fifo_sz, tc358746->vb_size);
+
+ v4l2_subdev_unlock_state(sink_state);
+
+ return tc358746->vb_size > TC358746_VB_MAX_SIZE ? -EINVAL : 0;
+}
+
+static int tc358746_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ struct tc358746 *tc358746 = to_tc358746(sd);
+
+ if (pad != TC358746_SOURCE)
+ return -EINVAL;
+
+ config->type = V4L2_MBUS_CSI2_DPHY;
+ config->bus.mipi_csi2 = tc358746->csi_vep.bus.mipi_csi2;
+
+ return 0;
+}
+
+static int __maybe_unused
+tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct tc358746 *tc358746 = to_tc358746(sd);
+
+ /* 32-bit registers starting from CLW_DPHYCONTTX */
+ reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4;
+
+ if (!pm_runtime_get_if_in_use(sd->dev))
+ return 0;
+
+ tc358746_read(tc358746, reg->reg, (u32 *)&reg->val);
+
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_sync_autosuspend(sd->dev);
+
+ return 0;
+}
+
+static int __maybe_unused
+tc358746_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+{
+ struct tc358746 *tc358746 = to_tc358746(sd);
+
+ if (!pm_runtime_get_if_in_use(sd->dev))
+ return 0;
+
+ tc358746_write(tc358746, (u32)reg->reg, (u32)reg->val);
+
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_sync_autosuspend(sd->dev);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops tc358746_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = tc358746_g_register,
+ .s_register = tc358746_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops tc358746_video_ops = {
+ .s_stream = tc358746_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops tc358746_pad_ops = {
+ .init_cfg = tc358746_init_cfg,
+ .enum_mbus_code = tc358746_enum_mbus_code,
+ .set_fmt = tc358746_set_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .link_validate = tc358746_link_validate,
+ .get_mbus_config = tc358746_get_mbus_config,
+};
+
+static const struct v4l2_subdev_ops tc358746_ops = {
+ .core = &tc358746_core_ops,
+ .video = &tc358746_video_ops,
+ .pad = &tc358746_pad_ops,
+};
+
+static const struct media_entity_operations tc358746_entity_ops = {
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int tc358746_mclk_enable(struct clk_hw *hw)
+{
+ struct tc358746 *tc358746 = clk_hw_to_tc358746(hw);
+ unsigned int div;
+ u32 val;
+ int err;
+
+ div = tc358746->mclk_postdiv / 2;
+ val = MCLK_HIGH(div - 1) | MCLK_LOW(div - 1);
+ dev_dbg(tc358746->sd.dev, "MCLKCTL: %u (0x%x)\n", val, val);
+ err = tc358746_write(tc358746, MCLKCTL_REG, val);
+ if (err)
+ return err;
+
+ if (tc358746->mclk_prediv == 8)
+ val = MCLKDIV(MCLKDIV_8);
+ else if (tc358746->mclk_prediv == 4)
+ val = MCLKDIV(MCLKDIV_4);
+ else
+ val = MCLKDIV(MCLKDIV_2);
+
+ dev_dbg(tc358746->sd.dev, "CLKCTL[MCLKDIV]: %u (0x%x)\n", val, val);
+
+ return tc358746_update_bits(tc358746, CLKCTL_REG, MCLKDIV_MASK, val);
+}
+
+static void tc358746_mclk_disable(struct clk_hw *hw)
+{
+ struct tc358746 *tc358746 = clk_hw_to_tc358746(hw);
+
+ tc358746_write(tc358746, MCLKCTL_REG, 0);
+}
+
+static long
+tc358746_find_mclk_settings(struct tc358746 *tc358746, unsigned long mclk_rate)
+{
+ unsigned long pll_rate = tc358746->pll_rate;
+ const unsigned char prediv[] = { 2, 4, 8 };
+ unsigned int mclk_prediv, mclk_postdiv;
+ struct device *dev = tc358746->sd.dev;
+ unsigned int postdiv, mclkdiv;
+ unsigned long best_mclk_rate;
+ unsigned int i;
+
+ /*
+ * MCLK-Div
+ * -------------------´`---------------------
+ * ´ `
+ * +-------------+ +------------------------+
+ * | MCLK-PreDiv | | MCLK-PostDiv |
+ * PLL --> | (2/4/8) | --> | (mclk_low + mclk_high) | --> MCLK
+ * +-------------+ +------------------------+
+ *
+ * The register value of mclk_low/high is mclk_low/high+1, i.e.:
+ * mclk_low/high = 1 --> 2 MCLK-Ref Counts
+ * mclk_low/high = 255 --> 256 MCLK-Ref Counts == max.
+ * If mclk_low and mclk_high are 0 then MCLK is disabled.
+ *
+ * Keep it simple and support 50/50 duty cycles only for now,
+ * so the calc will be:
+ *
+ * MCLK = PLL / (MCLK-PreDiv * 2 * MCLK-PostDiv)
+ */
+
+ if (mclk_rate == tc358746->mclk_rate)
+ return mclk_rate;
+
+ /* Highest possible rate */
+ mclkdiv = pll_rate / mclk_rate;
+ if (mclkdiv <= 8) {
+ mclk_prediv = 2;
+ mclk_postdiv = 4;
+ best_mclk_rate = pll_rate / (2 * 4);
+ goto out;
+ }
+
+ /* First check the prediv */
+ for (i = 0; i < ARRAY_SIZE(prediv); i++) {
+ postdiv = mclkdiv / prediv[i];
+
+ if (postdiv % 2)
+ continue;
+
+ if (postdiv >= 4 && postdiv <= 512) {
+ mclk_prediv = prediv[i];
+ mclk_postdiv = postdiv;
+ best_mclk_rate = pll_rate / (prediv[i] * postdiv);
+ goto out;
+ }
+ }
+
+ /* No suitable prediv found, so try to adjust the postdiv */
+ for (postdiv = 4; postdiv <= 512; postdiv += 2) {
+ unsigned int pre;
+
+ pre = mclkdiv / postdiv;
+ if (pre == 2 || pre == 4 || pre == 8) {
+ mclk_prediv = pre;
+ mclk_postdiv = postdiv;
+ best_mclk_rate = pll_rate / (pre * postdiv);
+ goto out;
+ }
+ }
+
+ /* The MCLK <-> PLL gap is to high -> use largest possible div */
+ mclk_prediv = 8;
+ mclk_postdiv = 512;
+ best_mclk_rate = pll_rate / (8 * 512);
+
+out:
+ tc358746->mclk_prediv = mclk_prediv;
+ tc358746->mclk_postdiv = mclk_postdiv;
+ tc358746->mclk_rate = best_mclk_rate;
+
+ if (best_mclk_rate != mclk_rate)
+ dev_warn(dev, "Request MCLK freq:%lu, found MCLK freq:%lu\n",
+ mclk_rate, best_mclk_rate);
+
+ dev_dbg(dev, "Found MCLK settings: freq:%lu prediv:%u postdiv:%u\n",
+ best_mclk_rate, mclk_prediv, mclk_postdiv);
+
+ return best_mclk_rate;
+}
+
+static unsigned long
+tc358746_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct tc358746 *tc358746 = clk_hw_to_tc358746(hw);
+ unsigned int prediv, postdiv;
+ u32 val;
+ int err;
+
+ err = tc358746_read(tc358746, MCLKCTL_REG, &val);
+ if (err)
+ return 0;
+
+ postdiv = FIELD_GET(MCLK_LOW_MASK, val) + 1;
+ postdiv += FIELD_GET(MCLK_HIGH_MASK, val) + 1;
+
+ err = tc358746_read(tc358746, CLKCTL_REG, &val);
+ if (err)
+ return 0;
+
+ prediv = FIELD_GET(MCLKDIV_MASK, val);
+ if (prediv == MCLKDIV_8)
+ prediv = 8;
+ else if (prediv == MCLKDIV_4)
+ prediv = 4;
+ else
+ prediv = 2;
+
+ return tc358746->pll_rate / (prediv * postdiv);
+}
+
+static long tc358746_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct tc358746 *tc358746 = clk_hw_to_tc358746(hw);
+
+ *parent_rate = tc358746->pll_rate;
+
+ return tc358746_find_mclk_settings(tc358746, rate);
+}
+
+static int tc358746_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tc358746 *tc358746 = clk_hw_to_tc358746(hw);
+
+ tc358746_find_mclk_settings(tc358746, rate);
+
+ return tc358746_mclk_enable(hw);
+}
+
+static const struct clk_ops tc358746_mclk_ops = {
+ .enable = tc358746_mclk_enable,
+ .disable = tc358746_mclk_disable,
+ .recalc_rate = tc358746_recalc_rate,
+ .round_rate = tc358746_mclk_round_rate,
+ .set_rate = tc358746_mclk_set_rate,
+};
+
+static int tc358746_setup_mclk_provider(struct tc358746 *tc358746)
+{
+ struct clk_init_data mclk_initdata = { };
+ struct device *dev = tc358746->sd.dev;
+ const char *mclk_name;
+ int err;
+
+ /* MCLK clk provider support is optional */
+ if (!device_property_present(dev, "#clock-cells"))
+ return 0;
+
+ /* Init to highest possibel MCLK */
+ tc358746->mclk_postdiv = 512;
+ tc358746->mclk_prediv = 8;
+
+ mclk_name = "tc358746-mclk";
+ device_property_read_string(dev, "clock-output-names", &mclk_name);
+
+ mclk_initdata.name = mclk_name;
+ mclk_initdata.ops = &tc358746_mclk_ops;
+ tc358746->mclk_hw.init = &mclk_initdata;
+
+ err = devm_clk_hw_register(dev, &tc358746->mclk_hw);
+ if (err) {
+ dev_err(dev, "Failed to register mclk provider\n");
+ return err;
+ }
+
+ err = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &tc358746->mclk_hw);
+ if (err)
+ dev_err(dev, "Failed to add mclk provider\n");
+
+ return err;
+}
+
+static int
+tc358746_init_subdev(struct tc358746 *tc358746, struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = &tc358746->sd;
+ int err;
+
+ v4l2_i2c_subdev_init(sd, client, &tc358746_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ sd->entity.ops = &tc358746_entity_ops;
+
+ tc358746->pads[TC358746_SINK].flags = MEDIA_PAD_FL_SINK;
+ tc358746->pads[TC358746_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ err = media_entity_pads_init(&sd->entity, TC358746_NR_PADS,
+ tc358746->pads);
+ if (err)
+ return err;
+
+ err = v4l2_subdev_init_finalize(sd);
+ if (err)
+ media_entity_cleanup(&sd->entity);
+
+ return err;
+}
+
+static int
+tc358746_init_output_port(struct tc358746 *tc358746, unsigned long refclk)
+{
+ struct device *dev = tc358746->sd.dev;
+ struct v4l2_fwnode_endpoint *vep;
+ unsigned long csi_link_rate;
+ struct fwnode_handle *ep;
+ unsigned char csi_lanes;
+ int err;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), TC358746_SOURCE,
+ 0, 0);
+ if (!ep) {
+ dev_err(dev, "Missing endpoint node\n");
+ return -EINVAL;
+ }
+
+ /* Currently we only support 'parallel in' -> 'csi out' */
+ vep = &tc358746->csi_vep;
+ vep->bus_type = V4L2_MBUS_CSI2_DPHY;
+ err = v4l2_fwnode_endpoint_alloc_parse(ep, vep);
+ fwnode_handle_put(ep);
+ if (err) {
+ dev_err(dev, "Failed to parse source endpoint\n");
+ return err;
+ }
+
+ csi_lanes = vep->bus.mipi_csi2.num_data_lanes;
+ if (csi_lanes == 0 || csi_lanes > 4 ||
+ vep->nr_of_link_frequencies == 0) {
+ dev_err(dev, "error: Invalid CSI-2 settings\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ /* TODO: Add support to handle multiple link frequencies */
+ csi_link_rate = (unsigned long)vep->link_frequencies[0];
+ tc358746->pll_rate = tc358746_find_pll_settings(tc358746, refclk,
+ csi_link_rate * 2);
+ if (!tc358746->pll_rate) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = phy_mipi_dphy_get_default_config_for_hsclk(tc358746->pll_rate,
+ csi_lanes, &tc358746->dphy_cfg);
+ if (err)
+ goto err;
+
+ tc358746->vb_size = TC358746_VB_DEFAULT_SIZE;
+
+ return 0;
+
+err:
+ v4l2_fwnode_endpoint_free(vep);
+
+ return err;
+}
+
+static int tc358746_init_hw(struct tc358746 *tc358746)
+{
+ struct device *dev = tc358746->sd.dev;
+ unsigned int chipid;
+ u32 val;
+ int err;
+
+ err = pm_runtime_resume_and_get(dev);
+ if (err < 0) {
+ dev_err(dev, "Failed to resume the device\n");
+ return err;
+ }
+
+ /* Ensure that CSI interface is put into LP-11 state */
+ err = tc358746_sw_reset(tc358746);
+ if (err) {
+ pm_runtime_put_sync(dev);
+ dev_err(dev, "Failed to reset the device\n");
+ return err;
+ }
+
+ err = tc358746_read(tc358746, CHIPID_REG, &val);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+ if (err)
+ return -ENODEV;
+
+ chipid = FIELD_GET(CHIPID, val);
+ if (chipid != 0x44) {
+ dev_err(dev, "Invalid chipid 0x%02x\n", chipid);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int tc358746_init_controls(struct tc358746 *tc358746)
+{
+ u64 *link_frequencies = tc358746->csi_vep.link_frequencies;
+ struct v4l2_ctrl *ctrl;
+ int err;
+
+ err = v4l2_ctrl_handler_init(&tc358746->ctrl_hdl, 1);
+ if (err)
+ return err;
+
+ /*
+ * The driver currently supports only one link-frequency, regardless of
+ * the input from the firmware, see: tc358746_init_output_port(). So
+ * report only the first frequency from the array of possible given
+ * frequencies.
+ */
+ ctrl = v4l2_ctrl_new_int_menu(&tc358746->ctrl_hdl, NULL,
+ V4L2_CID_LINK_FREQ, 0, 0,
+ link_frequencies);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ err = tc358746->ctrl_hdl.error;
+ if (err) {
+ v4l2_ctrl_handler_free(&tc358746->ctrl_hdl);
+ return err;
+ }
+
+ tc358746->sd.ctrl_handler = &tc358746->ctrl_hdl;
+
+ return 0;
+}
+
+static int tc358746_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct tc358746 *tc358746 =
+ container_of(notifier, struct tc358746, notifier);
+ u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
+ struct media_pad *sink = &tc358746->pads[TC358746_SINK];
+
+ return v4l2_create_fwnode_links_to_pad(sd, sink, flags);
+}
+
+static const struct v4l2_async_notifier_operations tc358746_notify_ops = {
+ .bound = tc358746_notify_bound,
+};
+
+static int tc358746_async_register(struct tc358746 *tc358746)
+{
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_PARALLEL,
+ };
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *ep;
+ int err;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(tc358746->sd.dev),
+ TC358746_SINK, 0, 0);
+ if (!ep)
+ return -ENOTCONN;
+
+ err = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (err) {
+ fwnode_handle_put(ep);
+ return err;
+ }
+
+ v4l2_async_nf_init(&tc358746->notifier);
+ asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep,
+ struct v4l2_async_subdev);
+ fwnode_handle_put(ep);
+
+ if (IS_ERR(asd)) {
+ err = PTR_ERR(asd);
+ goto err_cleanup;
+ }
+
+ tc358746->notifier.ops = &tc358746_notify_ops;
+
+ err = v4l2_async_subdev_nf_register(&tc358746->sd, &tc358746->notifier);
+ if (err)
+ goto err_cleanup;
+
+ tc358746->sd.fwnode = fwnode_graph_get_endpoint_by_id(
+ dev_fwnode(tc358746->sd.dev), TC358746_SOURCE, 0, 0);
+
+ err = v4l2_async_register_subdev(&tc358746->sd);
+ if (err)
+ goto err_unregister;
+
+ return 0;
+
+err_unregister:
+ fwnode_handle_put(tc358746->sd.fwnode);
+ v4l2_async_nf_unregister(&tc358746->notifier);
+err_cleanup:
+ v4l2_async_nf_cleanup(&tc358746->notifier);
+
+ return err;
+}
+
+static int tc358746_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct tc358746 *tc358746;
+ unsigned long refclk;
+ unsigned int i;
+ int err;
+
+ tc358746 = devm_kzalloc(&client->dev, sizeof(*tc358746), GFP_KERNEL);
+ if (!tc358746)
+ return -ENOMEM;
+
+ tc358746->regmap = devm_regmap_init_i2c(client, &tc358746_regmap_config);
+ if (IS_ERR(tc358746->regmap))
+ return dev_err_probe(dev, PTR_ERR(tc358746->regmap),
+ "Failed to init regmap\n");
+
+ tc358746->refclk = devm_clk_get(dev, "refclk");
+ if (IS_ERR(tc358746->refclk))
+ return dev_err_probe(dev, PTR_ERR(tc358746->refclk),
+ "Failed to get refclk\n");
+
+ err = clk_prepare_enable(tc358746->refclk);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Failed to enable refclk\n");
+
+ refclk = clk_get_rate(tc358746->refclk);
+ clk_disable_unprepare(tc358746->refclk);
+
+ if (refclk < 6 * HZ_PER_MHZ || refclk > 40 * HZ_PER_MHZ)
+ return dev_err_probe(dev, -EINVAL, "Invalid refclk range\n");
+
+ for (i = 0; i < ARRAY_SIZE(tc358746_supplies); i++)
+ tc358746->supplies[i].supply = tc358746_supplies[i];
+
+ err = devm_regulator_bulk_get(dev, ARRAY_SIZE(tc358746_supplies),
+ tc358746->supplies);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to get supplies\n");
+
+ tc358746->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(tc358746->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(tc358746->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ err = tc358746_init_subdev(tc358746, client);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to init subdev\n");
+
+ err = tc358746_init_output_port(tc358746, refclk);
+ if (err)
+ goto err_subdev;
+
+ /*
+ * Keep this order since we need the output port link-frequencies
+ * information.
+ */
+ err = tc358746_init_controls(tc358746);
+ if (err)
+ goto err_fwnode;
+
+ dev_set_drvdata(dev, tc358746);
+
+ /* Set to 1sec to give the stream reconfiguration enough time */
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
+
+ err = tc358746_init_hw(tc358746);
+ if (err)
+ goto err_pm;
+
+ err = tc358746_setup_mclk_provider(tc358746);
+ if (err)
+ goto err_pm;
+
+ err = tc358746_async_register(tc358746);
+ if (err < 0)
+ goto err_pm;
+
+ dev_dbg(dev, "%s found @ 0x%x (%s)\n", client->name,
+ client->addr, client->adapter->name);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+ v4l2_ctrl_handler_free(&tc358746->ctrl_hdl);
+err_fwnode:
+ v4l2_fwnode_endpoint_free(&tc358746->csi_vep);
+err_subdev:
+ v4l2_subdev_cleanup(&tc358746->sd);
+ media_entity_cleanup(&tc358746->sd.entity);
+
+ return err;
+}
+
+static void tc358746_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tc358746 *tc358746 = to_tc358746(sd);
+
+ v4l2_subdev_cleanup(sd);
+ v4l2_ctrl_handler_free(&tc358746->ctrl_hdl);
+ v4l2_fwnode_endpoint_free(&tc358746->csi_vep);
+ v4l2_async_nf_unregister(&tc358746->notifier);
+ v4l2_async_nf_cleanup(&tc358746->notifier);
+ fwnode_handle_put(sd->fwnode);
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+
+ pm_runtime_disable(sd->dev);
+ pm_runtime_set_suspended(sd->dev);
+ pm_runtime_dont_use_autosuspend(sd->dev);
+}
+
+static int tc358746_suspend(struct device *dev)
+{
+ struct tc358746 *tc358746 = dev_get_drvdata(dev);
+ int err;
+
+ clk_disable_unprepare(tc358746->refclk);
+
+ err = regulator_bulk_disable(ARRAY_SIZE(tc358746_supplies),
+ tc358746->supplies);
+ if (err)
+ clk_prepare_enable(tc358746->refclk);
+
+ return err;
+}
+
+static int tc358746_resume(struct device *dev)
+{
+ struct tc358746 *tc358746 = dev_get_drvdata(dev);
+ int err;
+
+ gpiod_set_value(tc358746->reset_gpio, 1);
+
+ err = regulator_bulk_enable(ARRAY_SIZE(tc358746_supplies),
+ tc358746->supplies);
+ if (err)
+ return err;
+
+ /* min. 200ns */
+ usleep_range(10, 20);
+
+ gpiod_set_value(tc358746->reset_gpio, 0);
+
+ err = clk_prepare_enable(tc358746->refclk);
+ if (err)
+ goto err;
+
+ /* min. 700us ... 1ms */
+ usleep_range(1000, 1500);
+
+ /*
+ * Enable the PLL here since it can be called by the clk-framework or by
+ * the .s_stream() callback. So this is the common place for both.
+ */
+ err = tc358746_apply_pll_config(tc358746);
+ if (err)
+ goto err_clk;
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(tc358746->refclk);
+err:
+ regulator_bulk_disable(ARRAY_SIZE(tc358746_supplies),
+ tc358746->supplies);
+ return err;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(tc358746_pm_ops, tc358746_suspend,
+ tc358746_resume, NULL);
+
+static const struct of_device_id __maybe_unused tc358746_of_match[] = {
+ { .compatible = "toshiba,tc358746" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tc358746_of_match);
+
+static struct i2c_driver tc358746_driver = {
+ .driver = {
+ .name = "tc358746",
+ .pm = pm_ptr(&tc358746_pm_ops),
+ .of_match_table = tc358746_of_match,
+ },
+ .probe_new = tc358746_probe,
+ .remove = tc358746_remove,
+};
+
+module_i2c_driver(tc358746_driver);
+
+MODULE_DESCRIPTION("Toshiba TC358746 Parallel to CSI-2 bridge driver");
+MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index 11e918311b13..bbceaac8e0b3 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -343,8 +343,7 @@ static const struct v4l2_subdev_ops tda7432_ops = {
* i2c interface functions *
* *********************** */
-static int tda7432_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda7432_probe(struct i2c_client *client)
{
struct tda7432 *t;
struct v4l2_subdev *sd;
@@ -410,7 +409,7 @@ static struct i2c_driver tda7432_driver = {
.driver = {
.name = "tda7432",
},
- .probe = tda7432_probe,
+ .probe_new = tda7432_probe,
.remove = tda7432_remove,
.id_table = tda7432_id,
};
diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c
index aaa74944fc7c..25fbd7e3950e 100644
--- a/drivers/media/i2c/tda9840.c
+++ b/drivers/media/i2c/tda9840.c
@@ -149,8 +149,7 @@ static const struct v4l2_subdev_ops tda9840_ops = {
/* ----------------------------------------------------------------------- */
-static int tda9840_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda9840_probe(struct i2c_client *client)
{
struct v4l2_subdev *sd;
@@ -192,7 +191,7 @@ static struct i2c_driver tda9840_driver = {
.driver = {
.name = "tda9840",
},
- .probe = tda9840_probe,
+ .probe_new = tda9840_probe,
.remove = tda9840_remove,
.id_table = tda9840_id,
};
diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c
index 50e74314f315..d375d2d24354 100644
--- a/drivers/media/i2c/tea6415c.c
+++ b/drivers/media/i2c/tea6415c.c
@@ -116,8 +116,7 @@ static const struct v4l2_subdev_ops tea6415c_ops = {
.video = &tea6415c_video_ops,
};
-static int tea6415c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tea6415c_probe(struct i2c_client *client)
{
struct v4l2_subdev *sd;
@@ -151,7 +150,7 @@ static struct i2c_driver tea6415c_driver = {
.driver = {
.name = "tea6415c",
},
- .probe = tea6415c_probe,
+ .probe_new = tea6415c_probe,
.remove = tea6415c_remove,
.id_table = tea6415c_id,
};
diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c
index 246f2b10ccc7..9da1f3b02c57 100644
--- a/drivers/media/i2c/tea6420.c
+++ b/drivers/media/i2c/tea6420.c
@@ -87,8 +87,7 @@ static const struct v4l2_subdev_ops tea6420_ops = {
.audio = &tea6420_audio_ops,
};
-static int tea6420_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tea6420_probe(struct i2c_client *client)
{
struct v4l2_subdev *sd;
int err, i;
@@ -133,7 +132,7 @@ static struct i2c_driver tea6420_driver = {
.driver = {
.name = "tea6420",
},
- .probe = tea6420_probe,
+ .probe_new = tea6420_probe,
.remove = tea6420_remove,
.id_table = tea6420_id,
};
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index 2a0f9a3d1a66..67de90cf696e 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -322,8 +322,7 @@ static const struct v4l2_subdev_ops ths7303_ops = {
.video = &ths7303_video_ops,
};
-static int ths7303_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ths7303_probe(struct i2c_client *client)
{
struct ths7303_platform_data *pdata = client->dev.platform_data;
struct ths7303_state *state;
@@ -377,7 +376,7 @@ static struct i2c_driver ths7303_driver = {
.driver = {
.name = "ths73x3",
},
- .probe = ths7303_probe,
+ .probe_new = ths7303_probe,
.remove = ths7303_remove,
.id_table = ths7303_id,
};
diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c
index 937fa1dbaecb..47198e803817 100644
--- a/drivers/media/i2c/tlv320aic23b.c
+++ b/drivers/media/i2c/tlv320aic23b.c
@@ -129,8 +129,7 @@ static const struct v4l2_subdev_ops tlv320aic23b_ops = {
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int tlv320aic23b_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tlv320aic23b_probe(struct i2c_client *client)
{
struct tlv320aic23b_state *state;
struct v4l2_subdev *sd;
@@ -198,7 +197,7 @@ static struct i2c_driver tlv320aic23b_driver = {
.driver = {
.name = "tlv320aic23b",
},
- .probe = tlv320aic23b_probe,
+ .probe_new = tlv320aic23b_probe,
.remove = tlv320aic23b_remove,
.id_table = tlv320aic23b_id,
};
diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c
index c7c8dfe8a8a8..710790ece11b 100644
--- a/drivers/media/i2c/tw2804.c
+++ b/drivers/media/i2c/tw2804.c
@@ -343,8 +343,7 @@ static const struct v4l2_subdev_ops tw2804_ops = {
.video = &tw2804_video_ops,
};
-static int tw2804_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tw2804_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct tw2804 *state;
@@ -424,7 +423,7 @@ static struct i2c_driver tw2804_driver = {
.driver = {
.name = "tw2804",
},
- .probe = tw2804_probe,
+ .probe_new = tw2804_probe,
.remove = tw2804_remove,
.id_table = tw2804_id,
};
diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c
index d7eef7986b75..428ee55787e1 100644
--- a/drivers/media/i2c/tw9903.c
+++ b/drivers/media/i2c/tw9903.c
@@ -189,8 +189,7 @@ static const struct v4l2_subdev_ops tw9903_ops = {
/* --------------------------------------------------------------------------*/
-static int tw9903_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tw9903_probe(struct i2c_client *client)
{
struct tw9903 *dec;
struct v4l2_subdev *sd;
@@ -255,7 +254,7 @@ static struct i2c_driver tw9903_driver = {
.driver = {
.name = "tw9903",
},
- .probe = tw9903_probe,
+ .probe_new = tw9903_probe,
.remove = tw9903_remove,
.id_table = tw9903_id,
};
diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c
index 549ad8f72f12..7824ed9b04ed 100644
--- a/drivers/media/i2c/tw9906.c
+++ b/drivers/media/i2c/tw9906.c
@@ -157,8 +157,7 @@ static const struct v4l2_subdev_ops tw9906_ops = {
.video = &tw9906_video_ops,
};
-static int tw9906_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tw9906_probe(struct i2c_client *client)
{
struct tw9906 *dec;
struct v4l2_subdev *sd;
@@ -223,7 +222,7 @@ static struct i2c_driver tw9906_driver = {
.driver = {
.name = "tw9906",
},
- .probe = tw9906_probe,
+ .probe_new = tw9906_probe,
.remove = tw9906_remove,
.id_table = tw9906_id,
};
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
index 853b5acead32..459fa22f4341 100644
--- a/drivers/media/i2c/tw9910.c
+++ b/drivers/media/i2c/tw9910.c
@@ -928,8 +928,7 @@ static const struct v4l2_subdev_ops tw9910_subdev_ops = {
* i2c_driver function
*/
-static int tw9910_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int tw9910_probe(struct i2c_client *client)
{
struct tw9910_priv *priv;
@@ -1013,7 +1012,7 @@ static struct i2c_driver tw9910_i2c_driver = {
.driver = {
.name = "tw9910",
},
- .probe = tw9910_probe,
+ .probe_new = tw9910_probe,
.remove = tw9910_remove,
.id_table = tw9910_id,
};
diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c
index d0659c4392f2..b6873d866272 100644
--- a/drivers/media/i2c/uda1342.c
+++ b/drivers/media/i2c/uda1342.c
@@ -45,8 +45,7 @@ static const struct v4l2_subdev_ops uda1342_ops = {
.audio = &uda1342_audio_ops,
};
-static int uda1342_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int uda1342_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct v4l2_subdev *sd;
@@ -89,7 +88,7 @@ static struct i2c_driver uda1342_driver = {
.driver = {
.name = "uda1342",
},
- .probe = uda1342_probe,
+ .probe_new = uda1342_probe,
.remove = uda1342_remove,
.id_table = uda1342_id,
};
diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c
index 4de26ed2ba00..47eed3aab060 100644
--- a/drivers/media/i2c/upd64031a.c
+++ b/drivers/media/i2c/upd64031a.c
@@ -183,8 +183,7 @@ static const struct v4l2_subdev_ops upd64031a_ops = {
/* i2c implementation */
-static int upd64031a_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int upd64031a_probe(struct i2c_client *client)
{
struct upd64031a_state *state;
struct v4l2_subdev *sd;
@@ -229,7 +228,7 @@ static struct i2c_driver upd64031a_driver = {
.driver = {
.name = "upd64031a",
},
- .probe = upd64031a_probe,
+ .probe_new = upd64031a_probe,
.remove = upd64031a_remove,
.id_table = upd64031a_id,
};
diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c
index 2bfd5443d406..3f5a7d4853a1 100644
--- a/drivers/media/i2c/upd64083.c
+++ b/drivers/media/i2c/upd64083.c
@@ -154,8 +154,7 @@ static const struct v4l2_subdev_ops upd64083_ops = {
/* i2c implementation */
-static int upd64083_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int upd64083_probe(struct i2c_client *client)
{
struct upd64083_state *state;
struct v4l2_subdev *sd;
@@ -200,7 +199,7 @@ static struct i2c_driver upd64083_driver = {
.driver = {
.name = "upd64083",
},
- .probe = upd64083_probe,
+ .probe_new = upd64083_probe,
.remove = upd64083_remove,
.id_table = upd64083_id,
};
diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
index c832edad5fa7..ed1c58ea8ed3 100644
--- a/drivers/media/i2c/vp27smpx.c
+++ b/drivers/media/i2c/vp27smpx.c
@@ -138,8 +138,7 @@ static const struct v4l2_subdev_ops vp27smpx_ops = {
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int vp27smpx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vp27smpx_probe(struct i2c_client *client)
{
struct vp27smpx_state *state;
struct v4l2_subdev *sd;
@@ -182,7 +181,7 @@ static struct i2c_driver vp27smpx_driver = {
.driver = {
.name = "vp27smpx",
},
- .probe = vp27smpx_probe,
+ .probe_new = vp27smpx_probe,
.remove = vp27smpx_remove,
.id_table = vp27smpx_id,
};
diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c
index b481ec196b88..aa73d5dcc3e7 100644
--- a/drivers/media/i2c/vpx3220.c
+++ b/drivers/media/i2c/vpx3220.c
@@ -456,8 +456,7 @@ static const struct v4l2_subdev_ops vpx3220_ops = {
* Client management code
*/
-static int vpx3220_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vpx3220_probe(struct i2c_client *client)
{
struct vpx3220 *decoder;
struct v4l2_subdev *sd;
@@ -547,7 +546,7 @@ static struct i2c_driver vpx3220_driver = {
.driver = {
.name = "vpx3220",
},
- .probe = vpx3220_probe,
+ .probe_new = vpx3220_probe,
.remove = vpx3220_remove,
.id_table = vpx3220_id,
};
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index d496bb45f201..d35c5ec148f4 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -738,8 +738,7 @@ static const struct v4l2_subdev_ops vs6624_ops = {
.pad = &vs6624_pad_ops,
};
-static int vs6624_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vs6624_probe(struct i2c_client *client)
{
struct vs6624 *sensor;
struct v4l2_subdev *sd;
@@ -843,7 +842,7 @@ static struct i2c_driver vs6624_driver = {
.driver = {
.name = "vs6624",
},
- .probe = vs6624_probe,
+ .probe_new = vs6624_probe,
.remove = vs6624_remove,
.id_table = vs6624_id,
};
diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c
index 180b35347521..8b34a673ffd3 100644
--- a/drivers/media/i2c/wm8739.c
+++ b/drivers/media/i2c/wm8739.c
@@ -178,8 +178,7 @@ static const struct v4l2_subdev_ops wm8739_ops = {
/* i2c implementation */
-static int wm8739_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int wm8739_probe(struct i2c_client *client)
{
struct wm8739_state *state;
struct v4l2_subdev *sd;
@@ -253,7 +252,7 @@ static struct i2c_driver wm8739_driver = {
.driver = {
.name = "wm8739",
},
- .probe = wm8739_probe,
+ .probe_new = wm8739_probe,
.remove = wm8739_remove,
.id_table = wm8739_id,
};
diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c
index 8ff97867d3cd..56d98518f7eb 100644
--- a/drivers/media/i2c/wm8775.c
+++ b/drivers/media/i2c/wm8775.c
@@ -190,8 +190,7 @@ static const struct v4l2_subdev_ops wm8775_ops = {
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int wm8775_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int wm8775_probe(struct i2c_client *client)
{
struct wm8775_state *state;
struct v4l2_subdev *sd;
@@ -299,7 +298,7 @@ static struct i2c_driver wm8775_driver = {
.driver = {
.name = "wm8775",
},
- .probe = wm8775_probe,
+ .probe_new = wm8775_probe,
.remove = wm8775_remove,
.id_table = wm8775_id,
};
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index d24b9ef9f59f..eed7eeb3b963 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -289,7 +289,6 @@ extern void bttv_init_card2(struct bttv *btv);
extern void bttv_init_tuner(struct bttv *btv);
/* card-specific functions */
-extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits);
/* extra tweaks for some chipsets */
diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h
index cf0d3f5509e7..080c8490a250 100644
--- a/drivers/media/pci/cx25821/cx25821-video.h
+++ b/drivers/media/pci/cx25821/cx25821-video.h
@@ -36,9 +36,6 @@ do { \
} while (0)
#define FORMAT_FLAGS_PACKED 0x01
-extern void cx25821_video_wakeup(struct cx25821_dev *dev,
- struct cx25821_dmaqueue *q, u32 count);
-
extern int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig
index 39bd3be0b43d..65b0c1598fbf 100644
--- a/drivers/media/pci/intel/ipu3/Kconfig
+++ b/drivers/media/pci/intel/ipu3/Kconfig
@@ -21,6 +21,7 @@ config VIDEO_IPU3_CIO2
config CIO2_BRIDGE
bool "IPU3 CIO2 Sensors Bridge"
depends on VIDEO_IPU3_CIO2 && ACPI
+ depends on I2C
help
This extension provides an API for the ipu3-cio2 driver to create
connections to cameras that are hidden in the SSDB buffer in ACPI.
diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig
index 9dfaf2c9a7b3..374b8f382f62 100644
--- a/drivers/media/pci/mantis/Kconfig
+++ b/drivers/media/pci/mantis/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config MANTIS_CORE
tristate "Mantis/Hopper PCI bridge based devices"
- depends on PCI && I2C && INPUT && RC_CORE
+ depends on PCI && I2C && INPUT && RC_CORE && DVB_CORE
help
Support for PCI cards based on the Mantis and Hopper PCi bridge.
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
index f6deac85962e..246f73b8a9e7 100644
--- a/drivers/media/pci/pt3/pt3.c
+++ b/drivers/media/pci/pt3/pt3.c
@@ -707,18 +707,10 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret < 0)
return ret;
- ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
- if (ret == 0)
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
- else {
- ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret == 0)
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- else {
- dev_err(&pdev->dev, "Failed to set DMA mask\n");
- return ret;
- }
- dev_info(&pdev->dev, "Use 32bit DMA\n");
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set DMA mask\n");
+ return ret;
}
pt3 = devm_kzalloc(&pdev->dev, sizeof(*pt3), GFP_KERNEL);
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 49fe0f6bacba..5c9b2912a9d1 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -866,7 +866,6 @@ int saa7134_ts_stop(struct saa7134_dev *dev);
/* saa7134-vbi.c */
extern const struct vb2_ops saa7134_vbi_qops;
-extern struct video_device saa7134_vbi_template;
int saa7134_vbi_init1(struct saa7134_dev *dev);
int saa7134_vbi_fini(struct saa7134_dev *dev);
@@ -897,9 +896,6 @@ void saa7134_enable_i2s(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
/* saa7134-oss.c */
-extern const struct file_operations saa7134_dsp_fops;
-extern const struct file_operations saa7134_mixer_fops;
-
int saa7134_oss_init1(struct saa7134_dev *dev);
int saa7134_oss_fini(struct saa7134_dev *dev);
void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index d5f32e3ff544..a8a004f28ca0 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -352,7 +352,7 @@ static void saa7164_work_enchandler(struct work_struct *w)
container_of(w, struct saa7164_port, workenc);
struct saa7164_dev *dev = port->dev;
- u32 wp, mcb, rp, cnt = 0;
+ u32 wp, mcb, rp;
port->last_svc_msecs_diff = port->last_svc_msecs;
port->last_svc_msecs = jiffies_to_msecs(jiffies);
@@ -405,7 +405,6 @@ static void saa7164_work_enchandler(struct work_struct *w)
saa7164_work_enchandler_helper(port, rp);
port->last_svc_rp = rp;
- cnt++;
if (rp == mcb)
break;
@@ -429,7 +428,7 @@ static void saa7164_work_vbihandler(struct work_struct *w)
container_of(w, struct saa7164_port, workenc);
struct saa7164_dev *dev = port->dev;
- u32 wp, mcb, rp, cnt = 0;
+ u32 wp, mcb, rp;
port->last_svc_msecs_diff = port->last_svc_msecs;
port->last_svc_msecs = jiffies_to_msecs(jiffies);
@@ -481,7 +480,6 @@ static void saa7164_work_vbihandler(struct work_struct *w)
saa7164_work_enchandler_helper(port, rp);
port->last_svc_rp = rp;
- cnt++;
if (rp == mcb)
break;
@@ -1259,7 +1257,7 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
if (saa7164_dev_setup(dev) < 0) {
err = -EINVAL;
- goto fail_free;
+ goto fail_dev;
}
/* print pci info */
@@ -1427,6 +1425,8 @@ fail_fw:
fail_irq:
saa7164_dev_unregister(dev);
+fail_dev:
+ pci_disable_device(pci_dev);
fail_free:
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
index 4b4eb156e214..eede47b686a3 100644
--- a/drivers/media/pci/saa7164/saa7164.h
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -493,8 +493,6 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev);
/* saa7164-i2c.c */
extern int saa7164_i2c_register(struct saa7164_i2c *bus);
extern int saa7164_i2c_unregister(struct saa7164_i2c *bus);
-extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
- unsigned int cmd, void *arg);
/* ----------------------------------------------------------- */
/* saa7164-bus.c */
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
index 4a546eeefe38..6d87fbb0ee04 100644
--- a/drivers/media/pci/solo6x10/solo6x10-core.c
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -420,6 +420,7 @@ static int solo_sysfs_init(struct solo_dev *solo_dev)
solo_dev->nr_chans);
if (device_register(dev)) {
+ put_device(dev);
dev->parent = NULL;
return -ENOMEM;
}
diff --git a/drivers/media/pci/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h
index 34fd5cc914eb..237e830ae726 100644
--- a/drivers/media/pci/zoran/zoran_device.h
+++ b/drivers/media/pci/zoran/zoran_device.h
@@ -47,8 +47,6 @@ void zr36057_restart(struct zoran *zr);
extern const struct zoran_format zoran_formats[];
-extern int v4l_bufsize;
-extern int jpg_bufsize;
extern int pass_through;
/* i2c */
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index a9334263fa9b..ee579916f874 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -72,6 +72,7 @@ source "drivers/media/platform/chips-media/Kconfig"
source "drivers/media/platform/intel/Kconfig"
source "drivers/media/platform/marvell/Kconfig"
source "drivers/media/platform/mediatek/Kconfig"
+source "drivers/media/platform/microchip/Kconfig"
source "drivers/media/platform/nvidia/Kconfig"
source "drivers/media/platform/nxp/Kconfig"
source "drivers/media/platform/qcom/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index a91f42024273..5453bb868e67 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -15,6 +15,7 @@ obj-y += chips-media/
obj-y += intel/
obj-y += marvell/
obj-y += mediatek/
+obj-y += microchip/
obj-y += nvidia/
obj-y += nxp/
obj-y += qcom/
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index feb75dc204de..87f9f8e90ab1 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -69,72 +69,101 @@ struct vdec_t {
static const struct vpu_format vdec_formats[] = {
{
.pixfmt = V4L2_PIX_FMT_NV12M_8L128,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12_8L128,
+ },
+ {
+ .pixfmt = V4L2_PIX_FMT_NV12_8L128,
+ .mem_planes = 1,
+ .comp_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12M_8L128,
},
{
.pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12_10BE_8L128,
+ },
+ {
+ .pixfmt = V4L2_PIX_FMT_NV12_10BE_8L128,
+ .mem_planes = 1,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12M_10BE_8L128
},
{
.pixfmt = V4L2_PIX_FMT_H264,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_H264_MVC,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_HEVC,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_MPEG2,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_XVID,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VP8,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_H263,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{0, 0, 0, 0},
};
@@ -256,23 +285,22 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
int ret = -EINVAL;
vpu_inst_lock(inst);
- if (!V4L2_TYPE_IS_OUTPUT(f->type) && vdec->fixed_fmt) {
- if (f->index == 0) {
- f->pixelformat = inst->cap_format.pixfmt;
- f->flags = inst->cap_format.flags;
- ret = 0;
- }
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) {
+ fmt = vpu_get_format(inst, f->type);
+ if (f->index == 1)
+ fmt = vpu_helper_find_sibling(inst, f->type, fmt->pixfmt);
+ if (f->index > 1)
+ fmt = NULL;
} else {
fmt = vpu_helper_enum_format(inst, f->type, f->index);
- memset(f->reserved, 0, sizeof(f->reserved));
- if (!fmt)
- goto exit;
-
- f->pixelformat = fmt->pixfmt;
- f->flags = fmt->flags;
- ret = 0;
}
+ if (!fmt)
+ goto exit;
+ memset(f->reserved, 0, sizeof(f->reserved));
+ f->pixelformat = fmt->pixfmt;
+ f->flags = fmt->flags;
+ ret = 0;
exit:
vpu_inst_unlock(inst);
return ret;
@@ -286,23 +314,25 @@ static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
struct vpu_format *cur_fmt;
int i;
+ vpu_inst_lock(inst);
cur_fmt = vpu_get_format(inst, f->type);
pixmp->pixelformat = cur_fmt->pixfmt;
- pixmp->num_planes = cur_fmt->num_planes;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
pixmp->field = cur_fmt->field;
pixmp->flags = cur_fmt->flags;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries;
f->fmt.pix_mp.xfer_func = vdec->codec_info.transfer_chars;
f->fmt.pix_mp.ycbcr_enc = vdec->codec_info.matrix_coeffs;
f->fmt.pix_mp.quantization = vdec->codec_info.full_range;
+ vpu_inst_unlock(inst);
return 0;
}
@@ -311,10 +341,19 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_inst *inst = to_inst(file);
struct vdec_t *vdec = inst->priv;
-
- vpu_try_fmt_common(inst, f);
+ struct vpu_format fmt;
vpu_inst_lock(inst);
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) {
+ struct vpu_format *cap_fmt = vpu_get_format(inst, f->type);
+
+ if (!vpu_helper_match_format(inst, cap_fmt->type, cap_fmt->pixfmt,
+ f->fmt.pix_mp.pixelformat))
+ f->fmt.pix_mp.pixelformat = cap_fmt->pixfmt;
+ }
+
+ vpu_try_fmt_common(inst, f, &fmt);
+
if (vdec->fixed_fmt) {
f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries;
f->fmt.pix_mp.xfer_func = vdec->codec_info.transfer_chars;
@@ -334,7 +373,7 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
- const struct vpu_format *fmt;
+ struct vpu_format fmt;
struct vpu_format *cur_fmt;
struct vb2_queue *q;
struct vdec_t *vdec = inst->priv;
@@ -349,36 +388,30 @@ static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
if (vb2_is_busy(q))
return -EBUSY;
- fmt = vpu_try_fmt_common(inst, f);
- if (!fmt)
+ if (vpu_try_fmt_common(inst, f, &fmt))
return -EINVAL;
cur_fmt = vpu_get_format(inst, f->type);
if (V4L2_TYPE_IS_OUTPUT(f->type) && inst->state != VPU_CODEC_STATE_DEINIT) {
- if (cur_fmt->pixfmt != fmt->pixfmt) {
+ if (cur_fmt->pixfmt != fmt.pixfmt) {
vdec->reset_codec = true;
vdec->fixed_fmt = false;
}
}
- cur_fmt->pixfmt = fmt->pixfmt;
if (V4L2_TYPE_IS_OUTPUT(f->type) || !vdec->fixed_fmt) {
- cur_fmt->num_planes = fmt->num_planes;
- cur_fmt->flags = fmt->flags;
- cur_fmt->width = pixmp->width;
- cur_fmt->height = pixmp->height;
- for (i = 0; i < fmt->num_planes; i++) {
- cur_fmt->sizeimage[i] = pixmp->plane_fmt[i].sizeimage;
- cur_fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline;
- }
- if (pixmp->field != V4L2_FIELD_ANY)
- cur_fmt->field = pixmp->field;
+ memcpy(cur_fmt, &fmt, sizeof(*cur_fmt));
} else {
- pixmp->num_planes = cur_fmt->num_planes;
+ if (vpu_helper_match_format(inst, f->type, cur_fmt->pixfmt, pixmp->pixelformat)) {
+ cur_fmt->pixfmt = fmt.pixfmt;
+ cur_fmt->mem_planes = fmt.mem_planes;
+ }
+ pixmp->pixelformat = cur_fmt->pixfmt;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
pixmp->field = cur_fmt->field;
}
@@ -678,9 +711,11 @@ static struct vpu_vb2_buffer *vdec_find_buffer(struct vpu_inst *inst, u32 luma)
static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
{
struct vdec_t *vdec = inst->priv;
+ struct vpu_format *cur_fmt;
struct vpu_vb2_buffer *vpu_buf;
struct vb2_v4l2_buffer *vbuf;
u32 sequence;
+ int i;
if (!frame)
return;
@@ -699,6 +734,7 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
return;
}
+ cur_fmt = vpu_get_format(inst, inst->cap_format.type);
vbuf = &vpu_buf->m2m_buf.vb;
if (vbuf->vb2_buf.index != frame->id)
dev_err(inst->dev, "[%d] buffer id(%d, %d) dismatch\n",
@@ -707,9 +743,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED)
dev_err(inst->dev, "[%d] buffer(%d) ready without decoded\n", inst->id, frame->id);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY);
- vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]);
- vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]);
- vbuf->field = inst->cap_format.field;
+ for (i = 0; i < vbuf->vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&vbuf->vb2_buf, i, vpu_get_fmt_plane_size(cur_fmt, i));
+ vbuf->field = cur_fmt->field;
vbuf->sequence = sequence;
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
@@ -747,15 +783,20 @@ static void vdec_stop_done(struct vpu_inst *inst)
static bool vdec_check_source_change(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
- const struct vpu_format *fmt;
- int i;
+ const struct vpu_format *sibling;
if (!inst->fh.m2m_ctx)
return false;
+ if (vdec->reset_codec)
+ return false;
+
+ sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt);
+ if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt)
+ vdec->codec_info.pixfmt = inst->cap_format.pixfmt;
+
if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)))
return true;
- fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt);
if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt)
return true;
if (inst->cap_format.width != vdec->codec_info.decoded_width)
@@ -772,14 +813,6 @@ static bool vdec_check_source_change(struct vpu_inst *inst)
return true;
if (inst->crop.height != vdec->codec_info.height)
return true;
- if (fmt && inst->cap_format.num_planes != fmt->num_planes)
- return true;
- for (i = 0; i < inst->cap_format.num_planes; i++) {
- if (inst->cap_format.bytesperline[i] != vdec->codec_info.bytesperline[i])
- return true;
- if (inst->cap_format.sizeimage[i] != vdec->codec_info.sizeimage[i])
- return true;
- }
return false;
}
@@ -787,27 +820,21 @@ static bool vdec_check_source_change(struct vpu_inst *inst)
static void vdec_init_fmt(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
- const struct vpu_format *fmt;
- int i;
+ struct v4l2_format f;
- fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt);
- inst->out_format.width = vdec->codec_info.width;
- inst->out_format.height = vdec->codec_info.height;
- inst->cap_format.width = vdec->codec_info.decoded_width;
- inst->cap_format.height = vdec->codec_info.decoded_height;
- inst->cap_format.pixfmt = vdec->codec_info.pixfmt;
- if (fmt) {
- inst->cap_format.num_planes = fmt->num_planes;
- inst->cap_format.flags = fmt->flags;
- }
- for (i = 0; i < inst->cap_format.num_planes; i++) {
- inst->cap_format.bytesperline[i] = vdec->codec_info.bytesperline[i];
- inst->cap_format.sizeimage[i] = vdec->codec_info.sizeimage[i];
- }
+ memset(&f, 0, sizeof(f));
+ f.type = inst->cap_format.type;
+ f.fmt.pix_mp.pixelformat = vdec->codec_info.pixfmt;
+ f.fmt.pix_mp.width = vdec->codec_info.decoded_width;
+ f.fmt.pix_mp.height = vdec->codec_info.decoded_height;
if (vdec->codec_info.progressive)
- inst->cap_format.field = V4L2_FIELD_NONE;
+ f.fmt.pix_mp.field = V4L2_FIELD_NONE;
else
- inst->cap_format.field = V4L2_FIELD_SEQ_TB;
+ f.fmt.pix_mp.field = V4L2_FIELD_SEQ_TB;
+ vpu_try_fmt_common(inst, &f, &inst->cap_format);
+
+ inst->out_format.width = vdec->codec_info.width;
+ inst->out_format.height = vdec->codec_info.height;
}
static void vdec_init_crop(struct vpu_inst *inst)
@@ -966,7 +993,10 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb
info.tag = vdec->seq_tag;
info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0);
info.luma_size = inst->cap_format.sizeimage[0];
- info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1);
+ if (vbuf->vb2_buf.num_planes > 1)
+ info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1);
+ else
+ info.chroma_addr = info.luma_addr + info.luma_size;
info.chromau_size = inst->cap_format.sizeimage[1];
info.bytesperline = inst->cap_format.bytesperline[0];
ret = vpu_session_alloc_fs(inst, &info);
@@ -975,7 +1005,7 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb
vpu_buf->tag = info.tag;
vpu_buf->luma = info.luma_addr;
- vpu_buf->chroma_u = info.chromau_size;
+ vpu_buf->chroma_u = info.chroma_addr;
vpu_buf->chroma_v = 0;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
vdec->slots[info.id] = vpu_buf;
@@ -1088,7 +1118,8 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
vdec->seq_tag = vdec->codec_info.tag;
if (vdec->is_source_changed) {
vdec_update_state(inst, VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE, 0);
- vpu_notify_source_change(inst);
+ vdec->source_change++;
+ vdec_handle_resolution_change(inst);
vdec->is_source_changed = false;
}
}
@@ -1335,6 +1366,8 @@ static void vdec_abort(struct vpu_inst *inst)
vdec->decoded_frame_count,
vdec->display_frame_count,
vdec->sequence);
+ if (!vdec->seq_hdr_found)
+ vdec->reset_codec = true;
vdec->params.end_flag = 0;
vdec->drain = 0;
vdec->params.frame_count = 0;
@@ -1342,6 +1375,7 @@ static void vdec_abort(struct vpu_inst *inst)
vdec->display_frame_count = 0;
vdec->sequence = 0;
vdec->aborting = false;
+ inst->extra_size = 0;
}
static void vdec_stop(struct vpu_inst *inst, bool free)
@@ -1464,8 +1498,7 @@ static int vdec_start_session(struct vpu_inst *inst, u32 type)
}
if (V4L2_TYPE_IS_OUTPUT(type)) {
- if (inst->state == VPU_CODEC_STATE_SEEK)
- vdec_update_state(inst, vdec->state, 1);
+ vdec_update_state(inst, vdec->state, 1);
vdec->eos_received = 0;
vpu_process_output_buffer(inst);
} else {
@@ -1629,6 +1662,7 @@ static int vdec_open(struct file *file)
return ret;
vdec->fixed_fmt = false;
+ vdec->state = VPU_CODEC_STATE_ACTIVE;
inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP;
inst->min_buffer_out = VDEC_MIN_BUFFER_OUT;
vdec_init(file);
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 37212f087fdd..3cbe8ce637e5 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -69,13 +69,24 @@ struct venc_frame_t {
static const struct vpu_format venc_formats[] = {
{
.pixfmt = V4L2_PIX_FMT_NV12M,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .pixfmt = V4L2_PIX_FMT_NV12,
+ .mem_planes = 1,
+ .comp_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .sibling = V4L2_PIX_FMT_NV12M,
},
{
.pixfmt = V4L2_PIX_FMT_H264,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED
},
{0, 0, 0, 0},
};
@@ -173,14 +184,14 @@ static int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
cur_fmt = vpu_get_format(inst, f->type);
pixmp->pixelformat = cur_fmt->pixfmt;
- pixmp->num_planes = cur_fmt->num_planes;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
pixmp->field = cur_fmt->field;
pixmp->flags = cur_fmt->flags;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
f->fmt.pix_mp.colorspace = venc->params.color.primaries;
@@ -194,8 +205,9 @@ static int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
static int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_inst *inst = to_inst(file);
+ struct vpu_format fmt;
- vpu_try_fmt_common(inst, f);
+ vpu_try_fmt_common(inst, f, &fmt);
return 0;
}
@@ -203,12 +215,11 @@ static int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_inst *inst = to_inst(file);
- const struct vpu_format *fmt;
+ struct vpu_format fmt;
struct vpu_format *cur_fmt;
struct vb2_queue *q;
struct venc_t *venc = inst->priv;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- int i;
q = v4l2_m2m_get_vq(inst->fh.m2m_ctx, f->type);
if (!q)
@@ -216,24 +227,12 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
if (vb2_is_busy(q))
return -EBUSY;
- fmt = vpu_try_fmt_common(inst, f);
- if (!fmt)
+ if (vpu_try_fmt_common(inst, f, &fmt))
return -EINVAL;
cur_fmt = vpu_get_format(inst, f->type);
- cur_fmt->pixfmt = fmt->pixfmt;
- cur_fmt->num_planes = fmt->num_planes;
- cur_fmt->flags = fmt->flags;
- cur_fmt->width = pix_mp->width;
- cur_fmt->height = pix_mp->height;
- for (i = 0; i < fmt->num_planes; i++) {
- cur_fmt->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
- cur_fmt->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
- }
-
- if (pix_mp->field != V4L2_FIELD_ANY)
- cur_fmt->field = pix_mp->field;
+ memcpy(cur_fmt, &fmt, sizeof(*cur_fmt));
if (V4L2_TYPE_IS_OUTPUT(f->type)) {
venc->params.input_format = cur_fmt->pixfmt;
diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h
index beac0309ca8d..3bfe193722af 100644
--- a/drivers/media/platform/amphion/vpu.h
+++ b/drivers/media/platform/amphion/vpu.h
@@ -13,6 +13,7 @@
#include <linux/mailbox_controller.h>
#include <linux/kfifo.h>
+#define VPU_TIMEOUT_WAKEUP msecs_to_jiffies(200)
#define VPU_TIMEOUT msecs_to_jiffies(1000)
#define VPU_INST_NULL_ID (-1L)
#define VPU_MSG_BUFFER_SIZE (8192)
@@ -84,7 +85,8 @@ struct vpu_dev {
struct vpu_format {
u32 pixfmt;
- unsigned int num_planes;
+ u32 mem_planes;
+ u32 comp_planes;
u32 type;
u32 flags;
u32 width;
@@ -92,6 +94,7 @@ struct vpu_format {
u32 sizeimage[VIDEO_MAX_PLANES];
u32 bytesperline[VIDEO_MAX_PLANES];
u32 field;
+ u32 sibling;
};
struct vpu_core_resources {
diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
index f4d7ca78a621..fa581ba6bab2 100644
--- a/drivers/media/platform/amphion/vpu_cmds.c
+++ b/drivers/media/platform/amphion/vpu_cmds.c
@@ -269,7 +269,7 @@ exit:
return flag;
}
-static int sync_session_response(struct vpu_inst *inst, unsigned long key)
+static int sync_session_response(struct vpu_inst *inst, unsigned long key, long timeout, int try)
{
struct vpu_core *core;
@@ -279,10 +279,12 @@ static int sync_session_response(struct vpu_inst *inst, unsigned long key)
core = inst->core;
call_void_vop(inst, wait_prepare);
- wait_event_timeout(core->ack_wq, check_is_responsed(inst, key), VPU_TIMEOUT);
+ wait_event_timeout(core->ack_wq, check_is_responsed(inst, key), timeout);
call_void_vop(inst, wait_finish);
if (!check_is_responsed(inst, key)) {
+ if (try)
+ return -EINVAL;
dev_err(inst->dev, "[%d] sync session timeout\n", inst->id);
set_bit(inst->id, &core->hang_mask);
mutex_lock(&inst->core->cmd_lock);
@@ -294,6 +296,19 @@ static int sync_session_response(struct vpu_inst *inst, unsigned long key)
return 0;
}
+static void vpu_core_keep_active(struct vpu_core *core)
+{
+ struct vpu_rpc_event pkt;
+
+ memset(&pkt, 0, sizeof(pkt));
+ vpu_iface_pack_cmd(core, &pkt, 0, VPU_CMD_ID_NOOP, NULL);
+
+ dev_dbg(core->dev, "try to wake up\n");
+ mutex_lock(&core->cmd_lock);
+ vpu_cmd_send(core, &pkt);
+ mutex_unlock(&core->cmd_lock);
+}
+
static int vpu_session_send_cmd(struct vpu_inst *inst, u32 id, void *data)
{
unsigned long key;
@@ -304,9 +319,25 @@ static int vpu_session_send_cmd(struct vpu_inst *inst, u32 id, void *data)
return -EINVAL;
ret = vpu_request_cmd(inst, id, data, &key, &sync);
- if (!ret && sync)
- ret = sync_session_response(inst, key);
+ if (ret)
+ goto exit;
+
+ /* workaround for a firmware issue,
+ * firmware should be waked up by start or configure command,
+ * but there is a very small change that firmware failed to wakeup.
+ * in such case, try to wakeup firmware again by sending a noop command
+ */
+ if (sync && (id == VPU_CMD_ID_CONFIGURE_CODEC || id == VPU_CMD_ID_START)) {
+ if (sync_session_response(inst, key, VPU_TIMEOUT_WAKEUP, 1))
+ vpu_core_keep_active(inst->core);
+ else
+ goto exit;
+ }
+
+ if (sync)
+ ret = sync_session_response(inst, key, VPU_TIMEOUT, 0);
+exit:
if (ret)
dev_err(inst->dev, "[%d] send cmd(0x%x) fail\n", inst->id, id);
diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
index 260f1c4b8f8d..44b830ae01d8 100644
--- a/drivers/media/platform/amphion/vpu_dbg.c
+++ b/drivers/media/platform/amphion/vpu_dbg.c
@@ -90,9 +90,9 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
vq->last_buffer_dequeued);
if (seq_write(s, str, num))
return 0;
- for (i = 0; i < inst->out_format.num_planes; i++) {
+ for (i = 0; i < inst->out_format.mem_planes; i++) {
num = scnprintf(str, sizeof(str), " %d(%d)",
- inst->out_format.sizeimage[i],
+ vpu_get_fmt_plane_size(&inst->out_format, i),
inst->out_format.bytesperline[i]);
if (seq_write(s, str, num))
return 0;
@@ -114,9 +114,9 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
vq->last_buffer_dequeued);
if (seq_write(s, str, num))
return 0;
- for (i = 0; i < inst->cap_format.num_planes; i++) {
+ for (i = 0; i < inst->cap_format.mem_planes; i++) {
num = scnprintf(str, sizeof(str), " %d(%d)",
- inst->cap_format.sizeimage[i],
+ vpu_get_fmt_plane_size(&inst->cap_format, i),
inst->cap_format.bytesperline[i]);
if (seq_write(s, str, num))
return 0;
diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c
index 9d5a5075343d..f01ce49d27e8 100644
--- a/drivers/media/platform/amphion/vpu_drv.c
+++ b/drivers/media/platform/amphion/vpu_drv.c
@@ -245,7 +245,11 @@ static int __init vpu_driver_init(void)
if (ret)
return ret;
- return vpu_core_driver_init();
+ ret = vpu_core_driver_init();
+ if (ret)
+ platform_driver_unregister(&amphion_vpu_driver);
+
+ return ret;
}
static void __exit vpu_driver_exit(void)
diff --git a/drivers/media/platform/amphion/vpu_helpers.c b/drivers/media/platform/amphion/vpu_helpers.c
index e9aeb3453dfc..019c77e84514 100644
--- a/drivers/media/platform/amphion/vpu_helpers.c
+++ b/drivers/media/platform/amphion/vpu_helpers.c
@@ -59,6 +59,36 @@ const struct vpu_format *vpu_helper_find_format(struct vpu_inst *inst, u32 type,
return NULL;
}
+const struct vpu_format *vpu_helper_find_sibling(struct vpu_inst *inst, u32 type, u32 pixelfmt)
+{
+ const struct vpu_format *fmt;
+ const struct vpu_format *sibling;
+
+ fmt = vpu_helper_find_format(inst, type, pixelfmt);
+ if (!fmt || !fmt->sibling)
+ return NULL;
+
+ sibling = vpu_helper_find_format(inst, type, fmt->sibling);
+ if (!sibling || sibling->sibling != fmt->pixfmt ||
+ sibling->comp_planes != fmt->comp_planes)
+ return NULL;
+
+ return sibling;
+}
+
+bool vpu_helper_match_format(struct vpu_inst *inst, u32 type, u32 fmta, u32 fmtb)
+{
+ const struct vpu_format *sibling;
+
+ if (fmta == fmtb)
+ return true;
+
+ sibling = vpu_helper_find_sibling(inst, type, fmta);
+ if (sibling && sibling->pixfmt == fmtb)
+ return true;
+ return false;
+}
+
const struct vpu_format *vpu_helper_enum_format(struct vpu_inst *inst, u32 type, int index)
{
const struct vpu_format *pfmt;
@@ -123,9 +153,10 @@ static u32 get_nv12_plane_size(u32 width, u32 height, int plane_no,
u32 bytesperline;
u32 size = 0;
- bytesperline = ALIGN(width, stride);
+ bytesperline = width;
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, stride);
height = ALIGN(height, 2);
if (plane_no == 0)
size = bytesperline * height;
@@ -148,13 +179,13 @@ static u32 get_tiled_8l128_plane_size(u32 fmt, u32 width, u32 height, int plane_
if (interlaced)
hs++;
- if (fmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
+ if (fmt == V4L2_PIX_FMT_NV12M_10BE_8L128 || fmt == V4L2_PIX_FMT_NV12_10BE_8L128)
bitdepth = 10;
bytesperline = DIV_ROUND_UP(width * bitdepth, BITS_PER_BYTE);
- bytesperline = ALIGN(bytesperline, 1 << ws);
- bytesperline = ALIGN(bytesperline, stride);
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, 1 << ws);
+ bytesperline = ALIGN(bytesperline, stride);
height = ALIGN(height, 1 << hs);
if (plane_no == 0)
size = bytesperline * height;
@@ -172,9 +203,10 @@ static u32 get_default_plane_size(u32 width, u32 height, int plane_no,
u32 bytesperline;
u32 size = 0;
- bytesperline = ALIGN(width, stride);
+ bytesperline = width;
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, stride);
if (plane_no == 0)
size = bytesperline * height;
if (pbl)
@@ -187,9 +219,12 @@ u32 vpu_helper_get_plane_size(u32 fmt, u32 w, u32 h, int plane_no,
u32 stride, u32 interlaced, u32 *pbl)
{
switch (fmt) {
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
return get_nv12_plane_size(w, h, plane_no, stride, interlaced, pbl);
+ case V4L2_PIX_FMT_NV12_8L128:
case V4L2_PIX_FMT_NV12M_8L128:
+ case V4L2_PIX_FMT_NV12_10BE_8L128:
case V4L2_PIX_FMT_NV12M_10BE_8L128:
return get_tiled_8l128_plane_size(fmt, w, h, plane_no, stride, interlaced, pbl);
default:
diff --git a/drivers/media/platform/amphion/vpu_helpers.h b/drivers/media/platform/amphion/vpu_helpers.h
index bc28350958be..0eaddb07190d 100644
--- a/drivers/media/platform/amphion/vpu_helpers.h
+++ b/drivers/media/platform/amphion/vpu_helpers.h
@@ -14,6 +14,8 @@ struct vpu_pair {
int vpu_helper_find_in_array_u8(const u8 *array, u32 size, u32 x);
bool vpu_helper_check_type(struct vpu_inst *inst, u32 type);
const struct vpu_format *vpu_helper_find_format(struct vpu_inst *inst, u32 type, u32 pixelfmt);
+const struct vpu_format *vpu_helper_find_sibling(struct vpu_inst *inst, u32 type, u32 pixelfmt);
+bool vpu_helper_match_format(struct vpu_inst *inst, u32 type, u32 fmta, u32 fmtb);
const struct vpu_format *vpu_helper_enum_format(struct vpu_inst *inst, u32 type, int index);
u32 vpu_helper_valid_frame_width(struct vpu_inst *inst, u32 width);
u32 vpu_helper_valid_frame_height(struct vpu_inst *inst, u32 height);
diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c
index 51e0702f9ae1..2c9bfc6a5a72 100644
--- a/drivers/media/platform/amphion/vpu_malone.c
+++ b/drivers/media/platform/amphion/vpu_malone.c
@@ -583,7 +583,8 @@ bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt)
if (!vpu_imx8q_check_fmt(type, pixelfmt))
return false;
- if (pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
+ if (pixelfmt == V4L2_PIX_FMT_NV12_8L128 || pixelfmt == V4L2_PIX_FMT_NV12_10BE_8L128 ||
+ pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
return true;
if (vpu_malone_format_remap(pixelfmt) == MALONE_FMT_NULL)
return false;
@@ -692,6 +693,7 @@ int vpu_malone_set_decode_params(struct vpu_shared_addr *shared,
}
static struct vpu_pair malone_cmds[] = {
+ {VPU_CMD_ID_NOOP, VID_API_CMD_NULL},
{VPU_CMD_ID_START, VID_API_CMD_START},
{VPU_CMD_ID_STOP, VID_API_CMD_STOP},
{VPU_CMD_ID_ABORT, VID_API_CMD_ABORT},
diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c
index d8247f36d84b..92672a802b49 100644
--- a/drivers/media/platform/amphion/vpu_msgs.c
+++ b/drivers/media/platform/amphion/vpu_msgs.c
@@ -43,6 +43,7 @@ static void vpu_session_handle_mem_request(struct vpu_inst *inst, struct vpu_rpc
req_data.ref_frame_num,
req_data.act_buf_size,
req_data.act_buf_num);
+ vpu_inst_lock(inst);
call_void_vop(inst, mem_request,
req_data.enc_frame_size,
req_data.enc_frame_num,
@@ -50,6 +51,7 @@ static void vpu_session_handle_mem_request(struct vpu_inst *inst, struct vpu_rpc
req_data.ref_frame_num,
req_data.act_buf_size,
req_data.act_buf_num);
+ vpu_inst_unlock(inst);
}
static void vpu_session_handle_stop_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index b779e0ba916c..6773b885597c 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -65,18 +65,11 @@ unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf)
void vpu_v4l2_set_error(struct vpu_inst *inst)
{
- struct vb2_queue *src_q;
- struct vb2_queue *dst_q;
-
vpu_inst_lock(inst);
dev_err(inst->dev, "some error occurs in codec\n");
if (inst->fh.m2m_ctx) {
- src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
- dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
- src_q->error = 1;
- dst_q->error = 1;
- wake_up(&src_q->done_wq);
- wake_up(&dst_q->done_wq);
+ vb2_queue_error(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx));
+ vb2_queue_error(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
}
vpu_inst_unlock(inst);
}
@@ -140,51 +133,136 @@ bool vpu_is_source_empty(struct vpu_inst *inst)
return true;
}
-const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
+static int vpu_init_format(struct vpu_inst *inst, struct vpu_format *fmt)
+{
+ const struct vpu_format *info;
+
+ info = vpu_helper_find_format(inst, fmt->type, fmt->pixfmt);
+ if (!info) {
+ info = vpu_helper_enum_format(inst, fmt->type, 0);
+ if (!info)
+ return -EINVAL;
+ }
+ memcpy(fmt, info, sizeof(*fmt));
+
+ return 0;
+}
+
+static int vpu_calc_fmt_bytesperline(struct v4l2_format *f, struct vpu_format *fmt)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
- u32 type = f->type;
+ int i;
+
+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = 0;
+ return 0;
+ }
+ if (pixmp->num_planes == fmt->comp_planes) {
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline;
+ return 0;
+ }
+ if (pixmp->num_planes > 1)
+ return -EINVAL;
+
+ /*amphion vpu only support nv12 and nv12 tiled,
+ * so the bytesperline of luma and chroma should be same
+ */
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = pixmp->plane_fmt[0].bytesperline;
+
+ return 0;
+}
+
+static int vpu_calc_fmt_sizeimage(struct vpu_inst *inst, struct vpu_format *fmt)
+{
u32 stride = 1;
- u32 bytesperline;
- u32 sizeimage;
- const struct vpu_format *fmt;
- const struct vpu_core_resources *res;
int i;
- fmt = vpu_helper_find_format(inst, type, pixmp->pixelformat);
- if (!fmt) {
- fmt = vpu_helper_enum_format(inst, type, 0);
- if (!fmt)
- return NULL;
- pixmp->pixelformat = fmt->pixfmt;
+ if (!(fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
+ const struct vpu_core_resources *res = vpu_get_resource(inst);
+
+ if (res)
+ stride = res->stride;
}
- res = vpu_get_resource(inst);
- if (res)
- stride = res->stride;
- if (pixmp->width)
- pixmp->width = vpu_helper_valid_frame_width(inst, pixmp->width);
- if (pixmp->height)
- pixmp->height = vpu_helper_valid_frame_height(inst, pixmp->height);
+ for (i = 0; i < fmt->comp_planes; i++) {
+ fmt->sizeimage[i] = vpu_helper_get_plane_size(fmt->pixfmt,
+ fmt->width,
+ fmt->height,
+ i,
+ stride,
+ fmt->field != V4L2_FIELD_NONE ? 1 : 0,
+ &fmt->bytesperline[i]);
+ fmt->sizeimage[i] = max_t(u32, fmt->sizeimage[i], PAGE_SIZE);
+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ fmt->sizeimage[i] = clamp_val(fmt->sizeimage[i], SZ_128K, SZ_8M);
+ fmt->bytesperline[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+u32 vpu_get_fmt_plane_size(struct vpu_format *fmt, u32 plane_no)
+{
+ u32 size;
+ int i;
+
+ if (plane_no >= fmt->mem_planes)
+ return 0;
+
+ if (fmt->comp_planes == fmt->mem_planes)
+ return fmt->sizeimage[plane_no];
+ if (plane_no < fmt->mem_planes - 1)
+ return fmt->sizeimage[plane_no];
+
+ size = fmt->sizeimage[plane_no];
+ for (i = fmt->mem_planes; i < fmt->comp_planes; i++)
+ size += fmt->sizeimage[i];
+
+ return size;
+}
+
+int vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f, struct vpu_format *fmt)
+{
+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+ int i;
+ int ret;
+
+ fmt->pixfmt = pixmp->pixelformat;
+ fmt->type = f->type;
+ ret = vpu_init_format(inst, fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt->width = pixmp->width;
+ fmt->height = pixmp->height;
+ if (fmt->width)
+ fmt->width = vpu_helper_valid_frame_width(inst, fmt->width);
+ if (fmt->height)
+ fmt->height = vpu_helper_valid_frame_height(inst, fmt->height);
+ fmt->field = pixmp->field == V4L2_FIELD_ANY ? V4L2_FIELD_NONE : pixmp->field;
+ vpu_calc_fmt_bytesperline(f, fmt);
+ vpu_calc_fmt_sizeimage(inst, fmt);
+ if ((fmt->flags & V4L2_FMT_FLAG_COMPRESSED) && pixmp->plane_fmt[0].sizeimage)
+ fmt->sizeimage[0] = clamp_val(pixmp->plane_fmt[0].sizeimage, SZ_128K, SZ_8M);
+
+ pixmp->pixelformat = fmt->pixfmt;
+ pixmp->width = fmt->width;
+ pixmp->height = fmt->height;
pixmp->flags = fmt->flags;
- pixmp->num_planes = fmt->num_planes;
- if (pixmp->field == V4L2_FIELD_ANY)
- pixmp->field = V4L2_FIELD_NONE;
+ pixmp->num_planes = fmt->mem_planes;
+ pixmp->field = fmt->field;
+ memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
for (i = 0; i < pixmp->num_planes; i++) {
- bytesperline = max_t(s32, pixmp->plane_fmt[i].bytesperline, 0);
- sizeimage = vpu_helper_get_plane_size(pixmp->pixelformat,
- pixmp->width,
- pixmp->height,
- i,
- stride,
- pixmp->field > V4L2_FIELD_NONE ? 1 : 0,
- &bytesperline);
- sizeimage = max_t(s32, pixmp->plane_fmt[i].sizeimage, sizeimage);
- pixmp->plane_fmt[i].bytesperline = bytesperline;
- pixmp->plane_fmt[i].sizeimage = sizeimage;
+ pixmp->plane_fmt[i].bytesperline = fmt->bytesperline[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(fmt, i);
+ memset(pixmp->plane_fmt[i].reserved, 0, sizeof(pixmp->plane_fmt[i].reserved));
}
- return fmt;
+ return 0;
}
static bool vpu_check_ready(struct vpu_inst *inst, u32 type)
@@ -249,8 +327,12 @@ int vpu_process_capture_buffer(struct vpu_inst *inst)
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst)
{
- struct vb2_v4l2_buffer *src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
+ struct vb2_v4l2_buffer *src_buf = NULL;
+
+ if (!inst->fh.m2m_ctx)
+ return NULL;
+ src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return NULL;
@@ -273,7 +355,7 @@ void vpu_skip_frame(struct vpu_inst *inst, int count)
enum vb2_buffer_state state;
int i = 0;
- if (count <= 0)
+ if (count <= 0 || !inst->fh.m2m_ctx)
return;
while (i < count) {
@@ -389,10 +471,10 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq,
cur_fmt = vpu_get_format(inst, vq->type);
if (*plane_count) {
- if (*plane_count != cur_fmt->num_planes)
+ if (*plane_count != cur_fmt->mem_planes)
return -EINVAL;
- for (i = 0; i < cur_fmt->num_planes; i++) {
- if (psize[i] < cur_fmt->sizeimage[i])
+ for (i = 0; i < cur_fmt->mem_planes; i++) {
+ if (psize[i] < vpu_get_fmt_plane_size(cur_fmt, i))
return -EINVAL;
}
return 0;
@@ -402,9 +484,9 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq,
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out);
else
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap);
- *plane_count = cur_fmt->num_planes;
- for (i = 0; i < cur_fmt->num_planes; i++)
- psize[i] = cur_fmt->sizeimage[i];
+ *plane_count = cur_fmt->mem_planes;
+ for (i = 0; i < cur_fmt->mem_planes; i++)
+ psize[i] = vpu_get_fmt_plane_size(cur_fmt, i);
return 0;
}
@@ -434,8 +516,8 @@ static int vpu_vb2_buf_prepare(struct vb2_buffer *vb)
u32 i;
cur_fmt = vpu_get_format(inst, vb->type);
- for (i = 0; i < cur_fmt->num_planes; i++) {
- if (vpu_get_vb_length(vb, i) < cur_fmt->sizeimage[i]) {
+ for (i = 0; i < cur_fmt->mem_planes; i++) {
+ if (vpu_get_vb_length(vb, i) < vpu_get_fmt_plane_size(cur_fmt, i)) {
dev_dbg(inst->dev, "[%d] %s buf[%d] is invalid\n",
inst->id, vpu_type_name(vb->type), vb->index);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR);
@@ -603,10 +685,6 @@ static int vpu_v4l2_release(struct vpu_inst *inst)
inst->workqueue = NULL;
}
- if (inst->fh.m2m_ctx) {
- v4l2_m2m_ctx_release(inst->fh.m2m_ctx);
- inst->fh.m2m_ctx = NULL;
- }
v4l2_ctrl_handler_free(&inst->ctrl_handler);
mutex_destroy(&inst->lock);
v4l2_fh_del(&inst->fh);
@@ -689,6 +767,13 @@ int vpu_v4l2_close(struct file *file)
vpu_trace(vpu->dev, "tgid = %d, pid = %d, inst = %p\n", inst->tgid, inst->pid, inst);
+ vpu_inst_lock(inst);
+ if (inst->fh.m2m_ctx) {
+ v4l2_m2m_ctx_release(inst->fh.m2m_ctx);
+ inst->fh.m2m_ctx = NULL;
+ }
+ vpu_inst_unlock(inst);
+
call_void_vop(inst, release);
vpu_inst_unregister(inst);
vpu_inst_put(inst);
diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h
index 795ca33a6a50..ef5de6b66e47 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.h
+++ b/drivers/media/platform/amphion/vpu_v4l2.h
@@ -16,7 +16,8 @@ unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf);
int vpu_v4l2_open(struct file *file, struct vpu_inst *inst);
int vpu_v4l2_close(struct file *file);
-const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f);
+u32 vpu_get_fmt_plane_size(struct vpu_format *fmt, u32 plane_no);
+int vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f, struct vpu_format *fmt);
int vpu_process_output_buffer(struct vpu_inst *inst);
int vpu_process_capture_buffer(struct vpu_inst *inst);
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst);
diff --git a/drivers/media/platform/amphion/vpu_windsor.c b/drivers/media/platform/amphion/vpu_windsor.c
index 1526af2ef9da..b245ff6a1102 100644
--- a/drivers/media/platform/amphion/vpu_windsor.c
+++ b/drivers/media/platform/amphion/vpu_windsor.c
@@ -658,6 +658,7 @@ int vpu_windsor_get_stream_buffer_size(struct vpu_shared_addr *shared)
}
static struct vpu_pair windsor_cmds[] = {
+ {VPU_CMD_ID_NOOP, GTB_ENC_CMD_NOOP},
{VPU_CMD_ID_CONFIGURE_CODEC, GTB_ENC_CMD_CONFIGURE_CODEC},
{VPU_CMD_ID_START, GTB_ENC_CMD_STREAM_START},
{VPU_CMD_ID_STOP, GTB_ENC_CMD_STREAM_STOP},
@@ -775,6 +776,8 @@ static int vpu_windsor_fill_yuv_frame(struct vpu_shared_addr *shared,
u32 instance,
struct vb2_buffer *vb)
{
+ struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpu_format *out_fmt;
struct vpu_enc_yuv_desc *desc;
struct vb2_v4l2_buffer *vbuf;
@@ -782,6 +785,7 @@ static int vpu_windsor_fill_yuv_frame(struct vpu_shared_addr *shared,
return -EINVAL;
desc = get_yuv_desc(shared, instance);
+ out_fmt = vpu_get_format(inst, vb->type);
vbuf = to_vb2_v4l2_buffer(vb);
desc->frame_id = vbuf->sequence;
@@ -790,7 +794,10 @@ static int vpu_windsor_fill_yuv_frame(struct vpu_shared_addr *shared,
else
desc->key_frame = 0;
desc->luma_base = vpu_get_vb_phy_addr(vb, 0);
- desc->chroma_base = vpu_get_vb_phy_addr(vb, 1);
+ if (vb->num_planes > 1)
+ desc->chroma_base = vpu_get_vb_phy_addr(vb, 1);
+ else
+ desc->chroma_base = desc->luma_base + out_fmt->sizeimage[0];
return 0;
}
diff --git a/drivers/media/platform/aspeed/Kconfig b/drivers/media/platform/aspeed/Kconfig
index c871eda33570..16c5d8913488 100644
--- a/drivers/media/platform/aspeed/Kconfig
+++ b/drivers/media/platform/aspeed/Kconfig
@@ -4,6 +4,7 @@ comment "Aspeed media platform drivers"
config VIDEO_ASPEED
tristate "Aspeed AST2400 and AST2500 Video Engine driver"
+ depends on ARCH_ASPEED || COMPILE_TEST
depends on V4L_PLATFORM_DRIVERS
depends on VIDEO_DEV
select VIDEOBUF2_DMA_CONTIG
diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index 20f795ccc11b..794d4dc3a654 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -33,6 +33,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h>
+#include <uapi/linux/aspeed-video.h>
#define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3
@@ -59,6 +60,7 @@
#define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */
#define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */
+#define VE_BCD_BUFF_SIZE 0x9000 /* (1920/8) * (1200/8) */
#define VE_PROTECTION_KEY 0x000
#define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8
@@ -107,6 +109,13 @@
#define VE_SCALING_FILTER2 0x020
#define VE_SCALING_FILTER3 0x024
+#define VE_BCD_CTRL 0x02C
+#define VE_BCD_CTRL_EN_BCD BIT(0)
+#define VE_BCD_CTRL_EN_ABCD BIT(1)
+#define VE_BCD_CTRL_EN_CB BIT(2)
+#define VE_BCD_CTRL_THR GENMASK(23, 16)
+#define VE_BCD_CTRL_ABCD_THR GENMASK(31, 24)
+
#define VE_CAP_WINDOW 0x030
#define VE_COMP_WINDOW 0x034
#define VE_COMP_PROC_OFFSET 0x038
@@ -115,6 +124,7 @@
#define VE_SRC0_ADDR 0x044
#define VE_SRC_SCANLINE_OFFSET 0x048
#define VE_SRC1_ADDR 0x04c
+#define VE_BCD_ADDR 0x050
#define VE_COMP_ADDR 0x054
#define VE_STREAM_BUF_SIZE 0x058
@@ -135,6 +145,8 @@
#define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22)
#define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27)
+#define VE_CB_ADDR 0x06C
+
#define AST2400_VE_COMP_SIZE_READ_BACK 0x078
#define AST2600_VE_COMP_SIZE_READ_BACK 0x084
@@ -211,6 +223,12 @@ enum {
VIDEO_CLOCKS_ON,
};
+enum aspeed_video_format {
+ VIDEO_FMT_STANDARD = 0,
+ VIDEO_FMT_ASPEED,
+ VIDEO_FMT_MAX = VIDEO_FMT_ASPEED
+};
+
// for VE_CTRL_CAPTURE_FMT
enum aspeed_video_capture_format {
VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0,
@@ -245,16 +263,20 @@ struct aspeed_video_perf {
/*
* struct aspeed_video - driver data
*
- * res_work: holds the delayed_work for res-detection if unlock
- * buffers: holds the list of buffer queued from user
+ * res_work: holds the delayed_work for res-detection if unlock
+ * buffers: holds the list of buffer queued from user
* flags: holds the state of video
* sequence: holds the last number of frame completed
* max_compressed_size: holds max compressed stream's size
* srcs: holds the buffer information for srcs
* jpeg: holds the buffer information for jpeg header
+ * bcd: holds the buffer information for bcd work
* yuv420: a flag raised if JPEG subsampling is 420
+ * format: holds the video format
+ * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED
* frame_rate: holds the frame_rate
* jpeg_quality: holds jpeq's quality (0~11)
+ * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled
* frame_bottom: end position of video data in vertical direction
* frame_left: start position of video data in horizontal direction
* frame_right: end position of video data in horizontal direction
@@ -290,10 +312,14 @@ struct aspeed_video {
unsigned int max_compressed_size;
struct aspeed_video_addr srcs[2];
struct aspeed_video_addr jpeg;
+ struct aspeed_video_addr bcd;
bool yuv420;
+ enum aspeed_video_format format;
+ bool hq_mode;
unsigned int frame_rate;
unsigned int jpeg_quality;
+ unsigned int jpeg_hq_quality;
unsigned int frame_bottom;
unsigned int frame_left;
@@ -458,8 +484,18 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = {
},
};
+static const char * const format_str[] = {"Standard JPEG",
+ "Aspeed JPEG"};
+
static unsigned int debug;
+static bool aspeed_video_alloc_buf(struct aspeed_video *video,
+ struct aspeed_video_addr *addr,
+ unsigned int size);
+
+static void aspeed_video_free_buf(struct aspeed_video *video,
+ struct aspeed_video_addr *addr);
+
static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
{
int i;
@@ -547,24 +583,39 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
unsigned long flags;
struct aspeed_video_buffer *buf;
u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
+ bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD);
if (video->v4l2_input_status) {
- v4l2_warn(&video->v4l2_dev, "No signal; don't start frame\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "No signal; don't start frame\n");
return 0;
}
if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) ||
!(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) {
- v4l2_warn(&video->v4l2_dev, "Engine busy; don't start frame\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "Engine busy; don't start frame\n");
return -EBUSY;
}
+ if (bcd_buf_need && !video->bcd.size) {
+ if (!aspeed_video_alloc_buf(video, &video->bcd,
+ VE_BCD_BUFF_SIZE)) {
+ dev_err(video->dev, "Failed to allocate BCD buffer\n");
+ dev_err(video->dev, "don't start frame\n");
+ return -ENOMEM;
+ }
+ aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n",
+ &video->bcd.dma, video->bcd.size);
+ } else if (!bcd_buf_need && video->bcd.size) {
+ aspeed_video_free_buf(video, &video->bcd);
+ }
+
spin_lock_irqsave(&video->lock, flags);
buf = list_first_entry_or_null(&video->buffers,
struct aspeed_video_buffer, link);
if (!buf) {
spin_unlock_irqrestore(&video->lock, flags);
- v4l2_warn(&video->v4l2_dev, "No buffers; don't start frame\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "No buffers; don't start frame\n");
return -EPROTO;
}
@@ -657,6 +708,24 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
schedule_delayed_work(&video->res_work, delay);
}
+static void aspeed_video_swap_src_buf(struct aspeed_video *v)
+{
+ if (v->format == VIDEO_FMT_STANDARD)
+ return;
+
+ /* Reset bcd buffer to have a full frame update every 8 frames. */
+ if (IS_ALIGNED(v->sequence, 8))
+ memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE);
+
+ if (v->sequence & 0x01) {
+ aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[1].dma);
+ aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[0].dma);
+ } else {
+ aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[0].dma);
+ aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[1].dma);
+ }
+}
+
static irqreturn_t aspeed_video_irq(int irq, void *arg)
{
struct aspeed_video *video = arg;
@@ -705,6 +774,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
if (sts & VE_INTERRUPT_COMP_COMPLETE) {
struct aspeed_video_buffer *buf;
+ bool empty = true;
u32 frame_size = aspeed_video_read(video,
video->comp_size_read);
@@ -718,13 +788,23 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
if (buf) {
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size);
- if (!list_is_last(&buf->link, &video->buffers)) {
+ /*
+ * aspeed_jpeg requires continuous update.
+ * On the contrary, standard jpeg can keep last buffer
+ * to always have the latest result.
+ */
+ if (video->format == VIDEO_FMT_STANDARD &&
+ list_is_last(&buf->link, &video->buffers)) {
+ empty = false;
+ v4l2_dbg(1, debug, &video->v4l2_dev, "skip to keep last frame updated\n");
+ } else {
buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = video->sequence++;
buf->vb.field = V4L2_FIELD_NONE;
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_DONE);
list_del(&buf->link);
+ empty = list_empty(&video->buffers);
}
}
spin_unlock(&video->lock);
@@ -738,7 +818,10 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
aspeed_video_write(video, VE_INTERRUPT_STATUS,
VE_INTERRUPT_COMP_COMPLETE);
sts &= ~VE_INTERRUPT_COMP_COMPLETE;
- if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
+
+ aspeed_video_swap_src_buf(video);
+
+ if (test_bit(VIDEO_STREAMING, &video->flags) && !empty)
aspeed_video_start_frame(video);
}
@@ -977,7 +1060,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
res_check(video),
MODE_DETECT_TIMEOUT);
if (!rc) {
- v4l2_warn(&video->v4l2_dev, "Timed out; first mode detect\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "Timed out; first mode detect\n");
clear_bit(VIDEO_RES_DETECT, &video->flags);
return;
}
@@ -998,7 +1081,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
MODE_DETECT_TIMEOUT);
clear_bit(VIDEO_RES_DETECT, &video->flags);
if (!rc) {
- v4l2_warn(&video->v4l2_dev, "Timed out; second mode detect\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "Timed out; second mode detect\n");
return;
}
@@ -1021,7 +1104,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
} while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES));
if (invalid_resolution) {
- v4l2_warn(&video->v4l2_dev, "Invalid resolution detected\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "Invalid resolution detected\n");
return;
}
@@ -1085,10 +1168,14 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
FIELD_PREP(VE_TGS_FIRST, video->frame_top) |
FIELD_PREP(VE_TGS_LAST,
video->frame_bottom + 1));
- aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE);
+ aspeed_video_update(video, VE_CTRL,
+ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
+ VE_CTRL_INT_DE);
} else {
v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n");
- aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
+ aspeed_video_update(video, VE_CTRL,
+ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
+ VE_CTRL_DIRECT_FETCH);
}
size *= 4;
@@ -1121,21 +1208,65 @@ err_mem:
aspeed_video_free_buf(video, &video->srcs[0]);
}
-static void aspeed_video_init_regs(struct aspeed_video *video)
+static void aspeed_video_update_regs(struct aspeed_video *video)
{
- u32 comp_ctrl = VE_COMP_CTRL_RSVD |
- FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
- FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
- u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
- FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
- u32 seq_ctrl = video->jpeg_mode;
+ u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0,
+ ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1);
+ u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
+ FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10) |
+ FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode) |
+ FIELD_PREP(VE_COMP_CTRL_HQ_DCT_LUM, jpeg_hq_quality) |
+ FIELD_PREP(VE_COMP_CTRL_HQ_DCT_CHR, jpeg_hq_quality | 0x10);
+ u32 ctrl = 0;
+ u32 seq_ctrl = 0;
+
+ v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n",
+ video->frame_rate);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n",
+ format_str[video->format],
+ video->yuv420 ? "420" : "444");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "compression quality(%d)\n",
+ video->jpeg_quality);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "hq_mode(%s) hq_quality(%d)\n",
+ video->hq_mode ? "on" : "off", video->jpeg_hq_quality);
+
+ if (video->format == VIDEO_FMT_ASPEED)
+ aspeed_video_update(video, VE_BCD_CTRL, 0, VE_BCD_CTRL_EN_BCD);
+ else
+ aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0);
if (video->frame_rate)
ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
+ if (video->format == VIDEO_FMT_STANDARD) {
+ comp_ctrl &= ~FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode);
+ seq_ctrl |= video->jpeg_mode;
+ }
+
if (video->yuv420)
seq_ctrl |= VE_SEQ_CTRL_YUV420;
+ if (video->jpeg.virt)
+ aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
+
+ /* Set control registers */
+ aspeed_video_update(video, VE_SEQ_CTRL,
+ video->jpeg_mode | VE_SEQ_CTRL_YUV420,
+ seq_ctrl);
+ aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl);
+ aspeed_video_update(video, VE_COMP_CTRL,
+ VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR |
+ VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM |
+ VE_COMP_CTRL_HQ_DCT_CHR | VE_COMP_CTRL_VQ_4COLOR |
+ VE_COMP_CTRL_VQ_DCT_ONLY,
+ comp_ctrl);
+}
+
+static void aspeed_video_init_regs(struct aspeed_video *video)
+{
+ u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
+ FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
+
/* Unlock VE registers */
aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK);
@@ -1150,9 +1281,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
/* Set control registers */
- aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
aspeed_video_write(video, VE_CTRL, ctrl);
- aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl);
+ aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD);
/* Don't downscale */
aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000);
@@ -1168,6 +1298,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65));
+
+ aspeed_video_write(video, VE_BCD_CTRL, 0);
}
static void aspeed_video_start(struct aspeed_video *video)
@@ -1201,6 +1333,9 @@ static void aspeed_video_stop(struct aspeed_video *video)
if (video->srcs[1].size)
aspeed_video_free_buf(video, &video->srcs[1]);
+ if (video->bcd.size)
+ aspeed_video_free_buf(video, &video->bcd);
+
video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
video->flags = 0;
}
@@ -1219,10 +1354,12 @@ static int aspeed_video_querycap(struct file *file, void *fh,
static int aspeed_video_enum_format(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
+ struct aspeed_video *video = video_drvdata(file);
+
if (f->index)
return -EINVAL;
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ f->pixelformat = video->pix_fmt.pixelformat;
return 0;
}
@@ -1237,6 +1374,29 @@ static int aspeed_video_get_format(struct file *file, void *fh,
return 0;
}
+static int aspeed_video_set_format(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct aspeed_video *video = video_drvdata(file);
+
+ if (vb2_is_busy(&video->queue))
+ return -EBUSY;
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_JPEG:
+ video->format = VIDEO_FMT_STANDARD;
+ break;
+ case V4L2_PIX_FMT_AJPG:
+ video->format = VIDEO_FMT_ASPEED;
+ break;
+ default:
+ return -EINVAL;
+ }
+ video->pix_fmt.pixelformat = f->fmt.pix.pixelformat;
+
+ return 0;
+}
+
static int aspeed_video_enum_input(struct file *file, void *fh,
struct v4l2_input *inp)
{
@@ -1454,7 +1614,7 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
.vidioc_enum_fmt_vid_cap = aspeed_video_enum_format,
.vidioc_g_fmt_vid_cap = aspeed_video_get_format,
- .vidioc_s_fmt_vid_cap = aspeed_video_get_format,
+ .vidioc_s_fmt_vid_cap = aspeed_video_set_format,
.vidioc_try_fmt_vid_cap = aspeed_video_get_format,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
@@ -1486,27 +1646,6 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-static void aspeed_video_update_jpeg_quality(struct aspeed_video *video)
-{
- u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
- FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
-
- aspeed_video_update(video, VE_COMP_CTRL,
- VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR,
- comp_ctrl);
-}
-
-static void aspeed_video_update_subsampling(struct aspeed_video *video)
-{
- if (video->jpeg.virt)
- aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
-
- if (video->yuv420)
- aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420);
- else
- aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0);
-}
-
static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct aspeed_video *video = container_of(ctrl->handler,
@@ -1516,16 +1655,23 @@ static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
video->jpeg_quality = ctrl->val;
- aspeed_video_update_jpeg_quality(video);
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
break;
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
- if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
- video->yuv420 = true;
- aspeed_video_update_subsampling(video);
- } else {
- video->yuv420 = false;
- aspeed_video_update_subsampling(video);
- }
+ video->yuv420 = (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420);
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
+ break;
+ case V4L2_CID_ASPEED_HQ_MODE:
+ video->hq_mode = ctrl->val;
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
+ break;
+ case V4L2_CID_ASPEED_HQ_JPEG_QUALITY:
+ video->jpeg_hq_quality = ctrl->val;
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
break;
default:
return -EINVAL;
@@ -1538,6 +1684,28 @@ static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
.s_ctrl = aspeed_video_set_ctrl,
};
+static const struct v4l2_ctrl_config aspeed_ctrl_HQ_mode = {
+ .ops = &aspeed_video_ctrl_ops,
+ .id = V4L2_CID_ASPEED_HQ_MODE,
+ .name = "Aspeed HQ Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = false,
+};
+
+static const struct v4l2_ctrl_config aspeed_ctrl_HQ_jpeg_quality = {
+ .ops = &aspeed_video_ctrl_ops,
+ .id = V4L2_CID_ASPEED_HQ_JPEG_QUALITY,
+ .name = "Aspeed HQ Quality",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = ASPEED_VIDEO_JPEG_NUM_QUALITIES,
+ .step = 1,
+ .def = 1,
+};
+
static void aspeed_video_resolution_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -1552,6 +1720,8 @@ static void aspeed_video_resolution_work(struct work_struct *work)
aspeed_video_init_regs(video);
+ aspeed_video_update_regs(video);
+
aspeed_video_get_resolution(video);
if (video->detected_timings.width != video->active_timings.width ||
@@ -1662,6 +1832,8 @@ static int aspeed_video_start_streaming(struct vb2_queue *q,
video->perf.duration_max = 0;
video->perf.duration_min = 0xffffffff;
+ aspeed_video_update_regs(video);
+
rc = aspeed_video_start_frame(video);
if (rc) {
aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED);
@@ -1683,7 +1855,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q)
!test_bit(VIDEO_FRAME_INPRG, &video->flags),
STOP_TIMEOUT);
if (!rc) {
- v4l2_warn(&video->v4l2_dev, "Timed out when stopping streaming\n");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "Timed out when stopping streaming\n");
/*
* Need to force stop any DMA and try and get HW into a good
@@ -1732,9 +1904,29 @@ static const struct vb2_ops aspeed_video_vb2_ops = {
static int aspeed_video_debugfs_show(struct seq_file *s, void *data)
{
struct aspeed_video *v = s->private;
+ u32 val08;
seq_puts(s, "\n");
+ seq_puts(s, "Capture:\n");
+ val08 = aspeed_video_read(v, VE_CTRL);
+ if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) {
+ seq_printf(s, " %-20s:\tDirect fetch\n", "Mode");
+ seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode",
+ FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32");
+ } else {
+ seq_printf(s, " %-20s:\tSync\n", "Mode");
+ seq_printf(s, " %-20s:\t%s\n", "Video source",
+ FIELD_GET(VE_CTRL_SOURCE, val08) ?
+ "external" : "internal");
+ seq_printf(s, " %-20s:\t%s\n", "DE source",
+ FIELD_GET(VE_CTRL_INT_DE, val08) ?
+ "internal" : "external");
+ seq_printf(s, " %-20s:\t%s\n", "Cursor overlay",
+ FIELD_GET(VE_CTRL_AUTO_OR_CURSOR, val08) ?
+ "Without" : "With");
+ }
+
seq_printf(s, " %-20s:\t%s\n", "Signal",
v->v4l2_input_status ? "Unlock" : "Lock");
seq_printf(s, " %-20s:\t%d\n", "Width", v->pix_fmt.width);
@@ -1743,29 +1935,33 @@ static int aspeed_video_debugfs_show(struct seq_file *s, void *data)
seq_puts(s, "\n");
+ seq_puts(s, "Compression:\n");
+ seq_printf(s, " %-20s:\t%s\n", "Format", format_str[v->format]);
+ seq_printf(s, " %-20s:\t%s\n", "Subsampling",
+ v->yuv420 ? "420" : "444");
+ seq_printf(s, " %-20s:\t%d\n", "Quality", v->jpeg_quality);
+ if (v->format == VIDEO_FMT_ASPEED) {
+ seq_printf(s, " %-20s:\t%s\n", "HQ Mode",
+ v->hq_mode ? "on" : "off");
+ seq_printf(s, " %-20s:\t%d\n", "HQ Quality",
+ v->hq_mode ? v->jpeg_hq_quality : 0);
+ }
+
+ seq_puts(s, "\n");
+
seq_puts(s, "Performance:\n");
seq_printf(s, " %-20s:\t%d\n", "Frame#", v->sequence);
seq_printf(s, " %-20s:\n", "Frame Duration(ms)");
seq_printf(s, " %-18s:\t%d\n", "Now", v->perf.duration);
seq_printf(s, " %-18s:\t%d\n", "Min", v->perf.duration_min);
seq_printf(s, " %-18s:\t%d\n", "Max", v->perf.duration_max);
- seq_printf(s, " %-20s:\t%d\n", "FPS", 1000 / (v->perf.totaltime / v->sequence));
+ seq_printf(s, " %-20s:\t%d\n", "FPS",
+ (v->perf.totaltime && v->sequence) ?
+ 1000 / (v->perf.totaltime / v->sequence) : 0);
return 0;
}
-
-static int aspeed_video_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, aspeed_video_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations aspeed_video_debugfs_ops = {
- .owner = THIS_MODULE,
- .open = aspeed_video_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(aspeed_video_debugfs);
static struct dentry *debugfs_entry;
@@ -1779,7 +1975,7 @@ static int aspeed_video_debugfs_create(struct aspeed_video *video)
{
debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL,
video,
- &aspeed_video_debugfs_ops);
+ &aspeed_video_debugfs_fops);
if (!debugfs_entry)
aspeed_video_debugfs_remove(video);
@@ -1800,6 +1996,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
struct v4l2_device *v4l2_dev = &video->v4l2_dev;
struct vb2_queue *vbq = &video->queue;
struct video_device *vdev = &video->vdev;
+ struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
int rc;
video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
@@ -1814,16 +2011,18 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc;
}
- v4l2_ctrl_handler_init(&video->ctrl_handler, 2);
- v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &aspeed_video_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0);
- v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+ v4l2_ctrl_new_std_menu(hdl, &aspeed_video_ctrl_ops,
V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
V4L2_JPEG_CHROMA_SUBSAMPLING_444);
+ v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_mode, NULL);
+ v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_jpeg_quality, NULL);
- rc = video->ctrl_handler.error;
+ rc = hdl->error;
if (rc) {
v4l2_ctrl_handler_free(&video->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
@@ -1832,7 +2031,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc;
}
- v4l2_dev->ctrl_handler = &video->ctrl_handler;
+ v4l2_dev->ctrl_handler = hdl;
vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
@@ -1980,6 +2179,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
video->comp_size_read = config->comp_size_read;
video->frame_rate = 30;
+ video->jpeg_hq_quality = 1;
video->dev = &pdev->dev;
spin_lock_init(&video->lock);
mutex_init(&video->video_lock);
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig
index f399dba62e17..3866ccae07df 100644
--- a/drivers/media/platform/atmel/Kconfig
+++ b/drivers/media/platform/atmel/Kconfig
@@ -2,42 +2,6 @@
comment "Atmel media platform drivers"
-config VIDEO_ATMEL_ISC
- tristate "ATMEL Image Sensor Controller (ISC) support"
- depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && COMMON_CLK
- depends on ARCH_AT91 || COMPILE_TEST
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- select VIDEOBUF2_DMA_CONTIG
- select REGMAP_MMIO
- select V4L2_FWNODE
- select VIDEO_ATMEL_ISC_BASE
- help
- This module makes the ATMEL Image Sensor Controller available
- as a v4l2 device.
-
-config VIDEO_ATMEL_XISC
- tristate "ATMEL eXtended Image Sensor Controller (XISC) support"
- depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && COMMON_CLK
- depends on ARCH_AT91 || COMPILE_TEST
- select VIDEOBUF2_DMA_CONTIG
- select REGMAP_MMIO
- select V4L2_FWNODE
- select VIDEO_ATMEL_ISC_BASE
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- help
- This module makes the ATMEL eXtended Image Sensor Controller
- available as a v4l2 device.
-
-config VIDEO_ATMEL_ISC_BASE
- tristate
- default n
- help
- ATMEL ISC and XISC common code base.
-
config VIDEO_ATMEL_ISI
tristate "ATMEL Image Sensor Interface (ISI) support"
depends on V4L_PLATFORM_DRIVERS
@@ -49,18 +13,3 @@ config VIDEO_ATMEL_ISI
This module makes the ATMEL Image Sensor Interface available
as a v4l2 device.
-config VIDEO_MICROCHIP_CSI2DC
- tristate "Microchip CSI2 Demux Controller"
- depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && COMMON_CLK && OF
- depends on ARCH_AT91 || COMPILE_TEST
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- select V4L2_FWNODE
- help
- CSI2 Demux Controller driver. CSI2DC is a helper chip
- that converts IDI interface byte stream to a parallel pixel stream.
- It supports various RAW formats as input.
-
- To compile this driver as a module, choose M here: the
- module will be called microchip-csi2dc.
diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile
index 794e8f739287..a14ac6b5211d 100644
--- a/drivers/media/platform/atmel/Makefile
+++ b/drivers/media/platform/atmel/Makefile
@@ -1,10 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-atmel-isc-objs = atmel-sama5d2-isc.o
-atmel-xisc-objs = atmel-sama7g5-isc.o
-atmel-isc-common-objs = atmel-isc-base.o atmel-isc-clk.o
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
-obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += atmel-isc-common.o
-obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
-obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
-obj-$(CONFIG_VIDEO_MICROCHIP_CSI2DC) += microchip-csi2dc.o
diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda-bit.c
index 2736a902e3df..ed47d5bd8d61 100644
--- a/drivers/media/platform/chips-media/coda-bit.c
+++ b/drivers/media/platform/chips-media/coda-bit.c
@@ -854,7 +854,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
/* Only H.264BP and H.263P3 are considered */
iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
- if (!iram_info->buf_dbk_c_use)
+ if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
goto out;
iram_info->axi_sram_use |= dbk_bits;
@@ -878,7 +878,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
- if (!iram_info->buf_dbk_c_use)
+ if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
goto out;
iram_info->axi_sram_use |= dbk_bits;
@@ -1084,10 +1084,16 @@ static int coda_start_encoding(struct coda_ctx *ctx)
}
if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
- if (!ctx->params.jpeg_qmat_tab[0])
+ if (!ctx->params.jpeg_qmat_tab[0]) {
ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
- if (!ctx->params.jpeg_qmat_tab[1])
+ if (!ctx->params.jpeg_qmat_tab[0])
+ return -ENOMEM;
+ }
+ if (!ctx->params.jpeg_qmat_tab[1]) {
ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+ if (!ctx->params.jpeg_qmat_tab[1])
+ return -ENOMEM;
+ }
coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
}
diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c
index 435e7030fc2a..ba8f41002917 100644
--- a/drivers/media/platform/chips-media/coda-jpeg.c
+++ b/drivers/media/platform/chips-media/coda-jpeg.c
@@ -1052,10 +1052,16 @@ static int coda9_jpeg_start_encoding(struct coda_ctx *ctx)
v4l2_err(&dev->v4l2_dev, "error loading Huffman tables\n");
return ret;
}
- if (!ctx->params.jpeg_qmat_tab[0])
+ if (!ctx->params.jpeg_qmat_tab[0]) {
ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
- if (!ctx->params.jpeg_qmat_tab[1])
+ if (!ctx->params.jpeg_qmat_tab[0])
+ return -ENOMEM;
+ }
+ if (!ctx->params.jpeg_qmat_tab[1]) {
ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+ if (!ctx->params.jpeg_qmat_tab[1])
+ return -ENOMEM;
+ }
coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
return 0;
diff --git a/drivers/media/platform/mediatek/jpeg/Makefile b/drivers/media/platform/mediatek/jpeg/Makefile
index 76c33aad0f3f..26e84852523e 100644
--- a/drivers/media/platform/mediatek/jpeg/Makefile
+++ b/drivers/media/platform/mediatek/jpeg/Makefile
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
-mtk_jpeg-objs := mtk_jpeg_core.o \
- mtk_jpeg_dec_hw.o \
- mtk_jpeg_dec_parse.o \
- mtk_jpeg_enc_hw.o
-obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o
+obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o \
+ mtk-jpeg-enc-hw.o \
+ mtk-jpeg-dec-hw.o
+
+mtk_jpeg-y := mtk_jpeg_core.o \
+ mtk_jpeg_dec_parse.o
+
+mtk-jpeg-enc-hw-y := mtk_jpeg_enc_hw.o
+mtk-jpeg-dec-hw-y := mtk_jpeg_dec_hw.o
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 3071b61946c3..969516a940ba 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -104,11 +104,11 @@ static struct mtk_jpeg_fmt mtk_jpeg_dec_formats[] = {
#define MTK_JPEG_ENC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_enc_formats)
#define MTK_JPEG_DEC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_dec_formats)
+#define MTK_JPEG_MAX_RETRY_TIME 5000
-struct mtk_jpeg_src_buf {
- struct vb2_v4l2_buffer b;
- struct list_head list;
- struct mtk_jpeg_dec_param dec_param;
+enum {
+ MTK_JPEG_BUF_FLAGS_INIT = 0,
+ MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1,
};
static int debug;
@@ -586,6 +586,31 @@ static int mtk_jpeg_enc_s_selection(struct file *file, void *priv,
return 0;
}
+static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct v4l2_fh *fh = file->private_data;
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct vb2_queue *vq;
+ struct vb2_buffer *vb;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ goto end;
+
+ vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
+ if (buf->index >= vq->num_buffers) {
+ dev_err(ctx->jpeg->dev, "buffer index out of range\n");
+ return -EINVAL;
+ }
+
+ vb = vq->bufs[buf->index];
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+ jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
+
+end:
+ return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+
static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = {
.vidioc_querycap = mtk_jpeg_querycap,
.vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap,
@@ -611,6 +636,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = {
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_encoder_cmd = v4l2_m2m_ioctl_encoder_cmd,
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
};
static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = {
@@ -623,7 +651,7 @@ static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = {
.vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane,
.vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane,
- .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_qbuf = mtk_jpeg_qbuf,
.vidioc_subscribe_event = mtk_jpeg_subscribe_event,
.vidioc_g_selection = mtk_jpeg_dec_g_selection,
@@ -637,6 +665,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = {
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
};
static int mtk_jpeg_queue_setup(struct vb2_queue *q,
@@ -678,7 +709,7 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct mtk_jpeg_q_data *q_data = NULL;
- struct v4l2_plane_pix_format plane_fmt;
+ struct v4l2_plane_pix_format plane_fmt = {};
int i;
q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
@@ -905,6 +936,148 @@ static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
return 0;
}
+static int mtk_jpegenc_get_hw(struct mtk_jpeg_ctx *ctx)
+{
+ struct mtk_jpegenc_comp_dev *comp_jpeg;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ unsigned long flags;
+ int hw_id = -1;
+ int i;
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
+ comp_jpeg = jpeg->enc_hw_dev[i];
+ if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
+ hw_id = i;
+ comp_jpeg->hw_state = MTK_JPEG_HW_BUSY;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+
+ return hw_id;
+}
+
+static int mtk_jpegenc_set_hw_param(struct mtk_jpeg_ctx *ctx,
+ int hw_id,
+ struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf)
+{
+ struct mtk_jpegenc_comp_dev *jpeg = ctx->jpeg->enc_hw_dev[hw_id];
+
+ jpeg->hw_param.curr_ctx = ctx;
+ jpeg->hw_param.src_buffer = src_buf;
+ jpeg->hw_param.dst_buffer = dst_buf;
+
+ return 0;
+}
+
+static int mtk_jpegenc_put_hw(struct mtk_jpeg_dev *jpeg, int hw_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ jpeg->enc_hw_dev[hw_id]->hw_state = MTK_JPEG_HW_IDLE;
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+
+ return 0;
+}
+
+static void mtk_jpegenc_worker(struct work_struct *work)
+{
+ struct mtk_jpegenc_comp_dev *comp_jpeg[MTK_JPEGENC_HW_MAX];
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ struct mtk_jpeg_src_buf *jpeg_dst_buf;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ int ret, i, hw_id = 0;
+ unsigned long flags;
+
+ struct mtk_jpeg_ctx *ctx = container_of(work,
+ struct mtk_jpeg_ctx,
+ jpeg_work);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
+ comp_jpeg[i] = jpeg->enc_hw_dev[i];
+ i = 0;
+
+retry_select:
+ hw_id = mtk_jpegenc_get_hw(ctx);
+ if (hw_id < 0) {
+ ret = wait_event_interruptible(jpeg->enc_hw_wq,
+ atomic_read(&jpeg->enchw_rdy) > 0);
+ if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) {
+ dev_err(jpeg->dev, "%s : %d, all HW are busy\n",
+ __func__, __LINE__);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ return;
+ }
+
+ goto retry_select;
+ }
+
+ atomic_dec(&jpeg->enchw_rdy);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ if (!src_buf)
+ goto getbuf_fail;
+
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ if (!dst_buf)
+ goto getbuf_fail;
+
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ mtk_jpegenc_set_hw_param(ctx, hw_id, src_buf, dst_buf);
+ ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev);
+ if (ret < 0) {
+ dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n",
+ __func__, __LINE__);
+ goto enc_end;
+ }
+
+ ret = clk_prepare_enable(comp_jpeg[hw_id]->venc_clk.clks->clk);
+ if (ret) {
+ dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable fail\n",
+ __func__, __LINE__);
+ goto enc_end;
+ }
+
+ schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
+ spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
+ jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
+ jpeg_dst_buf->curr_ctx = ctx;
+ jpeg_dst_buf->frame_num = ctx->total_frame_num;
+ ctx->total_frame_num++;
+ mtk_jpeg_enc_reset(comp_jpeg[hw_id]->reg_base);
+ mtk_jpeg_set_enc_dst(ctx,
+ comp_jpeg[hw_id]->reg_base,
+ &dst_buf->vb2_buf);
+ mtk_jpeg_set_enc_src(ctx,
+ comp_jpeg[hw_id]->reg_base,
+ &src_buf->vb2_buf);
+ mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
+ mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
+
+ return;
+
+enc_end:
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ v4l2_m2m_buf_done(dst_buf, buf_state);
+getbuf_fail:
+ atomic_inc(&jpeg->enchw_rdy);
+ mtk_jpegenc_put_hw(jpeg, hw_id);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
static void mtk_jpeg_enc_device_run(void *priv)
{
struct mtk_jpeg_ctx *ctx = priv;
@@ -922,7 +1095,7 @@ static void mtk_jpeg_enc_device_run(void *priv)
goto enc_end;
schedule_delayed_work(&jpeg->job_timeout_work,
- msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
spin_lock_irqsave(&jpeg->hw_lock, flags);
@@ -947,6 +1120,189 @@ enc_end:
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
+static void mtk_jpeg_multicore_enc_device_run(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ queue_work(jpeg->workqueue, &ctx->jpeg_work);
+}
+
+static int mtk_jpegdec_get_hw(struct mtk_jpeg_ctx *ctx)
+{
+ struct mtk_jpegdec_comp_dev *comp_jpeg;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ unsigned long flags;
+ int hw_id = -1;
+ int i;
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
+ comp_jpeg = jpeg->dec_hw_dev[i];
+ if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
+ hw_id = i;
+ comp_jpeg->hw_state = MTK_JPEG_HW_BUSY;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+
+ return hw_id;
+}
+
+static int mtk_jpegdec_put_hw(struct mtk_jpeg_dev *jpeg, int hw_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ jpeg->dec_hw_dev[hw_id]->hw_state =
+ MTK_JPEG_HW_IDLE;
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+
+ return 0;
+}
+
+static int mtk_jpegdec_set_hw_param(struct mtk_jpeg_ctx *ctx,
+ int hw_id,
+ struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf)
+{
+ struct mtk_jpegdec_comp_dev *jpeg =
+ ctx->jpeg->dec_hw_dev[hw_id];
+
+ jpeg->hw_param.curr_ctx = ctx;
+ jpeg->hw_param.src_buffer = src_buf;
+ jpeg->hw_param.dst_buffer = dst_buf;
+
+ return 0;
+}
+
+static void mtk_jpegdec_worker(struct work_struct *work)
+{
+ struct mtk_jpeg_ctx *ctx = container_of(work, struct mtk_jpeg_ctx,
+ jpeg_work);
+ struct mtk_jpegdec_comp_dev *comp_jpeg[MTK_JPEGDEC_HW_MAX];
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ struct mtk_jpeg_src_buf *jpeg_src_buf, *jpeg_dst_buf;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ int ret, i, hw_id = 0;
+ struct mtk_jpeg_bs bs;
+ struct mtk_jpeg_fb fb;
+ unsigned long flags;
+
+ for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
+ comp_jpeg[i] = jpeg->dec_hw_dev[i];
+ i = 0;
+
+retry_select:
+ hw_id = mtk_jpegdec_get_hw(ctx);
+ if (hw_id < 0) {
+ ret = wait_event_interruptible_timeout(jpeg->dec_hw_wq,
+ atomic_read(&jpeg->dechw_rdy) > 0,
+ MTK_JPEG_HW_TIMEOUT_MSEC);
+ if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) {
+ dev_err(jpeg->dev, "%s : %d, all HW are busy\n",
+ __func__, __LINE__);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ return;
+ }
+
+ goto retry_select;
+ }
+
+ atomic_dec(&jpeg->dechw_rdy);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ if (!src_buf)
+ goto getbuf_fail;
+
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ if (!dst_buf)
+ goto getbuf_fail;
+
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
+ jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
+
+ if (mtk_jpeg_check_resolution_change(ctx,
+ &jpeg_src_buf->dec_param)) {
+ mtk_jpeg_queue_src_chg_event(ctx);
+ ctx->state = MTK_JPEG_SOURCE_CHANGE;
+ goto dec_end;
+ }
+
+ jpeg_src_buf->curr_ctx = ctx;
+ jpeg_src_buf->frame_num = ctx->total_frame_num;
+ jpeg_dst_buf->curr_ctx = ctx;
+ jpeg_dst_buf->frame_num = ctx->total_frame_num;
+
+ mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
+ ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev);
+ if (ret < 0) {
+ dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n",
+ __func__, __LINE__);
+ goto dec_end;
+ }
+
+ ret = clk_prepare_enable(comp_jpeg[hw_id]->jdec_clk.clks->clk);
+ if (ret) {
+ dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable fail\n",
+ __func__, __LINE__);
+ goto clk_end;
+ }
+
+ schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
+ mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
+ if (mtk_jpeg_set_dec_dst(ctx,
+ &jpeg_src_buf->dec_param,
+ &dst_buf->vb2_buf, &fb)) {
+ dev_err(jpeg->dev, "%s : %d, mtk_jpeg_set_dec_dst fail\n",
+ __func__, __LINE__);
+ goto setdst_end;
+ }
+
+ spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
+ ctx->total_frame_num++;
+ mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
+ mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
+ &jpeg_src_buf->dec_param,
+ jpeg_src_buf->bs_size,
+ &bs,
+ &fb);
+ mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
+
+ return;
+
+setdst_end:
+ clk_disable_unprepare(comp_jpeg[hw_id]->jdec_clk.clks->clk);
+clk_end:
+ pm_runtime_put(comp_jpeg[hw_id]->dev);
+dec_end:
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ v4l2_m2m_buf_done(dst_buf, buf_state);
+getbuf_fail:
+ atomic_inc(&jpeg->dechw_rdy);
+ mtk_jpegdec_put_hw(jpeg, hw_id);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void mtk_jpeg_multicore_dec_device_run(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ queue_work(jpeg->workqueue, &ctx->jpeg_work);
+}
+
static void mtk_jpeg_dec_device_run(void *priv)
{
struct mtk_jpeg_ctx *ctx = priv;
@@ -984,8 +1340,10 @@ static void mtk_jpeg_dec_device_run(void *priv)
spin_lock_irqsave(&jpeg->hw_lock, flags);
mtk_jpeg_dec_reset(jpeg->reg_base);
mtk_jpeg_dec_set_config(jpeg->reg_base,
- &jpeg_src_buf->dec_param, &bs, &fb);
-
+ &jpeg_src_buf->dec_param,
+ jpeg_src_buf->bs_size,
+ &bs,
+ &fb);
mtk_jpeg_dec_start(jpeg->reg_base);
spin_unlock_irqrestore(&jpeg->hw_lock, flags);
return;
@@ -1009,6 +1367,14 @@ static const struct v4l2_m2m_ops mtk_jpeg_enc_m2m_ops = {
.device_run = mtk_jpeg_enc_device_run,
};
+static const struct v4l2_m2m_ops mtk_jpeg_multicore_enc_m2m_ops = {
+ .device_run = mtk_jpeg_multicore_enc_device_run,
+};
+
+static const struct v4l2_m2m_ops mtk_jpeg_multicore_dec_m2m_ops = {
+ .device_run = mtk_jpeg_multicore_dec_device_run,
+};
+
static const struct v4l2_m2m_ops mtk_jpeg_dec_m2m_ops = {
.device_run = mtk_jpeg_dec_device_run,
.job_ready = mtk_jpeg_dec_job_ready,
@@ -1209,6 +1575,14 @@ static int mtk_jpeg_open(struct file *file)
goto free;
}
+ if (jpeg->is_jpgenc_multihw)
+ INIT_WORK(&ctx->jpeg_work, mtk_jpegenc_worker);
+
+ if (jpeg->is_jpgdec_multihw)
+ INIT_WORK(&ctx->jpeg_work, mtk_jpegdec_worker);
+
+ INIT_LIST_HEAD(&ctx->dst_done_queue);
+ spin_lock_init(&ctx->done_queue_lock);
v4l2_fh_init(&ctx->fh, vfd);
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
@@ -1230,6 +1604,7 @@ static int mtk_jpeg_open(struct file *file)
} else {
v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 0);
}
+
mtk_jpeg_set_default_params(ctx);
mutex_unlock(&jpeg->lock);
return 0;
@@ -1310,38 +1685,51 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
spin_lock_init(&jpeg->hw_lock);
jpeg->dev = &pdev->dev;
jpeg->variant = of_device_get_match_data(jpeg->dev);
- INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work);
- jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(jpeg->reg_base)) {
- ret = PTR_ERR(jpeg->reg_base);
- return ret;
+ ret = devm_of_platform_populate(&pdev->dev);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "Master of platform populate failed.");
+ return -EINVAL;
}
- jpeg_irq = platform_get_irq(pdev, 0);
- if (jpeg_irq < 0)
- return jpeg_irq;
+ if (list_empty(&pdev->dev.devres_head)) {
+ INIT_DELAYED_WORK(&jpeg->job_timeout_work,
+ mtk_jpeg_job_timeout_work);
- ret = devm_request_irq(&pdev->dev, jpeg_irq,
- jpeg->variant->irq_handler, 0, pdev->name, jpeg);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n",
- jpeg_irq, ret);
- goto err_req_irq;
- }
+ jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(jpeg->reg_base)) {
+ ret = PTR_ERR(jpeg->reg_base);
+ return ret;
+ }
- ret = devm_clk_bulk_get(jpeg->dev, jpeg->variant->num_clks,
- jpeg->variant->clks);
- if (ret) {
- dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret);
- goto err_clk_init;
+ jpeg_irq = platform_get_irq(pdev, 0);
+ if (jpeg_irq < 0)
+ return jpeg_irq;
+
+ ret = devm_request_irq(&pdev->dev,
+ jpeg_irq,
+ jpeg->variant->irq_handler,
+ 0,
+ pdev->name, jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n",
+ jpeg_irq, ret);
+ return ret;
+ }
+
+ ret = devm_clk_bulk_get(jpeg->dev,
+ jpeg->variant->num_clks,
+ jpeg->variant->clks);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init clk\n");
+ return ret;
+ }
}
ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to register v4l2 device\n");
- ret = -EINVAL;
- goto err_dev_register;
+ return -EINVAL;
}
jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
@@ -1399,12 +1787,6 @@ err_vfd_jpeg_alloc:
err_m2m_init:
v4l2_device_unregister(&jpeg->v4l2_dev);
-err_dev_register:
-
-err_clk_init:
-
-err_req_irq:
-
return ret;
}
@@ -1494,6 +1876,29 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = {
.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
};
+static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
+ .formats = mtk_jpeg_enc_formats,
+ .num_formats = MTK_JPEG_ENC_NUM_FORMATS,
+ .qops = &mtk_jpeg_enc_qops,
+ .m2m_ops = &mtk_jpeg_multicore_enc_m2m_ops,
+ .dev_name = "mtk-jpeg-enc",
+ .ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
+ .out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
+ .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+};
+
+static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
+ .formats = mtk_jpeg_dec_formats,
+ .num_formats = MTK_JPEG_DEC_NUM_FORMATS,
+ .qops = &mtk_jpeg_dec_qops,
+ .m2m_ops = &mtk_jpeg_multicore_dec_m2m_ops,
+ .dev_name = "mtk-jpeg-dec",
+ .ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
+ .out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+ .cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+};
+
+#if defined(CONFIG_OF)
static const struct of_device_id mtk_jpeg_match[] = {
{
.compatible = "mediatek,mt8173-jpgdec",
@@ -1507,17 +1912,26 @@ static const struct of_device_id mtk_jpeg_match[] = {
.compatible = "mediatek,mtk-jpgenc",
.data = &mtk_jpeg_drvdata,
},
+ {
+ .compatible = "mediatek,mt8195-jpgenc",
+ .data = &mtk8195_jpegenc_drvdata,
+ },
+ {
+ .compatible = "mediatek,mt8195-jpgdec",
+ .data = &mtk8195_jpegdec_drvdata,
+ },
{},
};
MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
+#endif
static struct platform_driver mtk_jpeg_driver = {
.probe = mtk_jpeg_probe,
.remove = mtk_jpeg_remove,
.driver = {
.name = MTK_JPEG_NAME,
- .of_match_table = mtk_jpeg_match,
+ .of_match_table = of_match_ptr(mtk_jpeg_match),
.pm = &mtk_jpeg_pm_ops,
},
};
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index 3e4811a41ba2..b9126476be8f 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -9,14 +9,16 @@
#ifndef _MTK_JPEG_CORE_H
#define _MTK_JPEG_CORE_H
+#include <linux/clk.h>
#include <linux/interrupt.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
-#define MTK_JPEG_NAME "mtk-jpeg"
+#include "mtk_jpeg_dec_hw.h"
-#define MTK_JPEG_COMP_MAX 3
+#define MTK_JPEG_NAME "mtk-jpeg"
#define MTK_JPEG_FMT_FLAG_OUTPUT BIT(0)
#define MTK_JPEG_FMT_FLAG_CAPTURE BIT(1)
@@ -74,6 +76,115 @@ struct mtk_jpeg_variant {
u32 cap_q_default_fourcc;
};
+struct mtk_jpeg_src_buf {
+ u32 frame_num;
+ struct vb2_v4l2_buffer b;
+ struct list_head list;
+ u32 bs_size;
+ struct mtk_jpeg_dec_param dec_param;
+
+ struct mtk_jpeg_ctx *curr_ctx;
+};
+
+enum mtk_jpeg_hw_state {
+ MTK_JPEG_HW_IDLE = 0,
+ MTK_JPEG_HW_BUSY = 1,
+};
+
+struct mtk_jpeg_hw_param {
+ struct vb2_v4l2_buffer *src_buffer;
+ struct vb2_v4l2_buffer *dst_buffer;
+ struct mtk_jpeg_ctx *curr_ctx;
+};
+
+enum mtk_jpegenc_hw_id {
+ MTK_JPEGENC_HW0,
+ MTK_JPEGENC_HW1,
+ MTK_JPEGENC_HW_MAX,
+};
+
+enum mtk_jpegdec_hw_id {
+ MTK_JPEGDEC_HW0,
+ MTK_JPEGDEC_HW1,
+ MTK_JPEGDEC_HW2,
+ MTK_JPEGDEC_HW_MAX,
+};
+
+/**
+ * struct mtk_jpegenc_clk - Structure used to store vcodec clock information
+ * @clks: JPEG encode clock
+ * @clk_num: JPEG encode clock numbers
+ */
+struct mtk_jpegenc_clk {
+ struct clk_bulk_data *clks;
+ int clk_num;
+};
+
+/**
+ * struct mtk_jpegdec_clk - Structure used to store vcodec clock information
+ * @clks: JPEG decode clock
+ * @clk_num: JPEG decode clock numbers
+ */
+struct mtk_jpegdec_clk {
+ struct clk_bulk_data *clks;
+ int clk_num;
+};
+
+/**
+ * struct mtk_jpegenc_comp_dev - JPEG COREX abstraction
+ * @dev: JPEG device
+ * @plat_dev: platform device data
+ * @reg_base: JPEG registers mapping
+ * @master_dev: mtk_jpeg_dev device
+ * @venc_clk: jpeg encode clock
+ * @jpegenc_irq: jpeg encode irq num
+ * @job_timeout_work: encode timeout workqueue
+ * @hw_param: jpeg encode hw parameters
+ * @hw_rdy: record hw ready
+ * @hw_state: record hw state
+ * @hw_lock: spinlock protecting the hw device resource
+ */
+struct mtk_jpegenc_comp_dev {
+ struct device *dev;
+ struct platform_device *plat_dev;
+ void __iomem *reg_base;
+ struct mtk_jpeg_dev *master_dev;
+ struct mtk_jpegenc_clk venc_clk;
+ int jpegenc_irq;
+ struct delayed_work job_timeout_work;
+ struct mtk_jpeg_hw_param hw_param;
+ enum mtk_jpeg_hw_state hw_state;
+ /* spinlock protecting the hw device resource */
+ spinlock_t hw_lock;
+};
+
+/**
+ * struct mtk_jpegdec_comp_dev - JPEG COREX abstraction
+ * @dev: JPEG device
+ * @plat_dev: platform device data
+ * @reg_base: JPEG registers mapping
+ * @master_dev: mtk_jpeg_dev device
+ * @jdec_clk: mtk_jpegdec_clk
+ * @jpegdec_irq: jpeg decode irq num
+ * @job_timeout_work: decode timeout workqueue
+ * @hw_param: jpeg decode hw parameters
+ * @hw_state: record hw state
+ * @hw_lock: spinlock protecting hw
+ */
+struct mtk_jpegdec_comp_dev {
+ struct device *dev;
+ struct platform_device *plat_dev;
+ void __iomem *reg_base;
+ struct mtk_jpeg_dev *master_dev;
+ struct mtk_jpegdec_clk jdec_clk;
+ int jpegdec_irq;
+ struct delayed_work job_timeout_work;
+ struct mtk_jpeg_hw_param hw_param;
+ enum mtk_jpeg_hw_state hw_state;
+ /* spinlock protecting the hw device resource */
+ spinlock_t hw_lock;
+};
+
/**
* struct mtk_jpeg_dev - JPEG IP abstraction
* @lock: the mutex protecting this structure
@@ -87,6 +198,17 @@ struct mtk_jpeg_variant {
* @reg_base: JPEG registers mapping
* @job_timeout_work: IRQ timeout structure
* @variant: driver variant to be used
+ * @reg_encbase: jpg encode register base addr
+ * @enc_hw_dev: jpg encode hardware device
+ * @is_jpgenc_multihw: the flag of multi-hw core
+ * @enc_hw_wq: jpg encode wait queue
+ * @enchw_rdy: jpg encode hw ready flag
+ * @reg_decbase: jpg decode register base addr
+ * @dec_hw_dev: jpg decode hardware device
+ * @is_jpgdec_multihw: the flag of dec multi-hw core
+ * @dec_hw_wq: jpg decode wait queue
+ * @dec_workqueue: jpg decode work queue
+ * @dechw_rdy: jpg decode hw ready flag
*/
struct mtk_jpeg_dev {
struct mutex lock;
@@ -100,6 +222,19 @@ struct mtk_jpeg_dev {
void __iomem *reg_base;
struct delayed_work job_timeout_work;
const struct mtk_jpeg_variant *variant;
+
+ void __iomem *reg_encbase[MTK_JPEGENC_HW_MAX];
+ struct mtk_jpegenc_comp_dev *enc_hw_dev[MTK_JPEGENC_HW_MAX];
+ bool is_jpgenc_multihw;
+ wait_queue_head_t enc_hw_wq;
+ atomic_t enchw_rdy;
+
+ void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX];
+ struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX];
+ bool is_jpgdec_multihw;
+ wait_queue_head_t dec_hw_wq;
+ struct workqueue_struct *dec_workqueue;
+ atomic_t dechw_rdy;
};
/**
@@ -138,15 +273,20 @@ struct mtk_jpeg_q_data {
/**
* struct mtk_jpeg_ctx - the device context data
- * @jpeg: JPEG IP device for this context
- * @out_q: source (output) queue information
- * @cap_q: destination (capture) queue queue information
- * @fh: V4L2 file handle
- * @state: state of the context
- * @enable_exif: enable exif mode of jpeg encoder
- * @enc_quality: jpeg encoder quality
- * @restart_interval: jpeg encoder restart interval
- * @ctrl_hdl: controls handler
+ * @jpeg: JPEG IP device for this context
+ * @out_q: source (output) queue information
+ * @cap_q: destination queue information
+ * @fh: V4L2 file handle
+ * @state: state of the context
+ * @enable_exif: enable exif mode of jpeg encoder
+ * @enc_quality: jpeg encoder quality
+ * @restart_interval: jpeg encoder restart interval
+ * @ctrl_hdl: controls handler
+ * @jpeg_work: jpeg encoder workqueue
+ * @total_frame_num: encoded frame number
+ * @dst_done_queue: encoded frame buffer queue
+ * @done_queue_lock: encoded frame operation spinlock
+ * @last_done_frame_num: the last encoded frame number
*/
struct mtk_jpeg_ctx {
struct mtk_jpeg_dev *jpeg;
@@ -158,6 +298,13 @@ struct mtk_jpeg_ctx {
u8 enc_quality;
u8 restart_interval;
struct v4l2_ctrl_handler ctrl_hdl;
+
+ struct work_struct jpeg_work;
+ u32 total_frame_num;
+ struct list_head dst_done_queue;
+ /* spinlock protecting the encode done buffer */
+ spinlock_t done_queue_lock;
+ u32 last_done_frame_num;
};
#endif /* _MTK_JPEG_CORE_H */
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index afbbfd5d02bc..8c07fa02fd9a 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -5,10 +5,26 @@
* Rick Chang <rick.chang@mediatek.com>
*/
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <media/media-device.h>
#include <media/videobuf2-core.h>
-
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "mtk_jpeg_core.h"
#include "mtk_jpeg_dec_hw.h"
#define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3)
@@ -23,6 +39,16 @@ enum mtk_jpeg_color {
MTK_JPEG_COLOR_400 = 0x00110000
};
+#if defined(CONFIG_OF)
+static const struct of_device_id mtk_jpegdec_hw_ids[] = {
+ {
+ .compatible = "mediatek,mt8195-jpgdec-hw",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_jpegdec_hw_ids);
+#endif
+
static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg)
{
if (val & (align - 1)) {
@@ -188,6 +214,7 @@ int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param)
return 0;
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_fill_param);
u32 mtk_jpeg_dec_get_int_status(void __iomem *base)
{
@@ -199,6 +226,7 @@ u32 mtk_jpeg_dec_get_int_status(void __iomem *base)
return ret;
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_get_int_status);
u32 mtk_jpeg_dec_enum_result(u32 irq_result)
{
@@ -215,11 +243,13 @@ u32 mtk_jpeg_dec_enum_result(u32 irq_result)
return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN;
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_enum_result);
void mtk_jpeg_dec_start(void __iomem *base)
{
writel(0, base + JPGDEC_REG_TRIG);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_start);
static void mtk_jpeg_dec_soft_reset(void __iomem *base)
{
@@ -239,6 +269,7 @@ void mtk_jpeg_dec_reset(void __iomem *base)
mtk_jpeg_dec_soft_reset(base);
mtk_jpeg_dec_hard_reset(base);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_reset);
static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w,
u8 yscale_h, u8 uvscale_w, u8 uvscale_h)
@@ -299,12 +330,14 @@ static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr)
writel(ptr, base + JPGDEC_REG_FILE_BRP);
}
-static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size)
+static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size,
+ u32 bitstream_size)
{
mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR);
mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE);
writel(addr, base + JPGDEC_REG_FILE_ADDR);
writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE);
+ writel(bitstream_size, base + JPGDEC_REG_BIT_STREAM_SIZE);
}
static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u,
@@ -373,37 +406,275 @@ static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num,
}
void mtk_jpeg_dec_set_config(void __iomem *base,
- struct mtk_jpeg_dec_param *config,
+ struct mtk_jpeg_dec_param *cfg,
+ u32 bitstream_size,
struct mtk_jpeg_bs *bs,
struct mtk_jpeg_fb *fb)
{
- mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0);
+ mtk_jpeg_dec_set_brz_factor(base, 0, 0, cfg->uv_brz_w, 0);
mtk_jpeg_dec_set_dec_mode(base, 0);
- mtk_jpeg_dec_set_comp0_du(base, config->unit_num);
- mtk_jpeg_dec_set_total_mcu(base, config->total_mcu);
- mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size);
+ mtk_jpeg_dec_set_comp0_du(base, cfg->unit_num);
+ mtk_jpeg_dec_set_total_mcu(base, cfg->total_mcu);
+ mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size, bitstream_size);
mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr);
- mtk_jpeg_dec_set_du_membership(base, config->membership, 1,
- (config->comp_num == 1) ? 1 : 0);
- mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1],
- config->comp_id[2]);
- mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0],
- config->qtbl_num[1], config->qtbl_num[2]);
- mtk_jpeg_dec_set_sampling_factor(base, config->comp_num,
- config->sampling_w[0],
- config->sampling_h[0],
- config->sampling_w[1],
- config->sampling_h[1],
- config->sampling_w[2],
- config->sampling_h[2]);
- mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0],
- config->mem_stride[1]);
- mtk_jpeg_dec_set_img_stride(base, config->img_stride[0],
- config->img_stride[1]);
+ mtk_jpeg_dec_set_du_membership(base, cfg->membership, 1,
+ (cfg->comp_num == 1) ? 1 : 0);
+ mtk_jpeg_dec_set_comp_id(base, cfg->comp_id[0], cfg->comp_id[1],
+ cfg->comp_id[2]);
+ mtk_jpeg_dec_set_q_table(base, cfg->qtbl_num[0],
+ cfg->qtbl_num[1], cfg->qtbl_num[2]);
+ mtk_jpeg_dec_set_sampling_factor(base, cfg->comp_num,
+ cfg->sampling_w[0],
+ cfg->sampling_h[0],
+ cfg->sampling_w[1],
+ cfg->sampling_h[1],
+ cfg->sampling_w[2],
+ cfg->sampling_h[2]);
+ mtk_jpeg_dec_set_mem_stride(base, cfg->mem_stride[0],
+ cfg->mem_stride[1]);
+ mtk_jpeg_dec_set_img_stride(base, cfg->img_stride[0],
+ cfg->img_stride[1]);
mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0],
fb->plane_addr[1], fb->plane_addr[2]);
mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0);
- mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group,
- config->dma_last_mcu);
- mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu);
+ mtk_jpeg_dec_set_dma_group(base, cfg->dma_mcu, cfg->dma_group,
+ cfg->dma_last_mcu);
+ mtk_jpeg_dec_set_pause_mcu_idx(base, cfg->total_mcu);
+}
+EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config);
+
+static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg)
+{
+ struct mtk_jpeg_src_buf *dst_done_buf, *tmp_dst_done_buf;
+ struct vb2_v4l2_buffer *dst_buffer;
+ struct list_head *temp_entry;
+ struct list_head *pos = NULL;
+ struct mtk_jpeg_ctx *ctx;
+ unsigned long flags;
+
+ ctx = jpeg->hw_param.curr_ctx;
+ if (unlikely(!ctx)) {
+ dev_err(jpeg->dev, "comp_jpeg ctx fail !!!\n");
+ return;
+ }
+
+ dst_buffer = jpeg->hw_param.dst_buffer;
+ if (!dst_buffer) {
+ dev_err(jpeg->dev, "comp_jpeg dst_buffer fail !!!\n");
+ return;
+ }
+
+ dst_done_buf = container_of(dst_buffer, struct mtk_jpeg_src_buf, b);
+
+ spin_lock_irqsave(&ctx->done_queue_lock, flags);
+ list_add_tail(&dst_done_buf->list, &ctx->dst_done_queue);
+ while (!list_empty(&ctx->dst_done_queue) &&
+ (pos != &ctx->dst_done_queue)) {
+ list_for_each_prev_safe(pos, temp_entry, &ctx->dst_done_queue) {
+ tmp_dst_done_buf = list_entry(pos,
+ struct mtk_jpeg_src_buf,
+ list);
+ if (tmp_dst_done_buf->frame_num ==
+ ctx->last_done_frame_num) {
+ list_del(&tmp_dst_done_buf->list);
+ v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
+ VB2_BUF_STATE_DONE);
+ ctx->last_done_frame_num++;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
+}
+
+static void mtk_jpegdec_timeout_work(struct work_struct *work)
+{
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ struct mtk_jpegdec_comp_dev *cjpeg =
+ container_of(work, struct mtk_jpegdec_comp_dev,
+ job_timeout_work.work);
+ struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = cjpeg->hw_param.src_buffer;
+ dst_buf = cjpeg->hw_param.dst_buffer;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ mtk_jpeg_dec_reset(cjpeg->reg_base);
+ clk_disable_unprepare(cjpeg->jdec_clk.clks->clk);
+ pm_runtime_put(cjpeg->dev);
+ cjpeg->hw_state = MTK_JPEG_HW_IDLE;
+ atomic_inc(&master_jpeg->dechw_rdy);
+ wake_up(&master_jpeg->dec_hw_wq);
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ mtk_jpegdec_put_buf(cjpeg);
+}
+
+static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
+{
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+ enum vb2_buffer_state buf_state;
+ struct mtk_jpeg_ctx *ctx;
+ u32 dec_irq_ret;
+ u32 irq_status;
+ int i;
+
+ struct mtk_jpegdec_comp_dev *jpeg = priv;
+ struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev;
+
+ cancel_delayed_work(&jpeg->job_timeout_work);
+
+ ctx = jpeg->hw_param.curr_ctx;
+ src_buf = jpeg->hw_param.src_buffer;
+ dst_buf = jpeg->hw_param.dst_buffer;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ irq_status = mtk_jpeg_dec_get_int_status(jpeg->reg_base);
+ dec_irq_ret = mtk_jpeg_dec_enum_result(irq_status);
+ if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW)
+ mtk_jpeg_dec_reset(jpeg->reg_base);
+
+ if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE)
+ dev_warn(jpeg->dev, "Jpg Dec occurs unknown Err.");
+
+ jpeg_src_buf =
+ container_of(src_buf, struct mtk_jpeg_src_buf, b);
+
+ for (i = 0; i < dst_buf->vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&dst_buf->vb2_buf, i,
+ jpeg_src_buf->dec_param.comp_size[i]);
+
+ buf_state = VB2_BUF_STATE_DONE;
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ mtk_jpegdec_put_buf(jpeg);
+ pm_runtime_put(ctx->jpeg->dev);
+ clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
+
+ jpeg->hw_state = MTK_JPEG_HW_IDLE;
+ wake_up(&master_jpeg->dec_hw_wq);
+ atomic_inc(&master_jpeg->dechw_rdy);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ int ret;
+
+ dev->jpegdec_irq = platform_get_irq(pdev, 0);
+ if (dev->jpegdec_irq < 0)
+ return dev->jpegdec_irq;
+
+ ret = devm_request_irq(&pdev->dev,
+ dev->jpegdec_irq,
+ mtk_jpegdec_hw_irq_handler,
+ 0,
+ pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to devm_request_irq %d (%d)",
+ dev->jpegdec_irq, ret);
+ return ret;
+ }
+
+ return 0;
}
+
+static void mtk_jpegdec_destroy_workqueue(void *data)
+{
+ destroy_workqueue(data);
+}
+
+static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
+{
+ struct mtk_jpegdec_clk *jpegdec_clk;
+ struct mtk_jpeg_dev *master_dev;
+ struct mtk_jpegdec_comp_dev *dev;
+ int ret, i;
+
+ struct device *decs = &pdev->dev;
+
+ if (!decs->parent)
+ return -EPROBE_DEFER;
+
+ master_dev = dev_get_drvdata(decs->parent);
+ if (!master_dev)
+ return -EPROBE_DEFER;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->plat_dev = pdev;
+ dev->dev = &pdev->dev;
+
+ if (!master_dev->is_jpgdec_multihw) {
+ master_dev->is_jpgdec_multihw = true;
+ for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
+ master_dev->dec_hw_dev[i] = NULL;
+
+ init_waitqueue_head(&master_dev->dec_hw_wq);
+ master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME,
+ WQ_MEM_RECLAIM
+ | WQ_FREEZABLE);
+ if (!master_dev->workqueue)
+ return -EINVAL;
+
+ ret = devm_add_action_or_reset(&pdev->dev, mtk_jpegdec_destroy_workqueue,
+ master_dev->workqueue);
+ if (ret)
+ return ret;
+ }
+
+ atomic_set(&master_dev->dechw_rdy, MTK_JPEGDEC_HW_MAX);
+ spin_lock_init(&dev->hw_lock);
+ dev->hw_state = MTK_JPEG_HW_IDLE;
+
+ INIT_DELAYED_WORK(&dev->job_timeout_work,
+ mtk_jpegdec_timeout_work);
+
+ jpegdec_clk = &dev->jdec_clk;
+
+ jpegdec_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev,
+ &jpegdec_clk->clks);
+ if (jpegdec_clk->clk_num < 0)
+ return dev_err_probe(&pdev->dev,
+ jpegdec_clk->clk_num,
+ "Failed to get jpegdec clock count.\n");
+
+ dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dev->reg_base))
+ return PTR_ERR(dev->reg_base);
+
+ ret = mtk_jpegdec_hw_init_irq(dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to register JPEGDEC irq handler.\n");
+
+ for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
+ if (master_dev->dec_hw_dev[i])
+ continue;
+
+ master_dev->dec_hw_dev[i] = dev;
+ master_dev->reg_decbase[i] = dev->reg_base;
+ dev->master_dev = master_dev;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver mtk_jpegdec_hw_driver = {
+ .probe = mtk_jpegdec_hw_probe,
+ .driver = {
+ .name = "mtk-jpegdec-hw",
+ .of_match_table = of_match_ptr(mtk_jpegdec_hw_ids),
+ },
+};
+
+module_platform_driver(mtk_jpegdec_hw_driver);
+
+MODULE_DESCRIPTION("MediaTek JPEG decode HW driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h
index fa0d45fd7c34..8c31c6b12417 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h
@@ -11,9 +11,10 @@
#include <media/videobuf2-core.h>
-#include "mtk_jpeg_core.h"
#include "mtk_jpeg_dec_reg.h"
+#define MTK_JPEG_COMP_MAX 3
+
enum {
MTK_JPEG_DEC_RESULT_EOF_DONE = 0,
MTK_JPEG_DEC_RESULT_PAUSE = 1,
@@ -70,7 +71,8 @@ int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param);
u32 mtk_jpeg_dec_get_int_status(void __iomem *dec_reg_base);
u32 mtk_jpeg_dec_enum_result(u32 irq_result);
void mtk_jpeg_dec_set_config(void __iomem *base,
- struct mtk_jpeg_dec_param *config,
+ struct mtk_jpeg_dec_param *cfg,
+ u32 bitstream_size,
struct mtk_jpeg_bs *bs,
struct mtk_jpeg_fb *fb);
void mtk_jpeg_dec_reset(void __iomem *dec_reg_base);
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h
index 21ec8f96797f..27b7711ca341 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h
@@ -45,5 +45,6 @@
#define JPGDEC_REG_QT_ID 0x0270
#define JPGDEC_REG_INTERRUPT_STATUS 0x0274
#define JPGDEC_REG_STATUS 0x0278
+#define JPGDEC_REG_BIT_STREAM_SIZE 0x0344
#endif /* _MTK_JPEG_REG_H */
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 1cf037bf72dd..1bbb712d78d0 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -5,11 +5,27 @@
*
*/
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <media/media-device.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include "mtk_jpeg_core.h"
#include "mtk_jpeg_enc_hw.h"
static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = {
@@ -30,18 +46,30 @@ static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = {
{.quality_param = 97, .hardware_value = JPEG_ENC_QUALITY_Q97},
};
+#if defined(CONFIG_OF)
+static const struct of_device_id mtk_jpegenc_drv_ids[] = {
+ {
+ .compatible = "mediatek,mt8195-jpgenc-hw",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_jpegenc_drv_ids);
+#endif
+
void mtk_jpeg_enc_reset(void __iomem *base)
{
writel(0, base + JPEG_ENC_RSTB);
writel(JPEG_ENC_RESET_BIT, base + JPEG_ENC_RSTB);
writel(0, base + JPEG_ENC_CODEC_SEL);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_enc_reset);
u32 mtk_jpeg_enc_get_file_size(void __iomem *base)
{
return readl(base + JPEG_ENC_DMA_ADDR0) -
readl(base + JPEG_ENC_DST_ADDR0);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_enc_get_file_size);
void mtk_jpeg_enc_start(void __iomem *base)
{
@@ -51,6 +79,7 @@ void mtk_jpeg_enc_start(void __iomem *base)
value |= JPEG_ENC_CTRL_INT_EN_BIT | JPEG_ENC_CTRL_ENABLE_BIT;
writel(value, base + JPEG_ENC_CTRL);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_enc_start);
void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base,
struct vb2_buffer *src_buf)
@@ -67,6 +96,7 @@ void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base,
writel(dma_addr, base + JPEG_ENC_SRC_CHROMA_ADDR);
}
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_src);
void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base,
struct vb2_buffer *dst_buf)
@@ -86,6 +116,7 @@ void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base,
writel(dma_addr & ~0xf, base + JPEG_ENC_DST_ADDR0);
writel((dma_addr + size) & ~0xf, base + JPEG_ENC_STALL_ADDR0);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_dst);
void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base)
{
@@ -152,3 +183,227 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base)
writel(ctx->restart_interval, base + JPEG_ENC_RST_MCU_NUM);
}
+EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_params);
+
+static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg)
+{
+ struct mtk_jpeg_ctx *ctx;
+ struct vb2_v4l2_buffer *dst_buffer;
+ struct list_head *temp_entry;
+ struct list_head *pos = NULL;
+ struct mtk_jpeg_src_buf *dst_done_buf, *tmp_dst_done_buf;
+ unsigned long flags;
+
+ ctx = jpeg->hw_param.curr_ctx;
+ if (!ctx) {
+ dev_err(jpeg->dev, "comp_jpeg ctx fail !!!\n");
+ return;
+ }
+
+ dst_buffer = jpeg->hw_param.dst_buffer;
+ if (!dst_buffer) {
+ dev_err(jpeg->dev, "comp_jpeg dst_buffer fail !!!\n");
+ return;
+ }
+
+ dst_done_buf = container_of(dst_buffer,
+ struct mtk_jpeg_src_buf, b);
+
+ spin_lock_irqsave(&ctx->done_queue_lock, flags);
+ list_add_tail(&dst_done_buf->list, &ctx->dst_done_queue);
+ while (!list_empty(&ctx->dst_done_queue) &&
+ (pos != &ctx->dst_done_queue)) {
+ list_for_each_prev_safe(pos, temp_entry, &ctx->dst_done_queue) {
+ tmp_dst_done_buf = list_entry(pos,
+ struct mtk_jpeg_src_buf,
+ list);
+ if (tmp_dst_done_buf->frame_num ==
+ ctx->last_done_frame_num) {
+ list_del(&tmp_dst_done_buf->list);
+ v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
+ VB2_BUF_STATE_DONE);
+ ctx->last_done_frame_num++;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
+}
+
+static void mtk_jpegenc_timeout_work(struct work_struct *work)
+{
+ struct delayed_work *dly_work = to_delayed_work(work);
+ struct mtk_jpegenc_comp_dev *cjpeg =
+ container_of(dly_work,
+ struct mtk_jpegenc_comp_dev,
+ job_timeout_work);
+ struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = cjpeg->hw_param.src_buffer;
+ dst_buf = cjpeg->hw_param.dst_buffer;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ mtk_jpeg_enc_reset(cjpeg->reg_base);
+ clk_disable_unprepare(cjpeg->venc_clk.clks->clk);
+ pm_runtime_put(cjpeg->dev);
+ cjpeg->hw_state = MTK_JPEG_HW_IDLE;
+ atomic_inc(&master_jpeg->enchw_rdy);
+ wake_up(&master_jpeg->enc_hw_wq);
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ mtk_jpegenc_put_buf(cjpeg);
+}
+
+static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
+{
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ enum vb2_buffer_state buf_state;
+ struct mtk_jpeg_ctx *ctx;
+ u32 result_size;
+ u32 irq_status;
+
+ struct mtk_jpegenc_comp_dev *jpeg = priv;
+ struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev;
+
+ cancel_delayed_work(&jpeg->job_timeout_work);
+
+ ctx = jpeg->hw_param.curr_ctx;
+ src_buf = jpeg->hw_param.src_buffer;
+ dst_buf = jpeg->hw_param.dst_buffer;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+
+ irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) &
+ JPEG_ENC_INT_STATUS_MASK_ALLIRQ;
+ if (irq_status)
+ writel(0, jpeg->reg_base + JPEG_ENC_INT_STS);
+ if (!(irq_status & JPEG_ENC_INT_STATUS_DONE))
+ dev_warn(jpeg->dev, "Jpg Enc occurs unknown Err.");
+
+ result_size = mtk_jpeg_enc_get_file_size(jpeg->reg_base);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size);
+ buf_state = VB2_BUF_STATE_DONE;
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ mtk_jpegenc_put_buf(jpeg);
+ pm_runtime_put(ctx->jpeg->dev);
+ clk_disable_unprepare(jpeg->venc_clk.clks->clk);
+ if (!list_empty(&ctx->fh.m2m_ctx->out_q_ctx.rdy_queue) ||
+ !list_empty(&ctx->fh.m2m_ctx->cap_q_ctx.rdy_queue)) {
+ queue_work(master_jpeg->workqueue, &ctx->jpeg_work);
+ }
+
+ jpeg->hw_state = MTK_JPEG_HW_IDLE;
+ wake_up(&master_jpeg->enc_hw_wq);
+ atomic_inc(&master_jpeg->enchw_rdy);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_jpegenc_hw_init_irq(struct mtk_jpegenc_comp_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ int ret;
+
+ dev->jpegenc_irq = platform_get_irq(pdev, 0);
+ if (dev->jpegenc_irq < 0)
+ return dev->jpegenc_irq;
+
+ ret = devm_request_irq(&pdev->dev,
+ dev->jpegenc_irq,
+ mtk_jpegenc_hw_irq_handler,
+ 0,
+ pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to devm_request_irq %d (%d)",
+ dev->jpegenc_irq, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
+{
+ struct mtk_jpegenc_clk *jpegenc_clk;
+ struct mtk_jpeg_dev *master_dev;
+ struct mtk_jpegenc_comp_dev *dev;
+ int ret, i;
+
+ struct device *decs = &pdev->dev;
+
+ if (!decs->parent)
+ return -EPROBE_DEFER;
+
+ master_dev = dev_get_drvdata(decs->parent);
+ if (!master_dev)
+ return -EPROBE_DEFER;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->plat_dev = pdev;
+ dev->dev = &pdev->dev;
+
+ if (!master_dev->is_jpgenc_multihw) {
+ master_dev->is_jpgenc_multihw = true;
+ for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
+ master_dev->enc_hw_dev[i] = NULL;
+
+ init_waitqueue_head(&master_dev->enc_hw_wq);
+ master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME,
+ WQ_MEM_RECLAIM
+ | WQ_FREEZABLE);
+ if (!master_dev->workqueue)
+ return -EINVAL;
+ }
+
+ atomic_set(&master_dev->enchw_rdy, MTK_JPEGENC_HW_MAX);
+ spin_lock_init(&dev->hw_lock);
+ dev->hw_state = MTK_JPEG_HW_IDLE;
+
+ INIT_DELAYED_WORK(&dev->job_timeout_work,
+ mtk_jpegenc_timeout_work);
+
+ jpegenc_clk = &dev->venc_clk;
+
+ jpegenc_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev,
+ &jpegenc_clk->clks);
+ if (jpegenc_clk->clk_num < 0)
+ return dev_err_probe(&pdev->dev, jpegenc_clk->clk_num,
+ "Failed to get jpegenc clock count\n");
+
+ dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dev->reg_base))
+ return PTR_ERR(dev->reg_base);
+
+ ret = mtk_jpegenc_hw_init_irq(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
+ if (master_dev->enc_hw_dev[i])
+ continue;
+
+ master_dev->enc_hw_dev[i] = dev;
+ master_dev->reg_encbase[i] = dev->reg_base;
+ dev->master_dev = master_dev;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver mtk_jpegenc_hw_driver = {
+ .probe = mtk_jpegenc_hw_probe,
+ .driver = {
+ .name = "mtk-jpegenc-hw",
+ .of_match_table = of_match_ptr(mtk_jpegenc_drv_ids),
+ },
+};
+
+module_platform_driver(mtk_jpegenc_hw_driver);
+
+MODULE_DESCRIPTION("MediaTek JPEG encode HW driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_comp.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_comp.c
index 1e3833f1c9ae..ad5fab2d8bfa 100644
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_comp.c
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_comp.c
@@ -52,9 +52,8 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
comp->clk[i] = of_clk_get(node, i);
if (IS_ERR(comp->clk[i])) {
- if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER)
- dev_err(dev, "Failed to get clock\n");
- ret = PTR_ERR(comp->clk[i]);
+ ret = dev_err_probe(dev, PTR_ERR(comp->clk[i]),
+ "Failed to get clock\n");
goto put_dev;
}
diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig
index 50ae07b75b5f..846e759a8f6a 100644
--- a/drivers/media/platform/mediatek/mdp3/Kconfig
+++ b/drivers/media/platform/mediatek/mdp3/Kconfig
@@ -9,7 +9,6 @@ config VIDEO_MEDIATEK_MDP3
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select MTK_MMSYS
- select VIDEO_MEDIATEK_VPU
select MTK_CMDQ
select MTK_SCP
default n
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
index 3e66ebaee2da..c7f231f8ea3e 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
@@ -51,14 +51,14 @@ struct img_sw_addr {
struct img_plane_format {
u32 size;
- u16 stride;
+ u32 stride;
} __packed;
struct img_pix_format {
- u16 width;
- u16 height;
+ u32 width;
+ u32 height;
u32 colorformat; /* enum mdp_color */
- u16 ycbcr_prof; /* enum mdp_ycbcr_profile */
+ u32 ycbcr_prof; /* enum mdp_ycbcr_profile */
struct img_plane_format plane_fmt[IMG_MAX_PLANES];
} __packed;
@@ -72,10 +72,10 @@ struct img_image_buffer {
#define IMG_SUBPIXEL_SHIFT 20
struct img_crop {
- s16 left;
- s16 top;
- u16 width;
- u16 height;
+ s32 left;
+ s32 top;
+ u32 width;
+ u32 height;
u32 left_subpix;
u32 top_subpix;
u32 width_subpix;
@@ -90,24 +90,24 @@ struct img_crop {
struct img_input {
struct img_image_buffer buffer;
- u16 flags; /* HDR, DRE, dither */
+ u32 flags; /* HDR, DRE, dither */
} __packed;
struct img_output {
struct img_image_buffer buffer;
struct img_crop crop;
- s16 rotation;
- u16 flags; /* H-flip, sharpness, dither */
+ s32 rotation;
+ u32 flags; /* H-flip, sharpness, dither */
} __packed;
struct img_ipi_frameparam {
u32 index;
u32 frame_no;
struct img_timeval timestamp;
- u8 type; /* enum mdp_stream_type */
- u8 state;
- u8 num_inputs;
- u8 num_outputs;
+ u32 type; /* enum mdp_stream_type */
+ u32 state;
+ u32 num_inputs;
+ u32 num_outputs;
u64 drv_data;
struct img_input inputs[IMG_MAX_HW_INPUTS];
struct img_output outputs[IMG_MAX_HW_OUTPUTS];
@@ -123,51 +123,51 @@ struct img_sw_buffer {
} __packed;
struct img_ipi_param {
- u8 usage;
+ u32 usage;
struct img_sw_buffer frm_param;
} __packed;
struct img_frameparam {
struct list_head list_entry;
struct img_ipi_frameparam frameparam;
-};
+} __packed;
/* ISP-MDP generic output information */
struct img_comp_frame {
- u32 output_disable:1;
- u32 bypass:1;
- u16 in_width;
- u16 in_height;
- u16 out_width;
- u16 out_height;
+ u32 output_disable;
+ u32 bypass;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
struct img_crop crop;
- u16 in_total_width;
- u16 out_total_width;
+ u32 in_total_width;
+ u32 out_total_width;
} __packed;
struct img_region {
- s16 left;
- s16 right;
- s16 top;
- s16 bottom;
+ s32 left;
+ s32 right;
+ s32 top;
+ s32 bottom;
} __packed;
struct img_offset {
- s16 left;
- s16 top;
+ s32 left;
+ s32 top;
u32 left_subpix;
u32 top_subpix;
} __packed;
struct img_comp_subfrm {
- u32 tile_disable:1;
+ u32 tile_disable;
struct img_region in;
struct img_region out;
struct img_offset luma;
struct img_offset chroma;
- s16 out_vertical; /* Output vertical index */
- s16 out_horizontal; /* Output horizontal index */
+ s32 out_vertical; /* Output vertical index */
+ s32 out_horizontal; /* Output horizontal index */
} __packed;
#define IMG_MAX_SUBFRAMES 14
@@ -250,8 +250,8 @@ struct isp_data {
} __packed;
struct img_compparam {
- u16 type; /* enum mdp_comp_type */
- u16 id; /* enum mtk_mdp_comp_id */
+ u32 type; /* enum mdp_comp_id */
+ u32 id; /* engine alias_id */
u32 input;
u32 outputs[IMG_MAX_HW_OUTPUTS];
u32 num_outputs;
@@ -273,12 +273,12 @@ struct img_mux {
u32 reg;
u32 value;
u32 subsys_id;
-};
+} __packed;
struct img_mmsys_ctrl {
struct img_mux sets[IMG_MAX_COMPONENTS * 2];
u32 num_sets;
-};
+} __packed;
struct img_config {
struct img_compparam components[IMG_MAX_COMPONENTS];
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
index 86c054600a08..124c1b96e96b 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
@@ -252,10 +252,9 @@ static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
dma_addr_t dma_addr;
pkt->va_base = kzalloc(size, GFP_KERNEL);
- if (!pkt->va_base) {
- kfree(pkt);
+ if (!pkt->va_base)
return -ENOMEM;
- }
+
pkt->buf_size = size;
pkt->cl = (void *)client;
@@ -368,25 +367,30 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_cancel_job;
}
- if (mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K)) {
- ret = -ENOMEM;
- goto err_cmdq_data;
- }
+ ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
+ if (ret)
+ goto err_free_cmd;
comps = kcalloc(param->config->num_components, sizeof(*comps),
GFP_KERNEL);
if (!comps) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_destroy_pkt;
}
path = kzalloc(sizeof(*path), GFP_KERNEL);
if (!path) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_free_comps;
+ }
+
+ ret = mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ if (ret) {
+ dev_err(dev, "Fail to enable mutex clk\n");
+ goto err_free_path;
}
path->mdp_dev = mdp;
@@ -406,15 +410,13 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
ret = mdp_path_ctx_init(mdp, path);
if (ret) {
dev_err(dev, "mdp_path_ctx_init error\n");
- goto err_cmdq_data;
+ goto err_free_path;
}
- mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
-
ret = mdp_path_config(mdp, cmd, path);
if (ret) {
dev_err(dev, "mdp_path_config error\n");
- goto err_cmdq_data;
+ goto err_free_path;
}
cmdq_pkt_finalize(&cmd->pkt);
@@ -431,10 +433,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cmd->mdp_ctx = param->mdp_ctx;
ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
- if (ret) {
- dev_err(dev, "comp %d failed to enable clock!\n", ret);
- goto err_clock_off;
- }
+ if (ret)
+ goto err_free_path;
dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
@@ -450,17 +450,20 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
return 0;
err_clock_off:
- mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
-err_cmdq_data:
+err_free_path:
+ mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
kfree(path);
- atomic_dec(&mdp->job_count);
- wake_up(&mdp->callback_wq);
- if (cmd && cmd->pkt.buf_size > 0)
- mdp_cmdq_pkt_destroy(&cmd->pkt);
+err_free_comps:
kfree(comps);
+err_destroy_pkt:
+ mdp_cmdq_pkt_destroy(&cmd->pkt);
+err_free_cmd:
kfree(cmd);
+err_cancel_job:
+ atomic_dec(&mdp->job_count);
+
return ret;
}
EXPORT_SYMBOL_GPL(mdp_cmdq_send);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
index d3eaf8884412..7bc05f42a23c 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
@@ -699,12 +699,22 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
dev_err(dev,
"Failed to enable clk %d. type:%d id:%d\n",
i, comp->type, comp->id);
- pm_runtime_put(comp->comp_dev);
- return ret;
+ goto err_revert;
}
}
return 0;
+
+err_revert:
+ while (--i >= 0) {
+ if (IS_ERR_OR_NULL(comp->clks[i]))
+ continue;
+ clk_disable_unprepare(comp->clks[i]);
+ }
+ if (comp->comp_dev)
+ pm_runtime_put_sync(comp->comp_dev);
+
+ return ret;
}
void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
@@ -723,11 +733,13 @@ void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num)
{
- int i;
+ int i, ret;
- for (i = 0; i < num; i++)
- if (mdp_comp_clock_on(dev, &comps[i]) != 0)
- return ++i;
+ for (i = 0; i < num; i++) {
+ ret = mdp_comp_clock_on(dev, &comps[i]);
+ if (ret)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index c413e59d4286..2d1f6ae9f080 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -196,27 +196,27 @@ static int mdp_probe(struct platform_device *pdev)
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS);
if (!mm_pdev) {
ret = -ENODEV;
- goto err_return;
+ goto err_destroy_device;
}
mdp->mdp_mmsys = &mm_pdev->dev;
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX);
if (WARN_ON(!mm_pdev)) {
ret = -ENODEV;
- goto err_return;
+ goto err_destroy_device;
}
for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
if (!mdp->mdp_mutex[i]) {
ret = -ENODEV;
- goto err_return;
+ goto err_free_mutex;
}
}
ret = mdp_comp_config(mdp);
if (ret) {
dev_err(dev, "Failed to config mdp components\n");
- goto err_return;
+ goto err_free_mutex;
}
mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
@@ -287,11 +287,12 @@ err_destroy_job_wq:
destroy_workqueue(mdp->job_wq);
err_deinit_comp:
mdp_comp_destroy(mdp);
-err_return:
+err_free_mutex:
for (i = 0; i < MDP_PIPE_MAX; i++)
- if (mdp)
- mtk_mutex_put(mdp->mdp_mutex[i]);
+ mtk_mutex_put(mdp->mdp_mutex[i]);
+err_destroy_device:
kfree(mdp);
+err_return:
dev_dbg(dev, "Errno %d\n", ret);
return ret;
}
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
index c45bd2599bb2..ffbcee04dc26 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
@@ -138,10 +138,13 @@ static void mtk_vdec_stateless_cap_to_disp(struct mtk_vcodec_ctx *ctx, int error
state = VB2_BUF_STATE_DONE;
vb2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
- v4l2_m2m_buf_done(vb2_dst, state);
-
- mtk_v4l2_debug(2, "free frame buffer id:%d to done list",
- vb2_dst->vb2_buf.index);
+ if (vb2_dst) {
+ v4l2_m2m_buf_done(vb2_dst, state);
+ mtk_v4l2_debug(2, "free frame buffer id:%d to done list",
+ vb2_dst->vb2_buf.index);
+ } else {
+ mtk_v4l2_err("dst buffer is NULL");
+ }
if (src_buf_req)
v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
@@ -250,7 +253,7 @@ static void mtk_vdec_worker(struct work_struct *work)
state = ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE;
if (!IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch) ||
- ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME || ret) {
+ ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME) {
v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, state);
if (src_buf_req)
v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
index d810a78dde51..d65800a3b89d 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
@@ -1397,7 +1397,10 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
- 0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
+ ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
h264_max_level,
0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
index 4cc92700692b..955b2d0c8f53 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
@@ -471,14 +471,19 @@ static int vdec_h264_slice_core_decode(struct vdec_lat_buf *lat_buf)
sizeof(share_info->h264_slice_params));
fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx);
- y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
- vdec_fb_va = (unsigned long)fb;
+ if (!fb) {
+ err = -EBUSY;
+ mtk_vcodec_err(inst, "fb buffer is NULL");
+ goto vdec_dec_end;
+ }
+ vdec_fb_va = (unsigned long)fb;
+ y_fb_dma = (u64)fb->base_y.dma_addr;
if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1)
c_fb_dma =
y_fb_dma + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h;
else
- c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+ c_fb_dma = (u64)fb->base_c.dma_addr;
mtk_vcodec_debug(inst, "[h264-core] y/c addr = 0x%llx 0x%llx", y_fb_dma,
c_fb_dma);
@@ -539,6 +544,29 @@ vdec_dec_end:
return 0;
}
+static void vdec_h264_insert_startcode(struct mtk_vcodec_dev *vcodec_dev, unsigned char *buf,
+ size_t *bs_size, struct mtk_h264_pps_param *pps)
+{
+ struct device *dev = &vcodec_dev->plat_dev->dev;
+
+ /* Need to add pending data at the end of bitstream when bs_sz is small than
+ * 20 bytes for cavlc bitstream, or lat will decode fail. This pending data is
+ * useful for mt8192 and mt8195 platform.
+ *
+ * cavlc bitstream when entropy_coding_mode_flag is false.
+ */
+ if (pps->entropy_coding_mode_flag || *bs_size > 20 ||
+ !(of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec") ||
+ of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")))
+ return;
+
+ buf[*bs_size] = 0;
+ buf[*bs_size + 1] = 0;
+ buf[*bs_size + 2] = 1;
+ buf[*bs_size + 3] = 0xff;
+ (*bs_size) += 4;
+}
+
static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_fb *fb, bool *res_chg)
{
@@ -582,9 +610,6 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
}
inst->vsi->dec.nal_info = buf[nal_start_idx];
- inst->vsi->dec.bs_buf_addr = (u64)bs->dma_addr;
- inst->vsi->dec.bs_buf_size = bs->size;
-
lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req;
v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true);
@@ -592,6 +617,12 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
if (err)
goto err_free_fb_out;
+ vdec_h264_insert_startcode(inst->ctx->dev, buf, &bs->size,
+ &share_info->h264_slice_params.pps);
+
+ inst->vsi->dec.bs_buf_addr = (uint64_t)bs->dma_addr;
+ inst->vsi->dec.bs_buf_size = bs->size;
+
*res_chg = inst->resolution_changed;
if (inst->resolution_changed) {
mtk_vcodec_debug(inst, "- resolution changed -");
@@ -630,7 +661,7 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
err = vpu_dec_start(vpu, data, 2);
if (err) {
mtk_vcodec_debug(inst, "lat decode err: %d", err);
- goto err_scp_decode;
+ goto err_free_fb_out;
}
share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
@@ -647,12 +678,17 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
/* wait decoder done interrupt */
timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0);
+ if (timeout)
+ mtk_vcodec_err(inst, "lat decode timeout: pic_%d", inst->slice_dec_num);
inst->vsi->dec.timeout = !!timeout;
err = vpu_dec_end(vpu);
- if (err == SLICE_HEADER_FULL || timeout || err == TRANS_BUFFER_FULL) {
- err = -EINVAL;
- goto err_scp_decode;
+ if (err == SLICE_HEADER_FULL || err == TRANS_BUFFER_FULL) {
+ if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability))
+ vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
+ inst->slice_dec_num++;
+ mtk_vcodec_err(inst, "lat dec fail: pic_%d err:%d", inst->slice_dec_num, err);
+ return -EINVAL;
}
share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
@@ -669,10 +705,6 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
inst->slice_dec_num++;
return 0;
-
-err_scp_decode:
- if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability))
- vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
err_free_fb_out:
vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err);
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
index fb1c36a3592d..cbb6728b8a40 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
@@ -2073,21 +2073,23 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
return -EBUSY;
}
pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data;
- if (!pfc)
- return -EINVAL;
+ if (!pfc) {
+ ret = -EINVAL;
+ goto err_free_fb_out;
+ }
vsi = &pfc->vsi;
ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc);
if (ret) {
mtk_vcodec_err(instance, "Failed to setup VP9 lat ret %d\n", ret);
- return ret;
+ goto err_free_fb_out;
}
vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi);
ret = vpu_dec_start(&instance->vpu, NULL, 0);
if (ret) {
mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret);
- return ret;
+ goto err_free_fb_out;
}
if (instance->irq) {
@@ -2107,7 +2109,7 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
/* LAT trans full, no more UBE or decode timeout */
if (ret) {
mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret);
- return ret;
+ goto err_free_fb_out;
}
mtk_vcodec_debug(instance, "lat dma addr: 0x%lx 0x%lx\n",
@@ -2120,6 +2122,9 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
vdec_msg_queue_qbuf(&ctx->dev->msg_queue_core_ctx, lat_buf);
return 0;
+err_free_fb_out:
+ vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);
+ return ret;
}
static int vdec_vp9_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
index ae500980ad45..dc2004790a47 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
@@ -221,7 +221,7 @@ static void vdec_msg_queue_core_work(struct work_struct *work)
mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE);
vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);
- if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) {
+ if (!list_empty(&dev->msg_queue_core_ctx.ready_queue)) {
mtk_v4l2_debug(3, "re-schedule to decode for core: %d",
dev->msg_queue_core_ctx.ready_num);
queue_work(dev->core_workqueue, &msg_queue->core_work);
diff --git a/drivers/media/platform/microchip/Kconfig b/drivers/media/platform/microchip/Kconfig
new file mode 100644
index 000000000000..4734ecced029
--- /dev/null
+++ b/drivers/media/platform/microchip/Kconfig
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Microchip Technology, Inc. media platform drivers"
+
+config VIDEO_MICROCHIP_ISC
+ tristate "Microchip Image Sensor Controller (ISC) support"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && COMMON_CLK
+ depends on ARCH_AT91 || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP_MMIO
+ select V4L2_FWNODE
+ select VIDEO_MICROCHIP_ISC_BASE
+ help
+ This module makes the Microchip Image Sensor Controller available
+ as a v4l2 device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called microchip-isc.
+
+config VIDEO_MICROCHIP_XISC
+ tristate "Microchip eXtended Image Sensor Controller (XISC) support"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && COMMON_CLK
+ depends on ARCH_AT91 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP_MMIO
+ select V4L2_FWNODE
+ select VIDEO_MICROCHIP_ISC_BASE
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This module makes the Microchip eXtended Image Sensor Controller
+ available as a v4l2 device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called microchip-xisc.
+
+config VIDEO_MICROCHIP_ISC_BASE
+ tristate
+ default n
+ help
+ Microchip ISC and XISC common code base.
+
+config VIDEO_MICROCHIP_CSI2DC
+ tristate "Microchip CSI2 Demux Controller"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && COMMON_CLK && OF
+ depends on ARCH_AT91 || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ CSI2 Demux Controller driver. CSI2DC is a helper chip
+ that converts IDI interface byte stream to a parallel pixel stream.
+ It supports various RAW formats as input.
+
+ To compile this driver as a module, choose M here: the
+ module will be called microchip-csi2dc.
diff --git a/drivers/media/platform/microchip/Makefile b/drivers/media/platform/microchip/Makefile
new file mode 100644
index 000000000000..bd8d6e779c51
--- /dev/null
+++ b/drivers/media/platform/microchip/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+microchip-isc-objs = microchip-sama5d2-isc.o
+microchip-xisc-objs = microchip-sama7g5-isc.o
+microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o
+
+obj-$(CONFIG_VIDEO_MICROCHIP_ISC_BASE) += microchip-isc-common.o
+obj-$(CONFIG_VIDEO_MICROCHIP_ISC) += microchip-isc.o
+obj-$(CONFIG_VIDEO_MICROCHIP_XISC) += microchip-xisc.o
+obj-$(CONFIG_VIDEO_MICROCHIP_CSI2DC) += microchip-csi2dc.o
diff --git a/drivers/media/platform/atmel/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index d5b359f607ae..d5b359f607ae 100644
--- a/drivers/media/platform/atmel/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
new file mode 100644
index 000000000000..e2994d48f10c
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -0,0 +1,2040 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Microchip Image Sensor Controller (ISC) common driver base
+ *
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+#include <linux/atmel-isc-media.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+#define ISC_IS_FORMAT_RAW(mbus_code) \
+ (((mbus_code) & 0xf000) == 0x3000)
+
+#define ISC_IS_FORMAT_GREY(mbus_code) \
+ (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
+ (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
+
+static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ /* In here we set the v4l2 controls w.r.t. our pipeline config */
+ v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]);
+ v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]);
+ v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]);
+ v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]);
+
+ v4l2_ctrl_s_ctrl(isc->r_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_R]);
+ v4l2_ctrl_s_ctrl(isc->b_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_B]);
+ v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GR]);
+ v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]);
+}
+
+static inline void isc_update_awb_ctrls(struct isc_device *isc)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ /* In here we set our actual hw pipeline config */
+
+ regmap_write(isc->regmap, ISC_WB_O_RGR,
+ ((ctrls->offset[ISC_HIS_CFG_MODE_R])) |
+ ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
+ regmap_write(isc->regmap, ISC_WB_O_BGB,
+ ((ctrls->offset[ISC_HIS_CFG_MODE_B])) |
+ ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
+ regmap_write(isc->regmap, ISC_WB_G_RGR,
+ ctrls->gain[ISC_HIS_CFG_MODE_R] |
+ (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
+ regmap_write(isc->regmap, ISC_WB_G_BGB,
+ ctrls->gain[ISC_HIS_CFG_MODE_B] |
+ (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
+}
+
+static inline void isc_reset_awb_ctrls(struct isc_device *isc)
+{
+ unsigned int c;
+
+ for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ /* gains have a fixed point at 9 decimals */
+ isc->ctrls.gain[c] = 1 << 9;
+ /* offsets are in 2's complements */
+ isc->ctrls.offset[c] = 0;
+ }
+}
+
+static int isc_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct isc_device *isc = vb2_get_drv_priv(vq);
+ unsigned int size = isc->fmt.fmt.pix.sizeimage;
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static int isc_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size = isc->fmt.fmt.pix.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ vbuf->field = isc->fmt.fmt.pix.field;
+
+ return 0;
+}
+
+static void isc_crop_pfe(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 h, w;
+
+ h = isc->fmt.fmt.pix.height;
+ w = isc->fmt.fmt.pix.width;
+
+ /*
+ * In case the sensor is not RAW, it will output a pixel (12-16 bits)
+ * with two samples on the ISC Data bus (which is 8-12)
+ * ISC will count each sample, so, we need to multiply these values
+ * by two, to get the real number of samples for the required pixels.
+ */
+ if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
+ h <<= 1;
+ w <<= 1;
+ }
+
+ /*
+ * We limit the column/row count that the ISC will output according
+ * to the configured resolution that we want.
+ * This will avoid the situation where the sensor is misconfigured,
+ * sending more data, and the ISC will just take it and DMA to memory,
+ * causing corruption.
+ */
+ regmap_write(regmap, ISC_PFE_CFG1,
+ (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) |
+ (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK));
+
+ regmap_write(regmap, ISC_PFE_CFG2,
+ (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) |
+ (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK));
+
+ regmap_update_bits(regmap, ISC_PFE_CFG0,
+ ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
+ ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
+}
+
+static void isc_start_dma(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
+ u32 dctrl_dview;
+ dma_addr_t addr0;
+
+ addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
+ regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
+
+ switch (isc->config.fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+ addr0 + (sizeimage * 2) / 3);
+ regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+ addr0 + (sizeimage * 5) / 6);
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+ addr0 + sizeimage / 2);
+ regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+ addr0 + (sizeimage * 3) / 4);
+ break;
+ default:
+ break;
+ }
+
+ dctrl_dview = isc->config.dctrl_dview;
+
+ regmap_write(regmap, ISC_DCTRL + isc->offsets.dma,
+ dctrl_dview | ISC_DCTRL_IE_IS);
+ spin_lock(&isc->awb_lock);
+ regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
+ spin_unlock(&isc->awb_lock);
+}
+
+static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
+{
+ struct regmap *regmap = isc->regmap;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ u32 val, bay_cfg;
+ const u32 *gamma;
+ unsigned int i;
+
+ /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
+ for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
+ val = pipeline & BIT(i) ? 1 : 0;
+ regmap_field_write(isc->pipeline[i], val);
+ }
+
+ if (!pipeline)
+ return;
+
+ bay_cfg = isc->config.sd_format->cfa_baycfg;
+
+ regmap_write(regmap, ISC_WB_CFG, bay_cfg);
+ isc_update_awb_ctrls(isc);
+ isc_update_v4l2_ctrls(isc);
+
+ regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
+
+ gamma = &isc->gamma_table[ctrls->gamma_index][0];
+ regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+
+ isc->config_dpc(isc);
+ isc->config_csc(isc);
+ isc->config_cbc(isc);
+ isc->config_cc(isc);
+ isc->config_gam(isc);
+}
+
+static int isc_update_profile(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 sr;
+ int counter = 100;
+
+ regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
+
+ regmap_read(regmap, ISC_CTRLSR, &sr);
+ while ((sr & ISC_CTRL_UPPRO) && counter--) {
+ usleep_range(1000, 2000);
+ regmap_read(regmap, ISC_CTRLSR, &sr);
+ }
+
+ if (counter < 0) {
+ v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void isc_set_histogram(struct isc_device *isc, bool enable)
+{
+ struct regmap *regmap = isc->regmap;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ if (enable) {
+ regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
+ ISC_HIS_CFG_MODE_GR |
+ (isc->config.sd_format->cfa_baycfg
+ << ISC_HIS_CFG_BAYSEL_SHIFT) |
+ ISC_HIS_CFG_RAR);
+ regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
+ ISC_HIS_CTRL_EN);
+ regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
+ ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
+ isc_update_profile(isc);
+ regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+
+ ctrls->hist_stat = HIST_ENABLED;
+ } else {
+ regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
+ regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
+ ISC_HIS_CTRL_DIS);
+
+ ctrls->hist_stat = HIST_DISABLED;
+ }
+}
+
+static int isc_configure(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 pfe_cfg0, dcfg, mask, pipeline;
+ struct isc_subdev_entity *subdev = isc->current_subdev;
+
+ pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
+ pipeline = isc->config.bits_pipeline;
+
+ dcfg = isc->config.dcfg_imode | isc->dcfg;
+
+ pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
+ mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
+ ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
+ ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
+
+ regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
+
+ isc->config_rlp(isc);
+
+ regmap_write(regmap, ISC_DCFG + isc->offsets.dma, dcfg);
+
+ /* Set the pipeline */
+ isc_set_pipeline(isc, pipeline);
+
+ /*
+ * The current implemented histogram is available for RAW R, B, GB, GR
+ * channels. We need to check if sensor is outputting RAW BAYER
+ */
+ if (isc->ctrls.awb &&
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ isc_set_histogram(isc, true);
+ else
+ isc_set_histogram(isc, false);
+
+ /* Update profile */
+ return isc_update_profile(isc);
+}
+
+static int isc_prepare_streaming(struct vb2_queue *vq)
+{
+ struct isc_device *isc = vb2_get_drv_priv(vq);
+
+ return media_pipeline_start(isc->video_dev.entity.pads, &isc->mpipe);
+}
+
+static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct isc_device *isc = vb2_get_drv_priv(vq);
+ struct regmap *regmap = isc->regmap;
+ struct isc_buffer *buf;
+ unsigned long flags;
+ int ret;
+
+ /* Enable stream on the sub device */
+ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD) {
+ v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n",
+ ret);
+ goto err_start_stream;
+ }
+
+ ret = pm_runtime_resume_and_get(isc->dev);
+ if (ret < 0) {
+ v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
+ ret);
+ goto err_pm_get;
+ }
+
+ ret = isc_configure(isc);
+ if (unlikely(ret))
+ goto err_configure;
+
+ /* Enable DMA interrupt */
+ regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE);
+
+ spin_lock_irqsave(&isc->dma_queue_lock, flags);
+
+ isc->sequence = 0;
+ isc->stop = false;
+ reinit_completion(&isc->comp);
+
+ isc->cur_frm = list_first_entry(&isc->dma_queue,
+ struct isc_buffer, list);
+ list_del(&isc->cur_frm->list);
+
+ isc_crop_pfe(isc);
+ isc_start_dma(isc);
+
+ spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
+
+ /* if we streaming from RAW, we can do one-shot white balance adj */
+ if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ v4l2_ctrl_activate(isc->do_wb_ctrl, true);
+
+ return 0;
+
+err_configure:
+ pm_runtime_put_sync(isc->dev);
+err_pm_get:
+ v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
+
+err_start_stream:
+ spin_lock_irqsave(&isc->dma_queue_lock, flags);
+ list_for_each_entry(buf, &isc->dma_queue, list)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ INIT_LIST_HEAD(&isc->dma_queue);
+ spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
+
+ return ret;
+}
+
+static void isc_unprepare_streaming(struct vb2_queue *vq)
+{
+ struct isc_device *isc = vb2_get_drv_priv(vq);
+
+ /* Stop media pipeline */
+ media_pipeline_stop(isc->video_dev.entity.pads);
+}
+
+static void isc_stop_streaming(struct vb2_queue *vq)
+{
+ struct isc_device *isc = vb2_get_drv_priv(vq);
+ unsigned long flags;
+ struct isc_buffer *buf;
+ int ret;
+
+ mutex_lock(&isc->awb_mutex);
+ v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+
+ isc->stop = true;
+
+ /* Wait until the end of the current frame */
+ if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
+ v4l2_err(&isc->v4l2_dev,
+ "Timeout waiting for end of the capture\n");
+
+ mutex_unlock(&isc->awb_mutex);
+
+ /* Disable DMA interrupt */
+ regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
+
+ pm_runtime_put_sync(isc->dev);
+
+ /* Disable stream on the sub device */
+ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
+ if (ret && ret != -ENOIOCTLCMD)
+ v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
+
+ /* Release all active buffers */
+ spin_lock_irqsave(&isc->dma_queue_lock, flags);
+ if (unlikely(isc->cur_frm)) {
+ vb2_buffer_done(&isc->cur_frm->vb.vb2_buf,
+ VB2_BUF_STATE_ERROR);
+ isc->cur_frm = NULL;
+ }
+ list_for_each_entry(buf, &isc->dma_queue, list)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ INIT_LIST_HEAD(&isc->dma_queue);
+ spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
+}
+
+static void isc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb);
+ struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&isc->dma_queue_lock, flags);
+ if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
+ vb2_start_streaming_called(vb->vb2_queue)) {
+ isc->cur_frm = buf;
+ isc_start_dma(isc);
+ } else {
+ list_add_tail(&buf->list, &isc->dma_queue);
+ }
+ spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
+}
+
+static const struct vb2_ops isc_vb2_ops = {
+ .queue_setup = isc_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_prepare = isc_buffer_prepare,
+ .start_streaming = isc_start_streaming,
+ .stop_streaming = isc_stop_streaming,
+ .buf_queue = isc_buffer_queue,
+ .prepare_streaming = isc_prepare_streaming,
+ .unprepare_streaming = isc_unprepare_streaming,
+};
+
+static int isc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
+ strscpy(cap->card, "Microchip Image Sensor Controller", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", isc->v4l2_dev.name);
+
+ return 0;
+}
+
+static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct isc_device *isc = video_drvdata(file);
+ u32 index = f->index;
+ u32 i, supported_index = 0;
+ struct isc_format *fmt;
+
+ /*
+ * If we are not asked a specific mbus_code, we have to report all
+ * the formats that we can output.
+ */
+ if (!f->mbus_code) {
+ if (index >= isc->controller_formats_size)
+ return -EINVAL;
+
+ f->pixelformat = isc->controller_formats[index].fourcc;
+
+ return 0;
+ }
+
+ /*
+ * If a specific mbus_code is requested, check if we support
+ * this mbus_code as input for the ISC.
+ * If it's supported, then we report the corresponding pixelformat
+ * as first possible option for the ISC.
+ * E.g. mbus MEDIA_BUS_FMT_YUYV8_2X8 and report
+ * 'YUYV' (YUYV 4:2:2)
+ */
+ fmt = isc_find_format_by_code(isc, f->mbus_code, &i);
+ if (!fmt)
+ return -EINVAL;
+
+ if (!index) {
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+ }
+
+ supported_index++;
+
+ /* If the index is not raw, we don't have anymore formats to report */
+ if (!ISC_IS_FORMAT_RAW(f->mbus_code))
+ return -EINVAL;
+
+ /*
+ * We are asked for a specific mbus code, which is raw.
+ * We have to search through the formats we can convert to.
+ * We have to skip the raw formats, we cannot convert to raw.
+ * E.g. 'AR12' (16-bit ARGB 4-4-4-4), 'AR15' (16-bit ARGB 1-5-5-5), etc.
+ */
+ for (i = 0; i < isc->controller_formats_size; i++) {
+ if (isc->controller_formats[i].raw)
+ continue;
+ if (index == supported_index) {
+ f->pixelformat = isc->controller_formats[i].fourcc;
+ return 0;
+ }
+ supported_index++;
+ }
+
+ return -EINVAL;
+}
+
+static int isc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ *fmt = isc->fmt;
+
+ return 0;
+}
+
+/*
+ * Checks the current configured format, if ISC can output it,
+ * considering which type of format the ISC receives from the sensor
+ */
+static int isc_try_validate_formats(struct isc_device *isc)
+{
+ int ret;
+ bool bayer = false, yuv = false, rgb = false, grey = false;
+
+ /* all formats supported by the RLP module are OK */
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ ret = 0;
+ bayer = true;
+ break;
+
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ ret = 0;
+ yuv = true;
+ break;
+
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ case V4L2_PIX_FMT_ARGB444:
+ case V4L2_PIX_FMT_ARGB555:
+ ret = 0;
+ rgb = true;
+ break;
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y10:
+ case V4L2_PIX_FMT_Y16:
+ ret = 0;
+ grey = true;
+ break;
+ default:
+ /* any other different formats are not supported */
+ v4l2_err(&isc->v4l2_dev, "Requested unsupported format.\n");
+ ret = -EINVAL;
+ }
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
+ rgb, yuv, grey, bayer);
+
+ if (bayer &&
+ !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ v4l2_err(&isc->v4l2_dev, "Cannot output RAW if we do not receive RAW.\n");
+ return -EINVAL;
+ }
+
+ if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
+ !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
+ v4l2_err(&isc->v4l2_dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
+ return -EINVAL;
+ }
+
+ if ((rgb || bayer || yuv) &&
+ ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
+ v4l2_err(&isc->v4l2_dev, "Cannot convert GREY to another format.\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*
+ * Configures the RLP and DMA modules, depending on the output format
+ * configured for the ISC.
+ * If direct_dump == true, just dump raw data 8/16 bits depending on format.
+ */
+static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
+{
+ isc->try_config.rlp_cfg_mode = 0;
+
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 8;
+ isc->try_config.bpp_v4l2 = 8;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_ARGB444:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_ARGB555:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 32;
+ isc->try_config.bpp_v4l2 = 32;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
+ isc->try_config.bpp = 12;
+ isc->try_config.bpp_v4l2 = 8; /* only first plane */
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 8; /* only first plane */
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ case V4L2_PIX_FMT_GREY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 8;
+ isc->try_config.bpp_v4l2 = 8;
+ break;
+ case V4L2_PIX_FMT_Y16:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH;
+ fallthrough;
+ case V4L2_PIX_FMT_Y10:
+ isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ isc->try_config.bpp_v4l2 = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (direct_dump) {
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Configuring pipeline modules, depending on which format the ISC outputs
+ * and considering which format it has as input from the sensor.
+ */
+static int isc_try_configure_pipeline(struct isc_device *isc)
+{
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_ARGB555:
+ case V4L2_PIX_FMT_ARGB444:
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
+ CC_ENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
+ SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+ DPC_BLCENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y16:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ CBC_ENABLE | DPC_BLCENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ default:
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+ isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
+ else
+ isc->try_config.bits_pipeline = 0x0;
+ }
+
+ /* Tune the pipeline to product specific */
+ isc->adapt_pipeline(isc);
+
+ return 0;
+}
+
+static void isc_try_fse(struct isc_device *isc,
+ struct v4l2_subdev_state *sd_state)
+{
+ int ret;
+ struct v4l2_subdev_frame_size_enum fse = {};
+
+ /*
+ * If we do not know yet which format the subdev is using, we cannot
+ * do anything.
+ */
+ if (!isc->config.sd_format)
+ return;
+
+ fse.code = isc->try_config.sd_format->mbus_code;
+ fse.which = V4L2_SUBDEV_FORMAT_TRY;
+
+ ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
+ sd_state, &fse);
+ /*
+ * Attempt to obtain format size from subdev. If not available,
+ * just use the maximum ISC can receive.
+ */
+ if (ret) {
+ sd_state->pads->try_crop.width = isc->max_width;
+ sd_state->pads->try_crop.height = isc->max_height;
+ } else {
+ sd_state->pads->try_crop.width = fse.max_width;
+ sd_state->pads->try_crop.height = fse.max_height;
+ }
+}
+
+static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pixfmt = &f->fmt.pix;
+ unsigned int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ isc->try_config.fourcc = isc->controller_formats[0].fourcc;
+
+ /* find if the format requested is supported */
+ for (i = 0; i < isc->controller_formats_size; i++)
+ if (isc->controller_formats[i].fourcc == pixfmt->pixelformat) {
+ isc->try_config.fourcc = pixfmt->pixelformat;
+ break;
+ }
+
+ isc_try_configure_rlp_dma(isc, false);
+
+ /* Limit to Microchip ISC hardware capabilities */
+ v4l_bound_align_image(&pixfmt->width, 16, isc->max_width, 0,
+ &pixfmt->height, 16, isc->max_height, 0, 0);
+ /* If we did not find the requested format, we will fallback here */
+ pixfmt->pixelformat = isc->try_config.fourcc;
+ pixfmt->colorspace = V4L2_COLORSPACE_SRGB;
+ pixfmt->field = V4L2_FIELD_NONE;
+
+ pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp_v4l2) >> 3;
+ pixfmt->sizeimage = ((pixfmt->width * isc->try_config.bpp) >> 3) *
+ pixfmt->height;
+
+ isc->try_fmt = *f;
+
+ return 0;
+}
+
+static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
+{
+ isc_try_fmt(isc, f);
+
+ /* make the try configuration active */
+ isc->config = isc->try_config;
+ isc->fmt = isc->try_fmt;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev, "ISC set_fmt to %.4s @%dx%d\n",
+ (char *)&f->fmt.pix.pixelformat,
+ f->fmt.pix.width, f->fmt.pix.height);
+
+ return 0;
+}
+
+static int isc_validate(struct isc_device *isc)
+{
+ int ret;
+ int i;
+ struct isc_format *sd_fmt = NULL;
+ struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = isc->remote_pad,
+ };
+ struct v4l2_subdev_pad_config pad_cfg = {};
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg,
+ };
+
+ /* Get current format from subdev */
+ ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL,
+ &format);
+ if (ret)
+ return ret;
+
+ /* Identify the subdev's format configuration */
+ for (i = 0; i < isc->formats_list_size; i++)
+ if (isc->formats_list[i].mbus_code == format.format.code) {
+ sd_fmt = &isc->formats_list[i];
+ break;
+ }
+
+ /* Check if the format is not supported */
+ if (!sd_fmt) {
+ v4l2_err(&isc->v4l2_dev,
+ "Current subdevice is streaming a media bus code that is not supported 0x%x\n",
+ format.format.code);
+ return -EPIPE;
+ }
+
+ /* At this moment we know which format the subdev will use */
+ isc->try_config.sd_format = sd_fmt;
+
+ /* If the sensor is not RAW, we can only do a direct dump */
+ if (!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+ isc_try_configure_rlp_dma(isc, true);
+
+ /* Limit to Microchip ISC hardware capabilities */
+ v4l_bound_align_image(&format.format.width, 16, isc->max_width, 0,
+ &format.format.height, 16, isc->max_height, 0, 0);
+
+ /* Check if the frame size is the same. Otherwise we may overflow */
+ if (pixfmt->height != format.format.height ||
+ pixfmt->width != format.format.width) {
+ v4l2_err(&isc->v4l2_dev,
+ "ISC not configured with the proper frame size: %dx%d\n",
+ format.format.width, format.format.height);
+ return -EPIPE;
+ }
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "Identified subdev using format %.4s with %dx%d %d bpp\n",
+ (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
+ isc->try_config.bpp);
+
+ /* Reset and restart AWB if the subdevice changed the format */
+ if (isc->try_config.sd_format && isc->config.sd_format &&
+ isc->try_config.sd_format != isc->config.sd_format) {
+ isc->ctrls.hist_stat = HIST_INIT;
+ isc_reset_awb_ctrls(isc);
+ isc_update_v4l2_ctrls(isc);
+ }
+
+ /* Validate formats */
+ ret = isc_try_validate_formats(isc);
+ if (ret)
+ return ret;
+
+ /* Obtain frame sizes if possible to have crop requirements ready */
+ isc_try_fse(isc, &pad_state);
+
+ /* Configure ISC pipeline for the config */
+ ret = isc_try_configure_pipeline(isc);
+ if (ret)
+ return ret;
+
+ isc->config = isc->try_config;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n");
+
+ return 0;
+}
+
+static int isc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ if (vb2_is_busy(&isc->vb2_vidq))
+ return -EBUSY;
+
+ return isc_set_fmt(isc, f);
+}
+
+static int isc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ return isc_try_fmt(isc, f);
+}
+
+static int isc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = 0;
+ strscpy(inp->name, "Camera", sizeof(inp->name));
+
+ return 0;
+}
+
+static int isc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int isc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
+}
+
+static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct isc_device *isc = video_drvdata(file);
+
+ return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
+}
+
+static int isc_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct isc_device *isc = video_drvdata(file);
+ int ret = -EINVAL;
+ int i;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ for (i = 0; i < isc->controller_formats_size; i++)
+ if (isc->controller_formats[i].fourcc == fsize->pixel_format)
+ ret = 0;
+
+ if (ret)
+ return ret;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+
+ fsize->stepwise.min_width = 16;
+ fsize->stepwise.max_width = isc->max_width;
+ fsize->stepwise.min_height = 16;
+ fsize->stepwise.max_height = isc->max_height;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops isc_ioctl_ops = {
+ .vidioc_querycap = isc_querycap,
+ .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap,
+
+ .vidioc_enum_input = isc_enum_input,
+ .vidioc_g_input = isc_g_input,
+ .vidioc_s_input = isc_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_g_parm = isc_g_parm,
+ .vidioc_s_parm = isc_s_parm,
+ .vidioc_enum_framesizes = isc_enum_framesizes,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int isc_open(struct file *file)
+{
+ struct isc_device *isc = video_drvdata(file);
+ struct v4l2_subdev *sd = isc->current_subdev->sd;
+ int ret;
+
+ if (mutex_lock_interruptible(&isc->lock))
+ return -ERESTARTSYS;
+
+ ret = v4l2_fh_open(file);
+ if (ret < 0)
+ goto unlock;
+
+ if (!v4l2_fh_is_singular_file(file))
+ goto unlock;
+
+ ret = v4l2_subdev_call(sd, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ v4l2_fh_release(file);
+ goto unlock;
+ }
+
+ ret = isc_set_fmt(isc, &isc->fmt);
+ if (ret) {
+ v4l2_subdev_call(sd, core, s_power, 0);
+ v4l2_fh_release(file);
+ }
+
+unlock:
+ mutex_unlock(&isc->lock);
+ return ret;
+}
+
+static int isc_release(struct file *file)
+{
+ struct isc_device *isc = video_drvdata(file);
+ struct v4l2_subdev *sd = isc->current_subdev->sd;
+ bool fh_singular;
+ int ret;
+
+ mutex_lock(&isc->lock);
+
+ fh_singular = v4l2_fh_is_singular_file(file);
+
+ ret = _vb2_fop_release(file, NULL);
+
+ if (fh_singular)
+ v4l2_subdev_call(sd, core, s_power, 0);
+
+ mutex_unlock(&isc->lock);
+
+ return ret;
+}
+
+static const struct v4l2_file_operations isc_fops = {
+ .owner = THIS_MODULE,
+ .open = isc_open,
+ .release = isc_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
+irqreturn_t microchip_isc_interrupt(int irq, void *dev_id)
+{
+ struct isc_device *isc = (struct isc_device *)dev_id;
+ struct regmap *regmap = isc->regmap;
+ u32 isc_intsr, isc_intmask, pending;
+ irqreturn_t ret = IRQ_NONE;
+
+ regmap_read(regmap, ISC_INTSR, &isc_intsr);
+ regmap_read(regmap, ISC_INTMASK, &isc_intmask);
+
+ pending = isc_intsr & isc_intmask;
+
+ if (likely(pending & ISC_INT_DDONE)) {
+ spin_lock(&isc->dma_queue_lock);
+ if (isc->cur_frm) {
+ struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
+ struct vb2_buffer *vb = &vbuf->vb2_buf;
+
+ vb->timestamp = ktime_get_ns();
+ vbuf->sequence = isc->sequence++;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ isc->cur_frm = NULL;
+ }
+
+ if (!list_empty(&isc->dma_queue) && !isc->stop) {
+ isc->cur_frm = list_first_entry(&isc->dma_queue,
+ struct isc_buffer, list);
+ list_del(&isc->cur_frm->list);
+
+ isc_start_dma(isc);
+ }
+
+ if (isc->stop)
+ complete(&isc->comp);
+
+ ret = IRQ_HANDLED;
+ spin_unlock(&isc->dma_queue_lock);
+ }
+
+ if (pending & ISC_INT_HISDONE) {
+ schedule_work(&isc->awb_work);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(microchip_isc_interrupt);
+
+static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
+{
+ struct regmap *regmap = isc->regmap;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
+ u32 *hist_entry = &ctrls->hist_entry[0];
+ u32 i;
+
+ *min = 0;
+ *max = HIST_ENTRIES;
+
+ regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
+ hist_entry, HIST_ENTRIES);
+
+ *hist_count = 0;
+ /*
+ * we deliberately ignore the end of the histogram,
+ * the most white pixels
+ */
+ for (i = 1; i < HIST_ENTRIES; i++) {
+ if (*hist_entry && !*min)
+ *min = i;
+ if (*hist_entry)
+ *max = i;
+ *hist_count += i * (*hist_entry++);
+ }
+
+ if (!*min)
+ *min = 1;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "isc wb: hist_id %u, hist_count %u",
+ ctrls->hist_id, *hist_count);
+}
+
+static void isc_wb_update(struct isc_ctrls *ctrls)
+{
+ struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
+ u32 *hist_count = &ctrls->hist_count[0];
+ u32 c, offset[4];
+ u64 avg = 0;
+ /* We compute two gains, stretch gain and grey world gain */
+ u32 s_gain[4], gw_gain[4];
+
+ /*
+ * According to Grey World, we need to set gains for R/B to normalize
+ * them towards the green channel.
+ * Thus we want to keep Green as fixed and adjust only Red/Blue
+ * Compute the average of the both green channels first
+ */
+ avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
+ (u64)hist_count[ISC_HIS_CFG_MODE_GB];
+ avg >>= 1;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "isc wb: green components average %llu\n", avg);
+
+ /* Green histogram is null, nothing to do */
+ if (!avg)
+ return;
+
+ for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ /*
+ * the color offset is the minimum value of the histogram.
+ * we stretch this color to the full range by substracting
+ * this value from the color component.
+ */
+ offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ /*
+ * The offset is always at least 1. If the offset is 1, we do
+ * not need to adjust it, so our result must be zero.
+ * the offset is computed in a histogram on 9 bits (0..512)
+ * but the offset in register is based on
+ * 12 bits pipeline (0..4096).
+ * we need to shift with the 3 bits that the histogram is
+ * ignoring
+ */
+ ctrls->offset[c] = (offset[c] - 1) << 3;
+
+ /*
+ * the offset is then taken and converted to 2's complements,
+ * and must be negative, as we subtract this value from the
+ * color components
+ */
+ ctrls->offset[c] = -ctrls->offset[c];
+
+ /*
+ * the stretch gain is the total number of histogram bins
+ * divided by the actual range of color component (Max - Min)
+ * If we compute gain like this, the actual color component
+ * will be stretched to the full histogram.
+ * We need to shift 9 bits for precision, we have 9 bits for
+ * decimals
+ */
+ s_gain[c] = (HIST_ENTRIES << 9) /
+ (ctrls->hist_minmax[c][HIST_MAX_INDEX] -
+ ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
+
+ /*
+ * Now we have to compute the gain w.r.t. the average.
+ * Add/lose gain to the component towards the average.
+ * If it happens that the component is zero, use the
+ * fixed point value : 1.0 gain.
+ */
+ if (hist_count[c])
+ gw_gain[c] = div_u64(avg << 9, hist_count[c]);
+ else
+ gw_gain[c] = 1 << 9;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "isc wb: component %d, s_gain %u, gw_gain %u\n",
+ c, s_gain[c], gw_gain[c]);
+ /* multiply both gains and adjust for decimals */
+ ctrls->gain[c] = s_gain[c] * gw_gain[c];
+ ctrls->gain[c] >>= 9;
+
+ /* make sure we are not out of range */
+ ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "isc wb: component %d, final gain %u\n",
+ c, ctrls->gain[c]);
+ }
+}
+
+static void isc_awb_work(struct work_struct *w)
+{
+ struct isc_device *isc =
+ container_of(w, struct isc_device, awb_work);
+ struct regmap *regmap = isc->regmap;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ u32 hist_id = ctrls->hist_id;
+ u32 baysel;
+ unsigned long flags;
+ u32 min, max;
+ int ret;
+
+ if (ctrls->hist_stat != HIST_ENABLED)
+ return;
+
+ isc_hist_count(isc, &min, &max);
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
+
+ ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
+ ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
+
+ if (hist_id != ISC_HIS_CFG_MODE_B) {
+ hist_id++;
+ } else {
+ isc_wb_update(ctrls);
+ hist_id = ISC_HIS_CFG_MODE_GR;
+ }
+
+ ctrls->hist_id = hist_id;
+ baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
+
+ ret = pm_runtime_resume_and_get(isc->dev);
+ if (ret < 0)
+ return;
+
+ /*
+ * only update if we have all the required histograms and controls
+ * if awb has been disabled, we need to reset registers as well.
+ */
+ if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
+ /*
+ * It may happen that DMA Done IRQ will trigger while we are
+ * updating white balance registers here.
+ * In that case, only parts of the controls have been updated.
+ * We can avoid that by locking the section.
+ */
+ spin_lock_irqsave(&isc->awb_lock, flags);
+ isc_update_awb_ctrls(isc);
+ spin_unlock_irqrestore(&isc->awb_lock, flags);
+
+ /*
+ * if we are doing just the one time white balance adjustment,
+ * we are basically done.
+ */
+ if (ctrls->awb == ISC_WB_ONETIME) {
+ v4l2_info(&isc->v4l2_dev,
+ "Completed one time white-balance adjustment.\n");
+ /* update the v4l2 controls values */
+ isc_update_v4l2_ctrls(isc);
+ ctrls->awb = ISC_WB_NONE;
+ }
+ }
+ regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
+ hist_id | baysel | ISC_HIS_CFG_RAR);
+
+ /*
+ * We have to make sure the streaming has not stopped meanwhile.
+ * ISC requires a frame to clock the internal profile update.
+ * To avoid issues, lock the sequence with a mutex
+ */
+ mutex_lock(&isc->awb_mutex);
+
+ /* streaming is not active anymore */
+ if (isc->stop) {
+ mutex_unlock(&isc->awb_mutex);
+ return;
+ }
+
+ isc_update_profile(isc);
+
+ mutex_unlock(&isc->awb_mutex);
+
+ /* if awb has been disabled, we don't need to start another histogram */
+ if (ctrls->awb)
+ regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+
+ pm_runtime_put_sync(isc->dev);
+}
+
+static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
+ break;
+ case V4L2_CID_GAMMA:
+ ctrls->gamma_index = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_ctrl_ops = {
+ .s_ctrl = isc_s_ctrl,
+};
+
+static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ if (ctrl->val == 1)
+ ctrls->awb = ISC_WB_AUTO;
+ else
+ ctrls->awb = ISC_WB_NONE;
+
+ /* configure the controls with new values from v4l2 */
+ if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
+ ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new)
+ ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new)
+ ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new)
+ ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val;
+
+ if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new)
+ ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new)
+ ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new)
+ ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val;
+ if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new)
+ ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val;
+
+ isc_update_awb_ctrls(isc);
+
+ mutex_lock(&isc->awb_mutex);
+ if (vb2_is_streaming(&isc->vb2_vidq)) {
+ /*
+ * If we are streaming, we can update profile to
+ * have the new settings in place.
+ */
+ isc_update_profile(isc);
+ } else {
+ /*
+ * The auto cluster will activate automatically this
+ * control. This has to be deactivated when not
+ * streaming.
+ */
+ v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+ }
+ mutex_unlock(&isc->awb_mutex);
+
+ /* if we have autowhitebalance on, start histogram procedure */
+ if (ctrls->awb == ISC_WB_AUTO &&
+ vb2_is_streaming(&isc->vb2_vidq) &&
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ isc_set_histogram(isc, true);
+
+ /*
+ * for one time whitebalance adjustment, check the button,
+ * if it's pressed, perform the one time operation.
+ */
+ if (ctrls->awb == ISC_WB_NONE &&
+ ctrl->cluster[ISC_CTRL_DO_WB]->is_new &&
+ !(ctrl->cluster[ISC_CTRL_DO_WB]->flags &
+ V4L2_CTRL_FLAG_INACTIVE)) {
+ ctrls->awb = ISC_WB_ONETIME;
+ isc_set_histogram(isc, true);
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "One time white-balance started.\n");
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ switch (ctrl->id) {
+ /* being a cluster, this id will be called for every control */
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->cluster[ISC_CTRL_R_GAIN]->val =
+ ctrls->gain[ISC_HIS_CFG_MODE_R];
+ ctrl->cluster[ISC_CTRL_B_GAIN]->val =
+ ctrls->gain[ISC_HIS_CFG_MODE_B];
+ ctrl->cluster[ISC_CTRL_GR_GAIN]->val =
+ ctrls->gain[ISC_HIS_CFG_MODE_GR];
+ ctrl->cluster[ISC_CTRL_GB_GAIN]->val =
+ ctrls->gain[ISC_HIS_CFG_MODE_GB];
+
+ ctrl->cluster[ISC_CTRL_R_OFF]->val =
+ ctrls->offset[ISC_HIS_CFG_MODE_R];
+ ctrl->cluster[ISC_CTRL_B_OFF]->val =
+ ctrls->offset[ISC_HIS_CFG_MODE_B];
+ ctrl->cluster[ISC_CTRL_GR_OFF]->val =
+ ctrls->offset[ISC_HIS_CFG_MODE_GR];
+ ctrl->cluster[ISC_CTRL_GB_OFF]->val =
+ ctrls->offset[ISC_HIS_CFG_MODE_GB];
+ break;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_awb_ops = {
+ .s_ctrl = isc_s_awb_ctrl,
+ .g_volatile_ctrl = isc_g_volatile_awb_ctrl,
+};
+
+#define ISC_CTRL_OFF(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_awb_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER, \
+ .min = -4095, \
+ .max = 4095, \
+ .step = 1, \
+ .def = 0, \
+ }
+
+ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
+ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
+ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
+ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset");
+
+#define ISC_CTRL_GAIN(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_awb_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER, \
+ .min = 0, \
+ .max = 8191, \
+ .step = 1, \
+ .def = 512, \
+ }
+
+ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
+ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
+ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
+ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
+
+static int isc_ctrl_init(struct isc_device *isc)
+{
+ const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int ret;
+
+ ctrls->hist_stat = HIST_INIT;
+ isc_reset_awb_ctrls(isc);
+
+ ret = v4l2_ctrl_handler_init(hdl, 13);
+ if (ret < 0)
+ return ret;
+
+ /* Initialize product specific controls. For example, contrast */
+ isc->config_ctrls(isc, ops);
+
+ ctrls->brightness = 0;
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
+ isc->gamma_max);
+ isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+
+ /* do_white_balance is a button, so min,max,step,default are ignored */
+ isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
+ V4L2_CID_DO_WHITE_BALANCE,
+ 0, 0, 0, 0);
+
+ if (!isc->do_wb_ctrl) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+
+ isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
+ isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
+ isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL);
+ isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL);
+ isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL);
+ isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL);
+ isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
+ isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+
+ /*
+ * The cluster is in auto mode with autowhitebalance enabled
+ * and manual mode otherwise.
+ */
+ v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true);
+
+ v4l2_ctrl_handler_setup(hdl);
+
+ return 0;
+}
+
+static int isc_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct isc_device *isc = container_of(notifier->v4l2_dev,
+ struct isc_device, v4l2_dev);
+ struct isc_subdev_entity *subdev_entity =
+ container_of(notifier, struct isc_subdev_entity, notifier);
+ int pad;
+
+ if (video_is_registered(&isc->video_dev)) {
+ v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
+ return -EBUSY;
+ }
+
+ subdev_entity->sd = subdev;
+
+ pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (pad < 0) {
+ v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n",
+ subdev->name);
+ return pad;
+ }
+
+ isc->remote_pad = pad;
+
+ return 0;
+}
+
+static void isc_async_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct isc_device *isc = container_of(notifier->v4l2_dev,
+ struct isc_device, v4l2_dev);
+ mutex_destroy(&isc->awb_mutex);
+ cancel_work_sync(&isc->awb_work);
+ video_unregister_device(&isc->video_dev);
+ v4l2_ctrl_handler_free(&isc->ctrls.handler);
+}
+
+struct isc_format *isc_find_format_by_code(struct isc_device *isc,
+ unsigned int code, int *index)
+{
+ struct isc_format *fmt = &isc->formats_list[0];
+ unsigned int i;
+
+ for (i = 0; i < isc->formats_list_size; i++) {
+ if (fmt->mbus_code == code) {
+ *index = i;
+ return fmt;
+ }
+
+ fmt++;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(isc_find_format_by_code);
+
+static int isc_set_default_fmt(struct isc_device *isc)
+{
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .field = V4L2_FIELD_NONE,
+ .pixelformat = isc->controller_formats[0].fourcc,
+ },
+ };
+ int ret;
+
+ ret = isc_try_fmt(isc, &f);
+ if (ret)
+ return ret;
+
+ isc->fmt = f;
+ return 0;
+}
+
+static int isc_async_complete(struct v4l2_async_notifier *notifier)
+{
+ struct isc_device *isc = container_of(notifier->v4l2_dev,
+ struct isc_device, v4l2_dev);
+ struct video_device *vdev = &isc->video_dev;
+ struct vb2_queue *q = &isc->vb2_vidq;
+ int ret = 0;
+
+ INIT_WORK(&isc->awb_work, isc_awb_work);
+
+ ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
+ return ret;
+ }
+
+ isc->current_subdev = container_of(notifier,
+ struct isc_subdev_entity, notifier);
+ mutex_init(&isc->lock);
+ mutex_init(&isc->awb_mutex);
+
+ init_completion(&isc->comp);
+
+ /* Initialize videobuf2 queue */
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = isc;
+ q->buf_struct_size = sizeof(struct isc_buffer);
+ q->ops = &isc_vb2_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &isc->lock;
+ q->min_buffers_needed = 1;
+ q->dev = isc->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ v4l2_err(&isc->v4l2_dev,
+ "vb2_queue_init() failed: %d\n", ret);
+ goto isc_async_complete_err;
+ }
+
+ /* Init video dma queues */
+ INIT_LIST_HEAD(&isc->dma_queue);
+ spin_lock_init(&isc->dma_queue_lock);
+ spin_lock_init(&isc->awb_lock);
+
+ ret = isc_set_default_fmt(isc);
+ if (ret) {
+ v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
+ goto isc_async_complete_err;
+ }
+
+ ret = isc_ctrl_init(isc);
+ if (ret) {
+ v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
+ goto isc_async_complete_err;
+ }
+
+ /* Register video device */
+ strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
+ vdev->release = video_device_release_empty;
+ vdev->fops = &isc_fops;
+ vdev->ioctl_ops = &isc_ioctl_ops;
+ vdev->v4l2_dev = &isc->v4l2_dev;
+ vdev->vfl_dir = VFL_DIR_RX;
+ vdev->queue = q;
+ vdev->lock = &isc->lock;
+ vdev->ctrl_handler = &isc->ctrls.handler;
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_IO_MC;
+ video_set_drvdata(vdev, isc);
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret < 0) {
+ v4l2_err(&isc->v4l2_dev,
+ "video_register_device failed: %d\n", ret);
+ goto isc_async_complete_err;
+ }
+
+ ret = isc_scaler_link(isc);
+ if (ret < 0)
+ goto isc_async_complete_unregister_device;
+
+ ret = media_device_register(&isc->mdev);
+ if (ret < 0)
+ goto isc_async_complete_unregister_device;
+
+ return 0;
+
+isc_async_complete_unregister_device:
+ video_unregister_device(vdev);
+
+isc_async_complete_err:
+ mutex_destroy(&isc->awb_mutex);
+ mutex_destroy(&isc->lock);
+ return ret;
+}
+
+const struct v4l2_async_notifier_operations microchip_isc_async_ops = {
+ .bound = isc_async_bound,
+ .unbind = isc_async_unbind,
+ .complete = isc_async_complete,
+};
+EXPORT_SYMBOL_GPL(microchip_isc_async_ops);
+
+void microchip_isc_subdev_cleanup(struct isc_device *isc)
+{
+ struct isc_subdev_entity *subdev_entity;
+
+ list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
+ v4l2_async_nf_unregister(&subdev_entity->notifier);
+ v4l2_async_nf_cleanup(&subdev_entity->notifier);
+ }
+
+ INIT_LIST_HEAD(&isc->subdev_entities);
+}
+EXPORT_SYMBOL_GPL(microchip_isc_subdev_cleanup);
+
+int microchip_isc_pipeline_init(struct isc_device *isc)
+{
+ struct device *dev = isc->dev;
+ struct regmap *regmap = isc->regmap;
+ struct regmap_field *regs;
+ unsigned int i;
+
+ /*
+ * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
+ * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
+ */
+ const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
+ REG_FIELD(ISC_DPC_CTRL, 0, 0),
+ REG_FIELD(ISC_DPC_CTRL, 1, 1),
+ REG_FIELD(ISC_DPC_CTRL, 2, 2),
+ REG_FIELD(ISC_WB_CTRL, 0, 0),
+ REG_FIELD(ISC_CFA_CTRL, 0, 0),
+ REG_FIELD(ISC_CC_CTRL, 0, 0),
+ REG_FIELD(ISC_GAM_CTRL, 0, 0),
+ REG_FIELD(ISC_GAM_CTRL, 1, 1),
+ REG_FIELD(ISC_GAM_CTRL, 2, 2),
+ REG_FIELD(ISC_GAM_CTRL, 3, 3),
+ REG_FIELD(ISC_VHXS_CTRL, 0, 0),
+ REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
+ REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
+ REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
+ REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
+ };
+
+ for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
+ regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ isc->pipeline[i] = regs;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init);
+
+static int isc_link_validate(struct media_link *link)
+{
+ struct video_device *vdev =
+ media_entity_to_video_device(link->sink->entity);
+ struct isc_device *isc = video_get_drvdata(vdev);
+ int ret;
+
+ ret = v4l2_subdev_link_validate(link);
+ if (ret)
+ return ret;
+
+ return isc_validate(isc);
+}
+
+static const struct media_entity_operations isc_entity_operations = {
+ .link_validate = isc_link_validate,
+};
+
+int isc_mc_init(struct isc_device *isc, u32 ver)
+{
+ const struct of_device_id *match;
+ int ret;
+
+ isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L;
+ isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT;
+ isc->video_dev.entity.ops = &isc_entity_operations;
+
+ isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+ ret = media_entity_pads_init(&isc->video_dev.entity, ISC_PADS_NUM,
+ isc->pads);
+ if (ret < 0) {
+ dev_err(isc->dev, "media entity init failed\n");
+ return ret;
+ }
+
+ isc->mdev.dev = isc->dev;
+
+ match = of_match_node(isc->dev->driver->of_match_table,
+ isc->dev->of_node);
+
+ strscpy(isc->mdev.driver_name, KBUILD_MODNAME,
+ sizeof(isc->mdev.driver_name));
+ strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model));
+ snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s",
+ isc->v4l2_dev.name);
+ isc->mdev.hw_revision = ver;
+
+ media_device_init(&isc->mdev);
+
+ isc->v4l2_dev.mdev = &isc->mdev;
+
+ return isc_scaler_init(isc);
+}
+EXPORT_SYMBOL_GPL(isc_mc_init);
+
+void isc_mc_cleanup(struct isc_device *isc)
+{
+ media_entity_cleanup(&isc->video_dev.entity);
+ media_device_cleanup(&isc->mdev);
+}
+EXPORT_SYMBOL_GPL(isc_mc_cleanup);
+
+/* regmap configuration */
+#define MICROCHIP_ISC_REG_MAX 0xd5c
+const struct regmap_config microchip_isc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = MICROCHIP_ISC_REG_MAX,
+};
+EXPORT_SYMBOL_GPL(microchip_isc_regmap_config);
+
+MODULE_AUTHOR("Songjun Wu");
+MODULE_AUTHOR("Eugen Hristev");
+MODULE_DESCRIPTION("Microchip ISC common code base");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/microchip/microchip-isc-clk.c b/drivers/media/platform/microchip/microchip-isc-clk.c
new file mode 100644
index 000000000000..24358d804e75
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc-clk.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Microchip Image Sensor Controller (ISC) common clock driver setup
+ *
+ * Copyright (C) 2016 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+static int isc_wait_clk_stable(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ struct regmap *regmap = isc_clk->regmap;
+ unsigned long timeout = jiffies + usecs_to_jiffies(1000);
+ unsigned int status;
+
+ while (time_before(jiffies, timeout)) {
+ regmap_read(regmap, ISC_CLKSR, &status);
+ if (!(status & ISC_CLKSR_SIP))
+ return 0;
+
+ usleep_range(10, 250);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int isc_clk_prepare(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(isc_clk->dev);
+ if (ret < 0)
+ return ret;
+
+ return isc_wait_clk_stable(hw);
+}
+
+static void isc_clk_unprepare(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+
+ isc_wait_clk_stable(hw);
+
+ pm_runtime_put_sync(isc_clk->dev);
+}
+
+static int isc_clk_enable(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ u32 id = isc_clk->id;
+ struct regmap *regmap = isc_clk->regmap;
+ unsigned long flags;
+ unsigned int status;
+
+ dev_dbg(isc_clk->dev, "ISC CLK: %s, id = %d, div = %d, parent id = %d\n",
+ __func__, id, isc_clk->div, isc_clk->parent_id);
+
+ spin_lock_irqsave(&isc_clk->lock, flags);
+ regmap_update_bits(regmap, ISC_CLKCFG,
+ ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id),
+ (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) |
+ (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id)));
+
+ regmap_write(regmap, ISC_CLKEN, ISC_CLK(id));
+ spin_unlock_irqrestore(&isc_clk->lock, flags);
+
+ regmap_read(regmap, ISC_CLKSR, &status);
+ if (status & ISC_CLK(id))
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static void isc_clk_disable(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ u32 id = isc_clk->id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isc_clk->lock, flags);
+ regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id));
+ spin_unlock_irqrestore(&isc_clk->lock, flags);
+}
+
+static int isc_clk_is_enabled(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ u32 status;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(isc_clk->dev);
+ if (ret < 0)
+ return 0;
+
+ regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
+
+ pm_runtime_put_sync(isc_clk->dev);
+
+ return status & ISC_CLK(isc_clk->id) ? 1 : 0;
+}
+
+static unsigned long
+isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+
+ return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1);
+}
+
+static int isc_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ long best_rate = -EINVAL;
+ int best_diff = -1;
+ unsigned int i, div;
+
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+ struct clk_hw *parent;
+ unsigned long parent_rate;
+
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
+
+ parent_rate = clk_hw_get_rate(parent);
+ if (!parent_rate)
+ continue;
+
+ for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) {
+ unsigned long rate;
+ int diff;
+
+ rate = DIV_ROUND_CLOSEST(parent_rate, div);
+ diff = abs(req->rate - rate);
+
+ if (best_diff < 0 || best_diff > diff) {
+ best_rate = rate;
+ best_diff = diff;
+ req->best_parent_rate = parent_rate;
+ req->best_parent_hw = parent;
+ }
+
+ if (!best_diff || rate < req->rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ dev_dbg(isc_clk->dev,
+ "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
+ __func__, best_rate,
+ __clk_get_name((req->best_parent_hw)->clk),
+ req->best_parent_rate);
+
+ if (best_rate < 0)
+ return best_rate;
+
+ req->rate = best_rate;
+
+ return 0;
+}
+
+static int isc_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+
+ if (index >= clk_hw_get_num_parents(hw))
+ return -EINVAL;
+
+ isc_clk->parent_id = index;
+
+ return 0;
+}
+
+static u8 isc_clk_get_parent(struct clk_hw *hw)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+
+ return isc_clk->parent_id;
+}
+
+static int isc_clk_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ u32 div;
+
+ if (!rate)
+ return -EINVAL;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if (div > (ISC_CLK_MAX_DIV + 1) || !div)
+ return -EINVAL;
+
+ isc_clk->div = div - 1;
+
+ return 0;
+}
+
+static const struct clk_ops isc_clk_ops = {
+ .prepare = isc_clk_prepare,
+ .unprepare = isc_clk_unprepare,
+ .enable = isc_clk_enable,
+ .disable = isc_clk_disable,
+ .is_enabled = isc_clk_is_enabled,
+ .recalc_rate = isc_clk_recalc_rate,
+ .determine_rate = isc_clk_determine_rate,
+ .set_parent = isc_clk_set_parent,
+ .get_parent = isc_clk_get_parent,
+ .set_rate = isc_clk_set_rate,
+};
+
+static int isc_clk_register(struct isc_device *isc, unsigned int id)
+{
+ struct regmap *regmap = isc->regmap;
+ struct device_node *np = isc->dev->of_node;
+ struct isc_clk *isc_clk;
+ struct clk_init_data init;
+ const char *clk_name = np->name;
+ const char *parent_names[3];
+ int num_parents;
+
+ if (id == ISC_ISPCK && !isc->ispck_required)
+ return 0;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents < 1 || num_parents > 3)
+ return -EINVAL;
+
+ if (num_parents > 2 && id == ISC_ISPCK)
+ num_parents = 2;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ if (id == ISC_MCK)
+ of_property_read_string(np, "clock-output-names", &clk_name);
+ else
+ clk_name = "isc-ispck";
+
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.name = clk_name;
+ init.ops = &isc_clk_ops;
+ init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+ isc_clk = &isc->isc_clks[id];
+ isc_clk->hw.init = &init;
+ isc_clk->regmap = regmap;
+ isc_clk->id = id;
+ isc_clk->dev = isc->dev;
+ spin_lock_init(&isc_clk->lock);
+
+ isc_clk->clk = clk_register(isc->dev, &isc_clk->hw);
+ if (IS_ERR(isc_clk->clk)) {
+ dev_err(isc->dev, "%s: clock register fail\n", clk_name);
+ return PTR_ERR(isc_clk->clk);
+ } else if (id == ISC_MCK) {
+ of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk);
+ }
+
+ return 0;
+}
+
+int microchip_isc_clk_init(struct isc_device *isc)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++)
+ isc->isc_clks[i].clk = ERR_PTR(-EINVAL);
+
+ for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
+ ret = isc_clk_register(isc, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(microchip_isc_clk_init);
+
+void microchip_isc_clk_cleanup(struct isc_device *isc)
+{
+ unsigned int i;
+
+ of_clk_del_provider(isc->dev->of_node);
+
+ for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
+ struct isc_clk *isc_clk = &isc->isc_clks[i];
+
+ if (!IS_ERR(isc_clk->clk))
+ clk_unregister(isc_clk->clk);
+ }
+}
+EXPORT_SYMBOL_GPL(microchip_isc_clk_cleanup);
diff --git a/drivers/media/platform/microchip/microchip-isc-regs.h b/drivers/media/platform/microchip/microchip-isc-regs.h
new file mode 100644
index 000000000000..e77e1d9a1db8
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc-regs.h
@@ -0,0 +1,413 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MICROCHIP_ISC_REGS_H
+#define __MICROCHIP_ISC_REGS_H
+
+#include <linux/bitops.h>
+
+/* ISC Control Enable Register 0 */
+#define ISC_CTRLEN 0x00000000
+
+/* ISC Control Disable Register 0 */
+#define ISC_CTRLDIS 0x00000004
+
+/* ISC Control Status Register 0 */
+#define ISC_CTRLSR 0x00000008
+
+#define ISC_CTRL_CAPTURE BIT(0)
+#define ISC_CTRL_UPPRO BIT(1)
+#define ISC_CTRL_HISREQ BIT(2)
+#define ISC_CTRL_HISCLR BIT(3)
+
+/* ISC Parallel Front End Configuration 0 Register */
+#define ISC_PFE_CFG0 0x0000000c
+
+#define ISC_PFE_CFG0_HPOL_LOW BIT(0)
+#define ISC_PFE_CFG0_VPOL_LOW BIT(1)
+#define ISC_PFE_CFG0_PPOL_LOW BIT(2)
+#define ISC_PFE_CFG0_CCIR656 BIT(9)
+#define ISC_PFE_CFG0_CCIR_CRC BIT(10)
+#define ISC_PFE_CFG0_MIPI BIT(14)
+
+#define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4)
+#define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4)
+
+#define ISC_PFE_CFG0_BPS_EIGHT (0x4 << 28)
+#define ISC_PFG_CFG0_BPS_NINE (0x3 << 28)
+#define ISC_PFG_CFG0_BPS_TEN (0x2 << 28)
+#define ISC_PFG_CFG0_BPS_ELEVEN (0x1 << 28)
+#define ISC_PFG_CFG0_BPS_TWELVE (0x0 << 28)
+#define ISC_PFE_CFG0_BPS_MASK GENMASK(30, 28)
+
+#define ISC_PFE_CFG0_COLEN BIT(12)
+#define ISC_PFE_CFG0_ROWEN BIT(13)
+
+/* ISC Parallel Front End Configuration 1 Register */
+#define ISC_PFE_CFG1 0x00000010
+
+#define ISC_PFE_CFG1_COLMIN(v) ((v))
+#define ISC_PFE_CFG1_COLMIN_MASK GENMASK(15, 0)
+#define ISC_PFE_CFG1_COLMAX(v) ((v) << 16)
+#define ISC_PFE_CFG1_COLMAX_MASK GENMASK(31, 16)
+
+/* ISC Parallel Front End Configuration 2 Register */
+#define ISC_PFE_CFG2 0x00000014
+
+#define ISC_PFE_CFG2_ROWMIN(v) ((v))
+#define ISC_PFE_CFG2_ROWMIN_MASK GENMASK(15, 0)
+#define ISC_PFE_CFG2_ROWMAX(v) ((v) << 16)
+#define ISC_PFE_CFG2_ROWMAX_MASK GENMASK(31, 16)
+
+/* ISC Clock Enable Register */
+#define ISC_CLKEN 0x00000018
+
+/* ISC Clock Disable Register */
+#define ISC_CLKDIS 0x0000001c
+
+/* ISC Clock Status Register */
+#define ISC_CLKSR 0x00000020
+#define ISC_CLKSR_SIP BIT(31)
+
+#define ISC_CLK(n) BIT(n)
+
+/* ISC Clock Configuration Register */
+#define ISC_CLKCFG 0x00000024
+#define ISC_CLKCFG_DIV_SHIFT(n) ((n) * 16)
+#define ISC_CLKCFG_DIV_MASK(n) GENMASK(((n) * 16 + 7), (n) * 16)
+#define ISC_CLKCFG_SEL_SHIFT(n) ((n) * 16 + 8)
+#define ISC_CLKCFG_SEL_MASK(n) GENMASK(((n) * 17 + 8), ((n) * 16 + 8))
+
+/* ISC Interrupt Enable Register */
+#define ISC_INTEN 0x00000028
+
+/* ISC Interrupt Disable Register */
+#define ISC_INTDIS 0x0000002c
+
+/* ISC Interrupt Mask Register */
+#define ISC_INTMASK 0x00000030
+
+/* ISC Interrupt Status Register */
+#define ISC_INTSR 0x00000034
+
+#define ISC_INT_DDONE BIT(8)
+#define ISC_INT_HISDONE BIT(12)
+
+/* ISC DPC Control Register */
+#define ISC_DPC_CTRL 0x40
+
+#define ISC_DPC_CTRL_DPCEN BIT(0)
+#define ISC_DPC_CTRL_GDCEN BIT(1)
+#define ISC_DPC_CTRL_BLCEN BIT(2)
+
+/* ISC DPC Config Register */
+#define ISC_DPC_CFG 0x44
+
+#define ISC_DPC_CFG_BAYSEL_SHIFT 0
+
+#define ISC_DPC_CFG_EITPOL BIT(4)
+
+#define ISC_DPC_CFG_TA_ENABLE BIT(14)
+#define ISC_DPC_CFG_TC_ENABLE BIT(13)
+#define ISC_DPC_CFG_TM_ENABLE BIT(12)
+
+#define ISC_DPC_CFG_RE_MODE BIT(17)
+
+#define ISC_DPC_CFG_GDCCLP_SHIFT 20
+#define ISC_DPC_CFG_GDCCLP_MASK GENMASK(22, 20)
+
+#define ISC_DPC_CFG_BLOFF_SHIFT 24
+#define ISC_DPC_CFG_BLOFF_MASK GENMASK(31, 24)
+
+#define ISC_DPC_CFG_BAYCFG_SHIFT 0
+#define ISC_DPC_CFG_BAYCFG_MASK GENMASK(1, 0)
+/* ISC DPC Threshold Median Register */
+#define ISC_DPC_THRESHM 0x48
+
+/* ISC DPC Threshold Closest Register */
+#define ISC_DPC_THRESHC 0x4C
+
+/* ISC DPC Threshold Average Register */
+#define ISC_DPC_THRESHA 0x50
+
+/* ISC DPC STatus Register */
+#define ISC_DPC_SR 0x54
+
+/* ISC White Balance Control Register */
+#define ISC_WB_CTRL 0x00000058
+
+/* ISC White Balance Configuration Register */
+#define ISC_WB_CFG 0x0000005c
+
+/* ISC White Balance Offset for R, GR Register */
+#define ISC_WB_O_RGR 0x00000060
+
+/* ISC White Balance Offset for B, GB Register */
+#define ISC_WB_O_BGB 0x00000064
+
+/* ISC White Balance Gain for R, GR Register */
+#define ISC_WB_G_RGR 0x00000068
+
+/* ISC White Balance Gain for B, GB Register */
+#define ISC_WB_G_BGB 0x0000006c
+
+/* ISC Color Filter Array Control Register */
+#define ISC_CFA_CTRL 0x00000070
+
+/* ISC Color Filter Array Configuration Register */
+#define ISC_CFA_CFG 0x00000074
+#define ISC_CFA_CFG_EITPOL BIT(4)
+
+#define ISC_BAY_CFG_GRGR 0x0
+#define ISC_BAY_CFG_RGRG 0x1
+#define ISC_BAY_CFG_GBGB 0x2
+#define ISC_BAY_CFG_BGBG 0x3
+
+/* ISC Color Correction Control Register */
+#define ISC_CC_CTRL 0x00000078
+
+/* ISC Color Correction RR RG Register */
+#define ISC_CC_RR_RG 0x0000007c
+
+/* ISC Color Correction RB OR Register */
+#define ISC_CC_RB_OR 0x00000080
+
+/* ISC Color Correction GR GG Register */
+#define ISC_CC_GR_GG 0x00000084
+
+/* ISC Color Correction GB OG Register */
+#define ISC_CC_GB_OG 0x00000088
+
+/* ISC Color Correction BR BG Register */
+#define ISC_CC_BR_BG 0x0000008c
+
+/* ISC Color Correction BB OB Register */
+#define ISC_CC_BB_OB 0x00000090
+
+/* ISC Gamma Correction Control Register */
+#define ISC_GAM_CTRL 0x00000094
+
+#define ISC_GAM_CTRL_BIPART BIT(4)
+
+/* ISC_Gamma Correction Blue Entry Register */
+#define ISC_GAM_BENTRY 0x00000098
+
+/* ISC_Gamma Correction Green Entry Register */
+#define ISC_GAM_GENTRY 0x00000198
+
+/* ISC_Gamma Correction Green Entry Register */
+#define ISC_GAM_RENTRY 0x00000298
+
+/* ISC VHXS Control Register */
+#define ISC_VHXS_CTRL 0x398
+
+/* ISC VHXS Source Size Register */
+#define ISC_VHXS_SS 0x39C
+
+/* ISC VHXS Destination Size Register */
+#define ISC_VHXS_DS 0x3A0
+
+/* ISC Vertical Factor Register */
+#define ISC_VXS_FACT 0x3a4
+
+/* ISC Horizontal Factor Register */
+#define ISC_HXS_FACT 0x3a8
+
+/* ISC Vertical Config Register */
+#define ISC_VXS_CFG 0x3ac
+
+/* ISC Horizontal Config Register */
+#define ISC_HXS_CFG 0x3b0
+
+/* ISC Vertical Tap Register */
+#define ISC_VXS_TAP 0x3b4
+
+/* ISC Horizontal Tap Register */
+#define ISC_HXS_TAP 0x434
+
+/* Offset for CSC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CSC_OFFSET 0
+/* Offset for CSC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CSC_OFFSET 0x11c
+
+/* Color Space Conversion Control Register */
+#define ISC_CSC_CTRL 0x00000398
+
+/* Color Space Conversion YR YG Register */
+#define ISC_CSC_YR_YG 0x0000039c
+
+/* Color Space Conversion YB OY Register */
+#define ISC_CSC_YB_OY 0x000003a0
+
+/* Color Space Conversion CBR CBG Register */
+#define ISC_CSC_CBR_CBG 0x000003a4
+
+/* Color Space Conversion CBB OCB Register */
+#define ISC_CSC_CBB_OCB 0x000003a8
+
+/* Color Space Conversion CRR CRG Register */
+#define ISC_CSC_CRR_CRG 0x000003ac
+
+/* Color Space Conversion CRB OCR Register */
+#define ISC_CSC_CRB_OCR 0x000003b0
+
+/* Offset for CBC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CBC_OFFSET 0
+/* Offset for CBC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CBC_OFFSET 0x11c
+
+/* Contrast And Brightness Control Register */
+#define ISC_CBC_CTRL 0x000003b4
+
+/* Contrast And Brightness Configuration Register */
+#define ISC_CBC_CFG 0x000003b8
+
+/* Brightness Register */
+#define ISC_CBC_BRIGHT 0x000003bc
+#define ISC_CBC_BRIGHT_MASK GENMASK(10, 0)
+
+/* Contrast Register */
+#define ISC_CBC_CONTRAST 0x000003c0
+#define ISC_CBC_CONTRAST_MASK GENMASK(11, 0)
+
+/* Hue Register */
+#define ISC_CBCHS_HUE 0x4e0
+/* Saturation Register */
+#define ISC_CBCHS_SAT 0x4e4
+
+/* Offset for SUB422 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB422_OFFSET 0
+/* Offset for SUB422 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB422_OFFSET 0x124
+
+/* Subsampling 4:4:4 to 4:2:2 Control Register */
+#define ISC_SUB422_CTRL 0x000003c4
+
+/* Offset for SUB420 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB420_OFFSET 0
+/* Offset for SUB420 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB420_OFFSET 0x124
+/* Subsampling 4:2:2 to 4:2:0 Control Register */
+#define ISC_SUB420_CTRL 0x000003cc
+
+/* Offset for RLP register specific to sama5d2 product */
+#define ISC_SAMA5D2_RLP_OFFSET 0
+/* Offset for RLP register specific to sama7g5 product */
+#define ISC_SAMA7G5_RLP_OFFSET 0x124
+/* Rounding, Limiting and Packing Configuration Register */
+#define ISC_RLP_CFG 0x000003d0
+
+#define ISC_RLP_CFG_MODE_DAT8 0x0
+#define ISC_RLP_CFG_MODE_DAT9 0x1
+#define ISC_RLP_CFG_MODE_DAT10 0x2
+#define ISC_RLP_CFG_MODE_DAT11 0x3
+#define ISC_RLP_CFG_MODE_DAT12 0x4
+#define ISC_RLP_CFG_MODE_DATY8 0x5
+#define ISC_RLP_CFG_MODE_DATY10 0x6
+#define ISC_RLP_CFG_MODE_ARGB444 0x7
+#define ISC_RLP_CFG_MODE_ARGB555 0x8
+#define ISC_RLP_CFG_MODE_RGB565 0x9
+#define ISC_RLP_CFG_MODE_ARGB32 0xa
+#define ISC_RLP_CFG_MODE_YYCC 0xb
+#define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc
+#define ISC_RLP_CFG_MODE_YCYC 0xd
+#define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0)
+
+#define ISC_RLP_CFG_LSH BIT(5)
+
+#define ISC_RLP_CFG_YMODE_YUYV (3 << 6)
+#define ISC_RLP_CFG_YMODE_YVYU (2 << 6)
+#define ISC_RLP_CFG_YMODE_VYUY (0 << 6)
+#define ISC_RLP_CFG_YMODE_UYVY (1 << 6)
+
+#define ISC_RLP_CFG_YMODE_MASK GENMASK(7, 6)
+
+/* Offset for HIS register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_OFFSET 0
+/* Offset for HIS register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_OFFSET 0x124
+/* Histogram Control Register */
+#define ISC_HIS_CTRL 0x000003d4
+
+#define ISC_HIS_CTRL_EN BIT(0)
+#define ISC_HIS_CTRL_DIS 0x0
+
+/* Histogram Configuration Register */
+#define ISC_HIS_CFG 0x000003d8
+
+#define ISC_HIS_CFG_MODE_GR 0x0
+#define ISC_HIS_CFG_MODE_R 0x1
+#define ISC_HIS_CFG_MODE_GB 0x2
+#define ISC_HIS_CFG_MODE_B 0x3
+#define ISC_HIS_CFG_MODE_Y 0x4
+#define ISC_HIS_CFG_MODE_RAW 0x5
+#define ISC_HIS_CFG_MODE_YCCIR656 0x6
+
+#define ISC_HIS_CFG_BAYSEL_SHIFT 4
+
+#define ISC_HIS_CFG_RAR BIT(8)
+
+/* Offset for DMA register specific to sama5d2 product */
+#define ISC_SAMA5D2_DMA_OFFSET 0
+/* Offset for DMA register specific to sama7g5 product */
+#define ISC_SAMA7G5_DMA_OFFSET 0x13c
+
+/* DMA Configuration Register */
+#define ISC_DCFG 0x000003e0
+#define ISC_DCFG_IMODE_PACKED8 0x0
+#define ISC_DCFG_IMODE_PACKED16 0x1
+#define ISC_DCFG_IMODE_PACKED32 0x2
+#define ISC_DCFG_IMODE_YC422SP 0x3
+#define ISC_DCFG_IMODE_YC422P 0x4
+#define ISC_DCFG_IMODE_YC420SP 0x5
+#define ISC_DCFG_IMODE_YC420P 0x6
+#define ISC_DCFG_IMODE_MASK GENMASK(2, 0)
+
+#define ISC_DCFG_YMBSIZE_SINGLE (0x0 << 4)
+#define ISC_DCFG_YMBSIZE_BEATS4 (0x1 << 4)
+#define ISC_DCFG_YMBSIZE_BEATS8 (0x2 << 4)
+#define ISC_DCFG_YMBSIZE_BEATS16 (0x3 << 4)
+#define ISC_DCFG_YMBSIZE_BEATS32 (0x4 << 4)
+#define ISC_DCFG_YMBSIZE_MASK GENMASK(6, 4)
+
+#define ISC_DCFG_CMBSIZE_SINGLE (0x0 << 8)
+#define ISC_DCFG_CMBSIZE_BEATS4 (0x1 << 8)
+#define ISC_DCFG_CMBSIZE_BEATS8 (0x2 << 8)
+#define ISC_DCFG_CMBSIZE_BEATS16 (0x3 << 8)
+#define ISC_DCFG_CMBSIZE_BEATS32 (0x4 << 8)
+#define ISC_DCFG_CMBSIZE_MASK GENMASK(10, 8)
+
+/* DMA Control Register */
+#define ISC_DCTRL 0x000003e4
+
+#define ISC_DCTRL_DVIEW_PACKED (0x0 << 1)
+#define ISC_DCTRL_DVIEW_SEMIPLANAR (0x1 << 1)
+#define ISC_DCTRL_DVIEW_PLANAR (0x2 << 1)
+#define ISC_DCTRL_DVIEW_MASK GENMASK(2, 1)
+
+#define ISC_DCTRL_IE_IS (0x0 << 4)
+
+/* DMA Descriptor Address Register */
+#define ISC_DNDA 0x000003e8
+
+/* DMA Address 0 Register */
+#define ISC_DAD0 0x000003ec
+
+/* DMA Address 1 Register */
+#define ISC_DAD1 0x000003f4
+
+/* DMA Address 2 Register */
+#define ISC_DAD2 0x000003fc
+
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_VERSION_OFFSET 0
+#define ISC_SAMA7G5_VERSION_OFFSET 0x13c
+/* Version Register */
+#define ISC_VERSION 0x0000040c
+
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_ENTRY_OFFSET 0
+/* Offset for version register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_ENTRY_OFFSET 0x14c
+/* Histogram Entry */
+#define ISC_HIS_ENTRY 0x00000410
+
+#endif
diff --git a/drivers/media/platform/microchip/microchip-isc-scaler.c b/drivers/media/platform/microchip/microchip-isc-scaler.c
new file mode 100644
index 000000000000..0f29a32d15ce
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc-scaler.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Microchip Image Sensor Controller (ISC) Scaler entity support
+ *
+ * Copyright (C) 2022 Microchip Technology, Inc.
+ *
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+static void isc_scaler_prepare_fmt(struct v4l2_mbus_framefmt *framefmt)
+{
+ framefmt->colorspace = V4L2_COLORSPACE_SRGB;
+ framefmt->field = V4L2_FIELD_NONE;
+ framefmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ framefmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ framefmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+};
+
+static int isc_scaler_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
+ struct v4l2_mbus_framefmt *v4l2_try_fmt;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ format->pad);
+ format->format = *v4l2_try_fmt;
+
+ return 0;
+ }
+
+ format->format = isc->scaler_format[format->pad];
+
+ return 0;
+}
+
+static int isc_scaler_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *req_fmt)
+{
+ struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
+ struct v4l2_mbus_framefmt *v4l2_try_fmt;
+ struct isc_format *fmt;
+ unsigned int i;
+
+ /* Source format is fixed, we cannot change it */
+ if (req_fmt->pad == ISC_SCALER_PAD_SOURCE) {
+ req_fmt->format = isc->scaler_format[ISC_SCALER_PAD_SOURCE];
+ return 0;
+ }
+
+ /* There is no limit on the frame size on the sink pad */
+ v4l_bound_align_image(&req_fmt->format.width, 16, UINT_MAX, 0,
+ &req_fmt->format.height, 16, UINT_MAX, 0, 0);
+
+ isc_scaler_prepare_fmt(&req_fmt->format);
+
+ fmt = isc_find_format_by_code(isc, req_fmt->format.code, &i);
+
+ if (!fmt)
+ fmt = &isc->formats_list[0];
+
+ req_fmt->format.code = fmt->mbus_code;
+
+ if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ req_fmt->pad);
+ *v4l2_try_fmt = req_fmt->format;
+ /* Trying on the sink pad makes the source pad change too */
+ v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ ISC_SCALER_PAD_SOURCE);
+ *v4l2_try_fmt = req_fmt->format;
+
+ v4l_bound_align_image(&v4l2_try_fmt->width,
+ 16, isc->max_width, 0,
+ &v4l2_try_fmt->height,
+ 16, isc->max_height, 0, 0);
+ /* if we are just trying, we are done */
+ return 0;
+ }
+
+ isc->scaler_format[ISC_SCALER_PAD_SINK] = req_fmt->format;
+
+ /* The source pad is the same as the sink, but we have to crop it */
+ isc->scaler_format[ISC_SCALER_PAD_SOURCE] =
+ isc->scaler_format[ISC_SCALER_PAD_SINK];
+ v4l_bound_align_image
+ (&isc->scaler_format[ISC_SCALER_PAD_SOURCE].width, 16,
+ isc->max_width, 0,
+ &isc->scaler_format[ISC_SCALER_PAD_SOURCE].height, 16,
+ isc->max_height, 0, 0);
+
+ return 0;
+}
+
+static int isc_scaler_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
+
+ /*
+ * All formats supported by the ISC are supported by the scaler.
+ * Advertise the formats which the ISC can take as input, as the scaler
+ * entity cropping is part of the PFE module (parallel front end)
+ */
+ if (code->index < isc->formats_list_size) {
+ code->code = isc->formats_list[code->index].mbus_code;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int isc_scaler_g_sel(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
+
+ if (sel->pad == ISC_SCALER_PAD_SOURCE)
+ return -EINVAL;
+
+ if (sel->target != V4L2_SEL_TGT_CROP_BOUNDS &&
+ sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ sel->r.height = isc->scaler_format[ISC_SCALER_PAD_SOURCE].height;
+ sel->r.width = isc->scaler_format[ISC_SCALER_PAD_SOURCE].width;
+
+ sel->r.left = 0;
+ sel->r.top = 0;
+
+ return 0;
+}
+
+static int isc_scaler_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_mbus_framefmt *v4l2_try_fmt =
+ v4l2_subdev_get_try_format(sd, sd_state, 0);
+ struct v4l2_rect *try_crop;
+ struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
+
+ *v4l2_try_fmt = isc->scaler_format[ISC_SCALER_PAD_SOURCE];
+
+ try_crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
+
+ try_crop->top = 0;
+ try_crop->left = 0;
+ try_crop->width = v4l2_try_fmt->width;
+ try_crop->height = v4l2_try_fmt->height;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops isc_scaler_pad_ops = {
+ .enum_mbus_code = isc_scaler_enum_mbus_code,
+ .set_fmt = isc_scaler_set_fmt,
+ .get_fmt = isc_scaler_get_fmt,
+ .get_selection = isc_scaler_g_sel,
+ .init_cfg = isc_scaler_init_cfg,
+};
+
+static const struct media_entity_operations isc_scaler_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_ops xisc_scaler_subdev_ops = {
+ .pad = &isc_scaler_pad_ops,
+};
+
+int isc_scaler_init(struct isc_device *isc)
+{
+ int ret;
+
+ v4l2_subdev_init(&isc->scaler_sd, &xisc_scaler_subdev_ops);
+
+ isc->scaler_sd.owner = THIS_MODULE;
+ isc->scaler_sd.dev = isc->dev;
+ snprintf(isc->scaler_sd.name, sizeof(isc->scaler_sd.name),
+ "microchip_isc_scaler");
+
+ isc->scaler_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ isc->scaler_sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ isc->scaler_sd.entity.ops = &isc_scaler_entity_ops;
+ isc->scaler_pads[ISC_SCALER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ isc->scaler_pads[ISC_SCALER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ isc_scaler_prepare_fmt(&isc->scaler_format[ISC_SCALER_PAD_SOURCE]);
+ isc->scaler_format[ISC_SCALER_PAD_SOURCE].height = isc->max_height;
+ isc->scaler_format[ISC_SCALER_PAD_SOURCE].width = isc->max_width;
+ isc->scaler_format[ISC_SCALER_PAD_SOURCE].code =
+ isc->formats_list[0].mbus_code;
+
+ isc->scaler_format[ISC_SCALER_PAD_SINK] =
+ isc->scaler_format[ISC_SCALER_PAD_SOURCE];
+
+ ret = media_entity_pads_init(&isc->scaler_sd.entity,
+ ISC_SCALER_PADS_NUM,
+ isc->scaler_pads);
+ if (ret < 0) {
+ dev_err(isc->dev, "scaler sd media entity init failed\n");
+ return ret;
+ }
+
+ ret = v4l2_device_register_subdev(&isc->v4l2_dev, &isc->scaler_sd);
+ if (ret < 0) {
+ dev_err(isc->dev, "scaler sd failed to register subdev\n");
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(isc_scaler_init);
+
+int isc_scaler_link(struct isc_device *isc)
+{
+ int ret;
+
+ ret = media_create_pad_link(&isc->current_subdev->sd->entity,
+ isc->remote_pad, &isc->scaler_sd.entity,
+ ISC_SCALER_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+
+ if (ret < 0) {
+ dev_err(isc->dev, "Failed to create pad link: %s to %s\n",
+ isc->current_subdev->sd->entity.name,
+ isc->scaler_sd.entity.name);
+ return ret;
+ }
+
+ dev_dbg(isc->dev, "link with %s pad: %d\n",
+ isc->current_subdev->sd->name, isc->remote_pad);
+
+ ret = media_create_pad_link(&isc->scaler_sd.entity,
+ ISC_SCALER_PAD_SOURCE,
+ &isc->video_dev.entity, ISC_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+
+ if (ret < 0) {
+ dev_err(isc->dev, "Failed to create pad link: %s to %s\n",
+ isc->scaler_sd.entity.name,
+ isc->video_dev.entity.name);
+ return ret;
+ }
+
+ dev_dbg(isc->dev, "link with %s pad: %d\n", isc->scaler_sd.name,
+ ISC_SCALER_PAD_SOURCE);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(isc_scaler_link);
+
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
new file mode 100644
index 000000000000..e3a6c7367e70
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -0,0 +1,400 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Microchip Image Sensor Controller (ISC) driver header file
+ *
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+#ifndef _MICROCHIP_ISC_H_
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define ISC_CLK_MAX_DIV 255
+
+enum isc_clk_id {
+ ISC_ISPCK = 0,
+ ISC_MCK = 1,
+};
+
+struct isc_clk {
+ struct clk_hw hw;
+ struct clk *clk;
+ struct regmap *regmap;
+ spinlock_t lock; /* serialize access to clock registers */
+ u8 id;
+ u8 parent_id;
+ u32 div;
+ struct device *dev;
+};
+
+#define to_isc_clk(v) container_of(v, struct isc_clk, hw)
+
+struct isc_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+struct isc_subdev_entity {
+ struct v4l2_subdev *sd;
+ struct v4l2_async_subdev *asd;
+ struct device_node *epn;
+ struct v4l2_async_notifier notifier;
+
+ u32 pfe_cfg0;
+
+ struct list_head list;
+};
+
+/*
+ * struct isc_format - ISC media bus format information
+ This structure represents the interface between the ISC
+ and the sensor. It's the input format received by
+ the ISC.
+ * @fourcc: Fourcc code for this format
+ * @mbus_code: V4L2 media bus format code.
+ * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer.
+ this is either BGBG, RGRG, etc.
+ * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC
+ * @raw: If the format is raw bayer.
+ */
+
+struct isc_format {
+ u32 fourcc;
+ u32 mbus_code;
+ u32 cfa_baycfg;
+ u32 pfe_cfg0_bps;
+
+ bool raw;
+};
+
+/* Pipeline bitmap */
+#define DPC_DPCENABLE BIT(0)
+#define DPC_GDCENABLE BIT(1)
+#define DPC_BLCENABLE BIT(2)
+#define WB_ENABLE BIT(3)
+#define CFA_ENABLE BIT(4)
+#define CC_ENABLE BIT(5)
+#define GAM_ENABLE BIT(6)
+#define GAM_BENABLE BIT(7)
+#define GAM_GENABLE BIT(8)
+#define GAM_RENABLE BIT(9)
+#define VHXS_ENABLE BIT(10)
+#define CSC_ENABLE BIT(11)
+#define CBC_ENABLE BIT(12)
+#define SUB422_ENABLE BIT(13)
+#define SUB420_ENABLE BIT(14)
+
+#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
+
+/*
+ * struct fmt_config - ISC format configuration and internal pipeline
+ This structure represents the internal configuration
+ of the ISC.
+ It also holds the format that ISC will present to v4l2.
+ * @sd_format: Pointer to an isc_format struct that holds the sensor
+ configuration.
+ * @fourcc: Fourcc code for this format.
+ * @bpp: Bytes per pixel in the current format.
+ * @bpp_v4l2: Bytes per pixel in the current format, for v4l2.
+ This differs from 'bpp' in the sense that in planar
+ formats, it refers only to the first plane.
+ * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging)
+ * @dcfg_imode: Configuration of the input of the DMA module
+ * @dctrl_dview: Configuration of the output of the DMA module
+ * @bits_pipeline: Configuration of the pipeline, which modules are enabled
+ */
+struct fmt_config {
+ struct isc_format *sd_format;
+
+ u32 fourcc;
+ u8 bpp;
+ u8 bpp_v4l2;
+
+ u32 rlp_cfg_mode;
+ u32 dcfg_imode;
+ u32 dctrl_dview;
+
+ u32 bits_pipeline;
+};
+
+#define HIST_ENTRIES 512
+#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1)
+
+enum{
+ HIST_INIT = 0,
+ HIST_ENABLED,
+ HIST_DISABLED,
+};
+
+struct isc_ctrls {
+ struct v4l2_ctrl_handler handler;
+
+ u32 brightness;
+ u32 contrast;
+ u8 gamma_index;
+#define ISC_WB_NONE 0
+#define ISC_WB_AUTO 1
+#define ISC_WB_ONETIME 2
+ u8 awb;
+
+ /* one for each component : GR, R, GB, B */
+ u32 gain[HIST_BAYER];
+ s32 offset[HIST_BAYER];
+
+ u32 hist_entry[HIST_ENTRIES];
+ u32 hist_count[HIST_BAYER];
+ u8 hist_id;
+ u8 hist_stat;
+#define HIST_MIN_INDEX 0
+#define HIST_MAX_INDEX 1
+ u32 hist_minmax[HIST_BAYER][2];
+};
+
+#define ISC_PIPE_LINE_NODE_NUM 15
+
+/*
+ * struct isc_reg_offsets - ISC device register offsets
+ * @csc: Offset for the CSC register
+ * @cbc: Offset for the CBC register
+ * @sub422: Offset for the SUB422 register
+ * @sub420: Offset for the SUB420 register
+ * @rlp: Offset for the RLP register
+ * @his: Offset for the HIS related registers
+ * @dma: Offset for the DMA related registers
+ * @version: Offset for the version register
+ * @his_entry: Offset for the HIS entries registers
+ */
+struct isc_reg_offsets {
+ u32 csc;
+ u32 cbc;
+ u32 sub422;
+ u32 sub420;
+ u32 rlp;
+ u32 his;
+ u32 dma;
+ u32 version;
+ u32 his_entry;
+};
+
+enum isc_mc_pads {
+ ISC_PAD_SINK = 0,
+ ISC_PADS_NUM = 1,
+};
+
+enum isc_scaler_pads {
+ ISC_SCALER_PAD_SINK = 0,
+ ISC_SCALER_PAD_SOURCE = 1,
+ ISC_SCALER_PADS_NUM = 2,
+};
+
+/*
+ * struct isc_device - ISC device driver data/config struct
+ * @regmap: Register map
+ * @hclock: Hclock clock input (refer datasheet)
+ * @ispck: iscpck clock (refer datasheet)
+ * @isc_clks: ISC clocks
+ * @ispck_required: ISC requires ISP Clock initialization
+ * @dcfg: DMA master configuration, architecture dependent
+ *
+ * @dev: Registered device driver
+ * @v4l2_dev: v4l2 registered device
+ * @video_dev: registered video device
+ *
+ * @vb2_vidq: video buffer 2 video queue
+ * @dma_queue_lock: lock to serialize the dma buffer queue
+ * @dma_queue: the queue for dma buffers
+ * @cur_frm: current isc frame/buffer
+ * @sequence: current frame number
+ * @stop: true if isc is not streaming, false if streaming
+ * @comp: completion reference that signals frame completion
+ *
+ * @fmt: current v42l format
+ * @try_fmt: current v4l2 try format
+ *
+ * @config: current ISC format configuration
+ * @try_config: the current ISC try format , not yet activated
+ *
+ * @ctrls: holds information about ISC controls
+ * @do_wb_ctrl: control regarding the DO_WHITE_BALANCE button
+ * @awb_work: workqueue reference for autowhitebalance histogram
+ * analysis
+ *
+ * @lock: lock for serializing userspace file operations
+ * with ISC operations
+ * @awb_mutex: serialize access to streaming status from awb work queue
+ * @awb_lock: lock for serializing awb work queue operations
+ * with DMA/buffer operations
+ *
+ * @pipeline: configuration of the ISC pipeline
+ *
+ * @current_subdev: current subdevice: the sensor
+ * @subdev_entities: list of subdevice entitites
+ *
+ * @gamma_table: pointer to the table with gamma values, has
+ * gamma_max sets of GAMMA_ENTRIES entries each
+ * @gamma_max: maximum number of sets of inside the gamma_table
+ *
+ * @max_width: maximum frame width, dependent on the internal RAM
+ * @max_height: maximum frame height, dependent on the internal RAM
+ *
+ * @config_dpc: pointer to a function that initializes product
+ * specific DPC module
+ * @config_csc: pointer to a function that initializes product
+ * specific CSC module
+ * @config_cbc: pointer to a function that initializes product
+ * specific CBC module
+ * @config_cc: pointer to a function that initializes product
+ * specific CC module
+ * @config_gam: pointer to a function that initializes product
+ * specific GAMMA module
+ * @config_rlp: pointer to a function that initializes product
+ * specific RLP module
+ * @config_ctrls: pointer to a functoin that initializes product
+ * specific v4l2 controls.
+ *
+ * @adapt_pipeline: pointer to a function that adapts the pipeline bits
+ * to the product specific pipeline
+ *
+ * @offsets: struct holding the product specific register offsets
+ * @controller_formats: pointer to the array of possible formats that the
+ * controller can output
+ * @formats_list: pointer to the array of possible formats that can
+ * be used as an input to the controller
+ * @controller_formats_size: size of controller_formats array
+ * @formats_list_size: size of formats_list array
+ * @pads: media controller pads for isc video entity
+ * @mdev: media device that is registered by the isc
+ * @mpipe: media device pipeline used by the isc
+ * @remote_pad: remote pad on the connected subdevice
+ * @scaler_sd: subdevice for the scaler that isc registers
+ * @scaler_pads: media controller pads for the scaler subdevice
+ * @scaler_format: current format for the scaler subdevice
+ */
+struct isc_device {
+ struct regmap *regmap;
+ struct clk *hclock;
+ struct clk *ispck;
+ struct isc_clk isc_clks[2];
+ bool ispck_required;
+ u32 dcfg;
+
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct video_device video_dev;
+
+ struct vb2_queue vb2_vidq;
+ spinlock_t dma_queue_lock;
+ struct list_head dma_queue;
+ struct isc_buffer *cur_frm;
+ unsigned int sequence;
+ bool stop;
+ struct completion comp;
+
+ struct v4l2_format fmt;
+ struct v4l2_format try_fmt;
+
+ struct fmt_config config;
+ struct fmt_config try_config;
+
+ struct isc_ctrls ctrls;
+ struct work_struct awb_work;
+
+ struct mutex lock;
+ struct mutex awb_mutex;
+ spinlock_t awb_lock;
+
+ struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];
+
+ struct isc_subdev_entity *current_subdev;
+ struct list_head subdev_entities;
+
+ struct {
+#define ISC_CTRL_DO_WB 1
+#define ISC_CTRL_R_GAIN 2
+#define ISC_CTRL_B_GAIN 3
+#define ISC_CTRL_GR_GAIN 4
+#define ISC_CTRL_GB_GAIN 5
+#define ISC_CTRL_R_OFF 6
+#define ISC_CTRL_B_OFF 7
+#define ISC_CTRL_GR_OFF 8
+#define ISC_CTRL_GB_OFF 9
+ struct v4l2_ctrl *awb_ctrl;
+ struct v4l2_ctrl *do_wb_ctrl;
+ struct v4l2_ctrl *r_gain_ctrl;
+ struct v4l2_ctrl *b_gain_ctrl;
+ struct v4l2_ctrl *gr_gain_ctrl;
+ struct v4l2_ctrl *gb_gain_ctrl;
+ struct v4l2_ctrl *r_off_ctrl;
+ struct v4l2_ctrl *b_off_ctrl;
+ struct v4l2_ctrl *gr_off_ctrl;
+ struct v4l2_ctrl *gb_off_ctrl;
+ };
+
+#define GAMMA_ENTRIES 64
+ /* pointer to the defined gamma table */
+ const u32 (*gamma_table)[GAMMA_ENTRIES];
+ u32 gamma_max;
+
+ u32 max_width;
+ u32 max_height;
+
+ struct {
+ void (*config_dpc)(struct isc_device *isc);
+ void (*config_csc)(struct isc_device *isc);
+ void (*config_cbc)(struct isc_device *isc);
+ void (*config_cc)(struct isc_device *isc);
+ void (*config_gam)(struct isc_device *isc);
+ void (*config_rlp)(struct isc_device *isc);
+
+ void (*config_ctrls)(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops);
+
+ void (*adapt_pipeline)(struct isc_device *isc);
+ };
+
+ struct isc_reg_offsets offsets;
+ const struct isc_format *controller_formats;
+ struct isc_format *formats_list;
+ u32 controller_formats_size;
+ u32 formats_list_size;
+
+ struct {
+ struct media_pad pads[ISC_PADS_NUM];
+ struct media_device mdev;
+ struct media_pipeline mpipe;
+
+ u32 remote_pad;
+ };
+
+ struct {
+ struct v4l2_subdev scaler_sd;
+ struct media_pad scaler_pads[ISC_SCALER_PADS_NUM];
+ struct v4l2_mbus_framefmt scaler_format[ISC_SCALER_PADS_NUM];
+ };
+};
+
+extern const struct regmap_config microchip_isc_regmap_config;
+extern const struct v4l2_async_notifier_operations microchip_isc_async_ops;
+
+irqreturn_t microchip_isc_interrupt(int irq, void *dev_id);
+int microchip_isc_pipeline_init(struct isc_device *isc);
+int microchip_isc_clk_init(struct isc_device *isc);
+void microchip_isc_subdev_cleanup(struct isc_device *isc);
+void microchip_isc_clk_cleanup(struct isc_device *isc);
+
+int isc_scaler_link(struct isc_device *isc);
+int isc_scaler_init(struct isc_device *isc);
+int isc_mc_init(struct isc_device *isc, u32 ver);
+void isc_mc_cleanup(struct isc_device *isc);
+
+struct isc_format *isc_find_format_by_code(struct isc_device *isc,
+ unsigned int code, int *index);
+#endif
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
new file mode 100644
index 000000000000..ac4715d91de6
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip Image Sensor Controller (ISC) driver
+ *
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ *
+ * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
+ *
+ * ISC video pipeline integrates the following submodules:
+ * PFE: Parallel Front End to sample the camera sensor input stream
+ * WB: Programmable white balance in the Bayer domain
+ * CFA: Color filter array interpolation module
+ * CC: Programmable color correction
+ * GAM: Gamma correction
+ * CSC: Programmable color space conversion
+ * CBC: Contrast and Brightness control
+ * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
+ * RLP: This module performs rounding, range limiting
+ * and packing of the incoming data
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+#define ISC_SAMA5D2_MAX_SUPPORT_WIDTH 2592
+#define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT 1944
+
+#define ISC_SAMA5D2_PIPELINE \
+ (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama5d2_controller_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB444,
+ }, {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ }, {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ }, {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .raw = true,
+ },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama5d2_formats_list[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ },
+
+};
+
+static void isc_sama5d2_config_csc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Convert RGB to YUV */
+ regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+ 0x42 | (0x81 << 16));
+ regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+ 0x19 | (0x10 << 16));
+ regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+ 0xFDA | (0xFB6 << 16));
+ regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+ 0x70 | (0x80 << 16));
+ regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+ 0x70 | (0xFA2 << 16));
+ regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+ 0xFEE | (0x80 << 16));
+}
+
+static void isc_sama5d2_config_cbc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
+ isc->ctrls.brightness);
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
+ isc->ctrls.contrast);
+}
+
+static void isc_sama5d2_config_cc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+ regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+ regmap_write(regmap, ISC_CC_RB_OR, 0);
+ regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+ regmap_write(regmap, ISC_CC_GB_OG, 0);
+ regmap_write(regmap, ISC_CC_BR_BG, 0);
+ regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama5d2_config_ctrls(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ ctrls->contrast = 256;
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
+}
+
+static void isc_sama5d2_config_dpc(struct isc_device *isc)
+{
+ /* This module is not present on sama5d2 pipeline */
+}
+
+static void isc_sama5d2_config_gam(struct isc_device *isc)
+{
+ /* No specific gamma configuration */
+}
+
+static void isc_sama5d2_config_rlp(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+ /*
+ * In sama5d2, the YUV planar modes and the YUYV modes are treated
+ * in the same way in RLP register.
+ * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
+ * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
+ * but in sama5d2, the YCYC mode does not exist, and YYCC must be
+ * selected for both planar and interleaved modes, as in fact
+ * both modes are supported.
+ *
+ * Thus, if the YCYC mode is selected, replace it with the
+ * sama5d2-compliant mode which is YYCC .
+ */
+ if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
+ rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
+ rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
+ }
+
+ regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+ ISC_RLP_CFG_MODE_MASK, rlp_mode);
+}
+
+static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
+{
+ isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
+ /* 0 --> gamma 1/1.8 */
+ { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A,
+ 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
+ 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
+ 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
+ 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
+ 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
+ 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
+ 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
+ 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
+ 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
+ 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
+
+ /* 1 --> gamma 1/2 */
+ { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B,
+ 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
+ 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
+ 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
+ 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
+ 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
+ 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
+ 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
+ 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
+ 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
+ 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
+
+ /* 2 --> gamma 1/2.2 */
+ { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B,
+ 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
+ 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
+ 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
+ 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
+ 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
+ 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
+ 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
+ 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
+ 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
+ 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
+};
+
+static int isc_parse_dt(struct device *dev, struct isc_device *isc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *epn = NULL;
+ struct isc_subdev_entity *subdev_entity;
+ unsigned int flags;
+ int ret;
+
+ INIT_LIST_HEAD(&isc->subdev_entities);
+
+ while (1) {
+ struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
+ epn = of_graph_get_next_endpoint(np, epn);
+ if (!epn)
+ return 0;
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
+ &v4l2_epn);
+ if (ret) {
+ ret = -EINVAL;
+ dev_err(dev, "Could not parse the endpoint\n");
+ break;
+ }
+
+ subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
+ GFP_KERNEL);
+ if (!subdev_entity) {
+ ret = -ENOMEM;
+ break;
+ }
+ subdev_entity->epn = epn;
+
+ flags = v4l2_epn.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
+
+ if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656;
+
+ list_add_tail(&subdev_entity->list, &isc->subdev_entities);
+ }
+ of_node_put(epn);
+
+ return ret;
+}
+
+static int microchip_isc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct isc_device *isc;
+ struct resource *res;
+ void __iomem *io_base;
+ struct isc_subdev_entity *subdev_entity;
+ int irq;
+ int ret;
+ u32 ver;
+
+ isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
+ if (!isc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, isc);
+ isc->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
+ if (IS_ERR(isc->regmap)) {
+ ret = PTR_ERR(isc->regmap);
+ dev_err(dev, "failed to init register map: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
+ "microchip-sama5d2-isc", isc);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ irq, ret);
+ return ret;
+ }
+
+ isc->gamma_table = isc_sama5d2_gamma_table;
+ isc->gamma_max = 2;
+
+ isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
+
+ isc->config_dpc = isc_sama5d2_config_dpc;
+ isc->config_csc = isc_sama5d2_config_csc;
+ isc->config_cbc = isc_sama5d2_config_cbc;
+ isc->config_cc = isc_sama5d2_config_cc;
+ isc->config_gam = isc_sama5d2_config_gam;
+ isc->config_rlp = isc_sama5d2_config_rlp;
+ isc->config_ctrls = isc_sama5d2_config_ctrls;
+
+ isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
+
+ isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
+ isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
+ isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
+ isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
+ isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
+ isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
+ isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
+ isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
+ isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
+
+ isc->controller_formats = sama5d2_controller_formats;
+ isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
+ isc->formats_list = sama5d2_formats_list;
+ isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
+
+ /* sama5d2-isc - 8 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+
+ /* sama5d2-isc : ISPCK is required and mandatory */
+ isc->ispck_required = true;
+
+ ret = microchip_isc_pipeline_init(isc);
+ if (ret)
+ return ret;
+
+ isc->hclock = devm_clk_get(dev, "hclock");
+ if (IS_ERR(isc->hclock)) {
+ ret = PTR_ERR(isc->hclock);
+ dev_err(dev, "failed to get hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret) {
+ dev_err(dev, "failed to enable hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = microchip_isc_clk_init(isc);
+ if (ret) {
+ dev_err(dev, "failed to init isc clock: %d\n", ret);
+ goto unprepare_hclk;
+ }
+ ret = v4l2_device_register(dev, &isc->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "unable to register v4l2 device.\n");
+ goto unprepare_clk;
+ }
+
+ ret = isc_parse_dt(dev, isc);
+ if (ret) {
+ dev_err(dev, "fail to parse device tree\n");
+ goto unregister_v4l2_device;
+ }
+
+ if (list_empty(&isc->subdev_entities)) {
+ dev_err(dev, "no subdev found\n");
+ ret = -ENODEV;
+ goto unregister_v4l2_device;
+ }
+
+ list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *fwnode =
+ of_fwnode_handle(subdev_entity->epn);
+
+ v4l2_async_nf_init(&subdev_entity->notifier);
+
+ asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
+ fwnode,
+ struct v4l2_async_subdev);
+
+ of_node_put(subdev_entity->epn);
+ subdev_entity->epn = NULL;
+
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ goto cleanup_subdev;
+ }
+
+ subdev_entity->notifier.ops = &microchip_isc_async_ops;
+
+ ret = v4l2_async_nf_register(&isc->v4l2_dev,
+ &subdev_entity->notifier);
+ if (ret) {
+ dev_err(dev, "fail to register async notifier\n");
+ goto cleanup_subdev;
+ }
+
+ if (video_is_registered(&isc->video_dev))
+ break;
+ }
+
+ regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+
+ ret = isc_mc_init(isc, ver);
+ if (ret < 0)
+ goto isc_probe_mc_init_err;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_request_idle(dev);
+
+ isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
+
+ ret = clk_prepare_enable(isc->ispck);
+ if (ret) {
+ dev_err(dev, "failed to enable ispck: %d\n", ret);
+ goto disable_pm;
+ }
+
+ /* ispck should be greater or equal to hclock */
+ ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
+ if (ret) {
+ dev_err(dev, "failed to set ispck rate: %d\n", ret);
+ goto unprepare_clk;
+ }
+
+ dev_info(dev, "Microchip ISC version %x\n", ver);
+
+ return 0;
+
+unprepare_clk:
+ clk_disable_unprepare(isc->ispck);
+
+disable_pm:
+ pm_runtime_disable(dev);
+
+isc_probe_mc_init_err:
+ isc_mc_cleanup(isc);
+
+cleanup_subdev:
+ microchip_isc_subdev_cleanup(isc);
+
+unregister_v4l2_device:
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+unprepare_hclk:
+ clk_disable_unprepare(isc->hclock);
+
+ microchip_isc_clk_cleanup(isc);
+
+ return ret;
+}
+
+static int microchip_isc_remove(struct platform_device *pdev)
+{
+ struct isc_device *isc = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ isc_mc_cleanup(isc);
+
+ microchip_isc_subdev_cleanup(isc);
+
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+ clk_disable_unprepare(isc->ispck);
+ clk_disable_unprepare(isc->hclock);
+
+ microchip_isc_clk_cleanup(isc);
+
+ return 0;
+}
+
+static int __maybe_unused isc_runtime_suspend(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(isc->ispck);
+ clk_disable_unprepare(isc->hclock);
+
+ return 0;
+}
+
+static int __maybe_unused isc_runtime_resume(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(isc->ispck);
+ if (ret)
+ clk_disable_unprepare(isc->hclock);
+
+ return ret;
+}
+
+static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
+};
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id microchip_isc_of_match[] = {
+ { .compatible = "atmel,sama5d2-isc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
+#endif
+
+static struct platform_driver microchip_isc_driver = {
+ .probe = microchip_isc_probe,
+ .remove = microchip_isc_remove,
+ .driver = {
+ .name = "microchip-sama5d2-isc",
+ .pm = &microchip_isc_dev_pm_ops,
+ .of_match_table = of_match_ptr(microchip_isc_of_match),
+ },
+};
+
+module_platform_driver(microchip_isc_driver);
+
+MODULE_AUTHOR("Songjun Wu");
+MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
new file mode 100644
index 000000000000..d583eafe5cc1
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -0,0 +1,646 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip eXtended Image Sensor Controller (XISC) driver
+ *
+ * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
+ *
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
+ *
+ * ISC video pipeline integrates the following submodules:
+ * PFE: Parallel Front End to sample the camera sensor input stream
+ * DPC: Defective Pixel Correction with black offset correction, green disparity
+ * correction and defective pixel correction (3 modules total)
+ * WB: Programmable white balance in the Bayer domain
+ * CFA: Color filter array interpolation module
+ * CC: Programmable color correction
+ * GAM: Gamma correction
+ *VHXS: Vertical and Horizontal Scaler
+ * CSC: Programmable color space conversion
+ *CBHS: Contrast Brightness Hue and Saturation control
+ * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
+ * RLP: This module performs rounding, range limiting
+ * and packing of the incoming data
+ * DMA: This module performs DMA master accesses to write frames to external RAM
+ * HIS: Histogram module performs statistic counters on the frames
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
+#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
+
+#define ISC_SAMA7G5_PIPELINE \
+ (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama7g5_controller_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB444,
+ }, {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ }, {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ }, {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .raw = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .raw = true,
+ },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama7g5_formats_list[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ },
+};
+
+static void isc_sama7g5_config_csc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Convert RGB to YUV */
+ regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+ 0x42 | (0x81 << 16));
+ regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+ 0x19 | (0x10 << 16));
+ regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+ 0xFDA | (0xFB6 << 16));
+ regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+ 0x70 | (0x80 << 16));
+ regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+ 0x70 | (0xFA2 << 16));
+ regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+ 0xFEE | (0x80 << 16));
+}
+
+static void isc_sama7g5_config_cbc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure what is set via v4l2 ctrls */
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
+ /* Configure Hue and Saturation as neutral midpoint */
+ regmap_write(regmap, ISC_CBCHS_HUE, 0);
+ regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
+}
+
+static void isc_sama7g5_config_cc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+ regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+ regmap_write(regmap, ISC_CC_RB_OR, 0);
+ regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+ regmap_write(regmap, ISC_CC_GB_OG, 0);
+ regmap_write(regmap, ISC_CC_BR_BG, 0);
+ regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama7g5_config_ctrls(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ ctrls->contrast = 16;
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
+}
+
+static void isc_sama7g5_config_dpc(struct isc_device *isc)
+{
+ u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
+ struct regmap *regmap = isc->regmap;
+
+ regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
+ (64 << ISC_DPC_CFG_BLOFF_SHIFT));
+ regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
+ (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
+}
+
+static void isc_sama7g5_config_gam(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
+ ISC_GAM_CTRL_BIPART);
+}
+
+static void isc_sama7g5_config_rlp(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+ regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+ ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
+ ISC_RLP_CFG_YMODE_MASK, rlp_mode);
+}
+
+static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
+{
+ isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
+ /* index 0 --> gamma bipartite */
+ {
+ 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
+ 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
+ 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
+ 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+ 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+ 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+ 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+ 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+ 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+ 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+ 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+};
+
+static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *epn = NULL;
+ struct isc_subdev_entity *subdev_entity;
+ unsigned int flags;
+ int ret;
+ bool mipi_mode;
+
+ INIT_LIST_HEAD(&isc->subdev_entities);
+
+ mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
+
+ while (1) {
+ struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
+ epn = of_graph_get_next_endpoint(np, epn);
+ if (!epn)
+ return 0;
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
+ &v4l2_epn);
+ if (ret) {
+ ret = -EINVAL;
+ dev_err(dev, "Could not parse the endpoint\n");
+ break;
+ }
+
+ subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
+ GFP_KERNEL);
+ if (!subdev_entity) {
+ ret = -ENOMEM;
+ break;
+ }
+ subdev_entity->epn = epn;
+
+ flags = v4l2_epn.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
+
+ if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656;
+
+ if (mipi_mode)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
+
+ list_add_tail(&subdev_entity->list, &isc->subdev_entities);
+ }
+ of_node_put(epn);
+
+ return ret;
+}
+
+static int microchip_xisc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct isc_device *isc;
+ struct resource *res;
+ void __iomem *io_base;
+ struct isc_subdev_entity *subdev_entity;
+ int irq;
+ int ret;
+ u32 ver;
+
+ isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
+ if (!isc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, isc);
+ isc->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
+ if (IS_ERR(isc->regmap)) {
+ ret = PTR_ERR(isc->regmap);
+ dev_err(dev, "failed to init register map: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
+ "microchip-sama7g5-xisc", isc);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ irq, ret);
+ return ret;
+ }
+
+ isc->gamma_table = isc_sama7g5_gamma_table;
+ isc->gamma_max = 0;
+
+ isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+
+ isc->config_dpc = isc_sama7g5_config_dpc;
+ isc->config_csc = isc_sama7g5_config_csc;
+ isc->config_cbc = isc_sama7g5_config_cbc;
+ isc->config_cc = isc_sama7g5_config_cc;
+ isc->config_gam = isc_sama7g5_config_gam;
+ isc->config_rlp = isc_sama7g5_config_rlp;
+ isc->config_ctrls = isc_sama7g5_config_ctrls;
+
+ isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
+
+ isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
+ isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
+ isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
+ isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
+ isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
+ isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
+ isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
+ isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
+ isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
+
+ isc->controller_formats = sama7g5_controller_formats;
+ isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
+ isc->formats_list = sama7g5_formats_list;
+ isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
+
+ /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
+
+ /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
+ isc->ispck_required = false;
+
+ ret = microchip_isc_pipeline_init(isc);
+ if (ret)
+ return ret;
+
+ isc->hclock = devm_clk_get(dev, "hclock");
+ if (IS_ERR(isc->hclock)) {
+ ret = PTR_ERR(isc->hclock);
+ dev_err(dev, "failed to get hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret) {
+ dev_err(dev, "failed to enable hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = microchip_isc_clk_init(isc);
+ if (ret) {
+ dev_err(dev, "failed to init isc clock: %d\n", ret);
+ goto unprepare_hclk;
+ }
+
+ ret = v4l2_device_register(dev, &isc->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "unable to register v4l2 device.\n");
+ goto unprepare_hclk;
+ }
+
+ ret = xisc_parse_dt(dev, isc);
+ if (ret) {
+ dev_err(dev, "fail to parse device tree\n");
+ goto unregister_v4l2_device;
+ }
+
+ if (list_empty(&isc->subdev_entities)) {
+ dev_err(dev, "no subdev found\n");
+ ret = -ENODEV;
+ goto unregister_v4l2_device;
+ }
+
+ list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *fwnode =
+ of_fwnode_handle(subdev_entity->epn);
+
+ v4l2_async_nf_init(&subdev_entity->notifier);
+
+ asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
+ fwnode,
+ struct v4l2_async_subdev);
+
+ of_node_put(subdev_entity->epn);
+ subdev_entity->epn = NULL;
+
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ goto cleanup_subdev;
+ }
+
+ subdev_entity->notifier.ops = &microchip_isc_async_ops;
+
+ ret = v4l2_async_nf_register(&isc->v4l2_dev,
+ &subdev_entity->notifier);
+ if (ret) {
+ dev_err(dev, "fail to register async notifier\n");
+ goto cleanup_subdev;
+ }
+
+ if (video_is_registered(&isc->video_dev))
+ break;
+ }
+
+ regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+
+ ret = isc_mc_init(isc, ver);
+ if (ret < 0)
+ goto isc_probe_mc_init_err;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_request_idle(dev);
+
+ dev_info(dev, "Microchip XISC version %x\n", ver);
+
+ return 0;
+
+isc_probe_mc_init_err:
+ isc_mc_cleanup(isc);
+
+cleanup_subdev:
+ microchip_isc_subdev_cleanup(isc);
+
+unregister_v4l2_device:
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+unprepare_hclk:
+ clk_disable_unprepare(isc->hclock);
+
+ microchip_isc_clk_cleanup(isc);
+
+ return ret;
+}
+
+static int microchip_xisc_remove(struct platform_device *pdev)
+{
+ struct isc_device *isc = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ isc_mc_cleanup(isc);
+
+ microchip_isc_subdev_cleanup(isc);
+
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+ clk_disable_unprepare(isc->hclock);
+
+ microchip_isc_clk_cleanup(isc);
+
+ return 0;
+}
+
+static int __maybe_unused xisc_runtime_suspend(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(isc->hclock);
+
+ return 0;
+}
+
+static int __maybe_unused xisc_runtime_resume(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
+};
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id microchip_xisc_of_match[] = {
+ { .compatible = "microchip,sama7g5-isc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
+#endif
+
+static struct platform_driver microchip_xisc_driver = {
+ .probe = microchip_xisc_probe,
+ .remove = microchip_xisc_remove,
+ .driver = {
+ .name = "microchip-sama7g5-xisc",
+ .pm = &microchip_xisc_dev_pm_ops,
+ .of_match_table = of_match_ptr(microchip_xisc_of_match),
+ },
+};
+
+module_platform_driver(microchip_xisc_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c
index 69c346148070..1c5b94989aec 100644
--- a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c
+++ b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c
@@ -38,7 +38,7 @@ static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry)
if (entry->vde->domain)
tegra_vde_iommu_unmap(entry->vde, entry->iova);
- dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir);
+ dma_buf_unmap_attachment_unlocked(entry->a, entry->sgt, entry->dma_dir);
dma_buf_detach(dmabuf, entry->a);
dma_buf_put(dmabuf);
@@ -102,7 +102,7 @@ int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde,
goto err_unlock;
}
- sgt = dma_buf_map_attachment(attachment, dma_dir);
+ sgt = dma_buf_map_attachment_unlocked(attachment, dma_dir);
if (IS_ERR(sgt)) {
dev_err(dev, "Failed to get dmabufs sg_table\n");
err = PTR_ERR(sgt);
@@ -152,7 +152,7 @@ ref:
err_free:
kfree(entry);
err_unmap:
- dma_buf_unmap_attachment(attachment, sgt, dma_dir);
+ dma_buf_unmap_attachment_unlocked(attachment, sgt, dma_dir);
err_detach:
dma_buf_detach(dmabuf, attachment);
err_unlock:
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 5917634889b5..730f39971e1c 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -4,6 +4,19 @@
comment "NXP media platform drivers"
+config VIDEO_IMX7_CSI
+ tristate "NXP CSI Bridge driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on HAS_DMA
+ depends on VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Driver for the NXP Camera Sensor Interface (CSI) Bridge. This device
+ is found in the i.MX6UL/L, i.MX7 and i.MX8M[MQ] SoCs.
+
config VIDEO_IMX_MIPI_CSIS
tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 81ab304ef31c..1a129b58d99e 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -3,6 +3,7 @@
obj-y += dw100/
obj-y += imx-jpeg/
+obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
index 9418fcf740a8..ef28122a5ed4 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
@@ -76,12 +76,14 @@ void print_wrapper_info(struct device *dev, void __iomem *reg)
void mxc_jpeg_enable_irq(void __iomem *reg, int slot)
{
- writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
+ writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
+ writel(0xF0C, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
}
void mxc_jpeg_disable_irq(void __iomem *reg, int slot)
{
writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
+ writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
}
void mxc_jpeg_sw_reset(void __iomem *reg)
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 32fd04a3d8bb..6cd015a35f7c 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -69,7 +69,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.fourcc = V4L2_PIX_FMT_JPEG,
.subsampling = -1,
.nc = -1,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.flags = MXC_JPEG_FMT_TYPE_ENC,
},
{
@@ -78,11 +79,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
.nc = 3,
.depth = 24,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
.precision = 8,
+ .is_rgb = 1,
},
{
.name = "ABGR", /* ABGR packed format */
@@ -90,11 +93,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
.nc = 4,
.depth = 32,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
.precision = 8,
+ .is_rgb = 1,
},
{
.name = "YUV420", /* 1st plane = Y, 2nd plane = UV */
@@ -102,7 +107,21 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
.nc = 3,
.depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */
- .colplanes = 2, /* 1 plane Y, 1 plane UV interleaved */
+ .mem_planes = 2,
+ .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */
+ .h_align = 4,
+ .v_align = 4,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
+ },
+ {
+ .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .nc = 3,
+ .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */
+ .mem_planes = 1,
+ .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */
.h_align = 4,
.v_align = 4,
.flags = MXC_JPEG_FMT_TYPE_RAW,
@@ -114,7 +133,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
.nc = 3,
.depth = 16,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.h_align = 4,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
@@ -126,7 +146,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
.nc = 3,
.depth = 24,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
@@ -138,7 +159,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
.nc = 1,
.depth = 8,
- .colplanes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
@@ -330,6 +352,10 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-3)");
+static unsigned int hw_timeout = 2000;
+module_param(hw_timeout, int, 0644);
+MODULE_PARM_DESC(hw_timeout, "MXC JPEG hw timeout, the number of milliseconds");
+
static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision);
static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q);
@@ -415,6 +441,7 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc)
return MXC_JPEG_GRAY;
case V4L2_PIX_FMT_YUYV:
return MXC_JPEG_YUV422;
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
return MXC_JPEG_YUV420;
case V4L2_PIX_FMT_YUV24:
@@ -441,12 +468,17 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
struct vb2_buffer *jpeg_buf, int offset)
{
int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK;
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(raw_buf->vb2_queue);
+ struct mxc_jpeg_q_data *q_data;
+ q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type);
desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0);
desc->buf_base1 = 0;
if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
- WARN_ON(raw_buf->num_planes < 2);
- desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1);
+ if (raw_buf->num_planes == 2)
+ desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1);
+ else
+ desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0];
}
desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) +
offset;
@@ -519,7 +551,6 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg,
GFP_ATOMIC);
if (!cfg_stm)
goto err;
- memset(cfg_stm, 0, MXC_JPEG_MAX_CFG_STREAM);
jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm;
skip_alloc:
@@ -570,6 +601,48 @@ static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx,
}
}
+static void mxc_jpeg_job_finish(struct mxc_jpeg_ctx *ctx, enum vb2_buffer_state state, bool reset)
+{
+ struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+ void __iomem *reg = jpeg->base_reg;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf);
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, state);
+ v4l2_m2m_buf_done(dst_buf, state);
+
+ mxc_jpeg_disable_irq(reg, ctx->slot);
+ ctx->mxc_jpeg->slot_data[ctx->slot].used = false;
+ if (reset)
+ mxc_jpeg_sw_reset(reg);
+}
+
+static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no)
+{
+ const struct mxc_jpeg_fmt *fmt = q_data->fmt;
+ u32 size;
+ int i;
+
+ if (plane_no >= fmt->mem_planes)
+ return 0;
+
+ if (fmt->mem_planes == fmt->comp_planes)
+ return q_data->sizeimage[plane_no];
+
+ if (plane_no < fmt->mem_planes - 1)
+ return q_data->sizeimage[plane_no];
+
+ size = q_data->sizeimage[fmt->mem_planes - 1];
+ for (i = fmt->mem_planes; i < fmt->comp_planes; i++)
+ size += q_data->sizeimage[i];
+
+ return size;
+}
+
static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
{
struct mxc_jpeg_dev *jpeg = priv;
@@ -602,6 +675,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
goto job_unlock;
}
+ if (!jpeg->slot_data[slot].used)
+ goto job_unlock;
+
dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */
@@ -646,11 +722,11 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
payload);
} else {
q_data = mxc_jpeg_get_q_data(ctx, cap_type);
- payload = q_data->sizeimage[0];
+ payload = mxc_jpeg_get_plane_size(q_data, 0);
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload);
vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
- if (q_data->fmt->colplanes == 2) {
- payload = q_data->sizeimage[1];
+ if (q_data->fmt->mem_planes == 2) {
+ payload = mxc_jpeg_get_plane_size(q_data, 1);
vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload);
}
dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n",
@@ -666,14 +742,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
buf_state = VB2_BUF_STATE_DONE;
buffers_done:
- mxc_jpeg_disable_irq(reg, ctx->slot);
- jpeg->slot_data[slot].used = false; /* unused, but don't free */
- mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf);
- v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
- v4l2_m2m_buf_done(src_buf, buf_state);
- v4l2_m2m_buf_done(dst_buf, buf_state);
+ mxc_jpeg_job_finish(ctx, buf_state, false);
spin_unlock(&jpeg->hw_lock);
+ cancel_delayed_work(&ctx->task_timer);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
return IRQ_HANDLED;
job_unlock:
@@ -694,6 +765,7 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
_bswap16(&sof->width);
switch (fourcc) {
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
sof->components_no = 3;
sof->comp[0].v = 0x2;
@@ -730,6 +802,7 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos,
u8 *sof_u8 = (u8 *)sos;
switch (fourcc) {
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
sos->components_no = 3;
break;
@@ -902,8 +975,8 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
jpeg->slot_data[slot].cfg_stream_size =
mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
q_data->fmt->fourcc,
- q_data->w,
- q_data->h);
+ q_data->crop.width,
+ q_data->crop.height);
/* chain the config descriptor with the encoding descriptor */
cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
@@ -920,11 +993,13 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
desc->next_descpt_ptr = 0; /* end of chain */
/* use adjusted resolution for CAST IP job */
- w = q_data->w_adjusted;
- h = q_data->h_adjusted;
+ w = q_data->crop.width;
+ h = q_data->crop.height;
+ v4l_bound_align_image(&w, w, MXC_JPEG_MAX_WIDTH, q_data->fmt->h_align,
+ &h, h, MXC_JPEG_MAX_HEIGHT, q_data->fmt->v_align, 0);
mxc_jpeg_set_res(desc, w, h);
- mxc_jpeg_set_line_pitch(desc, w * (q_data->fmt->depth / 8));
- mxc_jpeg_set_bufsize(desc, desc->line_pitch * h);
+ mxc_jpeg_set_line_pitch(desc, q_data->bytesperline[0]);
+ mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(dst_buf, 0), 1024));
img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
if (img_fmt == MXC_JPEG_INVALID)
dev_err(jpeg->dev, "No valid image format detected\n");
@@ -943,6 +1018,32 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
}
+static const struct mxc_jpeg_fmt *mxc_jpeg_get_sibling_format(const struct mxc_jpeg_fmt *fmt)
+{
+ int i;
+
+ for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) {
+ if (mxc_formats[i].subsampling == fmt->subsampling &&
+ mxc_formats[i].nc == fmt->nc &&
+ mxc_formats[i].precision == fmt->precision &&
+ mxc_formats[i].is_rgb == fmt->is_rgb &&
+ mxc_formats[i].fourcc != fmt->fourcc)
+ return &mxc_formats[i];
+ }
+
+ return NULL;
+}
+
+static bool mxc_jpeg_compare_format(const struct mxc_jpeg_fmt *fmt1,
+ const struct mxc_jpeg_fmt *fmt2)
+{
+ if (fmt1 == fmt2)
+ return true;
+ if (mxc_jpeg_get_sibling_format(fmt1) == fmt2)
+ return true;
+ return false;
+}
+
static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
struct mxc_jpeg_src_buf *jpeg_src_buf)
{
@@ -953,6 +1054,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
return false;
q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (mxc_jpeg_compare_format(q_data_cap->fmt, jpeg_src_buf->fmt))
+ jpeg_src_buf->fmt = q_data_cap->fmt;
if (q_data_cap->fmt != jpeg_src_buf->fmt ||
q_data_cap->w != jpeg_src_buf->w ||
q_data_cap->h != jpeg_src_buf->h) {
@@ -973,6 +1076,10 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
q_data_cap->fmt = jpeg_src_buf->fmt;
q_data_cap->w_adjusted = q_data_cap->w;
q_data_cap->h_adjusted = q_data_cap->h;
+ q_data_cap->crop.left = 0;
+ q_data_cap->crop.top = 0;
+ q_data_cap->crop.width = jpeg_src_buf->w;
+ q_data_cap->crop.height = jpeg_src_buf->h;
/*
* align up the resolution for CAST IP,
@@ -985,7 +1092,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
&q_data_cap->h_adjusted,
q_data_cap->h_adjusted, /* adjust up */
MXC_JPEG_MAX_HEIGHT,
- 0,
+ q_data_cap->fmt->v_align,
0);
/* setup bytesperline/sizeimage for capture queue */
@@ -994,6 +1101,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
notify_src_chg(ctx);
ctx->source_change = 1;
}
+
return ctx->source_change ? true : false;
}
@@ -1004,6 +1112,23 @@ static int mxc_jpeg_job_ready(void *priv)
return ctx->source_change ? 0 : 1;
}
+static void mxc_jpeg_device_run_timeout(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mxc_jpeg_ctx *ctx = container_of(dwork, struct mxc_jpeg_ctx, task_timer);
+ struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
+ if (ctx->slot < MXC_MAX_SLOTS && ctx->mxc_jpeg->slot_data[ctx->slot].used) {
+ dev_warn(jpeg->dev, "%s timeout, cancel it\n",
+ ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? "decode" : "encode");
+ mxc_jpeg_job_finish(ctx, VB2_BUF_STATE_ERROR, true);
+ v4l2_m2m_job_finish(ctx->mxc_jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ }
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+}
+
static void mxc_jpeg_device_run(void *priv)
{
struct mxc_jpeg_ctx *ctx = priv;
@@ -1035,9 +1160,9 @@ static void mxc_jpeg_device_run(void *priv)
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf);
- if (q_data_cap->fmt->colplanes != dst_buf->vb2_buf.num_planes) {
+ if (q_data_cap->fmt->mem_planes != dst_buf->vb2_buf.num_planes) {
dev_err(dev, "Capture format %s has %d planes, but capture buffer has %d planes\n",
- q_data_cap->fmt->name, q_data_cap->fmt->colplanes,
+ q_data_cap->fmt->name, q_data_cap->fmt->mem_planes,
dst_buf->vb2_buf.num_planes);
jpeg_src_buf->jpeg_parse_error = true;
}
@@ -1089,6 +1214,7 @@ static void mxc_jpeg_device_run(void *priv)
&src_buf->vb2_buf, &dst_buf->vb2_buf);
mxc_jpeg_dec_mode_go(dev, reg);
}
+ schedule_delayed_work(&ctx->task_timer, msecs_to_jiffies(hw_timeout));
end:
spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
}
@@ -1098,6 +1224,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
{
struct v4l2_fh *fh = file->private_data;
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ unsigned long flags;
int ret;
ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
@@ -1107,7 +1234,9 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)))
return 0;
+ spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd);
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
if (ret < 0)
return ret;
@@ -1128,6 +1257,7 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
{
struct v4l2_fh *fh = file->private_data;
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ unsigned long flags;
int ret;
ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
@@ -1138,7 +1268,9 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
!vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx)))
return 0;
+ spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd);
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
if (ret < 0)
return 0;
@@ -1161,39 +1293,27 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
{
struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
struct mxc_jpeg_q_data *q_data = NULL;
- struct mxc_jpeg_q_data tmp_q;
int i;
q_data = mxc_jpeg_get_q_data(ctx, q->type);
if (!q_data)
return -EINVAL;
- tmp_q.fmt = q_data->fmt;
- tmp_q.w = q_data->w_adjusted;
- tmp_q.h = q_data->h_adjusted;
- for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) {
- tmp_q.bytesperline[i] = q_data->bytesperline[i];
- tmp_q.sizeimage[i] = q_data->sizeimage[i];
- }
- mxc_jpeg_sizeimage(&tmp_q);
- for (i = 0; i < MXC_JPEG_MAX_PLANES; i++)
- tmp_q.sizeimage[i] = max(tmp_q.sizeimage[i], q_data->sizeimage[i]);
-
/* Handle CREATE_BUFS situation - *nplanes != 0 */
if (*nplanes) {
- if (*nplanes != q_data->fmt->colplanes)
+ if (*nplanes != q_data->fmt->mem_planes)
return -EINVAL;
for (i = 0; i < *nplanes; i++) {
- if (sizes[i] < tmp_q.sizeimage[i])
+ if (sizes[i] < mxc_jpeg_get_plane_size(q_data, i))
return -EINVAL;
}
return 0;
}
/* Handle REQBUFS situation */
- *nplanes = q_data->fmt->colplanes;
+ *nplanes = q_data->fmt->mem_planes;
for (i = 0; i < *nplanes; i++)
- sizes[i] = tmp_q.sizeimage[i];
+ sizes[i] = mxc_jpeg_get_plane_size(q_data, i);
return 0;
}
@@ -1238,7 +1358,8 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
}
- v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
+ if (V4L2_TYPE_IS_OUTPUT(q->type) || !ctx->source_change)
+ v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
if (V4L2_TYPE_IS_OUTPUT(q->type) &&
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) {
notify_eos(ctx);
@@ -1277,19 +1398,40 @@ static int mxc_jpeg_valid_comp_id(struct device *dev,
return valid;
}
+static bool mxc_jpeg_match_image_format(const struct mxc_jpeg_fmt *fmt,
+ const struct v4l2_jpeg_header *header)
+{
+ if (fmt->subsampling != header->frame.subsampling ||
+ fmt->nc != header->frame.num_components ||
+ fmt->precision != header->frame.precision)
+ return false;
+
+ /*
+ * If the transform flag from APP14 marker is 0, images that are
+ * encoded with 3 components have RGB colorspace, see Recommendation
+ * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding
+ */
+ if (header->frame.subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) {
+ u8 is_rgb = header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB ? 1 : 0;
+
+ if (is_rgb != fmt->is_rgb)
+ return false;
+ }
+ return true;
+}
+
static u32 mxc_jpeg_get_image_format(struct device *dev,
const struct v4l2_jpeg_header *header)
{
int i;
u32 fourcc = 0;
- for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++)
- if (mxc_formats[i].subsampling == header->frame.subsampling &&
- mxc_formats[i].nc == header->frame.num_components &&
- mxc_formats[i].precision == header->frame.precision) {
+ for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) {
+ if (mxc_jpeg_match_image_format(&mxc_formats[i], header)) {
fourcc = mxc_formats[i].fourcc;
break;
}
+ }
if (fourcc == 0) {
dev_err(dev,
"Could not identify image format nc=%d, subsampling=%d, precision=%d\n",
@@ -1298,17 +1440,6 @@ static u32 mxc_jpeg_get_image_format(struct device *dev,
header->frame.precision);
return fourcc;
}
- /*
- * If the transform flag from APP14 marker is 0, images that are
- * encoded with 3 components have RGB colorspace, see Recommendation
- * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding
- */
- if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) {
- if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB)
- fourcc = V4L2_PIX_FMT_BGR24;
- else
- fourcc = V4L2_PIX_FMT_YUV24;
- }
return fourcc;
}
@@ -1325,17 +1456,17 @@ static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision)
* applies to the first plane and is divided by the same factor
* as the width field for the other planes
*/
- q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8);
+ q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8);
q->bytesperline[1] = q->bytesperline[0];
} else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) {
- q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * 2;
+ q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8) * 2;
q->bytesperline[1] = 0;
} else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) {
- q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * q->fmt->nc;
+ q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8) * q->fmt->nc;
q->bytesperline[1] = 0;
} else {
/* grayscale */
- q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8);
+ q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8);
q->bytesperline[1] = 0;
}
}
@@ -1354,9 +1485,9 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q)
/* jpeg stream size must be multiple of 1K */
q->sizeimage[0] = ALIGN(q->sizeimage[0], 1024);
} else {
- q->sizeimage[0] = q->bytesperline[0] * q->h;
+ q->sizeimage[0] = q->bytesperline[0] * q->h_adjusted;
q->sizeimage[1] = 0;
- if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
q->sizeimage[1] = q->sizeimage[0] / 2;
}
}
@@ -1365,6 +1496,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
{
struct device *dev = ctx->mxc_jpeg->dev;
struct mxc_jpeg_q_data *q_data_out;
+ struct mxc_jpeg_q_data *q_data_cap;
u32 fourcc;
struct v4l2_jpeg_header header;
struct mxc_jpeg_sof *psof = NULL;
@@ -1422,7 +1554,11 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
if (!mxc_jpeg_valid_comp_id(dev, psof, psos))
dev_warn(dev, "JPEG component ids should be 0-3 or 1-4");
- fourcc = mxc_jpeg_get_image_format(dev, &header);
+ q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (q_data_cap->fmt && mxc_jpeg_match_image_format(q_data_cap->fmt, &header))
+ fourcc = q_data_cap->fmt->fourcc;
+ else
+ fourcc = mxc_jpeg_get_image_format(dev, &header);
if (fourcc == 0)
return -EINVAL;
@@ -1498,8 +1634,8 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
if (!q_data)
return -EINVAL;
- for (i = 0; i < q_data->fmt->colplanes; i++) {
- sizeimage = q_data->sizeimage[i];
+ for (i = 0; i < q_data->fmt->mem_planes; i++) {
+ sizeimage = mxc_jpeg_get_plane_size(q_data, i);
if (vb2_plane_size(vb, i) < sizeimage) {
dev_err(dev, "plane %d too small (%lu < %lu)",
i, vb2_plane_size(vb, i), sizeimage);
@@ -1578,6 +1714,10 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx)
q[i]->h = MXC_JPEG_DEFAULT_HEIGHT;
q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH;
q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT;
+ q[i]->crop.left = 0;
+ q[i]->crop.top = 0;
+ q[i]->crop.width = MXC_JPEG_DEFAULT_WIDTH;
+ q[i]->crop.height = MXC_JPEG_DEFAULT_HEIGHT;
mxc_jpeg_bytesperline(q[i], q[i]->fmt->precision);
mxc_jpeg_sizeimage(q[i]);
}
@@ -1672,6 +1812,7 @@ static int mxc_jpeg_open(struct file *file)
ctx->fh.ctrl_handler = &ctx->ctrl_handler;
mxc_jpeg_set_default_params(ctx);
ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */
+ INIT_DELAYED_WORK(&ctx->task_timer, mxc_jpeg_device_run_timeout);
if (mxc_jpeg->mode == MXC_JPEG_DECODE)
dev_dbg(dev, "Opened JPEG decoder instance %p\n", ctx);
@@ -1721,10 +1862,25 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
* (more precisely what was propagated on capture queue
* after jpeg parse on the output buffer)
*/
- if (f->index)
- return -EINVAL;
- f->pixelformat = q_data->fmt->fourcc;
- return 0;
+ int ret = -EINVAL;
+ const struct mxc_jpeg_fmt *sibling;
+
+ switch (f->index) {
+ case 0:
+ f->pixelformat = q_data->fmt->fourcc;
+ ret = 0;
+ break;
+ case 1:
+ sibling = mxc_jpeg_get_sibling_format(q_data->fmt);
+ if (sibling) {
+ f->pixelformat = sibling->fourcc;
+ ret = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
}
}
@@ -1744,55 +1900,105 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
return 0;
}
-static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt,
- struct mxc_jpeg_ctx *ctx, int q_type)
+static u32 mxc_jpeg_get_fmt_type(struct mxc_jpeg_ctx *ctx, u32 type)
+{
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
+ return V4L2_TYPE_IS_OUTPUT(type) ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW;
+ else
+ return V4L2_TYPE_IS_CAPTURE(type) ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW;
+}
+
+static u32 mxc_jpeg_get_default_fourcc(struct mxc_jpeg_ctx *ctx, u32 type)
+{
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
+ return V4L2_TYPE_IS_OUTPUT(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT;
+ else
+ return V4L2_TYPE_IS_CAPTURE(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT;
+}
+
+static u32 mxc_jpeg_try_fourcc(struct mxc_jpeg_ctx *ctx, u32 fourcc)
+{
+ const struct mxc_jpeg_fmt *sibling;
+ struct mxc_jpeg_q_data *q_data_cap;
+
+ if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE)
+ return fourcc;
+ if (!ctx->header_parsed)
+ return fourcc;
+
+ q_data_cap = &ctx->cap_q;
+ if (q_data_cap->fmt->fourcc == fourcc)
+ return fourcc;
+
+ sibling = mxc_jpeg_get_sibling_format(q_data_cap->fmt);
+ if (sibling && sibling->fourcc == fourcc)
+ return sibling->fourcc;
+
+ return q_data_cap->fmt->fourcc;
+}
+
+static int mxc_jpeg_try_fmt(struct v4l2_format *f,
+ struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_q_data *q_data)
{
+ const struct mxc_jpeg_fmt *fmt;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *pfmt;
+ u32 fourcc = f->fmt.pix_mp.pixelformat;
u32 w = (pix_mp->width < MXC_JPEG_MAX_WIDTH) ?
pix_mp->width : MXC_JPEG_MAX_WIDTH;
u32 h = (pix_mp->height < MXC_JPEG_MAX_HEIGHT) ?
pix_mp->height : MXC_JPEG_MAX_HEIGHT;
int i;
- struct mxc_jpeg_q_data tmp_q;
+
+ fmt = mxc_jpeg_find_format(ctx, fourcc);
+ if (!fmt || fmt->flags != mxc_jpeg_get_fmt_type(ctx, f->type)) {
+ dev_warn(ctx->mxc_jpeg->dev, "Format not supported: %c%c%c%c, use the default.\n",
+ (fourcc & 0xff),
+ (fourcc >> 8) & 0xff,
+ (fourcc >> 16) & 0xff,
+ (fourcc >> 24) & 0xff);
+ fourcc = mxc_jpeg_get_default_fourcc(ctx, f->type);
+ fmt = mxc_jpeg_find_format(ctx, fourcc);
+ if (!fmt)
+ return -EINVAL;
+ f->fmt.pix_mp.pixelformat = fourcc;
+ }
+ q_data->fmt = fmt;
memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->num_planes = fmt->colplanes;
+ pix_mp->num_planes = fmt->mem_planes;
pix_mp->pixelformat = fmt->fourcc;
- pix_mp->width = w;
- pix_mp->height = h;
- v4l_bound_align_image(&w,
+ q_data->w = w;
+ q_data->h = h;
+ q_data->w_adjusted = w;
+ q_data->h_adjusted = h;
+ v4l_bound_align_image(&q_data->w_adjusted,
w, /* adjust upwards*/
MXC_JPEG_MAX_WIDTH,
fmt->h_align,
- &h,
+ &q_data->h_adjusted,
h, /* adjust upwards*/
MXC_JPEG_MAX_HEIGHT,
- 0,
+ fmt->v_align,
0);
-
- /* get user input into the tmp_q */
- tmp_q.w = w;
- tmp_q.h = h;
- tmp_q.fmt = fmt;
for (i = 0; i < pix_mp->num_planes; i++) {
pfmt = &pix_mp->plane_fmt[i];
- tmp_q.bytesperline[i] = pfmt->bytesperline;
- tmp_q.sizeimage[i] = pfmt->sizeimage;
+ q_data->bytesperline[i] = pfmt->bytesperline;
+ q_data->sizeimage[i] = pfmt->sizeimage;
}
- /* calculate bytesperline & sizeimage into the tmp_q */
- mxc_jpeg_bytesperline(&tmp_q, fmt->precision);
- mxc_jpeg_sizeimage(&tmp_q);
+ /* calculate bytesperline & sizeimage */
+ mxc_jpeg_bytesperline(q_data, fmt->precision);
+ mxc_jpeg_sizeimage(q_data);
/* adjust user format according to our calculations */
for (i = 0; i < pix_mp->num_planes; i++) {
pfmt = &pix_mp->plane_fmt[i];
memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
- pfmt->bytesperline = tmp_q.bytesperline[i];
- pfmt->sizeimage = tmp_q.sizeimage[i];
+ pfmt->bytesperline = q_data->bytesperline[i];
+ pfmt->sizeimage = mxc_jpeg_get_plane_size(q_data, i);
}
/* fix colorspace information to sRGB for both output & capture */
@@ -1806,6 +2012,16 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm
*/
pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ if (fmt->flags == MXC_JPEG_FMT_TYPE_RAW) {
+ q_data->crop.left = 0;
+ q_data->crop.top = 0;
+ q_data->crop.width = q_data->w;
+ q_data->crop.height = q_data->h;
+ }
+
+ pix_mp->width = q_data->w_adjusted;
+ pix_mp->height = q_data->h_adjusted;
+
return 0;
}
@@ -1815,29 +2031,17 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
- const struct mxc_jpeg_fmt *fmt;
- u32 fourcc = f->fmt.pix_mp.pixelformat;
-
- int q_type = (jpeg->mode == MXC_JPEG_DECODE) ?
- MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
+ struct mxc_jpeg_q_data tmp_q;
if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type);
return -EINVAL;
}
- fmt = mxc_jpeg_find_format(ctx, fourcc);
- if (!fmt || fmt->flags != q_type) {
- dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n",
- (fourcc & 0xff),
- (fourcc >> 8) & 0xff,
- (fourcc >> 16) & 0xff,
- (fourcc >> 24) & 0xff);
- f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_DECODE) ?
- MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG;
- fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
- }
- return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
+ if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(f->type))
+ f->fmt.pix_mp.pixelformat = mxc_jpeg_try_fourcc(ctx, f->fmt.pix_mp.pixelformat);
+
+ return mxc_jpeg_try_fmt(f, ctx, &tmp_q);
}
static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
@@ -1846,88 +2050,55 @@ static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
- const struct mxc_jpeg_fmt *fmt;
- u32 fourcc = f->fmt.pix_mp.pixelformat;
-
- int q_type = (jpeg->mode == MXC_JPEG_ENCODE) ?
- MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
+ struct mxc_jpeg_q_data tmp_q;
if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type);
return -EINVAL;
}
- fmt = mxc_jpeg_find_format(ctx, fourcc);
- if (!fmt || fmt->flags != q_type) {
- dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n",
- (fourcc & 0xff),
- (fourcc >> 8) & 0xff,
- (fourcc >> 16) & 0xff,
- (fourcc >> 24) & 0xff);
- f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_ENCODE) ?
- MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG;
- fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
- }
- return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
+ return mxc_jpeg_try_fmt(f, ctx, &tmp_q);
+}
+
+static void mxc_jpeg_s_parsed_fmt(struct mxc_jpeg_ctx *ctx, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mxc_jpeg_q_data *q_data_cap;
+
+ if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE || !V4L2_TYPE_IS_CAPTURE(f->type))
+ return;
+ if (!ctx->header_parsed)
+ return;
+
+ q_data_cap = mxc_jpeg_get_q_data(ctx, f->type);
+ pix_mp->pixelformat = mxc_jpeg_try_fourcc(ctx, pix_mp->pixelformat);
+ pix_mp->width = q_data_cap->w;
+ pix_mp->height = q_data_cap->h;
}
static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
struct v4l2_format *f)
{
struct vb2_queue *vq;
- struct mxc_jpeg_q_data *q_data = NULL;
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
- int i;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
- q_data = mxc_jpeg_get_q_data(ctx, f->type);
-
if (vb2_is_busy(vq)) {
v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
return -EBUSY;
}
- q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat);
- q_data->w = pix_mp->width;
- q_data->h = pix_mp->height;
-
- q_data->w_adjusted = q_data->w;
- q_data->h_adjusted = q_data->h;
- /*
- * align up the resolution for CAST IP,
- * but leave the buffer resolution unchanged
- */
- v4l_bound_align_image(&q_data->w_adjusted,
- q_data->w_adjusted, /* adjust upwards */
- MXC_JPEG_MAX_WIDTH,
- q_data->fmt->h_align,
- &q_data->h_adjusted,
- q_data->h_adjusted, /* adjust upwards */
- MXC_JPEG_MAX_HEIGHT,
- q_data->fmt->v_align,
- 0);
-
- for (i = 0; i < pix_mp->num_planes; i++) {
- q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
- q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
- }
+ mxc_jpeg_s_parsed_fmt(ctx, f);
- return 0;
+ return mxc_jpeg_try_fmt(f, ctx, mxc_jpeg_get_q_data(ctx, f->type));
}
static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- int ret;
-
- ret = mxc_jpeg_try_fmt_vid_cap(file, priv, f);
- if (ret)
- return ret;
-
return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
}
@@ -1941,10 +2112,6 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
struct v4l2_format fc;
- ret = mxc_jpeg_try_fmt_vid_out(file, priv, f);
- if (ret)
- return ret;
-
ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
if (ret)
return ret;
@@ -1990,6 +2157,10 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
pix_mp->width = q_data->w;
pix_mp->height = q_data->h;
pix_mp->field = V4L2_FIELD_NONE;
+ if (q_data->fmt->flags == MXC_JPEG_FMT_TYPE_RAW) {
+ pix_mp->width = q_data->w_adjusted;
+ pix_mp->height = q_data->h_adjusted;
+ }
/* fix colorspace information to sRGB for both output & capture */
pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
@@ -1997,15 +2168,109 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB;
pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- pix_mp->num_planes = q_data->fmt->colplanes;
+ pix_mp->num_planes = q_data->fmt->mem_planes;
for (i = 0; i < pix_mp->num_planes; i++) {
pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
- pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ pix_mp->plane_fmt[i].sizeimage = mxc_jpeg_get_plane_size(q_data, i);
+ }
+
+ return 0;
+}
+
+static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_q_data *q_data_cap;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ q_data_cap = mxc_jpeg_get_q_data(ctx, s->type);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r = q_data_cap->crop;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data_cap->w_adjusted;
+ s->r.height = q_data_cap->h_adjusted;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
+static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_q_data *q_data_out;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ q_data_out = mxc_jpeg_get_q_data(ctx, s->type);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data_out->w;
+ s->r.height = q_data_out->h;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ s->r = q_data_out->crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
+ return mxc_jpeg_dec_g_selection(file, fh, s);
+ else
+ return mxc_jpeg_enc_g_selection(file, fh, s);
+}
+
+static int mxc_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_q_data *q_data_out;
+
+ if (ctx->mxc_jpeg->mode != MXC_JPEG_ENCODE)
+ return -ENOTTY;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+ if (s->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ q_data_out = mxc_jpeg_get_q_data(ctx, s->type);
+ if (s->r.left || s->r.top)
+ return -EINVAL;
+ if (s->r.width > q_data_out->w || s->r.height > q_data_out->h)
+ return -EINVAL;
+
+ q_data_out->crop.left = 0;
+ q_data_out->crop.top = 0;
+ q_data_out->crop.width = s->r.width;
+ q_data_out->crop.height = s->r.height;
+
+ return 0;
+}
+
static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
@@ -2035,6 +2300,9 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
.vidioc_g_fmt_vid_cap_mplane = mxc_jpeg_g_fmt_vid,
.vidioc_g_fmt_vid_out_mplane = mxc_jpeg_g_fmt_vid,
+ .vidioc_g_selection = mxc_jpeg_g_selection,
+ .vidioc_s_selection = mxc_jpeg_s_selection,
+
.vidioc_subscribe_event = mxc_jpeg_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -2163,6 +2431,8 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
unsigned int slot;
of_id = of_match_node(mxc_jpeg_match, dev->of_node);
+ if (!of_id)
+ return -ENODEV;
mode = *(const int *)of_id->data;
jpeg = devm_kzalloc(dev, sizeof(struct mxc_jpeg_dev), GFP_KERNEL);
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
index c508d41a906f..8fa8c0aec5a2 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
@@ -45,11 +45,13 @@ enum mxc_jpeg_mode {
* @subsampling: subsampling of jpeg components
* @nc: number of color components
* @depth: number of bits per pixel
- * @colplanes: number of color planes (1 for packed formats)
+ * @mem_planes: number of memory planes (1 for packed formats)
+ * @comp_planes:number of component planes, which includes the alpha plane (1 to 4).
* @h_align: horizontal alignment order (align to 2^h_align)
* @v_align: vertical alignment order (align to 2^v_align)
* @flags: flags describing format applicability
* @precision: jpeg sample precision
+ * @is_rgb: is an RGB pixel format
*/
struct mxc_jpeg_fmt {
const char *name;
@@ -57,11 +59,13 @@ struct mxc_jpeg_fmt {
enum v4l2_jpeg_chroma_subsampling subsampling;
int nc;
int depth;
- int colplanes;
+ int mem_planes;
+ int comp_planes;
int h_align;
int v_align;
u32 flags;
u8 precision;
+ u8 is_rgb;
};
struct mxc_jpeg_desc {
@@ -84,6 +88,7 @@ struct mxc_jpeg_q_data {
int h;
int h_adjusted;
unsigned int sequence;
+ struct v4l2_rect crop;
};
struct mxc_jpeg_ctx {
@@ -97,6 +102,7 @@ struct mxc_jpeg_ctx {
bool header_parsed;
struct v4l2_ctrl_handler ctrl_handler;
u8 jpeg_quality;
+ struct delayed_work task_timer;
};
struct mxc_jpeg_slot_data {
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index e5b550ccfa22..886374d3a6ff 100644
--- a/drivers/staging/media/imx/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -8,7 +8,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gcd.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
@@ -200,7 +199,7 @@ to_imx7_csi_vb2_buffer(struct vb2_buffer *vb)
struct imx7_csi_dma_buf {
void *virt;
- dma_addr_t phys;
+ dma_addr_t dma_addr;
unsigned long len;
};
@@ -384,13 +383,13 @@ static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
}
-static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,
+static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t dma_addr,
int buf_num)
{
if (buf_num == 1)
- imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB2);
+ imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB2);
else
- imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);
+ imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB1);
}
static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi);
@@ -399,21 +398,22 @@ static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
{
struct imx7_csi_vb2_buffer *buf;
struct vb2_buffer *vb2_buf;
- dma_addr_t phys[2];
int i;
for (i = 0; i < 2; i++) {
+ dma_addr_t dma_addr;
+
buf = imx7_csi_video_next_buf(csi);
if (buf) {
csi->active_vb2_buf[i] = buf;
vb2_buf = &buf->vbuf.vb2_buf;
- phys[i] = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
+ dma_addr = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
} else {
csi->active_vb2_buf[i] = NULL;
- phys[i] = csi->underrun_buf.phys;
+ dma_addr = csi->underrun_buf.dma_addr;
}
- imx7_csi_update_buf(csi, phys[i], i);
+ imx7_csi_update_buf(csi, dma_addr, i);
}
}
@@ -440,10 +440,10 @@ static void imx7_csi_free_dma_buf(struct imx7_csi *csi,
struct imx7_csi_dma_buf *buf)
{
if (buf->virt)
- dma_free_coherent(csi->dev, buf->len, buf->virt, buf->phys);
+ dma_free_coherent(csi->dev, buf->len, buf->virt, buf->dma_addr);
buf->virt = NULL;
- buf->phys = 0;
+ buf->dma_addr = 0;
}
static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi,
@@ -452,7 +452,7 @@ static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi,
imx7_csi_free_dma_buf(csi, buf);
buf->len = PAGE_ALIGN(size);
- buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->phys,
+ buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->dma_addr,
GFP_DMA | GFP_KERNEL);
if (!buf->virt)
return -ENOMEM;
@@ -521,9 +521,9 @@ static void imx7_csi_configure(struct imx7_csi *csi)
cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
cr18 &= ~(BIT_CSI_HW_ENABLE | BIT_MIPI_DATA_FORMAT_MASK |
- BIT_DATA_FROM_MIPI | BIT_BASEADDR_CHG_ERR_EN |
- BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL |
- BIT_DEINTERLACE_EN);
+ BIT_DATA_FROM_MIPI | BIT_MIPI_DOUBLE_CMPNT |
+ BIT_BASEADDR_CHG_ERR_EN | BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_SWITCH_EN | BIT_DEINTERLACE_EN);
if (out_pix->field == V4L2_FIELD_INTERLACED) {
cr18 |= BIT_DEINTERLACE_EN;
@@ -713,7 +713,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
{
struct imx7_csi_vb2_buffer *done, *next;
struct vb2_buffer *vb;
- dma_addr_t phys;
+ dma_addr_t dma_addr;
done = csi->active_vb2_buf[csi->buf_num];
if (done) {
@@ -728,14 +728,14 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
/* get next queued buffer */
next = imx7_csi_video_next_buf(csi);
if (next) {
- phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
+ dma_addr = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
csi->active_vb2_buf[csi->buf_num] = next;
} else {
- phys = csi->underrun_buf.phys;
+ dma_addr = csi->underrun_buf.dma_addr;
csi->active_vb2_buf[csi->buf_num] = NULL;
}
- imx7_csi_update_buf(csi, phys, csi->buf_num);
+ imx7_csi_update_buf(csi, dma_addr, csi->buf_num);
}
static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
@@ -806,6 +806,30 @@ static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
* List of supported pixel formats for the subdevs. Keep V4L2_PIX_FMT_UYVY and
* MEDIA_BUS_FMT_UYVY8_2X8 first to match IMX7_CSI_DEF_PIX_FORMAT and
* IMX7_CSI_DEF_MBUS_CODE.
+ *
+ * TODO: Restrict the supported formats list based on the SoC integration.
+ *
+ * The CSI bridge can be configured to sample pixel components from the Rx queue
+ * in single (8bpp) or double (16bpp) component modes. Image format variants
+ * with different sample sizes (ie YUYV_2X8 vs YUYV_1X16) determine the pixel
+ * components sampling size per each clock cycle and their packing mode (see
+ * imx7_csi_configure() for details).
+ *
+ * As the CSI bridge can be interfaced with different IP blocks depending on the
+ * SoC model it is integrated on, the Rx queue sampling size should match the
+ * size of the samples transferred by the transmitting IP block. To avoid
+ * misconfigurations of the capture pipeline, the enumeration of the supported
+ * formats should be restricted to match the pixel source transmitting mode.
+ *
+ * Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2
+ * receiver which operates in dual pixel sampling mode. The CSI bridge should
+ * only expose the 1X16 formats variant which instructs it to operate in dual
+ * pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7,
+ * which supports both serial and parallel input, it should expose both
+ * variants.
+ *
+ * This currently only applies to YUYV formats, but other formats might need to
+ * be handled in the same way.
*/
static const struct imx7_csi_pixfmt pixel_formats[] = {
/*** YUV formats start here ***/
@@ -1296,12 +1320,88 @@ static int imx7_csi_video_buf_prepare(struct vb2_buffer *vb)
return 0;
}
+static bool imx7_csi_fast_track_buffer(struct imx7_csi *csi,
+ struct imx7_csi_vb2_buffer *buf)
+{
+ unsigned long flags;
+ dma_addr_t dma_addr;
+ int buf_num;
+ u32 isr;
+
+ if (!csi->is_streaming)
+ return false;
+
+ dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vbuf.vb2_buf, 0);
+
+ /*
+ * buf_num holds the framebuffer ID of the most recently (*not* the
+ * next anticipated) triggered interrupt. Without loss of generality,
+ * if buf_num is 0, the hardware is capturing to FB2. If FB1 has been
+ * programmed with a dummy buffer (as indicated by active_vb2_buf[0]
+ * being NULL), then we can fast-track the new buffer by programming
+ * its address in FB1 before the hardware completes FB2, instead of
+ * adding it to the buffer queue and incurring a delay of one
+ * additional frame.
+ *
+ * The irqlock prevents races with the interrupt handler that updates
+ * buf_num when it programs the next buffer, but we can still race with
+ * the hardware if we program the buffer in FB1 just after the hardware
+ * completes FB2 and switches to FB1 and before buf_num can be updated
+ * by the interrupt handler for FB2. The fast-tracked buffer would
+ * then be ignored by the hardware while the driver would think it has
+ * successfully been processed.
+ *
+ * To avoid this problem, if we can't avoid the race, we can detect
+ * that we have lost it by checking, after programming the buffer in
+ * FB1, if the interrupt flag indicating completion of FB2 has been
+ * raised. If that is not the case, fast-tracking succeeded, and we can
+ * update active_vb2_buf[0]. Otherwise, we may or may not have lost the
+ * race (as the interrupt flag may have been raised just after
+ * programming FB1 and before we read the interrupt status register),
+ * and we need to assume the worst case of a race loss and queue the
+ * buffer through the slow path.
+ */
+
+ spin_lock_irqsave(&csi->irqlock, flags);
+
+ buf_num = csi->buf_num;
+ if (csi->active_vb2_buf[buf_num]) {
+ spin_unlock_irqrestore(&csi->irqlock, flags);
+ return false;
+ }
+
+ imx7_csi_update_buf(csi, dma_addr, buf_num);
+
+ isr = imx7_csi_reg_read(csi, CSI_CSISR);
+ if (isr & (buf_num ? BIT_DMA_TSF_DONE_FB1 : BIT_DMA_TSF_DONE_FB2)) {
+ /*
+ * The interrupt for the /other/ FB just came (the isr hasn't
+ * run yet though, because we have the lock here); we can't be
+ * sure we've programmed buf_num FB in time, so queue the buffer
+ * to the buffer queue normally. No need to undo writing the FB
+ * register, since we won't return it as active_vb2_buf is NULL,
+ * so it's okay to potentially write it to both FB1 and FB2;
+ * only the one where it was queued normally will be returned.
+ */
+ spin_unlock_irqrestore(&csi->irqlock, flags);
+ return false;
+ }
+
+ csi->active_vb2_buf[buf_num] = buf;
+
+ spin_unlock_irqrestore(&csi->irqlock, flags);
+ return true;
+}
+
static void imx7_csi_video_buf_queue(struct vb2_buffer *vb)
{
struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
struct imx7_csi_vb2_buffer *buf = to_imx7_csi_vb2_buffer(vb);
unsigned long flags;
+ if (imx7_csi_fast_track_buffer(csi, buf))
+ return;
+
spin_lock_irqsave(&csi->q_lock, flags);
list_add_tail(&buf->list, &csi->ready_q);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
index 600150cfc4f7..8e506a805d11 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-170.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
@@ -687,7 +687,12 @@ out_unlock:
*/
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
- /* nop */
+ struct camss *camss = vfe->camss;
+
+ if (vfe->id >= camss->vfe_num)
+ return;
+
+ device_link_del(camss->genpd_link[vfe->id]);
}
/*
@@ -696,6 +701,19 @@ static void vfe_pm_domain_off(struct vfe_device *vfe)
*/
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
+ struct camss *camss = vfe->camss;
+ enum vfe_line_id id = vfe->id;
+
+ if (id >= camss->vfe_num)
+ return 0;
+
+ camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!camss->genpd_link[id])
+ return -EINVAL;
+
return 0;
}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 129585110393..3aa962b5663b 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -494,7 +494,12 @@ out_unlock:
*/
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
- /* nop */
+ struct camss *camss = vfe->camss;
+
+ if (vfe->id >= camss->vfe_num)
+ return;
+
+ device_link_del(camss->genpd_link[vfe->id]);
}
/*
@@ -503,6 +508,19 @@ static void vfe_pm_domain_off(struct vfe_device *vfe)
*/
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
+ struct camss *camss = vfe->camss;
+ enum vfe_line_id id = vfe->id;
+
+ if (id >= camss->vfe_num)
+ return 0;
+
+ camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!camss->genpd_link[id])
+ return -EINVAL;
+
return 0;
}
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 81fb3a5bc1d5..41deda232e4a 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -495,7 +495,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
ret = video_device_pipeline_start(vdev, &video->pipe);
if (ret < 0)
- return ret;
+ goto flush_buffers;
ret = video_check_format(video);
if (ret < 0)
@@ -524,6 +524,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
error:
video_device_pipeline_stop(vdev);
+flush_buffers:
video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
return ret;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 1118c40886d5..9cda284f1e71 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1170,7 +1170,7 @@ static int camss_init_subdevices(struct camss *camss)
}
/* note: SM8250 requires VFE to be initialized before CSID */
- for (i = 0; i < camss->vfe_num; i++) {
+ for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) {
ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
&vfe_res[i], i);
if (ret < 0) {
@@ -1242,7 +1242,7 @@ static int camss_register_entities(struct camss *camss)
goto err_reg_ispif;
}
- for (i = 0; i < camss->vfe_num; i++) {
+ for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) {
ret = msm_vfe_register_entities(&camss->vfe[i],
&camss->v4l2_dev);
if (ret < 0) {
@@ -1314,7 +1314,7 @@ static int camss_register_entities(struct camss *camss)
}
} else {
for (i = 0; i < camss->csid_num; i++)
- for (k = 0; k < camss->vfe_num; k++)
+ for (k = 0; k < camss->vfe_num + camss->vfe_lite_num; k++)
for (j = 0; j < camss->vfe[k].line_num; j++) {
struct v4l2_subdev *csid = &camss->csid[i].subdev;
struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
@@ -1338,7 +1338,7 @@ static int camss_register_entities(struct camss *camss)
return 0;
err_link:
- i = camss->vfe_num;
+ i = camss->vfe_num + camss->vfe_lite_num;
err_reg_vfe:
for (i--; i >= 0; i--)
msm_vfe_unregister_entities(&camss->vfe[i]);
@@ -1377,7 +1377,7 @@ static void camss_unregister_entities(struct camss *camss)
msm_ispif_unregister_entities(camss->ispif);
- for (i = 0; i < camss->vfe_num; i++)
+ for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++)
msm_vfe_unregister_entities(&camss->vfe[i]);
}
@@ -1453,7 +1453,6 @@ static const struct media_device_ops camss_media_ops = {
static int camss_configure_pd(struct camss *camss)
{
struct device *dev = camss->dev;
- int last_pm_domain = 0;
int i;
int ret;
@@ -1465,6 +1464,14 @@ static int camss_configure_pd(struct camss *camss)
return camss->genpd_num;
}
+ /*
+ * If a platform device has just one power domain, then it is attached
+ * at platform_probe() level, thus there shall be no need and even no
+ * option to attach it again, this is the case for CAMSS on MSM8916.
+ */
+ if (camss->genpd_num == 1)
+ return 0;
+
camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
sizeof(*camss->genpd), GFP_KERNEL);
if (!camss->genpd)
@@ -1476,32 +1483,34 @@ static int camss_configure_pd(struct camss *camss)
if (!camss->genpd_link)
return -ENOMEM;
+ /*
+ * VFE power domains are in the beginning of the list, and while all
+ * power domains should be attached, only if TITAN_TOP power domain is
+ * found in the list, it should be linked over here.
+ */
for (i = 0; i < camss->genpd_num; i++) {
camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
if (IS_ERR(camss->genpd[i])) {
ret = PTR_ERR(camss->genpd[i]);
goto fail_pm;
}
+ }
- camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i],
- DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (!camss->genpd_link[i]) {
- dev_pm_domain_detach(camss->genpd[i], true);
+ if (i > camss->vfe_num) {
+ camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1],
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!camss->genpd_link[i - 1]) {
ret = -EINVAL;
goto fail_pm;
}
-
- last_pm_domain = i;
}
return 0;
fail_pm:
- for (i = 0; i < last_pm_domain; i++) {
- device_link_del(camss->genpd_link[i]);
+ for (--i ; i >= 0; i--)
dev_pm_domain_detach(camss->genpd[i], true);
- }
return ret;
}
@@ -1571,13 +1580,15 @@ static int camss_probe(struct platform_device *pdev)
camss->version = CAMSS_845;
camss->csiphy_num = 4;
camss->csid_num = 3;
- camss->vfe_num = 3;
+ camss->vfe_num = 2;
+ camss->vfe_lite_num = 1;
} else if (of_device_is_compatible(dev->of_node,
"qcom,sm8250-camss")) {
camss->version = CAMSS_8250;
camss->csiphy_num = 6;
camss->csid_num = 4;
- camss->vfe_num = 4;
+ camss->vfe_num = 2;
+ camss->vfe_lite_num = 2;
} else {
return -EINVAL;
}
@@ -1599,8 +1610,8 @@ static int camss_probe(struct platform_device *pdev)
return -ENOMEM;
}
- camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
- GFP_KERNEL);
+ camss->vfe = devm_kcalloc(dev, camss->vfe_num + camss->vfe_lite_num,
+ sizeof(*camss->vfe), GFP_KERNEL);
if (!camss->vfe)
return -ENOMEM;
@@ -1698,10 +1709,14 @@ void camss_delete(struct camss *camss)
pm_runtime_disable(camss->dev);
- for (i = 0; i < camss->genpd_num; i++) {
- device_link_del(camss->genpd_link[i]);
+ if (camss->genpd_num == 1)
+ return;
+
+ if (camss->genpd_num > camss->vfe_num)
+ device_link_del(camss->genpd_link[camss->genpd_num - 1]);
+
+ for (i = 0; i < camss->genpd_num; i++)
dev_pm_domain_detach(camss->genpd[i], true);
- }
}
/*
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 0db80cadbbaa..3acd2b3403e8 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -97,6 +97,7 @@ struct camss {
struct csid_device *csid;
struct ispif_device *ispif;
int vfe_num;
+ int vfe_lite_num;
struct vfe_device *vfe;
atomic_t ref_count;
int genpd_num;
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 14b6f1d05991..142d4c74017c 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -38,8 +38,8 @@ static void venus_reset_cpu(struct venus_core *core)
writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR);
writel(0, wrapper_base + WRAPPER_CPA_START_ADDR);
writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR);
- writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR);
- writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR);
+ writel(0, wrapper_base + WRAPPER_NONPIX_START_ADDR);
+ writel(0, wrapper_base + WRAPPER_NONPIX_END_ADDR);
if (IS_V6(core)) {
/* Bring XTSS out of reset */
@@ -68,9 +68,11 @@ int venus_set_hw_state(struct venus_core *core, bool resume)
venus_reset_cpu(core);
} else {
if (IS_V6(core))
- writel(1, core->wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
+ writel(WRAPPER_XTSS_SW_RESET_BIT,
+ core->wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
else
- writel(1, core->wrapper_base + WRAPPER_A9SS_SW_RESET);
+ writel(WRAPPER_A9SS_SW_RESET_BIT,
+ core->wrapper_base + WRAPPER_A9SS_SW_RESET);
}
return 0;
@@ -179,17 +181,15 @@ static int venus_shutdown_no_tz(struct venus_core *core)
if (IS_V6(core)) {
/* Assert the reset to XTSS */
- reg = readl_relaxed(wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
+ reg = readl(wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
reg |= WRAPPER_XTSS_SW_RESET_BIT;
- writel_relaxed(reg, wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
+ writel(reg, wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
} else {
/* Assert the reset to ARM9 */
- reg = readl_relaxed(wrapper_base + WRAPPER_A9SS_SW_RESET);
+ reg = readl(wrapper_base + WRAPPER_A9SS_SW_RESET);
reg |= WRAPPER_A9SS_SW_RESET_BIT;
- writel_relaxed(reg, wrapper_base + WRAPPER_A9SS_SW_RESET);
+ writel(reg, wrapper_base + WRAPPER_A9SS_SW_RESET);
}
- /* Make sure reset is asserted before the mapping is removed */
- mb();
iommu = core->fw.iommu_domain;
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index c93d2906e4c7..48c9084bb4db 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -869,8 +869,8 @@ static int vcodec_domains_get(struct venus_core *core)
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
pd = dev_pm_domain_attach_by_name(dev,
res->vcodec_pmdomains[i]);
- if (IS_ERR(pd))
- return PTR_ERR(pd);
+ if (IS_ERR_OR_NULL(pd))
+ return PTR_ERR(pd) ? : -ENODATA;
core->pmdomains[i] = pd;
}
diff --git a/drivers/media/platform/renesas/Kconfig b/drivers/media/platform/renesas/Kconfig
index 9fd90672ea2d..ed788e991f74 100644
--- a/drivers/media/platform/renesas/Kconfig
+++ b/drivers/media/platform/renesas/Kconfig
@@ -41,6 +41,7 @@ config VIDEO_SH_VOU
Support for the Video Output Unit (VOU) on SuperH SoCs.
source "drivers/media/platform/renesas/rcar-vin/Kconfig"
+source "drivers/media/platform/renesas/rzg2l-cru/Kconfig"
# Mem2mem drivers
diff --git a/drivers/media/platform/renesas/Makefile b/drivers/media/platform/renesas/Makefile
index 3ec226ef5fd2..55854e868887 100644
--- a/drivers/media/platform/renesas/Makefile
+++ b/drivers/media/platform/renesas/Makefile
@@ -4,6 +4,7 @@
#
obj-y += rcar-vin/
+obj-y += rzg2l-cru/
obj-y += vsp1/
obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 2f7daa853ed8..5e53d6b7036c 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -1131,6 +1131,7 @@ static const struct rvin_info rcar_info_h1 = {
.use_mc = false,
.max_width = 2048,
.max_height = 2048,
+ .scaler = rvin_scaler_gen2,
};
static const struct rvin_info rcar_info_m1 = {
@@ -1138,6 +1139,7 @@ static const struct rvin_info rcar_info_m1 = {
.use_mc = false,
.max_width = 2048,
.max_height = 2048,
+ .scaler = rvin_scaler_gen2,
};
static const struct rvin_info rcar_info_gen2 = {
@@ -1145,6 +1147,7 @@ static const struct rvin_info rcar_info_gen2 = {
.use_mc = false,
.max_width = 2048,
.max_height = 2048,
+ .scaler = rvin_scaler_gen2,
};
static const struct rvin_group_route rcar_info_r8a774e1_routes[] = {
@@ -1177,6 +1180,7 @@ static const struct rvin_info rcar_info_r8a7795 = {
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a7795_routes,
+ .scaler = rvin_scaler_gen3,
};
static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = {
@@ -1212,6 +1216,7 @@ static const struct rvin_info rcar_info_r8a7796 = {
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a7796_routes,
+ .scaler = rvin_scaler_gen3,
};
static const struct rvin_group_route rcar_info_r8a77965_routes[] = {
@@ -1229,6 +1234,7 @@ static const struct rvin_info rcar_info_r8a77965 = {
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77965_routes,
+ .scaler = rvin_scaler_gen3,
};
static const struct rvin_group_route rcar_info_r8a77970_routes[] = {
@@ -1271,6 +1277,7 @@ static const struct rvin_info rcar_info_r8a77990 = {
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77990_routes,
+ .scaler = rvin_scaler_gen3,
};
static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
@@ -1284,6 +1291,7 @@ static const struct rvin_info rcar_info_r8a77995 = {
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77995_routes,
+ .scaler = rvin_scaler_gen3,
};
static const struct rvin_info rcar_info_r8a779a0 = {
@@ -1408,13 +1416,21 @@ static int rcar_vin_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vin);
- if (vin->info->use_isp)
+ if (vin->info->use_isp) {
ret = rvin_isp_init(vin);
- else if (vin->info->use_mc)
+ } else if (vin->info->use_mc) {
ret = rvin_csi2_init(vin);
- else
+
+ if (vin->info->scaler &&
+ rvin_group_id_to_master(vin->id) == vin->id)
+ vin->scaler = vin->info->scaler;
+ } else {
ret = rvin_parallel_init(vin);
+ if (vin->info->scaler)
+ vin->scaler = vin->info->scaler;
+ }
+
if (ret) {
rvin_dma_unregister(vin);
return ret;
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index 3aea96d85165..98bfd445a649 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -74,6 +74,10 @@
/* Register offsets specific for Gen3 */
#define VNCSI_IFMD_REG 0x20 /* Video n CSI2 Interface Mode Register */
+#define VNUDS_CTRL_REG 0x80 /* Video n scaling control register */
+#define VNUDS_SCALE_REG 0x84 /* Video n scaling factor register */
+#define VNUDS_PASS_BWIDTH_REG 0x90 /* Video n passband register */
+#define VNUDS_CLIP_SIZE_REG 0xa4 /* Video n UDS output size clipping reg */
/* Register bit fields for R-Car VIN */
/* Video n Main Control Register bits */
@@ -140,6 +144,9 @@
#define VNCSI_IFMD_DES0 (1 << 25)
#define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0)
+/* Video n scaling control register (Gen3) */
+#define VNUDS_CTRL_AMD (1 << 30)
+
struct rvin_buffer {
struct vb2_v4l2_buffer vb;
struct list_head list;
@@ -160,9 +167,17 @@ static u32 rvin_read(struct rvin_dev *vin, u32 offset)
}
/* -----------------------------------------------------------------------------
- * Crop and Scaling Gen2
+ * Crop and Scaling
*/
+static bool rvin_scaler_needed(const struct rvin_dev *vin)
+{
+ return !(vin->crop.width == vin->format.width &&
+ vin->compose.width == vin->format.width &&
+ vin->crop.height == vin->format.height &&
+ vin->compose.height == vin->format.height);
+}
+
struct vin_coeff {
unsigned short xs_value;
u32 coeff_set[24];
@@ -535,7 +550,7 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
}
-static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
+void rvin_scaler_gen2(struct rvin_dev *vin)
{
unsigned int crop_height;
u32 xs, ys;
@@ -583,6 +598,69 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
0, 0);
}
+static unsigned int rvin_uds_scale_ratio(unsigned int in, unsigned int out)
+{
+ unsigned int ratio;
+
+ ratio = in * 4096 / out;
+ return ratio >= 0x10000 ? 0xffff : ratio;
+}
+
+static unsigned int rvin_uds_filter_width(unsigned int ratio)
+{
+ if (ratio >= 0x1000)
+ return 64 * (ratio & 0xf000) / ratio;
+
+ return 64;
+}
+
+void rvin_scaler_gen3(struct rvin_dev *vin)
+{
+ unsigned int ratio_h, ratio_v;
+ unsigned int bwidth_h, bwidth_v;
+ u32 vnmc, clip_size;
+
+ vnmc = rvin_read(vin, VNMC_REG);
+
+ /* Disable scaler if not needed. */
+ if (!rvin_scaler_needed(vin)) {
+ rvin_write(vin, vnmc & ~VNMC_SCLE, VNMC_REG);
+ return;
+ }
+
+ ratio_h = rvin_uds_scale_ratio(vin->crop.width, vin->compose.width);
+ bwidth_h = rvin_uds_filter_width(ratio_h);
+
+ ratio_v = rvin_uds_scale_ratio(vin->crop.height, vin->compose.height);
+ bwidth_v = rvin_uds_filter_width(ratio_v);
+
+ clip_size = vin->compose.width << 16;
+
+ switch (vin->format.field) {
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
+ clip_size |= vin->compose.height / 2;
+ break;
+ default:
+ clip_size |= vin->compose.height;
+ break;
+ }
+
+ rvin_write(vin, vnmc | VNMC_SCLE, VNMC_REG);
+ rvin_write(vin, VNUDS_CTRL_AMD, VNUDS_CTRL_REG);
+ rvin_write(vin, (ratio_h << 16) | ratio_v, VNUDS_SCALE_REG);
+ rvin_write(vin, (bwidth_h << 16) | bwidth_v, VNUDS_PASS_BWIDTH_REG);
+ rvin_write(vin, clip_size, VNUDS_CLIP_SIZE_REG);
+
+ vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u Post-Clip: %ux%u@%u:%u\n",
+ vin->crop.width, vin->crop.height, vin->crop.left,
+ vin->crop.top, vin->compose.width, vin->compose.height,
+ vin->compose.left, vin->compose.top);
+}
+
void rvin_crop_scale_comp(struct rvin_dev *vin)
{
const struct rvin_video_format *fmt;
@@ -594,9 +672,8 @@ void rvin_crop_scale_comp(struct rvin_dev *vin)
rvin_write(vin, vin->crop.top, VNSLPRC_REG);
rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG);
- /* TODO: Add support for the UDS scaler. */
- if (vin->info->model != RCAR_GEN3)
- rvin_crop_scale_comp_gen2(vin);
+ if (vin->scaler)
+ vin->scaler(vin);
fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
stride = vin->format.bytesperline / fmt->bpp;
@@ -984,12 +1061,12 @@ static int rvin_capture_start(struct rvin_dev *vin)
for (slot = 0; slot < HW_BUFFER_NUM; slot++)
rvin_fill_hw_slot(vin, slot);
- rvin_crop_scale_comp(vin);
-
ret = rvin_setup(vin);
if (ret)
return ret;
+ rvin_crop_scale_comp(vin);
+
vin_dbg(vin, "Starting to capture\n");
/* Continuous Frame Capture Mode */
@@ -1234,9 +1311,16 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
return -EPIPE;
}
- if (fmt.format.width != vin->format.width ||
- fmt.format.height != vin->format.height ||
- fmt.format.code != vin->mbus_code)
+ if (rvin_scaler_needed(vin)) {
+ if (!vin->scaler)
+ return -EPIPE;
+ } else {
+ if (fmt.format.width != vin->format.width ||
+ fmt.format.height != vin->format.height)
+ return -EPIPE;
+ }
+
+ if (fmt.format.code != vin->mbus_code)
return -EPIPE;
return 0;
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
index 576059f9bbe3..073f70c6ac68 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
@@ -226,10 +226,10 @@ static int rvin_reset_format(struct rvin_dev *vin)
v4l2_fill_pix_format(&vin->format, &fmt.format);
- vin->src_rect.top = 0;
- vin->src_rect.left = 0;
- vin->src_rect.width = vin->format.width;
- vin->src_rect.height = vin->format.height;
+ vin->crop.top = 0;
+ vin->crop.left = 0;
+ vin->crop.width = vin->format.width;
+ vin->crop.height = vin->format.height;
/* Make use of the hardware interlacer by default. */
if (vin->format.field == V4L2_FIELD_ALTERNATE) {
@@ -239,8 +239,6 @@ static int rvin_reset_format(struct rvin_dev *vin)
rvin_format_align(vin, &vin->format);
- vin->crop = vin->src_rect;
-
vin->compose.top = 0;
vin->compose.left = 0;
vin->compose.width = vin->format.width;
@@ -349,7 +347,6 @@ static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
v4l2_rect_map_inside(&vin->crop, &src_rect);
v4l2_rect_map_inside(&vin->compose, &fmt_rect);
- vin->src_rect = src_rect;
return 0;
}
@@ -428,10 +425,60 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
}
+static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_subdev *sd;
+ unsigned int index;
+ int ret;
+
+ if (vin->info->use_mc) {
+ struct media_pad *pad = media_pad_remote_pad_first(&vin->pad);
+
+ if (!pad)
+ return -EINVAL;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ index = pad->index;
+ } else {
+ sd = vin_to_source(vin);
+ index = vin->parallel.source_pad;
+ }
+
+ fmt.pad = index;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+ if (ret)
+ return ret;
+
+ rect->left = rect->top = 0;
+ rect->width = fmt.format.width;
+ rect->height = fmt.format.height;
+
+ if (fmt.format.field == V4L2_FIELD_ALTERNATE) {
+ switch (vin->format.field) {
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
+ rect->height *= 2;
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int rvin_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
struct rvin_dev *vin = video_drvdata(file);
+ int ret;
+
+ if (!vin->scaler)
+ return -ENOIOCTLCMD;
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -439,9 +486,10 @@ static int rvin_g_selection(struct file *file, void *fh,
switch (s->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- s->r.left = s->r.top = 0;
- s->r.width = vin->src_rect.width;
- s->r.height = vin->src_rect.height;
+ ret = rvin_remote_rectangle(vin, &s->r);
+ if (ret)
+ return ret;
+
break;
case V4L2_SEL_TGT_CROP:
s->r = vin->crop;
@@ -473,6 +521,10 @@ static int rvin_s_selection(struct file *file, void *fh,
.width = 6,
.height = 2,
};
+ int ret;
+
+ if (!vin->scaler)
+ return -ENOIOCTLCMD;
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -482,23 +534,23 @@ static int rvin_s_selection(struct file *file, void *fh,
switch (s->target) {
case V4L2_SEL_TGT_CROP:
/* Can't crop outside of source input */
- max_rect.top = max_rect.left = 0;
- max_rect.width = vin->src_rect.width;
- max_rect.height = vin->src_rect.height;
+ ret = rvin_remote_rectangle(vin, &max_rect);
+ if (ret)
+ return ret;
+
v4l2_rect_map_inside(&r, &max_rect);
- v4l_bound_align_image(&r.width, 6, vin->src_rect.width, 0,
- &r.height, 2, vin->src_rect.height, 0, 0);
+ v4l_bound_align_image(&r.width, 6, max_rect.width, 0,
+ &r.height, 2, max_rect.height, 0, 0);
- r.top = clamp_t(s32, r.top, 0,
- vin->src_rect.height - r.height);
- r.left = clamp_t(s32, r.left, 0, vin->src_rect.width - r.width);
+ r.top = clamp_t(s32, r.top, 0, max_rect.height - r.height);
+ r.left = clamp_t(s32, r.left, 0, max_rect.width - r.width);
vin->crop = s->r = r;
vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
r.width, r.height, r.left, r.top,
- vin->src_rect.width, vin->src_rect.height);
+ max_rect.width, max_rect.height);
break;
case V4L2_SEL_TGT_COMPOSE:
/* Make sure compose rect fits inside output format */
@@ -866,6 +918,9 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
.vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
.vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
+ .vidioc_g_selection = rvin_g_selection,
+ .vidioc_s_selection = rvin_s_selection,
+
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
index 1f94589d9ef1..cb206d3976dd 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
@@ -31,6 +31,7 @@
/* Max number on VIN instances that can be in a system */
#define RCAR_VIN_NUM 32
+struct rvin_dev;
struct rvin_group;
enum model_id {
@@ -155,6 +156,7 @@ struct rvin_group_route {
* @max_height: max input height the VIN supports
* @routes: list of possible routes from the CSI-2 recivers to
* all VINs. The list mush be NULL terminated.
+ * @scaler: Optional scaler
*/
struct rvin_info {
enum model_id model;
@@ -165,6 +167,7 @@ struct rvin_info {
unsigned int max_width;
unsigned int max_height;
const struct rvin_group_route *routes;
+ void (*scaler)(struct rvin_dev *vin);
};
/**
@@ -203,7 +206,7 @@ struct rvin_info {
*
* @crop: active cropping
* @compose: active composing
- * @src_rect: active size of the video source
+ * @scaler: Optional scaler
* @std: active video standard of the video source
*
* @alpha: Alpha component to fill in for supported pixel formats
@@ -247,7 +250,7 @@ struct rvin_dev {
struct v4l2_rect crop;
struct v4l2_rect compose;
- struct v4l2_rect src_rect;
+ void (*scaler)(struct rvin_dev *vin);
v4l2_std_id std;
unsigned int alpha;
@@ -304,6 +307,8 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
/* Cropping, composing and scaling */
+void rvin_scaler_gen2(struct rvin_dev *vin);
+void rvin_scaler_gen3(struct rvin_dev *vin);
void rvin_crop_scale_comp(struct rvin_dev *vin);
int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/Kconfig b/drivers/media/platform/renesas/rzg2l-cru/Kconfig
new file mode 100644
index 000000000000..b39818c1f053
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/Kconfig
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config VIDEO_RZG2L_CSI2
+ tristate "RZ/G2L MIPI CSI-2 Receiver"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && OF
+ select MEDIA_CONTROLLER
+ select RESET_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Support for Renesas RZ/G2L (and alike SoC's) MIPI CSI-2
+ Receiver driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rzg2l-csi2.
+
+config VIDEO_RZG2L_CRU
+ tristate "RZ/G2L Camera Receiving Unit (CRU) Driver"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && OF
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Support for Renesas RZ/G2L (and alike SoC's) Camera Receiving
+ Unit (CRU) driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rzg2l-cru.
diff --git a/drivers/media/platform/renesas/rzg2l-cru/Makefile b/drivers/media/platform/renesas/rzg2l-cru/Makefile
new file mode 100644
index 000000000000..c4db2632874f
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_VIDEO_RZG2L_CSI2) += rzg2l-csi2.o
+
+rzg2l-cru-objs = rzg2l-core.o rzg2l-ip.o rzg2l-video.o
+obj-$(CONFIG_VIDEO_RZG2L_CRU) += rzg2l-cru.o
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
new file mode 100644
index 000000000000..5939f5165a5e
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Renesas RZ/G2L CRU
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ *
+ * Based on Renesas R-Car VIN
+ * Copyright (C) 2011-2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
+ * Copyright (C) 2008 Magnus Damm
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+
+#include "rzg2l-cru.h"
+
+static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct rzg2l_cru_dev, notifier);
+}
+
+static const struct media_device_ops rzg2l_cru_media_ops = {
+ .link_notify = v4l2_pipeline_link_notify,
+};
+
+/* -----------------------------------------------------------------------------
+ * Group async notifier
+ */
+
+static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct rzg2l_cru_dev *cru = notifier_to_cru(notifier);
+ struct media_entity *source, *sink;
+ int ret;
+
+ ret = rzg2l_cru_ip_subdev_register(cru);
+ if (ret)
+ return ret;
+
+ ret = v4l2_device_register_subdev_nodes(&cru->v4l2_dev);
+ if (ret) {
+ dev_err(cru->dev, "Failed to register subdev nodes\n");
+ return ret;
+ }
+
+ ret = rzg2l_cru_video_register(cru);
+ if (ret)
+ return ret;
+
+ /*
+ * CRU can be connected either to CSI2 or PARALLEL device
+ * For now we are only supporting CSI2
+ *
+ * Create media device link between CSI-2 <-> CRU IP
+ */
+ source = &cru->csi.subdev->entity;
+ sink = &cru->ip.subdev.entity;
+ ret = media_create_pad_link(source, 1, sink, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(cru->dev, "Error creating link from %s to %s\n",
+ source->name, sink->name);
+ return ret;
+ }
+ cru->csi.channel = 0;
+ cru->ip.remote = cru->csi.subdev;
+
+ /* Create media device link between CRU IP <-> CRU OUTPUT */
+ source = &cru->ip.subdev.entity;
+ sink = &cru->vdev.entity;
+ ret = media_create_pad_link(source, 1, sink, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(cru->dev, "Error creating link from %s to %s\n",
+ source->name, sink->name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct rzg2l_cru_dev *cru = notifier_to_cru(notifier);
+
+ rzg2l_cru_ip_subdev_unregister(cru);
+
+ mutex_lock(&cru->mdev_lock);
+
+ if (cru->csi.asd == asd) {
+ cru->csi.subdev = NULL;
+ dev_dbg(cru->dev, "Unbind CSI-2 %s\n", subdev->name);
+ }
+
+ mutex_unlock(&cru->mdev_lock);
+}
+
+static int rzg2l_cru_group_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct rzg2l_cru_dev *cru = notifier_to_cru(notifier);
+
+ mutex_lock(&cru->mdev_lock);
+
+ if (cru->csi.asd == asd) {
+ cru->csi.subdev = subdev;
+ dev_dbg(cru->dev, "Bound CSI-2 %s\n", subdev->name);
+ }
+
+ mutex_unlock(&cru->mdev_lock);
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations rzg2l_cru_async_ops = {
+ .bound = rzg2l_cru_group_notify_bound,
+ .unbind = rzg2l_cru_group_notify_unbind,
+ .complete = rzg2l_cru_group_notify_complete,
+};
+
+static int rzg2l_cru_mc_parse_of(struct rzg2l_cru_dev *cru)
+{
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *ep, *fwnode;
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(cru->dev), 1, 0, 0);
+ if (!ep)
+ return 0;
+
+ fwnode = fwnode_graph_get_remote_endpoint(ep);
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ fwnode_handle_put(ep);
+ if (ret) {
+ dev_err(cru->dev, "Failed to parse %pOF\n", to_of_node(fwnode));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!of_device_is_available(to_of_node(fwnode))) {
+ dev_dbg(cru->dev, "OF device %pOF disabled, ignoring\n",
+ to_of_node(fwnode));
+ ret = -ENOTCONN;
+ goto out;
+ }
+
+ asd = v4l2_async_nf_add_fwnode(&cru->notifier, fwnode,
+ struct v4l2_async_subdev);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ goto out;
+ }
+
+ cru->csi.asd = asd;
+
+ dev_dbg(cru->dev, "Added OF device %pOF to slot %u\n",
+ to_of_node(fwnode), vep.base.id);
+out:
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
+
+static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
+{
+ int ret;
+
+ v4l2_async_nf_init(&cru->notifier);
+
+ ret = rzg2l_cru_mc_parse_of(cru);
+ if (ret)
+ return ret;
+
+ cru->notifier.ops = &rzg2l_cru_async_ops;
+
+ if (list_empty(&cru->notifier.asd_list))
+ return 0;
+
+ ret = v4l2_async_nf_register(&cru->v4l2_dev, &cru->notifier);
+ if (ret < 0) {
+ dev_err(cru->dev, "Notifier registration failed\n");
+ v4l2_async_nf_cleanup(&cru->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
+{
+ struct media_device *mdev = NULL;
+ const struct of_device_id *match;
+ int ret;
+
+ cru->pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&cru->vdev.entity, 1, &cru->pad);
+ if (ret)
+ return ret;
+
+ mutex_init(&cru->mdev_lock);
+ mdev = &cru->mdev;
+ mdev->dev = cru->dev;
+ mdev->ops = &rzg2l_cru_media_ops;
+
+ match = of_match_node(cru->dev->driver->of_match_table,
+ cru->dev->of_node);
+
+ strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name));
+ strscpy(mdev->model, match->compatible, sizeof(mdev->model));
+
+ cru->v4l2_dev.mdev = &cru->mdev;
+
+ media_device_init(mdev);
+
+ ret = rzg2l_cru_mc_parse_of_graph(cru);
+ if (ret) {
+ mutex_lock(&cru->mdev_lock);
+ cru->v4l2_dev.mdev = NULL;
+ mutex_unlock(&cru->mdev_lock);
+ }
+
+ return 0;
+}
+
+static int rzg2l_cru_probe(struct platform_device *pdev)
+{
+ struct rzg2l_cru_dev *cru;
+ int ret;
+
+ cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL);
+ if (!cru)
+ return -ENOMEM;
+
+ cru->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(cru->base))
+ return PTR_ERR(cru->base);
+
+ cru->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn");
+ if (IS_ERR(cru->presetn))
+ return dev_err_probe(&pdev->dev, PTR_ERR(cru->presetn),
+ "Failed to get cpg presetn\n");
+
+ cru->aresetn = devm_reset_control_get_exclusive(&pdev->dev, "aresetn");
+ if (IS_ERR(cru->aresetn))
+ return dev_err_probe(&pdev->dev, PTR_ERR(cru->aresetn),
+ "Failed to get cpg aresetn\n");
+
+ cru->vclk = devm_clk_get(&pdev->dev, "video");
+ if (IS_ERR(cru->vclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(cru->vclk),
+ "Failed to get video clock\n");
+
+ cru->dev = &pdev->dev;
+ cru->info = of_device_get_match_data(&pdev->dev);
+
+ cru->image_conv_irq = platform_get_irq(pdev, 0);
+ if (cru->image_conv_irq < 0)
+ return cru->image_conv_irq;
+
+ platform_set_drvdata(pdev, cru);
+
+ ret = rzg2l_cru_dma_register(cru);
+ if (ret)
+ return ret;
+
+ cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
+ pm_suspend_ignore_children(&pdev->dev, true);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = rzg2l_cru_media_init(cru);
+ if (ret)
+ goto error_dma_unregister;
+
+ return 0;
+
+error_dma_unregister:
+ rzg2l_cru_dma_unregister(cru);
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static int rzg2l_cru_remove(struct platform_device *pdev)
+{
+ struct rzg2l_cru_dev *cru = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ v4l2_async_nf_unregister(&cru->notifier);
+ v4l2_async_nf_cleanup(&cru->notifier);
+
+ rzg2l_cru_video_unregister(cru);
+ media_device_cleanup(&cru->mdev);
+ mutex_destroy(&cru->mdev_lock);
+
+ rzg2l_cru_dma_unregister(cru);
+
+ return 0;
+}
+
+static const struct of_device_id rzg2l_cru_of_id_table[] = {
+ { .compatible = "renesas,rzg2l-cru", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
+
+static struct platform_driver rzg2l_cru_driver = {
+ .driver = {
+ .name = "rzg2l-cru",
+ .of_match_table = rzg2l_cru_of_id_table,
+ },
+ .probe = rzg2l_cru_probe,
+ .remove = rzg2l_cru_remove,
+};
+
+module_platform_driver(rzg2l_cru_driver);
+
+MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L CRU driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
new file mode 100644
index 000000000000..0b682cbae3eb
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Driver for Renesas RZ/G2L CRU
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#ifndef __RZG2L_CRU__
+#define __RZG2L_CRU__
+
+#include <linux/reset.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-v4l2.h>
+
+/* Number of HW buffers */
+#define RZG2L_CRU_HW_BUFFER_MAX 8
+#define RZG2L_CRU_HW_BUFFER_DEFAULT 3
+
+/* Address alignment mask for HW buffers */
+#define RZG2L_CRU_HW_BUFFER_MASK 0x1ff
+
+/* Maximum number of CSI2 virtual channels */
+#define RZG2L_CRU_CSI2_VCHANNEL 4
+
+#define RZG2L_CRU_MIN_INPUT_WIDTH 320
+#define RZG2L_CRU_MAX_INPUT_WIDTH 2800
+#define RZG2L_CRU_MIN_INPUT_HEIGHT 240
+#define RZG2L_CRU_MAX_INPUT_HEIGHT 4095
+
+/**
+ * enum rzg2l_cru_dma_state - DMA states
+ * @RZG2L_CRU_DMA_STOPPED: No operation in progress
+ * @RZG2L_CRU_DMA_STARTING: Capture starting up
+ * @RZG2L_CRU_DMA_RUNNING: Operation in progress have buffers
+ * @RZG2L_CRU_DMA_STOPPING: Stopping operation
+ */
+enum rzg2l_cru_dma_state {
+ RZG2L_CRU_DMA_STOPPED = 0,
+ RZG2L_CRU_DMA_STARTING,
+ RZG2L_CRU_DMA_RUNNING,
+ RZG2L_CRU_DMA_STOPPING,
+};
+
+struct rzg2l_cru_csi {
+ struct v4l2_async_subdev *asd;
+ struct v4l2_subdev *subdev;
+ u32 channel;
+};
+
+struct rzg2l_cru_ip {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[2];
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *remote;
+};
+
+/**
+ * struct rzg2l_cru_dev - Renesas CRU device structure
+ * @dev: (OF) device
+ * @base: device I/O register space remapped to virtual memory
+ * @info: info about CRU instance
+ *
+ * @presetn: CRU_PRESETN reset line
+ * @aresetn: CRU_ARESETN reset line
+ *
+ * @vclk: CRU Main clock
+ *
+ * @image_conv_irq: Holds image conversion interrupt number
+ *
+ * @vdev: V4L2 video device associated with CRU
+ * @v4l2_dev: V4L2 device
+ * @num_buf: Holds the current number of buffers enabled
+ * @notifier: V4L2 asynchronous subdevs notifier
+ *
+ * @ip: Image processing subdev info
+ * @csi: CSI info
+ * @mdev: media device
+ * @mdev_lock: protects the count, notifier and csi members
+ * @pad: media pad for the video device entity
+ *
+ * @lock: protects @queue
+ * @queue: vb2 buffers queue
+ * @scratch: cpu address for scratch buffer
+ * @scratch_phys: physical address of the scratch buffer
+ *
+ * @qlock: protects @queue_buf, @buf_list, @sequence
+ * @state
+ * @queue_buf: Keeps track of buffers given to HW slot
+ * @buf_list: list of queued buffers
+ * @sequence: V4L2 buffers sequence number
+ * @state: keeps track of operation state
+ *
+ * @format: active V4L2 pixel format
+ */
+struct rzg2l_cru_dev {
+ struct device *dev;
+ void __iomem *base;
+ const struct rzg2l_cru_info *info;
+
+ struct reset_control *presetn;
+ struct reset_control *aresetn;
+
+ struct clk *vclk;
+
+ int image_conv_irq;
+
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+ u8 num_buf;
+
+ struct v4l2_async_notifier notifier;
+
+ struct rzg2l_cru_ip ip;
+ struct rzg2l_cru_csi csi;
+ struct media_device mdev;
+ struct mutex mdev_lock;
+ struct media_pad pad;
+
+ struct mutex lock;
+ struct vb2_queue queue;
+ void *scratch;
+ dma_addr_t scratch_phys;
+
+ spinlock_t qlock;
+ struct vb2_v4l2_buffer *queue_buf[RZG2L_CRU_HW_BUFFER_MAX];
+ struct list_head buf_list;
+ unsigned int sequence;
+ enum rzg2l_cru_dma_state state;
+
+ struct v4l2_pix_format format;
+};
+
+void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru);
+int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru);
+
+int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru);
+
+int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
+
+int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
+
+const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
+
+int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru);
+struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru);
+
+#endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
new file mode 100644
index 000000000000..33e08efa3039
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Renesas RZ/G2L MIPI CSI-2 Receiver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sys_soc.h>
+#include <linux/units.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* LINK registers */
+/* Module Configuration Register */
+#define CSI2nMCG 0x0
+#define CSI2nMCG_SDLN GENMASK(11, 8)
+
+/* Module Control Register 0 */
+#define CSI2nMCT0 0x10
+#define CSI2nMCT0_VDLN(x) ((x) << 0)
+
+/* Module Control Register 2 */
+#define CSI2nMCT2 0x18
+#define CSI2nMCT2_FRRSKW(x) ((x) << 16)
+#define CSI2nMCT2_FRRCLK(x) ((x) << 0)
+
+/* Module Control Register 3 */
+#define CSI2nMCT3 0x1c
+#define CSI2nMCT3_RXEN BIT(0)
+
+/* Reset Control Register */
+#define CSI2nRTCT 0x28
+#define CSI2nRTCT_VSRST BIT(0)
+
+/* Reset Status Register */
+#define CSI2nRTST 0x2c
+#define CSI2nRTST_VSRSTS BIT(0)
+
+/* Receive Data Type Enable Low Register */
+#define CSI2nDTEL 0x60
+
+/* Receive Data Type Enable High Register */
+#define CSI2nDTEH 0x64
+
+/* DPHY registers */
+/* D-PHY Control Register 0 */
+#define CSIDPHYCTRL0 0x400
+#define CSIDPHYCTRL0_EN_LDO1200 BIT(1)
+#define CSIDPHYCTRL0_EN_BGR BIT(0)
+
+/* D-PHY Timing Register 0 */
+#define CSIDPHYTIM0 0x404
+#define CSIDPHYTIM0_TCLK_MISS(x) ((x) << 24)
+#define CSIDPHYTIM0_T_INIT(x) ((x) << 0)
+
+/* D-PHY Timing Register 1 */
+#define CSIDPHYTIM1 0x408
+#define CSIDPHYTIM1_THS_PREPARE(x) ((x) << 24)
+#define CSIDPHYTIM1_TCLK_PREPARE(x) ((x) << 16)
+#define CSIDPHYTIM1_THS_SETTLE(x) ((x) << 8)
+#define CSIDPHYTIM1_TCLK_SETTLE(x) ((x) << 0)
+
+/* D-PHY Skew Adjustment Function */
+#define CSIDPHYSKW0 0x460
+#define CSIDPHYSKW0_UTIL_DL0_SKW_ADJ(x) ((x) & 0x3)
+#define CSIDPHYSKW0_UTIL_DL1_SKW_ADJ(x) (((x) & 0x3) << 4)
+#define CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(x) (((x) & 0x3) << 8)
+#define CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(x) (((x) & 0x3) << 12)
+#define CSIDPHYSKW0_DEFAULT_SKW CSIDPHYSKW0_UTIL_DL0_SKW_ADJ(1) | \
+ CSIDPHYSKW0_UTIL_DL1_SKW_ADJ(1) | \
+ CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(1) | \
+ CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(1)
+
+#define VSRSTS_RETRIES 20
+
+#define RZG2L_CSI2_MIN_WIDTH 320
+#define RZG2L_CSI2_MIN_HEIGHT 240
+#define RZG2L_CSI2_MAX_WIDTH 2800
+#define RZG2L_CSI2_MAX_HEIGHT 4095
+
+#define RZG2L_CSI2_DEFAULT_WIDTH RZG2L_CSI2_MIN_WIDTH
+#define RZG2L_CSI2_DEFAULT_HEIGHT RZG2L_CSI2_MIN_HEIGHT
+#define RZG2L_CSI2_DEFAULT_FMT MEDIA_BUS_FMT_UYVY8_1X16
+
+enum rzg2l_csi2_pads {
+ RZG2L_CSI2_SINK = 0,
+ RZG2L_CSI2_SOURCE,
+ NR_OF_RZG2L_CSI2_PAD,
+};
+
+struct rzg2l_csi2 {
+ struct device *dev;
+ void __iomem *base;
+ struct reset_control *presetn;
+ struct reset_control *cmn_rstb;
+ struct clk *sysclk;
+ unsigned long vclk_rate;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pads[NR_OF_RZG2L_CSI2_PAD];
+
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *remote_source;
+
+ unsigned short lanes;
+ unsigned long hsfreq;
+
+ bool dphy_enabled;
+};
+
+struct rzg2l_csi2_timings {
+ u32 t_init;
+ u32 tclk_miss;
+ u32 tclk_settle;
+ u32 ths_settle;
+ u32 tclk_prepare;
+ u32 ths_prepare;
+ u32 max_hsfreq;
+};
+
+static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = {
+ {
+ .max_hsfreq = 80,
+ .t_init = 79801,
+ .tclk_miss = 4,
+ .tclk_settle = 23,
+ .ths_settle = 31,
+ .tclk_prepare = 10,
+ .ths_prepare = 19,
+ },
+ {
+ .max_hsfreq = 125,
+ .t_init = 79801,
+ .tclk_miss = 4,
+ .tclk_settle = 23,
+ .ths_settle = 28,
+ .tclk_prepare = 10,
+ .ths_prepare = 19,
+ },
+ {
+ .max_hsfreq = 250,
+ .t_init = 79801,
+ .tclk_miss = 4,
+ .tclk_settle = 23,
+ .ths_settle = 22,
+ .tclk_prepare = 10,
+ .ths_prepare = 16,
+ },
+ {
+ .max_hsfreq = 360,
+ .t_init = 79801,
+ .tclk_miss = 4,
+ .tclk_settle = 18,
+ .ths_settle = 19,
+ .tclk_prepare = 10,
+ .ths_prepare = 10,
+ },
+ {
+ .max_hsfreq = 1500,
+ .t_init = 79801,
+ .tclk_miss = 4,
+ .tclk_settle = 18,
+ .ths_settle = 18,
+ .tclk_prepare = 10,
+ .ths_prepare = 10,
+ },
+};
+
+struct rzg2l_csi2_format {
+ u32 code;
+ unsigned int datatype;
+ unsigned int bpp;
+};
+
+static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = {
+ { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
+};
+
+static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct rzg2l_csi2, subdev);
+}
+
+static const struct rzg2l_csi2_format *rzg2l_csi2_code_to_fmt(unsigned int code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rzg2l_csi2_formats); i++)
+ if (rzg2l_csi2_formats[i].code == code)
+ return &rzg2l_csi2_formats[i];
+
+ return NULL;
+}
+
+static inline struct rzg2l_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct rzg2l_csi2, notifier);
+}
+
+static u32 rzg2l_csi2_read(struct rzg2l_csi2 *csi2, unsigned int reg)
+{
+ return ioread32(csi2->base + reg);
+}
+
+static void rzg2l_csi2_write(struct rzg2l_csi2 *csi2, unsigned int reg,
+ u32 data)
+{
+ iowrite32(data, csi2->base + reg);
+}
+
+static void rzg2l_csi2_set(struct rzg2l_csi2 *csi2, unsigned int reg, u32 set)
+{
+ rzg2l_csi2_write(csi2, reg, rzg2l_csi2_read(csi2, reg) | set);
+}
+
+static void rzg2l_csi2_clr(struct rzg2l_csi2 *csi2, unsigned int reg, u32 clr)
+{
+ rzg2l_csi2_write(csi2, reg, rzg2l_csi2_read(csi2, reg) & ~clr);
+}
+
+static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2)
+{
+ struct v4l2_subdev *source = csi2->remote_source;
+ const struct rzg2l_csi2_format *format;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_state *state;
+ struct v4l2_ctrl *ctrl;
+ u64 mbps;
+
+ /* Read the pixel rate control from remote. */
+ ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE);
+ if (!ctrl) {
+ dev_err(csi2->dev, "no pixel rate control in subdev %s\n",
+ source->name);
+ return -EINVAL;
+ }
+
+ state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev);
+ fmt = v4l2_subdev_get_pad_format(&csi2->subdev, state, RZG2L_CSI2_SINK);
+ format = rzg2l_csi2_code_to_fmt(fmt->code);
+ v4l2_subdev_unlock_state(state);
+
+ /*
+ * Calculate hsfreq in Mbps
+ * hsfreq = (pixel_rate * bits_per_sample) / number_of_lanes
+ */
+ mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * format->bpp;
+ do_div(mbps, csi2->lanes * 1000000);
+
+ return mbps;
+}
+
+/* -----------------------------------------------------------------------------
+ * DPHY setting
+ */
+
+static int rzg2l_csi2_dphy_disable(struct rzg2l_csi2 *csi2)
+{
+ int ret;
+
+ /* Reset the CRU (D-PHY) */
+ ret = reset_control_assert(csi2->cmn_rstb);
+ if (ret)
+ return ret;
+
+ /* Stop the D-PHY clock */
+ clk_disable_unprepare(csi2->sysclk);
+
+ /* Cancel the EN_LDO1200 register setting */
+ rzg2l_csi2_clr(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_LDO1200);
+
+ /* Cancel the EN_BGR register setting */
+ rzg2l_csi2_clr(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_BGR);
+
+ csi2->dphy_enabled = false;
+
+ return 0;
+}
+
+static int rzg2l_csi2_dphy_enable(struct rzg2l_csi2 *csi2)
+{
+ const struct rzg2l_csi2_timings *dphy_timing;
+ u32 dphytim0, dphytim1;
+ unsigned int i;
+ int mbps;
+ int ret;
+
+ mbps = rzg2l_csi2_calc_mbps(csi2);
+ if (mbps < 0)
+ return mbps;
+
+ csi2->hsfreq = mbps;
+
+ /* Set DPHY timing parameters */
+ for (i = 0; i < ARRAY_SIZE(rzg2l_csi2_global_timings); ++i) {
+ dphy_timing = &rzg2l_csi2_global_timings[i];
+
+ if (csi2->hsfreq <= dphy_timing->max_hsfreq)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(rzg2l_csi2_global_timings))
+ return -EINVAL;
+
+ /* Set D-PHY timing parameters */
+ dphytim0 = CSIDPHYTIM0_TCLK_MISS(dphy_timing->tclk_miss) |
+ CSIDPHYTIM0_T_INIT(dphy_timing->t_init);
+ dphytim1 = CSIDPHYTIM1_THS_PREPARE(dphy_timing->ths_prepare) |
+ CSIDPHYTIM1_TCLK_PREPARE(dphy_timing->tclk_prepare) |
+ CSIDPHYTIM1_THS_SETTLE(dphy_timing->ths_settle) |
+ CSIDPHYTIM1_TCLK_SETTLE(dphy_timing->tclk_settle);
+ rzg2l_csi2_write(csi2, CSIDPHYTIM0, dphytim0);
+ rzg2l_csi2_write(csi2, CSIDPHYTIM1, dphytim1);
+
+ /* Enable D-PHY power control 0 */
+ rzg2l_csi2_write(csi2, CSIDPHYSKW0, CSIDPHYSKW0_DEFAULT_SKW);
+
+ /* Set the EN_BGR bit */
+ rzg2l_csi2_set(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_BGR);
+
+ /* Delay 20us to be stable */
+ usleep_range(20, 40);
+
+ /* Enable D-PHY power control 1 */
+ rzg2l_csi2_set(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_LDO1200);
+
+ /* Delay 10us to be stable */
+ usleep_range(10, 20);
+
+ /* Start supplying the internal clock for the D-PHY block */
+ ret = clk_prepare_enable(csi2->sysclk);
+ if (ret)
+ rzg2l_csi2_dphy_disable(csi2);
+
+ csi2->dphy_enabled = true;
+
+ return ret;
+}
+
+static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+
+ if (on)
+ return rzg2l_csi2_dphy_enable(csi2);
+
+ return rzg2l_csi2_dphy_disable(csi2);
+}
+
+static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
+{
+ unsigned long vclk_rate = csi2->vclk_rate / HZ_PER_MHZ;
+ u32 frrskw, frrclk, frrskw_coeff, frrclk_coeff;
+
+ /* Select data lanes */
+ rzg2l_csi2_write(csi2, CSI2nMCT0, CSI2nMCT0_VDLN(csi2->lanes));
+
+ frrskw_coeff = 3 * vclk_rate * 8;
+ frrclk_coeff = frrskw_coeff / 2;
+ frrskw = DIV_ROUND_UP(frrskw_coeff, csi2->hsfreq);
+ frrclk = DIV_ROUND_UP(frrclk_coeff, csi2->hsfreq);
+ rzg2l_csi2_write(csi2, CSI2nMCT2, CSI2nMCT2_FRRSKW(frrskw) |
+ CSI2nMCT2_FRRCLK(frrclk));
+
+ /*
+ * Select data type.
+ * FS, FE, LS, LE, Generic Short Packet Codes 1 to 8,
+ * Generic Long Packet Data Types 1 to 4 YUV422 8-bit,
+ * RGB565, RGB888, RAW8 to RAW20, User-defined 8-bit
+ * data types 1 to 8
+ */
+ rzg2l_csi2_write(csi2, CSI2nDTEL, 0xf778ff0f);
+ rzg2l_csi2_write(csi2, CSI2nDTEH, 0x00ffff1f);
+
+ /* Enable LINK reception */
+ rzg2l_csi2_write(csi2, CSI2nMCT3, CSI2nMCT3_RXEN);
+}
+
+static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
+{
+ unsigned int timeout = VSRSTS_RETRIES;
+
+ /* Stop LINK reception */
+ rzg2l_csi2_clr(csi2, CSI2nMCT3, CSI2nMCT3_RXEN);
+
+ /* Request a software reset of the LINK Video Pixel Interface */
+ rzg2l_csi2_write(csi2, CSI2nRTCT, CSI2nRTCT_VSRST);
+
+ /* Make sure CSI2nRTST.VSRSTS bit is cleared */
+ while (--timeout) {
+ if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS))
+ break;
+ usleep_range(100, 200);
+ };
+
+ if (!timeout)
+ dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n");
+}
+
+static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+
+ if (on)
+ rzg2l_csi2_mipi_link_enable(csi2);
+ else
+ rzg2l_csi2_mipi_link_disable(csi2);
+
+ return 0;
+}
+
+static int rzg2l_csi2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+ int s_stream_ret = 0;
+ int ret;
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(csi2->dev);
+ if (ret)
+ return ret;
+
+ ret = rzg2l_csi2_mipi_link_setting(sd, 1);
+ if (ret)
+ goto err_pm_put;
+
+ ret = reset_control_deassert(csi2->cmn_rstb);
+ if (ret)
+ goto err_mipi_link_disable;
+ }
+
+ ret = v4l2_subdev_call(csi2->remote_source, video, s_stream, enable);
+ if (ret)
+ s_stream_ret = ret;
+
+ if (enable && ret)
+ goto err_assert_rstb;
+
+ if (!enable) {
+ ret = rzg2l_csi2_dphy_setting(sd, 0);
+ if (ret && !s_stream_ret)
+ s_stream_ret = ret;
+ ret = rzg2l_csi2_mipi_link_setting(sd, 0);
+ if (ret && !s_stream_ret)
+ s_stream_ret = ret;
+
+ pm_runtime_put_sync(csi2->dev);
+ }
+
+ return s_stream_ret;
+
+err_assert_rstb:
+ reset_control_assert(csi2->cmn_rstb);
+err_mipi_link_disable:
+ rzg2l_csi2_mipi_link_setting(sd, 0);
+err_pm_put:
+ pm_runtime_put_sync(csi2->dev);
+ return ret;
+}
+
+static int rzg2l_csi2_pre_streamon(struct v4l2_subdev *sd, u32 flags)
+{
+ return rzg2l_csi2_dphy_setting(sd, 1);
+}
+
+static int rzg2l_csi2_post_streamoff(struct v4l2_subdev *sd)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+
+ /*
+ * In ideal case D-PHY will be disabled in s_stream(0) callback
+ * as mentioned in the HW manual. The below will only happen when
+ * pre_streamon succeeds and further down the line s_stream(1)
+ * fails so we need to undo things in post_streamoff.
+ */
+ if (csi2->dphy_enabled)
+ return rzg2l_csi2_dphy_setting(sd, 0);
+
+ return 0;
+}
+
+static int rzg2l_csi2_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *src_format;
+ struct v4l2_mbus_framefmt *sink_format;
+
+ src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SOURCE);
+ if (fmt->pad == RZG2L_CSI2_SOURCE) {
+ fmt->format = *src_format;
+ return 0;
+ }
+
+ sink_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SINK);
+
+ if (!rzg2l_csi2_code_to_fmt(fmt->format.code))
+ sink_format->code = rzg2l_csi2_formats[0].code;
+ else
+ sink_format->code = fmt->format.code;
+
+ sink_format->field = V4L2_FIELD_NONE;
+ sink_format->colorspace = fmt->format.colorspace;
+ sink_format->xfer_func = fmt->format.xfer_func;
+ sink_format->ycbcr_enc = fmt->format.ycbcr_enc;
+ sink_format->quantization = fmt->format.quantization;
+ sink_format->width = clamp_t(u32, fmt->format.width,
+ RZG2L_CSI2_MIN_WIDTH, RZG2L_CSI2_MAX_WIDTH);
+ sink_format->height = clamp_t(u32, fmt->format.height,
+ RZG2L_CSI2_MIN_HEIGHT, RZG2L_CSI2_MAX_HEIGHT);
+ fmt->format = *sink_format;
+
+ /* propagate format to source pad */
+ *src_format = *sink_format;
+
+ return 0;
+}
+
+static int rzg2l_csi2_init_config(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = { .pad = RZG2L_CSI2_SINK, };
+
+ fmt.format.width = RZG2L_CSI2_DEFAULT_WIDTH;
+ fmt.format.height = RZG2L_CSI2_DEFAULT_HEIGHT;
+ fmt.format.field = V4L2_FIELD_NONE;
+ fmt.format.code = RZG2L_CSI2_DEFAULT_FMT;
+ fmt.format.colorspace = V4L2_COLORSPACE_SRGB;
+ fmt.format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt.format.quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt.format.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ return rzg2l_csi2_set_format(sd, sd_state, &fmt);
+}
+
+static int rzg2l_csi2_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(rzg2l_csi2_formats))
+ return -EINVAL;
+
+ code->code = rzg2l_csi2_formats[code->index].code;
+
+ return 0;
+}
+
+static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index != 0)
+ return -EINVAL;
+
+ fse->min_width = RZG2L_CSI2_MIN_WIDTH;
+ fse->min_height = RZG2L_CSI2_MIN_HEIGHT;
+ fse->max_width = RZG2L_CSI2_MAX_WIDTH;
+ fse->max_height = RZG2L_CSI2_MAX_HEIGHT;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = {
+ .s_stream = rzg2l_csi2_s_stream,
+ .pre_streamon = rzg2l_csi2_pre_streamon,
+ .post_streamoff = rzg2l_csi2_post_streamoff,
+};
+
+static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = {
+ .enum_mbus_code = rzg2l_csi2_enum_mbus_code,
+ .init_cfg = rzg2l_csi2_init_config,
+ .enum_frame_size = rzg2l_csi2_enum_frame_size,
+ .set_fmt = rzg2l_csi2_set_format,
+ .get_fmt = v4l2_subdev_get_fmt,
+};
+
+static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = {
+ .video = &rzg2l_csi2_video_ops,
+ .pad = &rzg2l_csi2_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Async handling and registration of subdevices and links.
+ */
+
+static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
+
+ csi2->remote_source = subdev;
+
+ dev_dbg(csi2->dev, "Bound subdev: %s pad\n", subdev->name);
+
+ return media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK,
+ &csi2->subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+}
+
+static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
+
+ csi2->remote_source = NULL;
+
+ dev_dbg(csi2->dev, "Unbind subdev %s\n", subdev->name);
+}
+
+static const struct v4l2_async_notifier_operations rzg2l_csi2_notify_ops = {
+ .bound = rzg2l_csi2_notify_bound,
+ .unbind = rzg2l_csi2_notify_unbind,
+};
+
+static int rzg2l_csi2_parse_v4l2(struct rzg2l_csi2 *csi2,
+ struct v4l2_fwnode_endpoint *vep)
+{
+ /* Only port 0 endpoint 0 is valid. */
+ if (vep->base.port || vep->base.id)
+ return -ENOTCONN;
+
+ csi2->lanes = vep->bus.mipi_csi2.num_data_lanes;
+
+ return 0;
+}
+
+static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2)
+{
+ struct v4l2_fwnode_endpoint v4l2_ep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *ep;
+ int ret;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0, 0);
+ if (!ep) {
+ dev_err(csi2->dev, "Not connected to subdevice\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
+ if (ret) {
+ dev_err(csi2->dev, "Could not parse v4l2 endpoint\n");
+ fwnode_handle_put(ep);
+ return -EINVAL;
+ }
+
+ ret = rzg2l_csi2_parse_v4l2(csi2, &v4l2_ep);
+ if (ret) {
+ fwnode_handle_put(ep);
+ return ret;
+ }
+
+ fwnode = fwnode_graph_get_remote_endpoint(ep);
+ fwnode_handle_put(ep);
+
+ v4l2_async_nf_init(&csi2->notifier);
+ csi2->notifier.ops = &rzg2l_csi2_notify_ops;
+
+ asd = v4l2_async_nf_add_fwnode(&csi2->notifier, fwnode,
+ struct v4l2_async_subdev);
+ fwnode_handle_put(fwnode);
+ if (IS_ERR(asd))
+ return PTR_ERR(asd);
+
+ ret = v4l2_async_subdev_nf_register(&csi2->subdev, &csi2->notifier);
+ if (ret)
+ v4l2_async_nf_cleanup(&csi2->notifier);
+
+ return ret;
+}
+
+static int rzg2l_validate_csi2_lanes(struct rzg2l_csi2 *csi2)
+{
+ int lanes;
+ int ret;
+
+ if (csi2->lanes != 1 && csi2->lanes != 2 && csi2->lanes != 4) {
+ dev_err(csi2->dev, "Unsupported number of data-lanes: %u\n",
+ csi2->lanes);
+ return -EINVAL;
+ }
+
+ ret = pm_runtime_resume_and_get(csi2->dev);
+ if (ret)
+ return ret;
+
+ /* Checking the maximum lanes support for CSI-2 module */
+ lanes = (rzg2l_csi2_read(csi2, CSI2nMCG) & CSI2nMCG_SDLN) >> 8;
+ if (lanes < csi2->lanes) {
+ dev_err(csi2->dev,
+ "Failed to support %d data lanes\n", csi2->lanes);
+ ret = -EINVAL;
+ }
+
+ pm_runtime_put_sync(csi2->dev);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver.
+ */
+
+static const struct media_entity_operations rzg2l_csi2_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int rzg2l_csi2_probe(struct platform_device *pdev)
+{
+ struct rzg2l_csi2 *csi2;
+ struct clk *vclk;
+ int ret;
+
+ csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
+ if (!csi2)
+ return -ENOMEM;
+
+ csi2->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(csi2->base))
+ return PTR_ERR(csi2->base);
+
+ csi2->cmn_rstb = devm_reset_control_get_exclusive(&pdev->dev, "cmn-rstb");
+ if (IS_ERR(csi2->cmn_rstb))
+ return dev_err_probe(&pdev->dev, PTR_ERR(csi2->cmn_rstb),
+ "Failed to get cpg cmn-rstb\n");
+
+ csi2->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn");
+ if (IS_ERR(csi2->presetn))
+ return dev_err_probe(&pdev->dev, PTR_ERR(csi2->presetn),
+ "Failed to get cpg presetn\n");
+
+ csi2->sysclk = devm_clk_get(&pdev->dev, "system");
+ if (IS_ERR(csi2->sysclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk),
+ "Failed to get system clk\n");
+
+ vclk = clk_get(&pdev->dev, "video");
+ if (IS_ERR(vclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vclk),
+ "Failed to get video clock\n");
+ csi2->vclk_rate = clk_get_rate(vclk);
+ clk_put(vclk);
+
+ csi2->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, csi2);
+
+ ret = rzg2l_csi2_parse_dt(csi2);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = rzg2l_validate_csi2_lanes(csi2);
+ if (ret)
+ goto error_pm;
+
+ csi2->subdev.dev = &pdev->dev;
+ v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
+ v4l2_set_subdevdata(&csi2->subdev, &pdev->dev);
+ snprintf(csi2->subdev.name, sizeof(csi2->subdev.name),
+ "csi-%s", dev_name(&pdev->dev));
+ csi2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops;
+
+ csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
+ /*
+ * TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual
+ * channels should be implemented by streams API which is under
+ * development lets hardcode to VC0 for now.
+ */
+ csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads);
+ if (ret)
+ goto error_pm;
+
+ ret = v4l2_subdev_init_finalize(&csi2->subdev);
+ if (ret < 0)
+ goto error_async;
+
+ ret = v4l2_async_register_subdev(&csi2->subdev);
+ if (ret < 0)
+ goto error_subdev;
+
+ return 0;
+
+error_subdev:
+ v4l2_subdev_cleanup(&csi2->subdev);
+error_async:
+ v4l2_async_nf_unregister(&csi2->notifier);
+ v4l2_async_nf_cleanup(&csi2->notifier);
+ media_entity_cleanup(&csi2->subdev.entity);
+error_pm:
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static int rzg2l_csi2_remove(struct platform_device *pdev)
+{
+ struct rzg2l_csi2 *csi2 = platform_get_drvdata(pdev);
+
+ v4l2_async_nf_unregister(&csi2->notifier);
+ v4l2_async_nf_cleanup(&csi2->notifier);
+ v4l2_async_unregister_subdev(&csi2->subdev);
+ v4l2_subdev_cleanup(&csi2->subdev);
+ media_entity_cleanup(&csi2->subdev.entity);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev)
+{
+ struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev);
+
+ reset_control_assert(csi2->presetn);
+
+ return 0;
+}
+
+static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev)
+{
+ struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev);
+
+ return reset_control_deassert(csi2->presetn);
+}
+
+static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
+ SET_RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend, rzg2l_csi2_pm_runtime_resume, NULL)
+};
+
+static const struct of_device_id rzg2l_csi2_of_table[] = {
+ { .compatible = "renesas,rzg2l-csi2", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver rzg2l_csi2_pdrv = {
+ .remove = rzg2l_csi2_remove,
+ .probe = rzg2l_csi2_probe,
+ .driver = {
+ .name = "rzg2l-csi2",
+ .of_match_table = rzg2l_csi2_of_table,
+ .pm = &rzg2l_csi2_pm_ops,
+ },
+};
+
+module_platform_driver(rzg2l_csi2_pdrv);
+
+MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L MIPI CSI2 receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
new file mode 100644
index 000000000000..4dcd2faff5bb
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Renesas RZ/G2L CRU
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include "rzg2l-cru.h"
+
+struct rzg2l_cru_ip_format {
+ u32 code;
+ unsigned int datatype;
+ unsigned int bpp;
+};
+
+static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = {
+ { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
+};
+
+enum rzg2l_csi2_pads {
+ RZG2L_CRU_IP_SINK = 0,
+ RZG2L_CRU_IP_SOURCE,
+};
+
+static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++)
+ if (rzg2l_cru_ip_formats[i].code == code)
+ return &rzg2l_cru_ip_formats[i];
+
+ return NULL;
+}
+
+struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru)
+{
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
+
+ state = v4l2_subdev_lock_and_get_active_state(&cru->ip.subdev);
+ fmt = v4l2_subdev_get_pad_format(&cru->ip.subdev, state, 1);
+ v4l2_subdev_unlock_state(state);
+
+ return fmt;
+}
+
+static int rzg2l_cru_ip_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct rzg2l_cru_dev *cru;
+ int s_stream_ret = 0;
+ int ret;
+
+ cru = v4l2_get_subdevdata(sd);
+
+ if (!enable) {
+ ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable);
+ if (ret)
+ s_stream_ret = ret;
+
+ ret = v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (ret && !s_stream_ret)
+ s_stream_ret = ret;
+ rzg2l_cru_stop_image_processing(cru);
+ } else {
+ ret = v4l2_subdev_call(cru->ip.remote, video, pre_streamon, 0);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (ret)
+ return ret;
+
+ ret = rzg2l_cru_start_image_processing(cru);
+ if (ret) {
+ v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
+ return ret;
+ }
+
+ rzg2l_cru_vclk_unprepare(cru);
+
+ ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (!ret) {
+ ret = rzg2l_cru_vclk_prepare(cru);
+ if (!ret)
+ return 0;
+ } else {
+ /* enable back vclk so that s_stream in error path disables it */
+ if (rzg2l_cru_vclk_prepare(cru))
+ dev_err(cru->dev, "Failed to enable vclk\n");
+ }
+
+ s_stream_ret = ret;
+
+ v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
+ rzg2l_cru_stop_image_processing(cru);
+ }
+
+ return s_stream_ret;
+}
+
+static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *src_format;
+ struct v4l2_mbus_framefmt *sink_format;
+
+ src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CRU_IP_SOURCE);
+ if (fmt->pad == RZG2L_CRU_IP_SOURCE) {
+ fmt->format = *src_format;
+ return 0;
+ }
+
+ sink_format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code))
+ sink_format->code = rzg2l_cru_ip_formats[0].code;
+ else
+ sink_format->code = fmt->format.code;
+
+ sink_format->field = V4L2_FIELD_NONE;
+ sink_format->colorspace = fmt->format.colorspace;
+ sink_format->xfer_func = fmt->format.xfer_func;
+ sink_format->ycbcr_enc = fmt->format.ycbcr_enc;
+ sink_format->quantization = fmt->format.quantization;
+ sink_format->width = clamp_t(u32, fmt->format.width,
+ RZG2L_CRU_MIN_INPUT_WIDTH, RZG2L_CRU_MAX_INPUT_WIDTH);
+ sink_format->height = clamp_t(u32, fmt->format.height,
+ RZG2L_CRU_MIN_INPUT_HEIGHT, RZG2L_CRU_MAX_INPUT_HEIGHT);
+
+ fmt->format = *sink_format;
+
+ /* propagate format to source pad */
+ *src_format = *sink_format;
+
+ return 0;
+}
+
+static int rzg2l_cru_ip_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(rzg2l_cru_ip_formats))
+ return -EINVAL;
+
+ code->code = rzg2l_cru_ip_formats[code->index].code;
+ return 0;
+}
+
+static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index != 0)
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16)
+ return -EINVAL;
+
+ fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
+ fse->min_height = RZG2L_CRU_MIN_INPUT_HEIGHT;
+ fse->max_width = RZG2L_CRU_MAX_INPUT_WIDTH;
+ fse->max_height = RZG2L_CRU_MAX_INPUT_HEIGHT;
+
+ return 0;
+}
+
+static int rzg2l_cru_ip_init_config(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = { .pad = RZG2L_CRU_IP_SINK, };
+
+ fmt.format.width = RZG2L_CRU_MIN_INPUT_WIDTH;
+ fmt.format.height = RZG2L_CRU_MIN_INPUT_HEIGHT;
+ fmt.format.field = V4L2_FIELD_NONE;
+ fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
+ fmt.format.colorspace = V4L2_COLORSPACE_SRGB;
+ fmt.format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt.format.quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt.format.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ return rzg2l_cru_ip_set_format(sd, sd_state, &fmt);
+}
+
+static const struct v4l2_subdev_video_ops rzg2l_cru_ip_video_ops = {
+ .s_stream = rzg2l_cru_ip_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops rzg2l_cru_ip_pad_ops = {
+ .enum_mbus_code = rzg2l_cru_ip_enum_mbus_code,
+ .enum_frame_size = rzg2l_cru_ip_enum_frame_size,
+ .init_cfg = rzg2l_cru_ip_init_config,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = rzg2l_cru_ip_set_format,
+};
+
+static const struct v4l2_subdev_ops rzg2l_cru_ip_subdev_ops = {
+ .video = &rzg2l_cru_ip_video_ops,
+ .pad = &rzg2l_cru_ip_pad_ops,
+};
+
+static const struct media_entity_operations rzg2l_cru_ip_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru)
+{
+ struct rzg2l_cru_ip *ip = &cru->ip;
+ int ret;
+
+ ip->subdev.dev = cru->dev;
+ v4l2_subdev_init(&ip->subdev, &rzg2l_cru_ip_subdev_ops);
+ v4l2_set_subdevdata(&ip->subdev, cru);
+ snprintf(ip->subdev.name, sizeof(ip->subdev.name),
+ "cru-ip-%s", dev_name(cru->dev));
+ ip->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops;
+
+ ip->pads[0].flags = MEDIA_PAD_FL_SINK;
+ ip->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_init_finalize(&ip->subdev);
+ if (ret < 0)
+ goto entity_cleanup;
+
+ ret = v4l2_device_register_subdev(&cru->v4l2_dev, &ip->subdev);
+ if (ret < 0)
+ goto error_subdev;
+
+ return 0;
+error_subdev:
+ v4l2_subdev_cleanup(&ip->subdev);
+entity_cleanup:
+ media_entity_cleanup(&ip->subdev.entity);
+
+ return ret;
+}
+
+void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru)
+{
+ struct rzg2l_cru_ip *ip = &cru->ip;
+
+ media_entity_cleanup(&ip->subdev.entity);
+ v4l2_subdev_cleanup(&ip->subdev);
+ v4l2_device_unregister_subdev(&ip->subdev);
+}
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
new file mode 100644
index 000000000000..91b57c7c2e56
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -0,0 +1,1058 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Renesas RZ/G2L CRU
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ *
+ * Based on Renesas R-Car VIN
+ * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2011-2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
+ * Copyright (C) 2008 Magnus Damm
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "rzg2l-cru.h"
+
+/* HW CRU Registers Definition */
+
+/* CRU Control Register */
+#define CRUnCTRL 0x0
+#define CRUnCTRL_VINSEL(x) ((x) << 0)
+
+/* CRU Interrupt Enable Register */
+#define CRUnIE 0x4
+#define CRUnIE_EFE BIT(17)
+
+/* CRU Interrupt Status Register */
+#define CRUnINTS 0x8
+#define CRUnINTS_SFS BIT(16)
+
+/* CRU Reset Register */
+#define CRUnRST 0xc
+#define CRUnRST_VRESETN BIT(0)
+
+/* Memory Bank Base Address (Lower) Register for CRU Image Data */
+#define AMnMBxADDRL(x) (0x100 + ((x) * 8))
+
+/* Memory Bank Base Address (Higher) Register for CRU Image Data */
+#define AMnMBxADDRH(x) (0x104 + ((x) * 8))
+
+/* Memory Bank Enable Register for CRU Image Data */
+#define AMnMBVALID 0x148
+#define AMnMBVALID_MBVALID(x) GENMASK(x, 0)
+
+/* Memory Bank Status Register for CRU Image Data */
+#define AMnMBS 0x14c
+#define AMnMBS_MBSTS 0x7
+
+/* AXI Master FIFO Pointer Register for CRU Image Data */
+#define AMnFIFOPNTR 0x168
+#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0)
+#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16)
+
+/* AXI Master Transfer Stop Register for CRU Image Data */
+#define AMnAXISTP 0x174
+#define AMnAXISTP_AXI_STOP BIT(0)
+
+/* AXI Master Transfer Stop Status Register for CRU Image Data */
+#define AMnAXISTPACK 0x178
+#define AMnAXISTPACK_AXI_STOP_ACK BIT(0)
+
+/* CRU Image Processing Enable Register */
+#define ICnEN 0x200
+#define ICnEN_ICEN BIT(0)
+
+/* CRU Image Processing Main Control Register */
+#define ICnMC 0x208
+#define ICnMC_CSCTHR BIT(5)
+#define ICnMC_INF_YUV8_422 (0x1e << 16)
+#define ICnMC_INF_USER (0x30 << 16)
+#define ICnMC_VCSEL(x) ((x) << 22)
+#define ICnMC_INF_MASK GENMASK(21, 16)
+
+/* CRU Module Status Register */
+#define ICnMS 0x254
+#define ICnMS_IA BIT(2)
+
+/* CRU Data Output Mode Register */
+#define ICnDMR 0x26c
+#define ICnDMR_YCMODE_UYVY (1 << 4)
+
+#define RZG2L_TIMEOUT_MS 100
+#define RZG2L_RETRIES 10
+
+#define RZG2L_CRU_DEFAULT_FORMAT V4L2_PIX_FMT_UYVY
+#define RZG2L_CRU_DEFAULT_WIDTH RZG2L_CRU_MIN_INPUT_WIDTH
+#define RZG2L_CRU_DEFAULT_HEIGHT RZG2L_CRU_MIN_INPUT_HEIGHT
+#define RZG2L_CRU_DEFAULT_FIELD V4L2_FIELD_NONE
+#define RZG2L_CRU_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
+
+struct rzg2l_cru_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+#define to_buf_list(vb2_buffer) \
+ (&container_of(vb2_buffer, struct rzg2l_cru_buffer, vb)->list)
+
+/* -----------------------------------------------------------------------------
+ * DMA operations
+ */
+static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
+{
+ iowrite32(value, cru->base + offset);
+}
+
+static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
+{
+ return ioread32(cru->base + offset);
+}
+
+/* Need to hold qlock before calling */
+static void return_unused_buffers(struct rzg2l_cru_dev *cru,
+ enum vb2_buffer_state state)
+{
+ struct rzg2l_cru_buffer *buf, *node;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&cru->qlock, flags);
+ for (i = 0; i < cru->num_buf; i++) {
+ if (cru->queue_buf[i]) {
+ vb2_buffer_done(&cru->queue_buf[i]->vb2_buf,
+ state);
+ cru->queue_buf[i] = NULL;
+ }
+ }
+
+ list_for_each_entry_safe(buf, node, &cru->buf_list, list) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
+ spin_unlock_irqrestore(&cru->qlock, flags);
+}
+
+static int rzg2l_cru_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
+
+ /* Make sure the image size is large enough. */
+ if (*nplanes)
+ return sizes[0] < cru->format.sizeimage ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = cru->format.sizeimage;
+
+ return 0;
+};
+
+static int rzg2l_cru_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size = cru->format.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_err(cru->dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cru->qlock, flags);
+
+ list_add_tail(to_buf_list(vbuf), &cru->buf_list);
+
+ spin_unlock_irqrestore(&cru->qlock, flags);
+}
+
+static int rzg2l_cru_mc_validate_format(struct rzg2l_cru_dev *cru,
+ struct v4l2_subdev *sd,
+ struct media_pad *pad)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ fmt.pad = pad->index;
+ if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt))
+ return -EPIPE;
+
+ switch (fmt.format.code) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ break;
+ default:
+ return -EPIPE;
+ }
+
+ switch (fmt.format.field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
+ break;
+ default:
+ return -EPIPE;
+ }
+
+ if (fmt.format.width != cru->format.width ||
+ fmt.format.height != cru->format.height)
+ return -EPIPE;
+
+ return 0;
+}
+
+static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
+ int slot, dma_addr_t addr)
+{
+ /*
+ * The address needs to be 512 bytes aligned. Driver should never accept
+ * settings that do not satisfy this in the first place...
+ */
+ if (WARN_ON((addr) & RZG2L_CRU_HW_BUFFER_MASK))
+ return;
+
+ /* Currently, we just use the buffer in 32 bits address */
+ rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
+ rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
+}
+
+/*
+ * Moves a buffer from the queue to the HW slot. If no buffer is
+ * available use the scratch buffer. The scratch buffer is never
+ * returned to userspace, its only function is to enable the capture
+ * loop to keep running.
+ */
+static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
+{
+ struct vb2_v4l2_buffer *vbuf;
+ struct rzg2l_cru_buffer *buf;
+ dma_addr_t phys_addr;
+
+ /* A already populated slot shall never be overwritten. */
+ if (WARN_ON(cru->queue_buf[slot]))
+ return;
+
+ dev_dbg(cru->dev, "Filling HW slot: %d\n", slot);
+
+ if (list_empty(&cru->buf_list)) {
+ cru->queue_buf[slot] = NULL;
+ phys_addr = cru->scratch_phys;
+ } else {
+ /* Keep track of buffer we give to HW */
+ buf = list_entry(cru->buf_list.next,
+ struct rzg2l_cru_buffer, list);
+ vbuf = &buf->vb;
+ list_del_init(to_buf_list(vbuf));
+ cru->queue_buf[slot] = vbuf;
+
+ /* Setup DMA */
+ phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+ }
+
+ rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
+}
+
+static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
+{
+ unsigned int slot;
+
+ /*
+ * Set image data memory banks.
+ * Currently, we will use maximum address.
+ */
+ rzg2l_cru_write(cru, AMnMBVALID, AMnMBVALID_MBVALID(cru->num_buf - 1));
+
+ for (slot = 0; slot < cru->num_buf; slot++)
+ rzg2l_cru_fill_hw_slot(cru, slot);
+}
+
+static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, bool *input_is_yuv,
+ struct v4l2_mbus_framefmt *ip_sd_fmt)
+{
+ u32 icnmc;
+
+ switch (ip_sd_fmt->code) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ icnmc = ICnMC_INF_YUV8_422;
+ *input_is_yuv = true;
+ break;
+ default:
+ *input_is_yuv = false;
+ icnmc = ICnMC_INF_USER;
+ break;
+ }
+
+ icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK);
+
+ /* Set virtual channel CSI2 */
+ icnmc |= ICnMC_VCSEL(cru->csi.channel);
+
+ rzg2l_cru_write(cru, ICnMC, icnmc);
+}
+
+static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
+ struct v4l2_mbus_framefmt *ip_sd_fmt)
+{
+ bool output_is_yuv = false;
+ bool input_is_yuv = false;
+ u32 icndmr;
+
+ rzg2l_cru_csi2_setup(cru, &input_is_yuv, ip_sd_fmt);
+
+ /* Output format */
+ switch (cru->format.pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ icndmr = ICnDMR_YCMODE_UYVY;
+ output_is_yuv = true;
+ break;
+ default:
+ dev_err(cru->dev, "Invalid pixelformat (0x%x)\n",
+ cru->format.pixelformat);
+ return -EINVAL;
+ }
+
+ /* If input and output use same colorspace, do bypass mode */
+ if (output_is_yuv == input_is_yuv)
+ rzg2l_cru_write(cru, ICnMC,
+ rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR);
+ else
+ rzg2l_cru_write(cru, ICnMC,
+ rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR));
+
+ /* Set output data format */
+ rzg2l_cru_write(cru, ICnDMR, icndmr);
+
+ return 0;
+}
+
+void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
+{
+ u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
+ unsigned int retries = 0;
+ unsigned long flags;
+ u32 icnms;
+
+ spin_lock_irqsave(&cru->qlock, flags);
+
+ /* Disable and clear the interrupt */
+ rzg2l_cru_write(cru, CRUnIE, 0);
+ rzg2l_cru_write(cru, CRUnINTS, 0x001F0F0F);
+
+ /* Stop the operation of image conversion */
+ rzg2l_cru_write(cru, ICnEN, 0);
+
+ /* Wait for streaming to stop */
+ while ((rzg2l_cru_read(cru, ICnMS) & ICnMS_IA) && retries++ < RZG2L_RETRIES) {
+ spin_unlock_irqrestore(&cru->qlock, flags);
+ msleep(RZG2L_TIMEOUT_MS);
+ spin_lock_irqsave(&cru->qlock, flags);
+ }
+
+ icnms = rzg2l_cru_read(cru, ICnMS) & ICnMS_IA;
+ if (icnms)
+ dev_err(cru->dev, "Failed stop HW, something is seriously broken\n");
+
+ cru->state = RZG2L_CRU_DMA_STOPPED;
+
+ /* Wait until the FIFO becomes empty */
+ for (retries = 5; retries > 0; retries--) {
+ amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
+
+ amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR;
+ amnfifopntr_r_y =
+ (amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16;
+ if (amnfifopntr_w == amnfifopntr_r_y)
+ break;
+
+ usleep_range(10, 20);
+ }
+
+ /* Notify that FIFO is not empty here */
+ if (!retries)
+ dev_err(cru->dev, "Failed to empty FIFO\n");
+
+ /* Stop AXI bus */
+ rzg2l_cru_write(cru, AMnAXISTP, AMnAXISTP_AXI_STOP);
+
+ /* Wait until the AXI bus stop */
+ for (retries = 5; retries > 0; retries--) {
+ if (rzg2l_cru_read(cru, AMnAXISTPACK) &
+ AMnAXISTPACK_AXI_STOP_ACK)
+ break;
+
+ usleep_range(10, 20);
+ };
+
+ /* Notify that AXI bus can not stop here */
+ if (!retries)
+ dev_err(cru->dev, "Failed to stop AXI bus\n");
+
+ /* Cancel the AXI bus stop request */
+ rzg2l_cru_write(cru, AMnAXISTP, 0);
+
+ /* Reset the CRU (AXI-master) */
+ reset_control_assert(cru->aresetn);
+
+ /* Resets the image processing module */
+ rzg2l_cru_write(cru, CRUnRST, 0);
+
+ spin_unlock_irqrestore(&cru->qlock, flags);
+}
+
+int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
+{
+ struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&cru->qlock, flags);
+
+ /* Initialize image convert */
+ ret = rzg2l_cru_initialize_image_conv(cru, fmt);
+ if (ret) {
+ spin_unlock_irqrestore(&cru->qlock, flags);
+ return ret;
+ }
+
+ /* Select a video input */
+ rzg2l_cru_write(cru, CRUnCTRL, CRUnCTRL_VINSEL(0));
+
+ /* Cancel the software reset for image processing block */
+ rzg2l_cru_write(cru, CRUnRST, CRUnRST_VRESETN);
+
+ /* Disable and clear the interrupt before using */
+ rzg2l_cru_write(cru, CRUnIE, 0);
+ rzg2l_cru_write(cru, CRUnINTS, 0x001f000f);
+
+ /* Initialize the AXI master */
+ rzg2l_cru_initialize_axi(cru);
+
+ /* Enable interrupt */
+ rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
+
+ /* Enable image processing reception */
+ rzg2l_cru_write(cru, ICnEN, ICnEN_ICEN);
+
+ spin_unlock_irqrestore(&cru->qlock, flags);
+
+ return 0;
+}
+
+void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru)
+{
+ clk_disable_unprepare(cru->vclk);
+}
+
+int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru)
+{
+ return clk_prepare_enable(cru->vclk);
+}
+
+static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
+{
+ struct media_pipeline *pipe;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ int ret;
+
+ pad = media_pad_remote_pad_first(&cru->pad);
+ if (!pad)
+ return -EPIPE;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (!on) {
+ int stream_off_ret = 0;
+
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ if (ret)
+ stream_off_ret = ret;
+
+ ret = v4l2_subdev_call(sd, video, post_streamoff);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (ret && !stream_off_ret)
+ stream_off_ret = ret;
+
+ video_device_pipeline_stop(&cru->vdev);
+
+ pm_runtime_put_sync(cru->dev);
+ clk_disable_unprepare(cru->vclk);
+
+ return stream_off_ret;
+ }
+
+ ret = pm_runtime_resume_and_get(cru->dev);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(cru->vclk);
+ if (ret)
+ goto err_pm_put;
+
+ ret = rzg2l_cru_mc_validate_format(cru, sd, pad);
+ if (ret)
+ goto err_vclk_disable;
+
+ pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe;
+ ret = video_device_pipeline_start(&cru->vdev, pipe);
+ if (ret)
+ goto err_vclk_disable;
+
+ ret = v4l2_subdev_call(sd, video, pre_streamon, 0);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (ret)
+ goto pipe_line_stop;
+
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ if (ret == -ENOIOCTLCMD)
+ ret = 0;
+ if (ret)
+ goto err_s_stream;
+
+ return 0;
+
+err_s_stream:
+ v4l2_subdev_call(sd, video, post_streamoff);
+
+pipe_line_stop:
+ video_device_pipeline_stop(&cru->vdev);
+
+err_vclk_disable:
+ clk_disable_unprepare(cru->vclk);
+
+err_pm_put:
+ pm_runtime_put_sync(cru->dev);
+
+ return ret;
+}
+
+static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
+{
+ cru->state = RZG2L_CRU_DMA_STOPPING;
+
+ rzg2l_cru_set_stream(cru, 0);
+}
+
+static irqreturn_t rzg2l_cru_irq(int irq, void *data)
+{
+ struct rzg2l_cru_dev *cru = data;
+ unsigned int handled = 0;
+ unsigned long flags;
+ u32 irq_status;
+ u32 amnmbs;
+ int slot;
+
+ spin_lock_irqsave(&cru->qlock, flags);
+
+ irq_status = rzg2l_cru_read(cru, CRUnINTS);
+ if (!irq_status)
+ goto done;
+
+ handled = 1;
+
+ rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
+
+ /* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
+ if (cru->state == RZG2L_CRU_DMA_STOPPED) {
+ dev_dbg(cru->dev, "IRQ while state stopped\n");
+ goto done;
+ }
+
+ /* Increase stop retries if capture status is 'RZG2L_CRU_DMA_STOPPING' */
+ if (cru->state == RZG2L_CRU_DMA_STOPPING) {
+ if (irq_status & CRUnINTS_SFS)
+ dev_dbg(cru->dev, "IRQ while state stopping\n");
+ goto done;
+ }
+
+ /* Prepare for capture and update state */
+ amnmbs = rzg2l_cru_read(cru, AMnMBS);
+ slot = amnmbs & AMnMBS_MBSTS;
+
+ /*
+ * AMnMBS.MBSTS indicates the destination of Memory Bank (MB).
+ * Recalculate to get the current transfer complete MB.
+ */
+ if (slot == 0)
+ slot = cru->num_buf - 1;
+ else
+ slot--;
+
+ /*
+ * To hand buffers back in a known order to userspace start
+ * to capture first from slot 0.
+ */
+ if (cru->state == RZG2L_CRU_DMA_STARTING) {
+ if (slot != 0) {
+ dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
+ goto done;
+ }
+
+ dev_dbg(cru->dev, "Capture start synced!\n");
+ cru->state = RZG2L_CRU_DMA_RUNNING;
+ }
+
+ /* Capture frame */
+ if (cru->queue_buf[slot]) {
+ cru->queue_buf[slot]->field = cru->format.field;
+ cru->queue_buf[slot]->sequence = cru->sequence;
+ cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
+ vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
+ VB2_BUF_STATE_DONE);
+ cru->queue_buf[slot] = NULL;
+ } else {
+ /* Scratch buffer was used, dropping frame. */
+ dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
+ }
+
+ cru->sequence++;
+
+ /* Prepare for next frame */
+ rzg2l_cru_fill_hw_slot(cru, slot);
+
+done:
+ spin_unlock_irqrestore(&cru->qlock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
+{
+ struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
+ int ret;
+
+ /* Release reset state */
+ ret = reset_control_deassert(cru->aresetn);
+ if (ret) {
+ dev_err(cru->dev, "failed to deassert aresetn\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(cru->presetn);
+ if (ret) {
+ reset_control_assert(cru->aresetn);
+ dev_err(cru->dev, "failed to deassert presetn\n");
+ return ret;
+ }
+
+ ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq,
+ IRQF_SHARED, KBUILD_MODNAME, cru);
+ if (ret) {
+ dev_err(cru->dev, "failed to request irq\n");
+ goto assert_resets;
+ }
+
+ /* Allocate scratch buffer. */
+ cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
+ &cru->scratch_phys, GFP_KERNEL);
+ if (!cru->scratch) {
+ return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
+ dev_err(cru->dev, "Failed to allocate scratch buffer\n");
+ ret = -ENOMEM;
+ goto free_image_conv_irq;
+ }
+
+ cru->sequence = 0;
+
+ ret = rzg2l_cru_set_stream(cru, 1);
+ if (ret) {
+ return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
+ goto out;
+ }
+
+ cru->state = RZG2L_CRU_DMA_STARTING;
+ dev_dbg(cru->dev, "Starting to capture\n");
+ return 0;
+
+out:
+ if (ret)
+ dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch,
+ cru->scratch_phys);
+free_image_conv_irq:
+ free_irq(cru->image_conv_irq, cru);
+
+assert_resets:
+ reset_control_assert(cru->presetn);
+ reset_control_assert(cru->aresetn);
+
+ return ret;
+}
+
+static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
+{
+ struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
+
+ rzg2l_cru_stop_streaming(cru);
+
+ /* Free scratch buffer */
+ dma_free_coherent(cru->dev, cru->format.sizeimage,
+ cru->scratch, cru->scratch_phys);
+
+ free_irq(cru->image_conv_irq, cru);
+ reset_control_assert(cru->presetn);
+
+ return_unused_buffers(cru, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops rzg2l_cru_qops = {
+ .queue_setup = rzg2l_cru_queue_setup,
+ .buf_prepare = rzg2l_cru_buffer_prepare,
+ .buf_queue = rzg2l_cru_buffer_queue,
+ .start_streaming = rzg2l_cru_start_streaming_vq,
+ .stop_streaming = rzg2l_cru_stop_streaming_vq,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru)
+{
+ mutex_destroy(&cru->lock);
+
+ v4l2_device_unregister(&cru->v4l2_dev);
+ vb2_queue_release(&cru->queue);
+}
+
+int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
+{
+ struct vb2_queue *q = &cru->queue;
+ unsigned int i;
+ int ret;
+
+ /* Initialize the top-level structure */
+ ret = v4l2_device_register(cru->dev, &cru->v4l2_dev);
+ if (ret)
+ return ret;
+
+ mutex_init(&cru->lock);
+ INIT_LIST_HEAD(&cru->buf_list);
+
+ spin_lock_init(&cru->qlock);
+
+ cru->state = RZG2L_CRU_DMA_STOPPED;
+
+ for (i = 0; i < RZG2L_CRU_HW_BUFFER_MAX; i++)
+ cru->queue_buf[i] = NULL;
+
+ /* buffer queue */
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->lock = &cru->lock;
+ q->drv_priv = cru;
+ q->buf_struct_size = sizeof(struct rzg2l_cru_buffer);
+ q->ops = &rzg2l_cru_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 4;
+ q->dev = cru->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(cru->dev, "failed to initialize VB2 queue\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ mutex_destroy(&cru->lock);
+ v4l2_device_unregister(&cru->v4l2_dev);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 stuff
+ */
+
+static const struct v4l2_format_info rzg2l_cru_formats[] = {
+ {
+ .format = V4L2_PIX_FMT_UYVY,
+ .bpp[0] = 2,
+ },
+};
+
+const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rzg2l_cru_formats); i++)
+ if (rzg2l_cru_formats[i].format == format)
+ return rzg2l_cru_formats + i;
+
+ return NULL;
+}
+
+static u32 rzg2l_cru_format_bytesperline(struct v4l2_pix_format *pix)
+{
+ const struct v4l2_format_info *fmt;
+
+ fmt = rzg2l_cru_format_from_pixel(pix->pixelformat);
+
+ if (WARN_ON(!fmt))
+ return -EINVAL;
+
+ return pix->width * fmt->bpp[0];
+}
+
+static u32 rzg2l_cru_format_sizeimage(struct v4l2_pix_format *pix)
+{
+ return pix->bytesperline * pix->height;
+}
+
+static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
+ struct v4l2_pix_format *pix)
+{
+ if (!rzg2l_cru_format_from_pixel(pix->pixelformat))
+ pix->pixelformat = RZG2L_CRU_DEFAULT_FORMAT;
+
+ switch (pix->field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ pix->field = RZG2L_CRU_DEFAULT_FIELD;
+ break;
+ }
+
+ /* Limit to CRU capabilities */
+ v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1,
+ &pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0);
+
+ pix->bytesperline = rzg2l_cru_format_bytesperline(pix);
+ pix->sizeimage = rzg2l_cru_format_sizeimage(pix);
+
+ dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n",
+ pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+}
+
+static void rzg2l_cru_try_format(struct rzg2l_cru_dev *cru,
+ struct v4l2_pix_format *pix)
+{
+ /*
+ * The V4L2 specification clearly documents the colorspace fields
+ * as being set by drivers for capture devices. Using the values
+ * supplied by userspace thus wouldn't comply with the API. Until
+ * the API is updated force fixed values.
+ */
+ pix->colorspace = RZG2L_CRU_DEFAULT_COLORSPACE;
+ pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
+ pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
+ pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
+ pix->ycbcr_enc);
+
+ rzg2l_cru_format_align(cru, pix);
+}
+
+static int rzg2l_cru_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, "RZG2L_CRU", sizeof(cap->card));
+
+ return 0;
+}
+
+static int rzg2l_cru_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rzg2l_cru_dev *cru = video_drvdata(file);
+
+ rzg2l_cru_try_format(cru, &f->fmt.pix);
+
+ return 0;
+}
+
+static int rzg2l_cru_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rzg2l_cru_dev *cru = video_drvdata(file);
+
+ if (vb2_is_busy(&cru->queue))
+ return -EBUSY;
+
+ rzg2l_cru_try_format(cru, &f->fmt.pix);
+
+ cru->format = f->fmt.pix;
+
+ return 0;
+}
+
+static int rzg2l_cru_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rzg2l_cru_dev *cru = video_drvdata(file);
+
+ f->fmt.pix = cru->format;
+
+ return 0;
+}
+
+static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(rzg2l_cru_formats))
+ return -EINVAL;
+
+ f->pixelformat = rzg2l_cru_formats[f->index].format;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops rzg2l_cru_ioctl_ops = {
+ .vidioc_querycap = rzg2l_cru_querycap,
+ .vidioc_try_fmt_vid_cap = rzg2l_cru_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = rzg2l_cru_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = rzg2l_cru_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = rzg2l_cru_enum_fmt_vid_cap,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media controller file operations
+ */
+
+static int rzg2l_cru_open(struct file *file)
+{
+ struct rzg2l_cru_dev *cru = video_drvdata(file);
+ int ret;
+
+ ret = mutex_lock_interruptible(&cru->lock);
+ if (ret)
+ return ret;
+
+ file->private_data = cru;
+ ret = v4l2_fh_open(file);
+ if (ret)
+ goto err_unlock;
+
+ mutex_unlock(&cru->lock);
+
+ return 0;
+
+err_unlock:
+ mutex_unlock(&cru->lock);
+
+ return ret;
+}
+
+static int rzg2l_cru_release(struct file *file)
+{
+ struct rzg2l_cru_dev *cru = video_drvdata(file);
+ int ret;
+
+ mutex_lock(&cru->lock);
+
+ /* the release helper will cleanup any on-going streaming. */
+ ret = _vb2_fop_release(file, NULL);
+
+ mutex_unlock(&cru->lock);
+
+ return ret;
+}
+
+static const struct v4l2_file_operations rzg2l_cru_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = rzg2l_cru_open,
+ .release = rzg2l_cru_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .read = vb2_fop_read,
+};
+
+static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru)
+{
+ struct video_device *vdev = &cru->vdev;
+
+ vdev->v4l2_dev = &cru->v4l2_dev;
+ vdev->queue = &cru->queue;
+ snprintf(vdev->name, sizeof(vdev->name), "CRU output");
+ vdev->release = video_device_release_empty;
+ vdev->lock = &cru->lock;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ vdev->device_caps |= V4L2_CAP_IO_MC;
+ vdev->fops = &rzg2l_cru_fops;
+ vdev->ioctl_ops = &rzg2l_cru_ioctl_ops;
+
+ /* Set a default format */
+ cru->format.pixelformat = RZG2L_CRU_DEFAULT_FORMAT;
+ cru->format.width = RZG2L_CRU_DEFAULT_WIDTH;
+ cru->format.height = RZG2L_CRU_DEFAULT_HEIGHT;
+ cru->format.field = RZG2L_CRU_DEFAULT_FIELD;
+ cru->format.colorspace = RZG2L_CRU_DEFAULT_COLORSPACE;
+ rzg2l_cru_format_align(cru, &cru->format);
+}
+
+void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru)
+{
+ media_device_unregister(&cru->mdev);
+ video_unregister_device(&cru->vdev);
+}
+
+int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru)
+{
+ struct video_device *vdev = &cru->vdev;
+ int ret;
+
+ if (video_is_registered(&cru->vdev)) {
+ struct media_entity *entity;
+
+ entity = &cru->vdev.entity;
+ if (!entity->graph_obj.mdev)
+ entity->graph_obj.mdev = &cru->mdev;
+ return 0;
+ }
+
+ rzg2l_cru_v4l2_init(cru);
+ video_set_drvdata(vdev, cru);
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(cru->dev, "Failed to register video device\n");
+ return ret;
+ }
+
+ ret = media_device_register(&cru->mdev);
+ if (ret) {
+ video_unregister_device(&cru->vdev);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index d8731ebbf479..3482f7d707b7 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -715,7 +715,7 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params,
u32 exp_ctrl;
u32 block_hsize, block_vsize;
u32 wnd_num_idx = 1;
- const u32 ae_wnd_num[] = { 5, 9, 15, 15 };
+ static const u32 ae_wnd_num[] = { 5, 9, 15, 15 };
/* avoid to override the old enable value */
exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL);
@@ -822,7 +822,7 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params,
u32 block_hsize, block_vsize;
u32 wnd_num_idx, hist_weight_num, hist_ctrl, value;
u8 weight15x15[RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12];
- const u32 hist_wnd_num[] = { 5, 9, 15, 15 };
+ static const u32 hist_wnd_num[] = { 5, 9, 15, 15 };
/* now we just support 9x9 window */
wnd_num_idx = 1;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
index 91cc8d58a663..1791100b6935 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
@@ -1173,7 +1173,7 @@ int __init fimc_register_driver(void)
return platform_driver_register(&fimc_driver);
}
-void __exit fimc_unregister_driver(void)
+void fimc_unregister_driver(void)
{
platform_driver_unregister(&fimc_driver);
}
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 52b43ea04030..98a60f01129d 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -1380,9 +1380,7 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
/* Find platform data for this sensor subdev */
for (i = 0; i < ARRAY_SIZE(fmd->sensor); i++)
- if (fmd->sensor[i].asd &&
- fmd->sensor[i].asd->match.fwnode ==
- of_fwnode_handle(subdev->dev->of_node))
+ if (fmd->sensor[i].asd == asd)
si = &fmd->sensor[i];
if (si == NULL)
@@ -1473,9 +1471,7 @@ static int fimc_md_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pinctrl)) {
- ret = PTR_ERR(pinctrl);
- if (ret != EPROBE_DEFER)
- dev_err(dev, "Failed to get pinctrl: %d\n", ret);
+ ret = dev_err_probe(dev, PTR_ERR(pinctrl), "Failed to get pinctrl\n");
goto err_clk;
}
@@ -1586,7 +1582,11 @@ static int __init fimc_md_init(void)
if (ret)
return ret;
- return platform_driver_register(&fimc_md_driver);
+ ret = platform_driver_register(&fimc_md_driver);
+ if (ret)
+ fimc_unregister_driver();
+
+ return ret;
}
static void __exit fimc_md_exit(void)
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index fca5c6405eec..f3e4cdac1ef3 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -36,7 +36,7 @@
#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
int mfc_debug_level;
-module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR);
+module_param_named(debug, mfc_debug_level, int, 0644);
MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
static char *mfc_mem_size;
@@ -148,11 +148,13 @@ static void s5p_mfc_watchdog(struct timer_list *t)
if (test_bit(0, &dev->hw_lock))
atomic_inc(&dev->watchdog_cnt);
if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
- /* This means that hw is busy and no interrupts were
+ /*
+ * This means that hw is busy and no interrupts were
* generated by hw for the Nth time of running this
* watchdog timer. This usually means a serious hw
* error. Now it is time to kill all instances and
- * reset the MFC. */
+ * reset the MFC.
+ */
mfc_err("Time out during waiting for HW\n");
schedule_work(&dev->watchdog_work);
}
@@ -172,8 +174,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
mfc_err("Driver timeout error handling\n");
- /* Lock the mutex that protects open and release.
- * This is necessary as they may load and unload firmware. */
+ /*
+ * Lock the mutex that protects open and release.
+ * This is necessary as they may load and unload firmware.
+ */
mutex_locked = mutex_trylock(&dev->mfc_mutex);
if (!mutex_locked)
mfc_err("Error: some instance may be closing/opening\n");
@@ -197,8 +201,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
/* De-init MFC */
s5p_mfc_deinit_hw(dev);
- /* Double check if there is at least one instance running.
- * If no instance is in memory than no firmware should be present */
+ /*
+ * Double check if there is at least one instance running.
+ * If no instance is in memory than no firmware should be present
+ */
if (dev->num_inst > 0) {
ret = s5p_mfc_load_firmware(dev);
if (ret) {
@@ -260,8 +266,10 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
return;
dec_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev);
- /* Copy timestamp / timecode from decoded src to dst and set
- appropriate flags. */
+ /*
+ * Copy timestamp / timecode from decoded src to dst and set
+ * appropriate flags.
+ */
src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0);
@@ -289,8 +297,10 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
V4L2_BUF_FLAG_BFRAME;
break;
default:
- /* Don't know how to handle
- S5P_FIMV_DECODE_FRAME_OTHER_FRAME. */
+ /*
+ * Don't know how to handle
+ * S5P_FIMV_DECODE_FRAME_OTHER_FRAME.
+ */
mfc_debug(2, "Unexpected frame type: %d\n",
frame_type);
}
@@ -322,8 +332,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
return;
}
ctx->sequence++;
- /* The MFC returns address of the buffer, now we have to
- * check which vb2_buffer does it correspond to */
+ /*
+ * The MFC returns address of the buffer, now we have to
+ * check which vb2_buffer does it correspond to
+ */
list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0);
@@ -476,8 +488,10 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
case MFCINST_FINISHING:
case MFCINST_FINISHED:
case MFCINST_RUNNING:
- /* It is highly probable that an error occurred
- * while decoding a frame */
+ /*
+ * It is highly probable that an error occurred
+ * while decoding a frame
+ */
clear_work_bit(ctx);
ctx->state = MFCINST_ERROR;
/* Mark all dst buffers as having an error */
@@ -535,6 +549,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) &&
!list_empty(&ctx->src_queue)) {
struct s5p_mfc_buf *src_buf;
+
src_buf = list_entry(ctx->src_queue.next,
struct s5p_mfc_buf, list);
if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream,
@@ -951,7 +966,7 @@ static int s5p_mfc_release(struct file *file)
/*
* If instance was initialised and not yet freed,
* return instance and free resources
- */
+ */
if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
mfc_debug(2, "Has to free instance\n");
s5p_mfc_close_mfc_inst(dev, ctx);
@@ -1047,10 +1062,10 @@ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
int ret;
if (offset < DST_QUEUE_OFF_BASE) {
- mfc_debug(2, "mmaping source\n");
+ mfc_debug(2, "mmapping source\n");
ret = vb2_mmap(&ctx->vq_src, vma);
} else { /* capture */
- mfc_debug(2, "mmaping destination\n");
+ mfc_debug(2, "mmapping destination\n");
vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
ret = vb2_mmap(&ctx->vq_dst, vma);
}
@@ -1149,7 +1164,6 @@ static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev)
bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK_R_CTX],
align_size, &bank2_dma_addr, GFP_KERNEL);
if (!bank2_virt) {
- mfc_err("Allocating bank2 base failed\n");
s5p_mfc_release_firmware(mfc_dev);
device_unregister(mfc_dev->mem_dev[BANK_R_CTX]);
device_unregister(mfc_dev->mem_dev[BANK_L_CTX]);
@@ -1318,7 +1332,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
/*
* Load fails if fs isn't mounted. Try loading anyway.
- * _open() will load it, it it fails now. Ignore failure.
+ * _open() will load it, it fails now. Ignore failure.
*/
s5p_mfc_load_firmware(dev);
@@ -1429,7 +1443,7 @@ static int s5p_mfc_remove(struct platform_device *pdev)
* Clear ctx dev pointer to avoid races between s5p_mfc_remove()
* and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev
* after s5p_mfc_remove() is run during unbind.
- */
+ */
mutex_lock(&dev->mfc_mutex);
for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
ctx = dev->ctx[i];
@@ -1576,8 +1590,18 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = {
.port_num = MFC_NUM_PORTS_V7,
.buf_size = &buf_size_v7,
.fw_name[0] = "s5p-mfc-v7.fw",
- .clk_names = {"mfc", "sclk_mfc"},
- .num_clocks = 2,
+ .clk_names = {"mfc"},
+ .num_clocks = 1,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v7_3250 = {
+ .version = MFC_VERSION_V7,
+ .version_bit = MFC_V7_BIT,
+ .port_num = MFC_NUM_PORTS_V7,
+ .buf_size = &buf_size_v7,
+ .fw_name[0] = "s5p-mfc-v7.fw",
+ .clk_names = {"mfc", "sclk_mfc"},
+ .num_clocks = 2,
};
static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
@@ -1648,6 +1672,9 @@ static const struct of_device_id exynos_mfc_match[] = {
.compatible = "samsung,mfc-v7",
.data = &mfc_drvdata_v7,
}, {
+ .compatible = "samsung,exynos3250-mfc",
+ .data = &mfc_drvdata_v7_3250,
+ }, {
.compatible = "samsung,mfc-v8",
.data = &mfc_drvdata_v8,
}, {
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
index 72d70984e99a..6d3c92045c05 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
@@ -468,8 +468,10 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
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))
+ S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)){
+ clear_work_bit_irqsave(ctx);
mfc_err("Err returning instance\n");
+ }
/* Free resources */
s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index b65e506665af..f62703cebb77 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -1218,6 +1218,7 @@ 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;
+ bool src_ready;
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);
@@ -1257,7 +1258,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
}
}
}
- if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+ if (ctx->src_queue_cnt > 0 && (ctx->state == MFCINST_RUNNING ||
+ ctx->state == MFCINST_FINISHING)) {
mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
list);
if (mb_entry->flags & MFC_BUF_FLAG_USED) {
@@ -1288,7 +1290,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);
}
- if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0))
+
+ src_ready = true;
+ if (ctx->state == MFCINST_RUNNING && ctx->src_queue_cnt == 0)
+ src_ready = false;
+ if (ctx->state == MFCINST_FINISHING && ctx->ref_queue_cnt == 0)
+ src_ready = false;
+ if (!src_ready || ctx->dst_queue_cnt == 0)
clear_work_bit(ctx);
return 0;
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
index 8227004f6746..c0df5ac9fcff 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1060,7 +1060,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
}
/* aspect ratio VUI */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 5);
reg |= ((p_h264->vui_sar & 0x1) << 5);
writel(reg, mfc_regs->e_h264_options);
@@ -1083,7 +1083,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
/* intra picture period for H.264 open GOP */
/* control */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 4);
reg |= ((p_h264->open_gop & 0x1) << 4);
writel(reg, mfc_regs->e_h264_options);
@@ -1097,23 +1097,23 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
}
/* 'WEIGHTED_BI_PREDICTION' for B is disable */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x3 << 9);
writel(reg, mfc_regs->e_h264_options);
/* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 14);
writel(reg, mfc_regs->e_h264_options);
/* ASO */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 6);
reg |= ((p_h264->aso & 0x1) << 6);
writel(reg, mfc_regs->e_h264_options);
/* hier qp enable */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 8);
reg |= ((p_h264->open_gop & 0x1) << 8);
writel(reg, mfc_regs->e_h264_options);
@@ -1134,7 +1134,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
writel(reg, mfc_regs->e_h264_num_t_layer);
/* frame packing SEI generation */
- readl(mfc_regs->e_h264_options);
+ reg = readl(mfc_regs->e_h264_options);
reg &= ~(0x1 << 25);
reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
writel(reg, mfc_regs->e_h264_options);
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
index cefe6b7bfdc4..c38b62d4f1ae 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
@@ -24,16 +24,18 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
-#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/usb.h>
#include <linux/wait.h>
-#include <linux/pinctrl/pinctrl.h>
-#include "c8sectpfe-core.h"
#include "c8sectpfe-common.h"
+#include "c8sectpfe-core.h"
#include "c8sectpfe-debugfs.h"
+
#include <media/dmxdev.h>
#include <media/dvb_demux.h>
#include <media/dvb_frontend.h>
@@ -925,6 +927,7 @@ static int configure_channels(struct c8sectpfei *fei)
if (ret) {
dev_err(fei->dev,
"configure_memdma_and_inputblock failed\n");
+ of_node_put(child);
goto err_unmap;
}
index++;
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 37458d4d9564..ad8e9742e1ae 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -1946,12 +1946,9 @@ static int dcmi_probe(struct platform_device *pdev)
return -ENOMEM;
dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(dcmi->rstc)) {
- if (PTR_ERR(dcmi->rstc) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Could not get reset control\n");
-
- return PTR_ERR(dcmi->rstc);
- }
+ if (IS_ERR(dcmi->rstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dcmi->rstc),
+ "Could not get reset control\n");
/* Get bus characteristics from devicetree */
np = of_graph_get_next_endpoint(np, NULL);
@@ -1997,26 +1994,18 @@ static int dcmi_probe(struct platform_device *pdev)
}
dcmi->regs = devm_ioremap_resource(&pdev->dev, dcmi->res);
- if (IS_ERR(dcmi->regs)) {
- dev_err(&pdev->dev, "Could not map registers\n");
+ if (IS_ERR(dcmi->regs))
return PTR_ERR(dcmi->regs);
- }
mclk = devm_clk_get(&pdev->dev, "mclk");
- if (IS_ERR(mclk)) {
- if (PTR_ERR(mclk) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Unable to get mclk\n");
- return PTR_ERR(mclk);
- }
+ if (IS_ERR(mclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(mclk),
+ "Unable to get mclk\n");
chan = dma_request_chan(&pdev->dev, "tx");
- if (IS_ERR(chan)) {
- ret = PTR_ERR(chan);
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "Failed to request DMA channel: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(chan))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chan),
+ "Failed to request DMA channel\n");
dcmi->dma_max_burst = UINT_MAX;
ret = dma_get_slave_caps(chan, &caps);
diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile
index e7e315347804..87e7a715140a 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/Makefile
+++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-sun6i-csi-y += sun6i_video.o sun6i_csi.o
+sun6i-csi-y += sun6i_csi.o sun6i_csi_bridge.o sun6i_csi_capture.o
obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 8b99c17e8403..e3e6650181c8 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -1,18 +1,14 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
- * All rights reserved.
* Author: Yong Deng <yong.deng@magewell.com>
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/fs.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ioctl.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -20,561 +16,56 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <linux/sched.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-mc.h>
#include "sun6i_csi.h"
+#include "sun6i_csi_bridge.h"
+#include "sun6i_csi_capture.h"
#include "sun6i_csi_reg.h"
-/* Helpers */
+/* ISP */
-/* TODO add 10&12 bit YUV, RGB support */
-bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev,
- u32 pixformat, u32 mbus_code)
+int sun6i_csi_isp_complete(struct sun6i_csi_device *csi_dev,
+ struct v4l2_device *v4l2_dev)
{
- struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
-
- /*
- * Some video receivers have the ability to be compatible with
- * 8bit and 16bit bus width.
- * Identify the media bus format from device tree.
- */
- if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
- || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656)
- && v4l2->v4l2_ep.bus.parallel.bus_width == 16) {
- switch (pixformat) {
- case V4L2_PIX_FMT_NV12_16L16:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_YUV422P:
- switch (mbus_code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- case MEDIA_BUS_FMT_VYUY8_1X16:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YVYU8_1X16:
- return true;
- default:
- dev_dbg(csi_dev->dev,
- "Unsupported mbus code: 0x%x\n",
- mbus_code);
- break;
- }
- break;
- default:
- dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n",
- pixformat);
- break;
- }
- return false;
- }
+ if (csi_dev->v4l2_dev && csi_dev->v4l2_dev != v4l2_dev)
+ return -EINVAL;
- switch (pixformat) {
- case V4L2_PIX_FMT_SBGGR8:
- return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8);
- case V4L2_PIX_FMT_SGBRG8:
- return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8);
- case V4L2_PIX_FMT_SGRBG8:
- return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8);
- case V4L2_PIX_FMT_SRGGB8:
- return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8);
- case V4L2_PIX_FMT_SBGGR10:
- return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10);
- case V4L2_PIX_FMT_SGBRG10:
- return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10);
- case V4L2_PIX_FMT_SGRBG10:
- return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10);
- case V4L2_PIX_FMT_SRGGB10:
- return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10);
- case V4L2_PIX_FMT_SBGGR12:
- return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12);
- case V4L2_PIX_FMT_SGBRG12:
- return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12);
- case V4L2_PIX_FMT_SGRBG12:
- return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12);
- case V4L2_PIX_FMT_SRGGB12:
- return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12);
-
- case V4L2_PIX_FMT_YUYV:
- return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8);
- case V4L2_PIX_FMT_YVYU:
- return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8);
- case V4L2_PIX_FMT_UYVY:
- return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8);
- case V4L2_PIX_FMT_VYUY:
- return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8);
-
- case V4L2_PIX_FMT_NV12_16L16:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_YUV422P:
- switch (mbus_code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_VYUY8_2X8:
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_YVYU8_2X8:
- return true;
- default:
- dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
- mbus_code);
- break;
- }
- break;
-
- case V4L2_PIX_FMT_RGB565:
- return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_LE);
- case V4L2_PIX_FMT_RGB565X:
- return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_BE);
-
- case V4L2_PIX_FMT_JPEG:
- return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8);
-
- default:
- dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n",
- pixformat);
- break;
- }
+ csi_dev->v4l2_dev = v4l2_dev;
+ csi_dev->media_dev = v4l2_dev->mdev;
- return false;
+ return sun6i_csi_capture_setup(csi_dev);
}
-int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable)
+static int sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
{
struct device *dev = csi_dev->dev;
- struct regmap *regmap = csi_dev->regmap;
- int ret;
-
- if (!enable) {
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
- pm_runtime_put(dev);
+ struct fwnode_handle *handle;
+ /*
+ * ISP is not available if not connected via fwnode graph.
+ * This will also check that the remote parent node is available.
+ */
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ SUN6I_CSI_PORT_ISP, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!handle)
return 0;
- }
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret < 0)
- return ret;
-
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
-
- return 0;
-}
-
-static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev,
- u32 mbus_code, u32 pixformat)
-{
- /* non-YUV */
- if ((mbus_code & 0xF000) != 0x2000)
- return CSI_INPUT_FORMAT_RAW;
-
- switch (pixformat) {
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- return CSI_INPUT_FORMAT_RAW;
- default:
- break;
- }
- /* not support YUV420 input format yet */
- dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n");
- return CSI_INPUT_FORMAT_YUV422;
-}
-
-static enum csi_output_fmt
-get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat,
- u32 field)
-{
- bool buf_interlaced = false;
-
- if (field == V4L2_FIELD_INTERLACED
- || field == V4L2_FIELD_INTERLACED_TB
- || field == V4L2_FIELD_INTERLACED_BT)
- buf_interlaced = true;
-
- switch (pixformat) {
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SGBRG8:
- case V4L2_PIX_FMT_SGRBG8:
- case V4L2_PIX_FMT_SRGGB8:
- return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
- case V4L2_PIX_FMT_SBGGR10:
- case V4L2_PIX_FMT_SGBRG10:
- case V4L2_PIX_FMT_SGRBG10:
- case V4L2_PIX_FMT_SRGGB10:
- return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10;
- case V4L2_PIX_FMT_SBGGR12:
- case V4L2_PIX_FMT_SGBRG12:
- case V4L2_PIX_FMT_SGRBG12:
- case V4L2_PIX_FMT_SRGGB12:
- return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12;
-
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
-
- case V4L2_PIX_FMT_NV12_16L16:
- return buf_interlaced ? CSI_FRAME_MB_YUV420 :
- CSI_FIELD_MB_YUV420;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 :
- CSI_FIELD_UV_CB_YUV420;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 :
- CSI_FIELD_PLANAR_YUV420;
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 :
- CSI_FIELD_UV_CB_YUV422;
- case V4L2_PIX_FMT_YUV422P:
- return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 :
- CSI_FIELD_PLANAR_YUV422;
-
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565;
-
- case V4L2_PIX_FMT_JPEG:
- return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
-
- default:
- dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
- break;
- }
+ fwnode_handle_put(handle);
- return CSI_FIELD_RAW_8;
-}
-
-static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev,
- u32 mbus_code, u32 pixformat)
-{
- /* Input sequence does not apply to non-YUV formats */
- if ((mbus_code & 0xF000) != 0x2000)
+ if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP)) {
+ dev_warn(dev,
+ "ISP link is detected but not enabled in kernel config!");
return 0;
-
- switch (pixformat) {
- case V4L2_PIX_FMT_NV12_16L16:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YUV422P:
- switch (mbus_code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_UYVY8_1X16:
- return CSI_INPUT_SEQ_UYVY;
- case MEDIA_BUS_FMT_VYUY8_2X8:
- case MEDIA_BUS_FMT_VYUY8_1X16:
- return CSI_INPUT_SEQ_VYUY;
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- return CSI_INPUT_SEQ_YUYV;
- case MEDIA_BUS_FMT_YVYU8_1X16:
- case MEDIA_BUS_FMT_YVYU8_2X8:
- return CSI_INPUT_SEQ_YVYU;
- default:
- dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
- mbus_code);
- break;
- }
- break;
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV61:
- case V4L2_PIX_FMT_YVU420:
- switch (mbus_code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_UYVY8_1X16:
- return CSI_INPUT_SEQ_VYUY;
- case MEDIA_BUS_FMT_VYUY8_2X8:
- case MEDIA_BUS_FMT_VYUY8_1X16:
- return CSI_INPUT_SEQ_UYVY;
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- return CSI_INPUT_SEQ_YVYU;
- case MEDIA_BUS_FMT_YVYU8_1X16:
- case MEDIA_BUS_FMT_YVYU8_2X8:
- return CSI_INPUT_SEQ_YUYV;
- default:
- dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
- mbus_code);
- break;
- }
- break;
-
- case V4L2_PIX_FMT_YUYV:
- return CSI_INPUT_SEQ_YUYV;
-
- default:
- dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
- pixformat);
- break;
- }
-
- return CSI_INPUT_SEQ_YUYV;
-}
-
-static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)
-{
- struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep;
- struct sun6i_csi_config *config = &csi_dev->config;
- unsigned char bus_width;
- u32 flags;
- u32 cfg;
- bool input_interlaced = false;
-
- if (config->field == V4L2_FIELD_INTERLACED
- || config->field == V4L2_FIELD_INTERLACED_TB
- || config->field == V4L2_FIELD_INTERLACED_BT)
- input_interlaced = true;
-
- bus_width = endpoint->bus.parallel.bus_width;
-
- regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg);
-
- cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
- CSI_IF_CFG_IF_DATA_WIDTH_MASK |
- CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK |
- CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK |
- CSI_IF_CFG_SRC_TYPE_MASK);
-
- if (input_interlaced)
- cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED;
- else
- cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED;
-
- switch (endpoint->bus_type) {
- case V4L2_MBUS_PARALLEL:
- cfg |= CSI_IF_CFG_MIPI_IF_CSI;
-
- flags = endpoint->bus.parallel.flags;
-
- cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT :
- CSI_IF_CFG_CSI_IF_YUV422_INTLV;
-
- if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= CSI_IF_CFG_FIELD_POSITIVE;
-
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- cfg |= CSI_IF_CFG_VREF_POL_POSITIVE;
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= CSI_IF_CFG_HREF_POL_POSITIVE;
-
- if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
- break;
- case V4L2_MBUS_BT656:
- cfg |= CSI_IF_CFG_MIPI_IF_CSI;
-
- flags = endpoint->bus.parallel.flags;
-
- cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 :
- CSI_IF_CFG_CSI_IF_BT656;
-
- if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= CSI_IF_CFG_FIELD_POSITIVE;
-
- if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
- break;
- default:
- dev_warn(csi_dev->dev, "Unsupported bus type: %d\n",
- endpoint->bus_type);
- break;
- }
-
- switch (bus_width) {
- case 8:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
- break;
- case 10:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
- break;
- case 12:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
- break;
- case 16: /* No need to configure DATA_WIDTH for 16bit */
- break;
- default:
- dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width);
- break;
- }
-
- regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg);
-}
-
-static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_csi_config *config = &csi_dev->config;
- u32 cfg;
- u32 val;
-
- regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg);
-
- cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
- CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
- CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
- CSI_CH_CFG_INPUT_SEQ_MASK);
-
- val = get_csi_input_format(csi_dev, config->code,
- config->pixelformat);
- cfg |= CSI_CH_CFG_INPUT_FMT(val);
-
- val = get_csi_output_format(csi_dev, config->pixelformat,
- config->field);
- cfg |= CSI_CH_CFG_OUTPUT_FMT(val);
-
- val = get_csi_input_seq(csi_dev, config->code,
- config->pixelformat);
- cfg |= CSI_CH_CFG_INPUT_SEQ(val);
-
- if (config->field == V4L2_FIELD_TOP)
- cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
- else if (config->field == V4L2_FIELD_BOTTOM)
- cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
- else
- cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;
-
- regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg);
-}
-
-static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_csi_config *config = &csi_dev->config;
- u32 bytesperline_y;
- u32 bytesperline_c;
- int *planar_offset = csi_dev->planar_offset;
- u32 width = config->width;
- u32 height = config->height;
- u32 hor_len = width;
-
- switch (config->pixelformat) {
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- dev_dbg(csi_dev->dev,
- "Horizontal length should be 2 times of width for packed YUV formats!\n");
- hor_len = width * 2;
- break;
- default:
- break;
- }
-
- regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG,
- CSI_CH_HSIZE_HOR_LEN(hor_len) |
- CSI_CH_HSIZE_HOR_START(0));
- regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG,
- CSI_CH_VSIZE_VER_LEN(height) |
- CSI_CH_VSIZE_VER_START(0));
-
- planar_offset[0] = 0;
- switch (config->pixelformat) {
- case V4L2_PIX_FMT_NV12_16L16:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- bytesperline_y = width;
- bytesperline_c = width;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = -1;
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- bytesperline_y = width;
- bytesperline_c = width / 2;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = planar_offset[1] +
- bytesperline_c * height / 2;
- break;
- case V4L2_PIX_FMT_YUV422P:
- bytesperline_y = width;
- bytesperline_c = width / 2;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = planar_offset[1] +
- bytesperline_c * height;
- break;
- default: /* raw */
- dev_dbg(csi_dev->dev,
- "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n",
- config->pixelformat);
- bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
- config->width) / 8;
- bytesperline_c = 0;
- planar_offset[1] = -1;
- planar_offset[2] = -1;
- break;
}
- regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG,
- CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
- CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
-}
-
-int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
- struct sun6i_csi_config *config)
-{
- if (!config)
- return -EINVAL;
-
- memcpy(&csi_dev->config, config, sizeof(csi_dev->config));
-
- sun6i_csi_setup_bus(csi_dev);
- sun6i_csi_set_format(csi_dev);
- sun6i_csi_set_window(csi_dev);
+ csi_dev->isp_available = true;
return 0;
}
-void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
- dma_addr_t addr)
-{
- regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG,
- (addr + csi_dev->planar_offset[0]) >> 2);
- if (csi_dev->planar_offset[1] != -1)
- regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG,
- (addr + csi_dev->planar_offset[1]) >> 2);
- if (csi_dev->planar_offset[2] != -1)
- regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG,
- (addr + csi_dev->planar_offset[2]) >> 2);
-}
-
-void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
-{
- struct regmap *regmap = csi_dev->regmap;
-
- if (!enable) {
- regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
- regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
- return;
- }
-
- regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
- regmap_write(regmap, CSI_CH_INT_EN_REG,
- CSI_CH_INT_EN_HB_OF_INT_EN |
- CSI_CH_INT_EN_FIFO2_OF_INT_EN |
- CSI_CH_INT_EN_FIFO1_OF_INT_EN |
- CSI_CH_INT_EN_FIFO0_OF_INT_EN |
- CSI_CH_INT_EN_FD_INT_EN |
- CSI_CH_INT_EN_CD_INT_EN);
-
- regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
- CSI_CAP_CH0_VCAP_ON);
-}
-
/* Media */
static const struct media_device_ops sun6i_csi_media_ops = {
@@ -583,103 +74,11 @@ static const struct media_device_ops sun6i_csi_media_ops = {
/* V4L2 */
-static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev,
- struct media_entity *entity,
- struct fwnode_handle *fwnode)
-{
- struct media_entity *sink;
- struct media_pad *sink_pad;
- int src_pad_index;
- int ret;
-
- ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE);
- if (ret < 0) {
- dev_err(csi_dev->dev,
- "%s: no source pad in external entity %s\n", __func__,
- entity->name);
- return -EINVAL;
- }
-
- src_pad_index = ret;
-
- sink = &csi_dev->video.video_dev.entity;
- sink_pad = &csi_dev->video.pad;
-
- dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n",
- entity->name, src_pad_index, sink->name, sink_pad->index);
- ret = media_create_pad_link(entity, src_pad_index, sink,
- sink_pad->index,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0) {
- dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n",
- entity->name, src_pad_index,
- sink->name, sink_pad->index);
- return ret;
- }
-
- return 0;
-}
-
-static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier)
-{
- struct sun6i_csi_device *csi_dev =
- container_of(notifier, struct sun6i_csi_device,
- v4l2.notifier);
- struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
- struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
- struct v4l2_subdev *sd;
- int ret;
-
- dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n");
-
- sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list);
- if (!sd)
- return -EINVAL;
-
- ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode);
- if (ret < 0)
- return ret;
-
- ret = v4l2_device_register_subdev_nodes(v4l2_dev);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = {
- .complete = sun6i_subdev_notify_complete,
-};
-
-static int sun6i_csi_fwnode_parse(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd)
-{
- struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
-
- if (vep->base.port || vep->base.id) {
- dev_warn(dev, "Only support a single port with one endpoint\n");
- return -ENOTCONN;
- }
-
- switch (vep->bus_type) {
- case V4L2_MBUS_PARALLEL:
- case V4L2_MBUS_BT656:
- csi_dev->v4l2.v4l2_ep = *vep;
- return 0;
- default:
- dev_err(dev, "Unsupported media bus type\n");
- return -ENOTCONN;
- }
-}
-
static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev)
{
struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
struct media_device *media_dev = &v4l2->media_dev;
struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
- struct v4l2_async_notifier *notifier = &v4l2->notifier;
struct device *dev = csi_dev->dev;
int ret;
@@ -709,42 +108,11 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev)
goto error_media;
}
- /* Video */
-
- ret = sun6i_video_setup(csi_dev);
- if (ret)
- goto error_v4l2_device;
-
- /* V4L2 Async */
-
- v4l2_async_nf_init(notifier);
- notifier->ops = &sun6i_csi_async_ops;
-
- ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier,
- sizeof(struct
- v4l2_async_subdev),
- sun6i_csi_fwnode_parse);
- if (ret)
- goto error_video;
-
- ret = v4l2_async_nf_register(v4l2_dev, notifier);
- if (ret) {
- dev_err(dev, "failed to register v4l2 async notifier: %d\n",
- ret);
- goto error_v4l2_async_notifier;
- }
+ csi_dev->v4l2_dev = v4l2_dev;
+ csi_dev->media_dev = media_dev;
return 0;
-error_v4l2_async_notifier:
- v4l2_async_nf_cleanup(notifier);
-
-error_video:
- sun6i_video_cleanup(csi_dev);
-
-error_v4l2_device:
- v4l2_device_unregister(&v4l2->v4l2_dev);
-
error_media:
media_device_unregister(media_dev);
media_device_cleanup(media_dev);
@@ -757,9 +125,6 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
media_device_unregister(&v4l2->media_dev);
- v4l2_async_nf_unregister(&v4l2->notifier);
- v4l2_async_nf_cleanup(&v4l2->notifier);
- sun6i_video_cleanup(csi_dev);
v4l2_device_unregister(&v4l2->v4l2_dev);
media_device_cleanup(&v4l2->media_dev);
}
@@ -769,29 +134,39 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
{
struct sun6i_csi_device *csi_dev = private;
+ bool capture_streaming = csi_dev->capture.state.streaming;
struct regmap *regmap = csi_dev->regmap;
- u32 status;
+ u32 status = 0, enable = 0;
- regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
+ regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status);
+ regmap_read(regmap, SUN6I_CSI_CH_INT_EN_REG, &enable);
- if (!(status & 0xFF))
+ if (!status)
return IRQ_NONE;
-
- if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) ||
- (status & CSI_CH_INT_STA_FIFO1_OF_PD) ||
- (status & CSI_CH_INT_STA_FIFO2_OF_PD) ||
- (status & CSI_CH_INT_STA_HB_OF_PD)) {
- regmap_write(regmap, CSI_CH_INT_STA_REG, status);
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
- CSI_EN_CSI_EN);
+ else if (!(status & enable) || !capture_streaming)
+ goto complete;
+
+ if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_HB_OF)) {
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);
+
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
+ SUN6I_CSI_EN_CSI_EN, 0);
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
+ SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN);
return IRQ_HANDLED;
}
- if (status & CSI_CH_INT_STA_FD_PD)
- sun6i_video_frame_done(csi_dev);
+ if (status & SUN6I_CSI_CH_INT_STA_FD)
+ sun6i_csi_capture_frame_done(csi_dev);
+
+ if (status & SUN6I_CSI_CH_INT_STA_VS)
+ sun6i_csi_capture_sync(csi_dev);
- regmap_write(regmap, CSI_CH_INT_STA_REG, status);
+complete:
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);
return IRQ_HANDLED;
}
@@ -913,13 +288,12 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,
irq = platform_get_irq(platform_dev, 0);
if (irq < 0) {
- dev_err(dev, "failed to get interrupt\n");
ret = -ENXIO;
goto error_clock_rate_exclusive;
}
- ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME,
- csi_dev);
+ ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, IRQF_SHARED,
+ SUN6I_CSI_NAME, csi_dev);
if (ret) {
dev_err(dev, "failed to request interrupt\n");
goto error_clock_rate_exclusive;
@@ -960,12 +334,41 @@ static int sun6i_csi_probe(struct platform_device *platform_dev)
if (ret)
return ret;
- ret = sun6i_csi_v4l2_setup(csi_dev);
+ ret = sun6i_csi_isp_detect(csi_dev);
if (ret)
goto error_resources;
+ /*
+ * Register our own v4l2 and media devices when there is no ISP around.
+ * Otherwise the ISP will use async subdev registration with our bridge,
+ * which will provide v4l2 and media devices that are used to register
+ * the video interface.
+ */
+ if (!csi_dev->isp_available) {
+ ret = sun6i_csi_v4l2_setup(csi_dev);
+ if (ret)
+ goto error_resources;
+ }
+
+ ret = sun6i_csi_bridge_setup(csi_dev);
+ if (ret)
+ goto error_v4l2;
+
+ if (!csi_dev->isp_available) {
+ ret = sun6i_csi_capture_setup(csi_dev);
+ if (ret)
+ goto error_bridge;
+ }
+
return 0;
+error_bridge:
+ sun6i_csi_bridge_cleanup(csi_dev);
+
+error_v4l2:
+ if (!csi_dev->isp_available)
+ sun6i_csi_v4l2_cleanup(csi_dev);
+
error_resources:
sun6i_csi_resources_cleanup(csi_dev);
@@ -976,7 +379,12 @@ static int sun6i_csi_remove(struct platform_device *pdev)
{
struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev);
- sun6i_csi_v4l2_cleanup(csi_dev);
+ sun6i_csi_capture_cleanup(csi_dev);
+ sun6i_csi_bridge_cleanup(csi_dev);
+
+ if (!csi_dev->isp_available)
+ sun6i_csi_v4l2_cleanup(csi_dev);
+
sun6i_csi_resources_cleanup(csi_dev);
return 0;
@@ -1030,4 +438,5 @@ module_platform_driver(sun6i_csi_platform_driver);
MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver");
MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>");
+MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index bab705678280..bc3f0dae35df 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -1,166 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
- * All rights reserved.
* Author: Yong Deng <yong.deng@magewell.com>
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
-#ifndef __SUN6I_CSI_H__
-#define __SUN6I_CSI_H__
+#ifndef _SUN6I_CSI_H_
+#define _SUN6I_CSI_H_
#include <media/v4l2-device.h>
-#include <media/v4l2-fwnode.h>
#include <media/videobuf2-v4l2.h>
-#include "sun6i_video.h"
+#include "sun6i_csi_bridge.h"
+#include "sun6i_csi_capture.h"
#define SUN6I_CSI_NAME "sun6i-csi"
#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device"
+enum sun6i_csi_port {
+ SUN6I_CSI_PORT_PARALLEL = 0,
+ SUN6I_CSI_PORT_MIPI_CSI2 = 1,
+ SUN6I_CSI_PORT_ISP = 2,
+};
+
struct sun6i_csi_buffer {
struct vb2_v4l2_buffer v4l2_buffer;
struct list_head list;
-
- dma_addr_t dma_addr;
- bool queued_to_csi;
-};
-
-/**
- * struct sun6i_csi_config - configs for sun6i csi
- * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*)
- * @code: media bus format code (MEDIA_BUS_FMT_*)
- * @field: used interlacing type (enum v4l2_field)
- * @width: frame width
- * @height: frame height
- */
-struct sun6i_csi_config {
- u32 pixelformat;
- u32 code;
- u32 field;
- u32 width;
- u32 height;
};
struct sun6i_csi_v4l2 {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
-
- struct v4l2_async_notifier notifier;
- /* video port settings */
- struct v4l2_fwnode_endpoint v4l2_ep;
};
struct sun6i_csi_device {
struct device *dev;
+ struct v4l2_device *v4l2_dev;
+ struct media_device *media_dev;
- struct sun6i_csi_config config;
struct sun6i_csi_v4l2 v4l2;
- struct sun6i_video video;
+ struct sun6i_csi_bridge bridge;
+ struct sun6i_csi_capture capture;
struct regmap *regmap;
struct clk *clock_mod;
struct clk *clock_ram;
struct reset_control *reset;
- int planar_offset[3];
+ bool isp_available;
};
struct sun6i_csi_variant {
unsigned long clock_mod_rate;
};
-/**
- * sun6i_csi_is_format_supported() - check if the format supported by csi
- * @csi_dev: pointer to the csi device
- * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*)
- * @mbus_code: media bus format code (MEDIA_BUS_FMT_*)
- *
- * Return: true if format is supported, false otherwise.
- */
-bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev,
- u32 pixformat, u32 mbus_code);
-
-/**
- * sun6i_csi_set_power() - power on/off the csi
- * @csi_dev: pointer to the csi device
- * @enable: on/off
- *
- * Return: 0 if successful, error code otherwise.
- */
-int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable);
-
-/**
- * sun6i_csi_update_config() - update the csi register settings
- * @csi_dev: pointer to the csi device
- * @config: see struct sun6i_csi_config
- *
- * Return: 0 if successful, error code otherwise.
- */
-int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
- struct sun6i_csi_config *config);
-
-/**
- * sun6i_csi_update_buf_addr() - update the csi frame buffer address
- * @csi_dev: pointer to the csi device
- * @addr: frame buffer's physical address
- */
-void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
- dma_addr_t addr);
-
-/**
- * sun6i_csi_set_stream() - start/stop csi streaming
- * @csi_dev: pointer to the csi device
- * @enable: start/stop
- */
-void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable);
-
-/* get bpp form v4l2 pixformat */
-static inline int sun6i_csi_get_bpp(unsigned int pixformat)
-{
- switch (pixformat) {
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SGBRG8:
- case V4L2_PIX_FMT_SGRBG8:
- case V4L2_PIX_FMT_SRGGB8:
- case V4L2_PIX_FMT_JPEG:
- return 8;
- case V4L2_PIX_FMT_SBGGR10:
- case V4L2_PIX_FMT_SGBRG10:
- case V4L2_PIX_FMT_SGRBG10:
- case V4L2_PIX_FMT_SRGGB10:
- return 10;
- case V4L2_PIX_FMT_SBGGR12:
- case V4L2_PIX_FMT_SGBRG12:
- case V4L2_PIX_FMT_SGRBG12:
- case V4L2_PIX_FMT_SRGGB12:
- case V4L2_PIX_FMT_NV12_16L16:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- return 12;
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- case V4L2_PIX_FMT_YUV422P:
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- return 16;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- return 24;
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:
- return 32;
- default:
- WARN(1, "Unsupported pixformat: 0x%x\n", pixformat);
- break;
- }
+/* ISP */
- return 0;
-}
+int sun6i_csi_isp_complete(struct sun6i_csi_device *csi_dev,
+ struct v4l2_device *v4l2_dev);
-#endif /* __SUN6I_CSI_H__ */
+#endif
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
new file mode 100644
index 000000000000..ebfc870d2af5
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "sun6i_csi.h"
+#include "sun6i_csi_bridge.h"
+#include "sun6i_csi_reg.h"
+
+/* Helpers */
+
+void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev,
+ unsigned int *width, unsigned int *height)
+{
+ if (width)
+ *width = csi_dev->bridge.mbus_format.width;
+ if (height)
+ *height = csi_dev->bridge.mbus_format.height;
+}
+
+void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev,
+ u32 *mbus_code, u32 *field)
+{
+ if (mbus_code)
+ *mbus_code = csi_dev->bridge.mbus_format.code;
+ if (field)
+ *field = csi_dev->bridge.mbus_format.field;
+}
+
+/* Format */
+
+static const struct sun6i_csi_bridge_format sun6i_csi_bridge_formats[] = {
+ /* Bayer */
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ /* RGB */
+ {
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+ /* YUV422 */
+ {
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .input_format = SUN6I_CSI_INPUT_FMT_YUV422,
+ .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY,
+ .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY,
+ },
+ /* Compressed */
+ {
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ .input_format = SUN6I_CSI_INPUT_FMT_RAW,
+ },
+};
+
+const struct sun6i_csi_bridge_format *
+sun6i_csi_bridge_format_find(u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_csi_bridge_formats); i++)
+ if (sun6i_csi_bridge_formats[i].mbus_code == mbus_code)
+ return &sun6i_csi_bridge_formats[i];
+
+ return NULL;
+}
+
+/* Bridge */
+
+static void sun6i_csi_bridge_irq_enable(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+
+ regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG,
+ SUN6I_CSI_CH_INT_EN_VS |
+ SUN6I_CSI_CH_INT_EN_HB_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO2_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO1_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO0_OF |
+ SUN6I_CSI_CH_INT_EN_FD |
+ SUN6I_CSI_CH_INT_EN_CD);
+}
+
+static void sun6i_csi_bridge_irq_disable(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+
+ regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0);
+}
+
+static void sun6i_csi_bridge_irq_clear(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+
+ regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0);
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG,
+ SUN6I_CSI_CH_INT_STA_CLEAR);
+}
+
+static void sun6i_csi_bridge_enable(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN,
+ SUN6I_CSI_EN_CSI_EN);
+
+ regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON,
+ SUN6I_CSI_CAP_VCAP_ON);
+}
+
+static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+
+ regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0);
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 0);
+}
+
+static void
+sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev)
+{
+ struct device *dev = csi_dev->dev;
+ struct regmap *regmap = csi_dev->regmap;
+ struct v4l2_fwnode_endpoint *endpoint =
+ &csi_dev->bridge.source_parallel.endpoint;
+ unsigned char bus_width = endpoint->bus.parallel.bus_width;
+ unsigned int flags = endpoint->bus.parallel.flags;
+ u32 field;
+ u32 value = SUN6I_CSI_IF_CFG_IF_CSI;
+
+ sun6i_csi_bridge_format(csi_dev, NULL, &field);
+
+ if (field == V4L2_FIELD_INTERLACED ||
+ field == V4L2_FIELD_INTERLACED_TB ||
+ field == V4L2_FIELD_INTERLACED_BT)
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
+ SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
+ SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
+ else
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
+
+ switch (endpoint->bus_type) {
+ case V4L2_MBUS_PARALLEL:
+ if (bus_width == 16)
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
+ else
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;
+
+ if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
+ value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ else
+ value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
+ else
+ value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
+ else
+ value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ else
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
+ break;
+ case V4L2_MBUS_BT656:
+ if (bus_width == 16)
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
+ else
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;
+
+ if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
+ value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ else
+ value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ else
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
+ break;
+ default:
+ dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type);
+ break;
+ }
+
+ switch (bus_width) {
+ case 8:
+ /* 16-bit YUV formats use a doubled width in 8-bit mode. */
+ case 16:
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
+ break;
+ case 10:
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
+ break;
+ case 12:
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
+ break;
+ default:
+ dev_warn(dev, "unsupported bus width: %u\n", bus_width);
+ break;
+ }
+
+ regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
+}
+
+static void
+sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+ u32 value = SUN6I_CSI_IF_CFG_IF_MIPI;
+ u32 field;
+
+ sun6i_csi_bridge_format(csi_dev, NULL, &field);
+
+ if (field == V4L2_FIELD_INTERLACED ||
+ field == V4L2_FIELD_INTERLACED_TB ||
+ field == V4L2_FIELD_INTERLACED_BT)
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED;
+ else
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
+
+ regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
+}
+
+static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+ bool capture_streaming = csi_dev->capture.state.streaming;
+ const struct sun6i_csi_bridge_format *bridge_format;
+ const struct sun6i_csi_capture_format *capture_format;
+ u32 mbus_code, field, pixelformat;
+ u8 input_format, input_yuv_seq, output_format;
+ u32 value = 0;
+
+ sun6i_csi_bridge_format(csi_dev, &mbus_code, &field);
+
+ bridge_format = sun6i_csi_bridge_format_find(mbus_code);
+ if (WARN_ON(!bridge_format))
+ return;
+
+ input_format = bridge_format->input_format;
+ input_yuv_seq = bridge_format->input_yuv_seq;
+
+ if (capture_streaming) {
+ sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
+
+ capture_format = sun6i_csi_capture_format_find(pixelformat);
+ if (WARN_ON(!capture_format))
+ return;
+
+ if (capture_format->input_format_raw)
+ input_format = SUN6I_CSI_INPUT_FMT_RAW;
+
+ if (capture_format->input_yuv_seq_invert)
+ input_yuv_seq = bridge_format->input_yuv_seq_invert;
+
+ if (field == V4L2_FIELD_INTERLACED ||
+ field == V4L2_FIELD_INTERLACED_TB ||
+ field == V4L2_FIELD_INTERLACED_BT)
+ output_format = capture_format->output_format_field;
+ else
+ output_format = capture_format->output_format_frame;
+
+ value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format);
+ }
+
+ value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format);
+ value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq);
+
+ if (field == V4L2_FIELD_TOP)
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
+ else if (field == V4L2_FIELD_BOTTOM)
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
+ else
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;
+
+ regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value);
+}
+
+static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev,
+ struct sun6i_csi_bridge_source *source)
+{
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
+
+ if (source == &bridge->source_parallel)
+ sun6i_csi_bridge_configure_parallel(csi_dev);
+ else
+ sun6i_csi_bridge_configure_mipi_csi2(csi_dev);
+
+ sun6i_csi_bridge_configure_format(csi_dev);
+}
+
+/* V4L2 Subdev */
+
+static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)
+{
+ struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev);
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
+ struct media_pad *local_pad = &bridge->pads[SUN6I_CSI_BRIDGE_PAD_SINK];
+ bool capture_streaming = csi_dev->capture.state.streaming;
+ struct device *dev = csi_dev->dev;
+ struct sun6i_csi_bridge_source *source;
+ struct v4l2_subdev *source_subdev;
+ struct media_pad *remote_pad;
+ int ret;
+
+ /* Source */
+
+ remote_pad = media_pad_remote_pad_unique(local_pad);
+ if (IS_ERR(remote_pad)) {
+ dev_err(dev,
+ "zero or more than a single source connected to the bridge\n");
+ return PTR_ERR(remote_pad);
+ }
+
+ source_subdev = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ if (source_subdev == bridge->source_parallel.subdev)
+ source = &bridge->source_parallel;
+ else
+ source = &bridge->source_mipi_csi2;
+
+ if (!on) {
+ v4l2_subdev_call(source_subdev, video, s_stream, 0);
+ ret = 0;
+ goto disable;
+ }
+
+ /* PM */
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ /* Clear */
+
+ sun6i_csi_bridge_irq_clear(csi_dev);
+
+ /* Configure */
+
+ sun6i_csi_bridge_configure(csi_dev, source);
+
+ if (capture_streaming)
+ sun6i_csi_capture_configure(csi_dev);
+
+ /* State Update */
+
+ if (capture_streaming)
+ sun6i_csi_capture_state_update(csi_dev);
+
+ /* Enable */
+
+ if (capture_streaming)
+ sun6i_csi_bridge_irq_enable(csi_dev);
+
+ sun6i_csi_bridge_enable(csi_dev);
+
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto disable;
+
+ return 0;
+
+disable:
+ if (capture_streaming)
+ sun6i_csi_bridge_irq_disable(csi_dev);
+
+ sun6i_csi_bridge_disable(csi_dev);
+
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops sun6i_csi_bridge_video_ops = {
+ .s_stream = sun6i_csi_bridge_s_stream,
+};
+
+static void
+sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
+{
+ if (!sun6i_csi_bridge_format_find(mbus_format->code))
+ mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code;
+
+ mbus_format->field = V4L2_FIELD_NONE;
+ mbus_format->colorspace = V4L2_COLORSPACE_RAW;
+ mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
+{
+ struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev);
+ unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK;
+ struct v4l2_mbus_framefmt *mbus_format =
+ v4l2_subdev_get_try_format(subdev, state, pad);
+ struct mutex *lock = &csi_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code;
+ mbus_format->width = 1280;
+ mbus_format->height = 720;
+
+ sun6i_csi_bridge_mbus_format_prepare(mbus_format);
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int
+sun6i_csi_bridge_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code_enum)
+{
+ if (code_enum->index >= ARRAY_SIZE(sun6i_csi_bridge_formats))
+ return -EINVAL;
+
+ code_enum->code = sun6i_csi_bridge_formats[code_enum->index].mbus_code;
+
+ return 0;
+}
+
+static int sun6i_csi_bridge_get_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
+ format->pad);
+ else
+ *mbus_format = csi_dev->bridge.mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ sun6i_csi_bridge_mbus_format_prepare(mbus_format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *mbus_format;
+ else
+ csi_dev->bridge.mbus_format = *mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun6i_csi_bridge_pad_ops = {
+ .init_cfg = sun6i_csi_bridge_init_cfg,
+ .enum_mbus_code = sun6i_csi_bridge_enum_mbus_code,
+ .get_fmt = sun6i_csi_bridge_get_fmt,
+ .set_fmt = sun6i_csi_bridge_set_fmt,
+};
+
+static const struct v4l2_subdev_ops sun6i_csi_bridge_subdev_ops = {
+ .video = &sun6i_csi_bridge_video_ops,
+ .pad = &sun6i_csi_bridge_pad_ops,
+};
+
+/* Media Entity */
+
+static const struct media_entity_operations sun6i_csi_bridge_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* V4L2 Async */
+
+static int sun6i_csi_bridge_link(struct sun6i_csi_device *csi_dev,
+ int sink_pad_index,
+ struct v4l2_subdev *remote_subdev,
+ bool enabled)
+{
+ struct device *dev = csi_dev->dev;
+ struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
+ struct media_entity *sink_entity = &subdev->entity;
+ struct media_entity *source_entity = &remote_subdev->entity;
+ int source_pad_index;
+ int ret;
+
+ /* Get the first remote source pad. */
+ ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "missing source pad in external entity %s\n",
+ source_entity->name);
+ return -EINVAL;
+ }
+
+ source_pad_index = ret;
+
+ dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name,
+ source_pad_index, sink_entity->name, sink_pad_index);
+
+ ret = media_create_pad_link(source_entity, source_pad_index,
+ sink_entity, sink_pad_index,
+ enabled ? MEDIA_LNK_FL_ENABLED : 0);
+ if (ret < 0) {
+ dev_err(dev, "failed to create %s:%u -> %s:%u link\n",
+ source_entity->name, source_pad_index,
+ sink_entity->name, sink_pad_index);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *remote_subdev,
+ struct v4l2_async_subdev *async_subdev)
+{
+ struct sun6i_csi_device *csi_dev =
+ container_of(notifier, struct sun6i_csi_device,
+ bridge.notifier);
+ struct sun6i_csi_bridge_async_subdev *bridge_async_subdev =
+ container_of(async_subdev, struct sun6i_csi_bridge_async_subdev,
+ async_subdev);
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
+ struct sun6i_csi_bridge_source *source = bridge_async_subdev->source;
+ bool enabled = false;
+ int ret;
+
+ switch (source->endpoint.base.port) {
+ case SUN6I_CSI_PORT_PARALLEL:
+ enabled = true;
+ break;
+ case SUN6I_CSI_PORT_MIPI_CSI2:
+ enabled = !bridge->source_parallel.expected;
+ break;
+ default:
+ break;
+ }
+
+ source->subdev = remote_subdev;
+
+ if (csi_dev->isp_available) {
+ /*
+ * Hook to the first available remote subdev to get v4l2 and
+ * media devices and register the capture device then.
+ */
+ ret = sun6i_csi_isp_complete(csi_dev, remote_subdev->v4l2_dev);
+ if (ret)
+ return ret;
+ }
+
+ return sun6i_csi_bridge_link(csi_dev, SUN6I_CSI_BRIDGE_PAD_SINK,
+ remote_subdev, enabled);
+}
+
+static int
+sun6i_csi_bridge_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+ struct sun6i_csi_device *csi_dev =
+ container_of(notifier, struct sun6i_csi_device,
+ bridge.notifier);
+ struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
+
+ if (csi_dev->isp_available)
+ return 0;
+
+ return v4l2_device_register_subdev_nodes(v4l2_dev);
+}
+
+static const struct v4l2_async_notifier_operations
+sun6i_csi_bridge_notifier_ops = {
+ .bound = sun6i_csi_bridge_notifier_bound,
+ .complete = sun6i_csi_bridge_notifier_complete,
+};
+
+/* Bridge */
+
+static int sun6i_csi_bridge_source_setup(struct sun6i_csi_device *csi_dev,
+ struct sun6i_csi_bridge_source *source,
+ u32 port,
+ enum v4l2_mbus_type *bus_types)
+{
+ struct device *dev = csi_dev->dev;
+ struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier;
+ struct v4l2_fwnode_endpoint *endpoint = &source->endpoint;
+ struct sun6i_csi_bridge_async_subdev *bridge_async_subdev;
+ struct fwnode_handle *handle;
+ int ret;
+
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), port, 0, 0);
+ if (!handle)
+ return -ENODEV;
+
+ ret = v4l2_fwnode_endpoint_parse(handle, endpoint);
+ if (ret)
+ goto complete;
+
+ if (bus_types) {
+ bool valid = false;
+ unsigned int i;
+
+ for (i = 0; bus_types[i] != V4L2_MBUS_INVALID; i++) {
+ if (endpoint->bus_type == bus_types[i]) {
+ valid = true;
+ break;
+ }
+ }
+
+ if (!valid) {
+ dev_err(dev, "unsupported bus type for port %d\n",
+ port);
+ ret = -EINVAL;
+ goto complete;
+ }
+ }
+
+ bridge_async_subdev =
+ v4l2_async_nf_add_fwnode_remote(notifier, handle,
+ struct
+ sun6i_csi_bridge_async_subdev);
+ if (IS_ERR(bridge_async_subdev)) {
+ ret = PTR_ERR(bridge_async_subdev);
+ goto complete;
+ }
+
+ bridge_async_subdev->source = source;
+
+ source->expected = true;
+
+complete:
+ fwnode_handle_put(handle);
+
+ return ret;
+}
+
+int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
+{
+ struct device *dev = csi_dev->dev;
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
+ struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
+ struct v4l2_subdev *subdev = &bridge->subdev;
+ struct v4l2_async_notifier *notifier = &bridge->notifier;
+ struct media_pad *pads = bridge->pads;
+ enum v4l2_mbus_type parallel_mbus_types[] = {
+ V4L2_MBUS_PARALLEL,
+ V4L2_MBUS_BT656,
+ V4L2_MBUS_INVALID
+ };
+ int ret;
+
+ mutex_init(&bridge->lock);
+
+ /* V4L2 Subdev */
+
+ v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops);
+ strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->owner = THIS_MODULE;
+ subdev->dev = dev;
+
+ v4l2_set_subdevdata(subdev, csi_dev);
+
+ /* Media Entity */
+
+ subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ subdev->entity.ops = &sun6i_csi_bridge_entity_ops;
+
+ /* Media Pads */
+
+ pads[SUN6I_CSI_BRIDGE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[SUN6I_CSI_BRIDGE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
+
+ ret = media_entity_pads_init(&subdev->entity,
+ SUN6I_CSI_BRIDGE_PAD_COUNT, pads);
+ if (ret < 0)
+ return ret;
+
+ /* V4L2 Subdev */
+
+ if (csi_dev->isp_available)
+ ret = v4l2_async_register_subdev(subdev);
+ else
+ ret = v4l2_device_register_subdev(v4l2_dev, subdev);
+
+ if (ret) {
+ dev_err(dev, "failed to register v4l2 subdev: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* V4L2 Async */
+
+ v4l2_async_nf_init(notifier);
+ notifier->ops = &sun6i_csi_bridge_notifier_ops;
+
+ sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel,
+ SUN6I_CSI_PORT_PARALLEL,
+ parallel_mbus_types);
+ sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2,
+ SUN6I_CSI_PORT_MIPI_CSI2, NULL);
+
+ if (csi_dev->isp_available)
+ ret = v4l2_async_subdev_nf_register(subdev, notifier);
+ else
+ ret = v4l2_async_nf_register(v4l2_dev, notifier);
+ if (ret) {
+ dev_err(dev, "failed to register v4l2 async notifier: %d\n",
+ ret);
+ goto error_v4l2_async_notifier;
+ }
+
+ return 0;
+
+error_v4l2_async_notifier:
+ v4l2_async_nf_cleanup(notifier);
+
+ if (csi_dev->isp_available)
+ v4l2_async_unregister_subdev(subdev);
+ else
+ v4l2_device_unregister_subdev(subdev);
+
+error_media_entity:
+ media_entity_cleanup(&subdev->entity);
+
+ return ret;
+}
+
+void sun6i_csi_bridge_cleanup(struct sun6i_csi_device *csi_dev)
+{
+ struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
+ struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier;
+
+ v4l2_async_nf_unregister(notifier);
+ v4l2_async_nf_cleanup(notifier);
+
+ v4l2_device_unregister_subdev(subdev);
+
+ media_entity_cleanup(&subdev->entity);
+}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
new file mode 100644
index 000000000000..ee592a14b9c5
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_CSI_BRIDGE_H_
+#define _SUN6I_CSI_BRIDGE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define SUN6I_CSI_BRIDGE_NAME "sun6i-csi-bridge"
+
+enum sun6i_csi_bridge_pad {
+ SUN6I_CSI_BRIDGE_PAD_SINK = 0,
+ SUN6I_CSI_BRIDGE_PAD_SOURCE = 1,
+ SUN6I_CSI_BRIDGE_PAD_COUNT = 2,
+};
+
+struct sun6i_csi_device;
+
+struct sun6i_csi_bridge_format {
+ u32 mbus_code;
+ u8 input_format;
+ u8 input_yuv_seq;
+ u8 input_yuv_seq_invert;
+};
+
+struct sun6i_csi_bridge_source {
+ struct v4l2_subdev *subdev;
+ struct v4l2_fwnode_endpoint endpoint;
+ bool expected;
+};
+
+struct sun6i_csi_bridge_async_subdev {
+ struct v4l2_async_subdev async_subdev;
+ struct sun6i_csi_bridge_source *source;
+};
+
+struct sun6i_csi_bridge {
+ struct v4l2_subdev subdev;
+ struct v4l2_async_notifier notifier;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt mbus_format;
+ struct mutex lock; /* Mbus format lock. */
+
+ struct sun6i_csi_bridge_source source_parallel;
+ struct sun6i_csi_bridge_source source_mipi_csi2;
+};
+
+/* Helpers */
+
+void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev,
+ unsigned int *width, unsigned int *height);
+void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev,
+ u32 *mbus_code, u32 *field);
+
+/* Format */
+
+const struct sun6i_csi_bridge_format *
+sun6i_csi_bridge_format_find(u32 mbus_code);
+
+/* Bridge */
+
+int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_bridge_cleanup(struct sun6i_csi_device *csi_dev);
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
new file mode 100644
index 000000000000..6d34f5c0768f
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -0,0 +1,1102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * Author: Yong Deng <yong.deng@magewell.com>
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun6i_csi.h"
+#include "sun6i_csi_bridge.h"
+#include "sun6i_csi_capture.h"
+#include "sun6i_csi_reg.h"
+
+/* Helpers */
+
+void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev,
+ unsigned int *width, unsigned int *height)
+{
+ if (width)
+ *width = csi_dev->capture.format.fmt.pix.width;
+ if (height)
+ *height = csi_dev->capture.format.fmt.pix.height;
+}
+
+void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev,
+ u32 *pixelformat, u32 *field)
+{
+ if (pixelformat)
+ *pixelformat = csi_dev->capture.format.fmt.pix.pixelformat;
+
+ if (field)
+ *field = csi_dev->capture.format.fmt.pix.field;
+}
+
+/* Format */
+
+static const struct sun6i_csi_capture_format sun6i_csi_capture_formats[] = {
+ /* Bayer */
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG8,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB8,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG12,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG12,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB12,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
+ },
+ /* RGB */
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
+ },
+ /* YUV422 */
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ .input_format_raw = true,
+ .hsize_len_factor = 2,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ .input_format_raw = true,
+ .hsize_len_factor = 2,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ .input_format_raw = true,
+ .hsize_len_factor = 2,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ .input_format_raw = true,
+ .hsize_len_factor = 2,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV16,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV61,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
+ .input_yuv_seq_invert = true,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P,
+ },
+ /* YUV420 */
+ {
+ .pixelformat = V4L2_PIX_FMT_NV12_16L16,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
+ .input_yuv_seq_invert = true,
+ },
+
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
+ .input_yuv_seq_invert = true,
+ },
+ /* Compressed */
+ {
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
+ .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
+ },
+};
+
+const
+struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++)
+ if (sun6i_csi_capture_formats[i].pixelformat == pixelformat)
+ return &sun6i_csi_capture_formats[i];
+
+ return NULL;
+}
+
+/* RAW formats need an exact match between pixel and mbus formats. */
+static const
+struct sun6i_csi_capture_format_match sun6i_csi_capture_format_matches[] = {
+ /* YUV420 */
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
+ },
+ /* RGB */
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ },
+ /* Bayer */
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ },
+ /* Compressed */
+ {
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ },
+};
+
+static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_format_matches); i++) {
+ const struct sun6i_csi_capture_format_match *match =
+ &sun6i_csi_capture_format_matches[i];
+
+ if (match->pixelformat == pixelformat &&
+ match->mbus_code == mbus_code)
+ return true;
+ }
+
+ return false;
+}
+
+/* Capture */
+
+static void
+sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
+ struct sun6i_csi_buffer *csi_buffer)
+{
+ struct regmap *regmap = csi_dev->regmap;
+ const struct v4l2_format_info *info;
+ struct vb2_buffer *vb2_buffer;
+ unsigned int width, height;
+ dma_addr_t address;
+ u32 pixelformat;
+
+ vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
+ address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);
+
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+
+ sun6i_csi_capture_dimensions(csi_dev, &width, &height);
+ sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
+
+ info = v4l2_format_info(pixelformat);
+ /* Unsupported formats are single-plane, so we can stop here. */
+ if (!info)
+ return;
+
+ if (info->comp_planes > 1) {
+ address += info->bpp[0] * width * height;
+
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+ }
+
+ if (info->comp_planes > 2) {
+ address += info->bpp[1] * DIV_ROUND_UP(width, info->hdiv) *
+ DIV_ROUND_UP(height, info->vdiv);
+
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+ }
+}
+
+void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+ const struct sun6i_csi_capture_format *format;
+ const struct v4l2_format_info *info;
+ u32 hsize_len, vsize_len;
+ u32 luma_line, chroma_line = 0;
+ u32 pixelformat, field;
+ u32 width, height;
+
+ sun6i_csi_capture_dimensions(csi_dev, &width, &height);
+ sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
+
+ format = sun6i_csi_capture_format_find(pixelformat);
+ if (WARN_ON(!format))
+ return;
+
+ hsize_len = width;
+ vsize_len = height;
+
+ /*
+ * When using 8-bit raw input/output (for packed YUV), we need to adapt
+ * the width to account for the difference in bpp when it's not 8-bit.
+ */
+ if (format->hsize_len_factor)
+ hsize_len *= format->hsize_len_factor;
+
+ regmap_write(regmap, SUN6I_CSI_CH_HSIZE_REG,
+ SUN6I_CSI_CH_HSIZE_LEN(hsize_len) |
+ SUN6I_CSI_CH_HSIZE_START(0));
+
+ regmap_write(regmap, SUN6I_CSI_CH_VSIZE_REG,
+ SUN6I_CSI_CH_VSIZE_LEN(vsize_len) |
+ SUN6I_CSI_CH_VSIZE_START(0));
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_RGB565X:
+ luma_line = width * 2;
+ break;
+ case V4L2_PIX_FMT_NV12_16L16:
+ luma_line = width;
+ chroma_line = width;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ luma_line = width;
+ break;
+ default:
+ info = v4l2_format_info(pixelformat);
+ if (WARN_ON(!info))
+ return;
+
+ luma_line = width * info->bpp[0];
+
+ if (info->comp_planes > 1)
+ chroma_line = width * info->bpp[1] / info->hdiv;
+ break;
+ }
+
+ regmap_write(regmap, SUN6I_CSI_CH_BUF_LEN_REG,
+ SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(chroma_line) |
+ SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(luma_line));
+}
+
+/* State */
+
+static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev,
+ bool error)
+{
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ struct sun6i_csi_buffer **csi_buffer_states[] = {
+ &state->pending, &state->current, &state->complete,
+ };
+ struct sun6i_csi_buffer *csi_buffer;
+ struct vb2_buffer *vb2_buffer;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(csi_buffer_states); i++) {
+ csi_buffer = *csi_buffer_states[i];
+ if (!csi_buffer)
+ continue;
+
+ vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+
+ *csi_buffer_states[i] = NULL;
+ }
+
+ list_for_each_entry(csi_buffer, &state->queue, list) {
+ vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+ }
+
+ INIT_LIST_HEAD(&state->queue);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ struct sun6i_csi_buffer *csi_buffer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (list_empty(&state->queue))
+ goto complete;
+
+ if (state->pending)
+ goto complete;
+
+ csi_buffer = list_first_entry(&state->queue, struct sun6i_csi_buffer,
+ list);
+
+ sun6i_csi_capture_buffer_configure(csi_dev, csi_buffer);
+
+ list_del(&csi_buffer->list);
+
+ state->pending = csi_buffer;
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+static void sun6i_csi_capture_state_complete(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (!state->pending)
+ goto complete;
+
+ state->complete = state->current;
+ state->current = state->pending;
+ state->pending = NULL;
+
+ if (state->complete) {
+ struct sun6i_csi_buffer *csi_buffer = state->complete;
+ struct vb2_buffer *vb2_buffer =
+ &csi_buffer->v4l2_buffer.vb2_buf;
+
+ vb2_buffer->timestamp = ktime_get_ns();
+ csi_buffer->v4l2_buffer.sequence = state->sequence;
+
+ vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
+
+ state->complete = NULL;
+ }
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+ state->sequence++;
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev)
+{
+ sun6i_csi_capture_state_complete(csi_dev);
+ sun6i_csi_capture_state_update(csi_dev);
+}
+
+/* Queue */
+
+static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue,
+ unsigned int *buffers_count,
+ unsigned int *planes_count,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
+ unsigned int size = csi_dev->capture.format.fmt.pix.sizeimage;
+
+ if (*planes_count)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *planes_count = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer)
+{
+ struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
+ unsigned long size = capture->format.fmt.pix.sizeimage;
+
+ if (vb2_plane_size(buffer, 0) < size) {
+ v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(buffer, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(buffer, 0, size);
+
+ v4l2_buffer->field = capture->format.fmt.pix.field;
+
+ return 0;
+}
+
+static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer)
+{
+ struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
+ struct sun6i_csi_buffer *csi_buffer =
+ container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+ list_add_tail(&csi_buffer->list, &state->queue);
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
+{
+ struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ struct video_device *video_dev = &csi_dev->capture.video_dev;
+ struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
+ int ret;
+
+ state->sequence = 0;
+
+ ret = video_device_pipeline_alloc_start(video_dev);
+ if (ret < 0)
+ goto error_state;
+
+ state->streaming = true;
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto error_streaming;
+
+ return 0;
+
+error_streaming:
+ state->streaming = false;
+
+ video_device_pipeline_stop(video_dev);
+
+error_state:
+ sun6i_csi_capture_state_cleanup(csi_dev, false);
+
+ return ret;
+}
+
+static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue)
+{
+ struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
+ struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
+ struct video_device *video_dev = &csi_dev->capture.video_dev;
+ struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
+
+ v4l2_subdev_call(subdev, video, s_stream, 0);
+
+ state->streaming = false;
+
+ video_device_pipeline_stop(video_dev);
+
+ sun6i_csi_capture_state_cleanup(csi_dev, true);
+}
+
+static const struct vb2_ops sun6i_csi_capture_queue_ops = {
+ .queue_setup = sun6i_csi_capture_queue_setup,
+ .buf_prepare = sun6i_csi_capture_buffer_prepare,
+ .buf_queue = sun6i_csi_capture_buffer_queue,
+ .start_streaming = sun6i_csi_capture_start_streaming,
+ .stop_streaming = sun6i_csi_capture_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* V4L2 Device */
+
+static void sun6i_csi_capture_format_prepare(struct v4l2_format *format)
+{
+ struct v4l2_pix_format *pix_format = &format->fmt.pix;
+ const struct v4l2_format_info *info;
+ unsigned int width, height;
+
+ v4l_bound_align_image(&pix_format->width, SUN6I_CSI_CAPTURE_WIDTH_MIN,
+ SUN6I_CSI_CAPTURE_WIDTH_MAX, 1,
+ &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN,
+ SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0);
+
+ if (!sun6i_csi_capture_format_find(pix_format->pixelformat))
+ pix_format->pixelformat =
+ sun6i_csi_capture_formats[0].pixelformat;
+
+ width = pix_format->width;
+ height = pix_format->height;
+
+ info = v4l2_format_info(pix_format->pixelformat);
+
+ switch (pix_format->pixelformat) {
+ case V4L2_PIX_FMT_NV12_16L16:
+ pix_format->bytesperline = width * 12 / 8;
+ pix_format->sizeimage = pix_format->bytesperline * height;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ pix_format->bytesperline = width;
+ pix_format->sizeimage = pix_format->bytesperline * height;
+ break;
+ default:
+ v4l2_fill_pixfmt(pix_format, pix_format->pixelformat,
+ width, height);
+ break;
+ }
+
+ if (pix_format->field == V4L2_FIELD_ANY)
+ pix_format->field = V4L2_FIELD_NONE;
+
+ if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
+ pix_format->colorspace = V4L2_COLORSPACE_JPEG;
+ else if (info && info->pixel_enc == V4L2_PIXEL_ENC_BAYER)
+ pix_format->colorspace = V4L2_COLORSPACE_RAW;
+ else
+ pix_format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun6i_csi_capture_querycap(struct file *file, void *private,
+ struct v4l2_capability *capability)
+{
+ struct sun6i_csi_device *csi_dev = video_drvdata(file);
+ struct video_device *video_dev = &csi_dev->capture.video_dev;
+
+ strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
+ strscpy(capability->card, video_dev->name, sizeof(capability->card));
+ snprintf(capability->bus_info, sizeof(capability->bus_info),
+ "platform:%s", dev_name(csi_dev->dev));
+
+ return 0;
+}
+
+static int sun6i_csi_capture_enum_fmt(struct file *file, void *private,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ u32 index = fmtdesc->index;
+
+ if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
+ return -EINVAL;
+
+ fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
+
+ return 0;
+}
+
+static int sun6i_csi_capture_g_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ struct sun6i_csi_device *csi_dev = video_drvdata(file);
+
+ *format = csi_dev->capture.format;
+
+ return 0;
+}
+
+static int sun6i_csi_capture_s_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ struct sun6i_csi_device *csi_dev = video_drvdata(file);
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+
+ if (vb2_is_busy(&capture->queue))
+ return -EBUSY;
+
+ sun6i_csi_capture_format_prepare(format);
+
+ csi_dev->capture.format = *format;
+
+ return 0;
+}
+
+static int sun6i_csi_capture_try_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ sun6i_csi_capture_format_prepare(format);
+
+ return 0;
+}
+
+static int sun6i_csi_capture_enum_input(struct file *file, void *private,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strscpy(input->name, "Camera", sizeof(input->name));
+
+ return 0;
+}
+
+static int sun6i_csi_capture_g_input(struct file *file, void *private,
+ unsigned int *index)
+{
+ *index = 0;
+
+ return 0;
+}
+
+static int sun6i_csi_capture_s_input(struct file *file, void *private,
+ unsigned int index)
+{
+ if (index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = {
+ .vidioc_querycap = sun6i_csi_capture_querycap,
+
+ .vidioc_enum_fmt_vid_cap = sun6i_csi_capture_enum_fmt,
+ .vidioc_g_fmt_vid_cap = sun6i_csi_capture_g_fmt,
+ .vidioc_s_fmt_vid_cap = sun6i_csi_capture_s_fmt,
+ .vidioc_try_fmt_vid_cap = sun6i_csi_capture_try_fmt,
+
+ .vidioc_enum_input = sun6i_csi_capture_enum_input,
+ .vidioc_g_input = sun6i_csi_capture_g_input,
+ .vidioc_s_input = sun6i_csi_capture_s_input,
+
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+/* V4L2 File */
+
+static int sun6i_csi_capture_open(struct file *file)
+{
+ struct sun6i_csi_device *csi_dev = video_drvdata(file);
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&capture->lock))
+ return -ERESTARTSYS;
+
+ ret = v4l2_pipeline_pm_get(&capture->video_dev.entity);
+ if (ret < 0)
+ goto error_lock;
+
+ ret = v4l2_fh_open(file);
+ if (ret < 0)
+ goto error_pipeline;
+
+ mutex_unlock(&capture->lock);
+
+ return 0;
+
+error_pipeline:
+ v4l2_pipeline_pm_put(&capture->video_dev.entity);
+
+error_lock:
+ mutex_unlock(&capture->lock);
+
+ return ret;
+}
+
+static int sun6i_csi_capture_close(struct file *file)
+{
+ struct sun6i_csi_device *csi_dev = video_drvdata(file);
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+
+ mutex_lock(&capture->lock);
+
+ _vb2_fop_release(file, NULL);
+ v4l2_pipeline_pm_put(&capture->video_dev.entity);
+
+ mutex_unlock(&capture->lock);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations sun6i_csi_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = sun6i_csi_capture_open,
+ .release = sun6i_csi_capture_close,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll
+};
+
+/* Media Entity */
+
+static int sun6i_csi_capture_link_validate(struct media_link *link)
+{
+ struct video_device *video_dev =
+ media_entity_to_video_device(link->sink->entity);
+ struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev);
+ struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
+ const struct sun6i_csi_capture_format *capture_format;
+ const struct sun6i_csi_bridge_format *bridge_format;
+ unsigned int capture_width, capture_height;
+ unsigned int bridge_width, bridge_height;
+ const struct v4l2_format_info *format_info;
+ u32 pixelformat, capture_field;
+ u32 mbus_code, bridge_field;
+ bool match;
+
+ sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height);
+
+ sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field);
+ capture_format = sun6i_csi_capture_format_find(pixelformat);
+ if (WARN_ON(!capture_format))
+ return -EINVAL;
+
+ sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height);
+
+ sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field);
+ bridge_format = sun6i_csi_bridge_format_find(mbus_code);
+ if (WARN_ON(!bridge_format))
+ return -EINVAL;
+
+ /* No cropping/scaling is supported. */
+ if (capture_width != bridge_width || capture_height != bridge_height) {
+ v4l2_err(v4l2_dev,
+ "invalid input/output dimensions: %ux%u/%ux%u\n",
+ bridge_width, bridge_height, capture_width,
+ capture_height);
+ return -EINVAL;
+ }
+
+ format_info = v4l2_format_info(pixelformat);
+ /* Some formats are not listed. */
+ if (!format_info)
+ return 0;
+
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
+ goto invalid;
+
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
+ goto invalid;
+
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+ if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422)
+ goto invalid;
+
+ /* YUV420 input can't produce YUV422 output. */
+ if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 &&
+ format_info->vdiv == 1)
+ goto invalid;
+ }
+
+ /* With raw input mode, we need a 1:1 match between input and output. */
+ if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW ||
+ capture_format->input_format_raw) {
+ match = sun6i_csi_capture_format_match(pixelformat, mbus_code);
+ if (!match)
+ goto invalid;
+ }
+
+ return 0;
+
+invalid:
+ v4l2_err(v4l2_dev, "invalid input/output format combination\n");
+ return -EINVAL;
+}
+
+static const struct media_entity_operations sun6i_csi_capture_media_ops = {
+ .link_validate = sun6i_csi_capture_link_validate
+};
+
+/* Capture */
+
+int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ struct sun6i_csi_capture_state *state = &capture->state;
+ struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
+ struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev;
+ struct video_device *video_dev = &capture->video_dev;
+ struct vb2_queue *queue = &capture->queue;
+ struct media_pad *pad = &capture->pad;
+ struct v4l2_format *format = &csi_dev->capture.format;
+ struct v4l2_pix_format *pix_format = &format->fmt.pix;
+ int ret;
+
+ /* This may happen with multiple bridge notifier bound calls. */
+ if (state->setup)
+ return 0;
+
+ /* State */
+
+ INIT_LIST_HEAD(&state->queue);
+ spin_lock_init(&state->lock);
+
+ /* Media Entity */
+
+ video_dev->entity.ops = &sun6i_csi_capture_media_ops;
+
+ /* Media Pad */
+
+ pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+
+ ret = media_entity_pads_init(&video_dev->entity, 1, pad);
+ if (ret < 0)
+ return ret;
+
+ /* Queue */
+
+ mutex_init(&capture->lock);
+
+ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->io_modes = VB2_MMAP | VB2_DMABUF;
+ queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
+ queue->ops = &sun6i_csi_capture_queue_ops;
+ queue->mem_ops = &vb2_dma_contig_memops;
+ queue->min_buffers_needed = 2;
+ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->lock = &capture->lock;
+ queue->dev = csi_dev->dev;
+ queue->drv_priv = csi_dev;
+
+ ret = vb2_queue_init(queue);
+ if (ret) {
+ v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* V4L2 Format */
+
+ format->type = queue->type;
+ pix_format->pixelformat = sun6i_csi_capture_formats[0].pixelformat;
+ pix_format->width = 1280;
+ pix_format->height = 720;
+ pix_format->field = V4L2_FIELD_NONE;
+
+ sun6i_csi_capture_format_prepare(format);
+
+ /* Video Device */
+
+ strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
+ sizeof(video_dev->name));
+ video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ video_dev->vfl_dir = VFL_DIR_RX;
+ video_dev->release = video_device_release_empty;
+ video_dev->fops = &sun6i_csi_capture_fops;
+ video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops;
+ video_dev->v4l2_dev = v4l2_dev;
+ video_dev->queue = queue;
+ video_dev->lock = &capture->lock;
+
+ video_set_drvdata(video_dev, csi_dev);
+
+ ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to register video device: %d\n",
+ ret);
+ goto error_media_entity;
+ }
+
+ /* Media Pad Link */
+
+ ret = media_create_pad_link(&bridge_subdev->entity,
+ SUN6I_CSI_BRIDGE_PAD_SOURCE,
+ &video_dev->entity, 0,
+ csi_dev->isp_available ? 0 :
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
+ bridge_subdev->entity.name,
+ SUN6I_CSI_BRIDGE_PAD_SOURCE,
+ video_dev->entity.name, 0);
+ goto error_video_device;
+ }
+
+ state->setup = true;
+
+ return 0;
+
+error_video_device:
+ vb2_video_unregister_device(video_dev);
+
+error_media_entity:
+ media_entity_cleanup(&video_dev->entity);
+
+ mutex_destroy(&capture->lock);
+
+ return ret;
+}
+
+void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ struct video_device *video_dev = &capture->video_dev;
+
+ /* This may happen if async registration failed to complete. */
+ if (!capture->state.setup)
+ return;
+
+ vb2_video_unregister_device(video_dev);
+ media_entity_cleanup(&video_dev->entity);
+ mutex_destroy(&capture->lock);
+
+ capture->state.setup = false;
+}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
new file mode 100644
index 000000000000..3ee5ccefbd10
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * Author: Yong Deng <yong.deng@magewell.com>
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_CAPTURE_H_
+#define _SUN6I_CAPTURE_H_
+
+#include <media/v4l2-device.h>
+
+#define SUN6I_CSI_CAPTURE_NAME "sun6i-csi-capture"
+
+#define SUN6I_CSI_CAPTURE_WIDTH_MIN 32
+#define SUN6I_CSI_CAPTURE_WIDTH_MAX 4800
+#define SUN6I_CSI_CAPTURE_HEIGHT_MIN 32
+#define SUN6I_CSI_CAPTURE_HEIGHT_MAX 4800
+
+struct sun6i_csi_device;
+
+struct sun6i_csi_capture_format {
+ u32 pixelformat;
+ u8 output_format_field;
+ u8 output_format_frame;
+ bool input_yuv_seq_invert;
+ bool input_format_raw;
+ u32 hsize_len_factor;
+};
+
+struct sun6i_csi_capture_format_match {
+ u32 pixelformat;
+ u32 mbus_code;
+};
+
+#undef current
+struct sun6i_csi_capture_state {
+ struct list_head queue;
+ spinlock_t lock; /* Queue and buffers lock. */
+
+ struct sun6i_csi_buffer *pending;
+ struct sun6i_csi_buffer *current;
+ struct sun6i_csi_buffer *complete;
+
+ unsigned int sequence;
+ bool streaming;
+ bool setup;
+};
+
+struct sun6i_csi_capture {
+ struct sun6i_csi_capture_state state;
+
+ struct video_device video_dev;
+ struct vb2_queue queue;
+ struct mutex lock; /* Queue lock. */
+ struct media_pad pad;
+
+ struct v4l2_format format;
+};
+
+/* Helpers */
+
+void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev,
+ unsigned int *width, unsigned int *height);
+void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev,
+ u32 *pixelformat, u32 *field);
+
+/* Format */
+
+const
+struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat);
+
+/* Capture */
+
+void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev);
+
+/* State */
+
+void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev);
+
+/* Capture */
+
+int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev);
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
index 703fa14bb313..e01c5b9c2d60 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
@@ -1,196 +1,184 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
- * All rights reserved.
* Author: Yong Deng <yong.deng@magewell.com>
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
-#ifndef __SUN6I_CSI_REG_H__
-#define __SUN6I_CSI_REG_H__
+#ifndef _SUN6I_CSI_REG_H_
+#define _SUN6I_CSI_REG_H_
#include <linux/kernel.h>
-#define CSI_EN_REG 0x0
-#define CSI_EN_VER_EN BIT(30)
-#define CSI_EN_CSI_EN BIT(0)
-
-#define CSI_IF_CFG_REG 0x4
-#define CSI_IF_CFG_SRC_TYPE_MASK BIT(21)
-#define CSI_IF_CFG_SRC_TYPE_PROGRESSED ((0 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
-#define CSI_IF_CFG_SRC_TYPE_INTERLACED ((1 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
-#define CSI_IF_CFG_FPS_DS_EN BIT(20)
-#define CSI_IF_CFG_FIELD_MASK BIT(19)
-#define CSI_IF_CFG_FIELD_NEGATIVE ((0 << 19) & CSI_IF_CFG_FIELD_MASK)
-#define CSI_IF_CFG_FIELD_POSITIVE ((1 << 19) & CSI_IF_CFG_FIELD_MASK)
-#define CSI_IF_CFG_VREF_POL_MASK BIT(18)
-#define CSI_IF_CFG_VREF_POL_NEGATIVE ((0 << 18) & CSI_IF_CFG_VREF_POL_MASK)
-#define CSI_IF_CFG_VREF_POL_POSITIVE ((1 << 18) & CSI_IF_CFG_VREF_POL_MASK)
-#define CSI_IF_CFG_HREF_POL_MASK BIT(17)
-#define CSI_IF_CFG_HREF_POL_NEGATIVE ((0 << 17) & CSI_IF_CFG_HREF_POL_MASK)
-#define CSI_IF_CFG_HREF_POL_POSITIVE ((1 << 17) & CSI_IF_CFG_HREF_POL_MASK)
-#define CSI_IF_CFG_CLK_POL_MASK BIT(16)
-#define CSI_IF_CFG_CLK_POL_RISING_EDGE ((0 << 16) & CSI_IF_CFG_CLK_POL_MASK)
-#define CSI_IF_CFG_CLK_POL_FALLING_EDGE ((1 << 16) & CSI_IF_CFG_CLK_POL_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_MASK GENMASK(10, 8)
-#define CSI_IF_CFG_IF_DATA_WIDTH_8BIT ((0 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_10BIT ((1 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_12BIT ((2 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_MIPI_IF_MASK BIT(7)
-#define CSI_IF_CFG_MIPI_IF_CSI (0 << 7)
-#define CSI_IF_CFG_MIPI_IF_MIPI BIT(7)
-#define CSI_IF_CFG_CSI_IF_MASK GENMASK(4, 0)
-#define CSI_IF_CFG_CSI_IF_YUV422_INTLV ((0 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_YUV422_16BIT ((1 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_BT656 ((4 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_BT1120 ((5 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-
-#define CSI_CAP_REG 0x8
-#define CSI_CAP_CH0_CAP_MASK_MASK GENMASK(5, 2)
-#define CSI_CAP_CH0_CAP_MASK(count) (((count) << 2) & CSI_CAP_CH0_CAP_MASK_MASK)
-#define CSI_CAP_CH0_VCAP_ON BIT(1)
-#define CSI_CAP_CH0_SCAP_ON BIT(0)
-
-#define CSI_SYNC_CNT_REG 0xc
-#define CSI_FIFO_THRS_REG 0x10
-#define CSI_BT656_HEAD_CFG_REG 0x14
-#define CSI_PTN_LEN_REG 0x30
-#define CSI_PTN_ADDR_REG 0x34
-#define CSI_VER_REG 0x3c
-
-#define CSI_CH_CFG_REG 0x44
-#define CSI_CH_CFG_INPUT_FMT_MASK GENMASK(23, 20)
-#define CSI_CH_CFG_INPUT_FMT(fmt) (((fmt) << 20) & CSI_CH_CFG_INPUT_FMT_MASK)
-#define CSI_CH_CFG_OUTPUT_FMT_MASK GENMASK(19, 16)
-#define CSI_CH_CFG_OUTPUT_FMT(fmt) (((fmt) << 16) & CSI_CH_CFG_OUTPUT_FMT_MASK)
-#define CSI_CH_CFG_VFLIP_EN BIT(13)
-#define CSI_CH_CFG_HFLIP_EN BIT(12)
-#define CSI_CH_CFG_FIELD_SEL_MASK GENMASK(11, 10)
-#define CSI_CH_CFG_FIELD_SEL_FIELD0 ((0 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_FIELD_SEL_FIELD1 ((1 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_FIELD_SEL_BOTH ((2 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_INPUT_SEQ_MASK GENMASK(9, 8)
-#define CSI_CH_CFG_INPUT_SEQ(seq) (((seq) << 8) & CSI_CH_CFG_INPUT_SEQ_MASK)
-
-#define CSI_CH_SCALE_REG 0x4c
-#define CSI_CH_SCALE_QUART_EN BIT(0)
-
-#define CSI_CH_F0_BUFA_REG 0x50
-
-#define CSI_CH_F1_BUFA_REG 0x58
-
-#define CSI_CH_F2_BUFA_REG 0x60
-
-#define CSI_CH_STA_REG 0x6c
-#define CSI_CH_STA_FIELD_STA_MASK BIT(2)
-#define CSI_CH_STA_FIELD_STA_FIELD0 ((0 << 2) & CSI_CH_STA_FIELD_STA_MASK)
-#define CSI_CH_STA_FIELD_STA_FIELD1 ((1 << 2) & CSI_CH_STA_FIELD_STA_MASK)
-#define CSI_CH_STA_VCAP_STA BIT(1)
-#define CSI_CH_STA_SCAP_STA BIT(0)
-
-#define CSI_CH_INT_EN_REG 0x70
-#define CSI_CH_INT_EN_VS_INT_EN BIT(7)
-#define CSI_CH_INT_EN_HB_OF_INT_EN BIT(6)
-#define CSI_CH_INT_EN_MUL_ERR_INT_EN BIT(5)
-#define CSI_CH_INT_EN_FIFO2_OF_INT_EN BIT(4)
-#define CSI_CH_INT_EN_FIFO1_OF_INT_EN BIT(3)
-#define CSI_CH_INT_EN_FIFO0_OF_INT_EN BIT(2)
-#define CSI_CH_INT_EN_FD_INT_EN BIT(1)
-#define CSI_CH_INT_EN_CD_INT_EN BIT(0)
-
-#define CSI_CH_INT_STA_REG 0x74
-#define CSI_CH_INT_STA_VS_PD BIT(7)
-#define CSI_CH_INT_STA_HB_OF_PD BIT(6)
-#define CSI_CH_INT_STA_MUL_ERR_PD BIT(5)
-#define CSI_CH_INT_STA_FIFO2_OF_PD BIT(4)
-#define CSI_CH_INT_STA_FIFO1_OF_PD BIT(3)
-#define CSI_CH_INT_STA_FIFO0_OF_PD BIT(2)
-#define CSI_CH_INT_STA_FD_PD BIT(1)
-#define CSI_CH_INT_STA_CD_PD BIT(0)
-
-#define CSI_CH_FLD1_VSIZE_REG 0x78
-
-#define CSI_CH_HSIZE_REG 0x80
-#define CSI_CH_HSIZE_HOR_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_HSIZE_HOR_LEN(len) (((len) << 16) & CSI_CH_HSIZE_HOR_LEN_MASK)
-#define CSI_CH_HSIZE_HOR_START_MASK GENMASK(12, 0)
-#define CSI_CH_HSIZE_HOR_START(start) (((start) << 0) & CSI_CH_HSIZE_HOR_START_MASK)
-
-#define CSI_CH_VSIZE_REG 0x84
-#define CSI_CH_VSIZE_VER_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_VSIZE_VER_LEN(len) (((len) << 16) & CSI_CH_VSIZE_VER_LEN_MASK)
-#define CSI_CH_VSIZE_VER_START_MASK GENMASK(12, 0)
-#define CSI_CH_VSIZE_VER_START(start) (((start) << 0) & CSI_CH_VSIZE_VER_START_MASK)
-
-#define CSI_CH_BUF_LEN_REG 0x88
-#define CSI_CH_BUF_LEN_BUF_LEN_C_MASK GENMASK(29, 16)
-#define CSI_CH_BUF_LEN_BUF_LEN_C(len) (((len) << 16) & CSI_CH_BUF_LEN_BUF_LEN_C_MASK)
-#define CSI_CH_BUF_LEN_BUF_LEN_Y_MASK GENMASK(13, 0)
-#define CSI_CH_BUF_LEN_BUF_LEN_Y(len) (((len) << 0) & CSI_CH_BUF_LEN_BUF_LEN_Y_MASK)
-
-#define CSI_CH_FLIP_SIZE_REG 0x8c
-#define CSI_CH_FLIP_SIZE_VER_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_FLIP_SIZE_VER_LEN(len) (((len) << 16) & CSI_CH_FLIP_SIZE_VER_LEN_MASK)
-#define CSI_CH_FLIP_SIZE_VALID_LEN_MASK GENMASK(12, 0)
-#define CSI_CH_FLIP_SIZE_VALID_LEN(len) (((len) << 0) & CSI_CH_FLIP_SIZE_VALID_LEN_MASK)
-
-#define CSI_CH_FRM_CLK_CNT_REG 0x90
-#define CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94
-#define CSI_CH_FIFO_STAT_REG 0x98
-#define CSI_CH_PCLK_STAT_REG 0x9c
-
-/*
- * csi input data format
- */
-enum csi_input_fmt {
- CSI_INPUT_FORMAT_RAW = 0,
- CSI_INPUT_FORMAT_YUV422 = 3,
- CSI_INPUT_FORMAT_YUV420 = 4,
-};
-
-/*
- * csi output data format
- */
-enum csi_output_fmt {
- /* only when input format is RAW */
- CSI_FIELD_RAW_8 = 0,
- CSI_FIELD_RAW_10 = 1,
- CSI_FIELD_RAW_12 = 2,
- CSI_FIELD_RGB565 = 4,
- CSI_FIELD_RGB888 = 5,
- CSI_FIELD_PRGB888 = 6,
- CSI_FRAME_RAW_8 = 8,
- CSI_FRAME_RAW_10 = 9,
- CSI_FRAME_RAW_12 = 10,
- CSI_FRAME_RGB565 = 12,
- CSI_FRAME_RGB888 = 13,
- CSI_FRAME_PRGB888 = 14,
-
- /* only when input format is YUV422 */
- CSI_FIELD_PLANAR_YUV422 = 0,
- CSI_FIELD_PLANAR_YUV420 = 1,
- CSI_FRAME_PLANAR_YUV420 = 2,
- CSI_FRAME_PLANAR_YUV422 = 3,
- CSI_FIELD_UV_CB_YUV422 = 4,
- CSI_FIELD_UV_CB_YUV420 = 5,
- CSI_FRAME_UV_CB_YUV420 = 6,
- CSI_FRAME_UV_CB_YUV422 = 7,
- CSI_FIELD_MB_YUV422 = 8,
- CSI_FIELD_MB_YUV420 = 9,
- CSI_FRAME_MB_YUV420 = 10,
- CSI_FRAME_MB_YUV422 = 11,
- CSI_FIELD_UV_CB_YUV422_10 = 12,
- CSI_FIELD_UV_CB_YUV420_10 = 13,
-};
-
-/*
- * csi YUV input data sequence
- */
-enum csi_input_seq {
- /* only when input format is YUV422 */
- CSI_INPUT_SEQ_YUYV = 0,
- CSI_INPUT_SEQ_YVYU,
- CSI_INPUT_SEQ_UYVY,
- CSI_INPUT_SEQ_VYUY,
-};
-
-#endif /* __SUN6I_CSI_REG_H__ */
+#define SUN6I_CSI_ADDR_VALUE(a) ((a) >> 2)
+
+#define SUN6I_CSI_EN_REG 0x0
+#define SUN6I_CSI_EN_VER_EN BIT(30)
+#define SUN6I_CSI_EN_PTN_CYCLE(v) (((v) << 16) & GENMASK(23, 16))
+#define SUN6I_CSI_EN_SRAM_PWDN BIT(8)
+#define SUN6I_CSI_EN_PTN_START BIT(4)
+#define SUN6I_CSI_EN_CLK_CNT_SPL_VSYNC BIT(3)
+#define SUN6I_CSI_EN_CLK_CNT_EN BIT(2)
+#define SUN6I_CSI_EN_PTN_GEN_EN BIT(1)
+#define SUN6I_CSI_EN_CSI_EN BIT(0)
+
+/* Note that Allwinner manuals and code invert positive/negative definitions. */
+
+#define SUN6I_CSI_IF_CFG_REG 0x4
+#define SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(v) (((v) << 24) & GENMASK(27, 24))
+#define SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE (0 << 21)
+#define SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED (1 << 21)
+#define SUN6I_CSI_IF_CFG_FPS_DS BIT(20)
+#define SUN6I_CSI_IF_CFG_FIELD_POSITIVE (0 << 19)
+#define SUN6I_CSI_IF_CFG_FIELD_NEGATIVE (1 << 19)
+#define SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE (0 << 18)
+#define SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE (1 << 18)
+#define SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE (0 << 17)
+#define SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE (1 << 17)
+#define SUN6I_CSI_IF_CFG_CLK_POL_FALLING (0 << 16)
+#define SUN6I_CSI_IF_CFG_CLK_POL_RISING (1 << 16)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC (0 << 14)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD (1 << 14)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_VSYNC (2 << 14)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8 (0 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_10 (1 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_12 (2 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8_PLUS_2 (3 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_2_TIMES_8 (4 << 8)
+#define SUN6I_CSI_IF_CFG_IF_CSI (0 << 7)
+#define SUN6I_CSI_IF_CFG_IF_MIPI (1 << 7)
+#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW (0 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED (1 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_BT656 (4 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_BT1120 (5 << 0)
+
+#define SUN6I_CSI_CAP_REG 0x8
+#define SUN6I_CSI_CAP_MASK(v) (((v) << 2) & GENMASK(5, 2))
+#define SUN6I_CSI_CAP_VCAP_ON BIT(1)
+#define SUN6I_CSI_CAP_SCAP_ON BIT(0)
+
+#define SUN6I_CSI_SYNC_CNT_REG 0xc
+#define SUN6I_CSI_FIFO_THRS_REG 0x10
+#define SUN6I_CSI_BT656_HEAD_CFG_REG 0x14
+
+#define SUN6I_CSI_PTN_LEN_REG 0x30
+#define SUN6I_CSI_PTN_ADDR_REG 0x34
+#define SUN6I_CSI_VER_REG 0x3c
+
+#define SUN6I_CSI_CH_CFG_REG 0x44
+#define SUN6I_CSI_CH_CFG_PAD_VAL(v) (((v) << 24) & GENMASK(31, 24))
+#define SUN6I_CSI_CH_CFG_INPUT_FMT(v) (((v) << 20) & GENMASK(23, 20))
+#define SUN6I_CSI_CH_CFG_OUTPUT_FMT(v) (((v) << 16) & GENMASK(19, 16))
+#define SUN6I_CSI_CH_CFG_VFLIP_EN BIT(13)
+#define SUN6I_CSI_CH_CFG_HFLIP_EN BIT(12)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0 (0 << 10)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1 (1 << 10)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER (2 << 10)
+#define SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(v) (((v) << 8) & GENMASK(9, 8))
+
+#define SUN6I_CSI_INPUT_FMT_RAW 0
+#define SUN6I_CSI_INPUT_FMT_YUV422 3
+#define SUN6I_CSI_INPUT_FMT_YUV420 4
+
+/* Note that Allwinner manuals and code invert frame/field definitions. */
+
+/* RAW */
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8 0
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10 1
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12 2
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565 4
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB888 5
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_PRGB888 6
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8 8
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10 9
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12 10
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565 12
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB888 13
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_PRGB888 14
+
+/* YUV */
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P 0
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P 1
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P 2
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P 3
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP 4
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP 5
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP 6
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP 7
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422MB 8
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB 9
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB 10
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422MB 11
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP_10 12
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP_10 13
+
+/* YUV Planar */
+#define SUN6I_CSI_INPUT_YUV_SEQ_YUYV 0
+#define SUN6I_CSI_INPUT_YUV_SEQ_YVYU 1
+#define SUN6I_CSI_INPUT_YUV_SEQ_UYVY 2
+#define SUN6I_CSI_INPUT_YUV_SEQ_VYUY 3
+
+/* YUV Semi-planar */
+#define SUN6I_CSI_INPUT_YUV_SEQ_UV 0
+#define SUN6I_CSI_INPUT_YUV_SEQ_VU 1
+
+#define SUN6I_CSI_CH_SCALE_REG 0x4c
+#define SUN6I_CSI_CH_SCALE_QUART_EN BIT(0)
+
+#define SUN6I_CSI_CH_FIFO0_ADDR_REG 0x50
+#define SUN6I_CSI_CH_FIFO1_ADDR_REG 0x58
+#define SUN6I_CSI_CH_FIFO2_ADDR_REG 0x60
+
+#define SUN6I_CSI_CH_STA_REG 0x6c
+#define SUN6I_CSI_CH_STA_FIELD BIT(2)
+#define SUN6I_CSI_CH_STA_VCAP BIT(1)
+#define SUN6I_CSI_CH_STA_SCAP BIT(0)
+
+#define SUN6I_CSI_CH_INT_EN_REG 0x70
+#define SUN6I_CSI_CH_INT_EN_VS BIT(7)
+#define SUN6I_CSI_CH_INT_EN_HB_OF BIT(6)
+#define SUN6I_CSI_CH_INT_EN_MUL_ERR BIT(5)
+#define SUN6I_CSI_CH_INT_EN_FIFO2_OF BIT(4)
+#define SUN6I_CSI_CH_INT_EN_FIFO1_OF BIT(3)
+#define SUN6I_CSI_CH_INT_EN_FIFO0_OF BIT(2)
+#define SUN6I_CSI_CH_INT_EN_FD BIT(1)
+#define SUN6I_CSI_CH_INT_EN_CD BIT(0)
+
+#define SUN6I_CSI_CH_INT_STA_REG 0x74
+#define SUN6I_CSI_CH_INT_STA_CLEAR 0xff
+#define SUN6I_CSI_CH_INT_STA_VS BIT(7)
+#define SUN6I_CSI_CH_INT_STA_HB_OF BIT(6)
+#define SUN6I_CSI_CH_INT_STA_MUL_ERR BIT(5)
+#define SUN6I_CSI_CH_INT_STA_FIFO2_OF BIT(4)
+#define SUN6I_CSI_CH_INT_STA_FIFO1_OF BIT(3)
+#define SUN6I_CSI_CH_INT_STA_FIFO0_OF BIT(2)
+#define SUN6I_CSI_CH_INT_STA_FD BIT(1)
+#define SUN6I_CSI_CH_INT_STA_CD BIT(0)
+
+#define SUN6I_CSI_CH_FLD1_VSIZE_REG 0x78
+#define SUN6I_CSI_CH_FLD1_VSIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_FLD1_VSIZE_VER_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_HSIZE_REG 0x80
+#define SUN6I_CSI_CH_HSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_HSIZE_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_VSIZE_REG 0x84
+#define SUN6I_CSI_CH_VSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_VSIZE_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_BUF_LEN_REG 0x88
+#define SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(v) (((v) << 16) & GENMASK(29, 16))
+#define SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(v) ((v) & GENMASK(13, 0))
+
+#define SUN6I_CSI_CH_FLIP_SIZE_REG 0x8c
+#define SUN6I_CSI_CH_FLIP_SIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_FLIP_SIZE_VALID_LEN(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_FRM_CLK_CNT_REG 0x90
+#define SUN6I_CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94
+#define SUN6I_CSI_CH_FIFO_STAT_REG 0x98
+#define SUN6I_CSI_CH_PCLK_STAT_REG 0x9c
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
deleted file mode 100644
index 791583d23a65..000000000000
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ /dev/null
@@ -1,733 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
- * All rights reserved.
- * Author: Yong Deng <yong.deng@magewell.com>
- */
-
-#include <linux/of.h>
-
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mc.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/videobuf2-v4l2.h>
-
-#include "sun6i_csi.h"
-#include "sun6i_video.h"
-
-/* This is got from BSP sources. */
-#define MIN_WIDTH (32)
-#define MIN_HEIGHT (32)
-#define MAX_WIDTH (4800)
-#define MAX_HEIGHT (4800)
-
-/* Helpers */
-
-static struct v4l2_subdev *
-sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
-{
- struct media_pad *remote;
-
- remote = media_pad_remote_pad_first(&video->pad);
-
- if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
- return NULL;
-
- if (pad)
- *pad = remote->index;
-
- return media_entity_to_v4l2_subdev(remote->entity);
-}
-
-/* Format */
-
-static const u32 sun6i_video_formats[] = {
- V4L2_PIX_FMT_SBGGR8,
- V4L2_PIX_FMT_SGBRG8,
- V4L2_PIX_FMT_SGRBG8,
- V4L2_PIX_FMT_SRGGB8,
- V4L2_PIX_FMT_SBGGR10,
- V4L2_PIX_FMT_SGBRG10,
- V4L2_PIX_FMT_SGRBG10,
- V4L2_PIX_FMT_SRGGB10,
- V4L2_PIX_FMT_SBGGR12,
- V4L2_PIX_FMT_SGBRG12,
- V4L2_PIX_FMT_SGRBG12,
- V4L2_PIX_FMT_SRGGB12,
- V4L2_PIX_FMT_YUYV,
- V4L2_PIX_FMT_YVYU,
- V4L2_PIX_FMT_UYVY,
- V4L2_PIX_FMT_VYUY,
- V4L2_PIX_FMT_NV12_16L16,
- V4L2_PIX_FMT_NV12,
- V4L2_PIX_FMT_NV21,
- V4L2_PIX_FMT_YUV420,
- V4L2_PIX_FMT_YVU420,
- V4L2_PIX_FMT_NV16,
- V4L2_PIX_FMT_NV61,
- V4L2_PIX_FMT_YUV422P,
- V4L2_PIX_FMT_RGB565,
- V4L2_PIX_FMT_RGB565X,
- V4L2_PIX_FMT_JPEG,
-};
-
-static bool sun6i_video_format_check(u32 format)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++)
- if (sun6i_video_formats[i] == format)
- return true;
-
- return false;
-}
-
-/* Video */
-
-static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev,
- struct sun6i_csi_buffer *csi_buffer)
-{
- csi_buffer->queued_to_csi = true;
- sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr);
-}
-
-static void sun6i_video_configure(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_video *video = &csi_dev->video;
- struct sun6i_csi_config config = { 0 };
-
- config.pixelformat = video->format.fmt.pix.pixelformat;
- config.code = video->mbus_code;
- config.field = video->format.fmt.pix.field;
- config.width = video->format.fmt.pix.width;
- config.height = video->format.fmt.pix.height;
-
- sun6i_csi_update_config(csi_dev, &config);
-}
-
-/* Queue */
-
-static int sun6i_video_queue_setup(struct vb2_queue *queue,
- unsigned int *buffers_count,
- unsigned int *planes_count,
- unsigned int sizes[],
- struct device *alloc_devs[])
-{
- struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
- unsigned int size = video->format.fmt.pix.sizeimage;
-
- if (*planes_count)
- return sizes[0] < size ? -EINVAL : 0;
-
- *planes_count = 1;
- sizes[0] = size;
-
- return 0;
-}
-
-static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer)
-{
- struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
- struct sun6i_video *video = &csi_dev->video;
- struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
- struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
- struct sun6i_csi_buffer *csi_buffer =
- container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
- unsigned long size = video->format.fmt.pix.sizeimage;
-
- if (vb2_plane_size(buffer, 0) < size) {
- v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
- vb2_plane_size(buffer, 0), size);
- return -EINVAL;
- }
-
- vb2_set_plane_payload(buffer, 0, size);
-
- csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0);
- v4l2_buffer->field = video->format.fmt.pix.field;
-
- return 0;
-}
-
-static void sun6i_video_buffer_queue(struct vb2_buffer *buffer)
-{
- struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
- struct sun6i_video *video = &csi_dev->video;
- struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
- struct sun6i_csi_buffer *csi_buffer =
- container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
- unsigned long flags;
-
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- csi_buffer->queued_to_csi = false;
- list_add_tail(&csi_buffer->list, &video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
-}
-
-static int sun6i_video_start_streaming(struct vb2_queue *queue,
- unsigned int count)
-{
- struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
- struct video_device *video_dev = &video->video_dev;
- struct sun6i_csi_buffer *buf;
- struct sun6i_csi_buffer *next_buf;
- struct v4l2_subdev *subdev;
- unsigned long flags;
- int ret;
-
- video->sequence = 0;
-
- ret = video_device_pipeline_alloc_start(video_dev);
- if (ret < 0)
- goto error_dma_queue_flush;
-
- if (video->mbus_code == 0) {
- ret = -EINVAL;
- goto error_media_pipeline;
- }
-
- subdev = sun6i_video_remote_subdev(video, NULL);
- if (!subdev) {
- ret = -EINVAL;
- goto error_media_pipeline;
- }
-
- sun6i_video_configure(csi_dev);
-
- spin_lock_irqsave(&video->dma_queue_lock, flags);
-
- buf = list_first_entry(&video->dma_queue,
- struct sun6i_csi_buffer, list);
- sun6i_video_buffer_configure(csi_dev, buf);
-
- sun6i_csi_set_stream(csi_dev, true);
-
- /*
- * CSI will lookup the next dma buffer for next frame before the
- * current frame done IRQ triggered. This is not documented
- * but reported by Ondřej Jirman.
- * The BSP code has workaround for this too. It skip to mark the
- * first buffer as frame done for VB2 and pass the second buffer
- * to CSI in the first frame done ISR call. Then in second frame
- * done ISR call, it mark the first buffer as frame done for VB2
- * and pass the third buffer to CSI. And so on. The bad thing is
- * that the first buffer will be written twice and the first frame
- * is dropped even the queued buffer is sufficient.
- * So, I make some improvement here. Pass the next buffer to CSI
- * just follow starting the CSI. In this case, the first frame
- * will be stored in first buffer, second frame in second buffer.
- * This method is used to avoid dropping the first frame, it
- * would also drop frame when lacking of queued buffer.
- */
- next_buf = list_next_entry(buf, list);
- sun6i_video_buffer_configure(csi_dev, next_buf);
-
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
-
- ret = v4l2_subdev_call(subdev, video, s_stream, 1);
- if (ret && ret != -ENOIOCTLCMD)
- goto error_stream;
-
- return 0;
-
-error_stream:
- sun6i_csi_set_stream(csi_dev, false);
-
-error_media_pipeline:
- video_device_pipeline_stop(video_dev);
-
-error_dma_queue_flush:
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- list_for_each_entry(buf, &video->dma_queue, list)
- vb2_buffer_done(&buf->v4l2_buffer.vb2_buf,
- VB2_BUF_STATE_QUEUED);
- INIT_LIST_HEAD(&video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
-
- return ret;
-}
-
-static void sun6i_video_stop_streaming(struct vb2_queue *queue)
-{
- struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
- struct v4l2_subdev *subdev;
- unsigned long flags;
- struct sun6i_csi_buffer *buf;
-
- subdev = sun6i_video_remote_subdev(video, NULL);
- if (subdev)
- v4l2_subdev_call(subdev, video, s_stream, 0);
-
- sun6i_csi_set_stream(csi_dev, false);
-
- video_device_pipeline_stop(&video->video_dev);
-
- /* Release all active buffers */
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- list_for_each_entry(buf, &video->dma_queue, list)
- vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR);
- INIT_LIST_HEAD(&video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
-}
-
-void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_video *video = &csi_dev->video;
- struct sun6i_csi_buffer *buf;
- struct sun6i_csi_buffer *next_buf;
- struct vb2_v4l2_buffer *v4l2_buffer;
-
- spin_lock(&video->dma_queue_lock);
-
- buf = list_first_entry(&video->dma_queue,
- struct sun6i_csi_buffer, list);
- if (list_is_last(&buf->list, &video->dma_queue)) {
- dev_dbg(csi_dev->dev, "Frame dropped!\n");
- goto complete;
- }
-
- next_buf = list_next_entry(buf, list);
- /* If a new buffer (#next_buf) had not been queued to CSI, the old
- * buffer (#buf) is still holding by CSI for storing the next
- * frame. So, we queue a new buffer (#next_buf) to CSI then wait
- * for next ISR call.
- */
- if (!next_buf->queued_to_csi) {
- sun6i_video_buffer_configure(csi_dev, next_buf);
- dev_dbg(csi_dev->dev, "Frame dropped!\n");
- goto complete;
- }
-
- list_del(&buf->list);
- v4l2_buffer = &buf->v4l2_buffer;
- v4l2_buffer->vb2_buf.timestamp = ktime_get_ns();
- v4l2_buffer->sequence = video->sequence;
- vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE);
-
- /* Prepare buffer for next frame but one. */
- if (!list_is_last(&next_buf->list, &video->dma_queue)) {
- next_buf = list_next_entry(next_buf, list);
- sun6i_video_buffer_configure(csi_dev, next_buf);
- } else {
- dev_dbg(csi_dev->dev, "Next frame will be dropped!\n");
- }
-
-complete:
- video->sequence++;
- spin_unlock(&video->dma_queue_lock);
-}
-
-static const struct vb2_ops sun6i_video_queue_ops = {
- .queue_setup = sun6i_video_queue_setup,
- .buf_prepare = sun6i_video_buffer_prepare,
- .buf_queue = sun6i_video_buffer_queue,
- .start_streaming = sun6i_video_start_streaming,
- .stop_streaming = sun6i_video_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
-};
-
-/* V4L2 Device */
-
-static int sun6i_video_querycap(struct file *file, void *private,
- struct v4l2_capability *capability)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct video_device *video_dev = &csi_dev->video.video_dev;
-
- strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
- strscpy(capability->card, video_dev->name, sizeof(capability->card));
- snprintf(capability->bus_info, sizeof(capability->bus_info),
- "platform:%s", dev_name(csi_dev->dev));
-
- return 0;
-}
-
-static int sun6i_video_enum_fmt(struct file *file, void *private,
- struct v4l2_fmtdesc *fmtdesc)
-{
- u32 index = fmtdesc->index;
-
- if (index >= ARRAY_SIZE(sun6i_video_formats))
- return -EINVAL;
-
- fmtdesc->pixelformat = sun6i_video_formats[index];
-
- return 0;
-}
-
-static int sun6i_video_g_fmt(struct file *file, void *private,
- struct v4l2_format *format)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
-
- *format = video->format;
-
- return 0;
-}
-
-static int sun6i_video_format_try(struct sun6i_video *video,
- struct v4l2_format *format)
-{
- struct v4l2_pix_format *pix_format = &format->fmt.pix;
- int bpp;
-
- if (!sun6i_video_format_check(pix_format->pixelformat))
- pix_format->pixelformat = sun6i_video_formats[0];
-
- v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1,
- &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);
-
- bpp = sun6i_csi_get_bpp(pix_format->pixelformat);
- pix_format->bytesperline = (pix_format->width * bpp) >> 3;
- pix_format->sizeimage = pix_format->bytesperline * pix_format->height;
-
- if (pix_format->field == V4L2_FIELD_ANY)
- pix_format->field = V4L2_FIELD_NONE;
-
- if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
- pix_format->colorspace = V4L2_COLORSPACE_JPEG;
- else
- pix_format->colorspace = V4L2_COLORSPACE_SRGB;
-
- pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
- pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
- return 0;
-}
-
-static int sun6i_video_format_set(struct sun6i_video *video,
- struct v4l2_format *format)
-{
- int ret;
-
- ret = sun6i_video_format_try(video, format);
- if (ret)
- return ret;
-
- video->format = *format;
-
- return 0;
-}
-
-static int sun6i_video_s_fmt(struct file *file, void *private,
- struct v4l2_format *format)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
-
- if (vb2_is_busy(&video->queue))
- return -EBUSY;
-
- return sun6i_video_format_set(video, format);
-}
-
-static int sun6i_video_try_fmt(struct file *file, void *private,
- struct v4l2_format *format)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
-
- return sun6i_video_format_try(video, format);
-}
-
-static int sun6i_video_enum_input(struct file *file, void *private,
- struct v4l2_input *input)
-{
- if (input->index != 0)
- return -EINVAL;
-
- input->type = V4L2_INPUT_TYPE_CAMERA;
- strscpy(input->name, "Camera", sizeof(input->name));
-
- return 0;
-}
-
-static int sun6i_video_g_input(struct file *file, void *private,
- unsigned int *index)
-{
- *index = 0;
-
- return 0;
-}
-
-static int sun6i_video_s_input(struct file *file, void *private,
- unsigned int index)
-{
- if (index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
- .vidioc_querycap = sun6i_video_querycap,
-
- .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt,
- .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt,
- .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt,
- .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt,
-
- .vidioc_enum_input = sun6i_video_enum_input,
- .vidioc_g_input = sun6i_video_g_input,
- .vidioc_s_input = sun6i_video_s_input,
-
- .vidioc_create_bufs = vb2_ioctl_create_bufs,
- .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
- .vidioc_reqbufs = vb2_ioctl_reqbufs,
- .vidioc_querybuf = vb2_ioctl_querybuf,
- .vidioc_expbuf = vb2_ioctl_expbuf,
- .vidioc_qbuf = vb2_ioctl_qbuf,
- .vidioc_dqbuf = vb2_ioctl_dqbuf,
- .vidioc_streamon = vb2_ioctl_streamon,
- .vidioc_streamoff = vb2_ioctl_streamoff,
-};
-
-/* V4L2 File */
-
-static int sun6i_video_open(struct file *file)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
- int ret = 0;
-
- if (mutex_lock_interruptible(&video->lock))
- return -ERESTARTSYS;
-
- ret = v4l2_fh_open(file);
- if (ret < 0)
- goto error_lock;
-
- ret = v4l2_pipeline_pm_get(&video->video_dev.entity);
- if (ret < 0)
- goto error_v4l2_fh;
-
- /* Power on at first open. */
- if (v4l2_fh_is_singular_file(file)) {
- ret = sun6i_csi_set_power(csi_dev, true);
- if (ret < 0)
- goto error_v4l2_fh;
- }
-
- mutex_unlock(&video->lock);
-
- return 0;
-
-error_v4l2_fh:
- v4l2_fh_release(file);
-
-error_lock:
- mutex_unlock(&video->lock);
-
- return ret;
-}
-
-static int sun6i_video_close(struct file *file)
-{
- struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
- bool last_close;
-
- mutex_lock(&video->lock);
-
- last_close = v4l2_fh_is_singular_file(file);
-
- _vb2_fop_release(file, NULL);
- v4l2_pipeline_pm_put(&video->video_dev.entity);
-
- /* Power off at last close. */
- if (last_close)
- sun6i_csi_set_power(csi_dev, false);
-
- mutex_unlock(&video->lock);
-
- return 0;
-}
-
-static const struct v4l2_file_operations sun6i_video_fops = {
- .owner = THIS_MODULE,
- .open = sun6i_video_open,
- .release = sun6i_video_close,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vb2_fop_mmap,
- .poll = vb2_fop_poll
-};
-
-/* Media Entity */
-
-static int sun6i_video_link_validate_get_format(struct media_pad *pad,
- struct v4l2_subdev_format *fmt)
-{
- if (is_media_entity_v4l2_subdev(pad->entity)) {
- struct v4l2_subdev *sd =
- media_entity_to_v4l2_subdev(pad->entity);
-
- fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt->pad = pad->index;
- return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
- }
-
- return -EINVAL;
-}
-
-static int sun6i_video_link_validate(struct media_link *link)
-{
- struct video_device *vdev = container_of(link->sink->entity,
- struct video_device, entity);
- struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev);
- struct sun6i_video *video = &csi_dev->video;
- struct v4l2_subdev_format source_fmt;
- int ret;
-
- video->mbus_code = 0;
-
- if (!media_pad_remote_pad_first(link->sink->entity->pads)) {
- dev_info(csi_dev->dev, "video node %s pad not connected\n",
- vdev->name);
- return -ENOLINK;
- }
-
- ret = sun6i_video_link_validate_get_format(link->source, &source_fmt);
- if (ret < 0)
- return ret;
-
- if (!sun6i_csi_is_format_supported(csi_dev,
- video->format.fmt.pix.pixelformat,
- source_fmt.format.code)) {
- dev_err(csi_dev->dev,
- "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
- video->format.fmt.pix.pixelformat,
- source_fmt.format.code);
- return -EPIPE;
- }
-
- if (source_fmt.format.width != video->format.fmt.pix.width ||
- source_fmt.format.height != video->format.fmt.pix.height) {
- dev_err(csi_dev->dev,
- "Wrong width or height %ux%u (%ux%u expected)\n",
- video->format.fmt.pix.width, video->format.fmt.pix.height,
- source_fmt.format.width, source_fmt.format.height);
- return -EPIPE;
- }
-
- video->mbus_code = source_fmt.format.code;
-
- return 0;
-}
-
-static const struct media_entity_operations sun6i_video_media_ops = {
- .link_validate = sun6i_video_link_validate
-};
-
-/* Video */
-
-int sun6i_video_setup(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_video *video = &csi_dev->video;
- struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
- struct video_device *video_dev = &video->video_dev;
- struct vb2_queue *queue = &video->queue;
- struct media_pad *pad = &video->pad;
- struct v4l2_format format = { 0 };
- struct v4l2_pix_format *pix_format = &format.fmt.pix;
- int ret;
-
- /* Media Entity */
-
- video_dev->entity.ops = &sun6i_video_media_ops;
-
- /* Media Pad */
-
- pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
-
- ret = media_entity_pads_init(&video_dev->entity, 1, pad);
- if (ret < 0)
- return ret;
-
- /* DMA queue */
-
- INIT_LIST_HEAD(&video->dma_queue);
- spin_lock_init(&video->dma_queue_lock);
-
- video->sequence = 0;
-
- /* Queue */
-
- mutex_init(&video->lock);
-
- queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- queue->io_modes = VB2_MMAP | VB2_DMABUF;
- queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
- queue->ops = &sun6i_video_queue_ops;
- queue->mem_ops = &vb2_dma_contig_memops;
- queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- queue->lock = &video->lock;
- queue->dev = csi_dev->dev;
- queue->drv_priv = csi_dev;
-
- /* Make sure non-dropped frame. */
- queue->min_buffers_needed = 3;
-
- ret = vb2_queue_init(queue);
- if (ret) {
- v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
- goto error_media_entity;
- }
-
- /* V4L2 Format */
-
- format.type = queue->type;
- pix_format->pixelformat = sun6i_video_formats[0];
- pix_format->width = 1280;
- pix_format->height = 720;
- pix_format->field = V4L2_FIELD_NONE;
-
- sun6i_video_format_set(video, &format);
-
- /* Video Device */
-
- strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name));
- video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- video_dev->vfl_dir = VFL_DIR_RX;
- video_dev->release = video_device_release_empty;
- video_dev->fops = &sun6i_video_fops;
- video_dev->ioctl_ops = &sun6i_video_ioctl_ops;
- video_dev->v4l2_dev = v4l2_dev;
- video_dev->queue = queue;
- video_dev->lock = &video->lock;
-
- video_set_drvdata(video_dev, csi_dev);
-
- ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
- if (ret < 0) {
- v4l2_err(v4l2_dev, "failed to register video device: %d\n",
- ret);
- goto error_media_entity;
- }
-
- return 0;
-
-error_media_entity:
- media_entity_cleanup(&video_dev->entity);
-
- mutex_destroy(&video->lock);
-
- return ret;
-}
-
-void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_video *video = &csi_dev->video;
- struct video_device *video_dev = &video->video_dev;
-
- vb2_video_unregister_device(video_dev);
- media_entity_cleanup(&video_dev->entity);
- mutex_destroy(&video->lock);
-}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
deleted file mode 100644
index a917d2da6deb..000000000000
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
- * All rights reserved.
- * Author: Yong Deng <yong.deng@magewell.com>
- */
-
-#ifndef __SUN6I_VIDEO_H__
-#define __SUN6I_VIDEO_H__
-
-#include <media/v4l2-dev.h>
-#include <media/videobuf2-core.h>
-
-struct sun6i_csi_device;
-
-struct sun6i_video {
- struct video_device video_dev;
- struct vb2_queue queue;
- struct mutex lock; /* Queue lock. */
- struct media_pad pad;
-
- struct list_head dma_queue;
- spinlock_t dma_queue_lock; /* DMA queue lock. */
-
- struct v4l2_format format;
- u32 mbus_code;
- unsigned int sequence;
-};
-
-int sun6i_video_setup(struct sun6i_csi_device *csi_dev);
-void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev);
-
-void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev);
-
-#endif /* __SUN6I_VIDEO_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index 30d6c0c5161f..484ac5f054d5 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -498,6 +498,7 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
struct v4l2_async_notifier *notifier = &bridge->notifier;
struct media_pad *pads = bridge->pads;
struct device *dev = csi2_dev->dev;
+ bool notifier_registered = false;
int ret;
mutex_init(&bridge->lock);
@@ -519,8 +520,10 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
/* Media Pads */
- pads[SUN6I_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[SUN6I_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ pads[SUN6I_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ pads[SUN6I_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&subdev->entity, SUN6I_MIPI_CSI2_PAD_COUNT,
pads);
@@ -533,12 +536,17 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
notifier->ops = &sun6i_mipi_csi2_notifier_ops;
ret = sun6i_mipi_csi2_bridge_source_setup(csi2_dev);
- if (ret)
+ if (ret && ret != -ENODEV)
goto error_v4l2_notifier_cleanup;
- ret = v4l2_async_subdev_nf_register(subdev, notifier);
- if (ret < 0)
- goto error_v4l2_notifier_cleanup;
+ /* Only register the notifier when a sensor is connected. */
+ if (ret != -ENODEV) {
+ ret = v4l2_async_subdev_nf_register(subdev, notifier);
+ if (ret < 0)
+ goto error_v4l2_notifier_cleanup;
+
+ notifier_registered = true;
+ }
/* V4L2 Subdev */
@@ -549,7 +557,8 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
return 0;
error_v4l2_notifier_unregister:
- v4l2_async_nf_unregister(notifier);
+ if (notifier_registered)
+ v4l2_async_nf_unregister(notifier);
error_v4l2_notifier_cleanup:
v4l2_async_nf_cleanup(notifier);
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index b032ec13a683..d993c09a4820 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -536,6 +536,7 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
struct v4l2_async_notifier *notifier = &bridge->notifier;
struct media_pad *pads = bridge->pads;
struct device *dev = csi2_dev->dev;
+ bool notifier_registered = false;
int ret;
mutex_init(&bridge->lock);
@@ -557,8 +558,10 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
/* Media Pads */
- pads[SUN8I_A83T_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[SUN8I_A83T_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ pads[SUN8I_A83T_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ pads[SUN8I_A83T_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&subdev->entity,
SUN8I_A83T_MIPI_CSI2_PAD_COUNT, pads);
@@ -571,12 +574,17 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
notifier->ops = &sun8i_a83t_mipi_csi2_notifier_ops;
ret = sun8i_a83t_mipi_csi2_bridge_source_setup(csi2_dev);
- if (ret)
+ if (ret && ret != -ENODEV)
goto error_v4l2_notifier_cleanup;
- ret = v4l2_async_subdev_nf_register(subdev, notifier);
- if (ret < 0)
- goto error_v4l2_notifier_cleanup;
+ /* Only register the notifier when a sensor is connected. */
+ if (ret != -ENODEV) {
+ ret = v4l2_async_subdev_nf_register(subdev, notifier);
+ if (ret < 0)
+ goto error_v4l2_notifier_cleanup;
+
+ notifier_registered = true;
+ }
/* V4L2 Subdev */
@@ -587,7 +595,8 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
return 0;
error_v4l2_notifier_unregister:
- v4l2_async_nf_unregister(notifier);
+ if (notifier_registered)
+ v4l2_async_nf_unregister(notifier);
error_v4l2_notifier_cleanup:
v4l2_async_nf_cleanup(notifier);
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index 24d2383400b0..1d40bb59ff81 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -1884,8 +1884,7 @@ static int isp_initialize_modules(struct isp_device *isp)
ret = omap3isp_ccp2_init(isp);
if (ret < 0) {
- if (ret != -EPROBE_DEFER)
- dev_err(isp->dev, "CCP2 initialization failed\n");
+ dev_err_probe(isp->dev, ret, "CCP2 initialization failed\n");
goto error_ccp2;
}
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index 29b53febc2e7..d8a23f18cfbc 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -976,11 +976,9 @@ static int xcsi2rxss_probe(struct platform_device *pdev)
/* Reset GPIO */
xcsi2rxss->rst_gpio = devm_gpiod_get_optional(dev, "video-reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(xcsi2rxss->rst_gpio)) {
- if (PTR_ERR(xcsi2rxss->rst_gpio) != -EPROBE_DEFER)
- dev_err(dev, "Video Reset GPIO not setup in DT");
- return PTR_ERR(xcsi2rxss->rst_gpio);
- }
+ if (IS_ERR(xcsi2rxss->rst_gpio))
+ return dev_err_probe(dev, PTR_ERR(xcsi2rxss->rst_gpio),
+ "Video Reset GPIO not setup in DT\n");
ret = xcsi2rxss_parse_of(xcsi2rxss);
if (ret < 0)
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index abda40e81612..2cb74afba49c 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -411,8 +411,7 @@ static const struct video_device tea5764_radio_template = {
};
/* I2C probe: check if the device exists and register with v4l if it is */
-static int tea5764_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tea5764_i2c_probe(struct i2c_client *client)
{
struct tea5764_device *radio;
struct v4l2_device *v4l2_dev;
@@ -512,7 +511,7 @@ static struct i2c_driver tea5764_i2c_driver = {
.driver = {
.name = "radio-tea5764",
},
- .probe = tea5764_i2c_probe,
+ .probe_new = tea5764_i2c_probe,
.remove = tea5764_i2c_remove,
.id_table = tea5764_id,
};
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 8b8ce2b46a55..621bb8523271 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -82,7 +82,6 @@ static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol
static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
{
int i;
- int p;
int temp;
long rest;
unsigned char buffer[25]; /* we have to bit shift 25 registers */
@@ -93,7 +92,6 @@ static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
rest = freq * 10 + 10700; /* I once had understood what is going on here */
/* maybe some wise guy (friedhelm?) can comment this stuff */
i = 13;
- p = 10;
temp = 102400;
while (rest != 0) {
if (rest % temp == rest)
@@ -103,7 +101,6 @@ static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
rest = rest - temp;
}
i--;
- p--;
temp = temp / 2;
}
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index f9e990a9c3ef..3c758a983344 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -331,8 +331,7 @@ static const struct v4l2_subdev_ops empty_ops = {};
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int saa7706h_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa7706h_probe(struct i2c_client *client)
{
struct saa7706h_state *state;
struct v4l2_subdev *sd;
@@ -406,7 +405,7 @@ static struct i2c_driver saa7706h_driver = {
.driver = {
.name = DRIVER_NAME,
},
- .probe = saa7706h_probe,
+ .probe_new = saa7706h_probe,
.remove = saa7706h_remove,
.id_table = saa7706h_id,
};
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 6b2768623c88..aa7a580dbecc 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -727,8 +727,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* start radio */
retval = si470x_start_usb(radio);
- if (retval < 0)
+ if (retval < 0 && !radio->int_in_running)
goto err_buf;
+ else if (retval < 0) /* in case of radio->int_in_running == 1 */
+ goto err_all;
/* set initial frequency */
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 7b0870a9785b..d14c97d79e83 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -141,8 +141,7 @@ static const struct v4l2_subdev_ops tef6862_ops = {
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int tef6862_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tef6862_probe(struct i2c_client *client)
{
struct tef6862_state *state;
struct v4l2_subdev *sd;
@@ -184,7 +183,7 @@ static struct i2c_driver tef6862_driver = {
.driver = {
.name = DRIVER_NAME,
},
- .probe = tef6862_probe,
+ .probe_new = tef6862_probe,
.remove = tef6862_remove,
.id_table = tef6862_id,
};
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 22e524b69806..8f1fff7af6c9 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -74,13 +74,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
return -ENOMEM;
gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
- if (IS_ERR(gpio_dev->gpiod)) {
- rc = PTR_ERR(gpio_dev->gpiod);
- /* Just try again if this happens */
- if (rc != -EPROBE_DEFER)
- dev_err(dev, "error getting gpio (%d)\n", rc);
- return rc;
- }
+ if (IS_ERR(gpio_dev->gpiod))
+ return dev_err_probe(dev, PTR_ERR(gpio_dev->gpiod),
+ "error getting gpio\n");
gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod);
if (gpio_dev->irq < 0)
return gpio_dev->irq;
diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c
index d3063ddb472e..2b829c146db1 100644
--- a/drivers/media/rc/gpio-ir-tx.c
+++ b/drivers/media/rc/gpio-ir-tx.c
@@ -174,12 +174,9 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)
return -ENOMEM;
gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
- if (IS_ERR(gpio_ir->gpio)) {
- if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to get gpio (%ld)\n",
- PTR_ERR(gpio_ir->gpio));
- return PTR_ERR(gpio_ir->gpio);
- }
+ if (IS_ERR(gpio_ir->gpio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(gpio_ir->gpio),
+ "Failed to get gpio\n");
rcdev->priv = gpio_ir;
rcdev->driver_name = DRIVER_NAME;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 5edfd8a9e849..74546f7e3469 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -646,15 +646,14 @@ static int send_packet(struct imon_context *ictx)
pr_err_ratelimited("error submitting urb(%d)\n", retval);
} else {
/* Wait for transmission to complete (or abort) */
- mutex_unlock(&ictx->lock);
retval = wait_for_completion_interruptible(
&ictx->tx.finished);
if (retval) {
usb_kill_urb(ictx->tx_urb);
pr_err_ratelimited("task interrupted\n");
}
- mutex_lock(&ictx->lock);
+ ictx->tx.busy = false;
retval = ictx->tx.status;
if (retval)
pr_err_ratelimited("packet tx failed (%d)\n", retval);
@@ -953,7 +952,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
if (ictx->disconnected)
return -ENODEV;
- mutex_lock(&ictx->lock);
+ if (mutex_lock_interruptible(&ictx->lock))
+ return -ERESTARTSYS;
if (!ictx->dev_present_intf0) {
pr_err_ratelimited("no iMON device present\n");
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
index a3b145183260..85080c3d2053 100644
--- a/drivers/media/rc/ir-rx51.c
+++ b/drivers/media/rc/ir-rx51.c
@@ -231,13 +231,8 @@ static int ir_rx51_probe(struct platform_device *dev)
struct rc_dev *rcdev;
pwm = pwm_get(&dev->dev, NULL);
- if (IS_ERR(pwm)) {
- int err = PTR_ERR(pwm);
-
- if (err != -EPROBE_DEFER)
- dev_err(&dev->dev, "pwm_get failed: %d\n", err);
- return err;
- }
+ if (IS_ERR(pwm))
+ return dev_err_probe(&dev->dev, PTR_ERR(pwm), "pwm_get failed\n");
/* Use default, in case userspace does not set the carrier */
ir_rx51.freq = DIV_ROUND_CLOSEST_ULL(pwm_get_period(pwm), NSEC_PER_SEC);
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index 51aa55a84bb5..bbc81bed4f90 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -158,8 +158,15 @@ static const struct of_device_id ir_spi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ir_spi_of_match);
+static const struct spi_device_id ir_spi_ids[] = {
+ { "ir-spi-led" },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, ir_spi_ids);
+
static struct spi_driver ir_spi_driver = {
.probe = ir_spi_probe,
+ .id_table = ir_spi_ids,
.driver = {
.name = IR_SPI_DRIVER_NAME,
.of_match_table = ir_spi_of_match,
diff --git a/drivers/media/test-drivers/Kconfig b/drivers/media/test-drivers/Kconfig
index 51cf27834df0..459b433e9fae 100644
--- a/drivers/media/test-drivers/Kconfig
+++ b/drivers/media/test-drivers/Kconfig
@@ -20,6 +20,7 @@ config VIDEO_VIM2M
source "drivers/media/test-drivers/vicodec/Kconfig"
source "drivers/media/test-drivers/vimc/Kconfig"
source "drivers/media/test-drivers/vivid/Kconfig"
+source "drivers/media/test-drivers/visl/Kconfig"
endif #V4L_TEST_DRIVERS
diff --git a/drivers/media/test-drivers/Makefile b/drivers/media/test-drivers/Makefile
index ff390b687189..740714a4584d 100644
--- a/drivers/media/test-drivers/Makefile
+++ b/drivers/media/test-drivers/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_VIDEO_VICODEC) += vicodec/
obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
obj-$(CONFIG_VIDEO_VIMC) += vimc/
obj-$(CONFIG_VIDEO_VIVID) += vivid/
+obj-$(CONFIG_VIDEO_VISL) += visl/
diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
index 82620613d56b..dff7265a42ca 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
@@ -459,26 +459,20 @@ fail_dmx_conn:
for (j = j - 1; j >= 0; --j)
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx,
&dvb->dmx_fe[j]);
-fail_dmx_dev:
dvb_dmxdev_release(&dvb->dmx_dev);
-fail_dmx:
+fail_dmx_dev:
dvb_dmx_release(&dvb->demux);
+fail_dmx:
+fail_demod_probe:
+ for (i = i - 1; i >= 0; --i) {
+ dvb_unregister_frontend(dvb->fe[i]);
fail_fe:
- for (j = i; j >= 0; --j)
- dvb_unregister_frontend(dvb->fe[j]);
+ dvb_module_release(dvb->i2c_client_tuner[i]);
fail_tuner_probe:
- for (j = i; j >= 0; --j)
- if (dvb->i2c_client_tuner[j])
- dvb_module_release(dvb->i2c_client_tuner[j]);
-
-fail_demod_probe:
- for (j = i; j >= 0; --j)
- if (dvb->i2c_client_demod[j])
- dvb_module_release(dvb->i2c_client_demod[j]);
-
+ dvb_module_release(dvb->i2c_client_demod[i]);
+ }
fail_adapter:
dvb_unregister_adapter(&dvb->adapter);
-
fail_i2c:
i2c_del_adapter(&dvb->i2c_adapter);
diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.c b/drivers/media/test-drivers/vidtv/vidtv_demod.c
index e7959ab1add8..b878db798686 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_demod.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_demod.c
@@ -188,11 +188,11 @@ static void vidtv_demod_update_stats(struct dvb_frontend *fe)
* Also, usually, signal strength is a negative number in dBm.
*/
c->strength.stat[0].svalue = state->tuner_cnr;
- c->strength.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
+ c->strength.stat[0].svalue -= get_random_u32_below(state->tuner_cnr / 50);
c->strength.stat[0].svalue -= 68000; /* Adjust to a better range */
c->cnr.stat[0].svalue = state->tuner_cnr;
- c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
+ c->cnr.stat[0].svalue -= get_random_u32_below(state->tuner_cnr / 50);
}
static int vidtv_demod_read_status(struct dvb_frontend *fe,
@@ -213,11 +213,11 @@ static int vidtv_demod_read_status(struct dvb_frontend *fe,
if (snr < cnr2qual->cnr_ok) {
/* eventually lose the TS lock */
- if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
+ if (get_random_u32_below(100) < config->drop_tslock_prob_on_low_snr)
state->status = 0;
} else {
/* recover if the signal improves */
- if (prandom_u32_max(100) <
+ if (get_random_u32_below(100) <
config->recover_tslock_prob_on_good_snr)
state->status = FE_HAS_SIGNAL |
FE_HAS_CARRIER |
@@ -412,8 +412,7 @@ static const struct i2c_device_id vidtv_demod_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, vidtv_demod_i2c_id_table);
-static int vidtv_demod_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vidtv_demod_i2c_probe(struct i2c_client *client)
{
struct vidtv_tuner_config *config = client->dev.platform_data;
struct vidtv_demod_state *state;
@@ -450,7 +449,7 @@ static struct i2c_driver vidtv_demod_i2c_driver = {
.name = "dvb_vidtv_demod",
.suppress_bind_attrs = true,
},
- .probe = vidtv_demod_i2c_probe,
+ .probe_new = vidtv_demod_i2c_probe,
.remove = vidtv_demod_i2c_remove,
.id_table = vidtv_demod_i2c_id_table,
};
diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.c b/drivers/media/test-drivers/vidtv/vidtv_tuner.c
index aabc97ed736b..55a4387f3854 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_tuner.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.c
@@ -390,8 +390,7 @@ static const struct i2c_device_id vidtv_tuner_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, vidtv_tuner_i2c_id_table);
-static int vidtv_tuner_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vidtv_tuner_i2c_probe(struct i2c_client *client)
{
struct vidtv_tuner_config *config = client->dev.platform_data;
struct dvb_frontend *fe = config->fe;
@@ -426,7 +425,7 @@ static struct i2c_driver vidtv_tuner_i2c_driver = {
.name = "dvb_vidtv_tuner",
.suppress_bind_attrs = true,
},
- .probe = vidtv_tuner_i2c_probe,
+ .probe_new = vidtv_tuner_i2c_probe,
.remove = vidtv_tuner_i2c_remove,
.id_table = vidtv_tuner_i2c_id_table,
};
diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
index 2ae7a0f11ebf..e82cfa5ffbf4 100644
--- a/drivers/media/test-drivers/vimc/vimc-core.c
+++ b/drivers/media/test-drivers/vimc/vimc-core.c
@@ -433,7 +433,7 @@ static int __init vimc_init(void)
if (ret) {
dev_err(&vimc_pdev.dev,
"platform driver registration failed (err=%d)\n", ret);
- platform_driver_unregister(&vimc_pdrv);
+ platform_device_unregister(&vimc_pdev);
return ret;
}
diff --git a/drivers/media/test-drivers/visl/Kconfig b/drivers/media/test-drivers/visl/Kconfig
new file mode 100644
index 000000000000..7508b904f196
--- /dev/null
+++ b/drivers/media/test-drivers/visl/Kconfig
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0+
+config VIDEO_VISL
+ tristate "Virtual Stateless Decoder Driver (visl)"
+ depends on VIDEO_DEV
+ select FONT_SUPPORT
+ select FONT_8x16
+ select VIDEOBUF2_VMALLOC
+ select V4L2_MEM2MEM_DEV
+ select MEDIA_CONTROLLER
+ select MEDIA_CONTROLLER_REQUEST_API
+ select VIDEO_V4L2_TPG
+ help
+
+ A virtual stateless decoder device for uAPI development purposes.
+
+ A userspace implementation can use visl to run a decoding loop even
+ when no hardware is available or when the kernel uAPI for the codec
+ has not been upstreamed yet. This can reveal bugs at an early stage.
+
+ When in doubt, say N.
+
+config VISL_DEBUGFS
+ bool "Enable debugfs for visl"
+ depends on VIDEO_VISL
+ depends on DEBUG_FS
+
+ help
+ Choose Y to dump the bitstream buffers through debugfs.
+ When in doubt, say N.
diff --git a/drivers/media/test-drivers/visl/Makefile b/drivers/media/test-drivers/visl/Makefile
new file mode 100644
index 000000000000..fb4d5ae1b17f
--- /dev/null
+++ b/drivers/media/test-drivers/visl/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+visl-y := visl-core.o visl-video.o visl-dec.o visl-trace-points.o
+
+ifeq ($(CONFIG_VISL_DEBUGFS),y)
+ visl-y += visl-debugfs.o
+endif
+
+obj-$(CONFIG_VIDEO_VISL) += visl.o
diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
new file mode 100644
index 000000000000..9cb60ab653bf
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-core.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A virtual stateless decoder device for stateless uAPI development purposes.
+ *
+ * This tool's objective is to help the development and testing of userspace
+ * applications that use the V4L2 stateless API to decode media.
+ *
+ * A userspace implementation can use visl to run a decoding loop even when no
+ * hardware is available or when the kernel uAPI for the codec has not been
+ * upstreamed yet. This can reveal bugs at an early stage.
+ *
+ * This driver can also trace the contents of the V4L2 controls submitted to it.
+ * It can also dump the contents of the vb2 buffers through a debugfs
+ * interface. This is in many ways similar to the tracing infrastructure
+ * available for other popular encode/decode APIs out there and can help develop
+ * a userspace application by using another (working) one as a reference.
+ *
+ * Note that no actual decoding of video frames is performed by visl. The V4L2
+ * test pattern generator is used to write various debug information to the
+ * capture buffers instead.
+ *
+ * Copyright (C) 2022 Collabora, Ltd.
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * Based on the vicodec driver, that is:
+ *
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "visl.h"
+#include "visl-dec.h"
+#include "visl-debugfs.h"
+#include "visl-video.h"
+
+unsigned int visl_debug;
+module_param(visl_debug, uint, 0644);
+MODULE_PARM_DESC(visl_debug, " activates debug info");
+
+unsigned int visl_transtime_ms;
+module_param(visl_transtime_ms, uint, 0644);
+MODULE_PARM_DESC(visl_transtime_ms, " simulated process time in milliseconds.");
+
+/*
+ * dprintk can be slow through serial. This lets one limit the tracing to a
+ * particular number of frames
+ */
+int visl_dprintk_frame_start = -1;
+module_param(visl_dprintk_frame_start, int, 0);
+MODULE_PARM_DESC(visl_dprintk_frame_start,
+ " a frame number to start tracing with dprintk");
+
+unsigned int visl_dprintk_nframes;
+module_param(visl_dprintk_nframes, uint, 0);
+MODULE_PARM_DESC(visl_dprintk_nframes,
+ " the number of frames to trace with dprintk");
+
+bool keep_bitstream_buffers;
+module_param(keep_bitstream_buffers, bool, false);
+MODULE_PARM_DESC(keep_bitstream_buffers,
+ " keep bitstream buffers in debugfs after streaming is stopped");
+
+int bitstream_trace_frame_start = -1;
+module_param(bitstream_trace_frame_start, int, 0);
+MODULE_PARM_DESC(bitstream_trace_frame_start,
+ " a frame number to start dumping the bitstream through debugfs");
+
+unsigned int bitstream_trace_nframes;
+module_param(bitstream_trace_nframes, uint, 0);
+MODULE_PARM_DESC(bitstream_trace_nframes,
+ " the number of frames to dump the bitstream through debugfs");
+
+static const struct visl_ctrl_desc visl_fwht_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_FWHT_PARAMS,
+ },
+};
+
+const struct visl_ctrls visl_fwht_ctrls = {
+ .ctrls = visl_fwht_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_fwht_ctrl_descs)
+};
+
+static const struct visl_ctrl_desc visl_mpeg2_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_MPEG2_PICTURE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
+ },
+};
+
+const struct visl_ctrls visl_mpeg2_ctrls = {
+ .ctrls = visl_mpeg2_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_mpeg2_ctrl_descs),
+};
+
+static const struct visl_ctrl_desc visl_vp8_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_VP8_FRAME,
+ },
+};
+
+const struct visl_ctrls visl_vp8_ctrls = {
+ .ctrls = visl_vp8_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_vp8_ctrl_descs),
+};
+
+static const struct visl_ctrl_desc visl_vp9_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_VP9_FRAME,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR,
+ },
+};
+
+const struct visl_ctrls visl_vp9_ctrls = {
+ .ctrls = visl_vp9_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_vp9_ctrl_descs),
+};
+
+static const struct visl_ctrl_desc visl_h264_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SPS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_PPS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_START_CODE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
+ },
+};
+
+const struct visl_ctrls visl_h264_ctrls = {
+ .ctrls = visl_h264_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_h264_ctrl_descs),
+};
+
+static const struct visl_ctrl_desc visl_hevc_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
+ /* The absolute maximum for level > 6 */
+ .cfg.dims = { 600 },
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS,
+ .cfg.dims = { 256 },
+ .cfg.max = 0xffffffff,
+ .cfg.step = 1,
+ },
+
+};
+
+const struct visl_ctrls visl_hevc_ctrls = {
+ .ctrls = visl_hevc_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_hevc_ctrl_descs),
+};
+
+struct v4l2_ctrl *visl_find_control(struct visl_ctx *ctx, u32 id)
+{
+ struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+
+ return v4l2_ctrl_find(hdl, id);
+}
+
+void *visl_find_control_data(struct visl_ctx *ctx, u32 id)
+{
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = visl_find_control(ctx, id);
+ if (ctrl)
+ return ctrl->p_cur.p;
+
+ return NULL;
+}
+
+u32 visl_control_num_elems(struct visl_ctx *ctx, u32 id)
+{
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = visl_find_control(ctx, id);
+ if (ctrl)
+ return ctrl->elems;
+
+ return 0;
+}
+
+static void visl_device_release(struct video_device *vdev)
+{
+ struct visl_dev *dev = container_of(vdev, struct visl_dev, vfd);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_m2m_release(dev->m2m_dev);
+ media_device_cleanup(&dev->mdev);
+ visl_debugfs_deinit(dev);
+ kfree(dev);
+}
+
+#define VISL_CONTROLS_COUNT ARRAY_SIZE(visl_controls)
+
+static int visl_init_ctrls(struct visl_ctx *ctx)
+{
+ struct visl_dev *dev = ctx->dev;
+ struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+ unsigned int ctrl_cnt = 0;
+ unsigned int i;
+ unsigned int j;
+ const struct visl_ctrls *ctrls;
+
+ for (i = 0; i < num_coded_fmts; i++)
+ ctrl_cnt += visl_coded_fmts[i].ctrls->num_ctrls;
+
+ v4l2_ctrl_handler_init(hdl, ctrl_cnt);
+
+ for (i = 0; i < num_coded_fmts; i++) {
+ ctrls = visl_coded_fmts[i].ctrls;
+ for (j = 0; j < ctrls->num_ctrls; j++)
+ v4l2_ctrl_new_custom(hdl, &ctrls->ctrls[j].cfg, NULL);
+ }
+
+ if (hdl->error) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to initialize control handler\n");
+ v4l2_ctrl_handler_free(hdl);
+ return hdl->error;
+ }
+
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+
+ return 0;
+}
+
+static int visl_open(struct file *file)
+{
+ struct visl_dev *dev = video_drvdata(file);
+ struct visl_ctx *ctx = NULL;
+ int rc = 0;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto unlock;
+ }
+
+ ctx->tpg_str_buf = kzalloc(TPG_STR_BUF_SZ, GFP_KERNEL);
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+
+ rc = visl_init_ctrls(ctx);
+ if (rc)
+ goto free_ctx;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &visl_queue_init);
+
+ mutex_init(&ctx->vb_mutex);
+
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ rc = PTR_ERR(ctx->fh.m2m_ctx);
+ goto free_hdl;
+ }
+
+ rc = visl_set_default_format(ctx);
+ if (rc)
+ goto free_m2m_ctx;
+
+ v4l2_fh_add(&ctx->fh);
+
+ dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
+ ctx, ctx->fh.m2m_ctx);
+
+ mutex_unlock(&dev->dev_mutex);
+ return rc;
+
+free_m2m_ctx:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+free_hdl:
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ v4l2_fh_exit(&ctx->fh);
+free_ctx:
+ kfree(ctx->tpg_str_buf);
+ kfree(ctx);
+unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return rc;
+}
+
+static int visl_release(struct file *file)
+{
+ struct visl_dev *dev = video_drvdata(file);
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+
+ dprintk(dev, "Releasing instance %p\n", ctx);
+
+ tpg_free(&ctx->tpg);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ mutex_lock(&dev->dev_mutex);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ mutex_unlock(&dev->dev_mutex);
+
+ kfree(ctx->tpg_str_buf);
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations visl_fops = {
+ .owner = THIS_MODULE,
+ .open = visl_open,
+ .release = visl_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device visl_videodev = {
+ .name = VISL_NAME,
+ .vfl_dir = VFL_DIR_M2M,
+ .fops = &visl_fops,
+ .ioctl_ops = &visl_ioctl_ops,
+ .minor = -1,
+ .release = visl_device_release,
+ .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops visl_m2m_ops = {
+ .device_run = visl_device_run,
+};
+
+static const struct media_device_ops visl_m2m_media_ops = {
+ .req_validate = visl_request_validate,
+ .req_queue = v4l2_m2m_request_queue,
+};
+
+static int visl_probe(struct platform_device *pdev)
+{
+ struct visl_dev *dev;
+ struct video_device *vfd;
+ int ret;
+ int rc;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto error_visl_dev;
+
+ mutex_init(&dev->dev_mutex);
+
+ dev->vfd = visl_videodev;
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ video_set_drvdata(vfd, dev);
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->m2m_dev = v4l2_m2m_init(&visl_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+ dev->m2m_dev = NULL;
+ goto error_dev;
+ }
+
+ dev->mdev.dev = &pdev->dev;
+ strscpy(dev->mdev.model, "visl", sizeof(dev->mdev.model));
+ strscpy(dev->mdev.bus_info, "platform:visl",
+ sizeof(dev->mdev.bus_info));
+ media_device_init(&dev->mdev);
+ dev->mdev.ops = &visl_m2m_media_ops;
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto error_m2m;
+ }
+
+ v4l2_info(&dev->v4l2_dev,
+ "Device registered as /dev/video%d\n", vfd->num);
+
+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
+ MEDIA_ENT_F_PROC_VIDEO_DECODER);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
+ goto error_v4l2;
+ }
+
+ ret = media_device_register(&dev->mdev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
+ goto error_m2m_mc;
+ }
+
+ rc = visl_debugfs_init(dev);
+ if (rc)
+ dprintk(dev, "visl_debugfs_init failed: %d\n"
+ "Continuing without debugfs support\n", rc);
+
+ return 0;
+
+error_m2m_mc:
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+error_v4l2:
+ video_unregister_device(&dev->vfd);
+ /* visl_device_release called by video_unregister_device to release various objects */
+ return ret;
+error_m2m:
+ v4l2_m2m_release(dev->m2m_dev);
+error_dev:
+ v4l2_device_unregister(&dev->v4l2_dev);
+error_visl_dev:
+ kfree(dev);
+
+ return ret;
+}
+
+static int visl_remove(struct platform_device *pdev)
+{
+ struct visl_dev *dev = platform_get_drvdata(pdev);
+
+ v4l2_info(&dev->v4l2_dev, "Removing " VISL_NAME);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (media_devnode_is_registered(dev->mdev.devnode)) {
+ media_device_unregister(&dev->mdev);
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+ }
+#endif
+ video_unregister_device(&dev->vfd);
+
+ return 0;
+}
+
+static struct platform_driver visl_pdrv = {
+ .probe = visl_probe,
+ .remove = visl_remove,
+ .driver = {
+ .name = VISL_NAME,
+ },
+};
+
+static void visl_dev_release(struct device *dev) {}
+
+static struct platform_device visl_pdev = {
+ .name = VISL_NAME,
+ .dev.release = visl_dev_release,
+};
+
+static void __exit visl_exit(void)
+{
+ platform_driver_unregister(&visl_pdrv);
+ platform_device_unregister(&visl_pdev);
+}
+
+static int __init visl_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&visl_pdev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&visl_pdrv);
+ if (ret)
+ platform_device_unregister(&visl_pdev);
+
+ return ret;
+}
+
+MODULE_DESCRIPTION("Virtual stateless decoder device");
+MODULE_AUTHOR("Daniel Almeida <daniel.almeida@collabora.com>");
+MODULE_LICENSE("GPL");
+
+module_init(visl_init);
+module_exit(visl_exit);
diff --git a/drivers/media/test-drivers/visl/visl-debugfs.c b/drivers/media/test-drivers/visl/visl-debugfs.c
new file mode 100644
index 000000000000..45f2a8268014
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-debugfs.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Debugfs tracing for bitstream buffers. This is similar to VA-API's
+ * LIBVA_TRACE_BUFDATA in that the raw bitstream can be dumped as a debugging
+ * aid.
+ *
+ * Produces one file per OUTPUT buffer. Files are automatically cleared on
+ * STREAMOFF unless the module parameter "keep_bitstream_buffers" is set.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "visl-debugfs.h"
+
+int visl_debugfs_init(struct visl_dev *dev)
+{
+ dev->debugfs_root = debugfs_create_dir("visl", NULL);
+ INIT_LIST_HEAD(&dev->bitstream_blobs);
+ mutex_init(&dev->bitstream_lock);
+
+ if (IS_ERR(dev->debugfs_root))
+ return PTR_ERR(dev->debugfs_root);
+
+ return visl_debugfs_bitstream_init(dev);
+}
+
+int visl_debugfs_bitstream_init(struct visl_dev *dev)
+{
+ dev->bitstream_debugfs = debugfs_create_dir("bitstream",
+ dev->debugfs_root);
+ if (IS_ERR(dev->bitstream_debugfs))
+ return PTR_ERR(dev->bitstream_debugfs);
+
+ return 0;
+}
+
+void visl_trace_bitstream(struct visl_ctx *ctx, struct visl_run *run)
+{
+ u8 *vaddr = vb2_plane_vaddr(&run->src->vb2_buf, 0);
+ struct visl_blob *blob;
+ size_t data_sz = vb2_get_plane_payload(&run->src->vb2_buf, 0);
+ struct dentry *dentry;
+ char name[32];
+
+ blob = kzalloc(sizeof(*blob), GFP_KERNEL);
+ if (!blob)
+ return;
+
+ blob->blob.data = vzalloc(data_sz);
+ if (!blob->blob.data)
+ goto err_vmalloc;
+
+ blob->blob.size = data_sz;
+ snprintf(name, 32, "bitstream%d", run->src->sequence);
+
+ memcpy(blob->blob.data, vaddr, data_sz);
+
+ dentry = debugfs_create_blob(name, 0444, ctx->dev->bitstream_debugfs,
+ &blob->blob);
+ if (IS_ERR(dentry))
+ goto err_debugfs;
+
+ blob->dentry = dentry;
+
+ mutex_lock(&ctx->dev->bitstream_lock);
+ list_add_tail(&blob->list, &ctx->dev->bitstream_blobs);
+ mutex_unlock(&ctx->dev->bitstream_lock);
+
+ return;
+
+err_debugfs:
+ vfree(blob->blob.data);
+err_vmalloc:
+ kfree(blob);
+}
+
+void visl_debugfs_clear_bitstream(struct visl_dev *dev)
+{
+ struct visl_blob *blob;
+ struct visl_blob *tmp;
+
+ mutex_lock(&dev->bitstream_lock);
+ if (list_empty(&dev->bitstream_blobs))
+ goto unlock;
+
+ list_for_each_entry_safe(blob, tmp, &dev->bitstream_blobs, list) {
+ list_del(&blob->list);
+ debugfs_remove(blob->dentry);
+ vfree(blob->blob.data);
+ kfree(blob);
+ }
+
+unlock:
+ mutex_unlock(&dev->bitstream_lock);
+}
+
+void visl_debugfs_bitstream_deinit(struct visl_dev *dev)
+{
+ visl_debugfs_clear_bitstream(dev);
+ debugfs_remove_recursive(dev->bitstream_debugfs);
+ dev->bitstream_debugfs = NULL;
+}
+
+void visl_debugfs_deinit(struct visl_dev *dev)
+{
+ visl_debugfs_bitstream_deinit(dev);
+ debugfs_remove_recursive(dev->debugfs_root);
+ dev->debugfs_root = NULL;
+}
diff --git a/drivers/media/test-drivers/visl/visl-debugfs.h b/drivers/media/test-drivers/visl/visl-debugfs.h
new file mode 100644
index 000000000000..81508f611918
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-debugfs.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Debugfs tracing for bitstream buffers. This is similar to VA-API's
+ * LIBVA_TRACE_BUFDATA in that the raw bitstream can be dumped as a debugging
+ * aid.
+ *
+ * Produces one file per OUTPUT buffer. Files are automatically cleared on
+ * STREAMOFF unless the module parameter "keep_bitstream_buffers" is set.
+ */
+
+#include "visl.h"
+#include "visl-dec.h"
+
+#ifdef CONFIG_VISL_DEBUGFS
+
+int visl_debugfs_init(struct visl_dev *dev);
+int visl_debugfs_bitstream_init(struct visl_dev *dev);
+void visl_trace_bitstream(struct visl_ctx *ctx, struct visl_run *run);
+void visl_debugfs_clear_bitstream(struct visl_dev *dev);
+void visl_debugfs_bitstream_deinit(struct visl_dev *dev);
+void visl_debugfs_deinit(struct visl_dev *dev);
+
+#else
+
+static inline int visl_debugfs_init(struct visl_dev *dev)
+{
+ return 0;
+}
+
+static inline int visl_debugfs_bitstream_init(struct visl_dev *dev)
+{
+ return 0;
+}
+
+static inline void visl_trace_bitstream(struct visl_ctx *ctx, struct visl_run *run) {}
+static inline void visl_debugfs_clear_bitstream(struct visl_dev *dev) {}
+static inline void visl_debugfs_bitstream_deinit(struct visl_dev *dev) {}
+static inline void visl_debugfs_deinit(struct visl_dev *dev) {}
+
+#endif
diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
new file mode 100644
index 000000000000..318d675e5668
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Contains the virtual decoder logic. The functions here control the
+ * tracing/TPG on a per-frame basis
+ */
+
+#include "visl.h"
+#include "visl-debugfs.h"
+#include "visl-dec.h"
+#include "visl-trace-fwht.h"
+#include "visl-trace-mpeg2.h"
+#include "visl-trace-vp8.h"
+#include "visl-trace-vp9.h"
+#include "visl-trace-h264.h"
+#include "visl-trace-hevc.h"
+
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/tpg/v4l2-tpg.h>
+
+static void *plane_vaddr(struct tpg_data *tpg, struct vb2_buffer *buf,
+ u32 p, u32 bpl[TPG_MAX_PLANES], u32 h)
+{
+ u32 i;
+ void *vbuf;
+
+ if (p == 0 || tpg_g_buffers(tpg) > 1)
+ return vb2_plane_vaddr(buf, p);
+ vbuf = vb2_plane_vaddr(buf, 0);
+ for (i = 0; i < p; i++)
+ vbuf += bpl[i] * h / tpg->vdownsampling[i];
+ return vbuf;
+}
+
+static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
+ __kernel_size_t buflen, struct visl_run *run)
+{
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ char header[] = "Reference frames:\n";
+ u32 i;
+ u32 len;
+
+ len = scnprintf(buf, buflen, header);
+ buf += len;
+ buflen -= len;
+
+ switch (ctx->current_codec) {
+ case VISL_CODEC_NONE:
+ break;
+
+ case VISL_CODEC_FWHT: {
+ struct vb2_buffer *vb2_buf;
+
+ vb2_buf = vb2_find_buffer(cap_q, run->fwht.params->backward_ref_ts);
+
+ scnprintf(buf, buflen, "backwards_ref_ts: %lld, vb2_idx: %d",
+ run->fwht.params->backward_ref_ts,
+ vb2_buf ? vb2_buf->index : -1);
+ break;
+ }
+
+ case VISL_CODEC_MPEG2: {
+ struct vb2_buffer *b_ref;
+ struct vb2_buffer *f_ref;
+
+ b_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->backward_ref_ts);
+ f_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->forward_ref_ts);
+
+ scnprintf(buf, buflen,
+ "backward_ref_ts: %llu, vb2_idx: %d\n"
+ "forward_ref_ts: %llu, vb2_idx: %d\n",
+ run->mpeg2.pic->backward_ref_ts,
+ b_ref ? b_ref->index : -1,
+ run->mpeg2.pic->forward_ref_ts,
+ f_ref ? f_ref->index : -1);
+ break;
+ }
+
+ case VISL_CODEC_VP8: {
+ struct vb2_buffer *last;
+ struct vb2_buffer *golden;
+ struct vb2_buffer *alt;
+
+ last = vb2_find_buffer(cap_q, run->vp8.frame->last_frame_ts);
+ golden = vb2_find_buffer(cap_q, run->vp8.frame->golden_frame_ts);
+ alt = vb2_find_buffer(cap_q, run->vp8.frame->alt_frame_ts);
+
+ scnprintf(buf, buflen,
+ "last_ref_ts: %llu, vb2_idx: %d\n"
+ "golden_ref_ts: %llu, vb2_idx: %d\n"
+ "alt_ref_ts: %llu, vb2_idx: %d\n",
+ run->vp8.frame->last_frame_ts,
+ last ? last->index : -1,
+ run->vp8.frame->golden_frame_ts,
+ golden ? golden->index : -1,
+ run->vp8.frame->alt_frame_ts,
+ alt ? alt->index : -1);
+ break;
+ }
+
+ case VISL_CODEC_VP9: {
+ struct vb2_buffer *last;
+ struct vb2_buffer *golden;
+ struct vb2_buffer *alt;
+
+ last = vb2_find_buffer(cap_q, run->vp9.frame->last_frame_ts);
+ golden = vb2_find_buffer(cap_q, run->vp9.frame->golden_frame_ts);
+ alt = vb2_find_buffer(cap_q, run->vp9.frame->alt_frame_ts);
+
+ scnprintf(buf, buflen,
+ "last_ref_ts: %llu, vb2_idx: %d\n"
+ "golden_ref_ts: %llu, vb2_idx: %d\n"
+ "alt_ref_ts: %llu, vb2_idx: %d\n",
+ run->vp9.frame->last_frame_ts,
+ last ? last->index : -1,
+ run->vp9.frame->golden_frame_ts,
+ golden ? golden->index : -1,
+ run->vp9.frame->alt_frame_ts,
+ alt ? alt->index : -1);
+ break;
+ }
+
+ case VISL_CODEC_H264: {
+ char entry[] = "dpb[%d]:%u, vb2_index: %d\n";
+ struct vb2_buffer *vb2_buf;
+
+ for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++) {
+ vb2_buf = vb2_find_buffer(cap_q, run->h264.dpram->dpb[i].reference_ts);
+ len = scnprintf(buf, buflen, entry, i,
+ run->h264.dpram->dpb[i].reference_ts,
+ vb2_buf ? vb2_buf->index : -1);
+ buf += len;
+ buflen -= len;
+ }
+
+ break;
+ }
+
+ case VISL_CODEC_HEVC: {
+ char entry[] = "dpb[%d]:%u, vb2_index: %d\n";
+ struct vb2_buffer *vb2_buf;
+
+ for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++) {
+ vb2_buf = vb2_find_buffer(cap_q, run->hevc.dpram->dpb[i].timestamp);
+ len = scnprintf(buf, buflen, entry, i,
+ run->hevc.dpram->dpb[i].timestamp,
+ vb2_buf ? vb2_buf->index : -1);
+ buf += len;
+ buflen -= len;
+ }
+
+ break;
+ }
+ }
+}
+
+static char *visl_get_vb2_state(enum vb2_buffer_state state)
+{
+ switch (state) {
+ case VB2_BUF_STATE_DEQUEUED:
+ return "Dequeued";
+ case VB2_BUF_STATE_IN_REQUEST:
+ return "In request";
+ case VB2_BUF_STATE_PREPARING:
+ return "Preparing";
+ case VB2_BUF_STATE_QUEUED:
+ return "Queued";
+ case VB2_BUF_STATE_ACTIVE:
+ return "Active";
+ case VB2_BUF_STATE_DONE:
+ return "Done";
+ case VB2_BUF_STATE_ERROR:
+ return "Error";
+ default:
+ return "";
+ }
+}
+
+static int visl_fill_bytesused(struct vb2_v4l2_buffer *v4l2_vb2_buf, char *buf, size_t bufsz)
+{
+ int len = 0;
+ u32 i;
+
+ for (i = 0; i < v4l2_vb2_buf->vb2_buf.num_planes; i++)
+ len += scnprintf(buf, bufsz,
+ "bytesused[%u]: %u length[%u]: %u data_offset[%u]: %u",
+ i, v4l2_vb2_buf->planes[i].bytesused,
+ i, v4l2_vb2_buf->planes[i].length,
+ i, v4l2_vb2_buf->planes[i].data_offset);
+
+ return len;
+}
+
+static void visl_tpg_fill_sequence(struct visl_ctx *ctx,
+ struct visl_run *run, char buf[], size_t bufsz)
+{
+ u32 stream_ms;
+
+ stream_ms = jiffies_to_msecs(get_jiffies_64() - ctx->capture_streamon_jiffies);
+
+ scnprintf(buf, bufsz,
+ "stream time: %02d:%02d:%02d:%03d sequence:%u timestamp:%lld field:%s",
+ (stream_ms / (60 * 60 * 1000)) % 24,
+ (stream_ms / (60 * 1000)) % 60,
+ (stream_ms / 1000) % 60,
+ stream_ms % 1000,
+ run->dst->sequence,
+ run->dst->vb2_buf.timestamp,
+ (run->dst->field == V4L2_FIELD_ALTERNATE) ?
+ (run->dst->field == V4L2_FIELD_TOP ?
+ " top" : " bottom") : "none");
+}
+
+static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
+{
+ u8 *basep[TPG_MAX_PLANES][2];
+ char *buf = ctx->tpg_str_buf;
+ char *tmp = buf;
+ char *line_str;
+ u32 line = 1;
+ const u32 line_height = 16;
+ u32 len;
+ struct vb2_queue *out_q = &ctx->fh.m2m_ctx->out_q_ctx.q;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct v4l2_pix_format_mplane *coded_fmt = &ctx->coded_fmt.fmt.pix_mp;
+ struct v4l2_pix_format_mplane *decoded_fmt = &ctx->decoded_fmt.fmt.pix_mp;
+ u32 p;
+ u32 i;
+
+ for (p = 0; p < tpg_g_planes(&ctx->tpg); p++) {
+ void *vbuf = plane_vaddr(&ctx->tpg,
+ &run->dst->vb2_buf, p,
+ ctx->tpg.bytesperline,
+ ctx->tpg.buf_height);
+
+ tpg_calc_text_basep(&ctx->tpg, basep, p, vbuf);
+ tpg_fill_plane_buffer(&ctx->tpg, 0, p, vbuf);
+ }
+
+ visl_tpg_fill_sequence(ctx, run, buf, TPG_STR_BUF_SZ);
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "");
+ line++;
+
+ visl_get_ref_frames(ctx, buf, TPG_STR_BUF_SZ, run);
+
+ while ((line_str = strsep(&tmp, "\n")) && strlen(line_str)) {
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, line_str);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", line_str);
+ }
+
+ frame_dprintk(ctx->dev, run->dst->sequence, "");
+ line++;
+
+ scnprintf(buf,
+ TPG_STR_BUF_SZ,
+ "OUTPUT pixelformat: %c%c%c%c, resolution: %dx%d, num_planes: %d",
+ coded_fmt->pixelformat,
+ (coded_fmt->pixelformat >> 8) & 0xff,
+ (coded_fmt->pixelformat >> 16) & 0xff,
+ (coded_fmt->pixelformat >> 24) & 0xff,
+ coded_fmt->width,
+ coded_fmt->height,
+ coded_fmt->num_planes);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+
+ for (i = 0; i < coded_fmt->num_planes; i++) {
+ scnprintf(buf,
+ TPG_STR_BUF_SZ,
+ "plane[%d]: bytesperline: %d, sizeimage: %d",
+ i,
+ coded_fmt->plane_fmt[i].bytesperline,
+ coded_fmt->plane_fmt[i].sizeimage);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+ }
+
+ line++;
+ frame_dprintk(ctx->dev, run->dst->sequence, "");
+ scnprintf(buf, TPG_STR_BUF_SZ, "Output queue status:");
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+
+ len = 0;
+ for (i = 0; i < out_q->num_buffers; i++) {
+ char entry[] = "index: %u, state: %s, request_fd: %d, ";
+ u32 old_len = len;
+ char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
+
+ len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
+ entry, i, q_status,
+ to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
+
+ len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
+ &buf[len],
+ TPG_STR_BUF_SZ - len);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
+ }
+
+ line++;
+ frame_dprintk(ctx->dev, run->dst->sequence, "");
+
+ scnprintf(buf,
+ TPG_STR_BUF_SZ,
+ "CAPTURE pixelformat: %c%c%c%c, resolution: %dx%d, num_planes: %d",
+ decoded_fmt->pixelformat,
+ (decoded_fmt->pixelformat >> 8) & 0xff,
+ (decoded_fmt->pixelformat >> 16) & 0xff,
+ (decoded_fmt->pixelformat >> 24) & 0xff,
+ decoded_fmt->width,
+ decoded_fmt->height,
+ decoded_fmt->num_planes);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+
+ for (i = 0; i < decoded_fmt->num_planes; i++) {
+ scnprintf(buf,
+ TPG_STR_BUF_SZ,
+ "plane[%d]: bytesperline: %d, sizeimage: %d",
+ i,
+ decoded_fmt->plane_fmt[i].bytesperline,
+ decoded_fmt->plane_fmt[i].sizeimage);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+ }
+
+ line++;
+ frame_dprintk(ctx->dev, run->dst->sequence, "");
+ scnprintf(buf, TPG_STR_BUF_SZ, "Capture queue status:");
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
+
+ len = 0;
+ for (i = 0; i < cap_q->num_buffers; i++) {
+ u32 old_len = len;
+ char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
+
+ len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
+ "index: %u, status: %s, timestamp: %llu, is_held: %d",
+ cap_q->bufs[i]->index, q_status,
+ cap_q->bufs[i]->timestamp,
+ to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
+
+ tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
+ frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
+ }
+}
+
+static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
+{
+ int i;
+
+ switch (ctx->current_codec) {
+ default:
+ case VISL_CODEC_NONE:
+ break;
+ case VISL_CODEC_FWHT:
+ trace_v4l2_ctrl_fwht_params(run->fwht.params);
+ break;
+ case VISL_CODEC_MPEG2:
+ trace_v4l2_ctrl_mpeg2_sequence(run->mpeg2.seq);
+ trace_v4l2_ctrl_mpeg2_picture(run->mpeg2.pic);
+ trace_v4l2_ctrl_mpeg2_quantisation(run->mpeg2.quant);
+ break;
+ case VISL_CODEC_VP8:
+ trace_v4l2_ctrl_vp8_frame(run->vp8.frame);
+ trace_v4l2_ctrl_vp8_entropy(run->vp8.frame);
+ break;
+ case VISL_CODEC_VP9:
+ trace_v4l2_ctrl_vp9_frame(run->vp9.frame);
+ trace_v4l2_ctrl_vp9_compressed_hdr(run->vp9.probs);
+ trace_v4l2_ctrl_vp9_compressed_coeff(run->vp9.probs);
+ trace_v4l2_vp9_mv_probs(&run->vp9.probs->mv);
+ break;
+ case VISL_CODEC_H264:
+ trace_v4l2_ctrl_h264_sps(run->h264.sps);
+ trace_v4l2_ctrl_h264_pps(run->h264.pps);
+ trace_v4l2_ctrl_h264_scaling_matrix(run->h264.sm);
+ trace_v4l2_ctrl_h264_slice_params(run->h264.spram);
+
+ for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
+ trace_v4l2_h264_ref_pic_list0(&run->h264.spram->ref_pic_list0[i], i);
+ for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
+ trace_v4l2_h264_ref_pic_list1(&run->h264.spram->ref_pic_list1[i], i);
+
+ trace_v4l2_ctrl_h264_decode_params(run->h264.dpram);
+
+ for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++)
+ trace_v4l2_h264_dpb_entry(&run->h264.dpram->dpb[i], i);
+
+ trace_v4l2_ctrl_h264_pred_weights(run->h264.pwht);
+ break;
+ case VISL_CODEC_HEVC:
+ trace_v4l2_ctrl_hevc_sps(run->hevc.sps);
+ trace_v4l2_ctrl_hevc_pps(run->hevc.pps);
+ trace_v4l2_ctrl_hevc_slice_params(run->hevc.spram);
+ trace_v4l2_ctrl_hevc_scaling_matrix(run->hevc.sm);
+ trace_v4l2_ctrl_hevc_decode_params(run->hevc.dpram);
+
+ for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++)
+ trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);
+
+ trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table);
+ break;
+ }
+}
+
+void visl_device_run(void *priv)
+{
+ struct visl_ctx *ctx = priv;
+ struct visl_run run = {};
+ struct media_request *src_req;
+
+ run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ /* Apply request(s) controls if needed. */
+ src_req = run.src->vb2_buf.req_obj.req;
+
+ if (src_req)
+ v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+
+ v4l2_m2m_buf_copy_metadata(run.src, run.dst, true);
+ run.dst->sequence = ctx->q_data[V4L2_M2M_DST].sequence++;
+ run.src->sequence = ctx->q_data[V4L2_M2M_SRC].sequence++;
+ run.dst->field = ctx->decoded_fmt.fmt.pix.field;
+
+ switch (ctx->current_codec) {
+ default:
+ case VISL_CODEC_NONE:
+ break;
+ case VISL_CODEC_FWHT:
+ run.fwht.params = visl_find_control_data(ctx, V4L2_CID_STATELESS_FWHT_PARAMS);
+ break;
+ case VISL_CODEC_MPEG2:
+ run.mpeg2.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+ run.mpeg2.pic = visl_find_control_data(ctx, V4L2_CID_STATELESS_MPEG2_PICTURE);
+ run.mpeg2.quant = visl_find_control_data(ctx,
+ V4L2_CID_STATELESS_MPEG2_QUANTISATION);
+ break;
+ case VISL_CODEC_VP8:
+ run.vp8.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP8_FRAME);
+ break;
+ case VISL_CODEC_VP9:
+ run.vp9.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP9_FRAME);
+ run.vp9.probs = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP9_COMPRESSED_HDR);
+ break;
+ case VISL_CODEC_H264:
+ run.h264.sps = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SPS);
+ run.h264.pps = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_PPS);
+ run.h264.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX);
+ run.h264.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SLICE_PARAMS);
+ run.h264.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+ run.h264.pwht = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_PRED_WEIGHTS);
+ break;
+ case VISL_CODEC_HEVC:
+ run.hevc.sps = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS);
+ run.hevc.pps = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_PPS);
+ run.hevc.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
+ run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+ run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+ break;
+ }
+
+ frame_dprintk(ctx->dev, run.dst->sequence,
+ "Got OUTPUT buffer sequence %d, timestamp %llu\n",
+ run.src->sequence, run.src->vb2_buf.timestamp);
+
+ frame_dprintk(ctx->dev, run.dst->sequence,
+ "Got CAPTURE buffer sequence %d, timestamp %llu\n",
+ run.dst->sequence, run.dst->vb2_buf.timestamp);
+
+ visl_tpg_fill(ctx, &run);
+ visl_trace_ctrls(ctx, &run);
+
+ if (bitstream_trace_frame_start > -1 &&
+ run.dst->sequence >= bitstream_trace_frame_start &&
+ run.dst->sequence < bitstream_trace_frame_start + bitstream_trace_nframes)
+ visl_trace_bitstream(ctx, &run);
+
+ /* Complete request(s) controls if needed. */
+ if (src_req)
+ v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
+ if (visl_transtime_ms)
+ usleep_range(visl_transtime_ms * 1000, 2 * visl_transtime_ms * 1000);
+
+ v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
+ ctx->fh.m2m_ctx, VB2_BUF_STATE_DONE);
+}
diff --git a/drivers/media/test-drivers/visl/visl-dec.h b/drivers/media/test-drivers/visl/visl-dec.h
new file mode 100644
index 000000000000..4a706a9de02e
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-dec.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Contains the virtual decoder logic. The functions here control the
+ * tracing/TPG on a per-frame basis
+ */
+
+#ifndef _VISL_DEC_H_
+#define _VISL_DEC_H_
+
+#include "visl.h"
+
+struct visl_fwht_run {
+ const struct v4l2_ctrl_fwht_params *params;
+};
+
+struct visl_mpeg2_run {
+ const struct v4l2_ctrl_mpeg2_sequence *seq;
+ const struct v4l2_ctrl_mpeg2_picture *pic;
+ const struct v4l2_ctrl_mpeg2_quantisation *quant;
+};
+
+struct visl_vp8_run {
+ const struct v4l2_ctrl_vp8_frame *frame;
+};
+
+struct visl_vp9_run {
+ const struct v4l2_ctrl_vp9_frame *frame;
+ const struct v4l2_ctrl_vp9_compressed_hdr *probs;
+};
+
+struct visl_h264_run {
+ const struct v4l2_ctrl_h264_sps *sps;
+ const struct v4l2_ctrl_h264_pps *pps;
+ const struct v4l2_ctrl_h264_scaling_matrix *sm;
+ const struct v4l2_ctrl_h264_slice_params *spram;
+ const struct v4l2_ctrl_h264_decode_params *dpram;
+ const struct v4l2_ctrl_h264_pred_weights *pwht;
+};
+
+struct visl_hevc_run {
+ const struct v4l2_ctrl_hevc_sps *sps;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ const struct v4l2_ctrl_hevc_slice_params *spram;
+ const struct v4l2_ctrl_hevc_scaling_matrix *sm;
+ const struct v4l2_ctrl_hevc_decode_params *dpram;
+};
+
+struct visl_run {
+ struct vb2_v4l2_buffer *src;
+ struct vb2_v4l2_buffer *dst;
+
+ union {
+ struct visl_fwht_run fwht;
+ struct visl_mpeg2_run mpeg2;
+ struct visl_vp8_run vp8;
+ struct visl_vp9_run vp9;
+ struct visl_h264_run h264;
+ struct visl_hevc_run hevc;
+ };
+};
+
+int visl_dec_start(struct visl_ctx *ctx);
+int visl_dec_stop(struct visl_ctx *ctx);
+int visl_job_ready(void *priv);
+void visl_device_run(void *priv);
+
+#endif /* _VISL_DEC_H_ */
diff --git a/drivers/media/test-drivers/visl/visl-trace-fwht.h b/drivers/media/test-drivers/visl/visl-trace-fwht.h
new file mode 100644
index 000000000000..54b119359ff5
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-fwht.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_FWHT_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_FWHT_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_fwht_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(
+ __field(u64, backward_ref_ts)
+ __field(u32, version)
+ __field(u32, width)
+ __field(u32, height)
+ __field(u32, flags)
+ __field(u32, colorspace)
+ __field(u32, xfer_func)
+ __field(u32, ycbcr_enc)
+ __field(u32, quantization)
+ ),
+ TP_fast_assign(
+ __entry->backward_ref_ts = p->backward_ref_ts;
+ __entry->version = p->version;
+ __entry->width = p->width;
+ __entry->height = p->height;
+ __entry->flags = p->flags;
+ __entry->colorspace = p->colorspace;
+ __entry->xfer_func = p->xfer_func;
+ __entry->ycbcr_enc = p->ycbcr_enc;
+ __entry->quantization = p->quantization;
+ ),
+ TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u xfer_func %u ycbcr_enc %u quantization %u",
+ __entry->backward_ref_ts, __entry->version, __entry->width, __entry->height,
+ __print_flags(__entry->flags, "|",
+ {V4L2_FWHT_FL_IS_INTERLACED, "IS_INTERLACED"},
+ {V4L2_FWHT_FL_IS_BOTTOM_FIRST, "IS_BOTTOM_FIRST"},
+ {V4L2_FWHT_FL_IS_ALTERNATE, "IS_ALTERNATE"},
+ {V4L2_FWHT_FL_IS_BOTTOM_FIELD, "IS_BOTTOM_FIELD"},
+ {V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED, "LUMA_IS_UNCOMPRESSED"},
+ {V4L2_FWHT_FL_CB_IS_UNCOMPRESSED, "CB_IS_UNCOMPRESSED"},
+ {V4L2_FWHT_FL_CR_IS_UNCOMPRESSED, "CR_IS_UNCOMPRESSED"},
+ {V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED, "ALPHA_IS_UNCOMPRESSED"},
+ {V4L2_FWHT_FL_I_FRAME, "I_FRAME"},
+ {V4L2_FWHT_FL_PIXENC_HSV, "PIXENC_HSV"},
+ {V4L2_FWHT_FL_PIXENC_RGB, "PIXENC_RGB"},
+ {V4L2_FWHT_FL_PIXENC_YUV, "PIXENC_YUV"}),
+ __entry->colorspace, __entry->xfer_func, __entry->ycbcr_enc,
+ __entry->quantization)
+);
+
+DEFINE_EVENT(v4l2_ctrl_fwht_params_tmpl, v4l2_ctrl_fwht_params,
+ TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
+ TP_ARGS(p)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-fwht
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-h264.h b/drivers/media/test-drivers/visl/visl-trace-h264.h
new file mode 100644
index 000000000000..d84296a01deb
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-h264.h
@@ -0,0 +1,349 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_H264_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_H264_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_h264_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_sps, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nprofile_idc %u\n"
+ "constraint_set_flags %s\n"
+ "level_idc %u\n"
+ "seq_parameter_set_id %u\n"
+ "chroma_format_idc %u\n"
+ "bit_depth_luma_minus8 %u\n"
+ "bit_depth_chroma_minus8 %u\n"
+ "log2_max_frame_num_minus4 %u\n"
+ "pic_order_cnt_type %u\n"
+ "log2_max_pic_order_cnt_lsb_minus4 %u\n"
+ "max_num_ref_frames %u\n"
+ "num_ref_frames_in_pic_order_cnt_cycle %u\n"
+ "offset_for_ref_frame %s\n"
+ "offset_for_non_ref_pic %d\n"
+ "offset_for_top_to_bottom_field %d\n"
+ "pic_width_in_mbs_minus1 %u\n"
+ "pic_height_in_map_units_minus1 %u\n"
+ "flags %s",
+ __entry->s.profile_idc,
+ __print_flags(__entry->s.constraint_set_flags, "|",
+ {V4L2_H264_SPS_CONSTRAINT_SET0_FLAG, "CONSTRAINT_SET0_FLAG"},
+ {V4L2_H264_SPS_CONSTRAINT_SET1_FLAG, "CONSTRAINT_SET1_FLAG"},
+ {V4L2_H264_SPS_CONSTRAINT_SET2_FLAG, "CONSTRAINT_SET2_FLAG"},
+ {V4L2_H264_SPS_CONSTRAINT_SET3_FLAG, "CONSTRAINT_SET3_FLAG"},
+ {V4L2_H264_SPS_CONSTRAINT_SET4_FLAG, "CONSTRAINT_SET4_FLAG"},
+ {V4L2_H264_SPS_CONSTRAINT_SET5_FLAG, "CONSTRAINT_SET5_FLAG"}),
+ __entry->s.level_idc,
+ __entry->s.seq_parameter_set_id,
+ __entry->s.chroma_format_idc,
+ __entry->s.bit_depth_luma_minus8,
+ __entry->s.bit_depth_chroma_minus8,
+ __entry->s.log2_max_frame_num_minus4,
+ __entry->s.pic_order_cnt_type,
+ __entry->s.log2_max_pic_order_cnt_lsb_minus4,
+ __entry->s.max_num_ref_frames,
+ __entry->s.num_ref_frames_in_pic_order_cnt_cycle,
+ __print_array(__entry->s.offset_for_ref_frame,
+ ARRAY_SIZE(__entry->s.offset_for_ref_frame),
+ sizeof(__entry->s.offset_for_ref_frame[0])),
+ __entry->s.offset_for_non_ref_pic,
+ __entry->s.offset_for_top_to_bottom_field,
+ __entry->s.pic_width_in_mbs_minus1,
+ __entry->s.pic_height_in_map_units_minus1,
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
+ {V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS, "QPPRIME_Y_ZERO_TRANSFORM_BYPASS"},
+ {V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO, "DELTA_PIC_ORDER_ALWAYS_ZERO"},
+ {V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED, "GAPS_IN_FRAME_NUM_VALUE_ALLOWED"},
+ {V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY, "FRAME_MBS_ONLY"},
+ {V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD, "MB_ADAPTIVE_FRAME_FIELD"},
+ {V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE, "DIRECT_8X8_INFERENCE"}
+ ))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pps, p)),
+ TP_fast_assign(__entry->p = *p),
+ TP_printk("\npic_parameter_set_id %u\n"
+ "seq_parameter_set_id %u\n"
+ "num_slice_groups_minus1 %u\n"
+ "num_ref_idx_l0_default_active_minus1 %u\n"
+ "num_ref_idx_l1_default_active_minus1 %u\n"
+ "weighted_bipred_idc %u\n"
+ "pic_init_qp_minus26 %d\n"
+ "pic_init_qs_minus26 %d\n"
+ "chroma_qp_index_offset %d\n"
+ "second_chroma_qp_index_offset %d\n"
+ "flags %s",
+ __entry->p.pic_parameter_set_id,
+ __entry->p.seq_parameter_set_id,
+ __entry->p.num_slice_groups_minus1,
+ __entry->p.num_ref_idx_l0_default_active_minus1,
+ __entry->p.num_ref_idx_l1_default_active_minus1,
+ __entry->p.weighted_bipred_idc,
+ __entry->p.pic_init_qp_minus26,
+ __entry->p.pic_init_qs_minus26,
+ __entry->p.chroma_qp_index_offset,
+ __entry->p.second_chroma_qp_index_offset,
+ __print_flags(__entry->p.flags, "|",
+ {V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE, "ENTROPY_CODING_MODE"},
+ {V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT, "BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT"},
+ {V4L2_H264_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
+ {V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+ {V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
+ {V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT, "REDUNDANT_PIC_CNT_PRESENT"},
+ {V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE, "TRANSFORM_8X8_MODE"},
+ {V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT, "SCALING_MATRIX_PRESENT"}
+ ))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_scaling_matrix, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_4x4,
+ sizeof(__entry->s.scaling_list_4x4),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_8x8,
+ sizeof(__entry->s.scaling_list_8x8),
+ false)
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pred_weights, p)),
+ TP_fast_assign(__entry->p = *p),
+ TP_printk("\nluma_log2_weight_denom %u\n"
+ "chroma_log2_weight_denom %u\n"
+ "weight_factor[0].luma_weight %s\n"
+ "weight_factor[0].luma_offset %s\n"
+ "weight_factor[0].chroma_weight {%s}\n"
+ "weight_factor[0].chroma_offset {%s}\n"
+ "weight_factor[1].luma_weight %s\n"
+ "weight_factor[1].luma_offset %s\n"
+ "weight_factor[1].chroma_weight {%s}\n"
+ "weight_factor[1].chroma_offset {%s}\n",
+ __entry->p.luma_log2_weight_denom,
+ __entry->p.chroma_log2_weight_denom,
+ __print_array(__entry->p.weight_factors[0].luma_weight,
+ ARRAY_SIZE(__entry->p.weight_factors[0].luma_weight),
+ sizeof(__entry->p.weight_factors[0].luma_weight[0])),
+ __print_array(__entry->p.weight_factors[0].luma_offset,
+ ARRAY_SIZE(__entry->p.weight_factors[0].luma_offset),
+ sizeof(__entry->p.weight_factors[0].luma_offset[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.weight_factors[0].chroma_weight,
+ sizeof(__entry->p.weight_factors[0].chroma_weight),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.weight_factors[0].chroma_offset,
+ sizeof(__entry->p.weight_factors[0].chroma_offset),
+ false),
+ __print_array(__entry->p.weight_factors[1].luma_weight,
+ ARRAY_SIZE(__entry->p.weight_factors[1].luma_weight),
+ sizeof(__entry->p.weight_factors[1].luma_weight[0])),
+ __print_array(__entry->p.weight_factors[1].luma_offset,
+ ARRAY_SIZE(__entry->p.weight_factors[1].luma_offset),
+ sizeof(__entry->p.weight_factors[1].luma_offset[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.weight_factors[1].chroma_weight,
+ sizeof(__entry->p.weight_factors[1].chroma_weight),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.weight_factors[1].chroma_offset,
+ sizeof(__entry->p.weight_factors[1].chroma_offset),
+ false)
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_slice_params, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nheader_bit_size %u\n"
+ "first_mb_in_slice %u\n"
+ "slice_type %s\n"
+ "colour_plane_id %u\n"
+ "redundant_pic_cnt %u\n"
+ "cabac_init_idc %u\n"
+ "slice_qp_delta %d\n"
+ "slice_qs_delta %d\n"
+ "disable_deblocking_filter_idc %u\n"
+ "slice_alpha_c0_offset_div2 %u\n"
+ "slice_beta_offset_div2 %u\n"
+ "num_ref_idx_l0_active_minus1 %u\n"
+ "num_ref_idx_l1_active_minus1 %u\n"
+ "flags %s",
+ __entry->s.header_bit_size,
+ __entry->s.first_mb_in_slice,
+ __print_symbolic(__entry->s.slice_type,
+ {V4L2_H264_SLICE_TYPE_P, "P"},
+ {V4L2_H264_SLICE_TYPE_B, "B"},
+ {V4L2_H264_SLICE_TYPE_I, "I"},
+ {V4L2_H264_SLICE_TYPE_SP, "SP"},
+ {V4L2_H264_SLICE_TYPE_SI, "SI"}),
+ __entry->s.colour_plane_id,
+ __entry->s.redundant_pic_cnt,
+ __entry->s.cabac_init_idc,
+ __entry->s.slice_qp_delta,
+ __entry->s.slice_qs_delta,
+ __entry->s.disable_deblocking_filter_idc,
+ __entry->s.slice_alpha_c0_offset_div2,
+ __entry->s.slice_beta_offset_div2,
+ __entry->s.num_ref_idx_l0_active_minus1,
+ __entry->s.num_ref_idx_l1_active_minus1,
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED, "DIRECT_SPATIAL_MV_PRED"},
+ {V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH, "SP_FOR_SWITCH"})
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
+ TP_PROTO(const struct v4l2_h264_reference *r, int i),
+ TP_ARGS(r, i),
+ TP_STRUCT__entry(__field_struct(struct v4l2_h264_reference, r)
+ __field(int, i)),
+ TP_fast_assign(__entry->r = *r; __entry->i = i;),
+ TP_printk("[%d]: fields %s index %u",
+ __entry->i,
+ __print_flags(__entry->r.fields, "|",
+ {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
+ {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
+ {V4L2_H264_FRAME_REF, "FRAME_REF"}),
+ __entry->r.index
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
+ TP_ARGS(d),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_decode_params, d)),
+ TP_fast_assign(__entry->d = *d),
+ TP_printk("\nnal_ref_idc %u\n"
+ "frame_num %u\n"
+ "top_field_order_cnt %d\n"
+ "bottom_field_order_cnt %d\n"
+ "idr_pic_id %u\n"
+ "pic_order_cnt_lsb %u\n"
+ "delta_pic_order_cnt_bottom %d\n"
+ "delta_pic_order_cnt0 %d\n"
+ "delta_pic_order_cnt1 %d\n"
+ "dec_ref_pic_marking_bit_size %u\n"
+ "pic_order_cnt_bit_size %u\n"
+ "slice_group_change_cycle %u\n"
+ "flags %s\n",
+ __entry->d.nal_ref_idc,
+ __entry->d.frame_num,
+ __entry->d.top_field_order_cnt,
+ __entry->d.bottom_field_order_cnt,
+ __entry->d.idr_pic_id,
+ __entry->d.pic_order_cnt_lsb,
+ __entry->d.delta_pic_order_cnt_bottom,
+ __entry->d.delta_pic_order_cnt0,
+ __entry->d.delta_pic_order_cnt1,
+ __entry->d.dec_ref_pic_marking_bit_size,
+ __entry->d.pic_order_cnt_bit_size,
+ __entry->d.slice_group_change_cycle,
+ __print_flags(__entry->d.flags, "|",
+ {V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
+ {V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC, "FIELD_PIC"},
+ {V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD, "BOTTOM_FIELD"},
+ {V4L2_H264_DECODE_PARAM_FLAG_PFRAME, "PFRAME"},
+ {V4L2_H264_DECODE_PARAM_FLAG_BFRAME, "BFRAME"})
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
+ TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
+ TP_ARGS(e, i),
+ TP_STRUCT__entry(__field_struct(struct v4l2_h264_dpb_entry, e)
+ __field(int, i)),
+ TP_fast_assign(__entry->e = *e; __entry->i = i;),
+ TP_printk("[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
+ "top_field_order_cnt %d bottom_field_order_cnt %d flags %s",
+ __entry->i,
+ __entry->e.reference_ts,
+ __entry->e.pic_num,
+ __entry->e.frame_num,
+ __print_flags(__entry->e.fields, "|",
+ {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
+ {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
+ {V4L2_H264_FRAME_REF, "FRAME_REF"}),
+ __entry->e.top_field_order_cnt,
+ __entry->e.bottom_field_order_cnt,
+ __print_flags(__entry->e.flags, "|",
+ {V4L2_H264_DPB_ENTRY_FLAG_VALID, "VALID"},
+ {V4L2_H264_DPB_ENTRY_FLAG_ACTIVE, "ACTIVE"},
+ {V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM, "LONG_TERM"},
+ {V4L2_H264_DPB_ENTRY_FLAG_FIELD, "FIELD"})
+
+ )
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_sps_tmpl, v4l2_ctrl_h264_sps,
+ TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_pps_tmpl, v4l2_ctrl_h264_pps,
+ TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
+ TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_scaling_matrix_tmpl, v4l2_ctrl_h264_scaling_matrix,
+ TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_pred_weights_tmpl, v4l2_ctrl_h264_pred_weights,
+ TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
+ TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_slice_params_tmpl, v4l2_ctrl_h264_slice_params,
+ TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list0,
+ TP_PROTO(const struct v4l2_h264_reference *r, int i),
+ TP_ARGS(r, i)
+);
+
+DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list1,
+ TP_PROTO(const struct v4l2_h264_reference *r, int i),
+ TP_ARGS(r, i)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_decode_params_tmpl, v4l2_ctrl_h264_decode_params,
+ TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
+ TP_ARGS(d)
+);
+
+DEFINE_EVENT(v4l2_h264_dpb_entry_tmpl, v4l2_h264_dpb_entry,
+ TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
+ TP_ARGS(e, i)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-h264
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-hevc.h b/drivers/media/test-drivers/visl/visl-trace-hevc.h
new file mode 100644
index 000000000000..837b8ec12e97
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-hevc.h
@@ -0,0 +1,405 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#if !defined(_VISL_TRACE_HEVC_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_HEVC_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_hevc_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_sps, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nvideo_parameter_set_id %u\n"
+ "seq_parameter_set_id %u\n"
+ "pic_width_in_luma_samples %u\n"
+ "pic_height_in_luma_samples %u\n"
+ "bit_depth_luma_minus8 %u\n"
+ "bit_depth_chroma_minus8 %u\n"
+ "log2_max_pic_order_cnt_lsb_minus4 %u\n"
+ "sps_max_dec_pic_buffering_minus1 %u\n"
+ "sps_max_num_reorder_pics %u\n"
+ "sps_max_latency_increase_plus1 %u\n"
+ "log2_min_luma_coding_block_size_minus3 %u\n"
+ "log2_diff_max_min_luma_coding_block_size %u\n"
+ "log2_min_luma_transform_block_size_minus2 %u\n"
+ "log2_diff_max_min_luma_transform_block_size %u\n"
+ "max_transform_hierarchy_depth_inter %u\n"
+ "max_transform_hierarchy_depth_intra %u\n"
+ "pcm_sample_bit_depth_luma_minus1 %u\n"
+ "pcm_sample_bit_depth_chroma_minus1 %u\n"
+ "log2_min_pcm_luma_coding_block_size_minus3 %u\n"
+ "log2_diff_max_min_pcm_luma_coding_block_size %u\n"
+ "num_short_term_ref_pic_sets %u\n"
+ "num_long_term_ref_pics_sps %u\n"
+ "chroma_format_idc %u\n"
+ "sps_max_sub_layers_minus1 %u\n"
+ "flags %s",
+ __entry->s.video_parameter_set_id,
+ __entry->s.seq_parameter_set_id,
+ __entry->s.pic_width_in_luma_samples,
+ __entry->s.pic_height_in_luma_samples,
+ __entry->s.bit_depth_luma_minus8,
+ __entry->s.bit_depth_chroma_minus8,
+ __entry->s.log2_max_pic_order_cnt_lsb_minus4,
+ __entry->s.sps_max_dec_pic_buffering_minus1,
+ __entry->s.sps_max_num_reorder_pics,
+ __entry->s.sps_max_latency_increase_plus1,
+ __entry->s.log2_min_luma_coding_block_size_minus3,
+ __entry->s.log2_diff_max_min_luma_coding_block_size,
+ __entry->s.log2_min_luma_transform_block_size_minus2,
+ __entry->s.log2_diff_max_min_luma_transform_block_size,
+ __entry->s.max_transform_hierarchy_depth_inter,
+ __entry->s.max_transform_hierarchy_depth_intra,
+ __entry->s.pcm_sample_bit_depth_luma_minus1,
+ __entry->s.pcm_sample_bit_depth_chroma_minus1,
+ __entry->s.log2_min_pcm_luma_coding_block_size_minus3,
+ __entry->s.log2_diff_max_min_pcm_luma_coding_block_size,
+ __entry->s.num_short_term_ref_pic_sets,
+ __entry->s.num_long_term_ref_pics_sps,
+ __entry->s.chroma_format_idc,
+ __entry->s.sps_max_sub_layers_minus1,
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
+ {V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED, "SCALING_LIST_ENABLED"},
+ {V4L2_HEVC_SPS_FLAG_AMP_ENABLED, "AMP_ENABLED"},
+ {V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET, "SAMPLE_ADAPTIVE_OFFSET"},
+ {V4L2_HEVC_SPS_FLAG_PCM_ENABLED, "PCM_ENABLED"},
+ {V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED, "V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED"},
+ {V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT, "LONG_TERM_REF_PICS_PRESENT"},
+ {V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED, "TEMPORAL_MVP_ENABLED"},
+ {V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED, "STRONG_INTRA_SMOOTHING_ENABLED"}
+ ))
+
+);
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_pps, p)),
+ TP_fast_assign(__entry->p = *p),
+ TP_printk("\npic_parameter_set_id %u\n"
+ "num_extra_slice_header_bits %u\n"
+ "num_ref_idx_l0_default_active_minus1 %u\n"
+ "num_ref_idx_l1_default_active_minus1 %u\n"
+ "init_qp_minus26 %d\n"
+ "diff_cu_qp_delta_depth %u\n"
+ "pps_cb_qp_offset %d\n"
+ "pps_cr_qp_offset %d\n"
+ "num_tile_columns_minus1 %d\n"
+ "num_tile_rows_minus1 %d\n"
+ "column_width_minus1 %s\n"
+ "row_height_minus1 %s\n"
+ "pps_beta_offset_div2 %d\n"
+ "pps_tc_offset_div2 %d\n"
+ "log2_parallel_merge_level_minus2 %u\n"
+ "flags %s",
+ __entry->p.pic_parameter_set_id,
+ __entry->p.num_extra_slice_header_bits,
+ __entry->p.num_ref_idx_l0_default_active_minus1,
+ __entry->p.num_ref_idx_l1_default_active_minus1,
+ __entry->p.init_qp_minus26,
+ __entry->p.diff_cu_qp_delta_depth,
+ __entry->p.pps_cb_qp_offset,
+ __entry->p.pps_cr_qp_offset,
+ __entry->p.num_tile_columns_minus1,
+ __entry->p.num_tile_rows_minus1,
+ __print_array(__entry->p.column_width_minus1,
+ ARRAY_SIZE(__entry->p.column_width_minus1),
+ sizeof(__entry->p.column_width_minus1[0])),
+ __print_array(__entry->p.row_height_minus1,
+ ARRAY_SIZE(__entry->p.row_height_minus1),
+ sizeof(__entry->p.row_height_minus1[0])),
+ __entry->p.pps_beta_offset_div2,
+ __entry->p.pps_tc_offset_div2,
+ __entry->p.log2_parallel_merge_level_minus2,
+ __print_flags(__entry->p.flags, "|",
+ {V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED, "DEPENDENT_SLICE_SEGMENT_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT, "OUTPUT_FLAG_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED, "SIGN_DATA_HIDING_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT, "CABAC_INIT_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
+ {V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED, "CU_QP_DELTA_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT, "PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
+ {V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED, "WEIGHTED_BIPRED"},
+ {V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, "TRANSQUANT_BYPASS_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_TILES_ENABLED, "TILES_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, "ENTROPY_CODING_SYNC_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, "LOOP_FILTER_ACROSS_TILES_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, "PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED, "DEBLOCKING_FILTER_OVERRIDE_ENABLED"},
+ {V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER, "DISABLE_DEBLOCKING_FILTER"},
+ {V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT, "LISTS_MODIFICATION_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT, "SLICE_SEGMENT_HEADER_EXTENSION_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+ {V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING, "UNIFORM_SPACING"}
+ ))
+
+);
+
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_slice_params, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nbit_size %u\n"
+ "data_byte_offset %u\n"
+ "num_entry_point_offsets %u\n"
+ "nal_unit_type %u\n"
+ "nuh_temporal_id_plus1 %u\n"
+ "slice_type %u\n"
+ "colour_plane_id %u\n"
+ "slice_pic_order_cnt %d\n"
+ "num_ref_idx_l0_active_minus1 %u\n"
+ "num_ref_idx_l1_active_minus1 %u\n"
+ "collocated_ref_idx %u\n"
+ "five_minus_max_num_merge_cand %u\n"
+ "slice_qp_delta %d\n"
+ "slice_cb_qp_offset %d\n"
+ "slice_cr_qp_offset %d\n"
+ "slice_act_y_qp_offset %d\n"
+ "slice_act_cb_qp_offset %d\n"
+ "slice_act_cr_qp_offset %d\n"
+ "slice_beta_offset_div2 %d\n"
+ "slice_tc_offset_div2 %d\n"
+ "pic_struct %u\n"
+ "slice_segment_addr %u\n"
+ "ref_idx_l0 %s\n"
+ "ref_idx_l1 %s\n"
+ "short_term_ref_pic_set_size %u\n"
+ "long_term_ref_pic_set_size %u\n"
+ "flags %s",
+ __entry->s.bit_size,
+ __entry->s.data_byte_offset,
+ __entry->s.num_entry_point_offsets,
+ __entry->s.nal_unit_type,
+ __entry->s.nuh_temporal_id_plus1,
+ __entry->s.slice_type,
+ __entry->s.colour_plane_id,
+ __entry->s.slice_pic_order_cnt,
+ __entry->s.num_ref_idx_l0_active_minus1,
+ __entry->s.num_ref_idx_l1_active_minus1,
+ __entry->s.collocated_ref_idx,
+ __entry->s.five_minus_max_num_merge_cand,
+ __entry->s.slice_qp_delta,
+ __entry->s.slice_cb_qp_offset,
+ __entry->s.slice_cr_qp_offset,
+ __entry->s.slice_act_y_qp_offset,
+ __entry->s.slice_act_cb_qp_offset,
+ __entry->s.slice_act_cr_qp_offset,
+ __entry->s.slice_beta_offset_div2,
+ __entry->s.slice_tc_offset_div2,
+ __entry->s.pic_struct,
+ __entry->s.slice_segment_addr,
+ __print_array(__entry->s.ref_idx_l0,
+ ARRAY_SIZE(__entry->s.ref_idx_l0),
+ sizeof(__entry->s.ref_idx_l0[0])),
+ __print_array(__entry->s.ref_idx_l1,
+ ARRAY_SIZE(__entry->s.ref_idx_l1),
+ sizeof(__entry->s.ref_idx_l1[0])),
+ __entry->s.short_term_ref_pic_set_size,
+ __entry->s.long_term_ref_pic_set_size,
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA, "SLICE_SAO_LUMA"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA, "SLICE_SAO_CHROMA"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED, "SLICE_TEMPORAL_MVP_ENABLED"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO, "MVD_L1_ZERO"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT, "CABAC_INIT"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0, "COLLOCATED_FROM_L0"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV, "USE_INTEGER_MV"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, "SLICE_DEBLOCKING_FILTER_DISABLED"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, "SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+ {V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, "DEPENDENT_SLICE_SEGMENT"}
+
+ ))
+);
+
+DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
+ TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_hevc_pred_weight_table, p)),
+ TP_fast_assign(__entry->p = *p),
+ TP_printk("\ndelta_luma_weight_l0 %s\n"
+ "luma_offset_l0 %s\n"
+ "delta_chroma_weight_l0 {%s}\n"
+ "chroma_offset_l0 {%s}\n"
+ "delta_luma_weight_l1 %s\n"
+ "luma_offset_l1 %s\n"
+ "delta_chroma_weight_l1 {%s}\n"
+ "chroma_offset_l1 {%s}\n"
+ "luma_log2_weight_denom %d\n"
+ "delta_chroma_log2_weight_denom %d\n",
+ __print_array(__entry->p.delta_luma_weight_l0,
+ ARRAY_SIZE(__entry->p.delta_luma_weight_l0),
+ sizeof(__entry->p.delta_luma_weight_l0[0])),
+ __print_array(__entry->p.luma_offset_l0,
+ ARRAY_SIZE(__entry->p.luma_offset_l0),
+ sizeof(__entry->p.luma_offset_l0[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.delta_chroma_weight_l0,
+ sizeof(__entry->p.delta_chroma_weight_l0),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.chroma_offset_l0,
+ sizeof(__entry->p.chroma_offset_l0),
+ false),
+ __print_array(__entry->p.delta_luma_weight_l1,
+ ARRAY_SIZE(__entry->p.delta_luma_weight_l1),
+ sizeof(__entry->p.delta_luma_weight_l1[0])),
+ __print_array(__entry->p.luma_offset_l1,
+ ARRAY_SIZE(__entry->p.luma_offset_l1),
+ sizeof(__entry->p.luma_offset_l1[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.delta_chroma_weight_l1,
+ sizeof(__entry->p.delta_chroma_weight_l1),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.chroma_offset_l1,
+ sizeof(__entry->p.chroma_offset_l1),
+ false),
+ __entry->p.luma_log2_weight_denom,
+ __entry->p.delta_chroma_log2_weight_denom
+
+ ))
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_scaling_matrix, s)),
+ TP_fast_assign(__entry->s = *s),
+ TP_printk("\nscaling_list_4x4 {%s}\n"
+ "scaling_list_8x8 {%s}\n"
+ "scaling_list_16x16 {%s}\n"
+ "scaling_list_32x32 {%s}\n"
+ "scaling_list_dc_coef_16x16 %s\n"
+ "scaling_list_dc_coef_32x32 %s\n",
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_4x4,
+ sizeof(__entry->s.scaling_list_4x4),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_8x8,
+ sizeof(__entry->s.scaling_list_8x8),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_16x16,
+ sizeof(__entry->s.scaling_list_16x16),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->s.scaling_list_32x32,
+ sizeof(__entry->s.scaling_list_32x32),
+ false),
+ __print_array(__entry->s.scaling_list_dc_coef_16x16,
+ ARRAY_SIZE(__entry->s.scaling_list_dc_coef_16x16),
+ sizeof(__entry->s.scaling_list_dc_coef_16x16[0])),
+ __print_array(__entry->s.scaling_list_dc_coef_32x32,
+ ARRAY_SIZE(__entry->s.scaling_list_dc_coef_32x32),
+ sizeof(__entry->s.scaling_list_dc_coef_32x32[0]))
+ ))
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
+ TP_ARGS(d),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_decode_params, d)),
+ TP_fast_assign(__entry->d = *d),
+ TP_printk("\npic_order_cnt_val %d\n"
+ "short_term_ref_pic_set_size %u\n"
+ "long_term_ref_pic_set_size %u\n"
+ "num_active_dpb_entries %u\n"
+ "num_poc_st_curr_before %u\n"
+ "num_poc_st_curr_after %u\n"
+ "num_poc_lt_curr %u\n"
+ "poc_st_curr_before %s\n"
+ "poc_st_curr_after %s\n"
+ "poc_lt_curr %s\n"
+ "flags %s",
+ __entry->d.pic_order_cnt_val,
+ __entry->d.short_term_ref_pic_set_size,
+ __entry->d.long_term_ref_pic_set_size,
+ __entry->d.num_active_dpb_entries,
+ __entry->d.num_poc_st_curr_before,
+ __entry->d.num_poc_st_curr_after,
+ __entry->d.num_poc_lt_curr,
+ __print_array(__entry->d.poc_st_curr_before,
+ ARRAY_SIZE(__entry->d.poc_st_curr_before),
+ sizeof(__entry->d.poc_st_curr_before[0])),
+ __print_array(__entry->d.poc_st_curr_after,
+ ARRAY_SIZE(__entry->d.poc_st_curr_after),
+ sizeof(__entry->d.poc_st_curr_after[0])),
+ __print_array(__entry->d.poc_lt_curr,
+ ARRAY_SIZE(__entry->d.poc_lt_curr),
+ sizeof(__entry->d.poc_lt_curr[0])),
+ __print_flags(__entry->d.flags, "|",
+ {V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC, "IRAP_PIC"},
+ {V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
+ {V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR, "NO_OUTPUT_OF_PRIOR"}
+ ))
+);
+
+
+DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
+ TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
+ TP_ARGS(e),
+ TP_STRUCT__entry(__field_struct(struct v4l2_hevc_dpb_entry, e)),
+ TP_fast_assign(__entry->e = *e),
+ TP_printk("\ntimestamp %llu\n"
+ "flags %s\n"
+ "field_pic %u\n"
+ "pic_order_cnt_val %d\n",
+ __entry->e.timestamp,
+ __print_flags(__entry->e.flags, "|",
+ {V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE, "LONG_TERM_REFERENCE"}
+ ),
+ __entry->e.field_pic,
+ __entry->e.pic_order_cnt_val
+ ))
+
+DEFINE_EVENT(v4l2_ctrl_hevc_sps_tmpl, v4l2_ctrl_hevc_sps,
+ TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_pps_tmpl, v4l2_ctrl_hevc_pps,
+ TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
+ TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_slice_params_tmpl, v4l2_ctrl_hevc_slice_params,
+ TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_hevc_pred_weight_table_tmpl, v4l2_hevc_pred_weight_table,
+ TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
+ TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_scaling_matrix_tmpl, v4l2_ctrl_hevc_scaling_matrix,
+ TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
+ TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
+ TP_ARGS(d)
+);
+
+DEFINE_EVENT(v4l2_hevc_dpb_entry_tmpl, v4l2_hevc_dpb_entry,
+ TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
+ TP_ARGS(e)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-hevc
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-mpeg2.h b/drivers/media/test-drivers/visl/visl-trace-mpeg2.h
new file mode 100644
index 000000000000..ba6c65481194
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-mpeg2.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_MPEG2_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_MPEG2_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_mpeg2_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_sequence, s)),
+ TP_fast_assign(__entry->s = *s;),
+ TP_printk("\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
+ "profile_and_level_indication %u\nchroma_format %u\nflags %s\n",
+ __entry->s.horizontal_size,
+ __entry->s.vertical_size,
+ __entry->s.vbv_buffer_size,
+ __entry->s.profile_and_level_indication,
+ __entry->s.chroma_format,
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE, "PROGRESSIVE"})
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_picture, p)),
+ TP_fast_assign(__entry->p = *p;),
+ TP_printk("\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
+ "picture_coding_type: %u\npicture_structure %u\nintra_dc_precision %u\n",
+ __entry->p.backward_ref_ts,
+ __entry->p.forward_ref_ts,
+ __print_flags(__entry->p.flags, "|",
+ {V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST, "TOP_FIELD_FIRST"},
+ {V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT, "FRAME_PRED_DCT"},
+ {V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV, "CONCEALMENT_MV"},
+ {V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE, "Q_SCALE_TYPE"},
+ {V4L2_MPEG2_PIC_FLAG_INTRA_VLC, "INTA_VLC"},
+ {V4L2_MPEG2_PIC_FLAG_ALT_SCAN, "ALT_SCAN"},
+ {V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST, "REPEAT_FIRST"},
+ {V4L2_MPEG2_PIC_FLAG_PROGRESSIVE, "PROGRESSIVE"}),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.f_code,
+ sizeof(__entry->p.f_code),
+ false),
+ __entry->p.picture_coding_type,
+ __entry->p.picture_structure,
+ __entry->p.intra_dc_precision
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
+ TP_ARGS(q),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_quantisation, q)),
+ TP_fast_assign(__entry->q = *q;),
+ TP_printk("\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
+ "chroma_intra_quantiser_matrix %s\nchroma_non_intra_quantiser_matrix %s\n",
+ __print_array(__entry->q.intra_quantiser_matrix,
+ ARRAY_SIZE(__entry->q.intra_quantiser_matrix),
+ sizeof(__entry->q.intra_quantiser_matrix[0])),
+ __print_array(__entry->q.non_intra_quantiser_matrix,
+ ARRAY_SIZE(__entry->q.non_intra_quantiser_matrix),
+ sizeof(__entry->q.non_intra_quantiser_matrix[0])),
+ __print_array(__entry->q.chroma_intra_quantiser_matrix,
+ ARRAY_SIZE(__entry->q.chroma_intra_quantiser_matrix),
+ sizeof(__entry->q.chroma_intra_quantiser_matrix[0])),
+ __print_array(__entry->q.chroma_non_intra_quantiser_matrix,
+ ARRAY_SIZE(__entry->q.chroma_non_intra_quantiser_matrix),
+ sizeof(__entry->q.chroma_non_intra_quantiser_matrix[0]))
+ )
+)
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_seq_tmpl, v4l2_ctrl_mpeg2_sequence,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_pic_tmpl, v4l2_ctrl_mpeg2_picture,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
+ TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_quant_tmpl, v4l2_ctrl_mpeg2_quantisation,
+ TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
+ TP_ARGS(q)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-mpeg2
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-points.c b/drivers/media/test-drivers/visl/visl-trace-points.c
new file mode 100644
index 000000000000..f7b866534f1e
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-points.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "visl.h"
+
+#define CREATE_TRACE_POINTS
+#include "visl-trace-fwht.h"
+#include "visl-trace-mpeg2.h"
+#include "visl-trace-vp8.h"
+#include "visl-trace-vp9.h"
+#include "visl-trace-h264.h"
+#include "visl-trace-hevc.h"
diff --git a/drivers/media/test-drivers/visl/visl-trace-vp8.h b/drivers/media/test-drivers/visl/visl-trace-vp8.h
new file mode 100644
index 000000000000..dabe17d69ddc
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-vp8.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_VP8_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_VP8_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_vp8_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+ TP_ARGS(f),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
+ TP_fast_assign(__entry->f = *f;),
+ TP_printk("\nentropy.coeff_probs {%s}\n"
+ "entropy.y_mode_probs %s\n"
+ "entropy.uv_mode_probs %s\n"
+ "entropy.mv_probs {%s}",
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->f.entropy.coeff_probs,
+ sizeof(__entry->f.entropy.coeff_probs),
+ false),
+ __print_array(__entry->f.entropy.y_mode_probs,
+ ARRAY_SIZE(__entry->f.entropy.y_mode_probs),
+ sizeof(__entry->f.entropy.y_mode_probs[0])),
+ __print_array(__entry->f.entropy.uv_mode_probs,
+ ARRAY_SIZE(__entry->f.entropy.uv_mode_probs),
+ sizeof(__entry->f.entropy.uv_mode_probs[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->f.entropy.mv_probs,
+ sizeof(__entry->f.entropy.mv_probs),
+ false)
+ )
+)
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+ TP_ARGS(f),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
+ TP_fast_assign(__entry->f = *f;),
+ TP_printk("\nsegment.quant_update %s\n"
+ "segment.lf_update %s\n"
+ "segment.segment_probs %s\n"
+ "segment.flags %s\n"
+ "lf.ref_frm_delta %s\n"
+ "lf.mb_mode_delta %s\n"
+ "lf.sharpness_level %u\n"
+ "lf.level %u\n"
+ "lf.flags %s\n"
+ "quant.y_ac_qi %u\n"
+ "quant.y_dc_delta %d\n"
+ "quant.y2_dc_delta %d\n"
+ "quant.y2_ac_delta %d\n"
+ "quant.uv_dc_delta %d\n"
+ "quant.uv_ac_delta %d\n"
+ "coder_state.range %u\n"
+ "coder_state.value %u\n"
+ "coder_state.bit_count %u\n"
+ "width %u\n"
+ "height %u\n"
+ "horizontal_scale %u\n"
+ "vertical_scale %u\n"
+ "version %u\n"
+ "prob_skip_false %u\n"
+ "prob_intra %u\n"
+ "prob_last %u\n"
+ "prob_gf %u\n"
+ "num_dct_parts %u\n"
+ "first_part_size %u\n"
+ "first_part_header_bits %u\n"
+ "dct_part_sizes %s\n"
+ "last_frame_ts %llu\n"
+ "golden_frame_ts %llu\n"
+ "alt_frame_ts %llu\n"
+ "flags %s",
+ __print_array(__entry->f.segment.quant_update,
+ ARRAY_SIZE(__entry->f.segment.quant_update),
+ sizeof(__entry->f.segment.quant_update[0])),
+ __print_array(__entry->f.segment.lf_update,
+ ARRAY_SIZE(__entry->f.segment.lf_update),
+ sizeof(__entry->f.segment.lf_update[0])),
+ __print_array(__entry->f.segment.segment_probs,
+ ARRAY_SIZE(__entry->f.segment.segment_probs),
+ sizeof(__entry->f.segment.segment_probs[0])),
+ __print_flags(__entry->f.segment.flags, "|",
+ {V4L2_VP8_SEGMENT_FLAG_ENABLED, "SEGMENT_ENABLED"},
+ {V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP, "SEGMENT_UPDATE_MAP"},
+ {V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA, "SEGMENT_UPDATE_FEATURE_DATA"},
+ {V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE, "SEGMENT_DELTA_VALUE_MODE"}),
+ __print_array(__entry->f.lf.ref_frm_delta,
+ ARRAY_SIZE(__entry->f.lf.ref_frm_delta),
+ sizeof(__entry->f.lf.ref_frm_delta[0])),
+ __print_array(__entry->f.lf.mb_mode_delta,
+ ARRAY_SIZE(__entry->f.lf.mb_mode_delta),
+ sizeof(__entry->f.lf.mb_mode_delta[0])),
+ __entry->f.lf.sharpness_level,
+ __entry->f.lf.level,
+ __print_flags(__entry->f.lf.flags, "|",
+ {V4L2_VP8_LF_ADJ_ENABLE, "LF_ADJ_ENABLED"},
+ {V4L2_VP8_LF_DELTA_UPDATE, "LF_DELTA_UPDATE"},
+ {V4L2_VP8_LF_FILTER_TYPE_SIMPLE, "LF_FILTER_TYPE_SIMPLE"}),
+ __entry->f.quant.y_ac_qi,
+ __entry->f.quant.y_dc_delta,
+ __entry->f.quant.y2_dc_delta,
+ __entry->f.quant.y2_ac_delta,
+ __entry->f.quant.uv_dc_delta,
+ __entry->f.quant.uv_ac_delta,
+ __entry->f.coder_state.range,
+ __entry->f.coder_state.value,
+ __entry->f.coder_state.bit_count,
+ __entry->f.width,
+ __entry->f.height,
+ __entry->f.horizontal_scale,
+ __entry->f.vertical_scale,
+ __entry->f.version,
+ __entry->f.prob_skip_false,
+ __entry->f.prob_intra,
+ __entry->f.prob_last,
+ __entry->f.prob_gf,
+ __entry->f.num_dct_parts,
+ __entry->f.first_part_size,
+ __entry->f.first_part_header_bits,
+ __print_array(__entry->f.dct_part_sizes,
+ ARRAY_SIZE(__entry->f.dct_part_sizes),
+ sizeof(__entry->f.dct_part_sizes[0])),
+ __entry->f.last_frame_ts,
+ __entry->f.golden_frame_ts,
+ __entry->f.alt_frame_ts,
+ __print_flags(__entry->f.flags, "|",
+ {V4L2_VP8_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
+ {V4L2_VP8_FRAME_FLAG_EXPERIMENTAL, "EXPERIMENTAL"},
+ {V4L2_VP8_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+ {V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF, "MB_NO_SKIP_COEFF"},
+ {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
+ {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"})
+ )
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp8_frame_tmpl, v4l2_ctrl_vp8_frame,
+ TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+ TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp8_entropy_tmpl, v4l2_ctrl_vp8_entropy,
+ TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+ TP_ARGS(f)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-vp8
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-vp9.h b/drivers/media/test-drivers/visl/visl-trace-vp9.h
new file mode 100644
index 000000000000..362b92b07f93
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-vp9.h
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_VP9_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_VP9_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_vp9_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
+ TP_ARGS(f),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_frame, f)),
+ TP_fast_assign(__entry->f = *f;),
+ TP_printk("\nlf.ref_deltas %s\n"
+ "lf.mode_deltas %s\n"
+ "lf.level %u\n"
+ "lf.sharpness %u\n"
+ "lf.flags %s\n"
+ "quant.base_q_idx %u\n"
+ "quant.delta_q_y_dc %d\n"
+ "quant.delta_q_uv_dc %d\n"
+ "quant.delta_q_uv_ac %d\n"
+ "seg.feature_data {%s}\n"
+ "seg.feature_enabled %s\n"
+ "seg.tree_probs %s\n"
+ "seg.pred_probs %s\n"
+ "seg.flags %s\n"
+ "flags %s\n"
+ "compressed_header_size %u\n"
+ "uncompressed_header_size %u\n"
+ "frame_width_minus_1 %u\n"
+ "frame_height_minus_1 %u\n"
+ "render_width_minus_1 %u\n"
+ "render_height_minus_1 %u\n"
+ "last_frame_ts %llu\n"
+ "golden_frame_ts %llu\n"
+ "alt_frame_ts %llu\n"
+ "ref_frame_sign_bias %s\n"
+ "reset_frame_context %s\n"
+ "frame_context_idx %u\n"
+ "profile %u\n"
+ "bit_depth %u\n"
+ "interpolation_filter %s\n"
+ "tile_cols_log2 %u\n"
+ "tile_rows_log_2 %u\n"
+ "reference_mode %s\n",
+ __print_array(__entry->f.lf.ref_deltas,
+ ARRAY_SIZE(__entry->f.lf.ref_deltas),
+ sizeof(__entry->f.lf.ref_deltas[0])),
+ __print_array(__entry->f.lf.mode_deltas,
+ ARRAY_SIZE(__entry->f.lf.mode_deltas),
+ sizeof(__entry->f.lf.mode_deltas[0])),
+ __entry->f.lf.level,
+ __entry->f.lf.sharpness,
+ __print_flags(__entry->f.lf.flags, "|",
+ {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
+ {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"}),
+ __entry->f.quant.base_q_idx,
+ __entry->f.quant.delta_q_y_dc,
+ __entry->f.quant.delta_q_uv_dc,
+ __entry->f.quant.delta_q_uv_ac,
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->f.seg.feature_data,
+ sizeof(__entry->f.seg.feature_data),
+ false),
+ __print_array(__entry->f.seg.feature_enabled,
+ ARRAY_SIZE(__entry->f.seg.feature_enabled),
+ sizeof(__entry->f.seg.feature_enabled[0])),
+ __print_array(__entry->f.seg.tree_probs,
+ ARRAY_SIZE(__entry->f.seg.tree_probs),
+ sizeof(__entry->f.seg.tree_probs[0])),
+ __print_array(__entry->f.seg.pred_probs,
+ ARRAY_SIZE(__entry->f.seg.pred_probs),
+ sizeof(__entry->f.seg.pred_probs[0])),
+ __print_flags(__entry->f.seg.flags, "|",
+ {V4L2_VP9_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
+ {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
+ {V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
+ {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
+ {V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE, "ABS_OR_DELTA_UPDATE"}),
+ __print_flags(__entry->f.flags, "|",
+ {V4L2_VP9_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
+ {V4L2_VP9_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+ {V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT, "ERROR_RESILIENT"},
+ {V4L2_VP9_FRAME_FLAG_INTRA_ONLY, "INTRA_ONLY"},
+ {V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV, "ALLOW_HIGH_PREC_MV"},
+ {V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX, "REFRESH_FRAME_CTX"},
+ {V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE, "PARALLEL_DEC_MODE"},
+ {V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING, "X_SUBSAMPLING"},
+ {V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING, "Y_SUBSAMPLING"},
+ {V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING, "COLOR_RANGE_FULL_SWING"}),
+ __entry->f.compressed_header_size,
+ __entry->f.uncompressed_header_size,
+ __entry->f.frame_width_minus_1,
+ __entry->f.frame_height_minus_1,
+ __entry->f.render_width_minus_1,
+ __entry->f.render_height_minus_1,
+ __entry->f.last_frame_ts,
+ __entry->f.golden_frame_ts,
+ __entry->f.alt_frame_ts,
+ __print_symbolic(__entry->f.ref_frame_sign_bias,
+ {V4L2_VP9_SIGN_BIAS_LAST, "SIGN_BIAS_LAST"},
+ {V4L2_VP9_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
+ {V4L2_VP9_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"}),
+ __print_symbolic(__entry->f.reset_frame_context,
+ {V4L2_VP9_RESET_FRAME_CTX_NONE, "RESET_FRAME_CTX_NONE"},
+ {V4L2_VP9_RESET_FRAME_CTX_SPEC, "RESET_FRAME_CTX_SPEC"},
+ {V4L2_VP9_RESET_FRAME_CTX_ALL, "RESET_FRAME_CTX_ALL"}),
+ __entry->f.frame_context_idx,
+ __entry->f.profile,
+ __entry->f.bit_depth,
+ __print_symbolic(__entry->f.interpolation_filter,
+ {V4L2_VP9_INTERP_FILTER_EIGHTTAP, "INTERP_FILTER_EIGHTTAP"},
+ {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH, "INTERP_FILTER_EIGHTTAP_SMOOTH"},
+ {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SHARP, "INTERP_FILTER_EIGHTTAP_SHARP"},
+ {V4L2_VP9_INTERP_FILTER_BILINEAR, "INTERP_FILTER_BILINEAR"},
+ {V4L2_VP9_INTERP_FILTER_SWITCHABLE, "INTERP_FILTER_SWITCHABLE"}),
+ __entry->f.tile_cols_log2,
+ __entry->f.tile_rows_log2,
+ __print_symbolic(__entry->f.reference_mode,
+ {V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, "REFERENCE_MODE_SINGLE_REFERENCE"},
+ {V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE, "REFERENCE_MODE_COMPOUND_REFERENCE"},
+ {V4L2_VP9_REFERENCE_MODE_SELECT, "REFERENCE_MODE_SELECT"}))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+ TP_ARGS(h),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
+ TP_fast_assign(__entry->h = *h;),
+ TP_printk("\ntx_mode %s\n"
+ "tx8 {%s}\n"
+ "tx16 {%s}\n"
+ "tx32 {%s}\n"
+ "skip %s\n"
+ "inter_mode {%s}\n"
+ "interp_filter {%s}\n"
+ "is_inter %s\n"
+ "comp_mode %s\n"
+ "single_ref {%s}\n"
+ "comp_ref %s\n"
+ "y_mode {%s}\n"
+ "uv_mode {%s}\n"
+ "partition {%s}\n",
+ __print_symbolic(__entry->h.tx_mode,
+ {V4L2_VP9_TX_MODE_ONLY_4X4, "TX_MODE_ONLY_4X4"},
+ {V4L2_VP9_TX_MODE_ALLOW_8X8, "TX_MODE_ALLOW_8X8"},
+ {V4L2_VP9_TX_MODE_ALLOW_16X16, "TX_MODE_ALLOW_16X16"},
+ {V4L2_VP9_TX_MODE_ALLOW_32X32, "TX_MODE_ALLOW_32X32"},
+ {V4L2_VP9_TX_MODE_SELECT, "TX_MODE_SELECT"}),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.tx8,
+ sizeof(__entry->h.tx8),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.tx16,
+ sizeof(__entry->h.tx16),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.tx32,
+ sizeof(__entry->h.tx32),
+ false),
+ __print_array(__entry->h.skip,
+ ARRAY_SIZE(__entry->h.skip),
+ sizeof(__entry->h.skip[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.inter_mode,
+ sizeof(__entry->h.inter_mode),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.interp_filter,
+ sizeof(__entry->h.interp_filter),
+ false),
+ __print_array(__entry->h.is_inter,
+ ARRAY_SIZE(__entry->h.is_inter),
+ sizeof(__entry->h.is_inter[0])),
+ __print_array(__entry->h.comp_mode,
+ ARRAY_SIZE(__entry->h.comp_mode),
+ sizeof(__entry->h.comp_mode[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.single_ref,
+ sizeof(__entry->h.single_ref),
+ false),
+ __print_array(__entry->h.comp_ref,
+ ARRAY_SIZE(__entry->h.comp_ref),
+ sizeof(__entry->h.comp_ref[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.y_mode,
+ sizeof(__entry->h.y_mode),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.uv_mode,
+ sizeof(__entry->h.uv_mode),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.partition,
+ sizeof(__entry->h.partition),
+ false)
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+ TP_ARGS(h),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
+ TP_fast_assign(__entry->h = *h;),
+ TP_printk("\n coef {%s}",
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->h.coef,
+ sizeof(__entry->h.coef),
+ false)
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
+ TP_PROTO(const struct v4l2_vp9_mv_probs *p),
+ TP_ARGS(p),
+ TP_STRUCT__entry(__field_struct(struct v4l2_vp9_mv_probs, p)),
+ TP_fast_assign(__entry->p = *p;),
+ TP_printk("\n joint %s\n"
+ "sign %s\n"
+ "classes {%s}\n"
+ "class0_bit %s\n"
+ "bits {%s}\n"
+ "class0_fr {%s}\n"
+ "fr {%s}\n"
+ "class0_hp %s\n"
+ "hp %s\n",
+ __print_array(__entry->p.joint,
+ ARRAY_SIZE(__entry->p.joint),
+ sizeof(__entry->p.joint[0])),
+ __print_array(__entry->p.sign,
+ ARRAY_SIZE(__entry->p.sign),
+ sizeof(__entry->p.sign[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.classes,
+ sizeof(__entry->p.classes),
+ false),
+ __print_array(__entry->p.class0_bit,
+ ARRAY_SIZE(__entry->p.class0_bit),
+ sizeof(__entry->p.class0_bit[0])),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.bits,
+ sizeof(__entry->p.bits),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.class0_fr,
+ sizeof(__entry->p.class0_fr),
+ false),
+ __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+ __entry->p.fr,
+ sizeof(__entry->p.fr),
+ false),
+ __print_array(__entry->p.class0_hp,
+ ARRAY_SIZE(__entry->p.class0_hp),
+ sizeof(__entry->p.class0_hp[0])),
+ __print_array(__entry->p.hp,
+ ARRAY_SIZE(__entry->p.hp),
+ sizeof(__entry->p.hp[0]))
+ )
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_frame_tmpl, v4l2_ctrl_vp9_frame,
+ TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
+ TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_compressed_hdr_tmpl, v4l2_ctrl_vp9_compressed_hdr,
+ TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+ TP_ARGS(h)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_compressed_coef_tmpl, v4l2_ctrl_vp9_compressed_coeff,
+ TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+ TP_ARGS(h)
+);
+
+
+DEFINE_EVENT(v4l2_vp9_mv_probs_tmpl, v4l2_vp9_mv_probs,
+ TP_PROTO(const struct v4l2_vp9_mv_probs *p),
+ TP_ARGS(p)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-vp9
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c
new file mode 100644
index 000000000000..b08664dfbe5f
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-video.c
@@ -0,0 +1,767 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Contains the driver implementation for the V4L2 stateless interface.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/font.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "visl-video.h"
+
+#include "visl.h"
+#include "visl-debugfs.h"
+
+#define MIN_CODED_SZ (1024U * 256U)
+
+static void visl_set_current_codec(struct visl_ctx *ctx)
+{
+ u32 fourcc = ctx->coded_fmt.fmt.pix_mp.pixelformat;
+
+ switch (fourcc) {
+ case V4L2_PIX_FMT_FWHT_STATELESS:
+ ctx->current_codec = VISL_CODEC_FWHT;
+ break;
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ ctx->current_codec = VISL_CODEC_MPEG2;
+ break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ ctx->current_codec = VISL_CODEC_VP8;
+ break;
+ case V4L2_PIX_FMT_VP9_FRAME:
+ ctx->current_codec = VISL_CODEC_VP9;
+ break;
+ case V4L2_PIX_FMT_H264_SLICE:
+ ctx->current_codec = VISL_CODEC_H264;
+ break;
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ ctx->current_codec = VISL_CODEC_HEVC;
+ break;
+ default:
+ dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n", fourcc);
+ ctx->current_codec = VISL_CODEC_NONE;
+ break;
+ }
+}
+
+static void visl_print_fmt(struct visl_ctx *ctx, const struct v4l2_format *f)
+{
+ const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ u32 i;
+
+ dprintk(ctx->dev, "width: %d\n", pix_mp->width);
+ dprintk(ctx->dev, "height: %d\n", pix_mp->height);
+ dprintk(ctx->dev, "pixelformat: %c%c%c%c\n",
+ pix_mp->pixelformat,
+ (pix_mp->pixelformat >> 8) & 0xff,
+ (pix_mp->pixelformat >> 16) & 0xff,
+ (pix_mp->pixelformat >> 24) & 0xff);
+
+ dprintk(ctx->dev, "field: %d\n", pix_mp->field);
+ dprintk(ctx->dev, "colorspace: %d\n", pix_mp->colorspace);
+ dprintk(ctx->dev, "num_planes: %d\n", pix_mp->num_planes);
+ dprintk(ctx->dev, "flags: %d\n", pix_mp->flags);
+ dprintk(ctx->dev, "quantization: %d\n", pix_mp->quantization);
+ dprintk(ctx->dev, "xfer_func: %d\n", pix_mp->xfer_func);
+
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ dprintk(ctx->dev,
+ "plane[%d]: sizeimage: %d\n", i, pix_mp->plane_fmt[i].sizeimage);
+ dprintk(ctx->dev,
+ "plane[%d]: bytesperline: %d\n", i, pix_mp->plane_fmt[i].bytesperline);
+ }
+}
+
+static int visl_tpg_init(struct visl_ctx *ctx)
+{
+ const struct font_desc *font;
+ const char *font_name = "VGA8x16";
+ int ret;
+ u32 width = ctx->decoded_fmt.fmt.pix_mp.width;
+ u32 height = ctx->decoded_fmt.fmt.pix_mp.height;
+ struct v4l2_pix_format_mplane *f = &ctx->decoded_fmt.fmt.pix_mp;
+
+ tpg_free(&ctx->tpg);
+
+ font = find_font(font_name);
+ if (font) {
+ tpg_init(&ctx->tpg, width, height);
+
+ ret = tpg_alloc(&ctx->tpg, width);
+ if (ret)
+ goto err_alloc;
+
+ tpg_set_font(font->data);
+ ret = tpg_s_fourcc(&ctx->tpg,
+ f->pixelformat);
+
+ if (!ret)
+ goto err_fourcc;
+
+ tpg_reset_source(&ctx->tpg, width, height, f->field);
+
+ tpg_s_pattern(&ctx->tpg, TPG_PAT_75_COLORBAR);
+
+ tpg_s_field(&ctx->tpg, f->field, false);
+ tpg_s_colorspace(&ctx->tpg, f->colorspace);
+ tpg_s_ycbcr_enc(&ctx->tpg, f->ycbcr_enc);
+ tpg_s_quantization(&ctx->tpg, f->quantization);
+ tpg_s_xfer_func(&ctx->tpg, f->xfer_func);
+ } else {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Font %s not found\n", font_name);
+
+ return -EINVAL;
+ }
+
+ dprintk(ctx->dev, "Initialized the V4L2 test pattern generator, w=%d, h=%d, max_w=%d\n",
+ width, height, width);
+
+ return 0;
+err_alloc:
+ return ret;
+err_fourcc:
+ tpg_free(&ctx->tpg);
+ return ret;
+}
+
+static const u32 visl_decoded_fmts[] = {
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV420,
+};
+
+const struct visl_coded_format_desc visl_coded_fmts[] = {
+ {
+ .pixelformat = V4L2_PIX_FMT_FWHT_STATELESS,
+ .frmsize = {
+ .min_width = 640,
+ .max_width = 4096,
+ .step_width = 1,
+ .min_height = 360,
+ .max_height = 2160,
+ .step_height = 1,
+ },
+ .ctrls = &visl_fwht_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
+ .frmsize = {
+ .min_width = 16,
+ .max_width = 1920,
+ .step_width = 1,
+ .min_height = 16,
+ .max_height = 1152,
+ .step_height = 1,
+ },
+ .ctrls = &visl_mpeg2_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VP8_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 16383,
+ .step_width = 1,
+ .min_height = 64,
+ .max_height = 16383,
+ .step_height = 1,
+ },
+ .ctrls = &visl_vp8_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VP9_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 8192,
+ .step_width = 1,
+ .min_height = 64,
+ .max_height = 4352,
+ .step_height = 1,
+ },
+ .ctrls = &visl_vp9_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_H264_SLICE,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 4096,
+ .step_width = 1,
+ .min_height = 64,
+ .max_height = 2304,
+ .step_height = 1,
+ },
+ .ctrls = &visl_h264_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_HEVC_SLICE,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 4096,
+ .step_width = 1,
+ .min_height = 64,
+ .max_height = 2304,
+ .step_height = 1,
+ },
+ .ctrls = &visl_hevc_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+};
+
+const size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts);
+
+static const struct visl_coded_format_desc*
+visl_find_coded_fmt_desc(u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(visl_coded_fmts); i++) {
+ if (visl_coded_fmts[i].pixelformat == fourcc)
+ return &visl_coded_fmts[i];
+ }
+
+ return NULL;
+}
+
+static void visl_init_fmt(struct v4l2_format *f, u32 fourcc)
+{ memset(f, 0, sizeof(*f));
+ f->fmt.pix_mp.pixelformat = fourcc;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
+ f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+ f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static void visl_reset_coded_fmt(struct visl_ctx *ctx)
+{
+ struct v4l2_format *f = &ctx->coded_fmt;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+
+ ctx->coded_format_desc = &visl_coded_fmts[0];
+ visl_init_fmt(f, ctx->coded_format_desc->pixelformat);
+
+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ f->fmt.pix_mp.width = ctx->coded_format_desc->frmsize.min_width;
+ f->fmt.pix_mp.height = ctx->coded_format_desc->frmsize.min_height;
+
+ pix_mp->num_planes = 1;
+ pix_mp->plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * 8;
+
+ dprintk(ctx->dev, "OUTPUT format was set to:\n");
+ visl_print_fmt(ctx, &ctx->coded_fmt);
+
+ visl_set_current_codec(ctx);
+}
+
+static int visl_reset_decoded_fmt(struct visl_ctx *ctx)
+{
+ struct v4l2_format *f = &ctx->decoded_fmt;
+ u32 decoded_fmt = ctx->coded_format_desc[0].decoded_fmts[0];
+
+ visl_init_fmt(f, decoded_fmt);
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+ v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
+ ctx->coded_format_desc->decoded_fmts[0],
+ ctx->coded_fmt.fmt.pix_mp.width,
+ ctx->coded_fmt.fmt.pix_mp.height);
+
+ dprintk(ctx->dev, "CAPTURE format was set to:\n");
+ visl_print_fmt(ctx, &ctx->decoded_fmt);
+
+ return visl_tpg_init(ctx);
+}
+
+int visl_set_default_format(struct visl_ctx *ctx)
+{
+ visl_reset_coded_fmt(ctx);
+ return visl_reset_decoded_fmt(ctx);
+}
+
+static struct visl_q_data *get_q_data(struct visl_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &ctx->q_data[V4L2_M2M_SRC];
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return &ctx->q_data[V4L2_M2M_DST];
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static int visl_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, VISL_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VISL_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", VISL_NAME);
+
+ return 0;
+}
+
+static int visl_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+
+ if (f->index >= ctx->coded_format_desc->num_decoded_fmts)
+ return -EINVAL;
+
+ f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index];
+ return 0;
+}
+
+static int visl_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(visl_coded_fmts))
+ return -EINVAL;
+
+ f->pixelformat = visl_coded_fmts[f->index].pixelformat;
+ return 0;
+}
+
+static int visl_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+ *f = ctx->decoded_fmt;
+
+ return 0;
+}
+
+static int visl_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+
+ *f = ctx->coded_fmt;
+ return 0;
+}
+
+static int visl_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+ const struct visl_coded_format_desc *coded_desc;
+ unsigned int i;
+
+ coded_desc = ctx->coded_format_desc;
+
+ for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
+ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
+ break;
+ }
+
+ if (i == coded_desc->num_decoded_fmts)
+ pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &coded_desc->frmsize);
+
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+
+ pix_mp->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int visl_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct visl_coded_format_desc *coded_desc;
+
+ coded_desc = visl_find_coded_fmt_desc(pix_mp->pixelformat);
+ if (!coded_desc) {
+ pix_mp->pixelformat = visl_coded_fmts[0].pixelformat;
+ coded_desc = &visl_coded_fmts[0];
+ }
+
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &coded_desc->frmsize);
+
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = 1;
+
+ if (pix_mp->plane_fmt[0].sizeimage == 0)
+ pix_mp->plane_fmt[0].sizeimage = max(MIN_CODED_SZ,
+ pix_mp->width * pix_mp->height * 3);
+
+ return 0;
+}
+
+static int visl_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ const struct visl_coded_format_desc *desc;
+ struct vb2_queue *peer_vq;
+ int ret;
+
+ peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(peer_vq))
+ return -EBUSY;
+
+ dprintk(ctx->dev, "Trying to set the OUTPUT format to:\n");
+ visl_print_fmt(ctx, f);
+
+ ret = visl_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ desc = visl_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat);
+ ctx->coded_format_desc = desc;
+ ctx->coded_fmt = *f;
+
+ ret = visl_reset_decoded_fmt(ctx);
+ if (ret)
+ return ret;
+
+ ctx->decoded_fmt.fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+ ctx->decoded_fmt.fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+ ctx->decoded_fmt.fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+ ctx->decoded_fmt.fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+
+ dprintk(ctx->dev, "OUTPUT format was set to:\n");
+ visl_print_fmt(ctx, &ctx->coded_fmt);
+
+ visl_set_current_codec(ctx);
+ return 0;
+}
+
+static int visl_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+ int ret;
+
+ dprintk(ctx->dev, "Trying to set the CAPTURE format to:\n");
+ visl_print_fmt(ctx, f);
+
+ ret = visl_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->decoded_fmt = *f;
+
+ dprintk(ctx->dev, "CAPTURE format was set to:\n");
+ visl_print_fmt(ctx, &ctx->decoded_fmt);
+
+ visl_tpg_init(ctx);
+ return 0;
+}
+
+static int visl_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ const struct visl_coded_format_desc *fmt;
+ struct visl_ctx *ctx = visl_file_to_ctx(file);
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ fmt = visl_find_coded_fmt_desc(fsize->pixel_format);
+ if (!fmt) {
+ dprintk(ctx->dev,
+ "Unsupported format for the OUTPUT queue: %d\n",
+ fsize->pixel_format);
+
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = fmt->frmsize;
+ return 0;
+}
+
+const struct v4l2_ioctl_ops visl_ioctl_ops = {
+ .vidioc_querycap = visl_querycap,
+ .vidioc_enum_framesizes = visl_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = visl_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap_mplane = visl_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap_mplane = visl_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap_mplane = visl_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = visl_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out_mplane = visl_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out_mplane = visl_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out_mplane = visl_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int visl_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct visl_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_format *f;
+ u32 i;
+ char *qname;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ f = &ctx->coded_fmt;
+ qname = "Output";
+ } else {
+ f = &ctx->decoded_fmt;
+ qname = "Capture";
+ }
+
+ if (*num_planes) {
+ if (*num_planes != f->fmt.pix_mp.num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
+ sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ dprintk(ctx->dev, "%s: %d buffer(s) requested, num_planes=%d.\n",
+ qname, *nbuffers, *num_planes);
+
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
+ dprintk(ctx->dev, "plane[%d].sizeimage=%d\n",
+ i, f->fmt.pix_mp.plane_fmt[i].sizeimage);
+
+ return 0;
+}
+
+static void visl_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+ struct visl_ctx *ctx = vb2_get_drv_priv(vq);
+ struct vb2_v4l2_buffer *vbuf;
+
+ dprintk(ctx->dev, "Cleaning up queues\n");
+ for (;;) {
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (!vbuf)
+ break;
+
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->hdl);
+ dprintk(ctx->dev, "Marked request %p as complete\n",
+ vbuf->vb2_buf.req_obj.req);
+
+ v4l2_m2m_buf_done(vbuf, state);
+ dprintk(ctx->dev,
+ "Marked buffer %llu as done, state is %d\n",
+ vbuf->vb2_buf.timestamp,
+ state);
+ }
+}
+
+static int visl_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+static int visl_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct visl_ctx *ctx = vb2_get_drv_priv(vq);
+ u32 plane_sz = vb2_plane_size(vb, 0);
+ struct v4l2_pix_format *pix_fmt;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ pix_fmt = &ctx->coded_fmt.fmt.pix;
+ } else {
+ pix_fmt = &ctx->decoded_fmt.fmt.pix;
+ vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+ }
+
+ if (plane_sz < pix_fmt->sizeimage) {
+ v4l2_err(&ctx->dev->v4l2_dev, "plane[0] size is %d, sizeimage is %d\n",
+ plane_sz, pix_fmt->sizeimage);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int visl_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct visl_ctx *ctx = vb2_get_drv_priv(vq);
+ struct visl_q_data *q_data = get_q_data(ctx, vq->type);
+ int rc = 0;
+
+ if (!q_data) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ q_data->sequence = 0;
+
+ if (V4L2_TYPE_IS_CAPTURE(vq->type)) {
+ ctx->capture_streamon_jiffies = get_jiffies_64();
+ return 0;
+ }
+
+ if (WARN_ON(!ctx->coded_format_desc)) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ visl_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
+ return rc;
+}
+
+static void visl_stop_streaming(struct vb2_queue *vq)
+{
+ struct visl_ctx *ctx = vb2_get_drv_priv(vq);
+
+ dprintk(ctx->dev, "Stop streaming\n");
+ visl_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+
+ if (!keep_bitstream_buffers)
+ visl_debugfs_clear_bitstream(ctx->dev);
+}
+
+static void visl_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void visl_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
+const struct vb2_ops visl_qops = {
+ .queue_setup = visl_queue_setup,
+ .buf_out_validate = visl_buf_out_validate,
+ .buf_prepare = visl_buf_prepare,
+ .buf_queue = visl_buf_queue,
+ .start_streaming = visl_start_streaming,
+ .stop_streaming = visl_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_request_complete = visl_buf_request_complete,
+};
+
+int visl_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct visl_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &visl_qops;
+ src_vq->mem_ops = &vb2_vmalloc_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->vb_mutex;
+ src_vq->supports_requests = true;
+ src_vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &visl_qops;
+ dst_vq->mem_ops = &vb2_vmalloc_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->vb_mutex;
+
+ return vb2_queue_init(dst_vq);
+}
+
+int visl_request_validate(struct media_request *req)
+{
+ struct media_request_object *obj;
+ struct visl_ctx *ctx = NULL;
+ unsigned int count;
+
+ list_for_each_entry(obj, &req->objects, list) {
+ struct vb2_buffer *vb;
+
+ if (vb2_request_object_is_buffer(obj)) {
+ vb = container_of(obj, struct vb2_buffer, req_obj);
+ ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ break;
+ }
+ }
+
+ if (!ctx)
+ return -ENOENT;
+
+ count = vb2_request_buffer_cnt(req);
+ if (!count) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "No buffer was provided with the request\n");
+ return -ENOENT;
+ } else if (count > 1) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "More than one buffer was provided with the request\n");
+ return -EINVAL;
+ }
+
+ return vb2_request_validate(req);
+}
diff --git a/drivers/media/test-drivers/visl/visl-video.h b/drivers/media/test-drivers/visl/visl-video.h
new file mode 100644
index 000000000000..27ad70a558db
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-video.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Contains the driver implementation for the V4L2 stateless interface.
+ */
+
+#ifndef _VISL_VIDEO_H_
+#define _VISL_VIDEO_H_
+#include <media/v4l2-mem2mem.h>
+
+#include "visl.h"
+
+extern const struct v4l2_ioctl_ops visl_ioctl_ops;
+
+extern const struct visl_ctrls visl_fwht_ctrls;
+extern const struct visl_ctrls visl_mpeg2_ctrls;
+extern const struct visl_ctrls visl_vp8_ctrls;
+extern const struct visl_ctrls visl_vp9_ctrls;
+extern const struct visl_ctrls visl_h264_ctrls;
+extern const struct visl_ctrls visl_hevc_ctrls;
+
+int visl_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
+
+int visl_set_default_format(struct visl_ctx *ctx);
+int visl_request_validate(struct media_request *req);
+
+#endif /* _VISL_VIDEO_H_ */
diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h
new file mode 100644
index 000000000000..31639f2e593d
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * A virtual stateless device for stateless uAPI development purposes.
+ *
+ * This tool's objective is to help the development and testing of userspace
+ * applications that use the V4L2 stateless API to decode media.
+ *
+ * A userspace implementation can use visl to run a decoding loop even when no
+ * hardware is available or when the kernel uAPI for the codec has not been
+ * upstreamed yet. This can reveal bugs at an early stage.
+ *
+ * This driver can also trace the contents of the V4L2 controls submitted to it.
+ * It can also dump the contents of the vb2 buffers through a debugfs
+ * interface. This is in many ways similar to the tracing infrastructure
+ * available for other popular encode/decode APIs out there and can help develop
+ * a userspace application by using another (working) one as a reference.
+ *
+ * Note that no actual decoding of video frames is performed by visl. The V4L2
+ * test pattern generator is used to write various debug information to the
+ * capture buffers instead.
+ *
+ * Copyright (C) 2022 Collabora, Ltd.
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * Based on the vicodec driver, that is:
+ *
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#ifndef _VISL_H_
+#define _VISL_H_
+
+#include <linux/debugfs.h>
+#include <linux/list.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/tpg/v4l2-tpg.h>
+
+#define VISL_NAME "visl"
+#define VISL_M2M_NQUEUES 2
+
+#define TPG_STR_BUF_SZ 2048
+
+extern unsigned int visl_transtime_ms;
+
+struct visl_ctrls {
+ const struct visl_ctrl_desc *ctrls;
+ unsigned int num_ctrls;
+};
+
+struct visl_coded_format_desc {
+ u32 pixelformat;
+ struct v4l2_frmsize_stepwise frmsize;
+ const struct visl_ctrls *ctrls;
+ unsigned int num_decoded_fmts;
+ const u32 *decoded_fmts;
+};
+
+extern const struct visl_coded_format_desc visl_coded_fmts[];
+extern const size_t num_coded_fmts;
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+extern unsigned int visl_debug;
+#define dprintk(dev, fmt, arg...) \
+ v4l2_dbg(1, visl_debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+extern int visl_dprintk_frame_start;
+extern unsigned int visl_dprintk_nframes;
+extern bool keep_bitstream_buffers;
+extern int bitstream_trace_frame_start;
+extern unsigned int bitstream_trace_nframes;
+
+#define frame_dprintk(dev, current, fmt, arg...) \
+ do { \
+ if (visl_dprintk_frame_start > -1 && \
+ (current) >= visl_dprintk_frame_start && \
+ (current) < visl_dprintk_frame_start + visl_dprintk_nframes) \
+ dprintk(dev, fmt, ## arg); \
+ } while (0) \
+
+struct visl_q_data {
+ unsigned int sequence;
+};
+
+struct visl_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+#endif
+
+ struct mutex dev_mutex;
+
+ struct v4l2_m2m_dev *m2m_dev;
+
+#ifdef CONFIG_VISL_DEBUGFS
+ struct dentry *debugfs_root;
+ struct dentry *bitstream_debugfs;
+ struct list_head bitstream_blobs;
+
+ /* Protects the "blob" list */
+ struct mutex bitstream_lock;
+#endif
+};
+
+enum visl_codec {
+ VISL_CODEC_NONE,
+ VISL_CODEC_FWHT,
+ VISL_CODEC_MPEG2,
+ VISL_CODEC_VP8,
+ VISL_CODEC_VP9,
+ VISL_CODEC_H264,
+ VISL_CODEC_HEVC,
+};
+
+struct visl_blob {
+ struct list_head list;
+ struct dentry *dentry;
+ struct debugfs_blob_wrapper blob;
+};
+
+struct visl_ctx {
+ struct v4l2_fh fh;
+ struct visl_dev *dev;
+ struct v4l2_ctrl_handler hdl;
+
+ struct mutex vb_mutex;
+
+ struct visl_q_data q_data[VISL_M2M_NQUEUES];
+ enum visl_codec current_codec;
+
+ const struct visl_coded_format_desc *coded_format_desc;
+
+ struct v4l2_format coded_fmt;
+ struct v4l2_format decoded_fmt;
+
+ struct tpg_data tpg;
+ u64 capture_streamon_jiffies;
+ char *tpg_str_buf;
+};
+
+struct visl_ctrl_desc {
+ struct v4l2_ctrl_config cfg;
+};
+
+static inline struct visl_ctx *visl_file_to_ctx(struct file *file)
+{
+ return container_of(file->private_data, struct visl_ctx, fh);
+}
+
+static inline struct visl_ctx *visl_v4l2fh_to_ctx(struct v4l2_fh *v4l2_fh)
+{
+ return container_of(v4l2_fh, struct visl_ctx, fh);
+}
+
+void *visl_find_control_data(struct visl_ctx *ctx, u32 id);
+struct v4l2_ctrl *visl_find_control(struct visl_ctx *ctx, u32 id);
+u32 visl_control_num_elems(struct visl_ctx *ctx, u32 id);
+
+#endif /* _VISL_H_ */
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index 92b1a7598470..f2b20e25a7a4 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -36,6 +36,8 @@
#define VIVID_CID_RO_INTEGER (VIVID_CID_CUSTOM_BASE + 12)
#define VIVID_CID_U32_DYN_ARRAY (VIVID_CID_CUSTOM_BASE + 13)
#define VIVID_CID_U8_PIXEL_ARRAY (VIVID_CID_CUSTOM_BASE + 14)
+#define VIVID_CID_S32_ARRAY (VIVID_CID_CUSTOM_BASE + 15)
+#define VIVID_CID_S64_ARRAY (VIVID_CID_CUSTOM_BASE + 16)
#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)
#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)
@@ -241,6 +243,30 @@ static const struct v4l2_ctrl_config vivid_ctrl_u8_pixel_array = {
.dims = { 640 / PIXEL_ARRAY_DIV, 360 / PIXEL_ARRAY_DIV },
};
+static const struct v4l2_ctrl_config vivid_ctrl_s32_array = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_S32_ARRAY,
+ .name = "S32 2 Element Array",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 2,
+ .min = -10,
+ .max = 10,
+ .step = 1,
+ .dims = { 2 },
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_s64_array = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_S64_ARRAY,
+ .name = "S64 5 Element Array",
+ .type = V4L2_CTRL_TYPE_INTEGER64,
+ .def = 4,
+ .min = -10,
+ .max = 10,
+ .step = 1,
+ .dims = { 5 },
+};
+
static const char * const vivid_ctrl_menu_strings[] = {
"Menu Item 0 (Skipped)",
"Menu Item 1",
@@ -1656,6 +1682,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL);
dev->pixel_array = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_pixel_array, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_s32_array, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_s64_array, NULL);
if (dev->has_vid_cap) {
/* Image Processing Controls */
diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
index 690daada7db4..ee65d20314d3 100644
--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
@@ -693,7 +693,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
/* Drop a certain percentage of buffers. */
if (dev->perc_dropped_buffers &&
- prandom_u32_max(100) < dev->perc_dropped_buffers)
+ get_random_u32_below(100) < dev->perc_dropped_buffers)
goto update_mv;
spin_lock(&dev->slock);
diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-out.c b/drivers/media/test-drivers/vivid/vivid-kthread-out.c
index 0833e021bb11..fac6208b51da 100644
--- a/drivers/media/test-drivers/vivid/vivid-kthread-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-kthread-out.c
@@ -51,7 +51,7 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
/* Drop a certain percentage of buffers. */
if (dev->perc_dropped_buffers &&
- prandom_u32_max(100) < dev->perc_dropped_buffers)
+ get_random_u32_below(100) < dev->perc_dropped_buffers)
return;
spin_lock(&dev->slock);
diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.c b/drivers/media/test-drivers/vivid/vivid-radio-rx.c
index 8bd09589fb15..79c1723bd84c 100644
--- a/drivers/media/test-drivers/vivid/vivid-radio-rx.c
+++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.c
@@ -94,8 +94,8 @@ retry:
if (data_blk == 0 && dev->radio_rds_loop)
vivid_radio_rds_init(dev);
- if (perc && prandom_u32_max(100) < perc) {
- switch (prandom_u32_max(4)) {
+ if (perc && get_random_u32_below(100) < perc) {
+ switch (get_random_u32_below(4)) {
case 0:
rds.block |= V4L2_RDS_BLOCK_CORRECTED;
break;
diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
index 0ae5628b86c9..a81f26b76988 100644
--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
@@ -90,7 +90,7 @@ static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
/* Drop a certain percentage of buffers. */
if (dev->perc_dropped_buffers &&
- prandom_u32_max(100) < dev->perc_dropped_buffers)
+ get_random_u32_below(100) < dev->perc_dropped_buffers)
return;
spin_lock(&dev->slock);
diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
index 6cc32eb54f9d..c7f6e23df51e 100644
--- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
@@ -221,7 +221,7 @@ static void vivid_fill_buff_noise(__s16 *tch_buf, int size)
static inline int get_random_pressure(void)
{
- return prandom_u32_max(VIVID_PRESSURE_LIMIT);
+ return get_random_u32_below(VIVID_PRESSURE_LIMIT);
}
static void vivid_tch_buf_set(struct v4l2_pix_format *f,
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-gen.c b/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
index a141369a7a63..70a4024d461e 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
@@ -194,7 +194,6 @@ static void vivid_vbi_gen_set_time_of_day(u8 *packet)
for (checksum = i = 0; i <= 8; i++)
checksum += packet[i] & 0x7f;
packet[9] = calc_parity(0x100 - checksum);
- checksum = 0;
packet[10] = calc_parity(0x07);
packet[11] = calc_parity(0x04);
if (sys_tz.tz_minuteswest >= 0)
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 11620eaf941e..c0999581c599 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -973,6 +973,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
if (dev->has_compose_cap) {
v4l2_rect_set_min_size(compose, &min_rect);
v4l2_rect_set_max_size(compose, &max_rect);
+ v4l2_rect_map_inside(compose, &fmt);
}
dev->fmt_cap_rect = fmt;
tpg_s_buf_height(&dev->tpg, fmt.height);
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 61ae884ea59a..7c269f3159ef 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -609,8 +609,7 @@ static const struct dvb_tuner_ops e4000_dvb_tuner_ops = {
.get_if_frequency = e4000_dvb_get_if_frequency,
};
-static int e4000_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int e4000_probe(struct i2c_client *client)
{
struct e4000_dev *dev;
struct e4000_config *cfg = client->dev.platform_data;
@@ -730,7 +729,7 @@ static struct i2c_driver e4000_driver = {
.name = "e4000",
.suppress_bind_attrs = true,
},
- .probe = e4000_probe,
+ .probe_new = e4000_probe,
.remove = e4000_remove,
.id_table = e4000_id_table,
};
diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c
index f30932e1a0f3..3cd8279f4f2e 100644
--- a/drivers/media/tuners/fc2580.c
+++ b/drivers/media/tuners/fc2580.c
@@ -506,8 +506,7 @@ static struct v4l2_subdev *fc2580_get_v4l2_subdev(struct i2c_client *client)
return NULL;
}
-static int fc2580_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int fc2580_probe(struct i2c_client *client)
{
struct fc2580_dev *dev;
struct fc2580_platform_data *pdata = client->dev.platform_data;
@@ -611,7 +610,7 @@ static struct i2c_driver fc2580_driver = {
.name = "fc2580",
.suppress_bind_attrs = true,
},
- .probe = fc2580_probe,
+ .probe_new = fc2580_probe,
.remove = fc2580_remove,
.id_table = fc2580_id_table,
};
diff --git a/drivers/media/tuners/m88rs6000t.c b/drivers/media/tuners/m88rs6000t.c
index e32e3e9daa15..7d172a5a66d9 100644
--- a/drivers/media/tuners/m88rs6000t.c
+++ b/drivers/media/tuners/m88rs6000t.c
@@ -573,8 +573,7 @@ static const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
.get_rf_strength = m88rs6000t_get_rf_strength,
};
-static int m88rs6000t_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m88rs6000t_probe(struct i2c_client *client)
{
struct m88rs6000t_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
@@ -719,7 +718,7 @@ static struct i2c_driver m88rs6000t_driver = {
.driver = {
.name = "m88rs6000t",
},
- .probe = m88rs6000t_probe,
+ .probe_new = m88rs6000t_probe,
.remove = m88rs6000t_remove,
.id_table = m88rs6000t_id,
};
diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c
index 322c806228a5..e5d86874adb3 100644
--- a/drivers/media/tuners/mt2060.c
+++ b/drivers/media/tuners/mt2060.c
@@ -442,8 +442,7 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
}
EXPORT_SYMBOL(mt2060_attach);
-static int mt2060_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mt2060_probe(struct i2c_client *client)
{
struct mt2060_platform_data *pdata = client->dev.platform_data;
struct dvb_frontend *fe;
@@ -525,7 +524,7 @@ static struct i2c_driver mt2060_driver = {
.name = "mt2060",
.suppress_bind_attrs = true,
},
- .probe = mt2060_probe,
+ .probe_new = mt2060_probe,
.remove = mt2060_remove,
.id_table = mt2060_id_table,
};
diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
index 6422056185a9..c35442a77ae5 100644
--- a/drivers/media/tuners/mxl301rf.c
+++ b/drivers/media/tuners/mxl301rf.c
@@ -283,8 +283,7 @@ static const struct dvb_tuner_ops mxl301rf_ops = {
};
-static int mxl301rf_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mxl301rf_probe(struct i2c_client *client)
{
struct mxl301rf_state *state;
struct mxl301rf_config *cfg;
@@ -327,7 +326,7 @@ static struct i2c_driver mxl301rf_driver = {
.driver = {
.name = "mxl301rf",
},
- .probe = mxl301rf_probe,
+ .probe_new = mxl301rf_probe,
.remove = mxl301rf_remove,
.id_table = mxl301rf_id,
};
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
index ab4c43df9d18..3a509038c8df 100644
--- a/drivers/media/tuners/mxl5005s.c
+++ b/drivers/media/tuners/mxl5005s.c
@@ -3637,7 +3637,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
u16 status = 0;
int i;
- u8 RegAddr[] = {43, 136};
+ static const u8 RegAddr[] = {43, 136};
*count = ARRAY_SIZE(RegAddr);
diff --git a/drivers/media/tuners/qm1d1b0004.c b/drivers/media/tuners/qm1d1b0004.c
index 9cba0893207c..0b6f750c54ad 100644
--- a/drivers/media/tuners/qm1d1b0004.c
+++ b/drivers/media/tuners/qm1d1b0004.c
@@ -197,7 +197,7 @@ static const struct dvb_tuner_ops qm1d1b0004_ops = {
};
static int
-qm1d1b0004_probe(struct i2c_client *client, const struct i2c_device_id *id)
+qm1d1b0004_probe(struct i2c_client *client)
{
struct dvb_frontend *fe;
struct qm1d1b0004_config *cfg;
@@ -253,7 +253,7 @@ static struct i2c_driver qm1d1b0004_driver = {
.driver = {
.name = "qm1d1b0004",
},
- .probe = qm1d1b0004_probe,
+ .probe_new = qm1d1b0004_probe,
.remove = qm1d1b0004_remove,
.id_table = qm1d1b0004_id,
};
diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c
index 2d60bf501fb5..f9be7a721d2c 100644
--- a/drivers/media/tuners/qm1d1c0042.c
+++ b/drivers/media/tuners/qm1d1c0042.c
@@ -401,8 +401,7 @@ static const struct dvb_tuner_ops qm1d1c0042_ops = {
};
-static int qm1d1c0042_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int qm1d1c0042_probe(struct i2c_client *client)
{
struct qm1d1c0042_state *state;
struct qm1d1c0042_config *cfg;
@@ -444,7 +443,7 @@ static struct i2c_driver qm1d1c0042_driver = {
.driver = {
.name = "qm1d1c0042",
},
- .probe = qm1d1c0042_probe,
+ .probe_new = qm1d1c0042_probe,
.remove = qm1d1c0042_remove,
.id_table = qm1d1c0042_id,
};
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
index eb97711c9c68..5fdf05a97415 100644
--- a/drivers/media/tuners/tda18212.c
+++ b/drivers/media/tuners/tda18212.c
@@ -173,8 +173,7 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = {
.get_if_frequency = tda18212_get_if_frequency,
};
-static int tda18212_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda18212_probe(struct i2c_client *client)
{
struct tda18212_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
@@ -264,7 +263,7 @@ static struct i2c_driver tda18212_driver = {
.driver = {
.name = "tda18212",
},
- .probe = tda18212_probe,
+ .probe_new = tda18212_probe,
.remove = tda18212_remove,
.id_table = tda18212_id,
};
diff --git a/drivers/media/tuners/tda18250.c b/drivers/media/tuners/tda18250.c
index e404a5afad4c..66ff2d035de7 100644
--- a/drivers/media/tuners/tda18250.c
+++ b/drivers/media/tuners/tda18250.c
@@ -741,8 +741,7 @@ static const struct dvb_tuner_ops tda18250_ops = {
.sleep = tda18250_sleep,
};
-static int tda18250_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda18250_probe(struct i2c_client *client)
{
struct tda18250_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
@@ -878,7 +877,7 @@ static struct i2c_driver tda18250_driver = {
.driver = {
.name = "tda18250",
},
- .probe = tda18250_probe,
+ .probe_new = tda18250_probe,
.remove = tda18250_remove,
.id_table = tda18250_id_table,
};
diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c
index d141d000b819..ac38afd3441a 100644
--- a/drivers/media/tuners/tua9001.c
+++ b/drivers/media/tuners/tua9001.c
@@ -167,8 +167,7 @@ static const struct dvb_tuner_ops tua9001_tuner_ops = {
.get_if_frequency = tua9001_get_if_frequency,
};
-static int tua9001_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tua9001_probe(struct i2c_client *client)
{
struct tua9001_dev *dev;
struct tua9001_platform_data *pdata = client->dev.platform_data;
@@ -256,7 +255,7 @@ static struct i2c_driver tua9001_driver = {
.name = "tua9001",
.suppress_bind_attrs = true,
},
- .probe = tua9001_probe,
+ .probe_new = tua9001_probe,
.remove = tua9001_remove,
.id_table = tua9001_id_table,
};
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index 97f5e8733c2a..b0333637b747 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <media/v4l2-mc.h>
/* ------------------------------------------------------------------ */
@@ -70,6 +71,7 @@ const struct vb2_ops au0828_vbi_qops = {
.queue_setup = vbi_queue_setup,
.buf_prepare = vbi_buffer_prepare,
.buf_queue = vbi_buffer_queue,
+ .prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_vbi_streaming,
.wait_prepare = vb2_ops_wait_prepare,
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index eb303e94cceb..fd9fc43d47e0 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -915,6 +915,7 @@ static const struct vb2_ops au0828_video_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
+ .prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index cf15988dfb51..7d78ee09be5e 100644
--- a/drivers/media/usb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -975,6 +975,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
if (msg[i].addr == 0x99) {
req = 0xBE;
index = 0;
+ if (msg[i].len < 1) {
+ i = -EOPNOTSUPP;
+ break;
+ }
value = msg[i].buf[0] & 0x00ff;
length = 1;
az6027_usb_out_op(d, req, value, index, data, length);
diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
index 2defbd8b6fc1..ac06a9ab2641 100644
--- a/drivers/media/usb/dvb-usb/dib0700.h
+++ b/drivers/media/usb/dvb-usb/dib0700.h
@@ -72,7 +72,6 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_device_count;
-extern int dvb_usb_dib0700_ir_proto;
extern struct dvb_usb_device_properties dib0700_devices[];
extern struct usb_device_id dib0700_usb_id_table[];
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 7f8bebfa3e8e..3af594134a6d 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -2024,13 +2024,6 @@ static struct dib0090_config tfe8096p_dib0090_config = {
.force_cband_input = 0,
};
-struct dibx090p_adc {
- u32 freq; /* RF freq MHz */
- u32 timf; /* New Timf */
- u32 pll_loopdiv; /* New prediv */
- u32 pll_prediv; /* New loopdiv */
-};
-
struct dibx090p_best_adc {
u32 timf;
u32 pll_loopdiv;
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 61439c8f33ca..fbf58012becd 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -81,7 +81,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
ret = dvb_usb_adapter_stream_init(adap);
if (ret)
- return ret;
+ goto stream_init_err;
ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs);
if (ret)
@@ -92,7 +92,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
goto frontend_init_err;
/* use exclusive FE lock if there is multiple shared FEs */
- if (adap->fe_adap[1].fe)
+ if (adap->fe_adap[1].fe && adap->dvb_adap.mfe_shared < 1)
adap->dvb_adap.mfe_shared = 1;
d->num_adapters_initialized++;
@@ -114,6 +114,8 @@ frontend_init_err:
dvb_usb_adapter_dvb_exit(adap);
dvb_init_err:
dvb_usb_adapter_stream_exit(adap);
+stream_init_err:
+ kfree(adap->priv);
return ret;
}
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 548199cd86f6..fea5bcf72a31 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -485,14 +485,14 @@ static int m920x_identify_state(struct usb_device *udev,
static int m920x_mt352_demod_init(struct dvb_frontend *fe)
{
int ret;
- u8 config[] = { CONFIG, 0x3d };
- u8 clock[] = { CLOCK_CTL, 0x30 };
- u8 reset[] = { RESET, 0x80 };
- u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
- u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
- u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
- u8 unk1[] = { 0x93, 0x1a };
- u8 unk2[] = { 0xb5, 0x7a };
+ static const u8 config[] = { CONFIG, 0x3d };
+ static const u8 clock[] = { CLOCK_CTL, 0x30 };
+ static const u8 reset[] = { RESET, 0x80 };
+ static const u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
+ static const u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
+ static const u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
+ static const u8 unk1[] = { 0x93, 0x1a };
+ static const u8 unk2[] = { 0xb5, 0x7a };
deb("Demod init!\n");
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 185e89c18d68..9fce59979e3b 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1204,6 +1204,12 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev)
/* attach SEC */
a8293_pdata.dvb_frontend = dvb->fe[0];
+ /*
+ * 461e has a tendency to have vIN undervoltage troubles.
+ * Slew mitigates this.
+ */
+ a8293_pdata.volt_slew_nanos_per_mv = 20;
+
dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
&dev->i2c_adap[dev->def_i2c_bus],
0x08, &a8293_pdata);
diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c
index 2f45188bf9d4..29dfcc6d0b0a 100644
--- a/drivers/media/usb/go7007/s2250-board.c
+++ b/drivers/media/usb/go7007/s2250-board.c
@@ -494,8 +494,7 @@ static const struct v4l2_subdev_ops s2250_ops = {
/* --------------------------------------------------------------------------*/
-static int s2250_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int s2250_probe(struct i2c_client *client)
{
struct i2c_client *audio;
struct i2c_adapter *adapter = client->adapter;
@@ -621,7 +620,7 @@ static struct i2c_driver s2250_driver = {
.driver = {
.name = "s2250",
},
- .probe = s2250_probe,
+ .probe_new = s2250_probe,
.remove = s2250_remove,
.id_table = s2250_id,
};
diff --git a/drivers/media/usb/pwc/pwc-uncompress.c b/drivers/media/usb/pwc/pwc-uncompress.c
index faf44cdeb268..cf2591a9675c 100644
--- a/drivers/media/usb/pwc/pwc-uncompress.c
+++ b/drivers/media/usb/pwc/pwc-uncompress.c
@@ -39,7 +39,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
* first 3 bytes is filled (Nala case). We can
* determine this using the type of the webcam */
memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
- memcpy(raw_frame+1, yuv, pdev->frame_size);
+ memcpy(raw_frame->rawframe, yuv, pdev->frame_size);
vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0,
struct_size(raw_frame, rawframe, pdev->frame_size));
return 0;
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 215fb483efb0..e4bcb5011360 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1266,12 +1266,9 @@ static int uvc_gpio_parse(struct uvc_device *dev)
return PTR_ERR_OR_ZERO(gpio_privacy);
irq = gpiod_to_irq(gpio_privacy);
- if (irq < 0) {
- if (irq != EPROBE_DEFER)
- dev_err(&dev->udev->dev,
- "No IRQ for privacy GPIO (%d)\n", irq);
- return irq;
- }
+ if (irq < 0)
+ return dev_err_probe(&dev->udev->dev, irq,
+ "No IRQ for privacy GPIO\n");
unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1);
if (!unit)
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 33162dc1daf6..1c0d23c52203 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -614,7 +614,6 @@ static void tuner_lookup(struct i2c_adapter *adap,
*tuner_probe - Probes the existing tuners on an I2C bus
*
* @client: i2c_client descriptor
- * @id: not used
*
* This routine probes for tuners at the expected I2C addresses. On most
* cases, if a device answers to a given I2C address, it assumes that the
@@ -625,8 +624,7 @@ static void tuner_lookup(struct i2c_adapter *adap,
* During client attach, set_type is called by adapter's attach_inform callback.
* set_type must then be completed by tuner_probe.
*/
-static int tuner_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tuner_probe(struct i2c_client *client)
{
struct tuner *t;
struct tuner *radio;
@@ -1413,7 +1411,7 @@ static struct i2c_driver tuner_driver = {
.name = "tuner",
.pm = &tuner_pm_ops,
},
- .probe = tuner_probe,
+ .probe_new = tuner_probe,
.remove = tuner_remove,
.command = tuner_command,
.id_table = tuner_id,
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 0dab1d7b90f0..29169170880a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -1827,7 +1827,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
- if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) {
+ if ((!qmenu && !qmenu_int) || (qmenu_int && max >= qmenu_int_len)) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index e22921e7ea61..564fedee2c88 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -1043,6 +1043,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size";
case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation";
case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation";
+ case V4L2_CID_HDR_SENSOR_MODE: return "HDR Sensor Mode";
/* FM Radio Modulator controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -1370,6 +1371,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_STATELESS_H264_START_CODE:
case V4L2_CID_CAMERA_ORIENTATION:
case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE:
+ case V4L2_CID_HDR_SENSOR_MODE:
*type = V4L2_CTRL_TYPE_MENU;
break;
case V4L2_CID_LINK_FREQ:
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index 003c32fed3f7..942d0005c55e 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -145,6 +145,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
const struct v4l2_bt_timings *bt = &t->bt;
const struct v4l2_bt_timings_cap *cap = &dvcap->bt;
u32 caps = cap->capabilities;
+ const u32 max_vert = 10240;
+ u32 max_hor = 3 * bt->width;
if (t->type != V4L2_DV_BT_656_1120)
return false;
@@ -166,14 +168,20 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
if (!bt->interlaced &&
(bt->il_vbackporch || bt->il_vsync || bt->il_vfrontporch))
return false;
- if (bt->hfrontporch > 2 * bt->width ||
- bt->hsync > 1024 || bt->hbackporch > 1024)
+ /*
+ * Some video receivers cannot properly separate the frontporch,
+ * backporch and sync values, and instead they only have the total
+ * blanking. That can be assigned to any of these three fields.
+ * So just check that none of these are way out of range.
+ */
+ if (bt->hfrontporch > max_hor ||
+ bt->hsync > max_hor || bt->hbackporch > max_hor)
return false;
- if (bt->vfrontporch > 4096 ||
- bt->vsync > 128 || bt->vbackporch > 4096)
+ if (bt->vfrontporch > max_vert ||
+ bt->vsync > max_vert || bt->vbackporch > max_vert)
return false;
- if (bt->interlaced && (bt->il_vfrontporch > 4096 ||
- bt->il_vsync > 128 || bt->il_vbackporch > 4096))
+ if (bt->interlaced && (bt->il_vfrontporch > max_vert ||
+ bt->il_vsync > max_vert || bt->il_vbackporch > max_vert))
return false;
return fnc == NULL || fnc(t, fnc_handle);
}
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 3d85a8600f57..3d9533c1b202 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -298,10 +298,25 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING);
- flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
- V4L2_MBUS_PCLK_SAMPLE_FALLING;
- pr_debug("pclk-sample %s\n", v ? "high" : "low");
+ V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_PCLK_SAMPLE_DUALEDGE);
+ switch (v) {
+ case 0:
+ flags |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ pr_debug("pclk-sample low\n");
+ break;
+ case 1:
+ flags |= V4L2_MBUS_PCLK_SAMPLE_RISING;
+ pr_debug("pclk-sample high\n");
+ break;
+ case 2:
+ flags |= V4L2_MBUS_PCLK_SAMPLE_DUALEDGE;
+ pr_debug("pclk-sample dual edge\n");
+ break;
+ default:
+ pr_warn("invalid argument for pclk-sample");
+ break;
+ }
}
if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index fddba75d9074..8e0a0ff62a70 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -31,12 +31,6 @@
#include <trace/events/v4l2.h>
-/* Zero out the end of the struct pointed to by p. Everything after, but
- * not including, the specified field is cleared. */
-#define CLEAR_AFTER_FIELD(p, field) \
- memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
- 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
-
#define is_valid_ioctl(vfd, cmd) test_bit(_IOC_NR(cmd), (vfd)->valid_ioctls)
struct std_descr {
@@ -1347,23 +1341,23 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break;
case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break;
case V4L2_PIX_FMT_M420: descr = "YUV 4:2:0 (M420)"; break;
- case V4L2_PIX_FMT_NV12: descr = "Y/CbCr 4:2:0"; break;
- case V4L2_PIX_FMT_NV21: descr = "Y/CrCb 4:2:0"; break;
- case V4L2_PIX_FMT_NV16: descr = "Y/CbCr 4:2:2"; break;
- case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break;
- case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break;
- case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break;
- case V4L2_PIX_FMT_P010: descr = "10-bit Y/CbCr 4:2:0"; break;
- case V4L2_PIX_FMT_NV12_4L4: descr = "Y/CbCr 4:2:0 (4x4 Linear)"; break;
- case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break;
- case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break;
- case V4L2_PIX_FMT_P010_4L4: descr = "10-bit Y/CbCr 4:2:0 (4x4 Linear)"; break;
- case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break;
- case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break;
- case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break;
- case V4L2_PIX_FMT_NV61M: descr = "Y/CrCb 4:2:2 (N-C)"; break;
- case V4L2_PIX_FMT_NV12MT: descr = "Y/CbCr 4:2:0 (64x32 MB, N-C)"; break;
- case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/CbCr 4:2:0 (16x16 MB, N-C)"; break;
+ case V4L2_PIX_FMT_NV12: descr = "Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_NV21: descr = "Y/VU 4:2:0"; break;
+ case V4L2_PIX_FMT_NV16: descr = "Y/UV 4:2:2"; break;
+ case V4L2_PIX_FMT_NV61: descr = "Y/VU 4:2:2"; break;
+ case V4L2_PIX_FMT_NV24: descr = "Y/UV 4:4:4"; break;
+ case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break;
+ case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break;
+ case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break;
+ case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break;
+ case V4L2_PIX_FMT_P010_4L4: descr = "10-bit Y/UV 4:2:0 (4x4 Linear)"; break;
+ case V4L2_PIX_FMT_NV12M: descr = "Y/UV 4:2:0 (N-C)"; break;
+ case V4L2_PIX_FMT_NV21M: descr = "Y/VU 4:2:0 (N-C)"; break;
+ case V4L2_PIX_FMT_NV16M: descr = "Y/UV 4:2:2 (N-C)"; break;
+ case V4L2_PIX_FMT_NV61M: descr = "Y/VU 4:2:2 (N-C)"; break;
+ case V4L2_PIX_FMT_NV12MT: descr = "Y/UV 4:2:0 (64x32 MB, N-C)"; break;
+ case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/UV 4:2:0 (16x16 MB, N-C)"; break;
case V4L2_PIX_FMT_YUV420M: descr = "Planar YUV 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YVU420M: descr = "Planar YVU 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YUV422M: descr = "Planar YUV 4:2:2 (N-C)"; break;
@@ -1444,7 +1438,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break;
case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break;
case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break;
+ case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break;
case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break;
+ case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break;
case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break;
default:
@@ -1497,6 +1493,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break;
case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break;
case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
+ case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break;
default:
if (fmt->description[0])
return;
@@ -1530,7 +1527,7 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
p->mbus_code = 0;
mbus_code = p->mbus_code;
- CLEAR_AFTER_FIELD(p, type);
+ memset_after(p, 0, type);
p->mbus_code = mbus_code;
switch (p->type) {
@@ -1705,7 +1702,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_vid_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix);
+ memset_after(p, 0, fmt.pix);
ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
@@ -1715,30 +1712,30 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ memset_after(p, 0, fmt.pix_mp.xfer_func);
for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
- CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i],
- bytesperline);
+ memset_after(&p->fmt.pix_mp.plane_fmt[i],
+ 0, bytesperline);
return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
break;
- CLEAR_AFTER_FIELD(p, fmt.win);
+ memset_after(p, 0, fmt.win);
return ops->vidioc_s_fmt_vid_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ memset_after(p, 0, fmt.vbi.flags);
return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ memset_after(p, 0, fmt.sliced.io_size);
return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_vid_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix);
+ memset_after(p, 0, fmt.pix);
ret = ops->vidioc_s_fmt_vid_out(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
@@ -1746,45 +1743,45 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ memset_after(p, 0, fmt.pix_mp.xfer_func);
for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
- CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i],
- bytesperline);
+ memset_after(&p->fmt.pix_mp.plane_fmt[i],
+ 0, bytesperline);
return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
break;
- CLEAR_AFTER_FIELD(p, fmt.win);
+ memset_after(p, 0, fmt.win);
return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_vbi_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ memset_after(p, 0, fmt.vbi.flags);
return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ memset_after(p, 0, fmt.sliced.io_size);
return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
case V4L2_BUF_TYPE_SDR_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_sdr_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ memset_after(p, 0, fmt.sdr.buffersize);
return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
case V4L2_BUF_TYPE_SDR_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_sdr_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ memset_after(p, 0, fmt.sdr.buffersize);
return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
case V4L2_BUF_TYPE_META_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_meta_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.meta);
+ memset_after(p, 0, fmt.meta);
return ops->vidioc_s_fmt_meta_cap(file, fh, arg);
case V4L2_BUF_TYPE_META_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_meta_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.meta);
+ memset_after(p, 0, fmt.meta);
return ops->vidioc_s_fmt_meta_out(file, fh, arg);
}
return -EINVAL;
@@ -1807,7 +1804,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_vid_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix);
+ memset_after(p, 0, fmt.pix);
ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
@@ -1817,30 +1814,30 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ memset_after(p, 0, fmt.pix_mp.xfer_func);
for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
- CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i],
- bytesperline);
+ memset_after(&p->fmt.pix_mp.plane_fmt[i],
+ 0, bytesperline);
return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
break;
- CLEAR_AFTER_FIELD(p, fmt.win);
+ memset_after(p, 0, fmt.win);
return ops->vidioc_try_fmt_vid_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ memset_after(p, 0, fmt.vbi.flags);
return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ memset_after(p, 0, fmt.sliced.io_size);
return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_vid_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix);
+ memset_after(p, 0, fmt.pix);
ret = ops->vidioc_try_fmt_vid_out(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
@@ -1848,45 +1845,45 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane))
break;
- CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ memset_after(p, 0, fmt.pix_mp.xfer_func);
for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
- CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i],
- bytesperline);
+ memset_after(&p->fmt.pix_mp.plane_fmt[i],
+ 0, bytesperline);
return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg);
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
break;
- CLEAR_AFTER_FIELD(p, fmt.win);
+ memset_after(p, 0, fmt.win);
return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_vbi_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ memset_after(p, 0, fmt.vbi.flags);
return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ memset_after(p, 0, fmt.sliced.io_size);
return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
case V4L2_BUF_TYPE_SDR_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_sdr_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ memset_after(p, 0, fmt.sdr.buffersize);
return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
case V4L2_BUF_TYPE_SDR_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_sdr_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ memset_after(p, 0, fmt.sdr.buffersize);
return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
case V4L2_BUF_TYPE_META_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_meta_cap))
break;
- CLEAR_AFTER_FIELD(p, fmt.meta);
+ memset_after(p, 0, fmt.meta);
return ops->vidioc_try_fmt_meta_cap(file, fh, arg);
case V4L2_BUF_TYPE_META_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_meta_out))
break;
- CLEAR_AFTER_FIELD(p, fmt.meta);
+ memset_after(p, 0, fmt.meta);
return ops->vidioc_try_fmt_meta_out(file, fh, arg);
}
return -EINVAL;
@@ -2085,7 +2082,7 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- CLEAR_AFTER_FIELD(p, flags);
+ memset_after(p, 0, flags);
return ops->vidioc_reqbufs(file, fh, p);
}
@@ -2126,7 +2123,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- CLEAR_AFTER_FIELD(create, flags);
+ memset_after(create, 0, flags);
v4l_sanitize_format(&create->format);
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 5c27bac772ea..4988a25bd8f4 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -318,6 +318,20 @@ static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
sd->ops->pad->get_mbus_config(sd, pad, config);
}
+static int call_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret;
+
+ ret = sd->ops->video->s_stream(sd, enable);
+
+ if (!enable && ret < 0) {
+ dev_warn(sd->dev, "disabling streaming failed (%d)\n", ret);
+ return 0;
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_MEDIA_CONTROLLER
/*
* Create state-management wrapper for pad ops dealing with subdev state. The
@@ -377,6 +391,7 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
.g_frame_interval = call_g_frame_interval,
.s_frame_interval = call_s_frame_interval,
+ .s_stream = call_s_stream,
};
const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = {
@@ -845,7 +860,7 @@ int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity,
fwnode = fwnode_graph_get_port_parent(endpoint->local_fwnode);
fwnode_handle_put(fwnode);
- if (dev_fwnode(sd->dev) == fwnode)
+ if (device_match_fwnode(sd->dev, fwnode))
return endpoint->port;
return -ENXIO;
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 52312ce2ba05..f2c439359557 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -36,12 +36,11 @@ struct videobuf_dma_contig_memory {
static int __videobuf_dc_alloc(struct device *dev,
struct videobuf_dma_contig_memory *mem,
- unsigned long size, gfp_t flags)
+ unsigned long size)
{
mem->size = size;
- mem->vaddr = dma_alloc_coherent(dev, mem->size,
- &mem->dma_handle, flags);
-
+ mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle,
+ GFP_KERNEL);
if (!mem->vaddr) {
dev_err(dev, "memory alloc size %ld failed\n", mem->size);
return -ENOMEM;
@@ -258,8 +257,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
return videobuf_dma_contig_user_get(mem, vb);
/* allocate memory for the read() method */
- if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
- GFP_KERNEL))
+ if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size)))
return -ENOMEM;
break;
case V4L2_MEMORY_OVERLAY:
@@ -295,22 +293,18 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
- if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
- GFP_KERNEL | __GFP_COMP))
+ if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize)))
goto error;
- /* Try to remap memory */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
/* the "vm_pgoff" is just used in v4l2 to find the
* corresponding buffer data structure which is allocated
* earlier and it does not mean the offset from the physical
* buffer start address as usual. So set it to 0 to pass
- * the sanity check in vm_iomap_memory().
+ * the sanity check in dma_mmap_coherent().
*/
vma->vm_pgoff = 0;
-
- retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
+ retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
+ mem->size);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ",
retval);
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 2351f2708da2..57d9f91fe89b 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -134,6 +134,7 @@
#define GPMC_CONFIG_DEV_SIZE 0x00000002
#define GPMC_CONFIG_DEV_TYPE 0x00000003
+#define GPMC_CONFIG_WAITPINPOLARITY(pin) (BIT(pin) << 8)
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
@@ -229,6 +230,12 @@ struct omap3_gpmc_regs {
struct gpmc_cs_config cs_context[GPMC_CS_NUM];
};
+struct gpmc_waitpin {
+ u32 pin;
+ u32 polarity;
+ struct gpio_desc *desc;
+};
+
struct gpmc_device {
struct device *dev;
int irq;
@@ -236,6 +243,7 @@ struct gpmc_device {
struct gpio_chip gpio_chip;
struct notifier_block nb;
struct omap3_gpmc_regs context;
+ struct gpmc_waitpin *waitpins;
int nirqs;
unsigned int is_suspended:1;
struct resource *data;
@@ -1035,6 +1043,62 @@ void gpmc_cs_free(int cs)
}
EXPORT_SYMBOL(gpmc_cs_free);
+static bool gpmc_is_valid_waitpin(u32 waitpin)
+{
+ return waitpin < gpmc_nr_waitpins;
+}
+
+static int gpmc_alloc_waitpin(struct gpmc_device *gpmc,
+ struct gpmc_settings *p)
+{
+ int ret;
+ struct gpmc_waitpin *waitpin;
+ struct gpio_desc *waitpin_desc;
+
+ if (!gpmc_is_valid_waitpin(p->wait_pin))
+ return -EINVAL;
+
+ waitpin = &gpmc->waitpins[p->wait_pin];
+
+ if (!waitpin->desc) {
+ /* Reserve the GPIO for wait pin usage.
+ * GPIO polarity doesn't matter here. Wait pin polarity
+ * is set in GPMC_CONFIG register.
+ */
+ waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
+ p->wait_pin, "WAITPIN",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_IN);
+
+ ret = PTR_ERR(waitpin_desc);
+ if (IS_ERR(waitpin_desc) && ret != -EBUSY)
+ return ret;
+
+ /* New wait pin */
+ waitpin->desc = waitpin_desc;
+ waitpin->pin = p->wait_pin;
+ waitpin->polarity = p->wait_pin_polarity;
+ } else {
+ /* Shared wait pin */
+ if (p->wait_pin_polarity != waitpin->polarity ||
+ p->wait_pin != waitpin->pin) {
+ dev_err(gpmc->dev,
+ "shared-wait-pin: invalid configuration\n");
+ return -EINVAL;
+ }
+ dev_info(gpmc->dev, "shared wait-pin: %d\n", waitpin->pin);
+ }
+
+ return 0;
+}
+
+static void gpmc_free_waitpin(struct gpmc_device *gpmc,
+ int wait_pin)
+{
+ if (gpmc_is_valid_waitpin(wait_pin))
+ gpiochip_free_own_desc(gpmc->waitpins[wait_pin].desc);
+}
+
/**
* gpmc_configure - write request to configure gpmc
* @cmd: command type
@@ -1886,6 +1950,17 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
+ if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_INVALID) {
+ config1 = gpmc_read_reg(GPMC_CONFIG);
+
+ if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_LOW)
+ config1 &= ~GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);
+ else if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_HIGH)
+ config1 |= GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);
+
+ gpmc_write_reg(GPMC_CONFIG, config1);
+ }
+
return 0;
}
@@ -1975,7 +2050,25 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
__func__);
}
+ p->wait_pin = GPMC_WAITPIN_INVALID;
+ p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;
+
if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
+ if (!gpmc_is_valid_waitpin(p->wait_pin)) {
+ pr_err("%s: Invalid wait-pin (%d)\n", __func__, p->wait_pin);
+ p->wait_pin = GPMC_WAITPIN_INVALID;
+ }
+
+ if (!of_property_read_u32(np, "ti,wait-pin-polarity",
+ &p->wait_pin_polarity)) {
+ if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_HIGH &&
+ p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_LOW) {
+ pr_err("%s: Invalid wait-pin-polarity (%d)\n",
+ __func__, p->wait_pin_polarity);
+ p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;
+ }
+ }
+
p->wait_on_read = of_property_read_bool(np,
"gpmc,wait-on-read");
p->wait_on_write = of_property_read_bool(np,
@@ -2080,7 +2173,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
const char *name;
int ret, cs;
u32 val;
- struct gpio_desc *waitpin_desc = NULL;
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
if (of_property_read_u32(child, "reg", &cs) < 0) {
@@ -2208,17 +2300,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
/* Reserve wait pin if it is required and valid */
if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
- unsigned int wait_pin = gpmc_s.wait_pin;
-
- waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
- wait_pin, "WAITPIN",
- GPIO_ACTIVE_HIGH,
- GPIOD_IN);
- if (IS_ERR(waitpin_desc)) {
- dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
- ret = PTR_ERR(waitpin_desc);
+ ret = gpmc_alloc_waitpin(gpmc, &gpmc_s);
+ if (ret < 0)
goto err;
- }
}
gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
@@ -2260,7 +2344,7 @@ err_child_fail:
ret = -ENODEV;
err_cs:
- gpiochip_free_own_desc(waitpin_desc);
+ gpmc_free_waitpin(gpmc, gpmc_s.wait_pin);
err:
gpmc_cs_free(cs);
@@ -2489,7 +2573,7 @@ static int omap_gpmc_context_notifier(struct notifier_block *nb,
static int gpmc_probe(struct platform_device *pdev)
{
- int rc;
+ int rc, i;
u32 l;
struct resource *res;
struct gpmc_device *gpmc;
@@ -2545,6 +2629,15 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
}
+ gpmc->waitpins = devm_kzalloc(&pdev->dev,
+ gpmc_nr_waitpins * sizeof(struct gpmc_waitpin),
+ GFP_KERNEL);
+ if (!gpmc->waitpins)
+ return -ENOMEM;
+
+ for (i = 0; i < gpmc_nr_waitpins; i++)
+ gpmc->waitpins[i].pin = GPMC_WAITPIN_INVALID;
+
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -2598,9 +2691,12 @@ gpio_init_failed:
static int gpmc_remove(struct platform_device *pdev)
{
+ int i;
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&gpmc->nb);
+ for (i = 0; i < gpmc_nr_waitpins; i++)
+ gpmc_free_waitpin(gpmc, i);
gpmc_free_irq(gpmc);
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
index 4316988d791a..09cd4318a83d 100644
--- a/drivers/memory/renesas-rpc-if.c
+++ b/drivers/memory/renesas-rpc-if.c
@@ -136,7 +136,8 @@
#define RPCIF_PHYCNT_DDRCAL BIT(19)
#define RPCIF_PHYCNT_HS BIT(18)
#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */
-#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15) /* valid for R-Car and RZ/G2{E,H,M,N} */
+#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */
+
#define RPCIF_PHYCNT_WBUF2 BIT(4)
#define RPCIF_PHYCNT_WBUF BIT(2)
#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0)
@@ -317,9 +318,15 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_PHYMEM_MASK,
RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0));
+ /* DMA Transfer is not supported */
+ regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_HS, 0);
+
if (rpc->type == RPCIF_RCAR_GEN3)
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
RPCIF_PHYCNT_STRTIM(7), RPCIF_PHYCNT_STRTIM(7));
+ else if (rpc->type == RPCIF_RCAR_GEN4)
+ regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
+ RPCIF_PHYCNT_STRTIM(15), RPCIF_PHYCNT_STRTIM(15));
regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET1, RPCIF_PHYOFFSET1_DDRTMG(3),
RPCIF_PHYOFFSET1_DDRTMG(3));
@@ -330,17 +337,17 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
regmap_update_bits(rpc->regmap, RPCIF_PHYINT,
RPCIF_PHYINT_WPVAL, 0);
- if (rpc->type == RPCIF_RCAR_GEN3)
- regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
- RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3),
- RPCIF_CMNCR_MOIIO(3) |
- RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
- else
+ if (rpc->type == RPCIF_RZ_G2L)
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) |
RPCIF_CMNCR_BSZ(3),
RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) |
RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
+ else
+ regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
+ RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3),
+ RPCIF_CMNCR_MOIIO(3) |
+ RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
/* Set RCF after BSZ update */
regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF);
@@ -715,6 +722,7 @@ static int rpcif_remove(struct platform_device *pdev)
static const struct of_device_id rpcif_of_match[] = {
{ .compatible = "renesas,rcar-gen3-rpc-if", .data = (void *)RPCIF_RCAR_GEN3 },
+ { .compatible = "renesas,rcar-gen4-rpc-if", .data = (void *)RPCIF_RCAR_GEN4 },
{ .compatible = "renesas,rzg2l-rpc-if", .data = (void *)RPCIF_RZ_G2L },
{},
};
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 2f7a58a9df1a..592907546ee6 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -107,6 +107,31 @@ int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
}
EXPORT_SYMBOL_GPL(tegra_mc_probe_device);
+int tegra_mc_get_carveout_info(struct tegra_mc *mc, unsigned int id,
+ phys_addr_t *base, u64 *size)
+{
+ u32 offset;
+
+ if (id < 1 || id >= mc->soc->num_carveouts)
+ return -EINVAL;
+
+ if (id < 6)
+ offset = 0xc0c + 0x50 * (id - 1);
+ else
+ offset = 0x2004 + 0x50 * (id - 6);
+
+ *base = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, offset + 0x0);
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ *base |= (phys_addr_t)mc_ch_readl(mc, MC_BROADCAST_CHANNEL, offset + 0x4) << 32;
+#endif
+
+ if (size)
+ *size = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, offset + 0x8) << 17;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_mc_get_carveout_info);
+
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index 54b47ca33483..26e763bde92a 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -84,20 +84,7 @@ static int tegra186_emc_debug_available_rates_show(struct seq_file *s,
return 0;
}
-
-static int tegra186_emc_debug_available_rates_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, tegra186_emc_debug_available_rates_show,
- inode->i_private);
-}
-
-static const struct file_operations tegra186_emc_debug_available_rates_fops = {
- .open = tegra186_emc_debug_available_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra186_emc_debug_available_rates);
static int tegra186_emc_debug_min_rate_get(void *data, u64 *rate)
{
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
index 25ba3c5e4ad6..bd4e37b6552d 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -841,20 +841,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data)
return 0;
}
-
-static int tegra_emc_debug_available_rates_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, tegra_emc_debug_available_rates_show,
- inode->i_private);
-}
-
-static const struct file_operations tegra_emc_debug_available_rates_fops = {
- .open = tegra_emc_debug_available_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
{
diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index cbe1a7723514..ae5f982f861b 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -1621,20 +1621,7 @@ static int tegra210_emc_debug_available_rates_show(struct seq_file *s,
return 0;
}
-
-static int tegra210_emc_debug_available_rates_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, tegra210_emc_debug_available_rates_show,
- inode->i_private);
-}
-
-static const struct file_operations tegra210_emc_debug_available_rates_fops = {
- .open = tegra210_emc_debug_available_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra210_emc_debug_available_rates);
static int tegra210_emc_debug_min_rate_get(void *data, u64 *rate)
{
diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c
index a9e8fd99730f..02dcc5748bba 100644
--- a/drivers/memory/tegra/tegra234.c
+++ b/drivers/memory/tegra/tegra234.c
@@ -170,6 +170,166 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.security = 0x504,
},
},
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
+ .name = "dla0rda",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x5f0,
+ .security = 0x5f4,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB,
+ .name = "dla0falrdb",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x5f8,
+ .security = 0x5fc,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0WRA,
+ .name = "dla0wra",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x600,
+ .security = 0x604,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0RDB,
+ .name = "dla0rdb",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x160,
+ .security = 0x164,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1,
+ .name = "dla0rda1",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x748,
+ .security = 0x74c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB,
+ .name = "dla0falwrb",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x608,
+ .security = 0x60c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1,
+ .name = "dla0rdb1",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x168,
+ .security = 0x16c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA0WRB,
+ .name = "dla0wrb",
+ .sid = TEGRA234_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x170,
+ .security = 0x174,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1RDA,
+ .name = "dla0rda",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x610,
+ .security = 0x614,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB,
+ .name = "dla0falrdb",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x618,
+ .security = 0x61c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1WRA,
+ .name = "dla0wra",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x620,
+ .security = 0x624,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1RDB,
+ .name = "dla0rdb",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x178,
+ .security = 0x17c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1,
+ .name = "dla0rda1",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x750,
+ .security = 0x754,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB,
+ .name = "dla0falwrb",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x628,
+ .security = 0x62c,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1,
+ .name = "dla0rdb1",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x370,
+ .security = 0x374,
+ },
+ },
+ }, {
+ .id = TEGRA234_MEMORY_CLIENT_DLA1WRB,
+ .name = "dla0wrb",
+ .sid = TEGRA234_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x378,
+ .security = 0x37c,
+ },
+ },
},
};
@@ -187,4 +347,9 @@ const struct tegra_mc_soc tegra234_mc_soc = {
.ops = &tegra186_mc_ops,
.ch_intmask = 0x0000ff00,
.global_intstatus_channel_shift = 8,
+ /*
+ * Additionally, there are lite carveouts but those are not currently
+ * supported.
+ */
+ .num_carveouts = 32,
};
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 9ba2a9e5316b..77706e9bc543 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -1359,20 +1359,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data)
return 0;
}
-
-static int tegra_emc_debug_available_rates_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, tegra_emc_debug_available_rates_show,
- inode->i_private);
-}
-
-static const struct file_operations tegra_emc_debug_available_rates_fops = {
- .open = tegra_emc_debug_available_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
{
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 7ff0b63c25e3..0f467a71b069 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-resv.h>
#include <linux/idr.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
@@ -310,8 +311,8 @@ static void fastrpc_free_map(struct kref *ref)
return;
}
}
- dma_buf_unmap_attachment(map->attach, map->table,
- DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(map->attach, map->table,
+ DMA_BIDIRECTIONAL);
dma_buf_detach(map->buf, map->attach);
dma_buf_put(map->buf);
}
@@ -682,6 +683,8 @@ static int fastrpc_mmap(struct dma_buf *dmabuf,
struct fastrpc_buf *buf = dmabuf->priv;
size_t size = vma->vm_end - vma->vm_start;
+ dma_resv_assert_held(dmabuf->resv);
+
return dma_mmap_coherent(buf->dev, vma, buf->virt,
FASTRPC_PHYS(buf->phys), size);
}
@@ -726,7 +729,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
goto attach_err;
}
- map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL);
+ map->table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL);
if (IS_ERR(map->table)) {
err = PTR_ERR(map->table);
goto map_err;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 46aa3554e97b..1fbe127ff633 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
+#include <linux/scatterlist.h>
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
@@ -100,9 +101,18 @@ ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
cb->internal = !!(mode & MEI_CL_IO_TX_INTERNAL);
cb->blocking = !!(mode & MEI_CL_IO_TX_BLOCKING);
memcpy(cb->buf.data, buf, length);
+ /* hack we point data to header */
+ if (mode & MEI_CL_IO_SGL) {
+ cb->ext_hdr = (struct mei_ext_hdr *)cb->buf.data;
+ cb->buf.data = NULL;
+ cb->buf.size = 0;
+ }
rets = mei_cl_write(cl, cb);
+ if (mode & MEI_CL_IO_SGL && rets == 0)
+ rets = length;
+
out:
mutex_unlock(&bus->device_lock);
@@ -205,9 +215,16 @@ copy:
goto free;
}
- r_length = min_t(size_t, length, cb->buf_idx);
- memcpy(buf, cb->buf.data, r_length);
+ /* for the GSC type - copy the extended header to the buffer */
+ if (cb->ext_hdr && cb->ext_hdr->type == MEI_EXT_HDR_GSC) {
+ r_length = min_t(size_t, length, cb->ext_hdr->length * sizeof(u32));
+ memcpy(buf, cb->ext_hdr, r_length);
+ } else {
+ r_length = min_t(size_t, length, cb->buf_idx);
+ memcpy(buf, cb->buf.data, r_length);
+ }
rets = r_length;
+
if (vtag)
*vtag = cb->vtag;
@@ -823,6 +840,131 @@ out:
EXPORT_SYMBOL_GPL(mei_cldev_disable);
/**
+ * mei_cldev_send_gsc_command - sends a gsc command, by sending
+ * a gsl mei message to gsc and receiving reply from gsc
+ *
+ * @cldev: me client device
+ * @client_id: client id to send the command to
+ * @fence_id: fence id to send the command to
+ * @sg_in: scatter gather list containing addresses for rx message buffer
+ * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes
+ * @sg_out: scatter gather list containing addresses for tx message buffer
+ *
+ * Return:
+ * * written size in bytes
+ * * < 0 on error
+ */
+ssize_t mei_cldev_send_gsc_command(struct mei_cl_device *cldev,
+ u8 client_id, u32 fence_id,
+ struct scatterlist *sg_in,
+ size_t total_in_len,
+ struct scatterlist *sg_out)
+{
+ struct mei_cl *cl;
+ struct mei_device *bus;
+ ssize_t ret = 0;
+
+ struct mei_ext_hdr_gsc_h2f *ext_hdr;
+ size_t buf_sz = sizeof(struct mei_ext_hdr_gsc_h2f);
+ int sg_out_nents, sg_in_nents;
+ int i;
+ struct scatterlist *sg;
+ struct mei_ext_hdr_gsc_f2h rx_msg;
+ unsigned int sg_len;
+
+ if (!cldev || !sg_in || !sg_out)
+ return -EINVAL;
+
+ cl = cldev->cl;
+ bus = cldev->bus;
+
+ dev_dbg(bus->dev, "client_id %u, fence_id %u\n", client_id, fence_id);
+
+ if (!bus->hbm_f_gsc_supported)
+ return -EOPNOTSUPP;
+
+ sg_out_nents = sg_nents(sg_out);
+ sg_in_nents = sg_nents(sg_in);
+ /* at least one entry in tx and rx sgls must be present */
+ if (sg_out_nents <= 0 || sg_in_nents <= 0)
+ return -EINVAL;
+
+ buf_sz += (sg_out_nents + sg_in_nents) * sizeof(struct mei_gsc_sgl);
+ ext_hdr = kzalloc(buf_sz, GFP_KERNEL);
+ if (!ext_hdr)
+ return -ENOMEM;
+
+ /* construct the GSC message */
+ ext_hdr->hdr.type = MEI_EXT_HDR_GSC;
+ ext_hdr->hdr.length = buf_sz / sizeof(u32); /* length is in dw */
+
+ ext_hdr->client_id = client_id;
+ ext_hdr->addr_type = GSC_ADDRESS_TYPE_PHYSICAL_SGL;
+ ext_hdr->fence_id = fence_id;
+ ext_hdr->input_address_count = sg_in_nents;
+ ext_hdr->output_address_count = sg_out_nents;
+ ext_hdr->reserved[0] = 0;
+ ext_hdr->reserved[1] = 0;
+
+ /* copy in-sgl to the message */
+ for (i = 0, sg = sg_in; i < sg_in_nents; i++, sg++) {
+ ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg));
+ ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg));
+ sg_len = min_t(unsigned int, sg_dma_len(sg), PAGE_SIZE);
+ ext_hdr->sgl[i].length = (sg_len <= total_in_len) ? sg_len : total_in_len;
+ total_in_len -= ext_hdr->sgl[i].length;
+ }
+
+ /* copy out-sgl to the message */
+ for (i = sg_in_nents, sg = sg_out; i < sg_in_nents + sg_out_nents; i++, sg++) {
+ ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg));
+ ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg));
+ sg_len = min_t(unsigned int, sg_dma_len(sg), PAGE_SIZE);
+ ext_hdr->sgl[i].length = sg_len;
+ }
+
+ /* send the message to GSC */
+ ret = __mei_cl_send(cl, (u8 *)ext_hdr, buf_sz, 0, MEI_CL_IO_SGL);
+ if (ret < 0) {
+ dev_err(bus->dev, "__mei_cl_send failed, returned %zd\n", ret);
+ goto end;
+ }
+ if (ret != buf_sz) {
+ dev_err(bus->dev, "__mei_cl_send returned %zd instead of expected %zd\n",
+ ret, buf_sz);
+ ret = -EIO;
+ goto end;
+ }
+
+ /* receive the reply from GSC, note that at this point sg_in should contain the reply */
+ ret = __mei_cl_recv(cl, (u8 *)&rx_msg, sizeof(rx_msg), NULL, MEI_CL_IO_SGL, 0);
+
+ if (ret != sizeof(rx_msg)) {
+ dev_err(bus->dev, "__mei_cl_recv returned %zd instead of expected %zd\n",
+ ret, sizeof(rx_msg));
+ if (ret >= 0)
+ ret = -EIO;
+ goto end;
+ }
+
+ /* check rx_msg.client_id and rx_msg.fence_id match the ones we send */
+ if (rx_msg.client_id != client_id || rx_msg.fence_id != fence_id) {
+ dev_err(bus->dev, "received client_id/fence_id %u/%u instead of %u/%u sent\n",
+ rx_msg.client_id, rx_msg.fence_id, client_id, fence_id);
+ ret = -EFAULT;
+ goto end;
+ }
+
+ dev_dbg(bus->dev, "gsc command: successfully written %u bytes\n", rx_msg.written);
+ ret = rx_msg.written;
+
+end:
+ kfree(ext_hdr);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mei_cldev_send_gsc_command);
+
+/**
* mei_cl_device_find - find matching entry in the driver id table
*
* @cldev: me client device
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 0b2fbe1335a7..6c8b71ae32c8 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -322,6 +322,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
list_del(&cb->list);
kfree(cb->buf.data);
+ kfree(cb->ext_hdr);
kfree(cb);
}
@@ -401,6 +402,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
cb->buf_idx = 0;
cb->fop_type = type;
cb->vtag = 0;
+ cb->ext_hdr = NULL;
return cb;
}
@@ -1740,6 +1742,17 @@ static inline u8 mei_ext_hdr_set_vtag(void *ext, u8 vtag)
return vtag_hdr->hdr.length;
}
+static inline bool mei_ext_hdr_is_gsc(struct mei_ext_hdr *ext)
+{
+ return ext && ext->type == MEI_EXT_HDR_GSC;
+}
+
+static inline u8 mei_ext_hdr_set_gsc(struct mei_ext_hdr *ext, struct mei_ext_hdr *gsc_hdr)
+{
+ memcpy(ext, gsc_hdr, mei_ext_hdr_len(gsc_hdr));
+ return ext->length;
+}
+
/**
* mei_msg_hdr_init - allocate and initialize mei message header
*
@@ -1752,14 +1765,17 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
size_t hdr_len;
struct mei_ext_meta_hdr *meta;
struct mei_msg_hdr *mei_hdr;
- bool is_ext, is_vtag;
+ bool is_ext, is_hbm, is_gsc, is_vtag;
+ struct mei_ext_hdr *next_ext;
if (!cb)
return ERR_PTR(-EINVAL);
/* Extended header for vtag is attached only on the first fragment */
is_vtag = (cb->vtag && cb->buf_idx == 0);
- is_ext = is_vtag;
+ is_hbm = cb->cl->me_cl->client_id == 0;
+ is_gsc = ((!is_hbm) && cb->cl->dev->hbm_f_gsc_supported && mei_ext_hdr_is_gsc(cb->ext_hdr));
+ is_ext = is_vtag || is_gsc;
/* Compute extended header size */
hdr_len = sizeof(*mei_hdr);
@@ -1771,6 +1787,9 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
if (is_vtag)
hdr_len += sizeof(struct mei_ext_hdr_vtag);
+ if (is_gsc)
+ hdr_len += mei_ext_hdr_len(cb->ext_hdr);
+
setup_hdr:
mei_hdr = kzalloc(hdr_len, GFP_KERNEL);
if (!mei_hdr)
@@ -1785,10 +1804,20 @@ setup_hdr:
goto out;
meta = (struct mei_ext_meta_hdr *)mei_hdr->extension;
+ meta->size = 0;
+ next_ext = (struct mei_ext_hdr *)meta->hdrs;
if (is_vtag) {
meta->count++;
- meta->size += mei_ext_hdr_set_vtag(meta->hdrs, cb->vtag);
+ meta->size += mei_ext_hdr_set_vtag(next_ext, cb->vtag);
+ next_ext = mei_ext_next(next_ext);
+ }
+
+ if (is_gsc) {
+ meta->count++;
+ meta->size += mei_ext_hdr_set_gsc(next_ext, cb->ext_hdr);
+ next_ext = mei_ext_next(next_ext);
}
+
out:
mei_hdr->length = hdr_len - sizeof(*mei_hdr);
return mei_hdr;
@@ -1812,14 +1841,14 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_msg_hdr *mei_hdr = NULL;
size_t hdr_len;
size_t hbuf_len, dr_len;
- size_t buf_len;
+ size_t buf_len = 0;
size_t data_len;
int hbuf_slots;
u32 dr_slots;
u32 dma_len;
int rets;
bool first_chunk;
- const void *data;
+ const void *data = NULL;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -1839,8 +1868,10 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
- buf_len = buf->size - cb->buf_idx;
- data = buf->data + cb->buf_idx;
+ if (buf->data) {
+ buf_len = buf->size - cb->buf_idx;
+ data = buf->data + cb->buf_idx;
+ }
hbuf_slots = mei_hbuf_empty_slots(dev);
if (hbuf_slots < 0) {
rets = -EOVERFLOW;
@@ -1858,9 +1889,6 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
goto err;
}
- cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",
- mei_hdr->extended, cb->vtag);
-
hdr_len = sizeof(*mei_hdr) + mei_hdr->length;
/**
@@ -1889,7 +1917,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
}
mei_hdr->length += data_len;
- if (mei_hdr->dma_ring)
+ if (mei_hdr->dma_ring && buf->data)
mei_dma_ring_write(dev, buf->data + cb->buf_idx, buf_len);
rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);
@@ -1983,9 +2011,6 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
goto err;
}
- cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",
- mei_hdr->extended, cb->vtag);
-
hdr_len = sizeof(*mei_hdr) + mei_hdr->length;
if (rets == 0) {
@@ -2030,7 +2055,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
mei_hdr->length += data_len;
- if (mei_hdr->dma_ring)
+ if (mei_hdr->dma_ring && buf->data)
mei_dma_ring_write(dev, buf->data, buf_len);
rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index de712cbf5d07..12a62a911e42 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -340,9 +340,13 @@ static int mei_hbm_capabilities_req(struct mei_device *dev)
req.hbm_cmd = MEI_HBM_CAPABILITIES_REQ_CMD;
if (dev->hbm_f_vt_supported)
req.capability_requested[0] |= HBM_CAP_VT;
+
if (dev->hbm_f_cd_supported)
req.capability_requested[0] |= HBM_CAP_CD;
+ if (dev->hbm_f_gsc_supported)
+ req.capability_requested[0] |= HBM_CAP_GSC;
+
ret = mei_hbm_write_message(dev, &mei_hdr, &req);
if (ret) {
dev_err(dev->dev,
@@ -1200,6 +1204,12 @@ static void mei_hbm_config_features(struct mei_device *dev)
dev->version.minor_version >= HBM_MINOR_VERSION_VT))
dev->hbm_f_vt_supported = 1;
+ /* GSC support */
+ if (dev->version.major_version > HBM_MAJOR_VERSION_GSC ||
+ (dev->version.major_version == HBM_MAJOR_VERSION_GSC &&
+ dev->version.minor_version >= HBM_MINOR_VERSION_GSC))
+ dev->hbm_f_gsc_supported = 1;
+
/* Capability message Support */
dev->hbm_f_cap_supported = 0;
if (dev->version.major_version > HBM_MAJOR_VERSION_CAP ||
@@ -1367,6 +1377,9 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
if (!(capability_res->capability_granted[0] & HBM_CAP_CD))
dev->hbm_f_cd_supported = 0;
+ if (!(capability_res->capability_granted[0] & HBM_CAP_GSC))
+ dev->hbm_f_gsc_supported = 0;
+
if (dev->hbm_f_dr_supported) {
if (mei_dmam_ring_alloc(dev))
dev_info(dev->dev, "running w/o dma ring\n");
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 9e2f781c6ed5..da4ef0b51954 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -590,9 +590,14 @@ static int mei_me_hbuf_write(struct mei_device *dev,
u32 dw_cnt;
int empty_slots;
- if (WARN_ON(!hdr || !data || hdr_len & 0x3))
+ if (WARN_ON(!hdr || hdr_len & 0x3))
return -EINVAL;
+ if (!data && data_len) {
+ dev_err(dev->dev, "wrong parameters null data with data_len = %zu\n", data_len);
+ return -EINVAL;
+ }
+
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr));
empty_slots = mei_hbuf_empty_slots(dev);
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index e7e020dba6b1..319418ddf4fb 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -93,6 +93,12 @@
#define HBM_MAJOR_VERSION_VT 2
/*
+ * MEI version with GSC support
+ */
+#define HBM_MINOR_VERSION_GSC 2
+#define HBM_MAJOR_VERSION_GSC 2
+
+/*
* MEI version with capabilities message support
*/
#define HBM_MINOR_VERSION_CAP 2
@@ -229,18 +235,19 @@ enum mei_cl_disconnect_status {
*
* @MEI_EXT_HDR_NONE: sentinel
* @MEI_EXT_HDR_VTAG: vtag header
+ * @MEI_EXT_HDR_GSC: gsc header
*/
enum mei_ext_hdr_type {
MEI_EXT_HDR_NONE = 0,
MEI_EXT_HDR_VTAG = 1,
+ MEI_EXT_HDR_GSC = 2,
};
/**
* struct mei_ext_hdr - extend header descriptor (TLV)
* @type: enum mei_ext_hdr_type
* @length: length excluding descriptor
- * @ext_payload: payload of the specific extended header
- * @hdr: place holder for actual header
+ * @data: the extended header payload
*/
struct mei_ext_hdr {
u8 type;
@@ -279,12 +286,11 @@ struct mei_ext_hdr_vtag {
* Extended header iterator functions
*/
/**
- * mei_ext_hdr - extended header iterator begin
+ * mei_ext_begin - extended header iterator begin
*
* @meta: meta header of the extended header list
*
- * Return:
- * The first extended header
+ * Return: The first extended header
*/
static inline struct mei_ext_hdr *mei_ext_begin(struct mei_ext_meta_hdr *meta)
{
@@ -305,6 +311,60 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta,
return (u8 *)ext >= (u8 *)meta + sizeof(*meta) + (meta->size * 4);
}
+struct mei_gsc_sgl {
+ u32 low;
+ u32 high;
+ u32 length;
+} __packed;
+
+#define GSC_HECI_MSG_KERNEL 0
+#define GSC_HECI_MSG_USER 1
+
+#define GSC_ADDRESS_TYPE_GTT 0
+#define GSC_ADDRESS_TYPE_PPGTT 1
+#define GSC_ADDRESS_TYPE_PHYSICAL_CONTINUOUS 2 /* max of 64K */
+#define GSC_ADDRESS_TYPE_PHYSICAL_SGL 3
+
+/**
+ * struct mei_ext_hdr_gsc_h2f - extended header: gsc host to firmware interface
+ *
+ * @hdr: extended header
+ * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER
+ * @addr_type: GSC_ADDRESS_TYPE_{GTT, PPGTT, PHYSICAL_CONTINUOUS, PHYSICAL_SGL}
+ * @fence_id: synchronization marker
+ * @input_address_count: number of input sgl buffers
+ * @output_address_count: number of output sgl buffers
+ * @reserved: reserved
+ * @sgl: sg list
+ */
+struct mei_ext_hdr_gsc_h2f {
+ struct mei_ext_hdr hdr;
+ u8 client_id;
+ u8 addr_type;
+ u32 fence_id;
+ u8 input_address_count;
+ u8 output_address_count;
+ u8 reserved[2];
+ struct mei_gsc_sgl sgl[];
+} __packed;
+
+/**
+ * struct mei_ext_hdr_gsc_f2h - gsc firmware to host interface
+ *
+ * @hdr: extended header
+ * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER
+ * @reserved: reserved
+ * @fence_id: synchronization marker
+ * @written: number of bytes written to firmware
+ */
+struct mei_ext_hdr_gsc_f2h {
+ struct mei_ext_hdr hdr;
+ u8 client_id;
+ u8 reserved;
+ u32 fence_id;
+ u32 written;
+} __packed;
+
/**
* mei_ext_next - following extended header on the TLV list
*
@@ -321,6 +381,21 @@ static inline struct mei_ext_hdr *mei_ext_next(struct mei_ext_hdr *ext)
}
/**
+ * mei_ext_hdr_len - get ext header length in bytes
+ *
+ * @ext: extend header
+ *
+ * Return: extend header length in bytes
+ */
+static inline u32 mei_ext_hdr_len(const struct mei_ext_hdr *ext)
+{
+ if (!ext)
+ return 0;
+
+ return ext->length * sizeof(u32);
+}
+
+/**
* struct mei_msg_hdr - MEI BUS Interface Section
*
* @me_addr: device address
@@ -682,6 +757,10 @@ struct hbm_dma_ring_ctrl {
/* virtual tag supported */
#define HBM_CAP_VT BIT(0)
+
+/* gsc extended header support */
+#define HBM_CAP_GSC BIT(1)
+
/* client dma supported */
#define HBM_CAP_CD BIT(2)
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 0706322154cb..0a0e984e5673 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -98,9 +98,12 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
+ struct mei_ext_hdr_vtag *vtag_hdr = NULL;
+ struct mei_ext_hdr_gsc_f2h *gsc_f2h = NULL;
+
size_t buf_sz;
u32 length;
- int ext_len;
+ u32 ext_len;
length = mei_hdr->length;
ext_len = 0;
@@ -122,18 +125,24 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
}
if (mei_hdr->extended) {
- struct mei_ext_hdr *ext;
- struct mei_ext_hdr_vtag *vtag_hdr = NULL;
-
- ext = mei_ext_begin(meta);
+ struct mei_ext_hdr *ext = mei_ext_begin(meta);
do {
switch (ext->type) {
case MEI_EXT_HDR_VTAG:
vtag_hdr = (struct mei_ext_hdr_vtag *)ext;
break;
+ case MEI_EXT_HDR_GSC:
+ gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext;
+ cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL);
+ if (!cb->ext_hdr) {
+ cb->status = -ENOMEM;
+ goto discard;
+ }
+ break;
case MEI_EXT_HDR_NONE:
fallthrough;
default:
+ cl_err(dev, cl, "unknown extended header\n");
cb->status = -EPROTO;
break;
}
@@ -141,12 +150,14 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
ext = mei_ext_next(ext);
} while (!mei_ext_last(meta, ext));
- if (!vtag_hdr) {
- cl_dbg(dev, cl, "vtag not found in extended header.\n");
+ if (!vtag_hdr && !gsc_f2h) {
+ cl_dbg(dev, cl, "no vtag or gsc found in extended header.\n");
cb->status = -EPROTO;
goto discard;
}
+ }
+ if (vtag_hdr) {
cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag);
if (cb->vtag && cb->vtag != vtag_hdr->vtag) {
cl_err(dev, cl, "mismatched tag: %d != %d\n",
@@ -157,6 +168,28 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
cb->vtag = vtag_hdr->vtag;
}
+ if (gsc_f2h) {
+ u32 ext_hdr_len = mei_ext_hdr_len(&gsc_f2h->hdr);
+
+ if (!dev->hbm_f_gsc_supported) {
+ cl_err(dev, cl, "gsc extended header is not supported\n");
+ cb->status = -EPROTO;
+ goto discard;
+ }
+
+ if (length) {
+ cl_err(dev, cl, "no data allowed in cb with gsc\n");
+ cb->status = -EPROTO;
+ goto discard;
+ }
+ if (ext_hdr_len > sizeof(*gsc_f2h)) {
+ cl_err(dev, cl, "gsc extended header is too big %u\n", ext_hdr_len);
+ cb->status = -EPROTO;
+ goto discard;
+ }
+ memcpy(cb->ext_hdr, gsc_f2h, ext_hdr_len);
+ }
+
if (!mei_cl_is_connected(cl)) {
cl_dbg(dev, cl, "not connected\n");
cb->status = -ENODEV;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 6bb3e1ba9ded..8d8018428d9d 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -116,12 +116,16 @@ enum mei_cb_file_ops {
* @MEI_CL_IO_TX_INTERNAL: internal communication between driver and FW
*
* @MEI_CL_IO_RX_NONBLOCK: recv is non-blocking
+ *
+ * @MEI_CL_IO_SGL: send command with sgl list.
*/
enum mei_cl_io_mode {
MEI_CL_IO_TX_BLOCKING = BIT(0),
MEI_CL_IO_TX_INTERNAL = BIT(1),
MEI_CL_IO_RX_NONBLOCK = BIT(2),
+
+ MEI_CL_IO_SGL = BIT(3),
};
/*
@@ -206,6 +210,7 @@ struct mei_cl;
* @status: io status of the cb
* @internal: communication between driver and FW flag
* @blocking: transmission blocking mode
+ * @ext_hdr: extended header
*/
struct mei_cl_cb {
struct list_head list;
@@ -218,6 +223,7 @@ struct mei_cl_cb {
int status;
u32 internal:1;
u32 blocking:1;
+ struct mei_ext_hdr *ext_hdr;
};
/**
@@ -494,6 +500,7 @@ struct mei_dev_timeouts {
* @hbm_f_vt_supported : hbm feature vtag supported
* @hbm_f_cap_supported : hbm feature capabilities message supported
* @hbm_f_cd_supported : hbm feature client dma supported
+ * @hbm_f_gsc_supported : hbm feature gsc supported
*
* @fw_ver : FW versions
*
@@ -585,6 +592,7 @@ struct mei_device {
unsigned int hbm_f_vt_supported:1;
unsigned int hbm_f_cap_supported:1;
unsigned int hbm_f_cd_supported:1;
+ unsigned int hbm_f_gsc_supported:1;
struct mei_fw_version fw_ver[MEI_MAX_FW_VER_BLOCKS];
diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c
index 5c39457e3f53..8dd09b1722eb 100644
--- a/drivers/misc/mei/pxp/mei_pxp.c
+++ b/drivers/misc/mei/pxp/mei_pxp.c
@@ -77,10 +77,35 @@ mei_pxp_receive_message(struct device *dev, void *buffer, size_t size)
return byte;
}
+/**
+ * mei_pxp_gsc_command() - sends a gsc command, by sending
+ * a sgl mei message to gsc and receiving reply from gsc
+ *
+ * @dev: device corresponding to the mei_cl_device
+ * @client_id: client id to send the command to
+ * @fence_id: fence id to send the command to
+ * @sg_in: scatter gather list containing addresses for rx message buffer
+ * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes
+ * @sg_out: scatter gather list containing addresses for tx message buffer
+ *
+ * Return: bytes sent on Success, <0 on Failure
+ */
+static ssize_t mei_pxp_gsc_command(struct device *dev, u8 client_id, u32 fence_id,
+ struct scatterlist *sg_in, size_t total_in_len,
+ struct scatterlist *sg_out)
+{
+ struct mei_cl_device *cldev;
+
+ cldev = to_mei_cl_device(dev);
+
+ return mei_cldev_send_gsc_command(cldev, client_id, fence_id, sg_in, total_in_len, sg_out);
+}
+
static const struct i915_pxp_component_ops mei_pxp_ops = {
.owner = THIS_MODULE,
.send = mei_pxp_send_message,
.recv = mei_pxp_receive_message,
+ .gsc_command = mei_pxp_gsc_command,
};
static int mei_component_master_bind(struct device *dev)
@@ -131,17 +156,24 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent,
{
struct device *base = data;
+ if (!dev)
+ return 0;
+
if (!dev->driver || strcmp(dev->driver->name, "i915") ||
subcomponent != I915_COMPONENT_PXP)
return 0;
base = base->parent;
- if (!base)
+ if (!base) /* mei device */
return 0;
- base = base->parent;
- dev = dev->parent;
+ base = base->parent; /* pci device */
+ /* for dgfx */
+ if (base && dev == base)
+ return 1;
+ /* for pch */
+ dev = dev->parent;
return (base && dev && dev == base);
}
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index e71068f7759b..73d71c4ec139 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -854,6 +854,7 @@ static int qp_notify_peer_local(bool attach, struct vmci_handle handle)
u32 context_id = vmci_get_context_id();
struct vmci_event_qp ev;
+ memset(&ev, 0, sizeof(ev));
ev.msg.hdr.dst = vmci_make_handle(context_id, VMCI_EVENT_HANDLER);
ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
VMCI_CONTEXT_RESOURCE_ID);
@@ -1467,6 +1468,7 @@ static int qp_notify_peer(bool attach,
* kernel.
*/
+ memset(&ev, 0, sizeof(ev));
ev.msg.hdr.dst = vmci_make_handle(peer_id, VMCI_EVENT_HANDLER);
ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
VMCI_CONTEXT_RESOURCE_ID);
@@ -3042,7 +3044,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&from, WRITE, &v, 1, buf_size);
+ iov_iter_kvec(&from, ITER_SOURCE, &v, 1, buf_size);
qp_lock(qpair);
@@ -3086,7 +3088,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&to, READ, &v, 1, buf_size);
+ iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
qp_lock(qpair);
@@ -3131,7 +3133,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&to, READ, &v, 1, buf_size);
+ iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
qp_lock(qpair);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 95fa8fb1d45f..f0d19356ad76 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -97,8 +97,8 @@ static void mmc_should_fail_request(struct mmc_host *host,
!should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
return;
- data->error = data_errors[prandom_u32_max(ARRAY_SIZE(data_errors))];
- data->bytes_xfered = prandom_u32_max(data->bytes_xfered >> 9) << 9;
+ data->error = data_errors[get_random_u32_below(ARRAY_SIZE(data_errors))];
+ data->bytes_xfered = get_random_u32_below(data->bytes_xfered >> 9) << 9;
}
#else /* CONFIG_FAIL_MMC_REQUEST */
@@ -1134,7 +1134,13 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
mmc_power_cycle(host, ocr);
} else {
bit = fls(ocr) - 1;
- ocr &= 3 << bit;
+ /*
+ * The bit variable represents the highest voltage bit set in
+ * the OCR register.
+ * To keep a range of 2 values (e.g. 3.2V/3.3V and 3.3V/3.4V),
+ * we must shift the mask '3' with (bit - 1).
+ */
+ ocr &= 3 << (bit - 1);
if (bit != host->ios.vdd)
dev_warn(mmc_dev(host), "exceeding card's volts\n");
}
@@ -1478,6 +1484,11 @@ void mmc_init_erase(struct mmc_card *card)
card->pref_erase = 0;
}
+static bool is_trim_arg(unsigned int arg)
+{
+ return (arg & MMC_TRIM_OR_DISCARD_ARGS) && arg != MMC_DISCARD_ARG;
+}
+
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
unsigned int arg, unsigned int qty)
{
@@ -1760,7 +1771,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
return -EOPNOTSUPP;
- if (mmc_card_mmc(card) && (arg & MMC_TRIM_ARGS) &&
+ if (mmc_card_mmc(card) && is_trim_arg(arg) &&
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
return -EOPNOTSUPP;
@@ -1790,7 +1801,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
* identified by the card->eg_boundary flag.
*/
rem = card->erase_size - (from % card->erase_size);
- if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
+ if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) {
err = mmc_do_erase(card, from, from + rem - 1, arg);
from += rem;
if ((err) || (to <= from))
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index 8d9bceeff986..155ce2bdfe62 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -3179,7 +3179,8 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
struct mmc_test_dbgfs_file *df;
if (card->debugfs_root)
- debugfs_create_file(name, mode, card->debugfs_root, card, fops);
+ file = debugfs_create_file(name, mode, card->debugfs_root,
+ card, fops);
df = kmalloc(sizeof(*df), GFP_KERNEL);
if (!df) {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index c78bbc22e0d1..6ef410053037 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1858,7 +1858,7 @@ static void dw_mci_start_fault_timer(struct dw_mci *host)
* Try to inject the error at random points during the data transfer.
*/
hrtimer_start(&host->fault_timer,
- ms_to_ktime(prandom_u32_max(25)),
+ ms_to_ktime(get_random_u32_below(25)),
HRTIMER_MODE_REL);
}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index df941438aef5..26bc59b5a7cc 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -2588,13 +2588,11 @@ static int msdc_of_clock_parse(struct platform_device *pdev,
return PTR_ERR(host->src_clk_cg);
}
- host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg");
+ /* If present, always enable for this clock gate */
+ host->sys_clk_cg = devm_clk_get_optional_enabled(&pdev->dev, "sys_cg");
if (IS_ERR(host->sys_clk_cg))
host->sys_clk_cg = NULL;
- /* If present, always enable for this clock gate */
- clk_prepare_enable(host->sys_clk_cg);
-
host->bulk_clks[0].id = "pclk_cg";
host->bulk_clks[1].id = "axi_cg";
host->bulk_clks[2].id = "ahb_cg";
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index aff36a933ebe..55d8bd232695 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
+#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#include "cqhci.h"
@@ -55,7 +56,7 @@ static void brcmstb_reset(struct sdhci_host *host, u8 mask)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
- sdhci_reset(host, mask);
+ sdhci_and_cqhci_reset(host, mask);
/* Reset will clear this, so re-enable it */
if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)
diff --git a/drivers/mmc/host/sdhci-cqhci.h b/drivers/mmc/host/sdhci-cqhci.h
new file mode 100644
index 000000000000..cf8e7ba71bbd
--- /dev/null
+++ b/drivers/mmc/host/sdhci-cqhci.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2022 The Chromium OS Authors
+ *
+ * Support that applies to the combination of SDHCI and CQHCI, while not
+ * expressing a dependency between the two modules.
+ */
+
+#ifndef __MMC_HOST_SDHCI_CQHCI_H__
+#define __MMC_HOST_SDHCI_CQHCI_H__
+
+#include "cqhci.h"
+#include "sdhci.h"
+
+static inline void sdhci_and_cqhci_reset(struct sdhci_host *host, u8 mask)
+{
+ if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
+ host->mmc->cqe_private)
+ cqhci_deactivate(host->mmc);
+
+ sdhci_reset(host, mask);
+}
+
+#endif /* __MMC_HOST_SDHCI_CQHCI_H__ */
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 747df79d90ee..ffeb5759830f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -25,6 +25,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
+#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
#include "cqhci.h"
@@ -1288,7 +1289,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
- sdhci_reset(host, mask);
+ sdhci_and_cqhci_reset(host, mask);
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
@@ -1511,7 +1512,7 @@ static void esdhc_cqe_enable(struct mmc_host *mmc)
* system resume back.
*/
cqhci_writel(cq_host, 0, CQHCI_CTL);
- if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT)
+ if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
dev_err(mmc_dev(host->mmc),
"failed to exit halt state when enable CQE\n");
@@ -1671,14 +1672,14 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
- if (host->caps & MMC_CAP_8_BIT_DATA &&
+ if (host->mmc->caps & MMC_CAP_8_BIT_DATA &&
imx_data->socdata->flags & ESDHC_FLAG_HS400)
host->mmc->caps2 |= MMC_CAP2_HS400;
if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
- if (host->caps & MMC_CAP_8_BIT_DATA &&
+ if (host->mmc->caps & MMC_CAP_8_BIT_DATA &&
imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
host->mmc->caps2 |= MMC_CAP2_HS400_ES;
host->mmc_host_ops.hs400_enhanced_strobe =
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 3997cad1f793..cfb891430174 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -25,6 +25,7 @@
#include <linux/firmware/xlnx-zynqmp.h>
#include "cqhci.h"
+#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
@@ -366,7 +367,7 @@ static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
- sdhci_reset(host, mask);
+ sdhci_and_cqhci_reset(host, mask);
if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 34ea1acbb3cc..28dc65023fa9 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1749,6 +1749,8 @@ static int amd_probe(struct sdhci_pci_chip *chip)
}
}
+ pci_dev_put(smbus_dev);
+
if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ)
chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index ad457cd9cbaa..bca1d095b759 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -32,6 +32,7 @@
#define O2_SD_CAPS 0xE0
#define O2_SD_ADMA1 0xE2
#define O2_SD_ADMA2 0xE7
+#define O2_SD_MISC_CTRL2 0xF0
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
#define O2_SD_MISC_CTRL 0x1C0
@@ -877,6 +878,12 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
/* Set Tuning Windows to 5 */
pci_write_config_byte(chip->pdev,
O2_SD_TUNING_CTRL, 0x55);
+ //Adjust 1st and 2nd CD debounce time
+ pci_read_config_dword(chip->pdev, O2_SD_MISC_CTRL2, &scratch_32);
+ scratch_32 &= 0xFFE7FFFF;
+ scratch_32 |= 0x00180000;
+ pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL2, scratch_32);
+ pci_write_config_dword(chip->pdev, O2_SD_DETECT_SETTING, 1);
/* Lock WP */
ret = pci_read_config_byte(chip->pdev,
O2_SD_LOCK_WP, &scratch);
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index b92a408f138d..bec3f9e3cd3f 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -470,7 +470,7 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (IS_ERR(sprd_host->pinctrl))
- return 0;
+ goto reset;
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_180:
@@ -498,6 +498,8 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
/* Wait for 300 ~ 500 us for pin state stable */
usleep_range(300, 500);
+
+reset:
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
return 0;
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 413925bce0ca..c71000a07656 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -28,6 +28,7 @@
#include <soc/tegra/common.h>
+#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#include "cqhci.h"
@@ -367,7 +368,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
u32 misc_ctrl, clk_ctrl, pad_ctrl;
- sdhci_reset(host, mask);
+ sdhci_and_cqhci_reset(host, mask);
if (!(mask & SDHCI_RESET_ALL))
return;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index fef03de85b99..c7ad32a75b57 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -373,6 +373,7 @@ static void sdhci_init(struct sdhci_host *host, int soft)
if (soft) {
/* force clock reconfiguration */
host->clock = 0;
+ host->reinit_uhs = true;
mmc->ops->set_ios(mmc, &mmc->ios);
}
}
@@ -2293,11 +2294,46 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+static bool sdhci_timing_has_preset(unsigned char timing)
+{
+ switch (timing) {
+ case MMC_TIMING_UHS_SDR12:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ return true;
+ };
+ return false;
+}
+
+static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
+{
+ return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+ sdhci_timing_has_preset(timing);
+}
+
+static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
+{
+ /*
+ * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
+ * Frequency. Check if preset values need to be enabled, or the Driver
+ * Strength needs updating. Note, clock changes are handled separately.
+ */
+ return !host->preset_enabled &&
+ (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+}
+
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
+ bool reinit_uhs = host->reinit_uhs;
+ bool turning_on_clk = false;
u8 ctrl;
+ host->reinit_uhs = false;
+
if (ios->power_mode == MMC_POWER_UNDEFINED)
return;
@@ -2323,6 +2359,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_enable_preset_value(host, false);
if (!ios->clock || ios->clock != host->clock) {
+ turning_on_clk = ios->clock && !host->clock;
+
host->ops->set_clock(host, ios->clock);
host->clock = ios->clock;
@@ -2349,6 +2387,17 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->ops->set_bus_width(host, ios->bus_width);
+ /*
+ * Special case to avoid multiple clock changes during voltage
+ * switching.
+ */
+ if (!reinit_uhs &&
+ turning_on_clk &&
+ host->timing == ios->timing &&
+ host->version >= SDHCI_SPEC_300 &&
+ !sdhci_presetable_values_change(host, ios))
+ return;
+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
@@ -2392,6 +2441,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ host->drv_type = ios->drv_type;
} else {
/*
* According to SDHC Spec v3.00, if the Preset Value
@@ -2419,19 +2469,14 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->ops->set_uhs_signaling(host, ios->timing);
host->timing = ios->timing;
- if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
- ((ios->timing == MMC_TIMING_UHS_SDR12) ||
- (ios->timing == MMC_TIMING_UHS_SDR25) ||
- (ios->timing == MMC_TIMING_UHS_SDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_DDR50) ||
- (ios->timing == MMC_TIMING_MMC_DDR52))) {
+ if (sdhci_preset_needed(host, ios->timing)) {
u16 preset;
sdhci_enable_preset_value(host, true);
preset = sdhci_get_preset_value(host);
ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
preset);
+ host->drv_type = ios->drv_type;
}
/* Re-enable SD Clock */
@@ -3768,6 +3813,7 @@ int sdhci_resume_host(struct sdhci_host *host)
sdhci_init(host, 0);
host->pwr = 0;
host->clock = 0;
+ host->reinit_uhs = true;
mmc->ops->set_ios(mmc, &mmc->ios);
} else {
sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
@@ -3830,6 +3876,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset)
/* Force clock and power re-program */
host->pwr = 0;
host->clock = 0;
+ host->reinit_uhs = true;
mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
mmc->ops->set_ios(mmc, &mmc->ios);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d750c464bd1e..87a3aaa07438 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -524,6 +524,8 @@ struct sdhci_host {
unsigned int clock; /* Current clock (MHz) */
u8 pwr; /* Current voltage */
+ u8 drv_type; /* Current UHS-I driver type */
+ bool reinit_uhs; /* Force UHS-related re-initialization */
bool runtime_suspended; /* Host is runtime suspended */
bool bus_on; /* Bus power prevents runtime suspend */
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 8f1023480e12..c2333c7acac9 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -15,6 +15,7 @@
#include <linux/sys_soc.h>
#include "cqhci.h"
+#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
/* CTL_CFG Registers */
@@ -378,7 +379,7 @@ static void sdhci_am654_reset(struct sdhci_host *host, u8 mask)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
- sdhci_reset(host, mask);
+ sdhci_and_cqhci_reset(host, mask);
if (sdhci_am654->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) {
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
@@ -464,7 +465,7 @@ static struct sdhci_ops sdhci_am654_ops = {
.set_clock = sdhci_am654_set_clock,
.write_b = sdhci_am654_write_b,
.irq = sdhci_am654_cqhci_irq,
- .reset = sdhci_reset,
+ .reset = sdhci_and_cqhci_reset,
};
static const struct sdhci_pltfm_data sdhci_am654_pdata = {
@@ -494,7 +495,7 @@ static struct sdhci_ops sdhci_j721e_8bit_ops = {
.set_clock = sdhci_am654_set_clock,
.write_b = sdhci_am654_write_b,
.irq = sdhci_am654_cqhci_irq,
- .reset = sdhci_reset,
+ .reset = sdhci_and_cqhci_reset,
};
static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 79cb981ececc..ff2f9e55ef28 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -136,14 +136,6 @@ config MTD_PHRAM
doesn't have access to, memory beyond the mem=xxx limit, nvram,
memory on the video card, etc...
-config MTD_LART
- tristate "28F160xx flash driver for LART"
- depends on SA1100_LART
- help
- This enables the flash driver for LART. Please note that you do
- not need any mapping/chip driver for LART. This one does it all
- for you, so go disable all of those if you enabled some of them (:
-
config MTD_MTDRAM
tristate "Test driver using RAM"
help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 0362cf6bdc67..d11eb2b8b6f8 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_MTD_PHRAM) += phram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
-obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
deleted file mode 100644
index aecd441e4183..000000000000
--- a/drivers/mtd/devices/lart.c
+++ /dev/null
@@ -1,682 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-/*
- * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
- *
- * Author: Abraham vd Merwe <abraham@2d3d.co.za>
- *
- * Copyright (c) 2001, 2d3D, Inc.
- *
- * References:
- *
- * [1] 3 Volt Fast Boot Block Flash Memory" Intel Datasheet
- * - Order Number: 290644-005
- * - January 2000
- *
- * [2] MTD internal API documentation
- * - http://www.linux-mtd.infradead.org/
- *
- * Limitations:
- *
- * Even though this driver is written for 3 Volt Fast Boot
- * Block Flash Memory, it is rather specific to LART. With
- * Minor modifications, notably the without data/address line
- * mangling and different bus settings, etc. it should be
- * trivial to adapt to other platforms.
- *
- * If somebody would sponsor me a different board, I'll
- * adapt the driver (:
- */
-
-/* debugging */
-//#define LART_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#ifndef CONFIG_SA1100_LART
-#error This is for LART architecture only
-#endif
-
-static char module_name[] = "lart";
-
-/*
- * These values is specific to 28Fxxxx3 flash memory.
- * See section 2.3.1 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet
- */
-#define FLASH_BLOCKSIZE_PARAM (4096 * BUSWIDTH)
-#define FLASH_NUMBLOCKS_16m_PARAM 8
-#define FLASH_NUMBLOCKS_8m_PARAM 8
-
-/*
- * These values is specific to 28Fxxxx3 flash memory.
- * See section 2.3.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet
- */
-#define FLASH_BLOCKSIZE_MAIN (32768 * BUSWIDTH)
-#define FLASH_NUMBLOCKS_16m_MAIN 31
-#define FLASH_NUMBLOCKS_8m_MAIN 15
-
-/*
- * These values are specific to LART
- */
-
-/* general */
-#define BUSWIDTH 4 /* don't change this - a lot of the code _will_ break if you change this */
-#define FLASH_OFFSET 0xe8000000 /* see linux/arch/arm/mach-sa1100/lart.c */
-
-/* blob */
-#define NUM_BLOB_BLOCKS FLASH_NUMBLOCKS_16m_PARAM
-#define PART_BLOB_START 0x00000000
-#define PART_BLOB_LEN (NUM_BLOB_BLOCKS * FLASH_BLOCKSIZE_PARAM)
-
-/* kernel */
-#define NUM_KERNEL_BLOCKS 7
-#define PART_KERNEL_START (PART_BLOB_START + PART_BLOB_LEN)
-#define PART_KERNEL_LEN (NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE_MAIN)
-
-/* initial ramdisk */
-#define NUM_INITRD_BLOCKS 24
-#define PART_INITRD_START (PART_KERNEL_START + PART_KERNEL_LEN)
-#define PART_INITRD_LEN (NUM_INITRD_BLOCKS * FLASH_BLOCKSIZE_MAIN)
-
-/*
- * See section 4.0 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet
- */
-#define READ_ARRAY 0x00FF00FF /* Read Array/Reset */
-#define READ_ID_CODES 0x00900090 /* Read Identifier Codes */
-#define ERASE_SETUP 0x00200020 /* Block Erase */
-#define ERASE_CONFIRM 0x00D000D0 /* Block Erase and Program Resume */
-#define PGM_SETUP 0x00400040 /* Program */
-#define STATUS_READ 0x00700070 /* Read Status Register */
-#define STATUS_CLEAR 0x00500050 /* Clear Status Register */
-#define STATUS_BUSY 0x00800080 /* Write State Machine Status (WSMS) */
-#define STATUS_ERASE_ERR 0x00200020 /* Erase Status (ES) */
-#define STATUS_PGM_ERR 0x00100010 /* Program Status (PS) */
-
-/*
- * See section 4.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet
- */
-#define FLASH_MANUFACTURER 0x00890089
-#define FLASH_DEVICE_8mbit_TOP 0x88f188f1
-#define FLASH_DEVICE_8mbit_BOTTOM 0x88f288f2
-#define FLASH_DEVICE_16mbit_TOP 0x88f388f3
-#define FLASH_DEVICE_16mbit_BOTTOM 0x88f488f4
-
-/***************************************************************************************************/
-
-/*
- * The data line mapping on LART is as follows:
- *
- * U2 CPU | U3 CPU
- * -------------------
- * 0 20 | 0 12
- * 1 22 | 1 14
- * 2 19 | 2 11
- * 3 17 | 3 9
- * 4 24 | 4 0
- * 5 26 | 5 2
- * 6 31 | 6 7
- * 7 29 | 7 5
- * 8 21 | 8 13
- * 9 23 | 9 15
- * 10 18 | 10 10
- * 11 16 | 11 8
- * 12 25 | 12 1
- * 13 27 | 13 3
- * 14 30 | 14 6
- * 15 28 | 15 4
- */
-
-/* Mangle data (x) */
-#define DATA_TO_FLASH(x) \
- ( \
- (((x) & 0x08009000) >> 11) + \
- (((x) & 0x00002000) >> 10) + \
- (((x) & 0x04004000) >> 8) + \
- (((x) & 0x00000010) >> 4) + \
- (((x) & 0x91000820) >> 3) + \
- (((x) & 0x22080080) >> 2) + \
- ((x) & 0x40000400) + \
- (((x) & 0x00040040) << 1) + \
- (((x) & 0x00110000) << 4) + \
- (((x) & 0x00220100) << 5) + \
- (((x) & 0x00800208) << 6) + \
- (((x) & 0x00400004) << 9) + \
- (((x) & 0x00000001) << 12) + \
- (((x) & 0x00000002) << 13) \
- )
-
-/* Unmangle data (x) */
-#define FLASH_TO_DATA(x) \
- ( \
- (((x) & 0x00010012) << 11) + \
- (((x) & 0x00000008) << 10) + \
- (((x) & 0x00040040) << 8) + \
- (((x) & 0x00000001) << 4) + \
- (((x) & 0x12200104) << 3) + \
- (((x) & 0x08820020) << 2) + \
- ((x) & 0x40000400) + \
- (((x) & 0x00080080) >> 1) + \
- (((x) & 0x01100000) >> 4) + \
- (((x) & 0x04402000) >> 5) + \
- (((x) & 0x20008200) >> 6) + \
- (((x) & 0x80000800) >> 9) + \
- (((x) & 0x00001000) >> 12) + \
- (((x) & 0x00004000) >> 13) \
- )
-
-/*
- * The address line mapping on LART is as follows:
- *
- * U3 CPU | U2 CPU
- * -------------------
- * 0 2 | 0 2
- * 1 3 | 1 3
- * 2 9 | 2 9
- * 3 13 | 3 8
- * 4 8 | 4 7
- * 5 12 | 5 6
- * 6 11 | 6 5
- * 7 10 | 7 4
- * 8 4 | 8 10
- * 9 5 | 9 11
- * 10 6 | 10 12
- * 11 7 | 11 13
- *
- * BOOT BLOCK BOUNDARY
- *
- * 12 15 | 12 15
- * 13 14 | 13 14
- * 14 16 | 14 16
- *
- * MAIN BLOCK BOUNDARY
- *
- * 15 17 | 15 18
- * 16 18 | 16 17
- * 17 20 | 17 20
- * 18 19 | 18 19
- * 19 21 | 19 21
- *
- * As we can see from above, the addresses aren't mangled across
- * block boundaries, so we don't need to worry about address
- * translations except for sending/reading commands during
- * initialization
- */
-
-/* Mangle address (x) on chip U2 */
-#define ADDR_TO_FLASH_U2(x) \
- ( \
- (((x) & 0x00000f00) >> 4) + \
- (((x) & 0x00042000) << 1) + \
- (((x) & 0x0009c003) << 2) + \
- (((x) & 0x00021080) << 3) + \
- (((x) & 0x00000010) << 4) + \
- (((x) & 0x00000040) << 5) + \
- (((x) & 0x00000024) << 7) + \
- (((x) & 0x00000008) << 10) \
- )
-
-/* Unmangle address (x) on chip U2 */
-#define FLASH_U2_TO_ADDR(x) \
- ( \
- (((x) << 4) & 0x00000f00) + \
- (((x) >> 1) & 0x00042000) + \
- (((x) >> 2) & 0x0009c003) + \
- (((x) >> 3) & 0x00021080) + \
- (((x) >> 4) & 0x00000010) + \
- (((x) >> 5) & 0x00000040) + \
- (((x) >> 7) & 0x00000024) + \
- (((x) >> 10) & 0x00000008) \
- )
-
-/* Mangle address (x) on chip U3 */
-#define ADDR_TO_FLASH_U3(x) \
- ( \
- (((x) & 0x00000080) >> 3) + \
- (((x) & 0x00000040) >> 1) + \
- (((x) & 0x00052020) << 1) + \
- (((x) & 0x00084f03) << 2) + \
- (((x) & 0x00029010) << 3) + \
- (((x) & 0x00000008) << 5) + \
- (((x) & 0x00000004) << 7) \
- )
-
-/* Unmangle address (x) on chip U3 */
-#define FLASH_U3_TO_ADDR(x) \
- ( \
- (((x) << 3) & 0x00000080) + \
- (((x) << 1) & 0x00000040) + \
- (((x) >> 1) & 0x00052020) + \
- (((x) >> 2) & 0x00084f03) + \
- (((x) >> 3) & 0x00029010) + \
- (((x) >> 5) & 0x00000008) + \
- (((x) >> 7) & 0x00000004) \
- )
-
-/***************************************************************************************************/
-
-static __u8 read8 (__u32 offset)
-{
- volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset);
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data);
-#endif
- return (*data);
-}
-
-static __u32 read32 (__u32 offset)
-{
- volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data);
-#endif
- return (*data);
-}
-
-static void write32 (__u32 x,__u32 offset)
-{
- volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
- *data = x;
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data);
-#endif
-}
-
-/***************************************************************************************************/
-
-/*
- * Probe for 16mbit flash memory on a LART board without doing
- * too much damage. Since we need to write 1 dword to memory,
- * we're f**cked if this happens to be DRAM since we can't
- * restore the memory (otherwise we might exit Read Array mode).
- *
- * Returns 1 if we found 16mbit flash memory on LART, 0 otherwise.
- */
-static int flash_probe (void)
-{
- __u32 manufacturer,devtype;
-
- /* setup "Read Identifier Codes" mode */
- write32 (DATA_TO_FLASH (READ_ID_CODES),0x00000000);
-
- /* probe U2. U2/U3 returns the same data since the first 3
- * address lines is mangled in the same way */
- manufacturer = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000000)));
- devtype = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000001)));
-
- /* put the flash back into command mode */
- write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000);
-
- return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM));
-}
-
-/*
- * Erase one block of flash memory at offset ``offset'' which is any
- * address within the block which should be erased.
- *
- * Returns 1 if successful, 0 otherwise.
- */
-static inline int erase_block (__u32 offset)
-{
- __u32 status;
-
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset);
-#endif
-
- /* erase and confirm */
- write32 (DATA_TO_FLASH (ERASE_SETUP),offset);
- write32 (DATA_TO_FLASH (ERASE_CONFIRM),offset);
-
- /* wait for block erase to finish */
- do
- {
- write32 (DATA_TO_FLASH (STATUS_READ),offset);
- status = FLASH_TO_DATA (read32 (offset));
- }
- while ((~status & STATUS_BUSY) != 0);
-
- /* put the flash back into command mode */
- write32 (DATA_TO_FLASH (READ_ARRAY),offset);
-
- /* was the erase successful? */
- if ((status & STATUS_ERASE_ERR))
- {
- printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",module_name,offset);
- return (0);
- }
-
- return (1);
-}
-
-static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
-{
- __u32 addr,len;
- int i,first;
-
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
-#endif
-
- /*
- * check that both start and end of the requested erase are
- * aligned with the erasesize at the appropriate addresses.
- *
- * skip all erase regions which are ended before the start of
- * the requested erase. Actually, to save on the calculations,
- * we skip to the first erase region which starts after the
- * start of the requested erase, and then go back one.
- */
- for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ;
- i--;
-
- /*
- * ok, now i is pointing at the erase region in which this
- * erase request starts. Check the start of the requested
- * erase range is aligned with the erase size which is in
- * effect here.
- */
- if (i < 0 || (instr->addr & (mtd->eraseregions[i].erasesize - 1)))
- return -EINVAL;
-
- /* Remember the erase region we start on */
- first = i;
-
- /*
- * next, check that the end of the requested erase is aligned
- * with the erase region at that address.
- *
- * as before, drop back one to point at the region in which
- * the address actually falls
- */
- for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ;
- i--;
-
- /* is the end aligned on a block boundary? */
- if (i < 0 || ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)))
- return -EINVAL;
-
- addr = instr->addr;
- len = instr->len;
-
- i = first;
-
- /* now erase those blocks */
- while (len)
- {
- if (!erase_block (addr))
- return (-EIO);
-
- addr += mtd->eraseregions[i].erasesize;
- len -= mtd->eraseregions[i].erasesize;
-
- if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++;
- }
-
- return (0);
-}
-
-static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf)
-{
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
-#endif
-
- /* we always read len bytes */
- *retlen = len;
-
- /* first, we read bytes until we reach a dword boundary */
- if (from & (BUSWIDTH - 1))
- {
- int gap = BUSWIDTH - (from & (BUSWIDTH - 1));
-
- while (len && gap--) {
- *buf++ = read8 (from++);
- len--;
- }
- }
-
- /* now we read dwords until we reach a non-dword boundary */
- while (len >= BUSWIDTH)
- {
- *((__u32 *) buf) = read32 (from);
-
- buf += BUSWIDTH;
- from += BUSWIDTH;
- len -= BUSWIDTH;
- }
-
- /* top up the last unaligned bytes */
- if (len & (BUSWIDTH - 1))
- while (len--) *buf++ = read8 (from++);
-
- return (0);
-}
-
-/*
- * Write one dword ``x'' to flash memory at offset ``offset''. ``offset''
- * must be 32 bits, i.e. it must be on a dword boundary.
- *
- * Returns 1 if successful, 0 otherwise.
- */
-static inline int write_dword (__u32 offset,__u32 x)
-{
- __u32 status;
-
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x);
-#endif
-
- /* setup writing */
- write32 (DATA_TO_FLASH (PGM_SETUP),offset);
-
- /* write the data */
- write32 (x,offset);
-
- /* wait for the write to finish */
- do
- {
- write32 (DATA_TO_FLASH (STATUS_READ),offset);
- status = FLASH_TO_DATA (read32 (offset));
- }
- while ((~status & STATUS_BUSY) != 0);
-
- /* put the flash back into command mode */
- write32 (DATA_TO_FLASH (READ_ARRAY),offset);
-
- /* was the write successful? */
- if ((status & STATUS_PGM_ERR) || read32 (offset) != x)
- {
- printk (KERN_WARNING "%s: write error at address 0x%.8x.\n",module_name,offset);
- return (0);
- }
-
- return (1);
-}
-
-static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf)
-{
- __u8 tmp[4];
- int i,n;
-
-#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
-#endif
-
- /* sanity checks */
- if (!len) return (0);
-
- /* first, we write a 0xFF.... padded byte until we reach a dword boundary */
- if (to & (BUSWIDTH - 1))
- {
- __u32 aligned = to & ~(BUSWIDTH - 1);
- int gap = to - aligned;
-
- i = n = 0;
-
- while (gap--) tmp[i++] = 0xFF;
- while (len && i < BUSWIDTH) {
- tmp[i++] = buf[n++];
- len--;
- }
- while (i < BUSWIDTH) tmp[i++] = 0xFF;
-
- if (!write_dword (aligned,*((__u32 *) tmp))) return (-EIO);
-
- to += n;
- buf += n;
- *retlen += n;
- }
-
- /* now we write dwords until we reach a non-dword boundary */
- while (len >= BUSWIDTH)
- {
- if (!write_dword (to,*((__u32 *) buf))) return (-EIO);
-
- to += BUSWIDTH;
- buf += BUSWIDTH;
- *retlen += BUSWIDTH;
- len -= BUSWIDTH;
- }
-
- /* top up the last unaligned bytes, padded with 0xFF.... */
- if (len & (BUSWIDTH - 1))
- {
- i = n = 0;
-
- while (len--) tmp[i++] = buf[n++];
- while (i < BUSWIDTH) tmp[i++] = 0xFF;
-
- if (!write_dword (to,*((__u32 *) tmp))) return (-EIO);
-
- *retlen += n;
- }
-
- return (0);
-}
-
-/***************************************************************************************************/
-
-static struct mtd_info mtd;
-
-static struct mtd_erase_region_info erase_regions[] = {
- /* parameter blocks */
- {
- .offset = 0x00000000,
- .erasesize = FLASH_BLOCKSIZE_PARAM,
- .numblocks = FLASH_NUMBLOCKS_16m_PARAM,
- },
- /* main blocks */
- {
- .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
- .erasesize = FLASH_BLOCKSIZE_MAIN,
- .numblocks = FLASH_NUMBLOCKS_16m_MAIN,
- }
-};
-
-static const struct mtd_partition lart_partitions[] = {
- /* blob */
- {
- .name = "blob",
- .offset = PART_BLOB_START,
- .size = PART_BLOB_LEN,
- },
- /* kernel */
- {
- .name = "kernel",
- .offset = PART_KERNEL_START, /* MTDPART_OFS_APPEND */
- .size = PART_KERNEL_LEN,
- },
- /* initial ramdisk / file system */
- {
- .name = "file system",
- .offset = PART_INITRD_START, /* MTDPART_OFS_APPEND */
- .size = PART_INITRD_LEN, /* MTDPART_SIZ_FULL */
- }
-};
-#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions)
-
-static int __init lart_flash_init (void)
-{
- int result;
- memset (&mtd,0,sizeof (mtd));
- printk ("MTD driver for LART. Written by Abraham vd Merwe <abraham@2d3d.co.za>\n");
- printk ("%s: Probing for 28F160x3 flash on LART...\n",module_name);
- if (!flash_probe ())
- {
- printk (KERN_WARNING "%s: Found no LART compatible flash device\n",module_name);
- return (-ENXIO);
- }
- printk ("%s: This looks like a LART board to me.\n",module_name);
- mtd.name = module_name;
- mtd.type = MTD_NORFLASH;
- mtd.writesize = 1;
- mtd.writebufsize = 4;
- mtd.flags = MTD_CAP_NORFLASH;
- mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
- mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
- mtd.numeraseregions = ARRAY_SIZE(erase_regions);
- mtd.eraseregions = erase_regions;
- mtd._erase = flash_erase;
- mtd._read = flash_read;
- mtd._write = flash_write;
- mtd.owner = THIS_MODULE;
-
-#ifdef LART_DEBUG
- printk (KERN_DEBUG
- "mtd.name = %s\n"
- "mtd.size = 0x%.8x (%uM)\n"
- "mtd.erasesize = 0x%.8x (%uK)\n"
- "mtd.numeraseregions = %d\n",
- mtd.name,
- mtd.size,mtd.size / (1024*1024),
- mtd.erasesize,mtd.erasesize / 1024,
- mtd.numeraseregions);
-
- if (mtd.numeraseregions)
- for (result = 0; result < mtd.numeraseregions; result++)
- printk (KERN_DEBUG
- "\n\n"
- "mtd.eraseregions[%d].offset = 0x%.8x\n"
- "mtd.eraseregions[%d].erasesize = 0x%.8x (%uK)\n"
- "mtd.eraseregions[%d].numblocks = %d\n",
- result,mtd.eraseregions[result].offset,
- result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024,
- result,mtd.eraseregions[result].numblocks);
-
- printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions));
-
- for (result = 0; result < ARRAY_SIZE(lart_partitions); result++)
- printk (KERN_DEBUG
- "\n\n"
- "lart_partitions[%d].name = %s\n"
- "lart_partitions[%d].offset = 0x%.8x\n"
- "lart_partitions[%d].size = 0x%.8x (%uK)\n",
- result,lart_partitions[result].name,
- result,lart_partitions[result].offset,
- result,lart_partitions[result].size,lart_partitions[result].size / 1024);
-#endif
-
- result = mtd_device_register(&mtd, lart_partitions,
- ARRAY_SIZE(lart_partitions));
-
- return (result);
-}
-
-static void __exit lart_flash_exit (void)
-{
- mtd_device_unregister(&mtd);
-}
-
-module_init (lart_flash_init);
-module_exit (lart_flash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>");
-MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board");
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 58ca1c21ebe6..9739387cff8c 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -356,7 +356,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
* Newest unit in chain now contains data from _all_ older units.
* So go through and erase each unit in chain, oldest first. (This
* is important, by doing oldest first if we crash/reboot then it
- * it is relatively simple to clean up the mess).
+ * is relatively simple to clean up the mess).
*/
pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC);
diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c
index 367e2d906de0..e71af4c49096 100644
--- a/drivers/mtd/lpddr/lpddr2_nvm.c
+++ b/drivers/mtd/lpddr/lpddr2_nvm.c
@@ -433,6 +433,8 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
/* lpddr2_nvm address range */
add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!add_range)
+ return -ENODEV;
/* Populate map_info data structure */
*map = (struct map_info) {
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index 1749dbbacc13..62a5bf41a6d7 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -64,6 +64,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
if (!info->map.virt) {
printk(KERN_WARNING "Failed to ioremap %s\n",
info->map.name);
+ kfree(info);
return -ENOMEM;
}
info->map.cached = ioremap_cache(info->map.phys, info->map.size);
@@ -85,6 +86,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
iounmap((void *)info->map.virt);
if (info->map.cached)
iounmap(info->map.cached);
+ kfree(info);
return -EIO;
}
info->mtd->dev.parent = &pdev->dev;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 0b4ca0aa4132..0feacb9fbdac 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -28,6 +28,7 @@
#include <linux/leds.h>
#include <linux/debugfs.h>
#include <linux/nvmem-provider.h>
+#include <linux/root_dev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -551,22 +552,22 @@ static void mtd_check_of_node(struct mtd_info *mtd)
struct device_node *partitions, *parent_dn, *mtd_dn = NULL;
const char *pname, *prefix = "partition-";
int plen, mtd_name_len, offset, prefix_len;
- struct mtd_info *parent;
- bool found = false;
/* Check if MTD already has a device node */
- if (dev_of_node(&mtd->dev))
+ if (mtd_get_of_node(mtd))
return;
- /* Check if a partitions node exist */
if (!mtd_is_partition(mtd))
return;
- parent = mtd->parent;
- parent_dn = of_node_get(dev_of_node(&parent->dev));
+
+ parent_dn = of_node_get(mtd_get_of_node(mtd->parent));
if (!parent_dn)
return;
- partitions = of_get_child_by_name(parent_dn, "partitions");
+ if (mtd_is_partition(mtd->parent))
+ partitions = of_node_get(parent_dn);
+ else
+ partitions = of_get_child_by_name(parent_dn, "partitions");
if (!partitions)
goto exit_parent;
@@ -575,34 +576,26 @@ static void mtd_check_of_node(struct mtd_info *mtd)
/* Search if a partition is defined with the same name */
for_each_child_of_node(partitions, mtd_dn) {
- offset = 0;
-
/* Skip partition with no/wrong prefix */
- if (!of_node_name_prefix(mtd_dn, "partition-"))
+ if (!of_node_name_prefix(mtd_dn, prefix))
continue;
/* Label have priority. Check that first */
- if (of_property_read_string(mtd_dn, "label", &pname)) {
- of_property_read_string(mtd_dn, "name", &pname);
+ if (!of_property_read_string(mtd_dn, "label", &pname)) {
+ offset = 0;
+ } else {
+ pname = mtd_dn->name;
offset = prefix_len;
}
plen = strlen(pname) - offset;
if (plen == mtd_name_len &&
!strncmp(mtd->name, pname + offset, plen)) {
- found = true;
+ mtd_set_of_node(mtd, mtd_dn);
break;
}
}
- if (!found)
- goto exit_partitions;
-
- /* Set of_node only for nvmem */
- if (of_device_is_compatible(mtd_dn, "nvmem-cells"))
- mtd_set_of_node(mtd, mtd_dn);
-
-exit_partitions:
of_node_put(partitions);
exit_parent:
of_node_put(parent_dn);
@@ -723,8 +716,10 @@ int add_mtd_device(struct mtd_info *mtd)
mtd_check_of_node(mtd);
of_node_get(mtd_get_of_node(mtd));
error = device_register(&mtd->dev);
- if (error)
+ if (error) {
+ put_device(&mtd->dev);
goto fail_added;
+ }
/* Add the nvmem provider */
error = mtd_nvmem_add(mtd);
@@ -743,6 +738,17 @@ int add_mtd_device(struct mtd_info *mtd)
not->add(mtd);
mutex_unlock(&mtd_table_mutex);
+
+ if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) {
+ if (IS_BUILTIN(CONFIG_MTD)) {
+ pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
+ } else {
+ pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n",
+ mtd->index, mtd->name);
+ }
+ }
+
/* We _know_ we aren't being removed, because
our caller is still holding us here. So none
of this try_ nonsense, and no bitching about it
@@ -774,6 +780,7 @@ int del_mtd_device(struct mtd_info *mtd)
{
int ret;
struct mtd_notifier *not;
+ struct device_node *mtd_of_node;
mutex_lock(&mtd_table_mutex);
@@ -792,6 +799,7 @@ int del_mtd_device(struct mtd_info *mtd)
mtd->index, mtd->name, mtd->usecount);
ret = -EBUSY;
} else {
+ mtd_of_node = mtd_get_of_node(mtd);
debugfs_remove_recursive(mtd->dbg.dfs_dir);
/* Try to remove the NVMEM provider */
@@ -803,7 +811,7 @@ int del_mtd_device(struct mtd_info *mtd)
memset(&mtd->dev, 0, sizeof(mtd->dev));
idr_remove(&mtd_idr, mtd->index);
- of_node_put(mtd_get_of_node(mtd));
+ of_node_put(mtd_of_node);
module_put(THIS_MODULE);
ret = 0;
@@ -2483,6 +2491,7 @@ static int __init init_mtd(void)
out_procfs:
if (proc_mtd)
remove_proc_entry("mtd", NULL);
+ bdi_unregister(mtd_bdi);
bdi_put(mtd_bdi);
err_bdi:
class_unregister(&mtd_class);
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 3d4a2ffb5b01..2f11585b5613 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -7,6 +7,8 @@
* Author: Richard Purdie <rpurdie@openedhand.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/console.h>
@@ -93,9 +95,9 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
ret = mtd_erase(mtd, &erase);
if (ret) {
- printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
- (unsigned long long)erase.addr,
- (unsigned long long)erase.len, mtddev);
+ pr_warn("erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
+ (unsigned long long)erase.addr,
+ (unsigned long long)erase.len, mtddev);
return ret;
}
@@ -106,29 +108,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
return 0;
}
-static void mtdoops_inc_counter(struct mtdoops_context *cxt)
-{
- cxt->nextpage++;
- if (cxt->nextpage >= cxt->oops_pages)
- cxt->nextpage = 0;
- cxt->nextcount++;
- if (cxt->nextcount == 0xffffffff)
- cxt->nextcount = 0;
-
- if (page_is_used(cxt, cxt->nextpage)) {
- schedule_work(&cxt->work_erase);
- return;
- }
-
- printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
- cxt->nextpage, cxt->nextcount);
-}
-
-/* Scheduled work - when we can't proceed without erasing a block */
-static void mtdoops_workfunc_erase(struct work_struct *work)
+static void mtdoops_erase(struct mtdoops_context *cxt)
{
- struct mtdoops_context *cxt =
- container_of(work, struct mtdoops_context, work_erase);
struct mtd_info *mtd = cxt->mtd;
int i = 0, j, ret, mod;
@@ -145,20 +126,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) {
badblock:
- printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
- cxt->nextpage * record_size);
+ pr_warn("bad block at %08lx\n",
+ cxt->nextpage * record_size);
i++;
cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size);
if (cxt->nextpage >= cxt->oops_pages)
cxt->nextpage = 0;
if (i == cxt->oops_pages / (mtd->erasesize / record_size)) {
- printk(KERN_ERR "mtdoops: all blocks bad!\n");
+ pr_err("all blocks bad!\n");
return;
}
}
if (ret < 0) {
- printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n");
+ pr_err("mtd_block_isbad failed, aborting\n");
return;
}
@@ -166,21 +147,55 @@ badblock:
ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
if (ret >= 0) {
- printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
- cxt->nextpage, cxt->nextcount);
+ pr_debug("ready %d, %d\n",
+ cxt->nextpage, cxt->nextcount);
return;
}
if (ret == -EIO) {
ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
if (ret < 0 && ret != -EOPNOTSUPP) {
- printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
+ pr_err("block_markbad failed, aborting\n");
return;
}
}
goto badblock;
}
+/* Scheduled work - when we can't proceed without erasing a block */
+static void mtdoops_workfunc_erase(struct work_struct *work)
+{
+ struct mtdoops_context *cxt =
+ container_of(work, struct mtdoops_context, work_erase);
+ mtdoops_erase(cxt);
+}
+
+static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic)
+{
+ cxt->nextpage++;
+ if (cxt->nextpage >= cxt->oops_pages)
+ cxt->nextpage = 0;
+ cxt->nextcount++;
+ if (cxt->nextcount == 0xffffffff)
+ cxt->nextcount = 0;
+
+ if (page_is_used(cxt, cxt->nextpage)) {
+ pr_debug("not ready %d, %d (erase %s)\n",
+ cxt->nextpage, cxt->nextcount,
+ panic ? "immediately" : "scheduled");
+ if (panic) {
+ /* In case of panic, erase immediately */
+ mtdoops_erase(cxt);
+ } else {
+ /* Otherwise, schedule work to erase it "nicely" */
+ schedule_work(&cxt->work_erase);
+ }
+ } else {
+ pr_debug("ready %d, %d (no erase)\n",
+ cxt->nextpage, cxt->nextcount);
+ }
+}
+
static void mtdoops_write(struct mtdoops_context *cxt, int panic)
{
struct mtd_info *mtd = cxt->mtd;
@@ -201,7 +216,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
ret = mtd_panic_write(mtd, cxt->nextpage * record_size,
record_size, &retlen, cxt->oops_buf);
if (ret == -EOPNOTSUPP) {
- printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+ pr_err("Cannot write from panic without panic_write\n");
goto out;
}
} else
@@ -209,12 +224,12 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
record_size, &retlen, cxt->oops_buf);
if (retlen != record_size || ret < 0)
- printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n",
+ pr_err("write failure at %ld (%td of %ld written), error %d\n",
cxt->nextpage * record_size, retlen, record_size, ret);
mark_page_used(cxt, cxt->nextpage);
memset(cxt->oops_buf, 0xff, record_size);
- mtdoops_inc_counter(cxt);
+ mtdoops_inc_counter(cxt, panic);
out:
clear_bit(0, &cxt->oops_buf_busy);
}
@@ -244,7 +259,7 @@ static void find_next_position(struct mtdoops_context *cxt)
&retlen, (u_char *)&hdr);
if (retlen != sizeof(hdr) ||
(ret < 0 && !mtd_is_bitflip(ret))) {
- printk(KERN_ERR "mtdoops: read failure at %ld (%zu of %zu read), err %d\n",
+ pr_err("read failure at %ld (%zu of %zu read), err %d\n",
page * record_size, retlen, sizeof(hdr), ret);
continue;
}
@@ -279,7 +294,7 @@ static void find_next_position(struct mtdoops_context *cxt)
cxt->nextcount = maxcount;
}
- mtdoops_inc_counter(cxt);
+ mtdoops_inc_counter(cxt, 0);
}
static void mtdoops_do_dump(struct kmsg_dumper *dumper,
@@ -324,17 +339,17 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
return;
if (mtd->size < mtd->erasesize * 2) {
- printk(KERN_ERR "mtdoops: MTD partition %d not big enough for mtdoops\n",
+ pr_err("MTD partition %d not big enough for mtdoops\n",
mtd->index);
return;
}
if (mtd->erasesize < record_size) {
- printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n",
+ pr_err("eraseblock size of MTD partition %d too small\n",
mtd->index);
return;
}
if (mtd->size > MTDOOPS_MAX_MTD_SIZE) {
- printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n",
+ pr_err("mtd%d is too large (limit is %d MiB)\n",
mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024);
return;
}
@@ -345,7 +360,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
DIV_ROUND_UP(mtdoops_pages,
BITS_PER_LONG)));
if (!cxt->oops_page_used) {
- printk(KERN_ERR "mtdoops: could not allocate page array\n");
+ pr_err("could not allocate page array\n");
return;
}
@@ -353,7 +368,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
cxt->dump.dump = mtdoops_do_dump;
err = kmsg_dump_register(&cxt->dump);
if (err) {
- printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err);
+ pr_err("registering kmsg dumper failed, error %d\n", err);
vfree(cxt->oops_page_used);
cxt->oops_page_used = NULL;
return;
@@ -362,7 +377,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
cxt->mtd = mtd;
cxt->oops_pages = (int)mtd->size / record_size;
find_next_position(cxt);
- printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
+ pr_info("Attached to MTD device %d\n", mtd->index);
}
static void mtdoops_notify_remove(struct mtd_info *mtd)
@@ -373,7 +388,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
return;
if (kmsg_dump_unregister(&cxt->dump) < 0)
- printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n");
+ pr_warn("could not unregister kmsg_dumper\n");
cxt->mtd = NULL;
flush_work(&cxt->work_erase);
@@ -393,15 +408,15 @@ static int __init mtdoops_init(void)
char *endp;
if (strlen(mtddev) == 0) {
- printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+ pr_err("mtd device (mtddev=name/number) must be supplied\n");
return -EINVAL;
}
if ((record_size & 4095) != 0) {
- printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
+ pr_err("record_size must be a multiple of 4096\n");
return -EINVAL;
}
if (record_size < 4096) {
- printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
+ pr_err("record_size must be over 4096 bytes\n");
return -EINVAL;
}
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index dbd7b06524b3..7737b1a4a177 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved);
*
* Return: 0 in case of success, a negative error code otherwise.
*/
-int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
+static int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
{
if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
pr_warn("attempt to erase a bad/reserved block @%llx\n",
@@ -136,7 +136,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
return nand->ops->erase(nand, pos);
}
-EXPORT_SYMBOL_GPL(nanddev_erase);
/**
* nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
diff --git a/drivers/mtd/nand/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig
index 34d9a7a82ad4..c94bf483541e 100644
--- a/drivers/mtd/nand/onenand/Kconfig
+++ b/drivers/mtd/nand/onenand/Kconfig
@@ -26,6 +26,7 @@ config MTD_ONENAND_OMAP2
tristate "OneNAND on OMAP2/OMAP3 support"
depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM)
depends on OF || COMPILE_TEST
+ depends on OMAP_GPMC
help
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
via the GPMC memory controller.
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 4cd40af362de..98ea1c9e65c8 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -415,7 +415,7 @@ config MTD_NAND_PLATFORM
config MTD_NAND_CADENCE
tristate "Support Cadence NAND (HPNFC) controller"
- depends on (OF || COMPILE_TEST) && HAS_IOMEM
+ depends on OF && HAS_IOMEM
help
Enable the driver for NAND flash on platforms using a Cadence NAND
controller.
@@ -430,7 +430,7 @@ config MTD_NAND_ARASAN
config MTD_NAND_INTEL_LGM
tristate "Support for NAND controller on Intel LGM SoC"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on HAS_IOMEM
help
Enables support for NAND Flash chips on Intel's LGM SoC.
@@ -450,7 +450,7 @@ config MTD_NAND_ROCKCHIP
config MTD_NAND_PL35X
tristate "ARM PL35X NAND controller"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on PL353_SMC
help
Enables support for PrimeCell SMC PL351 and PL353 NAND
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 9dac3ca69d57..7661a5cf1883 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl)
if (cadence_nand_read_bch_caps(cdns_ctrl))
return -EIO;
+#ifndef CONFIG_64BIT
+ if (cdns_ctrl->caps2.data_dma_width == 8) {
+ dev_err(cdns_ctrl->dev,
+ "cannot access 64-bit dma on !64-bit architectures");
+ return -EIO;
+ }
+#endif
+
/*
* Set IO width access to 8.
* It is because during SW device discovering width access
@@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status;
if (!cdns_ctrl->caps1->has_dma) {
- int len_in_words = len >> 2;
+ u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
+
+ int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
/* read alingment data */
- ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+ if (data_dma_width == 4)
+ ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+#ifdef CONFIG_64BIT
+ else
+ readsq(cdns_ctrl->io.virt, buf, len_in_words);
+#endif
+
if (sdma_size > len) {
+ int read_bytes = (data_dma_width == 4) ?
+ len_in_words << 2 : len_in_words << 3;
+
/* read rest data from slave DMA interface if any */
- ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
- sdma_size / 4 - len_in_words);
+ if (data_dma_width == 4)
+ ioread32_rep(cdns_ctrl->io.virt,
+ cdns_ctrl->buf,
+ sdma_size / 4 - len_in_words);
+#ifdef CONFIG_64BIT
+ else
+ readsq(cdns_ctrl->io.virt, cdns_ctrl->buf,
+ sdma_size / 8 - len_in_words);
+#endif
+
/* copy rest of data */
- memcpy(buf + (len_in_words << 2), cdns_ctrl->buf,
- len - (len_in_words << 2));
+ memcpy(buf + read_bytes, cdns_ctrl->buf,
+ len - read_bytes);
}
return 0;
}
@@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status;
if (!cdns_ctrl->caps1->has_dma) {
- int len_in_words = len >> 2;
+ u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
+
+ int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
+
+ if (data_dma_width == 4)
+ iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+#ifdef CONFIG_64BIT
+ else
+ writesq(cdns_ctrl->io.virt, buf, len_in_words);
+#endif
- iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
if (sdma_size > len) {
+ int written_bytes = (data_dma_width == 4) ?
+ len_in_words << 2 : len_in_words << 3;
+
/* copy rest of data */
- memcpy(cdns_ctrl->buf, buf + (len_in_words << 2),
- len - (len_in_words << 2));
+ memcpy(cdns_ctrl->buf, buf + written_bytes,
+ len - written_bytes);
+
/* write all expected by nand controller data */
- iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
- sdma_size / 4 - len_in_words);
+ if (data_dma_width == 4)
+ iowrite32_rep(cdns_ctrl->io.virt,
+ cdns_ctrl->buf,
+ sdma_size / 4 - len_in_words);
+#ifdef CONFIG_64BIT
+ else
+ writesq(cdns_ctrl->io.virt, cdns_ctrl->buf,
+ sdma_size / 8 - len_in_words);
+#endif
}
return 0;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 01ccbde748f3..ada83344b0f9 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -148,11 +148,9 @@ static int gpmi_init(struct gpmi_nand_data *this)
struct resources *r = &this->resources;
int ret;
- ret = pm_runtime_get_sync(this->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(this->dev);
+ ret = pm_runtime_resume_and_get(this->dev);
+ if (ret < 0)
return ret;
- }
ret = gpmi_reset_block(r->gpmi_regs, false);
if (ret)
@@ -2504,11 +2502,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip,
for (i = 0; i < GPMI_MAX_TRANSFERS; i++)
this->transfers[i].direction = DMA_NONE;
- ret = pm_runtime_get_sync(this->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(this->dev);
+ ret = pm_runtime_resume_and_get(this->dev);
+ if (ret < 0)
return ret;
- }
/*
* This driver currently supports only one NAND chip. Plus, dies share
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index 452ecaf7775a..ae7f6429a5f6 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -25,7 +25,7 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mtd/lpc32xx_mlc.h>
#include <linux/io.h>
#include <linux/mm.h>
@@ -122,7 +122,6 @@ struct lpc32xx_nand_cfg_mlc {
uint32_t rd_low;
uint32_t wr_high;
uint32_t wr_low;
- int wp_gpio;
struct mtd_partition *parts;
unsigned num_parts;
};
@@ -177,6 +176,7 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk;
+ struct gpio_desc *wp_gpio;
void __iomem *io_base;
int irq;
struct lpc32xx_nand_cfg_mlc *ncfg;
@@ -370,8 +370,8 @@ static int lpc32xx_waitfunc(struct nand_chip *chip)
*/
static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
{
- if (gpio_is_valid(host->ncfg->wp_gpio))
- gpio_set_value(host->ncfg->wp_gpio, 0);
+ if (host->wp_gpio)
+ gpiod_set_value_cansleep(host->wp_gpio, 1);
}
/*
@@ -379,8 +379,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
*/
static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
{
- if (gpio_is_valid(host->ncfg->wp_gpio))
- gpio_set_value(host->ncfg->wp_gpio, 1);
+ if (host->wp_gpio)
+ gpiod_set_value_cansleep(host->wp_gpio, 0);
}
static void lpc32xx_dma_complete_func(void *completion)
@@ -636,8 +636,6 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
return NULL;
}
- ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
-
return ncfg;
}
@@ -713,14 +711,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
"Missing or bad NAND config from device tree\n");
return -ENOENT;
}
- if (host->ncfg->wp_gpio == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- if (gpio_is_valid(host->ncfg->wp_gpio) &&
- gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
- dev_err(&pdev->dev, "GPIO not available\n");
- return -EBUSY;
+
+ /* Start with WP disabled, if available */
+ host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
+ res = PTR_ERR_OR_ZERO(host->wp_gpio);
+ if (res) {
+ if (res != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "WP GPIO is not available: %d\n",
+ res);
+ return res;
}
- lpc32xx_wp_disable(host);
+
+ gpiod_set_consumer_name(host->wp_gpio, "NAND WP");
host->pdata = dev_get_platdata(&pdev->dev);
@@ -817,7 +819,7 @@ put_clk:
clk_put(host->clk);
free_gpio:
lpc32xx_wp_enable(host);
- gpio_free(host->ncfg->wp_gpio);
+ gpiod_put(host->wp_gpio);
return res;
}
@@ -843,12 +845,11 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
clk_put(host->clk);
lpc32xx_wp_enable(host);
- gpio_free(host->ncfg->wp_gpio);
+ gpiod_put(host->wp_gpio);
return 0;
}
-#ifdef CONFIG_PM
static int lpc32xx_nand_resume(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@@ -880,11 +881,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
return 0;
}
-#else
-#define lpc32xx_nand_resume NULL
-#define lpc32xx_nand_suspend NULL
-#endif
-
static const struct of_device_id lpc32xx_nand_match[] = {
{ .compatible = "nxp,lpc3220-mlc" },
{ /* sentinel */ },
@@ -894,8 +890,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove,
- .resume = lpc32xx_nand_resume,
- .suspend = lpc32xx_nand_suspend,
+ .resume = pm_ptr(lpc32xx_nand_resume),
+ .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = {
.name = DRV_NAME,
.of_match_table = lpc32xx_nand_match,
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index 6b7269cfb7d8..6918737346c9 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -23,9 +23,8 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/mtd/lpc32xx_slc.h>
#define LPC32XX_MODNAME "lpc32xx-nand"
@@ -208,7 +207,6 @@ struct lpc32xx_nand_cfg_slc {
uint32_t rwidth;
uint32_t rhold;
uint32_t rsetup;
- int wp_gpio;
struct mtd_partition *parts;
unsigned num_parts;
};
@@ -217,6 +215,7 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip;
struct lpc32xx_slc_platform_data *pdata;
struct clk *clk;
+ struct gpio_desc *wp_gpio;
void __iomem *io_base;
struct lpc32xx_nand_cfg_slc *ncfg;
@@ -309,8 +308,8 @@ static int lpc32xx_nand_device_ready(struct nand_chip *chip)
*/
static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
{
- if (gpio_is_valid(host->ncfg->wp_gpio))
- gpio_set_value(host->ncfg->wp_gpio, 0);
+ if (host->wp_gpio)
+ gpiod_set_value_cansleep(host->wp_gpio, 1);
}
/*
@@ -318,8 +317,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
*/
static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
{
- if (gpio_is_valid(host->ncfg->wp_gpio))
- gpio_set_value(host->ncfg->wp_gpio, 1);
+ if (host->wp_gpio)
+ gpiod_set_value_cansleep(host->wp_gpio, 0);
}
/*
@@ -764,8 +763,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
return NULL;
}
- ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
-
return ncfg;
}
@@ -852,14 +849,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
"Missing or bad NAND config from device tree\n");
return -ENOENT;
}
- if (host->ncfg->wp_gpio == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
- host->ncfg->wp_gpio, "NAND WP")) {
- dev_err(&pdev->dev, "GPIO not available\n");
- return -EBUSY;
+
+ /* Start with WP disabled, if available */
+ host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
+ res = PTR_ERR_OR_ZERO(host->wp_gpio);
+ if (res) {
+ if (res != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "WP GPIO is not available: %d\n",
+ res);
+ return res;
}
- lpc32xx_wp_disable(host);
+
+ gpiod_set_consumer_name(host->wp_gpio, "NAND WP");
host->pdata = dev_get_platdata(&pdev->dev);
@@ -968,7 +969,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int lpc32xx_nand_resume(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@@ -1007,11 +1007,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
return 0;
}
-#else
-#define lpc32xx_nand_resume NULL
-#define lpc32xx_nand_suspend NULL
-#endif
-
static const struct of_device_id lpc32xx_nand_match[] = {
{ .compatible = "nxp,lpc3220-slc" },
{ /* sentinel */ },
@@ -1021,8 +1016,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove,
- .resume = lpc32xx_nand_resume,
- .suspend = lpc32xx_nand_suspend,
+ .resume = pm_ptr(lpc32xx_nand_resume),
+ .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = {
.name = LPC32XX_MODNAME,
.of_match_table = lpc32xx_nand_match,
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index b9d1e96e3334..42c64dcea767 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -114,6 +114,7 @@
#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
+#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN BIT(27)
#define GENCONF_CLK_GATING_CTRL 0x220
#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
#define GENCONF_ND_CLK_CTRL 0x700
@@ -2880,7 +2881,8 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
GENCONF_SOC_DEVICE_MUX_NFC_EN |
GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
- GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
+ GENCONF_SOC_DEVICE_MUX_NFC_INT_EN |
+ GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN);
regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
GENCONF_CLK_GATING_CTRL_ND_GATE,
diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
index 800d774aed8e..f68349cb7824 100644
--- a/drivers/mtd/nand/raw/mpc5121_nfc.c
+++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -663,7 +663,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
prv->irq = irq_of_parse_and_map(dn, 0);
- if (prv->irq == NO_IRQ) {
+ if (!prv->irq) {
dev_err(dev, "Error mapping IRQ!\n");
return -EINVAL;
}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 33f2c98a030e..c3cc66039925 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5834,7 +5834,7 @@ nand_match_ecc_req(struct nand_chip *chip,
int req_step = requirements->step_size;
int req_strength = requirements->strength;
int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
- int best_step, best_strength, best_ecc_bytes;
+ int best_step = 0, best_strength = 0, best_ecc_bytes = 0;
int best_ecc_bytes_total = INT_MAX;
int i, j;
@@ -5915,7 +5915,7 @@ nand_maximize_ecc(struct nand_chip *chip,
int step_size, strength, nsteps, ecc_bytes, corr;
int best_corr = 0;
int best_step = 0;
- int best_strength, best_ecc_bytes;
+ int best_strength = 0, best_ecc_bytes = 0;
int i, j;
for (i = 0; i < caps->nstepinfos; i++) {
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 672719023241..c21abf748948 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -1405,9 +1405,9 @@ static void ns_do_bit_flips(struct nandsim *ns, int num)
if (bitflips && get_random_u16() < (1 << 6)) {
int flips = 1;
if (bitflips > 1)
- flips = prandom_u32_max(bitflips) + 1;
+ flips = get_random_u32_inclusive(1, bitflips);
while (flips--) {
- int pos = prandom_u32_max(num * 8);
+ int pos = get_random_u32_below(num * 8);
ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
NS_WARN("read_page: flipping bit %d in page %d "
"reading from %d ecc: corrected=%u failed=%u\n",
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 8f80019a9f01..198a44794d2d 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -3167,16 +3167,18 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
if (ret)
- nand_cleanup(chip);
+ goto err;
if (nandc->props->use_codeword_fixup) {
ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn);
- if (ret) {
- nand_cleanup(chip);
- return ret;
- }
+ if (ret)
+ goto err;
}
+ return 0;
+
+err:
+ nand_cleanup(chip);
return ret;
}
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 76684428354e..3ad58cd284d8 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -74,9 +74,75 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->spimem, &op);
}
+static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 64 + (16 * section);
+ region->length = 13;
+
+ return 0;
+}
+
+static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = (16 * section) + 2;
+ region->length = 14;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
+ .ecc = w25n02kv_ooblayout_ecc,
+ .free = w25n02kv_ooblayout_free,
+};
+
+static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ u8 mbf = 0;
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ /*
+ * Let's try to retrieve the real maximum number of bitflips
+ * in order to avoid forcing the wear-leveling layer to move
+ * data around if it's not necessary.
+ */
+ if (spi_mem_exec_op(spinand->spimem, &op))
+ return nanddev_get_ecc_conf(nand)->strength;
+
+ mbf >>= 4;
+
+ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
+ return nanddev_get_ecc_conf(nand)->strength;
+
+ return mbf;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO("W25M02GV",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -86,7 +152,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
SPINAND_INFO("W25N01GV",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -94,6 +160,15 @@ static const struct spinand_info winbond_spinand_table[] = {
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+ SPINAND_INFO("W25N02KV",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
};
static int winbond_spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig
index aaa06050c9bc..b20e0c38b517 100644
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -22,7 +22,7 @@ config MTD_BCM63XX_PARTS
config MTD_BRCM_U_BOOT
tristate "Broadcom's U-Boot partition parser"
- depends on ARCH_BCM4908 || COMPILE_TEST
+ depends on ARCH_BCMBCA || COMPILE_TEST
help
Broadcom uses a custom way of storing U-Boot environment variables.
They are placed inside U-Boot partition itself at unspecified offset.
@@ -75,7 +75,7 @@ config MTD_OF_PARTS
This provides a open firmware device tree partition parser
which derives the partition map from the children of the
flash memory node, as described in
- Documentation/devicetree/bindings/mtd/partition.txt.
+ Documentation/devicetree/bindings/mtd/mtd.yaml.
config MTD_OF_PARTS_BCM4908
bool "BCM4908 partitioning support"
@@ -123,6 +123,21 @@ config MTD_AFS_PARTS
for your particular device. It won't happen automatically. The
'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
+config MTD_PARSER_TPLINK_SAFELOADER
+ tristate "TP-Link Safeloader partitions parser"
+ depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST)
+ help
+ TP-Link home routers use flash partitions to store various data. Info
+ about flash space layout is stored in a partitions table using a
+ custom ASCII-based format.
+
+ That format was first found in devices with SafeLoader bootloader and
+ was named after it. Later it was adapted to CFE and U-Boot
+ bootloaders.
+
+ This driver reads partitions table, parses it and creates MTD
+ partitions.
+
config MTD_PARSER_TRX
tristate "Parser for TRX format partitions"
depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST)
diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile
index 23fa4de4016f..0e70b621a1d8 100644
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c
new file mode 100644
index 000000000000..f601e7bd8627
--- /dev/null
+++ b/drivers/mtd/parsers/tplink_safeloader.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#define TPLINK_SAFELOADER_DATA_OFFSET 4
+#define TPLINK_SAFELOADER_MAX_PARTS 32
+
+struct safeloader_cmn_header {
+ __be32 size;
+ uint32_t unused;
+} __packed;
+
+static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd)
+{
+ struct safeloader_cmn_header hdr;
+ struct device_node *np;
+ size_t bytes_read;
+ size_t size;
+ u32 offset;
+ char *buf;
+ int err;
+
+ np = mtd_get_of_node(mtd);
+ if (mtd_is_partition(mtd))
+ of_node_get(np);
+ else
+ np = of_get_child_by_name(np, "partitions");
+
+ if (of_property_read_u32(np, "partitions-table-offset", &offset)) {
+ pr_err("Failed to get partitions table offset\n");
+ goto err_put;
+ }
+
+ err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("Failed to read from %s at 0x%x\n", mtd->name, offset);
+ goto err_put;
+ }
+
+ size = be32_to_cpu(hdr.size);
+
+ buf = kmalloc(size + 1, GFP_KERNEL);
+ if (!buf)
+ goto err_put;
+
+ err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr));
+ goto err_kfree;
+ }
+
+ buf[size] = '\0';
+
+ of_node_put(np);
+
+ return buf;
+
+err_kfree:
+ kfree(buf);
+err_put:
+ of_node_put(np);
+ return NULL;
+}
+
+static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct mtd_partition *parts;
+ char name[65];
+ size_t offset;
+ size_t bytes;
+ char *buf;
+ int idx;
+ int err;
+
+ parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
+ if (!parts) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ buf = mtd_parser_tplink_safeloader_read_table(mtd);
+ if (!buf) {
+ err = -ENOENT;
+ goto err_out;
+ }
+
+ for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
+ idx < TPLINK_SAFELOADER_MAX_PARTS &&
+ sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n",
+ name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
+ idx++, offset += bytes + 1) {
+ parts[idx].name = kstrdup(name, GFP_KERNEL);
+ if (!parts[idx].name) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+ }
+
+ if (idx == TPLINK_SAFELOADER_MAX_PARTS)
+ pr_warn("Reached maximum number of partitions!\n");
+
+ kfree(buf);
+
+ *pparts = parts;
+
+ return idx;
+
+err_free:
+ for (idx -= 1; idx >= 0; idx--)
+ kfree(parts[idx].name);
+err_out:
+ return err;
+};
+
+static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts,
+ int nr_parts)
+{
+ int i;
+
+ for (i = 0; i < nr_parts; i++)
+ kfree(pparts[i].name);
+
+ kfree(pparts);
+}
+
+static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = {
+ { .compatible = "tplink,safeloader-partitions" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table);
+
+static struct mtd_part_parser mtd_parser_tplink_safeloader = {
+ .parse_fn = mtd_parser_tplink_safeloader_parse,
+ .cleanup = mtd_parser_tplink_safeloader_cleanup,
+ .name = "tplink-safeloader",
+ .of_match_table = mtd_parser_tplink_safeloader_of_match_table,
+};
+module_mtd_part_parser(mtd_parser_tplink_safeloader);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index bee8fc4c9f07..d8703d7dfd0a 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -1184,6 +1184,8 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
continue;
erase = &map->erase_type[i];
+ if (!erase->size)
+ continue;
/* Alignment is not mandatory for overlaid regions */
if (region->offset & SNOR_OVERLAID_REGION &&
@@ -1632,6 +1634,16 @@ static const struct spi_nor_manufacturer *manufacturers[] = {
&spi_nor_xmc,
};
+static const struct flash_info spi_nor_generic_flash = {
+ .name = "spi-nor-generic",
+ /*
+ * JESD216 rev A doesn't specify the page size, therefore we need a
+ * sane default.
+ */
+ .page_size = 256,
+ .parse_sfdp = true,
+};
+
static const struct flash_info *spi_nor_match_id(struct spi_nor *nor,
const u8 *id)
{
@@ -1664,7 +1676,20 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
return ERR_PTR(ret);
}
+ /* Cache the complete flash ID. */
+ nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL);
+ if (!nor->id)
+ return ERR_PTR(-ENOMEM);
+
info = spi_nor_match_id(nor, id);
+
+ /* Fallback to a generic flash described only by its SFDP data. */
+ if (!info) {
+ ret = spi_nor_check_sfdp_signature(nor);
+ if (!ret)
+ info = &spi_nor_generic_flash;
+ }
+
if (!info) {
dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n",
SPI_NOR_MAX_ID_LEN, id);
@@ -1914,7 +1939,8 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
spi_nor_spimem_setup_op(nor, &op, read->proto);
/* convert the dummy cycles to the number of bytes */
- op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+ op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
+ op.dummy.buswidth / 8;
if (spi_nor_protocol_is_dtr(nor->read_proto))
op.dummy.nbytes *= 2;
@@ -2091,8 +2117,12 @@ static int spi_nor_select_pp(struct spi_nor *nor,
* spi_nor_select_uniform_erase() - select optimum uniform erase type
* @map: the erase map of the SPI NOR
* @wanted_size: the erase type size to search for. Contains the value of
- * info->sector_size or of the "small sector" size in case
- * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
+ * info->sector_size, the "small sector" size in case
+ * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined or 0 if
+ * there is no information about the sector size. The
+ * latter is the case if the flash parameters are parsed
+ * solely by SFDP, then the largest supported erase type
+ * is selected.
*
* Once the optimum uniform sector erase command is found, disable all the
* other.
@@ -2113,6 +2143,10 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
tested_erase = &map->erase_type[i];
+ /* Skip masked erase types. */
+ if (!tested_erase->size)
+ continue;
+
/*
* If the current erase size is the one, stop here:
* we have found the right uniform Sector Erase command.
@@ -2565,6 +2599,12 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
params->hwcaps.mask |= SNOR_HWCAPS_PP;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP, SNOR_PROTO_1_1_1);
+
+ if (info->flags & SPI_NOR_QUAD_PP) {
+ params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
+ spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
+ SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4);
+ }
}
/**
@@ -2840,10 +2880,20 @@ static void spi_nor_put_device(struct mtd_info *mtd)
void spi_nor_restore(struct spi_nor *nor)
{
+ int ret;
+
/* restore the addressing mode */
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
- nor->flags & SNOR_F_BROKEN_RESET)
- nor->params->set_4byte_addr_mode(nor, false);
+ nor->flags & SNOR_F_BROKEN_RESET) {
+ ret = nor->params->set_4byte_addr_mode(nor, false);
+ if (ret)
+ /*
+ * Do not stop the execution in the hope that the flash
+ * will default to the 3-byte address mode after the
+ * software reset.
+ */
+ dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret);
+ }
if (nor->flags & SNOR_F_SOFT_RESET)
spi_nor_soft_reset(nor);
@@ -2935,6 +2985,27 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
mtd->_put_device = spi_nor_put_device;
}
+static int spi_nor_hw_reset(struct spi_nor *nor)
+{
+ struct gpio_desc *reset;
+
+ reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR_OR_NULL(reset))
+ return PTR_ERR_OR_ZERO(reset);
+
+ /*
+ * Experimental delay values by looking at different flash device
+ * vendors datasheets.
+ */
+ usleep_range(1, 5);
+ gpiod_set_value_cansleep(reset, 1);
+ usleep_range(100, 150);
+ gpiod_set_value_cansleep(reset, 0);
+ usleep_range(1000, 1200);
+
+ return 0;
+}
+
int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps)
{
@@ -2967,6 +3038,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (!nor->bouncebuf)
return -ENOMEM;
+ ret = spi_nor_hw_reset(nor);
+ if (ret)
+ return ret;
+
info = spi_nor_get_flash_info(nor, name);
if (IS_ERR(info))
return PTR_ERR(info);
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 85b0cf254e97..f03b55cf7e6f 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -458,6 +458,7 @@ struct spi_nor_fixups {
* SPI_NOR_NO_ERASE: no erase command needed.
* NO_CHIP_ERASE: chip does not support chip erase.
* SPI_NOR_NO_FR: can't do fastread.
+ * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
*
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
* Used when SFDP tables are not defined in the flash. These
@@ -507,6 +508,7 @@ struct flash_info {
#define SPI_NOR_NO_ERASE BIT(6)
#define NO_CHIP_ERASE BIT(7)
#define SPI_NOR_NO_FR BIT(8)
+#define SPI_NOR_QUAD_PP BIT(9)
u8 no_sfdp_flags;
#define SPI_NOR_SKIP_SFDP BIT(0)
@@ -701,6 +703,9 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
const u8 *buf, size_t len);
+int spi_nor_check_sfdp_signature(struct spi_nor *nor);
+int spi_nor_parse_sfdp(struct spi_nor *nor);
+
static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
{
return container_of(mtd, struct spi_nor, mtd);
diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c
index df76cb5de3f9..ff895f6758ea 100644
--- a/drivers/mtd/spi-nor/debugfs.c
+++ b/drivers/mtd/spi-nor/debugfs.c
@@ -81,7 +81,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
int i;
seq_printf(s, "name\t\t%s\n", info->name);
- seq_printf(s, "id\t\t%*ph\n", info->id_len, info->id);
+ seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id);
string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
seq_printf(s, "size\t\t%s\n", buf);
seq_printf(s, "write size\t%u\n", params->writesize);
diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c
index 119b38e6fc2a..d57ddaf1525b 100644
--- a/drivers/mtd/spi-nor/gigadevice.c
+++ b/drivers/mtd/spi-nor/gigadevice.c
@@ -8,19 +8,29 @@
#include "core.h"
-static void gd25q256_default_init(struct spi_nor *nor)
+static int
+gd25q256_post_bfpt(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt)
{
/*
- * Some manufacturer like GigaDevice may use different
- * bit to set QE on different memories, so the MFR can't
- * indicate the quad_enable method for this case, we need
- * to set it in the default_init fixup hook.
+ * GD25Q256C supports the first version of JESD216 which does not define
+ * the Quad Enable methods. Overwrite the default Quad Enable method.
+ *
+ * GD25Q256 GENERATION | SFDP MAJOR VERSION | SFDP MINOR VERSION
+ * GD25Q256C | SFDP_JESD216_MAJOR | SFDP_JESD216_MINOR
+ * GD25Q256D | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR
+ * GD25Q256E | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR
*/
- nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
+ if (bfpt_header->major == SFDP_JESD216_MAJOR &&
+ bfpt_header->minor == SFDP_JESD216_MINOR)
+ nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
+
+ return 0;
}
static const struct spi_nor_fixups gd25q256_fixups = {
- .default_init = gd25q256_default_init,
+ .post_bfpt = gd25q256_post_bfpt,
};
static const struct flash_info gigadevice_nor_parts[] = {
diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index 89a66a19d754..a0ddad2afffc 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -70,9 +70,10 @@ static const struct flash_info issi_nor_parts[] = {
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
- { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ { "is25wp256", INFO(0x9d7019, 0, 0, 0)
+ PARSE_SFDP
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ FLAGS(SPI_NOR_QUAD_PP)
.fixups = &is25lp256_fixups },
/* PMC */
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index 3c9681a3f7a3..7bb86df52f0b 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -52,18 +52,21 @@ static int micron_st_nor_octal_dtr_en(struct spi_nor *nor)
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
+ u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
/* Use 20 dummy cycles for memory array reads. */
*buf = 20;
op = (struct spi_mem_op)
- MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR1V, 1, buf);
+ MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
+ SPINOR_REG_MT_CFR1V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
buf[0] = SPINOR_MT_OCT_DTR;
op = (struct spi_mem_op)
- MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR0V, 1, buf);
+ MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
+ SPINOR_REG_MT_CFR0V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
@@ -98,7 +101,8 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor)
buf[0] = SPINOR_MT_EXSPI;
buf[1] = SPINOR_REG_MT_CFR1V_DEF;
op = (struct spi_mem_op)
- MICRON_ST_NOR_WR_ANY_REG_OP(4, SPINOR_REG_MT_CFR0V, 2, buf);
+ MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
+ SPINOR_REG_MT_CFR0V, 2, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
if (ret)
return ret;
@@ -201,6 +205,8 @@ static const struct flash_info st_nor_parts[] = {
MFR_FLAGS(USE_FSR)
},
{ "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512)
+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
+ SPI_NOR_BP3_SR_BIT6)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
MFR_FLAGS(USE_FSR)
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 2257f1b4c2e2..8434f654eca1 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -135,8 +135,7 @@ struct sfdp_4bait {
/**
* spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
* addr_nbytes and read_dummy members of the struct spi_nor
- * should be previously
- * set.
+ * should be previously set.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the serial flash memory
* @len: number of bytes to read
@@ -1183,10 +1182,17 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
dummy = round_up(dummy, 2);
/* Update the fast read settings. */
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
0, dummy, opcode,
SNOR_PROTO_8_8_8_DTR);
+ /*
+ * Page Program is "Required Command" in the xSPI Profile 1.0. Update
+ * the params->hwcaps.mask here.
+ */
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
out:
kfree(dwords);
return ret;
@@ -1250,6 +1256,33 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor)
}
/**
+ * spi_nor_check_sfdp_signature() - check for a valid SFDP signature
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * Used to detect if the flash supports the RDSFDP command as well as the
+ * presence of a valid SFDP table.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+int spi_nor_check_sfdp_signature(struct spi_nor *nor)
+{
+ u32 signature;
+ int err;
+
+ /* Get the SFDP header. */
+ err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(signature),
+ &signature);
+ if (err < 0)
+ return err;
+
+ /* Check the SFDP signature. */
+ if (le32_to_cpu(signature) != SFDP_SIGNATURE)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
*
diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h
index bbf80d2990ab..c1969f0a2f46 100644
--- a/drivers/mtd/spi-nor/sfdp.h
+++ b/drivers/mtd/spi-nor/sfdp.h
@@ -107,6 +107,4 @@ struct sfdp_parameter_header {
u8 id_msb;
};
-int spi_nor_parse_sfdp(struct spi_nor *nor);
-
#endif /* __LINUX_MTD_SFDP_H */
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 0150049007be..b621cdfd506f 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -49,11 +49,13 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
+ u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
/* Use 24 dummy cycles for memory array reads. */
*buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf);
+ CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
+ SPINOR_REG_CYPRESS_CFR2V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
@@ -64,14 +66,16 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
/* Set the octal and DTR enable bits. */
buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf);
+ CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
+ SPINOR_REG_CYPRESS_CFR5V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
/* Read flash ID to make sure the switch was successful. */
- ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR);
+ ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf,
+ SNOR_PROTO_8_8_8_DTR);
if (ret) {
dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
return ret;
@@ -97,7 +101,8 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS;
buf[1] = 0;
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf);
+ CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
+ SPINOR_REG_CYPRESS_CFR5V, 2, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
if (ret)
return ret;
@@ -191,7 +196,8 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
static int cypress_nor_set_page_size(struct spi_nor *nor)
{
struct spi_mem_op op =
- CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR3V,
+ CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
+ SPINOR_REG_CYPRESS_CFR3V,
nor->bouncebuf);
int ret;
@@ -275,13 +281,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
cypress_nor_octal_dtr_dis(nor);
}
-static void s28hs512t_default_init(struct spi_nor *nor)
-{
- nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
- nor->params->writesize = 16;
-}
-
-static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor)
+static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
{
/*
* On older versions of the flash the xSPI Profile 1.0 table has the
@@ -309,17 +309,23 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor)
nor->params->rdsr_addr_nbytes = 4;
}
-static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
- const struct sfdp_parameter_header *bfpt_header,
- const struct sfdp_bfpt *bfpt)
+static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt)
{
return cypress_nor_set_page_size(nor);
}
-static const struct spi_nor_fixups s28hs512t_fixups = {
- .default_init = s28hs512t_default_init,
- .post_sfdp = s28hs512t_post_sfdp_fixup,
- .post_bfpt = s28hs512t_post_bfpt_fixup,
+static void s28hx_t_late_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
+ nor->params->writesize = 16;
+}
+
+static const struct spi_nor_fixups s28hx_t_fixups = {
+ .post_sfdp = s28hx_t_post_sfdp_fixup,
+ .post_bfpt = s28hx_t_post_bfpt_fixup,
+ .late_init = s28hx_t_late_init,
};
static int
@@ -453,10 +459,21 @@ static const struct flash_info spansion_nor_parts[] = {
.fixups = &s25hx_t_fixups },
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
FLAGS(SPI_NOR_NO_ERASE) },
+ { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256)
+ PARSE_SFDP
+ .fixups = &s28hx_t_fixups,
+ },
+ { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512)
+ PARSE_SFDP
+ .fixups = &s28hx_t_fixups,
+ },
{ "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_DTR_READ |
- SPI_NOR_OCTAL_DTR_PP)
- .fixups = &s28hs512t_fixups,
+ PARSE_SFDP
+ .fixups = &s28hx_t_fixups,
+ },
+ { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512)
+ PARSE_SFDP
+ .fixups = &s28hx_t_fixups,
},
};
diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c
index 9aec9d8a98ad..c09bb832b3b9 100644
--- a/drivers/mtd/spi-nor/sysfs.c
+++ b/drivers/mtd/spi-nor/sysfs.c
@@ -35,8 +35,10 @@ static ssize_t jedec_id_show(struct device *dev,
struct spi_device *spi = to_spi_device(dev);
struct spi_mem *spimem = spi_get_drvdata(spi);
struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+ const u8 *id = nor->info->id_len ? nor->info->id : nor->id;
+ u8 id_len = nor->info->id_len ?: SPI_NOR_MAX_ID_LEN;
- return sysfs_emit(buf, "%*phN\n", nor->info->id_len, nor->info->id);
+ return sysfs_emit(buf, "%*phN\n", id_len, id);
}
static DEVICE_ATTR_RO(jedec_id);
@@ -67,6 +69,21 @@ static struct bin_attribute *spi_nor_sysfs_bin_entries[] = {
NULL
};
+static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct spi_device *spi = to_spi_device(kobj_to_dev(kobj));
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+ if (attr == &dev_attr_manufacturer.attr && !nor->manufacturer)
+ return 0;
+ if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len && !nor->id)
+ return 0;
+
+ return 0444;
+}
+
static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj,
struct bin_attribute *attr, int n)
{
@@ -82,6 +99,7 @@ static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj,
static const struct attribute_group spi_nor_sysfs_group = {
.name = "spi-nor",
+ .is_visible = spi_nor_sysfs_is_visible,
.is_bin_visible = spi_nor_sysfs_is_bin_visible,
.attrs = spi_nor_sysfs_entries,
.bin_attrs = spi_nor_sysfs_bin_entries,
diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c
index ffaa24055259..ca39acf4112c 100644
--- a/drivers/mtd/spi-nor/winbond.c
+++ b/drivers/mtd/spi-nor/winbond.c
@@ -133,6 +133,9 @@ static const struct flash_info winbond_nor_parts[] = {
{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ |
SPI_NOR_DUAL_READ) },
+ { "w25q512nwq", INFO(0xef6020, 0, 0, 0)
+ PARSE_SFDP
+ OTP_INFO(256, 3, 0x1000, 0x1000) },
{ "w25q512nwm", INFO(0xef8020, 0, 64 * 1024, 1024)
PARSE_SFDP
OTP_INFO(256, 3, 0x1000, 0x1000) },
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 440988562cfd..824cc1c03b6a 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -47,7 +47,7 @@ struct nand_ecc_test {
static void single_bit_error_data(void *error_data, void *correct_data,
size_t size)
{
- unsigned int offset = prandom_u32_max(size * BITS_PER_BYTE);
+ unsigned int offset = get_random_u32_below(size * BITS_PER_BYTE);
memcpy(error_data, correct_data, size);
__change_bit_le(offset, error_data);
@@ -58,9 +58,9 @@ static void double_bit_error_data(void *error_data, void *correct_data,
{
unsigned int offset[2];
- offset[0] = prandom_u32_max(size * BITS_PER_BYTE);
+ offset[0] = get_random_u32_below(size * BITS_PER_BYTE);
do {
- offset[1] = prandom_u32_max(size * BITS_PER_BYTE);
+ offset[1] = get_random_u32_below(size * BITS_PER_BYTE);
} while (offset[0] == offset[1]);
memcpy(error_data, correct_data, size);
@@ -71,7 +71,7 @@ static void double_bit_error_data(void *error_data, void *correct_data,
static unsigned int random_ecc_bit(size_t size)
{
- unsigned int offset = prandom_u32_max(3 * BITS_PER_BYTE);
+ unsigned int offset = get_random_u32_below(3 * BITS_PER_BYTE);
if (size == 256) {
/*
@@ -79,7 +79,7 @@ static unsigned int random_ecc_bit(size_t size)
* and 17th bit) in ECC code for 256 byte data block
*/
while (offset == 16 || offset == 17)
- offset = prandom_u32_max(3 * BITS_PER_BYTE);
+ offset = get_random_u32_below(3 * BITS_PER_BYTE);
}
return offset;
diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c
index 75b6ddc5dc4d..8062098930d6 100644
--- a/drivers/mtd/tests/stresstest.c
+++ b/drivers/mtd/tests/stresstest.c
@@ -46,7 +46,7 @@ static int rand_eb(void)
again:
/* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
- eb = prandom_u32_max(ebcnt - 1);
+ eb = get_random_u32_below(ebcnt - 1);
if (bbt[eb])
goto again;
return eb;
@@ -54,12 +54,12 @@ again:
static int rand_offs(void)
{
- return prandom_u32_max(bufsize);
+ return get_random_u32_below(bufsize);
}
static int rand_len(int offs)
{
- return prandom_u32_max(bufsize - offs);
+ return get_random_u32_below(bufsize - offs);
}
static int do_read(void)
@@ -118,7 +118,7 @@ static int do_write(void)
static int do_operation(void)
{
- if (prandom_u32_max(2))
+ if (get_random_u32_below(2))
return do_read();
else
return do_write();
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 908d0e088557..fcca6942dbdd 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -590,7 +590,7 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
- ubi->dbg.power_cut_counter += prandom_u32_max(range);
+ ubi->dbg.power_cut_counter += get_random_u32_below(range);
}
return 0;
}
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index dc8d8f83657a..23676f32b681 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -73,7 +73,7 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
{
if (ubi->dbg.emulate_bitflips)
- return !prandom_u32_max(200);
+ return !get_random_u32_below(200);
return 0;
}
@@ -87,7 +87,7 @@ static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
{
if (ubi->dbg.emulate_io_failures)
- return !prandom_u32_max(500);
+ return !get_random_u32_below(500);
return 0;
}
@@ -101,7 +101,7 @@ static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
{
if (ubi->dbg.emulate_io_failures)
- return !prandom_u32_max(400);
+ return !get_random_u32_below(400);
return 0;
}
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index 24150c933fcb..dc3253b318da 100644
--- a/drivers/net/arcnet/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -113,6 +113,7 @@ static int com20020_probe(struct pcmcia_device *p_dev)
struct com20020_dev *info;
struct net_device *dev;
struct arcnet_local *lp;
+ int ret = -ENOMEM;
dev_dbg(&p_dev->dev, "com20020_attach()\n");
@@ -142,12 +143,18 @@ static int com20020_probe(struct pcmcia_device *p_dev)
info->dev = dev;
p_dev->priv = info;
- return com20020_config(p_dev);
+ ret = com20020_config(p_dev);
+ if (ret)
+ goto fail_config;
+
+ return 0;
+fail_config:
+ free_arcdev(dev);
fail_alloc_dev:
kfree(info);
fail_alloc_info:
- return -ENOMEM;
+ return ret;
} /* com20020_attach */
static void com20020_detach(struct pcmcia_device *link)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e84c49bf4d0c..b9a882f182d2 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3231,16 +3231,23 @@ static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
struct slave *curr_active_slave, *curr_arp_slave;
- struct icmp6hdr *hdr = icmp6_hdr(skb);
struct in6_addr *saddr, *daddr;
+ struct {
+ struct ipv6hdr ip6;
+ struct icmp6hdr icmp6;
+ } *combined, _combined;
if (skb->pkt_type == PACKET_OTHERHOST ||
- skb->pkt_type == PACKET_LOOPBACK ||
- hdr->icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT)
+ skb->pkt_type == PACKET_LOOPBACK)
+ goto out;
+
+ combined = skb_header_pointer(skb, 0, sizeof(_combined), &_combined);
+ if (!combined || combined->ip6.nexthdr != NEXTHDR_ICMP ||
+ combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT)
goto out;
- saddr = &ipv6_hdr(skb)->saddr;
- daddr = &ipv6_hdr(skb)->daddr;
+ saddr = &combined->ip6.saddr;
+ daddr = &combined->ip6.daddr;
slave_dbg(bond->dev, slave->dev, "%s: %s/%d av %d sv %d sip %pI6c tip %pI6c\n",
__func__, slave->dev->name, bond_slave_state(slave),
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 3a2d109a3792..199cb200f2bd 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -452,7 +452,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int mb, prio;
u32 reg_mid, reg_mcr;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
mb = get_tx_next_mb(priv);
diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
index d6605dbb7737..c63f7fc1e691 100644
--- a/drivers/net/can/c_can/c_can_main.c
+++ b/drivers/net/can/c_can/c_can_main.c
@@ -457,7 +457,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
struct c_can_tx_ring *tx_ring = &priv->tx;
u32 idx, obj, cmd = IF_COMM_TX;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
if (c_can_tx_busy(priv, tx_ring))
diff --git a/drivers/net/can/can327.c b/drivers/net/can/can327.c
index 0aa1af31d0fe..dc7192ecb001 100644
--- a/drivers/net/can/can327.c
+++ b/drivers/net/can/can327.c
@@ -263,8 +263,10 @@ static void can327_feed_frame_to_netdev(struct can327 *elm, struct sk_buff *skb)
{
lockdep_assert_held(&elm->lock);
- if (!netif_running(elm->dev))
+ if (!netif_running(elm->dev)) {
+ kfree_skb(skb);
return;
+ }
/* Queue for NAPI pickup.
* rx-offload will update stats and LEDs for us.
@@ -794,9 +796,9 @@ static int can327_netdev_close(struct net_device *dev)
netif_stop_queue(dev);
- /* Give UART one final chance to flush. */
- clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
- flush_work(&elm->tx_work);
+ /* We don't flush the UART TX queue here, as we want final stop
+ * commands (like the above dummy char) to be flushed out.
+ */
can_rx_offload_disable(&elm->offload);
elm->can.state = CAN_STATE_STOPPED;
@@ -813,7 +815,7 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb,
struct can327 *elm = netdev_priv(dev);
struct can_frame *frame = (struct can_frame *)skb->data;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
/* We shouldn't get here after a hardware fault:
@@ -1067,12 +1069,15 @@ static void can327_ldisc_close(struct tty_struct *tty)
{
struct can327 *elm = (struct can327 *)tty->disc_data;
- /* unregister_netdev() calls .ndo_stop() so we don't have to.
- * Our .ndo_stop() also flushes the TTY write wakeup handler,
- * so we can safely set elm->tty = NULL after this.
- */
+ /* unregister_netdev() calls .ndo_stop() so we don't have to. */
unregister_candev(elm->dev);
+ /* Give UART one final chance to flush.
+ * No need to clear TTY_DO_WRITE_WAKEUP since .write_wakeup() is
+ * serialised against .close() and will not be called once we return.
+ */
+ flush_work(&elm->tx_work);
+
/* Mark channel as dead */
spin_lock_bh(&elm->lock);
tty->disc_data = NULL;
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index 0b9dfc76e769..30909f3aab57 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -429,7 +429,7 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct cc770_priv *priv = netdev_priv(dev);
unsigned int mo = obj2msgobj(CC770_OBJ_TX);
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c
index 194c86e0f340..8f6dccd5a587 100644
--- a/drivers/net/can/cc770/cc770_isa.c
+++ b/drivers/net/can/cc770/cc770_isa.c
@@ -264,22 +264,24 @@ static int cc770_isa_probe(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev,
"couldn't register device (err=%d)\n", err);
- goto exit_unmap;
+ goto exit_free;
}
dev_info(&pdev->dev, "device registered (reg_base=0x%p, irq=%d)\n",
priv->reg_base, dev->irq);
return 0;
- exit_unmap:
+exit_free:
+ free_cc770dev(dev);
+exit_unmap:
if (mem[idx])
iounmap(base);
- exit_release:
+exit_release:
if (mem[idx])
release_mem_region(mem[idx], iosize);
else
release_region(port[idx], iosize);
- exit:
+exit:
return err;
}
diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c
index b8da15ea6ad9..64c349fd4600 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_base.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_base.c
@@ -600,7 +600,7 @@ static netdev_tx_t ctucan_start_xmit(struct sk_buff *skb, struct net_device *nde
bool ok;
unsigned long flags;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
if (unlikely(!CTU_CAN_FD_TXTNF(priv))) {
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 791a51e2f5d6..241ec636e91f 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -5,7 +5,6 @@
*/
#include <linux/can/dev.h>
-#include <linux/can/netlink.h>
#include <linux/module.h>
#define MOD_DESC "CAN device driver interface"
@@ -337,8 +336,6 @@ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
{
- struct can_priv *priv = netdev_priv(dev);
-
switch (ntohs(skb->protocol)) {
case ETH_P_CAN:
if (!can_is_can_skb(skb))
@@ -359,13 +356,8 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
goto inval_skb;
}
- if (!can_skb_headroom_valid(dev, skb)) {
+ if (!can_skb_headroom_valid(dev, skb))
goto inval_skb;
- } else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
- netdev_info_once(dev,
- "interface in listen only mode, dropping skb\n");
- goto inval_skb;
- }
return false;
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 5ee38e586fd8..9bdadd716f4e 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -742,7 +742,7 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_fd_len2dlc(cfd->len)) << 16);
int i;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 6c37aab93eb3..4bedcc3eea0d 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1345,7 +1345,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
unsigned long flags;
u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
/* Trying to transmit in silent mode will generate error interrupts, but
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
index 8d42b7e6661f..07eaf724a572 100644
--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -860,7 +860,7 @@ static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
u32 txst, txid, txdlc;
int i;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
/* Check if the TX buffer is full */
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 71a2caae0757..0732a5092141 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1693,7 +1693,7 @@ static netdev_tx_t ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
void __iomem *desc_addr;
unsigned long flags;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
spin_lock_irqsave(&mod->lock, flags);
diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c
index 4e9680c8eb34..bcad11709bc9 100644
--- a/drivers/net/can/kvaser_pciefd.c
+++ b/drivers/net/can/kvaser_pciefd.c
@@ -772,7 +772,7 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb,
int nwords;
u8 count;
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
nwords = kvaser_pciefd_prepare_tx_packet(&packet, can, skb);
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index dcb582563d5e..e5575d2755e4 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1721,7 +1721,7 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
{
struct m_can_classdev *cdev = netdev_priv(dev);
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
if (cdev->is_peripheral) {
@@ -1909,7 +1909,7 @@ int m_can_class_get_clocks(struct m_can_classdev *cdev)
cdev->hclk = devm_clk_get(cdev->dev, "hclk");
cdev->cclk = devm_clk_get(cdev->dev, "cclk");
- if (IS_ERR(cdev->cclk)) {
+ if (IS_ERR(cdev->hclk) || IS_ERR(cdev->cclk)) {
dev_err(cdev->dev, "no clock found\n");
ret = -ENODEV;
}
diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c
index 8f184a852a0a..f2219aa2824b 100644
--- a/drivers/net/can/m_can/m_can_pci.c
+++ b/drivers/net/can/m_can/m_can_pci.c
@@ -120,7 +120,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)
- return ret;
+ goto err_free_dev;
mcan_class->dev = &pci->dev;
mcan_class->net->irq = pci_irq_vector(pci, 0);
@@ -132,7 +132,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = m_can_class_register(mcan_class);
if (ret)
- goto err;
+ goto err_free_irq;
/* Enable interrupt control at CAN wrapper IP */
writel(0x1, base + CTL_CSR_INT_CTL_OFFSET);
@@ -144,8 +144,10 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
return 0;
-err:
+err_free_irq:
pci_free_irq_vectors(pci);
+err_free_dev:
+ m_can_class_free_dev(mcan_class->net);
return ret;
}
@@ -161,6 +163,7 @@ static void m_can_pci_remove(struct pci_dev *pci)
writel(0x0, priv->base + CTL_CSR_INT_CTL_OFFSET);
m_can_class_unregister(mcan_class);
+ m_can_class_free_dev(mcan_class->net);
pci_free_irq_vectors(pci);
}
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 2119fbb287ef..a6829cdc0e81 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -191,7 +191,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i, rtr, buf_id;
u32 can_id;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
out_8(&regs->cantier, 0);
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index 0558ff67ec6a..2a44b2803e55 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -882,7 +882,7 @@ static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
int i;
u32 id2;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
tx_obj_no = priv->tx_obj;
diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c
index f8420cc1d907..31c9c127e24b 100644
--- a/drivers/net/can/peak_canfd/peak_canfd.c
+++ b/drivers/net/can/peak_canfd/peak_canfd.c
@@ -651,7 +651,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
int room_left;
u8 len;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
msg_size = ALIGN(sizeof(*msg) + cf->len, 4);
diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c
index 6ee968c59ac9..cc43c9c5e38c 100644
--- a/drivers/net/can/rcar/rcar_can.c
+++ b/drivers/net/can/rcar/rcar_can.c
@@ -590,7 +590,7 @@ static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
struct can_frame *cf = (struct can_frame *)skb->data;
u32 data, i;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 198da643ee6d..b306cf554634 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -81,8 +81,7 @@ enum rcanfd_chip_id {
/* RSCFDnCFDGERFL / RSCFDnGERFL */
#define RCANFD_GERFL_EEF0_7 GENMASK(23, 16)
-#define RCANFD_GERFL_EEF1 BIT(17)
-#define RCANFD_GERFL_EEF0 BIT(16)
+#define RCANFD_GERFL_EEF(ch) BIT(16 + (ch))
#define RCANFD_GERFL_CMPOF BIT(3) /* CAN FD only */
#define RCANFD_GERFL_THLES BIT(2)
#define RCANFD_GERFL_MES BIT(1)
@@ -90,7 +89,7 @@ enum rcanfd_chip_id {
#define RCANFD_GERFL_ERR(gpriv, x) \
((x) & (reg_v3u(gpriv, RCANFD_GERFL_EEF0_7, \
- RCANFD_GERFL_EEF0 | RCANFD_GERFL_EEF1) | \
+ RCANFD_GERFL_EEF(0) | RCANFD_GERFL_EEF(1)) | \
RCANFD_GERFL_MES | \
((gpriv)->fdmode ? RCANFD_GERFL_CMPOF : 0)))
@@ -936,12 +935,8 @@ static void rcar_canfd_global_error(struct net_device *ndev)
u32 ridx = ch + RCANFD_RFFIFO_IDX;
gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
- if ((gerfl & RCANFD_GERFL_EEF0) && (ch == 0)) {
- netdev_dbg(ndev, "Ch0: ECC Error flag\n");
- stats->tx_dropped++;
- }
- if ((gerfl & RCANFD_GERFL_EEF1) && (ch == 1)) {
- netdev_dbg(ndev, "Ch1: ECC Error flag\n");
+ if (gerfl & RCANFD_GERFL_EEF(ch)) {
+ netdev_dbg(ndev, "Ch%u: ECC Error flag\n", ch);
stats->tx_dropped++;
}
if (gerfl & RCANFD_GERFL_MES) {
@@ -1481,7 +1476,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
unsigned long flags;
u32 ch = priv->channel;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
if (cf->can_id & CAN_EFF_FLAG) {
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 1bb1129b0450..aac5956e4a53 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -291,7 +291,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
u8 cmd_reg_val = 0x00;
int i;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c
index d513fac50718..db3e767d5320 100644
--- a/drivers/net/can/sja1000/sja1000_isa.c
+++ b/drivers/net/can/sja1000/sja1000_isa.c
@@ -202,22 +202,24 @@ static int sja1000_isa_probe(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
- goto exit_unmap;
+ goto exit_free;
}
dev_info(&pdev->dev, "%s device registered (reg_base=0x%p, irq=%d)\n",
DRV_NAME, priv->reg_base, dev->irq);
return 0;
- exit_unmap:
+exit_free:
+ free_sja1000dev(dev);
+exit_unmap:
if (mem[idx])
iounmap(base);
- exit_release:
+exit_release:
if (mem[idx])
release_mem_region(mem[idx], iosize);
else
release_region(port[idx], iosize);
- exit:
+exit:
return err;
}
diff --git a/drivers/net/can/slcan/slcan-core.c b/drivers/net/can/slcan/slcan-core.c
index 8d13fdf8c28a..f4db77007c13 100644
--- a/drivers/net/can/slcan/slcan-core.c
+++ b/drivers/net/can/slcan/slcan-core.c
@@ -594,7 +594,7 @@ static netdev_tx_t slcan_netdev_xmit(struct sk_buff *skb,
{
struct slcan *sl = netdev_priv(dev);
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
spin_lock(&sl->lock);
@@ -864,12 +864,14 @@ static void slcan_close(struct tty_struct *tty)
{
struct slcan *sl = (struct slcan *)tty->disc_data;
- /* unregister_netdev() calls .ndo_stop() so we don't have to.
- * Our .ndo_stop() also flushes the TTY write wakeup handler,
- * so we can safely set sl->tty = NULL after this.
- */
unregister_candev(sl->dev);
+ /*
+ * The netdev needn't be UP (so .ndo_stop() is not called). Hence make
+ * sure this is not running before freeing it up.
+ */
+ flush_work(&sl->tx_work);
+
/* Mark channel as dead */
spin_lock_bh(&sl->lock);
tty->disc_data = NULL;
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index a5ef57f415f7..c72f505d29fe 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -60,7 +60,7 @@ static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
struct can_frame *cf = (struct can_frame *)skb->data;
uint8_t buf[DPRAM_TX_SIZE];
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
spin_lock(&card->spin);
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index b87dc420428d..e1b8533a602e 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -373,7 +373,7 @@ static netdev_tx_t hi3110_hard_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- if (can_dropped_invalid_skb(net, skb))
+ if (can_dev_dropped_skb(net, skb))
return NETDEV_TX_OK;
netif_stop_queue(net);
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 24883a65ca66..79c4bab5f724 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -789,7 +789,7 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- if (can_dropped_invalid_skb(net, skb))
+ if (can_dev_dropped_skb(net, skb))
return NETDEV_TX_OK;
netif_stop_queue(net);
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c
index ffb6c36b7d9b..160528d3cc26 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c
@@ -172,7 +172,7 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
u8 tx_head;
int err;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
if (mcp251xfd_tx_busy(priv, tx_ring))
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
index 525309da1320..2b78f9197681 100644
--- a/drivers/net/can/sun4i_can.c
+++ b/drivers/net/can/sun4i_can.c
@@ -429,7 +429,7 @@ static netdev_tx_t sun4ican_start_xmit(struct sk_buff *skb, struct net_device *d
canid_t id;
int i;
- if (can_dropped_invalid_skb(dev, skb))
+ if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index b218fb3c6b76..27700f72eac2 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -470,7 +470,7 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
u32 mbxno, mbx_mask, data;
unsigned long flags;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
mbxno = get_tx_head_mb(priv);
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index d31191686a54..050c0b49938a 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -747,7 +747,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN
+ sizeof(struct cpc_can_msg);
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
/* create a URB, and a buffer for it, and copy the data to the URB */
diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
index 1bcfad11b1e4..42323f5e6f3a 100644
--- a/drivers/net/can/usb/esd_usb.c
+++ b/drivers/net/can/usb/esd_usb.c
@@ -234,6 +234,10 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv,
u8 rxerr = msg->msg.rx.data[2];
u8 txerr = msg->msg.rx.data[3];
+ netdev_dbg(priv->netdev,
+ "CAN_ERR_EV_EXT: dlc=%#02x state=%02x ecc=%02x rec=%02x tec=%02x\n",
+ msg->msg.rx.dlc, state, ecc, rxerr, txerr);
+
skb = alloc_can_err_skb(priv->netdev, &cf);
if (skb == NULL) {
stats->rx_dropped++;
@@ -260,6 +264,8 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv,
break;
default:
priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ txerr = 0;
+ rxerr = 0;
break;
}
} else {
@@ -725,7 +731,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
int ret = NETDEV_TX_OK;
size_t size = sizeof(struct esd_usb_msg);
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
/* create a URB, and a buffer for it, and copy the data to the URB */
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index 51294b717040..ddb7c5735c9a 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -1913,7 +1913,7 @@ static netdev_tx_t es58x_start_xmit(struct sk_buff *skb,
unsigned int frame_len;
int ret;
- if (can_dropped_invalid_skb(netdev, skb)) {
+ if (can_dev_dropped_skb(netdev, skb)) {
if (priv->tx_urb)
goto xmit_commit;
return NETDEV_TX_OK;
@@ -2091,8 +2091,11 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx)
netdev->dev_port = channel_idx;
ret = register_candev(netdev);
- if (ret)
+ if (ret) {
+ es58x_dev->netdev[channel_idx] = NULL;
+ free_candev(netdev);
return ret;
+ }
netdev_queue_set_dql_min_limit(netdev_get_tx_queue(netdev, 0),
es58x_dev->param->dql_min_limit);
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index f0065d40eb24..9c2c25fde3d1 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -723,7 +723,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
unsigned int idx;
struct gs_tx_context *txc;
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
/* find an empty context to keep track of transmission */
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
index e91648ed7386..802e27c0eced 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -570,7 +570,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
unsigned int i;
unsigned long flags;
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
urb = usb_alloc_urb(0, GFP_ATOMIC);
diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c
index 69346c63021f..47619e9cb005 100644
--- a/drivers/net/can/usb/mcba_usb.c
+++ b/drivers/net/can/usb/mcba_usb.c
@@ -47,6 +47,10 @@
#define MCBA_VER_REQ_USB 1
#define MCBA_VER_REQ_CAN 2
+/* Drive the CAN_RES signal LOW "0" to activate R24 and R25 */
+#define MCBA_VER_TERMINATION_ON 0
+#define MCBA_VER_TERMINATION_OFF 1
+
#define MCBA_SIDL_EXID_MASK 0x8
#define MCBA_DLC_MASK 0xf
#define MCBA_DLC_RTR_MASK 0x40
@@ -311,7 +315,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
.cmd_id = MBCA_CMD_TRANSMIT_MESSAGE_EV
};
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
ctx = mcba_usb_get_free_ctx(priv, cf);
@@ -463,7 +467,7 @@ static void mcba_usb_process_ka_usb(struct mcba_priv *priv,
priv->usb_ka_first_pass = false;
}
- if (msg->termination_state)
+ if (msg->termination_state == MCBA_VER_TERMINATION_ON)
priv->can.termination = MCBA_TERMINATION_ENABLED;
else
priv->can.termination = MCBA_TERMINATION_DISABLED;
@@ -785,9 +789,9 @@ static int mcba_set_termination(struct net_device *netdev, u16 term)
};
if (term == MCBA_TERMINATION_ENABLED)
- usb_msg.termination = 1;
+ usb_msg.termination = MCBA_VER_TERMINATION_ON;
else
- usb_msg.termination = 0;
+ usb_msg.termination = MCBA_VER_TERMINATION_OFF;
mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index 225697d70a9a..1d996d3320fe 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -351,7 +351,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
int i, err;
size_t size = dev->adapter->tx_buffer_size;
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index 7c35f50fda4e..67c2ff407d06 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -1120,7 +1120,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
struct can_frame *cf = (struct can_frame *)skb->data;
/* check skb */
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
/* allocate a context and slow down tx path, if fifo state is low */
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index 64c00abe91cf..8a5596ce4e46 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -602,7 +602,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
int i, err;
size_t size = sizeof(struct usb_8dev_tx_msg);
- if (can_dropped_invalid_skb(netdev, skb))
+ if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
/* create a URB, and a buffer for it, and copy the data to the URB */
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index 5d3172795ad0..43c812ea1de0 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -743,7 +743,7 @@ static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct xcan_priv *priv = netdev_priv(ndev);
int ret;
- if (can_dropped_invalid_skb(ndev, skb))
+ if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK;
if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES)
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index 438e46af03e9..80f07bd20593 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -961,7 +961,7 @@ static const struct lan9303_mib_desc lan9303_mib[] = {
{ .offset = LAN9303_MAC_TX_BRDCST_CNT_0, .name = "TxBroad", },
{ .offset = LAN9303_MAC_TX_PAUSE_CNT_0, .name = "TxPause", },
{ .offset = LAN9303_MAC_TX_MULCST_CNT_0, .name = "TxMulti", },
- { .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "TxUnderRun", },
+ { .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "RxShort", },
{ .offset = LAN9303_MAC_TX_64_CNT_0, .name = "Tx64Byte", },
{ .offset = LAN9303_MAC_TX_127_CNT_0, .name = "Tx128Byte", },
{ .offset = LAN9303_MAC_TX_255_CNT_0, .name = "Tx256Byte", },
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2479be3a1e35..937cb22cb3d4 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -833,10 +833,13 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
chip->info->ops->phylink_get_caps(chip, port, config);
- /* Internal ports need GMII for PHYLIB */
- if (mv88e6xxx_phy_is_internal(ds, port))
+ if (mv88e6xxx_phy_is_internal(ds, port)) {
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+ /* Internal ports with no phy-mode need GMII for PHYLIB */
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces);
+ }
}
static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/sja1105/sja1105_devlink.c b/drivers/net/dsa/sja1105/sja1105_devlink.c
index 10c6fea1227f..bdbbff2a7909 100644
--- a/drivers/net/dsa/sja1105/sja1105_devlink.c
+++ b/drivers/net/dsa/sja1105/sja1105_devlink.c
@@ -95,6 +95,8 @@ static int sja1105_setup_devlink_regions(struct dsa_switch *ds)
if (IS_ERR(region)) {
while (--i >= 0)
dsa_devlink_region_destroy(priv->regions[i]);
+
+ kfree(priv->regions);
return PTR_ERR(region);
}
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 412666111b0c..b70dcf32a26d 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -1038,7 +1038,7 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
policing[bcast].sharindx = port;
/* Only SJA1110 has multicast policers */
- if (mcast <= table->ops->max_entry_count)
+ if (mcast < table->ops->max_entry_count)
policing[mcast].sharindx = port;
}
diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c
index 215dd17ca790..4059fcc8c832 100644
--- a/drivers/net/dsa/sja1105/sja1105_mdio.c
+++ b/drivers/net/dsa/sja1105/sja1105_mdio.c
@@ -256,6 +256,9 @@ static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
u32 tmp;
int rc;
+ if (reg & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
&tmp, NULL);
if (rc < 0)
@@ -272,6 +275,9 @@ static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
const struct sja1105_regs *regs = priv->info->regs;
u32 tmp = val;
+ if (reg & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
&tmp, NULL);
}
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index e104fb02817d..aa0d2f3aaeaa 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -258,6 +258,7 @@ static int greth_init_rings(struct greth_private *greth)
if (dma_mapping_error(greth->dev, dma_addr)) {
if (netif_msg_ifup(greth))
dev_err(greth->dev, "Could not create initial DMA mapping\n");
+ dev_kfree_skb(skb);
goto cleanup;
}
greth->rx_skbuff[i] = skb;
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index 7633b227b2ca..711d5b5a4c49 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -990,6 +990,7 @@ static int tse_shutdown(struct net_device *dev)
int ret;
phylink_stop(priv->phylink);
+ phylink_disconnect_phy(priv->phylink);
netif_stop_queue(dev);
napi_disable(&priv->napi);
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index d350eeec8bad..5a454b58498f 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -4543,13 +4543,19 @@ static struct pci_driver ena_pci_driver = {
static int __init ena_init(void)
{
+ int ret;
+
ena_wq = create_singlethread_workqueue(DRV_MODULE_NAME);
if (!ena_wq) {
pr_err("Failed to create workqueue\n");
return -ENOMEM;
}
- return pci_register_driver(&ena_pci_driver);
+ ret = pci_register_driver(&ena_pci_driver);
+ if (ret)
+ destroy_workqueue(ena_wq);
+
+ return ret;
}
static void __exit ena_cleanup(void)
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index d6cfea65a714..390671640388 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -1004,8 +1004,10 @@ static int xgene_enet_open(struct net_device *ndev)
xgene_enet_napi_enable(pdata);
ret = xgene_enet_register_irq(ndev);
- if (ret)
+ if (ret) {
+ xgene_enet_napi_disable(pdata);
return ret;
+ }
if (ndev->phydev) {
phy_start(ndev->phydev);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index a08f221e30d4..ac4ea93bd8dd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -13,6 +13,7 @@
#include "aq_ptp.h"
#include "aq_filters.h"
#include "aq_macsec.h"
+#include "aq_main.h"
#include <linux/ptp_clock_kernel.h>
@@ -858,7 +859,7 @@ static int aq_set_ringparam(struct net_device *ndev,
if (netif_running(ndev)) {
ndev_running = true;
- dev_close(ndev);
+ aq_ndev_close(ndev);
}
cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
@@ -874,7 +875,7 @@ static int aq_set_ringparam(struct net_device *ndev,
goto err_exit;
if (ndev_running)
- err = dev_open(ndev, NULL);
+ err = aq_ndev_open(ndev);
err_exit:
return err;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c
index a0180811305d..7eb5851eb95d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c
@@ -570,6 +570,7 @@ static int aq_update_txsa(struct aq_nic_s *nic, const unsigned int sc_idx,
ret = aq_mss_set_egress_sakey_record(hw, &key_rec, sa_idx);
+ memzero_explicit(&key_rec, sizeof(key_rec));
return ret;
}
@@ -899,6 +900,7 @@ static int aq_update_rxsa(struct aq_nic_s *nic, const unsigned int sc_idx,
ret = aq_mss_set_ingress_sakey_record(hw, &sa_key_record, sa_idx);
+ memzero_explicit(&sa_key_record, sizeof(sa_key_record));
return ret;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index 8a0af371e7dc..77609dc0a08d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -58,7 +58,7 @@ struct net_device *aq_ndev_alloc(void)
return ndev;
}
-static int aq_ndev_open(struct net_device *ndev)
+int aq_ndev_open(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
@@ -88,7 +88,7 @@ err_exit:
return err;
}
-static int aq_ndev_close(struct net_device *ndev)
+int aq_ndev_close(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.h b/drivers/net/ethernet/aquantia/atlantic/aq_main.h
index 99870865f66d..a78c1a168d8e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.h
@@ -16,5 +16,7 @@ DECLARE_STATIC_KEY_FALSE(aq_xdp_locking_key);
void aq_ndev_schedule_work(struct work_struct *work);
struct net_device *aq_ndev_alloc(void);
+int aq_ndev_open(struct net_device *ndev);
+int aq_ndev_close(struct net_device *ndev);
#endif /* AQ_MAIN_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/macsec/macsec_api.c b/drivers/net/ethernet/aquantia/atlantic/macsec/macsec_api.c
index 36c7cf05630a..431924959520 100644
--- a/drivers/net/ethernet/aquantia/atlantic/macsec/macsec_api.c
+++ b/drivers/net/ethernet/aquantia/atlantic/macsec/macsec_api.c
@@ -757,6 +757,7 @@ set_ingress_sakey_record(struct aq_hw_s *hw,
u16 table_index)
{
u16 packed_record[18];
+ int ret;
if (table_index >= NUMROWS_INGRESSSAKEYRECORD)
return -EINVAL;
@@ -789,9 +790,12 @@ set_ingress_sakey_record(struct aq_hw_s *hw,
packed_record[16] = rec->key_len & 0x3;
- return set_raw_ingress_record(hw, packed_record, 18, 2,
- ROWOFFSET_INGRESSSAKEYRECORD +
- table_index);
+ ret = set_raw_ingress_record(hw, packed_record, 18, 2,
+ ROWOFFSET_INGRESSSAKEYRECORD +
+ table_index);
+
+ memzero_explicit(packed_record, sizeof(packed_record));
+ return ret;
}
int aq_mss_set_ingress_sakey_record(struct aq_hw_s *hw,
@@ -1739,14 +1743,14 @@ static int set_egress_sakey_record(struct aq_hw_s *hw,
ret = set_raw_egress_record(hw, packed_record, 8, 2,
ROWOFFSET_EGRESSSAKEYRECORD + table_index);
if (unlikely(ret))
- return ret;
+ goto clear_key;
ret = set_raw_egress_record(hw, packed_record + 8, 8, 2,
ROWOFFSET_EGRESSSAKEYRECORD + table_index -
32);
- if (unlikely(ret))
- return ret;
- return 0;
+clear_key:
+ memzero_explicit(packed_record, sizeof(packed_record));
+ return ret;
}
int aq_mss_set_egress_sakey_record(struct aq_hw_s *hw,
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c
index cc932b3cf873..4a1efe9b37d0 100644
--- a/drivers/net/ethernet/atheros/ag71xx.c
+++ b/drivers/net/ethernet/atheros/ag71xx.c
@@ -1427,7 +1427,7 @@ static int ag71xx_open(struct net_device *ndev)
if (ret) {
netif_err(ag, link, ndev, "phylink_of_phy_connect filed with err: %i\n",
ret);
- goto err;
+ return ret;
}
max_frame_len = ag71xx_max_frame_len(ndev->mtu);
@@ -1448,6 +1448,7 @@ static int ag71xx_open(struct net_device *ndev)
err:
ag71xx_rings_cleanup(ag);
+ phylink_disconnect_phy(ag->phylink);
return ret;
}
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index f4e1ca68d831..f4ca0c6c0f51 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -71,6 +71,7 @@ config BCM63XX_ENET
config BCMGENET
tristate "Broadcom GENET internal MAC support"
depends on HAS_IOMEM
+ depends on PTP_1588_CLOCK_OPTIONAL || !ARCH_BCM2835
select MII
select PHYLIB
select FIXED_PHY
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 5fb3af5670ec..3038386a5afd 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1568,7 +1568,6 @@ void bgmac_enet_remove(struct bgmac *bgmac)
phy_disconnect(bgmac->net_dev->phydev);
netif_napi_del(&bgmac->napi);
bgmac_dma_free(bgmac);
- free_netdev(bgmac->net_dev);
}
EXPORT_SYMBOL_GPL(bgmac_enet_remove);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 11d15cd03600..77d4cb4ad782 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -795,16 +795,20 @@ static void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
{
- struct pci_dev *dev;
struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+ struct pci_dev *dev;
+ bool pending;
if (!vf)
return false;
dev = pci_get_domain_bus_and_slot(vf->domain, vf->bus, vf->devfn);
- if (dev)
- return bnx2x_is_pcie_pending(dev);
- return false;
+ if (!dev)
+ return false;
+ pending = bnx2x_is_pcie_pending(dev);
+ pci_dev_put(dev);
+
+ return pending;
}
int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 04cf7684f1b0..9f8a6ce4b356 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -9983,17 +9983,12 @@ static int bnxt_try_recover_fw(struct bnxt *bp)
return -ENODEV;
}
-int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset)
+static void bnxt_clear_reservations(struct bnxt *bp, bool fw_reset)
{
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
- int rc;
if (!BNXT_NEW_RM(bp))
- return 0; /* no resource reservations required */
-
- rc = bnxt_hwrm_func_resc_qcaps(bp, true);
- if (rc)
- netdev_err(bp->dev, "resc_qcaps failed\n");
+ return; /* no resource reservations required */
hw_resc->resv_cp_rings = 0;
hw_resc->resv_stat_ctxs = 0;
@@ -10006,6 +10001,20 @@ int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset)
bp->tx_nr_rings = 0;
bp->rx_nr_rings = 0;
}
+}
+
+int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset)
+{
+ int rc;
+
+ if (!BNXT_NEW_RM(bp))
+ return 0; /* no resource reservations required */
+
+ rc = bnxt_hwrm_func_resc_qcaps(bp, true);
+ if (rc)
+ netdev_err(bp->dev, "resc_qcaps failed\n");
+
+ bnxt_clear_reservations(bp, fw_reset);
return rc;
}
@@ -12894,8 +12903,8 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
rcu_read_lock();
hlist_for_each_entry_rcu(fltr, head, hash) {
if (bnxt_fltr_match(fltr, new_fltr)) {
+ rc = fltr->sw_id;
rcu_read_unlock();
- rc = 0;
goto err_free;
}
}
@@ -13913,7 +13922,9 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
struct net_device *netdev = pci_get_drvdata(pdev);
struct bnxt *bp = netdev_priv(netdev);
- int err = 0, off;
+ int retry = 0;
+ int err = 0;
+ int off;
netdev_info(bp->dev, "PCI Slot Reset\n");
@@ -13941,11 +13952,36 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
pci_restore_state(pdev);
pci_save_state(pdev);
+ bnxt_inv_fw_health_reg(bp);
+ bnxt_try_map_fw_health_reg(bp);
+
+ /* In some PCIe AER scenarios, firmware may take up to
+ * 10 seconds to become ready in the worst case.
+ */
+ do {
+ err = bnxt_try_recover_fw(bp);
+ if (!err)
+ break;
+ retry++;
+ } while (retry < BNXT_FW_SLOT_RESET_RETRY);
+
+ if (err) {
+ dev_err(&pdev->dev, "Firmware not ready\n");
+ goto reset_exit;
+ }
+
err = bnxt_hwrm_func_reset(bp);
if (!err)
result = PCI_ERS_RESULT_RECOVERED;
+
+ bnxt_ulp_irq_stop(bp);
+ bnxt_clear_int_mode(bp);
+ err = bnxt_init_int_mode(bp);
+ bnxt_ulp_irq_restart(bp, err);
}
+reset_exit:
+ bnxt_clear_reservations(bp, true);
rtnl_unlock();
return result;
@@ -14001,8 +14037,16 @@ static struct pci_driver bnxt_pci_driver = {
static int __init bnxt_init(void)
{
+ int err;
+
bnxt_debug_init();
- return pci_register_driver(&bnxt_pci_driver);
+ err = pci_register_driver(&bnxt_pci_driver);
+ if (err) {
+ bnxt_debug_exit();
+ return err;
+ }
+
+ return 0;
}
static void __exit bnxt_exit(void)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index b1b17f911300..d5fa43cfe524 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -1621,6 +1621,7 @@ struct bnxt_fw_health {
#define BNXT_FW_RETRY 5
#define BNXT_FW_IF_RETRY 10
+#define BNXT_FW_SLOT_RESET_RETRY 4
enum board_idx {
BCM57301,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index f57e524c7e30..8cad15c458b3 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -162,7 +162,7 @@ static int bnxt_set_coalesce(struct net_device *dev,
}
reset_coalesce:
- if (netif_running(dev)) {
+ if (test_bit(BNXT_STATE_OPEN, &bp->state)) {
if (update_stats) {
rc = bnxt_close_nic(bp, true, false);
if (!rc)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c
index b01d42928a53..132442f16fe6 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c
@@ -476,7 +476,8 @@ static int __hwrm_send(struct bnxt *bp, struct bnxt_hwrm_ctx *ctx)
memset(ctx->resp, 0, PAGE_SIZE);
req_type = le16_to_cpu(ctx->req->req_type);
- if (BNXT_NO_FW_ACCESS(bp) && req_type != HWRM_FUNC_RESET) {
+ if (BNXT_NO_FW_ACCESS(bp) &&
+ (req_type != HWRM_FUNC_RESET && req_type != HWRM_VER_GET)) {
netdev_dbg(bp->dev, "hwrm req_type 0x%x skipped, FW channel down\n",
req_type);
goto exit;
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 2198e35d9e18..7926aaef8f0c 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1027,16 +1027,14 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
- &udev->l2_ring_map,
- GFP_KERNEL | __GFP_COMP);
+ &udev->l2_ring_map, GFP_KERNEL);
if (!udev->l2_ring)
return -ENOMEM;
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
- &udev->l2_buf_map,
- GFP_KERNEL | __GFP_COMP);
+ &udev->l2_buf_map, GFP_KERNEL);
if (!udev->l2_buf) {
__cnic_free_uio_rings(udev);
return -ENOMEM;
@@ -4105,7 +4103,7 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev)
for (i = 0; i < MAX_CM_SK_TBL_SZ; i++)
atomic_set(&cp->csk_tbl[i].ref_count, 0);
- port_id = prandom_u32_max(CNIC_LOCAL_PORT_RANGE);
+ port_id = get_random_u32_below(CNIC_LOCAL_PORT_RANGE);
if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
CNIC_LOCAL_PORT_MIN, port_id)) {
cnic_cm_free_mem(dev);
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index d312bd594935..98793b2ac2c7 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -1794,13 +1794,10 @@ static int liquidio_open(struct net_device *netdev)
ifstate_set(lio, LIO_IFSTATE_RUNNING);
- if (OCTEON_CN23XX_PF(oct)) {
- if (!oct->msix_on)
- if (setup_tx_poll_fn(netdev))
- return -1;
- } else {
- if (setup_tx_poll_fn(netdev))
- return -1;
+ if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) {
+ ret = setup_tx_poll_fn(netdev);
+ if (ret)
+ goto err_poll;
}
netif_tx_start_all_queues(netdev);
@@ -1813,7 +1810,7 @@ static int liquidio_open(struct net_device *netdev)
/* tell Octeon to start forwarding packets to host */
ret = send_rx_ctrl_cmd(lio, 1);
if (ret)
- return ret;
+ goto err_rx_ctrl;
/* start periodical statistics fetch */
INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats);
@@ -1824,6 +1821,27 @@ static int liquidio_open(struct net_device *netdev)
dev_info(&oct->pci_dev->dev, "%s interface is opened\n",
netdev->name);
+ return 0;
+
+err_rx_ctrl:
+ if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on)
+ cleanup_tx_poll_fn(netdev);
+err_poll:
+ if (lio->ptp_clock) {
+ ptp_clock_unregister(lio->ptp_clock);
+ lio->ptp_clock = NULL;
+ }
+
+ if (oct->props[lio->ifidx].napi_enabled == 1) {
+ list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
+ napi_disable(napi);
+
+ oct->props[lio->ifidx].napi_enabled = 0;
+
+ if (OCTEON_CN23XX_PF(oct))
+ oct->droq[0]->ops.poll_mode = 0;
+ }
+
return ret;
}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index 98f3dc460ca7..f2f95493ec89 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -2239,7 +2239,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
- goto err_unregister_interrupts;
+ goto err_destroy_workqueue;
}
nic->msg_enable = debug;
@@ -2248,6 +2248,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+err_destroy_workqueue:
+ destroy_workqueue(nic->nicvf_rx_mode_wq);
err_unregister_interrupts:
nicvf_unregister_interrupts(nic);
err_free_netdev:
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 2f6484dc186a..7eb2ddbe9bad 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -1436,8 +1436,10 @@ static acpi_status bgx_acpi_match_id(acpi_handle handle, u32 lvl,
return AE_OK;
}
- if (strncmp(string.pointer, bgx_sel, 4))
+ if (strncmp(string.pointer, bgx_sel, 4)) {
+ kfree(string.pointer);
return AE_OK;
+ }
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
bgx_acpi_register_phy, NULL, bgx, NULL);
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index a52e6b6e2876..9b84c8d8d309 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1301,6 +1301,7 @@ static int cxgb_up(struct adapter *adap)
if (ret < 0) {
CH_ERR(adap, "failed to bind qsets, err %d\n", ret);
t3_intr_disable(adap);
+ quiesce_rx(adap);
free_irq_resources(adap);
err = ret;
goto out;
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 54db79f4dcfe..63b2bd084130 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -858,7 +858,7 @@ static int cxgb4vf_open(struct net_device *dev)
*/
err = t4vf_update_port_info(pi);
if (err < 0)
- return err;
+ goto err_unwind;
/*
* Note that this interface is up and start everything up ...
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c
index a4256087ac82..ae6b17b96bf1 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c
@@ -919,8 +919,8 @@ static int csk_wait_memory(struct chtls_dev *cdev,
current_timeo = *timeo_p;
noblock = (*timeo_p ? false : true);
if (csk_mem_free(cdev, sk)) {
- current_timeo = prandom_u32_max(HZ / 5) + 2;
- vm_wait = prandom_u32_max(HZ / 5) + 2;
+ current_timeo = get_random_u32_below(HZ / 5) + 2;
+ vm_wait = get_random_u32_below(HZ / 5) + 2;
}
add_wait_queue(sk_sleep(sk), &wait);
diff --git a/drivers/net/ethernet/davicom/dm9051.c b/drivers/net/ethernet/davicom/dm9051.c
index a523ddda7609..de7105a84747 100644
--- a/drivers/net/ethernet/davicom/dm9051.c
+++ b/drivers/net/ethernet/davicom/dm9051.c
@@ -798,8 +798,10 @@ static int dm9051_loop_rx(struct board_info *db)
}
ret = dm9051_stop_mrcmd(db);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
skb->protocol = eth_type_trans(skb, db->ndev);
if (db->ndev->features & NETIF_F_RXCSUM)
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index 48fb391951dd..13d5ff4e0e02 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -542,6 +542,27 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
return (budget != 0);
}
+static bool tsnep_tx_pending(struct tsnep_tx *tx)
+{
+ unsigned long flags;
+ struct tsnep_tx_entry *entry;
+ bool pending = false;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (tx->read != tx->write) {
+ entry = &tx->entry[tx->read];
+ if ((__le32_to_cpu(entry->desc_wb->properties) &
+ TSNEP_TX_DESC_OWNER_MASK) ==
+ (entry->properties & TSNEP_TX_DESC_OWNER_MASK))
+ pending = true;
+ }
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ return pending;
+}
+
static int tsnep_tx_open(struct tsnep_adapter *adapter, void __iomem *addr,
int queue_index, struct tsnep_tx *tx)
{
@@ -821,6 +842,19 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
return done;
}
+static bool tsnep_rx_pending(struct tsnep_rx *rx)
+{
+ struct tsnep_rx_entry *entry;
+
+ entry = &rx->entry[rx->read];
+ if ((__le32_to_cpu(entry->desc_wb->properties) &
+ TSNEP_DESC_OWNER_COUNTER_MASK) ==
+ (entry->properties & TSNEP_DESC_OWNER_COUNTER_MASK))
+ return true;
+
+ return false;
+}
+
static int tsnep_rx_open(struct tsnep_adapter *adapter, void __iomem *addr,
int queue_index, struct tsnep_rx *rx)
{
@@ -866,6 +900,17 @@ static void tsnep_rx_close(struct tsnep_rx *rx)
tsnep_rx_ring_cleanup(rx);
}
+static bool tsnep_pending(struct tsnep_queue *queue)
+{
+ if (queue->tx && tsnep_tx_pending(queue->tx))
+ return true;
+
+ if (queue->rx && tsnep_rx_pending(queue->rx))
+ return true;
+
+ return false;
+}
+
static int tsnep_poll(struct napi_struct *napi, int budget)
{
struct tsnep_queue *queue = container_of(napi, struct tsnep_queue,
@@ -886,9 +931,19 @@ static int tsnep_poll(struct napi_struct *napi, int budget)
if (!complete)
return budget;
- if (likely(napi_complete_done(napi, done)))
+ if (likely(napi_complete_done(napi, done))) {
tsnep_enable_irq(queue->adapter, queue->irq_mask);
+ /* reschedule if work is already pending, prevent rotten packets
+ * which are transmitted or received after polling but before
+ * interrupt enable
+ */
+ if (tsnep_pending(queue)) {
+ tsnep_disable_irq(queue->adapter, queue->irq_mask);
+ napi_schedule(napi);
+ }
+ }
+
return min(done, budget - 1);
}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
index cacd454ac696..c39b866e2582 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
@@ -132,6 +132,7 @@ int dpaa2_switch_acl_entry_add(struct dpaa2_switch_filter_block *filter_block,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {
dev_err(dev, "DMA mapping failed\n");
+ kfree(cmd_buff);
return -EFAULT;
}
@@ -142,6 +143,7 @@ int dpaa2_switch_acl_entry_add(struct dpaa2_switch_filter_block *filter_block,
DMA_TO_DEVICE);
if (err) {
dev_err(dev, "dpsw_acl_add_entry() failed %d\n", err);
+ kfree(cmd_buff);
return err;
}
@@ -172,6 +174,7 @@ dpaa2_switch_acl_entry_remove(struct dpaa2_switch_filter_block *block,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {
dev_err(dev, "DMA mapping failed\n");
+ kfree(cmd_buff);
return -EFAULT;
}
@@ -182,6 +185,7 @@ dpaa2_switch_acl_entry_remove(struct dpaa2_switch_filter_block *block,
DMA_TO_DEVICE);
if (err) {
dev_err(dev, "dpsw_acl_remove_entry() failed %d\n", err);
+ kfree(cmd_buff);
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index f8c06c3f9464..8671591cb750 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2058,7 +2058,7 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
/* enable Tx ints by setting pkt thr to 1 */
enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
- tbmr = ENETC_TBMR_EN;
+ tbmr = ENETC_TBMR_EN | ENETC_TBMR_SET_PRIO(tx_ring->prio);
if (tx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
tbmr |= ENETC_TBMR_VIH;
@@ -2461,7 +2461,8 @@ int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
/* Reset all ring priorities to 0 */
for (i = 0; i < priv->num_tx_rings; i++) {
tx_ring = priv->tx_ring[i];
- enetc_set_bdr_prio(hw, tx_ring->index, 0);
+ tx_ring->prio = 0;
+ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
}
return 0;
@@ -2480,7 +2481,8 @@ int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
*/
for (i = 0; i < num_tc; i++) {
tx_ring = priv->tx_ring[i];
- enetc_set_bdr_prio(hw, tx_ring->index, i);
+ tx_ring->prio = i;
+ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
}
/* Reset the number of netdev queues based on the TC count */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 161930a65f61..c6d8cc15c270 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -95,6 +95,7 @@ struct enetc_bdr {
void __iomem *rcir;
};
u16 index;
+ u16 prio;
int bd_count; /* # of BDs */
int next_to_use;
int next_to_clean;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index a842e1999122..fcebb54224c0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -137,6 +137,7 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
struct tc_taprio_qopt_offload *taprio = type_data;
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_hw *hw = &priv->si->hw;
+ struct enetc_bdr *tx_ring;
int err;
int i;
@@ -145,16 +146,20 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
if (priv->tx_ring[i]->tsd_enable)
return -EBUSY;
- for (i = 0; i < priv->num_tx_rings; i++)
- enetc_set_bdr_prio(hw, priv->tx_ring[i]->index,
- taprio->enable ? i : 0);
+ for (i = 0; i < priv->num_tx_rings; i++) {
+ tx_ring = priv->tx_ring[i];
+ tx_ring->prio = taprio->enable ? i : 0;
+ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
+ }
err = enetc_setup_taprio(ndev, taprio);
-
- if (err)
- for (i = 0; i < priv->num_tx_rings; i++)
- enetc_set_bdr_prio(hw, priv->tx_ring[i]->index,
- taprio->enable ? 0 : i);
+ if (err) {
+ for (i = 0; i < priv->num_tx_rings; i++) {
+ tx_ring = priv->tx_ring[i];
+ tx_ring->prio = taprio->enable ? 0 : i;
+ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
+ }
+ }
return err;
}
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f623c12eaf95..23e1a94b9ce4 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -74,7 +74,7 @@
#include "fec.h"
static void set_multicast_list(struct net_device *ndev);
-static void fec_enet_itr_coal_init(struct net_device *ndev);
+static void fec_enet_itr_coal_set(struct net_device *ndev);
#define DRIVER_NAME "fec"
@@ -1220,8 +1220,8 @@ fec_restart(struct net_device *ndev)
writel(0, fep->hwp + FEC_IMASK);
/* Init the interrupt coalescing */
- fec_enet_itr_coal_init(ndev);
-
+ if (fep->quirks & FEC_QUIRK_HAS_COALESCE)
+ fec_enet_itr_coal_set(ndev);
}
static int fec_enet_ipc_handle_init(struct fec_enet_private *fep)
@@ -2856,19 +2856,6 @@ static int fec_enet_set_coalesce(struct net_device *ndev,
return 0;
}
-static void fec_enet_itr_coal_init(struct net_device *ndev)
-{
- struct ethtool_coalesce ec;
-
- ec.rx_coalesce_usecs = FEC_ITR_ICTT_DEFAULT;
- ec.rx_max_coalesced_frames = FEC_ITR_ICFT_DEFAULT;
-
- ec.tx_coalesce_usecs = FEC_ITR_ICTT_DEFAULT;
- ec.tx_max_coalesced_frames = FEC_ITR_ICFT_DEFAULT;
-
- fec_enet_set_coalesce(ndev, &ec, NULL, NULL);
-}
-
static int fec_enet_get_tunable(struct net_device *netdev,
const struct ethtool_tunable *tuna,
void *data)
@@ -3623,6 +3610,10 @@ static int fec_enet_init(struct net_device *ndev)
fep->rx_align = 0x3;
fep->tx_align = 0x3;
#endif
+ fep->rx_pkts_itr = FEC_ITR_ICFT_DEFAULT;
+ fep->tx_pkts_itr = FEC_ITR_ICFT_DEFAULT;
+ fep->rx_time_itr = FEC_ITR_ICTT_DEFAULT;
+ fep->tx_time_itr = FEC_ITR_ICTT_DEFAULT;
/* Check mask of the streaming and coherent API */
ret = dma_set_mask_and_coherent(&fep->pdev->dev, DMA_BIT_MASK(32));
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 65df308bad97..13e67f2864be 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -487,12 +487,21 @@ _return_of_node_put:
return err;
}
+static int mac_remove(struct platform_device *pdev)
+{
+ struct mac_device *mac_dev = platform_get_drvdata(pdev);
+
+ platform_device_unregister(mac_dev->priv->eth_dev);
+ return 0;
+}
+
static struct platform_driver mac_driver = {
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = mac_match,
},
.probe = mac_probe,
+ .remove = mac_remove,
};
builtin_platform_driver(mac_driver);
diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c
index 93846bace028..ce2571c16e43 100644
--- a/drivers/net/ethernet/hisilicon/hisi_femac.c
+++ b/drivers/net/ethernet/hisilicon/hisi_femac.c
@@ -283,7 +283,7 @@ static int hisi_femac_rx(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
napi_gro_receive(&priv->napi, skb);
dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += len;
next:
pos = (pos + 1) % rxq->num;
if (rx_pkts_num >= limit)
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index ffcf797dfa90..f867e9531117 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -550,7 +550,7 @@ static int hix5hd2_rx(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
napi_gro_receive(&priv->napi, skb);
dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += len;
next:
pos = dma_ring_incr(pos, RX_DESC_NUM);
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 0179fc288f5f..17137de9338c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -819,7 +819,6 @@ struct hnae3_knic_private_info {
const struct hnae3_dcb_ops *dcb_ops;
u16 int_rl_setting;
- enum pkt_hash_types rss_type;
void __iomem *io_base;
};
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c
index e23729ac3bb8..ae2736549526 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c
@@ -191,23 +191,6 @@ u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle)
return HCLGE_COMM_RSS_KEY_SIZE;
}
-void hclge_comm_get_rss_type(struct hnae3_handle *nic,
- struct hclge_comm_rss_tuple_cfg *rss_tuple_sets)
-{
- if (rss_tuple_sets->ipv4_tcp_en ||
- rss_tuple_sets->ipv4_udp_en ||
- rss_tuple_sets->ipv4_sctp_en ||
- rss_tuple_sets->ipv6_tcp_en ||
- rss_tuple_sets->ipv6_udp_en ||
- rss_tuple_sets->ipv6_sctp_en)
- nic->kinfo.rss_type = PKT_HASH_TYPE_L4;
- else if (rss_tuple_sets->ipv4_fragment_en ||
- rss_tuple_sets->ipv6_fragment_en)
- nic->kinfo.rss_type = PKT_HASH_TYPE_L3;
- else
- nic->kinfo.rss_type = PKT_HASH_TYPE_NONE;
-}
-
int hclge_comm_parse_rss_hfunc(struct hclge_comm_rss_cfg *rss_cfg,
const u8 hfunc, u8 *hash_algo)
{
@@ -344,9 +327,6 @@ int hclge_comm_set_rss_input_tuple(struct hnae3_handle *nic,
req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
- if (is_pf)
- hclge_comm_get_rss_type(nic, &rss_cfg->rss_tuple_sets);
-
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret)
dev_err(&hw->cmq.csq.pdev->dev,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h
index 946d166a452d..92af3d2980d3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h
@@ -95,8 +95,6 @@ struct hclge_comm_rss_tc_mode_cmd {
};
u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle);
-void hclge_comm_get_rss_type(struct hnae3_handle *nic,
- struct hclge_comm_rss_tuple_cfg *rss_tuple_sets);
void hclge_comm_rss_indir_init_cfg(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_cfg *rss_cfg);
int hclge_comm_get_rss_tuple(struct hclge_comm_rss_cfg *rss_cfg, int flow_type,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 4cb2421e71a7..028577943ec5 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -105,26 +105,28 @@ static const struct pci_device_id hns3_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, hns3_pci_tbl);
-#define HNS3_RX_PTYPE_ENTRY(ptype, l, s, t) \
+#define HNS3_RX_PTYPE_ENTRY(ptype, l, s, t, h) \
{ ptype, \
l, \
CHECKSUM_##s, \
HNS3_L3_TYPE_##t, \
- 1 }
+ 1, \
+ h}
#define HNS3_RX_PTYPE_UNUSED_ENTRY(ptype) \
- { ptype, 0, CHECKSUM_NONE, HNS3_L3_TYPE_PARSE_FAIL, 0 }
+ { ptype, 0, CHECKSUM_NONE, HNS3_L3_TYPE_PARSE_FAIL, 0, \
+ PKT_HASH_TYPE_NONE }
static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
HNS3_RX_PTYPE_UNUSED_ENTRY(0),
- HNS3_RX_PTYPE_ENTRY(1, 0, COMPLETE, ARP),
- HNS3_RX_PTYPE_ENTRY(2, 0, COMPLETE, RARP),
- HNS3_RX_PTYPE_ENTRY(3, 0, COMPLETE, LLDP),
- HNS3_RX_PTYPE_ENTRY(4, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(5, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(6, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(7, 0, COMPLETE, CNM),
- HNS3_RX_PTYPE_ENTRY(8, 0, NONE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(1, 0, COMPLETE, ARP, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(2, 0, COMPLETE, RARP, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(3, 0, COMPLETE, LLDP, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(4, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(5, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(6, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(7, 0, COMPLETE, CNM, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(8, 0, NONE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
HNS3_RX_PTYPE_UNUSED_ENTRY(9),
HNS3_RX_PTYPE_UNUSED_ENTRY(10),
HNS3_RX_PTYPE_UNUSED_ENTRY(11),
@@ -132,36 +134,36 @@ static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
HNS3_RX_PTYPE_UNUSED_ENTRY(13),
HNS3_RX_PTYPE_UNUSED_ENTRY(14),
HNS3_RX_PTYPE_UNUSED_ENTRY(15),
- HNS3_RX_PTYPE_ENTRY(16, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(17, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(18, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(19, 0, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(20, 0, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(21, 0, NONE, IPV4),
- HNS3_RX_PTYPE_ENTRY(22, 0, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(23, 0, NONE, IPV4),
- HNS3_RX_PTYPE_ENTRY(24, 0, NONE, IPV4),
- HNS3_RX_PTYPE_ENTRY(25, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(16, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(17, 0, COMPLETE, IPV4, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(18, 0, COMPLETE, IPV4, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(19, 0, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(20, 0, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(21, 0, NONE, IPV4, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(22, 0, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(23, 0, NONE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(24, 0, NONE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(25, 0, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
HNS3_RX_PTYPE_UNUSED_ENTRY(26),
HNS3_RX_PTYPE_UNUSED_ENTRY(27),
HNS3_RX_PTYPE_UNUSED_ENTRY(28),
- HNS3_RX_PTYPE_ENTRY(29, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(30, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(31, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(32, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(33, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(34, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(35, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(36, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(37, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(29, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(30, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(31, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(32, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(33, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(34, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(35, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(36, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(37, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
HNS3_RX_PTYPE_UNUSED_ENTRY(38),
- HNS3_RX_PTYPE_ENTRY(39, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(40, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(41, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(42, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(43, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(44, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(45, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(39, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(40, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(41, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(42, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(43, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(44, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(45, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
HNS3_RX_PTYPE_UNUSED_ENTRY(46),
HNS3_RX_PTYPE_UNUSED_ENTRY(47),
HNS3_RX_PTYPE_UNUSED_ENTRY(48),
@@ -227,35 +229,35 @@ static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
HNS3_RX_PTYPE_UNUSED_ENTRY(108),
HNS3_RX_PTYPE_UNUSED_ENTRY(109),
HNS3_RX_PTYPE_UNUSED_ENTRY(110),
- HNS3_RX_PTYPE_ENTRY(111, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(112, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(113, 0, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(114, 0, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(115, 0, NONE, IPV6),
- HNS3_RX_PTYPE_ENTRY(116, 0, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(117, 0, NONE, IPV6),
- HNS3_RX_PTYPE_ENTRY(118, 0, NONE, IPV6),
- HNS3_RX_PTYPE_ENTRY(119, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(111, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(112, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(113, 0, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(114, 0, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(115, 0, NONE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(116, 0, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(117, 0, NONE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(118, 0, NONE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(119, 0, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
HNS3_RX_PTYPE_UNUSED_ENTRY(120),
HNS3_RX_PTYPE_UNUSED_ENTRY(121),
HNS3_RX_PTYPE_UNUSED_ENTRY(122),
- HNS3_RX_PTYPE_ENTRY(123, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(124, 0, COMPLETE, PARSE_FAIL),
- HNS3_RX_PTYPE_ENTRY(125, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(126, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(127, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(128, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(129, 1, UNNECESSARY, IPV4),
- HNS3_RX_PTYPE_ENTRY(130, 0, COMPLETE, IPV4),
- HNS3_RX_PTYPE_ENTRY(131, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(123, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(124, 0, COMPLETE, PARSE_FAIL, PKT_HASH_TYPE_NONE),
+ HNS3_RX_PTYPE_ENTRY(125, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(126, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(127, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(128, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(129, 1, UNNECESSARY, IPV4, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(130, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(131, 0, COMPLETE, IPV4, PKT_HASH_TYPE_L3),
HNS3_RX_PTYPE_UNUSED_ENTRY(132),
- HNS3_RX_PTYPE_ENTRY(133, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(134, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(135, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(136, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(137, 1, UNNECESSARY, IPV6),
- HNS3_RX_PTYPE_ENTRY(138, 0, COMPLETE, IPV6),
- HNS3_RX_PTYPE_ENTRY(139, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(133, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(134, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(135, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(136, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(137, 1, UNNECESSARY, IPV6, PKT_HASH_TYPE_L4),
+ HNS3_RX_PTYPE_ENTRY(138, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
+ HNS3_RX_PTYPE_ENTRY(139, 0, COMPLETE, IPV6, PKT_HASH_TYPE_L3),
HNS3_RX_PTYPE_UNUSED_ENTRY(140),
HNS3_RX_PTYPE_UNUSED_ENTRY(141),
HNS3_RX_PTYPE_UNUSED_ENTRY(142),
@@ -3776,8 +3778,8 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
desc_cb->reuse_flag = 1;
} else if (frag_size <= ring->rx_copybreak) {
ret = hns3_handle_rx_copybreak(skb, i, ring, pull_len, desc_cb);
- if (ret)
- goto out;
+ if (!ret)
+ return;
}
out:
@@ -4171,15 +4173,35 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
}
static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring,
- struct sk_buff *skb, u32 rss_hash)
+ struct sk_buff *skb, u32 rss_hash,
+ u32 l234info, u32 ol_info)
{
- struct hnae3_handle *handle = ring->tqp->handle;
- enum pkt_hash_types rss_type;
+ enum pkt_hash_types rss_type = PKT_HASH_TYPE_NONE;
+ struct net_device *netdev = ring_to_netdev(ring);
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
- if (rss_hash)
- rss_type = handle->kinfo.rss_type;
- else
- rss_type = PKT_HASH_TYPE_NONE;
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
+ u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S);
+
+ rss_type = hns3_rx_ptype_tbl[ptype].hash_type;
+ } else {
+ int l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
+ HNS3_RXD_L3ID_S);
+ int l4_type = hnae3_get_field(l234info, HNS3_RXD_L4ID_M,
+ HNS3_RXD_L4ID_S);
+
+ if (l3_type == HNS3_L3_TYPE_IPV4 ||
+ l3_type == HNS3_L3_TYPE_IPV6) {
+ if (l4_type == HNS3_L4_TYPE_UDP ||
+ l4_type == HNS3_L4_TYPE_TCP ||
+ l4_type == HNS3_L4_TYPE_SCTP)
+ rss_type = PKT_HASH_TYPE_L4;
+ else if (l4_type == HNS3_L4_TYPE_IGMP ||
+ l4_type == HNS3_L4_TYPE_ICMP)
+ rss_type = PKT_HASH_TYPE_L3;
+ }
+ }
skb_set_hash(skb, rss_hash, rss_type);
}
@@ -4282,7 +4304,8 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
ring->tqp_vector->rx_group.total_bytes += len;
- hns3_set_rx_skb_rss_type(ring, skb, le32_to_cpu(desc->rx.rss_hash));
+ hns3_set_rx_skb_rss_type(ring, skb, le32_to_cpu(desc->rx.rss_hash),
+ l234info, ol_info);
return 0;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index 133a054af6b7..294a14b4fdef 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -404,6 +404,7 @@ struct hns3_rx_ptype {
u32 ip_summed : 2;
u32 l3_type : 4;
u32 valid : 1;
+ u32 hash_type: 3;
};
struct ring_stats {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 6962a9d69cf8..4e54f91f7a6c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -3443,6 +3443,7 @@ static int hclge_update_tp_port_info(struct hclge_dev *hdev)
hdev->hw.mac.autoneg = cmd.base.autoneg;
hdev->hw.mac.speed = cmd.base.speed;
hdev->hw.mac.duplex = cmd.base.duplex;
+ linkmode_copy(hdev->hw.mac.advertising, cmd.link_modes.advertising);
return 0;
}
@@ -4859,7 +4860,6 @@ static int hclge_set_rss_tuple(struct hnae3_handle *handle,
return ret;
}
- hclge_comm_get_rss_type(&vport->nic, &hdev->rss_cfg.rss_tuple_sets);
return 0;
}
@@ -11587,9 +11587,12 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret)
goto err_msi_irq_uninit;
- if (hdev->hw.mac.media_type == HNAE3_MEDIA_TYPE_COPPER &&
- !hnae3_dev_phy_imp_supported(hdev)) {
- ret = hclge_mac_mdio_config(hdev);
+ if (hdev->hw.mac.media_type == HNAE3_MEDIA_TYPE_COPPER) {
+ if (hnae3_dev_phy_imp_supported(hdev))
+ ret = hclge_update_tp_port_info(hdev);
+ else
+ ret = hclge_mac_mdio_config(hdev);
+
if (ret)
goto err_msi_irq_uninit;
}
@@ -12984,14 +12987,16 @@ static void hclge_clean_vport_config(struct hnae3_ae_dev *ae_dev, int num_vfs)
static int hclge_get_dscp_prio(struct hnae3_handle *h, u8 dscp, u8 *tc_mode,
u8 *priority)
{
+ struct hclge_vport *vport = hclge_get_vport(h);
+
if (dscp >= HNAE3_MAX_DSCP)
return -EINVAL;
if (tc_mode)
- *tc_mode = h->kinfo.tc_map_mode;
+ *tc_mode = vport->nic.kinfo.tc_map_mode;
if (priority)
- *priority = h->kinfo.dscp_prio[dscp] == HNAE3_PRIO_ID_INVALID ? 0 :
- h->kinfo.dscp_prio[dscp];
+ *priority = vport->nic.kinfo.dscp_prio[dscp] == HNAE3_PRIO_ID_INVALID ? 0 :
+ vport->nic.kinfo.dscp_prio[dscp];
return 0;
}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index e1f54a2f28b2..2d6906aba2a2 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -1474,8 +1474,15 @@ static struct pci_driver hinic_driver = {
static int __init hinic_module_init(void)
{
+ int ret;
+
hinic_dbg_register_debugfs(HINIC_DRV_NAME);
- return pci_register_driver(&hinic_driver);
+
+ ret = pci_register_driver(&hinic_driver);
+ if (ret)
+ hinic_dbg_unregister_debugfs();
+
+ return ret;
}
static void __exit hinic_module_exit(void)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 3b14dc93f59d..5b96cd94dcd2 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1757,7 +1757,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
kobject_uevent(kobj, KOBJ_ADD);
}
- rc = netif_set_real_num_tx_queues(netdev, ibmveth_real_max_tx_queues());
+ rc = netif_set_real_num_tx_queues(netdev, min(num_online_cpus(),
+ IBMVETH_DEFAULT_QUEUES));
if (rc) {
netdev_dbg(netdev, "failed to set number of tx queues rc=%d\n",
rc);
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index daf6f615c03f..115d4c45aa77 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -100,6 +100,7 @@ static inline long h_illan_attributes(unsigned long unit_address,
#define IBMVETH_MAX_BUF_SIZE (1024 * 128)
#define IBMVETH_MAX_TX_BUF_SIZE (1024 * 64)
#define IBMVETH_MAX_QUEUES 16U
+#define IBMVETH_DEFAULT_QUEUES 8U
static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 };
static int pool_count[] = { 256, 512, 256, 256, 256 };
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index 560d1d442232..d3fdc290937f 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -1741,11 +1741,8 @@ static int e100_xmit_prepare(struct nic *nic, struct cb *cb,
dma_addr = dma_map_single(&nic->pdev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
/* If we can't map the skb, have the upper layer try later */
- if (dma_mapping_error(&nic->pdev->dev, dma_addr)) {
- dev_kfree_skb_any(skb);
- skb = NULL;
+ if (dma_mapping_error(&nic->pdev->dev, dma_addr))
return -ENOMEM;
- }
/*
* Use the last 4 bytes of the SKB payload packet as the CRC, used for
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 49e926959ad3..55cf2f62bb30 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5936,9 +5936,9 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
e1000_tx_queue(tx_ring, tx_flags, count);
/* Make sure there is space in the ring for the next send. */
e1000_maybe_stop_tx(tx_ring,
- (MAX_SKB_FRAGS *
+ ((MAX_SKB_FRAGS + 1) *
DIV_ROUND_UP(PAGE_SIZE,
- adapter->tx_fifo_limit) + 2));
+ adapter->tx_fifo_limit) + 4));
if (!netdev_xmit_more() ||
netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) {
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index 4a6630586ec9..fc373472e4e1 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -32,6 +32,8 @@ struct workqueue_struct *fm10k_workqueue;
**/
static int __init fm10k_init_module(void)
{
+ int ret;
+
pr_info("%s\n", fm10k_driver_string);
pr_info("%s\n", fm10k_copyright);
@@ -43,7 +45,13 @@ static int __init fm10k_init_module(void)
fm10k_dbg_init();
- return fm10k_register_pci_driver();
+ ret = fm10k_register_pci_driver();
+ if (ret) {
+ fm10k_dbg_exit();
+ destroy_workqueue(fm10k_workqueue);
+ }
+
+ return ret;
}
module_init(fm10k_init_module);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 4a6a6e48c615..f6fa63e4253c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -4464,11 +4464,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
return -EOPNOTSUPP;
/* First 4 bytes of L4 header */
- if (usr_ip4_spec->l4_4_bytes == htonl(0xFFFFFFFF))
- new_mask |= I40E_L4_SRC_MASK | I40E_L4_DST_MASK;
- else if (!usr_ip4_spec->l4_4_bytes)
- new_mask &= ~(I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
- else
+ if (usr_ip4_spec->l4_4_bytes)
return -EOPNOTSUPP;
/* Filtering on Type of Service is not supported. */
@@ -4507,11 +4503,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
else
return -EOPNOTSUPP;
- if (usr_ip6_spec->l4_4_bytes == htonl(0xFFFFFFFF))
- new_mask |= I40E_L4_SRC_MASK | I40E_L4_DST_MASK;
- else if (!usr_ip6_spec->l4_4_bytes)
- new_mask &= ~(I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
- else
+ if (usr_ip6_spec->l4_4_bytes)
return -EOPNOTSUPP;
/* Filtering on Traffic class is not supported. */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index b5dcd15ced36..6416322d7c18 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -10655,6 +10655,21 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)
}
/**
+ * i40e_clean_xps_state - clean xps state for every tx_ring
+ * @vsi: ptr to the VSI
+ **/
+static void i40e_clean_xps_state(struct i40e_vsi *vsi)
+{
+ int i;
+
+ if (vsi->tx_rings)
+ for (i = 0; i < vsi->num_queue_pairs; i++)
+ if (vsi->tx_rings[i])
+ clear_bit(__I40E_TX_XPS_INIT_DONE,
+ vsi->tx_rings[i]->state);
+}
+
+/**
* i40e_prep_for_reset - prep for the core to reset
* @pf: board private structure
*
@@ -10678,8 +10693,10 @@ static void i40e_prep_for_reset(struct i40e_pf *pf)
i40e_pf_quiesce_all_vsi(pf);
for (v = 0; v < pf->num_alloc_vsi; v++) {
- if (pf->vsi[v])
+ if (pf->vsi[v]) {
+ i40e_clean_xps_state(pf->vsi[v]);
pf->vsi[v]->seid = 0;
+ }
}
i40e_shutdown_adminq(&pf->hw);
@@ -16644,6 +16661,8 @@ static struct pci_driver i40e_driver = {
**/
static int __init i40e_init_module(void)
{
+ int err;
+
pr_info("%s: %s\n", i40e_driver_name, i40e_driver_string);
pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);
@@ -16661,7 +16680,14 @@ static int __init i40e_init_module(void)
}
i40e_dbg_init();
- return pci_register_driver(&i40e_driver);
+ err = pci_register_driver(&i40e_driver);
+ if (err) {
+ destroy_workqueue(i40e_wq);
+ i40e_dbg_exit();
+ return err;
+ }
+
+ return 0;
}
module_init(i40e_init_module);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 72ddcefc45b1..635f93d60318 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -1578,6 +1578,7 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
i40e_cleanup_reset_vf(vf);
i40e_flush(hw);
+ usleep_range(20000, 40000);
clear_bit(I40E_VF_STATE_RESETTING, &vf->vf_states);
return true;
@@ -1701,6 +1702,7 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
}
i40e_flush(hw);
+ usleep_range(20000, 40000);
clear_bit(__I40E_VF_DISABLE, pf->state);
return true;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 3f6187c16424..0d1bab4ac1b0 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -298,7 +298,6 @@ struct iavf_adapter {
#define IAVF_FLAG_QUEUES_DISABLED BIT(17)
#define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18)
#define IAVF_FLAG_REINIT_MSIX_NEEDED BIT(20)
-#define IAVF_FLAG_INITIAL_MAC_SET BIT(23)
/* duplicates for common code */
#define IAVF_FLAG_DCB_ENABLED 0
/* flags for admin queue service task */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 3fc572341781..f71e132ede09 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1087,12 +1087,6 @@ static int iavf_set_mac(struct net_device *netdev, void *p)
if (ret)
return ret;
- /* If this is an initial set MAC during VF spawn do not wait */
- if (adapter->flags & IAVF_FLAG_INITIAL_MAC_SET) {
- adapter->flags &= ~IAVF_FLAG_INITIAL_MAC_SET;
- return 0;
- }
-
ret = wait_event_interruptible_timeout(adapter->vc_waitqueue,
iavf_is_mac_set_handled(netdev, addr->sa_data),
msecs_to_jiffies(2500));
@@ -2605,8 +2599,6 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
}
- adapter->flags |= IAVF_FLAG_INITIAL_MAC_SET;
-
adapter->tx_desc_count = IAVF_DEFAULT_TXD;
adapter->rx_desc_count = IAVF_DEFAULT_RXD;
err = iavf_init_interrupt_scheme(adapter);
@@ -2921,7 +2913,6 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
iavf_free_queues(adapter);
memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE);
iavf_shutdown_adminq(&adapter->hw);
- adapter->netdev->flags &= ~IFF_UP;
adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
iavf_change_state(adapter, __IAVF_DOWN);
wake_up(&adapter->down_waitqueue);
@@ -3021,6 +3012,11 @@ static void iavf_reset_task(struct work_struct *work)
iavf_disable_vf(adapter);
mutex_unlock(&adapter->client_lock);
mutex_unlock(&adapter->crit_lock);
+ if (netif_running(netdev)) {
+ rtnl_lock();
+ dev_close(netdev);
+ rtnl_unlock();
+ }
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -3033,6 +3029,7 @@ continue_reset:
if (running) {
netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
adapter->link_up = false;
iavf_napi_disable_all(adapter);
}
@@ -3172,6 +3169,16 @@ reset_err:
mutex_unlock(&adapter->client_lock);
mutex_unlock(&adapter->crit_lock);
+
+ if (netif_running(netdev)) {
+ /* Close device to ensure that Tx queues will not be started
+ * during netif_device_attach() at the end of the reset task.
+ */
+ rtnl_lock();
+ dev_close(netdev);
+ rtnl_unlock();
+ }
+
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
reset_finish:
rtnl_lock();
@@ -5035,23 +5042,21 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
static void iavf_remove(struct pci_dev *pdev)
{
struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
- struct net_device *netdev = adapter->netdev;
struct iavf_fdir_fltr *fdir, *fdirtmp;
struct iavf_vlan_filter *vlf, *vlftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
struct iavf_adv_rss *rss, *rsstmp;
struct iavf_mac_filter *f, *ftmp;
- struct iavf_cloud_filter *cf, *cftmp;
- struct iavf_hw *hw = &adapter->hw;
+ struct net_device *netdev;
+ struct iavf_hw *hw;
int err;
- /* When reboot/shutdown is in progress no need to do anything
- * as the adapter is already REMOVE state that was set during
- * iavf_shutdown() callback.
- */
- if (adapter->state == __IAVF_REMOVE)
+ netdev = adapter->netdev;
+ hw = &adapter->hw;
+
+ if (test_and_set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
return;
- set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section);
/* Wait until port initialization is complete.
* There are flows where register/unregister netdev may race.
*/
@@ -5191,6 +5196,8 @@ static struct pci_driver iavf_driver = {
**/
static int __init iavf_init_module(void)
{
+ int ret;
+
pr_info("iavf: %s\n", iavf_driver_string);
pr_info("%s\n", iavf_copyright);
@@ -5201,7 +5208,12 @@ static int __init iavf_init_module(void)
pr_err("%s: Failed to create workqueue\n", iavf_driver_name);
return -ENOMEM;
}
- return pci_register_driver(&iavf_driver);
+
+ ret = pci_register_driver(&iavf_driver);
+ if (ret)
+ destroy_workqueue(iavf_wq);
+
+ return ret;
}
module_init(iavf_init_module);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 5a9e6563923e..24a701fd140e 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2438,6 +2438,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->is_new_vlan) {
f->is_new_vlan = false;
+ if (!f->vlan.vid)
+ continue;
if (f->vlan.tpid == ETH_P_8021Q)
set_bit(f->vlan.vid,
adapter->vsi.active_cvlans);
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 9e36f01dfa4f..e864634d66bc 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -958,7 +958,7 @@ ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
* associated to the queue to schedule NAPI handler
*/
q_vector = ring->q_vector;
- if (q_vector)
+ if (q_vector && !(vsi->vf && ice_is_vf_disabled(vsi->vf)))
ice_trigger_sw_intr(hw, q_vector);
status = ice_dis_vsi_txq(vsi->port_info, txq_meta->vsi_idx,
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 938ba8c215cb..7276badfa19e 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -2240,6 +2240,31 @@ int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi)
}
/**
+ * ice_vsi_is_rx_queue_active
+ * @vsi: the VSI being configured
+ *
+ * Return true if at least one queue is active.
+ */
+bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int i;
+
+ ice_for_each_rxq(vsi, i) {
+ u32 rx_reg;
+ int pf_q;
+
+ pf_q = vsi->rxq_map[i];
+ rx_reg = rd32(hw, QRX_CTRL(pf_q));
+ if (rx_reg & QRX_CTRL_QENA_STAT_M)
+ return true;
+ }
+
+ return false;
+}
+
+/**
* ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not
* @vsi: VSI to check whether or not VLAN pruning is enabled.
*
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index ec4bf0c89857..dcdf69a693e9 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -129,4 +129,5 @@ u16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi);
bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f);
void ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f);
void ice_init_feature_support(struct ice_pf *pf);
+bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi);
#endif /* !_ICE_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 0f6718719453..ca2898467dcb 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3145,15 +3145,15 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
*/
static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
{
- irqreturn_t ret = IRQ_HANDLED;
struct ice_pf *pf = data;
- bool irq_handled;
- irq_handled = ice_ptp_process_ts(pf);
- if (!irq_handled)
- ret = IRQ_WAKE_THREAD;
+ if (ice_is_reset_in_progress(pf->state))
+ return IRQ_HANDLED;
- return ret;
+ while (!ice_ptp_process_ts(pf))
+ usleep_range(50, 100);
+
+ return IRQ_HANDLED;
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 011b727ab190..0f668468d141 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -614,11 +614,14 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
* 2) extend the 40b timestamp value to get a 64bit timestamp
* 3) send that timestamp to the stack
*
- * After looping, if we still have waiting SKBs, return true. This may cause us
- * effectively poll even when not strictly necessary. We do this because it's
- * possible a new timestamp was requested around the same time as the interrupt.
- * In some cases hardware might not interrupt us again when the timestamp is
- * captured.
+ * Returns true if all timestamps were handled, and false if any slots remain
+ * without a timestamp.
+ *
+ * After looping, if we still have waiting SKBs, return false. This may cause
+ * us effectively poll even when not strictly necessary. We do this because
+ * it's possible a new timestamp was requested around the same time as the
+ * interrupt. In some cases hardware might not interrupt us again when the
+ * timestamp is captured.
*
* Note that we only take the tracking lock when clearing the bit and when
* checking if we need to re-queue this task. The only place where bits can be
@@ -641,7 +644,7 @@ static bool ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
u8 idx;
if (!tx->init)
- return false;
+ return true;
ptp_port = container_of(tx, struct ice_ptp_port, tx);
pf = ptp_port_to_pf(ptp_port);
@@ -2381,10 +2384,7 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
*/
bool ice_ptp_process_ts(struct ice_pf *pf)
{
- if (pf->ptp.port.tx.init)
- return ice_ptp_tx_tstamp(&pf->ptp.port.tx);
-
- return false;
+ return ice_ptp_tx_tstamp(&pf->ptp.port.tx);
}
static void ice_ptp_periodic_work(struct kthread_work *work)
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 0abeed092de1..1c51778db951 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -576,7 +576,10 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
return -EINVAL;
}
ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, vf->vf_id);
- ice_vsi_stop_all_rx_rings(vsi);
+
+ if (ice_vsi_is_rx_queue_active(vsi))
+ ice_vsi_stop_all_rx_rings(vsi);
+
dev_dbg(dev, "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n",
vf->vf_id);
return 0;
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index e5f3e7680dc6..ff911af16a4b 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -1413,6 +1413,8 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
*data = 1;
return -1;
}
+ wr32(E1000_IVAR_MISC, E1000_IVAR_VALID << 8);
+ wr32(E1000_EIMS, BIT(0));
} else if (adapter->flags & IGB_FLAG_HAS_MSI) {
shared_int = false;
if (request_irq(irq,
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 99933e89717a..e338fa572793 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -4869,6 +4869,8 @@ static struct pci_driver ixgbevf_driver = {
**/
static int __init ixgbevf_init_module(void)
{
+ int err;
+
pr_info("%s\n", ixgbevf_driver_string);
pr_info("%s\n", ixgbevf_copyright);
ixgbevf_wq = create_singlethread_workqueue(ixgbevf_driver_name);
@@ -4877,7 +4879,13 @@ static int __init ixgbevf_init_module(void)
return -ENOMEM;
}
- return pci_register_driver(&ixgbevf_driver);
+ err = pci_register_driver(&ixgbevf_driver);
+ if (err) {
+ destroy_workqueue(ixgbevf_wq);
+ return err;
+ }
+
+ return 0;
}
module_init(ixgbevf_init_module);
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 707993b445d1..8941f69d93e9 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2481,6 +2481,7 @@ out_free:
for (i = 0; i < mp->rxq_count; i++)
rxq_deinit(mp->rxq + i);
out:
+ napi_disable(&mp->napi);
free_irq(dev->irq, dev);
return err;
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index ff3e361e06e7..5aefaaff0871 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -4271,7 +4271,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)
/* Use the cpu associated to the rxq when it is online, in all
* the other cases, use the cpu 0 which can't be offline.
*/
- if (cpu_online(pp->rxq_def))
+ if (pp->rxq_def < nr_cpu_ids && cpu_online(pp->rxq_def))
elected_cpu = pp->rxq_def;
max_cpu = num_present_cpus();
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index eb0fb8128096..b399bdb1ca36 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -7350,6 +7350,7 @@ static int mvpp2_get_sram(struct platform_device *pdev,
struct mvpp2 *priv)
{
struct resource *res;
+ void __iomem *base;
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (!res) {
@@ -7360,9 +7361,12 @@ static int mvpp2_get_sram(struct platform_device *pdev,
return 0;
}
- priv->cm3_base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- return PTR_ERR_OR_ZERO(priv->cm3_base);
+ priv->cm3_base = base;
+ return 0;
}
static int mvpp2_probe(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
index 9089adcb75f9..b45dd7f04e21 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
@@ -521,14 +521,12 @@ static int octep_open(struct net_device *netdev)
octep_oq_dbell_init(oct);
ret = octep_get_link_status(oct);
- if (ret)
+ if (ret > 0)
octep_link_up(netdev);
return 0;
set_queues_err:
- octep_napi_disable(oct);
- octep_napi_delete(oct);
octep_clean_irqs(oct);
setup_irq_err:
octep_free_oqs(oct);
@@ -958,7 +956,7 @@ int octep_device_setup(struct octep_device *oct)
ret = octep_ctrl_mbox_init(ctrl_mbox);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize control mbox\n");
- return -1;
+ goto unsupported_dev;
}
oct->ctrl_mbox_ifstats_offset = OCTEP_CTRL_MBOX_SZ(ctrl_mbox->h2fq.elem_sz,
ctrl_mbox->h2fq.elem_cnt,
@@ -968,6 +966,10 @@ int octep_device_setup(struct octep_device *oct)
return 0;
unsupported_dev:
+ for (i = 0; i < OCTEP_MMIO_REGIONS; i++)
+ iounmap(oct->mmio[i].hw_addr);
+
+ kfree(oct->conf);
return -1;
}
@@ -1070,7 +1072,11 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->max_mtu = OCTEP_MAX_MTU;
netdev->mtu = OCTEP_DEFAULT_MTU;
- octep_get_mac_addr(octep_dev, octep_dev->mac_addr);
+ err = octep_get_mac_addr(octep_dev, octep_dev->mac_addr);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to get mac address\n");
+ goto register_dev_err;
+ }
eth_hw_addr_set(netdev, octep_dev->mac_addr);
err = register_netdev(netdev);
diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig
index e1036b0eb6b1..993ac180a5db 100644
--- a/drivers/net/ethernet/marvell/octeontx2/Kconfig
+++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig
@@ -36,6 +36,7 @@ config OCTEONTX2_PF
select DIMLIB
depends on PCI
depends on PTP_1588_CLOCK_OPTIONAL
+ depends on MACSEC || !MACSEC
help
This driver supports Marvell's OcteonTX2 NIC physical function.
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c
index 4a343f853b28..c0bedf402da9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c
@@ -951,7 +951,7 @@ static void mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction d
else
event.intr_mask = (dir == MCS_RX) ?
MCS_BBE_RX_PLFIFO_OVERFLOW_INT :
- MCS_BBE_RX_PLFIFO_OVERFLOW_INT;
+ MCS_BBE_TX_PLFIFO_OVERFLOW_INT;
/* Notify the lmac_id info which ran into BBE fatal error */
event.lmac_id = i & 0x3ULL;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index a1970ebedf95..f66dde2b0f92 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -880,6 +880,8 @@ static int rvu_dbg_rvu_pf_cgx_map_display(struct seq_file *filp, void *unused)
sprintf(lmac, "LMAC%d", lmac_id);
seq_printf(filp, "%s\t0x%x\t\tNIX%d\t\t%s\t%s\n",
dev_name(&pdev->dev), pcifunc, blkid, cgx, lmac);
+
+ pci_dev_put(pdev);
}
return 0;
}
@@ -2566,6 +2568,7 @@ static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id)
}
}
+ pci_dev_put(pdev);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 7646bb2ec89b..a62c1b322012 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -4985,6 +4985,8 @@ static int nix_setup_ipolicers(struct rvu *rvu,
ipolicer->ref_count = devm_kcalloc(rvu->dev,
ipolicer->band_prof.max,
sizeof(u16), GFP_KERNEL);
+ if (!ipolicer->ref_count)
+ return -ENOMEM;
}
/* Set policer timeunit to 2us ie (19 + 1) * 100 nsec = 2us */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c
index b04fb226f708..ae50d56258ec 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c
@@ -62,15 +62,18 @@ int rvu_sdp_init(struct rvu *rvu)
pfvf->sdp_info = devm_kzalloc(rvu->dev,
sizeof(struct sdp_node_info),
GFP_KERNEL);
- if (!pfvf->sdp_info)
+ if (!pfvf->sdp_info) {
+ pci_dev_put(pdev);
return -ENOMEM;
+ }
dev_info(rvu->dev, "SDP PF number:%d\n", sdp_pf_num[i]);
- put_device(&pdev->dev);
i++;
}
+ pci_dev_put(pdev);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index 9ac9e6615ae7..9e10e7471b88 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -898,6 +898,7 @@ static int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
}
sq->head = 0;
+ sq->cons_head = 0;
sq->sqe_per_sqb = (pfvf->hw.sqb_size / sq->sqe_size) - 1;
sq->num_sqbs = (qset->sqe_cnt + sq->sqe_per_sqb) / sq->sqe_per_sqb;
/* Set SQE threshold to 10% of total SQEs */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index 282db6fe3b08..67aa02bb2b85 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -884,7 +884,7 @@ static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf,
static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx)
{
#ifdef CONFIG_DCB
- if (pfvf->pfc_alloc_status[qidx])
+ if (qidx < NIX_PF_PFC_PRIO_MAX && pfvf->pfc_alloc_status[qidx])
return pfvf->pfc_schq_list[NIX_TXSCH_LVL_SMQ][qidx];
#endif
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 892ca88e0cf4..303930499a4c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -15,6 +15,7 @@
#include <net/ip.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
+#include <linux/bitfield.h>
#include "otx2_reg.h"
#include "otx2_common.h"
@@ -1171,6 +1172,59 @@ int otx2_set_real_num_queues(struct net_device *netdev,
}
EXPORT_SYMBOL(otx2_set_real_num_queues);
+static char *nix_sqoperr_e_str[NIX_SQOPERR_MAX] = {
+ "NIX_SQOPERR_OOR",
+ "NIX_SQOPERR_CTX_FAULT",
+ "NIX_SQOPERR_CTX_POISON",
+ "NIX_SQOPERR_DISABLED",
+ "NIX_SQOPERR_SIZE_ERR",
+ "NIX_SQOPERR_OFLOW",
+ "NIX_SQOPERR_SQB_NULL",
+ "NIX_SQOPERR_SQB_FAULT",
+ "NIX_SQOPERR_SQE_SZ_ZERO",
+};
+
+static char *nix_mnqerr_e_str[NIX_MNQERR_MAX] = {
+ "NIX_MNQERR_SQ_CTX_FAULT",
+ "NIX_MNQERR_SQ_CTX_POISON",
+ "NIX_MNQERR_SQB_FAULT",
+ "NIX_MNQERR_SQB_POISON",
+ "NIX_MNQERR_TOTAL_ERR",
+ "NIX_MNQERR_LSO_ERR",
+ "NIX_MNQERR_CQ_QUERY_ERR",
+ "NIX_MNQERR_MAX_SQE_SIZE_ERR",
+ "NIX_MNQERR_MAXLEN_ERR",
+ "NIX_MNQERR_SQE_SIZEM1_ZERO",
+};
+
+static char *nix_snd_status_e_str[NIX_SND_STATUS_MAX] = {
+ "NIX_SND_STATUS_GOOD",
+ "NIX_SND_STATUS_SQ_CTX_FAULT",
+ "NIX_SND_STATUS_SQ_CTX_POISON",
+ "NIX_SND_STATUS_SQB_FAULT",
+ "NIX_SND_STATUS_SQB_POISON",
+ "NIX_SND_STATUS_HDR_ERR",
+ "NIX_SND_STATUS_EXT_ERR",
+ "NIX_SND_STATUS_JUMP_FAULT",
+ "NIX_SND_STATUS_JUMP_POISON",
+ "NIX_SND_STATUS_CRC_ERR",
+ "NIX_SND_STATUS_IMM_ERR",
+ "NIX_SND_STATUS_SG_ERR",
+ "NIX_SND_STATUS_MEM_ERR",
+ "NIX_SND_STATUS_INVALID_SUBDC",
+ "NIX_SND_STATUS_SUBDC_ORDER_ERR",
+ "NIX_SND_STATUS_DATA_FAULT",
+ "NIX_SND_STATUS_DATA_POISON",
+ "NIX_SND_STATUS_NPC_DROP_ACTION",
+ "NIX_SND_STATUS_LOCK_VIOL",
+ "NIX_SND_STATUS_NPC_UCAST_CHAN_ERR",
+ "NIX_SND_STATUS_NPC_MCAST_CHAN_ERR",
+ "NIX_SND_STATUS_NPC_MCAST_ABORT",
+ "NIX_SND_STATUS_NPC_VTAG_PTR_ERR",
+ "NIX_SND_STATUS_NPC_VTAG_SIZE_ERR",
+ "NIX_SND_STATUS_SEND_STATS_ERR",
+};
+
static irqreturn_t otx2_q_intr_handler(int irq, void *data)
{
struct otx2_nic *pf = data;
@@ -1204,46 +1258,67 @@ static irqreturn_t otx2_q_intr_handler(int irq, void *data)
/* SQ */
for (qidx = 0; qidx < pf->hw.tot_tx_queues; qidx++) {
+ u64 sq_op_err_dbg, mnq_err_dbg, snd_err_dbg;
+ u8 sq_op_err_code, mnq_err_code, snd_err_code;
+
+ /* Below debug registers captures first errors corresponding to
+ * those registers. We don't have to check against SQ qid as
+ * these are fatal errors.
+ */
+
ptr = otx2_get_regaddr(pf, NIX_LF_SQ_OP_INT);
val = otx2_atomic64_add((qidx << 44), ptr);
otx2_write64(pf, NIX_LF_SQ_OP_INT, (qidx << 44) |
(val & NIX_SQINT_BITS));
- if (!(val & (NIX_SQINT_BITS | BIT_ULL(42))))
- continue;
-
if (val & BIT_ULL(42)) {
netdev_err(pf->netdev, "SQ%lld: error reading NIX_LF_SQ_OP_INT, NIX_LF_ERR_INT 0x%llx\n",
qidx, otx2_read64(pf, NIX_LF_ERR_INT));
- } else {
- if (val & BIT_ULL(NIX_SQINT_LMT_ERR)) {
- netdev_err(pf->netdev, "SQ%lld: LMT store error NIX_LF_SQ_OP_ERR_DBG:0x%llx",
- qidx,
- otx2_read64(pf,
- NIX_LF_SQ_OP_ERR_DBG));
- otx2_write64(pf, NIX_LF_SQ_OP_ERR_DBG,
- BIT_ULL(44));
- }
- if (val & BIT_ULL(NIX_SQINT_MNQ_ERR)) {
- netdev_err(pf->netdev, "SQ%lld: Meta-descriptor enqueue error NIX_LF_MNQ_ERR_DGB:0x%llx\n",
- qidx,
- otx2_read64(pf, NIX_LF_MNQ_ERR_DBG));
- otx2_write64(pf, NIX_LF_MNQ_ERR_DBG,
- BIT_ULL(44));
- }
- if (val & BIT_ULL(NIX_SQINT_SEND_ERR)) {
- netdev_err(pf->netdev, "SQ%lld: Send error, NIX_LF_SEND_ERR_DBG 0x%llx",
- qidx,
- otx2_read64(pf,
- NIX_LF_SEND_ERR_DBG));
- otx2_write64(pf, NIX_LF_SEND_ERR_DBG,
- BIT_ULL(44));
- }
- if (val & BIT_ULL(NIX_SQINT_SQB_ALLOC_FAIL))
- netdev_err(pf->netdev, "SQ%lld: SQB allocation failed",
- qidx);
+ goto done;
}
+ sq_op_err_dbg = otx2_read64(pf, NIX_LF_SQ_OP_ERR_DBG);
+ if (!(sq_op_err_dbg & BIT(44)))
+ goto chk_mnq_err_dbg;
+
+ sq_op_err_code = FIELD_GET(GENMASK(7, 0), sq_op_err_dbg);
+ netdev_err(pf->netdev, "SQ%lld: NIX_LF_SQ_OP_ERR_DBG(%llx) err=%s\n",
+ qidx, sq_op_err_dbg, nix_sqoperr_e_str[sq_op_err_code]);
+
+ otx2_write64(pf, NIX_LF_SQ_OP_ERR_DBG, BIT_ULL(44));
+
+ if (sq_op_err_code == NIX_SQOPERR_SQB_NULL)
+ goto chk_mnq_err_dbg;
+
+ /* Err is not NIX_SQOPERR_SQB_NULL, call aq function to read SQ structure.
+ * TODO: But we are in irq context. How to call mbox functions which does sleep
+ */
+
+chk_mnq_err_dbg:
+ mnq_err_dbg = otx2_read64(pf, NIX_LF_MNQ_ERR_DBG);
+ if (!(mnq_err_dbg & BIT(44)))
+ goto chk_snd_err_dbg;
+
+ mnq_err_code = FIELD_GET(GENMASK(7, 0), mnq_err_dbg);
+ netdev_err(pf->netdev, "SQ%lld: NIX_LF_MNQ_ERR_DBG(%llx) err=%s\n",
+ qidx, mnq_err_dbg, nix_mnqerr_e_str[mnq_err_code]);
+ otx2_write64(pf, NIX_LF_MNQ_ERR_DBG, BIT_ULL(44));
+
+chk_snd_err_dbg:
+ snd_err_dbg = otx2_read64(pf, NIX_LF_SEND_ERR_DBG);
+ if (snd_err_dbg & BIT(44)) {
+ snd_err_code = FIELD_GET(GENMASK(7, 0), snd_err_dbg);
+ netdev_err(pf->netdev, "SQ%lld: NIX_LF_SND_ERR_DBG:0x%llx err=%s\n",
+ qidx, snd_err_dbg, nix_snd_status_e_str[snd_err_code]);
+ otx2_write64(pf, NIX_LF_SEND_ERR_DBG, BIT_ULL(44));
+ }
+
+done:
+ /* Print values and reset */
+ if (val & BIT_ULL(NIX_SQINT_SQB_ALLOC_FAIL))
+ netdev_err(pf->netdev, "SQ%lld: SQB allocation failed",
+ qidx);
+
schedule_work(&pf->reset_task);
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_struct.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_struct.h
index aa205a0d158f..fa37b9f312ca 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_struct.h
@@ -281,4 +281,61 @@ enum nix_sqint_e {
BIT_ULL(NIX_SQINT_SEND_ERR) | \
BIT_ULL(NIX_SQINT_SQB_ALLOC_FAIL))
+enum nix_sqoperr_e {
+ NIX_SQOPERR_OOR = 0,
+ NIX_SQOPERR_CTX_FAULT = 1,
+ NIX_SQOPERR_CTX_POISON = 2,
+ NIX_SQOPERR_DISABLED = 3,
+ NIX_SQOPERR_SIZE_ERR = 4,
+ NIX_SQOPERR_OFLOW = 5,
+ NIX_SQOPERR_SQB_NULL = 6,
+ NIX_SQOPERR_SQB_FAULT = 7,
+ NIX_SQOPERR_SQE_SZ_ZERO = 8,
+ NIX_SQOPERR_MAX,
+};
+
+enum nix_mnqerr_e {
+ NIX_MNQERR_SQ_CTX_FAULT = 0,
+ NIX_MNQERR_SQ_CTX_POISON = 1,
+ NIX_MNQERR_SQB_FAULT = 2,
+ NIX_MNQERR_SQB_POISON = 3,
+ NIX_MNQERR_TOTAL_ERR = 4,
+ NIX_MNQERR_LSO_ERR = 5,
+ NIX_MNQERR_CQ_QUERY_ERR = 6,
+ NIX_MNQERR_MAX_SQE_SIZE_ERR = 7,
+ NIX_MNQERR_MAXLEN_ERR = 8,
+ NIX_MNQERR_SQE_SIZEM1_ZERO = 9,
+ NIX_MNQERR_MAX,
+};
+
+enum nix_snd_status_e {
+ NIX_SND_STATUS_GOOD = 0x0,
+ NIX_SND_STATUS_SQ_CTX_FAULT = 0x1,
+ NIX_SND_STATUS_SQ_CTX_POISON = 0x2,
+ NIX_SND_STATUS_SQB_FAULT = 0x3,
+ NIX_SND_STATUS_SQB_POISON = 0x4,
+ NIX_SND_STATUS_HDR_ERR = 0x5,
+ NIX_SND_STATUS_EXT_ERR = 0x6,
+ NIX_SND_STATUS_JUMP_FAULT = 0x7,
+ NIX_SND_STATUS_JUMP_POISON = 0x8,
+ NIX_SND_STATUS_CRC_ERR = 0x9,
+ NIX_SND_STATUS_IMM_ERR = 0x10,
+ NIX_SND_STATUS_SG_ERR = 0x11,
+ NIX_SND_STATUS_MEM_ERR = 0x12,
+ NIX_SND_STATUS_INVALID_SUBDC = 0x13,
+ NIX_SND_STATUS_SUBDC_ORDER_ERR = 0x14,
+ NIX_SND_STATUS_DATA_FAULT = 0x15,
+ NIX_SND_STATUS_DATA_POISON = 0x16,
+ NIX_SND_STATUS_NPC_DROP_ACTION = 0x17,
+ NIX_SND_STATUS_LOCK_VIOL = 0x18,
+ NIX_SND_STATUS_NPC_UCAST_CHAN_ERR = 0x19,
+ NIX_SND_STATUS_NPC_MCAST_CHAN_ERR = 0x20,
+ NIX_SND_STATUS_NPC_MCAST_ABORT = 0x21,
+ NIX_SND_STATUS_NPC_VTAG_PTR_ERR = 0x22,
+ NIX_SND_STATUS_NPC_VTAG_SIZE_ERR = 0x23,
+ NIX_SND_STATUS_SEND_MEM_FAULT = 0x24,
+ NIX_SND_STATUS_SEND_STATS_ERR = 0x25,
+ NIX_SND_STATUS_MAX,
+};
+
#endif /* OTX2_STRUCT_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index e64318c110fd..6a01ab1a6e6f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -1134,7 +1134,12 @@ int otx2_init_tc(struct otx2_nic *nic)
return err;
tc->flow_ht_params = tc_flow_ht_params;
- return rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
+ err = rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
+ if (err) {
+ kfree(tc->tc_entries_bitmap);
+ tc->tc_entries_bitmap = NULL;
+ }
+ return err;
}
EXPORT_SYMBOL(otx2_init_tc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 5ec11d71bf60..ef10aef3cda0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -441,6 +441,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,
struct otx2_cq_queue *cq, int budget)
{
int tx_pkts = 0, tx_bytes = 0, qidx;
+ struct otx2_snd_queue *sq;
struct nix_cqe_tx_s *cqe;
int processed_cqe = 0;
@@ -451,6 +452,9 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,
return 0;
process_cqe:
+ qidx = cq->cq_idx - pfvf->hw.rx_queues;
+ sq = &pfvf->qset.sq[qidx];
+
while (likely(processed_cqe < budget) && cq->pend_cqe) {
cqe = (struct nix_cqe_tx_s *)otx2_get_next_cqe(cq);
if (unlikely(!cqe)) {
@@ -458,18 +462,20 @@ process_cqe:
return 0;
break;
}
+
if (cq->cq_type == CQ_XDP) {
- qidx = cq->cq_idx - pfvf->hw.rx_queues;
- otx2_xdp_snd_pkt_handler(pfvf, &pfvf->qset.sq[qidx],
- cqe);
+ otx2_xdp_snd_pkt_handler(pfvf, sq, cqe);
} else {
- otx2_snd_pkt_handler(pfvf, cq,
- &pfvf->qset.sq[cq->cint_idx],
- cqe, budget, &tx_pkts, &tx_bytes);
+ otx2_snd_pkt_handler(pfvf, cq, sq, cqe, budget,
+ &tx_pkts, &tx_bytes);
}
+
cqe->hdr.cqe_type = NIX_XQE_TYPE_INVALID;
processed_cqe++;
cq->pend_cqe--;
+
+ sq->cons_head++;
+ sq->cons_head &= (sq->sqe_cnt - 1);
}
/* Free CQEs to HW */
@@ -1072,17 +1078,17 @@ bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq,
{
struct netdev_queue *txq = netdev_get_tx_queue(netdev, qidx);
struct otx2_nic *pfvf = netdev_priv(netdev);
- int offset, num_segs, free_sqe;
+ int offset, num_segs, free_desc;
struct nix_sqe_hdr_s *sqe_hdr;
- /* Check if there is room for new SQE.
- * 'Num of SQBs freed to SQ's pool - SQ's Aura count'
- * will give free SQE count.
+ /* Check if there is enough room between producer
+ * and consumer index.
*/
- free_sqe = (sq->num_sqbs - *sq->aura_fc_addr) * sq->sqe_per_sqb;
+ free_desc = (sq->cons_head - sq->head - 1 + sq->sqe_cnt) & (sq->sqe_cnt - 1);
+ if (free_desc < sq->sqe_thresh)
+ return false;
- if (free_sqe < sq->sqe_thresh ||
- free_sqe < otx2_get_sqe_count(pfvf, skb))
+ if (free_desc < otx2_get_sqe_count(pfvf, skb))
return false;
num_segs = skb_shinfo(skb)->nr_frags + 1;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
index fbe62bbfb789..93cac2c2664c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
@@ -79,6 +79,7 @@ struct sg_list {
struct otx2_snd_queue {
u8 aura_id;
u16 head;
+ u16 cons_head;
u16 sqe_size;
u32 sqe_cnt;
u16 num_sqbs;
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index 24f9d6024745..47796e4d900c 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -746,6 +746,7 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
return 0;
err_sfp_bind:
+ unregister_netdev(dev);
err_register_netdev:
prestera_port_list_del(port);
err_port_init:
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
index 4046be0e86ff..a9a1028cb17b 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
@@ -457,7 +457,7 @@ prestera_kern_neigh_cache_find(struct prestera_switch *sw,
n_cache =
rhashtable_lookup_fast(&sw->router->kern_neigh_cache_ht, key,
__prestera_kern_neigh_cache_ht_params);
- return IS_ERR(n_cache) ? NULL : n_cache;
+ return n_cache;
}
static void
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c
index aa080dc57ff0..02faaea2aefa 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c
@@ -330,7 +330,7 @@ prestera_nh_neigh_find(struct prestera_switch *sw,
nh_neigh = rhashtable_lookup_fast(&sw->router->nh_neigh_ht,
key, __prestera_nh_neigh_ht_params);
- return IS_ERR(nh_neigh) ? NULL : nh_neigh;
+ return nh_neigh;
}
struct prestera_nh_neigh *
@@ -484,7 +484,7 @@ __prestera_nexthop_group_find(struct prestera_switch *sw,
nh_grp = rhashtable_lookup_fast(&sw->router->nexthop_group_ht,
key, __prestera_nexthop_group_ht_params);
- return IS_ERR(nh_grp) ? NULL : nh_grp;
+ return nh_grp;
}
static struct prestera_nexthop_group *
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
index 42ee963e9f75..9277a8fd1339 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
@@ -776,6 +776,7 @@ tx_done:
int prestera_rxtx_switch_init(struct prestera_switch *sw)
{
struct prestera_rxtx *rxtx;
+ int err;
rxtx = kzalloc(sizeof(*rxtx), GFP_KERNEL);
if (!rxtx)
@@ -783,7 +784,11 @@ int prestera_rxtx_switch_init(struct prestera_switch *sw)
sw->rxtx = rxtx;
- return prestera_sdma_switch_init(sw);
+ err = prestera_sdma_switch_init(sw);
+ if (err)
+ kfree(rxtx);
+
+ return err;
}
void prestera_rxtx_switch_fini(struct prestera_switch *sw)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 7cd381530aa4..1d36619c5ec9 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2378,8 +2378,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
data + NET_SKB_PAD + eth->ip_align,
ring->buf_size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(eth->dma_dev,
- dma_addr)))
+ dma_addr))) {
+ skb_free_frag(data);
return -ENOMEM;
+ }
}
rxd->rxd1 = (unsigned int)dma_addr;
ring->data[i] = data;
@@ -2996,8 +2998,10 @@ static int mtk_open(struct net_device *dev)
int i;
err = mtk_start_dma(eth);
- if (err)
+ if (err) {
+ phylink_disconnect_phy(mac->phylink);
return err;
+ }
for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
mtk_ppe_start(eth->ppe[i]);
@@ -4143,13 +4147,13 @@ static int mtk_probe(struct platform_device *pdev)
eth->soc->offload_version, i);
if (!eth->ppe[i]) {
err = -ENOMEM;
- goto err_free_dev;
+ goto err_deinit_ppe;
}
}
err = mtk_eth_offload_init(eth);
if (err)
- goto err_free_dev;
+ goto err_deinit_ppe;
}
for (i = 0; i < MTK_MAX_DEVS; i++) {
@@ -4159,7 +4163,7 @@ static int mtk_probe(struct platform_device *pdev)
err = register_netdev(eth->netdev[i]);
if (err) {
dev_err(eth->dev, "error bringing up device\n");
- goto err_deinit_mdio;
+ goto err_deinit_ppe;
} else
netif_info(eth, probe, eth->netdev[i],
"mediatek frame engine at 0x%08lx, irq %d\n",
@@ -4177,7 +4181,8 @@ static int mtk_probe(struct platform_device *pdev)
return 0;
-err_deinit_mdio:
+err_deinit_ppe:
+ mtk_ppe_deinit(eth);
mtk_mdio_cleanup(eth);
err_free_dev:
mtk_free_dev(eth);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 2d8ca99f2467..784ecb2dc9fb 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -737,7 +737,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
MTK_PPE_ENTRIES * soc->foe_entry_size,
&ppe->foe_phys, GFP_KERNEL);
if (!foe)
- return NULL;
+ goto err_free_l2_flows;
ppe->foe_table = foe;
@@ -745,11 +745,26 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
sizeof(*ppe->foe_flow);
ppe->foe_flow = devm_kzalloc(dev, foe_flow_size, GFP_KERNEL);
if (!ppe->foe_flow)
- return NULL;
+ goto err_free_l2_flows;
mtk_ppe_debugfs_init(ppe, index);
return ppe;
+
+err_free_l2_flows:
+ rhashtable_destroy(&ppe->l2_flows);
+ return NULL;
+}
+
+void mtk_ppe_deinit(struct mtk_eth *eth)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) {
+ if (!eth->ppe[i])
+ return;
+ rhashtable_destroy(&eth->ppe[i]->l2_flows);
+ }
}
static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 0b7a67a958e4..a09c32539bcc 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -304,6 +304,7 @@ struct mtk_ppe {
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
int version, int index);
+void mtk_ppe_deinit(struct mtk_eth *eth);
void mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c
index 7e890f81148e..7050351250b7 100644
--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c
+++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c
@@ -1026,6 +1026,8 @@ static int mtk_star_enable(struct net_device *ndev)
return 0;
err_free_irq:
+ napi_disable(&priv->rx_napi);
+ napi_disable(&priv->tx_napi);
free_irq(ndev->irq, ndev);
err_free_skbs:
mtk_star_free_rx_skbs(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index b149e601f673..48cfaa7eaf50 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -697,7 +697,8 @@ static int mlx4_create_zones(struct mlx4_dev *dev,
err = mlx4_bitmap_init(*bitmap + k, 1,
MLX4_QP_TABLE_RAW_ETH_SIZE - 1, 0,
0);
- mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0);
+ if (!err)
+ mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0);
}
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index 46ba4c2faad2..e7a894ba5c3e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -45,6 +45,8 @@
#include "mlx5_core.h"
#include "lib/eq.h"
#include "lib/tout.h"
+#define CREATE_TRACE_POINTS
+#include "diag/cmd_tracepoint.h"
enum {
CMD_IF_REV = 5,
@@ -785,27 +787,14 @@ EXPORT_SYMBOL(mlx5_cmd_out_err);
static void cmd_status_print(struct mlx5_core_dev *dev, void *in, void *out)
{
u16 opcode, op_mod;
- u32 syndrome;
- u8 status;
u16 uid;
- int err;
-
- syndrome = MLX5_GET(mbox_out, out, syndrome);
- status = MLX5_GET(mbox_out, out, status);
opcode = MLX5_GET(mbox_in, in, opcode);
op_mod = MLX5_GET(mbox_in, in, op_mod);
uid = MLX5_GET(mbox_in, in, uid);
- err = cmd_status_to_err(status);
-
if (!uid && opcode != MLX5_CMD_OP_DESTROY_MKEY)
mlx5_cmd_out_err(dev, opcode, op_mod, out);
- else
- mlx5_core_dbg(dev,
- "%s(0x%x) op_mod(0x%x) uid(%d) failed, status %s(0x%x), syndrome (0x%x), err(%d)\n",
- mlx5_command_str(opcode), opcode, op_mod, uid,
- cmd_status_str(status), status, syndrome, err);
}
int mlx5_cmd_check(struct mlx5_core_dev *dev, int err, void *in, void *out)
@@ -1016,6 +1005,7 @@ static void cmd_work_handler(struct work_struct *work)
cmd_ent_get(ent);
set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
+ cmd_ent_get(ent); /* for the _real_ FW event on completion */
/* Skip sending command to fw if internal error */
if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) {
ent->ret = -ENXIO;
@@ -1023,7 +1013,6 @@ static void cmd_work_handler(struct work_struct *work)
return;
}
- cmd_ent_get(ent); /* for the _real_ FW event on completion */
/* ring doorbell after the descriptor is valid */
mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
wmb();
@@ -1508,8 +1497,8 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf,
return -EFAULT;
err = sscanf(outlen_str, "%d", &outlen);
- if (err < 0)
- return err;
+ if (err != 1)
+ return -EINVAL;
ptr = kzalloc(outlen, GFP_KERNEL);
if (!ptr)
@@ -1672,8 +1661,8 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
cmd_ent_put(ent); /* timeout work was canceled */
if (!forced || /* Real FW completion */
- pci_channel_offline(dev->pdev) || /* FW is inaccessible */
- dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
+ mlx5_cmd_is_down(dev) || /* No real FW completion is expected */
+ !opcode_allowed(cmd, ent->op))
cmd_ent_put(ent);
ent->ts2 = ktime_get_ns();
@@ -1770,12 +1759,17 @@ void mlx5_cmd_flush(struct mlx5_core_dev *dev)
struct mlx5_cmd *cmd = &dev->cmd;
int i;
- for (i = 0; i < cmd->max_reg_cmds; i++)
- while (down_trylock(&cmd->sem))
+ for (i = 0; i < cmd->max_reg_cmds; i++) {
+ while (down_trylock(&cmd->sem)) {
mlx5_cmd_trigger_completions(dev);
+ cond_resched();
+ }
+ }
- while (down_trylock(&cmd->pages_sem))
+ while (down_trylock(&cmd->pages_sem)) {
mlx5_cmd_trigger_completions(dev);
+ cond_resched();
+ }
/* Unlock cmdif */
up(&cmd->pages_sem);
@@ -1887,6 +1881,16 @@ out_in:
return err;
}
+static void mlx5_cmd_err_trace(struct mlx5_core_dev *dev, u16 opcode, u16 op_mod, void *out)
+{
+ u32 syndrome = MLX5_GET(mbox_out, out, syndrome);
+ u8 status = MLX5_GET(mbox_out, out, status);
+
+ trace_mlx5_cmd(mlx5_command_str(opcode), opcode, op_mod,
+ cmd_status_str(status), status, syndrome,
+ cmd_status_to_err(status));
+}
+
static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
u32 syndrome, int err)
{
@@ -1909,7 +1913,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
}
/* preserve -EREMOTEIO for outbox.status != OK, otherwise return err as is */
-static int cmd_status_err(struct mlx5_core_dev *dev, int err, u16 opcode, void *out)
+static int cmd_status_err(struct mlx5_core_dev *dev, int err, u16 opcode, u16 op_mod, void *out)
{
u32 syndrome = MLX5_GET(mbox_out, out, syndrome);
u8 status = MLX5_GET(mbox_out, out, status);
@@ -1917,8 +1921,10 @@ static int cmd_status_err(struct mlx5_core_dev *dev, int err, u16 opcode, void *
if (err == -EREMOTEIO) /* -EREMOTEIO is preserved */
err = -EIO;
- if (!err && status != MLX5_CMD_STAT_OK)
+ if (!err && status != MLX5_CMD_STAT_OK) {
err = -EREMOTEIO;
+ mlx5_cmd_err_trace(dev, opcode, op_mod, out);
+ }
cmd_status_log(dev, opcode, status, syndrome, err);
return err;
@@ -1946,9 +1952,9 @@ int mlx5_cmd_do(struct mlx5_core_dev *dev, void *in, int in_size, void *out, int
{
int err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, false);
u16 opcode = MLX5_GET(mbox_in, in, opcode);
+ u16 op_mod = MLX5_GET(mbox_in, in, op_mod);
- err = cmd_status_err(dev, err, opcode, out);
- return err;
+ return cmd_status_err(dev, err, opcode, op_mod, out);
}
EXPORT_SYMBOL(mlx5_cmd_do);
@@ -1992,8 +1998,9 @@ int mlx5_cmd_exec_polling(struct mlx5_core_dev *dev, void *in, int in_size,
{
int err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, true);
u16 opcode = MLX5_GET(mbox_in, in, opcode);
+ u16 op_mod = MLX5_GET(mbox_in, in, op_mod);
- err = cmd_status_err(dev, err, opcode, out);
+ err = cmd_status_err(dev, err, opcode, op_mod, out);
return mlx5_cmd_check(dev, err, in, out);
}
EXPORT_SYMBOL(mlx5_cmd_exec_polling);
@@ -2029,7 +2036,7 @@ static void mlx5_cmd_exec_cb_handler(int status, void *_work)
struct mlx5_async_ctx *ctx;
ctx = work->ctx;
- status = cmd_status_err(ctx->dev, status, work->opcode, work->out);
+ status = cmd_status_err(ctx->dev, status, work->opcode, work->op_mod, work->out);
work->user_callback(status, work);
if (atomic_dec_and_test(&ctx->num_inflight))
complete(&ctx->inflight_done);
@@ -2044,6 +2051,7 @@ int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size,
work->ctx = ctx;
work->user_callback = callback;
work->opcode = MLX5_GET(mbox_in, in, opcode);
+ work->op_mod = MLX5_GET(mbox_in, in, op_mod);
work->out = out;
if (WARN_ON(!atomic_inc_not_zero(&ctx->num_inflight)))
return -EIO;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/cmd_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/cmd_tracepoint.h
new file mode 100644
index 000000000000..406ebe17405f
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/cmd_tracepoint.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mlx5
+
+#if !defined(_MLX5_CMD_TP_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MLX5_CMD_TP_H_
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+TRACE_EVENT(mlx5_cmd,
+ TP_PROTO(const char *command_str, u16 opcode, u16 op_mod,
+ const char *status_str, u8 status, u32 syndrome, int err),
+ TP_ARGS(command_str, opcode, op_mod, status_str, status, syndrome, err),
+ TP_STRUCT__entry(__string(command_str, command_str)
+ __field(u16, opcode)
+ __field(u16, op_mod)
+ __string(status_str, status_str)
+ __field(u8, status)
+ __field(u32, syndrome)
+ __field(int, err)
+ ),
+ TP_fast_assign(__assign_str(command_str, command_str);
+ __entry->opcode = opcode;
+ __entry->op_mod = op_mod;
+ __assign_str(status_str, status_str);
+ __entry->status = status;
+ __entry->syndrome = syndrome;
+ __entry->err = err;
+ ),
+ TP_printk("%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x), err(%d)",
+ __get_str(command_str), __entry->opcode, __entry->op_mod,
+ __get_str(status_str), __entry->status, __entry->syndrome,
+ __entry->err)
+);
+
+#endif /* _MLX5_CMD_TP_H_ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ./diag
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE cmd_tracepoint
+#include <trace/define_trace.h>
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
index 978a2bb8e122..21831386b26e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
@@ -638,7 +638,7 @@ static void mlx5_tracer_handle_timestamp_trace(struct mlx5_fw_tracer *tracer,
trace_timestamp = (timestamp_event.timestamp & MASK_52_7) |
(str_frmt->timestamp & MASK_6_0);
else
- trace_timestamp = ((timestamp_event.timestamp & MASK_52_7) - 1) |
+ trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) |
(str_frmt->timestamp & MASK_6_0);
mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
index 39ef2a2561a3..8099a21e674c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
@@ -164,6 +164,36 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr
return err;
}
+static int
+mlx5_esw_bridge_changeupper_validate_netdev(void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct net_device *upper = info->upper_dev;
+ struct net_device *lower;
+ struct list_head *iter;
+
+ if (!netif_is_bridge_master(upper) || !netif_is_lag_master(dev))
+ return 0;
+
+ netdev_for_each_lower_dev(dev, lower, iter) {
+ struct mlx5_core_dev *mdev;
+ struct mlx5e_priv *priv;
+
+ if (!mlx5e_eswitch_rep(lower))
+ continue;
+
+ priv = netdev_priv(lower);
+ mdev = priv->mdev;
+ if (!mlx5_lag_is_active(mdev))
+ return -EAGAIN;
+ if (!mlx5_lag_is_shared_fdb(mdev))
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -171,6 +201,7 @@ static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb,
switch (event) {
case NETDEV_PRECHANGEUPPER:
+ err = mlx5_esw_bridge_changeupper_validate_netdev(ptr);
break;
case NETDEV_CHANGEUPPER:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
index 305fde62a78d..3337241cfd84 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
@@ -6,70 +6,42 @@
#include "en/tc_priv.h"
#include "mlx5_core.h"
-/* Must be aligned with enum flow_action_id. */
static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
- &mlx5e_tc_act_accept,
- &mlx5e_tc_act_drop,
- &mlx5e_tc_act_trap,
- &mlx5e_tc_act_goto,
- &mlx5e_tc_act_mirred,
- &mlx5e_tc_act_mirred,
- &mlx5e_tc_act_redirect_ingress,
- NULL, /* FLOW_ACTION_MIRRED_INGRESS, */
- &mlx5e_tc_act_vlan,
- &mlx5e_tc_act_vlan,
- &mlx5e_tc_act_vlan_mangle,
- &mlx5e_tc_act_tun_encap,
- &mlx5e_tc_act_tun_decap,
- &mlx5e_tc_act_pedit,
- &mlx5e_tc_act_pedit,
- &mlx5e_tc_act_csum,
- NULL, /* FLOW_ACTION_MARK, */
- &mlx5e_tc_act_ptype,
- NULL, /* FLOW_ACTION_PRIORITY, */
- NULL, /* FLOW_ACTION_WAKE, */
- NULL, /* FLOW_ACTION_QUEUE, */
- &mlx5e_tc_act_sample,
- &mlx5e_tc_act_police,
- &mlx5e_tc_act_ct,
- NULL, /* FLOW_ACTION_CT_METADATA, */
- &mlx5e_tc_act_mpls_push,
- &mlx5e_tc_act_mpls_pop,
- NULL, /* FLOW_ACTION_MPLS_MANGLE, */
- NULL, /* FLOW_ACTION_GATE, */
- NULL, /* FLOW_ACTION_PPPOE_PUSH, */
- NULL, /* FLOW_ACTION_JUMP, */
- NULL, /* FLOW_ACTION_PIPE, */
- &mlx5e_tc_act_vlan,
- &mlx5e_tc_act_vlan,
+ [FLOW_ACTION_ACCEPT] = &mlx5e_tc_act_accept,
+ [FLOW_ACTION_DROP] = &mlx5e_tc_act_drop,
+ [FLOW_ACTION_TRAP] = &mlx5e_tc_act_trap,
+ [FLOW_ACTION_GOTO] = &mlx5e_tc_act_goto,
+ [FLOW_ACTION_REDIRECT] = &mlx5e_tc_act_mirred,
+ [FLOW_ACTION_MIRRED] = &mlx5e_tc_act_mirred,
+ [FLOW_ACTION_REDIRECT_INGRESS] = &mlx5e_tc_act_redirect_ingress,
+ [FLOW_ACTION_VLAN_PUSH] = &mlx5e_tc_act_vlan,
+ [FLOW_ACTION_VLAN_POP] = &mlx5e_tc_act_vlan,
+ [FLOW_ACTION_VLAN_MANGLE] = &mlx5e_tc_act_vlan_mangle,
+ [FLOW_ACTION_TUNNEL_ENCAP] = &mlx5e_tc_act_tun_encap,
+ [FLOW_ACTION_TUNNEL_DECAP] = &mlx5e_tc_act_tun_decap,
+ [FLOW_ACTION_MANGLE] = &mlx5e_tc_act_pedit,
+ [FLOW_ACTION_ADD] = &mlx5e_tc_act_pedit,
+ [FLOW_ACTION_CSUM] = &mlx5e_tc_act_csum,
+ [FLOW_ACTION_PTYPE] = &mlx5e_tc_act_ptype,
+ [FLOW_ACTION_SAMPLE] = &mlx5e_tc_act_sample,
+ [FLOW_ACTION_POLICE] = &mlx5e_tc_act_police,
+ [FLOW_ACTION_CT] = &mlx5e_tc_act_ct,
+ [FLOW_ACTION_MPLS_PUSH] = &mlx5e_tc_act_mpls_push,
+ [FLOW_ACTION_MPLS_POP] = &mlx5e_tc_act_mpls_pop,
+ [FLOW_ACTION_VLAN_PUSH_ETH] = &mlx5e_tc_act_vlan,
+ [FLOW_ACTION_VLAN_POP_ETH] = &mlx5e_tc_act_vlan,
};
-/* Must be aligned with enum flow_action_id. */
static struct mlx5e_tc_act *tc_acts_nic[NUM_FLOW_ACTIONS] = {
- &mlx5e_tc_act_accept,
- &mlx5e_tc_act_drop,
- NULL, /* FLOW_ACTION_TRAP, */
- &mlx5e_tc_act_goto,
- &mlx5e_tc_act_mirred_nic,
- NULL, /* FLOW_ACTION_MIRRED, */
- NULL, /* FLOW_ACTION_REDIRECT_INGRESS, */
- NULL, /* FLOW_ACTION_MIRRED_INGRESS, */
- NULL, /* FLOW_ACTION_VLAN_PUSH, */
- NULL, /* FLOW_ACTION_VLAN_POP, */
- NULL, /* FLOW_ACTION_VLAN_MANGLE, */
- NULL, /* FLOW_ACTION_TUNNEL_ENCAP, */
- NULL, /* FLOW_ACTION_TUNNEL_DECAP, */
- &mlx5e_tc_act_pedit,
- &mlx5e_tc_act_pedit,
- &mlx5e_tc_act_csum,
- &mlx5e_tc_act_mark,
- NULL, /* FLOW_ACTION_PTYPE, */
- NULL, /* FLOW_ACTION_PRIORITY, */
- NULL, /* FLOW_ACTION_WAKE, */
- NULL, /* FLOW_ACTION_QUEUE, */
- NULL, /* FLOW_ACTION_SAMPLE, */
- NULL, /* FLOW_ACTION_POLICE, */
- &mlx5e_tc_act_ct,
+ [FLOW_ACTION_ACCEPT] = &mlx5e_tc_act_accept,
+ [FLOW_ACTION_DROP] = &mlx5e_tc_act_drop,
+ [FLOW_ACTION_GOTO] = &mlx5e_tc_act_goto,
+ [FLOW_ACTION_REDIRECT] = &mlx5e_tc_act_mirred_nic,
+ [FLOW_ACTION_MANGLE] = &mlx5e_tc_act_pedit,
+ [FLOW_ACTION_ADD] = &mlx5e_tc_act_pedit,
+ [FLOW_ACTION_CSUM] = &mlx5e_tc_act_csum,
+ [FLOW_ACTION_MARK] = &mlx5e_tc_act_mark,
+ [FLOW_ACTION_CT] = &mlx5e_tc_act_ct,
};
/**
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
index 5aff97914367..ff73d25bc6eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
@@ -224,15 +224,16 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
list_for_each_entry(flow, flow_list, tmp_list) {
if (!mlx5e_is_offloaded_flow(flow) || flow_flag_test(flow, SLOW))
continue;
- spec = &flow->attr->parse_attr->spec;
-
- /* update from encap rule to slow path rule */
- rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec);
attr = mlx5e_tc_get_encap_attr(flow);
esw_attr = attr->esw_attr;
/* mark the flow's encap dest as non-valid */
esw_attr->dests[flow->tmp_entry_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
+ esw_attr->dests[flow->tmp_entry_index].pkt_reformat = NULL;
+
+ /* update from encap rule to slow path rule */
+ spec = &flow->attr->parse_attr->spec;
+ rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
@@ -251,6 +252,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
/* we know that the encap is valid */
e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat);
+ e->pkt_reformat = NULL;
}
static void mlx5e_take_tmp_flow(struct mlx5e_tc_flow *flow,
@@ -762,8 +764,7 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
struct net_device *mirred_dev,
int out_index,
struct netlink_ext_ack *extack,
- struct net_device **encap_dev,
- bool *encap_valid)
+ struct net_device **encap_dev)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5e_tc_flow_parse_attr *parse_attr;
@@ -878,9 +879,8 @@ attach_flow:
if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
attr->esw_attr->dests[out_index].pkt_reformat = e->pkt_reformat;
attr->esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
- *encap_valid = true;
} else {
- *encap_valid = false;
+ flow_flag_set(flow, SLOW);
}
mutex_unlock(&esw->offloads.encap_tbl_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h
index d542b8476491..8ad273dde40e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h
@@ -17,8 +17,7 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
struct net_device *mirred_dev,
int out_index,
struct netlink_ext_ack *extack,
- struct net_device **encap_dev,
- bool *encap_valid);
+ struct net_device **encap_dev);
int mlx5e_attach_decap(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index cb164b62f543..853f312cd757 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -11,6 +11,27 @@
#define INL_HDR_START_SZ (sizeof(((struct mlx5_wqe_eth_seg *)NULL)->inline_hdr.start))
+/* IPSEC inline data includes:
+ * 1. ESP trailer: up to 255 bytes of padding, 1 byte for pad length, 1 byte for
+ * next header.
+ * 2. ESP authentication data: 16 bytes for ICV.
+ */
+#define MLX5E_MAX_TX_IPSEC_DS DIV_ROUND_UP(sizeof(struct mlx5_wqe_inline_seg) + \
+ 255 + 1 + 1 + 16, MLX5_SEND_WQE_DS)
+
+/* 366 should be big enough to cover all L2, L3 and L4 headers with possible
+ * encapsulations.
+ */
+#define MLX5E_MAX_TX_INLINE_DS DIV_ROUND_UP(366 - INL_HDR_START_SZ + VLAN_HLEN, \
+ MLX5_SEND_WQE_DS)
+
+/* Sync the calculation with mlx5e_sq_calc_wqe_attr. */
+#define MLX5E_MAX_TX_WQEBBS DIV_ROUND_UP(MLX5E_TX_WQE_EMPTY_DS_COUNT + \
+ MLX5E_MAX_TX_INLINE_DS + \
+ MLX5E_MAX_TX_IPSEC_DS + \
+ MAX_SKB_FRAGS + 1, \
+ MLX5_SEND_WQEBB_NUM_DS)
+
#define MLX5E_RX_ERR_CQE(cqe) (get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND)
static inline
@@ -424,6 +445,8 @@ mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
static inline u16 mlx5e_stop_room_for_wqe(struct mlx5_core_dev *mdev, u16 wqe_size)
{
+ WARN_ON_ONCE(PAGE_SIZE / MLX5_SEND_WQE_BB < mlx5e_get_max_sq_wqebbs(mdev));
+
/* A WQE must not cross the page boundary, hence two conditions:
* 1. Its size must not exceed the page size.
* 2. If the WQE size is X, and the space remaining in a page is less
@@ -436,7 +459,6 @@ static inline u16 mlx5e_stop_room_for_wqe(struct mlx5_core_dev *mdev, u16 wqe_si
"wqe_size %u is greater than max SQ WQEBBs %u",
wqe_size, mlx5e_get_max_sq_wqebbs(mdev));
-
return MLX5E_STOP_ROOM(wqe_size);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index 4685c652c97e..20507ef2f956 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -117,7 +117,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
xdpi.page.rq = rq;
dma_addr = page_pool_get_dma_addr(page) + (xdpf->data - (void *)xdpf);
- dma_sync_single_for_device(sq->pdev, dma_addr, xdptxd.len, DMA_TO_DEVICE);
+ dma_sync_single_for_device(sq->pdev, dma_addr, xdptxd.len, DMA_BIDIRECTIONAL);
if (unlikely(xdp_frame_has_frags(xdpf))) {
sinfo = xdp_get_shared_info_from_frame(xdpf);
@@ -131,7 +131,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
skb_frag_off(frag);
len = skb_frag_size(frag);
dma_sync_single_for_device(sq->pdev, addr, len,
- DMA_TO_DEVICE);
+ DMA_BIDIRECTIONAL);
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
index 285d32d2fd08..d7c020f72401 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
@@ -365,7 +365,7 @@ void mlx5e_accel_fs_tcp_destroy(struct mlx5e_flow_steering *fs)
for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++)
accel_fs_tcp_destroy_table(fs, i);
- kfree(accel_tcp);
+ kvfree(accel_tcp);
mlx5e_fs_set_accel_tcp(fs, NULL);
}
@@ -397,7 +397,7 @@ int mlx5e_accel_fs_tcp_create(struct mlx5e_flow_steering *fs)
err_destroy_tables:
while (--i >= 0)
accel_fs_tcp_destroy_table(fs, i);
- kfree(accel_tcp);
+ kvfree(accel_tcp);
mlx5e_fs_set_accel_tcp(fs, NULL);
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index 2ef36cb9555a..f900709639f6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -368,15 +368,15 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
obj_attrs.aso_pdn = macsec->aso.pdn;
obj_attrs.epn_state = sa->epn_state;
- if (is_tx) {
- obj_attrs.ssci = cpu_to_be32((__force u32)ctx->sa.tx_sa->ssci);
- key = &ctx->sa.tx_sa->key;
- } else {
- obj_attrs.ssci = cpu_to_be32((__force u32)ctx->sa.rx_sa->ssci);
- key = &ctx->sa.rx_sa->key;
+ key = (is_tx) ? &ctx->sa.tx_sa->key : &ctx->sa.rx_sa->key;
+
+ if (sa->epn_state.epn_enabled) {
+ obj_attrs.ssci = (is_tx) ? cpu_to_be32((__force u32)ctx->sa.tx_sa->ssci) :
+ cpu_to_be32((__force u32)ctx->sa.rx_sa->ssci);
+
+ memcpy(&obj_attrs.salt, &key->salt, sizeof(key->salt));
}
- memcpy(&obj_attrs.salt, &key->salt, sizeof(key->salt));
obj_attrs.replay_window = ctx->secy->replay_window;
obj_attrs.replay_protect = ctx->secy->replay_protect;
@@ -427,15 +427,15 @@ mlx5e_macsec_get_rx_sc_from_sc_list(const struct list_head *list, sci_t sci)
return NULL;
}
-static int mlx5e_macsec_update_rx_sa(struct mlx5e_macsec *macsec,
- struct mlx5e_macsec_sa *rx_sa,
- bool active)
+static int macsec_rx_sa_active_update(struct macsec_context *ctx,
+ struct mlx5e_macsec_sa *rx_sa,
+ bool active)
{
- struct mlx5_core_dev *mdev = macsec->mdev;
- struct mlx5_macsec_obj_attrs attrs = {};
+ struct mlx5e_priv *priv = netdev_priv(ctx->netdev);
+ struct mlx5e_macsec *macsec = priv->macsec;
int err = 0;
- if (rx_sa->active != active)
+ if (rx_sa->active == active)
return 0;
rx_sa->active = active;
@@ -444,13 +444,11 @@ static int mlx5e_macsec_update_rx_sa(struct mlx5e_macsec *macsec,
return 0;
}
- attrs.sci = cpu_to_be64((__force u64)rx_sa->sci);
- attrs.enc_key_id = rx_sa->enc_key_id;
- err = mlx5e_macsec_create_object(mdev, &attrs, false, &rx_sa->macsec_obj_id);
+ err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false);
if (err)
- return err;
+ rx_sa->active = false;
- return 0;
+ return err;
}
static bool mlx5e_macsec_secy_features_validate(struct macsec_context *ctx)
@@ -476,6 +474,11 @@ static bool mlx5e_macsec_secy_features_validate(struct macsec_context *ctx)
return false;
}
+ if (!ctx->secy->tx_sc.encrypt) {
+ netdev_err(netdev, "MACsec offload: encrypt off isn't supported\n");
+ return false;
+ }
+
return true;
}
@@ -620,6 +623,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
if (tx_sa->active == ctx_tx_sa->active)
goto out;
+ tx_sa->active = ctx_tx_sa->active;
if (tx_sa->assoc_num != tx_sc->encoding_sa)
goto out;
@@ -635,8 +639,6 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
mlx5e_macsec_cleanup_sa(macsec, tx_sa, true);
}
-
- tx_sa->active = ctx_tx_sa->active;
out:
mutex_unlock(&macsec->lock);
@@ -736,9 +738,14 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
sc_xarray_element->rx_sc = rx_sc;
err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element,
- XA_LIMIT(1, USHRT_MAX), GFP_KERNEL);
- if (err)
+ XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);
+ if (err) {
+ if (err == -EBUSY)
+ netdev_err(ctx->netdev,
+ "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n",
+ MLX5_MACEC_RX_FS_ID_MAX);
goto destroy_sc_xarray_elemenet;
+ }
rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
if (!rx_sc->md_dst) {
@@ -798,16 +805,16 @@ static int mlx5e_macsec_upd_rxsc(struct macsec_context *ctx)
goto out;
}
- rx_sc->active = ctx_rx_sc->active;
if (rx_sc->active == ctx_rx_sc->active)
goto out;
+ rx_sc->active = ctx_rx_sc->active;
for (i = 0; i < MACSEC_NUM_AN; ++i) {
rx_sa = rx_sc->rx_sa[i];
if (!rx_sa)
continue;
- err = mlx5e_macsec_update_rx_sa(macsec, rx_sa, rx_sa->active && ctx_rx_sc->active);
+ err = macsec_rx_sa_active_update(ctx, rx_sa, rx_sa->active && ctx_rx_sc->active);
if (err)
goto out;
}
@@ -818,16 +825,43 @@ out:
return err;
}
+static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec_rx_sc *rx_sc)
+{
+ struct mlx5e_macsec_sa *rx_sa;
+ int i;
+
+ for (i = 0; i < MACSEC_NUM_AN; ++i) {
+ rx_sa = rx_sc->rx_sa[i];
+ if (!rx_sa)
+ continue;
+
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
+ mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
+
+ kfree(rx_sa);
+ rx_sc->rx_sa[i] = NULL;
+ }
+
+ /* At this point the relevant MACsec offload Rx rule already removed at
+ * mlx5e_macsec_cleanup_sa need to wait for datapath to finish current
+ * Rx related data propagating using xa_erase which uses rcu to sync,
+ * once fs_id is erased then this rx_sc is hidden from datapath.
+ */
+ list_del_rcu(&rx_sc->rx_sc_list_element);
+ xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id);
+ metadata_dst_free(rx_sc->md_dst);
+ kfree(rx_sc->sc_xarray_element);
+ kfree_rcu(rx_sc);
+}
+
static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx)
{
struct mlx5e_priv *priv = netdev_priv(ctx->netdev);
struct mlx5e_macsec_device *macsec_device;
struct mlx5e_macsec_rx_sc *rx_sc;
- struct mlx5e_macsec_sa *rx_sa;
struct mlx5e_macsec *macsec;
struct list_head *list;
int err = 0;
- int i;
mutex_lock(&priv->macsec->lock);
@@ -849,31 +883,7 @@ static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx)
goto out;
}
- for (i = 0; i < MACSEC_NUM_AN; ++i) {
- rx_sa = rx_sc->rx_sa[i];
- if (!rx_sa)
- continue;
-
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
- mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
-
- kfree(rx_sa);
- rx_sc->rx_sa[i] = NULL;
- }
-
-/*
- * At this point the relevant MACsec offload Rx rule already removed at
- * mlx5e_macsec_cleanup_sa need to wait for datapath to finish current
- * Rx related data propagating using xa_erase which uses rcu to sync,
- * once fs_id is erased then this rx_sc is hidden from datapath.
- */
- list_del_rcu(&rx_sc->rx_sc_list_element);
- xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id);
- metadata_dst_free(rx_sc->md_dst);
- kfree(rx_sc->sc_xarray_element);
-
- kfree_rcu(rx_sc);
-
+ macsec_del_rxsc_ctx(macsec, rx_sc);
out:
mutex_unlock(&macsec->lock);
@@ -1015,7 +1025,7 @@ static int mlx5e_macsec_upd_rxsa(struct macsec_context *ctx)
goto out;
}
- err = mlx5e_macsec_update_rx_sa(macsec, rx_sa, ctx_rx_sa->active);
+ err = macsec_rx_sa_active_update(ctx, rx_sa, ctx_rx_sa->active);
out:
mutex_unlock(&macsec->lock);
@@ -1155,7 +1165,7 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
continue;
if (rx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, rx_sa, false, false);
+ err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false);
if (err)
goto out;
}
@@ -1234,7 +1244,6 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
struct mlx5e_priv *priv = netdev_priv(ctx->netdev);
struct mlx5e_macsec_device *macsec_device;
struct mlx5e_macsec_rx_sc *rx_sc, *tmp;
- struct mlx5e_macsec_sa *rx_sa;
struct mlx5e_macsec_sa *tx_sa;
struct mlx5e_macsec *macsec;
struct list_head *list;
@@ -1263,28 +1272,15 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
}
list = &macsec_device->macsec_rx_sc_list_head;
- list_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element) {
- for (i = 0; i < MACSEC_NUM_AN; ++i) {
- rx_sa = rx_sc->rx_sa[i];
- if (!rx_sa)
- continue;
-
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
- mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
- kfree(rx_sa);
- rx_sc->rx_sa[i] = NULL;
- }
-
- list_del_rcu(&rx_sc->rx_sc_list_element);
-
- kfree_rcu(rx_sc);
- }
+ list_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element)
+ macsec_del_rxsc_ctx(macsec, rx_sc);
kfree(macsec_device->dev_addr);
macsec_device->dev_addr = NULL;
list_del_rcu(&macsec_device->macsec_device_list_element);
--macsec->num_of_devices;
+ kfree(macsec_device);
out:
mutex_unlock(&macsec->lock);
@@ -1536,6 +1532,8 @@ static void macsec_async_event(struct work_struct *work)
async_work = container_of(work, struct mlx5e_macsec_async_work, work);
macsec = async_work->macsec;
+ mutex_lock(&macsec->lock);
+
mdev = async_work->mdev;
obj_id = async_work->obj_id;
macsec_sa = get_macsec_tx_sa_from_obj_id(macsec, obj_id);
@@ -1557,6 +1555,7 @@ static void macsec_async_event(struct work_struct *work)
out_async_work:
kfree(async_work);
+ mutex_unlock(&macsec->lock);
}
static int macsec_obj_change_event(struct notifier_block *nb, unsigned long event, void *data)
@@ -1745,7 +1744,7 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,
if (!macsec)
return;
- fs_id = MLX5_MACSEC_METADATA_HANDLE(macsec_meta_data);
+ fs_id = MLX5_MACSEC_RX_METADAT_HANDLE(macsec_meta_data);
rcu_read_lock();
sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
index d580b4a91253..347380a2cd9c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
@@ -10,9 +10,11 @@
#include <net/macsec.h>
#include <net/dst_metadata.h>
-/* Bit31 - 30: MACsec marker, Bit3-0: MACsec id */
+/* Bit31 - 30: MACsec marker, Bit15-0: MACsec id */
+#define MLX5_MACEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */
+#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACEC_RX_FS_ID_MAX
#define MLX5_MACSEC_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x1)
-#define MLX5_MACSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(3, 0))
+#define MLX5_MACSEC_RX_METADAT_HANDLE(metadata) ((metadata) & MLX5_MACSEC_RX_FS_ID_MASK)
struct mlx5e_priv;
struct mlx5e_macsec;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c
index 1ac0cf04e811..5b658a5588c6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c
@@ -250,7 +250,7 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs)
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
u32 *flow_group_in;
- int err = 0;
+ int err;
ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_EGRESS_MACSEC);
if (!ns)
@@ -261,8 +261,10 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs)
return -ENOMEM;
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
- if (!flow_group_in)
+ if (!flow_group_in) {
+ err = -ENOMEM;
goto out_spec;
+ }
tx_tables = &tx_fs->tables;
ft_crypto = &tx_tables->ft_crypto;
@@ -898,7 +900,7 @@ static int macsec_fs_rx_create(struct mlx5e_macsec_fs *macsec_fs)
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
u32 *flow_group_in;
- int err = 0;
+ int err;
ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
if (!ns)
@@ -909,8 +911,10 @@ static int macsec_fs_rx_create(struct mlx5e_macsec_fs *macsec_fs)
return -ENOMEM;
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
- if (!flow_group_in)
+ if (!flow_group_in) {
+ err = -ENOMEM;
goto free_spec;
+ }
rx_tables = &rx_fs->tables;
ft_crypto = &rx_tables->ft_crypto;
@@ -1142,10 +1146,10 @@ macsec_fs_rx_add_rule(struct mlx5e_macsec_fs *macsec_fs,
ft_crypto = &rx_tables->ft_crypto;
/* Set bit[31 - 30] macsec marker - 0x01 */
- /* Set bit[3-0] fs id */
+ /* Set bit[15-0] fs id */
MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
- MLX5_SET(set_action_in, action, data, fs_id | BIT(30));
+ MLX5_SET(set_action_in, action, data, MLX5_MACSEC_RX_METADAT_HANDLE(fs_id) | BIT(30));
MLX5_SET(set_action_in, action, offset, 0);
MLX5_SET(set_action_in, action, length, 32);
@@ -1205,6 +1209,7 @@ macsec_fs_rx_add_rule(struct mlx5e_macsec_fs *macsec_fs,
rx_rule->rule[1] = rule;
}
+ kvfree(spec);
return macsec_rule;
err:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 24aa25da482b..1728e197558d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -35,7 +35,6 @@
#include "en.h"
#include "en/port.h"
#include "en/params.h"
-#include "en/xsk/pool.h"
#include "en/ptp.h"
#include "lib/clock.h"
#include "en/fs_ethtool.h"
@@ -412,15 +411,8 @@ void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv,
struct ethtool_channels *ch)
{
mutex_lock(&priv->state_lock);
-
ch->max_combined = priv->max_nch;
ch->combined_count = priv->channels.params.num_channels;
- if (priv->xsk.refcnt) {
- /* The upper half are XSK queues. */
- ch->max_combined *= 2;
- ch->combined_count *= 2;
- }
-
mutex_unlock(&priv->state_lock);
}
@@ -454,16 +446,6 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
mutex_lock(&priv->state_lock);
- /* Don't allow changing the number of channels if there is an active
- * XSK, because the numeration of the XSK and regular RQs will change.
- */
- if (priv->xsk.refcnt) {
- err = -EINVAL;
- netdev_err(priv->netdev, "%s: AF_XDP is active, cannot change the number of channels\n",
- __func__);
- goto out;
- }
-
/* Don't allow changing the number of channels if HTB offload is active,
* because the numeration of the QoS SQs will change, while per-queue
* qdiscs are attached.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 364f04309149..5e41dfdf79c8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -206,10 +206,11 @@ static void mlx5e_disable_blocking_events(struct mlx5e_priv *priv)
static u16 mlx5e_mpwrq_umr_octowords(u32 entries, enum mlx5e_mpwrq_umr_mode umr_mode)
{
u8 umr_entry_size = mlx5e_mpwrq_umr_entry_size(umr_mode);
+ u32 sz;
- WARN_ON_ONCE(entries * umr_entry_size % MLX5_OCTWORD);
+ sz = ALIGN(entries * umr_entry_size, MLX5_UMR_MTT_ALIGNMENT);
- return entries * umr_entry_size / MLX5_OCTWORD;
+ return sz / MLX5_OCTWORD;
}
static inline void mlx5e_build_umr_wqe(struct mlx5e_rq *rq,
@@ -5694,6 +5695,13 @@ int mlx5e_attach_netdev(struct mlx5e_priv *priv)
mlx5e_fs_set_state_destroy(priv->fs,
!test_bit(MLX5E_STATE_DESTROYING, &priv->state));
+ /* Validate the max_wqe_size_sq capability. */
+ if (WARN_ON_ONCE(mlx5e_get_max_sq_wqebbs(priv->mdev) < MLX5E_MAX_TX_WQEBBS)) {
+ mlx5_core_warn(priv->mdev, "MLX5E: Max SQ WQEBBs firmware capability: %u, needed %lu\n",
+ mlx5e_get_max_sq_wqebbs(priv->mdev), MLX5E_MAX_TX_WQEBBS);
+ return -EIO;
+ }
+
/* max number of channels may have changed */
max_nch = mlx5e_calc_max_nch(priv->mdev, priv->netdev, profile);
if (priv->channels.params.num_channels > max_nch) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 58084650151f..a61a43fc8d5c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -266,7 +266,7 @@ static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq, union mlx5e_alloc_uni
addr = page_pool_get_dma_addr(au->page);
/* Non-XSK always uses PAGE_SIZE. */
- dma_sync_single_for_device(rq->pdev, addr, PAGE_SIZE, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(rq->pdev, addr, PAGE_SIZE, rq->buff.map_dir);
return true;
}
@@ -282,8 +282,7 @@ static inline int mlx5e_page_alloc_pool(struct mlx5e_rq *rq, union mlx5e_alloc_u
return -ENOMEM;
/* Non-XSK always uses PAGE_SIZE. */
- addr = dma_map_page_attrs(rq->pdev, au->page, 0, PAGE_SIZE,
- rq->buff.map_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ addr = dma_map_page(rq->pdev, au->page, 0, PAGE_SIZE, rq->buff.map_dir);
if (unlikely(dma_mapping_error(rq->pdev, addr))) {
page_pool_recycle_direct(rq->page_pool, au->page);
au->page = NULL;
@@ -427,14 +426,15 @@ mlx5e_add_skb_frag(struct mlx5e_rq *rq, struct sk_buff *skb,
{
dma_addr_t addr = page_pool_get_dma_addr(au->page);
- dma_sync_single_for_cpu(rq->pdev, addr + frag_offset, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(rq->pdev, addr + frag_offset, len,
+ rq->buff.map_dir);
page_ref_inc(au->page);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
au->page, frag_offset, len, truesize);
}
static inline void
-mlx5e_copy_skb_header(struct device *pdev, struct sk_buff *skb,
+mlx5e_copy_skb_header(struct mlx5e_rq *rq, struct sk_buff *skb,
struct page *page, dma_addr_t addr,
int offset_from, int dma_offset, u32 headlen)
{
@@ -442,7 +442,8 @@ mlx5e_copy_skb_header(struct device *pdev, struct sk_buff *skb,
/* Aligning len to sizeof(long) optimizes memcpy performance */
unsigned int len = ALIGN(headlen, sizeof(long));
- dma_sync_single_for_cpu(pdev, addr + dma_offset, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(rq->pdev, addr + dma_offset, len,
+ rq->buff.map_dir);
skb_copy_to_linear_data(skb, from, len);
}
@@ -1538,7 +1539,7 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,
addr = page_pool_get_dma_addr(au->page);
dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
- frag_size, DMA_FROM_DEVICE);
+ frag_size, rq->buff.map_dir);
net_prefetch(data);
prog = rcu_dereference(rq->xdp_prog);
@@ -1587,7 +1588,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
addr = page_pool_get_dma_addr(au->page);
dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
- rq->buff.frame0_sz, DMA_FROM_DEVICE);
+ rq->buff.frame0_sz, rq->buff.map_dir);
net_prefetchw(va); /* xdp_frame data area */
net_prefetch(va + rx_headroom);
@@ -1608,7 +1609,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
addr = page_pool_get_dma_addr(au->page);
dma_sync_single_for_cpu(rq->pdev, addr + wi->offset,
- frag_consumed_bytes, DMA_FROM_DEVICE);
+ frag_consumed_bytes, rq->buff.map_dir);
if (!xdp_buff_has_frags(&xdp)) {
/* Init on the first fragment to avoid cold cache access
@@ -1905,7 +1906,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
mlx5e_fill_skb_data(skb, rq, au, byte_cnt, frag_offset);
/* copy header */
addr = page_pool_get_dma_addr(head_au->page);
- mlx5e_copy_skb_header(rq->pdev, skb, head_au->page, addr,
+ mlx5e_copy_skb_header(rq, skb, head_au->page, addr,
head_offset, head_offset, headlen);
/* skb linear part was allocated with headlen and aligned to long */
skb->tail += headlen;
@@ -1939,7 +1940,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
addr = page_pool_get_dma_addr(au->page);
dma_sync_single_range_for_cpu(rq->pdev, addr, head_offset,
- frag_size, DMA_FROM_DEVICE);
+ frag_size, rq->buff.map_dir);
net_prefetch(data);
prog = rcu_dereference(rq->xdp_prog);
@@ -1987,7 +1988,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
if (likely(frag_size <= BIT(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE))) {
/* build SKB around header */
- dma_sync_single_range_for_cpu(rq->pdev, head->addr, 0, frag_size, DMA_FROM_DEVICE);
+ dma_sync_single_range_for_cpu(rq->pdev, head->addr, 0, frag_size, rq->buff.map_dir);
prefetchw(hdr);
prefetch(data);
skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size, 0);
@@ -2009,7 +2010,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
}
prefetchw(skb->data);
- mlx5e_copy_skb_header(rq->pdev, skb, head->page, head->addr,
+ mlx5e_copy_skb_header(rq, skb, head->page, head->addr,
head_offset + rx_headroom,
rx_headroom, head_size);
/* skb linear part was allocated with headlen and aligned to long */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index dd6fea9e9a5b..bd9936af4582 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1634,7 +1634,6 @@ set_encap_dests(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
struct mlx5_flow_attr *attr,
struct netlink_ext_ack *extack,
- bool *encap_valid,
bool *vf_tun)
{
struct mlx5e_tc_flow_parse_attr *parse_attr;
@@ -1651,7 +1650,6 @@ set_encap_dests(struct mlx5e_priv *priv,
parse_attr = attr->parse_attr;
esw_attr = attr->esw_attr;
*vf_tun = false;
- *encap_valid = true;
for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
struct net_device *out_dev;
@@ -1668,7 +1666,7 @@ set_encap_dests(struct mlx5e_priv *priv,
goto out;
}
err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index,
- extack, &encap_dev, encap_valid);
+ extack, &encap_dev);
dev_put(out_dev);
if (err)
goto out;
@@ -1732,8 +1730,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5_flow_attr *attr = flow->attr;
struct mlx5_esw_flow_attr *esw_attr;
- bool vf_tun, encap_valid;
u32 max_prio, max_chain;
+ bool vf_tun;
int err = 0;
parse_attr = attr->parse_attr;
@@ -1823,7 +1821,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
esw_attr->int_port = int_port;
}
- err = set_encap_dests(priv, flow, attr, extack, &encap_valid, &vf_tun);
+ err = set_encap_dests(priv, flow, attr, extack, &vf_tun);
if (err)
goto err_out;
@@ -1853,7 +1851,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
* (1) there's no error
* (2) there's an encap action and we don't have valid neigh
*/
- if (!encap_valid || flow_flag_test(flow, SLOW))
+ if (flow_flag_test(flow, SLOW))
flow->rule[0] = mlx5e_tc_offload_to_slow_path(esw, flow, &parse_attr->spec);
else
flow->rule[0] = mlx5e_tc_offload_fdb_rules(esw, flow, &parse_attr->spec, attr);
@@ -3633,10 +3631,14 @@ mlx5e_clone_flow_attr_for_post_act(struct mlx5_flow_attr *attr,
attr2->action = 0;
attr2->flags = 0;
attr2->parse_attr = parse_attr;
- attr2->esw_attr->out_count = 0;
- attr2->esw_attr->split_count = 0;
attr2->dest_chain = 0;
attr2->dest_ft = NULL;
+
+ if (ns_type == MLX5_FLOW_NAMESPACE_FDB) {
+ attr2->esw_attr->out_count = 0;
+ attr2->esw_attr->split_count = 0;
+ }
+
return attr2;
}
@@ -3755,7 +3757,7 @@ alloc_flow_post_acts(struct mlx5e_tc_flow *flow, struct netlink_ext_ack *extack)
struct mlx5e_post_act *post_act = get_post_action(flow->priv);
struct mlx5_flow_attr *attr, *next_attr = NULL;
struct mlx5e_post_act_handle *handle;
- bool vf_tun, encap_valid = true;
+ bool vf_tun;
int err;
/* This is going in reverse order as needed.
@@ -3777,13 +3779,10 @@ alloc_flow_post_acts(struct mlx5e_tc_flow *flow, struct netlink_ext_ack *extack)
if (list_is_last(&attr->list, &flow->attrs))
break;
- err = set_encap_dests(flow->priv, flow, attr, extack, &encap_valid, &vf_tun);
+ err = set_encap_dests(flow->priv, flow, attr, extack, &vf_tun);
if (err)
goto out_free;
- if (!encap_valid)
- flow_flag_set(flow, SLOW);
-
err = actions_prepare_mod_hdr_actions(flow->priv, flow, attr, extack);
if (err)
goto out_free;
@@ -4758,12 +4757,6 @@ int mlx5e_policer_validate(const struct flow_action *action,
return -EOPNOTSUPP;
}
- if (act->police.rate_pkt_ps) {
- NL_SET_ERR_MSG_MOD(extack,
- "QoS offload not support packets per second");
- return -EOPNOTSUPP;
- }
-
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 6adca01fbdc9..f7897ddb29c5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -305,6 +305,8 @@ static void mlx5e_sq_calc_wqe_attr(struct sk_buff *skb, const struct mlx5e_tx_at
u16 ds_cnt_inl = 0;
u16 ds_cnt_ids = 0;
+ /* Sync the calculation with MLX5E_MAX_TX_WQEBBS. */
+
if (attr->insz)
ds_cnt_ids = DIV_ROUND_UP(sizeof(struct mlx5_wqe_inline_seg) + attr->insz,
MLX5_SEND_WQE_DS);
@@ -317,6 +319,9 @@ static void mlx5e_sq_calc_wqe_attr(struct sk_buff *skb, const struct mlx5e_tx_at
inl += VLAN_HLEN;
ds_cnt_inl = DIV_ROUND_UP(inl, MLX5_SEND_WQE_DS);
+ if (WARN_ON_ONCE(ds_cnt_inl > MLX5E_MAX_TX_INLINE_DS))
+ netdev_warn(skb->dev, "ds_cnt_inl = %u > max %u\n", ds_cnt_inl,
+ (u16)MLX5E_MAX_TX_INLINE_DS);
ds_cnt += ds_cnt_inl;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index c59107fa9e6d..374e3fbdc2cf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1362,6 +1362,9 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
devl_rate_nodes_destroy(devlink);
}
+ /* Destroy legacy fdb when disabling sriov in legacy mode. */
+ if (esw->mode == MLX5_ESWITCH_LEGACY)
+ mlx5_eswitch_disable_locked(esw);
esw->esw_funcs.num_vfs = 0;
@@ -1387,12 +1390,14 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->esw_funcs.num_vfs, esw->enabled_vports);
- esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;
- if (esw->mode == MLX5_ESWITCH_OFFLOADS)
- esw_offloads_disable(esw);
- else if (esw->mode == MLX5_ESWITCH_LEGACY)
- esw_legacy_disable(esw);
- mlx5_esw_acls_ns_cleanup(esw);
+ if (esw->fdb_table.flags & MLX5_ESW_FDB_CREATED) {
+ esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS)
+ esw_offloads_disable(esw);
+ else if (esw->mode == MLX5_ESWITCH_LEGACY)
+ esw_legacy_disable(esw);
+ mlx5_esw_acls_ns_cleanup(esw);
+ }
if (esw->mode == MLX5_ESWITCH_OFFLOADS)
devl_rate_nodes_destroy(devlink);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index f68dc2d0dbe6..3029bc1c0dd0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -736,6 +736,14 @@ void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw,
struct mlx5_eswitch *slave_esw);
int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
+static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
+{
+ if (mlx5_esw_allowed(esw))
+ return esw->esw_funcs.num_vfs;
+
+ return 0;
+}
+
#else /* CONFIG_MLX5_ESWITCH */
/* eswitch API stubs */
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 4e50df3139c6..8c6c9bcb3dc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -433,7 +433,7 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
mlx5_lag_mpesw_is_activated(esw->dev))
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
}
- if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP) {
+ if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {
if (pkt_reformat) {
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
@@ -2310,7 +2310,7 @@ out_free:
static int esw_offloads_start(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
- int err, err1;
+ int err;
esw->mode = MLX5_ESWITCH_OFFLOADS;
err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
@@ -2318,11 +2318,6 @@ static int esw_offloads_start(struct mlx5_eswitch *esw,
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch to offloads");
esw->mode = MLX5_ESWITCH_LEGACY;
- err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
- if (err1) {
- NL_SET_ERR_MSG_MOD(extack,
- "Failed setting eswitch back to legacy");
- }
mlx5_rescan_drivers(esw->dev);
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
@@ -3389,19 +3384,19 @@ err_metadata:
static int esw_offloads_stop(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
- int err, err1;
+ int err;
esw->mode = MLX5_ESWITCH_LEGACY;
+
+ /* If changing from switchdev to legacy mode without sriov enabled,
+ * no need to create legacy fdb.
+ */
+ if (!mlx5_sriov_is_enabled(esw->dev))
+ return 0;
+
err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
- if (err) {
+ if (err)
NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
- esw->mode = MLX5_ESWITCH_OFFLOADS;
- err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
- if (err1) {
- NL_SET_ERR_MSG_MOD(extack,
- "Failed setting eswitch back to offloads");
- }
- }
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
index ee568bf34ae2..edd910258314 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
@@ -30,9 +30,9 @@ mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
sizeof(dest->vport.num), hash);
hash = jhash((const void *)&dest->vport.vhca_id,
sizeof(dest->vport.num), hash);
- if (dest->vport.pkt_reformat)
- hash = jhash(dest->vport.pkt_reformat,
- sizeof(*dest->vport.pkt_reformat),
+ if (flow_act->pkt_reformat)
+ hash = jhash(flow_act->pkt_reformat,
+ sizeof(*flow_act->pkt_reformat),
hash);
return hash;
}
@@ -53,9 +53,11 @@ mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
if (ret)
return ret;
- return dest1->vport.pkt_reformat && dest2->vport.pkt_reformat ?
- memcmp(dest1->vport.pkt_reformat, dest2->vport.pkt_reformat,
- sizeof(*dest1->vport.pkt_reformat)) : 0;
+ if (flow_act1->pkt_reformat && flow_act2->pkt_reformat)
+ return memcmp(flow_act1->pkt_reformat, flow_act2->pkt_reformat,
+ sizeof(*flow_act1->pkt_reformat));
+
+ return !(flow_act1->pkt_reformat == flow_act2->pkt_reformat);
}
static int
@@ -310,6 +312,8 @@ revert_changes:
for (curr_dest = 0; curr_dest < num_vport_dests; curr_dest++) {
struct mlx5_termtbl_handle *tt = attr->dests[curr_dest].termtbl;
+ attr->dests[curr_dest].termtbl = NULL;
+
/* search for the destination associated with the
* current term table
*/
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
index 07c583996c29..1e46f9afa40e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
@@ -9,7 +9,8 @@ enum {
MLX5_FW_RESET_FLAGS_RESET_REQUESTED,
MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST,
MLX5_FW_RESET_FLAGS_PENDING_COMP,
- MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS
+ MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS,
+ MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED
};
struct mlx5_fw_reset {
@@ -152,7 +153,8 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev)
mlx5_unload_one(dev);
if (mlx5_health_wait_pci_up(dev))
mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n");
- mlx5_load_one(dev, false);
+ else
+ mlx5_load_one(dev, false);
devlink_remote_reload_actions_performed(priv_to_devlink(dev), 0,
BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE));
@@ -405,7 +407,7 @@ static void mlx5_sync_reset_now_event(struct work_struct *work)
err = mlx5_pci_link_toggle(dev);
if (err) {
mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, no reset done, err %d\n", err);
- goto done;
+ set_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags);
}
mlx5_enter_error_state(dev, true);
@@ -481,6 +483,10 @@ int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev)
goto out;
}
err = fw_reset->ret;
+ if (test_and_clear_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags)) {
+ mlx5_unload_one_devl_locked(dev);
+ mlx5_load_one_devl_locked(dev, false);
+ }
out:
clear_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index a9f4ede4a9bf..32c3e0a649a7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -228,9 +228,8 @@ static void mlx5_ldev_free(struct kref *ref)
if (ldev->nb.notifier_call)
unregister_netdevice_notifier_net(&init_net, &ldev->nb);
mlx5_lag_mp_cleanup(ldev);
- mlx5_lag_mpesw_cleanup(ldev);
- cancel_work_sync(&ldev->mpesw_work);
destroy_workqueue(ldev->wq);
+ mlx5_lag_mpesw_cleanup(ldev);
mutex_destroy(&ldev->lock);
kfree(ldev);
}
@@ -701,10 +700,13 @@ static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
return false;
#ifdef CONFIG_MLX5_ESWITCH
- dev = ldev->pf[MLX5_LAG_P1].dev;
- if ((mlx5_sriov_is_enabled(dev)) && !is_mdev_switchdev_mode(dev))
- return false;
+ for (i = 0; i < ldev->ports; i++) {
+ dev = ldev->pf[i].dev;
+ if (mlx5_eswitch_num_vfs(dev->priv.eswitch) && !is_mdev_switchdev_mode(dev))
+ return false;
+ }
+ dev = ldev->pf[MLX5_LAG_P1].dev;
mode = mlx5_eswitch_mode(dev);
for (i = 0; i < ldev->ports; i++)
if (mlx5_eswitch_mode(ldev->pf[i].dev) != mode)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index ce2ce8ccbd70..f30ac2de639f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -50,6 +50,19 @@ struct lag_tracker {
enum netdev_lag_hash hash_type;
};
+enum mpesw_op {
+ MLX5_MPESW_OP_ENABLE,
+ MLX5_MPESW_OP_DISABLE,
+};
+
+struct mlx5_mpesw_work_st {
+ struct work_struct work;
+ struct mlx5_lag *lag;
+ enum mpesw_op op;
+ struct completion comp;
+ int result;
+};
+
/* LAG data of a ConnectX card.
* It serves both its phys functions.
*/
@@ -66,7 +79,6 @@ struct mlx5_lag {
struct lag_tracker tracker;
struct workqueue_struct *wq;
struct delayed_work bond_work;
- struct work_struct mpesw_work;
struct notifier_block nb;
struct lag_mp lag_mp;
struct mlx5_lag_port_sel port_sel;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index f643202b29c6..c17e8f1ec914 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -7,63 +7,95 @@
#include "eswitch.h"
#include "lib/mlx5.h"
-void mlx5_mpesw_work(struct work_struct *work)
+static int add_mpesw_rule(struct mlx5_lag *ldev)
{
- struct mlx5_lag *ldev = container_of(work, struct mlx5_lag, mpesw_work);
+ struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
+ int err;
- mutex_lock(&ldev->lock);
- mlx5_disable_lag(ldev);
- mutex_unlock(&ldev->lock);
-}
+ if (atomic_add_return(1, &ldev->lag_mpesw.mpesw_rule_count) != 1)
+ return 0;
-static void mlx5_lag_disable_mpesw(struct mlx5_core_dev *dev)
-{
- struct mlx5_lag *ldev = dev->priv.lag;
+ if (ldev->mode != MLX5_LAG_MODE_NONE) {
+ err = -EINVAL;
+ goto out_err;
+ }
- if (!queue_work(ldev->wq, &ldev->mpesw_work))
- mlx5_core_warn(dev, "failed to queue work\n");
+ err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false);
+ if (err) {
+ mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err);
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ atomic_dec(&ldev->lag_mpesw.mpesw_rule_count);
+ return err;
}
-void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev)
+static void del_mpesw_rule(struct mlx5_lag *ldev)
{
- struct mlx5_lag *ldev = dev->priv.lag;
+ if (!atomic_dec_return(&ldev->lag_mpesw.mpesw_rule_count) &&
+ ldev->mode == MLX5_LAG_MODE_MPESW)
+ mlx5_disable_lag(ldev);
+}
- if (!ldev)
- return;
+static void mlx5_mpesw_work(struct work_struct *work)
+{
+ struct mlx5_mpesw_work_st *mpesww = container_of(work, struct mlx5_mpesw_work_st, work);
+ struct mlx5_lag *ldev = mpesww->lag;
mutex_lock(&ldev->lock);
- if (!atomic_dec_return(&ldev->lag_mpesw.mpesw_rule_count) &&
- ldev->mode == MLX5_LAG_MODE_MPESW)
- mlx5_lag_disable_mpesw(dev);
+ if (mpesww->op == MLX5_MPESW_OP_ENABLE)
+ mpesww->result = add_mpesw_rule(ldev);
+ else if (mpesww->op == MLX5_MPESW_OP_DISABLE)
+ del_mpesw_rule(ldev);
mutex_unlock(&ldev->lock);
+
+ complete(&mpesww->comp);
}
-int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
+static int mlx5_lag_mpesw_queue_work(struct mlx5_core_dev *dev,
+ enum mpesw_op op)
{
struct mlx5_lag *ldev = dev->priv.lag;
+ struct mlx5_mpesw_work_st *work;
int err = 0;
if (!ldev)
return 0;
- mutex_lock(&ldev->lock);
- if (atomic_add_return(1, &ldev->lag_mpesw.mpesw_rule_count) != 1)
- goto out;
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
- if (ldev->mode != MLX5_LAG_MODE_NONE) {
+ INIT_WORK(&work->work, mlx5_mpesw_work);
+ init_completion(&work->comp);
+ work->op = op;
+ work->lag = ldev;
+
+ if (!queue_work(ldev->wq, &work->work)) {
+ mlx5_core_warn(dev, "failed to queue mpesw work\n");
err = -EINVAL;
goto out;
}
-
- err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false);
- if (err)
- mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err);
-
+ wait_for_completion(&work->comp);
+ err = work->result;
out:
- mutex_unlock(&ldev->lock);
+ kfree(work);
return err;
}
+void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev)
+{
+ mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_DISABLE);
+}
+
+int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
+{
+ return mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_ENABLE);
+}
+
int mlx5_lag_do_mirred(struct mlx5_core_dev *mdev, struct net_device *out_dev)
{
struct mlx5_lag *ldev = mdev->priv.lag;
@@ -71,12 +103,9 @@ int mlx5_lag_do_mirred(struct mlx5_core_dev *mdev, struct net_device *out_dev)
if (!netif_is_bond_master(out_dev) || !ldev)
return 0;
- mutex_lock(&ldev->lock);
- if (ldev->mode == MLX5_LAG_MODE_MPESW) {
- mutex_unlock(&ldev->lock);
+ if (ldev->mode == MLX5_LAG_MODE_MPESW)
return -EOPNOTSUPP;
- }
- mutex_unlock(&ldev->lock);
+
return 0;
}
@@ -90,11 +119,10 @@ bool mlx5_lag_mpesw_is_activated(struct mlx5_core_dev *dev)
void mlx5_lag_mpesw_init(struct mlx5_lag *ldev)
{
- INIT_WORK(&ldev->mpesw_work, mlx5_mpesw_work);
atomic_set(&ldev->lag_mpesw.mpesw_rule_count, 0);
}
void mlx5_lag_mpesw_cleanup(struct mlx5_lag *ldev)
{
- cancel_delayed_work_sync(&ldev->bond_work);
+ WARN_ON(atomic_read(&ldev->lag_mpesw.mpesw_rule_count));
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
index be4abcb8fcd5..88e8daffcf92 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
@@ -12,7 +12,6 @@ struct lag_mpesw {
atomic_t mpesw_rule_count;
};
-void mlx5_mpesw_work(struct work_struct *work);
int mlx5_lag_do_mirred(struct mlx5_core_dev *mdev, struct net_device *out_dev);
bool mlx5_lag_mpesw_is_activated(struct mlx5_core_dev *dev);
#if IS_ENABLED(CONFIG_MLX5_ESWITCH)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 283c4cc28944..e58775a7d955 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1798,7 +1798,8 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
res = state == pci_channel_io_perm_failure ?
PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
- mlx5_pci_trace(dev, "Exit, result = %d, %s\n", res, result2str(res));
+ mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Exit, result = %d, %s\n",
+ __func__, dev->state, dev->pci_status, res, result2str(res));
return res;
}
@@ -1837,7 +1838,8 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
int err;
- mlx5_pci_trace(dev, "Enter\n");
+ mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Enter\n",
+ __func__, dev->state, dev->pci_status);
err = mlx5_pci_enable_device(dev);
if (err) {
@@ -1859,7 +1861,8 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
res = PCI_ERS_RESULT_RECOVERED;
out:
- mlx5_pci_trace(dev, "Exit, err = %d, result = %d, %s\n", err, res, result2str(res));
+ mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Exit, err = %d, result = %d, %s\n",
+ __func__, dev->state, dev->pci_status, err, res, result2str(res));
return res;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
index 7da012ff0d41..8e2abbab05f0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
@@ -18,6 +18,10 @@ struct mlx5_sf_dev_table {
phys_addr_t base_address;
u64 sf_bar_length;
struct notifier_block nb;
+ struct mutex table_lock; /* Serializes sf life cycle and vhca state change handler */
+ struct workqueue_struct *active_wq;
+ struct work_struct work;
+ u8 stop_active_wq:1;
struct mlx5_core_dev *dev;
};
@@ -168,6 +172,7 @@ mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_
return 0;
sf_index = event->function_id - base_id;
+ mutex_lock(&table->table_lock);
sf_dev = xa_load(&table->devices, sf_index);
switch (event->new_vhca_state) {
case MLX5_VHCA_STATE_INVALID:
@@ -191,6 +196,7 @@ mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_
default:
break;
}
+ mutex_unlock(&table->table_lock);
return 0;
}
@@ -215,6 +221,78 @@ static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table)
return 0;
}
+static void mlx5_sf_dev_add_active_work(struct work_struct *work)
+{
+ struct mlx5_sf_dev_table *table = container_of(work, struct mlx5_sf_dev_table, work);
+ u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {};
+ struct mlx5_core_dev *dev = table->dev;
+ u16 max_functions;
+ u16 function_id;
+ u16 sw_func_id;
+ int err = 0;
+ u8 state;
+ int i;
+
+ max_functions = mlx5_sf_max_functions(dev);
+ function_id = MLX5_CAP_GEN(dev, sf_base_id);
+ for (i = 0; i < max_functions; i++, function_id++) {
+ if (table->stop_active_wq)
+ return;
+ err = mlx5_cmd_query_vhca_state(dev, function_id, out, sizeof(out));
+ if (err)
+ /* A failure of specific vhca doesn't mean others will
+ * fail as well.
+ */
+ continue;
+ state = MLX5_GET(query_vhca_state_out, out, vhca_state_context.vhca_state);
+ if (state != MLX5_VHCA_STATE_ACTIVE)
+ continue;
+
+ sw_func_id = MLX5_GET(query_vhca_state_out, out, vhca_state_context.sw_function_id);
+ mutex_lock(&table->table_lock);
+ /* Don't probe device which is already probe */
+ if (!xa_load(&table->devices, i))
+ mlx5_sf_dev_add(dev, i, function_id, sw_func_id);
+ /* There is a race where SF got inactive after the query
+ * above. e.g.: the query returns that the state of the
+ * SF is active, and after that the eswitch manager set it to
+ * inactive.
+ * This case cannot be managed in SW, since the probing of the
+ * SF is on one system, and the inactivation is on a different
+ * system.
+ * If the inactive is done after the SF perform init_hca(),
+ * the SF will fully probe and then removed. If it was
+ * done before init_hca(), the SF probe will fail.
+ */
+ mutex_unlock(&table->table_lock);
+ }
+}
+
+/* In case SFs are generated externally, probe active SFs */
+static int mlx5_sf_dev_queue_active_work(struct mlx5_sf_dev_table *table)
+{
+ if (MLX5_CAP_GEN(table->dev, eswitch_manager))
+ return 0; /* the table is local */
+
+ /* Use a workqueue to probe active SFs, which are in large
+ * quantity and may take up to minutes to probe.
+ */
+ table->active_wq = create_singlethread_workqueue("mlx5_active_sf");
+ if (!table->active_wq)
+ return -ENOMEM;
+ INIT_WORK(&table->work, &mlx5_sf_dev_add_active_work);
+ queue_work(table->active_wq, &table->work);
+ return 0;
+}
+
+static void mlx5_sf_dev_destroy_active_work(struct mlx5_sf_dev_table *table)
+{
+ if (table->active_wq) {
+ table->stop_active_wq = true;
+ destroy_workqueue(table->active_wq);
+ }
+}
+
void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
{
struct mlx5_sf_dev_table *table;
@@ -240,11 +318,17 @@ void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
table->base_address = pci_resource_start(dev->pdev, 2);
table->max_sfs = max_sfs;
xa_init(&table->devices);
+ mutex_init(&table->table_lock);
dev->priv.sf_dev_table = table;
err = mlx5_vhca_event_notifier_register(dev, &table->nb);
if (err)
goto vhca_err;
+
+ err = mlx5_sf_dev_queue_active_work(table);
+ if (err)
+ goto add_active_err;
+
err = mlx5_sf_dev_vhca_arm_all(table);
if (err)
goto arm_err;
@@ -252,6 +336,8 @@ void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
return;
arm_err:
+ mlx5_sf_dev_destroy_active_work(table);
+add_active_err:
mlx5_vhca_event_notifier_unregister(dev, &table->nb);
vhca_err:
table->max_sfs = 0;
@@ -279,7 +365,9 @@ void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev)
if (!table)
return;
+ mlx5_sf_dev_destroy_active_work(table);
mlx5_vhca_event_notifier_unregister(dev, &table->nb);
+ mutex_destroy(&table->table_lock);
/* Now that event handler is not running, it is safe to destroy
* the sf device without race.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
index 31d443dd8386..f68461b13391 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
@@ -46,7 +46,7 @@ static int dr_table_set_miss_action_nic(struct mlx5dr_domain *dmn,
int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
struct mlx5dr_action *action)
{
- int ret;
+ int ret = -EOPNOTSUPP;
if (action && action->action_type != DR_ACTION_TYP_FT)
return -EOPNOTSUPP;
@@ -67,6 +67,9 @@ int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
goto out;
}
+ if (ret)
+ goto out;
+
/* Release old action */
if (tbl->miss_action)
refcount_dec(&tbl->miss_action->refcount);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 4efccd942fb8..1290b2d3eae6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -3470,6 +3470,8 @@ mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,
u16 vid;
vxlan_fdb_info = &switchdev_work->vxlan_fdb_info;
+ if (!vxlan_fdb_info->offloaded)
+ return;
bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
if (!bridge_device)
diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c
index 81a8ccca7e5e..5693784eec5b 100644
--- a/drivers/net/ethernet/microchip/encx24j600-regmap.c
+++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c
@@ -359,7 +359,7 @@ static int regmap_encx24j600_phy_reg_read(void *context, unsigned int reg,
goto err_out;
usleep_range(26, 100);
- while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
+ while (((ret = regmap_read(ctx->regmap, MISTAT, &mistat)) == 0) &&
(mistat & BUSY))
cpu_relax();
@@ -397,7 +397,7 @@ static int regmap_encx24j600_phy_reg_write(void *context, unsigned int reg,
goto err_out;
usleep_range(26, 100);
- while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
+ while (((ret = regmap_read(ctx->regmap, MISTAT, &mistat)) == 0) &&
(mistat & BUSY))
cpu_relax();
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
index fea42542be28..06811c60d598 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
@@ -716,6 +716,9 @@ int lan966x_stats_init(struct lan966x *lan966x)
snprintf(queue_name, sizeof(queue_name), "%s-stats",
dev_name(lan966x->dev));
lan966x->stats_queue = create_singlethread_workqueue(queue_name);
+ if (!lan966x->stats_queue)
+ return -ENOMEM;
+
INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work);
queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
LAN966X_STATS_CHECK_DELAY);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
index 6b0febcb7fa9..01f3a3a41cdb 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
@@ -1253,6 +1253,9 @@ int sparx_stats_init(struct sparx5 *sparx5)
snprintf(queue_name, sizeof(queue_name), "%s-stats",
dev_name(sparx5->dev));
sparx5->stats_queue = create_singlethread_workqueue(queue_name);
+ if (!sparx5->stats_queue)
+ return -ENOMEM;
+
INIT_DELAYED_WORK(&sparx5->stats_work, sparx5_check_stats_work);
queue_delayed_work(sparx5->stats_queue, &sparx5->stats_work,
SPX5_STATS_CHECK_DELAY);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
index 66360c8c5a38..141897dfe388 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
@@ -317,7 +317,7 @@ int sparx5_fdma_xmit(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb)
next_dcb_hw = sparx5_fdma_next_dcb(tx, tx->curr_entry);
db_hw = &next_dcb_hw->db[0];
if (!(db_hw->status & FDMA_DCB_STATUS_DONE))
- tx->dropped++;
+ return -EINVAL;
db = list_first_entry(&tx->db_list, struct sparx5_db, list);
list_move_tail(&db->list, &tx->db_list);
next_dcb_hw->nextptr = FDMA_DCB_INVALID_DATA;
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
index 62a325e96345..b6bbb3c9bd7a 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -659,6 +659,9 @@ static int sparx5_start(struct sparx5 *sparx5)
snprintf(queue_name, sizeof(queue_name), "%s-mact",
dev_name(sparx5->dev));
sparx5->mact_queue = create_singlethread_workqueue(queue_name);
+ if (!sparx5->mact_queue)
+ return -ENOMEM;
+
INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work);
queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work,
SPX5_MACT_PULL_DELAY);
@@ -884,6 +887,8 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
cleanup_ports:
sparx5_cleanup_ports(sparx5);
+ if (sparx5->mact_queue)
+ destroy_workqueue(sparx5->mact_queue);
cleanup_config:
kfree(configs);
cleanup_pnode:
@@ -908,6 +913,7 @@ static int mchp_sparx5_remove(struct platform_device *pdev)
sparx5_cleanup_ports(sparx5);
/* Unregister netdevs */
sparx5_unregister_notifier_blocks(sparx5);
+ destroy_workqueue(sparx5->mact_queue);
return 0;
}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
index 19516ccad533..d078156581d5 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -104,7 +104,7 @@ static int sparx5_port_open(struct net_device *ndev)
err = phylink_of_phy_connect(port->phylink, port->of_node, 0);
if (err) {
netdev_err(ndev, "Could not attach to PHY\n");
- return err;
+ goto err_connect;
}
phylink_start(port->phylink);
@@ -116,10 +116,20 @@ static int sparx5_port_open(struct net_device *ndev)
err = sparx5_serdes_set(port->sparx5, port, &port->conf);
else
err = phy_power_on(port->serdes);
- if (err)
+ if (err) {
netdev_err(ndev, "%s failed\n", __func__);
+ goto out_power;
+ }
}
+ return 0;
+
+out_power:
+ phylink_stop(port->phylink);
+ phylink_disconnect_phy(port->phylink);
+err_connect:
+ sparx5_port_enable(port, false);
+
return err;
}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
index 83c16ca5b30f..6db6ac6a3bbc 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
@@ -234,9 +234,8 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
sparx5_set_port_ifh(ifh, port->portno);
if (sparx5->ptp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
- ret = sparx5_ptp_txtstamp_request(port, skb);
- if (ret)
- return ret;
+ if (sparx5_ptp_txtstamp_request(port, skb) < 0)
+ return NETDEV_TX_BUSY;
sparx5_set_port_ifh_rew_op(ifh, SPARX5_SKB_CB(skb)->rew_op);
sparx5_set_port_ifh_pdu_type(ifh, SPARX5_SKB_CB(skb)->pdu_type);
@@ -250,23 +249,31 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
else
ret = sparx5_inject(sparx5, ifh, skb, dev);
- if (ret == NETDEV_TX_OK) {
- stats->tx_bytes += skb->len;
- stats->tx_packets++;
+ if (ret == -EBUSY)
+ goto busy;
+ if (ret < 0)
+ goto drop;
- if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
- SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
- return ret;
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ sparx5->tx.packets++;
- dev_kfree_skb_any(skb);
- } else {
- stats->tx_dropped++;
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
+ return NETDEV_TX_OK;
- if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
- SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
- sparx5_ptp_txtstamp_release(port, skb);
- }
- return ret;
+ dev_consume_skb_any(skb);
+ return NETDEV_TX_OK;
+drop:
+ stats->tx_dropped++;
+ sparx5->tx.dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+busy:
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
+ sparx5_ptp_txtstamp_release(port, skb);
+ return NETDEV_TX_BUSY;
}
static enum hrtimer_restart sparx5_injection_timeout(struct hrtimer *tmr)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c
index e05429c751ee..dc2c3756e3a2 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c
@@ -90,13 +90,10 @@ static int sparx5_tc_setup_qdisc_ets(struct net_device *ndev,
}
}
- sparx5_tc_ets_add(port, params);
- break;
+ return sparx5_tc_ets_add(port, params);
case TC_ETS_DESTROY:
- sparx5_tc_ets_del(port);
-
- break;
+ return sparx5_tc_ets_del(port);
case TC_ETS_GRAFT:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/microsoft/mana/gdma.h b/drivers/net/ethernet/microsoft/mana/gdma.h
index 4a6efe6ada08..65c24ee49efd 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma.h
+++ b/drivers/net/ethernet/microsoft/mana/gdma.h
@@ -498,7 +498,14 @@ enum {
#define GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT BIT(0)
-#define GDMA_DRV_CAP_FLAGS1 GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT
+/* Advertise to the NIC firmware: the NAPI work_done variable race is fixed,
+ * so the driver is able to reliably support features like busy_poll.
+ */
+#define GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX BIT(2)
+
+#define GDMA_DRV_CAP_FLAGS1 \
+ (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
+ GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX)
#define GDMA_DRV_CAP_FLAGS2 0
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 9259a74eca40..27a0f3af8aab 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1303,10 +1303,11 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
xdp_do_flush();
}
-static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
+static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
{
struct mana_cq *cq = context;
u8 arm_bit;
+ int w;
WARN_ON_ONCE(cq->gdma_cq != gdma_queue);
@@ -1315,26 +1316,31 @@ static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
else
mana_poll_tx_cq(cq);
- if (cq->work_done < cq->budget &&
- napi_complete_done(&cq->napi, cq->work_done)) {
+ w = cq->work_done;
+
+ if (w < cq->budget &&
+ napi_complete_done(&cq->napi, w)) {
arm_bit = SET_ARM_BIT;
} else {
arm_bit = 0;
}
mana_gd_ring_cq(gdma_queue, arm_bit);
+
+ return w;
}
static int mana_poll(struct napi_struct *napi, int budget)
{
struct mana_cq *cq = container_of(napi, struct mana_cq, napi);
+ int w;
cq->work_done = 0;
cq->budget = budget;
- mana_cq_handler(cq, cq->gdma_cq);
+ w = mana_cq_handler(cq, cq->gdma_cq);
- return min(cq->work_done, budget);
+ return min(w, budget);
}
static void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue)
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index dcf8212119f9..1d3c4474b7cb 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -7128,9 +7128,8 @@ static int s2io_card_up(struct s2io_nic *sp)
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
- s2io_reset(sp);
- free_rx_buffers(sp);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_fill_buff;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
ring->rx_bufs_left);
@@ -7168,18 +7167,16 @@ static int s2io_card_up(struct s2io_nic *sp)
/* Enable Rx Traffic and interrupts on the NIC */
if (start_nic(sp)) {
DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
- s2io_reset(sp);
- free_rx_buffers(sp);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_out;
}
/* Add interrupt service routine */
if (s2io_add_isr(sp) != 0) {
if (sp->config.intr_type == MSI_X)
s2io_rem_isr(sp);
- s2io_reset(sp);
- free_rx_buffers(sp);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_out;
}
timer_setup(&sp->alarm_timer, s2io_alarm_handle, 0);
@@ -7199,6 +7196,20 @@ static int s2io_card_up(struct s2io_nic *sp)
}
return 0;
+
+err_out:
+ if (config->napi) {
+ if (config->intr_type == MSI_X) {
+ for (i = 0; i < sp->config.rx_ring_num; i++)
+ napi_disable(&sp->mac_control.rings[i].napi);
+ } else {
+ napi_disable(&sp->napi);
+ }
+ }
+err_fill_buff:
+ s2io_reset(sp);
+ free_rx_buffers(sp);
+ return ret;
}
/**
diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
index 2b427d8ccb2f..ccacb6ab6c39 100644
--- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
@@ -282,7 +282,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
dma_len = skb_headlen(skb);
if (skb_is_gso(skb))
type = NFDK_DESC_TX_TYPE_TSO;
- else if (!nr_frags && dma_len < NFDK_TX_MAX_DATA_PER_HEAD)
+ else if (!nr_frags && dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
type = NFDK_DESC_TX_TYPE_SIMPLE;
else
type = NFDK_DESC_TX_TYPE_GATHER;
@@ -927,7 +927,7 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
dma_len = pkt_len;
dma_addr = rxbuf->dma_addr + dma_off;
- if (dma_len < NFDK_TX_MAX_DATA_PER_HEAD)
+ if (dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
type = NFDK_DESC_TX_TYPE_SIMPLE;
else
type = NFDK_DESC_TX_TYPE_GATHER;
@@ -1325,7 +1325,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
txbuf = &tx_ring->ktxbufs[wr_idx];
dma_len = skb_headlen(skb);
- if (dma_len < NFDK_TX_MAX_DATA_PER_HEAD)
+ if (dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
type = NFDK_DESC_TX_TYPE_SIMPLE;
else
type = NFDK_DESC_TX_TYPE_GATHER;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 405786c00334..cb08d7bf9524 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -341,7 +341,7 @@ int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
return ret;
attrs.split = eth_port.is_split;
- attrs.splittable = !attrs.split;
+ attrs.splittable = eth_port.port_lanes > 1 && !attrs.split;
attrs.lanes = eth_port.port_lanes;
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
attrs.phys.port_number = eth_port.label_port;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 22a5d2419084..991059d6cb32 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -1432,6 +1432,9 @@ nfp_port_get_module_info(struct net_device *netdev,
u8 data;
port = nfp_port_from_netdev(netdev);
+ if (!port)
+ return -EOPNOTSUPP;
+
/* update port state to get latest interface */
set_bit(NFP_PORT_CHANGED, &port->flags);
eth_port = nfp_port_get_eth_port(port);
@@ -1477,15 +1480,15 @@ nfp_port_get_module_info(struct net_device *netdev,
if (data < 0x3) {
modinfo->type = ETH_MODULE_SFF_8436;
- modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
} else {
modinfo->type = ETH_MODULE_SFF_8636;
- modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
}
break;
case NFP_INTERFACE_QSFP28:
modinfo->type = ETH_MODULE_SFF_8636;
- modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
break;
default:
netdev_err(netdev, "Unsupported module 0x%x detected\n",
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 3db4a2431741..62320be4de5a 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -249,25 +249,26 @@ static void nixge_hw_dma_bd_release(struct net_device *ndev)
struct sk_buff *skb;
int i;
- for (i = 0; i < RX_BD_NUM; i++) {
- phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
- phys);
-
- dma_unmap_single(ndev->dev.parent, phys_addr,
- NIXGE_MAX_JUMBO_FRAME_SIZE,
- DMA_FROM_DEVICE);
-
- skb = (struct sk_buff *)(uintptr_t)
- nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
- sw_id_offset);
- dev_kfree_skb(skb);
- }
+ if (priv->rx_bd_v) {
+ for (i = 0; i < RX_BD_NUM; i++) {
+ phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+ phys);
+
+ dma_unmap_single(ndev->dev.parent, phys_addr,
+ NIXGE_MAX_JUMBO_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+
+ skb = (struct sk_buff *)(uintptr_t)
+ nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+ sw_id_offset);
+ dev_kfree_skb(skb);
+ }
- if (priv->rx_bd_v)
dma_free_coherent(ndev->dev.parent,
sizeof(*priv->rx_bd_v) * RX_BD_NUM,
priv->rx_bd_v,
priv->rx_bd_p);
+ }
if (priv->tx_skb)
devm_kfree(ndev->dev.parent, priv->tx_skb);
@@ -900,6 +901,7 @@ static int nixge_open(struct net_device *ndev)
err_rx_irq:
free_irq(priv->tx_irq, ndev);
err_tx_irq:
+ napi_disable(&priv->napi);
phy_stop(phy);
phy_disconnect(phy);
tasklet_kill(&priv->dma_err_tasklet);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 3f2c30184752..28b7cec485ef 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -1143,6 +1143,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
buffer_info->dma = 0;
buffer_info->time_stamp = 0;
tx_ring->next_to_use = ring_num;
+ dev_kfree_skb_any(skb);
return;
}
buffer_info->mapped = true;
@@ -2459,6 +2460,7 @@ static void pch_gbe_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
pch_gbe_phy_hw_reset(&adapter->hw);
+ pci_dev_put(adapter->ptp_pdev);
free_netdev(netdev);
}
@@ -2533,7 +2535,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
/* setup the private structure */
ret = pch_gbe_sw_init(adapter);
if (ret)
- goto err_free_netdev;
+ goto err_put_dev;
/* Initialize PHY */
ret = pch_gbe_init_phy(adapter);
@@ -2591,6 +2593,8 @@ static int pch_gbe_probe(struct pci_dev *pdev,
err_free_adapter:
pch_gbe_phy_hw_reset(&adapter->hw);
+err_put_dev:
+ pci_dev_put(adapter->ptp_pdev);
err_free_netdev:
free_netdev(netdev);
return ret;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 56f93b030551..5456c2b15d9b 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -687,8 +687,14 @@ int ionic_port_reset(struct ionic *ionic)
static int __init ionic_init_module(void)
{
+ int ret;
+
ionic_debugfs_create();
- return ionic_bus_register_driver();
+ ret = ionic_bus_register_driver();
+ if (ret)
+ ionic_debugfs_destroy();
+
+ return ret;
}
static void __exit ionic_cleanup_module(void)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 9fb1fa479d4b..16e6bd466143 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -767,34 +767,34 @@ static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn,
return rc;
}
-#define CONFIG_QEDE_BITMAP_IDX BIT(0)
-#define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1)
-#define CONFIG_QEDR_BITMAP_IDX BIT(2)
-#define CONFIG_QEDF_BITMAP_IDX BIT(4)
-#define CONFIG_QEDI_BITMAP_IDX BIT(5)
-#define CONFIG_QED_LL2_BITMAP_IDX BIT(6)
+#define BITMAP_IDX_FOR_CONFIG_QEDE BIT(0)
+#define BITMAP_IDX_FOR_CONFIG_QED_SRIOV BIT(1)
+#define BITMAP_IDX_FOR_CONFIG_QEDR BIT(2)
+#define BITMAP_IDX_FOR_CONFIG_QEDF BIT(4)
+#define BITMAP_IDX_FOR_CONFIG_QEDI BIT(5)
+#define BITMAP_IDX_FOR_CONFIG_QED_LL2 BIT(6)
static u32 qed_get_config_bitmap(void)
{
u32 config_bitmap = 0x0;
if (IS_ENABLED(CONFIG_QEDE))
- config_bitmap |= CONFIG_QEDE_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QEDE;
if (IS_ENABLED(CONFIG_QED_SRIOV))
- config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QED_SRIOV;
if (IS_ENABLED(CONFIG_QED_RDMA))
- config_bitmap |= CONFIG_QEDR_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QEDR;
if (IS_ENABLED(CONFIG_QED_FCOE))
- config_bitmap |= CONFIG_QEDF_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QEDF;
if (IS_ENABLED(CONFIG_QED_ISCSI))
- config_bitmap |= CONFIG_QEDI_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QEDI;
if (IS_ENABLED(CONFIG_QED_LL2))
- config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX;
+ config_bitmap |= BITMAP_IDX_FOR_CONFIG_QED_LL2;
return config_bitmap;
}
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 76072f8c3d2f..0d57ffcedf0c 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2471,6 +2471,7 @@ static netdev_tx_t ql3xxx_send(struct sk_buff *skb,
skb_shinfo(skb)->nr_frags);
if (tx_cb->seg_count == -1) {
netdev_err(ndev, "%s: invalid segment count!\n", __func__);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index bd0607680329..2fd5c6fdb500 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -2991,7 +2991,7 @@ static void qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)
QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
dev_info(&adapter->pdev->dev,
"%s: lock recovery initiated\n", __func__);
- msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+ mdelay(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
id = ((val >> 2) & 0xF);
if (id == adapter->portnum) {
@@ -3027,7 +3027,7 @@ int qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)
if (status)
break;
- msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+ mdelay(QLC_83XX_DRV_LOCK_WAIT_DELAY);
i++;
if (i == 1)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 36324126db6d..33f723a9f471 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -841,7 +841,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
napi_gro_receive(&priv->napi[q],
priv->rx_1st_skb);
stats->rx_packets++;
- stats->rx_bytes += priv->rx_1st_skb->len;
+ stats->rx_bytes += pkt_len;
break;
}
}
@@ -3020,6 +3020,7 @@ static int __maybe_unused ravb_resume(struct device *dev)
ret = ravb_open(ndev);
if (ret < 0)
return ret;
+ ravb_set_rx_mode(ndev);
netif_device_attach(ndev);
}
diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
index 88fa29572e23..ddcc325ed570 100644
--- a/drivers/net/ethernet/sfc/ef100_netdev.c
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -218,6 +218,7 @@ netdev_tx_t __ef100_hard_start_xmit(struct sk_buff *skb,
skb->len, skb->data_len, channel->channel);
if (!efx->n_channels || !efx->n_tx_channels || !channel) {
netif_stop_queue(net_dev);
+ dev_kfree_skb_any(skb);
goto err;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 0a2afc1a3124..7deb1f817dac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -629,7 +629,6 @@ static int ehl_common_data(struct pci_dev *pdev,
{
plat->rx_queues_to_use = 8;
plat->tx_queues_to_use = 8;
- plat->clk_ptp_rate = 200000000;
plat->use_phy_wol = 1;
plat->safety_feat_cfg->tsoee = 1;
@@ -654,6 +653,8 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
+ plat->clk_ptp_rate = 204800000;
+
return ehl_common_data(pdev, plat);
}
@@ -667,6 +668,8 @@ static int ehl_rgmii_data(struct pci_dev *pdev,
plat->bus_id = 1;
plat->phy_interface = PHY_INTERFACE_MODE_RGMII;
+ plat->clk_ptp_rate = 204800000;
+
return ehl_common_data(pdev, plat);
}
@@ -683,6 +686,8 @@ static int ehl_pse0_common_data(struct pci_dev *pdev,
plat->bus_id = 2;
plat->addr64 = 32;
+ plat->clk_ptp_rate = 200000000;
+
intel_mgbe_pse_crossts_adj(intel_priv, EHL_PSE_ART_MHZ);
return ehl_common_data(pdev, plat);
@@ -722,6 +727,8 @@ static int ehl_pse1_common_data(struct pci_dev *pdev,
plat->bus_id = 3;
plat->addr64 = 32;
+ plat->clk_ptp_rate = 200000000;
+
intel_mgbe_pse_crossts_adj(intel_priv, EHL_PSE_ART_MHZ);
return ehl_common_data(pdev, plat);
@@ -757,7 +764,7 @@ static int tgl_common_data(struct pci_dev *pdev,
{
plat->rx_queues_to_use = 6;
plat->tx_queues_to_use = 4;
- plat->clk_ptp_rate = 200000000;
+ plat->clk_ptp_rate = 204800000;
plat->speed_mode_2500 = intel_speed_mode_2500;
plat->safety_feat_cfg->tsoee = 1;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index 79fa7870563b..a25c187d3185 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -75,20 +75,24 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
sizeof(*plat->mdio_bus_data),
GFP_KERNEL);
- if (!plat->mdio_bus_data)
- return -ENOMEM;
+ if (!plat->mdio_bus_data) {
+ ret = -ENOMEM;
+ goto err_put_node;
+ }
plat->mdio_bus_data->needs_reset = true;
}
plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL);
- if (!plat->dma_cfg)
- return -ENOMEM;
+ if (!plat->dma_cfg) {
+ ret = -ENOMEM;
+ goto err_put_node;
+ }
/* Enable pci device */
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__);
- return ret;
+ goto err_put_node;
}
/* Get the base address of device */
@@ -97,7 +101,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
continue;
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
if (ret)
- return ret;
+ goto err_disable_device;
break;
}
@@ -108,7 +112,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
phy_mode = device_get_phy_mode(&pdev->dev);
if (phy_mode < 0) {
dev_err(&pdev->dev, "phy_mode not found\n");
- return phy_mode;
+ ret = phy_mode;
+ goto err_disable_device;
}
plat->phy_interface = phy_mode;
@@ -125,6 +130,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
if (res.irq < 0) {
dev_err(&pdev->dev, "IRQ macirq not found\n");
ret = -ENODEV;
+ goto err_disable_msi;
}
res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
@@ -137,15 +143,31 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
if (res.lpi_irq < 0) {
dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
ret = -ENODEV;
+ goto err_disable_msi;
}
- return stmmac_dvr_probe(&pdev->dev, plat, &res);
+ ret = stmmac_dvr_probe(&pdev->dev, plat, &res);
+ if (ret)
+ goto err_disable_msi;
+
+ return ret;
+
+err_disable_msi:
+ pci_disable_msi(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+err_put_node:
+ of_node_put(plat->mdio_node);
+ return ret;
}
static void loongson_dwmac_remove(struct pci_dev *pdev)
{
+ struct net_device *ndev = dev_get_drvdata(&pdev->dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
int i;
+ of_node_put(priv->plat->mdio_node);
stmmac_dvr_remove(&pdev->dev);
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
@@ -155,6 +177,7 @@ static void loongson_dwmac_remove(struct pci_dev *pdev)
break;
}
+ pci_disable_msi(pdev);
pci_disable_device(pdev);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index c7a6588d9398..e8b507f88fbc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -272,11 +272,9 @@ static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac,
if (ret)
return ret;
- devm_add_action_or_reset(dwmac->dev,
- (void(*)(void *))clk_disable_unprepare,
- dwmac->rgmii_tx_clk);
-
- return 0;
+ return devm_add_action_or_reset(dwmac->dev,
+ (void(*)(void *))clk_disable_unprepare,
+ clk);
}
static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index c25bfecb4a2d..e5cfde1cbd5c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -748,6 +748,8 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
if (fc & FLOW_RX) {
pr_debug("\tReceive Flow-Control ON\n");
flow |= GMAC_RX_FLOW_CTRL_RFE;
+ } else {
+ pr_debug("\tReceive Flow-Control OFF\n");
}
writel(flow, ioaddr + GMAC_RX_FLOW_CTRL);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 8273e6a175c8..23ec0a9e396c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1061,8 +1061,16 @@ static void stmmac_mac_link_up(struct phylink_config *config,
ctrl |= priv->hw->link.duplex;
/* Flow Control operation */
- if (tx_pause && rx_pause)
- stmmac_mac_flow_ctrl(priv, duplex);
+ if (rx_pause && tx_pause)
+ priv->flow_ctrl = FLOW_AUTO;
+ else if (rx_pause && !tx_pause)
+ priv->flow_ctrl = FLOW_RX;
+ else if (!rx_pause && tx_pause)
+ priv->flow_ctrl = FLOW_TX;
+ else
+ priv->flow_ctrl = FLOW_OFF;
+
+ stmmac_mac_flow_ctrl(priv, duplex);
if (ctrl != old_ctrl)
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
@@ -6548,6 +6556,9 @@ void stmmac_xdp_release(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
u32 chan;
+ /* Ensure tx function is not running */
+ netif_tx_disable(dev);
+
/* Disable NAPI process */
stmmac_disable_all_queues(priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 50f6b4a14be4..eb6d9cd8e93f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -108,10 +108,10 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
- axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
- axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
- axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
- axi->axi_rb = of_property_read_bool(np, "snps,axi_rb");
+ axi->axi_kbbe = of_property_read_bool(np, "snps,kbbe");
+ axi->axi_fb = of_property_read_bool(np, "snps,fb");
+ axi->axi_mb = of_property_read_bool(np, "snps,mb");
+ axi->axi_rb = of_property_read_bool(np, "snps,rb");
if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
axi->axi_wr_osr_lmt = 1;
diff --git a/drivers/net/ethernet/sunplus/spl2sw_driver.c b/drivers/net/ethernet/sunplus/spl2sw_driver.c
index 9be585237277..c499a14314f1 100644
--- a/drivers/net/ethernet/sunplus/spl2sw_driver.c
+++ b/drivers/net/ethernet/sunplus/spl2sw_driver.c
@@ -287,7 +287,6 @@ static u32 spl2sw_init_netdev(struct platform_device *pdev, u8 *mac_addr,
if (ret) {
dev_err(&pdev->dev, "Failed to register net device \"%s\"!\n",
ndev->name);
- free_netdev(ndev);
*r_ndev = NULL;
return ret;
}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 7f86068f3ff6..b3b0ba842541 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -1454,7 +1454,7 @@ static void am65_cpsw_nuss_mac_link_up(struct phylink_config *config, struct phy
if (speed == SPEED_1000)
mac_control |= CPSW_SL_CTL_GIG;
- if (speed == SPEED_10 && interface == PHY_INTERFACE_MODE_RGMII)
+ if (speed == SPEED_10 && phy_interface_mode_is_rgmii(interface))
/* Can be used with in band mode only */
mac_control |= CPSW_SL_CTL_EXT_EN;
if (speed == SPEED_100 && interface == PHY_INTERFACE_MODE_RMII)
@@ -2082,7 +2082,7 @@ static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
for (i = 0; i < common->port_num; i++) {
port = &common->ports[i];
- if (port->ndev)
+ if (port->ndev && port->ndev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->ndev);
}
}
@@ -2823,7 +2823,6 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
if (ret < 0)
return ret;
- am65_cpsw_nuss_phylink_cleanup(common);
am65_cpsw_unregister_devlink(common);
am65_cpsw_unregister_notifiers(common);
@@ -2831,6 +2830,7 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
* dma_deconfigure(dev) before devres_release_all(dev)
*/
am65_cpsw_nuss_cleanup_ndev(common);
+ am65_cpsw_nuss_phylink_cleanup(common);
of_platform_device_destroy(common->mdio_dev, NULL);
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 709ca6dd6ecb..13c9c2d6b79b 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -854,6 +854,8 @@ static int cpsw_ndo_open(struct net_device *ndev)
err_cleanup:
if (!cpsw->usage_count) {
+ napi_disable(&cpsw->napi_rx);
+ napi_disable(&cpsw->napi_tx);
cpdma_ctlr_stop(cpsw->dma);
cpsw_destroy_xdp_rxqs(cpsw);
}
diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 2cd2afc3fff0..d09d352e1c0a 100644
--- a/drivers/net/ethernet/tundra/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -1290,12 +1290,15 @@ static int tsi108_open(struct net_device *dev)
data->rxring = dma_alloc_coherent(&data->pdev->dev, rxring_size,
&data->rxdma, GFP_KERNEL);
- if (!data->rxring)
+ if (!data->rxring) {
+ free_irq(data->irq_num, dev);
return -ENOMEM;
+ }
data->txring = dma_alloc_coherent(&data->pdev->dev, txring_size,
&data->txdma, GFP_KERNEL);
if (!data->txring) {
+ free_irq(data->irq_num, dev);
dma_free_coherent(&data->pdev->dev, rxring_size, data->rxring,
data->rxdma);
return -ENOMEM;
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 1eff202f6a1f..2513be6d4e11 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c
@@ -145,14 +145,12 @@ static int fjes_acpi_add(struct acpi_device *device)
return 0;
}
-static int fjes_acpi_remove(struct acpi_device *device)
+static void fjes_acpi_remove(struct acpi_device *device)
{
struct platform_device *plat_dev;
plat_dev = (struct platform_device *)acpi_driver_data(device);
platform_device_unregister(plat_dev);
-
- return 0;
}
static struct acpi_driver fjes_acpi_driver = {
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 30af0081e2be..83a16d10eedb 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -533,7 +533,7 @@ static int bpq_device_event(struct notifier_block *this,
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
- if (!dev_is_ethdev(dev))
+ if (!dev_is_ethdev(dev) && !bpq_get_ax25_dev(dev))
return NOTIFY_DONE;
switch (event) {
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index 450b16ad40a4..e1a569b99e4a 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -885,7 +885,7 @@ static int ca8210_spi_transfer(
dev_dbg(&spi->dev, "%s called\n", __func__);
- cas_ctl = kmalloc(sizeof(*cas_ctl), GFP_ATOMIC);
+ cas_ctl = kzalloc(sizeof(*cas_ctl), GFP_ATOMIC);
if (!cas_ctl)
return -ENOMEM;
diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index c69b87d3837d..edc769daad07 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -970,7 +970,7 @@ static int cc2520_hw_init(struct cc2520_private *priv)
if (timeout-- <= 0) {
dev_err(&priv->spi->dev, "oscillator start failed!\n");
- return ret;
+ return -ETIMEDOUT;
}
udelay(1);
} while (!(status & CC2520_STATUS_XOSC32M_STABLE));
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index de94921cbef9..025e0c19ec25 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -98,6 +98,7 @@ struct ipvl_port {
struct sk_buff_head backlog;
int count;
struct ida ida;
+ netdevice_tracker dev_tracker;
};
struct ipvl_skb_cb {
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 54c94a69c2bb..796a38f9d7b2 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -83,6 +83,7 @@ static int ipvlan_port_create(struct net_device *dev)
if (err)
goto err;
+ netdev_hold(dev, &port->dev_tracker, GFP_KERNEL);
return 0;
err:
@@ -95,6 +96,7 @@ static void ipvlan_port_destroy(struct net_device *dev)
struct ipvl_port *port = ipvlan_port_get_rtnl(dev);
struct sk_buff *skb;
+ netdev_put(dev, &port->dev_tracker);
if (port->mode == IPVLAN_MODE_L3S)
ipvlan_l3s_unregister(port);
netdev_rx_handler_unregister(dev);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 14e8d04cb434..2e9742952c4e 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -211,7 +211,7 @@ static __net_init int loopback_net_init(struct net *net)
int err;
err = -ENOMEM;
- dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);
+ dev = alloc_netdev(0, "lo", NET_NAME_PREDICTABLE, loopback_setup);
if (!dev)
goto out;
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index c891b60937a7..2fbac51b9b19 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -1413,7 +1413,8 @@ static struct macsec_rx_sc *del_rx_sc(struct macsec_secy *secy, sci_t sci)
return NULL;
}
-static struct macsec_rx_sc *create_rx_sc(struct net_device *dev, sci_t sci)
+static struct macsec_rx_sc *create_rx_sc(struct net_device *dev, sci_t sci,
+ bool active)
{
struct macsec_rx_sc *rx_sc;
struct macsec_dev *macsec;
@@ -1437,7 +1438,7 @@ static struct macsec_rx_sc *create_rx_sc(struct net_device *dev, sci_t sci)
}
rx_sc->sci = sci;
- rx_sc->active = true;
+ rx_sc->active = active;
refcount_set(&rx_sc->refcnt, 1);
secy = &macsec_priv(dev)->secy;
@@ -1838,6 +1839,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
secy->key_len);
err = macsec_offload(ops->mdo_add_rxsa, &ctx);
+ memzero_explicit(ctx.sa.key, secy->key_len);
if (err)
goto cleanup;
}
@@ -1876,7 +1878,7 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
struct macsec_rx_sc *rx_sc;
struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
struct macsec_secy *secy;
- bool was_active;
+ bool active = true;
int ret;
if (!attrs[MACSEC_ATTR_IFINDEX])
@@ -1898,16 +1900,15 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
secy = &macsec_priv(dev)->secy;
sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]);
- rx_sc = create_rx_sc(dev, sci);
+ if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE])
+ active = nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
+
+ rx_sc = create_rx_sc(dev, sci, active);
if (IS_ERR(rx_sc)) {
rtnl_unlock();
return PTR_ERR(rx_sc);
}
- was_active = rx_sc->active;
- if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE])
- rx_sc->active = !!nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
-
if (macsec_is_offloaded(netdev_priv(dev))) {
const struct macsec_ops *ops;
struct macsec_context ctx;
@@ -1931,7 +1932,8 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
return 0;
cleanup:
- rx_sc->active = was_active;
+ del_rx_sc(secy, sci);
+ free_rx_sc(rx_sc);
rtnl_unlock();
return ret;
}
@@ -2080,6 +2082,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
secy->key_len);
err = macsec_offload(ops->mdo_add_txsa, &ctx);
+ memzero_explicit(ctx.sa.key, secy->key_len);
if (err)
goto cleanup;
}
@@ -2570,7 +2573,7 @@ static bool macsec_is_configured(struct macsec_dev *macsec)
struct macsec_tx_sc *tx_sc = &secy->tx_sc;
int i;
- if (secy->n_rx_sc > 0)
+ if (secy->rx_sc)
return true;
for (i = 0; i < MACSEC_NUM_AN; i++)
@@ -2654,11 +2657,6 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
if (ret)
goto rollback;
- /* Force features update, since they are different for SW MACSec and
- * HW offloading cases.
- */
- netdev_update_features(dev);
-
rtnl_unlock();
return 0;
@@ -3432,16 +3430,9 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
return ret;
}
-#define SW_MACSEC_FEATURES \
+#define MACSEC_FEATURES \
(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
-/* If h/w offloading is enabled, use real device features save for
- * VLAN_FEATURES - they require additional ops
- * HW_MACSEC - no reason to report it
- */
-#define REAL_DEV_FEATURES(dev) \
- ((dev)->features & ~(NETIF_F_VLAN_FEATURES | NETIF_F_HW_MACSEC))
-
static int macsec_dev_init(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
@@ -3458,12 +3449,8 @@ static int macsec_dev_init(struct net_device *dev)
return err;
}
- if (macsec_is_offloaded(macsec)) {
- dev->features = REAL_DEV_FEATURES(real_dev);
- } else {
- dev->features = real_dev->features & SW_MACSEC_FEATURES;
- dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
- }
+ dev->features = real_dev->features & MACSEC_FEATURES;
+ dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
dev->needed_headroom = real_dev->needed_headroom +
MACSEC_NEEDED_HEADROOM;
@@ -3495,10 +3482,7 @@ static netdev_features_t macsec_fix_features(struct net_device *dev,
struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->real_dev;
- if (macsec_is_offloaded(macsec))
- return REAL_DEV_FEATURES(real_dev);
-
- features &= (real_dev->features & SW_MACSEC_FEATURES) |
+ features &= (real_dev->features & MACSEC_FEATURES) |
NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES;
features |= NETIF_F_LLTX;
@@ -3714,6 +3698,7 @@ static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = {
[IFLA_MACSEC_SCB] = { .type = NLA_U8 },
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
[IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
+ [IFLA_MACSEC_OFFLOAD] = { .type = NLA_U8 },
};
static void macsec_free_netdev(struct net_device *dev)
@@ -3851,7 +3836,6 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
if (macsec_is_offloaded(macsec)) {
const struct macsec_ops *ops;
struct macsec_context ctx;
- int ret;
ops = macsec_get_ops(netdev_priv(dev), &ctx);
if (!ops) {
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index c5cfe8555199..b8cc55b2d721 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -141,7 +141,7 @@ static struct macvlan_source_entry *macvlan_hash_lookup_source(
u32 idx = macvlan_eth_hash(addr);
struct hlist_head *h = &vlan->port->vlan_source_hash[idx];
- hlist_for_each_entry_rcu(entry, h, hlist) {
+ hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (ether_addr_equal_64bits(entry->addr, addr) &&
entry->vlan == vlan)
return entry;
@@ -1533,8 +1533,10 @@ destroy_macvlan_port:
/* the macvlan port may be freed by macvlan_uninit when fail to register.
* so we destroy the macvlan port only when it's valid.
*/
- if (create && macvlan_port_get_rtnl(lowerdev))
+ if (create && macvlan_port_get_rtnl(lowerdev)) {
+ macvlan_flush_sources(port, vlan);
macvlan_port_destroy(port->dev);
+ }
return err;
}
EXPORT_SYMBOL_GPL(macvlan_common_newlink);
@@ -1645,7 +1647,7 @@ static int macvlan_fill_info_macaddr(struct sk_buff *skb,
struct hlist_head *h = &vlan->port->vlan_source_hash[i];
struct macvlan_source_entry *entry;
- hlist_for_each_entry_rcu(entry, h, hlist) {
+ hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (entry->vlan != vlan)
continue;
if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr))
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
index 0762c735dd8a..1d67a3ca1fd1 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
@@ -43,6 +43,7 @@
enum {
MCTP_I2C_FLOW_STATE_NEW = 0,
MCTP_I2C_FLOW_STATE_ACTIVE,
+ MCTP_I2C_FLOW_STATE_INVALID,
};
/* List of all struct mctp_i2c_client
@@ -374,12 +375,18 @@ mctp_i2c_get_tx_flow_state(struct mctp_i2c_dev *midev, struct sk_buff *skb)
*/
if (!key->valid) {
state = MCTP_I2C_TX_FLOW_INVALID;
-
- } else if (key->dev_flow_state == MCTP_I2C_FLOW_STATE_NEW) {
- key->dev_flow_state = MCTP_I2C_FLOW_STATE_ACTIVE;
- state = MCTP_I2C_TX_FLOW_NEW;
} else {
- state = MCTP_I2C_TX_FLOW_EXISTING;
+ switch (key->dev_flow_state) {
+ case MCTP_I2C_FLOW_STATE_NEW:
+ key->dev_flow_state = MCTP_I2C_FLOW_STATE_ACTIVE;
+ state = MCTP_I2C_TX_FLOW_NEW;
+ break;
+ case MCTP_I2C_FLOW_STATE_ACTIVE:
+ state = MCTP_I2C_TX_FLOW_EXISTING;
+ break;
+ default:
+ state = MCTP_I2C_TX_FLOW_INVALID;
+ }
}
spin_unlock_irqrestore(&key->lock, flags);
@@ -617,21 +624,31 @@ static void mctp_i2c_release_flow(struct mctp_dev *mdev,
{
struct mctp_i2c_dev *midev = netdev_priv(mdev->dev);
+ bool queue_release = false;
unsigned long flags;
spin_lock_irqsave(&midev->lock, flags);
- midev->release_count++;
- spin_unlock_irqrestore(&midev->lock, flags);
-
- /* Ensure we have a release operation queued, through the fake
- * marker skb
+ /* if we have seen the flow/key previously, we need to pair the
+ * original lock with a release
*/
- spin_lock(&midev->tx_queue.lock);
- if (!midev->unlock_marker.next)
- __skb_queue_tail(&midev->tx_queue, &midev->unlock_marker);
- spin_unlock(&midev->tx_queue.lock);
+ if (key->dev_flow_state == MCTP_I2C_FLOW_STATE_ACTIVE) {
+ midev->release_count++;
+ queue_release = true;
+ }
+ key->dev_flow_state = MCTP_I2C_FLOW_STATE_INVALID;
+ spin_unlock_irqrestore(&midev->lock, flags);
- wake_up(&midev->tx_wq);
+ if (queue_release) {
+ /* Ensure we have a release operation queued, through the fake
+ * marker skb
+ */
+ spin_lock(&midev->tx_queue.lock);
+ if (!midev->unlock_marker.next)
+ __skb_queue_tail(&midev->tx_queue,
+ &midev->unlock_marker);
+ spin_unlock(&midev->tx_queue.lock);
+ wake_up(&midev->tx_wq);
+ }
}
static const struct net_device_ops mctp_i2c_ops = {
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
index 689e728345ce..b782c35c4ac1 100644
--- a/drivers/net/mdio/fwnode_mdio.c
+++ b/drivers/net/mdio/fwnode_mdio.c
@@ -98,6 +98,7 @@ int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
*/
rc = phy_device_register(phy);
if (rc) {
+ device_set_node(&phy->mdio.dev, NULL);
fwnode_handle_put(child);
return rc;
}
@@ -148,12 +149,13 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
/* Associate the fwnode with the device structure so it
* can be looked up later.
*/
- phy->mdio.dev.fwnode = child;
+ phy->mdio.dev.fwnode = fwnode_handle_get(child);
/* All data is now stored in the phy struct, so register it */
rc = phy_device_register(phy);
if (rc) {
- fwnode_handle_put(phy->mdio.dev.fwnode);
+ phy->mdio.dev.fwnode = NULL;
+ fwnode_handle_put(child);
goto clean_phy;
}
} else if (is_of_node(child)) {
diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c
index 796e9c7857d0..510822d6d0d9 100644
--- a/drivers/net/mdio/of_mdio.c
+++ b/drivers/net/mdio/of_mdio.c
@@ -68,8 +68,9 @@ static int of_mdiobus_register_device(struct mii_bus *mdio,
/* All data is now stored in the mdiodev struct; register it. */
rc = mdio_device_register(mdiodev);
if (rc) {
+ device_set_node(&mdiodev->dev, NULL);
+ fwnode_handle_put(fwnode);
mdio_device_free(mdiodev);
- of_node_put(child);
return rc;
}
diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c
index 0b1b6f650104..0b9d37979133 100644
--- a/drivers/net/mhi_net.c
+++ b/drivers/net/mhi_net.c
@@ -343,6 +343,8 @@ static void mhi_net_dellink(struct mhi_device *mhi_dev, struct net_device *ndev)
kfree_skb(mhi_netdev->skbagg_head);
+ free_netdev(ndev);
+
dev_set_drvdata(&mhi_dev->dev, NULL);
}
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index bdff9ac5056d..4f4f79532c6c 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -332,10 +332,8 @@ static ssize_t enabled_store(struct config_item *item,
}
if (enabled) { /* true */
- if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
- netconsole_ext.flags |= CON_ENABLED;
+ if (nt->extended && !console_is_registered(&netconsole_ext))
register_console(&netconsole_ext);
- }
/*
* Skip netpoll_parse_options() -- all the attributes are
@@ -869,7 +867,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
static struct console netconsole_ext = {
.name = "netcon_ext",
- .flags = CON_EXTENDED, /* starts disabled, registered on first use */
+ .flags = CON_ENABLED | CON_EXTENDED,
.write = write_ext_msg,
};
@@ -883,6 +881,7 @@ static int __init init_netconsole(void)
{
int err;
struct netconsole_target *nt, *tmp;
+ bool extended = false;
unsigned long flags;
char *target_config;
char *input = config;
@@ -895,11 +894,12 @@ static int __init init_netconsole(void)
goto fail;
}
/* Dump existing printks when we register */
- if (nt->extended)
- netconsole_ext.flags |= CON_PRINTBUFFER |
- CON_ENABLED;
- else
+ if (nt->extended) {
+ extended = true;
+ netconsole_ext.flags |= CON_PRINTBUFFER;
+ } else {
netconsole.flags |= CON_PRINTBUFFER;
+ }
spin_lock_irqsave(&target_list_lock, flags);
list_add(&nt->list, &target_list);
@@ -915,7 +915,7 @@ static int __init init_netconsole(void)
if (err)
goto undonotifier;
- if (netconsole_ext.flags & CON_ENABLED)
+ if (extended)
register_console(&netconsole_ext);
register_console(&netconsole);
pr_info("network logging started\n");
@@ -945,7 +945,8 @@ static void __exit cleanup_netconsole(void)
{
struct netconsole_target *nt, *tmp;
- unregister_console(&netconsole_ext);
+ if (console_is_registered(&netconsole_ext))
+ unregister_console(&netconsole_ext);
unregister_console(&netconsole);
dynamic_netconsole_exit();
unregister_netdevice_notifier(&netconsole_netdev_notifier);
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index a7880c7ce94c..68e56e451b2b 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -1683,6 +1683,7 @@ void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev)
ARRAY_SIZE(nsim_devlink_params));
devl_resources_unregister(devlink);
kfree(nsim_dev->vfconfigs);
+ kfree(nsim_dev->fa_cookie);
devl_unlock(devlink);
devlink_free(devlink);
dev_set_drvdata(&nsim_bus_dev->dev, NULL);
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index 464d88ca8ab0..a4abea921046 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -484,7 +484,14 @@ static int __init ntb_netdev_init_module(void)
rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
if (rc)
return rc;
- return ntb_transport_register_client(&ntb_netdev_client);
+
+ rc = ntb_transport_register_client(&ntb_netdev_client);
+ if (rc) {
+ ntb_transport_unregister_client_dev(KBUILD_MODNAME);
+ return rc;
+ }
+
+ return 0;
}
module_init(ntb_netdev_init_module);
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 349b7b1dbbf2..22f4458274aa 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -870,8 +870,10 @@ static int at803x_probe(struct phy_device *phydev)
.wolopts = 0,
};
- if (ccr < 0)
+ if (ccr < 0) {
+ ret = ccr;
goto err;
+ }
mode_cfg = ccr & AT803X_MODE_CFG_MASK;
switch (mode_cfg) {
@@ -1758,7 +1760,7 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
static int qca808x_phy_ms_random_seed_set(struct phy_device *phydev)
{
- u16 seed_value = prandom_u32_max(QCA808X_MASTER_SLAVE_SEED_RANGE);
+ u16 seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
QCA808X_MASTER_SLAVE_SEED_CFG,
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 417527f8bbf5..7446d5c6c714 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -682,6 +682,13 @@ static int dp83867_of_init(struct phy_device *phydev)
*/
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN / 2;
+ /* For non-OF device, the RX and TX FIFO depths are taken from
+ * default value. So, we init RX & TX FIFO depths here
+ * so that it is configured correctly later in dp83867_config_init();
+ */
+ dp83867->tx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
+ dp83867->rx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
+
return 0;
}
#endif /* CONFIG_OF_MDIO */
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 2810f4f9da0c..0d706ee266af 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2015,14 +2015,16 @@ static int m88e1510_loopback(struct phy_device *phydev, bool enable)
if (err < 0)
return err;
- /* FIXME: Based on trial and error test, it seem 1G need to have
- * delay between soft reset and loopback enablement.
- */
- if (phydev->speed == SPEED_1000)
- msleep(1000);
+ err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
+ BMCR_LOOPBACK);
- return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
- BMCR_LOOPBACK);
+ if (!err) {
+ /* It takes some time for PHY device to switch
+ * into/out-of loopback mode.
+ */
+ msleep(1000);
+ }
+ return err;
} else {
err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);
if (err < 0)
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index 250742ffdfd9..044828d081d2 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/unistd.h>
+#include <linux/property.h>
void mdio_device_free(struct mdio_device *mdiodev)
{
@@ -30,6 +31,7 @@ EXPORT_SYMBOL(mdio_device_free);
static void mdio_device_release(struct device *dev)
{
+ fwnode_handle_put(dev->fwnode);
kfree(to_mdio_device(dev));
}
diff --git a/drivers/net/phy/mscc/mscc_macsec.c b/drivers/net/phy/mscc/mscc_macsec.c
index ee5b17edca39..f81b077618f4 100644
--- a/drivers/net/phy/mscc/mscc_macsec.c
+++ b/drivers/net/phy/mscc/mscc_macsec.c
@@ -632,6 +632,7 @@ static void vsc8584_macsec_free_flow(struct vsc8531_private *priv,
list_del(&flow->list);
clear_bit(flow->index, bitmap);
+ memzero_explicit(flow->key, sizeof(flow->key));
kfree(flow);
}
diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c
index 24bae27eedef..cae24091fb6f 100644
--- a/drivers/net/phy/mxl-gpy.c
+++ b/drivers/net/phy/mxl-gpy.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/hwmon.h>
+#include <linux/mutex.h>
#include <linux/phy.h>
#include <linux/polynomial.h>
#include <linux/netdevice.h>
@@ -70,6 +71,14 @@
#define VPSPEC1_TEMP_STA 0x0E
#define VPSPEC1_TEMP_STA_DATA GENMASK(9, 0)
+/* Mailbox */
+#define VSPEC1_MBOX_DATA 0x5
+#define VSPEC1_MBOX_ADDRLO 0x6
+#define VSPEC1_MBOX_CMD 0x7
+#define VSPEC1_MBOX_CMD_ADDRHI GENMASK(7, 0)
+#define VSPEC1_MBOX_CMD_RD (0 << 8)
+#define VSPEC1_MBOX_CMD_READY BIT(15)
+
/* WoL */
#define VPSPEC2_WOL_CTL 0x0E06
#define VPSPEC2_WOL_AD01 0x0E08
@@ -77,7 +86,13 @@
#define VPSPEC2_WOL_AD45 0x0E0A
#define WOL_EN BIT(0)
+/* Internal registers, access via mbox */
+#define REG_GPIO0_OUT 0xd3ce00
+
struct gpy_priv {
+ /* serialize mailbox acesses */
+ struct mutex mbox_lock;
+
u8 fw_major;
u8 fw_minor;
};
@@ -187,6 +202,45 @@ static int gpy_hwmon_register(struct phy_device *phydev)
}
#endif
+static int gpy_mbox_read(struct phy_device *phydev, u32 addr)
+{
+ struct gpy_priv *priv = phydev->priv;
+ int val, ret;
+ u16 cmd;
+
+ mutex_lock(&priv->mbox_lock);
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_MBOX_ADDRLO,
+ addr);
+ if (ret)
+ goto out;
+
+ cmd = VSPEC1_MBOX_CMD_RD;
+ cmd |= FIELD_PREP(VSPEC1_MBOX_CMD_ADDRHI, addr >> 16);
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_MBOX_CMD, cmd);
+ if (ret)
+ goto out;
+
+ /* The mbox read is used in the interrupt workaround. It was observed
+ * that a read might take up to 2.5ms. This is also the time for which
+ * the interrupt line is stuck low. To be on the safe side, poll the
+ * ready bit for 10ms.
+ */
+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+ VSPEC1_MBOX_CMD, val,
+ (val & VSPEC1_MBOX_CMD_READY),
+ 500, 10000, false);
+ if (ret)
+ goto out;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_MBOX_DATA);
+
+out:
+ mutex_unlock(&priv->mbox_lock);
+ return ret;
+}
+
static int gpy_config_init(struct phy_device *phydev)
{
int ret;
@@ -201,6 +255,13 @@ static int gpy_config_init(struct phy_device *phydev)
return ret < 0 ? ret : 0;
}
+static bool gpy_has_broken_mdint(struct phy_device *phydev)
+{
+ /* At least these PHYs are known to have broken interrupt handling */
+ return phydev->drv->phy_id == PHY_ID_GPY215B ||
+ phydev->drv->phy_id == PHY_ID_GPY215C;
+}
+
static int gpy_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -218,6 +279,7 @@ static int gpy_probe(struct phy_device *phydev)
if (!priv)
return -ENOMEM;
phydev->priv = priv;
+ mutex_init(&priv->mbox_lock);
fw_version = phy_read(phydev, PHY_FWV);
if (fw_version < 0)
@@ -492,6 +554,29 @@ static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
if (!(reg & PHY_IMASK_MASK))
return IRQ_NONE;
+ /* The PHY might leave the interrupt line asserted even after PHY_ISTAT
+ * is read. To avoid interrupt storms, delay the interrupt handling as
+ * long as the PHY drives the interrupt line. An internal bus read will
+ * stall as long as the interrupt line is asserted, thus just read a
+ * random register here.
+ * Because we cannot access the internal bus at all while the interrupt
+ * is driven by the PHY, there is no way to make the interrupt line
+ * unstuck (e.g. by changing the pinmux to GPIO input) during that time
+ * frame. Therefore, polling is the best we can do and won't do any more
+ * harm.
+ * It was observed that this bug happens on link state and link speed
+ * changes on a GPY215B and GYP215C independent of the firmware version
+ * (which doesn't mean that this list is exhaustive).
+ */
+ if (gpy_has_broken_mdint(phydev) &&
+ (reg & (PHY_IMASK_LSTC | PHY_IMASK_LSPC))) {
+ reg = gpy_mbox_read(phydev, REG_GPIO0_OUT);
+ if (reg < 0) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+ }
+
phy_trigger_machine(phydev);
return IRQ_HANDLED;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 57849ac0384e..8cff61dbc4b5 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -217,6 +217,7 @@ static void phy_mdio_device_free(struct mdio_device *mdiodev)
static void phy_device_release(struct device *dev)
{
+ fwnode_handle_put(dev->fwnode);
kfree(to_phy_device(dev));
}
@@ -1520,6 +1521,7 @@ error:
error_module_put:
module_put(d->driver->owner);
+ d->driver = NULL;
error_put_device:
put_device(d);
if (ndev_owner != bus->owner)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 6547b6cc6cbe..2805b04d6402 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1603,19 +1603,29 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
linkmode_copy(supported, phy->supported);
linkmode_copy(config.advertising, phy->advertising);
- /* Clause 45 PHYs switch their Serdes lane between several different
- * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G
- * speeds. We really need to know which interface modes the PHY and
- * MAC supports to properly work out which linkmodes can be supported.
+ /* Check whether we would use rate matching for the proposed interface
+ * mode.
*/
- if (phy->is_c45 &&
+ config.rate_matching = phy_get_rate_matching(phy, interface);
+
+ /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
+ * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
+ * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
+ * their Serdes is either unnecessary or not reasonable.
+ *
+ * For these which switch interface modes, we really need to know which
+ * interface modes the PHY supports to properly work out which ethtool
+ * linkmodes can be supported. For now, as a work-around, we validate
+ * against all interface modes, which may lead to more ethtool link
+ * modes being advertised than are actually supported.
+ */
+ if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
interface != PHY_INTERFACE_MODE_RXAUI &&
interface != PHY_INTERFACE_MODE_XAUI &&
interface != PHY_INTERFACE_MODE_USXGMII)
config.interface = PHY_INTERFACE_MODE_NA;
else
config.interface = interface;
- config.rate_matching = phy_get_rate_matching(phy, config.interface);
ret = phylink_validate(pl, supported, &config);
if (ret) {
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index c8791e9b451d..40ce8abe6999 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -450,12 +450,12 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
}
rcv->state = PLIP_PK_DONE;
if (rcv->skb) {
- kfree_skb(rcv->skb);
+ dev_kfree_skb_irq(rcv->skb);
rcv->skb = NULL;
}
snd->state = PLIP_PK_DONE;
if (snd->skb) {
- dev_kfree_skb(snd->skb);
+ dev_consume_skb_irq(snd->skb);
snd->skb = NULL;
}
spin_unlock_irq(&nl->lock);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 9206c660a72e..be2fab0469cf 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -480,7 +480,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
ret = -EFAULT;
iov.iov_base = buf;
iov.iov_len = count;
- iov_iter_init(&to, READ, &iov, 1, count);
+ iov_iter_init(&to, ITER_DEST, &iov, 1, count);
if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
goto outf;
ret = skb->len;
diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c
index f3f8dd428402..53d0ce34b8ce 100644
--- a/drivers/net/team/team_mode_random.c
+++ b/drivers/net/team/team_mode_random.c
@@ -16,7 +16,7 @@ static bool rnd_transmit(struct team *team, struct sk_buff *skb)
struct team_port *port;
int port_index;
- port_index = prandom_u32_max(team->en_port_count);
+ port_index = get_random_u32_below(team->en_port_count);
port = team_get_port_by_index_rcu(team, port_index);
if (unlikely(!port))
goto drop;
diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
index 83fcaeb2ac5e..6312f67f260e 100644
--- a/drivers/net/thunderbolt.c
+++ b/drivers/net/thunderbolt.c
@@ -914,6 +914,7 @@ static int tbnet_open(struct net_device *dev)
eof_mask, tbnet_start_poll, net);
if (!ring) {
netdev_err(dev, "failed to allocate Rx ring\n");
+ tb_xdomain_release_out_hopid(xd, hopid);
tb_ring_free(net->tx_ring.ring);
net->tx_ring.ring = NULL;
return -ENOMEM;
@@ -1391,12 +1392,21 @@ static int __init tbnet_init(void)
tb_property_add_immediate(tbnet_dir, "prtcstns", flags);
ret = tb_register_property_dir("network", tbnet_dir);
- if (ret) {
- tb_property_free_dir(tbnet_dir);
- return ret;
- }
+ if (ret)
+ goto err_free_dir;
+
+ ret = tb_register_service_driver(&tbnet_driver);
+ if (ret)
+ goto err_unregister;
- return tb_register_service_driver(&tbnet_driver);
+ return 0;
+
+err_unregister:
+ tb_unregister_property_dir("network", tbnet_dir);
+err_free_dir:
+ tb_property_free_dir(tbnet_dir);
+
+ return ret;
}
module_init(tbnet_init);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 946628050f28..24001112c323 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -686,7 +686,6 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
if (tun)
xdp_rxq_info_unreg(&tfile->xdp_rxq);
ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free);
- sock_put(&tfile->sk);
}
}
@@ -702,6 +701,9 @@ static void tun_detach(struct tun_file *tfile, bool clean)
if (dev)
netdev_state_change(dev);
rtnl_unlock();
+
+ if (clean)
+ sock_put(&tfile->sk);
}
static void tun_detach_all(struct net_device *dev)
@@ -1967,17 +1969,25 @@ drop:
skb_headlen(skb));
if (unlikely(headlen > skb_headlen(skb))) {
+ WARN_ON_ONCE(1);
+ err = -ENOMEM;
dev_core_stats_rx_dropped_inc(tun->dev);
+napi_busy:
napi_free_frags(&tfile->napi);
rcu_read_unlock();
mutex_unlock(&tfile->napi_mutex);
- WARN_ON(1);
- return -ENOMEM;
+ return err;
}
- local_bh_disable();
- napi_gro_frags(&tfile->napi);
- local_bh_enable();
+ if (likely(napi_schedule_prep(&tfile->napi))) {
+ local_bh_disable();
+ napi_gro_frags(&tfile->napi);
+ napi_complete(&tfile->napi);
+ local_bh_enable();
+ } else {
+ err = -EBUSY;
+ goto napi_busy;
+ }
mutex_unlock(&tfile->napi_mutex);
} else if (tfile->napi_enabled) {
struct sk_buff_head *queue = &tfile->sk.sk_write_queue;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 8d5cbda33f66..0897fdb6254b 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1915,6 +1915,7 @@ static const struct driver_info cdc_ncm_zlp_info = {
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
.tx_fixup = cdc_ncm_tx_fixup,
+ .set_rx_mode = usbnet_cdc_update_filter,
};
/* Same as cdc_ncm_info, but with FLAG_WWAN */
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 26c34a7c21bd..554d4e2a84a4 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1357,6 +1357,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */
+ {QMI_QUIRK_SET_DTR(0x1bc7, 0x103a, 0)}, /* Telit LE910C4-WWX */
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1057, 2)}, /* Telit FN980 */
@@ -1422,6 +1423,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */
{QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/
{QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
+ {QMI_QUIRK_SET_DTR(0x1546, 0x1342, 4)}, /* u-blox LARA-L6 */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index bfb58c91db04..32d2c60d334d 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -66,6 +66,7 @@ struct smsc95xx_priv {
spinlock_t mac_cr_lock;
u8 features;
u8 suspend_flags;
+ bool is_internal_phy;
struct irq_chip irqchip;
struct irq_domain *irqdomain;
struct fwnode_handle *irqfwnode;
@@ -252,6 +253,43 @@ done:
mutex_unlock(&dev->phy_mutex);
}
+static int smsc95xx_mdiobus_reset(struct mii_bus *bus)
+{
+ struct smsc95xx_priv *pdata;
+ struct usbnet *dev;
+ u32 val;
+ int ret;
+
+ dev = bus->priv;
+ pdata = dev->driver_priv;
+
+ if (pdata->is_internal_phy)
+ return 0;
+
+ mutex_lock(&dev->phy_mutex);
+
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ if (ret < 0)
+ goto reset_out;
+
+ val |= PM_CTL_PHY_RST_;
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ if (ret < 0)
+ goto reset_out;
+
+ /* Driver has no knowledge at this point about the external PHY.
+ * The 802.3 specifies that the reset process shall
+ * be completed within 0.5 s.
+ */
+ fsleep(500000);
+
+reset_out:
+ mutex_unlock(&dev->phy_mutex);
+
+ return 0;
+}
+
static int smsc95xx_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
{
struct usbnet *dev = bus->priv;
@@ -1052,7 +1090,6 @@ static void smsc95xx_handle_link_change(struct net_device *net)
static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
{
struct smsc95xx_priv *pdata;
- bool is_internal_phy;
char usb_path[64];
int ret, phy_irq;
u32 val;
@@ -1133,13 +1170,14 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
if (ret < 0)
goto free_mdio;
- is_internal_phy = !(val & HW_CFG_PSEL_);
- if (is_internal_phy)
+ pdata->is_internal_phy = !(val & HW_CFG_PSEL_);
+ if (pdata->is_internal_phy)
pdata->mdiobus->phy_mask = ~(1u << SMSC95XX_INTERNAL_PHY_ID);
pdata->mdiobus->priv = dev;
pdata->mdiobus->read = smsc95xx_mdiobus_read;
pdata->mdiobus->write = smsc95xx_mdiobus_write;
+ pdata->mdiobus->reset = smsc95xx_mdiobus_reset;
pdata->mdiobus->name = "smsc95xx-mdiobus";
pdata->mdiobus->parent = &dev->udev->dev;
@@ -1160,7 +1198,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
}
pdata->phydev->irq = phy_irq;
- pdata->phydev->is_internal = is_internal_phy;
+ pdata->phydev->is_internal = pdata->is_internal_phy;
/* detect device revision as different features may be available */
ret = smsc95xx_read_reg(dev, ID_REV, &val);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7106932c6f88..86e52454b5b5 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3949,12 +3949,11 @@ static int virtnet_probe(struct virtio_device *vdev)
return 0;
free_unregister_netdev:
- virtio_reset_device(vdev);
-
unregister_netdev(dev);
free_failover:
net_failover_destroy(vi->failover);
free_vqs:
+ virtio_reset_device(vdev);
cancel_delayed_work_sync(&vi->refill);
free_receive_page_frags(vi);
virtnet_del_vqs(vi);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index d3e7b27eb933..6f1e560fb15c 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -75,8 +75,14 @@ vmxnet3_enable_all_intrs(struct vmxnet3_adapter *adapter)
for (i = 0; i < adapter->intr.num_intrs; i++)
vmxnet3_enable_intr(adapter, i);
- adapter->shared->devRead.intrConf.intrCtrl &=
+ if (!VMXNET3_VERSION_GE_6(adapter) ||
+ !adapter->queuesExtEnabled) {
+ adapter->shared->devRead.intrConf.intrCtrl &=
+ cpu_to_le32(~VMXNET3_IC_DISABLE_ALL);
+ } else {
+ adapter->shared->devReadExt.intrConfExt.intrCtrl &=
cpu_to_le32(~VMXNET3_IC_DISABLE_ALL);
+ }
}
@@ -85,8 +91,14 @@ vmxnet3_disable_all_intrs(struct vmxnet3_adapter *adapter)
{
int i;
- adapter->shared->devRead.intrConf.intrCtrl |=
+ if (!VMXNET3_VERSION_GE_6(adapter) ||
+ !adapter->queuesExtEnabled) {
+ adapter->shared->devRead.intrConf.intrCtrl |=
+ cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
+ } else {
+ adapter->shared->devReadExt.intrConfExt.intrCtrl |=
cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
+ }
for (i = 0; i < adapter->intr.num_intrs; i++)
vmxnet3_disable_intr(adapter, i);
}
@@ -1396,6 +1408,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
};
u32 num_pkts = 0;
bool skip_page_frags = false;
+ bool encap_lro = false;
struct Vmxnet3_RxCompDesc *rcd;
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
u16 segCnt = 0, mss = 0;
@@ -1556,13 +1569,18 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
if (VMXNET3_VERSION_GE_2(adapter) &&
rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) {
struct Vmxnet3_RxCompDescExt *rcdlro;
+ union Vmxnet3_GenericDesc *gdesc;
+
rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd;
+ gdesc = (union Vmxnet3_GenericDesc *)rcd;
segCnt = rcdlro->segCnt;
WARN_ON_ONCE(segCnt == 0);
mss = rcdlro->mss;
if (unlikely(segCnt <= 1))
segCnt = 0;
+ encap_lro = (le32_to_cpu(gdesc->dword[0]) &
+ (1UL << VMXNET3_RCD_HDR_INNER_SHIFT));
} else {
segCnt = 0;
}
@@ -1630,7 +1648,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
vmxnet3_rx_csum(adapter, skb,
(union Vmxnet3_GenericDesc *)rcd);
skb->protocol = eth_type_trans(skb, adapter->netdev);
- if (!rcd->tcp ||
+ if ((!rcd->tcp && !encap_lro) ||
!(adapter->netdev->features & NETIF_F_LRO))
goto not_lro;
@@ -1639,7 +1657,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
skb_shinfo(skb)->gso_size = mss;
skb_shinfo(skb)->gso_segs = segCnt;
- } else if (segCnt != 0 || skb->len > mtu) {
+ } else if ((segCnt != 0 || skb->len > mtu) && !encap_lro) {
u32 hlen;
hlen = vmxnet3_get_hdr_len(adapter, skb,
@@ -1668,6 +1686,7 @@ not_lro:
napi_gro_receive(&rq->napi, skb);
ctx->skb = NULL;
+ encap_lro = false;
num_pkts++;
}
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 960f1393595c..d62a904d2e42 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -325,6 +325,7 @@ static int lapbeth_open(struct net_device *dev)
err = lapb_register(dev, &lapbeth_callbacks);
if (err != LAPB_OK) {
+ napi_disable(&lapbeth->napi);
pr_err("lapb_register error: %d\n", err);
return -ENODEV;
}
@@ -446,7 +447,7 @@ static int lapbeth_device_event(struct notifier_block *this,
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
- if (!dev_is_ethdev(dev))
+ if (!dev_is_ethdev(dev) && !lapbeth_get_x25_dev(dev))
return NOTIFY_DONE;
switch (event) {
diff --git a/drivers/net/wireguard/selftest/allowedips.c b/drivers/net/wireguard/selftest/allowedips.c
index 19eac00b2381..78ebe2892a78 100644
--- a/drivers/net/wireguard/selftest/allowedips.c
+++ b/drivers/net/wireguard/selftest/allowedips.c
@@ -285,8 +285,8 @@ static __init bool randomized_test(void)
for (i = 0; i < NUM_RAND_ROUTES; ++i) {
get_random_bytes(ip, 4);
- cidr = prandom_u32_max(32) + 1;
- peer = peers[prandom_u32_max(NUM_PEERS)];
+ cidr = get_random_u32_inclusive(1, 32);
+ peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr,
peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
@@ -300,7 +300,7 @@ static __init bool randomized_test(void)
for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
memcpy(mutated, ip, 4);
get_random_bytes(mutate_mask, 4);
- mutate_amount = prandom_u32_max(32);
+ mutate_amount = get_random_u32_below(32);
for (k = 0; k < mutate_amount / 8; ++k)
mutate_mask[k] = 0xff;
mutate_mask[k] = 0xff
@@ -311,8 +311,8 @@ static __init bool randomized_test(void)
mutated[k] = (mutated[k] & mutate_mask[k]) |
(~mutate_mask[k] &
get_random_u8());
- cidr = prandom_u32_max(32) + 1;
- peer = peers[prandom_u32_max(NUM_PEERS)];
+ cidr = get_random_u32_inclusive(1, 32);
+ peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v4(&t,
(struct in_addr *)mutated,
cidr, peer, &mutex) < 0) {
@@ -329,8 +329,8 @@ static __init bool randomized_test(void)
for (i = 0; i < NUM_RAND_ROUTES; ++i) {
get_random_bytes(ip, 16);
- cidr = prandom_u32_max(128) + 1;
- peer = peers[prandom_u32_max(NUM_PEERS)];
+ cidr = get_random_u32_inclusive(1, 128);
+ peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr,
peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
@@ -344,7 +344,7 @@ static __init bool randomized_test(void)
for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
memcpy(mutated, ip, 16);
get_random_bytes(mutate_mask, 16);
- mutate_amount = prandom_u32_max(128);
+ mutate_amount = get_random_u32_below(128);
for (k = 0; k < mutate_amount / 8; ++k)
mutate_mask[k] = 0xff;
mutate_mask[k] = 0xff
@@ -355,8 +355,8 @@ static __init bool randomized_test(void)
mutated[k] = (mutated[k] & mutate_mask[k]) |
(~mutate_mask[k] &
get_random_u8());
- cidr = prandom_u32_max(128) + 1;
- peer = peers[prandom_u32_max(NUM_PEERS)];
+ cidr = get_random_u32_inclusive(1, 128);
+ peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v6(&t,
(struct in6_addr *)mutated,
cidr, peer, &mutex) < 0) {
diff --git a/drivers/net/wireguard/timers.c b/drivers/net/wireguard/timers.c
index d54d32ac9bc4..b5706b6718b1 100644
--- a/drivers/net/wireguard/timers.c
+++ b/drivers/net/wireguard/timers.c
@@ -147,7 +147,7 @@ void wg_timers_data_sent(struct wg_peer *peer)
if (!timer_pending(&peer->timer_new_handshake))
mod_peer_timer(peer, &peer->timer_new_handshake,
jiffies + (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * HZ +
- prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
+ get_random_u32_below(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
}
/* Should be called after an authenticated data packet is received. */
@@ -183,7 +183,7 @@ void wg_timers_handshake_initiated(struct wg_peer *peer)
{
mod_peer_timer(peer, &peer->timer_retransmit_handshake,
jiffies + REKEY_TIMEOUT * HZ +
- prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
+ get_random_u32_below(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
}
/* Should be called after a handshake response message is received and processed
diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
index 2ec56a34fa81..0909d53cefeb 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -27,7 +27,7 @@
#define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 52
#define ATH11K_QMI_CALDB_SIZE 0x480000
#define ATH11K_QMI_BDF_EXT_STR_LENGTH 0x20
-#define ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT 3
+#define ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT 5
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c
index 7ee3ff69dfc8..6fae4e61ede7 100644
--- a/drivers/net/wireless/ath/ath11k/reg.c
+++ b/drivers/net/wireless/ath/ath11k/reg.c
@@ -287,11 +287,7 @@ int ath11k_regd_update(struct ath11k *ar)
goto err;
}
- rtnl_lock();
- wiphy_lock(ar->hw->wiphy);
- ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
- wiphy_unlock(ar->hw->wiphy);
- rtnl_unlock();
+ ret = regulatory_set_wiphy_regd(ar->hw->wiphy, regd_copy);
kfree(regd_copy);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index bc3f4e4edcdf..dac7eb77799b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -228,6 +228,10 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
brcmf_fweh_event_name(event->code), event->code,
event->emsg.ifidx, event->emsg.bsscfgidx,
event->emsg.addr);
+ if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) {
+ bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx);
+ goto event_free;
+ }
/* convert event message */
emsg_be = &event->emsg;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 10d9d9c63b28..c704ca752138 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -1128,7 +1128,7 @@ static void brcmf_p2p_afx_handler(struct work_struct *work)
if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
/* 100ms ~ 300ms */
err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
- 100 * (1 + prandom_u32_max(3)));
+ 100 * get_random_u32_inclusive(1, 3));
else
err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index 10daef81c355..fb2c35bd73bb 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -5232,7 +5232,7 @@ static int get_wep_tx_idx(struct airo_info *ai)
return -1;
}
-static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
+static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key,
u16 keylen, int perm, int lock)
{
static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
@@ -5283,7 +5283,7 @@ static void proc_wepkey_on_close(struct inode *inode, struct file *file)
struct net_device *dev = pde_data(inode);
struct airo_info *ai = dev->ml_priv;
int i, rc;
- char key[16];
+ u8 key[16];
u16 index = 0;
int j = 0;
@@ -5311,12 +5311,22 @@ static void proc_wepkey_on_close(struct inode *inode, struct file *file)
}
for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) {
+ int val;
+
+ if (i % 3 == 2)
+ continue;
+
+ val = hex_to_bin(data->wbuffer[i+j]);
+ if (val < 0) {
+ airo_print_err(ai->dev->name, "WebKey passed invalid key hex");
+ return;
+ }
switch(i%3) {
case 0:
- key[i/3] = hex_to_bin(data->wbuffer[i+j])<<4;
+ key[i/3] = (u8)val << 4;
break;
case 1:
- key[i/3] |= hex_to_bin(data->wbuffer[i+j]);
+ key[i/3] |= (u8)val;
break;
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index de0c545d50fd..3a7a44bb3c60 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -1099,7 +1099,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
iwl_mvm_mac_ap_iterator, &data);
if (data.beacon_device_ts) {
- u32 rand = prandom_u32_max(64 - 36) + 36;
+ u32 rand = get_random_u32_inclusive(36, 63);
mvmvif->ap_beacon_time = data.beacon_device_ts +
ieee80211_tu_to_usec(data.beacon_int * rand /
100);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a40636c90ec3..0d81098c7b45 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -910,6 +910,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *cb;
if (!vp->assoc)
return;
@@ -931,6 +932,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
memcpy(hdr->addr2, mac, ETH_ALEN);
memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+ cb = IEEE80211_SKB_CB(skb);
+ cb->control.rates[0].count = 1;
+ cb->control.rates[1].idx = -1;
+
rcu_read_lock();
mac80211_hwsim_tx_frame(data->hw, skb,
rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan);
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 9bbfff803357..b545d93c6e37 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -959,30 +959,51 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
return;
while (index + sizeof(*e) <= len) {
+ u16 attr_size;
+
e = (struct wilc_attr_entry *)&buf[index];
- if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST)
+ attr_size = le16_to_cpu(e->attr_len);
+
+ if (index + sizeof(*e) + attr_size > len)
+ return;
+
+ if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST &&
+ attr_size >= (sizeof(struct wilc_attr_ch_list) - sizeof(*e)))
ch_list_idx = index;
- else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL)
+ else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL &&
+ attr_size == (sizeof(struct wilc_attr_oper_ch) - sizeof(*e)))
op_ch_idx = index;
+
if (ch_list_idx && op_ch_idx)
break;
- index += le16_to_cpu(e->attr_len) + sizeof(*e);
+
+ index += sizeof(*e) + attr_size;
}
if (ch_list_idx) {
- u16 attr_size;
- struct wilc_ch_list_elem *e;
- int i;
+ u16 elem_size;
ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
- attr_size = le16_to_cpu(ch_list->attr_len);
- for (i = 0; i < attr_size;) {
+ /* the number of bytes following the final 'elem' member */
+ elem_size = le16_to_cpu(ch_list->attr_len) -
+ (sizeof(*ch_list) - sizeof(struct wilc_attr_entry));
+ for (unsigned int i = 0; i < elem_size;) {
+ struct wilc_ch_list_elem *e;
+
e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
+
+ i += sizeof(*e);
+ if (i > elem_size)
+ break;
+
+ i += e->no_of_channels;
+ if (i > elem_size)
+ break;
+
if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
memset(e->ch_list, sta_ch, e->no_of_channels);
break;
}
- i += e->no_of_channels;
}
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index eb1d1ba3a443..67df8221b5ae 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -482,14 +482,25 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
if (rsn_ie) {
+ int rsn_ie_len = sizeof(struct element) + rsn_ie[1];
int offset = 8;
- param->mode_802_11i = 2;
- param->rsn_found = true;
/* extract RSN capabilities */
- offset += (rsn_ie[offset] * 4) + 2;
- offset += (rsn_ie[offset] * 4) + 2;
- memcpy(param->rsn_cap, &rsn_ie[offset], 2);
+ if (offset < rsn_ie_len) {
+ /* skip over pairwise suites */
+ offset += (rsn_ie[offset] * 4) + 2;
+
+ if (offset < rsn_ie_len) {
+ /* skip over authentication suites */
+ offset += (rsn_ie[offset] * 4) + 2;
+
+ if (offset + 1 < rsn_ie_len) {
+ param->mode_802_11i = 2;
+ param->rsn_found = true;
+ memcpy(param->rsn_cap, &rsn_ie[offset], 2);
+ }
+ }
+ }
}
if (param->rsn_found) {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
index 273c5eac3362..ddfc16de1b26 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
@@ -1023,9 +1023,9 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
{
u32 reg, reg2;
unsigned int i;
- char put_to_sleep;
- char bbp_state;
- char rf_state;
+ bool put_to_sleep;
+ u8 bbp_state;
+ u8 rf_state;
put_to_sleep = (state != STATE_AWAKE);
@@ -1561,7 +1561,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power;
+ u8 *tx_power;
unsigned int i;
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.h b/drivers/net/wireless/ralink/rt2x00/rt2400pci.h
index b8187b6de143..979d5fd8babf 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.h
@@ -939,7 +939,7 @@
#define DEFAULT_TXPOWER 39
#define __CLAMP_TX(__txpower) \
- clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
+ clamp_t(u8, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
#define TXPOWER_FROM_DEV(__txpower) \
((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
index 8faa0a80e73a..cd6371e25062 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
@@ -1176,9 +1176,9 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
{
u32 reg, reg2;
unsigned int i;
- char put_to_sleep;
- char bbp_state;
- char rf_state;
+ bool put_to_sleep;
+ u8 bbp_state;
+ u8 rf_state;
put_to_sleep = (state != STATE_AWAKE);
@@ -1856,7 +1856,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power;
+ u8 *tx_power;
unsigned int i;
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.h b/drivers/net/wireless/ralink/rt2x00/rt2500pci.h
index 7e64aee2a172..ba362675c52c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.h
@@ -1219,6 +1219,6 @@
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
- clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
+ clamp_t(u8, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
index bb5ed6630645..4f3b0e6c6256 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
@@ -984,9 +984,9 @@ static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev,
u16 reg;
u16 reg2;
unsigned int i;
- char put_to_sleep;
- char bbp_state;
- char rf_state;
+ bool put_to_sleep;
+ u8 bbp_state;
+ u8 rf_state;
put_to_sleep = (state != STATE_AWAKE);
@@ -1663,7 +1663,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power;
+ u8 *tx_power;
unsigned int i;
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.h b/drivers/net/wireless/ralink/rt2x00/rt2500usb.h
index 0c070288a140..746f0e950b76 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.h
@@ -839,6 +839,6 @@
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
- clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
+ clamp_t(u8, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index cbbb1a4849cf..12b700c7b9c3 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3372,10 +3372,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
/* r55/r59 value array of channel 1~14 */
- static const char r55_bt_rev[] = {0x83, 0x83,
+ static const u8 r55_bt_rev[] = {0x83, 0x83,
0x83, 0x73, 0x73, 0x63, 0x53, 0x53,
0x53, 0x43, 0x43, 0x43, 0x43, 0x43};
- static const char r59_bt_rev[] = {0x0e, 0x0e,
+ static const u8 r59_bt_rev[] = {0x0e, 0x0e,
0x0e, 0x0e, 0x0e, 0x0b, 0x0a, 0x09,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07};
@@ -3384,7 +3384,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
rt2800_rfcsr_write(rt2x00dev, 59,
r59_bt_rev[idx]);
} else {
- static const char r59_bt[] = {0x8b, 0x8b, 0x8b,
+ static const u8 r59_bt[] = {0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x89,
0x88, 0x88, 0x86, 0x85, 0x84};
@@ -3392,10 +3392,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
}
} else {
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
- static const char r55_nonbt_rev[] = {0x23, 0x23,
+ static const u8 r55_nonbt_rev[] = {0x23, 0x23,
0x23, 0x23, 0x13, 0x13, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
- static const char r59_nonbt_rev[] = {0x07, 0x07,
+ static const u8 r59_nonbt_rev[] = {0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x06, 0x05, 0x04, 0x04};
@@ -3406,14 +3406,14 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
} else if (rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392) ||
rt2x00_rt(rt2x00dev, RT6352)) {
- static const char r59_non_bt[] = {0x8f, 0x8f,
+ static const u8 r59_non_bt[] = {0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
rt2800_rfcsr_write(rt2x00dev, 59,
r59_non_bt[idx]);
} else if (rt2x00_rt(rt2x00dev, RT5350)) {
- static const char r59_non_bt[] = {0x0b, 0x0b,
+ static const u8 r59_non_bt[] = {0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a,
0x0a, 0x09, 0x08, 0x07, 0x07, 0x06};
@@ -4035,23 +4035,23 @@ static void rt2800_iq_calibrate(struct rt2x00_dev *rt2x00dev, int channel)
rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
}
-static char rt2800_txpower_to_dev(struct rt2x00_dev *rt2x00dev,
+static s8 rt2800_txpower_to_dev(struct rt2x00_dev *rt2x00dev,
unsigned int channel,
- char txpower)
+ s8 txpower)
{
if (rt2x00_rt(rt2x00dev, RT3593) ||
rt2x00_rt(rt2x00dev, RT3883))
txpower = rt2x00_get_field8(txpower, EEPROM_TXPOWER_ALC);
if (channel <= 14)
- return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER);
+ return clamp_t(s8, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER);
if (rt2x00_rt(rt2x00dev, RT3593) ||
rt2x00_rt(rt2x00dev, RT3883))
- return clamp_t(char, txpower, MIN_A_TXPOWER_3593,
+ return clamp_t(s8, txpower, MIN_A_TXPOWER_3593,
MAX_A_TXPOWER_3593);
else
- return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER);
+ return clamp_t(s8, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER);
}
static void rt3883_bbp_adjust(struct rt2x00_dev *rt2x00dev,
@@ -8530,7 +8530,7 @@ static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
u8 bytevalue = 0;
int rcalcode;
u8 r_cal_code = 0;
- char d1 = 0, d2 = 0;
+ s8 d1 = 0, d2 = 0;
u8 rfvalue;
u32 MAC_RF_BYPASS0, MAC_RF_CONTROL0, MAC_PWR_PIN_CFG;
u32 maccfg;
@@ -8591,7 +8591,7 @@ static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
if (bytevalue > 128)
d1 = bytevalue - 256;
else
- d1 = (char)bytevalue;
+ d1 = (s8)bytevalue;
rt2800_bbp_write(rt2x00dev, 22, 0x0);
rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x01);
@@ -8601,7 +8601,7 @@ static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
if (bytevalue > 128)
d2 = bytevalue - 256;
else
- d2 = (char)bytevalue;
+ d2 = (s8)bytevalue;
rt2800_bbp_write(rt2x00dev, 22, 0x0);
rcalcode = rt2800_calcrcalibrationcode(rt2x00dev, d1, d2);
@@ -8703,7 +8703,7 @@ static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev)
static u32 rt2800_do_sqrt_accumulation(u32 si)
{
u32 root, root_pre, bit;
- char i;
+ s8 i;
bit = 1 << 15;
root = 0;
@@ -9330,11 +9330,11 @@ static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx,
u8 alc_idx, u8 dc_result[][RF_ALC_NUM][2])
{
u32 p0 = 0, p1 = 0, pf = 0;
- char idx0 = 0, idx1 = 0;
+ s8 idx0 = 0, idx1 = 0;
u8 idxf[] = {0x00, 0x00};
u8 ibit = 0x20;
u8 iorq;
- char bidx;
+ s8 bidx;
rt2800_bbp_write(rt2x00dev, 158, 0xb0);
rt2800_bbp_write(rt2x00dev, 159, 0x80);
@@ -9384,17 +9384,17 @@ static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx,
static void rt2800_iq_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 *ges, u8 *pes)
{
u32 p0 = 0, p1 = 0, pf = 0;
- char perr = 0, gerr = 0, iq_err = 0;
- char pef = 0, gef = 0;
- char psta, pend;
- char gsta, gend;
+ s8 perr = 0, gerr = 0, iq_err = 0;
+ s8 pef = 0, gef = 0;
+ s8 psta, pend;
+ s8 gsta, gend;
u8 ibit = 0x20;
u8 first_search = 0x00, touch_neg_max = 0x00;
- char idx0 = 0, idx1 = 0;
+ s8 idx0 = 0, idx1 = 0;
u8 gop;
u8 bbp = 0;
- char bidx;
+ s8 bidx;
for (bidx = 5; bidx >= 1; bidx--) {
for (gop = 0; gop < 2; gop++) {
@@ -10043,11 +10043,11 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal)
return 0;
}
-static char rt2800_lp_tx_filter_bw_cal(struct rt2x00_dev *rt2x00dev)
+static s8 rt2800_lp_tx_filter_bw_cal(struct rt2x00_dev *rt2x00dev)
{
unsigned int cnt;
u8 bbp_val;
- char cal_val;
+ s8 cal_val;
rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x82);
@@ -10079,7 +10079,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev,
u8 rx_filter_target_20m = 0x27, rx_filter_target_40m = 0x31;
int loop = 0, is_ht40, cnt;
u8 bbp_val, rf_val;
- char cal_r32_init, cal_r32_val, cal_diff;
+ s8 cal_r32_init, cal_r32_val, cal_diff;
u8 saverfb5r00, saverfb5r01, saverfb5r03, saverfb5r04, saverfb5r05;
u8 saverfb5r06, saverfb5r07;
u8 saverfb5r08, saverfb5r17, saverfb5r18, saverfb5r19, saverfb5r20;
@@ -11550,9 +11550,9 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *default_power1;
- char *default_power2;
- char *default_power3;
+ s8 *default_power1;
+ s8 *default_power2;
+ s8 *default_power3;
unsigned int i, tx_chains, rx_chains;
u32 reg;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 3cbef77b4bd3..194de676df8f 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -32,10 +32,10 @@ struct rf_reg_pair {
struct rt2800_drv_data {
u8 calibration_bw20;
u8 calibration_bw40;
- char rx_calibration_bw20;
- char rx_calibration_bw40;
- char tx_calibration_bw20;
- char tx_calibration_bw40;
+ s8 rx_calibration_bw20;
+ s8 rx_calibration_bw40;
+ s8 tx_calibration_bw20;
+ s8 tx_calibration_bw40;
u8 bbp25;
u8 bbp26;
u8 txmixer_gain_24g;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 0827bc860bf8..8fd22c69855f 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -117,12 +117,12 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u16 buffer_length)
{
int status = 0;
- unsigned char *tb;
+ u8 *tb;
u16 off, len, bsize;
mutex_lock(&rt2x00dev->csr_mutex);
- tb = (char *)buffer;
+ tb = (u8 *)buffer;
off = offset;
len = buffer_length;
while (len && !status) {
@@ -215,7 +215,7 @@ void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
rd->cr.wLength = cpu_to_le16(sizeof(u32));
usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg),
+ (u8 *)(&rd->cr), &rd->reg, sizeof(rd->reg),
rt2x00usb_register_read_async_cb, rd);
usb_anchor_urb(urb, rt2x00dev->anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
index d92f9eb07dc9..81db7f57c7e4 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
@@ -1709,7 +1709,7 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
{
u32 reg, reg2;
unsigned int i;
- char put_to_sleep;
+ bool put_to_sleep;
put_to_sleep = (state != STATE_AWAKE);
@@ -2656,7 +2656,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power;
+ u8 *tx_power;
unsigned int i;
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.h b/drivers/net/wireless/ralink/rt2x00/rt61pci.h
index 5f208ad509bd..d72d0ffd1127 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.h
@@ -1484,6 +1484,6 @@ struct hw_pairwise_ta_entry {
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
- clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
+ clamp_t(u8, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
index e3269fd7c59e..861035444374 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
@@ -1378,7 +1378,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
{
u32 reg, reg2;
unsigned int i;
- char put_to_sleep;
+ bool put_to_sleep;
put_to_sleep = (state != STATE_AWAKE);
@@ -2090,7 +2090,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power;
+ u8 *tx_power;
unsigned int i;
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.h b/drivers/net/wireless/ralink/rt2x00/rt73usb.h
index 1b56d285c34b..bb0a68516c08 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.h
@@ -1063,6 +1063,6 @@ struct hw_pairwise_ta_entry {
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
- clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
+ clamp_t(u8, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT73USB_H */
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index 3486ffe94ac4..ac4d73b5626f 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -94,7 +94,7 @@ config RPMSG_WWAN_CTRL
config IOSM
tristate "IOSM Driver for Intel M.2 WWAN Device"
- depends on INTEL_IOMMU
+ depends on PCI
select NET_DEVLINK
select RELAY if WWAN_DEBUGFS
help
diff --git a/drivers/net/wwan/iosm/iosm_ipc_coredump.c b/drivers/net/wwan/iosm/iosm_ipc_coredump.c
index 9acd87724c9d..26ca30476f40 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_coredump.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_coredump.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
+#include <linux/vmalloc.h>
#include "iosm_ipc_coredump.h"
diff --git a/drivers/net/wwan/iosm/iosm_ipc_devlink.c b/drivers/net/wwan/iosm/iosm_ipc_devlink.c
index 17da85a8f337..2fe724d623c0 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_devlink.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_devlink.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
+#include <linux/vmalloc.h>
#include "iosm_ipc_chnl_cfg.h"
#include "iosm_ipc_coredump.h"
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
index b7f9237dedf7..66b90cc4c346 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
@@ -91,6 +91,14 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
}
ipc_chnl_cfg_get(&chnl_cfg, ipc_imem->nr_of_channels);
+
+ if (ipc_imem->mmio->mux_protocol == MUX_AGGREGATION &&
+ ipc_imem->nr_of_channels == IPC_MEM_IP_CHL_ID_0) {
+ chnl_cfg.ul_nr_of_entries = IPC_MEM_MAX_TDS_MUX_AGGR_UL;
+ chnl_cfg.dl_nr_of_entries = IPC_MEM_MAX_TDS_MUX_AGGR_DL;
+ chnl_cfg.dl_buf_size = IPC_MEM_MAX_ADB_BUF_SIZE;
+ }
+
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_WWAN, chnl_cfg,
IRQ_MOD_OFF);
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.c b/drivers/net/wwan/iosm/iosm_ipc_mux.c
index 9c7a9a2a1f25..fc928b298a98 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_mux.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux.c
@@ -332,6 +332,7 @@ struct iosm_mux *ipc_mux_init(struct ipc_mux_config *mux_cfg,
if (!ipc_mux->ul_adb.pp_qlt[i]) {
for (j = i - 1; j >= 0; j--)
kfree(ipc_mux->ul_adb.pp_qlt[j]);
+ kfree(ipc_mux);
return NULL;
}
}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.h b/drivers/net/wwan/iosm/iosm_ipc_mux.h
index cd9d74cc097f..9968bb885c1f 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_mux.h
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux.h
@@ -10,6 +10,7 @@
#define IPC_MEM_MAX_UL_DG_ENTRIES 100
#define IPC_MEM_MAX_TDS_MUX_AGGR_UL 60
+#define IPC_MEM_MAX_TDS_MUX_AGGR_DL 60
#define IPC_MEM_MAX_ADB_BUF_SIZE (16 * 1024)
#define IPC_MEM_MAX_UL_ADB_BUF_SIZE IPC_MEM_MAX_ADB_BUF_SIZE
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
index d41e373f9c0a..d6b166fc5c0e 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
@@ -365,7 +365,8 @@ static void ipc_mux_dl_cmd_decode(struct iosm_mux *ipc_mux, struct sk_buff *skb)
/* Pass the DL packet to the netif layer. */
static int ipc_mux_net_receive(struct iosm_mux *ipc_mux, int if_id,
struct iosm_wwan *wwan, u32 offset,
- u8 service_class, struct sk_buff *skb)
+ u8 service_class, struct sk_buff *skb,
+ u32 pkt_len)
{
struct sk_buff *dest_skb = skb_clone(skb, GFP_ATOMIC);
@@ -373,7 +374,7 @@ static int ipc_mux_net_receive(struct iosm_mux *ipc_mux, int if_id,
return -ENOMEM;
skb_pull(dest_skb, offset);
- skb_set_tail_pointer(dest_skb, dest_skb->len);
+ skb_trim(dest_skb, pkt_len);
/* Pass the packet to the netif layer. */
dest_skb->priority = service_class;
@@ -429,7 +430,7 @@ static void ipc_mux_dl_fcth_decode(struct iosm_mux *ipc_mux,
static void ipc_mux_dl_adgh_decode(struct iosm_mux *ipc_mux,
struct sk_buff *skb)
{
- u32 pad_len, packet_offset;
+ u32 pad_len, packet_offset, adgh_len;
struct iosm_wwan *wwan;
struct mux_adgh *adgh;
u8 *block = skb->data;
@@ -470,10 +471,12 @@ static void ipc_mux_dl_adgh_decode(struct iosm_mux *ipc_mux,
packet_offset = sizeof(*adgh) + pad_len;
if_id += ipc_mux->wwan_q_offset;
+ adgh_len = le16_to_cpu(adgh->length);
/* Pass the packet to the netif layer */
rc = ipc_mux_net_receive(ipc_mux, if_id, wwan, packet_offset,
- adgh->service_class, skb);
+ adgh->service_class, skb,
+ adgh_len - packet_offset);
if (rc) {
dev_err(ipc_mux->dev, "mux adgh decoding error");
return;
@@ -547,7 +550,7 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh,
int if_id, int nr_of_dg)
{
u32 dl_head_pad_len = ipc_mux->session[if_id].dl_head_pad_len;
- u32 packet_offset, i, rc;
+ u32 packet_offset, i, rc, dg_len;
for (i = 0; i < nr_of_dg; i++, dg++) {
if (le32_to_cpu(dg->datagram_index)
@@ -562,11 +565,12 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh,
packet_offset =
le32_to_cpu(dg->datagram_index) +
dl_head_pad_len;
+ dg_len = le16_to_cpu(dg->datagram_length);
/* Pass the packet to the netif layer. */
rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan,
packet_offset,
- dg->service_class,
- skb);
+ dg->service_class, skb,
+ dg_len - dl_head_pad_len);
if (rc)
goto dg_error;
}
@@ -1207,10 +1211,9 @@ static int mux_ul_dg_update_tbl_index(struct iosm_mux *ipc_mux,
qlth_n_ql_size, ul_list);
ipc_mux_ul_adb_finish(ipc_mux);
if (ipc_mux_ul_adb_allocate(ipc_mux, adb, &ipc_mux->size_needed,
- IOSM_AGGR_MUX_SIG_ADBH)) {
- dev_kfree_skb(src_skb);
+ IOSM_AGGR_MUX_SIG_ADBH))
return -ENOMEM;
- }
+
ipc_mux->size_needed = le32_to_cpu(adb->adbh->block_length);
ipc_mux->size_needed += offsetof(struct mux_adth, dg);
@@ -1471,8 +1474,7 @@ void ipc_mux_ul_encoded_process(struct iosm_mux *ipc_mux, struct sk_buff *skb)
ipc_mux->ul_data_pend_bytes);
/* Reset the skb settings. */
- skb->tail = 0;
- skb->len = 0;
+ skb_trim(skb, 0);
/* Add the consumed ADB to the free list. */
skb_queue_tail((&ipc_mux->ul_adb.free_list), skb);
diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c
index 31f57b986df2..5bf5a93937c9 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_pcie.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c
@@ -232,6 +232,7 @@ static void ipc_pcie_config_init(struct iosm_pcie *ipc_pcie)
*/
static enum ipc_pcie_sleep_state ipc_pcie_read_bios_cfg(struct device *dev)
{
+ enum ipc_pcie_sleep_state sleep_state = IPC_PCIE_D0L12;
union acpi_object *object;
acpi_handle handle_acpi;
@@ -242,18 +243,23 @@ static enum ipc_pcie_sleep_state ipc_pcie_read_bios_cfg(struct device *dev)
}
object = acpi_evaluate_dsm(handle_acpi, &wwan_acpi_guid, 0, 3, NULL);
+ if (!object)
+ goto default_ret;
+
+ if (object->integer.value == 3)
+ sleep_state = IPC_PCIE_D3L2;
- if (object && object->integer.value == 3)
- return IPC_PCIE_D3L2;
+ ACPI_FREE(object);
default_ret:
- return IPC_PCIE_D0L12;
+ return sleep_state;
}
static int ipc_pcie_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
struct iosm_pcie *ipc_pcie = kzalloc(sizeof(*ipc_pcie), GFP_KERNEL);
+ int ret;
pr_debug("Probing device 0x%X from the vendor 0x%X", pci_id->device,
pci_id->vendor);
@@ -286,6 +292,12 @@ static int ipc_pcie_probe(struct pci_dev *pci,
goto pci_enable_fail;
}
+ ret = dma_set_mask(ipc_pcie->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_err(ipc_pcie->dev, "Could not set PCI DMA mask: %d", ret);
+ return ret;
+ }
+
ipc_pcie_config_aspm(ipc_pcie);
dev_dbg(ipc_pcie->dev, "PCIe device enabled.");
diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol.h b/drivers/net/wwan/iosm/iosm_ipc_protocol.h
index 9b3a6d86ece7..289397c4ea6c 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_protocol.h
+++ b/drivers/net/wwan/iosm/iosm_ipc_protocol.h
@@ -122,7 +122,7 @@ struct iosm_protocol {
struct iosm_imem *imem;
struct ipc_rsp *rsp_ring[IPC_MEM_MSG_ENTRIES];
struct device *dev;
- phys_addr_t phy_ap_shm;
+ dma_addr_t phy_ap_shm;
u32 old_msg_tail;
};
diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c
index 2f1f8b5d5b59..4c9022a93e01 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c
@@ -40,13 +40,11 @@ struct iosm_netdev_priv {
* @ipc_imem: Pointer to imem data-struct
* @sub_netlist: List of active netdevs
* @dev: Pointer device structure
- * @if_mutex: Mutex used for add and remove interface id
*/
struct iosm_wwan {
struct iosm_imem *ipc_imem;
struct iosm_netdev_priv __rcu *sub_netlist[IP_MUX_SESSION_END + 1];
struct device *dev;
- struct mutex if_mutex; /* Mutex used for add and remove interface id */
};
/* Bring-up the wwan net link */
@@ -55,14 +53,11 @@ static int ipc_wwan_link_open(struct net_device *netdev)
struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev);
struct iosm_wwan *ipc_wwan = priv->ipc_wwan;
int if_id = priv->if_id;
- int ret;
if (if_id < IP_MUX_SESSION_START ||
if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
return -EINVAL;
- mutex_lock(&ipc_wwan->if_mutex);
-
/* get channel id */
priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id);
@@ -70,8 +65,7 @@ static int ipc_wwan_link_open(struct net_device *netdev)
dev_err(ipc_wwan->dev,
"cannot connect wwan0 & id %d to the IPC mem layer",
if_id);
- ret = -ENODEV;
- goto out;
+ return -ENODEV;
}
/* enable tx path, DL data may follow */
@@ -80,10 +74,7 @@ static int ipc_wwan_link_open(struct net_device *netdev)
dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d",
priv->ch_id, priv->if_id);
- ret = 0;
-out:
- mutex_unlock(&ipc_wwan->if_mutex);
- return ret;
+ return 0;
}
/* Bring-down the wwan net link */
@@ -93,11 +84,9 @@ static int ipc_wwan_link_stop(struct net_device *netdev)
netif_stop_queue(netdev);
- mutex_lock(&priv->ipc_wwan->if_mutex);
ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id,
priv->ch_id);
priv->ch_id = -1;
- mutex_unlock(&priv->ipc_wwan->if_mutex);
return 0;
}
@@ -168,6 +157,7 @@ static void ipc_wwan_setup(struct net_device *iosm_dev)
iosm_dev->max_mtu = ETH_MAX_MTU;
iosm_dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ iosm_dev->needs_free_netdev = true;
iosm_dev->netdev_ops = &ipc_inm_ops;
}
@@ -189,26 +179,17 @@ static int ipc_wwan_newlink(void *ctxt, struct net_device *dev,
priv->netdev = dev;
priv->ipc_wwan = ipc_wwan;
- mutex_lock(&ipc_wwan->if_mutex);
- if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id])) {
- err = -EBUSY;
- goto out_unlock;
- }
+ if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id]))
+ return -EBUSY;
err = register_netdevice(dev);
if (err)
- goto out_unlock;
+ return err;
rcu_assign_pointer(ipc_wwan->sub_netlist[if_id], priv);
- mutex_unlock(&ipc_wwan->if_mutex);
-
netif_device_attach(dev);
return 0;
-
-out_unlock:
- mutex_unlock(&ipc_wwan->if_mutex);
- return err;
}
static void ipc_wwan_dellink(void *ctxt, struct net_device *dev,
@@ -222,17 +203,12 @@ static void ipc_wwan_dellink(void *ctxt, struct net_device *dev,
if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)))
return;
- mutex_lock(&ipc_wwan->if_mutex);
-
if (WARN_ON(rcu_access_pointer(ipc_wwan->sub_netlist[if_id]) != priv))
- goto unlock;
+ return;
RCU_INIT_POINTER(ipc_wwan->sub_netlist[if_id], NULL);
/* unregistering includes synchronize_net() */
unregister_netdevice_queue(dev, head);
-
-unlock:
- mutex_unlock(&ipc_wwan->if_mutex);
}
static const struct wwan_ops iosm_wwan_ops = {
@@ -323,12 +299,9 @@ struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev)
ipc_wwan->dev = dev;
ipc_wwan->ipc_imem = ipc_imem;
- mutex_init(&ipc_wwan->if_mutex);
-
/* WWAN core will create a netdev for the default IP MUX channel */
if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan,
IP_MUX_SESSION_DEFAULT)) {
- mutex_destroy(&ipc_wwan->if_mutex);
kfree(ipc_wwan);
return NULL;
}
@@ -341,7 +314,5 @@ void ipc_wwan_deinit(struct iosm_wwan *ipc_wwan)
/* This call will remove all child netdev(s) */
wwan_unregister_ops(ipc_wwan->dev);
- mutex_destroy(&ipc_wwan->if_mutex);
-
kfree(ipc_wwan);
}
diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c
index 6872782e8dd8..ef70bb7c88ad 100644
--- a/drivers/net/wwan/mhi_wwan_mbim.c
+++ b/drivers/net/wwan/mhi_wwan_mbim.c
@@ -582,6 +582,7 @@ static void mhi_mbim_setup(struct net_device *ndev)
ndev->min_mtu = ETH_MIN_MTU;
ndev->max_mtu = MHI_MAX_BUF_SZ - ndev->needed_headroom;
ndev->tx_queue_len = 1000;
+ ndev->needs_free_netdev = true;
}
static const struct wwan_ops mhi_mbim_wwan_ops = {
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index 3458af31e864..7d0f5e4f0a78 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -165,6 +165,8 @@ static int t7xx_acpi_reset(struct t7xx_pci_dev *t7xx_dev, char *fn_name)
return -EFAULT;
}
+ kfree(buffer.pointer);
+
#endif
return 0;
}
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 1545cbee77a4..3dbfc8a6924e 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -386,7 +386,7 @@ int xenvif_dealloc_kthread(void *data);
irqreturn_t xenvif_ctrl_irq_fn(int irq, void *data);
bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread);
-void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);
+bool xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);
void xenvif_carrier_on(struct xenvif *vif);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 650fa180220f..f3f2c07423a6 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -254,14 +254,16 @@ xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
skb_clear_hash(skb);
- xenvif_rx_queue_tail(queue, skb);
+ if (!xenvif_rx_queue_tail(queue, skb))
+ goto drop;
+
xenvif_kick_thread(queue);
return NETDEV_TX_OK;
drop:
vif->dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 3d2081bbbc86..bf627af723bf 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -332,10 +332,13 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
struct xenvif_tx_cb {
- u16 pending_idx;
+ u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1];
+ u8 copy_count;
};
#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+#define copy_pending_idx(skb, i) (XENVIF_TX_CB(skb)->copy_pending_idx[i])
+#define copy_count(skb) (XENVIF_TX_CB(skb)->copy_count)
static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue,
u16 pending_idx,
@@ -370,31 +373,93 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
return skb;
}
-static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_map_grant_ref *gop,
- unsigned int frag_overflow,
- struct sk_buff *nskb)
+static void xenvif_get_requests(struct xenvif_queue *queue,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *first,
+ struct xen_netif_tx_request *txfrags,
+ unsigned *copy_ops,
+ unsigned *map_ops,
+ unsigned int frag_overflow,
+ struct sk_buff *nskb,
+ unsigned int extra_count,
+ unsigned int data_len)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
- u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
- int start;
+ u16 pending_idx;
pending_ring_idx_t index;
unsigned int nr_slots;
+ struct gnttab_copy *cop = queue->tx_copy_ops + *copy_ops;
+ struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops;
+ struct xen_netif_tx_request *txp = first;
+
+ nr_slots = shinfo->nr_frags + 1;
+
+ copy_count(skb) = 0;
+
+ /* Create copy ops for exactly data_len bytes into the skb head. */
+ __skb_put(skb, data_len);
+ while (data_len > 0) {
+ int amount = data_len > txp->size ? txp->size : data_len;
+
+ cop->source.u.ref = txp->gref;
+ cop->source.domid = queue->vif->domid;
+ cop->source.offset = txp->offset;
+
+ cop->dest.domid = DOMID_SELF;
+ cop->dest.offset = (offset_in_page(skb->data +
+ skb_headlen(skb) -
+ data_len)) & ~XEN_PAGE_MASK;
+ cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb)
+ - data_len);
+
+ cop->len = amount;
+ cop->flags = GNTCOPY_source_gref;
- nr_slots = shinfo->nr_frags;
+ index = pending_index(queue->pending_cons);
+ pending_idx = queue->pending_ring[index];
+ callback_param(queue, pending_idx).ctx = NULL;
+ copy_pending_idx(skb, copy_count(skb)) = pending_idx;
+ copy_count(skb)++;
+
+ cop++;
+ data_len -= amount;
- /* Skip first skb fragment if it is on same page as header fragment. */
- start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+ if (amount == txp->size) {
+ /* The copy op covered the full tx_request */
+
+ memcpy(&queue->pending_tx_info[pending_idx].req,
+ txp, sizeof(*txp));
+ queue->pending_tx_info[pending_idx].extra_count =
+ (txp == first) ? extra_count : 0;
+
+ if (txp == first)
+ txp = txfrags;
+ else
+ txp++;
+ queue->pending_cons++;
+ nr_slots--;
+ } else {
+ /* The copy op partially covered the tx_request.
+ * The remainder will be mapped.
+ */
+ txp->offset += amount;
+ txp->size -= amount;
+ }
+ }
- for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots;
- shinfo->nr_frags++, txp++, gop++) {
+ for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots;
+ shinfo->nr_frags++, gop++) {
index = pending_index(queue->pending_cons++);
pending_idx = queue->pending_ring[index];
- xenvif_tx_create_map_op(queue, pending_idx, txp, 0, gop);
+ xenvif_tx_create_map_op(queue, pending_idx, txp,
+ txp == first ? extra_count : 0, gop);
frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+
+ if (txp == first)
+ txp = txfrags;
+ else
+ txp++;
}
if (frag_overflow) {
@@ -415,7 +480,8 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
skb_shinfo(skb)->frag_list = nskb;
}
- return gop;
+ (*copy_ops) = cop - queue->tx_copy_ops;
+ (*map_ops) = gop - queue->tx_map_ops;
}
static inline void xenvif_grant_handle_set(struct xenvif_queue *queue,
@@ -451,7 +517,7 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
struct gnttab_copy **gopp_copy)
{
struct gnttab_map_grant_ref *gop_map = *gopp_map;
- u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ u16 pending_idx;
/* This always points to the shinfo of the skb being checked, which
* could be either the first or the one on the frag_list
*/
@@ -462,24 +528,37 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
struct skb_shared_info *first_shinfo = NULL;
int nr_frags = shinfo->nr_frags;
const bool sharedslot = nr_frags &&
- frag_get_pending_idx(&shinfo->frags[0]) == pending_idx;
- int i, err;
+ frag_get_pending_idx(&shinfo->frags[0]) ==
+ copy_pending_idx(skb, copy_count(skb) - 1);
+ int i, err = 0;
- /* Check status of header. */
- err = (*gopp_copy)->status;
- if (unlikely(err)) {
- if (net_ratelimit())
- netdev_dbg(queue->vif->dev,
- "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n",
- (*gopp_copy)->status,
- pending_idx,
- (*gopp_copy)->source.u.ref);
- /* The first frag might still have this slot mapped */
- if (!sharedslot)
- xenvif_idx_release(queue, pending_idx,
- XEN_NETIF_RSP_ERROR);
+ for (i = 0; i < copy_count(skb); i++) {
+ int newerr;
+
+ /* Check status of header. */
+ pending_idx = copy_pending_idx(skb, i);
+
+ newerr = (*gopp_copy)->status;
+ if (likely(!newerr)) {
+ /* The first frag might still have this slot mapped */
+ if (i < copy_count(skb) - 1 || !sharedslot)
+ xenvif_idx_release(queue, pending_idx,
+ XEN_NETIF_RSP_OKAY);
+ } else {
+ err = newerr;
+ if (net_ratelimit())
+ netdev_dbg(queue->vif->dev,
+ "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n",
+ (*gopp_copy)->status,
+ pending_idx,
+ (*gopp_copy)->source.u.ref);
+ /* The first frag might still have this slot mapped */
+ if (i < copy_count(skb) - 1 || !sharedslot)
+ xenvif_idx_release(queue, pending_idx,
+ XEN_NETIF_RSP_ERROR);
+ }
+ (*gopp_copy)++;
}
- (*gopp_copy)++;
check_frags:
for (i = 0; i < nr_frags; i++, gop_map++) {
@@ -526,14 +605,6 @@ check_frags:
if (err)
continue;
- /* First error: if the header haven't shared a slot with the
- * first frag, release it as well.
- */
- if (!sharedslot)
- xenvif_idx_release(queue,
- XENVIF_TX_CB(skb)->pending_idx,
- XEN_NETIF_RSP_OKAY);
-
/* Invalidate preceding fragments of this skb. */
for (j = 0; j < i; j++) {
pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
@@ -803,7 +874,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
unsigned *copy_ops,
unsigned *map_ops)
{
- struct gnttab_map_grant_ref *gop = queue->tx_map_ops;
struct sk_buff *skb, *nskb;
int ret;
unsigned int frag_overflow;
@@ -885,8 +955,12 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
continue;
}
+ data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN) ?
+ XEN_NETBACK_TX_COPY_LEN : txreq.size;
+
ret = xenvif_count_requests(queue, &txreq, extra_count,
txfrags, work_to_do);
+
if (unlikely(ret < 0))
break;
@@ -912,9 +986,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
index = pending_index(queue->pending_cons);
pending_idx = queue->pending_ring[index];
- data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN &&
- ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
- XEN_NETBACK_TX_COPY_LEN : txreq.size;
+ if (ret >= XEN_NETBK_LEGACY_SLOTS_MAX - 1 && data_len < txreq.size)
+ data_len = txreq.size;
skb = xenvif_alloc_skb(data_len);
if (unlikely(skb == NULL)) {
@@ -925,8 +998,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
}
skb_shinfo(skb)->nr_frags = ret;
- if (data_len < txreq.size)
- skb_shinfo(skb)->nr_frags++;
/* At this point shinfo->nr_frags is in fact the number of
* slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
*/
@@ -988,54 +1059,19 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
type);
}
- XENVIF_TX_CB(skb)->pending_idx = pending_idx;
-
- __skb_put(skb, data_len);
- queue->tx_copy_ops[*copy_ops].source.u.ref = txreq.gref;
- queue->tx_copy_ops[*copy_ops].source.domid = queue->vif->domid;
- queue->tx_copy_ops[*copy_ops].source.offset = txreq.offset;
-
- queue->tx_copy_ops[*copy_ops].dest.u.gmfn =
- virt_to_gfn(skb->data);
- queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF;
- queue->tx_copy_ops[*copy_ops].dest.offset =
- offset_in_page(skb->data) & ~XEN_PAGE_MASK;
-
- queue->tx_copy_ops[*copy_ops].len = data_len;
- queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref;
-
- (*copy_ops)++;
-
- if (data_len < txreq.size) {
- frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
- pending_idx);
- xenvif_tx_create_map_op(queue, pending_idx, &txreq,
- extra_count, gop);
- gop++;
- } else {
- frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
- INVALID_PENDING_IDX);
- memcpy(&queue->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
- queue->pending_tx_info[pending_idx].extra_count =
- extra_count;
- }
-
- queue->pending_cons++;
-
- gop = xenvif_get_requests(queue, skb, txfrags, gop,
- frag_overflow, nskb);
+ xenvif_get_requests(queue, skb, &txreq, txfrags, copy_ops,
+ map_ops, frag_overflow, nskb, extra_count,
+ data_len);
__skb_queue_tail(&queue->tx_queue, skb);
queue->tx.req_cons = idx;
- if (((gop-queue->tx_map_ops) >= ARRAY_SIZE(queue->tx_map_ops)) ||
+ if ((*map_ops >= ARRAY_SIZE(queue->tx_map_ops)) ||
(*copy_ops >= ARRAY_SIZE(queue->tx_copy_ops)))
break;
}
- (*map_ops) = gop - queue->tx_map_ops;
return;
}
@@ -1114,9 +1150,8 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
while ((skb = __skb_dequeue(&queue->tx_queue)) != NULL) {
struct xen_netif_tx_request *txp;
u16 pending_idx;
- unsigned data_len;
- pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ pending_idx = copy_pending_idx(skb, 0);
txp = &queue->pending_tx_info[pending_idx].req;
/* Check the remap error code. */
@@ -1135,18 +1170,6 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
continue;
}
- data_len = skb->len;
- callback_param(queue, pending_idx).ctx = NULL;
- if (data_len < txp->size) {
- /* Append the packet payload as a fragment. */
- txp->offset += data_len;
- txp->size -= data_len;
- } else {
- /* Schedule a response immediately. */
- xenvif_idx_release(queue, pending_idx,
- XEN_NETIF_RSP_OKAY);
- }
-
if (txp->flags & XEN_NETTXF_csum_blank)
skb->ip_summed = CHECKSUM_PARTIAL;
else if (txp->flags & XEN_NETTXF_data_validated)
@@ -1332,7 +1355,7 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue)
/* Called after netfront has transmitted */
int xenvif_tx_action(struct xenvif_queue *queue, int budget)
{
- unsigned nr_mops, nr_cops = 0;
+ unsigned nr_mops = 0, nr_cops = 0;
int work_done, ret;
if (unlikely(!tx_work_todo(queue)))
diff --git a/drivers/net/xen-netback/rx.c b/drivers/net/xen-netback/rx.c
index 932762177110..0ba754ebc5ba 100644
--- a/drivers/net/xen-netback/rx.c
+++ b/drivers/net/xen-netback/rx.c
@@ -82,9 +82,10 @@ static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
return false;
}
-void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
+bool xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
{
unsigned long flags;
+ bool ret = true;
spin_lock_irqsave(&queue->rx_queue.lock, flags);
@@ -92,8 +93,7 @@ void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
struct net_device *dev = queue->vif->dev;
netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id));
- kfree_skb(skb);
- queue->vif->dev->stats.rx_dropped++;
+ ret = false;
} else {
if (skb_queue_empty(&queue->rx_queue))
xenvif_update_needed_slots(queue, skb);
@@ -104,6 +104,8 @@ void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
}
spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
+
+ return ret;
}
static struct sk_buff *xenvif_rx_dequeue(struct xenvif_queue *queue)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 9af2b027c19c..dc404e05970c 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1862,6 +1862,12 @@ static int netfront_resume(struct xenbus_device *dev)
netif_tx_unlock_bh(info->netdev);
xennet_disconnect_backend(info);
+
+ rtnl_lock();
+ if (info->queues)
+ xennet_destroy_queues(info);
+ rtnl_unlock();
+
return 0;
}
diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c
index 24436c9e54c9..97600826af69 100644
--- a/drivers/nfc/nfcmrvl/i2c.c
+++ b/drivers/nfc/nfcmrvl/i2c.c
@@ -112,8 +112,10 @@ static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv,
struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;
int ret;
- if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags))
+ if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags)) {
+ kfree_skb(skb);
return -EREMOTEIO;
+ }
ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);
diff --git a/drivers/nfc/nxp-nci/core.c b/drivers/nfc/nxp-nci/core.c
index 580cb6ecffee..66b198663387 100644
--- a/drivers/nfc/nxp-nci/core.c
+++ b/drivers/nfc/nxp-nci/core.c
@@ -73,11 +73,15 @@ static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
struct nxp_nci_info *info = nci_get_drvdata(ndev);
int r;
- if (!info->phy_ops->write)
+ if (!info->phy_ops->write) {
+ kfree_skb(skb);
return -EOPNOTSUPP;
+ }
- if (info->mode != NXP_NCI_MODE_NCI)
+ if (info->mode != NXP_NCI_MODE_NCI) {
+ kfree_skb(skb);
return -EINVAL;
+ }
r = info->phy_ops->write(info->phy_id, skb);
if (r < 0) {
diff --git a/drivers/nfc/s3fwrn5/core.c b/drivers/nfc/s3fwrn5/core.c
index 0270e05b68df..aec356880adf 100644
--- a/drivers/nfc/s3fwrn5/core.c
+++ b/drivers/nfc/s3fwrn5/core.c
@@ -105,6 +105,7 @@ static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
mutex_lock(&info->mutex);
if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) {
+ kfree_skb(skb);
mutex_unlock(&info->mutex);
return -EINVAL;
}
diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c
index 7764b1a4c3cf..ec87dd21e054 100644
--- a/drivers/nfc/st-nci/se.c
+++ b/drivers/nfc/st-nci/se.c
@@ -312,6 +312,8 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
int r = 0;
struct device *dev = &ndev->nfc_dev->dev;
struct nfc_evt_transaction *transaction;
+ u32 aid_len;
+ u8 params_len;
pr_debug("connectivity gate event: %x\n", event);
@@ -325,26 +327,47 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
* Description Tag Length
* AID 81 5 to 16
* PARAMETERS 82 0 to 255
+ *
+ * The key differences are aid storage length is variably sized
+ * in the packet, but fixed in nfc_evt_transaction, and that
+ * the aid_len is u8 in the packet, but u32 in the structure,
+ * and the tags in the packet are not included in
+ * nfc_evt_transaction.
+ *
+ * size(b): 1 1 5-16 1 1 0-255
+ * offset: 0 1 2 aid_len + 2 aid_len + 3 aid_len + 4
+ * mem name: aid_tag(M) aid_len aid params_tag(M) params_len params
+ * example: 0x81 5-16 X 0x82 0-255 X
*/
- if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
- skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
+ if (skb->len < 2 || skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
return -EPROTO;
- transaction = devm_kzalloc(dev, skb->len - 2, GFP_KERNEL);
- if (!transaction)
- return -ENOMEM;
+ aid_len = skb->data[1];
- transaction->aid_len = skb->data[1];
- memcpy(transaction->aid, &skb->data[2], transaction->aid_len);
+ if (skb->len < aid_len + 4 ||
+ aid_len > sizeof(transaction->aid))
+ return -EPROTO;
- /* Check next byte is PARAMETERS tag (82) */
- if (skb->data[transaction->aid_len + 2] !=
- NFC_EVT_TRANSACTION_PARAMS_TAG)
+ params_len = skb->data[aid_len + 3];
+
+ /* Verify PARAMETERS tag is (82), and final check that there is
+ * enough space in the packet to read everything.
+ */
+ if (skb->data[aid_len + 2] != NFC_EVT_TRANSACTION_PARAMS_TAG ||
+ skb->len < aid_len + 4 + params_len)
return -EPROTO;
- transaction->params_len = skb->data[transaction->aid_len + 3];
- memcpy(transaction->params, skb->data +
- transaction->aid_len + 4, transaction->params_len);
+ transaction = devm_kzalloc(dev, sizeof(*transaction) +
+ params_len, GFP_KERNEL);
+ if (!transaction)
+ return -ENOMEM;
+
+ transaction->aid_len = aid_len;
+ transaction->params_len = params_len;
+
+ memcpy(transaction->aid, &skb->data[2], aid_len);
+ memcpy(transaction->params, &skb->data[aid_len + 4],
+ params_len);
r = nfc_se_transaction(ndev->nfc_dev, host, transaction);
break;
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
index 5a29046e3319..79d93126453d 100644
--- a/drivers/nvdimm/Kconfig
+++ b/drivers/nvdimm/Kconfig
@@ -114,4 +114,16 @@ config NVDIMM_TEST_BUILD
core devm_memremap_pages() implementation and other
infrastructure.
+config NVDIMM_SECURITY_TEST
+ bool "Enable NVDIMM security unit tests"
+ depends on NVDIMM_KEYS
+ help
+ The NVDIMM and CXL subsystems support unit testing of their device
+ security state machines. The NVDIMM_SECURITY_TEST option disables CPU
+ cache maintenance operations around events like secure erase and
+ overwrite. Also, when enabled, the NVDIMM subsystem core helps the unit
+ test implement a mock state machine.
+
+ Select N if unsure.
+
endif
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index c7c980577491..1fc081dcf631 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -349,11 +349,18 @@ static ssize_t available_slots_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_slots);
-__weak ssize_t security_show(struct device *dev,
+ssize_t security_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
+ /*
+ * For the test version we need to poll the "hardware" in order
+ * to get the updated status for unlock testing.
+ */
+ if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST))
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
+
if (test_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags))
return sprintf(buf, "overwrite\n");
if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index 390123d293ea..88dc062af5f8 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -2,6 +2,7 @@
/*
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
*/
+#include <linux/memregion.h>
#include <linux/cpumask.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -100,6 +101,16 @@ static void nd_region_remove(struct device *dev)
*/
sysfs_put(nd_region->bb_state);
nd_region->bb_state = NULL;
+
+ /*
+ * Try to flush caches here since a disabled region may be subject to
+ * secure erase while disabled, and previous dirty data should not be
+ * written back to a new instance of the region. This only matters on
+ * bare metal where security commands are available, so silent failure
+ * here is ok.
+ */
+ if (cpu_cache_has_invalidate_memregion())
+ cpu_cache_invalidate_memregion(IORES_DESC_PERSISTENT_MEMORY);
}
static int child_notify(struct device *dev, void *data)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e0875d369762..83dbf398ea84 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -59,9 +59,51 @@ static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
return 0;
}
+static int nd_region_invalidate_memregion(struct nd_region *nd_region)
+{
+ int i, incoherent = 0;
+
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+ if (test_bit(NDD_INCOHERENT, &nvdimm->flags)) {
+ incoherent++;
+ break;
+ }
+ }
+
+ if (!incoherent)
+ return 0;
+
+ if (!cpu_cache_has_invalidate_memregion()) {
+ if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST)) {
+ dev_warn(
+ &nd_region->dev,
+ "Bypassing cpu_cache_invalidate_memergion() for testing!\n");
+ goto out;
+ } else {
+ dev_err(&nd_region->dev,
+ "Failed to synchronize CPU cache state\n");
+ return -ENXIO;
+ }
+ }
+
+ cpu_cache_invalidate_memregion(IORES_DESC_PERSISTENT_MEMORY);
+out:
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+ clear_bit(NDD_INCOHERENT, &nvdimm->flags);
+ }
+
+ return 0;
+}
+
int nd_region_activate(struct nd_region *nd_region)
{
- int i, j, num_flush = 0;
+ int i, j, rc, num_flush = 0;
struct nd_region_data *ndrd;
struct device *dev = &nd_region->dev;
size_t flush_data_size = sizeof(void *);
@@ -85,6 +127,10 @@ int nd_region_activate(struct nd_region *nd_region)
}
nvdimm_bus_unlock(&nd_region->dev);
+ rc = nd_region_invalidate_memregion(nd_region);
+ if (rc)
+ return rc;
+
ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
if (!ndrd)
return -ENOMEM;
@@ -1222,3 +1268,5 @@ int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict);
}
+
+MODULE_IMPORT_NS(DEVMEM);
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c
index 8aefb60c42ff..a03e3c45f297 100644
--- a/drivers/nvdimm/security.c
+++ b/drivers/nvdimm/security.c
@@ -177,6 +177,10 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
|| !nvdimm->sec.flags)
return -EIO;
+ /* cxl_test needs this to pre-populate the security state */
+ if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST))
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
+
/* No need to go further if security is disabled */
if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
return 0;
@@ -204,6 +208,8 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
rc = nvdimm->sec.ops->unlock(nvdimm, data);
dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key),
rc == 0 ? "success" : "fail");
+ if (rc == 0)
+ set_bit(NDD_INCOHERENT, &nvdimm->flags);
nvdimm_put_key(key);
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
@@ -239,7 +245,8 @@ static int check_security_state(struct nvdimm *nvdimm)
return 0;
}
-static int security_disable(struct nvdimm *nvdimm, unsigned int keyid)
+static int security_disable(struct nvdimm *nvdimm, unsigned int keyid,
+ enum nvdimm_passphrase_type pass_type)
{
struct device *dev = &nvdimm->dev;
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
@@ -250,8 +257,13 @@ static int security_disable(struct nvdimm *nvdimm, unsigned int keyid)
/* The bus lock should be held at the top level of the call stack */
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
- if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable
- || !nvdimm->sec.flags)
+ if (!nvdimm->sec.ops || !nvdimm->sec.flags)
+ return -EOPNOTSUPP;
+
+ if (pass_type == NVDIMM_USER && !nvdimm->sec.ops->disable)
+ return -EOPNOTSUPP;
+
+ if (pass_type == NVDIMM_MASTER && !nvdimm->sec.ops->disable_master)
return -EOPNOTSUPP;
rc = check_security_state(nvdimm);
@@ -263,12 +275,21 @@ static int security_disable(struct nvdimm *nvdimm, unsigned int keyid)
if (!data)
return -ENOKEY;
- rc = nvdimm->sec.ops->disable(nvdimm, data);
- dev_dbg(dev, "key: %d disable: %s\n", key_serial(key),
+ if (pass_type == NVDIMM_MASTER) {
+ rc = nvdimm->sec.ops->disable_master(nvdimm, data);
+ dev_dbg(dev, "key: %d disable_master: %s\n", key_serial(key),
rc == 0 ? "success" : "fail");
+ } else {
+ rc = nvdimm->sec.ops->disable(nvdimm, data);
+ dev_dbg(dev, "key: %d disable: %s\n", key_serial(key),
+ rc == 0 ? "success" : "fail");
+ }
nvdimm_put_key(key);
- nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
+ if (pass_type == NVDIMM_MASTER)
+ nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
+ else
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc;
}
@@ -355,6 +376,8 @@ static int security_erase(struct nvdimm *nvdimm, unsigned int keyid,
return -ENOKEY;
rc = nvdimm->sec.ops->erase(nvdimm, data, pass_type);
+ if (rc == 0)
+ set_bit(NDD_INCOHERENT, &nvdimm->flags);
dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key),
pass_type == NVDIMM_MASTER ? "(master)" : "(user)",
rc == 0 ? "success" : "fail");
@@ -389,6 +412,8 @@ static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
return -ENOKEY;
rc = nvdimm->sec.ops->overwrite(nvdimm, data);
+ if (rc == 0)
+ set_bit(NDD_INCOHERENT, &nvdimm->flags);
dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key),
rc == 0 ? "success" : "fail");
@@ -473,6 +498,7 @@ void nvdimm_security_overwrite_query(struct work_struct *work)
#define OPS \
C( OP_FREEZE, "freeze", 1), \
C( OP_DISABLE, "disable", 2), \
+ C( OP_DISABLE_MASTER, "disable_master", 2), \
C( OP_UPDATE, "update", 3), \
C( OP_ERASE, "erase", 2), \
C( OP_OVERWRITE, "overwrite", 2), \
@@ -524,7 +550,10 @@ ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len)
rc = nvdimm_security_freeze(nvdimm);
} else if (i == OP_DISABLE) {
dev_dbg(dev, "disable %u\n", key);
- rc = security_disable(nvdimm, key);
+ rc = security_disable(nvdimm, key, NVDIMM_USER);
+ } else if (i == OP_DISABLE_MASTER) {
+ dev_dbg(dev, "disable_master %u\n", key);
+ rc = security_disable(nvdimm, key, NVDIMM_MASTER);
} else if (i == OP_UPDATE || i == OP_MASTER_UPDATE) {
dev_dbg(dev, "%s %u %u\n", ops[i].name, key, newkey);
rc = security_update(nvdimm, key, newkey, i == OP_UPDATE
diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c
index ff8b083dc5c6..e36aeb50b4ed 100644
--- a/drivers/nvme/host/apple.c
+++ b/drivers/nvme/host/apple.c
@@ -763,7 +763,7 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
goto out_free_cmd;
}
- blk_mq_start_request(req);
+ nvme_start_request(req);
apple_nvme_submit_cmd(q, cmnd);
return BLK_STS_OK;
@@ -821,7 +821,7 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
if (!dead && shutdown && freeze)
nvme_wait_freeze_timeout(&anv->ctrl, NVME_IO_TIMEOUT);
- nvme_stop_queues(&anv->ctrl);
+ nvme_quiesce_io_queues(&anv->ctrl);
if (!dead) {
if (READ_ONCE(anv->ioq.enabled)) {
@@ -829,15 +829,13 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
apple_nvme_remove_cq(anv);
}
- if (shutdown)
- nvme_shutdown_ctrl(&anv->ctrl);
- nvme_disable_ctrl(&anv->ctrl);
+ nvme_disable_ctrl(&anv->ctrl, shutdown);
}
WRITE_ONCE(anv->ioq.enabled, false);
WRITE_ONCE(anv->adminq.enabled, false);
mb(); /* ensure that nvme_queue_rq() sees that enabled is cleared */
- nvme_stop_admin_queue(&anv->ctrl);
+ nvme_quiesce_admin_queue(&anv->ctrl);
/* last chance to complete any requests before nvme_cancel_request */
spin_lock_irqsave(&anv->lock, flags);
@@ -854,8 +852,8 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
* deadlocking blk-mq hot-cpu notifier.
*/
if (shutdown) {
- nvme_start_queues(&anv->ctrl);
- nvme_start_admin_queue(&anv->ctrl);
+ nvme_unquiesce_io_queues(&anv->ctrl);
+ nvme_unquiesce_admin_queue(&anv->ctrl);
}
}
@@ -1093,7 +1091,7 @@ static void apple_nvme_reset_work(struct work_struct *work)
dev_dbg(anv->dev, "Starting admin queue");
apple_nvme_init_queue(&anv->adminq);
- nvme_start_admin_queue(&anv->ctrl);
+ nvme_unquiesce_admin_queue(&anv->ctrl);
if (!nvme_change_ctrl_state(&anv->ctrl, NVME_CTRL_CONNECTING)) {
dev_warn(anv->ctrl.device,
@@ -1102,7 +1100,7 @@ static void apple_nvme_reset_work(struct work_struct *work)
goto out;
}
- ret = nvme_init_ctrl_finish(&anv->ctrl);
+ ret = nvme_init_ctrl_finish(&anv->ctrl, false);
if (ret)
goto out;
@@ -1127,7 +1125,7 @@ static void apple_nvme_reset_work(struct work_struct *work)
anv->ctrl.queue_count = nr_io_queues + 1;
- nvme_start_queues(&anv->ctrl);
+ nvme_unquiesce_io_queues(&anv->ctrl);
nvme_wait_freeze(&anv->ctrl);
blk_mq_update_nr_hw_queues(&anv->tagset, 1);
nvme_unfreeze(&anv->ctrl);
@@ -1153,7 +1151,7 @@ out:
nvme_change_ctrl_state(&anv->ctrl, NVME_CTRL_DELETING);
nvme_get_ctrl(&anv->ctrl);
apple_nvme_disable(anv, false);
- nvme_kill_queues(&anv->ctrl);
+ nvme_mark_namespaces_dead(&anv->ctrl);
if (!queue_work(nvme_wq, &anv->remove_work))
nvme_put_ctrl(&anv->ctrl);
}
@@ -1507,14 +1505,6 @@ static int apple_nvme_probe(struct platform_device *pdev)
goto put_dev;
}
- if (!blk_get_queue(anv->ctrl.admin_q)) {
- nvme_start_admin_queue(&anv->ctrl);
- blk_mq_destroy_queue(anv->ctrl.admin_q);
- anv->ctrl.admin_q = NULL;
- ret = -ENODEV;
- goto put_dev;
- }
-
nvme_reset_ctrl(&anv->ctrl);
async_schedule(apple_nvme_async_probe, anv);
diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index c8a6db7c4498..bb0abbe4491c 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -13,6 +13,10 @@
#include "fabrics.h"
#include <linux/nvme-auth.h>
+#define CHAP_BUF_SIZE 4096
+static struct kmem_cache *nvme_chap_buf_cache;
+static mempool_t *nvme_chap_buf_pool;
+
struct nvme_dhchap_queue_context {
struct list_head entry;
struct work_struct auth_work;
@@ -20,7 +24,6 @@ struct nvme_dhchap_queue_context {
struct crypto_shash *shash_tfm;
struct crypto_kpp *dh_tfm;
void *buf;
- size_t buf_size;
int qid;
int error;
u32 s1;
@@ -47,6 +50,12 @@ struct nvme_dhchap_queue_context {
#define nvme_auth_queue_from_qid(ctrl, qid) \
(qid == 0) ? (ctrl)->fabrics_q : (ctrl)->connect_q
+static inline int ctrl_max_dhchaps(struct nvme_ctrl *ctrl)
+{
+ return ctrl->opts->nr_io_queues + ctrl->opts->nr_write_queues +
+ ctrl->opts->nr_poll_queues + 1;
+}
+
static int nvme_auth_submit(struct nvme_ctrl *ctrl, int qid,
void *data, size_t data_len, bool auth_send)
{
@@ -112,7 +121,7 @@ static int nvme_auth_set_dhchap_negotiate_data(struct nvme_ctrl *ctrl,
struct nvmf_auth_dhchap_negotiate_data *data = chap->buf;
size_t size = sizeof(*data) + sizeof(union nvmf_auth_protocol);
- if (chap->buf_size < size) {
+ if (size > CHAP_BUF_SIZE) {
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return -EINVAL;
}
@@ -147,7 +156,7 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl,
const char *gid_name = nvme_auth_dhgroup_name(data->dhgid);
const char *hmac_name, *kpp_name;
- if (chap->buf_size < size) {
+ if (size > CHAP_BUF_SIZE) {
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return NVME_SC_INVALID_FIELD;
}
@@ -197,12 +206,6 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl,
return NVME_SC_AUTH_REQUIRED;
}
- /* Reset host response if the hash had been changed */
- if (chap->hash_id != data->hashid) {
- kfree(chap->host_response);
- chap->host_response = NULL;
- }
-
chap->hash_id = data->hashid;
chap->hash_len = data->hl;
dev_dbg(ctrl->device, "qid %d: selected hash %s\n",
@@ -219,14 +222,6 @@ select_kpp:
return NVME_SC_AUTH_REQUIRED;
}
- /* Clear host and controller key to avoid accidental reuse */
- kfree_sensitive(chap->host_key);
- chap->host_key = NULL;
- chap->host_key_len = 0;
- kfree_sensitive(chap->ctrl_key);
- chap->ctrl_key = NULL;
- chap->ctrl_key_len = 0;
-
if (chap->dhgroup_id == data->dhgid &&
(data->dhgid == NVME_AUTH_DHGROUP_NULL || chap->dh_tfm)) {
dev_dbg(ctrl->device,
@@ -302,7 +297,7 @@ static int nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
if (chap->host_key_len)
size += chap->host_key_len;
- if (chap->buf_size < size) {
+ if (size > CHAP_BUF_SIZE) {
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return -EINVAL;
}
@@ -344,10 +339,10 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl,
struct nvmf_auth_dhchap_success1_data *data = chap->buf;
size_t size = sizeof(*data);
- if (ctrl->ctrl_key)
+ if (chap->ctrl_key)
size += chap->hash_len;
- if (chap->buf_size < size) {
+ if (size > CHAP_BUF_SIZE) {
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return NVME_SC_INVALID_FIELD;
}
@@ -521,6 +516,7 @@ static int nvme_auth_dhchap_setup_ctrl_response(struct nvme_ctrl *ctrl,
ret = PTR_ERR(ctrl_response);
return ret;
}
+
ret = crypto_shash_setkey(chap->shash_tfm,
ctrl_response, ctrl->ctrl_key->len);
if (ret) {
@@ -621,9 +617,6 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
if (ret) {
dev_dbg(ctrl->device,
"failed to generate public key, error %d\n", ret);
- kfree(chap->host_key);
- chap->host_key = NULL;
- chap->host_key_len = 0;
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return ret;
}
@@ -643,9 +636,6 @@ gen_sesskey:
if (ret) {
dev_dbg(ctrl->device,
"failed to generate shared secret, error %d\n", ret);
- kfree_sensitive(chap->sess_key);
- chap->sess_key = NULL;
- chap->sess_key_len = 0;
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return ret;
}
@@ -654,7 +644,7 @@ gen_sesskey:
return 0;
}
-static void __nvme_auth_reset(struct nvme_dhchap_queue_context *chap)
+static void nvme_auth_reset_dhchap(struct nvme_dhchap_queue_context *chap)
{
kfree_sensitive(chap->host_response);
chap->host_response = NULL;
@@ -674,24 +664,20 @@ static void __nvme_auth_reset(struct nvme_dhchap_queue_context *chap)
chap->transaction = 0;
memset(chap->c1, 0, sizeof(chap->c1));
memset(chap->c2, 0, sizeof(chap->c2));
+ mempool_free(chap->buf, nvme_chap_buf_pool);
+ chap->buf = NULL;
}
-static void __nvme_auth_free(struct nvme_dhchap_queue_context *chap)
+static void nvme_auth_free_dhchap(struct nvme_dhchap_queue_context *chap)
{
- __nvme_auth_reset(chap);
+ nvme_auth_reset_dhchap(chap);
if (chap->shash_tfm)
crypto_free_shash(chap->shash_tfm);
if (chap->dh_tfm)
crypto_free_kpp(chap->dh_tfm);
- kfree_sensitive(chap->ctrl_key);
- kfree_sensitive(chap->host_key);
- kfree_sensitive(chap->sess_key);
- kfree_sensitive(chap->host_response);
- kfree(chap->buf);
- kfree(chap);
}
-static void __nvme_auth_work(struct work_struct *work)
+static void nvme_queue_auth_work(struct work_struct *work)
{
struct nvme_dhchap_queue_context *chap =
container_of(work, struct nvme_dhchap_queue_context, auth_work);
@@ -699,6 +685,16 @@ static void __nvme_auth_work(struct work_struct *work)
size_t tl;
int ret = 0;
+ /*
+ * Allocate a large enough buffer for the entire negotiation:
+ * 4k is enough to ffdhe8192.
+ */
+ chap->buf = mempool_alloc(nvme_chap_buf_pool, GFP_KERNEL);
+ if (!chap->buf) {
+ chap->error = -ENOMEM;
+ return;
+ }
+
chap->transaction = ctrl->transaction++;
/* DH-HMAC-CHAP Step 1: send negotiate */
@@ -720,8 +716,9 @@ static void __nvme_auth_work(struct work_struct *work)
dev_dbg(ctrl->device, "%s: qid %d receive challenge\n",
__func__, chap->qid);
- memset(chap->buf, 0, chap->buf_size);
- ret = nvme_auth_submit(ctrl, chap->qid, chap->buf, chap->buf_size, false);
+ memset(chap->buf, 0, CHAP_BUF_SIZE);
+ ret = nvme_auth_submit(ctrl, chap->qid, chap->buf, CHAP_BUF_SIZE,
+ false);
if (ret) {
dev_warn(ctrl->device,
"qid %d failed to receive challenge, %s %d\n",
@@ -757,11 +754,14 @@ static void __nvme_auth_work(struct work_struct *work)
dev_dbg(ctrl->device, "%s: qid %d host response\n",
__func__, chap->qid);
+ mutex_lock(&ctrl->dhchap_auth_mutex);
ret = nvme_auth_dhchap_setup_host_response(ctrl, chap);
if (ret) {
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
chap->error = ret;
goto fail2;
}
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
/* DH-HMAC-CHAP Step 3: send reply */
dev_dbg(ctrl->device, "%s: qid %d send reply\n",
@@ -783,8 +783,9 @@ static void __nvme_auth_work(struct work_struct *work)
dev_dbg(ctrl->device, "%s: qid %d receive success1\n",
__func__, chap->qid);
- memset(chap->buf, 0, chap->buf_size);
- ret = nvme_auth_submit(ctrl, chap->qid, chap->buf, chap->buf_size, false);
+ memset(chap->buf, 0, CHAP_BUF_SIZE);
+ ret = nvme_auth_submit(ctrl, chap->qid, chap->buf, CHAP_BUF_SIZE,
+ false);
if (ret) {
dev_warn(ctrl->device,
"qid %d failed to receive success1, %s %d\n",
@@ -801,16 +802,19 @@ static void __nvme_auth_work(struct work_struct *work)
return;
}
+ mutex_lock(&ctrl->dhchap_auth_mutex);
if (ctrl->ctrl_key) {
dev_dbg(ctrl->device,
"%s: qid %d controller response\n",
__func__, chap->qid);
ret = nvme_auth_dhchap_setup_ctrl_response(ctrl, chap);
if (ret) {
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
chap->error = ret;
goto fail2;
}
}
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
ret = nvme_auth_process_dhchap_success1(ctrl, chap);
if (ret) {
@@ -819,7 +823,7 @@ static void __nvme_auth_work(struct work_struct *work)
goto fail2;
}
- if (ctrl->ctrl_key) {
+ if (chap->ctrl_key) {
/* DH-HMAC-CHAP Step 5: send success2 */
dev_dbg(ctrl->device, "%s: qid %d send success2\n",
__func__, chap->qid);
@@ -860,42 +864,8 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
return -ENOKEY;
}
- mutex_lock(&ctrl->dhchap_auth_mutex);
- /* Check if the context is already queued */
- list_for_each_entry(chap, &ctrl->dhchap_auth_list, entry) {
- WARN_ON(!chap->buf);
- if (chap->qid == qid) {
- dev_dbg(ctrl->device, "qid %d: re-using context\n", qid);
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- flush_work(&chap->auth_work);
- __nvme_auth_reset(chap);
- queue_work(nvme_wq, &chap->auth_work);
- return 0;
- }
- }
- chap = kzalloc(sizeof(*chap), GFP_KERNEL);
- if (!chap) {
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- return -ENOMEM;
- }
- chap->qid = (qid == NVME_QID_ANY) ? 0 : qid;
- chap->ctrl = ctrl;
-
- /*
- * Allocate a large enough buffer for the entire negotiation:
- * 4k should be enough to ffdhe8192.
- */
- chap->buf_size = 4096;
- chap->buf = kzalloc(chap->buf_size, GFP_KERNEL);
- if (!chap->buf) {
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- kfree(chap);
- return -ENOMEM;
- }
-
- INIT_WORK(&chap->auth_work, __nvme_auth_work);
- list_add(&chap->entry, &ctrl->dhchap_auth_list);
- mutex_unlock(&ctrl->dhchap_auth_mutex);
+ chap = &ctrl->dhchap_ctxs[qid];
+ cancel_work_sync(&chap->auth_work);
queue_work(nvme_wq, &chap->auth_work);
return 0;
}
@@ -906,40 +876,28 @@ int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid)
struct nvme_dhchap_queue_context *chap;
int ret;
- mutex_lock(&ctrl->dhchap_auth_mutex);
- list_for_each_entry(chap, &ctrl->dhchap_auth_list, entry) {
- if (chap->qid != qid)
- continue;
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- flush_work(&chap->auth_work);
- ret = chap->error;
- return ret;
- }
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- return -ENXIO;
+ chap = &ctrl->dhchap_ctxs[qid];
+ flush_work(&chap->auth_work);
+ ret = chap->error;
+ /* clear sensitive info */
+ nvme_auth_reset_dhchap(chap);
+ return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_wait);
-void nvme_auth_reset(struct nvme_ctrl *ctrl)
-{
- struct nvme_dhchap_queue_context *chap;
-
- mutex_lock(&ctrl->dhchap_auth_mutex);
- list_for_each_entry(chap, &ctrl->dhchap_auth_list, entry) {
- mutex_unlock(&ctrl->dhchap_auth_mutex);
- flush_work(&chap->auth_work);
- __nvme_auth_reset(chap);
- }
- mutex_unlock(&ctrl->dhchap_auth_mutex);
-}
-EXPORT_SYMBOL_GPL(nvme_auth_reset);
-
-static void nvme_dhchap_auth_work(struct work_struct *work)
+static void nvme_ctrl_auth_work(struct work_struct *work)
{
struct nvme_ctrl *ctrl =
container_of(work, struct nvme_ctrl, dhchap_auth_work);
int ret, q;
+ /*
+ * If the ctrl is no connected, bail as reconnect will handle
+ * authentication.
+ */
+ if (ctrl->state != NVME_CTRL_LIVE)
+ return;
+
/* Authenticate admin queue first */
ret = nvme_auth_negotiate(ctrl, 0);
if (ret) {
@@ -968,43 +926,75 @@ static void nvme_dhchap_auth_work(struct work_struct *work)
* Failure is a soft-state; credentials remain valid until
* the controller terminates the connection.
*/
+ for (q = 1; q < ctrl->queue_count; q++) {
+ ret = nvme_auth_wait(ctrl, q);
+ if (ret)
+ dev_warn(ctrl->device,
+ "qid %d: authentication failed\n", q);
+ }
}
-void nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
+int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
{
- INIT_LIST_HEAD(&ctrl->dhchap_auth_list);
- INIT_WORK(&ctrl->dhchap_auth_work, nvme_dhchap_auth_work);
+ struct nvme_dhchap_queue_context *chap;
+ int i, ret;
+
mutex_init(&ctrl->dhchap_auth_mutex);
+ INIT_WORK(&ctrl->dhchap_auth_work, nvme_ctrl_auth_work);
if (!ctrl->opts)
- return;
- nvme_auth_generate_key(ctrl->opts->dhchap_secret, &ctrl->host_key);
- nvme_auth_generate_key(ctrl->opts->dhchap_ctrl_secret, &ctrl->ctrl_key);
+ return 0;
+ ret = nvme_auth_generate_key(ctrl->opts->dhchap_secret,
+ &ctrl->host_key);
+ if (ret)
+ return ret;
+ ret = nvme_auth_generate_key(ctrl->opts->dhchap_ctrl_secret,
+ &ctrl->ctrl_key);
+ if (ret)
+ goto err_free_dhchap_secret;
+
+ if (!ctrl->opts->dhchap_secret && !ctrl->opts->dhchap_ctrl_secret)
+ return ret;
+
+ ctrl->dhchap_ctxs = kvcalloc(ctrl_max_dhchaps(ctrl),
+ sizeof(*chap), GFP_KERNEL);
+ if (!ctrl->dhchap_ctxs) {
+ ret = -ENOMEM;
+ goto err_free_dhchap_ctrl_secret;
+ }
+
+ for (i = 0; i < ctrl_max_dhchaps(ctrl); i++) {
+ chap = &ctrl->dhchap_ctxs[i];
+ chap->qid = i;
+ chap->ctrl = ctrl;
+ INIT_WORK(&chap->auth_work, nvme_queue_auth_work);
+ }
+
+ return 0;
+err_free_dhchap_ctrl_secret:
+ nvme_auth_free_key(ctrl->ctrl_key);
+ ctrl->ctrl_key = NULL;
+err_free_dhchap_secret:
+ nvme_auth_free_key(ctrl->host_key);
+ ctrl->host_key = NULL;
+ return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_init_ctrl);
void nvme_auth_stop(struct nvme_ctrl *ctrl)
{
- struct nvme_dhchap_queue_context *chap = NULL, *tmp;
-
cancel_work_sync(&ctrl->dhchap_auth_work);
- mutex_lock(&ctrl->dhchap_auth_mutex);
- list_for_each_entry_safe(chap, tmp, &ctrl->dhchap_auth_list, entry)
- cancel_work_sync(&chap->auth_work);
- mutex_unlock(&ctrl->dhchap_auth_mutex);
}
EXPORT_SYMBOL_GPL(nvme_auth_stop);
void nvme_auth_free(struct nvme_ctrl *ctrl)
{
- struct nvme_dhchap_queue_context *chap = NULL, *tmp;
+ int i;
- mutex_lock(&ctrl->dhchap_auth_mutex);
- list_for_each_entry_safe(chap, tmp, &ctrl->dhchap_auth_list, entry) {
- list_del_init(&chap->entry);
- flush_work(&chap->auth_work);
- __nvme_auth_free(chap);
+ if (ctrl->dhchap_ctxs) {
+ for (i = 0; i < ctrl_max_dhchaps(ctrl); i++)
+ nvme_auth_free_dhchap(&ctrl->dhchap_ctxs[i]);
+ kfree(ctrl->dhchap_ctxs);
}
- mutex_unlock(&ctrl->dhchap_auth_mutex);
if (ctrl->host_key) {
nvme_auth_free_key(ctrl->host_key);
ctrl->host_key = NULL;
@@ -1015,3 +1005,27 @@ void nvme_auth_free(struct nvme_ctrl *ctrl)
}
}
EXPORT_SYMBOL_GPL(nvme_auth_free);
+
+int __init nvme_init_auth(void)
+{
+ nvme_chap_buf_cache = kmem_cache_create("nvme-chap-buf-cache",
+ CHAP_BUF_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!nvme_chap_buf_cache)
+ return -ENOMEM;
+
+ nvme_chap_buf_pool = mempool_create(16, mempool_alloc_slab,
+ mempool_free_slab, nvme_chap_buf_cache);
+ if (!nvme_chap_buf_pool)
+ goto err_destroy_chap_buf_cache;
+
+ return 0;
+err_destroy_chap_buf_cache:
+ kmem_cache_destroy(nvme_chap_buf_cache);
+ return -ENOMEM;
+}
+
+void __exit nvme_exit_auth(void)
+{
+ mempool_destroy(nvme_chap_buf_pool);
+ kmem_cache_destroy(nvme_chap_buf_cache);
+}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index dc4220600585..e26b085a007a 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -384,6 +384,8 @@ static inline void nvme_end_req(struct request *req)
nvme_log_error(req);
nvme_end_req_zoned(req);
nvme_trace_bio_complete(req);
+ if (req->cmd_flags & REQ_NVME_MPATH)
+ nvme_mpath_end_request(req);
blk_mq_end_request(req, status);
}
@@ -675,6 +677,7 @@ void nvme_init_request(struct request *req, struct nvme_command *cmd)
if (req->mq_hctx->type == HCTX_TYPE_POLL)
req->cmd_flags |= REQ_POLLED;
nvme_clear_nvme_request(req);
+ req->rq_flags |= RQF_QUIET;
memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd));
}
EXPORT_SYMBOL_GPL(nvme_init_request);
@@ -850,8 +853,11 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
cmnd->write_zeroes.length =
cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
+ if (!(req->cmd_flags & REQ_NOUNMAP) && (ns->features & NVME_NS_DEAC))
+ cmnd->write_zeroes.control |= cpu_to_le16(NVME_WZ_DEAC);
+
if (nvme_ns_has_pi(ns)) {
- cmnd->write_zeroes.control = cpu_to_le16(NVME_RW_PRINFO_PRACT);
+ cmnd->write_zeroes.control |= cpu_to_le16(NVME_RW_PRINFO_PRACT);
switch (ns->pi_type) {
case NVME_NS_DPS_PI_TYPE1:
@@ -1037,7 +1043,6 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
goto out;
}
- req->rq_flags |= RQF_QUIET;
ret = nvme_execute_rq(req, at_head);
if (result && ret >= 0)
*result = nvme_req(req)->result;
@@ -1118,11 +1123,12 @@ void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects,
nvme_unfreeze(ctrl);
nvme_mpath_unfreeze(ctrl->subsys);
mutex_unlock(&ctrl->subsys->lock);
- nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL);
mutex_unlock(&ctrl->scan_lock);
}
- if (effects & NVME_CMD_EFFECTS_CCC)
- nvme_init_ctrl_finish(ctrl);
+ if (effects & NVME_CMD_EFFECTS_CCC) {
+ dev_info(ctrl->device,
+"controller capabilities changed, reset may be required to take effect.\n");
+ }
if (effects & (NVME_CMD_EFFECTS_NIC | NVME_CMD_EFFECTS_NCC)) {
nvme_queue_scan(ctrl);
flush_work(&ctrl->scan_work);
@@ -1227,7 +1233,6 @@ static void nvme_keep_alive_work(struct work_struct *work)
rq->timeout = ctrl->kato * HZ;
rq->end_io = nvme_keep_alive_end_io;
rq->end_io_data = ctrl;
- rq->rq_flags |= RQF_QUIET;
blk_execute_rq_nowait(rq, false);
}
@@ -2004,6 +2009,14 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
}
}
+ /*
+ * Only set the DEAC bit if the device guarantees that reads from
+ * deallocated data return zeroes. While the DEAC bit does not
+ * require that, it must be a no-op if reads from deallocated data
+ * do not return zeroes.
+ */
+ if ((id->dlfeat & 0x7) == 0x1 && (id->dlfeat & (1 << 3)))
+ ns->features |= NVME_NS_DEAC;
set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
set_bit(NVME_NS_READY, &ns->flags);
blk_mq_unfreeze_queue(ns->disk->queue);
@@ -2180,7 +2193,7 @@ const struct pr_ops nvme_pr_ops = {
};
#ifdef CONFIG_BLK_SED_OPAL
-int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+static int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
bool send)
{
struct nvme_ctrl *ctrl = data;
@@ -2197,7 +2210,23 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
NVME_QID_ANY, 1, 0);
}
-EXPORT_SYMBOL_GPL(nvme_sec_submit);
+
+static void nvme_configure_opal(struct nvme_ctrl *ctrl, bool was_suspended)
+{
+ if (ctrl->oacs & NVME_CTRL_OACS_SEC_SUPP) {
+ if (!ctrl->opal_dev)
+ ctrl->opal_dev = init_opal_dev(ctrl, &nvme_sec_submit);
+ else if (was_suspended)
+ opal_unlock_from_suspend(ctrl->opal_dev);
+ } else {
+ free_opal_dev(ctrl->opal_dev);
+ ctrl->opal_dev = NULL;
+ }
+}
+#else
+static void nvme_configure_opal(struct nvme_ctrl *ctrl, bool was_suspended)
+{
+}
#endif /* CONFIG_BLK_SED_OPAL */
#ifdef CONFIG_BLK_DEV_ZONED
@@ -2222,16 +2251,17 @@ static const struct block_device_operations nvme_bdev_ops = {
.pr_ops = &nvme_pr_ops,
};
-static int nvme_wait_ready(struct nvme_ctrl *ctrl, u32 timeout, bool enabled)
+static int nvme_wait_ready(struct nvme_ctrl *ctrl, u32 mask, u32 val,
+ u32 timeout, const char *op)
{
- unsigned long timeout_jiffies = ((timeout + 1) * HZ / 2) + jiffies;
- u32 csts, bit = enabled ? NVME_CSTS_RDY : 0;
+ unsigned long timeout_jiffies = jiffies + timeout * HZ;
+ u32 csts;
int ret;
while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) {
if (csts == ~0)
return -ENODEV;
- if ((csts & NVME_CSTS_RDY) == bit)
+ if ((csts & mask) == val)
break;
usleep_range(1000, 2000);
@@ -2240,7 +2270,7 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u32 timeout, bool enabled)
if (time_after(jiffies, timeout_jiffies)) {
dev_err(ctrl->device,
"Device not ready; aborting %s, CSTS=0x%x\n",
- enabled ? "initialisation" : "reset", csts);
+ op, csts);
return -ENODEV;
}
}
@@ -2248,27 +2278,29 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u32 timeout, bool enabled)
return ret;
}
-/*
- * If the device has been passed off to us in an enabled state, just clear
- * the enabled bit. The spec says we should set the 'shutdown notification
- * bits', but doing so may cause the device to complete commands to the
- * admin queue ... and we don't know what memory that might be pointing at!
- */
-int nvme_disable_ctrl(struct nvme_ctrl *ctrl)
+int nvme_disable_ctrl(struct nvme_ctrl *ctrl, bool shutdown)
{
int ret;
ctrl->ctrl_config &= ~NVME_CC_SHN_MASK;
- ctrl->ctrl_config &= ~NVME_CC_ENABLE;
+ if (shutdown)
+ ctrl->ctrl_config |= NVME_CC_SHN_NORMAL;
+ else
+ ctrl->ctrl_config &= ~NVME_CC_ENABLE;
ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
if (ret)
return ret;
+ if (shutdown) {
+ return nvme_wait_ready(ctrl, NVME_CSTS_SHST_MASK,
+ NVME_CSTS_SHST_CMPLT,
+ ctrl->shutdown_timeout, "shutdown");
+ }
if (ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY)
msleep(NVME_QUIRK_DELAY_AMOUNT);
-
- return nvme_wait_ready(ctrl, NVME_CAP_TIMEOUT(ctrl->cap), false);
+ return nvme_wait_ready(ctrl, NVME_CSTS_RDY, 0,
+ (NVME_CAP_TIMEOUT(ctrl->cap) + 1) / 2, "reset");
}
EXPORT_SYMBOL_GPL(nvme_disable_ctrl);
@@ -2333,41 +2365,11 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl)
ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
if (ret)
return ret;
- return nvme_wait_ready(ctrl, timeout, true);
+ return nvme_wait_ready(ctrl, NVME_CSTS_RDY, NVME_CSTS_RDY,
+ (timeout + 1) / 2, "initialisation");
}
EXPORT_SYMBOL_GPL(nvme_enable_ctrl);
-int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl)
-{
- unsigned long timeout = jiffies + (ctrl->shutdown_timeout * HZ);
- u32 csts;
- int ret;
-
- ctrl->ctrl_config &= ~NVME_CC_SHN_MASK;
- ctrl->ctrl_config |= NVME_CC_SHN_NORMAL;
-
- ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
- if (ret)
- return ret;
-
- while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) {
- if ((csts & NVME_CSTS_SHST_MASK) == NVME_CSTS_SHST_CMPLT)
- break;
-
- msleep(100);
- if (fatal_signal_pending(current))
- return -EINTR;
- if (time_after(jiffies, timeout)) {
- dev_err(ctrl->device,
- "Device shutdown incomplete; abort shutdown\n");
- return -ENODEV;
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(nvme_shutdown_ctrl);
-
static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)
{
__le64 ts;
@@ -3050,7 +3052,7 @@ static int nvme_init_non_mdts_limits(struct nvme_ctrl *ctrl)
id = kzalloc(sizeof(*id), GFP_KERNEL);
if (!id)
- return 0;
+ return -ENOMEM;
c.identify.opcode = nvme_admin_identify;
c.identify.cns = NVME_ID_CNS_CS_CTRL;
@@ -3096,10 +3098,6 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
if (!ctrl->identified) {
unsigned int i;
- ret = nvme_init_subsystem(ctrl, id);
- if (ret)
- goto out_free;
-
/*
* Check for quirks. Quirk can depend on firmware version,
* so, in principle, the set of quirks present can change
@@ -3112,6 +3110,10 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
if (quirk_matches(id, &core_quirks[i]))
ctrl->quirks |= core_quirks[i].quirks;
}
+
+ ret = nvme_init_subsystem(ctrl, id);
+ if (ret)
+ goto out_free;
}
memcpy(ctrl->subsys->firmware_rev, id->fr,
sizeof(ctrl->subsys->firmware_rev));
@@ -3230,7 +3232,7 @@ out_free:
* register in our nvme_ctrl structure. This should be called as soon as
* the admin queue is fully up and running.
*/
-int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)
+int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl, bool was_suspended)
{
int ret;
@@ -3261,6 +3263,8 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)
if (ret < 0)
return ret;
+ nvme_configure_opal(ctrl, was_suspended);
+
if (!ctrl->identified && !nvme_discovery_ctrl(ctrl)) {
/*
* Do not return errors unless we are in a controller reset,
@@ -3746,15 +3750,19 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
memcpy(dhchap_secret, buf, count);
nvme_auth_stop(ctrl);
if (strcmp(dhchap_secret, opts->dhchap_secret)) {
+ struct nvme_dhchap_key *key, *host_key;
int ret;
- ret = nvme_auth_generate_key(dhchap_secret, &ctrl->host_key);
+ ret = nvme_auth_generate_key(dhchap_secret, &key);
if (ret)
return ret;
kfree(opts->dhchap_secret);
opts->dhchap_secret = dhchap_secret;
- /* Key has changed; re-authentication with new key */
- nvme_auth_reset(ctrl);
+ host_key = ctrl->host_key;
+ mutex_lock(&ctrl->dhchap_auth_mutex);
+ ctrl->host_key = key;
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
+ nvme_auth_free_key(host_key);
}
/* Start re-authentication */
dev_info(ctrl->device, "re-authenticating controller\n");
@@ -3796,15 +3804,19 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
memcpy(dhchap_secret, buf, count);
nvme_auth_stop(ctrl);
if (strcmp(dhchap_secret, opts->dhchap_ctrl_secret)) {
+ struct nvme_dhchap_key *key, *ctrl_key;
int ret;
- ret = nvme_auth_generate_key(dhchap_secret, &ctrl->ctrl_key);
+ ret = nvme_auth_generate_key(dhchap_secret, &key);
if (ret)
return ret;
kfree(opts->dhchap_ctrl_secret);
opts->dhchap_ctrl_secret = dhchap_secret;
- /* Key has changed; re-authentication with new key */
- nvme_auth_reset(ctrl);
+ ctrl_key = ctrl->ctrl_key;
+ mutex_lock(&ctrl->dhchap_auth_mutex);
+ ctrl->ctrl_key = key;
+ mutex_unlock(&ctrl->dhchap_auth_mutex);
+ nvme_auth_free_key(ctrl_key);
}
/* Start re-authentication */
dev_info(ctrl->device, "re-authenticating controller\n");
@@ -3876,10 +3888,11 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
return a->mode;
}
-static const struct attribute_group nvme_dev_attrs_group = {
+const struct attribute_group nvme_dev_attrs_group = {
.attrs = nvme_dev_attrs,
.is_visible = nvme_dev_attrs_are_visible,
};
+EXPORT_SYMBOL_GPL(nvme_dev_attrs_group);
static const struct attribute_group *nvme_dev_attr_groups[] = {
&nvme_dev_attrs_group,
@@ -4305,7 +4318,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
mutex_unlock(&ns->ctrl->subsys->lock);
/* guarantee not available in head->list */
- synchronize_rcu();
+ synchronize_srcu(&ns->head->srcu);
if (!nvme_ns_head_multipath(ns->head))
nvme_cdev_del(&ns->cdev, &ns->cdev_device);
@@ -4334,10 +4347,6 @@ static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_info *info)
{
int ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
- if (test_bit(NVME_NS_DEAD, &ns->flags))
- goto out;
-
- ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
if (!nvme_ns_ids_equal(&ns->head->ids, &info->ids)) {
dev_err(ns->ctrl->device,
"identifiers changed for nsid %d\n", ns->head->ns_id);
@@ -4408,7 +4417,7 @@ static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
down_write(&ctrl->namespaces_rwsem);
list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) {
- if (ns->head->ns_id > nsid || test_bit(NVME_NS_DEAD, &ns->flags))
+ if (ns->head->ns_id > nsid)
list_move_tail(&ns->list, &rm_list);
}
up_write(&ctrl->namespaces_rwsem);
@@ -4425,9 +4434,6 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl)
u32 prev = 0;
int ret = 0, i;
- if (nvme_ctrl_limited_cns(ctrl))
- return -EOPNOTSUPP;
-
ns_list = kzalloc(NVME_IDENTIFY_DATA_SIZE, GFP_KERNEL);
if (!ns_list)
return -ENOMEM;
@@ -4535,8 +4541,18 @@ static void nvme_scan_work(struct work_struct *work)
}
mutex_lock(&ctrl->scan_lock);
- if (nvme_scan_ns_list(ctrl) != 0)
+ if (nvme_ctrl_limited_cns(ctrl)) {
nvme_scan_ns_sequential(ctrl);
+ } else {
+ /*
+ * Fall back to sequential scan if DNR is set to handle broken
+ * devices which should support Identify NS List (as per the VS
+ * they report) but don't actually support it.
+ */
+ ret = nvme_scan_ns_list(ctrl);
+ if (ret > 0 && ret & NVME_SC_DNR)
+ nvme_scan_ns_sequential(ctrl);
+ }
mutex_unlock(&ctrl->scan_lock);
}
@@ -4566,8 +4582,10 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
* removing the namespaces' disks; fail all the queues now to avoid
* potentially having to clean up the failed sync later.
*/
- if (ctrl->state == NVME_CTRL_DEAD)
- nvme_kill_queues(ctrl);
+ if (ctrl->state == NVME_CTRL_DEAD) {
+ nvme_mark_namespaces_dead(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
+ }
/* this is a no-op when called from the controller reset handler */
nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING_NOIO);
@@ -4693,7 +4711,7 @@ static void nvme_fw_act_work(struct work_struct *work)
fw_act_timeout = jiffies +
msecs_to_jiffies(admin_timeout * 1000);
- nvme_stop_queues(ctrl);
+ nvme_quiesce_io_queues(ctrl);
while (nvme_ctrl_pp_status(ctrl)) {
if (time_after(jiffies, fw_act_timeout)) {
dev_warn(ctrl->device,
@@ -4707,7 +4725,7 @@ static void nvme_fw_act_work(struct work_struct *work)
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE))
return;
- nvme_start_queues(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
/* read FW slot information to clear the AER */
nvme_get_fw_slot_info(ctrl);
@@ -4812,8 +4830,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
EXPORT_SYMBOL_GPL(nvme_complete_async_event);
int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
- const struct blk_mq_ops *ops, unsigned int flags,
- unsigned int cmd_size)
+ const struct blk_mq_ops *ops, unsigned int cmd_size)
{
int ret;
@@ -4823,7 +4840,9 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
if (ctrl->ops->flags & NVME_F_FABRICS)
set->reserved_tags = NVMF_RESERVED_TAGS;
set->numa_node = ctrl->numa_node;
- set->flags = flags;
+ set->flags = BLK_MQ_F_NO_SCHED;
+ if (ctrl->ops->flags & NVME_F_BLOCKING)
+ set->flags |= BLK_MQ_F_BLOCKING;
set->cmd_size = cmd_size;
set->driver_data = ctrl;
set->nr_hw_queues = 1;
@@ -4851,6 +4870,7 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
out_cleanup_admin_q:
blk_mq_destroy_queue(ctrl->admin_q);
+ blk_put_queue(ctrl->admin_q);
out_free_tagset:
blk_mq_free_tag_set(ctrl->admin_tagset);
return ret;
@@ -4860,14 +4880,17 @@ EXPORT_SYMBOL_GPL(nvme_alloc_admin_tag_set);
void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl)
{
blk_mq_destroy_queue(ctrl->admin_q);
- if (ctrl->ops->flags & NVME_F_FABRICS)
+ blk_put_queue(ctrl->admin_q);
+ if (ctrl->ops->flags & NVME_F_FABRICS) {
blk_mq_destroy_queue(ctrl->fabrics_q);
+ blk_put_queue(ctrl->fabrics_q);
+ }
blk_mq_free_tag_set(ctrl->admin_tagset);
}
EXPORT_SYMBOL_GPL(nvme_remove_admin_tag_set);
int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
- const struct blk_mq_ops *ops, unsigned int flags,
+ const struct blk_mq_ops *ops, unsigned int nr_maps,
unsigned int cmd_size)
{
int ret;
@@ -4875,15 +4898,23 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
memset(set, 0, sizeof(*set));
set->ops = ops;
set->queue_depth = ctrl->sqsize + 1;
- set->reserved_tags = NVMF_RESERVED_TAGS;
+ /*
+ * Some Apple controllers requires tags to be unique across admin and
+ * the (only) I/O queue, so reserve the first 32 tags of the I/O queue.
+ */
+ if (ctrl->quirks & NVME_QUIRK_SHARED_TAGS)
+ set->reserved_tags = NVME_AQ_DEPTH;
+ else if (ctrl->ops->flags & NVME_F_FABRICS)
+ set->reserved_tags = NVMF_RESERVED_TAGS;
set->numa_node = ctrl->numa_node;
- set->flags = flags;
+ set->flags = BLK_MQ_F_SHOULD_MERGE;
+ if (ctrl->ops->flags & NVME_F_BLOCKING)
+ set->flags |= BLK_MQ_F_BLOCKING;
set->cmd_size = cmd_size,
set->driver_data = ctrl;
set->nr_hw_queues = ctrl->queue_count - 1;
set->timeout = NVME_IO_TIMEOUT;
- if (ops->map_queues)
- set->nr_maps = ctrl->opts->nr_poll_queues ? HCTX_MAX_TYPES : 2;
+ set->nr_maps = nr_maps;
ret = blk_mq_alloc_tag_set(set);
if (ret)
return ret;
@@ -4894,6 +4925,8 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
ret = PTR_ERR(ctrl->connect_q);
goto out_free_tag_set;
}
+ blk_queue_flag_set(QUEUE_FLAG_SKIP_TAGSET_QUIESCE,
+ ctrl->connect_q);
}
ctrl->tagset = set;
@@ -4907,8 +4940,10 @@ EXPORT_SYMBOL_GPL(nvme_alloc_io_tag_set);
void nvme_remove_io_tag_set(struct nvme_ctrl *ctrl)
{
- if (ctrl->ops->flags & NVME_F_FABRICS)
+ if (ctrl->ops->flags & NVME_F_FABRICS) {
blk_mq_destroy_queue(ctrl->connect_q);
+ blk_put_queue(ctrl->connect_q);
+ }
blk_mq_free_tag_set(ctrl->tagset);
}
EXPORT_SYMBOL_GPL(nvme_remove_io_tag_set);
@@ -4944,7 +4979,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
if (ctrl->queue_count > 1) {
nvme_queue_scan(ctrl);
- nvme_start_queues(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
nvme_mpath_update(ctrl);
}
@@ -4989,6 +5024,7 @@ static void nvme_free_ctrl(struct device *dev)
nvme_auth_stop(ctrl);
nvme_auth_free(ctrl);
__free_page(ctrl->discard_page);
+ free_opal_dev(ctrl->opal_dev);
if (subsys) {
mutex_lock(&nvme_subsystems_lock);
@@ -5054,7 +5090,10 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
ctrl->instance);
ctrl->device->class = nvme_class;
ctrl->device->parent = ctrl->dev;
- ctrl->device->groups = nvme_dev_attr_groups;
+ if (ops->dev_attr_groups)
+ ctrl->device->groups = ops->dev_attr_groups;
+ else
+ ctrl->device->groups = nvme_dev_attr_groups;
ctrl->device->release = nvme_free_ctrl;
dev_set_drvdata(ctrl->device, ctrl);
ret = dev_set_name(ctrl->device, "nvme%d", ctrl->instance);
@@ -5078,9 +5117,13 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
nvme_mpath_init_ctrl(ctrl);
- nvme_auth_init_ctrl(ctrl);
+ ret = nvme_auth_init_ctrl(ctrl);
+ if (ret)
+ goto out_free_cdev;
return 0;
+out_free_cdev:
+ cdev_device_del(&ctrl->cdev, ctrl->device);
out_free_name:
nvme_put_ctrl(ctrl);
kfree_const(ctrl->device->kobj.name);
@@ -5093,62 +5136,17 @@ out:
}
EXPORT_SYMBOL_GPL(nvme_init_ctrl);
-static void nvme_start_ns_queue(struct nvme_ns *ns)
-{
- if (test_and_clear_bit(NVME_NS_STOPPED, &ns->flags))
- blk_mq_unquiesce_queue(ns->queue);
-}
-
-static void nvme_stop_ns_queue(struct nvme_ns *ns)
-{
- if (!test_and_set_bit(NVME_NS_STOPPED, &ns->flags))
- blk_mq_quiesce_queue(ns->queue);
- else
- blk_mq_wait_quiesce_done(ns->queue);
-}
-
-/*
- * Prepare a queue for teardown.
- *
- * This must forcibly unquiesce queues to avoid blocking dispatch, and only set
- * the capacity to 0 after that to avoid blocking dispatchers that may be
- * holding bd_butex. This will end buffered writers dirtying pages that can't
- * be synced.
- */
-static void nvme_set_queue_dying(struct nvme_ns *ns)
-{
- if (test_and_set_bit(NVME_NS_DEAD, &ns->flags))
- return;
-
- blk_mark_disk_dead(ns->disk);
- nvme_start_ns_queue(ns);
-
- set_capacity_and_notify(ns->disk, 0);
-}
-
-/**
- * nvme_kill_queues(): Ends all namespace queues
- * @ctrl: the dead controller that needs to end
- *
- * Call this function when the driver determines it is unable to get the
- * controller in a state capable of servicing IO.
- */
-void nvme_kill_queues(struct nvme_ctrl *ctrl)
+/* let I/O to all namespaces fail in preparation for surprise removal */
+void nvme_mark_namespaces_dead(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns;
down_read(&ctrl->namespaces_rwsem);
-
- /* Forcibly unquiesce queues to avoid blocking dispatch */
- if (ctrl->admin_q && !blk_queue_dying(ctrl->admin_q))
- nvme_start_admin_queue(ctrl);
-
list_for_each_entry(ns, &ctrl->namespaces, list)
- nvme_set_queue_dying(ns);
-
+ blk_mark_disk_dead(ns->disk);
up_read(&ctrl->namespaces_rwsem);
}
-EXPORT_SYMBOL_GPL(nvme_kill_queues);
+EXPORT_SYMBOL_GPL(nvme_mark_namespaces_dead);
void nvme_unfreeze(struct nvme_ctrl *ctrl)
{
@@ -5198,43 +5196,41 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl)
}
EXPORT_SYMBOL_GPL(nvme_start_freeze);
-void nvme_stop_queues(struct nvme_ctrl *ctrl)
+void nvme_quiesce_io_queues(struct nvme_ctrl *ctrl)
{
- struct nvme_ns *ns;
-
- down_read(&ctrl->namespaces_rwsem);
- list_for_each_entry(ns, &ctrl->namespaces, list)
- nvme_stop_ns_queue(ns);
- up_read(&ctrl->namespaces_rwsem);
+ if (!ctrl->tagset)
+ return;
+ if (!test_and_set_bit(NVME_CTRL_STOPPED, &ctrl->flags))
+ blk_mq_quiesce_tagset(ctrl->tagset);
+ else
+ blk_mq_wait_quiesce_done(ctrl->tagset);
}
-EXPORT_SYMBOL_GPL(nvme_stop_queues);
+EXPORT_SYMBOL_GPL(nvme_quiesce_io_queues);
-void nvme_start_queues(struct nvme_ctrl *ctrl)
+void nvme_unquiesce_io_queues(struct nvme_ctrl *ctrl)
{
- struct nvme_ns *ns;
-
- down_read(&ctrl->namespaces_rwsem);
- list_for_each_entry(ns, &ctrl->namespaces, list)
- nvme_start_ns_queue(ns);
- up_read(&ctrl->namespaces_rwsem);
+ if (!ctrl->tagset)
+ return;
+ if (test_and_clear_bit(NVME_CTRL_STOPPED, &ctrl->flags))
+ blk_mq_unquiesce_tagset(ctrl->tagset);
}
-EXPORT_SYMBOL_GPL(nvme_start_queues);
+EXPORT_SYMBOL_GPL(nvme_unquiesce_io_queues);
-void nvme_stop_admin_queue(struct nvme_ctrl *ctrl)
+void nvme_quiesce_admin_queue(struct nvme_ctrl *ctrl)
{
if (!test_and_set_bit(NVME_CTRL_ADMIN_Q_STOPPED, &ctrl->flags))
blk_mq_quiesce_queue(ctrl->admin_q);
else
- blk_mq_wait_quiesce_done(ctrl->admin_q);
+ blk_mq_wait_quiesce_done(ctrl->admin_q->tag_set);
}
-EXPORT_SYMBOL_GPL(nvme_stop_admin_queue);
+EXPORT_SYMBOL_GPL(nvme_quiesce_admin_queue);
-void nvme_start_admin_queue(struct nvme_ctrl *ctrl)
+void nvme_unquiesce_admin_queue(struct nvme_ctrl *ctrl)
{
if (test_and_clear_bit(NVME_CTRL_ADMIN_Q_STOPPED, &ctrl->flags))
blk_mq_unquiesce_queue(ctrl->admin_q);
}
-EXPORT_SYMBOL_GPL(nvme_start_admin_queue);
+EXPORT_SYMBOL_GPL(nvme_unquiesce_admin_queue);
void nvme_sync_io_queues(struct nvme_ctrl *ctrl)
{
@@ -5345,8 +5341,13 @@ static int __init nvme_core_init(void)
goto unregister_generic_ns;
}
+ result = nvme_init_auth();
+ if (result)
+ goto destroy_ns_chr;
return 0;
+destroy_ns_chr:
+ class_destroy(nvme_ns_chr_class);
unregister_generic_ns:
unregister_chrdev_region(nvme_ns_chr_devt, NVME_MINORS);
destroy_subsys_class:
@@ -5367,6 +5368,7 @@ out:
static void __exit nvme_core_exit(void)
{
+ nvme_exit_auth();
class_destroy(nvme_ns_chr_class);
class_destroy(nvme_subsys_class);
class_destroy(nvme_class);
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 5d57a042dbca..4564f16a0b20 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1475,6 +1475,8 @@ nvme_fc_xmt_ls_rsp_done(struct nvmefc_ls_rsp *lsrsp)
fc_dma_unmap_single(lport->dev, lsop->rspdma,
sizeof(*lsop->rspbuf), DMA_TO_DEVICE);
+ kfree(lsop->rspbuf);
+ kfree(lsop->rqstbuf);
kfree(lsop);
nvme_fc_rport_put(rport);
@@ -1699,6 +1701,15 @@ restart:
spin_unlock_irqrestore(&rport->lock, flags);
}
+static
+void nvme_fc_rcv_ls_req_err_msg(struct nvme_fc_lport *lport,
+ struct fcnvme_ls_rqst_w0 *w0)
+{
+ dev_info(lport->dev, "RCV %s LS failed: No memory\n",
+ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ?
+ nvmefc_ls_names[w0->ls_cmd] : "");
+}
+
/**
* nvme_fc_rcv_ls_req - transport entry point called by an LLDD
* upon the reception of a NVME LS request.
@@ -1751,20 +1762,20 @@ nvme_fc_rcv_ls_req(struct nvme_fc_remote_port *portptr,
goto out_put;
}
- lsop = kzalloc(sizeof(*lsop) +
- sizeof(union nvmefc_ls_requests) +
- sizeof(union nvmefc_ls_responses),
- GFP_KERNEL);
+ lsop = kzalloc(sizeof(*lsop), GFP_KERNEL);
if (!lsop) {
- dev_info(lport->dev,
- "RCV %s LS failed: No memory\n",
- (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ?
- nvmefc_ls_names[w0->ls_cmd] : "");
+ nvme_fc_rcv_ls_req_err_msg(lport, w0);
ret = -ENOMEM;
goto out_put;
}
- lsop->rqstbuf = (union nvmefc_ls_requests *)&lsop[1];
- lsop->rspbuf = (union nvmefc_ls_responses *)&lsop->rqstbuf[1];
+
+ lsop->rqstbuf = kzalloc(sizeof(*lsop->rqstbuf), GFP_KERNEL);
+ lsop->rspbuf = kzalloc(sizeof(*lsop->rspbuf), GFP_KERNEL);
+ if (!lsop->rqstbuf || !lsop->rspbuf) {
+ nvme_fc_rcv_ls_req_err_msg(lport, w0);
+ ret = -ENOMEM;
+ goto out_free;
+ }
lsop->rspdma = fc_dma_map_single(lport->dev, lsop->rspbuf,
sizeof(*lsop->rspbuf),
@@ -1801,6 +1812,8 @@ out_unmap:
fc_dma_unmap_single(lport->dev, lsop->rspdma,
sizeof(*lsop->rspbuf), DMA_TO_DEVICE);
out_free:
+ kfree(lsop->rspbuf);
+ kfree(lsop->rqstbuf);
kfree(lsop);
out_put:
nvme_fc_rport_put(rport);
@@ -2391,7 +2404,7 @@ nvme_fc_ctrl_free(struct kref *ref)
list_del(&ctrl->ctrl_list);
spin_unlock_irqrestore(&ctrl->rport->lock, flags);
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
nvme_remove_admin_tag_set(&ctrl->ctrl);
kfree(ctrl->queues);
@@ -2492,20 +2505,20 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues)
* (but with error status).
*/
if (ctrl->ctrl.queue_count > 1) {
- nvme_stop_queues(&ctrl->ctrl);
+ nvme_quiesce_io_queues(&ctrl->ctrl);
nvme_sync_io_queues(&ctrl->ctrl);
blk_mq_tagset_busy_iter(&ctrl->tag_set,
nvme_fc_terminate_exchange, &ctrl->ctrl);
blk_mq_tagset_wait_completed_request(&ctrl->tag_set);
if (start_queues)
- nvme_start_queues(&ctrl->ctrl);
+ nvme_unquiesce_io_queues(&ctrl->ctrl);
}
/*
* Other transports, which don't have link-level contexts bound
* to sqe's, would try to gracefully shutdown the controller by
* writing the registers for shutdown and polling (call
- * nvme_shutdown_ctrl()). Given a bunch of i/o was potentially
+ * nvme_disable_ctrl()). Given a bunch of i/o was potentially
* just aborted and we will wait on those contexts, and given
* there was no indication of how live the controlelr is on the
* link, don't send more io to create more contexts for the
@@ -2516,13 +2529,13 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues)
/*
* clean up the admin queue. Same thing as above.
*/
- nvme_stop_admin_queue(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
blk_sync_queue(ctrl->ctrl.admin_q);
blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
nvme_fc_terminate_exchange, &ctrl->ctrl);
blk_mq_tagset_wait_completed_request(&ctrl->admin_tag_set);
if (start_queues)
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
}
static void
@@ -2732,7 +2745,7 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
atomic_set(&op->state, FCPOP_STATE_ACTIVE);
if (!(op->flags & FCOP_FLAGS_AEN))
- blk_mq_start_request(op->rq);
+ nvme_start_request(op->rq);
cmdiu->csn = cpu_to_be32(atomic_inc_return(&queue->csn));
ret = ctrl->lport->ops->fcp_io(&ctrl->lport->localport,
@@ -2903,7 +2916,7 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
nvme_fc_init_io_queues(ctrl);
ret = nvme_alloc_io_tag_set(&ctrl->ctrl, &ctrl->tag_set,
- &nvme_fc_mq_ops, BLK_MQ_F_SHOULD_MERGE,
+ &nvme_fc_mq_ops, 1,
struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
ctrl->lport->ops->fcprqst_priv_sz));
if (ret)
@@ -3104,9 +3117,9 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
ctrl->ctrl.max_hw_sectors = ctrl->ctrl.max_segments <<
(ilog2(SZ_4K) - 9);
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
- ret = nvme_init_ctrl_finish(&ctrl->ctrl);
+ ret = nvme_init_ctrl_finish(&ctrl->ctrl, false);
if (ret || test_bit(ASSOC_FAILED, &ctrl->flags))
goto out_disconnect_admin_queue;
@@ -3250,10 +3263,10 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl)
nvme_fc_free_queue(&ctrl->queues[0]);
/* re-enable the admin_q so anything new can fast fail */
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
/* resume the io queues so that things will fast fail */
- nvme_start_queues(&ctrl->ctrl);
+ nvme_unquiesce_io_queues(&ctrl->ctrl);
nvme_fc_ctlr_inactive_on_rport(ctrl);
}
@@ -3509,7 +3522,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
nvme_fc_init_queue(ctrl, 0);
ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
- &nvme_fc_admin_mq_ops, BLK_MQ_F_NO_SCHED,
+ &nvme_fc_admin_mq_ops,
struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
ctrl->lport->ops->fcprqst_priv_sz));
if (ret)
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 81f5550b670d..9ddda571f046 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -8,6 +8,50 @@
#include <linux/io_uring.h>
#include "nvme.h"
+static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
+ fmode_t mode)
+{
+ if (capable(CAP_SYS_ADMIN))
+ return true;
+
+ /*
+ * Do not allow unprivileged processes to send vendor specific or fabrics
+ * commands as we can't be sure about their effects.
+ */
+ if (c->common.opcode >= nvme_cmd_vendor_start ||
+ c->common.opcode == nvme_fabrics_command)
+ return false;
+
+ /*
+ * Do not allow unprivileged passthrough of admin commands except
+ * for a subset of identify commands that contain information required
+ * to form proper I/O commands in userspace and do not expose any
+ * potentially sensitive information.
+ */
+ if (!ns) {
+ if (c->common.opcode == nvme_admin_identify) {
+ switch (c->identify.cns) {
+ case NVME_ID_CNS_NS:
+ case NVME_ID_CNS_CS_NS:
+ case NVME_ID_CNS_NS_CS_INDEP:
+ case NVME_ID_CNS_CS_CTRL:
+ case NVME_ID_CNS_CTRL:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Only allow I/O commands that transfer data to the controller if the
+ * special file is open for writing, but always allow I/O commands that
+ * transfer data from the controller.
+ */
+ if (nvme_is_write(c))
+ return mode & FMODE_WRITE;
+ return true;
+}
+
/*
* Convert integer values from ioctl structures to user pointers, silently
* ignoring the upper bits in the compat case to match behaviour of 32-bit
@@ -261,7 +305,7 @@ static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
}
static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
- struct nvme_passthru_cmd __user *ucmd)
+ struct nvme_passthru_cmd __user *ucmd, fmode_t mode)
{
struct nvme_passthru_cmd cmd;
struct nvme_command c;
@@ -269,8 +313,6 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
u64 result;
int status;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
return -EFAULT;
if (cmd.flags)
@@ -291,6 +333,9 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
c.common.cdw14 = cpu_to_le32(cmd.cdw14);
c.common.cdw15 = cpu_to_le32(cmd.cdw15);
+ if (!nvme_cmd_allowed(ns, &c, mode))
+ return -EACCES;
+
if (cmd.timeout_ms)
timeout = msecs_to_jiffies(cmd.timeout_ms);
@@ -308,15 +353,14 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
}
static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
- struct nvme_passthru_cmd64 __user *ucmd, bool vec)
+ struct nvme_passthru_cmd64 __user *ucmd, bool vec,
+ fmode_t mode)
{
struct nvme_passthru_cmd64 cmd;
struct nvme_command c;
unsigned timeout = 0;
int status;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
return -EFAULT;
if (cmd.flags)
@@ -337,6 +381,9 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
c.common.cdw14 = cpu_to_le32(cmd.cdw14);
c.common.cdw15 = cpu_to_le32(cmd.cdw15);
+ if (!nvme_cmd_allowed(ns, &c, mode))
+ return -EACCES;
+
if (cmd.timeout_ms)
timeout = msecs_to_jiffies(cmd.timeout_ms);
@@ -483,9 +530,6 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
void *meta = NULL;
int ret;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
c.common.opcode = READ_ONCE(cmd->opcode);
c.common.flags = READ_ONCE(cmd->flags);
if (c.common.flags)
@@ -507,6 +551,9 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
c.common.cdw14 = cpu_to_le32(READ_ONCE(cmd->cdw14));
c.common.cdw15 = cpu_to_le32(READ_ONCE(cmd->cdw15));
+ if (!nvme_cmd_allowed(ns, &c, ioucmd->file->f_mode))
+ return -EACCES;
+
d.metadata = READ_ONCE(cmd->metadata);
d.addr = READ_ONCE(cmd->addr);
d.data_len = READ_ONCE(cmd->data_len);
@@ -570,13 +617,13 @@ static bool is_ctrl_ioctl(unsigned int cmd)
}
static int nvme_ctrl_ioctl(struct nvme_ctrl *ctrl, unsigned int cmd,
- void __user *argp)
+ void __user *argp, fmode_t mode)
{
switch (cmd) {
case NVME_IOCTL_ADMIN_CMD:
- return nvme_user_cmd(ctrl, NULL, argp);
+ return nvme_user_cmd(ctrl, NULL, argp, mode);
case NVME_IOCTL_ADMIN64_CMD:
- return nvme_user_cmd64(ctrl, NULL, argp, false);
+ return nvme_user_cmd64(ctrl, NULL, argp, false, mode);
default:
return sed_ioctl(ctrl->opal_dev, cmd, argp);
}
@@ -601,14 +648,14 @@ struct nvme_user_io32 {
#endif /* COMPAT_FOR_U64_ALIGNMENT */
static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
- void __user *argp)
+ void __user *argp, fmode_t mode)
{
switch (cmd) {
case NVME_IOCTL_ID:
force_successful_syscall_return();
return ns->head->ns_id;
case NVME_IOCTL_IO_CMD:
- return nvme_user_cmd(ns->ctrl, ns, argp);
+ return nvme_user_cmd(ns->ctrl, ns, argp, mode);
/*
* struct nvme_user_io can have different padding on some 32-bit ABIs.
* Just accept the compat version as all fields that are used are the
@@ -620,19 +667,20 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
case NVME_IOCTL_SUBMIT_IO:
return nvme_submit_io(ns, argp);
case NVME_IOCTL_IO64_CMD:
- return nvme_user_cmd64(ns->ctrl, ns, argp, false);
+ return nvme_user_cmd64(ns->ctrl, ns, argp, false, mode);
case NVME_IOCTL_IO64_CMD_VEC:
- return nvme_user_cmd64(ns->ctrl, ns, argp, true);
+ return nvme_user_cmd64(ns->ctrl, ns, argp, true, mode);
default:
return -ENOTTY;
}
}
-static int __nvme_ioctl(struct nvme_ns *ns, unsigned int cmd, void __user *arg)
+static int __nvme_ioctl(struct nvme_ns *ns, unsigned int cmd, void __user *arg,
+ fmode_t mode)
{
- if (is_ctrl_ioctl(cmd))
- return nvme_ctrl_ioctl(ns->ctrl, cmd, arg);
- return nvme_ns_ioctl(ns, cmd, arg);
+ if (is_ctrl_ioctl(cmd))
+ return nvme_ctrl_ioctl(ns->ctrl, cmd, arg, mode);
+ return nvme_ns_ioctl(ns, cmd, arg, mode);
}
int nvme_ioctl(struct block_device *bdev, fmode_t mode,
@@ -640,7 +688,7 @@ int nvme_ioctl(struct block_device *bdev, fmode_t mode,
{
struct nvme_ns *ns = bdev->bd_disk->private_data;
- return __nvme_ioctl(ns, cmd, (void __user *)arg);
+ return __nvme_ioctl(ns, cmd, (void __user *)arg, mode);
}
long nvme_ns_chr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -648,7 +696,7 @@ long nvme_ns_chr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct nvme_ns *ns =
container_of(file_inode(file)->i_cdev, struct nvme_ns, cdev);
- return __nvme_ioctl(ns, cmd, (void __user *)arg);
+ return __nvme_ioctl(ns, cmd, (void __user *)arg, file->f_mode);
}
static int nvme_uring_cmd_checks(unsigned int issue_flags)
@@ -716,7 +764,8 @@ int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd,
}
#ifdef CONFIG_NVME_MULTIPATH
static int nvme_ns_head_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
- void __user *argp, struct nvme_ns_head *head, int srcu_idx)
+ void __user *argp, struct nvme_ns_head *head, int srcu_idx,
+ fmode_t mode)
__releases(&head->srcu)
{
struct nvme_ctrl *ctrl = ns->ctrl;
@@ -724,7 +773,7 @@ static int nvme_ns_head_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
nvme_get_ctrl(ns->ctrl);
srcu_read_unlock(&head->srcu, srcu_idx);
- ret = nvme_ctrl_ioctl(ns->ctrl, cmd, argp);
+ ret = nvme_ctrl_ioctl(ns->ctrl, cmd, argp, mode);
nvme_put_ctrl(ctrl);
return ret;
@@ -749,9 +798,10 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode,
* deadlock when deleting namespaces using the passthrough interface.
*/
if (is_ctrl_ioctl(cmd))
- return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
+ return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx,
+ mode);
- ret = nvme_ns_ioctl(ns, cmd, argp);
+ ret = nvme_ns_ioctl(ns, cmd, argp, mode);
out_unlock:
srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
@@ -773,9 +823,10 @@ long nvme_ns_head_chr_ioctl(struct file *file, unsigned int cmd,
goto out_unlock;
if (is_ctrl_ioctl(cmd))
- return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
+ return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx,
+ file->f_mode);
- ret = nvme_ns_ioctl(ns, cmd, argp);
+ ret = nvme_ns_ioctl(ns, cmd, argp, file->f_mode);
out_unlock:
srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
@@ -849,7 +900,8 @@ int nvme_dev_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags)
return ret;
}
-static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
+static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp,
+ fmode_t mode)
{
struct nvme_ns *ns;
int ret;
@@ -873,7 +925,7 @@ static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
kref_get(&ns->kref);
up_read(&ctrl->namespaces_rwsem);
- ret = nvme_user_cmd(ctrl, ns, argp);
+ ret = nvme_user_cmd(ctrl, ns, argp, mode);
nvme_put_ns(ns);
return ret;
@@ -890,11 +942,11 @@ long nvme_dev_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case NVME_IOCTL_ADMIN_CMD:
- return nvme_user_cmd(ctrl, NULL, argp);
+ return nvme_user_cmd(ctrl, NULL, argp, file->f_mode);
case NVME_IOCTL_ADMIN64_CMD:
- return nvme_user_cmd64(ctrl, NULL, argp, false);
+ return nvme_user_cmd64(ctrl, NULL, argp, false, file->f_mode);
case NVME_IOCTL_IO_CMD:
- return nvme_dev_user_cmd(ctrl, argp);
+ return nvme_dev_user_cmd(ctrl, argp, file->f_mode);
case NVME_IOCTL_RESET:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 93e2138a8b42..c03093b6813c 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -114,6 +114,31 @@ void nvme_failover_req(struct request *req)
kblockd_schedule_work(&ns->head->requeue_work);
}
+void nvme_mpath_start_request(struct request *rq)
+{
+ struct nvme_ns *ns = rq->q->queuedata;
+ struct gendisk *disk = ns->head->disk;
+
+ if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq))
+ return;
+
+ nvme_req(rq)->flags |= NVME_MPATH_IO_STATS;
+ nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0,
+ blk_rq_bytes(rq) >> SECTOR_SHIFT,
+ req_op(rq), jiffies);
+}
+EXPORT_SYMBOL_GPL(nvme_mpath_start_request);
+
+void nvme_mpath_end_request(struct request *rq)
+{
+ struct nvme_ns *ns = rq->q->queuedata;
+
+ if (!(nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
+ return;
+ bdev_end_io_acct(ns->head->disk->part0, req_op(rq),
+ nvme_req(rq)->start_time);
+}
+
void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns;
@@ -174,11 +199,14 @@ void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
struct nvme_ns_head *head = ns->head;
sector_t capacity = get_capacity(head->disk);
int node;
+ int srcu_idx;
+ srcu_idx = srcu_read_lock(&head->srcu);
list_for_each_entry_rcu(ns, &head->list, siblings) {
if (capacity != get_capacity(ns->disk))
clear_bit(NVME_NS_READY, &ns->flags);
}
+ srcu_read_unlock(&head->srcu, srcu_idx);
for_each_node(node)
rcu_assign_pointer(head->current_path[node], NULL);
@@ -503,6 +531,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
blk_queue_flag_set(QUEUE_FLAG_NONROT, head->disk->queue);
blk_queue_flag_set(QUEUE_FLAG_NOWAIT, head->disk->queue);
+ blk_queue_flag_set(QUEUE_FLAG_IO_STAT, head->disk->queue);
/*
* This assumes all controllers that refer to a namespace either
* support poll queues or not. That is not a strict guarantee,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index a29877217ee6..6bbb73ef8b25 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -162,6 +162,9 @@ struct nvme_request {
u8 retries;
u8 flags;
u16 status;
+#ifdef CONFIG_NVME_MULTIPATH
+ unsigned long start_time;
+#endif
struct nvme_ctrl *ctrl;
};
@@ -173,6 +176,7 @@ struct nvme_request {
enum {
NVME_REQ_CANCELLED = (1 << 0),
NVME_REQ_USERCMD = (1 << 1),
+ NVME_MPATH_IO_STATS = (1 << 2),
};
static inline struct nvme_request *nvme_req(struct request *req)
@@ -237,6 +241,7 @@ enum nvme_ctrl_flags {
NVME_CTRL_FAILFAST_EXPIRED = 0,
NVME_CTRL_ADMIN_Q_STOPPED = 1,
NVME_CTRL_STARTED_ONCE = 2,
+ NVME_CTRL_STOPPED = 3,
};
struct nvme_ctrl {
@@ -336,8 +341,8 @@ struct nvme_ctrl {
#ifdef CONFIG_NVME_AUTH
struct work_struct dhchap_auth_work;
- struct list_head dhchap_auth_list;
struct mutex dhchap_auth_mutex;
+ struct nvme_dhchap_queue_context *dhchap_ctxs;
struct nvme_dhchap_key *host_key;
struct nvme_dhchap_key *ctrl_key;
u16 transaction;
@@ -454,6 +459,7 @@ static inline bool nvme_ns_head_multipath(struct nvme_ns_head *head)
enum nvme_ns_features {
NVME_NS_EXT_LBAS = 1 << 0, /* support extended LBA format */
NVME_NS_METADATA_SUPPORTED = 1 << 1, /* support getting generated md */
+ NVME_NS_DEAC, /* DEAC bit in Write Zeores supported */
};
struct nvme_ns {
@@ -483,11 +489,9 @@ struct nvme_ns {
unsigned long features;
unsigned long flags;
#define NVME_NS_REMOVING 0
-#define NVME_NS_DEAD 1
#define NVME_NS_ANA_PENDING 2
#define NVME_NS_FORCE_RO 3
#define NVME_NS_READY 4
-#define NVME_NS_STOPPED 5
struct cdev cdev;
struct device cdev_device;
@@ -508,6 +512,9 @@ struct nvme_ctrl_ops {
unsigned int flags;
#define NVME_F_FABRICS (1 << 0)
#define NVME_F_METADATA_SUPPORTED (1 << 1)
+#define NVME_F_BLOCKING (1 << 2)
+
+ const struct attribute_group **dev_attr_groups;
int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
@@ -728,37 +735,32 @@ void nvme_cancel_tagset(struct nvme_ctrl *ctrl);
void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl);
bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
enum nvme_ctrl_state new_state);
-int nvme_disable_ctrl(struct nvme_ctrl *ctrl);
+int nvme_disable_ctrl(struct nvme_ctrl *ctrl, bool shutdown);
int nvme_enable_ctrl(struct nvme_ctrl *ctrl);
-int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl);
int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
const struct nvme_ctrl_ops *ops, unsigned long quirks);
void nvme_uninit_ctrl(struct nvme_ctrl *ctrl);
void nvme_start_ctrl(struct nvme_ctrl *ctrl);
void nvme_stop_ctrl(struct nvme_ctrl *ctrl);
-int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl);
+int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl, bool was_suspended);
int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
- const struct blk_mq_ops *ops, unsigned int flags,
- unsigned int cmd_size);
+ const struct blk_mq_ops *ops, unsigned int cmd_size);
void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl);
int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
- const struct blk_mq_ops *ops, unsigned int flags,
+ const struct blk_mq_ops *ops, unsigned int nr_maps,
unsigned int cmd_size);
void nvme_remove_io_tag_set(struct nvme_ctrl *ctrl);
void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
-int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
- bool send);
-
void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
volatile union nvme_result *res);
-void nvme_stop_queues(struct nvme_ctrl *ctrl);
-void nvme_start_queues(struct nvme_ctrl *ctrl);
-void nvme_stop_admin_queue(struct nvme_ctrl *ctrl);
-void nvme_start_admin_queue(struct nvme_ctrl *ctrl);
-void nvme_kill_queues(struct nvme_ctrl *ctrl);
+void nvme_quiesce_io_queues(struct nvme_ctrl *ctrl);
+void nvme_unquiesce_io_queues(struct nvme_ctrl *ctrl);
+void nvme_quiesce_admin_queue(struct nvme_ctrl *ctrl);
+void nvme_unquiesce_admin_queue(struct nvme_ctrl *ctrl);
+void nvme_mark_namespaces_dead(struct nvme_ctrl *ctrl);
void nvme_sync_queues(struct nvme_ctrl *ctrl);
void nvme_sync_io_queues(struct nvme_ctrl *ctrl);
void nvme_unfreeze(struct nvme_ctrl *ctrl);
@@ -857,6 +859,7 @@ int nvme_dev_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags);
extern const struct attribute_group *nvme_ns_id_attr_groups[];
extern const struct pr_ops nvme_pr_ops;
extern const struct block_device_operations nvme_ns_head_ops;
+extern const struct attribute_group nvme_dev_attrs_group;
struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
#ifdef CONFIG_NVME_MULTIPATH
@@ -883,6 +886,8 @@ bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
void nvme_mpath_revalidate_paths(struct nvme_ns *ns);
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
void nvme_mpath_shutdown_disk(struct nvme_ns_head *head);
+void nvme_mpath_start_request(struct request *rq);
+void nvme_mpath_end_request(struct request *rq);
static inline void nvme_trace_bio_complete(struct request *req)
{
@@ -968,6 +973,12 @@ static inline void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
static inline void nvme_mpath_default_iopolicy(struct nvme_subsystem *subsys)
{
}
+static inline void nvme_mpath_start_request(struct request *rq)
+{
+}
+static inline void nvme_mpath_end_request(struct request *rq)
+{
+}
#endif /* CONFIG_NVME_MULTIPATH */
int nvme_revalidate_zones(struct nvme_ns *ns);
@@ -1013,20 +1024,38 @@ static inline void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
}
#endif
+static inline void nvme_start_request(struct request *rq)
+{
+ if (rq->cmd_flags & REQ_NVME_MPATH)
+ nvme_mpath_start_request(rq);
+ blk_mq_start_request(rq);
+}
+
static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl)
{
return ctrl->sgls & ((1 << 0) | (1 << 1));
}
#ifdef CONFIG_NVME_AUTH
-void nvme_auth_init_ctrl(struct nvme_ctrl *ctrl);
+int __init nvme_init_auth(void);
+void __exit nvme_exit_auth(void);
+int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl);
void nvme_auth_stop(struct nvme_ctrl *ctrl);
int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid);
int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid);
-void nvme_auth_reset(struct nvme_ctrl *ctrl);
void nvme_auth_free(struct nvme_ctrl *ctrl);
#else
-static inline void nvme_auth_init_ctrl(struct nvme_ctrl *ctrl) {};
+static inline int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
+{
+ return 0;
+}
+static inline int __init nvme_init_auth(void)
+{
+ return 0;
+}
+static inline void __exit nvme_exit_auth(void)
+{
+}
static inline void nvme_auth_stop(struct nvme_ctrl *ctrl) {};
static inline int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
{
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 31e577b01257..f0f8027644bb 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/kstrtox.h>
#include <linux/memremap.h>
#include <linux/mm.h>
#include <linux/module.h>
@@ -108,7 +109,7 @@ struct nvme_dev;
struct nvme_queue;
static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown);
-static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode);
+static void nvme_delete_io_queues(struct nvme_dev *dev);
/*
* Represents an NVM Express device. Each nvme_dev is a PCI function.
@@ -130,7 +131,6 @@ struct nvme_dev {
u32 db_stride;
void __iomem *bar;
unsigned long bar_mapped_size;
- struct work_struct remove_work;
struct mutex shutdown_lock;
bool subsystem;
u64 cmb_size;
@@ -158,8 +158,6 @@ struct nvme_dev {
unsigned int nr_allocated_queues;
unsigned int nr_write_queues;
unsigned int nr_poll_queues;
-
- bool attrs_added;
};
static int io_queue_depth_set(const char *val, const struct kernel_param *kp)
@@ -241,10 +239,13 @@ static inline unsigned int nvme_dbbuf_size(struct nvme_dev *dev)
return dev->nr_allocated_queues * 8 * dev->db_stride;
}
-static int nvme_dbbuf_dma_alloc(struct nvme_dev *dev)
+static void nvme_dbbuf_dma_alloc(struct nvme_dev *dev)
{
unsigned int mem_size = nvme_dbbuf_size(dev);
+ if (!(dev->ctrl.oacs & NVME_CTRL_OACS_DBBUF_SUPP))
+ return;
+
if (dev->dbbuf_dbs) {
/*
* Clear the dbbuf memory so the driver doesn't observe stale
@@ -252,25 +253,27 @@ static int nvme_dbbuf_dma_alloc(struct nvme_dev *dev)
*/
memset(dev->dbbuf_dbs, 0, mem_size);
memset(dev->dbbuf_eis, 0, mem_size);
- return 0;
+ return;
}
dev->dbbuf_dbs = dma_alloc_coherent(dev->dev, mem_size,
&dev->dbbuf_dbs_dma_addr,
GFP_KERNEL);
if (!dev->dbbuf_dbs)
- return -ENOMEM;
+ goto fail;
dev->dbbuf_eis = dma_alloc_coherent(dev->dev, mem_size,
&dev->dbbuf_eis_dma_addr,
GFP_KERNEL);
- if (!dev->dbbuf_eis) {
- dma_free_coherent(dev->dev, mem_size,
- dev->dbbuf_dbs, dev->dbbuf_dbs_dma_addr);
- dev->dbbuf_dbs = NULL;
- return -ENOMEM;
- }
+ if (!dev->dbbuf_eis)
+ goto fail_free_dbbuf_dbs;
+ return;
- return 0;
+fail_free_dbbuf_dbs:
+ dma_free_coherent(dev->dev, mem_size, dev->dbbuf_dbs,
+ dev->dbbuf_dbs_dma_addr);
+ dev->dbbuf_dbs = NULL;
+fail:
+ dev_warn(dev->dev, "unable to allocate dma for dbbuf\n");
}
static void nvme_dbbuf_dma_free(struct nvme_dev *dev)
@@ -392,18 +395,10 @@ static int nvme_pci_npages_sgl(void)
PAGE_SIZE);
}
-static size_t nvme_pci_iod_alloc_size(void)
-{
- size_t npages = max(nvme_pci_npages_prp(), nvme_pci_npages_sgl());
-
- return sizeof(__le64 *) * npages +
- sizeof(struct scatterlist) * NVME_MAX_SEGS;
-}
-
static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
unsigned int hctx_idx)
{
- struct nvme_dev *dev = data;
+ struct nvme_dev *dev = to_nvme_dev(data);
struct nvme_queue *nvmeq = &dev->queues[0];
WARN_ON(hctx_idx != 0);
@@ -416,7 +411,7 @@ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
unsigned int hctx_idx)
{
- struct nvme_dev *dev = data;
+ struct nvme_dev *dev = to_nvme_dev(data);
struct nvme_queue *nvmeq = &dev->queues[hctx_idx + 1];
WARN_ON(dev->tagset.tags[hctx_idx] != hctx->tags);
@@ -428,7 +423,7 @@ static int nvme_pci_init_request(struct blk_mq_tag_set *set,
struct request *req, unsigned int hctx_idx,
unsigned int numa_node)
{
- struct nvme_dev *dev = set->driver_data;
+ struct nvme_dev *dev = to_nvme_dev(set->driver_data);
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
nvme_req(req)->ctrl = &dev->ctrl;
@@ -447,7 +442,7 @@ static int queue_irq_offset(struct nvme_dev *dev)
static void nvme_pci_map_queues(struct blk_mq_tag_set *set)
{
- struct nvme_dev *dev = set->driver_data;
+ struct nvme_dev *dev = to_nvme_dev(set->driver_data);
int i, qoff, offset;
offset = queue_irq_offset(dev);
@@ -797,6 +792,8 @@ static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev,
cmnd->dptr.prp1 = cpu_to_le64(iod->first_dma);
if (bv->bv_len > first_prp_len)
cmnd->dptr.prp2 = cpu_to_le64(iod->first_dma + first_prp_len);
+ else
+ cmnd->dptr.prp2 = 0;
return BLK_STS_OK;
}
@@ -912,7 +909,7 @@ static blk_status_t nvme_prep_rq(struct nvme_dev *dev, struct request *req)
goto out_unmap_data;
}
- blk_mq_start_request(req);
+ nvme_start_request(req);
return BLK_STS_OK;
out_unmap_data:
nvme_unmap_data(dev, req);
@@ -1436,7 +1433,6 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
abort_req->end_io = abort_endio;
abort_req->end_io_data = NULL;
- abort_req->rq_flags |= RQF_QUIET;
blk_execute_rq_nowait(abort_req, false);
/*
@@ -1473,24 +1469,21 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest)
}
}
-/**
- * nvme_suspend_queue - put queue into suspended state
- * @nvmeq: queue to suspend
- */
-static int nvme_suspend_queue(struct nvme_queue *nvmeq)
+static void nvme_suspend_queue(struct nvme_dev *dev, unsigned int qid)
{
+ struct nvme_queue *nvmeq = &dev->queues[qid];
+
if (!test_and_clear_bit(NVMEQ_ENABLED, &nvmeq->flags))
- return 1;
+ return;
/* ensure that nvme_queue_rq() sees NVMEQ_ENABLED cleared */
mb();
nvmeq->dev->online_queues--;
if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q)
- nvme_stop_admin_queue(&nvmeq->dev->ctrl);
+ nvme_quiesce_admin_queue(&nvmeq->dev->ctrl);
if (!test_and_clear_bit(NVMEQ_POLLED, &nvmeq->flags))
- pci_free_irq(to_pci_dev(nvmeq->dev->dev), nvmeq->cq_vector, nvmeq);
- return 0;
+ pci_free_irq(to_pci_dev(dev->dev), nvmeq->cq_vector, nvmeq);
}
static void nvme_suspend_io_queues(struct nvme_dev *dev)
@@ -1498,19 +1491,7 @@ static void nvme_suspend_io_queues(struct nvme_dev *dev)
int i;
for (i = dev->ctrl.queue_count - 1; i > 0; i--)
- nvme_suspend_queue(&dev->queues[i]);
-}
-
-static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown)
-{
- struct nvme_queue *nvmeq = &dev->queues[0];
-
- if (shutdown)
- nvme_shutdown_ctrl(&dev->ctrl);
- else
- nvme_disable_ctrl(&dev->ctrl);
-
- nvme_poll_irqdisable(nvmeq);
+ nvme_suspend_queue(dev, i);
}
/*
@@ -1747,44 +1728,11 @@ static void nvme_dev_remove_admin(struct nvme_dev *dev)
* user requests may be waiting on a stopped queue. Start the
* queue to flush these to completion.
*/
- nvme_start_admin_queue(&dev->ctrl);
- blk_mq_destroy_queue(dev->ctrl.admin_q);
- blk_mq_free_tag_set(&dev->admin_tagset);
+ nvme_unquiesce_admin_queue(&dev->ctrl);
+ nvme_remove_admin_tag_set(&dev->ctrl);
}
}
-static int nvme_pci_alloc_admin_tag_set(struct nvme_dev *dev)
-{
- struct blk_mq_tag_set *set = &dev->admin_tagset;
-
- set->ops = &nvme_mq_admin_ops;
- set->nr_hw_queues = 1;
-
- set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
- set->timeout = NVME_ADMIN_TIMEOUT;
- set->numa_node = dev->ctrl.numa_node;
- set->cmd_size = sizeof(struct nvme_iod);
- set->flags = BLK_MQ_F_NO_SCHED;
- set->driver_data = dev;
-
- if (blk_mq_alloc_tag_set(set))
- return -ENOMEM;
- dev->ctrl.admin_tagset = set;
-
- dev->ctrl.admin_q = blk_mq_init_queue(set);
- if (IS_ERR(dev->ctrl.admin_q)) {
- blk_mq_free_tag_set(set);
- dev->ctrl.admin_q = NULL;
- return -ENOMEM;
- }
- if (!blk_get_queue(dev->ctrl.admin_q)) {
- nvme_dev_remove_admin(dev);
- dev->ctrl.admin_q = NULL;
- return -ENODEV;
- }
- return 0;
-}
-
static unsigned long db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues)
{
return NVME_REG_DBS + ((nr_io_queues + 1) * 8 * dev->db_stride);
@@ -1828,7 +1776,14 @@ static int nvme_pci_configure_admin_queue(struct nvme_dev *dev)
(readl(dev->bar + NVME_REG_CSTS) & NVME_CSTS_NSSRO))
writel(NVME_CSTS_NSSRO, dev->bar + NVME_REG_CSTS);
- result = nvme_disable_ctrl(&dev->ctrl);
+ /*
+ * If the device has been passed off to us in an enabled state, just
+ * clear the enabled bit. The spec says we should set the 'shutdown
+ * notification bits', but doing so may cause the device to complete
+ * commands to the admin queue ... and we don't know what memory that
+ * might be pointing at!
+ */
+ result = nvme_disable_ctrl(&dev->ctrl, false);
if (result < 0)
return result;
@@ -2111,6 +2066,9 @@ static int nvme_setup_host_mem(struct nvme_dev *dev)
u32 enable_bits = NVME_HOST_MEM_ENABLE;
int ret;
+ if (!dev->ctrl.hmpre)
+ return 0;
+
preferred = min(preferred, max);
if (min > max) {
dev_warn(dev->ctrl.device,
@@ -2191,7 +2149,7 @@ static ssize_t hmb_store(struct device *dev, struct device_attribute *attr,
bool new;
int ret;
- if (strtobool(buf, &new) < 0)
+ if (kstrtobool(buf, &new) < 0)
return -EINVAL;
if (new == ndev->hmb)
@@ -2239,11 +2197,17 @@ static struct attribute *nvme_pci_attrs[] = {
NULL,
};
-static const struct attribute_group nvme_pci_attr_group = {
+static const struct attribute_group nvme_pci_dev_attrs_group = {
.attrs = nvme_pci_attrs,
.is_visible = nvme_pci_attrs_are_visible,
};
+static const struct attribute_group *nvme_pci_dev_attr_groups[] = {
+ &nvme_dev_attrs_group,
+ &nvme_pci_dev_attrs_group,
+ NULL,
+};
+
/*
* nirqs is the number of interrupts available for write and read
* queues. The core already reserved an interrupt for the admin queue.
@@ -2318,12 +2282,6 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
}
-static void nvme_disable_io_queues(struct nvme_dev *dev)
-{
- if (__nvme_disable_io_queues(dev, nvme_admin_delete_sq))
- __nvme_disable_io_queues(dev, nvme_admin_delete_cq);
-}
-
static unsigned int nvme_max_io_queues(struct nvme_dev *dev)
{
/*
@@ -2431,7 +2389,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (dev->online_queues - 1 < dev->max_qid) {
nr_io_queues = dev->online_queues - 1;
- nvme_disable_io_queues(dev);
+ nvme_delete_io_queues(dev);
result = nvme_setup_io_queues_trylock(dev);
if (result)
return result;
@@ -2490,12 +2448,11 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
req->end_io_data = nvmeq;
init_completion(&nvmeq->delete_done);
- req->rq_flags |= RQF_QUIET;
blk_execute_rq_nowait(req, false);
return 0;
}
-static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode)
+static bool __nvme_delete_io_queues(struct nvme_dev *dev, u8 opcode)
{
int nr_queues = dev->online_queues - 1, sent = 0;
unsigned long timeout;
@@ -2523,40 +2480,19 @@ static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode)
return true;
}
-static void nvme_pci_alloc_tag_set(struct nvme_dev *dev)
+static void nvme_delete_io_queues(struct nvme_dev *dev)
{
- struct blk_mq_tag_set * set = &dev->tagset;
- int ret;
+ if (__nvme_delete_io_queues(dev, nvme_admin_delete_sq))
+ __nvme_delete_io_queues(dev, nvme_admin_delete_cq);
+}
- set->ops = &nvme_mq_ops;
- set->nr_hw_queues = dev->online_queues - 1;
- set->nr_maps = 1;
- if (dev->io_queues[HCTX_TYPE_READ])
- set->nr_maps = 2;
+static unsigned int nvme_pci_nr_maps(struct nvme_dev *dev)
+{
if (dev->io_queues[HCTX_TYPE_POLL])
- set->nr_maps = 3;
- set->timeout = NVME_IO_TIMEOUT;
- set->numa_node = dev->ctrl.numa_node;
- set->queue_depth = min_t(unsigned, dev->q_depth, BLK_MQ_MAX_DEPTH) - 1;
- set->cmd_size = sizeof(struct nvme_iod);
- set->flags = BLK_MQ_F_SHOULD_MERGE;
- set->driver_data = dev;
-
- /*
- * Some Apple controllers requires tags to be unique
- * across admin and IO queue, so reserve the first 32
- * tags of the IO queue.
- */
- if (dev->ctrl.quirks & NVME_QUIRK_SHARED_TAGS)
- set->reserved_tags = NVME_AQ_DEPTH;
-
- ret = blk_mq_alloc_tag_set(set);
- if (ret) {
- dev_warn(dev->ctrl.device,
- "IO queues tagset allocation failed %d\n", ret);
- return;
- }
- dev->ctrl.tagset = set;
+ return 3;
+ if (dev->io_queues[HCTX_TYPE_READ])
+ return 2;
+ return 1;
}
static void nvme_pci_update_nr_queues(struct nvme_dev *dev)
@@ -2647,7 +2583,8 @@ static int nvme_pci_enable(struct nvme_dev *dev)
pci_enable_pcie_error_reporting(pdev);
pci_save_state(pdev);
- return 0;
+
+ return nvme_pci_configure_admin_queue(dev);
disable:
pci_disable_device(pdev);
@@ -2661,57 +2598,53 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
pci_release_mem_regions(to_pci_dev(dev->dev));
}
-static void nvme_pci_disable(struct nvme_dev *dev)
+static bool nvme_pci_ctrl_is_dead(struct nvme_dev *dev)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
+ u32 csts;
- pci_free_irq_vectors(pdev);
+ if (!pci_is_enabled(pdev) || !pci_device_is_present(pdev))
+ return true;
+ if (pdev->error_state != pci_channel_io_normal)
+ return true;
- if (pci_is_enabled(pdev)) {
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
- }
+ csts = readl(dev->bar + NVME_REG_CSTS);
+ return (csts & NVME_CSTS_CFS) || !(csts & NVME_CSTS_RDY);
}
static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
{
- bool dead = true, freeze = false;
struct pci_dev *pdev = to_pci_dev(dev->dev);
+ bool dead;
mutex_lock(&dev->shutdown_lock);
- if (pci_is_enabled(pdev)) {
- u32 csts;
-
- if (pci_device_is_present(pdev))
- csts = readl(dev->bar + NVME_REG_CSTS);
- else
- csts = ~0;
-
- if (dev->ctrl.state == NVME_CTRL_LIVE ||
- dev->ctrl.state == NVME_CTRL_RESETTING) {
- freeze = true;
+ dead = nvme_pci_ctrl_is_dead(dev);
+ if (dev->ctrl.state == NVME_CTRL_LIVE ||
+ dev->ctrl.state == NVME_CTRL_RESETTING) {
+ if (pci_is_enabled(pdev))
nvme_start_freeze(&dev->ctrl);
- }
- dead = !!((csts & NVME_CSTS_CFS) || !(csts & NVME_CSTS_RDY) ||
- pdev->error_state != pci_channel_io_normal);
+ /*
+ * Give the controller a chance to complete all entered requests
+ * if doing a safe shutdown.
+ */
+ if (!dead && shutdown)
+ nvme_wait_freeze_timeout(&dev->ctrl, NVME_IO_TIMEOUT);
}
- /*
- * Give the controller a chance to complete all entered requests if
- * doing a safe shutdown.
- */
- if (!dead && shutdown && freeze)
- nvme_wait_freeze_timeout(&dev->ctrl, NVME_IO_TIMEOUT);
-
- nvme_stop_queues(&dev->ctrl);
+ nvme_quiesce_io_queues(&dev->ctrl);
if (!dead && dev->ctrl.queue_count > 0) {
- nvme_disable_io_queues(dev);
- nvme_disable_admin_queue(dev, shutdown);
+ nvme_delete_io_queues(dev);
+ nvme_disable_ctrl(&dev->ctrl, shutdown);
+ nvme_poll_irqdisable(&dev->queues[0]);
}
nvme_suspend_io_queues(dev);
- nvme_suspend_queue(&dev->queues[0]);
- nvme_pci_disable(dev);
+ nvme_suspend_queue(dev, 0);
+ pci_free_irq_vectors(pdev);
+ if (pci_is_enabled(pdev)) {
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
+ }
nvme_reap_pending_cqes(dev);
nvme_cancel_tagset(&dev->ctrl);
@@ -2723,9 +2656,9 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
* deadlocking blk-mq hot-cpu notifier.
*/
if (shutdown) {
- nvme_start_queues(&dev->ctrl);
+ nvme_unquiesce_io_queues(&dev->ctrl);
if (dev->ctrl.admin_q && !blk_queue_dying(dev->ctrl.admin_q))
- nvme_start_admin_queue(&dev->ctrl);
+ nvme_unquiesce_admin_queue(&dev->ctrl);
}
mutex_unlock(&dev->shutdown_lock);
}
@@ -2762,42 +2695,40 @@ static void nvme_release_prp_pools(struct nvme_dev *dev)
dma_pool_destroy(dev->prp_small_pool);
}
+static int nvme_pci_alloc_iod_mempool(struct nvme_dev *dev)
+{
+ size_t npages = max(nvme_pci_npages_prp(), nvme_pci_npages_sgl());
+ size_t alloc_size = sizeof(__le64 *) * npages +
+ sizeof(struct scatterlist) * NVME_MAX_SEGS;
+
+ WARN_ON_ONCE(alloc_size > PAGE_SIZE);
+ dev->iod_mempool = mempool_create_node(1,
+ mempool_kmalloc, mempool_kfree,
+ (void *)alloc_size, GFP_KERNEL,
+ dev_to_node(dev->dev));
+ if (!dev->iod_mempool)
+ return -ENOMEM;
+ return 0;
+}
+
static void nvme_free_tagset(struct nvme_dev *dev)
{
if (dev->tagset.tags)
- blk_mq_free_tag_set(&dev->tagset);
+ nvme_remove_io_tag_set(&dev->ctrl);
dev->ctrl.tagset = NULL;
}
+/* pairs with nvme_pci_alloc_dev */
static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
{
struct nvme_dev *dev = to_nvme_dev(ctrl);
- nvme_dbbuf_dma_free(dev);
nvme_free_tagset(dev);
- if (dev->ctrl.admin_q)
- blk_put_queue(dev->ctrl.admin_q);
- free_opal_dev(dev->ctrl.opal_dev);
- mempool_destroy(dev->iod_mempool);
put_device(dev->dev);
kfree(dev->queues);
kfree(dev);
}
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
-{
- /*
- * Set state to deleting now to avoid blocking nvme_wait_reset(), which
- * may be holding this pci_dev's device lock.
- */
- nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
- nvme_get_ctrl(&dev->ctrl);
- nvme_dev_disable(dev, false);
- nvme_kill_queues(&dev->ctrl);
- if (!queue_work(nvme_wq, &dev->remove_work))
- nvme_put_ctrl(&dev->ctrl);
-}
-
static void nvme_reset_work(struct work_struct *work)
{
struct nvme_dev *dev =
@@ -2808,8 +2739,7 @@ static void nvme_reset_work(struct work_struct *work)
if (dev->ctrl.state != NVME_CTRL_RESETTING) {
dev_warn(dev->ctrl.device, "ctrl state %d is not RESETTING\n",
dev->ctrl.state);
- result = -ENODEV;
- goto out;
+ return;
}
/*
@@ -2824,34 +2754,7 @@ static void nvme_reset_work(struct work_struct *work)
result = nvme_pci_enable(dev);
if (result)
goto out_unlock;
-
- result = nvme_pci_configure_admin_queue(dev);
- if (result)
- goto out_unlock;
-
- if (!dev->ctrl.admin_q) {
- result = nvme_pci_alloc_admin_tag_set(dev);
- if (result)
- goto out_unlock;
- } else {
- nvme_start_admin_queue(&dev->ctrl);
- }
-
- dma_set_min_align_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1);
-
- /*
- * Limit the max command size to prevent iod->sg allocations going
- * over a single page.
- */
- dev->ctrl.max_hw_sectors = min_t(u32,
- NVME_MAX_KB_SZ << 1, dma_max_mapping_size(dev->dev) >> 9);
- dev->ctrl.max_segments = NVME_MAX_SEGS;
-
- /*
- * Don't limit the IOMMU merged segment size.
- */
- dma_set_max_seg_size(dev->dev, 0xffffffff);
-
+ nvme_unquiesce_admin_queue(&dev->ctrl);
mutex_unlock(&dev->shutdown_lock);
/*
@@ -2865,62 +2768,37 @@ static void nvme_reset_work(struct work_struct *work)
goto out;
}
- /*
- * We do not support an SGL for metadata (yet), so we are limited to a
- * single integrity segment for the separate metadata pointer.
- */
- dev->ctrl.max_integrity_segments = 1;
-
- result = nvme_init_ctrl_finish(&dev->ctrl);
+ result = nvme_init_ctrl_finish(&dev->ctrl, was_suspend);
if (result)
goto out;
- if (dev->ctrl.oacs & NVME_CTRL_OACS_SEC_SUPP) {
- if (!dev->ctrl.opal_dev)
- dev->ctrl.opal_dev =
- init_opal_dev(&dev->ctrl, &nvme_sec_submit);
- else if (was_suspend)
- opal_unlock_from_suspend(dev->ctrl.opal_dev);
- } else {
- free_opal_dev(dev->ctrl.opal_dev);
- dev->ctrl.opal_dev = NULL;
- }
-
- if (dev->ctrl.oacs & NVME_CTRL_OACS_DBBUF_SUPP) {
- result = nvme_dbbuf_dma_alloc(dev);
- if (result)
- dev_warn(dev->dev,
- "unable to allocate dma for dbbuf\n");
- }
+ nvme_dbbuf_dma_alloc(dev);
- if (dev->ctrl.hmpre) {
- result = nvme_setup_host_mem(dev);
- if (result < 0)
- goto out;
- }
+ result = nvme_setup_host_mem(dev);
+ if (result < 0)
+ goto out;
result = nvme_setup_io_queues(dev);
if (result)
goto out;
/*
- * Keep the controller around but remove all namespaces if we don't have
- * any working I/O queue.
+ * Freeze and update the number of I/O queues as thos might have
+ * changed. If there are no I/O queues left after this reset, keep the
+ * controller around but remove all namespaces.
*/
- if (dev->online_queues < 2) {
- dev_warn(dev->ctrl.device, "IO queues not created\n");
- nvme_kill_queues(&dev->ctrl);
- nvme_remove_namespaces(&dev->ctrl);
- nvme_free_tagset(dev);
- } else {
- nvme_start_queues(&dev->ctrl);
+ if (dev->online_queues > 1) {
+ nvme_unquiesce_io_queues(&dev->ctrl);
nvme_wait_freeze(&dev->ctrl);
- if (!dev->ctrl.tagset)
- nvme_pci_alloc_tag_set(dev);
- else
- nvme_pci_update_nr_queues(dev);
+ nvme_pci_update_nr_queues(dev);
nvme_dbbuf_set(dev);
nvme_unfreeze(&dev->ctrl);
+ } else {
+ dev_warn(dev->ctrl.device, "IO queues lost\n");
+ nvme_mark_namespaces_dead(&dev->ctrl);
+ nvme_unquiesce_io_queues(&dev->ctrl);
+ nvme_remove_namespaces(&dev->ctrl);
+ nvme_free_tagset(dev);
}
/*
@@ -2934,30 +2812,22 @@ static void nvme_reset_work(struct work_struct *work)
goto out;
}
- if (!dev->attrs_added && !sysfs_create_group(&dev->ctrl.device->kobj,
- &nvme_pci_attr_group))
- dev->attrs_added = true;
-
nvme_start_ctrl(&dev->ctrl);
return;
out_unlock:
mutex_unlock(&dev->shutdown_lock);
out:
- if (result)
- dev_warn(dev->ctrl.device,
- "Removing after probe failure status: %d\n", result);
- nvme_remove_dead_ctrl(dev);
-}
-
-static void nvme_remove_dead_ctrl_work(struct work_struct *work)
-{
- struct nvme_dev *dev = container_of(work, struct nvme_dev, remove_work);
- struct pci_dev *pdev = to_pci_dev(dev->dev);
-
- if (pci_get_drvdata(pdev))
- device_release_driver(&pdev->dev);
- nvme_put_ctrl(&dev->ctrl);
+ /*
+ * Set state to deleting now to avoid blocking nvme_wait_reset(), which
+ * may be holding this pci_dev's device lock.
+ */
+ dev_warn(dev->ctrl.device, "Disabling device after reset failure: %d\n",
+ result);
+ nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
+ nvme_dev_disable(dev, true);
+ nvme_mark_namespaces_dead(&dev->ctrl);
+ nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DEAD);
}
static int nvme_pci_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
@@ -3010,6 +2880,7 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
.name = "pcie",
.module = THIS_MODULE,
.flags = NVME_F_METADATA_SUPPORTED,
+ .dev_attr_groups = nvme_pci_dev_attr_groups,
.reg_read32 = nvme_pci_reg_read32,
.reg_write32 = nvme_pci_reg_write32,
.reg_read64 = nvme_pci_reg_read64,
@@ -3079,29 +2950,22 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
return 0;
}
-static void nvme_async_probe(void *data, async_cookie_t cookie)
+static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
+ const struct pci_device_id *id)
{
- struct nvme_dev *dev = data;
-
- flush_work(&dev->ctrl.reset_work);
- flush_work(&dev->ctrl.scan_work);
- nvme_put_ctrl(&dev->ctrl);
-}
-
-static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- int node, result = -ENOMEM;
- struct nvme_dev *dev;
unsigned long quirks = id->driver_data;
- size_t alloc_size;
+ int node = dev_to_node(&pdev->dev);
+ struct nvme_dev *dev;
+ int ret = -ENOMEM;
- node = dev_to_node(&pdev->dev);
if (node == NUMA_NO_NODE)
set_dev_node(&pdev->dev, first_memory_node);
dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node);
if (!dev)
- return -ENOMEM;
+ return NULL;
+ INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work);
+ mutex_init(&dev->shutdown_lock);
dev->nr_write_queues = write_queues;
dev->nr_poll_queues = poll_queues;
@@ -3109,25 +2973,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->queues = kcalloc_node(dev->nr_allocated_queues,
sizeof(struct nvme_queue), GFP_KERNEL, node);
if (!dev->queues)
- goto free;
+ goto out_free_dev;
dev->dev = get_device(&pdev->dev);
- pci_set_drvdata(pdev, dev);
-
- result = nvme_dev_map(dev);
- if (result)
- goto put_pci;
-
- INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work);
- INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
- mutex_init(&dev->shutdown_lock);
-
- result = nvme_setup_prp_pools(dev);
- if (result)
- goto unmap;
quirks |= check_vendor_combination_bug(pdev);
-
if (!noacpi && acpi_storage_d3(&pdev->dev)) {
/*
* Some systems use a bios work around to ask for D3 on
@@ -3137,46 +2987,131 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
"platform quirk: setting simple suspend\n");
quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
}
+ ret = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
+ quirks);
+ if (ret)
+ goto out_put_device;
+
+ dma_set_min_align_mask(&pdev->dev, NVME_CTRL_PAGE_SIZE - 1);
+ dma_set_max_seg_size(&pdev->dev, 0xffffffff);
/*
- * Double check that our mempool alloc size will cover the biggest
- * command we support.
+ * Limit the max command size to prevent iod->sg allocations going
+ * over a single page.
*/
- alloc_size = nvme_pci_iod_alloc_size();
- WARN_ON_ONCE(alloc_size > PAGE_SIZE);
+ dev->ctrl.max_hw_sectors = min_t(u32,
+ NVME_MAX_KB_SZ << 1, dma_max_mapping_size(&pdev->dev) >> 9);
+ dev->ctrl.max_segments = NVME_MAX_SEGS;
- dev->iod_mempool = mempool_create_node(1, mempool_kmalloc,
- mempool_kfree,
- (void *) alloc_size,
- GFP_KERNEL, node);
- if (!dev->iod_mempool) {
- result = -ENOMEM;
- goto release_pools;
- }
+ /*
+ * There is no support for SGLs for metadata (yet), so we are limited to
+ * a single integrity segment for the separate metadata pointer.
+ */
+ dev->ctrl.max_integrity_segments = 1;
+ return dev;
+
+out_put_device:
+ put_device(dev->dev);
+ kfree(dev->queues);
+out_free_dev:
+ kfree(dev);
+ return ERR_PTR(ret);
+}
+
+static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct nvme_dev *dev;
+ int result = -ENOMEM;
+
+ dev = nvme_pci_alloc_dev(pdev, id);
+ if (!dev)
+ return -ENOMEM;
+
+ result = nvme_dev_map(dev);
+ if (result)
+ goto out_uninit_ctrl;
- result = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
- quirks);
+ result = nvme_setup_prp_pools(dev);
if (result)
- goto release_mempool;
+ goto out_dev_unmap;
+
+ result = nvme_pci_alloc_iod_mempool(dev);
+ if (result)
+ goto out_release_prp_pools;
dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
- nvme_reset_ctrl(&dev->ctrl);
- async_schedule(nvme_async_probe, dev);
+ result = nvme_pci_enable(dev);
+ if (result)
+ goto out_release_iod_mempool;
+
+ result = nvme_alloc_admin_tag_set(&dev->ctrl, &dev->admin_tagset,
+ &nvme_mq_admin_ops, sizeof(struct nvme_iod));
+ if (result)
+ goto out_disable;
+ /*
+ * Mark the controller as connecting before sending admin commands to
+ * allow the timeout handler to do the right thing.
+ */
+ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) {
+ dev_warn(dev->ctrl.device,
+ "failed to mark controller CONNECTING\n");
+ result = -EBUSY;
+ goto out_disable;
+ }
+
+ result = nvme_init_ctrl_finish(&dev->ctrl, false);
+ if (result)
+ goto out_disable;
+
+ nvme_dbbuf_dma_alloc(dev);
+
+ result = nvme_setup_host_mem(dev);
+ if (result < 0)
+ goto out_disable;
+
+ result = nvme_setup_io_queues(dev);
+ if (result)
+ goto out_disable;
+
+ if (dev->online_queues > 1) {
+ nvme_alloc_io_tag_set(&dev->ctrl, &dev->tagset, &nvme_mq_ops,
+ nvme_pci_nr_maps(dev), sizeof(struct nvme_iod));
+ nvme_dbbuf_set(dev);
+ }
+
+ if (!dev->ctrl.tagset)
+ dev_warn(dev->ctrl.device, "IO queues not created\n");
+
+ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_LIVE)) {
+ dev_warn(dev->ctrl.device,
+ "failed to mark controller live state\n");
+ result = -ENODEV;
+ goto out_disable;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ nvme_start_ctrl(&dev->ctrl);
+ nvme_put_ctrl(&dev->ctrl);
return 0;
- release_mempool:
+out_disable:
+ nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
+ nvme_dev_disable(dev, true);
+ nvme_free_host_mem(dev);
+ nvme_dev_remove_admin(dev);
+ nvme_dbbuf_dma_free(dev);
+ nvme_free_queues(dev, 0);
+out_release_iod_mempool:
mempool_destroy(dev->iod_mempool);
- release_pools:
+out_release_prp_pools:
nvme_release_prp_pools(dev);
- unmap:
+out_dev_unmap:
nvme_dev_unmap(dev);
- put_pci:
- put_device(dev->dev);
- free:
- kfree(dev->queues);
- kfree(dev);
+out_uninit_ctrl:
+ nvme_uninit_ctrl(&dev->ctrl);
return result;
}
@@ -3208,13 +3143,6 @@ static void nvme_shutdown(struct pci_dev *pdev)
nvme_disable_prepare_reset(dev, true);
}
-static void nvme_remove_attrs(struct nvme_dev *dev)
-{
- if (dev->attrs_added)
- sysfs_remove_group(&dev->ctrl.device->kobj,
- &nvme_pci_attr_group);
-}
-
/*
* The driver's remove may be called on a device in a partially initialized
* state. This function must not have any dependencies on the device state in
@@ -3236,10 +3164,11 @@ static void nvme_remove(struct pci_dev *pdev)
nvme_stop_ctrl(&dev->ctrl);
nvme_remove_namespaces(&dev->ctrl);
nvme_dev_disable(dev, true);
- nvme_remove_attrs(dev);
nvme_free_host_mem(dev);
nvme_dev_remove_admin(dev);
+ nvme_dbbuf_dma_free(dev);
nvme_free_queues(dev, 0);
+ mempool_destroy(dev->iod_mempool);
nvme_release_prp_pools(dev);
nvme_dev_unmap(dev);
nvme_uninit_ctrl(&dev->ctrl);
@@ -3491,6 +3420,8 @@ static const struct pci_device_id nvme_id_table[] = {
NVME_QUIRK_IGNORE_DEV_SUBNQN, },
{ PCI_DEVICE(0x1344, 0x5407), /* Micron Technology Inc NVMe SSD */
.driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN },
+ { PCI_DEVICE(0x1344, 0x6001), /* Micron Nitro NVMe */
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
{ PCI_DEVICE(0x1c5c, 0x1504), /* SK Hynix PC400 */
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
{ PCI_DEVICE(0x1c5c, 0x174a), /* SK Hynix P31 SSD */
@@ -3521,6 +3452,8 @@ static const struct pci_device_id nvme_id_table[] = {
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
{ PCI_DEVICE(0x2646, 0x501E), /* KINGSTON OM3PGP4xxxxQ OS21011 NVMe SSD */
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+ { PCI_DEVICE(0x1f40, 0x5236), /* Netac Technologies Co. NV7000 NVMe SSD */
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
{ PCI_DEVICE(0x1e4B, 0x1001), /* MAXIO MAP1001 */
.driver_data = NVME_QUIRK_BOGUS_NID, },
{ PCI_DEVICE(0x1e4B, 0x1002), /* MAXIO MAP1002 */
@@ -3572,11 +3505,12 @@ static struct pci_driver nvme_driver = {
.probe = nvme_probe,
.remove = nvme_remove,
.shutdown = nvme_shutdown,
-#ifdef CONFIG_PM_SLEEP
.driver = {
- .pm = &nvme_dev_pm_ops,
- },
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &nvme_dev_pm_ops,
#endif
+ },
.sriov_configure = pci_sriov_configure_simple,
.err_handler = &nvme_err_handler,
};
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 6e079abb22ee..bbad26b82b56 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -798,7 +798,9 @@ static int nvme_rdma_alloc_tag_set(struct nvme_ctrl *ctrl)
NVME_RDMA_METADATA_SGL_SIZE;
return nvme_alloc_io_tag_set(ctrl, &to_rdma_ctrl(ctrl)->tag_set,
- &nvme_rdma_mq_ops, BLK_MQ_F_SHOULD_MERGE, cmd_size);
+ &nvme_rdma_mq_ops,
+ ctrl->opts->nr_poll_queues ? HCTX_MAX_TYPES : 2,
+ cmd_size);
}
static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl)
@@ -846,7 +848,6 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
if (new) {
error = nvme_alloc_admin_tag_set(&ctrl->ctrl,
&ctrl->admin_tag_set, &nvme_rdma_admin_mq_ops,
- BLK_MQ_F_NO_SCHED,
sizeof(struct nvme_rdma_request) +
NVME_RDMA_DATA_SGL_SIZE);
if (error)
@@ -869,16 +870,16 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
else
ctrl->ctrl.max_integrity_segments = 0;
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
- error = nvme_init_ctrl_finish(&ctrl->ctrl);
+ error = nvme_init_ctrl_finish(&ctrl->ctrl, false);
if (error)
goto out_quiesce_queue;
return 0;
out_quiesce_queue:
- nvme_stop_admin_queue(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
blk_sync_queue(ctrl->ctrl.admin_q);
out_stop_queue:
nvme_rdma_stop_queue(&ctrl->queues[0]);
@@ -922,7 +923,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
goto out_cleanup_tagset;
if (!new) {
- nvme_start_queues(&ctrl->ctrl);
+ nvme_unquiesce_io_queues(&ctrl->ctrl);
if (!nvme_wait_freeze_timeout(&ctrl->ctrl, NVME_IO_TIMEOUT)) {
/*
* If we timed out waiting for freeze we are likely to
@@ -949,7 +950,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
return 0;
out_wait_freeze_timed_out:
- nvme_stop_queues(&ctrl->ctrl);
+ nvme_quiesce_io_queues(&ctrl->ctrl);
nvme_sync_io_queues(&ctrl->ctrl);
nvme_rdma_stop_io_queues(ctrl);
out_cleanup_tagset:
@@ -964,12 +965,12 @@ out_free_io_queues:
static void nvme_rdma_teardown_admin_queue(struct nvme_rdma_ctrl *ctrl,
bool remove)
{
- nvme_stop_admin_queue(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
blk_sync_queue(ctrl->ctrl.admin_q);
nvme_rdma_stop_queue(&ctrl->queues[0]);
nvme_cancel_admin_tagset(&ctrl->ctrl);
if (remove) {
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
nvme_remove_admin_tag_set(&ctrl->ctrl);
}
nvme_rdma_destroy_admin_queue(ctrl);
@@ -980,12 +981,12 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
{
if (ctrl->ctrl.queue_count > 1) {
nvme_start_freeze(&ctrl->ctrl);
- nvme_stop_queues(&ctrl->ctrl);
+ nvme_quiesce_io_queues(&ctrl->ctrl);
nvme_sync_io_queues(&ctrl->ctrl);
nvme_rdma_stop_io_queues(ctrl);
nvme_cancel_tagset(&ctrl->ctrl);
if (remove) {
- nvme_start_queues(&ctrl->ctrl);
+ nvme_unquiesce_io_queues(&ctrl->ctrl);
nvme_remove_io_tag_set(&ctrl->ctrl);
}
nvme_rdma_free_io_queues(ctrl);
@@ -1106,7 +1107,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
destroy_io:
if (ctrl->ctrl.queue_count > 1) {
- nvme_stop_queues(&ctrl->ctrl);
+ nvme_quiesce_io_queues(&ctrl->ctrl);
nvme_sync_io_queues(&ctrl->ctrl);
nvme_rdma_stop_io_queues(ctrl);
nvme_cancel_tagset(&ctrl->ctrl);
@@ -1115,7 +1116,7 @@ destroy_io:
nvme_rdma_free_io_queues(ctrl);
}
destroy_admin:
- nvme_stop_admin_queue(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
blk_sync_queue(ctrl->ctrl.admin_q);
nvme_rdma_stop_queue(&ctrl->queues[0]);
nvme_cancel_admin_tagset(&ctrl->ctrl);
@@ -1153,13 +1154,13 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
struct nvme_rdma_ctrl *ctrl = container_of(work,
struct nvme_rdma_ctrl, err_work);
- nvme_auth_stop(&ctrl->ctrl);
nvme_stop_keep_alive(&ctrl->ctrl);
flush_work(&ctrl->ctrl.async_event_work);
nvme_rdma_teardown_io_queues(ctrl, false);
- nvme_start_queues(&ctrl->ctrl);
+ nvme_unquiesce_io_queues(&ctrl->ctrl);
nvme_rdma_teardown_admin_queue(ctrl, false);
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
+ nvme_auth_stop(&ctrl->ctrl);
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
/* state change failure is ok if we started ctrl delete */
@@ -2040,7 +2041,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
if (ret)
goto unmap_qe;
- blk_mq_start_request(rq);
+ nvme_start_request(rq);
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
queue->pi_support &&
@@ -2207,11 +2208,8 @@ static const struct blk_mq_ops nvme_rdma_admin_mq_ops = {
static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl, bool shutdown)
{
nvme_rdma_teardown_io_queues(ctrl, shutdown);
- nvme_stop_admin_queue(&ctrl->ctrl);
- if (shutdown)
- nvme_shutdown_ctrl(&ctrl->ctrl);
- else
- nvme_disable_ctrl(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
+ nvme_disable_ctrl(&ctrl->ctrl, shutdown);
nvme_rdma_teardown_admin_queue(ctrl, shutdown);
}
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 9b47dcb2a7d9..b69b89166b6b 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -301,7 +301,7 @@ static inline void nvme_tcp_advance_req(struct nvme_tcp_request *req,
if (!iov_iter_count(&req->iter) &&
req->data_sent < req->data_len) {
req->curr_bio = req->curr_bio->bi_next;
- nvme_tcp_init_iter(req, WRITE);
+ nvme_tcp_init_iter(req, ITER_SOURCE);
}
}
@@ -781,7 +781,7 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
nvme_tcp_init_recv_ctx(queue);
return -EIO;
}
- nvme_tcp_init_iter(req, READ);
+ nvme_tcp_init_iter(req, ITER_DEST);
}
/* we can read only from what is left in this bio */
@@ -1867,7 +1867,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
if (new) {
ret = nvme_alloc_io_tag_set(ctrl, &to_tcp_ctrl(ctrl)->tag_set,
&nvme_tcp_mq_ops,
- BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING,
+ ctrl->opts->nr_poll_queues ? HCTX_MAX_TYPES : 2,
sizeof(struct nvme_tcp_request));
if (ret)
goto out_free_io_queues;
@@ -1884,7 +1884,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
goto out_cleanup_connect_q;
if (!new) {
- nvme_start_queues(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) {
/*
* If we timed out waiting for freeze we are likely to
@@ -1911,7 +1911,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
return 0;
out_wait_freeze_timed_out:
- nvme_stop_queues(ctrl);
+ nvme_quiesce_io_queues(ctrl);
nvme_sync_io_queues(ctrl);
nvme_tcp_stop_io_queues(ctrl);
out_cleanup_connect_q:
@@ -1942,7 +1942,7 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
if (new) {
error = nvme_alloc_admin_tag_set(ctrl,
&to_tcp_ctrl(ctrl)->admin_tag_set,
- &nvme_tcp_admin_mq_ops, BLK_MQ_F_BLOCKING,
+ &nvme_tcp_admin_mq_ops,
sizeof(struct nvme_tcp_request));
if (error)
goto out_free_queue;
@@ -1956,16 +1956,16 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
if (error)
goto out_stop_queue;
- nvme_start_admin_queue(ctrl);
+ nvme_unquiesce_admin_queue(ctrl);
- error = nvme_init_ctrl_finish(ctrl);
+ error = nvme_init_ctrl_finish(ctrl, false);
if (error)
goto out_quiesce_queue;
return 0;
out_quiesce_queue:
- nvme_stop_admin_queue(ctrl);
+ nvme_quiesce_admin_queue(ctrl);
blk_sync_queue(ctrl->admin_q);
out_stop_queue:
nvme_tcp_stop_queue(ctrl, 0);
@@ -1981,12 +1981,12 @@ out_free_queue:
static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
bool remove)
{
- nvme_stop_admin_queue(ctrl);
+ nvme_quiesce_admin_queue(ctrl);
blk_sync_queue(ctrl->admin_q);
nvme_tcp_stop_queue(ctrl, 0);
nvme_cancel_admin_tagset(ctrl);
if (remove)
- nvme_start_admin_queue(ctrl);
+ nvme_unquiesce_admin_queue(ctrl);
nvme_tcp_destroy_admin_queue(ctrl, remove);
}
@@ -1995,14 +1995,14 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
{
if (ctrl->queue_count <= 1)
return;
- nvme_stop_admin_queue(ctrl);
+ nvme_quiesce_admin_queue(ctrl);
nvme_start_freeze(ctrl);
- nvme_stop_queues(ctrl);
+ nvme_quiesce_io_queues(ctrl);
nvme_sync_io_queues(ctrl);
nvme_tcp_stop_io_queues(ctrl);
nvme_cancel_tagset(ctrl);
if (remove)
- nvme_start_queues(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
nvme_tcp_destroy_io_queues(ctrl, remove);
}
@@ -2083,14 +2083,14 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
destroy_io:
if (ctrl->queue_count > 1) {
- nvme_stop_queues(ctrl);
+ nvme_quiesce_io_queues(ctrl);
nvme_sync_io_queues(ctrl);
nvme_tcp_stop_io_queues(ctrl);
nvme_cancel_tagset(ctrl);
nvme_tcp_destroy_io_queues(ctrl, new);
}
destroy_admin:
- nvme_stop_admin_queue(ctrl);
+ nvme_quiesce_admin_queue(ctrl);
blk_sync_queue(ctrl->admin_q);
nvme_tcp_stop_queue(ctrl, 0);
nvme_cancel_admin_tagset(ctrl);
@@ -2128,14 +2128,14 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
struct nvme_tcp_ctrl, err_work);
struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
- nvme_auth_stop(ctrl);
nvme_stop_keep_alive(ctrl);
flush_work(&ctrl->async_event_work);
nvme_tcp_teardown_io_queues(ctrl, false);
/* unquiesce to fail fast pending requests */
- nvme_start_queues(ctrl);
+ nvme_unquiesce_io_queues(ctrl);
nvme_tcp_teardown_admin_queue(ctrl, false);
- nvme_start_admin_queue(ctrl);
+ nvme_unquiesce_admin_queue(ctrl);
+ nvme_auth_stop(ctrl);
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING)) {
/* state change failure is ok if we started ctrl delete */
@@ -2150,11 +2150,8 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
static void nvme_tcp_teardown_ctrl(struct nvme_ctrl *ctrl, bool shutdown)
{
nvme_tcp_teardown_io_queues(ctrl, shutdown);
- nvme_stop_admin_queue(ctrl);
- if (shutdown)
- nvme_shutdown_ctrl(ctrl);
- else
- nvme_disable_ctrl(ctrl);
+ nvme_quiesce_admin_queue(ctrl);
+ nvme_disable_ctrl(ctrl, shutdown);
nvme_tcp_teardown_admin_queue(ctrl, shutdown);
}
@@ -2414,7 +2411,7 @@ static blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx,
if (unlikely(ret))
return ret;
- blk_mq_start_request(rq);
+ nvme_start_request(rq);
nvme_tcp_queue_request(req, true, bd->last);
@@ -2523,7 +2520,7 @@ static const struct blk_mq_ops nvme_tcp_admin_mq_ops = {
static const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = {
.name = "tcp",
.module = THIS_MODULE,
- .flags = NVME_F_FABRICS,
+ .flags = NVME_F_FABRICS | NVME_F_BLOCKING,
.reg_read32 = nvmf_reg_read32,
.reg_read64 = nvmf_reg_read64,
.reg_write32 = nvmf_reg_write32,
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index c8a061ce3ee5..53a004ea320c 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -370,7 +370,9 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
memcpy_and_pad(id->mn, sizeof(id->mn), subsys->model_number,
strlen(subsys->model_number), ' ');
memcpy_and_pad(id->fr, sizeof(id->fr),
- UTS_RELEASE, strlen(UTS_RELEASE), ' ');
+ subsys->firmware_rev, strlen(subsys->firmware_rev), ' ');
+
+ put_unaligned_le24(subsys->ieee_oui, id->ieee);
id->rab = 6;
@@ -379,11 +381,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
else
id->cntrltype = NVME_CTRL_IO;
- /*
- * XXX: figure out how we can assign a IEEE OUI, but until then
- * the safest is to leave it as zeroes.
- */
-
/* we support multiple ports, multiples hosts and ANA: */
id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL |
NVME_CTRL_CMIC_ANA;
@@ -564,7 +561,7 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
}
if (req->ns->readonly)
- id->nsattr |= (1 << 0);
+ id->nsattr |= NVME_NS_ATTR_RO;
done:
if (!status)
status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index c4113b43dbfe..4dcddcf95279 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -45,9 +45,11 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
if (!dhchap_secret)
return -ENOMEM;
if (set_ctrl) {
+ kfree(host->dhchap_ctrl_secret);
host->dhchap_ctrl_secret = strim(dhchap_secret);
host->dhchap_ctrl_key_hash = key_hash;
} else {
+ kfree(host->dhchap_secret);
host->dhchap_secret = strim(dhchap_secret);
host->dhchap_key_hash = key_hash;
}
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 9443ee1d4ae3..907143870da5 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -4,6 +4,7 @@
* Copyright (c) 2015-2016 HGST, a Western Digital Company.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kstrtox.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -267,7 +268,7 @@ static ssize_t nvmet_param_pi_enable_store(struct config_item *item,
struct nvmet_port *port = to_nvmet_port(item);
bool val;
- if (strtobool(page, &val))
+ if (kstrtobool(page, &val))
return -EINVAL;
if (nvmet_is_port_enabled(port, __func__))
@@ -532,7 +533,7 @@ static ssize_t nvmet_ns_enable_store(struct config_item *item,
bool enable;
int ret = 0;
- if (strtobool(page, &enable))
+ if (kstrtobool(page, &enable))
return -EINVAL;
if (enable)
@@ -556,7 +557,7 @@ static ssize_t nvmet_ns_buffered_io_store(struct config_item *item,
struct nvmet_ns *ns = to_nvmet_ns(item);
bool val;
- if (strtobool(page, &val))
+ if (kstrtobool(page, &val))
return -EINVAL;
mutex_lock(&ns->subsys->lock);
@@ -579,7 +580,7 @@ static ssize_t nvmet_ns_revalidate_size_store(struct config_item *item,
struct nvmet_ns *ns = to_nvmet_ns(item);
bool val;
- if (strtobool(page, &val))
+ if (kstrtobool(page, &val))
return -EINVAL;
if (!val)
@@ -728,7 +729,7 @@ static ssize_t nvmet_passthru_enable_store(struct config_item *item,
bool enable;
int ret = 0;
- if (strtobool(page, &enable))
+ if (kstrtobool(page, &enable))
return -EINVAL;
if (enable)
@@ -995,7 +996,7 @@ static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item,
bool allow_any_host;
int ret = 0;
- if (strtobool(page, &allow_any_host))
+ if (kstrtobool(page, &allow_any_host))
return -EINVAL;
down_write(&nvmet_config_sem);
@@ -1215,6 +1216,7 @@ static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
const char *page, size_t count)
{
int pos = 0, len;
+ char *val;
if (subsys->subsys_discovered) {
pr_err("Can't set model number. %s is already assigned\n",
@@ -1237,9 +1239,11 @@ static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
return -EINVAL;
}
- subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL);
- if (!subsys->model_number)
+ val = kmemdup_nul(page, len, GFP_KERNEL);
+ if (!val)
return -ENOMEM;
+ kfree(subsys->model_number);
+ subsys->model_number = val;
return count;
}
@@ -1259,6 +1263,116 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
}
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+static ssize_t nvmet_subsys_attr_ieee_oui_show(struct config_item *item,
+ char *page)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+
+ return sysfs_emit(page, "0x%06x\n", subsys->ieee_oui);
+}
+
+static ssize_t nvmet_subsys_attr_ieee_oui_store_locked(struct nvmet_subsys *subsys,
+ const char *page, size_t count)
+{
+ uint32_t val = 0;
+ int ret;
+
+ if (subsys->subsys_discovered) {
+ pr_err("Can't set IEEE OUI. 0x%06x is already assigned\n",
+ subsys->ieee_oui);
+ return -EINVAL;
+ }
+
+ ret = kstrtou32(page, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val >= 0x1000000)
+ return -EINVAL;
+
+ subsys->ieee_oui = val;
+
+ return count;
+}
+
+static ssize_t nvmet_subsys_attr_ieee_oui_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ ssize_t ret;
+
+ down_write(&nvmet_config_sem);
+ mutex_lock(&subsys->lock);
+ ret = nvmet_subsys_attr_ieee_oui_store_locked(subsys, page, count);
+ mutex_unlock(&subsys->lock);
+ up_write(&nvmet_config_sem);
+
+ return ret;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_ieee_oui);
+
+static ssize_t nvmet_subsys_attr_firmware_show(struct config_item *item,
+ char *page)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+
+ return sysfs_emit(page, "%s\n", subsys->firmware_rev);
+}
+
+static ssize_t nvmet_subsys_attr_firmware_store_locked(struct nvmet_subsys *subsys,
+ const char *page, size_t count)
+{
+ int pos = 0, len;
+ char *val;
+
+ if (subsys->subsys_discovered) {
+ pr_err("Can't set firmware revision. %s is already assigned\n",
+ subsys->firmware_rev);
+ return -EINVAL;
+ }
+
+ len = strcspn(page, "\n");
+ if (!len)
+ return -EINVAL;
+
+ if (len > NVMET_FR_MAX_SIZE) {
+ pr_err("Firmware revision size can not exceed %d Bytes\n",
+ NVMET_FR_MAX_SIZE);
+ return -EINVAL;
+ }
+
+ for (pos = 0; pos < len; pos++) {
+ if (!nvmet_is_ascii(page[pos]))
+ return -EINVAL;
+ }
+
+ val = kmemdup_nul(page, len, GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
+
+ kfree(subsys->firmware_rev);
+
+ subsys->firmware_rev = val;
+
+ return count;
+}
+
+static ssize_t nvmet_subsys_attr_firmware_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ ssize_t ret;
+
+ down_write(&nvmet_config_sem);
+ mutex_lock(&subsys->lock);
+ ret = nvmet_subsys_attr_firmware_store_locked(subsys, page, count);
+ mutex_unlock(&subsys->lock);
+ up_write(&nvmet_config_sem);
+
+ return ret;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_firmware);
+
#ifdef CONFIG_BLK_DEV_INTEGRITY
static ssize_t nvmet_subsys_attr_pi_enable_show(struct config_item *item,
char *page)
@@ -1272,7 +1386,7 @@ static ssize_t nvmet_subsys_attr_pi_enable_store(struct config_item *item,
struct nvmet_subsys *subsys = to_subsys(item);
bool pi_enable;
- if (strtobool(page, &pi_enable))
+ if (kstrtobool(page, &pi_enable))
return -EINVAL;
subsys->pi_support = pi_enable;
@@ -1290,6 +1404,8 @@ static ssize_t nvmet_subsys_attr_qid_max_show(struct config_item *item,
static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
const char *page, size_t cnt)
{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ struct nvmet_ctrl *ctrl;
u16 qid_max;
if (sscanf(page, "%hu\n", &qid_max) != 1)
@@ -1299,8 +1415,13 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
return -EINVAL;
down_write(&nvmet_config_sem);
- to_subsys(item)->max_qid = qid_max;
+ subsys->max_qid = qid_max;
+
+ /* Force reconnect */
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ ctrl->ops->delete_ctrl(ctrl);
up_write(&nvmet_config_sem);
+
return cnt;
}
CONFIGFS_ATTR(nvmet_subsys_, attr_qid_max);
@@ -1313,6 +1434,8 @@ static struct configfs_attribute *nvmet_subsys_attrs[] = {
&nvmet_subsys_attr_attr_cntlid_max,
&nvmet_subsys_attr_attr_model,
&nvmet_subsys_attr_attr_qid_max,
+ &nvmet_subsys_attr_attr_ieee_oui,
+ &nvmet_subsys_attr_attr_firmware,
#ifdef CONFIG_BLK_DEV_INTEGRITY
&nvmet_subsys_attr_attr_pi_enable,
#endif
@@ -1392,7 +1515,7 @@ static ssize_t nvmet_referral_enable_store(struct config_item *item,
struct nvmet_port *port = to_nvmet_port(item);
bool enable;
- if (strtobool(page, &enable))
+ if (kstrtobool(page, &enable))
goto inval;
if (enable)
@@ -1836,6 +1959,7 @@ static void nvmet_host_release(struct config_item *item)
#ifdef CONFIG_NVME_TARGET_AUTH
kfree(host->dhchap_secret);
+ kfree(host->dhchap_ctrl_secret);
#endif
kfree(host);
}
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index aecb5853f8da..f66ed13d7c11 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -10,11 +10,14 @@
#include <linux/pci-p2pdma.h>
#include <linux/scatterlist.h>
+#include <generated/utsrelease.h>
+
#define CREATE_TRACE_POINTS
#include "trace.h"
#include "nvmet.h"
+struct kmem_cache *nvmet_bvec_cache;
struct workqueue_struct *buffered_io_wq;
struct workqueue_struct *zbd_wq;
static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
@@ -695,11 +698,10 @@ static void nvmet_update_sq_head(struct nvmet_req *req)
if (req->sq->size) {
u32 old_sqhd, new_sqhd;
+ old_sqhd = READ_ONCE(req->sq->sqhd);
do {
- old_sqhd = req->sq->sqhd;
new_sqhd = (old_sqhd + 1) % req->sq->size;
- } while (cmpxchg(&req->sq->sqhd, old_sqhd, new_sqhd) !=
- old_sqhd);
+ } while (!try_cmpxchg(&req->sq->sqhd, &old_sqhd, new_sqhd));
}
req->cqe->sq_head = cpu_to_le16(req->sq->sqhd & 0x0000FFFF);
}
@@ -1561,6 +1563,14 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
goto free_subsys;
}
+ subsys->ieee_oui = 0;
+
+ subsys->firmware_rev = kstrndup(UTS_RELEASE, NVMET_FR_MAX_SIZE, GFP_KERNEL);
+ if (!subsys->firmware_rev) {
+ ret = -ENOMEM;
+ goto free_mn;
+ }
+
switch (type) {
case NVME_NQN_NVME:
subsys->max_qid = NVMET_NR_QUEUES;
@@ -1572,14 +1582,14 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
default:
pr_err("%s: Unknown Subsystem type - %d\n", __func__, type);
ret = -EINVAL;
- goto free_mn;
+ goto free_fr;
}
subsys->type = type;
subsys->subsysnqn = kstrndup(subsysnqn, NVMF_NQN_SIZE,
GFP_KERNEL);
if (!subsys->subsysnqn) {
ret = -ENOMEM;
- goto free_mn;
+ goto free_fr;
}
subsys->cntlid_min = NVME_CNTLID_MIN;
subsys->cntlid_max = NVME_CNTLID_MAX;
@@ -1592,6 +1602,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
return subsys;
+free_fr:
+ kfree(subsys->firmware_rev);
free_mn:
kfree(subsys->model_number);
free_subsys:
@@ -1611,6 +1623,7 @@ static void nvmet_subsys_free(struct kref *ref)
kfree(subsys->subsysnqn);
kfree(subsys->model_number);
+ kfree(subsys->firmware_rev);
kfree(subsys);
}
@@ -1631,26 +1644,28 @@ void nvmet_subsys_put(struct nvmet_subsys *subsys)
static int __init nvmet_init(void)
{
- int error;
+ int error = -ENOMEM;
nvmet_ana_group_enabled[NVMET_DEFAULT_ANA_GRPID] = 1;
+ nvmet_bvec_cache = kmem_cache_create("nvmet-bvec",
+ NVMET_MAX_MPOOL_BVEC * sizeof(struct bio_vec), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!nvmet_bvec_cache)
+ return -ENOMEM;
+
zbd_wq = alloc_workqueue("nvmet-zbd-wq", WQ_MEM_RECLAIM, 0);
if (!zbd_wq)
- return -ENOMEM;
+ goto out_destroy_bvec_cache;
buffered_io_wq = alloc_workqueue("nvmet-buffered-io-wq",
WQ_MEM_RECLAIM, 0);
- if (!buffered_io_wq) {
- error = -ENOMEM;
+ if (!buffered_io_wq)
goto out_free_zbd_work_queue;
- }
nvmet_wq = alloc_workqueue("nvmet-wq", WQ_MEM_RECLAIM, 0);
- if (!nvmet_wq) {
- error = -ENOMEM;
+ if (!nvmet_wq)
goto out_free_buffered_work_queue;
- }
error = nvmet_init_discovery();
if (error)
@@ -1669,6 +1684,8 @@ out_free_buffered_work_queue:
destroy_workqueue(buffered_io_wq);
out_free_zbd_work_queue:
destroy_workqueue(zbd_wq);
+out_destroy_bvec_cache:
+ kmem_cache_destroy(nvmet_bvec_cache);
return error;
}
@@ -1680,6 +1697,7 @@ static void __exit nvmet_exit(void)
destroy_workqueue(nvmet_wq);
destroy_workqueue(buffered_io_wq);
destroy_workqueue(zbd_wq);
+ kmem_cache_destroy(nvmet_bvec_cache);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_entry) != 1024);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_hdr) != 1024);
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 64b47e2a4633..871c4f32f443 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -11,7 +11,6 @@
#include <linux/fs.h>
#include "nvmet.h"
-#define NVMET_MAX_MPOOL_BVEC 16
#define NVMET_MIN_MPOOL_OBJ 16
void nvmet_file_ns_revalidate(struct nvmet_ns *ns)
@@ -26,8 +25,6 @@ void nvmet_file_ns_disable(struct nvmet_ns *ns)
flush_workqueue(buffered_io_wq);
mempool_destroy(ns->bvec_pool);
ns->bvec_pool = NULL;
- kmem_cache_destroy(ns->bvec_cache);
- ns->bvec_cache = NULL;
fput(ns->file);
ns->file = NULL;
}
@@ -59,16 +56,8 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
ns->blksize_shift = min_t(u8,
file_inode(ns->file)->i_blkbits, 12);
- ns->bvec_cache = kmem_cache_create("nvmet-bvec",
- NVMET_MAX_MPOOL_BVEC * sizeof(struct bio_vec),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!ns->bvec_cache) {
- ret = -ENOMEM;
- goto err;
- }
-
ns->bvec_pool = mempool_create(NVMET_MIN_MPOOL_OBJ, mempool_alloc_slab,
- mempool_free_slab, ns->bvec_cache);
+ mempool_free_slab, nvmet_bvec_cache);
if (!ns->bvec_pool) {
ret = -ENOMEM;
@@ -77,9 +66,10 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
return ret;
err:
+ fput(ns->file);
+ ns->file = NULL;
ns->size = 0;
ns->blksize_shift = 0;
- nvmet_file_ns_disable(ns);
return ret;
}
@@ -102,10 +92,10 @@ static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos,
if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
ki_flags |= IOCB_DSYNC;
call_iter = req->ns->file->f_op->write_iter;
- rw = WRITE;
+ rw = ITER_SOURCE;
} else {
call_iter = req->ns->file->f_op->read_iter;
- rw = READ;
+ rw = ITER_DEST;
}
iov_iter_bvec(&iter, rw, req->f.bvec, nr_segs, count);
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index b45fe3adf015..f2d24b2d992f 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -145,7 +145,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
if (ret)
return ret;
- blk_mq_start_request(req);
+ nvme_start_request(req);
iod->cmd.common.flags |= NVME_CMD_SGL_METABUF;
iod->req.port = queue->ctrl->port;
if (!nvmet_req_init(&iod->req, &queue->nvme_cq,
@@ -353,7 +353,7 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
ctrl->ctrl.queue_count = 1;
error = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
- &nvme_loop_admin_mq_ops, BLK_MQ_F_NO_SCHED,
+ &nvme_loop_admin_mq_ops,
sizeof(struct nvme_loop_iod) +
NVME_INLINE_SG_CNT * sizeof(struct scatterlist));
if (error)
@@ -375,9 +375,9 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
ctrl->ctrl.max_hw_sectors =
(NVME_LOOP_MAX_SEGMENTS - 1) << (PAGE_SHIFT - 9);
- nvme_start_admin_queue(&ctrl->ctrl);
+ nvme_unquiesce_admin_queue(&ctrl->ctrl);
- error = nvme_init_ctrl_finish(&ctrl->ctrl);
+ error = nvme_init_ctrl_finish(&ctrl->ctrl, false);
if (error)
goto out_cleanup_tagset;
@@ -394,14 +394,14 @@ out_free_sq:
static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl)
{
if (ctrl->ctrl.queue_count > 1) {
- nvme_stop_queues(&ctrl->ctrl);
+ nvme_quiesce_io_queues(&ctrl->ctrl);
nvme_cancel_tagset(&ctrl->ctrl);
nvme_loop_destroy_io_queues(ctrl);
}
- nvme_stop_admin_queue(&ctrl->ctrl);
+ nvme_quiesce_admin_queue(&ctrl->ctrl);
if (ctrl->ctrl.state == NVME_CTRL_LIVE)
- nvme_shutdown_ctrl(&ctrl->ctrl);
+ nvme_disable_ctrl(&ctrl->ctrl, true);
nvme_cancel_admin_tagset(&ctrl->ctrl);
nvme_loop_destroy_admin_queue(ctrl);
@@ -494,7 +494,7 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
return ret;
ret = nvme_alloc_io_tag_set(&ctrl->ctrl, &ctrl->tag_set,
- &nvme_loop_mq_ops, BLK_MQ_F_SHOULD_MERGE,
+ &nvme_loop_mq_ops, 1,
sizeof(struct nvme_loop_iod) +
NVME_INLINE_SG_CNT * sizeof(struct scatterlist));
if (ret)
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index dfe3894205aa..89bedfcd974c 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -29,6 +29,7 @@
#define NVMET_DEFAULT_CTRL_MODEL "Linux"
#define NVMET_MN_MAX_SIZE 40
#define NVMET_SN_MAX_SIZE 20
+#define NVMET_FR_MAX_SIZE 8
/*
* Supported optional AENs:
@@ -77,7 +78,6 @@ struct nvmet_ns {
struct completion disable_done;
mempool_t *bvec_pool;
- struct kmem_cache *bvec_cache;
int use_p2pmem;
struct pci_dev *p2p_dev;
@@ -264,6 +264,8 @@ struct nvmet_subsys {
struct config_group allowed_hosts_group;
char *model_number;
+ u32 ieee_oui;
+ char *firmware_rev;
#ifdef CONFIG_NVME_TARGET_PASSTHRU
struct nvme_ctrl *passthru_ctrl;
@@ -393,6 +395,8 @@ struct nvmet_req {
u64 error_slba;
};
+#define NVMET_MAX_MPOOL_BVEC 16
+extern struct kmem_cache *nvmet_bvec_cache;
extern struct workqueue_struct *buffered_io_wq;
extern struct workqueue_struct *zbd_wq;
extern struct workqueue_struct *nvmet_wq;
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 6c1476e086ef..cc05c094de22 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -331,7 +331,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
sg_offset = 0;
}
- iov_iter_bvec(&cmd->recv_msg.msg_iter, READ, cmd->iov,
+ iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov,
nr_pages, cmd->pdu_len);
}
diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c
index 4441daa20965..34130449f2d2 100644
--- a/drivers/nvmem/brcm_nvram.c
+++ b/drivers/nvmem/brcm_nvram.c
@@ -3,6 +3,7 @@
* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
*/
+#include <linux/bcm47xx_nvram.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -136,6 +137,8 @@ static int brcm_nvram_probe(struct platform_device *pdev)
if (err)
return err;
+ bcm47xx_nvram_init_from_iomem(priv->base, resource_size(res));
+
config.dev = dev;
config.cells = priv->cells;
config.ncells = priv->ncells;
diff --git a/drivers/nvmem/lan9662-otpc.c b/drivers/nvmem/lan9662-otpc.c
index f6732fd216d8..56fc19f092a7 100644
--- a/drivers/nvmem/lan9662-otpc.c
+++ b/drivers/nvmem/lan9662-otpc.c
@@ -36,7 +36,7 @@ struct lan9662_otp {
void __iomem *base;
};
-static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag)
+static int lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag)
{
u32 val;
@@ -203,7 +203,7 @@ static int lan9662_otp_probe(struct platform_device *pdev)
}
static const struct of_device_id lan9662_otp_match[] = {
- { .compatible = "microchip,lan9662-otp", },
+ { .compatible = "microchip,lan9662-otpc", },
{ },
};
MODULE_DEVICE_TABLE(of, lan9662_otp_match);
diff --git a/drivers/nvmem/rmem.c b/drivers/nvmem/rmem.c
index b11c3c974b3d..80cb187f1481 100644
--- a/drivers/nvmem/rmem.c
+++ b/drivers/nvmem/rmem.c
@@ -37,9 +37,9 @@ static int rmem_read(void *context, unsigned int offset,
* but as of Dec 2020 this isn't possible on arm64.
*/
addr = memremap(priv->mem->base, available, MEMREMAP_WB);
- if (IS_ERR(addr)) {
+ if (!addr) {
dev_err(priv->dev, "Failed to remap memory region\n");
- return PTR_ERR(addr);
+ return -ENOMEM;
}
count = memory_read_from_buffer(val, bytes, &off, addr, available);
diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c
index 8e72d1bbd649..4fdbdccebda1 100644
--- a/drivers/nvmem/u-boot-env.c
+++ b/drivers/nvmem/u-boot-env.c
@@ -135,7 +135,7 @@ static int u_boot_env_parse(struct u_boot_env *priv)
break;
case U_BOOT_FORMAT_REDUNDANT:
crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark);
+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
data_offset = offsetof(struct u_boot_env_image_redundant, data);
break;
}
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 967f79b59016..134cfc980b70 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -993,8 +993,10 @@ of_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
nargs, index, &of_args);
if (ret < 0)
return ret;
- if (!args)
+ if (!args) {
+ of_node_put(of_args.np);
return 0;
+ }
args->nargs = of_args.args_count;
args->fwnode = of_fwnode_handle(of_args.np);
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
index d072f3ba3971..ea5f4da68e23 100644
--- a/drivers/of/unittest-data/Makefile
+++ b/drivers/of/unittest-data/Makefile
@@ -1,38 +1,38 @@
# SPDX-License-Identifier: GPL-2.0
-obj-y += testcases.dtb.o
+obj-y += testcases.dtbo.o
-obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
- overlay_0.dtb.o \
- overlay_1.dtb.o \
- overlay_2.dtb.o \
- overlay_3.dtb.o \
- overlay_4.dtb.o \
- overlay_5.dtb.o \
- overlay_6.dtb.o \
- overlay_7.dtb.o \
- overlay_8.dtb.o \
- overlay_9.dtb.o \
- overlay_10.dtb.o \
- overlay_11.dtb.o \
- overlay_12.dtb.o \
- overlay_13.dtb.o \
- overlay_15.dtb.o \
- overlay_16.dtb.o \
- overlay_17.dtb.o \
- overlay_18.dtb.o \
- overlay_19.dtb.o \
- overlay_20.dtb.o \
- overlay_bad_add_dup_node.dtb.o \
- overlay_bad_add_dup_prop.dtb.o \
- overlay_bad_phandle.dtb.o \
- overlay_bad_symbol.dtb.o \
- overlay_base.dtb.o \
- overlay_gpio_01.dtb.o \
- overlay_gpio_02a.dtb.o \
- overlay_gpio_02b.dtb.o \
- overlay_gpio_03.dtb.o \
- overlay_gpio_04a.dtb.o \
- overlay_gpio_04b.dtb.o
+obj-$(CONFIG_OF_OVERLAY) += overlay.dtbo.o \
+ overlay_0.dtbo.o \
+ overlay_1.dtbo.o \
+ overlay_2.dtbo.o \
+ overlay_3.dtbo.o \
+ overlay_4.dtbo.o \
+ overlay_5.dtbo.o \
+ overlay_6.dtbo.o \
+ overlay_7.dtbo.o \
+ overlay_8.dtbo.o \
+ overlay_9.dtbo.o \
+ overlay_10.dtbo.o \
+ overlay_11.dtbo.o \
+ overlay_12.dtbo.o \
+ overlay_13.dtbo.o \
+ overlay_15.dtbo.o \
+ overlay_16.dtbo.o \
+ overlay_17.dtbo.o \
+ overlay_18.dtbo.o \
+ overlay_19.dtbo.o \
+ overlay_20.dtbo.o \
+ overlay_bad_add_dup_node.dtbo.o \
+ overlay_bad_add_dup_prop.dtbo.o \
+ overlay_bad_phandle.dtbo.o \
+ overlay_bad_symbol.dtbo.o \
+ overlay_base.dtbo.o \
+ overlay_gpio_01.dtbo.o \
+ overlay_gpio_02a.dtbo.o \
+ overlay_gpio_02b.dtbo.o \
+ overlay_gpio_03.dtbo.o \
+ overlay_gpio_04a.dtbo.o \
+ overlay_gpio_04b.dtbo.o
# enable creation of __symbols__ node
DTC_FLAGS_overlay += -@
diff --git a/drivers/of/unittest-data/overlay.dts b/drivers/of/unittest-data/overlay.dtso
index 3bbc59e922fe..3bbc59e922fe 100644
--- a/drivers/of/unittest-data/overlay.dts
+++ b/drivers/of/unittest-data/overlay.dtso
diff --git a/drivers/of/unittest-data/overlay_0.dts b/drivers/of/unittest-data/overlay_0.dtso
index ac0f9e0fe65f..ac0f9e0fe65f 100644
--- a/drivers/of/unittest-data/overlay_0.dts
+++ b/drivers/of/unittest-data/overlay_0.dtso
diff --git a/drivers/of/unittest-data/overlay_1.dts b/drivers/of/unittest-data/overlay_1.dtso
index e92a626e2948..e92a626e2948 100644
--- a/drivers/of/unittest-data/overlay_1.dts
+++ b/drivers/of/unittest-data/overlay_1.dtso
diff --git a/drivers/of/unittest-data/overlay_10.dts b/drivers/of/unittest-data/overlay_10.dtso
index 73993bf23bf8..73993bf23bf8 100644
--- a/drivers/of/unittest-data/overlay_10.dts
+++ b/drivers/of/unittest-data/overlay_10.dtso
diff --git a/drivers/of/unittest-data/overlay_11.dts b/drivers/of/unittest-data/overlay_11.dtso
index 9a79b253a809..9a79b253a809 100644
--- a/drivers/of/unittest-data/overlay_11.dts
+++ b/drivers/of/unittest-data/overlay_11.dtso
diff --git a/drivers/of/unittest-data/overlay_12.dts b/drivers/of/unittest-data/overlay_12.dtso
index ca3441e2cbec..ca3441e2cbec 100644
--- a/drivers/of/unittest-data/overlay_12.dts
+++ b/drivers/of/unittest-data/overlay_12.dtso
diff --git a/drivers/of/unittest-data/overlay_13.dts b/drivers/of/unittest-data/overlay_13.dtso
index 3c30dec63894..3c30dec63894 100644
--- a/drivers/of/unittest-data/overlay_13.dts
+++ b/drivers/of/unittest-data/overlay_13.dtso
diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dtso
index 5728490474f6..5728490474f6 100644
--- a/drivers/of/unittest-data/overlay_15.dts
+++ b/drivers/of/unittest-data/overlay_15.dtso
diff --git a/drivers/of/unittest-data/overlay_16.dts b/drivers/of/unittest-data/overlay_16.dtso
index 80a46dc02581..80a46dc02581 100644
--- a/drivers/of/unittest-data/overlay_16.dts
+++ b/drivers/of/unittest-data/overlay_16.dtso
diff --git a/drivers/of/unittest-data/overlay_17.dts b/drivers/of/unittest-data/overlay_17.dtso
index 5b8a2209177f..5b8a2209177f 100644
--- a/drivers/of/unittest-data/overlay_17.dts
+++ b/drivers/of/unittest-data/overlay_17.dtso
diff --git a/drivers/of/unittest-data/overlay_18.dts b/drivers/of/unittest-data/overlay_18.dtso
index dcddd5f6d301..dcddd5f6d301 100644
--- a/drivers/of/unittest-data/overlay_18.dts
+++ b/drivers/of/unittest-data/overlay_18.dtso
diff --git a/drivers/of/unittest-data/overlay_19.dts b/drivers/of/unittest-data/overlay_19.dtso
index 32b3ba0b66a3..32b3ba0b66a3 100644
--- a/drivers/of/unittest-data/overlay_19.dts
+++ b/drivers/of/unittest-data/overlay_19.dtso
diff --git a/drivers/of/unittest-data/overlay_2.dts b/drivers/of/unittest-data/overlay_2.dtso
index db8684ba89d9..db8684ba89d9 100644
--- a/drivers/of/unittest-data/overlay_2.dts
+++ b/drivers/of/unittest-data/overlay_2.dtso
diff --git a/drivers/of/unittest-data/overlay_20.dts b/drivers/of/unittest-data/overlay_20.dtso
index d4a4f2f32ec7..d4a4f2f32ec7 100644
--- a/drivers/of/unittest-data/overlay_20.dts
+++ b/drivers/of/unittest-data/overlay_20.dtso
diff --git a/drivers/of/unittest-data/overlay_3.dts b/drivers/of/unittest-data/overlay_3.dtso
index 40f289e7c237..40f289e7c237 100644
--- a/drivers/of/unittest-data/overlay_3.dts
+++ b/drivers/of/unittest-data/overlay_3.dtso
diff --git a/drivers/of/unittest-data/overlay_4.dts b/drivers/of/unittest-data/overlay_4.dtso
index a8a77ddf9abe..a8a77ddf9abe 100644
--- a/drivers/of/unittest-data/overlay_4.dts
+++ b/drivers/of/unittest-data/overlay_4.dtso
diff --git a/drivers/of/unittest-data/overlay_5.dts b/drivers/of/unittest-data/overlay_5.dtso
index 706f5f1b737c..706f5f1b737c 100644
--- a/drivers/of/unittest-data/overlay_5.dts
+++ b/drivers/of/unittest-data/overlay_5.dtso
diff --git a/drivers/of/unittest-data/overlay_6.dts b/drivers/of/unittest-data/overlay_6.dtso
index 21a7fa4ca45e..21a7fa4ca45e 100644
--- a/drivers/of/unittest-data/overlay_6.dts
+++ b/drivers/of/unittest-data/overlay_6.dtso
diff --git a/drivers/of/unittest-data/overlay_7.dts b/drivers/of/unittest-data/overlay_7.dtso
index 58ba1bb51b50..58ba1bb51b50 100644
--- a/drivers/of/unittest-data/overlay_7.dts
+++ b/drivers/of/unittest-data/overlay_7.dtso
diff --git a/drivers/of/unittest-data/overlay_8.dts b/drivers/of/unittest-data/overlay_8.dtso
index e9718d118e38..e9718d118e38 100644
--- a/drivers/of/unittest-data/overlay_8.dts
+++ b/drivers/of/unittest-data/overlay_8.dtso
diff --git a/drivers/of/unittest-data/overlay_9.dts b/drivers/of/unittest-data/overlay_9.dtso
index b35e23edae50..b35e23edae50 100644
--- a/drivers/of/unittest-data/overlay_9.dts
+++ b/drivers/of/unittest-data/overlay_9.dtso
diff --git a/drivers/of/unittest-data/overlay_bad_add_dup_node.dts b/drivers/of/unittest-data/overlay_bad_add_dup_node.dtso
index 145dfc3b1024..145dfc3b1024 100644
--- a/drivers/of/unittest-data/overlay_bad_add_dup_node.dts
+++ b/drivers/of/unittest-data/overlay_bad_add_dup_node.dtso
diff --git a/drivers/of/unittest-data/overlay_bad_add_dup_prop.dts b/drivers/of/unittest-data/overlay_bad_add_dup_prop.dtso
index 6327d1ffb963..6327d1ffb963 100644
--- a/drivers/of/unittest-data/overlay_bad_add_dup_prop.dts
+++ b/drivers/of/unittest-data/overlay_bad_add_dup_prop.dtso
diff --git a/drivers/of/unittest-data/overlay_bad_phandle.dts b/drivers/of/unittest-data/overlay_bad_phandle.dtso
index 83b797360318..83b797360318 100644
--- a/drivers/of/unittest-data/overlay_bad_phandle.dts
+++ b/drivers/of/unittest-data/overlay_bad_phandle.dtso
diff --git a/drivers/of/unittest-data/overlay_bad_symbol.dts b/drivers/of/unittest-data/overlay_bad_symbol.dtso
index 98c6d1de144a..98c6d1de144a 100644
--- a/drivers/of/unittest-data/overlay_bad_symbol.dts
+++ b/drivers/of/unittest-data/overlay_bad_symbol.dtso
diff --git a/drivers/of/unittest-data/overlay_base.dts b/drivers/of/unittest-data/overlay_base.dtso
index ab9014589c5d..ab9014589c5d 100644
--- a/drivers/of/unittest-data/overlay_base.dts
+++ b/drivers/of/unittest-data/overlay_base.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_01.dts b/drivers/of/unittest-data/overlay_gpio_01.dtso
index 699ff104ae10..699ff104ae10 100644
--- a/drivers/of/unittest-data/overlay_gpio_01.dts
+++ b/drivers/of/unittest-data/overlay_gpio_01.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_02a.dts b/drivers/of/unittest-data/overlay_gpio_02a.dtso
index ec59aff6ed47..ec59aff6ed47 100644
--- a/drivers/of/unittest-data/overlay_gpio_02a.dts
+++ b/drivers/of/unittest-data/overlay_gpio_02a.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_02b.dts b/drivers/of/unittest-data/overlay_gpio_02b.dtso
index 43ce111d41ce..43ce111d41ce 100644
--- a/drivers/of/unittest-data/overlay_gpio_02b.dts
+++ b/drivers/of/unittest-data/overlay_gpio_02b.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_03.dts b/drivers/of/unittest-data/overlay_gpio_03.dtso
index 6e0312340a1b..6e0312340a1b 100644
--- a/drivers/of/unittest-data/overlay_gpio_03.dts
+++ b/drivers/of/unittest-data/overlay_gpio_03.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_04a.dts b/drivers/of/unittest-data/overlay_gpio_04a.dtso
index 7b1e04ebfa7a..7b1e04ebfa7a 100644
--- a/drivers/of/unittest-data/overlay_gpio_04a.dts
+++ b/drivers/of/unittest-data/overlay_gpio_04a.dtso
diff --git a/drivers/of/unittest-data/overlay_gpio_04b.dts b/drivers/of/unittest-data/overlay_gpio_04b.dtso
index a14e95c6699a..a14e95c6699a 100644
--- a/drivers/of/unittest-data/overlay_gpio_04b.dts
+++ b/drivers/of/unittest-data/overlay_gpio_04b.dtso
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dtso
index 61cdd3d5fccb..61cdd3d5fccb 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dtso
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index b89ab5d9fea5..1d810c0e18f8 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1423,12 +1423,12 @@ static int __init unittest_data_add(void)
void *unittest_data_align;
struct device_node *unittest_data_node = NULL, *np;
/*
- * __dtb_testcases_begin[] and __dtb_testcases_end[] are magically
- * created by cmd_dt_S_dtb in scripts/Makefile.lib
+ * __dtbo_testcases_begin[] and __dtbo_testcases_end[] are magically
+ * created by cmd_dt_S_dtbo in scripts/Makefile.lib
*/
- extern uint8_t __dtb_testcases_begin[];
- extern uint8_t __dtb_testcases_end[];
- const int size = __dtb_testcases_end - __dtb_testcases_begin;
+ extern uint8_t __dtbo_testcases_begin[];
+ extern uint8_t __dtbo_testcases_end[];
+ const int size = __dtbo_testcases_end - __dtbo_testcases_begin;
int rc;
void *ret;
@@ -1443,7 +1443,7 @@ static int __init unittest_data_add(void)
return -ENOMEM;
unittest_data_align = PTR_ALIGN(unittest_data, FDT_ALIGN_SIZE);
- memcpy(unittest_data_align, __dtb_testcases_begin, size);
+ memcpy(unittest_data_align, __dtbo_testcases_begin, size);
ret = of_fdt_unflatten_tree(unittest_data_align, NULL, &unittest_data_node);
if (!ret) {
@@ -3003,24 +3003,24 @@ static inline void __init of_unittest_overlay(void) { }
#ifdef CONFIG_OF_OVERLAY
/*
- * __dtb_ot_begin[] and __dtb_ot_end[] are created by cmd_dt_S_dtb
- * in scripts/Makefile.lib
+ * __dtbo_##overlay_name##_begin[] and __dtbo_##overlay_name##_end[] are
+ * created by cmd_dt_S_dtbo in scripts/Makefile.lib
*/
-#define OVERLAY_INFO_EXTERN(name) \
- extern uint8_t __dtb_##name##_begin[]; \
- extern uint8_t __dtb_##name##_end[]
+#define OVERLAY_INFO_EXTERN(overlay_name) \
+ extern uint8_t __dtbo_##overlay_name##_begin[]; \
+ extern uint8_t __dtbo_##overlay_name##_end[]
-#define OVERLAY_INFO(overlay_name, expected) \
-{ .dtb_begin = __dtb_##overlay_name##_begin, \
- .dtb_end = __dtb_##overlay_name##_end, \
- .expected_result = expected, \
- .name = #overlay_name, \
+#define OVERLAY_INFO(overlay_name, expected) \
+{ .dtbo_begin = __dtbo_##overlay_name##_begin, \
+ .dtbo_end = __dtbo_##overlay_name##_end, \
+ .expected_result = expected, \
+ .name = #overlay_name, \
}
struct overlay_info {
- uint8_t *dtb_begin;
- uint8_t *dtb_end;
+ uint8_t *dtbo_begin;
+ uint8_t *dtbo_end;
int expected_result;
int ovcs_id;
char *name;
@@ -3094,7 +3094,7 @@ static struct overlay_info overlays[] = {
OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
/* end marker */
- {.dtb_begin = NULL, .dtb_end = NULL, .expected_result = 0, .name = NULL}
+ {.dtbo_begin = NULL, .dtbo_end = NULL, .expected_result = 0, .name = NULL}
};
static struct device_node *overlay_base_root;
@@ -3151,13 +3151,13 @@ void __init unittest_unflatten_overlay_base(void)
return;
}
- data_size = info->dtb_end - info->dtb_begin;
+ data_size = info->dtbo_end - info->dtbo_begin;
if (!data_size) {
pr_err("No dtb 'overlay_base' to attach\n");
return;
}
- size = fdt_totalsize(info->dtb_begin);
+ size = fdt_totalsize(info->dtbo_begin);
if (size != data_size) {
pr_err("dtb 'overlay_base' header totalsize != actual size");
return;
@@ -3169,7 +3169,7 @@ void __init unittest_unflatten_overlay_base(void)
return;
}
- memcpy(new_fdt, info->dtb_begin, size);
+ memcpy(new_fdt, info->dtbo_begin, size);
__unflatten_device_tree(new_fdt, NULL, &overlay_base_root,
dt_alloc_memory, true);
@@ -3204,11 +3204,11 @@ static int __init overlay_data_apply(const char *overlay_name, int *ovcs_id)
return 0;
}
- size = info->dtb_end - info->dtb_begin;
+ size = info->dtbo_end - info->dtbo_begin;
if (!size)
pr_err("no overlay data for %s\n", overlay_name);
- ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->ovcs_id);
+ ret = of_overlay_fdt_apply(info->dtbo_begin, size, &info->ovcs_id);
if (ovcs_id)
*ovcs_id = info->ovcs_id;
if (ret < 0)
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 605d68673f92..e55c6095adf0 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -578,169 +578,140 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
return false;
}
-static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
- struct opp_table *opp_table)
+static u32 *_parse_named_prop(struct dev_pm_opp *opp, struct device *dev,
+ struct opp_table *opp_table,
+ const char *prop_type, bool *triplet)
{
- u32 *microvolt, *microamp = NULL, *microwatt = NULL;
- int supplies = opp_table->regulator_count;
- int vcount, icount, pcount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
+ int count, ret;
+ u32 *out;
- /* Search for "opp-microvolt-<name>" */
+ /* Search for "opp-<prop_type>-<name>" */
if (opp_table->prop_name) {
- snprintf(name, sizeof(name), "opp-microvolt-%s",
+ snprintf(name, sizeof(name), "opp-%s-%s", prop_type,
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (!prop) {
- /* Search for "opp-microvolt" */
- sprintf(name, "opp-microvolt");
+ /* Search for "opp-<prop_type>" */
+ snprintf(name, sizeof(name), "opp-%s", prop_type);
prop = of_find_property(opp->np, name, NULL);
-
- /* Missing property isn't a problem, but an invalid entry is */
- if (!prop) {
- if (unlikely(supplies == -1)) {
- /* Initialize regulator_count */
- opp_table->regulator_count = 0;
- return 0;
- }
-
- if (!supplies)
- return 0;
-
- dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
- __func__);
- return -EINVAL;
- }
+ if (!prop)
+ return NULL;
}
- if (unlikely(supplies == -1)) {
- /* Initialize regulator_count */
- supplies = opp_table->regulator_count = 1;
- } else if (unlikely(!supplies)) {
- dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
- return -EINVAL;
+ count = of_property_count_u32_elems(opp->np, name);
+ if (count < 0) {
+ dev_err(dev, "%s: Invalid %s property (%d)\n", __func__, name,
+ count);
+ return ERR_PTR(count);
}
- vcount = of_property_count_u32_elems(opp->np, name);
- if (vcount < 0) {
- dev_err(dev, "%s: Invalid %s property (%d)\n",
- __func__, name, vcount);
- return vcount;
- }
-
- /* There can be one or three elements per supply */
- if (vcount != supplies && vcount != supplies * 3) {
- dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
- __func__, name, vcount, supplies);
- return -EINVAL;
+ /*
+ * Initialize regulator_count, if regulator information isn't provided
+ * by the platform. Now that one of the properties is available, fix the
+ * regulator_count to 1.
+ */
+ if (unlikely(opp_table->regulator_count == -1))
+ opp_table->regulator_count = 1;
+
+ if (count != opp_table->regulator_count &&
+ (!triplet || count != opp_table->regulator_count * 3)) {
+ dev_err(dev, "%s: Invalid number of elements in %s property (%u) with supplies (%d)\n",
+ __func__, prop_type, count, opp_table->regulator_count);
+ return ERR_PTR(-EINVAL);
}
- microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
- if (!microvolt)
- return -ENOMEM;
+ out = kmalloc_array(count, sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return ERR_PTR(-EINVAL);
- ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
+ ret = of_property_read_u32_array(opp->np, name, out, count);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
- ret = -EINVAL;
- goto free_microvolt;
- }
-
- /* Search for "opp-microamp-<name>" */
- prop = NULL;
- if (opp_table->prop_name) {
- snprintf(name, sizeof(name), "opp-microamp-%s",
- opp_table->prop_name);
- prop = of_find_property(opp->np, name, NULL);
+ kfree(out);
+ return ERR_PTR(-EINVAL);
}
- if (!prop) {
- /* Search for "opp-microamp" */
- sprintf(name, "opp-microamp");
- prop = of_find_property(opp->np, name, NULL);
- }
+ if (triplet)
+ *triplet = count != opp_table->regulator_count;
- if (prop) {
- icount = of_property_count_u32_elems(opp->np, name);
- if (icount < 0) {
- dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
- name, icount);
- ret = icount;
- goto free_microvolt;
- }
+ return out;
+}
- if (icount != supplies) {
- dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
- __func__, name, icount, supplies);
- ret = -EINVAL;
- goto free_microvolt;
- }
+static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
+ struct opp_table *opp_table, bool *triplet)
+{
+ u32 *microvolt;
- microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
- if (!microamp) {
- ret = -EINVAL;
- goto free_microvolt;
- }
+ microvolt = _parse_named_prop(opp, dev, opp_table, "microvolt", triplet);
+ if (IS_ERR(microvolt))
+ return microvolt;
- ret = of_property_read_u32_array(opp->np, name, microamp,
- icount);
- if (ret) {
- dev_err(dev, "%s: error parsing %s: %d\n", __func__,
- name, ret);
- ret = -EINVAL;
- goto free_microamp;
+ if (!microvolt) {
+ /*
+ * Missing property isn't a problem, but an invalid
+ * entry is. This property isn't optional if regulator
+ * information is provided. Check only for the first OPP, as
+ * regulator_count may get initialized after that to a valid
+ * value.
+ */
+ if (list_empty(&opp_table->opp_list) &&
+ opp_table->regulator_count > 0) {
+ dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
+ __func__);
+ return ERR_PTR(-EINVAL);
}
}
- /* Search for "opp-microwatt" */
- sprintf(name, "opp-microwatt");
- prop = of_find_property(opp->np, name, NULL);
-
- if (prop) {
- pcount = of_property_count_u32_elems(opp->np, name);
- if (pcount < 0) {
- dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
- name, pcount);
- ret = pcount;
- goto free_microamp;
- }
+ return microvolt;
+}
- if (pcount != supplies) {
- dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
- __func__, name, pcount, supplies);
- ret = -EINVAL;
- goto free_microamp;
- }
+static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
+ struct opp_table *opp_table)
+{
+ u32 *microvolt, *microamp, *microwatt;
+ int ret = 0, i, j;
+ bool triplet;
- microwatt = kmalloc_array(pcount, sizeof(*microwatt),
- GFP_KERNEL);
- if (!microwatt) {
- ret = -EINVAL;
- goto free_microamp;
- }
+ microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
+ if (IS_ERR(microvolt))
+ return PTR_ERR(microvolt);
- ret = of_property_read_u32_array(opp->np, name, microwatt,
- pcount);
- if (ret) {
- dev_err(dev, "%s: error parsing %s: %d\n", __func__,
- name, ret);
- ret = -EINVAL;
- goto free_microwatt;
- }
+ microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
+ if (IS_ERR(microamp)) {
+ ret = PTR_ERR(microamp);
+ goto free_microvolt;
}
- for (i = 0, j = 0; i < supplies; i++) {
- opp->supplies[i].u_volt = microvolt[j++];
+ microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
+ if (IS_ERR(microwatt)) {
+ ret = PTR_ERR(microwatt);
+ goto free_microamp;
+ }
- if (vcount == supplies) {
- opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
- opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
- } else {
- opp->supplies[i].u_volt_min = microvolt[j++];
- opp->supplies[i].u_volt_max = microvolt[j++];
+ /*
+ * Initialize regulator_count if it is uninitialized and no properties
+ * are found.
+ */
+ if (unlikely(opp_table->regulator_count == -1)) {
+ opp_table->regulator_count = 0;
+ return 0;
+ }
+
+ for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
+ if (microvolt) {
+ opp->supplies[i].u_volt = microvolt[j++];
+
+ if (triplet) {
+ opp->supplies[i].u_volt_min = microvolt[j++];
+ opp->supplies[i].u_volt_max = microvolt[j++];
+ } else {
+ opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
+ opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+ }
}
if (microamp)
@@ -750,7 +721,6 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
opp->supplies[i].u_watt = microwatt[i];
}
-free_microwatt:
kfree(microwatt);
free_microamp:
kfree(microamp);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 7c45927e2131..5784dc20fb38 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -468,7 +468,7 @@ static size_t parport_pc_fifo_write_block_pio(struct parport *port,
const unsigned char *bufp = buf;
size_t left = length;
unsigned long expire = jiffies + port->physport->cad->timeout;
- const int fifo = FIFO(port);
+ const unsigned long fifo = FIFO(port);
int poll_for = 8; /* 80 usecs */
const struct parport_pc_private *priv = port->physport->private_data;
const int fifo_depth = priv->fifo_depth;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 55c028af4bd9..9309f2469b41 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -51,11 +51,6 @@ config PCI_MSI
If you don't know what to do here, say Y.
-config PCI_MSI_IRQ_DOMAIN
- def_bool y
- depends on PCI_MSI
- select GENERIC_MSI_IRQ_DOMAIN
-
config PCI_MSI_ARCH_FALLBACKS
bool
@@ -192,7 +187,7 @@ config PCI_LABEL
config PCI_HYPERV
tristate "Hyper-V PCI Frontend"
- depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS
+ depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && SYSFS
select PCI_HYPERV_INTERFACE
help
The PCI device frontend driver allows the kernel to import arbitrary
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index bfd9bac37e24..1569d9a3ada0 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -19,7 +19,7 @@ config PCI_AARDVARK
tristate "Aardvark PCIe controller"
depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCI_BRIDGE_EMUL
help
Add support for Aardvark 64bit PCIe Host Controller. This
@@ -29,7 +29,7 @@ config PCI_AARDVARK
config PCIE_XILINX_NWL
bool "NWL PCIe Core"
depends on ARCH_ZYNQMP || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say 'Y' here if you want kernel support for Xilinx
NWL PCIe controller. The controller can act as Root Port
@@ -53,7 +53,7 @@ config PCI_IXP4XX
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say Y here if you want support for the PCIe host controller found
on NVIDIA Tegra SoCs.
@@ -70,7 +70,7 @@ config PCI_RCAR_GEN2
config PCIE_RCAR_HOST
bool "Renesas R-Car PCIe host controller"
depends on ARCH_RENESAS || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say Y here if you want PCIe controller support on R-Car SoCs in host
mode.
@@ -99,7 +99,7 @@ config PCI_HOST_GENERIC
config PCIE_XILINX
bool "Xilinx AXI PCIe host bridge support"
depends on OF || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
Host Bridge driver.
@@ -124,7 +124,7 @@ config PCI_XGENE
config PCI_XGENE_MSI
bool "X-Gene v1 PCIe MSI feature"
depends on PCI_XGENE
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
default y
help
Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
@@ -170,7 +170,7 @@ config PCIE_IPROC_BCMA
config PCIE_IPROC_MSI
bool "Broadcom iProc PCIe MSI support"
depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
default ARCH_BCM_IPROC
help
Say Y here if you want to enable MSI support for Broadcom's iProc
@@ -186,7 +186,7 @@ config PCIE_ALTERA
config PCIE_ALTERA_MSI
tristate "Altera PCIe MSI feature"
depends on PCIE_ALTERA
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say Y here if you want PCIe MSI support for the Altera FPGA.
This MSI driver supports Altera MSI to GIC controller IP.
@@ -215,7 +215,7 @@ config PCIE_ROCKCHIP_HOST
tristate "Rockchip PCIe host controller"
depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select MFD_SYSCON
select PCIE_ROCKCHIP
help
@@ -239,7 +239,7 @@ config PCIE_MEDIATEK
tristate "MediaTek PCIe controller"
depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Say Y here if you want to enable PCIe controller support on
MediaTek SoCs.
@@ -247,7 +247,7 @@ config PCIE_MEDIATEK
config PCIE_MEDIATEK_GEN3
tristate "MediaTek Gen3 PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
help
Adds support for PCIe Gen3 MAC controller for MediaTek SoCs.
This PCIe controller is compatible with Gen3, Gen2 and Gen1 speed,
@@ -277,7 +277,7 @@ config PCIE_BRCMSTB
depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCMBCA || \
BMIPS_GENERIC || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
default ARCH_BRCMSTB || BMIPS_GENERIC
help
Say Y here to enable PCIe host controller support for
@@ -285,7 +285,7 @@ config PCIE_BRCMSTB
config PCI_HYPERV_INTERFACE
tristate "Hyper-V PCI Interface"
- depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN
+ depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI
help
The Hyper-V PCI Interface is a helper driver allows other drivers to
have a common interface with the Hyper-V PCI frontend driver.
@@ -303,8 +303,6 @@ config PCI_LOONGSON
config PCIE_MICROCHIP_HOST
bool "Microchip AXI PCIe host bridge support"
depends on PCI_MSI && OF
- select PCI_MSI_IRQ_DOMAIN
- select GENERIC_MSI_IRQ_DOMAIN
select PCI_HOST_COMMON
help
Say Y here if you want kernel to support the Microchip AXI PCIe
@@ -326,7 +324,7 @@ config PCIE_APPLE
tristate "Apple PCIe controller"
depends on ARCH_APPLE || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCI_HOST_COMMON
help
Say Y here if you want to enable PCIe controller support on Apple
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 62ce3abf0f19..f3c462130627 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -21,7 +21,7 @@ config PCI_DRA7XX_HOST
tristate "TI DRA7xx PCIe controller Host Mode"
depends on SOC_DRA7XX || COMPILE_TEST
depends on OF && HAS_IOMEM && TI_PIPE3
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCI_DRA7XX
default y if SOC_DRA7XX
@@ -53,7 +53,7 @@ config PCIE_DW_PLAT
config PCIE_DW_PLAT_HOST
bool "Platform bus based DesignWare PCIe Controller - Host mode"
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCIE_DW_PLAT
help
@@ -67,7 +67,7 @@ config PCIE_DW_PLAT_HOST
config PCIE_DW_PLAT_EP
bool "Platform bus based DesignWare PCIe Controller - Endpoint mode"
- depends on PCI && PCI_MSI_IRQ_DOMAIN
+ depends on PCI && PCI_MSI
depends on PCI_ENDPOINT
select PCIE_DW_EP
select PCIE_DW_PLAT
@@ -83,7 +83,7 @@ config PCIE_DW_PLAT_EP
config PCI_EXYNOS
tristate "Samsung Exynos PCIe controller"
depends on ARCH_EXYNOS || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Enables support for the PCIe controller in the Samsung Exynos SoCs
@@ -94,13 +94,13 @@ config PCI_EXYNOS
config PCI_IMX6
bool "Freescale i.MX6/7/8 PCIe controller"
depends on ARCH_MXC || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
config PCIE_SPEAR13XX
bool "STMicroelectronics SPEAr PCIe controller"
depends on ARCH_SPEAR13XX || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want PCIe support on SPEAr13XX SoCs.
@@ -111,7 +111,7 @@ config PCI_KEYSTONE
config PCI_KEYSTONE_HOST
bool "PCI Keystone Host Mode"
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCI_KEYSTONE
help
@@ -135,7 +135,7 @@ config PCI_KEYSTONE_EP
config PCI_LAYERSCAPE
bool "Freescale Layerscape PCIe controller - Host mode"
depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST)
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select MFD_SYSCON
help
@@ -160,7 +160,7 @@ config PCI_LAYERSCAPE_EP
config PCI_HISI
depends on OF && (ARM64 || COMPILE_TEST)
bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers"
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCI_HOST_COMMON
help
@@ -170,7 +170,7 @@ config PCI_HISI
config PCIE_QCOM
bool "Qualcomm PCIe controller"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select CRC8
help
@@ -191,7 +191,7 @@ config PCIE_QCOM_EP
config PCIE_ARMADA_8K
bool "Marvell Armada-8K PCIe controller"
depends on ARCH_MVEBU || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want to enable PCIe controller support on
@@ -205,7 +205,7 @@ config PCIE_ARTPEC6
config PCIE_ARTPEC6_HOST
bool "Axis ARTPEC-6 PCIe controller Host Mode"
depends on MACH_ARTPEC6 || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCIE_ARTPEC6
help
@@ -226,7 +226,7 @@ config PCIE_ROCKCHIP_DW_HOST
bool "Rockchip DesignWare PCIe controller"
select PCIE_DW
select PCIE_DW_HOST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on OF
help
@@ -236,7 +236,7 @@ config PCIE_ROCKCHIP_DW_HOST
config PCIE_INTEL_GW
bool "Intel Gateway PCIe host controller support"
depends on OF && (X86 || COMPILE_TEST)
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say 'Y' here to enable PCIe Host controller support on Intel
@@ -250,7 +250,7 @@ config PCIE_KEEMBAY
config PCIE_KEEMBAY_HOST
bool "Intel Keem Bay PCIe controller - Host mode"
depends on ARCH_KEEMBAY || COMPILE_TEST
- depends on PCI && PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCIE_KEEMBAY
help
@@ -262,7 +262,7 @@ config PCIE_KEEMBAY_HOST
config PCIE_KEEMBAY_EP
bool "Intel Keem Bay PCIe controller - Endpoint mode"
depends on ARCH_KEEMBAY || COMPILE_TEST
- depends on PCI && PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
depends on PCI_ENDPOINT
select PCIE_DW_EP
select PCIE_KEEMBAY
@@ -275,7 +275,7 @@ config PCIE_KEEMBAY_EP
config PCIE_KIRIN
depends on OF && (ARM64 || COMPILE_TEST)
tristate "HiSilicon Kirin series SoCs PCIe controllers"
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want PCIe controller support
@@ -284,7 +284,7 @@ config PCIE_KIRIN
config PCIE_HISI_STB
bool "HiSilicon STB SoCs PCIe controllers"
depends on ARCH_HISI || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want PCIe controller support on HiSilicon STB SoCs
@@ -292,7 +292,7 @@ config PCIE_HISI_STB
config PCI_MESON
tristate "MESON PCIe controller"
default m if ARCH_MESON
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want to enable PCI controller support on Amlogic
@@ -306,7 +306,7 @@ config PCIE_TEGRA194
config PCIE_TEGRA194_HOST
tristate "NVIDIA Tegra194 (and later) PCIe controller - Host Mode"
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PHY_TEGRA194_P2U
select PCIE_TEGRA194
@@ -336,7 +336,7 @@ config PCIE_TEGRA194_EP
config PCIE_VISCONTI_HOST
bool "Toshiba Visconti PCIe controllers"
depends on ARCH_VISCONTI || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want PCIe controller support on Toshiba Visconti SoC.
@@ -346,7 +346,7 @@ config PCIE_UNIPHIER
bool "Socionext UniPhier PCIe host controllers"
depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && HAS_IOMEM
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
help
Say Y here if you want PCIe host controller support on UniPhier SoCs.
@@ -365,7 +365,7 @@ config PCIE_UNIPHIER_EP
config PCIE_AL
bool "Amazon Annapurna Labs PCIe controller"
depends on OF && (ARM64 || COMPILE_TEST)
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_DW_HOST
select PCI_ECAM
help
@@ -377,7 +377,7 @@ config PCIE_AL
config PCIE_FU740
bool "SiFive FU740 PCIe host controller"
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
depends on SOC_SIFIVE || COMPILE_TEST
select PCIE_DW_HOST
help
diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
index e4643fb94e78..1d7a07ba9ccd 100644
--- a/drivers/pci/controller/mobiveil/Kconfig
+++ b/drivers/pci/controller/mobiveil/Kconfig
@@ -8,14 +8,14 @@ config PCIE_MOBIVEIL
config PCIE_MOBIVEIL_HOST
bool
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_MOBIVEIL
config PCIE_MOBIVEIL_PLAT
bool "Mobiveil AXI PCIe controller"
depends on ARCH_ZYNQMP || COMPILE_TEST
depends on OF
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_MOBIVEIL_HOST
help
Say Y here if you want to enable support for the Mobiveil AXI PCIe
@@ -25,7 +25,7 @@ config PCIE_MOBIVEIL_PLAT
config PCIE_LAYERSCAPE_GEN4
bool "Freescale Layerscape PCIe Gen4 controller"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
- depends on PCI_MSI_IRQ_DOMAIN
+ depends on PCI_MSI
select PCIE_MOBIVEIL_HOST
help
Say Y here if you want PCIe Gen4 controller support on
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index e7c6f6629e7c..084f5313895c 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -611,20 +611,7 @@ static unsigned int hv_msi_get_int_vector(struct irq_data *data)
return cfg->vector;
}
-static int hv_msi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
-{
- int ret = pci_msi_prepare(domain, dev, nvec, info);
-
- /*
- * By using the interrupt remapper in the hypervisor IOMMU, contiguous
- * CPU vectors is not needed for multi-MSI
- */
- if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
- info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
-
- return ret;
-}
+#define hv_msi_prepare pci_msi_prepare
/**
* hv_arch_irq_unmask() - "Unmask" the IRQ by setting its current
@@ -735,9 +722,9 @@ exit_unlock:
* during hibernation does not matter (at this time all the devices
* have been frozen). Note: the correct affinity info is still updated
* into the irqdata data structure in migrate_one_irq() ->
- * irq_do_set_affinity() -> hv_set_affinity(), so later when the VM
- * resumes, hv_pci_restore_msi_state() is able to correctly restore
- * the interrupt with the correct affinity.
+ * irq_do_set_affinity(), so later when the VM resumes,
+ * hv_pci_restore_msi_state() is able to correctly restore the
+ * interrupt with the correct affinity.
*/
if (!hv_result_success(res) && hbus->state != hv_pcibus_removing)
dev_err(&hbus->hdev->device,
@@ -1613,8 +1600,8 @@ out:
}
static u32 hv_compose_msi_req_v1(
- struct pci_create_interrupt *int_pkt, const struct cpumask *affinity,
- u32 slot, u8 vector, u8 vector_count)
+ struct pci_create_interrupt *int_pkt,
+ u32 slot, u8 vector, u16 vector_count)
{
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
int_pkt->wslot.slot = slot;
@@ -1632,6 +1619,35 @@ static u32 hv_compose_msi_req_v1(
}
/*
+ * The vCPU selected by hv_compose_multi_msi_req_get_cpu() and
+ * hv_compose_msi_req_get_cpu() is a "dummy" vCPU because the final vCPU to be
+ * interrupted is specified later in hv_irq_unmask() and communicated to Hyper-V
+ * via the HVCALL_RETARGET_INTERRUPT hypercall. But the choice of dummy vCPU is
+ * not irrelevant because Hyper-V chooses the physical CPU to handle the
+ * interrupts based on the vCPU specified in message sent to the vPCI VSP in
+ * hv_compose_msi_msg(). Hyper-V's choice of pCPU is not visible to the guest,
+ * but assigning too many vPCI device interrupts to the same pCPU can cause a
+ * performance bottleneck. So we spread out the dummy vCPUs to influence Hyper-V
+ * to spread out the pCPUs that it selects.
+ *
+ * For the single-MSI and MSI-X cases, it's OK for hv_compose_msi_req_get_cpu()
+ * to always return the same dummy vCPU, because a second call to
+ * hv_compose_msi_msg() contains the "real" vCPU, causing Hyper-V to choose a
+ * new pCPU for the interrupt. But for the multi-MSI case, the second call to
+ * hv_compose_msi_msg() exits without sending a message to the vPCI VSP, so the
+ * original dummy vCPU is used. This dummy vCPU must be round-robin'ed so that
+ * the pCPUs are spread out. All interrupts for a multi-MSI device end up using
+ * the same pCPU, even though the vCPUs will be spread out by later calls
+ * to hv_irq_unmask(), but that is the best we can do now.
+ *
+ * With Hyper-V in Nov 2022, the HVCALL_RETARGET_INTERRUPT hypercall does *not*
+ * cause Hyper-V to reselect the pCPU based on the specified vCPU. Such an
+ * enhancement is planned for a future version. With that enhancement, the
+ * dummy vCPU selection won't matter, and interrupts for the same multi-MSI
+ * device will be spread across multiple pCPUs.
+ */
+
+/*
* Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
* by subsequent retarget in hv_irq_unmask().
*/
@@ -1640,18 +1656,39 @@ static int hv_compose_msi_req_get_cpu(const struct cpumask *affinity)
return cpumask_first_and(affinity, cpu_online_mask);
}
-static u32 hv_compose_msi_req_v2(
- struct pci_create_interrupt2 *int_pkt, const struct cpumask *affinity,
- u32 slot, u8 vector, u8 vector_count)
+/*
+ * Make sure the dummy vCPU values for multi-MSI don't all point to vCPU0.
+ */
+static int hv_compose_multi_msi_req_get_cpu(void)
{
+ static DEFINE_SPINLOCK(multi_msi_cpu_lock);
+
+ /* -1 means starting with CPU 0 */
+ static int cpu_next = -1;
+
+ unsigned long flags;
int cpu;
+ spin_lock_irqsave(&multi_msi_cpu_lock, flags);
+
+ cpu_next = cpumask_next_wrap(cpu_next, cpu_online_mask, nr_cpu_ids,
+ false);
+ cpu = cpu_next;
+
+ spin_unlock_irqrestore(&multi_msi_cpu_lock, flags);
+
+ return cpu;
+}
+
+static u32 hv_compose_msi_req_v2(
+ struct pci_create_interrupt2 *int_pkt, int cpu,
+ u32 slot, u8 vector, u16 vector_count)
+{
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE2;
int_pkt->wslot.slot = slot;
int_pkt->int_desc.vector = vector;
int_pkt->int_desc.vector_count = vector_count;
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
- cpu = hv_compose_msi_req_get_cpu(affinity);
int_pkt->int_desc.processor_array[0] =
hv_cpu_number_to_vp_number(cpu);
int_pkt->int_desc.processor_count = 1;
@@ -1660,18 +1697,15 @@ static u32 hv_compose_msi_req_v2(
}
static u32 hv_compose_msi_req_v3(
- struct pci_create_interrupt3 *int_pkt, const struct cpumask *affinity,
- u32 slot, u32 vector, u8 vector_count)
+ struct pci_create_interrupt3 *int_pkt, int cpu,
+ u32 slot, u32 vector, u16 vector_count)
{
- int cpu;
-
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE3;
int_pkt->wslot.slot = slot;
int_pkt->int_desc.vector = vector;
int_pkt->int_desc.reserved = 0;
int_pkt->int_desc.vector_count = vector_count;
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
- cpu = hv_compose_msi_req_get_cpu(affinity);
int_pkt->int_desc.processor_array[0] =
hv_cpu_number_to_vp_number(cpu);
int_pkt->int_desc.processor_count = 1;
@@ -1701,7 +1735,12 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct compose_comp_ctxt comp;
struct tran_int_desc *int_desc;
struct msi_desc *msi_desc;
- u8 vector, vector_count;
+ /*
+ * vector_count should be u16: see hv_msi_desc, hv_msi_desc2
+ * and hv_msi_desc3. vector must be u32: see hv_msi_desc3.
+ */
+ u16 vector_count;
+ u32 vector;
struct {
struct pci_packet pci_pkt;
union {
@@ -1710,12 +1749,18 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct pci_create_interrupt3 v3;
} int_pkts;
} __packed ctxt;
+ bool multi_msi;
u64 trans_id;
u32 size;
int ret;
+ int cpu;
+
+ msi_desc = irq_data_get_msi_desc(data);
+ multi_msi = !msi_desc->pci.msi_attrib.is_msix &&
+ msi_desc->nvec_used > 1;
/* Reuse the previous allocation */
- if (data->chip_data) {
+ if (data->chip_data && multi_msi) {
int_desc = data->chip_data;
msg->address_hi = int_desc->address >> 32;
msg->address_lo = int_desc->address & 0xffffffff;
@@ -1723,7 +1768,6 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
return;
}
- msi_desc = irq_data_get_msi_desc(data);
pdev = msi_desc_to_pci_dev(msi_desc);
dest = irq_data_get_effective_affinity_mask(data);
pbus = pdev->bus;
@@ -1733,11 +1777,18 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
if (!hpdev)
goto return_null_message;
+ /* Free any previous message that might have already been composed. */
+ if (data->chip_data && !multi_msi) {
+ int_desc = data->chip_data;
+ data->chip_data = NULL;
+ hv_int_desc_free(hpdev, int_desc);
+ }
+
int_desc = kzalloc(sizeof(*int_desc), GFP_ATOMIC);
if (!int_desc)
goto drop_reference;
- if (!msi_desc->pci.msi_attrib.is_msix && msi_desc->nvec_used > 1) {
+ if (multi_msi) {
/*
* If this is not the first MSI of Multi MSI, we already have
* a mapping. Can exit early.
@@ -1762,11 +1813,18 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
*/
vector = 32;
vector_count = msi_desc->nvec_used;
+ cpu = hv_compose_multi_msi_req_get_cpu();
} else {
vector = hv_msi_get_int_vector(data);
vector_count = 1;
+ cpu = hv_compose_msi_req_get_cpu(dest);
}
+ /*
+ * hv_compose_msi_req_v1 and v2 are for x86 only, meaning 'vector'
+ * can't exceed u8. Cast 'vector' down to u8 for v1/v2 explicitly
+ * for better readability.
+ */
memset(&ctxt, 0, sizeof(ctxt));
init_completion(&comp.comp_pkt.host_event);
ctxt.pci_pkt.completion_func = hv_pci_compose_compl;
@@ -1775,24 +1833,23 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
switch (hbus->protocol_version) {
case PCI_PROTOCOL_VERSION_1_1:
size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
- dest,
hpdev->desc.win_slot.slot,
- vector,
+ (u8)vector,
vector_count);
break;
case PCI_PROTOCOL_VERSION_1_2:
case PCI_PROTOCOL_VERSION_1_3:
size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
- dest,
+ cpu,
hpdev->desc.win_slot.slot,
- vector,
+ (u8)vector,
vector_count);
break;
case PCI_PROTOCOL_VERSION_1_4:
size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3,
- dest,
+ cpu,
hpdev->desc.win_slot.slot,
vector,
vector_count);
diff --git a/drivers/pci/msi/Makefile b/drivers/pci/msi/Makefile
index 93ef7b9e404d..839ff72d72a8 100644
--- a/drivers/pci/msi/Makefile
+++ b/drivers/pci/msi/Makefile
@@ -2,6 +2,5 @@
#
# Makefile for the PCI/MSI
obj-$(CONFIG_PCI) += pcidev_msi.o
-obj-$(CONFIG_PCI_MSI) += msi.o
-obj-$(CONFIG_PCI_MSI_IRQ_DOMAIN) += irqdomain.o
+obj-$(CONFIG_PCI_MSI) += api.o msi.o irqdomain.o
obj-$(CONFIG_PCI_MSI_ARCH_FALLBACKS) += legacy.o
diff --git a/drivers/pci/msi/api.c b/drivers/pci/msi/api.c
new file mode 100644
index 000000000000..b8009aa11f3c
--- /dev/null
+++ b/drivers/pci/msi/api.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCI MSI/MSI-X — Exported APIs for device drivers
+ *
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Copyright (C) 2016 Christoph Hellwig.
+ * Copyright (C) 2022 Linutronix GmbH
+ */
+
+#include <linux/export.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/**
+ * pci_enable_msi() - Enable MSI interrupt mode on device
+ * @dev: the PCI device to operate on
+ *
+ * Legacy device driver API to enable MSI interrupts mode on device and
+ * allocate a single interrupt vector. On success, the allocated vector
+ * Linux IRQ will be saved at @dev->irq. The driver must invoke
+ * pci_disable_msi() on cleanup.
+ *
+ * NOTE: The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API
+ * pair should, in general, be used instead.
+ *
+ * Return: 0 on success, errno otherwise
+ */
+int pci_enable_msi(struct pci_dev *dev)
+{
+ int rc = __pci_enable_msi_range(dev, 1, 1, NULL);
+ if (rc < 0)
+ return rc;
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_msi);
+
+/**
+ * pci_disable_msi() - Disable MSI interrupt mode on device
+ * @dev: the PCI device to operate on
+ *
+ * Legacy device driver API to disable MSI interrupt mode on device,
+ * free earlier allocated interrupt vectors, and restore INTx emulation.
+ * The PCI device Linux IRQ (@dev->irq) is restored to its default
+ * pin-assertion IRQ. This is the cleanup pair of pci_enable_msi().
+ *
+ * NOTE: The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API
+ * pair should, in general, be used instead.
+ */
+void pci_disable_msi(struct pci_dev *dev)
+{
+ if (!pci_msi_enabled() || !dev || !dev->msi_enabled)
+ return;
+
+ msi_lock_descs(&dev->dev);
+ pci_msi_shutdown(dev);
+ pci_free_msi_irqs(dev);
+ msi_unlock_descs(&dev->dev);
+}
+EXPORT_SYMBOL(pci_disable_msi);
+
+/**
+ * pci_msix_vec_count() - Get number of MSI-X interrupt vectors on device
+ * @dev: the PCI device to operate on
+ *
+ * Return: number of MSI-X interrupt vectors available on this device
+ * (i.e., the device's MSI-X capability structure "table size"), -EINVAL
+ * if the device is not MSI-X capable, other errnos otherwise.
+ */
+int pci_msix_vec_count(struct pci_dev *dev)
+{
+ u16 control;
+
+ if (!dev->msix_cap)
+ return -EINVAL;
+
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+ return msix_table_size(control);
+}
+EXPORT_SYMBOL(pci_msix_vec_count);
+
+/**
+ * pci_enable_msix_range() - Enable MSI-X interrupt mode on device
+ * @dev: the PCI device to operate on
+ * @entries: input/output parameter, array of MSI-X configuration entries
+ * @minvec: minimum required number of MSI-X vectors
+ * @maxvec: maximum desired number of MSI-X vectors
+ *
+ * Legacy device driver API to enable MSI-X interrupt mode on device and
+ * configure its MSI-X capability structure as appropriate. The passed
+ * @entries array must have each of its members "entry" field set to a
+ * desired (valid) MSI-X vector number, where the range of valid MSI-X
+ * vector numbers can be queried through pci_msix_vec_count(). If
+ * successful, the driver must invoke pci_disable_msix() on cleanup.
+ *
+ * NOTE: The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API
+ * pair should, in general, be used instead.
+ *
+ * Return: number of MSI-X vectors allocated (which might be smaller
+ * than @maxvecs), where Linux IRQ numbers for such allocated vectors
+ * are saved back in the @entries array elements' "vector" field. Return
+ * -ENOSPC if less than @minvecs interrupt vectors are available.
+ * Return -EINVAL if one of the passed @entries members "entry" field
+ * was invalid or a duplicate, or if plain MSI interrupts mode was
+ * earlier enabled on device. Return other errnos otherwise.
+ */
+int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
+ int minvec, int maxvec)
+{
+ return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
+}
+EXPORT_SYMBOL(pci_enable_msix_range);
+
+/**
+ * pci_msix_can_alloc_dyn - Query whether dynamic allocation after enabling
+ * MSI-X is supported
+ *
+ * @dev: PCI device to operate on
+ *
+ * Return: True if supported, false otherwise
+ */
+bool pci_msix_can_alloc_dyn(struct pci_dev *dev)
+{
+ if (!dev->msix_cap)
+ return false;
+
+ return pci_msi_domain_supports(dev, MSI_FLAG_PCI_MSIX_ALLOC_DYN, DENY_LEGACY);
+}
+EXPORT_SYMBOL_GPL(pci_msix_can_alloc_dyn);
+
+/**
+ * pci_msix_alloc_irq_at - Allocate an MSI-X interrupt after enabling MSI-X
+ * at a given MSI-X vector index or any free vector index
+ *
+ * @dev: PCI device to operate on
+ * @index: Index to allocate. If @index == MSI_ANY_INDEX this allocates
+ * the next free index in the MSI-X table
+ * @affdesc: Optional pointer to an affinity descriptor structure. NULL otherwise
+ *
+ * Return: A struct msi_map
+ *
+ * On success msi_map::index contains the allocated index (>= 0) and
+ * msi_map::virq contains the allocated Linux interrupt number (> 0).
+ *
+ * On fail msi_map::index contains the error code and msi_map::virq
+ * is set to 0.
+ */
+struct msi_map pci_msix_alloc_irq_at(struct pci_dev *dev, unsigned int index,
+ const struct irq_affinity_desc *affdesc)
+{
+ struct msi_map map = { .index = -ENOTSUPP };
+
+ if (!dev->msix_enabled)
+ return map;
+
+ if (!pci_msix_can_alloc_dyn(dev))
+ return map;
+
+ return msi_domain_alloc_irq_at(&dev->dev, MSI_DEFAULT_DOMAIN, index, affdesc, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_msix_alloc_irq_at);
+
+/**
+ * pci_msix_free_irq - Free an interrupt on a PCI/MSIX interrupt domain
+ * which was allocated via pci_msix_alloc_irq_at()
+ *
+ * @dev: The PCI device to operate on
+ * @map: A struct msi_map describing the interrupt to free
+ * as returned from the allocation function.
+ */
+void pci_msix_free_irq(struct pci_dev *dev, struct msi_map map)
+{
+ if (WARN_ON_ONCE(map.index < 0 || map.virq <= 0))
+ return;
+ if (WARN_ON_ONCE(!pci_msix_can_alloc_dyn(dev)))
+ return;
+ msi_domain_free_irqs_range(&dev->dev, MSI_DEFAULT_DOMAIN, map.index, map.index);
+}
+EXPORT_SYMBOL_GPL(pci_msix_free_irq);
+
+/**
+ * pci_disable_msix() - Disable MSI-X interrupt mode on device
+ * @dev: the PCI device to operate on
+ *
+ * Legacy device driver API to disable MSI-X interrupt mode on device,
+ * free earlier-allocated interrupt vectors, and restore INTx.
+ * The PCI device Linux IRQ (@dev->irq) is restored to its default pin
+ * assertion IRQ. This is the cleanup pair of pci_enable_msix_range().
+ *
+ * NOTE: The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API
+ * pair should, in general, be used instead.
+ */
+void pci_disable_msix(struct pci_dev *dev)
+{
+ if (!pci_msi_enabled() || !dev || !dev->msix_enabled)
+ return;
+
+ msi_lock_descs(&dev->dev);
+ pci_msix_shutdown(dev);
+ pci_free_msi_irqs(dev);
+ msi_unlock_descs(&dev->dev);
+}
+EXPORT_SYMBOL(pci_disable_msix);
+
+/**
+ * pci_alloc_irq_vectors() - Allocate multiple device interrupt vectors
+ * @dev: the PCI device to operate on
+ * @min_vecs: minimum required number of vectors (must be >= 1)
+ * @max_vecs: maximum desired number of vectors
+ * @flags: One or more of:
+ *
+ * * %PCI_IRQ_MSIX Allow trying MSI-X vector allocations
+ * * %PCI_IRQ_MSI Allow trying MSI vector allocations
+ *
+ * * %PCI_IRQ_LEGACY Allow trying legacy INTx interrupts, if
+ * and only if @min_vecs == 1
+ *
+ * * %PCI_IRQ_AFFINITY Auto-manage IRQs affinity by spreading
+ * the vectors around available CPUs
+ *
+ * Allocate up to @max_vecs interrupt vectors on device. MSI-X irq
+ * vector allocation has a higher precedence over plain MSI, which has a
+ * higher precedence over legacy INTx emulation.
+ *
+ * Upon a successful allocation, the caller should use pci_irq_vector()
+ * to get the Linux IRQ number to be passed to request_threaded_irq().
+ * The driver must call pci_free_irq_vectors() on cleanup.
+ *
+ * Return: number of allocated vectors (which might be smaller than
+ * @max_vecs), -ENOSPC if less than @min_vecs interrupt vectors are
+ * available, other errnos otherwise.
+ */
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags)
+{
+ return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs,
+ flags, NULL);
+}
+EXPORT_SYMBOL(pci_alloc_irq_vectors);
+
+/**
+ * pci_alloc_irq_vectors_affinity() - Allocate multiple device interrupt
+ * vectors with affinity requirements
+ * @dev: the PCI device to operate on
+ * @min_vecs: minimum required number of vectors (must be >= 1)
+ * @max_vecs: maximum desired number of vectors
+ * @flags: allocation flags, as in pci_alloc_irq_vectors()
+ * @affd: affinity requirements (can be %NULL).
+ *
+ * Same as pci_alloc_irq_vectors(), but with the extra @affd parameter.
+ * Check that function docs, and &struct irq_affinity, for more details.
+ */
+int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags,
+ struct irq_affinity *affd)
+{
+ struct irq_affinity msi_default_affd = {0};
+ int nvecs = -ENOSPC;
+
+ if (flags & PCI_IRQ_AFFINITY) {
+ if (!affd)
+ affd = &msi_default_affd;
+ } else {
+ if (WARN_ON(affd))
+ affd = NULL;
+ }
+
+ if (flags & PCI_IRQ_MSIX) {
+ nvecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
+ affd, flags);
+ if (nvecs > 0)
+ return nvecs;
+ }
+
+ if (flags & PCI_IRQ_MSI) {
+ nvecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd);
+ if (nvecs > 0)
+ return nvecs;
+ }
+
+ /* use legacy IRQ if allowed */
+ if (flags & PCI_IRQ_LEGACY) {
+ if (min_vecs == 1 && dev->irq) {
+ /*
+ * Invoke the affinity spreading logic to ensure that
+ * the device driver can adjust queue configuration
+ * for the single interrupt case.
+ */
+ if (affd)
+ irq_create_affinity_masks(1, affd);
+ pci_intx(dev, 1);
+ return 1;
+ }
+ }
+
+ return nvecs;
+}
+EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity);
+
+/**
+ * pci_irq_vector() - Get Linux IRQ number of a device interrupt vector
+ * @dev: the PCI device to operate on
+ * @nr: device-relative interrupt vector index (0-based); has different
+ * meanings, depending on interrupt mode:
+ *
+ * * MSI-X the index in the MSI-X vector table
+ * * MSI the index of the enabled MSI vectors
+ * * INTx must be 0
+ *
+ * Return: the Linux IRQ number, or -EINVAL if @nr is out of range
+ */
+int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
+{
+ unsigned int irq;
+
+ if (!dev->msi_enabled && !dev->msix_enabled)
+ return !nr ? dev->irq : -EINVAL;
+
+ irq = msi_get_virq(&dev->dev, nr);
+ return irq ? irq : -EINVAL;
+}
+EXPORT_SYMBOL(pci_irq_vector);
+
+/**
+ * pci_irq_get_affinity() - Get a device interrupt vector affinity
+ * @dev: the PCI device to operate on
+ * @nr: device-relative interrupt vector index (0-based); has different
+ * meanings, depending on interrupt mode:
+ *
+ * * MSI-X the index in the MSI-X vector table
+ * * MSI the index of the enabled MSI vectors
+ * * INTx must be 0
+ *
+ * Return: MSI/MSI-X vector affinity, NULL if @nr is out of range or if
+ * the MSI(-X) vector was allocated without explicit affinity
+ * requirements (e.g., by pci_enable_msi(), pci_enable_msix_range(), or
+ * pci_alloc_irq_vectors() without the %PCI_IRQ_AFFINITY flag). Return a
+ * generic set of CPU IDs representing all possible CPUs available
+ * during system boot if the device is in legacy INTx mode.
+ */
+const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
+{
+ int idx, irq = pci_irq_vector(dev, nr);
+ struct msi_desc *desc;
+
+ if (WARN_ON_ONCE(irq <= 0))
+ return NULL;
+
+ desc = irq_get_msi_desc(irq);
+ /* Non-MSI does not have the information handy */
+ if (!desc)
+ return cpu_possible_mask;
+
+ /* MSI[X] interrupts can be allocated without affinity descriptor */
+ if (!desc->affinity)
+ return NULL;
+
+ /*
+ * MSI has a mask array in the descriptor.
+ * MSI-X has a single mask.
+ */
+ idx = dev->msi_enabled ? nr : 0;
+ return &desc->affinity[idx].mask;
+}
+EXPORT_SYMBOL(pci_irq_get_affinity);
+
+/**
+ * pci_ims_alloc_irq - Allocate an interrupt on a PCI/IMS interrupt domain
+ * @dev: The PCI device to operate on
+ * @icookie: Pointer to an IMS implementation specific cookie for this
+ * IMS instance (PASID, queue ID, pointer...).
+ * The cookie content is copied into the MSI descriptor for the
+ * interrupt chip callbacks or domain specific setup functions.
+ * @affdesc: Optional pointer to an interrupt affinity descriptor
+ *
+ * There is no index for IMS allocations as IMS is an implementation
+ * specific storage and does not have any direct associations between
+ * index, which might be a pure software construct, and device
+ * functionality. This association is established by the driver either via
+ * the index - if there is a hardware table - or in case of purely software
+ * managed IMS implementation the association happens via the
+ * irq_write_msi_msg() callback of the implementation specific interrupt
+ * chip, which utilizes the provided @icookie to store the MSI message in
+ * the appropriate place.
+ *
+ * Return: A struct msi_map
+ *
+ * On success msi_map::index contains the allocated index (>= 0) and
+ * msi_map::virq the allocated Linux interrupt number (> 0).
+ *
+ * On fail msi_map::index contains the error code and msi_map::virq
+ * is set to 0.
+ */
+struct msi_map pci_ims_alloc_irq(struct pci_dev *dev, union msi_instance_cookie *icookie,
+ const struct irq_affinity_desc *affdesc)
+{
+ return msi_domain_alloc_irq_at(&dev->dev, MSI_SECONDARY_DOMAIN, MSI_ANY_INDEX,
+ affdesc, icookie);
+}
+EXPORT_SYMBOL_GPL(pci_ims_alloc_irq);
+
+/**
+ * pci_ims_free_irq - Allocate an interrupt on a PCI/IMS interrupt domain
+ * which was allocated via pci_ims_alloc_irq()
+ * @dev: The PCI device to operate on
+ * @map: A struct msi_map describing the interrupt to free as
+ * returned from pci_ims_alloc_irq()
+ */
+void pci_ims_free_irq(struct pci_dev *dev, struct msi_map map)
+{
+ if (WARN_ON_ONCE(map.index < 0 || map.virq <= 0))
+ return;
+ msi_domain_free_irqs_range(&dev->dev, MSI_SECONDARY_DOMAIN, map.index, map.index);
+}
+EXPORT_SYMBOL_GPL(pci_ims_free_irq);
+
+/**
+ * pci_free_irq_vectors() - Free previously allocated IRQs for a device
+ * @dev: the PCI device to operate on
+ *
+ * Undo the interrupt vector allocations and possible device MSI/MSI-X
+ * enablement earlier done through pci_alloc_irq_vectors_affinity() or
+ * pci_alloc_irq_vectors().
+ */
+void pci_free_irq_vectors(struct pci_dev *dev)
+{
+ pci_disable_msix(dev);
+ pci_disable_msi(dev);
+}
+EXPORT_SYMBOL(pci_free_irq_vectors);
+
+/**
+ * pci_restore_msi_state() - Restore cached MSI(-X) state on device
+ * @dev: the PCI device to operate on
+ *
+ * Write the Linux-cached MSI(-X) state back on device. This is
+ * typically useful upon system resume, or after an error-recovery PCI
+ * adapter reset.
+ */
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+ __pci_restore_msi_state(dev);
+ __pci_restore_msix_state(dev);
+}
+EXPORT_SYMBOL_GPL(pci_restore_msi_state);
+
+/**
+ * pci_msi_enabled() - Are MSI(-X) interrupts enabled system-wide?
+ *
+ * Return: true if MSI has not been globally disabled through ACPI FADT,
+ * PCI bridge quirks, or the "pci=nomsi" kernel command-line option.
+ */
+int pci_msi_enabled(void)
+{
+ return pci_msi_enable;
+}
+EXPORT_SYMBOL(pci_msi_enabled);
diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c
index e9cf318e6670..e33bcc872699 100644
--- a/drivers/pci/msi/irqdomain.c
+++ b/drivers/pci/msi/irqdomain.c
@@ -14,7 +14,7 @@ int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
domain = dev_get_msi_domain(&dev->dev);
if (domain && irq_domain_is_hierarchy(domain))
- return msi_domain_alloc_irqs_descs_locked(domain, &dev->dev, nvec);
+ return msi_domain_alloc_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN, nvec);
return pci_msi_legacy_setup_msi_irqs(dev, nvec, type);
}
@@ -24,11 +24,12 @@ void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
struct irq_domain *domain;
domain = dev_get_msi_domain(&dev->dev);
- if (domain && irq_domain_is_hierarchy(domain))
- msi_domain_free_irqs_descs_locked(domain, &dev->dev);
- else
+ if (domain && irq_domain_is_hierarchy(domain)) {
+ msi_domain_free_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN);
+ } else {
pci_msi_legacy_teardown_msi_irqs(dev);
- msi_free_msi_descs(&dev->dev);
+ msi_free_msi_descs(&dev->dev);
+ }
}
/**
@@ -63,51 +64,6 @@ static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
(pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
}
-static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
-{
- return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
-}
-
-/**
- * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
- * for @dev
- * @domain: The interrupt domain to check
- * @info: The domain info for verification
- * @dev: The device to check
- *
- * Returns:
- * 0 if the functionality is supported
- * 1 if Multi MSI is requested, but the domain does not support it
- * -ENOTSUPP otherwise
- */
-static int pci_msi_domain_check_cap(struct irq_domain *domain,
- struct msi_domain_info *info,
- struct device *dev)
-{
- struct msi_desc *desc = msi_first_desc(dev, MSI_DESC_ALL);
-
- /* Special handling to support __pci_enable_msi_range() */
- if (pci_msi_desc_is_multi_msi(desc) &&
- !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
- return 1;
-
- if (desc->pci.msi_attrib.is_msix) {
- if (!(info->flags & MSI_FLAG_PCI_MSIX))
- return -ENOTSUPP;
-
- if (info->flags & MSI_FLAG_MSIX_CONTIGUOUS) {
- unsigned int idx = 0;
-
- /* Check for gaps in the entry indices */
- msi_for_each_desc(desc, dev, MSI_DESC_ALL) {
- if (desc->msi_index != idx++)
- return -ENOTSUPP;
- }
- }
- }
- return 0;
-}
-
static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
struct msi_desc *desc)
{
@@ -117,7 +73,6 @@ static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
static struct msi_domain_ops pci_msi_domain_ops_default = {
.set_desc = pci_msi_domain_set_desc,
- .msi_check = pci_msi_domain_check_cap,
};
static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
@@ -129,8 +84,6 @@ static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
} else {
if (ops->set_desc == NULL)
ops->set_desc = pci_msi_domain_set_desc;
- if (ops->msi_check == NULL)
- ops->msi_check = pci_msi_domain_check_cap;
}
}
@@ -162,8 +115,6 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent)
{
- struct irq_domain *domain;
-
if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
@@ -172,23 +123,298 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
pci_msi_domain_update_chip_ops(info);
+ /* Let the core code free MSI descriptors when freeing interrupts */
+ info->flags |= MSI_FLAG_FREE_MSI_DESCS;
+
info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS;
if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
info->flags |= MSI_FLAG_MUST_REACTIVATE;
/* PCI-MSI is oneshot-safe */
info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
+ /* Let the core update the bus token */
+ info->bus_token = DOMAIN_BUS_PCI_MSI;
- domain = msi_create_irq_domain(fwnode, info, parent);
- if (!domain)
- return NULL;
-
- irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
- return domain;
+ return msi_create_irq_domain(fwnode, info, parent);
}
EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
/*
+ * Per device MSI[-X] domain functionality
+ */
+static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+ arg->desc = desc;
+ arg->hwirq = desc->msi_index;
+}
+
+static void pci_irq_mask_msi(struct irq_data *data)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+
+ pci_msi_mask(desc, BIT(data->irq - desc->irq));
+}
+
+static void pci_irq_unmask_msi(struct irq_data *data)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+
+ pci_msi_unmask(desc, BIT(data->irq - desc->irq));
+}
+
+#ifdef CONFIG_GENERIC_IRQ_RESERVATION_MODE
+# define MSI_REACTIVATE MSI_FLAG_MUST_REACTIVATE
+#else
+# define MSI_REACTIVATE 0
+#endif
+
+#define MSI_COMMON_FLAGS (MSI_FLAG_FREE_MSI_DESCS | \
+ MSI_FLAG_ACTIVATE_EARLY | \
+ MSI_FLAG_DEV_SYSFS | \
+ MSI_REACTIVATE)
+
+static const struct msi_domain_template pci_msi_template = {
+ .chip = {
+ .name = "PCI-MSI",
+ .irq_mask = pci_irq_mask_msi,
+ .irq_unmask = pci_irq_unmask_msi,
+ .irq_write_msi_msg = pci_msi_domain_write_msg,
+ .flags = IRQCHIP_ONESHOT_SAFE,
+ },
+
+ .ops = {
+ .set_desc = pci_device_domain_set_desc,
+ },
+
+ .info = {
+ .flags = MSI_COMMON_FLAGS | MSI_FLAG_MULTI_PCI_MSI,
+ .bus_token = DOMAIN_BUS_PCI_DEVICE_MSI,
+ },
+};
+
+static void pci_irq_mask_msix(struct irq_data *data)
+{
+ pci_msix_mask(irq_data_get_msi_desc(data));
+}
+
+static void pci_irq_unmask_msix(struct irq_data *data)
+{
+ pci_msix_unmask(irq_data_get_msi_desc(data));
+}
+
+static void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *arg,
+ struct msi_desc *desc)
+{
+ /* Don't fiddle with preallocated MSI descriptors */
+ if (!desc->pci.mask_base)
+ msix_prepare_msi_desc(to_pci_dev(desc->dev), desc);
+}
+
+static const struct msi_domain_template pci_msix_template = {
+ .chip = {
+ .name = "PCI-MSIX",
+ .irq_mask = pci_irq_mask_msix,
+ .irq_unmask = pci_irq_unmask_msix,
+ .irq_write_msi_msg = pci_msi_domain_write_msg,
+ .flags = IRQCHIP_ONESHOT_SAFE,
+ },
+
+ .ops = {
+ .prepare_desc = pci_msix_prepare_desc,
+ .set_desc = pci_device_domain_set_desc,
+ },
+
+ .info = {
+ .flags = MSI_COMMON_FLAGS | MSI_FLAG_PCI_MSIX |
+ MSI_FLAG_PCI_MSIX_ALLOC_DYN,
+ .bus_token = DOMAIN_BUS_PCI_DEVICE_MSIX,
+ },
+};
+
+static bool pci_match_device_domain(struct pci_dev *pdev, enum irq_domain_bus_token bus_token)
+{
+ return msi_match_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN, bus_token);
+}
+
+static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_domain_template *tmpl,
+ unsigned int hwsize)
+{
+ struct irq_domain *domain = dev_get_msi_domain(&pdev->dev);
+
+ if (!domain || !irq_domain_is_msi_parent(domain))
+ return true;
+
+ return msi_create_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN, tmpl,
+ hwsize, NULL, NULL);
+}
+
+/**
+ * pci_setup_msi_device_domain - Setup a device MSI interrupt domain
+ * @pdev: The PCI device to create the domain on
+ *
+ * Return:
+ * True when:
+ * - The device does not have a MSI parent irq domain associated,
+ * which keeps the legacy architecture specific and the global
+ * PCI/MSI domain models working
+ * - The MSI domain exists already
+ * - The MSI domain was successfully allocated
+ * False when:
+ * - MSI-X is enabled
+ * - The domain creation fails.
+ *
+ * The created MSI domain is preserved until:
+ * - The device is removed
+ * - MSI is disabled and a MSI-X domain is created
+ */
+bool pci_setup_msi_device_domain(struct pci_dev *pdev)
+{
+ if (WARN_ON_ONCE(pdev->msix_enabled))
+ return false;
+
+ if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSI))
+ return true;
+ if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX))
+ msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN);
+
+ return pci_create_device_domain(pdev, &pci_msi_template, 1);
+}
+
+/**
+ * pci_setup_msix_device_domain - Setup a device MSI-X interrupt domain
+ * @pdev: The PCI device to create the domain on
+ * @hwsize: The size of the MSI-X vector table
+ *
+ * Return:
+ * True when:
+ * - The device does not have a MSI parent irq domain associated,
+ * which keeps the legacy architecture specific and the global
+ * PCI/MSI domain models working
+ * - The MSI-X domain exists already
+ * - The MSI-X domain was successfully allocated
+ * False when:
+ * - MSI is enabled
+ * - The domain creation fails.
+ *
+ * The created MSI-X domain is preserved until:
+ * - The device is removed
+ * - MSI-X is disabled and a MSI domain is created
+ */
+bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize)
+{
+ if (WARN_ON_ONCE(pdev->msi_enabled))
+ return false;
+
+ if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX))
+ return true;
+ if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSI))
+ msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN);
+
+ return pci_create_device_domain(pdev, &pci_msix_template, hwsize);
+}
+
+/**
+ * pci_msi_domain_supports - Check for support of a particular feature flag
+ * @pdev: The PCI device to operate on
+ * @feature_mask: The feature mask to check for (full match)
+ * @mode: If ALLOW_LEGACY this grants the feature when there is no irq domain
+ * associated to the device. If DENY_LEGACY the lack of an irq domain
+ * makes the feature unsupported
+ */
+bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask,
+ enum support_mode mode)
+{
+ struct msi_domain_info *info;
+ struct irq_domain *domain;
+ unsigned int supported;
+
+ domain = dev_get_msi_domain(&pdev->dev);
+
+ if (!domain || !irq_domain_is_hierarchy(domain))
+ return mode == ALLOW_LEGACY;
+
+ if (!irq_domain_is_msi_parent(domain)) {
+ /*
+ * For "global" PCI/MSI interrupt domains the associated
+ * msi_domain_info::flags is the authoritive source of
+ * information.
+ */
+ info = domain->host_data;
+ supported = info->flags;
+ } else {
+ /*
+ * For MSI parent domains the supported feature set
+ * is avaliable in the parent ops. This makes checks
+ * possible before actually instantiating the
+ * per device domain because the parent is never
+ * expanding the PCI/MSI functionality.
+ */
+ supported = domain->msi_parent_ops->supported_flags;
+ }
+
+ return (supported & feature_mask) == feature_mask;
+}
+
+/**
+ * pci_create_ims_domain - Create a secondary IMS domain for a PCI device
+ * @pdev: The PCI device to operate on
+ * @template: The MSI info template which describes the domain
+ * @hwsize: The size of the hardware entry table or 0 if the domain
+ * is purely software managed
+ * @data: Optional pointer to domain specific data to be stored
+ * in msi_domain_info::data
+ *
+ * Return: True on success, false otherwise
+ *
+ * An IMS domain is expected to have the following constraints:
+ * - The index space is managed by the core code
+ *
+ * - There is no requirement for consecutive index ranges
+ *
+ * - The interrupt chip must provide the following callbacks:
+ * - irq_mask()
+ * - irq_unmask()
+ * - irq_write_msi_msg()
+ *
+ * - The interrupt chip must provide the following optional callbacks
+ * when the irq_mask(), irq_unmask() and irq_write_msi_msg() callbacks
+ * cannot operate directly on hardware, e.g. in the case that the
+ * interrupt message store is in queue memory:
+ * - irq_bus_lock()
+ * - irq_bus_unlock()
+ *
+ * These callbacks are invoked from preemptible task context and are
+ * allowed to sleep. In this case the mandatory callbacks above just
+ * store the information. The irq_bus_unlock() callback is supposed
+ * to make the change effective before returning.
+ *
+ * - Interrupt affinity setting is handled by the underlying parent
+ * interrupt domain and communicated to the IMS domain via
+ * irq_write_msi_msg().
+ *
+ * The domain is automatically destroyed when the PCI device is removed.
+ */
+bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
+ unsigned int hwsize, void *data)
+{
+ struct irq_domain *domain = dev_get_msi_domain(&pdev->dev);
+
+ if (!domain || !irq_domain_is_msi_parent(domain))
+ return false;
+
+ if (template->info.bus_token != DOMAIN_BUS_PCI_DEVICE_IMS ||
+ !(template->info.flags & MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS) ||
+ !(template->info.flags & MSI_FLAG_FREE_MSI_DESCS) ||
+ !template->chip.irq_mask || !template->chip.irq_unmask ||
+ !template->chip.irq_write_msi_msg || template->chip.irq_set_affinity)
+ return false;
+
+ return msi_create_device_irq_domain(&pdev->dev, MSI_SECONDARY_DOMAIN, template,
+ hwsize, data, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_create_ims_domain);
+
+/*
* Users of the generic MSI infrastructure expect a device to have a single ID,
* so with DMA aliases we have to pick the least-worst compromise. Devices with
* DMA phantom functions tend to still emit MSIs from the real function number,
@@ -257,24 +483,3 @@ struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
DOMAIN_BUS_PCI_MSI);
return dom;
}
-
-/**
- * pci_dev_has_special_msi_domain - Check whether the device is handled by
- * a non-standard PCI-MSI domain
- * @pdev: The PCI device to check.
- *
- * Returns: True if the device irqdomain or the bus irqdomain is
- * non-standard PCI/MSI.
- */
-bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
-{
- struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
-
- if (!dom)
- dom = dev_get_msi_domain(&pdev->bus->dev);
-
- if (!dom)
- return true;
-
- return dom->bus_token != DOMAIN_BUS_PCI_MSI;
-}
diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
index fdd2ec09651e..1f716624ca56 100644
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -13,82 +13,114 @@
#include "../pci.h"
#include "msi.h"
-static int pci_msi_enable = 1;
+int pci_msi_enable = 1;
int pci_msi_ignore_mask;
-static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
+/**
+ * pci_msi_supported - check whether MSI may be enabled on a device
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: how many MSIs have been requested?
+ *
+ * Look at global flags, the device itself, and its parent buses
+ * to determine if MSI/-X are supported for the device. If MSI/-X is
+ * supported return 1, else return 0.
+ **/
+static int pci_msi_supported(struct pci_dev *dev, int nvec)
{
- raw_spinlock_t *lock = &to_pci_dev(desc->dev)->msi_lock;
- unsigned long flags;
+ struct pci_bus *bus;
- if (!desc->pci.msi_attrib.can_mask)
- return;
+ /* MSI must be globally enabled and supported by the device */
+ if (!pci_msi_enable)
+ return 0;
- raw_spin_lock_irqsave(lock, flags);
- desc->pci.msi_mask &= ~clear;
- desc->pci.msi_mask |= set;
- pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->pci.mask_pos,
- desc->pci.msi_mask);
- raw_spin_unlock_irqrestore(lock, flags);
-}
+ if (!dev || dev->no_msi)
+ return 0;
-static inline void pci_msi_mask(struct msi_desc *desc, u32 mask)
-{
- pci_msi_update_mask(desc, 0, mask);
-}
+ /*
+ * You can't ask to have 0 or less MSIs configured.
+ * a) it's stupid ..
+ * b) the list manipulation code assumes nvec >= 1.
+ */
+ if (nvec < 1)
+ return 0;
-static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
-{
- pci_msi_update_mask(desc, mask, 0);
+ /*
+ * Any bridge which does NOT route MSI transactions from its
+ * secondary bus to its primary bus must set NO_MSI flag on
+ * the secondary pci_bus.
+ *
+ * The NO_MSI flag can either be set directly by:
+ * - arch-specific PCI host bus controller drivers (deprecated)
+ * - quirks for specific PCI bridges
+ *
+ * or indirectly by platform-specific PCI host bridge drivers by
+ * advertising the 'msi_domain' property, which results in
+ * the NO_MSI flag when no MSI domain is found for this bridge
+ * at probe time.
+ */
+ for (bus = dev->bus; bus; bus = bus->parent)
+ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+ return 0;
+
+ return 1;
}
-static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
+static void pcim_msi_release(void *pcidev)
{
- return desc->pci.mask_base + desc->msi_index * PCI_MSIX_ENTRY_SIZE;
+ struct pci_dev *dev = pcidev;
+
+ dev->is_msi_managed = false;
+ pci_free_irq_vectors(dev);
}
/*
- * This internal function does not flush PCI writes to the device. All
- * users must ensure that they read from the device before either assuming
- * that the device state is up to date, or returning out of this file.
- * It does not affect the msi_desc::msix_ctrl cache either. Use with care!
+ * Needs to be separate from pcim_release to prevent an ordering problem
+ * vs. msi_device_data_release() in the MSI core code.
*/
-static void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
+static int pcim_setup_msi_release(struct pci_dev *dev)
{
- void __iomem *desc_addr = pci_msix_desc_addr(desc);
+ int ret;
- if (desc->pci.msi_attrib.can_mask)
- writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
-}
+ if (!pci_is_managed(dev) || dev->is_msi_managed)
+ return 0;
-static inline void pci_msix_mask(struct msi_desc *desc)
-{
- desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
- pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
- /* Flush write to device */
- readl(desc->pci.mask_base);
+ ret = devm_add_action(&dev->dev, pcim_msi_release, dev);
+ if (!ret)
+ dev->is_msi_managed = true;
+ return ret;
}
-static inline void pci_msix_unmask(struct msi_desc *desc)
+/*
+ * Ordering vs. devres: msi device data has to be installed first so that
+ * pcim_msi_release() is invoked before it on device release.
+ */
+static int pci_setup_msi_context(struct pci_dev *dev)
{
- desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
- pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
-}
+ int ret = msi_setup_device_data(&dev->dev);
-static void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
-{
- if (desc->pci.msi_attrib.is_msix)
- pci_msix_mask(desc);
- else
- pci_msi_mask(desc, mask);
+ if (!ret)
+ ret = pcim_setup_msi_release(dev);
+ return ret;
}
-static void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
+/*
+ * Helper functions for mask/unmask and MSI message handling
+ */
+
+void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
{
- if (desc->pci.msi_attrib.is_msix)
- pci_msix_unmask(desc);
- else
- pci_msi_unmask(desc, mask);
+ raw_spinlock_t *lock = &to_pci_dev(desc->dev)->msi_lock;
+ unsigned long flags;
+
+ if (!desc->pci.msi_attrib.can_mask)
+ return;
+
+ raw_spin_lock_irqsave(lock, flags);
+ desc->pci.msi_mask &= ~clear;
+ desc->pci.msi_mask |= set;
+ pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->pci.mask_pos,
+ desc->pci.msi_mask);
+ raw_spin_unlock_irqrestore(lock, flags);
}
/**
@@ -148,6 +180,58 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
}
}
+static inline void pci_write_msg_msi(struct pci_dev *dev, struct msi_desc *desc,
+ struct msi_msg *msg)
+{
+ int pos = dev->msi_cap;
+ u16 msgctl;
+
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+ msgctl &= ~PCI_MSI_FLAGS_QSIZE;
+ msgctl |= desc->pci.msi_attrib.multiple << 4;
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
+
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, msg->address_lo);
+ if (desc->pci.msi_attrib.is_64) {
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, msg->address_hi);
+ pci_write_config_word(dev, pos + PCI_MSI_DATA_64, msg->data);
+ } else {
+ pci_write_config_word(dev, pos + PCI_MSI_DATA_32, msg->data);
+ }
+ /* Ensure that the writes are visible in the device */
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+}
+
+static inline void pci_write_msg_msix(struct msi_desc *desc, struct msi_msg *msg)
+{
+ void __iomem *base = pci_msix_desc_addr(desc);
+ u32 ctrl = desc->pci.msix_ctrl;
+ bool unmasked = !(ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
+
+ if (desc->pci.msi_attrib.is_virtual)
+ return;
+ /*
+ * The specification mandates that the entry is masked
+ * when the message is modified:
+ *
+ * "If software changes the Address or Data value of an
+ * entry while the entry is unmasked, the result is
+ * undefined."
+ */
+ if (unmasked)
+ pci_msix_write_vector_ctrl(desc, ctrl | PCI_MSIX_ENTRY_CTRL_MASKBIT);
+
+ writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
+ writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
+ writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
+
+ if (unmasked)
+ pci_msix_write_vector_ctrl(desc, ctrl);
+
+ /* Ensure that the writes are visible in the device */
+ readl(base + PCI_MSIX_ENTRY_DATA);
+}
+
void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
struct pci_dev *dev = msi_desc_to_pci_dev(entry);
@@ -155,63 +239,15 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
if (dev->current_state != PCI_D0 || pci_dev_is_disconnected(dev)) {
/* Don't touch the hardware now */
} else if (entry->pci.msi_attrib.is_msix) {
- void __iomem *base = pci_msix_desc_addr(entry);
- u32 ctrl = entry->pci.msix_ctrl;
- bool unmasked = !(ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
-
- if (entry->pci.msi_attrib.is_virtual)
- goto skip;
-
- /*
- * The specification mandates that the entry is masked
- * when the message is modified:
- *
- * "If software changes the Address or Data value of an
- * entry while the entry is unmasked, the result is
- * undefined."
- */
- if (unmasked)
- pci_msix_write_vector_ctrl(entry, ctrl | PCI_MSIX_ENTRY_CTRL_MASKBIT);
-
- writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
- writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
- writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
-
- if (unmasked)
- pci_msix_write_vector_ctrl(entry, ctrl);
-
- /* Ensure that the writes are visible in the device */
- readl(base + PCI_MSIX_ENTRY_DATA);
+ pci_write_msg_msix(entry, msg);
} else {
- int pos = dev->msi_cap;
- u16 msgctl;
-
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
- msgctl &= ~PCI_MSI_FLAGS_QSIZE;
- msgctl |= entry->pci.msi_attrib.multiple << 4;
- pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
-
- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
- msg->address_lo);
- if (entry->pci.msi_attrib.is_64) {
- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
- msg->address_hi);
- pci_write_config_word(dev, pos + PCI_MSI_DATA_64,
- msg->data);
- } else {
- pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
- msg->data);
- }
- /* Ensure that the writes are visible in the device */
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+ pci_write_msg_msi(dev, entry, msg);
}
-skip:
entry->msg = *msg;
if (entry->write_msi_msg)
entry->write_msi_msg(entry, entry->write_msi_msg_data);
-
}
void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
@@ -222,15 +258,8 @@ void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
}
EXPORT_SYMBOL_GPL(pci_write_msi_msg);
-static void free_msi_irqs(struct pci_dev *dev)
-{
- pci_msi_teardown_msi_irqs(dev);
- if (dev->msix_base) {
- iounmap(dev->msix_base);
- dev->msix_base = NULL;
- }
-}
+/* PCI/MSI specific functionality */
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
{
@@ -249,118 +278,6 @@ static void pci_msi_set_enable(struct pci_dev *dev, int enable)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
-/*
- * Architecture override returns true when the PCI MSI message should be
- * written by the generic restore function.
- */
-bool __weak arch_restore_msi_irqs(struct pci_dev *dev)
-{
- return true;
-}
-
-static void __pci_restore_msi_state(struct pci_dev *dev)
-{
- struct msi_desc *entry;
- u16 control;
-
- if (!dev->msi_enabled)
- return;
-
- entry = irq_get_msi_desc(dev->irq);
-
- pci_intx_for_msi(dev, 0);
- pci_msi_set_enable(dev, 0);
- if (arch_restore_msi_irqs(dev))
- __pci_write_msi_msg(entry, &entry->msg);
-
- pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
- pci_msi_update_mask(entry, 0, 0);
- control &= ~PCI_MSI_FLAGS_QSIZE;
- control |= (entry->pci.msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
- pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
-}
-
-static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
-{
- u16 ctrl;
-
- pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
- ctrl &= ~clear;
- ctrl |= set;
- pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
-}
-
-static void __pci_restore_msix_state(struct pci_dev *dev)
-{
- struct msi_desc *entry;
- bool write_msg;
-
- if (!dev->msix_enabled)
- return;
-
- /* route the table */
- pci_intx_for_msi(dev, 0);
- pci_msix_clear_and_set_ctrl(dev, 0,
- PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
-
- write_msg = arch_restore_msi_irqs(dev);
-
- msi_lock_descs(&dev->dev);
- msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
- if (write_msg)
- __pci_write_msi_msg(entry, &entry->msg);
- pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
- }
- msi_unlock_descs(&dev->dev);
-
- pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
-}
-
-void pci_restore_msi_state(struct pci_dev *dev)
-{
- __pci_restore_msi_state(dev);
- __pci_restore_msix_state(dev);
-}
-EXPORT_SYMBOL_GPL(pci_restore_msi_state);
-
-static void pcim_msi_release(void *pcidev)
-{
- struct pci_dev *dev = pcidev;
-
- dev->is_msi_managed = false;
- pci_free_irq_vectors(dev);
-}
-
-/*
- * Needs to be separate from pcim_release to prevent an ordering problem
- * vs. msi_device_data_release() in the MSI core code.
- */
-static int pcim_setup_msi_release(struct pci_dev *dev)
-{
- int ret;
-
- if (!pci_is_managed(dev) || dev->is_msi_managed)
- return 0;
-
- ret = devm_add_action(&dev->dev, pcim_msi_release, dev);
- if (!ret)
- dev->is_msi_managed = true;
- return ret;
-}
-
-/*
- * Ordering vs. devres: msi device data has to be installed first so that
- * pcim_msi_release() is invoked before it on device release.
- */
-static int pci_setup_msi_context(struct pci_dev *dev)
-{
- int ret = msi_setup_device_data(&dev->dev);
-
- if (!ret)
- ret = pcim_setup_msi_release(dev);
- return ret;
-}
-
static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
struct irq_affinity_desc *masks)
{
@@ -395,7 +312,7 @@ static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
if (desc.pci.msi_attrib.can_mask)
pci_read_config_dword(dev, desc.pci.mask_pos, &desc.pci.msi_mask);
- return msi_add_msi_desc(&dev->dev, &desc);
+ return msi_insert_msi_desc(&dev->dev, &desc);
}
static int msi_verify_entries(struct pci_dev *dev)
@@ -434,6 +351,10 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
struct msi_desc *entry;
int ret;
+ /* Reject multi-MSI early on irq domain enabled architectures */
+ if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
+ return 1;
+
/*
* Disable MSI during setup in the hardware, but mark it enabled
* so that setup code can evaluate it.
@@ -472,7 +393,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
err:
pci_msi_unmask(entry, msi_multi_mask(entry));
- free_msi_irqs(dev);
+ pci_free_msi_irqs(dev);
fail:
dev->msi_enabled = 0;
unlock:
@@ -481,6 +402,152 @@ unlock:
return ret;
}
+int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
+ struct irq_affinity *affd)
+{
+ int nvec;
+ int rc;
+
+ if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0)
+ return -EINVAL;
+
+ /* Check whether driver already requested MSI-X IRQs */
+ if (dev->msix_enabled) {
+ pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
+ return -EINVAL;
+ }
+
+ if (maxvec < minvec)
+ return -ERANGE;
+
+ if (WARN_ON_ONCE(dev->msi_enabled))
+ return -EINVAL;
+
+ nvec = pci_msi_vec_count(dev);
+ if (nvec < 0)
+ return nvec;
+ if (nvec < minvec)
+ return -ENOSPC;
+
+ if (nvec > maxvec)
+ nvec = maxvec;
+
+ rc = pci_setup_msi_context(dev);
+ if (rc)
+ return rc;
+
+ if (!pci_setup_msi_device_domain(dev))
+ return -ENODEV;
+
+ for (;;) {
+ if (affd) {
+ nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
+ if (nvec < minvec)
+ return -ENOSPC;
+ }
+
+ rc = msi_capability_init(dev, nvec, affd);
+ if (rc == 0)
+ return nvec;
+
+ if (rc < 0)
+ return rc;
+ if (rc < minvec)
+ return -ENOSPC;
+
+ nvec = rc;
+ }
+}
+
+/**
+ * pci_msi_vec_count - Return the number of MSI vectors a device can send
+ * @dev: device to report about
+ *
+ * This function returns the number of MSI vectors a device requested via
+ * Multiple Message Capable register. It returns a negative errno if the
+ * device is not capable sending MSI interrupts. Otherwise, the call succeeds
+ * and returns a power of two, up to a maximum of 2^5 (32), according to the
+ * MSI specification.
+ **/
+int pci_msi_vec_count(struct pci_dev *dev)
+{
+ int ret;
+ u16 msgctl;
+
+ if (!dev->msi_cap)
+ return -EINVAL;
+
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
+ ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+
+ return ret;
+}
+EXPORT_SYMBOL(pci_msi_vec_count);
+
+/*
+ * Architecture override returns true when the PCI MSI message should be
+ * written by the generic restore function.
+ */
+bool __weak arch_restore_msi_irqs(struct pci_dev *dev)
+{
+ return true;
+}
+
+void __pci_restore_msi_state(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+ u16 control;
+
+ if (!dev->msi_enabled)
+ return;
+
+ entry = irq_get_msi_desc(dev->irq);
+
+ pci_intx_for_msi(dev, 0);
+ pci_msi_set_enable(dev, 0);
+ if (arch_restore_msi_irqs(dev))
+ __pci_write_msi_msg(entry, &entry->msg);
+
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
+ pci_msi_update_mask(entry, 0, 0);
+ control &= ~PCI_MSI_FLAGS_QSIZE;
+ control |= (entry->pci.msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
+ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
+}
+
+void pci_msi_shutdown(struct pci_dev *dev)
+{
+ struct msi_desc *desc;
+
+ if (!pci_msi_enable || !dev || !dev->msi_enabled)
+ return;
+
+ pci_msi_set_enable(dev, 0);
+ pci_intx_for_msi(dev, 1);
+ dev->msi_enabled = 0;
+
+ /* Return the device with MSI unmasked as initial states */
+ desc = msi_first_desc(&dev->dev, MSI_DESC_ALL);
+ if (!WARN_ON_ONCE(!desc))
+ pci_msi_unmask(desc, msi_multi_mask(desc));
+
+ /* Restore dev->irq to its default pin-assertion IRQ */
+ dev->irq = desc->pci.msi_attrib.default_irq;
+ pcibios_alloc_irq(dev);
+}
+
+/* PCI/MSI-X specific functionality */
+
+static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
+{
+ u16 ctrl;
+
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
+ ctrl &= ~clear;
+ ctrl |= set;
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
+}
+
static void __iomem *msix_map_region(struct pci_dev *dev,
unsigned int nr_entries)
{
@@ -502,36 +569,58 @@ static void __iomem *msix_map_region(struct pci_dev *dev,
return ioremap(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
}
-static int msix_setup_msi_descs(struct pci_dev *dev, void __iomem *base,
- struct msix_entry *entries, int nvec,
- struct irq_affinity_desc *masks)
+/**
+ * msix_prepare_msi_desc - Prepare a half initialized MSI descriptor for operation
+ * @dev: The PCI device for which the descriptor is prepared
+ * @desc: The MSI descriptor for preparation
+ *
+ * This is separate from msix_setup_msi_descs() below to handle dynamic
+ * allocations for MSI-X after initial enablement.
+ *
+ * Ideally the whole MSI-X setup would work that way, but there is no way to
+ * support this for the legacy arch_setup_msi_irqs() mechanism and for the
+ * fake irq domains like the x86 XEN one. Sigh...
+ *
+ * The descriptor is zeroed and only @desc::msi_index and @desc::affinity
+ * are set. When called from msix_setup_msi_descs() then the is_virtual
+ * attribute is initialized as well.
+ *
+ * Fill in the rest.
+ */
+void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc)
+{
+ desc->nvec_used = 1;
+ desc->pci.msi_attrib.is_msix = 1;
+ desc->pci.msi_attrib.is_64 = 1;
+ desc->pci.msi_attrib.default_irq = dev->irq;
+ desc->pci.mask_base = dev->msix_base;
+ desc->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
+ !desc->pci.msi_attrib.is_virtual;
+
+ if (desc->pci.msi_attrib.can_mask) {
+ void __iomem *addr = pci_msix_desc_addr(desc);
+
+ desc->pci.msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
+ }
+}
+
+static int msix_setup_msi_descs(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, struct irq_affinity_desc *masks)
{
int ret = 0, i, vec_count = pci_msix_vec_count(dev);
struct irq_affinity_desc *curmsk;
struct msi_desc desc;
- void __iomem *addr;
memset(&desc, 0, sizeof(desc));
- desc.nvec_used = 1;
- desc.pci.msi_attrib.is_msix = 1;
- desc.pci.msi_attrib.is_64 = 1;
- desc.pci.msi_attrib.default_irq = dev->irq;
- desc.pci.mask_base = base;
-
for (i = 0, curmsk = masks; i < nvec; i++, curmsk++) {
desc.msi_index = entries ? entries[i].entry : i;
desc.affinity = masks ? curmsk : NULL;
desc.pci.msi_attrib.is_virtual = desc.msi_index >= vec_count;
- desc.pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
- !desc.pci.msi_attrib.is_virtual;
- if (desc.pci.msi_attrib.can_mask) {
- addr = pci_msix_desc_addr(&desc);
- desc.pci.msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
- }
+ msix_prepare_msi_desc(dev, &desc);
- ret = msi_add_msi_desc(&dev->dev, &desc);
+ ret = msi_insert_msi_desc(&dev->dev, &desc);
if (ret)
break;
}
@@ -562,9 +651,8 @@ static void msix_mask_all(void __iomem *base, int tsize)
writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
}
-static int msix_setup_interrupts(struct pci_dev *dev, void __iomem *base,
- struct msix_entry *entries, int nvec,
- struct irq_affinity *affd)
+static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, struct irq_affinity *affd)
{
struct irq_affinity_desc *masks = NULL;
int ret;
@@ -573,7 +661,7 @@ static int msix_setup_interrupts(struct pci_dev *dev, void __iomem *base,
masks = irq_create_affinity_masks(nvec, affd);
msi_lock_descs(&dev->dev);
- ret = msix_setup_msi_descs(dev, base, entries, nvec, masks);
+ ret = msix_setup_msi_descs(dev, entries, nvec, masks);
if (ret)
goto out_free;
@@ -590,7 +678,7 @@ static int msix_setup_interrupts(struct pci_dev *dev, void __iomem *base,
goto out_unlock;
out_free:
- free_msi_irqs(dev);
+ pci_free_msi_irqs(dev);
out_unlock:
msi_unlock_descs(&dev->dev);
kfree(masks);
@@ -611,7 +699,6 @@ out_unlock:
static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
int nvec, struct irq_affinity *affd)
{
- void __iomem *base;
int ret, tsize;
u16 control;
@@ -629,15 +716,13 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
/* Request & Map MSI-X table region */
tsize = msix_table_size(control);
- base = msix_map_region(dev, tsize);
- if (!base) {
+ dev->msix_base = msix_map_region(dev, tsize);
+ if (!dev->msix_base) {
ret = -ENOMEM;
goto out_disable;
}
- dev->msix_base = base;
-
- ret = msix_setup_interrupts(dev, base, entries, nvec, affd);
+ ret = msix_setup_interrupts(dev, entries, nvec, affd);
if (ret)
goto out_disable;
@@ -652,7 +737,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
* which takes the MSI-X mask bits into account even
* when MSI-X is disabled, which prevents MSI delivery.
*/
- msix_mask_all(base, tsize);
+ msix_mask_all(dev->msix_base, tsize);
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
pcibios_free_irq(dev);
@@ -665,236 +750,82 @@ out_disable:
return ret;
}
-/**
- * pci_msi_supported - check whether MSI may be enabled on a device
- * @dev: pointer to the pci_dev data structure of MSI device function
- * @nvec: how many MSIs have been requested?
- *
- * Look at global flags, the device itself, and its parent buses
- * to determine if MSI/-X are supported for the device. If MSI/-X is
- * supported return 1, else return 0.
- **/
-static int pci_msi_supported(struct pci_dev *dev, int nvec)
-{
- struct pci_bus *bus;
-
- /* MSI must be globally enabled and supported by the device */
- if (!pci_msi_enable)
- return 0;
-
- if (!dev || dev->no_msi)
- return 0;
-
- /*
- * You can't ask to have 0 or less MSIs configured.
- * a) it's stupid ..
- * b) the list manipulation code assumes nvec >= 1.
- */
- if (nvec < 1)
- return 0;
-
- /*
- * Any bridge which does NOT route MSI transactions from its
- * secondary bus to its primary bus must set NO_MSI flag on
- * the secondary pci_bus.
- *
- * The NO_MSI flag can either be set directly by:
- * - arch-specific PCI host bus controller drivers (deprecated)
- * - quirks for specific PCI bridges
- *
- * or indirectly by platform-specific PCI host bridge drivers by
- * advertising the 'msi_domain' property, which results in
- * the NO_MSI flag when no MSI domain is found for this bridge
- * at probe time.
- */
- for (bus = dev->bus; bus; bus = bus->parent)
- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
- return 0;
-
- return 1;
-}
-
-/**
- * pci_msi_vec_count - Return the number of MSI vectors a device can send
- * @dev: device to report about
- *
- * This function returns the number of MSI vectors a device requested via
- * Multiple Message Capable register. It returns a negative errno if the
- * device is not capable sending MSI interrupts. Otherwise, the call succeeds
- * and returns a power of two, up to a maximum of 2^5 (32), according to the
- * MSI specification.
- **/
-int pci_msi_vec_count(struct pci_dev *dev)
-{
- int ret;
- u16 msgctl;
-
- if (!dev->msi_cap)
- return -EINVAL;
-
- pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
- ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
-
- return ret;
-}
-EXPORT_SYMBOL(pci_msi_vec_count);
-
-static void pci_msi_shutdown(struct pci_dev *dev)
-{
- struct msi_desc *desc;
-
- if (!pci_msi_enable || !dev || !dev->msi_enabled)
- return;
-
- pci_msi_set_enable(dev, 0);
- pci_intx_for_msi(dev, 1);
- dev->msi_enabled = 0;
-
- /* Return the device with MSI unmasked as initial states */
- desc = msi_first_desc(&dev->dev, MSI_DESC_ALL);
- if (!WARN_ON_ONCE(!desc))
- pci_msi_unmask(desc, msi_multi_mask(desc));
-
- /* Restore dev->irq to its default pin-assertion IRQ */
- dev->irq = desc->pci.msi_attrib.default_irq;
- pcibios_alloc_irq(dev);
-}
-
-void pci_disable_msi(struct pci_dev *dev)
-{
- if (!pci_msi_enable || !dev || !dev->msi_enabled)
- return;
-
- msi_lock_descs(&dev->dev);
- pci_msi_shutdown(dev);
- free_msi_irqs(dev);
- msi_unlock_descs(&dev->dev);
-}
-EXPORT_SYMBOL(pci_disable_msi);
-
-/**
- * pci_msix_vec_count - return the number of device's MSI-X table entries
- * @dev: pointer to the pci_dev data structure of MSI-X device function
- * This function returns the number of device's MSI-X table entries and
- * therefore the number of MSI-X vectors device is capable of sending.
- * It returns a negative errno if the device is not capable of sending MSI-X
- * interrupts.
- **/
-int pci_msix_vec_count(struct pci_dev *dev)
-{
- u16 control;
-
- if (!dev->msix_cap)
- return -EINVAL;
-
- pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
- return msix_table_size(control);
-}
-EXPORT_SYMBOL(pci_msix_vec_count);
-
-static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
- int nvec, struct irq_affinity *affd, int flags)
+static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, int hwsize)
{
- int nr_entries;
+ bool nogap;
int i, j;
- if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0)
- return -EINVAL;
+ if (!entries)
+ return true;
- nr_entries = pci_msix_vec_count(dev);
- if (nr_entries < 0)
- return nr_entries;
- if (nvec > nr_entries && !(flags & PCI_IRQ_VIRTUAL))
- return nr_entries;
+ nogap = pci_msi_domain_supports(dev, MSI_FLAG_MSIX_CONTIGUOUS, DENY_LEGACY);
- if (entries) {
- /* Check for any invalid entries */
- for (i = 0; i < nvec; i++) {
- if (entries[i].entry >= nr_entries)
- return -EINVAL; /* invalid entry */
- for (j = i + 1; j < nvec; j++) {
- if (entries[i].entry == entries[j].entry)
- return -EINVAL; /* duplicate entry */
- }
- }
- }
+ for (i = 0; i < nvec; i++) {
+ /* Entry within hardware limit? */
+ if (entries[i].entry >= hwsize)
+ return false;
- /* Check whether driver already requested for MSI IRQ */
- if (dev->msi_enabled) {
- pci_info(dev, "can't enable MSI-X (MSI IRQ already assigned)\n");
- return -EINVAL;
+ /* Check for duplicate entries */
+ for (j = i + 1; j < nvec; j++) {
+ if (entries[i].entry == entries[j].entry)
+ return false;
+ }
+ /* Check for unsupported gaps */
+ if (nogap && entries[i].entry != i)
+ return false;
}
- return msix_capability_init(dev, entries, nvec, affd);
+ return true;
}
-static void pci_msix_shutdown(struct pci_dev *dev)
+int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec,
+ int maxvec, struct irq_affinity *affd, int flags)
{
- struct msi_desc *desc;
+ int hwsize, rc, nvec = maxvec;
- if (!pci_msi_enable || !dev || !dev->msix_enabled)
- return;
+ if (maxvec < minvec)
+ return -ERANGE;
- if (pci_dev_is_disconnected(dev)) {
- dev->msix_enabled = 0;
- return;
+ if (dev->msi_enabled) {
+ pci_info(dev, "can't enable MSI-X (MSI already enabled)\n");
+ return -EINVAL;
}
- /* Return the device with MSI-X masked as initial states */
- msi_for_each_desc(desc, &dev->dev, MSI_DESC_ALL)
- pci_msix_mask(desc);
+ if (WARN_ON_ONCE(dev->msix_enabled))
+ return -EINVAL;
- pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
- pci_intx_for_msi(dev, 1);
- dev->msix_enabled = 0;
- pcibios_alloc_irq(dev);
-}
+ /* Check MSI-X early on irq domain enabled architectures */
+ if (!pci_msi_domain_supports(dev, MSI_FLAG_PCI_MSIX, ALLOW_LEGACY))
+ return -ENOTSUPP;
-void pci_disable_msix(struct pci_dev *dev)
-{
- if (!pci_msi_enable || !dev || !dev->msix_enabled)
- return;
-
- msi_lock_descs(&dev->dev);
- pci_msix_shutdown(dev);
- free_msi_irqs(dev);
- msi_unlock_descs(&dev->dev);
-}
-EXPORT_SYMBOL(pci_disable_msix);
+ if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0)
+ return -EINVAL;
-static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
- struct irq_affinity *affd)
-{
- int nvec;
- int rc;
+ hwsize = pci_msix_vec_count(dev);
+ if (hwsize < 0)
+ return hwsize;
- if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0)
+ if (!pci_msix_validate_entries(dev, entries, nvec, hwsize))
return -EINVAL;
- /* Check whether driver already requested MSI-X IRQs */
- if (dev->msix_enabled) {
- pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
- return -EINVAL;
+ if (hwsize < nvec) {
+ /* Keep the IRQ virtual hackery working */
+ if (flags & PCI_IRQ_VIRTUAL)
+ hwsize = nvec;
+ else
+ nvec = hwsize;
}
- if (maxvec < minvec)
- return -ERANGE;
-
- if (WARN_ON_ONCE(dev->msi_enabled))
- return -EINVAL;
-
- nvec = pci_msi_vec_count(dev);
- if (nvec < 0)
- return nvec;
if (nvec < minvec)
return -ENOSPC;
- if (nvec > maxvec)
- nvec = maxvec;
-
rc = pci_setup_msi_context(dev);
if (rc)
return rc;
+ if (!pci_setup_msix_device_domain(dev, hwsize))
+ return -ENODEV;
+
for (;;) {
if (affd) {
nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
@@ -902,7 +833,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
return -ENOSPC;
}
- rc = msi_capability_init(dev, nvec, affd);
+ rc = msix_capability_init(dev, entries, nvec, affd);
if (rc == 0)
return nvec;
@@ -915,214 +846,67 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
}
}
-/* deprecated, don't use */
-int pci_enable_msi(struct pci_dev *dev)
-{
- int rc = __pci_enable_msi_range(dev, 1, 1, NULL);
- if (rc < 0)
- return rc;
- return 0;
-}
-EXPORT_SYMBOL(pci_enable_msi);
-
-static int __pci_enable_msix_range(struct pci_dev *dev,
- struct msix_entry *entries, int minvec,
- int maxvec, struct irq_affinity *affd,
- int flags)
+void __pci_restore_msix_state(struct pci_dev *dev)
{
- int rc, nvec = maxvec;
-
- if (maxvec < minvec)
- return -ERANGE;
-
- if (WARN_ON_ONCE(dev->msix_enabled))
- return -EINVAL;
-
- rc = pci_setup_msi_context(dev);
- if (rc)
- return rc;
+ struct msi_desc *entry;
+ bool write_msg;
- for (;;) {
- if (affd) {
- nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
- if (nvec < minvec)
- return -ENOSPC;
- }
+ if (!dev->msix_enabled)
+ return;
- rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
- if (rc == 0)
- return nvec;
+ /* route the table */
+ pci_intx_for_msi(dev, 0);
+ pci_msix_clear_and_set_ctrl(dev, 0,
+ PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
- if (rc < 0)
- return rc;
- if (rc < minvec)
- return -ENOSPC;
+ write_msg = arch_restore_msi_irqs(dev);
- nvec = rc;
+ msi_lock_descs(&dev->dev);
+ msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
+ if (write_msg)
+ __pci_write_msi_msg(entry, &entry->msg);
+ pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
}
-}
+ msi_unlock_descs(&dev->dev);
-/**
- * pci_enable_msix_range - configure device's MSI-X capability structure
- * @dev: pointer to the pci_dev data structure of MSI-X device function
- * @entries: pointer to an array of MSI-X entries
- * @minvec: minimum number of MSI-X IRQs requested
- * @maxvec: maximum number of MSI-X IRQs requested
- *
- * Setup the MSI-X capability structure of device function with a maximum
- * possible number of interrupts in the range between @minvec and @maxvec
- * upon its software driver call to request for MSI-X mode enabled on its
- * hardware device function. It returns a negative errno if an error occurs.
- * If it succeeds, it returns the actual number of interrupts allocated and
- * indicates the successful configuration of MSI-X capability structure
- * with new allocated MSI-X interrupts.
- **/
-int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
- int minvec, int maxvec)
-{
- return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
+ pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
}
-EXPORT_SYMBOL(pci_enable_msix_range);
-/**
- * pci_alloc_irq_vectors_affinity - allocate multiple IRQs for a device
- * @dev: PCI device to operate on
- * @min_vecs: minimum number of vectors required (must be >= 1)
- * @max_vecs: maximum (desired) number of vectors
- * @flags: flags or quirks for the allocation
- * @affd: optional description of the affinity requirements
- *
- * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
- * vectors if available, and fall back to a single legacy vector
- * if neither is available. Return the number of vectors allocated,
- * (which might be smaller than @max_vecs) if successful, or a negative
- * error code on error. If less than @min_vecs interrupt vectors are
- * available for @dev the function will fail with -ENOSPC.
- *
- * To get the Linux IRQ number used for a vector that can be passed to
- * request_irq() use the pci_irq_vector() helper.
- */
-int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
- unsigned int max_vecs, unsigned int flags,
- struct irq_affinity *affd)
+void pci_msix_shutdown(struct pci_dev *dev)
{
- struct irq_affinity msi_default_affd = {0};
- int nvecs = -ENOSPC;
-
- if (flags & PCI_IRQ_AFFINITY) {
- if (!affd)
- affd = &msi_default_affd;
- } else {
- if (WARN_ON(affd))
- affd = NULL;
- }
+ struct msi_desc *desc;
- if (flags & PCI_IRQ_MSIX) {
- nvecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
- affd, flags);
- if (nvecs > 0)
- return nvecs;
- }
+ if (!pci_msi_enable || !dev || !dev->msix_enabled)
+ return;
- if (flags & PCI_IRQ_MSI) {
- nvecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd);
- if (nvecs > 0)
- return nvecs;
+ if (pci_dev_is_disconnected(dev)) {
+ dev->msix_enabled = 0;
+ return;
}
- /* use legacy IRQ if allowed */
- if (flags & PCI_IRQ_LEGACY) {
- if (min_vecs == 1 && dev->irq) {
- /*
- * Invoke the affinity spreading logic to ensure that
- * the device driver can adjust queue configuration
- * for the single interrupt case.
- */
- if (affd)
- irq_create_affinity_masks(1, affd);
- pci_intx(dev, 1);
- return 1;
- }
- }
+ /* Return the device with MSI-X masked as initial states */
+ msi_for_each_desc(desc, &dev->dev, MSI_DESC_ALL)
+ pci_msix_mask(desc);
- return nvecs;
+ pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
+ pci_intx_for_msi(dev, 1);
+ dev->msix_enabled = 0;
+ pcibios_alloc_irq(dev);
}
-EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity);
-/**
- * pci_free_irq_vectors - free previously allocated IRQs for a device
- * @dev: PCI device to operate on
- *
- * Undoes the allocations and enabling in pci_alloc_irq_vectors().
- */
-void pci_free_irq_vectors(struct pci_dev *dev)
-{
- pci_disable_msix(dev);
- pci_disable_msi(dev);
-}
-EXPORT_SYMBOL(pci_free_irq_vectors);
+/* Common interfaces */
-/**
- * pci_irq_vector - return Linux IRQ number of a device vector
- * @dev: PCI device to operate on
- * @nr: Interrupt vector index (0-based)
- *
- * @nr has the following meanings depending on the interrupt mode:
- * MSI-X: The index in the MSI-X vector table
- * MSI: The index of the enabled MSI vectors
- * INTx: Must be 0
- *
- * Return: The Linux interrupt number or -EINVAl if @nr is out of range.
- */
-int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
+void pci_free_msi_irqs(struct pci_dev *dev)
{
- unsigned int irq;
-
- if (!dev->msi_enabled && !dev->msix_enabled)
- return !nr ? dev->irq : -EINVAL;
+ pci_msi_teardown_msi_irqs(dev);
- irq = msi_get_virq(&dev->dev, nr);
- return irq ? irq : -EINVAL;
+ if (dev->msix_base) {
+ iounmap(dev->msix_base);
+ dev->msix_base = NULL;
+ }
}
-EXPORT_SYMBOL(pci_irq_vector);
-/**
- * pci_irq_get_affinity - return the affinity of a particular MSI vector
- * @dev: PCI device to operate on
- * @nr: device-relative interrupt vector index (0-based).
- *
- * @nr has the following meanings depending on the interrupt mode:
- * MSI-X: The index in the MSI-X vector table
- * MSI: The index of the enabled MSI vectors
- * INTx: Must be 0
- *
- * Return: A cpumask pointer or NULL if @nr is out of range
- */
-const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
-{
- int idx, irq = pci_irq_vector(dev, nr);
- struct msi_desc *desc;
-
- if (WARN_ON_ONCE(irq <= 0))
- return NULL;
-
- desc = irq_get_msi_desc(irq);
- /* Non-MSI does not have the information handy */
- if (!desc)
- return cpu_possible_mask;
-
- /* MSI[X] interrupts can be allocated without affinity descriptor */
- if (!desc->affinity)
- return NULL;
-
- /*
- * MSI has a mask array in the descriptor.
- * MSI-X has a single mask.
- */
- idx = dev->msi_enabled ? nr : 0;
- return &desc->affinity[idx].mask;
-}
-EXPORT_SYMBOL(pci_irq_get_affinity);
+/* Misc. infrastructure */
struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
{
@@ -1134,15 +918,3 @@ void pci_no_msi(void)
{
pci_msi_enable = 0;
}
-
-/**
- * pci_msi_enabled - is MSI enabled?
- *
- * Returns true if MSI has not been disabled by the command-line option
- * pci=nomsi.
- **/
-int pci_msi_enabled(void)
-{
- return pci_msi_enable;
-}
-EXPORT_SYMBOL(pci_msi_enabled);
diff --git a/drivers/pci/msi/msi.h b/drivers/pci/msi/msi.h
index dbeff066bedd..ee53cf079f4e 100644
--- a/drivers/pci/msi/msi.h
+++ b/drivers/pci/msi/msi.h
@@ -5,24 +5,70 @@
#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
-extern int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
-extern void pci_msi_teardown_msi_irqs(struct pci_dev *dev);
+int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+void pci_msi_teardown_msi_irqs(struct pci_dev *dev);
-#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
-extern int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
-extern void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev);
-#else
-static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+/* Mask/unmask helpers */
+void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set);
+
+static inline void pci_msi_mask(struct msi_desc *desc, u32 mask)
{
- WARN_ON_ONCE(1);
- return -ENODEV;
+ pci_msi_update_mask(desc, 0, mask);
}
-static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
+static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
{
- WARN_ON_ONCE(1);
+ pci_msi_update_mask(desc, mask, 0);
+}
+
+static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
+{
+ return desc->pci.mask_base + desc->msi_index * PCI_MSIX_ENTRY_SIZE;
+}
+
+/*
+ * This internal function does not flush PCI writes to the device. All
+ * users must ensure that they read from the device before either assuming
+ * that the device state is up to date, or returning out of this file.
+ * It does not affect the msi_desc::msix_ctrl cache either. Use with care!
+ */
+static inline void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
+{
+ void __iomem *desc_addr = pci_msix_desc_addr(desc);
+
+ if (desc->pci.msi_attrib.can_mask)
+ writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
+}
+
+static inline void pci_msix_mask(struct msi_desc *desc)
+{
+ desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
+ /* Flush write to device */
+ readl(desc->pci.mask_base);
+}
+
+static inline void pci_msix_unmask(struct msi_desc *desc)
+{
+ desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
+}
+
+static inline void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
+{
+ if (desc->pci.msi_attrib.is_msix)
+ pci_msix_mask(desc);
+ else
+ pci_msi_mask(desc, mask);
+}
+
+static inline void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
+{
+ if (desc->pci.msi_attrib.is_msix)
+ pci_msix_unmask(desc);
+ else
+ pci_msi_unmask(desc, mask);
}
-#endif
/*
* PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
@@ -37,3 +83,47 @@ static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
return 0xffffffff;
return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
}
+
+void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc);
+
+/* Subsystem variables */
+extern int pci_msi_enable;
+
+/* MSI internal functions invoked from the public APIs */
+void pci_msi_shutdown(struct pci_dev *dev);
+void pci_msix_shutdown(struct pci_dev *dev);
+void pci_free_msi_irqs(struct pci_dev *dev);
+int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd);
+int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec,
+ int maxvec, struct irq_affinity *affd, int flags);
+void __pci_restore_msi_state(struct pci_dev *dev);
+void __pci_restore_msix_state(struct pci_dev *dev);
+
+/* irq_domain related functionality */
+
+enum support_mode {
+ ALLOW_LEGACY,
+ DENY_LEGACY,
+};
+
+bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode);
+bool pci_setup_msi_device_domain(struct pci_dev *pdev);
+bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize);
+
+/* Legacy (!IRQDOMAIN) fallbacks */
+
+#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
+int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev);
+#else
+static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ WARN_ON_ONCE(1);
+ return -ENODEV;
+}
+
+static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
+{
+ WARN_ON_ONCE(1);
+}
+#endif
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index 88dc66ee1c46..86812d2073ea 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -89,6 +89,90 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(published);
+static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, struct vm_area_struct *vma)
+{
+ struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+ size_t len = vma->vm_end - vma->vm_start;
+ struct pci_p2pdma *p2pdma;
+ struct percpu_ref *ref;
+ unsigned long vaddr;
+ void *kaddr;
+ int ret;
+
+ /* prevent private mappings from being established */
+ if ((vma->vm_flags & VM_MAYSHARE) != VM_MAYSHARE) {
+ pci_info_ratelimited(pdev,
+ "%s: fail, attempted private mapping\n",
+ current->comm);
+ return -EINVAL;
+ }
+
+ if (vma->vm_pgoff) {
+ pci_info_ratelimited(pdev,
+ "%s: fail, attempted mapping with non-zero offset\n",
+ current->comm);
+ return -EINVAL;
+ }
+
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (!p2pdma) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ kaddr = (void *)gen_pool_alloc_owner(p2pdma->pool, len, (void **)&ref);
+ if (!kaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * vm_insert_page() can sleep, so a reference is taken to mapping
+ * such that rcu_read_unlock() can be done before inserting the
+ * pages
+ */
+ if (unlikely(!percpu_ref_tryget_live_rcu(ref))) {
+ ret = -ENODEV;
+ goto out_free_mem;
+ }
+ rcu_read_unlock();
+
+ for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
+ ret = vm_insert_page(vma, vaddr, virt_to_page(kaddr));
+ if (ret) {
+ gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len);
+ return ret;
+ }
+ percpu_ref_get(ref);
+ put_page(virt_to_page(kaddr));
+ kaddr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+
+ percpu_ref_put(ref);
+
+ return 0;
+out_free_mem:
+ gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len);
+out:
+ rcu_read_unlock();
+ return ret;
+}
+
+static struct bin_attribute p2pmem_alloc_attr = {
+ .attr = { .name = "allocate", .mode = 0660 },
+ .mmap = p2pmem_alloc_mmap,
+ /*
+ * Some places where we want to call mmap (ie. python) will check
+ * that the file size is greater than the mmap size before allowing
+ * the mmap to continue. To work around this, just set the size
+ * to be very large.
+ */
+ .size = SZ_1T,
+};
+
static struct attribute *p2pmem_attrs[] = {
&dev_attr_size.attr,
&dev_attr_available.attr,
@@ -96,11 +180,32 @@ static struct attribute *p2pmem_attrs[] = {
NULL,
};
+static struct bin_attribute *p2pmem_bin_attrs[] = {
+ &p2pmem_alloc_attr,
+ NULL,
+};
+
static const struct attribute_group p2pmem_group = {
.attrs = p2pmem_attrs,
+ .bin_attrs = p2pmem_bin_attrs,
.name = "p2pmem",
};
+static void p2pdma_page_free(struct page *page)
+{
+ struct pci_p2pdma_pagemap *pgmap = to_p2p_pgmap(page->pgmap);
+ struct percpu_ref *ref;
+
+ gen_pool_free_owner(pgmap->provider->p2pdma->pool,
+ (uintptr_t)page_to_virt(page), PAGE_SIZE,
+ (void **)&ref);
+ percpu_ref_put(ref);
+}
+
+static const struct dev_pagemap_ops p2pdma_pgmap_ops = {
+ .page_free = p2pdma_page_free,
+};
+
static void pci_p2pdma_release(void *data)
{
struct pci_dev *pdev = data;
@@ -152,6 +257,19 @@ out:
return error;
}
+static void pci_p2pdma_unmap_mappings(void *data)
+{
+ struct pci_dev *pdev = data;
+
+ /*
+ * Removing the alloc attribute from sysfs will call
+ * unmap_mapping_range() on the inode, teardown any existing userspace
+ * mappings and prevent new ones from being created.
+ */
+ sysfs_remove_file_from_group(&pdev->dev.kobj, &p2pmem_alloc_attr.attr,
+ p2pmem_group.name);
+}
+
/**
* pci_p2pdma_add_resource - add memory for use as p2p memory
* @pdev: the device to add the memory to
@@ -198,6 +316,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
pgmap->range.end = pgmap->range.start + size - 1;
pgmap->nr_range = 1;
pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
+ pgmap->ops = &p2pdma_pgmap_ops;
p2p_pgmap->provider = pdev;
p2p_pgmap->bus_offset = pci_bus_address(pdev, bar) -
@@ -209,6 +328,11 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
goto pgmap_free;
}
+ error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_unmap_mappings,
+ pdev);
+ if (error)
+ goto pages_free;
+
p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
error = gen_pool_add_owner(p2pdma->pool, (unsigned long)addr,
pci_bus_address(pdev, bar) + offset,
@@ -673,7 +797,7 @@ struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients)
}
if (dev_cnt)
- pdev = pci_dev_get(closest_pdevs[prandom_u32_max(dev_cnt)]);
+ pdev = pci_dev_get(closest_pdevs[get_random_u32_below(dev_cnt)]);
for (i = 0; i < dev_cnt; i++)
pci_dev_put(closest_pdevs[i]);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 0a2eeb82cebd..6c250eb214e8 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -756,6 +756,13 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
if (ret)
return ret;
+ if (resource_is_exclusive(&dev->driver_exclusive_resource, off,
+ count)) {
+ pci_warn_once(dev, "%s: Unexpected write to kernel-exclusive config offset %llx",
+ current->comm, off);
+ add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+ }
+
if (off > dev->cfg_size)
return 0;
if (off + count > dev->cfg_size) {
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index e2d8a74f83c3..625f7b2cafe4 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -961,8 +961,14 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
if (aer)
pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS,
info->status);
- if (pcie_aer_is_native(dev))
+ if (pcie_aer_is_native(dev)) {
+ struct pci_driver *pdrv = dev->driver;
+
+ if (pdrv && pdrv->err_handler &&
+ pdrv->err_handler->cor_error_detected)
+ pdrv->err_handler->cor_error_detected(dev);
pcie_clear_device_status(dev);
+ }
} else if (info->severity == AER_NONFATAL)
pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);
else if (info->severity == AER_FATAL)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b66fa42c4b1f..334fd91f01e1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -842,7 +842,6 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
if (!d)
d = pci_host_bridge_acpi_msi_domain(bus);
-#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
/*
* If no IRQ domain was found via the OF tree, try looking it up
* directly through the fwnode_handle.
@@ -854,7 +853,6 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
d = irq_find_matching_fwnode(fwnode,
DOMAIN_BUS_PCI_MSI);
}
-#endif
return d;
}
@@ -2307,6 +2305,12 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
INIT_LIST_HEAD(&dev->bus_list);
dev->dev.type = &pci_dev_type;
dev->bus = pci_bus_get(bus);
+ dev->driver_exclusive_resource = (struct resource) {
+ .name = "PCI Exclusive",
+ .start = 0,
+ .end = -1,
+ };
+
#ifdef CONFIG_PCI_MSI
raw_spin_lock_init(&dev->msi_lock);
#endif
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 341010f20b77..66c259000a44 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -93,7 +93,7 @@ config ARM_PMU_ACPI
config ARM_SMMU_V3_PMU
tristate "ARM SMMUv3 Performance Monitors Extension"
depends on (ARM64 && ACPI) || (COMPILE_TEST && 64BIT)
- depends on GENERIC_MSI_IRQ_DOMAIN
+ depends on GENERIC_MSI_IRQ
help
Provides support for the ARM SMMUv3 Performance Monitor Counter
Groups (PMCG), which provide monitoring of transactions passing
@@ -199,4 +199,8 @@ config MARVELL_CN10K_DDR_PMU
Enable perf support for Marvell DDR Performance monitoring
event on CN10K platform.
+source "drivers/perf/arm_cspmu/Kconfig"
+
+source "drivers/perf/amlogic/Kconfig"
+
endmenu
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index 050d04ee19dd..13e45da61100 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -21,3 +21,5 @@ obj-$(CONFIG_MARVELL_CN10K_TAD_PMU) += marvell_cn10k_tad_pmu.o
obj-$(CONFIG_MARVELL_CN10K_DDR_PMU) += marvell_cn10k_ddr_pmu.o
obj-$(CONFIG_APPLE_M1_CPU_PMU) += apple_m1_cpu_pmu.o
obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o
+obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu/
+obj-$(CONFIG_MESON_DDR_PMU) += amlogic/
diff --git a/drivers/perf/amlogic/Kconfig b/drivers/perf/amlogic/Kconfig
new file mode 100644
index 000000000000..f68db01a7f17
--- /dev/null
+++ b/drivers/perf/amlogic/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config MESON_DDR_PMU
+ tristate "Amlogic DDR Bandwidth Performance Monitor"
+ depends on ARCH_MESON || COMPILE_TEST
+ help
+ Provides support for the DDR performance monitor
+ in Amlogic SoCs, which can give information about
+ memory throughput and other related events. It
+ supports multiple channels to monitor the memory
+ bandwidth simultaneously.
diff --git a/drivers/perf/amlogic/Makefile b/drivers/perf/amlogic/Makefile
new file mode 100644
index 000000000000..d3ab2ac5353b
--- /dev/null
+++ b/drivers/perf/amlogic/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_MESON_DDR_PMU) += meson_ddr_pmu_g12.o
+
+meson_ddr_pmu_g12-y := meson_ddr_pmu_core.o meson_g12_ddr_pmu.o
diff --git a/drivers/perf/amlogic/meson_ddr_pmu_core.c b/drivers/perf/amlogic/meson_ddr_pmu_core.c
new file mode 100644
index 000000000000..b84346dbac2c
--- /dev/null
+++ b/drivers/perf/amlogic/meson_ddr_pmu_core.c
@@ -0,0 +1,561 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Amlogic, Inc. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/init.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <soc/amlogic/meson_ddr_pmu.h>
+
+struct ddr_pmu {
+ struct pmu pmu;
+ struct dmc_info info;
+ struct dmc_counter counters; /* save counters from hw */
+ bool pmu_enabled;
+ struct device *dev;
+ char *name;
+ struct hlist_node node;
+ enum cpuhp_state cpuhp_state;
+ int cpu; /* for cpu hotplug */
+};
+
+#define DDR_PERF_DEV_NAME "meson_ddr_bw"
+#define MAX_AXI_PORTS_OF_CHANNEL 4 /* A DMC channel can monitor max 4 axi ports */
+
+#define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu)
+#define dmc_info_to_pmu(p) container_of(p, struct ddr_pmu, info)
+
+static void dmc_pmu_enable(struct ddr_pmu *pmu)
+{
+ if (!pmu->pmu_enabled)
+ pmu->info.hw_info->enable(&pmu->info);
+
+ pmu->pmu_enabled = true;
+}
+
+static void dmc_pmu_disable(struct ddr_pmu *pmu)
+{
+ if (pmu->pmu_enabled)
+ pmu->info.hw_info->disable(&pmu->info);
+
+ pmu->pmu_enabled = false;
+}
+
+static void meson_ddr_set_axi_filter(struct perf_event *event, u8 axi_id)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ int chann;
+
+ if (event->attr.config > ALL_CHAN_COUNTER_ID &&
+ event->attr.config < COUNTER_MAX_ID) {
+ chann = event->attr.config - CHAN1_COUNTER_ID;
+
+ pmu->info.hw_info->set_axi_filter(&pmu->info, axi_id, chann);
+ }
+}
+
+static void ddr_cnt_addition(struct dmc_counter *sum,
+ struct dmc_counter *add1,
+ struct dmc_counter *add2,
+ int chann_nr)
+{
+ int i;
+ u64 cnt1, cnt2;
+
+ sum->all_cnt = add1->all_cnt + add2->all_cnt;
+ sum->all_req = add1->all_req + add2->all_req;
+ for (i = 0; i < chann_nr; i++) {
+ cnt1 = add1->channel_cnt[i];
+ cnt2 = add2->channel_cnt[i];
+
+ sum->channel_cnt[i] = cnt1 + cnt2;
+ }
+}
+
+static void meson_ddr_perf_event_update(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ u64 new_raw_count = 0;
+ struct dmc_counter dc = {0}, sum_dc = {0};
+ int idx;
+ int chann_nr = pmu->info.hw_info->chann_nr;
+
+ /* get the remain counters in register. */
+ pmu->info.hw_info->get_counters(&pmu->info, &dc);
+
+ ddr_cnt_addition(&sum_dc, &pmu->counters, &dc, chann_nr);
+
+ switch (event->attr.config) {
+ case ALL_CHAN_COUNTER_ID:
+ new_raw_count = sum_dc.all_cnt;
+ break;
+ case CHAN1_COUNTER_ID:
+ case CHAN2_COUNTER_ID:
+ case CHAN3_COUNTER_ID:
+ case CHAN4_COUNTER_ID:
+ case CHAN5_COUNTER_ID:
+ case CHAN6_COUNTER_ID:
+ case CHAN7_COUNTER_ID:
+ case CHAN8_COUNTER_ID:
+ idx = event->attr.config - CHAN1_COUNTER_ID;
+ new_raw_count = sum_dc.channel_cnt[idx];
+ break;
+ }
+
+ local64_set(&event->count, new_raw_count);
+}
+
+static int meson_ddr_perf_event_init(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ u64 config1 = event->attr.config1;
+ u64 config2 = event->attr.config2;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EOPNOTSUPP;
+
+ if (event->cpu < 0)
+ return -EOPNOTSUPP;
+
+ /* check if the number of parameters is too much */
+ if (event->attr.config != ALL_CHAN_COUNTER_ID &&
+ hweight64(config1) + hweight64(config2) > MAX_AXI_PORTS_OF_CHANNEL)
+ return -EOPNOTSUPP;
+
+ event->cpu = pmu->cpu;
+
+ return 0;
+}
+
+static void meson_ddr_perf_event_start(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+
+ memset(&pmu->counters, 0, sizeof(pmu->counters));
+ dmc_pmu_enable(pmu);
+}
+
+static int meson_ddr_perf_event_add(struct perf_event *event, int flags)
+{
+ u64 config1 = event->attr.config1;
+ u64 config2 = event->attr.config2;
+ int i;
+
+ for_each_set_bit(i, (const unsigned long *)&config1, sizeof(config1))
+ meson_ddr_set_axi_filter(event, i);
+
+ for_each_set_bit(i, (const unsigned long *)&config2, sizeof(config2))
+ meson_ddr_set_axi_filter(event, i + 64);
+
+ if (flags & PERF_EF_START)
+ meson_ddr_perf_event_start(event, flags);
+
+ return 0;
+}
+
+static void meson_ddr_perf_event_stop(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+
+ if (flags & PERF_EF_UPDATE)
+ meson_ddr_perf_event_update(event);
+
+ dmc_pmu_disable(pmu);
+}
+
+static void meson_ddr_perf_event_del(struct perf_event *event, int flags)
+{
+ meson_ddr_perf_event_stop(event, PERF_EF_UPDATE);
+}
+
+static ssize_t meson_ddr_perf_cpumask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ddr_pmu *pmu = dev_get_drvdata(dev);
+
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(pmu->cpu));
+}
+
+static struct device_attribute meson_ddr_perf_cpumask_attr =
+__ATTR(cpumask, 0444, meson_ddr_perf_cpumask_show, NULL);
+
+static struct attribute *meson_ddr_perf_cpumask_attrs[] = {
+ &meson_ddr_perf_cpumask_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ddr_perf_cpumask_attr_group = {
+ .attrs = meson_ddr_perf_cpumask_attrs,
+};
+
+static ssize_t
+pmu_event_show(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+ return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
+static ssize_t
+event_show_unit(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ return sysfs_emit(page, "MB\n");
+}
+
+static ssize_t
+event_show_scale(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ /* one count = 16byte = 1.52587890625e-05 MB */
+ return sysfs_emit(page, "1.52587890625e-05\n");
+}
+
+#define AML_DDR_PMU_EVENT_ATTR(_name, _id) \
+{ \
+ .attr = __ATTR(_name, 0444, pmu_event_show, NULL), \
+ .id = _id, \
+}
+
+#define AML_DDR_PMU_EVENT_UNIT_ATTR(_name) \
+ __ATTR(_name.unit, 0444, event_show_unit, NULL)
+
+#define AML_DDR_PMU_EVENT_SCALE_ATTR(_name) \
+ __ATTR(_name.scale, 0444, event_show_scale, NULL)
+
+static struct device_attribute event_unit_attrs[] = {
+ AML_DDR_PMU_EVENT_UNIT_ATTR(total_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_1_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_2_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_3_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_4_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_5_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_6_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_7_rw_bytes),
+ AML_DDR_PMU_EVENT_UNIT_ATTR(chan_8_rw_bytes),
+};
+
+static struct device_attribute event_scale_attrs[] = {
+ AML_DDR_PMU_EVENT_SCALE_ATTR(total_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_1_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_2_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_3_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_4_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_5_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_6_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_7_rw_bytes),
+ AML_DDR_PMU_EVENT_SCALE_ATTR(chan_8_rw_bytes),
+};
+
+static struct perf_pmu_events_attr event_attrs[] = {
+ AML_DDR_PMU_EVENT_ATTR(total_rw_bytes, ALL_CHAN_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_1_rw_bytes, CHAN1_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_2_rw_bytes, CHAN2_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_3_rw_bytes, CHAN3_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_4_rw_bytes, CHAN4_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_5_rw_bytes, CHAN5_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_6_rw_bytes, CHAN6_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_7_rw_bytes, CHAN7_COUNTER_ID),
+ AML_DDR_PMU_EVENT_ATTR(chan_8_rw_bytes, CHAN8_COUNTER_ID),
+};
+
+/* three attrs are combined an event */
+static struct attribute *ddr_perf_events_attrs[COUNTER_MAX_ID * 3];
+
+static struct attribute_group ddr_perf_events_attr_group = {
+ .name = "events",
+ .attrs = ddr_perf_events_attrs,
+};
+
+static umode_t meson_ddr_perf_format_attr_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int n)
+{
+ struct pmu *pmu = dev_get_drvdata(kobj_to_dev(kobj));
+ struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu);
+ const u64 *capability = ddr_pmu->info.hw_info->capability;
+ struct device_attribute *dev_attr;
+ int id;
+ char value[20]; // config1:xxx, 20 is enough
+
+ dev_attr = container_of(attr, struct device_attribute, attr);
+ dev_attr->show(NULL, NULL, value);
+
+ if (sscanf(value, "config1:%d", &id) == 1)
+ return capability[0] & (1ULL << id) ? attr->mode : 0;
+
+ if (sscanf(value, "config2:%d", &id) == 1)
+ return capability[1] & (1ULL << id) ? attr->mode : 0;
+
+ return attr->mode;
+}
+
+static struct attribute_group ddr_perf_format_attr_group = {
+ .name = "format",
+ .is_visible = meson_ddr_perf_format_attr_visible,
+};
+
+static ssize_t meson_ddr_perf_identifier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct ddr_pmu *pmu = dev_get_drvdata(dev);
+
+ return sysfs_emit(page, "%s\n", pmu->name);
+}
+
+static struct device_attribute meson_ddr_perf_identifier_attr =
+__ATTR(identifier, 0444, meson_ddr_perf_identifier_show, NULL);
+
+static struct attribute *meson_ddr_perf_identifier_attrs[] = {
+ &meson_ddr_perf_identifier_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ddr_perf_identifier_attr_group = {
+ .attrs = meson_ddr_perf_identifier_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &ddr_perf_events_attr_group,
+ &ddr_perf_format_attr_group,
+ &ddr_perf_cpumask_attr_group,
+ &ddr_perf_identifier_attr_group,
+ NULL,
+};
+
+static irqreturn_t dmc_irq_handler(int irq, void *dev_id)
+{
+ struct dmc_info *info = dev_id;
+ struct ddr_pmu *pmu;
+ struct dmc_counter counters, *sum_cnter;
+ int i;
+
+ pmu = dmc_info_to_pmu(info);
+
+ if (info->hw_info->irq_handler(info, &counters) != 0)
+ goto out;
+
+ sum_cnter = &pmu->counters;
+ sum_cnter->all_cnt += counters.all_cnt;
+ sum_cnter->all_req += counters.all_req;
+
+ for (i = 0; i < pmu->info.hw_info->chann_nr; i++)
+ sum_cnter->channel_cnt[i] += counters.channel_cnt[i];
+
+ if (pmu->pmu_enabled)
+ /*
+ * the timer interrupt only supprt
+ * one shot mode, we have to re-enable
+ * it in ISR to support continue mode.
+ */
+ info->hw_info->enable(info);
+
+ dev_dbg(pmu->dev, "counts: %llu %llu %llu, %llu, %llu, %llu\t\t"
+ "sum: %llu %llu %llu, %llu, %llu, %llu\n",
+ counters.all_req,
+ counters.all_cnt,
+ counters.channel_cnt[0],
+ counters.channel_cnt[1],
+ counters.channel_cnt[2],
+ counters.channel_cnt[3],
+
+ pmu->counters.all_req,
+ pmu->counters.all_cnt,
+ pmu->counters.channel_cnt[0],
+ pmu->counters.channel_cnt[1],
+ pmu->counters.channel_cnt[2],
+ pmu->counters.channel_cnt[3]);
+out:
+ return IRQ_HANDLED;
+}
+
+static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+ struct ddr_pmu *pmu = hlist_entry_safe(node, struct ddr_pmu, node);
+ int target;
+
+ if (cpu != pmu->cpu)
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target >= nr_cpu_ids)
+ return 0;
+
+ perf_pmu_migrate_context(&pmu->pmu, cpu, target);
+ pmu->cpu = target;
+
+ WARN_ON(irq_set_affinity(pmu->info.irq_num, cpumask_of(pmu->cpu)));
+
+ return 0;
+}
+
+static void fill_event_attr(struct ddr_pmu *pmu)
+{
+ int i, j, k;
+ struct attribute **dst = ddr_perf_events_attrs;
+
+ j = 0;
+ k = 0;
+
+ /* fill ALL_CHAN_COUNTER_ID event */
+ dst[j++] = &event_attrs[k].attr.attr;
+ dst[j++] = &event_unit_attrs[k].attr;
+ dst[j++] = &event_scale_attrs[k].attr;
+
+ k++;
+
+ /* fill each channel event */
+ for (i = 0; i < pmu->info.hw_info->chann_nr; i++, k++) {
+ dst[j++] = &event_attrs[k].attr.attr;
+ dst[j++] = &event_unit_attrs[k].attr;
+ dst[j++] = &event_scale_attrs[k].attr;
+ }
+
+ dst[j] = NULL; /* mark end */
+}
+
+static void fmt_attr_fill(struct attribute **fmt_attr)
+{
+ ddr_perf_format_attr_group.attrs = fmt_attr;
+}
+
+static int ddr_pmu_parse_dt(struct platform_device *pdev,
+ struct dmc_info *info)
+{
+ void __iomem *base;
+ int i, ret;
+
+ info->hw_info = of_device_get_match_data(&pdev->dev);
+
+ for (i = 0; i < info->hw_info->dmc_nr; i++) {
+ /* resource 0 for ddr register base */
+ base = devm_platform_ioremap_resource(pdev, i);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ info->ddr_reg[i] = base;
+ }
+
+ /* resource i for pll register base */
+ base = devm_platform_ioremap_resource(pdev, i);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ info->pll_reg = base;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+
+ info->irq_num = ret;
+
+ ret = devm_request_irq(&pdev->dev, info->irq_num, dmc_irq_handler,
+ IRQF_NOBALANCING, dev_name(&pdev->dev),
+ (void *)info);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int meson_ddr_pmu_create(struct platform_device *pdev)
+{
+ int ret;
+ char *name;
+ struct ddr_pmu *pmu;
+
+ pmu = devm_kzalloc(&pdev->dev, sizeof(struct ddr_pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ *pmu = (struct ddr_pmu) {
+ .pmu = {
+ .module = THIS_MODULE,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+ .task_ctx_nr = perf_invalid_context,
+ .attr_groups = attr_groups,
+ .event_init = meson_ddr_perf_event_init,
+ .add = meson_ddr_perf_event_add,
+ .del = meson_ddr_perf_event_del,
+ .start = meson_ddr_perf_event_start,
+ .stop = meson_ddr_perf_event_stop,
+ .read = meson_ddr_perf_event_update,
+ },
+ };
+
+ ret = ddr_pmu_parse_dt(pdev, &pmu->info);
+ if (ret < 0)
+ return ret;
+
+ fmt_attr_fill(pmu->info.hw_info->fmt_attr);
+
+ pmu->cpu = smp_processor_id();
+
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME);
+ if (!name)
+ return -ENOMEM;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, name, NULL,
+ ddr_perf_offline_cpu);
+ if (ret < 0)
+ return ret;
+
+ pmu->cpuhp_state = ret;
+
+ /* Register the pmu instance for cpu hotplug */
+ ret = cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+ if (ret)
+ goto cpuhp_instance_err;
+
+ fill_event_attr(pmu);
+
+ ret = perf_pmu_register(&pmu->pmu, name, -1);
+ if (ret)
+ goto pmu_register_err;
+
+ pmu->name = name;
+ pmu->dev = &pdev->dev;
+ pmu->pmu_enabled = false;
+
+ platform_set_drvdata(pdev, pmu);
+
+ return 0;
+
+pmu_register_err:
+ cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+
+cpuhp_instance_err:
+ cpuhp_remove_state(pmu->cpuhp_state);
+
+ return ret;
+}
+
+int meson_ddr_pmu_remove(struct platform_device *pdev)
+{
+ struct ddr_pmu *pmu = platform_get_drvdata(pdev);
+
+ perf_pmu_unregister(&pmu->pmu);
+ cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+ cpuhp_remove_state(pmu->cpuhp_state);
+
+ return 0;
+}
diff --git a/drivers/perf/amlogic/meson_g12_ddr_pmu.c b/drivers/perf/amlogic/meson_g12_ddr_pmu.c
new file mode 100644
index 000000000000..a78fdb15e26c
--- /dev/null
+++ b/drivers/perf/amlogic/meson_g12_ddr_pmu.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Amlogic, Inc. All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+#include <soc/amlogic/meson_ddr_pmu.h>
+
+#define PORT_MAJOR 32
+#define DEFAULT_XTAL_FREQ 24000000UL
+
+#define DMC_QOS_IRQ BIT(30)
+
+/* DMC bandwidth monitor register address offset */
+#define DMC_MON_G12_CTRL0 (0x20 << 2)
+#define DMC_MON_G12_CTRL1 (0x21 << 2)
+#define DMC_MON_G12_CTRL2 (0x22 << 2)
+#define DMC_MON_G12_CTRL3 (0x23 << 2)
+#define DMC_MON_G12_CTRL4 (0x24 << 2)
+#define DMC_MON_G12_CTRL5 (0x25 << 2)
+#define DMC_MON_G12_CTRL6 (0x26 << 2)
+#define DMC_MON_G12_CTRL7 (0x27 << 2)
+#define DMC_MON_G12_CTRL8 (0x28 << 2)
+
+#define DMC_MON_G12_ALL_REQ_CNT (0x29 << 2)
+#define DMC_MON_G12_ALL_GRANT_CNT (0x2a << 2)
+#define DMC_MON_G12_ONE_GRANT_CNT (0x2b << 2)
+#define DMC_MON_G12_SEC_GRANT_CNT (0x2c << 2)
+#define DMC_MON_G12_THD_GRANT_CNT (0x2d << 2)
+#define DMC_MON_G12_FOR_GRANT_CNT (0x2e << 2)
+#define DMC_MON_G12_TIMER (0x2f << 2)
+
+/* Each bit represent a axi line */
+PMU_FORMAT_ATTR(event, "config:0-7");
+PMU_FORMAT_ATTR(arm, "config1:0");
+PMU_FORMAT_ATTR(gpu, "config1:1");
+PMU_FORMAT_ATTR(pcie, "config1:2");
+PMU_FORMAT_ATTR(hdcp, "config1:3");
+PMU_FORMAT_ATTR(hevc_front, "config1:4");
+PMU_FORMAT_ATTR(usb3_0, "config1:6");
+PMU_FORMAT_ATTR(device, "config1:7");
+PMU_FORMAT_ATTR(hevc_back, "config1:8");
+PMU_FORMAT_ATTR(h265enc, "config1:9");
+PMU_FORMAT_ATTR(vpu_read1, "config1:16");
+PMU_FORMAT_ATTR(vpu_read2, "config1:17");
+PMU_FORMAT_ATTR(vpu_read3, "config1:18");
+PMU_FORMAT_ATTR(vpu_write1, "config1:19");
+PMU_FORMAT_ATTR(vpu_write2, "config1:20");
+PMU_FORMAT_ATTR(vdec, "config1:21");
+PMU_FORMAT_ATTR(hcodec, "config1:22");
+PMU_FORMAT_ATTR(ge2d, "config1:23");
+
+PMU_FORMAT_ATTR(spicc1, "config1:32");
+PMU_FORMAT_ATTR(usb0, "config1:33");
+PMU_FORMAT_ATTR(dma, "config1:34");
+PMU_FORMAT_ATTR(arb0, "config1:35");
+PMU_FORMAT_ATTR(sd_emmc_b, "config1:36");
+PMU_FORMAT_ATTR(usb1, "config1:37");
+PMU_FORMAT_ATTR(audio, "config1:38");
+PMU_FORMAT_ATTR(aififo, "config1:39");
+PMU_FORMAT_ATTR(parser, "config1:41");
+PMU_FORMAT_ATTR(ao_cpu, "config1:42");
+PMU_FORMAT_ATTR(sd_emmc_c, "config1:43");
+PMU_FORMAT_ATTR(spicc2, "config1:44");
+PMU_FORMAT_ATTR(ethernet, "config1:45");
+PMU_FORMAT_ATTR(sana, "config1:46");
+
+/* for sm1 and g12b */
+PMU_FORMAT_ATTR(nna, "config1:10");
+
+/* for g12b only */
+PMU_FORMAT_ATTR(gdc, "config1:11");
+PMU_FORMAT_ATTR(mipi_isp, "config1:12");
+PMU_FORMAT_ATTR(arm1, "config1:13");
+PMU_FORMAT_ATTR(sd_emmc_a, "config1:40");
+
+static struct attribute *g12_pmu_format_attrs[] = {
+ &format_attr_event.attr,
+ &format_attr_arm.attr,
+ &format_attr_gpu.attr,
+ &format_attr_nna.attr,
+ &format_attr_gdc.attr,
+ &format_attr_arm1.attr,
+ &format_attr_mipi_isp.attr,
+ &format_attr_sd_emmc_a.attr,
+ &format_attr_pcie.attr,
+ &format_attr_hdcp.attr,
+ &format_attr_hevc_front.attr,
+ &format_attr_usb3_0.attr,
+ &format_attr_device.attr,
+ &format_attr_hevc_back.attr,
+ &format_attr_h265enc.attr,
+ &format_attr_vpu_read1.attr,
+ &format_attr_vpu_read2.attr,
+ &format_attr_vpu_read3.attr,
+ &format_attr_vpu_write1.attr,
+ &format_attr_vpu_write2.attr,
+ &format_attr_vdec.attr,
+ &format_attr_hcodec.attr,
+ &format_attr_ge2d.attr,
+ &format_attr_spicc1.attr,
+ &format_attr_usb0.attr,
+ &format_attr_dma.attr,
+ &format_attr_arb0.attr,
+ &format_attr_sd_emmc_b.attr,
+ &format_attr_usb1.attr,
+ &format_attr_audio.attr,
+ &format_attr_aififo.attr,
+ &format_attr_parser.attr,
+ &format_attr_ao_cpu.attr,
+ &format_attr_sd_emmc_c.attr,
+ &format_attr_spicc2.attr,
+ &format_attr_ethernet.attr,
+ &format_attr_sana.attr,
+ NULL,
+};
+
+/* calculate ddr clock */
+static unsigned long dmc_g12_get_freq_quick(struct dmc_info *info)
+{
+ unsigned int val;
+ unsigned int n, m, od1;
+ unsigned int od_div = 0xfff;
+ unsigned long freq = 0;
+
+ val = readl(info->pll_reg);
+ val = val & 0xfffff;
+ switch ((val >> 16) & 7) {
+ case 0:
+ od_div = 2;
+ break;
+
+ case 1:
+ od_div = 3;
+ break;
+
+ case 2:
+ od_div = 4;
+ break;
+
+ case 3:
+ od_div = 6;
+ break;
+
+ case 4:
+ od_div = 8;
+ break;
+
+ default:
+ break;
+ }
+
+ m = val & 0x1ff;
+ n = ((val >> 10) & 0x1f);
+ od1 = (((val >> 19) & 0x1)) == 1 ? 2 : 1;
+ freq = DEFAULT_XTAL_FREQ / 1000; /* avoid overflow */
+ if (n)
+ freq = ((((freq * m) / n) >> od1) / od_div) * 1000;
+
+ return freq;
+}
+
+#ifdef DEBUG
+static void g12_dump_reg(struct dmc_info *db)
+{
+ int s = 0, i;
+ unsigned int r;
+
+ for (i = 0; i < 9; i++) {
+ r = readl(db->ddr_reg[0] + (DMC_MON_G12_CTRL0 + (i << 2)));
+ pr_notice("DMC_MON_CTRL%d: %08x\n", i, r);
+ }
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);
+ pr_notice("DMC_MON_ALL_REQ_CNT: %08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);
+ pr_notice("DMC_MON_ALL_GRANT_CNT:%08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_ONE_GRANT_CNT);
+ pr_notice("DMC_MON_ONE_GRANT_CNT:%08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_SEC_GRANT_CNT);
+ pr_notice("DMC_MON_SEC_GRANT_CNT:%08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_THD_GRANT_CNT);
+ pr_notice("DMC_MON_THD_GRANT_CNT:%08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_FOR_GRANT_CNT);
+ pr_notice("DMC_MON_FOR_GRANT_CNT:%08x\n", r);
+ r = readl(db->ddr_reg[0] + DMC_MON_G12_TIMER);
+ pr_notice("DMC_MON_TIMER: %08x\n", r);
+}
+#endif
+
+static void dmc_g12_counter_enable(struct dmc_info *info)
+{
+ unsigned int val;
+ unsigned long clock_count = dmc_g12_get_freq_quick(info) / 10; /* 100ms */
+
+ writel(clock_count, info->ddr_reg[0] + DMC_MON_G12_TIMER);
+
+ val = readl(info->ddr_reg[0] + DMC_MON_G12_CTRL0);
+
+ /* enable all channel */
+ val = BIT(31) | /* enable bit */
+ BIT(20) | /* use timer */
+ 0x0f; /* 4 channels */
+
+ writel(val, info->ddr_reg[0] + DMC_MON_G12_CTRL0);
+
+#ifdef DEBUG
+ g12_dump_reg(info);
+#endif
+}
+
+static void dmc_g12_config_fiter(struct dmc_info *info,
+ int port, int channel)
+{
+ u32 val;
+ u32 rp[MAX_CHANNEL_NUM] = {DMC_MON_G12_CTRL1, DMC_MON_G12_CTRL3,
+ DMC_MON_G12_CTRL5, DMC_MON_G12_CTRL7};
+ u32 rs[MAX_CHANNEL_NUM] = {DMC_MON_G12_CTRL2, DMC_MON_G12_CTRL4,
+ DMC_MON_G12_CTRL6, DMC_MON_G12_CTRL8};
+ int subport = -1;
+
+ /* clear all port mask */
+ if (port < 0) {
+ writel(0, info->ddr_reg[0] + rp[channel]);
+ writel(0, info->ddr_reg[0] + rs[channel]);
+ return;
+ }
+
+ if (port >= PORT_MAJOR)
+ subport = port - PORT_MAJOR;
+
+ if (subport < 0) {
+ val = readl(info->ddr_reg[0] + rp[channel]);
+ val |= (1 << port);
+ writel(val, info->ddr_reg[0] + rp[channel]);
+ val = 0xffff;
+ writel(val, info->ddr_reg[0] + rs[channel]);
+ } else {
+ val = BIT(23); /* select device */
+ writel(val, info->ddr_reg[0] + rp[channel]);
+ val = readl(info->ddr_reg[0] + rs[channel]);
+ val |= (1 << subport);
+ writel(val, info->ddr_reg[0] + rs[channel]);
+ }
+}
+
+static void dmc_g12_set_axi_filter(struct dmc_info *info, int axi_id, int channel)
+{
+ if (channel > info->hw_info->chann_nr)
+ return;
+
+ dmc_g12_config_fiter(info, axi_id, channel);
+}
+
+static void dmc_g12_counter_disable(struct dmc_info *info)
+{
+ int i;
+
+ /* clear timer */
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_CTRL0);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_TIMER);
+
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_ONE_GRANT_CNT);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_SEC_GRANT_CNT);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_THD_GRANT_CNT);
+ writel(0, info->ddr_reg[0] + DMC_MON_G12_FOR_GRANT_CNT);
+
+ /* clear port channel mapping */
+ for (i = 0; i < info->hw_info->chann_nr; i++)
+ dmc_g12_config_fiter(info, -1, i);
+}
+
+static void dmc_g12_get_counters(struct dmc_info *info,
+ struct dmc_counter *counter)
+{
+ int i;
+ unsigned int reg;
+
+ counter->all_cnt = readl(info->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);
+ counter->all_req = readl(info->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);
+
+ for (i = 0; i < info->hw_info->chann_nr; i++) {
+ reg = DMC_MON_G12_ONE_GRANT_CNT + (i << 2);
+ counter->channel_cnt[i] = readl(info->ddr_reg[0] + reg);
+ }
+}
+
+static int dmc_g12_irq_handler(struct dmc_info *info,
+ struct dmc_counter *counter)
+{
+ unsigned int val;
+ int ret = -EINVAL;
+
+ val = readl(info->ddr_reg[0] + DMC_MON_G12_CTRL0);
+ if (val & DMC_QOS_IRQ) {
+ dmc_g12_get_counters(info, counter);
+ /* clear irq flags */
+ writel(val, info->ddr_reg[0] + DMC_MON_G12_CTRL0);
+ ret = 0;
+ }
+ return ret;
+}
+
+static const struct dmc_hw_info g12a_dmc_info = {
+ .enable = dmc_g12_counter_enable,
+ .disable = dmc_g12_counter_disable,
+ .irq_handler = dmc_g12_irq_handler,
+ .get_counters = dmc_g12_get_counters,
+ .set_axi_filter = dmc_g12_set_axi_filter,
+
+ .dmc_nr = 1,
+ .chann_nr = 4,
+ .capability = {0X7EFF00FF03DF, 0},
+ .fmt_attr = g12_pmu_format_attrs,
+};
+
+static const struct dmc_hw_info g12b_dmc_info = {
+ .enable = dmc_g12_counter_enable,
+ .disable = dmc_g12_counter_disable,
+ .irq_handler = dmc_g12_irq_handler,
+ .get_counters = dmc_g12_get_counters,
+ .set_axi_filter = dmc_g12_set_axi_filter,
+
+ .dmc_nr = 1,
+ .chann_nr = 4,
+ .capability = {0X7FFF00FF3FDF, 0},
+ .fmt_attr = g12_pmu_format_attrs,
+};
+
+static const struct dmc_hw_info sm1_dmc_info = {
+ .enable = dmc_g12_counter_enable,
+ .disable = dmc_g12_counter_disable,
+ .irq_handler = dmc_g12_irq_handler,
+ .get_counters = dmc_g12_get_counters,
+ .set_axi_filter = dmc_g12_set_axi_filter,
+
+ .dmc_nr = 1,
+ .chann_nr = 4,
+ .capability = {0X7EFF00FF07DF, 0},
+ .fmt_attr = g12_pmu_format_attrs,
+};
+
+static int g12_ddr_pmu_probe(struct platform_device *pdev)
+{
+ return meson_ddr_pmu_create(pdev);
+}
+
+static int g12_ddr_pmu_remove(struct platform_device *pdev)
+{
+ meson_ddr_pmu_remove(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id meson_ddr_pmu_dt_match[] = {
+ {
+ .compatible = "amlogic,g12a-ddr-pmu",
+ .data = &g12a_dmc_info,
+ },
+ {
+ .compatible = "amlogic,g12b-ddr-pmu",
+ .data = &g12b_dmc_info,
+ },
+ {
+ .compatible = "amlogic,sm1-ddr-pmu",
+ .data = &sm1_dmc_info,
+ },
+ {}
+};
+
+static struct platform_driver g12_ddr_pmu_driver = {
+ .probe = g12_ddr_pmu_probe,
+ .remove = g12_ddr_pmu_remove,
+
+ .driver = {
+ .name = "meson-g12-ddr-pmu",
+ .of_match_table = meson_ddr_pmu_dt_match,
+ },
+};
+
+module_platform_driver(g12_ddr_pmu_driver);
+MODULE_AUTHOR("Jiucheng Xu");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Amlogic G12 series SoC DDR PMU");
diff --git a/drivers/perf/arm_cspmu/Kconfig b/drivers/perf/arm_cspmu/Kconfig
new file mode 100644
index 000000000000..0b316fe69a45
--- /dev/null
+++ b/drivers/perf/arm_cspmu/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+config ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU
+ tristate "ARM Coresight Architecture PMU"
+ depends on ARM64 && ACPI
+ depends on ACPI_APMT || COMPILE_TEST
+ help
+ Provides support for performance monitoring unit (PMU) devices
+ based on ARM CoreSight PMU architecture. Note that this PMU
+ architecture does not have relationship with the ARM CoreSight
+ Self-Hosted Tracing.
diff --git a/drivers/perf/arm_cspmu/Makefile b/drivers/perf/arm_cspmu/Makefile
new file mode 100644
index 000000000000..fedb17df982d
--- /dev/null
+++ b/drivers/perf/arm_cspmu/Makefile
@@ -0,0 +1,6 @@
+# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu_module.o
+arm_cspmu_module-y := arm_cspmu.o nvidia_cspmu.o
diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c
new file mode 100644
index 000000000000..e31302ab7e37
--- /dev/null
+++ b/drivers/perf/arm_cspmu/arm_cspmu.c
@@ -0,0 +1,1303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM CoreSight Architecture PMU driver.
+ *
+ * This driver adds support for uncore PMU based on ARM CoreSight Performance
+ * Monitoring Unit Architecture. The PMU is accessible via MMIO registers and
+ * like other uncore PMUs, it does not support process specific events and
+ * cannot be used in sampling mode.
+ *
+ * This code is based on other uncore PMUs like ARM DSU PMU. It provides a
+ * generic implementation to operate the PMU according to CoreSight PMU
+ * architecture and ACPI ARM PMU table (APMT) documents below:
+ * - ARM CoreSight PMU architecture document number: ARM IHI 0091 A.a-00bet0.
+ * - APMT document number: ARM DEN0117.
+ *
+ * The user should refer to the vendor technical documentation to get details
+ * about the supported events.
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/cacheinfo.h>
+#include <linux/ctype.h>
+#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/module.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <acpi/processor.h>
+
+#include "arm_cspmu.h"
+#include "nvidia_cspmu.h"
+
+#define PMUNAME "arm_cspmu"
+#define DRVNAME "arm-cs-arch-pmu"
+
+#define ARM_CSPMU_CPUMASK_ATTR(_name, _config) \
+ ARM_CSPMU_EXT_ATTR(_name, arm_cspmu_cpumask_show, \
+ (unsigned long)_config)
+
+/*
+ * CoreSight PMU Arch register offsets.
+ */
+#define PMEVCNTR_LO 0x0
+#define PMEVCNTR_HI 0x4
+#define PMEVTYPER 0x400
+#define PMCCFILTR 0x47C
+#define PMEVFILTR 0xA00
+#define PMCNTENSET 0xC00
+#define PMCNTENCLR 0xC20
+#define PMINTENSET 0xC40
+#define PMINTENCLR 0xC60
+#define PMOVSCLR 0xC80
+#define PMOVSSET 0xCC0
+#define PMCFGR 0xE00
+#define PMCR 0xE04
+#define PMIIDR 0xE08
+
+/* PMCFGR register field */
+#define PMCFGR_NCG GENMASK(31, 28)
+#define PMCFGR_HDBG BIT(24)
+#define PMCFGR_TRO BIT(23)
+#define PMCFGR_SS BIT(22)
+#define PMCFGR_FZO BIT(21)
+#define PMCFGR_MSI BIT(20)
+#define PMCFGR_UEN BIT(19)
+#define PMCFGR_NA BIT(17)
+#define PMCFGR_EX BIT(16)
+#define PMCFGR_CCD BIT(15)
+#define PMCFGR_CC BIT(14)
+#define PMCFGR_SIZE GENMASK(13, 8)
+#define PMCFGR_N GENMASK(7, 0)
+
+/* PMCR register field */
+#define PMCR_TRO BIT(11)
+#define PMCR_HDBG BIT(10)
+#define PMCR_FZO BIT(9)
+#define PMCR_NA BIT(8)
+#define PMCR_DP BIT(5)
+#define PMCR_X BIT(4)
+#define PMCR_D BIT(3)
+#define PMCR_C BIT(2)
+#define PMCR_P BIT(1)
+#define PMCR_E BIT(0)
+
+/* Each SET/CLR register supports up to 32 counters. */
+#define ARM_CSPMU_SET_CLR_COUNTER_SHIFT 5
+#define ARM_CSPMU_SET_CLR_COUNTER_NUM \
+ (1 << ARM_CSPMU_SET_CLR_COUNTER_SHIFT)
+
+/* Convert counter idx into SET/CLR register number. */
+#define COUNTER_TO_SET_CLR_ID(idx) \
+ (idx >> ARM_CSPMU_SET_CLR_COUNTER_SHIFT)
+
+/* Convert counter idx into SET/CLR register bit. */
+#define COUNTER_TO_SET_CLR_BIT(idx) \
+ (idx & (ARM_CSPMU_SET_CLR_COUNTER_NUM - 1))
+
+#define ARM_CSPMU_ACTIVE_CPU_MASK 0x0
+#define ARM_CSPMU_ASSOCIATED_CPU_MASK 0x1
+
+/* Check if field f in flags is set with value v */
+#define CHECK_APMT_FLAG(flags, f, v) \
+ ((flags & (ACPI_APMT_FLAGS_ ## f)) == (ACPI_APMT_FLAGS_ ## f ## _ ## v))
+
+/* Check and use default if implementer doesn't provide attribute callback */
+#define CHECK_DEFAULT_IMPL_OPS(ops, callback) \
+ do { \
+ if (!ops->callback) \
+ ops->callback = arm_cspmu_ ## callback; \
+ } while (0)
+
+/*
+ * Maximum poll count for reading counter value using high-low-high sequence.
+ */
+#define HILOHI_MAX_POLL 1000
+
+/* JEDEC-assigned JEP106 identification code */
+#define ARM_CSPMU_IMPL_ID_NVIDIA 0x36B
+
+static unsigned long arm_cspmu_cpuhp_state;
+
+/*
+ * In CoreSight PMU architecture, all of the MMIO registers are 32-bit except
+ * counter register. The counter register can be implemented as 32-bit or 64-bit
+ * register depending on the value of PMCFGR.SIZE field. For 64-bit access,
+ * single-copy 64-bit atomic support is implementation defined. APMT node flag
+ * is used to identify if the PMU supports 64-bit single copy atomic. If 64-bit
+ * single copy atomic is not supported, the driver treats the register as a pair
+ * of 32-bit register.
+ */
+
+/*
+ * Read 64-bit register as a pair of 32-bit registers using hi-lo-hi sequence.
+ */
+static u64 read_reg64_hilohi(const void __iomem *addr, u32 max_poll_count)
+{
+ u32 val_lo, val_hi;
+ u64 val;
+
+ /* Use high-low-high sequence to avoid tearing */
+ do {
+ if (max_poll_count-- == 0) {
+ pr_err("ARM CSPMU: timeout hi-low-high sequence\n");
+ return 0;
+ }
+
+ val_hi = readl(addr + 4);
+ val_lo = readl(addr);
+ } while (val_hi != readl(addr + 4));
+
+ val = (((u64)val_hi << 32) | val_lo);
+
+ return val;
+}
+
+/* Check if PMU supports 64-bit single copy atomic. */
+static inline bool supports_64bit_atomics(const struct arm_cspmu *cspmu)
+{
+ return CHECK_APMT_FLAG(cspmu->apmt_node->flags, ATOMIC, SUPP);
+}
+
+/* Check if cycle counter is supported. */
+static inline bool supports_cycle_counter(const struct arm_cspmu *cspmu)
+{
+ return (cspmu->pmcfgr & PMCFGR_CC);
+}
+
+/* Get counter size, which is (PMCFGR_SIZE + 1). */
+static inline u32 counter_size(const struct arm_cspmu *cspmu)
+{
+ return FIELD_GET(PMCFGR_SIZE, cspmu->pmcfgr) + 1;
+}
+
+/* Get counter mask. */
+static inline u64 counter_mask(const struct arm_cspmu *cspmu)
+{
+ return GENMASK_ULL(counter_size(cspmu) - 1, 0);
+}
+
+/* Check if counter is implemented as 64-bit register. */
+static inline bool use_64b_counter_reg(const struct arm_cspmu *cspmu)
+{
+ return (counter_size(cspmu) > 32);
+}
+
+ssize_t arm_cspmu_sysfs_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr =
+ container_of(attr, struct dev_ext_attribute, attr);
+ return sysfs_emit(buf, "event=0x%llx\n",
+ (unsigned long long)eattr->var);
+}
+EXPORT_SYMBOL_GPL(arm_cspmu_sysfs_event_show);
+
+/* Default event list. */
+static struct attribute *arm_cspmu_event_attrs[] = {
+ ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
+ NULL,
+};
+
+static struct attribute **
+arm_cspmu_get_event_attrs(const struct arm_cspmu *cspmu)
+{
+ struct attribute **attrs;
+
+ attrs = devm_kmemdup(cspmu->dev, arm_cspmu_event_attrs,
+ sizeof(arm_cspmu_event_attrs), GFP_KERNEL);
+
+ return attrs;
+}
+
+static umode_t
+arm_cspmu_event_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int unused)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct arm_cspmu *cspmu = to_arm_cspmu(dev_get_drvdata(dev));
+ struct perf_pmu_events_attr *eattr;
+
+ eattr = container_of(attr, typeof(*eattr), attr.attr);
+
+ /* Hide cycle event if not supported */
+ if (!supports_cycle_counter(cspmu) &&
+ eattr->id == ARM_CSPMU_EVT_CYCLES_DEFAULT)
+ return 0;
+
+ return attr->mode;
+}
+
+ssize_t arm_cspmu_sysfs_format_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dev_ext_attribute *eattr =
+ container_of(attr, struct dev_ext_attribute, attr);
+ return sysfs_emit(buf, "%s\n", (char *)eattr->var);
+}
+EXPORT_SYMBOL_GPL(arm_cspmu_sysfs_format_show);
+
+static struct attribute *arm_cspmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ ARM_CSPMU_FORMAT_FILTER_ATTR,
+ NULL,
+};
+
+static struct attribute **
+arm_cspmu_get_format_attrs(const struct arm_cspmu *cspmu)
+{
+ struct attribute **attrs;
+
+ attrs = devm_kmemdup(cspmu->dev, arm_cspmu_format_attrs,
+ sizeof(arm_cspmu_format_attrs), GFP_KERNEL);
+
+ return attrs;
+}
+
+static u32 arm_cspmu_event_type(const struct perf_event *event)
+{
+ return event->attr.config & ARM_CSPMU_EVENT_MASK;
+}
+
+static bool arm_cspmu_is_cycle_counter_event(const struct perf_event *event)
+{
+ return (event->attr.config == ARM_CSPMU_EVT_CYCLES_DEFAULT);
+}
+
+static u32 arm_cspmu_event_filter(const struct perf_event *event)
+{
+ return event->attr.config1 & ARM_CSPMU_FILTER_MASK;
+}
+
+static ssize_t arm_cspmu_identifier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(dev_get_drvdata(dev));
+
+ return sysfs_emit(page, "%s\n", cspmu->identifier);
+}
+
+static struct device_attribute arm_cspmu_identifier_attr =
+ __ATTR(identifier, 0444, arm_cspmu_identifier_show, NULL);
+
+static struct attribute *arm_cspmu_identifier_attrs[] = {
+ &arm_cspmu_identifier_attr.attr,
+ NULL,
+};
+
+static struct attribute_group arm_cspmu_identifier_attr_group = {
+ .attrs = arm_cspmu_identifier_attrs,
+};
+
+static const char *arm_cspmu_get_identifier(const struct arm_cspmu *cspmu)
+{
+ const char *identifier =
+ devm_kasprintf(cspmu->dev, GFP_KERNEL, "%x",
+ cspmu->impl.pmiidr);
+ return identifier;
+}
+
+static const char *arm_cspmu_type_str[ACPI_APMT_NODE_TYPE_COUNT] = {
+ "mc",
+ "smmu",
+ "pcie",
+ "acpi",
+ "cache",
+};
+
+static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu)
+{
+ struct device *dev;
+ struct acpi_apmt_node *apmt_node;
+ u8 pmu_type;
+ char *name;
+ char acpi_hid_string[ACPI_ID_LEN] = { 0 };
+ static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT] = { 0 };
+
+ dev = cspmu->dev;
+ apmt_node = cspmu->apmt_node;
+ pmu_type = apmt_node->type;
+
+ if (pmu_type >= ACPI_APMT_NODE_TYPE_COUNT) {
+ dev_err(dev, "unsupported PMU type-%u\n", pmu_type);
+ return NULL;
+ }
+
+ if (pmu_type == ACPI_APMT_NODE_TYPE_ACPI) {
+ memcpy(acpi_hid_string,
+ &apmt_node->inst_primary,
+ sizeof(apmt_node->inst_primary));
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s_%s_%u", PMUNAME,
+ arm_cspmu_type_str[pmu_type],
+ acpi_hid_string,
+ apmt_node->inst_secondary);
+ } else {
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s_%d", PMUNAME,
+ arm_cspmu_type_str[pmu_type],
+ atomic_fetch_inc(&pmu_idx[pmu_type]));
+ }
+
+ return name;
+}
+
+static ssize_t arm_cspmu_cpumask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pmu *pmu = dev_get_drvdata(dev);
+ struct arm_cspmu *cspmu = to_arm_cspmu(pmu);
+ struct dev_ext_attribute *eattr =
+ container_of(attr, struct dev_ext_attribute, attr);
+ unsigned long mask_id = (unsigned long)eattr->var;
+ const cpumask_t *cpumask;
+
+ switch (mask_id) {
+ case ARM_CSPMU_ACTIVE_CPU_MASK:
+ cpumask = &cspmu->active_cpu;
+ break;
+ case ARM_CSPMU_ASSOCIATED_CPU_MASK:
+ cpumask = &cspmu->associated_cpus;
+ break;
+ default:
+ return 0;
+ }
+ return cpumap_print_to_pagebuf(true, buf, cpumask);
+}
+
+static struct attribute *arm_cspmu_cpumask_attrs[] = {
+ ARM_CSPMU_CPUMASK_ATTR(cpumask, ARM_CSPMU_ACTIVE_CPU_MASK),
+ ARM_CSPMU_CPUMASK_ATTR(associated_cpus, ARM_CSPMU_ASSOCIATED_CPU_MASK),
+ NULL,
+};
+
+static struct attribute_group arm_cspmu_cpumask_attr_group = {
+ .attrs = arm_cspmu_cpumask_attrs,
+};
+
+struct impl_match {
+ u32 pmiidr;
+ u32 mask;
+ int (*impl_init_ops)(struct arm_cspmu *cspmu);
+};
+
+static const struct impl_match impl_match[] = {
+ {
+ .pmiidr = ARM_CSPMU_IMPL_ID_NVIDIA,
+ .mask = ARM_CSPMU_PMIIDR_IMPLEMENTER,
+ .impl_init_ops = nv_cspmu_init_ops
+ },
+ {}
+};
+
+static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu)
+{
+ int ret;
+ struct acpi_apmt_node *apmt_node = cspmu->apmt_node;
+ struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
+ const struct impl_match *match = impl_match;
+
+ /*
+ * Get PMU implementer and product id from APMT node.
+ * If APMT node doesn't have implementer/product id, try get it
+ * from PMIIDR.
+ */
+ cspmu->impl.pmiidr =
+ (apmt_node->impl_id) ? apmt_node->impl_id :
+ readl(cspmu->base0 + PMIIDR);
+
+ /* Find implementer specific attribute ops. */
+ for (; match->pmiidr; match++) {
+ const u32 mask = match->mask;
+
+ if ((match->pmiidr & mask) == (cspmu->impl.pmiidr & mask)) {
+ ret = match->impl_init_ops(cspmu);
+ if (ret)
+ return ret;
+
+ break;
+ }
+ }
+
+ /* Use default callbacks if implementer doesn't provide one. */
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, get_event_attrs);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, get_format_attrs);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, get_identifier);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, get_name);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, is_cycle_counter_event);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, event_type);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, event_filter);
+ CHECK_DEFAULT_IMPL_OPS(impl_ops, event_attr_is_visible);
+
+ return 0;
+}
+
+static struct attribute_group *
+arm_cspmu_alloc_event_attr_group(struct arm_cspmu *cspmu)
+{
+ struct attribute_group *event_group;
+ struct device *dev = cspmu->dev;
+ const struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
+
+ event_group =
+ devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);
+ if (!event_group)
+ return NULL;
+
+ event_group->name = "events";
+ event_group->is_visible = impl_ops->event_attr_is_visible;
+ event_group->attrs = impl_ops->get_event_attrs(cspmu);
+
+ if (!event_group->attrs)
+ return NULL;
+
+ return event_group;
+}
+
+static struct attribute_group *
+arm_cspmu_alloc_format_attr_group(struct arm_cspmu *cspmu)
+{
+ struct attribute_group *format_group;
+ struct device *dev = cspmu->dev;
+
+ format_group =
+ devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);
+ if (!format_group)
+ return NULL;
+
+ format_group->name = "format";
+ format_group->attrs = cspmu->impl.ops.get_format_attrs(cspmu);
+
+ if (!format_group->attrs)
+ return NULL;
+
+ return format_group;
+}
+
+static struct attribute_group **
+arm_cspmu_alloc_attr_group(struct arm_cspmu *cspmu)
+{
+ struct attribute_group **attr_groups = NULL;
+ struct device *dev = cspmu->dev;
+ const struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
+ int ret;
+
+ ret = arm_cspmu_init_impl_ops(cspmu);
+ if (ret)
+ return NULL;
+
+ cspmu->identifier = impl_ops->get_identifier(cspmu);
+ cspmu->name = impl_ops->get_name(cspmu);
+
+ if (!cspmu->identifier || !cspmu->name)
+ return NULL;
+
+ attr_groups = devm_kcalloc(dev, 5, sizeof(struct attribute_group *),
+ GFP_KERNEL);
+ if (!attr_groups)
+ return NULL;
+
+ attr_groups[0] = arm_cspmu_alloc_event_attr_group(cspmu);
+ attr_groups[1] = arm_cspmu_alloc_format_attr_group(cspmu);
+ attr_groups[2] = &arm_cspmu_identifier_attr_group;
+ attr_groups[3] = &arm_cspmu_cpumask_attr_group;
+
+ if (!attr_groups[0] || !attr_groups[1])
+ return NULL;
+
+ return attr_groups;
+}
+
+static inline void arm_cspmu_reset_counters(struct arm_cspmu *cspmu)
+{
+ u32 pmcr = 0;
+
+ pmcr |= PMCR_P;
+ pmcr |= PMCR_C;
+ writel(pmcr, cspmu->base0 + PMCR);
+}
+
+static inline void arm_cspmu_start_counters(struct arm_cspmu *cspmu)
+{
+ writel(PMCR_E, cspmu->base0 + PMCR);
+}
+
+static inline void arm_cspmu_stop_counters(struct arm_cspmu *cspmu)
+{
+ writel(0, cspmu->base0 + PMCR);
+}
+
+static void arm_cspmu_enable(struct pmu *pmu)
+{
+ bool disabled;
+ struct arm_cspmu *cspmu = to_arm_cspmu(pmu);
+
+ disabled = bitmap_empty(cspmu->hw_events.used_ctrs,
+ cspmu->num_logical_ctrs);
+
+ if (disabled)
+ return;
+
+ arm_cspmu_start_counters(cspmu);
+}
+
+static void arm_cspmu_disable(struct pmu *pmu)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(pmu);
+
+ arm_cspmu_stop_counters(cspmu);
+}
+
+static int arm_cspmu_get_event_idx(struct arm_cspmu_hw_events *hw_events,
+ struct perf_event *event)
+{
+ int idx;
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+
+ if (supports_cycle_counter(cspmu)) {
+ if (cspmu->impl.ops.is_cycle_counter_event(event)) {
+ /* Search for available cycle counter. */
+ if (test_and_set_bit(cspmu->cycle_counter_logical_idx,
+ hw_events->used_ctrs))
+ return -EAGAIN;
+
+ return cspmu->cycle_counter_logical_idx;
+ }
+
+ /*
+ * Search a regular counter from the used counter bitmap.
+ * The cycle counter divides the bitmap into two parts. Search
+ * the first then second half to exclude the cycle counter bit.
+ */
+ idx = find_first_zero_bit(hw_events->used_ctrs,
+ cspmu->cycle_counter_logical_idx);
+ if (idx >= cspmu->cycle_counter_logical_idx) {
+ idx = find_next_zero_bit(
+ hw_events->used_ctrs,
+ cspmu->num_logical_ctrs,
+ cspmu->cycle_counter_logical_idx + 1);
+ }
+ } else {
+ idx = find_first_zero_bit(hw_events->used_ctrs,
+ cspmu->num_logical_ctrs);
+ }
+
+ if (idx >= cspmu->num_logical_ctrs)
+ return -EAGAIN;
+
+ set_bit(idx, hw_events->used_ctrs);
+
+ return idx;
+}
+
+static bool arm_cspmu_validate_event(struct pmu *pmu,
+ struct arm_cspmu_hw_events *hw_events,
+ struct perf_event *event)
+{
+ if (is_software_event(event))
+ return true;
+
+ /* Reject groups spanning multiple HW PMUs. */
+ if (event->pmu != pmu)
+ return false;
+
+ return (arm_cspmu_get_event_idx(hw_events, event) >= 0);
+}
+
+/*
+ * Make sure the group of events can be scheduled at once
+ * on the PMU.
+ */
+static bool arm_cspmu_validate_group(struct perf_event *event)
+{
+ struct perf_event *sibling, *leader = event->group_leader;
+ struct arm_cspmu_hw_events fake_hw_events;
+
+ if (event->group_leader == event)
+ return true;
+
+ memset(&fake_hw_events, 0, sizeof(fake_hw_events));
+
+ if (!arm_cspmu_validate_event(event->pmu, &fake_hw_events, leader))
+ return false;
+
+ for_each_sibling_event(sibling, leader) {
+ if (!arm_cspmu_validate_event(event->pmu, &fake_hw_events,
+ sibling))
+ return false;
+ }
+
+ return arm_cspmu_validate_event(event->pmu, &fake_hw_events, event);
+}
+
+static int arm_cspmu_event_init(struct perf_event *event)
+{
+ struct arm_cspmu *cspmu;
+ struct hw_perf_event *hwc = &event->hw;
+
+ cspmu = to_arm_cspmu(event->pmu);
+
+ /*
+ * Following other "uncore" PMUs, we do not support sampling mode or
+ * attach to a task (per-process mode).
+ */
+ if (is_sampling_event(event)) {
+ dev_dbg(cspmu->pmu.dev,
+ "Can't support sampling events\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) {
+ dev_dbg(cspmu->pmu.dev,
+ "Can't support per-task counters\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure the CPU assignment is on one of the CPUs associated with
+ * this PMU.
+ */
+ if (!cpumask_test_cpu(event->cpu, &cspmu->associated_cpus)) {
+ dev_dbg(cspmu->pmu.dev,
+ "Requested cpu is not associated with the PMU\n");
+ return -EINVAL;
+ }
+
+ /* Enforce the current active CPU to handle the events in this PMU. */
+ event->cpu = cpumask_first(&cspmu->active_cpu);
+ if (event->cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ if (!arm_cspmu_validate_group(event))
+ return -EINVAL;
+
+ /*
+ * The logical counter id is tracked with hw_perf_event.extra_reg.idx.
+ * The physical counter id is tracked with hw_perf_event.idx.
+ * We don't assign an index until we actually place the event onto
+ * hardware. Use -1 to signify that we haven't decided where to put it
+ * yet.
+ */
+ hwc->idx = -1;
+ hwc->extra_reg.idx = -1;
+ hwc->config = cspmu->impl.ops.event_type(event);
+
+ return 0;
+}
+
+static inline u32 counter_offset(u32 reg_sz, u32 ctr_idx)
+{
+ return (PMEVCNTR_LO + (reg_sz * ctr_idx));
+}
+
+static void arm_cspmu_write_counter(struct perf_event *event, u64 val)
+{
+ u32 offset;
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+
+ if (use_64b_counter_reg(cspmu)) {
+ offset = counter_offset(sizeof(u64), event->hw.idx);
+
+ writeq(val, cspmu->base1 + offset);
+ } else {
+ offset = counter_offset(sizeof(u32), event->hw.idx);
+
+ writel(lower_32_bits(val), cspmu->base1 + offset);
+ }
+}
+
+static u64 arm_cspmu_read_counter(struct perf_event *event)
+{
+ u32 offset;
+ const void __iomem *counter_addr;
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+
+ if (use_64b_counter_reg(cspmu)) {
+ offset = counter_offset(sizeof(u64), event->hw.idx);
+ counter_addr = cspmu->base1 + offset;
+
+ return supports_64bit_atomics(cspmu) ?
+ readq(counter_addr) :
+ read_reg64_hilohi(counter_addr, HILOHI_MAX_POLL);
+ }
+
+ offset = counter_offset(sizeof(u32), event->hw.idx);
+ return readl(cspmu->base1 + offset);
+}
+
+/*
+ * arm_cspmu_set_event_period: Set the period for the counter.
+ *
+ * To handle cases of extreme interrupt latency, we program
+ * the counter with half of the max count for the counters.
+ */
+static void arm_cspmu_set_event_period(struct perf_event *event)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ u64 val = counter_mask(cspmu) >> 1ULL;
+
+ local64_set(&event->hw.prev_count, val);
+ arm_cspmu_write_counter(event, val);
+}
+
+static void arm_cspmu_enable_counter(struct arm_cspmu *cspmu, int idx)
+{
+ u32 reg_id, reg_bit, inten_off, cnten_off;
+
+ reg_id = COUNTER_TO_SET_CLR_ID(idx);
+ reg_bit = COUNTER_TO_SET_CLR_BIT(idx);
+
+ inten_off = PMINTENSET + (4 * reg_id);
+ cnten_off = PMCNTENSET + (4 * reg_id);
+
+ writel(BIT(reg_bit), cspmu->base0 + inten_off);
+ writel(BIT(reg_bit), cspmu->base0 + cnten_off);
+}
+
+static void arm_cspmu_disable_counter(struct arm_cspmu *cspmu, int idx)
+{
+ u32 reg_id, reg_bit, inten_off, cnten_off;
+
+ reg_id = COUNTER_TO_SET_CLR_ID(idx);
+ reg_bit = COUNTER_TO_SET_CLR_BIT(idx);
+
+ inten_off = PMINTENCLR + (4 * reg_id);
+ cnten_off = PMCNTENCLR + (4 * reg_id);
+
+ writel(BIT(reg_bit), cspmu->base0 + cnten_off);
+ writel(BIT(reg_bit), cspmu->base0 + inten_off);
+}
+
+static void arm_cspmu_event_update(struct perf_event *event)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u64 delta, prev, now;
+
+ do {
+ prev = local64_read(&hwc->prev_count);
+ now = arm_cspmu_read_counter(event);
+ } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
+
+ delta = (now - prev) & counter_mask(cspmu);
+ local64_add(delta, &event->count);
+}
+
+static inline void arm_cspmu_set_event(struct arm_cspmu *cspmu,
+ struct hw_perf_event *hwc)
+{
+ u32 offset = PMEVTYPER + (4 * hwc->idx);
+
+ writel(hwc->config, cspmu->base0 + offset);
+}
+
+static inline void arm_cspmu_set_ev_filter(struct arm_cspmu *cspmu,
+ struct hw_perf_event *hwc,
+ u32 filter)
+{
+ u32 offset = PMEVFILTR + (4 * hwc->idx);
+
+ writel(filter, cspmu->base0 + offset);
+}
+
+static inline void arm_cspmu_set_cc_filter(struct arm_cspmu *cspmu, u32 filter)
+{
+ u32 offset = PMCCFILTR;
+
+ writel(filter, cspmu->base0 + offset);
+}
+
+static void arm_cspmu_start(struct perf_event *event, int pmu_flags)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 filter;
+
+ /* We always reprogram the counter */
+ if (pmu_flags & PERF_EF_RELOAD)
+ WARN_ON(!(hwc->state & PERF_HES_UPTODATE));
+
+ arm_cspmu_set_event_period(event);
+
+ filter = cspmu->impl.ops.event_filter(event);
+
+ if (event->hw.extra_reg.idx == cspmu->cycle_counter_logical_idx) {
+ arm_cspmu_set_cc_filter(cspmu, filter);
+ } else {
+ arm_cspmu_set_event(cspmu, hwc);
+ arm_cspmu_set_ev_filter(cspmu, hwc, filter);
+ }
+
+ hwc->state = 0;
+
+ arm_cspmu_enable_counter(cspmu, hwc->idx);
+}
+
+static void arm_cspmu_stop(struct perf_event *event, int pmu_flags)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (hwc->state & PERF_HES_STOPPED)
+ return;
+
+ arm_cspmu_disable_counter(cspmu, hwc->idx);
+ arm_cspmu_event_update(event);
+
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+}
+
+static inline u32 to_phys_idx(struct arm_cspmu *cspmu, u32 idx)
+{
+ return (idx == cspmu->cycle_counter_logical_idx) ?
+ ARM_CSPMU_CYCLE_CNTR_IDX : idx;
+}
+
+static int arm_cspmu_add(struct perf_event *event, int flags)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ struct arm_cspmu_hw_events *hw_events = &cspmu->hw_events;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ if (WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(),
+ &cspmu->associated_cpus)))
+ return -ENOENT;
+
+ idx = arm_cspmu_get_event_idx(hw_events, event);
+ if (idx < 0)
+ return idx;
+
+ hw_events->events[idx] = event;
+ hwc->idx = to_phys_idx(cspmu, idx);
+ hwc->extra_reg.idx = idx;
+ hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+ if (flags & PERF_EF_START)
+ arm_cspmu_start(event, PERF_EF_RELOAD);
+
+ /* Propagate changes to the userspace mapping. */
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+static void arm_cspmu_del(struct perf_event *event, int flags)
+{
+ struct arm_cspmu *cspmu = to_arm_cspmu(event->pmu);
+ struct arm_cspmu_hw_events *hw_events = &cspmu->hw_events;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->extra_reg.idx;
+
+ arm_cspmu_stop(event, PERF_EF_UPDATE);
+
+ hw_events->events[idx] = NULL;
+
+ clear_bit(idx, hw_events->used_ctrs);
+
+ perf_event_update_userpage(event);
+}
+
+static void arm_cspmu_read(struct perf_event *event)
+{
+ arm_cspmu_event_update(event);
+}
+
+static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev)
+{
+ struct acpi_apmt_node *apmt_node;
+ struct arm_cspmu *cspmu;
+ struct device *dev;
+
+ dev = &pdev->dev;
+ apmt_node = *(struct acpi_apmt_node **)dev_get_platdata(dev);
+ if (!apmt_node) {
+ dev_err(dev, "failed to get APMT node\n");
+ return NULL;
+ }
+
+ cspmu = devm_kzalloc(dev, sizeof(*cspmu), GFP_KERNEL);
+ if (!cspmu)
+ return NULL;
+
+ cspmu->dev = dev;
+ cspmu->apmt_node = apmt_node;
+
+ platform_set_drvdata(pdev, cspmu);
+
+ return cspmu;
+}
+
+static int arm_cspmu_init_mmio(struct arm_cspmu *cspmu)
+{
+ struct device *dev;
+ struct platform_device *pdev;
+ struct acpi_apmt_node *apmt_node;
+
+ dev = cspmu->dev;
+ pdev = to_platform_device(dev);
+ apmt_node = cspmu->apmt_node;
+
+ /* Base address for page 0. */
+ cspmu->base0 = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(cspmu->base0)) {
+ dev_err(dev, "ioremap failed for page-0 resource\n");
+ return PTR_ERR(cspmu->base0);
+ }
+
+ /* Base address for page 1 if supported. Otherwise point to page 0. */
+ cspmu->base1 = cspmu->base0;
+ if (CHECK_APMT_FLAG(apmt_node->flags, DUAL_PAGE, SUPP)) {
+ cspmu->base1 = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(cspmu->base1)) {
+ dev_err(dev, "ioremap failed for page-1 resource\n");
+ return PTR_ERR(cspmu->base1);
+ }
+ }
+
+ cspmu->pmcfgr = readl(cspmu->base0 + PMCFGR);
+
+ cspmu->num_logical_ctrs = FIELD_GET(PMCFGR_N, cspmu->pmcfgr) + 1;
+
+ cspmu->cycle_counter_logical_idx = ARM_CSPMU_MAX_HW_CNTRS;
+
+ if (supports_cycle_counter(cspmu)) {
+ /*
+ * The last logical counter is mapped to cycle counter if
+ * there is a gap between regular and cycle counter. Otherwise,
+ * logical and physical have 1-to-1 mapping.
+ */
+ cspmu->cycle_counter_logical_idx =
+ (cspmu->num_logical_ctrs <= ARM_CSPMU_CYCLE_CNTR_IDX) ?
+ cspmu->num_logical_ctrs - 1 :
+ ARM_CSPMU_CYCLE_CNTR_IDX;
+ }
+
+ cspmu->num_set_clr_reg =
+ DIV_ROUND_UP(cspmu->num_logical_ctrs,
+ ARM_CSPMU_SET_CLR_COUNTER_NUM);
+
+ cspmu->hw_events.events =
+ devm_kcalloc(dev, cspmu->num_logical_ctrs,
+ sizeof(*cspmu->hw_events.events), GFP_KERNEL);
+
+ if (!cspmu->hw_events.events)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static inline int arm_cspmu_get_reset_overflow(struct arm_cspmu *cspmu,
+ u32 *pmovs)
+{
+ int i;
+ u32 pmovclr_offset = PMOVSCLR;
+ u32 has_overflowed = 0;
+
+ for (i = 0; i < cspmu->num_set_clr_reg; ++i) {
+ pmovs[i] = readl(cspmu->base1 + pmovclr_offset);
+ has_overflowed |= pmovs[i];
+ writel(pmovs[i], cspmu->base1 + pmovclr_offset);
+ pmovclr_offset += sizeof(u32);
+ }
+
+ return has_overflowed != 0;
+}
+
+static irqreturn_t arm_cspmu_handle_irq(int irq_num, void *dev)
+{
+ int idx, has_overflowed;
+ struct perf_event *event;
+ struct arm_cspmu *cspmu = dev;
+ DECLARE_BITMAP(pmovs, ARM_CSPMU_MAX_HW_CNTRS);
+ bool handled = false;
+
+ arm_cspmu_stop_counters(cspmu);
+
+ has_overflowed = arm_cspmu_get_reset_overflow(cspmu, (u32 *)pmovs);
+ if (!has_overflowed)
+ goto done;
+
+ for_each_set_bit(idx, cspmu->hw_events.used_ctrs,
+ cspmu->num_logical_ctrs) {
+ event = cspmu->hw_events.events[idx];
+
+ if (!event)
+ continue;
+
+ if (!test_bit(event->hw.idx, pmovs))
+ continue;
+
+ arm_cspmu_event_update(event);
+ arm_cspmu_set_event_period(event);
+
+ handled = true;
+ }
+
+done:
+ arm_cspmu_start_counters(cspmu);
+ return IRQ_RETVAL(handled);
+}
+
+static int arm_cspmu_request_irq(struct arm_cspmu *cspmu)
+{
+ int irq, ret;
+ struct device *dev;
+ struct platform_device *pdev;
+ struct acpi_apmt_node *apmt_node;
+
+ dev = cspmu->dev;
+ pdev = to_platform_device(dev);
+ apmt_node = cspmu->apmt_node;
+
+ /* Skip IRQ request if the PMU does not support overflow interrupt. */
+ if (apmt_node->ovflw_irq == 0)
+ return 0;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, arm_cspmu_handle_irq,
+ IRQF_NOBALANCING | IRQF_NO_THREAD, dev_name(dev),
+ cspmu);
+ if (ret) {
+ dev_err(dev, "Could not request IRQ %d\n", irq);
+ return ret;
+ }
+
+ cspmu->irq = irq;
+
+ return 0;
+}
+
+static inline int arm_cspmu_find_cpu_container(int cpu, u32 container_uid)
+{
+ u32 acpi_uid;
+ struct device *cpu_dev = get_cpu_device(cpu);
+ struct acpi_device *acpi_dev = ACPI_COMPANION(cpu_dev);
+
+ if (!cpu_dev)
+ return -ENODEV;
+
+ while (acpi_dev) {
+ if (!strcmp(acpi_device_hid(acpi_dev),
+ ACPI_PROCESSOR_CONTAINER_HID) &&
+ !kstrtouint(acpi_device_uid(acpi_dev), 0, &acpi_uid) &&
+ acpi_uid == container_uid)
+ return 0;
+
+ acpi_dev = acpi_dev_parent(acpi_dev);
+ }
+
+ return -ENODEV;
+}
+
+static int arm_cspmu_get_cpus(struct arm_cspmu *cspmu)
+{
+ struct device *dev;
+ struct acpi_apmt_node *apmt_node;
+ int affinity_flag;
+ int cpu;
+
+ dev = cspmu->pmu.dev;
+ apmt_node = cspmu->apmt_node;
+ affinity_flag = apmt_node->flags & ACPI_APMT_FLAGS_AFFINITY;
+
+ if (affinity_flag == ACPI_APMT_FLAGS_AFFINITY_PROC) {
+ for_each_possible_cpu(cpu) {
+ if (apmt_node->proc_affinity ==
+ get_acpi_id_for_cpu(cpu)) {
+ cpumask_set_cpu(cpu, &cspmu->associated_cpus);
+ break;
+ }
+ }
+ } else {
+ for_each_possible_cpu(cpu) {
+ if (arm_cspmu_find_cpu_container(
+ cpu, apmt_node->proc_affinity))
+ continue;
+
+ cpumask_set_cpu(cpu, &cspmu->associated_cpus);
+ }
+ }
+
+ if (cpumask_empty(&cspmu->associated_cpus)) {
+ dev_dbg(dev, "No cpu associated with the PMU\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu)
+{
+ int ret, capabilities;
+ struct attribute_group **attr_groups;
+
+ attr_groups = arm_cspmu_alloc_attr_group(cspmu);
+ if (!attr_groups)
+ return -ENOMEM;
+
+ ret = cpuhp_state_add_instance(arm_cspmu_cpuhp_state,
+ &cspmu->cpuhp_node);
+ if (ret)
+ return ret;
+
+ capabilities = PERF_PMU_CAP_NO_EXCLUDE;
+ if (cspmu->irq == 0)
+ capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+
+ cspmu->pmu = (struct pmu){
+ .task_ctx_nr = perf_invalid_context,
+ .module = THIS_MODULE,
+ .pmu_enable = arm_cspmu_enable,
+ .pmu_disable = arm_cspmu_disable,
+ .event_init = arm_cspmu_event_init,
+ .add = arm_cspmu_add,
+ .del = arm_cspmu_del,
+ .start = arm_cspmu_start,
+ .stop = arm_cspmu_stop,
+ .read = arm_cspmu_read,
+ .attr_groups = (const struct attribute_group **)attr_groups,
+ .capabilities = capabilities,
+ };
+
+ /* Hardware counter init */
+ arm_cspmu_stop_counters(cspmu);
+ arm_cspmu_reset_counters(cspmu);
+
+ ret = perf_pmu_register(&cspmu->pmu, cspmu->name, -1);
+ if (ret) {
+ cpuhp_state_remove_instance(arm_cspmu_cpuhp_state,
+ &cspmu->cpuhp_node);
+ }
+
+ return ret;
+}
+
+static int arm_cspmu_device_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct arm_cspmu *cspmu;
+
+ cspmu = arm_cspmu_alloc(pdev);
+ if (!cspmu)
+ return -ENOMEM;
+
+ ret = arm_cspmu_init_mmio(cspmu);
+ if (ret)
+ return ret;
+
+ ret = arm_cspmu_request_irq(cspmu);
+ if (ret)
+ return ret;
+
+ ret = arm_cspmu_get_cpus(cspmu);
+ if (ret)
+ return ret;
+
+ ret = arm_cspmu_register_pmu(cspmu);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int arm_cspmu_device_remove(struct platform_device *pdev)
+{
+ struct arm_cspmu *cspmu = platform_get_drvdata(pdev);
+
+ perf_pmu_unregister(&cspmu->pmu);
+ cpuhp_state_remove_instance(arm_cspmu_cpuhp_state, &cspmu->cpuhp_node);
+
+ return 0;
+}
+
+static struct platform_driver arm_cspmu_driver = {
+ .driver = {
+ .name = DRVNAME,
+ .suppress_bind_attrs = true,
+ },
+ .probe = arm_cspmu_device_probe,
+ .remove = arm_cspmu_device_remove,
+};
+
+static void arm_cspmu_set_active_cpu(int cpu, struct arm_cspmu *cspmu)
+{
+ cpumask_set_cpu(cpu, &cspmu->active_cpu);
+ WARN_ON(irq_set_affinity(cspmu->irq, &cspmu->active_cpu));
+}
+
+static int arm_cspmu_cpu_online(unsigned int cpu, struct hlist_node *node)
+{
+ struct arm_cspmu *cspmu =
+ hlist_entry_safe(node, struct arm_cspmu, cpuhp_node);
+
+ if (!cpumask_test_cpu(cpu, &cspmu->associated_cpus))
+ return 0;
+
+ /* If the PMU is already managed, there is nothing to do */
+ if (!cpumask_empty(&cspmu->active_cpu))
+ return 0;
+
+ /* Use this CPU for event counting */
+ arm_cspmu_set_active_cpu(cpu, cspmu);
+
+ return 0;
+}
+
+static int arm_cspmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
+{
+ int dst;
+ struct cpumask online_supported;
+
+ struct arm_cspmu *cspmu =
+ hlist_entry_safe(node, struct arm_cspmu, cpuhp_node);
+
+ /* Nothing to do if this CPU doesn't own the PMU */
+ if (!cpumask_test_and_clear_cpu(cpu, &cspmu->active_cpu))
+ return 0;
+
+ /* Choose a new CPU to migrate ownership of the PMU to */
+ cpumask_and(&online_supported, &cspmu->associated_cpus,
+ cpu_online_mask);
+ dst = cpumask_any_but(&online_supported, cpu);
+ if (dst >= nr_cpu_ids)
+ return 0;
+
+ /* Use this CPU for event counting */
+ perf_pmu_migrate_context(&cspmu->pmu, cpu, dst);
+ arm_cspmu_set_active_cpu(dst, cspmu);
+
+ return 0;
+}
+
+static int __init arm_cspmu_init(void)
+{
+ int ret;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ "perf/arm/cspmu:online",
+ arm_cspmu_cpu_online,
+ arm_cspmu_cpu_teardown);
+ if (ret < 0)
+ return ret;
+ arm_cspmu_cpuhp_state = ret;
+ return platform_driver_register(&arm_cspmu_driver);
+}
+
+static void __exit arm_cspmu_exit(void)
+{
+ platform_driver_unregister(&arm_cspmu_driver);
+ cpuhp_remove_multi_state(arm_cspmu_cpuhp_state);
+}
+
+module_init(arm_cspmu_init);
+module_exit(arm_cspmu_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/perf/arm_cspmu/arm_cspmu.h b/drivers/perf/arm_cspmu/arm_cspmu.h
new file mode 100644
index 000000000000..51323b175a4a
--- /dev/null
+++ b/drivers/perf/arm_cspmu/arm_cspmu.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * ARM CoreSight Architecture PMU driver.
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ */
+
+#ifndef __ARM_CSPMU_H__
+#define __ARM_CSPMU_H__
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define to_arm_cspmu(p) (container_of(p, struct arm_cspmu, pmu))
+
+#define ARM_CSPMU_EXT_ATTR(_name, _func, _config) \
+ (&((struct dev_ext_attribute[]){ \
+ { \
+ .attr = __ATTR(_name, 0444, _func, NULL), \
+ .var = (void *)_config \
+ } \
+ })[0].attr.attr)
+
+#define ARM_CSPMU_FORMAT_ATTR(_name, _config) \
+ ARM_CSPMU_EXT_ATTR(_name, arm_cspmu_sysfs_format_show, (char *)_config)
+
+#define ARM_CSPMU_EVENT_ATTR(_name, _config) \
+ PMU_EVENT_ATTR_ID(_name, arm_cspmu_sysfs_event_show, _config)
+
+
+/* Default event id mask */
+#define ARM_CSPMU_EVENT_MASK GENMASK_ULL(63, 0)
+
+/* Default filter value mask */
+#define ARM_CSPMU_FILTER_MASK GENMASK_ULL(63, 0)
+
+/* Default event format */
+#define ARM_CSPMU_FORMAT_EVENT_ATTR \
+ ARM_CSPMU_FORMAT_ATTR(event, "config:0-32")
+
+/* Default filter format */
+#define ARM_CSPMU_FORMAT_FILTER_ATTR \
+ ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31")
+
+/*
+ * This is the default event number for cycle count, if supported, since the
+ * ARM Coresight PMU specification does not define a standard event code
+ * for cycle count.
+ */
+#define ARM_CSPMU_EVT_CYCLES_DEFAULT (0x1ULL << 32)
+
+/*
+ * The ARM Coresight PMU supports up to 256 event counters.
+ * If the counters are larger-than 32-bits, then the PMU includes at
+ * most 128 counters.
+ */
+#define ARM_CSPMU_MAX_HW_CNTRS 256
+
+/* The cycle counter, if implemented, is located at counter[31]. */
+#define ARM_CSPMU_CYCLE_CNTR_IDX 31
+
+/* PMIIDR register field */
+#define ARM_CSPMU_PMIIDR_IMPLEMENTER GENMASK(11, 0)
+#define ARM_CSPMU_PMIIDR_PRODUCTID GENMASK(31, 20)
+
+struct arm_cspmu;
+
+/* This tracks the events assigned to each counter in the PMU. */
+struct arm_cspmu_hw_events {
+ /* The events that are active on the PMU for a given logical index. */
+ struct perf_event **events;
+
+ /*
+ * Each bit indicates a logical counter is being used (or not) for an
+ * event. If cycle counter is supported and there is a gap between
+ * regular and cycle counter, the last logical counter is mapped to
+ * cycle counter. Otherwise, logical and physical have 1-to-1 mapping.
+ */
+ DECLARE_BITMAP(used_ctrs, ARM_CSPMU_MAX_HW_CNTRS);
+};
+
+/* Contains ops to query vendor/implementer specific attribute. */
+struct arm_cspmu_impl_ops {
+ /* Get event attributes */
+ struct attribute **(*get_event_attrs)(const struct arm_cspmu *cspmu);
+ /* Get format attributes */
+ struct attribute **(*get_format_attrs)(const struct arm_cspmu *cspmu);
+ /* Get string identifier */
+ const char *(*get_identifier)(const struct arm_cspmu *cspmu);
+ /* Get PMU name to register to core perf */
+ const char *(*get_name)(const struct arm_cspmu *cspmu);
+ /* Check if the event corresponds to cycle count event */
+ bool (*is_cycle_counter_event)(const struct perf_event *event);
+ /* Decode event type/id from configs */
+ u32 (*event_type)(const struct perf_event *event);
+ /* Decode filter value from configs */
+ u32 (*event_filter)(const struct perf_event *event);
+ /* Hide/show unsupported events */
+ umode_t (*event_attr_is_visible)(struct kobject *kobj,
+ struct attribute *attr, int unused);
+};
+
+/* Vendor/implementer descriptor. */
+struct arm_cspmu_impl {
+ u32 pmiidr;
+ struct arm_cspmu_impl_ops ops;
+ void *ctx;
+};
+
+/* Coresight PMU descriptor. */
+struct arm_cspmu {
+ struct pmu pmu;
+ struct device *dev;
+ struct acpi_apmt_node *apmt_node;
+ const char *name;
+ const char *identifier;
+ void __iomem *base0;
+ void __iomem *base1;
+ int irq;
+ cpumask_t associated_cpus;
+ cpumask_t active_cpu;
+ struct hlist_node cpuhp_node;
+
+ u32 pmcfgr;
+ u32 num_logical_ctrs;
+ u32 num_set_clr_reg;
+ int cycle_counter_logical_idx;
+
+ struct arm_cspmu_hw_events hw_events;
+
+ struct arm_cspmu_impl impl;
+};
+
+/* Default function to show event attribute in sysfs. */
+ssize_t arm_cspmu_sysfs_event_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+/* Default function to show format attribute in sysfs. */
+ssize_t arm_cspmu_sysfs_format_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+#endif /* __ARM_CSPMU_H__ */
diff --git a/drivers/perf/arm_cspmu/nvidia_cspmu.c b/drivers/perf/arm_cspmu/nvidia_cspmu.c
new file mode 100644
index 000000000000..72ef80caa3c8
--- /dev/null
+++ b/drivers/perf/arm_cspmu/nvidia_cspmu.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ */
+
+/* Support for NVIDIA specific attributes. */
+
+#include <linux/topology.h>
+
+#include "nvidia_cspmu.h"
+
+#define NV_PCIE_PORT_COUNT 10ULL
+#define NV_PCIE_FILTER_ID_MASK GENMASK_ULL(NV_PCIE_PORT_COUNT - 1, 0)
+
+#define NV_NVL_C2C_PORT_COUNT 2ULL
+#define NV_NVL_C2C_FILTER_ID_MASK GENMASK_ULL(NV_NVL_C2C_PORT_COUNT - 1, 0)
+
+#define NV_CNVL_PORT_COUNT 4ULL
+#define NV_CNVL_FILTER_ID_MASK GENMASK_ULL(NV_CNVL_PORT_COUNT - 1, 0)
+
+#define NV_GENERIC_FILTER_ID_MASK GENMASK_ULL(31, 0)
+
+#define NV_PRODID_MASK GENMASK(31, 0)
+
+#define NV_FORMAT_NAME_GENERIC 0
+
+#define to_nv_cspmu_ctx(cspmu) ((struct nv_cspmu_ctx *)(cspmu->impl.ctx))
+
+#define NV_CSPMU_EVENT_ATTR_4_INNER(_pref, _num, _suff, _config) \
+ ARM_CSPMU_EVENT_ATTR(_pref##_num##_suff, _config)
+
+#define NV_CSPMU_EVENT_ATTR_4(_pref, _suff, _config) \
+ NV_CSPMU_EVENT_ATTR_4_INNER(_pref, _0_, _suff, _config), \
+ NV_CSPMU_EVENT_ATTR_4_INNER(_pref, _1_, _suff, _config + 1), \
+ NV_CSPMU_EVENT_ATTR_4_INNER(_pref, _2_, _suff, _config + 2), \
+ NV_CSPMU_EVENT_ATTR_4_INNER(_pref, _3_, _suff, _config + 3)
+
+struct nv_cspmu_ctx {
+ const char *name;
+ u32 filter_mask;
+ u32 filter_default_val;
+ struct attribute **event_attr;
+ struct attribute **format_attr;
+};
+
+static struct attribute *scf_pmu_event_attrs[] = {
+ ARM_CSPMU_EVENT_ATTR(bus_cycles, 0x1d),
+
+ ARM_CSPMU_EVENT_ATTR(scf_cache_allocate, 0xF0),
+ ARM_CSPMU_EVENT_ATTR(scf_cache_refill, 0xF1),
+ ARM_CSPMU_EVENT_ATTR(scf_cache, 0xF2),
+ ARM_CSPMU_EVENT_ATTR(scf_cache_wb, 0xF3),
+
+ NV_CSPMU_EVENT_ATTR_4(socket, rd_data, 0x101),
+ NV_CSPMU_EVENT_ATTR_4(socket, dl_rsp, 0x105),
+ NV_CSPMU_EVENT_ATTR_4(socket, wb_data, 0x109),
+ NV_CSPMU_EVENT_ATTR_4(socket, ev_rsp, 0x10d),
+ NV_CSPMU_EVENT_ATTR_4(socket, prb_data, 0x111),
+
+ NV_CSPMU_EVENT_ATTR_4(socket, rd_outstanding, 0x115),
+ NV_CSPMU_EVENT_ATTR_4(socket, dl_outstanding, 0x119),
+ NV_CSPMU_EVENT_ATTR_4(socket, wb_outstanding, 0x11d),
+ NV_CSPMU_EVENT_ATTR_4(socket, wr_outstanding, 0x121),
+ NV_CSPMU_EVENT_ATTR_4(socket, ev_outstanding, 0x125),
+ NV_CSPMU_EVENT_ATTR_4(socket, prb_outstanding, 0x129),
+
+ NV_CSPMU_EVENT_ATTR_4(socket, rd_access, 0x12d),
+ NV_CSPMU_EVENT_ATTR_4(socket, dl_access, 0x131),
+ NV_CSPMU_EVENT_ATTR_4(socket, wb_access, 0x135),
+ NV_CSPMU_EVENT_ATTR_4(socket, wr_access, 0x139),
+ NV_CSPMU_EVENT_ATTR_4(socket, ev_access, 0x13d),
+ NV_CSPMU_EVENT_ATTR_4(socket, prb_access, 0x141),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_data, 0x145),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_access, 0x149),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_access, 0x14d),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_outstanding, 0x151),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_outstanding, 0x155),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_data, 0x159),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_access, 0x15d),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_access, 0x161),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_outstanding, 0x165),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_outstanding, 0x169),
+
+ ARM_CSPMU_EVENT_ATTR(gmem_rd_data, 0x16d),
+ ARM_CSPMU_EVENT_ATTR(gmem_rd_access, 0x16e),
+ ARM_CSPMU_EVENT_ATTR(gmem_rd_outstanding, 0x16f),
+ ARM_CSPMU_EVENT_ATTR(gmem_dl_rsp, 0x170),
+ ARM_CSPMU_EVENT_ATTR(gmem_dl_access, 0x171),
+ ARM_CSPMU_EVENT_ATTR(gmem_dl_outstanding, 0x172),
+ ARM_CSPMU_EVENT_ATTR(gmem_wb_data, 0x173),
+ ARM_CSPMU_EVENT_ATTR(gmem_wb_access, 0x174),
+ ARM_CSPMU_EVENT_ATTR(gmem_wb_outstanding, 0x175),
+ ARM_CSPMU_EVENT_ATTR(gmem_ev_rsp, 0x176),
+ ARM_CSPMU_EVENT_ATTR(gmem_ev_access, 0x177),
+ ARM_CSPMU_EVENT_ATTR(gmem_ev_outstanding, 0x178),
+ ARM_CSPMU_EVENT_ATTR(gmem_wr_data, 0x179),
+ ARM_CSPMU_EVENT_ATTR(gmem_wr_outstanding, 0x17a),
+ ARM_CSPMU_EVENT_ATTR(gmem_wr_access, 0x17b),
+
+ NV_CSPMU_EVENT_ATTR_4(socket, wr_data, 0x17c),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_data, 0x180),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_data, 0x184),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_access, 0x188),
+ NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_outstanding, 0x18c),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_data, 0x190),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_data, 0x194),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_access, 0x198),
+ NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_outstanding, 0x19c),
+
+ ARM_CSPMU_EVENT_ATTR(gmem_wr_total_bytes, 0x1a0),
+ ARM_CSPMU_EVENT_ATTR(remote_socket_wr_total_bytes, 0x1a1),
+ ARM_CSPMU_EVENT_ATTR(remote_socket_rd_data, 0x1a2),
+ ARM_CSPMU_EVENT_ATTR(remote_socket_rd_outstanding, 0x1a3),
+ ARM_CSPMU_EVENT_ATTR(remote_socket_rd_access, 0x1a4),
+
+ ARM_CSPMU_EVENT_ATTR(cmem_rd_data, 0x1a5),
+ ARM_CSPMU_EVENT_ATTR(cmem_rd_access, 0x1a6),
+ ARM_CSPMU_EVENT_ATTR(cmem_rd_outstanding, 0x1a7),
+ ARM_CSPMU_EVENT_ATTR(cmem_dl_rsp, 0x1a8),
+ ARM_CSPMU_EVENT_ATTR(cmem_dl_access, 0x1a9),
+ ARM_CSPMU_EVENT_ATTR(cmem_dl_outstanding, 0x1aa),
+ ARM_CSPMU_EVENT_ATTR(cmem_wb_data, 0x1ab),
+ ARM_CSPMU_EVENT_ATTR(cmem_wb_access, 0x1ac),
+ ARM_CSPMU_EVENT_ATTR(cmem_wb_outstanding, 0x1ad),
+ ARM_CSPMU_EVENT_ATTR(cmem_ev_rsp, 0x1ae),
+ ARM_CSPMU_EVENT_ATTR(cmem_ev_access, 0x1af),
+ ARM_CSPMU_EVENT_ATTR(cmem_ev_outstanding, 0x1b0),
+ ARM_CSPMU_EVENT_ATTR(cmem_wr_data, 0x1b1),
+ ARM_CSPMU_EVENT_ATTR(cmem_wr_outstanding, 0x1b2),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_data, 0x1b3),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_access, 0x1b7),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_access, 0x1bb),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_outstanding, 0x1bf),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_outstanding, 0x1c3),
+
+ ARM_CSPMU_EVENT_ATTR(ocu_prb_access, 0x1c7),
+ ARM_CSPMU_EVENT_ATTR(ocu_prb_data, 0x1c8),
+ ARM_CSPMU_EVENT_ATTR(ocu_prb_outstanding, 0x1c9),
+
+ ARM_CSPMU_EVENT_ATTR(cmem_wr_access, 0x1ca),
+
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_access, 0x1cb),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_data, 0x1cf),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_data, 0x1d3),
+ NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_outstanding, 0x1d7),
+
+ ARM_CSPMU_EVENT_ATTR(cmem_wr_total_bytes, 0x1db),
+
+ ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
+ NULL,
+};
+
+static struct attribute *mcf_pmu_event_attrs[] = {
+ ARM_CSPMU_EVENT_ATTR(rd_bytes_loc, 0x0),
+ ARM_CSPMU_EVENT_ATTR(rd_bytes_rem, 0x1),
+ ARM_CSPMU_EVENT_ATTR(wr_bytes_loc, 0x2),
+ ARM_CSPMU_EVENT_ATTR(wr_bytes_rem, 0x3),
+ ARM_CSPMU_EVENT_ATTR(total_bytes_loc, 0x4),
+ ARM_CSPMU_EVENT_ATTR(total_bytes_rem, 0x5),
+ ARM_CSPMU_EVENT_ATTR(rd_req_loc, 0x6),
+ ARM_CSPMU_EVENT_ATTR(rd_req_rem, 0x7),
+ ARM_CSPMU_EVENT_ATTR(wr_req_loc, 0x8),
+ ARM_CSPMU_EVENT_ATTR(wr_req_rem, 0x9),
+ ARM_CSPMU_EVENT_ATTR(total_req_loc, 0xa),
+ ARM_CSPMU_EVENT_ATTR(total_req_rem, 0xb),
+ ARM_CSPMU_EVENT_ATTR(rd_cum_outs_loc, 0xc),
+ ARM_CSPMU_EVENT_ATTR(rd_cum_outs_rem, 0xd),
+ ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
+ NULL,
+};
+
+static struct attribute *generic_pmu_event_attrs[] = {
+ ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
+ NULL,
+};
+
+static struct attribute *scf_pmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ NULL,
+};
+
+static struct attribute *pcie_pmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ ARM_CSPMU_FORMAT_ATTR(root_port, "config1:0-9"),
+ NULL,
+};
+
+static struct attribute *nvlink_c2c_pmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ NULL,
+};
+
+static struct attribute *cnvlink_pmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ ARM_CSPMU_FORMAT_ATTR(rem_socket, "config1:0-3"),
+ NULL,
+};
+
+static struct attribute *generic_pmu_format_attrs[] = {
+ ARM_CSPMU_FORMAT_EVENT_ATTR,
+ ARM_CSPMU_FORMAT_FILTER_ATTR,
+ NULL,
+};
+
+static struct attribute **
+nv_cspmu_get_event_attrs(const struct arm_cspmu *cspmu)
+{
+ const struct nv_cspmu_ctx *ctx = to_nv_cspmu_ctx(cspmu);
+
+ return ctx->event_attr;
+}
+
+static struct attribute **
+nv_cspmu_get_format_attrs(const struct arm_cspmu *cspmu)
+{
+ const struct nv_cspmu_ctx *ctx = to_nv_cspmu_ctx(cspmu);
+
+ return ctx->format_attr;
+}
+
+static const char *
+nv_cspmu_get_name(const struct arm_cspmu *cspmu)
+{
+ const struct nv_cspmu_ctx *ctx = to_nv_cspmu_ctx(cspmu);
+
+ return ctx->name;
+}
+
+static u32 nv_cspmu_event_filter(const struct perf_event *event)
+{
+ const struct nv_cspmu_ctx *ctx =
+ to_nv_cspmu_ctx(to_arm_cspmu(event->pmu));
+
+ if (ctx->filter_mask == 0)
+ return ctx->filter_default_val;
+
+ return event->attr.config1 & ctx->filter_mask;
+}
+
+enum nv_cspmu_name_fmt {
+ NAME_FMT_GENERIC,
+ NAME_FMT_SOCKET
+};
+
+struct nv_cspmu_match {
+ u32 prodid;
+ u32 prodid_mask;
+ u64 filter_mask;
+ u32 filter_default_val;
+ const char *name_pattern;
+ enum nv_cspmu_name_fmt name_fmt;
+ struct attribute **event_attr;
+ struct attribute **format_attr;
+};
+
+static const struct nv_cspmu_match nv_cspmu_match[] = {
+ {
+ .prodid = 0x103,
+ .prodid_mask = NV_PRODID_MASK,
+ .filter_mask = NV_PCIE_FILTER_ID_MASK,
+ .filter_default_val = NV_PCIE_FILTER_ID_MASK,
+ .name_pattern = "nvidia_pcie_pmu_%u",
+ .name_fmt = NAME_FMT_SOCKET,
+ .event_attr = mcf_pmu_event_attrs,
+ .format_attr = pcie_pmu_format_attrs
+ },
+ {
+ .prodid = 0x104,
+ .prodid_mask = NV_PRODID_MASK,
+ .filter_mask = 0x0,
+ .filter_default_val = NV_NVL_C2C_FILTER_ID_MASK,
+ .name_pattern = "nvidia_nvlink_c2c1_pmu_%u",
+ .name_fmt = NAME_FMT_SOCKET,
+ .event_attr = mcf_pmu_event_attrs,
+ .format_attr = nvlink_c2c_pmu_format_attrs
+ },
+ {
+ .prodid = 0x105,
+ .prodid_mask = NV_PRODID_MASK,
+ .filter_mask = 0x0,
+ .filter_default_val = NV_NVL_C2C_FILTER_ID_MASK,
+ .name_pattern = "nvidia_nvlink_c2c0_pmu_%u",
+ .name_fmt = NAME_FMT_SOCKET,
+ .event_attr = mcf_pmu_event_attrs,
+ .format_attr = nvlink_c2c_pmu_format_attrs
+ },
+ {
+ .prodid = 0x106,
+ .prodid_mask = NV_PRODID_MASK,
+ .filter_mask = NV_CNVL_FILTER_ID_MASK,
+ .filter_default_val = NV_CNVL_FILTER_ID_MASK,
+ .name_pattern = "nvidia_cnvlink_pmu_%u",
+ .name_fmt = NAME_FMT_SOCKET,
+ .event_attr = mcf_pmu_event_attrs,
+ .format_attr = cnvlink_pmu_format_attrs
+ },
+ {
+ .prodid = 0x2CF,
+ .prodid_mask = NV_PRODID_MASK,
+ .filter_mask = 0x0,
+ .filter_default_val = 0x0,
+ .name_pattern = "nvidia_scf_pmu_%u",
+ .name_fmt = NAME_FMT_SOCKET,
+ .event_attr = scf_pmu_event_attrs,
+ .format_attr = scf_pmu_format_attrs
+ },
+ {
+ .prodid = 0,
+ .prodid_mask = 0,
+ .filter_mask = NV_GENERIC_FILTER_ID_MASK,
+ .filter_default_val = NV_GENERIC_FILTER_ID_MASK,
+ .name_pattern = "nvidia_uncore_pmu_%u",
+ .name_fmt = NAME_FMT_GENERIC,
+ .event_attr = generic_pmu_event_attrs,
+ .format_attr = generic_pmu_format_attrs
+ },
+};
+
+static char *nv_cspmu_format_name(const struct arm_cspmu *cspmu,
+ const struct nv_cspmu_match *match)
+{
+ char *name;
+ struct device *dev = cspmu->dev;
+
+ static atomic_t pmu_generic_idx = {0};
+
+ switch (match->name_fmt) {
+ case NAME_FMT_SOCKET: {
+ const int cpu = cpumask_first(&cspmu->associated_cpus);
+ const int socket = cpu_to_node(cpu);
+
+ name = devm_kasprintf(dev, GFP_KERNEL, match->name_pattern,
+ socket);
+ break;
+ }
+ case NAME_FMT_GENERIC:
+ name = devm_kasprintf(dev, GFP_KERNEL, match->name_pattern,
+ atomic_fetch_inc(&pmu_generic_idx));
+ break;
+ default:
+ name = NULL;
+ break;
+ }
+
+ return name;
+}
+
+int nv_cspmu_init_ops(struct arm_cspmu *cspmu)
+{
+ u32 prodid;
+ struct nv_cspmu_ctx *ctx;
+ struct device *dev = cspmu->dev;
+ struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
+ const struct nv_cspmu_match *match = nv_cspmu_match;
+
+ ctx = devm_kzalloc(dev, sizeof(struct nv_cspmu_ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ prodid = FIELD_GET(ARM_CSPMU_PMIIDR_PRODUCTID, cspmu->impl.pmiidr);
+
+ /* Find matching PMU. */
+ for (; match->prodid; match++) {
+ const u32 prodid_mask = match->prodid_mask;
+
+ if ((match->prodid & prodid_mask) == (prodid & prodid_mask))
+ break;
+ }
+
+ ctx->name = nv_cspmu_format_name(cspmu, match);
+ ctx->filter_mask = match->filter_mask;
+ ctx->filter_default_val = match->filter_default_val;
+ ctx->event_attr = match->event_attr;
+ ctx->format_attr = match->format_attr;
+
+ cspmu->impl.ctx = ctx;
+
+ /* NVIDIA specific callbacks. */
+ impl_ops->event_filter = nv_cspmu_event_filter;
+ impl_ops->get_event_attrs = nv_cspmu_get_event_attrs;
+ impl_ops->get_format_attrs = nv_cspmu_get_format_attrs;
+ impl_ops->get_name = nv_cspmu_get_name;
+
+ /* Set others to NULL to use default callback. */
+ impl_ops->event_type = NULL;
+ impl_ops->event_attr_is_visible = NULL;
+ impl_ops->get_identifier = NULL;
+ impl_ops->is_cycle_counter_event = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nv_cspmu_init_ops);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/perf/arm_cspmu/nvidia_cspmu.h b/drivers/perf/arm_cspmu/nvidia_cspmu.h
new file mode 100644
index 000000000000..71e18f0dc50b
--- /dev/null
+++ b/drivers/perf/arm_cspmu/nvidia_cspmu.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ */
+
+/* Support for NVIDIA specific attributes. */
+
+#ifndef __NVIDIA_CSPMU_H__
+#define __NVIDIA_CSPMU_H__
+
+#include "arm_cspmu.h"
+
+/* Allocate NVIDIA descriptor. */
+int nv_cspmu_init_ops(struct arm_cspmu *cspmu);
+
+#endif /* __NVIDIA_CSPMU_H__ */
diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c
index 280a6ae3e27c..54aa4658fb36 100644
--- a/drivers/perf/arm_dmc620_pmu.c
+++ b/drivers/perf/arm_dmc620_pmu.c
@@ -725,6 +725,8 @@ static struct platform_driver dmc620_pmu_driver = {
static int __init dmc620_pmu_init(void)
{
+ int ret;
+
cpuhp_state_num = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
DMC620_DRVNAME,
NULL,
@@ -732,7 +734,11 @@ static int __init dmc620_pmu_init(void)
if (cpuhp_state_num < 0)
return cpuhp_state_num;
- return platform_driver_register(&dmc620_pmu_driver);
+ ret = platform_driver_register(&dmc620_pmu_driver);
+ if (ret)
+ cpuhp_remove_multi_state(cpuhp_state_num);
+
+ return ret;
}
static void __exit dmc620_pmu_exit(void)
diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index 4a15c86f45ef..fe2abb412c00 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -858,7 +858,11 @@ static int __init dsu_pmu_init(void)
if (ret < 0)
return ret;
dsu_pmu_cpuhp_state = ret;
- return platform_driver_register(&dsu_pmu_driver);
+ ret = platform_driver_register(&dsu_pmu_driver);
+ if (ret)
+ cpuhp_remove_multi_state(dsu_pmu_cpuhp_state);
+
+ return ret;
}
static void __exit dsu_pmu_exit(void)
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 3f07df5a7e95..9b593f985805 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -514,9 +514,6 @@ static int armpmu_event_init(struct perf_event *event)
if (has_branch_stack(event))
return -EOPNOTSUPP;
- if (armpmu->map_event(event) == -ENOENT)
- return -ENOENT;
-
return __hw_perf_event_init(event);
}
@@ -550,15 +547,14 @@ static void armpmu_disable(struct pmu *pmu)
* microarchitecture, and aren't suitable for another. Thus, only match CPUs of
* the same microarchitecture.
*/
-static int armpmu_filter_match(struct perf_event *event)
+static bool armpmu_filter(struct pmu *pmu, int cpu)
{
- struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
- unsigned int cpu = smp_processor_id();
- int ret;
+ struct arm_pmu *armpmu = to_arm_pmu(pmu);
+ bool ret;
ret = cpumask_test_cpu(cpu, &armpmu->supported_cpus);
- if (ret && armpmu->filter_match)
- return armpmu->filter_match(event);
+ if (ret && armpmu->filter)
+ return armpmu->filter(pmu, cpu);
return ret;
}
@@ -861,16 +857,16 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
&cpu_pmu->node);
}
-static struct arm_pmu *__armpmu_alloc(gfp_t flags)
+struct arm_pmu *armpmu_alloc(void)
{
struct arm_pmu *pmu;
int cpu;
- pmu = kzalloc(sizeof(*pmu), flags);
+ pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
if (!pmu)
goto out;
- pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
+ pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, GFP_KERNEL);
if (!pmu->hw_events) {
pr_info("failed to allocate per-cpu PMU data.\n");
goto out_free_pmu;
@@ -885,14 +881,13 @@ static struct arm_pmu *__armpmu_alloc(gfp_t flags)
.start = armpmu_start,
.stop = armpmu_stop,
.read = armpmu_read,
- .filter_match = armpmu_filter_match,
+ .filter = armpmu_filter,
.attr_groups = pmu->attr_groups,
/*
* This is a CPU PMU potentially in a heterogeneous
* configuration (e.g. big.LITTLE). This is not an uncore PMU,
* and we have taken ctx sharing into account (e.g. with our
- * pmu::filter_match callback and pmu::event_init group
- * validation).
+ * pmu::filter callback and pmu::event_init group validation).
*/
.capabilities = PERF_PMU_CAP_HETEROGENEOUS_CPUS | PERF_PMU_CAP_EXTENDED_REGS,
};
@@ -916,17 +911,6 @@ out:
return NULL;
}
-struct arm_pmu *armpmu_alloc(void)
-{
- return __armpmu_alloc(GFP_KERNEL);
-}
-
-struct arm_pmu *armpmu_alloc_atomic(void)
-{
- return __armpmu_alloc(GFP_ATOMIC);
-}
-
-
void armpmu_free(struct arm_pmu *pmu)
{
free_percpu(pmu->hw_events);
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index 96ffadd654ff..90815ad762eb 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -13,6 +13,7 @@
#include <linux/percpu.h>
#include <linux/perf/arm_pmu.h>
+#include <asm/cpu.h>
#include <asm/cputype.h>
static DEFINE_PER_CPU(struct arm_pmu *, probed_pmus);
@@ -187,7 +188,7 @@ out_err:
return err;
}
-static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
+static struct arm_pmu *arm_pmu_acpi_find_pmu(void)
{
unsigned long cpuid = read_cpuid_id();
struct arm_pmu *pmu;
@@ -201,16 +202,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
return pmu;
}
- pmu = armpmu_alloc_atomic();
- if (!pmu) {
- pr_warn("Unable to allocate PMU for CPU%d\n",
- smp_processor_id());
- return NULL;
- }
-
- pmu->acpi_cpuid = cpuid;
-
- return pmu;
+ return NULL;
}
/*
@@ -242,6 +234,22 @@ static bool pmu_irq_matches(struct arm_pmu *pmu, int irq)
return true;
}
+static void arm_pmu_acpi_associate_pmu_cpu(struct arm_pmu *pmu,
+ unsigned int cpu)
+{
+ int irq = per_cpu(pmu_irqs, cpu);
+
+ per_cpu(probed_pmus, cpu) = pmu;
+
+ if (pmu_irq_matches(pmu, irq)) {
+ struct pmu_hw_events __percpu *hw_events;
+ hw_events = pmu->hw_events;
+ per_cpu(hw_events->irq, cpu) = irq;
+ }
+
+ cpumask_set_cpu(cpu, &pmu->supported_cpus);
+}
+
/*
* This must run before the common arm_pmu hotplug logic, so that we can
* associate a CPU and its interrupt before the common code tries to manage the
@@ -254,42 +262,50 @@ static bool pmu_irq_matches(struct arm_pmu *pmu, int irq)
static int arm_pmu_acpi_cpu_starting(unsigned int cpu)
{
struct arm_pmu *pmu;
- struct pmu_hw_events __percpu *hw_events;
- int irq;
/* If we've already probed this CPU, we have nothing to do */
if (per_cpu(probed_pmus, cpu))
return 0;
- irq = per_cpu(pmu_irqs, cpu);
-
- pmu = arm_pmu_acpi_find_alloc_pmu();
- if (!pmu)
- return -ENOMEM;
+ pmu = arm_pmu_acpi_find_pmu();
+ if (!pmu) {
+ pr_warn_ratelimited("Unable to associate CPU%d with a PMU\n",
+ cpu);
+ return 0;
+ }
- per_cpu(probed_pmus, cpu) = pmu;
+ arm_pmu_acpi_associate_pmu_cpu(pmu, cpu);
+ return 0;
+}
- if (pmu_irq_matches(pmu, irq)) {
- hw_events = pmu->hw_events;
- per_cpu(hw_events->irq, cpu) = irq;
- }
+static void arm_pmu_acpi_probe_matching_cpus(struct arm_pmu *pmu,
+ unsigned long cpuid)
+{
+ int cpu;
- cpumask_set_cpu(cpu, &pmu->supported_cpus);
+ for_each_online_cpu(cpu) {
+ unsigned long cpu_cpuid = per_cpu(cpu_data, cpu).reg_midr;
- /*
- * Ideally, we'd probe the PMU here when we find the first matching
- * CPU. We can't do that for several reasons; see the comment in
- * arm_pmu_acpi_init().
- *
- * So for the time being, we're done.
- */
- return 0;
+ if (cpu_cpuid == cpuid)
+ arm_pmu_acpi_associate_pmu_cpu(pmu, cpu);
+ }
}
int arm_pmu_acpi_probe(armpmu_init_fn init_fn)
{
int pmu_idx = 0;
- int cpu, ret;
+ unsigned int cpu;
+ int ret;
+
+ ret = arm_pmu_acpi_parse_irqs();
+ if (ret)
+ return ret;
+
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_ACPI_STARTING,
+ "perf/arm/pmu_acpi:starting",
+ arm_pmu_acpi_cpu_starting, NULL);
+ if (ret)
+ return ret;
/*
* Initialise and register the set of PMUs which we know about right
@@ -304,13 +320,27 @@ int arm_pmu_acpi_probe(armpmu_init_fn init_fn)
* For the moment, as with the platform/DT case, we need at least one
* of a PMU's CPUs to be online at probe time.
*/
- for_each_possible_cpu(cpu) {
+ for_each_online_cpu(cpu) {
struct arm_pmu *pmu = per_cpu(probed_pmus, cpu);
+ unsigned long cpuid;
char *base_name;
- if (!pmu || pmu->name)
+ /* If we've already probed this CPU, we have nothing to do */
+ if (pmu)
continue;
+ pmu = armpmu_alloc();
+ if (!pmu) {
+ pr_warn("Unable to allocate PMU for CPU%d\n",
+ cpu);
+ return -ENOMEM;
+ }
+
+ cpuid = per_cpu(cpu_data, cpu).reg_midr;
+ pmu->acpi_cpuid = cpuid;
+
+ arm_pmu_acpi_probe_matching_cpus(pmu, cpuid);
+
ret = init_fn(pmu);
if (ret == -ENODEV) {
/* PMU not handled by this driver, or not present */
@@ -335,26 +365,16 @@ int arm_pmu_acpi_probe(armpmu_init_fn init_fn)
}
}
- return 0;
+ return ret;
}
static int arm_pmu_acpi_init(void)
{
- int ret;
-
if (acpi_disabled)
return 0;
arm_spe_acpi_register_device();
- ret = arm_pmu_acpi_parse_irqs();
- if (ret)
- return ret;
-
- ret = cpuhp_setup_state(CPUHP_AP_PERF_ARM_ACPI_STARTING,
- "perf/arm/pmu_acpi:starting",
- arm_pmu_acpi_cpu_starting, NULL);
-
- return ret;
+ return 0;
}
subsys_initcall(arm_pmu_acpi_init)
diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c
index 00d4c45a8017..25a269d431e4 100644
--- a/drivers/perf/arm_smmuv3_pmu.c
+++ b/drivers/perf/arm_smmuv3_pmu.c
@@ -959,6 +959,8 @@ static struct platform_driver smmu_pmu_driver = {
static int __init arm_smmu_pmu_init(void)
{
+ int ret;
+
cpuhp_state_num = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
"perf/arm/pmcg:online",
NULL,
@@ -966,7 +968,11 @@ static int __init arm_smmu_pmu_init(void)
if (cpuhp_state_num < 0)
return cpuhp_state_num;
- return platform_driver_register(&smmu_pmu_driver);
+ ret = platform_driver_register(&smmu_pmu_driver);
+ if (ret)
+ cpuhp_remove_multi_state(cpuhp_state_num);
+
+ return ret;
}
module_init(arm_smmu_pmu_init);
diff --git a/drivers/perf/hisilicon/hisi_pcie_pmu.c b/drivers/perf/hisilicon/hisi_pcie_pmu.c
index 21771708597d..6fee0b6e163b 100644
--- a/drivers/perf/hisilicon/hisi_pcie_pmu.c
+++ b/drivers/perf/hisilicon/hisi_pcie_pmu.c
@@ -47,10 +47,14 @@
#define HISI_PCIE_EVENT_M GENMASK_ULL(15, 0)
#define HISI_PCIE_THR_MODE_M GENMASK_ULL(27, 27)
#define HISI_PCIE_THR_M GENMASK_ULL(31, 28)
+#define HISI_PCIE_LEN_M GENMASK_ULL(35, 34)
#define HISI_PCIE_TARGET_M GENMASK_ULL(52, 36)
#define HISI_PCIE_TRIG_MODE_M GENMASK_ULL(53, 53)
#define HISI_PCIE_TRIG_M GENMASK_ULL(59, 56)
+/* Default config of TLP length mode, will count both TLP headers and payloads */
+#define HISI_PCIE_LEN_M_DEFAULT 3ULL
+
#define HISI_PCIE_MAX_COUNTERS 8
#define HISI_PCIE_REG_STEP 8
#define HISI_PCIE_THR_MAX_VAL 10
@@ -91,6 +95,7 @@ HISI_PCIE_PMU_FILTER_ATTR(thr_len, config1, 3, 0);
HISI_PCIE_PMU_FILTER_ATTR(thr_mode, config1, 4, 4);
HISI_PCIE_PMU_FILTER_ATTR(trig_len, config1, 8, 5);
HISI_PCIE_PMU_FILTER_ATTR(trig_mode, config1, 9, 9);
+HISI_PCIE_PMU_FILTER_ATTR(len_mode, config1, 11, 10);
HISI_PCIE_PMU_FILTER_ATTR(port, config2, 15, 0);
HISI_PCIE_PMU_FILTER_ATTR(bdf, config2, 31, 16);
@@ -215,8 +220,8 @@ static void hisi_pcie_pmu_config_filter(struct perf_event *event)
{
struct hisi_pcie_pmu *pcie_pmu = to_pcie_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
+ u64 port, trig_len, thr_len, len_mode;
u64 reg = HISI_PCIE_INIT_SET;
- u64 port, trig_len, thr_len;
/* Config HISI_PCIE_EVENT_CTRL according to event. */
reg |= FIELD_PREP(HISI_PCIE_EVENT_M, hisi_pcie_get_real_event(event));
@@ -245,6 +250,12 @@ static void hisi_pcie_pmu_config_filter(struct perf_event *event)
reg |= HISI_PCIE_THR_EN;
}
+ len_mode = hisi_pcie_get_len_mode(event);
+ if (len_mode)
+ reg |= FIELD_PREP(HISI_PCIE_LEN_M, len_mode);
+ else
+ reg |= FIELD_PREP(HISI_PCIE_LEN_M, HISI_PCIE_LEN_M_DEFAULT);
+
hisi_pcie_pmu_writeq(pcie_pmu, HISI_PCIE_EVENT_CTRL, hwc->idx, reg);
}
@@ -693,10 +704,10 @@ static struct attribute *hisi_pcie_pmu_events_attr[] = {
HISI_PCIE_PMU_EVENT_ATTR(rx_mrd_cnt, 0x10210),
HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_latency, 0x0011),
HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_cnt, 0x10011),
- HISI_PCIE_PMU_EVENT_ATTR(rx_mrd_flux, 0x1005),
- HISI_PCIE_PMU_EVENT_ATTR(rx_mrd_time, 0x11005),
- HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_flux, 0x2004),
- HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_time, 0x12004),
+ HISI_PCIE_PMU_EVENT_ATTR(rx_mrd_flux, 0x0804),
+ HISI_PCIE_PMU_EVENT_ATTR(rx_mrd_time, 0x10804),
+ HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_flux, 0x0405),
+ HISI_PCIE_PMU_EVENT_ATTR(tx_mrd_time, 0x10405),
NULL
};
@@ -711,6 +722,7 @@ static struct attribute *hisi_pcie_pmu_format_attr[] = {
HISI_PCIE_PMU_FORMAT_ATTR(thr_mode, "config1:4"),
HISI_PCIE_PMU_FORMAT_ATTR(trig_len, "config1:5-8"),
HISI_PCIE_PMU_FORMAT_ATTR(trig_mode, "config1:9"),
+ HISI_PCIE_PMU_FORMAT_ATTR(len_mode, "config1:10-11"),
HISI_PCIE_PMU_FORMAT_ATTR(port, "config2:0-15"),
HISI_PCIE_PMU_FORMAT_ATTR(bdf, "config2:16-31"),
NULL
diff --git a/drivers/perf/marvell_cn10k_tad_pmu.c b/drivers/perf/marvell_cn10k_tad_pmu.c
index 69c3050a4348..a1166afb3702 100644
--- a/drivers/perf/marvell_cn10k_tad_pmu.c
+++ b/drivers/perf/marvell_cn10k_tad_pmu.c
@@ -408,7 +408,11 @@ static int __init tad_pmu_init(void)
if (ret < 0)
return ret;
tad_pmu_cpuhp_state = ret;
- return platform_driver_register(&tad_pmu_driver);
+ ret = platform_driver_register(&tad_pmu_driver);
+ if (ret)
+ cpuhp_remove_multi_state(tad_pmu_cpuhp_state);
+
+ return ret;
}
static void __exit tad_pmu_exit(void)
diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c
index 929e86d6558e..f4956a417a47 100644
--- a/drivers/phy/phy-core-mipi-dphy.c
+++ b/drivers/phy/phy-core-mipi-dphy.c
@@ -17,19 +17,21 @@
* from the valid ranges specified in Section 6.9, Table 14, Page 41
* of the D-PHY specification (v1.2).
*/
-int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
+static int phy_mipi_dphy_calc_config(unsigned long pixel_clock,
unsigned int bpp,
unsigned int lanes,
+ unsigned long long hs_clk_rate,
struct phy_configure_opts_mipi_dphy *cfg)
{
- unsigned long long hs_clk_rate;
unsigned long long ui;
if (!cfg)
return -EINVAL;
- hs_clk_rate = pixel_clock * bpp;
- do_div(hs_clk_rate, lanes);
+ if (!hs_clk_rate) {
+ hs_clk_rate = pixel_clock * bpp;
+ do_div(hs_clk_rate, lanes);
+ }
ui = ALIGN(PSEC_PER_SEC, hs_clk_rate);
do_div(ui, hs_clk_rate);
@@ -75,8 +77,29 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
return 0;
}
+
+int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
+ unsigned int bpp,
+ unsigned int lanes,
+ struct phy_configure_opts_mipi_dphy *cfg)
+{
+ return phy_mipi_dphy_calc_config(pixel_clock, bpp, lanes, 0, cfg);
+
+}
EXPORT_SYMBOL(phy_mipi_dphy_get_default_config);
+int phy_mipi_dphy_get_default_config_for_hsclk(unsigned long long hs_clk_rate,
+ unsigned int lanes,
+ struct phy_configure_opts_mipi_dphy *cfg)
+{
+ if (!hs_clk_rate)
+ return -EINVAL;
+
+ return phy_mipi_dphy_calc_config(0, 0, lanes, hs_clk_rate, cfg);
+
+}
+EXPORT_SYMBOL(phy_mipi_dphy_get_default_config_for_hsclk);
+
/*
* Validate D-PHY configuration according to MIPI D-PHY specification
* (v1.2, Section Section 6.9 "Global Operation Timing Parameters").
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 9807c4d935cd..ba9d761ec49a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -2240,7 +2240,7 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_phy *qphy)
static void qmp_combo_disable_autonomous_mode(struct qmp_phy *qphy)
{
const struct qmp_phy_cfg *cfg = qphy->cfg;
- void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs_usb;
+ void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs;
void __iomem *pcs_misc = qphy->pcs_misc;
/* Disable i/o clamp_n on resume for normal mode */
diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c
index 5e6530f545b5..85888ab2d307 100644
--- a/drivers/phy/ralink/phy-mt7621-pci.c
+++ b/drivers/phy/ralink/phy-mt7621-pci.c
@@ -280,7 +280,8 @@ static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev,
}
static const struct soc_device_attribute mt7621_pci_quirks_match[] = {
- { .soc_id = "mt7621", .revision = "E2" }
+ { .soc_id = "mt7621", .revision = "E2" },
+ { /* sentinel */ }
};
static const struct regmap_config mt7621_pci_phy_regmap_config = {
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index a98c911cc37a..5bb9647b078f 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -710,6 +710,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
ret = of_property_read_u32(child, "reg", &index);
if (ret || index > usbphyc->nphys) {
dev_err(&phy->dev, "invalid reg property: %d\n", ret);
+ if (!ret)
+ ret = -EINVAL;
goto put_child;
}
diff --git a/drivers/phy/sunplus/phy-sunplus-usb2.c b/drivers/phy/sunplus/phy-sunplus-usb2.c
index b932087c55b2..e827b79f6d49 100644
--- a/drivers/phy/sunplus/phy-sunplus-usb2.c
+++ b/drivers/phy/sunplus/phy-sunplus-usb2.c
@@ -256,8 +256,8 @@ static int sp_usb_phy_probe(struct platform_device *pdev)
usbphy->moon4_res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon4");
usbphy->moon4_regs = devm_ioremap(&pdev->dev, usbphy->moon4_res_mem->start,
resource_size(usbphy->moon4_res_mem));
- if (IS_ERR(usbphy->moon4_regs))
- return PTR_ERR(usbphy->moon4_regs);
+ if (!usbphy->moon4_regs)
+ return -ENOMEM;
usbphy->phy_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(usbphy->phy_clk))
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 95091876c422..dce45fbbd699 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -1461,8 +1461,14 @@ EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
- struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_lane *lane;
+ struct tegra_xusb_padctl *padctl;
+
+ if (!phy)
+ return;
+
+ lane = phy_get_drvdata(phy);
+ padctl = lane->pad->padctl;
if (padctl->soc->ops->utmi_pad_power_on)
padctl->soc->ops->utmi_pad_power_on(phy);
@@ -1471,8 +1477,14 @@ EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_on);
void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
- struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_lane *lane;
+ struct tegra_xusb_padctl *padctl;
+
+ if (!phy)
+ return;
+
+ lane = phy_get_drvdata(phy);
+ padctl = lane->pad->padctl;
if (padctl->soc->ops->utmi_pad_power_down)
padctl->soc->ops->utmi_pad_power_down(phy);
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index ef898ee8ca6b..6e0a40962f38 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -220,6 +220,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
for (state = 0; ; state++) {
/* Retrieve the pinctrl-* property */
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
+ if (!propname)
+ return -ENOMEM;
prop = of_find_property(np, propname, &size);
kfree(propname);
if (!prop) {
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 52ecd66ce357..047a8374b4fd 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -436,9 +436,14 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
writel(value, padcfg0);
}
+static int __intel_gpio_get_gpio_mode(u32 value)
+{
+ return (value & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
+}
+
static int intel_gpio_get_gpio_mode(void __iomem *padcfg0)
{
- return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
+ return __intel_gpio_get_gpio_mode(readl(padcfg0));
}
static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
@@ -1674,6 +1679,7 @@ EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data);
static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
+ u32 value;
if (!pd || !intel_pad_usable(pctrl, pin))
return false;
@@ -1688,6 +1694,25 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int
gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin)))
return true;
+ /*
+ * The firmware on some systems may configure GPIO pins to be
+ * an interrupt source in so called "direct IRQ" mode. In such
+ * cases the GPIO controller driver has no idea if those pins
+ * are being used or not. At the same time, there is a known bug
+ * in the firmwares that don't restore the pin settings correctly
+ * after suspend, i.e. by an unknown reason the Rx value becomes
+ * inverted.
+ *
+ * Hence, let's save and restore the pins that are configured
+ * as GPIOs in the input mode with GPIROUTIOXAPIC bit set.
+ *
+ * See https://bugzilla.kernel.org/show_bug.cgi?id=214749.
+ */
+ value = readl(intel_get_padcfg(pctrl, pin, PADCFG0));
+ if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
+ (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO))
+ return true;
+
return false;
}
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index f7b54a551764..27f0a54e12bf 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -24,6 +24,7 @@
#define MTK_EINT_EDGE_SENSITIVE 0
#define MTK_EINT_LEVEL_SENSITIVE 1
#define MTK_EINT_DBNC_SET_DBNC_BITS 4
+#define MTK_EINT_DBNC_MAX 16
#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
@@ -48,6 +49,21 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_clr = 0x700,
};
+const unsigned int debounce_time_mt2701[] = {
+ 500, 1000, 16000, 32000, 64000, 128000, 256000, 0
+};
+EXPORT_SYMBOL_GPL(debounce_time_mt2701);
+
+const unsigned int debounce_time_mt6765[] = {
+ 125, 250, 500, 1000, 16000, 32000, 64000, 128000, 256000, 512000, 0
+};
+EXPORT_SYMBOL_GPL(debounce_time_mt6765);
+
+const unsigned int debounce_time_mt6795[] = {
+ 500, 1000, 16000, 32000, 64000, 128000, 256000, 512000, 0
+};
+EXPORT_SYMBOL_GPL(debounce_time_mt6795);
+
static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
unsigned int eint_num,
unsigned int offset)
@@ -287,12 +303,15 @@ static struct irq_chip mtk_eint_irq_chip = {
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *reg = eint->base + eint->regs->dom_en;
+ void __iomem *dom_en = eint->base + eint->regs->dom_en;
+ void __iomem *mask_set = eint->base + eint->regs->mask_set;
unsigned int i;
for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, reg);
- reg += 4;
+ writel(0xffffffff, dom_en);
+ writel(0xffffffff, mask_set);
+ dom_en += 4;
+ mask_set += 4;
}
return 0;
@@ -404,10 +423,11 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
int virq, eint_offset;
unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
dbnc;
- static const unsigned int debounce_time[] = {500, 1000, 16000, 32000,
- 64000, 128000, 256000};
struct irq_data *d;
+ if (!eint->hw->db_time)
+ return -EOPNOTSUPP;
+
virq = irq_find_mapping(eint->domain, eint_num);
eint_offset = (eint_num % 4) * 8;
d = irq_get_irq_data(virq);
@@ -418,9 +438,9 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
- dbnc = ARRAY_SIZE(debounce_time);
- for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
- if (debounce <= debounce_time[i]) {
+ dbnc = eint->num_db_time;
+ for (i = 0; i < eint->num_db_time; i++) {
+ if (debounce <= eint->hw->db_time[i]) {
dbnc = i;
break;
}
@@ -494,6 +514,13 @@ int mtk_eint_do_init(struct mtk_eint *eint)
if (!eint->domain)
return -ENOMEM;
+ if (eint->hw->db_time) {
+ for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
+ if (eint->hw->db_time[i] == 0)
+ break;
+ eint->num_db_time = i;
+ }
+
mtk_eint_hw_init(eint);
for (i = 0; i < eint->hw->ap_num; i++) {
int virq = irq_create_mapping(eint->domain, i);
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 48468d0fae68..6139b16cd225 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -37,8 +37,13 @@ struct mtk_eint_hw {
u8 ports;
unsigned int ap_num;
unsigned int db_cnt;
+ const unsigned int *db_time;
};
+extern const unsigned int debounce_time_mt2701[];
+extern const unsigned int debounce_time_mt6765[];
+extern const unsigned int debounce_time_mt6795[];
+
struct mtk_eint;
struct mtk_eint_xt {
@@ -62,6 +67,7 @@ struct mtk_eint {
/* Used to fit into various EINT device */
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
+ u16 num_db_time;
/* Used to fit into various pinctrl device */
void *pctl;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index d1583b4fdd9d..b185538452a0 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -518,6 +518,7 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.ports = 6,
.ap_num = 169,
.db_cnt = 16,
+ .db_time = debounce_time_mt2701,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index b921068f9e69..730a496848dc 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -567,6 +567,7 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.ports = 8,
.ap_num = 229,
.db_cnt = 40,
+ .db_time = debounce_time_mt2701,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6765.c b/drivers/pinctrl/mediatek/pinctrl-mt6765.c
index c57b19fcda03..f6ec41eb6e0c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6765.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6765.c
@@ -1062,6 +1062,7 @@ static const struct mtk_eint_hw mt6765_eint_hw = {
.ports = 6,
.ap_num = 160,
.db_cnt = 13,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt6765_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6779.c b/drivers/pinctrl/mediatek/pinctrl-mt6779.c
index 4ddf8bda6827..62d4f5ad6737 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6779.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6779.c
@@ -737,6 +737,7 @@ static const struct mtk_eint_hw mt6779_eint_hw = {
.ports = 6,
.ap_num = 195,
.db_cnt = 13,
+ .db_time = debounce_time_mt2701,
};
static const struct mtk_pin_soc mt6779_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6795.c b/drivers/pinctrl/mediatek/pinctrl-mt6795.c
index f90152261a0f..01e855ccd4dd 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6795.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6795.c
@@ -475,6 +475,7 @@ static const struct mtk_eint_hw mt6795_eint_hw = {
.ports = 7,
.ap_num = 224,
.db_cnt = 32,
+ .db_time = debounce_time_mt6795,
};
static const unsigned int mt6795_pull_type[] = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
index 68eee881ee3d..3c1148d59eff 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
@@ -846,6 +846,7 @@ static const struct mtk_eint_hw mt7622_eint_hw = {
.ports = 7,
.ap_num = ARRAY_SIZE(mt7622_pins),
.db_cnt = 20,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt7622_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
index b8d9d31db74f..699977074697 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -1369,6 +1369,7 @@ static const struct mtk_eint_hw mt7623_eint_hw = {
.ports = 6,
.ap_num = 169,
.db_cnt = 20,
+ .db_time = debounce_time_mt2701,
};
static struct mtk_pin_soc mt7623_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
index b5f0fa43245f..2ce411cb9c6e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7629.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
@@ -402,6 +402,7 @@ static const struct mtk_eint_hw mt7629_eint_hw = {
.ports = 7,
.ap_num = ARRAY_SIZE(mt7629_pins),
.db_cnt = 16,
+ .db_time = debounce_time_mt2701,
};
static struct mtk_pin_soc mt7629_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
index f26869f1a367..50cb736f9f11 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
@@ -826,6 +826,7 @@ static const struct mtk_eint_hw mt7986a_eint_hw = {
.ports = 7,
.ap_num = ARRAY_SIZE(mt7986a_pins),
.db_cnt = 16,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_eint_hw mt7986b_eint_hw = {
@@ -833,6 +834,7 @@ static const struct mtk_eint_hw mt7986b_eint_hw = {
.ports = 7,
.ap_num = ARRAY_SIZE(mt7986b_pins),
.db_cnt = 16,
+ .db_time = debounce_time_mt6765,
};
static struct mtk_pin_soc mt7986a_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index 91c530e7b00e..e8772dcfe69e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -286,6 +286,7 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.ports = 6,
.ap_num = 143,
.db_cnt = 16,
+ .db_time = debounce_time_mt2701,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index 562846756517..cdb0252071fb 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -315,6 +315,7 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.ports = 6,
.ap_num = 192,
.db_cnt = 16,
+ .db_time = debounce_time_mt2701,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8167.c b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
index 825167f5d020..866da2c4a890 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8167.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
@@ -319,6 +319,7 @@ static const struct mtk_pinctrl_devdata mt8167_pinctrl_data = {
.ports = 6,
.ap_num = 169,
.db_cnt = 64,
+ .db_time = debounce_time_mt6795,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 1d7d11a32e7d..37d8cec1c3ce 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -327,6 +327,7 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.ports = 6,
.ap_num = 224,
.db_cnt = 16,
+ .db_time = debounce_time_mt2701,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
index fecb1e64fff4..ddc48b725c22 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8183.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
@@ -545,6 +545,7 @@ static const struct mtk_eint_hw mt8183_eint_hw = {
.ports = 6,
.ap_num = 212,
.db_cnt = 13,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt8183_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8186.c b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
index a4dd5197abc1..a02f7c326970 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8186.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
@@ -1222,6 +1222,7 @@ static const struct mtk_eint_hw mt8186_eint_hw = {
.ports = 7,
.ap_num = 217,
.db_cnt = 32,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt8186_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8188.c b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
index d0e75c1b4417..6a3d0126288e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8188.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
@@ -1625,6 +1625,7 @@ static const struct mtk_eint_hw mt8188_eint_hw = {
.ports = 7,
.ap_num = 225,
.db_cnt = 32,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt8188_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8192.c b/drivers/pinctrl/mediatek/pinctrl-mt8192.c
index 78c02b7c81f0..9695f4ec6aba 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8192.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8192.c
@@ -1371,6 +1371,7 @@ static const struct mtk_eint_hw mt8192_eint_hw = {
.ports = 7,
.ap_num = 224,
.db_cnt = 32,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_reg_calc mt8192_reg_cals[PINCTRL_PIN_REG_MAX] = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8195.c b/drivers/pinctrl/mediatek/pinctrl-mt8195.c
index 563693d3d4c2..89557c7ed2ab 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8195.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8195.c
@@ -935,6 +935,7 @@ static const struct mtk_eint_hw mt8195_eint_hw = {
.ports = 7,
.ap_num = 225,
.db_cnt = 32,
+ .db_time = debounce_time_mt6765,
};
static const struct mtk_pin_soc mt8195_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8365.c b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
index 57f37a294063..e31b89b226b7 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8365.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
@@ -453,6 +453,7 @@ static const struct mtk_pinctrl_devdata mt8365_pinctrl_data = {
.ports = 5,
.ap_num = 160,
.db_cnt = 160,
+ .db_time = debounce_time_mt6765,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8516.c b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
index 939a1932b8dc..e929339dd2cb 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8516.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
@@ -319,6 +319,7 @@ static const struct mtk_pinctrl_devdata mt8516_pinctrl_data = {
.ports = 6,
.ap_num = 169,
.db_cnt = 64,
+ .db_time = debounce_time_mt6795,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index e1ae3beb9f72..b7921b59eb7b 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -709,6 +709,9 @@ static int mtk_pinconf_bias_set_rsel(struct mtk_pinctrl *hw,
{
int err, rsel_val;
+ if (!pullup && arg == MTK_DISABLE)
+ return 0;
+
if (hw->rsel_si_unit) {
/* find pin rsel_index from pin_rsel array*/
err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, &rsel_val);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 53bdfc40f055..da974ff2d75d 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -679,14 +679,54 @@ static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
}
static struct rockchip_mux_route_data px30_mux_route_data[] = {
+ RK_MUXROUTE_SAME(2, RK_PB4, 1, 0x184, BIT(16 + 7)), /* cif-d0m0 */
+ RK_MUXROUTE_SAME(3, RK_PA1, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d0m1 */
+ RK_MUXROUTE_SAME(2, RK_PB6, 1, 0x184, BIT(16 + 7)), /* cif-d1m0 */
+ RK_MUXROUTE_SAME(3, RK_PA2, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d1m1 */
RK_MUXROUTE_SAME(2, RK_PA0, 1, 0x184, BIT(16 + 7)), /* cif-d2m0 */
RK_MUXROUTE_SAME(3, RK_PA3, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d2m1 */
+ RK_MUXROUTE_SAME(2, RK_PA1, 1, 0x184, BIT(16 + 7)), /* cif-d3m0 */
+ RK_MUXROUTE_SAME(3, RK_PA5, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d3m1 */
+ RK_MUXROUTE_SAME(2, RK_PA2, 1, 0x184, BIT(16 + 7)), /* cif-d4m0 */
+ RK_MUXROUTE_SAME(3, RK_PA7, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d4m1 */
+ RK_MUXROUTE_SAME(2, RK_PA3, 1, 0x184, BIT(16 + 7)), /* cif-d5m0 */
+ RK_MUXROUTE_SAME(3, RK_PB0, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d5m1 */
+ RK_MUXROUTE_SAME(2, RK_PA4, 1, 0x184, BIT(16 + 7)), /* cif-d6m0 */
+ RK_MUXROUTE_SAME(3, RK_PB1, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d6m1 */
+ RK_MUXROUTE_SAME(2, RK_PA5, 1, 0x184, BIT(16 + 7)), /* cif-d7m0 */
+ RK_MUXROUTE_SAME(3, RK_PB4, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d7m1 */
+ RK_MUXROUTE_SAME(2, RK_PA6, 1, 0x184, BIT(16 + 7)), /* cif-d8m0 */
+ RK_MUXROUTE_SAME(3, RK_PB6, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d8m1 */
+ RK_MUXROUTE_SAME(2, RK_PA7, 1, 0x184, BIT(16 + 7)), /* cif-d9m0 */
+ RK_MUXROUTE_SAME(3, RK_PB7, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d9m1 */
+ RK_MUXROUTE_SAME(2, RK_PB7, 1, 0x184, BIT(16 + 7)), /* cif-d10m0 */
+ RK_MUXROUTE_SAME(3, RK_PC6, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d10m1 */
+ RK_MUXROUTE_SAME(2, RK_PC0, 1, 0x184, BIT(16 + 7)), /* cif-d11m0 */
+ RK_MUXROUTE_SAME(3, RK_PC7, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-d11m1 */
+ RK_MUXROUTE_SAME(2, RK_PB0, 1, 0x184, BIT(16 + 7)), /* cif-vsyncm0 */
+ RK_MUXROUTE_SAME(3, RK_PD1, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-vsyncm1 */
+ RK_MUXROUTE_SAME(2, RK_PB1, 1, 0x184, BIT(16 + 7)), /* cif-hrefm0 */
+ RK_MUXROUTE_SAME(3, RK_PD2, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-hrefm1 */
+ RK_MUXROUTE_SAME(2, RK_PB2, 1, 0x184, BIT(16 + 7)), /* cif-clkinm0 */
+ RK_MUXROUTE_SAME(3, RK_PD3, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-clkinm1 */
+ RK_MUXROUTE_SAME(2, RK_PB3, 1, 0x184, BIT(16 + 7)), /* cif-clkoutm0 */
+ RK_MUXROUTE_SAME(3, RK_PD0, 3, 0x184, BIT(16 + 7) | BIT(7)), /* cif-clkoutm1 */
RK_MUXROUTE_SAME(3, RK_PC6, 2, 0x184, BIT(16 + 8)), /* pdm-m0 */
RK_MUXROUTE_SAME(2, RK_PC6, 1, 0x184, BIT(16 + 8) | BIT(8)), /* pdm-m1 */
+ RK_MUXROUTE_SAME(3, RK_PD3, 2, 0x184, BIT(16 + 8)), /* pdm-sdi0m0 */
+ RK_MUXROUTE_SAME(2, RK_PC5, 2, 0x184, BIT(16 + 8) | BIT(8)), /* pdm-sdi0m1 */
RK_MUXROUTE_SAME(1, RK_PD3, 2, 0x184, BIT(16 + 10)), /* uart2-rxm0 */
RK_MUXROUTE_SAME(2, RK_PB6, 2, 0x184, BIT(16 + 10) | BIT(10)), /* uart2-rxm1 */
+ RK_MUXROUTE_SAME(1, RK_PD2, 2, 0x184, BIT(16 + 10)), /* uart2-txm0 */
+ RK_MUXROUTE_SAME(2, RK_PB4, 2, 0x184, BIT(16 + 10) | BIT(10)), /* uart2-txm1 */
RK_MUXROUTE_SAME(0, RK_PC1, 2, 0x184, BIT(16 + 9)), /* uart3-rxm0 */
RK_MUXROUTE_SAME(1, RK_PB7, 2, 0x184, BIT(16 + 9) | BIT(9)), /* uart3-rxm1 */
+ RK_MUXROUTE_SAME(0, RK_PC0, 2, 0x184, BIT(16 + 9)), /* uart3-txm0 */
+ RK_MUXROUTE_SAME(1, RK_PB6, 2, 0x184, BIT(16 + 9) | BIT(9)), /* uart3-txm1 */
+ RK_MUXROUTE_SAME(0, RK_PC2, 2, 0x184, BIT(16 + 9)), /* uart3-ctsm0 */
+ RK_MUXROUTE_SAME(1, RK_PB4, 2, 0x184, BIT(16 + 9) | BIT(9)), /* uart3-ctsm1 */
+ RK_MUXROUTE_SAME(0, RK_PC3, 2, 0x184, BIT(16 + 9)), /* uart3-rtsm0 */
+ RK_MUXROUTE_SAME(1, RK_PB5, 2, 0x184, BIT(16 + 9) | BIT(9)), /* uart3-rtsm1 */
};
static struct rockchip_mux_route_data rv1126_mux_route_data[] = {
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 67bec7ea0f8b..414ee6bb8ac9 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -727,7 +727,7 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
mux_bytes = pcs->width / BITS_PER_BYTE;
- if (pcs->bits_per_mux) {
+ if (pcs->bits_per_mux && pcs->fmask) {
pcs->bits_per_pin = fls(pcs->fmask);
nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
} else {
diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c
index aa2075390f3e..e96c00686a25 100644
--- a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c
+++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c
@@ -1873,8 +1873,8 @@ static const struct msm_pingroup sc8280xp_groups[] = {
[225] = PINGROUP(225, hs3_mi2s, phase_flag, _, _, _, _, egpio),
[226] = PINGROUP(226, hs3_mi2s, phase_flag, _, _, _, _, egpio),
[227] = PINGROUP(227, hs3_mi2s, phase_flag, _, _, _, _, egpio),
- [228] = UFS_RESET(ufs_reset, 0xf1004),
- [229] = UFS_RESET(ufs1_reset, 0xf3004),
+ [228] = UFS_RESET(ufs_reset, 0xf1000),
+ [229] = UFS_RESET(ufs1_reset, 0xf3000),
[230] = SDC_QDSD_PINGROUP(sdc2_clk, 0xe8000, 14, 6),
[231] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xe8000, 11, 3),
[232] = SDC_QDSD_PINGROUP(sdc2_data, 0xe8000, 9, 0),
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index dbd327712205..868b20361769 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-if MIPS
source "drivers/platform/mips/Kconfig"
-endif
source "drivers/platform/loongarch/Kconfig"
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 6b954c5acadb..c1ca247987d2 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -228,6 +228,16 @@ config CROS_EC_TYPEC
To compile this driver as a module, choose M here: the module will be
called cros_ec_typec.
+config CROS_HPS_I2C
+ tristate "ChromeOS HPS device"
+ depends on HID && I2C && PM
+ help
+ Say Y here if you want to enable support for the ChromeOS
+ human presence sensor (HPS), attached via I2C. The driver supports a
+ sensor connected to the I2C bus and exposes it as a character device.
+ To save power, the sensor is automatically powered down when no
+ clients are accessing it.
+
config CROS_USBPD_LOGGER
tristate "Logging driver for USB PD charger"
depends on CHARGER_CROS_USBPD
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 2950610101f1..f6068d077a40 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o
cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o
obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o
obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o
+obj-$(CONFIG_CROS_HPS_I2C) += cros_hps_i2c.o
obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
diff --git a/drivers/platform/chrome/chromeos_privacy_screen.c b/drivers/platform/chrome/chromeos_privacy_screen.c
index 77e9f5ee8e33..bb74ddf9af4a 100644
--- a/drivers/platform/chrome/chromeos_privacy_screen.c
+++ b/drivers/platform/chrome/chromeos_privacy_screen.c
@@ -123,12 +123,11 @@ static int chromeos_privacy_screen_add(struct acpi_device *adev)
return 0;
}
-static int chromeos_privacy_screen_remove(struct acpi_device *adev)
+static void chromeos_privacy_screen_remove(struct acpi_device *adev)
{
struct drm_privacy_screen *drm_privacy_screen = acpi_driver_data(adev);
drm_privacy_screen_unregister(drm_privacy_screen);
- return 0;
}
static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = {
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index 4e63adf083ea..21d973fc6be2 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -521,6 +521,7 @@ static struct platform_driver cros_ec_debugfs_driver = {
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_debugfs_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = cros_ec_debugfs_probe,
.remove = cros_ec_debugfs_remove,
diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c
index b6823c654c3f..dbe698f33128 100644
--- a/drivers/platform/chrome/cros_ec_i2c.c
+++ b/drivers/platform/chrome/cros_ec_i2c.c
@@ -286,8 +286,7 @@ done:
return ret;
}
-static int cros_ec_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *dev_id)
+static int cros_ec_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct cros_ec_device *ec_dev = NULL;
@@ -373,7 +372,7 @@ static struct i2c_driver cros_ec_driver = {
.of_match_table = of_match_ptr(cros_ec_i2c_of_match),
.pm = &cros_ec_i2c_pm_ops,
},
- .probe = cros_ec_i2c_probe,
+ .probe_new = cros_ec_i2c_probe,
.remove = cros_ec_i2c_remove,
.id_table = cros_ec_i2c_id,
};
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 469dfc7a4a03..1674105decfb 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -8,6 +8,7 @@
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kobject.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -493,7 +494,7 @@ static ssize_t userspace_control_store(struct device *dev,
bool enable;
int ret;
- ret = strtobool(buf, &enable);
+ ret = kstrtobool(buf, &enable);
if (ret < 0)
return ret;
@@ -601,6 +602,7 @@ static struct platform_driver cros_ec_lightbar_driver = {
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_lightbar_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = cros_ec_lightbar_probe,
.remove = cros_ec_lightbar_remove,
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 7677ab3c0ead..7fc8f82280ac 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -354,6 +354,9 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
return -EBUSY;
}
+ cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
+ EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
+
/*
* Read the mapped ID twice, the first one is assuming the
* EC is a Microchip Embedded Controller (MEC) variant, if the
@@ -554,6 +557,12 @@ static struct platform_driver cros_ec_lpc_driver = {
.name = DRV_NAME,
.acpi_match_table = cros_ec_lpc_acpi_device_ids,
.pm = &cros_ec_lpc_pm_ops,
+ /*
+ * ACPI child devices may probe before us, and they racily
+ * check our drvdata pointer. Force synchronous probe until
+ * those races are resolved.
+ */
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
.probe = cros_ec_lpc_probe,
.remove = cros_ec_lpc_remove,
@@ -586,14 +595,10 @@ static int __init cros_ec_lpc_init(void)
return -ENODEV;
}
- cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
- EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
-
/* Register the driver */
ret = platform_driver_register(&cros_ec_lpc_driver);
if (ret) {
pr_err(DRV_NAME ": can't register driver: %d\n", ret);
- cros_ec_lpc_mec_destroy();
return ret;
}
@@ -603,7 +608,6 @@ static int __init cros_ec_lpc_init(void)
if (ret) {
pr_err(DRV_NAME ": can't register device: %d\n", ret);
platform_driver_unregister(&cros_ec_lpc_driver);
- cros_ec_lpc_mec_destroy();
}
}
@@ -615,7 +619,6 @@ static void __exit cros_ec_lpc_exit(void)
if (!cros_ec_lpc_acpi_device_found)
platform_device_unregister(&cros_ec_lpc_device);
platform_driver_unregister(&cros_ec_lpc_driver);
- cros_ec_lpc_mec_destroy();
}
module_init(cros_ec_lpc_init);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
index bbc2884f5e2f..0d9c79b270ce 100644
--- a/drivers/platform/chrome/cros_ec_lpc_mec.c
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
@@ -146,9 +146,3 @@ void cros_ec_lpc_mec_init(unsigned int base, unsigned int end)
mec_emi_end = end;
}
EXPORT_SYMBOL(cros_ec_lpc_mec_init);
-
-void cros_ec_lpc_mec_destroy(void)
-{
- mutex_destroy(&io_mutex);
-}
-EXPORT_SYMBOL(cros_ec_lpc_mec_destroy);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.h b/drivers/platform/chrome/cros_ec_lpc_mec.h
index aa1018f6b0f2..9d0521b23e8a 100644
--- a/drivers/platform/chrome/cros_ec_lpc_mec.h
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.h
@@ -45,13 +45,6 @@ enum cros_ec_lpc_mec_io_type {
*/
void cros_ec_lpc_mec_init(unsigned int base, unsigned int end);
-/*
- * cros_ec_lpc_mec_destroy
- *
- * Cleanup MEC I/O.
- */
-void cros_ec_lpc_mec_destroy(void);
-
/**
* cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range.
*
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c
index 7360b3ff6e4f..21143dba8970 100644
--- a/drivers/platform/chrome/cros_ec_spi.c
+++ b/drivers/platform/chrome/cros_ec_spi.c
@@ -834,6 +834,7 @@ static struct spi_driver cros_ec_driver_spi = {
.name = "cros-ec-spi",
.of_match_table = cros_ec_spi_of_match,
.pm = &cros_ec_spi_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = cros_ec_spi_probe,
.remove = cros_ec_spi_remove,
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 2a7ff14dc37e..59de4ce01fab 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -173,10 +173,13 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
role_sw_err:
typec_switch_put(port->ori_sw);
+ port->ori_sw = NULL;
ori_sw_err:
typec_retimer_put(port->retimer);
+ port->retimer = NULL;
retimer_sw_err:
typec_mux_put(port->mux);
+ port->mux = NULL;
mux_err:
return -ENODEV;
}
diff --git a/drivers/platform/chrome/cros_hps_i2c.c b/drivers/platform/chrome/cros_hps_i2c.c
new file mode 100644
index 000000000000..62ccb1acb5de
--- /dev/null
+++ b/drivers/platform/chrome/cros_hps_i2c.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the ChromeOS human presence sensor (HPS), attached via I2C.
+ *
+ * The driver exposes HPS as a character device, although currently no read or
+ * write operations are supported. Instead, the driver only controls the power
+ * state of the sensor, keeping it on only while userspace holds an open file
+ * descriptor to the HPS device.
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#define HPS_ACPI_ID "GOOG0020"
+
+struct hps_drvdata {
+ struct i2c_client *client;
+ struct miscdevice misc_device;
+ struct gpio_desc *enable_gpio;
+};
+
+static void hps_set_power(struct hps_drvdata *hps, bool state)
+{
+ gpiod_set_value_cansleep(hps->enable_gpio, state);
+}
+
+static int hps_open(struct inode *inode, struct file *file)
+{
+ struct hps_drvdata *hps = container_of(file->private_data,
+ struct hps_drvdata, misc_device);
+ struct device *dev = &hps->client->dev;
+
+ return pm_runtime_resume_and_get(dev);
+}
+
+static int hps_release(struct inode *inode, struct file *file)
+{
+ struct hps_drvdata *hps = container_of(file->private_data,
+ struct hps_drvdata, misc_device);
+ struct device *dev = &hps->client->dev;
+
+ return pm_runtime_put(dev);
+}
+
+static const struct file_operations hps_fops = {
+ .owner = THIS_MODULE,
+ .open = hps_open,
+ .release = hps_release,
+};
+
+static int hps_i2c_probe(struct i2c_client *client)
+{
+ struct hps_drvdata *hps;
+ int ret;
+
+ hps = devm_kzalloc(&client->dev, sizeof(*hps), GFP_KERNEL);
+ if (!hps)
+ return -ENOMEM;
+
+ hps->misc_device.parent = &client->dev;
+ hps->misc_device.minor = MISC_DYNAMIC_MINOR;
+ hps->misc_device.name = "cros-hps";
+ hps->misc_device.fops = &hps_fops;
+
+ i2c_set_clientdata(client, hps);
+ hps->client = client;
+
+ /*
+ * HPS is powered on from firmware before entering the kernel, so we
+ * acquire the line with GPIOD_OUT_HIGH here to preserve the existing
+ * state. The peripheral is powered off after successful probe below.
+ */
+ hps->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(hps->enable_gpio)) {
+ ret = PTR_ERR(hps->enable_gpio);
+ dev_err(&client->dev, "failed to get enable gpio: %d\n", ret);
+ return ret;
+ }
+
+ ret = misc_register(&hps->misc_device);
+ if (ret) {
+ dev_err(&client->dev, "failed to initialize misc device: %d\n", ret);
+ return ret;
+ }
+
+ hps_set_power(hps, false);
+ pm_runtime_enable(&client->dev);
+ return 0;
+}
+
+static void hps_i2c_remove(struct i2c_client *client)
+{
+ struct hps_drvdata *hps = i2c_get_clientdata(client);
+
+ pm_runtime_disable(&client->dev);
+ misc_deregister(&hps->misc_device);
+
+ /*
+ * Re-enable HPS, in order to return it to its default state
+ * (i.e. powered on).
+ */
+ hps_set_power(hps, true);
+}
+
+static int hps_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct hps_drvdata *hps = i2c_get_clientdata(client);
+
+ hps_set_power(hps, false);
+ return 0;
+}
+
+static int hps_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct hps_drvdata *hps = i2c_get_clientdata(client);
+
+ hps_set_power(hps, true);
+ return 0;
+}
+static UNIVERSAL_DEV_PM_OPS(hps_pm_ops, hps_suspend, hps_resume, NULL);
+
+static const struct i2c_device_id hps_i2c_id[] = {
+ { "cros-hps", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, hps_i2c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hps_acpi_id[] = {
+ { HPS_ACPI_ID, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, hps_acpi_id);
+#endif /* CONFIG_ACPI */
+
+static struct i2c_driver hps_i2c_driver = {
+ .probe_new = hps_i2c_probe,
+ .remove = hps_i2c_remove,
+ .id_table = hps_i2c_id,
+ .driver = {
+ .name = "cros-hps",
+ .pm = &hps_pm_ops,
+ .acpi_match_table = ACPI_PTR(hps_acpi_id),
+ },
+};
+module_i2c_driver(hps_i2c_driver);
+
+MODULE_ALIAS("acpi:" HPS_ACPI_ID);
+MODULE_AUTHOR("Sami Kyöstilä <skyostil@chromium.org>");
+MODULE_DESCRIPTION("Driver for ChromeOS HPS");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c
index 4b5a81c9dc6d..10670b6588e3 100644
--- a/drivers/platform/chrome/cros_usbpd_notify.c
+++ b/drivers/platform/chrome/cros_usbpd_notify.c
@@ -239,7 +239,11 @@ static int __init cros_usbpd_notify_init(void)
return ret;
#ifdef CONFIG_ACPI
- platform_driver_register(&cros_usbpd_notify_acpi_driver);
+ ret = platform_driver_register(&cros_usbpd_notify_acpi_driver);
+ if (ret) {
+ platform_driver_unregister(&cros_usbpd_notify_plat_driver);
+ return ret;
+ }
#endif
return 0;
}
diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
index 5b42992bff38..d6a994bdc182 100644
--- a/drivers/platform/chrome/wilco_ec/core.c
+++ b/drivers/platform/chrome/wilco_ec/core.c
@@ -129,7 +129,6 @@ unregister_rtc:
unregister_debugfs:
if (ec->debugfs_pdev)
platform_device_unregister(ec->debugfs_pdev);
- cros_ec_lpc_mec_destroy();
return ret;
}
@@ -143,10 +142,6 @@ static int wilco_ec_remove(struct platform_device *pdev)
platform_device_unregister(ec->rtc_pdev);
if (ec->debugfs_pdev)
platform_device_unregister(ec->debugfs_pdev);
-
- /* Teardown cros_ec interface */
- cros_ec_lpc_mec_destroy();
-
return 0;
}
diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c
index 32e400590be5..69ceead8cdaa 100644
--- a/drivers/platform/chrome/wilco_ec/event.c
+++ b/drivers/platform/chrome/wilco_ec/event.c
@@ -500,15 +500,13 @@ free_minor:
return error;
}
-static int event_device_remove(struct acpi_device *adev)
+static void event_device_remove(struct acpi_device *adev)
{
struct event_device_data *dev_data = adev->driver_data;
cdev_device_del(&dev_data->cdev, &dev_data->dev);
ida_simple_remove(&event_ida, MINOR(dev_data->dev.devt));
hangup_device(dev_data);
-
- return 0;
}
static const struct acpi_device_id event_acpi_ids[] = {
diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c
index 65b4a819f1bd..c2c9b0d3244c 100644
--- a/drivers/platform/mellanox/mlxbf-pmc.c
+++ b/drivers/platform/mellanox/mlxbf-pmc.c
@@ -358,7 +358,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = {
{ 0x32, "DDN_DIAG_W_INGRESS" },
{ 0x33, "DDN_DIAG_C_INGRESS" },
{ 0x34, "DDN_DIAG_CORE_SENT" },
- { 0x35, "NDN_DIAG_S_OUT_OF_CRED" },
+ { 0x35, "NDN_DIAG_N_OUT_OF_CRED" },
{ 0x36, "NDN_DIAG_S_OUT_OF_CRED" },
{ 0x37, "NDN_DIAG_E_OUT_OF_CRED" },
{ 0x38, "NDN_DIAG_W_OUT_OF_CRED" },
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h
index e4f0d2eda714..44fb8c5b1484 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h
+++ b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h
@@ -60,4 +60,14 @@
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
+/* BF3 register offsets within resource 0. */
+#define MLXBF_TMFIFO_RX_DATA_BF3 0x0000
+#define MLXBF_TMFIFO_TX_DATA_BF3 0x1000
+
+/* BF3 register offsets within resource 1. */
+#define MLXBF_TMFIFO_RX_STS_BF3 0x0000
+#define MLXBF_TMFIFO_RX_CTL_BF3 0x0008
+#define MLXBF_TMFIFO_TX_STS_BF3 0x0100
+#define MLXBF_TMFIFO_TX_CTL_BF3 0x0108
+
#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
index 1ae3c56b66b0..91a077c35b8b 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -47,6 +47,9 @@
/* Message with data needs at least two words (for header & data). */
#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
+/* ACPI UID for BlueField-3. */
+#define TMFIFO_BF3_UID 1
+
struct mlxbf_tmfifo;
/**
@@ -137,11 +140,25 @@ struct mlxbf_tmfifo_irq_info {
};
/**
+ * mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx)
+ * @ctl: control register offset (TMFIFO_RX_CTL / TMFIFO_TX_CTL)
+ * @sts: status register offset (TMFIFO_RX_STS / TMFIFO_TX_STS)
+ * @data: data register offset (TMFIFO_RX_DATA / TMFIFO_TX_DATA)
+ */
+struct mlxbf_tmfifo_io {
+ void __iomem *ctl;
+ void __iomem *sts;
+ void __iomem *data;
+};
+
+/**
* mlxbf_tmfifo - Structure of the TmFifo
* @vdev: array of the virtual devices running over the TmFifo
* @lock: lock to protect the TmFifo access
- * @rx_base: mapped register base address for the Rx FIFO
- * @tx_base: mapped register base address for the Tx FIFO
+ * @res0: mapped resource block 0
+ * @res1: mapped resource block 1
+ * @rx: rx io resource
+ * @tx: tx io resource
* @rx_fifo_size: number of entries of the Rx FIFO
* @tx_fifo_size: number of entries of the Tx FIFO
* @pend_events: pending bits for deferred events
@@ -155,8 +172,10 @@ struct mlxbf_tmfifo_irq_info {
struct mlxbf_tmfifo {
struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
struct mutex lock; /* TmFifo lock */
- void __iomem *rx_base;
- void __iomem *tx_base;
+ void __iomem *res0;
+ void __iomem *res1;
+ struct mlxbf_tmfifo_io rx;
+ struct mlxbf_tmfifo_io tx;
int rx_fifo_size;
int tx_fifo_size;
unsigned long pend_events;
@@ -472,7 +491,7 @@ static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo)
{
u64 sts;
- sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS);
+ sts = readq(fifo->rx.sts);
return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts);
}
@@ -489,7 +508,7 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
else
tx_reserve = 1;
- sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS);
+ sts = readq(fifo->tx.sts);
count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts);
return fifo->tx_fifo_size - tx_reserve - count;
}
@@ -525,7 +544,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
/* Write header. */
hdr.type = VIRTIO_ID_CONSOLE;
hdr.len = htons(size);
- writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+ writeq(*(u64 *)&hdr, fifo->tx.data);
/* Use spin-lock to protect the 'cons->tx_buf'. */
spin_lock_irqsave(&fifo->spin_lock[0], flags);
@@ -542,7 +561,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
memcpy((u8 *)&data + seg, cons->tx_buf.buf,
sizeof(u64) - seg);
}
- writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+ writeq(data, fifo->tx.data);
if (size >= sizeof(u64)) {
cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) %
@@ -573,7 +592,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
/* Read a word from FIFO for Rx. */
if (is_rx)
- data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
+ data = readq(fifo->rx.data);
if (vring->cur_len + sizeof(u64) <= len) {
/* The whole word. */
@@ -595,7 +614,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
/* Write the word into FIFO for Tx. */
if (!is_rx)
- writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+ writeq(data, fifo->tx.data);
}
/*
@@ -617,7 +636,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
/* Read/Write packet header. */
if (is_rx) {
/* Drain one word from the FIFO. */
- *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
+ *(u64 *)&hdr = readq(fifo->rx.data);
/* Skip the length 0 packets (keepalive). */
if (hdr.len == 0)
@@ -661,7 +680,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?
VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;
hdr.len = htons(vring->pkt_len - hdr_len);
- writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+ writeq(*(u64 *)&hdr, fifo->tx.data);
}
vring->cur_len = hdr_len;
@@ -1157,7 +1176,7 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
u64 ctl;
/* Get Tx FIFO size and set the low/high watermark. */
- ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
+ ctl = readq(fifo->tx.ctl);
fifo->tx_fifo_size =
FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl);
ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) |
@@ -1166,17 +1185,17 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) |
FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK,
fifo->tx_fifo_size - 1);
- writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
+ writeq(ctl, fifo->tx.ctl);
/* Get Rx FIFO size and set the low/high watermark. */
- ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
+ ctl = readq(fifo->rx.ctl);
fifo->rx_fifo_size =
FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl);
ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) |
FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0);
ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) |
FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1);
- writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
+ writeq(ctl, fifo->rx.ctl);
}
static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
@@ -1197,8 +1216,15 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev)
struct virtio_net_config net_config;
struct device *dev = &pdev->dev;
struct mlxbf_tmfifo *fifo;
+ u64 dev_id;
int i, rc;
+ rc = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &dev_id);
+ if (rc) {
+ dev_err(dev, "Cannot retrieve UID\n");
+ return rc;
+ }
+
fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
if (!fifo)
return -ENOMEM;
@@ -1209,14 +1235,30 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev)
mutex_init(&fifo->lock);
/* Get the resource of the Rx FIFO. */
- fifo->rx_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(fifo->rx_base))
- return PTR_ERR(fifo->rx_base);
+ fifo->res0 = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(fifo->res0))
+ return PTR_ERR(fifo->res0);
/* Get the resource of the Tx FIFO. */
- fifo->tx_base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(fifo->tx_base))
- return PTR_ERR(fifo->tx_base);
+ fifo->res1 = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(fifo->res1))
+ return PTR_ERR(fifo->res1);
+
+ if (dev_id == TMFIFO_BF3_UID) {
+ fifo->rx.ctl = fifo->res1 + MLXBF_TMFIFO_RX_CTL_BF3;
+ fifo->rx.sts = fifo->res1 + MLXBF_TMFIFO_RX_STS_BF3;
+ fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA_BF3;
+ fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL_BF3;
+ fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS_BF3;
+ fifo->tx.data = fifo->res0 + MLXBF_TMFIFO_TX_DATA_BF3;
+ } else {
+ fifo->rx.ctl = fifo->res0 + MLXBF_TMFIFO_RX_CTL;
+ fifo->rx.sts = fifo->res0 + MLXBF_TMFIFO_RX_STS;
+ fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA;
+ fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL;
+ fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS;
+ fifo->tx.data = fifo->res1 + MLXBF_TMFIFO_TX_DATA;
+ }
platform_set_drvdata(pdev, fifo);
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 6b51ad01f791..fb4ac4b08e89 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -6,6 +6,7 @@
menuconfig MIPS_PLATFORM_DEVICES
bool "MIPS Platform Specific Device Drivers"
default y
+ depends on MIPS
help
Say Y here to get to see options for device drivers of various
MIPS platforms, including vendor-specific netbook/laptop/desktop
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index 6748fe4ac5d5..def8d7ac541f 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -1596,16 +1596,32 @@ static void ssh_ptl_timeout_reap(struct work_struct *work)
ssh_ptl_tx_wakeup_packet(ptl);
}
-static bool ssh_ptl_rx_retransmit_check(struct ssh_ptl *ptl, u8 seq)
+static bool ssh_ptl_rx_retransmit_check(struct ssh_ptl *ptl, const struct ssh_frame *frame)
{
int i;
/*
+ * Ignore unsequenced packets. On some devices (notably Surface Pro 9),
+ * unsequenced events will always be sent with SEQ=0x00. Attempting to
+ * detect retransmission would thus just block all events.
+ *
+ * While sequence numbers would also allow detection of retransmitted
+ * packets in unsequenced communication, they have only ever been used
+ * to cover edge-cases in sequenced transmission. In particular, the
+ * only instance of packets being retransmitted (that we are aware of)
+ * is due to an ACK timeout. As this does not happen in unsequenced
+ * communication, skip the retransmission check for those packets
+ * entirely.
+ */
+ if (frame->type == SSH_FRAME_TYPE_DATA_NSQ)
+ return false;
+
+ /*
* Check if SEQ has been seen recently (i.e. packet was
* re-transmitted and we should ignore it).
*/
for (i = 0; i < ARRAY_SIZE(ptl->rx.blocked.seqs); i++) {
- if (likely(ptl->rx.blocked.seqs[i] != seq))
+ if (likely(ptl->rx.blocked.seqs[i] != frame->seq))
continue;
ptl_dbg(ptl, "ptl: ignoring repeated data packet\n");
@@ -1613,7 +1629,7 @@ static bool ssh_ptl_rx_retransmit_check(struct ssh_ptl *ptl, u8 seq)
}
/* Update list of blocked sequence IDs. */
- ptl->rx.blocked.seqs[ptl->rx.blocked.offset] = seq;
+ ptl->rx.blocked.seqs[ptl->rx.blocked.offset] = frame->seq;
ptl->rx.blocked.offset = (ptl->rx.blocked.offset + 1)
% ARRAY_SIZE(ptl->rx.blocked.seqs);
@@ -1624,7 +1640,7 @@ static void ssh_ptl_rx_dataframe(struct ssh_ptl *ptl,
const struct ssh_frame *frame,
const struct ssam_span *payload)
{
- if (ssh_ptl_rx_retransmit_check(ptl, frame->seq))
+ if (ssh_ptl_rx_retransmit_check(ptl, frame))
return;
ptl->ops.data_received(ptl, payload);
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index 585911020cea..023f126121d7 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -234,6 +234,19 @@ static const struct software_node *ssam_node_group_sl3[] = {
NULL,
};
+/* Devices for Surface Laptop 5. */
+static const struct software_node *ssam_node_group_sl5[] = {
+ &ssam_node_root,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_pprof,
+ &ssam_node_hid_main_keyboard,
+ &ssam_node_hid_main_touchpad,
+ &ssam_node_hid_main_iid5,
+ &ssam_node_hid_sam_ucm_ucsi,
+ NULL,
+};
+
/* Devices for Surface Laptop Studio. */
static const struct software_node *ssam_node_group_sls[] = {
&ssam_node_root,
@@ -268,6 +281,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
NULL,
};
+/* Devices for Surface Pro 8 */
static const struct software_node *ssam_node_group_sp8[] = {
&ssam_node_root,
&ssam_node_hub_kip,
@@ -284,6 +298,23 @@ static const struct software_node *ssam_node_group_sp8[] = {
NULL,
};
+/* Devices for Surface Pro 9 */
+static const struct software_node *ssam_node_group_sp9[] = {
+ &ssam_node_root,
+ &ssam_node_hub_kip,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_pprof,
+ /* TODO: Tablet mode switch (via POS subsystem) */
+ &ssam_node_hid_kip_keyboard,
+ &ssam_node_hid_kip_penstash,
+ &ssam_node_hid_kip_touchpad,
+ &ssam_node_hid_kip_fwupd,
+ &ssam_node_hid_sam_sensors,
+ &ssam_node_hid_sam_ucm_ucsi,
+ NULL,
+};
+
/* -- SSAM platform/meta-hub driver. ---------------------------------------- */
@@ -303,6 +334,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Pro 8 */
{ "MSHW0263", (unsigned long)ssam_node_group_sp8 },
+ /* Surface Pro 9 */
+ { "MSHW0343", (unsigned long)ssam_node_group_sp9 },
+
/* Surface Book 2 */
{ "MSHW0107", (unsigned long)ssam_node_group_gen5 },
@@ -324,6 +358,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop 4 (13", Intel) */
{ "MSHW0250", (unsigned long)ssam_node_group_sl3 },
+ /* Surface Laptop 5 */
+ { "MSHW0350", (unsigned long)ssam_node_group_sl5 },
+
/* Surface Laptop Go 1 */
{ "MSHW0118", (unsigned long)ssam_node_group_slg1 },
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
index 242fb690dcaf..2755601f979c 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -239,13 +239,12 @@ static int surface_button_add(struct acpi_device *device)
return error;
}
-static int surface_button_remove(struct acpi_device *device)
+static void surface_button_remove(struct acpi_device *device)
{
struct surface_button *button = acpi_driver_data(device);
input_unregister_device(button->input);
kfree(button);
- return 0;
}
static SIMPLE_DEV_PM_OPS(surface_button_pm,
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f5312f51de19..5692385e2d26 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -424,24 +424,7 @@ config GPD_POCKET_FAN
of the CPU temperature. Say Y or M if the kernel may be used on a
GPD pocket.
-config HP_ACCEL
- tristate "HP laptop accelerometer"
- depends on INPUT && ACPI
- depends on SERIO_I8042
- select SENSORS_LIS3LV02D
- select NEW_LEDS
- select LEDS_CLASS
- help
- This driver provides support for the "Mobile Data Protection System 3D"
- or "3D DriveGuard" feature of HP laptops. On such systems the driver
- should load automatically (via ACPI alias).
-
- Support for a led indicating disk protection will be provided as
- hp::hddprotect. For more information on the feature, refer to
- Documentation/misc-devices/lis3lv02d.rst.
-
- To compile this driver as a module, choose M here: the module will
- be called hp_accel.
+source "drivers/platform/x86/hp/Kconfig"
config WIRELESS_HOTKEY
tristate "Wireless hotkey button"
@@ -455,30 +438,6 @@ config WIRELESS_HOTKEY
To compile this driver as a module, choose M here: the module will
be called wireless-hotkey.
-config HP_WMI
- tristate "HP WMI extras"
- depends on ACPI_WMI
- depends on INPUT
- depends on RFKILL || RFKILL = n
- select INPUT_SPARSEKMAP
- select ACPI_PLATFORM_PROFILE
- select HWMON
- help
- Say Y here if you want to support WMI-based hotkeys on HP laptops and
- to read data from WMI such as docking or ambient light sensor state.
-
- To compile this driver as a module, choose M here: the module will
- be called hp-wmi.
-
-config TC1100_WMI
- tristate "HP Compaq TC1100 Tablet WMI Extras"
- depends on !X86_64
- depends on ACPI
- depends on ACPI_WMI
- help
- This is a driver for the WMI extensions (wireless and bluetooth power
- control) of the HP Compaq TC1100 tablet.
-
config IBM_RTL
tristate "Device driver to enable PRTL support"
depends on PCI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 5a428caa654a..1d3d1b02541b 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -55,9 +55,7 @@ obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o
obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
# Hewlett Packard
-obj-$(CONFIG_HP_ACCEL) += hp_accel.o
-obj-$(CONFIG_HP_WMI) += hp-wmi.o
-obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
+obj-$(CONFIG_X86_PLATFORM_DRIVERS_HP) += hp/
# Hewlett Packard Enterprise
obj-$(CONFIG_UV_SYSFS) += uv_sysfs.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 18224f9a5bc0..ee67efdd5499 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -566,6 +566,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
},
{
.callback = set_force_caps,
+ .ident = "Acer Aspire Switch V 10 SW5-017",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
+ },
+ .driver_data = (void *)ACER_CAP_KBD_DOCK,
+ },
+ {
+ .callback = set_force_caps,
.ident = "Acer One 10 (S1003)",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c
index 96e790e639a2..439d282aafd1 100644
--- a/drivers/platform/x86/amd/pmc.c
+++ b/drivers/platform/x86/amd/pmc.c
@@ -276,7 +276,6 @@ static const struct file_operations amd_pmc_stb_debugfs_fops_v2 = {
.release = amd_pmc_stb_debugfs_release_v2,
};
-#if defined(CONFIG_SUSPEND) || defined(CONFIG_DEBUG_FS)
static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
{
if (dev->cpu_id == AMD_CPU_ID_PCO) {
@@ -351,7 +350,6 @@ static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table
memcpy_fromio(table, pdev->smu_virt_addr, sizeof(struct smu_metrics));
return 0;
}
-#endif /* CONFIG_SUSPEND || CONFIG_DEBUG_FS */
#ifdef CONFIG_SUSPEND
static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev)
@@ -741,8 +739,14 @@ static void amd_pmc_s2idle_prepare(void)
static void amd_pmc_s2idle_check(void)
{
struct amd_pmc_dev *pdev = &pmc;
+ struct smu_metrics table;
int rc;
+ /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */
+ if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) &&
+ table.s0i3_last_entry_status)
+ usleep_range(10000, 20000);
+
/* Dump the IdleMask before we add to the STB */
amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
@@ -964,6 +968,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = {
{"AMDI0006", 0},
{"AMDI0007", 0},
{"AMDI0008", 0},
+ {"AMDI0009", 0},
{"AMD0004", 0},
{"AMD0005", 0},
{ }
diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c
index 668c7c0fea83..3f9731a2ac28 100644
--- a/drivers/platform/x86/amd/pmf/cnqf.c
+++ b/drivers/platform/x86/amd/pmf/cnqf.c
@@ -158,100 +158,100 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l
return 0;
}
-static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output out)
+static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out)
{
struct cnqf_tran_params *tp;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET];
- tp->time_constant = out.t_balanced_to_quiet;
+ tp->time_constant = out->t_balanced_to_quiet;
tp->target_mode = CNQF_MODE_QUIET;
tp->shifting_up = false;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];
- tp->time_constant = out.t_balanced_to_perf;
+ tp->time_constant = out->t_balanced_to_perf;
tp->target_mode = CNQF_MODE_PERFORMANCE;
tp->shifting_up = true;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];
- tp->time_constant = out.t_quiet_to_balanced;
+ tp->time_constant = out->t_quiet_to_balanced;
tp->target_mode = CNQF_MODE_BALANCE;
tp->shifting_up = true;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];
- tp->time_constant = out.t_perf_to_balanced;
+ tp->time_constant = out->t_perf_to_balanced;
tp->target_mode = CNQF_MODE_BALANCE;
tp->shifting_up = false;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];
- tp->time_constant = out.t_turbo_to_perf;
+ tp->time_constant = out->t_turbo_to_perf;
tp->target_mode = CNQF_MODE_PERFORMANCE;
tp->shifting_up = false;
tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO];
- tp->time_constant = out.t_perf_to_turbo;
+ tp->time_constant = out->t_perf_to_turbo;
tp->target_mode = CNQF_MODE_TURBO;
tp->shifting_up = true;
}
-static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output out)
+static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out)
{
struct cnqf_mode_settings *ms;
/* Quiet Mode */
ms = &config_store.mode_set[idx][CNQF_MODE_QUIET];
- ms->power_floor = out.ps[APMF_CNQF_QUIET].pfloor;
- ms->power_control.fppt = out.ps[APMF_CNQF_QUIET].fppt;
- ms->power_control.sppt = out.ps[APMF_CNQF_QUIET].sppt;
- ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_QUIET].sppt_apu_only;
- ms->power_control.spl = out.ps[APMF_CNQF_QUIET].spl;
- ms->power_control.stt_min = out.ps[APMF_CNQF_QUIET].stt_min_limit;
+ ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor;
+ ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt;
+ ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt;
+ ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only;
+ ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl;
+ ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit;
ms->power_control.stt_skin_temp[STT_TEMP_APU] =
- out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU];
+ out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU];
ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
- out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2];
- ms->fan_control.fan_id = out.ps[APMF_CNQF_QUIET].fan_id;
+ out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2];
+ ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id;
/* Balance Mode */
ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE];
- ms->power_floor = out.ps[APMF_CNQF_BALANCE].pfloor;
- ms->power_control.fppt = out.ps[APMF_CNQF_BALANCE].fppt;
- ms->power_control.sppt = out.ps[APMF_CNQF_BALANCE].sppt;
- ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_BALANCE].sppt_apu_only;
- ms->power_control.spl = out.ps[APMF_CNQF_BALANCE].spl;
- ms->power_control.stt_min = out.ps[APMF_CNQF_BALANCE].stt_min_limit;
+ ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor;
+ ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt;
+ ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt;
+ ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only;
+ ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl;
+ ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit;
ms->power_control.stt_skin_temp[STT_TEMP_APU] =
- out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU];
+ out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU];
ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
- out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2];
- ms->fan_control.fan_id = out.ps[APMF_CNQF_BALANCE].fan_id;
+ out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2];
+ ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id;
/* Performance Mode */
ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE];
- ms->power_floor = out.ps[APMF_CNQF_PERFORMANCE].pfloor;
- ms->power_control.fppt = out.ps[APMF_CNQF_PERFORMANCE].fppt;
- ms->power_control.sppt = out.ps[APMF_CNQF_PERFORMANCE].sppt;
- ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_PERFORMANCE].sppt_apu_only;
- ms->power_control.spl = out.ps[APMF_CNQF_PERFORMANCE].spl;
- ms->power_control.stt_min = out.ps[APMF_CNQF_PERFORMANCE].stt_min_limit;
+ ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor;
+ ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt;
+ ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt;
+ ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only;
+ ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl;
+ ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit;
ms->power_control.stt_skin_temp[STT_TEMP_APU] =
- out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU];
+ out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU];
ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
- out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2];
- ms->fan_control.fan_id = out.ps[APMF_CNQF_PERFORMANCE].fan_id;
+ out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2];
+ ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id;
/* Turbo Mode */
ms = &config_store.mode_set[idx][CNQF_MODE_TURBO];
- ms->power_floor = out.ps[APMF_CNQF_TURBO].pfloor;
- ms->power_control.fppt = out.ps[APMF_CNQF_TURBO].fppt;
- ms->power_control.sppt = out.ps[APMF_CNQF_TURBO].sppt;
- ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_TURBO].sppt_apu_only;
- ms->power_control.spl = out.ps[APMF_CNQF_TURBO].spl;
- ms->power_control.stt_min = out.ps[APMF_CNQF_TURBO].stt_min_limit;
+ ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor;
+ ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt;
+ ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt;
+ ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only;
+ ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl;
+ ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit;
ms->power_control.stt_skin_temp[STT_TEMP_APU] =
- out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU];
+ out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU];
ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
- out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2];
- ms->fan_control.fan_id = out.ps[APMF_CNQF_TURBO].fan_id;
+ out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2];
+ ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id;
}
static int amd_pmf_check_flags(struct amd_pmf_dev *dev)
@@ -284,8 +284,8 @@ static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev)
return ret;
}
- amd_pmf_update_mode_set(i, out);
- amd_pmf_update_trans_data(i, out);
+ amd_pmf_update_mode_set(i, &out);
+ amd_pmf_update_trans_data(i, &out);
amd_pmf_update_power_threshold(i);
for (j = 0; j < CNQF_MODE_MAX; j++) {
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 47b2f8bb6fb5..761029f39314 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1901,7 +1901,7 @@ fail_platform:
return result;
}
-static int asus_acpi_remove(struct acpi_device *device)
+static void asus_acpi_remove(struct acpi_device *device)
{
struct asus_laptop *asus = acpi_driver_data(device);
@@ -1914,7 +1914,6 @@ static int asus_acpi_remove(struct acpi_device *device)
kfree(asus->name);
kfree(asus);
- return 0;
}
static const struct acpi_device_id asus_device_ids[] = {
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index d3e7171928e5..abf01e00b799 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -175,7 +175,7 @@ static int asus_wireless_add(struct acpi_device *adev)
return err;
}
-static int asus_wireless_remove(struct acpi_device *adev)
+static void asus_wireless_remove(struct acpi_device *adev)
{
struct asus_wireless_data *data = acpi_driver_data(adev);
@@ -183,7 +183,6 @@ static int asus_wireless_remove(struct acpi_device *adev)
devm_led_classdev_unregister(&adev->dev, &data->led);
destroy_workqueue(data->wq);
}
- return 0;
}
static struct acpi_driver asus_wireless_driver = {
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 6e8e093f96b3..6f81b2844dcb 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -883,7 +883,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
static DEVICE_ATTR_RW(charge_control_end_threshold);
-static int asus_wmi_battery_add(struct power_supply *battery)
+static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
/* The WMI method does not provide a way to specific a battery, so we
* just assume it is the first battery.
@@ -910,7 +910,7 @@ static int asus_wmi_battery_add(struct power_supply *battery)
return 0;
}
-static int asus_wmi_battery_remove(struct power_supply *battery)
+static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_file(&battery->dev,
&dev_attr_charge_control_end_threshold);
@@ -1738,6 +1738,8 @@ static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
cpu_to_le32(ports_available));
+ pci_dev_put(xhci_pdev);
+
pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
orig_ports_available, ports_available);
}
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 9309ab5792cb..8b6a14611859 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -418,11 +418,11 @@ failed_sensitivity:
return error;
}
-static int cmpc_accel_remove_v4(struct acpi_device *acpi)
+static void cmpc_accel_remove_v4(struct acpi_device *acpi)
{
device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
- return cmpc_remove_acpi_notify_device(acpi);
+ cmpc_remove_acpi_notify_device(acpi);
}
static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
@@ -648,10 +648,10 @@ failed_file:
return error;
}
-static int cmpc_accel_remove(struct acpi_device *acpi)
+static void cmpc_accel_remove(struct acpi_device *acpi)
{
device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
- return cmpc_remove_acpi_notify_device(acpi);
+ cmpc_remove_acpi_notify_device(acpi);
}
static const struct acpi_device_id cmpc_accel_device_ids[] = {
@@ -727,9 +727,9 @@ static int cmpc_tablet_add(struct acpi_device *acpi)
cmpc_tablet_idev_init);
}
-static int cmpc_tablet_remove(struct acpi_device *acpi)
+static void cmpc_tablet_remove(struct acpi_device *acpi)
{
- return cmpc_remove_acpi_notify_device(acpi);
+ cmpc_remove_acpi_notify_device(acpi);
}
#ifdef CONFIG_PM_SLEEP
@@ -974,7 +974,7 @@ out_bd:
return retval;
}
-static int cmpc_ipml_remove(struct acpi_device *acpi)
+static void cmpc_ipml_remove(struct acpi_device *acpi)
{
struct ipml200_dev *ipml;
@@ -988,8 +988,6 @@ static int cmpc_ipml_remove(struct acpi_device *acpi)
}
kfree(ipml);
-
- return 0;
}
static const struct acpi_device_id cmpc_ipml_device_ids[] = {
@@ -1055,9 +1053,9 @@ static int cmpc_keys_add(struct acpi_device *acpi)
cmpc_keys_idev_init);
}
-static int cmpc_keys_remove(struct acpi_device *acpi)
+static void cmpc_keys_remove(struct acpi_device *acpi)
{
- return cmpc_remove_acpi_notify_device(acpi);
+ cmpc_remove_acpi_notify_device(acpi);
}
static const struct acpi_device_id cmpc_keys_device_ids[] = {
diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
index 25421e061c47..d319de8f2132 100644
--- a/drivers/platform/x86/dell/Kconfig
+++ b/drivers/platform/x86/dell/Kconfig
@@ -189,6 +189,19 @@ config DELL_WMI_DESCRIPTOR
default n
depends on ACPI_WMI
+config DELL_WMI_DDV
+ tristate "Dell WMI sensors Support"
+ default m
+ depends on ACPI_BATTERY
+ depends on ACPI_WMI
+ help
+ This option adds support for WMI-based sensors like
+ battery temperature sensors found on some Dell notebooks.
+ It also supports reading of the battery ePPID.
+
+ To compile this drivers as a module, choose M here: the module will
+ be called dell-wmi-ddv.
+
config DELL_WMI_LED
tristate "External LED on Dell Business Netbooks"
default m
diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
index ddba1df71e80..1b8942426622 100644
--- a/drivers/platform/x86/dell/Makefile
+++ b/drivers/platform/x86/dell/Makefile
@@ -19,5 +19,6 @@ dell-wmi-objs := dell-wmi-base.o
dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
+obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index a34e07ef2c79..a9477e5432e4 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -398,10 +398,10 @@ static ssize_t show_control_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (lighting_control_state == LEGACY_BOOTING)
- return scnprintf(buf, PAGE_SIZE, "[booting] running suspend\n");
+ return sysfs_emit(buf, "[booting] running suspend\n");
else if (lighting_control_state == LEGACY_SUSPEND)
- return scnprintf(buf, PAGE_SIZE, "booting running [suspend]\n");
- return scnprintf(buf, PAGE_SIZE, "booting [running] suspend\n");
+ return sysfs_emit(buf, "booting running [suspend]\n");
+ return sysfs_emit(buf, "booting [running] suspend\n");
}
static ssize_t store_control_state(struct device *dev,
@@ -547,14 +547,12 @@ static ssize_t show_hdmi_cable(struct device *dev,
(u32 *) &out_data);
if (ACPI_SUCCESS(status)) {
if (out_data == 0)
- return scnprintf(buf, PAGE_SIZE,
- "[unconnected] connected unknown\n");
+ return sysfs_emit(buf, "[unconnected] connected unknown\n");
else if (out_data == 1)
- return scnprintf(buf, PAGE_SIZE,
- "unconnected [connected] unknown\n");
+ return sysfs_emit(buf, "unconnected [connected] unknown\n");
}
pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status);
- return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n");
+ return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
static ssize_t show_hdmi_source(struct device *dev,
@@ -571,14 +569,12 @@ static ssize_t show_hdmi_source(struct device *dev,
if (ACPI_SUCCESS(status)) {
if (out_data == 1)
- return scnprintf(buf, PAGE_SIZE,
- "[input] gpu unknown\n");
+ return sysfs_emit(buf, "[input] gpu unknown\n");
else if (out_data == 2)
- return scnprintf(buf, PAGE_SIZE,
- "input [gpu] unknown\n");
+ return sysfs_emit(buf, "input [gpu] unknown\n");
}
pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
- return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
+ return sysfs_emit(buf, "input gpu [unknown]\n");
}
static ssize_t toggle_hdmi_source(struct device *dev,
@@ -652,14 +648,12 @@ static ssize_t show_amplifier_status(struct device *dev,
(u32 *) &out_data);
if (ACPI_SUCCESS(status)) {
if (out_data == 0)
- return scnprintf(buf, PAGE_SIZE,
- "[unconnected] connected unknown\n");
+ return sysfs_emit(buf, "[unconnected] connected unknown\n");
else if (out_data == 1)
- return scnprintf(buf, PAGE_SIZE,
- "unconnected [connected] unknown\n");
+ return sysfs_emit(buf, "unconnected [connected] unknown\n");
}
pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status);
- return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n");
+ return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL);
@@ -706,17 +700,14 @@ static ssize_t show_deepsleep_status(struct device *dev,
(u32 *) &out_data);
if (ACPI_SUCCESS(status)) {
if (out_data == 0)
- return scnprintf(buf, PAGE_SIZE,
- "[disabled] s5 s5_s4\n");
+ return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
else if (out_data == 1)
- return scnprintf(buf, PAGE_SIZE,
- "disabled [s5] s5_s4\n");
+ return sysfs_emit(buf, "disabled [s5] s5_s4\n");
else if (out_data == 2)
- return scnprintf(buf, PAGE_SIZE,
- "disabled s5 [s5_s4]\n");
+ return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
}
pr_err("alienware-wmi: unknown deep sleep status: %d\n", status);
- return scnprintf(buf, PAGE_SIZE, "disabled s5 s5_s4 [unknown]\n");
+ return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
}
static ssize_t toggle_deepsleep(struct device *dev,
diff --git a/drivers/platform/x86/dell/dell-rbtn.c b/drivers/platform/x86/dell/dell-rbtn.c
index a89fad47ff13..aa0e6c907494 100644
--- a/drivers/platform/x86/dell/dell-rbtn.c
+++ b/drivers/platform/x86/dell/dell-rbtn.c
@@ -206,7 +206,7 @@ static void rbtn_input_event(struct rbtn_data *rbtn_data)
*/
static int rbtn_add(struct acpi_device *device);
-static int rbtn_remove(struct acpi_device *device);
+static void rbtn_remove(struct acpi_device *device);
static void rbtn_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id rbtn_ids[] = {
@@ -426,7 +426,7 @@ static int rbtn_add(struct acpi_device *device)
}
-static int rbtn_remove(struct acpi_device *device)
+static void rbtn_remove(struct acpi_device *device)
{
struct rbtn_data *rbtn_data = device->driver_data;
@@ -443,8 +443,6 @@ static int rbtn_remove(struct acpi_device *device)
rbtn_acquire(device, false);
device->driver_data = NULL;
-
- return 0;
}
static void rbtn_notify(struct acpi_device *device, u32 event)
diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c
new file mode 100644
index 000000000000..2bb449845d14
--- /dev/null
+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux driver for WMI sensor information on Dell notebooks.
+ *
+ * Copyright (C) 2022 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#define pr_format(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/kernel.h>
+#include <linux/kstrtox.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/limits.h>
+#include <linux/power_supply.h>
+#include <linux/printk.h>
+#include <linux/seq_file.h>
+#include <linux/sysfs.h>
+#include <linux/wmi.h>
+
+#include <acpi/battery.h>
+
+#define DRIVER_NAME "dell-wmi-ddv"
+
+#define DELL_DDV_SUPPORTED_INTERFACE 2
+#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"
+
+#define DELL_EPPID_LENGTH 20
+#define DELL_EPPID_EXT_LENGTH 23
+
+enum dell_ddv_method {
+ DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,
+ DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,
+ DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03,
+ DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04,
+ DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05,
+ DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06,
+ DELL_DDV_BATTERY_TEMPERATURE = 0x07,
+ DELL_DDV_BATTERY_CURRENT = 0x08,
+ DELL_DDV_BATTERY_VOLTAGE = 0x09,
+ DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A,
+ DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B,
+ DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C,
+ DELL_DDV_BATTERY_EPPID = 0x0D,
+ DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,
+ DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,
+ DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,
+
+ DELL_DDV_INTERFACE_VERSION = 0x12,
+
+ DELL_DDV_FAN_SENSOR_INFORMATION = 0x20,
+ DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,
+};
+
+struct dell_wmi_ddv_data {
+ struct acpi_battery_hook hook;
+ struct device_attribute temp_attr;
+ struct device_attribute eppid_attr;
+ struct wmi_device *wdev;
+};
+
+static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,
+ union acpi_object **result, acpi_object_type type)
+{
+ struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+ const struct acpi_buffer in = {
+ .length = sizeof(arg),
+ .pointer = &arg,
+ };
+ union acpi_object *obj;
+ acpi_status ret;
+
+ ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);
+ if (ACPI_FAILURE(ret))
+ return -EIO;
+
+ obj = out.pointer;
+ if (!obj)
+ return -ENODATA;
+
+ if (obj->type != type) {
+ kfree(obj);
+ return -EIO;
+ }
+
+ *result = obj;
+
+ return 0;
+}
+
+static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method,
+ u32 arg, u32 *res)
+{
+ union acpi_object *obj;
+ int ret;
+
+ ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER);
+ if (ret < 0)
+ return ret;
+
+ if (obj->integer.value <= U32_MAX)
+ *res = (u32)obj->integer.value;
+ else
+ ret = -ERANGE;
+
+ kfree(obj);
+
+ return ret;
+}
+
+static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method,
+ u32 arg, union acpi_object **result)
+{
+ union acpi_object *obj;
+ u64 buffer_size;
+ int ret;
+
+ ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE);
+ if (ret < 0)
+ return ret;
+
+ if (obj->package.count != 2)
+ goto err_free;
+
+ if (obj->package.elements[0].type != ACPI_TYPE_INTEGER)
+ goto err_free;
+
+ buffer_size = obj->package.elements[0].integer.value;
+
+ if (obj->package.elements[1].type != ACPI_TYPE_BUFFER)
+ goto err_free;
+
+ if (buffer_size > obj->package.elements[1].buffer.length) {
+ dev_warn(&wdev->dev,
+ FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",
+ buffer_size, obj->package.elements[1].buffer.length);
+
+ goto err_free;
+ }
+
+ *result = obj;
+
+ return 0;
+
+err_free:
+ kfree(obj);
+
+ return -EIO;
+}
+
+static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,
+ u32 arg, union acpi_object **result)
+{
+ return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);
+}
+
+static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
+{
+ const char *uid_str;
+
+ uid_str = acpi_device_uid(acpi_dev);
+ if (!uid_str)
+ return -ENODEV;
+
+ return kstrtou32(uid_str, 10, index);
+}
+
+static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr);
+ u32 index, value;
+ int ret;
+
+ ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
+ if (ret < 0)
+ return ret;
+
+ ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", DIV_ROUND_CLOSEST(value, 10));
+}
+
+static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr);
+ union acpi_object *obj;
+ u32 index;
+ int ret;
+
+ ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
+ if (ret < 0)
+ return ret;
+
+ ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj);
+ if (ret < 0)
+ return ret;
+
+ if (obj->string.length != DELL_EPPID_LENGTH && obj->string.length != DELL_EPPID_EXT_LENGTH)
+ dev_info_once(&data->wdev->dev, FW_INFO "Suspicious ePPID length (%d)\n",
+ obj->string.length);
+
+ ret = sysfs_emit(buf, "%s\n", obj->string.pointer);
+
+ kfree(obj);
+
+ return ret;
+}
+
+static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
+ u32 index;
+ int ret;
+
+ /* Return 0 instead of error to avoid being unloaded */
+ ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index);
+ if (ret < 0)
+ return 0;
+
+ ret = device_create_file(&battery->dev, &data->temp_attr);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(&battery->dev, &data->eppid_attr);
+ if (ret < 0) {
+ device_remove_file(&battery->dev, &data->temp_attr);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
+
+ device_remove_file(&battery->dev, &data->temp_attr);
+ device_remove_file(&battery->dev, &data->eppid_attr);
+
+ return 0;
+}
+
+static void dell_wmi_ddv_battery_remove(void *data)
+{
+ struct acpi_battery_hook *hook = data;
+
+ battery_hook_unregister(hook);
+}
+
+static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)
+{
+ data->hook.name = "Dell DDV Battery Extension";
+ data->hook.add_battery = dell_wmi_ddv_add_battery;
+ data->hook.remove_battery = dell_wmi_ddv_remove_battery;
+
+ sysfs_attr_init(&data->temp_attr.attr);
+ data->temp_attr.attr.name = "temp";
+ data->temp_attr.attr.mode = 0444;
+ data->temp_attr.show = temp_show;
+
+ sysfs_attr_init(&data->eppid_attr.attr);
+ data->eppid_attr.attr.name = "eppid";
+ data->eppid_attr.attr.mode = 0444;
+ data->eppid_attr.show = eppid_show;
+
+ battery_hook_register(&data->hook);
+
+ return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook);
+}
+
+static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)
+{
+ struct device *dev = seq->private;
+ struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
+ union acpi_object *obj;
+ u64 size;
+ u8 *buf;
+ int ret;
+
+ ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj);
+ if (ret < 0)
+ return ret;
+
+ size = obj->package.elements[0].integer.value;
+ buf = obj->package.elements[1].buffer.pointer;
+ ret = seq_write(seq, buf, size);
+ kfree(obj);
+
+ return ret;
+}
+
+static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset)
+{
+ return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION);
+}
+
+static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset)
+{
+ return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION);
+}
+
+static void dell_wmi_ddv_debugfs_remove(void *data)
+{
+ struct dentry *entry = data;
+
+ debugfs_remove(entry);
+}
+
+static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev)
+{
+ struct dentry *entry;
+ char name[64];
+
+ scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));
+ entry = debugfs_create_dir(name, NULL);
+
+ debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry,
+ dell_wmi_ddv_fan_read);
+ debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry,
+ dell_wmi_ddv_temp_read);
+
+ devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry);
+}
+
+static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
+{
+ struct dell_wmi_ddv_data *data;
+ u32 version;
+ int ret;
+
+ ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);
+ if (version != DELL_DDV_SUPPORTED_INTERFACE)
+ return -ENODEV;
+
+ data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ dev_set_drvdata(&wdev->dev, data);
+ data->wdev = wdev;
+
+ dell_wmi_ddv_debugfs_init(wdev);
+
+ return dell_wmi_ddv_battery_add(data);
+}
+
+static const struct wmi_device_id dell_wmi_ddv_id_table[] = {
+ { DELL_DDV_GUID, NULL },
+ { }
+};
+MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);
+
+static struct wmi_driver dell_wmi_ddv_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .id_table = dell_wmi_ddv_id_table,
+ .probe = dell_wmi_ddv_probe,
+};
+module_wmi_driver(dell_wmi_ddv_driver);
+
+MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
+MODULE_DESCRIPTION("Dell WMI sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index a388a28b6f2a..62b71e8e3567 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1440,7 +1440,7 @@ fail_platform:
return result;
}
-static int eeepc_acpi_remove(struct acpi_device *device)
+static void eeepc_acpi_remove(struct acpi_device *device)
{
struct eeepc_laptop *eeepc = acpi_driver_data(device);
@@ -1451,7 +1451,6 @@ static int eeepc_acpi_remove(struct acpi_device *device)
eeepc_platform_exit(eeepc);
kfree(eeepc);
- return 0;
}
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index b543d117b12c..085e044e888e 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -847,15 +847,13 @@ err_free_fifo:
return ret;
}
-static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
+static void acpi_fujitsu_laptop_remove(struct acpi_device *device)
{
struct fujitsu_laptop *priv = acpi_driver_data(device);
fujitsu_laptop_platform_remove(device);
kfifo_free(&priv->fifo);
-
- return 0;
}
static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 7fb7fe5eb55a..17f08ce7552d 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -484,12 +484,11 @@ static int acpi_fujitsu_add(struct acpi_device *adev)
return 0;
}
-static int acpi_fujitsu_remove(struct acpi_device *adev)
+static void acpi_fujitsu_remove(struct acpi_device *adev)
{
free_irq(fujitsu.irq, fujitsu_interrupt);
release_region(fujitsu.io_base, fujitsu.io_length);
input_fujitsu_remove();
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/platform/x86/hp/Kconfig b/drivers/platform/x86/hp/Kconfig
new file mode 100644
index 000000000000..ae165955311c
--- /dev/null
+++ b/drivers/platform/x86/hp/Kconfig
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# X86 Platform Specific Drivers
+#
+menuconfig X86_PLATFORM_DRIVERS_HP
+ bool "HP X86 Platform Specific Device Drivers"
+ depends on X86_PLATFORM_DEVICES
+ help
+ Say Y here to get to see options for device drivers for various
+ HP x86 platforms, including vendor-specific laptop extension drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if X86_PLATFORM_DRIVERS_HP
+
+config HP_ACCEL
+ tristate "HP laptop accelerometer"
+ default m
+ depends on INPUT && ACPI
+ depends on SERIO_I8042
+ select SENSORS_LIS3LV02D
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This driver provides support for the "Mobile Data Protection System 3D"
+ or "3D DriveGuard" feature of HP laptops. On such systems the driver
+ should load automatically (via ACPI alias).
+
+ Support for a led indicating disk protection will be provided as
+ hp::hddprotect. For more information on the feature, refer to
+ Documentation/misc-devices/lis3lv02d.rst.
+
+ To compile this driver as a module, choose M here: the module will
+ be called hp_accel.
+
+config HP_WMI
+ tristate "HP WMI extras"
+ default m
+ depends on ACPI_WMI
+ depends on INPUT
+ depends on RFKILL || RFKILL = n
+ select INPUT_SPARSEKMAP
+ select ACPI_PLATFORM_PROFILE
+ select HWMON
+ help
+ Say Y here if you want to support WMI-based hotkeys on HP laptops and
+ to read data from WMI such as docking or ambient light sensor state.
+
+ To compile this driver as a module, choose M here: the module will
+ be called hp-wmi.
+
+config TC1100_WMI
+ tristate "HP Compaq TC1100 Tablet WMI Extras"
+ default m
+ depends on !X86_64
+ depends on ACPI
+ depends on ACPI_WMI
+ help
+ This is a driver for the WMI extensions (wireless and bluetooth power
+ control) of the HP Compaq TC1100 tablet.
+
+endif # X86_PLATFORM_DRIVERS_HP
diff --git a/drivers/platform/x86/hp/Makefile b/drivers/platform/x86/hp/Makefile
new file mode 100644
index 000000000000..db1eed4cd7c7
--- /dev/null
+++ b/drivers/platform/x86/hp/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for linux/drivers/platform/x86/hp
+# HP x86 Platform-Specific Drivers
+#
+
+# Hewlett Packard
+obj-$(CONFIG_HP_ACCEL) += hp_accel.o
+obj-$(CONFIG_HP_WMI) += hp-wmi.o
+obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 627a6d0eaf83..0a99058be813 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -90,6 +90,7 @@ enum hp_wmi_event_ids {
HPWMI_PEAKSHIFT_PERIOD = 0x0F,
HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
HPWMI_SANITIZATION_MODE = 0x17,
+ HPWMI_SMART_EXPERIENCE_APP = 0x21,
};
/*
@@ -859,6 +860,8 @@ static void hp_wmi_notify(u32 value, void *context)
break;
case HPWMI_SANITIZATION_MODE:
break;
+ case HPWMI_SMART_EXPERIENCE_APP:
+ break;
default:
pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
break;
@@ -1300,8 +1303,16 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wwan_rfkill = NULL;
rfkill2_count = 0;
- if (hp_wmi_rfkill_setup(device))
- hp_wmi_rfkill2_setup(device);
+ /*
+ * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that
+ * BIOS no longer controls the power for the wireless
+ * devices. All features supported by this command will no
+ * longer be supported.
+ */
+ if (!hp_wmi_bios_2009_later()) {
+ if (hp_wmi_rfkill_setup(device))
+ hp_wmi_rfkill2_setup(device);
+ }
err = hp_wmi_hwmon_init();
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp/hp_accel.c
index e9f852f7c27f..6477591747cf 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp/hp_accel.c
@@ -26,7 +26,7 @@
#include <linux/acpi.h>
#include <linux/i8042.h>
#include <linux/serio.h>
-#include "../../misc/lis3lv02d/lis3lv02d.h"
+#include "../../../misc/lis3lv02d/lis3lv02d.h"
/* Delayed LEDs infrastructure ------------------------------------ */
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/hp/tc1100-wmi.c
index ded26213c420..ded26213c420 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/hp/tc1100-wmi.c
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 5873c2663a65..2df1b2d5e3ea 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -63,7 +63,6 @@ struct huawei_wmi {
bool fn_lock_available;
struct huawei_wmi_debug debug;
- struct input_dev *idev[2];
struct led_classdev cdev;
struct device *dev;
@@ -323,12 +322,12 @@ static int huawei_wmi_battery_get(int *start, int *end)
u8 ret[0x100];
int err, i;
- err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100);
+ err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, sizeof(ret));
if (err)
return err;
/* Find the last two non-zero values. Return status is ignored. */
- i = 0xff;
+ i = ARRAY_SIZE(ret) - 1;
do {
if (start)
*start = ret[i-1];
@@ -468,7 +467,7 @@ static DEVICE_ATTR_RW(charge_control_start_threshold);
static DEVICE_ATTR_RW(charge_control_end_threshold);
static DEVICE_ATTR_RW(charge_control_thresholds);
-static int huawei_wmi_battery_add(struct power_supply *battery)
+static int huawei_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
int err = 0;
@@ -483,7 +482,7 @@ static int huawei_wmi_battery_add(struct power_supply *battery)
return err;
}
-static int huawei_wmi_battery_remove(struct power_supply *battery)
+static int huawei_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold);
device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold);
@@ -756,23 +755,34 @@ static void huawei_wmi_input_notify(u32 value, void *context)
kfree(response.pointer);
}
-static int huawei_wmi_input_setup(struct device *dev,
- const char *guid,
- struct input_dev **idev)
+static int huawei_wmi_input_setup(struct device *dev, const char *guid)
{
- *idev = devm_input_allocate_device(dev);
- if (!*idev)
+ struct input_dev *idev;
+ acpi_status status;
+ int err;
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev)
return -ENOMEM;
- (*idev)->name = "Huawei WMI hotkeys";
- (*idev)->phys = "wmi/input0";
- (*idev)->id.bustype = BUS_HOST;
- (*idev)->dev.parent = dev;
+ idev->name = "Huawei WMI hotkeys";
+ idev->phys = "wmi/input0";
+ idev->id.bustype = BUS_HOST;
+ idev->dev.parent = dev;
+
+ err = sparse_keymap_setup(idev, huawei_wmi_keymap, NULL);
+ if (err)
+ return err;
+
+ err = input_register_device(idev);
+ if (err)
+ return err;
+
+ status = wmi_install_notify_handler(guid, huawei_wmi_input_notify, idev);
+ if (ACPI_FAILURE(status))
+ return -EIO;
- return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) ||
- input_register_device(*idev) ||
- wmi_install_notify_handler(guid, huawei_wmi_input_notify,
- *idev);
+ return 0;
}
static void huawei_wmi_input_exit(struct device *dev, const char *guid)
@@ -797,17 +807,14 @@ static int huawei_wmi_probe(struct platform_device *pdev)
huawei_wmi->dev = &pdev->dev;
while (*guid->guid_string) {
- struct input_dev *idev = *huawei_wmi->idev;
-
if (wmi_has_guid(guid->guid_string)) {
- err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev);
+ err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string);
if (err) {
dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string);
return err;
}
}
- idev++;
guid++;
}
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index abd0c81d62c4..435d2d3d903b 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -30,6 +30,7 @@
#include <linux/seq_file.h>
#include <linux/sysfs.h>
#include <linux/types.h>
+#include <linux/wmi.h>
#include <acpi/video.h>
@@ -37,20 +38,23 @@
#define IDEAPAD_RFKILL_DEV_NUM 3
-#if IS_ENABLED(CONFIG_ACPI_WMI)
-static const char *const ideapad_wmi_fnesc_events[] = {
- "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
- "56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
- "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", /* Legion 5 */
-};
-#endif
-
enum {
CFG_CAP_BT_BIT = 16,
CFG_CAP_3G_BIT = 17,
CFG_CAP_WIFI_BIT = 18,
CFG_CAP_CAM_BIT = 19,
- CFG_CAP_TOUCHPAD_BIT = 30,
+
+ /*
+ * These are OnScreenDisplay support bits that can be useful to determine
+ * whether a hotkey exists/should show OSD. But they aren't particularly
+ * meaningful since they were introduced later, i.e. 2010 IdeaPads
+ * don't have these, but they still have had OSD for hotkeys.
+ */
+ CFG_OSD_NUMLK_BIT = 27,
+ CFG_OSD_CAPSLK_BIT = 28,
+ CFG_OSD_MICMUTE_BIT = 29,
+ CFG_OSD_TOUCHPAD_BIT = 30,
+ CFG_OSD_CAM_BIT = 31,
};
enum {
@@ -130,15 +134,17 @@ struct ideapad_private {
struct ideapad_dytc_priv *dytc;
struct dentry *debug;
unsigned long cfg;
- const char *fnesc_guid;
+ unsigned long r_touchpad_val;
struct {
bool conservation_mode : 1;
bool dytc : 1;
bool fan_mode : 1;
bool fn_lock : 1;
+ bool set_fn_lock_led : 1;
bool hw_rfkill_switch : 1;
bool kbd_bl : 1;
bool touchpad_ctrl_via_ec : 1;
+ bool ctrl_ps2_aux_port : 1;
bool usb_charging : 1;
} features;
struct {
@@ -154,7 +160,69 @@ MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
static bool allow_v4_dytc;
module_param(allow_v4_dytc, bool, 0444);
-MODULE_PARM_DESC(allow_v4_dytc, "Enable DYTC version 4 platform-profile support.");
+MODULE_PARM_DESC(allow_v4_dytc,
+ "Enable DYTC version 4 platform-profile support. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
+static bool hw_rfkill_switch;
+module_param(hw_rfkill_switch, bool, 0444);
+MODULE_PARM_DESC(hw_rfkill_switch,
+ "Enable rfkill support for laptops with a hw on/off wifi switch/slider. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
+static bool set_fn_lock_led;
+module_param(set_fn_lock_led, bool, 0444);
+MODULE_PARM_DESC(set_fn_lock_led,
+ "Enable driver based updates of the fn-lock LED on fn-lock changes. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
+static bool ctrl_ps2_aux_port;
+module_param(ctrl_ps2_aux_port, bool, 0444);
+MODULE_PARM_DESC(ctrl_ps2_aux_port,
+ "Enable driver based PS/2 aux port en-/dis-abling on touchpad on/off toggle. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
+static bool touchpad_ctrl_via_ec;
+module_param(touchpad_ctrl_via_ec, bool, 0444);
+MODULE_PARM_DESC(touchpad_ctrl_via_ec,
+ "Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
+ "tell the EC to enable/disable the touchpad. This may not work on all models.");
+
+/*
+ * shared data
+ */
+
+static struct ideapad_private *ideapad_shared;
+static DEFINE_MUTEX(ideapad_shared_mutex);
+
+static int ideapad_shared_init(struct ideapad_private *priv)
+{
+ int ret;
+
+ mutex_lock(&ideapad_shared_mutex);
+
+ if (!ideapad_shared) {
+ ideapad_shared = priv;
+ ret = 0;
+ } else {
+ dev_warn(&priv->adev->dev, "found multiple platform devices\n");
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&ideapad_shared_mutex);
+
+ return ret;
+}
+
+static void ideapad_shared_exit(struct ideapad_private *priv)
+{
+ mutex_lock(&ideapad_shared_mutex);
+
+ if (ideapad_shared == priv)
+ ideapad_shared = NULL;
+
+ mutex_unlock(&ideapad_shared_mutex);
+}
/*
* ACPI Helpers
@@ -371,8 +439,19 @@ static int debugfs_cfg_show(struct seq_file *s, void *data)
seq_puts(s, " wifi");
if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
seq_puts(s, " camera");
- if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
+ seq_puts(s, "\n");
+
+ seq_puts(s, "OSD support:");
+ if (test_bit(CFG_OSD_NUMLK_BIT, &priv->cfg))
+ seq_puts(s, " num-lock");
+ if (test_bit(CFG_OSD_CAPSLK_BIT, &priv->cfg))
+ seq_puts(s, " caps-lock");
+ if (test_bit(CFG_OSD_MICMUTE_BIT, &priv->cfg))
+ seq_puts(s, " mic-mute");
+ if (test_bit(CFG_OSD_TOUCHPAD_BIT, &priv->cfg))
seq_puts(s, " touchpad");
+ if (test_bit(CFG_OSD_CAM_BIT, &priv->cfg))
+ seq_puts(s, " camera");
seq_puts(s, "\n");
seq_puts(s, "Graphics: ");
@@ -578,6 +657,8 @@ static ssize_t touchpad_show(struct device *dev,
if (err)
return err;
+ priv->r_touchpad_val = result;
+
return sysfs_emit(buf, "%d\n", !!result);
}
@@ -597,6 +678,8 @@ static ssize_t touchpad_store(struct device *dev,
if (err)
return err;
+ priv->r_touchpad_val = state;
+
return count;
}
@@ -665,8 +748,7 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
else if (attr == &dev_attr_fn_lock.attr)
supported = priv->features.fn_lock;
else if (attr == &dev_attr_touchpad.attr)
- supported = priv->features.touchpad_ctrl_via_ec &&
- test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg);
+ supported = priv->features.touchpad_ctrl_via_ec;
else if (attr == &dev_attr_usb_charging.attr)
supported = priv->features.usb_charging;
@@ -1074,6 +1156,8 @@ static void ideapad_sysfs_exit(struct ideapad_private *priv)
/*
* input device
*/
+#define IDEAPAD_WMI_KEY 0x100
+
static const struct key_entry ideapad_keymap[] = {
{ KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 7, { KEY_CAMERA } },
@@ -1086,7 +1170,30 @@ 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, 68, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 128, { KEY_ESC } },
+
+ /*
+ * WMI keys
+ */
+
+ /* FnLock (handled by the firmware) */
+ { KE_IGNORE, 0x02 | IDEAPAD_WMI_KEY },
+ /* Esc (handled by the firmware) */
+ { KE_IGNORE, 0x03 | IDEAPAD_WMI_KEY },
+ /* Customizable Lenovo Hotkey ("star" with 'S' inside) */
+ { KE_KEY, 0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } },
+ /* Dark mode toggle */
+ { KE_KEY, 0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
+ /* Sound profile switch */
+ { KE_KEY, 0x12 | IDEAPAD_WMI_KEY, { KEY_PROG2 } },
+ /* Lenovo Virtual Background application */
+ { KE_KEY, 0x28 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
+ /* Lenovo Support */
+ { KE_KEY, 0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } },
+ /* Refresh Rate Toggle */
+ { KE_KEY, 0x0a | IDEAPAD_WMI_KEY, { KEY_DISPLAYTOGGLE } },
+
{ KE_END },
};
@@ -1399,26 +1506,41 @@ static void ideapad_kbd_bl_exit(struct ideapad_private *priv)
/*
* module init/exit
*/
-static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
+static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_events)
{
unsigned long value;
+ unsigned char param;
+ int ret;
- if (!priv->features.touchpad_ctrl_via_ec)
+ /* Without reading from EC touchpad LED doesn't switch state */
+ ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
+ if (ret)
return;
- /* Without reading from EC touchpad LED doesn't switch state */
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
- unsigned char param;
+ /*
+ * Some IdeaPads don't really turn off touchpad - they only
+ * switch the LED state. We (de)activate KBC AUX port to turn
+ * touchpad off and on. We send KEY_TOUCHPAD_OFF and
+ * KEY_TOUCHPAD_ON to not to get out of sync with LED
+ */
+ if (priv->features.ctrl_ps2_aux_port)
+ i8042_command(&param, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
+
+ if (send_events) {
/*
- * Some IdeaPads don't really turn off touchpad - they only
- * switch the LED state. We (de)activate KBC AUX port to turn
- * touchpad off and on. We send KEY_TOUCHPAD_OFF and
- * KEY_TOUCHPAD_ON to not to get out of sync with LED
+ * On older models the EC controls the touchpad and toggles it
+ * on/off itself, in this case we report KEY_TOUCHPAD_ON/_OFF.
+ * If the EC did not toggle, report KEY_TOUCHPAD_TOGGLE.
*/
- i8042_command(&param, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
- ideapad_input_report(priv, value ? 67 : 66);
- sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
+ if (value != priv->r_touchpad_val) {
+ ideapad_input_report(priv, value ? 67 : 66);
+ sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
+ } else {
+ ideapad_input_report(priv, 68);
+ }
}
+
+ priv->r_touchpad_val = value;
}
static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
@@ -1459,7 +1581,7 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
ideapad_sync_rfk_state(priv);
break;
case 5:
- ideapad_sync_touchpad_state(priv);
+ ideapad_sync_touchpad_state(priv, true);
break;
case 4:
ideapad_backlight_notify_brightness(priv);
@@ -1490,29 +1612,17 @@ 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)
-{
- struct ideapad_private *priv = context;
- unsigned long result;
-
- switch (value) {
- case 128:
- ideapad_input_report(priv, value);
- break;
- case 208:
- if (!eval_hals(priv->adev->handle, &result)) {
- bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
-
- exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
+/* On some models we need to call exec_sals(SALS_FNLOCK_ON/OFF) to set the LED */
+static const struct dmi_system_id set_fn_lock_led_list[] = {
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=212671 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"),
}
- break;
- default:
- dev_info(&priv->platform_device->dev,
- "Unknown WMI event: %u\n", value);
- }
-}
-#endif
+ },
+ {}
+};
/*
* Some ideapads have a hardware rfkill switch, but most do not have one.
@@ -1533,15 +1643,35 @@ static const struct dmi_system_id hw_rfkill_list[] = {
{}
};
+/*
+ * On some models the EC toggles the touchpad muted LED on touchpad toggle
+ * hotkey presses, but the EC does not actually disable the touchpad itself.
+ * On these models the driver needs to explicitly enable/disable the i8042
+ * (PS/2) aux port.
+ */
+static const struct dmi_system_id ctrl_ps2_aux_port_list[] = {
+ {
+ /* Lenovo Ideapad Z570 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
+ },
+ },
+ {}
+};
+
static void ideapad_check_features(struct ideapad_private *priv)
{
acpi_handle handle = priv->adev->handle;
unsigned long val;
- priv->features.hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
-
- /* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */
- priv->features.touchpad_ctrl_via_ec = !acpi_dev_present("ELAN0634", NULL, -1);
+ priv->features.set_fn_lock_led =
+ set_fn_lock_led || dmi_check_system(set_fn_lock_led_list);
+ priv->features.hw_rfkill_switch =
+ hw_rfkill_switch || dmi_check_system(hw_rfkill_list);
+ priv->features.ctrl_ps2_aux_port =
+ ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
+ priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
priv->features.fan_mode = true;
@@ -1566,6 +1696,118 @@ static void ideapad_check_features(struct ideapad_private *priv)
}
}
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+/*
+ * WMI driver
+ */
+enum ideapad_wmi_event_type {
+ IDEAPAD_WMI_EVENT_ESC,
+ IDEAPAD_WMI_EVENT_FN_KEYS,
+};
+
+struct ideapad_wmi_private {
+ enum ideapad_wmi_event_type event;
+};
+
+static int ideapad_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct ideapad_wmi_private *wpriv;
+
+ wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL);
+ if (!wpriv)
+ return -ENOMEM;
+
+ *wpriv = *(const struct ideapad_wmi_private *)context;
+
+ dev_set_drvdata(&wdev->dev, wpriv);
+ return 0;
+}
+
+static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
+{
+ struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev);
+ struct ideapad_private *priv;
+ unsigned long result;
+
+ mutex_lock(&ideapad_shared_mutex);
+
+ priv = ideapad_shared;
+ if (!priv)
+ goto unlock;
+
+ switch (wpriv->event) {
+ case IDEAPAD_WMI_EVENT_ESC:
+ ideapad_input_report(priv, 128);
+ break;
+ case IDEAPAD_WMI_EVENT_FN_KEYS:
+ if (priv->features.set_fn_lock_led &&
+ !eval_hals(priv->adev->handle, &result)) {
+ bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
+
+ exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
+ }
+
+ if (data->type != ACPI_TYPE_INTEGER) {
+ dev_warn(&wdev->dev,
+ "WMI event data is not an integer\n");
+ break;
+ }
+
+ dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
+ data->integer.value);
+
+ ideapad_input_report(priv,
+ data->integer.value | IDEAPAD_WMI_KEY);
+
+ break;
+ }
+unlock:
+ mutex_unlock(&ideapad_shared_mutex);
+}
+
+static const struct ideapad_wmi_private ideapad_wmi_context_esc = {
+ .event = IDEAPAD_WMI_EVENT_ESC
+};
+
+static const struct ideapad_wmi_private ideapad_wmi_context_fn_keys = {
+ .event = IDEAPAD_WMI_EVENT_FN_KEYS
+};
+
+static const struct wmi_device_id ideapad_wmi_ids[] = {
+ { "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", &ideapad_wmi_context_esc }, /* Yoga 3 */
+ { "56322276-8493-4CE8-A783-98C991274F5E", &ideapad_wmi_context_esc }, /* Yoga 700 */
+ { "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", &ideapad_wmi_context_fn_keys }, /* Legion 5 */
+ {},
+};
+MODULE_DEVICE_TABLE(wmi, ideapad_wmi_ids);
+
+static struct wmi_driver ideapad_wmi_driver = {
+ .driver = {
+ .name = "ideapad_wmi",
+ },
+ .id_table = ideapad_wmi_ids,
+ .probe = ideapad_wmi_probe,
+ .notify = ideapad_wmi_notify,
+};
+
+static int ideapad_wmi_driver_register(void)
+{
+ return wmi_driver_register(&ideapad_wmi_driver);
+}
+
+static void ideapad_wmi_driver_unregister(void)
+{
+ return wmi_driver_unregister(&ideapad_wmi_driver);
+}
+
+#else
+static inline int ideapad_wmi_driver_register(void) { return 0; }
+static inline void ideapad_wmi_driver_unregister(void) { }
+#endif
+
+/*
+ * ACPI driver
+ */
static int ideapad_acpi_add(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
@@ -1614,16 +1856,12 @@ static int ideapad_acpi_add(struct platform_device *pdev)
if (!priv->features.hw_rfkill_switch)
write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
- /* The same for Touchpad */
- if (!priv->features.touchpad_ctrl_via_ec)
- write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
-
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
ideapad_register_rfkill(priv, i);
ideapad_sync_rfk_state(priv);
- ideapad_sync_touchpad_state(priv);
+ ideapad_sync_touchpad_state(priv, false);
err = ideapad_dytc_profile_init(priv);
if (err) {
@@ -1647,30 +1885,16 @@ static int ideapad_acpi_add(struct platform_device *pdev)
goto notification_failed;
}
-#if IS_ENABLED(CONFIG_ACPI_WMI)
- for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
- status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
- ideapad_wmi_notify, priv);
- if (ACPI_SUCCESS(status)) {
- priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
- break;
- }
- }
-
- if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
- err = -EIO;
- goto notification_failed_wmi;
- }
-#endif
+ err = ideapad_shared_init(priv);
+ if (err)
+ goto shared_init_failed;
return 0;
-#if IS_ENABLED(CONFIG_ACPI_WMI)
-notification_failed_wmi:
+shared_init_failed:
acpi_remove_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY,
ideapad_acpi_notify);
-#endif
notification_failed:
ideapad_backlight_exit(priv);
@@ -1696,10 +1920,7 @@ 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)
- if (priv->fnesc_guid)
- wmi_remove_notify_handler(priv->fnesc_guid);
-#endif
+ ideapad_shared_exit(priv);
acpi_remove_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY,
@@ -1725,7 +1946,7 @@ static int ideapad_acpi_resume(struct device *dev)
struct ideapad_private *priv = dev_get_drvdata(dev);
ideapad_sync_rfk_state(priv);
- ideapad_sync_touchpad_state(priv);
+ ideapad_sync_touchpad_state(priv, false);
if (priv->dytc)
dytc_profile_refresh(priv);
@@ -1751,7 +1972,30 @@ static struct platform_driver ideapad_acpi_driver = {
},
};
-module_platform_driver(ideapad_acpi_driver);
+static int __init ideapad_laptop_init(void)
+{
+ int err;
+
+ err = ideapad_wmi_driver_register();
+ if (err)
+ return err;
+
+ err = platform_driver_register(&ideapad_acpi_driver);
+ if (err) {
+ ideapad_wmi_driver_unregister();
+ return err;
+ }
+
+ return 0;
+}
+module_init(ideapad_laptop_init)
+
+static void __exit ideapad_laptop_exit(void)
+{
+ ideapad_wmi_driver_unregister();
+ platform_driver_unregister(&ideapad_acpi_driver);
+}
+module_exit(ideapad_laptop_exit)
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("IdeaPad ACPI Extras");
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 794968bda115..d5a33473e838 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -157,13 +157,13 @@ config INTEL_RST
as usual.
config INTEL_SDSI
- tristate "Intel Software Defined Silicon Driver"
+ tristate "Intel On Demand (Software Defined Silicon) Driver"
depends on INTEL_VSEC
depends on X86_64
help
- This driver enables access to the Intel Software Defined Silicon
- interface used to provision silicon features with an authentication
- certificate and capability license.
+ This driver enables access to the Intel On Demand (formerly Software
+ Defined Silicon) interface used to provision silicon features with an
+ authentication certificate and capability license.
To compile this driver as a module, choose M here: the module will
be called intel_sdsi.
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 79cff1fc675c..b6c06b37862e 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -16,6 +16,25 @@
#include <linux/suspend.h>
#include "../dual_accel_detect.h"
+enum intel_hid_tablet_sw_mode {
+ TABLET_SW_AUTO = -1,
+ TABLET_SW_OFF = 0,
+ TABLET_SW_AT_EVENT,
+ TABLET_SW_AT_PROBE,
+};
+
+static bool enable_5_button_array;
+module_param(enable_5_button_array, bool, 0444);
+MODULE_PARM_DESC(enable_5_button_array,
+ "Enable 5 Button Array support. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
+static int enable_sw_tablet_mode = TABLET_SW_AUTO;
+module_param(enable_sw_tablet_mode, int, 0444);
+MODULE_PARM_DESC(enable_sw_tablet_mode,
+ "Enable SW_TABLET_MODE reporting -1:auto 0:off 1:at-first-event 2:at-probe. "
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
+
/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
#define TABLET_MODE_FLAG BIT(6)
@@ -27,6 +46,9 @@ static const struct acpi_device_id intel_hid_ids[] = {
{"INTC1051", 0},
{"INTC1054", 0},
{"INTC1070", 0},
+ {"INTC1076", 0},
+ {"INTC1077", 0},
+ {"INTC1078", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
@@ -154,7 +176,6 @@ struct intel_hid_priv {
struct input_dev *array;
struct input_dev *switches;
bool wakeup_mode;
- bool auto_add_switch;
};
#define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054"
@@ -484,7 +505,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
* SW_TABLET_MODE report, in these cases we enable support when receiving
* the first event instead of during driver setup.
*/
- if (!priv->switches && priv->auto_add_switch && (event == 0xcc || event == 0xcd)) {
+ if (!priv->switches && enable_sw_tablet_mode == TABLET_SW_AT_EVENT &&
+ (event == 0xcc || event == 0xcd)) {
dev_info(&device->dev, "switch event received, enable switches supports\n");
err = intel_hid_switches_setup(device);
if (err)
@@ -589,7 +611,7 @@ static bool button_array_present(struct platform_device *device)
return true;
}
- if (dmi_check_system(button_array_table))
+ if (enable_5_button_array || dmi_check_system(button_array_table))
return true;
return false;
@@ -626,7 +648,14 @@ static int intel_hid_probe(struct platform_device *device)
dev_set_drvdata(&device->dev, priv);
/* See dual_accel_detect.h for more info on the dual_accel check. */
- priv->auto_add_switch = dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect();
+ if (enable_sw_tablet_mode == TABLET_SW_AUTO) {
+ if (dmi_check_system(dmi_vgbs_allow_list))
+ enable_sw_tablet_mode = TABLET_SW_AT_PROBE;
+ else if (dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect())
+ enable_sw_tablet_mode = TABLET_SW_AT_EVENT;
+ else
+ enable_sw_tablet_mode = TABLET_SW_OFF;
+ }
err = intel_hid_input_setup(device);
if (err) {
@@ -643,7 +672,7 @@ static int intel_hid_probe(struct platform_device *device)
}
/* Setup switches for devices that we know VGBS return correctly */
- if (dmi_check_system(dmi_vgbs_allow_list)) {
+ if (enable_sw_tablet_mode == TABLET_SW_AT_PROBE) {
dev_info(&device->dev, "platform supports switches\n");
err = intel_hid_switches_setup(device);
if (err)
diff --git a/drivers/platform/x86/intel/pmc/Makefile b/drivers/platform/x86/intel/pmc/Makefile
index 8966fcdc0e1d..f96bc2e19503 100644
--- a/drivers/platform/x86/intel/pmc/Makefile
+++ b/drivers/platform/x86/intel/pmc/Makefile
@@ -3,7 +3,8 @@
# Intel x86 Platform-Specific Drivers
#
-intel_pmc_core-y := core.o
+intel_pmc_core-y := core.o spt.o cnp.o icl.o tgl.o \
+ adl.o mtl.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
intel_pmc_core_pltdrv-y := pltdrv.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o
diff --git a/drivers/platform/x86/intel/pmc/adl.c b/drivers/platform/x86/intel/pmc/adl.c
new file mode 100644
index 000000000000..5cbd40979f2a
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/adl.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Alder Lake PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+/* Alder Lake: PGD PFET Enable Ack Status Register(s) bitmap */
+const struct pmc_bit_map adl_pfear_map[] = {
+ {"SPI/eSPI", BIT(2)},
+ {"XHCI", BIT(3)},
+ {"SPA", BIT(4)},
+ {"SPB", BIT(5)},
+ {"SPC", BIT(6)},
+ {"GBE", BIT(7)},
+
+ {"SATA", BIT(0)},
+ {"HDA_PGD0", BIT(1)},
+ {"HDA_PGD1", BIT(2)},
+ {"HDA_PGD2", BIT(3)},
+ {"HDA_PGD3", BIT(4)},
+ {"SPD", BIT(5)},
+ {"LPSS", BIT(6)},
+
+ {"SMB", BIT(0)},
+ {"ISH", BIT(1)},
+ {"ITH", BIT(3)},
+
+ {"XDCI", BIT(1)},
+ {"DCI", BIT(2)},
+ {"CSE", BIT(3)},
+ {"CSME_KVM", BIT(4)},
+ {"CSME_PMT", BIT(5)},
+ {"CSME_CLINK", BIT(6)},
+ {"CSME_PTIO", BIT(7)},
+
+ {"CSME_USBR", BIT(0)},
+ {"CSME_SUSRAM", BIT(1)},
+ {"CSME_SMT1", BIT(2)},
+ {"CSME_SMS2", BIT(4)},
+ {"CSME_SMS1", BIT(5)},
+ {"CSME_RTC", BIT(6)},
+ {"CSME_PSF", BIT(7)},
+
+ {"CNVI", BIT(3)},
+ {"HDA_PGD4", BIT(2)},
+ {"HDA_PGD5", BIT(3)},
+ {"HDA_PGD6", BIT(4)},
+ {}
+};
+
+const struct pmc_bit_map *ext_adl_pfear_map[] = {
+ /*
+ * Check intel_pmc_core_ids[] users of cnp_reg_map for
+ * a list of core SoCs using this.
+ */
+ adl_pfear_map,
+ NULL
+};
+
+const struct pmc_bit_map adl_ltr_show_map[] = {
+ {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
+ {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
+ {"SATA", CNP_PMC_LTR_SATA},
+ {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
+ {"XHCI", CNP_PMC_LTR_XHCI},
+ {"SOUTHPORT_F", ADL_PMC_LTR_SPF},
+ {"ME", CNP_PMC_LTR_ME},
+ /* EVA is Enterprise Value Add, doesn't really exist on PCH */
+ {"SATA1", CNP_PMC_LTR_EVA},
+ {"SOUTHPORT_C", CNP_PMC_LTR_SPC},
+ {"HD_AUDIO", CNP_PMC_LTR_AZ},
+ {"CNV", CNP_PMC_LTR_CNV},
+ {"LPSS", CNP_PMC_LTR_LPSS},
+ {"SOUTHPORT_D", CNP_PMC_LTR_SPD},
+ {"SOUTHPORT_E", CNP_PMC_LTR_SPE},
+ {"SATA2", CNP_PMC_LTR_CAM},
+ {"ESPI", CNP_PMC_LTR_ESPI},
+ {"SCC", CNP_PMC_LTR_SCC},
+ {"ISH", CNP_PMC_LTR_ISH},
+ {"UFSX2", CNP_PMC_LTR_UFSX2},
+ {"EMMC", CNP_PMC_LTR_EMMC},
+ /*
+ * Check intel_pmc_core_ids[] users of cnp_reg_map for
+ * a list of core SoCs using this.
+ */
+ {"WIGIG", ICL_PMC_LTR_WIGIG},
+ {"THC0", TGL_PMC_LTR_THC0},
+ {"THC1", TGL_PMC_LTR_THC1},
+ {"SOUTHPORT_G", CNP_PMC_LTR_RESERVED},
+
+ /* Below two cannot be used for LTR_IGNORE */
+ {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
+ {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
+ {}
+};
+
+const struct pmc_bit_map adl_clocksource_status_map[] = {
+ {"CLKPART1_OFF_STS", BIT(0)},
+ {"CLKPART2_OFF_STS", BIT(1)},
+ {"CLKPART3_OFF_STS", BIT(2)},
+ {"CLKPART4_OFF_STS", BIT(3)},
+ {"CLKPART5_OFF_STS", BIT(4)},
+ {"CLKPART6_OFF_STS", BIT(5)},
+ {"CLKPART7_OFF_STS", BIT(6)},
+ {"CLKPART8_OFF_STS", BIT(7)},
+ {"PCIE0PLL_OFF_STS", BIT(10)},
+ {"PCIE1PLL_OFF_STS", BIT(11)},
+ {"PCIE2PLL_OFF_STS", BIT(12)},
+ {"PCIE3PLL_OFF_STS", BIT(13)},
+ {"PCIE4PLL_OFF_STS", BIT(14)},
+ {"PCIE5PLL_OFF_STS", BIT(15)},
+ {"PCIE6PLL_OFF_STS", BIT(16)},
+ {"USB2PLL_OFF_STS", BIT(18)},
+ {"OCPLL_OFF_STS", BIT(22)},
+ {"AUDIOPLL_OFF_STS", BIT(23)},
+ {"GBEPLL_OFF_STS", BIT(24)},
+ {"Fast_XTAL_Osc_OFF_STS", BIT(25)},
+ {"AC_Ring_Osc_OFF_STS", BIT(26)},
+ {"MC_Ring_Osc_OFF_STS", BIT(27)},
+ {"SATAPLL_OFF_STS", BIT(29)},
+ {"USB3PLL_OFF_STS", BIT(31)},
+ {}
+};
+
+const struct pmc_bit_map adl_power_gating_status_0_map[] = {
+ {"PMC_PGD0_PG_STS", BIT(0)},
+ {"DMI_PGD0_PG_STS", BIT(1)},
+ {"ESPISPI_PGD0_PG_STS", BIT(2)},
+ {"XHCI_PGD0_PG_STS", BIT(3)},
+ {"SPA_PGD0_PG_STS", BIT(4)},
+ {"SPB_PGD0_PG_STS", BIT(5)},
+ {"SPC_PGD0_PG_STS", BIT(6)},
+ {"GBE_PGD0_PG_STS", BIT(7)},
+ {"SATA_PGD0_PG_STS", BIT(8)},
+ {"DSP_PGD0_PG_STS", BIT(9)},
+ {"DSP_PGD1_PG_STS", BIT(10)},
+ {"DSP_PGD2_PG_STS", BIT(11)},
+ {"DSP_PGD3_PG_STS", BIT(12)},
+ {"SPD_PGD0_PG_STS", BIT(13)},
+ {"LPSS_PGD0_PG_STS", BIT(14)},
+ {"SMB_PGD0_PG_STS", BIT(16)},
+ {"ISH_PGD0_PG_STS", BIT(17)},
+ {"NPK_PGD0_PG_STS", BIT(19)},
+ {"PECI_PGD0_PG_STS", BIT(21)},
+ {"XDCI_PGD0_PG_STS", BIT(25)},
+ {"EXI_PGD0_PG_STS", BIT(26)},
+ {"CSE_PGD0_PG_STS", BIT(27)},
+ {"KVMCC_PGD0_PG_STS", BIT(28)},
+ {"PMT_PGD0_PG_STS", BIT(29)},
+ {"CLINK_PGD0_PG_STS", BIT(30)},
+ {"PTIO_PGD0_PG_STS", BIT(31)},
+ {}
+};
+
+const struct pmc_bit_map adl_power_gating_status_1_map[] = {
+ {"USBR0_PGD0_PG_STS", BIT(0)},
+ {"SMT1_PGD0_PG_STS", BIT(2)},
+ {"CSMERTC_PGD0_PG_STS", BIT(6)},
+ {"CSMEPSF_PGD0_PG_STS", BIT(7)},
+ {"CNVI_PGD0_PG_STS", BIT(19)},
+ {"DSP_PGD4_PG_STS", BIT(26)},
+ {"SPG_PGD0_PG_STS", BIT(27)},
+ {"SPE_PGD0_PG_STS", BIT(28)},
+ {}
+};
+
+const struct pmc_bit_map adl_power_gating_status_2_map[] = {
+ {"THC0_PGD0_PG_STS", BIT(7)},
+ {"THC1_PGD0_PG_STS", BIT(8)},
+ {"SPF_PGD0_PG_STS", BIT(14)},
+ {}
+};
+
+const struct pmc_bit_map adl_d3_status_0_map[] = {
+ {"ISH_D3_STS", BIT(2)},
+ {"LPSS_D3_STS", BIT(3)},
+ {"XDCI_D3_STS", BIT(4)},
+ {"XHCI_D3_STS", BIT(5)},
+ {"SPA_D3_STS", BIT(12)},
+ {"SPB_D3_STS", BIT(13)},
+ {"SPC_D3_STS", BIT(14)},
+ {"SPD_D3_STS", BIT(15)},
+ {"SPE_D3_STS", BIT(16)},
+ {"DSP_D3_STS", BIT(19)},
+ {"SATA_D3_STS", BIT(20)},
+ {"DMI_D3_STS", BIT(22)},
+ {}
+};
+
+const struct pmc_bit_map adl_d3_status_1_map[] = {
+ {"GBE_D3_STS", BIT(19)},
+ {"CNVI_D3_STS", BIT(27)},
+ {}
+};
+
+const struct pmc_bit_map adl_d3_status_2_map[] = {
+ {"CSMERTC_D3_STS", BIT(1)},
+ {"CSE_D3_STS", BIT(4)},
+ {"KVMCC_D3_STS", BIT(5)},
+ {"USBR0_D3_STS", BIT(6)},
+ {"SMT1_D3_STS", BIT(8)},
+ {"PTIO_D3_STS", BIT(16)},
+ {"PMT_D3_STS", BIT(17)},
+ {}
+};
+
+const struct pmc_bit_map adl_d3_status_3_map[] = {
+ {"THC0_D3_STS", BIT(14)},
+ {"THC1_D3_STS", BIT(15)},
+ {}
+};
+
+const struct pmc_bit_map adl_vnn_req_status_0_map[] = {
+ {"ISH_VNN_REQ_STS", BIT(2)},
+ {"ESPISPI_VNN_REQ_STS", BIT(18)},
+ {"DSP_VNN_REQ_STS", BIT(19)},
+ {}
+};
+
+const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
+ {"NPK_VNN_REQ_STS", BIT(4)},
+ {"EXI_VNN_REQ_STS", BIT(9)},
+ {"GBE_VNN_REQ_STS", BIT(19)},
+ {"SMB_VNN_REQ_STS", BIT(25)},
+ {"CNVI_VNN_REQ_STS", BIT(27)},
+ {}
+};
+
+const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
+ {"CSMERTC_VNN_REQ_STS", BIT(1)},
+ {"CSE_VNN_REQ_STS", BIT(4)},
+ {"SMT1_VNN_REQ_STS", BIT(8)},
+ {"CLINK_VNN_REQ_STS", BIT(14)},
+ {"GPIOCOM4_VNN_REQ_STS", BIT(20)},
+ {"GPIOCOM3_VNN_REQ_STS", BIT(21)},
+ {"GPIOCOM2_VNN_REQ_STS", BIT(22)},
+ {"GPIOCOM1_VNN_REQ_STS", BIT(23)},
+ {"GPIOCOM0_VNN_REQ_STS", BIT(24)},
+ {}
+};
+
+const struct pmc_bit_map adl_vnn_req_status_3_map[] = {
+ {"GPIOCOM5_VNN_REQ_STS", BIT(11)},
+ {}
+};
+
+const struct pmc_bit_map adl_vnn_misc_status_map[] = {
+ {"CPU_C10_REQ_STS", BIT(0)},
+ {"PCIe_LPM_En_REQ_STS", BIT(3)},
+ {"ITH_REQ_STS", BIT(5)},
+ {"CNVI_REQ_STS", BIT(6)},
+ {"ISH_REQ_STS", BIT(7)},
+ {"USB2_SUS_PG_Sys_REQ_STS", BIT(10)},
+ {"PCIe_Clk_REQ_STS", BIT(12)},
+ {"MPHY_Core_DL_REQ_STS", BIT(16)},
+ {"Break-even_En_REQ_STS", BIT(17)},
+ {"MPHY_SUS_REQ_STS", BIT(22)},
+ {"xDCI_attached_REQ_STS", BIT(24)},
+ {}
+};
+
+const struct pmc_bit_map *adl_lpm_maps[] = {
+ adl_clocksource_status_map,
+ adl_power_gating_status_0_map,
+ adl_power_gating_status_1_map,
+ adl_power_gating_status_2_map,
+ adl_d3_status_0_map,
+ adl_d3_status_1_map,
+ adl_d3_status_2_map,
+ adl_d3_status_3_map,
+ adl_vnn_req_status_0_map,
+ adl_vnn_req_status_1_map,
+ adl_vnn_req_status_2_map,
+ adl_vnn_req_status_3_map,
+ adl_vnn_misc_status_map,
+ tgl_signal_status_map,
+ NULL
+};
+
+const struct pmc_reg_map adl_reg_map = {
+ .pfear_sts = ext_adl_pfear_map,
+ .slp_s0_offset = ADL_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
+ .ltr_show_sts = adl_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
+ .lpm_num_modes = ADL_LPM_NUM_MODES,
+ .lpm_num_maps = ADL_LPM_NUM_MAPS,
+ .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
+ .etr3_offset = ETR3_OFFSET,
+ .lpm_sts_latch_en_offset = ADL_LPM_STATUS_LATCH_EN_OFFSET,
+ .lpm_priority_offset = ADL_LPM_PRI_OFFSET,
+ .lpm_en_offset = ADL_LPM_EN_OFFSET,
+ .lpm_residency_offset = ADL_LPM_RESIDENCY_OFFSET,
+ .lpm_sts = adl_lpm_maps,
+ .lpm_status_offset = ADL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = ADL_LPM_LIVE_STATUS_OFFSET,
+};
+
+void adl_core_configure(struct pmc_dev *pmcdev)
+{
+ /* Due to a hardware limitation, the GBE LTR blocks PC10
+ * when a cable is attached. Tell the PMC to ignore it.
+ */
+ dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+ pmc_core_send_ltr_ignore(pmcdev, 3);
+}
+
+void adl_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &adl_reg_map;
+ pmcdev->core_configure = adl_core_configure;
+}
diff --git a/drivers/platform/x86/intel/pmc/cnp.c b/drivers/platform/x86/intel/pmc/cnp.c
new file mode 100644
index 000000000000..7fb38815c4eb
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/cnp.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Cannon Lake Point PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+/* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */
+const struct pmc_bit_map cnp_pfear_map[] = {
+ {"PMC", BIT(0)},
+ {"OPI-DMI", BIT(1)},
+ {"SPI/eSPI", BIT(2)},
+ {"XHCI", BIT(3)},
+ {"SPA", BIT(4)},
+ {"SPB", BIT(5)},
+ {"SPC", BIT(6)},
+ {"GBE", BIT(7)},
+
+ {"SATA", BIT(0)},
+ {"HDA_PGD0", BIT(1)},
+ {"HDA_PGD1", BIT(2)},
+ {"HDA_PGD2", BIT(3)},
+ {"HDA_PGD3", BIT(4)},
+ {"SPD", BIT(5)},
+ {"LPSS", BIT(6)},
+ {"LPC", BIT(7)},
+
+ {"SMB", BIT(0)},
+ {"ISH", BIT(1)},
+ {"P2SB", BIT(2)},
+ {"NPK_VNN", BIT(3)},
+ {"SDX", BIT(4)},
+ {"SPE", BIT(5)},
+ {"Fuse", BIT(6)},
+ {"SBR8", BIT(7)},
+
+ {"CSME_FSC", BIT(0)},
+ {"USB3_OTG", BIT(1)},
+ {"EXI", BIT(2)},
+ {"CSE", BIT(3)},
+ {"CSME_KVM", BIT(4)},
+ {"CSME_PMT", BIT(5)},
+ {"CSME_CLINK", BIT(6)},
+ {"CSME_PTIO", BIT(7)},
+
+ {"CSME_USBR", BIT(0)},
+ {"CSME_SUSRAM", BIT(1)},
+ {"CSME_SMT1", BIT(2)},
+ {"CSME_SMT4", BIT(3)},
+ {"CSME_SMS2", BIT(4)},
+ {"CSME_SMS1", BIT(5)},
+ {"CSME_RTC", BIT(6)},
+ {"CSME_PSF", BIT(7)},
+
+ {"SBR0", BIT(0)},
+ {"SBR1", BIT(1)},
+ {"SBR2", BIT(2)},
+ {"SBR3", BIT(3)},
+ {"SBR4", BIT(4)},
+ {"SBR5", BIT(5)},
+ {"CSME_PECI", BIT(6)},
+ {"PSF1", BIT(7)},
+
+ {"PSF2", BIT(0)},
+ {"PSF3", BIT(1)},
+ {"PSF4", BIT(2)},
+ {"CNVI", BIT(3)},
+ {"UFS0", BIT(4)},
+ {"EMMC", BIT(5)},
+ {"SPF", BIT(6)},
+ {"SBR6", BIT(7)},
+
+ {"SBR7", BIT(0)},
+ {"NPK_AON", BIT(1)},
+ {"HDA_PGD4", BIT(2)},
+ {"HDA_PGD5", BIT(3)},
+ {"HDA_PGD6", BIT(4)},
+ {"PSF6", BIT(5)},
+ {"PSF7", BIT(6)},
+ {"PSF8", BIT(7)},
+ {}
+};
+
+const struct pmc_bit_map *ext_cnp_pfear_map[] = {
+ /*
+ * Check intel_pmc_core_ids[] users of cnp_reg_map for
+ * a list of core SoCs using this.
+ */
+ cnp_pfear_map,
+ NULL
+};
+
+const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
+ {"AUDIO_D3", BIT(0)},
+ {"OTG_D3", BIT(1)},
+ {"XHCI_D3", BIT(2)},
+ {"LPIO_D3", BIT(3)},
+ {"SDX_D3", BIT(4)},
+ {"SATA_D3", BIT(5)},
+ {"UFS0_D3", BIT(6)},
+ {"UFS1_D3", BIT(7)},
+ {"EMMC_D3", BIT(8)},
+ {}
+};
+
+const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
+ {"SDIO_PLL_OFF", BIT(0)},
+ {"USB2_PLL_OFF", BIT(1)},
+ {"AUDIO_PLL_OFF", BIT(2)},
+ {"OC_PLL_OFF", BIT(3)},
+ {"MAIN_PLL_OFF", BIT(4)},
+ {"XOSC_OFF", BIT(5)},
+ {"LPC_CLKS_GATED", BIT(6)},
+ {"PCIE_CLKREQS_IDLE", BIT(7)},
+ {"AUDIO_ROSC_OFF", BIT(8)},
+ {"HPET_XOSC_CLK_REQ", BIT(9)},
+ {"PMC_ROSC_SLOW_CLK", BIT(10)},
+ {"AON2_ROSC_GATED", BIT(11)},
+ {"CLKACKS_DEASSERTED", BIT(12)},
+ {}
+};
+
+const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
+ {"MPHY_CORE_GATED", BIT(0)},
+ {"CSME_GATED", BIT(1)},
+ {"USB2_SUS_GATED", BIT(2)},
+ {"DYN_FLEX_IO_IDLE", BIT(3)},
+ {"GBE_NO_LINK", BIT(4)},
+ {"THERM_SEN_DISABLED", BIT(5)},
+ {"PCIE_LOW_POWER", BIT(6)},
+ {"ISH_VNNAON_REQ_ACT", BIT(7)},
+ {"ISH_VNN_REQ_ACT", BIT(8)},
+ {"CNV_VNNAON_REQ_ACT", BIT(9)},
+ {"CNV_VNN_REQ_ACT", BIT(10)},
+ {"NPK_VNNON_REQ_ACT", BIT(11)},
+ {"PMSYNC_STATE_IDLE", BIT(12)},
+ {"ALST_GT_THRES", BIT(13)},
+ {"PMC_ARC_PG_READY", BIT(14)},
+ {}
+};
+
+const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
+ cnp_slps0_dbg0_map,
+ cnp_slps0_dbg1_map,
+ cnp_slps0_dbg2_map,
+ NULL
+};
+
+const struct pmc_bit_map cnp_ltr_show_map[] = {
+ {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
+ {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
+ {"SATA", CNP_PMC_LTR_SATA},
+ {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
+ {"XHCI", CNP_PMC_LTR_XHCI},
+ {"Reserved", CNP_PMC_LTR_RESERVED},
+ {"ME", CNP_PMC_LTR_ME},
+ /* EVA is Enterprise Value Add, doesn't really exist on PCH */
+ {"EVA", CNP_PMC_LTR_EVA},
+ {"SOUTHPORT_C", CNP_PMC_LTR_SPC},
+ {"HD_AUDIO", CNP_PMC_LTR_AZ},
+ {"CNV", CNP_PMC_LTR_CNV},
+ {"LPSS", CNP_PMC_LTR_LPSS},
+ {"SOUTHPORT_D", CNP_PMC_LTR_SPD},
+ {"SOUTHPORT_E", CNP_PMC_LTR_SPE},
+ {"CAMERA", CNP_PMC_LTR_CAM},
+ {"ESPI", CNP_PMC_LTR_ESPI},
+ {"SCC", CNP_PMC_LTR_SCC},
+ {"ISH", CNP_PMC_LTR_ISH},
+ {"UFSX2", CNP_PMC_LTR_UFSX2},
+ {"EMMC", CNP_PMC_LTR_EMMC},
+ /*
+ * Check intel_pmc_core_ids[] users of cnp_reg_map for
+ * a list of core SoCs using this.
+ */
+ {"WIGIG", ICL_PMC_LTR_WIGIG},
+ {"THC0", TGL_PMC_LTR_THC0},
+ {"THC1", TGL_PMC_LTR_THC1},
+ /* Below two cannot be used for LTR_IGNORE */
+ {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
+ {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
+ {}
+};
+
+const struct pmc_reg_map cnp_reg_map = {
+ .pfear_sts = ext_cnp_pfear_map,
+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
+ .slps0_dbg_maps = cnp_slps0_dbg_maps,
+ .ltr_show_sts = cnp_ltr_show_map,
+ .msr_sts = msr_map,
+ .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
+ .etr3_offset = ETR3_OFFSET,
+};
+
+void cnp_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &cnp_reg_map;
+}
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index 17ec5825d13d..f1d802f6ec3f 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -11,7 +11,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -19,13 +18,9 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/suspend.h>
-#include <linux/uaccess.h>
-#include <linux/uuid.h>
-#include <acpi/acpi_bus.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/msr.h>
@@ -33,11 +28,21 @@
#include "core.h"
-#define ACPI_S0IX_DSM_UUID "57a6512e-3979-4e9d-9708-ff13b2508972"
-#define ACPI_GET_LOW_MODE_REGISTERS 1
+/* Maximum number of modes supported by platfoms that has low power mode capability */
+const char *pmc_lpm_modes[] = {
+ "S0i2.0",
+ "S0i2.1",
+ "S0i2.2",
+ "S0i3.0",
+ "S0i3.1",
+ "S0i3.2",
+ "S0i3.3",
+ "S0i3.4",
+ NULL
+};
/* PKGC MSRs are common across Intel Core SoCs */
-static const struct pmc_bit_map msr_map[] = {
+const struct pmc_bit_map msr_map[] = {
{"Package C2", MSR_PKG_C2_RESIDENCY},
{"Package C3", MSR_PKG_C3_RESIDENCY},
{"Package C6", MSR_PKG_C6_RESIDENCY},
@@ -48,903 +53,6 @@ static const struct pmc_bit_map msr_map[] = {
{}
};
-static const struct pmc_bit_map spt_pll_map[] = {
- {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0},
- {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
- {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
- {"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3},
- {}
-};
-
-static const struct pmc_bit_map spt_mphy_map[] = {
- {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0},
- {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1},
- {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2},
- {"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3},
- {"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4},
- {"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5},
- {"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6},
- {"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7},
- {"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8},
- {"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9},
- {"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10},
- {"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11},
- {"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12},
- {"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13},
- {"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14},
- {"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15},
- {}
-};
-
-static const struct pmc_bit_map spt_pfear_map[] = {
- {"PMC", SPT_PMC_BIT_PMC},
- {"OPI-DMI", SPT_PMC_BIT_OPI},
- {"SPI / eSPI", SPT_PMC_BIT_SPI},
- {"XHCI", SPT_PMC_BIT_XHCI},
- {"SPA", SPT_PMC_BIT_SPA},
- {"SPB", SPT_PMC_BIT_SPB},
- {"SPC", SPT_PMC_BIT_SPC},
- {"GBE", SPT_PMC_BIT_GBE},
- {"SATA", SPT_PMC_BIT_SATA},
- {"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0},
- {"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1},
- {"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2},
- {"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3},
- {"RSVD", SPT_PMC_BIT_RSVD_0B},
- {"LPSS", SPT_PMC_BIT_LPSS},
- {"LPC", SPT_PMC_BIT_LPC},
- {"SMB", SPT_PMC_BIT_SMB},
- {"ISH", SPT_PMC_BIT_ISH},
- {"P2SB", SPT_PMC_BIT_P2SB},
- {"DFX", SPT_PMC_BIT_DFX},
- {"SCC", SPT_PMC_BIT_SCC},
- {"RSVD", SPT_PMC_BIT_RSVD_0C},
- {"FUSE", SPT_PMC_BIT_FUSE},
- {"CAMERA", SPT_PMC_BIT_CAMREA},
- {"RSVD", SPT_PMC_BIT_RSVD_0D},
- {"USB3-OTG", SPT_PMC_BIT_USB3_OTG},
- {"EXI", SPT_PMC_BIT_EXI},
- {"CSE", SPT_PMC_BIT_CSE},
- {"CSME_KVM", SPT_PMC_BIT_CSME_KVM},
- {"CSME_PMT", SPT_PMC_BIT_CSME_PMT},
- {"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK},
- {"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO},
- {"CSME_USBR", SPT_PMC_BIT_CSME_USBR},
- {"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM},
- {"CSME_SMT", SPT_PMC_BIT_CSME_SMT},
- {"RSVD", SPT_PMC_BIT_RSVD_1A},
- {"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2},
- {"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1},
- {"CSME_RTC", SPT_PMC_BIT_CSME_RTC},
- {"CSME_PSF", SPT_PMC_BIT_CSME_PSF},
- {}
-};
-
-static const struct pmc_bit_map *ext_spt_pfear_map[] = {
- /*
- * Check intel_pmc_core_ids[] users of spt_reg_map for
- * a list of core SoCs using this.
- */
- spt_pfear_map,
- NULL
-};
-
-static const struct pmc_bit_map spt_ltr_show_map[] = {
- {"SOUTHPORT_A", SPT_PMC_LTR_SPA},
- {"SOUTHPORT_B", SPT_PMC_LTR_SPB},
- {"SATA", SPT_PMC_LTR_SATA},
- {"GIGABIT_ETHERNET", SPT_PMC_LTR_GBE},
- {"XHCI", SPT_PMC_LTR_XHCI},
- {"Reserved", SPT_PMC_LTR_RESERVED},
- {"ME", SPT_PMC_LTR_ME},
- /* EVA is Enterprise Value Add, doesn't really exist on PCH */
- {"EVA", SPT_PMC_LTR_EVA},
- {"SOUTHPORT_C", SPT_PMC_LTR_SPC},
- {"HD_AUDIO", SPT_PMC_LTR_AZ},
- {"LPSS", SPT_PMC_LTR_LPSS},
- {"SOUTHPORT_D", SPT_PMC_LTR_SPD},
- {"SOUTHPORT_E", SPT_PMC_LTR_SPE},
- {"CAMERA", SPT_PMC_LTR_CAM},
- {"ESPI", SPT_PMC_LTR_ESPI},
- {"SCC", SPT_PMC_LTR_SCC},
- {"ISH", SPT_PMC_LTR_ISH},
- /* Below two cannot be used for LTR_IGNORE */
- {"CURRENT_PLATFORM", SPT_PMC_LTR_CUR_PLT},
- {"AGGREGATED_SYSTEM", SPT_PMC_LTR_CUR_ASLT},
- {}
-};
-
-static const struct pmc_reg_map spt_reg_map = {
- .pfear_sts = ext_spt_pfear_map,
- .mphy_sts = spt_mphy_map,
- .pll_sts = spt_pll_map,
- .ltr_show_sts = spt_ltr_show_map,
- .msr_sts = msr_map,
- .slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
- .ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET,
- .regmap_length = SPT_PMC_MMIO_REG_LEN,
- .ppfear0_offset = SPT_PMC_XRAM_PPFEAR0A,
- .ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES,
- .pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET,
- .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
- .ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED,
- .pm_vric1_offset = SPT_PMC_VRIC1_OFFSET,
-};
-
-/* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */
-static const struct pmc_bit_map cnp_pfear_map[] = {
- {"PMC", BIT(0)},
- {"OPI-DMI", BIT(1)},
- {"SPI/eSPI", BIT(2)},
- {"XHCI", BIT(3)},
- {"SPA", BIT(4)},
- {"SPB", BIT(5)},
- {"SPC", BIT(6)},
- {"GBE", BIT(7)},
-
- {"SATA", BIT(0)},
- {"HDA_PGD0", BIT(1)},
- {"HDA_PGD1", BIT(2)},
- {"HDA_PGD2", BIT(3)},
- {"HDA_PGD3", BIT(4)},
- {"SPD", BIT(5)},
- {"LPSS", BIT(6)},
- {"LPC", BIT(7)},
-
- {"SMB", BIT(0)},
- {"ISH", BIT(1)},
- {"P2SB", BIT(2)},
- {"NPK_VNN", BIT(3)},
- {"SDX", BIT(4)},
- {"SPE", BIT(5)},
- {"Fuse", BIT(6)},
- {"SBR8", BIT(7)},
-
- {"CSME_FSC", BIT(0)},
- {"USB3_OTG", BIT(1)},
- {"EXI", BIT(2)},
- {"CSE", BIT(3)},
- {"CSME_KVM", BIT(4)},
- {"CSME_PMT", BIT(5)},
- {"CSME_CLINK", BIT(6)},
- {"CSME_PTIO", BIT(7)},
-
- {"CSME_USBR", BIT(0)},
- {"CSME_SUSRAM", BIT(1)},
- {"CSME_SMT1", BIT(2)},
- {"CSME_SMT4", BIT(3)},
- {"CSME_SMS2", BIT(4)},
- {"CSME_SMS1", BIT(5)},
- {"CSME_RTC", BIT(6)},
- {"CSME_PSF", BIT(7)},
-
- {"SBR0", BIT(0)},
- {"SBR1", BIT(1)},
- {"SBR2", BIT(2)},
- {"SBR3", BIT(3)},
- {"SBR4", BIT(4)},
- {"SBR5", BIT(5)},
- {"CSME_PECI", BIT(6)},
- {"PSF1", BIT(7)},
-
- {"PSF2", BIT(0)},
- {"PSF3", BIT(1)},
- {"PSF4", BIT(2)},
- {"CNVI", BIT(3)},
- {"UFS0", BIT(4)},
- {"EMMC", BIT(5)},
- {"SPF", BIT(6)},
- {"SBR6", BIT(7)},
-
- {"SBR7", BIT(0)},
- {"NPK_AON", BIT(1)},
- {"HDA_PGD4", BIT(2)},
- {"HDA_PGD5", BIT(3)},
- {"HDA_PGD6", BIT(4)},
- {"PSF6", BIT(5)},
- {"PSF7", BIT(6)},
- {"PSF8", BIT(7)},
- {}
-};
-
-static const struct pmc_bit_map *ext_cnp_pfear_map[] = {
- /*
- * Check intel_pmc_core_ids[] users of cnp_reg_map for
- * a list of core SoCs using this.
- */
- cnp_pfear_map,
- NULL
-};
-
-static const struct pmc_bit_map icl_pfear_map[] = {
- {"RES_65", BIT(0)},
- {"RES_66", BIT(1)},
- {"RES_67", BIT(2)},
- {"TAM", BIT(3)},
- {"GBETSN", BIT(4)},
- {"TBTLSX", BIT(5)},
- {"RES_71", BIT(6)},
- {"RES_72", BIT(7)},
- {}
-};
-
-static const struct pmc_bit_map *ext_icl_pfear_map[] = {
- /*
- * Check intel_pmc_core_ids[] users of icl_reg_map for
- * a list of core SoCs using this.
- */
- cnp_pfear_map,
- icl_pfear_map,
- NULL
-};
-
-static const struct pmc_bit_map tgl_pfear_map[] = {
- {"PSF9", BIT(0)},
- {"RES_66", BIT(1)},
- {"RES_67", BIT(2)},
- {"RES_68", BIT(3)},
- {"RES_69", BIT(4)},
- {"RES_70", BIT(5)},
- {"TBTLSX", BIT(6)},
- {}
-};
-
-static const struct pmc_bit_map *ext_tgl_pfear_map[] = {
- /*
- * Check intel_pmc_core_ids[] users of tgl_reg_map for
- * a list of core SoCs using this.
- */
- cnp_pfear_map,
- tgl_pfear_map,
- NULL
-};
-
-static const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
- {"AUDIO_D3", BIT(0)},
- {"OTG_D3", BIT(1)},
- {"XHCI_D3", BIT(2)},
- {"LPIO_D3", BIT(3)},
- {"SDX_D3", BIT(4)},
- {"SATA_D3", BIT(5)},
- {"UFS0_D3", BIT(6)},
- {"UFS1_D3", BIT(7)},
- {"EMMC_D3", BIT(8)},
- {}
-};
-
-static const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
- {"SDIO_PLL_OFF", BIT(0)},
- {"USB2_PLL_OFF", BIT(1)},
- {"AUDIO_PLL_OFF", BIT(2)},
- {"OC_PLL_OFF", BIT(3)},
- {"MAIN_PLL_OFF", BIT(4)},
- {"XOSC_OFF", BIT(5)},
- {"LPC_CLKS_GATED", BIT(6)},
- {"PCIE_CLKREQS_IDLE", BIT(7)},
- {"AUDIO_ROSC_OFF", BIT(8)},
- {"HPET_XOSC_CLK_REQ", BIT(9)},
- {"PMC_ROSC_SLOW_CLK", BIT(10)},
- {"AON2_ROSC_GATED", BIT(11)},
- {"CLKACKS_DEASSERTED", BIT(12)},
- {}
-};
-
-static const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
- {"MPHY_CORE_GATED", BIT(0)},
- {"CSME_GATED", BIT(1)},
- {"USB2_SUS_GATED", BIT(2)},
- {"DYN_FLEX_IO_IDLE", BIT(3)},
- {"GBE_NO_LINK", BIT(4)},
- {"THERM_SEN_DISABLED", BIT(5)},
- {"PCIE_LOW_POWER", BIT(6)},
- {"ISH_VNNAON_REQ_ACT", BIT(7)},
- {"ISH_VNN_REQ_ACT", BIT(8)},
- {"CNV_VNNAON_REQ_ACT", BIT(9)},
- {"CNV_VNN_REQ_ACT", BIT(10)},
- {"NPK_VNNON_REQ_ACT", BIT(11)},
- {"PMSYNC_STATE_IDLE", BIT(12)},
- {"ALST_GT_THRES", BIT(13)},
- {"PMC_ARC_PG_READY", BIT(14)},
- {}
-};
-
-static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
- cnp_slps0_dbg0_map,
- cnp_slps0_dbg1_map,
- cnp_slps0_dbg2_map,
- NULL
-};
-
-static const struct pmc_bit_map cnp_ltr_show_map[] = {
- {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
- {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
- {"SATA", CNP_PMC_LTR_SATA},
- {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
- {"XHCI", CNP_PMC_LTR_XHCI},
- {"Reserved", CNP_PMC_LTR_RESERVED},
- {"ME", CNP_PMC_LTR_ME},
- /* EVA is Enterprise Value Add, doesn't really exist on PCH */
- {"EVA", CNP_PMC_LTR_EVA},
- {"SOUTHPORT_C", CNP_PMC_LTR_SPC},
- {"HD_AUDIO", CNP_PMC_LTR_AZ},
- {"CNV", CNP_PMC_LTR_CNV},
- {"LPSS", CNP_PMC_LTR_LPSS},
- {"SOUTHPORT_D", CNP_PMC_LTR_SPD},
- {"SOUTHPORT_E", CNP_PMC_LTR_SPE},
- {"CAMERA", CNP_PMC_LTR_CAM},
- {"ESPI", CNP_PMC_LTR_ESPI},
- {"SCC", CNP_PMC_LTR_SCC},
- {"ISH", CNP_PMC_LTR_ISH},
- {"UFSX2", CNP_PMC_LTR_UFSX2},
- {"EMMC", CNP_PMC_LTR_EMMC},
- /*
- * Check intel_pmc_core_ids[] users of cnp_reg_map for
- * a list of core SoCs using this.
- */
- {"WIGIG", ICL_PMC_LTR_WIGIG},
- {"THC0", TGL_PMC_LTR_THC0},
- {"THC1", TGL_PMC_LTR_THC1},
- /* Below two cannot be used for LTR_IGNORE */
- {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
- {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
- {}
-};
-
-static const struct pmc_reg_map cnp_reg_map = {
- .pfear_sts = ext_cnp_pfear_map,
- .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
- .slps0_dbg_maps = cnp_slps0_dbg_maps,
- .ltr_show_sts = cnp_ltr_show_map,
- .msr_sts = msr_map,
- .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
- .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
- .regmap_length = CNP_PMC_MMIO_REG_LEN,
- .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
- .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
- .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
- .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
- .etr3_offset = ETR3_OFFSET,
-};
-
-static const struct pmc_reg_map icl_reg_map = {
- .pfear_sts = ext_icl_pfear_map,
- .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP,
- .slps0_dbg_maps = cnp_slps0_dbg_maps,
- .ltr_show_sts = cnp_ltr_show_map,
- .msr_sts = msr_map,
- .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
- .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
- .regmap_length = CNP_PMC_MMIO_REG_LEN,
- .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
- .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
- .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
- .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
- .etr3_offset = ETR3_OFFSET,
-};
-
-static const struct pmc_bit_map tgl_clocksource_status_map[] = {
- {"USB2PLL_OFF_STS", BIT(18)},
- {"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)},
- {"PCIe_Gen3PLL_OFF_STS", BIT(20)},
- {"OPIOPLL_OFF_STS", BIT(21)},
- {"OCPLL_OFF_STS", BIT(22)},
- {"MainPLL_OFF_STS", BIT(23)},
- {"MIPIPLL_OFF_STS", BIT(24)},
- {"Fast_XTAL_Osc_OFF_STS", BIT(25)},
- {"AC_Ring_Osc_OFF_STS", BIT(26)},
- {"MC_Ring_Osc_OFF_STS", BIT(27)},
- {"SATAPLL_OFF_STS", BIT(29)},
- {"XTAL_USB2PLL_OFF_STS", BIT(31)},
- {}
-};
-
-static const struct pmc_bit_map tgl_power_gating_status_map[] = {
- {"CSME_PG_STS", BIT(0)},
- {"SATA_PG_STS", BIT(1)},
- {"xHCI_PG_STS", BIT(2)},
- {"UFSX2_PG_STS", BIT(3)},
- {"OTG_PG_STS", BIT(5)},
- {"SPA_PG_STS", BIT(6)},
- {"SPB_PG_STS", BIT(7)},
- {"SPC_PG_STS", BIT(8)},
- {"SPD_PG_STS", BIT(9)},
- {"SPE_PG_STS", BIT(10)},
- {"SPF_PG_STS", BIT(11)},
- {"LSX_PG_STS", BIT(13)},
- {"P2SB_PG_STS", BIT(14)},
- {"PSF_PG_STS", BIT(15)},
- {"SBR_PG_STS", BIT(16)},
- {"OPIDMI_PG_STS", BIT(17)},
- {"THC0_PG_STS", BIT(18)},
- {"THC1_PG_STS", BIT(19)},
- {"GBETSN_PG_STS", BIT(20)},
- {"GBE_PG_STS", BIT(21)},
- {"LPSS_PG_STS", BIT(22)},
- {"MMP_UFSX2_PG_STS", BIT(23)},
- {"MMP_UFSX2B_PG_STS", BIT(24)},
- {"FIA_PG_STS", BIT(25)},
- {}
-};
-
-static const struct pmc_bit_map tgl_d3_status_map[] = {
- {"ADSP_D3_STS", BIT(0)},
- {"SATA_D3_STS", BIT(1)},
- {"xHCI0_D3_STS", BIT(2)},
- {"xDCI1_D3_STS", BIT(5)},
- {"SDX_D3_STS", BIT(6)},
- {"EMMC_D3_STS", BIT(7)},
- {"IS_D3_STS", BIT(8)},
- {"THC0_D3_STS", BIT(9)},
- {"THC1_D3_STS", BIT(10)},
- {"GBE_D3_STS", BIT(11)},
- {"GBE_TSN_D3_STS", BIT(12)},
- {}
-};
-
-static const struct pmc_bit_map tgl_vnn_req_status_map[] = {
- {"GPIO_COM0_VNN_REQ_STS", BIT(1)},
- {"GPIO_COM1_VNN_REQ_STS", BIT(2)},
- {"GPIO_COM2_VNN_REQ_STS", BIT(3)},
- {"GPIO_COM3_VNN_REQ_STS", BIT(4)},
- {"GPIO_COM4_VNN_REQ_STS", BIT(5)},
- {"GPIO_COM5_VNN_REQ_STS", BIT(6)},
- {"Audio_VNN_REQ_STS", BIT(7)},
- {"ISH_VNN_REQ_STS", BIT(8)},
- {"CNVI_VNN_REQ_STS", BIT(9)},
- {"eSPI_VNN_REQ_STS", BIT(10)},
- {"Display_VNN_REQ_STS", BIT(11)},
- {"DTS_VNN_REQ_STS", BIT(12)},
- {"SMBUS_VNN_REQ_STS", BIT(14)},
- {"CSME_VNN_REQ_STS", BIT(15)},
- {"SMLINK0_VNN_REQ_STS", BIT(16)},
- {"SMLINK1_VNN_REQ_STS", BIT(17)},
- {"CLINK_VNN_REQ_STS", BIT(20)},
- {"DCI_VNN_REQ_STS", BIT(21)},
- {"ITH_VNN_REQ_STS", BIT(22)},
- {"CSME_VNN_REQ_STS", BIT(24)},
- {"GBE_VNN_REQ_STS", BIT(25)},
- {}
-};
-
-static const struct pmc_bit_map tgl_vnn_misc_status_map[] = {
- {"CPU_C10_REQ_STS_0", BIT(0)},
- {"PCIe_LPM_En_REQ_STS_3", BIT(3)},
- {"ITH_REQ_STS_5", BIT(5)},
- {"CNVI_REQ_STS_6", BIT(6)},
- {"ISH_REQ_STS_7", BIT(7)},
- {"USB2_SUS_PG_Sys_REQ_STS_10", BIT(10)},
- {"PCIe_Clk_REQ_STS_12", BIT(12)},
- {"MPHY_Core_DL_REQ_STS_16", BIT(16)},
- {"Break-even_En_REQ_STS_17", BIT(17)},
- {"Auto-demo_En_REQ_STS_18", BIT(18)},
- {"MPHY_SUS_REQ_STS_22", BIT(22)},
- {"xDCI_attached_REQ_STS_24", BIT(24)},
- {}
-};
-
-static const struct pmc_bit_map tgl_signal_status_map[] = {
- {"LSX_Wake0_En_STS", BIT(0)},
- {"LSX_Wake0_Pol_STS", BIT(1)},
- {"LSX_Wake1_En_STS", BIT(2)},
- {"LSX_Wake1_Pol_STS", BIT(3)},
- {"LSX_Wake2_En_STS", BIT(4)},
- {"LSX_Wake2_Pol_STS", BIT(5)},
- {"LSX_Wake3_En_STS", BIT(6)},
- {"LSX_Wake3_Pol_STS", BIT(7)},
- {"LSX_Wake4_En_STS", BIT(8)},
- {"LSX_Wake4_Pol_STS", BIT(9)},
- {"LSX_Wake5_En_STS", BIT(10)},
- {"LSX_Wake5_Pol_STS", BIT(11)},
- {"LSX_Wake6_En_STS", BIT(12)},
- {"LSX_Wake6_Pol_STS", BIT(13)},
- {"LSX_Wake7_En_STS", BIT(14)},
- {"LSX_Wake7_Pol_STS", BIT(15)},
- {"Intel_Se_IO_Wake0_En_STS", BIT(16)},
- {"Intel_Se_IO_Wake0_Pol_STS", BIT(17)},
- {"Intel_Se_IO_Wake1_En_STS", BIT(18)},
- {"Intel_Se_IO_Wake1_Pol_STS", BIT(19)},
- {"Int_Timer_SS_Wake0_En_STS", BIT(20)},
- {"Int_Timer_SS_Wake0_Pol_STS", BIT(21)},
- {"Int_Timer_SS_Wake1_En_STS", BIT(22)},
- {"Int_Timer_SS_Wake1_Pol_STS", BIT(23)},
- {"Int_Timer_SS_Wake2_En_STS", BIT(24)},
- {"Int_Timer_SS_Wake2_Pol_STS", BIT(25)},
- {"Int_Timer_SS_Wake3_En_STS", BIT(26)},
- {"Int_Timer_SS_Wake3_Pol_STS", BIT(27)},
- {"Int_Timer_SS_Wake4_En_STS", BIT(28)},
- {"Int_Timer_SS_Wake4_Pol_STS", BIT(29)},
- {"Int_Timer_SS_Wake5_En_STS", BIT(30)},
- {"Int_Timer_SS_Wake5_Pol_STS", BIT(31)},
- {}
-};
-
-static const struct pmc_bit_map *tgl_lpm_maps[] = {
- tgl_clocksource_status_map,
- tgl_power_gating_status_map,
- tgl_d3_status_map,
- tgl_vnn_req_status_map,
- tgl_vnn_misc_status_map,
- tgl_signal_status_map,
- NULL
-};
-
-static const struct pmc_reg_map tgl_reg_map = {
- .pfear_sts = ext_tgl_pfear_map,
- .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
- .ltr_show_sts = cnp_ltr_show_map,
- .msr_sts = msr_map,
- .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
- .regmap_length = CNP_PMC_MMIO_REG_LEN,
- .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
- .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
- .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
- .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
- .lpm_num_maps = TGL_LPM_NUM_MAPS,
- .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
- .lpm_sts_latch_en_offset = TGL_LPM_STS_LATCH_EN_OFFSET,
- .lpm_en_offset = TGL_LPM_EN_OFFSET,
- .lpm_priority_offset = TGL_LPM_PRI_OFFSET,
- .lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
- .lpm_sts = tgl_lpm_maps,
- .lpm_status_offset = TGL_LPM_STATUS_OFFSET,
- .lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET,
- .etr3_offset = ETR3_OFFSET,
-};
-
-static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
-{
- struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
- const int num_maps = pmcdev->map->lpm_num_maps;
- u32 lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
- union acpi_object *out_obj;
- struct acpi_device *adev;
- guid_t s0ix_dsm_guid;
- u32 *lpm_req_regs, *addr;
-
- adev = ACPI_COMPANION(&pdev->dev);
- if (!adev)
- return;
-
- guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
-
- out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
- ACPI_GET_LOW_MODE_REGISTERS, NULL);
- if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
- u32 size = out_obj->buffer.length;
-
- if (size != lpm_size) {
- acpi_handle_debug(adev->handle,
- "_DSM returned unexpected buffer size, have %u, expect %u\n",
- size, lpm_size);
- goto free_acpi_obj;
- }
- } else {
- acpi_handle_debug(adev->handle,
- "_DSM function 0 evaluation failed\n");
- goto free_acpi_obj;
- }
-
- addr = (u32 *)out_obj->buffer.pointer;
-
- lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
- GFP_KERNEL);
- if (!lpm_req_regs)
- goto free_acpi_obj;
-
- memcpy(lpm_req_regs, addr, lpm_size);
- pmcdev->lpm_req_regs = lpm_req_regs;
-
-free_acpi_obj:
- ACPI_FREE(out_obj);
-}
-
-/* Alder Lake: PGD PFET Enable Ack Status Register(s) bitmap */
-static const struct pmc_bit_map adl_pfear_map[] = {
- {"SPI/eSPI", BIT(2)},
- {"XHCI", BIT(3)},
- {"SPA", BIT(4)},
- {"SPB", BIT(5)},
- {"SPC", BIT(6)},
- {"GBE", BIT(7)},
-
- {"SATA", BIT(0)},
- {"HDA_PGD0", BIT(1)},
- {"HDA_PGD1", BIT(2)},
- {"HDA_PGD2", BIT(3)},
- {"HDA_PGD3", BIT(4)},
- {"SPD", BIT(5)},
- {"LPSS", BIT(6)},
-
- {"SMB", BIT(0)},
- {"ISH", BIT(1)},
- {"ITH", BIT(3)},
-
- {"XDCI", BIT(1)},
- {"DCI", BIT(2)},
- {"CSE", BIT(3)},
- {"CSME_KVM", BIT(4)},
- {"CSME_PMT", BIT(5)},
- {"CSME_CLINK", BIT(6)},
- {"CSME_PTIO", BIT(7)},
-
- {"CSME_USBR", BIT(0)},
- {"CSME_SUSRAM", BIT(1)},
- {"CSME_SMT1", BIT(2)},
- {"CSME_SMS2", BIT(4)},
- {"CSME_SMS1", BIT(5)},
- {"CSME_RTC", BIT(6)},
- {"CSME_PSF", BIT(7)},
-
- {"CNVI", BIT(3)},
-
- {"HDA_PGD4", BIT(2)},
- {"HDA_PGD5", BIT(3)},
- {"HDA_PGD6", BIT(4)},
- {}
-};
-
-static const struct pmc_bit_map *ext_adl_pfear_map[] = {
- /*
- * Check intel_pmc_core_ids[] users of cnp_reg_map for
- * a list of core SoCs using this.
- */
- adl_pfear_map,
- NULL
-};
-
-static const struct pmc_bit_map adl_ltr_show_map[] = {
- {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
- {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
- {"SATA", CNP_PMC_LTR_SATA},
- {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
- {"XHCI", CNP_PMC_LTR_XHCI},
- {"SOUTHPORT_F", ADL_PMC_LTR_SPF},
- {"ME", CNP_PMC_LTR_ME},
- /* EVA is Enterprise Value Add, doesn't really exist on PCH */
- {"SATA1", CNP_PMC_LTR_EVA},
- {"SOUTHPORT_C", CNP_PMC_LTR_SPC},
- {"HD_AUDIO", CNP_PMC_LTR_AZ},
- {"CNV", CNP_PMC_LTR_CNV},
- {"LPSS", CNP_PMC_LTR_LPSS},
- {"SOUTHPORT_D", CNP_PMC_LTR_SPD},
- {"SOUTHPORT_E", CNP_PMC_LTR_SPE},
- {"SATA2", CNP_PMC_LTR_CAM},
- {"ESPI", CNP_PMC_LTR_ESPI},
- {"SCC", CNP_PMC_LTR_SCC},
- {"ISH", CNP_PMC_LTR_ISH},
- {"UFSX2", CNP_PMC_LTR_UFSX2},
- {"EMMC", CNP_PMC_LTR_EMMC},
- /*
- * Check intel_pmc_core_ids[] users of cnp_reg_map for
- * a list of core SoCs using this.
- */
- {"WIGIG", ICL_PMC_LTR_WIGIG},
- {"THC0", TGL_PMC_LTR_THC0},
- {"THC1", TGL_PMC_LTR_THC1},
- {"SOUTHPORT_G", CNP_PMC_LTR_RESERVED},
-
- /* Below two cannot be used for LTR_IGNORE */
- {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
- {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
- {}
-};
-
-static const struct pmc_bit_map adl_clocksource_status_map[] = {
- {"CLKPART1_OFF_STS", BIT(0)},
- {"CLKPART2_OFF_STS", BIT(1)},
- {"CLKPART3_OFF_STS", BIT(2)},
- {"CLKPART4_OFF_STS", BIT(3)},
- {"CLKPART5_OFF_STS", BIT(4)},
- {"CLKPART6_OFF_STS", BIT(5)},
- {"CLKPART7_OFF_STS", BIT(6)},
- {"CLKPART8_OFF_STS", BIT(7)},
- {"PCIE0PLL_OFF_STS", BIT(10)},
- {"PCIE1PLL_OFF_STS", BIT(11)},
- {"PCIE2PLL_OFF_STS", BIT(12)},
- {"PCIE3PLL_OFF_STS", BIT(13)},
- {"PCIE4PLL_OFF_STS", BIT(14)},
- {"PCIE5PLL_OFF_STS", BIT(15)},
- {"PCIE6PLL_OFF_STS", BIT(16)},
- {"USB2PLL_OFF_STS", BIT(18)},
- {"OCPLL_OFF_STS", BIT(22)},
- {"AUDIOPLL_OFF_STS", BIT(23)},
- {"GBEPLL_OFF_STS", BIT(24)},
- {"Fast_XTAL_Osc_OFF_STS", BIT(25)},
- {"AC_Ring_Osc_OFF_STS", BIT(26)},
- {"MC_Ring_Osc_OFF_STS", BIT(27)},
- {"SATAPLL_OFF_STS", BIT(29)},
- {"USB3PLL_OFF_STS", BIT(31)},
- {}
-};
-
-static const struct pmc_bit_map adl_power_gating_status_0_map[] = {
- {"PMC_PGD0_PG_STS", BIT(0)},
- {"DMI_PGD0_PG_STS", BIT(1)},
- {"ESPISPI_PGD0_PG_STS", BIT(2)},
- {"XHCI_PGD0_PG_STS", BIT(3)},
- {"SPA_PGD0_PG_STS", BIT(4)},
- {"SPB_PGD0_PG_STS", BIT(5)},
- {"SPC_PGD0_PG_STS", BIT(6)},
- {"GBE_PGD0_PG_STS", BIT(7)},
- {"SATA_PGD0_PG_STS", BIT(8)},
- {"DSP_PGD0_PG_STS", BIT(9)},
- {"DSP_PGD1_PG_STS", BIT(10)},
- {"DSP_PGD2_PG_STS", BIT(11)},
- {"DSP_PGD3_PG_STS", BIT(12)},
- {"SPD_PGD0_PG_STS", BIT(13)},
- {"LPSS_PGD0_PG_STS", BIT(14)},
- {"SMB_PGD0_PG_STS", BIT(16)},
- {"ISH_PGD0_PG_STS", BIT(17)},
- {"NPK_PGD0_PG_STS", BIT(19)},
- {"PECI_PGD0_PG_STS", BIT(21)},
- {"XDCI_PGD0_PG_STS", BIT(25)},
- {"EXI_PGD0_PG_STS", BIT(26)},
- {"CSE_PGD0_PG_STS", BIT(27)},
- {"KVMCC_PGD0_PG_STS", BIT(28)},
- {"PMT_PGD0_PG_STS", BIT(29)},
- {"CLINK_PGD0_PG_STS", BIT(30)},
- {"PTIO_PGD0_PG_STS", BIT(31)},
- {}
-};
-
-static const struct pmc_bit_map adl_power_gating_status_1_map[] = {
- {"USBR0_PGD0_PG_STS", BIT(0)},
- {"SMT1_PGD0_PG_STS", BIT(2)},
- {"CSMERTC_PGD0_PG_STS", BIT(6)},
- {"CSMEPSF_PGD0_PG_STS", BIT(7)},
- {"CNVI_PGD0_PG_STS", BIT(19)},
- {"DSP_PGD4_PG_STS", BIT(26)},
- {"SPG_PGD0_PG_STS", BIT(27)},
- {"SPE_PGD0_PG_STS", BIT(28)},
- {}
-};
-
-static const struct pmc_bit_map adl_power_gating_status_2_map[] = {
- {"THC0_PGD0_PG_STS", BIT(7)},
- {"THC1_PGD0_PG_STS", BIT(8)},
- {"SPF_PGD0_PG_STS", BIT(14)},
- {}
-};
-
-static const struct pmc_bit_map adl_d3_status_0_map[] = {
- {"ISH_D3_STS", BIT(2)},
- {"LPSS_D3_STS", BIT(3)},
- {"XDCI_D3_STS", BIT(4)},
- {"XHCI_D3_STS", BIT(5)},
- {"SPA_D3_STS", BIT(12)},
- {"SPB_D3_STS", BIT(13)},
- {"SPC_D3_STS", BIT(14)},
- {"SPD_D3_STS", BIT(15)},
- {"SPE_D3_STS", BIT(16)},
- {"DSP_D3_STS", BIT(19)},
- {"SATA_D3_STS", BIT(20)},
- {"DMI_D3_STS", BIT(22)},
- {}
-};
-
-static const struct pmc_bit_map adl_d3_status_1_map[] = {
- {"GBE_D3_STS", BIT(19)},
- {"CNVI_D3_STS", BIT(27)},
- {}
-};
-
-static const struct pmc_bit_map adl_d3_status_2_map[] = {
- {"CSMERTC_D3_STS", BIT(1)},
- {"CSE_D3_STS", BIT(4)},
- {"KVMCC_D3_STS", BIT(5)},
- {"USBR0_D3_STS", BIT(6)},
- {"SMT1_D3_STS", BIT(8)},
- {"PTIO_D3_STS", BIT(16)},
- {"PMT_D3_STS", BIT(17)},
- {}
-};
-
-static const struct pmc_bit_map adl_d3_status_3_map[] = {
- {"THC0_D3_STS", BIT(14)},
- {"THC1_D3_STS", BIT(15)},
- {}
-};
-
-static const struct pmc_bit_map adl_vnn_req_status_0_map[] = {
- {"ISH_VNN_REQ_STS", BIT(2)},
- {"ESPISPI_VNN_REQ_STS", BIT(18)},
- {"DSP_VNN_REQ_STS", BIT(19)},
- {}
-};
-
-static const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
- {"NPK_VNN_REQ_STS", BIT(4)},
- {"EXI_VNN_REQ_STS", BIT(9)},
- {"GBE_VNN_REQ_STS", BIT(19)},
- {"SMB_VNN_REQ_STS", BIT(25)},
- {"CNVI_VNN_REQ_STS", BIT(27)},
- {}
-};
-
-static const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
- {"CSMERTC_VNN_REQ_STS", BIT(1)},
- {"CSE_VNN_REQ_STS", BIT(4)},
- {"SMT1_VNN_REQ_STS", BIT(8)},
- {"CLINK_VNN_REQ_STS", BIT(14)},
- {"GPIOCOM4_VNN_REQ_STS", BIT(20)},
- {"GPIOCOM3_VNN_REQ_STS", BIT(21)},
- {"GPIOCOM2_VNN_REQ_STS", BIT(22)},
- {"GPIOCOM1_VNN_REQ_STS", BIT(23)},
- {"GPIOCOM0_VNN_REQ_STS", BIT(24)},
- {}
-};
-
-static const struct pmc_bit_map adl_vnn_req_status_3_map[] = {
- {"GPIOCOM5_VNN_REQ_STS", BIT(11)},
- {}
-};
-
-static const struct pmc_bit_map adl_vnn_misc_status_map[] = {
- {"CPU_C10_REQ_STS", BIT(0)},
- {"PCIe_LPM_En_REQ_STS", BIT(3)},
- {"ITH_REQ_STS", BIT(5)},
- {"CNVI_REQ_STS", BIT(6)},
- {"ISH_REQ_STS", BIT(7)},
- {"USB2_SUS_PG_Sys_REQ_STS", BIT(10)},
- {"PCIe_Clk_REQ_STS", BIT(12)},
- {"MPHY_Core_DL_REQ_STS", BIT(16)},
- {"Break-even_En_REQ_STS", BIT(17)},
- {"MPHY_SUS_REQ_STS", BIT(22)},
- {"xDCI_attached_REQ_STS", BIT(24)},
- {}
-};
-
-static const struct pmc_bit_map *adl_lpm_maps[] = {
- adl_clocksource_status_map,
- adl_power_gating_status_0_map,
- adl_power_gating_status_1_map,
- adl_power_gating_status_2_map,
- adl_d3_status_0_map,
- adl_d3_status_1_map,
- adl_d3_status_2_map,
- adl_d3_status_3_map,
- adl_vnn_req_status_0_map,
- adl_vnn_req_status_1_map,
- adl_vnn_req_status_2_map,
- adl_vnn_req_status_3_map,
- adl_vnn_misc_status_map,
- tgl_signal_status_map,
- NULL
-};
-
-static const struct pmc_reg_map adl_reg_map = {
- .pfear_sts = ext_adl_pfear_map,
- .slp_s0_offset = ADL_PMC_SLP_S0_RES_COUNTER_OFFSET,
- .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
- .ltr_show_sts = adl_ltr_show_map,
- .msr_sts = msr_map,
- .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
- .regmap_length = CNP_PMC_MMIO_REG_LEN,
- .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
- .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
- .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
- .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
- .lpm_num_modes = ADL_LPM_NUM_MODES,
- .lpm_num_maps = ADL_LPM_NUM_MAPS,
- .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
- .etr3_offset = ETR3_OFFSET,
- .lpm_sts_latch_en_offset = ADL_LPM_STATUS_LATCH_EN_OFFSET,
- .lpm_priority_offset = ADL_LPM_PRI_OFFSET,
- .lpm_en_offset = ADL_LPM_EN_OFFSET,
- .lpm_residency_offset = ADL_LPM_RESIDENCY_OFFSET,
- .lpm_sts = adl_lpm_maps,
- .lpm_status_offset = ADL_LPM_STATUS_OFFSET,
- .lpm_live_status_offset = ADL_LPM_LIVE_STATUS_OFFSET,
-};
-
static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
{
return readl(pmcdev->regbase + reg_offset);
@@ -1327,7 +435,7 @@ out_unlock:
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);
-static int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
+int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
{
const struct pmc_reg_map *map = pmcdev->map;
u32 reg;
@@ -1793,7 +901,11 @@ static void pmc_core_get_low_power_modes(struct platform_device *pdev)
return;
lpm_en = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_en_offset);
- pmcdev->num_lpm_modes = hweight32(lpm_en);
+ /* For MTL, BIT 31 is not an lpm mode but a enable bit.
+ * Lower byte is enough to cover the number of lpm modes for all
+ * platforms and hence mask the upper 3 bytes.
+ */
+ pmcdev->num_lpm_modes = hweight32(lpm_en & 0xFF);
/* Read 32 bit LPM_PRI register */
lpm_pri = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_priority_offset);
@@ -1896,26 +1008,27 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
}
static const struct x86_cpu_id intel_pmc_core_ids[] = {
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &spt_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &spt_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &spt_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &spt_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &cnp_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &icl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI, &icl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &cnp_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &cnp_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &icl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &adl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &tgl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &adl_reg_map),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &adl_reg_map),
+ X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, spt_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, spt_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, spt_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, spt_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, cnp_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, icl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI, icl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, cnp_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, cnp_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, icl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, adl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, adl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, adl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, mtl_core_init),
{}
};
@@ -1975,6 +1088,7 @@ static int pmc_core_probe(struct platform_device *pdev)
static bool device_initialized;
struct pmc_dev *pmcdev;
const struct x86_cpu_id *cpu_id;
+ void (*core_init)(struct pmc_dev *pmcdev);
u64 slp_s0_addr;
if (device_initialized)
@@ -1985,20 +1099,25 @@ static int pmc_core_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, pmcdev);
+ pmcdev->pdev = pdev;
cpu_id = x86_match_cpu(intel_pmc_core_ids);
if (!cpu_id)
return -ENODEV;
- pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data;
+ core_init = (void (*)(struct pmc_dev *))cpu_id->driver_data;
/*
* Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here
* Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap
* in this case.
*/
- if (pmcdev->map == &spt_reg_map && !pci_dev_present(pmc_pci_ids))
- pmcdev->map = &cnp_reg_map;
+ if (core_init == spt_core_init && !pci_dev_present(pmc_pci_ids))
+ core_init = cnp_core_init;
+
+ mutex_init(&pmcdev->lock);
+ core_init(pmcdev);
+
if (lpit_read_residency_count_address(&slp_s0_addr)) {
pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT;
@@ -2014,24 +1133,13 @@ static int pmc_core_probe(struct platform_device *pdev)
if (!pmcdev->regbase)
return -ENOMEM;
- mutex_init(&pmcdev->lock);
+ if (pmcdev->core_configure)
+ pmcdev->core_configure(pmcdev);
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev);
pmc_core_get_low_power_modes(pdev);
pmc_core_do_dmi_quirks(pmcdev);
- if (pmcdev->map == &tgl_reg_map)
- pmc_core_get_tgl_lpm_reqs(pdev);
-
- /*
- * On TGL and ADL, due to a hardware limitation, the GBE LTR blocks PC10
- * when a cable is attached. Tell the PMC to ignore it.
- */
- if (pmcdev->map == &tgl_reg_map || pmcdev->map == &adl_reg_map) {
- dev_dbg(&pdev->dev, "ignoring GBE LTR\n");
- pmc_core_send_ltr_ignore(pmcdev, 3);
- }
-
pmc_core_dbgfs_register(pmcdev);
device_initialized = true;
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 7a059e02c265..810204d758ab 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -12,7 +12,9 @@
#ifndef PMC_CORE_H
#define PMC_CORE_H
+#include <linux/acpi.h>
#include <linux/bits.h>
+#include <linux/platform_device.h>
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
@@ -236,17 +238,17 @@ enum ppfear_regs {
#define ADL_LPM_STATUS_LATCH_EN_OFFSET 0x1704
#define ADL_LPM_LIVE_STATUS_OFFSET 0x1764
-static const char *pmc_lpm_modes[] = {
- "S0i2.0",
- "S0i2.1",
- "S0i2.2",
- "S0i3.0",
- "S0i3.1",
- "S0i3.2",
- "S0i3.3",
- "S0i3.4",
- NULL
-};
+/* Meteor Lake Power Management Controller register offsets */
+#define MTL_LPM_EN_OFFSET 0x1798
+#define MTL_LPM_RESIDENCY_OFFSET 0x17A0
+
+/* Meteor Lake Low Power Mode debug registers */
+#define MTL_LPM_PRI_OFFSET 0x179C
+#define MTL_LPM_STATUS_LATCH_EN_OFFSET 0x16F8
+#define MTL_LPM_STATUS_OFFSET 0x1700
+#define MTL_LPM_LIVE_STATUS_OFFSET 0x175C
+
+extern const char *pmc_lpm_modes[];
struct pmc_bit_map {
const char *name;
@@ -264,7 +266,7 @@ struct pmc_bit_map {
* @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
* @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
* @regmap_length: Length of memory to map from PWRMBASE address to access
- * @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
+ * @ppfear0_offset: PWRMBASE offset to read PPFEAR*
* @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
* PPFEAR
* @pm_cfg_offset: PWRMBASE offset to PM_CFG register
@@ -312,6 +314,7 @@ struct pmc_reg_map {
* @regbase: pointer to io-remapped memory location
* @map: pointer to pmc_reg_map struct that contains platform
* specific attributes
+ * @pdev: pointer to platform_device struct
* @dbgfs_dir: path to debugfs interface
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
* used to read MPHY PG and PLL status are available
@@ -322,6 +325,7 @@ struct pmc_reg_map {
* @num_lpm_modes: Count of enabled modes
* @lpm_en_modes: Array of enabled modes from lowest to highest priority
* @lpm_req_regs: List of substate requirements
+ * @core_configure: Function pointer to configure the platform
*
* pmc_dev contains info about power management controller device.
*/
@@ -330,6 +334,7 @@ struct pmc_dev {
void __iomem *regbase;
const struct pmc_reg_map *map;
struct dentry *dbgfs_dir;
+ struct platform_device *pdev;
int pmc_xram_read_bit;
struct mutex lock; /* generic mutex lock for PMC Core */
@@ -339,8 +344,70 @@ struct pmc_dev {
int num_lpm_modes;
int lpm_en_modes[LPM_MAX_NUM_MODES];
u32 *lpm_req_regs;
+ void (*core_configure)(struct pmc_dev *pmcdev);
};
+extern const struct pmc_bit_map msr_map[];
+extern const struct pmc_bit_map spt_pll_map[];
+extern const struct pmc_bit_map spt_mphy_map[];
+extern const struct pmc_bit_map spt_pfear_map[];
+extern const struct pmc_bit_map *ext_spt_pfear_map[];
+extern const struct pmc_bit_map spt_ltr_show_map[];
+extern const struct pmc_reg_map spt_reg_map;
+extern const struct pmc_bit_map cnp_pfear_map[];
+extern const struct pmc_bit_map *ext_cnp_pfear_map[];
+extern const struct pmc_bit_map cnp_slps0_dbg0_map[];
+extern const struct pmc_bit_map cnp_slps0_dbg1_map[];
+extern const struct pmc_bit_map cnp_slps0_dbg2_map[];
+extern const struct pmc_bit_map *cnp_slps0_dbg_maps[];
+extern const struct pmc_bit_map cnp_ltr_show_map[];
+extern const struct pmc_reg_map cnp_reg_map;
+extern const struct pmc_bit_map icl_pfear_map[];
+extern const struct pmc_bit_map *ext_icl_pfear_map[];
+extern const struct pmc_reg_map icl_reg_map;
+extern const struct pmc_bit_map tgl_pfear_map[];
+extern const struct pmc_bit_map *ext_tgl_pfear_map[];
+extern const struct pmc_bit_map tgl_clocksource_status_map[];
+extern const struct pmc_bit_map tgl_power_gating_status_map[];
+extern const struct pmc_bit_map tgl_d3_status_map[];
+extern const struct pmc_bit_map tgl_vnn_req_status_map[];
+extern const struct pmc_bit_map tgl_vnn_misc_status_map[];
+extern const struct pmc_bit_map tgl_signal_status_map[];
+extern const struct pmc_bit_map *tgl_lpm_maps[];
+extern const struct pmc_reg_map tgl_reg_map;
+extern const struct pmc_bit_map adl_pfear_map[];
+extern const struct pmc_bit_map *ext_adl_pfear_map[];
+extern const struct pmc_bit_map adl_ltr_show_map[];
+extern const struct pmc_bit_map adl_clocksource_status_map[];
+extern const struct pmc_bit_map adl_power_gating_status_0_map[];
+extern const struct pmc_bit_map adl_power_gating_status_1_map[];
+extern const struct pmc_bit_map adl_power_gating_status_2_map[];
+extern const struct pmc_bit_map adl_d3_status_0_map[];
+extern const struct pmc_bit_map adl_d3_status_1_map[];
+extern const struct pmc_bit_map adl_d3_status_2_map[];
+extern const struct pmc_bit_map adl_d3_status_3_map[];
+extern const struct pmc_bit_map adl_vnn_req_status_0_map[];
+extern const struct pmc_bit_map adl_vnn_req_status_1_map[];
+extern const struct pmc_bit_map adl_vnn_req_status_2_map[];
+extern const struct pmc_bit_map adl_vnn_req_status_3_map[];
+extern const struct pmc_bit_map adl_vnn_misc_status_map[];
+extern const struct pmc_bit_map *adl_lpm_maps[];
+extern const struct pmc_reg_map adl_reg_map;
+extern const struct pmc_reg_map mtl_reg_map;
+
+extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
+extern int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value);
+
+void spt_core_init(struct pmc_dev *pmcdev);
+void cnp_core_init(struct pmc_dev *pmcdev);
+void icl_core_init(struct pmc_dev *pmcdev);
+void tgl_core_init(struct pmc_dev *pmcdev);
+void adl_core_init(struct pmc_dev *pmcdev);
+void mtl_core_init(struct pmc_dev *pmcdev);
+void tgl_core_configure(struct pmc_dev *pmcdev);
+void adl_core_configure(struct pmc_dev *pmcdev);
+void mtl_core_configure(struct pmc_dev *pmcdev);
+
#define pmc_for_each_mode(i, mode, pmcdev) \
for (i = 0, mode = pmcdev->lpm_en_modes[i]; \
i < pmcdev->num_lpm_modes; \
diff --git a/drivers/platform/x86/intel/pmc/icl.c b/drivers/platform/x86/intel/pmc/icl.c
new file mode 100644
index 000000000000..2f11b1a6daeb
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/icl.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Ice Lake PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+const struct pmc_bit_map icl_pfear_map[] = {
+ {"RES_65", BIT(0)},
+ {"RES_66", BIT(1)},
+ {"RES_67", BIT(2)},
+ {"TAM", BIT(3)},
+ {"GBETSN", BIT(4)},
+ {"TBTLSX", BIT(5)},
+ {"RES_71", BIT(6)},
+ {"RES_72", BIT(7)},
+ {}
+};
+
+const struct pmc_bit_map *ext_icl_pfear_map[] = {
+ /*
+ * Check intel_pmc_core_ids[] users of icl_reg_map for
+ * a list of core SoCs using this.
+ */
+ cnp_pfear_map,
+ icl_pfear_map,
+ NULL
+};
+
+const struct pmc_reg_map icl_reg_map = {
+ .pfear_sts = ext_icl_pfear_map,
+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP,
+ .slps0_dbg_maps = cnp_slps0_dbg_maps,
+ .ltr_show_sts = cnp_ltr_show_map,
+ .msr_sts = msr_map,
+ .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
+ .etr3_offset = ETR3_OFFSET,
+};
+
+void icl_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &icl_reg_map;
+}
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
new file mode 100644
index 000000000000..eeb3bd8c2502
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Meteor Lake PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+const struct pmc_reg_map mtl_reg_map = {
+ .pfear_sts = ext_tgl_pfear_map,
+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
+ .ltr_show_sts = adl_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
+ .lpm_num_modes = ADL_LPM_NUM_MODES,
+ .lpm_num_maps = ADL_LPM_NUM_MAPS,
+ .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
+ .etr3_offset = ETR3_OFFSET,
+ .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
+ .lpm_priority_offset = MTL_LPM_PRI_OFFSET,
+ .lpm_en_offset = MTL_LPM_EN_OFFSET,
+ .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
+ .lpm_sts = adl_lpm_maps,
+ .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
+};
+
+void mtl_core_configure(struct pmc_dev *pmcdev)
+{
+ /* Due to a hardware limitation, the GBE LTR blocks PC10
+ * when a cable is attached. Tell the PMC to ignore it.
+ */
+ dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+ pmc_core_send_ltr_ignore(pmcdev, 3);
+}
+
+void mtl_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &mtl_reg_map;
+ pmcdev->core_configure = mtl_core_configure;
+}
diff --git a/drivers/platform/x86/intel/pmc/pltdrv.c b/drivers/platform/x86/intel/pmc/pltdrv.c
index 15ca8afdd973..ddfba38c2104 100644
--- a/drivers/platform/x86/intel/pmc/pltdrv.c
+++ b/drivers/platform/x86/intel/pmc/pltdrv.c
@@ -18,6 +18,8 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
+#include <xen/xen.h>
+
static void intel_pmc_core_release(struct device *dev)
{
kfree(dev);
@@ -53,6 +55,13 @@ static int __init pmc_core_platform_init(void)
if (acpi_dev_present("INT33A1", NULL, -1))
return -ENODEV;
+ /*
+ * Skip forcefully attaching the device for VMs. Make an exception for
+ * Xen dom0, which does have full hardware access.
+ */
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR) && !xen_initial_domain())
+ return -ENODEV;
+
if (!x86_match_cpu(intel_pmc_core_platform_ids))
return -ENODEV;
diff --git a/drivers/platform/x86/intel/pmc/spt.c b/drivers/platform/x86/intel/pmc/spt.c
new file mode 100644
index 000000000000..e16982236778
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/spt.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Sunrise Point PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+const struct pmc_bit_map spt_pll_map[] = {
+ {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0},
+ {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
+ {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
+ {"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3},
+ {}
+};
+
+const struct pmc_bit_map spt_mphy_map[] = {
+ {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0},
+ {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1},
+ {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2},
+ {"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3},
+ {"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4},
+ {"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5},
+ {"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6},
+ {"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7},
+ {"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8},
+ {"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9},
+ {"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10},
+ {"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11},
+ {"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12},
+ {"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13},
+ {"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14},
+ {"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15},
+ {}
+};
+
+const struct pmc_bit_map spt_pfear_map[] = {
+ {"PMC", SPT_PMC_BIT_PMC},
+ {"OPI-DMI", SPT_PMC_BIT_OPI},
+ {"SPI / eSPI", SPT_PMC_BIT_SPI},
+ {"XHCI", SPT_PMC_BIT_XHCI},
+ {"SPA", SPT_PMC_BIT_SPA},
+ {"SPB", SPT_PMC_BIT_SPB},
+ {"SPC", SPT_PMC_BIT_SPC},
+ {"GBE", SPT_PMC_BIT_GBE},
+ {"SATA", SPT_PMC_BIT_SATA},
+ {"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0},
+ {"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1},
+ {"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2},
+ {"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3},
+ {"RSVD", SPT_PMC_BIT_RSVD_0B},
+ {"LPSS", SPT_PMC_BIT_LPSS},
+ {"LPC", SPT_PMC_BIT_LPC},
+ {"SMB", SPT_PMC_BIT_SMB},
+ {"ISH", SPT_PMC_BIT_ISH},
+ {"P2SB", SPT_PMC_BIT_P2SB},
+ {"DFX", SPT_PMC_BIT_DFX},
+ {"SCC", SPT_PMC_BIT_SCC},
+ {"RSVD", SPT_PMC_BIT_RSVD_0C},
+ {"FUSE", SPT_PMC_BIT_FUSE},
+ {"CAMERA", SPT_PMC_BIT_CAMREA},
+ {"RSVD", SPT_PMC_BIT_RSVD_0D},
+ {"USB3-OTG", SPT_PMC_BIT_USB3_OTG},
+ {"EXI", SPT_PMC_BIT_EXI},
+ {"CSE", SPT_PMC_BIT_CSE},
+ {"CSME_KVM", SPT_PMC_BIT_CSME_KVM},
+ {"CSME_PMT", SPT_PMC_BIT_CSME_PMT},
+ {"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK},
+ {"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO},
+ {"CSME_USBR", SPT_PMC_BIT_CSME_USBR},
+ {"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM},
+ {"CSME_SMT", SPT_PMC_BIT_CSME_SMT},
+ {"RSVD", SPT_PMC_BIT_RSVD_1A},
+ {"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2},
+ {"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1},
+ {"CSME_RTC", SPT_PMC_BIT_CSME_RTC},
+ {"CSME_PSF", SPT_PMC_BIT_CSME_PSF},
+ {}
+};
+
+const struct pmc_bit_map *ext_spt_pfear_map[] = {
+ /*
+ * Check intel_pmc_core_ids[] users of spt_reg_map for
+ * a list of core SoCs using this.
+ */
+ spt_pfear_map,
+ NULL
+};
+
+const struct pmc_bit_map spt_ltr_show_map[] = {
+ {"SOUTHPORT_A", SPT_PMC_LTR_SPA},
+ {"SOUTHPORT_B", SPT_PMC_LTR_SPB},
+ {"SATA", SPT_PMC_LTR_SATA},
+ {"GIGABIT_ETHERNET", SPT_PMC_LTR_GBE},
+ {"XHCI", SPT_PMC_LTR_XHCI},
+ {"Reserved", SPT_PMC_LTR_RESERVED},
+ {"ME", SPT_PMC_LTR_ME},
+ /* EVA is Enterprise Value Add, doesn't really exist on PCH */
+ {"EVA", SPT_PMC_LTR_EVA},
+ {"SOUTHPORT_C", SPT_PMC_LTR_SPC},
+ {"HD_AUDIO", SPT_PMC_LTR_AZ},
+ {"LPSS", SPT_PMC_LTR_LPSS},
+ {"SOUTHPORT_D", SPT_PMC_LTR_SPD},
+ {"SOUTHPORT_E", SPT_PMC_LTR_SPE},
+ {"CAMERA", SPT_PMC_LTR_CAM},
+ {"ESPI", SPT_PMC_LTR_ESPI},
+ {"SCC", SPT_PMC_LTR_SCC},
+ {"ISH", SPT_PMC_LTR_ISH},
+ /* Below two cannot be used for LTR_IGNORE */
+ {"CURRENT_PLATFORM", SPT_PMC_LTR_CUR_PLT},
+ {"AGGREGATED_SYSTEM", SPT_PMC_LTR_CUR_ASLT},
+ {}
+};
+
+const struct pmc_reg_map spt_reg_map = {
+ .pfear_sts = ext_spt_pfear_map,
+ .mphy_sts = spt_mphy_map,
+ .pll_sts = spt_pll_map,
+ .ltr_show_sts = spt_ltr_show_map,
+ .msr_sts = msr_map,
+ .slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
+ .ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = SPT_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = SPT_PMC_XRAM_PPFEAR0A,
+ .ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED,
+ .pm_vric1_offset = SPT_PMC_VRIC1_OFFSET,
+};
+
+void spt_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &spt_reg_map;
+}
diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c
new file mode 100644
index 000000000000..e3e50538465d
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/tgl.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Tiger Lake PCH.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ */
+
+#include "core.h"
+
+#define ACPI_S0IX_DSM_UUID "57a6512e-3979-4e9d-9708-ff13b2508972"
+#define ACPI_GET_LOW_MODE_REGISTERS 1
+
+const struct pmc_bit_map tgl_pfear_map[] = {
+ {"PSF9", BIT(0)},
+ {"RES_66", BIT(1)},
+ {"RES_67", BIT(2)},
+ {"RES_68", BIT(3)},
+ {"RES_69", BIT(4)},
+ {"RES_70", BIT(5)},
+ {"TBTLSX", BIT(6)},
+ {}
+};
+
+const struct pmc_bit_map *ext_tgl_pfear_map[] = {
+ /*
+ * Check intel_pmc_core_ids[] users of tgl_reg_map for
+ * a list of core SoCs using this.
+ */
+ cnp_pfear_map,
+ tgl_pfear_map,
+ NULL
+};
+
+const struct pmc_bit_map tgl_clocksource_status_map[] = {
+ {"USB2PLL_OFF_STS", BIT(18)},
+ {"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)},
+ {"PCIe_Gen3PLL_OFF_STS", BIT(20)},
+ {"OPIOPLL_OFF_STS", BIT(21)},
+ {"OCPLL_OFF_STS", BIT(22)},
+ {"MainPLL_OFF_STS", BIT(23)},
+ {"MIPIPLL_OFF_STS", BIT(24)},
+ {"Fast_XTAL_Osc_OFF_STS", BIT(25)},
+ {"AC_Ring_Osc_OFF_STS", BIT(26)},
+ {"MC_Ring_Osc_OFF_STS", BIT(27)},
+ {"SATAPLL_OFF_STS", BIT(29)},
+ {"XTAL_USB2PLL_OFF_STS", BIT(31)},
+ {}
+};
+
+const struct pmc_bit_map tgl_power_gating_status_map[] = {
+ {"CSME_PG_STS", BIT(0)},
+ {"SATA_PG_STS", BIT(1)},
+ {"xHCI_PG_STS", BIT(2)},
+ {"UFSX2_PG_STS", BIT(3)},
+ {"OTG_PG_STS", BIT(5)},
+ {"SPA_PG_STS", BIT(6)},
+ {"SPB_PG_STS", BIT(7)},
+ {"SPC_PG_STS", BIT(8)},
+ {"SPD_PG_STS", BIT(9)},
+ {"SPE_PG_STS", BIT(10)},
+ {"SPF_PG_STS", BIT(11)},
+ {"LSX_PG_STS", BIT(13)},
+ {"P2SB_PG_STS", BIT(14)},
+ {"PSF_PG_STS", BIT(15)},
+ {"SBR_PG_STS", BIT(16)},
+ {"OPIDMI_PG_STS", BIT(17)},
+ {"THC0_PG_STS", BIT(18)},
+ {"THC1_PG_STS", BIT(19)},
+ {"GBETSN_PG_STS", BIT(20)},
+ {"GBE_PG_STS", BIT(21)},
+ {"LPSS_PG_STS", BIT(22)},
+ {"MMP_UFSX2_PG_STS", BIT(23)},
+ {"MMP_UFSX2B_PG_STS", BIT(24)},
+ {"FIA_PG_STS", BIT(25)},
+ {}
+};
+
+const struct pmc_bit_map tgl_d3_status_map[] = {
+ {"ADSP_D3_STS", BIT(0)},
+ {"SATA_D3_STS", BIT(1)},
+ {"xHCI0_D3_STS", BIT(2)},
+ {"xDCI1_D3_STS", BIT(5)},
+ {"SDX_D3_STS", BIT(6)},
+ {"EMMC_D3_STS", BIT(7)},
+ {"IS_D3_STS", BIT(8)},
+ {"THC0_D3_STS", BIT(9)},
+ {"THC1_D3_STS", BIT(10)},
+ {"GBE_D3_STS", BIT(11)},
+ {"GBE_TSN_D3_STS", BIT(12)},
+ {}
+};
+
+const struct pmc_bit_map tgl_vnn_req_status_map[] = {
+ {"GPIO_COM0_VNN_REQ_STS", BIT(1)},
+ {"GPIO_COM1_VNN_REQ_STS", BIT(2)},
+ {"GPIO_COM2_VNN_REQ_STS", BIT(3)},
+ {"GPIO_COM3_VNN_REQ_STS", BIT(4)},
+ {"GPIO_COM4_VNN_REQ_STS", BIT(5)},
+ {"GPIO_COM5_VNN_REQ_STS", BIT(6)},
+ {"Audio_VNN_REQ_STS", BIT(7)},
+ {"ISH_VNN_REQ_STS", BIT(8)},
+ {"CNVI_VNN_REQ_STS", BIT(9)},
+ {"eSPI_VNN_REQ_STS", BIT(10)},
+ {"Display_VNN_REQ_STS", BIT(11)},
+ {"DTS_VNN_REQ_STS", BIT(12)},
+ {"SMBUS_VNN_REQ_STS", BIT(14)},
+ {"CSME_VNN_REQ_STS", BIT(15)},
+ {"SMLINK0_VNN_REQ_STS", BIT(16)},
+ {"SMLINK1_VNN_REQ_STS", BIT(17)},
+ {"CLINK_VNN_REQ_STS", BIT(20)},
+ {"DCI_VNN_REQ_STS", BIT(21)},
+ {"ITH_VNN_REQ_STS", BIT(22)},
+ {"CSME_VNN_REQ_STS", BIT(24)},
+ {"GBE_VNN_REQ_STS", BIT(25)},
+ {}
+};
+
+const struct pmc_bit_map tgl_vnn_misc_status_map[] = {
+ {"CPU_C10_REQ_STS_0", BIT(0)},
+ {"PCIe_LPM_En_REQ_STS_3", BIT(3)},
+ {"ITH_REQ_STS_5", BIT(5)},
+ {"CNVI_REQ_STS_6", BIT(6)},
+ {"ISH_REQ_STS_7", BIT(7)},
+ {"USB2_SUS_PG_Sys_REQ_STS_10", BIT(10)},
+ {"PCIe_Clk_REQ_STS_12", BIT(12)},
+ {"MPHY_Core_DL_REQ_STS_16", BIT(16)},
+ {"Break-even_En_REQ_STS_17", BIT(17)},
+ {"Auto-demo_En_REQ_STS_18", BIT(18)},
+ {"MPHY_SUS_REQ_STS_22", BIT(22)},
+ {"xDCI_attached_REQ_STS_24", BIT(24)},
+ {}
+};
+
+const struct pmc_bit_map tgl_signal_status_map[] = {
+ {"LSX_Wake0_En_STS", BIT(0)},
+ {"LSX_Wake0_Pol_STS", BIT(1)},
+ {"LSX_Wake1_En_STS", BIT(2)},
+ {"LSX_Wake1_Pol_STS", BIT(3)},
+ {"LSX_Wake2_En_STS", BIT(4)},
+ {"LSX_Wake2_Pol_STS", BIT(5)},
+ {"LSX_Wake3_En_STS", BIT(6)},
+ {"LSX_Wake3_Pol_STS", BIT(7)},
+ {"LSX_Wake4_En_STS", BIT(8)},
+ {"LSX_Wake4_Pol_STS", BIT(9)},
+ {"LSX_Wake5_En_STS", BIT(10)},
+ {"LSX_Wake5_Pol_STS", BIT(11)},
+ {"LSX_Wake6_En_STS", BIT(12)},
+ {"LSX_Wake6_Pol_STS", BIT(13)},
+ {"LSX_Wake7_En_STS", BIT(14)},
+ {"LSX_Wake7_Pol_STS", BIT(15)},
+ {"Intel_Se_IO_Wake0_En_STS", BIT(16)},
+ {"Intel_Se_IO_Wake0_Pol_STS", BIT(17)},
+ {"Intel_Se_IO_Wake1_En_STS", BIT(18)},
+ {"Intel_Se_IO_Wake1_Pol_STS", BIT(19)},
+ {"Int_Timer_SS_Wake0_En_STS", BIT(20)},
+ {"Int_Timer_SS_Wake0_Pol_STS", BIT(21)},
+ {"Int_Timer_SS_Wake1_En_STS", BIT(22)},
+ {"Int_Timer_SS_Wake1_Pol_STS", BIT(23)},
+ {"Int_Timer_SS_Wake2_En_STS", BIT(24)},
+ {"Int_Timer_SS_Wake2_Pol_STS", BIT(25)},
+ {"Int_Timer_SS_Wake3_En_STS", BIT(26)},
+ {"Int_Timer_SS_Wake3_Pol_STS", BIT(27)},
+ {"Int_Timer_SS_Wake4_En_STS", BIT(28)},
+ {"Int_Timer_SS_Wake4_Pol_STS", BIT(29)},
+ {"Int_Timer_SS_Wake5_En_STS", BIT(30)},
+ {"Int_Timer_SS_Wake5_Pol_STS", BIT(31)},
+ {}
+};
+
+const struct pmc_bit_map *tgl_lpm_maps[] = {
+ tgl_clocksource_status_map,
+ tgl_power_gating_status_map,
+ tgl_d3_status_map,
+ tgl_vnn_req_status_map,
+ tgl_vnn_misc_status_map,
+ tgl_signal_status_map,
+ NULL
+};
+
+const struct pmc_reg_map tgl_reg_map = {
+ .pfear_sts = ext_tgl_pfear_map,
+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
+ .ltr_show_sts = cnp_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
+ .lpm_num_maps = TGL_LPM_NUM_MAPS,
+ .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
+ .lpm_sts_latch_en_offset = TGL_LPM_STS_LATCH_EN_OFFSET,
+ .lpm_en_offset = TGL_LPM_EN_OFFSET,
+ .lpm_priority_offset = TGL_LPM_PRI_OFFSET,
+ .lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
+ .lpm_sts = tgl_lpm_maps,
+ .lpm_status_offset = TGL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET,
+ .etr3_offset = ETR3_OFFSET,
+};
+
+void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
+{
+ struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
+ const int num_maps = pmcdev->map->lpm_num_maps;
+ u32 lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
+ union acpi_object *out_obj;
+ struct acpi_device *adev;
+ guid_t s0ix_dsm_guid;
+ u32 *lpm_req_regs, *addr;
+
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return;
+
+ guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
+
+ out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
+ ACPI_GET_LOW_MODE_REGISTERS, NULL);
+ if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
+ u32 size = out_obj->buffer.length;
+
+ if (size != lpm_size) {
+ acpi_handle_debug(adev->handle,
+ "_DSM returned unexpected buffer size, have %u, expect %u\n",
+ size, lpm_size);
+ goto free_acpi_obj;
+ }
+ } else {
+ acpi_handle_debug(adev->handle,
+ "_DSM function 0 evaluation failed\n");
+ goto free_acpi_obj;
+ }
+
+ addr = (u32 *)out_obj->buffer.pointer;
+
+ lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
+ GFP_KERNEL);
+ if (!lpm_req_regs)
+ goto free_acpi_obj;
+
+ memcpy(lpm_req_regs, addr, lpm_size);
+ pmcdev->lpm_req_regs = lpm_req_regs;
+
+free_acpi_obj:
+ ACPI_FREE(out_obj);
+}
+
+void tgl_core_configure(struct pmc_dev *pmcdev)
+{
+ pmc_core_get_tgl_lpm_reqs(pmcdev->pdev);
+ /* Due to a hardware limitation, the GBE LTR blocks PC10
+ * when a cable is attached. Tell the PMC to ignore it.
+ */
+ dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+ pmc_core_send_ltr_ignore(pmcdev, 3);
+}
+
+void tgl_core_init(struct pmc_dev *pmcdev)
+{
+ pmcdev->map = &tgl_reg_map;
+ pmcdev->core_configure = tgl_core_configure;
+}
diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c
index 53d7fd2943b4..46598dcb634a 100644
--- a/drivers/platform/x86/intel/pmt/class.c
+++ b/drivers/platform/x86/intel/pmt/class.c
@@ -9,6 +9,7 @@
*/
#include <linux/kernel.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
@@ -19,6 +20,7 @@
#define PMT_XA_START 0
#define PMT_XA_MAX INT_MAX
#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
+#define GUID_SPR_PUNIT 0x9956f43f
bool intel_pmt_is_early_client_hw(struct device *dev)
{
@@ -33,6 +35,29 @@ bool intel_pmt_is_early_client_hw(struct device *dev)
}
EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw);
+static inline int
+pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count)
+{
+ int i, remain;
+ u64 *buf = to;
+
+ if (!IS_ALIGNED((unsigned long)from, 8))
+ return -EFAULT;
+
+ for (i = 0; i < count/8; i++)
+ buf[i] = readq(&from[i]);
+
+ /* Copy any remaining bytes */
+ remain = count % 8;
+ if (remain) {
+ u64 tmp = readq(&from[i]);
+
+ memcpy(&buf[i], &tmp, remain);
+ }
+
+ return count;
+}
+
/*
* sysfs
*/
@@ -54,7 +79,11 @@ intel_pmt_read(struct file *filp, struct kobject *kobj,
if (count > entry->size - off)
count = entry->size - off;
- memcpy_fromio(buf, entry->base + off, count);
+ if (entry->guid == GUID_SPR_PUNIT)
+ /* PUNIT on SPR only supports aligned 64-bit read */
+ count = pmt_memcpy64_fromio(buf, entry->base + off, count);
+ else
+ memcpy_fromio(buf, entry->base + off, count);
return count;
}
diff --git a/drivers/platform/x86/intel/rst.c b/drivers/platform/x86/intel/rst.c
index 3b81cb896fed..35814a7707af 100644
--- a/drivers/platform/x86/intel/rst.c
+++ b/drivers/platform/x86/intel/rst.c
@@ -113,12 +113,10 @@ static int irst_add(struct acpi_device *acpi)
return error;
}
-static int irst_remove(struct acpi_device *acpi)
+static void irst_remove(struct acpi_device *acpi)
{
device_remove_file(&acpi->dev, &irst_wakeup_attr);
device_remove_file(&acpi->dev, &irst_timeout_attr);
-
- return 0;
}
static const struct acpi_device_id irst_ids[] = {
diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c
index c830e98dfa38..9e0ea2cdd704 100644
--- a/drivers/platform/x86/intel/sdsi.c
+++ b/drivers/platform/x86/intel/sdsi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Intel Software Defined Silicon driver
+ * Intel On Demand (Software Defined Silicon) driver
*
* Copyright (c) 2022, Intel Corporation.
* All Rights Reserved.
@@ -27,9 +27,8 @@
#define ACCESS_TYPE_LOCAL 3
#define SDSI_MIN_SIZE_DWORDS 276
-#define SDSI_SIZE_CONTROL 8
#define SDSI_SIZE_MAILBOX 1024
-#define SDSI_SIZE_REGS 72
+#define SDSI_SIZE_REGS 80
#define SDSI_SIZE_CMD sizeof(u64)
/*
@@ -41,7 +40,9 @@
#define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)
#define SDSI_ENABLED_FEATURES_OFFSET 16
-#define SDSI_ENABLED BIT(3)
+#define SDSI_FEATURE_SDSI BIT(3)
+#define SDSI_FEATURE_METERING BIT(26)
+
#define SDSI_SOCKET_ID_OFFSET 64
#define SDSI_SOCKET_ID GENMASK(3, 0)
@@ -75,10 +76,18 @@
#define DT_TBIR GENMASK(2, 0)
#define DT_OFFSET(v) ((v) & GENMASK(31, 3))
+#define SDSI_GUID_V1 0x006DD191
+#define GUID_V1_CNTRL_SIZE 8
+#define GUID_V1_REGS_SIZE 72
+#define SDSI_GUID_V2 0xF210D9EF
+#define GUID_V2_CNTRL_SIZE 16
+#define GUID_V2_REGS_SIZE 80
+
enum sdsi_command {
- SDSI_CMD_PROVISION_AKC = 0x04,
- SDSI_CMD_PROVISION_CAP = 0x08,
- SDSI_CMD_READ_STATE = 0x10,
+ SDSI_CMD_PROVISION_AKC = 0x0004,
+ SDSI_CMD_PROVISION_CAP = 0x0008,
+ SDSI_CMD_READ_STATE = 0x0010,
+ SDSI_CMD_READ_METER = 0x0014,
};
struct sdsi_mbox_info {
@@ -99,8 +108,11 @@ struct sdsi_priv {
void __iomem *control_addr;
void __iomem *mbox_addr;
void __iomem *regs_addr;
+ int control_size;
+ int maibox_size;
+ int registers_size;
u32 guid;
- bool sdsi_enabled;
+ u32 features;
};
/* SDSi mailbox operations must be performed using 64bit mov instructions */
@@ -332,9 +344,6 @@ static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
struct sdsi_mbox_info info;
int ret;
- if (!priv->sdsi_enabled)
- return -EPERM;
-
if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
return -EOVERFLOW;
@@ -394,20 +403,14 @@ static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
}
static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
-static long state_certificate_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t off,
- size_t count)
+static ssize_t
+certificate_read(u64 command, struct sdsi_priv *priv, char *buf, loff_t off,
+ size_t count)
{
- struct device *dev = kobj_to_dev(kobj);
- struct sdsi_priv *priv = dev_get_drvdata(dev);
- u64 command = SDSI_CMD_READ_STATE;
struct sdsi_mbox_info info;
size_t size;
int ret;
- if (!priv->sdsi_enabled)
- return -EPERM;
-
if (off)
return 0;
@@ -440,7 +443,30 @@ free_buffer:
return size;
}
-static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG);
+
+static ssize_t
+state_certificate_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t off,
+ size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+ return certificate_read(SDSI_CMD_READ_STATE, priv, buf, off, count);
+}
+static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG);
+
+static ssize_t
+meter_certificate_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t off,
+ size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+ return certificate_read(SDSI_CMD_READ_METER, priv, buf, off, count);
+}
+static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG);
static ssize_t registers_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off,
@@ -449,21 +475,55 @@ static ssize_t registers_read(struct file *filp, struct kobject *kobj,
struct device *dev = kobj_to_dev(kobj);
struct sdsi_priv *priv = dev_get_drvdata(dev);
void __iomem *addr = priv->regs_addr;
+ int size = priv->registers_size;
+
+ /*
+ * The check below is performed by the sysfs caller based on the static
+ * file size. But this may be greater than the actual size which is based
+ * on the GUID. So check here again based on actual size before reading.
+ */
+ if (off >= size)
+ return 0;
+
+ if (off + count > size)
+ count = size - off;
memcpy_fromio(buf, addr + off, count);
return count;
}
-static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS);
+static BIN_ATTR_ADMIN_RO(registers, SDSI_SIZE_REGS);
static struct bin_attribute *sdsi_bin_attrs[] = {
&bin_attr_registers,
&bin_attr_state_certificate,
+ &bin_attr_meter_certificate,
&bin_attr_provision_akc,
&bin_attr_provision_cap,
NULL
};
+static umode_t
+sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+ /* Registers file is always readable if the device is present */
+ if (attr == &bin_attr_registers)
+ return attr->attr.mode;
+
+ /* All other attributes not visible if BIOS has not enabled On Demand */
+ if (!(priv->features & SDSI_FEATURE_SDSI))
+ return 0;
+
+ if (attr == &bin_attr_meter_certificate)
+ return (priv->features & SDSI_FEATURE_METERING) ?
+ attr->attr.mode : 0;
+
+ return attr->attr.mode;
+}
+
static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sdsi_priv *priv = dev_get_drvdata(dev);
@@ -480,9 +540,28 @@ static struct attribute *sdsi_attrs[] = {
static const struct attribute_group sdsi_group = {
.attrs = sdsi_attrs,
.bin_attrs = sdsi_bin_attrs,
+ .is_bin_visible = sdsi_battr_is_visible,
};
__ATTRIBUTE_GROUPS(sdsi);
+static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table)
+{
+ switch (table->guid) {
+ case SDSI_GUID_V1:
+ priv->control_size = GUID_V1_CNTRL_SIZE;
+ priv->registers_size = GUID_V1_REGS_SIZE;
+ break;
+ case SDSI_GUID_V2:
+ priv->control_size = GUID_V2_CNTRL_SIZE;
+ priv->registers_size = GUID_V2_REGS_SIZE;
+ break;
+ default:
+ dev_err(priv->dev, "Unrecognized GUID 0x%x\n", table->guid);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
struct disc_table *disc_table, struct resource *disc_res)
{
@@ -490,7 +569,6 @@ static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *paren
u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
u32 offset = DT_OFFSET(disc_table->offset);
- u32 features_offset;
struct resource res = {};
/* Starting location of SDSi MMIO region based on access type */
@@ -525,11 +603,10 @@ static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *paren
if (IS_ERR(priv->control_addr))
return PTR_ERR(priv->control_addr);
- priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL;
+ priv->mbox_addr = priv->control_addr + priv->control_size;
priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
- features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
- priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED);
+ priv->features = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
return 0;
}
@@ -561,6 +638,11 @@ static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_de
priv->guid = disc_table.guid;
+ /* Get guid based layout info */
+ ret = sdsi_get_layout(priv, &disc_table);
+ if (ret)
+ return ret;
+
/* Map the SDSi mailbox registers */
ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
if (ret)
@@ -586,5 +668,5 @@ static struct auxiliary_driver sdsi_aux_driver = {
module_auxiliary_driver(sdsi_aux_driver);
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
-MODULE_DESCRIPTION("Intel Software Defined Silicon driver");
+MODULE_DESCRIPTION("Intel On Demand (SDSi) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
index fd102678c75f..a7e02b24a87a 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
@@ -623,7 +623,7 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
/* Lock to prevent module registration when already opened by user space */
static DEFINE_MUTEX(punit_misc_dev_open_lock);
-/* Lock to allow one share misc device for all ISST interace */
+/* Lock to allow one shared misc device for all ISST interfaces */
static DEFINE_MUTEX(punit_misc_dev_reg_lock);
static int misc_usage_count;
static int misc_device_ret;
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
index 8f9c571d7257..00ac7e381441 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
@@ -203,6 +203,7 @@ static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL),
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids);
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 7cc9089d1e14..e7a3e3402817 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -583,7 +583,6 @@ __intel_scu_ipc_register(struct device *parent,
scu->dev.parent = parent;
scu->dev.class = &intel_scu_ipc_class;
scu->dev.release = intel_scu_ipc_release;
- dev_set_name(&scu->dev, "intel_scu_ipc");
if (!request_mem_region(scu_data->mem.start, resource_size(&scu_data->mem),
"intel_scu_ipc")) {
@@ -612,6 +611,7 @@ __intel_scu_ipc_register(struct device *parent,
* After this point intel_scu_ipc_release() takes care of
* releasing the SCU IPC resources once refcount drops to zero.
*/
+ dev_set_name(&scu->dev, "intel_scu_ipc");
err = device_register(&scu->dev);
if (err) {
put_device(&scu->dev);
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
index 332868b140ed..ad3c39e9e9f5 100644
--- a/drivers/platform/x86/lg-laptop.c
+++ b/drivers/platform/x86/lg-laptop.c
@@ -546,7 +546,7 @@ static DEVICE_ATTR_RW(fn_lock);
static DEVICE_ATTR_RW(charge_control_end_threshold);
static DEVICE_ATTR_RW(battery_care_limit);
-static int lg_battery_add(struct power_supply *battery)
+static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
if (device_create_file(&battery->dev,
&dev_attr_charge_control_end_threshold))
@@ -555,7 +555,7 @@ static int lg_battery_add(struct power_supply *battery)
return 0;
}
-static int lg_battery_remove(struct power_supply *battery)
+static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_file(&battery->dev,
&dev_attr_charge_control_end_threshold);
@@ -761,7 +761,7 @@ out_platform_registered:
return ret;
}
-static int acpi_remove(struct acpi_device *device)
+static void acpi_remove(struct acpi_device *device)
{
sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
@@ -773,8 +773,6 @@ static int acpi_remove(struct acpi_device *device)
platform_device_unregister(pf_device);
pf_device = NULL;
platform_driver_unregister(&pf_driver);
-
- return 0;
}
static const struct acpi_device_id device_ids[] = {
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
index 9a19fbd2f734..9a457956025a 100644
--- a/drivers/platform/x86/mxm-wmi.c
+++ b/drivers/platform/x86/mxm-wmi.c
@@ -35,13 +35,11 @@ int mxm_wmi_call_mxds(int adapter)
.xarg = 1,
};
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
printk("calling mux switch %d\n", adapter);
- status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input,
- &output);
+ status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, NULL);
if (ACPI_FAILURE(status))
return status;
@@ -60,13 +58,11 @@ int mxm_wmi_call_mxmx(int adapter)
.xarg = 1,
};
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
printk("calling mux switch %d\n", adapter);
- status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input,
- &output);
+ status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, NULL);
if (ACPI_FAILURE(status))
return status;
diff --git a/drivers/platform/x86/p2sb.c b/drivers/platform/x86/p2sb.c
index 384d0962ae93..1cf2471d54dd 100644
--- a/drivers/platform/x86/p2sb.c
+++ b/drivers/platform/x86/p2sb.c
@@ -19,26 +19,23 @@
#define P2SBC 0xe0
#define P2SBC_HIDE BIT(8)
+#define P2SB_DEVFN_DEFAULT PCI_DEVFN(31, 1)
+
static const struct x86_cpu_id p2sb_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)),
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, PCI_DEVFN(31, 1)),
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D, PCI_DEVFN(31, 1)),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, PCI_DEVFN(31, 1)),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, PCI_DEVFN(31, 1)),
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, PCI_DEVFN(31, 1)),
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, PCI_DEVFN(31, 1)),
{}
};
static int p2sb_get_devfn(unsigned int *devfn)
{
+ unsigned int fn = P2SB_DEVFN_DEFAULT;
const struct x86_cpu_id *id;
id = x86_match_cpu(p2sb_cpu_ids);
- if (!id)
- return -ENODEV;
+ if (id)
+ fn = (unsigned int)id->driver_data;
- *devfn = (unsigned int)id->driver_data;
+ *devfn = fn;
return 0;
}
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ad3083f9946d..cf845ee1c7b1 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -183,7 +183,7 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
static int acpi_pcc_hotkey_add(struct acpi_device *device);
-static int acpi_pcc_hotkey_remove(struct acpi_device *device);
+static void acpi_pcc_hotkey_remove(struct acpi_device *device);
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id pcc_device_ids[] = {
@@ -1065,12 +1065,12 @@ out_hotkey:
return result;
}
-static int acpi_pcc_hotkey_remove(struct acpi_device *device)
+static void acpi_pcc_hotkey_remove(struct acpi_device *device)
{
struct pcc_acpi *pcc = acpi_driver_data(device);
if (!device || !pcc)
- return -EINVAL;
+ return;
i8042_remove_filter(panasonic_i8042_filter);
@@ -1088,8 +1088,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device)
kfree(pcc->sinf);
kfree(pcc);
-
- return 0;
}
module_acpi_driver(acpi_pcc_driver);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 765fcaba4d12..7156ae2ad196 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -820,10 +820,9 @@ static ssize_t sony_nc_handles_show(struct device *dev,
int i;
for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
- len += scnprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
- handles->cap[i]);
+ len += sysfs_emit_at(buffer, len, "0x%.4x ", handles->cap[i]);
}
- len += scnprintf(buffer + len, PAGE_SIZE - len, "\n");
+ len += sysfs_emit_at(buffer, len, "\n");
return len;
}
@@ -2173,10 +2172,9 @@ static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
if (!cnt || (th_handle->profiles & cnt))
- idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
- snc_thermal_profiles[cnt]);
+ idx += sysfs_emit_at(buffer, idx, "%s ", snc_thermal_profiles[cnt]);
}
- idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "\n");
+ idx += sysfs_emit_at(buffer, idx, "\n");
return idx;
}
@@ -3263,7 +3261,7 @@ outwalk:
return result;
}
-static int sony_nc_remove(struct acpi_device *device)
+static void sony_nc_remove(struct acpi_device *device)
{
struct sony_nc_value *item;
@@ -3280,8 +3278,6 @@ static int sony_nc_remove(struct acpi_device *device)
sony_pf_remove();
sony_laptop_remove_input();
dprintk(SONY_NC_DRIVER_NAME " removed.\n");
-
- return 0;
}
static const struct acpi_device_id sony_device_ids[] = {
@@ -4630,14 +4626,14 @@ found:
* ACPI driver
*
*****************/
-static int sony_pic_remove(struct acpi_device *device)
+static void sony_pic_remove(struct acpi_device *device)
{
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
if (sony_pic_disable(device)) {
pr_err("Couldn't disable device\n");
- return -ENXIO;
+ return;
}
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
@@ -4667,7 +4663,6 @@ static int sony_pic_remove(struct acpi_device *device)
spic_dev.cur_irq = NULL;
dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
- return 0;
}
static int sony_pic_add(struct acpi_device *device)
diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c
index 958df41ad509..97f5a8255b91 100644
--- a/drivers/platform/x86/system76_acpi.c
+++ b/drivers/platform/x86/system76_acpi.c
@@ -254,7 +254,7 @@ static struct attribute *system76_battery_attrs[] = {
ATTRIBUTE_GROUPS(system76_battery);
-static int system76_battery_add(struct power_supply *battery)
+static int system76_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
// System76 EC only supports 1 battery
if (strcmp(battery->desc->name, "BAT0") != 0)
@@ -266,7 +266,7 @@ static int system76_battery_add(struct power_supply *battery)
return 0;
}
-static int system76_battery_remove(struct power_supply *battery)
+static int system76_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_groups(&battery->dev, system76_battery_groups);
return 0;
@@ -744,7 +744,7 @@ error:
}
// Remove a System76 ACPI device
-static int system76_remove(struct acpi_device *acpi_dev)
+static void system76_remove(struct acpi_device *acpi_dev)
{
struct system76_data *data;
@@ -760,8 +760,6 @@ static int system76_remove(struct acpi_device *acpi_dev)
devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led);
system76_get(data, "FINI");
-
- return 0;
}
static struct acpi_driver system76_driver = {
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 20e5c043a8e8..1195293b22fd 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -265,9 +265,6 @@ enum tpacpi_hkey_event_t {
#define FAN_NOT_PRESENT 65535
-#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
-
-
/****************************************************************************
* Driver-wide structs and misc. variables
*/
@@ -1335,9 +1332,9 @@ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
return -ENODEV;
while ((cmd = strsep(&buf, ","))) {
- if (strlencmp(cmd, "enable") == 0)
+ if (strstarts(cmd, "enable"))
status = TPACPI_RFK_RADIO_ON;
- else if (strlencmp(cmd, "disable") == 0)
+ else if (strstarts(cmd, "disable"))
status = TPACPI_RFK_RADIO_OFF;
else
return -EINVAL;
@@ -4198,12 +4195,12 @@ static int hotkey_write(char *buf)
res = 0;
while ((cmd = strsep(&buf, ","))) {
- if (strlencmp(cmd, "enable") == 0) {
+ if (strstarts(cmd, "enable")) {
hotkey_enabledisable_warn(1);
- } else if (strlencmp(cmd, "disable") == 0) {
+ } else if (strstarts(cmd, "disable")) {
hotkey_enabledisable_warn(0);
res = -EPERM;
- } else if (strlencmp(cmd, "reset") == 0) {
+ } else if (strstarts(cmd, "reset")) {
mask = (hotkey_all_mask | hotkey_source_mask)
& ~hotkey_reserved_mask;
} else if (sscanf(cmd, "0x%x", &mask) == 1) {
@@ -4497,6 +4494,14 @@ static const struct dmi_system_id fwbug_list[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
}
},
+ {
+ .ident = "P14s Gen2 AMD",
+ .driver_data = &quirk_s2idle_bug,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
+ }
+ },
{}
};
@@ -5225,33 +5230,33 @@ static int video_write(char *buf)
disable = 0;
while ((cmd = strsep(&buf, ","))) {
- if (strlencmp(cmd, "lcd_enable") == 0) {
+ if (strstarts(cmd, "lcd_enable")) {
enable |= TP_ACPI_VIDEO_S_LCD;
- } else if (strlencmp(cmd, "lcd_disable") == 0) {
+ } else if (strstarts(cmd, "lcd_disable")) {
disable |= TP_ACPI_VIDEO_S_LCD;
- } else if (strlencmp(cmd, "crt_enable") == 0) {
+ } else if (strstarts(cmd, "crt_enable")) {
enable |= TP_ACPI_VIDEO_S_CRT;
- } else if (strlencmp(cmd, "crt_disable") == 0) {
+ } else if (strstarts(cmd, "crt_disable")) {
disable |= TP_ACPI_VIDEO_S_CRT;
} else if (video_supported == TPACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_enable") == 0) {
+ strstarts(cmd, "dvi_enable")) {
enable |= TP_ACPI_VIDEO_S_DVI;
} else if (video_supported == TPACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_disable") == 0) {
+ strstarts(cmd, "dvi_disable")) {
disable |= TP_ACPI_VIDEO_S_DVI;
- } else if (strlencmp(cmd, "auto_enable") == 0) {
+ } else if (strstarts(cmd, "auto_enable")) {
res = video_autosw_set(1);
if (res)
return res;
- } else if (strlencmp(cmd, "auto_disable") == 0) {
+ } else if (strstarts(cmd, "auto_disable")) {
res = video_autosw_set(0);
if (res)
return res;
- } else if (strlencmp(cmd, "video_switch") == 0) {
+ } else if (strstarts(cmd, "video_switch")) {
res = video_outputsw_cycle();
if (res)
return res;
- } else if (strlencmp(cmd, "expand_toggle") == 0) {
+ } else if (strstarts(cmd, "expand_toggle")) {
res = video_expand_toggle();
if (res)
return res;
@@ -5564,6 +5569,7 @@ static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
static struct tpacpi_led_classdev tpacpi_led_thinklight = {
.led_classdev = {
.name = "tpacpi::thinklight",
+ .max_brightness = 1,
.brightness_set_blocking = &light_sysfs_set,
.brightness_get = &light_sysfs_get,
}
@@ -5644,9 +5650,9 @@ static int light_write(char *buf)
return -ENODEV;
while ((cmd = strsep(&buf, ","))) {
- if (strlencmp(cmd, "on") == 0) {
+ if (strstarts(cmd, "on")) {
newstatus = 1;
- } else if (strlencmp(cmd, "off") == 0) {
+ } else if (strstarts(cmd, "off")) {
newstatus = 0;
} else
return -EINVAL;
@@ -7117,10 +7123,10 @@ static int brightness_write(char *buf)
return level;
while ((cmd = strsep(&buf, ","))) {
- if (strlencmp(cmd, "up") == 0) {
+ if (strstarts(cmd, "up")) {
if (level < bright_maxlvl)
level++;
- } else if (strlencmp(cmd, "down") == 0) {
+ } else if (strstarts(cmd, "down")) {
if (level > 0)
level--;
} else if (sscanf(cmd, "level %d", &level) == 1 &&
@@ -7869,13 +7875,13 @@ static int volume_write(char *buf)
while ((cmd = strsep(&buf, ","))) {
if (!tp_features.mixer_no_level_control) {
- if (strlencmp(cmd, "up") == 0) {
+ if (strstarts(cmd, "up")) {
if (new_mute)
new_mute = 0;
else if (new_level < TP_EC_VOLUME_MAX)
new_level++;
continue;
- } else if (strlencmp(cmd, "down") == 0) {
+ } else if (strstarts(cmd, "down")) {
if (new_mute)
new_mute = 0;
else if (new_level > 0)
@@ -7887,9 +7893,9 @@ static int volume_write(char *buf)
continue;
}
}
- if (strlencmp(cmd, "mute") == 0)
+ if (strstarts(cmd, "mute"))
new_mute = TP_EC_AUDIO_MUTESW_MSK;
- else if (strlencmp(cmd, "unmute") == 0)
+ else if (strstarts(cmd, "unmute"))
new_mute = 0;
else
return -EINVAL;
@@ -9112,10 +9118,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
{
int level;
- if (strlencmp(cmd, "level auto") == 0)
+ if (strstarts(cmd, "level auto"))
level = TP_EC_FAN_AUTO;
- else if ((strlencmp(cmd, "level disengaged") == 0) ||
- (strlencmp(cmd, "level full-speed") == 0))
+ else if (strstarts(cmd, "level disengaged") || strstarts(cmd, "level full-speed"))
level = TP_EC_FAN_FULLSPEED;
else if (sscanf(cmd, "level %d", &level) != 1)
return 0;
@@ -9133,7 +9138,7 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
static int fan_write_cmd_enable(const char *cmd, int *rc)
{
- if (strlencmp(cmd, "enable") != 0)
+ if (!strstarts(cmd, "enable"))
return 0;
*rc = fan_set_enable();
@@ -9148,7 +9153,7 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
static int fan_write_cmd_disable(const char *cmd, int *rc)
{
- if (strlencmp(cmd, "disable") != 0)
+ if (!strstarts(cmd, "disable"))
return 0;
*rc = fan_set_disable();
@@ -9899,7 +9904,7 @@ ATTRIBUTE_GROUPS(tpacpi_battery);
/* ACPI battery hooking */
-static int tpacpi_battery_add(struct power_supply *battery)
+static int tpacpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
int batteryid = tpacpi_battery_get_id(battery->desc->name);
@@ -9910,7 +9915,7 @@ static int tpacpi_battery_add(struct power_supply *battery)
return 0;
}
-static int tpacpi_battery_remove(struct power_supply *battery)
+static int tpacpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_groups(&battery->dev, tpacpi_battery_groups);
return 0;
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index 6d18fbf8762b..20df1ebefc30 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -332,7 +332,7 @@ err_free:
return err;
}
-static int topstar_acpi_remove(struct acpi_device *device)
+static void topstar_acpi_remove(struct acpi_device *device)
{
struct topstar_laptop *topstar = acpi_driver_data(device);
@@ -344,7 +344,6 @@ static int topstar_acpi_remove(struct acpi_device *device)
topstar_acpi_exit(topstar);
kfree(topstar);
- return 0;
}
static const struct acpi_device_id topstar_device_ids[] = {
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 160abd3b3af8..b34984bbee33 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -3113,7 +3113,7 @@ static struct attribute *toshiba_acpi_battery_attrs[] = {
ATTRIBUTE_GROUPS(toshiba_acpi_battery);
-static int toshiba_acpi_battery_add(struct power_supply *battery)
+static int toshiba_acpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
if (toshiba_acpi == NULL) {
pr_err("Init order issue\n");
@@ -3126,7 +3126,7 @@ static int toshiba_acpi_battery_add(struct power_supply *battery)
return 0;
}
-static int toshiba_acpi_battery_remove(struct power_supply *battery)
+static int toshiba_acpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
{
device_remove_groups(&battery->dev, toshiba_acpi_battery_groups);
return 0;
@@ -3186,7 +3186,7 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
pr_cont("\n");
}
-static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
+static void toshiba_acpi_remove(struct acpi_device *acpi_dev)
{
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
@@ -3234,8 +3234,6 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
toshiba_acpi = NULL;
kfree(dev);
-
- return 0;
}
static const char *find_hci_method(acpi_handle handle)
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index 57a5dc60c58a..d8f81962a240 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -36,7 +36,7 @@ struct toshiba_bluetooth_dev {
};
static int toshiba_bt_rfkill_add(struct acpi_device *device);
-static int toshiba_bt_rfkill_remove(struct acpi_device *device);
+static void toshiba_bt_rfkill_remove(struct acpi_device *device);
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id bt_device_ids[] = {
@@ -279,7 +279,7 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
return result;
}
-static int toshiba_bt_rfkill_remove(struct acpi_device *device)
+static void toshiba_bt_rfkill_remove(struct acpi_device *device)
{
struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
@@ -291,7 +291,7 @@ static int toshiba_bt_rfkill_remove(struct acpi_device *device)
kfree(bt_dev);
- return toshiba_bluetooth_disable(device->handle);
+ toshiba_bluetooth_disable(device->handle);
}
module_acpi_driver(toshiba_bt_rfkill_driver);
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
index 49e84095bb01..8c9f76286b08 100644
--- a/drivers/platform/x86/toshiba_haps.c
+++ b/drivers/platform/x86/toshiba_haps.c
@@ -138,14 +138,12 @@ static void toshiba_haps_notify(struct acpi_device *device, u32 event)
event, 0);
}
-static int toshiba_haps_remove(struct acpi_device *device)
+static void toshiba_haps_remove(struct acpi_device *device)
{
sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
if (toshiba_haps)
toshiba_haps = NULL;
-
- return 0;
}
/* Helper function */
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index bc97bfa8e8a6..baae3120efd0 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -770,6 +770,22 @@ static const struct ts_dmi_data predia_basic_data = {
.properties = predia_basic_props,
};
+static const struct property_entry rca_cambio_w101_v2_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 4),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 20),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1644),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 874),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rca-cambio-w101-v2.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct ts_dmi_data rca_cambio_w101_v2_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = rca_cambio_w101_v2_props,
+};
+
static const struct property_entry rwc_nanote_p8_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-y", 46),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
@@ -1410,6 +1426,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* RCA Cambio W101 v2 */
+ /* https://github.com/onitake/gsl-firmware/discussions/193 */
+ .driver_data = (void *)&rca_cambio_w101_v2_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "RCA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "W101SA23T1"),
+ },
+ },
+ {
/* RWC NANOTE P8 */
.driver_data = (void *)&rwc_nanote_p8_data,
.matches = {
diff --git a/drivers/platform/x86/uv_sysfs.c b/drivers/platform/x86/uv_sysfs.c
index 625b0b79d185..73fc38ee7430 100644
--- a/drivers/platform/x86/uv_sysfs.c
+++ b/drivers/platform/x86/uv_sysfs.c
@@ -119,12 +119,12 @@ struct uv_hub {
static ssize_t hub_name_show(struct uv_bios_hub_info *hub_info, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->name);
+ return sysfs_emit(buf, "%s\n", hub_info->name);
}
static ssize_t hub_location_show(struct uv_bios_hub_info *hub_info, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->location);
+ return sysfs_emit(buf, "%s\n", hub_info->location);
}
static ssize_t hub_partition_show(struct uv_bios_hub_info *hub_info, char *buf)
@@ -460,12 +460,12 @@ struct uv_pci_top_obj {
static ssize_t uv_pci_type_show(struct uv_pci_top_obj *top_obj, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->type);
+ return sysfs_emit(buf, "%s\n", top_obj->type);
}
static ssize_t uv_pci_location_show(struct uv_pci_top_obj *top_obj, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->location);
+ return sysfs_emit(buf, "%s\n", top_obj->location);
}
static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf)
@@ -475,7 +475,7 @@ static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf)
static ssize_t uv_pci_ppb_addr_show(struct uv_pci_top_obj *top_obj, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->ppb_addr);
+ return sysfs_emit(buf, "%s\n", top_obj->ppb_addr);
}
static ssize_t uv_pci_slot_show(struct uv_pci_top_obj *top_obj, char *buf)
@@ -737,7 +737,7 @@ static ssize_t coherence_id_show(struct kobject *kobj,
static ssize_t uv_type_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", uv_type_string());
+ return sysfs_emit(buf, "%s\n", uv_type_string());
}
static ssize_t uv_archtype_show(struct kobject *kobj,
@@ -749,13 +749,13 @@ static ssize_t uv_archtype_show(struct kobject *kobj,
static ssize_t uv_hub_type_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_hub_type());
+ return sysfs_emit(buf, "0x%x\n", uv_hub_type());
}
static ssize_t uv_hubless_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_get_hubless_system());
+ return sysfs_emit(buf, "0x%x\n", uv_get_hubless_system());
}
static struct kobj_attribute partition_id_attr =
diff --git a/drivers/platform/x86/wireless-hotkey.c b/drivers/platform/x86/wireless-hotkey.c
index 11c60a273446..4422863f47bb 100644
--- a/drivers/platform/x86/wireless-hotkey.c
+++ b/drivers/platform/x86/wireless-hotkey.c
@@ -20,7 +20,10 @@ MODULE_ALIAS("acpi*:HPQ6001:*");
MODULE_ALIAS("acpi*:WSTADEF:*");
MODULE_ALIAS("acpi*:AMDI0051:*");
-static struct input_dev *wl_input_dev;
+struct wl_button {
+ struct input_dev *input_dev;
+ char phys[32];
+};
static const struct acpi_device_id wl_ids[] = {
{"HPQ6001", 0},
@@ -29,64 +32,80 @@ static const struct acpi_device_id wl_ids[] = {
{"", 0},
};
-static int wireless_input_setup(void)
+static int wireless_input_setup(struct acpi_device *device)
{
+ struct wl_button *button = acpi_driver_data(device);
int err;
- wl_input_dev = input_allocate_device();
- if (!wl_input_dev)
+ button->input_dev = input_allocate_device();
+ if (!button->input_dev)
return -ENOMEM;
- wl_input_dev->name = "Wireless hotkeys";
- wl_input_dev->phys = "hpq6001/input0";
- wl_input_dev->id.bustype = BUS_HOST;
- wl_input_dev->evbit[0] = BIT(EV_KEY);
- set_bit(KEY_RFKILL, wl_input_dev->keybit);
+ snprintf(button->phys, sizeof(button->phys), "%s/input0", acpi_device_hid(device));
+
+ button->input_dev->name = "Wireless hotkeys";
+ button->input_dev->phys = button->phys;
+ button->input_dev->id.bustype = BUS_HOST;
+ button->input_dev->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_RFKILL, button->input_dev->keybit);
- err = input_register_device(wl_input_dev);
+ err = input_register_device(button->input_dev);
if (err)
goto err_free_dev;
return 0;
err_free_dev:
- input_free_device(wl_input_dev);
+ input_free_device(button->input_dev);
return err;
}
-static void wireless_input_destroy(void)
+static void wireless_input_destroy(struct acpi_device *device)
{
- input_unregister_device(wl_input_dev);
+ struct wl_button *button = acpi_driver_data(device);
+
+ input_unregister_device(button->input_dev);
+ kfree(button);
}
static void wl_notify(struct acpi_device *acpi_dev, u32 event)
{
+ struct wl_button *button = acpi_driver_data(acpi_dev);
+
if (event != 0x80) {
pr_info("Received unknown event (0x%x)\n", event);
return;
}
- input_report_key(wl_input_dev, KEY_RFKILL, 1);
- input_sync(wl_input_dev);
- input_report_key(wl_input_dev, KEY_RFKILL, 0);
- input_sync(wl_input_dev);
+ input_report_key(button->input_dev, KEY_RFKILL, 1);
+ input_sync(button->input_dev);
+ input_report_key(button->input_dev, KEY_RFKILL, 0);
+ input_sync(button->input_dev);
}
static int wl_add(struct acpi_device *device)
{
+ struct wl_button *button;
int err;
- err = wireless_input_setup();
- if (err)
+ button = kzalloc(sizeof(struct wl_button), GFP_KERNEL);
+ if (!button)
+ return -ENOMEM;
+
+ device->driver_data = button;
+
+ err = wireless_input_setup(device);
+ if (err) {
pr_err("Failed to setup wireless hotkeys\n");
+ kfree(button);
+ }
return err;
}
-static int wl_remove(struct acpi_device *device)
+static void wl_remove(struct acpi_device *device)
{
- wireless_input_destroy();
- return 0;
+ wireless_input_destroy(device);
}
static struct acpi_driver wl_driver = {
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 223550a10d4d..5ffc00480aef 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
/* allow duplicate GUIDs as these device drivers use struct wmi_driver */
static const char * const allow_duplicates[] = {
"05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */
+ "8A42EA14-4F2A-FD45-6422-0087F7A7E608", /* dell-wmi-ddv */
NULL
};
diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c
index 4acd6fa8d43b..123a4618db55 100644
--- a/drivers/platform/x86/x86-android-tablets.c
+++ b/drivers/platform/x86/x86-android-tablets.c
@@ -5,7 +5,7 @@
* devices typically have a bunch of things hardcoded, rather than specified
* in their DSDT.
*
- * Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2021-2022 Hans de Goede <hdegoede@redhat.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -265,6 +265,56 @@ static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = {
},
};
+/*
+ * Advantech MICA-071
+ * This is a standard Windows tablet, but it has an extra "quick launch" button
+ * which is not described in the ACPI tables in anyway.
+ * Use the x86-android-tablets infra to create a gpio-button device for this.
+ */
+static struct gpio_keys_button advantech_mica_071_button = {
+ .code = KEY_PROG1,
+ /* .gpio gets filled in by advantech_mica_071_init() */
+ .active_low = true,
+ .desc = "prog1_key",
+ .type = EV_KEY,
+ .wakeup = false,
+ .debounce_interval = 50,
+};
+
+static const struct gpio_keys_platform_data advantech_mica_071_button_pdata __initconst = {
+ .buttons = &advantech_mica_071_button,
+ .nbuttons = 1,
+ .name = "prog1_key",
+};
+
+static const struct platform_device_info advantech_mica_071_pdevs[] __initconst = {
+ {
+ .name = "gpio-keys",
+ .id = PLATFORM_DEVID_AUTO,
+ .data = &advantech_mica_071_button_pdata,
+ .size_data = sizeof(advantech_mica_071_button_pdata),
+ },
+};
+
+static int __init advantech_mica_071_init(void)
+{
+ struct gpio_desc *gpiod;
+ int ret;
+
+ ret = x86_android_tablet_get_gpiod("INT33FC:00", 2, &gpiod);
+ if (ret < 0)
+ return ret;
+ advantech_mica_071_button.gpio = desc_to_gpio(gpiod);
+
+ return 0;
+}
+
+static const struct x86_dev_info advantech_mica_071_info __initconst = {
+ .pdev_info = advantech_mica_071_pdevs,
+ .pdev_count = ARRAY_SIZE(advantech_mica_071_pdevs),
+ .init = advantech_mica_071_init,
+};
+
/* Asus ME176C and TF103C tablets shared data */
static struct gpio_keys_button asus_me176c_tf103c_lid = {
.code = SW_LID,
@@ -987,6 +1037,212 @@ static void lenovo_yoga_tab2_830_1050_exit(void)
}
}
+/* Lenovo Yoga Tab 3 Pro YT3-X90F */
+
+/*
+ * There are 2 batteries, with 2 bq27500 fuel-gauges and 2 bq25892 chargers,
+ * "bq25890-charger-1" is instantiated from: drivers/i2c/busses/i2c-cht-wc.c.
+ */
+static const char * const lenovo_yt3_bq25892_0_suppliers[] = { "cht_wcove_pwrsrc" };
+static const char * const bq25890_1_psy[] = { "bq25890-charger-1" };
+
+static const struct property_entry fg_bq25890_1_supply_props[] = {
+ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_1_psy),
+ { }
+};
+
+static const struct software_node fg_bq25890_1_supply_node = {
+ .properties = fg_bq25890_1_supply_props,
+};
+
+/* bq25892 charger settings for the flat lipo battery behind the screen */
+static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
+ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
+ PROPERTY_ENTRY_STRING("linux,power-supply-name", "bq25892-second-chrg"),
+ PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
+ PROPERTY_ENTRY_BOOL("linux,skip-reset"),
+ /* Values taken from Android Factory Image */
+ PROPERTY_ENTRY_U32("ti,charge-current", 2048000),
+ PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
+ PROPERTY_ENTRY_U32("ti,termination-current", 128000),
+ PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
+ PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
+ PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
+ PROPERTY_ENTRY_U32("ti,boost-max-current", 500000),
+ PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
+ { }
+};
+
+static const struct software_node lenovo_yt3_bq25892_0_node = {
+ .properties = lenovo_yt3_bq25892_0_props,
+};
+
+static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
+ {
+ /* bq27500 fuel-gauge for the flat lipo battery behind the screen */
+ .board_info = {
+ .type = "bq27500",
+ .addr = 0x55,
+ .dev_name = "bq27500_0",
+ .swnode = &fg_bq25890_supply_node,
+ },
+ .adapter_path = "\\_SB_.PCI0.I2C1",
+ }, {
+ /* bq25892 charger for the flat lipo battery behind the screen */
+ .board_info = {
+ .type = "bq25892",
+ .addr = 0x6b,
+ .dev_name = "bq25892_0",
+ .swnode = &lenovo_yt3_bq25892_0_node,
+ },
+ .adapter_path = "\\_SB_.PCI0.I2C1",
+ .irq_data = {
+ .type = X86_ACPI_IRQ_TYPE_GPIOINT,
+ .chip = "INT33FF:01",
+ .index = 5,
+ .trigger = ACPI_EDGE_SENSITIVE,
+ .polarity = ACPI_ACTIVE_LOW,
+ },
+ }, {
+ /* bq27500 fuel-gauge for the round li-ion cells in the hinge */
+ .board_info = {
+ .type = "bq27500",
+ .addr = 0x55,
+ .dev_name = "bq27500_1",
+ .swnode = &fg_bq25890_1_supply_node,
+ },
+ .adapter_path = "\\_SB_.PCI0.I2C2",
+ }
+};
+
+static int __init lenovo_yt3_init(void)
+{
+ struct gpio_desc *gpiod;
+ int ret;
+
+ /*
+ * The "bq25892_0" charger IC has its /CE (Charge-Enable) and OTG pins
+ * connected to GPIOs, rather then having them hardwired to the correct
+ * values as is normally done.
+ *
+ * The bq25890_charger driver controls these through I2C, but this only
+ * works if not overridden by the pins. Set these pins here:
+ * 1. Set /CE to 0 to allow charging.
+ * 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
+ * the main "bq25892_1" charger is used when necessary.
+ */
+
+ /* /CE pin */
+ ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, &gpiod);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The gpio_desc returned by x86_android_tablet_get_gpiod() is a "raw"
+ * gpio_desc, that is there is no way to pass lookup-flags like
+ * GPIO_ACTIVE_LOW. Set the GPIO to 0 here to enable charging since
+ * the /CE pin is active-low, but not marked as such in the gpio_desc.
+ */
+ gpiod_set_value(gpiod, 0);
+
+ /* OTG pin */
+ ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, &gpiod);
+ if (ret < 0)
+ return ret;
+
+ gpiod_set_value(gpiod, 0);
+
+ return 0;
+}
+
+static const struct x86_dev_info lenovo_yt3_info __initconst = {
+ .i2c_client_info = lenovo_yt3_i2c_clients,
+ .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients),
+ .init = lenovo_yt3_init,
+};
+
+/* Medion Lifetab S10346 tablets have an Android factory img with everything hardcoded */
+static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
+ "0", "1", "0",
+ "1", "0", "0",
+ "0", "0", "1"
+};
+
+static const struct property_entry medion_lifetab_s10346_accel_props[] = {
+ PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
+ { }
+};
+
+static const struct software_node medion_lifetab_s10346_accel_node = {
+ .properties = medion_lifetab_s10346_accel_props,
+};
+
+/* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
+static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ { }
+};
+
+static const struct software_node medion_lifetab_s10346_touchscreen_node = {
+ .properties = medion_lifetab_s10346_touchscreen_props,
+};
+
+static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
+ {
+ /* kxtj21009 accel */
+ .board_info = {
+ .type = "kxtj21009",
+ .addr = 0x0f,
+ .dev_name = "kxtj21009",
+ .swnode = &medion_lifetab_s10346_accel_node,
+ },
+ .adapter_path = "\\_SB_.I2C3",
+ .irq_data = {
+ .type = X86_ACPI_IRQ_TYPE_GPIOINT,
+ .chip = "INT33FC:02",
+ .index = 23,
+ .trigger = ACPI_EDGE_SENSITIVE,
+ .polarity = ACPI_ACTIVE_HIGH,
+ },
+ }, {
+ /* goodix touchscreen */
+ .board_info = {
+ .type = "GDIX1001:00",
+ .addr = 0x14,
+ .dev_name = "goodix_ts",
+ .swnode = &medion_lifetab_s10346_touchscreen_node,
+ },
+ .adapter_path = "\\_SB_.I2C4",
+ .irq_data = {
+ .type = X86_ACPI_IRQ_TYPE_APIC,
+ .index = 0x44,
+ .trigger = ACPI_EDGE_SENSITIVE,
+ .polarity = ACPI_ACTIVE_LOW,
+ },
+ },
+};
+
+static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
+ .dev_id = "i2c-goodix_ts",
+ .table = {
+ GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
+ &medion_lifetab_s10346_goodix_gpios,
+ NULL
+};
+
+static const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
+ .i2c_client_info = medion_lifetab_s10346_i2c_clients,
+ .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
+ .gpiod_lookup_tables = medion_lifetab_s10346_gpios,
+};
+
/* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */
static const char * const nextbook_ares8_accel_mount_matrix[] = {
"0", "-1", "0",
@@ -1180,6 +1436,14 @@ static const struct x86_dev_info xiaomi_mipad2_info __initconst = {
static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
{
+ /* Advantech MICA-071 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"),
+ },
+ .driver_data = (void *)&advantech_mica_071_info,
+ },
+ {
/* Asus MeMO Pad 7 ME176C */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -1246,6 +1510,25 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
.driver_data = (void *)&lenovo_yoga_tab2_830_1050_info,
},
{
+ /* Lenovo Yoga Tab 3 Pro YT3-X90F */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
+ .driver_data = (void *)&lenovo_yt3_info,
+ },
+ {
+ /* Medion Lifetab S10346 */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+ /* Above strings are much too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"),
+ },
+ .driver_data = (void *)&medion_lifetab_s10346_info,
+ },
+ {
/* Nextbook Ares 8 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index 97440462aa25..391f7ea4431e 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -143,13 +143,12 @@ static int ebook_switch_add(struct acpi_device *device)
return error;
}
-static int ebook_switch_remove(struct acpi_device *device)
+static void ebook_switch_remove(struct acpi_device *device)
{
struct ebook_switch *button = acpi_driver_data(device);
input_unregister_device(button->input);
kfree(button);
- return 0;
}
static struct acpi_driver xo15_ebook_driver = {
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 4df5aa6a309c..6a60c5d83383 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -148,14 +148,14 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
dev->dev.coherent_dma_mask = dev->dma_mask;
dev->dev.release = &pnp_release_device;
- dev_set_name(&dev->dev, "%02x:%02x", dev->protocol->number, dev->number);
-
dev_id = pnp_add_id(dev, pnpid);
if (!dev_id) {
kfree(dev);
return NULL;
}
+ dev_set_name(&dev->dev, "%02x:%02x", dev->protocol->number, dev->number);
+
return dev;
}
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index c02e7bf643a6..46c534f6b1c9 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -182,7 +182,8 @@ static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
- if (pnp_can_disable(pnp_dev)) {
+ /* can_write is necessary to be able to re-start the device on resume */
+ if (pnp_can_disable(pnp_dev) && pnp_can_write(pnp_dev)) {
error = pnp_stop_dev(pnp_dev);
if (error)
return error;
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index 863fabe05bdc..307ee6f71042 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -725,7 +725,14 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
/* Get thermal zone and ADC */
di->tz = thermal_zone_get_zone_by_name("battery-thermal");
if (IS_ERR(di->tz)) {
- return dev_err_probe(dev, PTR_ERR(di->tz),
+ ret = PTR_ERR(di->tz);
+ /*
+ * This usually just means we are probing before the thermal
+ * zone, so just defer.
+ */
+ if (ret == -ENODEV)
+ ret = -EPROBE_DEFER;
+ return dev_err_probe(dev, ret,
"failed to get battery thermal zone\n");
}
di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
diff --git a/drivers/power/supply/ip5xxx_power.c b/drivers/power/supply/ip5xxx_power.c
index 218e8e689a3f..00221e9c0bfc 100644
--- a/drivers/power/supply/ip5xxx_power.c
+++ b/drivers/power/supply/ip5xxx_power.c
@@ -352,7 +352,7 @@ static int ip5xxx_battery_get_property(struct power_supply *psy,
ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0,
IP5XXX_BATIADC_DAT1, &raw);
- val->intval = DIV_ROUND_CLOSEST(raw * 745985, 1000);
+ val->intval = DIV_ROUND_CLOSEST(raw * 149197, 200);
return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index 635f051b0821..f20a6ac584cc 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -121,7 +121,7 @@ struct rk817_charger {
#define ADC_TO_CHARGE_UAH(adc_value, res_div) \
(adc_value / 3600 * 172 / res_div)
-static u8 rk817_chg_cur_to_reg(u32 chg_cur_ma)
+static int rk817_chg_cur_to_reg(u32 chg_cur_ma)
{
if (chg_cur_ma >= 3500)
return CHG_3_5A;
@@ -864,8 +864,8 @@ static int rk817_battery_init(struct rk817_charger *charger,
{
struct rk808 *rk808 = charger->rk808;
u32 tmp, max_chg_vol_mv, max_chg_cur_ma;
- u8 max_chg_vol_reg, chg_term_i_reg, max_chg_cur_reg;
- int ret, chg_term_ma;
+ u8 max_chg_vol_reg, chg_term_i_reg;
+ int ret, chg_term_ma, max_chg_cur_reg;
u8 bulk_reg[2];
/* Get initial plug state */
@@ -1116,14 +1116,12 @@ static int rk817_charger_probe(struct platform_device *pdev)
charger->bat_ps = devm_power_supply_register(&pdev->dev,
&rk817_bat_desc, &pscfg);
-
- charger->chg_ps = devm_power_supply_register(&pdev->dev,
- &rk817_chg_desc, &pscfg);
-
- if (IS_ERR(charger->chg_ps))
+ if (IS_ERR(charger->bat_ps))
return dev_err_probe(dev, -EINVAL,
"Battery failed to probe\n");
+ charger->chg_ps = devm_power_supply_register(&pdev->dev,
+ &rk817_chg_desc, &pscfg);
if (IS_ERR(charger->chg_ps))
return dev_err_probe(dev, -EINVAL,
"Charger failed to probe\n");
diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig
index 515e3ceb3393..90d33cd1b670 100644
--- a/drivers/powercap/Kconfig
+++ b/drivers/powercap/Kconfig
@@ -44,6 +44,19 @@ config IDLE_INJECT
synchronously on a set of specified CPUs or alternatively
on a per CPU basis.
+config ARM_SCMI_POWERCAP
+ tristate "ARM SCMI Powercap driver"
+ depends on ARM_SCMI_PROTOCOL
+ help
+ This enables support for the ARM Powercap based on ARM SCMI
+ Powercap protocol.
+
+ ARM SCMI Powercap protocol allows power limits to be enforced
+ and monitored against the SCMI Powercap domains advertised as
+ available by the SCMI platform firmware.
+
+ When compiled as module it will be called arm_scmi_powercap.ko.
+
config DTPM
bool "Power capping for Dynamic Thermal Power Management (EXPERIMENTAL)"
depends on OF
diff --git a/drivers/powercap/Makefile b/drivers/powercap/Makefile
index 494617cdad88..4474201b4aa7 100644
--- a/drivers/powercap/Makefile
+++ b/drivers/powercap/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_POWERCAP) += powercap_sys.o
obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o
obj-$(CONFIG_INTEL_RAPL) += intel_rapl_msr.o
obj-$(CONFIG_IDLE_INJECT) += idle_inject.o
+obj-$(CONFIG_ARM_SCMI_POWERCAP) += arm_scmi_powercap.o
diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
new file mode 100644
index 000000000000..05d0e516176a
--- /dev/null
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI Powercap support.
+ *
+ * Copyright (C) 2022 ARM Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/math.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/powercap.h>
+#include <linux/scmi_protocol.h>
+
+#define to_scmi_powercap_zone(z) \
+ container_of(z, struct scmi_powercap_zone, zone)
+
+static const struct scmi_powercap_proto_ops *powercap_ops;
+
+struct scmi_powercap_zone {
+ unsigned int height;
+ struct device *dev;
+ struct scmi_protocol_handle *ph;
+ const struct scmi_powercap_info *info;
+ struct scmi_powercap_zone *spzones;
+ struct powercap_zone zone;
+ struct list_head node;
+};
+
+struct scmi_powercap_root {
+ unsigned int num_zones;
+ struct scmi_powercap_zone *spzones;
+ struct list_head *registered_zones;
+};
+
+static struct powercap_control_type *scmi_top_pcntrl;
+
+static int scmi_powercap_zone_release(struct powercap_zone *pz)
+{
+ return 0;
+}
+
+static int scmi_powercap_get_max_power_range_uw(struct powercap_zone *pz,
+ u64 *max_power_range_uw)
+{
+ *max_power_range_uw = U32_MAX;
+ return 0;
+}
+
+static int scmi_powercap_get_power_uw(struct powercap_zone *pz,
+ u64 *power_uw)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+ u32 avg_power, pai;
+ int ret;
+
+ if (!spz->info->powercap_monitoring)
+ return -EINVAL;
+
+ ret = powercap_ops->measurements_get(spz->ph, spz->info->id, &avg_power,
+ &pai);
+ if (ret)
+ return ret;
+
+ *power_uw = avg_power;
+ if (spz->info->powercap_scale_mw)
+ *power_uw *= 1000;
+
+ return 0;
+}
+
+static const struct powercap_zone_ops zone_ops = {
+ .get_max_power_range_uw = scmi_powercap_get_max_power_range_uw,
+ .get_power_uw = scmi_powercap_get_power_uw,
+ .release = scmi_powercap_zone_release,
+};
+
+static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz,
+ u64 power_limit_uw, u32 *norm)
+{
+ bool scale_mw = spz->info->powercap_scale_mw;
+ u64 val;
+
+ val = scale_mw ? DIV_ROUND_UP_ULL(power_limit_uw, 1000) : power_limit_uw;
+ /*
+ * This cast is lossless since here @req_power is certain to be within
+ * the range [min_power_cap, max_power_cap] whose bounds are assured to
+ * be two unsigned 32bits quantities.
+ */
+ *norm = clamp_t(u32, val, spz->info->min_power_cap,
+ spz->info->max_power_cap);
+ *norm = rounddown(*norm, spz->info->power_cap_step);
+
+ val = (scale_mw) ? *norm * 1000 : *norm;
+ if (power_limit_uw != val)
+ dev_dbg(spz->dev,
+ "Normalized %s:CAP - requested:%llu - normalized:%llu\n",
+ spz->info->name, power_limit_uw, val);
+}
+
+static int scmi_powercap_set_power_limit_uw(struct powercap_zone *pz, int cid,
+ u64 power_uw)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+ u32 norm_power;
+
+ if (!spz->info->powercap_cap_config)
+ return -EINVAL;
+
+ scmi_powercap_normalize_cap(spz, power_uw, &norm_power);
+
+ return powercap_ops->cap_set(spz->ph, spz->info->id, norm_power, false);
+}
+
+static int scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid,
+ u64 *power_limit_uw)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+ u32 power;
+ int ret;
+
+ ret = powercap_ops->cap_get(spz->ph, spz->info->id, &power);
+ if (ret)
+ return ret;
+
+ *power_limit_uw = power;
+ if (spz->info->powercap_scale_mw)
+ *power_limit_uw *= 1000;
+
+ return 0;
+}
+
+static void scmi_powercap_normalize_time(const struct scmi_powercap_zone *spz,
+ u64 time_us, u32 *norm)
+{
+ /*
+ * This cast is lossless since here @time_us is certain to be within the
+ * range [min_pai, max_pai] whose bounds are assured to be two unsigned
+ * 32bits quantities.
+ */
+ *norm = clamp_t(u32, time_us, spz->info->min_pai, spz->info->max_pai);
+ *norm = rounddown(*norm, spz->info->pai_step);
+
+ if (time_us != *norm)
+ dev_dbg(spz->dev,
+ "Normalized %s:PAI - requested:%llu - normalized:%u\n",
+ spz->info->name, time_us, *norm);
+}
+
+static int scmi_powercap_set_time_window_us(struct powercap_zone *pz, int cid,
+ u64 time_window_us)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+ u32 norm_pai;
+
+ if (!spz->info->powercap_pai_config)
+ return -EINVAL;
+
+ scmi_powercap_normalize_time(spz, time_window_us, &norm_pai);
+
+ return powercap_ops->pai_set(spz->ph, spz->info->id, norm_pai);
+}
+
+static int scmi_powercap_get_time_window_us(struct powercap_zone *pz, int cid,
+ u64 *time_window_us)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+ int ret;
+ u32 pai;
+
+ ret = powercap_ops->pai_get(spz->ph, spz->info->id, &pai);
+ if (ret)
+ return ret;
+
+ *time_window_us = pai;
+
+ return 0;
+}
+
+static int scmi_powercap_get_max_power_uw(struct powercap_zone *pz, int cid,
+ u64 *max_power_uw)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+ *max_power_uw = spz->info->max_power_cap;
+ if (spz->info->powercap_scale_mw)
+ *max_power_uw *= 1000;
+
+ return 0;
+}
+
+static int scmi_powercap_get_min_power_uw(struct powercap_zone *pz, int cid,
+ u64 *min_power_uw)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+ *min_power_uw = spz->info->min_power_cap;
+ if (spz->info->powercap_scale_mw)
+ *min_power_uw *= 1000;
+
+ return 0;
+}
+
+static int scmi_powercap_get_max_time_window_us(struct powercap_zone *pz,
+ int cid, u64 *time_window_us)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+ *time_window_us = spz->info->max_pai;
+
+ return 0;
+}
+
+static int scmi_powercap_get_min_time_window_us(struct powercap_zone *pz,
+ int cid, u64 *time_window_us)
+{
+ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+ *time_window_us = (u64)spz->info->min_pai;
+
+ return 0;
+}
+
+static const char *scmi_powercap_get_name(struct powercap_zone *pz, int cid)
+{
+ return "SCMI power-cap";
+}
+
+static const struct powercap_zone_constraint_ops constraint_ops = {
+ .set_power_limit_uw = scmi_powercap_set_power_limit_uw,
+ .get_power_limit_uw = scmi_powercap_get_power_limit_uw,
+ .set_time_window_us = scmi_powercap_set_time_window_us,
+ .get_time_window_us = scmi_powercap_get_time_window_us,
+ .get_max_power_uw = scmi_powercap_get_max_power_uw,
+ .get_min_power_uw = scmi_powercap_get_min_power_uw,
+ .get_max_time_window_us = scmi_powercap_get_max_time_window_us,
+ .get_min_time_window_us = scmi_powercap_get_min_time_window_us,
+ .get_name = scmi_powercap_get_name,
+};
+
+static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr)
+{
+ int i;
+
+ /* Un-register children zones first starting from the leaves */
+ for (i = pr->num_zones - 1; i >= 0; i--) {
+ if (!list_empty(&pr->registered_zones[i])) {
+ struct scmi_powercap_zone *spz;
+
+ list_for_each_entry(spz, &pr->registered_zones[i], node)
+ powercap_unregister_zone(scmi_top_pcntrl,
+ &spz->zone);
+ }
+ }
+}
+
+static inline bool
+scmi_powercap_is_zone_registered(struct scmi_powercap_zone *spz)
+{
+ return !list_empty(&spz->node);
+}
+
+static inline unsigned int
+scmi_powercap_get_zone_height(struct scmi_powercap_zone *spz)
+{
+ if (spz->info->parent_id == SCMI_POWERCAP_ROOT_ZONE_ID)
+ return 0;
+
+ return spz->spzones[spz->info->parent_id].height + 1;
+}
+
+static inline struct scmi_powercap_zone *
+scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
+{
+ if (spz->info->parent_id == SCMI_POWERCAP_ROOT_ZONE_ID)
+ return NULL;
+
+ return &spz->spzones[spz->info->parent_id];
+}
+
+/**
+ * scmi_powercap_register_zone - Register an SCMI powercap zone recursively
+ *
+ * @pr: A reference to the root powercap zones descriptors
+ * @spz: A reference to the SCMI powercap zone to register
+ *
+ * When registering SCMI powercap zones with the powercap framework we should
+ * take care to always register zones starting from the root ones and to
+ * deregister starting from the leaves.
+ *
+ * Unfortunately we cannot assume that the array of available SCMI powercap
+ * zones provided by the SCMI platform firmware is built to comply with such
+ * requirement.
+ *
+ * This function, given an SCMI powercap zone to register, takes care to walk
+ * the SCMI powercap zones tree up to the root looking recursively for
+ * unregistered parent zones before registering the provided zone; at the same
+ * time each registered zone height in such a tree is accounted for and each
+ * zone, once registered, is stored in the @registered_zones array that is
+ * indexed by zone height: this way will be trivial, at unregister time, to walk
+ * the @registered_zones array backward and unregister all the zones starting
+ * from the leaves, removing children zones before parents.
+ *
+ * While doing this, we prune away any zone marked as invalid (like the ones
+ * sporting an SCMI abstract power scale) as long as they are positioned as
+ * leaves in the SCMI powercap zones hierarchy: any non-leaf invalid zone causes
+ * the entire process to fail since we cannot assume the correctness of an SCMI
+ * powercap zones hierarchy if some of the internal nodes are missing.
+ *
+ * Note that the array of SCMI powercap zones as returned by the SCMI platform
+ * is known to be sane, i.e. zones relationships have been validated at the
+ * protocol layer.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
+ struct scmi_powercap_zone *spz)
+{
+ int ret = 0;
+ struct scmi_powercap_zone *parent;
+
+ if (!spz->info)
+ return ret;
+
+ parent = scmi_powercap_get_parent_zone(spz);
+ if (parent && !scmi_powercap_is_zone_registered(parent)) {
+ /*
+ * Bail out if a parent domain was marked as unsupported:
+ * only domains participating as leaves can be skipped.
+ */
+ if (!parent->info)
+ return -ENODEV;
+
+ ret = scmi_powercap_register_zone(pr, parent);
+ if (ret)
+ return ret;
+ }
+
+ if (!scmi_powercap_is_zone_registered(spz)) {
+ struct powercap_zone *z;
+
+ z = powercap_register_zone(&spz->zone,
+ scmi_top_pcntrl,
+ spz->info->name,
+ parent ? &parent->zone : NULL,
+ &zone_ops, 1, &constraint_ops);
+ if (!IS_ERR(z)) {
+ spz->height = scmi_powercap_get_zone_height(spz);
+ list_add(&spz->node,
+ &pr->registered_zones[spz->height]);
+ dev_dbg(spz->dev,
+ "Registered node %s - parent %s - height:%d\n",
+ spz->info->name,
+ parent ? parent->info->name : "ROOT",
+ spz->height);
+ ret = 0;
+ } else {
+ ret = PTR_ERR(z);
+ dev_err(spz->dev,
+ "Error registering node:%s - parent:%s - h:%d - ret:%d\n",
+ spz->info->name,
+ parent ? parent->info->name : "ROOT",
+ spz->height, ret);
+ }
+ }
+
+ return ret;
+}
+
+static int scmi_powercap_probe(struct scmi_device *sdev)
+{
+ int ret, i;
+ struct scmi_powercap_root *pr;
+ struct scmi_powercap_zone *spz;
+ struct scmi_protocol_handle *ph;
+ struct device *dev = &sdev->dev;
+
+ if (!sdev->handle)
+ return -ENODEV;
+
+ powercap_ops = sdev->handle->devm_protocol_get(sdev,
+ SCMI_PROTOCOL_POWERCAP,
+ &ph);
+ if (IS_ERR(powercap_ops))
+ return PTR_ERR(powercap_ops);
+
+ pr = devm_kzalloc(dev, sizeof(*pr), GFP_KERNEL);
+ if (!pr)
+ return -ENOMEM;
+
+ ret = powercap_ops->num_domains_get(ph);
+ if (ret < 0) {
+ dev_err(dev, "number of powercap domains not found\n");
+ return ret;
+ }
+ pr->num_zones = ret;
+
+ pr->spzones = devm_kcalloc(dev, pr->num_zones,
+ sizeof(*pr->spzones), GFP_KERNEL);
+ if (!pr->spzones)
+ return -ENOMEM;
+
+ /* Allocate for worst possible scenario of maximum tree height. */
+ pr->registered_zones = devm_kcalloc(dev, pr->num_zones,
+ sizeof(*pr->registered_zones),
+ GFP_KERNEL);
+ if (!pr->registered_zones)
+ return -ENOMEM;
+
+ for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
+ /*
+ * Powercap domains are validate by the protocol layer, i.e.
+ * when only non-NULL domains are returned here, whose
+ * parent_id is assured to point to another valid domain.
+ */
+ spz->info = powercap_ops->info_get(ph, i);
+
+ spz->dev = dev;
+ spz->ph = ph;
+ spz->spzones = pr->spzones;
+ INIT_LIST_HEAD(&spz->node);
+ INIT_LIST_HEAD(&pr->registered_zones[i]);
+
+ /*
+ * Forcibly skip powercap domains using an abstract scale.
+ * Note that only leaves domains can be skipped, so this could
+ * lead later to a global failure.
+ */
+ if (!spz->info->powercap_scale_uw &&
+ !spz->info->powercap_scale_mw) {
+ dev_warn(dev,
+ "Abstract power scale not supported. Skip %s.\n",
+ spz->info->name);
+ spz->info = NULL;
+ continue;
+ }
+ }
+
+ /*
+ * Scan array of retrieved SCMI powercap domains and register them
+ * recursively starting from the root domains.
+ */
+ for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
+ ret = scmi_powercap_register_zone(pr, spz);
+ if (ret) {
+ dev_err(dev,
+ "Failed to register powercap zone %s - ret:%d\n",
+ spz->info->name, ret);
+ scmi_powercap_unregister_all_zones(pr);
+ return ret;
+ }
+ }
+
+ dev_set_drvdata(dev, pr);
+
+ dev_info(dev, "Registered %d SCMI Powercap domains !\n", pr->num_zones);
+
+ return ret;
+}
+
+static void scmi_powercap_remove(struct scmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ struct scmi_powercap_root *pr = dev_get_drvdata(dev);
+
+ scmi_powercap_unregister_all_zones(pr);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_POWERCAP, "powercap" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_powercap_driver = {
+ .name = "scmi-powercap",
+ .probe = scmi_powercap_probe,
+ .remove = scmi_powercap_remove,
+ .id_table = scmi_id_table,
+};
+
+static int __init scmi_powercap_init(void)
+{
+ int ret;
+
+ scmi_top_pcntrl = powercap_register_control_type(NULL, "arm-scmi", NULL);
+ if (IS_ERR(scmi_top_pcntrl))
+ return PTR_ERR(scmi_top_pcntrl);
+
+ ret = scmi_register(&scmi_powercap_driver);
+ if (ret)
+ powercap_unregister_control_type(scmi_top_pcntrl);
+
+ return ret;
+}
+module_init(scmi_powercap_init);
+
+static void __exit scmi_powercap_exit(void)
+{
+ scmi_unregister(&scmi_powercap_driver);
+
+ powercap_unregister_control_type(scmi_top_pcntrl);
+}
+module_exit(scmi_powercap_exit);
+
+MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI Powercap driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/powercap/idle_inject.c b/drivers/powercap/idle_inject.c
index 999e218d7793..fe86a09e3b67 100644
--- a/drivers/powercap/idle_inject.c
+++ b/drivers/powercap/idle_inject.c
@@ -147,6 +147,7 @@ static void idle_inject_fn(unsigned int cpu)
/**
* idle_inject_set_duration - idle and run duration update helper
+ * @ii_dev: idle injection control device structure
* @run_duration_us: CPU run time to allow in microseconds
* @idle_duration_us: CPU idle time to inject in microseconds
*/
@@ -162,6 +163,7 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev,
/**
* idle_inject_get_duration - idle and run duration retrieval helper
+ * @ii_dev: idle injection control device structure
* @run_duration_us: memory location to store the current CPU run time
* @idle_duration_us: memory location to store the current CPU idle time
*/
@@ -175,6 +177,7 @@ void idle_inject_get_duration(struct idle_inject_device *ii_dev,
/**
* idle_inject_set_latency - set the maximum latency allowed
+ * @ii_dev: idle injection control device structure
* @latency_us: set the latency requirement for the idle state
*/
void idle_inject_set_latency(struct idle_inject_device *ii_dev,
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c
index f0654a932b37..1f968353d479 100644
--- a/drivers/powercap/powercap_sys.c
+++ b/drivers/powercap/powercap_sys.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/powercap.h>
@@ -446,7 +447,7 @@ static ssize_t enabled_store(struct device *dev,
{
bool mode;
- if (strtobool(buf, &mode))
+ if (kstrtobool(buf, &mode))
return -EINVAL;
if (dev->parent) {
struct powercap_zone *power_zone = to_powercap_zone(dev);
diff --git a/drivers/ptp/ptp_vmw.c b/drivers/ptp/ptp_vmw.c
index 5dca26e14bdc..0dcbabd1533d 100644
--- a/drivers/ptp/ptp_vmw.c
+++ b/drivers/ptp/ptp_vmw.c
@@ -101,10 +101,9 @@ static int ptp_vmw_acpi_add(struct acpi_device *device)
return 0;
}
-static int ptp_vmw_acpi_remove(struct acpi_device *device)
+static void ptp_vmw_acpi_remove(struct acpi_device *device)
{
ptp_clock_unregister(ptp_vmw_clock);
- return 0;
}
static const struct acpi_device_id ptp_vmw_acpi_device_ids[] = {
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
index 2cdc054e53a5..43db495f1986 100644
--- a/drivers/rapidio/devices/rio_mport_cdev.c
+++ b/drivers/rapidio/devices/rio_mport_cdev.c
@@ -1804,8 +1804,11 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,
rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
0, 0xffff);
err = rio_add_device(rdev);
- if (err)
- goto cleanup;
+ if (err) {
+ put_device(&rdev->dev);
+ return err;
+ }
+
rio_dev_get(rdev);
return 0;
@@ -1901,10 +1904,6 @@ static int mport_cdev_open(struct inode *inode, struct file *filp)
priv->md = chdev;
- mutex_lock(&chdev->file_mutex);
- list_add_tail(&priv->list, &chdev->file_list);
- mutex_unlock(&chdev->file_mutex);
-
INIT_LIST_HEAD(&priv->db_filters);
INIT_LIST_HEAD(&priv->pw_filters);
spin_lock_init(&priv->fifo_lock);
@@ -1913,6 +1912,7 @@ static int mport_cdev_open(struct inode *inode, struct file *filp)
sizeof(struct rio_event) * MPORT_EVENT_DEPTH,
GFP_KERNEL);
if (ret < 0) {
+ put_device(&chdev->dev);
dev_err(&chdev->dev, DRV_NAME ": kfifo_alloc failed\n");
ret = -ENOMEM;
goto err_fifo;
@@ -1923,6 +1923,9 @@ static int mport_cdev_open(struct inode *inode, struct file *filp)
spin_lock_init(&priv->req_lock);
mutex_init(&priv->dma_lock);
#endif
+ mutex_lock(&chdev->file_mutex);
+ list_add_tail(&priv->list, &chdev->file_list);
+ mutex_unlock(&chdev->file_mutex);
filp->private_data = priv;
goto out;
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index b3134744fb55..0a42d6a2af24 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -2941,7 +2941,8 @@ static void tsi721_remove(struct pci_dev *pdev)
tsi721_disable_ints(priv);
tsi721_free_irq(priv);
- flush_scheduled_work();
+ flush_work(&priv->idb_work);
+ flush_work(&priv->pw_work);
rio_unregister_mport(&priv->mport);
tsi721_unregister_dma(priv);
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 19b0c33f4a62..fdcf742b2adb 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -454,8 +454,12 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
0, 0xffff);
ret = rio_add_device(rdev);
- if (ret)
- goto cleanup;
+ if (ret) {
+ if (rswitch)
+ kfree(rswitch->route_table);
+ put_device(&rdev->dev);
+ return NULL;
+ }
rio_dev_get(rdev);
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index e74cf09eeff0..9544b8ee0c96 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -2186,11 +2186,16 @@ int rio_register_mport(struct rio_mport *port)
atomic_set(&port->state, RIO_DEVICE_RUNNING);
res = device_register(&port->dev);
- if (res)
+ if (res) {
dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n",
port->id, res);
- else
+ mutex_lock(&rio_mport_list_lock);
+ list_del(&port->node);
+ mutex_unlock(&rio_mport_list_lock);
+ put_device(&port->dev);
+ } else {
dev_dbg(&port->dev, "RIO: registered mport%d\n", port->id);
+ }
return res;
}
diff --git a/drivers/ras/debugfs.c b/drivers/ras/debugfs.c
index 0d4f985afbf3..f0a6391b1146 100644
--- a/drivers/ras/debugfs.c
+++ b/drivers/ras/debugfs.c
@@ -15,7 +15,7 @@ EXPORT_SYMBOL_GPL(ras_userspace_consumers);
static int trace_show(struct seq_file *m, void *v)
{
- return atomic_read(&trace_count);
+ return 0;
}
static int trace_open(struct inode *inode, struct file *file)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c84e8d78dc7e..ace4ecc6d7c2 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -5168,6 +5168,7 @@ static void regulator_dev_release(struct device *dev)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
+ debugfs_remove_recursive(rdev->debugfs);
kfree(rdev->constraints);
of_node_put(rdev->dev.of_node);
kfree(rdev);
@@ -5659,11 +5660,15 @@ wash:
mutex_lock(&regulator_list_mutex);
regulator_ena_gpio_free(rdev);
mutex_unlock(&regulator_list_mutex);
+ put_device(&rdev->dev);
+ rdev = NULL;
clean:
if (dangling_of_gpiod)
gpiod_put(config->ena_gpiod);
+ if (rdev && rdev->dev.of_node)
+ of_node_put(rdev->dev.of_node);
+ kfree(rdev);
kfree(config);
- put_device(&rdev->dev);
rinse:
if (dangling_cfg_gpiod)
gpiod_put(cfg->ena_gpiod);
@@ -5692,7 +5697,6 @@ void regulator_unregister(struct regulator_dev *rdev)
mutex_lock(&regulator_list_mutex);
- debugfs_remove_recursive(rdev->debugfs);
WARN_ON(rdev->open_count);
regulator_remove_coupling(rdev);
unset_regulator_supplies(rdev);
diff --git a/drivers/regulator/rt5759-regulator.c b/drivers/regulator/rt5759-regulator.c
index 6b96899eb27e..8488417f4b2c 100644
--- a/drivers/regulator/rt5759-regulator.c
+++ b/drivers/regulator/rt5759-regulator.c
@@ -243,6 +243,7 @@ static int rt5759_regulator_register(struct rt5759_priv *priv)
if (priv->chip_type == CHIP_TYPE_RT5759A)
reg_desc->uV_step = RT5759A_STEP_UV;
+ memset(&reg_cfg, 0, sizeof(reg_cfg));
reg_cfg.dev = priv->dev;
reg_cfg.of_node = np;
reg_cfg.init_data = of_get_regulator_init_data(priv->dev, np, reg_desc);
diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c
index 75a941fb3c2b..1b2eee95ad3f 100644
--- a/drivers/regulator/slg51000-regulator.c
+++ b/drivers/regulator/slg51000-regulator.c
@@ -457,6 +457,8 @@ static int slg51000_i2c_probe(struct i2c_client *client)
chip->cs_gpiod = cs_gpiod;
}
+ usleep_range(10000, 11000);
+
i2c_set_clientdata(client, chip);
chip->chip_irq = client->irq;
chip->dev = dev;
diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c
index 430265c404d6..f3856750944f 100644
--- a/drivers/regulator/twl6030-regulator.c
+++ b/drivers/regulator/twl6030-regulator.c
@@ -67,6 +67,7 @@ struct twlreg_info {
#define TWL6030_CFG_STATE_SLEEP 0x03
#define TWL6030_CFG_STATE_GRP_SHIFT 5
#define TWL6030_CFG_STATE_APP_SHIFT 2
+#define TWL6030_CFG_STATE_MASK 0x03
#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
TWL6030_CFG_STATE_APP_SHIFT)
@@ -128,13 +129,14 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev)
if (grp < 0)
return grp;
grp &= P1_GRP_6030;
+ val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+ val = TWL6030_CFG_STATE_APP(val);
} else {
+ val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+ val &= TWL6030_CFG_STATE_MASK;
grp = 1;
}
- val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
- val = TWL6030_CFG_STATE_APP(val);
-
return grp && (val == TWL6030_CFG_STATE_ON);
}
@@ -187,7 +189,12 @@ static int twl6030reg_get_status(struct regulator_dev *rdev)
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
- switch (TWL6030_CFG_STATE_APP(val)) {
+ if (info->features & TWL6032_SUBCLASS)
+ val &= TWL6030_CFG_STATE_MASK;
+ else
+ val = TWL6030_CFG_STATE_APP(val);
+
+ switch (val) {
case TWL6030_CFG_STATE_ON:
return REGULATOR_STATUS_NORMAL;
@@ -530,6 +537,7 @@ static const struct twlreg_info TWL6030_INFO_##label = { \
#define TWL6032_ADJUSTABLE_LDO(label, offset) \
static const struct twlreg_info TWL6032_INFO_##label = { \
.base = offset, \
+ .features = TWL6032_SUBCLASS, \
.desc = { \
.name = #label, \
.id = TWL6032_REG_##label, \
@@ -562,6 +570,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
#define TWL6032_ADJUSTABLE_SMPS(label, offset) \
static const struct twlreg_info TWLSMPS_INFO_##label = { \
.base = offset, \
+ .features = TWL6032_SUBCLASS, \
.desc = { \
.name = #label, \
.id = TWL6032_REG_##label, \
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index cb83f81da416..df17f0f9cb0f 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1954,7 +1954,7 @@ dasd_copy_pair_show(struct device *dev,
break;
}
}
- if (!copy->entry[i].primary)
+ if (i == DASD_CP_ENTRIES)
goto out;
/* print all secondary */
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 662730f3b027..5d0b9991e91a 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -4722,7 +4722,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
struct dasd_device *basedev;
struct req_iterator iter;
struct dasd_ccw_req *cqr;
- unsigned int first_offs;
unsigned int trkcount;
unsigned long *idaws;
unsigned int size;
@@ -4756,7 +4755,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) /
DASD_RAW_SECTORS_PER_TRACK;
trkcount = last_trk - first_trk + 1;
- first_offs = 0;
if (rq_data_dir(req) == READ)
cmd = DASD_ECKD_CCW_READ_TRACK;
@@ -4800,13 +4798,13 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
if (use_prefix) {
prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev,
- startdev, 1, first_offs + 1, trkcount, 0, 0);
+ startdev, 1, 0, trkcount, 0, 0);
} else {
define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0);
ccw[-1].flags |= CCW_FLAG_CC;
data += sizeof(struct DE_eckd_data);
- locate_record_ext(ccw++, data, first_trk, first_offs + 1,
+ locate_record_ext(ccw++, data, first_trk, 0,
trkcount, cmd, basedev, 0, 0);
}
@@ -5500,7 +5498,7 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
* Dump the range of CCWs into 'page' buffer
* and return number of printed chars.
*/
-static int
+static void
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
{
int len, count;
@@ -5518,16 +5516,21 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
else
datap = (char *) ((addr_t) from->cda);
- /* dump data (max 32 bytes) */
- for (count = 0; count < from->count && count < 32; count++) {
- if (count % 8 == 0) len += sprintf(page + len, " ");
- if (count % 4 == 0) len += sprintf(page + len, " ");
+ /* dump data (max 128 bytes) */
+ for (count = 0; count < from->count && count < 128; count++) {
+ if (count % 32 == 0)
+ len += sprintf(page + len, "\n");
+ if (count % 8 == 0)
+ len += sprintf(page + len, " ");
+ if (count % 4 == 0)
+ len += sprintf(page + len, " ");
len += sprintf(page + len, "%02x", datap[count]);
}
len += sprintf(page + len, "\n");
from++;
}
- return len;
+ if (len > 0)
+ printk(KERN_ERR "%s", page);
}
static void
@@ -5619,37 +5622,33 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
if (req) {
/* req == NULL for unsolicited interrupts */
/* dump the Channel Program (max 140 Bytes per line) */
- /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+ /* Count CCW and print first CCWs (maximum 7) */
first = req->cpaddr;
for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
to = min(first + 6, last);
- len = sprintf(page, PRINTK_HEADER
- " Related CP in req: %p\n", req);
- dasd_eckd_dump_ccw_range(first, to, page + len);
- printk(KERN_ERR "%s", page);
+ printk(KERN_ERR PRINTK_HEADER " Related CP in req: %p\n", req);
+ dasd_eckd_dump_ccw_range(first, to, page);
/* print failing CCW area (maximum 4) */
/* scsw->cda is either valid or zero */
- len = 0;
from = ++to;
fail = (struct ccw1 *)(addr_t)
irb->scsw.cmd.cpa; /* failing CCW */
if (from < fail - 2) {
from = fail - 2; /* there is a gap - print header */
- len += sprintf(page, PRINTK_HEADER "......\n");
+ printk(KERN_ERR PRINTK_HEADER "......\n");
}
to = min(fail + 1, last);
- len += dasd_eckd_dump_ccw_range(from, to, page + len);
+ dasd_eckd_dump_ccw_range(from, to, page + len);
/* print last CCWs (maximum 2) */
+ len = 0;
from = max(from, ++to);
if (from < last - 1) {
from = last - 1; /* there is a gap - print header */
- len += sprintf(page + len, PRINTK_HEADER "......\n");
+ printk(KERN_ERR PRINTK_HEADER "......\n");
}
- len += dasd_eckd_dump_ccw_range(from, last, page + len);
- if (len > 0)
- printk(KERN_ERR "%s", page);
+ dasd_eckd_dump_ccw_range(from, last, page + len);
}
free_page((unsigned long) page);
}
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index d0ddf2cc9786..9327dcdd6e5e 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -401,7 +401,7 @@ dasd_ioctl_copy_pair_swap(struct block_device *bdev, void __user *argp)
return -EFAULT;
}
if (memchr_inv(data.reserved, 0, sizeof(data.reserved))) {
- pr_warn("%s: Ivalid swap data specified.\n",
+ pr_warn("%s: Invalid swap data specified\n",
dev_name(&device->cdev->dev));
dasd_put_device(device);
return DASD_COPYPAIRSWAP_INVALID;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 93b80da60277..b392b9f5482e 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -636,6 +636,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
dev_info->gd->minors = DCSSBLK_MINORS_PER_DISK;
dev_info->gd->fops = &dcssblk_devops;
dev_info->gd->private_data = dev_info;
+ dev_info->gd->flags |= GENHD_FL_NO_PART;
blk_queue_logical_block_size(dev_info->gd->queue, 4096);
blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->gd->queue);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 4ae07c7e2175..72ba83c1bc79 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -102,6 +102,7 @@ static struct raw3215_req *raw3215_freelist;
static DEFINE_SPINLOCK(raw3215_freelist_lock);
static struct tty_driver *tty3215_driver;
+static bool con3215_drop = true;
/*
* Get a request structure from the free list
@@ -159,7 +160,7 @@ static void raw3215_mk_read_req(struct raw3215_info *raw)
ccw->cmd_code = 0x0A; /* read inquiry */
ccw->flags = 0x20; /* ignore incorrect length */
ccw->count = 160;
- ccw->cda = (__u32) __pa(raw->inbuf);
+ ccw->cda = (__u32)__pa(raw->inbuf);
}
/*
@@ -218,8 +219,7 @@ static void raw3215_mk_write_req(struct raw3215_info *raw)
ccw[-1].flags |= 0x40; /* use command chaining */
ccw->cmd_code = 0x01; /* write, auto carrier return */
ccw->flags = 0x20; /* ignore incorrect length ind. */
- ccw->cda =
- (__u32) __pa(raw->buffer + ix);
+ ccw->cda = (__u32)__pa(raw->buffer + ix);
count = len;
if (ix + count > RAW3215_BUFFER_SIZE)
count = RAW3215_BUFFER_SIZE - ix;
@@ -447,13 +447,45 @@ put_tty:
}
/*
+ * Need to drop data to avoid blocking. Drop as much data as possible.
+ * This is unqueued part in the buffer and the queued part in the request.
+ * Also adjust the head position to append new data and set count
+ * accordingly.
+ *
+ * Return number of bytes available in buffer.
+ */
+static unsigned int raw3215_drop(struct raw3215_info *raw)
+{
+ struct raw3215_req *req;
+
+ req = raw->queued_write;
+ if (req) {
+ /* Drop queued data and delete request */
+ raw->written -= req->len;
+ raw3215_free_req(req);
+ raw->queued_write = NULL;
+ }
+ raw->head = (raw->head - raw->count + raw->written) &
+ (RAW3215_BUFFER_SIZE - 1);
+ raw->count = raw->written;
+
+ return RAW3215_BUFFER_SIZE - raw->count;
+}
+
+/*
* Wait until length bytes are available int the output buffer.
+ * If drop mode is active and wait condition holds true, start dropping
+ * data.
* Has to be called with the s390irq lock held. Can be called
* disabled.
*/
-static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
+static unsigned int raw3215_make_room(struct raw3215_info *raw,
+ unsigned int length, bool drop)
{
while (RAW3215_BUFFER_SIZE - raw->count < length) {
+ if (drop)
+ return raw3215_drop(raw);
+
/* there might be a request pending */
raw->flags |= RAW3215_FLUSHING;
raw3215_mk_write_req(raw);
@@ -470,75 +502,89 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
udelay(100);
spin_lock(get_ccwdev_lock(raw->cdev));
}
+ return length;
}
+#define RAW3215_COUNT 1
+#define RAW3215_STORE 2
+
/*
- * String write routine for 3215 devices
+ * Add text to console buffer. Find tabs in input and calculate size
+ * including tab replacement.
+ * This function operates in 2 different modes, depending on parameter
+ * opmode:
+ * RAW3215_COUNT: Get the size needed for the input string with
+ * proper tab replacement calculation.
+ * Return value is the number of bytes required to store the
+ * input. However no data is actually stored.
+ * The parameter todrop is not used.
+ * RAW3215_STORE: Add data to the console buffer. The parameter todrop is
+ * valid and contains the number of bytes to be dropped from head of
+ * string without blocking.
+ * Return value is the number of bytes copied.
*/
-static void raw3215_write(struct raw3215_info *raw, const char *str,
- unsigned int length)
+static unsigned int raw3215_addtext(const char *str, unsigned int length,
+ struct raw3215_info *raw, int opmode,
+ unsigned int todrop)
{
- unsigned long flags;
- int c, count;
+ unsigned int c, ch, i, blanks, expanded_size = 0;
+ unsigned int column = raw->line_pos;
- while (length > 0) {
- spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- count = (length > RAW3215_BUFFER_SIZE) ?
- RAW3215_BUFFER_SIZE : length;
- length -= count;
-
- raw3215_make_room(raw, count);
-
- /* copy string to output buffer and convert it to EBCDIC */
- while (1) {
- c = min_t(int, count,
- min(RAW3215_BUFFER_SIZE - raw->count,
- RAW3215_BUFFER_SIZE - raw->head));
- if (c <= 0)
- break;
- memcpy(raw->buffer + raw->head, str, c);
- ASCEBC(raw->buffer + raw->head, c);
- raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1);
- raw->count += c;
- raw->line_pos += c;
- str += c;
- count -= c;
+ if (opmode == RAW3215_COUNT)
+ todrop = 0;
+
+ for (c = 0; c < length; ++c) {
+ blanks = 1;
+ ch = str[c];
+
+ switch (ch) {
+ case '\n':
+ expanded_size++;
+ column = 0;
+ break;
+ case '\t':
+ blanks = TAB_STOP_SIZE - (column % TAB_STOP_SIZE);
+ column += blanks;
+ expanded_size += blanks;
+ ch = ' ';
+ break;
+ default:
+ expanded_size++;
+ column++;
+ break;
}
- if (!(raw->flags & RAW3215_WORKING)) {
- raw3215_mk_write_req(raw);
- /* start or queue request */
- raw3215_try_io(raw);
+
+ if (opmode == RAW3215_COUNT)
+ continue;
+ if (todrop && expanded_size < todrop) /* Drop head data */
+ continue;
+ for (i = 0; i < blanks; i++) {
+ raw->buffer[raw->head] = (char)_ascebc[(int)ch];
+ raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
+ raw->count++;
}
- spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
+ raw->line_pos = column;
}
+ return expanded_size - todrop;
}
/*
- * Put character routine for 3215 devices
+ * String write routine for 3215 devices
*/
-static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
+static void raw3215_write(struct raw3215_info *raw, const char *str,
+ unsigned int length)
{
+ unsigned int count, avail;
unsigned long flags;
- unsigned int length, i;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- if (ch == '\t') {
- length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE);
- raw->line_pos += length;
- ch = ' ';
- } else if (ch == '\n') {
- length = 1;
- raw->line_pos = 0;
- } else {
- length = 1;
- raw->line_pos++;
- }
- raw3215_make_room(raw, length);
- for (i = 0; i < length; i++) {
- raw->buffer[raw->head] = (char) _ascebc[(int) ch];
- raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
- raw->count++;
+ count = raw3215_addtext(str, length, raw, RAW3215_COUNT, 0);
+
+ avail = raw3215_make_room(raw, count, con3215_drop);
+ if (avail) {
+ raw3215_addtext(str, length, raw, RAW3215_STORE,
+ count - avail);
}
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
@@ -549,6 +595,14 @@ static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
}
/*
+ * Put character routine for 3215 devices
+ */
+static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
+{
+ raw3215_write(raw, &ch, 1);
+}
+
+/*
* Flush routine, it simply sets the flush flag and tries to start
* pending IO.
*/
@@ -642,7 +696,7 @@ static void raw3215_free_info(struct raw3215_info *raw)
kfree(raw);
}
-static int raw3215_probe (struct ccw_device *cdev)
+static int raw3215_probe(struct ccw_device *cdev)
{
struct raw3215_info *raw;
int line;
@@ -675,7 +729,7 @@ static int raw3215_probe (struct ccw_device *cdev)
return 0;
}
-static void raw3215_remove (struct ccw_device *cdev)
+static void raw3215_remove(struct ccw_device *cdev)
{
struct raw3215_info *raw;
unsigned int line;
@@ -694,7 +748,7 @@ static void raw3215_remove (struct ccw_device *cdev)
}
}
-static int raw3215_set_online (struct ccw_device *cdev)
+static int raw3215_set_online(struct ccw_device *cdev)
{
struct raw3215_info *raw;
@@ -705,7 +759,7 @@ static int raw3215_set_online (struct ccw_device *cdev)
return raw3215_startup(raw);
}
-static int raw3215_set_offline (struct ccw_device *cdev)
+static int raw3215_set_offline(struct ccw_device *cdev)
{
struct raw3215_info *raw;
@@ -723,9 +777,43 @@ static struct ccw_device_id raw3215_id[] = {
{ /* end of list */ },
};
+static ssize_t con_drop_store(struct device_driver *dev, const char *buf, size_t count)
+{
+ bool drop;
+ int rc;
+
+ rc = kstrtobool(buf, &drop);
+ if (!rc)
+ con3215_drop = drop;
+ return rc ?: count;
+}
+
+static ssize_t con_drop_show(struct device_driver *dev, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", con3215_drop ? 1 : 0);
+}
+
+static DRIVER_ATTR_RW(con_drop);
+
+static struct attribute *con3215_drv_attrs[] = {
+ &driver_attr_con_drop.attr,
+ NULL,
+};
+
+static struct attribute_group con3215_drv_attr_group = {
+ .attrs = con3215_drv_attrs,
+ NULL,
+};
+
+static const struct attribute_group *con3215_drv_attr_groups[] = {
+ &con3215_drv_attr_group,
+ NULL,
+};
+
static struct ccw_driver raw3215_ccw_driver = {
.driver = {
.name = "3215",
+ .groups = con3215_drv_attr_groups,
.owner = THIS_MODULE,
},
.ids = raw3215_id,
@@ -736,34 +824,27 @@ static struct ccw_driver raw3215_ccw_driver = {
.int_class = IRQIO_C15,
};
-#ifdef CONFIG_TN3215_CONSOLE
-/*
- * Write a string to the 3215 console
- */
-static void con3215_write(struct console *co, const char *str,
- unsigned int count)
+static void handle_write(struct raw3215_info *raw, const char *str, int count)
{
- struct raw3215_info *raw;
int i;
- if (count <= 0)
- return;
- raw = raw3215[0]; /* console 3215 is the first one */
while (count > 0) {
- for (i = 0; i < count; i++)
- if (str[i] == '\t' || str[i] == '\n')
- break;
+ i = min_t(int, count, RAW3215_BUFFER_SIZE - 1);
raw3215_write(raw, str, i);
count -= i;
str += i;
- if (count > 0) {
- raw3215_putchar(raw, *str);
- count--;
- str++;
- }
}
}
+#ifdef CONFIG_TN3215_CONSOLE
+/*
+ * Write a string to the 3215 console
+ */
+static void con3215_write(struct console *co, const char *str, unsigned int count)
+{
+ handle_write(raw3215[0], str, count);
+}
+
static struct tty_driver *con3215_device(struct console *c, int *index)
{
*index = c->index;
@@ -787,7 +868,7 @@ static int con3215_notify(struct notifier_block *self,
raw = raw3215[0]; /* console 3215 is the first one */
if (!spin_trylock_irqsave(get_ccwdev_lock(raw->cdev), flags))
return NOTIFY_DONE;
- raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
+ raw3215_make_room(raw, RAW3215_BUFFER_SIZE, false);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
return NOTIFY_DONE;
@@ -940,27 +1021,11 @@ static unsigned int tty3215_write_room(struct tty_struct *tty)
/*
* String write routine for 3215 ttys
*/
-static int tty3215_write(struct tty_struct * tty,
+static int tty3215_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct raw3215_info *raw = tty->driver_data;
- int i, written;
-
- written = count;
- while (count > 0) {
- for (i = 0; i < count; i++)
- if (buf[i] == '\t' || buf[i] == '\n')
- break;
- raw3215_write(raw, buf, i);
- count -= i;
- buf += i;
- if (count > 0) {
- raw3215_putchar(raw, *buf);
- count--;
- buf++;
- }
- }
- return written;
+ handle_write(tty->driver_data, buf, count);
+ return count;
}
/*
@@ -1000,7 +1065,7 @@ static void tty3215_flush_buffer(struct tty_struct *tty)
/*
* Disable reading from a 3215 tty
*/
-static void tty3215_throttle(struct tty_struct * tty)
+static void tty3215_throttle(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
@@ -1010,7 +1075,7 @@ static void tty3215_throttle(struct tty_struct * tty)
/*
* Enable reading from a 3215 tty
*/
-static void tty3215_unthrottle(struct tty_struct * tty)
+static void tty3215_unthrottle(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
unsigned long flags;
@@ -1065,6 +1130,18 @@ static const struct tty_operations tty3215_ops = {
.start = tty3215_start,
};
+static int __init con3215_setup_drop(char *str)
+{
+ bool drop;
+ int rc;
+
+ rc = kstrtobool(str, &drop);
+ if (!rc)
+ con3215_drop = drop;
+ return rc;
+}
+early_param("con3215_drop", con3215_setup_drop);
+
/*
* 3215 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 4e2b3a1a3b2e..fb3f62ac8be4 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -111,12 +111,6 @@ static inline int raw3270_state_ready(struct raw3270 *rp)
return rp->state == RAW3270_STATE_READY;
}
-static inline int raw3270_state_final(struct raw3270 *rp)
-{
- return rp->state == RAW3270_STATE_INIT ||
- rp->state == RAW3270_STATE_READY;
-}
-
void
raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
{
@@ -749,6 +743,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
/* Tentative definition - see below for actual definition. */
static struct ccw_driver raw3270_ccw_driver;
+static inline int raw3270_state_final(struct raw3270 *rp)
+{
+ return rp->state == RAW3270_STATE_INIT ||
+ rp->state == RAW3270_STATE_READY;
+}
+
/*
* Setup 3270 device configured as console.
*/
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index ae1d6ee382a5..8f74db689a0c 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -69,7 +69,7 @@ static struct init_sccb *sclp_init_sccb;
/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
int sclp_console_pages = SCLP_CONSOLE_PAGES;
/* Flag to indicate if buffer pages are dropped on buffer full condition */
-int sclp_console_drop = 1;
+bool sclp_console_drop = true;
/* Number of times the console dropped buffer pages */
unsigned long sclp_console_full;
@@ -195,12 +195,7 @@ __setup("sclp_con_pages=", sclp_setup_console_pages);
static int __init sclp_setup_console_drop(char *str)
{
- int drop, rc;
-
- rc = kstrtoint(str, 0, &drop);
- if (!rc)
- sclp_console_drop = drop;
- return 1;
+ return kstrtobool(str, &sclp_console_drop) == 0;
}
__setup("sclp_con_drop=", sclp_setup_console_drop);
@@ -1205,21 +1200,29 @@ static struct notifier_block sclp_reboot_notifier = {
static ssize_t con_pages_show(struct device_driver *dev, char *buf)
{
- return sprintf(buf, "%i\n", sclp_console_pages);
+ return sysfs_emit(buf, "%i\n", sclp_console_pages);
}
static DRIVER_ATTR_RO(con_pages);
+static ssize_t con_drop_store(struct device_driver *dev, const char *buf, size_t count)
+{
+ int rc;
+
+ rc = kstrtobool(buf, &sclp_console_drop);
+ return rc ?: count;
+}
+
static ssize_t con_drop_show(struct device_driver *dev, char *buf)
{
- return sprintf(buf, "%i\n", sclp_console_drop);
+ return sysfs_emit(buf, "%i\n", sclp_console_drop);
}
-static DRIVER_ATTR_RO(con_drop);
+static DRIVER_ATTR_RW(con_drop);
static ssize_t con_full_show(struct device_driver *dev, char *buf)
{
- return sprintf(buf, "%lu\n", sclp_console_full);
+ return sysfs_emit(buf, "%lu\n", sclp_console_full);
}
static DRIVER_ATTR_RO(con_full);
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 86dd2cde0f78..909ba7f08688 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -307,7 +307,7 @@ enum {
extern int sclp_init_state;
extern int sclp_console_pages;
-extern int sclp_console_drop;
+extern bool sclp_console_drop;
extern unsigned long sclp_console_full;
extern bool sclp_mask_compat_mode;
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index d15b0d541de3..c1c70a161c0e 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -57,8 +57,10 @@ static void __init sclp_early_facilities_detect(void)
sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
}
- if (sccb->cpuoff > 137)
+ if (sccb->cpuoff > 137) {
sclp.has_sipl = !!(sccb->cbl & 0x4000);
+ sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000);
+ }
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp.rzm <<= 20;
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c
index 676634de65a8..ac1d00980fa6 100644
--- a/drivers/s390/char/sclp_early_core.c
+++ b/drivers/s390/char/sclp_early_core.c
@@ -17,7 +17,7 @@
static struct read_info_sccb __bootdata(sclp_info_sccb);
static int __bootdata(sclp_info_sccb_valid);
-char *__bootdata(sclp_early_sccb);
+char *__bootdata_preserved(sclp_early_sccb);
int sclp_init_state = sclp_init_state_uninitialized;
/*
* Used to keep track of the size of the event masks. Qemu until version 2.11
@@ -241,6 +241,30 @@ void sclp_early_printk(const char *str)
}
/*
+ * Use sclp_emergency_printk() to print a string when the system is in a
+ * state where regular console drivers cannot be assumed to work anymore.
+ *
+ * Callers must make sure that no concurrent SCLP requests are outstanding
+ * and all other CPUs are stopped, or at least disabled for external
+ * interrupts.
+ */
+void sclp_emergency_printk(const char *str)
+{
+ int have_linemode, have_vt220;
+ unsigned int len;
+
+ len = strlen(str);
+ /*
+ * Don't care about return values; if requests fail, just ignore and
+ * continue to have a rather high chance that anything is printed.
+ */
+ sclp_early_setup(0, &have_linemode, &have_vt220);
+ sclp_early_print_lm(str, len);
+ sclp_early_print_vt220(str, len);
+ sclp_early_setup(1, &have_linemode, &have_vt220);
+}
+
+/*
* We can't pass sclp_info_sccb to sclp_early_cmd() here directly,
* because it might not fulfil the requiremets for a SCLP communication buffer:
* - lie below 2G in memory
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 6165e6aae762..599f547310f8 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -103,7 +103,7 @@ static inline int memcpy_hsa_kernel(void *dst, unsigned long src, size_t count)
kvec.iov_base = dst;
kvec.iov_len = count;
- iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
if (memcpy_hsa_iter(&iter, src, count) < count)
return -EIO;
return 0;
@@ -282,6 +282,10 @@ static int __init zcore_init(void)
TRACE("type: nvme\n");
TRACE("fid: %x\n", ipl_info.data.nvme.fid);
TRACE("nsid: %x\n", ipl_info.data.nvme.nsid);
+ } else if (ipl_info.type == IPL_TYPE_ECKD_DUMP) {
+ TRACE("type: eckd\n");
+ TRACE("devno: %x\n", ipl_info.data.eckd.dev_id.devno);
+ TRACE("ssid: %x\n", ipl_info.data.eckd.dev_id.ssid);
}
rc = sclp_sdias_init();
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 962dfa25a310..180ab899289c 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/device.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
@@ -85,7 +86,7 @@ static int chsc_subchannel_probe(struct subchannel *sch)
if (!private)
return -ENOMEM;
dev_set_drvdata(&sch->dev, private);
- ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+ ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
if (ret) {
CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
sch->schid.ssid, sch->schid.sch_no, ret);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 923f5ca4f5e6..6127add746d1 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -134,7 +134,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
memset(orb, 0, sizeof(union orb));
/* sch is always under 2G. */
- orb->cmd.intparm = (u32)(addr_t)sch;
+ orb->cmd.intparm = (u32)virt_to_phys(sch);
orb->cmd.fmt = 1;
orb->cmd.pfch = priv->options.prefetch == 0;
@@ -148,7 +148,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
orb->cmd.i2k = 0;
orb->cmd.key = key >> 4;
/* issue "Start Subchannel" */
- orb->cmd.cpa = (__u32) __pa(cpa);
+ orb->cmd.cpa = (u32)virt_to_phys(cpa);
ccode = ssch(sch->schid, orb);
/* process condition code */
@@ -539,13 +539,13 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
tpi_info = &get_irq_regs()->tpi_info;
trace_s390_cio_interrupt(tpi_info);
irb = this_cpu_ptr(&cio_irb);
- sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
- if (!sch) {
+ if (!tpi_info->intparm) {
/* Clear pending interrupt condition. */
inc_irq_stat(IRQIO_CIO);
tsch(tpi_info->schid, irb);
return IRQ_HANDLED;
}
+ sch = phys_to_virt(tpi_info->intparm);
spin_lock(sch->lock);
/* Store interrupt response block to lowcore. */
if (tsch(tpi_info->schid, irb) == 0) {
@@ -666,7 +666,7 @@ struct subchannel *cio_probe_console(void)
lockdep_set_class(sch->lock, &console_sch_key);
isc_register(CONSOLE_ISC);
sch->config.isc = CONSOLE_ISC;
- sch->config.intparm = (u32)(addr_t)sch;
+ sch->config.intparm = (u32)virt_to_phys(sch);
ret = cio_commit_config(sch);
if (ret) {
isc_unregister(CONSOLE_ISC);
@@ -713,11 +713,11 @@ int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
union orb *orb = &to_io_private(sch)->orb;
memset(orb, 0, sizeof(union orb));
- orb->tm.intparm = (u32) (addr_t) sch;
+ orb->tm.intparm = (u32)virt_to_phys(sch);
orb->tm.key = key >> 4;
orb->tm.b = 1;
orb->tm.lpm = lpm ? lpm : sch->lpm;
- orb->tm.tcw = (u32) (addr_t) tcw;
+ orb->tm.tcw = (u32)virt_to_phys(tcw);
cc = ssch(sch->schid, orb);
switch (cc) {
case 0:
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 3b1cd0c96a74..9e0cf44ff9d4 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -936,7 +936,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
if (old_enabled) {
/* Try to reenable the old subchannel. */
spin_lock_irq(old_sch->lock);
- cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch);
+ cio_enable_subchannel(old_sch, (u32)virt_to_phys(old_sch));
spin_unlock_irq(old_sch->lock);
}
/* Release child reference for new parent. */
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 6d63b968309a..2b2058427a2b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/string.h>
@@ -63,7 +64,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
printk(KERN_WARNING "cio: orb indicates transport mode\n");
printk(KERN_WARNING "cio: last tcw:\n");
print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
- (void *)(addr_t)orb->tm.tcw,
+ phys_to_virt(orb->tm.tcw),
sizeof(struct tcw), 0);
} else {
printk(KERN_WARNING "cio: orb indicates command mode\n");
@@ -77,7 +78,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
printk(KERN_WARNING "cio: last channel program:\n");
print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
- (void *)(addr_t)orb->cmd.cpa,
+ phys_to_virt(orb->cmd.cpa),
sizeof(struct ccw1), 0);
}
printk(KERN_WARNING "cio: ccw device state: %d\n",
@@ -397,7 +398,7 @@ void ccw_device_recognition(struct ccw_device *cdev)
*/
cdev->private->flags.recog_done = 0;
cdev->private->state = DEV_STATE_SENSE_ID;
- if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) {
+ if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch))) {
ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
return;
}
@@ -548,7 +549,7 @@ ccw_device_online(struct ccw_device *cdev)
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
- ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
if (ret != 0) {
/* Couldn't enable the subchannel for i/o. Sick device. */
if (ret == -ENODEV)
@@ -691,7 +692,7 @@ static void ccw_device_boxed_verify(struct ccw_device *cdev,
struct subchannel *sch = to_subchannel(cdev->dev.parent);
if (cdev->online) {
- if (cio_enable_subchannel(sch, (u32) (addr_t) sch))
+ if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)))
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
else
ccw_device_online_verify(cdev, dev_event);
@@ -922,7 +923,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
+ if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)) != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return;
cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID;
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 7835a87a60b5..ce99ee2457e6 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -210,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev)
snsid_init(cdev);
/* Channel program setup. */
cp->cmd_code = CCW_CMD_SENSE_ID;
- cp->cda = (u32) (addr_t) &cdev->private->dma_area->senseid;
+ cp->cda = (u32)virt_to_phys(&cdev->private->dma_area->senseid);
cp->count = sizeof(struct senseid);
cp->flags = CCW_FLAG_SLI;
/* Request setup. */
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 767a85635a0f..3862961697eb 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -140,7 +141,7 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn)
pgid->inf.fc = fn;
cp->cmd_code = CCW_CMD_SET_PGID;
- cp->cda = (u32) (addr_t) pgid;
+ cp->cda = (u32)virt_to_phys(pgid);
cp->count = sizeof(*pgid);
cp->flags = CCW_FLAG_SLI;
req->cp = cp;
@@ -441,7 +442,7 @@ static void snid_build_cp(struct ccw_device *cdev)
/* Channel program setup. */
cp->cmd_code = CCW_CMD_SENSE_PGID;
- cp->cda = (u32) (addr_t) &cdev->private->dma_area->pgid[i];
+ cp->cda = (u32)virt_to_phys(&cdev->private->dma_area->pgid[i]);
cp->count = sizeof(struct pgid);
cp->flags = CCW_FLAG_SLI;
req->cp = cp;
@@ -631,11 +632,11 @@ static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
struct ccw1 *cp = cdev->private->dma_area->iccws;
cp[0].cmd_code = CCW_CMD_STLCK;
- cp[0].cda = (u32) (addr_t) buf1;
+ cp[0].cda = (u32)virt_to_phys(buf1);
cp[0].count = 32;
cp[0].flags = CCW_FLAG_CC;
cp[1].cmd_code = CCW_CMD_RELEASE;
- cp[1].cda = (u32) (addr_t) buf2;
+ cp[1].cda = (u32)virt_to_phys(buf2);
cp[1].count = 32;
cp[1].flags = 0;
req->cp = cp;
@@ -698,7 +699,7 @@ int ccw_device_stlck(struct ccw_device *cdev)
init_completion(&data.done);
data.rc = -EIO;
spin_lock_irq(sch->lock);
- rc = cio_enable_subchannel(sch, (u32) (addr_t) sch);
+ rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
if (rc)
goto out_unlock;
/* Perform operation. */
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 0bd8f2642732..6c2e35065fec 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -331,7 +332,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
*/
sense_ccw = &to_io_private(sch)->dma_area->sense_ccw;
sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw);
+ sense_ccw->cda = virt_to_phys(cdev->private->dma_area->irb.ecw);
sense_ccw->count = SENSE_MAX_COUNT;
sense_ccw->flags = CCW_FLAG_SLI;
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c
index ab6a7495180a..826364d2facd 100644
--- a/drivers/s390/cio/eadm_sch.c
+++ b/drivers/s390/cio/eadm_sch.c
@@ -15,6 +15,7 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/list.h>
+#include <linux/io.h>
#include <asm/css_chars.h>
#include <asm/debug.h>
@@ -62,8 +63,8 @@ static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
int cc;
orb_init(orb);
- orb->eadm.aob = (u32)__pa(aob);
- orb->eadm.intparm = (u32)(addr_t)sch;
+ orb->eadm.aob = (u32)virt_to_phys(aob);
+ orb->eadm.intparm = (u32)virt_to_phys(sch);
orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
EADM_LOG(6, "start");
@@ -146,7 +147,7 @@ static void eadm_subchannel_irq(struct subchannel *sch)
css_sched_sch_todo(sch, SCH_TODO_EVAL);
return;
}
- scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
+ scm_irq_handler(phys_to_virt(scsw->aob), error);
private->state = EADM_IDLE;
if (private->completion)
@@ -225,7 +226,7 @@ static int eadm_subchannel_probe(struct subchannel *sch)
private->state = EADM_IDLE;
private->sch = sch;
sch->isc = EADM_SCH_ISC;
- ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+ ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
if (ret) {
set_eadm_private(sch, NULL);
spin_unlock_irq(sch->lock);
diff --git a/drivers/s390/cio/fcx.c b/drivers/s390/cio/fcx.c
index 99c900cc3e5b..84f24a2f46e4 100644
--- a/drivers/s390/cio/fcx.c
+++ b/drivers/s390/cio/fcx.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/io.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -24,7 +25,7 @@
*/
struct tcw *tcw_get_intrg(struct tcw *tcw)
{
- return (struct tcw *) ((addr_t) tcw->intrg);
+ return phys_to_virt(tcw->intrg);
}
EXPORT_SYMBOL(tcw_get_intrg);
@@ -39,9 +40,9 @@ EXPORT_SYMBOL(tcw_get_intrg);
void *tcw_get_data(struct tcw *tcw)
{
if (tcw->r)
- return (void *) ((addr_t) tcw->input);
+ return phys_to_virt(tcw->input);
if (tcw->w)
- return (void *) ((addr_t) tcw->output);
+ return phys_to_virt(tcw->output);
return NULL;
}
EXPORT_SYMBOL(tcw_get_data);
@@ -54,7 +55,7 @@ EXPORT_SYMBOL(tcw_get_data);
*/
struct tccb *tcw_get_tccb(struct tcw *tcw)
{
- return (struct tccb *) ((addr_t) tcw->tccb);
+ return phys_to_virt(tcw->tccb);
}
EXPORT_SYMBOL(tcw_get_tccb);
@@ -66,7 +67,7 @@ EXPORT_SYMBOL(tcw_get_tccb);
*/
struct tsb *tcw_get_tsb(struct tcw *tcw)
{
- return (struct tsb *) ((addr_t) tcw->tsb);
+ return phys_to_virt(tcw->tsb);
}
EXPORT_SYMBOL(tcw_get_tsb);
@@ -189,7 +190,7 @@ EXPORT_SYMBOL(tcw_finalize);
*/
void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
{
- tcw->intrg = (u32) ((addr_t) intrg_tcw);
+ tcw->intrg = (u32)virt_to_phys(intrg_tcw);
}
EXPORT_SYMBOL(tcw_set_intrg);
@@ -207,11 +208,11 @@ EXPORT_SYMBOL(tcw_set_intrg);
void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
{
if (tcw->r) {
- tcw->input = (u64) ((addr_t) data);
+ tcw->input = virt_to_phys(data);
if (use_tidal)
tcw->flags |= TCW_FLAGS_INPUT_TIDA;
} else if (tcw->w) {
- tcw->output = (u64) ((addr_t) data);
+ tcw->output = virt_to_phys(data);
if (use_tidal)
tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
}
@@ -227,7 +228,7 @@ EXPORT_SYMBOL(tcw_set_data);
*/
void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
{
- tcw->tccb = (u64) ((addr_t) tccb);
+ tcw->tccb = virt_to_phys(tccb);
}
EXPORT_SYMBOL(tcw_set_tccb);
@@ -240,7 +241,7 @@ EXPORT_SYMBOL(tcw_set_tccb);
*/
void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
{
- tcw->tsb = (u64) ((addr_t) tsb);
+ tcw->tsb = virt_to_phys(tsb);
}
EXPORT_SYMBOL(tcw_set_tsb);
@@ -345,7 +346,7 @@ struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
memset(tidaw, 0, sizeof(struct tidaw));
tidaw->flags = flags;
tidaw->count = count;
- tidaw->addr = (u64) ((addr_t) addr);
+ tidaw->addr = virt_to_phys(addr);
return tidaw;
}
EXPORT_SYMBOL(tcw_add_tidaw);
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
index 19e46363348c..dbd3099c520e 100644
--- a/drivers/s390/cio/itcw.c
+++ b/drivers/s390/cio/itcw.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/io.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -187,7 +188,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
/* Check for 2G limit. */
start = (addr_t) buffer;
end = start + size;
- if (end > (1 << 31))
+ if ((virt_to_phys(buffer) + size) > (1 << 31))
return ERR_PTR(-EINVAL);
memset(buffer, 0, size);
/* ITCW. */
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 7b02e97f4b29..c0a09fa8991a 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -394,7 +394,7 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
if (ccw_is_tic(ccw))
return;
- kfree((void *)(u64)ccw->cda);
+ kfree(phys_to_virt(ccw->cda));
}
/**
@@ -845,7 +845,7 @@ union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm)
chain = list_first_entry(&cp->ccwchain_list, struct ccwchain, next);
cpa = chain->ch_ccw;
- orb->cmd.cpa = (__u32) __pa(cpa);
+ orb->cmd.cpa = (__u32)virt_to_phys(cpa);
return orb;
}
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index a59c758869f8..0a5e8b4a6743 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -29,7 +29,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private)
spin_lock_irqsave(sch->lock, flags);
- orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm);
+ orb = cp_get_orb(&private->cp, (u32)virt_to_phys(sch), sch->lpm);
if (!orb) {
ret = -EIO;
goto out;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 59ac98f2bd27..b02c631f3b71 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -233,8 +233,11 @@ static void __init ap_init_qci_info(void)
if (!ap_qci_info)
return;
ap_qci_info_old = kzalloc(sizeof(*ap_qci_info_old), GFP_KERNEL);
- if (!ap_qci_info_old)
+ if (!ap_qci_info_old) {
+ kfree(ap_qci_info);
+ ap_qci_info = NULL;
return;
+ }
if (ap_fetch_qci_info(ap_qci_info) != 0) {
kfree(ap_qci_info);
kfree(ap_qci_info_old);
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 8fb34b8eeb18..5ad251477593 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -342,7 +342,10 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
};
struct {
struct type6_hdr hdr;
- struct CPRBX cprbx;
+ union {
+ struct CPRBX cprbx;
+ DECLARE_FLEX_ARRAY(u8, userdata);
+ };
} __packed * msg = ap_msg->msg;
int rcblen = CEIL4(xcrb->request_control_blk_length);
@@ -403,7 +406,8 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
msg->hdr.fromcardlen2 = xcrb->reply_data_length;
/* prepare CPRB */
- if (z_copy_from_user(userspace, &msg->cprbx, xcrb->request_control_blk_addr,
+ if (z_copy_from_user(userspace, msg->userdata,
+ xcrb->request_control_blk_addr,
xcrb->request_control_blk_length))
return -EFAULT;
if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
@@ -469,9 +473,14 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap
struct {
struct type6_hdr hdr;
- struct ep11_cprb cprbx;
- unsigned char pld_tag; /* fixed value 0x30 */
- unsigned char pld_lenfmt; /* payload length format */
+ union {
+ struct {
+ struct ep11_cprb cprbx;
+ unsigned char pld_tag; /* fixed value 0x30 */
+ unsigned char pld_lenfmt; /* length format */
+ } __packed;
+ DECLARE_FLEX_ARRAY(u8, userdata);
+ };
} __packed * msg = ap_msg->msg;
struct pld_hdr {
@@ -500,7 +509,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap
msg->hdr.fromcardlen1 = xcrb->resp_len;
/* Import CPRB data from the ioctl input parameter */
- if (z_copy_from_user(userspace, &msg->cprbx.cprb_len,
+ if (z_copy_from_user(userspace, msg->userdata,
(char __force __user *)xcrb->req, xcrb->req_len)) {
return -EFAULT;
}
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index d34bb6ec1490..dfd401d9e362 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -243,7 +243,8 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
dmb->cpu_addr = dma_alloc_coherent(&ism->pdev->dev, dmb->dmb_len,
&dmb->dma_addr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC | __GFP_COMP | __GFP_NORETRY);
+ GFP_KERNEL | __GFP_NOWARN |
+ __GFP_NOMEMALLOC | __GFP_NORETRY);
if (!dmb->cpu_addr)
clear_bit(dmb->sba_idx, ism->sba_bitmap);
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 9dc935886e9f..c6ded3fdd715 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -758,7 +758,6 @@ static void qeth_l2_br2dev_worker(struct work_struct *work)
struct list_head *iter;
int err = 0;
- kfree(br2dev_event_work);
QETH_CARD_TEXT_(card, 4, "b2dw%04lx", event);
QETH_CARD_TEXT_(card, 4, "ma%012llx", ether_addr_to_u64(addr));
@@ -815,6 +814,7 @@ unlock:
dev_put(brdev);
dev_put(lsyncdev);
dev_put(dstdev);
+ kfree(br2dev_event_work);
}
static int qeth_l2_br2dev_queue_work(struct net_device *brdev,
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 77917b339870..f21307537829 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -48,7 +48,7 @@ unsigned int zfcp_fc_port_scan_backoff(void)
{
if (!port_scan_backoff)
return 0;
- return prandom_u32_max(port_scan_backoff);
+ return get_random_u32_below(port_scan_backoff);
}
static void zfcp_fc_port_scan_time(struct zfcp_adapter *adapter)
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 19223b075568..ab3ea529cca7 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -884,7 +884,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
const bool is_srb = zfcp_fsf_req_is_status_read_buffer(req);
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
- int req_id = req->req_id;
+ unsigned long req_id = req->req_id;
zfcp_reqlist_add(adapter->req_list, req);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 843e830b5f87..ea914a7eaa7f 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -363,8 +363,8 @@ static int envctrl_read_cpu_info(int cpu, struct i2c_child_t *pchild,
char mon_type, unsigned char *bufdata)
{
unsigned char data;
- int i;
- char *tbl, j = -1;
+ int i, j = -1;
+ char *tbl;
/* Find the right monitor type and channel. */
for (i = 0; i < PCF8584_MAX_CHANNELS; i++) {
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index ddc048069af2..5c8d1ba3f8f3 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2233,7 +2233,7 @@ static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
fip->probe_tries++;
- wait = prandom_u32_max(FIP_VN_PROBE_WAIT);
+ wait = get_random_u32_below(FIP_VN_PROBE_WAIT);
} else
wait = FIP_VN_RLIM_INT;
mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
@@ -3125,7 +3125,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
fcoe_all_vn2vn, 0);
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_BEACON_INT +
- prandom_u32_max(FIP_VN_BEACON_FUZZ));
+ get_random_u32_below(FIP_VN_BEACON_FUZZ));
}
if (time_before(fip->port_ka_time, next_time))
next_time = fip->port_ka_time;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 00684e11976b..1a0c0b7289d2 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -708,8 +708,13 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost)
memset(vhost->async_crq.msgs.async, 0, PAGE_SIZE);
vhost->async_crq.cur = 0;
- list_for_each_entry(tgt, &vhost->targets, queue)
- ibmvfc_del_tgt(tgt);
+ list_for_each_entry(tgt, &vhost->targets, queue) {
+ if (vhost->client_migrated)
+ tgt->need_login = 1;
+ else
+ ibmvfc_del_tgt(tgt);
+ }
+
scsi_block_requests(vhost->host);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
vhost->job_step = ibmvfc_npiv_login;
@@ -3235,9 +3240,12 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost,
/* We need to re-setup the interpartition connection */
dev_info(vhost->dev, "Partition migrated, Re-enabling adapter\n");
vhost->client_migrated = 1;
+
+ scsi_block_requests(vhost->host);
ibmvfc_purge_requests(vhost, DID_REQUEUE);
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_state(vhost, IBMVFC_LINK_DOWN);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
+ wake_up(&vhost->work_wait_q);
} else if (crq->format == IBMVFC_PARTNER_FAILED || crq->format == IBMVFC_PARTNER_DEREGISTER) {
dev_err(vhost->dev, "Host partner adapter deregistered or failed (rc=%d)\n", crq->format);
ibmvfc_purge_requests(vhost, DID_ERROR);
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d35c9296f738..5692577f82e3 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -101,7 +101,7 @@ static void sas_ata_task_done(struct sas_task *task)
spin_lock_irqsave(ap->lock, flags);
/* check if we lost the race with libata/sas_ata_post_internal() */
- if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) {
+ if (unlikely(ata_port_is_frozen(ap))) {
spin_unlock_irqrestore(ap->lock, flags);
if (qc->scsicmd)
goto qc_already_gone;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index f77ee4051b00..3306de7170f6 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -3265,7 +3265,8 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
}
if (scmd->result != (DID_OK << 16) && (scmd->cmnd[0] != ATA_12) &&
- (scmd->cmnd[0] != ATA_16)) {
+ (scmd->cmnd[0] != ATA_16) &&
+ mrioc->logging_level & MPI3_DEBUG_SCSI_ERROR) {
ioc_info(mrioc, "%s :scmd->result 0x%x\n", __func__,
scmd->result);
scsi_print_command(scmd);
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index df2fe7bd26d1..f2ee49756df8 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -618,7 +618,7 @@ static int qedi_cm_alloc_mem(struct qedi_ctx *qedi)
sizeof(struct qedi_endpoint *)), GFP_KERNEL);
if (!qedi->ep_tbl)
return -ENOMEM;
- port_id = prandom_u32_max(QEDI_LOCAL_PORT_RANGE);
+ port_id = get_random_u32_below(QEDI_LOCAL_PORT_RANGE);
if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE,
QEDI_LOCAL_PORT_MIN, port_id)) {
qedi_cm_free_mem(qedi);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 697fc57bc711..a0797101a8a0 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1899,6 +1899,13 @@ static int resp_readcap16(struct scsi_cmnd *scp,
arr[14] |= 0x40;
}
+ /*
+ * Since the scsi_debug READ CAPACITY implementation always reports the
+ * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
+ */
+ if (devip->zmodel == BLK_ZONED_HM)
+ arr[12] |= 1 << 4;
+
arr[15] = sdebug_lowest_aligned & 0xff;
if (have_dif_prot) {
@@ -5695,16 +5702,16 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
u64 ns = jiffies_to_nsecs(delta_jiff);
if (sdebug_random && ns < U32_MAX) {
- ns = prandom_u32_max((u32)ns);
+ ns = get_random_u32_below((u32)ns);
} else if (sdebug_random) {
ns >>= 12; /* scale to 4 usec precision */
if (ns < U32_MAX) /* over 4 hours max */
- ns = prandom_u32_max((u32)ns);
+ ns = get_random_u32_below((u32)ns);
ns <<= 12;
}
kt = ns_to_ktime(ns);
} else { /* ndelay has a 4.2 second max */
- kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
+ kt = sdebug_random ? get_random_u32_below((u32)ndelay) :
(u32)ndelay;
if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
u64 d = ktime_get_boottime_ns() - ns_from_boot;
@@ -7316,8 +7323,12 @@ static int sdebug_add_host_helper(int per_host_idx)
dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
error = device_register(&sdbg_host->dev);
- if (error)
+ if (error) {
+ spin_lock(&sdebug_host_list_lock);
+ list_del(&sdbg_host->host_list);
+ spin_unlock(&sdebug_host_list_lock);
goto clean;
+ }
++sdebug_num_hosts;
return 0;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 6995c8979230..ac5ff0783b4f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -312,7 +312,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
* Ensure that all tasks observe the host state change before the
* host_failed change.
*/
- call_rcu(&scmd->rcu, scsi_eh_inc_host_failed);
+ call_rcu_hurry(&scmd->rcu, scsi_eh_inc_host_failed);
}
/**
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 8b89fab7c420..249757ddd8fe 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2735,7 +2735,7 @@ static void scsi_stop_queue(struct scsi_device *sdev, bool nowait)
blk_mq_quiesce_queue(sdev->request_queue);
} else {
if (!nowait)
- blk_mq_wait_quiesce_done(sdev->request_queue);
+ blk_mq_wait_quiesce_done(sdev->request_queue->tag_set);
}
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 5d27f5196de6..0a95fa787fdf 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -344,7 +344,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
sdev->request_queue = q;
q->queuedata = sdev;
__scsi_init_queue(sdev->host, q);
- WARN_ON_ONCE(!blk_get_queue(q));
depth = sdev->host->cmd_per_lun ?: 1;
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index cd3db9684e52..f473c002fa4d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -231,7 +231,7 @@ iscsi_create_endpoint(int dd_size)
dev_set_name(&ep->dev, "ep-%d", id);
err = device_register(&ep->dev);
if (err)
- goto free_id;
+ goto put_dev;
err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
if (err)
@@ -245,10 +245,12 @@ unregister_dev:
device_unregister(&ep->dev);
return NULL;
-free_id:
+put_dev:
mutex_lock(&iscsi_ep_idr_mutex);
idr_remove(&iscsi_ep_idr, id);
mutex_unlock(&iscsi_ep_idr_mutex);
+ put_device(&ep->dev);
+ return NULL;
free_ep:
kfree(ep);
return NULL;
@@ -766,7 +768,7 @@ iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport,
err = device_register(&iface->dev);
if (err)
- goto free_iface;
+ goto put_dev;
err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group);
if (err)
@@ -780,9 +782,8 @@ unreg_iface:
device_unregister(&iface->dev);
return NULL;
-free_iface:
- put_device(iface->dev.parent);
- kfree(iface);
+put_dev:
+ put_device(&iface->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_create_iface);
@@ -1251,15 +1252,15 @@ iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
err = device_register(&fnode_sess->dev);
if (err)
- goto free_fnode_sess;
+ goto put_dev;
if (dd_size)
fnode_sess->dd_data = &fnode_sess[1];
return fnode_sess;
-free_fnode_sess:
- kfree(fnode_sess);
+put_dev:
+ put_device(&fnode_sess->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_create_flashnode_sess);
@@ -1299,15 +1300,15 @@ iscsi_create_flashnode_conn(struct Scsi_Host *shost,
err = device_register(&fnode_conn->dev);
if (err)
- goto free_fnode_conn;
+ goto put_dev;
if (dd_size)
fnode_conn->dd_data = &fnode_conn[1];
return fnode_conn;
-free_fnode_conn:
- kfree(fnode_conn);
+put_dev:
+ put_device(&fnode_conn->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_create_flashnode_conn);
@@ -4815,7 +4816,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
dev_set_name(&priv->dev, "%s", tt->name);
err = device_register(&priv->dev);
if (err)
- goto free_priv;
+ goto put_dev;
err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
if (err)
@@ -4850,8 +4851,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
unregister_dev:
device_unregister(&priv->dev);
return NULL;
-free_priv:
- kfree(priv);
+put_dev:
+ put_device(&priv->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_register_transport);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 2f88c61216ee..74b99f2b0b74 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -722,12 +722,17 @@ int sas_phy_add(struct sas_phy *phy)
int error;
error = device_add(&phy->dev);
- if (!error) {
- transport_add_device(&phy->dev);
- transport_configure_device(&phy->dev);
+ if (error)
+ return error;
+
+ error = transport_add_device(&phy->dev);
+ if (error) {
+ device_del(&phy->dev);
+ return error;
}
+ transport_configure_device(&phy->dev);
- return error;
+ return 0;
}
EXPORT_SYMBOL(sas_phy_add);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ce34a8ad53b4..12344be14232 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1726,7 +1726,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
Sg_scatter_hold *rsv_schp = &sfp->reserve;
struct request_queue *q = sfp->parentdp->device->request_queue;
struct rq_map_data *md, map_data;
- int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
+ int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? ITER_SOURCE : ITER_DEST;
struct scsi_cmnd *scmd;
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index bc46721aa01c..3c5b7e4227b2 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -303,16 +303,21 @@ enum storvsc_request_type {
};
/*
- * SRB status codes and masks; a subset of the codes used here.
+ * SRB status codes and masks. In the 8-bit field, the two high order bits
+ * are flags, while the remaining 6 bits are an integer status code. The
+ * definitions here include only the subset of the integer status codes that
+ * are tested for in this driver.
*/
-
#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_DATA_OVERRUN 0x12
+
+/* SRB status integer codes */
+#define SRB_STATUS_SUCCESS 0x01
+#define SRB_STATUS_ABORTED 0x02
+#define SRB_STATUS_ERROR 0x04
+#define SRB_STATUS_INVALID_REQUEST 0x06
+#define SRB_STATUS_DATA_OVERRUN 0x12
+#define SRB_STATUS_INVALID_LUN 0x20
#define SRB_STATUS(status) \
(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
@@ -969,38 +974,25 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
void (*process_err_fn)(struct work_struct *work);
struct hv_host_device *host_dev = shost_priv(host);
- /*
- * In some situations, Hyper-V sets multiple bits in the
- * srb_status, such as ABORTED and ERROR. So process them
- * individually, with the most specific bits first.
- */
-
- if (vm_srb->srb_status & SRB_STATUS_INVALID_LUN) {
- set_host_byte(scmnd, DID_NO_CONNECT);
- process_err_fn = storvsc_remove_lun;
- goto do_work;
- }
+ switch (SRB_STATUS(vm_srb->srb_status)) {
+ case SRB_STATUS_ERROR:
+ case SRB_STATUS_ABORTED:
+ case SRB_STATUS_INVALID_REQUEST:
+ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) {
+ /* Check for capacity change */
+ if ((asc == 0x2a) && (ascq == 0x9)) {
+ process_err_fn = storvsc_device_scan;
+ /* Retry the I/O that triggered this. */
+ set_host_byte(scmnd, DID_REQUEUE);
+ goto do_work;
+ }
- if (vm_srb->srb_status & SRB_STATUS_ABORTED) {
- if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
- /* Capacity data has changed */
- (asc == 0x2a) && (ascq == 0x9)) {
- process_err_fn = storvsc_device_scan;
/*
- * Retry the I/O that triggered this.
+ * Otherwise, let upper layer deal with the
+ * error when sense message is present
*/
- set_host_byte(scmnd, DID_REQUEUE);
- goto do_work;
- }
- }
-
- if (vm_srb->srb_status & SRB_STATUS_ERROR) {
- /*
- * Let upper layer deal with error when
- * sense message is present.
- */
- if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
return;
+ }
/*
* If there is an error; offline the device since all
@@ -1023,6 +1015,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
default:
set_host_byte(scmnd, DID_ERROR);
}
+ return;
+
+ case SRB_STATUS_INVALID_LUN:
+ set_host_byte(scmnd, DID_NO_CONNECT);
+ process_err_fn = storvsc_remove_lun;
+ goto do_work;
+
}
return;
diff --git a/drivers/siox/siox-core.c b/drivers/siox/siox-core.c
index 7c4f32d76966..561408583b2b 100644
--- a/drivers/siox/siox-core.c
+++ b/drivers/siox/siox-core.c
@@ -839,6 +839,8 @@ static struct siox_device *siox_device_add(struct siox_master *smaster,
err_device_register:
/* don't care to make the buffer smaller again */
+ put_device(&sdevice->dev);
+ sdevice = NULL;
err_buf_alloc:
siox_master_unlock(smaster);
diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig
index 2ed821f75816..a0fdf9d792cb 100644
--- a/drivers/slimbus/Kconfig
+++ b/drivers/slimbus/Kconfig
@@ -23,7 +23,7 @@ config SLIM_QCOM_CTRL
config SLIM_QCOM_NGD_CTRL
tristate "Qualcomm SLIMbus Satellite Non-Generic Device Component"
depends on HAS_IOMEM && DMA_ENGINE && NET
- depends on QCOM_RPROC_COMMON || COMPILE_TEST
+ depends on QCOM_RPROC_COMMON || (COMPILE_TEST && !QCOM_RPROC_COMMON)
depends on ARCH_QCOM || COMPILE_TEST
select QCOM_QMI_HELPERS
select QCOM_PDR_HELPERS
diff --git a/drivers/slimbus/stream.c b/drivers/slimbus/stream.c
index 75f87b3d8b95..73a2aa362957 100644
--- a/drivers/slimbus/stream.c
+++ b/drivers/slimbus/stream.c
@@ -67,10 +67,10 @@ static const int slim_presence_rate_table[] = {
384000,
768000,
0, /* Reserved */
- 110250,
- 220500,
- 441000,
- 882000,
+ 11025,
+ 22050,
+ 44100,
+ 88200,
176400,
352800,
705600,
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index e461c071189b..5dbb09f843f7 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -13,6 +13,7 @@ source "drivers/soc/fujitsu/Kconfig"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig"
source "drivers/soc/litex/Kconfig"
+source "drivers/soc/loongson/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/microchip/Kconfig"
source "drivers/soc/pxa/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 69ba6508cf2c..fff513bd522d 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -18,6 +18,7 @@ obj-y += imx/
obj-y += ixp4xx/
obj-$(CONFIG_SOC_XWAY) += lantiq/
obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
+obj-y += loongson/
obj-y += mediatek/
obj-y += microchip/
obj-y += pxa/
diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
index 031ec4aa06d5..8ec74d7539eb 100644
--- a/drivers/soc/apple/rtkit.c
+++ b/drivers/soc/apple/rtkit.c
@@ -926,8 +926,10 @@ int apple_rtkit_wake(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_wake);
-static void apple_rtkit_free(struct apple_rtkit *rtk)
+static void apple_rtkit_free(void *data)
{
+ struct apple_rtkit *rtk = data;
+
mbox_free_channel(rtk->mbox_chan);
destroy_workqueue(rtk->wq);
@@ -950,8 +952,7 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
if (IS_ERR(rtk))
return rtk;
- ret = devm_add_action_or_reset(dev, (void (*)(void *))apple_rtkit_free,
- rtk);
+ ret = devm_add_action_or_reset(dev, apple_rtkit_free, rtk);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/soc/apple/sart.c b/drivers/soc/apple/sart.c
index 83804b16ad03..afa111736899 100644
--- a/drivers/soc/apple/sart.c
+++ b/drivers/soc/apple/sart.c
@@ -164,6 +164,11 @@ static int apple_sart_probe(struct platform_device *pdev)
return 0;
}
+static void apple_sart_put_device(void *dev)
+{
+ put_device(dev);
+}
+
struct apple_sart *devm_apple_sart_get(struct device *dev)
{
struct device_node *sart_node;
@@ -187,7 +192,7 @@ struct apple_sart *devm_apple_sart_get(struct device *dev)
return ERR_PTR(-EPROBE_DEFER);
}
- ret = devm_add_action_or_reset(dev, (void (*)(void *))put_device,
+ ret = devm_add_action_or_reset(dev, apple_sart_put_device,
&sart_pdev->dev);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c
index 5a2edc48dd79..74eace3109a1 100644
--- a/drivers/soc/fsl/dpio/dpio-driver.c
+++ b/drivers/soc/fsl/dpio/dpio-driver.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/msi.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/io.h>
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 99f7de43c3c6..1440922341d8 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -13,10 +13,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/of_gpio.h> /* for of_mm_gpio_chip */
+#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_to_chip() get rid of this */
-#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <soc/fsl/qe/qe.h>
@@ -25,9 +24,6 @@ struct qe_gpio_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
- unsigned long pin_flags[QE_PIO_PINS];
-#define QE_PIN_REQUESTED 0
-
/* shadowed data register to clear/set bits safely */
u32 cpdata;
@@ -149,62 +145,65 @@ struct qe_pin {
/**
* qe_pin_request - Request a QE pin
- * @np: device node to get a pin from
- * @index: index of a pin in the device tree
+ * @dev: device to get the pin from
+ * @index: index of the pin in the device tree
* Context: non-atomic
*
* This function return qe_pin so that you could use it with the rest of
* the QE Pin Multiplexing API.
*/
-struct qe_pin *qe_pin_request(struct device_node *np, int index)
+struct qe_pin *qe_pin_request(struct device *dev, int index)
{
struct qe_pin *qe_pin;
struct gpio_chip *gc;
- struct qe_gpio_chip *qe_gc;
+ struct gpio_desc *gpiod;
+ int gpio_num;
int err;
- unsigned long flags;
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
if (!qe_pin) {
- pr_debug("%s: can't allocate memory\n", __func__);
+ dev_dbg(dev, "%s: can't allocate memory\n", __func__);
return ERR_PTR(-ENOMEM);
}
- err = of_get_gpio(np, index);
- if (err < 0)
+ /*
+ * Request gpio as nonexclusive as it was likely reserved by the
+ * caller, and we are not planning on controlling it, we only need
+ * the descriptor to the to the gpio chip structure.
+ */
+ gpiod = gpiod_get_index(dev, NULL, index,
+ GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ err = PTR_ERR_OR_ZERO(gpiod);
+ if (err)
goto err0;
- gc = gpio_to_chip(err);
+
+ gc = gpiod_to_chip(gpiod);
+ gpio_num = desc_to_gpio(gpiod);
+ /* We no longer need this descriptor */
+ gpiod_put(gpiod);
+
if (WARN_ON(!gc)) {
err = -ENODEV;
goto err0;
}
+ qe_pin->controller = gpiochip_get_data(gc);
+ /*
+ * FIXME: this gets the local offset on the gpio_chip so that the driver
+ * can manipulate pin control settings through its custom API. The real
+ * solution is to create a real pin control driver for this.
+ */
+ qe_pin->num = gpio_num - gc->base;
+
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
- pr_debug("%s: tried to get a non-qe pin\n", __func__);
+ dev_dbg(dev, "%s: tried to get a non-qe pin\n", __func__);
err = -EINVAL;
goto err0;
}
-
- qe_gc = gpiochip_get_data(gc);
-
- spin_lock_irqsave(&qe_gc->lock, flags);
-
- err -= gc->base;
- if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
- qe_pin->controller = qe_gc;
- qe_pin->num = err;
- err = 0;
- } else {
- err = -EBUSY;
- }
-
- spin_unlock_irqrestore(&qe_gc->lock, flags);
-
- if (!err)
- return qe_pin;
+ return qe_pin;
err0:
kfree(qe_pin);
- pr_debug("%s failed with status %d\n", __func__, err);
+ dev_dbg(dev, "%s failed with status %d\n", __func__, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL(qe_pin_request);
@@ -219,14 +218,6 @@ EXPORT_SYMBOL(qe_pin_request);
*/
void qe_pin_free(struct qe_pin *qe_pin)
{
- struct qe_gpio_chip *qe_gc = qe_pin->controller;
- unsigned long flags;
- const int pin = qe_pin->num;
-
- spin_lock_irqsave(&qe_gc->lock, flags);
- test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]);
- spin_unlock_irqrestore(&qe_gc->lock, flags);
-
kfree(qe_pin);
}
EXPORT_SYMBOL(qe_pin_free);
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 88aee59730e3..7a47d14fde44 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -755,6 +755,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
[IMX8MM_POWER_DOMAIN_OTG1] = {
.genpd = {
.name = "usb-otg1",
+ .flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MM_OTG1_SW_Pxx_REQ,
@@ -766,6 +767,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
[IMX8MM_POWER_DOMAIN_OTG2] = {
.genpd = {
.name = "usb-otg2",
+ .flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MM_OTG2_SW_Pxx_REQ,
@@ -1232,6 +1234,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
[IMX8MN_POWER_DOMAIN_OTG1] = {
.genpd = {
.name = "usb-otg1",
+ .flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MN_OTG1_SW_Pxx_REQ,
diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c
index 00879615a701..ddcf6be3d8b4 100644
--- a/drivers/soc/imx/imx8m-blk-ctrl.c
+++ b/drivers/soc/imx/imx8m-blk-ctrl.c
@@ -210,9 +210,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
- if (IS_ERR(bc->bus_power_dev))
- return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
- "failed to attach power domain \"bus\"\n");
+ if (IS_ERR(bc->bus_power_dev)) {
+ if (PTR_ERR(bc->bus_power_dev) == -ENODEV)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "failed to attach power domain \"bus\"\n");
+ else
+ return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
+ "failed to attach power domain \"bus\"\n");
+ }
for (i = 0; i < bc_data->num_domains; i++) {
const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c
index cc57a384d74d..28144c699b0c 100644
--- a/drivers/soc/imx/soc-imx8m.c
+++ b/drivers/soc/imx/soc-imx8m.c
@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/arm-smccc.h>
#include <linux/of.h>
+#include <linux/clk.h>
#define REV_B1 0x21
@@ -56,6 +57,7 @@ static u32 __init imx8mq_soc_revision(void)
void __iomem *ocotp_base;
u32 magic;
u32 rev;
+ struct clk *clk;
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
if (!np)
@@ -63,6 +65,13 @@ static u32 __init imx8mq_soc_revision(void)
ocotp_base = of_iomap(np, 0);
WARN_ON(!ocotp_base);
+ clk = of_clk_get_by_name(np, NULL);
+ if (!clk) {
+ WARN_ON(!clk);
+ return 0;
+ }
+
+ clk_prepare_enable(clk);
/*
* SOC revision on older imx8mq is not available in fuses so query
@@ -79,6 +88,8 @@ static u32 __init imx8mq_soc_revision(void)
soc_uid <<= 32;
soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
+ clk_disable_unprepare(clk);
+ clk_put(clk);
iounmap(ocotp_base);
of_node_put(np);
diff --git a/drivers/soc/loongson/Kconfig b/drivers/soc/loongson/Kconfig
new file mode 100644
index 000000000000..707f56358dc4
--- /dev/null
+++ b/drivers/soc/loongson/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Loongson-2 series SoC drivers
+#
+
+config LOONGSON2_GUTS
+ tristate "Loongson-2 SoC Global UtiliTieS (GUTS) register block"
+ depends on LOONGARCH || COMPILE_TEST
+ select SOC_BUS
+ help
+ The global utilities block controls PCIE device enabling, alternate
+ function selection for multiplexed signals, consistency of HDA, USB
+ and PCIE, configuration of memory controller, rtc controller, lio
+ controller, and clock control. This patch adds a driver to manage
+ and access global utilities block for LoongArch architecture Loongson-2
+ SoCs. Initially only reading SVR and registering soc device are
+ supported. Other guts accesses, such as reading firmware configuration
+ by default, should eventually be added into this driver as well.
diff --git a/drivers/soc/loongson/Makefile b/drivers/soc/loongson/Makefile
new file mode 100644
index 000000000000..263c486df638
--- /dev/null
+++ b/drivers/soc/loongson/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Makefile for the Linux Kernel SoC Loongson-2 specific device drivers
+#
+
+obj-$(CONFIG_LOONGSON2_GUTS) += loongson2_guts.o
diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c
new file mode 100644
index 000000000000..bace4bc8e03b
--- /dev/null
+++ b/drivers/soc/loongson/loongson2_guts.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Yinbo Zhu <zhuyinbo@loongson.cn>
+ * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/sys_soc.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+static struct soc_device_attribute soc_dev_attr;
+static struct soc_device *soc_dev;
+
+/*
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names. In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+struct scfg_guts {
+ u32 svr; /* Version Register */
+ u8 res0[4];
+ u16 feature; /* Feature Register */
+ u32 vendor; /* Vendor Register */
+ u8 res1[6];
+ u32 id;
+ u8 res2[0x3ff8 - 0x18];
+ u32 chip;
+};
+
+static struct guts {
+ struct scfg_guts __iomem *regs;
+ bool little_endian;
+} *guts;
+
+struct loongson2_soc_die_attr {
+ char *die;
+ u32 svr;
+ u32 mask;
+};
+
+/* SoC die attribute definition for Loongson-2 platform */
+static const struct loongson2_soc_die_attr loongson2_soc_die[] = {
+
+ /*
+ * LoongArch-based SoCs Loongson-2 Series
+ */
+
+ /* Die: 2k1000, SoC: 2k1000 */
+ { .die = "2K1000",
+ .svr = 0x00000013,
+ .mask = 0x000000ff,
+ },
+ { },
+};
+
+static const struct loongson2_soc_die_attr *loongson2_soc_die_match(
+ u32 svr, const struct loongson2_soc_die_attr *matches)
+{
+ while (matches->svr) {
+ if (matches->svr == (svr & matches->mask))
+ return matches;
+ matches++;
+ };
+
+ return NULL;
+}
+
+static u32 loongson2_guts_get_svr(void)
+{
+ u32 svr = 0;
+
+ if (!guts || !guts->regs)
+ return svr;
+
+ if (guts->little_endian)
+ svr = ioread32(&guts->regs->svr);
+ else
+ svr = ioread32be(&guts->regs->svr);
+
+ return svr;
+}
+
+static int loongson2_guts_probe(struct platform_device *pdev)
+{
+ struct device_node *root, *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ const struct loongson2_soc_die_attr *soc_die;
+ const char *machine;
+ u32 svr;
+
+ /* Initialize guts */
+ guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
+ if (!guts)
+ return -ENOMEM;
+
+ guts->little_endian = of_property_read_bool(np, "little-endian");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ guts->regs = ioremap(res->start, res->end - res->start + 1);
+ if (IS_ERR(guts->regs))
+ return PTR_ERR(guts->regs);
+
+ /* Register soc device */
+ root = of_find_node_by_path("/");
+ if (of_property_read_string(root, "model", &machine))
+ of_property_read_string_index(root, "compatible", 0, &machine);
+ of_node_put(root);
+ if (machine)
+ soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+
+ svr = loongson2_guts_get_svr();
+ soc_die = loongson2_soc_die_match(svr, loongson2_soc_die);
+ if (soc_die) {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
+ "Loongson %s", soc_die->die);
+ } else {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "Loongson");
+ }
+ if (!soc_dev_attr.family)
+ return -ENOMEM;
+ soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
+ "svr:0x%08x", svr);
+ if (!soc_dev_attr.soc_id)
+ return -ENOMEM;
+ soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
+ (svr >> 4) & 0xf, svr & 0xf);
+ if (!soc_dev_attr.revision)
+ return -ENOMEM;
+
+ soc_dev = soc_device_register(&soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ pr_info("Machine: %s\n", soc_dev_attr.machine);
+ pr_info("SoC family: %s\n", soc_dev_attr.family);
+ pr_info("SoC ID: %s, Revision: %s\n",
+ soc_dev_attr.soc_id, soc_dev_attr.revision);
+
+ return 0;
+}
+
+static int loongson2_guts_remove(struct platform_device *dev)
+{
+ soc_device_unregister(soc_dev);
+
+ return 0;
+}
+
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for Loongson-2 SoCs.
+ */
+static const struct of_device_id loongson2_guts_of_match[] = {
+ { .compatible = "loongson,ls2k-chipid", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, loongson2_guts_of_match);
+
+static struct platform_driver loongson2_guts_driver = {
+ .driver = {
+ .name = "loongson2-guts",
+ .of_match_table = loongson2_guts_of_match,
+ },
+ .probe = loongson2_guts_probe,
+ .remove = loongson2_guts_remove,
+};
+
+static int __init loongson2_guts_init(void)
+{
+ return platform_driver_register(&loongson2_guts_driver);
+}
+core_initcall(loongson2_guts_init);
+
+static void __exit loongson2_guts_exit(void)
+{
+ platform_driver_unregister(&loongson2_guts_driver);
+}
+module_exit(loongson2_guts_exit);
+
+MODULE_DESCRIPTION("Loongson2 GUTS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mt8186-mmsys.h b/drivers/soc/mediatek/mt8186-mmsys.h
index 09b1ccbc0093..279d4138525b 100644
--- a/drivers/soc/mediatek/mt8186-mmsys.h
+++ b/drivers/soc/mediatek/mt8186-mmsys.h
@@ -5,9 +5,11 @@
/* Values for DPI configuration in MMSYS address space */
#define MT8186_MMSYS_DPI_OUTPUT_FORMAT 0x400
-#define DPI_FORMAT_MASK 0x1
-#define DPI_RGB888_DDR_CON BIT(0)
-#define DPI_RGB565_SDR_CON BIT(1)
+#define MT8186_DPI_FORMAT_MASK GENMASK(1, 0)
+#define MT8186_DPI_RGB888_SDR_CON 0
+#define MT8186_DPI_RGB888_DDR_CON 1
+#define MT8186_DPI_RGB565_SDR_CON 2
+#define MT8186_DPI_RGB565_DDR_CON 3
#define MT8186_MMSYS_OVL_CON 0xF04
#define MT8186_MMSYS_OVL0_CON_MASK 0x3
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index d2c7a87aab87..f3431448e843 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -26,61 +26,26 @@ static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
-static const struct mtk_mmsys_match_data mt2701_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt2701_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
.clk_driver = "clk-mt2712-mm",
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
-static const struct mtk_mmsys_match_data mt2712_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt2712_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
.clk_driver = "clk-mt6779-mm",
};
-static const struct mtk_mmsys_match_data mt6779_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt6779_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
.clk_driver = "clk-mt6797-mm",
};
-static const struct mtk_mmsys_match_data mt6797_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt6797_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
.clk_driver = "clk-mt8167-mm",
.routes = mt8167_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8167_mmsys_routing_table),
};
-static const struct mtk_mmsys_match_data mt8167_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8167_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.clk_driver = "clk-mt8173-mm",
.routes = mmsys_default_routing_table,
@@ -88,13 +53,6 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
};
-static const struct mtk_mmsys_match_data mt8173_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8173_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.clk_driver = "clk-mt8183-mm",
.routes = mmsys_mt8183_routing_table,
@@ -102,13 +60,6 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
};
-static const struct mtk_mmsys_match_data mt8183_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8183_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.clk_driver = "clk-mt8186-mm",
.routes = mmsys_mt8186_routing_table,
@@ -116,13 +67,6 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
};
-static const struct mtk_mmsys_match_data mt8186_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8186_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.clk_driver = "clk-mt8192-mm",
.routes = mmsys_mt8192_routing_table,
@@ -130,66 +74,25 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
};
-static const struct mtk_mmsys_match_data mt8192_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8192_mmsys_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
- .io_start = 0x1c01a000,
.clk_driver = "clk-mt8195-vdo0",
.routes = mmsys_mt8195_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
};
-static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
- .io_start = 0x1c100000,
- .clk_driver = "clk-mt8195-vdo1",
-};
-
-static const struct mtk_mmsys_match_data mt8195_mmsys_match_data = {
- .num_drv_data = 2,
- .drv_data = {
- &mt8195_vdosys0_driver_data,
- &mt8195_vdosys1_driver_data,
- },
-};
-
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
.clk_driver = "clk-mt8365-mm",
.routes = mt8365_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8365_mmsys_routing_table),
};
-static const struct mtk_mmsys_match_data mt8365_mmsys_match_data = {
- .num_drv_data = 1,
- .drv_data = {
- &mt8365_mmsys_driver_data,
- },
-};
-
struct mtk_mmsys {
void __iomem *regs;
const struct mtk_mmsys_driver_data *data;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
- phys_addr_t io_start;
};
-static int mtk_mmsys_find_match_drvdata(struct mtk_mmsys *mmsys,
- const struct mtk_mmsys_match_data *match)
-{
- int i;
-
- for (i = 0; i < match->num_drv_data; i++)
- if (mmsys->io_start == match->drv_data[i]->io_start)
- return i;
-
- return -EINVAL;
-}
-
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
@@ -238,12 +141,27 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
{
- if (val)
- mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- DPI_RGB888_DDR_CON, DPI_FORMAT_MASK);
- else
- mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- DPI_RGB565_SDR_CON, DPI_FORMAT_MASK);
+ struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+
+ switch (val) {
+ case MTK_DPI_RGB888_SDR_CON:
+ mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON);
+ break;
+ case MTK_DPI_RGB565_SDR_CON:
+ mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON);
+ break;
+ case MTK_DPI_RGB565_DDR_CON:
+ mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON);
+ break;
+ case MTK_DPI_RGB888_DDR_CON:
+ default:
+ mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON);
+ break;
+ }
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
@@ -304,9 +222,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct platform_device *clks;
struct platform_device *drm;
- const struct mtk_mmsys_match_data *match_data;
struct mtk_mmsys *mmsys;
- struct resource *res;
int ret;
mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
@@ -332,27 +248,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return ret;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "Couldn't get mmsys resource\n");
- return -EINVAL;
- }
- mmsys->io_start = res->start;
-
- match_data = of_device_get_match_data(dev);
- if (match_data->num_drv_data > 1) {
- /* This SoC has multiple mmsys channels */
- ret = mtk_mmsys_find_match_drvdata(mmsys, match_data);
- if (ret < 0) {
- dev_err(dev, "Couldn't get match driver data\n");
- return ret;
- }
- mmsys->data = match_data->drv_data[ret];
- } else {
- dev_dbg(dev, "Using single mmsys channel\n");
- mmsys->data = match_data->drv_data[0];
- }
-
+ mmsys->data = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, mmsys);
clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
@@ -373,47 +269,51 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
static const struct of_device_id of_match_mtk_mmsys[] = {
{
.compatible = "mediatek,mt2701-mmsys",
- .data = &mt2701_mmsys_match_data,
+ .data = &mt2701_mmsys_driver_data,
},
{
.compatible = "mediatek,mt2712-mmsys",
- .data = &mt2712_mmsys_match_data,
+ .data = &mt2712_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6779-mmsys",
- .data = &mt6779_mmsys_match_data,
+ .data = &mt6779_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6797-mmsys",
- .data = &mt6797_mmsys_match_data,
+ .data = &mt6797_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8167-mmsys",
- .data = &mt8167_mmsys_match_data,
+ .data = &mt8167_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8173-mmsys",
- .data = &mt8173_mmsys_match_data,
+ .data = &mt8173_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8183-mmsys",
- .data = &mt8183_mmsys_match_data,
+ .data = &mt8183_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8186-mmsys",
- .data = &mt8186_mmsys_match_data,
+ .data = &mt8186_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8192-mmsys",
- .data = &mt8192_mmsys_match_data,
+ .data = &mt8192_mmsys_driver_data,
},
- {
+ { /* deprecated compatible */
.compatible = "mediatek,mt8195-mmsys",
- .data = &mt8195_mmsys_match_data,
+ .data = &mt8195_vdosys0_driver_data,
+ },
+ {
+ .compatible = "mediatek,mt8195-vdosys0",
+ .data = &mt8195_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8365-mmsys",
- .data = &mt8365_mmsys_match_data,
+ .data = &mt8365_mmsys_driver_data,
},
{ }
};
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index f01ba206481d..77f37f8c715b 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -87,18 +87,12 @@ struct mtk_mmsys_routes {
};
struct mtk_mmsys_driver_data {
- const resource_size_t io_start;
const char *clk_driver;
const struct mtk_mmsys_routes *routes;
const unsigned int num_routes;
const u16 sw0_rst_offset;
};
-struct mtk_mmsys_match_data {
- unsigned short num_drv_data;
- const struct mtk_mmsys_driver_data *drv_data[];
-};
-
/*
* Routes in mt8173, mt2701, mt2712 are different. That means
* in the same register address, it controls different input/output
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index eb82ae06697f..15789a03e6c6 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -983,6 +983,68 @@ static int mt8195_regs[] = {
[PWRAP_WACS2_RDATA] = 0x8A8,
};
+static int mt8365_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_CSHEXT_WRITE] = 0x24,
+ [PWRAP_CSHEXT_READ] = 0x28,
+ [PWRAP_STAUPD_PRD] = 0x3c,
+ [PWRAP_STAUPD_GRPEN] = 0x40,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x58,
+ [PWRAP_STAUPD_STA] = 0x5c,
+ [PWRAP_WRAP_STA] = 0x60,
+ [PWRAP_HARB_INIT] = 0x64,
+ [PWRAP_HARB_HPRIO] = 0x68,
+ [PWRAP_HIPRIO_ARB_EN] = 0x6c,
+ [PWRAP_HARB_STA0] = 0x70,
+ [PWRAP_HARB_STA1] = 0x74,
+ [PWRAP_MAN_EN] = 0x7c,
+ [PWRAP_MAN_CMD] = 0x80,
+ [PWRAP_MAN_RDATA] = 0x84,
+ [PWRAP_MAN_VLDCLR] = 0x88,
+ [PWRAP_WACS0_EN] = 0x8c,
+ [PWRAP_INIT_DONE0] = 0x90,
+ [PWRAP_WACS0_CMD] = 0xc00,
+ [PWRAP_WACS0_RDATA] = 0xc04,
+ [PWRAP_WACS0_VLDCLR] = 0xc08,
+ [PWRAP_WACS1_EN] = 0x94,
+ [PWRAP_INIT_DONE1] = 0x98,
+ [PWRAP_WACS2_EN] = 0x9c,
+ [PWRAP_INIT_DONE2] = 0xa0,
+ [PWRAP_WACS2_CMD] = 0xc20,
+ [PWRAP_WACS2_RDATA] = 0xc24,
+ [PWRAP_WACS2_VLDCLR] = 0xc28,
+ [PWRAP_INT_EN] = 0xb4,
+ [PWRAP_INT_FLG_RAW] = 0xb8,
+ [PWRAP_INT_FLG] = 0xbc,
+ [PWRAP_INT_CLR] = 0xc0,
+ [PWRAP_SIG_ADR] = 0xd4,
+ [PWRAP_SIG_MODE] = 0xd8,
+ [PWRAP_SIG_VALUE] = 0xdc,
+ [PWRAP_SIG_ERRVAL] = 0xe0,
+ [PWRAP_CRC_EN] = 0xe4,
+ [PWRAP_TIMER_EN] = 0xe8,
+ [PWRAP_TIMER_STA] = 0xec,
+ [PWRAP_WDT_UNIT] = 0xf0,
+ [PWRAP_WDT_SRC_EN] = 0xf4,
+ [PWRAP_WDT_FLG] = 0xfc,
+ [PWRAP_DEBUG_INT_SEL] = 0x104,
+ [PWRAP_CIPHER_KEY_SEL] = 0x1c4,
+ [PWRAP_CIPHER_IV_SEL] = 0x1c8,
+ [PWRAP_CIPHER_RDY] = 0x1d0,
+ [PWRAP_CIPHER_MODE] = 0x1d4,
+ [PWRAP_CIPHER_SWRST] = 0x1d8,
+ [PWRAP_DCM_EN] = 0x1dc,
+ [PWRAP_DCM_DBC_PRD] = 0x1e0,
+ [PWRAP_EINT_STA0_ADR] = 0x44,
+ [PWRAP_EINT_STA1_ADR] = 0x48,
+ [PWRAP_INT1_EN] = 0xc4,
+ [PWRAP_INT1_FLG] = 0xcc,
+ [PWRAP_INT1_CLR] = 0xd0,
+ [PWRAP_WDT_SRC_EN_1] = 0xf8,
+};
+
static int mt8516_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
@@ -1139,6 +1201,7 @@ enum pwrap_type {
PWRAP_MT8183,
PWRAP_MT8186,
PWRAP_MT8195,
+ PWRAP_MT8365,
PWRAP_MT8516,
};
@@ -1171,6 +1234,8 @@ struct pmic_wrapper {
const struct pwrap_slv_type *slave;
struct clk *clk_spi;
struct clk *clk_wrap;
+ struct clk *clk_sys;
+ struct clk *clk_tmr;
struct reset_control *rstc;
struct reset_control *rstc_bridge;
@@ -1596,6 +1661,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
case PWRAP_MT6797:
case PWRAP_MT8173:
case PWRAP_MT8186:
+ case PWRAP_MT8365:
case PWRAP_MT8516:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
break;
@@ -2104,6 +2170,19 @@ static struct pmic_wrapper_type pwrap_mt8195 = {
.init_soc_specific = NULL,
};
+static const struct pmic_wrapper_type pwrap_mt8365 = {
+ .regs = mt8365_regs,
+ .type = PWRAP_MT8365,
+ .arb_en_all = 0x3ffff,
+ .int_en_all = 0x7f1fffff,
+ .int1_en_all = 0x0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
static struct pmic_wrapper_type pwrap_mt8516 = {
.regs = mt8516_regs,
.type = PWRAP_MT8516,
@@ -2141,6 +2220,7 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
{ .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183 },
{ .compatible = "mediatek,mt8186-pwrap", .data = &pwrap_mt8186 },
{ .compatible = "mediatek,mt8195-pwrap", .data = &pwrap_mt8195 },
+ { .compatible = "mediatek,mt8365-pwrap", .data = &pwrap_mt8365 },
{ .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516 },
{ /* sentinel */ }
};
@@ -2214,6 +2294,20 @@ static int pwrap_probe(struct platform_device *pdev)
return PTR_ERR(wrp->clk_wrap);
}
+ wrp->clk_sys = devm_clk_get_optional(wrp->dev, "sys");
+ if (IS_ERR(wrp->clk_sys)) {
+ return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_sys),
+ "failed to get clock: %pe\n",
+ wrp->clk_sys);
+ }
+
+ wrp->clk_tmr = devm_clk_get_optional(wrp->dev, "tmr");
+ if (IS_ERR(wrp->clk_tmr)) {
+ return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_tmr),
+ "failed to get clock: %pe\n",
+ wrp->clk_tmr);
+ }
+
ret = clk_prepare_enable(wrp->clk_spi);
if (ret)
return ret;
@@ -2222,6 +2316,14 @@ static int pwrap_probe(struct platform_device *pdev)
if (ret)
goto err_out1;
+ ret = clk_prepare_enable(wrp->clk_sys);
+ if (ret)
+ goto err_out2;
+
+ ret = clk_prepare_enable(wrp->clk_tmr);
+ if (ret)
+ goto err_out3;
+
/* Enable internal dynamic clock */
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
pwrap_writel(wrp, 1, PWRAP_DCM_EN);
@@ -2236,7 +2338,7 @@ static int pwrap_probe(struct platform_device *pdev)
ret = pwrap_init(wrp);
if (ret) {
dev_dbg(wrp->dev, "init failed with %d\n", ret);
- goto err_out2;
+ goto err_out4;
}
}
@@ -2250,7 +2352,7 @@ static int pwrap_probe(struct platform_device *pdev)
if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) {
dev_dbg(wrp->dev, "initialization isn't finished\n");
ret = -ENODEV;
- goto err_out2;
+ goto err_out4;
}
/* Initialize watchdog, may not be done by the bootloader */
@@ -2288,7 +2390,7 @@ static int pwrap_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH,
"mt-pmic-pwrap", wrp);
if (ret)
- goto err_out2;
+ goto err_out4;
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
if (IS_ERR(wrp->regmap)) {
@@ -2300,11 +2402,15 @@ static int pwrap_probe(struct platform_device *pdev)
if (ret) {
dev_dbg(wrp->dev, "failed to create child devices at %pOF\n",
np);
- goto err_out2;
+ goto err_out4;
}
return 0;
+err_out4:
+ clk_disable_unprepare(wrp->clk_tmr);
+err_out3:
+ clk_disable_unprepare(wrp->clk_sys);
err_out2:
clk_disable_unprepare(wrp->clk_wrap);
err_out1:
diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c
index 93449fb3519e..bd029e838241 100644
--- a/drivers/soc/pxa/ssp.c
+++ b/drivers/soc/pxa/ssp.c
@@ -146,10 +146,8 @@ static int pxa_ssp_probe(struct platform_device *pdev)
}
ssp->irq = platform_get_irq(pdev, 0);
- if (ssp->irq < 0) {
- dev_err(dev, "no IRQ resource defined\n");
+ if (ssp->irq < 0)
return -ENODEV;
- }
if (dev->of_node) {
const struct of_device_id *id =
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 024e420f1bb7..ae504c43d9e7 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -63,6 +63,7 @@ config QCOM_GSBI
config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver"
depends on ARCH_QCOM || COMPILE_TEST
+ select REGMAP_MMIO
help
Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver for platforms such as,
@@ -236,6 +237,7 @@ config QCOM_ICC_BWMON
tristate "QCOM Interconnect Bandwidth Monitor driver"
depends on ARCH_QCOM || COMPILE_TEST
select PM_OPP
+ select REGMAP_MMIO
help
Sets up driver monitoring bandwidth on various interconnects and
based on that voting for interconnect bandwidth, adjusting their
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index b4046f393575..cd44f17dad3d 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -454,11 +454,19 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->dev.driver = NULL;
spin_lock(&apr->svcs_lock);
- idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
+ ret = idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
spin_unlock(&apr->svcs_lock);
+ if (ret < 0) {
+ dev_err(dev, "idr_alloc failed: %d\n", ret);
+ goto out;
+ }
- of_property_read_string_index(np, "qcom,protection-domain",
- 1, &adev->service_path);
+ ret = of_property_read_string_index(np, "qcom,protection-domain",
+ 1, &adev->service_path);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read second value of qcom,protection-domain\n");
+ goto out;
+ }
dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev));
@@ -468,6 +476,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
put_device(&adev->dev);
}
+out:
return ret;
}
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index 629a7188b576..33856abd560c 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -338,6 +338,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
+ device_set_pm_not_required(&pdev->dev);
+
return 0;
}
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 8b7e8118f3ce..23ce2f78c4ed 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -21,6 +21,8 @@
#define ACTIVATE BIT(0)
#define DEACTIVATE BIT(1)
+#define ACT_CLEAR BIT(0)
+#define ACT_COMPLETE BIT(4)
#define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
#define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
#define ACT_CTRL_ACT_TRIG BIT(0)
@@ -41,19 +43,30 @@
#define MAX_CAP_TO_BYTES(n) (n * SZ_1K)
#define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K)
+#define LLCC_TRP_ACT_CLEARn(n) (8 + n * SZ_4K)
#define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
+#define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_8 * n)
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
#define LLCC_TRP_PCB_ACT 0x21f04
+#define LLCC_TRP_ALGO_CFG1 0x21f0c
+#define LLCC_TRP_ALGO_CFG2 0x21f10
+#define LLCC_TRP_ALGO_CFG3 0x21f14
+#define LLCC_TRP_ALGO_CFG4 0x21f18
+#define LLCC_TRP_ALGO_CFG5 0x21f1c
#define LLCC_TRP_WRSC_EN 0x21f20
+#define LLCC_TRP_ALGO_CFG6 0x21f24
+#define LLCC_TRP_ALGO_CFG7 0x21f28
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
+#define LLCC_TRP_ALGO_CFG8 0x21f30
#define BANK_OFFSET_STRIDE 0x80000
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
+#define LLCC_VERSION_4_1_0_0 0x04010000
/**
* struct llcc_slice_config - Data associated with the llcc slice
@@ -97,6 +110,14 @@ struct llcc_slice_config {
bool activate_on_init;
bool write_scid_en;
bool write_scid_cacheable_en;
+ bool stale_en;
+ bool stale_cap_en;
+ bool mru_uncap_en;
+ bool mru_rollover;
+ bool alloc_oneway_en;
+ bool ovcap_en;
+ bool ovcap_prio;
+ bool vict_prio;
};
struct qcom_llcc_config {
@@ -297,6 +318,38 @@ static const struct llcc_slice_config sm8450_data[] = {
{LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
};
+static const struct llcc_slice_config sm8550_data[] = {
+ {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_VIDSC0, 2, 512, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_MDMHPGRW, 25, 1024, 4, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_MDMPNG, 27, 1024, 0, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CVP, 8, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_MODPE, 29, 64, 1, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
+ {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CAMEXP0, 4, 256, 4, 1, 0xF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CMPTHCP, 17, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_LCPDARE, 30, 128, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
+ {LLCC_AENPU, 3, 3072, 1, 1, 0xFE01FF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_ISLAND1, 12, 1792, 7, 1, 0xFE00, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_ISLAND4, 15, 256, 7, 1, 0x10000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CAMEXP2, 19, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CAMEXP3, 20, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_CAMEXP4, 21, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_DISP_WB, 23, 1024, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_DISP_1, 24, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+};
+
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
@@ -443,6 +496,14 @@ static const struct qcom_llcc_config sm8450_cfg = {
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
};
+static const struct qcom_llcc_config sm8550_cfg = {
+ .sct_data = sm8550_data,
+ .size = ARRAY_SIZE(sm8550_data),
+ .need_llcc_cfg = true,
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+};
+
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
/**
@@ -497,6 +558,7 @@ static int llcc_update_act_ctrl(u32 sid,
u32 act_ctrl_reg_val, u32 status)
{
u32 act_ctrl_reg;
+ u32 act_clear_reg;
u32 status_reg;
u32 slice_status;
int ret;
@@ -505,6 +567,7 @@ static int llcc_update_act_ctrl(u32 sid,
return PTR_ERR(drv_data);
act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
+ act_clear_reg = LLCC_TRP_ACT_CLEARn(sid);
status_reg = LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */
@@ -521,9 +584,22 @@ static int llcc_update_act_ctrl(u32 sid,
if (ret)
return ret;
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
+ ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
+ slice_status, (slice_status & ACT_COMPLETE),
+ 0, LLCC_STATUS_READ_DELAY);
+ if (ret)
+ return ret;
+ }
+
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
+
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0)
+ ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,
+ ACT_CLEAR);
+
return ret;
}
@@ -636,8 +712,10 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
const struct qcom_llcc_config *cfg)
{
int ret;
+ u32 attr2_cfg;
u32 attr1_cfg;
u32 attr0_cfg;
+ u32 attr2_val;
u32 attr1_val;
u32 attr0_val;
u32 max_cap_cacheline;
@@ -667,8 +745,14 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
- attr0_val = config->res_ways & ATTR0_RES_WAYS_MASK;
- attr0_val |= config->bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
+ attr2_cfg = LLCC_TRP_ATTR2_CFGn(config->slice_id);
+ attr0_val = config->res_ways;
+ attr2_val = config->bonus_ways;
+ } else {
+ attr0_val = config->res_ways & ATTR0_RES_WAYS_MASK;
+ attr0_val |= config->bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
+ }
attr0_cfg = LLCC_TRP_ATTR0_CFGn(config->slice_id);
@@ -676,6 +760,12 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
+ ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val);
+ if (ret)
+ return ret;
+ }
+
if (cfg->need_llcc_cfg) {
u32 disable_cap_alloc, retain_pc;
@@ -685,11 +775,13 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
- retain_pc = config->retain_on_pc << config->slice_id;
- ret = regmap_write(drv_data->bcast_regmap,
- LLCC_TRP_PCB_ACT, retain_pc);
- if (ret)
- return ret;
+ if (drv_data->version < LLCC_VERSION_4_1_0_0) {
+ retain_pc = config->retain_on_pc << config->slice_id;
+ ret = regmap_write(drv_data->bcast_regmap,
+ LLCC_TRP_PCB_ACT, retain_pc);
+ if (ret)
+ return ret;
+ }
}
if (drv_data->version >= LLCC_VERSION_2_0_0_0) {
@@ -712,6 +804,65 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
+ u32 stale_en;
+ u32 stale_cap_en;
+ u32 mru_uncap_en;
+ u32 mru_rollover;
+ u32 alloc_oneway_en;
+ u32 ovcap_en;
+ u32 ovcap_prio;
+ u32 vict_prio;
+
+ stale_en = config->stale_en << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG1,
+ BIT(config->slice_id), stale_en);
+ if (ret)
+ return ret;
+
+ stale_cap_en = config->stale_cap_en << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG2,
+ BIT(config->slice_id), stale_cap_en);
+ if (ret)
+ return ret;
+
+ mru_uncap_en = config->mru_uncap_en << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG3,
+ BIT(config->slice_id), mru_uncap_en);
+ if (ret)
+ return ret;
+
+ mru_rollover = config->mru_rollover << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG4,
+ BIT(config->slice_id), mru_rollover);
+ if (ret)
+ return ret;
+
+ alloc_oneway_en = config->alloc_oneway_en << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG5,
+ BIT(config->slice_id), alloc_oneway_en);
+ if (ret)
+ return ret;
+
+ ovcap_en = config->ovcap_en << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG6,
+ BIT(config->slice_id), ovcap_en);
+ if (ret)
+ return ret;
+
+ ovcap_prio = config->ovcap_prio << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG7,
+ BIT(config->slice_id), ovcap_prio);
+ if (ret)
+ return ret;
+
+ vict_prio = config->vict_prio << config->slice_id;
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG8,
+ BIT(config->slice_id), vict_prio);
+ if (ret)
+ return ret;
+ }
+
if (config->activate_on_init) {
desc.slice_id = config->slice_id;
ret = llcc_slice_activate(&desc);
@@ -849,7 +1000,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
if (ret)
goto err;
- drv_data->ecc_irq = platform_get_irq(pdev, 0);
+ drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
if (drv_data->ecc_irq >= 0) {
llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data,
@@ -875,6 +1026,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
+ { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_llcc_of_match);
diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
index a30422214943..03c282b7f17e 100644
--- a/drivers/soc/qcom/pdr_internal.h
+++ b/drivers/soc/qcom/pdr_internal.h
@@ -28,7 +28,7 @@ struct servreg_location_entry {
u32 instance;
};
-static struct qmi_elem_info servreg_location_entry_ei[] = {
+static const struct qmi_elem_info servreg_location_entry_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@@ -74,7 +74,7 @@ struct servreg_get_domain_list_req {
u32 domain_offset;
};
-static struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
+static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@@ -116,7 +116,7 @@ struct servreg_get_domain_list_resp {
struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH];
};
-static struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
+static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@@ -199,7 +199,7 @@ struct servreg_register_listener_req {
char service_path[SERVREG_NAME_LENGTH + 1];
};
-static struct qmi_elem_info servreg_register_listener_req_ei[] = {
+static const struct qmi_elem_info servreg_register_listener_req_ei[] = {
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
@@ -227,7 +227,7 @@ struct servreg_register_listener_resp {
enum servreg_service_state curr_state;
};
-static struct qmi_elem_info servreg_register_listener_resp_ei[] = {
+static const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@@ -263,7 +263,7 @@ struct servreg_restart_pd_req {
char service_path[SERVREG_NAME_LENGTH + 1];
};
-static struct qmi_elem_info servreg_restart_pd_req_ei[] = {
+static const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@@ -280,7 +280,7 @@ struct servreg_restart_pd_resp {
struct qmi_response_type_v01 resp;
};
-static struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
+static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@@ -300,7 +300,7 @@ struct servreg_state_updated_ind {
u16 transaction_id;
};
-static struct qmi_elem_info servreg_state_updated_ind_ei[] = {
+static const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
{
.data_type = QMI_SIGNED_4_BYTE_ENUM,
.elem_len = 1,
@@ -336,7 +336,7 @@ struct servreg_set_ack_req {
u16 transaction_id;
};
-static struct qmi_elem_info servreg_set_ack_req_ei[] = {
+static const struct qmi_elem_info servreg_set_ack_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@@ -362,7 +362,7 @@ struct servreg_set_ack_resp {
struct qmi_response_type_v01 resp;
};
-static struct qmi_elem_info servreg_set_ack_resp_ei[] = {
+static const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 121ea409fafc..6228af057120 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -217,6 +217,8 @@ static int qcom_stats_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, root);
+ device_set_pm_not_required(&pdev->dev);
+
return 0;
}
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index 344ba687c13b..e3cf1beff803 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -59,7 +59,6 @@ struct tcs_group {
* @cmd: the payload that will be part of the @msg
* @completion: triggered when request is done
* @dev: the device making the request
- * @err: err return from the controller
* @needs_free: check to free dynamically allocated request object
*/
struct rpmh_request {
@@ -67,7 +66,6 @@ struct rpmh_request {
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
struct completion *completion;
const struct device *dev;
- int err;
bool needs_free;
};
@@ -86,18 +84,25 @@ struct rpmh_ctrlr {
struct list_head batch_cache;
};
+struct rsc_ver {
+ u32 major;
+ u32 minor;
+};
+
/**
* struct rsc_drv: the Direct Resource Voter (DRV) of the
* Resource State Coordinator controller (RSC)
*
* @name: Controller identifier.
+ * @base: Start address of the DRV registers in this controller.
* @tcs_base: Start address of the TCS registers in this controller.
* @id: Instance id in the controller (Direct Resource Voter).
* @num_tcs: Number of TCSes in this DRV.
* @rsc_pm: CPU PM notifier for controller.
* Used when solver mode is not present.
* @cpus_in_pm: Number of CPUs not in idle power collapse.
- * Used when solver mode is not present.
+ * Used when solver mode and "power-domains" is not present.
+ * @genpd_nb: PM Domain notifier for cluster genpd notifications.
* @tcs: TCS groups.
* @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY
* transfers, but might show a sleep/wake TCS in use if
@@ -110,27 +115,34 @@ struct rpmh_ctrlr {
* @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a
* slot
* @client: Handle to the DRV's client.
+ * @dev: RSC device.
*/
struct rsc_drv {
const char *name;
+ void __iomem *base;
void __iomem *tcs_base;
int id;
int num_tcs;
struct notifier_block rsc_pm;
+ struct notifier_block genpd_nb;
atomic_t cpus_in_pm;
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
+ struct device *dev;
+ struct rsc_ver ver;
+ u32 *regs;
};
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
void rpmh_rsc_invalidate(struct rsc_drv *drv);
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv);
-void rpmh_tx_done(const struct tcs_request *msg, int r);
+void rpmh_tx_done(const struct tcs_request *msg);
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
#endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 01c2f50cb97e..0f8b2249f889 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -12,16 +12,21 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <clocksource/arm_arch_timer.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/tcs.h>
#include <dt-bindings/soc/qcom,rpmh-rsc.h>
@@ -31,49 +36,50 @@
#define CREATE_TRACE_POINTS
#include "trace-rpmh.h"
-#define RSC_DRV_TCS_OFFSET 672
-#define RSC_DRV_CMD_OFFSET 20
+
+#define RSC_DRV_ID 0
+
+#define MAJOR_VER_MASK 0xFF
+#define MAJOR_VER_SHIFT 16
+#define MINOR_VER_MASK 0xFF
+#define MINOR_VER_SHIFT 8
+
+enum {
+ RSC_DRV_TCS_OFFSET,
+ RSC_DRV_CMD_OFFSET,
+ DRV_SOLVER_CONFIG,
+ DRV_PRNT_CHLD_CONFIG,
+ RSC_DRV_IRQ_ENABLE,
+ RSC_DRV_IRQ_STATUS,
+ RSC_DRV_IRQ_CLEAR,
+ RSC_DRV_CMD_WAIT_FOR_CMPL,
+ RSC_DRV_CONTROL,
+ RSC_DRV_STATUS,
+ RSC_DRV_CMD_ENABLE,
+ RSC_DRV_CMD_MSGID,
+ RSC_DRV_CMD_ADDR,
+ RSC_DRV_CMD_DATA,
+ RSC_DRV_CMD_STATUS,
+ RSC_DRV_CMD_RESP_DATA,
+};
/* DRV HW Solver Configuration Information Register */
-#define DRV_SOLVER_CONFIG 0x04
#define DRV_HW_SOLVER_MASK 1
#define DRV_HW_SOLVER_SHIFT 24
/* DRV TCS Configuration Information Register */
-#define DRV_PRNT_CHLD_CONFIG 0x0C
#define DRV_NUM_TCS_MASK 0x3F
#define DRV_NUM_TCS_SHIFT 6
#define DRV_NCPT_MASK 0x1F
#define DRV_NCPT_SHIFT 27
-/* Offsets for common TCS Registers, one bit per TCS */
-#define RSC_DRV_IRQ_ENABLE 0x00
-#define RSC_DRV_IRQ_STATUS 0x04
-#define RSC_DRV_IRQ_CLEAR 0x08 /* w/o; write 1 to clear */
-
-/*
- * Offsets for per TCS Registers.
- *
- * TCSes start at 0x10 from tcs_base and are stored one after another.
- * Multiply tcs_id by RSC_DRV_TCS_OFFSET to find a given TCS and add one
- * of the below to find a register.
- */
-#define RSC_DRV_CMD_WAIT_FOR_CMPL 0x10 /* 1 bit per command */
-#define RSC_DRV_CONTROL 0x14
-#define RSC_DRV_STATUS 0x18 /* zero if tcs is busy */
-#define RSC_DRV_CMD_ENABLE 0x1C /* 1 bit per command */
-
-/*
- * Offsets for per command in a TCS.
- *
- * Commands (up to 16) start at 0x30 in a TCS; multiply command index
- * by RSC_DRV_CMD_OFFSET and add one of the below to find a register.
- */
-#define RSC_DRV_CMD_MSGID 0x30
-#define RSC_DRV_CMD_ADDR 0x34
-#define RSC_DRV_CMD_DATA 0x38
-#define RSC_DRV_CMD_STATUS 0x3C
-#define RSC_DRV_CMD_RESP_DATA 0x40
+/* Offsets for CONTROL TCS Registers */
+#define RSC_DRV_CTL_TCS_DATA_HI 0x38
+#define RSC_DRV_CTL_TCS_DATA_HI_MASK 0xFFFFFF
+#define RSC_DRV_CTL_TCS_DATA_HI_VALID BIT(31)
+#define RSC_DRV_CTL_TCS_DATA_LO 0x40
+#define RSC_DRV_CTL_TCS_DATA_LO_MASK 0xFFFFFFFF
+#define RSC_DRV_CTL_TCS_DATA_SIZE 32
#define TCS_AMC_MODE_ENABLE BIT(16)
#define TCS_AMC_MODE_TRIGGER BIT(24)
@@ -139,16 +145,62 @@
* +---------------------------------------------------+
*/
+#define USECS_TO_CYCLES(time_usecs) \
+ xloops_to_cycles((time_usecs) * 0x10C7UL)
+
+static inline unsigned long xloops_to_cycles(u64 xloops)
+{
+ return (xloops * loops_per_jiffy * HZ) >> 32;
+}
+
+static u32 rpmh_rsc_reg_offset_ver_2_7[] = {
+ [RSC_DRV_TCS_OFFSET] = 672,
+ [RSC_DRV_CMD_OFFSET] = 20,
+ [DRV_SOLVER_CONFIG] = 0x04,
+ [DRV_PRNT_CHLD_CONFIG] = 0x0C,
+ [RSC_DRV_IRQ_ENABLE] = 0x00,
+ [RSC_DRV_IRQ_STATUS] = 0x04,
+ [RSC_DRV_IRQ_CLEAR] = 0x08,
+ [RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x10,
+ [RSC_DRV_CONTROL] = 0x14,
+ [RSC_DRV_STATUS] = 0x18,
+ [RSC_DRV_CMD_ENABLE] = 0x1C,
+ [RSC_DRV_CMD_MSGID] = 0x30,
+ [RSC_DRV_CMD_ADDR] = 0x34,
+ [RSC_DRV_CMD_DATA] = 0x38,
+ [RSC_DRV_CMD_STATUS] = 0x3C,
+ [RSC_DRV_CMD_RESP_DATA] = 0x40,
+};
+
+static u32 rpmh_rsc_reg_offset_ver_3_0[] = {
+ [RSC_DRV_TCS_OFFSET] = 672,
+ [RSC_DRV_CMD_OFFSET] = 24,
+ [DRV_SOLVER_CONFIG] = 0x04,
+ [DRV_PRNT_CHLD_CONFIG] = 0x0C,
+ [RSC_DRV_IRQ_ENABLE] = 0x00,
+ [RSC_DRV_IRQ_STATUS] = 0x04,
+ [RSC_DRV_IRQ_CLEAR] = 0x08,
+ [RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x20,
+ [RSC_DRV_CONTROL] = 0x24,
+ [RSC_DRV_STATUS] = 0x28,
+ [RSC_DRV_CMD_ENABLE] = 0x2C,
+ [RSC_DRV_CMD_MSGID] = 0x34,
+ [RSC_DRV_CMD_ADDR] = 0x38,
+ [RSC_DRV_CMD_DATA] = 0x3C,
+ [RSC_DRV_CMD_STATUS] = 0x40,
+ [RSC_DRV_CMD_RESP_DATA] = 0x44,
+};
+
static inline void __iomem *
tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id)
{
- return drv->tcs_base + RSC_DRV_TCS_OFFSET * tcs_id + reg;
+ return drv->tcs_base + drv->regs[RSC_DRV_TCS_OFFSET] * tcs_id + reg;
}
static inline void __iomem *
tcs_cmd_addr(const struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
{
- return tcs_reg_addr(drv, reg, tcs_id) + RSC_DRV_CMD_OFFSET * cmd_id;
+ return tcs_reg_addr(drv, reg, tcs_id) + drv->regs[RSC_DRV_CMD_OFFSET] * cmd_id;
}
static u32 read_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
@@ -216,7 +268,7 @@ static void tcs_invalidate(struct rsc_drv *drv, int type)
return;
for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
- write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
+ write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], m, 0);
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
}
@@ -330,24 +382,25 @@ static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
{
u32 enable;
+ u32 reg = drv->regs[RSC_DRV_CONTROL];
/*
* HW req: Clear the DRV_CONTROL and enable TCS again
* While clearing ensure that the AMC mode trigger is cleared
* and then the mode enable is cleared.
*/
- enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id);
+ enable = read_tcs_reg(drv, reg, tcs_id);
enable &= ~TCS_AMC_MODE_TRIGGER;
- write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable &= ~TCS_AMC_MODE_ENABLE;
- write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
if (trigger) {
/* Enable the AMC mode on the TCS and then trigger the TCS */
enable = TCS_AMC_MODE_ENABLE;
- write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
- write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ write_tcs_reg(drv, reg, tcs_id, enable);
}
}
@@ -363,13 +416,14 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
{
u32 data;
+ u32 reg = drv->regs[RSC_DRV_IRQ_ENABLE];
- data = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_ENABLE);
+ data = readl_relaxed(drv->tcs_base + reg);
if (enable)
data |= BIT(tcs_id);
else
data &= ~BIT(tcs_id);
- writel_relaxed(data, drv->tcs_base + RSC_DRV_IRQ_ENABLE);
+ writel_relaxed(data, drv->tcs_base + reg);
}
/**
@@ -385,34 +439,18 @@ static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
static irqreturn_t tcs_tx_done(int irq, void *p)
{
struct rsc_drv *drv = p;
- int i, j, err = 0;
+ int i;
unsigned long irq_status;
const struct tcs_request *req;
- struct tcs_cmd *cmd;
- irq_status = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_STATUS);
+ irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
req = get_req_from_tcs(drv, i);
if (WARN_ON(!req))
goto skip;
- err = 0;
- for (j = 0; j < req->num_cmds; j++) {
- u32 sts;
-
- cmd = &req->cmds[j];
- sts = read_tcs_cmd(drv, RSC_DRV_CMD_STATUS, i, j);
- if (!(sts & CMD_STATUS_ISSUED) ||
- ((req->wait_for_compl || cmd->wait) &&
- !(sts & CMD_STATUS_COMPL))) {
- pr_err("Incomplete request: %s: addr=%#x data=%#x",
- drv->name, cmd->addr, cmd->data);
- err = -EIO;
- }
- }
-
- trace_rpmh_tx_done(drv, i, req, err);
+ trace_rpmh_tx_done(drv, i, req);
/*
* If wake tcs was re-purposed for sending active
@@ -423,8 +461,8 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
__tcs_set_trigger(drv, i, false);
skip:
/* Reclaim the TCS */
- write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
- writel_relaxed(BIT(i), drv->tcs_base + RSC_DRV_IRQ_CLEAR);
+ write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
+ writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use);
/*
@@ -437,7 +475,7 @@ skip:
spin_unlock(&drv->lock);
wake_up(&drv->tcs_wait);
if (req)
- rpmh_tx_done(req, err);
+ rpmh_tx_done(req);
}
return IRQ_HANDLED;
@@ -475,14 +513,14 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
*/
msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
- write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid);
- write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr);
- write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
}
- cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id);
- write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable);
+ cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
+ write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
/**
@@ -514,10 +552,10 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
int i = tcs->offset;
for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
- curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i);
+ curr_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i);
for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
- addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, i, j);
+ addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
for (k = 0; k < msg->num_cmds; k++) {
if (addr == msg->cmds[k].addr)
return -EBUSY;
@@ -628,7 +666,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* repurposed TCS to avoid triggering them. tcs->slots will be
* cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
*/
- write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
+ write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
enable_tcs_irq(drv, tcs_id, true);
}
spin_unlock_irqrestore(&drv->lock, flags);
@@ -754,6 +792,48 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
}
/**
+ * rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS.
+ * @drv: The controller
+ *
+ * Writes maximum wakeup cycles when called from suspend.
+ * Writes earliest hrtimer wakeup when called from idle.
+ */
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
+{
+ ktime_t now, wakeup;
+ u64 wakeup_us, wakeup_cycles = ~0;
+ u32 lo, hi;
+
+ if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call)
+ return;
+
+ /* Set highest time when system (timekeeping) is suspended */
+ if (system_state == SYSTEM_SUSPEND)
+ goto exit;
+
+ /* Find the earliest hrtimer wakeup from online cpus */
+ wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev);
+
+ /* Find the relative wakeup in kernel time scale */
+ now = ktime_get();
+ wakeup = ktime_sub(wakeup, now);
+ wakeup_us = ktime_to_us(wakeup);
+
+ /* Convert the wakeup to arch timer scale */
+ wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
+ wakeup_cycles += arch_timer_read_counter();
+
+exit:
+ lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK;
+ hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE;
+ hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK;
+ hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID;
+
+ writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO);
+ writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI);
+}
+
+/**
* rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy.
* @nfb: Pointer to the notifier block in struct rsc_drv.
* @action: CPU_PM_ENTER, CPU_PM_ENTER_FAILED, or CPU_PM_EXIT.
@@ -834,8 +914,51 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb,
return ret;
}
-static int rpmh_probe_tcs_config(struct platform_device *pdev,
- struct rsc_drv *drv, void __iomem *base)
+/**
+ * rpmh_rsc_pd_callback() - Check if any of the AMCs are busy.
+ * @nfb: Pointer to the genpd notifier block in struct rsc_drv.
+ * @action: GENPD_NOTIFY_PRE_OFF, GENPD_NOTIFY_OFF, GENPD_NOTIFY_PRE_ON or GENPD_NOTIFY_ON.
+ * @v: Unused
+ *
+ * This function is given to dev_pm_genpd_add_notifier() so we can be informed
+ * about when cluster-pd is going down. When cluster go down we know no more active
+ * transfers will be started so we write sleep/wake sets. This function gets
+ * called from cpuidle code paths and also at system suspend time.
+ *
+ * If AMCs are not busy then writes cached sleep and wake messages to TCSes.
+ * The firmware then takes care of triggering them when entering deepest low power modes.
+ *
+ * Return:
+ * * NOTIFY_OK - success
+ * * NOTIFY_BAD - failure
+ */
+static int rpmh_rsc_pd_callback(struct notifier_block *nfb,
+ unsigned long action, void *v)
+{
+ struct rsc_drv *drv = container_of(nfb, struct rsc_drv, genpd_nb);
+
+ /* We don't need to lock as genpd on/off are serialized */
+ if ((action == GENPD_NOTIFY_PRE_OFF) &&
+ (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)))
+ return NOTIFY_BAD;
+
+ return NOTIFY_OK;
+}
+
+static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev)
+{
+ int ret;
+
+ pm_runtime_enable(dev);
+ drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback;
+ ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb);
+ if (ret)
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
{
struct tcs_type_config {
u32 type;
@@ -849,9 +972,9 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev,
ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
if (ret)
return ret;
- drv->tcs_base = base + offset;
+ drv->tcs_base = drv->base + offset;
- config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG);
+ config = readl_relaxed(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]);
max_tcs = config;
max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
@@ -913,7 +1036,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
char drv_id[10] = {0};
int ret, irq;
u32 solver_config;
- void __iomem *base;
+ u32 rsc_id;
/*
* Even though RPMh doesn't directly use cmd-db, all of its children
@@ -940,11 +1063,22 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->name = dev_name(&pdev->dev);
snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
- base = devm_platform_ioremap_resource_byname(pdev, drv_id);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id);
+ if (IS_ERR(drv->base))
+ return PTR_ERR(drv->base);
+
+ rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
+ drv->ver.major = rsc_id & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
+ drv->ver.major >>= MAJOR_VER_SHIFT;
+ drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
+ drv->ver.minor >>= MINOR_VER_SHIFT;
+
+ if (drv->ver.major == 3 && drv->ver.minor == 0)
+ drv->regs = rpmh_rsc_reg_offset_ver_3_0;
+ else
+ drv->regs = rpmh_rsc_reg_offset_ver_2_7;
- ret = rpmh_probe_tcs_config(pdev, drv, base);
+ ret = rpmh_probe_tcs_config(pdev, drv);
if (ret)
return ret;
@@ -963,29 +1097,42 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
return ret;
/*
- * CPU PM notification are not required for controllers that support
+ * CPU PM/genpd notification are not required for controllers that support
* 'HW solver' mode where they can be in autonomous mode executing low
* power mode to power down.
*/
- solver_config = readl_relaxed(base + DRV_SOLVER_CONFIG);
+ solver_config = readl_relaxed(drv->base + drv->regs[DRV_SOLVER_CONFIG]);
solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
if (!solver_config) {
- drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
- cpu_pm_register_notifier(&drv->rsc_pm);
+ if (pdev->dev.pm_domain) {
+ ret = rpmh_rsc_pd_attach(drv, &pdev->dev);
+ if (ret)
+ return ret;
+ } else {
+ drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
+ cpu_pm_register_notifier(&drv->rsc_pm);
+ }
}
/* Enable the active TCS to send requests immediately */
writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
- drv->tcs_base + RSC_DRV_IRQ_ENABLE);
+ drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
spin_lock_init(&drv->client.cache_lock);
INIT_LIST_HEAD(&drv->client.cache);
INIT_LIST_HEAD(&drv->client.batch_cache);
dev_set_drvdata(&pdev->dev, drv);
+ drv->dev = &pdev->dev;
+
+ ret = devm_of_platform_populate(&pdev->dev);
+ if (ret && pdev->dev.pm_domain) {
+ dev_pm_genpd_remove_notifier(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ }
- return devm_of_platform_populate(&pdev->dev);
+ return ret;
}
static const struct of_device_id rpmh_drv_match[] = {
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 01765ee9cdfb..08e09642d7f5 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -76,19 +76,13 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
return &drv->client;
}
-void rpmh_tx_done(const struct tcs_request *msg, int r)
+void rpmh_tx_done(const struct tcs_request *msg)
{
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
msg);
struct completion *compl = rpm_msg->completion;
bool free = rpm_msg->needs_free;
- rpm_msg->err = r;
-
- if (r)
- dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n",
- rpm_msg->msg.cmds[0].addr, r);
-
if (!compl)
goto exit;
@@ -194,7 +188,7 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
} else {
/* Clean up our call by spoofing tx_done */
ret = 0;
- rpmh_tx_done(&rpm_msg->msg, ret);
+ rpmh_tx_done(&rpm_msg->msg);
}
return ret;
@@ -450,7 +444,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
if (!ctrlr->dirty) {
pr_debug("Skipping flush, TCS has latest data.\n");
- goto exit;
+ goto write_next_wakeup;
}
/* Invalidate the TCSes first to avoid stale data */
@@ -479,6 +473,8 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
ctrlr->dirty = false;
+write_next_wakeup:
+ rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr));
exit:
spin_unlock(&ctrlr->cache_lock);
return ret;
diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
index 092f6ab09acf..4c2d2c296790 100644
--- a/drivers/soc/qcom/rpmhpd.c
+++ b/drivers/soc/qcom/rpmhpd.c
@@ -39,6 +39,7 @@
* @res_name: Resource name used for cmd-db lookup
* @addr: Resource address as looped up using resource name from
* cmd-db
+ * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource
*/
struct rpmhpd {
struct device *dev;
@@ -54,6 +55,7 @@ struct rpmhpd {
bool enabled;
const char *res_name;
u32 addr;
+ bool state_synced;
};
struct rpmhpd_desc {
@@ -210,6 +212,23 @@ static const struct rpmhpd_desc sa8540p_desc = {
.num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
};
+/* SDM670 RPMH powerdomains */
+static struct rpmhpd *sdm670_rpmhpds[] = {
+ [SDM670_CX] = &cx_w_mx_parent,
+ [SDM670_CX_AO] = &cx_ao_w_mx_parent,
+ [SDM670_GFX] = &gfx,
+ [SDM670_LCX] = &lcx,
+ [SDM670_LMX] = &lmx,
+ [SDM670_MSS] = &mss,
+ [SDM670_MX] = &mx,
+ [SDM670_MX_AO] = &mx_ao,
+};
+
+static const struct rpmhpd_desc sdm670_desc = {
+ .rpmhpds = sdm670_rpmhpds,
+ .num_pds = ARRAY_SIZE(sdm670_rpmhpds),
+};
+
/* SDM845 RPMH powerdomains */
static struct rpmhpd *sdm845_rpmhpds[] = {
[SDM845_CX] = &cx_w_mx_parent,
@@ -353,6 +372,42 @@ static const struct rpmhpd_desc sm8450_desc = {
.num_pds = ARRAY_SIZE(sm8450_rpmhpds),
};
+/* SM8550 RPMH powerdomains */
+static struct rpmhpd *sm8550_rpmhpds[] = {
+ [SM8550_CX] = &cx,
+ [SM8550_CX_AO] = &cx_ao,
+ [SM8550_EBI] = &ebi,
+ [SM8550_GFX] = &gfx,
+ [SM8550_LCX] = &lcx,
+ [SM8550_LMX] = &lmx,
+ [SM8550_MMCX] = &mmcx_w_cx_parent,
+ [SM8550_MMCX_AO] = &mmcx_ao_w_cx_parent,
+ [SM8550_MSS] = &mss,
+ [SM8550_MX] = &mx,
+ [SM8550_MX_AO] = &mx_ao,
+ [SM8550_MXC] = &mxc,
+ [SM8550_MXC_AO] = &mxc_ao,
+ [SM8550_NSP] = &nsp,
+};
+
+static const struct rpmhpd_desc sm8550_desc = {
+ .rpmhpds = sm8550_rpmhpds,
+ .num_pds = ARRAY_SIZE(sm8550_rpmhpds),
+};
+
+/* QDU1000/QRU1000 RPMH powerdomains */
+static struct rpmhpd *qdu1000_rpmhpds[] = {
+ [QDU1000_CX] = &cx,
+ [QDU1000_EBI] = &ebi,
+ [QDU1000_MSS] = &mss,
+ [QDU1000_MX] = &mx,
+};
+
+static const struct rpmhpd_desc qdu1000_desc = {
+ .rpmhpds = qdu1000_rpmhpds,
+ .num_pds = ARRAY_SIZE(qdu1000_rpmhpds),
+};
+
/* SC7180 RPMH powerdomains */
static struct rpmhpd *sc7180_rpmhpds[] = {
[SC7180_CX] = &cx_w_mx_parent,
@@ -430,11 +485,13 @@ static const struct rpmhpd_desc sc8280xp_desc = {
};
static const struct of_device_id rpmhpd_match_table[] = {
+ { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
{ .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
{ .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
+ { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
{ .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
@@ -443,6 +500,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
{ .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
+ { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
@@ -493,7 +551,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
unsigned int this_active_corner = 0, this_sleep_corner = 0;
unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
- to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
+ if (pd->state_synced) {
+ to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
+ } else {
+ /* Clamp to highest corner if sync_state hasn't happened */
+ this_active_corner = pd->level_count - 1;
+ this_sleep_corner = pd->level_count - 1;
+ }
if (peer && peer->enabled)
to_active_sleep(peer, peer->corner, &peer_active_corner,
@@ -708,11 +772,40 @@ static int rpmhpd_probe(struct platform_device *pdev)
return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
}
+static void rpmhpd_sync_state(struct device *dev)
+{
+ const struct rpmhpd_desc *desc = of_device_get_match_data(dev);
+ struct rpmhpd **rpmhpds = desc->rpmhpds;
+ unsigned int corner;
+ struct rpmhpd *pd;
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&rpmhpd_lock);
+ for (i = 0; i < desc->num_pds; i++) {
+ pd = rpmhpds[i];
+ if (!pd)
+ continue;
+
+ pd->state_synced = true;
+ if (pd->enabled)
+ corner = max(pd->corner, pd->enable_corner);
+ else
+ corner = 0;
+
+ ret = rpmhpd_aggregate_corner(pd, corner);
+ if (ret)
+ dev_err(dev, "failed to sync %s\n", pd->res_name);
+ }
+ mutex_unlock(&rpmhpd_lock);
+}
+
static struct platform_driver rpmhpd_driver = {
.driver = {
.name = "qcom-rpmhpd",
.of_match_table = rpmhpd_match_table,
.suppress_bind_attrs = true,
+ .sync_state = rpmhpd_sync_state,
},
.probe = rpmhpd_probe,
};
diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
index 337b1ad1cd3b..f0db6a10cf4e 100644
--- a/drivers/soc/qcom/rpmpd.c
+++ b/drivers/soc/qcom/rpmpd.c
@@ -471,6 +471,23 @@ static const struct rpmpd_desc qcm2290_desc = {
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
+static struct rpmpd *sm4250_rpmpds[] = {
+ [SM4250_VDDCX] = &sm6115_vddcx,
+ [SM4250_VDDCX_AO] = &sm6115_vddcx_ao,
+ [SM4250_VDDCX_VFL] = &sm6115_vddcx_vfl,
+ [SM4250_VDDMX] = &sm6115_vddmx,
+ [SM4250_VDDMX_AO] = &sm6115_vddmx_ao,
+ [SM4250_VDDMX_VFL] = &sm6115_vddmx_vfl,
+ [SM4250_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
+ [SM4250_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
+};
+
+static const struct rpmpd_desc sm4250_desc = {
+ .rpmpds = sm4250_rpmpds,
+ .num_pds = ARRAY_SIZE(sm4250_rpmpds),
+ .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
+};
+
static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
@@ -485,6 +502,7 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
+ { .compatible = "qcom,sm4250-rpmpd", .data = &sm4250_desc },
{ .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
{ .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
{ .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 413f9f4ae9cd..7e3b6a7ea34c 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -75,7 +75,7 @@ struct qcom_rpm_message {
__le32 length;
union {
__le32 msg_id;
- u8 message[0];
+ DECLARE_FLEX_ARRAY(u8, message);
};
};
@@ -246,6 +246,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-sdm660" },
{ .compatible = "qcom,rpm-sm6115" },
{ .compatible = "qcom,rpm-sm6125" },
+ { .compatible = "qcom,rpm-sm6375" },
{ .compatible = "qcom,rpm-qcm2290" },
{ .compatible = "qcom,rpm-qcs404" },
{}
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index d9c28a8a7cbf..e9c8030d50ee 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -422,7 +422,7 @@ static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
char buf[SMP2P_MAX_ENTRY_NAME] = {};
/* Allocate an entry from the smem item */
- strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
+ strscpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
/* Make the logical entry reference the physical value */
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index aa37e1bad095..ebcbf9b9c18b 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -12,11 +12,14 @@
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
#include <linux/string.h>
+#include <linux/stringify.h>
#include <linux/sys_soc.h>
#include <linux/types.h>
#include <asm/unaligned.h>
+#include <dt-bindings/arm/qcom,ids.h>
+
/*
* SoC version type with major number in the upper 16 bits and minor
* number in the lower 16 bits.
@@ -25,6 +28,10 @@
#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
+/* Helper macros to create soc_id table */
+#define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id)
+#define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name)
+
#define SMEM_SOCINFO_BUILD_ID_LENGTH 32
#define SMEM_SOCINFO_CHIP_ID_LENGTH 32
@@ -207,135 +214,150 @@ struct soc_id {
};
static const struct soc_id soc_id[] = {
- { 87, "MSM8960" },
- { 109, "APQ8064" },
- { 122, "MSM8660A" },
- { 123, "MSM8260A" },
- { 124, "APQ8060A" },
- { 126, "MSM8974" },
- { 130, "MPQ8064" },
- { 138, "MSM8960AB" },
- { 139, "APQ8060AB" },
- { 140, "MSM8260AB" },
- { 141, "MSM8660AB" },
- { 145, "MSM8626" },
- { 147, "MSM8610" },
- { 153, "APQ8064AB" },
- { 158, "MSM8226" },
- { 159, "MSM8526" },
- { 161, "MSM8110" },
- { 162, "MSM8210" },
- { 163, "MSM8810" },
- { 164, "MSM8212" },
- { 165, "MSM8612" },
- { 166, "MSM8112" },
- { 168, "MSM8225Q" },
- { 169, "MSM8625Q" },
- { 170, "MSM8125Q" },
- { 172, "APQ8064AA" },
- { 178, "APQ8084" },
- { 184, "APQ8074" },
- { 185, "MSM8274" },
- { 186, "MSM8674" },
- { 194, "MSM8974PRO-AC" },
- { 198, "MSM8126" },
- { 199, "APQ8026" },
- { 200, "MSM8926" },
- { 205, "MSM8326" },
- { 206, "MSM8916" },
- { 207, "MSM8994" },
- { 208, "APQ8074PRO-AA" },
- { 209, "APQ8074PRO-AB" },
- { 210, "APQ8074PRO-AC" },
- { 211, "MSM8274PRO-AA" },
- { 212, "MSM8274PRO-AB" },
- { 213, "MSM8274PRO-AC" },
- { 214, "MSM8674PRO-AA" },
- { 215, "MSM8674PRO-AB" },
- { 216, "MSM8674PRO-AC" },
- { 217, "MSM8974PRO-AA" },
- { 218, "MSM8974PRO-AB" },
- { 219, "APQ8028" },
- { 220, "MSM8128" },
- { 221, "MSM8228" },
- { 222, "MSM8528" },
- { 223, "MSM8628" },
- { 224, "MSM8928" },
- { 225, "MSM8510" },
- { 226, "MSM8512" },
- { 233, "MSM8936" },
- { 239, "MSM8939" },
- { 240, "APQ8036" },
- { 241, "APQ8039" },
- { 246, "MSM8996" },
- { 247, "APQ8016" },
- { 248, "MSM8216" },
- { 249, "MSM8116" },
- { 250, "MSM8616" },
- { 251, "MSM8992" },
- { 253, "APQ8094" },
- { 290, "MDM9607" },
- { 291, "APQ8096" },
- { 292, "MSM8998" },
- { 293, "MSM8953" },
- { 296, "MDM8207" },
- { 297, "MDM9207" },
- { 298, "MDM9307" },
- { 299, "MDM9628" },
- { 304, "APQ8053" },
- { 305, "MSM8996SG" },
- { 310, "MSM8996AU" },
- { 311, "APQ8096AU" },
- { 312, "APQ8096SG" },
- { 317, "SDM660" },
- { 318, "SDM630" },
- { 319, "APQ8098" },
- { 321, "SDM845" },
- { 322, "MDM9206" },
- { 323, "IPQ8074" },
- { 324, "SDA660" },
- { 325, "SDM658" },
- { 326, "SDA658" },
- { 327, "SDA630" },
- { 338, "SDM450" },
- { 341, "SDA845" },
- { 342, "IPQ8072" },
- { 343, "IPQ8076" },
- { 344, "IPQ8078" },
- { 345, "SDM636" },
- { 346, "SDA636" },
- { 349, "SDM632" },
- { 350, "SDA632" },
- { 351, "SDA450" },
- { 356, "SM8250" },
- { 375, "IPQ8070" },
- { 376, "IPQ8071" },
- { 389, "IPQ8072A" },
- { 390, "IPQ8074A" },
- { 391, "IPQ8076A" },
- { 392, "IPQ8078A" },
- { 394, "SM6125" },
- { 395, "IPQ8070A" },
- { 396, "IPQ8071A" },
- { 402, "IPQ6018" },
- { 403, "IPQ6028" },
- { 421, "IPQ6000" },
- { 422, "IPQ6010" },
- { 425, "SC7180" },
- { 434, "SM6350" },
- { 439, "SM8350" },
- { 449, "SC8280XP" },
- { 453, "IPQ6005" },
- { 455, "QRB5165" },
- { 457, "SM8450" },
- { 459, "SM7225" },
- { 460, "SA8295P" },
- { 461, "SA8540P" },
- { 480, "SM8450" },
- { 482, "SM8450" },
- { 487, "SC7280" },
- { 495, "SC7180P" },
- { 507, "SM6375" },
+ { qcom_board_id(MSM8960) },
+ { qcom_board_id(APQ8064) },
+ { qcom_board_id(MSM8660A) },
+ { qcom_board_id(MSM8260A) },
+ { qcom_board_id(APQ8060A) },
+ { qcom_board_id(MSM8974) },
+ { qcom_board_id(MPQ8064) },
+ { qcom_board_id(MSM8960AB) },
+ { qcom_board_id(APQ8060AB) },
+ { qcom_board_id(MSM8260AB) },
+ { qcom_board_id(MSM8660AB) },
+ { qcom_board_id(MSM8626) },
+ { qcom_board_id(MSM8610) },
+ { qcom_board_id(APQ8064AB) },
+ { qcom_board_id(MSM8226) },
+ { qcom_board_id(MSM8526) },
+ { qcom_board_id(MSM8110) },
+ { qcom_board_id(MSM8210) },
+ { qcom_board_id(MSM8810) },
+ { qcom_board_id(MSM8212) },
+ { qcom_board_id(MSM8612) },
+ { qcom_board_id(MSM8112) },
+ { qcom_board_id(MSM8225Q) },
+ { qcom_board_id(MSM8625Q) },
+ { qcom_board_id(MSM8125Q) },
+ { qcom_board_id(APQ8064AA) },
+ { qcom_board_id(APQ8084) },
+ { qcom_board_id(APQ8074) },
+ { qcom_board_id(MSM8274) },
+ { qcom_board_id(MSM8674) },
+ { qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
+ { qcom_board_id(MSM8126) },
+ { qcom_board_id(APQ8026) },
+ { qcom_board_id(MSM8926) },
+ { qcom_board_id(MSM8326) },
+ { qcom_board_id(MSM8916) },
+ { qcom_board_id(MSM8956) },
+ { qcom_board_id(MSM8976) },
+ { qcom_board_id(MSM8994) },
+ { qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
+ { qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
+ { qcom_board_id_named(APQ8074PRO_AC, "APQ8074PRO-AC") },
+ { qcom_board_id_named(MSM8274PRO_AA, "MSM8274PRO-AA") },
+ { qcom_board_id_named(MSM8274PRO_AB, "MSM8274PRO-AB") },
+ { qcom_board_id_named(MSM8274PRO_AC, "MSM8274PRO-AC") },
+ { qcom_board_id_named(MSM8674PRO_AA, "MSM8674PRO-AA") },
+ { qcom_board_id_named(MSM8674PRO_AB, "MSM8674PRO-AB") },
+ { qcom_board_id_named(MSM8674PRO_AC, "MSM8674PRO-AC") },
+ { qcom_board_id_named(MSM8974PRO_AA, "MSM8974PRO-AA") },
+ { qcom_board_id_named(MSM8974PRO_AB, "MSM8974PRO-AB") },
+ { qcom_board_id(APQ8028) },
+ { qcom_board_id(MSM8128) },
+ { qcom_board_id(MSM8228) },
+ { qcom_board_id(MSM8528) },
+ { qcom_board_id(MSM8628) },
+ { qcom_board_id(MSM8928) },
+ { qcom_board_id(MSM8510) },
+ { qcom_board_id(MSM8512) },
+ { qcom_board_id(MSM8936) },
+ { qcom_board_id(MSM8939) },
+ { qcom_board_id(APQ8036) },
+ { qcom_board_id(APQ8039) },
+ { qcom_board_id(MSM8996) },
+ { qcom_board_id(APQ8016) },
+ { qcom_board_id(MSM8216) },
+ { qcom_board_id(MSM8116) },
+ { qcom_board_id(MSM8616) },
+ { qcom_board_id(MSM8992) },
+ { qcom_board_id(APQ8094) },
+ { qcom_board_id(MDM9607) },
+ { qcom_board_id(APQ8096) },
+ { qcom_board_id(MSM8998) },
+ { qcom_board_id(MSM8953) },
+ { qcom_board_id(MDM8207) },
+ { qcom_board_id(MDM9207) },
+ { qcom_board_id(MDM9307) },
+ { qcom_board_id(MDM9628) },
+ { qcom_board_id(APQ8053) },
+ { qcom_board_id(MSM8996SG) },
+ { qcom_board_id(MSM8996AU) },
+ { qcom_board_id(APQ8096AU) },
+ { qcom_board_id(APQ8096SG) },
+ { qcom_board_id(SDM660) },
+ { qcom_board_id(SDM630) },
+ { qcom_board_id(APQ8098) },
+ { qcom_board_id(SDM845) },
+ { qcom_board_id(MDM9206) },
+ { qcom_board_id(IPQ8074) },
+ { qcom_board_id(SDA660) },
+ { qcom_board_id(SDM658) },
+ { qcom_board_id(SDA658) },
+ { qcom_board_id(SDA630) },
+ { qcom_board_id(SDM450) },
+ { qcom_board_id(SM8150) },
+ { qcom_board_id(SDA845) },
+ { qcom_board_id(IPQ8072) },
+ { qcom_board_id(IPQ8076) },
+ { qcom_board_id(IPQ8078) },
+ { qcom_board_id(SDM636) },
+ { qcom_board_id(SDA636) },
+ { qcom_board_id(SDM632) },
+ { qcom_board_id(SDA632) },
+ { qcom_board_id(SDA450) },
+ { qcom_board_id(SM8250) },
+ { qcom_board_id(SA8155) },
+ { qcom_board_id(IPQ8070) },
+ { qcom_board_id(IPQ8071) },
+ { qcom_board_id(IPQ8072A) },
+ { qcom_board_id(IPQ8074A) },
+ { qcom_board_id(IPQ8076A) },
+ { qcom_board_id(IPQ8078A) },
+ { qcom_board_id(SM6125) },
+ { qcom_board_id(IPQ8070A) },
+ { qcom_board_id(IPQ8071A) },
+ { qcom_board_id(IPQ6018) },
+ { qcom_board_id(IPQ6028) },
+ { qcom_board_id(SM4250) },
+ { qcom_board_id(IPQ6000) },
+ { qcom_board_id(IPQ6010) },
+ { qcom_board_id(SC7180) },
+ { qcom_board_id(SM6350) },
+ { qcom_board_id(SM8350) },
+ { qcom_board_id(SM6115) },
+ { qcom_board_id(SC8280XP) },
+ { qcom_board_id(IPQ6005) },
+ { qcom_board_id(QRB5165) },
+ { qcom_board_id(SM8450) },
+ { qcom_board_id(SM8550) },
+ { qcom_board_id(SM7225) },
+ { qcom_board_id(SA8295P) },
+ { qcom_board_id(SA8540P) },
+ { qcom_board_id(QCM4290) },
+ { qcom_board_id(QCS4290) },
+ { qcom_board_id_named(SM8450_2, "SM8450") },
+ { qcom_board_id_named(SM8450_3, "SM8450") },
+ { qcom_board_id(SC7280) },
+ { qcom_board_id(SC7180P) },
+ { qcom_board_id(SM6375) },
+ { qcom_board_id(QRU1000) },
+ { qcom_board_id(QDU1000) },
+ { qcom_board_id(QDU1010) },
+ { qcom_board_id(QRU1032) },
+ { qcom_board_id(QRU1052) },
+ { qcom_board_id(QRU1062) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index 484b42b7454e..a6cbeb40831b 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -98,6 +98,46 @@ static const struct spm_reg_data spm_reg_8916_cpu = {
.start_index[PM_SLEEP_MODE_SPC] = 5,
};
+static const struct spm_reg_data spm_reg_8939_cpu = {
+ .reg_offset = spm_reg_offset_v3_0,
+ .spm_cfg = 0x1,
+ .spm_dly = 0x3C102800,
+ .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x50, 0x1B, 0x10, 0x80,
+ 0x30, 0x90, 0x5B, 0x60, 0x50, 0x03, 0x60, 0x76, 0x76, 0x0B,
+ 0x50, 0x1B, 0x94, 0x5B, 0x80, 0x10, 0x26, 0x30, 0x50, 0x0F },
+ .start_index[PM_SLEEP_MODE_STBY] = 0,
+ .start_index[PM_SLEEP_MODE_SPC] = 5,
+};
+
+static const u16 spm_reg_offset_v2_3[SPM_REG_NR] = {
+ [SPM_REG_CFG] = 0x08,
+ [SPM_REG_SPM_CTL] = 0x30,
+ [SPM_REG_DLY] = 0x34,
+ [SPM_REG_PMIC_DATA_0] = 0x40,
+ [SPM_REG_PMIC_DATA_1] = 0x44,
+};
+
+/* SPM register data for 8976 */
+static const struct spm_reg_data spm_reg_8976_gold_l2 = {
+ .reg_offset = spm_reg_offset_v2_3,
+ .spm_cfg = 0x14,
+ .spm_dly = 0x3c11840a,
+ .pmic_data[0] = 0x03030080,
+ .pmic_data[1] = 0x00030000,
+ .start_index[PM_SLEEP_MODE_STBY] = 0,
+ .start_index[PM_SLEEP_MODE_SPC] = 3,
+};
+
+static const struct spm_reg_data spm_reg_8976_silver_l2 = {
+ .reg_offset = spm_reg_offset_v2_3,
+ .spm_cfg = 0x14,
+ .spm_dly = 0x3c102800,
+ .pmic_data[0] = 0x03030080,
+ .pmic_data[1] = 0x00030000,
+ .start_index[PM_SLEEP_MODE_STBY] = 0,
+ .start_index[PM_SLEEP_MODE_SPC] = 2,
+};
+
static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
[SPM_REG_SPM_CTL] = 0x30,
@@ -211,8 +251,14 @@ static const struct of_device_id spm_match_table[] = {
.data = &spm_reg_8909_cpu },
{ .compatible = "qcom,msm8916-saw2-v3.0-cpu",
.data = &spm_reg_8916_cpu },
+ { .compatible = "qcom,msm8939-saw2-v3.0-cpu",
+ .data = &spm_reg_8939_cpu },
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
.data = &spm_reg_8974_8084_cpu },
+ { .compatible = "qcom,msm8976-gold-saw2-v2.3-l2",
+ .data = &spm_reg_8976_gold_l2 },
+ { .compatible = "qcom,msm8976-silver-saw2-v2.3-l2",
+ .data = &spm_reg_8976_silver_l2 },
{ .compatible = "qcom,msm8998-gold-saw2-v4.1-l2",
.data = &spm_reg_8998_gold_l2 },
{ .compatible = "qcom,msm8998-silver-saw2-v4.1-l2",
diff --git a/drivers/soc/qcom/trace-rpmh.h b/drivers/soc/qcom/trace-rpmh.h
index feb0cb455e37..12b676b20cb2 100644
--- a/drivers/soc/qcom/trace-rpmh.h
+++ b/drivers/soc/qcom/trace-rpmh.h
@@ -14,16 +14,15 @@
TRACE_EVENT(rpmh_tx_done,
- TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
+ TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r),
- TP_ARGS(d, m, r, e),
+ TP_ARGS(d, m, r),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
__field(u32, addr)
__field(u32, data)
- __field(int, err)
),
TP_fast_assign(
@@ -31,12 +30,10 @@ TRACE_EVENT(rpmh_tx_done,
__entry->m = m;
__entry->addr = r->cmds[0].addr;
__entry->data = r->cmds[0].data;
- __entry->err = e;
),
- TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
- __get_str(name), __entry->m, __entry->addr, __entry->data,
- __entry->err)
+ TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x",
+ __get_str(name), __entry->m, __entry->addr, __entry->data)
);
TRACE_EVENT(rpmh_send_msg,
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index f95a1337450d..660498252ec5 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -2,6 +2,8 @@
menuconfig SOC_RENESAS
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
default y if ARCH_RENESAS
+ select GPIOLIB
+ select PINCTRL
select SOC_BUS
if SOC_RENESAS
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 621ceaa047d4..468ebce1ea88 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -76,6 +76,10 @@ static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
.name = "RZ/V2L",
};
+static const struct renesas_family fam_rzv2m __initconst __maybe_unused = {
+ .name = "RZ/V2M",
+};
+
static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
.name = "SH-Mobile",
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@@ -171,6 +175,10 @@ static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
.id = 0x8447447,
};
+static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = {
+ .family = &fam_rzv2m,
+};
+
static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
.family = &fam_rcar_gen1,
};
@@ -380,6 +388,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
#if defined(CONFIG_ARCH_R9A07G054)
{ .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
#endif
+#if defined(CONFIG_ARCH_R9A09G011)
+ { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
+#endif
#ifdef CONFIG_ARCH_SH73A0
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
#endif
@@ -405,6 +416,11 @@ static const struct renesas_id id_rzg2l __initconst = {
.mask = 0xfffffff,
};
+static const struct renesas_id id_rzv2m __initconst = {
+ .offset = 0x104,
+ .mask = 0xff,
+};
+
static const struct renesas_id id_prr __initconst = {
.offset = 0,
.mask = 0xff00,
@@ -415,6 +431,7 @@ static const struct of_device_id renesas_ids[] __initconst = {
{ .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m },
{ .compatible = "renesas,prr", .data = &id_prr },
{ /* sentinel */ }
};
@@ -485,6 +502,11 @@ static int __init renesas_soc_init(void)
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
eshi);
rev_prefix = "Rev ";
+ } else if (id == &id_rzv2m) {
+ eshi = ((product >> 4) & 0x0f);
+ eslo = product & 0xf;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u",
+ eshi, eslo);
}
if (soc->id &&
diff --git a/drivers/soc/sifive/sifive_ccache.c b/drivers/soc/sifive/sifive_ccache.c
index 1c171150e878..3684f5b40a80 100644
--- a/drivers/soc/sifive/sifive_ccache.c
+++ b/drivers/soc/sifive/sifive_ccache.c
@@ -215,20 +215,27 @@ static int __init sifive_ccache_init(void)
if (!np)
return -ENODEV;
- if (of_address_to_resource(np, 0, &res))
- return -ENODEV;
+ if (of_address_to_resource(np, 0, &res)) {
+ rc = -ENODEV;
+ goto err_node_put;
+ }
ccache_base = ioremap(res.start, resource_size(&res));
- if (!ccache_base)
- return -ENOMEM;
+ if (!ccache_base) {
+ rc = -ENOMEM;
+ goto err_node_put;
+ }
- if (of_property_read_u32(np, "cache-level", &level))
- return -ENOENT;
+ if (of_property_read_u32(np, "cache-level", &level)) {
+ rc = -ENOENT;
+ goto err_unmap;
+ }
intr_num = of_property_count_u32_elems(np, "interrupts");
if (!intr_num) {
pr_err("No interrupts property\n");
- return -ENODEV;
+ rc = -ENODEV;
+ goto err_unmap;
}
for (i = 0; i < intr_num; i++) {
@@ -237,9 +244,10 @@ static int __init sifive_ccache_init(void)
NULL);
if (rc) {
pr_err("Could not request IRQ %d\n", g_irq[i]);
- return rc;
+ goto err_free_irq;
}
}
+ of_node_put(np);
ccache_config_read();
@@ -250,6 +258,15 @@ static int __init sifive_ccache_init(void)
setup_sifive_debug();
#endif
return 0;
+
+err_free_irq:
+ while (--i >= 0)
+ free_irq(g_irq[i], NULL);
+err_unmap:
+ iounmap(ccache_base);
+err_node_put:
+ of_node_put(np);
+ return rc;
}
device_initcall(sifive_ccache_init);
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index d1ecadffa1bb..5f5324294636 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -143,6 +143,7 @@ config SOC_TEGRA_FLOWCTRL
config SOC_TEGRA_PMC
bool
select GENERIC_PINCONF
+ select IRQ_DOMAIN_HIERARCHY
select PM_OPP
select PM_GENERIC_DOMAINS
select REGMAP
diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c
index d200937353c7..a8566b9dd8de 100644
--- a/drivers/soc/tegra/cbb/tegra-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra-cbb.c
@@ -72,18 +72,7 @@ static int tegra_cbb_err_show(struct seq_file *file, void *data)
return cbb->ops->debugfs_show(cbb, file, data);
}
-
-static int tegra_cbb_err_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tegra_cbb_err_show, inode->i_private);
-}
-
-static const struct file_operations tegra_cbb_err_fops = {
- .open = tegra_cbb_err_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release
-};
+DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err);
static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb)
{
diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c
index 1ae0bd9a1ac1..d4112b683f00 100644
--- a/drivers/soc/tegra/cbb/tegra194-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra194-cbb.c
@@ -102,8 +102,6 @@
#define CLUSTER_NOC_VQC GENMASK(17, 16)
#define CLUSTER_NOC_MSTR_ID GENMASK(21, 18)
-#define USRBITS_MSTR_ID GENMASK(21, 18)
-
#define CBB_ERR_OPC GENMASK(4, 1)
#define CBB_ERR_ERRCODE GENMASK(10, 8)
#define CBB_ERR_LEN1 GENMASK(27, 16)
@@ -2038,15 +2036,17 @@ static irqreturn_t tegra194_cbb_err_isr(int irq, void *data)
smp_processor_id(), priv->noc->name, priv->res->start,
irq);
- mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->errlog5) - 1;
is_fatal = print_errlog(NULL, priv, status);
/*
- * If illegal request is from CCPLEX(0x1)
- * initiator then call BUG() to crash system.
+ * If illegal request is from CCPLEX(0x1) initiator
+ * and error is fatal then call BUG() to crash system.
*/
- if ((mstr_id == 0x1) && priv->noc->erd_mask_inband_err)
- is_inband_err = 1;
+ if (priv->noc->erd_mask_inband_err) {
+ mstr_id = FIELD_GET(CBB_NOC_MSTR_ID, priv->errlog5);
+ if (mstr_id == 0x1)
+ is_inband_err = 1;
+ }
}
}
@@ -2226,10 +2226,8 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node
cbb->bridges[i].base = devm_ioremap_resource(cbb->base.dev,
&cbb->bridges[i].res);
- if (IS_ERR(cbb->bridges[i].base)) {
- dev_err(cbb->base.dev, "failed to map AXI2APB range\n");
+ if (IS_ERR(cbb->bridges[i].base))
return PTR_ERR(cbb->bridges[i].base);
- }
}
}
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index 3528f9e15d5c..f33d094e5ea6 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -72,6 +72,11 @@
#define REQ_SOCKET_ID GENMASK(27, 24)
+#define CCPLEX_MSTRID 0x1
+#define FIREWALL_APERTURE_SZ 0x10000
+/* Write firewall check enable */
+#define WEN 0x20000
+
enum tegra234_cbb_fabric_ids {
CBB_FAB_ID,
SCE_FAB_ID,
@@ -92,11 +97,15 @@ struct tegra234_slave_lookup {
struct tegra234_cbb_fabric {
const char *name;
phys_addr_t off_mask_erd;
- bool erd_mask_inband_err;
+ phys_addr_t firewall_base;
+ unsigned int firewall_ctl;
+ unsigned int firewall_wr_ctl;
const char * const *master_id;
unsigned int notifier_offset;
const struct tegra_cbb_error *errors;
+ const int max_errors;
const struct tegra234_slave_lookup *slave_map;
+ const int max_slaves;
};
struct tegra234_cbb {
@@ -128,6 +137,44 @@ static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
static LIST_HEAD(cbb_list);
static DEFINE_SPINLOCK(cbb_lock);
+static bool
+tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb)
+{
+ u32 val;
+
+ if (!cbb->fabric->firewall_base ||
+ !cbb->fabric->firewall_ctl ||
+ !cbb->fabric->firewall_wr_ctl) {
+ dev_info(&pdev->dev, "SoC data missing for firewall\n");
+ return false;
+ }
+
+ if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) ||
+ (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) {
+ dev_err(&pdev->dev, "wrong firewall offset value\n");
+ return false;
+ }
+
+ val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl);
+ /*
+ * If the firewall check feature for allowing or blocking the
+ * write accesses through the firewall of a fabric is disabled
+ * then CCPLEX can write to the registers of that fabric.
+ */
+ if (!(val & WEN))
+ return true;
+
+ /*
+ * If the firewall check is enabled then check whether CCPLEX
+ * has write access to the fabric's error notifier registers
+ */
+ val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl);
+ if (val & (BIT(CCPLEX_MSTRID)))
+ return true;
+
+ return false;
+}
+
static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
{
struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
@@ -271,6 +318,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb
tegra_cbb_print_err(file, "\t Multiple type of errors reported\n");
while (status) {
+ if (type >= cbb->fabric->max_errors) {
+ tegra_cbb_print_err(file, "\t Wrong type index:%u, status:%u\n",
+ type, status);
+ return;
+ }
+
if (status & 0x1)
tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
cbb->fabric->errors[type].code);
@@ -282,6 +335,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb
type = 0;
while (overflow) {
+ if (type >= cbb->fabric->max_errors) {
+ tegra_cbb_print_err(file, "\t Wrong type index:%u, overflow:%u\n",
+ type, overflow);
+ return;
+ }
+
if (overflow & 0x1)
tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n",
cbb->fabric->errors[type].code);
@@ -334,8 +393,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0);
tegra_cbb_print_err(file, "\n");
- tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
- cbb->fabric->errors[cbb->type].code);
+ if (cbb->type < cbb->fabric->max_errors)
+ tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
+ cbb->fabric->errors[cbb->type].code);
+ else
+ tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type);
tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]);
tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access);
@@ -374,6 +436,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID))
return;
+ if (slave_id >= cbb->fabric->max_slaves) {
+ tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id);
+ return;
+ }
+
if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id);
return;
@@ -517,7 +584,7 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
u32 status = tegra_cbb_get_status(cbb);
if (status && (irq == priv->sec_irq)) {
- tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@%llx, irq=%d\n",
+ tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
smp_processor_id(), priv->fabric->name,
priv->res->start, irq);
@@ -525,14 +592,14 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
if (err)
goto unlock;
- mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
-
/*
- * If illegal request is from CCPLEX(id:0x1) master then call BUG() to
- * crash system.
+ * If illegal request is from CCPLEX(id:0x1) master then call WARN()
*/
- if ((mstr_id == 0x1) && priv->fabric->off_mask_erd)
- is_inband_err = 1;
+ if (priv->fabric->off_mask_erd) {
+ mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
+ if (mstr_id == CCPLEX_MSTRID)
+ is_inband_err = 1;
+ }
}
}
@@ -640,8 +707,13 @@ static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
.name = "aon-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_aon_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_aon_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x17000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x8d0,
+ .firewall_wr_ctl = 0x8c8,
};
static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
@@ -656,8 +728,13 @@ static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
.name = "bpmp-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_bpmp_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x8f0,
+ .firewall_wr_ctl = 0x8e8,
};
static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
@@ -728,55 +805,62 @@ static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
.name = "cbb-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_cbb_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x60000,
- .off_mask_erd = 0x3a004
+ .off_mask_erd = 0x3a004,
+ .firewall_base = 0x10000,
+ .firewall_ctl = 0x23f0,
+ .firewall_wr_ctl = 0x23e8,
};
-static const struct tegra234_slave_lookup tegra234_dce_slave_map[] = {
+static const struct tegra234_slave_lookup tegra234_common_slave_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST0", 0x15000 },
{ "AST1", 0x16000 },
+ { "CBB", 0x17000 },
+ { "RSVD", 0x00000 },
{ "CPU", 0x18000 },
};
static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
.name = "dce-fabric",
.master_id = tegra234_master_id,
- .slave_map = tegra234_dce_slave_map,
+ .slave_map = tegra234_common_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
-};
-
-static const struct tegra234_slave_lookup tegra234_rce_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST0", 0x15000 },
- { "AST1", 0x16000 },
- { "CPU", 0x18000 },
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x290,
+ .firewall_wr_ctl = 0x288,
};
static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
.name = "rce-fabric",
.master_id = tegra234_master_id,
- .slave_map = tegra234_rce_slave_map,
+ .slave_map = tegra234_common_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
-};
-
-static const struct tegra234_slave_lookup tegra234_sce_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST0", 0x15000 },
- { "AST1", 0x16000 },
- { "CBB", 0x17000 },
- { "CPU", 0x18000 },
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x290,
+ .firewall_wr_ctl = 0x288,
};
static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
.name = "sce-fabric",
.master_id = tegra234_master_id,
- .slave_map = tegra234_sce_slave_map,
+ .slave_map = tegra234_common_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x290,
+ .firewall_wr_ctl = 0x288,
};
static const char * const tegra241_master_id[] = {
@@ -889,7 +973,7 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = {
};
static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
- { "CCPLEX", 0x50000 },
+ { "RSVD", 0x00000 },
{ "PCIE_C8", 0x51000 },
{ "PCIE_C9", 0x52000 },
{ "RSVD", 0x00000 },
@@ -942,22 +1026,32 @@ static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
{ "PCIE_C3", 0x58000 },
{ "PCIE_C0", 0x59000 },
{ "PCIE_C1", 0x5a000 },
+ { "CCPLEX", 0x50000 },
{ "AXI2APB_29", 0x85000 },
{ "AXI2APB_30", 0x86000 },
+ { "CBB_CENTRAL", 0x00000 },
+ { "AXI2APB_31", 0x8E000 },
+ { "AXI2APB_32", 0x8F000 },
};
static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
.name = "cbb-fabric",
.master_id = tegra241_master_id,
.slave_map = tegra241_cbb_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map),
.errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
.notifier_offset = 0x60000,
.off_mask_erd = 0x40004,
+ .firewall_base = 0x20000,
+ .firewall_ctl = 0x2370,
+ .firewall_wr_ctl = 0x2368,
};
static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = {
{ "RSVD", 0x00000 },
{ "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
{ "CBB", 0x15000 },
{ "CPU", 0x16000 },
{ "AXI2APB", 0x00000 },
@@ -969,8 +1063,13 @@ static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
.name = "bpmp-fabric",
.master_id = tegra241_master_id,
.slave_map = tegra241_bpmp_slave_map,
+ .max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map),
.errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
.notifier_offset = 0x19000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x8f0,
+ .firewall_wr_ctl = 0x8e8,
};
static const struct of_device_id tegra234_cbb_dt_ids[] = {
@@ -1055,6 +1154,15 @@ static int tegra234_cbb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cbb);
+ /*
+ * Don't enable error reporting for a Fabric if write to it's registers
+ * is blocked by CBB firewall.
+ */
+ if (!tegra234_cbb_write_access_allowed(pdev, cbb)) {
+ dev_info(&pdev->dev, "error reporting not enabled due to firewall\n");
+ return 0;
+ }
+
spin_lock_irqsave(&cbb_lock, flags);
list_add(&cbb->base.node, &cbb_list);
spin_unlock_irqrestore(&cbb_lock, flags);
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 6542267a224d..f02953f793e9 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -35,6 +35,19 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A04] = "A04",
};
+static const char *tegra_platform_name[TEGRA_PLATFORM_MAX] = {
+ [TEGRA_PLATFORM_SILICON] = "Silicon",
+ [TEGRA_PLATFORM_QT] = "QT",
+ [TEGRA_PLATFORM_SYSTEM_FPGA] = "System FPGA",
+ [TEGRA_PLATFORM_UNIT_FPGA] = "Unit FPGA",
+ [TEGRA_PLATFORM_ASIM_QT] = "Asim QT",
+ [TEGRA_PLATFORM_ASIM_LINSIM] = "Asim Linsim",
+ [TEGRA_PLATFORM_DSIM_ASIM_LINSIM] = "Dsim Asim Linsim",
+ [TEGRA_PLATFORM_VERIFICATION_SIMULATION] = "Verification Simulation",
+ [TEGRA_PLATFORM_VDK] = "VDK",
+ [TEGRA_PLATFORM_VSP] = "VSP",
+};
+
static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra20-car", },
{ .compatible = "nvidia,tegra30-car", },
@@ -94,112 +107,6 @@ static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
return 0;
}
-static const struct nvmem_cell_info tegra_fuse_cells[] = {
- {
- .name = "tsensor-cpu1",
- .offset = 0x084,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-cpu2",
- .offset = 0x088,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-cpu0",
- .offset = 0x098,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "xusb-pad-calibration",
- .offset = 0x0f0,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-cpu3",
- .offset = 0x12c,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "sata-calibration",
- .offset = 0x124,
- .bytes = 1,
- .bit_offset = 0,
- .nbits = 2,
- }, {
- .name = "tsensor-gpu",
- .offset = 0x154,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-mem0",
- .offset = 0x158,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-mem1",
- .offset = 0x15c,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-pllx",
- .offset = 0x160,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-common",
- .offset = 0x180,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "gpu-gcplex-config-fuse",
- .offset = 0x1c8,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "tsensor-realignment",
- .offset = 0x1fc,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "gpu-calibration",
- .offset = 0x204,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "xusb-pad-calibration-ext",
- .offset = 0x250,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "gpu-pdi0",
- .offset = 0x300,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- }, {
- .name = "gpu-pdi1",
- .offset = 0x304,
- .bytes = 4,
- .bit_offset = 0,
- .nbits = 32,
- },
-};
-
static void tegra_fuse_restore(void *base)
{
fuse->base = (void __iomem *)base;
@@ -253,8 +160,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
nvmem.name = "fuse";
nvmem.id = -1;
nvmem.owner = THIS_MODULE;
- nvmem.cells = tegra_fuse_cells;
- nvmem.ncells = ARRAY_SIZE(tegra_fuse_cells);
+ nvmem.cells = fuse->soc->cells;
+ nvmem.ncells = fuse->soc->num_cells;
+ nvmem.keepout = fuse->soc->keepouts;
+ nvmem.nkeepout = fuse->soc->num_keepouts;
nvmem.type = NVMEM_TYPE_OTP;
nvmem.read_only = true;
nvmem.root_only = true;
@@ -474,8 +383,13 @@ struct device * __init tegra_soc_device_register(void)
return NULL;
attr->family = kasprintf(GFP_KERNEL, "Tegra");
- attr->revision = kasprintf(GFP_KERNEL, "%s",
- tegra_revision_name[tegra_sku_info.revision]);
+ if (tegra_is_silicon())
+ attr->revision = kasprintf(GFP_KERNEL, "%s %s",
+ tegra_platform_name[tegra_sku_info.platform],
+ tegra_revision_name[tegra_sku_info.revision]);
+ else
+ attr->revision = kasprintf(GFP_KERNEL, "%s",
+ tegra_platform_name[tegra_sku_info.platform]);
attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
attr->custom_attr_group = fuse->soc->soc_attr_group;
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index f01d8a2547b6..932a03c64534 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -9,6 +9,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -133,6 +134,82 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
#endif
#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
+static const struct nvmem_cell_info tegra124_fuse_cells[] = {
+ {
+ .name = "tsensor-cpu1",
+ .offset = 0x084,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu2",
+ .offset = 0x088,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu0",
+ .offset = 0x098,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu3",
+ .offset = 0x12c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "sata-calibration",
+ .offset = 0x124,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-gpu",
+ .offset = 0x154,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem0",
+ .offset = 0x158,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem1",
+ .offset = 0x15c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-pllx",
+ .offset = 0x160,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-common",
+ .offset = 0x180,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-realignment",
+ .offset = 0x1fc,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@@ -209,12 +286,96 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
.info = &tegra124_fuse_info,
.lookups = tegra124_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
+ .cells = tegra124_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra124_fuse_cells),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = true,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
+static const struct nvmem_cell_info tegra210_fuse_cells[] = {
+ {
+ .name = "tsensor-cpu1",
+ .offset = 0x084,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu2",
+ .offset = 0x088,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu0",
+ .offset = 0x098,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu3",
+ .offset = 0x12c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "sata-calibration",
+ .offset = 0x124,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-gpu",
+ .offset = 0x154,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem0",
+ .offset = 0x158,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem1",
+ .offset = 0x15c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-pllx",
+ .offset = 0x160,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-common",
+ .offset = 0x180,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "gpu-calibration",
+ .offset = 0x204,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration-ext",
+ .offset = 0x250,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@@ -295,6 +456,8 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
.speedo_init = tegra210_init_speedo_data,
.info = &tegra210_fuse_info,
.lookups = tegra210_fuse_lookups,
+ .cells = tegra210_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra210_fuse_cells),
.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
@@ -302,6 +465,22 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
#endif
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
+static const struct nvmem_cell_info tegra186_fuse_cells[] = {
+ {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration-ext",
+ .offset = 0x250,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@@ -316,9 +495,17 @@ static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
},
};
+static const struct nvmem_keepout tegra186_fuse_keepouts[] = {
+ { .start = 0x01c, .end = 0x0f0 },
+ { .start = 0x138, .end = 0x198 },
+ { .start = 0x1d8, .end = 0x250 },
+ { .start = 0x280, .end = 0x290 },
+ { .start = 0x340, .end = 0x344 }
+};
+
static const struct tegra_fuse_info tegra186_fuse_info = {
.read = tegra30_fuse_read,
- .size = 0x300,
+ .size = 0x478,
.spare = 0x280,
};
@@ -327,12 +514,50 @@ const struct tegra_fuse_soc tegra186_fuse_soc = {
.info = &tegra186_fuse_info,
.lookups = tegra186_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
+ .cells = tegra186_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra186_fuse_cells),
+ .keepouts = tegra186_fuse_keepouts,
+ .num_keepouts = ARRAY_SIZE(tegra186_fuse_keepouts),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+static const struct nvmem_cell_info tegra194_fuse_cells[] = {
+ {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "gpu-gcplex-config-fuse",
+ .offset = 0x1c8,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration-ext",
+ .offset = 0x250,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "gpu-pdi0",
+ .offset = 0x300,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "gpu-pdi1",
+ .offset = 0x304,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@@ -362,9 +587,18 @@ static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
},
};
+static const struct nvmem_keepout tegra194_fuse_keepouts[] = {
+ { .start = 0x01c, .end = 0x0b8 },
+ { .start = 0x12c, .end = 0x198 },
+ { .start = 0x1a0, .end = 0x1bc },
+ { .start = 0x1d8, .end = 0x250 },
+ { .start = 0x270, .end = 0x290 },
+ { .start = 0x310, .end = 0x45c }
+};
+
static const struct tegra_fuse_info tegra194_fuse_info = {
.read = tegra30_fuse_read,
- .size = 0x300,
+ .size = 0x650,
.spare = 0x280,
};
@@ -373,12 +607,32 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
.info = &tegra194_fuse_info,
.lookups = tegra194_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
+ .cells = tegra194_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra194_fuse_cells),
+ .keepouts = tegra194_fuse_keepouts,
+ .num_keepouts = ARRAY_SIZE(tegra194_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+static const struct nvmem_cell_info tegra234_fuse_cells[] = {
+ {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration-ext",
+ .offset = 0x250,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@@ -393,9 +647,23 @@ static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
},
};
+static const struct nvmem_keepout tegra234_fuse_keepouts[] = {
+ { .start = 0x01c, .end = 0x0c8 },
+ { .start = 0x12c, .end = 0x184 },
+ { .start = 0x190, .end = 0x198 },
+ { .start = 0x1a0, .end = 0x204 },
+ { .start = 0x21c, .end = 0x250 },
+ { .start = 0x25c, .end = 0x2f0 },
+ { .start = 0x310, .end = 0x3d8 },
+ { .start = 0x400, .end = 0x4f0 },
+ { .start = 0x4f8, .end = 0x7e8 },
+ { .start = 0x8d0, .end = 0x8d8 },
+ { .start = 0xacc, .end = 0xf00 }
+};
+
static const struct tegra_fuse_info tegra234_fuse_info = {
.read = tegra30_fuse_read,
- .size = 0x300,
+ .size = 0x98c,
.spare = 0x280,
};
@@ -404,6 +672,10 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.info = &tegra234_fuse_info,
.lookups = tegra234_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
+ .cells = tegra234_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra234_fuse_cells),
+ .keepouts = tegra234_fuse_keepouts,
+ .num_keepouts = ARRAY_SIZE(tegra234_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};
diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
index 2bb1f9d6a6e6..90f23be73894 100644
--- a/drivers/soc/tegra/fuse/fuse.h
+++ b/drivers/soc/tegra/fuse/fuse.h
@@ -32,6 +32,10 @@ struct tegra_fuse_soc {
const struct nvmem_cell_lookup *lookups;
unsigned int num_lookups;
+ const struct nvmem_cell_info *cells;
+ unsigned int num_cells;
+ const struct nvmem_keepout *keepouts;
+ unsigned int num_keepouts;
const struct attribute_group *soc_attr_group;
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index 3351bd872ab2..4591c5bcb690 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -156,6 +156,7 @@ void __init tegra_init_revision(void)
}
tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO);
+ tegra_sku_info.platform = tegra_get_platform();
}
void __init tegra_init_apbmisc(void)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 678e8bc8a45d..cf4cfbf9f7c5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -23,6 +23,7 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/irqdomain.h>
@@ -46,6 +47,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>
@@ -182,6 +184,9 @@
#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2))
#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2))
#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2))
+#define WAKE_AOWAKE_SW_STATUS_W_0 0x49c
+#define WAKE_AOWAKE_SW_STATUS(x) (0x4a0 + ((x) << 2))
+#define WAKE_LATCH_SW 0x498
#define WAKE_AOWAKE_CTRL 0x4f4
#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
@@ -269,16 +274,14 @@ struct tegra_powergate {
struct tegra_io_pad_soc {
enum tegra_io_pad id;
unsigned int dpd;
+ unsigned int request;
+ unsigned int status;
unsigned int voltage;
const char *name;
};
struct tegra_pmc_regs {
unsigned int scratch0;
- unsigned int dpd_req;
- unsigned int dpd_status;
- unsigned int dpd2_req;
- unsigned int dpd2_status;
unsigned int rst_status;
unsigned int rst_source_shift;
unsigned int rst_source_mask;
@@ -369,6 +372,8 @@ struct tegra_pmc_soc {
*/
const struct tegra_wake_event *wake_events;
unsigned int num_wake_events;
+ unsigned int max_wake_events;
+ unsigned int max_wake_vectors;
const struct pmc_clk_init_data *pmc_clks_data;
unsigned int num_pmc_clks;
@@ -409,6 +414,11 @@ struct tegra_pmc_soc {
* @clk_nb: pclk clock changes handler
* @core_domain_state_synced: flag marking the core domain's state as synced
* @core_domain_registered: flag marking the core domain as registered
+ * @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
+ * @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
+ * @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
+ * @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
+ * cntrl register associated with each wake during system suspend.
*/
struct tegra_pmc {
struct device *dev;
@@ -449,6 +459,12 @@ struct tegra_pmc {
bool core_domain_state_synced;
bool core_domain_registered;
+
+ unsigned long *wake_type_level_map;
+ unsigned long *wake_type_dual_edge_map;
+ unsigned long *wake_sw_status_map;
+ unsigned long *wake_cntrl_level_map;
+ struct syscore_ops syscore;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -1540,46 +1556,20 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
return NULL;
}
-static int tegra_io_pad_get_dpd_register_bit(struct tegra_pmc *pmc,
- enum tegra_io_pad id,
- unsigned long *request,
- unsigned long *status,
- u32 *mask)
-{
- const struct tegra_io_pad_soc *pad;
-
- pad = tegra_io_pad_find(pmc, id);
- if (!pad) {
- dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
- return -ENOENT;
- }
-
- if (pad->dpd == UINT_MAX)
- return -ENOTSUPP;
-
- *mask = BIT(pad->dpd % 32);
-
- if (pad->dpd < 32) {
- *status = pmc->soc->regs->dpd_status;
- *request = pmc->soc->regs->dpd_req;
- } else {
- *status = pmc->soc->regs->dpd2_status;
- *request = pmc->soc->regs->dpd2_req;
- }
-
- return 0;
-}
-
-static int tegra_io_pad_prepare(struct tegra_pmc *pmc, enum tegra_io_pad id,
- unsigned long *request, unsigned long *status,
+static int tegra_io_pad_prepare(struct tegra_pmc *pmc,
+ const struct tegra_io_pad_soc *pad,
+ unsigned long *request,
+ unsigned long *status,
u32 *mask)
{
unsigned long rate, value;
- int err;
- err = tegra_io_pad_get_dpd_register_bit(pmc, id, request, status, mask);
- if (err)
- return err;
+ if (pad->dpd == UINT_MAX)
+ return -EINVAL;
+
+ *request = pad->request;
+ *status = pad->status;
+ *mask = BIT(pad->dpd);
if (pmc->clk) {
rate = pmc->rate;
@@ -1631,13 +1621,20 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc)
*/
int tegra_io_pad_power_enable(enum tegra_io_pad id)
{
+ const struct tegra_io_pad_soc *pad;
unsigned long request, status;
u32 mask;
int err;
+ pad = tegra_io_pad_find(pmc, id);
+ if (!pad) {
+ dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
+ return -ENOENT;
+ }
+
mutex_lock(&pmc->powergates_lock);
- err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask);
+ err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask);
if (err < 0) {
dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err);
goto unlock;
@@ -1667,13 +1664,20 @@ EXPORT_SYMBOL(tegra_io_pad_power_enable);
*/
int tegra_io_pad_power_disable(enum tegra_io_pad id)
{
+ const struct tegra_io_pad_soc *pad;
unsigned long request, status;
u32 mask;
int err;
+ pad = tegra_io_pad_find(pmc, id);
+ if (!pad) {
+ dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
+ return -ENOENT;
+ }
+
mutex_lock(&pmc->powergates_lock);
- err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask);
+ err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask);
if (err < 0) {
dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err);
goto unlock;
@@ -1697,14 +1701,21 @@ EXPORT_SYMBOL(tegra_io_pad_power_disable);
static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
{
- unsigned long request, status;
+ const struct tegra_io_pad_soc *pad;
+ unsigned long status;
u32 mask, value;
- int err;
- err = tegra_io_pad_get_dpd_register_bit(pmc, id, &request, &status,
- &mask);
- if (err)
- return err;
+ pad = tegra_io_pad_find(pmc, id);
+ if (!pad) {
+ dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
+ return -ENOENT;
+ }
+
+ if (pad->dpd == UINT_MAX)
+ return -EINVAL;
+
+ status = pad->status;
+ mask = BIT(pad->dpd);
value = tegra_pmc_readl(pmc, status);
@@ -1930,10 +1941,30 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
return 0;
}
-static void tegra_pmc_init(struct tegra_pmc *pmc)
+static int tegra_pmc_init(struct tegra_pmc *pmc)
{
+ if (pmc->soc->max_wake_events > 0) {
+ pmc->wake_type_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
+ if (!pmc->wake_type_level_map)
+ return -ENOMEM;
+
+ pmc->wake_type_dual_edge_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
+ if (!pmc->wake_type_dual_edge_map)
+ return -ENOMEM;
+
+ pmc->wake_sw_status_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
+ if (!pmc->wake_sw_status_map)
+ return -ENOMEM;
+
+ pmc->wake_cntrl_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
+ if (!pmc->wake_cntrl_level_map)
+ return -ENOMEM;
+ }
+
if (pmc->soc->init)
pmc->soc->init(pmc);
+
+ return 0;
}
static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
@@ -2424,15 +2455,21 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_LEVEL_HIGH:
value |= WAKE_AOWAKE_CNTRL_LEVEL;
+ set_bit(data->hwirq, pmc->wake_type_level_map);
+ clear_bit(data->hwirq, pmc->wake_type_dual_edge_map);
break;
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_LEVEL_LOW:
value &= ~WAKE_AOWAKE_CNTRL_LEVEL;
+ clear_bit(data->hwirq, pmc->wake_type_level_map);
+ clear_bit(data->hwirq, pmc->wake_type_dual_edge_map);
break;
case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
value ^= WAKE_AOWAKE_CNTRL_LEVEL;
+ clear_bit(data->hwirq, pmc->wake_type_level_map);
+ set_bit(data->hwirq, pmc->wake_type_dual_edge_map);
break;
default:
@@ -2964,7 +3001,11 @@ static int tegra_pmc_probe(struct platform_device *pdev)
pmc->dev = &pdev->dev;
- tegra_pmc_init(pmc);
+ err = tegra_pmc_init(pmc);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to initialize PMC: %d\n", err);
+ return err;
+ }
tegra_pmc_init_tsense_reset(pmc);
@@ -3015,6 +3056,156 @@ cleanup_sysfs:
return err;
}
+/*
+ * Ensures that sufficient time is passed for a register write to
+ * serialize into the 32KHz domain.
+ */
+static void wke_32kwritel(struct tegra_pmc *pmc, u32 value, unsigned int offset)
+{
+ writel(value, pmc->wake + offset);
+ udelay(130);
+}
+
+static void wke_write_wake_level(struct tegra_pmc *pmc, int wake, int level)
+{
+ unsigned int offset = WAKE_AOWAKE_CNTRL(wake);
+ u32 value;
+
+ value = readl(pmc->wake + offset);
+ if (level)
+ value |= WAKE_AOWAKE_CNTRL_LEVEL;
+ else
+ value &= ~WAKE_AOWAKE_CNTRL_LEVEL;
+
+ writel(value, pmc->wake + offset);
+}
+
+static void wke_write_wake_levels(struct tegra_pmc *pmc)
+{
+ unsigned int i;
+
+ for (i = 0; i < pmc->soc->max_wake_events; i++)
+ wke_write_wake_level(pmc, i, test_bit(i, pmc->wake_cntrl_level_map));
+}
+
+static void wke_clear_sw_wake_status(struct tegra_pmc *pmc)
+{
+ wke_32kwritel(pmc, 1, WAKE_AOWAKE_SW_STATUS_W_0);
+}
+
+static void wke_read_sw_wake_status(struct tegra_pmc *pmc)
+{
+ unsigned long status;
+ unsigned int wake, i;
+
+ for (i = 0; i < pmc->soc->max_wake_events; i++)
+ wke_write_wake_level(pmc, i, 0);
+
+ wke_clear_sw_wake_status(pmc);
+
+ wke_32kwritel(pmc, 1, WAKE_LATCH_SW);
+
+ /*
+ * WAKE_AOWAKE_SW_STATUS is edge triggered, so in order to
+ * obtain the current status of the input wake signals, change
+ * the polarity of the wake level from 0->1 while latching to force
+ * a positive edge if the sampled signal is '1'.
+ */
+ for (i = 0; i < pmc->soc->max_wake_events; i++)
+ wke_write_wake_level(pmc, i, 1);
+
+ /*
+ * Wait for the update to be synced into the 32kHz domain,
+ * and let enough time lapse, so that the wake signals have time to
+ * be sampled.
+ */
+ udelay(300);
+
+ wke_32kwritel(pmc, 0, WAKE_LATCH_SW);
+
+ bitmap_zero(pmc->wake_sw_status_map, pmc->soc->max_wake_events);
+
+ for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
+ status = readl(pmc->wake + WAKE_AOWAKE_SW_STATUS(i));
+
+ for_each_set_bit(wake, &status, 32)
+ set_bit(wake + (i * 32), pmc->wake_sw_status_map);
+ }
+}
+
+static void wke_clear_wake_status(struct tegra_pmc *pmc)
+{
+ unsigned long status;
+ unsigned int i, wake;
+ u32 mask;
+
+ for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
+ mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
+ status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
+
+ for_each_set_bit(wake, &status, 32)
+ wke_32kwritel(pmc, 0x1, WAKE_AOWAKE_STATUS_W((i * 32) + wake));
+ }
+}
+
+/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */
+static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int index,
+ unsigned long status)
+{
+ unsigned int wake;
+
+ dev_dbg(pmc->dev, "Wake[%d:%d] status=%#lx\n", (index * 32) + 31, index * 32, status);
+
+ for_each_set_bit(wake, &status, 32) {
+ irq_hw_number_t hwirq = wake + 32 * index;
+ struct irq_desc *desc;
+ unsigned int irq;
+
+ irq = irq_find_mapping(pmc->domain, hwirq);
+
+ desc = irq_to_desc(irq);
+ if (!desc || !desc->action || !desc->action->name) {
+ dev_dbg(pmc->dev, "Resume caused by WAKE%ld, IRQ %d\n", hwirq, irq);
+ continue;
+ }
+
+ dev_dbg(pmc->dev, "Resume caused by WAKE%ld, %s\n", hwirq, desc->action->name);
+ generic_handle_irq(irq);
+ }
+}
+
+static void tegra186_pmc_wake_syscore_resume(void)
+{
+ u32 status, mask;
+ unsigned int i;
+
+ for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
+ mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
+ status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
+
+ tegra186_pmc_process_wake_events(pmc, i, status);
+ }
+}
+
+static int tegra186_pmc_wake_syscore_suspend(void)
+{
+ wke_read_sw_wake_status(pmc);
+
+ /* flip the wakeup trigger for dual-edge triggered pads
+ * which are currently asserting as wakeups
+ */
+ bitmap_andnot(pmc->wake_cntrl_level_map, pmc->wake_type_dual_edge_map,
+ pmc->wake_sw_status_map, pmc->soc->max_wake_events);
+ bitmap_or(pmc->wake_cntrl_level_map, pmc->wake_cntrl_level_map,
+ pmc->wake_type_level_map, pmc->soc->max_wake_events);
+
+ /* Clear PMC Wake Status registers while going to suspend */
+ wke_clear_wake_status(pmc);
+ wke_write_wake_levels(pmc);
+
+ return 0;
+}
+
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev)
{
@@ -3050,10 +3241,6 @@ static const char * const tegra20_powergates[] = {
static const struct tegra_pmc_regs tegra20_pmc_regs = {
.scratch0 = 0x50,
- .dpd_req = 0x1b8,
- .dpd_status = 0x1bc,
- .dpd2_req = 0x1c0,
- .dpd2_status = 0x1c4,
.rst_status = 0x1b4,
.rst_source_shift = 0x0,
.rst_source_mask = 0x7,
@@ -3297,59 +3484,86 @@ static const u8 tegra124_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
-#define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \
- ((struct tegra_io_pad_soc) { \
- .id = (_id), \
- .dpd = (_dpd), \
- .voltage = (_voltage), \
- .name = (_name), \
+#define TEGRA_IO_PAD(_id, _dpd, _request, _status, _voltage, _name) \
+ ((struct tegra_io_pad_soc) { \
+ .id = (_id), \
+ .dpd = (_dpd), \
+ .request = (_request), \
+ .status = (_status), \
+ .voltage = (_voltage), \
+ .name = (_name), \
})
-#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \
- ((struct pinctrl_pin_desc) { \
- .number = (_id), \
- .name = (_name) \
+#define TEGRA_IO_PIN_DESC(_id, _name) \
+ ((struct pinctrl_pin_desc) { \
+ .number = (_id), \
+ .name = (_name), \
})
-#define TEGRA124_IO_PAD_TABLE(_pad) \
- /* .id .dpd .voltage .name */ \
- _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
- _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \
- _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \
- _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \
- _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
- _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \
- _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \
- _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
- _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
- _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
- _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
- _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
- _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
- _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \
- _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
- _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
- _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \
- _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
- _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
- _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
- _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \
- _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \
- _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \
- _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \
- _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
- _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
- _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
- _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
- _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias")
-
static const struct tegra_io_pad_soc tegra124_io_pads[] = {
- TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD)
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, UINT_MAX, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_BB, 15, 0x1b8, 0x1bc, UINT_MAX, "bb"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, UINT_MAX, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_COMP, 22, 0x1b8, 0x1bc, UINT_MAX, "comp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HV, 6, 0x1c0, 0x1c4, UINT_MAX, "hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_NAND, 13, 0x1b8, 0x1bc, UINT_MAX, "nand"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x1c0, 0x1c4, UINT_MAX, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, UINT_MAX, "sdmmc1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, UINT_MAX, "sdmmc3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 3, 0x1c0, 0x1c4, UINT_MAX, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SYS_DDC, 26, 0x1c0, 0x1c4, UINT_MAX, "sys_ddc"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, UINT_MAX, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb_bias"),
};
static const struct pinctrl_pin_desc tegra124_pin_descs[] = {
- TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_BB, "bb"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_COMP, "comp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HV, "hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_NAND, "nand"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SYS_DDC, "sys_ddc"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb_bias"),
};
static const struct tegra_pmc_soc tegra124_pmc_soc = {
@@ -3415,53 +3629,86 @@ static const u8 tegra210_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
-#define TEGRA210_IO_PAD_TABLE(_pad) \
- /* .id .dpd .voltage .name */ \
- _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \
- _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \
- _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \
- _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
- _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
- _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \
- _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \
- _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \
- _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \
- _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \
- _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \
- _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \
- _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \
- _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
- _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
- _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
- _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
- _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \
- _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \
- _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \
- _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
- _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
- _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
- _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
- _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
- _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
- _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \
- _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \
- _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \
- _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \
- _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \
- _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \
- _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
- _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
- _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
- _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \
- _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias")
-
static const struct tegra_io_pad_soc tegra210_io_pads[] = {
- TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD)
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, 5, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x1c0, 0x1c4, 18, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, 10, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 10, 0x1c0, 0x1c4, UINT_MAX, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 11, 0x1c0, 0x1c4, UINT_MAX, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 13, 0x1c0, 0x1c4, UINT_MAX, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x1b8, 0x1bc, 19, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DEBUG_NONAO, 26, 0x1b8, 0x1bc, UINT_MAX, "debug-nonao"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC, 18, 0x1c0, 0x1c4, 20, "dmic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DP, 19, 0x1c0, 0x1c4, UINT_MAX, "dp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC, 3, 0x1c0, 0x1c4, UINT_MAX, "emmc"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC2, 5, 0x1c0, 0x1c4, UINT_MAX, "emmc2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GPIO, 27, 0x1b8, 0x1bc, 21, "gpio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, UINT_MAX, UINT_MAX, 11, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, 12, "sdmmc1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, 13, "sdmmc3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 14, 0x1c0, 0x1c4, 22, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI_HV, 15, 0x1c0, 0x1c4, 23, "spi-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, 2, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB3, 18, 0x1b8, 0x1bc, UINT_MAX, "usb3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb-bias"),
};
static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
- TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DEBUG_NONAO, "debug-nonao"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC, "dmic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DP, "dp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC, "emmc"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC2, "emmc2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GPIO, "gpio"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI_HV, "spi-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB3, "usb3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"),
};
static const char * const tegra210_reset_sources[] = {
@@ -3511,61 +3758,90 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.has_usb_sleepwalk = true,
};
-#define TEGRA186_IO_PAD_TABLE(_pad) \
- /* .id .dpd .voltage .name */ \
- _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
- _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
- _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
- _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \
- _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
- _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \
- _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
- _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
- _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
- _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \
- _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
- _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
- _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
- _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \
- _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \
- _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \
- _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
- _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \
- _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \
- _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \
- _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \
- _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \
- _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \
- _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \
- _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \
- _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \
- _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \
- _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \
- _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \
- _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \
- _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \
- _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \
- _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \
- _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \
- _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \
- _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv")
-
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
- TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD)
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x74, 0x78, UINT_MAX, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x74, 0x78, UINT_MAX, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x74, 0x78, UINT_MAX, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x74, 0x78, UINT_MAX, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x74, 0x78, UINT_MAX, "usb-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x74, 0x78, UINT_MAX, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC2_HV, 2, 0x7c, 0x80, 5, "sdmmc2-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 8, 0x7c, 0x80, UINT_MAX, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 9, 0x7c, 0x80, UINT_MAX, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 10, 0x7c, 0x80, UINT_MAX, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC_HV, 20, 0x7c, 0x80, 2, "dmic-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
};
static const struct pinctrl_pin_desc tegra186_pin_descs[] = {
- TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC2_HV, "sdmmc2-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC_HV, "dmic-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CONN, "conn"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
};
static const struct tegra_pmc_regs tegra186_pmc_regs = {
.scratch0 = 0x2000,
- .dpd_req = 0x74,
- .dpd_status = 0x78,
- .dpd2_req = 0x7c,
- .dpd2_status = 0x80,
.rst_status = 0x70,
.rst_source_shift = 0x2,
.rst_source_mask = 0x3c,
@@ -3573,6 +3849,14 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
.rst_level_mask = 0x3,
};
+static void tegra186_pmc_init(struct tegra_pmc *pmc)
+{
+ pmc->syscore.suspend = tegra186_pmc_wake_syscore_suspend;
+ pmc->syscore.resume = tegra186_pmc_wake_syscore_resume;
+
+ register_syscore_ops(&pmc->syscore);
+}
+
static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
struct device_node *np,
bool invert)
@@ -3652,7 +3936,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
.pin_descs = tegra186_pin_descs,
.regs = &tegra186_pmc_regs,
- .init = NULL,
+ .init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
@@ -3662,78 +3946,120 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
.num_wake_events = ARRAY_SIZE(tegra186_wake_events),
.wake_events = tegra186_wake_events,
+ .max_wake_events = 96,
+ .max_wake_vectors = 3,
.pmc_clks_data = NULL,
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
};
-#define TEGRA194_IO_PAD_TABLE(_pad) \
- /* .id .dpd .voltage .name */ \
- _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
- _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
- _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \
- _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
- _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \
- _pad(TEGRA_IO_PAD_EQOS, 8, UINT_MAX, "eqos"), \
- _pad(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, UINT_MAX, "pex-clk-2-bias"), \
- _pad(TEGRA_IO_PAD_PEX_CLK_2, 10, UINT_MAX, "pex-clk-2"), \
- _pad(TEGRA_IO_PAD_DAP3, 11, UINT_MAX, "dap3"), \
- _pad(TEGRA_IO_PAD_DAP5, 12, UINT_MAX, "dap5"), \
- _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
- _pad(TEGRA_IO_PAD_PWR_CTL, 15, UINT_MAX, "pwr-ctl"), \
- _pad(TEGRA_IO_PAD_SOC_GPIO53, 16, UINT_MAX, "soc-gpio53"), \
- _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
- _pad(TEGRA_IO_PAD_GP_PWM2, 18, UINT_MAX, "gp-pwm2"), \
- _pad(TEGRA_IO_PAD_GP_PWM3, 19, UINT_MAX, "gp-pwm3"), \
- _pad(TEGRA_IO_PAD_SOC_GPIO12, 20, UINT_MAX, "soc-gpio12"), \
- _pad(TEGRA_IO_PAD_SOC_GPIO13, 21, UINT_MAX, "soc-gpio13"), \
- _pad(TEGRA_IO_PAD_SOC_GPIO10, 22, UINT_MAX, "soc-gpio10"), \
- _pad(TEGRA_IO_PAD_UART4, 23, UINT_MAX, "uart4"), \
- _pad(TEGRA_IO_PAD_UART5, 24, UINT_MAX, "uart5"), \
- _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \
- _pad(TEGRA_IO_PAD_HDMI_DP3, 26, UINT_MAX, "hdmi-dp3"), \
- _pad(TEGRA_IO_PAD_HDMI_DP2, 27, UINT_MAX, "hdmi-dp2"), \
- _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \
- _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \
- _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
- _pad(TEGRA_IO_PAD_PEX_CTL2, 33, UINT_MAX, "pex-ctl2"), \
- _pad(TEGRA_IO_PAD_PEX_L0_RST_N, 34, UINT_MAX, "pex-l0-rst"), \
- _pad(TEGRA_IO_PAD_PEX_L1_RST_N, 35, UINT_MAX, "pex-l1-rst"), \
- _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \
- _pad(TEGRA_IO_PAD_PEX_L5_RST_N, 37, UINT_MAX, "pex-l5-rst"), \
- _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \
- _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \
- _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \
- _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \
- _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \
- _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \
- _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \
- _pad(TEGRA_IO_PAD_CSIG, 50, UINT_MAX, "csig"), \
- _pad(TEGRA_IO_PAD_CSIH, 51, UINT_MAX, "csih"), \
- _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \
- _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \
- _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \
- _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \
- _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \
- _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv")
-
static const struct tegra_io_pad_soc tegra194_io_pads[] = {
- TEGRA194_IO_PAD_TABLE(TEGRA_IO_PAD)
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EQOS, 8, 0x74, 0x78, UINT_MAX, "eqos"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, 0x74, 0x78, UINT_MAX, "pex-clk-2-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2, 10, 0x74, 0x78, UINT_MAX, "pex-clk-2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DAP3, 11, 0x74, 0x78, UINT_MAX, "dap3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DAP5, 12, 0x74, 0x78, UINT_MAX, "dap5"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PWR_CTL, 15, 0x74, 0x78, UINT_MAX, "pwr-ctl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO53, 16, 0x74, 0x78, UINT_MAX, "soc-gpio53"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM2, 18, 0x74, 0x78, UINT_MAX, "gp-pwm2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM3, 19, 0x74, 0x78, UINT_MAX, "gp-pwm3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO12, 20, 0x74, 0x78, UINT_MAX, "soc-gpio12"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO13, 21, 0x74, 0x78, UINT_MAX, "soc-gpio13"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO10, 22, 0x74, 0x78, UINT_MAX, "soc-gpio10"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART4, 23, 0x74, 0x78, UINT_MAX, "uart4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART5, 24, 0x74, 0x78, UINT_MAX, "uart5"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP3, 26, 0x74, 0x78, UINT_MAX, "hdmi-dp3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP2, 27, 0x74, 0x78, UINT_MAX, "hdmi-dp2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CTL2, 1, 0x7c, 0x80, UINT_MAX, "pex-ctl2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L0_RST, 2, 0x7c, 0x80, UINT_MAX, "pex-l0-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L1_RST, 3, 0x7c, 0x80, UINT_MAX, "pex-l1-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L5_RST, 5, 0x7c, 0x80, UINT_MAX, "pex-l5-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 18, 0x7c, 0x80, UINT_MAX, "csig"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 19, 0x7c, 0x80, UINT_MAX, "csih"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
};
static const struct pinctrl_pin_desc tegra194_pin_descs[] = {
- TEGRA194_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EQOS, "eqos"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2_BIAS, "pex-clk-2-bias"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2, "pex-clk-2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP3, "dap3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP5, "dap5"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PWR_CTL, "pwr-ctl"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO53, "soc-gpio53"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM2, "gp-pwm2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM3, "gp-pwm3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO12, "soc-gpio12"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO13, "soc-gpio13"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO10, "soc-gpio10"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART4, "uart4"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART5, "uart5"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP3, "hdmi-dp3"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP2, "hdmi-dp2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CTL2, "pex-ctl2"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L0_RST, "pex-l0-rst"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L1_RST, "pex-l1-rst"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L5_RST, "pex-l5-rst"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CONN, "conn"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
};
static const struct tegra_pmc_regs tegra194_pmc_regs = {
.scratch0 = 0x2000,
- .dpd_req = 0x74,
- .dpd_status = 0x78,
- .dpd2_req = 0x7c,
- .dpd2_status = 0x80,
.rst_status = 0x70,
.rst_source_shift = 0x2,
.rst_source_mask = 0x7c,
@@ -3794,7 +4120,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.num_pin_descs = ARRAY_SIZE(tegra194_pin_descs),
.pin_descs = tegra194_pin_descs,
.regs = &tegra194_pmc_regs,
- .init = NULL,
+ .init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
@@ -3804,18 +4130,52 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
.num_wake_events = ARRAY_SIZE(tegra194_wake_events),
.wake_events = tegra194_wake_events,
+ .max_wake_events = 96,
+ .max_wake_vectors = 3,
.pmc_clks_data = NULL,
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
};
+static const struct tegra_io_pad_soc tegra234_io_pads[] = {
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0xe0c0, 0xe0c4, UINT_MAX, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0xe0c0, 0xe0c4, UINT_MAX, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe0d0, 0xe0d4, UINT_MAX, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0xe0c0, 0xe0c4, UINT_MAX, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0xe0c0, 0xe0c4, UINT_MAX, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0xe0c0, 0xe0c4, UINT_MAX, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0xe0c0, 0xe0c4, UINT_MAX, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe064, 0xe068, UINT_MAX, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 1, 0xe05c, 0xe060, UINT_MAX, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe054, 0xe058, 4, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, 6, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 1, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0xe0c0, 0xe0c4, UINT_MAX, "csig"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0xe0c0, 0xe0c4, UINT_MAX, "csih"),
+};
+
+static const struct pinctrl_pin_desc tegra234_pin_descs[] = {
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"),
+};
+
static const struct tegra_pmc_regs tegra234_pmc_regs = {
.scratch0 = 0x2000,
- .dpd_req = 0,
- .dpd_status = 0,
- .dpd2_req = 0,
- .dpd2_status = 0,
.rst_status = 0x70,
.rst_source_shift = 0x2,
.rst_source_mask = 0xfc,
@@ -3880,12 +4240,12 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.needs_mbist_war = false,
.has_impl_33v_pwr = true,
.maybe_tz_only = false,
- .num_io_pads = 0,
- .io_pads = NULL,
- .num_pin_descs = 0,
- .pin_descs = NULL,
+ .num_io_pads = ARRAY_SIZE(tegra234_io_pads),
+ .io_pads = tegra234_io_pads,
+ .num_pin_descs = ARRAY_SIZE(tegra234_pin_descs),
+ .pin_descs = tegra234_pin_descs,
.regs = &tegra234_pmc_regs,
- .init = NULL,
+ .init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
@@ -3895,6 +4255,8 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
.num_wake_events = ARRAY_SIZE(tegra234_wake_events),
.wake_events = tegra234_wake_events,
+ .max_wake_events = 96,
+ .max_wake_vectors = 3,
.pmc_clks_data = NULL,
.num_pmc_clks = 0,
.has_blink_output = false,
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 7e2fb1c16af1..8c2a1036bef5 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -63,7 +63,7 @@ config TI_SCI_PM_DOMAINS
rootfs may be available.
config TI_K3_RINGACC
- bool "K3 Ring accelerator Sub System"
+ tristate "K3 Ring accelerator Sub System"
depends on ARCH_K3 || COMPILE_TEST
depends on TI_SCI_INTA_IRQCHIP
help
@@ -98,6 +98,6 @@ endif # SOC_TI
config TI_SCI_INTA_MSI_DOMAIN
bool
- select GENERIC_MSI_IRQ_DOMAIN
+ select GENERIC_MSI_IRQ
help
Driver to enable Interrupt Aggregator specific MSI Domain.
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c
index f7bf18b8229a..e01e4d815230 100644
--- a/drivers/soc/ti/k3-ringacc.c
+++ b/drivers/soc/ti/k3-ringacc.c
@@ -7,7 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -336,6 +336,9 @@ struct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc,
mutex_lock(&ringacc->req_lock);
+ if (!try_module_get(ringacc->dev->driver->owner))
+ goto err_module_get;
+
if (id == K3_RINGACC_RING_ID_ANY) {
/* Request for any general purpose ring */
struct ti_sci_resource_desc *gp_rings =
@@ -380,6 +383,9 @@ out:
return &ringacc->rings[id];
error:
+ module_put(ringacc->dev->driver->owner);
+
+err_module_get:
mutex_unlock(&ringacc->req_lock);
return NULL;
}
@@ -616,6 +622,8 @@ int k3_ringacc_ring_free(struct k3_ring *ring)
no_init:
clear_bit(ring->ring_id, ringacc->rings_inuse);
+ module_put(ringacc->dev->driver->owner);
+
out:
mutex_unlock(&ringacc->req_lock);
return 0;
@@ -1450,6 +1458,7 @@ static const struct of_device_id k3_ringacc_of_match[] = {
{ .compatible = "ti,am654-navss-ringacc", .data = &k3_ringacc_data, },
{},
};
+MODULE_DEVICE_TABLE(of, k3_ringacc_of_match);
struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev,
struct k3_ringacc_init_data *data)
@@ -1544,12 +1553,27 @@ static int k3_ringacc_probe(struct platform_device *pdev)
return 0;
}
+static int k3_ringacc_remove(struct platform_device *pdev)
+{
+ struct k3_ringacc *ringacc = dev_get_drvdata(&pdev->dev);
+
+ mutex_lock(&k3_ringacc_list_lock);
+ list_del(&ringacc->list);
+ mutex_unlock(&k3_ringacc_list_lock);
+ return 0;
+}
+
static struct platform_driver k3_ringacc_driver = {
.probe = k3_ringacc_probe,
+ .remove = k3_ringacc_remove,
.driver = {
.name = "k3-ringacc",
.of_match_table = k3_ringacc_of_match,
.suppress_bind_attrs = true,
},
};
-builtin_platform_driver(k3_ringacc_driver);
+module_platform_driver(k3_ringacc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI Ringacc driver for K3 SOCs");
+MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
index 91f441ee6175..d15764e19d96 100644
--- a/drivers/soc/ti/k3-socinfo.c
+++ b/drivers/soc/ti/k3-socinfo.c
@@ -43,6 +43,7 @@ static const struct k3_soc_id {
{ 0xBB38, "AM64X" },
{ 0xBB75, "J721S2"},
{ 0xBB7E, "AM62X" },
+ { 0xBB8D, "AM62AX" },
};
static int
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 92af7d1b6f5b..8fb76908be70 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -67,7 +67,7 @@ static DEFINE_MUTEX(knav_dev_lock);
* 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"};
+static const char * const knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"};
static bool device_ready;
bool knav_qmss_device_ready(void)
@@ -1785,6 +1785,7 @@ static int knav_queue_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
+ pm_runtime_disable(&pdev->dev);
dev_err(dev, "Failed to enable QMSS\n");
return ret;
}
diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c
index ad2bb72e640c..6a389a6444f3 100644
--- a/drivers/soc/ti/smartreflex.c
+++ b/drivers/soc/ti/smartreflex.c
@@ -932,6 +932,7 @@ static int omap_sr_probe(struct platform_device *pdev)
err_debugfs:
debugfs_remove_recursive(sr_info->dbg_dir);
err_list_del:
+ pm_runtime_disable(&pdev->dev);
list_del(&sr_info->node);
clk_unprepare(sr_info->fck);
diff --git a/drivers/soc/ti/ti_sci_inta_msi.c b/drivers/soc/ti/ti_sci_inta_msi.c
index 991c78b34745..b9251e1d9a5c 100644
--- a/drivers/soc/ti/ti_sci_inta_msi.c
+++ b/drivers/soc/ti/ti_sci_inta_msi.c
@@ -73,13 +73,13 @@ static int ti_sci_inta_msi_alloc_descs(struct device *dev,
for (set = 0; set < res->sets; set++) {
for (i = 0; i < res->desc[set].num; i++, count++) {
msi_desc.msi_index = res->desc[set].start + i;
- if (msi_add_msi_desc(dev, &msi_desc))
+ if (msi_insert_msi_desc(dev, &msi_desc))
goto fail;
}
for (i = 0; i < res->desc[set].num_sec; i++, count++) {
msi_desc.msi_index = res->desc[set].start_sec + i;
- if (msi_add_msi_desc(dev, &msi_desc))
+ if (msi_insert_msi_desc(dev, &msi_desc))
goto fail;
}
}
@@ -93,13 +93,8 @@ int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
struct ti_sci_resource *res)
{
struct platform_device *pdev = to_platform_device(dev);
- struct irq_domain *msi_domain;
int ret, nvec;
- msi_domain = dev_get_msi_domain(dev);
- if (!msi_domain)
- return -EINVAL;
-
if (pdev->id < 0)
return -ENODEV;
@@ -114,7 +109,8 @@ int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
goto unlock;
}
- ret = msi_domain_alloc_irqs_descs_locked(msi_domain, dev, nvec);
+ /* Use alloc ALL as it's unclear whether there are gaps in the indices */
+ ret = msi_domain_alloc_irqs_all_locked(dev, MSI_DEFAULT_DOMAIN, nvec);
if (ret)
dev_err(dev, "Failed to allocate IRQs %d\n", ret);
unlock:
diff --git a/drivers/soc/ux500/ux500-soc-id.c b/drivers/soc/ux500/ux500-soc-id.c
index a9472e0e5d61..27d6e25a0115 100644
--- a/drivers/soc/ux500/ux500-soc-id.c
+++ b/drivers/soc/ux500/ux500-soc-id.c
@@ -167,20 +167,18 @@ ATTRIBUTE_GROUPS(ux500_soc);
static const char *db8500_read_soc_id(struct device_node *backupram)
{
void __iomem *base;
- void __iomem *uid;
const char *retstr;
+ u32 uid[5];
base = of_iomap(backupram, 0);
if (!base)
return NULL;
- uid = base + 0x1fc0;
+ memcpy_fromio(uid, base + 0x1fc0, sizeof(uid));
/* Throw these device-specific numbers into the entropy pool */
- add_device_randomness(uid, 0x14);
+ add_device_randomness(uid, sizeof(uid));
retstr = kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
- readl((u32 *)uid+0),
- readl((u32 *)uid+1), readl((u32 *)uid+2),
- readl((u32 *)uid+3), readl((u32 *)uid+4));
+ uid[0], uid[1], uid[2], uid[3], uid[4]);
iounmap(base);
return retstr;
}
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 244209358784..8c76541d553f 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1513,6 +1513,7 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
bus->link_id = auxdev->id;
bus->dev_num_ida_min = INTEL_DEV_NUM_IDA_MIN;
+ bus->clk_stop_timeout = 1;
sdw_cdns_probe(cdns);
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index d091513919df..d6842925de61 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -125,30 +125,6 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
return 0;
}
-#define HDA_DSP_REG_ADSPIC2 (0x10)
-#define HDA_DSP_REG_ADSPIS2 (0x14)
-#define HDA_DSP_REG_ADSPIC2_SNDW BIT(5)
-
-/**
- * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
- * @mmio_base: The mmio base of the control register
- * @enable: true if enable
- */
-void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
-{
- u32 val;
-
- val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
-
- if (enable)
- val |= HDA_DSP_REG_ADSPIC2_SNDW;
- else
- val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
-
- writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
-}
-EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
-
irqreturn_t sdw_intel_thread(int irq, void *dev_id)
{
struct sdw_intel_ctx *ctx = dev_id;
@@ -157,7 +133,6 @@ irqreturn_t sdw_intel_thread(int irq, void *dev_id)
list_for_each_entry(link, &ctx->link_list, list)
sdw_cdns_irq(irq, link->cdns);
- sdw_intel_enable_irq(ctx->mmio_base, true);
return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
@@ -297,24 +272,12 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
{
struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle);
struct sdw_intel_link_dev *ldev;
- u32 caps;
u32 link_mask;
int i;
if (!adev)
return -EINVAL;
- /* Check SNDWLCAP.LCOUNT */
- caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP);
- caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
-
- /* Check HW supported vs property value */
- if (caps < ctx->count) {
- dev_err(&adev->dev,
- "BIOS master count is larger than hardware capabilities\n");
- return -EINVAL;
- }
-
if (!ctx->ldev)
return -EINVAL;
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index b33d5db494a5..cee2b2223141 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -344,6 +344,9 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
if (swrm_wait_for_wr_fifo_avail(swrm))
return SDW_CMD_FAIL_OTHER;
+ if (cmd_id == SWR_BROADCAST_CMD_ID)
+ reinit_completion(&swrm->broadcast);
+
/* Its assumed that write is okay as we do not get any status back */
swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
@@ -377,6 +380,12 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm,
val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr);
+ /*
+ * Check for outstanding cmd wrt. write fifo depth to avoid
+ * overflow as read will also increase write fifo cnt.
+ */
+ swrm_wait_for_wr_fifo_avail(swrm);
+
/* wait for FIFO RD to complete to avoid overflow */
usleep_range(100, 105);
swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c
index e23121456c70..bfc3ab5f39ea 100644
--- a/drivers/spi/spi-amd.c
+++ b/drivers/spi/spi-amd.c
@@ -65,7 +65,7 @@ enum amd_spi_speed {
F_16_66MHz,
F_100MHz,
F_800KHz,
- SPI_SPD7,
+ SPI_SPD7 = 0x7,
F_50MHz = 0x4,
F_4MHz = 0x32,
F_3_17MHz = 0x3F
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index 1322b8cce5b7..ababb910b391 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -128,12 +128,15 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
dw_spi_dma_sg_burst_init(dws);
+ pci_dev_put(dma_dev);
+
return 0;
free_rxchan:
dma_release_channel(dws->rxchan);
dws->rxchan = NULL;
err_exit:
+ pci_dev_put(dma_dev);
return -EBUSY;
}
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 30d82cc7300b..d209930069cf 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -444,8 +444,7 @@ static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
unsigned int pre, post;
unsigned int fin = spi_imx->spi_clk;
- if (unlikely(fspi > fin))
- return 0;
+ fspi = min(fspi, fin);
post = fls(fin) - fls(fspi);
if (fin > fspi << post)
@@ -1608,6 +1607,13 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
return spi_imx_pio_transfer_slave(spi, transfer);
/*
+ * If we decided in spi_imx_can_dma() that we want to do a DMA
+ * transfer, the SPI transfer has already been mapped, so we
+ * have to do the DMA transfer here.
+ */
+ if (spi_imx->usedma)
+ return spi_imx_dma_transfer(spi_imx, transfer);
+ /*
* Calculate the estimated time in us the transfer runs. Find
* the number of Hz per byte per polling limit.
*/
@@ -1618,9 +1624,6 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
if (transfer->len < byte_limit)
return spi_imx_poll_transfer(spi, transfer);
- if (spi_imx->usedma)
- return spi_imx_dma_transfer(spi_imx, transfer);
-
return spi_imx_pio_transfer(spi, transfer);
}
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index 605acb1bf4b0..3ac73691fbb5 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -52,17 +52,17 @@
#define FRACC 0x50
#define FREG(n) (0x54 + ((n) * 4))
-#define FREG_BASE_MASK 0x3fff
+#define FREG_BASE_MASK GENMASK(14, 0)
#define FREG_LIMIT_SHIFT 16
-#define FREG_LIMIT_MASK (0x03fff << FREG_LIMIT_SHIFT)
+#define FREG_LIMIT_MASK GENMASK(30, 16)
/* Offset is from @ispi->pregs */
#define PR(n) ((n) * 4)
#define PR_WPE BIT(31)
#define PR_LIMIT_SHIFT 16
-#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT)
+#define PR_LIMIT_MASK GENMASK(30, 16)
#define PR_RPE BIT(15)
-#define PR_BASE_MASK 0x3fff
+#define PR_BASE_MASK GENMASK(14, 0)
/* Offsets are from @ispi->sregs */
#define SSFSTS_CTL 0x00
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index bad201510a99..1b4195c54ee2 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -160,6 +160,7 @@ struct meson_spicc_device {
struct clk *clk;
struct spi_message *message;
struct spi_transfer *xfer;
+ struct completion done;
const struct meson_spicc_data *data;
u8 *tx_buf;
u8 *rx_buf;
@@ -282,7 +283,7 @@ static irqreturn_t meson_spicc_irq(int irq, void *data)
/* Disable all IRQs */
writel(0, spicc->base + SPICC_INTREG);
- spi_finalize_current_transfer(spicc->master);
+ complete(&spicc->done);
return IRQ_HANDLED;
}
@@ -386,6 +387,7 @@ static int meson_spicc_transfer_one(struct spi_master *master,
struct spi_transfer *xfer)
{
struct meson_spicc_device *spicc = spi_master_get_devdata(master);
+ uint64_t timeout;
/* Store current transfer */
spicc->xfer = xfer;
@@ -410,13 +412,29 @@ static int meson_spicc_transfer_one(struct spi_master *master,
/* Setup burst */
meson_spicc_setup_burst(spicc);
+ /* Setup wait for completion */
+ reinit_completion(&spicc->done);
+
+ /* For each byte we wait for 8 cycles of the SPI clock */
+ timeout = 8LL * MSEC_PER_SEC * xfer->len;
+ do_div(timeout, xfer->speed_hz);
+
+ /* Add 10us delay between each fifo bursts */
+ timeout += ((xfer->len >> 4) * 10) / MSEC_PER_SEC;
+
+ /* Increase it twice and add 200 ms tolerance */
+ timeout += timeout + 200;
+
/* Start burst */
writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
/* Enable interrupts */
writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
- return 1;
+ if (!wait_for_completion_timeout(&spicc->done, msecs_to_jiffies(timeout)))
+ return -ETIMEDOUT;
+
+ return 0;
}
static int meson_spicc_prepare_message(struct spi_master *master,
@@ -743,6 +761,8 @@ static int meson_spicc_probe(struct platform_device *pdev)
spicc->pdev = pdev;
platform_set_drvdata(pdev, spicc);
+ init_completion(&spicc->done);
+
spicc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spicc->base)) {
dev_err(&pdev->dev, "io resource mapping failed\n");
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 11aeae7fe7fc..d6aff909fc36 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -551,14 +551,17 @@ static void mtk_spi_enable_transfer(struct spi_master *master)
writel(cmd, mdata->base + SPI_CMD_REG);
}
-static int mtk_spi_get_mult_delta(u32 xfer_len)
+static int mtk_spi_get_mult_delta(struct mtk_spi *mdata, u32 xfer_len)
{
- u32 mult_delta;
+ u32 mult_delta = 0;
- if (xfer_len > MTK_SPI_PACKET_SIZE)
- mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
- else
- mult_delta = 0;
+ if (mdata->dev_comp->ipm_design) {
+ if (xfer_len > MTK_SPI_IPM_PACKET_SIZE)
+ mult_delta = xfer_len % MTK_SPI_IPM_PACKET_SIZE;
+ } else {
+ if (xfer_len > MTK_SPI_PACKET_SIZE)
+ mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
+ }
return mult_delta;
}
@@ -570,22 +573,22 @@ static void mtk_spi_update_mdata_len(struct spi_master *master)
if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
- mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
+ mult_delta = mtk_spi_get_mult_delta(mdata, mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
mdata->tx_sgl_len -= mdata->xfer_len;
} else {
- mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
+ mult_delta = mtk_spi_get_mult_delta(mdata, mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
mdata->rx_sgl_len -= mdata->xfer_len;
}
} else if (mdata->tx_sgl_len) {
- mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
+ mult_delta = mtk_spi_get_mult_delta(mdata, mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
} else if (mdata->rx_sgl_len) {
- mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
+ mult_delta = mtk_spi_get_mult_delta(mdata, mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
}
@@ -1270,8 +1273,11 @@ static int mtk_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
+ int ret;
- pm_runtime_disable(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ return ret;
mtk_spi_reset(mdata);
@@ -1280,6 +1286,9 @@ static int mtk_spi_remove(struct platform_device *pdev)
clk_unprepare(mdata->spi_hclk);
}
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 6fe617b445a5..def09cf0dc14 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -434,7 +434,7 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
u32 div, mbrdiv;
/* Ensure spi->clk_rate is even */
- div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz);
+ div = DIV_ROUND_CLOSEST(spi->clk_rate & ~0x1, speed_hz);
/*
* SPI framework set xfer->speed_hz to master->max_speed_hz if
@@ -886,6 +886,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
static DEFINE_RATELIMIT_STATE(rs,
DEFAULT_RATELIMIT_INTERVAL * 10,
1);
+ ratelimit_set_flags(&rs, RATELIMIT_MSG_ON_RELEASE);
if (__ratelimit(&rs))
dev_dbg_ratelimited(spi->dev, "Communication suspended\n");
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 904972606bd4..9f356612ba7e 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -720,6 +720,9 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
{
+ if (!tqspi->soc_data->has_dma)
+ return;
+
if (tqspi->tx_dma_buf) {
dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
tqspi->tx_dma_buf, tqspi->tx_dma_phys);
@@ -750,6 +753,9 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
u32 *dma_buf;
int err;
+ if (!tqspi->soc_data->has_dma)
+ return 0;
+
dma_chan = dma_request_chan(tqspi->dev, "rx");
if (IS_ERR(dma_chan)) {
err = PTR_ERR(dma_chan);
@@ -918,8 +924,9 @@ static int tegra_qspi_start_transfer_one(struct spi_device *spi,
static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_device *spi)
{
struct tegra_qspi_client_data *cdata;
+ struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
- cdata = devm_kzalloc(&spi->dev, sizeof(*cdata), GFP_KERNEL);
+ cdata = devm_kzalloc(tqspi->dev, sizeof(*cdata), GFP_KERNEL);
if (!cdata)
return NULL;
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index d4f03b203ae5..b79f93684c4f 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -51,6 +51,7 @@ menuconfig STAGING_MEDIA_DEPRECATED
If in doubt, say N here.
if STAGING_MEDIA_DEPRECATED
+source "drivers/staging/media/deprecated/atmel/Kconfig"
source "drivers/staging/media/deprecated/cpia2/Kconfig"
source "drivers/staging/media/deprecated/fsl-viu/Kconfig"
source "drivers/staging/media/deprecated/meye/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index a387692b84f2..54bbdd4b0d08 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += deprecated/atmel/
obj-$(CONFIG_INTEL_ATOMISP) += atomisp/
obj-$(CONFIG_VIDEO_CPIA2) += deprecated/cpia2/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 783f1b88ebf2..87a634bf9ff5 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -786,8 +786,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
return ret;
}
-static int power_down(struct v4l2_subdev *sd);
-
static int power_up(struct v4l2_subdev *sd)
{
struct gc0310_device *dev = to_gc0310_sensor(sd);
@@ -800,6 +798,9 @@ static int power_up(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (dev->power_on)
+ return 0; /* Already on */
+
/* power control */
ret = power_ctrl(sd, 1);
if (ret)
@@ -820,6 +821,7 @@ static int power_up(struct v4l2_subdev *sd)
msleep(100);
+ dev->power_on = true;
return 0;
fail_gpio:
@@ -844,6 +846,9 @@ static int power_down(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (!dev->power_on)
+ return 0; /* Already off */
+
/* gpio ctrl */
ret = gpio_ctrl(sd, 0);
if (ret) {
@@ -861,6 +866,7 @@ static int power_down(struct v4l2_subdev *sd)
if (ret)
dev_err(&client->dev, "vprog failed.\n");
+ dev->power_on = false;
return ret;
}
@@ -935,6 +941,9 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
return 0;
}
+ /* s_power has not been called yet for std v4l2 clients (camorama) */
+ power_up(sd);
+
dev_dbg(&client->dev, "%s: before gc0310_write_reg_array %s\n",
__func__, dev->res->desc);
ret = startup(sd);
@@ -1073,6 +1082,7 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
* as first power on by board may not fulfill the
* power on sequqence needed by the module
*/
+ dev->power_on = true; /* force power_down() to run */
ret = power_down(sd);
if (ret) {
dev_err(&client->dev, "gc0310 power-off err.\n");
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h
index db643ebc3909..4b9ce681bd93 100644
--- a/drivers/staging/media/atomisp/i2c/gc0310.h
+++ b/drivers/staging/media/atomisp/i2c/gc0310.h
@@ -152,6 +152,7 @@ struct gc0310_device {
int vt_pix_clk_freq_mhz;
struct gc0310_resolution *res;
u8 type;
+ bool power_on;
};
enum gc0310_tok_type {
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index 4e351196fe34..7ab337b859ad 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -485,19 +485,19 @@ static struct ov2680_reg const ov2680_720x592_30fps[] = {
static struct ov2680_reg const ov2680_800x600_30fps[] = {
{0x3086, 0x01},
{0x370a, 0x23},
- {0x3801, 0x00},
+ {0x3801, 0x00}, /* hstart 0 */
{0x3802, 0x00},
- {0x3803, 0x00},
+ {0x3803, 0x00}, /* vstart 0 */
{0x3804, 0x06},
- {0x3805, 0x4f},
+ {0x3805, 0x4f}, /* hend 1615 */
{0x3806, 0x04},
- {0x3807, 0xbf},
+ {0x3807, 0xbf}, /* vend 1215 */
{0x3808, 0x03},
- {0x3809, 0x20},
+ {0x3809, 0x20}, /* hsize 800 */
{0x380a, 0x02},
- {0x380b, 0x58},
+ {0x380b, 0x58}, /* vsize 600 */
{0x380c, 0x06},
- {0x380d, 0xac},
+ {0x380d, 0xac}, /* htotal 1708 */
{0x3810, 0x00},
{0x3811, 0x00},
{0x3812, 0x00},
@@ -524,19 +524,19 @@ static struct ov2680_reg const ov2680_800x600_30fps[] = {
static struct ov2680_reg const ov2680_720p_30fps[] = {
{0x3086, 0x00},
{0x370a, 0x21},
- {0x3801, 0xa0},
+ {0x3801, 0xa0}, /* hstart 160 */
{0x3802, 0x00},
- {0x3803, 0xf2},
+ {0x3803, 0xf2}, /* vstart 242 */
{0x3804, 0x05},
- {0x3805, 0xbf},
+ {0x3805, 0xbf}, /* hend 1471 */
{0x3806, 0x03},
- {0x3807, 0xdd},
+ {0x3807, 0xdd}, /* vend 989 */
{0x3808, 0x05},
- {0x3809, 0x10},
+ {0x3809, 0x10}, /* hsize 1296 */
{0x380a, 0x02},
- {0x380b, 0xe0},
+ {0x380b, 0xe0}, /* vsize 736 */
{0x380c, 0x06},
- {0x380d, 0xa8},
+ {0x380d, 0xa8}, /* htotal 1704 */
{0x3810, 0x00},
{0x3811, 0x08},
{0x3812, 0x00},
@@ -563,19 +563,19 @@ static struct ov2680_reg const ov2680_720p_30fps[] = {
static struct ov2680_reg const ov2680_1296x976_30fps[] = {
{0x3086, 0x00},
{0x370a, 0x21},
- {0x3801, 0xa0},
+ {0x3801, 0xa0}, /* hstart 160 */
{0x3802, 0x00},
- {0x3803, 0x78},
+ {0x3803, 0x78}, /* vstart 120 */
{0x3804, 0x05},
- {0x3805, 0xbf},
+ {0x3805, 0xbf}, /* hend 1471 */
{0x3806, 0x04},
- {0x3807, 0x57},
+ {0x3807, 0x57}, /* vend 1111 */
{0x3808, 0x05},
- {0x3809, 0x10},
+ {0x3809, 0x10}, /* hsize 1296 */
{0x380a, 0x03},
- {0x380b, 0xd0},
+ {0x380b, 0xd0}, /* vsize 976 */
{0x380c, 0x06},
- {0x380d, 0xa8},
+ {0x380d, 0xa8}, /* htotal 1704 */
{0x3810, 0x00},
{0x3811, 0x08},
{0x3812, 0x00},
@@ -820,8 +820,8 @@ static struct ov2680_resolution ov2680_res_preview[] = {
.regs = ov2680_1296x976_30fps,
},
{
- .width = 1280,
- .height = 720,
+ .width = 1296,
+ .height = 736,
.fps = 60,
.pix_clk_freq = 66,
.pixels_per_line = 1698,//1704,
diff --git a/drivers/staging/media/atomisp/include/hmm/hmm.h b/drivers/staging/media/atomisp/include/hmm/hmm.h
index c0384bb0a762..2bc323b34f89 100644
--- a/drivers/staging/media/atomisp/include/hmm/hmm.h
+++ b/drivers/staging/media/atomisp/include/hmm/hmm.h
@@ -37,7 +37,8 @@ int hmm_init(void);
void hmm_cleanup(void);
ia_css_ptr hmm_alloc(size_t bytes);
-ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr);
+ia_css_ptr hmm_create_from_vmalloc_buf(size_t bytes, void *vmalloc_addr);
+
void hmm_free(ia_css_ptr ptr);
int hmm_load(ia_css_ptr virt, void *data, unsigned int bytes);
int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes);
diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h
index c5cbae1d9cf9..b4c03e0ca9c0 100644
--- a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h
+++ b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h
@@ -73,7 +73,7 @@
enum hmm_bo_type {
HMM_BO_PRIVATE,
- HMM_BO_USER,
+ HMM_BO_VMALLOC,
HMM_BO_LAST,
};
@@ -207,7 +207,7 @@ int hmm_bo_allocated(struct hmm_buffer_object *bo);
*/
int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
enum hmm_bo_type type,
- const void __user *userptr);
+ void *vmalloc_addr);
void hmm_bo_free_pages(struct hmm_buffer_object *bo);
int hmm_bo_page_allocated(struct hmm_buffer_object *bo);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index c72d0e344671..d8c7e7367386 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -30,7 +30,6 @@
#include <asm/iosf_mbi.h>
#include <media/v4l2-event.h>
-#include <media/videobuf-vmalloc.h>
#define CREATE_TRACE_POINTS
#include "atomisp_trace_event.h"
@@ -208,11 +207,6 @@ int atomisp_freq_scaling(struct atomisp_device *isp,
int i, ret;
unsigned short fps = 0;
- if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP) {
- dev_err(isp->dev, "DFS cannot proceed due to no power.\n");
- return -EINVAL;
- }
-
if ((pdev->device & ATOMISP_PCI_DEVICE_SOC_MASK) ==
ATOMISP_PCI_DEVICE_SOC_CHT && ATOMISP_USE_YUVPP(asd))
isp->dfs = &dfs_config_cht_soc;
@@ -308,24 +302,16 @@ int atomisp_reset(struct atomisp_device *isp)
int ret = 0;
dev_dbg(isp->dev, "%s\n", __func__);
- atomisp_css_suspend(isp);
- ret = atomisp_runtime_suspend(isp->dev);
+
+ ret = atomisp_power_off(isp->dev);
if (ret < 0)
- dev_err(isp->dev, "atomisp_runtime_suspend failed, %d\n", ret);
- ret = atomisp_mrfld_power_down(isp);
+ dev_err(isp->dev, "atomisp_power_off failed, %d\n", ret);
+
+ ret = atomisp_power_on(isp->dev);
if (ret < 0) {
- dev_err(isp->dev, "can not disable ISP power\n");
- } else {
- ret = atomisp_mrfld_power_up(isp);
- if (ret < 0)
- dev_err(isp->dev, "can not enable ISP power\n");
- ret = atomisp_runtime_resume(isp->dev);
- if (ret < 0)
- dev_err(isp->dev, "atomisp_runtime_resume failed, %d\n", ret);
- }
- ret = atomisp_css_resume(isp);
- if (ret)
+ dev_err(isp->dev, "atomisp_power_on failed, %d\n", ret);
isp->isp_fatal_error = true;
+ }
return ret;
}
@@ -518,8 +504,8 @@ irqreturn_t atomisp_isr(int irq, void *dev)
int err;
spin_lock_irqsave(&isp->lock, flags);
- if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP ||
- !isp->css_initialized) {
+
+ if (!isp->css_initialized) {
spin_unlock_irqrestore(&isp->lock, flags);
return IRQ_HANDLED;
}
@@ -634,25 +620,6 @@ void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd)
memset(asd->metadata_bufs_in_css[i], 0,
sizeof(asd->metadata_bufs_in_css[i]));
asd->dis_bufs_in_css = 0;
- asd->video_out_capture.buffers_in_css = 0;
- asd->video_out_vf.buffers_in_css = 0;
- asd->video_out_preview.buffers_in_css = 0;
- asd->video_out_video_capture.buffers_in_css = 0;
-}
-
-/* ISP2400 */
-bool atomisp_buffers_queued(struct atomisp_sub_device *asd)
-{
- return asd->video_out_capture.buffers_in_css ||
- asd->video_out_vf.buffers_in_css ||
- asd->video_out_preview.buffers_in_css ||
- asd->video_out_video_capture.buffers_in_css;
-}
-
-/* ISP2401 */
-bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe)
-{
- return pipe->buffers_in_css ? true : false;
}
/* 0x100000 is the start of dmem inside SP */
@@ -681,57 +648,68 @@ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
} while (--size32);
}
-static struct videobuf_buffer *atomisp_css_frame_to_vbuf(
- struct atomisp_video_pipe *pipe, struct ia_css_frame *frame)
+int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe)
{
- struct videobuf_vmalloc_memory *vm_mem;
- struct ia_css_frame *handle;
- int i;
+ unsigned long irqflags;
+ struct list_head *pos;
+ int buffers_in_css = 0;
- for (i = 0; pipe->capq.bufs[i]; i++) {
- vm_mem = pipe->capq.bufs[i]->priv;
- handle = vm_mem->vaddr;
- if (handle && handle->data == frame->data)
- return pipe->capq.bufs[i];
- }
+ spin_lock_irqsave(&pipe->irq_lock, irqflags);
- return NULL;
+ list_for_each(pos, &pipe->buffers_in_css)
+ buffers_in_css++;
+
+ spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+
+ return buffers_in_css;
}
-static void atomisp_flush_video_pipe(struct atomisp_sub_device *asd,
- struct atomisp_video_pipe *pipe)
+void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state)
{
+ struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
+
+ lockdep_assert_held(&pipe->irq_lock);
+
+ frame->vb.vb2_buf.timestamp = ktime_get_ns();
+ frame->vb.field = pipe->pix.field;
+ frame->vb.sequence = atomic_read(&pipe->asd->sequence);
+ list_del(&frame->queue);
+ if (state == VB2_BUF_STATE_DONE)
+ vb2_set_plane_payload(&frame->vb.vb2_buf, 0, pipe->pix.sizeimage);
+ vb2_buffer_done(&frame->vb.vb2_buf, state);
+}
+
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames)
+{
+ struct ia_css_frame *frame, *_frame;
unsigned long irqflags;
- int i;
- if (!pipe->users)
- return;
+ spin_lock_irqsave(&pipe->irq_lock, irqflags);
- for (i = 0; pipe->capq.bufs[i]; i++) {
- spin_lock_irqsave(&pipe->irq_lock, irqflags);
- if (pipe->capq.bufs[i]->state == VIDEOBUF_ACTIVE ||
- pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED) {
- pipe->capq.bufs[i]->ts = ktime_get_ns();
- pipe->capq.bufs[i]->field_count =
- atomic_read(&asd->sequence) << 1;
- dev_dbg(asd->isp->dev, "release buffers on device %s\n",
- pipe->vdev.name);
- if (pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED)
- list_del_init(&pipe->capq.bufs[i]->queue);
- pipe->capq.bufs[i]->state = VIDEOBUF_ERROR;
- wake_up(&pipe->capq.bufs[i]->done);
- }
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+ list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) {
+ if (warn_on_css_frames)
+ dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n");
+ atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ }
+
+ list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue)
+ atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+
+ list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) {
+ pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0;
+ atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
}
+
+ spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
}
/* Returns queued buffers back to video-core */
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd)
{
- atomisp_flush_video_pipe(asd, &asd->video_out_capture);
- atomisp_flush_video_pipe(asd, &asd->video_out_vf);
- atomisp_flush_video_pipe(asd, &asd->video_out_preview);
- atomisp_flush_video_pipe(asd, &asd->video_out_video_capture);
+ atomisp_flush_video_pipe(&asd->video_out_capture, false);
+ atomisp_flush_video_pipe(&asd->video_out_vf, false);
+ atomisp_flush_video_pipe(&asd->video_out_preview, false);
+ atomisp_flush_video_pipe(&asd->video_out_video_capture, false);
}
/* clean out the parameters that did not apply */
@@ -763,93 +741,6 @@ static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe)
atomisp_handle_parameter_and_buffer(pipe);
}
-/* find atomisp_video_pipe with css pipe id, buffer type and atomisp run_mode */
-static struct atomisp_video_pipe *__atomisp_get_pipe(
- struct atomisp_sub_device *asd,
- enum atomisp_input_stream_id stream_id,
- enum ia_css_pipe_id css_pipe_id,
- enum ia_css_buffer_type buf_type)
-{
- /* video is same in online as in continuouscapture mode */
- if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
- /*
- * Disable vf_pp and run CSS in still capture mode. In this
- * mode, CSS does not cause extra latency with buffering, but
- * scaling is not available.
- */
- return &asd->video_out_capture;
- } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
- /*
- * Disable vf_pp and run CSS in video mode. This allows using
- * ISP scaling but it has one frame delay due to CSS internal
- * buffering.
- */
- return &asd->video_out_video_capture;
- } else if (css_pipe_id == IA_CSS_PIPE_ID_YUVPP) {
- /*
- * to SOC camera, yuvpp pipe is run for capture/video/SDV/ZSL.
- */
- if (asd->continuous_mode->val) {
- if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
- /* SDV case */
- switch (buf_type) {
- case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
- return &asd->video_out_video_capture;
- case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
- return &asd->video_out_preview;
- case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
- return &asd->video_out_capture;
- default:
- return &asd->video_out_vf;
- }
- } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
- /* ZSL case */
- switch (buf_type) {
- case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
- return &asd->video_out_preview;
- case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
- return &asd->video_out_capture;
- default:
- return &asd->video_out_vf;
- }
- }
- } else if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
- switch (asd->run_mode->val) {
- case ATOMISP_RUN_MODE_VIDEO:
- return &asd->video_out_video_capture;
- case ATOMISP_RUN_MODE_PREVIEW:
- return &asd->video_out_preview;
- default:
- return &asd->video_out_capture;
- }
- } else if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
- if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
- return &asd->video_out_preview;
- else
- return &asd->video_out_vf;
- }
- } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
- /* For online video or SDV video pipe. */
- if (css_pipe_id == IA_CSS_PIPE_ID_VIDEO ||
- css_pipe_id == IA_CSS_PIPE_ID_COPY ||
- css_pipe_id == IA_CSS_PIPE_ID_YUVPP) {
- if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
- return &asd->video_out_video_capture;
- return &asd->video_out_preview;
- }
- } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
- /* For online preview or ZSL preview pipe. */
- if (css_pipe_id == IA_CSS_PIPE_ID_PREVIEW ||
- css_pipe_id == IA_CSS_PIPE_ID_COPY ||
- css_pipe_id == IA_CSS_PIPE_ID_YUVPP)
- return &asd->video_out_preview;
- }
- /* For capture pipe. */
- if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
- return &asd->video_out_vf;
- return &asd->video_out_capture;
-}
-
enum atomisp_metadata_type
atomisp_get_metadata_type(struct atomisp_sub_device *asd,
enum ia_css_pipe_id pipe_id)
@@ -868,11 +759,9 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
enum ia_css_pipe_id css_pipe_id,
bool q_buffers, enum atomisp_input_stream_id stream_id)
{
- struct videobuf_buffer *vb = NULL;
struct atomisp_video_pipe *pipe = NULL;
struct atomisp_css_buffer buffer;
bool requeue = false;
- int err;
unsigned long irqflags;
struct ia_css_frame *frame = NULL;
struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter;
@@ -881,6 +770,7 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
enum atomisp_metadata_type md_type;
struct atomisp_device *isp = asd->isp;
struct v4l2_control ctrl;
+ int i, err;
lockdep_assert_held(&isp->mutex);
@@ -908,13 +798,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
return;
}
- /* need to know the atomisp pipe for frame buffers */
- pipe = __atomisp_get_pipe(asd, stream_id, css_pipe_id, buf_type);
- if (!pipe) {
- dev_err(isp->dev, "error getting atomisp pipe\n");
- return;
- }
-
switch (buf_type) {
case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp,
@@ -989,7 +872,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
break;
case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
- pipe->buffers_in_css--;
frame = buffer.css_buffer.data.frame;
if (!frame) {
WARN_ON(1);
@@ -998,6 +880,8 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
if (!frame->valid)
error = true;
+ pipe = vb_to_pipe(&frame->vb.vb2_buf);
+
/* FIXME:
* YUVPP doesn't set postview exp_id correctlly in SDV mode.
* This is a WORKAROUND to set exp_id. see HSDES-1503911606.
@@ -1022,10 +906,7 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
dev_dbg(isp->dev, "%s thumb no flash in this frame\n",
__func__);
}
- vb = atomisp_css_frame_to_vbuf(pipe, frame);
- WARN_ON(!vb);
- if (vb)
- pipe->frame_config_id[vb->i] = frame->isp_config_id;
+ pipe->frame_config_id[frame->vb.vb2_buf.index] = frame->isp_config_id;
if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE &&
asd->pending_capture_request > 0) {
err = atomisp_css_offline_capture_configure(asd,
@@ -1041,7 +922,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
break;
case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
- pipe->buffers_in_css--;
frame = buffer.css_buffer.data.frame;
if (!frame) {
WARN_ON(1);
@@ -1051,6 +931,8 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
if (!frame->valid)
error = true;
+ pipe = vb_to_pipe(&frame->vb.vb2_buf);
+
/* FIXME:
* YUVPP doesn't set preview exp_id correctlly in ZSL mode.
* This is a WORKAROUND to set exp_id. see HSDES-1503911606.
@@ -1062,72 +944,53 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n",
__func__, frame->exp_id);
- vb = atomisp_css_frame_to_vbuf(pipe, frame);
- if (!vb) {
- WARN_ON(1);
- break;
- }
+
+ i = frame->vb.vb2_buf.index;
/* free the parameters */
- if (pipe->frame_params[vb->i]) {
- if (asd->params.dvs_6axis ==
- pipe->frame_params[vb->i]->params.dvs_6axis)
+ if (pipe->frame_params[i]) {
+ if (asd->params.dvs_6axis == pipe->frame_params[i]->params.dvs_6axis)
asd->params.dvs_6axis = NULL;
- atomisp_free_css_parameters(
- &pipe->frame_params[vb->i]->params);
- kvfree(pipe->frame_params[vb->i]);
- pipe->frame_params[vb->i] = NULL;
+ atomisp_free_css_parameters(&pipe->frame_params[i]->params);
+ kvfree(pipe->frame_params[i]);
+ pipe->frame_params[i] = NULL;
}
- pipe->frame_config_id[vb->i] = frame->isp_config_id;
+ pipe->frame_config_id[i] = frame->isp_config_id;
ctrl.id = V4L2_CID_FLASH_MODE;
if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
- if (frame->flash_state
- == IA_CSS_FRAME_FLASH_STATE_PARTIAL) {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_FLASH_PARTIAL;
- dev_dbg(isp->dev, "%s partially flashed\n",
- __func__);
- } else if (frame->flash_state
- == IA_CSS_FRAME_FLASH_STATE_FULL) {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
+ if (frame->flash_state == IA_CSS_FRAME_FLASH_STATE_PARTIAL) {
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_PARTIAL;
+ dev_dbg(isp->dev, "%s partially flashed\n", __func__);
+ } else if (frame->flash_state == IA_CSS_FRAME_FLASH_STATE_FULL) {
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
asd->params.num_flash_frames--;
- dev_dbg(isp->dev, "%s completely flashed\n",
- __func__);
+ dev_dbg(isp->dev, "%s completely flashed\n", __func__);
} else {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_OK;
- dev_dbg(isp->dev,
- "%s no flash in this frame\n",
- __func__);
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
+ dev_dbg(isp->dev, "%s no flash in this frame\n", __func__);
}
/* Check if flashing sequence is done */
- if (asd->frame_status[vb->i] ==
- ATOMISP_FRAME_STATUS_FLASH_EXPOSED)
+ if (asd->frame_status[i] == ATOMISP_FRAME_STATUS_FLASH_EXPOSED)
asd->params.flash_state = ATOMISP_FLASH_DONE;
} else if (isp->flash) {
- if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) ==
- 0 && ctrl.value == ATOMISP_FLASH_MODE_TORCH) {
+ if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) == 0 &&
+ ctrl.value == ATOMISP_FLASH_MODE_TORCH) {
ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY;
- if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl)
- == 0 && ctrl.value > 0) {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
- } else {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_OK;
- }
+ if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) == 0 &&
+ ctrl.value > 0)
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
+ else
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
} else {
- asd->frame_status[vb->i] =
- ATOMISP_FRAME_STATUS_OK;
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
}
} else {
- asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK;
+ asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
}
- asd->params.last_frame_status = asd->frame_status[vb->i];
+ asd->params.last_frame_status = asd->frame_status[i];
if (asd->continuous_mode->val) {
if (css_pipe_id == IA_CSS_PIPE_ID_PREVIEW ||
@@ -1193,20 +1056,10 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
default:
break;
}
- if (vb) {
- vb->ts = ktime_get_ns();
- vb->field_count = atomic_read(&asd->sequence) << 1;
- /*mark videobuffer done for dequeue*/
+ if (frame) {
spin_lock_irqsave(&pipe->irq_lock, irqflags);
- vb->state = !error ? VIDEOBUF_DONE : VIDEOBUF_ERROR;
+ atomisp_buffer_done(frame, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
-
- /*
- * Frame capture done, wake up any process block on
- * current active buffer
- * possibly hold by videobuf_dqbuf()
- */
- wake_up(&vb->done);
}
/*
@@ -3288,7 +3141,7 @@ int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd,
if (!IS_ISP2401) {
if (sizeof(*cur) != sizeof(coefs->grid) ||
memcmp(&coefs->grid, cur, sizeof(coefs->grid))) {
- dev_err(asd->isp->dev, "dvs grid mis-match!\n");
+ dev_err(asd->isp->dev, "dvs grid mismatch!\n");
/* If the grid info in the argument differs from the current
grid info, we tell the caller to reset the grid size and
try again. */
@@ -3344,7 +3197,7 @@ int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd,
if (sizeof(*cur) != sizeof(dvs2_coefs.grid) ||
memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) {
- dev_err(asd->isp->dev, "dvs grid mis-match!\n");
+ dev_err(asd->isp->dev, "dvs grid mismatch!\n");
/* If the grid info in the argument differs from the current
grid info, we tell the caller to reset the grid size and
try again. */
@@ -3676,6 +3529,18 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
}
}
+static void atomisp_move_frame_to_activeq(struct ia_css_frame *frame,
+ struct atomisp_css_params_with_list *param)
+{
+ struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
+ unsigned long irqflags;
+
+ pipe->frame_params[frame->vb.vb2_buf.index] = param;
+ spin_lock_irqsave(&pipe->irq_lock, irqflags);
+ list_move_tail(&frame->queue, &pipe->activeq);
+ spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+}
+
/*
* Check parameter queue list and buffer queue list to find out if matched items
* and then set parameter to CSS and enqueue buffer to CSS.
@@ -3686,13 +3551,10 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
{
struct atomisp_sub_device *asd = pipe->asd;
- struct videobuf_buffer *vb = NULL, *vb_tmp;
+ struct ia_css_frame *frame = NULL, *frame_tmp;
struct atomisp_css_params_with_list *param = NULL, *param_tmp;
- struct videobuf_vmalloc_memory *vm_mem = NULL;
- unsigned long irqflags;
bool need_to_enqueue_buffer = false;
-
- lockdep_assert_held(&asd->isp->mutex);
+ int i;
if (!asd) {
dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
@@ -3700,6 +3562,8 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
return;
}
+ lockdep_assert_held(&asd->isp->mutex);
+
if (atomisp_is_vf_pipe(pipe))
return;
@@ -3714,44 +3578,32 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
list_empty(&pipe->buffers_waiting_for_param))
return;
- list_for_each_entry_safe(vb, vb_tmp,
+ list_for_each_entry_safe(frame, frame_tmp,
&pipe->buffers_waiting_for_param, queue) {
- if (pipe->frame_request_config_id[vb->i]) {
+ i = frame->vb.vb2_buf.index;
+ if (pipe->frame_request_config_id[i]) {
list_for_each_entry_safe(param, param_tmp,
&pipe->per_frame_params, list) {
- if (pipe->frame_request_config_id[vb->i] !=
- param->params.isp_config_id)
+ if (pipe->frame_request_config_id[i] != param->params.isp_config_id)
continue;
list_del(&param->list);
- list_del(&vb->queue);
+
/*
* clear the request config id as the buffer
* will be handled and enqueued into CSS soon
*/
- pipe->frame_request_config_id[vb->i] = 0;
- pipe->frame_params[vb->i] = param;
- vm_mem = vb->priv;
- BUG_ON(!vm_mem);
+ pipe->frame_request_config_id[i] = 0;
+ atomisp_move_frame_to_activeq(frame, param);
+ need_to_enqueue_buffer = true;
break;
}
- if (vm_mem) {
- spin_lock_irqsave(&pipe->irq_lock, irqflags);
- list_add_tail(&vb->queue, &pipe->activeq);
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
- vm_mem = NULL;
- need_to_enqueue_buffer = true;
- } else {
- /* The is the end, stop further loop */
+ /* If this is the end, stop further loop */
+ if (list_entry_is_head(param, &pipe->per_frame_params, list))
break;
- }
} else {
- list_del(&vb->queue);
- pipe->frame_params[vb->i] = NULL;
- spin_lock_irqsave(&pipe->irq_lock, irqflags);
- list_add_tail(&vb->queue, &pipe->activeq);
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+ atomisp_move_frame_to_activeq(frame, NULL);
need_to_enqueue_buffer = true;
}
}
@@ -3774,14 +3626,14 @@ int atomisp_set_parameters(struct video_device *vdev,
struct atomisp_css_params *css_param = &asd->params.css_param;
int ret;
- lockdep_assert_held(&asd->isp->mutex);
-
if (!asd) {
dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
__func__, vdev->name);
return -EINVAL;
}
+ lockdep_assert_held(&asd->isp->mutex);
+
if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
dev_err(asd->isp->dev, "%s: internal error!\n", __func__);
return -EINVAL;
@@ -5140,9 +4992,8 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
return css_input_resolution_changed(asd, ffmt);
}
-int atomisp_set_fmt(struct file *file, void *unused, struct v4l2_format *f)
+int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
@@ -5558,8 +5409,6 @@ done:
f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width *
pipe->pix.height * 2);
- pipe->capq.field = f->fmt.pix.field;
-
/*
* If in video 480P case, no GFX throttle
*/
@@ -5643,51 +5492,6 @@ out:
return ret;
}
-/*Turn off ISP dphy */
-int atomisp_ospm_dphy_down(struct atomisp_device *isp)
-{
- struct pci_dev *pdev = to_pci_dev(isp->dev);
- unsigned long flags;
- u32 reg;
-
- dev_dbg(isp->dev, "%s\n", __func__);
-
- /* if ISP timeout, we can force powerdown */
- if (isp->isp_timeout)
- goto done;
-
- if (!atomisp_dev_users(isp))
- goto done;
-
- spin_lock_irqsave(&isp->lock, flags);
- isp->sw_contex.power_state = ATOM_ISP_POWER_DOWN;
- spin_unlock_irqrestore(&isp->lock, flags);
-done:
- /*
- * MRFLD IUNIT DPHY is located in an always-power-on island
- * MRFLD HW design need all CSI ports are disabled before
- * powering down the IUNIT.
- */
- pci_read_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, &reg);
- reg |= MRFLD_ALL_CSI_PORTS_OFF_MASK;
- pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg);
- return 0;
-}
-
-/*Turn on ISP dphy */
-int atomisp_ospm_dphy_up(struct atomisp_device *isp)
-{
- unsigned long flags;
-
- dev_dbg(isp->dev, "%s\n", __func__);
-
- spin_lock_irqsave(&isp->lock, flags);
- isp->sw_contex.power_state = ATOM_ISP_POWER_UP;
- spin_unlock_irqrestore(&isp->lock, flags);
-
- return 0;
-}
-
int atomisp_exif_makernote(struct atomisp_sub_device *asd,
struct atomisp_makernote_info *config)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
index c9f92f1326b6..b8911491581a 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
@@ -55,12 +55,11 @@ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd);
struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev);
int atomisp_reset(struct atomisp_device *isp);
+int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe);
+void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state);
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames);
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd);
void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd);
-/* ISP2400 */
-bool atomisp_buffers_queued(struct atomisp_sub_device *asd);
-/* ISP2401 */
-bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe);
/* Interrupt functions */
void atomisp_msi_irq_init(struct atomisp_device *isp);
@@ -266,7 +265,7 @@ int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
bool *res_overflow);
-int atomisp_set_fmt(struct file *file, void *fh, struct v4l2_format *f);
+int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f);
int atomisp_set_shading_table(struct atomisp_sub_device *asd,
struct atomisp_shading_table *shading_table);
@@ -274,8 +273,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd,
int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
struct atomisp_cont_capture_conf *cvf_config);
-int atomisp_ospm_dphy_down(struct atomisp_device *isp);
-int atomisp_ospm_dphy_up(struct atomisp_device *isp);
int atomisp_exif_makernote(struct atomisp_sub_device *asd,
struct atomisp_makernote_info *config);
@@ -342,8 +339,6 @@ int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event);
int atomisp_get_invalid_frame_num(struct video_device *vdev,
int *invalid_frame_num);
-int atomisp_mrfld_power_up(struct atomisp_device *isp);
-int atomisp_mrfld_power_down(struct atomisp_device *isp);
-int atomisp_runtime_suspend(struct device *dev);
-int atomisp_runtime_resume(struct device *dev);
+int atomisp_power_off(struct device *dev);
+int atomisp_power_on(struct device *dev);
#endif /* __ATOMISP_CMD_H__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_common.h b/drivers/staging/media/atomisp/pci/atomisp_common.h
index b29874f2bc0f..07c38e487a66 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_common.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_common.h
@@ -25,7 +25,7 @@
#include <linux/v4l2-mediabus.h>
-#include <media/videobuf-core.h>
+#include <media/videobuf2-v4l2.h>
#include "atomisp_compat.h"
@@ -64,8 +64,4 @@ struct atomisp_fmt {
u32 bayer_order;
};
-struct atomisp_buffer {
- struct videobuf_buffer vb;
-};
-
#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h
index a6d85d0f9ae5..7316eb9f974a 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_compat.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h
@@ -22,7 +22,6 @@
#include "atomisp_compat_css20.h"
#include "../../include/linux/atomisp.h"
-#include <media/videobuf-vmalloc.h>
struct atomisp_device;
struct atomisp_sub_device;
@@ -42,10 +41,6 @@ int atomisp_css_init(struct atomisp_device *isp);
void atomisp_css_uninit(struct atomisp_device *isp);
-void atomisp_css_suspend(struct atomisp_device *isp);
-
-int atomisp_css_resume(struct atomisp_device *isp);
-
void atomisp_css_init_struct(struct atomisp_sub_device *asd);
int atomisp_css_irq_translate(struct atomisp_device *isp,
@@ -61,7 +56,7 @@ int atomisp_css_irq_enable(struct atomisp_device *isp,
enum ia_css_irq_info info, bool enable);
int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
- struct videobuf_vmalloc_memory *vm_mem,
+ struct ia_css_frame *frame,
enum atomisp_input_stream_id stream_id,
enum ia_css_buffer_type css_buf_type,
enum ia_css_pipe_id css_pipe_id);
@@ -258,13 +253,6 @@ int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd,
unsigned int padded_width,
enum ia_css_frame_format format);
-int atomisp_css_yuvpp_configure_viewfinder(
- struct atomisp_sub_device *asd,
- unsigned int stream_index,
- unsigned int width, unsigned int height,
- unsigned int min_width,
- enum ia_css_frame_format format);
-
int atomisp_css_yuvpp_get_output_frame_info(
struct atomisp_sub_device *asd,
unsigned int stream_index,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
index fdc05548d972..61e2e63a0ef1 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
@@ -237,18 +237,6 @@ static void __dump_pipe_config(struct atomisp_sub_device *asd,
"pipe_config.isp_pipe_version:%d.\n",
p_config->isp_pipe_version);
dev_dbg(isp->dev,
- "pipe_config.acc_extension=%p.\n",
- p_config->acc_extension);
- dev_dbg(isp->dev,
- "pipe_config.acc_stages=%p.\n",
- p_config->acc_stages);
- dev_dbg(isp->dev,
- "pipe_config.num_acc_stages=%d.\n",
- p_config->num_acc_stages);
- dev_dbg(isp->dev,
- "pipe_config.acc_num_execs=%d.\n",
- p_config->acc_num_execs);
- dev_dbg(isp->dev,
"pipe_config.default_capture_config.capture_mode=%d.\n",
p_config->default_capture_config.mode);
dev_dbg(isp->dev,
@@ -629,10 +617,6 @@ static void __apply_additional_pipe_config(
else
stream_env->pipe_configs[pipe_id].enable_dz = false;
break;
- case IA_CSS_PIPE_ID_ACC:
- stream_env->pipe_configs[pipe_id].mode = IA_CSS_PIPE_MODE_ACC;
- stream_env->pipe_configs[pipe_id].enable_dz = false;
- break;
default:
break;
}
@@ -644,7 +628,7 @@ static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd,
if (!asd)
return false;
- if (pipe_id == IA_CSS_PIPE_ID_ACC || pipe_id == IA_CSS_PIPE_ID_YUVPP)
+ if (pipe_id == IA_CSS_PIPE_ID_YUVPP)
return true;
if (asd->vfpp) {
@@ -718,12 +702,7 @@ static int __create_pipe(struct atomisp_sub_device *asd,
if (pipe_id >= IA_CSS_PIPE_ID_NUM)
return -EINVAL;
- if (pipe_id != IA_CSS_PIPE_ID_ACC &&
- !stream_env->pipe_configs[pipe_id].output_info[0].res.width)
- return 0;
-
- if (pipe_id == IA_CSS_PIPE_ID_ACC &&
- !stream_env->pipe_configs[pipe_id].acc_extension)
+ if (!stream_env->pipe_configs[pipe_id].output_info[0].res.width)
return 0;
if (!is_pipe_valid_to_current_run_mode(asd, pipe_id))
@@ -885,48 +864,10 @@ int atomisp_css_load_firmware(struct atomisp_device *isp)
void atomisp_css_uninit(struct atomisp_device *isp)
{
- struct atomisp_sub_device *asd;
- unsigned int i;
-
- for (i = 0; i < isp->num_of_streams; i++) {
- asd = &isp->asd[i];
- memset(&asd->params.config, 0, sizeof(asd->params.config));
- asd->params.css_update_params_needed = false;
- }
-
- isp->css_initialized = false;
- ia_css_uninit();
-}
-
-void atomisp_css_suspend(struct atomisp_device *isp)
-{
isp->css_initialized = false;
ia_css_uninit();
}
-int atomisp_css_resume(struct atomisp_device *isp)
-{
- unsigned int mmu_base_addr;
- int ret;
-
- ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr);
- if (ret) {
- dev_err(isp->dev, "get base address error.\n");
- return -EINVAL;
- }
-
- ret = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL,
- mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE);
- if (ret) {
- dev_err(isp->dev, "re-init css failed.\n");
- return -EINVAL;
- }
- ia_css_enable_isys_event_queue(true);
-
- isp->css_initialized = true;
- return 0;
-}
-
int atomisp_css_irq_translate(struct atomisp_device *isp,
unsigned int *infos)
{
@@ -996,7 +937,7 @@ void atomisp_css_init_struct(struct atomisp_sub_device *asd)
}
int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
- struct videobuf_vmalloc_memory *vm_mem,
+ struct ia_css_frame *frame,
enum atomisp_input_stream_id stream_id,
enum ia_css_buffer_type css_buf_type,
enum ia_css_pipe_id css_pipe_id)
@@ -1006,7 +947,7 @@ int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
int err;
css_buf.type = css_buf_type;
- css_buf.data.frame = vm_mem->vaddr;
+ css_buf.data.frame = frame;
err = ia_css_pipe_enqueue_buffer(
stream_env->pipes[css_pipe_id], &css_buf);
@@ -2141,8 +2082,6 @@ static enum ia_css_pipe_mode __pipe_id_to_pipe_mode(
return IA_CSS_PIPE_MODE_CAPTURE;
case IA_CSS_PIPE_ID_VIDEO:
return IA_CSS_PIPE_MODE_VIDEO;
- case IA_CSS_PIPE_ID_ACC:
- return IA_CSS_PIPE_MODE_ACC;
case IA_CSS_PIPE_ID_YUVPP:
return IA_CSS_PIPE_MODE_YUVPP;
default:
@@ -2688,7 +2627,7 @@ int atomisp_get_css_frame_info(struct atomisp_sub_device *asd,
if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index]
.pipes[pipe_index], &info)) {
- dev_err(isp->dev, "ia_css_pipe_get_info FAILED");
+ dev_dbg(isp->dev, "ia_css_pipe_get_info FAILED");
return -EINVAL;
}
@@ -2765,29 +2704,6 @@ int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd,
return 0;
}
-int atomisp_css_yuvpp_configure_viewfinder(
- struct atomisp_sub_device *asd,
- unsigned int stream_index,
- unsigned int width, unsigned int height,
- unsigned int min_width,
- enum ia_css_frame_format format)
-{
- struct atomisp_stream_env *stream_env =
- &asd->stream_env[stream_index];
- enum ia_css_pipe_id pipe_id = IA_CSS_PIPE_ID_YUVPP;
-
- stream_env->pipe_configs[pipe_id].mode =
- __pipe_id_to_pipe_mode(asd, pipe_id);
- stream_env->update_pipe[pipe_id] = true;
-
- stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width;
- stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height;
- stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format;
- stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width =
- min_width;
- return 0;
-}
-
int atomisp_css_yuvpp_get_output_frame_info(
struct atomisp_sub_device *asd,
unsigned int stream_index,
@@ -3180,7 +3096,7 @@ static int atomisp_compare_dvs_grid(struct atomisp_sub_device *asd,
}
if (sizeof(*cur) != sizeof(*atomgrid)) {
- dev_err(asd->isp->dev, "dvs grid mis-match!\n");
+ dev_err(asd->isp->dev, "dvs grid mismatch!\n");
return -EINVAL;
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c
index 84a84e0cdeef..acea7492847d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c
@@ -22,7 +22,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ioctl.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
#include "atomisp_cmd.h"
#include "atomisp_common.h"
@@ -35,49 +35,74 @@
#include "atomisp-regs.h"
#include "hmm/hmm.h"
+#include "ia_css_frame.h"
#include "type_support.h"
#include "device_access/device_access.h"
-#define ISP_LEFT_PAD 128 /* equal to 2*NWAY */
-
/*
- * input image data, and current frame resolution for test
+ * Videobuf2 ops
*/
-#define ISP_PARAM_MMAP_OFFSET 0xfffff000
+static int atomisp_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct atomisp_video_pipe *pipe = container_of(vq, struct atomisp_video_pipe, vb_queue);
+ u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
+ int ret;
-#define MAGIC_CHECK(is, should) \
- do { \
- if (unlikely((is) != (should))) { \
- pr_err("magic mismatch: %x (expected %x)\n", \
- is, should); \
- BUG(); \
- } \
- } while (0)
+ mutex_lock(&pipe->asd->isp->mutex); /* for get_css_frame_info() / set_fmt() */
-/*
- * Videobuf ops
- */
-static int atomisp_buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct atomisp_video_pipe *pipe = vq->priv_data;
+ /*
+ * When VIDIOC_S_FMT has not been called before VIDIOC_REQBUFS, then
+ * this will fail. Call atomisp_set_fmt() ourselves and try again.
+ */
+ ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info);
+ if (ret) {
+ struct v4l2_format f = {
+ .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420,
+ .fmt.pix.width = 10000,
+ .fmt.pix.height = 10000,
+ };
+
+ ret = atomisp_set_fmt(&pipe->vdev, &f);
+ if (ret)
+ goto out;
+
+ ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info);
+ if (ret)
+ goto out;
+ }
+
+ atomisp_alloc_css_stat_bufs(pipe->asd, ATOMISP_INPUT_STREAM_GENERAL);
- *size = pipe->pix.sizeimage;
+ *nplanes = 1;
+ sizes[0] = PAGE_ALIGN(pipe->pix.sizeimage);
+out:
+ mutex_unlock(&pipe->asd->isp->mutex);
return 0;
}
-static int atomisp_buf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int atomisp_buf_init(struct vb2_buffer *vb)
{
- struct atomisp_video_pipe *pipe = vq->priv_data;
+ struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
+ struct ia_css_frame *frame = vb_to_frame(vb);
+ int ret;
+
+ ret = ia_css_frame_init_from_info(frame, &pipe->frame_info);
+ if (ret)
+ return ret;
- vb->size = pipe->pix.sizeimage;
- vb->width = pipe->pix.width;
- vb->height = pipe->pix.height;
- vb->field = field;
- vb->state = VIDEOBUF_PREPARED;
+ if (frame->data_bytes > vb2_plane_size(vb, 0)) {
+ dev_err(pipe->asd->isp->dev, "Internal error frame.data_bytes(%u) > vb.length(%lu)\n",
+ frame->data_bytes, vb2_plane_size(vb, 0));
+ return -EIO;
+ }
+
+ frame->data = hmm_create_from_vmalloc_buf(vb2_plane_size(vb, 0),
+ vb2_plane_vaddr(vb, 0));
+ if (frame->data == mmgr_NULL)
+ return -ENOMEM;
return 0;
}
@@ -156,8 +181,7 @@ static int atomisp_q_one_s3a_buffer(struct atomisp_sub_device *asd,
} else {
list_add_tail(&s3a_buf->list, &asd->s3a_stats_in_css);
if (s3a_list == &asd->s3a_stats_ready)
- dev_warn(asd->isp->dev, "%s: drop one s3a stat which has exp_id %d!\n",
- __func__, exp_id);
+ dev_dbg(asd->isp->dev, "drop one s3a stat with exp_id %d\n", exp_id);
}
asd->s3a_bufs_in_css[css_pipe_id]++;
@@ -206,43 +230,44 @@ static int atomisp_q_one_dis_buffer(struct atomisp_sub_device *asd,
return 0;
}
-int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
- struct atomisp_video_pipe *pipe,
- enum atomisp_input_stream_id stream_id,
- enum ia_css_buffer_type css_buf_type,
- enum ia_css_pipe_id css_pipe_id)
+static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
+ struct atomisp_video_pipe *pipe,
+ enum atomisp_input_stream_id stream_id,
+ enum ia_css_buffer_type css_buf_type,
+ enum ia_css_pipe_id css_pipe_id)
{
- struct videobuf_vmalloc_memory *vm_mem;
struct atomisp_css_params_with_list *param;
struct ia_css_dvs_grid_info *dvs_grid =
atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
unsigned long irqflags;
- int err = 0;
+ int space, err = 0;
+
+ lockdep_assert_held(&asd->isp->mutex);
if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM))
return -EINVAL;
- while (pipe->buffers_in_css < ATOMISP_CSS_Q_DEPTH) {
- struct videobuf_buffer *vb;
+ if (pipe->stopping)
+ return -EINVAL;
+
+ space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe);
+ while (space--) {
+ struct ia_css_frame *frame;
spin_lock_irqsave(&pipe->irq_lock, irqflags);
- if (list_empty(&pipe->activeq)) {
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
- return -EINVAL;
- }
- vb = list_entry(pipe->activeq.next,
- struct videobuf_buffer, queue);
- list_del_init(&vb->queue);
- vb->state = VIDEOBUF_ACTIVE;
+ frame = list_first_entry_or_null(&pipe->activeq, struct ia_css_frame, queue);
+ if (frame)
+ list_move_tail(&frame->queue, &pipe->buffers_in_css);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+ if (!frame)
+ return -EINVAL;
+
/*
* If there is a per_frame setting to apply on the buffer,
* do it before buffer en-queueing.
*/
- vm_mem = vb->priv;
-
- param = pipe->frame_params[vb->i];
+ param = pipe->frame_params[frame->vb.vb2_buf.index];
if (param) {
atomisp_makeup_css_parameters(asd,
&asd->params.css_param.update_flag,
@@ -256,8 +281,7 @@ int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
if (!err)
asd->params.config.dz_config = &param->params.dz_config;
}
- atomisp_css_set_isp_config_applied_frame(asd,
- vm_mem->vaddr);
+ atomisp_css_set_isp_config_applied_frame(asd, frame);
atomisp_css_update_isp_params_on_pipe(asd,
asd->stream_env[stream_id].pipes[css_pipe_id]);
asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *)
@@ -282,20 +306,19 @@ int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
&asd->params.css_param.dz_config;
asd->params.css_update_params_needed = true;
}
+ pipe->frame_params[frame->vb.vb2_buf.index] = NULL;
}
/* Enqueue buffer */
- err = atomisp_q_video_buffer_to_css(asd, vm_mem, stream_id,
+ err = atomisp_q_video_buffer_to_css(asd, frame, stream_id,
css_buf_type, css_pipe_id);
if (err) {
spin_lock_irqsave(&pipe->irq_lock, irqflags);
- list_add_tail(&vb->queue, &pipe->activeq);
- vb->state = VIDEOBUF_QUEUED;
+ list_move_tail(&frame->queue, &pipe->activeq);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
dev_err(asd->isp->dev, "%s, css q fails: %d\n",
__func__, err);
return -EINVAL;
}
- pipe->buffers_in_css++;
/* enqueue 3A/DIS/metadata buffers */
if (asd->params.curr_grid_info.s3a_grid.enable &&
@@ -517,11 +540,32 @@ int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd)
return 0;
}
-static void atomisp_buf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void atomisp_buf_queue(struct vb2_buffer *vb)
{
- struct atomisp_video_pipe *pipe = vq->priv_data;
+ struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
+ struct ia_css_frame *frame = vb_to_frame(vb);
+ struct atomisp_sub_device *asd = pipe->asd;
+ u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
+ unsigned long irqflags;
+ int ret;
+
+ mutex_lock(&asd->isp->mutex);
+
+ ret = atomisp_pipe_check(pipe, false);
+ if (ret || pipe->stopping) {
+ spin_lock_irqsave(&pipe->irq_lock, irqflags);
+ atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+ goto out_unlock;
+ }
+
+ /* FIXME this ugliness comes from the original atomisp buffer handling */
+ if (!(vb->skip_cache_sync_on_finish && vb->skip_cache_sync_on_prepare))
+ wbinvd();
+ pipe->frame_params[vb->index] = NULL;
+
+ spin_lock_irqsave(&pipe->irq_lock, irqflags);
/*
* when a frame buffer meets following conditions, it should be put into
* the waiting list:
@@ -533,40 +577,83 @@ static void atomisp_buf_queue(struct videobuf_queue *vq,
* get enqueued.
*/
if (!atomisp_is_vf_pipe(pipe) &&
- (pipe->frame_request_config_id[vb->i] ||
+ (pipe->frame_request_config_id[vb->index] ||
!list_empty(&pipe->buffers_waiting_for_param)))
- list_add_tail(&vb->queue, &pipe->buffers_waiting_for_param);
+ list_add_tail(&frame->queue, &pipe->buffers_waiting_for_param);
else
- list_add_tail(&vb->queue, &pipe->activeq);
+ list_add_tail(&frame->queue, &pipe->activeq);
+
+ spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
+
+ /* TODO: do this better, not best way to queue to css */
+ if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
+ if (!list_empty(&pipe->buffers_waiting_for_param))
+ atomisp_handle_parameter_and_buffer(pipe);
+ else
+ atomisp_qbuffers_to_css(asd);
+ }
+
+ /*
+ * Workaround: Due to the design of HALv3,
+ * sometimes in ZSL or SDV mode HAL needs to
+ * capture multiple images within one streaming cycle.
+ * But the capture number cannot be determined by HAL.
+ * So HAL only sets the capture number to be 1 and queue multiple
+ * buffers. Atomisp driver needs to check this case and re-trigger
+ * CSS to do capture when new buffer is queued.
+ */
+ if (asd->continuous_mode->val && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
+ !asd->enable_raw_buffer_lock->val && asd->params.offline_parm.num_captures == 1) {
+ asd->pending_capture_request++;
+ dev_dbg(asd->isp->dev, "Add one pending capture request.\n");
+ }
- vb->state = VIDEOBUF_QUEUED;
+out_unlock:
+ mutex_unlock(&asd->isp->mutex);
}
-static void atomisp_buf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void atomisp_buf_cleanup(struct vb2_buffer *vb)
{
- vb->state = VIDEOBUF_NEEDS_INIT;
- atomisp_videobuf_free_buf(vb);
+ struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
+ struct ia_css_frame *frame = vb_to_frame(vb);
+ int index = frame->vb.vb2_buf.index;
+
+ pipe->frame_request_config_id[index] = 0;
+ pipe->frame_params[index] = NULL;
+
+ hmm_free(frame->data);
}
-static const struct videobuf_queue_ops videobuf_qops = {
- .buf_setup = atomisp_buf_setup,
- .buf_prepare = atomisp_buf_prepare,
- .buf_queue = atomisp_buf_queue,
- .buf_release = atomisp_buf_release,
+static const struct vb2_ops atomisp_vb2_ops = {
+ .queue_setup = atomisp_queue_setup,
+ .buf_init = atomisp_buf_init,
+ .buf_cleanup = atomisp_buf_cleanup,
+ .buf_queue = atomisp_buf_queue,
+ .start_streaming = atomisp_start_streaming,
+ .stop_streaming = atomisp_stop_streaming,
};
static int atomisp_init_pipe(struct atomisp_video_pipe *pipe)
{
+ int ret;
+
/* init locks */
spin_lock_init(&pipe->irq_lock);
+ mutex_init(&pipe->vb_queue_mutex);
+
+ /* Init videobuf2 queue structure */
+ pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
+ pipe->vb_queue.ops = &atomisp_vb2_ops;
+ pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&pipe->vb_queue);
+ if (ret)
+ return ret;
- videobuf_queue_vmalloc_init(&pipe->capq, &videobuf_qops, NULL,
- &pipe->irq_lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct atomisp_buffer), pipe,
- NULL); /* ext_lock: NULL */
+ pipe->vdev.queue = &pipe->vb_queue;
+ pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
@@ -721,13 +808,6 @@ static int atomisp_open(struct file *file)
goto error;
}
- /* Init ISP */
- if (atomisp_css_init(isp)) {
- ret = -EINVAL;
- /* Need to clean up CSS init if it fails. */
- goto css_error;
- }
-
atomisp_dev_init_struct(isp);
ret = v4l2_subdev_call(isp->flash, core, s_power, 1);
@@ -752,7 +832,6 @@ done:
return 0;
css_error:
- atomisp_css_uninit(isp);
pm_runtime_put(vdev->v4l2_dev->dev);
error:
mutex_unlock(&isp->mutex);
@@ -766,45 +845,26 @@ static int atomisp_release(struct file *file)
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
- struct v4l2_requestbuffers req;
struct v4l2_subdev_fh fh;
struct v4l2_rect clear_compose = {0};
unsigned long flags;
- int ret = 0;
+ int ret;
v4l2_fh_init(&fh.vfh, vdev);
- req.count = 0;
- if (!isp)
- return -EBADF;
-
- mutex_lock(&isp->mutex);
-
dev_dbg(isp->dev, "release device %s\n", vdev->name);
asd->subdev.devnode = vdev;
- pipe->users--;
-
- if (pipe->capq.streaming)
- dev_warn(isp->dev,
- "%s: ISP still streaming while closing!",
- __func__);
+ /* Note file must not be used after this! */
+ vb2_fop_release(file);
- if (pipe->capq.streaming &&
- atomisp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- dev_err(isp->dev, "atomisp_streamoff failed on release, driver bug");
- goto done;
- }
+ mutex_lock(&isp->mutex);
+ pipe->users--;
if (pipe->users)
goto done;
- if (atomisp_reqbufs(file, NULL, &req)) {
- dev_err(isp->dev, "atomisp_reqbufs failed on release, driver bug");
- goto done;
- }
-
/*
* A little trick here:
* file injection input resolution is recorded in the sink pad,
@@ -840,7 +900,6 @@ static int atomisp_release(struct file *file)
goto done;
atomisp_destroy_pipes_stream_force(asd);
- atomisp_css_uninit(isp);
if (defer_fw_load) {
ia_css_unload_firmware();
@@ -862,260 +921,15 @@ done:
V4L2_SEL_TGT_COMPOSE, 0,
&clear_compose);
mutex_unlock(&isp->mutex);
-
- return v4l2_fh_release(file);
-}
-
-/*
- * Memory help functions for image frame and private parameters
- */
-static int do_isp_mm_remap(struct atomisp_device *isp,
- struct vm_area_struct *vma,
- ia_css_ptr isp_virt, u32 host_virt, u32 pgnr)
-{
- u32 pfn;
-
- while (pgnr) {
- pfn = hmm_virt_to_phys(isp_virt) >> PAGE_SHIFT;
- if (remap_pfn_range(vma, host_virt, pfn,
- PAGE_SIZE, PAGE_SHARED)) {
- dev_err(isp->dev, "remap_pfn_range err.\n");
- return -EAGAIN;
- }
-
- isp_virt += PAGE_SIZE;
- host_virt += PAGE_SIZE;
- pgnr--;
- }
-
- return 0;
-}
-
-static int frame_mmap(struct atomisp_device *isp,
- const struct ia_css_frame *frame, struct vm_area_struct *vma)
-{
- ia_css_ptr isp_virt;
- u32 host_virt;
- u32 pgnr;
-
- if (!frame) {
- dev_err(isp->dev, "%s: NULL frame pointer.\n", __func__);
- return -EINVAL;
- }
-
- host_virt = vma->vm_start;
- isp_virt = frame->data;
- pgnr = DIV_ROUND_UP(frame->data_bytes, PAGE_SIZE);
-
- if (do_isp_mm_remap(isp, vma, isp_virt, host_virt, pgnr))
- return -EAGAIN;
-
return 0;
}
-int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q,
- struct vm_area_struct *vma)
-{
- u32 offset = vma->vm_pgoff << PAGE_SHIFT;
- int ret = -EINVAL, i;
- struct atomisp_device *isp =
- ((struct atomisp_video_pipe *)(q->priv_data))->isp;
- struct videobuf_vmalloc_memory *vm_mem;
- struct videobuf_mapping *map;
-
- MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) {
- dev_err(isp->dev, "map appl bug: PROT_WRITE and MAP_SHARED are required\n");
- return -EINVAL;
- }
-
- mutex_lock(&q->vb_lock);
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- struct videobuf_buffer *buf = q->bufs[i];
-
- if (!buf)
- continue;
-
- map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
- if (!map) {
- mutex_unlock(&q->vb_lock);
- return -ENOMEM;
- }
-
- buf->map = map;
- map->q = q;
-
- buf->baddr = vma->vm_start;
-
- if (buf && buf->memory == V4L2_MEMORY_MMAP &&
- buf->boff == offset) {
- vm_mem = buf->priv;
- ret = frame_mmap(isp, vm_mem->vaddr, vma);
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
- break;
- }
- }
- mutex_unlock(&q->vb_lock);
-
- return ret;
-}
-
-/* The input frame contains left and right padding that need to be removed.
- * There is always ISP_LEFT_PAD padding on the left side.
- * There is also padding on the right (padded_width - width).
- */
-static int remove_pad_from_frame(struct atomisp_device *isp,
- struct ia_css_frame *in_frame, __u32 width, __u32 height)
-{
- unsigned int i;
- unsigned short *buffer;
- int ret = 0;
- ia_css_ptr load = in_frame->data;
- ia_css_ptr store = load;
-
- buffer = kmalloc_array(width, sizeof(load), GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- load += ISP_LEFT_PAD;
- for (i = 0; i < height; i++) {
- ret = hmm_load(load, buffer, width * sizeof(load));
- if (ret < 0)
- goto remove_pad_error;
-
- ret = hmm_store(store, buffer, width * sizeof(store));
- if (ret < 0)
- goto remove_pad_error;
-
- load += in_frame->info.padded_width;
- store += width;
- }
-
-remove_pad_error:
- kfree(buffer);
- return ret;
-}
-
-static int atomisp_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_device *isp = video_get_drvdata(vdev);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- struct atomisp_sub_device *asd = pipe->asd;
- struct ia_css_frame *raw_virt_addr;
- u32 start = vma->vm_start;
- u32 end = vma->vm_end;
- u32 size = end - start;
- u32 origin_size, new_size;
- int ret;
-
- if (!asd) {
- dev_err(isp->dev, "%s(): asd is NULL, device is %s\n",
- __func__, vdev->name);
- return -EINVAL;
- }
-
- if (!(vma->vm_flags & (VM_WRITE | VM_READ)))
- return -EACCES;
-
- mutex_lock(&isp->mutex);
-
- if (!(vma->vm_flags & VM_SHARED)) {
- /* Map private buffer.
- * Set VM_SHARED to the flags since we need
- * to map the buffer page by page.
- * Without VM_SHARED, remap_pfn_range() treats
- * this kind of mapping as invalid.
- */
- vma->vm_flags |= VM_SHARED;
- ret = hmm_mmap(vma, vma->vm_pgoff << PAGE_SHIFT);
- mutex_unlock(&isp->mutex);
- return ret;
- }
-
- /* mmap for ISP offline raw data */
- if (atomisp_subdev_source_pad(vdev)
- == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
- vma->vm_pgoff == (ISP_PARAM_MMAP_OFFSET >> PAGE_SHIFT)) {
- new_size = pipe->pix.width * pipe->pix.height * 2;
- if (asd->params.online_process != 0) {
- ret = -EINVAL;
- goto error;
- }
- raw_virt_addr = asd->raw_output_frame;
- if (!raw_virt_addr) {
- dev_err(isp->dev, "Failed to request RAW frame\n");
- ret = -EINVAL;
- goto error;
- }
-
- ret = remove_pad_from_frame(isp, raw_virt_addr,
- pipe->pix.width, pipe->pix.height);
- if (ret < 0) {
- dev_err(isp->dev, "remove pad failed.\n");
- goto error;
- }
- origin_size = raw_virt_addr->data_bytes;
- raw_virt_addr->data_bytes = new_size;
-
- if (size != PAGE_ALIGN(new_size)) {
- dev_err(isp->dev, "incorrect size for mmap ISP Raw Frame\n");
- ret = -EINVAL;
- goto error;
- }
-
- if (frame_mmap(isp, raw_virt_addr, vma)) {
- dev_err(isp->dev, "frame_mmap failed.\n");
- raw_virt_addr->data_bytes = origin_size;
- ret = -EAGAIN;
- goto error;
- }
- raw_virt_addr->data_bytes = origin_size;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
- mutex_unlock(&isp->mutex);
- return 0;
- }
-
- /*
- * mmap for normal frames
- */
- if (size != pipe->pix.sizeimage) {
- dev_err(isp->dev, "incorrect size for mmap ISP frames\n");
- ret = -EINVAL;
- goto error;
- }
- mutex_unlock(&isp->mutex);
-
- return atomisp_videobuf_mmap_mapper(&pipe->capq, vma);
-
-error:
- mutex_unlock(&isp->mutex);
-
- return ret;
-}
-
-static __poll_t atomisp_poll(struct file *file,
- struct poll_table_struct *pt)
-{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_device *isp = video_get_drvdata(vdev);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
-
- mutex_lock(&isp->mutex);
- if (pipe->capq.streaming != 1) {
- mutex_unlock(&isp->mutex);
- return EPOLLERR;
- }
- mutex_unlock(&isp->mutex);
-
- return videobuf_poll_stream(file, &pipe->capq, pt);
-}
-
const struct v4l2_file_operations atomisp_fops = {
.owner = THIS_MODULE,
.open = atomisp_open,
.release = atomisp_release,
- .mmap = atomisp_mmap,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
/*
@@ -1124,5 +938,4 @@ const struct v4l2_file_operations atomisp_fops = {
.compat_ioctl32 = atomisp_compat_ioctl32,
*/
#endif
- .poll = atomisp_poll,
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h
index 3f1e442ba782..10e43126b693 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h
@@ -22,12 +22,6 @@
#define __ATOMISP_FOPS_H__
#include "atomisp_subdev.h"
-int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
- struct atomisp_video_pipe *pipe,
- enum atomisp_input_stream_id stream_id,
- enum ia_css_buffer_type css_buf_type,
- enum ia_css_pipe_id css_pipe_id);
-
unsigned int atomisp_dev_users(struct atomisp_device *isp);
unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd);
@@ -35,13 +29,6 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd);
* Memory help functions for image frame and private parameters
*/
-int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q,
- struct vm_area_struct *vma);
-
-int atomisp_qbuf_to_css(struct atomisp_device *isp,
- struct atomisp_video_pipe *pipe,
- struct videobuf_buffer *vb);
-
int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd);
extern const struct v4l2_file_operations atomisp_fops;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h
index d9d158cdf09e..653e6d74a966 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_internal.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h
@@ -195,7 +195,6 @@ struct atomisp_regs {
};
struct atomisp_sw_contex {
- int power_state;
int running_freq;
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index 0ddb0ed42dd9..cb01ba65c88f 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -23,7 +23,6 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/videobuf-vmalloc.h>
#include "atomisp_cmd.h"
#include "atomisp_common.h"
@@ -542,6 +541,11 @@ int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool settings_change)
if (pipe->isp->isp_fatal_error)
return -EIO;
+ if (settings_change && vb2_is_busy(&pipe->vb_queue)) {
+ dev_err(pipe->isp->dev, "Set fmt/input IOCTL while streaming\n");
+ return -EBUSY;
+ }
+
switch (pipe->asd->streaming) {
case ATOMISP_DEVICE_STREAMING_DISABLED:
break;
@@ -632,10 +636,10 @@ static int atomisp_enum_input(struct file *file, void *fh,
static unsigned int
atomisp_subdev_streaming_count(struct atomisp_sub_device *asd)
{
- return asd->video_out_preview.capq.streaming
- + asd->video_out_capture.capq.streaming
- + asd->video_out_video_capture.capq.streaming
- + asd->video_out_vf.capq.streaming;
+ return asd->video_out_preview.vb_queue.start_streaming_called
+ + asd->video_out_capture.vb_queue.start_streaming_called
+ + asd->video_out_video_capture.vb_queue.start_streaming_called
+ + asd->video_out_vf.vb_queue.start_streaming_called;
}
unsigned int atomisp_streaming_count(struct atomisp_device *isp)
@@ -661,6 +665,14 @@ static int atomisp_g_input(struct file *file, void *fh, unsigned int *input)
return 0;
}
+static int atomisp_s_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ return atomisp_set_fmt(vdev, f);
+}
+
/*
* set input are used to set current primary/secondary camera
*/
@@ -866,29 +878,8 @@ static int atomisp_adjust_fmt(struct v4l2_format *f)
u32 padded_width;
format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
-
- padded_width = f->fmt.pix.width + pad_w;
-
- if (format_bridge->planar) {
- f->fmt.pix.bytesperline = padded_width;
- f->fmt.pix.sizeimage = PAGE_ALIGN(f->fmt.pix.height *
- DIV_ROUND_UP(format_bridge->depth *
- padded_width, 8));
- } else {
- f->fmt.pix.bytesperline = DIV_ROUND_UP(format_bridge->depth *
- padded_width, 8);
- f->fmt.pix.sizeimage = PAGE_ALIGN(f->fmt.pix.height * f->fmt.pix.bytesperline);
- }
-
- if (f->fmt.pix.field == V4L2_FIELD_ANY)
- f->fmt.pix.field = V4L2_FIELD_NONE;
-
- format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
- if (!format_bridge)
- return -EINVAL;
-
/* Currently, raw formats are broken!!! */
- if (format_bridge->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
+ if (!format_bridge || format_bridge->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
@@ -931,6 +922,7 @@ static int atomisp_try_fmt_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
struct video_device *vdev = video_devdata(file);
+ u32 pixfmt = f->fmt.pix.pixelformat;
int ret;
/*
@@ -944,6 +936,12 @@ static int atomisp_try_fmt_cap(struct file *file, void *fh,
if (ret)
return ret;
+ /*
+ * atomisp_try_fmt() replaces pixelformat with the sensors native
+ * format, restore the actual format requested by userspace.
+ */
+ f->fmt.pix.pixelformat = pixfmt;
+
return atomisp_adjust_fmt(f);
}
@@ -961,44 +959,13 @@ static int atomisp_g_fmt_cap(struct file *file, void *fh,
if (f->fmt.pix.sizeimage)
return 0;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
f->fmt.pix.width = 10000;
f->fmt.pix.height = 10000;
return atomisp_try_fmt_cap(file, fh, f);
}
-/*
- * Free videobuffer buffer priv data
- */
-void atomisp_videobuf_free_buf(struct videobuf_buffer *vb)
-{
- struct videobuf_vmalloc_memory *vm_mem;
-
- if (!vb)
- return;
-
- vm_mem = vb->priv;
- if (vm_mem && vm_mem->vaddr) {
- ia_css_frame_free(vm_mem->vaddr);
- vm_mem->vaddr = NULL;
- }
-}
-
-/*
- * this function is used to free video buffer queue
- */
-static void atomisp_videobuf_free_queue(struct videobuf_queue *q)
-{
- int i;
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- atomisp_videobuf_free_buf(q->bufs[i]);
- kfree(q->bufs[i]);
- q->bufs[i] = NULL;
- }
-}
-
int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd,
uint16_t stream_id)
{
@@ -1100,178 +1067,13 @@ error:
return -ENOMEM;
}
-/*
- * Initiate Memory Mapping or User Pointer I/O
- */
-int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
-{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- struct atomisp_sub_device *asd = pipe->asd;
- struct ia_css_frame_info frame_info;
- struct ia_css_frame *frame;
- struct videobuf_vmalloc_memory *vm_mem;
- u16 source_pad = atomisp_subdev_source_pad(vdev);
- int ret = 0, i = 0;
-
- if (req->count == 0) {
- mutex_lock(&pipe->capq.vb_lock);
- if (!list_empty(&pipe->capq.stream))
- videobuf_queue_cancel(&pipe->capq);
-
- atomisp_videobuf_free_queue(&pipe->capq);
- mutex_unlock(&pipe->capq.vb_lock);
- /* clear request config id */
- memset(pipe->frame_request_config_id, 0,
- VIDEO_MAX_FRAME * sizeof(unsigned int));
- memset(pipe->frame_params, 0,
- VIDEO_MAX_FRAME *
- sizeof(struct atomisp_css_params_with_list *));
- return 0;
- }
-
- ret = videobuf_reqbufs(&pipe->capq, req);
- if (ret)
- return ret;
-
- atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL);
-
- /*
- * for user pointer type, buffers are not really allocated here,
- * buffers are setup in QBUF operation through v4l2_buffer structure
- */
- if (req->memory == V4L2_MEMORY_USERPTR)
- return 0;
-
- ret = atomisp_get_css_frame_info(asd, source_pad, &frame_info);
- if (ret)
- return ret;
-
- /*
- * Allocate the real frame here for selected node using our
- * memory management function
- */
- for (i = 0; i < req->count; i++) {
- if (ia_css_frame_allocate_from_info(&frame, &frame_info))
- goto error;
- vm_mem = pipe->capq.bufs[i]->priv;
- vm_mem->vaddr = frame;
- }
-
- return ret;
-
-error:
- while (i--) {
- vm_mem = pipe->capq.bufs[i]->priv;
- ia_css_frame_free(vm_mem->vaddr);
- }
-
- if (asd->vf_frame)
- ia_css_frame_free(asd->vf_frame);
-
- return -ENOMEM;
-}
-
-/* application query the status of a buffer */
-static int atomisp_querybuf(struct file *file, void *fh,
- struct v4l2_buffer *buf)
-{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
-
- return videobuf_querybuf(&pipe->capq, buf);
-}
-
-/*
- * Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or
- * filled (output) buffer in the drivers incoming queue.
- */
-static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
{
- static const int NOFLUSH_FLAGS = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE |
- V4L2_BUF_FLAG_NO_CACHE_CLEAN;
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- struct atomisp_sub_device *asd = pipe->asd;
- struct videobuf_buffer *vb;
- struct videobuf_vmalloc_memory *vm_mem;
- struct ia_css_frame_info frame_info;
- struct ia_css_frame *handle = NULL;
- u32 length;
- u32 pgnr;
- int ret;
-
- ret = atomisp_pipe_check(pipe, false);
- if (ret)
- return ret;
-
- if (!buf || buf->index >= VIDEO_MAX_FRAME ||
- !pipe->capq.bufs[buf->index]) {
- dev_err(isp->dev, "Invalid index for qbuf.\n");
- return -EINVAL;
- }
-
- /*
- * For userptr type frame, we convert user space address to physic
- * address and reprograme out page table properly
- */
- if (buf->memory == V4L2_MEMORY_USERPTR) {
- if (offset_in_page(buf->m.userptr)) {
- dev_err(isp->dev, "Error userptr is not page aligned.\n");
- return -EINVAL;
- }
-
- vb = pipe->capq.bufs[buf->index];
- vm_mem = vb->priv;
- if (!vm_mem)
- return -EINVAL;
-
- length = vb->bsize;
- pgnr = (length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-
- if (vb->baddr == buf->m.userptr && vm_mem->vaddr)
- goto done;
-
- if (atomisp_get_css_frame_info(asd,
- atomisp_subdev_source_pad(vdev), &frame_info))
- return -EIO;
-
- ret = ia_css_frame_map(&handle, &frame_info,
- (void __user *)buf->m.userptr,
- pgnr);
- if (ret) {
- dev_err(isp->dev, "Failed to map user buffer\n");
- return ret;
- }
-
- if (vm_mem->vaddr) {
- mutex_lock(&pipe->capq.vb_lock);
- ia_css_frame_free(vm_mem->vaddr);
- vm_mem->vaddr = NULL;
- vb->state = VIDEOBUF_NEEDS_INIT;
- mutex_unlock(&pipe->capq.vb_lock);
- }
-
- vm_mem->vaddr = handle;
-
- buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
- } else if (buf->memory == V4L2_MEMORY_MMAP) {
- buf->flags |= V4L2_BUF_FLAG_MAPPED;
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
-
- /*
- * For mmap, frames were allocated at request buffers
- */
- }
-
-done:
- if (!((buf->flags & NOFLUSH_FLAGS) == NOFLUSH_FLAGS))
- wbinvd();
+ /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */
if (!atomisp_is_vf_pipe(pipe) &&
(buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) {
/* this buffer will have a per-frame parameter */
@@ -1284,90 +1086,27 @@ done:
pipe->frame_request_config_id[buf->index] = 0;
}
- pipe->frame_params[buf->index] = NULL;
-
- mutex_unlock(&isp->mutex);
- ret = videobuf_qbuf(&pipe->capq, buf);
- mutex_lock(&isp->mutex);
- if (ret)
- return ret;
-
- /* TODO: do this better, not best way to queue to css */
- if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
- if (!list_empty(&pipe->buffers_waiting_for_param)) {
- atomisp_handle_parameter_and_buffer(pipe);
- } else {
- atomisp_qbuffers_to_css(asd);
- }
- }
-
- /*
- * Workaround: Due to the design of HALv3,
- * sometimes in ZSL or SDV mode HAL needs to
- * capture multiple images within one streaming cycle.
- * But the capture number cannot be determined by HAL.
- * So HAL only sets the capture number to be 1 and queue multiple
- * buffers. Atomisp driver needs to check this case and re-trigger
- * CSS to do capture when new buffer is queued.
- */
- if (asd->continuous_mode->val &&
- atomisp_subdev_source_pad(vdev)
- == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
- pipe->capq.streaming &&
- !asd->enable_raw_buffer_lock->val &&
- asd->params.offline_parm.num_captures == 1) {
- asd->pending_capture_request++;
- dev_dbg(isp->dev, "Add one pending capture request.\n");
- }
-
- dev_dbg(isp->dev, "qbuf buffer %d (%s) for asd%d\n", buf->index,
- vdev->name, asd->index);
-
- return 0;
+ return vb2_ioctl_qbuf(file, fh, buf);
}
-static int __get_frame_exp_id(struct atomisp_video_pipe *pipe,
- struct v4l2_buffer *buf)
-{
- struct videobuf_vmalloc_memory *vm_mem;
- struct ia_css_frame *handle;
- int i;
-
- for (i = 0; pipe->capq.bufs[i]; i++) {
- vm_mem = pipe->capq.bufs[i]->priv;
- handle = vm_mem->vaddr;
- if (buf->index == pipe->capq.bufs[i]->i && handle)
- return handle->exp_id;
- }
- return -EINVAL;
-}
-
-/*
- * Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
- * displayed (output buffer)from the driver's outgoing queue
- */
-static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
struct atomisp_device *isp = video_get_drvdata(vdev);
+ struct ia_css_frame *frame;
+ struct vb2_buffer *vb;
int ret;
- ret = atomisp_pipe_check(pipe, false);
+ ret = vb2_ioctl_dqbuf(file, fh, buf);
if (ret)
return ret;
- mutex_unlock(&isp->mutex);
- ret = videobuf_dqbuf(&pipe->capq, buf, file->f_flags & O_NONBLOCK);
- mutex_lock(&isp->mutex);
- if (ret) {
- if (ret != -EAGAIN)
- dev_dbg(isp->dev, "<%s: %d\n", __func__, ret);
- return ret;
- }
+ vb = pipe->vb_queue.bufs[buf->index];
+ frame = vb_to_frame(vb);
- buf->bytesused = pipe->pix.sizeimage;
+ /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */
buf->reserved = asd->frame_status[buf->index];
/*
@@ -1378,7 +1117,7 @@ static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
*/
buf->reserved &= 0x0000ffff;
if (!(buf->flags & V4L2_BUF_FLAG_ERROR))
- buf->reserved |= __get_frame_exp_id(pipe, buf) << 16;
+ buf->reserved |= frame->exp_id;
buf->reserved2 = pipe->frame_config_id[buf->index];
dev_dbg(isp->dev,
@@ -1506,36 +1245,26 @@ static void atomisp_dma_burst_len_cfg(struct atomisp_sub_device *asd)
atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00);
}
-/*
- * This ioctl start the capture during streaming I/O.
- */
-static int atomisp_streamon(struct file *file, void *fh,
- enum v4l2_buf_type type)
+int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
+ struct atomisp_video_pipe *pipe = vq_to_pipe(vq);
struct atomisp_sub_device *asd = pipe->asd;
- struct atomisp_device *isp = video_get_drvdata(vdev);
+ struct video_device *vdev = &pipe->vdev;
+ struct atomisp_device *isp = asd->isp;
struct pci_dev *pdev = to_pci_dev(isp->dev);
enum ia_css_pipe_id css_pipe_id;
unsigned int sensor_start_stream;
unsigned long irqflags;
int ret;
+ mutex_lock(&isp->mutex);
+
dev_dbg(isp->dev, "Start stream on pad %d for asd%d\n",
atomisp_subdev_source_pad(vdev), asd->index);
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_dbg(isp->dev, "unsupported v4l2 buf type\n");
- return -EINVAL;
- }
-
ret = atomisp_pipe_check(pipe, false);
if (ret)
- return ret;
-
- if (pipe->capq.streaming)
- return 0;
+ goto out_unlock;
/* Input system HW workaround */
atomisp_dma_burst_len_cfg(asd);
@@ -1546,18 +1275,6 @@ static int atomisp_streamon(struct file *file, void *fh,
*/
sensor_start_stream = atomisp_sensor_start_stream(asd);
- spin_lock_irqsave(&pipe->irq_lock, irqflags);
- if (list_empty(&pipe->capq.stream)) {
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
- dev_dbg(isp->dev, "no buffer in the queue\n");
- return -EINVAL;
- }
- spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
-
- ret = videobuf_streamon(&pipe->capq);
- if (ret)
- return ret;
-
/* Reset pending capture request count. */
asd->pending_capture_request = 0;
@@ -1578,8 +1295,10 @@ static int atomisp_streamon(struct file *file, void *fh,
mutex_unlock(&isp->mutex);
ret = wait_for_completion_interruptible(&asd->init_done);
mutex_lock(&isp->mutex);
- if (ret != 0)
- return -ERESTARTSYS;
+ if (ret) {
+ ret = -ERESTARTSYS;
+ goto out_unlock;
+ }
}
/* handle per_frame_setting parameter and buffers */
@@ -1601,12 +1320,15 @@ static int atomisp_streamon(struct file *file, void *fh,
asd->params.offline_parm.num_captures,
asd->params.offline_parm.skip_frames,
asd->params.offline_parm.offset);
- if (ret)
- return -EINVAL;
+ if (ret) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
}
}
atomisp_qbuffers_to_css(asd);
- return 0;
+ ret = 0;
+ goto out_unlock;
}
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
@@ -1631,8 +1353,10 @@ static int atomisp_streamon(struct file *file, void *fh,
asd->params.dvs_6axis = NULL;
ret = atomisp_css_start(asd, css_pipe_id, false);
- if (ret)
- return ret;
+ if (ret) {
+ atomisp_flush_video_pipe(pipe, true);
+ goto out_unlock;
+ }
spin_lock_irqsave(&isp->lock, irqflags);
asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED;
@@ -1652,8 +1376,10 @@ static int atomisp_streamon(struct file *file, void *fh,
atomisp_qbuffers_to_css(asd);
/* Only start sensor when the last streaming instance started */
- if (atomisp_subdev_streaming_count(asd) < sensor_start_stream)
- return 0;
+ if (atomisp_subdev_streaming_count(asd) < sensor_start_stream) {
+ ret = 0;
+ goto out_unlock;
+ }
start_sensor:
if (isp->flash) {
@@ -1684,7 +1410,7 @@ start_sensor:
ret = atomisp_stream_on_master_slave_sensor(isp, false);
if (ret) {
dev_err(isp->dev, "master slave sensor stream on failed!\n");
- return ret;
+ goto out_unlock;
}
goto start_delay_wq;
} else if (asd->depth_mode->val && (atomisp_streaming_count(isp) <
@@ -1706,7 +1432,8 @@ start_sensor:
spin_lock_irqsave(&isp->lock, irqflags);
asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
spin_unlock_irqrestore(&isp->lock, irqflags);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_unlock;
}
start_delay_wq:
@@ -1722,35 +1449,44 @@ start_delay_wq:
asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED;
}
- return 0;
+out_unlock:
+ mutex_unlock(&isp->mutex);
+ return ret;
}
-int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+void atomisp_stop_streaming(struct vb2_queue *vq)
{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_device *isp = video_get_drvdata(vdev);
- struct pci_dev *pdev = to_pci_dev(isp->dev);
- struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
+ struct atomisp_video_pipe *pipe = vq_to_pipe(vq);
struct atomisp_sub_device *asd = pipe->asd;
- struct atomisp_video_pipe *capture_pipe = NULL;
- struct atomisp_video_pipe *vf_pipe = NULL;
- struct atomisp_video_pipe *preview_pipe = NULL;
- struct atomisp_video_pipe *video_pipe = NULL;
- struct videobuf_buffer *vb, *_vb;
+ struct video_device *vdev = &pipe->vdev;
+ struct atomisp_device *isp = asd->isp;
+ struct pci_dev *pdev = to_pci_dev(isp->dev);
+ bool recreate_streams[MAX_STREAM_NUM] = {0};
enum ia_css_pipe_id css_pipe_id;
- int ret;
- unsigned long flags;
bool first_streamoff = false;
+ unsigned long flags;
+ int i, ret;
+
+ mutex_lock(&isp->mutex);
dev_dbg(isp->dev, "Stop stream on pad %d for asd%d\n",
atomisp_subdev_source_pad(vdev), asd->index);
- lockdep_assert_held(&isp->mutex);
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_dbg(isp->dev, "unsupported v4l2 buf type\n");
- return -EINVAL;
- }
+ /*
+ * There is no guarantee that the buffers queued to / owned by the ISP
+ * will properly be returned to the queue when stopping. Set a flag to
+ * avoid new buffers getting queued and then wait for all the current
+ * buffers to finish.
+ */
+ pipe->stopping = true;
+ mutex_unlock(&isp->mutex);
+ /* wait max 1 second */
+ ret = wait_event_timeout(pipe->vb_queue.done_wq,
+ atomisp_buffers_in_css(pipe) == 0, HZ);
+ mutex_lock(&isp->mutex);
+ pipe->stopping = false;
+ if (ret == 0)
+ dev_warn(isp->dev, "Warning timeout waiting for CSS to return buffers\n");
/*
* do only videobuf_streamoff for capture & vf pipes in
@@ -1766,36 +1502,10 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
0, 0, 0);
atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, false);
}
- /*
- * Currently there is no way to flush buffers queued to css.
- * When doing videobuf_streamoff, active buffers will be
- * marked as VIDEOBUF_NEEDS_INIT. HAL will be able to use
- * these buffers again, and these buffers might be queued to
- * css more than once! Warn here, if HAL has not dequeued all
- * buffers back before calling streamoff.
- */
- if (pipe->buffers_in_css != 0) {
- WARN(1, "%s: buffers of vdev %s still in CSS!\n",
- __func__, pipe->vdev.name);
-
- /*
- * Buffers remained in css maybe dequeued out in the
- * next stream on, while this will causes serious
- * issues as buffers already get invalid after
- * previous stream off.
- *
- * No way to flush buffers but to reset the whole css
- */
- dev_warn(isp->dev, "Reset CSS to clean up css buffers.\n");
- atomisp_css_flush(isp);
- }
- return videobuf_streamoff(&pipe->capq);
+ goto out_unlock;
}
- if (!pipe->capq.streaming)
- return 0;
-
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED)
first_streamoff = true;
@@ -1806,12 +1516,8 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING;
spin_unlock_irqrestore(&isp->lock, flags);
- if (!first_streamoff) {
- ret = videobuf_streamoff(&pipe->capq);
- if (ret)
- return ret;
+ if (!first_streamoff)
goto stopsensor;
- }
atomisp_clear_css_buffer_counters(asd);
atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false);
@@ -1824,48 +1530,12 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
css_pipe_id = atomisp_get_css_pipe_id(asd);
atomisp_css_stop(asd, css_pipe_id, false);
- /* cancel work queue*/
- if (asd->video_out_capture.users) {
- capture_pipe = &asd->video_out_capture;
- wake_up_interruptible(&capture_pipe->capq.wait);
- }
- if (asd->video_out_vf.users) {
- vf_pipe = &asd->video_out_vf;
- wake_up_interruptible(&vf_pipe->capq.wait);
- }
- if (asd->video_out_preview.users) {
- preview_pipe = &asd->video_out_preview;
- wake_up_interruptible(&preview_pipe->capq.wait);
- }
- if (asd->video_out_video_capture.users) {
- video_pipe = &asd->video_out_video_capture;
- wake_up_interruptible(&video_pipe->capq.wait);
- }
- ret = videobuf_streamoff(&pipe->capq);
- if (ret)
- return ret;
-
- /* cleanup css here */
- /* no need for this, as ISP will be reset anyway */
- /*atomisp_flush_bufs_in_css(isp);*/
-
- spin_lock_irqsave(&pipe->irq_lock, flags);
- list_for_each_entry_safe(vb, _vb, &pipe->activeq, queue) {
- vb->state = VIDEOBUF_PREPARED;
- list_del(&vb->queue);
- }
- list_for_each_entry_safe(vb, _vb, &pipe->buffers_waiting_for_param, queue) {
- vb->state = VIDEOBUF_PREPARED;
- list_del(&vb->queue);
- pipe->frame_request_config_id[vb->i] = 0;
- }
- spin_unlock_irqrestore(&pipe->irq_lock, flags);
+ atomisp_flush_video_pipe(pipe, true);
atomisp_subdev_cleanup_pending_events(asd);
stopsensor:
- if (atomisp_subdev_streaming_count(asd) + 1
- != atomisp_sensor_start_stream(asd))
- return 0;
+ if (atomisp_subdev_streaming_count(asd) != atomisp_sensor_start_stream(asd))
+ goto out_unlock;
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
video, s_stream, 0);
@@ -1878,7 +1548,7 @@ stopsensor:
/* if other streams are running, isp should not be powered off */
if (atomisp_streaming_count(isp)) {
atomisp_css_flush(isp);
- return 0;
+ goto out_unlock;
}
/* Disable the CSI interface on ANN B0/K0 */
@@ -1894,50 +1564,45 @@ stopsensor:
* ISP work around, need to reset isp
* Is it correct time to reset ISP when first node does streamoff?
*/
- if (isp->sw_contex.power_state == ATOM_ISP_POWER_UP) {
- unsigned int i;
- bool recreate_streams[MAX_STREAM_NUM] = {0};
-
- if (isp->isp_timeout)
- dev_err(isp->dev, "%s: Resetting with WA activated",
- __func__);
- /*
- * It is possible that the other asd stream is in the stage
- * that v4l2_setfmt is just get called on it, which will
- * create css stream on that stream. But at this point, there
- * is no way to destroy the css stream created on that stream.
- *
- * So force stream destroy here.
- */
- for (i = 0; i < isp->num_of_streams; i++) {
- if (isp->asd[i].stream_prepared) {
- atomisp_destroy_pipes_stream_force(&isp->
- asd[i]);
- recreate_streams[i] = true;
- }
+ if (isp->isp_timeout)
+ dev_err(isp->dev, "%s: Resetting with WA activated",
+ __func__);
+ /*
+ * It is possible that the other asd stream is in the stage
+ * that v4l2_setfmt is just get called on it, which will
+ * create css stream on that stream. But at this point, there
+ * is no way to destroy the css stream created on that stream.
+ *
+ * So force stream destroy here.
+ */
+ for (i = 0; i < isp->num_of_streams; i++) {
+ if (isp->asd[i].stream_prepared) {
+ atomisp_destroy_pipes_stream_force(&isp->asd[i]);
+ recreate_streams[i] = true;
}
+ }
- /* disable PUNIT/ISP acknowlede/handshake - SRSE=3 */
- pci_write_config_dword(pdev, PCI_I_CONTROL,
- isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK);
- dev_err(isp->dev, "atomisp_reset");
- atomisp_reset(isp);
- for (i = 0; i < isp->num_of_streams; i++) {
- if (recreate_streams[i]) {
- int ret2;
-
- ret2 = atomisp_create_pipes_stream(&isp->asd[i]);
- if (ret2) {
- dev_err(isp->dev, "%s error re-creating streams: %d\n",
- __func__, ret2);
- if (!ret)
- ret = ret2;
- }
+ /* disable PUNIT/ISP acknowlede/handshake - SRSE=3 */
+ pci_write_config_dword(pdev, PCI_I_CONTROL,
+ isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK);
+ dev_err(isp->dev, "atomisp_reset");
+ atomisp_reset(isp);
+ for (i = 0; i < isp->num_of_streams; i++) {
+ if (recreate_streams[i]) {
+ int ret2;
+
+ ret2 = atomisp_create_pipes_stream(&isp->asd[i]);
+ if (ret2) {
+ dev_err(isp->dev, "%s error re-creating streams: %d\n",
+ __func__, ret2);
+ if (!ret)
+ ret = ret2;
}
}
- isp->isp_timeout = false;
}
- return ret;
+ isp->isp_timeout = false;
+out_unlock:
+ mutex_unlock(&isp->mutex);
}
/*
@@ -2725,13 +2390,13 @@ const struct v4l2_ioctl_ops atomisp_ioctl_ops = {
.vidioc_enum_fmt_vid_cap = atomisp_enum_fmt_cap,
.vidioc_try_fmt_vid_cap = atomisp_try_fmt_cap,
.vidioc_g_fmt_vid_cap = atomisp_g_fmt_cap,
- .vidioc_s_fmt_vid_cap = atomisp_set_fmt,
- .vidioc_reqbufs = atomisp_reqbufs,
- .vidioc_querybuf = atomisp_querybuf,
- .vidioc_qbuf = atomisp_qbuf,
- .vidioc_dqbuf = atomisp_dqbuf,
- .vidioc_streamon = atomisp_streamon,
- .vidioc_streamoff = atomisp_streamoff,
+ .vidioc_s_fmt_vid_cap = atomisp_s_fmt_cap,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = atomisp_qbuf_wrapper,
+ .vidioc_dqbuf = atomisp_dqbuf_wrapper,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_default = atomisp_vidioc_default,
.vidioc_s_parm = atomisp_s_parm,
.vidioc_g_parm = atomisp_g_parm,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h
index c660f631d371..59e071f035f9 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h
@@ -39,14 +39,12 @@ int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool streaming_ok);
int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd,
uint16_t stream_id);
-int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type);
-int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req);
+int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count);
+void atomisp_stop_streaming(struct vb2_queue *vq);
enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device
*asd);
-void atomisp_videobuf_free_buf(struct videobuf_buffer *vb);
-
extern const struct v4l2_ioctl_ops atomisp_ioctl_ops;
unsigned int atomisp_streaming_count(struct atomisp_device *isp);
@@ -57,4 +55,8 @@ long atomisp_compat_ioctl32(struct file *file,
int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp,
bool isp_timeout);
+
+int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count);
+void atomisp_stop_streaming(struct vb2_queue *vq);
+
#endif /* __ATOMISP_IOCTL_H__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index 847dfee6ad78..cadc468b4c2f 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -1064,6 +1064,8 @@ static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
pipe->asd = asd;
pipe->isp = asd->isp;
spin_lock_init(&pipe->irq_lock);
+ mutex_init(&pipe->vb_queue_mutex);
+ INIT_LIST_HEAD(&pipe->buffers_in_css);
INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
INIT_LIST_HEAD(&pipe->per_frame_params);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
index a1f4da35235d..bd2872cbb50c 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
@@ -21,8 +21,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include <media/videobuf-core.h>
-
+#include <media/videobuf2-v4l2.h>
#include "atomisp_common.h"
#include "atomisp_compat.h"
#include "atomisp_v4l2.h"
@@ -69,7 +68,12 @@ struct atomisp_video_pipe {
struct video_device vdev;
enum v4l2_buf_type type;
struct media_pad pad;
- struct videobuf_queue capq;
+ struct vb2_queue vb_queue;
+ /* Lock for vb_queue, when also taking isp->mutex this must be taken first! */
+ struct mutex vb_queue_mutex;
+ /* List of video-buffers handed over to the CSS */
+ struct list_head buffers_in_css;
+ /* List of video-buffers handed over to the driver, but not yet to the CSS */
struct list_head activeq;
/*
* the buffers waiting for per-frame parameters, this is only valid
@@ -79,10 +83,13 @@ struct atomisp_video_pipe {
/* the link list to store per_frame parameters */
struct list_head per_frame_params;
+ /* Filled through atomisp_get_css_frame_info() on queue setup */
+ struct ia_css_frame_info frame_info;
+
/* Store here the initial run mode */
unsigned int default_run_mode;
-
- unsigned int buffers_in_css;
+ /* Set from streamoff to disallow queuing further buffers in CSS */
+ bool stopping;
/*
* irq_lock is used to protect video buffer state change operations and
@@ -110,6 +117,11 @@ struct atomisp_video_pipe {
struct atomisp_css_params_with_list *frame_params[VIDEO_MAX_FRAME];
};
+#define vq_to_pipe(queue) \
+ container_of(queue, struct atomisp_video_pipe, vb_queue)
+
+#define vb_to_pipe(vb) vq_to_pipe((vb)->vb2_queue)
+
struct atomisp_pad_format {
struct v4l2_mbus_framefmt fmt;
struct v4l2_rect crop;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index d5bb9906ca6f..e786b81921da 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -573,11 +573,7 @@ static int atomisp_mrfld_pre_power_down(struct atomisp_device *isp)
unsigned long flags;
spin_lock_irqsave(&isp->lock, flags);
- if (isp->sw_contex.power_state == ATOM_ISP_POWER_DOWN) {
- spin_unlock_irqrestore(&isp->lock, flags);
- dev_dbg(isp->dev, "<%s %d.\n", __func__, __LINE__);
- return 0;
- }
+
/*
* MRFLD HAS requirement: cannot power off i-unit if
* ISP has IRQ not serviced.
@@ -724,62 +720,51 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
return -EBUSY;
}
-/* Workaround for pmu_nc_set_power_state not ready in MRFLD */
-int atomisp_mrfld_power_down(struct atomisp_device *isp)
-{
- return atomisp_mrfld_power(isp, false);
-}
-
-/* Workaround for pmu_nc_set_power_state not ready in MRFLD */
-int atomisp_mrfld_power_up(struct atomisp_device *isp)
-{
- return atomisp_mrfld_power(isp, true);
-}
-
-int atomisp_runtime_suspend(struct device *dev)
+int atomisp_power_off(struct device *dev)
{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
+ struct atomisp_device *isp = dev_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
int ret;
+ u32 reg;
+
+ atomisp_css_uninit(isp);
ret = atomisp_mrfld_pre_power_down(isp);
if (ret)
return ret;
- /*Turn off the ISP d-phy*/
- ret = atomisp_ospm_dphy_down(isp);
- if (ret)
- return ret;
+ /*
+ * MRFLD IUNIT DPHY is located in an always-power-on island
+ * MRFLD HW design need all CSI ports are disabled before
+ * powering down the IUNIT.
+ */
+ pci_read_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, &reg);
+ reg |= MRFLD_ALL_CSI_PORTS_OFF_MASK;
+ pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg);
+
cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
- return atomisp_mrfld_power_down(isp);
+ return atomisp_mrfld_power(isp, false);
}
-int atomisp_runtime_resume(struct device *dev)
+int atomisp_power_on(struct device *dev)
{
struct atomisp_device *isp = (struct atomisp_device *)
dev_get_drvdata(dev);
int ret;
- ret = atomisp_mrfld_power_up(isp);
+ ret = atomisp_mrfld_power(isp, true);
if (ret)
return ret;
cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
- if (isp->sw_contex.power_state == ATOM_ISP_POWER_DOWN) {
- /*Turn on ISP d-phy */
- ret = atomisp_ospm_dphy_up(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to power up ISP!.\n");
- return -EINVAL;
- }
- }
/*restore register values for iUnit and iUnitPHY registers*/
if (isp->saved_regs.pcicmdsts)
atomisp_restore_iunit_reg(isp);
atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, true);
- return 0;
+
+ return atomisp_css_init(isp);
}
static int __maybe_unused atomisp_suspend(struct device *dev)
@@ -789,7 +774,6 @@ static int __maybe_unused atomisp_suspend(struct device *dev)
/* FIXME: only has one isp_subdev at present */
struct atomisp_sub_device *asd = &isp->asd[0];
unsigned long flags;
- int ret;
/*
* FIXME: Suspend is not supported by sensors. Abort if any video
@@ -806,45 +790,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev)
}
spin_unlock_irqrestore(&isp->lock, flags);
- ret = atomisp_mrfld_pre_power_down(isp);
- if (ret)
- return ret;
-
- /*Turn off the ISP d-phy */
- ret = atomisp_ospm_dphy_down(isp);
- if (ret) {
- dev_err(isp->dev, "fail to power off ISP\n");
- return ret;
- }
- cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
- return atomisp_mrfld_power_down(isp);
+ return atomisp_power_off(dev);
}
static int __maybe_unused atomisp_resume(struct device *dev)
{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
- int ret;
-
- ret = atomisp_mrfld_power_up(isp);
- if (ret)
- return ret;
-
- cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
-
- /*Turn on ISP d-phy */
- ret = atomisp_ospm_dphy_up(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to power up ISP!.\n");
- return -EINVAL;
- }
-
- /*restore register values for iUnit and iUnitPHY registers*/
- if (isp->saved_regs.pcicmdsts)
- atomisp_restore_iunit_reg(isp);
-
- atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, true);
- return 0;
+ return atomisp_power_on(dev);
}
int atomisp_csi_lane_config(struct atomisp_device *isp)
@@ -1459,7 +1410,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
isp->dev = &pdev->dev;
isp->base = pcim_iomap_table(pdev)[ATOM_ISP_PCI_BAR];
- isp->sw_contex.power_state = ATOM_ISP_POWER_UP;
isp->saved_regs.ispmmadr = start;
dev_dbg(&pdev->dev, "atomisp mmio base: %p\n", isp->base);
@@ -1723,10 +1673,8 @@ load_fw_fail:
atomisp_msi_irq_uninit(isp);
- atomisp_ospm_dphy_down(isp);
-
/* Address later when we worry about the ...field chips */
- if (IS_ENABLED(CONFIG_PM) && atomisp_mrfld_power_down(isp))
+ if (IS_ENABLED(CONFIG_PM) && atomisp_mrfld_power(isp, false))
dev_err(&pdev->dev, "Failed to switch off ISP\n");
atomisp_dev_alloc_fail:
@@ -1774,8 +1722,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl);
static const struct dev_pm_ops atomisp_pm_ops = {
- .runtime_suspend = atomisp_runtime_suspend,
- .runtime_resume = atomisp_runtime_resume,
+ .runtime_suspend = atomisp_power_off,
+ .runtime_resume = atomisp_power_on,
.suspend = atomisp_suspend,
.resume = atomisp_resume,
};
diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h
index 965cfda50707..e42eeaeb3ee4 100644
--- a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h
+++ b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h
@@ -16,6 +16,8 @@
#ifndef __IA_CSS_PIPE_BINARYDESC_H__
#define __IA_CSS_PIPE_BINARYDESC_H__
+#include <linux/math.h>
+
#include <ia_css_types.h> /* ia_css_pipe */
#include <ia_css_frame_public.h> /* ia_css_frame_info */
#include <ia_css_binary.h> /* ia_css_binary_descr */
@@ -56,17 +58,12 @@ void ia_css_pipe_get_vfpp_binarydesc(
*
* @param[in] bds_factor: The bayer downscaling factor.
* (= The bds_factor member in the sh_css_bds_factor structure.)
- * @param[out] bds_factor_numerator: The numerator of the bayer downscaling factor.
- * (= The numerator member in the sh_css_bds_factor structure.)
- * @param[out] bds_factor_denominator: The denominator of the bayer downscaling factor.
- * (= The denominator member in the sh_css_bds_factor structure.)
+ * @param[out] bds: The rational fraction of the bayer downscaling factor.
+ * (= The respective member in the sh_css_bds_factor structure.)
* @return 0 or error code upon error.
*
*/
-int sh_css_bds_factor_get_numerator_denominator(
- unsigned int bds_factor,
- unsigned int *bds_factor_numerator,
- unsigned int *bds_factor_denominator);
+int sh_css_bds_factor_get_fract(unsigned int bds_factor, struct u32_fract *bds);
/* @brief Get a binary descriptor for preview stage.
*
diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h
index 40c8145a0797..7a0c988d89ee 100644
--- a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h
+++ b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h
@@ -38,11 +38,6 @@ void ia_css_pipe_get_firmwares_stage_desc(
const struct ia_css_fw_info *fw,
unsigned int mode);
-void ia_css_pipe_get_acc_stage_desc(
- struct ia_css_pipeline_stage_desc *stage_desc,
- struct ia_css_binary *binary,
- struct ia_css_fw_info *fw);
-
void ia_css_pipe_get_sp_func_stage_desc(
struct ia_css_pipeline_stage_desc *stage_desc,
struct ia_css_frame *out_frame,
diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c
index 7dd0e4a53c8b..06664ce75b60 100644
--- a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c
+++ b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c
@@ -13,6 +13,9 @@
* more details.
*/
+#include <linux/kernel.h>
+#include <linux/math.h>
+
#include "ia_css_pipe_binarydesc.h"
#include "ia_css_frame_format.h"
#include "ia_css_pipe.h"
@@ -23,7 +26,6 @@
#include <assert_support.h>
/* HRT_GDC_N */
#include "gdc_device.h"
-#include <linux/kernel.h>
/* This module provides a binary descriptions to used to find a binary. Since,
* every stage is associated with a binary, it implicity helps stage
@@ -126,40 +128,29 @@ void ia_css_pipe_get_vfpp_binarydesc(
IA_CSS_LEAVE_PRIVATE("");
}
-static struct sh_css_bds_factor bds_factors_list[] = {
- {1, 1, SH_CSS_BDS_FACTOR_1_00},
- {5, 4, SH_CSS_BDS_FACTOR_1_25},
- {3, 2, SH_CSS_BDS_FACTOR_1_50},
- {2, 1, SH_CSS_BDS_FACTOR_2_00},
- {9, 4, SH_CSS_BDS_FACTOR_2_25},
- {5, 2, SH_CSS_BDS_FACTOR_2_50},
- {3, 1, SH_CSS_BDS_FACTOR_3_00},
- {4, 1, SH_CSS_BDS_FACTOR_4_00},
- {9, 2, SH_CSS_BDS_FACTOR_4_50},
- {5, 1, SH_CSS_BDS_FACTOR_5_00},
- {6, 1, SH_CSS_BDS_FACTOR_6_00},
- {8, 1, SH_CSS_BDS_FACTOR_8_00}
+static struct u32_fract bds_factors_list[] = {
+ [SH_CSS_BDS_FACTOR_1_00] = {1, 1},
+ [SH_CSS_BDS_FACTOR_1_25] = {5, 4},
+ [SH_CSS_BDS_FACTOR_1_50] = {3, 2},
+ [SH_CSS_BDS_FACTOR_2_00] = {2, 1},
+ [SH_CSS_BDS_FACTOR_2_25] = {9, 4},
+ [SH_CSS_BDS_FACTOR_2_50] = {5, 2},
+ [SH_CSS_BDS_FACTOR_3_00] = {3, 1},
+ [SH_CSS_BDS_FACTOR_4_00] = {4, 1},
+ [SH_CSS_BDS_FACTOR_4_50] = {9, 2},
+ [SH_CSS_BDS_FACTOR_5_00] = {5, 1},
+ [SH_CSS_BDS_FACTOR_6_00] = {6, 1},
+ [SH_CSS_BDS_FACTOR_8_00] = {8, 1},
};
-int sh_css_bds_factor_get_numerator_denominator(
- unsigned int bds_factor,
- unsigned int *bds_factor_numerator,
- unsigned int *bds_factor_denominator)
+int sh_css_bds_factor_get_fract(unsigned int bds_factor, struct u32_fract *bds)
{
- unsigned int i;
-
- /* Loop over all bds factors until a match is found */
- for (i = 0; i < ARRAY_SIZE(bds_factors_list); i++) {
- if (bds_factors_list[i].bds_factor == bds_factor) {
- *bds_factor_numerator = bds_factors_list[i].numerator;
- *bds_factor_denominator = bds_factors_list[i].denominator;
- return 0;
- }
- }
+ /* Throw an error since bds_factor cannot be found in bds_factors_list */
+ if (bds_factor >= ARRAY_SIZE(bds_factors_list))
+ return -EINVAL;
- /* Throw an error since bds_factor cannot be found
- in bds_factors_list */
- return -EINVAL;
+ *bds = bds_factors_list[bds_factor];
+ return 0;
}
int binarydesc_calculate_bds_factor(
@@ -194,7 +185,7 @@ int binarydesc_calculate_bds_factor(
(out_h * num / den <= in_h);
if (cond) {
- *bds_factor = bds_factors_list[i].bds_factor;
+ *bds_factor = i;
return 0;
}
}
diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c
index 82a24aabe8ce..6c93fa1c683b 100644
--- a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c
+++ b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c
@@ -74,27 +74,6 @@ void ia_css_pipe_get_firmwares_stage_desc(
stage_desc->vf_frame = vf_frame;
}
-void ia_css_pipe_get_acc_stage_desc(
- struct ia_css_pipeline_stage_desc *stage_desc,
- struct ia_css_binary *binary,
- struct ia_css_fw_info *fw)
-{
- unsigned int i;
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
- "ia_css_pipe_get_acc_stage_desc() enter:\n");
- stage_desc->binary = binary;
- stage_desc->firmware = fw;
- stage_desc->sp_func = IA_CSS_PIPELINE_NO_FUNC;
- stage_desc->max_input_width = 0;
- stage_desc->mode = IA_CSS_BINARY_MODE_VF_PP;
- stage_desc->in_frame = NULL;
- for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
- stage_desc->out_frame[i] = NULL;
- }
- stage_desc->vf_frame = NULL;
-}
-
void ia_css_pipe_get_sp_func_stage_desc(
struct ia_css_pipeline_stage_desc *stage_desc,
struct ia_css_frame *out_frame,
diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h
index 1c7938d8ccb5..8f79424bedb2 100644
--- a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h
+++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h
@@ -161,7 +161,7 @@ STORAGE_CLASS_PIXELGEN_C void pixelgen_ctrl_dump_state(
state->syng_stat_fcnt);
ia_css_print("Pixel Generator ID %d syng stat done 0x%x\n", ID,
state->syng_stat_done);
- ia_css_print("Pixel Generator ID %d tpg modee 0x%x\n", ID, state->tpg_mode);
+ ia_css_print("Pixel Generator ID %d tpg mode 0x%x\n", ID, state->tpg_mode);
ia_css_print("Pixel Generator ID %d tpg hcnt mask 0x%x\n", ID,
state->tpg_hcnt_mask);
ia_css_print("Pixel Generator ID %d tpg hcnt mask 0x%x\n", ID,
diff --git a/drivers/staging/media/atomisp/pci/hive_types.h b/drivers/staging/media/atomisp/pci/hive_types.h
index 4b8a679fb672..55d36931f079 100644
--- a/drivers/staging/media/atomisp/pci/hive_types.h
+++ b/drivers/staging/media/atomisp/pci/hive_types.h
@@ -42,7 +42,7 @@ typedef unsigned int hive_bool;
#define hive_false 0
#define hive_true 1
-typedef char hive_int8;
+typedef signed char hive_int8;
typedef short hive_int16;
typedef int hive_int32;
typedef long long hive_int64;
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c
index fc6cfe9f7744..bb12644fd033 100644
--- a/drivers/staging/media/atomisp/pci/hmm/hmm.c
+++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c
@@ -41,11 +41,9 @@ static bool hmm_initialized;
/*
* p: private
- * s: shared
- * u: user
- * i: ion
+ * v: vmalloc
*/
-static const char hmm_bo_type_string[] = "psui";
+static const char hmm_bo_type_string[] = "pv";
static ssize_t bo_show(struct device *dev, struct device_attribute *attr,
char *buf, struct list_head *bo_list, bool active)
@@ -168,7 +166,8 @@ void hmm_cleanup(void)
hmm_initialized = false;
}
-static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type, const void __user *userptr)
+static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type,
+ void *vmalloc_addr)
{
unsigned int pgnr;
struct hmm_buffer_object *bo;
@@ -192,7 +191,7 @@ static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type, const void __
}
/* Allocate pages for memory */
- ret = hmm_bo_alloc_pages(bo, type, userptr);
+ ret = hmm_bo_alloc_pages(bo, type, vmalloc_addr);
if (ret) {
dev_err(atomisp_dev, "hmm_bo_alloc_pages failed.\n");
goto alloc_page_err;
@@ -205,9 +204,8 @@ static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type, const void __
goto bind_err;
}
- dev_dbg(atomisp_dev,
- "%s: pages: 0x%08x (%zu bytes), type: %d, user ptr %p\n",
- __func__, bo->start, bytes, type, userptr);
+ dev_dbg(atomisp_dev, "pages: 0x%08x (%zu bytes), type: %d, vmalloc %p\n",
+ bo->start, bytes, type, vmalloc);
return bo->start;
@@ -224,9 +222,9 @@ ia_css_ptr hmm_alloc(size_t bytes)
return __hmm_alloc(bytes, HMM_BO_PRIVATE, NULL);
}
-ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr)
+ia_css_ptr hmm_create_from_vmalloc_buf(size_t bytes, void *vmalloc_addr)
{
- return __hmm_alloc(bytes, HMM_BO_USER, userptr);
+ return __hmm_alloc(bytes, HMM_BO_VMALLOC, vmalloc_addr);
}
void hmm_free(ia_css_ptr virt)
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
index a5fd6d38d3c4..5e53eed8ae95 100644
--- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
+++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
@@ -638,6 +638,7 @@ static int alloc_private_pages(struct hmm_buffer_object *bo)
ret = alloc_pages_bulk_array(gfp, bo->pgnr, bo->pages);
if (ret != bo->pgnr) {
free_pages_bulk_array(ret, bo->pages);
+ dev_err(atomisp_dev, "alloc_pages_bulk_array() failed\n");
return -ENOMEM;
}
@@ -651,61 +652,34 @@ static int alloc_private_pages(struct hmm_buffer_object *bo)
return 0;
}
-static void free_user_pages(struct hmm_buffer_object *bo,
- unsigned int page_nr)
+static int alloc_vmalloc_pages(struct hmm_buffer_object *bo, void *vmalloc_addr)
{
+ void *vaddr = vmalloc_addr;
int i;
- for (i = 0; i < page_nr; i++)
- put_page(bo->pages[i]);
-}
-
-/*
- * Convert user space virtual address into pages list
- */
-static int alloc_user_pages(struct hmm_buffer_object *bo,
- const void __user *userptr)
-{
- int page_nr;
-
- userptr = untagged_addr(userptr);
-
- /* Handle frame buffer allocated in user space */
- mutex_unlock(&bo->mutex);
- page_nr = get_user_pages_fast((unsigned long)userptr, bo->pgnr, 1, bo->pages);
- mutex_lock(&bo->mutex);
-
- /* can be written by caller, not forced */
- if (page_nr != bo->pgnr) {
- dev_err(atomisp_dev,
- "get_user_pages err: bo->pgnr = %d, pgnr actually pinned = %d.\n",
- bo->pgnr, page_nr);
- if (page_nr < 0)
- page_nr = 0;
- goto out_of_mem;
+ for (i = 0; i < bo->pgnr; i++) {
+ bo->pages[i] = vmalloc_to_page(vaddr);
+ if (!bo->pages[i]) {
+ dev_err(atomisp_dev, "Error could not get page %d of vmalloc buf\n", i);
+ return -ENOMEM;
+ }
+ vaddr += PAGE_SIZE;
}
return 0;
-
-out_of_mem:
-
- free_user_pages(bo, page_nr);
-
- return -ENOMEM;
}
/*
* allocate/free physical pages for the bo.
*
* type indicate where are the pages from. currently we have 3 types
- * of memory: HMM_BO_PRIVATE, HMM_BO_USER.
+ * of memory: HMM_BO_PRIVATE, HMM_BO_VMALLOC.
*
- * userptr is only valid when type is HMM_BO_USER, it indicates
- * the start address from user space task.
+ * vmalloc_addr is only valid when type is HMM_BO_VMALLOC.
*/
int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
enum hmm_bo_type type,
- const void __user *userptr)
+ void *vmalloc_addr)
{
int ret = -EINVAL;
@@ -720,14 +694,10 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
goto alloc_err;
}
- /*
- * TO DO:
- * add HMM_BO_USER type
- */
if (type == HMM_BO_PRIVATE) {
ret = alloc_private_pages(bo);
- } else if (type == HMM_BO_USER) {
- ret = alloc_user_pages(bo, userptr);
+ } else if (type == HMM_BO_VMALLOC) {
+ ret = alloc_vmalloc_pages(bo, vmalloc_addr);
} else {
dev_err(atomisp_dev, "invalid buffer type.\n");
ret = -EINVAL;
@@ -771,8 +741,8 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo)
if (bo->type == HMM_BO_PRIVATE)
free_private_bo_pages(bo);
- else if (bo->type == HMM_BO_USER)
- free_user_pages(bo, bo->pgnr);
+ else if (bo->type == HMM_BO_VMALLOC)
+ ; /* No-op, nothing to do */
else
dev_err(atomisp_dev, "invalid buffer type.\n");
diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h
index 514d933f934d..7ba464abf447 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h
@@ -20,6 +20,7 @@
* This file contains structs to describe various frame-formats supported by the ISP.
*/
+#include <media/videobuf2-v4l2.h>
#include <type_support.h>
#include "ia_css_err.h"
#include "ia_css_types.h"
@@ -146,7 +147,18 @@ enum ia_css_frame_flash_state {
* This is the main structure used for all input and output images.
*/
struct ia_css_frame {
- struct ia_css_frame_info info; /** info struct describing the frame */
+ /*
+ * The videobuf2 core will allocate buffers including room for private
+ * data (the rest of struct ia_css_frame). The vb2_v4l2_buffer must
+ * be the first member for this to work!
+ * Note the atomisp code also uses ia_css_frame-s which are not used
+ * as v4l2-buffers in some places. In this case the vb2 member will
+ * be unused.
+ */
+ struct vb2_v4l2_buffer vb;
+ /* List-head for linking into the activeq or buffers_waiting_for_param list */
+ struct list_head queue;
+ struct ia_css_frame_info frame_info; /** info struct describing the frame */
ia_css_ptr data; /** pointer to start of image data */
unsigned int data_bytes; /** size of image data in bytes */
/* LA: move this to ia_css_buffer */
@@ -183,22 +195,16 @@ struct ia_css_frame {
info.format */
};
+#define vb_to_frame(vb2) \
+ container_of(to_vb2_v4l2_buffer(vb2), struct ia_css_frame, vb)
+
#define DEFAULT_FRAME { \
- .info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
.dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID, \
.buf_type = IA_CSS_BUFFER_TYPE_INVALID, \
.flash_state = IA_CSS_FRAME_FLASH_STATE_NONE, \
}
-/* @brief Fill a frame with zeros
- *
- * @param frame The frame.
- * @return None
- *
- * Fill a frame with pixel values of zero
- */
-void ia_css_frame_zero(struct ia_css_frame *frame);
-
/* @brief Allocate a CSS frame structure
*
* @param frame The allocated frame.
@@ -220,6 +226,17 @@ ia_css_frame_allocate(struct ia_css_frame **frame,
unsigned int stride,
unsigned int raw_bit_depth);
+/* @brief Initialize a CSS frame structure using a frame info structure.
+ *
+ * @param frame The allocated frame.
+ * @param[in] info The frame info structure.
+ * @return The error code.
+ *
+ * Initialize a frame using the resolution and format from a frame info struct.
+ */
+int ia_css_frame_init_from_info(struct ia_css_frame *frame,
+ const struct ia_css_frame_info *info);
+
/* @brief Allocate a CSS frame structure using a frame info structure.
*
* @param frame The allocated frame.
@@ -244,69 +261,10 @@ ia_css_frame_allocate_from_info(struct ia_css_frame **frame,
void
ia_css_frame_free(struct ia_css_frame *frame);
-/* @brief Allocate a CSS frame structure using a frame info structure.
- *
- * @param frame The allocated frame.
- * @param[in] info The frame info structure.
- * @return The error code.
- *
- * Allocate an empty CSS frame with no data buffer using the parameters
- * in the frame info.
- */
-int
-ia_css_frame_create_from_info(struct ia_css_frame **frame,
- const struct ia_css_frame_info *info);
-
-/* @brief Set a mapped data buffer to a CSS frame
- *
- * @param[in] frame Valid CSS frame pointer
- * @param[in] mapped_data Mapped data buffer to be assigned to the CSS frame
- * @param[in] data_size_bytes Size of the mapped_data in bytes
- * @return The error code.
- *
- * Sets a mapped data buffer to this frame. This function can be called multiple
- * times with different buffers or NULL to reset the data pointer. This API
- * would not try free the mapped_data and its the callers responsiblity to
- * free the mapped_data buffer. However if ia_css_frame_free() is called and
- * the frame had a valid data buffer, it would be freed along with the frame.
- */
-int
-ia_css_frame_set_data(struct ia_css_frame *frame,
- const ia_css_ptr mapped_data,
- size_t data_size_bytes);
-
-/* @brief Map an existing frame data pointer to a CSS frame.
- *
- * @param frame Pointer to the frame to be initialized
- * @param[in] info The frame info.
- * @param[in] data Pointer to the allocated frame data.
- * @param[in] attribute Attributes to be passed to mmgr_mmap.
- * @param[in] context Pointer to the a context to be passed to mmgr_mmap.
- * @return The allocated frame structure.
- *
- * This function maps a pre-allocated pointer into a CSS frame. This can be
- * used when an upper software layer is responsible for allocating the frame
- * data and it wants to share that frame pointer with the CSS code.
- * This function will fill the CSS frame structure just like
- * ia_css_frame_allocate() does, but instead of allocating the memory, it will
- * map the pre-allocated memory into the CSS address space.
- */
-int
-ia_css_frame_map(struct ia_css_frame **frame,
- const struct ia_css_frame_info *info,
- const void __user *data,
- unsigned int pgnr);
-
-/* @brief Unmap a CSS frame structure.
- *
- * @param[in] frame Pointer to the CSS frame.
- * @return None
- *
- * This function unmaps the frame data pointer within a CSS frame and
- * then frees the CSS frame structure. Use this for frame pointers created
- * using ia_css_frame_map().
- */
-void
-ia_css_frame_unmap(struct ia_css_frame *frame);
+static inline const struct ia_css_frame_info *
+ia_css_frame_get_info(const struct ia_css_frame *frame)
+{
+ return frame ? &frame->frame_info : NULL;
+}
#endif /* __IA_CSS_FRAME_PUBLIC_H */
diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe.h b/drivers/staging/media/atomisp/pci/ia_css_pipe.h
index fb58535bff40..22522968b9e6 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_pipe.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_pipe.h
@@ -37,7 +37,6 @@ struct ia_css_preview_settings {
struct ia_css_pipe *copy_pipe;
struct ia_css_pipe *capture_pipe;
- struct ia_css_pipe *acc_pipe;
};
#define IA_CSS_DEFAULT_PREVIEW_SETTINGS { \
@@ -156,7 +155,7 @@ struct ia_css_pipe {
#define IA_CSS_DEFAULT_PIPE { \
.config = DEFAULT_PIPE_CONFIG, \
.info = DEFAULT_PIPE_INFO, \
- .mode = IA_CSS_PIPE_ID_ACC, /* (pipe_id) */ \
+ .mode = IA_CSS_PIPE_ID_VIDEO, /* (pipe_id) */ \
.pipeline = DEFAULT_PIPELINE, \
.output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
.bds_output_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h
index 7352cbf779fb..8ac1586dce4e 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h
@@ -45,7 +45,6 @@ enum ia_css_pipe_mode {
IA_CSS_PIPE_MODE_PREVIEW, /** Preview pipe */
IA_CSS_PIPE_MODE_VIDEO, /** Video pipe */
IA_CSS_PIPE_MODE_CAPTURE, /** Still capture pipe */
- IA_CSS_PIPE_MODE_ACC, /** Accelerated pipe */
IA_CSS_PIPE_MODE_COPY, /** Copy pipe, only used for embedded/image data copying */
IA_CSS_PIPE_MODE_YUVPP, /** YUV post processing pipe, used for all use cases with YUV input,
for SoC sensor and external ISP */
@@ -95,21 +94,11 @@ struct ia_css_pipe_config {
/** output of YUV scaling */
struct ia_css_frame_info vf_output_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
/** output of VF YUV scaling */
- struct ia_css_fw_info *acc_extension;
- /** Pipeline extension accelerator */
- struct ia_css_fw_info **acc_stages;
- /** Standalone accelerator stages */
- u32 num_acc_stages;
- /** Number of standalone accelerator stages */
struct ia_css_capture_config default_capture_config;
/** Default capture config for initial capture pipe configuration. */
struct ia_css_resolution dvs_envelope; /** temporary */
enum ia_css_frame_delay dvs_frame_delay;
/** indicates the DVS loop delay in frame periods */
- int acc_num_execs;
- /** For acceleration pipes only: determine how many times the pipe
- should be run. Setting this to -1 means it will run until
- stopped. */
bool enable_dz;
/** Disabling digital zoom for a pipeline, if this is set to false,
then setting a zoom factor will have no effect.
@@ -153,7 +142,6 @@ struct ia_css_pipe_config {
.vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
.default_capture_config = DEFAULT_CAPTURE_CONFIG, \
.dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \
- .acc_num_execs = -1, \
}
/* Pipe info, this struct describes properties of a pipe after it's stream has
@@ -224,9 +212,6 @@ struct ia_css_pipe_info {
{{0, 0}, 0, 0, 0, 0}, // second_output_info
{{0, 0}, 0, 0, 0, 0}, // vf_output_info
{{0, 0}, 0, 0, 0, 0}, // second_vf_output_info
- NULL, // acc_extension
- NULL, // acc_stages
- 0, // num_acc_stages
{
IA_CSS_CAPTURE_MODE_RAW, // mode
false, // enable_xnr
@@ -234,7 +219,6 @@ struct ia_css_pipe_info {
}, // default_capture_config
{0, 0}, // dvs_envelope
1, // dvs_frame_delay
- -1, // acc_num_execs
true, // enable_dz
NULL, // p_isp_config
};
@@ -426,59 +410,6 @@ int
ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
struct ia_css_buffer *buffer);
-/* @brief Set the state (Enable or Disable) of the Extension stage in the
- * given pipe.
- * @param[in] pipe Pipe handle.
- * @param[in] fw_handle Extension firmware Handle (ia_css_fw_info.handle)
- * @param[in] enable Enable Flag (1 to enable ; 0 to disable)
- *
- * @return
- * 0 : Success
- * -EINVAL : Invalid Parameters
- * -EBUSY : Inactive QOS Pipe
- * (No active stream with this pipe)
- *
- * This function will request state change (enable or disable) for the Extension
- * stage (firmware handle) in the given pipe.
- *
- * Note:
- * 1. Extension can be enabled/disabled only on QOS Extensions
- * 2. Extension can be enabled/disabled only with an active QOS Pipe
- * 3. Initial(Default) state of QOS Extensions is Disabled
- * 4. State change cannot be guaranteed immediately OR on frame boundary
- *
- */
-int
-ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe,
- u32 fw_handle,
- bool enable);
-
-/* @brief Get the state (Enable or Disable) of the Extension stage in the
- * given pipe.
- * @param[in] pipe Pipe handle.
- * @param[in] fw_handle Extension firmware Handle (ia_css_fw_info.handle)
- * @param[out] *enable Enable Flag
- *
- * @return
- * 0 : Success
- * -EINVAL : Invalid Parameters
- * -EBUSY : Inactive QOS Pipe
- * (No active stream with this pipe)
- *
- * This function will query the state of the Extension stage (firmware handle)
- * in the given Pipe.
- *
- * Note:
- * 1. Extension state can be queried only on QOS Extensions
- * 2. Extension can be enabled/disabled only with an active QOS Pipe
- * 3. Initial(Default) state of QOS Extensions is Disabled.
- *
- */
-int
-ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe,
- u32 fw_handle,
- bool *enable);
-
/* @brief Get selected configuration settings
* @param[in] pipe The pipe.
* @param[out] config Configuration settings.
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c
index c7d88552dfde..0091e2a3da52 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c
@@ -28,9 +28,7 @@ int ia_css_bayer_io_config(const struct ia_css_binary *binary,
const struct ia_css_frame *in_frame = args->in_frame;
const struct ia_css_frame **out_frames = (const struct ia_css_frame **)
&args->out_frame;
- const struct ia_css_frame_info *in_frame_info = (in_frame) ? &in_frame->info :
- &binary->in_frame_info;
-
+ const struct ia_css_frame_info *in_frame_info = ia_css_frame_get_info(in_frame);
const unsigned int ddr_bits_per_element = sizeof(short) * 8;
const unsigned int ddr_elems_per_word = ceil_div(HIVE_ISP_DDR_WORD_BITS,
ddr_bits_per_element);
@@ -80,12 +78,12 @@ int ia_css_bayer_io_config(const struct ia_css_binary *binary,
"ia_css_bayer_io_config() put part enter:\n");
#endif
- ret = ia_css_dma_configure_from_info(&config, &out_frames[0]->info);
+ ret = ia_css_dma_configure_from_info(&config, &out_frames[0]->frame_info);
if (ret)
return ret;
to->base_address = out_frames[0]->data;
- to->width = out_frames[0]->info.res.width;
- to->height = out_frames[0]->info.res.height;
+ to->width = out_frames[0]->frame_info.res.width;
+ to->height = out_frames[0]->frame_info.res.height;
to->stride = config.stride;
to->ddr_elems_per_word = ddr_elems_per_word;
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c
index 7d2ef6e26ee6..32c504a950ce 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c
@@ -28,9 +28,7 @@ int ia_css_yuv444_io_config(const struct ia_css_binary *binary,
const struct ia_css_frame *in_frame = args->in_frame;
const struct ia_css_frame **out_frames = (const struct ia_css_frame **)
&args->out_frame;
- const struct ia_css_frame_info *in_frame_info = (in_frame) ? &in_frame->info :
- &binary->in_frame_info;
-
+ const struct ia_css_frame_info *in_frame_info = ia_css_frame_get_info(in_frame);
const unsigned int ddr_bits_per_element = sizeof(short) * 8;
const unsigned int ddr_elems_per_word = ceil_div(HIVE_ISP_DDR_WORD_BITS,
ddr_bits_per_element);
@@ -81,13 +79,13 @@ int ia_css_yuv444_io_config(const struct ia_css_binary *binary,
"ia_css_yuv444_io_config() put part enter:\n");
#endif
- ret = ia_css_dma_configure_from_info(&config, &out_frames[0]->info);
+ ret = ia_css_dma_configure_from_info(&config, &out_frames[0]->frame_info);
if (ret)
return ret;
to->base_address = out_frames[0]->data;
- to->width = out_frames[0]->info.res.width;
- to->height = out_frames[0]->info.res.height;
+ to->width = out_frames[0]->frame_info.res.width;
+ to->height = out_frames[0]->frame_info.res.height;
to->stride = config.stride;
to->ddr_elems_per_word = ddr_elems_per_word;
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c
index 08ed916a7eb8..9288a7a37b37 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c
@@ -30,7 +30,7 @@ int ia_css_ref_config(struct sh_css_isp_ref_isp_config *to,
int ret;
if (from->ref_frames[0]) {
- ret = ia_css_dma_configure_from_info(&to->port_b, &from->ref_frames[0]->info);
+ ret = ia_css_dma_configure_from_info(&to->port_b, &from->ref_frames[0]->frame_info);
if (ret)
return ret;
to->width_a_over_b = elems_a / to->port_b.elems;
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c
index 53050c0c49fc..a5fea753ec64 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c
@@ -79,11 +79,11 @@ int ia_css_tnr_config(struct sh_css_isp_tnr_isp_config *to,
unsigned int i;
int ret;
- ret = ia_css_dma_configure_from_info(&to->port_b, &from->tnr_frames[0]->info);
+ ret = ia_css_dma_configure_from_info(&to->port_b, &from->tnr_frames[0]->frame_info);
if (ret)
return ret;
to->width_a_over_b = elems_a / to->port_b.elems;
- to->frame_height = from->tnr_frames[0]->info.res.height;
+ to->frame_height = from->tnr_frames[0]->frame_info.res.height;
for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) {
to->tnr_frame_addr[i] = from->tnr_frames[i]->data +
from->tnr_frames[i]->planes.yuyv.offset;
diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
index 406ed5fb4c6a..768da86b8c2c 100644
--- a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
+++ b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
@@ -13,6 +13,8 @@
* more details.
*/
+#include <linux/math.h>
+
#include <math_support.h>
#include <gdc_device.h> /* HR_GDC_N */
@@ -128,16 +130,8 @@ ia_css_binary_compute_shading_table_bayer_origin(
{
int err;
- /* Numerator and denominator of the fixed bayer downscaling factor.
- (numerator >= denominator) */
- unsigned int bds_num, bds_den;
-
- /* Horizontal/Vertical ratio of bayer scaling
- between input area and output area. */
- unsigned int bs_hor_ratio_in;
- unsigned int bs_hor_ratio_out;
- unsigned int bs_ver_ratio_in;
- unsigned int bs_ver_ratio_out;
+ /* Rational fraction of the fixed bayer downscaling factor. */
+ struct u32_fract bds;
/* Left padding set by InputFormatter. */
unsigned int left_padding_bqs; /* in bqs */
@@ -158,19 +152,11 @@ ia_css_binary_compute_shading_table_bayer_origin(
unsigned int bad_bqs_on_top_before_bs; /* in bqs */
unsigned int bad_bqs_on_top_after_bs; /* in bqs */
- /* Get the numerator and denominator of bayer downscaling factor. */
- err = sh_css_bds_factor_get_numerator_denominator
- (required_bds_factor, &bds_num, &bds_den);
+ /* Get the rational fraction of bayer downscaling factor. */
+ err = sh_css_bds_factor_get_fract(required_bds_factor, &bds);
if (err)
return err;
- /* Set the horizontal/vertical ratio of bayer scaling
- between input area and output area. */
- bs_hor_ratio_in = bds_num;
- bs_hor_ratio_out = bds_den;
- bs_ver_ratio_in = bds_num;
- bs_ver_ratio_out = bds_den;
-
/* Set the left padding set by InputFormatter. (ifmtr.c) */
if (stream_config->left_padding == -1)
left_padding_bqs = _ISP_BQS(binary->left_padding);
@@ -228,18 +214,18 @@ ia_css_binary_compute_shading_table_bayer_origin(
located on the shading table during the shading correction. */
res->sc_bayer_origin_x_bqs_on_shading_table =
((left_padding_adjusted_bqs + bad_bqs_on_left_before_bs)
- * bs_hor_ratio_out + bs_hor_ratio_in / 2) / bs_hor_ratio_in
+ * bds.denominator + bds.numerator / 2) / bds.numerator
+ bad_bqs_on_left_after_bs;
- /* "+ bs_hor_ratio_in/2": rounding for division by bs_hor_ratio_in */
+ /* "+ bds.numerator / 2": rounding for division by bds.numerator */
res->sc_bayer_origin_y_bqs_on_shading_table =
- (bad_bqs_on_top_before_bs * bs_ver_ratio_out + bs_ver_ratio_in / 2) / bs_ver_ratio_in
+ (bad_bqs_on_top_before_bs * bds.denominator + bds.numerator / 2) / bds.numerator
+ bad_bqs_on_top_after_bs;
- /* "+ bs_ver_ratio_in/2": rounding for division by bs_ver_ratio_in */
+ /* "+ bds.numerator / 2": rounding for division by bds.numerator */
- res->bayer_scale_hor_ratio_in = (uint32_t)bs_hor_ratio_in;
- res->bayer_scale_hor_ratio_out = (uint32_t)bs_hor_ratio_out;
- res->bayer_scale_ver_ratio_in = (uint32_t)bs_ver_ratio_in;
- res->bayer_scale_ver_ratio_out = (uint32_t)bs_ver_ratio_out;
+ res->bayer_scale_hor_ratio_in = bds.numerator;
+ res->bayer_scale_hor_ratio_out = bds.denominator;
+ res->bayer_scale_ver_ratio_in = bds.numerator;
+ res->bayer_scale_ver_ratio_out = bds.denominator;
return err;
}
diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
index 3d269bd23207..bb6204cb42c5 100644
--- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
+++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
@@ -133,7 +133,6 @@ static const char *const pipe_id_to_str[] = {
/* [IA_CSS_PIPE_ID_VIDEO] =*/ "video",
/* [IA_CSS_PIPE_ID_CAPTURE] =*/ "capture",
/* [IA_CSS_PIPE_ID_YUVPP] =*/ "yuvpp",
- /* [IA_CSS_PIPE_ID_ACC] =*/ "accelerator"
};
static char dot_id_input_bin[SH_CSS_MAX_BINARY_NAME + 10];
@@ -1301,11 +1300,11 @@ void ia_css_debug_frame_print(const struct ia_css_frame *frame,
data = (char *)HOST_ADDRESS(frame->data);
ia_css_debug_dtrace(2, "frame %s (%p):\n", descr, frame);
ia_css_debug_dtrace(2, " resolution = %dx%d\n",
- frame->info.res.width, frame->info.res.height);
+ frame->frame_info.res.width, frame->frame_info.res.height);
ia_css_debug_dtrace(2, " padded width = %d\n",
- frame->info.padded_width);
- ia_css_debug_dtrace(2, " format = %d\n", frame->info.format);
- switch (frame->info.format) {
+ frame->frame_info.padded_width);
+ ia_css_debug_dtrace(2, " format = %d\n", frame->frame_info.format);
+ switch (frame->frame_info.format) {
case IA_CSS_FRAME_FORMAT_NV12:
case IA_CSS_FRAME_FORMAT_NV16:
case IA_CSS_FRAME_FORMAT_NV21:
@@ -2565,11 +2564,11 @@ ia_css_debug_pipe_graph_dump_frame(
dtrace_dot(
"node [shape = box, fixedsize=true, width=2, height=0.7]; \"%p\" [label = \"%s\\n%d(%d) x %d, %dbpp\\n%s\"];",
frame,
- debug_frame_format2str(frame->info.format),
- frame->info.res.width,
- frame->info.padded_width,
- frame->info.res.height,
- frame->info.raw_bit_depth,
+ debug_frame_format2str(frame->frame_info.format),
+ frame->frame_info.res.width,
+ frame->frame_info.padded_width,
+ frame->frame_info.res.height,
+ frame->frame_info.raw_bit_depth,
bufinfo);
if (in_frame) {
@@ -2866,10 +2865,10 @@ ia_css_debug_pipe_graph_dump_sp_raw_copy(
snprintf(ring_buffer, sizeof(ring_buffer),
"node [shape = box, fixedsize=true, width=2, height=0.7]; \"%p\" [label = \"%s\\n%d(%d) x %d\\nRingbuffer\"];",
out_frame,
- debug_frame_format2str(out_frame->info.format),
- out_frame->info.res.width,
- out_frame->info.padded_width,
- out_frame->info.res.height);
+ debug_frame_format2str(out_frame->frame_info.format),
+ out_frame->frame_info.res.width,
+ out_frame->frame_info.padded_width,
+ out_frame->frame_info.res.height);
dtrace_dot(ring_buffer);
@@ -2989,16 +2988,10 @@ ia_css_debug_dump_pipe_config(
ia_css_debug_dump_frame_info(&config->vf_output_info[i],
"vf_output_info");
}
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "acc_extension: %p\n",
- config->acc_extension);
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "num_acc_stages: %d\n",
- config->num_acc_stages);
ia_css_debug_dump_capture_config(&config->default_capture_config);
ia_css_debug_dump_resolution(&config->dvs_envelope, "dvs_envelope");
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "dvs_frame_delay: %d\n",
config->dvs_frame_delay);
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "acc_num_execs: %d\n",
- config->acc_num_execs);
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "enable_dz: %d\n",
config->enable_dz);
IA_CSS_LEAVE_PRIVATE("");
diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c
index 5a7058320ee6..83bb42e05421 100644
--- a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c
+++ b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c
@@ -88,12 +88,6 @@ ia_css_elems_bytes_from_info(
** CSS API functions, exposed by ia_css.h
**************************************************************************/
-void ia_css_frame_zero(struct ia_css_frame *frame)
-{
- assert(frame);
- hmm_set(frame->data, 0, frame->data_bytes);
-}
-
int ia_css_frame_allocate_from_info(struct ia_css_frame **frame,
const struct ia_css_frame_info *info)
{
@@ -143,121 +137,6 @@ int ia_css_frame_allocate(struct ia_css_frame **frame,
return err;
}
-int ia_css_frame_map(struct ia_css_frame **frame,
- const struct ia_css_frame_info *info,
- const void __user *data,
- unsigned int pgnr)
-{
- int err = 0;
- struct ia_css_frame *me;
-
- assert(frame);
-
- /* Create the frame structure */
- err = ia_css_frame_create_from_info(&me, info);
-
- if (err)
- return err;
-
- if (pgnr < ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
- dev_err(atomisp_dev,
- "user space memory size is less than the expected size..\n");
- err = -ENOMEM;
- goto error;
- } else if (pgnr > ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
- dev_err(atomisp_dev,
- "user space memory size is large than the expected size..\n");
- err = -ENOMEM;
- goto error;
- }
-
- me->data = hmm_create_from_userdata(me->data_bytes, data);
- if (me->data == mmgr_NULL)
- err = -EINVAL;
-
-error:
- if (err) {
- kvfree(me);
- me = NULL;
- }
-
- *frame = me;
-
- return err;
-}
-
-int ia_css_frame_create_from_info(struct ia_css_frame **frame,
- const struct ia_css_frame_info *info)
-{
- int err = 0;
- struct ia_css_frame *me;
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_create_from_info() enter:\n");
- if (!frame || !info) {
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_create_from_info() leave: invalid arguments\n");
- return -EINVAL;
- }
-
- me = frame_create(info->res.width,
- info->res.height,
- info->format,
- info->padded_width,
- info->raw_bit_depth,
- false);
- if (!me) {
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_create_from_info() leave: frame create failed\n");
- return -ENOMEM;
- }
-
- err = ia_css_frame_init_planes(me);
-
- if (err) {
- kvfree(me);
- me = NULL;
- }
-
- *frame = me;
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_create_from_info() leave:\n");
-
- return err;
-}
-
-int ia_css_frame_set_data(struct ia_css_frame *frame,
- const ia_css_ptr mapped_data,
- size_t data_bytes)
-{
- int err = 0;
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_set_data() enter:\n");
- if (!frame) {
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_set_data() leave: NULL frame\n");
- return -EINVAL;
- }
-
- /* If we are setting a valid data.
- * Make sure that there is enough
- * room for the expected frame format
- */
- if ((mapped_data != mmgr_NULL) && (frame->data_bytes > data_bytes)) {
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "ia_css_frame_set_data() leave: invalid arguments\n");
- return -EINVAL;
- }
-
- frame->data = mapped_data;
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_set_data() leave:\n");
-
- return err;
-}
-
void ia_css_frame_free(struct ia_css_frame *frame)
{
IA_CSS_ENTER_PRIVATE("frame = %p", frame);
@@ -286,32 +165,32 @@ int ia_css_frame_init_planes(struct ia_css_frame *frame)
{
assert(frame);
- switch (frame->info.format) {
+ switch (frame->frame_info.format) {
case IA_CSS_FRAME_FORMAT_MIPI:
dev_err(atomisp_dev,
"%s: unexpected use of IA_CSS_FRAME_FORMAT_MIPI\n", __func__);
return -EINVAL;
case IA_CSS_FRAME_FORMAT_RAW_PACKED:
frame_init_raw_single_plane(frame, &frame->planes.raw,
- frame->info.res.height,
- frame->info.padded_width,
- frame->info.raw_bit_depth);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width,
+ frame->frame_info.raw_bit_depth);
break;
case IA_CSS_FRAME_FORMAT_RAW:
frame_init_single_plane(frame, &frame->planes.raw,
- frame->info.res.height,
- frame->info.padded_width,
- frame->info.raw_bit_depth <= 8 ? 1 : 2);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width,
+ frame->frame_info.raw_bit_depth <= 8 ? 1 : 2);
break;
case IA_CSS_FRAME_FORMAT_RGB565:
frame_init_single_plane(frame, &frame->planes.rgb,
- frame->info.res.height,
- frame->info.padded_width, 2);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width, 2);
break;
case IA_CSS_FRAME_FORMAT_RGBA888:
frame_init_single_plane(frame, &frame->planes.rgb,
- frame->info.res.height,
- frame->info.padded_width * 4, 1);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width * 4, 1);
break;
case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
frame_init_rgb_planes(frame, 1);
@@ -324,14 +203,14 @@ int ia_css_frame_init_planes(struct ia_css_frame *frame)
case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
frame_init_single_plane(frame, &frame->planes.yuyv,
- frame->info.res.height,
- frame->info.padded_width * 2, 1);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width * 2, 1);
break;
case IA_CSS_FRAME_FORMAT_YUV_LINE:
/* Needs 3 extra lines to allow vf_pp prefetching */
frame_init_single_plane(frame, &frame->planes.yuyv,
- frame->info.res.height * 3 / 2 + 3,
- frame->info.padded_width, 1);
+ frame->frame_info.res.height * 3 / 2 + 3,
+ frame->frame_info.padded_width, 1);
break;
case IA_CSS_FRAME_FORMAT_NV11:
frame_init_nv_planes(frame, 4, 1, 1);
@@ -380,8 +259,8 @@ int ia_css_frame_init_planes(struct ia_css_frame *frame)
break;
case IA_CSS_FRAME_FORMAT_BINARY_8:
frame_init_single_plane(frame, &frame->planes.binary.data,
- frame->info.res.height,
- frame->info.padded_width, 1);
+ frame->frame_info.res.height,
+ frame->frame_info.padded_width, 1);
frame->planes.binary.size = 0;
break;
default:
@@ -510,8 +389,8 @@ bool ia_css_frame_is_same_type(const struct ia_css_frame *frame_a,
const struct ia_css_frame *frame_b)
{
bool is_equal = false;
- const struct ia_css_frame_info *info_a = &frame_a->info,
- *info_b = &frame_b->info;
+ const struct ia_css_frame_info *info_a = &frame_a->frame_info;
+ const struct ia_css_frame_info *info_b = &frame_b->frame_info;
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
"ia_css_frame_is_same_type() enter:\n");
@@ -613,8 +492,8 @@ static void frame_init_nv_planes(struct ia_css_frame *frame,
unsigned int vertical_decimation,
unsigned int bytes_per_element)
{
- unsigned int y_width = frame->info.padded_width;
- unsigned int y_height = frame->info.res.height;
+ unsigned int y_width = frame->frame_info.padded_width;
+ unsigned int y_height = frame->frame_info.res.height;
unsigned int uv_width;
unsigned int uv_height;
unsigned int y_bytes;
@@ -627,7 +506,7 @@ static void frame_init_nv_planes(struct ia_css_frame *frame,
uv_width = 2 * (y_width / horizontal_decimation);
uv_height = y_height / vertical_decimation;
- if (frame->info.format == IA_CSS_FRAME_FORMAT_NV12_TILEY) {
+ if (frame->frame_info.format == IA_CSS_FRAME_FORMAT_NV12_TILEY) {
y_width = CEIL_MUL(y_width, NV12_TILEY_TILE_WIDTH);
uv_width = CEIL_MUL(uv_width, NV12_TILEY_TILE_WIDTH);
y_height = CEIL_MUL(y_height, NV12_TILEY_TILE_HEIGHT);
@@ -652,8 +531,8 @@ static void frame_init_yuv_planes(struct ia_css_frame *frame,
bool swap_uv,
unsigned int bytes_per_element)
{
- unsigned int y_width = frame->info.padded_width,
- y_height = frame->info.res.height,
+ unsigned int y_width = frame->frame_info.padded_width,
+ y_height = frame->frame_info.res.height,
uv_width = y_width / horizontal_decimation,
uv_height = y_height / vertical_decimation,
y_stride, y_bytes, uv_bytes, uv_stride;
@@ -682,8 +561,8 @@ static void frame_init_yuv_planes(struct ia_css_frame *frame,
static void frame_init_rgb_planes(struct ia_css_frame *frame,
unsigned int bytes_per_element)
{
- unsigned int width = frame->info.res.width,
- height = frame->info.res.height, stride, bytes;
+ unsigned int width = frame->frame_info.res.width,
+ height = frame->frame_info.res.height, stride, bytes;
stride = width * bytes_per_element;
bytes = stride * height;
@@ -698,8 +577,8 @@ static void frame_init_rgb_planes(struct ia_css_frame *frame,
static void frame_init_qplane6_planes(struct ia_css_frame *frame)
{
- unsigned int width = frame->info.padded_width / 2,
- height = frame->info.res.height / 2, bytes, stride;
+ unsigned int width = frame->frame_info.padded_width / 2,
+ height = frame->frame_info.res.height / 2, bytes, stride;
stride = width * 2;
bytes = stride * height;
@@ -781,11 +660,11 @@ static struct ia_css_frame *frame_create(unsigned int width,
return NULL;
memset(me, 0, sizeof(*me));
- me->info.res.width = width;
- me->info.res.height = height;
- me->info.format = format;
- me->info.padded_width = padded_width;
- me->info.raw_bit_depth = raw_bit_depth;
+ me->frame_info.res.width = width;
+ me->frame_info.res.height = height;
+ me->frame_info.format = format;
+ me->frame_info.padded_width = padded_width;
+ me->frame_info.raw_bit_depth = raw_bit_depth;
me->valid = valid;
me->data_bytes = 0;
me->data = mmgr_NULL;
@@ -847,3 +726,19 @@ void ia_css_resolution_to_sp_resolution(
to->width = (uint16_t)from->width;
to->height = (uint16_t)from->height;
}
+
+int ia_css_frame_init_from_info(struct ia_css_frame *frame,
+ const struct ia_css_frame_info *frame_info)
+{
+ frame->frame_info.res.width = frame_info->res.width;
+ frame->frame_info.res.height = frame_info->res.height;
+ frame->frame_info.format = frame_info->format;
+ frame->frame_info.padded_width = frame_info->padded_width;
+ frame->frame_info.raw_bit_depth = frame_info->raw_bit_depth;
+ frame->valid = true;
+ /* To indicate it is not valid frame. */
+ frame->dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID;
+ frame->buf_type = IA_CSS_BUFFER_TYPE_INVALID;
+
+ return ia_css_frame_init_planes(frame);
+}
diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h
index de2c526a58ae..222c381ff3b9 100644
--- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h
+++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h
@@ -54,7 +54,6 @@ struct ia_css_pipeline {
unsigned int inout_port_config;
int num_execs;
bool acquire_isp_each_stage;
- u32 pipe_qos_config;
};
#define DEFAULT_PIPELINE { \
@@ -65,7 +64,6 @@ struct ia_css_pipeline {
.dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \
.num_execs = -1, \
.acquire_isp_each_stage = true, \
- .pipe_qos_config = QOS_INVALID \
}
/* Stage descriptor used to create a new stage in the pipeline */
diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c
index dfc50247ea8e..e9e187649a65 100644
--- a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c
+++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c
@@ -774,14 +774,6 @@ ia_css_pipeline_configure_inout_port(struct ia_css_pipeline *me,
(uint8_t)SH_CSS_PORT_OUTPUT,
(uint8_t)SH_CSS_HOST_TYPE, 1);
break;
- case IA_CSS_PIPE_ID_ACC:
- SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
- (uint8_t)SH_CSS_PORT_INPUT,
- (uint8_t)SH_CSS_HOST_TYPE, 1);
- SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
- (uint8_t)SH_CSS_PORT_OUTPUT,
- (uint8_t)SH_CSS_HOST_TYPE, 1);
- break;
default:
break;
}
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index da96aaffebc1..726cb7aa4ecd 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -209,13 +209,6 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe,
enum ia_css_frame_format format);
/* ISP 2401 */
-static int
-ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware);
-
-static void
-ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware);
static void
ia_css_reset_defaults(struct sh_css *css);
@@ -287,10 +280,6 @@ init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
struct ia_css_frame *out_frame, unsigned int idx);
static int
-sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
- const void *acc_fw);
-
-static int
alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
static void
@@ -329,9 +318,6 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe);
static int
create_host_yuvpp_pipeline(struct ia_css_pipe *pipe);
-static int
-create_host_acc_pipeline(struct ia_css_pipe *pipe);
-
static unsigned int
sh_css_get_sw_interrupt_value(unsigned int irq);
@@ -362,12 +348,6 @@ static struct sh_css_hmm_buffer_record
*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
enum ia_css_buffer_type type);
-void
-ia_css_get_acc_configs(
- struct ia_css_pipe *pipe,
- struct ia_css_isp_config *config);
-
-
#ifdef ISP2401
static unsigned int get_crop_lines_for_bayer_order(const struct
ia_css_stream_config *config);
@@ -1649,15 +1629,6 @@ ia_css_enable_isys_event_queue(bool enable)
return 0;
}
-/* For Acceleration API: Flush FW (shared buffer pointer) arguments */
-void
-sh_css_flush(struct ia_css_acc_fw *fw)
-{
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_flush() enter:\n");
- if ((fw) && (my_css.flush))
- my_css.flush(fw);
-}
-
/*
* Mapping sp threads. Currently, this is done when a stream is created and
* pipelines are ready to be converted to sp pipelines. Be careful if you are
@@ -1670,7 +1641,6 @@ map_sp_threads(struct ia_css_stream *stream, bool map)
struct ia_css_pipe *main_pipe = NULL;
struct ia_css_pipe *copy_pipe = NULL;
struct ia_css_pipe *capture_pipe = NULL;
- struct ia_css_pipe *acc_pipe = NULL;
int err = 0;
enum ia_css_pipe_id pipe_id;
@@ -1691,7 +1661,6 @@ map_sp_threads(struct ia_css_stream *stream, bool map)
case IA_CSS_PIPE_ID_PREVIEW:
copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
- acc_pipe = main_pipe->pipe_settings.preview.acc_pipe;
break;
case IA_CSS_PIPE_ID_VIDEO:
@@ -1700,14 +1669,10 @@ map_sp_threads(struct ia_css_stream *stream, bool map)
break;
case IA_CSS_PIPE_ID_CAPTURE:
- case IA_CSS_PIPE_ID_ACC:
default:
break;
}
- if (acc_pipe)
- ia_css_pipeline_map(acc_pipe->pipe_num, map);
-
if (capture_pipe)
ia_css_pipeline_map(capture_pipe->pipe_num, map);
@@ -1735,7 +1700,6 @@ static int
create_host_pipeline_structure(struct ia_css_stream *stream)
{
struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
- struct ia_css_pipe *acc_pipe = NULL;
enum ia_css_pipe_id pipe_id;
struct ia_css_pipe *main_pipe = NULL;
int err = 0;
@@ -1763,7 +1727,6 @@ create_host_pipeline_structure(struct ia_css_stream *stream)
copy_pipe_delay = main_pipe->dvs_frame_delay;
capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
- acc_pipe = main_pipe->pipe_settings.preview.acc_pipe;
err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
main_pipe->pipe_num, main_pipe->dvs_frame_delay);
break;
@@ -1787,11 +1750,6 @@ create_host_pipeline_structure(struct ia_css_stream *stream)
main_pipe->pipe_num, main_pipe->dvs_frame_delay);
break;
- case IA_CSS_PIPE_ID_ACC:
- err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
- main_pipe->pipe_num, main_pipe->dvs_frame_delay);
- break;
-
default:
err = -EINVAL;
}
@@ -1808,10 +1766,6 @@ create_host_pipeline_structure(struct ia_css_stream *stream)
capture_pipe->pipe_num,
capture_pipe_delay);
- if (!(err) && acc_pipe)
- err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
- acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
-
/* DH regular multi pipe - not continuous mode: create the next pipelines too */
if (!stream->config.continuous) {
int i;
@@ -1837,7 +1791,6 @@ static int
create_host_pipeline(struct ia_css_stream *stream)
{
struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
- struct ia_css_pipe *acc_pipe = NULL;
enum ia_css_pipe_id pipe_id;
struct ia_css_pipe *main_pipe = NULL;
int err = 0;
@@ -1881,27 +1834,17 @@ create_host_pipeline(struct ia_css_stream *stream)
}
}
-#if !defined(ISP2401)
/* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
- if (pipe_id != IA_CSS_PIPE_ID_ACC) {
- err = allocate_mipi_frames(main_pipe, &stream->info);
- if (err)
- goto ERR;
- }
-#elif defined(ISP2401)
- if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
- (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
+ if (!IS_ISP2401 || main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY) {
err = allocate_mipi_frames(main_pipe, &stream->info);
if (err)
goto ERR;
}
-#endif
switch (pipe_id) {
case IA_CSS_PIPE_ID_PREVIEW:
copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
- acc_pipe = main_pipe->pipe_settings.preview.acc_pipe;
max_input_width =
main_pipe->pipe_settings.preview.preview_binary.info->sp.input.max_width;
@@ -1935,12 +1878,6 @@ create_host_pipeline(struct ia_css_stream *stream)
break;
- case IA_CSS_PIPE_ID_ACC:
- err = create_host_acc_pipeline(main_pipe);
- if (err)
- goto ERR;
-
- break;
default:
err = -EINVAL;
}
@@ -1960,12 +1897,6 @@ create_host_pipeline(struct ia_css_stream *stream)
goto ERR;
}
- if (acc_pipe) {
- err = create_host_acc_pipeline(acc_pipe);
- if (err)
- goto ERR;
- }
-
/* DH regular multi pipe - not continuous mode: create the next pipelines too */
if (!stream->config.continuous) {
int i;
@@ -1984,9 +1915,6 @@ create_host_pipeline(struct ia_css_stream *stream)
case IA_CSS_PIPE_ID_YUVPP:
err = create_host_yuvpp_pipeline(stream->pipes[i]);
break;
- case IA_CSS_PIPE_ID_ACC:
- err = create_host_acc_pipeline(stream->pipes[i]);
- break;
default:
err = -EINVAL;
}
@@ -2037,9 +1965,6 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
pipe->mode = IA_CSS_PIPE_ID_VIDEO;
memcpy(&pipe->pipe_settings.video, &video, sizeof(video));
break;
- case IA_CSS_PIPE_MODE_ACC:
- pipe->mode = IA_CSS_PIPE_ID_ACC;
- break;
case IA_CSS_PIPE_MODE_COPY:
pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
break;
@@ -2156,27 +2081,6 @@ find_pipe_by_num(uint32_t pipe_num)
return NULL;
}
-static void sh_css_pipe_free_acc_binaries(
- struct ia_css_pipe *pipe)
-{
- struct ia_css_pipeline *pipeline;
- struct ia_css_pipeline_stage *stage;
-
- if (!pipe) {
- IA_CSS_ERROR("NULL input pointer");
- return;
- }
- pipeline = &pipe->pipeline;
-
- /* loop through the stages and unload them */
- for (stage = pipeline->stages; stage; stage = stage->next) {
- struct ia_css_fw_info *firmware = (struct ia_css_fw_info *)
- stage->firmware;
- if (firmware)
- ia_css_pipe_unload_extension(pipe, firmware);
- }
-}
-
int
ia_css_pipe_destroy(struct ia_css_pipe *pipe)
{
@@ -2241,9 +2145,6 @@ ia_css_pipe_destroy(struct ia_css_pipe *pipe)
ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
pipe->pipe_settings.capture.delay_frames);
break;
- case IA_CSS_PIPE_MODE_ACC:
- sh_css_pipe_free_acc_binaries(pipe);
- break;
case IA_CSS_PIPE_MODE_COPY:
break;
case IA_CSS_PIPE_MODE_YUVPP:
@@ -2261,10 +2162,6 @@ ia_css_pipe_destroy(struct ia_css_pipe *pipe)
ia_css_pipeline_destroy(&pipe->pipeline);
pipe_release_pipe_num(ia_css_pipe_get_pipe_num(pipe));
- /* Temporarily, not every sh_css_pipe has an acc_extension. */
- if (pipe->config.acc_extension)
- ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
-
kfree(pipe);
IA_CSS_LEAVE("err = %d", err);
return err;
@@ -3060,7 +2957,7 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
assert(vf_frame);
- sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx);
+ sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->frame_info, idx);
vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id);
@@ -3229,31 +3126,31 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
assert(frame);
in_frame = frame;
- in_frame->info.format = format;
+ in_frame->frame_info.format = format;
#ifdef ISP2401
if (format == IA_CSS_FRAME_FORMAT_RAW)
- in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
+ in_frame->frame_info.format = (pipe->stream->config.pack_raw_pixels) ?
IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
#endif
- in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
- in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
- in_frame->info.raw_bit_depth =
- ia_css_pipe_util_pipe_input_format_bpp(pipe);
- ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
+ in_frame->frame_info.res.width = pipe->stream->config.input_config.input_res.width;
+ in_frame->frame_info.res.height = pipe->stream->config.input_config.input_res.height;
+ in_frame->frame_info.raw_bit_depth = ia_css_pipe_util_pipe_input_format_bpp(pipe);
+ ia_css_frame_info_set_width(&in_frame->frame_info,
+ pipe->stream->config.input_config.input_res.width, 0);
in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
in_frame->dynamic_queue_id = queue_id;
in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
#ifdef ISP2401
- ia_css_get_crop_offsets(pipe, &in_frame->info);
+ ia_css_get_crop_offsets(pipe, &in_frame->frame_info);
#endif
err = ia_css_frame_init_planes(in_frame);
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
- "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "%s() bayer_order = %d\n",
+ __func__, in_frame->frame_info.raw_bayer_order);
return err;
}
@@ -3268,7 +3165,7 @@ init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
assert(out_frame);
- sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
+ sh_css_pipe_get_output_frame_info(pipe, &out_frame->frame_info, idx);
out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
@@ -3433,31 +3330,6 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
}
}
- /* Append Extension on Video out, if enabled */
- if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
- (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
- struct ia_css_frame *out = NULL;
- struct ia_css_frame *in = NULL;
-
- if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
- (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
- (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
- /* In/Out Frame mapping to support output frame extension.*/
- out = video_stage->args.out_frame[0];
- err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
- if (err)
- goto ERR;
- video_stage->args.out_frame[0] = in;
- }
-
- err = add_firmwares(me, video_binary, pipe->output_stage,
- last_output_firmware(pipe->output_stage),
- IA_CSS_BINARY_MODE_VIDEO,
- in, out, NULL, &video_stage, NULL);
- if (err)
- goto ERR;
- }
-
if (need_yuv_pp && video_stage) {
struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
struct ia_css_frame *tmp_out_frame = NULL;
@@ -3489,45 +3361,6 @@ ERR:
return err;
}
-static int
-create_host_acc_pipeline(struct ia_css_pipe *pipe)
-{
- int err = 0;
- const struct ia_css_fw_info *fw;
- unsigned int i;
-
- IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (!pipe->stream)) {
- IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
- return -EINVAL;
- }
-
- pipe->pipeline.num_execs = pipe->config.acc_num_execs;
- /* Reset pipe_qos_config to default disable all QOS extension stages */
- if (pipe->config.acc_extension)
- pipe->pipeline.pipe_qos_config = 0;
-
- for (fw = pipe->vf_stage; fw; fw = fw->next) {
- err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
- if (err)
- goto ERR;
- }
-
- for (i = 0; i < pipe->config.num_acc_stages; i++) {
- struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
-
- err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
- if (err)
- goto ERR;
- }
-
- ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
-
-ERR:
- IA_CSS_LEAVE_ERR_PRIVATE(err);
- return err;
-}
-
/* Create stages for preview */
static int
create_host_preview_pipeline(struct ia_css_pipe *pipe)
@@ -3690,7 +3523,6 @@ preview_start(struct ia_css_pipe *pipe)
{
int err = 0;
struct ia_css_pipe *copy_pipe, *capture_pipe;
- struct ia_css_pipe *acc_pipe;
enum sh_css_pipe_config_override copy_ovrd;
enum ia_css_input_mode preview_pipe_input_mode;
unsigned int thread_id;
@@ -3705,7 +3537,6 @@ preview_start(struct ia_css_pipe *pipe)
copy_pipe = pipe->pipe_settings.preview.copy_pipe;
capture_pipe = pipe->pipe_settings.preview.capture_pipe;
- acc_pipe = pipe->pipe_settings.preview.acc_pipe;
sh_css_metrics_start_frame();
@@ -3764,22 +3595,6 @@ preview_start(struct ia_css_pipe *pipe)
(enum mipi_port_id)0);
}
- if (acc_pipe) {
- sh_css_sp_init_pipeline(&acc_pipe->pipeline,
- IA_CSS_PIPE_ID_ACC,
- (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
- false,
- pipe->stream->config.pixels_per_clock == 2,
- false, /* continuous */
- false, /* offline */
- pipe->required_bds_factor,
- 0,
- IA_CSS_INPUT_MODE_MEMORY,
- NULL,
- NULL,
- (enum mipi_port_id)0);
- }
-
start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -3850,9 +3665,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
pipeline = &pipe->pipeline;
- assert(pipeline ||
- pipe_id == IA_CSS_PIPE_ID_COPY ||
- pipe_id == IA_CSS_PIPE_ID_ACC);
+ assert(pipeline || pipe_id == IA_CSS_PIPE_ID_COPY);
assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr));
ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL);
@@ -4146,7 +3959,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
if (!frame->valid)
pipe->num_invalid_frames--;
- if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
+ if (frame->frame_info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
#ifdef ISP2401
frame->planes.binary.size = frame->data_bytes;
#else
@@ -4442,16 +4255,6 @@ ia_css_dequeue_isys_event(struct ia_css_event *event)
return err;
}
-static void
-acc_start(struct ia_css_pipe *pipe)
-{
- assert(pipe);
- assert(pipe->stream);
-
- start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
- pipe->stream->config.mode);
-}
-
static int
sh_css_pipe_start(struct ia_css_stream *stream)
{
@@ -4496,9 +4299,6 @@ sh_css_pipe_start(struct ia_css_stream *stream)
case IA_CSS_PIPE_ID_YUVPP:
err = yuvpp_start(pipe);
break;
- case IA_CSS_PIPE_ID_ACC:
- acc_start(pipe);
- break;
default:
err = -EINVAL;
}
@@ -4524,10 +4324,6 @@ sh_css_pipe_start(struct ia_css_stream *stream)
stream->pipes[i]->stop_requested = false;
err = yuvpp_start(stream->pipes[i]);
break;
- case IA_CSS_PIPE_ID_ACC:
- stream->pipes[i]->stop_requested = false;
- acc_start(stream->pipes[i]);
- break;
default:
err = -EINVAL;
}
@@ -4620,22 +4416,6 @@ sh_css_pipe_start(struct ia_css_stream *stream)
(uint8_t)thread_id, 0, 0);
}
- /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
- if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
- struct ia_css_pipe *acc_pipe = NULL;
-
- acc_pipe = pipe->pipe_settings.preview.acc_pipe;
-
- if (acc_pipe) {
- ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe),
- &thread_id);
- /* by the time we reach here q is initialized and handle is available.*/
- ia_css_bufq_enqueue_psys_event(
- IA_CSS_PSYS_SW_EVENT_START_STREAM,
- (uint8_t)thread_id, 0, 0);
- }
- }
-
stream->started = true;
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -6861,8 +6641,6 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
case IA_CSS_PIPE_ID_YUVPP:
err = load_yuvpp_binaries(pipe);
break;
- case IA_CSS_PIPE_ID_ACC:
- break;
default:
err = -EINVAL;
break;
@@ -7102,7 +6880,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
/* we use output port 1 as internal output port */
tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
- if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
+ if (tmp_vf_frame && (tmp_vf_frame->frame_info.res.width != 0)) {
in_frame = yuv_scaler_stage->args.out_vf_frame;
err = add_vf_pp_stage(pipe, in_frame,
tmp_vf_frame,
@@ -7118,7 +6896,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
}
}
} else if (copy_stage) {
- if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
+ if (vf_frame[0] && vf_frame[0]->frame_info.res.width != 0) {
in_frame = copy_stage->args.out_vf_frame;
err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
&vf_pp_binary[0], &vf_pp_stage);
@@ -7158,10 +6936,10 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
if (copy_on_sp(pipe) &&
pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
- ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
+ ia_css_frame_info_init(&out_frame->frame_info, JPEG_BYTES, 1,
IA_CSS_FRAME_FORMAT_BINARY_8, 0);
- } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
- out_frame->info.raw_bit_depth =
+ } else if (out_frame->frame_info.format == IA_CSS_FRAME_FORMAT_RAW) {
+ out_frame->frame_info.raw_bit_depth =
ia_css_pipe_util_pipe_input_format_bpp(pipe);
}
@@ -7200,7 +6978,7 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
ia_css_pipeline_clean(me);
/* Construct out_frame info */
- err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
+ err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->frame_info, 0);
if (err)
return err;
out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
@@ -7755,154 +7533,6 @@ ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
ia_css_inputfifo_end_frame(stream->config.channel_id);
}
-static void
-append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
-{
- IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
- if (!l) {
- IA_CSS_ERROR("NULL fw_info");
- IA_CSS_LEAVE_PRIVATE("");
- return;
- }
- while (*l)
- l = &(*l)->next;
- *l = firmware;
- /* when multiple acc extensions are loaded, 'next' can be not NULL */
- /*firmware->next = NULL;*/
- IA_CSS_LEAVE_PRIVATE("");
-}
-
-static void
-remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
-{
- assert(*l);
- assert(firmware);
- (void)l;
- (void)firmware;
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n");
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n");
- return; /* removing single and multiple firmware is handled in acc_unload_extension() */
-}
-
-static int upload_isp_code(struct ia_css_fw_info *firmware)
-{
- ia_css_ptr binary;
-
- if (!firmware) {
- IA_CSS_ERROR("NULL input parameter");
- return -EINVAL;
- }
- binary = firmware->info.isp.xmem_addr;
-
- if (!binary) {
- unsigned int size = firmware->blob.size;
- const unsigned char *blob;
- const unsigned char *binary_name;
-
- binary_name =
- (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME(
- firmware));
- blob = binary_name +
- strlen((const char *)binary_name) +
- 1;
- binary = sh_css_load_blob(blob, size);
- firmware->info.isp.xmem_addr = binary;
- }
-
- if (!binary)
- return -ENOMEM;
- return 0;
-}
-
-static int
-acc_load_extension(struct ia_css_fw_info *firmware)
-{
- int err;
- struct ia_css_fw_info *hd = firmware;
-
- while (hd) {
- err = upload_isp_code(hd);
- if (err)
- return err;
- hd = hd->next;
- }
-
- if (!firmware)
- return -EINVAL;
- firmware->loaded = true;
- return 0;
-}
-
-static void
-acc_unload_extension(struct ia_css_fw_info *firmware)
-{
- struct ia_css_fw_info *hd = firmware;
- struct ia_css_fw_info *hdn = NULL;
-
- if (!firmware) /* should not happen */
- return;
- /* unload and remove multiple firmwares */
- while (hd) {
- hdn = (hd->next) ? &(*hd->next) : NULL;
- if (hd->info.isp.xmem_addr) {
- hmm_free(hd->info.isp.xmem_addr);
- hd->info.isp.xmem_addr = mmgr_NULL;
- }
- hd->isp_code = NULL;
- hd->next = NULL;
- hd = hdn;
- }
-
- firmware->loaded = false;
-}
-
-/* Load firmware for extension */
-static int
-ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware)
-{
- int err = 0;
-
- IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
-
- if ((!firmware) || (!pipe)) {
- IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
- return -EINVAL;
- }
-
- if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
- append_firmware(&pipe->output_stage, firmware);
- else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
- append_firmware(&pipe->vf_stage, firmware);
- err = acc_load_extension(firmware);
-
- IA_CSS_LEAVE_ERR_PRIVATE(err);
- return err;
-}
-
-/* Unload firmware for extension */
-static void
-ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware)
-{
- IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
-
- if ((!firmware) || (!pipe)) {
- IA_CSS_ERROR("NULL input parameters");
- IA_CSS_LEAVE_PRIVATE("");
- return;
- }
-
- if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
- remove_firmware(&pipe->output_stage, firmware);
- else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
- remove_firmware(&pipe->vf_stage, firmware);
- acc_unload_extension(firmware);
-
- IA_CSS_LEAVE_PRIVATE("");
-}
-
bool
ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
{
@@ -7924,35 +7554,6 @@ ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
return false;
}
-static int
-sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
- const void *acc_fw)
-{
- struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
- /* In QoS case, load_extension already called, so skipping */
- int err = 0;
-
- if (!fw->loaded)
- err = acc_load_extension(fw);
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
- pipeline, acc_fw);
-
- if (!err) {
- struct ia_css_pipeline_stage_desc stage_desc;
-
- ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
- err = ia_css_pipeline_create_and_add_stage(pipeline,
- &stage_desc,
- NULL);
- }
-
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
- "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err);
- return err;
-}
-
/*
* @brief Tag a specific frame in continuous capture.
* Refer to "sh_css_internal.h" for details.
@@ -8177,26 +7778,6 @@ void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
stream_config->source.port.rxcount = 0x04040404;
}
-static int
-ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
-{
- int err = 0;
-
- if (!pipe) {
- IA_CSS_ERROR("NULL input parameter");
- return -EINVAL;
- }
-
- /* There is not meaning for num_execs = 0 semantically. Run at least once. */
- if (pipe->config.acc_num_execs == 0)
- pipe->config.acc_num_execs = 1;
-
- if (pipe->config.acc_extension)
- err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
-
- return err;
-}
-
int ia_css_pipe_create(const struct ia_css_pipe_config *config,
struct ia_css_pipe **pipe)
{
@@ -8257,23 +7838,6 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
else
ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
- if (config->mode == IA_CSS_PIPE_MODE_ACC) {
- /*
- * Temporary hack to migrate acceleration to CSS 2.0.
- * In the future the code for all pipe types should be
- * unified.
- */
- *pipe = internal_pipe;
- if (!internal_pipe->config.acc_extension &&
- internal_pipe->config.num_acc_stages ==
- 0) { /* if no acc binary and no standalone stage */
- *pipe = NULL;
- IA_CSS_LEAVE_ERR_PRIVATE(0);
- return 0;
- }
- return ia_css_acc_pipe_create(internal_pipe);
- }
-
/*
* Use config value when dvs_frame_delay setting equal to 2,
* otherwise always 1 by default
@@ -8368,15 +7932,6 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
}
}
}
- if (internal_pipe->config.acc_extension) {
- err = ia_css_pipe_load_extension(internal_pipe,
- internal_pipe->config.acc_extension);
- if (err) {
- IA_CSS_LEAVE_ERR_PRIVATE(err);
- kvfree(internal_pipe);
- return err;
- }
- }
/* set all info to zeroes first */
memset(&internal_pipe->info, 0, sizeof(internal_pipe->info));
@@ -8525,57 +8080,6 @@ find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
}
static int
-ia_css_acc_stream_create(struct ia_css_stream *stream)
-{
- int i;
- int err = 0;
-
- IA_CSS_ENTER_PRIVATE("stream = %p", stream);
-
- if (!stream) {
- IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
- return -EINVAL;
- }
-
- for (i = 0; i < stream->num_pipes; i++) {
- struct ia_css_pipe *pipe = stream->pipes[i];
-
- if (!pipe) {
- IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
- return -EINVAL;
- }
-
- pipe->stream = stream;
- }
-
- /* Map SP threads before doing anything. */
- err = map_sp_threads(stream, true);
- if (err) {
- IA_CSS_LEAVE_ERR_PRIVATE(err);
- return err;
- }
-
- for (i = 0; i < stream->num_pipes; i++) {
- struct ia_css_pipe *pipe = stream->pipes[i];
-
- assert(pipe);
- ia_css_pipe_map_queue(pipe, true);
- }
-
- err = create_host_pipeline_structure(stream);
- if (err) {
- IA_CSS_LEAVE_ERR_PRIVATE(err);
- return err;
- }
-
- stream->started = false;
-
- IA_CSS_LEAVE_ERR_PRIVATE(0);
-
- return 0;
-}
-
-static int
metadata_info_init(const struct ia_css_metadata_config *mdc,
struct ia_css_metadata_info *md)
{
@@ -8807,11 +8311,6 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
goto ERR;
IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
- if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
- *stream = curr_stream;
- err = ia_css_acc_stream_create(curr_stream);
- goto ERR;
- }
/* sensor binning */
if (!spcopyonly) {
sensor_binning_changed =
@@ -8832,7 +8331,6 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* Search for the preview pipe and create the copy pipe */
struct ia_css_pipe *preview_pipe;
struct ia_css_pipe *video_pipe;
- struct ia_css_pipe *acc_pipe;
struct ia_css_pipe *capture_pipe = NULL;
struct ia_css_pipe *copy_pipe = NULL;
@@ -8847,11 +8345,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
IA_CSS_PIPE_MODE_PREVIEW, false);
video_pipe = find_pipe(pipes, num_pipes,
IA_CSS_PIPE_MODE_VIDEO, false);
- acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
- false);
- if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
- curr_stream->cont_capt =
- false; /* preview + QoS case will not need cont_capt switch */
+
if (curr_stream->cont_capt) {
capture_pipe = find_pipe(pipes, num_pipes,
IA_CSS_PIPE_MODE_CAPTURE,
@@ -8888,9 +8382,6 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
}
if (video_pipe && curr_stream->cont_capt)
video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
-
- if (preview_pipe && acc_pipe)
- preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
}
for (i = 0; i < num_pipes; i++) {
curr_pipe = pipes[i];
@@ -9738,13 +9229,6 @@ void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
if (!pipe->stream->config.continuous)
ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
- } else if (pipe->mode == IA_CSS_PIPE_ID_ACC) {
- if (need_input_queue)
- ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
- ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
- ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
- ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
- ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
} else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) {
unsigned int idx;
@@ -9795,92 +9279,6 @@ ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
return ret;
}
-/*
- * @brief Set the state (Enable or Disable) of the Extension stage in the
- * given pipe.
- */
-int
-ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
- bool enable)
-{
- unsigned int thread_id;
- struct ia_css_pipeline_stage *stage;
- int err = 0;
-
- IA_CSS_ENTER("");
-
- /* Parameter Check */
- if (!pipe || !pipe->stream) {
- IA_CSS_ERROR("Invalid Pipe.");
- err = -EINVAL;
- } else if (!(pipe->config.acc_extension)) {
- IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
- err = -EINVAL;
- } else if (!sh_css_sp_is_running()) {
- IA_CSS_ERROR("Leaving: queue unavailable.");
- err = -EBUSY;
- } else {
- /* Query the threadid and stage_num for the Extension firmware*/
- ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
- err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
- if (!err) {
- /* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/
- err = ia_css_bufq_enqueue_psys_event(
- (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE,
- (uint8_t)thread_id,
- (uint8_t)stage->stage_num,
- enable ? 1 : 0);
- if (!err) {
- if (enable)
- SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
- else
- SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
- }
- }
- }
- IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable);
- return err;
-}
-
-/*
- * @brief Get the state (Enable or Disable) of the Extension stage in the
- * given pipe.
- */
-int
-ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
- bool *enable)
-{
- struct ia_css_pipeline_stage *stage;
- unsigned int thread_id;
- int err = 0;
-
- IA_CSS_ENTER("");
-
- /* Parameter Check */
- if (!pipe || !pipe->stream) {
- IA_CSS_ERROR("Invalid Pipe.");
- err = -EINVAL;
- } else if (!(pipe->config.acc_extension)) {
- IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
- err = -EINVAL;
- } else if (!sh_css_sp_is_running()) {
- IA_CSS_ERROR("Leaving: queue unavailable.");
- err = -EBUSY;
- } else {
- /* Query the threadid and stage_num corresponding to the Extension firmware*/
- ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
- err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
-
- if (!err) {
- /* Get the Extension State */
- *enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
- stage->stage_num)) ? true : false;
- }
- }
- IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable);
- return err;
-}
-
static void
sh_css_hmm_buffer_record_init(void)
{
diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h
index 435b3cedd1c3..d98f1323441e 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_internal.h
+++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h
@@ -488,16 +488,6 @@ ia_css_metadata_free_multiple(unsigned int num_bufs,
/* Macro for handling pipe_qos_config */
#define QOS_INVALID (~0U)
-#define QOS_ALL_STAGES_DISABLED (0U)
-#define QOS_STAGE_MASK(num) (0x00000001 << num)
-#define SH_CSS_IS_QOS_PIPE(pipe) ((pipe)->pipe_qos_config != QOS_INVALID)
-#define SH_CSS_QOS_STAGE_ENABLE(pipe, num) ((pipe)->pipe_qos_config |= QOS_STAGE_MASK(num))
-#define SH_CSS_QOS_STAGE_DISABLE(pipe, num) ((pipe)->pipe_qos_config &= ~QOS_STAGE_MASK(num))
-#define SH_CSS_QOS_STAGE_IS_ENABLED(pipe, num) ((pipe)->pipe_qos_config & QOS_STAGE_MASK(num))
-#define SH_CSS_QOS_STAGE_IS_ALL_DISABLED(pipe) ((pipe)->pipe_qos_config == QOS_ALL_STAGES_DISABLED)
-#define SH_CSS_QOS_MODE_PIPE_ADD(mode, pipe) ((mode) |= (0x1 << (pipe)->pipe_id))
-#define SH_CSS_QOS_MODE_PIPE_REMOVE(mode, pipe) ((mode) &= ~(0x1 << (pipe)->pipe_id))
-#define SH_CSS_IS_QOS_ONLY_MODE(mode) ((mode) == (0x1 << IA_CSS_PIPE_ID_ACC))
/* Information for a pipeline */
struct sh_css_sp_pipeline {
@@ -907,9 +897,6 @@ sh_css_params_init(void);
void
sh_css_params_uninit(void);
-/* For Acceleration API: Flush FW (shared buffer pointer) arguments */
-void sh_css_flush(struct ia_css_acc_fw *fw);
-
void
sh_css_binary_args_reset(struct sh_css_binary_args *args);
diff --git a/drivers/staging/media/atomisp/pci/sh_css_legacy.h b/drivers/staging/media/atomisp/pci/sh_css_legacy.h
index 567c8d6dcc2c..cdf239b070a8 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_legacy.h
+++ b/drivers/staging/media/atomisp/pci/sh_css_legacy.h
@@ -32,7 +32,6 @@ enum ia_css_pipe_id {
IA_CSS_PIPE_ID_VIDEO,
IA_CSS_PIPE_ID_CAPTURE,
IA_CSS_PIPE_ID_YUVPP,
- IA_CSS_PIPE_ID_ACC,
IA_CSS_PIPE_ID_NUM
};
diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_shading.c b/drivers/staging/media/atomisp/pci/sh_css_param_shading.c
index 41a4c9162319..5b43cc656269 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_param_shading.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_param_shading.c
@@ -13,6 +13,7 @@
* more details.
*/
+#include <linux/math.h>
#include <linux/slab.h>
#include <math_support.h>
@@ -239,10 +240,9 @@ prepare_shading_table(const struct ia_css_shading_table *in_table,
{
unsigned int input_width, input_height, table_width, table_height, i;
unsigned int left_padding, top_padding, left_cropping;
- unsigned int bds_numerator, bds_denominator;
- int right_padding;
-
struct ia_css_shading_table *result;
+ struct u32_fract bds;
+ int right_padding;
assert(target_table);
assert(binary);
@@ -265,17 +265,16 @@ prepare_shading_table(const struct ia_css_shading_table *in_table,
left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ?
binary->dvs_envelope.width : 2 * ISP_VEC_NELEMS;
- sh_css_bds_factor_get_numerator_denominator
- (bds_factor, &bds_numerator, &bds_denominator);
+ sh_css_bds_factor_get_fract(bds_factor, &bds);
left_padding = (left_padding + binary->info->sp.pipeline.left_cropping) *
- bds_numerator / bds_denominator -
+ bds.numerator / bds.denominator -
binary->info->sp.pipeline.left_cropping;
right_padding = (binary->internal_frame_info.res.width -
- binary->effective_in_frame_res.width * bds_denominator /
- bds_numerator - left_cropping) * bds_numerator / bds_denominator;
- top_padding = binary->info->sp.pipeline.top_cropping * bds_numerator /
- bds_denominator -
+ binary->effective_in_frame_res.width * bds.denominator /
+ bds.numerator - left_cropping) * bds.numerator / bds.denominator;
+ top_padding = binary->info->sp.pipeline.top_cropping * bds.numerator /
+ bds.denominator -
binary->info->sp.pipeline.top_cropping;
/*
diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c
index 67915d76a87f..f08564f58242 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_params.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_params.c
@@ -936,8 +936,8 @@ sh_css_set_black_frame(struct ia_css_stream *stream,
assert(raw_black_frame);
params = stream->isp_params_configs;
- height = raw_black_frame->info.res.height;
- width = raw_black_frame->info.padded_width;
+ height = raw_black_frame->frame_info.res.height;
+ width = raw_black_frame->frame_info.padded_width;
ptr = raw_black_frame->data
+ raw_black_frame->planes.raw.offset;
@@ -1187,16 +1187,15 @@ ia_css_process_zoom_and_motion(
const struct sh_css_binary_args *args = &stage->args;
const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
- if (args->out_frame[0])
- out_infos[0] = &args->out_frame[0]->info;
+ out_infos[0] = ia_css_frame_get_info(args->out_frame[0]);
+
info = &stage->firmware->info.isp;
ia_css_binary_fill_info(info, false, false,
ATOMISP_INPUT_FORMAT_RAW_10,
- args->in_frame ? &args->in_frame->info : NULL,
+ ia_css_frame_get_info(args->in_frame),
NULL,
out_infos,
- args->out_vf_frame ? &args->out_vf_frame->info
- : NULL,
+ ia_css_frame_get_info(args->out_vf_frame),
&tmp_binary,
NULL,
-1, true);
@@ -3461,10 +3460,10 @@ sh_css_params_write_to_ddr_internal(
if (stage->args.delay_frames[0]) {
/*When delay frames are present(as in case of video),
they are used for dvs. Configure DVS using those params*/
- dvs_in_frame_info = &stage->args.delay_frames[0]->info;
+ dvs_in_frame_info = &stage->args.delay_frames[0]->frame_info;
} else {
/*Otherwise, use input frame to configure DVS*/
- dvs_in_frame_info = &stage->args.in_frame->info;
+ dvs_in_frame_info = &stage->args.in_frame->frame_info;
}
/* Generate default DVS unity table on start up*/
diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c
index 615500a7d3c4..0dd58a7fe2cc 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_sp.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c
@@ -277,10 +277,10 @@ sh_css_sp_start_raw_copy(struct ia_css_frame *out_frame,
ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
pipe = &sh_css_sp_group.pipe[thread_id];
- pipe->copy.raw.height = out_frame->info.res.height;
- pipe->copy.raw.width = out_frame->info.res.width;
- pipe->copy.raw.padded_width = out_frame->info.padded_width;
- pipe->copy.raw.raw_bit_depth = out_frame->info.raw_bit_depth;
+ pipe->copy.raw.height = out_frame->frame_info.res.height;
+ pipe->copy.raw.width = out_frame->frame_info.res.width;
+ pipe->copy.raw.padded_width = out_frame->frame_info.padded_width;
+ pipe->copy.raw.raw_bit_depth = out_frame->frame_info.raw_bit_depth;
pipe->copy.raw.max_input_width = max_input_width;
pipe->num_stages = 1;
pipe->pipe_id = pipe_id;
@@ -351,10 +351,10 @@ sh_css_sp_start_isys_copy(struct ia_css_frame *out_frame,
ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
pipe = &sh_css_sp_group.pipe[thread_id];
- pipe->copy.raw.height = out_frame->info.res.height;
- pipe->copy.raw.width = out_frame->info.res.width;
- pipe->copy.raw.padded_width = out_frame->info.padded_width;
- pipe->copy.raw.raw_bit_depth = out_frame->info.raw_bit_depth;
+ pipe->copy.raw.height = out_frame->frame_info.res.height;
+ pipe->copy.raw.width = out_frame->frame_info.res.width;
+ pipe->copy.raw.padded_width = out_frame->frame_info.padded_width;
+ pipe->copy.raw.raw_bit_depth = out_frame->frame_info.raw_bit_depth;
pipe->copy.raw.max_input_width = max_input_width;
pipe->num_stages = 1;
pipe->pipe_id = pipe_id;
@@ -451,9 +451,9 @@ sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out,
frame_in->data,
frame_in->buf_type);
- ia_css_frame_info_to_frame_sp_info(&sp_frame_out->info, &frame_in->info);
+ ia_css_frame_info_to_frame_sp_info(&sp_frame_out->info, &frame_in->frame_info);
- switch (frame_in->info.format) {
+ switch (frame_in->frame_info.format) {
case IA_CSS_FRAME_FORMAT_RAW_PACKED:
case IA_CSS_FRAME_FORMAT_RAW:
sp_frame_out->planes.raw.offset = frame_in->planes.raw.offset;
@@ -536,7 +536,7 @@ set_input_frame_buffer(const struct ia_css_frame *frame)
if (!frame)
return -EINVAL;
- switch (frame->info.format) {
+ switch (frame->frame_info.format) {
case IA_CSS_FRAME_FORMAT_QPLANE6:
case IA_CSS_FRAME_FORMAT_YUV420_16:
case IA_CSS_FRAME_FORMAT_RAW_PACKED:
@@ -567,7 +567,7 @@ set_output_frame_buffer(const struct ia_css_frame *frame,
if (!frame)
return -EINVAL;
- switch (frame->info.format) {
+ switch (frame->frame_info.format) {
case IA_CSS_FRAME_FORMAT_YUV420:
case IA_CSS_FRAME_FORMAT_YUV422:
case IA_CSS_FRAME_FORMAT_YUV444:
@@ -608,7 +608,7 @@ set_view_finder_buffer(const struct ia_css_frame *frame)
if (!frame)
return -EINVAL;
- switch (frame->info.format) {
+ switch (frame->frame_info.format) {
/* the dual output pin */
case IA_CSS_FRAME_FORMAT_NV12:
case IA_CSS_FRAME_FORMAT_NV12_16:
@@ -819,34 +819,35 @@ static int configure_isp_from_args(const struct sh_css_sp_pipeline *pipeline,
ret = ia_css_fpn_configure(binary, &binary->in_frame_info);
if (ret)
return ret;
- ret = ia_css_crop_configure(binary, &args->delay_frames[0]->info);
+ ret = ia_css_crop_configure(binary, ia_css_frame_get_info(args->delay_frames[0]));
if (ret)
return ret;
ret = ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info);
if (ret)
return ret;
- ret = ia_css_output0_configure(binary, &args->out_frame[0]->info);
+ ret = ia_css_output0_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
if (ret)
return ret;
- ret = ia_css_output1_configure(binary, &args->out_vf_frame->info);
+ ret = ia_css_output1_configure(binary, ia_css_frame_get_info(args->out_vf_frame));
if (ret)
return ret;
ret = ia_css_copy_output_configure(binary, args->copy_output);
if (ret)
return ret;
- ret = ia_css_output0_configure(binary, &args->out_frame[0]->info);
+ ret = ia_css_output0_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
if (ret)
return ret;
- ret = ia_css_iterator_configure(binary, &args->in_frame->info);
+ ret = ia_css_iterator_configure(binary, ia_css_frame_get_info(args->in_frame));
if (ret)
return ret;
- ret = ia_css_dvs_configure(binary, &args->out_frame[0]->info);
+ ret = ia_css_dvs_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
if (ret)
return ret;
- ret = ia_css_output_configure(binary, &args->out_frame[0]->info);
+ ret = ia_css_output_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
if (ret)
return ret;
- ret = ia_css_raw_configure(pipeline, binary, &args->in_frame->info, &binary->in_frame_info, two_ppc, deinterleaved);
+ ret = ia_css_raw_configure(pipeline, binary, ia_css_frame_get_info(args->in_frame),
+ &binary->in_frame_info, two_ppc, deinterleaved);
if (ret)
return ret;
@@ -1037,7 +1038,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary,
return -EINVAL;
if (args->in_frame)
- ia_css_get_crop_offsets(pipe, &args->in_frame->info);
+ ia_css_get_crop_offsets(pipe, &args->in_frame->frame_info);
else
ia_css_get_crop_offsets(pipe, &binary->in_frame_info);
#else
@@ -1124,15 +1125,14 @@ sp_init_stage(struct ia_css_pipeline_stage *stage,
const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
if (args->out_frame[0])
- out_infos[0] = &args->out_frame[0]->info;
+ out_infos[0] = &args->out_frame[0]->frame_info;
info = &firmware->info.isp;
ia_css_binary_fill_info(info, false, false,
ATOMISP_INPUT_FORMAT_RAW_10,
- args->in_frame ? &args->in_frame->info : NULL,
+ ia_css_frame_get_info(args->in_frame),
NULL,
out_infos,
- args->out_vf_frame ? &args->out_vf_frame->info
- : NULL,
+ ia_css_frame_get_info(args->out_vf_frame),
&tmp_binary,
NULL,
-1, true);
@@ -1266,7 +1266,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me,
sh_css_sp_group.pipe[thread_id].thread_id = thread_id;
sh_css_sp_group.pipe[thread_id].pipe_num = pipe_num;
sh_css_sp_group.pipe[thread_id].num_execs = me->num_execs;
- sh_css_sp_group.pipe[thread_id].pipe_qos_config = me->pipe_qos_config;
+ sh_css_sp_group.pipe[thread_id].pipe_qos_config = QOS_INVALID;
sh_css_sp_group.pipe[thread_id].required_bds_factor = required_bds_factor;
sh_css_sp_group.pipe[thread_id].input_system_mode
= (uint32_t)input_mode;
diff --git a/drivers/staging/media/deprecated/atmel/Kconfig b/drivers/staging/media/deprecated/atmel/Kconfig
new file mode 100644
index 000000000000..418841ea5a0d
--- /dev/null
+++ b/drivers/staging/media/deprecated/atmel/Kconfig
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Atmel media platform drivers"
+
+config VIDEO_ATMEL_ISC
+ tristate "ATMEL Image Sensor Controller (ISC) support (DEPRECATED)"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && COMMON_CLK
+ depends on ARCH_AT91 || COMPILE_TEST
+ depends on !VIDEO_MICROCHIP_ISC_BASE || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP_MMIO
+ select V4L2_FWNODE
+ select VIDEO_ATMEL_ISC_BASE
+ help
+ This module makes the ATMEL Image Sensor Controller available
+ as a v4l2 device.
+
+ This driver is deprecated and is scheduled for removal by
+ the beginning of 2026. See the TODO file for more information.
+
+config VIDEO_ATMEL_XISC
+ tristate "ATMEL eXtended Image Sensor Controller (XISC) support (DEPRECATED)"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && COMMON_CLK
+ depends on ARCH_AT91 || COMPILE_TEST
+ depends on !VIDEO_MICROCHIP_ISC_BASE || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP_MMIO
+ select V4L2_FWNODE
+ select VIDEO_ATMEL_ISC_BASE
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This module makes the ATMEL eXtended Image Sensor Controller
+ available as a v4l2 device.
+
+ This driver is deprecated and is scheduled for removal by
+ the beginning of 2026. See the TODO file for more information.
+
+config VIDEO_ATMEL_ISC_BASE
+ tristate
+ default n
+ help
+ ATMEL ISC and XISC common code base.
diff --git a/drivers/staging/media/deprecated/atmel/Makefile b/drivers/staging/media/deprecated/atmel/Makefile
new file mode 100644
index 000000000000..34eaeeac5bba
--- /dev/null
+++ b/drivers/staging/media/deprecated/atmel/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+atmel-isc-objs = atmel-sama5d2-isc.o
+atmel-xisc-objs = atmel-sama7g5-isc.o
+atmel-isc-common-objs = atmel-isc-base.o atmel-isc-clk.o
+
+obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += atmel-isc-common.o
+obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
+obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
diff --git a/drivers/staging/media/deprecated/atmel/TODO b/drivers/staging/media/deprecated/atmel/TODO
new file mode 100644
index 000000000000..71691df07a80
--- /dev/null
+++ b/drivers/staging/media/deprecated/atmel/TODO
@@ -0,0 +1,34 @@
+The Atmel ISC driver is not compliant with media controller specification.
+In order to evolve this driver, it has to move to media controller, to
+support enhanced features and future products which embed it.
+The move to media controller involves several changes which are
+not backwards compatible with the current usability of the driver.
+
+The best example is the way the format is propagated from the top video
+driver /dev/videoX down to the sensor.
+
+In a simple configuration sensor ==> isc , the isc just calls subdev s_fmt
+and controls the sensor directly. This is achieved by having a lot of code
+inside the driver that will query the subdev at probe time and make a list
+of formats which are usable.
+Basically the user has nothing to configure, as the isc will handle
+everything at the top level. This is an easy way to capture, but also comes
+with the drawback of lack of flexibility.
+In a more complicated pipeline
+sensor ==> controller 1 ==> controller 2 ==> isc
+this will not be achievable, as controller 1 and controller 2 might be
+media-controller configurable, and will not propagate the formats down to
+the sensor.
+
+After discussions with the media maintainers, the decision is to move
+Atmel ISC to staging as-is, to keep the Kconfig symbols and the users
+to the driver in staging. Thus, all the existing users of the non
+media-controller paradigm will continue to be happy and use the old config
+way.
+
+The new driver was added in the media subsystem with a different
+symbol, with the conversion to media controller done, and new users
+of the driver will be able to use all the new features.
+
+The replacement driver is named VIDEO_MICROCHIP_ISC or
+VIDEO_MICROCHIP_XISC depending on the product flavor.
diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
index 9e5317a7d516..99e61bbfc9bc 100644
--- a/drivers/media/platform/atmel/atmel-isc-base.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
@@ -1221,7 +1221,7 @@ static const struct v4l2_file_operations isc_fops = {
.poll = vb2_fop_poll,
};
-irqreturn_t isc_interrupt(int irq, void *dev_id)
+irqreturn_t atmel_isc_interrupt(int irq, void *dev_id)
{
struct isc_device *isc = (struct isc_device *)dev_id;
struct regmap *regmap = isc->regmap;
@@ -1267,7 +1267,7 @@ irqreturn_t isc_interrupt(int irq, void *dev_id)
return ret;
}
-EXPORT_SYMBOL_GPL(isc_interrupt);
+EXPORT_SYMBOL_GPL(atmel_isc_interrupt);
static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
{
@@ -1934,14 +1934,14 @@ isc_async_complete_err:
return ret;
}
-const struct v4l2_async_notifier_operations isc_async_ops = {
+const struct v4l2_async_notifier_operations atmel_isc_async_ops = {
.bound = isc_async_bound,
.unbind = isc_async_unbind,
.complete = isc_async_complete,
};
-EXPORT_SYMBOL_GPL(isc_async_ops);
+EXPORT_SYMBOL_GPL(atmel_isc_async_ops);
-void isc_subdev_cleanup(struct isc_device *isc)
+void atmel_isc_subdev_cleanup(struct isc_device *isc)
{
struct isc_subdev_entity *subdev_entity;
@@ -1952,9 +1952,9 @@ void isc_subdev_cleanup(struct isc_device *isc)
INIT_LIST_HEAD(&isc->subdev_entities);
}
-EXPORT_SYMBOL_GPL(isc_subdev_cleanup);
+EXPORT_SYMBOL_GPL(atmel_isc_subdev_cleanup);
-int isc_pipeline_init(struct isc_device *isc)
+int atmel_isc_pipeline_init(struct isc_device *isc)
{
struct device *dev = isc->dev;
struct regmap *regmap = isc->regmap;
@@ -1993,17 +1993,17 @@ int isc_pipeline_init(struct isc_device *isc)
return 0;
}
-EXPORT_SYMBOL_GPL(isc_pipeline_init);
+EXPORT_SYMBOL_GPL(atmel_isc_pipeline_init);
/* regmap configuration */
#define ATMEL_ISC_REG_MAX 0xd5c
-const struct regmap_config isc_regmap_config = {
+const struct regmap_config atmel_isc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = ATMEL_ISC_REG_MAX,
};
-EXPORT_SYMBOL_GPL(isc_regmap_config);
+EXPORT_SYMBOL_GPL(atmel_isc_regmap_config);
MODULE_AUTHOR("Songjun Wu");
MODULE_AUTHOR("Eugen Hristev");
diff --git a/drivers/media/platform/atmel/atmel-isc-clk.c b/drivers/staging/media/deprecated/atmel/atmel-isc-clk.c
index 2059fe376b00..d442b5f4c931 100644
--- a/drivers/media/platform/atmel/atmel-isc-clk.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc-clk.c
@@ -277,7 +277,7 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id)
return 0;
}
-int isc_clk_init(struct isc_device *isc)
+int atmel_isc_clk_init(struct isc_device *isc)
{
unsigned int i;
int ret;
@@ -293,9 +293,9 @@ int isc_clk_init(struct isc_device *isc)
return 0;
}
-EXPORT_SYMBOL_GPL(isc_clk_init);
+EXPORT_SYMBOL_GPL(atmel_isc_clk_init);
-void isc_clk_cleanup(struct isc_device *isc)
+void atmel_isc_clk_cleanup(struct isc_device *isc)
{
unsigned int i;
@@ -308,4 +308,4 @@ void isc_clk_cleanup(struct isc_device *isc)
clk_unregister(isc_clk->clk);
}
}
-EXPORT_SYMBOL_GPL(isc_clk_cleanup);
+EXPORT_SYMBOL_GPL(atmel_isc_clk_cleanup);
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/staging/media/deprecated/atmel/atmel-isc-regs.h
index d06b72228d4f..d06b72228d4f 100644
--- a/drivers/media/platform/atmel/atmel-isc-regs.h
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc-regs.h
diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/staging/media/deprecated/atmel/atmel-isc.h
index ff60ba020cb9..dfc030b5a08f 100644
--- a/drivers/media/platform/atmel/atmel-isc.h
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc.h
@@ -350,13 +350,13 @@ struct isc_device {
u32 formats_list_size;
};
-extern const struct regmap_config isc_regmap_config;
-extern const struct v4l2_async_notifier_operations isc_async_ops;
-
-irqreturn_t isc_interrupt(int irq, void *dev_id);
-int isc_pipeline_init(struct isc_device *isc);
-int isc_clk_init(struct isc_device *isc);
-void isc_subdev_cleanup(struct isc_device *isc);
-void isc_clk_cleanup(struct isc_device *isc);
+extern const struct regmap_config atmel_isc_regmap_config;
+extern const struct v4l2_async_notifier_operations atmel_isc_async_ops;
+
+irqreturn_t atmel_isc_interrupt(int irq, void *dev_id);
+int atmel_isc_pipeline_init(struct isc_device *isc);
+int atmel_isc_clk_init(struct isc_device *isc);
+void atmel_isc_subdev_cleanup(struct isc_device *isc);
+void atmel_isc_clk_cleanup(struct isc_device *isc);
#endif
diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
index 9881d89a645b..ba0614f981a2 100644
--- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
@@ -408,7 +408,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
if (IS_ERR(io_base))
return PTR_ERR(io_base);
- isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
+ isc->regmap = devm_regmap_init_mmio(dev, io_base, &atmel_isc_regmap_config);
if (IS_ERR(isc->regmap)) {
ret = PTR_ERR(isc->regmap);
dev_err(dev, "failed to init register map: %d\n", ret);
@@ -419,7 +419,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, isc_interrupt, 0,
+ ret = devm_request_irq(dev, irq, atmel_isc_interrupt, 0,
"atmel-sama5d2-isc", isc);
if (ret < 0) {
dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
@@ -464,7 +464,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
/* sama5d2-isc : ISPCK is required and mandatory */
isc->ispck_required = true;
- ret = isc_pipeline_init(isc);
+ ret = atmel_isc_pipeline_init(isc);
if (ret)
return ret;
@@ -481,7 +481,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
return ret;
}
- ret = isc_clk_init(isc);
+ ret = atmel_isc_clk_init(isc);
if (ret) {
dev_err(dev, "failed to init isc clock: %d\n", ret);
goto unprepare_hclk;
@@ -523,7 +523,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
goto cleanup_subdev;
}
- subdev_entity->notifier.ops = &isc_async_ops;
+ subdev_entity->notifier.ops = &atmel_isc_async_ops;
ret = v4l2_async_nf_register(&isc->v4l2_dev,
&subdev_entity->notifier);
@@ -567,7 +567,7 @@ disable_pm:
pm_runtime_disable(dev);
cleanup_subdev:
- isc_subdev_cleanup(isc);
+ atmel_isc_subdev_cleanup(isc);
unregister_v4l2_device:
v4l2_device_unregister(&isc->v4l2_dev);
@@ -575,7 +575,7 @@ unregister_v4l2_device:
unprepare_hclk:
clk_disable_unprepare(isc->hclock);
- isc_clk_cleanup(isc);
+ atmel_isc_clk_cleanup(isc);
return ret;
}
@@ -586,14 +586,14 @@ static int atmel_isc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
- isc_subdev_cleanup(isc);
+ atmel_isc_subdev_cleanup(isc);
v4l2_device_unregister(&isc->v4l2_dev);
clk_disable_unprepare(isc->ispck);
clk_disable_unprepare(isc->hclock);
- isc_clk_cleanup(isc);
+ atmel_isc_clk_cleanup(isc);
return 0;
}
diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
index 8b11aa8340d7..01ababdfcbd9 100644
--- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
@@ -397,7 +397,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
if (IS_ERR(io_base))
return PTR_ERR(io_base);
- isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
+ isc->regmap = devm_regmap_init_mmio(dev, io_base, &atmel_isc_regmap_config);
if (IS_ERR(isc->regmap)) {
ret = PTR_ERR(isc->regmap);
dev_err(dev, "failed to init register map: %d\n", ret);
@@ -408,7 +408,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, isc_interrupt, 0,
+ ret = devm_request_irq(dev, irq, atmel_isc_interrupt, 0,
"microchip-sama7g5-xisc", isc);
if (ret < 0) {
dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
@@ -453,7 +453,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
/* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
isc->ispck_required = false;
- ret = isc_pipeline_init(isc);
+ ret = atmel_isc_pipeline_init(isc);
if (ret)
return ret;
@@ -470,7 +470,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
return ret;
}
- ret = isc_clk_init(isc);
+ ret = atmel_isc_clk_init(isc);
if (ret) {
dev_err(dev, "failed to init isc clock: %d\n", ret);
goto unprepare_hclk;
@@ -513,7 +513,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
goto cleanup_subdev;
}
- subdev_entity->notifier.ops = &isc_async_ops;
+ subdev_entity->notifier.ops = &atmel_isc_async_ops;
ret = v4l2_async_nf_register(&isc->v4l2_dev,
&subdev_entity->notifier);
@@ -536,7 +536,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
return 0;
cleanup_subdev:
- isc_subdev_cleanup(isc);
+ atmel_isc_subdev_cleanup(isc);
unregister_v4l2_device:
v4l2_device_unregister(&isc->v4l2_dev);
@@ -544,7 +544,7 @@ unregister_v4l2_device:
unprepare_hclk:
clk_disable_unprepare(isc->hclock);
- isc_clk_cleanup(isc);
+ atmel_isc_clk_cleanup(isc);
return ret;
}
@@ -555,13 +555,13 @@ static int microchip_xisc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
- isc_subdev_cleanup(isc);
+ atmel_isc_subdev_cleanup(isc);
v4l2_device_unregister(&isc->v4l2_dev);
clk_disable_unprepare(isc->hclock);
- isc_clk_cleanup(isc);
+ atmel_isc_clk_cleanup(isc);
return 0;
}
diff --git a/drivers/staging/media/deprecated/stkwebcam/Kconfig b/drivers/staging/media/deprecated/stkwebcam/Kconfig
index 4450403dff41..7234498e634a 100644
--- a/drivers/staging/media/deprecated/stkwebcam/Kconfig
+++ b/drivers/staging/media/deprecated/stkwebcam/Kconfig
@@ -2,7 +2,7 @@
config VIDEO_STKWEBCAM
tristate "USB Syntek DC1125 Camera support (DEPRECATED)"
depends on VIDEO_DEV
- depends on USB
+ depends on MEDIA_USB_SUPPORT && MEDIA_CAMERA_SUPPORT
help
Say Y here if you want to use this type of camera.
Supported devices are typically found in some Asus laptops,
diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index 0bacac302d7e..21fd79515042 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -23,12 +23,15 @@ config VIDEO_IMX_CSI
default y
help
A video4linux camera sensor interface driver for i.MX5/6.
-
-config VIDEO_IMX7_CSI
- tristate "i.MX6UL/L / i.MX7 / i.MX8M Camera Sensor Interface driver"
- default y
- help
- Enable support for video4linux camera sensor interface driver for
- i.MX6UL/L, i.MX7 or i.MX8M.
endmenu
endif
+
+config VIDEO_IMX8MQ_MIPI_CSI2
+ tristate "NXP i.MX8MQ MIPI CSI-2 receiver"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ V4L2 driver for the MIPI CSI-2 receiver found in the i.MX8MQ SoC.
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index d82be898145b..906a422aa656 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -14,5 +14,4 @@ obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
-obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
-obj-$(CONFIG_VIDEO_IMX7_CSI) += imx8mq-mipi-csi2.o
+obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO
index 5d3a337c8702..11c9e10d34ae 100644
--- a/drivers/staging/media/imx/TODO
+++ b/drivers/staging/media/imx/TODO
@@ -2,18 +2,6 @@
- The Frame Interval Monitor could be exported to v4l2-core for
general use.
-- The CSI subdevice parses its nearest upstream neighbor's device-tree
- bus config in order to setup the CSI. Laurent Pinchart argues that
- instead the CSI subdev should call its neighbor's g_mbus_config op
- (which should be propagated if necessary) to get this info. However
- Hans Verkuil is planning to remove the g_mbus_config op. For now this
- driver uses the parsed DT bus config method until this issue is
- resolved.
-
- 2020-06: g_mbus has been removed in favour of the get_mbus_config pad
- operation which should be used to avoid parsing the remote endpoint
- configuration.
-
- This media driver supports inheriting V4L2 controls to the
video capture devices, from the subdevices in the capture device's
pipeline. The controls for each capture device are updated in the
@@ -23,32 +11,3 @@
- Similarly to the legacy control handling, legacy format handling where
formats on the video nodes are influenced by the active format of the
connected subdev should be removed.
-
-- i.MX7: all of the above, since it uses the imx media core
-
-- i.MX7: use Frame Interval Monitor
-
-- imx7-media-csi: Restrict the supported formats list to the SoC version.
-
- The imx7 CSI bridge can be configured to sample pixel components from the Rx
- queue in single (8bpp) or double (16bpp) component modes. Image format
- variants with different sample sizes (ie YUYV_2X8 vs YUYV_1X16) determine the
- pixel components sampling size per each clock cycle and their packing mode
- (see imx7_csi_configure() for details).
-
- As the imx7 CSI bridge can be interfaced with different IP blocks depending on
- the SoC model it is integrated on, the Rx queue sampling size should match
- the size of the samples transferred by the transmitting IP block.
-
- To avoid mis-configurations of the capture pipeline, the enumeration of the
- supported formats should be restricted to match the pixel source transmitting
- mode.
-
- Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2
- receiver which operates in dual pixel sampling mode. The CSI bridge should
- only expose the 1X16 formats variant which instructs it to operate in dual
- pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7,
- which supports both serial and parallel input, it should expose both variants.
-
- This currently only applies to YUYV formats, but other formats might need
- to be handled in the same way.
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index b2b1f4dd41d7..5c3cc7de209d 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -97,8 +97,8 @@ struct csi_priv {
/* the mipi virtual channel number at link validate */
int vc_num;
- /* the upstream endpoint CSI is receiving from */
- struct v4l2_fwnode_endpoint upstream_ep;
+ /* media bus config of the upstream subdevice CSI is receiving from */
+ struct v4l2_mbus_config mbus_cfg;
spinlock_t irqlock; /* protect eof_irq handler */
struct timer_list eof_timeout_timer;
@@ -125,14 +125,14 @@ static inline struct csi_priv *notifier_to_dev(struct v4l2_async_notifier *n)
return container_of(n, struct csi_priv, notifier);
}
-static inline bool is_parallel_bus(struct v4l2_fwnode_endpoint *ep)
+static inline bool is_parallel_bus(struct v4l2_mbus_config *mbus_cfg)
{
- return ep->bus_type != V4L2_MBUS_CSI2_DPHY;
+ return mbus_cfg->type != V4L2_MBUS_CSI2_DPHY;
}
-static inline bool is_parallel_16bit_bus(struct v4l2_fwnode_endpoint *ep)
+static inline bool is_parallel_16bit_bus(struct v4l2_mbus_config *mbus_cfg)
{
- return is_parallel_bus(ep) && ep->bus.parallel.bus_width >= 16;
+ return is_parallel_bus(mbus_cfg) && mbus_cfg->bus.parallel.bus_width >= 16;
}
/*
@@ -145,36 +145,31 @@ static inline bool is_parallel_16bit_bus(struct v4l2_fwnode_endpoint *ep)
* - the CSI is receiving from an 8-bit parallel bus and the incoming
* media bus format is other than UYVY8_2X8/YUYV8_2X8.
*/
-static inline bool requires_passthrough(struct v4l2_fwnode_endpoint *ep,
+static inline bool requires_passthrough(struct v4l2_mbus_config *mbus_cfg,
struct v4l2_mbus_framefmt *infmt,
const struct imx_media_pixfmt *incc)
{
- if (ep->bus_type == V4L2_MBUS_BT656) // including BT.1120
+ if (mbus_cfg->type == V4L2_MBUS_BT656) // including BT.1120
return false;
- return incc->bayer || is_parallel_16bit_bus(ep) ||
- (is_parallel_bus(ep) &&
+ return incc->bayer || is_parallel_16bit_bus(mbus_cfg) ||
+ (is_parallel_bus(mbus_cfg) &&
infmt->code != MEDIA_BUS_FMT_UYVY8_2X8 &&
infmt->code != MEDIA_BUS_FMT_YUYV8_2X8);
}
/*
- * Parses the fwnode endpoint from the source pad of the entity
- * connected to this CSI. This will either be the entity directly
- * upstream from the CSI-2 receiver, directly upstream from the
- * video mux, or directly upstream from the CSI itself. The endpoint
- * is needed to determine the bus type and bus config coming into
- * the CSI.
+ * Queries the media bus config of the upstream entity that provides data to
+ * the CSI. This will either be the entity directly upstream from the CSI-2
+ * receiver, directly upstream from a video mux, or directly upstream from
+ * the CSI itself.
*/
-static int csi_get_upstream_endpoint(struct csi_priv *priv,
- struct v4l2_fwnode_endpoint *ep)
+static int csi_get_upstream_mbus_config(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
{
- struct fwnode_handle *endpoint;
- struct v4l2_subdev *sd;
- struct media_pad *pad;
-
- if (!IS_ENABLED(CONFIG_OF))
- return -ENXIO;
+ struct v4l2_subdev *sd, *remote_sd;
+ struct media_pad *remote_pad;
+ int ret;
if (!priv->src_sd)
return -EPIPE;
@@ -206,19 +201,21 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
}
/* get source pad of entity directly upstream from sd */
- pad = imx_media_pipeline_pad(&sd->entity, 0, 0, true);
- if (!pad)
- return -ENODEV;
-
- endpoint = imx_media_get_pad_fwnode(pad);
- if (IS_ERR(endpoint))
- return PTR_ERR(endpoint);
+ remote_pad = media_entity_remote_pad_unique(&sd->entity,
+ MEDIA_PAD_FL_SOURCE);
+ if (IS_ERR(remote_pad))
+ return PTR_ERR(remote_pad);
- v4l2_fwnode_endpoint_parse(endpoint, ep);
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- fwnode_handle_put(endpoint);
+ ret = v4l2_subdev_call(remote_sd, pad, get_mbus_config,
+ remote_pad->index, mbus_cfg);
+ if (ret == -ENOIOCTLCMD)
+ v4l2_err(&priv->sd,
+ "entity %s does not implement get_mbus_config()\n",
+ remote_pad->entity->name);
- return 0;
+ return ret;
}
static void csi_idmac_put_ipu_resources(struct csi_priv *priv)
@@ -435,7 +432,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
image.phys0 = phys[0];
image.phys1 = phys[1];
- passthrough = requires_passthrough(&priv->upstream_ep, infmt, incc);
+ passthrough = requires_passthrough(&priv->mbus_cfg, infmt, incc);
passthrough_cycles = 1;
/*
@@ -708,7 +705,6 @@ static int csi_setup(struct csi_priv *priv)
{
struct v4l2_mbus_framefmt *infmt, *outfmt;
const struct imx_media_pixfmt *incc;
- struct v4l2_mbus_config mbus_cfg;
struct v4l2_mbus_framefmt if_fmt;
struct v4l2_rect crop;
@@ -716,13 +712,6 @@ static int csi_setup(struct csi_priv *priv)
incc = priv->cc[CSI_SINK_PAD];
outfmt = &priv->format_mbus[priv->active_output_pad];
- /* compose mbus_config from the upstream endpoint */
- mbus_cfg.type = priv->upstream_ep.bus_type;
- if (is_parallel_bus(&priv->upstream_ep))
- mbus_cfg.bus.parallel = priv->upstream_ep.bus.parallel;
- else
- mbus_cfg.bus.mipi_csi2 = priv->upstream_ep.bus.mipi_csi2;
-
if_fmt = *infmt;
crop = priv->crop;
@@ -730,7 +719,7 @@ static int csi_setup(struct csi_priv *priv)
* if cycles is set, we need to handle this over multiple cycles as
* generic/bayer data
*/
- if (is_parallel_bus(&priv->upstream_ep) && incc->cycles) {
+ if (is_parallel_bus(&priv->mbus_cfg) && incc->cycles) {
if_fmt.width *= incc->cycles;
crop.width *= incc->cycles;
}
@@ -741,7 +730,7 @@ static int csi_setup(struct csi_priv *priv)
priv->crop.width == 2 * priv->compose.width,
priv->crop.height == 2 * priv->compose.height);
- ipu_csi_init_interface(priv->csi, &mbus_cfg, &if_fmt, outfmt);
+ ipu_csi_init_interface(priv->csi, &priv->mbus_cfg, &if_fmt, outfmt);
ipu_csi_set_dest(priv->csi, priv->dest);
@@ -769,7 +758,7 @@ static int csi_start(struct csi_priv *priv)
return ret;
/* Skip first few frames from a BT.656 source */
- if (priv->upstream_ep.bus_type == V4L2_MBUS_BT656) {
+ if (priv->mbus_cfg.type == V4L2_MBUS_BT656) {
u32 delay_usec, bad_frames = 20;
delay_usec = DIV_ROUND_UP_ULL((u64)USEC_PER_SEC *
@@ -1118,7 +1107,7 @@ static int csi_link_validate(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
+ struct v4l2_mbus_config mbus_cfg = { .type = 0 };
bool is_csi2;
int ret;
@@ -1127,16 +1116,17 @@ static int csi_link_validate(struct v4l2_subdev *sd,
if (ret)
return ret;
- ret = csi_get_upstream_endpoint(priv, &upstream_ep);
+ ret = csi_get_upstream_mbus_config(priv, &mbus_cfg);
if (ret) {
- v4l2_err(&priv->sd, "failed to find upstream endpoint\n");
+ v4l2_err(&priv->sd,
+ "failed to get upstream media bus configuration\n");
return ret;
}
mutex_lock(&priv->lock);
- priv->upstream_ep = upstream_ep;
- is_csi2 = !is_parallel_bus(&upstream_ep);
+ priv->mbus_cfg = mbus_cfg;
+ is_csi2 = !is_parallel_bus(&mbus_cfg);
if (is_csi2) {
/*
* NOTE! It seems the virtual channels from the mipi csi-2
@@ -1192,7 +1182,7 @@ static void csi_try_crop(struct csi_priv *priv,
struct v4l2_rect *crop,
struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *infmt,
- struct v4l2_fwnode_endpoint *upstream_ep)
+ struct v4l2_mbus_config *mbus_cfg)
{
u32 in_height;
@@ -1216,7 +1206,7 @@ static void csi_try_crop(struct csi_priv *priv,
* sync, so fix it to NTSC/PAL active lines. NTSC contains
* 2 extra lines of active video that need to be cropped.
*/
- if (upstream_ep->bus_type == V4L2_MBUS_BT656 &&
+ if (mbus_cfg->type == V4L2_MBUS_BT656 &&
(V4L2_FIELD_HAS_BOTH(infmt->field) ||
infmt->field == V4L2_FIELD_ALTERNATE)) {
crop->height = in_height;
@@ -1233,7 +1223,7 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_mbus_code_enum *code)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
+ struct v4l2_mbus_config mbus_cfg = { .type = 0 };
const struct imx_media_pixfmt *incc;
struct v4l2_mbus_framefmt *infmt;
int ret = 0;
@@ -1250,13 +1240,14 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd,
break;
case CSI_SRC_PAD_DIRECT:
case CSI_SRC_PAD_IDMAC:
- ret = csi_get_upstream_endpoint(priv, &upstream_ep);
+ ret = csi_get_upstream_mbus_config(priv, &mbus_cfg);
if (ret) {
- v4l2_err(&priv->sd, "failed to find upstream endpoint\n");
+ v4l2_err(&priv->sd,
+ "failed to get upstream media bus configuration\n");
goto out;
}
- if (requires_passthrough(&upstream_ep, infmt, incc)) {
+ if (requires_passthrough(&mbus_cfg, infmt, incc)) {
if (code->index != 0) {
ret = -EINVAL;
goto out;
@@ -1426,7 +1417,7 @@ static void csi_try_field(struct csi_priv *priv,
}
static void csi_try_fmt(struct csi_priv *priv,
- struct v4l2_fwnode_endpoint *upstream_ep,
+ struct v4l2_mbus_config *mbus_cfg,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat,
struct v4l2_rect *crop,
@@ -1447,7 +1438,7 @@ static void csi_try_fmt(struct csi_priv *priv,
sdformat->format.width = compose->width;
sdformat->format.height = compose->height;
- if (requires_passthrough(upstream_ep, infmt, incc)) {
+ if (requires_passthrough(mbus_cfg, infmt, incc)) {
sdformat->format.code = infmt->code;
*cc = incc;
} else {
@@ -1497,8 +1488,7 @@ static void csi_try_fmt(struct csi_priv *priv,
crop->height = sdformat->format.height;
if (sdformat->format.field == V4L2_FIELD_ALTERNATE)
crop->height *= 2;
- csi_try_crop(priv, crop, sd_state, &sdformat->format,
- upstream_ep);
+ csi_try_crop(priv, crop, sd_state, &sdformat->format, mbus_cfg);
compose->left = 0;
compose->top = 0;
compose->width = crop->width;
@@ -1516,7 +1506,7 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
+ struct v4l2_mbus_config mbus_cfg = { .type = 0 };
const struct imx_media_pixfmt *cc;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_rect *crop, *compose;
@@ -1525,9 +1515,10 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
if (sdformat->pad >= CSI_NUM_PADS)
return -EINVAL;
- ret = csi_get_upstream_endpoint(priv, &upstream_ep);
+ ret = csi_get_upstream_mbus_config(priv, &mbus_cfg);
if (ret) {
- v4l2_err(&priv->sd, "failed to find upstream endpoint\n");
+ v4l2_err(&priv->sd,
+ "failed to get upstream media bus configuration\n");
return ret;
}
@@ -1541,8 +1532,7 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
crop = __csi_get_crop(priv, sd_state, sdformat->which);
compose = __csi_get_compose(priv, sd_state, sdformat->which);
- csi_try_fmt(priv, &upstream_ep, sd_state, sdformat, crop, compose,
- &cc);
+ csi_try_fmt(priv, &mbus_cfg, sd_state, sdformat, crop, compose, &cc);
fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
@@ -1559,8 +1549,8 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
format.pad = pad;
format.which = sdformat->which;
format.format = sdformat->format;
- csi_try_fmt(priv, &upstream_ep, sd_state, &format,
- NULL, compose, &outcc);
+ csi_try_fmt(priv, &mbus_cfg, sd_state, &format, NULL,
+ compose, &outcc);
outfmt = __csi_get_fmt(priv, sd_state, pad,
sdformat->which);
@@ -1648,7 +1638,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_selection *sel)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
+ struct v4l2_mbus_config mbus_cfg = { .type = 0 };
struct v4l2_mbus_framefmt *infmt;
struct v4l2_rect *crop, *compose;
int pad, ret;
@@ -1656,9 +1646,10 @@ static int csi_set_selection(struct v4l2_subdev *sd,
if (sel->pad != CSI_SINK_PAD)
return -EINVAL;
- ret = csi_get_upstream_endpoint(priv, &upstream_ep);
+ ret = csi_get_upstream_mbus_config(priv, &mbus_cfg);
if (ret) {
- v4l2_err(&priv->sd, "failed to find upstream endpoint\n");
+ v4l2_err(&priv->sd,
+ "failed to get upstream media bus configuration\n");
return ret;
}
@@ -1687,7 +1678,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
goto out;
}
- csi_try_crop(priv, &sel->r, sd_state, infmt, &upstream_ep);
+ csi_try_crop(priv, &sel->r, sd_state, infmt, &mbus_cfg);
*crop = sel->r;
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index 3a9182933508..fb6590dcfc36 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -187,54 +187,6 @@ out_update_ts:
send_fim_event(fim, error_avg);
}
-#ifdef CONFIG_IMX_GPT_ICAP
-/*
- * Input Capture method of measuring frame intervals. Not subject
- * to interrupt latency.
- */
-static void fim_input_capture_handler(int channel, void *dev_id,
- ktime_t timestamp)
-{
- struct imx_media_fim *fim = dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(&fim->lock, flags);
-
- frame_interval_monitor(fim, timestamp);
-
- if (!completion_done(&fim->icap_first_event))
- complete(&fim->icap_first_event);
-
- spin_unlock_irqrestore(&fim->lock, flags);
-}
-
-static int fim_request_input_capture(struct imx_media_fim *fim)
-{
- init_completion(&fim->icap_first_event);
-
- return mxc_request_input_capture(fim->icap_channel,
- fim_input_capture_handler,
- fim->icap_flags, fim);
-}
-
-static void fim_free_input_capture(struct imx_media_fim *fim)
-{
- mxc_free_input_capture(fim->icap_channel, fim);
-}
-
-#else /* CONFIG_IMX_GPT_ICAP */
-
-static int fim_request_input_capture(struct imx_media_fim *fim)
-{
- return 0;
-}
-
-static void fim_free_input_capture(struct imx_media_fim *fim)
-{
-}
-
-#endif /* CONFIG_IMX_GPT_ICAP */
-
/*
* In case we are monitoring the first frame interval after streamon
* (when fim->num_skip = 0), we need a valid fim->last_ts before we
@@ -434,15 +386,8 @@ int imx_media_fim_set_stream(struct imx_media_fim *fim,
update_fim_nominal(fim, fi);
spin_unlock_irqrestore(&fim->lock, flags);
- if (icap_enabled(fim)) {
- ret = fim_request_input_capture(fim);
- if (ret)
- goto out;
- fim_acquire_first_ts(fim);
- }
- } else {
if (icap_enabled(fim))
- fim_free_input_capture(fim);
+ fim_acquire_first_ts(fim);
}
fim->stream_on = on;
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 3e7462112649..411e907b68eb 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -814,39 +814,6 @@ imx_media_pipeline_video_device(struct media_entity *start_entity,
EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
/*
- * Find a fwnode endpoint that maps to the given subdevice's pad.
- * If there are multiple endpoints that map to the pad, only the
- * first endpoint encountered is returned.
- *
- * On success the refcount of the returned fwnode endpoint is
- * incremented.
- */
-struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
-{
- struct fwnode_handle *endpoint;
- struct v4l2_subdev *sd;
-
- if (!is_media_entity_v4l2_subdev(pad->entity))
- return ERR_PTR(-ENODEV);
-
- sd = media_entity_to_v4l2_subdev(pad->entity);
-
- fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
- int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
- endpoint,
- pad->flags);
- if (pad_idx < 0)
- continue;
-
- if (pad_idx == pad->index)
- return endpoint;
- }
-
- return ERR_PTR(-ENODEV);
-}
-EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
-
-/*
* Turn current pipeline streaming on/off starting from entity.
*/
int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index f263fc3adbb9..f679249d82e4 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -219,7 +219,6 @@ imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
struct video_device *
imx_media_pipeline_video_device(struct media_entity *start_entity,
enum v4l2_buf_type buftype, bool upstream);
-struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad);
struct imx_media_dma_buf {
void *virt;
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index ce13e746c15f..e530767e80a5 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -188,6 +188,28 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
return 0;
}
+static struct v4l2_rect *
+imgu_subdev_get_crop(struct imgu_v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(&sd->subdev, sd_state, pad);
+ else
+ return &sd->rect.eff;
+}
+
+static struct v4l2_rect *
+imgu_subdev_get_compose(struct imgu_v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_compose(&sd->subdev, sd_state, pad);
+ else
+ return &sd->rect.bds;
+}
+
static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
@@ -200,18 +222,12 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- sel->r = *v4l2_subdev_get_try_crop(sd, sd_state,
- sel->pad);
- else
- sel->r = imgu_sd->rect.eff;
+ sel->r = *imgu_subdev_get_crop(imgu_sd, sd_state, sel->pad,
+ sel->which);
return 0;
case V4L2_SEL_TGT_COMPOSE:
- if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- sel->r = *v4l2_subdev_get_try_compose(sd, sd_state,
- sel->pad);
- else
- sel->r = imgu_sd->rect.bds;
+ sel->r = *imgu_subdev_get_compose(imgu_sd, sd_state, sel->pad,
+ sel->which);
return 0;
default:
return -EINVAL;
@@ -223,10 +239,9 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_selection *sel)
{
struct imgu_device *imgu = v4l2_get_subdevdata(sd);
- struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
- struct imgu_v4l2_subdev,
- subdev);
- struct v4l2_rect *rect, *try_sel;
+ struct imgu_v4l2_subdev *imgu_sd =
+ container_of(sd, struct imgu_v4l2_subdev, subdev);
+ struct v4l2_rect *rect;
dev_dbg(&imgu->pci_dev->dev,
"set subdev %u sel which %u target 0x%4x rect [%ux%u]",
@@ -238,22 +253,18 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
- rect = &imgu_sd->rect.eff;
+ rect = imgu_subdev_get_crop(imgu_sd, sd_state, sel->pad,
+ sel->which);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
- rect = &imgu_sd->rect.bds;
+ rect = imgu_subdev_get_compose(imgu_sd, sd_state, sel->pad,
+ sel->which);
break;
default:
return -EINVAL;
}
- if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- *try_sel = sel->r;
- else
- *rect = sel->r;
-
+ *rect = sel->r;
return 0;
}
diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c
index 897f5d7a6aad..394df5761556 100644
--- a/drivers/staging/media/meson/vdec/codec_vp9.c
+++ b/drivers/staging/media/meson/vdec/codec_vp9.c
@@ -1459,7 +1459,7 @@ static void vp9_tree_merge_probs(unsigned int *prev_prob,
if (den == 0) {
new_prob = pre_prob;
} else {
- m_count = den < MODE_MV_COUNT_SAT ? den : MODE_MV_COUNT_SAT;
+ m_count = min(den, MODE_MV_COUNT_SAT);
get_prob =
clip_prob(div_r32(((int64_t)tree_left * 256 +
(den >> 1)),
@@ -1513,7 +1513,7 @@ static void adapt_coef_probs_cxt(unsigned int *prev_prob,
/* get binary prob */
num = branch_ct[node][0];
den = branch_ct[node][0] + branch_ct[node][1];
- m_count = den < count_sat ? den : count_sat;
+ m_count = min(den, count_sat);
get_prob = (den == 0) ?
128u :
@@ -1649,8 +1649,7 @@ static void adapt_coef_probs(int prev_kf, int cur_kf, int pre_fc,
else if (coef_count_node_start ==
VP9_MV_BITS_1_COUNT_START)
coef_node_start = VP9_MV_BITS_1_START;
- else if (coef_count_node_start ==
- VP9_MV_CLASS0_HP_0_COUNT_START)
+ else /* node_start == VP9_MV_CLASS0_HP_0_COUNT_START */
coef_node_start = VP9_MV_CLASS0_HP_0_START;
den = count[coef_count_node_start] +
@@ -1664,8 +1663,7 @@ static void adapt_coef_probs(int prev_kf, int cur_kf, int pre_fc,
if (den == 0) {
new_prob = pre_prob;
} else {
- m_count = den < MODE_MV_COUNT_SAT ?
- den : MODE_MV_COUNT_SAT;
+ m_count = min(den, MODE_MV_COUNT_SAT);
get_prob =
clip_prob(div_r32(((int64_t)
count[coef_count_node_start] * 256 +
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 60f3d84be828..0ad70faa9ba0 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -19,8 +19,6 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mc.h>
-#include <asm/cacheflush.h>
-
#include "iss_video.h"
#include "iss.h"
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index ca2d5edb6261..19668d28b682 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -53,19 +53,19 @@ enum iss_pipeline_stream_state {
enum iss_pipeline_state {
/* The stream has been started on the input video node. */
- ISS_PIPELINE_STREAM_INPUT = 1,
+ ISS_PIPELINE_STREAM_INPUT = BIT(0),
/* The stream has been started on the output video node. */
- ISS_PIPELINE_STREAM_OUTPUT = (1 << 1),
+ ISS_PIPELINE_STREAM_OUTPUT = BIT(1),
/* At least one buffer is queued on the input video node. */
- ISS_PIPELINE_QUEUE_INPUT = (1 << 2),
+ ISS_PIPELINE_QUEUE_INPUT = BIT(2),
/* At least one buffer is queued on the output video node. */
- ISS_PIPELINE_QUEUE_OUTPUT = (1 << 3),
+ ISS_PIPELINE_QUEUE_OUTPUT = BIT(3),
/* The input entity is idle, ready to be started. */
- ISS_PIPELINE_IDLE_INPUT = (1 << 4),
+ ISS_PIPELINE_IDLE_INPUT = BIT(4),
/* The output entity is idle, ready to be started. */
- ISS_PIPELINE_IDLE_OUTPUT = (1 << 5),
+ ISS_PIPELINE_IDLE_OUTPUT = BIT(5),
/* The pipeline is currently streaming. */
- ISS_PIPELINE_STREAM = (1 << 6),
+ ISS_PIPELINE_STREAM = BIT(6),
};
/*
@@ -126,9 +126,9 @@ struct iss_buffer {
enum iss_video_dmaqueue_flags {
/* Set if DMA queue becomes empty when ISS_PIPELINE_STREAM_CONTINUOUS */
- ISS_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
+ ISS_VIDEO_DMAQUEUE_UNDERRUN = BIT(0),
/* Set when queuing buffer to an empty DMA queue */
- ISS_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
+ ISS_VIDEO_DMAQUEUE_QUEUED = BIT(1),
};
#define iss_video_dmaqueue_flags_clr(video) \
diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c
index d8c1c0db15c7..cfae99b40ccb 100644
--- a/drivers/staging/media/rkvdec/rkvdec-vp9.c
+++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c
@@ -84,6 +84,8 @@ struct rkvdec_vp9_probs {
struct rkvdec_vp9_inter_frame_probs inter;
struct rkvdec_vp9_intra_only_frame_probs intra_only;
};
+ /* 128 bit alignment */
+ u8 padding1[11];
};
/* Data structure describing auxiliary buffer format. */
@@ -1006,6 +1008,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
ctx->priv = vp9_ctx;
+ BUILD_BUG_ON(sizeof(priv_tbl->probs) % 16); /* ensure probs size is 128-bit aligned */
priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
&vp9_ctx->priv_tbl.dma, GFP_KERNEL);
if (!priv_tbl) {
diff --git a/drivers/staging/media/sunxi/Kconfig b/drivers/staging/media/sunxi/Kconfig
index 4549a135741f..62a486aba88b 100644
--- a/drivers/staging/media/sunxi/Kconfig
+++ b/drivers/staging/media/sunxi/Kconfig
@@ -12,5 +12,6 @@ config VIDEO_SUNXI
if VIDEO_SUNXI
source "drivers/staging/media/sunxi/cedrus/Kconfig"
+source "drivers/staging/media/sunxi/sun6i-isp/Kconfig"
endif
diff --git a/drivers/staging/media/sunxi/Makefile b/drivers/staging/media/sunxi/Makefile
index b87140b0e15f..3d20b2f0e644 100644
--- a/drivers/staging/media/sunxi/Makefile
+++ b/drivers/staging/media/sunxi/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus/
+obj-$(CONFIG_VIDEO_SUN6I_ISP) += sun6i-isp/
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index 55c54dfdc585..a43d5ff66716 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -45,23 +45,37 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
} else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
+ unsigned int bit_depth, max_depth;
+ struct vb2_queue *vq;
if (sps->chroma_format_idc != 1)
/* Only 4:2:0 is supported */
return -EINVAL;
- if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
- /* Luma and chroma bit depth mismatch */
+ bit_depth = max(sps->bit_depth_luma_minus8,
+ sps->bit_depth_chroma_minus8) + 8;
+
+ if (cedrus_is_capable(ctx, CEDRUS_CAPABILITY_H265_10_DEC))
+ max_depth = 10;
+ else
+ max_depth = 8;
+
+ if (bit_depth > max_depth)
return -EINVAL;
- if (ctx->dev->capabilities & CEDRUS_CAPABILITY_H265_10_DEC) {
- if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
- /* Only 8-bit and 10-bit are supported */
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ /*
+ * Bit depth can't be higher than currently set once
+ * buffers are allocated.
+ */
+ if (vb2_is_busy(vq)) {
+ if (ctx->bit_depth < bit_depth)
return -EINVAL;
} else {
- if (sps->bit_depth_luma_minus8 != 0)
- /* Only 8-bit is supported */
- return -EINVAL;
+ ctx->bit_depth = bit_depth;
+ cedrus_reset_cap_format(ctx);
}
}
@@ -77,56 +91,56 @@ static const struct cedrus_control cedrus_controls[] = {
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_PICTURE,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SPS,
.ops = &cedrus_ctrl_ops,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PPS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
@@ -134,7 +148,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
.def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
@@ -142,7 +156,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_START_CODE_NONE,
.def = V4L2_STATELESS_H264_START_CODE_NONE,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
/*
* We only expose supported profiles information,
@@ -160,20 +174,20 @@ static const struct cedrus_control cedrus_controls[] = {
.menu_skip_mask =
BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_SPS,
.ops = &cedrus_ctrl_ops,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_PPS,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -181,13 +195,13 @@ static const struct cedrus_control cedrus_controls[] = {
/* The driver can only handle 1 entry per slice for now */
.dims = { 1 },
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -197,7 +211,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = 0xffffffff,
.step = 1,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -205,7 +219,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
.def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -213,19 +227,19 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_START_CODE_NONE,
.def = V4L2_STATELESS_HEVC_START_CODE_NONE,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_VP8_FRAME,
},
- .codec = CEDRUS_CODEC_VP8,
+ .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
};
@@ -258,7 +272,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
struct v4l2_ctrl_handler *hdl = &ctx->hdl;
struct v4l2_ctrl *ctrl;
unsigned int ctrl_size;
- unsigned int i;
+ unsigned int i, j;
v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
if (hdl->error) {
@@ -274,7 +288,11 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
if (!ctx->ctrls)
return -ENOMEM;
+ j = 0;
for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
+ if (!cedrus_is_capable(ctx, cedrus_controls[i].capabilities))
+ continue;
+
ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
NULL);
if (hdl->error) {
@@ -289,7 +307,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
return hdl->error;
}
- ctx->ctrls[i] = ctrl;
+ ctx->ctrls[j++] = ctrl;
}
ctx->fh.ctrl_handler = hdl;
@@ -350,27 +368,20 @@ static int cedrus_open(struct file *file)
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
ctx->dev = dev;
-
- ret = cedrus_init_ctrls(dev, ctx);
- if (ret)
- goto err_free;
+ ctx->bit_depth = 8;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&cedrus_queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
- goto err_ctrls;
+ goto err_free;
}
- ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_NV12_32L32;
- cedrus_prepare_format(&ctx->dst_fmt);
- ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
- /*
- * TILED_NV12 has more strict requirements, so copy the width and
- * height to src_fmt to ensure that is matches the dst_fmt resolution.
- */
- ctx->src_fmt.width = ctx->dst_fmt.width;
- ctx->src_fmt.height = ctx->dst_fmt.height;
- cedrus_prepare_format(&ctx->src_fmt);
+
+ cedrus_reset_out_format(ctx);
+
+ ret = cedrus_init_ctrls(dev, ctx);
+ if (ret)
+ goto err_m2m_release;
v4l2_fh_add(&ctx->fh);
@@ -378,8 +389,8 @@ static int cedrus_open(struct file *file)
return 0;
-err_ctrls:
- v4l2_ctrl_handler_free(&ctx->hdl);
+err_m2m_release:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_free:
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
@@ -460,11 +471,6 @@ static int cedrus_probe(struct platform_device *pdev)
return ret;
}
- dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
- dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
- dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
- dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
-
mutex_init(&dev->dev_mutex);
INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 93a2196006f7..522c184e2afc 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -35,14 +35,6 @@
#define CEDRUS_CAPABILITY_VP8_DEC BIT(4)
#define CEDRUS_CAPABILITY_H265_10_DEC BIT(5)
-enum cedrus_codec {
- CEDRUS_CODEC_MPEG2,
- CEDRUS_CODEC_H264,
- CEDRUS_CODEC_H265,
- CEDRUS_CODEC_VP8,
- CEDRUS_CODEC_LAST,
-};
-
enum cedrus_irq_status {
CEDRUS_IRQ_NONE,
CEDRUS_IRQ_ERROR,
@@ -57,7 +49,7 @@ enum cedrus_h264_pic_type {
struct cedrus_control {
struct v4l2_ctrl_config cfg;
- enum cedrus_codec codec;
+ unsigned int capabilities;
};
struct cedrus_h264_run {
@@ -108,7 +100,15 @@ struct cedrus_buffer {
struct {
unsigned int position;
enum cedrus_h264_pic_type pic_type;
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
} h264;
+ struct {
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
+ } h265;
} codec;
};
@@ -118,17 +118,14 @@ struct cedrus_ctx {
struct v4l2_pix_format src_fmt;
struct v4l2_pix_format dst_fmt;
- enum cedrus_codec current_codec;
+ struct cedrus_dec_ops *current_codec;
+ unsigned int bit_depth;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl **ctrls;
union {
struct {
- void *mv_col_buf;
- dma_addr_t mv_col_buf_dma;
- ssize_t mv_col_buf_field_size;
- ssize_t mv_col_buf_size;
void *pic_info_buf;
dma_addr_t pic_info_buf_dma;
ssize_t pic_info_buf_size;
@@ -142,10 +139,6 @@ struct cedrus_ctx {
ssize_t intra_pred_buf_size;
} h264;
struct {
- void *mv_col_buf;
- dma_addr_t mv_col_buf_addr;
- ssize_t mv_col_buf_size;
- ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
void *entry_points_buf;
@@ -170,6 +163,8 @@ struct cedrus_dec_ops {
int (*start)(struct cedrus_ctx *ctx);
void (*stop)(struct cedrus_ctx *ctx);
void (*trigger)(struct cedrus_ctx *ctx);
+ unsigned int (*extra_cap_size)(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt);
};
struct cedrus_variant {
@@ -185,7 +180,6 @@ struct cedrus_dev {
struct platform_device *pdev;
struct device *dev;
struct v4l2_m2m_dev *m2m_dev;
- struct cedrus_dec_ops *dec_ops[CEDRUS_CODEC_LAST];
/* Device file mutex */
struct mutex dev_mutex;
@@ -268,6 +262,12 @@ vb2_to_cedrus_buffer(const struct vb2_buffer *p)
return vb2_v4l2_to_cedrus_buffer(to_vb2_v4l2_buffer(p));
}
+static inline bool
+cedrus_is_capable(struct cedrus_ctx *ctx, unsigned int capabilities)
+{
+ return (ctx->dev->capabilities & capabilities) == capabilities;
+}
+
void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index e7f7602a5ab4..fbbf9e6f0f50 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -94,7 +94,7 @@ void cedrus_device_run(void *priv)
cedrus_dst_format_set(dev, &ctx->dst_fmt);
- error = dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
+ error = ctx->current_codec->setup(ctx, &run);
if (error)
v4l2_err(&ctx->dev->v4l2_dev,
"Failed to setup decoding job: %d\n", error);
@@ -110,7 +110,7 @@ void cedrus_device_run(void *priv)
schedule_delayed_work(&dev->watchdog_work,
msecs_to_jiffies(2000));
- dev->dec_ops[ctx->current_codec]->trigger(ctx);
+ ctx->current_codec->trigger(ctx);
} else {
v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
ctx->fh.m2m_ctx,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index a8b236cd3800..dfb401df138a 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -54,17 +54,13 @@ static void cedrus_h264_write_sram(struct cedrus_dev *dev,
cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, *buffer++);
}
-static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int position,
+static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_buffer *buf,
unsigned int field)
{
- dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma;
-
- /* Adjust for the position */
- addr += position * ctx->codec.h264.mv_col_buf_field_size * 2;
+ dma_addr_t addr = buf->codec.h264.mv_col_buf_dma;
/* Adjust for the field */
- addr += field * ctx->codec.h264.mv_col_buf_field_size;
+ addr += field * buf->codec.h264.mv_col_buf_size / 2;
return addr;
}
@@ -76,7 +72,6 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
struct cedrus_h264_sram_ref_pic *pic)
{
struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
- unsigned int position = buf->codec.h264.position;
pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
@@ -84,14 +79,12 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
- pic->mv_col_top_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0));
- pic->mv_col_bot_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1));
+ pic->mv_col_top_ptr = cpu_to_le32(cedrus_h264_mv_col_buf_addr(buf, 0));
+ pic->mv_col_bot_ptr = cpu_to_le32(cedrus_h264_mv_col_buf_addr(buf, 1));
}
-static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
- struct cedrus_run *run)
+static int cedrus_write_frame_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
{
struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM];
const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
@@ -146,6 +139,31 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
output_buf->codec.h264.position = position;
+ if (!output_buf->codec.h264.mv_col_buf_size) {
+ const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
+ unsigned int field_size;
+
+ field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
+ DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE))
+ field_size = field_size * 2;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+ field_size = field_size * 2;
+
+ output_buf->codec.h264.mv_col_buf_size = field_size * 2;
+ /* Buffer is never accessed by CPU, so we can skip kernel mapping. */
+ output_buf->codec.h264.mv_col_buf =
+ dma_alloc_attrs(dev->dev,
+ output_buf->codec.h264.mv_col_buf_size,
+ &output_buf->codec.h264.mv_col_buf_dma,
+ GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
+
+ if (!output_buf->codec.h264.mv_col_buf) {
+ output_buf->codec.h264.mv_col_buf_size = 0;
+ return -ENOMEM;
+ }
+ }
+
if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
@@ -162,6 +180,8 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
pic_list, sizeof(pic_list));
cedrus_write(dev, VE_H264_OUTPUT_FRAME_IDX, position);
+
+ return 0;
}
#define CEDRUS_MAX_REF_IDX 32
@@ -496,8 +516,9 @@ static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx)
static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
{
struct cedrus_dev *dev = ctx->dev;
+ int ret;
- cedrus_engine_enable(ctx, CEDRUS_CODEC_H264);
+ cedrus_engine_enable(ctx);
cedrus_write(dev, VE_H264_SDROT_CTRL, 0);
cedrus_write(dev, VE_H264_EXTRA_BUFFER1,
@@ -506,7 +527,9 @@ static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
ctx->codec.h264.neighbor_info_buf_dma);
cedrus_write_scaling_lists(ctx, run);
- cedrus_write_frame_list(ctx, run);
+ ret = cedrus_write_frame_list(ctx, run);
+ if (ret)
+ return ret;
cedrus_set_params(ctx, run);
@@ -517,8 +540,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
unsigned int pic_info_size;
- unsigned int field_size;
- unsigned int mv_col_size;
int ret;
/*
@@ -566,38 +587,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
goto err_pic_buf;
}
- field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
- DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we
- * might have to rework this if memory efficiency ever is
- * something we need to work on.
- */
- field_size = field_size * 2;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might
- * have to rework this if memory efficiency ever is something
- * we need to work on.
- */
- field_size = field_size * 2;
- ctx->codec.h264.mv_col_buf_field_size = field_size;
-
- mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM;
- ctx->codec.h264.mv_col_buf_size = mv_col_size;
- ctx->codec.h264.mv_col_buf =
- dma_alloc_attrs(dev->dev,
- ctx->codec.h264.mv_col_buf_size,
- &ctx->codec.h264.mv_col_buf_dma,
- GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
- if (!ctx->codec.h264.mv_col_buf) {
- ret = -ENOMEM;
- goto err_neighbor_buf;
- }
-
if (ctx->src_fmt.width > 2048) {
/*
* Formulas for deblock and intra prediction buffer sizes
@@ -613,7 +602,7 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
if (!ctx->codec.h264.deblk_buf) {
ret = -ENOMEM;
- goto err_mv_col_buf;
+ goto err_neighbor_buf;
}
/*
@@ -641,12 +630,6 @@ err_deblk_buf:
ctx->codec.h264.deblk_buf_dma,
DMA_ATTR_NO_KERNEL_MAPPING);
-err_mv_col_buf:
- dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma,
- DMA_ATTR_NO_KERNEL_MAPPING);
-
err_neighbor_buf:
dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
@@ -664,11 +647,26 @@ err_pic_buf:
static void cedrus_h264_stop(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
+ struct cedrus_buffer *buf;
+ struct vb2_queue *vq;
+ unsigned int i;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ for (i = 0; i < vq->num_buffers; i++) {
+ buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i));
+
+ if (buf->codec.h264.mv_col_buf_size > 0) {
+ dma_free_attrs(dev->dev,
+ buf->codec.h264.mv_col_buf_size,
+ buf->codec.h264.mv_col_buf,
+ buf->codec.h264.mv_col_buf_dma,
+ DMA_ATTR_NO_KERNEL_MAPPING);
+
+ buf->codec.h264.mv_col_buf_size = 0;
+ }
+ }
- dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma,
- DMA_ATTR_NO_KERNEL_MAPPING);
dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
ctx->codec.h264.neighbor_info_buf_dma,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 4952fc17f3e6..fc9297232456 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -41,6 +41,19 @@ struct cedrus_h265_sram_pred_weight {
__s8 offset;
} __packed;
+static unsigned int cedrus_h265_2bit_size(unsigned int width,
+ unsigned int height)
+{
+ /*
+ * Vendor library additionally aligns width and height to 16,
+ * but all capture formats are already aligned to that anyway,
+ * so we can skip that here. All formats are also one form of
+ * YUV 4:2:0 or another, so we can safely assume multiplication
+ * factor of 1.5.
+ */
+ return ALIGN(width / 4, 32) * height * 3 / 2;
+}
+
static enum cedrus_irq_status cedrus_h265_irq_status(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
@@ -90,12 +103,13 @@ static void cedrus_h265_sram_write_data(struct cedrus_dev *dev, void *data,
}
static inline dma_addr_t
-cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int index, unsigned int field)
+cedrus_h265_frame_info_mv_col_buf_addr(struct vb2_buffer *buf,
+ unsigned int field)
{
- return ctx->codec.h265.mv_col_buf_addr + index *
- ctx->codec.h265.mv_col_buf_unit_size +
- field * ctx->codec.h265.mv_col_buf_unit_size / 2;
+ struct cedrus_buffer *cedrus_buf = vb2_to_cedrus_buffer(buf);
+
+ return cedrus_buf->codec.h265.mv_col_buf_dma +
+ field * cedrus_buf->codec.h265.mv_col_buf_size / 2;
}
static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
@@ -108,9 +122,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buf, 0);
dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buf, 1);
dma_addr_t mv_col_buf_addr[2] = {
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buf->index, 0),
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buf->index,
- field_pic ? 1 : 0)
+ cedrus_h265_frame_info_mv_col_buf_addr(buf, 0),
+ cedrus_h265_frame_info_mv_col_buf_addr(buf, field_pic ? 1 : 0)
};
u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO +
VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index;
@@ -242,6 +255,18 @@ static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num)
}
}
+static u32 cedrus_h265_show_bits(struct cedrus_dev *dev, int num)
+{
+ cedrus_write(dev, VE_DEC_H265_TRIGGER,
+ VE_DEC_H265_TRIGGER_SHOW_BITS |
+ VE_DEC_H265_TRIGGER_TYPE_N_BITS(num));
+
+ cedrus_wait_for(dev, VE_DEC_H265_STATUS,
+ VE_DEC_H265_STATUS_VLD_BUSY);
+
+ return cedrus_read(dev, VE_DEC_H265_BITS_READ);
+}
+
static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
@@ -400,13 +425,14 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
unsigned int width_in_ctb_luma, ctb_size_luma;
unsigned int log2_max_luma_coding_block_size;
unsigned int ctb_addr_x, ctb_addr_y;
+ struct cedrus_buffer *cedrus_buf;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
u32 chroma_log2_weight_denom;
u32 num_entry_point_offsets;
u32 output_pic_list_index;
u32 pic_order_cnt[2];
- u8 *padding;
+ u8 padding;
int count;
u32 reg;
@@ -416,6 +442,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
decode_params = run->h265.decode_params;
pred_weight_table = &slice_params->pred_weight_table;
num_entry_point_offsets = slice_params->num_entry_point_offsets;
+ cedrus_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
/*
* If entry points offsets are present, we should get them
@@ -433,37 +460,31 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
/* MV column buffer size and allocation. */
- if (!ctx->codec.h265.mv_col_buf_size) {
- unsigned int num_buffers =
- run->dst->vb2_buf.vb2_queue->num_buffers;
-
+ if (!cedrus_buf->codec.h265.mv_col_buf_size) {
/*
* Each CTB requires a MV col buffer with a specific unit size.
* Since the address is given with missing lsb bits, 1 KiB is
* added to each buffer to ensure proper alignment.
*/
- ctx->codec.h265.mv_col_buf_unit_size =
+ cedrus_buf->codec.h265.mv_col_buf_size =
DIV_ROUND_UP(ctx->src_fmt.width, ctb_size_luma) *
DIV_ROUND_UP(ctx->src_fmt.height, ctb_size_luma) *
CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE + SZ_1K;
- ctx->codec.h265.mv_col_buf_size = num_buffers *
- ctx->codec.h265.mv_col_buf_unit_size;
-
/* Buffer is never accessed by CPU, so we can skip kernel mapping. */
- ctx->codec.h265.mv_col_buf =
+ cedrus_buf->codec.h265.mv_col_buf =
dma_alloc_attrs(dev->dev,
- ctx->codec.h265.mv_col_buf_size,
- &ctx->codec.h265.mv_col_buf_addr,
+ cedrus_buf->codec.h265.mv_col_buf_size,
+ &cedrus_buf->codec.h265.mv_col_buf_dma,
GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
- if (!ctx->codec.h265.mv_col_buf) {
- ctx->codec.h265.mv_col_buf_size = 0;
+ if (!cedrus_buf->codec.h265.mv_col_buf) {
+ cedrus_buf->codec.h265.mv_col_buf_size = 0;
return -ENOMEM;
}
}
/* Activate H265 engine. */
- cedrus_engine_enable(ctx, CEDRUS_CODEC_H265);
+ cedrus_engine_enable(ctx);
/* Source offset and length in bits. */
@@ -520,21 +541,22 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
if (slice_params->data_byte_offset == 0)
return -EOPNOTSUPP;
- padding = (u8 *)vb2_plane_vaddr(&run->src->vb2_buf, 0) +
- slice_params->data_byte_offset - 1;
+ cedrus_h265_skip_bits(dev, (slice_params->data_byte_offset - 1) * 8);
+
+ padding = cedrus_h265_show_bits(dev, 8);
/* at least one bit must be set in that byte */
- if (*padding == 0)
+ if (padding == 0)
return -EINVAL;
for (count = 0; count < 8; count++)
- if (*padding & (1 << count))
+ if (padding & (1 << count))
break;
/* Include the one bit. */
count++;
- cedrus_h265_skip_bits(dev, slice_params->data_byte_offset * 8 - count);
+ cedrus_h265_skip_bits(dev, 8 - count);
/* Bitstream parameters. */
@@ -793,6 +815,18 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L1);
}
+ if (ctx->bit_depth > 8) {
+ unsigned int stride = ALIGN(ctx->dst_fmt.width / 4, 32);
+
+ reg = ctx->dst_fmt.sizeimage -
+ cedrus_h265_2bit_size(ctx->dst_fmt.width,
+ ctx->dst_fmt.height);
+ cedrus_write(dev, VE_DEC_H265_OFFSET_ADDR_FIRST_OUT, reg);
+
+ reg = VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(stride);
+ cedrus_write(dev, VE_DEC_H265_10BIT_CONFIGURE, reg);
+ }
+
/* Enable appropriate interruptions. */
cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK);
@@ -803,9 +837,6 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
- /* The buffer size is calculated at setup time. */
- ctx->codec.h265.mv_col_buf_size = 0;
-
/* Buffer is never accessed by CPU, so we can skip kernel mapping. */
ctx->codec.h265.neighbor_info_buf =
dma_alloc_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
@@ -832,14 +863,24 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
static void cedrus_h265_stop(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
+ struct cedrus_buffer *buf;
+ struct vb2_queue *vq;
+ unsigned int i;
- if (ctx->codec.h265.mv_col_buf_size > 0) {
- dma_free_attrs(dev->dev, ctx->codec.h265.mv_col_buf_size,
- ctx->codec.h265.mv_col_buf,
- ctx->codec.h265.mv_col_buf_addr,
- DMA_ATTR_NO_KERNEL_MAPPING);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ for (i = 0; i < vq->num_buffers; i++) {
+ buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i));
- ctx->codec.h265.mv_col_buf_size = 0;
+ if (buf->codec.h265.mv_col_buf_size > 0) {
+ dma_free_attrs(dev->dev,
+ buf->codec.h265.mv_col_buf_size,
+ buf->codec.h265.mv_col_buf,
+ buf->codec.h265.mv_col_buf_dma,
+ DMA_ATTR_NO_KERNEL_MAPPING);
+
+ buf->codec.h265.mv_col_buf_size = 0;
+ }
}
dma_free_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
@@ -858,6 +899,15 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
}
+static unsigned int cedrus_h265_extra_cap_size(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
+{
+ if (ctx->bit_depth > 8)
+ return cedrus_h265_2bit_size(pix_fmt->width, pix_fmt->height);
+
+ return 0;
+}
+
struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.irq_clear = cedrus_h265_irq_clear,
.irq_disable = cedrus_h265_irq_disable,
@@ -866,4 +916,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.start = cedrus_h265_start,
.stop = cedrus_h265_stop,
.trigger = cedrus_h265_trigger,
+ .extra_cap_size = cedrus_h265_extra_cap_size,
};
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index a6470a89851e..fa86a658fdc6 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -31,7 +31,7 @@
#include "cedrus_hw.h"
#include "cedrus_regs.h"
-int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
+int cedrus_engine_enable(struct cedrus_ctx *ctx)
{
u32 reg = 0;
@@ -42,18 +42,18 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
reg |= VE_MODE_REC_WR_MODE_2MB;
reg |= VE_MODE_DDR_MODE_BW_128;
- switch (codec) {
- case CEDRUS_CODEC_MPEG2:
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
reg |= VE_MODE_DEC_MPEG;
break;
/* H.264 and VP8 both use the same decoding mode bit. */
- case CEDRUS_CODEC_H264:
- case CEDRUS_CODEC_VP8:
+ case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_VP8_FRAME:
reg |= VE_MODE_DEC_H264;
break;
- case CEDRUS_CODEC_H265:
+ case V4L2_PIX_FMT_HEVC_SLICE:
reg |= VE_MODE_DEC_H265;
break;
@@ -132,12 +132,12 @@ static irqreturn_t cedrus_irq(int irq, void *data)
return IRQ_NONE;
}
- status = dev->dec_ops[ctx->current_codec]->irq_status(ctx);
+ status = ctx->current_codec->irq_status(ctx);
if (status == CEDRUS_IRQ_NONE)
return IRQ_NONE;
- dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
- dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
+ ctx->current_codec->irq_disable(ctx);
+ ctx->current_codec->irq_clear(ctx);
if (status == CEDRUS_IRQ_ERROR)
state = VB2_BUF_STATE_ERROR;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
index 7c92f00e36da..6f1e701b1ea8 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
@@ -16,7 +16,7 @@
#ifndef _CEDRUS_HW_H_
#define _CEDRUS_HW_H_
-int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec);
+int cedrus_engine_enable(struct cedrus_ctx *ctx);
void cedrus_engine_disable(struct cedrus_dev *dev);
void cedrus_dst_format_set(struct cedrus_dev *dev,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
index c1128d2cd555..10e98f08aafc 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
@@ -66,7 +66,7 @@ static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
quantisation = run->mpeg2.quantisation;
/* Activate MPEG engine. */
- cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
+ cedrus_engine_enable(ctx);
/* Set intra quantisation matrix. */
matrix = quantisation->intra_quantiser_matrix;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index d81f7513ade0..05e6cbc548ab 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -498,6 +498,22 @@
#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80)
+#define VE_DEC_H265_OFFSET_ADDR_FIRST_OUT (VE_ENGINE_DEC_H265 + 0x84)
+#define VE_DEC_H265_OFFSET_ADDR_SECOND_OUT (VE_ENGINE_DEC_H265 + 0x88)
+
+#define VE_DEC_H265_SECOND_OUT_FMT_8BIT_PLUS_2BIT 0
+#define VE_DEC_H265_SECOND_OUT_FMT_P010 1
+#define VE_DEC_H265_SECOND_OUT_FMT_10BIT_4x4_TILED 2
+
+#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_OUT_FMT(v) \
+ SHIFT_AND_MASK_BITS(v, 24, 23)
+#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_ENABLE BIT(22)
+#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_STRIDE(v) \
+ SHIFT_AND_MASK_BITS(v, 21, 11)
+#define VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(v) \
+ SHIFT_AND_MASK_BITS(v, 10, 0)
+#define VE_DEC_H265_10BIT_CONFIGURE (VE_ENGINE_DEC_H265 + 0x8c)
+
#define VE_DEC_H265_LOW_ADDR_PRIMARY_CHROMA(a) \
SHIFT_AND_MASK_BITS(a, 31, 24)
#define VE_DEC_H265_LOW_ADDR_SECONDARY_CHROMA(a) \
@@ -505,6 +521,8 @@
#define VE_DEC_H265_LOW_ADDR_ENTRY_POINTS_BUF(a) \
SHIFT_AND_MASK_BITS(a, 7, 0)
+#define VE_DEC_H265_BITS_READ (VE_ENGINE_DEC_H265 + 0xdc)
+
#define VE_DEC_H265_SRAM_OFFSET (VE_ENGINE_DEC_H265 + 0xe0)
#define VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_LUMA_L0 0x00
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 66714609b577..b00feaf4072c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -56,13 +56,13 @@ static struct cedrus_format cedrus_formats[] = {
.capabilities = CEDRUS_CAPABILITY_VP8_DEC,
},
{
- .pixelformat = V4L2_PIX_FMT_NV12_32L32,
+ .pixelformat = V4L2_PIX_FMT_NV12,
.directions = CEDRUS_DECODE_DST,
+ .capabilities = CEDRUS_CAPABILITY_UNTILED,
},
{
- .pixelformat = V4L2_PIX_FMT_NV12,
+ .pixelformat = V4L2_PIX_FMT_NV12_32L32,
.directions = CEDRUS_DECODE_DST,
- .capabilities = CEDRUS_CAPABILITY_UNTILED,
},
};
@@ -73,8 +73,8 @@ static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
return container_of(file->private_data, struct cedrus_ctx, fh);
}
-static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
- unsigned int capabilities)
+static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx,
+ u32 pixelformat, u32 directions)
{
struct cedrus_format *first_valid_fmt = NULL;
struct cedrus_format *fmt;
@@ -83,7 +83,7 @@ static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
fmt = &cedrus_formats[i];
- if ((fmt->capabilities & capabilities) != fmt->capabilities ||
+ if (!cedrus_is_capable(ctx, fmt->capabilities) ||
!(fmt->directions & directions))
continue;
@@ -177,19 +177,13 @@ static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
u32 direction)
{
struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- unsigned int capabilities = dev->capabilities;
- struct cedrus_format *fmt;
unsigned int i, index;
/* Index among formats that match the requested direction. */
index = 0;
for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
- fmt = &cedrus_formats[i];
-
- if (fmt->capabilities && (fmt->capabilities & capabilities) !=
- fmt->capabilities)
+ if (!cedrus_is_capable(ctx, cedrus_formats[i].capabilities))
continue;
if (!(cedrus_formats[i].directions & direction))
@@ -241,15 +235,12 @@ static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
return 0;
}
-static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int cedrus_try_fmt_vid_cap_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
struct cedrus_format *fmt =
- cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
- dev->capabilities);
+ cedrus_find_format(ctx, pix_fmt->pixelformat,
+ CEDRUS_DECODE_DST);
if (!fmt)
return -EINVAL;
@@ -259,18 +250,25 @@ static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
pix_fmt->height = ctx->src_fmt.height;
cedrus_prepare_format(pix_fmt);
+ if (ctx->current_codec->extra_cap_size)
+ pix_fmt->sizeimage +=
+ ctx->current_codec->extra_cap_size(ctx, pix_fmt);
+
return 0;
}
-static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
+static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
+ return cedrus_try_fmt_vid_cap_p(cedrus_file2ctx(file), &f->fmt.pix);
+}
+
+static int cedrus_try_fmt_vid_out_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
+{
struct cedrus_format *fmt =
- cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC,
- dev->capabilities);
+ cedrus_find_format(ctx, pix_fmt->pixelformat,
+ CEDRUS_DECODE_SRC);
if (!fmt)
return -EINVAL;
@@ -281,6 +279,12 @@ static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
return 0;
}
+static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return cedrus_try_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
+}
+
static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -301,18 +305,76 @@ static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
+void cedrus_reset_cap_format(struct cedrus_ctx *ctx)
+{
+ ctx->dst_fmt.pixelformat = 0;
+ cedrus_try_fmt_vid_cap_p(ctx, &ctx->dst_fmt);
+}
+
+static int cedrus_s_fmt_vid_out_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
struct vb2_queue *vq;
- struct vb2_queue *peer_vq;
int ret;
- ret = cedrus_try_fmt_vid_out(file, priv, f);
+ ret = cedrus_try_fmt_vid_out_p(ctx, pix_fmt);
if (ret)
return ret;
+ ctx->src_fmt = *pix_fmt;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ vq->subsystem_flags |=
+ VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+ break;
+ default:
+ vq->subsystem_flags &=
+ ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+ break;
+ }
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_mpeg2;
+ break;
+ case V4L2_PIX_FMT_H264_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_h264;
+ break;
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_h265;
+ break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ ctx->current_codec = &cedrus_dec_ops_vp8;
+ break;
+ }
+
+ /* Propagate format information to capture. */
+ ctx->dst_fmt.colorspace = pix_fmt->colorspace;
+ ctx->dst_fmt.xfer_func = pix_fmt->xfer_func;
+ ctx->dst_fmt.ycbcr_enc = pix_fmt->ycbcr_enc;
+ ctx->dst_fmt.quantization = pix_fmt->quantization;
+ cedrus_reset_cap_format(ctx);
+
+ return 0;
+}
+
+void cedrus_reset_out_format(struct cedrus_ctx *ctx)
+{
+ ctx->src_fmt.pixelformat = 0;
+ cedrus_s_fmt_vid_out_p(ctx, &ctx->src_fmt);
+}
+
+static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct vb2_queue *vq;
+ struct vb2_queue *peer_vq;
+
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
/*
* In order to support dynamic resolution change,
@@ -332,34 +394,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
if (vb2_is_busy(peer_vq))
return -EBUSY;
- ret = cedrus_try_fmt_vid_out(file, priv, f);
- if (ret)
- return ret;
-
- ctx->src_fmt = f->fmt.pix;
-
- switch (ctx->src_fmt.pixelformat) {
- case V4L2_PIX_FMT_H264_SLICE:
- case V4L2_PIX_FMT_HEVC_SLICE:
- vq->subsystem_flags |=
- VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
- break;
- default:
- vq->subsystem_flags &=
- ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
- break;
- }
-
- /* Propagate format information to capture. */
- ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
- ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
- ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
- ctx->dst_fmt.quantization = f->fmt.pix.quantization;
- ctx->dst_fmt.width = ctx->src_fmt.width;
- ctx->dst_fmt.height = ctx->src_fmt.height;
- cedrus_prepare_format(&ctx->dst_fmt);
-
- return 0;
+ return cedrus_s_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
}
const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
@@ -475,34 +510,13 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
struct cedrus_dev *dev = ctx->dev;
int ret = 0;
- switch (ctx->src_fmt.pixelformat) {
- case V4L2_PIX_FMT_MPEG2_SLICE:
- ctx->current_codec = CEDRUS_CODEC_MPEG2;
- break;
-
- case V4L2_PIX_FMT_H264_SLICE:
- ctx->current_codec = CEDRUS_CODEC_H264;
- break;
-
- case V4L2_PIX_FMT_HEVC_SLICE:
- ctx->current_codec = CEDRUS_CODEC_H265;
- break;
-
- case V4L2_PIX_FMT_VP8_FRAME:
- ctx->current_codec = CEDRUS_CODEC_VP8;
- break;
-
- default:
- return -EINVAL;
- }
-
if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
ret = pm_runtime_resume_and_get(dev->dev);
if (ret < 0)
goto err_cleanup;
- if (dev->dec_ops[ctx->current_codec]->start) {
- ret = dev->dec_ops[ctx->current_codec]->start(ctx);
+ if (ctx->current_codec->start) {
+ ret = ctx->current_codec->start(ctx);
if (ret)
goto err_pm;
}
@@ -524,8 +538,8 @@ static void cedrus_stop_streaming(struct vb2_queue *vq)
struct cedrus_dev *dev = ctx->dev;
if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
- if (dev->dec_ops[ctx->current_codec]->stop)
- dev->dec_ops[ctx->current_codec]->stop(ctx);
+ if (ctx->current_codec->stop)
+ ctx->current_codec->stop(ctx);
pm_runtime_put(dev->dev);
}
@@ -548,7 +562,7 @@ static void cedrus_buf_request_complete(struct vb2_buffer *vb)
v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
}
-static struct vb2_ops cedrus_qops = {
+static const struct vb2_ops cedrus_qops = {
.queue_setup = cedrus_queue_setup,
.buf_prepare = cedrus_buf_prepare,
.buf_queue = cedrus_buf_queue,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
index 05050c0a0921..8e1afc16a6a1 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
@@ -27,5 +27,7 @@ extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt);
+void cedrus_reset_cap_format(struct cedrus_ctx *ctx);
+void cedrus_reset_out_format(struct cedrus_ctx *ctx);
#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
index f7714baae37d..969677a3bbf9 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
@@ -662,7 +662,7 @@ static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
int header_size;
u32 reg;
- cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8);
+ cedrus_engine_enable(ctx);
cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);
diff --git a/drivers/staging/media/sunxi/sun6i-isp/Kconfig b/drivers/staging/media/sunxi/sun6i-isp/Kconfig
new file mode 100644
index 000000000000..68dcae9cd7d7
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_SUN6I_ISP
+ tristate "Allwinner A31 Image Signal Processor (ISP) Driver"
+ depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on PM && COMMON_CLK && HAS_DMA
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
+ select V4L2_FWNODE
+ select REGMAP_MMIO
+ help
+ Support for the Allwinner A31 Image Signal Processor (ISP), also
+ found on other platforms such as the A80, A83T or V3/V3s.
diff --git a/drivers/staging/media/sunxi/sun6i-isp/Makefile b/drivers/staging/media/sunxi/sun6i-isp/Makefile
new file mode 100644
index 000000000000..da1034785144
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+sun6i-isp-y += sun6i_isp.o sun6i_isp_proc.o sun6i_isp_capture.o sun6i_isp_params.o
+
+obj-$(CONFIG_VIDEO_SUN6I_ISP) += sun6i-isp.o
diff --git a/drivers/staging/media/sunxi/sun6i-isp/TODO.txt b/drivers/staging/media/sunxi/sun6i-isp/TODO.txt
new file mode 100644
index 000000000000..1e3236edc1ab
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/TODO.txt
@@ -0,0 +1,6 @@
+Unstaging requirements:
+- Add uAPI support and documentation for the configuration of all the hardware
+ modules and description of the statistics data structures;
+- Add support for statistics reporting;
+- Add userspace support in libcamera which demonstrates the ability to receive
+ statistics and adapt hardware modules configuration accordingly;
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c
new file mode 100644
index 000000000000..7b7947509b69
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mc.h>
+
+#include "sun6i_isp.h"
+#include "sun6i_isp_capture.h"
+#include "sun6i_isp_params.h"
+#include "sun6i_isp_proc.h"
+#include "sun6i_isp_reg.h"
+
+/* Helpers */
+
+u32 sun6i_isp_load_read(struct sun6i_isp_device *isp_dev, u32 offset)
+{
+ u32 *data = (u32 *)(isp_dev->tables.load.data + offset);
+
+ return *data;
+}
+
+void sun6i_isp_load_write(struct sun6i_isp_device *isp_dev, u32 offset,
+ u32 value)
+{
+ u32 *data = (u32 *)(isp_dev->tables.load.data + offset);
+
+ *data = value;
+}
+
+/* State */
+
+/*
+ * The ISP works with a load buffer, which gets copied to the actual registers
+ * by the hardware before processing a frame when a specific flag is set.
+ * This is represented by tracking the ISP state in the different parts of
+ * the code with explicit sync points:
+ * - state update: to update the load buffer for the next frame if necessary;
+ * - state complete: to indicate that the state update was applied.
+ */
+
+static void sun6i_isp_state_ready(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+ u32 value;
+
+ regmap_read(regmap, SUN6I_ISP_FE_CTRL_REG, &value);
+ value |= SUN6I_ISP_FE_CTRL_PARA_READY;
+ regmap_write(regmap, SUN6I_ISP_FE_CTRL_REG, value);
+}
+
+static void sun6i_isp_state_complete(struct sun6i_isp_device *isp_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp_dev->state_lock, flags);
+
+ sun6i_isp_capture_state_complete(isp_dev);
+ sun6i_isp_params_state_complete(isp_dev);
+
+ spin_unlock_irqrestore(&isp_dev->state_lock, flags);
+}
+
+void sun6i_isp_state_update(struct sun6i_isp_device *isp_dev, bool ready_hold)
+{
+ bool update = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp_dev->state_lock, flags);
+
+ sun6i_isp_capture_state_update(isp_dev, &update);
+ sun6i_isp_params_state_update(isp_dev, &update);
+
+ if (update && !ready_hold)
+ sun6i_isp_state_ready(isp_dev);
+
+ spin_unlock_irqrestore(&isp_dev->state_lock, flags);
+}
+
+/* Tables */
+
+static int sun6i_isp_table_setup(struct sun6i_isp_device *isp_dev,
+ struct sun6i_isp_table *table)
+{
+ table->data = dma_alloc_coherent(isp_dev->dev, table->size,
+ &table->address, GFP_KERNEL);
+ if (!table->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void sun6i_isp_table_cleanup(struct sun6i_isp_device *isp_dev,
+ struct sun6i_isp_table *table)
+{
+ dma_free_coherent(isp_dev->dev, table->size, table->data,
+ table->address);
+}
+
+void sun6i_isp_tables_configure(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+
+ regmap_write(regmap, SUN6I_ISP_REG_LOAD_ADDR_REG,
+ SUN6I_ISP_ADDR_VALUE(isp_dev->tables.load.address));
+
+ regmap_write(regmap, SUN6I_ISP_REG_SAVE_ADDR_REG,
+ SUN6I_ISP_ADDR_VALUE(isp_dev->tables.save.address));
+
+ regmap_write(regmap, SUN6I_ISP_LUT_TABLE_ADDR_REG,
+ SUN6I_ISP_ADDR_VALUE(isp_dev->tables.lut.address));
+
+ regmap_write(regmap, SUN6I_ISP_DRC_TABLE_ADDR_REG,
+ SUN6I_ISP_ADDR_VALUE(isp_dev->tables.drc.address));
+
+ regmap_write(regmap, SUN6I_ISP_STATS_ADDR_REG,
+ SUN6I_ISP_ADDR_VALUE(isp_dev->tables.stats.address));
+}
+
+static int sun6i_isp_tables_setup(struct sun6i_isp_device *isp_dev,
+ const struct sun6i_isp_variant *variant)
+{
+ struct sun6i_isp_tables *tables = &isp_dev->tables;
+ int ret;
+
+ tables->load.size = variant->table_load_save_size;
+ ret = sun6i_isp_table_setup(isp_dev, &tables->load);
+ if (ret)
+ return ret;
+
+ tables->save.size = variant->table_load_save_size;
+ ret = sun6i_isp_table_setup(isp_dev, &tables->save);
+ if (ret)
+ return ret;
+
+ tables->lut.size = variant->table_lut_size;
+ ret = sun6i_isp_table_setup(isp_dev, &tables->lut);
+ if (ret)
+ return ret;
+
+ tables->drc.size = variant->table_drc_size;
+ ret = sun6i_isp_table_setup(isp_dev, &tables->drc);
+ if (ret)
+ return ret;
+
+ tables->stats.size = variant->table_stats_size;
+ ret = sun6i_isp_table_setup(isp_dev, &tables->stats);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void sun6i_isp_tables_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_tables *tables = &isp_dev->tables;
+
+ sun6i_isp_table_cleanup(isp_dev, &tables->stats);
+ sun6i_isp_table_cleanup(isp_dev, &tables->drc);
+ sun6i_isp_table_cleanup(isp_dev, &tables->lut);
+ sun6i_isp_table_cleanup(isp_dev, &tables->save);
+ sun6i_isp_table_cleanup(isp_dev, &tables->load);
+}
+
+/* Media */
+
+static const struct media_device_ops sun6i_isp_media_ops = {
+ .link_notify = v4l2_pipeline_link_notify,
+};
+
+/* V4L2 */
+
+static int sun6i_isp_v4l2_setup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_v4l2 *v4l2 = &isp_dev->v4l2;
+ struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
+ struct media_device *media_dev = &v4l2->media_dev;
+ struct device *dev = isp_dev->dev;
+ int ret;
+
+ /* Media Device */
+
+ strscpy(media_dev->model, SUN6I_ISP_DESCRIPTION,
+ sizeof(media_dev->model));
+ media_dev->ops = &sun6i_isp_media_ops;
+ media_dev->hw_revision = 0;
+ media_dev->dev = dev;
+
+ media_device_init(media_dev);
+
+ ret = media_device_register(media_dev);
+ if (ret) {
+ dev_err(dev, "failed to register media device\n");
+ return ret;
+ }
+
+ /* V4L2 Device */
+
+ v4l2_dev->mdev = media_dev;
+
+ ret = v4l2_device_register(dev, v4l2_dev);
+ if (ret) {
+ dev_err(dev, "failed to register v4l2 device\n");
+ goto error_media;
+ }
+
+ return 0;
+
+error_media:
+ media_device_unregister(media_dev);
+ media_device_cleanup(media_dev);
+
+ return ret;
+}
+
+static void sun6i_isp_v4l2_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_v4l2 *v4l2 = &isp_dev->v4l2;
+
+ media_device_unregister(&v4l2->media_dev);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
+ media_device_cleanup(&v4l2->media_dev);
+}
+
+/* Platform */
+
+static irqreturn_t sun6i_isp_interrupt(int irq, void *private)
+{
+ struct sun6i_isp_device *isp_dev = private;
+ struct regmap *regmap = isp_dev->regmap;
+ u32 status = 0, enable = 0;
+
+ regmap_read(regmap, SUN6I_ISP_FE_INT_STA_REG, &status);
+ regmap_read(regmap, SUN6I_ISP_FE_INT_EN_REG, &enable);
+
+ if (!status)
+ return IRQ_NONE;
+ else if (!(status & enable))
+ goto complete;
+
+ /*
+ * The ISP working cycle starts with a params-load, which makes the
+ * state from the load buffer active. Then it starts processing the
+ * frame and gives a finish interrupt. Soon after that, the next state
+ * coming from the load buffer will be applied for the next frame,
+ * giving a params-load as well.
+ *
+ * Because both frame finish and params-load are received almost
+ * at the same time (one ISR call), handle them in chronology order.
+ */
+
+ if (status & SUN6I_ISP_FE_INT_STA_FINISH)
+ sun6i_isp_capture_finish(isp_dev);
+
+ if (status & SUN6I_ISP_FE_INT_STA_PARA_LOAD) {
+ sun6i_isp_state_complete(isp_dev);
+ sun6i_isp_state_update(isp_dev, false);
+ }
+
+complete:
+ regmap_write(regmap, SUN6I_ISP_FE_INT_STA_REG, status);
+
+ return IRQ_HANDLED;
+}
+
+static int sun6i_isp_suspend(struct device *dev)
+{
+ struct sun6i_isp_device *isp_dev = dev_get_drvdata(dev);
+
+ reset_control_assert(isp_dev->reset);
+ clk_disable_unprepare(isp_dev->clock_ram);
+ clk_disable_unprepare(isp_dev->clock_mod);
+
+ return 0;
+}
+
+static int sun6i_isp_resume(struct device *dev)
+{
+ struct sun6i_isp_device *isp_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(isp_dev->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(isp_dev->clock_mod);
+ if (ret) {
+ dev_err(dev, "failed to enable module clock\n");
+ goto error_reset;
+ }
+
+ ret = clk_prepare_enable(isp_dev->clock_ram);
+ if (ret) {
+ dev_err(dev, "failed to enable ram clock\n");
+ goto error_clock_mod;
+ }
+
+ return 0;
+
+error_clock_mod:
+ clk_disable_unprepare(isp_dev->clock_mod);
+
+error_reset:
+ reset_control_assert(isp_dev->reset);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sun6i_isp_pm_ops = {
+ .runtime_suspend = sun6i_isp_suspend,
+ .runtime_resume = sun6i_isp_resume,
+};
+
+static const struct regmap_config sun6i_isp_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x400,
+};
+
+static int sun6i_isp_resources_setup(struct sun6i_isp_device *isp_dev,
+ struct platform_device *platform_dev)
+{
+ struct device *dev = isp_dev->dev;
+ void __iomem *io_base;
+ int irq;
+ int ret;
+
+ /* Registers */
+
+ io_base = devm_platform_ioremap_resource(platform_dev, 0);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ isp_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base,
+ &sun6i_isp_regmap_config);
+ if (IS_ERR(isp_dev->regmap)) {
+ dev_err(dev, "failed to init register map\n");
+ return PTR_ERR(isp_dev->regmap);
+ }
+
+ /* Clocks */
+
+ isp_dev->clock_mod = devm_clk_get(dev, "mod");
+ if (IS_ERR(isp_dev->clock_mod)) {
+ dev_err(dev, "failed to acquire module clock\n");
+ return PTR_ERR(isp_dev->clock_mod);
+ }
+
+ isp_dev->clock_ram = devm_clk_get(dev, "ram");
+ if (IS_ERR(isp_dev->clock_ram)) {
+ dev_err(dev, "failed to acquire ram clock\n");
+ return PTR_ERR(isp_dev->clock_ram);
+ }
+
+ ret = clk_set_rate_exclusive(isp_dev->clock_mod, 297000000);
+ if (ret) {
+ dev_err(dev, "failed to set mod clock rate\n");
+ return ret;
+ }
+
+ /* Reset */
+
+ isp_dev->reset = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(isp_dev->reset)) {
+ dev_err(dev, "failed to acquire reset\n");
+ ret = PTR_ERR(isp_dev->reset);
+ goto error_clock_rate_exclusive;
+ }
+
+ /* Interrupt */
+
+ irq = platform_get_irq(platform_dev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get interrupt\n");
+ ret = -ENXIO;
+ goto error_clock_rate_exclusive;
+ }
+
+ ret = devm_request_irq(dev, irq, sun6i_isp_interrupt, IRQF_SHARED,
+ SUN6I_ISP_NAME, isp_dev);
+ if (ret) {
+ dev_err(dev, "failed to request interrupt\n");
+ goto error_clock_rate_exclusive;
+ }
+
+ /* Runtime PM */
+
+ pm_runtime_enable(dev);
+
+ return 0;
+
+error_clock_rate_exclusive:
+ clk_rate_exclusive_put(isp_dev->clock_mod);
+
+ return ret;
+}
+
+static void sun6i_isp_resources_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct device *dev = isp_dev->dev;
+
+ pm_runtime_disable(dev);
+ clk_rate_exclusive_put(isp_dev->clock_mod);
+}
+
+static int sun6i_isp_probe(struct platform_device *platform_dev)
+{
+ struct sun6i_isp_device *isp_dev;
+ struct device *dev = &platform_dev->dev;
+ const struct sun6i_isp_variant *variant;
+ int ret;
+
+ variant = of_device_get_match_data(dev);
+ if (!variant)
+ return -EINVAL;
+
+ isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL);
+ if (!isp_dev)
+ return -ENOMEM;
+
+ isp_dev->dev = dev;
+ platform_set_drvdata(platform_dev, isp_dev);
+
+ spin_lock_init(&isp_dev->state_lock);
+
+ ret = sun6i_isp_resources_setup(isp_dev, platform_dev);
+ if (ret)
+ return ret;
+
+ ret = sun6i_isp_tables_setup(isp_dev, variant);
+ if (ret) {
+ dev_err(dev, "failed to setup tables\n");
+ goto error_resources;
+ }
+
+ ret = sun6i_isp_v4l2_setup(isp_dev);
+ if (ret) {
+ dev_err(dev, "failed to setup v4l2\n");
+ goto error_tables;
+ }
+
+ ret = sun6i_isp_proc_setup(isp_dev);
+ if (ret) {
+ dev_err(dev, "failed to setup proc\n");
+ goto error_v4l2;
+ }
+
+ ret = sun6i_isp_capture_setup(isp_dev);
+ if (ret) {
+ dev_err(dev, "failed to setup capture\n");
+ goto error_proc;
+ }
+
+ ret = sun6i_isp_params_setup(isp_dev);
+ if (ret) {
+ dev_err(dev, "failed to setup params\n");
+ goto error_capture;
+ }
+
+ return 0;
+
+error_capture:
+ sun6i_isp_capture_cleanup(isp_dev);
+
+error_proc:
+ sun6i_isp_proc_cleanup(isp_dev);
+
+error_v4l2:
+ sun6i_isp_v4l2_cleanup(isp_dev);
+
+error_tables:
+ sun6i_isp_tables_cleanup(isp_dev);
+
+error_resources:
+ sun6i_isp_resources_cleanup(isp_dev);
+
+ return ret;
+}
+
+static int sun6i_isp_remove(struct platform_device *platform_dev)
+{
+ struct sun6i_isp_device *isp_dev = platform_get_drvdata(platform_dev);
+
+ sun6i_isp_params_cleanup(isp_dev);
+ sun6i_isp_capture_cleanup(isp_dev);
+ sun6i_isp_proc_cleanup(isp_dev);
+ sun6i_isp_v4l2_cleanup(isp_dev);
+ sun6i_isp_tables_cleanup(isp_dev);
+ sun6i_isp_resources_cleanup(isp_dev);
+
+ return 0;
+}
+
+/*
+ * History of sun6i-isp:
+ * - sun4i-a10-isp: initial ISP tied to the CSI0 controller,
+ * apparently unused in software implementations;
+ * - sun6i-a31-isp: separate ISP loosely based on sun4i-a10-isp,
+ * adding extra modules and features;
+ * - sun9i-a80-isp: based on sun6i-a31-isp with some register offset changes
+ * and new modules like saturation and cnr;
+ * - sun8i-a23-isp/sun8i-h3-isp: based on sun9i-a80-isp with most modules
+ * related to raw removed;
+ * - sun8i-a83t-isp: based on sun9i-a80-isp with some register offset changes
+ * - sun8i-v3s-isp: based on sun8i-a83t-isp with a new disc module;
+ */
+
+static const struct sun6i_isp_variant sun8i_v3s_isp_variant = {
+ .table_load_save_size = 0x1000,
+ .table_lut_size = 0xe00,
+ .table_drc_size = 0x600,
+ .table_stats_size = 0x2100,
+};
+
+static const struct of_device_id sun6i_isp_of_match[] = {
+ {
+ .compatible = "allwinner,sun8i-v3s-isp",
+ .data = &sun8i_v3s_isp_variant,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sun6i_isp_of_match);
+
+static struct platform_driver sun6i_isp_platform_driver = {
+ .probe = sun6i_isp_probe,
+ .remove = sun6i_isp_remove,
+ .driver = {
+ .name = SUN6I_ISP_NAME,
+ .of_match_table = of_match_ptr(sun6i_isp_of_match),
+ .pm = &sun6i_isp_pm_ops,
+ },
+};
+
+module_platform_driver(sun6i_isp_platform_driver);
+
+MODULE_DESCRIPTION("Allwinner A31 Image Signal Processor driver");
+MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.h
new file mode 100644
index 000000000000..0e5f188319ff
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_ISP_H_
+#define _SUN6I_ISP_H_
+
+#include <media/v4l2-device.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun6i_isp_capture.h"
+#include "sun6i_isp_params.h"
+#include "sun6i_isp_proc.h"
+
+#define SUN6I_ISP_NAME "sun6i-isp"
+#define SUN6I_ISP_DESCRIPTION "Allwinner A31 ISP Device"
+
+enum sun6i_isp_port {
+ SUN6I_ISP_PORT_CSI0 = 0,
+ SUN6I_ISP_PORT_CSI1 = 1,
+};
+
+struct sun6i_isp_buffer {
+ struct vb2_v4l2_buffer v4l2_buffer;
+ struct list_head list;
+};
+
+struct sun6i_isp_v4l2 {
+ struct v4l2_device v4l2_dev;
+ struct media_device media_dev;
+};
+
+struct sun6i_isp_table {
+ void *data;
+ dma_addr_t address;
+ unsigned int size;
+};
+
+struct sun6i_isp_tables {
+ struct sun6i_isp_table load;
+ struct sun6i_isp_table save;
+
+ struct sun6i_isp_table lut;
+ struct sun6i_isp_table drc;
+ struct sun6i_isp_table stats;
+};
+
+struct sun6i_isp_device {
+ struct device *dev;
+
+ struct sun6i_isp_tables tables;
+
+ struct sun6i_isp_v4l2 v4l2;
+ struct sun6i_isp_proc proc;
+ struct sun6i_isp_capture capture;
+ struct sun6i_isp_params params;
+
+ struct regmap *regmap;
+ struct clk *clock_mod;
+ struct clk *clock_ram;
+ struct reset_control *reset;
+
+ spinlock_t state_lock; /* State helpers lock. */
+};
+
+struct sun6i_isp_variant {
+ unsigned int table_load_save_size;
+ unsigned int table_lut_size;
+ unsigned int table_drc_size;
+ unsigned int table_stats_size;
+};
+
+/* Helpers */
+
+u32 sun6i_isp_load_read(struct sun6i_isp_device *isp_dev, u32 offset);
+void sun6i_isp_load_write(struct sun6i_isp_device *isp_dev, u32 offset,
+ u32 value);
+u32 sun6i_isp_address_value(dma_addr_t address);
+
+/* State */
+
+void sun6i_isp_state_update(struct sun6i_isp_device *isp_dev, bool ready_hold);
+
+/* Tables */
+
+void sun6i_isp_tables_configure(struct sun6i_isp_device *isp_dev);
+
+#endif
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c
new file mode 100644
index 000000000000..4b592820845a
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun6i_isp.h"
+#include "sun6i_isp_capture.h"
+#include "sun6i_isp_proc.h"
+#include "sun6i_isp_reg.h"
+
+/* Helpers */
+
+void sun6i_isp_capture_dimensions(struct sun6i_isp_device *isp_dev,
+ unsigned int *width, unsigned int *height)
+{
+ if (width)
+ *width = isp_dev->capture.format.fmt.pix.width;
+ if (height)
+ *height = isp_dev->capture.format.fmt.pix.height;
+}
+
+void sun6i_isp_capture_format(struct sun6i_isp_device *isp_dev,
+ u32 *pixelformat)
+{
+ if (pixelformat)
+ *pixelformat = isp_dev->capture.format.fmt.pix.pixelformat;
+}
+
+/* Format */
+
+static const struct sun6i_isp_capture_format sun6i_isp_capture_formats[] = {
+ {
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .output_format = SUN6I_ISP_OUTPUT_FMT_YUV420SP,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .output_format = SUN6I_ISP_OUTPUT_FMT_YVU420SP,
+ },
+};
+
+const struct sun6i_isp_capture_format *
+sun6i_isp_capture_format_find(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_isp_capture_formats); i++)
+ if (sun6i_isp_capture_formats[i].pixelformat == pixelformat)
+ return &sun6i_isp_capture_formats[i];
+
+ return NULL;
+}
+
+/* Capture */
+
+static void
+sun6i_isp_capture_buffer_configure(struct sun6i_isp_device *isp_dev,
+ struct sun6i_isp_buffer *isp_buffer)
+{
+ const struct v4l2_format_info *info;
+ struct vb2_buffer *vb2_buffer;
+ unsigned int width, height;
+ unsigned int width_aligned;
+ dma_addr_t address;
+ u32 pixelformat;
+
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+ address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MCH_Y_ADDR0_REG,
+ SUN6I_ISP_ADDR_VALUE(address));
+
+ sun6i_isp_capture_dimensions(isp_dev, &width, &height);
+ sun6i_isp_capture_format(isp_dev, &pixelformat);
+
+ info = v4l2_format_info(pixelformat);
+ if (WARN_ON(!info))
+ return;
+
+ /* Stride needs to be aligned to 4. */
+ width_aligned = ALIGN(width, 2);
+
+ if (info->comp_planes > 1) {
+ address += info->bpp[0] * width_aligned * height;
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MCH_U_ADDR0_REG,
+ SUN6I_ISP_ADDR_VALUE(address));
+ }
+
+ if (info->comp_planes > 2) {
+ address += info->bpp[1] *
+ DIV_ROUND_UP(width_aligned, info->hdiv) *
+ DIV_ROUND_UP(height, info->vdiv);
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MCH_V_ADDR0_REG,
+ SUN6I_ISP_ADDR_VALUE(address));
+ }
+}
+
+void sun6i_isp_capture_configure(struct sun6i_isp_device *isp_dev)
+{
+ unsigned int width, height;
+ unsigned int stride_luma, stride_chroma = 0;
+ unsigned int stride_luma_div4, stride_chroma_div4;
+ const struct sun6i_isp_capture_format *format;
+ const struct v4l2_format_info *info;
+ u32 pixelformat;
+
+ sun6i_isp_capture_dimensions(isp_dev, &width, &height);
+ sun6i_isp_capture_format(isp_dev, &pixelformat);
+
+ format = sun6i_isp_capture_format_find(pixelformat);
+ if (WARN_ON(!format))
+ return;
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MCH_SIZE_CFG_REG,
+ SUN6I_ISP_MCH_SIZE_CFG_WIDTH(width) |
+ SUN6I_ISP_MCH_SIZE_CFG_HEIGHT(height));
+
+ info = v4l2_format_info(pixelformat);
+ if (WARN_ON(!info))
+ return;
+
+ stride_luma = width * info->bpp[0];
+ stride_luma_div4 = DIV_ROUND_UP(stride_luma, 4);
+
+ if (info->comp_planes > 1) {
+ stride_chroma = width * info->bpp[1] / info->hdiv;
+ stride_chroma_div4 = DIV_ROUND_UP(stride_chroma, 4);
+ }
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MCH_CFG_REG,
+ SUN6I_ISP_MCH_CFG_EN |
+ SUN6I_ISP_MCH_CFG_OUTPUT_FMT(format->output_format) |
+ SUN6I_ISP_MCH_CFG_STRIDE_Y_DIV4(stride_luma_div4) |
+ SUN6I_ISP_MCH_CFG_STRIDE_UV_DIV4(stride_chroma_div4));
+}
+
+/* State */
+
+static void sun6i_isp_capture_state_cleanup(struct sun6i_isp_device *isp_dev,
+ bool error)
+{
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ struct sun6i_isp_buffer **isp_buffer_states[] = {
+ &state->pending, &state->current, &state->complete,
+ };
+ struct sun6i_isp_buffer *isp_buffer;
+ struct vb2_buffer *vb2_buffer;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(isp_buffer_states); i++) {
+ isp_buffer = *isp_buffer_states[i];
+ if (!isp_buffer)
+ continue;
+
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+
+ *isp_buffer_states[i] = NULL;
+ }
+
+ list_for_each_entry(isp_buffer, &state->queue, list) {
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+ }
+
+ INIT_LIST_HEAD(&state->queue);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_isp_capture_state_update(struct sun6i_isp_device *isp_dev,
+ bool *update)
+{
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ struct sun6i_isp_buffer *isp_buffer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (list_empty(&state->queue))
+ goto complete;
+
+ if (state->pending)
+ goto complete;
+
+ isp_buffer = list_first_entry(&state->queue, struct sun6i_isp_buffer,
+ list);
+
+ sun6i_isp_capture_buffer_configure(isp_dev, isp_buffer);
+
+ list_del(&isp_buffer->list);
+
+ state->pending = isp_buffer;
+
+ if (update)
+ *update = true;
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_isp_capture_state_complete(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (!state->pending)
+ goto complete;
+
+ state->complete = state->current;
+ state->current = state->pending;
+ state->pending = NULL;
+
+ if (state->complete) {
+ struct sun6i_isp_buffer *isp_buffer = state->complete;
+ struct vb2_buffer *vb2_buffer =
+ &isp_buffer->v4l2_buffer.vb2_buf;
+
+ vb2_buffer->timestamp = ktime_get_ns();
+ isp_buffer->v4l2_buffer.sequence = state->sequence;
+
+ vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
+
+ state->complete = NULL;
+ }
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_isp_capture_finish(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+ state->sequence++;
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+/* Queue */
+
+static int sun6i_isp_capture_queue_setup(struct vb2_queue *queue,
+ unsigned int *buffers_count,
+ unsigned int *planes_count,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ unsigned int size = isp_dev->capture.format.fmt.pix.sizeimage;
+
+ if (*planes_count)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *planes_count = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static int sun6i_isp_capture_buffer_prepare(struct vb2_buffer *vb2_buffer)
+{
+ struct sun6i_isp_device *isp_dev =
+ vb2_get_drv_priv(vb2_buffer->vb2_queue);
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ unsigned int size = isp_dev->capture.format.fmt.pix.sizeimage;
+
+ if (vb2_plane_size(vb2_buffer, 0) < size) {
+ v4l2_err(v4l2_dev, "buffer too small (%lu < %u)\n",
+ vb2_plane_size(vb2_buffer, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb2_buffer, 0, size);
+
+ return 0;
+}
+
+static void sun6i_isp_capture_buffer_queue(struct vb2_buffer *vb2_buffer)
+{
+ struct sun6i_isp_device *isp_dev =
+ vb2_get_drv_priv(vb2_buffer->vb2_queue);
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(vb2_buffer);
+ struct sun6i_isp_buffer *isp_buffer =
+ container_of(v4l2_buffer, struct sun6i_isp_buffer, v4l2_buffer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+ list_add_tail(&isp_buffer->list, &state->queue);
+ spin_unlock_irqrestore(&state->lock, flags);
+
+ /* Update the state to schedule our buffer as soon as possible. */
+ if (state->streaming)
+ sun6i_isp_state_update(isp_dev, false);
+}
+
+static int sun6i_isp_capture_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ struct video_device *video_dev = &isp_dev->capture.video_dev;
+ struct v4l2_subdev *subdev = &isp_dev->proc.subdev;
+ int ret;
+
+ state->sequence = 0;
+
+ ret = video_device_pipeline_alloc_start(video_dev);
+ if (ret < 0)
+ goto error_state;
+
+ state->streaming = true;
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto error_streaming;
+
+ return 0;
+
+error_streaming:
+ state->streaming = false;
+
+ video_device_pipeline_stop(video_dev);
+
+error_state:
+ sun6i_isp_capture_state_cleanup(isp_dev, false);
+
+ return ret;
+}
+
+static void sun6i_isp_capture_stop_streaming(struct vb2_queue *queue)
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ struct sun6i_isp_capture_state *state = &isp_dev->capture.state;
+ struct video_device *video_dev = &isp_dev->capture.video_dev;
+ struct v4l2_subdev *subdev = &isp_dev->proc.subdev;
+
+ v4l2_subdev_call(subdev, video, s_stream, 0);
+
+ state->streaming = false;
+
+ video_device_pipeline_stop(video_dev);
+
+ sun6i_isp_capture_state_cleanup(isp_dev, true);
+}
+
+static const struct vb2_ops sun6i_isp_capture_queue_ops = {
+ .queue_setup = sun6i_isp_capture_queue_setup,
+ .buf_prepare = sun6i_isp_capture_buffer_prepare,
+ .buf_queue = sun6i_isp_capture_buffer_queue,
+ .start_streaming = sun6i_isp_capture_start_streaming,
+ .stop_streaming = sun6i_isp_capture_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* Video Device */
+
+static void sun6i_isp_capture_format_prepare(struct v4l2_format *format)
+{
+ struct v4l2_pix_format *pix_format = &format->fmt.pix;
+ const struct v4l2_format_info *info;
+ unsigned int width, height;
+ unsigned int width_aligned;
+ unsigned int i;
+
+ v4l_bound_align_image(&pix_format->width, SUN6I_ISP_CAPTURE_WIDTH_MIN,
+ SUN6I_ISP_CAPTURE_WIDTH_MAX, 1,
+ &pix_format->height, SUN6I_ISP_CAPTURE_HEIGHT_MIN,
+ SUN6I_ISP_CAPTURE_HEIGHT_MAX, 1, 0);
+
+ if (!sun6i_isp_capture_format_find(pix_format->pixelformat))
+ pix_format->pixelformat =
+ sun6i_isp_capture_formats[0].pixelformat;
+
+ info = v4l2_format_info(pix_format->pixelformat);
+ if (WARN_ON(!info))
+ return;
+
+ width = pix_format->width;
+ height = pix_format->height;
+
+ /* Stride needs to be aligned to 4. */
+ width_aligned = ALIGN(width, 2);
+
+ pix_format->bytesperline = width_aligned * info->bpp[0];
+ pix_format->sizeimage = 0;
+
+ for (i = 0; i < info->comp_planes; i++) {
+ unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
+ unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
+
+ pix_format->sizeimage += info->bpp[i] *
+ DIV_ROUND_UP(width_aligned, hdiv) *
+ DIV_ROUND_UP(height, vdiv);
+ }
+
+ pix_format->field = V4L2_FIELD_NONE;
+
+ pix_format->colorspace = V4L2_COLORSPACE_RAW;
+ pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun6i_isp_capture_querycap(struct file *file, void *private,
+ struct v4l2_capability *capability)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+ struct video_device *video_dev = &isp_dev->capture.video_dev;
+
+ strscpy(capability->driver, SUN6I_ISP_NAME, sizeof(capability->driver));
+ strscpy(capability->card, video_dev->name, sizeof(capability->card));
+ snprintf(capability->bus_info, sizeof(capability->bus_info),
+ "platform:%s", dev_name(isp_dev->dev));
+
+ return 0;
+}
+
+static int sun6i_isp_capture_enum_fmt(struct file *file, void *private,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ u32 index = fmtdesc->index;
+
+ if (index >= ARRAY_SIZE(sun6i_isp_capture_formats))
+ return -EINVAL;
+
+ fmtdesc->pixelformat = sun6i_isp_capture_formats[index].pixelformat;
+
+ return 0;
+}
+
+static int sun6i_isp_capture_g_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+
+ *format = isp_dev->capture.format;
+
+ return 0;
+}
+
+static int sun6i_isp_capture_s_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+
+ if (vb2_is_busy(&isp_dev->capture.queue))
+ return -EBUSY;
+
+ sun6i_isp_capture_format_prepare(format);
+
+ isp_dev->capture.format = *format;
+
+ return 0;
+}
+
+static int sun6i_isp_capture_try_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ sun6i_isp_capture_format_prepare(format);
+
+ return 0;
+}
+
+static int sun6i_isp_capture_enum_input(struct file *file, void *private,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strscpy(input->name, "Camera", sizeof(input->name));
+
+ return 0;
+}
+
+static int sun6i_isp_capture_g_input(struct file *file, void *private,
+ unsigned int *index)
+{
+ *index = 0;
+
+ return 0;
+}
+
+static int sun6i_isp_capture_s_input(struct file *file, void *private,
+ unsigned int index)
+{
+ if (index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops sun6i_isp_capture_ioctl_ops = {
+ .vidioc_querycap = sun6i_isp_capture_querycap,
+
+ .vidioc_enum_fmt_vid_cap = sun6i_isp_capture_enum_fmt,
+ .vidioc_g_fmt_vid_cap = sun6i_isp_capture_g_fmt,
+ .vidioc_s_fmt_vid_cap = sun6i_isp_capture_s_fmt,
+ .vidioc_try_fmt_vid_cap = sun6i_isp_capture_try_fmt,
+
+ .vidioc_enum_input = sun6i_isp_capture_enum_input,
+ .vidioc_g_input = sun6i_isp_capture_g_input,
+ .vidioc_s_input = sun6i_isp_capture_s_input,
+
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static int sun6i_isp_capture_open(struct file *file)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+ struct video_device *video_dev = &isp_dev->capture.video_dev;
+ struct mutex *lock = &isp_dev->capture.lock;
+ int ret;
+
+ if (mutex_lock_interruptible(lock))
+ return -ERESTARTSYS;
+
+ ret = v4l2_pipeline_pm_get(&video_dev->entity);
+ if (ret)
+ goto error_mutex;
+
+ ret = v4l2_fh_open(file);
+ if (ret)
+ goto error_pipeline;
+
+ mutex_unlock(lock);
+
+ return 0;
+
+error_pipeline:
+ v4l2_pipeline_pm_put(&video_dev->entity);
+
+error_mutex:
+ mutex_unlock(lock);
+
+ return ret;
+}
+
+static int sun6i_isp_capture_release(struct file *file)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+ struct video_device *video_dev = &isp_dev->capture.video_dev;
+ struct mutex *lock = &isp_dev->capture.lock;
+
+ mutex_lock(lock);
+
+ _vb2_fop_release(file, NULL);
+ v4l2_pipeline_pm_put(&video_dev->entity);
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations sun6i_isp_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = sun6i_isp_capture_open,
+ .release = sun6i_isp_capture_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+};
+
+/* Media Entity */
+
+static int sun6i_isp_capture_link_validate(struct media_link *link)
+{
+ struct video_device *video_dev =
+ media_entity_to_video_device(link->sink->entity);
+ struct sun6i_isp_device *isp_dev = video_get_drvdata(video_dev);
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ unsigned int capture_width, capture_height;
+ unsigned int proc_width, proc_height;
+
+ sun6i_isp_capture_dimensions(isp_dev, &capture_width, &capture_height);
+ sun6i_isp_proc_dimensions(isp_dev, &proc_width, &proc_height);
+
+ /* No cropping/scaling is supported (yet). */
+ if (capture_width != proc_width || capture_height != proc_height) {
+ v4l2_err(v4l2_dev,
+ "invalid input/output dimensions: %ux%u/%ux%u\n",
+ proc_width, proc_height, capture_width,
+ capture_height);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations sun6i_isp_capture_entity_ops = {
+ .link_validate = sun6i_isp_capture_link_validate,
+};
+
+/* Capture */
+
+int sun6i_isp_capture_setup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_capture *capture = &isp_dev->capture;
+ struct sun6i_isp_capture_state *state = &capture->state;
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ struct v4l2_subdev *proc_subdev = &isp_dev->proc.subdev;
+ struct video_device *video_dev = &capture->video_dev;
+ struct vb2_queue *queue = &capture->queue;
+ struct media_pad *pad = &capture->pad;
+ struct v4l2_format *format = &capture->format;
+ struct v4l2_pix_format *pix_format = &format->fmt.pix;
+ int ret;
+
+ /* State */
+
+ INIT_LIST_HEAD(&state->queue);
+ spin_lock_init(&state->lock);
+
+ /* Media Entity */
+
+ video_dev->entity.ops = &sun6i_isp_capture_entity_ops;
+
+ /* Media Pads */
+
+ pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+
+ ret = media_entity_pads_init(&video_dev->entity, 1, pad);
+ if (ret)
+ goto error_mutex;
+
+ /* Queue */
+
+ mutex_init(&capture->lock);
+
+ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->io_modes = VB2_MMAP | VB2_DMABUF;
+ queue->buf_struct_size = sizeof(struct sun6i_isp_buffer);
+ queue->ops = &sun6i_isp_capture_queue_ops;
+ queue->mem_ops = &vb2_dma_contig_memops;
+ queue->min_buffers_needed = 2;
+ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->lock = &capture->lock;
+ queue->dev = isp_dev->dev;
+ queue->drv_priv = isp_dev;
+
+ ret = vb2_queue_init(queue);
+ if (ret) {
+ v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* V4L2 Format */
+
+ format->type = queue->type;
+ pix_format->pixelformat = sun6i_isp_capture_formats[0].pixelformat;
+ pix_format->width = 1280;
+ pix_format->height = 720;
+
+ sun6i_isp_capture_format_prepare(format);
+
+ /* Video Device */
+
+ strscpy(video_dev->name, SUN6I_ISP_CAPTURE_NAME,
+ sizeof(video_dev->name));
+ video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ video_dev->vfl_dir = VFL_DIR_RX;
+ video_dev->release = video_device_release_empty;
+ video_dev->fops = &sun6i_isp_capture_fops;
+ video_dev->ioctl_ops = &sun6i_isp_capture_ioctl_ops;
+ video_dev->v4l2_dev = v4l2_dev;
+ video_dev->queue = queue;
+ video_dev->lock = &capture->lock;
+
+ video_set_drvdata(video_dev, isp_dev);
+
+ ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev, "failed to register video device: %d\n",
+ ret);
+ goto error_media_entity;
+ }
+
+ /* Media Pad Link */
+
+ ret = media_create_pad_link(&proc_subdev->entity,
+ SUN6I_ISP_PROC_PAD_SOURCE,
+ &video_dev->entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
+ proc_subdev->entity.name, SUN6I_ISP_PROC_PAD_SOURCE,
+ video_dev->entity.name, 0);
+ goto error_video_device;
+ }
+
+ return 0;
+
+error_video_device:
+ vb2_video_unregister_device(video_dev);
+
+error_media_entity:
+ media_entity_cleanup(&video_dev->entity);
+
+error_mutex:
+ mutex_destroy(&capture->lock);
+
+ return ret;
+}
+
+void sun6i_isp_capture_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_capture *capture = &isp_dev->capture;
+ struct video_device *video_dev = &capture->video_dev;
+
+ vb2_video_unregister_device(video_dev);
+ media_entity_cleanup(&video_dev->entity);
+ mutex_destroy(&capture->lock);
+}
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.h
new file mode 100644
index 000000000000..0e3e4fa7a0f4
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_ISP_CAPTURE_H_
+#define _SUN6I_ISP_CAPTURE_H_
+
+#include <media/v4l2-device.h>
+
+#define SUN6I_ISP_CAPTURE_NAME "sun6i-isp-capture"
+
+#define SUN6I_ISP_CAPTURE_WIDTH_MIN 16
+#define SUN6I_ISP_CAPTURE_WIDTH_MAX 3264
+#define SUN6I_ISP_CAPTURE_HEIGHT_MIN 16
+#define SUN6I_ISP_CAPTURE_HEIGHT_MAX 2448
+
+struct sun6i_isp_device;
+
+struct sun6i_isp_capture_format {
+ u32 pixelformat;
+ u8 output_format;
+};
+
+#undef current
+struct sun6i_isp_capture_state {
+ struct list_head queue;
+ spinlock_t lock; /* Queue and buffers lock. */
+
+ struct sun6i_isp_buffer *pending;
+ struct sun6i_isp_buffer *current;
+ struct sun6i_isp_buffer *complete;
+
+ unsigned int sequence;
+ bool streaming;
+};
+
+struct sun6i_isp_capture {
+ struct sun6i_isp_capture_state state;
+
+ struct video_device video_dev;
+ struct vb2_queue queue;
+ struct mutex lock; /* Queue lock. */
+ struct media_pad pad;
+
+ struct v4l2_format format;
+};
+
+/* Helpers */
+
+void sun6i_isp_capture_dimensions(struct sun6i_isp_device *isp_dev,
+ unsigned int *width, unsigned int *height);
+void sun6i_isp_capture_format(struct sun6i_isp_device *isp_dev,
+ u32 *pixelformat);
+
+/* Format */
+
+const struct sun6i_isp_capture_format *
+sun6i_isp_capture_format_find(u32 pixelformat);
+
+/* Capture */
+
+void sun6i_isp_capture_configure(struct sun6i_isp_device *isp_dev);
+
+/* State */
+
+void sun6i_isp_capture_state_update(struct sun6i_isp_device *isp_dev,
+ bool *update);
+void sun6i_isp_capture_state_complete(struct sun6i_isp_device *isp_dev);
+void sun6i_isp_capture_finish(struct sun6i_isp_device *isp_dev);
+
+/* Capture */
+
+int sun6i_isp_capture_setup(struct sun6i_isp_device *isp_dev);
+void sun6i_isp_capture_cleanup(struct sun6i_isp_device *isp_dev);
+
+#endif
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c
new file mode 100644
index 000000000000..8039e311cb1c
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun6i_isp.h"
+#include "sun6i_isp_params.h"
+#include "sun6i_isp_reg.h"
+#include "uapi/sun6i-isp-config.h"
+
+/* Params */
+
+static const struct sun6i_isp_params_config sun6i_isp_params_config_default = {
+ .modules_used = SUN6I_ISP_MODULE_BAYER,
+
+ .bayer = {
+ .offset_r = 32,
+ .offset_gr = 32,
+ .offset_gb = 32,
+ .offset_b = 32,
+
+ .gain_r = 256,
+ .gain_gr = 256,
+ .gain_gb = 256,
+ .gain_b = 256,
+
+ },
+
+ .bdnf = {
+ .in_dis_min = 8,
+ .in_dis_max = 16,
+
+ .coefficients_g = { 15, 4, 1 },
+ .coefficients_rb = { 15, 4 },
+ },
+};
+
+static void sun6i_isp_params_configure_ob(struct sun6i_isp_device *isp_dev)
+{
+ unsigned int width, height;
+
+ sun6i_isp_proc_dimensions(isp_dev, &width, &height);
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SIZE_REG,
+ SUN6I_ISP_OB_SIZE_WIDTH(width) |
+ SUN6I_ISP_OB_SIZE_HEIGHT(height));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_VALID_REG,
+ SUN6I_ISP_OB_VALID_WIDTH(width) |
+ SUN6I_ISP_OB_VALID_HEIGHT(height));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SRC0_VALID_START_REG,
+ SUN6I_ISP_OB_SRC0_VALID_START_HORZ(0) |
+ SUN6I_ISP_OB_SRC0_VALID_START_VERT(0));
+}
+
+static void sun6i_isp_params_configure_ae(struct sun6i_isp_device *isp_dev)
+{
+ /* These are default values that need to be set to get an output. */
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_AE_CFG_REG,
+ SUN6I_ISP_AE_CFG_LOW_BRI_TH(0xff) |
+ SUN6I_ISP_AE_CFG_HORZ_NUM(8) |
+ SUN6I_ISP_AE_CFG_HIGH_BRI_TH(0xf00) |
+ SUN6I_ISP_AE_CFG_VERT_NUM(8));
+}
+
+static void
+sun6i_isp_params_configure_bayer(struct sun6i_isp_device *isp_dev,
+ const struct sun6i_isp_params_config *config)
+{
+ const struct sun6i_isp_params_config_bayer *bayer = &config->bayer;
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET0_REG,
+ SUN6I_ISP_BAYER_OFFSET0_R(bayer->offset_r) |
+ SUN6I_ISP_BAYER_OFFSET0_GR(bayer->offset_gr));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET1_REG,
+ SUN6I_ISP_BAYER_OFFSET1_GB(bayer->offset_gb) |
+ SUN6I_ISP_BAYER_OFFSET1_B(bayer->offset_b));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN0_REG,
+ SUN6I_ISP_BAYER_GAIN0_R(bayer->gain_r) |
+ SUN6I_ISP_BAYER_GAIN0_GR(bayer->gain_gr));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN1_REG,
+ SUN6I_ISP_BAYER_GAIN1_GB(bayer->gain_gb) |
+ SUN6I_ISP_BAYER_GAIN1_B(bayer->gain_b));
+}
+
+static void sun6i_isp_params_configure_wb(struct sun6i_isp_device *isp_dev)
+{
+ /* These are default values that need to be set to get an output. */
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN0_REG,
+ SUN6I_ISP_WB_GAIN0_R(256) |
+ SUN6I_ISP_WB_GAIN0_GR(256));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN1_REG,
+ SUN6I_ISP_WB_GAIN1_GB(256) |
+ SUN6I_ISP_WB_GAIN1_B(256));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_CFG_REG,
+ SUN6I_ISP_WB_CFG_CLIP(0xfff));
+}
+
+static void sun6i_isp_params_configure_base(struct sun6i_isp_device *isp_dev)
+{
+ sun6i_isp_params_configure_ae(isp_dev);
+ sun6i_isp_params_configure_ob(isp_dev);
+ sun6i_isp_params_configure_wb(isp_dev);
+}
+
+static void
+sun6i_isp_params_configure_bdnf(struct sun6i_isp_device *isp_dev,
+ const struct sun6i_isp_params_config *config)
+{
+ const struct sun6i_isp_params_config_bdnf *bdnf = &config->bdnf;
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_CFG_REG,
+ SUN6I_ISP_BDNF_CFG_IN_DIS_MIN(bdnf->in_dis_min) |
+ SUN6I_ISP_BDNF_CFG_IN_DIS_MAX(bdnf->in_dis_max));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_RB_REG,
+ SUN6I_ISP_BDNF_COEF_RB(0, bdnf->coefficients_rb[0]) |
+ SUN6I_ISP_BDNF_COEF_RB(1, bdnf->coefficients_rb[1]) |
+ SUN6I_ISP_BDNF_COEF_RB(2, bdnf->coefficients_rb[2]) |
+ SUN6I_ISP_BDNF_COEF_RB(3, bdnf->coefficients_rb[3]) |
+ SUN6I_ISP_BDNF_COEF_RB(4, bdnf->coefficients_rb[4]));
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_G_REG,
+ SUN6I_ISP_BDNF_COEF_G(0, bdnf->coefficients_g[0]) |
+ SUN6I_ISP_BDNF_COEF_G(1, bdnf->coefficients_g[1]) |
+ SUN6I_ISP_BDNF_COEF_G(2, bdnf->coefficients_g[2]) |
+ SUN6I_ISP_BDNF_COEF_G(3, bdnf->coefficients_g[3]) |
+ SUN6I_ISP_BDNF_COEF_G(4, bdnf->coefficients_g[4]) |
+ SUN6I_ISP_BDNF_COEF_G(5, bdnf->coefficients_g[5]) |
+ SUN6I_ISP_BDNF_COEF_G(6, bdnf->coefficients_g[6]));
+}
+
+static void
+sun6i_isp_params_configure_modules(struct sun6i_isp_device *isp_dev,
+ const struct sun6i_isp_params_config *config)
+{
+ u32 value;
+
+ if (config->modules_used & SUN6I_ISP_MODULE_BDNF)
+ sun6i_isp_params_configure_bdnf(isp_dev, config);
+
+ if (config->modules_used & SUN6I_ISP_MODULE_BAYER)
+ sun6i_isp_params_configure_bayer(isp_dev, config);
+
+ value = sun6i_isp_load_read(isp_dev, SUN6I_ISP_MODULE_EN_REG);
+ /* Clear all modules but keep input configuration. */
+ value &= SUN6I_ISP_MODULE_EN_SRC0 | SUN6I_ISP_MODULE_EN_SRC1;
+
+ if (config->modules_used & SUN6I_ISP_MODULE_BDNF)
+ value |= SUN6I_ISP_MODULE_EN_BDNF;
+
+ /* Bayer stage is always enabled. */
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MODULE_EN_REG, value);
+}
+
+void sun6i_isp_params_configure(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ sun6i_isp_params_configure_base(isp_dev);
+
+ /* Default config is only applied at the very first stream start. */
+ if (state->configured)
+ goto complete;
+
+ sun6i_isp_params_configure_modules(isp_dev,
+ &sun6i_isp_params_config_default);
+
+ state->configured = true;
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+/* State */
+
+static void sun6i_isp_params_state_cleanup(struct sun6i_isp_device *isp_dev,
+ bool error)
+{
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ struct sun6i_isp_buffer *isp_buffer;
+ struct vb2_buffer *vb2_buffer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (state->pending) {
+ vb2_buffer = &state->pending->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+ }
+
+ list_for_each_entry(isp_buffer, &state->queue, list) {
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+ vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
+ }
+
+ INIT_LIST_HEAD(&state->queue);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_isp_params_state_update(struct sun6i_isp_device *isp_dev,
+ bool *update)
+{
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ struct sun6i_isp_buffer *isp_buffer;
+ struct vb2_buffer *vb2_buffer;
+ const struct sun6i_isp_params_config *config;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (list_empty(&state->queue))
+ goto complete;
+
+ if (state->pending)
+ goto complete;
+
+ isp_buffer = list_first_entry(&state->queue, struct sun6i_isp_buffer,
+ list);
+
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+ config = vb2_plane_vaddr(vb2_buffer, 0);
+
+ sun6i_isp_params_configure_modules(isp_dev, config);
+
+ list_del(&isp_buffer->list);
+
+ state->pending = isp_buffer;
+
+ if (update)
+ *update = true;
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+void sun6i_isp_params_state_complete(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ struct sun6i_isp_buffer *isp_buffer;
+ struct vb2_buffer *vb2_buffer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ if (!state->pending)
+ goto complete;
+
+ isp_buffer = state->pending;
+ vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
+
+ vb2_buffer->timestamp = ktime_get_ns();
+
+ /* Parameters will be applied starting from the next frame. */
+ isp_buffer->v4l2_buffer.sequence = isp_dev->capture.state.sequence + 1;
+
+ vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
+
+ state->pending = NULL;
+
+complete:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+/* Queue */
+
+static int sun6i_isp_params_queue_setup(struct vb2_queue *queue,
+ unsigned int *buffers_count,
+ unsigned int *planes_count,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ unsigned int size = isp_dev->params.format.fmt.meta.buffersize;
+
+ if (*planes_count)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *planes_count = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static int sun6i_isp_params_buffer_prepare(struct vb2_buffer *vb2_buffer)
+{
+ struct sun6i_isp_device *isp_dev =
+ vb2_get_drv_priv(vb2_buffer->vb2_queue);
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ unsigned int size = isp_dev->params.format.fmt.meta.buffersize;
+
+ if (vb2_plane_size(vb2_buffer, 0) < size) {
+ v4l2_err(v4l2_dev, "buffer too small (%lu < %u)\n",
+ vb2_plane_size(vb2_buffer, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb2_buffer, 0, size);
+
+ return 0;
+}
+
+static void sun6i_isp_params_buffer_queue(struct vb2_buffer *vb2_buffer)
+{
+ struct sun6i_isp_device *isp_dev =
+ vb2_get_drv_priv(vb2_buffer->vb2_queue);
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(vb2_buffer);
+ struct sun6i_isp_buffer *isp_buffer =
+ container_of(v4l2_buffer, struct sun6i_isp_buffer, v4l2_buffer);
+ bool capture_streaming = isp_dev->capture.state.streaming;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+ list_add_tail(&isp_buffer->list, &state->queue);
+ spin_unlock_irqrestore(&state->lock, flags);
+
+ if (state->streaming && capture_streaming)
+ sun6i_isp_state_update(isp_dev, false);
+}
+
+static int sun6i_isp_params_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+ bool capture_streaming = isp_dev->capture.state.streaming;
+
+ state->streaming = true;
+
+ /*
+ * Update the state as soon as possible if capture is streaming,
+ * otherwise it will be applied when capture starts streaming.
+ */
+
+ if (capture_streaming)
+ sun6i_isp_state_update(isp_dev, false);
+
+ return 0;
+}
+
+static void sun6i_isp_params_stop_streaming(struct vb2_queue *queue)
+{
+ struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
+ struct sun6i_isp_params_state *state = &isp_dev->params.state;
+
+ state->streaming = false;
+ sun6i_isp_params_state_cleanup(isp_dev, true);
+}
+
+static const struct vb2_ops sun6i_isp_params_queue_ops = {
+ .queue_setup = sun6i_isp_params_queue_setup,
+ .buf_prepare = sun6i_isp_params_buffer_prepare,
+ .buf_queue = sun6i_isp_params_buffer_queue,
+ .start_streaming = sun6i_isp_params_start_streaming,
+ .stop_streaming = sun6i_isp_params_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* Video Device */
+
+static int sun6i_isp_params_querycap(struct file *file, void *private,
+ struct v4l2_capability *capability)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+ struct video_device *video_dev = &isp_dev->params.video_dev;
+
+ strscpy(capability->driver, SUN6I_ISP_NAME, sizeof(capability->driver));
+ strscpy(capability->card, video_dev->name, sizeof(capability->card));
+ snprintf(capability->bus_info, sizeof(capability->bus_info),
+ "platform:%s", dev_name(isp_dev->dev));
+
+ return 0;
+}
+
+static int sun6i_isp_params_enum_fmt(struct file *file, void *private,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+ struct v4l2_meta_format *params_format =
+ &isp_dev->params.format.fmt.meta;
+
+ if (fmtdesc->index > 0)
+ return -EINVAL;
+
+ fmtdesc->pixelformat = params_format->dataformat;
+
+ return 0;
+}
+
+static int sun6i_isp_params_g_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
+{
+ struct sun6i_isp_device *isp_dev = video_drvdata(file);
+
+ *format = isp_dev->params.format;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops sun6i_isp_params_ioctl_ops = {
+ .vidioc_querycap = sun6i_isp_params_querycap,
+
+ .vidioc_enum_fmt_meta_out = sun6i_isp_params_enum_fmt,
+ .vidioc_g_fmt_meta_out = sun6i_isp_params_g_fmt,
+ .vidioc_s_fmt_meta_out = sun6i_isp_params_g_fmt,
+ .vidioc_try_fmt_meta_out = sun6i_isp_params_g_fmt,
+
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static const struct v4l2_file_operations sun6i_isp_params_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
+/* Params */
+
+int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_params *params = &isp_dev->params;
+ struct sun6i_isp_params_state *state = &params->state;
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ struct v4l2_subdev *proc_subdev = &isp_dev->proc.subdev;
+ struct video_device *video_dev = &params->video_dev;
+ struct vb2_queue *queue = &isp_dev->params.queue;
+ struct media_pad *pad = &isp_dev->params.pad;
+ struct v4l2_format *format = &isp_dev->params.format;
+ struct v4l2_meta_format *params_format = &format->fmt.meta;
+ int ret;
+
+ /* State */
+
+ INIT_LIST_HEAD(&state->queue);
+ spin_lock_init(&state->lock);
+
+ /* Media Pads */
+
+ pad->flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+
+ ret = media_entity_pads_init(&video_dev->entity, 1, pad);
+ if (ret)
+ goto error_mutex;
+
+ /* Queue */
+
+ mutex_init(&params->lock);
+
+ queue->type = V4L2_BUF_TYPE_META_OUTPUT;
+ queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ queue->buf_struct_size = sizeof(struct sun6i_isp_buffer);
+ queue->ops = &sun6i_isp_params_queue_ops;
+ queue->mem_ops = &vb2_vmalloc_memops;
+ queue->min_buffers_needed = 1;
+ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->lock = &params->lock;
+ queue->dev = isp_dev->dev;
+ queue->drv_priv = isp_dev;
+
+ ret = vb2_queue_init(queue);
+ if (ret) {
+ v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* V4L2 Format */
+
+ format->type = queue->type;
+ params_format->dataformat = V4L2_META_FMT_SUN6I_ISP_PARAMS;
+ params_format->buffersize = sizeof(struct sun6i_isp_params_config);
+
+ /* Video Device */
+
+ strscpy(video_dev->name, SUN6I_ISP_PARAMS_NAME,
+ sizeof(video_dev->name));
+ video_dev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING;
+ video_dev->vfl_dir = VFL_DIR_TX;
+ video_dev->release = video_device_release_empty;
+ video_dev->fops = &sun6i_isp_params_fops;
+ video_dev->ioctl_ops = &sun6i_isp_params_ioctl_ops;
+ video_dev->v4l2_dev = v4l2_dev;
+ video_dev->queue = queue;
+ video_dev->lock = &params->lock;
+
+ video_set_drvdata(video_dev, isp_dev);
+
+ ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev, "failed to register video device: %d\n",
+ ret);
+ goto error_media_entity;
+ }
+
+ /* Media Pad Link */
+
+ ret = media_create_pad_link(&video_dev->entity, 0,
+ &proc_subdev->entity,
+ SUN6I_ISP_PROC_PAD_SINK_PARAMS,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
+ video_dev->entity.name, 0, proc_subdev->entity.name,
+ SUN6I_ISP_PROC_PAD_SINK_PARAMS);
+ goto error_video_device;
+ }
+
+ return 0;
+
+error_video_device:
+ vb2_video_unregister_device(video_dev);
+
+error_media_entity:
+ media_entity_cleanup(&video_dev->entity);
+
+error_mutex:
+ mutex_destroy(&params->lock);
+
+ return ret;
+}
+
+void sun6i_isp_params_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct sun6i_isp_params *params = &isp_dev->params;
+ struct video_device *video_dev = &params->video_dev;
+
+ vb2_video_unregister_device(video_dev);
+ media_entity_cleanup(&video_dev->entity);
+ mutex_destroy(&params->lock);
+}
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.h
new file mode 100644
index 000000000000..50f10f879c42
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_ISP_PARAMS_H_
+#define _SUN6I_ISP_PARAMS_H_
+
+#include <media/v4l2-device.h>
+
+#define SUN6I_ISP_PARAMS_NAME "sun6i-isp-params"
+
+struct sun6i_isp_device;
+
+struct sun6i_isp_params_state {
+ struct list_head queue; /* Queue and buffers lock. */
+ spinlock_t lock;
+
+ struct sun6i_isp_buffer *pending;
+
+ bool configured;
+ bool streaming;
+};
+
+struct sun6i_isp_params {
+ struct sun6i_isp_params_state state;
+
+ struct video_device video_dev;
+ struct vb2_queue queue;
+ struct mutex lock; /* Queue lock. */
+ struct media_pad pad;
+
+ struct v4l2_format format;
+};
+
+/* Params */
+
+void sun6i_isp_params_configure(struct sun6i_isp_device *isp_dev);
+
+/* State */
+
+void sun6i_isp_params_state_update(struct sun6i_isp_device *isp_dev,
+ bool *update);
+void sun6i_isp_params_state_complete(struct sun6i_isp_device *isp_dev);
+
+/* Params */
+
+int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev);
+void sun6i_isp_params_cleanup(struct sun6i_isp_device *isp_dev);
+
+#endif
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
new file mode 100644
index 000000000000..d69d2be0add2
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "sun6i_isp.h"
+#include "sun6i_isp_capture.h"
+#include "sun6i_isp_params.h"
+#include "sun6i_isp_proc.h"
+#include "sun6i_isp_reg.h"
+
+/* Helpers */
+
+void sun6i_isp_proc_dimensions(struct sun6i_isp_device *isp_dev,
+ unsigned int *width, unsigned int *height)
+{
+ if (width)
+ *width = isp_dev->proc.mbus_format.width;
+ if (height)
+ *height = isp_dev->proc.mbus_format.height;
+}
+
+/* Format */
+
+static const struct sun6i_isp_proc_format sun6i_isp_proc_formats[] = {
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_BGGR,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_GBRG,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_GRBG,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_RGGB,
+ },
+
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_BGGR,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_GBRG,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_GRBG,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .input_format = SUN6I_ISP_INPUT_FMT_RAW_RGGB,
+ },
+};
+
+const struct sun6i_isp_proc_format *sun6i_isp_proc_format_find(u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_isp_proc_formats); i++)
+ if (sun6i_isp_proc_formats[i].mbus_code == mbus_code)
+ return &sun6i_isp_proc_formats[i];
+
+ return NULL;
+}
+
+/* Processor */
+
+static void sun6i_isp_proc_irq_enable(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+
+ regmap_write(regmap, SUN6I_ISP_FE_INT_EN_REG,
+ SUN6I_ISP_FE_INT_EN_FINISH |
+ SUN6I_ISP_FE_INT_EN_START |
+ SUN6I_ISP_FE_INT_EN_PARA_SAVE |
+ SUN6I_ISP_FE_INT_EN_PARA_LOAD |
+ SUN6I_ISP_FE_INT_EN_SRC0_FIFO |
+ SUN6I_ISP_FE_INT_EN_ROT_FINISH);
+}
+
+static void sun6i_isp_proc_irq_disable(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+
+ regmap_write(regmap, SUN6I_ISP_FE_INT_EN_REG, 0);
+}
+
+static void sun6i_isp_proc_irq_clear(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+
+ regmap_write(regmap, SUN6I_ISP_FE_INT_EN_REG, 0);
+ regmap_write(regmap, SUN6I_ISP_FE_INT_STA_REG,
+ SUN6I_ISP_FE_INT_STA_CLEAR);
+}
+
+static void sun6i_isp_proc_enable(struct sun6i_isp_device *isp_dev,
+ struct sun6i_isp_proc_source *source)
+{
+ struct sun6i_isp_proc *proc = &isp_dev->proc;
+ struct regmap *regmap = isp_dev->regmap;
+ u8 mode;
+
+ /* Frontend */
+
+ if (source == &proc->source_csi0)
+ mode = SUN6I_ISP_SRC_MODE_CSI(0);
+ else
+ mode = SUN6I_ISP_SRC_MODE_CSI(1);
+
+ regmap_write(regmap, SUN6I_ISP_FE_CFG_REG,
+ SUN6I_ISP_FE_CFG_EN | SUN6I_ISP_FE_CFG_SRC0_MODE(mode));
+
+ regmap_write(regmap, SUN6I_ISP_FE_CTRL_REG,
+ SUN6I_ISP_FE_CTRL_VCAP_EN | SUN6I_ISP_FE_CTRL_PARA_READY);
+}
+
+static void sun6i_isp_proc_disable(struct sun6i_isp_device *isp_dev)
+{
+ struct regmap *regmap = isp_dev->regmap;
+
+ /* Frontend */
+
+ regmap_write(regmap, SUN6I_ISP_FE_CTRL_REG, 0);
+ regmap_write(regmap, SUN6I_ISP_FE_CFG_REG, 0);
+}
+
+static void sun6i_isp_proc_configure(struct sun6i_isp_device *isp_dev)
+{
+ struct v4l2_mbus_framefmt *mbus_format = &isp_dev->proc.mbus_format;
+ const struct sun6i_isp_proc_format *format;
+ u32 value;
+
+ /* Module */
+
+ value = sun6i_isp_load_read(isp_dev, SUN6I_ISP_MODULE_EN_REG);
+ value |= SUN6I_ISP_MODULE_EN_SRC0;
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MODULE_EN_REG, value);
+
+ /* Input */
+
+ format = sun6i_isp_proc_format_find(mbus_format->code);
+ if (WARN_ON(!format))
+ return;
+
+ sun6i_isp_load_write(isp_dev, SUN6I_ISP_MODE_REG,
+ SUN6I_ISP_MODE_INPUT_FMT(format->input_format) |
+ SUN6I_ISP_MODE_INPUT_YUV_SEQ(format->input_yuv_seq) |
+ SUN6I_ISP_MODE_SHARP(1) |
+ SUN6I_ISP_MODE_HIST(2));
+}
+
+/* V4L2 Subdev */
+
+static int sun6i_isp_proc_s_stream(struct v4l2_subdev *subdev, int on)
+{
+ struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev);
+ struct sun6i_isp_proc *proc = &isp_dev->proc;
+ struct media_pad *local_pad = &proc->pads[SUN6I_ISP_PROC_PAD_SINK_CSI];
+ struct device *dev = isp_dev->dev;
+ struct sun6i_isp_proc_source *source;
+ struct v4l2_subdev *source_subdev;
+ struct media_pad *remote_pad;
+ /* Initialize to 0 to use both in disable label (ret != 0) and off. */
+ int ret = 0;
+
+ /* Source */
+
+ remote_pad = media_pad_remote_pad_unique(local_pad);
+ if (IS_ERR(remote_pad)) {
+ dev_err(dev,
+ "zero or more than a single source connected to the bridge\n");
+ return PTR_ERR(remote_pad);
+ }
+
+ source_subdev = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ if (source_subdev == proc->source_csi0.subdev)
+ source = &proc->source_csi0;
+ else
+ source = &proc->source_csi1;
+
+ if (!on) {
+ sun6i_isp_proc_irq_disable(isp_dev);
+ v4l2_subdev_call(source_subdev, video, s_stream, 0);
+ goto disable;
+ }
+
+ /* PM */
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ /* Clear */
+
+ sun6i_isp_proc_irq_clear(isp_dev);
+
+ /* Configure */
+
+ sun6i_isp_tables_configure(isp_dev);
+ sun6i_isp_params_configure(isp_dev);
+ sun6i_isp_proc_configure(isp_dev);
+ sun6i_isp_capture_configure(isp_dev);
+
+ /* State Update */
+
+ sun6i_isp_state_update(isp_dev, true);
+
+ /* Enable */
+
+ sun6i_isp_proc_irq_enable(isp_dev);
+ sun6i_isp_proc_enable(isp_dev, source);
+
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD) {
+ sun6i_isp_proc_irq_disable(isp_dev);
+ goto disable;
+ }
+
+ return 0;
+
+disable:
+ sun6i_isp_proc_disable(isp_dev);
+
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops sun6i_isp_proc_video_ops = {
+ .s_stream = sun6i_isp_proc_s_stream,
+};
+
+static void
+sun6i_isp_proc_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
+{
+ if (!sun6i_isp_proc_format_find(mbus_format->code))
+ mbus_format->code = sun6i_isp_proc_formats[0].mbus_code;
+
+ mbus_format->field = V4L2_FIELD_NONE;
+ mbus_format->colorspace = V4L2_COLORSPACE_RAW;
+ mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun6i_isp_proc_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
+{
+ struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev);
+ unsigned int pad = SUN6I_ISP_PROC_PAD_SINK_CSI;
+ struct v4l2_mbus_framefmt *mbus_format =
+ v4l2_subdev_get_try_format(subdev, state, pad);
+ struct mutex *lock = &isp_dev->proc.lock;
+
+ mutex_lock(lock);
+
+ mbus_format->code = sun6i_isp_proc_formats[0].mbus_code;
+ mbus_format->width = 1280;
+ mbus_format->height = 720;
+
+ sun6i_isp_proc_mbus_format_prepare(mbus_format);
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int
+sun6i_isp_proc_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code_enum)
+{
+ if (code_enum->index >= ARRAY_SIZE(sun6i_isp_proc_formats))
+ return -EINVAL;
+
+ code_enum->code = sun6i_isp_proc_formats[code_enum->index].mbus_code;
+
+ return 0;
+}
+
+static int sun6i_isp_proc_get_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &isp_dev->proc.lock;
+
+ mutex_lock(lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
+ format->pad);
+ else
+ *mbus_format = isp_dev->proc.mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int sun6i_isp_proc_set_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &isp_dev->proc.lock;
+
+ mutex_lock(lock);
+
+ sun6i_isp_proc_mbus_format_prepare(mbus_format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *mbus_format;
+ else
+ isp_dev->proc.mbus_format = *mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun6i_isp_proc_pad_ops = {
+ .init_cfg = sun6i_isp_proc_init_cfg,
+ .enum_mbus_code = sun6i_isp_proc_enum_mbus_code,
+ .get_fmt = sun6i_isp_proc_get_fmt,
+ .set_fmt = sun6i_isp_proc_set_fmt,
+};
+
+const struct v4l2_subdev_ops sun6i_isp_proc_subdev_ops = {
+ .video = &sun6i_isp_proc_video_ops,
+ .pad = &sun6i_isp_proc_pad_ops,
+};
+
+/* Media Entity */
+
+static const struct media_entity_operations sun6i_isp_proc_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* V4L2 Async */
+
+static int sun6i_isp_proc_link(struct sun6i_isp_device *isp_dev,
+ int sink_pad_index,
+ struct v4l2_subdev *remote_subdev, bool enabled)
+{
+ struct device *dev = isp_dev->dev;
+ struct v4l2_subdev *subdev = &isp_dev->proc.subdev;
+ struct media_entity *sink_entity = &subdev->entity;
+ struct media_entity *source_entity = &remote_subdev->entity;
+ int source_pad_index;
+ int ret;
+
+ /* Get the first remote source pad. */
+ ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "missing source pad in external entity %s\n",
+ source_entity->name);
+ return -EINVAL;
+ }
+
+ source_pad_index = ret;
+
+ dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name,
+ source_pad_index, sink_entity->name, sink_pad_index);
+
+ ret = media_create_pad_link(source_entity, source_pad_index,
+ sink_entity, sink_pad_index,
+ enabled ? MEDIA_LNK_FL_ENABLED : 0);
+ if (ret < 0) {
+ dev_err(dev, "failed to create %s:%u -> %s:%u link\n",
+ source_entity->name, source_pad_index,
+ sink_entity->name, sink_pad_index);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sun6i_isp_proc_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *remote_subdev,
+ struct v4l2_async_subdev *async_subdev)
+{
+ struct sun6i_isp_device *isp_dev =
+ container_of(notifier, struct sun6i_isp_device, proc.notifier);
+ struct sun6i_isp_proc_async_subdev *proc_async_subdev =
+ container_of(async_subdev, struct sun6i_isp_proc_async_subdev,
+ async_subdev);
+ struct sun6i_isp_proc *proc = &isp_dev->proc;
+ struct sun6i_isp_proc_source *source = proc_async_subdev->source;
+ bool enabled;
+
+ switch (source->endpoint.base.port) {
+ case SUN6I_ISP_PORT_CSI0:
+ source = &proc->source_csi0;
+ enabled = true;
+ break;
+ case SUN6I_ISP_PORT_CSI1:
+ source = &proc->source_csi1;
+ enabled = !proc->source_csi0.expected;
+ break;
+ default:
+ break;
+ }
+
+ source->subdev = remote_subdev;
+
+ return sun6i_isp_proc_link(isp_dev, SUN6I_ISP_PROC_PAD_SINK_CSI,
+ remote_subdev, enabled);
+}
+
+static int
+sun6i_isp_proc_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+ struct sun6i_isp_device *isp_dev =
+ container_of(notifier, struct sun6i_isp_device, proc.notifier);
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ int ret;
+
+ ret = v4l2_device_register_subdev_nodes(v4l2_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations
+sun6i_isp_proc_notifier_ops = {
+ .bound = sun6i_isp_proc_notifier_bound,
+ .complete = sun6i_isp_proc_notifier_complete,
+};
+
+/* Processor */
+
+static int sun6i_isp_proc_source_setup(struct sun6i_isp_device *isp_dev,
+ struct sun6i_isp_proc_source *source,
+ u32 port)
+{
+ struct device *dev = isp_dev->dev;
+ struct v4l2_async_notifier *notifier = &isp_dev->proc.notifier;
+ struct v4l2_fwnode_endpoint *endpoint = &source->endpoint;
+ struct sun6i_isp_proc_async_subdev *proc_async_subdev;
+ struct fwnode_handle *handle = NULL;
+ int ret;
+
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), port, 0, 0);
+ if (!handle)
+ return -ENODEV;
+
+ ret = v4l2_fwnode_endpoint_parse(handle, endpoint);
+ if (ret)
+ goto complete;
+
+ proc_async_subdev =
+ v4l2_async_nf_add_fwnode_remote(notifier, handle,
+ struct
+ sun6i_isp_proc_async_subdev);
+ if (IS_ERR(proc_async_subdev)) {
+ ret = PTR_ERR(proc_async_subdev);
+ goto complete;
+ }
+
+ proc_async_subdev->source = source;
+
+ source->expected = true;
+
+complete:
+ fwnode_handle_put(handle);
+
+ return ret;
+}
+
+int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev)
+{
+ struct device *dev = isp_dev->dev;
+ struct sun6i_isp_proc *proc = &isp_dev->proc;
+ struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
+ struct v4l2_async_notifier *notifier = &proc->notifier;
+ struct v4l2_subdev *subdev = &proc->subdev;
+ struct media_pad *pads = proc->pads;
+ int ret;
+
+ mutex_init(&proc->lock);
+
+ /* V4L2 Subdev */
+
+ v4l2_subdev_init(subdev, &sun6i_isp_proc_subdev_ops);
+ strscpy(subdev->name, SUN6I_ISP_PROC_NAME, sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->owner = THIS_MODULE;
+ subdev->dev = dev;
+
+ v4l2_set_subdevdata(subdev, isp_dev);
+
+ /* Media Entity */
+
+ subdev->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP;
+ subdev->entity.ops = &sun6i_isp_proc_entity_ops;
+
+ /* Media Pads */
+
+ pads[SUN6I_ISP_PROC_PAD_SINK_CSI].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ pads[SUN6I_ISP_PROC_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ pads[SUN6I_ISP_PROC_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&subdev->entity, SUN6I_ISP_PROC_PAD_COUNT,
+ pads);
+ if (ret)
+ return ret;
+
+ /* V4L2 Subdev */
+
+ ret = v4l2_device_register_subdev(v4l2_dev, subdev);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to register v4l2 subdev: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* V4L2 Async */
+
+ v4l2_async_nf_init(notifier);
+ notifier->ops = &sun6i_isp_proc_notifier_ops;
+
+ sun6i_isp_proc_source_setup(isp_dev, &proc->source_csi0,
+ SUN6I_ISP_PORT_CSI0);
+ sun6i_isp_proc_source_setup(isp_dev, &proc->source_csi1,
+ SUN6I_ISP_PORT_CSI1);
+
+ ret = v4l2_async_nf_register(v4l2_dev, notifier);
+ if (ret) {
+ v4l2_err(v4l2_dev,
+ "failed to register v4l2 async notifier: %d\n", ret);
+ goto error_v4l2_async_notifier;
+ }
+
+ return 0;
+
+error_v4l2_async_notifier:
+ v4l2_async_nf_cleanup(notifier);
+
+ v4l2_device_unregister_subdev(subdev);
+
+error_media_entity:
+ media_entity_cleanup(&subdev->entity);
+
+ return ret;
+}
+
+void sun6i_isp_proc_cleanup(struct sun6i_isp_device *isp_dev)
+{
+ struct v4l2_async_notifier *notifier = &isp_dev->proc.notifier;
+ struct v4l2_subdev *subdev = &isp_dev->proc.subdev;
+
+ v4l2_async_nf_unregister(notifier);
+ v4l2_async_nf_cleanup(notifier);
+
+ v4l2_device_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+}
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h
new file mode 100644
index 000000000000..c5c274e21ad5
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_ISP_PROC_H_
+#define _SUN6I_ISP_PROC_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define SUN6I_ISP_PROC_NAME "sun6i-isp-proc"
+
+enum sun6i_isp_proc_pad {
+ SUN6I_ISP_PROC_PAD_SINK_CSI = 0,
+ SUN6I_ISP_PROC_PAD_SINK_PARAMS = 1,
+ SUN6I_ISP_PROC_PAD_SOURCE = 2,
+ SUN6I_ISP_PROC_PAD_COUNT = 3,
+};
+
+struct sun6i_isp_device;
+
+struct sun6i_isp_proc_format {
+ u32 mbus_code;
+ u8 input_format;
+ u8 input_yuv_seq;
+};
+
+struct sun6i_isp_proc_source {
+ struct v4l2_subdev *subdev;
+ struct v4l2_fwnode_endpoint endpoint;
+ bool expected;
+};
+
+struct sun6i_isp_proc_async_subdev {
+ struct v4l2_async_subdev async_subdev;
+ struct sun6i_isp_proc_source *source;
+};
+
+struct sun6i_isp_proc {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[3];
+ struct v4l2_async_notifier notifier;
+ struct v4l2_mbus_framefmt mbus_format;
+ struct mutex lock; /* Mbus format lock. */
+
+ struct sun6i_isp_proc_source source_csi0;
+ struct sun6i_isp_proc_source source_csi1;
+};
+
+/* Helpers */
+
+void sun6i_isp_proc_dimensions(struct sun6i_isp_device *isp_dev,
+ unsigned int *width, unsigned int *height);
+
+/* Format */
+
+const struct sun6i_isp_proc_format *sun6i_isp_proc_format_find(u32 mbus_code);
+
+/* Proc */
+
+int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev);
+void sun6i_isp_proc_cleanup(struct sun6i_isp_device *isp_dev);
+
+#endif
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_reg.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_reg.h
new file mode 100644
index 000000000000..83b9cdab2134
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_reg.h
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_ISP_REG_H_
+#define _SUN6I_ISP_REG_H_
+
+#include <linux/kernel.h>
+
+#define SUN6I_ISP_ADDR_VALUE(a) ((a) >> 2)
+
+/* Frontend */
+
+#define SUN6I_ISP_SRC_MODE_DRAM 0
+#define SUN6I_ISP_SRC_MODE_CSI(n) (1 + (n))
+
+#define SUN6I_ISP_FE_CFG_REG 0x0
+#define SUN6I_ISP_FE_CFG_EN BIT(0)
+#define SUN6I_ISP_FE_CFG_SRC0_MODE(v) (((v) << 8) & GENMASK(9, 8))
+#define SUN6I_ISP_FE_CFG_SRC1_MODE(v) (((v) << 16) & GENMASK(17, 16))
+
+#define SUN6I_ISP_FE_CTRL_REG 0x4
+#define SUN6I_ISP_FE_CTRL_SCAP_EN BIT(0)
+#define SUN6I_ISP_FE_CTRL_VCAP_EN BIT(1)
+#define SUN6I_ISP_FE_CTRL_PARA_READY BIT(2)
+#define SUN6I_ISP_FE_CTRL_LUT_UPDATE BIT(3)
+#define SUN6I_ISP_FE_CTRL_LENS_UPDATE BIT(4)
+#define SUN6I_ISP_FE_CTRL_GAMMA_UPDATE BIT(5)
+#define SUN6I_ISP_FE_CTRL_DRC_UPDATE BIT(6)
+#define SUN6I_ISP_FE_CTRL_DISC_UPDATE BIT(7)
+#define SUN6I_ISP_FE_CTRL_OUTPUT_SPEED_CTRL(v) (((v) << 16) & GENMASK(17, 16))
+#define SUN6I_ISP_FE_CTRL_VCAP_READ_START BIT(31)
+
+#define SUN6I_ISP_FE_INT_EN_REG 0x8
+#define SUN6I_ISP_FE_INT_EN_FINISH BIT(0)
+#define SUN6I_ISP_FE_INT_EN_START BIT(1)
+#define SUN6I_ISP_FE_INT_EN_PARA_SAVE BIT(2)
+#define SUN6I_ISP_FE_INT_EN_PARA_LOAD BIT(3)
+#define SUN6I_ISP_FE_INT_EN_SRC0_FIFO BIT(4)
+#define SUN6I_ISP_FE_INT_EN_SRC1_FIFO BIT(5)
+#define SUN6I_ISP_FE_INT_EN_ROT_FINISH BIT(6)
+#define SUN6I_ISP_FE_INT_EN_LINE_NUM_START BIT(7)
+
+#define SUN6I_ISP_FE_INT_STA_REG 0xc
+#define SUN6I_ISP_FE_INT_STA_CLEAR 0xff
+#define SUN6I_ISP_FE_INT_STA_FINISH BIT(0)
+#define SUN6I_ISP_FE_INT_STA_START BIT(1)
+#define SUN6I_ISP_FE_INT_STA_PARA_SAVE BIT(2)
+#define SUN6I_ISP_FE_INT_STA_PARA_LOAD BIT(3)
+#define SUN6I_ISP_FE_INT_STA_SRC0_FIFO BIT(4)
+#define SUN6I_ISP_FE_INT_STA_SRC1_FIFO BIT(5)
+#define SUN6I_ISP_FE_INT_STA_ROT_FINISH BIT(6)
+#define SUN6I_ISP_FE_INT_STA_LINE_NUM_START BIT(7)
+
+/* Only since sun9i-a80-isp. */
+#define SUN6I_ISP_FE_INT_LINE_NUM_REG 0x18
+#define SUN6I_ISP_FE_ROT_OF_CFG_REG 0x1c
+
+/* Buffers/tables */
+
+#define SUN6I_ISP_REG_LOAD_ADDR_REG 0x20
+#define SUN6I_ISP_REG_SAVE_ADDR_REG 0x24
+
+#define SUN6I_ISP_LUT_TABLE_ADDR_REG 0x28
+#define SUN6I_ISP_DRC_TABLE_ADDR_REG 0x2c
+#define SUN6I_ISP_STATS_ADDR_REG 0x30
+
+/* SRAM */
+
+#define SUN6I_ISP_SRAM_RW_OFFSET_REG 0x38
+#define SUN6I_ISP_SRAM_RW_DATA_REG 0x3c
+
+/* Global */
+
+#define SUN6I_ISP_MODULE_EN_REG 0x40
+#define SUN6I_ISP_MODULE_EN_AE BIT(0)
+#define SUN6I_ISP_MODULE_EN_OBC BIT(1)
+#define SUN6I_ISP_MODULE_EN_DPC_LUT BIT(2)
+#define SUN6I_ISP_MODULE_EN_DPC_OTF BIT(3)
+#define SUN6I_ISP_MODULE_EN_BDNF BIT(4)
+#define SUN6I_ISP_MODULE_EN_AWB BIT(6)
+#define SUN6I_ISP_MODULE_EN_WB BIT(7)
+#define SUN6I_ISP_MODULE_EN_LSC BIT(8)
+#define SUN6I_ISP_MODULE_EN_BGC BIT(9)
+#define SUN6I_ISP_MODULE_EN_SAP BIT(10)
+#define SUN6I_ISP_MODULE_EN_AF BIT(11)
+#define SUN6I_ISP_MODULE_EN_RGB2RGB BIT(12)
+#define SUN6I_ISP_MODULE_EN_RGB_DRC BIT(13)
+#define SUN6I_ISP_MODULE_EN_TDNF BIT(15)
+#define SUN6I_ISP_MODULE_EN_AFS BIT(16)
+#define SUN6I_ISP_MODULE_EN_HIST BIT(17)
+#define SUN6I_ISP_MODULE_EN_YUV_GAIN_OFFSET BIT(18)
+#define SUN6I_ISP_MODULE_EN_YUV_DRC BIT(19)
+#define SUN6I_ISP_MODULE_EN_TG BIT(20)
+#define SUN6I_ISP_MODULE_EN_ROT BIT(21)
+#define SUN6I_ISP_MODULE_EN_CONTRAST BIT(22)
+#define SUN6I_ISP_MODULE_EN_SATU BIT(24)
+#define SUN6I_ISP_MODULE_EN_SRC1 BIT(30)
+#define SUN6I_ISP_MODULE_EN_SRC0 BIT(31)
+
+#define SUN6I_ISP_MODE_REG 0x44
+#define SUN6I_ISP_MODE_INPUT_FMT(v) ((v) & GENMASK(2, 0))
+#define SUN6I_ISP_MODE_INPUT_YUV_SEQ(v) (((v) << 3) & GENMASK(4, 3))
+#define SUN6I_ISP_MODE_OTF_DPC(v) (((v) << 16) & BIT(16))
+#define SUN6I_ISP_MODE_SHARP(v) (((v) << 17) & BIT(17))
+#define SUN6I_ISP_MODE_HIST(v) (((v) << 20) & GENMASK(21, 20))
+
+#define SUN6I_ISP_INPUT_FMT_YUV420 0
+#define SUN6I_ISP_INPUT_FMT_YUV422 1
+#define SUN6I_ISP_INPUT_FMT_RAW_BGGR 4
+#define SUN6I_ISP_INPUT_FMT_RAW_RGGB 5
+#define SUN6I_ISP_INPUT_FMT_RAW_GBRG 6
+#define SUN6I_ISP_INPUT_FMT_RAW_GRBG 7
+
+#define SUN6I_ISP_INPUT_YUV_SEQ_YUYV 0
+#define SUN6I_ISP_INPUT_YUV_SEQ_YVYU 1
+#define SUN6I_ISP_INPUT_YUV_SEQ_UYVY 2
+#define SUN6I_ISP_INPUT_YUV_SEQ_VYUY 3
+
+#define SUN6I_ISP_IN_CFG_REG 0x48
+#define SUN6I_ISP_IN_CFG_STRIDE_DIV16(v) ((v) & GENMASK(10, 0))
+
+#define SUN6I_ISP_IN_LUMA_RGB_ADDR0_REG 0x4c
+#define SUN6I_ISP_IN_CHROMA_ADDR0_REG 0x50
+#define SUN6I_ISP_IN_LUMA_RGB_ADDR1_REG 0x54
+#define SUN6I_ISP_IN_CHROMA_ADDR1_REG 0x58
+
+/* AE */
+
+#define SUN6I_ISP_AE_CFG_REG 0x60
+#define SUN6I_ISP_AE_CFG_LOW_BRI_TH(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_AE_CFG_HORZ_NUM(v) (((v) << 12) & GENMASK(15, 12))
+#define SUN6I_ISP_AE_CFG_HIGH_BRI_TH(v) (((v) << 16) & GENMASK(27, 16))
+#define SUN6I_ISP_AE_CFG_VERT_NUM(v) (((v) << 28) & GENMASK(31, 28))
+
+#define SUN6I_ISP_AE_SIZE_REG 0x64
+#define SUN6I_ISP_AE_SIZE_WIDTH(v) ((v) & GENMASK(10, 0))
+#define SUN6I_ISP_AE_SIZE_HEIGHT(v) (((v) << 16) & GENMASK(26, 16))
+
+#define SUN6I_ISP_AE_POS_REG 0x68
+#define SUN6I_ISP_AE_POS_HORZ_START(v) ((v) & GENMASK(10, 0))
+#define SUN6I_ISP_AE_POS_VERT_START(v) (((v) << 16) & GENMASK(26, 16))
+
+/* OB */
+
+#define SUN6I_ISP_OB_SIZE_REG 0x78
+#define SUN6I_ISP_OB_SIZE_WIDTH(v) ((v) & GENMASK(13, 0))
+#define SUN6I_ISP_OB_SIZE_HEIGHT(v) (((v) << 16) & GENMASK(29, 16))
+
+#define SUN6I_ISP_OB_VALID_REG 0x7c
+#define SUN6I_ISP_OB_VALID_WIDTH(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_OB_VALID_HEIGHT(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_OB_SRC0_VALID_START_REG 0x80
+#define SUN6I_ISP_OB_SRC0_VALID_START_HORZ(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_OB_SRC0_VALID_START_VERT(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_OB_SRC1_VALID_START_REG 0x84
+#define SUN6I_ISP_OB_SRC1_VALID_START_HORZ(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_OB_SRC1_VALID_START_VERT(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_OB_SPRITE_REG 0x88
+#define SUN6I_ISP_OB_SPRITE_WIDTH(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_OB_SPRITE_HEIGHT(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_OB_SPRITE_START_REG 0x8c
+#define SUN6I_ISP_OB_SPRITE_START_HORZ(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_OB_SPRITE_START_VERT(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_OB_CFG_REG 0x90
+#define SUN6I_ISP_OB_HORZ_POS_REG 0x94
+#define SUN6I_ISP_OB_VERT_PARA_REG 0x98
+#define SUN6I_ISP_OB_OFFSET_FIXED_REG 0x9c
+
+/* BDNF */
+
+#define SUN6I_ISP_BDNF_CFG_REG 0xcc
+#define SUN6I_ISP_BDNF_CFG_IN_DIS_MIN(v) ((v) & GENMASK(7, 0))
+#define SUN6I_ISP_BDNF_CFG_IN_DIS_MAX(v) (((v) << 16) & GENMASK(23, 16))
+
+#define SUN6I_ISP_BDNF_COEF_RB_REG 0xd0
+#define SUN6I_ISP_BDNF_COEF_RB(i, v) (((v) << (4 * (i))) & \
+ GENMASK(4 * (i) + 3, 4 * (i)))
+
+#define SUN6I_ISP_BDNF_COEF_G_REG 0xd4
+#define SUN6I_ISP_BDNF_COEF_G(i, v) (((v) << (4 * (i))) & \
+ GENMASK(4 * (i) + 3, 4 * (i)))
+
+/* Bayer */
+
+#define SUN6I_ISP_BAYER_OFFSET0_REG 0xe0
+#define SUN6I_ISP_BAYER_OFFSET0_R(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_BAYER_OFFSET0_GR(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_BAYER_OFFSET1_REG 0xe4
+#define SUN6I_ISP_BAYER_OFFSET1_GB(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_BAYER_OFFSET1_B(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_BAYER_GAIN0_REG 0xe8
+#define SUN6I_ISP_BAYER_GAIN0_R(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_BAYER_GAIN0_GR(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_BAYER_GAIN1_REG 0xec
+#define SUN6I_ISP_BAYER_GAIN1_GB(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_BAYER_GAIN1_B(v) (((v) << 16) & GENMASK(27, 16))
+
+/* WB */
+
+#define SUN6I_ISP_WB_GAIN0_REG 0x140
+#define SUN6I_ISP_WB_GAIN0_R(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_WB_GAIN0_GR(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_WB_GAIN1_REG 0x144
+#define SUN6I_ISP_WB_GAIN1_GB(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_WB_GAIN1_B(v) (((v) << 16) & GENMASK(27, 16))
+
+#define SUN6I_ISP_WB_CFG_REG 0x148
+#define SUN6I_ISP_WB_CFG_CLIP(v) ((v) & GENMASK(11, 0))
+
+/* Global */
+
+#define SUN6I_ISP_MCH_SIZE_CFG_REG 0x1e0
+#define SUN6I_ISP_MCH_SIZE_CFG_WIDTH(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_MCH_SIZE_CFG_HEIGHT(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_MCH_SCALE_CFG_REG 0x1e4
+#define SUN6I_ISP_MCH_SCALE_CFG_X_RATIO(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_MCH_SCALE_CFG_Y_RATIO(v) (((v) << 16) & GENMASK(27, 16))
+#define SUN6I_ISP_MCH_SCALE_CFG_WEIGHT_SHIFT(v) (((v) << 28) & GENMASK(31, 28))
+
+#define SUN6I_ISP_SCH_SIZE_CFG_REG 0x1e8
+#define SUN6I_ISP_SCH_SIZE_CFG_WIDTH(v) ((v) & GENMASK(12, 0))
+#define SUN6I_ISP_SCH_SIZE_CFG_HEIGHT(v) (((v) << 16) & GENMASK(28, 16))
+
+#define SUN6I_ISP_SCH_SCALE_CFG_REG 0x1ec
+#define SUN6I_ISP_SCH_SCALE_CFG_X_RATIO(v) ((v) & GENMASK(11, 0))
+#define SUN6I_ISP_SCH_SCALE_CFG_Y_RATIO(v) (((v) << 16) & GENMASK(27, 16))
+#define SUN6I_ISP_SCH_SCALE_CFG_WEIGHT_SHIFT(v) (((v) << 28) & GENMASK(31, 28))
+
+#define SUN6I_ISP_MCH_CFG_REG 0x1f0
+#define SUN6I_ISP_MCH_CFG_EN BIT(0)
+#define SUN6I_ISP_MCH_CFG_SCALE_EN BIT(1)
+#define SUN6I_ISP_MCH_CFG_OUTPUT_FMT(v) (((v) << 2) & GENMASK(4, 2))
+#define SUN6I_ISP_MCH_CFG_MIRROR_EN BIT(5)
+#define SUN6I_ISP_MCH_CFG_FLIP_EN BIT(6)
+#define SUN6I_ISP_MCH_CFG_STRIDE_Y_DIV4(v) (((v) << 8) & GENMASK(18, 8))
+#define SUN6I_ISP_MCH_CFG_STRIDE_UV_DIV4(v) (((v) << 20) & GENMASK(30, 20))
+
+#define SUN6I_ISP_OUTPUT_FMT_YUV420SP 0
+#define SUN6I_ISP_OUTPUT_FMT_YUV422SP 1
+#define SUN6I_ISP_OUTPUT_FMT_YVU420SP 2
+#define SUN6I_ISP_OUTPUT_FMT_YVU422SP 3
+#define SUN6I_ISP_OUTPUT_FMT_YUV420P 4
+#define SUN6I_ISP_OUTPUT_FMT_YUV422P 5
+#define SUN6I_ISP_OUTPUT_FMT_YVU420P 6
+#define SUN6I_ISP_OUTPUT_FMT_YVU422P 7
+
+#define SUN6I_ISP_SCH_CFG_REG 0x1f4
+
+#define SUN6I_ISP_MCH_Y_ADDR0_REG 0x1f8
+#define SUN6I_ISP_MCH_U_ADDR0_REG 0x1fc
+#define SUN6I_ISP_MCH_V_ADDR0_REG 0x200
+#define SUN6I_ISP_MCH_Y_ADDR1_REG 0x204
+#define SUN6I_ISP_MCH_U_ADDR1_REG 0x208
+#define SUN6I_ISP_MCH_V_ADDR1_REG 0x20c
+#define SUN6I_ISP_SCH_Y_ADDR0_REG 0x210
+#define SUN6I_ISP_SCH_U_ADDR0_REG 0x214
+#define SUN6I_ISP_SCH_V_ADDR0_REG 0x218
+#define SUN6I_ISP_SCH_Y_ADDR1_REG 0x21c
+#define SUN6I_ISP_SCH_U_ADDR1_REG 0x220
+#define SUN6I_ISP_SCH_V_ADDR1_REG 0x224
+
+#endif
diff --git a/drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h b/drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h
new file mode 100644
index 000000000000..19c24c5fd322
--- /dev/null
+++ b/drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR MIT) */
+/*
+ * Allwinner A31 ISP Configuration
+ */
+
+#ifndef _UAPI_SUN6I_ISP_CONFIG_H
+#define _UAPI_SUN6I_ISP_CONFIG_H
+
+#include <linux/types.h>
+
+#define V4L2_META_FMT_SUN6I_ISP_PARAMS v4l2_fourcc('S', '6', 'I', 'P') /* Allwinner A31 ISP Parameters */
+
+#define SUN6I_ISP_MODULE_BAYER (1U << 0)
+#define SUN6I_ISP_MODULE_BDNF (1U << 1)
+
+struct sun6i_isp_params_config_bayer {
+ __u16 offset_r;
+ __u16 offset_gr;
+ __u16 offset_gb;
+ __u16 offset_b;
+
+ __u16 gain_r;
+ __u16 gain_gr;
+ __u16 gain_gb;
+ __u16 gain_b;
+};
+
+struct sun6i_isp_params_config_bdnf {
+ __u8 in_dis_min;
+ __u8 in_dis_max;
+
+ __u8 coefficients_g[7];
+ __u8 coefficients_rb[5];
+};
+
+struct sun6i_isp_params_config {
+ __u32 modules_used;
+
+ struct sun6i_isp_params_config_bayer bayer;
+ struct sun6i_isp_params_config_bdnf bdnf;
+};
+
+#endif /* _UAPI_SUN6I_ISP_CONFIG_H */
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index b26e44adb2be..426e653bd55d 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -433,7 +433,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
for (i = 0; i < chan->numgangports; i++)
chan->csi_port_nums[i] = port_num + i * CSI_PORTS_PER_BRICK;
- chan->of_node = node;
+ chan->of_node = of_node_get(node);
chan->numpads = num_pads;
if (num_pads & 0x2) {
chan->pads[0].flags = MEDIA_PAD_FL_SINK;
@@ -448,6 +448,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
chan->mipi = tegra_mipi_request(csi->dev, node);
if (IS_ERR(chan->mipi)) {
ret = PTR_ERR(chan->mipi);
+ chan->mipi = NULL;
dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
}
@@ -640,6 +641,7 @@ static void tegra_csi_channels_cleanup(struct tegra_csi *csi)
media_entity_cleanup(&subdev->entity);
}
+ of_node_put(chan->of_node);
list_del(&chan->list);
kfree(chan);
}
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 4ee05a1785cf..6960ea2e3d36 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -56,7 +56,7 @@ struct tegra_csi;
* @framerate: active framerate for TPG
* @h_blank: horizontal blanking for TPG active format
* @v_blank: vertical blanking for TPG active format
- * @mipi: mipi device for corresponding csi channel pads
+ * @mipi: mipi device for corresponding csi channel pads, or NULL if not applicable (TPG, error)
* @pixel_rate: active pixel rate from the sensor on this channel
*/
struct tegra_csi_channel {
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 9d46a36cc014..11dd142c98c5 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1811,7 +1811,7 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
}
/* skip entities that are already processed */
- if (remote == dev_fwnode(vi->dev) ||
+ if (device_match_fwnode(vi->dev, remote) ||
tegra_vi_graph_find_entity(chan, remote)) {
fwnode_handle_put(remote);
continue;
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dtso
index 096137fcd5cc..096137fcd5cc 100644
--- a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dtso
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
index a810548c5857..d317c0ec3419 100644
--- a/drivers/staging/pi433/Documentation/devicetree/pi433.txt
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -48,13 +48,13 @@ For Raspbian users only
=======================
Since Raspbian supports device tree overlays, you may use an overlay instead
of editing your boards device tree.
-To use the overlay, you need to compile the file pi433-overlay.dts which can
+To use the overlay, you need to compile the file pi433-overlay.dtso which can
be found alongside this documentation.
The file needs to be compiled - either manually or by integration in your kernel
source tree. For a manual compile, you may use a command line like the following:
-'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dtso'
-For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dtso to
arch/arm/boot/dts/overlays and you need to add the file to the list of files
in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
kernel make files compile the device tree overlay for you.
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index f9589c5b62ba..1e5ad3b476ef 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -439,7 +439,7 @@ int rtllib_wx_set_essid(struct rtllib_device *ieee,
union iwreq_data *wrqu, char *extra)
{
- int ret = 0, len, i;
+ int ret = 0, len;
short proto_started;
unsigned long flags;
@@ -455,13 +455,6 @@ int rtllib_wx_set_essid(struct rtllib_device *ieee,
goto out;
}
- for (i = 0; i < len; i++) {
- if (extra[i] < 0) {
- ret = -1;
- goto out;
- }
- }
-
if (proto_started)
rtllib_stop_protocol(ieee, true);
diff --git a/drivers/staging/sm750fb/Kconfig b/drivers/staging/sm750fb/Kconfig
index 8c0d8a873d5b..acb6c08d09dc 100644
--- a/drivers/staging/sm750fb/Kconfig
+++ b/drivers/staging/sm750fb/Kconfig
@@ -6,6 +6,7 @@ config FB_SM750
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Frame buffer driver for the Silicon Motion SM750 chip
with 2D accelearion and dual head support.
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 168ae2e9005d..effc7fcc3703 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -1168,6 +1168,9 @@ static int __init lynxfb_init(void)
{
char *option;
+ if (fb_modesetting_disabled("sm750fb"))
+ return -ENODEV;
+
#ifdef MODULE
option = g_option;
#else
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 02fdef7a16c8..c7cd54171d99 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -1116,8 +1116,8 @@ cleanup:
if (ctlx == get_active_ctlx(hw)) {
spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
- del_singleshot_timer_sync(&hw->reqtimer);
- del_singleshot_timer_sync(&hw->resptimer);
+ del_timer_sync(&hw->reqtimer);
+ del_timer_sync(&hw->resptimer);
hw->req_timer_done = 1;
hw->resp_timer_done = 1;
usb_kill_urb(&hw->ctlx_urb);
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index e13da7fadfff..c13f1699e5a2 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -170,9 +170,9 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface)
*/
prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
- del_singleshot_timer_sync(&hw->throttle);
- del_singleshot_timer_sync(&hw->reqtimer);
- del_singleshot_timer_sync(&hw->resptimer);
+ del_timer_sync(&hw->throttle);
+ del_timer_sync(&hw->reqtimer);
+ del_timer_sync(&hw->resptimer);
/* Unlink all the URBs. This "removes the wheels"
* from the entire CTLX handling mechanism.
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 8d9f21372b67..26dc8ed3045b 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -1225,7 +1225,7 @@ int rx_data(
return -1;
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, READ, iov, iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, iov, iov_count, data);
while (msg_data_left(&msg)) {
rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
@@ -1261,7 +1261,7 @@ int tx_data(
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, WRITE, iov, iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, iov_count, data);
while (msg_data_left(&msg)) {
int tx_loop = sock_sendmsg(conn->sock, &msg);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 4407b56aa6d1..139031ccb700 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -397,6 +397,7 @@ static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host
ret = device_register(&tl_hba->dev);
if (ret) {
pr_err("device_register() failed for tl_hba->dev: %d\n", ret);
+ put_device(&tl_hba->dev);
return -ENODEV;
}
@@ -1073,7 +1074,7 @@ check_len:
*/
ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt);
if (ret)
- goto out;
+ return ERR_PTR(ret);
sh = tl_hba->sh;
tcm_loop_hba_no_cnt++;
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 28aa643be5d5..7e81a53dbf3c 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -337,7 +337,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
len += sg->length;
}
- iov_iter_bvec(&iter, READ, bvec, sgl_nents, len);
+ iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len);
if (is_write)
ret = vfs_iter_write(fd, &iter, &pos, 0);
else
@@ -473,7 +473,7 @@ fd_execute_write_same(struct se_cmd *cmd)
len += se_dev->dev_attrib.block_size;
}
- iov_iter_bvec(&iter, READ, bvec, nolb, len);
+ iov_iter_bvec(&iter, ITER_SOURCE, bvec, nolb, len);
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
kfree(bvec);
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index daf07737c4fd..2a258bd3b6b5 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -188,7 +188,7 @@ void optee_remove_common(struct optee *optee)
static int smc_abi_rc;
static int ffa_abi_rc;
-static int optee_core_init(void)
+static int __init optee_core_init(void)
{
/*
* The kernel may have crashed at the same time that all available
@@ -210,7 +210,7 @@ static int optee_core_init(void)
}
module_init(optee_core_init);
-static void optee_core_exit(void)
+static void __exit optee_core_exit(void)
{
if (!smc_abi_rc)
optee_smc_abi_unregister();
diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
index f3947be13e2e..64f0e047c23d 100644
--- a/drivers/tee/optee/device.c
+++ b/drivers/tee/optee/device.c
@@ -80,7 +80,7 @@ static int optee_register_device(const uuid_t *device_uuid)
rc = device_register(&optee_device->dev);
if (rc) {
pr_err("device registration failed, err: %d\n", rc);
- kfree(optee_device);
+ put_device(&optee_device->dev);
}
return rc;
diff --git a/drivers/thermal/gov_fair_share.c b/drivers/thermal/gov_fair_share.c
index a4ee4661e9cc..1cfeac16e7ac 100644
--- a/drivers/thermal/gov_fair_share.c
+++ b/drivers/thermal/gov_fair_share.c
@@ -49,11 +49,7 @@ static int get_trip_level(struct thermal_zone_device *tz)
static long get_target_state(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev, int percentage, int level)
{
- unsigned long max_state;
-
- cdev->ops->get_max_state(cdev, &max_state);
-
- return (long)(percentage * level * max_state) / (100 * tz->num_trips);
+ return (long)(percentage * level * cdev->max_state) / (100 * tz->num_trips);
}
/**
diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c
index a0640f762dc5..6e604bda2b93 100644
--- a/drivers/thermal/intel/intel_hfi.c
+++ b/drivers/thermal/intel/intel_hfi.c
@@ -42,9 +42,7 @@
#include "../thermal_core.h"
#include "intel_hfi.h"
-
-#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | \
- BIT(9) | BIT(11) | BIT(26))
+#include "thermal_interrupt.h"
/* Hardware Feedback Interface MSR configuration bits */
#define HW_FEEDBACK_PTR_VALID_BIT BIT(0)
@@ -137,7 +135,7 @@ struct hfi_instance {
* Parameters and supported features that are common to all HFI instances
*/
struct hfi_features {
- unsigned int nr_table_pages;
+ size_t nr_table_pages;
unsigned int cpu_stride;
unsigned int hdr_size;
};
@@ -252,7 +250,7 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
struct hfi_instance *hfi_instance;
int cpu = smp_processor_id();
struct hfi_cpu_info *info;
- u64 new_timestamp;
+ u64 new_timestamp, msr, hfi;
if (!pkg_therm_status_msr_val)
return;
@@ -281,9 +279,21 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
if (!raw_spin_trylock(&hfi_instance->event_lock))
return;
- /* Skip duplicated updates. */
+ rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr);
+ hfi = msr & PACKAGE_THERM_STATUS_HFI_UPDATED;
+ if (!hfi) {
+ raw_spin_unlock(&hfi_instance->event_lock);
+ return;
+ }
+
+ /*
+ * Ack duplicate update. Since there is an active HFI
+ * status from HW, it must be a new event, not a case
+ * where a lagging CPU entered the locked region.
+ */
new_timestamp = *(u64 *)hfi_instance->hw_table;
if (*hfi_instance->timestamp == new_timestamp) {
+ thermal_clear_package_intr_status(PACKAGE_LEVEL, PACKAGE_THERM_STATUS_HFI_UPDATED);
raw_spin_unlock(&hfi_instance->event_lock);
return;
}
@@ -297,16 +307,14 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
memcpy(hfi_instance->local_table, hfi_instance->hw_table,
hfi_features.nr_table_pages << PAGE_SHIFT);
- raw_spin_unlock(&hfi_instance->table_lock);
- raw_spin_unlock(&hfi_instance->event_lock);
-
/*
* Let hardware know that we are done reading the HFI table and it is
* free to update it again.
*/
- pkg_therm_status_msr_val &= THERM_STATUS_CLEAR_PKG_MASK &
- ~PACKAGE_THERM_STATUS_HFI_UPDATED;
- wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, pkg_therm_status_msr_val);
+ thermal_clear_package_intr_status(PACKAGE_LEVEL, PACKAGE_THERM_STATUS_HFI_UPDATED);
+
+ raw_spin_unlock(&hfi_instance->table_lock);
+ raw_spin_unlock(&hfi_instance->event_lock);
queue_delayed_work(hfi_updates_wq, &hfi_instance->update_work,
HFI_UPDATE_INTERVAL);
@@ -371,7 +379,7 @@ void intel_hfi_online(unsigned int cpu)
die_id = topology_logical_die_id(cpu);
hfi_instance = info->hfi_instance;
if (!hfi_instance) {
- if (die_id < 0 || die_id >= max_hfi_instances)
+ if (die_id >= max_hfi_instances)
return;
hfi_instance = &hfi_instances[die_id];
diff --git a/drivers/thermal/intel/intel_menlow.c b/drivers/thermal/intel/intel_menlow.c
index 101d7e791a13..3f885b08a490 100644
--- a/drivers/thermal/intel/intel_menlow.c
+++ b/drivers/thermal/intel/intel_menlow.c
@@ -179,22 +179,20 @@ static int intel_menlow_memory_add(struct acpi_device *device)
}
-static int intel_menlow_memory_remove(struct acpi_device *device)
+static void intel_menlow_memory_remove(struct acpi_device *device)
{
struct thermal_cooling_device *cdev;
if (!device)
- return -EINVAL;
+ return;
cdev = acpi_driver_data(device);
if (!cdev)
- return -EINVAL;
+ return;
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&cdev->device.kobj, "device");
thermal_cooling_device_unregister(cdev);
-
- return 0;
}
static const struct acpi_device_id intel_menlow_memory_ids[] = {
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
index 95adac427b6f..a89e7e1890e4 100644
--- a/drivers/thermal/intel/intel_tcc_cooling.c
+++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -14,6 +14,7 @@
#define TCC_SHIFT 24
#define TCC_MASK (0x3fULL<<24)
#define TCC_PROGRAMMABLE BIT(30)
+#define TCC_LOCKED BIT(31)
static struct thermal_cooling_device *tcc_cdev;
@@ -84,6 +85,7 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, NULL),
{}
};
@@ -108,6 +110,15 @@ static int __init tcc_cooling_init(void)
if (!(val & TCC_PROGRAMMABLE))
return -ENODEV;
+ err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+ if (err)
+ return err;
+
+ if (val & TCC_LOCKED) {
+ pr_info("TCC Offset locked\n");
+ return -ENODEV;
+ }
+
pr_info("Programmable TCC Offset detected\n");
tcc_cdev =
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c
index 8352083b87c7..4bb7fddaa143 100644
--- a/drivers/thermal/intel/therm_throt.c
+++ b/drivers/thermal/intel/therm_throt.c
@@ -190,32 +190,33 @@ static const struct attribute_group thermal_attr_group = {
};
#endif /* CONFIG_SYSFS */
-#define CORE_LEVEL 0
-#define PACKAGE_LEVEL 1
-
#define THERM_THROT_POLL_INTERVAL HZ
#define THERM_STATUS_PROCHOT_LOG BIT(1)
#define THERM_STATUS_CLEAR_CORE_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(13) | BIT(15))
-#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11))
+#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(26))
-static void clear_therm_status_log(int level)
+/*
+ * Clear the bits in package thermal status register for bit = 1
+ * in bitmask
+ */
+void thermal_clear_package_intr_status(int level, u64 bit_mask)
{
+ u64 msr_val;
int msr;
- u64 mask, msr_val;
if (level == CORE_LEVEL) {
msr = MSR_IA32_THERM_STATUS;
- mask = THERM_STATUS_CLEAR_CORE_MASK;
+ msr_val = THERM_STATUS_CLEAR_CORE_MASK;
} else {
msr = MSR_IA32_PACKAGE_THERM_STATUS;
- mask = THERM_STATUS_CLEAR_PKG_MASK;
+ msr_val = THERM_STATUS_CLEAR_PKG_MASK;
}
- rdmsrl(msr, msr_val);
- msr_val &= mask;
- wrmsrl(msr, msr_val & ~THERM_STATUS_PROCHOT_LOG);
+ msr_val &= ~bit_mask;
+ wrmsrl(msr, msr_val);
}
+EXPORT_SYMBOL_GPL(thermal_clear_package_intr_status);
static void get_therm_status(int level, bool *proc_hot, u8 *temp)
{
@@ -295,7 +296,7 @@ static void __maybe_unused throttle_active_work(struct work_struct *work)
state->average = avg;
re_arm:
- clear_therm_status_log(state->level);
+ thermal_clear_package_intr_status(state->level, THERM_STATUS_PROCHOT_LOG);
schedule_delayed_work_on(this_cpu, &state->therm_work, THERM_THROT_POLL_INTERVAL);
}
diff --git a/drivers/thermal/intel/thermal_interrupt.h b/drivers/thermal/intel/thermal_interrupt.h
index 01e7bed2ffc7..01dfd4cdb5df 100644
--- a/drivers/thermal/intel/thermal_interrupt.h
+++ b/drivers/thermal/intel/thermal_interrupt.h
@@ -2,6 +2,9 @@
#ifndef _INTEL_THERMAL_INTERRUPT_H
#define _INTEL_THERMAL_INTERRUPT_H
+#define CORE_LEVEL 0
+#define PACKAGE_LEVEL 1
+
/* Interrupt Handler for package thermal thresholds */
extern int (*platform_thermal_package_notify)(__u64 msr_val);
@@ -15,4 +18,7 @@ extern bool (*platform_thermal_package_rate_control)(void);
/* Handle HWP interrupt */
extern void notify_hwp_interrupt(void);
+/* Common function to clear Package thermal status register */
+extern void thermal_clear_package_intr_status(int level, u64 bit_mask);
+
#endif /* _INTEL_THERMAL_INTERRUPT_H */
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index a0e234fce71a..84c3a116ed04 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -265,7 +265,6 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
struct thermal_zone_device *tzone = NULL;
int cpu = smp_processor_id();
struct zone_device *zonedev;
- u64 msr_val, wr_val;
mutex_lock(&thermal_zone_mutex);
raw_spin_lock_irq(&pkg_temp_lock);
@@ -279,12 +278,8 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
}
zonedev->work_scheduled = false;
- rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
- wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
- if (wr_val != msr_val) {
- wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val);
- tzone = zonedev->tzone;
- }
+ thermal_clear_package_intr_status(PACKAGE_LEVEL, THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
+ tzone = zonedev->tzone;
enable_pkg_thres_interrupt();
raw_spin_unlock_irq(&pkg_temp_lock);
diff --git a/drivers/thermal/tegra/tegra-bpmp-thermal.c b/drivers/thermal/tegra/tegra-bpmp-thermal.c
index eb84f0b9dc7c..0b7a1a1948cb 100644
--- a/drivers/thermal/tegra/tegra-bpmp-thermal.c
+++ b/drivers/thermal/tegra/tegra-bpmp-thermal.c
@@ -106,21 +106,22 @@ static void tz_device_update_work_fn(struct work_struct *work)
static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
void *data)
{
- struct mrq_thermal_bpmp_to_host_request *req;
+ struct mrq_thermal_bpmp_to_host_request req;
struct tegra_bpmp_thermal *tegra = data;
+ size_t offset;
int i;
- req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
+ offset = offsetof(struct tegra_bpmp_mb_data, data);
+ iosys_map_memcpy_from(&req, &ch->ib, offset, sizeof(req));
- if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
- dev_err(tegra->dev, "%s: invalid request type: %d\n",
- __func__, req->type);
+ if (req.type != CMD_THERMAL_HOST_TRIP_REACHED) {
+ dev_err(tegra->dev, "%s: invalid request type: %d\n", __func__, req.type);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
return;
}
for (i = 0; i < tegra->num_zones; ++i) {
- if (tegra->zones[i]->idx != req->host_trip_reached.zone)
+ if (tegra->zones[i]->idx != req.host_trip_reached.zone)
continue;
schedule_work(&tegra->zones[i]->tz_device_update_work);
@@ -129,7 +130,7 @@ static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
}
dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
- req->host_trip_reached.zone);
+ req.host_trip_reached.zone);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
}
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 117eeaf7dd24..f17ab2316dbd 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -203,6 +203,9 @@ int thermal_zone_device_set_policy(struct thermal_zone_device *tz,
mutex_lock(&thermal_governor_lock);
mutex_lock(&tz->lock);
+ if (!device_is_registered(&tz->device))
+ goto exit;
+
gov = __find_governor(strim(policy));
if (!gov)
goto exit;
@@ -403,6 +406,34 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
pos->initialized = false;
}
+void __thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_notify_event event)
+{
+ int count;
+
+ if (atomic_read(&in_suspend))
+ return;
+
+ if (WARN_ONCE(!tz->ops->get_temp,
+ "'%s' must not be called without 'get_temp' ops set\n",
+ __func__))
+ return;
+
+ if (!thermal_zone_device_is_enabled(tz))
+ return;
+
+ update_temperature(tz);
+
+ __thermal_zone_set_trips(tz);
+
+ tz->notify_event = event;
+
+ for (count = 0; count < tz->num_trips; count++)
+ handle_thermal_trip(tz, count);
+
+ monitor_thermal_zone(tz);
+}
+
static int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
enum thermal_device_mode mode)
{
@@ -417,15 +448,21 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
return ret;
}
+ if (!device_is_registered(&tz->device)) {
+ mutex_unlock(&tz->lock);
+
+ return -ENODEV;
+ }
+
if (tz->ops->change_mode)
ret = tz->ops->change_mode(tz, mode);
if (!ret)
tz->mode = mode;
- mutex_unlock(&tz->lock);
+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+ mutex_unlock(&tz->lock);
if (mode == THERMAL_DEVICE_ENABLED)
thermal_notify_tz_enable(tz->id);
@@ -457,31 +494,9 @@ int thermal_zone_device_is_enabled(struct thermal_zone_device *tz)
void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event)
{
- int count;
-
- if (atomic_read(&in_suspend))
- return;
-
- if (WARN_ONCE(!tz->ops->get_temp, "'%s' must not be called without "
- "'get_temp' ops set\n", __func__))
- return;
-
mutex_lock(&tz->lock);
-
- if (!thermal_zone_device_is_enabled(tz))
- goto out;
-
- update_temperature(tz);
-
- __thermal_zone_set_trips(tz);
-
- tz->notify_event = event;
-
- for (count = 0; count < tz->num_trips; count++)
- handle_thermal_trip(tz, count);
-
- monitor_thermal_zone(tz);
-out:
+ if (device_is_registered(&tz->device))
+ __thermal_zone_device_update(tz, event);
mutex_unlock(&tz->lock);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
@@ -603,8 +618,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
struct thermal_instance *pos;
struct thermal_zone_device *pos1;
struct thermal_cooling_device *pos2;
- unsigned long max_state;
- int result, ret;
+ int result;
if (trip >= tz->num_trips || trip < 0)
return -EINVAL;
@@ -621,15 +635,11 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
if (tz != pos1 || cdev != pos2)
return -EINVAL;
- ret = cdev->ops->get_max_state(cdev, &max_state);
- if (ret)
- return ret;
-
/* lower default 0, upper default max_state */
lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
- upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+ upper = upper == THERMAL_NO_LIMIT ? cdev->max_state : upper;
- if (lower > upper || upper > max_state)
+ if (lower > upper || upper > cdev->max_state)
return -EINVAL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -759,6 +769,7 @@ static void thermal_release(struct device *dev)
sizeof("thermal_zone") - 1)) {
tz = to_thermal_zone(dev);
thermal_zone_destroy_device_groups(tz);
+ mutex_destroy(&tz->lock);
kfree(tz);
} else if (!strncmp(dev_name(dev), "cooling_device",
sizeof("cooling_device") - 1)) {
@@ -883,10 +894,6 @@ __thermal_cooling_device_register(struct device_node *np,
cdev->id = ret;
id = ret;
- ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
- if (ret)
- goto out_ida_remove;
-
cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
if (!cdev->type) {
ret = -ENOMEM;
@@ -900,7 +907,17 @@ __thermal_cooling_device_register(struct device_node *np,
cdev->updated = false;
cdev->device.class = &thermal_class;
cdev->devdata = devdata;
+
+ ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
+ if (ret)
+ goto out_kfree_type;
+
thermal_cooling_device_setup_sysfs(cdev);
+ ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
+ if (ret) {
+ thermal_cooling_device_destroy_sysfs(cdev);
+ goto out_kfree_type;
+ }
ret = device_register(&cdev->device);
if (ret)
goto out_kfree_type;
@@ -1234,10 +1251,6 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
tz->id = id;
strscpy(tz->type, type, sizeof(tz->type));
- result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
- if (result)
- goto remove_id;
-
if (!ops->critical)
ops->critical = thermal_zone_device_critical;
@@ -1260,6 +1273,11 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
/* A new thermal zone needs to be updated anyway. */
atomic_set(&tz->need_update, 1);
+ result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
+ if (result) {
+ thermal_zone_destroy_device_groups(tz);
+ goto remove_id;
+ }
result = device_register(&tz->device);
if (result)
goto release_device;
@@ -1390,8 +1408,12 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
thermal_remove_hwmon_sysfs(tz);
ida_free(&thermal_tz_ida, tz->id);
ida_destroy(&tz->ida);
- mutex_destroy(&tz->lock);
- device_unregister(&tz->device);
+
+ mutex_lock(&tz->lock);
+ device_del(&tz->device);
+ mutex_unlock(&tz->lock);
+
+ put_device(&tz->device);
thermal_notify_tz_delete(tz_id);
}
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 1571917bd3c8..b834cb273429 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -109,9 +109,10 @@ int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);
int thermal_zone_device_set_policy(struct thermal_zone_device *, char *);
int thermal_build_list_of_policies(char *buf);
+void __thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_notify_event event);
/* Helpers */
-void thermal_zone_set_trips(struct thermal_zone_device *tz);
void __thermal_zone_set_trips(struct thermal_zone_device *tz);
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c
index c65cdce8f856..56aa2e88f34f 100644
--- a/drivers/thermal/thermal_helpers.c
+++ b/drivers/thermal/thermal_helpers.c
@@ -64,6 +64,20 @@ get_thermal_instance(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL(get_thermal_instance);
+/**
+ * __thermal_zone_get_temp() - returns the temperature of a thermal zone
+ * @tz: a valid pointer to a struct thermal_zone_device
+ * @temp: a valid pointer to where to store the resulting temperature.
+ *
+ * When a valid thermal zone reference is passed, it will fetch its
+ * temperature and fill @temp.
+ *
+ * Both tz and tz->ops must be valid pointers when calling this function,
+ * and the tz->ops->get_temp callback must be provided.
+ * The function must be called under tz->lock.
+ *
+ * Return: On success returns 0, an error code otherwise
+ */
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
{
int ret = -EINVAL;
@@ -73,9 +87,6 @@ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
lockdep_assert_held(&tz->lock);
- if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
- return -EINVAL;
-
ret = tz->ops->get_temp(tz, temp);
if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
@@ -114,14 +125,43 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
{
int ret;
+ if (IS_ERR_OR_NULL(tz))
+ return -EINVAL;
+
mutex_lock(&tz->lock);
- ret = __thermal_zone_get_temp(tz, temp);
+
+ if (!tz->ops->get_temp) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (device_is_registered(&tz->device))
+ ret = __thermal_zone_get_temp(tz, temp);
+ else
+ ret = -ENODEV;
+
+unlock:
mutex_unlock(&tz->lock);
return ret;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+/**
+ * __thermal_zone_set_trips - Computes the next trip points for the driver
+ * @tz: a pointer to a thermal zone device structure
+ *
+ * The function computes the next temperature boundaries by browsing
+ * the trip points. The result is the closer low and high trip points
+ * to the current temperature. These values are passed to the backend
+ * driver to let it set its own notification mechanism (usually an
+ * interrupt).
+ *
+ * This function must be called with tz->lock held. Both tz and tz->ops
+ * must be valid pointers.
+ *
+ * It does not return a value
+ */
void __thermal_zone_set_trips(struct thermal_zone_device *tz)
{
int low = -INT_MAX;
@@ -168,25 +208,6 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
}
-/**
- * thermal_zone_set_trips - Computes the next trip points for the driver
- * @tz: a pointer to a thermal zone device structure
- *
- * The function computes the next temperature boundaries by browsing
- * the trip points. The result is the closer low and high trip points
- * to the current temperature. These values are passed to the backend
- * driver to let it set its own notification mechanism (usually an
- * interrupt).
- *
- * It does not return a value
- */
-void thermal_zone_set_trips(struct thermal_zone_device *tz)
-{
- mutex_lock(&tz->lock);
- __thermal_zone_set_trips(tz);
- mutex_unlock(&tz->lock);
-}
-
static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
int target)
{
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
index f53f4ceb6a5d..c594c42bea6d 100644
--- a/drivers/thermal/thermal_hwmon.c
+++ b/drivers/thermal/thermal_hwmon.c
@@ -77,7 +77,15 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
int temperature;
int ret;
- ret = tz->ops->get_crit_temp(tz, &temperature);
+ mutex_lock(&tz->lock);
+
+ if (device_is_registered(&tz->device))
+ ret = tz->ops->get_crit_temp(tz, &temperature);
+ else
+ ret = -ENODEV;
+
+ mutex_unlock(&tz->lock);
+
if (ret)
return ret;
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index ec495c7dff03..d97f0bc0a26b 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -92,7 +92,14 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_type", &trip) != 1)
return -EINVAL;
- result = tz->ops->get_trip_type(tz, trip, &type);
+ mutex_lock(&tz->lock);
+
+ if (device_is_registered(dev))
+ result = tz->ops->get_trip_type(tz, trip, &type);
+ else
+ result = -ENODEV;
+
+ mutex_unlock(&tz->lock);
if (result)
return result;
@@ -128,10 +135,17 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
if (kstrtoint(buf, 10, &temperature))
return -EINVAL;
+ mutex_lock(&tz->lock);
+
+ if (!device_is_registered(dev)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
if (tz->ops->set_trip_temp) {
ret = tz->ops->set_trip_temp(tz, trip, temperature);
if (ret)
- return ret;
+ goto unlock;
}
if (tz->trips)
@@ -140,16 +154,22 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
if (tz->ops->get_trip_hyst) {
ret = tz->ops->get_trip_hyst(tz, trip, &hyst);
if (ret)
- return ret;
+ goto unlock;
}
ret = tz->ops->get_trip_type(tz, trip, &type);
if (ret)
- return ret;
+ goto unlock;
thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst);
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+unlock:
+ mutex_unlock(&tz->lock);
+
+ if (ret)
+ return ret;
return count;
}
@@ -168,7 +188,14 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1)
return -EINVAL;
- ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+ mutex_lock(&tz->lock);
+
+ if (device_is_registered(dev))
+ ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+ else
+ ret = -ENODEV;
+
+ mutex_unlock(&tz->lock);
if (ret)
return ret;
@@ -193,6 +220,13 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
if (kstrtoint(buf, 10, &temperature))
return -EINVAL;
+ mutex_lock(&tz->lock);
+
+ if (!device_is_registered(dev)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
/*
* We are not doing any check on the 'temperature' value
* here. The driver implementing 'set_trip_hyst' has to
@@ -201,7 +235,10 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
ret = tz->ops->set_trip_hyst(tz, trip, temperature);
if (!ret)
- thermal_zone_set_trips(tz);
+ __thermal_zone_set_trips(tz);
+
+unlock:
+ mutex_unlock(&tz->lock);
return ret ? ret : count;
}
@@ -220,7 +257,14 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1)
return -EINVAL;
- ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
+ mutex_lock(&tz->lock);
+
+ if (device_is_registered(dev))
+ ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
+ else
+ ret = -ENODEV;
+
+ mutex_unlock(&tz->lock);
return ret ? ret : sprintf(buf, "%d\n", temperature);
}
@@ -269,16 +313,23 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
if (kstrtoint(buf, 10, &temperature))
return -EINVAL;
- if (!tz->ops->set_emul_temp) {
- mutex_lock(&tz->lock);
+ mutex_lock(&tz->lock);
+
+ if (!device_is_registered(dev)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (!tz->ops->set_emul_temp)
tz->emul_temperature = temperature;
- mutex_unlock(&tz->lock);
- } else {
+ else
ret = tz->ops->set_emul_temp(tz, temperature);
- }
if (!ret)
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+unlock:
+ mutex_unlock(&tz->lock);
return ret ? ret : count;
}
@@ -589,13 +640,8 @@ static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int ret;
- ret = cdev->ops->get_max_state(cdev, &state);
- if (ret)
- return ret;
- return sprintf(buf, "%ld\n", state);
+ return sprintf(buf, "%ld\n", cdev->max_state);
}
static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
@@ -625,6 +671,10 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
if ((long)state < 0)
return -EINVAL;
+ /* Requested state should be less than max_state + 1 */
+ if (state > cdev->max_state)
+ return -EINVAL;
+
mutex_lock(&cdev->lock);
result = cdev->ops->set_cur_state(cdev, state);
@@ -662,7 +712,6 @@ struct cooling_dev_stats {
spinlock_t lock;
unsigned int total_trans;
unsigned long state;
- unsigned long max_states;
ktime_t last_time;
ktime_t *time_in_state;
unsigned int *trans_table;
@@ -692,7 +741,7 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
goto unlock;
update_time_in_state(stats);
- stats->trans_table[stats->state * stats->max_states + new_state]++;
+ stats->trans_table[stats->state * (cdev->max_state + 1) + new_state]++;
stats->state = new_state;
stats->total_trans++;
@@ -726,7 +775,7 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
spin_lock(&stats->lock);
update_time_in_state(stats);
- for (i = 0; i < stats->max_states; i++) {
+ for (i = 0; i <= cdev->max_state; i++) {
len += sprintf(buf + len, "state%u\t%llu\n", i,
ktime_to_ms(stats->time_in_state[i]));
}
@@ -741,7 +790,7 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats;
- int i, states = stats->max_states;
+ int i, states = cdev->max_state + 1;
spin_lock(&stats->lock);
@@ -750,7 +799,7 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
memset(stats->trans_table, 0,
states * states * sizeof(*stats->trans_table));
- for (i = 0; i < stats->max_states; i++)
+ for (i = 0; i < states; i++)
stats->time_in_state[i] = ktime_set(0, 0);
spin_unlock(&stats->lock);
@@ -768,7 +817,7 @@ static ssize_t trans_table_show(struct device *dev,
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
- for (i = 0; i < stats->max_states; i++) {
+ for (i = 0; i <= cdev->max_state; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
@@ -778,17 +827,17 @@ static ssize_t trans_table_show(struct device *dev,
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
- for (i = 0; i < stats->max_states; i++) {
+ for (i = 0; i <= cdev->max_state; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
- for (j = 0; j < stats->max_states; j++) {
+ for (j = 0; j <= cdev->max_state; j++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%8u ",
- stats->trans_table[i * stats->max_states + j]);
+ stats->trans_table[i * (cdev->max_state + 1) + j]);
}
if (len >= PAGE_SIZE)
break;
@@ -824,14 +873,10 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
{
const struct attribute_group *stats_attr_group = NULL;
struct cooling_dev_stats *stats;
- unsigned long states;
+ /* Total number of states is highest state + 1 */
+ unsigned long states = cdev->max_state + 1;
int var;
- if (cdev->ops->get_max_state(cdev, &states))
- goto out;
-
- states++; /* Total number of states is highest state + 1 */
-
var = sizeof(*stats);
var += sizeof(*stats->time_in_state) * states;
var += sizeof(*stats->trans_table) * states * states;
@@ -844,7 +889,6 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
stats->trans_table = (unsigned int *)(stats->time_in_state + states);
cdev->stats = stats;
stats->last_time = ktime_get();
- stats->max_states = states;
spin_lock_init(&stats->lock);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 4802cfaa107f..a683e21df19c 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -264,8 +264,8 @@ static void hvc_port_destruct(struct tty_port *port)
static void hvc_check_console(int index)
{
- /* Already enabled, bail out */
- if (hvc_console.flags & CON_ENABLED)
+ /* Already registered, bail out */
+ if (console_is_registered(&hvc_console))
return;
/* If this index is what the user requested, then register
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 5e516f5cac5a..b6e0cc4571ea 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -264,7 +264,7 @@ struct gsm_mux {
bool constipated; /* Asked by remote to shut up */
bool has_devices; /* Devices were registered */
- struct mutex tx_mutex;
+ spinlock_t tx_lock;
unsigned int tx_bytes; /* TX data outstanding */
#define TX_THRESH_HI 8192
#define TX_THRESH_LO 2048
@@ -272,7 +272,7 @@ struct gsm_mux {
struct list_head tx_data_list; /* Pending data packets */
/* Control messages */
- struct delayed_work kick_timeout; /* Kick TX queuing on timeout */
+ struct timer_list kick_timer; /* Kick TX queuing on timeout */
struct timer_list t2_timer; /* Retransmit timer for commands */
int cretries; /* Command retry counter */
struct gsm_control *pending_cmd;/* Our current pending command */
@@ -700,6 +700,7 @@ static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
struct gsm_msg *msg;
u8 *dp;
int ocr;
+ unsigned long flags;
msg = gsm_data_alloc(gsm, addr, 0, control);
if (!msg)
@@ -721,10 +722,10 @@ static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
gsm_print_packet("Q->", addr, cr, control, NULL, 0);
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
list_add_tail(&msg->list, &gsm->tx_ctrl_list);
gsm->tx_bytes += msg->len;
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
gsmld_write_trigger(gsm);
return 0;
@@ -749,7 +750,7 @@ static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci)
spin_unlock_irqrestore(&dlci->lock, flags);
/* Clear data packets in MUX write queue */
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) {
if (msg->addr != addr)
continue;
@@ -757,7 +758,7 @@ static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci)
list_del(&msg->list);
kfree(msg);
}
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
@@ -1028,7 +1029,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
gsm->tx_bytes += msg->len;
gsmld_write_trigger(gsm);
- schedule_delayed_work(&gsm->kick_timeout, 10 * gsm->t1 * HZ / 100);
+ mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100);
}
/**
@@ -1043,9 +1044,10 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
{
- mutex_lock(&dlci->gsm->tx_mutex);
+ unsigned long flags;
+ spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
__gsm_data_queue(dlci, msg);
- mutex_unlock(&dlci->gsm->tx_mutex);
+ spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
/**
@@ -1057,7 +1059,7 @@ static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
* is data. Keep to the MRU of the mux. This path handles the usual tty
* interface which is a byte stream with optional modem data.
*
- * Caller must hold the tx_mutex of the mux.
+ * Caller must hold the tx_lock of the mux.
*/
static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
@@ -1117,7 +1119,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
* is data. Keep to the MRU of the mux. This path handles framed data
* queued as skbuffs to the DLCI.
*
- * Caller must hold the tx_mutex of the mux.
+ * Caller must hold the tx_lock of the mux.
*/
static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
@@ -1133,7 +1135,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
if (dlci->adaption == 4)
overhead = 1;
- /* dlci->skb is locked by tx_mutex */
+ /* dlci->skb is locked by tx_lock */
if (dlci->skb == NULL) {
dlci->skb = skb_dequeue_tail(&dlci->skb_list);
if (dlci->skb == NULL)
@@ -1187,7 +1189,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
* Push an empty frame in to the transmit queue to update the modem status
* bits and to transmit an optional break.
*
- * Caller must hold the tx_mutex of the mux.
+ * Caller must hold the tx_lock of the mux.
*/
static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
@@ -1301,12 +1303,13 @@ static int gsm_dlci_data_sweep(struct gsm_mux *gsm)
static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
{
+ unsigned long flags;
int sweep;
if (dlci->constipated)
return;
- mutex_lock(&dlci->gsm->tx_mutex);
+ spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
/* If we have nothing running then we need to fire up */
sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
if (dlci->gsm->tx_bytes == 0) {
@@ -1317,7 +1320,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
}
if (sweep)
gsm_dlci_data_sweep(dlci->gsm);
- mutex_unlock(&dlci->gsm->tx_mutex);
+ spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
/*
@@ -1708,7 +1711,7 @@ static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
unsigned int command, u8 *data, int clen)
{
struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
- GFP_KERNEL);
+ GFP_ATOMIC);
unsigned long flags;
if (ctrl == NULL)
return NULL;
@@ -2019,23 +2022,24 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
}
/**
- * gsm_kick_timeout - transmit if possible
- * @work: work contained in our gsm object
+ * gsm_kick_timer - transmit if possible
+ * @t: timer contained in our gsm object
*
* Transmit data from DLCIs if the queue is empty. We can't rely on
* a tty wakeup except when we filled the pipe so we need to fire off
* new data ourselves in other cases.
*/
-static void gsm_kick_timeout(struct work_struct *work)
+static void gsm_kick_timer(struct timer_list *t)
{
- struct gsm_mux *gsm = container_of(work, struct gsm_mux, kick_timeout.work);
+ struct gsm_mux *gsm = from_timer(gsm, t, kick_timer);
+ unsigned long flags;
int sent = 0;
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
/* If we have nothing running then we need to fire up */
if (gsm->tx_bytes < TX_THRESH_LO)
sent = gsm_dlci_data_sweep(gsm);
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
if (sent && debug & DBG_DATA)
pr_info("%s TX queue stalled\n", __func__);
@@ -2492,7 +2496,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
}
/* Finish outstanding timers, making sure they are done */
- cancel_delayed_work_sync(&gsm->kick_timeout);
+ del_timer_sync(&gsm->kick_timer);
del_timer_sync(&gsm->t2_timer);
/* Finish writing to ldisc */
@@ -2565,7 +2569,6 @@ static void gsm_free_mux(struct gsm_mux *gsm)
break;
}
}
- mutex_destroy(&gsm->tx_mutex);
mutex_destroy(&gsm->mutex);
kfree(gsm->txframe);
kfree(gsm->buf);
@@ -2637,15 +2640,15 @@ static struct gsm_mux *gsm_alloc_mux(void)
}
spin_lock_init(&gsm->lock);
mutex_init(&gsm->mutex);
- mutex_init(&gsm->tx_mutex);
kref_init(&gsm->ref);
INIT_LIST_HEAD(&gsm->tx_ctrl_list);
INIT_LIST_HEAD(&gsm->tx_data_list);
- INIT_DELAYED_WORK(&gsm->kick_timeout, gsm_kick_timeout);
+ timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
INIT_WORK(&gsm->tx_work, gsmld_write_task);
init_waitqueue_head(&gsm->event);
spin_lock_init(&gsm->control_lock);
+ spin_lock_init(&gsm->tx_lock);
gsm->t1 = T1;
gsm->t2 = T2;
@@ -2670,7 +2673,6 @@ static struct gsm_mux *gsm_alloc_mux(void)
}
spin_unlock(&gsm_mux_lock);
if (i == MAX_MUX) {
- mutex_destroy(&gsm->tx_mutex);
mutex_destroy(&gsm->mutex);
kfree(gsm->txframe);
kfree(gsm->buf);
@@ -2826,16 +2828,17 @@ static void gsmld_write_trigger(struct gsm_mux *gsm)
static void gsmld_write_task(struct work_struct *work)
{
struct gsm_mux *gsm = container_of(work, struct gsm_mux, tx_work);
+ unsigned long flags;
int i, ret;
/* All outstanding control channel and control messages and one data
* frame is sent.
*/
ret = -ENODEV;
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
if (gsm->tty)
ret = gsm_data_kick(gsm);
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
if (ret >= 0)
for (i = 0; i < NUM_DLCI; i++)
@@ -3042,6 +3045,7 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
struct gsm_mux *gsm = tty->disc_data;
+ unsigned long flags;
int space;
int ret;
@@ -3049,13 +3053,13 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
return -ENODEV;
ret = -ENOBUFS;
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
space = tty_write_room(tty);
if (space >= nr)
ret = tty->ops->write(tty, buf, nr);
else
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
return ret;
}
@@ -3352,13 +3356,14 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
{
struct gsm_mux *gsm = dlci->gsm;
+ unsigned long flags;
if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
return;
- mutex_lock(&gsm->tx_mutex);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_modem_output(gsm, dlci, brk);
- mutex_unlock(&gsm->tx_mutex);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 94fbf0add2ce..74568292186f 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -565,7 +565,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
up->port.dev = dev;
- if (uart_console_enabled(&up->port))
+ if (uart_console_registered(&up->port))
pm_runtime_get_sync(up->port.dev);
serial8250_apply_quirks(up);
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 44cc755b1a29..0e43bdfb7459 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -174,6 +174,8 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
*/
up->dma = dma;
+ lpss->dma_maxburst = 16;
+
port->set_termios = dw8250_do_set_termios;
return 0;
@@ -277,8 +279,13 @@ static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port
struct dw_dma_slave *rx_param, *tx_param;
struct device *dev = port->port.dev;
- if (!lpss->dma_param.dma_dev)
+ if (!lpss->dma_param.dma_dev) {
+ dma = port->dma;
+ if (dma)
+ goto out_configuration_only;
+
return 0;
+ }
rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
if (!rx_param)
@@ -289,16 +296,18 @@ static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port
return -ENOMEM;
*rx_param = lpss->dma_param;
- dma->rxconf.src_maxburst = lpss->dma_maxburst;
-
*tx_param = lpss->dma_param;
- dma->txconf.dst_maxburst = lpss->dma_maxburst;
dma->fn = lpss8250_dma_filter;
dma->rx_param = rx_param;
dma->tx_param = tx_param;
port->dma = dma;
+
+out_configuration_only:
+ dma->rxconf.src_maxburst = lpss->dma_maxburst;
+ dma->txconf.dst_maxburst = lpss->dma_maxburst;
+
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 41b8c6b27136..3f33014022f0 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -157,7 +157,11 @@ static u32 uart_read(struct uart_8250_port *up, u32 reg)
return readl(up->port.membase + (reg << up->port.regshift));
}
-static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+/*
+ * Called on runtime PM resume path from omap8250_restore_regs(), and
+ * omap8250_set_mctrl().
+ */
+static void __omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
@@ -181,6 +185,20 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
}
}
+static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ int err;
+
+ err = pm_runtime_resume_and_get(port->dev);
+ if (err)
+ return;
+
+ __omap8250_set_mctrl(port, mctrl);
+
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
+}
+
/*
* Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
* The access to uart register after MDR1 Access
@@ -193,27 +211,10 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void omap_8250_mdr1_errataset(struct uart_8250_port *up,
struct omap8250_priv *priv)
{
- u8 timeout = 255;
-
serial_out(up, UART_OMAP_MDR1, priv->mdr1);
udelay(2);
serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT |
UART_FCR_CLEAR_RCVR);
- /*
- * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
- * TX_FIFO_E bit is 1.
- */
- while (UART_LSR_THRE != (serial_in(up, UART_LSR) &
- (UART_LSR_THRE | UART_LSR_DR))) {
- timeout--;
- if (!timeout) {
- /* Should *never* happen. we warn and carry on */
- dev_crit(up->port.dev, "Errata i202: timedout %x\n",
- serial_in(up, UART_LSR));
- break;
- }
- udelay(1);
- }
}
static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud,
@@ -292,6 +293,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
{
struct omap8250_priv *priv = up->port.private_data;
struct uart_8250_dma *dma = up->dma;
+ u8 mcr = serial8250_in_MCR(up);
if (dma && dma->tx_running) {
/*
@@ -308,7 +310,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial_out(up, UART_EFR, UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- serial8250_out_MCR(up, UART_MCR_TCRTLR);
+ serial8250_out_MCR(up, mcr | UART_MCR_TCRTLR);
serial_out(up, UART_FCR, up->fcr);
omap8250_update_scr(up, priv);
@@ -324,7 +326,8 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial_out(up, UART_LCR, 0);
/* drop TCR + TLR access, we setup XON/XOFF later */
- serial8250_out_MCR(up, up->mcr);
+ serial8250_out_MCR(up, mcr);
+
serial_out(up, UART_IER, up->ier);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -341,7 +344,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
omap8250_update_mdr1(up, priv);
- up->port.ops->set_mctrl(&up->port, up->port.mctrl);
+ __omap8250_set_mctrl(&up->port, up->port.mctrl);
if (up->port.rs485.flags & SER_RS485_ENABLED)
serial8250_em485_stop_tx(up);
@@ -669,7 +672,6 @@ static int omap_8250_startup(struct uart_port *port)
pm_runtime_get_sync(port->dev);
- up->mcr = 0;
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, UART_LCR, UART_LCR_WLEN8);
@@ -1458,9 +1460,15 @@ err:
static int omap8250_remove(struct platform_device *pdev)
{
struct omap8250_priv *priv = platform_get_drvdata(pdev);
+ int err;
+
+ err = pm_runtime_resume_and_get(&pdev->dev);
+ if (err)
+ return err;
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
+ flush_work(&priv->qos_work);
pm_runtime_disable(&pdev->dev);
serial8250_unregister_port(priv->line);
cpu_latency_qos_remove_request(&priv->pm_qos_request);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index fe8662cd9402..388172289627 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1897,10 +1897,13 @@ EXPORT_SYMBOL_GPL(serial8250_modem_status);
static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
{
switch (iir & 0x3f) {
- case UART_IIR_RX_TIMEOUT:
- serial8250_rx_dma_flush(up);
+ case UART_IIR_RDI:
+ if (!up->dma->rx_running)
+ break;
fallthrough;
case UART_IIR_RLSI:
+ case UART_IIR_RX_TIMEOUT:
+ serial8250_rx_dma_flush(up);
return true;
}
return up->dma->rx_dma(up);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index a5f380584cda..4f6e9bf57169 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -181,7 +181,7 @@ int __init setup_earlycon(char *buf)
if (!buf || !buf[0])
return -EINVAL;
- if (early_con.flags & CON_ENABLED)
+ if (console_is_registered(&early_con))
return -EALREADY;
again:
@@ -253,7 +253,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
bool big_endian;
u64 addr;
- if (early_con.flags & CON_ENABLED)
+ if (console_is_registered(&early_con))
return -EALREADY;
spin_lock_init(&port->lock);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 67fa113f77d4..888e01fbd9c5 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -12,6 +12,7 @@
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -404,33 +405,6 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
-static int lpuart_global_reset(struct lpuart_port *sport)
-{
- struct uart_port *port = &sport->port;
- void __iomem *global_addr;
- int ret;
-
- if (uart_console(port))
- return 0;
-
- ret = clk_prepare_enable(sport->ipg_clk);
- if (ret) {
- dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
- return ret;
- }
-
- if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
- global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
- writel(UART_GLOBAL_RST, global_addr);
- usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
- writel(0, global_addr);
- usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
- }
-
- clk_disable_unprepare(sport->ipg_clk);
- return 0;
-}
-
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -2636,6 +2610,54 @@ static const struct serial_rs485 lpuart_rs485_supported = {
/* delay_rts_* and RX_DURING_TX are not supported */
};
+static int lpuart_global_reset(struct lpuart_port *sport)
+{
+ struct uart_port *port = &sport->port;
+ void __iomem *global_addr;
+ unsigned long ctrl, bd;
+ unsigned int val = 0;
+ int ret;
+
+ ret = clk_prepare_enable(sport->ipg_clk);
+ if (ret) {
+ dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
+ /*
+ * If the transmitter is used by earlycon, wait for transmit engine to
+ * complete and then reset.
+ */
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_TE) {
+ bd = lpuart32_read(&sport->port, UARTBAUD);
+ if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false,
+ port)) {
+ dev_warn(sport->port.dev,
+ "timeout waiting for transmit engine to complete\n");
+ clk_disable_unprepare(sport->ipg_clk);
+ return 0;
+ }
+ }
+
+ global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
+ writel(UART_GLOBAL_RST, global_addr);
+ usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
+ writel(0, global_addr);
+ usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
+
+ /* Recover the transmitter for earlycon. */
+ if (ctrl & UARTCTRL_TE) {
+ lpuart32_write(port, bd, UARTBAUD);
+ lpuart32_write(port, ctrl, UARTCTRL);
+ }
+ }
+
+ clk_disable_unprepare(sport->ipg_clk);
+ return 0;
+}
+
static int lpuart_probe(struct platform_device *pdev)
{
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 05b432dc7a85..aadda66405b4 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2594,6 +2594,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = {
.suspend_noirq = imx_uart_suspend_noirq,
.resume_noirq = imx_uart_resume_noirq,
.freeze_noirq = imx_uart_suspend_noirq,
+ .thaw_noirq = imx_uart_resume_noirq,
.restore_noirq = imx_uart_resume_noirq,
.suspend = imx_uart_suspend,
.resume = imx_uart_resume,
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 7aa37be3216a..a3ed9b34e2ab 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -189,9 +189,27 @@ static int configure_kgdboc(void)
if (kgdboc_register_kbd(&cptr))
goto do_register;
+ /*
+ * tty_find_polling_driver() can call uart_set_options()
+ * (via poll_init) to configure the uart. Take the console_list_lock
+ * in order to synchronize against register_console(), which can also
+ * configure the uart via uart_set_options(). This also allows safe
+ * traversal of the console list.
+ */
+ console_list_lock();
+
p = tty_find_polling_driver(cptr, &tty_line);
- if (!p)
+ if (!p) {
+ console_list_unlock();
goto noconfig;
+ }
+
+ /*
+ * Take console_lock to serialize device() callback with
+ * other console operations. For example, fg_console is
+ * modified under console_lock when switching vt.
+ */
+ console_lock();
for_each_console(cons) {
int idx;
@@ -202,6 +220,10 @@ static int configure_kgdboc(void)
}
}
+ console_unlock();
+
+ console_list_unlock();
+
kgdb_tty_driver = p;
kgdb_tty_line = tty_line;
@@ -449,6 +471,7 @@ static void kgdboc_earlycon_pre_exp_handler(void)
{
struct console *con;
static bool already_warned;
+ int cookie;
if (already_warned)
return;
@@ -461,9 +484,14 @@ static void kgdboc_earlycon_pre_exp_handler(void)
* serial drivers might be OK with this, print a warning once per
* boot if we detect this case.
*/
- for_each_console(con)
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(con) {
if (con == kgdboc_earlycon_io_ops.cons)
- return;
+ break;
+ }
+ console_srcu_read_unlock(cookie);
+ if (con)
+ return;
already_warned = true;
pr_warn("kgdboc_earlycon is still using bootconsole\n");
@@ -528,7 +556,15 @@ static int __init kgdboc_earlycon_init(char *opt)
* Look for a matching console, or if the name was left blank just
* pick the first one we find.
*/
- console_lock();
+
+ /*
+ * Hold the console_list_lock to guarantee that no consoles are
+ * unregistered until the kgdboc_earlycon setup is complete.
+ * Trapping the exit() callback relies on exit() not being
+ * called until the trap is setup. This also allows safe
+ * traversal of the console list and race-free reading of @flags.
+ */
+ console_list_lock();
for_each_console(con) {
if (con->write && con->read &&
(con->flags & (CON_BOOT | CON_ENABLED)) &&
@@ -570,7 +606,7 @@ static int __init kgdboc_earlycon_init(char *opt)
}
unlock:
- console_unlock();
+ console_list_unlock();
/* Non-zero means malformed option so we always return zero */
return 0;
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index 2beada66c824..c38754d593ca 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -843,7 +843,7 @@ console_initcall(pic32_console_init);
*/
static int __init pic32_late_console_init(void)
{
- if (!(pic32_console.flags & CON_ENABLED))
+ if (!console_is_registered(&pic32_console))
register_console(&pic32_console);
return 0;
@@ -919,7 +919,7 @@ static int pic32_uart_probe(struct platform_device *pdev)
}
#ifdef CONFIG_SERIAL_PIC32_CONSOLE
- if (uart_console_enabled(port)) {
+ if (uart_console_registered(port)) {
/* The peripheral clock has been enabled by console_setup,
* so disable it till the port is used.
*/
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 77d1363029f5..9c252c9ca95a 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -1732,7 +1732,7 @@ static void __init s3c24xx_serial_register_console(void)
static void s3c24xx_serial_unregister_console(void)
{
- if (s3c24xx_serial_console.flags & CON_ENABLED)
+ if (console_is_registered(&s3c24xx_serial_console))
unregister_console(&s3c24xx_serial_console);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 179ee199df34..b9fbbee598b8 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2223,11 +2223,11 @@ uart_set_options(struct uart_port *port, struct console *co,
/*
* Ensure that the serial-console lock is initialised early.
*
- * Note that the console-enabled check is needed because of kgdboc,
- * which can end up calling uart_set_options() for an already enabled
+ * Note that the console-registered check is needed because
+ * kgdboc can call uart_set_options() for an already registered
* console via tty_find_polling_driver() and uart_poll_init().
*/
- if (!uart_console_enabled(port) && !port->console_reinit)
+ if (!uart_console_registered_locked(port) && !port->console_reinit)
uart_port_spin_lock_init(port);
memset(&termios, 0, sizeof(struct ktermios));
@@ -2573,7 +2573,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* successfully registered yet, try to re-register it.
* It may be that the port was not available.
*/
- if (port->cons && !(port->cons->flags & CON_ENABLED))
+ if (port->cons && !console_is_registered(port->cons))
register_console(port->cons);
/*
@@ -2956,7 +2956,7 @@ static ssize_t console_show(struct device *dev,
mutex_lock(&port->mutex);
uport = uart_port_check(state);
if (uport)
- console = uart_console_enabled(uport);
+ console = uart_console_registered(uport);
mutex_unlock(&port->mutex);
return sprintf(buf, "%c\n", console ? 'Y' : 'N');
@@ -2978,7 +2978,7 @@ static ssize_t console_store(struct device *dev,
mutex_lock(&port->mutex);
uport = uart_port_check(state);
if (uport) {
- oldconsole = uart_console_enabled(uport);
+ oldconsole = uart_console_registered(uport);
if (oldconsole && !newconsole) {
ret = unregister_console(uport->cons);
} else if (!oldconsole && newconsole) {
@@ -3086,7 +3086,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
* If this port is in use as a console then the spinlock is already
* initialised.
*/
- if (!uart_console_enabled(uport))
+ if (!uart_console_registered(uport))
uart_port_spin_lock_init(uport);
if (uport->cons && uport->dev)
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 62f773286d44..76452fe2af86 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -3054,15 +3054,29 @@ static struct console serial_console = {
};
#ifdef CONFIG_SUPERH
+static char early_serial_buf[32];
+
+static int early_serial_console_setup(struct console *co, char *options)
+{
+ /*
+ * This early console is always registered using the earlyprintk=
+ * parameter, which does not call add_preferred_console(). Thus
+ * @options is always NULL and the options for this early console
+ * are passed using a custom buffer.
+ */
+ WARN_ON(options);
+
+ return serial_console_setup(co, early_serial_buf);
+}
+
static struct console early_serial_console = {
.name = "early_ttySC",
.write = serial_console_write,
+ .setup = early_serial_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
-static char early_serial_buf[32];
-
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
@@ -3074,8 +3088,6 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
- serial_console_setup(&early_serial_console, early_serial_buf);
-
if (!strstr(early_serial_buf, "keep"))
early_serial_console.flags |= CON_BOOT;
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 2eff7cff57c4..0cbd1892c53b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1631,7 +1631,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (console_port == port &&
- !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
+ !console_is_registered(cdns_uart_uart_driver.cons)) {
console_port = NULL;
cdns_uart_console.index = -1;
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index de06c3c2ff70..cafdff575716 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3526,7 +3526,14 @@ static ssize_t show_cons_active(struct device *dev,
struct console *c;
ssize_t count = 0;
- console_lock();
+ /*
+ * Hold the console_list_lock to guarantee that no consoles are
+ * unregistered until all console processing is complete.
+ * This also allows safe traversal of the console list and
+ * race-free reading of @flags.
+ */
+ console_list_lock();
+
for_each_console(c) {
if (!c->device)
continue;
@@ -3538,6 +3545,13 @@ static ssize_t show_cons_active(struct device *dev,
if (i >= ARRAY_SIZE(cs))
break;
}
+
+ /*
+ * Take console_lock to serialize device() callback with
+ * other console operations. For example, fg_console is
+ * modified under console_lock when switching vt.
+ */
+ console_lock();
while (i--) {
int index = cs[i]->index;
struct tty_driver *drv = cs[i]->device(cs[i], &index);
@@ -3553,6 +3567,8 @@ static ssize_t show_cons_active(struct device *dev,
}
console_unlock();
+ console_list_unlock();
+
return count;
}
static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index b1f59a5fe632..d2b11d5b91ce 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -9544,6 +9544,7 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshpb_remove(hba);
ufs_sysfs_remove_nodes(hba->dev);
blk_mq_destroy_queue(hba->tmf_queue);
+ blk_put_queue(hba->tmf_queue);
blk_mq_free_tag_set(&hba->tmf_tag_set);
scsi_remove_host(hba->host);
/* disable interrupts */
@@ -9840,6 +9841,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
free_tmf_queue:
blk_mq_destroy_queue(hba->tmf_queue);
+ blk_put_queue(hba->tmf_queue);
free_tmf_tag_set:
blk_mq_free_tag_set(&hba->tmf_tag_set);
out_remove_scsi_host:
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index c67715f6f756..f9aa50ff14d4 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -600,11 +600,11 @@ int cdnsp_halt_endpoint(struct cdnsp_device *pdev,
trace_cdnsp_ep_halt(value ? "Set" : "Clear");
- if (value) {
- ret = cdnsp_cmd_stop_ep(pdev, pep);
- if (ret)
- return ret;
+ ret = cdnsp_cmd_stop_ep(pdev, pep);
+ if (ret)
+ return ret;
+ if (value) {
if (GET_EP_CTX_STATE(pep->out_ctx) == EP_STATE_STOPPED) {
cdnsp_queue_halt_endpoint(pdev, pep->idx);
cdnsp_ring_cmd_db(pdev);
@@ -613,10 +613,6 @@ int cdnsp_halt_endpoint(struct cdnsp_device *pdev,
pep->ep_state |= EP_HALTED;
} else {
- /*
- * In device mode driver can call reset endpoint command
- * from any endpoint state.
- */
cdnsp_queue_reset_ep(pdev, pep->idx);
cdnsp_ring_cmd_db(pdev);
ret = cdnsp_wait_for_cmd_compl(pdev);
diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c
index 794e413800ae..2f29431f612e 100644
--- a/drivers/usb/cdns3/cdnsp-ring.c
+++ b/drivers/usb/cdns3/cdnsp-ring.c
@@ -1763,10 +1763,15 @@ static u32 cdnsp_td_remainder(struct cdnsp_device *pdev,
int trb_buff_len,
unsigned int td_total_len,
struct cdnsp_request *preq,
- bool more_trbs_coming)
+ bool more_trbs_coming,
+ bool zlp)
{
u32 maxp, total_packet_count;
+ /* Before ZLP driver needs set TD_SIZE = 1. */
+ if (zlp)
+ return 1;
+
/* One TRB with a zero-length data packet. */
if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
trb_buff_len == td_total_len)
@@ -1960,7 +1965,8 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
/* Set the TRB length, TD size, and interrupter fields. */
remainder = cdnsp_td_remainder(pdev, enqd_len, trb_buff_len,
full_len, preq,
- more_trbs_coming);
+ more_trbs_coming,
+ zero_len_trb);
length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) |
TRB_INTR_TARGET(0);
@@ -2025,7 +2031,7 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
if (preq->request.length > 0) {
remainder = cdnsp_td_remainder(pdev, 0, preq->request.length,
- preq->request.length, preq, 1);
+ preq->request.length, preq, 1, 0);
length_field = TRB_LEN(preq->request.length) |
TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0);
@@ -2076,7 +2082,8 @@ int cdnsp_cmd_stop_ep(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
u32 ep_state = GET_EP_CTX_STATE(pep->out_ctx);
int ret = 0;
- if (ep_state == EP_STATE_STOPPED || ep_state == EP_STATE_DISABLED) {
+ if (ep_state == EP_STATE_STOPPED || ep_state == EP_STATE_DISABLED ||
+ ep_state == EP_STATE_HALTED) {
trace_cdnsp_ep_stopped_or_disabled(pep->out_ctx);
goto ep_stopped;
}
@@ -2225,7 +2232,7 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
/* Set the TRB length, TD size, & interrupter fields. */
remainder = cdnsp_td_remainder(pdev, running_total,
trb_buff_len, td_len, preq,
- more_trbs_coming);
+ more_trbs_coming, 0);
length_field = TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0);
diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
index 9643b905e2d8..6164fc4c96a4 100644
--- a/drivers/usb/cdns3/host.c
+++ b/drivers/usb/cdns3/host.c
@@ -24,11 +24,37 @@
#define CFG_RXDET_P3_EN BIT(15)
#define LPM_2_STB_SWITCH_EN BIT(25)
-static int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd);
+static void xhci_cdns3_plat_start(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ u32 value;
+
+ /* set usbcmd.EU3S */
+ value = readl(&xhci->op_regs->command);
+ value |= CMD_PM_INDEX;
+ writel(value, &xhci->op_regs->command);
+
+ if (hcd->regs) {
+ value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
+ value |= CFG_RXDET_P3_EN;
+ writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
+
+ value = readl(hcd->regs + XECP_PORT_CAP_REG);
+ value |= LPM_2_STB_SWITCH_EN;
+ writel(value, hcd->regs + XECP_PORT_CAP_REG);
+ }
+}
+
+static int xhci_cdns3_resume_quirk(struct usb_hcd *hcd)
+{
+ xhci_cdns3_plat_start(hcd);
+ return 0;
+}
static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
.quirks = XHCI_SKIP_PHY_INIT | XHCI_AVOID_BEI,
- .suspend_quirk = xhci_cdns3_suspend_quirk,
+ .plat_start = xhci_cdns3_plat_start,
+ .resume_quirk = xhci_cdns3_resume_quirk,
};
static int __cdns_host_init(struct cdns *cdns)
@@ -90,32 +116,6 @@ err1:
return ret;
}
-static int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd)
-{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- u32 value;
-
- if (pm_runtime_status_suspended(hcd->self.controller))
- return 0;
-
- /* set usbcmd.EU3S */
- value = readl(&xhci->op_regs->command);
- value |= CMD_PM_INDEX;
- writel(value, &xhci->op_regs->command);
-
- if (hcd->regs) {
- value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
- value |= CFG_RXDET_P3_EN;
- writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
-
- value = readl(hcd->regs + XECP_PORT_CAP_REG);
- value |= LPM_2_STB_SWITCH_EN;
- writel(value, hcd->regs + XECP_PORT_CAP_REG);
- }
-
- return 0;
-}
-
static void cdns_host_exit(struct cdns *cdns)
{
kfree(cdns->xhci_plat_data);
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index ada78daba6df..c17516c29b63 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -256,8 +256,10 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
ci->enabled_otg_timer_bits &= ~(1 << t);
if (ci->next_otg_timer == t) {
if (ci->enabled_otg_timer_bits == 0) {
+ spin_unlock_irqrestore(&ci->lock, flags);
/* No enabled timers after delete it */
hrtimer_cancel(&ci->otg_fsm_hrtimer);
+ spin_lock_irqsave(&ci->lock, flags);
ci->next_otg_timer = NUM_OTG_FSM_TIMERS;
} else {
/* Find the next timer */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 0722d2131305..079e183cf3bf 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -362,6 +362,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM },
{ USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
+ /* Realforce 87U Keyboard */
+ { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
+
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c0e7c76dc5c8..1f348bc867c2 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1711,6 +1711,16 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
return extcon_get_extcon_dev(name);
/*
+ * Check explicitly if "usb-role-switch" is used since
+ * extcon_find_edev_by_node() can not be used to check the absence of
+ * an extcon device. In the absence of an device it will always return
+ * EPROBE_DEFER.
+ */
+ if (IS_ENABLED(CONFIG_USB_ROLE_SWITCH) &&
+ device_property_read_bool(dev, "usb-role-switch"))
+ return NULL;
+
+ /*
* Try to get an extcon device from the USB PHY controller's "port"
* node. Check if it has the "port" node first, to avoid printing the
* error message from underlying code, as it's a valid case: extcon
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 0ecf20eeceee..4be6a873bd07 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -37,15 +37,6 @@ struct dwc3_exynos {
struct regulator *vdd10;
};
-static int dwc3_exynos_remove_child(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
@@ -142,7 +133,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
int i;
- device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
+ of_platform_depopulate(&pdev->dev);
for (i = exynos->num_clks - 1; i >= 0; i--)
clk_disable_unprepare(exynos->clks[i]);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5fe2d136dff5..6d524fa76443 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -291,7 +291,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
*
* DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
*/
- if (dwc->gadget->speed <= USB_SPEED_HIGH) {
+ if (dwc->gadget->speed <= USB_SPEED_HIGH ||
+ DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
@@ -1023,13 +1024,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
reg &= ~DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
- /* Clear out the ep descriptors for non-ep0 */
- if (dep->number > 1) {
- dep->endpoint.comp_desc = NULL;
- dep->endpoint.desc = NULL;
- }
-
- dwc3_remove_requests(dwc, dep, -ECONNRESET);
+ dwc3_remove_requests(dwc, dep, -ESHUTDOWN);
dep->stream_capable = false;
dep->type = 0;
@@ -1043,6 +1038,12 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
mask |= (DWC3_EP_DELAY_STOP | DWC3_EP_TRANSFER_STARTED);
dep->flags &= mask;
+ /* Clear out the ep descriptors for non-ep0 */
+ if (dep->number > 1) {
+ dep->endpoint.comp_desc = NULL;
+ dep->endpoint.desc = NULL;
+ }
+
return 0;
}
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index a7154fe8206d..f6f13e7f1ba1 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -11,13 +11,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
-#include "../host/xhci-plat.h"
#include "core.h"
-static const struct xhci_plat_priv dwc3_xhci_plat_priv = {
- .quirks = XHCI_SKIP_PHY_INIT,
-};
-
static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
int irq, char *name)
{
@@ -97,11 +92,6 @@ int dwc3_host_init(struct dwc3 *dwc)
goto err;
}
- ret = platform_device_add_data(xhci, &dwc3_xhci_plat_priv,
- sizeof(dwc3_xhci_plat_priv));
- if (ret)
- goto err;
-
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
if (dwc->usb3_lpm_capable)
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index bfb7e2b85299..797047154820 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -927,7 +927,7 @@ void __init early_xdbc_register_console(void)
static void xdbc_unregister_console(void)
{
- if (early_xdbc_console.flags & CON_ENABLED)
+ if (console_is_registered(&early_xdbc_console))
unregister_console(&early_xdbc_console);
}
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index c4ed48d6b8a4..a189b08bba80 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -199,16 +199,6 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
* V4L2 ioctls
*/
-struct uvc_format {
- u8 bpp;
- u32 fcc;
-};
-
-static struct uvc_format uvc_formats[] = {
- { 16, V4L2_PIX_FMT_YUYV },
- { 0, V4L2_PIX_FMT_MJPEG },
-};
-
static int
uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
@@ -243,47 +233,6 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
}
static int
-uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct video_device *vdev = video_devdata(file);
- struct uvc_device *uvc = video_get_drvdata(vdev);
- struct uvc_video *video = &uvc->video;
- struct uvc_format *format;
- unsigned int imagesize;
- unsigned int bpl;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
- format = &uvc_formats[i];
- if (format->fcc == fmt->fmt.pix.pixelformat)
- break;
- }
-
- if (i == ARRAY_SIZE(uvc_formats)) {
- uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
- fmt->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- bpl = format->bpp * fmt->fmt.pix.width / 8;
- imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
-
- video->fcc = format->fcc;
- video->bpp = format->bpp;
- video->width = fmt->fmt.pix.width;
- video->height = fmt->fmt.pix.height;
- video->imagesize = imagesize;
-
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- fmt->fmt.pix.bytesperline = bpl;
- fmt->fmt.pix.sizeimage = imagesize;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- fmt->fmt.pix.priv = 0;
-
- return 0;
-}
-
-static int
uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct video_device *vdev = video_devdata(file);
@@ -324,6 +273,27 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
}
static int
+uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvc_video *video = &uvc->video;
+ int ret;
+
+ ret = uvc_v4l2_try_format(file, fh, fmt);
+ if (ret)
+ return ret;
+
+ video->fcc = fmt->fmt.pix.pixelformat;
+ video->bpp = fmt->fmt.pix.bytesperline * 8 / video->width;
+ video->width = fmt->fmt.pix.width;
+ video->height = fmt->fmt.pix.height;
+ video->imagesize = fmt->fmt.pix.sizeimage;
+
+ return ret;
+}
+
+static int
uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *fival)
{
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 2df52f75f6b3..7558cc4d90cc 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -285,7 +285,7 @@ static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
{
struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
- if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
+ if (!usb_dev->gpio_desc)
return;
gpiod_set_value(usb_dev->gpio_desc, val);
@@ -406,9 +406,11 @@ static int bcma_hcd_probe(struct bcma_device *core)
return -ENOMEM;
usb_dev->core = core;
- if (core->dev.of_node)
- usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
- GPIOD_OUT_HIGH);
+ usb_dev->gpio_desc = devm_gpiod_get_optional(&core->dev, "vcc",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(usb_dev->gpio_desc))
+ return dev_err_probe(&core->dev, PTR_ERR(usb_dev->gpio_desc),
+ "error obtaining VCC GPIO");
switch (core->id.id) {
case BCMA_CORE_USB20_HOST:
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 95a44462bed0..1f666804fa91 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -651,7 +651,7 @@ static int of_fhci_probe(struct platform_device *ofdev)
}
for (j = 0; j < NUM_PINS; j++) {
- fhci->pins[j] = qe_pin_request(node, j);
+ fhci->pins[j] = qe_pin_request(dev, j);
if (IS_ERR(fhci->pins[j])) {
ret = PTR_ERR(fhci->pins[j]);
dev_err(dev, "can't get pin %d: %d\n", j, ret);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 697683e3fbff..c3b7f1d98e78 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -162,6 +162,8 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
+#define UBLOX_VENDOR_ID 0x1546
+
/* AMOI PRODUCTS */
#define AMOI_VENDOR_ID 0x1614
#define AMOI_PRODUCT_H01 0x0800
@@ -240,7 +242,6 @@ static void option_instat_callback(struct urb *urb);
#define QUECTEL_PRODUCT_UC15 0x9090
/* These u-blox products use Qualcomm's vendor ID */
#define UBLOX_PRODUCT_R410M 0x90b2
-#define UBLOX_PRODUCT_R6XX 0x90fa
/* These Yuga products use Qualcomm's vendor ID */
#define YUGA_PRODUCT_CLM920_NC5 0x9625
@@ -581,6 +582,9 @@ static void option_instat_callback(struct urb *urb);
#define OPPO_VENDOR_ID 0x22d9
#define OPPO_PRODUCT_R11 0x276c
+/* Sierra Wireless products */
+#define SIERRA_VENDOR_ID 0x1199
+#define SIERRA_PRODUCT_EM9191 0x90d3
/* Device flags */
@@ -1124,8 +1128,16 @@ static const struct usb_device_id option_ids[] = {
/* u-blox products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R410M),
.driver_info = RSVD(1) | RSVD(3) },
- { USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R6XX),
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x908b), /* u-blox LARA-R6 00B */
+ .driver_info = RSVD(4) },
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x90fa),
.driver_info = RSVD(3) },
+ /* u-blox products */
+ { USB_DEVICE(UBLOX_VENDOR_ID, 0x1341) }, /* u-blox LARA-L6 */
+ { USB_DEVICE(UBLOX_VENDOR_ID, 0x1342), /* u-blox LARA-L6 (RMNET) */
+ .driver_info = RSVD(4) },
+ { USB_DEVICE(UBLOX_VENDOR_ID, 0x1343), /* u-blox LARA-L6 (ECM) */
+ .driver_info = RSVD(4) },
/* Quectel products using Quectel vendor ID */
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21, 0xff, 0xff, 0xff),
.driver_info = NUMEP2 },
@@ -2167,6 +2179,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x010a, 0xff) }, /* Fibocom MA510 (ECM mode) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0111, 0xff) }, /* Fibocom FM160 (MBIM mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a2, 0xff) }, /* Fibocom FM101-GL (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a4, 0xff), /* Fibocom FM101-GL (laptop MBIM) */
@@ -2176,6 +2189,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */
{ USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) },
+ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) },
+ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index e1f4df7238bf..fdbf3694e21f 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -369,13 +369,24 @@ pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state)
return pmc_usb_command(port, (void *)&req, sizeof(req));
}
-static int pmc_usb_mux_safe_state(struct pmc_usb_port *port)
+static int pmc_usb_mux_safe_state(struct pmc_usb_port *port,
+ struct typec_mux_state *state)
{
u8 msg;
if (IOM_PORT_ACTIVITY_IS(port->iom_status, SAFE_MODE))
return 0;
+ if ((IOM_PORT_ACTIVITY_IS(port->iom_status, DP) ||
+ IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) &&
+ state->alt && state->alt->svid == USB_TYPEC_DP_SID)
+ return 0;
+
+ if ((IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) ||
+ IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) &&
+ state->alt && state->alt->svid == USB_TYPEC_TBT_SID)
+ return 0;
+
msg = PMC_USB_SAFE_MODE;
msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
@@ -443,7 +454,7 @@ pmc_usb_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
return 0;
if (state->mode == TYPEC_STATE_SAFE)
- return pmc_usb_mux_safe_state(port);
+ return pmc_usb_mux_safe_state(port, state);
if (state->mode == TYPEC_STATE_USB)
return pmc_usb_connect(port, port->role);
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index b637e8b378b3..2a77bab948f5 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -474,7 +474,7 @@ static void tps6598x_handle_plug_event(struct tps6598x *tps, u32 status)
static irqreturn_t cd321x_interrupt(int irq, void *data)
{
struct tps6598x *tps = data;
- u64 event;
+ u64 event = 0;
u32 status;
int ret;
@@ -519,8 +519,8 @@ err_unlock:
static irqreturn_t tps6598x_interrupt(int irq, void *data)
{
struct tps6598x *tps = data;
- u64 event1;
- u64 event2;
+ u64 event1 = 0;
+ u64 event2 = 0;
u32 status;
int ret;
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index 053a2bca4c47..f8b326eed54d 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -309,7 +309,7 @@ int usbip_recv(struct socket *sock, void *buf, int size)
if (!sock || !buf || !size)
return -EINVAL;
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
usbip_dbg_xmit("enter\n");
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
index 7b428eac3d3e..64d01f3fb13d 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
@@ -8,7 +8,6 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/eventfd.h>
-#include <linux/msi.h>
#include "linux/fsl/mc.h"
#include "vfio_fsl_mc_private.h"
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index badc9d828cac..e030c2120183 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -2488,12 +2488,12 @@ static bool vfio_pci_dev_set_needs_reset(struct vfio_device_set *dev_set)
struct vfio_pci_core_device *cur;
bool needs_reset = false;
- list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list) {
- /* No VFIO device in the set can have an open device FD */
- if (cur->vdev.open_count)
- return false;
+ /* No other VFIO device in the set can be open. */
+ if (vfio_device_set_open_count(dev_set) > 1)
+ return false;
+
+ list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list)
needs_reset |= cur->needs_reset;
- }
return needs_reset;
}
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 2d168793d4e1..6e8804fe0095 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -125,6 +125,19 @@ static void vfio_release_device_set(struct vfio_device *device)
xa_unlock(&vfio_device_set_xa);
}
+unsigned int vfio_device_set_open_count(struct vfio_device_set *dev_set)
+{
+ struct vfio_device *cur;
+ unsigned int open_count = 0;
+
+ lockdep_assert_held(&dev_set->lock);
+
+ list_for_each_entry(cur, &dev_set->device_list, dev_set_list)
+ open_count += cur->open_count;
+ return open_count;
+}
+EXPORT_SYMBOL_GPL(vfio_device_set_open_count);
+
/*
* Group objects - create, release, get, put, search
*/
@@ -801,8 +814,9 @@ static struct file *vfio_device_open(struct vfio_device *device)
err_close_device:
mutex_lock(&device->dev_set->lock);
mutex_lock(&device->group->group_lock);
- if (device->open_count == 1 && device->ops->close_device) {
- device->ops->close_device(device);
+ if (device->open_count == 1) {
+ if (device->ops->close_device)
+ device->ops->close_device(device);
vfio_device_container_unregister(device);
}
@@ -1017,10 +1031,12 @@ static int vfio_device_fops_release(struct inode *inode, struct file *filep)
mutex_lock(&device->dev_set->lock);
vfio_assert_device_open(device);
mutex_lock(&device->group->group_lock);
- if (device->open_count == 1 && device->ops->close_device)
- device->ops->close_device(device);
+ if (device->open_count == 1) {
+ if (device->ops->close_device)
+ device->ops->close_device(device);
- vfio_device_container_unregister(device);
+ vfio_device_container_unregister(device);
+ }
mutex_unlock(&device->group->group_lock);
device->open_count--;
if (device->open_count == 0)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 20265393aee7..9af19b0cf3b7 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -611,7 +611,7 @@ static size_t init_iov_iter(struct vhost_virtqueue *vq, struct iov_iter *iter,
/* Skip header. TODO: support TSO. */
size_t len = iov_length(vq->iov, out);
- iov_iter_init(iter, WRITE, vq->iov, out, len);
+ iov_iter_init(iter, ITER_SOURCE, vq->iov, out, len);
iov_iter_advance(iter, hdr_size);
return iov_iter_count(iter);
@@ -1184,14 +1184,14 @@ static void handle_rx(struct vhost_net *net)
msg.msg_control = vhost_net_buf_consume(&nvq->rxq);
/* On overrun, truncate and discard */
if (unlikely(headcount > UIO_MAXIOV)) {
- iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
+ iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, 1, 1);
err = sock->ops->recvmsg(sock, &msg,
1, MSG_DONTWAIT | MSG_TRUNC);
pr_debug("Discarded rx packet: len %zd\n", sock_len);
continue;
}
/* We don't need to be notified again. */
- iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
+ iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, in, vhost_len);
fixup = msg.msg_iter;
if (unlikely((vhost_hlen))) {
/* We will supply the header ourselves
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 7ebf106d50c1..dca6346d75b3 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -563,7 +563,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
memcpy(v_rsp.sense, cmd->tvc_sense_buf,
se_cmd->scsi_sense_length);
- iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
+ iov_iter_init(&iov_iter, ITER_DEST, &cmd->tvc_resp_iov,
cmd->tvc_in_iovs, sizeof(v_rsp));
ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
if (likely(ret == sizeof(v_rsp))) {
@@ -864,7 +864,7 @@ vhost_scsi_get_desc(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
* point at the start of the outgoing WRITE payload, if
* DMA_TO_DEVICE is set.
*/
- iov_iter_init(&vc->out_iter, WRITE, vq->iov, vc->out, vc->out_size);
+ iov_iter_init(&vc->out_iter, ITER_SOURCE, vq->iov, vc->out, vc->out_size);
ret = 0;
done:
@@ -1016,7 +1016,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
data_direction = DMA_FROM_DEVICE;
exp_data_len = vc.in_size - vc.rsp_size;
- iov_iter_init(&in_iter, READ, &vq->iov[vc.out], vc.in,
+ iov_iter_init(&in_iter, ITER_DEST, &vq->iov[vc.out], vc.in,
vc.rsp_size + exp_data_len);
iov_iter_advance(&in_iter, vc.rsp_size);
data_iter = in_iter;
@@ -1146,7 +1146,7 @@ vhost_scsi_send_tmf_resp(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
memset(&rsp, 0, sizeof(rsp));
rsp.response = tmf_resp_code;
- iov_iter_init(&iov_iter, READ, resp_iov, in_iovs, sizeof(rsp));
+ iov_iter_init(&iov_iter, ITER_DEST, resp_iov, in_iovs, sizeof(rsp));
ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
if (likely(ret == sizeof(rsp)))
@@ -1238,7 +1238,7 @@ vhost_scsi_send_an_resp(struct vhost_scsi *vs,
memset(&rsp, 0, sizeof(rsp)); /* event_actual = 0 */
rsp.response = VIRTIO_SCSI_S_OK;
- iov_iter_init(&iov_iter, READ, &vq->iov[vc->out], vc->in, sizeof(rsp));
+ iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[vc->out], vc->in, sizeof(rsp));
ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
if (likely(ret == sizeof(rsp)))
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 40097826cff0..5c9fe3c9c364 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -832,7 +832,7 @@ static int vhost_copy_to_user(struct vhost_virtqueue *vq, void __user *to,
VHOST_ACCESS_WO);
if (ret < 0)
goto out;
- iov_iter_init(&t, WRITE, vq->iotlb_iov, ret, size);
+ iov_iter_init(&t, ITER_DEST, vq->iotlb_iov, ret, size);
ret = copy_to_iter(from, size, &t);
if (ret == size)
ret = 0;
@@ -871,7 +871,7 @@ static int vhost_copy_from_user(struct vhost_virtqueue *vq, void *to,
(unsigned long long) size);
goto out;
}
- iov_iter_init(&f, READ, vq->iotlb_iov, ret, size);
+ iov_iter_init(&f, ITER_SOURCE, vq->iotlb_iov, ret, size);
ret = copy_from_iter(to, size, &f);
if (ret == size)
ret = 0;
@@ -2135,7 +2135,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
vq_err(vq, "Translation failure %d in indirect.\n", ret);
return ret;
}
- iov_iter_init(&from, READ, vq->indirect, ret, len);
+ iov_iter_init(&from, ITER_SOURCE, vq->indirect, ret, len);
count = len / sizeof desc;
/* Buffers are chained via a 16 bit next field, so
* we can have at most 2^16 of these. */
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index 11f59dd06a74..c9f5c8ea3afb 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -1162,7 +1162,7 @@ static inline int copy_from_iotlb(const struct vringh *vrh, void *dst,
else if (ret < 0)
return ret;
- iov_iter_bvec(&iter, READ, iov, ret, translated);
+ iov_iter_bvec(&iter, ITER_SOURCE, iov, ret, translated);
ret = copy_from_iter(dst, translated, &iter);
if (ret < 0)
@@ -1195,7 +1195,7 @@ static inline int copy_to_iotlb(const struct vringh *vrh, void *dst,
else if (ret < 0)
return ret;
- iov_iter_bvec(&iter, WRITE, iov, ret, translated);
+ iov_iter_bvec(&iter, ITER_DEST, iov, ret, translated);
ret = copy_to_iter(src, translated, &iter);
if (ret < 0)
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 5703775af129..cd6f7776013a 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -165,7 +165,7 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
break;
}
- iov_iter_init(&iov_iter, READ, &vq->iov[out], in, iov_len);
+ iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[out], in, iov_len);
payload_len = pkt->len - pkt->off;
/* If the packet is greater than the space available in the
@@ -371,7 +371,7 @@ vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq,
return NULL;
len = iov_length(vq->iov, out);
- iov_iter_init(&iov_iter, WRITE, vq->iov, out, len);
+ iov_iter_init(&iov_iter, ITER_SOURCE, vq->iov, out, len);
nbytes = copy_from_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter);
if (nbytes != sizeof(pkt->hdr)) {
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0587e21abad9..6d2fde6c5d11 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -11,6 +11,10 @@ config APERTURE_HELPERS
Support tracking and hand-over of aperture ownership. Required
by graphics drivers for firmware-provided framebuffers.
+config VIDEO_NOMODESET
+ bool
+ default n
+
if HAS_IOMEM
config HAVE_FB_ATMEL
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 5bb6b452cc83..a50eb528ed3c 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_APERTURE_HELPERS) += aperture.o
obj-$(CONFIG_VGASTATE) += vgastate.o
+obj-$(CONFIG_VIDEO_NOMODESET) += nomodeset.o
obj-$(CONFIG_HDMI) += hdmi.o
obj-$(CONFIG_VT) += console/
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
index c0d9339cff87..e9e7acb577bf 100644
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -193,13 +193,12 @@ static int apple_bl_add(struct acpi_device *dev)
return 0;
}
-static int apple_bl_remove(struct acpi_device *dev)
+static void apple_bl_remove(struct acpi_device *dev)
{
backlight_device_unregister(apple_backlight_device);
release_region(hw_data->iostart, hw_data->iolen);
hw_data = NULL;
- return 0;
}
static const struct acpi_device_id apple_bl_ids[] = {
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index cfc55273dc5d..71019b167f8b 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -227,6 +227,7 @@ config FB_CIRRUS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This enables support for Cirrus Logic GD542x/543x based boards on
Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
@@ -245,6 +246,7 @@ config FB_PM2
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for cards based on
the 3D Labs Permedia, Permedia 2 and Permedia 2V chips.
@@ -340,6 +342,7 @@ config FB_CYBER2000
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This enables support for the Integraphics CyberPro 20x0 and 5000
VGA chips used in the Rebel.com Netwinder and other machines.
@@ -455,6 +458,7 @@ config FB_ATARI
config FB_OF
bool "Open Firmware frame buffer device support"
depends on (FB = y) && PPC && (!PPC_PSERIES || PCI)
+ depends on !DRM_OFDRM
select APERTURE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -503,6 +507,7 @@ config FB_CT65550
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for the Chips & Technologies
65550 graphics chip in PowerBooks.
@@ -513,6 +518,7 @@ config FB_ASILIANT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for the Asiliant 69030 chipset
@@ -521,6 +527,7 @@ config FB_IMSTT
depends on (FB = y) && PCI
select FB_CFB_IMAGEBLIT
select FB_MACMODES if PPC_PMAC
+ select VIDEO_NOMODESET
help
The IMS Twin Turbo is a PCI-based frame buffer card bundled with
many Macintosh and compatible computers.
@@ -584,6 +591,7 @@ config FB_TGA
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select BITREVERSE
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for generic TGA and SFB+
graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards,
@@ -776,6 +784,7 @@ config FB_XVR500
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the framebuffer device for the Sun XVR-500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
@@ -789,6 +798,7 @@ config FB_XVR2500
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the framebuffer device for the Sun XVR-2500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
@@ -815,6 +825,7 @@ config FB_PVR2
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Say Y here if you have a PowerVR 2 card in your box. If you plan to
run linux on your Dreamcast, you will have to say Y here.
@@ -880,6 +891,7 @@ config FB_NVIDIA
select FB_CFB_IMAGEBLIT
select BITREVERSE
select VGASTATE
+ select VIDEO_NOMODESET
help
This driver supports graphics boards with the nVidia chips, TNT
and newer. For very old chipsets, such as the RIVA128, then use
@@ -927,6 +939,7 @@ config FB_RIVA
select FB_CFB_IMAGEBLIT
select BITREVERSE
select VGASTATE
+ select VIDEO_NOMODESET
help
This driver supports graphics boards with the nVidia Riva/Geforce
chips.
@@ -971,6 +984,7 @@ config FB_I740
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select VGASTATE
+ select VIDEO_NOMODESET
select FB_DDC
help
This driver supports graphics cards based on Intel740 chip.
@@ -983,6 +997,7 @@ config FB_I810
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select VGASTATE
+ select VIDEO_NOMODESET
help
This driver supports the on-board graphics built in to the Intel 810
and 815 chipsets. Say Y if you have and plan to use such a board.
@@ -1033,6 +1048,7 @@ config FB_LE80578
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This driver supports the LE80578 (Vermilion Range) chipset
@@ -1050,6 +1066,7 @@ config FB_INTEL
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select BOOT_VESA_SUPPORT if FB_INTEL = y
+ select VIDEO_NOMODESET
depends on !DRM_I915
help
This driver supports the on-board graphics built in to the Intel
@@ -1087,6 +1104,7 @@ config FB_MATROX
select FB_CFB_IMAGEBLIT
select FB_TILEBLITTING
select FB_MACMODES if PPC_PMAC
+ select VIDEO_NOMODESET
help
Say Y here if you have a Matrox Millennium, Matrox Millennium II,
Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
@@ -1207,6 +1225,7 @@ config FB_RADEON
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_MACMODES if PPC
+ select VIDEO_NOMODESET
help
Choose this option if you want to use an ATI Radeon graphics card as
a framebuffer device. There are both PCI and AGP versions. You
@@ -1246,6 +1265,7 @@ config FB_ATY128
select FB_CFB_IMAGEBLIT
select FB_BACKLIGHT if FB_ATY128_BACKLIGHT
select FB_MACMODES if PPC_PMAC
+ select VIDEO_NOMODESET
help
This driver supports graphics boards with the ATI Rage128 chips.
Say Y if you have such a graphics board and read
@@ -1270,6 +1290,7 @@ config FB_ATY
select FB_BACKLIGHT if FB_ATY_BACKLIGHT
select FB_MACMODES if PPC
select FB_ATY_CT if SPARC64 && PCI
+ select VIDEO_NOMODESET
help
This driver supports graphics boards with the ATI Mach64 chips.
Say Y if you have such a graphics board.
@@ -1320,6 +1341,7 @@ config FB_S3
select FB_TILEBLITTING
select FB_SVGALIB
select VGASTATE
+ select VIDEO_NOMODESET
select FONT_8x16 if FRAMEBUFFER_CONSOLE
help
Driver for graphics boards with S3 Trio / S3 Virge chip.
@@ -1340,6 +1362,7 @@ config FB_SAVAGE
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select VGASTATE
+ select VIDEO_NOMODESET
help
This driver supports notebooks and computers with S3 Savage PCI/AGP
chips.
@@ -1378,6 +1401,7 @@ config FB_SIS
select FB_CFB_IMAGEBLIT
select BOOT_VESA_SUPPORT if FB_SIS = y
select FB_SIS_300 if !FB_SIS_315
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for the SiS 300, 315, 330
and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets.
@@ -1407,6 +1431,7 @@ config FB_VIA
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@@ -1446,6 +1471,7 @@ config FB_NEOMAGIC
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select VGASTATE
+ select VIDEO_NOMODESET
help
This driver supports notebooks with NeoMagic PCI chips.
Say Y if you have such a graphics card.
@@ -1459,6 +1485,7 @@ config FB_KYRO
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Say Y here if you have a STG4000 / Kyro / PowerVR 3 based
graphics board.
@@ -1473,6 +1500,7 @@ config FB_3DFX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_MODE_HELPERS
+ select VIDEO_NOMODESET
help
This driver supports graphics boards with the 3Dfx Banshee,
Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have
@@ -1502,6 +1530,7 @@ config FB_VOODOO1
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or
Voodoo2 (cvg) based graphics card.
@@ -1523,6 +1552,7 @@ config FB_VT8623
select FB_TILEBLITTING
select FB_SVGALIB
select VGASTATE
+ select VIDEO_NOMODESET
select FONT_8x16 if FRAMEBUFFER_CONSOLE
help
Driver for CastleRock integrated graphics core in the
@@ -1536,6 +1566,7 @@ config FB_TRIDENT
select FB_CFB_IMAGEBLIT
select FB_DDC
select FB_MODE_HELPERS
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for Trident PCI/AGP chipsets.
Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D
@@ -1559,6 +1590,7 @@ config FB_ARK
select FB_TILEBLITTING
select FB_SVGALIB
select VGASTATE
+ select VIDEO_NOMODESET
select FONT_8x16 if FRAMEBUFFER_CONSOLE
help
Driver for PCI graphics boards with ARK 2000PV chip
@@ -1570,6 +1602,7 @@ config FB_PM3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for the 3DLabs Permedia3
chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
@@ -1582,6 +1615,7 @@ config FB_CARMINE
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
This is the frame buffer device driver for the Fujitsu Carmine chip.
The driver provides two independent frame buffer devices.
@@ -1960,6 +1994,7 @@ config FB_IBM_GXT4500
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Say Y here to enable support for the IBM GXT4000P/6000P and
GXT4500P/6500P display adaptor based on Raster Engine RC1000,
@@ -2100,6 +2135,7 @@ config FB_MB862XX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers.
@@ -2187,6 +2223,7 @@ config FB_HYPERV
select FB_CFB_IMAGEBLIT
select FB_DEFERRED_IO
select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
+ select VIDEO_NOMODESET
help
This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
@@ -2229,6 +2266,7 @@ config FB_SM712
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Frame buffer driver for the Silicon Motion SM710, SM712, SM721
and SM722 chips.
diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c
index 5f8fec9e5fd4..60a96fdb5dd8 100644
--- a/drivers/video/fbdev/arkfb.c
+++ b/drivers/video/fbdev/arkfb.c
@@ -1187,7 +1187,12 @@ static int __init arkfb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("arkfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("arkfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c
index 3818437a8f69..8383468f5577 100644
--- a/drivers/video/fbdev/asiliantfb.c
+++ b/drivers/video/fbdev/asiliantfb.c
@@ -616,6 +616,9 @@ static struct pci_driver asiliantfb_driver = {
static int __init asiliantfb_init(void)
{
+ if (fb_modesetting_disabled("asiliantfb"))
+ return -ENODEV;
+
if (fb_get_options("asiliantfb", NULL))
return -ENODEV;
diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c
index 57e398fe7a81..dd31b9d7d337 100644
--- a/drivers/video/fbdev/aty/aty128fb.c
+++ b/drivers/video/fbdev/aty/aty128fb.c
@@ -2503,7 +2503,12 @@ static int aty128fb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("aty128fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("aty128fb", &option))
return -ENODEV;
aty128fb_setup(option);
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index b3463d137152..0ccf5d401ecb 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -3965,7 +3965,12 @@ static int __init atyfb_init(void)
int err1 = 1, err2 = 1;
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("atyfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("atyfb", &option))
return -ENODEV;
atyfb_setup(option);
diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c
index 8b28c9bddd97..657064227de8 100644
--- a/drivers/video/fbdev/aty/radeon_base.c
+++ b/drivers/video/fbdev/aty/radeon_base.c
@@ -2607,7 +2607,12 @@ static int __init radeonfb_init (void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("radeonfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("radeonfb", &option))
return -ENODEV;
radeonfb_setup(option);
diff --git a/drivers/video/fbdev/carminefb.c b/drivers/video/fbdev/carminefb.c
index 4651b48a87f9..4ae21dbdb8ca 100644
--- a/drivers/video/fbdev/carminefb.c
+++ b/drivers/video/fbdev/carminefb.c
@@ -773,6 +773,9 @@ static struct pci_driver carmine_pci_driver = {
static int __init carminefb_init(void)
{
+ if (fb_modesetting_disabled("carminefb"))
+ return -ENODEV;
+
if (!(fb_displays &
(CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
printk(KERN_ERR "If you disable both displays than you don't "
diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
index f1c1c95c1fdf..cc37ec3f8fc1 100644
--- a/drivers/video/fbdev/chipsfb.c
+++ b/drivers/video/fbdev/chipsfb.c
@@ -506,6 +506,9 @@ static struct pci_driver chipsfb_driver = {
int __init chips_init(void)
{
+ if (fb_modesetting_disabled("chipsfb"))
+ return -ENODEV;
+
if (fb_get_options("chipsfb", NULL))
return -ENODEV;
diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c
index b08bee43779a..ba45e2147c52 100644
--- a/drivers/video/fbdev/cirrusfb.c
+++ b/drivers/video/fbdev/cirrusfb.c
@@ -2359,7 +2359,12 @@ static int __init cirrusfb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("cirrusfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("cirrusfb", &option))
return -ENODEV;
cirrusfb_setup(option);
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 098b62f7b701..c0143d38df83 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -577,7 +577,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
if (scr_readw(r) != vc->vc_video_erase_char)
break;
if (r != q && new_rows >= rows + logo_lines) {
- save = kmalloc(array3_size(logo_lines, new_cols, 2),
+ save = kzalloc(array3_size(logo_lines, new_cols, 2),
GFP_KERNEL);
if (save) {
int i = min(cols, new_cols);
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 1e70d8c67653..3a6c8458eb8d 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -40,6 +40,7 @@
#include <asm/fb.h>
+#include <video/nomodeset.h>
#include <video/vga.h>
/*
@@ -1844,4 +1845,18 @@ int fb_new_modelist(struct fb_info *info)
return 0;
}
+#if defined(CONFIG_VIDEO_NOMODESET)
+bool fb_modesetting_disabled(const char *drvname)
+{
+ bool fwonly = video_firmware_drivers_only();
+
+ if (fwonly)
+ pr_warn("Driver %s not loading because of nomodeset parameter\n",
+ drvname);
+
+ return fwonly;
+}
+EXPORT_SYMBOL(fb_modesetting_disabled);
+#endif
+
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c
index 31ff1da82c05..38c0a6866d76 100644
--- a/drivers/video/fbdev/cyber2000fb.c
+++ b/drivers/video/fbdev/cyber2000fb.c
@@ -48,7 +48,6 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-
#ifdef __arm__
#include <asm/mach-types.h>
#endif
@@ -1878,7 +1877,12 @@ static int __init cyber2000fb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+ if (fb_modesetting_disabled("CyberPro"))
+ return -ENODEV;
+
+#ifndef MODULE
if (fb_get_options("cyber2000fb", &option))
return -ENODEV;
cyber2000fb_setup(option);
diff --git a/drivers/video/fbdev/geode/Kconfig b/drivers/video/fbdev/geode/Kconfig
index ac9c860592aa..2f8f0fb1dae2 100644
--- a/drivers/video/fbdev/geode/Kconfig
+++ b/drivers/video/fbdev/geode/Kconfig
@@ -15,6 +15,7 @@ config FB_GEODE_LX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Framebuffer driver for the display controller integrated into the
AMD Geode LX processors.
@@ -30,6 +31,7 @@ config FB_GEODE_GX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Framebuffer driver for the display controller integrated into the
AMD Geode GX processors.
@@ -45,6 +47,7 @@ config FB_GEODE_GX1
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_NOMODESET
help
Framebuffer driver for the display controller integrated into the
AMD Geode GX1 processor.
diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c
index 1514c653a84f..9c942001ac10 100644
--- a/drivers/video/fbdev/geode/gx1fb_core.c
+++ b/drivers/video/fbdev/geode/gx1fb_core.c
@@ -446,7 +446,12 @@ static int __init gx1fb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("gx1fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("gx1fb", &option))
return -ENODEV;
gx1fb_setup(option);
diff --git a/drivers/video/fbdev/geode/gxfb_core.c b/drivers/video/fbdev/geode/gxfb_core.c
index 2527bd80ec5f..8e05e76de075 100644
--- a/drivers/video/fbdev/geode/gxfb_core.c
+++ b/drivers/video/fbdev/geode/gxfb_core.c
@@ -511,7 +511,12 @@ static int __init gxfb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("gxfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("gxfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c
index 9d26592dbfce..8130e9eee2b4 100644
--- a/drivers/video/fbdev/geode/lxfb_core.c
+++ b/drivers/video/fbdev/geode/lxfb_core.c
@@ -647,7 +647,12 @@ static int __init lxfb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("lxfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("lxfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c
index 0dcef4bec8d7..5f42d3d9d6ce 100644
--- a/drivers/video/fbdev/gxt4500.c
+++ b/drivers/video/fbdev/gxt4500.c
@@ -779,6 +779,9 @@ static struct pci_driver gxt4500_driver = {
static int gxt4500_init(void)
{
+ if (fb_modesetting_disabled("gxt4500"))
+ return -ENODEV;
+
#ifndef MODULE
if (fb_get_options("gxt4500", &mode_option))
return -ENODEV;
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 072ce07ba9e0..fdbf02b42723 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -59,7 +59,6 @@
#include <linux/hyperv.h>
-
/* Hyper-V Synthetic Video Protocol definitions and structures */
#define MAX_VMBUS_PKT_SIZE 0x4000
@@ -780,12 +779,18 @@ static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
static int hvfb_on_panic(struct notifier_block *nb,
unsigned long e, void *p)
{
+ struct hv_device *hdev;
struct hvfb_par *par;
struct fb_info *info;
par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
- par->synchronous_fb = true;
info = par->info;
+ hdev = device_to_hv_device(info->device);
+
+ if (hv_ringbuffer_spinlock_busy(hdev->channel))
+ return NOTIFY_DONE;
+
+ par->synchronous_fb = true;
if (par->need_docopy)
hvfb_docopy(par, 0, dio_fb_size);
synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
@@ -1208,7 +1213,15 @@ static int hvfb_probe(struct hv_device *hdev,
par->fb_ready = true;
par->synchronous_fb = false;
+
+ /*
+ * We need to be sure this panic notifier runs _before_ the
+ * vmbus disconnect, so order it by priority. It must execute
+ * before the function hv_panic_vmbus_unload() [drivers/hv/vmbus_drv.c],
+ * which is almost at the end of list, with priority = INT_MIN + 1.
+ */
par->hvfb_panic_nb.notifier_call = hvfb_on_panic;
+ par->hvfb_panic_nb.priority = INT_MIN + 10,
atomic_notifier_chain_register(&panic_notifier_list,
&par->hvfb_panic_nb);
@@ -1363,6 +1376,9 @@ static int __init hvfb_drv_init(void)
{
int ret;
+ if (fb_modesetting_disabled("hyper_fb"))
+ return -ENODEV;
+
ret = vmbus_driver_register(&hvfb_drv);
if (ret != 0)
return ret;
diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c
index b795f6503cb6..3860b137b86a 100644
--- a/drivers/video/fbdev/i740fb.c
+++ b/drivers/video/fbdev/i740fb.c
@@ -1285,7 +1285,12 @@ static int __init i740fb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("i740fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("i740fb", &option))
return -ENODEV;
i740fb_setup(option);
diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c
index ff09f8c20bfc..85abb65f07d7 100644
--- a/drivers/video/fbdev/i810/i810_main.c
+++ b/drivers/video/fbdev/i810/i810_main.c
@@ -2143,6 +2143,9 @@ static int i810fb_init(void)
{
char *option = NULL;
+ if (fb_modesetting_disabled("i810fb"))
+ return -ENODEV;
+
if (fb_get_options("i810fb", &option))
return -ENODEV;
i810fb_setup(option);
@@ -2159,6 +2162,9 @@ static int i810fb_init(void)
static int i810fb_init(void)
{
+ if (fb_modesetting_disabled("i810fb"))
+ return -ENODEV;
+
hsync1 *= 1000;
hsync2 *= 1000;
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index d7edb9c5d3a3..bea45647184e 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1617,7 +1617,12 @@ static int __init imsttfb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("imsttfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("imsttfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c
index d4a2891a9a7a..0a9e5067b201 100644
--- a/drivers/video/fbdev/intelfb/intelfbdrv.c
+++ b/drivers/video/fbdev/intelfb/intelfbdrv.c
@@ -389,6 +389,9 @@ static int __init intelfb_init(void)
if (idonly)
return -ENODEV;
+ if (fb_modesetting_disabled("intelfb"))
+ return -ENODEV;
+
#ifndef MODULE
if (fb_get_options("intelfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c
index b4b93054c520..0596573ef140 100644
--- a/drivers/video/fbdev/kyro/fbdev.c
+++ b/drivers/video/fbdev/kyro/fbdev.c
@@ -789,7 +789,12 @@ static int __init kyrofb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("kyrofb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("kyrofb", &option))
return -ENODEV;
kyrofb_setup(option);
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c
index 775d34115e2d..0d3cee7ae726 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.c
+++ b/drivers/video/fbdev/matrox/matroxfb_base.c
@@ -2314,6 +2314,9 @@ static void __init matroxfb_init_params(void) {
static int __init matrox_init(void) {
int err;
+ if (fb_modesetting_disabled("matroxfb"))
+ return -ENODEV;
+
matroxfb_init_params();
err = pci_register_driver(&matroxfb_driver);
dev = -1; /* accept all new devices... */
diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
index 90c79e8c1157..a236fc910148 100644
--- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
+++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
@@ -1181,6 +1181,9 @@ static int mb862xxfb_init(void)
{
int ret = -ENODEV;
+ if (fb_modesetting_disabled(DRV_NAME))
+ return -ENODEV;
+
#if defined(CONFIG_FB_MB862XX_LIME)
ret = platform_driver_register(&of_platform_mb862xxfb_driver);
#endif
diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c
index 93a2d2d1abe8..39d8cdef5c97 100644
--- a/drivers/video/fbdev/neofb.c
+++ b/drivers/video/fbdev/neofb.c
@@ -2209,7 +2209,12 @@ static int __init neofb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("neofb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("neofb", &option))
return -ENODEV;
neofb_setup(option);
diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c
index 329e2e8133c6..1960916098d4 100644
--- a/drivers/video/fbdev/nvidia/nvidia.c
+++ b/drivers/video/fbdev/nvidia/nvidia.c
@@ -1521,7 +1521,12 @@ static int nvidiafb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("nvidiafb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("nvidiafb", &option))
return -ENODEV;
nvidiafb_setup(option);
diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c
index 7da715d31a93..0823c9de859a 100644
--- a/drivers/video/fbdev/pm2fb.c
+++ b/drivers/video/fbdev/pm2fb.c
@@ -1799,7 +1799,12 @@ static int __init pm2fb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("pm2fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("pm2fb", &option))
return -ENODEV;
pm2fb_setup(option);
diff --git a/drivers/video/fbdev/pm3fb.c b/drivers/video/fbdev/pm3fb.c
index ba69846d444f..b46a471df9ae 100644
--- a/drivers/video/fbdev/pm3fb.c
+++ b/drivers/video/fbdev/pm3fb.c
@@ -1540,7 +1540,12 @@ static int __init pm3fb_init(void)
*/
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("pm3fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("pm3fb", &option))
return -ENODEV;
pm3fb_setup(option);
diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
index b73ad14efa20..6888127a5eb8 100644
--- a/drivers/video/fbdev/pvr2fb.c
+++ b/drivers/video/fbdev/pvr2fb.c
@@ -1082,7 +1082,12 @@ static int __init pvr2fb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("pvr2fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("pvr2fb", &option))
return -ENODEV;
pvr2fb_setup(option);
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
index 0ea74e28f915..644278146d3b 100644
--- a/drivers/video/fbdev/riva/fbdev.c
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -2165,7 +2165,12 @@ static int rivafb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("rivafb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("rivafb", &option))
return -ENODEV;
rivafb_setup(option);
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c
index 7713274bd04c..7d257489edcc 100644
--- a/drivers/video/fbdev/s3fb.c
+++ b/drivers/video/fbdev/s3fb.c
@@ -1558,7 +1558,12 @@ static int __init s3fb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("s3fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("s3fb", &option))
return -ENODEV;
s3fb_setup(option);
diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c
index b7818b652698..4a27b68798bf 100644
--- a/drivers/video/fbdev/savage/savagefb_driver.c
+++ b/drivers/video/fbdev/savage/savagefb_driver.c
@@ -2556,6 +2556,9 @@ static int __init savagefb_init(void)
DBG("savagefb_init");
+ if (fb_modesetting_disabled("savagefb"))
+ return -ENODEV;
+
if (fb_get_options("savagefb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c
index 1c197c3f9538..cfba776afcea 100644
--- a/drivers/video/fbdev/sis/sis_main.c
+++ b/drivers/video/fbdev/sis/sis_main.c
@@ -6588,7 +6588,12 @@ static int __init sisfb_init(void)
{
#ifndef MODULE
char *options = NULL;
+#endif
+
+ if (fb_modesetting_disabled("sisfb"))
+ return -ENODEV;
+#ifndef MODULE
if(fb_get_options("sisfb", &options))
return -ENODEV;
diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c
index a10f1057293b..40c130ab6b38 100644
--- a/drivers/video/fbdev/skeletonfb.c
+++ b/drivers/video/fbdev/skeletonfb.c
@@ -987,7 +987,12 @@ static int __init xxxfb_init(void)
*/
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("xxxfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("xxxfb", &option))
return -ENODEV;
xxxfb_setup(option);
diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c
index 3baf33635e65..b528776c7612 100644
--- a/drivers/video/fbdev/sm712fb.c
+++ b/drivers/video/fbdev/sm712fb.c
@@ -1756,6 +1756,9 @@ static int __init sm712fb_init(void)
{
char *option = NULL;
+ if (fb_modesetting_disabled("sm712fb"))
+ return -ENODEV;
+
if (fb_get_options("sm712fb", &option))
return -ENODEV;
if (option && *option)
diff --git a/drivers/video/fbdev/sstfb.c b/drivers/video/fbdev/sstfb.c
index a56b24288566..da296b2ab54a 100644
--- a/drivers/video/fbdev/sstfb.c
+++ b/drivers/video/fbdev/sstfb.c
@@ -1503,6 +1503,9 @@ static int sstfb_init(void)
{
char *option = NULL;
+ if (fb_modesetting_disabled("sstfb"))
+ return -ENODEV;
+
if (fb_get_options("sstfb", &option))
return -ENODEV;
sstfb_setup(option);
diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c
index f4059529c602..2cab4b9be68a 100644
--- a/drivers/video/fbdev/sunxvr2500.c
+++ b/drivers/video/fbdev/sunxvr2500.c
@@ -247,6 +247,9 @@ static struct pci_driver s3d_driver = {
static int __init s3d_init(void)
{
+ if (fb_modesetting_disabled("s3d"))
+ return -ENODEV;
+
if (fb_get_options("s3d", NULL))
return -ENODEV;
diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c
index b0c8cf0c535a..6ec358af1256 100644
--- a/drivers/video/fbdev/sunxvr500.c
+++ b/drivers/video/fbdev/sunxvr500.c
@@ -430,6 +430,9 @@ static struct pci_driver e3d_driver = {
static int __init e3d_init(void)
{
+ if (fb_modesetting_disabled("e3d"))
+ return -ENODEV;
+
if (fb_get_options("e3d", NULL))
return -ENODEV;
diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c
index 592a913d0718..d17e5e1472aa 100644
--- a/drivers/video/fbdev/tdfxfb.c
+++ b/drivers/video/fbdev/tdfxfb.c
@@ -1632,7 +1632,12 @@ static int __init tdfxfb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("tdfxfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("tdfxfb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c
index 251dbd282f5e..14d37c49633c 100644
--- a/drivers/video/fbdev/tgafb.c
+++ b/drivers/video/fbdev/tgafb.c
@@ -1597,7 +1597,12 @@ static int tgafb_init(void)
int status;
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("tgafb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("tgafb", &option))
return -ENODEV;
tgafb_setup(option);
diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c
index 219ce7292337..6099b9768ba1 100644
--- a/drivers/video/fbdev/tridentfb.c
+++ b/drivers/video/fbdev/tridentfb.c
@@ -1811,7 +1811,12 @@ static int __init tridentfb_init(void)
{
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("tridentfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("tridentfb", &option))
return -ENODEV;
tridentfb_setup(option);
diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c
index 82b36dbb5b1a..1465fb7b619e 100644
--- a/drivers/video/fbdev/vermilion/vermilion.c
+++ b/drivers/video/fbdev/vermilion/vermilion.c
@@ -1057,7 +1057,12 @@ static int __init vmlfb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("vmlfb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options(MODULE_NAME, &option))
return -ENODEV;
#endif
diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c
index 2ee8fcae08df..32a6399b080b 100644
--- a/drivers/video/fbdev/via/via-core.c
+++ b/drivers/video/fbdev/via/via-core.c
@@ -725,6 +725,9 @@ static int __init via_core_init(void)
{
int ret;
+ if (fb_modesetting_disabled("viafb"))
+ return -ENODEV;
+
ret = viafb_init();
if (ret)
return ret;
diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
index 49b9f148d3a1..034333ee6e45 100644
--- a/drivers/video/fbdev/vt8623fb.c
+++ b/drivers/video/fbdev/vt8623fb.c
@@ -920,7 +920,12 @@ static int __init vt8623fb_init(void)
#ifndef MODULE
char *option = NULL;
+#endif
+
+ if (fb_modesetting_disabled("vt8623fb"))
+ return -ENODEV;
+#ifndef MODULE
if (fb_get_options("vt8623fb", &option))
return -ENODEV;
diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c
index 4d2694d904aa..8752d389e382 100644
--- a/drivers/video/fbdev/xen-fbfront.c
+++ b/drivers/video/fbdev/xen-fbfront.c
@@ -504,18 +504,14 @@ static void xenfb_make_preferred_console(void)
if (console_set_on_cmdline)
return;
- console_lock();
+ console_list_lock();
for_each_console(c) {
if (!strcmp(c->name, "tty") && c->index == 0)
break;
}
- console_unlock();
- if (c) {
- unregister_console(c);
- c->flags |= CON_CONSDEV;
- c->flags &= ~CON_PRINTBUFFER; /* don't print again */
- register_console(c);
- }
+ if (c)
+ console_force_preferred_locked(c);
+ console_list_unlock();
}
static int xenfb_resume(struct xenbus_device *dev)
diff --git a/drivers/gpu/drm/drm_nomodeset.c b/drivers/video/nomodeset.c
index f3978d5bd3a1..13cc8b719697 100644
--- a/drivers/gpu/drm/drm_nomodeset.c
+++ b/drivers/video/nomodeset.c
@@ -3,17 +3,19 @@
#include <linux/module.h>
#include <linux/types.h>
-static bool drm_nomodeset;
+#include <video/nomodeset.h>
-bool drm_firmware_drivers_only(void)
+static bool video_nomodeset;
+
+bool video_firmware_drivers_only(void)
{
- return drm_nomodeset;
+ return video_nomodeset;
}
-EXPORT_SYMBOL(drm_firmware_drivers_only);
+EXPORT_SYMBOL(video_firmware_drivers_only);
static int __init disable_modeset(char *str)
{
- drm_nomodeset = true;
+ video_nomodeset = true;
pr_warn("Booted with the nomodeset parameter. Only the system framebuffer will be available\n");
diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
index 87ef258cec64..f79ab13a5c28 100644
--- a/drivers/virt/Kconfig
+++ b/drivers/virt/Kconfig
@@ -52,4 +52,6 @@ source "drivers/virt/coco/efi_secret/Kconfig"
source "drivers/virt/coco/sev-guest/Kconfig"
+source "drivers/virt/coco/tdx-guest/Kconfig"
+
endif
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
index 093674e05c40..e9aa6fc96fab 100644
--- a/drivers/virt/Makefile
+++ b/drivers/virt/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/
obj-$(CONFIG_ACRN_HSM) += acrn/
obj-$(CONFIG_EFI_SECRET) += coco/efi_secret/
obj-$(CONFIG_SEV_GUEST) += coco/sev-guest/
+obj-$(CONFIG_INTEL_TDX_GUEST) += coco/tdx-guest/
diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c
index f422f9c58ba7..1ea6d2e5b218 100644
--- a/drivers/virt/coco/sev-guest/sev-guest.c
+++ b/drivers/virt/coco/sev-guest/sev-guest.c
@@ -67,8 +67,27 @@ static bool is_vmpck_empty(struct snp_guest_dev *snp_dev)
return true;
}
+/*
+ * If an error is received from the host or AMD Secure Processor (ASP) there
+ * are two options. Either retry the exact same encrypted request or discontinue
+ * using the VMPCK.
+ *
+ * This is because in the current encryption scheme GHCB v2 uses AES-GCM to
+ * encrypt the requests. The IV for this scheme is the sequence number. GCM
+ * cannot tolerate IV reuse.
+ *
+ * The ASP FW v1.51 only increments the sequence numbers on a successful
+ * guest<->ASP back and forth and only accepts messages at its exact sequence
+ * number.
+ *
+ * So if the sequence number were to be reused the encryption scheme is
+ * vulnerable. If the sequence number were incremented for a fresh IV the ASP
+ * will reject the request.
+ */
static void snp_disable_vmpck(struct snp_guest_dev *snp_dev)
{
+ dev_alert(snp_dev->dev, "Disabling vmpck_id %d to prevent IV reuse.\n",
+ vmpck_id);
memzero_explicit(snp_dev->vmpck, VMPCK_KEY_LEN);
snp_dev->vmpck = NULL;
}
@@ -321,34 +340,71 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
if (rc)
return rc;
- /* Call firmware to process the request */
+ /*
+ * Call firmware to process the request. In this function the encrypted
+ * message enters shared memory with the host. So after this call the
+ * sequence number must be incremented or the VMPCK must be deleted to
+ * prevent reuse of the IV.
+ */
rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
+
+ /*
+ * If the extended guest request fails due to having too small of a
+ * certificate data buffer, retry the same guest request without the
+ * extended data request in order to increment the sequence number
+ * and thus avoid IV reuse.
+ */
+ if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST &&
+ err == SNP_GUEST_REQ_INVALID_LEN) {
+ const unsigned int certs_npages = snp_dev->input.data_npages;
+
+ exit_code = SVM_VMGEXIT_GUEST_REQUEST;
+
+ /*
+ * If this call to the firmware succeeds, the sequence number can
+ * be incremented allowing for continued use of the VMPCK. If
+ * there is an error reflected in the return value, this value
+ * is checked further down and the result will be the deletion
+ * of the VMPCK and the error code being propagated back to the
+ * user as an ioctl() return code.
+ */
+ rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
+
+ /*
+ * Override the error to inform callers the given extended
+ * request buffer size was too small and give the caller the
+ * required buffer size.
+ */
+ err = SNP_GUEST_REQ_INVALID_LEN;
+ snp_dev->input.data_npages = certs_npages;
+ }
+
if (fw_err)
*fw_err = err;
- if (rc)
- return rc;
+ if (rc) {
+ dev_alert(snp_dev->dev,
+ "Detected error from ASP request. rc: %d, fw_err: %llu\n",
+ rc, *fw_err);
+ goto disable_vmpck;
+ }
- /*
- * The verify_and_dec_payload() will fail only if the hypervisor is
- * actively modifying the message header or corrupting the encrypted payload.
- * This hints that hypervisor is acting in a bad faith. Disable the VMPCK so that
- * the key cannot be used for any communication. The key is disabled to ensure
- * that AES-GCM does not use the same IV while encrypting the request payload.
- */
rc = verify_and_dec_payload(snp_dev, resp_buf, resp_sz);
if (rc) {
dev_alert(snp_dev->dev,
- "Detected unexpected decode failure, disabling the vmpck_id %d\n",
- vmpck_id);
- snp_disable_vmpck(snp_dev);
- return rc;
+ "Detected unexpected decode failure from ASP. rc: %d\n",
+ rc);
+ goto disable_vmpck;
}
/* Increment to new message sequence after payload decryption was successful. */
snp_inc_msg_seqno(snp_dev);
return 0;
+
+disable_vmpck:
+ snp_disable_vmpck(snp_dev);
+ return rc;
}
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-guest/Kconfig
new file mode 100644
index 000000000000..14246fc2fb02
--- /dev/null
+++ b/drivers/virt/coco/tdx-guest/Kconfig
@@ -0,0 +1,10 @@
+config TDX_GUEST_DRIVER
+ tristate "TDX Guest driver"
+ depends on INTEL_TDX_GUEST
+ help
+ The driver provides userspace interface to communicate with
+ the TDX module to request the TDX guest details like attestation
+ report.
+
+ To compile this driver as module, choose M here. The module will
+ be called tdx-guest.
diff --git a/drivers/virt/coco/tdx-guest/Makefile b/drivers/virt/coco/tdx-guest/Makefile
new file mode 100644
index 000000000000..775cb463f9c8
--- /dev/null
+++ b/drivers/virt/coco/tdx-guest/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_TDX_GUEST_DRIVER) += tdx-guest.o
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
new file mode 100644
index 000000000000..5e44a0fa69bd
--- /dev/null
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TDX guest user interface driver
+ *
+ * Copyright (C) 2022 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+
+#include <uapi/linux/tdx-guest.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/tdx.h>
+
+static long tdx_get_report0(struct tdx_report_req __user *req)
+{
+ u8 *reportdata, *tdreport;
+ long ret;
+
+ reportdata = kmalloc(TDX_REPORTDATA_LEN, GFP_KERNEL);
+ if (!reportdata)
+ return -ENOMEM;
+
+ tdreport = kzalloc(TDX_REPORT_LEN, GFP_KERNEL);
+ if (!tdreport) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(reportdata, req->reportdata, TDX_REPORTDATA_LEN)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /* Generate TDREPORT0 using "TDG.MR.REPORT" TDCALL */
+ ret = tdx_mcall_get_report0(reportdata, tdreport);
+ if (ret)
+ goto out;
+
+ if (copy_to_user(req->tdreport, tdreport, TDX_REPORT_LEN))
+ ret = -EFAULT;
+
+out:
+ kfree(reportdata);
+ kfree(tdreport);
+
+ return ret;
+}
+
+static long tdx_guest_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case TDX_CMD_GET_REPORT0:
+ return tdx_get_report0((struct tdx_report_req __user *)arg);
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations tdx_guest_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = tdx_guest_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice tdx_misc_dev = {
+ .name = KBUILD_MODNAME,
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &tdx_guest_fops,
+};
+
+static const struct x86_cpu_id tdx_guest_ids[] = {
+ X86_MATCH_FEATURE(X86_FEATURE_TDX_GUEST, NULL),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, tdx_guest_ids);
+
+static int __init tdx_guest_init(void)
+{
+ if (!x86_match_cpu(tdx_guest_ids))
+ return -ENODEV;
+
+ return misc_register(&tdx_misc_dev);
+}
+module_init(tdx_guest_init);
+
+static void __exit tdx_guest_exit(void)
+{
+ misc_deregister(&tdx_misc_dev);
+}
+module_exit(tdx_guest_exit);
+
+MODULE_AUTHOR("Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>");
+MODULE_DESCRIPTION("TDX Guest Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ni903x_wdt.c b/drivers/watchdog/ni903x_wdt.c
index 4cebad324b20..045bb72d9a43 100644
--- a/drivers/watchdog/ni903x_wdt.c
+++ b/drivers/watchdog/ni903x_wdt.c
@@ -224,14 +224,12 @@ static int ni903x_acpi_add(struct acpi_device *device)
return 0;
}
-static int ni903x_acpi_remove(struct acpi_device *device)
+static void ni903x_acpi_remove(struct acpi_device *device)
{
struct ni903x_wdt *wdt = acpi_driver_data(device);
ni903x_wdd_stop(&wdt->wdd);
watchdog_unregister_device(&wdt->wdd);
-
- return 0;
}
static const struct acpi_device_id ni903x_device_ids[] = {
diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c
index 940e5e9e8a54..4440e626b797 100644
--- a/drivers/xen/gntdev-dmabuf.c
+++ b/drivers/xen/gntdev-dmabuf.c
@@ -600,7 +600,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev,
gntdev_dmabuf->u.imp.attach = attach;
- sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt)) {
ret = ERR_CAST(sgt);
goto fail_detach;
@@ -658,7 +658,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev,
fail_end_access:
dmabuf_imp_end_foreign_access(gntdev_dmabuf->u.imp.refs, count);
fail_unmap:
- dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL);
fail_detach:
dma_buf_detach(dma_buf, attach);
fail_free_obj:
@@ -708,8 +708,8 @@ static int dmabuf_imp_release(struct gntdev_dmabuf_priv *priv, u32 fd)
attach = gntdev_dmabuf->u.imp.attach;
if (gntdev_dmabuf->u.imp.sgt)
- dma_buf_unmap_attachment(attach, gntdev_dmabuf->u.imp.sgt,
- DMA_BIDIRECTIONAL);
+ dma_buf_unmap_attachment_unlocked(attach, gntdev_dmabuf->u.imp.sgt,
+ DMA_BIDIRECTIONAL);
dma_buf = attach->dmabuf;
dma_buf_detach(attach->dmabuf, attach);
dma_buf_put(dma_buf);
diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c
index daa525df7bdc..9784a77fa3c9 100644
--- a/drivers/xen/grant-dma-ops.c
+++ b/drivers/xen/grant-dma-ops.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/dma-map-ops.h>
#include <linux/of.h>
+#include <linux/pci.h>
#include <linux/pfn.h>
#include <linux/xarray.h>
#include <linux/virtio_anchor.h>
@@ -292,50 +293,48 @@ static const struct dma_map_ops xen_grant_dma_ops = {
.dma_supported = xen_grant_dma_supported,
};
-static bool xen_is_dt_grant_dma_device(struct device *dev)
+static struct device_node *xen_dt_get_node(struct device *dev)
{
- struct device_node *iommu_np;
- bool has_iommu;
+ if (dev_is_pci(dev)) {
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_bus *bus = pdev->bus;
- iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
- has_iommu = iommu_np &&
- of_device_is_compatible(iommu_np, "xen,grant-dma");
- of_node_put(iommu_np);
+ /* Walk up to the root bus to look for PCI Host controller */
+ while (!pci_is_root_bus(bus))
+ bus = bus->parent;
- return has_iommu;
-}
-
-bool xen_is_grant_dma_device(struct device *dev)
-{
- /* XXX Handle only DT devices for now */
- if (dev->of_node)
- return xen_is_dt_grant_dma_device(dev);
-
- return false;
-}
-
-bool xen_virtio_mem_acc(struct virtio_device *dev)
-{
- if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())
- return true;
+ return of_node_get(bus->bridge->parent->of_node);
+ }
- return xen_is_grant_dma_device(dev->dev.parent);
+ return of_node_get(dev->of_node);
}
static int xen_dt_grant_init_backend_domid(struct device *dev,
- struct xen_grant_dma_data *data)
+ struct device_node *np,
+ domid_t *backend_domid)
{
- struct of_phandle_args iommu_spec;
+ struct of_phandle_args iommu_spec = { .args_count = 1 };
- if (of_parse_phandle_with_args(dev->of_node, "iommus", "#iommu-cells",
- 0, &iommu_spec)) {
- dev_err(dev, "Cannot parse iommus property\n");
- return -ESRCH;
+ if (dev_is_pci(dev)) {
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
+
+ if (of_map_id(np, rid, "iommu-map", "iommu-map-mask", &iommu_spec.np,
+ iommu_spec.args)) {
+ dev_dbg(dev, "Cannot translate ID\n");
+ return -ESRCH;
+ }
+ } else {
+ if (of_parse_phandle_with_args(np, "iommus", "#iommu-cells",
+ 0, &iommu_spec)) {
+ dev_dbg(dev, "Cannot parse iommus property\n");
+ return -ESRCH;
+ }
}
if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") ||
iommu_spec.args_count != 1) {
- dev_err(dev, "Incompatible IOMMU node\n");
+ dev_dbg(dev, "Incompatible IOMMU node\n");
of_node_put(iommu_spec.np);
return -ESRCH;
}
@@ -346,12 +345,31 @@ static int xen_dt_grant_init_backend_domid(struct device *dev,
* The endpoint ID here means the ID of the domain where the
* corresponding backend is running
*/
- data->backend_domid = iommu_spec.args[0];
+ *backend_domid = iommu_spec.args[0];
return 0;
}
-void xen_grant_setup_dma_ops(struct device *dev)
+static int xen_grant_init_backend_domid(struct device *dev,
+ domid_t *backend_domid)
+{
+ struct device_node *np;
+ int ret = -ENODEV;
+
+ np = xen_dt_get_node(dev);
+ if (np) {
+ ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid);
+ of_node_put(np);
+ } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) {
+ dev_info(dev, "Using dom0 as backend\n");
+ *backend_domid = 0;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void xen_grant_setup_dma_ops(struct device *dev, domid_t backend_domid)
{
struct xen_grant_dma_data *data;
@@ -365,16 +383,7 @@ void xen_grant_setup_dma_ops(struct device *dev)
if (!data)
goto err;
- if (dev->of_node) {
- if (xen_dt_grant_init_backend_domid(dev, data))
- goto err;
- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) {
- dev_info(dev, "Using dom0 as backend\n");
- data->backend_domid = 0;
- } else {
- /* XXX ACPI device unsupported for now */
- goto err;
- }
+ data->backend_domid = backend_domid;
if (store_xen_grant_dma_data(dev, data)) {
dev_err(dev, "Cannot store Xen grant DMA data\n");
@@ -392,12 +401,14 @@ err:
bool xen_virtio_restricted_mem_acc(struct virtio_device *dev)
{
- bool ret = xen_virtio_mem_acc(dev);
+ domid_t backend_domid;
- if (ret)
- xen_grant_setup_dma_ops(dev->dev.parent);
+ if (!xen_grant_init_backend_domid(dev->dev.parent, &backend_domid)) {
+ xen_grant_setup_dma_ops(dev->dev.parent, backend_domid);
+ return true;
+ }
- return ret;
+ return false;
}
MODULE_DESCRIPTION("Xen grant DMA-mapping layer");
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
index 47aa3a1ccaf5..fd3a644b0855 100644
--- a/drivers/xen/pcpu.c
+++ b/drivers/xen/pcpu.c
@@ -228,7 +228,7 @@ static int register_pcpu(struct pcpu *pcpu)
err = device_register(dev);
if (err) {
- pcpu_release(dev);
+ put_device(dev);
return err;
}
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index 18f0ed8b1f93..cd07e3fed0fa 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -54,7 +54,8 @@ static uint64_t get_callback_via(struct pci_dev *pdev)
pin = pdev->pin;
/* We don't know the GSI. Specify the PCI INTx line instead. */
- return ((uint64_t)0x01 << HVM_CALLBACK_VIA_TYPE_SHIFT) | /* PCI INTx identifier */
+ return ((uint64_t)HVM_PARAM_CALLBACK_TYPE_PCI_INTX <<
+ HVM_CALLBACK_VIA_TYPE_SHIFT) |
((uint64_t)pci_domain_nr(pdev->bus) << 32) |
((uint64_t)pdev->bus->number << 16) |
((uint64_t)(pdev->devfn & 0xff) << 8) |
@@ -144,7 +145,7 @@ static int platform_pci_probe(struct pci_dev *pdev,
if (ret) {
dev_warn(&pdev->dev, "Unable to set the evtchn callback "
"err=%d\n", ret);
- goto out;
+ goto irq_out;
}
}
@@ -152,13 +153,16 @@ static int platform_pci_probe(struct pci_dev *pdev,
grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
ret = gnttab_setup_auto_xlat_frames(grant_frames);
if (ret)
- goto out;
+ goto irq_out;
ret = gnttab_init();
if (ret)
goto grant_out;
return 0;
grant_out:
gnttab_free_auto_xlat_frames();
+irq_out:
+ if (!xen_have_vector_callback)
+ free_irq(pdev->irq, pdev);
out:
pci_release_region(pdev, 0);
mem_out:
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index fae50a24630b..1edf45ee9890 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -760,7 +760,7 @@ static long privcmd_ioctl_mmap_resource(struct file *file,
goto out;
}
- pfns = kcalloc(kdata.num, sizeof(*pfns), GFP_KERNEL);
+ pfns = kcalloc(kdata.num, sizeof(*pfns), GFP_KERNEL | __GFP_NOWARN);
if (!pfns) {
rc = -ENOMEM;
goto out;
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index d6f945fd4147..28b2a1fa25ab 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -129,13 +129,13 @@ static bool pvcalls_conn_back_read(void *opaque)
if (masked_prod < masked_cons) {
vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = wanted;
- iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, wanted);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 1, wanted);
} else {
vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = array_size - masked_prod;
vec[1].iov_base = data->in;
vec[1].iov_len = wanted - vec[0].iov_len;
- iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, wanted);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 2, wanted);
}
atomic_set(&map->read, 0);
@@ -188,13 +188,13 @@ static bool pvcalls_conn_back_write(struct sock_mapping *map)
if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = size;
- iov_iter_kvec(&msg.msg_iter, READ, vec, 1, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 1, size);
} else {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
vec[1].iov_base = data->out;
vec[1].iov_len = size - vec[0].iov_len;
- iov_iter_kvec(&msg.msg_iter, READ, vec, 2, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 2, size);
}
atomic_set(&map->write, 0);
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index ccd8012020f1..ede69a5278d3 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -122,7 +122,7 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}
-static int acpi_pad_remove(struct acpi_device *device)
+static void acpi_pad_remove(struct acpi_device *device)
{
mutex_lock(&xen_cpu_lock);
xen_acpi_pad_idle_cpus(0);
@@ -130,7 +130,6 @@ static int acpi_pad_remove(struct acpi_device *device)
acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify);
- return 0;
}
static const struct acpi_device_id pad_device_ids[] = {
diff --git a/drivers/xen/xen-pciback/conf_space_capability.c b/drivers/xen/xen-pciback/conf_space_capability.c
index 5e53b4817f16..097316a74126 100644
--- a/drivers/xen/xen-pciback/conf_space_capability.c
+++ b/drivers/xen/xen-pciback/conf_space_capability.c
@@ -190,13 +190,16 @@ static const struct config_field caplist_pm[] = {
};
static struct msi_msix_field_config {
- u16 enable_bit; /* bit for enabling MSI/MSI-X */
- unsigned int int_type; /* interrupt type for exclusiveness check */
+ u16 enable_bit; /* bit for enabling MSI/MSI-X */
+ u16 allowed_bits; /* bits allowed to be changed */
+ unsigned int int_type; /* interrupt type for exclusiveness check */
} msi_field_config = {
.enable_bit = PCI_MSI_FLAGS_ENABLE,
+ .allowed_bits = PCI_MSI_FLAGS_ENABLE,
.int_type = INTERRUPT_TYPE_MSI,
}, msix_field_config = {
.enable_bit = PCI_MSIX_FLAGS_ENABLE,
+ .allowed_bits = PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL,
.int_type = INTERRUPT_TYPE_MSIX,
};
@@ -229,7 +232,7 @@ static int msi_msix_flags_write(struct pci_dev *dev, int offset, u16 new_value,
return 0;
if (!dev_data->allow_interrupt_control ||
- (new_value ^ old_value) & ~field_config->enable_bit)
+ (new_value ^ old_value) & ~field_config->allowed_bits)
return PCIBIOS_SET_FAILED;
if (new_value & field_config->enable_bit) {
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 4dac4a0dc5f4..c397c51f80d9 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -17,34 +17,64 @@
#include "v9fs_vfs.h"
#include "fid.h"
-static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
+static struct posix_acl *v9fs_fid_get_acl(struct p9_fid *fid, const char *name)
{
ssize_t size;
void *value = NULL;
struct posix_acl *acl = NULL;
size = v9fs_fid_xattr_get(fid, name, NULL, 0);
- if (size > 0) {
- value = kzalloc(size, GFP_NOFS);
- if (!value)
- return ERR_PTR(-ENOMEM);
- size = v9fs_fid_xattr_get(fid, name, value, size);
- if (size > 0) {
- acl = posix_acl_from_xattr(&init_user_ns, value, size);
- if (IS_ERR(acl))
- goto err_out;
- }
- } else if (size == -ENODATA || size == 0 ||
- size == -ENOSYS || size == -EOPNOTSUPP) {
- acl = NULL;
- } else
- acl = ERR_PTR(-EIO);
-
-err_out:
+ if (size < 0)
+ return ERR_PTR(size);
+ if (size == 0)
+ return ERR_PTR(-ENODATA);
+
+ value = kzalloc(size, GFP_NOFS);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+
+ size = v9fs_fid_xattr_get(fid, name, value, size);
+ if (size < 0)
+ acl = ERR_PTR(size);
+ else if (size == 0)
+ acl = ERR_PTR(-ENODATA);
+ else
+ acl = posix_acl_from_xattr(&init_user_ns, value, size);
kfree(value);
return acl;
}
+static struct posix_acl *v9fs_acl_get(struct dentry *dentry, const char *name)
+{
+ struct p9_fid *fid;
+ struct posix_acl *acl = NULL;
+
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return ERR_CAST(fid);
+
+ acl = v9fs_fid_get_acl(fid, name);
+ p9_fid_put(fid);
+ return acl;
+}
+
+static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, const char *name)
+{
+ int retval;
+ struct posix_acl *acl = NULL;
+
+ acl = v9fs_fid_get_acl(fid, name);
+ if (!IS_ERR(acl))
+ return acl;
+
+ retval = PTR_ERR(acl);
+ if (retval == -ENODATA || retval == -ENOSYS || retval == -EOPNOTSUPP)
+ return NULL;
+
+ /* map everything else to -EIO */
+ return ERR_PTR(-EIO);
+}
+
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
int retval = 0;
@@ -89,7 +119,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
return acl;
}
-struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type, bool rcu)
+struct posix_acl *v9fs_iop_get_inode_acl(struct inode *inode, int type, bool rcu)
{
struct v9fs_session_info *v9ses;
@@ -109,6 +139,112 @@ struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type, bool rcu)
}
+struct posix_acl *v9fs_iop_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type)
+{
+ struct v9fs_session_info *v9ses;
+
+ 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_acl_get(dentry, posix_acl_xattr_name(type));
+ return v9fs_get_cached_acl(d_inode(dentry), type);
+}
+
+int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type)
+{
+ int retval;
+ size_t size = 0;
+ void *value = NULL;
+ const char *acl_name;
+ struct v9fs_session_info *v9ses;
+ struct inode *inode = d_inode(dentry);
+
+ if (acl) {
+ retval = posix_acl_valid(inode->i_sb->s_user_ns, acl);
+ if (retval)
+ goto err_out;
+
+ size = posix_acl_xattr_size(acl->a_count);
+
+ value = kzalloc(size, GFP_NOFS);
+ if (!value) {
+ retval = -ENOMEM;
+ goto err_out;
+ }
+
+ retval = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+ if (retval < 0)
+ goto err_out;
+ }
+
+ /*
+ * set the attribute on the remote. Without even looking at the
+ * xattr value. We leave it to the server to validate
+ */
+ acl_name = posix_acl_xattr_name(type);
+ v9ses = v9fs_dentry2v9ses(dentry);
+ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+ retval = v9fs_xattr_set(dentry, acl_name, value, size, 0);
+ goto err_out;
+ }
+
+ if (S_ISLNK(inode->i_mode)) {
+ retval = -EOPNOTSUPP;
+ goto err_out;
+ }
+
+ if (!inode_owner_or_capable(&init_user_ns, inode)) {
+ retval = -EPERM;
+ goto err_out;
+ }
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ if (acl) {
+ struct iattr iattr = {};
+ struct posix_acl *acl_mode = acl;
+
+ retval = posix_acl_update_mode(&init_user_ns, inode,
+ &iattr.ia_mode,
+ &acl_mode);
+ if (retval)
+ goto err_out;
+ if (!acl_mode) {
+ /*
+ * ACL can be represented by the mode bits.
+ * So don't update ACL below.
+ */
+ kfree(value);
+ value = NULL;
+ size = 0;
+ }
+ iattr.ia_valid = ATTR_MODE;
+ /*
+ * FIXME should we update ctime ?
+ * What is the following setxattr update the mode ?
+ */
+ v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = acl ? -EINVAL : 0;
+ goto err_out;
+ }
+ break;
+ }
+
+ retval = v9fs_xattr_set(dentry, acl_name, value, size, 0);
+ if (!retval)
+ set_cached_acl(inode, type, acl);
+
+err_out:
+ kfree(value);
+ return retval;
+}
+
static int v9fs_set_acl(struct p9_fid *fid, int type, struct posix_acl *acl)
{
int retval;
@@ -207,124 +343,3 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
*modep = mode;
return 0;
}
-
-static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
- struct dentry *dentry, struct inode *inode,
- const char *name, void *buffer, size_t size)
-{
- struct v9fs_session_info *v9ses;
- struct posix_acl *acl;
- int error;
-
- 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_xattr_get(dentry, handler->name, buffer, size);
-
- acl = v9fs_get_cached_acl(inode, handler->flags);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (acl == NULL)
- return -ENODATA;
- error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
- posix_acl_release(acl);
-
- return error;
-}
-
-static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
- struct user_namespace *mnt_userns,
- struct dentry *dentry, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
-{
- int retval;
- struct posix_acl *acl;
- struct v9fs_session_info *v9ses;
-
- 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_xattr_set(dentry, handler->name, value, size,
- flags);
-
- if (S_ISLNK(inode->i_mode))
- return -EOPNOTSUPP;
- if (!inode_owner_or_capable(&init_user_ns, inode))
- return -EPERM;
- if (value) {
- /* update the cached acl value */
- acl = posix_acl_from_xattr(&init_user_ns, value, size);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- else if (acl) {
- retval = posix_acl_valid(inode->i_sb->s_user_ns, acl);
- if (retval)
- goto err_out;
- }
- } else
- acl = NULL;
-
- switch (handler->flags) {
- case ACL_TYPE_ACCESS:
- if (acl) {
- struct iattr iattr = { 0 };
- struct posix_acl *old_acl = acl;
-
- retval = posix_acl_update_mode(&init_user_ns, inode,
- &iattr.ia_mode, &acl);
- if (retval)
- goto err_out;
- if (!acl) {
- /*
- * ACL can be represented
- * by the mode bits. So don't
- * update ACL.
- */
- posix_acl_release(old_acl);
- value = NULL;
- size = 0;
- }
- iattr.ia_valid = ATTR_MODE;
- /* FIXME should we update ctime ?
- * What is the following setxattr update the
- * mode ?
- */
- v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
- }
- break;
- case ACL_TYPE_DEFAULT:
- if (!S_ISDIR(inode->i_mode)) {
- retval = acl ? -EINVAL : 0;
- goto err_out;
- }
- break;
- default:
- BUG();
- }
- retval = v9fs_xattr_set(dentry, handler->name, value, size, flags);
- if (!retval)
- set_cached_acl(inode, handler->flags, acl);
-err_out:
- posix_acl_release(acl);
- return retval;
-}
-
-const struct xattr_handler v9fs_xattr_acl_access_handler = {
- .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 = {
- .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/acl.h b/fs/9p/acl.h
index ce5175d463dd..4c60a2bce5de 100644
--- a/fs/9p/acl.h
+++ b/fs/9p/acl.h
@@ -8,8 +8,12 @@
#ifdef CONFIG_9P_FS_POSIX_ACL
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid);
-struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type,
+struct posix_acl *v9fs_iop_get_inode_acl(struct inode *inode, int type,
bool rcu);
+struct posix_acl *v9fs_iop_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type);
+int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type);
int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid);
int v9fs_set_create_acl(struct inode *inode, struct p9_fid *fid,
struct posix_acl *dacl, struct posix_acl *acl);
@@ -17,7 +21,9 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
struct posix_acl **dpacl, struct posix_acl **pacl);
void v9fs_put_acl(struct posix_acl *dacl, struct posix_acl *acl);
#else
+#define v9fs_iop_get_inode_acl NULL
#define v9fs_iop_get_acl NULL
+#define v9fs_iop_set_acl NULL
static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
return 0;
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 47b9a1122f34..a19891015f19 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -40,7 +40,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
size_t len = subreq->len - subreq->transferred;
int total, err;
- iov_iter_xarray(&to, READ, &rreq->mapping->i_pages, pos, len);
+ iov_iter_xarray(&to, ITER_DEST, &rreq->mapping->i_pages, pos, len);
total = p9_client_read(fid, pos, &to, &err);
@@ -172,7 +172,7 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
len = min_t(loff_t, i_size - start, len);
- iov_iter_xarray(&from, WRITE, &folio_mapping(folio)->i_pages, start, len);
+ iov_iter_xarray(&from, ITER_SOURCE, &folio_mapping(folio)->i_pages, start, len);
/* We should have writeback_fid always set */
BUG_ON(!v9inode->writeback_fid);
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 000fbaae9b18..3bb95adc9619 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -109,7 +109,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
struct iov_iter to;
int n;
- iov_iter_kvec(&to, READ, &kvec, 1, buflen);
+ iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buflen);
n = p9_client_read(file->private_data, ctx->pos, &to,
&err);
if (err)
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 5cfa4b4f070f..03c1743c4aff 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -983,14 +983,18 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.listxattr = v9fs_listxattr,
+ .get_inode_acl = v9fs_iop_get_inode_acl,
.get_acl = v9fs_iop_get_acl,
+ .set_acl = v9fs_iop_set_acl,
};
const struct inode_operations v9fs_file_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.listxattr = v9fs_listxattr,
+ .get_inode_acl = v9fs_iop_get_inode_acl,
.get_acl = v9fs_iop_get_acl,
+ .set_acl = v9fs_iop_set_acl,
};
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index 1f9298a4bd42..b6984311e00a 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/uio.h>
+#include <linux/posix_acl_xattr.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@@ -24,7 +25,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
struct iov_iter to;
int err;
- iov_iter_kvec(&to, READ, &kvec, 1, buffer_size);
+ iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buffer_size);
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
if (IS_ERR(attr_fid)) {
@@ -109,7 +110,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
struct iov_iter from;
int retval, err;
- iov_iter_kvec(&from, WRITE, &kvec, 1, value_len);
+ iov_iter_kvec(&from, ITER_SOURCE, &kvec, 1, value_len);
p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
name, value_len, flags);
@@ -182,9 +183,9 @@ static struct xattr_handler v9fs_xattr_security_handler = {
const struct xattr_handler *v9fs_xattr_handlers[] = {
&v9fs_xattr_user_handler,
&v9fs_xattr_trusted_handler,
-#ifdef CONFIG_9P_FS_POSIX_ACL
- &v9fs_xattr_acl_access_handler,
- &v9fs_xattr_acl_default_handler,
+#ifdef CONFIG_FS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
#endif
#ifdef CONFIG_9P_FS_SECURITY
&v9fs_xattr_security_handler,
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
index 3e11fc3331eb..b5636e544c8a 100644
--- a/fs/9p/xattr.h
+++ b/fs/9p/xattr.h
@@ -11,8 +11,6 @@
#include <net/9p/client.h>
extern const struct xattr_handler *v9fs_xattr_handlers[];
-extern const struct xattr_handler v9fs_xattr_acl_access_handler;
-extern const struct xattr_handler v9fs_xattr_acl_default_handler;
ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
void *buffer, size_t buffer_size);
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 0a090d614e76..7dcd59693a0c 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -298,7 +298,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
if (call->count2 != call->count && call->count2 != 0)
return afs_protocol_error(call, afs_eproto_cb_count);
call->iter = &call->def_iter;
- iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4);
+ iov_iter_discard(&call->def_iter, ITER_DEST, call->count2 * 3 * 4);
call->unmarshall++;
fallthrough;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 230c2d19116d..104df2964225 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -305,7 +305,7 @@ expand:
req->actual_len = i_size; /* May change */
req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */
req->data_version = dvnode->status.data_version; /* May change */
- iov_iter_xarray(&req->def_iter, READ, &dvnode->netfs.inode.i_mapping->i_pages,
+ iov_iter_xarray(&req->def_iter, ITER_DEST, &dvnode->netfs.inode.i_mapping->i_pages,
0, i_size);
req->iter = &req->def_iter;
diff --git a/fs/afs/file.c b/fs/afs/file.c
index d1cfb235c4b9..2eeab57df133 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -324,7 +324,7 @@ static void afs_issue_read(struct netfs_io_subrequest *subreq)
fsreq->vnode = vnode;
fsreq->iter = &fsreq->def_iter;
- iov_iter_xarray(&fsreq->def_iter, READ,
+ iov_iter_xarray(&fsreq->def_iter, ITER_DEST,
&fsreq->vnode->netfs.inode.i_mapping->i_pages,
fsreq->pos, fsreq->len);
@@ -346,7 +346,7 @@ static int afs_symlink_read_folio(struct file *file, struct folio *folio)
fsreq->len = folio_size(folio);
fsreq->vnode = vnode;
fsreq->iter = &fsreq->def_iter;
- iov_iter_xarray(&fsreq->def_iter, READ, &folio->mapping->i_pages,
+ iov_iter_xarray(&fsreq->def_iter, ITER_DEST, &folio->mapping->i_pages,
fsreq->pos, fsreq->len);
ret = afs_fetch_data(fsreq->vnode, fsreq);
diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
index c0031a3ab42f..3ac5fcf98d0d 100644
--- a/fs/afs/fs_probe.c
+++ b/fs/afs/fs_probe.c
@@ -167,8 +167,8 @@ responded:
clear_bit(AFS_SERVER_FL_HAS_FS64, &server->flags);
}
- if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
- rtt_us < server->probe.rtt) {
+ rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us);
+ if (rtt_us < server->probe.rtt) {
server->probe.rtt = rtt_us;
server->rtt = rtt_us;
alist->preferred = index;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 723d162078a3..9ba7b68375c9 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1301,7 +1301,7 @@ static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t si
call->iov_len = size;
call->kvec[0].iov_base = buf;
call->kvec[0].iov_len = size;
- iov_iter_kvec(&call->def_iter, READ, call->kvec, 1, size);
+ iov_iter_kvec(&call->def_iter, ITER_DEST, call->kvec, 1, size);
}
static inline void afs_extract_to_tmp(struct afs_call *call)
@@ -1319,7 +1319,7 @@ static inline void afs_extract_to_tmp64(struct afs_call *call)
static inline void afs_extract_discard(struct afs_call *call, size_t size)
{
call->iov_len = size;
- iov_iter_discard(&call->def_iter, READ, size);
+ iov_iter_discard(&call->def_iter, ITER_DEST, size);
}
static inline void afs_extract_to_buf(struct afs_call *call, size_t size)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index eccc3cd0cb70..c62939e5ea1f 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -359,7 +359,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
@@ -400,7 +400,7 @@ error_do_abort:
RX_USER_ABORT, ret, "KSD");
} else {
len = 0;
- iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
rxrpc_kernel_recv_data(call->net->socket, rxcall,
&msg.msg_iter, &len, false,
&call->abort_code, &call->service_id);
@@ -485,7 +485,7 @@ static void afs_deliver_to_call(struct afs_call *call)
) {
if (state == AFS_CALL_SV_AWAIT_ACK) {
len = 0;
- iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0);
+ iov_iter_kvec(&call->def_iter, ITER_DEST, NULL, 0, 0);
ret = rxrpc_kernel_recv_data(call->net->socket,
call->rxcall, &call->def_iter,
&len, false, &remote_abort,
@@ -822,7 +822,7 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, NULL, 0, 0);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
@@ -862,7 +862,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
iov[0].iov_len = len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, len);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 4981baf97835..b5237206eac3 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -406,7 +406,7 @@ void afs_put_server(struct afs_net *net, struct afs_server *server,
if (!server)
return;
- a = atomic_inc_return(&server->active);
+ a = atomic_read(&server->active);
zero = __refcount_dec_and_test(&server->ref, &r);
trace_afs_server(debug_id, r - 1, a, reason);
if (unlikely(zero))
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 9ebdd36eaf2f..08fd456dde67 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -609,7 +609,7 @@ static ssize_t afs_write_back_from_locked_folio(struct address_space *mapping,
*/
afs_write_to_cache(vnode, start, len, i_size, caching);
- iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len);
+ iov_iter_xarray(&iter, ITER_SOURCE, &mapping->i_pages, start, len);
ret = afs_store_data(vnode, &iter, start, false);
} else {
_debug("write discard %x @%llx [%llx]", len, start, i_size);
@@ -1000,7 +1000,7 @@ int afs_launder_folio(struct folio *folio)
bv[0].bv_page = &folio->page;
bv[0].bv_offset = f;
bv[0].bv_len = t - f;
- iov_iter_bvec(&iter, WRITE, bv, 1, bv[0].bv_len);
+ iov_iter_bvec(&iter, ITER_SOURCE, bv, 1, bv[0].bv_len);
trace_afs_folio_dirty(vnode, tracepoint_string("launder"), folio);
ret = afs_store_data(vnode, &iter, folio_pos(folio) + f, true);
diff --git a/fs/aio.c b/fs/aio.c
index 5b2ff20ad322..562916d85cba 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1552,7 +1552,7 @@ static int aio_read(struct kiocb *req, const struct iocb *iocb,
if (unlikely(!file->f_op->read_iter))
return -EINVAL;
- ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
+ ret = aio_setup_rw(ITER_DEST, iocb, &iovec, vectored, compat, &iter);
if (ret < 0)
return ret;
ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
@@ -1580,7 +1580,7 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
if (unlikely(!file->f_op->write_iter))
return -EINVAL;
- ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
+ ret = aio_setup_rw(ITER_SOURCE, iocb, &iovec, vectored, compat, &iter);
if (ret < 0)
return ret;
ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
diff --git a/fs/attr.c b/fs/attr.c
index 1552a5f23d6b..b45f30e516fa 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -18,6 +18,70 @@
#include <linux/evm.h>
#include <linux/ima.h>
+#include "internal.h"
+
+/**
+ * setattr_should_drop_sgid - determine whether the setgid bit needs to be
+ * removed
+ * @mnt_userns: user namespace of the mount @inode was found from
+ * @inode: inode to check
+ *
+ * This function determines whether the setgid bit needs to be removed.
+ * We retain backwards compatibility and require setgid bit to be removed
+ * unconditionally if S_IXGRP is set. Otherwise we have the exact same
+ * requirements as setattr_prepare() and setattr_copy().
+ *
+ * Return: ATTR_KILL_SGID if setgid bit needs to be removed, 0 otherwise.
+ */
+int setattr_should_drop_sgid(struct user_namespace *mnt_userns,
+ const struct inode *inode)
+{
+ umode_t mode = inode->i_mode;
+
+ if (!(mode & S_ISGID))
+ return 0;
+ if (mode & S_IXGRP)
+ return ATTR_KILL_SGID;
+ if (!in_group_or_capable(mnt_userns, inode,
+ i_gid_into_vfsgid(mnt_userns, inode)))
+ return ATTR_KILL_SGID;
+ return 0;
+}
+
+/**
+ * setattr_should_drop_suidgid - determine whether the set{g,u}id bit needs to
+ * be dropped
+ * @mnt_userns: user namespace of the mount @inode was found from
+ * @inode: inode to check
+ *
+ * This function determines whether the set{g,u}id bits need to be removed.
+ * If the setuid bit needs to be removed ATTR_KILL_SUID is returned. If the
+ * setgid bit needs to be removed ATTR_KILL_SGID is returned. If both
+ * set{g,u}id bits need to be removed the corresponding mask of both flags is
+ * returned.
+ *
+ * Return: A mask of ATTR_KILL_S{G,U}ID indicating which - if any - setid bits
+ * to remove, 0 otherwise.
+ */
+int setattr_should_drop_suidgid(struct user_namespace *mnt_userns,
+ struct inode *inode)
+{
+ umode_t mode = inode->i_mode;
+ int kill = 0;
+
+ /* suid always must be killed */
+ if (unlikely(mode & S_ISUID))
+ kill = ATTR_KILL_SUID;
+
+ kill |= setattr_should_drop_sgid(mnt_userns, inode);
+
+ if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
+ return kill;
+
+ return 0;
+}
+EXPORT_SYMBOL(setattr_should_drop_suidgid);
+
/**
* chown_ok - verify permissions to chown inode
* @mnt_userns: user namespace of the mount @inode was found from
@@ -140,8 +204,7 @@ int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,
vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
/* Also check the setgid bit! */
- if (!vfsgid_in_group_p(vfsgid) &&
- !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
+ if (!in_group_or_capable(mnt_userns, inode, vfsgid))
attr->ia_mode &= ~S_ISGID;
}
@@ -251,9 +314,8 @@ void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
inode->i_ctime = attr->ia_ctime;
if (ia_valid & ATTR_MODE) {
umode_t mode = attr->ia_mode;
- vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
- if (!vfsgid_in_group_p(vfsgid) &&
- !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
+ if (!in_group_or_capable(mnt_userns, inode,
+ i_gid_into_vfsgid(mnt_userns, inode)))
mode &= ~S_ISGID;
inode->i_mode = mode;
}
@@ -375,7 +437,7 @@ int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
}
}
if (ia_valid & ATTR_KILL_SGID) {
- if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+ if (mode & S_ISGID) {
if (!(ia_valid & ATTR_MODE)) {
ia_valid = attr->ia_valid |= ATTR_MODE;
attr->ia_mode = inode->i_mode;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 9d1cde8066cf..92737166203f 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -154,7 +154,7 @@ static int bad_inode_tmpfile(struct user_namespace *mnt_userns,
}
static int bad_inode_set_acl(struct user_namespace *mnt_userns,
- struct inode *inode, struct posix_acl *acl,
+ struct dentry *dentry, struct posix_acl *acl,
int type)
{
return -EIO;
@@ -177,7 +177,7 @@ static const struct inode_operations bad_inode_ops =
.setattr = bad_inode_setattr,
.listxattr = bad_inode_listxattr,
.get_link = bad_inode_get_link,
- .get_acl = bad_inode_get_acl,
+ .get_inode_acl = bad_inode_get_acl,
.fiemap = bad_inode_fiemap,
.update_time = bad_inode_update_time,
.atomic_open = bad_inode_atomic_open,
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 6a11025e5850..de63572a9404 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -248,7 +248,7 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
} while (0)
#ifdef ARCH_DLINFO
- /*
+ /*
* ARCH_DLINFO must come first so PPC can do its special alignment of
* AUXV.
* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in
@@ -456,13 +456,13 @@ static unsigned long maximum_alignment(struct elf_phdr *cmds, int nr)
*
* Loads ELF program headers from the binary file elf_file, which has the ELF
* header pointed to by elf_ex, into a newly allocated array. The caller is
- * responsible for freeing the allocated data. Returns an ERR_PTR upon failure.
+ * responsible for freeing the allocated data. Returns NULL upon failure.
*/
static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex,
struct file *elf_file)
{
struct elf_phdr *elf_phdata = NULL;
- int retval, err = -1;
+ int retval = -1;
unsigned int size;
/*
@@ -484,15 +484,9 @@ static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex,
/* Read in the program headers */
retval = elf_read(elf_file, elf_phdata, size, elf_ex->e_phoff);
- if (retval < 0) {
- err = retval;
- goto out;
- }
- /* Success! */
- err = 0;
out:
- if (err) {
+ if (retval) {
kfree(elf_phdata);
elf_phdata = NULL;
}
@@ -1020,7 +1014,7 @@ out_free_interp:
executable_stack);
if (retval < 0)
goto out_free_dentry;
-
+
elf_bss = 0;
elf_brk = 0;
@@ -1043,7 +1037,7 @@ out_free_interp:
if (unlikely (elf_brk > elf_bss)) {
unsigned long nbyte;
-
+
/* There was a PT_LOAD segment with p_memsz > p_filesz
before this one. Map anonymous pages, if needed,
and clear the area. */
@@ -1166,7 +1160,7 @@ out_free_interp:
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
- retval = IS_ERR((void *)error) ?
+ retval = IS_ERR_VALUE(error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
@@ -1251,7 +1245,7 @@ out_free_interp:
interpreter,
load_bias, interp_elf_phdata,
&arch_state);
- if (!IS_ERR((void *)elf_entry)) {
+ if (!IS_ERR_VALUE(elf_entry)) {
/*
* load_elf_interp() returns relocation
* adjustment
@@ -1260,7 +1254,7 @@ out_free_interp:
elf_entry += interp_elf_ex->e_entry;
}
if (BAD_ADDR(elf_entry)) {
- retval = IS_ERR((void *)elf_entry) ?
+ retval = IS_ERR_VALUE(elf_entry) ?
(int)elf_entry : -EINVAL;
goto out_free_dentry;
}
@@ -1521,7 +1515,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
phdr->p_align = 0;
}
-static void fill_note(struct memelfnote *note, const char *name, int type,
+static void fill_note(struct memelfnote *note, const char *name, int type,
unsigned int sz, void *data)
{
note->name = name;
@@ -1724,7 +1718,6 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm
return 0;
}
-#ifdef CORE_DUMP_USE_REGSET
#include <linux/regset.h>
struct elf_thread_core_info {
@@ -1745,6 +1738,7 @@ struct elf_note_info {
int thread_notes;
};
+#ifdef CORE_DUMP_USE_REGSET
/*
* When a regset has a writeback hook, we call it on each thread before
* dumping user memory. On register window machines, this makes sure the
@@ -1824,34 +1818,58 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
return 1;
}
+#else
+static int fill_thread_core_info(struct elf_thread_core_info *t,
+ const struct user_regset_view *view,
+ long signr, struct elf_note_info *info)
+{
+ struct task_struct *p = t->task;
+ elf_fpregset_t *fpu;
+
+ fill_prstatus(&t->prstatus.common, p, signr);
+ elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
+
+ fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
+ &(t->prstatus));
+ info->size += notesize(&t->notes[0]);
+
+ fpu = kzalloc(sizeof(elf_fpregset_t), GFP_KERNEL);
+ if (!fpu || !elf_core_copy_task_fpregs(p, fpu)) {
+ kfree(fpu);
+ return 1;
+ }
+
+ t->prstatus.pr_fpvalid = 1;
+ fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
+ info->size += notesize(&t->notes[1]);
+
+ return 1;
+}
+#endif
static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
struct coredump_params *cprm)
{
struct task_struct *dump_task = current;
- const struct user_regset_view *view = task_user_regset_view(dump_task);
+ const struct user_regset_view *view;
struct elf_thread_core_info *t;
struct elf_prpsinfo *psinfo;
struct core_thread *ct;
- unsigned int i;
-
- info->size = 0;
- info->thread = NULL;
psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
- if (psinfo == NULL) {
- info->psinfo.data = NULL; /* So we don't free this wrongly */
+ if (!psinfo)
return 0;
- }
-
fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
+#ifdef CORE_DUMP_USE_REGSET
+ view = task_user_regset_view(dump_task);
+
/*
* Figure out how many notes we're going to need for each thread.
*/
info->thread_notes = 0;
- for (i = 0; i < view->n; ++i)
+ for (int i = 0; i < view->n; ++i)
if (view->regsets[i].core_note_type != 0)
++info->thread_notes;
@@ -1870,11 +1888,23 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
*/
fill_elf_header(elf, phdrs,
view->e_machine, view->e_flags);
+#else
+ view = NULL;
+ info->thread_notes = 2;
+ fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
+#endif
/*
* Allocate a structure for each thread.
*/
- for (ct = &dump_task->signal->core_state->dumper; ct; ct = ct->next) {
+ info->thread = kzalloc(offsetof(struct elf_thread_core_info,
+ notes[info->thread_notes]),
+ GFP_KERNEL);
+ if (unlikely(!info->thread))
+ return 0;
+
+ info->thread->task = dump_task;
+ for (ct = dump_task->signal->core_state->dumper.next; ct; ct = ct->next) {
t = kzalloc(offsetof(struct elf_thread_core_info,
notes[info->thread_notes]),
GFP_KERNEL);
@@ -1882,17 +1912,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
return 0;
t->task = ct->task;
- if (ct->task == dump_task || !info->thread) {
- t->next = info->thread;
- info->thread = t;
- } else {
- /*
- * Make sure to keep the original task at
- * the head of the list.
- */
- t->next = info->thread->next;
- info->thread->next = t;
- }
+ t->next = info->thread->next;
+ info->thread->next = t;
}
/*
@@ -1920,11 +1941,6 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
return 1;
}
-static size_t get_note_info_size(struct elf_note_info *info)
-{
- return info->size;
-}
-
/*
* Write all the notes for each thread. When writing the first thread, the
* process-wide notes are interleaved after the first thread-specific note.
@@ -1979,197 +1995,6 @@ static void free_note_info(struct elf_note_info *info)
kvfree(info->files.data);
}
-#else
-
-/* Here is the structure in which status of each thread is captured. */
-struct elf_thread_status
-{
- struct list_head list;
- struct elf_prstatus prstatus; /* NT_PRSTATUS */
- elf_fpregset_t fpu; /* NT_PRFPREG */
- struct task_struct *thread;
- struct memelfnote notes[3];
- int num_notes;
-};
-
-/*
- * In order to add the specific thread information for the elf file format,
- * we need to keep a linked list of every threads pr_status and then create
- * a single section for them in the final core file.
- */
-static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
-{
- int sz = 0;
- struct task_struct *p = t->thread;
- t->num_notes = 0;
-
- fill_prstatus(&t->prstatus.common, p, signr);
- elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
-
- fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
- &(t->prstatus));
- t->num_notes++;
- sz += notesize(&t->notes[0]);
-
- if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL,
- &t->fpu))) {
- fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
- &(t->fpu));
- t->num_notes++;
- sz += notesize(&t->notes[1]);
- }
- return sz;
-}
-
-struct elf_note_info {
- struct memelfnote *notes;
- struct memelfnote *notes_files;
- struct elf_prstatus *prstatus; /* NT_PRSTATUS */
- struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
- struct list_head thread_list;
- elf_fpregset_t *fpu;
- user_siginfo_t csigdata;
- int thread_status_size;
- int numnote;
-};
-
-static int elf_note_info_init(struct elf_note_info *info)
-{
- memset(info, 0, sizeof(*info));
- INIT_LIST_HEAD(&info->thread_list);
-
- /* Allocate space for ELF notes */
- info->notes = kmalloc_array(8, sizeof(struct memelfnote), GFP_KERNEL);
- if (!info->notes)
- return 0;
- info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
- if (!info->psinfo)
- return 0;
- info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
- if (!info->prstatus)
- return 0;
- info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
- if (!info->fpu)
- return 0;
- return 1;
-}
-
-static int fill_note_info(struct elfhdr *elf, int phdrs,
- struct elf_note_info *info,
- struct coredump_params *cprm)
-{
- struct core_thread *ct;
- struct elf_thread_status *ets;
-
- if (!elf_note_info_init(info))
- return 0;
-
- for (ct = current->signal->core_state->dumper.next;
- ct; ct = ct->next) {
- ets = kzalloc(sizeof(*ets), GFP_KERNEL);
- if (!ets)
- return 0;
-
- ets->thread = ct->task;
- list_add(&ets->list, &info->thread_list);
- }
-
- list_for_each_entry(ets, &info->thread_list, list) {
- int sz;
-
- sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets);
- info->thread_status_size += sz;
- }
- /* now collect the dump for the current */
- memset(info->prstatus, 0, sizeof(*info->prstatus));
- fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
- elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs);
-
- /* Set up header */
- fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
-
- /*
- * Set up the notes in similar form to SVR4 core dumps made
- * with info from their /proc.
- */
-
- fill_note(info->notes + 0, "CORE", NT_PRSTATUS,
- sizeof(*info->prstatus), info->prstatus);
- fill_psinfo(info->psinfo, current->group_leader, current->mm);
- fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
- sizeof(*info->psinfo), info->psinfo);
-
- fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo);
- fill_auxv_note(info->notes + 3, current->mm);
- info->numnote = 4;
-
- if (fill_files_note(info->notes + info->numnote, cprm) == 0) {
- info->notes_files = info->notes + info->numnote;
- info->numnote++;
- }
-
- /* Try to dump the FPU. */
- info->prstatus->pr_fpvalid =
- elf_core_copy_task_fpregs(current, cprm->regs, info->fpu);
- if (info->prstatus->pr_fpvalid)
- fill_note(info->notes + info->numnote++,
- "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
- return 1;
-}
-
-static size_t get_note_info_size(struct elf_note_info *info)
-{
- int sz = 0;
- int i;
-
- for (i = 0; i < info->numnote; i++)
- sz += notesize(info->notes + i);
-
- sz += info->thread_status_size;
-
- return sz;
-}
-
-static int write_note_info(struct elf_note_info *info,
- struct coredump_params *cprm)
-{
- struct elf_thread_status *ets;
- int i;
-
- for (i = 0; i < info->numnote; i++)
- if (!writenote(info->notes + i, cprm))
- return 0;
-
- /* write out the thread status notes section */
- list_for_each_entry(ets, &info->thread_list, list) {
- for (i = 0; i < ets->num_notes; i++)
- if (!writenote(&ets->notes[i], cprm))
- return 0;
- }
-
- return 1;
-}
-
-static void free_note_info(struct elf_note_info *info)
-{
- while (!list_empty(&info->thread_list)) {
- struct list_head *tmp = info->thread_list.next;
- list_del(tmp);
- kfree(list_entry(tmp, struct elf_thread_status, list));
- }
-
- /* Free data possibly allocated by fill_files_note(): */
- if (info->notes_files)
- kvfree(info->notes_files->data);
-
- kfree(info->prstatus);
- kfree(info->psinfo);
- kfree(info->notes);
- kfree(info->fpu);
-}
-
-#endif
-
static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
elf_addr_t e_shoff, int segs)
{
@@ -2233,7 +2058,7 @@ static int elf_core_dump(struct coredump_params *cprm)
/* Write notes phdr entry */
{
- size_t sz = get_note_info_size(&info);
+ size_t sz = info.size;
/* For cell spufs */
sz += elf_coredump_extra_notes_size();
@@ -2295,7 +2120,7 @@ static int elf_core_dump(struct coredump_params *cprm)
if (!elf_core_write_extra_phdrs(cprm, offset))
goto end_coredump;
- /* write out the notes section */
+ /* write out the notes section */
if (!write_note_info(&info, cprm))
goto end_coredump;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 08d0c8797828..096e3520a0b1 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -434,8 +434,9 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
current->mm->start_stack = current->mm->start_brk + stack_size;
#endif
- if (create_elf_fdpic_tables(bprm, current->mm,
- &exec_params, &interp_params) < 0)
+ retval = create_elf_fdpic_tables(bprm, current->mm, &exec_params,
+ &interp_params);
+ if (retval < 0)
goto error;
kdebug("- start_code %lx", current->mm->start_code);
@@ -1603,7 +1604,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
if (!elf_core_write_extra_phdrs(cprm, offset))
goto end_coredump;
- /* write out the notes section */
+ /* write out the notes section */
if (!writenote(thread_list->notes, cprm))
goto end_coredump;
if (!writenote(&psinfo_note, cprm))
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index e1eae7ea823a..bb202ad369d5 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -44,10 +44,10 @@ static LIST_HEAD(entries);
static int enabled = 1;
enum {Enabled, Magic};
-#define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
-#define MISC_FMT_OPEN_BINARY (1 << 30)
-#define MISC_FMT_CREDENTIALS (1 << 29)
-#define MISC_FMT_OPEN_FILE (1 << 28)
+#define MISC_FMT_PRESERVE_ARGV0 (1UL << 31)
+#define MISC_FMT_OPEN_BINARY (1UL << 30)
+#define MISC_FMT_CREDENTIALS (1UL << 29)
+#define MISC_FMT_OPEN_FILE (1UL << 28)
typedef struct {
struct list_head list;
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index fa9ddcc9eb0b..555c962fdad6 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -23,15 +23,15 @@ obj-$(CONFIG_BTRFS_FS) := btrfs.o
btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
file-item.o inode-item.o disk-io.o \
- transaction.o inode.o file.o tree-defrag.o \
- extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
+ transaction.o inode.o file.o defrag.o \
+ extent_map.o sysfs.o accessors.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \
block-rsv.o delalloc-space.o block-group.o discard.o reflink.o \
- subpage.o tree-mod-log.o extent-io-tree.o
+ subpage.o tree-mod-log.o extent-io-tree.o fs.o messages.o bio.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
diff --git a/fs/btrfs/struct-funcs.c b/fs/btrfs/accessors.c
index 12455b2b41de..206cf1612c1d 100644
--- a/fs/btrfs/struct-funcs.c
+++ b/fs/btrfs/accessors.c
@@ -4,8 +4,9 @@
*/
#include <asm/unaligned.h>
-
+#include "messages.h"
#include "ctree.h"
+#include "accessors.h"
static bool check_setget_bounds(const struct extent_buffer *eb,
const void *ptr, unsigned off, int size)
@@ -23,6 +24,13 @@ static bool check_setget_bounds(const struct extent_buffer *eb,
return true;
}
+void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb)
+{
+ token->eb = eb;
+ token->kaddr = page_address(eb->pages[0]);
+ token->offset = 0;
+}
+
/*
* Macro templates that define helpers to read/write extent buffer data of a
* given size, that are also used via ctree.h for access to item members by
@@ -160,7 +168,7 @@ DEFINE_BTRFS_SETGET_BITS(64)
void btrfs_node_key(const struct extent_buffer *eb,
struct btrfs_disk_key *disk_key, int nr)
{
- unsigned long ptr = btrfs_node_key_ptr_offset(nr);
+ unsigned long ptr = btrfs_node_key_ptr_offset(eb, nr);
read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
struct btrfs_key_ptr, key, disk_key);
}
diff --git a/fs/btrfs/accessors.h b/fs/btrfs/accessors.h
new file mode 100644
index 000000000000..ceadfc5d6c66
--- /dev/null
+++ b/fs/btrfs/accessors.h
@@ -0,0 +1,1073 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_ACCESSORS_H
+#define BTRFS_ACCESSORS_H
+
+struct btrfs_map_token {
+ struct extent_buffer *eb;
+ char *kaddr;
+ unsigned long offset;
+};
+
+void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb);
+
+/*
+ * Some macros to generate set/get functions for the struct fields. This
+ * assumes there is a lefoo_to_cpu for every type, so lets make a simple one
+ * for u8:
+ */
+#define le8_to_cpu(v) (v)
+#define cpu_to_le8(v) (v)
+#define __le8 u8
+
+static inline u8 get_unaligned_le8(const void *p)
+{
+ return *(u8 *)p;
+}
+
+static inline void put_unaligned_le8(u8 val, void *p)
+{
+ *(u8 *)p = val;
+}
+
+#define read_eb_member(eb, ptr, type, member, result) (\
+ read_extent_buffer(eb, (char *)(result), \
+ ((unsigned long)(ptr)) + \
+ offsetof(type, member), \
+ sizeof(((type *)0)->member)))
+
+#define write_eb_member(eb, ptr, type, member, result) (\
+ write_extent_buffer(eb, (char *)(result), \
+ ((unsigned long)(ptr)) + \
+ offsetof(type, member), \
+ sizeof(((type *)0)->member)))
+
+#define DECLARE_BTRFS_SETGET_BITS(bits) \
+u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
+ const void *ptr, unsigned long off); \
+void btrfs_set_token_##bits(struct btrfs_map_token *token, \
+ const void *ptr, unsigned long off, \
+ u##bits val); \
+u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
+ const void *ptr, unsigned long off); \
+void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
+ unsigned long off, u##bits val);
+
+DECLARE_BTRFS_SETGET_BITS(8)
+DECLARE_BTRFS_SETGET_BITS(16)
+DECLARE_BTRFS_SETGET_BITS(32)
+DECLARE_BTRFS_SETGET_BITS(64)
+
+#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
+static inline u##bits btrfs_##name(const struct extent_buffer *eb, \
+ const type *s) \
+{ \
+ static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
+ return btrfs_get_##bits(eb, s, offsetof(type, member)); \
+} \
+static inline void btrfs_set_##name(const struct extent_buffer *eb, type *s, \
+ u##bits val) \
+{ \
+ static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
+ btrfs_set_##bits(eb, s, offsetof(type, member), val); \
+} \
+static inline u##bits btrfs_token_##name(struct btrfs_map_token *token, \
+ const type *s) \
+{ \
+ static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
+ return btrfs_get_token_##bits(token, s, offsetof(type, member));\
+} \
+static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\
+ type *s, u##bits val) \
+{ \
+ static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
+ btrfs_set_token_##bits(token, s, offsetof(type, member), val); \
+}
+
+#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
+static inline u##bits btrfs_##name(const struct extent_buffer *eb) \
+{ \
+ const type *p = page_address(eb->pages[0]) + \
+ offset_in_page(eb->start); \
+ return get_unaligned_le##bits(&p->member); \
+} \
+static inline void btrfs_set_##name(const struct extent_buffer *eb, \
+ u##bits val) \
+{ \
+ type *p = page_address(eb->pages[0]) + offset_in_page(eb->start); \
+ put_unaligned_le##bits(val, &p->member); \
+}
+
+#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
+static inline u##bits btrfs_##name(const type *s) \
+{ \
+ return get_unaligned_le##bits(&s->member); \
+} \
+static inline void btrfs_set_##name(type *s, u##bits val) \
+{ \
+ put_unaligned_le##bits(val, &s->member); \
+}
+
+static inline u64 btrfs_device_total_bytes(const struct extent_buffer *eb,
+ struct btrfs_dev_item *s)
+{
+ static_assert(sizeof(u64) ==
+ sizeof(((struct btrfs_dev_item *)0))->total_bytes);
+ return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item,
+ total_bytes));
+}
+static inline void btrfs_set_device_total_bytes(const struct extent_buffer *eb,
+ struct btrfs_dev_item *s,
+ u64 val)
+{
+ static_assert(sizeof(u64) ==
+ sizeof(((struct btrfs_dev_item *)0))->total_bytes);
+ WARN_ON(!IS_ALIGNED(val, eb->fs_info->sectorsize));
+ btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val);
+}
+
+BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64);
+BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64);
+BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32);
+BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);
+BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item, start_offset, 64);
+BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);
+BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
+BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);
+BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);
+BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);
+BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);
+
+BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
+ total_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,
+ bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,
+ io_align, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,
+ io_width, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,
+ sector_size, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item, dev_group, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,
+ seek_speed, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
+ bandwidth, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
+ generation, 64);
+
+static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d)
+{
+ return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid);
+}
+
+static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d)
+{
+ return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid);
+}
+
+BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
+BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);
+BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);
+BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32);
+BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);
+BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
+BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
+BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
+BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);
+BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
+BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);
+
+static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s)
+{
+ return (char *)s + offsetof(struct btrfs_stripe, dev_uuid);
+}
+
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk,
+ stripe_len, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk, io_align, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk, io_width, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,
+ sector_size, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
+ num_stripes, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,
+ sub_stripes, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);
+
+static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c, int nr)
+{
+ unsigned long offset = (unsigned long)c;
+
+ offset += offsetof(struct btrfs_chunk, stripe);
+ offset += nr * sizeof(struct btrfs_stripe);
+ return (struct btrfs_stripe *)offset;
+}
+
+static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr)
+{
+ return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr));
+}
+
+static inline u64 btrfs_stripe_offset_nr(const struct extent_buffer *eb,
+ struct btrfs_chunk *c, int nr)
+{
+ return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));
+}
+
+static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb,
+ struct btrfs_chunk *c, int nr,
+ u64 val)
+{
+ btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val);
+}
+
+static inline u64 btrfs_stripe_devid_nr(const struct extent_buffer *eb,
+ struct btrfs_chunk *c, int nr)
+{
+ return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));
+}
+
+static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb,
+ struct btrfs_chunk *c, int nr,
+ u64 val)
+{
+ btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val);
+}
+
+/* struct btrfs_block_group_item */
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_used, struct btrfs_block_group_item,
+ used, 64);
+BTRFS_SETGET_FUNCS(block_group_used, struct btrfs_block_group_item, used, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_chunk_objectid,
+ struct btrfs_block_group_item, chunk_objectid, 64);
+
+BTRFS_SETGET_FUNCS(block_group_chunk_objectid,
+ struct btrfs_block_group_item, chunk_objectid, 64);
+BTRFS_SETGET_FUNCS(block_group_flags, struct btrfs_block_group_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_flags,
+ struct btrfs_block_group_item, flags, 64);
+
+/* struct btrfs_free_space_info */
+BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info,
+ extent_count, 32);
+BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32);
+
+/* struct btrfs_inode_ref */
+BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
+BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_index, struct btrfs_inode_ref, index, 64);
+
+/* struct btrfs_inode_extref */
+BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref,
+ parent_objectid, 64);
+BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref,
+ name_len, 16);
+BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64);
+
+/* struct btrfs_inode_item */
+BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
+BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64);
+BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);
+BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
+BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64);
+BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
+BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);
+BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);
+BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
+BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
+BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
+BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
+ generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
+ sequence, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
+ transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item, nbytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
+ block_group, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
+BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
+BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
+
+/* struct btrfs_dev_extent */
+BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, chunk_tree, 64);
+BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent,
+ chunk_objectid, 64);
+BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,
+ chunk_offset, 64);
+BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_tree, struct btrfs_dev_extent,
+ chunk_tree, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_objectid, struct btrfs_dev_extent,
+ chunk_objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_offset, struct btrfs_dev_extent,
+ chunk_offset, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_length, struct btrfs_dev_extent, length, 64);
+
+BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);
+BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item, generation, 64);
+BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64);
+
+BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8);
+
+static inline void btrfs_tree_block_key(const struct extent_buffer *eb,
+ struct btrfs_tree_block_info *item,
+ struct btrfs_disk_key *key)
+{
+ read_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
+}
+
+static inline void btrfs_set_tree_block_key(const struct extent_buffer *eb,
+ struct btrfs_tree_block_info *item,
+ struct btrfs_disk_key *key)
+{
+ write_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
+}
+
+BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref, root, 64);
+BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref,
+ objectid, 64);
+BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref,
+ offset, 64);
+BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, count, 32);
+
+BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, count, 32);
+
+BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref,
+ type, 8);
+BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref,
+ offset, 64);
+
+static inline u32 btrfs_extent_inline_ref_size(int type)
+{
+ if (type == BTRFS_TREE_BLOCK_REF_KEY ||
+ type == BTRFS_SHARED_BLOCK_REF_KEY)
+ return sizeof(struct btrfs_extent_inline_ref);
+ if (type == BTRFS_SHARED_DATA_REF_KEY)
+ return sizeof(struct btrfs_shared_data_ref) +
+ sizeof(struct btrfs_extent_inline_ref);
+ if (type == BTRFS_EXTENT_DATA_REF_KEY)
+ return sizeof(struct btrfs_extent_data_ref) +
+ offsetof(struct btrfs_extent_inline_ref, offset);
+ return 0;
+}
+
+/* struct btrfs_node */
+BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
+BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr, blockptr, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr,
+ generation, 64);
+
+static inline u64 btrfs_node_blockptr(const struct extent_buffer *eb, int nr)
+{
+ unsigned long ptr;
+
+ ptr = offsetof(struct btrfs_node, ptrs) +
+ sizeof(struct btrfs_key_ptr) * nr;
+ return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr);
+}
+
+static inline void btrfs_set_node_blockptr(const struct extent_buffer *eb,
+ int nr, u64 val)
+{
+ unsigned long ptr;
+
+ ptr = offsetof(struct btrfs_node, ptrs) +
+ sizeof(struct btrfs_key_ptr) * nr;
+ btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
+}
+
+static inline u64 btrfs_node_ptr_generation(const struct extent_buffer *eb, int nr)
+{
+ unsigned long ptr;
+
+ ptr = offsetof(struct btrfs_node, ptrs) +
+ sizeof(struct btrfs_key_ptr) * nr;
+ return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);
+}
+
+static inline void btrfs_set_node_ptr_generation(const struct extent_buffer *eb,
+ int nr, u64 val)
+{
+ unsigned long ptr;
+
+ ptr = offsetof(struct btrfs_node, ptrs) +
+ sizeof(struct btrfs_key_ptr) * nr;
+ btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);
+}
+
+static inline unsigned long btrfs_node_key_ptr_offset(const struct extent_buffer *eb, int nr)
+{
+ return offsetof(struct btrfs_node, ptrs) +
+ sizeof(struct btrfs_key_ptr) * nr;
+}
+
+void btrfs_node_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr);
+
+static inline void btrfs_set_node_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr)
+{
+ unsigned long ptr;
+
+ ptr = btrfs_node_key_ptr_offset(eb, nr);
+ write_eb_member(eb, (struct btrfs_key_ptr *)ptr,
+ struct btrfs_key_ptr, key, disk_key);
+}
+
+/* struct btrfs_item */
+BTRFS_SETGET_FUNCS(raw_item_offset, struct btrfs_item, offset, 32);
+BTRFS_SETGET_FUNCS(raw_item_size, struct btrfs_item, size, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32);
+
+static inline unsigned long btrfs_item_nr_offset(const struct extent_buffer *eb, int nr)
+{
+ return offsetof(struct btrfs_leaf, items) +
+ sizeof(struct btrfs_item) * nr;
+}
+
+static inline struct btrfs_item *btrfs_item_nr(const struct extent_buffer *eb, int nr)
+{
+ return (struct btrfs_item *)btrfs_item_nr_offset(eb, nr);
+}
+
+#define BTRFS_ITEM_SETGET_FUNCS(member) \
+static inline u32 btrfs_item_##member(const struct extent_buffer *eb, int slot) \
+{ \
+ return btrfs_raw_item_##member(eb, btrfs_item_nr(eb, slot)); \
+} \
+static inline void btrfs_set_item_##member(const struct extent_buffer *eb, \
+ int slot, u32 val) \
+{ \
+ btrfs_set_raw_item_##member(eb, btrfs_item_nr(eb, slot), val); \
+} \
+static inline u32 btrfs_token_item_##member(struct btrfs_map_token *token, \
+ int slot) \
+{ \
+ struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \
+ return btrfs_token_raw_item_##member(token, item); \
+} \
+static inline void btrfs_set_token_item_##member(struct btrfs_map_token *token, \
+ int slot, u32 val) \
+{ \
+ struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \
+ btrfs_set_token_raw_item_##member(token, item, val); \
+}
+
+BTRFS_ITEM_SETGET_FUNCS(offset)
+BTRFS_ITEM_SETGET_FUNCS(size);
+
+static inline u32 btrfs_item_data_end(const struct extent_buffer *eb, int nr)
+{
+ return btrfs_item_offset(eb, nr) + btrfs_item_size(eb, nr);
+}
+
+static inline void btrfs_item_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr)
+{
+ struct btrfs_item *item = btrfs_item_nr(eb, nr);
+
+ read_eb_member(eb, item, struct btrfs_item, key, disk_key);
+}
+
+static inline void btrfs_set_item_key(struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr)
+{
+ struct btrfs_item *item = btrfs_item_nr(eb, nr);
+
+ write_eb_member(eb, item, struct btrfs_item, key, disk_key);
+}
+
+BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);
+
+/* struct btrfs_root_ref */
+BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
+BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
+BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
+
+/* struct btrfs_dir_item */
+BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
+BTRFS_SETGET_FUNCS(dir_flags, struct btrfs_dir_item, type, 8);
+BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
+BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_flags, struct btrfs_dir_item, type, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, data_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64);
+
+static inline u8 btrfs_dir_ftype(const struct extent_buffer *eb,
+ const struct btrfs_dir_item *item)
+{
+ return btrfs_dir_flags_to_ftype(btrfs_dir_flags(eb, item));
+}
+
+static inline u8 btrfs_stack_dir_ftype(const struct btrfs_dir_item *item)
+{
+ return btrfs_dir_flags_to_ftype(btrfs_stack_dir_flags(item));
+}
+
+static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
+ const struct btrfs_dir_item *item,
+ struct btrfs_disk_key *key)
+{
+ read_eb_member(eb, item, struct btrfs_dir_item, location, key);
+}
+
+static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
+ struct btrfs_dir_item *item,
+ const struct btrfs_disk_key *key)
+{
+ write_eb_member(eb, item, struct btrfs_dir_item, location, key);
+}
+
+BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header,
+ num_entries, 64);
+BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header,
+ num_bitmaps, 64);
+BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
+ generation, 64);
+
+static inline void btrfs_free_space_key(const struct extent_buffer *eb,
+ const struct btrfs_free_space_header *h,
+ struct btrfs_disk_key *key)
+{
+ read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+}
+
+static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
+ struct btrfs_free_space_header *h,
+ const struct btrfs_disk_key *key)
+{
+ write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+}
+
+/* struct btrfs_disk_key */
+BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);
+BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);
+
+#ifdef __LITTLE_ENDIAN
+
+/*
+ * Optimized helpers for little-endian architectures where CPU and on-disk
+ * structures have the same endianness and we can skip conversions.
+ */
+
+static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu_key,
+ const struct btrfs_disk_key *disk_key)
+{
+ memcpy(cpu_key, disk_key, sizeof(struct btrfs_key));
+}
+
+static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk_key,
+ const struct btrfs_key *cpu_key)
+{
+ memcpy(disk_key, cpu_key, sizeof(struct btrfs_key));
+}
+
+static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
+ struct btrfs_key *cpu_key, int nr)
+{
+ struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
+
+ btrfs_node_key(eb, disk_key, nr);
+}
+
+static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
+ struct btrfs_key *cpu_key, int nr)
+{
+ struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
+
+ btrfs_item_key(eb, disk_key, nr);
+}
+
+static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
+ const struct btrfs_dir_item *item,
+ struct btrfs_key *cpu_key)
+{
+ struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
+
+ btrfs_dir_item_key(eb, item, disk_key);
+}
+
+#else
+
+static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
+ const struct btrfs_disk_key *disk)
+{
+ cpu->offset = le64_to_cpu(disk->offset);
+ cpu->type = disk->type;
+ cpu->objectid = le64_to_cpu(disk->objectid);
+}
+
+static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,
+ const struct btrfs_key *cpu)
+{
+ disk->offset = cpu_to_le64(cpu->offset);
+ disk->type = cpu->type;
+ disk->objectid = cpu_to_le64(cpu->objectid);
+}
+
+static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
+ struct btrfs_key *key, int nr)
+{
+ struct btrfs_disk_key disk_key;
+
+ btrfs_node_key(eb, &disk_key, nr);
+ btrfs_disk_key_to_cpu(key, &disk_key);
+}
+
+static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
+ struct btrfs_key *key, int nr)
+{
+ struct btrfs_disk_key disk_key;
+
+ btrfs_item_key(eb, &disk_key, nr);
+ btrfs_disk_key_to_cpu(key, &disk_key);
+}
+
+static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
+ const struct btrfs_dir_item *item,
+ struct btrfs_key *key)
+{
+ struct btrfs_disk_key disk_key;
+
+ btrfs_dir_item_key(eb, item, &disk_key);
+ btrfs_disk_key_to_cpu(key, &disk_key);
+}
+
+#endif
+
+/* struct btrfs_header */
+BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
+BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, generation, 64);
+BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
+BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
+BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
+BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header,
+ generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, nritems, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
+
+static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag)
+{
+ return (btrfs_header_flags(eb) & flag) == flag;
+}
+
+static inline void btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)
+{
+ u64 flags = btrfs_header_flags(eb);
+
+ btrfs_set_header_flags(eb, flags | flag);
+}
+
+static inline void btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
+{
+ u64 flags = btrfs_header_flags(eb);
+
+ btrfs_set_header_flags(eb, flags & ~flag);
+}
+
+static inline int btrfs_header_backref_rev(const struct extent_buffer *eb)
+{
+ u64 flags = btrfs_header_flags(eb);
+
+ return flags >> BTRFS_BACKREF_REV_SHIFT;
+}
+
+static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb, int rev)
+{
+ u64 flags = btrfs_header_flags(eb);
+
+ flags &= ~BTRFS_BACKREF_REV_MASK;
+ flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT;
+ btrfs_set_header_flags(eb, flags);
+}
+
+static inline int btrfs_is_leaf(const struct extent_buffer *eb)
+{
+ return btrfs_header_level(eb) == 0;
+}
+
+/* struct btrfs_root_item */
+BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item, generation, 64);
+BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);
+BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);
+BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);
+BTRFS_SETGET_STACK_FUNCS(root_drop_level, struct btrfs_root_item, drop_level, 8);
+BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);
+BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);
+BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
+BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
+ last_snapshot, 64);
+BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
+ generation_v2, 64);
+BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item, ctransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item, otransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item, stransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, rtransid, 64);
+
+/* struct btrfs_root_backup */
+BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
+ tree_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup,
+ tree_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup,
+ tree_root_level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup,
+ chunk_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup,
+ chunk_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup,
+ chunk_root_level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup,
+ extent_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup,
+ extent_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup,
+ extent_root_level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup,
+ fs_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup,
+ fs_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup,
+ fs_root_level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup,
+ dev_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup,
+ dev_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup,
+ dev_root_level, 8);
+
+BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup,
+ csum_root, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup,
+ csum_root_gen, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup,
+ csum_root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup,
+ total_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup,
+ bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,
+ num_devices, 64);
+
+/* struct btrfs_balance_item */
+BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
+
+static inline void btrfs_balance_data(const struct extent_buffer *eb,
+ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+{
+ read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+}
+
+static inline void btrfs_set_balance_data(struct extent_buffer *eb,
+ struct btrfs_balance_item *bi,
+ const struct btrfs_disk_balance_args *ba)
+{
+ write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+}
+
+static inline void btrfs_balance_meta(const struct extent_buffer *eb,
+ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+{
+ read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+}
+
+static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
+ struct btrfs_balance_item *bi,
+ const struct btrfs_disk_balance_args *ba)
+{
+ write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+}
+
+static inline void btrfs_balance_sys(const struct extent_buffer *eb,
+ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+{
+ read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+}
+
+static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
+ struct btrfs_balance_item *bi,
+ const struct btrfs_disk_balance_args *ba)
+{
+ write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+}
+
+static inline void btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
+ const struct btrfs_disk_balance_args *disk)
+{
+ memset(cpu, 0, sizeof(*cpu));
+
+ cpu->profiles = le64_to_cpu(disk->profiles);
+ cpu->usage = le64_to_cpu(disk->usage);
+ cpu->devid = le64_to_cpu(disk->devid);
+ cpu->pstart = le64_to_cpu(disk->pstart);
+ cpu->pend = le64_to_cpu(disk->pend);
+ cpu->vstart = le64_to_cpu(disk->vstart);
+ cpu->vend = le64_to_cpu(disk->vend);
+ cpu->target = le64_to_cpu(disk->target);
+ cpu->flags = le64_to_cpu(disk->flags);
+ cpu->limit = le64_to_cpu(disk->limit);
+ cpu->stripes_min = le32_to_cpu(disk->stripes_min);
+ cpu->stripes_max = le32_to_cpu(disk->stripes_max);
+}
+
+static inline void btrfs_cpu_balance_args_to_disk(
+ struct btrfs_disk_balance_args *disk,
+ const struct btrfs_balance_args *cpu)
+{
+ memset(disk, 0, sizeof(*disk));
+
+ disk->profiles = cpu_to_le64(cpu->profiles);
+ disk->usage = cpu_to_le64(cpu->usage);
+ disk->devid = cpu_to_le64(cpu->devid);
+ disk->pstart = cpu_to_le64(cpu->pstart);
+ disk->pend = cpu_to_le64(cpu->pend);
+ disk->vstart = cpu_to_le64(cpu->vstart);
+ disk->vend = cpu_to_le64(cpu->vend);
+ disk->target = cpu_to_le64(cpu->target);
+ disk->flags = cpu_to_le64(cpu->flags);
+ disk->limit = cpu_to_le64(cpu->limit);
+ disk->stripes_min = cpu_to_le32(cpu->stripes_min);
+ disk->stripes_max = cpu_to_le32(cpu->stripes_max);
+}
+
+/* struct btrfs_super_block */
+BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
+BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
+ generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,
+ struct btrfs_super_block, sys_chunk_array_size, 32);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,
+ struct btrfs_super_block, chunk_root_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
+ root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
+ chunk_root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
+ chunk_root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block, log_root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
+ log_root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
+ total_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
+ bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,
+ sectorsize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
+ nodesize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
+ stripesize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
+ root_dir_objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
+ num_devices, 64);
+BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,
+ compat_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,
+ compat_ro_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,
+ incompat_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
+ csum_type, 16);
+BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
+ cache_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
+BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
+ uuid_tree_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
+ nr_global_roots, 64);
+
+/* struct btrfs_file_extent_item */
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
+ type, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
+ struct btrfs_file_extent_item, disk_bytenr, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset,
+ struct btrfs_file_extent_item, offset, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation,
+ struct btrfs_file_extent_item, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes,
+ struct btrfs_file_extent_item, num_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes,
+ struct btrfs_file_extent_item, ram_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes,
+ struct btrfs_file_extent_item, disk_num_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
+ struct btrfs_file_extent_item, compression, 8);
+
+
+BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
+BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
+ disk_bytenr, 64);
+BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
+ generation, 64);
+BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
+ disk_num_bytes, 64);
+BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
+ offset, 64);
+BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
+ num_bytes, 64);
+BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
+ ram_bytes, 64);
+BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
+ compression, 8);
+BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
+ encryption, 8);
+BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
+ other_encoding, 16);
+
+/* btrfs_qgroup_status_item */
+BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
+ generation, 64);
+BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item,
+ version, 64);
+BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item,
+ flags, 64);
+BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item,
+ rescan, 64);
+
+/* btrfs_qgroup_info_item */
+BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item,
+ generation, 64);
+BTRFS_SETGET_FUNCS(qgroup_info_rfer, struct btrfs_qgroup_info_item, rfer, 64);
+BTRFS_SETGET_FUNCS(qgroup_info_rfer_cmpr, struct btrfs_qgroup_info_item,
+ rfer_cmpr, 64);
+BTRFS_SETGET_FUNCS(qgroup_info_excl, struct btrfs_qgroup_info_item, excl, 64);
+BTRFS_SETGET_FUNCS(qgroup_info_excl_cmpr, struct btrfs_qgroup_info_item,
+ excl_cmpr, 64);
+
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation,
+ struct btrfs_qgroup_info_item, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer, struct btrfs_qgroup_info_item,
+ rfer, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer_cmpr,
+ struct btrfs_qgroup_info_item, rfer_cmpr, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl, struct btrfs_qgroup_info_item,
+ excl, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl_cmpr,
+ struct btrfs_qgroup_info_item, excl_cmpr, 64);
+
+/* btrfs_qgroup_limit_item */
+BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item, flags, 64);
+BTRFS_SETGET_FUNCS(qgroup_limit_max_rfer, struct btrfs_qgroup_limit_item,
+ max_rfer, 64);
+BTRFS_SETGET_FUNCS(qgroup_limit_max_excl, struct btrfs_qgroup_limit_item,
+ max_excl, 64);
+BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item,
+ rsv_rfer, 64);
+BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item,
+ rsv_excl, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags,
+ struct btrfs_qgroup_limit_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_rfer,
+ struct btrfs_qgroup_limit_item, max_rfer, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_excl,
+ struct btrfs_qgroup_limit_item, max_excl, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_rfer,
+ struct btrfs_qgroup_limit_item, rsv_rfer, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_excl,
+ struct btrfs_qgroup_limit_item, rsv_excl, 64);
+
+/* btrfs_dev_replace_item */
+BTRFS_SETGET_FUNCS(dev_replace_src_devid,
+ struct btrfs_dev_replace_item, src_devid, 64);
+BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode,
+ struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode,
+ 64);
+BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item,
+ replace_state, 64);
+BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item,
+ time_started, 64);
+BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item,
+ time_stopped, 64);
+BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item,
+ num_write_errors, 64);
+BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors,
+ struct btrfs_dev_replace_item, num_uncorrectable_read_errors,
+ 64);
+BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item,
+ cursor_left, 64);
+BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item,
+ cursor_right, 64);
+
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid,
+ struct btrfs_dev_replace_item, src_devid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode,
+ struct btrfs_dev_replace_item,
+ cont_reading_from_srcdev_mode, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state,
+ struct btrfs_dev_replace_item, replace_state, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started,
+ struct btrfs_dev_replace_item, time_started, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped,
+ struct btrfs_dev_replace_item, time_stopped, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors,
+ struct btrfs_dev_replace_item, num_write_errors, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors,
+ struct btrfs_dev_replace_item,
+ num_uncorrectable_read_errors, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left,
+ struct btrfs_dev_replace_item, cursor_left, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
+ struct btrfs_dev_replace_item, cursor_right, 64);
+
+/* btrfs_verity_descriptor_item */
+BTRFS_SETGET_FUNCS(verity_descriptor_encryption, struct btrfs_verity_descriptor_item,
+ encryption, 8);
+BTRFS_SETGET_FUNCS(verity_descriptor_size, struct btrfs_verity_descriptor_item,
+ size, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_encryption,
+ struct btrfs_verity_descriptor_item, encryption, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_size,
+ struct btrfs_verity_descriptor_item, size, 64);
+
+/* Cast into the data area of the leaf. */
+#define btrfs_item_ptr(leaf, slot, type) \
+ ((type *)(btrfs_item_nr_offset(leaf, 0) + btrfs_item_offset(leaf, slot)))
+
+#define btrfs_item_ptr_offset(leaf, slot) \
+ ((unsigned long)(btrfs_item_nr_offset(leaf, 0) + btrfs_item_offset(leaf, slot)))
+
+#endif
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 548d6a5477b4..3da1779e8b79 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -11,10 +11,10 @@
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/slab.h>
-
#include "ctree.h"
#include "btrfs_inode.h"
#include "xattr.h"
+#include "acl.h"
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
{
@@ -110,10 +110,11 @@ out:
return ret;
}
-int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int btrfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int ret;
+ struct inode *inode = d_inode(dentry);
umode_t old_mode = inode->i_mode;
if (type == ACL_TYPE_ACCESS && acl) {
diff --git a/fs/btrfs/acl.h b/fs/btrfs/acl.h
new file mode 100644
index 000000000000..39bd36e6eeb7
--- /dev/null
+++ b/fs/btrfs/acl.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_ACL_H
+#define BTRFS_ACL_H
+
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+
+struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
+int btrfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type);
+int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
+ struct posix_acl *acl, int type);
+
+#else
+
+#define btrfs_get_acl NULL
+#define btrfs_set_acl NULL
+static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
+ struct inode *inode, struct posix_acl *acl,
+ int type)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 18374a6d05bd..21c92c74bf71 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -15,49 +15,76 @@
#include "locking.h"
#include "misc.h"
#include "tree-mod-log.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "relocation.h"
+#include "tree-checker.h"
-/* Just an arbitrary number so we can be sure this happened */
-#define BACKREF_FOUND_SHARED 6
+/* Just arbitrary numbers so we can be sure one of these happened. */
+#define BACKREF_FOUND_SHARED 6
+#define BACKREF_FOUND_NOT_SHARED 7
struct extent_inode_elem {
u64 inum;
u64 offset;
+ u64 num_bytes;
struct extent_inode_elem *next;
};
-static int check_extent_in_eb(const struct btrfs_key *key,
+static int check_extent_in_eb(struct btrfs_backref_walk_ctx *ctx,
+ const struct btrfs_key *key,
const struct extent_buffer *eb,
const struct btrfs_file_extent_item *fi,
- u64 extent_item_pos,
- struct extent_inode_elem **eie,
- bool ignore_offset)
+ struct extent_inode_elem **eie)
{
- u64 offset = 0;
+ const u64 data_len = btrfs_file_extent_num_bytes(eb, fi);
+ u64 offset = key->offset;
struct extent_inode_elem *e;
+ const u64 *root_ids;
+ int root_count;
+ bool cached;
- if (!ignore_offset &&
- !btrfs_file_extent_compression(eb, fi) &&
+ if (!btrfs_file_extent_compression(eb, fi) &&
!btrfs_file_extent_encryption(eb, fi) &&
!btrfs_file_extent_other_encoding(eb, fi)) {
u64 data_offset;
- u64 data_len;
data_offset = btrfs_file_extent_offset(eb, fi);
- data_len = btrfs_file_extent_num_bytes(eb, fi);
- if (extent_item_pos < data_offset ||
- extent_item_pos >= data_offset + data_len)
+ if (ctx->extent_item_pos < data_offset ||
+ ctx->extent_item_pos >= data_offset + data_len)
return 1;
- offset = extent_item_pos - data_offset;
+ offset += ctx->extent_item_pos - data_offset;
}
+ if (!ctx->indirect_ref_iterator || !ctx->cache_lookup)
+ goto add_inode_elem;
+
+ cached = ctx->cache_lookup(eb->start, ctx->user_ctx, &root_ids,
+ &root_count);
+ if (!cached)
+ goto add_inode_elem;
+
+ for (int i = 0; i < root_count; i++) {
+ int ret;
+
+ ret = ctx->indirect_ref_iterator(key->objectid, offset,
+ data_len, root_ids[i],
+ ctx->user_ctx);
+ if (ret)
+ return ret;
+ }
+
+add_inode_elem:
e = kmalloc(sizeof(*e), GFP_NOFS);
if (!e)
return -ENOMEM;
e->next = *eie;
e->inum = key->objectid;
- e->offset = key->offset + offset;
+ e->offset = offset;
+ e->num_bytes = data_len;
*eie = e;
return 0;
@@ -73,10 +100,9 @@ static void free_inode_elem_list(struct extent_inode_elem *eie)
}
}
-static int find_extent_in_eb(const struct extent_buffer *eb,
- u64 wanted_disk_byte, u64 extent_item_pos,
- struct extent_inode_elem **eie,
- bool ignore_offset)
+static int find_extent_in_eb(struct btrfs_backref_walk_ctx *ctx,
+ const struct extent_buffer *eb,
+ struct extent_inode_elem **eie)
{
u64 disk_byte;
struct btrfs_key key;
@@ -102,11 +128,11 @@ static int find_extent_in_eb(const struct extent_buffer *eb,
continue;
/* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */
disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
- if (disk_byte != wanted_disk_byte)
+ if (disk_byte != ctx->bytenr)
continue;
- ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie, ignore_offset);
- if (ret < 0)
+ ret = check_extent_in_eb(ctx, &key, eb, fi, eie);
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP || ret < 0)
return ret;
}
@@ -135,9 +161,29 @@ struct preftrees {
* - decremented when a ref->count transitions to <1
*/
struct share_check {
- u64 root_objectid;
+ struct btrfs_backref_share_check_ctx *ctx;
+ struct btrfs_root *root;
u64 inum;
+ u64 data_bytenr;
+ u64 data_extent_gen;
+ /*
+ * Counts number of inodes that refer to an extent (different inodes in
+ * the same root or different roots) that we could find. The sharedness
+ * check typically stops once this counter gets greater than 1, so it
+ * may not reflect the total number of inodes.
+ */
int share_count;
+ /*
+ * The number of times we found our inode refers to the data extent we
+ * are determining the sharedness. In other words, how many file extent
+ * items we could find for our inode that point to our target data
+ * extent. The value we get here after finishing the extent sharedness
+ * check may be smaller than reality, but if it ends up being greater
+ * than 1, then we know for sure the inode has multiple file extent
+ * items that point to our inode, and we can safely assume it's useful
+ * to cache the sharedness check result.
+ */
+ int self_ref_count;
bool have_delayed_delete_refs;
};
@@ -207,7 +253,7 @@ static int prelim_ref_compare(struct prelim_ref *ref1,
}
static void update_share_count(struct share_check *sc, int oldcount,
- int newcount)
+ int newcount, struct prelim_ref *newref)
{
if ((!sc) || (oldcount == 0 && newcount < 1))
return;
@@ -216,6 +262,11 @@ static void update_share_count(struct share_check *sc, int oldcount,
sc->share_count--;
else if (oldcount < 1 && newcount > 0)
sc->share_count++;
+
+ if (newref->root_id == sc->root->root_key.objectid &&
+ newref->wanted_disk_byte == sc->data_bytenr &&
+ newref->key_for_search.objectid == sc->inum)
+ sc->self_ref_count += newref->count;
}
/*
@@ -266,14 +317,14 @@ static void prelim_ref_insert(const struct btrfs_fs_info *fs_info,
* BTRFS_[ADD|DROP]_DELAYED_REF actions.
*/
update_share_count(sc, ref->count,
- ref->count + newref->count);
+ ref->count + newref->count, newref);
ref->count += newref->count;
free_pref(newref);
return;
}
}
- update_share_count(sc, 0, newref->count);
+ update_share_count(sc, 0, newref->count, newref);
preftree->count++;
trace_btrfs_prelim_ref_insert(fs_info, newref, NULL, preftree->count);
rb_link_node(&newref->rbnode, parent, p);
@@ -416,11 +467,11 @@ static int is_shared_data_backref(struct preftrees *preftrees, u64 bytenr)
return 0;
}
-static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
+static int add_all_parents(struct btrfs_backref_walk_ctx *ctx,
+ struct btrfs_root *root, struct btrfs_path *path,
struct ulist *parents,
struct preftrees *preftrees, struct prelim_ref *ref,
- int level, u64 time_seq, const u64 *extent_item_pos,
- bool ignore_offset)
+ int level)
{
int ret = 0;
int slot;
@@ -456,10 +507,10 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
if (path->slots[0] >= btrfs_header_nritems(eb) ||
is_shared_data_backref(preftrees, eb->start) ||
ref->root_id != btrfs_header_owner(eb)) {
- if (time_seq == BTRFS_SEQ_LAST)
+ if (ctx->time_seq == BTRFS_SEQ_LAST)
ret = btrfs_next_leaf(root, path);
else
- ret = btrfs_next_old_leaf(root, path, time_seq);
+ ret = btrfs_next_old_leaf(root, path, ctx->time_seq);
}
while (!ret && count < ref->count) {
@@ -480,10 +531,10 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
if (slot == 0 &&
(is_shared_data_backref(preftrees, eb->start) ||
ref->root_id != btrfs_header_owner(eb))) {
- if (time_seq == BTRFS_SEQ_LAST)
+ if (ctx->time_seq == BTRFS_SEQ_LAST)
ret = btrfs_next_leaf(root, path);
else
- ret = btrfs_next_old_leaf(root, path, time_seq);
+ ret = btrfs_next_old_leaf(root, path, ctx->time_seq);
continue;
}
fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
@@ -497,11 +548,10 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
count++;
else
goto next;
- if (extent_item_pos) {
- ret = check_extent_in_eb(&key, eb, fi,
- *extent_item_pos,
- &eie, ignore_offset);
- if (ret < 0)
+ if (!ctx->ignore_extent_item_pos) {
+ ret = check_extent_in_eb(ctx, &key, eb, fi, &eie);
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP ||
+ ret < 0)
break;
}
if (ret > 0)
@@ -510,7 +560,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
eie, (void **)&old, GFP_NOFS);
if (ret < 0)
break;
- if (!ret && extent_item_pos) {
+ if (!ret && !ctx->ignore_extent_item_pos) {
while (old->next)
old = old->next;
old->next = eie;
@@ -518,16 +568,17 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
eie = NULL;
}
next:
- if (time_seq == BTRFS_SEQ_LAST)
+ if (ctx->time_seq == BTRFS_SEQ_LAST)
ret = btrfs_next_item(root, path);
else
- ret = btrfs_next_old_item(root, path, time_seq);
+ ret = btrfs_next_old_item(root, path, ctx->time_seq);
}
- if (ret > 0)
- ret = 0;
- else if (ret < 0)
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP || ret < 0)
free_inode_elem_list(eie);
+ else if (ret > 0)
+ ret = 0;
+
return ret;
}
@@ -535,11 +586,10 @@ next:
* resolve an indirect backref in the form (root_id, key, level)
* to a logical address
*/
-static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path, u64 time_seq,
+static int resolve_indirect_ref(struct btrfs_backref_walk_ctx *ctx,
+ struct btrfs_path *path,
struct preftrees *preftrees,
- struct prelim_ref *ref, struct ulist *parents,
- const u64 *extent_item_pos, bool ignore_offset)
+ struct prelim_ref *ref, struct ulist *parents)
{
struct btrfs_root *root;
struct extent_buffer *eb;
@@ -557,9 +607,9 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
* here.
*/
if (path->search_commit_root)
- root = btrfs_get_fs_root_commit_root(fs_info, path, ref->root_id);
+ root = btrfs_get_fs_root_commit_root(ctx->fs_info, path, ref->root_id);
else
- root = btrfs_get_fs_root(fs_info, ref->root_id, false);
+ root = btrfs_get_fs_root(ctx->fs_info, ref->root_id, false);
if (IS_ERR(root)) {
ret = PTR_ERR(root);
goto out_free;
@@ -571,17 +621,17 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
goto out;
}
- if (btrfs_is_testing(fs_info)) {
+ if (btrfs_is_testing(ctx->fs_info)) {
ret = -ENOENT;
goto out;
}
if (path->search_commit_root)
root_level = btrfs_header_level(root->commit_root);
- else if (time_seq == BTRFS_SEQ_LAST)
+ else if (ctx->time_seq == BTRFS_SEQ_LAST)
root_level = btrfs_header_level(root->node);
else
- root_level = btrfs_old_root_level(root, time_seq);
+ root_level = btrfs_old_root_level(root, ctx->time_seq);
if (root_level + 1 == level)
goto out;
@@ -609,12 +659,12 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
search_key.offset >= LLONG_MAX)
search_key.offset = 0;
path->lowest_level = level;
- if (time_seq == BTRFS_SEQ_LAST)
+ if (ctx->time_seq == BTRFS_SEQ_LAST)
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
else
- ret = btrfs_search_old_slot(root, &search_key, path, time_seq);
+ ret = btrfs_search_old_slot(root, &search_key, path, ctx->time_seq);
- btrfs_debug(fs_info,
+ btrfs_debug(ctx->fs_info,
"search slot in root %llu (level %d, ref count %d) returned %d for key (%llu %u %llu)",
ref->root_id, level, ref->count, ret,
ref->key_for_search.objectid, ref->key_for_search.type,
@@ -632,8 +682,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
eb = path->nodes[level];
}
- ret = add_all_parents(root, path, parents, preftrees, ref, level,
- time_seq, extent_item_pos, ignore_offset);
+ ret = add_all_parents(ctx, root, path, parents, preftrees, ref, level);
out:
btrfs_put_root(root);
out_free:
@@ -678,11 +727,10 @@ static void free_leaf_list(struct ulist *ulist)
* rbtree as they are encountered. The new backrefs are subsequently
* resolved as above.
*/
-static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path, u64 time_seq,
+static int resolve_indirect_refs(struct btrfs_backref_walk_ctx *ctx,
+ struct btrfs_path *path,
struct preftrees *preftrees,
- const u64 *extent_item_pos,
- struct share_check *sc, bool ignore_offset)
+ struct share_check *sc)
{
int err;
int ret = 0;
@@ -719,21 +767,18 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
continue;
}
- if (sc && sc->root_objectid &&
- ref->root_id != sc->root_objectid) {
+ if (sc && ref->root_id != sc->root->root_key.objectid) {
free_pref(ref);
ret = BACKREF_FOUND_SHARED;
goto out;
}
- err = resolve_indirect_ref(fs_info, path, time_seq, preftrees,
- ref, parents, extent_item_pos,
- ignore_offset);
+ err = resolve_indirect_ref(ctx, path, preftrees, ref, parents);
/*
* we can only tolerate ENOENT,otherwise,we should catch error
* and return directly.
*/
if (err == -ENOENT) {
- prelim_ref_insert(fs_info, &preftrees->direct, ref,
+ prelim_ref_insert(ctx->fs_info, &preftrees->direct, ref,
NULL);
continue;
} else if (err) {
@@ -762,7 +807,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
memcpy(new_ref, ref, sizeof(*ref));
new_ref->parent = node->val;
new_ref->inode_list = unode_aux_to_inode_list(node);
- prelim_ref_insert(fs_info, &preftrees->direct,
+ prelim_ref_insert(ctx->fs_info, &preftrees->direct,
new_ref, NULL);
}
@@ -770,7 +815,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
* Now it's a direct ref, put it in the direct tree. We must
* do this last because the ref could be merged/freed here.
*/
- prelim_ref_insert(fs_info, &preftrees->direct, ref, NULL);
+ prelim_ref_insert(ctx->fs_info, &preftrees->direct, ref, NULL);
ulist_reinit(parents);
cond_resched();
@@ -796,6 +841,8 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
struct rb_node *node;
while ((node = rb_first_cached(&tree->root))) {
+ struct btrfs_tree_parent_check check = { 0 };
+
ref = rb_entry(node, struct prelim_ref, rbnode);
rb_erase_cached(node, &tree->root);
@@ -803,8 +850,10 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
BUG_ON(ref->key_for_search.type);
BUG_ON(!ref->wanted_disk_byte);
- eb = read_tree_block(fs_info, ref->wanted_disk_byte,
- ref->root_id, 0, ref->level - 1, NULL);
+ check.level = ref->level - 1;
+ check.owner_root = ref->root_id;
+
+ eb = read_tree_block(fs_info, ref->wanted_disk_byte, &check);
if (IS_ERR(eb)) {
free_pref(ref);
return PTR_ERR(eb);
@@ -959,8 +1008,8 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
*
* Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
*/
-static int add_inline_refs(const struct btrfs_fs_info *fs_info,
- struct btrfs_path *path, u64 bytenr,
+static int add_inline_refs(struct btrfs_backref_walk_ctx *ctx,
+ struct btrfs_path *path,
int *info_level, struct preftrees *preftrees,
struct share_check *sc)
{
@@ -985,6 +1034,13 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
BUG_ON(item_size < sizeof(*ei));
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
+
+ if (ctx->check_extent_item) {
+ ret = ctx->check_extent_item(ctx->bytenr, ei, leaf, ctx->user_ctx);
+ if (ret)
+ return ret;
+ }
+
flags = btrfs_extent_flags(leaf, ei);
btrfs_item_key_to_cpu(leaf, &found_key, slot);
@@ -1020,9 +1076,9 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
switch (type) {
case BTRFS_SHARED_BLOCK_REF_KEY:
- ret = add_direct_ref(fs_info, preftrees,
+ ret = add_direct_ref(ctx->fs_info, preftrees,
*info_level + 1, offset,
- bytenr, 1, NULL, GFP_NOFS);
+ ctx->bytenr, 1, NULL, GFP_NOFS);
break;
case BTRFS_SHARED_DATA_REF_KEY: {
struct btrfs_shared_data_ref *sdref;
@@ -1031,14 +1087,14 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
sdref = (struct btrfs_shared_data_ref *)(iref + 1);
count = btrfs_shared_data_ref_count(leaf, sdref);
- ret = add_direct_ref(fs_info, preftrees, 0, offset,
- bytenr, count, sc, GFP_NOFS);
+ ret = add_direct_ref(ctx->fs_info, preftrees, 0, offset,
+ ctx->bytenr, count, sc, GFP_NOFS);
break;
}
case BTRFS_TREE_BLOCK_REF_KEY:
- ret = add_indirect_ref(fs_info, preftrees, offset,
+ ret = add_indirect_ref(ctx->fs_info, preftrees, offset,
NULL, *info_level + 1,
- bytenr, 1, NULL, GFP_NOFS);
+ ctx->bytenr, 1, NULL, GFP_NOFS);
break;
case BTRFS_EXTENT_DATA_REF_KEY: {
struct btrfs_extent_data_ref *dref;
@@ -1052,7 +1108,7 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = btrfs_extent_data_ref_offset(leaf, dref);
- if (sc && sc->inum && key.objectid != sc->inum &&
+ if (sc && key.objectid != sc->inum &&
!sc->have_delayed_delete_refs) {
ret = BACKREF_FOUND_SHARED;
break;
@@ -1060,10 +1116,12 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
root = btrfs_extent_data_ref_root(leaf, dref);
- ret = add_indirect_ref(fs_info, preftrees, root,
- &key, 0, bytenr, count,
- sc, GFP_NOFS);
-
+ if (!ctx->skip_data_ref ||
+ !ctx->skip_data_ref(root, key.objectid, key.offset,
+ ctx->user_ctx))
+ ret = add_indirect_ref(ctx->fs_info, preftrees,
+ root, &key, 0, ctx->bytenr,
+ count, sc, GFP_NOFS);
break;
}
default:
@@ -1082,8 +1140,9 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
*
* Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
*/
-static int add_keyed_refs(struct btrfs_root *extent_root,
- struct btrfs_path *path, u64 bytenr,
+static int add_keyed_refs(struct btrfs_backref_walk_ctx *ctx,
+ struct btrfs_root *extent_root,
+ struct btrfs_path *path,
int info_level, struct preftrees *preftrees,
struct share_check *sc)
{
@@ -1106,7 +1165,7 @@ static int add_keyed_refs(struct btrfs_root *extent_root,
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, slot);
- if (key.objectid != bytenr)
+ if (key.objectid != ctx->bytenr)
break;
if (key.type < BTRFS_TREE_BLOCK_REF_KEY)
continue;
@@ -1118,7 +1177,7 @@ static int add_keyed_refs(struct btrfs_root *extent_root,
/* SHARED DIRECT METADATA backref */
ret = add_direct_ref(fs_info, preftrees,
info_level + 1, key.offset,
- bytenr, 1, NULL, GFP_NOFS);
+ ctx->bytenr, 1, NULL, GFP_NOFS);
break;
case BTRFS_SHARED_DATA_REF_KEY: {
/* SHARED DIRECT FULL backref */
@@ -1129,14 +1188,14 @@ static int add_keyed_refs(struct btrfs_root *extent_root,
struct btrfs_shared_data_ref);
count = btrfs_shared_data_ref_count(leaf, sdref);
ret = add_direct_ref(fs_info, preftrees, 0,
- key.offset, bytenr, count,
+ key.offset, ctx->bytenr, count,
sc, GFP_NOFS);
break;
}
case BTRFS_TREE_BLOCK_REF_KEY:
/* NORMAL INDIRECT METADATA backref */
ret = add_indirect_ref(fs_info, preftrees, key.offset,
- NULL, info_level + 1, bytenr,
+ NULL, info_level + 1, ctx->bytenr,
1, NULL, GFP_NOFS);
break;
case BTRFS_EXTENT_DATA_REF_KEY: {
@@ -1153,16 +1212,20 @@ static int add_keyed_refs(struct btrfs_root *extent_root,
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = btrfs_extent_data_ref_offset(leaf, dref);
- if (sc && sc->inum && key.objectid != sc->inum &&
+ if (sc && key.objectid != sc->inum &&
!sc->have_delayed_delete_refs) {
ret = BACKREF_FOUND_SHARED;
break;
}
root = btrfs_extent_data_ref_root(leaf, dref);
- ret = add_indirect_ref(fs_info, preftrees, root,
- &key, 0, bytenr, count,
- sc, GFP_NOFS);
+
+ if (!ctx->skip_data_ref ||
+ !ctx->skip_data_ref(root, key.objectid, key.offset,
+ ctx->user_ctx))
+ ret = add_indirect_ref(fs_info, preftrees, root,
+ &key, 0, ctx->bytenr,
+ count, sc, GFP_NOFS);
break;
}
default:
@@ -1177,34 +1240,141 @@ static int add_keyed_refs(struct btrfs_root *extent_root,
}
/*
+ * The caller has joined a transaction or is holding a read lock on the
+ * fs_info->commit_root_sem semaphore, so no need to worry about the root's last
+ * snapshot field changing while updating or checking the cache.
+ */
+static bool lookup_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx,
+ struct btrfs_root *root,
+ u64 bytenr, int level, bool *is_shared)
+{
+ struct btrfs_backref_shared_cache_entry *entry;
+
+ if (!ctx->use_path_cache)
+ return false;
+
+ if (WARN_ON_ONCE(level >= BTRFS_MAX_LEVEL))
+ return false;
+
+ /*
+ * Level -1 is used for the data extent, which is not reliable to cache
+ * because its reference count can increase or decrease without us
+ * realizing. We cache results only for extent buffers that lead from
+ * the root node down to the leaf with the file extent item.
+ */
+ ASSERT(level >= 0);
+
+ entry = &ctx->path_cache_entries[level];
+
+ /* Unused cache entry or being used for some other extent buffer. */
+ if (entry->bytenr != bytenr)
+ return false;
+
+ /*
+ * We cached a false result, but the last snapshot generation of the
+ * root changed, so we now have a snapshot. Don't trust the result.
+ */
+ if (!entry->is_shared &&
+ entry->gen != btrfs_root_last_snapshot(&root->root_item))
+ return false;
+
+ /*
+ * If we cached a true result and the last generation used for dropping
+ * a root changed, we can not trust the result, because the dropped root
+ * could be a snapshot sharing this extent buffer.
+ */
+ if (entry->is_shared &&
+ entry->gen != btrfs_get_last_root_drop_gen(root->fs_info))
+ return false;
+
+ *is_shared = entry->is_shared;
+ /*
+ * If the node at this level is shared, than all nodes below are also
+ * shared. Currently some of the nodes below may be marked as not shared
+ * because we have just switched from one leaf to another, and switched
+ * also other nodes above the leaf and below the current level, so mark
+ * them as shared.
+ */
+ if (*is_shared) {
+ for (int i = 0; i < level; i++) {
+ ctx->path_cache_entries[i].is_shared = true;
+ ctx->path_cache_entries[i].gen = entry->gen;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * The caller has joined a transaction or is holding a read lock on the
+ * fs_info->commit_root_sem semaphore, so no need to worry about the root's last
+ * snapshot field changing while updating or checking the cache.
+ */
+static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx,
+ struct btrfs_root *root,
+ u64 bytenr, int level, bool is_shared)
+{
+ struct btrfs_backref_shared_cache_entry *entry;
+ u64 gen;
+
+ if (!ctx->use_path_cache)
+ return;
+
+ if (WARN_ON_ONCE(level >= BTRFS_MAX_LEVEL))
+ return;
+
+ /*
+ * Level -1 is used for the data extent, which is not reliable to cache
+ * because its reference count can increase or decrease without us
+ * realizing. We cache results only for extent buffers that lead from
+ * the root node down to the leaf with the file extent item.
+ */
+ ASSERT(level >= 0);
+
+ if (is_shared)
+ gen = btrfs_get_last_root_drop_gen(root->fs_info);
+ else
+ gen = btrfs_root_last_snapshot(&root->root_item);
+
+ entry = &ctx->path_cache_entries[level];
+ entry->bytenr = bytenr;
+ entry->is_shared = is_shared;
+ entry->gen = gen;
+
+ /*
+ * If we found an extent buffer is shared, set the cache result for all
+ * extent buffers below it to true. As nodes in the path are COWed,
+ * their sharedness is moved to their children, and if a leaf is COWed,
+ * then the sharedness of a data extent becomes direct, the refcount of
+ * data extent is increased in the extent item at the extent tree.
+ */
+ if (is_shared) {
+ for (int i = 0; i < level; i++) {
+ entry = &ctx->path_cache_entries[i];
+ entry->is_shared = is_shared;
+ entry->gen = gen;
+ }
+ }
+}
+
+/*
* this adds all existing backrefs (inline backrefs, backrefs and delayed
* refs) for the given bytenr to the refs list, merges duplicates and resolves
* indirect refs to their parent bytenr.
* When roots are found, they're added to the roots list
*
- * If time_seq is set to BTRFS_SEQ_LAST, it will not search delayed_refs, and
- * behave much like trans == NULL case, the difference only lies in it will not
- * commit root.
- * The special case is for qgroup to search roots in commit_transaction().
- *
- * @sc - if !NULL, then immediately return BACKREF_FOUND_SHARED when a
- * shared extent is detected.
+ * @ctx: Backref walking context object, must be not NULL.
+ * @sc: If !NULL, then immediately return BACKREF_FOUND_SHARED when a
+ * shared extent is detected.
*
* Otherwise this returns 0 for success and <0 for an error.
*
- * If ignore_offset is set to false, only extent refs whose offsets match
- * extent_item_pos are returned. If true, every extent ref is returned
- * and extent_item_pos is ignored.
- *
* FIXME some caching might speed things up
*/
-static int find_parent_nodes(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist *refs,
- struct ulist *roots, const u64 *extent_item_pos,
- struct share_check *sc, bool ignore_offset)
+static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
+ struct share_check *sc)
{
- struct btrfs_root *root = btrfs_extent_root(fs_info, bytenr);
+ struct btrfs_root *root = btrfs_extent_root(ctx->fs_info, ctx->bytenr);
struct btrfs_key key;
struct btrfs_path *path;
struct btrfs_delayed_ref_root *delayed_refs = NULL;
@@ -1220,9 +1390,13 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
.indirect_missing_keys = PREFTREE_INIT
};
- key.objectid = bytenr;
+ /* Roots ulist is not needed when using a sharedness check context. */
+ if (sc)
+ ASSERT(ctx->roots == NULL);
+
+ key.objectid = ctx->bytenr;
key.offset = (u64)-1;
- if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
+ if (btrfs_fs_incompat(ctx->fs_info, SKINNY_METADATA))
key.type = BTRFS_METADATA_ITEM_KEY;
else
key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -1230,12 +1404,12 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- if (!trans) {
+ if (!ctx->trans) {
path->search_commit_root = 1;
path->skip_locking = 1;
}
- if (time_seq == BTRFS_SEQ_LAST)
+ if (ctx->time_seq == BTRFS_SEQ_LAST)
path->skip_locking = 1;
again:
@@ -1251,17 +1425,17 @@ again:
goto out;
}
- if (trans && likely(trans->type != __TRANS_DUMMY) &&
- time_seq != BTRFS_SEQ_LAST) {
+ if (ctx->trans && likely(ctx->trans->type != __TRANS_DUMMY) &&
+ ctx->time_seq != BTRFS_SEQ_LAST) {
/*
* We have a specific time_seq we care about and trans which
* means we have the path lock, we need to grab the ref head and
* lock it so we have a consistent view of the refs at the given
* time.
*/
- delayed_refs = &trans->transaction->delayed_refs;
+ delayed_refs = &ctx->trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock);
- head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
+ head = btrfs_find_delayed_ref_head(delayed_refs, ctx->bytenr);
if (head) {
if (!mutex_trylock(&head->mutex)) {
refcount_inc(&head->refs);
@@ -1279,7 +1453,7 @@ again:
goto again;
}
spin_unlock(&delayed_refs->lock);
- ret = add_delayed_refs(fs_info, head, time_seq,
+ ret = add_delayed_refs(ctx->fs_info, head, ctx->time_seq,
&preftrees, sc);
mutex_unlock(&head->mutex);
if (ret)
@@ -1297,30 +1471,96 @@ again:
leaf = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(leaf, &key, slot);
- if (key.objectid == bytenr &&
+ if (key.objectid == ctx->bytenr &&
(key.type == BTRFS_EXTENT_ITEM_KEY ||
key.type == BTRFS_METADATA_ITEM_KEY)) {
- ret = add_inline_refs(fs_info, path, bytenr,
- &info_level, &preftrees, sc);
+ ret = add_inline_refs(ctx, path, &info_level,
+ &preftrees, sc);
if (ret)
goto out;
- ret = add_keyed_refs(root, path, bytenr, info_level,
+ ret = add_keyed_refs(ctx, root, path, info_level,
&preftrees, sc);
if (ret)
goto out;
}
}
+ /*
+ * If we have a share context and we reached here, it means the extent
+ * is not directly shared (no multiple reference items for it),
+ * otherwise we would have exited earlier with a return value of
+ * BACKREF_FOUND_SHARED after processing delayed references or while
+ * processing inline or keyed references from the extent tree.
+ * The extent may however be indirectly shared through shared subtrees
+ * as a result from creating snapshots, so we determine below what is
+ * its parent node, in case we are dealing with a metadata extent, or
+ * what's the leaf (or leaves), from a fs tree, that has a file extent
+ * item pointing to it in case we are dealing with a data extent.
+ */
+ ASSERT(extent_is_shared(sc) == 0);
+
+ /*
+ * If we are here for a data extent and we have a share_check structure
+ * it means the data extent is not directly shared (does not have
+ * multiple reference items), so we have to check if a path in the fs
+ * tree (going from the root node down to the leaf that has the file
+ * extent item pointing to the data extent) is shared, that is, if any
+ * of the extent buffers in the path is referenced by other trees.
+ */
+ if (sc && ctx->bytenr == sc->data_bytenr) {
+ /*
+ * If our data extent is from a generation more recent than the
+ * last generation used to snapshot the root, then we know that
+ * it can not be shared through subtrees, so we can skip
+ * resolving indirect references, there's no point in
+ * determining the extent buffers for the path from the fs tree
+ * root node down to the leaf that has the file extent item that
+ * points to the data extent.
+ */
+ if (sc->data_extent_gen >
+ btrfs_root_last_snapshot(&sc->root->root_item)) {
+ ret = BACKREF_FOUND_NOT_SHARED;
+ goto out;
+ }
+
+ /*
+ * If we are only determining if a data extent is shared or not
+ * and the corresponding file extent item is located in the same
+ * leaf as the previous file extent item, we can skip resolving
+ * indirect references for a data extent, since the fs tree path
+ * is the same (same leaf, so same path). We skip as long as the
+ * cached result for the leaf is valid and only if there's only
+ * one file extent item pointing to the data extent, because in
+ * the case of multiple file extent items, they may be located
+ * in different leaves and therefore we have multiple paths.
+ */
+ if (sc->ctx->curr_leaf_bytenr == sc->ctx->prev_leaf_bytenr &&
+ sc->self_ref_count == 1) {
+ bool cached;
+ bool is_shared;
+
+ cached = lookup_backref_shared_cache(sc->ctx, sc->root,
+ sc->ctx->curr_leaf_bytenr,
+ 0, &is_shared);
+ if (cached) {
+ if (is_shared)
+ ret = BACKREF_FOUND_SHARED;
+ else
+ ret = BACKREF_FOUND_NOT_SHARED;
+ goto out;
+ }
+ }
+ }
+
btrfs_release_path(path);
- ret = add_missing_keys(fs_info, &preftrees, path->skip_locking == 0);
+ ret = add_missing_keys(ctx->fs_info, &preftrees, path->skip_locking == 0);
if (ret)
goto out;
WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root));
- ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees,
- extent_item_pos, sc, ignore_offset);
+ ret = resolve_indirect_refs(ctx, path, &preftrees, sc);
if (ret)
goto out;
@@ -1347,25 +1587,22 @@ again:
* e.g. different offsets would not be merged,
* and would retain their original ref->count < 0.
*/
- if (roots && ref->count && ref->root_id && ref->parent == 0) {
- if (sc && sc->root_objectid &&
- ref->root_id != sc->root_objectid) {
- ret = BACKREF_FOUND_SHARED;
- goto out;
- }
-
+ if (ctx->roots && ref->count && ref->root_id && ref->parent == 0) {
/* no parent == root of tree */
- ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
+ ret = ulist_add(ctx->roots, ref->root_id, 0, GFP_NOFS);
if (ret < 0)
goto out;
}
if (ref->count && ref->parent) {
- if (extent_item_pos && !ref->inode_list &&
+ if (!ctx->ignore_extent_item_pos && !ref->inode_list &&
ref->level == 0) {
+ struct btrfs_tree_parent_check check = { 0 };
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, ref->parent, 0,
- 0, ref->level, NULL);
+ check.level = ref->level;
+
+ eb = read_tree_block(ctx->fs_info, ref->parent,
+ &check);
if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
goto out;
@@ -1378,12 +1615,12 @@ again:
if (!path->skip_locking)
btrfs_tree_read_lock(eb);
- ret = find_extent_in_eb(eb, bytenr,
- *extent_item_pos, &eie, ignore_offset);
+ ret = find_extent_in_eb(ctx, eb, &eie);
if (!path->skip_locking)
btrfs_tree_read_unlock(eb);
free_extent_buffer(eb);
- if (ret < 0)
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP ||
+ ret < 0)
goto out;
ref->inode_list = eie;
/*
@@ -1393,12 +1630,12 @@ again:
*/
eie = NULL;
}
- ret = ulist_add_merge_ptr(refs, ref->parent,
+ ret = ulist_add_merge_ptr(ctx->refs, ref->parent,
ref->inode_list,
(void **)&eie, GFP_NOFS);
if (ret < 0)
goto out;
- if (!ret && extent_item_pos) {
+ if (!ret && !ctx->ignore_extent_item_pos) {
/*
* We've recorded that parent, so we must extend
* its inode list here.
@@ -1436,34 +1673,36 @@ out:
prelim_release(&preftrees.indirect);
prelim_release(&preftrees.indirect_missing_keys);
- if (ret < 0)
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP || ret < 0)
free_inode_elem_list(eie);
return ret;
}
/*
- * Finds all leafs with a reference to the specified combination of bytenr and
- * offset. key_list_head will point to a list of corresponding keys (caller must
- * free each list element). The leafs will be stored in the leafs ulist, which
- * must be freed with ulist_free.
+ * Finds all leaves with a reference to the specified combination of
+ * @ctx->bytenr and @ctx->extent_item_pos. The bytenr of the found leaves are
+ * added to the ulist at @ctx->refs, and that ulist is allocated by this
+ * function. The caller should free the ulist with free_leaf_list() if
+ * @ctx->ignore_extent_item_pos is false, otherwise a fimple ulist_free() is
+ * enough.
*
- * returns 0 on success, <0 on error
+ * Returns 0 on success and < 0 on error. On error @ctx->refs is not allocated.
*/
-int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **leafs,
- const u64 *extent_item_pos, bool ignore_offset)
+int btrfs_find_all_leafs(struct btrfs_backref_walk_ctx *ctx)
{
int ret;
- *leafs = ulist_alloc(GFP_NOFS);
- if (!*leafs)
+ ASSERT(ctx->refs == NULL);
+
+ ctx->refs = ulist_alloc(GFP_NOFS);
+ if (!ctx->refs)
return -ENOMEM;
- ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
- *leafs, NULL, extent_item_pos, NULL, ignore_offset);
- if (ret < 0 && ret != -ENOENT) {
- free_leaf_list(*leafs);
+ ret = find_parent_nodes(ctx, NULL);
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP ||
+ (ret < 0 && ret != -ENOENT)) {
+ free_leaf_list(ctx->refs);
+ ctx->refs = NULL;
return ret;
}
@@ -1471,7 +1710,7 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
}
/*
- * walk all backrefs for a given extent to find all roots that reference this
+ * Walk all backrefs for a given extent to find all roots that reference this
* extent. Walking a backref means finding all extents that reference this
* extent and in turn walk the backrefs of those, too. Naturally this is a
* recursive process, but here it is implemented in an iterative fashion: We
@@ -1479,195 +1718,113 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
* list. In turn, we find all referencing extents for those, further appending
* to the list. The way we iterate the list allows adding more elements after
* the current while iterating. The process stops when we reach the end of the
- * list. Found roots are added to the roots list.
+ * list.
+ *
+ * Found roots are added to @ctx->roots, which is allocated by this function if
+ * it points to NULL, in which case the caller is responsible for freeing it
+ * after it's not needed anymore.
+ * This function requires @ctx->refs to be NULL, as it uses it for allocating a
+ * ulist to do temporary work, and frees it before returning.
*
- * returns 0 on success, < 0 on error.
+ * Returns 0 on success, < 0 on error.
*/
-static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **roots,
- bool ignore_offset)
+static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
{
- struct ulist *tmp;
- struct ulist_node *node = NULL;
+ const u64 orig_bytenr = ctx->bytenr;
+ const bool orig_ignore_extent_item_pos = ctx->ignore_extent_item_pos;
+ bool roots_ulist_allocated = false;
struct ulist_iterator uiter;
- int ret;
+ int ret = 0;
- tmp = ulist_alloc(GFP_NOFS);
- if (!tmp)
- return -ENOMEM;
- *roots = ulist_alloc(GFP_NOFS);
- if (!*roots) {
- ulist_free(tmp);
+ ASSERT(ctx->refs == NULL);
+
+ ctx->refs = ulist_alloc(GFP_NOFS);
+ if (!ctx->refs)
return -ENOMEM;
+
+ if (!ctx->roots) {
+ ctx->roots = ulist_alloc(GFP_NOFS);
+ if (!ctx->roots) {
+ ulist_free(ctx->refs);
+ ctx->refs = NULL;
+ return -ENOMEM;
+ }
+ roots_ulist_allocated = true;
}
+ ctx->ignore_extent_item_pos = true;
+
ULIST_ITER_INIT(&uiter);
while (1) {
- ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
- tmp, *roots, NULL, NULL, ignore_offset);
+ struct ulist_node *node;
+
+ ret = find_parent_nodes(ctx, NULL);
if (ret < 0 && ret != -ENOENT) {
- ulist_free(tmp);
- ulist_free(*roots);
- *roots = NULL;
- return ret;
+ if (roots_ulist_allocated) {
+ ulist_free(ctx->roots);
+ ctx->roots = NULL;
+ }
+ break;
}
- node = ulist_next(tmp, &uiter);
+ ret = 0;
+ node = ulist_next(ctx->refs, &uiter);
if (!node)
break;
- bytenr = node->val;
+ ctx->bytenr = node->val;
cond_resched();
}
- ulist_free(tmp);
- return 0;
+ ulist_free(ctx->refs);
+ ctx->refs = NULL;
+ ctx->bytenr = orig_bytenr;
+ ctx->ignore_extent_item_pos = orig_ignore_extent_item_pos;
+
+ return ret;
}
-int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **roots,
+int btrfs_find_all_roots(struct btrfs_backref_walk_ctx *ctx,
bool skip_commit_root_sem)
{
int ret;
- if (!trans && !skip_commit_root_sem)
- down_read(&fs_info->commit_root_sem);
- ret = btrfs_find_all_roots_safe(trans, fs_info, bytenr,
- time_seq, roots, false);
- if (!trans && !skip_commit_root_sem)
- up_read(&fs_info->commit_root_sem);
+ if (!ctx->trans && !skip_commit_root_sem)
+ down_read(&ctx->fs_info->commit_root_sem);
+ ret = btrfs_find_all_roots_safe(ctx);
+ if (!ctx->trans && !skip_commit_root_sem)
+ up_read(&ctx->fs_info->commit_root_sem);
return ret;
}
-/*
- * The caller has joined a transaction or is holding a read lock on the
- * fs_info->commit_root_sem semaphore, so no need to worry about the root's last
- * snapshot field changing while updating or checking the cache.
- */
-static bool lookup_backref_shared_cache(struct btrfs_backref_shared_cache *cache,
- struct btrfs_root *root,
- u64 bytenr, int level, bool *is_shared)
+struct btrfs_backref_share_check_ctx *btrfs_alloc_backref_share_check_ctx(void)
{
- struct btrfs_backref_shared_cache_entry *entry;
-
- if (!cache->use_cache)
- return false;
-
- if (WARN_ON_ONCE(level >= BTRFS_MAX_LEVEL))
- return false;
-
- /*
- * Level -1 is used for the data extent, which is not reliable to cache
- * because its reference count can increase or decrease without us
- * realizing. We cache results only for extent buffers that lead from
- * the root node down to the leaf with the file extent item.
- */
- ASSERT(level >= 0);
-
- entry = &cache->entries[level];
+ struct btrfs_backref_share_check_ctx *ctx;
- /* Unused cache entry or being used for some other extent buffer. */
- if (entry->bytenr != bytenr)
- return false;
-
- /*
- * We cached a false result, but the last snapshot generation of the
- * root changed, so we now have a snapshot. Don't trust the result.
- */
- if (!entry->is_shared &&
- entry->gen != btrfs_root_last_snapshot(&root->root_item))
- return false;
-
- /*
- * If we cached a true result and the last generation used for dropping
- * a root changed, we can not trust the result, because the dropped root
- * could be a snapshot sharing this extent buffer.
- */
- if (entry->is_shared &&
- entry->gen != btrfs_get_last_root_drop_gen(root->fs_info))
- return false;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
- *is_shared = entry->is_shared;
- /*
- * If the node at this level is shared, than all nodes below are also
- * shared. Currently some of the nodes below may be marked as not shared
- * because we have just switched from one leaf to another, and switched
- * also other nodes above the leaf and below the current level, so mark
- * them as shared.
- */
- if (*is_shared) {
- for (int i = 0; i < level; i++) {
- cache->entries[i].is_shared = true;
- cache->entries[i].gen = entry->gen;
- }
- }
+ ulist_init(&ctx->refs);
- return true;
+ return ctx;
}
-/*
- * The caller has joined a transaction or is holding a read lock on the
- * fs_info->commit_root_sem semaphore, so no need to worry about the root's last
- * snapshot field changing while updating or checking the cache.
- */
-static void store_backref_shared_cache(struct btrfs_backref_shared_cache *cache,
- struct btrfs_root *root,
- u64 bytenr, int level, bool is_shared)
+void btrfs_free_backref_share_ctx(struct btrfs_backref_share_check_ctx *ctx)
{
- struct btrfs_backref_shared_cache_entry *entry;
- u64 gen;
-
- if (!cache->use_cache)
- return;
-
- if (WARN_ON_ONCE(level >= BTRFS_MAX_LEVEL))
+ if (!ctx)
return;
- /*
- * Level -1 is used for the data extent, which is not reliable to cache
- * because its reference count can increase or decrease without us
- * realizing. We cache results only for extent buffers that lead from
- * the root node down to the leaf with the file extent item.
- */
- ASSERT(level >= 0);
-
- if (is_shared)
- gen = btrfs_get_last_root_drop_gen(root->fs_info);
- else
- gen = btrfs_root_last_snapshot(&root->root_item);
-
- entry = &cache->entries[level];
- entry->bytenr = bytenr;
- entry->is_shared = is_shared;
- entry->gen = gen;
-
- /*
- * If we found an extent buffer is shared, set the cache result for all
- * extent buffers below it to true. As nodes in the path are COWed,
- * their sharedness is moved to their children, and if a leaf is COWed,
- * then the sharedness of a data extent becomes direct, the refcount of
- * data extent is increased in the extent item at the extent tree.
- */
- if (is_shared) {
- for (int i = 0; i < level; i++) {
- entry = &cache->entries[i];
- entry->is_shared = is_shared;
- entry->gen = gen;
- }
- }
+ ulist_release(&ctx->refs);
+ kfree(ctx);
}
/*
* Check if a data extent is shared or not.
*
- * @root: The root the inode belongs to.
- * @inum: Number of the inode whose extent we are checking.
+ * @inode: The inode whose extent we are checking.
* @bytenr: Logical bytenr of the extent we are checking.
* @extent_gen: Generation of the extent (file extent item) or 0 if it is
* not known.
- * @roots: List of roots this extent is shared among.
- * @tmp: Temporary list used for iteration.
- * @cache: A backref lookup result cache.
+ * @ctx: A backref sharedness check context.
*
* btrfs_is_data_extent_shared uses the backref walking code but will short
* circuit as soon as it finds a root or inode that doesn't match the
@@ -1680,11 +1837,12 @@ static void store_backref_shared_cache(struct btrfs_backref_shared_cache *cache,
*
* Return: 0 if extent is not shared, 1 if it is shared, < 0 on error.
*/
-int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
+int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
u64 extent_gen,
- struct ulist *roots, struct ulist *tmp,
- struct btrfs_backref_shared_cache *cache)
+ struct btrfs_backref_share_check_ctx *ctx)
{
+ struct btrfs_backref_walk_ctx walk_ctx = { 0 };
+ struct btrfs_root *root = inode->root;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_trans_handle *trans;
struct ulist_iterator uiter;
@@ -1692,15 +1850,23 @@ int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
struct btrfs_seq_list elem = BTRFS_SEQ_LIST_INIT(elem);
int ret = 0;
struct share_check shared = {
- .root_objectid = root->root_key.objectid,
- .inum = inum,
+ .ctx = ctx,
+ .root = root,
+ .inum = btrfs_ino(inode),
+ .data_bytenr = bytenr,
+ .data_extent_gen = extent_gen,
.share_count = 0,
+ .self_ref_count = 0,
.have_delayed_delete_refs = false,
};
int level;
- ulist_init(roots);
- ulist_init(tmp);
+ for (int i = 0; i < BTRFS_BACKREF_CTX_PREV_EXTENTS_SIZE; i++) {
+ if (ctx->prev_extents_cache[i].bytenr == bytenr)
+ return ctx->prev_extents_cache[i].is_shared;
+ }
+
+ ulist_init(&ctx->refs);
trans = btrfs_join_transaction_nostart(root);
if (IS_ERR(trans)) {
@@ -1712,40 +1878,36 @@ int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
down_read(&fs_info->commit_root_sem);
} else {
btrfs_get_tree_mod_seq(fs_info, &elem);
+ walk_ctx.time_seq = elem.seq;
}
+ walk_ctx.ignore_extent_item_pos = true;
+ walk_ctx.trans = trans;
+ walk_ctx.fs_info = fs_info;
+ walk_ctx.refs = &ctx->refs;
+
/* -1 means we are in the bytenr of the data extent. */
level = -1;
ULIST_ITER_INIT(&uiter);
- cache->use_cache = true;
+ ctx->use_path_cache = true;
while (1) {
bool is_shared;
bool cached;
- ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp,
- roots, NULL, &shared, false);
- if (ret == BACKREF_FOUND_SHARED) {
- /* this is the only condition under which we return 1 */
- ret = 1;
+ walk_ctx.bytenr = bytenr;
+ ret = find_parent_nodes(&walk_ctx, &shared);
+ if (ret == BACKREF_FOUND_SHARED ||
+ ret == BACKREF_FOUND_NOT_SHARED) {
+ /* If shared must return 1, otherwise return 0. */
+ ret = (ret == BACKREF_FOUND_SHARED) ? 1 : 0;
if (level >= 0)
- store_backref_shared_cache(cache, root, bytenr,
- level, true);
+ store_backref_shared_cache(ctx, root, bytenr,
+ level, ret == 1);
break;
}
if (ret < 0 && ret != -ENOENT)
break;
ret = 0;
- /*
- * If our data extent is not shared through reflinks and it was
- * created in a generation after the last one used to create a
- * snapshot of the inode's root, then it can not be shared
- * indirectly through subtrees, as that can only happen with
- * snapshots. In this case bail out, no need to check for the
- * sharedness of extent buffers.
- */
- if (level == -1 &&
- extent_gen > btrfs_root_last_snapshot(&root->root_item))
- break;
/*
* If our data extent was not directly shared (without multiple
@@ -1762,18 +1924,18 @@ int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
* deal with), we can not use it if we have multiple leaves
* (which implies multiple paths).
*/
- if (level == -1 && tmp->nnodes > 1)
- cache->use_cache = false;
+ if (level == -1 && ctx->refs.nnodes > 1)
+ ctx->use_path_cache = false;
if (level >= 0)
- store_backref_shared_cache(cache, root, bytenr,
+ store_backref_shared_cache(ctx, root, bytenr,
level, false);
- node = ulist_next(tmp, &uiter);
+ node = ulist_next(&ctx->refs, &uiter);
if (!node)
break;
bytenr = node->val;
level++;
- cached = lookup_backref_shared_cache(cache, root, bytenr, level,
+ cached = lookup_backref_shared_cache(ctx, root, bytenr, level,
&is_shared);
if (cached) {
ret = (is_shared ? 1 : 0);
@@ -1784,6 +1946,20 @@ int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
cond_resched();
}
+ /*
+ * Cache the sharedness result for the data extent if we know our inode
+ * has more than 1 file extent item that refers to the data extent.
+ */
+ if (ret >= 0 && shared.self_ref_count > 1) {
+ int slot = ctx->prev_extents_cache_slot;
+
+ ctx->prev_extents_cache[slot].bytenr = shared.data_bytenr;
+ ctx->prev_extents_cache[slot].is_shared = (ret == 1);
+
+ slot = (slot + 1) % BTRFS_BACKREF_CTX_PREV_EXTENTS_SIZE;
+ ctx->prev_extents_cache_slot = slot;
+ }
+
if (trans) {
btrfs_put_tree_mod_seq(fs_info, &elem);
btrfs_end_transaction(trans);
@@ -1791,8 +1967,9 @@ int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
up_read(&fs_info->commit_root_sem);
}
out:
- ulist_release(roots);
- ulist_release(tmp);
+ ulist_release(&ctx->refs);
+ ctx->prev_leaf_bytenr = ctx->curr_leaf_bytenr;
+
return ret;
}
@@ -2139,7 +2316,7 @@ static int iterate_leaf_refs(struct btrfs_fs_info *fs_info,
"ref for %llu resolved, key (%llu EXTEND_DATA %llu), root %llu",
extent_item_objectid, eie->inum,
eie->offset, root);
- ret = iterate(eie->inum, eie->offset, root, ctx);
+ ret = iterate(eie->inum, eie->offset, eie->num_bytes, root, ctx);
if (ret) {
btrfs_debug(fs_info,
"stopping iteration for %llu due to ret=%d",
@@ -2156,82 +2333,128 @@ static int iterate_leaf_refs(struct btrfs_fs_info *fs_info,
* the given parameters.
* when the iterator function returns a non-zero value, iteration stops.
*/
-int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
- u64 extent_item_objectid, u64 extent_item_pos,
- int search_commit_root,
- iterate_extent_inodes_t *iterate, void *ctx,
- bool ignore_offset)
+int iterate_extent_inodes(struct btrfs_backref_walk_ctx *ctx,
+ bool search_commit_root,
+ iterate_extent_inodes_t *iterate, void *user_ctx)
{
int ret;
- struct btrfs_trans_handle *trans = NULL;
- struct ulist *refs = NULL;
- struct ulist *roots = NULL;
- struct ulist_node *ref_node = NULL;
- struct ulist_node *root_node = NULL;
+ struct ulist *refs;
+ struct ulist_node *ref_node;
struct btrfs_seq_list seq_elem = BTRFS_SEQ_LIST_INIT(seq_elem);
struct ulist_iterator ref_uiter;
- struct ulist_iterator root_uiter;
- btrfs_debug(fs_info, "resolving all inodes for extent %llu",
- extent_item_objectid);
+ btrfs_debug(ctx->fs_info, "resolving all inodes for extent %llu",
+ ctx->bytenr);
+
+ ASSERT(ctx->trans == NULL);
+ ASSERT(ctx->roots == NULL);
if (!search_commit_root) {
- trans = btrfs_attach_transaction(fs_info->tree_root);
+ struct btrfs_trans_handle *trans;
+
+ trans = btrfs_attach_transaction(ctx->fs_info->tree_root);
if (IS_ERR(trans)) {
if (PTR_ERR(trans) != -ENOENT &&
PTR_ERR(trans) != -EROFS)
return PTR_ERR(trans);
trans = NULL;
}
+ ctx->trans = trans;
}
- if (trans)
- btrfs_get_tree_mod_seq(fs_info, &seq_elem);
- else
- down_read(&fs_info->commit_root_sem);
+ if (ctx->trans) {
+ btrfs_get_tree_mod_seq(ctx->fs_info, &seq_elem);
+ ctx->time_seq = seq_elem.seq;
+ } else {
+ down_read(&ctx->fs_info->commit_root_sem);
+ }
- ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
- seq_elem.seq, &refs,
- &extent_item_pos, ignore_offset);
+ ret = btrfs_find_all_leafs(ctx);
if (ret)
goto out;
+ refs = ctx->refs;
+ ctx->refs = NULL;
ULIST_ITER_INIT(&ref_uiter);
while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
- ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val,
- seq_elem.seq, &roots,
- ignore_offset);
+ const u64 leaf_bytenr = ref_node->val;
+ struct ulist_node *root_node;
+ struct ulist_iterator root_uiter;
+ struct extent_inode_elem *inode_list;
+
+ inode_list = (struct extent_inode_elem *)(uintptr_t)ref_node->aux;
+
+ if (ctx->cache_lookup) {
+ const u64 *root_ids;
+ int root_count;
+ bool cached;
+
+ cached = ctx->cache_lookup(leaf_bytenr, ctx->user_ctx,
+ &root_ids, &root_count);
+ if (cached) {
+ for (int i = 0; i < root_count; i++) {
+ ret = iterate_leaf_refs(ctx->fs_info,
+ inode_list,
+ root_ids[i],
+ leaf_bytenr,
+ iterate,
+ user_ctx);
+ if (ret)
+ break;
+ }
+ continue;
+ }
+ }
+
+ if (!ctx->roots) {
+ ctx->roots = ulist_alloc(GFP_NOFS);
+ if (!ctx->roots) {
+ ret = -ENOMEM;
+ break;
+ }
+ }
+
+ ctx->bytenr = leaf_bytenr;
+ ret = btrfs_find_all_roots_safe(ctx);
if (ret)
break;
+
+ if (ctx->cache_store)
+ ctx->cache_store(leaf_bytenr, ctx->roots, ctx->user_ctx);
+
ULIST_ITER_INIT(&root_uiter);
- while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
- btrfs_debug(fs_info,
+ while (!ret && (root_node = ulist_next(ctx->roots, &root_uiter))) {
+ btrfs_debug(ctx->fs_info,
"root %llu references leaf %llu, data list %#llx",
root_node->val, ref_node->val,
ref_node->aux);
- ret = iterate_leaf_refs(fs_info,
- (struct extent_inode_elem *)
- (uintptr_t)ref_node->aux,
- root_node->val,
- extent_item_objectid,
- iterate, ctx);
+ ret = iterate_leaf_refs(ctx->fs_info, inode_list,
+ root_node->val, ctx->bytenr,
+ iterate, user_ctx);
}
- ulist_free(roots);
+ ulist_reinit(ctx->roots);
}
free_leaf_list(refs);
out:
- if (trans) {
- btrfs_put_tree_mod_seq(fs_info, &seq_elem);
- btrfs_end_transaction(trans);
+ if (ctx->trans) {
+ btrfs_put_tree_mod_seq(ctx->fs_info, &seq_elem);
+ btrfs_end_transaction(ctx->trans);
+ ctx->trans = NULL;
} else {
- up_read(&fs_info->commit_root_sem);
+ up_read(&ctx->fs_info->commit_root_sem);
}
+ ulist_free(ctx->roots);
+ ctx->roots = NULL;
+
+ if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP)
+ ret = 0;
+
return ret;
}
-static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
+static int build_ino_list(u64 inum, u64 offset, u64 num_bytes, u64 root, void *ctx)
{
struct btrfs_data_container *inodes = ctx;
const size_t c = 3 * sizeof(u64);
@@ -2255,8 +2478,8 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
void *ctx, bool ignore_offset)
{
+ struct btrfs_backref_walk_ctx walk_ctx = { 0 };
int ret;
- u64 extent_item_pos;
u64 flags = 0;
struct btrfs_key found_key;
int search_commit_root = path->search_commit_root;
@@ -2268,12 +2491,15 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
return -EINVAL;
- extent_item_pos = logical - found_key.objectid;
- ret = iterate_extent_inodes(fs_info, found_key.objectid,
- extent_item_pos, search_commit_root,
- build_ino_list, ctx, ignore_offset);
+ walk_ctx.bytenr = found_key.objectid;
+ if (ignore_offset)
+ walk_ctx.ignore_extent_item_pos = true;
+ else
+ walk_ctx.extent_item_pos = logical - found_key.objectid;
+ walk_ctx.fs_info = fs_info;
- return ret;
+ return iterate_extent_inodes(&walk_ctx, search_commit_root,
+ build_ino_list, ctx);
}
static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
@@ -2526,12 +2752,11 @@ void free_ipath(struct inode_fs_paths *ipath)
kfree(ipath);
}
-struct btrfs_backref_iter *btrfs_backref_iter_alloc(
- struct btrfs_fs_info *fs_info, gfp_t gfp_flag)
+struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info)
{
struct btrfs_backref_iter *ret;
- ret = kzalloc(sizeof(*ret), gfp_flag);
+ ret = kzalloc(sizeof(*ret), GFP_NOFS);
if (!ret)
return NULL;
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index 8e69584d538d..ef6bbea3f456 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -7,10 +7,128 @@
#define BTRFS_BACKREF_H
#include <linux/btrfs.h>
+#include "messages.h"
#include "ulist.h"
#include "disk-io.h"
#include "extent_io.h"
+/*
+ * Used by implementations of iterate_extent_inodes_t (see definition below) to
+ * signal that backref iteration can stop immediately and no error happened.
+ * The value must be non-negative and must not be 0, 1 (which is a common return
+ * value from things like btrfs_search_slot() and used internally in the backref
+ * walking code) and different from BACKREF_FOUND_SHARED and
+ * BACKREF_FOUND_NOT_SHARED
+ */
+#define BTRFS_ITERATE_EXTENT_INODES_STOP 5
+
+/*
+ * Should return 0 if no errors happened and iteration of backrefs should
+ * continue. Can return BTRFS_ITERATE_EXTENT_INODES_STOP or any other non-zero
+ * value to immediately stop iteration and possibly signal an error back to
+ * the caller.
+ */
+typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 num_bytes,
+ u64 root, void *ctx);
+
+/*
+ * Context and arguments for backref walking functions. Some of the fields are
+ * to be filled by the caller of such functions while other are filled by the
+ * functions themselves, as described below.
+ */
+struct btrfs_backref_walk_ctx {
+ /*
+ * The address of the extent for which we are doing backref walking.
+ * Can be either a data extent or a metadata extent.
+ *
+ * Must always be set by the top level caller.
+ */
+ u64 bytenr;
+ /*
+ * Offset relative to the target extent. This is only used for data
+ * extents, and it's meaningful because we can have file extent items
+ * that point only to a section of a data extent ("bookend" extents),
+ * and we want to filter out any that don't point to a section of the
+ * data extent containing the given offset.
+ *
+ * Must always be set by the top level caller.
+ */
+ u64 extent_item_pos;
+ /*
+ * If true and bytenr corresponds to a data extent, then references from
+ * all file extent items that point to the data extent are considered,
+ * @extent_item_pos is ignored.
+ */
+ bool ignore_extent_item_pos;
+ /* A valid transaction handle or NULL. */
+ struct btrfs_trans_handle *trans;
+ /*
+ * The file system's info object, can not be NULL.
+ *
+ * Must always be set by the top level caller.
+ */
+ struct btrfs_fs_info *fs_info;
+ /*
+ * Time sequence acquired from btrfs_get_tree_mod_seq(), in case the
+ * caller joined the tree mod log to get a consistent view of b+trees
+ * while we do backref walking, or BTRFS_SEQ_LAST.
+ * When using BTRFS_SEQ_LAST, delayed refs are not checked and it uses
+ * commit roots when searching b+trees - this is a special case for
+ * qgroups used during a transaction commit.
+ */
+ u64 time_seq;
+ /*
+ * Used to collect the bytenr of metadata extents that point to the
+ * target extent.
+ */
+ struct ulist *refs;
+ /*
+ * List used to collect the IDs of the roots from which the target
+ * extent is accessible. Can be NULL in case the caller does not care
+ * about collecting root IDs.
+ */
+ struct ulist *roots;
+ /*
+ * Used by iterate_extent_inodes() and the main backref walk code
+ * (find_parent_nodes()). Lookup and store functions for an optional
+ * cache which maps the logical address (bytenr) of leaves to an array
+ * of root IDs.
+ */
+ bool (*cache_lookup)(u64 leaf_bytenr, void *user_ctx,
+ const u64 **root_ids_ret, int *root_count_ret);
+ void (*cache_store)(u64 leaf_bytenr, const struct ulist *root_ids,
+ void *user_ctx);
+ /*
+ * If this is not NULL, then the backref walking code will call this
+ * for each indirect data extent reference as soon as it finds one,
+ * before collecting all the remaining backrefs and before resolving
+ * indirect backrefs. This allows for the caller to terminate backref
+ * walking as soon as it finds one backref that matches some specific
+ * criteria. The @cache_lookup and @cache_store callbacks should not
+ * be NULL in order to use this callback.
+ */
+ iterate_extent_inodes_t *indirect_ref_iterator;
+ /*
+ * If this is not NULL, then the backref walking code will call this for
+ * each extent item it's meant to process before it actually starts
+ * processing it. If this returns anything other than 0, then it stops
+ * the backref walking code immediately.
+ */
+ int (*check_extent_item)(u64 bytenr, const struct btrfs_extent_item *ei,
+ const struct extent_buffer *leaf, void *user_ctx);
+ /*
+ * If this is not NULL, then the backref walking code will call this for
+ * each extent data ref it finds (BTRFS_EXTENT_DATA_REF_KEY keys) before
+ * processing that data ref. If this callback return false, then it will
+ * ignore this data ref and it will never resolve the indirect data ref,
+ * saving time searching for leaves in a fs tree with file extent items
+ * matching the data ref.
+ */
+ bool (*skip_data_ref)(u64 root, u64 ino, u64 offset, void *user_ctx);
+ /* Context object to pass to the callbacks defined above. */
+ void *user_ctx;
+};
+
struct inode_fs_paths {
struct btrfs_path *btrfs_path;
struct btrfs_root *fs_root;
@@ -23,17 +141,59 @@ struct btrfs_backref_shared_cache_entry {
bool is_shared;
};
-struct btrfs_backref_shared_cache {
+#define BTRFS_BACKREF_CTX_PREV_EXTENTS_SIZE 8
+
+struct btrfs_backref_share_check_ctx {
+ /* Ulists used during backref walking. */
+ struct ulist refs;
+ /*
+ * The current leaf the caller of btrfs_is_data_extent_shared() is at.
+ * Typically the caller (at the moment only fiemap) tries to determine
+ * the sharedness of data extents point by file extent items from entire
+ * leaves.
+ */
+ u64 curr_leaf_bytenr;
+ /*
+ * The previous leaf the caller was at in the previous call to
+ * btrfs_is_data_extent_shared(). This may be the same as the current
+ * leaf. On the first call it must be 0.
+ */
+ u64 prev_leaf_bytenr;
/*
* A path from a root to a leaf that has a file extent item pointing to
* a given data extent should never exceed the maximum b+tree height.
*/
- struct btrfs_backref_shared_cache_entry entries[BTRFS_MAX_LEVEL];
- bool use_cache;
+ struct btrfs_backref_shared_cache_entry path_cache_entries[BTRFS_MAX_LEVEL];
+ bool use_path_cache;
+ /*
+ * Cache the sharedness result for the last few extents we have found,
+ * but only for extents for which we have multiple file extent items
+ * that point to them.
+ * It's very common to have several file extent items that point to the
+ * same extent (bytenr) but with different offsets and lengths. This
+ * typically happens for COW writes, partial writes into prealloc
+ * extents, NOCOW writes after snapshoting a root, hole punching or
+ * reflinking within the same file (less common perhaps).
+ * So keep a small cache with the lookup results for the extent pointed
+ * by the last few file extent items. This cache is checked, with a
+ * linear scan, whenever btrfs_is_data_extent_shared() is called, so
+ * it must be small so that it does not negatively affect performance in
+ * case we don't have multiple file extent items that point to the same
+ * data extent.
+ */
+ struct {
+ u64 bytenr;
+ bool is_shared;
+ } prev_extents_cache[BTRFS_BACKREF_CTX_PREV_EXTENTS_SIZE];
+ /*
+ * The slot in the prev_extents_cache array that will be used for
+ * storing the sharedness result of a new data extent.
+ */
+ int prev_extents_cache_slot;
};
-typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
- void *ctx);
+struct btrfs_backref_share_check_ctx *btrfs_alloc_backref_share_check_ctx(void);
+void btrfs_free_backref_share_ctx(struct btrfs_backref_share_check_ctx *ctx);
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_path *path, struct btrfs_key *found_key,
@@ -43,11 +203,9 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_key *key, struct btrfs_extent_item *ei,
u32 item_size, u64 *out_root, u8 *out_level);
-int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
- u64 extent_item_objectid,
- u64 extent_offset, int search_commit_root,
- iterate_extent_inodes_t *iterate, void *ctx,
- bool ignore_offset);
+int iterate_extent_inodes(struct btrfs_backref_walk_ctx *ctx,
+ bool search_commit_root,
+ iterate_extent_inodes_t *iterate, void *user_ctx);
int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
struct btrfs_path *path, void *ctx,
@@ -55,13 +213,8 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
-int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **leafs,
- const u64 *extent_item_pos, bool ignore_offset);
-int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **roots,
+int btrfs_find_all_leafs(struct btrfs_backref_walk_ctx *ctx);
+int btrfs_find_all_roots(struct btrfs_backref_walk_ctx *ctx,
bool skip_commit_root_sem);
char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
u32 name_len, unsigned long name_off,
@@ -77,10 +230,9 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
u64 start_off, struct btrfs_path *path,
struct btrfs_inode_extref **ret_extref,
u64 *found_off);
-int btrfs_is_data_extent_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
+int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
u64 extent_gen,
- struct ulist *roots, struct ulist *tmp,
- struct btrfs_backref_shared_cache *cache);
+ struct btrfs_backref_share_check_ctx *ctx);
int __init btrfs_prelim_ref_init(void);
void __cold btrfs_prelim_ref_exit(void);
@@ -111,8 +263,7 @@ struct btrfs_backref_iter {
u32 end_ptr;
};
-struct btrfs_backref_iter *btrfs_backref_iter_alloc(
- struct btrfs_fs_info *fs_info, gfp_t gfp_flag);
+struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info);
static inline void btrfs_backref_iter_free(struct btrfs_backref_iter *iter)
{
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
new file mode 100644
index 000000000000..b8fb7ef6b520
--- /dev/null
+++ b/fs/btrfs/bio.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ * Copyright (C) 2022 Christoph Hellwig.
+ */
+
+#include <linux/bio.h>
+#include "bio.h"
+#include "ctree.h"
+#include "volumes.h"
+#include "raid56.h"
+#include "async-thread.h"
+#include "check-integrity.h"
+#include "dev-replace.h"
+#include "rcu-string.h"
+#include "zoned.h"
+
+static struct bio_set btrfs_bioset;
+
+/*
+ * Initialize a btrfs_bio structure. This skips the embedded bio itself as it
+ * is already initialized by the block layer.
+ */
+static inline void btrfs_bio_init(struct btrfs_bio *bbio,
+ btrfs_bio_end_io_t end_io, void *private)
+{
+ memset(bbio, 0, offsetof(struct btrfs_bio, bio));
+ bbio->end_io = end_io;
+ bbio->private = private;
+}
+
+/*
+ * Allocate a btrfs_bio structure. The btrfs_bio is the main I/O container for
+ * btrfs, and is used for all I/O submitted through btrfs_submit_bio.
+ *
+ * Just like the underlying bio_alloc_bioset it will not fail as it is backed by
+ * a mempool.
+ */
+struct bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
+ btrfs_bio_end_io_t end_io, void *private)
+{
+ struct bio *bio;
+
+ bio = bio_alloc_bioset(NULL, nr_vecs, opf, GFP_NOFS, &btrfs_bioset);
+ btrfs_bio_init(btrfs_bio(bio), end_io, private);
+ return bio;
+}
+
+struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
+ btrfs_bio_end_io_t end_io, void *private)
+{
+ struct bio *bio;
+ struct btrfs_bio *bbio;
+
+ ASSERT(offset <= UINT_MAX && size <= UINT_MAX);
+
+ bio = bio_alloc_clone(orig->bi_bdev, orig, GFP_NOFS, &btrfs_bioset);
+ bbio = btrfs_bio(bio);
+ btrfs_bio_init(bbio, end_io, private);
+
+ bio_trim(bio, offset >> 9, size >> 9);
+ bbio->iter = bio->bi_iter;
+ return bio;
+}
+
+static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
+{
+ if (!dev || !dev->bdev)
+ return;
+ if (bio->bi_status != BLK_STS_IOERR && bio->bi_status != BLK_STS_TARGET)
+ return;
+
+ if (btrfs_op(bio) == BTRFS_MAP_WRITE)
+ btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
+ if (!(bio->bi_opf & REQ_RAHEAD))
+ btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
+ if (bio->bi_opf & REQ_PREFLUSH)
+ btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_FLUSH_ERRS);
+}
+
+static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_fs_info *fs_info,
+ struct bio *bio)
+{
+ if (bio->bi_opf & REQ_META)
+ return fs_info->endio_meta_workers;
+ return fs_info->endio_workers;
+}
+
+static void btrfs_end_bio_work(struct work_struct *work)
+{
+ struct btrfs_bio *bbio = container_of(work, struct btrfs_bio, end_io_work);
+
+ bbio->end_io(bbio);
+}
+
+static void btrfs_simple_end_io(struct bio *bio)
+{
+ struct btrfs_fs_info *fs_info = bio->bi_private;
+ struct btrfs_bio *bbio = btrfs_bio(bio);
+
+ btrfs_bio_counter_dec(fs_info);
+
+ if (bio->bi_status)
+ btrfs_log_dev_io_error(bio, bbio->device);
+
+ if (bio_op(bio) == REQ_OP_READ) {
+ INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
+ queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
+ } else {
+ bbio->end_io(bbio);
+ }
+}
+
+static void btrfs_raid56_end_io(struct bio *bio)
+{
+ struct btrfs_io_context *bioc = bio->bi_private;
+ struct btrfs_bio *bbio = btrfs_bio(bio);
+
+ btrfs_bio_counter_dec(bioc->fs_info);
+ bbio->mirror_num = bioc->mirror_num;
+ bbio->end_io(bbio);
+
+ btrfs_put_bioc(bioc);
+}
+
+static void btrfs_orig_write_end_io(struct bio *bio)
+{
+ struct btrfs_io_stripe *stripe = bio->bi_private;
+ struct btrfs_io_context *bioc = stripe->bioc;
+ struct btrfs_bio *bbio = btrfs_bio(bio);
+
+ btrfs_bio_counter_dec(bioc->fs_info);
+
+ if (bio->bi_status) {
+ atomic_inc(&bioc->error);
+ btrfs_log_dev_io_error(bio, stripe->dev);
+ }
+
+ /*
+ * Only send an error to the higher layers if it is beyond the tolerance
+ * threshold.
+ */
+ if (atomic_read(&bioc->error) > bioc->max_errors)
+ bio->bi_status = BLK_STS_IOERR;
+ else
+ bio->bi_status = BLK_STS_OK;
+
+ bbio->end_io(bbio);
+ btrfs_put_bioc(bioc);
+}
+
+static void btrfs_clone_write_end_io(struct bio *bio)
+{
+ struct btrfs_io_stripe *stripe = bio->bi_private;
+
+ if (bio->bi_status) {
+ atomic_inc(&stripe->bioc->error);
+ btrfs_log_dev_io_error(bio, stripe->dev);
+ }
+
+ /* Pass on control to the original bio this one was cloned from */
+ bio_endio(stripe->bioc->orig_bio);
+ bio_put(bio);
+}
+
+static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio)
+{
+ if (!dev || !dev->bdev ||
+ test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) ||
+ (btrfs_op(bio) == BTRFS_MAP_WRITE &&
+ !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state))) {
+ bio_io_error(bio);
+ return;
+ }
+
+ bio_set_dev(bio, dev->bdev);
+
+ /*
+ * For zone append writing, bi_sector must point the beginning of the
+ * zone
+ */
+ if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
+ u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;
+
+ if (btrfs_dev_is_sequential(dev, physical)) {
+ u64 zone_start = round_down(physical,
+ dev->fs_info->zone_size);
+
+ bio->bi_iter.bi_sector = zone_start >> SECTOR_SHIFT;
+ } else {
+ bio->bi_opf &= ~REQ_OP_ZONE_APPEND;
+ bio->bi_opf |= REQ_OP_WRITE;
+ }
+ }
+ btrfs_debug_in_rcu(dev->fs_info,
+ "%s: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u",
+ __func__, bio_op(bio), bio->bi_opf, bio->bi_iter.bi_sector,
+ (unsigned long)dev->bdev->bd_dev, btrfs_dev_name(dev),
+ dev->devid, bio->bi_iter.bi_size);
+
+ btrfsic_check_bio(bio);
+ submit_bio(bio);
+}
+
+static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr)
+{
+ struct bio *orig_bio = bioc->orig_bio, *bio;
+
+ ASSERT(bio_op(orig_bio) != REQ_OP_READ);
+
+ /* Reuse the bio embedded into the btrfs_bio for the last mirror */
+ if (dev_nr == bioc->num_stripes - 1) {
+ bio = orig_bio;
+ bio->bi_end_io = btrfs_orig_write_end_io;
+ } else {
+ bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &fs_bio_set);
+ bio_inc_remaining(orig_bio);
+ bio->bi_end_io = btrfs_clone_write_end_io;
+ }
+
+ bio->bi_private = &bioc->stripes[dev_nr];
+ bio->bi_iter.bi_sector = bioc->stripes[dev_nr].physical >> SECTOR_SHIFT;
+ bioc->stripes[dev_nr].bioc = bioc;
+ btrfs_submit_dev_bio(bioc->stripes[dev_nr].dev, bio);
+}
+
+void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num)
+{
+ u64 logical = bio->bi_iter.bi_sector << 9;
+ u64 length = bio->bi_iter.bi_size;
+ u64 map_length = length;
+ struct btrfs_io_context *bioc = NULL;
+ struct btrfs_io_stripe smap;
+ int ret;
+
+ btrfs_bio_counter_inc_blocked(fs_info);
+ ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
+ &bioc, &smap, &mirror_num, 1);
+ if (ret) {
+ btrfs_bio_counter_dec(fs_info);
+ btrfs_bio_end_io(btrfs_bio(bio), errno_to_blk_status(ret));
+ return;
+ }
+
+ if (map_length < length) {
+ btrfs_crit(fs_info,
+ "mapping failed logical %llu bio len %llu len %llu",
+ logical, length, map_length);
+ BUG();
+ }
+
+ if (!bioc) {
+ /* Single mirror read/write fast path */
+ btrfs_bio(bio)->mirror_num = mirror_num;
+ btrfs_bio(bio)->device = smap.dev;
+ bio->bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
+ bio->bi_private = fs_info;
+ bio->bi_end_io = btrfs_simple_end_io;
+ btrfs_submit_dev_bio(smap.dev, bio);
+ } else if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+ /* Parity RAID write or read recovery */
+ bio->bi_private = bioc;
+ bio->bi_end_io = btrfs_raid56_end_io;
+ if (bio_op(bio) == REQ_OP_READ)
+ raid56_parity_recover(bio, bioc, mirror_num);
+ else
+ raid56_parity_write(bio, bioc);
+ } else {
+ /* Write to multiple mirrors */
+ int total_devs = bioc->num_stripes;
+ int dev_nr;
+
+ bioc->orig_bio = bio;
+ for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
+ btrfs_submit_mirrored_bio(bioc, dev_nr);
+ }
+}
+
+/*
+ * Submit a repair write.
+ *
+ * This bypasses btrfs_submit_bio deliberately, as that writes all copies in a
+ * RAID setup. Here we only want to write the one bad copy, so we do the
+ * mapping ourselves and submit the bio directly.
+ *
+ * The I/O is issued sychronously to block the repair read completion from
+ * freeing the bio.
+ */
+int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
+ u64 length, u64 logical, struct page *page,
+ unsigned int pg_offset, int mirror_num)
+{
+ struct btrfs_device *dev;
+ struct bio_vec bvec;
+ struct bio bio;
+ u64 map_length = 0;
+ u64 sector;
+ struct btrfs_io_context *bioc = NULL;
+ int ret = 0;
+
+ ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
+ BUG_ON(!mirror_num);
+
+ if (btrfs_repair_one_zone(fs_info, logical))
+ return 0;
+
+ map_length = length;
+
+ /*
+ * Avoid races with device replace and make sure our bioc has devices
+ * associated to its stripes that don't go away while we are doing the
+ * read repair operation.
+ */
+ btrfs_bio_counter_inc_blocked(fs_info);
+ if (btrfs_is_parity_mirror(fs_info, logical, length)) {
+ /*
+ * Note that we don't use BTRFS_MAP_WRITE because it's supposed
+ * to update all raid stripes, but here we just want to correct
+ * bad stripe, thus BTRFS_MAP_READ is abused to only get the bad
+ * stripe's dev and sector.
+ */
+ ret = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
+ &map_length, &bioc, 0);
+ if (ret)
+ goto out_counter_dec;
+ ASSERT(bioc->mirror_num == 1);
+ } else {
+ ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical,
+ &map_length, &bioc, mirror_num);
+ if (ret)
+ goto out_counter_dec;
+ BUG_ON(mirror_num != bioc->mirror_num);
+ }
+
+ sector = bioc->stripes[bioc->mirror_num - 1].physical >> 9;
+ dev = bioc->stripes[bioc->mirror_num - 1].dev;
+ btrfs_put_bioc(bioc);
+
+ if (!dev || !dev->bdev ||
+ !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) {
+ ret = -EIO;
+ goto out_counter_dec;
+ }
+
+ bio_init(&bio, dev->bdev, &bvec, 1, REQ_OP_WRITE | REQ_SYNC);
+ bio.bi_iter.bi_sector = sector;
+ __bio_add_page(&bio, page, length, pg_offset);
+
+ btrfsic_check_bio(&bio);
+ ret = submit_bio_wait(&bio);
+ if (ret) {
+ /* try to remap that extent elsewhere? */
+ btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
+ goto out_bio_uninit;
+ }
+
+ btrfs_info_rl_in_rcu(fs_info,
+ "read error corrected: ino %llu off %llu (dev %s sector %llu)",
+ ino, start, btrfs_dev_name(dev), sector);
+ ret = 0;
+
+out_bio_uninit:
+ bio_uninit(&bio);
+out_counter_dec:
+ btrfs_bio_counter_dec(fs_info);
+ return ret;
+}
+
+int __init btrfs_bioset_init(void)
+{
+ if (bioset_init(&btrfs_bioset, BIO_POOL_SIZE,
+ offsetof(struct btrfs_bio, bio),
+ BIOSET_NEED_BVECS))
+ return -ENOMEM;
+ return 0;
+}
+
+void __cold btrfs_bioset_exit(void)
+{
+ bioset_exit(&btrfs_bioset);
+}
diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h
new file mode 100644
index 000000000000..b12f84b3b341
--- /dev/null
+++ b/fs/btrfs/bio.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ * Copyright (C) 2022 Christoph Hellwig.
+ */
+
+#ifndef BTRFS_BIO_H
+#define BTRFS_BIO_H
+
+#include <linux/bio.h>
+#include <linux/workqueue.h>
+#include "tree-checker.h"
+
+struct btrfs_bio;
+struct btrfs_fs_info;
+
+#define BTRFS_BIO_INLINE_CSUM_SIZE 64
+
+/*
+ * Maximum number of sectors for a single bio to limit the size of the
+ * checksum array. This matches the number of bio_vecs per bio and thus the
+ * I/O size for buffered I/O.
+ */
+#define BTRFS_MAX_BIO_SECTORS (256)
+
+typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio);
+
+/*
+ * Additional info to pass along bio.
+ *
+ * Mostly for btrfs specific features like csum and mirror_num.
+ */
+struct btrfs_bio {
+ unsigned int mirror_num:7;
+
+ /*
+ * Extra indicator for metadata bios.
+ * For some btrfs bios they use pages without a mapping, thus
+ * we can not rely on page->mapping->host to determine if
+ * it's a metadata bio.
+ */
+ unsigned int is_metadata:1;
+ struct bvec_iter iter;
+
+ /* for direct I/O */
+ u64 file_offset;
+
+ /* @device is for stripe IO submission. */
+ struct btrfs_device *device;
+ union {
+ /* For data checksum verification. */
+ struct {
+ u8 *csum;
+ u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
+ };
+
+ /* For metadata parentness verification. */
+ struct btrfs_tree_parent_check parent_check;
+ };
+
+ /* End I/O information supplied to btrfs_bio_alloc */
+ btrfs_bio_end_io_t end_io;
+ void *private;
+
+ /* For read end I/O handling */
+ struct work_struct end_io_work;
+
+ /*
+ * This member must come last, bio_alloc_bioset will allocate enough
+ * bytes for entire btrfs_bio but relies on bio being last.
+ */
+ struct bio bio;
+};
+
+static inline struct btrfs_bio *btrfs_bio(struct bio *bio)
+{
+ return container_of(bio, struct btrfs_bio, bio);
+}
+
+int __init btrfs_bioset_init(void);
+void __cold btrfs_bioset_exit(void);
+
+struct bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
+ btrfs_bio_end_io_t end_io, void *private);
+struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
+ btrfs_bio_end_io_t end_io, void *private);
+
+
+static inline void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
+{
+ bbio->bio.bi_status = status;
+ bbio->end_io(bbio);
+}
+
+static inline void btrfs_bio_free_csum(struct btrfs_bio *bbio)
+{
+ if (bbio->is_metadata)
+ return;
+ if (bbio->csum != bbio->csum_inline) {
+ kfree(bbio->csum);
+ bbio->csum = NULL;
+ }
+}
+
+/*
+ * Iterate through a btrfs_bio (@bbio) on a per-sector basis.
+ *
+ * bvl - struct bio_vec
+ * bbio - struct btrfs_bio
+ * iters - struct bvec_iter
+ * bio_offset - unsigned int
+ */
+#define btrfs_bio_for_each_sector(fs_info, bvl, bbio, iter, bio_offset) \
+ for ((iter) = (bbio)->iter, (bio_offset) = 0; \
+ (iter).bi_size && \
+ (((bvl) = bio_iter_iovec((&(bbio)->bio), (iter))), 1); \
+ (bio_offset) += fs_info->sectorsize, \
+ bio_advance_iter_single(&(bbio)->bio, &(iter), \
+ (fs_info)->sectorsize))
+
+void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+ int mirror_num);
+int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
+ u64 length, u64 logical, struct page *page,
+ unsigned int pg_offset, int mirror_num);
+
+#endif
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index deebc8ddbd93..708d843daa72 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -17,6 +17,21 @@
#include "discard.h"
#include "raid56.h"
#include "zoned.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+
+#ifdef CONFIG_BTRFS_DEBUG
+int btrfs_should_fragment_free_space(struct btrfs_block_group *block_group)
+{
+ struct btrfs_fs_info *fs_info = block_group->fs_info;
+
+ return (btrfs_test_opt(fs_info, FRAGMENT_METADATA) &&
+ block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+ (btrfs_test_opt(fs_info, FRAGMENT_DATA) &&
+ block_group->flags & BTRFS_BLOCK_GROUP_DATA);
+}
+#endif
/*
* Return target flags in extended format or 0 if restripe for this chunk_type
@@ -284,7 +299,7 @@ struct btrfs_block_group *btrfs_next_block_group(
return cache;
}
-/**
+/*
* Check if we can do a NOCOW write for a given extent.
*
* @fs_info: The filesystem information object.
@@ -325,11 +340,9 @@ struct btrfs_block_group *btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info,
return bg;
}
-/**
+/*
* Decrement the number of NOCOW writers in a block group.
*
- * @bg: The block group.
- *
* This is meant to be called after a previous call to btrfs_inc_nocow_writers(),
* and on the block group returned by that call. Typically this is called after
* creating an ordered extent for a NOCOW write, to prevent races with scrub and
@@ -1527,6 +1540,30 @@ static inline bool btrfs_should_reclaim(struct btrfs_fs_info *fs_info)
return true;
}
+static bool should_reclaim_block_group(struct btrfs_block_group *bg, u64 bytes_freed)
+{
+ const struct btrfs_space_info *space_info = bg->space_info;
+ const int reclaim_thresh = READ_ONCE(space_info->bg_reclaim_threshold);
+ const u64 new_val = bg->used;
+ const u64 old_val = new_val + bytes_freed;
+ u64 thresh;
+
+ if (reclaim_thresh == 0)
+ return false;
+
+ thresh = mult_perc(bg->length, reclaim_thresh);
+
+ /*
+ * If we were below the threshold before don't reclaim, we are likely a
+ * brand new block group and we don't want to relocate new block groups.
+ */
+ if (old_val < thresh)
+ return false;
+ if (new_val >= thresh)
+ return false;
+ return true;
+}
+
void btrfs_reclaim_bgs_work(struct work_struct *work)
{
struct btrfs_fs_info *fs_info =
@@ -1594,6 +1631,40 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
up_write(&space_info->groups_sem);
goto next;
}
+ if (bg->used == 0) {
+ /*
+ * It is possible that we trigger relocation on a block
+ * group as its extents are deleted and it first goes
+ * below the threshold, then shortly after goes empty.
+ *
+ * In this case, relocating it does delete it, but has
+ * some overhead in relocation specific metadata, looking
+ * for the non-existent extents and running some extra
+ * transactions, which we can avoid by using one of the
+ * other mechanisms for dealing with empty block groups.
+ */
+ if (!btrfs_test_opt(fs_info, DISCARD_ASYNC))
+ btrfs_mark_bg_unused(bg);
+ spin_unlock(&bg->lock);
+ up_write(&space_info->groups_sem);
+ goto next;
+
+ }
+ /*
+ * The block group might no longer meet the reclaim condition by
+ * the time we get around to reclaiming it, so to avoid
+ * reclaiming overly full block_groups, skip reclaiming them.
+ *
+ * Since the decision making process also depends on the amount
+ * being freed, pass in a fake giant value to skip that extra
+ * check, which is more meaningful when adding to the list in
+ * the first place.
+ */
+ if (!should_reclaim_block_group(bg, bg->length)) {
+ spin_unlock(&bg->lock);
+ up_write(&space_info->groups_sem);
+ goto next;
+ }
spin_unlock(&bg->lock);
/* Get out fast, in case we're unmounting the filesystem */
@@ -1740,8 +1811,8 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
write_sequnlock(&fs_info->profiles_lock);
}
-/**
- * Map a physical disk address to a list of logical addresses
+/*
+ * Map a physical disk address to a list of logical addresses.
*
* @fs_info: the filesystem
* @chunk_start: logical address of block group
@@ -2001,6 +2072,7 @@ static int read_one_block_group(struct btrfs_fs_info *info,
cache->length = key->offset;
cache->used = btrfs_stack_block_group_used(bgi);
+ cache->commit_used = cache->used;
cache->flags = btrfs_stack_block_group_flags(bgi);
cache->global_root_id = btrfs_stack_block_group_chunk_objectid(bgi);
@@ -2481,7 +2553,7 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
cache->global_root_id = calculate_global_root_id(fs_info, cache->start);
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
- cache->needs_free_space = 1;
+ set_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &cache->runtime_flags);
ret = btrfs_load_block_group_zone_info(cache, true);
if (ret) {
@@ -2692,6 +2764,25 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf;
struct btrfs_block_group_item bgi;
struct btrfs_key key;
+ u64 old_commit_used;
+ u64 used;
+
+ /*
+ * Block group items update can be triggered out of commit transaction
+ * critical section, thus we need a consistent view of used bytes.
+ * We cannot use cache->used directly outside of the spin lock, as it
+ * may be changed.
+ */
+ spin_lock(&cache->lock);
+ old_commit_used = cache->commit_used;
+ used = cache->used;
+ /* No change in used bytes, can safely skip it. */
+ if (cache->commit_used == used) {
+ spin_unlock(&cache->lock);
+ return 0;
+ }
+ cache->commit_used = used;
+ spin_unlock(&cache->lock);
key.objectid = cache->start;
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
@@ -2706,7 +2797,7 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
- btrfs_set_stack_block_group_used(&bgi, cache->used);
+ btrfs_set_stack_block_group_used(&bgi, used);
btrfs_set_stack_block_group_chunk_objectid(&bgi,
cache->global_root_id);
btrfs_set_stack_block_group_flags(&bgi, cache->flags);
@@ -2714,6 +2805,12 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
fail:
btrfs_release_path(path);
+ /* We didn't update the block group item, need to revert @commit_used. */
+ if (ret < 0) {
+ spin_lock(&cache->lock);
+ cache->commit_used = old_commit_used;
+ spin_unlock(&cache->lock);
+ }
return ret;
}
@@ -3211,31 +3308,6 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)
return ret;
}
-static inline bool should_reclaim_block_group(struct btrfs_block_group *bg,
- u64 bytes_freed)
-{
- const struct btrfs_space_info *space_info = bg->space_info;
- const int reclaim_thresh = READ_ONCE(space_info->bg_reclaim_threshold);
- const u64 new_val = bg->used;
- const u64 old_val = new_val + bytes_freed;
- u64 thresh;
-
- if (reclaim_thresh == 0)
- return false;
-
- thresh = div_factor_fine(bg->length, reclaim_thresh);
-
- /*
- * If we were below the threshold before don't reclaim, we are likely a
- * brand new block group and we don't want to relocate new block groups.
- */
- if (old_val < thresh)
- return false;
- if (new_val >= thresh)
- return false;
- return true;
-}
-
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, bool alloc)
{
@@ -3347,8 +3419,9 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
return ret;
}
-/**
- * btrfs_add_reserved_bytes - update the block_group and space info counters
+/*
+ * Update the block_group and space info counters.
+ *
* @cache: The cache we are manipulating
* @ram_bytes: The number of bytes of file content, and will be same to
* @num_bytes except for the compress path.
@@ -3391,8 +3464,9 @@ int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
return ret;
}
-/**
- * btrfs_free_reserved_bytes - update the block_group and space info counters
+/*
+ * Update the block_group and space info counters.
+ *
* @cache: The cache we are manipulating
* @num_bytes: The number of bytes in question
* @delalloc: The blocks are allocated for the delalloc write
@@ -3449,13 +3523,13 @@ static int should_alloc_chunk(struct btrfs_fs_info *fs_info,
*/
if (force == CHUNK_ALLOC_LIMITED) {
thresh = btrfs_super_total_bytes(fs_info->super_copy);
- thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1));
+ thresh = max_t(u64, SZ_64M, mult_perc(thresh, 1));
if (sinfo->total_bytes - bytes_used < thresh)
return 1;
}
- if (bytes_used + SZ_2M < div_factor(sinfo->total_bytes, 8))
+ if (bytes_used + SZ_2M < mult_perc(sinfo->total_bytes, 80))
return 0;
return 1;
}
diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
index 8fb14b99a1d1..a02ea76fd6cf 100644
--- a/fs/btrfs/block-group.h
+++ b/fs/btrfs/block-group.h
@@ -55,6 +55,10 @@ enum btrfs_block_group_flags {
BLOCK_GROUP_FLAG_CHUNK_ITEM_INSERTED,
BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE,
BLOCK_GROUP_FLAG_ZONED_DATA_RELOC,
+ /* Does the block group need to be added to the free space tree? */
+ BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE,
+ /* Indicate that the block group is placed on a sequential zone */
+ BLOCK_GROUP_FLAG_SEQUENTIAL_ZONE,
};
enum btrfs_caching_type {
@@ -100,6 +104,12 @@ struct btrfs_block_group {
u64 global_root_id;
/*
+ * The last committed used bytes of this block group, if the above @used
+ * is still the same as @commit_used, we don't need to update block
+ * group item of this block group.
+ */
+ u64 commit_used;
+ /*
* If the free space extent count exceeds this number, convert the block
* group to bitmaps.
*/
@@ -203,15 +213,6 @@ struct btrfs_block_group {
struct mutex free_space_lock;
/*
- * Does the block group need to be added to the free space tree?
- * Protected by free_space_lock.
- */
- int needs_free_space;
-
- /* Flag indicating this block group is placed on a sequential zone */
- bool seq_zone;
-
- /*
* Number of extents in this block group used for swap files.
* All accesses protected by the spinlock 'lock'.
*/
@@ -251,16 +252,7 @@ static inline bool btrfs_is_block_group_data_only(
}
#ifdef CONFIG_BTRFS_DEBUG
-static inline int btrfs_should_fragment_free_space(
- struct btrfs_block_group *block_group)
-{
- struct btrfs_fs_info *fs_info = block_group->fs_info;
-
- return (btrfs_test_opt(fs_info, FRAGMENT_METADATA) &&
- block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||
- (btrfs_test_opt(fs_info, FRAGMENT_DATA) &&
- block_group->flags & BTRFS_BLOCK_GROUP_DATA);
-}
+int btrfs_should_fragment_free_space(struct btrfs_block_group *block_group);
#endif
struct btrfs_block_group *btrfs_lookup_first_block_group(
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index ec96285357e0..5367a14d44d2 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -7,6 +7,8 @@
#include "transaction.h"
#include "block-group.h"
#include "disk-io.h"
+#include "fs.h"
+#include "accessors.h"
/*
* HOW DO BLOCK RESERVES WORK
@@ -225,7 +227,7 @@ int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
return ret;
}
-int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
+int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_percent)
{
u64 num_bytes = 0;
int ret = -ENOSPC;
@@ -234,7 +236,7 @@ int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
return 0;
spin_lock(&block_rsv->lock);
- num_bytes = div_factor(block_rsv->size, min_factor);
+ num_bytes = mult_perc(block_rsv->size, min_percent);
if (block_rsv->reserved >= num_bytes)
ret = 0;
spin_unlock(&block_rsv->lock);
@@ -323,31 +325,6 @@ void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
spin_unlock(&block_rsv->lock);
}
-int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
- struct btrfs_block_rsv *dest, u64 num_bytes,
- int min_factor)
-{
- struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
- u64 min_bytes;
-
- if (global_rsv->space_info != dest->space_info)
- return -ENOSPC;
-
- spin_lock(&global_rsv->lock);
- min_bytes = div_factor(global_rsv->size, min_factor);
- if (global_rsv->reserved < min_bytes + num_bytes) {
- spin_unlock(&global_rsv->lock);
- return -ENOSPC;
- }
- global_rsv->reserved -= num_bytes;
- if (global_rsv->reserved < global_rsv->size)
- global_rsv->full = false;
- spin_unlock(&global_rsv->lock);
-
- btrfs_block_rsv_add_bytes(dest, num_bytes, true);
- return 0;
-}
-
void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
{
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
@@ -552,5 +529,17 @@ try_reserve:
if (!ret)
return global_rsv;
}
+
+ /*
+ * All hope is lost, but of course our reservations are overly
+ * pessimistic, so instead of possibly having an ENOSPC abort here, try
+ * one last time to force a reservation if there's enough actual space
+ * on disk to make the reservation.
+ */
+ ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, blocksize,
+ BTRFS_RESERVE_FLUSH_EMERGENCY);
+ if (!ret)
+ return block_rsv;
+
return ERR_PTR(ret);
}
diff --git a/fs/btrfs/block-rsv.h b/fs/btrfs/block-rsv.h
index 578c3497a455..4cc41c9aaa82 100644
--- a/fs/btrfs/block-rsv.h
+++ b/fs/btrfs/block-rsv.h
@@ -4,6 +4,7 @@
#define BTRFS_BLOCK_RSV_H
struct btrfs_trans_handle;
+struct btrfs_root;
enum btrfs_reserve_flush_enum;
/*
@@ -62,7 +63,7 @@ void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 num_bytes,
enum btrfs_reserve_flush_enum flush);
-int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor);
+int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_percent);
int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 min_reserved,
enum btrfs_reserve_flush_enum flush);
@@ -70,9 +71,6 @@ int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
struct btrfs_block_rsv *dst_rsv, u64 num_bytes,
bool update_size);
int btrfs_block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, u64 num_bytes);
-int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
- struct btrfs_block_rsv *dest, u64 num_bytes,
- int min_factor);
void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
u64 num_bytes, bool update_size);
u64 btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 54c2ccb36b61..195c09e20609 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -411,29 +411,142 @@ static inline void btrfs_inode_split_flags(u64 inode_item_flags,
#define CSUM_FMT "0x%*phN"
#define CSUM_FMT_VALUE(size, bytes) size, bytes
-static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode,
- u64 logical_start, u8 *csum, u8 *csum_expected, int mirror_num)
-{
- struct btrfs_root *root = inode->root;
- const u32 csum_size = root->fs_info->csum_size;
-
- /* Output minus objectid, which is more meaningful */
- if (root->root_key.objectid >= BTRFS_LAST_FREE_OBJECTID)
- btrfs_warn_rl(root->fs_info,
-"csum failed root %lld ino %lld off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
- root->root_key.objectid, btrfs_ino(inode),
- logical_start,
- CSUM_FMT_VALUE(csum_size, csum),
- CSUM_FMT_VALUE(csum_size, csum_expected),
- mirror_num);
- else
- btrfs_warn_rl(root->fs_info,
-"csum failed root %llu ino %llu off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
- root->root_key.objectid, btrfs_ino(inode),
- logical_start,
- CSUM_FMT_VALUE(csum_size, csum),
- CSUM_FMT_VALUE(csum_size, csum_expected),
- mirror_num);
-}
+void btrfs_submit_data_write_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num);
+void btrfs_submit_data_read_bio(struct btrfs_inode *inode, struct bio *bio,
+ int mirror_num, enum btrfs_compression_type compress_type);
+void btrfs_submit_dio_repair_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num);
+blk_status_t btrfs_submit_bio_start(struct btrfs_inode *inode, struct bio *bio);
+blk_status_t btrfs_submit_bio_start_direct_io(struct btrfs_inode *inode,
+ struct bio *bio,
+ u64 dio_file_offset);
+int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
+ u32 pgoff, u8 *csum, const u8 * const csum_expected);
+int btrfs_check_data_csum(struct btrfs_inode *inode, struct btrfs_bio *bbio,
+ u32 bio_offset, struct page *page, u32 pgoff);
+unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
+ u32 bio_offset, struct page *page,
+ u64 start, u64 end);
+noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
+ u64 *orig_start, u64 *orig_block_len,
+ u64 *ram_bytes, bool nowait, bool strict);
+
+void __btrfs_del_delalloc_inode(struct btrfs_root *root, struct btrfs_inode *inode);
+struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
+int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index);
+int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *dir, struct btrfs_inode *inode,
+ const struct fscrypt_str *name);
+int btrfs_add_link(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *parent_inode, struct btrfs_inode *inode,
+ const struct fscrypt_str *name, int add_backref, u64 index);
+int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry);
+int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
+ int front);
+
+int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
+int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
+ bool in_reclaim_context);
+int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
+ unsigned int extra_bits,
+ struct extent_state **cached_state);
+
+struct btrfs_new_inode_args {
+ /* Input */
+ struct inode *dir;
+ struct dentry *dentry;
+ struct inode *inode;
+ bool orphan;
+ bool subvol;
+
+ /* Output from btrfs_new_inode_prepare(), input to btrfs_create_new_inode(). */
+ struct posix_acl *default_acl;
+ struct posix_acl *acl;
+ struct fscrypt_name fname;
+};
+
+int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
+ unsigned int *trans_num_items);
+int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_new_inode_args *args);
+void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
+struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
+ struct inode *dir);
+ void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *state,
+ u32 bits);
+void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
+ struct extent_state *state, u32 bits);
+void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state *new,
+ struct extent_state *other);
+void btrfs_split_delalloc_extent(struct btrfs_inode *inode,
+ struct extent_state *orig, u64 split);
+void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end);
+vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf);
+void btrfs_evict_inode(struct inode *inode);
+struct inode *btrfs_alloc_inode(struct super_block *sb);
+void btrfs_destroy_inode(struct inode *inode);
+void btrfs_free_inode(struct inode *inode);
+int btrfs_drop_inode(struct inode *inode);
+int __init btrfs_init_cachep(void);
+void __cold btrfs_destroy_cachep(void);
+struct inode *btrfs_iget_path(struct super_block *s, u64 ino,
+ struct btrfs_root *root, struct btrfs_path *path);
+struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root);
+struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
+ struct page *page, size_t pg_offset,
+ u64 start, u64 end);
+int btrfs_update_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_inode *inode);
+int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_inode *inode);
+int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct btrfs_inode *inode);
+int btrfs_orphan_cleanup(struct btrfs_root *root);
+int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size);
+void btrfs_add_delayed_iput(struct btrfs_inode *inode);
+void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info);
+int btrfs_wait_on_delayed_iputs(struct btrfs_fs_info *fs_info);
+int btrfs_prealloc_file_range(struct inode *inode, int mode,
+ u64 start, u64 num_bytes, u64 min_size,
+ loff_t actual_len, u64 *alloc_hint);
+int btrfs_prealloc_file_range_trans(struct inode *inode,
+ struct btrfs_trans_handle *trans, int mode,
+ u64 start, u64 num_bytes, u64 min_size,
+ loff_t actual_len, u64 *alloc_hint);
+int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page,
+ u64 start, u64 end, int *page_started,
+ unsigned long *nr_written, struct writeback_control *wbc);
+int btrfs_writepage_cow_fixup(struct page *page);
+void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
+ struct page *page, u64 start,
+ u64 end, bool uptodate);
+int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
+ int compress_type);
+int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
+ u64 file_offset, u64 disk_bytenr,
+ u64 disk_io_size,
+ struct page **pages);
+ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
+ struct btrfs_ioctl_encoded_io_args *encoded);
+ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ const struct btrfs_ioctl_encoded_io_args *encoded);
+
+ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,
+ size_t done_before);
+struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter,
+ size_t done_before);
+
+extern const struct dentry_operations btrfs_dentry_operations;
+
+/* Inode locking type flags, by default the exclusive lock is taken. */
+enum btrfs_ilock_type {
+ ENUM_BIT(BTRFS_ILOCK_SHARED),
+ ENUM_BIT(BTRFS_ILOCK_TRY),
+ ENUM_BIT(BTRFS_ILOCK_MMAP),
+};
+
+int btrfs_inode_lock(struct btrfs_inode *inode, unsigned int ilock_flags);
+void btrfs_inode_unlock(struct btrfs_inode *inode, unsigned int ilock_flags);
+void btrfs_update_inode_bytes(struct btrfs_inode *inode, const u64 add_bytes,
+ const u64 del_bytes);
+void btrfs_assert_inode_range_clean(struct btrfs_inode *inode, u64 start, u64 end);
#endif
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 98c6e5feab19..82e49d985019 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -82,6 +82,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <crypto/hash.h>
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -92,6 +93,7 @@
#include "check-integrity.h"
#include "rcu-string.h"
#include "compression.h"
+#include "accessors.h"
#define BTRFSIC_BLOCK_HASHTABLE_SIZE 0x10000
#define BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE 0x10000
@@ -755,7 +757,7 @@ static int btrfsic_process_superblock_dev_mirror(
btrfs_info_in_rcu(fs_info,
"new initial S-block (bdev %p, %s) @%llu (%pg/%llu/%d)",
superblock_bdev,
- rcu_str_deref(device->name), dev_bytenr,
+ btrfs_dev_name(device), dev_bytenr,
dev_state->bdev, dev_bytenr,
superblock_mirror_num);
list_add(&superblock_tmp->all_blocks_node,
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index f1f051ad3147..5122ca79f7ea 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -23,16 +23,19 @@
#include <crypto/hash.h>
#include "misc.h"
#include "ctree.h"
+#include "fs.h"
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
-#include "volumes.h"
+#include "bio.h"
#include "ordered-data.h"
#include "compression.h"
#include "extent_io.h"
#include "extent_map.h"
#include "subpage.h"
#include "zoned.h"
+#include "file-item.h"
+#include "super.h"
static const char* const btrfs_compress_types[] = { "", "zlib", "lzo", "zstd" };
@@ -116,7 +119,7 @@ static int compression_decompress_bio(struct list_head *ws,
}
static int compression_decompress(int type, struct list_head *ws,
- unsigned char *data_in, struct page *dest_page,
+ const u8 *data_in, struct page *dest_page,
unsigned long start_byte, size_t srclen, size_t destlen)
{
switch (type) {
@@ -183,7 +186,7 @@ static void end_compressed_bio_read(struct btrfs_bio *bbio)
u64 start = bbio->file_offset + offset;
if (!status &&
- (!csum || !btrfs_check_data_csum(inode, bbio, offset,
+ (!csum || !btrfs_check_data_csum(bi, bbio, offset,
bv.bv_page, bv.bv_offset))) {
btrfs_clean_io_failure(bi, start, bv.bv_page,
bv.bv_offset);
@@ -191,9 +194,9 @@ static void end_compressed_bio_read(struct btrfs_bio *bbio)
int ret;
refcount_inc(&cb->pending_ios);
- ret = btrfs_repair_one_sector(inode, bbio, offset,
+ ret = btrfs_repair_one_sector(BTRFS_I(inode), bbio, offset,
bv.bv_page, bv.bv_offset,
- btrfs_submit_data_read_bio);
+ true);
if (ret) {
refcount_dec(&cb->pending_ios);
status = errno_to_blk_status(ret);
@@ -512,7 +515,7 @@ static u64 bio_end_offset(struct bio *bio)
static noinline int add_ra_bio_pages(struct inode *inode,
u64 compressed_end,
struct compressed_bio *cb,
- unsigned long *pflags)
+ int *memstall, unsigned long *pflags)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
unsigned long end_index;
@@ -581,8 +584,10 @@ static noinline int add_ra_bio_pages(struct inode *inode,
continue;
}
- if (PageWorkingset(page))
+ if (!*memstall && PageWorkingset(page)) {
psi_memstall_enter(pflags);
+ *memstall = 1;
+ }
ret = set_page_extent_mapped(page);
if (ret < 0) {
@@ -670,8 +675,8 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
u64 em_len;
u64 em_start;
struct extent_map *em;
- /* Initialize to 1 to make skip psi_memstall_leave unless needed */
- unsigned long pflags = 1;
+ unsigned long pflags;
+ int memstall = 0;
blk_status_t ret;
int ret2;
int i;
@@ -727,7 +732,7 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
goto fail;
}
- add_ra_bio_pages(inode, em_start + em_len, cb, &pflags);
+ add_ra_bio_pages(inode, em_start + em_len, cb, &memstall, &pflags);
/* include any pages we added in add_ra-bio_pages */
cb->len = bio->bi_iter.bi_size;
@@ -807,7 +812,7 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
}
}
- if (!pflags)
+ if (memstall)
psi_memstall_leave(&pflags);
if (refcount_dec_and_test(&cb->pending_ios))
@@ -1227,7 +1232,7 @@ static int btrfs_decompress_bio(struct compressed_bio *cb)
* single page, and we want to read a single page out of it.
* start_byte tells us the offset into the compressed data we're interested in
*/
-int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
+int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page,
unsigned long start_byte, size_t srclen, size_t destlen)
{
struct list_head *workspace;
@@ -1241,12 +1246,13 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
return ret;
}
-void __init btrfs_init_compress(void)
+int __init btrfs_init_compress(void)
{
btrfs_init_workspace_manager(BTRFS_COMPRESS_NONE);
btrfs_init_workspace_manager(BTRFS_COMPRESS_ZLIB);
btrfs_init_workspace_manager(BTRFS_COMPRESS_LZO);
zstd_init_workspace_manager();
+ return 0;
}
void __cold btrfs_exit_compress(void)
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 1aa02903de69..6209d40a1e08 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -6,6 +6,7 @@
#ifndef BTRFS_COMPRESSION_H
#define BTRFS_COMPRESSION_H
+#include <linux/blk_types.h>
#include <linux/sizes.h>
struct btrfs_inode;
@@ -77,7 +78,7 @@ static inline unsigned int btrfs_compress_level(unsigned int type_level)
return ((type_level & 0xF0) >> 4);
}
-void __init btrfs_init_compress(void);
+int __init btrfs_init_compress(void);
void __cold btrfs_exit_compress(void);
int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
@@ -85,7 +86,7 @@ int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
unsigned long *out_pages,
unsigned long *total_in,
unsigned long *total_out);
-int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
+int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page,
unsigned long start_byte, size_t srclen, size_t destlen);
int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
struct compressed_bio *cb, u32 decompressed);
@@ -149,7 +150,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
u64 start, struct page **pages, unsigned long *out_pages,
unsigned long *total_in, unsigned long *total_out);
int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
-int zlib_decompress(struct list_head *ws, unsigned char *data_in,
+int zlib_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen);
struct list_head *zlib_alloc_workspace(unsigned int level);
@@ -160,7 +161,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
u64 start, struct page **pages, unsigned long *out_pages,
unsigned long *total_in, unsigned long *total_out);
int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
-int lzo_decompress(struct list_head *ws, unsigned char *data_in,
+int lzo_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen);
struct list_head *lzo_alloc_workspace(unsigned int level);
@@ -170,7 +171,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
u64 start, struct page **pages, unsigned long *out_pages,
unsigned long *total_in, unsigned long *total_out);
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
-int zstd_decompress(struct list_head *ws, unsigned char *data_in,
+int zstd_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen);
void zstd_init_workspace_manager(void);
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index b39b339fbf96..4754c9101a4c 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -8,6 +8,7 @@
#include <linux/rbtree.h>
#include <linux/mm.h>
#include <linux/error-injection.h>
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -17,6 +18,13 @@
#include "qgroup.h"
#include "tree-mod-log.h"
#include "tree-checker.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "relocation.h"
+#include "file-item.h"
+
+static struct kmem_cache *btrfs_path_cachep;
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
@@ -44,6 +52,104 @@ static const struct btrfs_csums {
.driver = "blake2b-256" },
};
+/*
+ * The leaf data grows from end-to-front in the node. this returns the address
+ * of the start of the last item, which is the stop of the leaf data stack.
+ */
+static unsigned int leaf_data_end(const struct extent_buffer *leaf)
+{
+ u32 nr = btrfs_header_nritems(leaf);
+
+ if (nr == 0)
+ return BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
+ return btrfs_item_offset(leaf, nr - 1);
+}
+
+/*
+ * Move data in a @leaf (using memmove, safe for overlapping ranges).
+ *
+ * @leaf: leaf that we're doing a memmove on
+ * @dst_offset: item data offset we're moving to
+ * @src_offset: item data offset were' moving from
+ * @len: length of the data we're moving
+ *
+ * Wrapper around memmove_extent_buffer() that takes into account the header on
+ * the leaf. The btrfs_item offset's start directly after the header, so we
+ * have to adjust any offsets to account for the header in the leaf. This
+ * handles that math to simplify the callers.
+ */
+static inline void memmove_leaf_data(const struct extent_buffer *leaf,
+ unsigned long dst_offset,
+ unsigned long src_offset,
+ unsigned long len)
+{
+ memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) + dst_offset,
+ btrfs_item_nr_offset(leaf, 0) + src_offset, len);
+}
+
+/*
+ * Copy item data from @src into @dst at the given @offset.
+ *
+ * @dst: destination leaf that we're copying into
+ * @src: source leaf that we're copying from
+ * @dst_offset: item data offset we're copying to
+ * @src_offset: item data offset were' copying from
+ * @len: length of the data we're copying
+ *
+ * Wrapper around copy_extent_buffer() that takes into account the header on
+ * the leaf. The btrfs_item offset's start directly after the header, so we
+ * have to adjust any offsets to account for the header in the leaf. This
+ * handles that math to simplify the callers.
+ */
+static inline void copy_leaf_data(const struct extent_buffer *dst,
+ const struct extent_buffer *src,
+ unsigned long dst_offset,
+ unsigned long src_offset, unsigned long len)
+{
+ copy_extent_buffer(dst, src, btrfs_item_nr_offset(dst, 0) + dst_offset,
+ btrfs_item_nr_offset(src, 0) + src_offset, len);
+}
+
+/*
+ * Move items in a @leaf (using memmove).
+ *
+ * @dst: destination leaf for the items
+ * @dst_item: the item nr we're copying into
+ * @src_item: the item nr we're copying from
+ * @nr_items: the number of items to copy
+ *
+ * Wrapper around memmove_extent_buffer() that does the math to get the
+ * appropriate offsets into the leaf from the item numbers.
+ */
+static inline void memmove_leaf_items(const struct extent_buffer *leaf,
+ int dst_item, int src_item, int nr_items)
+{
+ memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, dst_item),
+ btrfs_item_nr_offset(leaf, src_item),
+ nr_items * sizeof(struct btrfs_item));
+}
+
+/*
+ * Copy items from @src into @dst at the given @offset.
+ *
+ * @dst: destination leaf for the items
+ * @src: source leaf for the items
+ * @dst_item: the item nr we're copying into
+ * @src_item: the item nr we're copying from
+ * @nr_items: the number of items to copy
+ *
+ * Wrapper around copy_extent_buffer() that does the math to get the
+ * appropriate offsets into the leaf from the item numbers.
+ */
+static inline void copy_leaf_items(const struct extent_buffer *dst,
+ const struct extent_buffer *src,
+ int dst_item, int src_item, int nr_items)
+{
+ copy_extent_buffer(dst, src, btrfs_item_nr_offset(dst, dst_item),
+ btrfs_item_nr_offset(src, src_item),
+ nr_items * sizeof(struct btrfs_item));
+}
+
int btrfs_super_csum_size(const struct btrfs_super_block *s)
{
u16 t = btrfs_super_csum_type(s);
@@ -78,6 +184,8 @@ size_t __attribute_const__ btrfs_get_num_csums(void)
struct btrfs_path *btrfs_alloc_path(void)
{
+ might_sleep();
+
return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
}
@@ -114,6 +222,22 @@ noinline void btrfs_release_path(struct btrfs_path *p)
}
/*
+ * We want the transaction abort to print stack trace only for errors where the
+ * cause could be a bug, eg. due to ENOSPC, and not for common errors that are
+ * caused by external factors.
+ */
+bool __cold abort_should_print_stack(int errno)
+{
+ switch (errno) {
+ case -EIO:
+ case -EROFS:
+ case -ENOMEM:
+ return false;
+ }
+ return true;
+}
+
+/*
* safely gets a reference on the root node of a tree. A lock
* is not taken, so a concurrent writer may put a different node
* at the root of the tree. See btrfs_lock_root_node for the
@@ -471,7 +595,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
} else {
WARN_ON(trans->transid != btrfs_header_generation(parent));
btrfs_tree_mod_log_insert_key(parent, parent_slot,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REPLACE);
btrfs_set_node_blockptr(parent, parent_slot,
cow->start);
btrfs_set_node_ptr_generation(parent, parent_slot,
@@ -834,19 +958,22 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
int slot)
{
int level = btrfs_header_level(parent);
+ struct btrfs_tree_parent_check check = { 0 };
struct extent_buffer *eb;
- struct btrfs_key first_key;
if (slot < 0 || slot >= btrfs_header_nritems(parent))
return ERR_PTR(-ENOENT);
BUG_ON(level == 0);
- btrfs_node_key_to_cpu(parent, &first_key, slot);
+ check.level = level - 1;
+ check.transid = btrfs_node_ptr_generation(parent, slot);
+ check.owner_root = btrfs_header_owner(parent);
+ check.has_first_key = true;
+ btrfs_node_key_to_cpu(parent, &check.first_key, slot);
+
eb = read_tree_block(parent->fs_info, btrfs_node_blockptr(parent, slot),
- btrfs_header_owner(parent),
- btrfs_node_ptr_generation(parent, slot),
- level - 1, &first_key);
+ &check);
if (IS_ERR(eb))
return eb;
if (!extent_buffer_uptodate(eb)) {
@@ -1000,7 +1127,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
struct btrfs_disk_key right_key;
btrfs_node_key(right, &right_key, 0);
ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REPLACE);
BUG_ON(ret < 0);
btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
@@ -1046,7 +1173,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
struct btrfs_disk_key mid_key;
btrfs_node_key(mid, &mid_key, 0);
ret = btrfs_tree_mod_log_insert_key(parent, pslot,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REPLACE);
BUG_ON(ret < 0);
btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent);
@@ -1148,7 +1275,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
orig_slot += left_nr;
btrfs_node_key(mid, &disk_key, 0);
ret = btrfs_tree_mod_log_insert_key(parent, pslot,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REPLACE);
BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent);
@@ -1202,7 +1329,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
btrfs_node_key(right, &disk_key, 0);
ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REPLACE);
BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
@@ -1405,10 +1532,10 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
const struct btrfs_key *key)
{
struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_tree_parent_check check = { 0 };
u64 blocknr;
u64 gen;
struct extent_buffer *tmp;
- struct btrfs_key first_key;
int ret;
int parent_level;
bool unlock_up;
@@ -1417,7 +1544,11 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
blocknr = btrfs_node_blockptr(*eb_ret, slot);
gen = btrfs_node_ptr_generation(*eb_ret, slot);
parent_level = btrfs_header_level(*eb_ret);
- btrfs_node_key_to_cpu(*eb_ret, &first_key, slot);
+ btrfs_node_key_to_cpu(*eb_ret, &check.first_key, slot);
+ check.has_first_key = true;
+ check.level = parent_level - 1;
+ check.transid = gen;
+ check.owner_root = root->root_key.objectid;
/*
* If we need to read an extent buffer from disk and we are holding locks
@@ -1439,7 +1570,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
* parents (shared tree blocks).
*/
if (btrfs_verify_level_key(tmp,
- parent_level - 1, &first_key, gen)) {
+ parent_level - 1, &check.first_key, gen)) {
free_extent_buffer(tmp);
return -EUCLEAN;
}
@@ -1456,7 +1587,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
btrfs_unlock_up_safe(p, level + 1);
/* now we're allowed to do a blocking uptodate check */
- ret = btrfs_read_extent_buffer(tmp, gen, parent_level - 1, &first_key);
+ ret = btrfs_read_extent_buffer(tmp, &check);
if (ret) {
free_extent_buffer(tmp);
btrfs_release_path(p);
@@ -1486,8 +1617,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
if (p->reada != READA_NONE)
reada_for_search(fs_info, p, level, slot, key->objectid);
- tmp = read_tree_block(fs_info, blocknr, root->root_key.objectid,
- gen, parent_level - 1, &first_key);
+ tmp = read_tree_block(fs_info, blocknr, &check);
if (IS_ERR(tmp)) {
btrfs_release_path(p);
return PTR_ERR(tmp);
@@ -1918,6 +2048,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int min_write_lock_level;
int prev_cmp;
+ might_sleep();
+
lowest_level = p->lowest_level;
WARN_ON(lowest_level && ins_len > 0);
WARN_ON(p->nodes[0] != NULL);
@@ -2341,7 +2473,7 @@ int btrfs_search_backwards(struct btrfs_root *root, struct btrfs_key *key,
return ret;
}
-/**
+/*
* Search for a valid slot for the given path.
*
* @root: The root node of the tree.
@@ -2400,7 +2532,7 @@ static void fixup_low_keys(struct btrfs_path *path,
break;
t = path->nodes[i];
ret = btrfs_tree_mod_log_insert_key(t, tslot,
- BTRFS_MOD_LOG_KEY_REPLACE, GFP_ATOMIC);
+ BTRFS_MOD_LOG_KEY_REPLACE);
BUG_ON(ret < 0);
btrfs_set_node_key(t, key, tslot);
btrfs_mark_buffer_dirty(path->nodes[i]);
@@ -2569,8 +2701,8 @@ static int push_node_left(struct btrfs_trans_handle *trans,
return ret;
}
copy_extent_buffer(dst, src,
- btrfs_node_key_ptr_offset(dst_nritems),
- btrfs_node_key_ptr_offset(0),
+ btrfs_node_key_ptr_offset(dst, dst_nritems),
+ btrfs_node_key_ptr_offset(src, 0),
push_items * sizeof(struct btrfs_key_ptr));
if (push_items < src_nritems) {
@@ -2578,8 +2710,8 @@ static int push_node_left(struct btrfs_trans_handle *trans,
* Don't call btrfs_tree_mod_log_insert_move() here, key removal
* was already fully logged by btrfs_tree_mod_log_eb_copy() above.
*/
- memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
- btrfs_node_key_ptr_offset(push_items),
+ memmove_extent_buffer(src, btrfs_node_key_ptr_offset(src, 0),
+ btrfs_node_key_ptr_offset(src, push_items),
(src_nritems - push_items) *
sizeof(struct btrfs_key_ptr));
}
@@ -2639,8 +2771,8 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
}
ret = btrfs_tree_mod_log_insert_move(dst, push_items, 0, dst_nritems);
BUG_ON(ret < 0);
- memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items),
- btrfs_node_key_ptr_offset(0),
+ memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(dst, push_items),
+ btrfs_node_key_ptr_offset(dst, 0),
(dst_nritems) *
sizeof(struct btrfs_key_ptr));
@@ -2651,8 +2783,8 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
return ret;
}
copy_extent_buffer(dst, src,
- btrfs_node_key_ptr_offset(0),
- btrfs_node_key_ptr_offset(src_nritems - push_items),
+ btrfs_node_key_ptr_offset(dst, 0),
+ btrfs_node_key_ptr_offset(src, src_nritems - push_items),
push_items * sizeof(struct btrfs_key_ptr));
btrfs_set_header_nritems(src, src_nritems - push_items);
@@ -2755,13 +2887,13 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
BUG_ON(ret < 0);
}
memmove_extent_buffer(lower,
- btrfs_node_key_ptr_offset(slot + 1),
- btrfs_node_key_ptr_offset(slot),
+ btrfs_node_key_ptr_offset(lower, slot + 1),
+ btrfs_node_key_ptr_offset(lower, slot),
(nritems - slot) * sizeof(struct btrfs_key_ptr));
}
if (level) {
ret = btrfs_tree_mod_log_insert_key(lower, slot,
- BTRFS_MOD_LOG_KEY_ADD, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_ADD);
BUG_ON(ret < 0);
}
btrfs_set_node_key(lower, key, slot);
@@ -2838,8 +2970,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
return ret;
}
copy_extent_buffer(split, c,
- btrfs_node_key_ptr_offset(0),
- btrfs_node_key_ptr_offset(mid),
+ btrfs_node_key_ptr_offset(split, 0),
+ btrfs_node_key_ptr_offset(c, mid),
(c_nritems - mid) * sizeof(struct btrfs_key_ptr));
btrfs_set_header_nritems(split, c_nritems - mid);
btrfs_set_header_nritems(c, mid);
@@ -2979,25 +3111,17 @@ static noinline int __push_leaf_right(struct btrfs_path *path,
/* make room in the right data area */
data_end = leaf_data_end(right);
- memmove_extent_buffer(right,
- BTRFS_LEAF_DATA_OFFSET + data_end - push_space,
- BTRFS_LEAF_DATA_OFFSET + data_end,
- BTRFS_LEAF_DATA_SIZE(fs_info) - data_end);
+ memmove_leaf_data(right, data_end - push_space, data_end,
+ BTRFS_LEAF_DATA_SIZE(fs_info) - data_end);
/* copy from the left data area */
- copy_extent_buffer(right, left, BTRFS_LEAF_DATA_OFFSET +
- BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
- BTRFS_LEAF_DATA_OFFSET + leaf_data_end(left),
- push_space);
+ copy_leaf_data(right, left, BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
+ leaf_data_end(left), push_space);
- memmove_extent_buffer(right, btrfs_item_nr_offset(push_items),
- btrfs_item_nr_offset(0),
- right_nritems * sizeof(struct btrfs_item));
+ memmove_leaf_items(right, push_items, 0, right_nritems);
/* copy the items from left to right */
- copy_extent_buffer(right, left, btrfs_item_nr_offset(0),
- btrfs_item_nr_offset(left_nritems - push_items),
- push_items * sizeof(struct btrfs_item));
+ copy_leaf_items(right, left, 0, left_nritems - push_items, push_items);
/* update the item pointers */
btrfs_init_map_token(&token, right);
@@ -3189,19 +3313,13 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,
WARN_ON(!empty && push_items == btrfs_header_nritems(right));
/* push data from right to left */
- copy_extent_buffer(left, right,
- btrfs_item_nr_offset(btrfs_header_nritems(left)),
- btrfs_item_nr_offset(0),
- push_items * sizeof(struct btrfs_item));
+ copy_leaf_items(left, right, btrfs_header_nritems(left), 0, push_items);
push_space = BTRFS_LEAF_DATA_SIZE(fs_info) -
btrfs_item_offset(right, push_items - 1);
- copy_extent_buffer(left, right, BTRFS_LEAF_DATA_OFFSET +
- leaf_data_end(left) - push_space,
- BTRFS_LEAF_DATA_OFFSET +
- btrfs_item_offset(right, push_items - 1),
- push_space);
+ copy_leaf_data(left, right, leaf_data_end(left) - push_space,
+ btrfs_item_offset(right, push_items - 1), push_space);
old_left_nritems = btrfs_header_nritems(left);
BUG_ON(old_left_nritems <= 0);
@@ -3224,15 +3342,12 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,
if (push_items < right_nritems) {
push_space = btrfs_item_offset(right, push_items - 1) -
leaf_data_end(right);
- memmove_extent_buffer(right, BTRFS_LEAF_DATA_OFFSET +
- BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
- BTRFS_LEAF_DATA_OFFSET +
- leaf_data_end(right), push_space);
+ memmove_leaf_data(right,
+ BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
+ leaf_data_end(right), push_space);
- memmove_extent_buffer(right, btrfs_item_nr_offset(0),
- btrfs_item_nr_offset(push_items),
- (btrfs_header_nritems(right) - push_items) *
- sizeof(struct btrfs_item));
+ memmove_leaf_items(right, 0, push_items,
+ btrfs_header_nritems(right) - push_items);
}
btrfs_init_map_token(&token, right);
@@ -3364,14 +3479,10 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(right, nritems);
data_copy_size = btrfs_item_data_end(l, mid) - leaf_data_end(l);
- copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
- btrfs_item_nr_offset(mid),
- nritems * sizeof(struct btrfs_item));
+ copy_leaf_items(right, l, 0, mid, nritems);
- copy_extent_buffer(right, l,
- BTRFS_LEAF_DATA_OFFSET + BTRFS_LEAF_DATA_SIZE(fs_info) -
- data_copy_size, BTRFS_LEAF_DATA_OFFSET +
- leaf_data_end(l), data_copy_size);
+ copy_leaf_data(right, l, BTRFS_LEAF_DATA_SIZE(fs_info) - data_copy_size,
+ leaf_data_end(l), data_copy_size);
rt_data_off = BTRFS_LEAF_DATA_SIZE(fs_info) - btrfs_item_data_end(l, mid);
@@ -3741,9 +3852,7 @@ static noinline int split_item(struct btrfs_path *path,
nritems = btrfs_header_nritems(leaf);
if (slot != nritems) {
/* shift the items */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
- btrfs_item_nr_offset(slot),
- (nritems - slot) * sizeof(struct btrfs_item));
+ memmove_leaf_items(leaf, slot + 1, slot, nritems - slot);
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -3854,9 +3963,8 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
/* shift the data */
if (from_end) {
- memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
- data_end + size_diff, BTRFS_LEAF_DATA_OFFSET +
- data_end, old_data_start + new_size - data_end);
+ memmove_leaf_data(leaf, data_end + size_diff, data_end,
+ old_data_start + new_size - data_end);
} else {
struct btrfs_disk_key disk_key;
u64 offset;
@@ -3881,9 +3989,8 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
}
}
- memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
- data_end + size_diff, BTRFS_LEAF_DATA_OFFSET +
- data_end, old_data_start - data_end);
+ memmove_leaf_data(leaf, data_end + size_diff, data_end,
+ old_data_start - data_end);
offset = btrfs_disk_key_offset(&disk_key);
btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
@@ -3948,9 +4055,8 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
}
/* shift the data */
- memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
- data_end - data_size, BTRFS_LEAF_DATA_OFFSET +
- data_end, old_data - data_end);
+ memmove_leaf_data(leaf, data_end - data_size, data_end,
+ old_data - data_end);
data_end = old_data;
old_size = btrfs_item_size(leaf, slot);
@@ -3963,14 +4069,15 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
}
}
-/**
- * setup_items_for_insert - Helper called before inserting one or more items
- * to a leaf. Main purpose is to save stack depth by doing the bulk of the work
- * in a function that doesn't call btrfs_search_slot
+/*
+ * Make space in the node before inserting one or more items.
*
* @root: root we are inserting items to
* @path: points to the leaf/slot where we are going to insert new items
* @batch: information about the batch of items to insert
+ *
+ * Main purpose is to save stack depth by doing the bulk of the work in a
+ * function that doesn't call btrfs_search_slot
*/
static void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
const struct btrfs_item_batch *batch)
@@ -4033,15 +4140,11 @@ static void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *p
ioff - batch->total_data_size);
}
/* shift the items */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + batch->nr),
- btrfs_item_nr_offset(slot),
- (nritems - slot) * sizeof(struct btrfs_item));
+ memmove_leaf_items(leaf, slot + batch->nr, slot, nritems - slot);
/* shift the data */
- memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
- data_end - batch->total_data_size,
- BTRFS_LEAF_DATA_OFFSET + data_end,
- old_data - data_end);
+ memmove_leaf_data(leaf, data_end - batch->total_data_size,
+ data_end, old_data - data_end);
data_end = old_data;
}
@@ -4195,13 +4298,13 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
BUG_ON(ret < 0);
}
memmove_extent_buffer(parent,
- btrfs_node_key_ptr_offset(slot),
- btrfs_node_key_ptr_offset(slot + 1),
+ btrfs_node_key_ptr_offset(parent, slot),
+ btrfs_node_key_ptr_offset(parent, slot + 1),
sizeof(struct btrfs_key_ptr) *
(nritems - slot - 1));
} else if (level) {
ret = btrfs_tree_mod_log_insert_key(parent, slot,
- BTRFS_MOD_LOG_KEY_REMOVE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REMOVE);
BUG_ON(ret < 0);
}
@@ -4276,10 +4379,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
for (i = 0; i < nr; i++)
dsize += btrfs_item_size(leaf, slot + i);
- memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
- data_end + dsize,
- BTRFS_LEAF_DATA_OFFSET + data_end,
- last_off - data_end);
+ memmove_leaf_data(leaf, data_end + dsize, data_end,
+ last_off - data_end);
btrfs_init_map_token(&token, leaf);
for (i = slot + nr; i < nritems; i++) {
@@ -4289,10 +4390,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
btrfs_set_token_item_offset(&token, i, ioff + dsize);
}
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),
- btrfs_item_nr_offset(slot + nr),
- sizeof(struct btrfs_item) *
- (nritems - slot - nr));
+ memmove_leaf_items(leaf, slot, slot + nr, nritems - slot - nr);
}
btrfs_set_header_nritems(leaf, nritems - nr);
nritems -= nr;
@@ -4647,7 +4745,12 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
int ret;
int i;
- ASSERT(!path->nowait);
+ /*
+ * The nowait semantics are used only for write paths, where we don't
+ * use the tree mod log and sequence numbers.
+ */
+ if (time_seq)
+ ASSERT(!path->nowait);
nritems = btrfs_header_nritems(path->nodes[0]);
if (nritems == 0)
@@ -4667,7 +4770,14 @@ again:
if (path->need_commit_sem) {
path->need_commit_sem = 0;
need_commit_sem = true;
- down_read(&fs_info->commit_root_sem);
+ if (path->nowait) {
+ if (!down_read_trylock(&fs_info->commit_root_sem)) {
+ ret = -EAGAIN;
+ goto done;
+ }
+ } else {
+ down_read(&fs_info->commit_root_sem);
+ }
}
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
}
@@ -4743,7 +4853,7 @@ again:
next = c;
ret = read_block_for_search(root, path, &next, level,
slot, &key);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN && !path->nowait)
goto again;
if (ret < 0) {
@@ -4753,6 +4863,10 @@ again:
if (!path->skip_locking) {
ret = btrfs_try_tree_read_lock(next);
+ if (!ret && path->nowait) {
+ ret = -EAGAIN;
+ goto done;
+ }
if (!ret && time_seq) {
/*
* If we don't get the lock, we may be racing
@@ -4783,7 +4897,7 @@ again:
ret = read_block_for_search(root, path, &next, level,
0, &key);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN && !path->nowait)
goto again;
if (ret < 0) {
@@ -4791,8 +4905,16 @@ again:
goto done;
}
- if (!path->skip_locking)
- btrfs_tree_read_lock(next);
+ if (!path->skip_locking) {
+ if (path->nowait) {
+ if (!btrfs_try_tree_read_lock(next)) {
+ ret = -EAGAIN;
+ goto done;
+ }
+ } else {
+ btrfs_tree_read_lock(next);
+ }
+ }
}
ret = 0;
done:
@@ -4810,6 +4932,14 @@ done:
return ret;
}
+int btrfs_next_old_item(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq)
+{
+ path->slots[0]++;
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0]))
+ return btrfs_next_old_leaf(root, path, time_seq);
+ return 0;
+}
+
/*
* this uses btrfs_prev_leaf to walk backwards in the tree, and keeps
* searching until it gets past min_objectid or finds an item of 'type'
@@ -4893,3 +5023,18 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
}
return 1;
}
+
+int __init btrfs_ctree_init(void)
+{
+ btrfs_path_cachep = kmem_cache_create("btrfs_path",
+ sizeof(struct btrfs_path), 0,
+ SLAB_MEM_SPREAD, NULL);
+ if (!btrfs_path_cachep)
+ return -ENOMEM;
+ return 0;
+}
+
+void __cold btrfs_ctree_exit(void)
+{
+ kmem_cache_destroy(btrfs_path_cachep);
+}
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f677b49df8ae..6965703a81b6 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -28,12 +28,15 @@
#include <linux/refcount.h>
#include <linux/crc32c.h>
#include <linux/iomap.h>
+#include <linux/fscrypt.h>
#include "extent-io-tree.h"
#include "extent_io.h"
#include "extent_map.h"
#include "async-thread.h"
#include "block-rsv.h"
#include "locking.h"
+#include "misc.h"
+#include "fs.h"
struct btrfs_trans_handle;
struct btrfs_transaction;
@@ -41,10 +44,6 @@ struct btrfs_pending_snapshot;
struct btrfs_delayed_ref_root;
struct btrfs_space_info;
struct btrfs_block_group;
-extern struct kmem_cache *btrfs_trans_handle_cachep;
-extern struct kmem_cache *btrfs_path_cachep;
-extern struct kmem_cache *btrfs_free_space_cachep;
-extern struct kmem_cache *btrfs_free_space_bitmap_cachep;
struct btrfs_ordered_sum;
struct btrfs_ref;
struct btrfs_bio;
@@ -55,340 +54,6 @@ struct btrfs_balance_control;
struct btrfs_delayed_root;
struct reloc_control;
-#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
-
-/*
- * Maximum number of mirrors that can be available for all profiles counting
- * the target device of dev-replace as one. During an active device replace
- * procedure, the target device of the copy operation is a mirror for the
- * filesystem data as well that can be used to read data in order to repair
- * read errors on other disks.
- *
- * Current value is derived from RAID1C4 with 4 copies.
- */
-#define BTRFS_MAX_MIRRORS (4 + 1)
-
-#define BTRFS_MAX_LEVEL 8
-
-#define BTRFS_OLDEST_GENERATION 0ULL
-
-/*
- * we can actually store much bigger names, but lets not confuse the rest
- * of linux
- */
-#define BTRFS_NAME_LEN 255
-
-/*
- * Theoretical limit is larger, but we keep this down to a sane
- * value. That should limit greatly the possibility of collisions on
- * inode ref items.
- */
-#define BTRFS_LINK_MAX 65535U
-
-#define BTRFS_EMPTY_DIR_SIZE 0
-
-/* ioprio of readahead is set to idle */
-#define BTRFS_IOPRIO_READA (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0))
-
-#define BTRFS_DIRTY_METADATA_THRESH SZ_32M
-
-/*
- * Use large batch size to reduce overhead of metadata updates. On the reader
- * side, we only read it when we are close to ENOSPC and the read overhead is
- * mostly related to the number of CPUs, so it is OK to use arbitrary large
- * value here.
- */
-#define BTRFS_TOTAL_BYTES_PINNED_BATCH SZ_128M
-
-#define BTRFS_MAX_EXTENT_SIZE SZ_128M
-
-/*
- * Deltas are an effective way to populate global statistics. Give macro names
- * to make it clear what we're doing. An example is discard_extents in
- * btrfs_free_space_ctl.
- */
-#define BTRFS_STAT_NR_ENTRIES 2
-#define BTRFS_STAT_CURR 0
-#define BTRFS_STAT_PREV 1
-
-static inline unsigned long btrfs_chunk_item_size(int num_stripes)
-{
- BUG_ON(num_stripes == 0);
- return sizeof(struct btrfs_chunk) +
- sizeof(struct btrfs_stripe) * (num_stripes - 1);
-}
-
-/*
- * Runtime (in-memory) states of filesystem
- */
-enum {
- /* Global indicator of serious filesystem errors */
- BTRFS_FS_STATE_ERROR,
- /*
- * Filesystem is being remounted, allow to skip some operations, like
- * defrag
- */
- BTRFS_FS_STATE_REMOUNTING,
- /* Filesystem in RO mode */
- BTRFS_FS_STATE_RO,
- /* Track if a transaction abort has been reported on this filesystem */
- BTRFS_FS_STATE_TRANS_ABORTED,
- /*
- * Bio operations should be blocked on this filesystem because a source
- * or target device is being destroyed as part of a device replace
- */
- BTRFS_FS_STATE_DEV_REPLACING,
- /* The btrfs_fs_info created for self-tests */
- BTRFS_FS_STATE_DUMMY_FS_INFO,
-
- BTRFS_FS_STATE_NO_CSUMS,
-
- /* Indicates there was an error cleaning up a log tree. */
- BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
-
- BTRFS_FS_STATE_COUNT
-};
-
-#define BTRFS_BACKREF_REV_MAX 256
-#define BTRFS_BACKREF_REV_SHIFT 56
-#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \
- BTRFS_BACKREF_REV_SHIFT)
-
-#define BTRFS_OLD_BACKREF_REV 0
-#define BTRFS_MIXED_BACKREF_REV 1
-
-/*
- * every tree block (leaf or node) starts with this header.
- */
-struct btrfs_header {
- /* these first four must match the super block */
- u8 csum[BTRFS_CSUM_SIZE];
- u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
- __le64 bytenr; /* which block this node is supposed to live in */
- __le64 flags;
-
- /* allowed to be different from the super from here on down */
- u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
- __le64 generation;
- __le64 owner;
- __le32 nritems;
- u8 level;
-} __attribute__ ((__packed__));
-
-/*
- * this is a very generous portion of the super block, giving us
- * room to translate 14 chunks with 3 stripes each.
- */
-#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
-
-/*
- * just in case we somehow lose the roots and are not able to mount,
- * we store an array of the roots from previous transactions
- * in the super.
- */
-#define BTRFS_NUM_BACKUP_ROOTS 4
-struct btrfs_root_backup {
- __le64 tree_root;
- __le64 tree_root_gen;
-
- __le64 chunk_root;
- __le64 chunk_root_gen;
-
- __le64 extent_root;
- __le64 extent_root_gen;
-
- __le64 fs_root;
- __le64 fs_root_gen;
-
- __le64 dev_root;
- __le64 dev_root_gen;
-
- __le64 csum_root;
- __le64 csum_root_gen;
-
- __le64 total_bytes;
- __le64 bytes_used;
- __le64 num_devices;
- /* future */
- __le64 unused_64[4];
-
- u8 tree_root_level;
- u8 chunk_root_level;
- u8 extent_root_level;
- u8 fs_root_level;
- u8 dev_root_level;
- u8 csum_root_level;
- /* future and to align */
- u8 unused_8[10];
-} __attribute__ ((__packed__));
-
-#define BTRFS_SUPER_INFO_OFFSET SZ_64K
-#define BTRFS_SUPER_INFO_SIZE 4096
-
-/*
- * The reserved space at the beginning of each device.
- * It covers the primary super block and leaves space for potential use by other
- * tools like bootloaders or to lower potential damage of accidental overwrite.
- */
-#define BTRFS_DEVICE_RANGE_RESERVED (SZ_1M)
-
-/*
- * the super block basically lists the main trees of the FS
- * it currently lacks any block count etc etc
- */
-struct btrfs_super_block {
- /* the first 4 fields must match struct btrfs_header */
- u8 csum[BTRFS_CSUM_SIZE];
- /* FS specific UUID, visible to user */
- u8 fsid[BTRFS_FSID_SIZE];
- __le64 bytenr; /* this block number */
- __le64 flags;
-
- /* allowed to be different from the btrfs_header from here own down */
- __le64 magic;
- __le64 generation;
- __le64 root;
- __le64 chunk_root;
- __le64 log_root;
-
- /*
- * This member has never been utilized since the very beginning, thus
- * it's always 0 regardless of kernel version. We always use
- * generation + 1 to read log tree root. So here we mark it deprecated.
- */
- __le64 __unused_log_root_transid;
- __le64 total_bytes;
- __le64 bytes_used;
- __le64 root_dir_objectid;
- __le64 num_devices;
- __le32 sectorsize;
- __le32 nodesize;
- __le32 __unused_leafsize;
- __le32 stripesize;
- __le32 sys_chunk_array_size;
- __le64 chunk_root_generation;
- __le64 compat_flags;
- __le64 compat_ro_flags;
- __le64 incompat_flags;
- __le16 csum_type;
- u8 root_level;
- u8 chunk_root_level;
- u8 log_root_level;
- struct btrfs_dev_item dev_item;
-
- char label[BTRFS_LABEL_SIZE];
-
- __le64 cache_generation;
- __le64 uuid_tree_generation;
-
- /* the UUID written into btree blocks */
- u8 metadata_uuid[BTRFS_FSID_SIZE];
-
- /* future expansion */
- u8 reserved8[8];
- __le64 reserved[27];
- u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
- struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
-
- /* Padded to 4096 bytes */
- u8 padding[565];
-} __attribute__ ((__packed__));
-static_assert(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE);
-
-/*
- * Compat flags that we support. If any incompat flags are set other than the
- * ones specified below then we will fail to mount
- */
-#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
-#define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL
-#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL
-
-#define BTRFS_FEATURE_COMPAT_RO_SUPP \
- (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \
- BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID | \
- BTRFS_FEATURE_COMPAT_RO_VERITY | \
- BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE)
-
-#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
-#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL
-
-#ifdef CONFIG_BTRFS_DEBUG
-/*
- * Extent tree v2 supported only with CONFIG_BTRFS_DEBUG
- */
-#define BTRFS_FEATURE_INCOMPAT_SUPP \
- (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
- BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
- BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
- BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
- BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
- BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
- BTRFS_FEATURE_INCOMPAT_RAID56 | \
- BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
- BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
- BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
- BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
- BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
- BTRFS_FEATURE_INCOMPAT_ZONED | \
- BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2)
-#else
-#define BTRFS_FEATURE_INCOMPAT_SUPP \
- (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
- BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
- BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
- BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
- BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
- BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
- BTRFS_FEATURE_INCOMPAT_RAID56 | \
- BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
- BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
- BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
- BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
- BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
- BTRFS_FEATURE_INCOMPAT_ZONED)
-#endif
-
-#define BTRFS_FEATURE_INCOMPAT_SAFE_SET \
- (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
-#define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL
-
-/*
- * A leaf is full of items. offset and size tell us where to find
- * the item in the leaf (relative to the start of the data area)
- */
-struct btrfs_item {
- struct btrfs_disk_key key;
- __le32 offset;
- __le32 size;
-} __attribute__ ((__packed__));
-
-/*
- * leaves have an item area and a data area:
- * [item0, item1....itemN] [free space] [dataN...data1, data0]
- *
- * The data is separate from the items to get the keys closer together
- * during searches.
- */
-struct btrfs_leaf {
- struct btrfs_header header;
- struct btrfs_item items[];
-} __attribute__ ((__packed__));
-
-/*
- * all non-leaf blocks are nodes, they hold only keys and pointers to
- * other blocks
- */
-struct btrfs_key_ptr {
- struct btrfs_disk_key key;
- __le64 blockptr;
- __le64 generation;
-} __attribute__ ((__packed__));
-
-struct btrfs_node {
- struct btrfs_header header;
- struct btrfs_key_ptr ptrs[];
-} __attribute__ ((__packed__));
-
/* Read ahead values for struct btrfs_path.reada */
enum {
READA_NONE,
@@ -447,712 +112,6 @@ struct btrfs_path {
unsigned int nowait:1;
};
-struct btrfs_dev_replace {
- u64 replace_state; /* see #define above */
- time64_t time_started; /* seconds since 1-Jan-1970 */
- time64_t time_stopped; /* seconds since 1-Jan-1970 */
- atomic64_t num_write_errors;
- atomic64_t num_uncorrectable_read_errors;
-
- u64 cursor_left;
- u64 committed_cursor_left;
- u64 cursor_left_last_write_of_item;
- u64 cursor_right;
-
- u64 cont_reading_from_srcdev_mode; /* see #define above */
-
- int is_valid;
- int item_needs_writeback;
- struct btrfs_device *srcdev;
- struct btrfs_device *tgtdev;
-
- struct mutex lock_finishing_cancel_unmount;
- struct rw_semaphore rwsem;
-
- struct btrfs_scrub_progress scrub_progress;
-
- struct percpu_counter bio_counter;
- wait_queue_head_t replace_wait;
-};
-
-/*
- * free clusters are used to claim free space in relatively large chunks,
- * allowing us to do less seeky writes. They are used for all metadata
- * allocations. In ssd_spread mode they are also used for data allocations.
- */
-struct btrfs_free_cluster {
- spinlock_t lock;
- spinlock_t refill_lock;
- struct rb_root root;
-
- /* largest extent in this cluster */
- u64 max_size;
-
- /* first extent starting offset */
- u64 window_start;
-
- /* We did a full search and couldn't create a cluster */
- bool fragmented;
-
- struct btrfs_block_group *block_group;
- /*
- * when a cluster is allocated from a block group, we put the
- * cluster onto a list in the block group so that it can
- * be freed before the block group is freed.
- */
- struct list_head block_group_list;
-};
-
-/* Discard control. */
-/*
- * Async discard uses multiple lists to differentiate the discard filter
- * parameters. Index 0 is for completely free block groups where we need to
- * ensure the entire block group is trimmed without being lossy. Indices
- * afterwards represent monotonically decreasing discard filter sizes to
- * prioritize what should be discarded next.
- */
-#define BTRFS_NR_DISCARD_LISTS 3
-#define BTRFS_DISCARD_INDEX_UNUSED 0
-#define BTRFS_DISCARD_INDEX_START 1
-
-struct btrfs_discard_ctl {
- struct workqueue_struct *discard_workers;
- struct delayed_work work;
- spinlock_t lock;
- struct btrfs_block_group *block_group;
- struct list_head discard_list[BTRFS_NR_DISCARD_LISTS];
- u64 prev_discard;
- u64 prev_discard_time;
- atomic_t discardable_extents;
- atomic64_t discardable_bytes;
- u64 max_discard_size;
- u64 delay_ms;
- u32 iops_limit;
- u32 kbps_limit;
- u64 discard_extent_bytes;
- u64 discard_bitmap_bytes;
- atomic64_t discard_bytes_saved;
-};
-
-enum {
- BTRFS_FS_CLOSING_START,
- BTRFS_FS_CLOSING_DONE,
- BTRFS_FS_LOG_RECOVERING,
- BTRFS_FS_OPEN,
- BTRFS_FS_QUOTA_ENABLED,
- BTRFS_FS_UPDATE_UUID_TREE_GEN,
- BTRFS_FS_CREATING_FREE_SPACE_TREE,
- BTRFS_FS_BTREE_ERR,
- BTRFS_FS_LOG1_ERR,
- BTRFS_FS_LOG2_ERR,
- BTRFS_FS_QUOTA_OVERRIDE,
- /* Used to record internally whether fs has been frozen */
- BTRFS_FS_FROZEN,
- /*
- * Indicate that balance has been set up from the ioctl and is in the
- * main phase. The fs_info::balance_ctl is initialized.
- */
- BTRFS_FS_BALANCE_RUNNING,
-
- /*
- * Indicate that relocation of a chunk has started, it's set per chunk
- * and is toggled between chunks.
- */
- BTRFS_FS_RELOC_RUNNING,
-
- /* Indicate that the cleaner thread is awake and doing something. */
- BTRFS_FS_CLEANER_RUNNING,
-
- /*
- * The checksumming has an optimized version and is considered fast,
- * so we don't need to offload checksums to workqueues.
- */
- BTRFS_FS_CSUM_IMPL_FAST,
-
- /* Indicate that the discard workqueue can service discards. */
- BTRFS_FS_DISCARD_RUNNING,
-
- /* Indicate that we need to cleanup space cache v1 */
- BTRFS_FS_CLEANUP_SPACE_CACHE_V1,
-
- /* Indicate that we can't trust the free space tree for caching yet */
- BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED,
-
- /* Indicate whether there are any tree modification log users */
- BTRFS_FS_TREE_MOD_LOG_USERS,
-
- /* Indicate that we want the transaction kthread to commit right now. */
- BTRFS_FS_COMMIT_TRANS,
-
- /* Indicate we have half completed snapshot deletions pending. */
- BTRFS_FS_UNFINISHED_DROPS,
-
- /* Indicate we have to finish a zone to do next allocation. */
- BTRFS_FS_NEED_ZONE_FINISH,
-
-#if BITS_PER_LONG == 32
- /* Indicate if we have error/warn message printed on 32bit systems */
- BTRFS_FS_32BIT_ERROR,
- BTRFS_FS_32BIT_WARN,
-#endif
-};
-
-/*
- * Exclusive operations (device replace, resize, device add/remove, balance)
- */
-enum btrfs_exclusive_operation {
- BTRFS_EXCLOP_NONE,
- BTRFS_EXCLOP_BALANCE_PAUSED,
- BTRFS_EXCLOP_BALANCE,
- BTRFS_EXCLOP_DEV_ADD,
- BTRFS_EXCLOP_DEV_REMOVE,
- BTRFS_EXCLOP_DEV_REPLACE,
- BTRFS_EXCLOP_RESIZE,
- BTRFS_EXCLOP_SWAP_ACTIVATE,
-};
-
-/* Store data about transaction commits, exported via sysfs. */
-struct btrfs_commit_stats {
- /* Total number of commits */
- u64 commit_count;
- /* The maximum commit duration so far in ns */
- u64 max_commit_dur;
- /* The last commit duration in ns */
- u64 last_commit_dur;
- /* The total commit duration in ns */
- u64 total_commit_dur;
-};
-
-struct btrfs_fs_info {
- u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
- unsigned long flags;
- struct btrfs_root *tree_root;
- struct btrfs_root *chunk_root;
- struct btrfs_root *dev_root;
- struct btrfs_root *fs_root;
- struct btrfs_root *quota_root;
- struct btrfs_root *uuid_root;
- struct btrfs_root *data_reloc_root;
- struct btrfs_root *block_group_root;
-
- /* the log root tree is a directory of all the other log roots */
- struct btrfs_root *log_root_tree;
-
- /* The tree that holds the global roots (csum, extent, etc) */
- rwlock_t global_root_lock;
- struct rb_root global_root_tree;
-
- spinlock_t fs_roots_radix_lock;
- struct radix_tree_root fs_roots_radix;
-
- /* block group cache stuff */
- rwlock_t block_group_cache_lock;
- struct rb_root_cached block_group_cache_tree;
-
- /* keep track of unallocated space */
- atomic64_t free_chunk_space;
-
- /* Track ranges which are used by log trees blocks/logged data extents */
- struct extent_io_tree excluded_extents;
-
- /* logical->physical extent mapping */
- struct extent_map_tree mapping_tree;
-
- /*
- * block reservation for extent, checksum, root tree and
- * delayed dir index item
- */
- struct btrfs_block_rsv global_block_rsv;
- /* block reservation for metadata operations */
- struct btrfs_block_rsv trans_block_rsv;
- /* block reservation for chunk tree */
- struct btrfs_block_rsv chunk_block_rsv;
- /* block reservation for delayed operations */
- struct btrfs_block_rsv delayed_block_rsv;
- /* block reservation for delayed refs */
- struct btrfs_block_rsv delayed_refs_rsv;
-
- struct btrfs_block_rsv empty_block_rsv;
-
- u64 generation;
- u64 last_trans_committed;
- /*
- * Generation of the last transaction used for block group relocation
- * since the filesystem was last mounted (or 0 if none happened yet).
- * Must be written and read while holding btrfs_fs_info::commit_root_sem.
- */
- u64 last_reloc_trans;
- u64 avg_delayed_ref_runtime;
-
- /*
- * this is updated to the current trans every time a full commit
- * is required instead of the faster short fsync log commits
- */
- u64 last_trans_log_full_commit;
- unsigned long mount_opt;
- /*
- * Track requests for actions that need to be done during transaction
- * commit (like for some mount options).
- */
- unsigned long pending_changes;
- unsigned long compress_type:4;
- unsigned int compress_level;
- u32 commit_interval;
- /*
- * It is a suggestive number, the read side is safe even it gets a
- * wrong number because we will write out the data into a regular
- * extent. The write side(mount/remount) is under ->s_umount lock,
- * so it is also safe.
- */
- u64 max_inline;
-
- struct btrfs_transaction *running_transaction;
- wait_queue_head_t transaction_throttle;
- wait_queue_head_t transaction_wait;
- wait_queue_head_t transaction_blocked_wait;
- wait_queue_head_t async_submit_wait;
-
- /*
- * Used to protect the incompat_flags, compat_flags, compat_ro_flags
- * when they are updated.
- *
- * Because we do not clear the flags for ever, so we needn't use
- * the lock on the read side.
- *
- * We also needn't use the lock when we mount the fs, because
- * there is no other task which will update the flag.
- */
- spinlock_t super_lock;
- struct btrfs_super_block *super_copy;
- struct btrfs_super_block *super_for_commit;
- struct super_block *sb;
- struct inode *btree_inode;
- struct mutex tree_log_mutex;
- struct mutex transaction_kthread_mutex;
- struct mutex cleaner_mutex;
- struct mutex chunk_mutex;
-
- /*
- * this is taken to make sure we don't set block groups ro after
- * the free space cache has been allocated on them
- */
- struct mutex ro_block_group_mutex;
-
- /* this is used during read/modify/write to make sure
- * no two ios are trying to mod the same stripe at the same
- * time
- */
- struct btrfs_stripe_hash_table *stripe_hash_table;
-
- /*
- * this protects the ordered operations list only while we are
- * processing all of the entries on it. This way we make
- * sure the commit code doesn't find the list temporarily empty
- * because another function happens to be doing non-waiting preflush
- * before jumping into the main commit.
- */
- struct mutex ordered_operations_mutex;
-
- struct rw_semaphore commit_root_sem;
-
- struct rw_semaphore cleanup_work_sem;
-
- struct rw_semaphore subvol_sem;
-
- spinlock_t trans_lock;
- /*
- * the reloc mutex goes with the trans lock, it is taken
- * during commit to protect us from the relocation code
- */
- struct mutex reloc_mutex;
-
- struct list_head trans_list;
- struct list_head dead_roots;
- struct list_head caching_block_groups;
-
- spinlock_t delayed_iput_lock;
- struct list_head delayed_iputs;
- atomic_t nr_delayed_iputs;
- wait_queue_head_t delayed_iputs_wait;
-
- atomic64_t tree_mod_seq;
-
- /* this protects tree_mod_log and tree_mod_seq_list */
- rwlock_t tree_mod_log_lock;
- struct rb_root tree_mod_log;
- struct list_head tree_mod_seq_list;
-
- atomic_t async_delalloc_pages;
-
- /*
- * this is used to protect the following list -- ordered_roots.
- */
- spinlock_t ordered_root_lock;
-
- /*
- * all fs/file tree roots in which there are data=ordered extents
- * pending writeback are added into this list.
- *
- * these can span multiple transactions and basically include
- * every dirty data page that isn't from nodatacow
- */
- struct list_head ordered_roots;
-
- struct mutex delalloc_root_mutex;
- spinlock_t delalloc_root_lock;
- /* all fs/file tree roots that have delalloc inodes. */
- struct list_head delalloc_roots;
-
- /*
- * there is a pool of worker threads for checksumming during writes
- * and a pool for checksumming after reads. This is because readers
- * can run with FS locks held, and the writers may be waiting for
- * those locks. We don't want ordering in the pending list to cause
- * deadlocks, and so the two are serviced separately.
- *
- * A third pool does submit_bio to avoid deadlocking with the other
- * two
- */
- struct btrfs_workqueue *workers;
- struct btrfs_workqueue *hipri_workers;
- struct btrfs_workqueue *delalloc_workers;
- struct btrfs_workqueue *flush_workers;
- struct workqueue_struct *endio_workers;
- struct workqueue_struct *endio_meta_workers;
- struct workqueue_struct *endio_raid56_workers;
- struct workqueue_struct *rmw_workers;
- struct workqueue_struct *compressed_write_workers;
- struct btrfs_workqueue *endio_write_workers;
- struct btrfs_workqueue *endio_freespace_worker;
- struct btrfs_workqueue *caching_workers;
-
- /*
- * fixup workers take dirty pages that didn't properly go through
- * the cow mechanism and make them safe to write. It happens
- * for the sys_munmap function call path
- */
- struct btrfs_workqueue *fixup_workers;
- struct btrfs_workqueue *delayed_workers;
-
- struct task_struct *transaction_kthread;
- struct task_struct *cleaner_kthread;
- u32 thread_pool_size;
-
- struct kobject *space_info_kobj;
- struct kobject *qgroups_kobj;
- struct kobject *discard_kobj;
-
- /* used to keep from writing metadata until there is a nice batch */
- struct percpu_counter dirty_metadata_bytes;
- struct percpu_counter delalloc_bytes;
- struct percpu_counter ordered_bytes;
- s32 dirty_metadata_batch;
- s32 delalloc_batch;
-
- struct list_head dirty_cowonly_roots;
-
- struct btrfs_fs_devices *fs_devices;
-
- /*
- * The space_info list is effectively read only after initial
- * setup. It is populated at mount time and cleaned up after
- * all block groups are removed. RCU is used to protect it.
- */
- struct list_head space_info;
-
- struct btrfs_space_info *data_sinfo;
-
- struct reloc_control *reloc_ctl;
-
- /* data_alloc_cluster is only used in ssd_spread mode */
- struct btrfs_free_cluster data_alloc_cluster;
-
- /* all metadata allocations go through this cluster */
- struct btrfs_free_cluster meta_alloc_cluster;
-
- /* auto defrag inodes go here */
- spinlock_t defrag_inodes_lock;
- struct rb_root defrag_inodes;
- atomic_t defrag_running;
-
- /* Used to protect avail_{data, metadata, system}_alloc_bits */
- seqlock_t profiles_lock;
- /*
- * these three are in extended format (availability of single
- * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other
- * types are denoted by corresponding BTRFS_BLOCK_GROUP_* bits)
- */
- u64 avail_data_alloc_bits;
- u64 avail_metadata_alloc_bits;
- u64 avail_system_alloc_bits;
-
- /* restriper state */
- spinlock_t balance_lock;
- struct mutex balance_mutex;
- atomic_t balance_pause_req;
- atomic_t balance_cancel_req;
- struct btrfs_balance_control *balance_ctl;
- wait_queue_head_t balance_wait_q;
-
- /* Cancellation requests for chunk relocation */
- atomic_t reloc_cancel_req;
-
- u32 data_chunk_allocations;
- u32 metadata_ratio;
-
- void *bdev_holder;
-
- /* private scrub information */
- struct mutex scrub_lock;
- atomic_t scrubs_running;
- atomic_t scrub_pause_req;
- atomic_t scrubs_paused;
- atomic_t scrub_cancel_req;
- wait_queue_head_t scrub_pause_wait;
- /*
- * The worker pointers are NULL iff the refcount is 0, ie. scrub is not
- * running.
- */
- refcount_t scrub_workers_refcnt;
- struct workqueue_struct *scrub_workers;
- struct workqueue_struct *scrub_wr_completion_workers;
- struct workqueue_struct *scrub_parity_workers;
- struct btrfs_subpage_info *subpage_info;
-
- struct btrfs_discard_ctl discard_ctl;
-
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
- u32 check_integrity_print_mask;
-#endif
- /* is qgroup tracking in a consistent state? */
- u64 qgroup_flags;
-
- /* holds configuration and tracking. Protected by qgroup_lock */
- struct rb_root qgroup_tree;
- spinlock_t qgroup_lock;
-
- /*
- * used to avoid frequently calling ulist_alloc()/ulist_free()
- * when doing qgroup accounting, it must be protected by qgroup_lock.
- */
- struct ulist *qgroup_ulist;
-
- /*
- * Protect user change for quota operations. If a transaction is needed,
- * it must be started before locking this lock.
- */
- struct mutex qgroup_ioctl_lock;
-
- /* list of dirty qgroups to be written at next commit */
- struct list_head dirty_qgroups;
-
- /* used by qgroup for an efficient tree traversal */
- u64 qgroup_seq;
-
- /* qgroup rescan items */
- struct mutex qgroup_rescan_lock; /* protects the progress item */
- struct btrfs_key qgroup_rescan_progress;
- struct btrfs_workqueue *qgroup_rescan_workers;
- struct completion qgroup_rescan_completion;
- struct btrfs_work qgroup_rescan_work;
- bool qgroup_rescan_running; /* protected by qgroup_rescan_lock */
- u8 qgroup_drop_subtree_thres;
-
- /* filesystem state */
- unsigned long fs_state;
-
- struct btrfs_delayed_root *delayed_root;
-
- /* Extent buffer radix tree */
- spinlock_t buffer_lock;
- /* Entries are eb->start / sectorsize */
- struct radix_tree_root buffer_radix;
-
- /* next backup root to be overwritten */
- int backup_root_index;
-
- /* device replace state */
- struct btrfs_dev_replace dev_replace;
-
- struct semaphore uuid_tree_rescan_sem;
-
- /* Used to reclaim the metadata space in the background. */
- struct work_struct async_reclaim_work;
- struct work_struct async_data_reclaim_work;
- struct work_struct preempt_reclaim_work;
-
- /* Reclaim partially filled block groups in the background */
- struct work_struct reclaim_bgs_work;
- struct list_head reclaim_bgs;
- int bg_reclaim_threshold;
-
- spinlock_t unused_bgs_lock;
- struct list_head unused_bgs;
- struct mutex unused_bg_unpin_mutex;
- /* Protect block groups that are going to be deleted */
- struct mutex reclaim_bgs_lock;
-
- /* Cached block sizes */
- u32 nodesize;
- u32 sectorsize;
- /* ilog2 of sectorsize, use to avoid 64bit division */
- u32 sectorsize_bits;
- u32 csum_size;
- u32 csums_per_leaf;
- u32 stripesize;
-
- /*
- * Maximum size of an extent. BTRFS_MAX_EXTENT_SIZE on regular
- * filesystem, on zoned it depends on the device constraints.
- */
- u64 max_extent_size;
-
- /* Block groups and devices containing active swapfiles. */
- spinlock_t swapfile_pins_lock;
- struct rb_root swapfile_pins;
-
- struct crypto_shash *csum_shash;
-
- /* Type of exclusive operation running, protected by super_lock */
- enum btrfs_exclusive_operation exclusive_operation;
-
- /*
- * Zone size > 0 when in ZONED mode, otherwise it's used for a check
- * if the mode is enabled
- */
- u64 zone_size;
-
- /* Max size to emit ZONE_APPEND write command */
- u64 max_zone_append_size;
- struct mutex zoned_meta_io_lock;
- spinlock_t treelog_bg_lock;
- u64 treelog_bg;
-
- /*
- * Start of the dedicated data relocation block group, protected by
- * relocation_bg_lock.
- */
- spinlock_t relocation_bg_lock;
- u64 data_reloc_bg;
- struct mutex zoned_data_reloc_io_lock;
-
- u64 nr_global_roots;
-
- spinlock_t zone_active_bgs_lock;
- struct list_head zone_active_bgs;
-
- /* Updates are not protected by any lock */
- struct btrfs_commit_stats commit_stats;
-
- /*
- * Last generation where we dropped a non-relocation root.
- * Use btrfs_set_last_root_drop_gen() and btrfs_get_last_root_drop_gen()
- * to change it and to read it, respectively.
- */
- u64 last_root_drop_gen;
-
- /*
- * Annotations for transaction events (structures are empty when
- * compiled without lockdep).
- */
- struct lockdep_map btrfs_trans_num_writers_map;
- struct lockdep_map btrfs_trans_num_extwriters_map;
- struct lockdep_map btrfs_state_change_map[4];
- struct lockdep_map btrfs_trans_pending_ordered_map;
- struct lockdep_map btrfs_ordered_extent_map;
-
-#ifdef CONFIG_BTRFS_FS_REF_VERIFY
- spinlock_t ref_verify_lock;
- struct rb_root block_tree;
-#endif
-
-#ifdef CONFIG_BTRFS_DEBUG
- struct kobject *debug_kobj;
- struct list_head allocated_roots;
-
- spinlock_t eb_leak_lock;
- struct list_head allocated_ebs;
-#endif
-};
-
-static inline void btrfs_set_last_root_drop_gen(struct btrfs_fs_info *fs_info,
- u64 gen)
-{
- WRITE_ONCE(fs_info->last_root_drop_gen, gen);
-}
-
-static inline u64 btrfs_get_last_root_drop_gen(const struct btrfs_fs_info *fs_info)
-{
- return READ_ONCE(fs_info->last_root_drop_gen);
-}
-
-static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
-{
- return sb->s_fs_info;
-}
-
-/*
- * Take the number of bytes to be checksummed and figure out how many leaves
- * it would require to store the csums for that many bytes.
- */
-static inline u64 btrfs_csum_bytes_to_leaves(
- const struct btrfs_fs_info *fs_info, u64 csum_bytes)
-{
- const u64 num_csums = csum_bytes >> fs_info->sectorsize_bits;
-
- return DIV_ROUND_UP_ULL(num_csums, fs_info->csums_per_leaf);
-}
-
-/*
- * Use this if we would be adding new items, as we could split nodes as we cow
- * down the tree.
- */
-static inline u64 btrfs_calc_insert_metadata_size(struct btrfs_fs_info *fs_info,
- unsigned num_items)
-{
- return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items;
-}
-
-/*
- * Doing a truncate or a modification won't result in new nodes or leaves, just
- * what we need for COW.
- */
-static inline u64 btrfs_calc_metadata_size(struct btrfs_fs_info *fs_info,
- unsigned num_items)
-{
- return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;
-}
-
-#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \
- sizeof(struct btrfs_item))
-
-static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info)
-{
- return fs_info->zone_size > 0;
-}
-
-/*
- * Count how many fs_info->max_extent_size cover the @size
- */
-static inline u32 count_max_extents(struct btrfs_fs_info *fs_info, u64 size)
-{
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
- if (!fs_info)
- return div_u64(size + BTRFS_MAX_EXTENT_SIZE - 1, BTRFS_MAX_EXTENT_SIZE);
-#endif
-
- return div_u64(size + fs_info->max_extent_size - 1, fs_info->max_extent_size);
-}
-
-bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
- enum btrfs_exclusive_operation type);
-bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
- enum btrfs_exclusive_operation type);
-void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
-void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
-void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
- enum btrfs_exclusive_operation op);
-
/*
* The state of btrfs root
*/
@@ -1215,87 +174,6 @@ enum {
BTRFS_ROOT_RESET_LOCKDEP_CLASS,
};
-enum btrfs_lockdep_trans_states {
- BTRFS_LOCKDEP_TRANS_COMMIT_START,
- BTRFS_LOCKDEP_TRANS_UNBLOCKED,
- BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED,
- BTRFS_LOCKDEP_TRANS_COMPLETED,
-};
-
-/*
- * Lockdep annotation for wait events.
- *
- * @owner: The struct where the lockdep map is defined
- * @lock: The lockdep map corresponding to a wait event
- *
- * This macro is used to annotate a wait event. In this case a thread acquires
- * the lockdep map as writer (exclusive lock) because it has to block until all
- * the threads that hold the lock as readers signal the condition for the wait
- * event and release their locks.
- */
-#define btrfs_might_wait_for_event(owner, lock) \
- do { \
- rwsem_acquire(&owner->lock##_map, 0, 0, _THIS_IP_); \
- rwsem_release(&owner->lock##_map, _THIS_IP_); \
- } while (0)
-
-/*
- * Protection for the resource/condition of a wait event.
- *
- * @owner: The struct where the lockdep map is defined
- * @lock: The lockdep map corresponding to a wait event
- *
- * Many threads can modify the condition for the wait event at the same time
- * and signal the threads that block on the wait event. The threads that modify
- * the condition and do the signaling acquire the lock as readers (shared
- * lock).
- */
-#define btrfs_lockdep_acquire(owner, lock) \
- rwsem_acquire_read(&owner->lock##_map, 0, 0, _THIS_IP_)
-
-/*
- * Used after signaling the condition for a wait event to release the lockdep
- * map held by a reader thread.
- */
-#define btrfs_lockdep_release(owner, lock) \
- rwsem_release(&owner->lock##_map, _THIS_IP_)
-
-/*
- * Macros for the transaction states wait events, similar to the generic wait
- * event macros.
- */
-#define btrfs_might_wait_for_state(owner, i) \
- do { \
- rwsem_acquire(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_); \
- rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_); \
- } while (0)
-
-#define btrfs_trans_state_lockdep_acquire(owner, i) \
- rwsem_acquire_read(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_)
-
-#define btrfs_trans_state_lockdep_release(owner, i) \
- rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_)
-
-/* Initialization of the lockdep map */
-#define btrfs_lockdep_init_map(owner, lock) \
- do { \
- static struct lock_class_key lock##_key; \
- lockdep_init_map(&owner->lock##_map, #lock, &lock##_key, 0); \
- } while (0)
-
-/* Initialization of the transaction states lockdep maps. */
-#define btrfs_state_lockdep_init_map(owner, lock, state) \
- do { \
- static struct lock_class_key lock##_key; \
- lockdep_init_map(&owner->btrfs_state_change_map[state], #lock, \
- &lock##_key, 0); \
- } while (0)
-
-static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
-{
- clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
-}
-
/*
* Record swapped tree blocks of a subvolume tree for delayed subtree trace
* code. For detail check comment in fs/btrfs/qgroup.c.
@@ -1457,6 +335,23 @@ struct btrfs_root {
#endif
};
+static inline bool btrfs_root_readonly(const struct btrfs_root *root)
+{
+ /* Byte-swap the constant at compile time, root_item::flags is LE */
+ return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
+}
+
+static inline bool btrfs_root_dead(const struct btrfs_root *root)
+{
+ /* Byte-swap the constant at compile time, root_item::flags is LE */
+ return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
+}
+
+static inline u64 btrfs_root_id(const struct btrfs_root *root)
+{
+ return root->root_key.objectid;
+}
+
/*
* Structure that conveys information about an extent that is going to replace
* all the extents in a file range.
@@ -1548,17 +443,14 @@ struct btrfs_drop_extents_args {
struct btrfs_file_private {
void *filldir_buf;
+ struct extent_state *llseek_cached_state;
};
-
static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_fs_info *info)
{
-
return info->nodesize - sizeof(struct btrfs_header);
}
-#define BTRFS_LEAF_DATA_OFFSET offsetof(struct btrfs_leaf, items)
-
static inline u32 BTRFS_MAX_ITEM_SIZE(const struct btrfs_fs_info *info)
{
return BTRFS_LEAF_DATA_SIZE(info) - sizeof(struct btrfs_item);
@@ -1569,1254 +461,14 @@ static inline u32 BTRFS_NODEPTRS_PER_BLOCK(const struct btrfs_fs_info *info)
return BTRFS_LEAF_DATA_SIZE(info) / sizeof(struct btrfs_key_ptr);
}
-#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
- (offsetof(struct btrfs_file_extent_item, disk_bytenr))
-static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info)
-{
- return BTRFS_MAX_ITEM_SIZE(info) -
- BTRFS_FILE_EXTENT_INLINE_DATA_START;
-}
-
static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
{
return BTRFS_MAX_ITEM_SIZE(info) - sizeof(struct btrfs_dir_item);
}
-/*
- * Flags for mount options.
- *
- * Note: don't forget to add new options to btrfs_show_options()
- */
-enum {
- BTRFS_MOUNT_NODATASUM = (1UL << 0),
- BTRFS_MOUNT_NODATACOW = (1UL << 1),
- BTRFS_MOUNT_NOBARRIER = (1UL << 2),
- BTRFS_MOUNT_SSD = (1UL << 3),
- BTRFS_MOUNT_DEGRADED = (1UL << 4),
- BTRFS_MOUNT_COMPRESS = (1UL << 5),
- BTRFS_MOUNT_NOTREELOG = (1UL << 6),
- BTRFS_MOUNT_FLUSHONCOMMIT = (1UL << 7),
- BTRFS_MOUNT_SSD_SPREAD = (1UL << 8),
- BTRFS_MOUNT_NOSSD = (1UL << 9),
- BTRFS_MOUNT_DISCARD_SYNC = (1UL << 10),
- BTRFS_MOUNT_FORCE_COMPRESS = (1UL << 11),
- BTRFS_MOUNT_SPACE_CACHE = (1UL << 12),
- BTRFS_MOUNT_CLEAR_CACHE = (1UL << 13),
- BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED = (1UL << 14),
- BTRFS_MOUNT_ENOSPC_DEBUG = (1UL << 15),
- BTRFS_MOUNT_AUTO_DEFRAG = (1UL << 16),
- BTRFS_MOUNT_USEBACKUPROOT = (1UL << 17),
- BTRFS_MOUNT_SKIP_BALANCE = (1UL << 18),
- BTRFS_MOUNT_CHECK_INTEGRITY = (1UL << 19),
- BTRFS_MOUNT_CHECK_INTEGRITY_DATA = (1UL << 20),
- BTRFS_MOUNT_PANIC_ON_FATAL_ERROR = (1UL << 21),
- BTRFS_MOUNT_RESCAN_UUID_TREE = (1UL << 22),
- BTRFS_MOUNT_FRAGMENT_DATA = (1UL << 23),
- BTRFS_MOUNT_FRAGMENT_METADATA = (1UL << 24),
- BTRFS_MOUNT_FREE_SPACE_TREE = (1UL << 25),
- BTRFS_MOUNT_NOLOGREPLAY = (1UL << 26),
- BTRFS_MOUNT_REF_VERIFY = (1UL << 27),
- BTRFS_MOUNT_DISCARD_ASYNC = (1UL << 28),
- BTRFS_MOUNT_IGNOREBADROOTS = (1UL << 29),
- BTRFS_MOUNT_IGNOREDATACSUMS = (1UL << 30),
-};
-
-#define BTRFS_DEFAULT_COMMIT_INTERVAL (30)
-#define BTRFS_DEFAULT_MAX_INLINE (2048)
-
-#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
-#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
-#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt)
-#define btrfs_test_opt(fs_info, opt) ((fs_info)->mount_opt & \
- BTRFS_MOUNT_##opt)
-
-#define btrfs_set_and_info(fs_info, opt, fmt, args...) \
-do { \
- if (!btrfs_test_opt(fs_info, opt)) \
- btrfs_info(fs_info, fmt, ##args); \
- btrfs_set_opt(fs_info->mount_opt, opt); \
-} while (0)
-
-#define btrfs_clear_and_info(fs_info, opt, fmt, args...) \
-do { \
- if (btrfs_test_opt(fs_info, opt)) \
- btrfs_info(fs_info, fmt, ##args); \
- btrfs_clear_opt(fs_info->mount_opt, opt); \
-} while (0)
-
-/*
- * Requests for changes that need to be done during transaction commit.
- *
- * Internal mount options that are used for special handling of the real
- * mount options (eg. cannot be set during remount and have to be set during
- * transaction commit)
- */
-
-#define BTRFS_PENDING_COMMIT (0)
-
-#define btrfs_test_pending(info, opt) \
- test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
-#define btrfs_set_pending(info, opt) \
- set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
-#define btrfs_clear_pending(info, opt) \
- clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
-
-/*
- * Helpers for setting pending mount option changes.
- *
- * Expects corresponding macros
- * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name
- */
-#define btrfs_set_pending_and_info(info, opt, fmt, args...) \
-do { \
- if (!btrfs_raw_test_opt((info)->mount_opt, opt)) { \
- btrfs_info((info), fmt, ##args); \
- btrfs_set_pending((info), SET_##opt); \
- btrfs_clear_pending((info), CLEAR_##opt); \
- } \
-} while(0)
-
-#define btrfs_clear_pending_and_info(info, opt, fmt, args...) \
-do { \
- if (btrfs_raw_test_opt((info)->mount_opt, opt)) { \
- btrfs_info((info), fmt, ##args); \
- btrfs_set_pending((info), CLEAR_##opt); \
- btrfs_clear_pending((info), SET_##opt); \
- } \
-} while(0)
-
-/*
- * Inode flags
- */
-#define BTRFS_INODE_NODATASUM (1U << 0)
-#define BTRFS_INODE_NODATACOW (1U << 1)
-#define BTRFS_INODE_READONLY (1U << 2)
-#define BTRFS_INODE_NOCOMPRESS (1U << 3)
-#define BTRFS_INODE_PREALLOC (1U << 4)
-#define BTRFS_INODE_SYNC (1U << 5)
-#define BTRFS_INODE_IMMUTABLE (1U << 6)
-#define BTRFS_INODE_APPEND (1U << 7)
-#define BTRFS_INODE_NODUMP (1U << 8)
-#define BTRFS_INODE_NOATIME (1U << 9)
-#define BTRFS_INODE_DIRSYNC (1U << 10)
-#define BTRFS_INODE_COMPRESS (1U << 11)
-
-#define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31)
-
-#define BTRFS_INODE_FLAG_MASK \
- (BTRFS_INODE_NODATASUM | \
- BTRFS_INODE_NODATACOW | \
- BTRFS_INODE_READONLY | \
- BTRFS_INODE_NOCOMPRESS | \
- BTRFS_INODE_PREALLOC | \
- BTRFS_INODE_SYNC | \
- BTRFS_INODE_IMMUTABLE | \
- BTRFS_INODE_APPEND | \
- BTRFS_INODE_NODUMP | \
- BTRFS_INODE_NOATIME | \
- BTRFS_INODE_DIRSYNC | \
- BTRFS_INODE_COMPRESS | \
- BTRFS_INODE_ROOT_ITEM_INIT)
-
-#define BTRFS_INODE_RO_VERITY (1U << 0)
-
-#define BTRFS_INODE_RO_FLAG_MASK (BTRFS_INODE_RO_VERITY)
-
-struct btrfs_map_token {
- struct extent_buffer *eb;
- char *kaddr;
- unsigned long offset;
-};
-
#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \
((bytes) >> (fs_info)->sectorsize_bits)
-static inline void btrfs_init_map_token(struct btrfs_map_token *token,
- struct extent_buffer *eb)
-{
- token->eb = eb;
- token->kaddr = page_address(eb->pages[0]);
- token->offset = 0;
-}
-
-/* some macros to generate set/get functions for the struct fields. This
- * assumes there is a lefoo_to_cpu for every type, so lets make a simple
- * one for u8:
- */
-#define le8_to_cpu(v) (v)
-#define cpu_to_le8(v) (v)
-#define __le8 u8
-
-static inline u8 get_unaligned_le8(const void *p)
-{
- return *(u8 *)p;
-}
-
-static inline void put_unaligned_le8(u8 val, void *p)
-{
- *(u8 *)p = val;
-}
-
-#define read_eb_member(eb, ptr, type, member, result) (\
- read_extent_buffer(eb, (char *)(result), \
- ((unsigned long)(ptr)) + \
- offsetof(type, member), \
- sizeof(((type *)0)->member)))
-
-#define write_eb_member(eb, ptr, type, member, result) (\
- write_extent_buffer(eb, (char *)(result), \
- ((unsigned long)(ptr)) + \
- offsetof(type, member), \
- sizeof(((type *)0)->member)))
-
-#define DECLARE_BTRFS_SETGET_BITS(bits) \
-u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
- const void *ptr, unsigned long off); \
-void btrfs_set_token_##bits(struct btrfs_map_token *token, \
- const void *ptr, unsigned long off, \
- u##bits val); \
-u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
- const void *ptr, unsigned long off); \
-void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
- unsigned long off, u##bits val);
-
-DECLARE_BTRFS_SETGET_BITS(8)
-DECLARE_BTRFS_SETGET_BITS(16)
-DECLARE_BTRFS_SETGET_BITS(32)
-DECLARE_BTRFS_SETGET_BITS(64)
-
-#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
-static inline u##bits btrfs_##name(const struct extent_buffer *eb, \
- const type *s) \
-{ \
- static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
- return btrfs_get_##bits(eb, s, offsetof(type, member)); \
-} \
-static inline void btrfs_set_##name(const struct extent_buffer *eb, type *s, \
- u##bits val) \
-{ \
- static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
- btrfs_set_##bits(eb, s, offsetof(type, member), val); \
-} \
-static inline u##bits btrfs_token_##name(struct btrfs_map_token *token, \
- const type *s) \
-{ \
- static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
- return btrfs_get_token_##bits(token, s, offsetof(type, member));\
-} \
-static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\
- type *s, u##bits val) \
-{ \
- static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
- btrfs_set_token_##bits(token, s, offsetof(type, member), val); \
-}
-
-#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
-static inline u##bits btrfs_##name(const struct extent_buffer *eb) \
-{ \
- const type *p = page_address(eb->pages[0]) + \
- offset_in_page(eb->start); \
- return get_unaligned_le##bits(&p->member); \
-} \
-static inline void btrfs_set_##name(const struct extent_buffer *eb, \
- u##bits val) \
-{ \
- type *p = page_address(eb->pages[0]) + offset_in_page(eb->start); \
- put_unaligned_le##bits(val, &p->member); \
-}
-
-#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
-static inline u##bits btrfs_##name(const type *s) \
-{ \
- return get_unaligned_le##bits(&s->member); \
-} \
-static inline void btrfs_set_##name(type *s, u##bits val) \
-{ \
- put_unaligned_le##bits(val, &s->member); \
-}
-
-static inline u64 btrfs_device_total_bytes(const struct extent_buffer *eb,
- struct btrfs_dev_item *s)
-{
- static_assert(sizeof(u64) ==
- sizeof(((struct btrfs_dev_item *)0))->total_bytes);
- return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item,
- total_bytes));
-}
-static inline void btrfs_set_device_total_bytes(const struct extent_buffer *eb,
- struct btrfs_dev_item *s,
- u64 val)
-{
- static_assert(sizeof(u64) ==
- sizeof(((struct btrfs_dev_item *)0))->total_bytes);
- WARN_ON(!IS_ALIGNED(val, eb->fs_info->sectorsize));
- btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val);
-}
-
-
-BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64);
-BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64);
-BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32);
-BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);
-BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item,
- start_offset, 64);
-BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);
-BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
-BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);
-BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);
-BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);
-BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);
-
-BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
- total_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,
- bytes_used, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,
- io_align, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,
- io_width, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,
- sector_size, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item,
- dev_group, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,
- seek_speed, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
- bandwidth, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
- generation, 64);
-
-static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d)
-{
- return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid);
-}
-
-static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d)
-{
- return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid);
-}
-
-BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
-BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);
-BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);
-BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32);
-BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);
-BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
-BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
-BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
-BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);
-BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
-BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);
-
-static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s)
-{
- return (char *)s + offsetof(struct btrfs_stripe, dev_uuid);
-}
-
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk,
- stripe_len, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk,
- io_align, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk,
- io_width, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,
- sector_size, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
- num_stripes, 16);
-BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,
- sub_stripes, 16);
-BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);
-
-static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c,
- int nr)
-{
- unsigned long offset = (unsigned long)c;
- offset += offsetof(struct btrfs_chunk, stripe);
- offset += nr * sizeof(struct btrfs_stripe);
- return (struct btrfs_stripe *)offset;
-}
-
-static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr)
-{
- return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr));
-}
-
-static inline u64 btrfs_stripe_offset_nr(const struct extent_buffer *eb,
- struct btrfs_chunk *c, int nr)
-{
- return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));
-}
-
-static inline u64 btrfs_stripe_devid_nr(const struct extent_buffer *eb,
- struct btrfs_chunk *c, int nr)
-{
- return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));
-}
-
-/* struct btrfs_block_group_item */
-BTRFS_SETGET_STACK_FUNCS(stack_block_group_used, struct btrfs_block_group_item,
- used, 64);
-BTRFS_SETGET_FUNCS(block_group_used, struct btrfs_block_group_item,
- used, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_block_group_chunk_objectid,
- struct btrfs_block_group_item, chunk_objectid, 64);
-
-BTRFS_SETGET_FUNCS(block_group_chunk_objectid,
- struct btrfs_block_group_item, chunk_objectid, 64);
-BTRFS_SETGET_FUNCS(block_group_flags,
- struct btrfs_block_group_item, flags, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_block_group_flags,
- struct btrfs_block_group_item, flags, 64);
-
-/* struct btrfs_free_space_info */
-BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info,
- extent_count, 32);
-BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32);
-
-/* struct btrfs_inode_ref */
-BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
-BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
-
-/* struct btrfs_inode_extref */
-BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref,
- parent_objectid, 64);
-BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref,
- name_len, 16);
-BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64);
-
-/* struct btrfs_inode_item */
-BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
-BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64);
-BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);
-BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
-BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64);
-BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
-BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);
-BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);
-BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
-BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
-BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
-BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
- generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
- sequence, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
- transid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
- nbytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
- block_group, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
-BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
-BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
-
-/* struct btrfs_dev_extent */
-BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,
- chunk_tree, 64);
-BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent,
- chunk_objectid, 64);
-BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,
- chunk_offset, 64);
-BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);
-BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);
-BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item,
- generation, 64);
-BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64);
-
-BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8);
-
-static inline void btrfs_tree_block_key(const struct extent_buffer *eb,
- struct btrfs_tree_block_info *item,
- struct btrfs_disk_key *key)
-{
- read_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
-}
-
-static inline void btrfs_set_tree_block_key(const struct extent_buffer *eb,
- struct btrfs_tree_block_info *item,
- struct btrfs_disk_key *key)
-{
- write_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
-}
-
-BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref,
- root, 64);
-BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref,
- objectid, 64);
-BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref,
- offset, 64);
-BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref,
- count, 32);
-
-BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref,
- count, 32);
-
-BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref,
- type, 8);
-BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref,
- offset, 64);
-
-static inline u32 btrfs_extent_inline_ref_size(int type)
-{
- if (type == BTRFS_TREE_BLOCK_REF_KEY ||
- type == BTRFS_SHARED_BLOCK_REF_KEY)
- return sizeof(struct btrfs_extent_inline_ref);
- if (type == BTRFS_SHARED_DATA_REF_KEY)
- return sizeof(struct btrfs_shared_data_ref) +
- sizeof(struct btrfs_extent_inline_ref);
- if (type == BTRFS_EXTENT_DATA_REF_KEY)
- return sizeof(struct btrfs_extent_data_ref) +
- offsetof(struct btrfs_extent_inline_ref, offset);
- return 0;
-}
-
-/* struct btrfs_node */
-BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
-BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr,
- blockptr, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr,
- generation, 64);
-
-static inline u64 btrfs_node_blockptr(const struct extent_buffer *eb, int nr)
-{
- unsigned long ptr;
- ptr = offsetof(struct btrfs_node, ptrs) +
- sizeof(struct btrfs_key_ptr) * nr;
- return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr);
-}
-
-static inline void btrfs_set_node_blockptr(const struct extent_buffer *eb,
- int nr, u64 val)
-{
- unsigned long ptr;
- ptr = offsetof(struct btrfs_node, ptrs) +
- sizeof(struct btrfs_key_ptr) * nr;
- btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
-}
-
-static inline u64 btrfs_node_ptr_generation(const struct extent_buffer *eb, int nr)
-{
- unsigned long ptr;
- ptr = offsetof(struct btrfs_node, ptrs) +
- sizeof(struct btrfs_key_ptr) * nr;
- return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);
-}
-
-static inline void btrfs_set_node_ptr_generation(const struct extent_buffer *eb,
- int nr, u64 val)
-{
- unsigned long ptr;
- ptr = offsetof(struct btrfs_node, ptrs) +
- sizeof(struct btrfs_key_ptr) * nr;
- btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);
-}
-
-static inline unsigned long btrfs_node_key_ptr_offset(int nr)
-{
- return offsetof(struct btrfs_node, ptrs) +
- sizeof(struct btrfs_key_ptr) * nr;
-}
-
-void btrfs_node_key(const struct extent_buffer *eb,
- struct btrfs_disk_key *disk_key, int nr);
-
-static inline void btrfs_set_node_key(const struct extent_buffer *eb,
- struct btrfs_disk_key *disk_key, int nr)
-{
- unsigned long ptr;
- ptr = btrfs_node_key_ptr_offset(nr);
- write_eb_member(eb, (struct btrfs_key_ptr *)ptr,
- struct btrfs_key_ptr, key, disk_key);
-}
-
-/* struct btrfs_item */
-BTRFS_SETGET_FUNCS(raw_item_offset, struct btrfs_item, offset, 32);
-BTRFS_SETGET_FUNCS(raw_item_size, struct btrfs_item, size, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32);
-
-static inline unsigned long btrfs_item_nr_offset(int nr)
-{
- return offsetof(struct btrfs_leaf, items) +
- sizeof(struct btrfs_item) * nr;
-}
-
-static inline struct btrfs_item *btrfs_item_nr(int nr)
-{
- return (struct btrfs_item *)btrfs_item_nr_offset(nr);
-}
-
-#define BTRFS_ITEM_SETGET_FUNCS(member) \
-static inline u32 btrfs_item_##member(const struct extent_buffer *eb, \
- int slot) \
-{ \
- return btrfs_raw_item_##member(eb, btrfs_item_nr(slot)); \
-} \
-static inline void btrfs_set_item_##member(const struct extent_buffer *eb, \
- int slot, u32 val) \
-{ \
- btrfs_set_raw_item_##member(eb, btrfs_item_nr(slot), val); \
-} \
-static inline u32 btrfs_token_item_##member(struct btrfs_map_token *token, \
- int slot) \
-{ \
- struct btrfs_item *item = btrfs_item_nr(slot); \
- return btrfs_token_raw_item_##member(token, item); \
-} \
-static inline void btrfs_set_token_item_##member(struct btrfs_map_token *token, \
- int slot, u32 val) \
-{ \
- struct btrfs_item *item = btrfs_item_nr(slot); \
- btrfs_set_token_raw_item_##member(token, item, val); \
-}
-
-BTRFS_ITEM_SETGET_FUNCS(offset)
-BTRFS_ITEM_SETGET_FUNCS(size);
-
-static inline u32 btrfs_item_data_end(const struct extent_buffer *eb, int nr)
-{
- return btrfs_item_offset(eb, nr) + btrfs_item_size(eb, nr);
-}
-
-static inline void btrfs_item_key(const struct extent_buffer *eb,
- struct btrfs_disk_key *disk_key, int nr)
-{
- struct btrfs_item *item = btrfs_item_nr(nr);
- read_eb_member(eb, item, struct btrfs_item, key, disk_key);
-}
-
-static inline void btrfs_set_item_key(struct extent_buffer *eb,
- struct btrfs_disk_key *disk_key, int nr)
-{
- struct btrfs_item *item = btrfs_item_nr(nr);
- write_eb_member(eb, item, struct btrfs_item, key, disk_key);
-}
-
-BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);
-
-/*
- * struct btrfs_root_ref
- */
-BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
-BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
-BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
-
-/* struct btrfs_dir_item */
-BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
-BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
-BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
-BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item,
- data_len, 16);
-BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item,
- name_len, 16);
-BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
- transid, 64);
-
-static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
- const struct btrfs_dir_item *item,
- struct btrfs_disk_key *key)
-{
- read_eb_member(eb, item, struct btrfs_dir_item, location, key);
-}
-
-static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
- struct btrfs_dir_item *item,
- const struct btrfs_disk_key *key)
-{
- write_eb_member(eb, item, struct btrfs_dir_item, location, key);
-}
-
-BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header,
- num_entries, 64);
-BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header,
- num_bitmaps, 64);
-BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
- generation, 64);
-
-static inline void btrfs_free_space_key(const struct extent_buffer *eb,
- const struct btrfs_free_space_header *h,
- struct btrfs_disk_key *key)
-{
- read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
-}
-
-static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
- struct btrfs_free_space_header *h,
- const struct btrfs_disk_key *key)
-{
- write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
-}
-
-/* struct btrfs_disk_key */
-BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,
- objectid, 64);
-BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);
-BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);
-
-#ifdef __LITTLE_ENDIAN
-
-/*
- * Optimized helpers for little-endian architectures where CPU and on-disk
- * structures have the same endianness and we can skip conversions.
- */
-
-static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu_key,
- const struct btrfs_disk_key *disk_key)
-{
- memcpy(cpu_key, disk_key, sizeof(struct btrfs_key));
-}
-
-static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk_key,
- const struct btrfs_key *cpu_key)
-{
- memcpy(disk_key, cpu_key, sizeof(struct btrfs_key));
-}
-
-static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
- struct btrfs_key *cpu_key, int nr)
-{
- struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
-
- btrfs_node_key(eb, disk_key, nr);
-}
-
-static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
- struct btrfs_key *cpu_key, int nr)
-{
- struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
-
- btrfs_item_key(eb, disk_key, nr);
-}
-
-static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
- const struct btrfs_dir_item *item,
- struct btrfs_key *cpu_key)
-{
- struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key;
-
- btrfs_dir_item_key(eb, item, disk_key);
-}
-
-#else
-
-static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
- const struct btrfs_disk_key *disk)
-{
- cpu->offset = le64_to_cpu(disk->offset);
- cpu->type = disk->type;
- cpu->objectid = le64_to_cpu(disk->objectid);
-}
-
-static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,
- const struct btrfs_key *cpu)
-{
- disk->offset = cpu_to_le64(cpu->offset);
- disk->type = cpu->type;
- disk->objectid = cpu_to_le64(cpu->objectid);
-}
-
-static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
- struct btrfs_key *key, int nr)
-{
- struct btrfs_disk_key disk_key;
- btrfs_node_key(eb, &disk_key, nr);
- btrfs_disk_key_to_cpu(key, &disk_key);
-}
-
-static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
- struct btrfs_key *key, int nr)
-{
- struct btrfs_disk_key disk_key;
- btrfs_item_key(eb, &disk_key, nr);
- btrfs_disk_key_to_cpu(key, &disk_key);
-}
-
-static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
- const struct btrfs_dir_item *item,
- struct btrfs_key *key)
-{
- struct btrfs_disk_key disk_key;
- btrfs_dir_item_key(eb, item, &disk_key);
- btrfs_disk_key_to_cpu(key, &disk_key);
-}
-
-#endif
-
-/* struct btrfs_header */
-BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
-BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
- generation, 64);
-BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
-BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
-BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
-BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header,
- generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header,
- nritems, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
-
-static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag)
-{
- return (btrfs_header_flags(eb) & flag) == flag;
-}
-
-static inline void btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)
-{
- u64 flags = btrfs_header_flags(eb);
- btrfs_set_header_flags(eb, flags | flag);
-}
-
-static inline void btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
-{
- u64 flags = btrfs_header_flags(eb);
- btrfs_set_header_flags(eb, flags & ~flag);
-}
-
-static inline int btrfs_header_backref_rev(const struct extent_buffer *eb)
-{
- u64 flags = btrfs_header_flags(eb);
- return flags >> BTRFS_BACKREF_REV_SHIFT;
-}
-
-static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
- int rev)
-{
- u64 flags = btrfs_header_flags(eb);
- flags &= ~BTRFS_BACKREF_REV_MASK;
- flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT;
- btrfs_set_header_flags(eb, flags);
-}
-
-static inline int btrfs_is_leaf(const struct extent_buffer *eb)
-{
- return btrfs_header_level(eb) == 0;
-}
-
-/* struct btrfs_root_item */
-BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item,
- generation, 64);
-BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);
-BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);
-BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item,
- generation, 64);
-BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);
-BTRFS_SETGET_STACK_FUNCS(root_drop_level, struct btrfs_root_item, drop_level, 8);
-BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);
-BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);
-BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);
-BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64);
-BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
-BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
-BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
- last_snapshot, 64);
-BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
- generation_v2, 64);
-BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,
- ctransid, 64);
-BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,
- otransid, 64);
-BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
- stransid, 64);
-BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
- rtransid, 64);
-
-static inline bool btrfs_root_readonly(const struct btrfs_root *root)
-{
- /* Byte-swap the constant at compile time, root_item::flags is LE */
- return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
-}
-
-static inline bool btrfs_root_dead(const struct btrfs_root *root)
-{
- /* Byte-swap the constant at compile time, root_item::flags is LE */
- return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
-}
-
-static inline u64 btrfs_root_id(const struct btrfs_root *root)
-{
- return root->root_key.objectid;
-}
-
-/* struct btrfs_root_backup */
-BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
- tree_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup,
- tree_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup,
- tree_root_level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup,
- chunk_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup,
- chunk_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup,
- chunk_root_level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup,
- extent_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup,
- extent_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup,
- extent_root_level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup,
- fs_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup,
- fs_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup,
- fs_root_level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup,
- dev_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup,
- dev_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup,
- dev_root_level, 8);
-
-BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup,
- csum_root, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup,
- csum_root_gen, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup,
- csum_root_level, 8);
-BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup,
- total_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup,
- bytes_used, 64);
-BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,
- num_devices, 64);
-
-/* struct btrfs_balance_item */
-BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
-
-static inline void btrfs_balance_data(const struct extent_buffer *eb,
- const struct btrfs_balance_item *bi,
- struct btrfs_disk_balance_args *ba)
-{
- read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
-}
-
-static inline void btrfs_set_balance_data(struct extent_buffer *eb,
- struct btrfs_balance_item *bi,
- const struct btrfs_disk_balance_args *ba)
-{
- write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
-}
-
-static inline void btrfs_balance_meta(const struct extent_buffer *eb,
- const struct btrfs_balance_item *bi,
- struct btrfs_disk_balance_args *ba)
-{
- read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
-}
-
-static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
- struct btrfs_balance_item *bi,
- const struct btrfs_disk_balance_args *ba)
-{
- write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
-}
-
-static inline void btrfs_balance_sys(const struct extent_buffer *eb,
- const struct btrfs_balance_item *bi,
- struct btrfs_disk_balance_args *ba)
-{
- read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
-}
-
-static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
- struct btrfs_balance_item *bi,
- const struct btrfs_disk_balance_args *ba)
-{
- write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
-}
-
-static inline void
-btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
- const struct btrfs_disk_balance_args *disk)
-{
- memset(cpu, 0, sizeof(*cpu));
-
- cpu->profiles = le64_to_cpu(disk->profiles);
- cpu->usage = le64_to_cpu(disk->usage);
- cpu->devid = le64_to_cpu(disk->devid);
- cpu->pstart = le64_to_cpu(disk->pstart);
- cpu->pend = le64_to_cpu(disk->pend);
- cpu->vstart = le64_to_cpu(disk->vstart);
- cpu->vend = le64_to_cpu(disk->vend);
- cpu->target = le64_to_cpu(disk->target);
- cpu->flags = le64_to_cpu(disk->flags);
- cpu->limit = le64_to_cpu(disk->limit);
- cpu->stripes_min = le32_to_cpu(disk->stripes_min);
- cpu->stripes_max = le32_to_cpu(disk->stripes_max);
-}
-
-static inline void
-btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
- const struct btrfs_balance_args *cpu)
-{
- memset(disk, 0, sizeof(*disk));
-
- disk->profiles = cpu_to_le64(cpu->profiles);
- disk->usage = cpu_to_le64(cpu->usage);
- disk->devid = cpu_to_le64(cpu->devid);
- disk->pstart = cpu_to_le64(cpu->pstart);
- disk->pend = cpu_to_le64(cpu->pend);
- disk->vstart = cpu_to_le64(cpu->vstart);
- disk->vend = cpu_to_le64(cpu->vend);
- disk->target = cpu_to_le64(cpu->target);
- disk->flags = cpu_to_le64(cpu->flags);
- disk->limit = cpu_to_le64(cpu->limit);
- disk->stripes_min = cpu_to_le32(cpu->stripes_min);
- disk->stripes_max = cpu_to_le32(cpu->stripes_max);
-}
-
-/* struct btrfs_super_block */
-BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
-BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
-BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
- generation, 64);
-BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
-BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,
- struct btrfs_super_block, sys_chunk_array_size, 32);
-BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,
- struct btrfs_super_block, chunk_root_generation, 64);
-BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
- root_level, 8);
-BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
- chunk_root, 64);
-BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
- chunk_root_level, 8);
-BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,
- log_root, 64);
-BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
- log_root_level, 8);
-BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
- total_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
- bytes_used, 64);
-BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,
- sectorsize, 32);
-BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
- nodesize, 32);
-BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
- stripesize, 32);
-BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
- root_dir_objectid, 64);
-BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
- num_devices, 64);
-BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,
- compat_flags, 64);
-BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,
- compat_ro_flags, 64);
-BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,
- incompat_flags, 64);
-BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
- csum_type, 16);
-BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
- cache_generation, 64);
-BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
-BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
- uuid_tree_generation, 64);
-
-int btrfs_super_csum_size(const struct btrfs_super_block *s);
-const char *btrfs_super_csum_name(u16 csum_type);
-const char *btrfs_super_csum_driver(u16 csum_type);
-size_t __attribute_const__ btrfs_get_num_csums(void);
-
-
-/*
- * The leaf data grows from end-to-front in the node.
- * this returns the address of the start of the last item,
- * which is the stop of the leaf data stack
- */
-static inline unsigned int leaf_data_end(const struct extent_buffer *leaf)
-{
- u32 nr = btrfs_header_nritems(leaf);
-
- if (nr == 0)
- return BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
- return btrfs_item_offset(leaf, nr - 1);
-}
-
-/* struct btrfs_file_extent_item */
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
- type, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
- struct btrfs_file_extent_item, disk_bytenr, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset,
- struct btrfs_file_extent_item, offset, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation,
- struct btrfs_file_extent_item, generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes,
- struct btrfs_file_extent_item, num_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes,
- struct btrfs_file_extent_item, ram_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes,
- struct btrfs_file_extent_item, disk_num_bytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
- struct btrfs_file_extent_item, compression, 8);
-
-static inline unsigned long
-btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e)
-{
- return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
-}
-
-static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
-{
- return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize;
-}
-
-BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
-BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
- disk_bytenr, 64);
-BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
- generation, 64);
-BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
- disk_num_bytes, 64);
-BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
- offset, 64);
-BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
- num_bytes, 64);
-BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
- ram_bytes, 64);
-BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
- compression, 8);
-BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
- encryption, 8);
-BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
- other_encoding, 16);
-
-/*
- * this returns the number of bytes used by the item on disk, minus the
- * size of any extent headers. If a file is compressed on disk, this is
- * the compressed size
- */
-static inline u32 btrfs_file_extent_inline_item_len(
- const struct extent_buffer *eb,
- int nr)
-{
- return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
-}
-
-/* btrfs_qgroup_status_item */
-BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
- generation, 64);
-BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item,
- version, 64);
-BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item,
- flags, 64);
-BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item,
- rescan, 64);
-
-/* btrfs_qgroup_info_item */
-BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item,
- generation, 64);
-BTRFS_SETGET_FUNCS(qgroup_info_rfer, struct btrfs_qgroup_info_item, rfer, 64);
-BTRFS_SETGET_FUNCS(qgroup_info_rfer_cmpr, struct btrfs_qgroup_info_item,
- rfer_cmpr, 64);
-BTRFS_SETGET_FUNCS(qgroup_info_excl, struct btrfs_qgroup_info_item, excl, 64);
-BTRFS_SETGET_FUNCS(qgroup_info_excl_cmpr, struct btrfs_qgroup_info_item,
- excl_cmpr, 64);
-
-BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation,
- struct btrfs_qgroup_info_item, generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer, struct btrfs_qgroup_info_item,
- rfer, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer_cmpr,
- struct btrfs_qgroup_info_item, rfer_cmpr, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl, struct btrfs_qgroup_info_item,
- excl, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl_cmpr,
- struct btrfs_qgroup_info_item, excl_cmpr, 64);
-
-/* btrfs_qgroup_limit_item */
-BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item,
- flags, 64);
-BTRFS_SETGET_FUNCS(qgroup_limit_max_rfer, struct btrfs_qgroup_limit_item,
- max_rfer, 64);
-BTRFS_SETGET_FUNCS(qgroup_limit_max_excl, struct btrfs_qgroup_limit_item,
- max_excl, 64);
-BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item,
- rsv_rfer, 64);
-BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item,
- rsv_excl, 64);
-
-/* btrfs_dev_replace_item */
-BTRFS_SETGET_FUNCS(dev_replace_src_devid,
- struct btrfs_dev_replace_item, src_devid, 64);
-BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode,
- struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode,
- 64);
-BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item,
- replace_state, 64);
-BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item,
- time_started, 64);
-BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item,
- time_stopped, 64);
-BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item,
- num_write_errors, 64);
-BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors,
- struct btrfs_dev_replace_item, num_uncorrectable_read_errors,
- 64);
-BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item,
- cursor_left, 64);
-BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item,
- cursor_right, 64);
-
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid,
- struct btrfs_dev_replace_item, src_devid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode,
- struct btrfs_dev_replace_item,
- cont_reading_from_srcdev_mode, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state,
- struct btrfs_dev_replace_item, replace_state, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started,
- struct btrfs_dev_replace_item, time_started, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped,
- struct btrfs_dev_replace_item, time_stopped, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors,
- struct btrfs_dev_replace_item, num_write_errors, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors,
- struct btrfs_dev_replace_item,
- num_uncorrectable_read_errors, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left,
- struct btrfs_dev_replace_item, cursor_left, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
- struct btrfs_dev_replace_item, cursor_right, 64);
-
-/* helper function to cast into the data area of the leaf. */
-#define btrfs_item_ptr(leaf, slot, type) \
- ((type *)(BTRFS_LEAF_DATA_OFFSET + \
- btrfs_item_offset(leaf, slot)))
-
-#define btrfs_item_ptr_offset(leaf, slot) \
- ((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \
- btrfs_item_offset(leaf, slot)))
-
static inline u32 btrfs_crc32c(u32 crc, const void *address, unsigned length)
{
return crc32c(crc, address, length);
@@ -2846,163 +498,15 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
return mapping_gfp_constraint(mapping, ~__GFP_FS);
}
-/* extent-tree.c */
-
-enum btrfs_inline_ref_type {
- BTRFS_REF_TYPE_INVALID,
- BTRFS_REF_TYPE_BLOCK,
- BTRFS_REF_TYPE_DATA,
- BTRFS_REF_TYPE_ANY,
-};
-
-int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
- struct btrfs_extent_inline_ref *iref,
- enum btrfs_inline_ref_type is_data);
-u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
-
-
-int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,
- u64 start, u64 num_bytes);
-void btrfs_free_excluded_extents(struct btrfs_block_group *cache);
-int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
- unsigned long count);
-void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
- struct btrfs_delayed_ref_root *delayed_refs,
- struct btrfs_delayed_ref_head *head);
-int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len);
-int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 offset, int metadata, u64 *refs, u64 *flags);
-int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num,
- int reserved);
-int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
- u64 bytenr, u64 num_bytes);
-int btrfs_exclude_logged_extents(struct extent_buffer *eb);
-int btrfs_cross_ref_exist(struct btrfs_root *root,
- u64 objectid, u64 offset, u64 bytenr, bool strict,
- struct btrfs_path *path);
-struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- u64 parent, u64 root_objectid,
- const struct btrfs_disk_key *key,
- int level, u64 hint,
- u64 empty_size,
- enum btrfs_lock_nesting nest);
-void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
- u64 root_id,
- struct extent_buffer *buf,
- u64 parent, int last_ref);
-int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 owner,
- u64 offset, u64 ram_bytes,
- struct btrfs_key *ins);
-int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
- u64 root_objectid, u64 owner, u64 offset,
- struct btrfs_key *ins);
-int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes,
- u64 min_alloc_size, u64 empty_size, u64 hint_byte,
- struct btrfs_key *ins, int is_data, int delalloc);
-int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
- struct extent_buffer *buf, int full_backref);
-int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
- struct extent_buffer *buf, int full_backref);
-int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
- struct extent_buffer *eb, u64 flags, int level);
-int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref);
-
-int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
- u64 start, u64 len, int delalloc);
-int btrfs_pin_reserved_extent(struct btrfs_trans_handle *trans, u64 start,
- u64 len);
-int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);
-int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
- struct btrfs_ref *generic_ref);
-
-void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
-
-/*
- * Different levels for to flush space when doing space reservations.
- *
- * The higher the level, the more methods we try to reclaim space.
- */
-enum btrfs_reserve_flush_enum {
- /* If we are in the transaction, we can't flush anything.*/
- BTRFS_RESERVE_NO_FLUSH,
-
- /*
- * Flush space by:
- * - Running delayed inode items
- * - Allocating a new chunk
- */
- BTRFS_RESERVE_FLUSH_LIMIT,
-
- /*
- * Flush space by:
- * - Running delayed inode items
- * - Running delayed refs
- * - Running delalloc and waiting for ordered extents
- * - Allocating a new chunk
- */
- BTRFS_RESERVE_FLUSH_EVICT,
-
- /*
- * Flush space by above mentioned methods and by:
- * - Running delayed iputs
- * - Committing transaction
- *
- * Can be interrupted by a fatal signal.
- */
- BTRFS_RESERVE_FLUSH_DATA,
- BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE,
- BTRFS_RESERVE_FLUSH_ALL,
-
- /*
- * Pretty much the same as FLUSH_ALL, but can also steal space from
- * global rsv.
- *
- * Can be interrupted by a fatal signal.
- */
- BTRFS_RESERVE_FLUSH_ALL_STEAL,
-};
-
-enum btrfs_flush_state {
- FLUSH_DELAYED_ITEMS_NR = 1,
- FLUSH_DELAYED_ITEMS = 2,
- FLUSH_DELAYED_REFS_NR = 3,
- FLUSH_DELAYED_REFS = 4,
- FLUSH_DELALLOC = 5,
- FLUSH_DELALLOC_WAIT = 6,
- FLUSH_DELALLOC_FULL = 7,
- ALLOC_CHUNK = 8,
- ALLOC_CHUNK_FORCE = 9,
- RUN_DELAYED_IPUTS = 10,
- COMMIT_TRANS = 11,
-};
-
-int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
- struct btrfs_block_rsv *rsv,
- int nitems, bool use_global_rsv);
-void btrfs_subvolume_release_metadata(struct btrfs_root *root,
- struct btrfs_block_rsv *rsv);
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
-
-int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
- u64 disk_num_bytes, bool noflush);
-u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
u64 start, u64 end);
int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
u64 num_bytes, u64 *actual_bytes);
int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
-int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
-int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
-int btrfs_start_write_no_snapshotting(struct btrfs_root *root);
-void btrfs_end_write_no_snapshotting(struct btrfs_root *root);
-void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);
-
/* ctree.c */
+int __init btrfs_ctree_init(void);
+void __cold btrfs_ctree_exit(void);
int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,
int *slot);
int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
@@ -3163,14 +667,7 @@ int btrfs_get_next_valid_item(struct btrfs_root *root, struct btrfs_key *key,
(path)->slots[0]++ \
)
-static inline int btrfs_next_old_item(struct btrfs_root *root,
- struct btrfs_path *p, u64 time_seq)
-{
- ++p->slots[0];
- if (p->slots[0] >= btrfs_header_nritems(p->nodes[0]))
- return btrfs_next_old_leaf(root, p, time_seq);
- return 0;
-}
+int btrfs_next_old_item(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq);
/*
* Search the tree again to find a leaf with greater keys.
@@ -3188,862 +685,6 @@ static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p)
return btrfs_next_old_item(root, p, 0);
}
int btrfs_leaf_free_space(struct extent_buffer *leaf);
-int __must_check btrfs_drop_snapshot(struct btrfs_root *root, int update_ref,
- int for_reloc);
-int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct extent_buffer *node,
- struct extent_buffer *parent);
-static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
-{
- /*
- * Do it this way so we only ever do one test_bit in the normal case.
- */
- if (test_bit(BTRFS_FS_CLOSING_START, &fs_info->flags)) {
- if (test_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags))
- return 2;
- return 1;
- }
- return 0;
-}
-
-/*
- * If we remount the fs to be R/O or umount the fs, the cleaner needn't do
- * anything except sleeping. This function is used to check the status of
- * the fs.
- * We check for BTRFS_FS_STATE_RO to avoid races with a concurrent remount,
- * since setting and checking for SB_RDONLY in the superblock's flags is not
- * atomic.
- */
-static inline int btrfs_need_cleaner_sleep(struct btrfs_fs_info *fs_info)
-{
- return test_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state) ||
- btrfs_fs_closing(fs_info);
-}
-
-static inline void btrfs_set_sb_rdonly(struct super_block *sb)
-{
- sb->s_flags |= SB_RDONLY;
- set_bit(BTRFS_FS_STATE_RO, &btrfs_sb(sb)->fs_state);
-}
-
-static inline void btrfs_clear_sb_rdonly(struct super_block *sb)
-{
- sb->s_flags &= ~SB_RDONLY;
- clear_bit(BTRFS_FS_STATE_RO, &btrfs_sb(sb)->fs_state);
-}
-
-/* root-item.c */
-int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
- u64 ref_id, u64 dirid, u64 sequence, const char *name,
- int name_len);
-int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
- u64 ref_id, u64 dirid, u64 *sequence, const char *name,
- int name_len);
-int btrfs_del_root(struct btrfs_trans_handle *trans,
- const struct btrfs_key *key);
-int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
- const struct btrfs_key *key,
- struct btrfs_root_item *item);
-int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_key *key,
- struct btrfs_root_item *item);
-int btrfs_find_root(struct btrfs_root *root, const struct btrfs_key *search_key,
- struct btrfs_path *path, struct btrfs_root_item *root_item,
- struct btrfs_key *root_key);
-int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info);
-void btrfs_set_root_node(struct btrfs_root_item *item,
- struct extent_buffer *node);
-void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
-void btrfs_update_root_times(struct btrfs_trans_handle *trans,
- struct btrfs_root *root);
-
-/* uuid-tree.c */
-int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
- u64 subid);
-int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
- u64 subid);
-int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info);
-
-/* dir-item.c */
-int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
- const char *name, int name_len);
-int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
- int name_len, struct btrfs_inode *dir,
- struct btrfs_key *location, u8 type, u64 index);
-struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 dir,
- const char *name, int name_len,
- int mod);
-struct btrfs_dir_item *
-btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 dir,
- u64 index, const char *name, int name_len,
- int mod);
-struct btrfs_dir_item *
-btrfs_search_dir_index_item(struct btrfs_root *root,
- struct btrfs_path *path, u64 dirid,
- const char *name, int name_len);
-int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct btrfs_dir_item *di);
-int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 objectid,
- const char *name, u16 name_len,
- const void *data, u16 data_len);
-struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 dir,
- const char *name, u16 name_len,
- int mod);
-struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path,
- const char *name,
- int name_len);
-
-/* orphan.c */
-int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 offset);
-int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 offset);
-int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset);
-
-/* file-item.c */
-int btrfs_del_csums(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 bytenr, u64 len);
-blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst);
-int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid, u64 pos,
- u64 num_bytes);
-int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 objectid,
- u64 bytenr, int mod);
-int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_ordered_sum *sums);
-blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
- u64 offset, bool one_ordered);
-int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
- struct list_head *list, int search_commit,
- bool nowait);
-void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
- const struct btrfs_path *path,
- struct btrfs_file_extent_item *fi,
- const bool new_inline,
- struct extent_map *em);
-int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
- u64 len);
-int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start,
- u64 len);
-void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_size);
-u64 btrfs_file_extent_end(const struct btrfs_path *path);
-
-/* inode.c */
-void btrfs_submit_data_write_bio(struct inode *inode, struct bio *bio, int mirror_num);
-void btrfs_submit_data_read_bio(struct inode *inode, struct bio *bio,
- int mirror_num, enum btrfs_compression_type compress_type);
-int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
- u32 pgoff, u8 *csum, const u8 * const csum_expected);
-int btrfs_check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
- u32 bio_offset, struct page *page, u32 pgoff);
-unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
- u32 bio_offset, struct page *page,
- u64 start, u64 end);
-int btrfs_check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
- u32 bio_offset, struct page *page, u32 pgoff);
-noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
- u64 *orig_start, u64 *orig_block_len,
- u64 *ram_bytes, bool nowait, bool strict);
-
-void __btrfs_del_delalloc_inode(struct btrfs_root *root,
- struct btrfs_inode *inode);
-struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
-int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index);
-int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
- struct btrfs_inode *dir, struct btrfs_inode *inode,
- const char *name, int name_len);
-int btrfs_add_link(struct btrfs_trans_handle *trans,
- struct btrfs_inode *parent_inode, struct btrfs_inode *inode,
- const char *name, int name_len, int add_backref, u64 index);
-int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry);
-int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
- int front);
-
-int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
-int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
- bool in_reclaim_context);
-int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
- unsigned int extra_bits,
- struct extent_state **cached_state);
-struct btrfs_new_inode_args {
- /* Input */
- struct inode *dir;
- struct dentry *dentry;
- struct inode *inode;
- bool orphan;
- bool subvol;
-
- /*
- * Output from btrfs_new_inode_prepare(), input to
- * btrfs_create_new_inode().
- */
- struct posix_acl *default_acl;
- struct posix_acl *acl;
-};
-int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
- unsigned int *trans_num_items);
-int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
- struct btrfs_new_inode_args *args);
-void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
-struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
- struct inode *dir);
- void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
- u32 bits);
-void btrfs_clear_delalloc_extent(struct inode *inode,
- struct extent_state *state, u32 bits);
-void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new,
- struct extent_state *other);
-void btrfs_split_delalloc_extent(struct inode *inode,
- struct extent_state *orig, u64 split);
-void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end);
-vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf);
-void btrfs_evict_inode(struct inode *inode);
-struct inode *btrfs_alloc_inode(struct super_block *sb);
-void btrfs_destroy_inode(struct inode *inode);
-void btrfs_free_inode(struct inode *inode);
-int btrfs_drop_inode(struct inode *inode);
-int __init btrfs_init_cachep(void);
-void __cold btrfs_destroy_cachep(void);
-struct inode *btrfs_iget_path(struct super_block *s, u64 ino,
- struct btrfs_root *root, struct btrfs_path *path);
-struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root);
-struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
- struct page *page, size_t pg_offset,
- u64 start, u64 end);
-int btrfs_update_inode(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct btrfs_inode *inode);
-int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct btrfs_inode *inode);
-int btrfs_orphan_add(struct btrfs_trans_handle *trans,
- struct btrfs_inode *inode);
-int btrfs_orphan_cleanup(struct btrfs_root *root);
-int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size);
-void btrfs_add_delayed_iput(struct inode *inode);
-void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info);
-int btrfs_wait_on_delayed_iputs(struct btrfs_fs_info *fs_info);
-int btrfs_prealloc_file_range(struct inode *inode, int mode,
- u64 start, u64 num_bytes, u64 min_size,
- loff_t actual_len, u64 *alloc_hint);
-int btrfs_prealloc_file_range_trans(struct inode *inode,
- struct btrfs_trans_handle *trans, int mode,
- u64 start, u64 num_bytes, u64 min_size,
- loff_t actual_len, u64 *alloc_hint);
-int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page,
- u64 start, u64 end, int *page_started, unsigned long *nr_written,
- struct writeback_control *wbc);
-int btrfs_writepage_cow_fixup(struct page *page);
-void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
- struct page *page, u64 start,
- u64 end, bool uptodate);
-int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
- int compress_type);
-int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
- u64 file_offset, u64 disk_bytenr,
- u64 disk_io_size,
- struct page **pages);
-ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
- struct btrfs_ioctl_encoded_io_args *encoded);
-ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
- const struct btrfs_ioctl_encoded_io_args *encoded);
-
-ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,
- size_t done_before);
-struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter,
- size_t done_before);
-
-extern const struct dentry_operations btrfs_dentry_operations;
-
-/* Inode locking type flags, by default the exclusive lock is taken */
-#define BTRFS_ILOCK_SHARED (1U << 0)
-#define BTRFS_ILOCK_TRY (1U << 1)
-#define BTRFS_ILOCK_MMAP (1U << 2)
-
-int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags);
-void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags);
-void btrfs_update_inode_bytes(struct btrfs_inode *inode,
- const u64 add_bytes,
- const u64 del_bytes);
-void btrfs_assert_inode_range_clean(struct btrfs_inode *inode, u64 start, u64 end);
-
-/* ioctl.c */
-long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
-int btrfs_fileattr_set(struct user_namespace *mnt_userns,
- struct dentry *dentry, struct fileattr *fa);
-int btrfs_ioctl_get_supported_features(void __user *arg);
-void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
-int __pure btrfs_is_empty_uuid(u8 *uuid);
-int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
- struct btrfs_ioctl_defrag_range_args *range,
- u64 newer_than, unsigned long max_to_defrag);
-void btrfs_get_block_group_info(struct list_head *groups_list,
- struct btrfs_ioctl_space_info *space);
-void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
- struct btrfs_ioctl_balance_args *bargs);
-
-/* file.c */
-int __init btrfs_auto_defrag_init(void);
-void __cold btrfs_auto_defrag_exit(void);
-int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
- struct btrfs_inode *inode, u32 extent_thresh);
-int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
-void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
-int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
-extern const struct file_operations btrfs_file_operations;
-int btrfs_drop_extents(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct btrfs_inode *inode,
- struct btrfs_drop_extents_args *args);
-int btrfs_replace_file_extents(struct btrfs_inode *inode,
- struct btrfs_path *path, const u64 start,
- const u64 end,
- struct btrfs_replace_extent_info *extent_info,
- struct btrfs_trans_handle **trans_out);
-int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
- struct btrfs_inode *inode, u64 start, u64 end);
-ssize_t btrfs_do_write_iter(struct kiocb *iocb, struct iov_iter *from,
- const struct btrfs_ioctl_encoded_io_args *encoded);
-int btrfs_release_file(struct inode *inode, struct file *file);
-int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages,
- size_t num_pages, loff_t pos, size_t write_bytes,
- struct extent_state **cached, bool noreserve);
-int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
-int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
- size_t *write_bytes, bool nowait);
-void btrfs_check_nocow_unlock(struct btrfs_inode *inode);
-bool btrfs_find_delalloc_in_range(struct btrfs_inode *inode, u64 start, u64 end,
- u64 *delalloc_start_ret, u64 *delalloc_end_ret);
-
-/* tree-defrag.c */
-int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
- struct btrfs_root *root);
-
-/* super.c */
-int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
- unsigned long new_flags);
-int btrfs_sync_fs(struct super_block *sb, int wait);
-char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
- u64 subvol_objectid);
-
-static inline __printf(2, 3) __cold
-void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
-{
-}
-
-#ifdef CONFIG_PRINTK_INDEX
-
-#define btrfs_printk(fs_info, fmt, args...) \
-do { \
- printk_index_subsys_emit("%sBTRFS %s (device %s): ", NULL, fmt); \
- _btrfs_printk(fs_info, fmt, ##args); \
-} while (0)
-
-__printf(2, 3)
-__cold
-void _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...);
-
-#elif defined(CONFIG_PRINTK)
-
-#define btrfs_printk(fs_info, fmt, args...) \
- _btrfs_printk(fs_info, fmt, ##args)
-
-__printf(2, 3)
-__cold
-void _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...);
-
-#else
-
-#define btrfs_printk(fs_info, fmt, args...) \
- btrfs_no_printk(fs_info, fmt, ##args)
-#endif
-
-#define btrfs_emerg(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_EMERG fmt, ##args)
-#define btrfs_alert(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_ALERT fmt, ##args)
-#define btrfs_crit(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_CRIT fmt, ##args)
-#define btrfs_err(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_ERR fmt, ##args)
-#define btrfs_warn(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_WARNING fmt, ##args)
-#define btrfs_notice(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_NOTICE fmt, ##args)
-#define btrfs_info(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_INFO fmt, ##args)
-
-/*
- * Wrappers that use printk_in_rcu
- */
-#define btrfs_emerg_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_EMERG fmt, ##args)
-#define btrfs_alert_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_ALERT fmt, ##args)
-#define btrfs_crit_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_CRIT fmt, ##args)
-#define btrfs_err_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_ERR fmt, ##args)
-#define btrfs_warn_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_WARNING fmt, ##args)
-#define btrfs_notice_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
-#define btrfs_info_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_INFO fmt, ##args)
-
-/*
- * Wrappers that use a ratelimited printk_in_rcu
- */
-#define btrfs_emerg_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_EMERG fmt, ##args)
-#define btrfs_alert_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_ALERT fmt, ##args)
-#define btrfs_crit_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_CRIT fmt, ##args)
-#define btrfs_err_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_ERR fmt, ##args)
-#define btrfs_warn_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_WARNING fmt, ##args)
-#define btrfs_notice_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
-#define btrfs_info_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_INFO fmt, ##args)
-
-/*
- * Wrappers that use a ratelimited printk
- */
-#define btrfs_emerg_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_EMERG fmt, ##args)
-#define btrfs_alert_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_ALERT fmt, ##args)
-#define btrfs_crit_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_CRIT fmt, ##args)
-#define btrfs_err_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_ERR fmt, ##args)
-#define btrfs_warn_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_WARNING fmt, ##args)
-#define btrfs_notice_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_NOTICE fmt, ##args)
-#define btrfs_info_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_INFO fmt, ##args)
-
-#if defined(CONFIG_DYNAMIC_DEBUG)
-#define btrfs_debug(fs_info, fmt, args...) \
- _dynamic_func_call_no_desc(fmt, btrfs_printk, \
- fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
- _dynamic_func_call_no_desc(fmt, btrfs_printk_in_rcu, \
- fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
- _dynamic_func_call_no_desc(fmt, btrfs_printk_rl_in_rcu, \
- fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl(fs_info, fmt, args...) \
- _dynamic_func_call_no_desc(fmt, btrfs_printk_ratelimited, \
- fs_info, KERN_DEBUG fmt, ##args)
-#elif defined(DEBUG)
-#define btrfs_debug(fs_info, fmt, args...) \
- btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl(fs_info, fmt, args...) \
- btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, ##args)
-#else
-#define btrfs_debug(fs_info, fmt, args...) \
- btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
- btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
- btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
-#define btrfs_debug_rl(fs_info, fmt, args...) \
- btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
-#endif
-
-#define btrfs_printk_in_rcu(fs_info, fmt, args...) \
-do { \
- rcu_read_lock(); \
- btrfs_printk(fs_info, fmt, ##args); \
- rcu_read_unlock(); \
-} while (0)
-
-#define btrfs_no_printk_in_rcu(fs_info, fmt, args...) \
-do { \
- rcu_read_lock(); \
- btrfs_no_printk(fs_info, fmt, ##args); \
- rcu_read_unlock(); \
-} while (0)
-
-#define btrfs_printk_ratelimited(fs_info, fmt, args...) \
-do { \
- static DEFINE_RATELIMIT_STATE(_rs, \
- DEFAULT_RATELIMIT_INTERVAL, \
- DEFAULT_RATELIMIT_BURST); \
- if (__ratelimit(&_rs)) \
- btrfs_printk(fs_info, fmt, ##args); \
-} while (0)
-
-#define btrfs_printk_rl_in_rcu(fs_info, fmt, args...) \
-do { \
- rcu_read_lock(); \
- btrfs_printk_ratelimited(fs_info, fmt, ##args); \
- rcu_read_unlock(); \
-} while (0)
-
-#ifdef CONFIG_BTRFS_ASSERT
-__cold __noreturn
-static inline void assertfail(const char *expr, const char *file, int line)
-{
- pr_err("assertion failed: %s, in %s:%d\n", expr, file, line);
- BUG();
-}
-
-#define ASSERT(expr) \
- (likely(expr) ? (void)0 : assertfail(#expr, __FILE__, __LINE__))
-
-#else
-static inline void assertfail(const char *expr, const char* file, int line) { }
-#define ASSERT(expr) (void)(expr)
-#endif
-
-#if BITS_PER_LONG == 32
-#define BTRFS_32BIT_MAX_FILE_SIZE (((u64)ULONG_MAX + 1) << PAGE_SHIFT)
-/*
- * The warning threshold is 5/8th of the MAX_LFS_FILESIZE that limits the logical
- * addresses of extents.
- *
- * For 4K page size it's about 10T, for 64K it's 160T.
- */
-#define BTRFS_32BIT_EARLY_WARN_THRESHOLD (BTRFS_32BIT_MAX_FILE_SIZE * 5 / 8)
-void btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info);
-void btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info);
-#endif
-
-/*
- * Get the correct offset inside the page of extent buffer.
- *
- * @eb: target extent buffer
- * @start: offset inside the extent buffer
- *
- * Will handle both sectorsize == PAGE_SIZE and sectorsize < PAGE_SIZE cases.
- */
-static inline size_t get_eb_offset_in_page(const struct extent_buffer *eb,
- unsigned long offset)
-{
- /*
- * For sectorsize == PAGE_SIZE case, eb->start will always be aligned
- * to PAGE_SIZE, thus adding it won't cause any difference.
- *
- * For sectorsize < PAGE_SIZE, we must only read the data that belongs
- * to the eb, thus we have to take the eb->start into consideration.
- */
- return offset_in_page(offset + eb->start);
-}
-
-static inline unsigned long get_eb_page_index(unsigned long offset)
-{
- /*
- * For sectorsize == PAGE_SIZE case, plain >> PAGE_SHIFT is enough.
- *
- * For sectorsize < PAGE_SIZE case, we only support 64K PAGE_SIZE,
- * and have ensured that all tree blocks are contained in one page,
- * thus we always get index == 0.
- */
- return offset >> PAGE_SHIFT;
-}
-
-/*
- * Use that for functions that are conditionally exported for sanity tests but
- * otherwise static
- */
-#ifndef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-#define EXPORT_FOR_TESTS static
-#else
-#define EXPORT_FOR_TESTS
-#endif
-
-__cold
-static inline void btrfs_print_v0_err(struct btrfs_fs_info *fs_info)
-{
- btrfs_err(fs_info,
-"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel");
-}
-
-__printf(5, 6)
-__cold
-void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
- unsigned int line, int errno, const char *fmt, ...);
-
-const char * __attribute_const__ btrfs_decode_error(int errno);
-
-__cold
-void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
- const char *function,
- unsigned int line, int errno, bool first_hit);
-
-/*
- * Call btrfs_abort_transaction as early as possible when an error condition is
- * detected, that way the exact line number is reported.
- */
-#define btrfs_abort_transaction(trans, errno) \
-do { \
- bool first = false; \
- /* Report first abort since mount */ \
- if (!test_and_set_bit(BTRFS_FS_STATE_TRANS_ABORTED, \
- &((trans)->fs_info->fs_state))) { \
- first = true; \
- if ((errno) != -EIO && (errno) != -EROFS) { \
- WARN(1, KERN_DEBUG \
- "BTRFS: Transaction aborted (error %d)\n", \
- (errno)); \
- } else { \
- btrfs_debug((trans)->fs_info, \
- "Transaction aborted (error %d)", \
- (errno)); \
- } \
- } \
- __btrfs_abort_transaction((trans), __func__, \
- __LINE__, (errno), first); \
-} while (0)
-
-#ifdef CONFIG_PRINTK_INDEX
-
-#define btrfs_handle_fs_error(fs_info, errno, fmt, args...) \
-do { \
- printk_index_subsys_emit( \
- "BTRFS: error (device %s%s) in %s:%d: errno=%d %s", \
- KERN_CRIT, fmt); \
- __btrfs_handle_fs_error((fs_info), __func__, __LINE__, \
- (errno), fmt, ##args); \
-} while (0)
-
-#else
-
-#define btrfs_handle_fs_error(fs_info, errno, fmt, args...) \
- __btrfs_handle_fs_error((fs_info), __func__, __LINE__, \
- (errno), fmt, ##args)
-
-#endif
-
-#define BTRFS_FS_ERROR(fs_info) (unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
- &(fs_info)->fs_state)))
-#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info) \
- (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR, \
- &(fs_info)->fs_state)))
-
-__printf(5, 6)
-__cold
-void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
- unsigned int line, int errno, const char *fmt, ...);
-/*
- * If BTRFS_MOUNT_PANIC_ON_FATAL_ERROR is in mount_opt, __btrfs_panic
- * will panic(). Otherwise we BUG() here.
- */
-#define btrfs_panic(fs_info, errno, fmt, args...) \
-do { \
- __btrfs_panic(fs_info, __func__, __LINE__, errno, fmt, ##args); \
- BUG(); \
-} while (0)
-
-
-/* compatibility and incompatibility defines */
-
-#define btrfs_set_fs_incompat(__fs_info, opt) \
- __btrfs_set_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, \
- #opt)
-
-static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
- u64 flag, const char* name)
-{
- struct btrfs_super_block *disk_super;
- u64 features;
-
- disk_super = fs_info->super_copy;
- features = btrfs_super_incompat_flags(disk_super);
- if (!(features & flag)) {
- spin_lock(&fs_info->super_lock);
- features = btrfs_super_incompat_flags(disk_super);
- if (!(features & flag)) {
- features |= flag;
- btrfs_set_super_incompat_flags(disk_super, features);
- btrfs_info(fs_info,
- "setting incompat feature flag for %s (0x%llx)",
- name, flag);
- }
- spin_unlock(&fs_info->super_lock);
- }
-}
-
-#define btrfs_clear_fs_incompat(__fs_info, opt) \
- __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, \
- #opt)
-
-static inline void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info,
- u64 flag, const char* name)
-{
- struct btrfs_super_block *disk_super;
- u64 features;
-
- disk_super = fs_info->super_copy;
- features = btrfs_super_incompat_flags(disk_super);
- if (features & flag) {
- spin_lock(&fs_info->super_lock);
- features = btrfs_super_incompat_flags(disk_super);
- if (features & flag) {
- features &= ~flag;
- btrfs_set_super_incompat_flags(disk_super, features);
- btrfs_info(fs_info,
- "clearing incompat feature flag for %s (0x%llx)",
- name, flag);
- }
- spin_unlock(&fs_info->super_lock);
- }
-}
-
-#define btrfs_fs_incompat(fs_info, opt) \
- __btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
-
-static inline bool __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
-{
- struct btrfs_super_block *disk_super;
- disk_super = fs_info->super_copy;
- return !!(btrfs_super_incompat_flags(disk_super) & flag);
-}
-
-#define btrfs_set_fs_compat_ro(__fs_info, opt) \
- __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, \
- #opt)
-
-static inline void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info,
- u64 flag, const char *name)
-{
- struct btrfs_super_block *disk_super;
- u64 features;
-
- disk_super = fs_info->super_copy;
- features = btrfs_super_compat_ro_flags(disk_super);
- if (!(features & flag)) {
- spin_lock(&fs_info->super_lock);
- features = btrfs_super_compat_ro_flags(disk_super);
- if (!(features & flag)) {
- features |= flag;
- btrfs_set_super_compat_ro_flags(disk_super, features);
- btrfs_info(fs_info,
- "setting compat-ro feature flag for %s (0x%llx)",
- name, flag);
- }
- spin_unlock(&fs_info->super_lock);
- }
-}
-
-#define btrfs_clear_fs_compat_ro(__fs_info, opt) \
- __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, \
- #opt)
-
-static inline void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info,
- u64 flag, const char *name)
-{
- struct btrfs_super_block *disk_super;
- u64 features;
-
- disk_super = fs_info->super_copy;
- features = btrfs_super_compat_ro_flags(disk_super);
- if (features & flag) {
- spin_lock(&fs_info->super_lock);
- features = btrfs_super_compat_ro_flags(disk_super);
- if (features & flag) {
- features &= ~flag;
- btrfs_set_super_compat_ro_flags(disk_super, features);
- btrfs_info(fs_info,
- "clearing compat-ro feature flag for %s (0x%llx)",
- name, flag);
- }
- spin_unlock(&fs_info->super_lock);
- }
-}
-
-#define btrfs_fs_compat_ro(fs_info, opt) \
- __btrfs_fs_compat_ro((fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
-
-static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
-{
- struct btrfs_super_block *disk_super;
- disk_super = fs_info->super_copy;
- return !!(btrfs_super_compat_ro_flags(disk_super) & flag);
-}
-
-/* acl.c */
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
-struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
-int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
- struct posix_acl *acl, int type);
-int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
- struct posix_acl *acl, int type);
-#else
-#define btrfs_get_acl NULL
-#define btrfs_set_acl NULL
-static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
- struct inode *inode, struct posix_acl *acl,
- int type)
-{
- return -EOPNOTSUPP;
-}
-#endif
-
-/* relocation.c */
-int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start);
-int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
- struct btrfs_root *root);
-int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
- struct btrfs_root *root);
-int btrfs_recover_relocation(struct btrfs_fs_info *fs_info);
-int btrfs_reloc_clone_csums(struct btrfs_inode *inode, u64 file_pos, u64 len);
-int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct extent_buffer *buf,
- struct extent_buffer *cow);
-void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending,
- u64 *bytes_to_reserve);
-int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
- struct btrfs_pending_snapshot *pending);
-int btrfs_should_cancel_balance(struct btrfs_fs_info *fs_info);
-struct btrfs_root *find_reloc_root(struct btrfs_fs_info *fs_info,
- u64 bytenr);
-int btrfs_should_ignore_reloc_root(struct btrfs_root *root);
-
-/* scrub.c */
-int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
- u64 end, struct btrfs_scrub_progress *progress,
- int readonly, int is_dev_replace);
-void btrfs_scrub_pause(struct btrfs_fs_info *fs_info);
-void btrfs_scrub_continue(struct btrfs_fs_info *fs_info);
-int btrfs_scrub_cancel(struct btrfs_fs_info *info);
-int btrfs_scrub_cancel_dev(struct btrfs_device *dev);
-int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid,
- struct btrfs_scrub_progress *progress);
-
-/* dev-replace.c */
-void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info);
-void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount);
-
-static inline void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info)
-{
- btrfs_bio_counter_sub(fs_info, 1);
-}
static inline int is_fstree(u64 rootid)
{
@@ -4054,61 +695,16 @@ static inline int is_fstree(u64 rootid)
return 0;
}
-static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
-{
- return signal_pending(current);
-}
-
-/* verity.c */
-#ifdef CONFIG_FS_VERITY
-
-extern const struct fsverity_operations btrfs_verityops;
-int btrfs_drop_verity_items(struct btrfs_inode *inode);
-int btrfs_get_verity_descriptor(struct inode *inode, void *buf, size_t buf_size);
-
-BTRFS_SETGET_FUNCS(verity_descriptor_encryption, struct btrfs_verity_descriptor_item,
- encryption, 8);
-BTRFS_SETGET_FUNCS(verity_descriptor_size, struct btrfs_verity_descriptor_item,
- size, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_encryption,
- struct btrfs_verity_descriptor_item, encryption, 8);
-BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_size,
- struct btrfs_verity_descriptor_item, size, 64);
-
-#else
-
-static inline int btrfs_drop_verity_items(struct btrfs_inode *inode)
-{
- return 0;
-}
-
-static inline int btrfs_get_verity_descriptor(struct inode *inode, void *buf,
- size_t buf_size)
-{
- return -EPERM;
-}
-
-#endif
-
-/* Sanity test specific functions */
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-void btrfs_test_destroy_inode(struct inode *inode);
-static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)
-{
- return test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
-}
-#else
-static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)
-{
- return 0;
-}
-#endif
-
static inline bool btrfs_is_data_reloc_root(const struct btrfs_root *root)
{
return root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID;
}
+int btrfs_super_csum_size(const struct btrfs_super_block *s);
+const char *btrfs_super_csum_name(u16 csum_type);
+const char *btrfs_super_csum_driver(u16 csum_type);
+size_t __attribute_const__ btrfs_get_num_csums(void);
+
/*
* We use page status Private2 to indicate there is an ordered extent with
* unfinished IO.
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
new file mode 100644
index 000000000000..0a3c261b69c9
--- /dev/null
+++ b/fs/btrfs/defrag.c
@@ -0,0 +1,1376 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ */
+
+#include <linux/sched.h>
+#include "ctree.h"
+#include "disk-io.h"
+#include "print-tree.h"
+#include "transaction.h"
+#include "locking.h"
+#include "accessors.h"
+#include "messages.h"
+#include "delalloc-space.h"
+#include "subpage.h"
+#include "defrag.h"
+#include "file-item.h"
+#include "super.h"
+
+static struct kmem_cache *btrfs_inode_defrag_cachep;
+
+/*
+ * When auto defrag is enabled we queue up these defrag structs to remember
+ * which inodes need defragging passes.
+ */
+struct inode_defrag {
+ struct rb_node rb_node;
+ /* Inode number */
+ u64 ino;
+ /*
+ * Transid where the defrag was added, we search for extents newer than
+ * this.
+ */
+ u64 transid;
+
+ /* Root objectid */
+ u64 root;
+
+ /*
+ * The extent size threshold for autodefrag.
+ *
+ * This value is different for compressed/non-compressed extents, thus
+ * needs to be passed from higher layer.
+ * (aka, inode_should_defrag())
+ */
+ u32 extent_thresh;
+};
+
+static int __compare_inode_defrag(struct inode_defrag *defrag1,
+ struct inode_defrag *defrag2)
+{
+ if (defrag1->root > defrag2->root)
+ return 1;
+ else if (defrag1->root < defrag2->root)
+ return -1;
+ else if (defrag1->ino > defrag2->ino)
+ return 1;
+ else if (defrag1->ino < defrag2->ino)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * Pop a record for an inode into the defrag tree. The lock must be held
+ * already.
+ *
+ * If you're inserting a record for an older transid than an existing record,
+ * the transid already in the tree is lowered.
+ *
+ * If an existing record is found the defrag item you pass in is freed.
+ */
+static int __btrfs_add_inode_defrag(struct btrfs_inode *inode,
+ struct inode_defrag *defrag)
+{
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
+ struct inode_defrag *entry;
+ struct rb_node **p;
+ struct rb_node *parent = NULL;
+ int ret;
+
+ p = &fs_info->defrag_inodes.rb_node;
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct inode_defrag, rb_node);
+
+ ret = __compare_inode_defrag(defrag, entry);
+ if (ret < 0)
+ p = &parent->rb_left;
+ else if (ret > 0)
+ p = &parent->rb_right;
+ else {
+ /*
+ * If we're reinserting an entry for an old defrag run,
+ * make sure to lower the transid of our existing
+ * record.
+ */
+ if (defrag->transid < entry->transid)
+ entry->transid = defrag->transid;
+ entry->extent_thresh = min(defrag->extent_thresh,
+ entry->extent_thresh);
+ return -EEXIST;
+ }
+ }
+ set_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags);
+ rb_link_node(&defrag->rb_node, parent, p);
+ rb_insert_color(&defrag->rb_node, &fs_info->defrag_inodes);
+ return 0;
+}
+
+static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info)
+{
+ if (!btrfs_test_opt(fs_info, AUTO_DEFRAG))
+ return 0;
+
+ if (btrfs_fs_closing(fs_info))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Insert a defrag record for this inode if auto defrag is enabled.
+ */
+int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *inode, u32 extent_thresh)
+{
+ struct btrfs_root *root = inode->root;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct inode_defrag *defrag;
+ u64 transid;
+ int ret;
+
+ if (!__need_auto_defrag(fs_info))
+ return 0;
+
+ if (test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags))
+ return 0;
+
+ if (trans)
+ transid = trans->transid;
+ else
+ transid = inode->root->last_trans;
+
+ defrag = kmem_cache_zalloc(btrfs_inode_defrag_cachep, GFP_NOFS);
+ if (!defrag)
+ return -ENOMEM;
+
+ defrag->ino = btrfs_ino(inode);
+ defrag->transid = transid;
+ defrag->root = root->root_key.objectid;
+ defrag->extent_thresh = extent_thresh;
+
+ spin_lock(&fs_info->defrag_inodes_lock);
+ if (!test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) {
+ /*
+ * If we set IN_DEFRAG flag and evict the inode from memory,
+ * and then re-read this inode, this new inode doesn't have
+ * IN_DEFRAG flag. At the case, we may find the existed defrag.
+ */
+ ret = __btrfs_add_inode_defrag(inode, defrag);
+ if (ret)
+ kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+ } else {
+ kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+ }
+ spin_unlock(&fs_info->defrag_inodes_lock);
+ return 0;
+}
+
+/*
+ * Pick the defragable inode that we want, if it doesn't exist, we will get the
+ * next one.
+ */
+static struct inode_defrag *btrfs_pick_defrag_inode(
+ struct btrfs_fs_info *fs_info, u64 root, u64 ino)
+{
+ struct inode_defrag *entry = NULL;
+ struct inode_defrag tmp;
+ struct rb_node *p;
+ struct rb_node *parent = NULL;
+ int ret;
+
+ tmp.ino = ino;
+ tmp.root = root;
+
+ spin_lock(&fs_info->defrag_inodes_lock);
+ p = fs_info->defrag_inodes.rb_node;
+ while (p) {
+ parent = p;
+ entry = rb_entry(parent, struct inode_defrag, rb_node);
+
+ ret = __compare_inode_defrag(&tmp, entry);
+ if (ret < 0)
+ p = parent->rb_left;
+ else if (ret > 0)
+ p = parent->rb_right;
+ else
+ goto out;
+ }
+
+ if (parent && __compare_inode_defrag(&tmp, entry) > 0) {
+ parent = rb_next(parent);
+ if (parent)
+ entry = rb_entry(parent, struct inode_defrag, rb_node);
+ else
+ entry = NULL;
+ }
+out:
+ if (entry)
+ rb_erase(parent, &fs_info->defrag_inodes);
+ spin_unlock(&fs_info->defrag_inodes_lock);
+ return entry;
+}
+
+void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
+{
+ struct inode_defrag *defrag;
+ struct rb_node *node;
+
+ spin_lock(&fs_info->defrag_inodes_lock);
+ node = rb_first(&fs_info->defrag_inodes);
+ while (node) {
+ rb_erase(node, &fs_info->defrag_inodes);
+ defrag = rb_entry(node, struct inode_defrag, rb_node);
+ kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+
+ cond_resched_lock(&fs_info->defrag_inodes_lock);
+
+ node = rb_first(&fs_info->defrag_inodes);
+ }
+ spin_unlock(&fs_info->defrag_inodes_lock);
+}
+
+#define BTRFS_DEFRAG_BATCH 1024
+
+static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
+ struct inode_defrag *defrag)
+{
+ struct btrfs_root *inode_root;
+ struct inode *inode;
+ struct btrfs_ioctl_defrag_range_args range;
+ int ret = 0;
+ u64 cur = 0;
+
+again:
+ if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
+ goto cleanup;
+ if (!__need_auto_defrag(fs_info))
+ goto cleanup;
+
+ /* Get the inode */
+ inode_root = btrfs_get_fs_root(fs_info, defrag->root, true);
+ if (IS_ERR(inode_root)) {
+ ret = PTR_ERR(inode_root);
+ goto cleanup;
+ }
+
+ inode = btrfs_iget(fs_info->sb, defrag->ino, inode_root);
+ btrfs_put_root(inode_root);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
+ goto cleanup;
+ }
+
+ if (cur >= i_size_read(inode)) {
+ iput(inode);
+ goto cleanup;
+ }
+
+ /* Do a chunk of defrag */
+ clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
+ memset(&range, 0, sizeof(range));
+ range.len = (u64)-1;
+ range.start = cur;
+ range.extent_thresh = defrag->extent_thresh;
+
+ sb_start_write(fs_info->sb);
+ ret = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
+ BTRFS_DEFRAG_BATCH);
+ sb_end_write(fs_info->sb);
+ iput(inode);
+
+ if (ret < 0)
+ goto cleanup;
+
+ cur = max(cur + fs_info->sectorsize, range.start);
+ goto again;
+
+cleanup:
+ kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+ return ret;
+}
+
+/*
+ * Run through the list of inodes in the FS that need defragging.
+ */
+int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
+{
+ struct inode_defrag *defrag;
+ u64 first_ino = 0;
+ u64 root_objectid = 0;
+
+ atomic_inc(&fs_info->defrag_running);
+ while (1) {
+ /* Pause the auto defragger. */
+ if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
+ break;
+
+ if (!__need_auto_defrag(fs_info))
+ break;
+
+ /* find an inode to defrag */
+ defrag = btrfs_pick_defrag_inode(fs_info, root_objectid, first_ino);
+ if (!defrag) {
+ if (root_objectid || first_ino) {
+ root_objectid = 0;
+ first_ino = 0;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ first_ino = defrag->ino + 1;
+ root_objectid = defrag->root;
+
+ __btrfs_run_defrag_inode(fs_info, defrag);
+ }
+ atomic_dec(&fs_info->defrag_running);
+
+ /*
+ * During unmount, we use the transaction_wait queue to wait for the
+ * defragger to stop.
+ */
+ wake_up(&fs_info->transaction_wait);
+ return 0;
+}
+
+/*
+ * Defrag all the leaves in a given btree.
+ * Read all the leaves and try to get key order to
+ * better reflect disk order
+ */
+
+int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct btrfs_path *path = NULL;
+ struct btrfs_key key;
+ int ret = 0;
+ int wret;
+ int level;
+ int next_key_ret = 0;
+ u64 last_ret = 0;
+
+ if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
+ goto out;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ level = btrfs_header_level(root->node);
+
+ if (level == 0)
+ goto out;
+
+ if (root->defrag_progress.objectid == 0) {
+ struct extent_buffer *root_node;
+ u32 nritems;
+
+ root_node = btrfs_lock_root_node(root);
+ nritems = btrfs_header_nritems(root_node);
+ root->defrag_max.objectid = 0;
+ /* from above we know this is not a leaf */
+ btrfs_node_key_to_cpu(root_node, &root->defrag_max,
+ nritems - 1);
+ btrfs_tree_unlock(root_node);
+ free_extent_buffer(root_node);
+ memset(&key, 0, sizeof(key));
+ } else {
+ memcpy(&key, &root->defrag_progress, sizeof(key));
+ }
+
+ path->keep_locks = 1;
+
+ ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ btrfs_release_path(path);
+ /*
+ * We don't need a lock on a leaf. btrfs_realloc_node() will lock all
+ * leafs from path->nodes[1], so set lowest_level to 1 to avoid later
+ * a deadlock (attempting to write lock an already write locked leaf).
+ */
+ path->lowest_level = 1;
+ wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+
+ if (wret < 0) {
+ ret = wret;
+ goto out;
+ }
+ if (!path->nodes[1]) {
+ ret = 0;
+ goto out;
+ }
+ /*
+ * The node at level 1 must always be locked when our path has
+ * keep_locks set and lowest_level is 1, regardless of the value of
+ * path->slots[1].
+ */
+ BUG_ON(path->locks[1] == 0);
+ ret = btrfs_realloc_node(trans, root,
+ path->nodes[1], 0,
+ &last_ret,
+ &root->defrag_progress);
+ if (ret) {
+ WARN_ON(ret == -EAGAIN);
+ goto out;
+ }
+ /*
+ * Now that we reallocated the node we can find the next key. Note that
+ * btrfs_find_next_key() can release our path and do another search
+ * without COWing, this is because even with path->keep_locks = 1,
+ * btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a
+ * node when path->slots[node_level - 1] does not point to the last
+ * item or a slot beyond the last item (ctree.c:unlock_up()). Therefore
+ * we search for the next key after reallocating our node.
+ */
+ path->slots[1] = btrfs_header_nritems(path->nodes[1]);
+ next_key_ret = btrfs_find_next_key(root, path, &key, 1,
+ BTRFS_OLDEST_GENERATION);
+ if (next_key_ret == 0) {
+ memcpy(&root->defrag_progress, &key, sizeof(key));
+ ret = -EAGAIN;
+ }
+out:
+ btrfs_free_path(path);
+ if (ret == -EAGAIN) {
+ if (root->defrag_max.objectid > root->defrag_progress.objectid)
+ goto done;
+ if (root->defrag_max.type > root->defrag_progress.type)
+ goto done;
+ if (root->defrag_max.offset > root->defrag_progress.offset)
+ goto done;
+ ret = 0;
+ }
+done:
+ if (ret != -EAGAIN)
+ memset(&root->defrag_progress, 0,
+ sizeof(root->defrag_progress));
+
+ return ret;
+}
+
+/*
+ * Defrag specific helper to get an extent map.
+ *
+ * Differences between this and btrfs_get_extent() are:
+ *
+ * - No extent_map will be added to inode->extent_tree
+ * To reduce memory usage in the long run.
+ *
+ * - Extra optimization to skip file extents older than @newer_than
+ * By using btrfs_search_forward() we can skip entire file ranges that
+ * have extents created in past transactions, because btrfs_search_forward()
+ * will not visit leaves and nodes with a generation smaller than given
+ * minimal generation threshold (@newer_than).
+ *
+ * Return valid em if we find a file extent matching the requirement.
+ * Return NULL if we can not find a file extent matching the requirement.
+ *
+ * Return ERR_PTR() for error.
+ */
+static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
+ u64 start, u64 newer_than)
+{
+ struct btrfs_root *root = inode->root;
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_path path = { 0 };
+ struct extent_map *em;
+ struct btrfs_key key;
+ u64 ino = btrfs_ino(inode);
+ int ret;
+
+ em = alloc_extent_map();
+ if (!em) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ key.objectid = ino;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = start;
+
+ if (newer_than) {
+ ret = btrfs_search_forward(root, &key, &path, newer_than);
+ if (ret < 0)
+ goto err;
+ /* Can't find anything newer */
+ if (ret > 0)
+ goto not_found;
+ } else {
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret < 0)
+ goto err;
+ }
+ if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
+ /*
+ * If btrfs_search_slot() makes path to point beyond nritems,
+ * we should not have an empty leaf, as this inode must at
+ * least have its INODE_ITEM.
+ */
+ ASSERT(btrfs_header_nritems(path.nodes[0]));
+ path.slots[0] = btrfs_header_nritems(path.nodes[0]) - 1;
+ }
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+ /* Perfect match, no need to go one slot back */
+ if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY &&
+ key.offset == start)
+ goto iterate;
+
+ /* We didn't find a perfect match, needs to go one slot back */
+ if (path.slots[0] > 0) {
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+ if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY)
+ path.slots[0]--;
+ }
+
+iterate:
+ /* Iterate through the path to find a file extent covering @start */
+ while (true) {
+ u64 extent_end;
+
+ if (path.slots[0] >= btrfs_header_nritems(path.nodes[0]))
+ goto next;
+
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+
+ /*
+ * We may go one slot back to INODE_REF/XATTR item, then
+ * need to go forward until we reach an EXTENT_DATA.
+ * But we should still has the correct ino as key.objectid.
+ */
+ if (WARN_ON(key.objectid < ino) || key.type < BTRFS_EXTENT_DATA_KEY)
+ goto next;
+
+ /* It's beyond our target range, definitely not extent found */
+ if (key.objectid > ino || key.type > BTRFS_EXTENT_DATA_KEY)
+ goto not_found;
+
+ /*
+ * | |<- File extent ->|
+ * \- start
+ *
+ * This means there is a hole between start and key.offset.
+ */
+ if (key.offset > start) {
+ em->start = start;
+ em->orig_start = start;
+ em->block_start = EXTENT_MAP_HOLE;
+ em->len = key.offset - start;
+ break;
+ }
+
+ fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_file_extent_item);
+ extent_end = btrfs_file_extent_end(&path);
+
+ /*
+ * |<- file extent ->| |
+ * \- start
+ *
+ * We haven't reached start, search next slot.
+ */
+ if (extent_end <= start)
+ goto next;
+
+ /* Now this extent covers @start, convert it to em */
+ btrfs_extent_item_to_extent_map(inode, &path, fi, em);
+ break;
+next:
+ ret = btrfs_next_item(root, &path);
+ if (ret < 0)
+ goto err;
+ if (ret > 0)
+ goto not_found;
+ }
+ btrfs_release_path(&path);
+ return em;
+
+not_found:
+ btrfs_release_path(&path);
+ free_extent_map(em);
+ return NULL;
+
+err:
+ btrfs_release_path(&path);
+ free_extent_map(em);
+ return ERR_PTR(ret);
+}
+
+static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
+ u64 newer_than, bool locked)
+{
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+ struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+ struct extent_map *em;
+ const u32 sectorsize = BTRFS_I(inode)->root->fs_info->sectorsize;
+
+ /*
+ * Hopefully we have this extent in the tree already, try without the
+ * full extent lock.
+ */
+ read_lock(&em_tree->lock);
+ em = lookup_extent_mapping(em_tree, start, sectorsize);
+ read_unlock(&em_tree->lock);
+
+ /*
+ * We can get a merged extent, in that case, we need to re-search
+ * tree to get the original em for defrag.
+ *
+ * If @newer_than is 0 or em::generation < newer_than, we can trust
+ * this em, as either we don't care about the generation, or the
+ * merged extent map will be rejected anyway.
+ */
+ if (em && test_bit(EXTENT_FLAG_MERGED, &em->flags) &&
+ newer_than && em->generation >= newer_than) {
+ free_extent_map(em);
+ em = NULL;
+ }
+
+ if (!em) {
+ struct extent_state *cached = NULL;
+ u64 end = start + sectorsize - 1;
+
+ /* Get the big lock and read metadata off disk. */
+ if (!locked)
+ lock_extent(io_tree, start, end, &cached);
+ em = defrag_get_extent(BTRFS_I(inode), start, newer_than);
+ if (!locked)
+ unlock_extent(io_tree, start, end, &cached);
+
+ if (IS_ERR(em))
+ return NULL;
+ }
+
+ return em;
+}
+
+static u32 get_extent_max_capacity(const struct btrfs_fs_info *fs_info,
+ const struct extent_map *em)
+{
+ if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
+ return BTRFS_MAX_COMPRESSED;
+ return fs_info->max_extent_size;
+}
+
+static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
+ u32 extent_thresh, u64 newer_than, bool locked)
+{
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct extent_map *next;
+ bool ret = false;
+
+ /* This is the last extent */
+ if (em->start + em->len >= i_size_read(inode))
+ return false;
+
+ /*
+ * Here we need to pass @newer_then when checking the next extent, or
+ * we will hit a case we mark current extent for defrag, but the next
+ * one will not be a target.
+ * This will just cause extra IO without really reducing the fragments.
+ */
+ next = defrag_lookup_extent(inode, em->start + em->len, newer_than, locked);
+ /* No more em or hole */
+ if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)
+ goto out;
+ if (test_bit(EXTENT_FLAG_PREALLOC, &next->flags))
+ goto out;
+ /*
+ * If the next extent is at its max capacity, defragging current extent
+ * makes no sense, as the total number of extents won't change.
+ */
+ if (next->len >= get_extent_max_capacity(fs_info, em))
+ goto out;
+ /* Skip older extent */
+ if (next->generation < newer_than)
+ goto out;
+ /* Also check extent size */
+ if (next->len >= extent_thresh)
+ goto out;
+
+ ret = true;
+out:
+ free_extent_map(next);
+ return ret;
+}
+
+/*
+ * Prepare one page to be defragged.
+ *
+ * This will ensure:
+ *
+ * - Returned page is locked and has been set up properly.
+ * - No ordered extent exists in the page.
+ * - The page is uptodate.
+ *
+ * NOTE: Caller should also wait for page writeback after the cluster is
+ * prepared, here we don't do writeback wait for each page.
+ */
+static struct page *defrag_prepare_one_page(struct btrfs_inode *inode, pgoff_t index)
+{
+ struct address_space *mapping = inode->vfs_inode.i_mapping;
+ gfp_t mask = btrfs_alloc_write_mask(mapping);
+ u64 page_start = (u64)index << PAGE_SHIFT;
+ u64 page_end = page_start + PAGE_SIZE - 1;
+ struct extent_state *cached_state = NULL;
+ struct page *page;
+ int ret;
+
+again:
+ page = find_or_create_page(mapping, index, mask);
+ if (!page)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * Since we can defragment files opened read-only, we can encounter
+ * transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS). We
+ * can't do I/O using huge pages yet, so return an error for now.
+ * Filesystem transparent huge pages are typically only used for
+ * executables that explicitly enable them, so this isn't very
+ * restrictive.
+ */
+ if (PageCompound(page)) {
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(-ETXTBSY);
+ }
+
+ ret = set_page_extent_mapped(page);
+ if (ret < 0) {
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(ret);
+ }
+
+ /* Wait for any existing ordered extent in the range */
+ while (1) {
+ struct btrfs_ordered_extent *ordered;
+
+ lock_extent(&inode->io_tree, page_start, page_end, &cached_state);
+ ordered = btrfs_lookup_ordered_range(inode, page_start, PAGE_SIZE);
+ unlock_extent(&inode->io_tree, page_start, page_end,
+ &cached_state);
+ if (!ordered)
+ break;
+
+ unlock_page(page);
+ btrfs_start_ordered_extent(ordered, 1);
+ btrfs_put_ordered_extent(ordered);
+ lock_page(page);
+ /*
+ * We unlocked the page above, so we need check if it was
+ * released or not.
+ */
+ if (page->mapping != mapping || !PagePrivate(page)) {
+ unlock_page(page);
+ put_page(page);
+ goto again;
+ }
+ }
+
+ /*
+ * Now the page range has no ordered extent any more. Read the page to
+ * make it uptodate.
+ */
+ if (!PageUptodate(page)) {
+ btrfs_read_folio(NULL, page_folio(page));
+ lock_page(page);
+ if (page->mapping != mapping || !PagePrivate(page)) {
+ unlock_page(page);
+ put_page(page);
+ goto again;
+ }
+ if (!PageUptodate(page)) {
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(-EIO);
+ }
+ }
+ return page;
+}
+
+struct defrag_target_range {
+ struct list_head list;
+ u64 start;
+ u64 len;
+};
+
+/*
+ * Collect all valid target extents.
+ *
+ * @start: file offset to lookup
+ * @len: length to lookup
+ * @extent_thresh: file extent size threshold, any extent size >= this value
+ * will be ignored
+ * @newer_than: only defrag extents newer than this value
+ * @do_compress: whether the defrag is doing compression
+ * if true, @extent_thresh will be ignored and all regular
+ * file extents meeting @newer_than will be targets.
+ * @locked: if the range has already held extent lock
+ * @target_list: list of targets file extents
+ */
+static int defrag_collect_targets(struct btrfs_inode *inode,
+ u64 start, u64 len, u32 extent_thresh,
+ u64 newer_than, bool do_compress,
+ bool locked, struct list_head *target_list,
+ u64 *last_scanned_ret)
+{
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
+ bool last_is_target = false;
+ u64 cur = start;
+ int ret = 0;
+
+ while (cur < start + len) {
+ struct extent_map *em;
+ struct defrag_target_range *new;
+ bool next_mergeable = true;
+ u64 range_len;
+
+ last_is_target = false;
+ em = defrag_lookup_extent(&inode->vfs_inode, cur, newer_than, locked);
+ if (!em)
+ break;
+
+ /*
+ * If the file extent is an inlined one, we may still want to
+ * defrag it (fallthrough) if it will cause a regular extent.
+ * This is for users who want to convert inline extents to
+ * regular ones through max_inline= mount option.
+ */
+ if (em->block_start == EXTENT_MAP_INLINE &&
+ em->len <= inode->root->fs_info->max_inline)
+ goto next;
+
+ /* Skip hole/delalloc/preallocated extents */
+ if (em->block_start == EXTENT_MAP_HOLE ||
+ em->block_start == EXTENT_MAP_DELALLOC ||
+ test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+ goto next;
+
+ /* Skip older extent */
+ if (em->generation < newer_than)
+ goto next;
+
+ /* This em is under writeback, no need to defrag */
+ if (em->generation == (u64)-1)
+ goto next;
+
+ /*
+ * Our start offset might be in the middle of an existing extent
+ * map, so take that into account.
+ */
+ range_len = em->len - (cur - em->start);
+ /*
+ * If this range of the extent map is already flagged for delalloc,
+ * skip it, because:
+ *
+ * 1) We could deadlock later, when trying to reserve space for
+ * delalloc, because in case we can't immediately reserve space
+ * the flusher can start delalloc and wait for the respective
+ * ordered extents to complete. The deadlock would happen
+ * because we do the space reservation while holding the range
+ * locked, and starting writeback, or finishing an ordered
+ * extent, requires locking the range;
+ *
+ * 2) If there's delalloc there, it means there's dirty pages for
+ * which writeback has not started yet (we clean the delalloc
+ * flag when starting writeback and after creating an ordered
+ * extent). If we mark pages in an adjacent range for defrag,
+ * then we will have a larger contiguous range for delalloc,
+ * very likely resulting in a larger extent after writeback is
+ * triggered (except in a case of free space fragmentation).
+ */
+ if (test_range_bit(&inode->io_tree, cur, cur + range_len - 1,
+ EXTENT_DELALLOC, 0, NULL))
+ goto next;
+
+ /*
+ * For do_compress case, we want to compress all valid file
+ * extents, thus no @extent_thresh or mergeable check.
+ */
+ if (do_compress)
+ goto add;
+
+ /* Skip too large extent */
+ if (range_len >= extent_thresh)
+ goto next;
+
+ /*
+ * Skip extents already at its max capacity, this is mostly for
+ * compressed extents, which max cap is only 128K.
+ */
+ if (em->len >= get_extent_max_capacity(fs_info, em))
+ goto next;
+
+ /*
+ * Normally there are no more extents after an inline one, thus
+ * @next_mergeable will normally be false and not defragged.
+ * So if an inline extent passed all above checks, just add it
+ * for defrag, and be converted to regular extents.
+ */
+ if (em->block_start == EXTENT_MAP_INLINE)
+ goto add;
+
+ next_mergeable = defrag_check_next_extent(&inode->vfs_inode, em,
+ extent_thresh, newer_than, locked);
+ if (!next_mergeable) {
+ struct defrag_target_range *last;
+
+ /* Empty target list, no way to merge with last entry */
+ if (list_empty(target_list))
+ goto next;
+ last = list_entry(target_list->prev,
+ struct defrag_target_range, list);
+ /* Not mergeable with last entry */
+ if (last->start + last->len != cur)
+ goto next;
+
+ /* Mergeable, fall through to add it to @target_list. */
+ }
+
+add:
+ last_is_target = true;
+ range_len = min(extent_map_end(em), start + len) - cur;
+ /*
+ * This one is a good target, check if it can be merged into
+ * last range of the target list.
+ */
+ if (!list_empty(target_list)) {
+ struct defrag_target_range *last;
+
+ last = list_entry(target_list->prev,
+ struct defrag_target_range, list);
+ ASSERT(last->start + last->len <= cur);
+ if (last->start + last->len == cur) {
+ /* Mergeable, enlarge the last entry */
+ last->len += range_len;
+ goto next;
+ }
+ /* Fall through to allocate a new entry */
+ }
+
+ /* Allocate new defrag_target_range */
+ new = kmalloc(sizeof(*new), GFP_NOFS);
+ if (!new) {
+ free_extent_map(em);
+ ret = -ENOMEM;
+ break;
+ }
+ new->start = cur;
+ new->len = range_len;
+ list_add_tail(&new->list, target_list);
+
+next:
+ cur = extent_map_end(em);
+ free_extent_map(em);
+ }
+ if (ret < 0) {
+ struct defrag_target_range *entry;
+ struct defrag_target_range *tmp;
+
+ list_for_each_entry_safe(entry, tmp, target_list, list) {
+ list_del_init(&entry->list);
+ kfree(entry);
+ }
+ }
+ if (!ret && last_scanned_ret) {
+ /*
+ * If the last extent is not a target, the caller can skip to
+ * the end of that extent.
+ * Otherwise, we can only go the end of the specified range.
+ */
+ if (!last_is_target)
+ *last_scanned_ret = max(cur, *last_scanned_ret);
+ else
+ *last_scanned_ret = max(start + len, *last_scanned_ret);
+ }
+ return ret;
+}
+
+#define CLUSTER_SIZE (SZ_256K)
+static_assert(IS_ALIGNED(CLUSTER_SIZE, PAGE_SIZE));
+
+/*
+ * Defrag one contiguous target range.
+ *
+ * @inode: target inode
+ * @target: target range to defrag
+ * @pages: locked pages covering the defrag range
+ * @nr_pages: number of locked pages
+ *
+ * Caller should ensure:
+ *
+ * - Pages are prepared
+ * Pages should be locked, no ordered extent in the pages range,
+ * no writeback.
+ *
+ * - Extent bits are locked
+ */
+static int defrag_one_locked_target(struct btrfs_inode *inode,
+ struct defrag_target_range *target,
+ struct page **pages, int nr_pages,
+ struct extent_state **cached_state)
+{
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
+ struct extent_changeset *data_reserved = NULL;
+ const u64 start = target->start;
+ const u64 len = target->len;
+ unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
+ unsigned long start_index = start >> PAGE_SHIFT;
+ unsigned long first_index = page_index(pages[0]);
+ int ret = 0;
+ int i;
+
+ ASSERT(last_index - first_index + 1 <= nr_pages);
+
+ ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len);
+ if (ret < 0)
+ return ret;
+ clear_extent_bit(&inode->io_tree, start, start + len - 1,
+ EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
+ EXTENT_DEFRAG, cached_state);
+ set_extent_defrag(&inode->io_tree, start, start + len - 1, cached_state);
+
+ /* Update the page status */
+ for (i = start_index - first_index; i <= last_index - first_index; i++) {
+ ClearPageChecked(pages[i]);
+ btrfs_page_clamp_set_dirty(fs_info, pages[i], start, len);
+ }
+ btrfs_delalloc_release_extents(inode, len);
+ extent_changeset_free(data_reserved);
+
+ return ret;
+}
+
+static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
+ u32 extent_thresh, u64 newer_than, bool do_compress,
+ u64 *last_scanned_ret)
+{
+ struct extent_state *cached_state = NULL;
+ struct defrag_target_range *entry;
+ struct defrag_target_range *tmp;
+ LIST_HEAD(target_list);
+ struct page **pages;
+ const u32 sectorsize = inode->root->fs_info->sectorsize;
+ u64 last_index = (start + len - 1) >> PAGE_SHIFT;
+ u64 start_index = start >> PAGE_SHIFT;
+ unsigned int nr_pages = last_index - start_index + 1;
+ int ret = 0;
+ int i;
+
+ ASSERT(nr_pages <= CLUSTER_SIZE / PAGE_SIZE);
+ ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(len, sectorsize));
+
+ pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
+ if (!pages)
+ return -ENOMEM;
+
+ /* Prepare all pages */
+ for (i = 0; i < nr_pages; i++) {
+ pages[i] = defrag_prepare_one_page(inode, start_index + i);
+ if (IS_ERR(pages[i])) {
+ ret = PTR_ERR(pages[i]);
+ pages[i] = NULL;
+ goto free_pages;
+ }
+ }
+ for (i = 0; i < nr_pages; i++)
+ wait_on_page_writeback(pages[i]);
+
+ /* Lock the pages range */
+ lock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
+ (last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
+ &cached_state);
+ /*
+ * Now we have a consistent view about the extent map, re-check
+ * which range really needs to be defragged.
+ *
+ * And this time we have extent locked already, pass @locked = true
+ * so that we won't relock the extent range and cause deadlock.
+ */
+ ret = defrag_collect_targets(inode, start, len, extent_thresh,
+ newer_than, do_compress, true,
+ &target_list, last_scanned_ret);
+ if (ret < 0)
+ goto unlock_extent;
+
+ list_for_each_entry(entry, &target_list, list) {
+ ret = defrag_one_locked_target(inode, entry, pages, nr_pages,
+ &cached_state);
+ if (ret < 0)
+ break;
+ }
+
+ list_for_each_entry_safe(entry, tmp, &target_list, list) {
+ list_del_init(&entry->list);
+ kfree(entry);
+ }
+unlock_extent:
+ unlock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
+ (last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
+ &cached_state);
+free_pages:
+ for (i = 0; i < nr_pages; i++) {
+ if (pages[i]) {
+ unlock_page(pages[i]);
+ put_page(pages[i]);
+ }
+ }
+ kfree(pages);
+ return ret;
+}
+
+static int defrag_one_cluster(struct btrfs_inode *inode,
+ struct file_ra_state *ra,
+ u64 start, u32 len, u32 extent_thresh,
+ u64 newer_than, bool do_compress,
+ unsigned long *sectors_defragged,
+ unsigned long max_sectors,
+ u64 *last_scanned_ret)
+{
+ const u32 sectorsize = inode->root->fs_info->sectorsize;
+ struct defrag_target_range *entry;
+ struct defrag_target_range *tmp;
+ LIST_HEAD(target_list);
+ int ret;
+
+ ret = defrag_collect_targets(inode, start, len, extent_thresh,
+ newer_than, do_compress, false,
+ &target_list, NULL);
+ if (ret < 0)
+ goto out;
+
+ list_for_each_entry(entry, &target_list, list) {
+ u32 range_len = entry->len;
+
+ /* Reached or beyond the limit */
+ if (max_sectors && *sectors_defragged >= max_sectors) {
+ ret = 1;
+ break;
+ }
+
+ if (max_sectors)
+ range_len = min_t(u32, range_len,
+ (max_sectors - *sectors_defragged) * sectorsize);
+
+ /*
+ * If defrag_one_range() has updated last_scanned_ret,
+ * our range may already be invalid (e.g. hole punched).
+ * Skip if our range is before last_scanned_ret, as there is
+ * no need to defrag the range anymore.
+ */
+ if (entry->start + range_len <= *last_scanned_ret)
+ continue;
+
+ if (ra)
+ page_cache_sync_readahead(inode->vfs_inode.i_mapping,
+ ra, NULL, entry->start >> PAGE_SHIFT,
+ ((entry->start + range_len - 1) >> PAGE_SHIFT) -
+ (entry->start >> PAGE_SHIFT) + 1);
+ /*
+ * Here we may not defrag any range if holes are punched before
+ * we locked the pages.
+ * But that's fine, it only affects the @sectors_defragged
+ * accounting.
+ */
+ ret = defrag_one_range(inode, entry->start, range_len,
+ extent_thresh, newer_than, do_compress,
+ last_scanned_ret);
+ if (ret < 0)
+ break;
+ *sectors_defragged += range_len >>
+ inode->root->fs_info->sectorsize_bits;
+ }
+out:
+ list_for_each_entry_safe(entry, tmp, &target_list, list) {
+ list_del_init(&entry->list);
+ kfree(entry);
+ }
+ if (ret >= 0)
+ *last_scanned_ret = max(*last_scanned_ret, start + len);
+ return ret;
+}
+
+/*
+ * Entry point to file defragmentation.
+ *
+ * @inode: inode to be defragged
+ * @ra: readahead state (can be NUL)
+ * @range: defrag options including range and flags
+ * @newer_than: minimum transid to defrag
+ * @max_to_defrag: max number of sectors to be defragged, if 0, the whole inode
+ * will be defragged.
+ *
+ * Return <0 for error.
+ * Return >=0 for the number of sectors defragged, and range->start will be updated
+ * to indicate the file offset where next defrag should be started at.
+ * (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
+ * defragging all the range).
+ */
+int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
+ struct btrfs_ioctl_defrag_range_args *range,
+ u64 newer_than, unsigned long max_to_defrag)
+{
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ unsigned long sectors_defragged = 0;
+ u64 isize = i_size_read(inode);
+ u64 cur;
+ u64 last_byte;
+ bool do_compress = (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS);
+ bool ra_allocated = false;
+ int compress_type = BTRFS_COMPRESS_ZLIB;
+ int ret = 0;
+ u32 extent_thresh = range->extent_thresh;
+ pgoff_t start_index;
+
+ if (isize == 0)
+ return 0;
+
+ if (range->start >= isize)
+ return -EINVAL;
+
+ if (do_compress) {
+ if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES)
+ return -EINVAL;
+ if (range->compress_type)
+ compress_type = range->compress_type;
+ }
+
+ if (extent_thresh == 0)
+ extent_thresh = SZ_256K;
+
+ if (range->start + range->len > range->start) {
+ /* Got a specific range */
+ last_byte = min(isize, range->start + range->len);
+ } else {
+ /* Defrag until file end */
+ last_byte = isize;
+ }
+
+ /* Align the range */
+ cur = round_down(range->start, fs_info->sectorsize);
+ last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
+
+ /*
+ * If we were not given a ra, allocate a readahead context. As
+ * readahead is just an optimization, defrag will work without it so
+ * we don't error out.
+ */
+ if (!ra) {
+ ra_allocated = true;
+ ra = kzalloc(sizeof(*ra), GFP_KERNEL);
+ if (ra)
+ file_ra_state_init(ra, inode->i_mapping);
+ }
+
+ /*
+ * Make writeback start from the beginning of the range, so that the
+ * defrag range can be written sequentially.
+ */
+ start_index = cur >> PAGE_SHIFT;
+ if (start_index < inode->i_mapping->writeback_index)
+ inode->i_mapping->writeback_index = start_index;
+
+ while (cur < last_byte) {
+ const unsigned long prev_sectors_defragged = sectors_defragged;
+ u64 last_scanned = cur;
+ u64 cluster_end;
+
+ if (btrfs_defrag_cancelled(fs_info)) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ /* We want the cluster end at page boundary when possible */
+ cluster_end = (((cur >> PAGE_SHIFT) +
+ (SZ_256K >> PAGE_SHIFT)) << PAGE_SHIFT) - 1;
+ cluster_end = min(cluster_end, last_byte);
+
+ btrfs_inode_lock(BTRFS_I(inode), 0);
+ if (IS_SWAPFILE(inode)) {
+ ret = -ETXTBSY;
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
+ break;
+ }
+ if (!(inode->i_sb->s_flags & SB_ACTIVE)) {
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
+ break;
+ }
+ if (do_compress)
+ BTRFS_I(inode)->defrag_compress = compress_type;
+ ret = defrag_one_cluster(BTRFS_I(inode), ra, cur,
+ cluster_end + 1 - cur, extent_thresh,
+ newer_than, do_compress, &sectors_defragged,
+ max_to_defrag, &last_scanned);
+
+ if (sectors_defragged > prev_sectors_defragged)
+ balance_dirty_pages_ratelimited(inode->i_mapping);
+
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
+ if (ret < 0)
+ break;
+ cur = max(cluster_end + 1, last_scanned);
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ cond_resched();
+ }
+
+ if (ra_allocated)
+ kfree(ra);
+ /*
+ * Update range.start for autodefrag, this will indicate where to start
+ * in next run.
+ */
+ range->start = cur;
+ if (sectors_defragged) {
+ /*
+ * We have defragged some sectors, for compression case they
+ * need to be written back immediately.
+ */
+ if (range->flags & BTRFS_DEFRAG_RANGE_START_IO) {
+ filemap_flush(inode->i_mapping);
+ if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+ &BTRFS_I(inode)->runtime_flags))
+ filemap_flush(inode->i_mapping);
+ }
+ if (range->compress_type == BTRFS_COMPRESS_LZO)
+ btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
+ else if (range->compress_type == BTRFS_COMPRESS_ZSTD)
+ btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
+ ret = sectors_defragged;
+ }
+ if (do_compress) {
+ btrfs_inode_lock(BTRFS_I(inode), 0);
+ BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE;
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
+ }
+ return ret;
+}
+
+void __cold btrfs_auto_defrag_exit(void)
+{
+ kmem_cache_destroy(btrfs_inode_defrag_cachep);
+}
+
+int __init btrfs_auto_defrag_init(void)
+{
+ btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
+ sizeof(struct inode_defrag), 0,
+ SLAB_MEM_SPREAD,
+ NULL);
+ if (!btrfs_inode_defrag_cachep)
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/fs/btrfs/defrag.h b/fs/btrfs/defrag.h
new file mode 100644
index 000000000000..5305f2283b5e
--- /dev/null
+++ b/fs/btrfs/defrag.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_DEFRAG_H
+#define BTRFS_DEFRAG_H
+
+int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
+ struct btrfs_ioctl_defrag_range_args *range,
+ u64 newer_than, unsigned long max_to_defrag);
+int __init btrfs_auto_defrag_init(void);
+void __cold btrfs_auto_defrag_exit(void);
+int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *inode, u32 extent_thresh);
+int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
+void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
+int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, struct btrfs_root *root);
+
+static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
+{
+ return signal_pending(current);
+}
+
+#endif
diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c
index 118b2e20b2e1..7ddb1d104e8e 100644
--- a/fs/btrfs/delalloc-space.c
+++ b/fs/btrfs/delalloc-space.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include "messages.h"
#include "ctree.h"
#include "delalloc-space.h"
#include "block-rsv.h"
@@ -8,6 +9,7 @@
#include "transaction.h"
#include "qgroup.h"
#include "block-group.h"
+#include "fs.h"
/*
* HOW DOES THIS WORK
@@ -200,8 +202,8 @@ void btrfs_free_reserved_data_space(struct btrfs_inode *inode,
btrfs_qgroup_free_data(inode, reserved, start, len);
}
-/**
- * Release any excessive reservation
+/*
+ * Release any excessive reservations for an inode.
*
* @inode: the inode we need to release from
* @qgroup_free: free or convert qgroup meta. Unlike normal operation, qgroup
@@ -375,12 +377,12 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
return 0;
}
-/**
- * Release a metadata reservation for an inode
+/*
+ * Release a metadata reservation for an inode.
*
- * @inode: the inode to release the reservation for.
- * @num_bytes: the number of bytes we are releasing.
- * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
+ * @inode: the inode to release the reservation for.
+ * @num_bytes: the number of bytes we are releasing.
+ * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
*
* This will release the metadata reservation for an inode. This can be called
* once we complete IO for a given set of bytes to release their metadata
@@ -403,10 +405,11 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
btrfs_inode_rsv_release(inode, qgroup_free);
}
-/**
- * btrfs_delalloc_release_extents - release our outstanding_extents
- * @inode: the inode to balance the reservation for.
- * @num_bytes: the number of bytes we originally reserved with
+/*
+ * Release our outstanding_extents for an inode.
+ *
+ * @inode: the inode to balance the reservation for.
+ * @num_bytes: the number of bytes we originally reserved with
*
* When we reserve space we increase outstanding_extents for the extents we may
* add. Once we've set the range as delalloc or created our ordered extents we
@@ -431,30 +434,30 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
btrfs_inode_rsv_release(inode, true);
}
-/**
- * btrfs_delalloc_reserve_space - reserve data and metadata space for
- * delalloc
- * @inode: inode we're writing to
- * @start: start range we are writing to
- * @len: how long the range we are writing to
- * @reserved: mandatory parameter, record actually reserved qgroup ranges of
- * current reservation.
+/*
+ * Reserve data and metadata space for delalloc
+ *
+ * @inode: inode we're writing to
+ * @start: start range we are writing to
+ * @len: how long the range we are writing to
+ * @reserved: mandatory parameter, record actually reserved qgroup ranges of
+ * current reservation.
*
* This will do the following things
*
- * - reserve space in data space info for num bytes
- * and reserve precious corresponding qgroup space
+ * - reserve space in data space info for num bytes and reserve precious
+ * corresponding qgroup space
* (Done in check_data_free_space)
*
* - reserve space for metadata space, based on the number of outstanding
- * extents and how much csums will be needed
- * also reserve metadata space in a per root over-reserve method.
+ * extents and how much csums will be needed also reserve metadata space in a
+ * per root over-reserve method.
* - add to the inodes->delalloc_bytes
* - add it to the fs_info's delalloc inodes list.
* (Above 3 all done in delalloc_reserve_metadata)
*
* Return 0 for success
- * Return <0 for error(-ENOSPC or -EQUOT)
+ * Return <0 for error(-ENOSPC or -EDQUOT)
*/
int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
struct extent_changeset **reserved, u64 start, u64 len)
@@ -473,7 +476,7 @@ int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
return ret;
}
-/**
+/*
* Release data and metadata space for delalloc
*
* @inode: inode we're releasing space for
@@ -482,10 +485,10 @@ int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
* @len: length of the space already reserved
* @qgroup_free: should qgroup reserved-space also be freed
*
- * This function will release the metadata space that was not used and will
- * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
- * list if there are no delalloc bytes left.
- * Also it will handle the qgroup reserved space.
+ * Release the metadata space that was not used and will decrement
+ * ->delalloc_bytes and remove it from the fs_info->delalloc_inodes list if
+ * there are no delalloc bytes left. Also it will handle the qgroup reserved
+ * space.
*/
void btrfs_delalloc_release_space(struct btrfs_inode *inode,
struct extent_changeset *reserved,
diff --git a/fs/btrfs/delalloc-space.h b/fs/btrfs/delalloc-space.h
index e07d46043455..c5d573f2366e 100644
--- a/fs/btrfs/delalloc-space.h
+++ b/fs/btrfs/delalloc-space.h
@@ -20,5 +20,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
bool qgroup_free);
int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
struct extent_changeset **reserved, u64 start, u64 len);
+int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
+ u64 disk_num_bytes, bool noflush);
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
#endif /* BTRFS_DELALLOC_SPACE_H */
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index cac5169eaf8d..0095c6e4c3d1 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -6,14 +6,19 @@
#include <linux/slab.h>
#include <linux/iversion.h>
+#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
#include "misc.h"
#include "delayed-inode.h"
#include "disk-io.h"
#include "transaction.h"
-#include "ctree.h"
#include "qgroup.h"
#include "locking.h"
#include "inode-item.h"
+#include "space-info.h"
+#include "accessors.h"
+#include "file-item.h"
#define BTRFS_DELAYED_WRITEBACK 512
#define BTRFS_DELAYED_BACKGROUND 128
@@ -1412,7 +1417,7 @@ void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info)
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
const char *name, int name_len,
struct btrfs_inode *dir,
- struct btrfs_disk_key *disk_key, u8 type,
+ struct btrfs_disk_key *disk_key, u8 flags,
u64 index)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -1443,7 +1448,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
btrfs_set_stack_dir_transid(dir_item, trans->transid);
btrfs_set_stack_dir_data_len(dir_item, 0);
btrfs_set_stack_dir_name_len(dir_item, name_len);
- btrfs_set_stack_dir_type(dir_item, type);
+ btrfs_set_stack_dir_flags(dir_item, flags);
memcpy((char *)(dir_item + 1), name, name_len);
data_len = delayed_item->data_len + sizeof(struct btrfs_item);
@@ -1641,8 +1646,8 @@ bool btrfs_readdir_get_delayed_items(struct inode *inode,
* We can only do one readdir with delayed items at a time because of
* item->readdir_list.
*/
- btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
- btrfs_inode_lock(inode, 0);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
+ btrfs_inode_lock(BTRFS_I(inode), 0);
mutex_lock(&delayed_node->mutex);
item = __btrfs_first_delayed_insertion_item(delayed_node);
@@ -1753,7 +1758,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
name = (char *)(di + 1);
name_len = btrfs_stack_dir_name_len(di);
- d_type = fs_ftype_to_dtype(di->type);
+ d_type = fs_ftype_to_dtype(btrfs_dir_flags_to_ftype(di->type));
btrfs_disk_key_to_cpu(&location, &di->location);
over = !dir_emit(ctx, name, name_len,
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
index 0163ca637a96..4f21daa3dbc7 100644
--- a/fs/btrfs/delayed-inode.h
+++ b/fs/btrfs/delayed-inode.h
@@ -113,7 +113,7 @@ static inline void btrfs_init_delayed_root(
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
const char *name, int name_len,
struct btrfs_inode *dir,
- struct btrfs_disk_key *disk_key, u8 type,
+ struct btrfs_disk_key *disk_key, u8 flags,
u64 index);
int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 36a3debe9493..573ebab886e2 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -6,12 +6,14 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/sort.h>
+#include "messages.h"
#include "ctree.h"
#include "delayed-ref.h"
#include "transaction.h"
#include "qgroup.h"
#include "space-info.h"
#include "tree-mod-log.h"
+#include "fs.h"
struct kmem_cache *btrfs_delayed_ref_head_cachep;
struct kmem_cache *btrfs_delayed_tree_ref_cachep;
@@ -69,14 +71,14 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans)
return btrfs_check_space_for_delayed_refs(trans->fs_info);
}
-/**
- * Release a ref head's reservation
+/*
+ * Release a ref head's reservation.
*
* @fs_info: the filesystem
* @nr: number of items to drop
*
- * This drops the delayed ref head's count from the delayed refs rsv and frees
- * any excess reservation we had.
+ * Drops the delayed ref head's count from the delayed refs rsv and free any
+ * excess reservation we had.
*/
void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
{
@@ -102,8 +104,7 @@ void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
}
/*
- * btrfs_update_delayed_refs_rsv - adjust the size of the delayed refs rsv
- * @trans - the trans that may have generated delayed refs
+ * Adjust the size of the delayed refs rsv.
*
* This is to be called anytime we may have adjusted trans->delayed_ref_updates,
* it'll calculate the additional size and add it to the delayed_refs_rsv.
@@ -137,8 +138,8 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
trans->delayed_ref_updates = 0;
}
-/**
- * Transfer bytes to our delayed refs rsv
+/*
+ * Transfer bytes to our delayed refs rsv.
*
* @fs_info: the filesystem
* @src: source block rsv to transfer from
@@ -186,8 +187,8 @@ void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
delayed_refs_rsv->space_info, to_free);
}
-/**
- * Refill based on our delayed refs usage
+/*
+ * Refill based on our delayed refs usage.
*
* @fs_info: the filesystem
* @flush: control how we can flush for this reservation.
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 61e58066b5fd..78696d331639 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -18,11 +18,13 @@
#include "volumes.h"
#include "async-thread.h"
#include "check-integrity.h"
-#include "rcu-string.h"
#include "dev-replace.h"
#include "sysfs.h"
#include "zoned.h"
#include "block-group.h"
+#include "fs.h"
+#include "accessors.h"
+#include "scrub.h"
/*
* Device replace overview
@@ -246,7 +248,6 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
struct btrfs_device *device;
struct block_device *bdev;
- struct rcu_string *name;
u64 devid = BTRFS_DEV_REPLACE_DEVID;
int ret = 0;
@@ -290,19 +291,12 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
}
- device = btrfs_alloc_device(NULL, &devid, NULL);
+ device = btrfs_alloc_device(NULL, &devid, NULL, device_path);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
goto error;
}
- name = rcu_string_strdup(device_path, GFP_KERNEL);
- if (!name) {
- btrfs_free_device(device);
- ret = -ENOMEM;
- goto error;
- }
- rcu_assign_pointer(device->name, name);
ret = lookup_bdev(device_path, &device->devt);
if (ret)
goto error;
@@ -456,14 +450,6 @@ out:
return ret;
}
-static char* btrfs_dev_name(struct btrfs_device *device)
-{
- if (!device || test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
- return "<missing disk>";
- else
- return rcu_str_deref(device->name);
-}
-
static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info,
struct btrfs_device *src_dev)
{
@@ -679,7 +665,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
"dev_replace from %s (devid %llu) to %s started",
btrfs_dev_name(src_device),
src_device->devid,
- rcu_str_deref(tgt_device->name));
+ btrfs_dev_name(tgt_device));
/*
* from now on, the writes to the srcdev are all duplicated to
@@ -938,7 +924,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
"btrfs_scrub_dev(%s, %llu, %s) failed %d",
btrfs_dev_name(src_device),
src_device->devid,
- rcu_str_deref(tgt_device->name), scrub_ret);
+ btrfs_dev_name(tgt_device), scrub_ret);
error:
up_write(&dev_replace->rwsem);
mutex_unlock(&fs_info->chunk_mutex);
@@ -956,7 +942,7 @@ error:
"dev_replace from %s (devid %llu) to %s finished",
btrfs_dev_name(src_device),
src_device->devid,
- rcu_str_deref(tgt_device->name));
+ btrfs_dev_name(tgt_device));
clear_bit(BTRFS_DEV_STATE_REPLACE_TGT, &tgt_device->dev_state);
tgt_device->devid = src_device->devid;
src_device->devid = BTRFS_DEV_REPLACE_DEVID;
diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h
index 6084b313056a..675082ccec89 100644
--- a/fs/btrfs/dev-replace.h
+++ b/fs/btrfs/dev-replace.h
@@ -25,5 +25,13 @@ int __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
bool btrfs_finish_block_group_to_copy(struct btrfs_device *srcdev,
struct btrfs_block_group *cache,
u64 physical);
+void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info);
+void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount);
+
+static inline void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info)
+{
+ btrfs_bio_counter_sub(fs_info, 1);
+}
+
#endif
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index 72fb2c518a2b..082eb0e19598 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -3,9 +3,12 @@
* Copyright (C) 2007 Oracle. All rights reserved.
*/
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
+#include "accessors.h"
+#include "dir-item.h"
/*
* insert a name into a directory, doing overflow properly if there is a hash
@@ -81,7 +84,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
btrfs_cpu_key_to_disk(&disk_key, &location);
btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
- btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
+ btrfs_set_dir_flags(leaf, dir_item, BTRFS_FT_XATTR);
btrfs_set_dir_name_len(leaf, dir_item, name_len);
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
btrfs_set_dir_data_len(leaf, dir_item, data_len);
@@ -103,8 +106,8 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
* to use for the second index (if one is created).
* Will return 0 or -ENOMEM
*/
-int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
- int name_len, struct btrfs_inode *dir,
+int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
+ const struct fscrypt_str *name, struct btrfs_inode *dir,
struct btrfs_key *location, u8 type, u64 index)
{
int ret = 0;
@@ -120,7 +123,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
key.objectid = btrfs_ino(dir);
key.type = BTRFS_DIR_ITEM_KEY;
- key.offset = btrfs_name_hash(name, name_len);
+ key.offset = btrfs_name_hash(name->name, name->len);
path = btrfs_alloc_path();
if (!path)
@@ -128,9 +131,9 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
btrfs_cpu_key_to_disk(&disk_key, location);
- data_size = sizeof(*dir_item) + name_len;
+ data_size = sizeof(*dir_item) + name->len;
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
- name, name_len);
+ name->name, name->len);
if (IS_ERR(dir_item)) {
ret = PTR_ERR(dir_item);
if (ret == -EEXIST)
@@ -138,15 +141,18 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
goto out_free;
}
+ if (IS_ENCRYPTED(&dir->vfs_inode))
+ type |= BTRFS_FT_ENCRYPTED;
+
leaf = path->nodes[0];
btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
- btrfs_set_dir_type(leaf, dir_item, type);
+ btrfs_set_dir_flags(leaf, dir_item, type);
btrfs_set_dir_data_len(leaf, dir_item, 0);
- btrfs_set_dir_name_len(leaf, dir_item, name_len);
+ btrfs_set_dir_name_len(leaf, dir_item, name->len);
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
name_ptr = (unsigned long)(dir_item + 1);
- write_extent_buffer(leaf, name, name_ptr, name_len);
+ write_extent_buffer(leaf, name->name, name_ptr, name->len);
btrfs_mark_buffer_dirty(leaf);
second_insert:
@@ -157,7 +163,7 @@ second_insert:
}
btrfs_release_path(path);
- ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir,
+ ret2 = btrfs_insert_delayed_dir_index(trans, name->name, name->len, dir,
&disk_key, type, index);
out_free:
btrfs_free_path(path);
@@ -206,7 +212,7 @@ static struct btrfs_dir_item *btrfs_lookup_match_dir(
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 dir,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
int mod)
{
struct btrfs_key key;
@@ -214,9 +220,10 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
key.objectid = dir;
key.type = BTRFS_DIR_ITEM_KEY;
- key.offset = btrfs_name_hash(name, name_len);
+ key.offset = btrfs_name_hash(name->name, name->len);
- di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
+ di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
+ name->len, mod);
if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
return NULL;
@@ -224,7 +231,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
}
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
- const char *name, int name_len)
+ const struct fscrypt_str *name)
{
int ret;
struct btrfs_key key;
@@ -240,9 +247,10 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
key.objectid = dir;
key.type = BTRFS_DIR_ITEM_KEY;
- key.offset = btrfs_name_hash(name, name_len);
+ key.offset = btrfs_name_hash(name->name, name->len);
- di = btrfs_lookup_match_dir(NULL, root, path, &key, name, name_len, 0);
+ di = btrfs_lookup_match_dir(NULL, root, path, &key, name->name,
+ name->len, 0);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
/* Nothing found, we're safe */
@@ -262,11 +270,8 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
goto out;
}
- /*
- * see if there is room in the item to insert this
- * name
- */
- data_size = sizeof(*di) + name_len;
+ /* See if there is room in the item to insert this name. */
+ data_size = sizeof(*di) + name->len;
leaf = path->nodes[0];
slot = path->slots[0];
if (data_size + btrfs_item_size(leaf, slot) +
@@ -303,8 +308,7 @@ struct btrfs_dir_item *
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 dir,
- u64 index, const char *name, int name_len,
- int mod)
+ u64 index, const struct fscrypt_str *name, int mod)
{
struct btrfs_dir_item *di;
struct btrfs_key key;
@@ -313,7 +317,8 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = index;
- di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
+ di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
+ name->len, mod);
if (di == ERR_PTR(-ENOENT))
return NULL;
@@ -321,9 +326,8 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
}
struct btrfs_dir_item *
-btrfs_search_dir_index_item(struct btrfs_root *root,
- struct btrfs_path *path, u64 dirid,
- const char *name, int name_len)
+btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path,
+ u64 dirid, const struct fscrypt_str *name)
{
struct btrfs_dir_item *di;
struct btrfs_key key;
@@ -338,7 +342,7 @@ btrfs_search_dir_index_item(struct btrfs_root *root,
break;
di = btrfs_match_dir_item_name(root->fs_info, path,
- name, name_len);
+ name->name, name->len);
if (di)
return di;
}
diff --git a/fs/btrfs/dir-item.h b/fs/btrfs/dir-item.h
new file mode 100644
index 000000000000..aab4b7cc7fa0
--- /dev/null
+++ b/fs/btrfs/dir-item.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_DIR_ITEM_H
+#define BTRFS_DIR_ITEM_H
+
+int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
+ const struct fscrypt_str *name);
+int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
+ const struct fscrypt_str *name, struct btrfs_inode *dir,
+ struct btrfs_key *location, u8 type, u64 index);
+struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ const struct fscrypt_str *name, int mod);
+struct btrfs_dir_item *btrfs_lookup_dir_index_item(
+ struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ u64 index, const struct fscrypt_str *name, int mod);
+struct btrfs_dir_item *btrfs_search_dir_index_item(struct btrfs_root *root,
+ struct btrfs_path *path, u64 dirid,
+ const struct fscrypt_str *name);
+int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct btrfs_dir_item *di);
+int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 objectid,
+ const char *name, u16 name_len,
+ const void *data, u16 data_len);
+struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ const char *name, u16 name_len,
+ int mod);
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
+ struct btrfs_path *path,
+ const char *name,
+ int name_len);
+
+#endif
diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c
index e1b7bd927d69..ff2e524d9937 100644
--- a/fs/btrfs/discard.c
+++ b/fs/btrfs/discard.c
@@ -11,6 +11,7 @@
#include "block-group.h"
#include "discard.h"
#include "free-space-cache.h"
+#include "fs.h"
/*
* This contains the logic to handle async discard.
@@ -61,7 +62,7 @@
#define BTRFS_DISCARD_MAX_DELAY_MSEC (1000UL)
#define BTRFS_DISCARD_MAX_IOPS (10U)
-/* Montonically decreasing minimum length filters after index 0 */
+/* Monotonically decreasing minimum length filters after index 0 */
static int discard_minlen[BTRFS_NR_DISCARD_LISTS] = {
0,
BTRFS_ASYNC_DISCARD_MAX_FILTER,
@@ -146,10 +147,11 @@ static bool remove_from_discard_list(struct btrfs_discard_ctl *discard_ctl,
return running;
}
-/**
- * find_next_block_group - find block_group that's up next for discarding
- * @discard_ctl: discard control
- * @now: current time
+/*
+ * Find block_group that's up next for discarding.
+ *
+ * @discard_ctl: discard control
+ * @now: current time
*
* Iterate over the discard lists to find the next block_group up for
* discarding checking the discard_eligible_time of block_group.
@@ -184,17 +186,17 @@ static struct btrfs_block_group *find_next_block_group(
return ret_block_group;
}
-/**
- * Wrap find_next_block_group()
+/*
+ * Look up next block group and set it for use.
*
* @discard_ctl: discard control
* @discard_state: the discard_state of the block_group after state management
* @discard_index: the discard_index of the block_group after state management
* @now: time when discard was invoked, in ns
*
- * This wraps find_next_block_group() and sets the block_group to be in use.
- * discard_state's control flow is managed here. Variables related to
- * discard_state are reset here as needed (eg discard_cursor). @discard_state
+ * Wrap find_next_block_group() and set the block_group to be in use.
+ * @discard_state's control flow is managed here. Variables related to
+ * @discard_state are reset here as needed (eg. @discard_cursor). @discard_state
* and @discard_index are remembered as it may change while we're discarding,
* but we want the discard to execute in the context determined here.
*/
@@ -233,10 +235,11 @@ again:
return block_group;
}
-/**
- * btrfs_discard_check_filter - updates a block groups filters
- * @block_group: block group of interest
- * @bytes: recently freed region size after coalescing
+/*
+ * Update a block group's filters.
+ *
+ * @block_group: block group of interest
+ * @bytes: recently freed region size after coalescing
*
* Async discard maintains multiple lists with progressively smaller filters
* to prioritize discarding based on size. Should a free space that matches
@@ -271,8 +274,9 @@ void btrfs_discard_check_filter(struct btrfs_block_group *block_group,
}
}
-/**
- * btrfs_update_discard_index - moves a block group along the discard lists
+/*
+ * Move a block group along the discard lists.
+ *
* @discard_ctl: discard control
* @block_group: block_group of interest
*
@@ -291,13 +295,14 @@ static void btrfs_update_discard_index(struct btrfs_discard_ctl *discard_ctl,
add_to_discard_list(discard_ctl, block_group);
}
-/**
- * btrfs_discard_cancel_work - remove a block_group from the discard lists
+/*
+ * Remove a block_group from the discard lists.
+ *
* @discard_ctl: discard control
* @block_group: block_group of interest
*
- * This removes @block_group from the discard lists. If necessary, it waits on
- * the current work and then reschedules the delayed work.
+ * Remove @block_group from the discard lists. If necessary, wait on the
+ * current work and then reschedule the delayed work.
*/
void btrfs_discard_cancel_work(struct btrfs_discard_ctl *discard_ctl,
struct btrfs_block_group *block_group)
@@ -308,12 +313,13 @@ void btrfs_discard_cancel_work(struct btrfs_discard_ctl *discard_ctl,
}
}
-/**
- * btrfs_discard_queue_work - handles queuing the block_groups
+/*
+ * Handles queuing the block_groups.
+ *
* @discard_ctl: discard control
* @block_group: block_group of interest
*
- * This maintains the LRU order of the discard lists.
+ * Maintain the LRU order of the discard lists.
*/
void btrfs_discard_queue_work(struct btrfs_discard_ctl *discard_ctl,
struct btrfs_block_group *block_group)
@@ -383,7 +389,8 @@ static void __btrfs_discard_schedule_work(struct btrfs_discard_ctl *discard_ctl,
}
/*
- * btrfs_discard_schedule_work - responsible for scheduling the discard work
+ * Responsible for scheduling the discard work.
+ *
* @discard_ctl: discard control
* @override: override the current timer
*
@@ -401,15 +408,16 @@ void btrfs_discard_schedule_work(struct btrfs_discard_ctl *discard_ctl,
spin_unlock(&discard_ctl->lock);
}
-/**
- * btrfs_finish_discard_pass - determine next step of a block_group
+/*
+ * Determine next step of a block_group.
+ *
* @discard_ctl: discard control
* @block_group: block_group of interest
*
- * This determines the next step for a block group after it's finished going
- * through a pass on a discard list. If it is unused and fully trimmed, we can
- * mark it unused and send it to the unused_bgs path. Otherwise, pass it onto
- * the appropriate filter list or let it fall off.
+ * Determine the next step for a block group after it's finished going through
+ * a pass on a discard list. If it is unused and fully trimmed, we can mark it
+ * unused and send it to the unused_bgs path. Otherwise, pass it onto the
+ * appropriate filter list or let it fall off.
*/
static void btrfs_finish_discard_pass(struct btrfs_discard_ctl *discard_ctl,
struct btrfs_block_group *block_group)
@@ -426,12 +434,13 @@ static void btrfs_finish_discard_pass(struct btrfs_discard_ctl *discard_ctl,
}
}
-/**
- * btrfs_discard_workfn - discard work function
+/*
+ * Discard work queue callback
+ *
* @work: work
*
- * This finds the next block_group to start discarding and then discards a
- * single region. It does this in a two-pass fashion: first extents and second
+ * Find the next block_group to start discarding and then discard a single
+ * region. It does this in a two-pass fashion: first extents and second
* bitmaps. Completely discarded block groups are sent to the unused_bgs path.
*/
static void btrfs_discard_workfn(struct work_struct *work)
@@ -507,11 +516,12 @@ static void btrfs_discard_workfn(struct work_struct *work)
spin_unlock(&discard_ctl->lock);
}
-/**
- * btrfs_run_discard_work - determines if async discard should be running
+/*
+ * Determine if async discard should be running.
+ *
* @discard_ctl: discard control
*
- * Checks if the file system is writeable and BTRFS_FS_DISCARD_RUNNING is set.
+ * Check if the file system is writeable and BTRFS_FS_DISCARD_RUNNING is set.
*/
bool btrfs_run_discard_work(struct btrfs_discard_ctl *discard_ctl)
{
@@ -523,8 +533,9 @@ bool btrfs_run_discard_work(struct btrfs_discard_ctl *discard_ctl)
test_bit(BTRFS_FS_DISCARD_RUNNING, &fs_info->flags));
}
-/**
- * btrfs_discard_calc_delay - recalculate the base delay
+/*
+ * Recalculate the base delay.
+ *
* @discard_ctl: discard control
*
* Recalculate the base delay which is based off the total number of
@@ -545,7 +556,7 @@ void btrfs_discard_calc_delay(struct btrfs_discard_ctl *discard_ctl)
spin_lock(&discard_ctl->lock);
/*
- * The following is to fix a potential -1 discrepenancy that we're not
+ * The following is to fix a potential -1 discrepancy that we're not
* sure how to reproduce. But given that this is the only place that
* utilizes these numbers and this is only called by from
* btrfs_finish_extent_commit() which is synchronized, we can correct
@@ -578,13 +589,14 @@ void btrfs_discard_calc_delay(struct btrfs_discard_ctl *discard_ctl)
spin_unlock(&discard_ctl->lock);
}
-/**
- * btrfs_discard_update_discardable - propagate discard counters
+/*
+ * Propagate discard counters.
+ *
* @block_group: block_group of interest
*
- * This propagates deltas of counters up to the discard_ctl. It maintains a
- * current counter and a previous counter passing the delta up to the global
- * stat. Then the current counter value becomes the previous counter value.
+ * Propagate deltas of counters up to the discard_ctl. It maintains a current
+ * counter and a previous counter passing the delta up to the global stat.
+ * Then the current counter value becomes the previous counter value.
*/
void btrfs_discard_update_discardable(struct btrfs_block_group *block_group)
{
@@ -619,8 +631,9 @@ void btrfs_discard_update_discardable(struct btrfs_block_group *block_group)
}
}
-/**
- * btrfs_discard_punt_unused_bgs_list - punt unused_bgs list to discard lists
+/*
+ * Punt unused_bgs list to discard lists.
+ *
* @fs_info: fs_info of interest
*
* The unused_bgs list needs to be punted to the discard lists because the
@@ -644,8 +657,9 @@ void btrfs_discard_punt_unused_bgs_list(struct btrfs_fs_info *fs_info)
spin_unlock(&fs_info->unused_bgs_lock);
}
-/**
- * btrfs_discard_purge_list - purge discard lists
+/*
+ * Purge discard lists.
+ *
* @discard_ctl: discard control
*
* If we are disabling async discard, we may have intercepted block groups that
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 4b28263c3d32..0888d484df80 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -23,7 +23,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
-#include "volumes.h"
+#include "bio.h"
#include "print-tree.h"
#include "locking.h"
#include "tree-log.h"
@@ -43,6 +43,15 @@
#include "space-info.h"
#include "zoned.h"
#include "subpage.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "defrag.h"
+#include "uuid-tree.h"
+#include "relocation.h"
+#include "scrub.h"
+#include "super.h"
#define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\
BTRFS_HEADER_FLAG_RELOC |\
@@ -75,12 +84,12 @@ static void btrfs_free_csum_hash(struct btrfs_fs_info *fs_info)
* just before they are sent down the IO stack.
*/
struct async_submit_bio {
- struct inode *inode;
+ struct btrfs_inode *inode;
struct bio *bio;
- extent_submit_bio_start_t *submit_bio_start;
+ enum btrfs_wq_submit_cmd submit_cmd;
int mirror_num;
- /* Optional parameter for submit_bio_start used by direct io */
+ /* Optional parameter for used by direct io */
u64 dio_file_offset;
struct btrfs_work work;
blk_status_t status;
@@ -246,40 +255,54 @@ int btrfs_verify_level_key(struct extent_buffer *eb, int level,
return ret;
}
+static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
+ int mirror_num)
+{
+ struct btrfs_fs_info *fs_info = eb->fs_info;
+ u64 start = eb->start;
+ int i, num_pages = num_extent_pages(eb);
+ int ret = 0;
+
+ if (sb_rdonly(fs_info->sb))
+ return -EROFS;
+
+ for (i = 0; i < num_pages; i++) {
+ struct page *p = eb->pages[i];
+
+ ret = btrfs_repair_io_failure(fs_info, 0, start, PAGE_SIZE,
+ start, p, start - page_offset(p), mirror_num);
+ if (ret)
+ break;
+ start += PAGE_SIZE;
+ }
+
+ return ret;
+}
+
/*
* helper to read a given tree block, doing retries as required when
* the checksums don't match and we have alternate mirrors to try.
*
- * @parent_transid: expected transid, skip check if 0
- * @level: expected level, mandatory check
- * @first_key: expected key of first slot, skip check if NULL
+ * @check: expected tree parentness check, see the comments of the
+ * structure for details.
*/
int btrfs_read_extent_buffer(struct extent_buffer *eb,
- u64 parent_transid, int level,
- struct btrfs_key *first_key)
+ struct btrfs_tree_parent_check *check)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
- struct extent_io_tree *io_tree;
int failed = 0;
int ret;
int num_copies = 0;
int mirror_num = 0;
int failed_mirror = 0;
- io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
+ ASSERT(check);
+
while (1) {
clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
- ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num);
- if (!ret) {
- if (verify_parent_transid(io_tree, eb,
- parent_transid, 0))
- ret = -EIO;
- else if (btrfs_verify_level_key(eb, level,
- first_key, parent_transid))
- ret = -EUCLEAN;
- else
- break;
- }
+ ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num, check);
+ if (!ret)
+ break;
num_copies = btrfs_num_copies(fs_info,
eb->start, eb->len);
@@ -455,7 +478,8 @@ static int check_tree_block_fsid(struct extent_buffer *eb)
}
/* Do basic extent buffer checks at read time */
-static int validate_extent_buffer(struct extent_buffer *eb)
+static int validate_extent_buffer(struct extent_buffer *eb,
+ struct btrfs_tree_parent_check *check)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
u64 found_start;
@@ -465,6 +489,8 @@ static int validate_extent_buffer(struct extent_buffer *eb)
const u8 *header_csum;
int ret = 0;
+ ASSERT(check);
+
found_start = btrfs_header_bytenr(eb);
if (found_start != eb->start) {
btrfs_err_rl(fs_info,
@@ -503,6 +529,45 @@ static int validate_extent_buffer(struct extent_buffer *eb)
goto out;
}
+ if (found_level != check->level) {
+ ret = -EIO;
+ goto out;
+ }
+ if (unlikely(check->transid &&
+ btrfs_header_generation(eb) != check->transid)) {
+ btrfs_err_rl(eb->fs_info,
+"parent transid verify failed on logical %llu mirror %u wanted %llu found %llu",
+ eb->start, eb->read_mirror, check->transid,
+ btrfs_header_generation(eb));
+ ret = -EIO;
+ goto out;
+ }
+ if (check->has_first_key) {
+ struct btrfs_key *expect_key = &check->first_key;
+ struct btrfs_key found_key;
+
+ if (found_level)
+ btrfs_node_key_to_cpu(eb, &found_key, 0);
+ else
+ btrfs_item_key_to_cpu(eb, &found_key, 0);
+ if (unlikely(btrfs_comp_cpu_keys(expect_key, &found_key))) {
+ btrfs_err(fs_info,
+"tree first key mismatch detected, bytenr=%llu parent_transid=%llu key expected=(%llu,%u,%llu) has=(%llu,%u,%llu)",
+ eb->start, check->transid,
+ expect_key->objectid,
+ expect_key->type, expect_key->offset,
+ found_key.objectid, found_key.type,
+ found_key.offset);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ }
+ if (check->owner_root) {
+ ret = btrfs_check_eb_owner(eb, check->owner_root);
+ if (ret < 0)
+ goto out;
+ }
+
/*
* If this is a leaf block and it is corrupt, set the corrupt bit so
* that we don't try and read the other copies of this block, just
@@ -527,13 +592,15 @@ out:
}
static int validate_subpage_buffer(struct page *page, u64 start, u64 end,
- int mirror)
+ int mirror, struct btrfs_tree_parent_check *check)
{
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
struct extent_buffer *eb;
bool reads_done;
int ret = 0;
+ ASSERT(check);
+
/*
* We don't allow bio merge for subpage metadata read, so we should
* only get one eb for each endio hook.
@@ -557,7 +624,7 @@ static int validate_subpage_buffer(struct page *page, u64 start, u64 end,
ret = -EIO;
goto err;
}
- ret = validate_extent_buffer(eb);
+ ret = validate_extent_buffer(eb, check);
if (ret < 0)
goto err;
@@ -587,7 +654,8 @@ int btrfs_validate_metadata_buffer(struct btrfs_bio *bbio,
ASSERT(page->private);
if (btrfs_sb(page->mapping->host->i_sb)->nodesize < PAGE_SIZE)
- return validate_subpage_buffer(page, start, end, mirror);
+ return validate_subpage_buffer(page, start, end, mirror,
+ &bbio->parent_check);
eb = (struct extent_buffer *)page->private;
@@ -606,7 +674,7 @@ int btrfs_validate_metadata_buffer(struct btrfs_bio *bbio,
ret = -EIO;
goto err;
}
- ret = validate_extent_buffer(eb);
+ ret = validate_extent_buffer(eb, &bbio->parent_check);
err:
if (ret) {
/*
@@ -628,8 +696,18 @@ static void run_one_async_start(struct btrfs_work *work)
blk_status_t ret;
async = container_of(work, struct async_submit_bio, work);
- ret = async->submit_bio_start(async->inode, async->bio,
- async->dio_file_offset);
+ switch (async->submit_cmd) {
+ case WQ_SUBMIT_METADATA:
+ ret = btree_submit_bio_start(async->bio);
+ break;
+ case WQ_SUBMIT_DATA:
+ ret = btrfs_submit_bio_start(async->inode, async->bio);
+ break;
+ case WQ_SUBMIT_DATA_DIO:
+ ret = btrfs_submit_bio_start_direct_io(async->inode,
+ async->bio, async->dio_file_offset);
+ break;
+ }
if (ret)
async->status = ret;
}
@@ -646,7 +724,7 @@ static void run_one_async_done(struct btrfs_work *work)
{
struct async_submit_bio *async =
container_of(work, struct async_submit_bio, work);
- struct inode *inode = async->inode;
+ struct btrfs_inode *inode = async->inode;
struct btrfs_bio *bbio = btrfs_bio(async->bio);
/* If an error occurred we just want to clean up the bio and move on */
@@ -661,7 +739,7 @@ static void run_one_async_done(struct btrfs_work *work)
* This changes nothing when cgroups aren't in use.
*/
async->bio->bi_opf |= REQ_CGROUP_PUNT;
- btrfs_submit_bio(btrfs_sb(inode->i_sb), async->bio, async->mirror_num);
+ btrfs_submit_bio(inode->root->fs_info, async->bio, async->mirror_num);
}
static void run_one_async_free(struct btrfs_work *work)
@@ -679,11 +757,10 @@ static void run_one_async_free(struct btrfs_work *work)
* - true if the work has been succesfuly submitted
* - false in case of error
*/
-bool btrfs_wq_submit_bio(struct inode *inode, struct bio *bio, int mirror_num,
- u64 dio_file_offset,
- extent_submit_bio_start_t *submit_bio_start)
+bool btrfs_wq_submit_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num,
+ u64 dio_file_offset, enum btrfs_wq_submit_cmd cmd)
{
- struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct async_submit_bio *async;
async = kmalloc(sizeof(*async), GFP_NOFS);
@@ -693,7 +770,7 @@ bool btrfs_wq_submit_bio(struct inode *inode, struct bio *bio, int mirror_num,
async->inode = inode;
async->bio = bio;
async->mirror_num = mirror_num;
- async->submit_bio_start = submit_bio_start;
+ async->submit_cmd = cmd;
btrfs_init_work(&async->work, run_one_async_start, run_one_async_done,
run_one_async_free);
@@ -727,8 +804,7 @@ static blk_status_t btree_csum_one_bio(struct bio *bio)
return errno_to_blk_status(ret);
}
-static blk_status_t btree_submit_bio_start(struct inode *inode, struct bio *bio,
- u64 dio_file_offset)
+blk_status_t btree_submit_bio_start(struct bio *bio)
{
/*
* when we're called for a write, we're already in the async
@@ -749,13 +825,14 @@ static bool should_async_write(struct btrfs_fs_info *fs_info,
return true;
}
-void btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, int mirror_num)
+void btrfs_submit_metadata_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_bio *bbio = btrfs_bio(bio);
blk_status_t ret;
bio->bi_opf |= REQ_META;
+ bbio->is_metadata = 1;
if (btrfs_op(bio) != BTRFS_MAP_WRITE) {
btrfs_submit_bio(fs_info, bio, mirror_num);
@@ -766,8 +843,8 @@ void btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, int mirror_
* Kthread helpers are used to submit writes so that checksumming can
* happen in parallel across all CPUs.
*/
- if (should_async_write(fs_info, BTRFS_I(inode)) &&
- btrfs_wq_submit_bio(inode, bio, mirror_num, 0, btree_submit_bio_start))
+ if (should_async_write(fs_info, inode) &&
+ btrfs_wq_submit_bio(inode, bio, mirror_num, 0, WQ_SUBMIT_METADATA))
return;
ret = btree_csum_one_bio(bio);
@@ -919,28 +996,28 @@ struct extent_buffer *btrfs_find_create_tree_block(
* Read tree block at logical address @bytenr and do variant basic but critical
* verification.
*
- * @owner_root: the objectid of the root owner for this block.
- * @parent_transid: expected transid of this tree block, skip check if 0
- * @level: expected level, mandatory check
- * @first_key: expected key in slot 0, skip check if NULL
+ * @check: expected tree parentness check, see comments of the
+ * structure for details.
*/
struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 owner_root, u64 parent_transid,
- int level, struct btrfs_key *first_key)
+ struct btrfs_tree_parent_check *check)
{
struct extent_buffer *buf = NULL;
int ret;
- buf = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
+ ASSERT(check);
+
+ buf = btrfs_find_create_tree_block(fs_info, bytenr, check->owner_root,
+ check->level);
if (IS_ERR(buf))
return buf;
- ret = btrfs_read_extent_buffer(buf, parent_transid, level, first_key);
+ ret = btrfs_read_extent_buffer(buf, check);
if (ret) {
free_extent_buffer_stale(buf);
return ERR_PTR(ret);
}
- if (btrfs_check_eb_owner(buf, owner_root)) {
+ if (btrfs_check_eb_owner(buf, check->owner_root)) {
free_extent_buffer_stale(buf);
return ERR_PTR(-EUCLEAN);
}
@@ -1027,9 +1104,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
root->anon_dev = 0;
if (!dummy) {
extent_io_tree_init(fs_info, &root->dirty_log_pages,
- IO_TREE_ROOT_DIRTY_LOG_PAGES, NULL);
+ IO_TREE_ROOT_DIRTY_LOG_PAGES);
extent_io_tree_init(fs_info, &root->log_csum_range,
- IO_TREE_LOG_CSUM_RANGE, NULL);
+ IO_TREE_LOG_CSUM_RANGE);
}
spin_lock_init(&root->root_item_lock);
@@ -1167,6 +1244,13 @@ struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr)
return btrfs_global_root(fs_info, &key);
}
+struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info)
+{
+ if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE))
+ return fs_info->block_group_root;
+ return btrfs_extent_root(fs_info, 0);
+}
+
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
u64 objectid)
{
@@ -1197,7 +1281,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf);
leaf = NULL;
- goto fail_unlock;
+ goto fail;
}
root->node = leaf;
@@ -1232,9 +1316,6 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
return root;
-fail_unlock:
- if (leaf)
- btrfs_tree_unlock(leaf);
fail:
btrfs_put_root(root);
@@ -1352,6 +1433,7 @@ static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,
struct btrfs_key *key)
{
struct btrfs_root *root;
+ struct btrfs_tree_parent_check check = { 0 };
struct btrfs_fs_info *fs_info = tree_root->fs_info;
u64 generation;
int ret;
@@ -1371,9 +1453,11 @@ static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,
generation = btrfs_root_generation(&root->root_item);
level = btrfs_root_level(&root->root_item);
- root->node = read_tree_block(fs_info,
- btrfs_root_bytenr(&root->root_item),
- key->objectid, generation, level, NULL);
+ check.level = level;
+ check.transid = generation;
+ check.owner_root = key->objectid;
+ root->node = read_tree_block(fs_info, btrfs_root_bytenr(&root->root_item),
+ &check);
if (IS_ERR(root->node)) {
ret = PTR_ERR(root->node);
root->node = NULL;
@@ -2084,8 +2168,6 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
btrfs_destroy_workqueue(fs_info->workers);
if (fs_info->endio_workers)
destroy_workqueue(fs_info->endio_workers);
- if (fs_info->endio_raid56_workers)
- destroy_workqueue(fs_info->endio_raid56_workers);
if (fs_info->rmw_workers)
destroy_workqueue(fs_info->rmw_workers);
if (fs_info->compressed_write_workers)
@@ -2231,7 +2313,7 @@ static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info)
RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node);
extent_io_tree_init(fs_info, &BTRFS_I(inode)->io_tree,
- IO_TREE_BTREE_INODE_IO, NULL);
+ IO_TREE_BTREE_INODE_IO);
extent_map_tree_init(&BTRFS_I(inode)->extent_tree);
BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root);
@@ -2291,8 +2373,6 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
alloc_workqueue("btrfs-endio", flags, max_active);
fs_info->endio_meta_workers =
alloc_workqueue("btrfs-endio-meta", flags, max_active);
- fs_info->endio_raid56_workers =
- alloc_workqueue("btrfs-endio-raid56", flags, max_active);
fs_info->rmw_workers = alloc_workqueue("btrfs-rmw", flags, max_active);
fs_info->endio_write_workers =
btrfs_alloc_workqueue(fs_info, "endio-write", flags,
@@ -2314,7 +2394,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
fs_info->delalloc_workers && fs_info->flush_workers &&
fs_info->endio_workers && fs_info->endio_meta_workers &&
fs_info->compressed_write_workers &&
- fs_info->endio_write_workers && fs_info->endio_raid56_workers &&
+ fs_info->endio_write_workers &&
fs_info->endio_freespace_worker && fs_info->rmw_workers &&
fs_info->caching_workers && fs_info->fixup_workers &&
fs_info->delayed_workers && fs_info->qgroup_rescan_workers &&
@@ -2350,6 +2430,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
struct btrfs_fs_devices *fs_devices)
{
int ret;
+ struct btrfs_tree_parent_check check = { 0 };
struct btrfs_root *log_tree_root;
struct btrfs_super_block *disk_super = fs_info->super_copy;
u64 bytenr = btrfs_super_log_root(disk_super);
@@ -2365,10 +2446,10 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
if (!log_tree_root)
return -ENOMEM;
- log_tree_root->node = read_tree_block(fs_info, bytenr,
- BTRFS_TREE_LOG_OBJECTID,
- fs_info->generation + 1, level,
- NULL);
+ check.level = level;
+ check.transid = fs_info->generation + 1;
+ check.owner_root = BTRFS_TREE_LOG_OBJECTID;
+ log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
if (IS_ERR(log_tree_root->node)) {
btrfs_warn(fs_info, "failed to read log tree");
ret = PTR_ERR(log_tree_root->node);
@@ -2551,7 +2632,9 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
fs_info->dev_root = root;
}
/* Initialize fs_info for all devices in any case */
- btrfs_init_devices_late(fs_info);
+ ret = btrfs_init_devices_late(fs_info);
+ if (ret)
+ goto out;
/*
* This tree can share blocks with some other fs tree during relocation
@@ -2844,10 +2927,14 @@ out:
static int load_super_root(struct btrfs_root *root, u64 bytenr, u64 gen, int level)
{
+ struct btrfs_tree_parent_check check = {
+ .level = level,
+ .transid = gen,
+ .owner_root = root->root_key.objectid
+ };
int ret = 0;
- root->node = read_tree_block(root->fs_info, bytenr,
- root->root_key.objectid, gen, level, NULL);
+ root->node = read_tree_block(root->fs_info, bytenr, &check);
if (IS_ERR(root->node)) {
ret = PTR_ERR(root->node);
root->node = NULL;
@@ -3055,7 +3142,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
fs_info->block_group_cache_tree = RB_ROOT_CACHED;
extent_io_tree_init(fs_info, &fs_info->excluded_extents,
- IO_TREE_FS_EXCLUDED_EXTENTS, NULL);
+ IO_TREE_FS_EXCLUDED_EXTENTS);
mutex_init(&fs_info->ordered_operations_mutex);
mutex_init(&fs_info->tree_log_mutex);
@@ -3741,10 +3828,18 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
}
/*
- * Mount does not set all options immediately, we can do it now and do
- * not have to wait for transaction commit
+ * For devices supporting discard turn on discard=async automatically,
+ * unless it's already set or disabled. This could be turned off by
+ * nodiscard for the same mount.
*/
- btrfs_apply_pending_changes(fs_info);
+ if (!(btrfs_test_opt(fs_info, DISCARD_SYNC) ||
+ btrfs_test_opt(fs_info, DISCARD_ASYNC) ||
+ btrfs_test_opt(fs_info, NODISCARD)) &&
+ fs_info->fs_devices->discardable) {
+ btrfs_set_and_info(fs_info, DISCARD_ASYNC,
+ "auto enabling async discard");
+ btrfs_clear_opt(fs_info->mount_opt, NODISCARD);
+ }
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
if (btrfs_test_opt(fs_info, CHECK_INTEGRITY)) {
@@ -3873,7 +3968,7 @@ static void btrfs_end_super_write(struct bio *bio)
if (bio->bi_status) {
btrfs_warn_rl_in_rcu(device->fs_info,
"lost page write due to IO error on %s (%d)",
- rcu_str_deref(device->name),
+ btrfs_dev_name(device),
blk_status_to_errno(bio->bi_status));
ClearPageUptodate(page);
SetPageError(page);
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 9fa923e005a3..363935cfc084 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -27,14 +27,14 @@ static inline u64 btrfs_sb_offset(int mirror)
struct btrfs_device;
struct btrfs_fs_devices;
+struct btrfs_tree_parent_check;
void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info);
void btrfs_init_fs_info(struct btrfs_fs_info *fs_info);
int btrfs_verify_level_key(struct extent_buffer *eb, int level,
struct btrfs_key *first_key, u64 parent_transid);
struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 owner_root, u64 parent_transid,
- int level, struct btrfs_key *first_key);
+ struct btrfs_tree_parent_check *check);
struct extent_buffer *btrfs_find_create_tree_block(
struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root,
@@ -75,6 +75,7 @@ struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *key);
struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr);
struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr);
+struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info);
void btrfs_free_fs_info(struct btrfs_fs_info *fs_info);
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
@@ -85,7 +86,7 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
int btrfs_validate_metadata_buffer(struct btrfs_bio *bbio,
struct page *page, u64 start, u64 end,
int mirror);
-void btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, int mirror_num);
+void btrfs_submit_metadata_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info);
#endif
@@ -106,24 +107,22 @@ static inline struct btrfs_root *btrfs_grab_root(struct btrfs_root *root)
return NULL;
}
-static inline struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info)
-{
- if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE))
- return fs_info->block_group_root;
- return btrfs_extent_root(fs_info, 0);
-}
-
void btrfs_put_root(struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic);
-int btrfs_read_extent_buffer(struct extent_buffer *buf, u64 parent_transid,
- int level, struct btrfs_key *first_key);
-bool btrfs_wq_submit_bio(struct inode *inode, struct bio *bio, int mirror_num,
- u64 dio_file_offset,
- extent_submit_bio_start_t *submit_bio_start);
-blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio,
- int mirror_num);
+int btrfs_read_extent_buffer(struct extent_buffer *buf,
+ struct btrfs_tree_parent_check *check);
+
+enum btrfs_wq_submit_cmd {
+ WQ_SUBMIT_METADATA,
+ WQ_SUBMIT_DATA,
+ WQ_SUBMIT_DATA_DIO,
+};
+
+bool btrfs_wq_submit_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num,
+ u64 dio_file_offset, enum btrfs_wq_submit_cmd cmd);
+blk_status_t btree_submit_bio_start(struct bio *bio);
int btrfs_alloc_log_tree_node(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
@@ -136,8 +135,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans,
struct btrfs_fs_info *fs_info);
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
u64 objectid);
-int btree_lock_page_hook(struct page *page, void *data,
- void (*flush_fn)(void *));
int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags);
int btrfs_get_free_objectid(struct btrfs_root *root, u64 *objectid);
int btrfs_init_root_free_objectid(struct btrfs_root *root);
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index fab7eb76e53b..744a02b7fd67 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -7,6 +7,8 @@
#include "btrfs_inode.h"
#include "print-tree.h"
#include "export.h"
+#include "accessors.h"
+#include "super.h"
#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
parent_objectid) / 4)
@@ -57,9 +59,20 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
return type;
}
+/*
+ * Read dentry of inode with @objectid from filesystem root @root_objectid.
+ *
+ * @sb: the filesystem super block
+ * @objectid: inode objectid
+ * @root_objectid: object id of the subvolume root where to look up the inode
+ * @generation: optional, if not zero, verify that the found inode
+ * generation matches
+ *
+ * Return dentry alias for the inode, otherwise an error. In case the
+ * generation does not match return ESTALE.
+ */
struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
- u64 root_objectid, u64 generation,
- int check_generation)
+ u64 root_objectid, u64 generation)
{
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
struct btrfs_root *root;
@@ -77,7 +90,7 @@ struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
if (IS_ERR(inode))
return ERR_CAST(inode);
- if (check_generation && generation != inode->i_generation) {
+ if (generation != 0 && generation != inode->i_generation) {
iput(inode);
return ERR_PTR(-ESTALE);
}
@@ -106,7 +119,7 @@ static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
objectid = fid->parent_objectid;
generation = fid->parent_gen;
- return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
+ return btrfs_get_dentry(sb, objectid, root_objectid, generation);
}
static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
@@ -128,7 +141,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
root_objectid = fid->root_objectid;
generation = fid->gen;
- return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
+ return btrfs_get_dentry(sb, objectid, root_objectid, generation);
}
struct dentry *btrfs_get_parent(struct dentry *child)
@@ -188,7 +201,7 @@ struct dentry *btrfs_get_parent(struct dentry *child)
if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
return btrfs_get_dentry(fs_info->sb, key.objectid,
- found_key.offset, 0, 0);
+ found_key.offset, 0);
}
return d_obtain_alias(btrfs_iget(fs_info->sb, key.objectid, root));
diff --git a/fs/btrfs/export.h b/fs/btrfs/export.h
index 5afb7ca42828..eba6bc4f5a61 100644
--- a/fs/btrfs/export.h
+++ b/fs/btrfs/export.h
@@ -19,8 +19,7 @@ struct btrfs_fid {
} __attribute__ ((packed));
struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
- u64 root_objectid, u64 generation,
- int check_generation);
+ u64 root_objectid, u64 generation);
struct dentry *btrfs_get_parent(struct dentry *child);
#endif
diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c
index 83cb0378096f..9ae9cd1e7035 100644
--- a/fs/btrfs/extent-io-tree.c
+++ b/fs/btrfs/extent-io-tree.c
@@ -2,6 +2,7 @@
#include <linux/slab.h>
#include <trace/events/btrfs.h>
+#include "messages.h"
#include "ctree.h"
#include "extent-io-tree.h"
#include "btrfs_inode.h"
@@ -57,17 +58,17 @@ static inline void __btrfs_debug_check_extent_io_range(const char *caller,
struct extent_io_tree *tree,
u64 start, u64 end)
{
- struct inode *inode = tree->private_data;
+ struct btrfs_inode *inode = tree->inode;
u64 isize;
if (!inode)
return;
- isize = i_size_read(inode);
+ isize = i_size_read(&inode->vfs_inode);
if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) {
- btrfs_debug_rl(BTRFS_I(inode)->root->fs_info,
+ btrfs_debug_rl(inode->root->fs_info,
"%s: ino %llu isize %llu odd range [%llu,%llu]",
- caller, btrfs_ino(BTRFS_I(inode)), isize, start, end);
+ caller, btrfs_ino(inode), isize, start, end);
}
}
#else
@@ -93,13 +94,12 @@ struct tree_entry {
};
void extent_io_tree_init(struct btrfs_fs_info *fs_info,
- struct extent_io_tree *tree, unsigned int owner,
- void *private_data)
+ struct extent_io_tree *tree, unsigned int owner)
{
tree->fs_info = fs_info;
tree->state = RB_ROOT;
spin_lock_init(&tree->lock);
- tree->private_data = private_data;
+ tree->inode = NULL;
tree->owner = owner;
if (owner == IO_TREE_INODE_FILE_EXTENT)
lockdep_set_class(&tree->lock, &file_extent_tree_class);
@@ -346,9 +346,8 @@ static void merge_state(struct extent_io_tree *tree, struct extent_state *state)
other = prev_state(state);
if (other && other->end == state->start - 1 &&
other->state == state->state) {
- if (tree->private_data)
- btrfs_merge_delalloc_extent(tree->private_data,
- state, other);
+ if (tree->inode)
+ btrfs_merge_delalloc_extent(tree->inode, state, other);
state->start = other->start;
rb_erase(&other->rb_node, &tree->state);
RB_CLEAR_NODE(&other->rb_node);
@@ -357,9 +356,8 @@ static void merge_state(struct extent_io_tree *tree, struct extent_state *state)
other = next_state(state);
if (other && other->start == state->end + 1 &&
other->state == state->state) {
- if (tree->private_data)
- btrfs_merge_delalloc_extent(tree->private_data, state,
- other);
+ if (tree->inode)
+ btrfs_merge_delalloc_extent(tree->inode, state, other);
state->end = other->end;
rb_erase(&other->rb_node, &tree->state);
RB_CLEAR_NODE(&other->rb_node);
@@ -374,8 +372,8 @@ static void set_state_bits(struct extent_io_tree *tree,
u32 bits_to_set = bits & ~EXTENT_CTLBITS;
int ret;
- if (tree->private_data)
- btrfs_set_delalloc_extent(tree->private_data, state, bits);
+ if (tree->inode)
+ btrfs_set_delalloc_extent(tree->inode, state, bits);
ret = add_extent_changeset(state, bits_to_set, changeset, 1);
BUG_ON(ret < 0);
@@ -397,7 +395,7 @@ static int insert_state(struct extent_io_tree *tree,
u32 bits, struct extent_changeset *changeset)
{
struct rb_node **node;
- struct rb_node *parent;
+ struct rb_node *parent = NULL;
const u64 end = state->end;
set_state_bits(tree, state, bits, changeset);
@@ -462,8 +460,8 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
struct rb_node *parent = NULL;
struct rb_node **node;
- if (tree->private_data)
- btrfs_split_delalloc_extent(tree->private_data, orig, split);
+ if (tree->inode)
+ btrfs_split_delalloc_extent(tree->inode, orig, split);
prealloc->start = orig->start;
prealloc->end = split - 1;
@@ -510,8 +508,8 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
u32 bits_to_clear = bits & ~EXTENT_CTLBITS;
int ret;
- if (tree->private_data)
- btrfs_clear_delalloc_extent(tree->private_data, state, bits);
+ if (tree->inode)
+ btrfs_clear_delalloc_extent(tree->inode, state, bits);
ret = add_extent_changeset(state, bits_to_clear, changeset, 0);
BUG_ON(ret < 0);
@@ -572,7 +570,7 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (bits & (EXTENT_LOCKED | EXTENT_BOUNDARY))
clear = 1;
again:
- if (!prealloc && gfpflags_allow_blocking(mask)) {
+ if (!prealloc) {
/*
* Don't care for allocation failure here because we might end
* up not needing the pre-allocated extent state at all, which
@@ -636,7 +634,8 @@ hit_next:
if (state->start < start) {
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
err = split_state(tree, state, prealloc, start);
if (err)
extent_io_tree_panic(tree, err);
@@ -657,7 +656,8 @@ hit_next:
*/
if (state->start <= end && state->end > end) {
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
err = split_state(tree, state, prealloc, end + 1);
if (err)
extent_io_tree_panic(tree, err);
@@ -714,7 +714,8 @@ static void wait_on_state(struct extent_io_tree *tree,
* The range [start, end] is inclusive.
* The tree lock is taken by this function
*/
-void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits)
+void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
+ struct extent_state **cached_state)
{
struct extent_state *state;
@@ -722,6 +723,16 @@ void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits)
spin_lock(&tree->lock);
again:
+ /*
+ * Maintain cached_state, as we may not remove it from the tree if there
+ * are more bits than the bits we're waiting on set on this state.
+ */
+ if (cached_state && *cached_state) {
+ state = *cached_state;
+ if (extent_state_in_tree(state) &&
+ state->start <= start && start < state->end)
+ goto process_node;
+ }
while (1) {
/*
* This search will find all the extents that end after our
@@ -752,6 +763,12 @@ process_node:
}
}
out:
+ /* This state is no longer useful, clear it and free it up. */
+ if (cached_state && *cached_state) {
+ state = *cached_state;
+ *cached_state = NULL;
+ free_extent_state(state);
+ }
spin_unlock(&tree->lock);
}
@@ -939,13 +956,17 @@ out:
* sleeping, so the gfp mask is used to indicate what is allowed.
*
* If any of the exclusive bits are set, this will fail with -EEXIST if some
- * part of the range already has the desired bits set. The start of the
- * existing range is returned in failed_start in this case.
+ * part of the range already has the desired bits set. The extent_state of the
+ * existing range is returned in failed_state in this case, and the start of the
+ * existing range is returned in failed_start. failed_state is used as an
+ * optimization for wait_extent_bit, failed_start must be used as the source of
+ * truth as failed_state may have changed since we returned.
*
* [start, end] is inclusive This takes the tree lock.
*/
static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
u32 bits, u64 *failed_start,
+ struct extent_state **failed_state,
struct extent_state **cached_state,
struct extent_changeset *changeset, gfp_t mask)
{
@@ -964,9 +985,9 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (exclusive_bits)
ASSERT(failed_start);
else
- ASSERT(failed_start == NULL);
+ ASSERT(failed_start == NULL && failed_state == NULL);
again:
- if (!prealloc && gfpflags_allow_blocking(mask)) {
+ if (!prealloc) {
/*
* Don't care for allocation failure here because we might end
* up not needing the pre-allocated extent state at all, which
@@ -991,7 +1012,8 @@ again:
state = tree_search_for_insert(tree, start, &p, &parent);
if (!state) {
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
prealloc->start = start;
prealloc->end = end;
insert_state_fast(tree, prealloc, p, parent, bits, changeset);
@@ -1012,6 +1034,7 @@ hit_next:
if (state->start == start && state->end <= end) {
if (state->state & exclusive_bits) {
*failed_start = state->start;
+ cache_state(state, failed_state);
err = -EEXIST;
goto out;
}
@@ -1047,6 +1070,7 @@ hit_next:
if (state->start < start) {
if (state->state & exclusive_bits) {
*failed_start = start;
+ cache_state(state, failed_state);
err = -EEXIST;
goto out;
}
@@ -1062,7 +1086,8 @@ hit_next:
}
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
err = split_state(tree, state, prealloc, start);
if (err)
extent_io_tree_panic(tree, err);
@@ -1099,7 +1124,8 @@ hit_next:
this_end = last_start - 1;
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
/*
* Avoid to free 'prealloc' if it can be merged with the later
@@ -1125,12 +1151,14 @@ hit_next:
if (state->start <= end && state->end > end) {
if (state->state & exclusive_bits) {
*failed_start = start;
+ cache_state(state, failed_state);
err = -EEXIST;
goto out;
}
prealloc = alloc_extent_state_atomic(prealloc);
- BUG_ON(!prealloc);
+ if (!prealloc)
+ goto search_again;
err = split_state(tree, state, prealloc, end + 1);
if (err)
extent_io_tree_panic(tree, err);
@@ -1162,8 +1190,8 @@ out:
int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
u32 bits, struct extent_state **cached_state, gfp_t mask)
{
- return __set_extent_bit(tree, start, end, bits, NULL, cached_state,
- NULL, mask);
+ return __set_extent_bit(tree, start, end, bits, NULL, NULL,
+ cached_state, NULL, mask);
}
/*
@@ -1397,7 +1425,7 @@ void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits)
{
struct extent_state *state;
- struct extent_state *prev = NULL, *next;
+ struct extent_state *prev = NULL, *next = NULL;
spin_lock(&tree->lock);
@@ -1487,15 +1515,37 @@ out:
}
/*
- * Count the number of bytes in the tree that have a given bit(s) set. This
- * can be fairly slow, except for EXTENT_DIRTY which is cached. The total
- * number found is returned.
+ * Count the number of bytes in the tree that have a given bit(s) set for a
+ * given range.
+ *
+ * @tree: The io tree to search.
+ * @start: The start offset of the range. This value is updated to the
+ * offset of the first byte found with the given bit(s), so it
+ * can end up being bigger than the initial value.
+ * @search_end: The end offset (inclusive value) of the search range.
+ * @max_bytes: The maximum byte count we are interested. The search stops
+ * once it reaches this count.
+ * @bits: The bits the range must have in order to be accounted for.
+ * If multiple bits are set, then only subranges that have all
+ * the bits set are accounted for.
+ * @contig: Indicate if we should ignore holes in the range or not. If
+ * this is true, then stop once we find a hole.
+ * @cached_state: A cached state to be used across multiple calls to this
+ * function in order to speedup searches. Use NULL if this is
+ * called only once or if each call does not start where the
+ * previous one ended.
+ *
+ * Returns the total number of bytes found within the given range that have
+ * all given bits set. If the returned number of bytes is greater than zero
+ * then @start is updated with the offset of the first byte with the bits set.
*/
u64 count_range_bits(struct extent_io_tree *tree,
u64 *start, u64 search_end, u64 max_bytes,
- u32 bits, int contig)
+ u32 bits, int contig,
+ struct extent_state **cached_state)
{
- struct extent_state *state;
+ struct extent_state *state = NULL;
+ struct extent_state *cached;
u64 cur_start = *start;
u64 total_bytes = 0;
u64 last = 0;
@@ -1506,11 +1556,41 @@ u64 count_range_bits(struct extent_io_tree *tree,
spin_lock(&tree->lock);
+ if (!cached_state || !*cached_state)
+ goto search;
+
+ cached = *cached_state;
+
+ if (!extent_state_in_tree(cached))
+ goto search;
+
+ if (cached->start <= cur_start && cur_start <= cached->end) {
+ state = cached;
+ } else if (cached->start > cur_start) {
+ struct extent_state *prev;
+
+ /*
+ * The cached state starts after our search range's start. Check
+ * if the previous state record starts at or before the range we
+ * are looking for, and if so, use it - this is a common case
+ * when there are holes between records in the tree. If there is
+ * no previous state record, we can start from our cached state.
+ */
+ prev = prev_state(cached);
+ if (!prev)
+ state = cached;
+ else if (prev->start <= cur_start && cur_start <= prev->end)
+ state = prev;
+ }
+
/*
* This search will find all the extents that end after our range
* starts.
*/
- state = tree_search(tree, cur_start);
+search:
+ if (!state)
+ state = tree_search(tree, cur_start);
+
while (state) {
if (state->start > search_end)
break;
@@ -1531,7 +1611,16 @@ u64 count_range_bits(struct extent_io_tree *tree,
}
state = next_state(state);
}
+
+ if (cached_state) {
+ free_extent_state(*cached_state);
+ *cached_state = state;
+ if (state)
+ refcount_inc(&state->refs);
+ }
+
spin_unlock(&tree->lock);
+
return total_bytes;
}
@@ -1598,8 +1687,8 @@ int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
*/
ASSERT(!(bits & EXTENT_LOCKED));
- return __set_extent_bit(tree, start, end, bits, NULL, NULL, changeset,
- GFP_NOFS);
+ return __set_extent_bit(tree, start, end, bits, NULL, NULL, NULL,
+ changeset, GFP_NOFS);
}
int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
@@ -1615,17 +1704,18 @@ int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
changeset);
}
-int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
+int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached)
{
int err;
u64 failed_start;
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start,
- NULL, NULL, GFP_NOFS);
+ NULL, cached, NULL, GFP_NOFS);
if (err == -EEXIST) {
if (failed_start > start)
clear_extent_bit(tree, start, failed_start - 1,
- EXTENT_LOCKED, NULL);
+ EXTENT_LOCKED, cached);
return 0;
}
return 1;
@@ -1638,20 +1728,22 @@ int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached_state)
{
+ struct extent_state *failed_state = NULL;
int err;
u64 failed_start;
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start,
- cached_state, NULL, GFP_NOFS);
+ &failed_state, cached_state, NULL, GFP_NOFS);
while (err == -EEXIST) {
if (failed_start != start)
clear_extent_bit(tree, start, failed_start - 1,
EXTENT_LOCKED, cached_state);
- wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
+ wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED,
+ &failed_state);
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED,
- &failed_start, cached_state, NULL,
- GFP_NOFS);
+ &failed_start, &failed_state,
+ cached_state, NULL, GFP_NOFS);
}
return err;
}
diff --git a/fs/btrfs/extent-io-tree.h b/fs/btrfs/extent-io-tree.h
index a855f40dd61d..e3eeec380844 100644
--- a/fs/btrfs/extent-io-tree.h
+++ b/fs/btrfs/extent-io-tree.h
@@ -3,43 +3,48 @@
#ifndef BTRFS_EXTENT_IO_TREE_H
#define BTRFS_EXTENT_IO_TREE_H
+#include "misc.h"
+
struct extent_changeset;
struct io_failure_record;
/* Bits for the extent state */
-#define EXTENT_DIRTY (1U << 0)
-#define EXTENT_UPTODATE (1U << 1)
-#define EXTENT_LOCKED (1U << 2)
-#define EXTENT_NEW (1U << 3)
-#define EXTENT_DELALLOC (1U << 4)
-#define EXTENT_DEFRAG (1U << 5)
-#define EXTENT_BOUNDARY (1U << 6)
-#define EXTENT_NODATASUM (1U << 7)
-#define EXTENT_CLEAR_META_RESV (1U << 8)
-#define EXTENT_NEED_WAIT (1U << 9)
-#define EXTENT_NORESERVE (1U << 11)
-#define EXTENT_QGROUP_RESERVED (1U << 12)
-#define EXTENT_CLEAR_DATA_RESV (1U << 13)
-/*
- * Must be cleared only during ordered extent completion or on error paths if we
- * did not manage to submit bios and create the ordered extents for the range.
- * Should not be cleared during page release and page invalidation (if there is
- * an ordered extent in flight), that is left for the ordered extent completion.
- */
-#define EXTENT_DELALLOC_NEW (1U << 14)
-/*
- * When an ordered extent successfully completes for a region marked as a new
- * delalloc range, use this flag when clearing a new delalloc range to indicate
- * that the VFS' inode number of bytes should be incremented and the inode's new
- * delalloc bytes decremented, in an atomic way to prevent races with stat(2).
- */
-#define EXTENT_ADD_INODE_BYTES (1U << 15)
-
-/*
- * Set during truncate when we're clearing an entire range and we just want the
- * extent states to go away.
- */
-#define EXTENT_CLEAR_ALL_BITS (1U << 16)
+enum {
+ ENUM_BIT(EXTENT_DIRTY),
+ ENUM_BIT(EXTENT_UPTODATE),
+ ENUM_BIT(EXTENT_LOCKED),
+ ENUM_BIT(EXTENT_NEW),
+ ENUM_BIT(EXTENT_DELALLOC),
+ ENUM_BIT(EXTENT_DEFRAG),
+ ENUM_BIT(EXTENT_BOUNDARY),
+ ENUM_BIT(EXTENT_NODATASUM),
+ ENUM_BIT(EXTENT_CLEAR_META_RESV),
+ ENUM_BIT(EXTENT_NEED_WAIT),
+ ENUM_BIT(EXTENT_NORESERVE),
+ ENUM_BIT(EXTENT_QGROUP_RESERVED),
+ ENUM_BIT(EXTENT_CLEAR_DATA_RESV),
+ /*
+ * Must be cleared only during ordered extent completion or on error
+ * paths if we did not manage to submit bios and create the ordered
+ * extents for the range. Should not be cleared during page release
+ * and page invalidation (if there is an ordered extent in flight),
+ * that is left for the ordered extent completion.
+ */
+ ENUM_BIT(EXTENT_DELALLOC_NEW),
+ /*
+ * When an ordered extent successfully completes for a region marked as
+ * a new delalloc range, use this flag when clearing a new delalloc
+ * range to indicate that the VFS' inode number of bytes should be
+ * incremented and the inode's new delalloc bytes decremented, in an
+ * atomic way to prevent races with stat(2).
+ */
+ ENUM_BIT(EXTENT_ADD_INODE_BYTES),
+ /*
+ * Set during truncate when we're clearing an entire range and we just
+ * want the extent states to go away.
+ */
+ ENUM_BIT(EXTENT_CLEAR_ALL_BITS),
+};
#define EXTENT_DO_ACCOUNTING (EXTENT_CLEAR_META_RESV | \
EXTENT_CLEAR_DATA_RESV)
@@ -75,7 +80,8 @@ enum {
struct extent_io_tree {
struct rb_root state;
struct btrfs_fs_info *fs_info;
- void *private_data;
+ /* Inode associated with this tree, or NULL. */
+ struct btrfs_inode *inode;
/* Who owns this io tree, should be one of IO_TREE_* */
u8 owner;
@@ -99,21 +105,22 @@ struct extent_state {
};
void extent_io_tree_init(struct btrfs_fs_info *fs_info,
- struct extent_io_tree *tree, unsigned int owner,
- void *private_data);
+ struct extent_io_tree *tree, unsigned int owner);
void extent_io_tree_release(struct extent_io_tree *tree);
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached);
-int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
+int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached);
int __init extent_state_init_cachep(void);
void __cold extent_state_free_cachep(void);
u64 count_range_bits(struct extent_io_tree *tree,
u64 *start, u64 search_end,
- u64 max_bytes, u32 bits, int contig);
+ u64 max_bytes, u32 bits, int contig,
+ struct extent_state **cached_state);
void free_extent_state(struct extent_state *state);
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
@@ -139,13 +146,6 @@ static inline int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
GFP_NOFS, NULL);
}
-static inline int unlock_extent_atomic(struct extent_io_tree *tree, u64 start,
- u64 end, struct extent_state **cached)
-{
- return __clear_extent_bit(tree, start, end, EXTENT_LOCKED, cached,
- GFP_ATOMIC, NULL);
-}
-
static inline int clear_extent_bits(struct extent_io_tree *tree, u64 start,
u64 end, u32 bits)
{
@@ -217,13 +217,6 @@ static inline int set_extent_new(struct extent_io_tree *tree, u64 start,
return set_extent_bit(tree, start, end, EXTENT_NEW, NULL, GFP_NOFS);
}
-static inline int set_extent_uptodate(struct extent_io_tree *tree, u64 start,
- u64 end, struct extent_state **cached_state, gfp_t mask)
-{
- return set_extent_bit(tree, start, end, EXTENT_UPTODATE,
- cached_state, mask);
-}
-
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits,
struct extent_state **cached_state);
@@ -234,6 +227,7 @@ int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start,
bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start,
u64 *end, u64 max_bytes,
struct extent_state **cached_state);
-void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits);
+void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
+ struct extent_state **cached_state);
#endif /* BTRFS_EXTENT_IO_TREE_H */
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 2801c991814f..892d78c1853c 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -36,6 +36,13 @@
#include "rcu-string.h"
#include "zoned.h"
#include "dev-replace.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "file-item.h"
+#include "orphan.h"
+#include "tree-checker.h"
#undef SCRAMBLE_DELAYED_REFS
@@ -5255,8 +5262,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
u64 bytenr;
u64 generation;
u64 parent;
+ struct btrfs_tree_parent_check check = { 0 };
struct btrfs_key key;
- struct btrfs_key first_key;
struct btrfs_ref ref = { 0 };
struct extent_buffer *next;
int level = wc->level;
@@ -5278,7 +5285,12 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
}
bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
- btrfs_node_key_to_cpu(path->nodes[level], &first_key,
+
+ check.level = level - 1;
+ check.transid = generation;
+ check.owner_root = root->root_key.objectid;
+ check.has_first_key = true;
+ btrfs_node_key_to_cpu(path->nodes[level], &check.first_key,
path->slots[level]);
next = find_extent_buffer(fs_info, bytenr);
@@ -5340,8 +5352,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
if (!next) {
if (reada && level == 1)
reada_walk_down(trans, root, wc, path);
- next = read_tree_block(fs_info, bytenr, root->root_key.objectid,
- generation, level - 1, &first_key);
+ next = read_tree_block(fs_info, bytenr, &check);
if (IS_ERR(next)) {
return PTR_ERR(next);
} else if (!extent_buffer_uptodate(next)) {
@@ -5973,40 +5984,6 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
return ret;
}
-/*
- * helper to account the unused space of all the readonly block group in the
- * space_info. takes mirrors into account.
- */
-u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
-{
- struct btrfs_block_group *block_group;
- u64 free_bytes = 0;
- int factor;
-
- /* It's df, we don't care if it's racy */
- if (list_empty(&sinfo->ro_bgs))
- return 0;
-
- spin_lock(&sinfo->lock);
- list_for_each_entry(block_group, &sinfo->ro_bgs, ro_list) {
- spin_lock(&block_group->lock);
-
- if (!block_group->ro) {
- spin_unlock(&block_group->lock);
- continue;
- }
-
- factor = btrfs_bg_type_to_factor(block_group->flags);
- free_bytes += (block_group->length -
- block_group->used) * factor;
-
- spin_unlock(&block_group->lock);
- }
- spin_unlock(&sinfo->lock);
-
- return free_bytes;
-}
-
int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
u64 start, u64 end)
{
@@ -6072,7 +6049,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
btrfs_warn_in_rcu(fs_info,
"ignoring attempt to trim beyond device size: offset %llu length %llu device %s device size %llu",
start, end - start + 1,
- rcu_str_deref(device->name),
+ btrfs_dev_name(device),
device->total_bytes);
mutex_unlock(&fs_info->chunk_mutex);
ret = 0;
diff --git a/fs/btrfs/extent-tree.h b/fs/btrfs/extent-tree.h
new file mode 100644
index 000000000000..ae5425253603
--- /dev/null
+++ b/fs/btrfs/extent-tree.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_EXTENT_TREE_H
+#define BTRFS_EXTENT_TREE_H
+
+enum btrfs_inline_ref_type {
+ BTRFS_REF_TYPE_INVALID,
+ BTRFS_REF_TYPE_BLOCK,
+ BTRFS_REF_TYPE_DATA,
+ BTRFS_REF_TYPE_ANY,
+};
+
+int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
+ struct btrfs_extent_inline_ref *iref,
+ enum btrfs_inline_ref_type is_data);
+u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
+
+int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,
+ u64 start, u64 num_bytes);
+void btrfs_free_excluded_extents(struct btrfs_block_group *cache);
+int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, unsigned long count);
+void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
+ struct btrfs_delayed_ref_root *delayed_refs,
+ struct btrfs_delayed_ref_head *head);
+int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len);
+int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info, u64 bytenr,
+ u64 offset, int metadata, u64 *refs, u64 *flags);
+int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num,
+ int reserved);
+int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
+ u64 bytenr, u64 num_bytes);
+int btrfs_exclude_logged_extents(struct extent_buffer *eb);
+int btrfs_cross_ref_exist(struct btrfs_root *root,
+ u64 objectid, u64 offset, u64 bytenr, bool strict,
+ struct btrfs_path *path);
+struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 parent, u64 root_objectid,
+ const struct btrfs_disk_key *key,
+ int level, u64 hint,
+ u64 empty_size,
+ enum btrfs_lock_nesting nest);
+void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+ u64 root_id,
+ struct extent_buffer *buf,
+ u64 parent, int last_ref);
+int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 owner,
+ u64 offset, u64 ram_bytes,
+ struct btrfs_key *ins);
+int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
+ u64 root_objectid, u64 owner, u64 offset,
+ struct btrfs_key *ins);
+int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes,
+ u64 min_alloc_size, u64 empty_size, u64 hint_byte,
+ struct btrfs_key *ins, int is_data, int delalloc);
+int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct extent_buffer *buf, int full_backref);
+int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct extent_buffer *buf, int full_backref);
+int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
+ struct extent_buffer *eb, u64 flags, int level);
+int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref);
+
+int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
+ u64 start, u64 len, int delalloc);
+int btrfs_pin_reserved_extent(struct btrfs_trans_handle *trans, u64 start, u64 len);
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);
+int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_ref *generic_ref);
+int __must_check btrfs_drop_snapshot(struct btrfs_root *root, int update_ref,
+ int for_reloc);
+int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *node,
+ struct extent_buffer *parent);
+
+#endif
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 4dcf22e051ff..83dd3aa59663 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -20,7 +20,7 @@
#include "extent_map.h"
#include "ctree.h"
#include "btrfs_inode.h"
-#include "volumes.h"
+#include "bio.h"
#include "check-integrity.h"
#include "locking.h"
#include "rcu-string.h"
@@ -30,6 +30,12 @@
#include "zoned.h"
#include "block-group.h"
#include "compression.h"
+#include "fs.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "file.h"
+#include "dev-replace.h"
+#include "super.h"
static struct kmem_cache *extent_buffer_cache;
@@ -96,24 +102,22 @@ struct btrfs_bio_ctrl {
u32 len_to_stripe_boundary;
u32 len_to_oe_boundary;
btrfs_bio_end_io_t end_io_func;
-};
-struct extent_page_data {
- struct btrfs_bio_ctrl bio_ctrl;
- /* tells writepage not to lock the state bits for this range
- * it still does the unlocking
+ /*
+ * Tell writepage not to lock the state bits for this range, it still
+ * does the unlocking.
*/
- unsigned int extent_locked:1;
+ bool extent_locked;
- /* tells the submit_bio code to use REQ_SYNC */
- unsigned int sync_io:1;
+ /* Tell the submit_bio code to use REQ_SYNC */
+ bool sync_io;
};
static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
{
struct bio *bio;
struct bio_vec *bv;
- struct inode *inode;
+ struct btrfs_inode *inode;
int mirror_num;
if (!bio_ctrl->bio)
@@ -121,7 +125,7 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
bio = bio_ctrl->bio;
bv = bio_first_bvec_all(bio);
- inode = bv->bv_page->mapping->host;
+ inode = BTRFS_I(bv->bv_page->mapping->host);
mirror_num = bio_ctrl->mirror_num;
/* Caller should ensure the bio has at least some range added */
@@ -129,7 +133,7 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
btrfs_bio(bio)->file_offset = page_offset(bv->bv_page) + bv->bv_offset;
- if (!is_data_inode(inode))
+ if (!is_data_inode(&inode->vfs_inode))
btrfs_submit_metadata_bio(inode, bio, mirror_num);
else if (btrfs_op(bio) == BTRFS_MAP_WRITE)
btrfs_submit_data_write_bio(inode, bio, mirror_num);
@@ -142,11 +146,11 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
}
/*
- * Submit or fail the current bio in an extent_page_data structure.
+ * Submit or fail the current bio in the bio_ctrl structure.
*/
-static void submit_write_bio(struct extent_page_data *epd, int ret)
+static void submit_write_bio(struct btrfs_bio_ctrl *bio_ctrl, int ret)
{
- struct bio *bio = epd->bio_ctrl.bio;
+ struct bio *bio = bio_ctrl->bio;
if (!bio)
return;
@@ -155,9 +159,9 @@ static void submit_write_bio(struct extent_page_data *epd, int ret)
ASSERT(ret < 0);
btrfs_bio_end_io(btrfs_bio(bio), errno_to_blk_status(ret));
/* The bio is owned by the end_io handler now */
- epd->bio_ctrl.bio = NULL;
+ bio_ctrl->bio = NULL;
} else {
- submit_one_bio(&epd->bio_ctrl);
+ submit_one_bio(bio_ctrl);
}
}
@@ -527,120 +531,6 @@ static void free_io_failure(struct btrfs_inode *inode,
kfree(rec);
}
-/*
- * this bypasses the standard btrfs submit functions deliberately, as
- * the standard behavior is to write all copies in a raid setup. here we only
- * want to write the one bad copy. so we do the mapping for ourselves and issue
- * submit_bio directly.
- * to avoid any synchronization issues, wait for the data after writing, which
- * actually prevents the read that triggered the error from finishing.
- * currently, there can be no more than two copies of every data bit. thus,
- * exactly one rewrite is required.
- */
-static int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
- u64 length, u64 logical, struct page *page,
- unsigned int pg_offset, int mirror_num)
-{
- struct btrfs_device *dev;
- struct bio_vec bvec;
- struct bio bio;
- u64 map_length = 0;
- u64 sector;
- struct btrfs_io_context *bioc = NULL;
- int ret = 0;
-
- ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
- BUG_ON(!mirror_num);
-
- if (btrfs_repair_one_zone(fs_info, logical))
- return 0;
-
- map_length = length;
-
- /*
- * Avoid races with device replace and make sure our bioc has devices
- * associated to its stripes that don't go away while we are doing the
- * read repair operation.
- */
- btrfs_bio_counter_inc_blocked(fs_info);
- if (btrfs_is_parity_mirror(fs_info, logical, length)) {
- /*
- * Note that we don't use BTRFS_MAP_WRITE because it's supposed
- * to update all raid stripes, but here we just want to correct
- * bad stripe, thus BTRFS_MAP_READ is abused to only get the bad
- * stripe's dev and sector.
- */
- ret = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
- &map_length, &bioc, 0);
- if (ret)
- goto out_counter_dec;
- ASSERT(bioc->mirror_num == 1);
- } else {
- ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical,
- &map_length, &bioc, mirror_num);
- if (ret)
- goto out_counter_dec;
- BUG_ON(mirror_num != bioc->mirror_num);
- }
-
- sector = bioc->stripes[bioc->mirror_num - 1].physical >> 9;
- dev = bioc->stripes[bioc->mirror_num - 1].dev;
- btrfs_put_bioc(bioc);
-
- if (!dev || !dev->bdev ||
- !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) {
- ret = -EIO;
- goto out_counter_dec;
- }
-
- bio_init(&bio, dev->bdev, &bvec, 1, REQ_OP_WRITE | REQ_SYNC);
- bio.bi_iter.bi_sector = sector;
- __bio_add_page(&bio, page, length, pg_offset);
-
- btrfsic_check_bio(&bio);
- ret = submit_bio_wait(&bio);
- if (ret) {
- /* try to remap that extent elsewhere? */
- btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
- goto out_bio_uninit;
- }
-
- btrfs_info_rl_in_rcu(fs_info,
- "read error corrected: ino %llu off %llu (dev %s sector %llu)",
- ino, start,
- rcu_str_deref(dev->name), sector);
- ret = 0;
-
-out_bio_uninit:
- bio_uninit(&bio);
-out_counter_dec:
- btrfs_bio_counter_dec(fs_info);
- return ret;
-}
-
-int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num)
-{
- struct btrfs_fs_info *fs_info = eb->fs_info;
- u64 start = eb->start;
- int i, num_pages = num_extent_pages(eb);
- int ret = 0;
-
- if (sb_rdonly(fs_info->sb))
- return -EROFS;
-
- for (i = 0; i < num_pages; i++) {
- struct page *p = eb->pages[i];
-
- ret = repair_io_failure(fs_info, 0, start, PAGE_SIZE, start, p,
- start - page_offset(p), mirror_num);
- if (ret)
- break;
- start += PAGE_SIZE;
- }
-
- return ret;
-}
-
static int next_mirror(const struct io_failure_record *failrec, int cur_mirror)
{
if (cur_mirror == failrec->num_copies)
@@ -688,7 +578,7 @@ int btrfs_clean_io_failure(struct btrfs_inode *inode, u64 start,
mirror = failrec->this_mirror;
do {
mirror = prev_mirror(failrec, mirror);
- repair_io_failure(fs_info, ino, start, failrec->len,
+ btrfs_repair_io_failure(fs_info, ino, start, failrec->len,
failrec->logical, page, pg_offset, mirror);
} while (mirror != failrec->failed_mirror);
@@ -791,13 +681,13 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode
return failrec;
}
-int btrfs_repair_one_sector(struct inode *inode, struct btrfs_bio *failed_bbio,
+int btrfs_repair_one_sector(struct btrfs_inode *inode, struct btrfs_bio *failed_bbio,
u32 bio_offset, struct page *page, unsigned int pgoff,
- submit_bio_hook_t *submit_bio_hook)
+ bool submit_buffered)
{
u64 start = failed_bbio->file_offset + bio_offset;
struct io_failure_record *failrec;
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct bio *failed_bio = &failed_bbio->bio;
const int icsum = bio_offset >> fs_info->sectorsize_bits;
struct bio *repair_bio;
@@ -808,7 +698,7 @@ int btrfs_repair_one_sector(struct inode *inode, struct btrfs_bio *failed_bbio,
BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
- failrec = btrfs_get_io_failure_record(inode, failed_bbio, bio_offset);
+ failrec = btrfs_get_io_failure_record(&inode->vfs_inode, failed_bbio, bio_offset);
if (IS_ERR(failrec))
return PTR_ERR(failrec);
@@ -819,14 +709,14 @@ int btrfs_repair_one_sector(struct inode *inode, struct btrfs_bio *failed_bbio,
*
* Since we're only doing repair for one sector, we only need to get
* a good copy of the failed sector and if we succeed, we have setup
- * everything for repair_io_failure to do the rest for us.
+ * everything for btrfs_repair_io_failure to do the rest for us.
*/
failrec->this_mirror = next_mirror(failrec, failrec->this_mirror);
if (failrec->this_mirror == failrec->failed_mirror) {
btrfs_debug(fs_info,
"failed to repair num_copies %d this_mirror %d failed_mirror %d",
failrec->num_copies, failrec->this_mirror, failrec->failed_mirror);
- free_io_failure(BTRFS_I(inode), failrec);
+ free_io_failure(inode, failrec);
return -EIO;
}
@@ -847,16 +737,21 @@ int btrfs_repair_one_sector(struct inode *inode, struct btrfs_bio *failed_bbio,
bio_add_page(repair_bio, page, failrec->len, pgoff);
repair_bbio->iter = repair_bio->bi_iter;
- btrfs_debug(btrfs_sb(inode->i_sb),
+ btrfs_debug(fs_info,
"repair read error: submitting new read to mirror %d",
failrec->this_mirror);
/*
- * At this point we have a bio, so any errors from submit_bio_hook()
- * will be handled by the endio on the repair_bio, so we can't return an
+ * At this point we have a bio, so any errors from bio submission will
+ * be handled by the endio on the repair_bio, so we can't return an
* error here.
*/
- submit_bio_hook(inode, repair_bio, failrec->this_mirror, 0);
+ if (submit_buffered)
+ btrfs_submit_data_read_bio(inode, repair_bio,
+ failrec->this_mirror, 0);
+ else
+ btrfs_submit_dio_repair_bio(inode, repair_bio, failrec->this_mirror);
+
return BLK_STS_OK;
}
@@ -892,14 +787,9 @@ static void end_sector_io(struct page *page, u64 offset, bool uptodate)
{
struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
const u32 sectorsize = inode->root->fs_info->sectorsize;
- struct extent_state *cached = NULL;
end_page_read(page, uptodate, offset, sectorsize);
- if (uptodate)
- set_extent_uptodate(&inode->io_tree, offset,
- offset + sectorsize - 1, &cached, GFP_ATOMIC);
- unlock_extent_atomic(&inode->io_tree, offset, offset + sectorsize - 1,
- &cached);
+ unlock_extent(&inode->io_tree, offset, offset + sectorsize - 1, NULL);
}
static void submit_data_read_repair(struct inode *inode,
@@ -945,9 +835,9 @@ static void submit_data_read_repair(struct inode *inode,
goto next;
}
- ret = btrfs_repair_one_sector(inode, failed_bbio,
+ ret = btrfs_repair_one_sector(BTRFS_I(inode), failed_bbio,
bio_offset + offset, page, pgoff + offset,
- btrfs_submit_data_read_bio);
+ true);
if (!ret) {
/*
* We have submitted the read repair, the page release
@@ -1103,7 +993,7 @@ static void endio_readpage_release_extent(struct processed_extent *processed,
* Now we don't have range contiguous to the processed range, release
* the processed range now.
*/
- unlock_extent_atomic(tree, processed->start, processed->end, &cached);
+ unlock_extent(tree, processed->start, processed->end, &cached);
update:
/* Update processed to current range */
@@ -1296,7 +1186,7 @@ static void end_bio_extent_readpage(struct btrfs_bio *bbio)
bio_put(bio);
}
-/**
+/*
* Populate every free slot in a provided array with pages.
*
* @nr_pages: number of pages to allocate
@@ -1332,16 +1222,16 @@ int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array)
return 0;
}
-/**
- * Attempt to add a page to bio
+/*
+ * Attempt to add a page to bio.
*
- * @bio_ctrl: record both the bio, and its bio_flags
- * @page: page to add to the bio
- * @disk_bytenr: offset of the new bio or to check whether we are adding
- * a contiguous page to the previous one
- * @size: portion of page that we want to write
- * @pg_offset: starting offset in the page
- * @compress_type: compression type of the current bio to see if we can merge them
+ * @bio_ctrl: record both the bio, and its bio_flags
+ * @page: page to add to the bio
+ * @disk_bytenr: offset of the new bio or to check whether we are adding
+ * a contiguous page to the previous one
+ * @size: portion of page that we want to write
+ * @pg_offset: starting offset in the page
+ * @compress_type: compression type of the current bio to see if we can merge them
*
* Attempt to add a page to bio considering stripe alignment etc.
*
@@ -1772,13 +1662,9 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
ASSERT(IS_ALIGNED(cur, fs_info->sectorsize));
if (cur >= last_byte) {
- struct extent_state *cached = NULL;
-
iosize = PAGE_SIZE - pg_offset;
memzero_page(page, pg_offset, iosize);
- set_extent_uptodate(tree, cur, cur + iosize - 1,
- &cached, GFP_NOFS);
- unlock_extent(tree, cur, cur + iosize - 1, &cached);
+ unlock_extent(tree, cur, cur + iosize - 1, NULL);
end_page_read(page, true, cur, iosize);
break;
}
@@ -1854,13 +1740,9 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
/* we've found a hole, just zero and go on */
if (block_start == EXTENT_MAP_HOLE) {
- struct extent_state *cached = NULL;
-
memzero_page(page, pg_offset, iosize);
- set_extent_uptodate(tree, cur, cur + iosize - 1,
- &cached, GFP_NOFS);
- unlock_extent(tree, cur, cur + iosize - 1, &cached);
+ unlock_extent(tree, cur, cur + iosize - 1, NULL);
end_page_read(page, true, cur, iosize);
cur = cur + iosize;
pg_offset += iosize;
@@ -2065,7 +1947,7 @@ static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
struct page *page,
struct writeback_control *wbc,
- struct extent_page_data *epd,
+ struct btrfs_bio_ctrl *bio_ctrl,
loff_t i_size,
int *nr_ret)
{
@@ -2097,7 +1979,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
*/
wbc->nr_to_write--;
- epd->bio_ctrl.end_io_func = end_bio_extent_writepage;
+ bio_ctrl->end_io_func = end_bio_extent_writepage;
while (cur <= end) {
u64 disk_bytenr;
u64 em_end;
@@ -2191,7 +2073,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
btrfs_page_clear_dirty(fs_info, page, cur, iosize);
ret = submit_extent_page(op | write_flags, wbc,
- &epd->bio_ctrl, disk_bytenr,
+ bio_ctrl, disk_bytenr,
page, iosize,
cur - page_offset(page),
0, false);
@@ -2231,7 +2113,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
* Return <0 for error.
*/
static int __extent_writepage(struct page *page, struct writeback_control *wbc,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
struct folio *folio = page_folio(page);
struct inode *inode = page->mapping->host;
@@ -2268,7 +2150,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
goto done;
}
- if (!epd->extent_locked) {
+ if (!bio_ctrl->extent_locked) {
ret = writepage_delalloc(BTRFS_I(inode), page, wbc);
if (ret == 1)
return 0;
@@ -2276,7 +2158,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
goto done;
}
- ret = __extent_writepage_io(BTRFS_I(inode), page, wbc, epd, i_size,
+ ret = __extent_writepage_io(BTRFS_I(inode), page, wbc, bio_ctrl, i_size,
&nr);
if (ret == 1)
return 0;
@@ -2320,9 +2202,9 @@ done:
*/
if (PageError(page))
end_extent_writepage(page, ret, page_start, page_end);
- if (epd->extent_locked) {
+ if (bio_ctrl->extent_locked) {
/*
- * If epd->extent_locked, it's from extent_write_locked_range(),
+ * If bio_ctrl->extent_locked, it's from extent_write_locked_range(),
* the page can either be locked by lock_page() or
* process_one_page().
* Let btrfs_page_unlock_writer() handle both cases.
@@ -2361,7 +2243,7 @@ static void end_extent_buffer_writeback(struct extent_buffer *eb)
* Return <0 if something went wrong, no page is locked.
*/
static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
int i, num_pages;
@@ -2369,17 +2251,17 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
int ret = 0;
if (!btrfs_try_tree_write_lock(eb)) {
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
flush = 1;
btrfs_tree_lock(eb);
}
if (test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags)) {
btrfs_tree_unlock(eb);
- if (!epd->sync_io)
+ if (!bio_ctrl->sync_io)
return 0;
if (!flush) {
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
flush = 1;
}
while (1) {
@@ -2426,7 +2308,7 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
if (!trylock_page(p)) {
if (!flush) {
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
flush = 1;
}
lock_page(p);
@@ -2647,15 +2529,19 @@ static void prepare_eb_write(struct extent_buffer *eb)
/* Set btree blocks beyond nritems with 0 to avoid stale content */
nritems = btrfs_header_nritems(eb);
if (btrfs_header_level(eb) > 0) {
- end = btrfs_node_key_ptr_offset(nritems);
+ end = btrfs_node_key_ptr_offset(eb, nritems);
memzero_extent_buffer(eb, end, eb->len - end);
} else {
/*
* Leaf:
* header 0 1 2 .. N ... data_N .. data_2 data_1 data_0
*/
- start = btrfs_item_nr_offset(nritems);
- end = BTRFS_LEAF_DATA_OFFSET + leaf_data_end(eb);
+ start = btrfs_item_nr_offset(eb, nritems);
+ end = btrfs_item_nr_offset(eb, 0);
+ if (nritems == 0)
+ end += BTRFS_LEAF_DATA_SIZE(eb->fs_info);
+ else
+ end += btrfs_item_offset(eb, nritems - 1);
memzero_extent_buffer(eb, start, end - start);
}
}
@@ -2666,7 +2552,7 @@ static void prepare_eb_write(struct extent_buffer *eb)
*/
static int write_one_subpage_eb(struct extent_buffer *eb,
struct writeback_control *wbc,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
struct page *page = eb->pages[0];
@@ -2686,10 +2572,10 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
if (no_dirty_ebs)
clear_page_dirty_for_io(page);
- epd->bio_ctrl.end_io_func = end_bio_subpage_eb_writepage;
+ bio_ctrl->end_io_func = end_bio_subpage_eb_writepage;
ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc,
- &epd->bio_ctrl, eb->start, page, eb->len,
+ bio_ctrl, eb->start, page, eb->len,
eb->start - page_offset(page), 0, false);
if (ret) {
btrfs_subpage_clear_writeback(fs_info, page, eb->start, eb->len);
@@ -2712,7 +2598,7 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
struct writeback_control *wbc,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
u64 disk_bytenr = eb->start;
int i, num_pages;
@@ -2721,7 +2607,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
prepare_eb_write(eb);
- epd->bio_ctrl.end_io_func = end_bio_extent_buffer_writepage;
+ bio_ctrl->end_io_func = end_bio_extent_buffer_writepage;
num_pages = num_extent_pages(eb);
for (i = 0; i < num_pages; i++) {
@@ -2730,7 +2616,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
clear_page_dirty_for_io(p);
set_page_writeback(p);
ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc,
- &epd->bio_ctrl, disk_bytenr, p,
+ bio_ctrl, disk_bytenr, p,
PAGE_SIZE, 0, 0, false);
if (ret) {
set_btree_ioerr(p, eb);
@@ -2773,7 +2659,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
*/
static int submit_eb_subpage(struct page *page,
struct writeback_control *wbc,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
int submitted = 0;
@@ -2826,7 +2712,7 @@ static int submit_eb_subpage(struct page *page,
if (!eb)
continue;
- ret = lock_extent_buffer_for_io(eb, epd);
+ ret = lock_extent_buffer_for_io(eb, bio_ctrl);
if (ret == 0) {
free_extent_buffer(eb);
continue;
@@ -2835,7 +2721,7 @@ static int submit_eb_subpage(struct page *page,
free_extent_buffer(eb);
goto cleanup;
}
- ret = write_one_subpage_eb(eb, wbc, epd);
+ ret = write_one_subpage_eb(eb, wbc, bio_ctrl);
free_extent_buffer(eb);
if (ret < 0)
goto cleanup;
@@ -2845,7 +2731,7 @@ static int submit_eb_subpage(struct page *page,
cleanup:
/* We hit error, end bio for the submitted extent buffers */
- submit_write_bio(epd, ret);
+ submit_write_bio(bio_ctrl, ret);
return ret;
}
@@ -2870,7 +2756,7 @@ cleanup:
* Return <0 for fatal error.
*/
static int submit_eb_page(struct page *page, struct writeback_control *wbc,
- struct extent_page_data *epd,
+ struct btrfs_bio_ctrl *bio_ctrl,
struct extent_buffer **eb_context)
{
struct address_space *mapping = page->mapping;
@@ -2882,7 +2768,7 @@ static int submit_eb_page(struct page *page, struct writeback_control *wbc,
return 0;
if (btrfs_sb(page->mapping->host->i_sb)->nodesize < PAGE_SIZE)
- return submit_eb_subpage(page, wbc, epd);
+ return submit_eb_subpage(page, wbc, bio_ctrl);
spin_lock(&mapping->private_lock);
if (!PagePrivate(page)) {
@@ -2925,7 +2811,7 @@ static int submit_eb_page(struct page *page, struct writeback_control *wbc,
*eb_context = eb;
- ret = lock_extent_buffer_for_io(eb, epd);
+ ret = lock_extent_buffer_for_io(eb, bio_ctrl);
if (ret <= 0) {
btrfs_revert_meta_write_pointer(cache, eb);
if (cache)
@@ -2940,7 +2826,7 @@ static int submit_eb_page(struct page *page, struct writeback_control *wbc,
btrfs_schedule_zone_finish_bg(cache, eb);
btrfs_put_block_group(cache);
}
- ret = write_one_eb(eb, wbc, epd);
+ ret = write_one_eb(eb, wbc, bio_ctrl);
free_extent_buffer(eb);
if (ret < 0)
return ret;
@@ -2951,10 +2837,9 @@ int btree_write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct extent_buffer *eb_context = NULL;
- struct extent_page_data epd = {
- .bio_ctrl = { 0 },
+ struct btrfs_bio_ctrl bio_ctrl = {
.extent_locked = 0,
- .sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ .sync_io = (wbc->sync_mode == WB_SYNC_ALL),
};
struct btrfs_fs_info *fs_info = BTRFS_I(mapping->host)->root->fs_info;
int ret = 0;
@@ -2997,7 +2882,7 @@ retry:
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
- ret = submit_eb_page(page, wbc, &epd, &eb_context);
+ ret = submit_eb_page(page, wbc, &bio_ctrl, &eb_context);
if (ret == 0)
continue;
if (ret < 0) {
@@ -3058,18 +2943,18 @@ retry:
ret = 0;
if (!ret && BTRFS_FS_ERROR(fs_info))
ret = -EROFS;
- submit_write_bio(&epd, ret);
+ submit_write_bio(&bio_ctrl, ret);
btrfs_zoned_meta_io_unlock(fs_info);
return ret;
}
-/**
+/*
* Walk the list of dirty pages of the given address space and write all of them.
*
- * @mapping: address space structure to write
- * @wbc: subtract the number of written pages from *@wbc->nr_to_write
- * @epd: holds context for the write, namely the bio
+ * @mapping: address space structure to write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ * @bio_ctrl: holds context for the write, namely the bio
*
* If a page is already under I/O, write_cache_pages() skips it, even
* if it's dirty. This is desirable behaviour for memory-cleaning writeback,
@@ -3081,7 +2966,7 @@ retry:
*/
static int extent_write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc,
- struct extent_page_data *epd)
+ struct btrfs_bio_ctrl *bio_ctrl)
{
struct inode *inode = mapping->host;
int ret = 0;
@@ -3162,7 +3047,7 @@ retry:
* tmpfs file mapping
*/
if (!trylock_page(page)) {
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
lock_page(page);
}
@@ -3173,7 +3058,7 @@ retry:
if (wbc->sync_mode != WB_SYNC_NONE) {
if (PageWriteback(page))
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
wait_on_page_writeback(page);
}
@@ -3183,7 +3068,7 @@ retry:
continue;
}
- ret = __extent_writepage(page, wbc, epd);
+ ret = __extent_writepage(page, wbc, bio_ctrl);
if (ret < 0) {
done = 1;
break;
@@ -3213,14 +3098,14 @@ retry:
* page in our current bio, and thus deadlock, so flush the
* write bio here.
*/
- submit_write_bio(epd, 0);
+ submit_write_bio(bio_ctrl, 0);
goto retry;
}
if (wbc->range_cyclic || (wbc->nr_to_write > 0 && range_whole))
mapping->writeback_index = done_index;
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
return ret;
}
@@ -3239,8 +3124,7 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end)
u64 cur = start;
unsigned long nr_pages;
const u32 sectorsize = btrfs_sb(inode->i_sb)->sectorsize;
- struct extent_page_data epd = {
- .bio_ctrl = { 0 },
+ struct btrfs_bio_ctrl bio_ctrl = {
.extent_locked = 1,
.sync_io = 1,
};
@@ -3271,7 +3155,7 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end)
ASSERT(PageLocked(page));
ASSERT(PageDirty(page));
clear_page_dirty_for_io(page);
- ret = __extent_writepage(page, &wbc_writepages, &epd);
+ ret = __extent_writepage(page, &wbc_writepages, &bio_ctrl);
ASSERT(ret <= 0);
if (ret < 0) {
found_error = true;
@@ -3281,7 +3165,7 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end)
cur = cur_end + 1;
}
- submit_write_bio(&epd, found_error ? ret : 0);
+ submit_write_bio(&bio_ctrl, found_error ? ret : 0);
wbc_detach_inode(&wbc_writepages);
if (found_error)
@@ -3294,10 +3178,9 @@ int extent_writepages(struct address_space *mapping,
{
struct inode *inode = mapping->host;
int ret = 0;
- struct extent_page_data epd = {
- .bio_ctrl = { 0 },
+ struct btrfs_bio_ctrl bio_ctrl = {
.extent_locked = 0,
- .sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ .sync_io = (wbc->sync_mode == WB_SYNC_ALL),
};
/*
@@ -3305,8 +3188,8 @@ int extent_writepages(struct address_space *mapping,
* protect the write pointer updates.
*/
btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
- ret = extent_write_cache_pages(mapping, wbc, &epd);
- submit_write_bio(&epd, ret);
+ ret = extent_write_cache_pages(mapping, wbc, &bio_ctrl);
+ submit_write_bio(&bio_ctrl, ret);
btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
return ret;
}
@@ -3705,14 +3588,13 @@ static int fiemap_search_slot(struct btrfs_inode *inode, struct btrfs_path *path
static int fiemap_process_hole(struct btrfs_inode *inode,
struct fiemap_extent_info *fieinfo,
struct fiemap_cache *cache,
- struct btrfs_backref_shared_cache *backref_cache,
+ struct extent_state **delalloc_cached_state,
+ struct btrfs_backref_share_check_ctx *backref_ctx,
u64 disk_bytenr, u64 extent_offset,
u64 extent_gen,
- struct ulist *roots, struct ulist *tmp_ulist,
u64 start, u64 end)
{
const u64 i_size = i_size_read(&inode->vfs_inode);
- const u64 ino = btrfs_ino(inode);
u64 cur_offset = start;
u64 last_delalloc_end = 0;
u32 prealloc_flags = FIEMAP_EXTENT_UNWRITTEN;
@@ -3731,6 +3613,7 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
bool delalloc;
delalloc = btrfs_find_delalloc_in_range(inode, cur_offset, end,
+ delalloc_cached_state,
&delalloc_start,
&delalloc_end);
if (!delalloc)
@@ -3752,11 +3635,10 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
if (prealloc_len > 0) {
if (!checked_extent_shared && fieinfo->fi_extents_max) {
- ret = btrfs_is_data_extent_shared(inode->root,
- ino, disk_bytenr,
- extent_gen, roots,
- tmp_ulist,
- backref_cache);
+ ret = btrfs_is_data_extent_shared(inode,
+ disk_bytenr,
+ extent_gen,
+ backref_ctx);
if (ret < 0)
return ret;
else if (ret > 0)
@@ -3802,11 +3684,10 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
}
if (!checked_extent_shared && fieinfo->fi_extents_max) {
- ret = btrfs_is_data_extent_shared(inode->root,
- ino, disk_bytenr,
- extent_gen, roots,
- tmp_ulist,
- backref_cache);
+ ret = btrfs_is_data_extent_shared(inode,
+ disk_bytenr,
+ extent_gen,
+ backref_ctx);
if (ret < 0)
return ret;
else if (ret > 0)
@@ -3903,12 +3784,10 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
{
const u64 ino = btrfs_ino(inode);
struct extent_state *cached_state = NULL;
+ struct extent_state *delalloc_cached_state = NULL;
struct btrfs_path *path;
- struct btrfs_root *root = inode->root;
struct fiemap_cache cache = { 0 };
- struct btrfs_backref_shared_cache *backref_cache;
- struct ulist *roots;
- struct ulist *tmp_ulist;
+ struct btrfs_backref_share_check_ctx *backref_ctx;
u64 last_extent_end;
u64 prev_extent_end;
u64 lockstart;
@@ -3916,17 +3795,15 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
bool stopped = false;
int ret;
- backref_cache = kzalloc(sizeof(*backref_cache), GFP_KERNEL);
+ backref_ctx = btrfs_alloc_backref_share_check_ctx();
path = btrfs_alloc_path();
- roots = ulist_alloc(GFP_KERNEL);
- tmp_ulist = ulist_alloc(GFP_KERNEL);
- if (!backref_cache || !path || !roots || !tmp_ulist) {
+ if (!backref_ctx || !path) {
ret = -ENOMEM;
goto out;
}
- lockstart = round_down(start, root->fs_info->sectorsize);
- lockend = round_up(start + len, root->fs_info->sectorsize);
+ lockstart = round_down(start, inode->root->fs_info->sectorsize);
+ lockend = round_up(start + len, inode->root->fs_info->sectorsize);
prev_extent_end = lockstart;
lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
@@ -3975,13 +3852,15 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
if (extent_end <= lockstart)
goto next_item;
+ backref_ctx->curr_leaf_bytenr = leaf->start;
+
/* We have in implicit hole (NO_HOLES feature enabled). */
if (prev_extent_end < key.offset) {
const u64 range_end = min(key.offset, lockend) - 1;
ret = fiemap_process_hole(inode, fieinfo, &cache,
- backref_cache, 0, 0, 0,
- roots, tmp_ulist,
+ &delalloc_cached_state,
+ backref_ctx, 0, 0, 0,
prev_extent_end, range_end);
if (ret < 0) {
goto out_unlock;
@@ -4021,25 +3900,24 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
extent_len, flags);
} else if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
ret = fiemap_process_hole(inode, fieinfo, &cache,
- backref_cache,
+ &delalloc_cached_state,
+ backref_ctx,
disk_bytenr, extent_offset,
- extent_gen, roots, tmp_ulist,
- key.offset, extent_end - 1);
+ extent_gen, key.offset,
+ extent_end - 1);
} else if (disk_bytenr == 0) {
/* We have an explicit hole. */
ret = fiemap_process_hole(inode, fieinfo, &cache,
- backref_cache, 0, 0, 0,
- roots, tmp_ulist,
+ &delalloc_cached_state,
+ backref_ctx, 0, 0, 0,
key.offset, extent_end - 1);
} else {
/* We have a regular extent. */
if (fieinfo->fi_extents_max) {
- ret = btrfs_is_data_extent_shared(root, ino,
+ ret = btrfs_is_data_extent_shared(inode,
disk_bytenr,
extent_gen,
- roots,
- tmp_ulist,
- backref_cache);
+ backref_ctx);
if (ret < 0)
goto out_unlock;
else if (ret > 0)
@@ -4088,9 +3966,9 @@ check_eof_delalloc:
path = NULL;
if (!stopped && prev_extent_end < lockend) {
- ret = fiemap_process_hole(inode, fieinfo, &cache, backref_cache,
- 0, 0, 0, roots, tmp_ulist,
- prev_extent_end, lockend - 1);
+ ret = fiemap_process_hole(inode, fieinfo, &cache,
+ &delalloc_cached_state, backref_ctx,
+ 0, 0, 0, prev_extent_end, lockend - 1);
if (ret < 0)
goto out_unlock;
prev_extent_end = lockend;
@@ -4107,6 +3985,7 @@ check_eof_delalloc:
delalloc = btrfs_find_delalloc_in_range(inode,
prev_extent_end,
i_size - 1,
+ &delalloc_cached_state,
&delalloc_start,
&delalloc_end);
if (!delalloc)
@@ -4121,10 +4000,9 @@ check_eof_delalloc:
out_unlock:
unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
out:
- kfree(backref_cache);
+ free_extent_state(delalloc_cached_state);
+ btrfs_free_backref_share_ctx(backref_ctx);
btrfs_free_path(path);
- ulist_free(roots);
- ulist_free(tmp_ulist);
return ret;
}
@@ -4266,7 +4144,6 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
eb->start = start;
eb->len = len;
eb->fs_info = fs_info;
- eb->bflags = 0;
init_rwsem(&eb->lock);
btrfs_leak_debug_add_eb(eb);
@@ -4299,7 +4176,6 @@ struct extent_buffer *btrfs_clone_extent_buffer(const struct extent_buffer *src)
*/
set_bit(EXTENT_BUFFER_UNMAPPED, &new->bflags);
- memset(new->pages, 0, sizeof(*new->pages) * num_pages);
ret = btrfs_alloc_page_array(num_pages, new->pages);
if (ret) {
btrfs_release_extent_buffer(new);
@@ -4944,11 +4820,13 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb)
}
static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
- int mirror_num)
+ int mirror_num,
+ struct btrfs_tree_parent_check *check)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
struct extent_io_tree *io_tree;
struct page *page = eb->pages[0];
+ struct extent_state *cached_state = NULL;
struct btrfs_bio_ctrl bio_ctrl = {
.mirror_num = mirror_num,
};
@@ -4956,13 +4834,16 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
ASSERT(!test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags));
ASSERT(PagePrivate(page));
+ ASSERT(check);
io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
if (wait == WAIT_NONE) {
- if (!try_lock_extent(io_tree, eb->start, eb->start + eb->len - 1))
+ if (!try_lock_extent(io_tree, eb->start, eb->start + eb->len - 1,
+ &cached_state))
return -EAGAIN;
} else {
- ret = lock_extent(io_tree, eb->start, eb->start + eb->len - 1, NULL);
+ ret = lock_extent(io_tree, eb->start, eb->start + eb->len - 1,
+ &cached_state);
if (ret < 0)
return ret;
}
@@ -4972,7 +4853,8 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
PageUptodate(page) ||
btrfs_subpage_test_uptodate(fs_info, page, eb->start, eb->len)) {
set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
- unlock_extent(io_tree, eb->start, eb->start + eb->len - 1, NULL);
+ unlock_extent(io_tree, eb->start, eb->start + eb->len - 1,
+ &cached_state);
return ret;
}
@@ -4996,17 +4878,22 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
*/
atomic_dec(&eb->io_pages);
}
+ memcpy(&btrfs_bio(bio_ctrl.bio)->parent_check, check, sizeof(*check));
submit_one_bio(&bio_ctrl);
- if (ret || wait != WAIT_COMPLETE)
+ if (ret || wait != WAIT_COMPLETE) {
+ free_extent_state(cached_state);
return ret;
+ }
- wait_extent_bit(io_tree, eb->start, eb->start + eb->len - 1, EXTENT_LOCKED);
+ wait_extent_bit(io_tree, eb->start, eb->start + eb->len - 1,
+ EXTENT_LOCKED, &cached_state);
if (!test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
ret = -EIO;
return ret;
}
-int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
+int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
+ struct btrfs_tree_parent_check *check)
{
int i;
struct page *page;
@@ -5032,7 +4919,7 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
return -EIO;
if (eb->fs_info->nodesize < PAGE_SIZE)
- return read_extent_buffer_subpage(eb, wait, mirror_num);
+ return read_extent_buffer_subpage(eb, wait, mirror_num, check);
num_pages = num_extent_pages(eb);
for (i = 0; i < num_pages; i++) {
@@ -5109,6 +4996,7 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
}
}
+ memcpy(&btrfs_bio(bio_ctrl.bio)->parent_check, check, sizeof(*check));
submit_one_bio(&bio_ctrl);
if (ret || wait != WAIT_COMPLETE)
@@ -5467,11 +5355,12 @@ static inline void eb_bitmap_offset(const struct extent_buffer *eb,
*page_offset = offset_in_page(offset);
}
-/**
- * extent_buffer_test_bit - determine whether a bit in a bitmap item is set
- * @eb: the extent buffer
- * @start: offset of the bitmap item in the extent buffer
- * @nr: bit number to test
+/*
+ * Determine whether a bit in a bitmap item is set.
+ *
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @nr: bit number to test
*/
int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
unsigned long nr)
@@ -5488,12 +5377,13 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1)));
}
-/**
- * extent_buffer_bitmap_set - set an area of a bitmap
- * @eb: the extent buffer
- * @start: offset of the bitmap item in the extent buffer
- * @pos: bit number of the first bit
- * @len: number of bits to set
+/*
+ * Set an area of a bitmap to 1.
+ *
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @pos: bit number of the first bit
+ * @len: number of bits to set
*/
void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long start,
unsigned long pos, unsigned long len)
@@ -5530,12 +5420,13 @@ void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long star
}
-/**
- * extent_buffer_bitmap_clear - clear an area of a bitmap
- * @eb: the extent buffer
- * @start: offset of the bitmap item in the extent buffer
- * @pos: bit number of the first bit
- * @len: number of bits to clear
+/*
+ * Clear an area of a bitmap.
+ *
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @pos: bit number of the first bit
+ * @len: number of bits to clear
*/
void extent_buffer_bitmap_clear(const struct extent_buffer *eb,
unsigned long start, unsigned long pos,
@@ -5841,6 +5732,11 @@ int try_release_extent_buffer(struct page *page)
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level)
{
+ struct btrfs_tree_parent_check check = {
+ .has_first_key = 0,
+ .level = level,
+ .transid = gen
+ };
struct extent_buffer *eb;
int ret;
@@ -5853,7 +5749,7 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
return;
}
- ret = read_extent_buffer_pages(eb, WAIT_NONE, 0);
+ ret = read_extent_buffer_pages(eb, WAIT_NONE, 0, &check);
if (ret < 0)
free_extent_buffer_stale(eb);
else
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 7929f054dda3..a2c82448b2e0 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -9,6 +9,7 @@
#include <linux/btrfs_tree.h>
#include "compression.h"
#include "ulist.h"
+#include "misc.h"
enum {
EXTENT_BUFFER_UPTODATE,
@@ -29,13 +30,15 @@ enum {
};
/* these are flags for __process_pages_contig */
-#define PAGE_UNLOCK (1 << 0)
-/* Page starts writeback, clear dirty bit and set writeback bit */
-#define PAGE_START_WRITEBACK (1 << 1)
-#define PAGE_END_WRITEBACK (1 << 2)
-#define PAGE_SET_ORDERED (1 << 3)
-#define PAGE_SET_ERROR (1 << 4)
-#define PAGE_LOCK (1 << 5)
+enum {
+ ENUM_BIT(PAGE_UNLOCK),
+ /* Page starts writeback, clear dirty bit and set writeback bit */
+ ENUM_BIT(PAGE_START_WRITEBACK),
+ ENUM_BIT(PAGE_END_WRITEBACK),
+ ENUM_BIT(PAGE_SET_ORDERED),
+ ENUM_BIT(PAGE_SET_ERROR),
+ ENUM_BIT(PAGE_LOCK),
+};
/*
* page->private values. Every page that is controlled by the extent
@@ -63,17 +66,11 @@ struct btrfs_inode;
struct btrfs_fs_info;
struct io_failure_record;
struct extent_io_tree;
+struct btrfs_tree_parent_check;
int __init extent_buffer_init_cachep(void);
void __cold extent_buffer_free_cachep(void);
-typedef void (submit_bio_hook_t)(struct inode *inode, struct bio *bio,
- int mirror_num,
- enum btrfs_compression_type compress_type);
-
-typedef blk_status_t (extent_submit_bio_start_t)(struct inode *inode,
- struct bio *bio, u64 dio_file_offset);
-
#define INLINE_EXTENT_BUFFER_PAGES (BTRFS_MAX_METADATA_BLOCKSIZE / PAGE_SIZE)
struct extent_buffer {
u64 start;
@@ -99,6 +96,39 @@ struct extent_buffer {
};
/*
+ * Get the correct offset inside the page of extent buffer.
+ *
+ * @eb: target extent buffer
+ * @start: offset inside the extent buffer
+ *
+ * Will handle both sectorsize == PAGE_SIZE and sectorsize < PAGE_SIZE cases.
+ */
+static inline size_t get_eb_offset_in_page(const struct extent_buffer *eb,
+ unsigned long offset)
+{
+ /*
+ * For sectorsize == PAGE_SIZE case, eb->start will always be aligned
+ * to PAGE_SIZE, thus adding it won't cause any difference.
+ *
+ * For sectorsize < PAGE_SIZE, we must only read the data that belongs
+ * to the eb, thus we have to take the eb->start into consideration.
+ */
+ return offset_in_page(offset + eb->start);
+}
+
+static inline unsigned long get_eb_page_index(unsigned long offset)
+{
+ /*
+ * For sectorsize == PAGE_SIZE case, plain >> PAGE_SHIFT is enough.
+ *
+ * For sectorsize < PAGE_SIZE case, we only support 64K PAGE_SIZE,
+ * and have ensured that all tree blocks are contained in one page,
+ * thus we always get index == 0.
+ */
+ return offset >> PAGE_SHIFT;
+}
+
+/*
* Structure to record how many bytes and which ranges are set/cleared
*/
struct extent_changeset {
@@ -174,8 +204,8 @@ void free_extent_buffer_stale(struct extent_buffer *eb);
#define WAIT_NONE 0
#define WAIT_COMPLETE 1
#define WAIT_PAGE_LOCK 2
-int read_extent_buffer_pages(struct extent_buffer *eb, int wait,
- int mirror_num);
+int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
+ struct btrfs_tree_parent_check *parent_check);
void wait_on_extent_buffer_writeback(struct extent_buffer *eb);
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level);
@@ -248,7 +278,6 @@ int extent_invalidate_folio(struct extent_io_tree *tree,
int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array);
void end_extent_writepage(struct page *page, int err, u64 start, u64 end);
-int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num);
/*
* When IO fails, either with EIO or csum verification fails, we
@@ -272,9 +301,9 @@ struct io_failure_record {
int num_copies;
};
-int btrfs_repair_one_sector(struct inode *inode, struct btrfs_bio *failed_bbio,
+int btrfs_repair_one_sector(struct btrfs_inode *inode, struct btrfs_bio *failed_bbio,
u32 bio_offset, struct page *page, unsigned int pgoff,
- submit_bio_hook_t *submit_bio_hook);
+ bool submit_buffered);
void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start, u64 end);
int btrfs_clean_io_failure(struct btrfs_inode *inode, u64 start,
struct page *page, unsigned int pg_offset);
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 6092a4eedc92..be94030e1dfb 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -3,6 +3,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include "messages.h"
#include "ctree.h"
#include "volumes.h"
#include "extent_map.h"
@@ -27,12 +28,9 @@ void __cold extent_map_exit(void)
kmem_cache_destroy(extent_map_cache);
}
-/**
- * extent_map_tree_init - initialize extent map tree
- * @tree: tree to initialize
- *
- * Initialize the extent tree @tree. Should be called for each new inode
- * or other user of the extent_map interface.
+/*
+ * Initialize the extent tree @tree. Should be called for each new inode or
+ * other user of the extent_map interface.
*/
void extent_map_tree_init(struct extent_map_tree *tree)
{
@@ -41,12 +39,9 @@ void extent_map_tree_init(struct extent_map_tree *tree)
rwlock_init(&tree->lock);
}
-/**
- * alloc_extent_map - allocate new extent map structure
- *
- * Allocate a new extent_map structure. The new structure is
- * returned with a reference count of one and needs to be
- * freed using free_extent_map()
+/*
+ * Allocate a new extent_map structure. The new structure is returned with a
+ * reference count of one and needs to be freed using free_extent_map()
*/
struct extent_map *alloc_extent_map(void)
{
@@ -61,12 +56,9 @@ struct extent_map *alloc_extent_map(void)
return em;
}
-/**
- * free_extent_map - drop reference count of an extent_map
- * @em: extent map being released
- *
- * Drops the reference out on @em by one and free the structure
- * if the reference count hits zero.
+/*
+ * Drop the reference out on @em by one and free the structure if the reference
+ * count hits zero.
*/
void free_extent_map(struct extent_map *em)
{
@@ -81,7 +73,7 @@ void free_extent_map(struct extent_map *em)
}
}
-/* simple helper to do math around the end of an extent, handling wrap */
+/* Do the math around the end of an extent, handling wrapping. */
static u64 range_end(u64 start, u64 len)
{
if (start + len < start)
@@ -137,8 +129,8 @@ static int tree_insert(struct rb_root_cached *root, struct extent_map *em)
}
/*
- * search through the tree for an extent_map with a given offset. If
- * it can't be found, try to find some neighboring extents
+ * Search through the tree for an extent_map with a given offset. If it can't
+ * be found, try to find some neighboring extents
*/
static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
struct rb_node **prev_or_next_ret)
@@ -190,7 +182,7 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
return NULL;
}
-/* check to see if two extent_map structs are adjacent and safe to merge */
+/* Check to see if two extent_map structs are adjacent and safe to merge. */
static int mergable_maps(struct extent_map *prev, struct extent_map *next)
{
if (test_bit(EXTENT_FLAG_PINNED, &prev->flags))
@@ -288,8 +280,9 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
}
}
-/**
- * unpin_extent_cache - unpin an extent from the cache
+/*
+ * Unpin an extent from the cache.
+ *
* @tree: tree to unpin the extent in
* @start: logical offset in the file
* @len: length of the extent
@@ -392,7 +385,7 @@ static void extent_map_device_clear_bits(struct extent_map *em, unsigned bits)
}
}
-/**
+/*
* Add new extent map to the extent tree
*
* @tree: tree to insert new map in
@@ -451,8 +444,9 @@ __lookup_extent_mapping(struct extent_map_tree *tree,
return em;
}
-/**
- * lookup_extent_mapping - lookup extent_map
+/*
+ * Lookup extent_map that intersects @start + @len range.
+ *
* @tree: tree to lookup in
* @start: byte offset to start the search
* @len: length of the lookup range
@@ -468,8 +462,9 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
return __lookup_extent_mapping(tree, start, len, 1);
}
-/**
- * search_extent_mapping - find a nearby extent map
+/*
+ * Find a nearby extent map intersecting @start + @len (not an exact search).
+ *
* @tree: tree to lookup in
* @start: byte offset to start the search
* @len: length of the lookup range
@@ -485,13 +480,14 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
return __lookup_extent_mapping(tree, start, len, 0);
}
-/**
- * remove_extent_mapping - removes an extent_map from the extent tree
+/*
+ * Remove an extent_map from the extent tree.
+ *
* @tree: extent tree to remove from
* @em: extent map being removed
*
- * Removes @em from @tree. No reference counts are dropped, and no checks
- * are done to see if the range is in use
+ * Remove @em from @tree. No reference counts are dropped, and no checks
+ * are done to see if the range is in use.
*/
void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
{
@@ -523,7 +519,7 @@ void replace_extent_mapping(struct extent_map_tree *tree,
setup_extent_mapping(tree, new, modified);
}
-static struct extent_map *next_extent_map(struct extent_map *em)
+static struct extent_map *next_extent_map(const struct extent_map *em)
{
struct rb_node *next;
@@ -585,8 +581,8 @@ static noinline int merge_extent_mapping(struct extent_map_tree *em_tree,
return add_extent_mapping(em_tree, em, 0);
}
-/**
- * Add extent mapping into em_tree
+/*
+ * Add extent mapping into em_tree.
*
* @fs_info: the filesystem
* @em_tree: extent tree into which we want to insert the extent mapping
@@ -613,6 +609,13 @@ int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info,
int ret;
struct extent_map *em = *em_in;
+ /*
+ * Tree-checker should have rejected any inline extent with non-zero
+ * file offset. Here just do a sanity check.
+ */
+ if (em->block_start == EXTENT_MAP_INLINE)
+ ASSERT(em->start == 0);
+
ret = add_extent_mapping(em_tree, em, 0);
/* it is possible that someone inserted the extent into the tree
* while we had the lock dropped. It is also possible that
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 6bb9fa961a6a..5de73466b2ca 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -9,13 +9,18 @@
#include <linux/highmem.h>
#include <linux/sched/mm.h>
#include <crypto/hash.h>
+#include "messages.h"
#include "misc.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
-#include "volumes.h"
+#include "bio.h"
#include "print-tree.h"
#include "compression.h"
+#include "fs.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "super.h"
#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) * 2) / \
@@ -24,8 +29,8 @@
#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
PAGE_SIZE))
-/**
- * Set inode's size according to filesystem options
+/*
+ * Set inode's size according to filesystem options.
*
* @inode: inode we want to update the disk_i_size for
* @new_i_size: i_size we want to set to, 0 if we use i_size
@@ -64,8 +69,8 @@ void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_siz
spin_unlock(&inode->lock);
}
-/**
- * Mark range within a file as having a new extent inserted
+/*
+ * Mark range within a file as having a new extent inserted.
*
* @inode: inode being modified
* @start: start file offset of the file extent we've inserted
@@ -92,8 +97,8 @@ int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start,
EXTENT_DIRTY);
}
-/**
- * Marks an inode range as not having a backing extent
+/*
+ * Mark an inode range as not having a backing extent.
*
* @inode: inode being modified
* @start: start file offset of the file extent we've inserted
@@ -121,12 +126,26 @@ int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
start + len - 1, EXTENT_DIRTY, NULL);
}
-static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info,
- u16 csum_size)
+static size_t bytes_to_csum_size(const struct btrfs_fs_info *fs_info, u32 bytes)
+{
+ ASSERT(IS_ALIGNED(bytes, fs_info->sectorsize));
+
+ return (bytes >> fs_info->sectorsize_bits) * fs_info->csum_size;
+}
+
+static size_t csum_size_to_bytes(const struct btrfs_fs_info *fs_info, u32 csum_size)
{
- u32 ncsums = (PAGE_SIZE - sizeof(struct btrfs_ordered_sum)) / csum_size;
+ ASSERT(IS_ALIGNED(csum_size, fs_info->csum_size));
- return ncsums * fs_info->sectorsize;
+ return (csum_size / fs_info->csum_size) << fs_info->sectorsize_bits;
+}
+
+static inline u32 max_ordered_sum_bytes(const struct btrfs_fs_info *fs_info)
+{
+ u32 max_csum_size = round_down(PAGE_SIZE - sizeof(struct btrfs_ordered_sum),
+ fs_info->csum_size);
+
+ return csum_size_to_bytes(fs_info, max_csum_size);
}
/*
@@ -135,9 +154,7 @@ static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info,
*/
static int btrfs_ordered_sum_size(struct btrfs_fs_info *fs_info, unsigned long bytes)
{
- int num_sectors = (int)DIV_ROUND_UP(bytes, fs_info->sectorsize);
-
- return sizeof(struct btrfs_ordered_sum) + num_sectors * fs_info->csum_size;
+ return sizeof(struct btrfs_ordered_sum) + bytes_to_csum_size(fs_info, bytes);
}
int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
@@ -254,7 +271,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
/*
* Find checksums for logical bytenr range [disk_bytenr, disk_bytenr + len) and
- * estore the result to @dst.
+ * store the result to @dst.
*
* Return >0 for the number of sectors we found.
* Return 0 for the range [disk_bytenr, disk_bytenr + sectorsize) has no csum
@@ -360,15 +377,15 @@ static int search_file_offset_in_bio(struct bio *bio, struct inode *inode,
return ret;
}
-/**
+/*
* Lookup the checksum for the read bio in csum tree.
*
- * @inode: inode that the bio is for.
- * @bio: bio to look up.
- * @dst: Buffer of size nblocks * btrfs_super_csum_size() used to return
- * checksum (nblocks = bio->bi_iter.bi_size / fs_info->sectorsize). If
- * NULL, the checksum buffer is allocated and returned in
- * btrfs_bio(bio)->csum instead.
+ * @inode: inode that the bio is for.
+ * @bio: bio to look up.
+ * @dst: Buffer of size nblocks * btrfs_super_csum_size() used to return
+ * checksum (nblocks = bio->bi_iter.bi_size / fs_info->sectorsize). If
+ * NULL, the checksum buffer is allocated and returned in
+ * btrfs_bio(bio)->csum instead.
*
* Return: BLK_STS_RESOURCE if allocating memory fails, BLK_STS_OK otherwise.
*/
@@ -510,9 +527,9 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst
return ret;
}
-int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
- struct list_head *list, int search_commit,
- bool nowait)
+int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
+ struct list_head *list, int search_commit,
+ bool nowait)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_key key;
@@ -521,11 +538,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
struct btrfs_ordered_sum *sums;
struct btrfs_csum_item *item;
LIST_HEAD(tmplist);
- unsigned long offset;
int ret;
- size_t size;
- u64 csum_end;
- const u32 csum_size = fs_info->csum_size;
ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
IS_ALIGNED(end + 1, fs_info->sectorsize));
@@ -551,16 +564,33 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
if (ret > 0 && path->slots[0] > 0) {
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
+
+ /*
+ * There are two cases we can hit here for the previous csum
+ * item:
+ *
+ * |<- search range ->|
+ * |<- csum item ->|
+ *
+ * Or
+ * |<- search range ->|
+ * |<- csum item ->|
+ *
+ * Check if the previous csum item covers the leading part of
+ * the search range. If so we have to start from previous csum
+ * item.
+ */
if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
key.type == BTRFS_EXTENT_CSUM_KEY) {
- offset = (start - key.offset) >> fs_info->sectorsize_bits;
- if (offset * csum_size <
+ if (bytes_to_csum_size(fs_info, start - key.offset) <
btrfs_item_size(leaf, path->slots[0] - 1))
path->slots[0]--;
}
}
while (start <= end) {
+ u64 csum_end;
+
leaf = path->nodes[0];
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path);
@@ -580,8 +610,8 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
if (key.offset > start)
start = key.offset;
- size = btrfs_item_size(leaf, path->slots[0]);
- csum_end = key.offset + (size / csum_size) * fs_info->sectorsize;
+ csum_end = key.offset + csum_size_to_bytes(fs_info,
+ btrfs_item_size(leaf, path->slots[0]));
if (csum_end <= start) {
path->slots[0]++;
continue;
@@ -591,8 +621,11 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_csum_item);
while (start < csum_end) {
+ unsigned long offset;
+ size_t size;
+
size = min_t(size_t, csum_end - start,
- max_ordered_sum_bytes(fs_info, csum_size));
+ max_ordered_sum_bytes(fs_info));
sums = kzalloc(btrfs_ordered_sum_size(fs_info, size),
GFP_NOFS);
if (!sums) {
@@ -603,16 +636,14 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
sums->bytenr = start;
sums->len = (int)size;
- offset = (start - key.offset) >> fs_info->sectorsize_bits;
- offset *= csum_size;
- size >>= fs_info->sectorsize_bits;
+ offset = bytes_to_csum_size(fs_info, start - key.offset);
read_extent_buffer(path->nodes[0],
sums->sums,
((unsigned long)item) + offset,
- csum_size * size);
+ bytes_to_csum_size(fs_info, size));
- start += fs_info->sectorsize * size;
+ start += size;
list_add_tail(&sums->list, &tmplist);
}
path->slots[0]++;
@@ -630,8 +661,129 @@ fail:
return ret;
}
-/**
- * Calculate checksums of the data contained inside a bio
+/*
+ * Do the same work as btrfs_lookup_csums_list(), the difference is in how
+ * we return the result.
+ *
+ * This version will set the corresponding bits in @csum_bitmap to represent
+ * that there is a csum found.
+ * Each bit represents a sector. Thus caller should ensure @csum_buf passed
+ * in is large enough to contain all csums.
+ */
+int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
+ u8 *csum_buf, unsigned long *csum_bitmap)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_key key;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_csum_item *item;
+ const u64 orig_start = start;
+ int ret;
+
+ ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
+ IS_ALIGNED(end + 1, fs_info->sectorsize));
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
+ key.type = BTRFS_EXTENT_CSUM_KEY;
+ key.offset = start;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ goto fail;
+ if (ret > 0 && path->slots[0] > 0) {
+ leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
+
+ /*
+ * There are two cases we can hit here for the previous csum
+ * item:
+ *
+ * |<- search range ->|
+ * |<- csum item ->|
+ *
+ * Or
+ * |<- search range ->|
+ * |<- csum item ->|
+ *
+ * Check if the previous csum item covers the leading part of
+ * the search range. If so we have to start from previous csum
+ * item.
+ */
+ if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
+ key.type == BTRFS_EXTENT_CSUM_KEY) {
+ if (bytes_to_csum_size(fs_info, start - key.offset) <
+ btrfs_item_size(leaf, path->slots[0] - 1))
+ path->slots[0]--;
+ }
+ }
+
+ while (start <= end) {
+ u64 csum_end;
+
+ leaf = path->nodes[0];
+ if (path->slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0)
+ goto fail;
+ if (ret > 0)
+ break;
+ leaf = path->nodes[0];
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
+ key.type != BTRFS_EXTENT_CSUM_KEY ||
+ key.offset > end)
+ break;
+
+ if (key.offset > start)
+ start = key.offset;
+
+ csum_end = key.offset + csum_size_to_bytes(fs_info,
+ btrfs_item_size(leaf, path->slots[0]));
+ if (csum_end <= start) {
+ path->slots[0]++;
+ continue;
+ }
+
+ csum_end = min(csum_end, end + 1);
+ item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_csum_item);
+ while (start < csum_end) {
+ unsigned long offset;
+ size_t size;
+ u8 *csum_dest = csum_buf + bytes_to_csum_size(fs_info,
+ start - orig_start);
+
+ size = min_t(size_t, csum_end - start, end + 1 - start);
+
+ offset = bytes_to_csum_size(fs_info, start - key.offset);
+
+ read_extent_buffer(path->nodes[0], csum_dest,
+ ((unsigned long)item) + offset,
+ bytes_to_csum_size(fs_info, size));
+
+ bitmap_set(csum_bitmap,
+ (start - orig_start) >> fs_info->sectorsize_bits,
+ size >> fs_info->sectorsize_bits);
+
+ start += size;
+ }
+ path->slots[0]++;
+ }
+ ret = 0;
+fail:
+ btrfs_free_path(path);
+ return ret;
+}
+
+/*
+ * Calculate checksums of the data contained inside a bio.
*
* @inode: Owner of the data inside the bio
* @bio: Contains the data to be checksummed
@@ -746,15 +898,16 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
}
/*
- * helper function for csum removal, this expects the
- * key to describe the csum pointed to by the path, and it expects
- * the csum to overlap the range [bytenr, len]
+ * Remove one checksum overlapping a range.
*
- * The csum should not be entirely contained in the range and the
- * range should not be entirely contained in the csum.
+ * This expects the key to describe the csum pointed to by the path, and it
+ * expects the csum to overlap the range [bytenr, len]
*
- * This calls btrfs_truncate_item with the correct args based on the
- * overlap, and fixes up the key as required.
+ * The csum should not be entirely contained in the range and the range should
+ * not be entirely contained in the csum.
+ *
+ * This calls btrfs_truncate_item with the correct args based on the overlap,
+ * and fixes up the key as required.
*/
static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
@@ -803,8 +956,7 @@ static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info,
}
/*
- * deletes the csum items from the csum tree for a given
- * range of bytes.
+ * Delete the csum items from the csum tree for a given range of bytes.
*/
int btrfs_del_csums(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 len)
@@ -1209,7 +1361,6 @@ out:
void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
- const bool new_inline,
struct extent_map *em)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
@@ -1261,10 +1412,9 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
*/
em->orig_start = EXTENT_MAP_HOLE;
em->block_len = (u64)-1;
- if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) {
+ em->compress_type = compress_type;
+ if (compress_type != BTRFS_COMPRESS_NONE)
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
- em->compress_type = compress_type;
- }
} else {
btrfs_err(fs_info,
"unknown file extent item type %d, inode %llu, offset %llu, "
diff --git a/fs/btrfs/file-item.h b/fs/btrfs/file-item.h
new file mode 100644
index 000000000000..031225668434
--- /dev/null
+++ b/fs/btrfs/file-item.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_FILE_ITEM_H
+#define BTRFS_FILE_ITEM_H
+
+#include "accessors.h"
+
+#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
+ (offsetof(struct btrfs_file_extent_item, disk_bytenr))
+
+static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info)
+{
+ return BTRFS_MAX_ITEM_SIZE(info) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
+}
+
+/*
+ * Return the number of bytes used by the item on disk, minus the size of any
+ * extent headers. If a file is compressed on disk, this is the compressed
+ * size.
+ */
+static inline u32 btrfs_file_extent_inline_item_len(
+ const struct extent_buffer *eb,
+ int nr)
+{
+ return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
+}
+
+static inline unsigned long btrfs_file_extent_inline_start(
+ const struct btrfs_file_extent_item *e)
+{
+ return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
+}
+
+static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
+{
+ return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize;
+}
+
+int btrfs_del_csums(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 bytenr, u64 len);
+blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst);
+int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid, u64 pos,
+ u64 num_bytes);
+int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 objectid,
+ u64 bytenr, int mod);
+int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_ordered_sum *sums);
+blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
+ u64 offset, bool one_ordered);
+int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
+ struct list_head *list, int search_commit,
+ bool nowait);
+int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
+ u8 *csum_buf, unsigned long *csum_bitmap);
+void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
+ const struct btrfs_path *path,
+ struct btrfs_file_extent_item *fi,
+ struct extent_map *em);
+int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
+ u64 len);
+int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start, u64 len);
+void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_size);
+u64 btrfs_file_extent_end(const struct btrfs_path *path);
+
+#endif
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index d01631d47806..91b00eb2440e 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -30,329 +30,13 @@
#include "delalloc-space.h"
#include "reflink.h"
#include "subpage.h"
-
-static struct kmem_cache *btrfs_inode_defrag_cachep;
-/*
- * when auto defrag is enabled we
- * queue up these defrag structs to remember which
- * inodes need defragging passes
- */
-struct inode_defrag {
- struct rb_node rb_node;
- /* objectid */
- u64 ino;
- /*
- * transid where the defrag was added, we search for
- * extents newer than this
- */
- u64 transid;
-
- /* root objectid */
- u64 root;
-
- /*
- * The extent size threshold for autodefrag.
- *
- * This value is different for compressed/non-compressed extents,
- * thus needs to be passed from higher layer.
- * (aka, inode_should_defrag())
- */
- u32 extent_thresh;
-};
-
-static int __compare_inode_defrag(struct inode_defrag *defrag1,
- struct inode_defrag *defrag2)
-{
- if (defrag1->root > defrag2->root)
- return 1;
- else if (defrag1->root < defrag2->root)
- return -1;
- else if (defrag1->ino > defrag2->ino)
- return 1;
- else if (defrag1->ino < defrag2->ino)
- return -1;
- else
- return 0;
-}
-
-/* pop a record for an inode into the defrag tree. The lock
- * must be held already
- *
- * If you're inserting a record for an older transid than an
- * existing record, the transid already in the tree is lowered
- *
- * If an existing record is found the defrag item you
- * pass in is freed
- */
-static int __btrfs_add_inode_defrag(struct btrfs_inode *inode,
- struct inode_defrag *defrag)
-{
- struct btrfs_fs_info *fs_info = inode->root->fs_info;
- struct inode_defrag *entry;
- struct rb_node **p;
- struct rb_node *parent = NULL;
- int ret;
-
- p = &fs_info->defrag_inodes.rb_node;
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct inode_defrag, rb_node);
-
- ret = __compare_inode_defrag(defrag, entry);
- if (ret < 0)
- p = &parent->rb_left;
- else if (ret > 0)
- p = &parent->rb_right;
- else {
- /* if we're reinserting an entry for
- * an old defrag run, make sure to
- * lower the transid of our existing record
- */
- if (defrag->transid < entry->transid)
- entry->transid = defrag->transid;
- entry->extent_thresh = min(defrag->extent_thresh,
- entry->extent_thresh);
- return -EEXIST;
- }
- }
- set_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags);
- rb_link_node(&defrag->rb_node, parent, p);
- rb_insert_color(&defrag->rb_node, &fs_info->defrag_inodes);
- return 0;
-}
-
-static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info)
-{
- if (!btrfs_test_opt(fs_info, AUTO_DEFRAG))
- return 0;
-
- if (btrfs_fs_closing(fs_info))
- return 0;
-
- return 1;
-}
-
-/*
- * insert a defrag record for this inode if auto defrag is
- * enabled
- */
-int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
- struct btrfs_inode *inode, u32 extent_thresh)
-{
- struct btrfs_root *root = inode->root;
- struct btrfs_fs_info *fs_info = root->fs_info;
- struct inode_defrag *defrag;
- u64 transid;
- int ret;
-
- if (!__need_auto_defrag(fs_info))
- return 0;
-
- if (test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags))
- return 0;
-
- if (trans)
- transid = trans->transid;
- else
- transid = inode->root->last_trans;
-
- defrag = kmem_cache_zalloc(btrfs_inode_defrag_cachep, GFP_NOFS);
- if (!defrag)
- return -ENOMEM;
-
- defrag->ino = btrfs_ino(inode);
- defrag->transid = transid;
- defrag->root = root->root_key.objectid;
- defrag->extent_thresh = extent_thresh;
-
- spin_lock(&fs_info->defrag_inodes_lock);
- if (!test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) {
- /*
- * If we set IN_DEFRAG flag and evict the inode from memory,
- * and then re-read this inode, this new inode doesn't have
- * IN_DEFRAG flag. At the case, we may find the existed defrag.
- */
- ret = __btrfs_add_inode_defrag(inode, defrag);
- if (ret)
- kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
- } else {
- kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
- }
- spin_unlock(&fs_info->defrag_inodes_lock);
- return 0;
-}
-
-/*
- * pick the defragable inode that we want, if it doesn't exist, we will get
- * the next one.
- */
-static struct inode_defrag *
-btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, u64 root, u64 ino)
-{
- struct inode_defrag *entry = NULL;
- struct inode_defrag tmp;
- struct rb_node *p;
- struct rb_node *parent = NULL;
- int ret;
-
- tmp.ino = ino;
- tmp.root = root;
-
- spin_lock(&fs_info->defrag_inodes_lock);
- p = fs_info->defrag_inodes.rb_node;
- while (p) {
- parent = p;
- entry = rb_entry(parent, struct inode_defrag, rb_node);
-
- ret = __compare_inode_defrag(&tmp, entry);
- if (ret < 0)
- p = parent->rb_left;
- else if (ret > 0)
- p = parent->rb_right;
- else
- goto out;
- }
-
- if (parent && __compare_inode_defrag(&tmp, entry) > 0) {
- parent = rb_next(parent);
- if (parent)
- entry = rb_entry(parent, struct inode_defrag, rb_node);
- else
- entry = NULL;
- }
-out:
- if (entry)
- rb_erase(parent, &fs_info->defrag_inodes);
- spin_unlock(&fs_info->defrag_inodes_lock);
- return entry;
-}
-
-void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
-{
- struct inode_defrag *defrag;
- struct rb_node *node;
-
- spin_lock(&fs_info->defrag_inodes_lock);
- node = rb_first(&fs_info->defrag_inodes);
- while (node) {
- rb_erase(node, &fs_info->defrag_inodes);
- defrag = rb_entry(node, struct inode_defrag, rb_node);
- kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
-
- cond_resched_lock(&fs_info->defrag_inodes_lock);
-
- node = rb_first(&fs_info->defrag_inodes);
- }
- spin_unlock(&fs_info->defrag_inodes_lock);
-}
-
-#define BTRFS_DEFRAG_BATCH 1024
-
-static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
- struct inode_defrag *defrag)
-{
- struct btrfs_root *inode_root;
- struct inode *inode;
- struct btrfs_ioctl_defrag_range_args range;
- int ret = 0;
- u64 cur = 0;
-
-again:
- if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
- goto cleanup;
- if (!__need_auto_defrag(fs_info))
- goto cleanup;
-
- /* get the inode */
- inode_root = btrfs_get_fs_root(fs_info, defrag->root, true);
- if (IS_ERR(inode_root)) {
- ret = PTR_ERR(inode_root);
- goto cleanup;
- }
-
- inode = btrfs_iget(fs_info->sb, defrag->ino, inode_root);
- btrfs_put_root(inode_root);
- if (IS_ERR(inode)) {
- ret = PTR_ERR(inode);
- goto cleanup;
- }
-
- if (cur >= i_size_read(inode)) {
- iput(inode);
- goto cleanup;
- }
-
- /* do a chunk of defrag */
- clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
- memset(&range, 0, sizeof(range));
- range.len = (u64)-1;
- range.start = cur;
- range.extent_thresh = defrag->extent_thresh;
-
- sb_start_write(fs_info->sb);
- ret = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
- BTRFS_DEFRAG_BATCH);
- sb_end_write(fs_info->sb);
- iput(inode);
-
- if (ret < 0)
- goto cleanup;
-
- cur = max(cur + fs_info->sectorsize, range.start);
- goto again;
-
-cleanup:
- kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
- return ret;
-}
-
-/*
- * run through the list of inodes in the FS that need
- * defragging
- */
-int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
-{
- struct inode_defrag *defrag;
- u64 first_ino = 0;
- u64 root_objectid = 0;
-
- atomic_inc(&fs_info->defrag_running);
- while (1) {
- /* Pause the auto defragger. */
- if (test_bit(BTRFS_FS_STATE_REMOUNTING,
- &fs_info->fs_state))
- break;
-
- if (!__need_auto_defrag(fs_info))
- break;
-
- /* find an inode to defrag */
- defrag = btrfs_pick_defrag_inode(fs_info, root_objectid,
- first_ino);
- if (!defrag) {
- if (root_objectid || first_ino) {
- root_objectid = 0;
- first_ino = 0;
- continue;
- } else {
- break;
- }
- }
-
- first_ino = defrag->ino + 1;
- root_objectid = defrag->root;
-
- __btrfs_run_defrag_inode(fs_info, defrag);
- }
- atomic_dec(&fs_info->defrag_running);
-
- /*
- * during unmount, we use the transaction_wait queue to
- * wait for the defragger to stop
- */
- wake_up(&fs_info->transaction_wait);
- return 0;
-}
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "file-item.h"
+#include "ioctl.h"
+#include "file.h"
+#include "super.h"
/* simple helper to fault in pages and copy. This should go away
* and be replaced with calls into generic code.
@@ -696,7 +380,10 @@ next_slot:
args->start - extent_offset,
0, false);
ret = btrfs_inc_extent_ref(trans, &ref);
- BUG_ON(ret); /* -ENOMEM */
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ break;
+ }
}
key.offset = args->start;
}
@@ -783,7 +470,10 @@ delete_extent_item:
key.offset - extent_offset, 0,
false);
ret = btrfs_free_extent(trans, &ref);
- BUG_ON(ret); /* -ENOMEM */
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ break;
+ }
args->bytes_found += extent_end - key.offset;
}
@@ -1302,7 +992,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
struct btrfs_ordered_extent *ordered;
if (nowait) {
- if (!try_lock_extent(&inode->io_tree, start_pos, last_pos)) {
+ if (!try_lock_extent(&inode->io_tree, start_pos, last_pos,
+ cached_state)) {
for (i = 0; i < num_pages; i++) {
unlock_page(pages[i]);
put_page(pages[i]);
@@ -1372,6 +1063,7 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_root *root = inode->root;
+ struct extent_state *cached_state = NULL;
u64 lockstart, lockend;
u64 num_bytes;
int ret;
@@ -1388,12 +1080,14 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
num_bytes = lockend - lockstart + 1;
if (nowait) {
- if (!btrfs_try_lock_ordered_range(inode, lockstart, lockend)) {
+ if (!btrfs_try_lock_ordered_range(inode, lockstart, lockend,
+ &cached_state)) {
btrfs_drew_write_unlock(&root->snapshot_lock);
return -EAGAIN;
}
} else {
- btrfs_lock_and_flush_ordered_range(inode, lockstart, lockend, NULL);
+ btrfs_lock_and_flush_ordered_range(inode, lockstart, lockend,
+ &cached_state);
}
ret = can_nocow_extent(&inode->vfs_inode, lockstart, &num_bytes,
NULL, NULL, NULL, nowait, false);
@@ -1402,7 +1096,7 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
else
*write_bytes = min_t(size_t, *write_bytes ,
num_bytes - pos + lockstart);
- unlock_extent(&inode->io_tree, lockstart, lockend, NULL);
+ unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
return ret;
}
@@ -1505,7 +1199,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
if (nowait)
ilock_flags |= BTRFS_ILOCK_TRY;
- ret = btrfs_inode_lock(inode, ilock_flags);
+ ret = btrfs_inode_lock(BTRFS_I(inode), ilock_flags);
if (ret < 0)
return ret;
@@ -1740,7 +1434,7 @@ again:
iocb->ki_pos += num_written;
}
out:
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
return num_written ? num_written : ret;
}
@@ -1780,19 +1474,19 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
ilock_flags |= BTRFS_ILOCK_SHARED;
relock:
- err = btrfs_inode_lock(inode, ilock_flags);
+ err = btrfs_inode_lock(BTRFS_I(inode), ilock_flags);
if (err < 0)
return err;
err = generic_write_checks(iocb, from);
if (err <= 0) {
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
return err;
}
err = btrfs_write_check(iocb, from, err);
if (err < 0) {
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
goto out;
}
@@ -1803,13 +1497,13 @@ relock:
*/
if ((ilock_flags & BTRFS_ILOCK_SHARED) &&
pos + iov_iter_count(from) > i_size_read(inode)) {
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
ilock_flags &= ~BTRFS_ILOCK_SHARED;
goto relock;
}
if (check_direct_IO(fs_info, from, pos)) {
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
goto buffered;
}
@@ -1840,7 +1534,7 @@ relock:
* iocb, and that needs to lock the inode. So unlock it before calling
* iomap_dio_complete() to avoid a deadlock.
*/
- btrfs_inode_unlock(inode, ilock_flags);
+ btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
if (IS_ERR_OR_NULL(dio))
err = PTR_ERR_OR_ZERO(dio);
@@ -1887,8 +1581,8 @@ buffered:
/*
* If we are in a NOWAIT context, then return -EAGAIN to signal the caller
* it must retry the operation in a context where blocking is acceptable,
- * since we currently don't have NOWAIT semantics support for buffered IO
- * and may block there for many reasons (reserving space for example).
+ * because even if we end up not blocking during the buffered IO attempt
+ * below, we will block when flushing and waiting for the IO.
*/
if (iocb->ki_flags & IOCB_NOWAIT) {
err = -EAGAIN;
@@ -1928,7 +1622,7 @@ static ssize_t btrfs_encoded_write(struct kiocb *iocb, struct iov_iter *from,
loff_t count;
ssize_t ret;
- btrfs_inode_lock(inode, 0);
+ btrfs_inode_lock(BTRFS_I(inode), 0);
count = encoded->len;
ret = generic_write_checks_count(iocb, &count);
if (ret == 0 && count != encoded->len) {
@@ -1947,7 +1641,7 @@ static ssize_t btrfs_encoded_write(struct kiocb *iocb, struct iov_iter *from,
ret = btrfs_do_encoded_write(iocb, from, encoded);
out:
- btrfs_inode_unlock(inode, 0);
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
return ret;
}
@@ -2008,10 +1702,12 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
{
struct btrfs_file_private *private = filp->private_data;
- if (private && private->filldir_buf)
+ if (private) {
kfree(private->filldir_buf);
- kfree(private);
- filp->private_data = NULL;
+ free_extent_state(private->llseek_cached_state);
+ kfree(private);
+ filp->private_data = NULL;
+ }
/*
* Set by setattr when we are about to truncate a file from a non-zero
@@ -2118,7 +1814,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (ret)
goto out;
- btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
atomic_inc(&root->log_batch);
@@ -2142,7 +1838,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
*/
ret = start_ordered_ops(inode, start, end);
if (ret) {
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
goto out;
}
@@ -2245,7 +1941,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
* file again, but that will end up using the synchronization
* inside btrfs_sync_log to keep things safe.
*/
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
if (ret == BTRFS_NO_LOG_SYNC) {
ret = btrfs_end_transaction(trans);
@@ -2313,7 +2009,7 @@ out:
out_release_extents:
btrfs_release_log_ctx_extents(&ctx);
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
goto out;
}
@@ -2908,7 +2604,7 @@ static int btrfs_punch_hole(struct file *file, loff_t offset, loff_t len)
bool truncated_block = false;
bool updated_inode = false;
- btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
ret = btrfs_wait_ordered_range(inode, offset, len);
if (ret)
@@ -2956,7 +2652,7 @@ static int btrfs_punch_hole(struct file *file, loff_t offset, loff_t len)
truncated_block = true;
ret = btrfs_truncate_block(BTRFS_I(inode), offset, 0, 0);
if (ret) {
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
return ret;
}
}
@@ -3055,7 +2751,7 @@ out_only_mutex:
ret = ret2;
}
}
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
return ret;
}
@@ -3366,7 +3062,7 @@ static long btrfs_fallocate(struct file *file, int mode,
if (mode & FALLOC_FL_PUNCH_HOLE)
return btrfs_punch_hole(file, offset, len);
- btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) {
ret = inode_newsize_ok(inode, offset + len);
@@ -3416,7 +3112,7 @@ static long btrfs_fallocate(struct file *file, int mode,
if (mode & FALLOC_FL_ZERO_RANGE) {
ret = btrfs_zero_range(inode, offset, len, mode);
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
return ret;
}
@@ -3514,7 +3210,7 @@ out_unlock:
unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
&cached_state);
out:
- btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_MMAP);
extent_changeset_free(data_reserved);
return ret;
}
@@ -3526,117 +3222,106 @@ out:
* looping while it gets adjacent subranges, and merging them together.
*/
static bool find_delalloc_subrange(struct btrfs_inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state,
+ bool *search_io_tree,
u64 *delalloc_start_ret, u64 *delalloc_end_ret)
{
- const u64 len = end + 1 - start;
- struct extent_map_tree *em_tree = &inode->extent_tree;
- struct extent_map *em;
- u64 em_end;
- u64 delalloc_len;
+ u64 len = end + 1 - start;
+ u64 delalloc_len = 0;
+ struct btrfs_ordered_extent *oe;
+ u64 oe_start;
+ u64 oe_end;
/*
* Search the io tree first for EXTENT_DELALLOC. If we find any, it
* means we have delalloc (dirty pages) for which writeback has not
* started yet.
*/
- *delalloc_start_ret = start;
- delalloc_len = count_range_bits(&inode->io_tree, delalloc_start_ret, end,
- len, EXTENT_DELALLOC, 1);
- /*
- * If delalloc was found then *delalloc_start_ret has a sector size
- * aligned value (rounded down).
- */
- if (delalloc_len > 0)
+ if (*search_io_tree) {
+ spin_lock(&inode->lock);
+ if (inode->delalloc_bytes > 0) {
+ spin_unlock(&inode->lock);
+ *delalloc_start_ret = start;
+ delalloc_len = count_range_bits(&inode->io_tree,
+ delalloc_start_ret, end,
+ len, EXTENT_DELALLOC, 1,
+ cached_state);
+ } else {
+ spin_unlock(&inode->lock);
+ }
+ }
+
+ if (delalloc_len > 0) {
+ /*
+ * If delalloc was found then *delalloc_start_ret has a sector size
+ * aligned value (rounded down).
+ */
*delalloc_end_ret = *delalloc_start_ret + delalloc_len - 1;
+ if (*delalloc_start_ret == start) {
+ /* Delalloc for the whole range, nothing more to do. */
+ if (*delalloc_end_ret == end)
+ return true;
+ /* Else trim our search range for ordered extents. */
+ start = *delalloc_end_ret + 1;
+ len = end + 1 - start;
+ }
+ } else {
+ /* No delalloc, future calls don't need to search again. */
+ *search_io_tree = false;
+ }
+
/*
- * Now also check if there's any extent map in the range that does not
- * map to a hole or prealloc extent. We do this because:
+ * Now also check if there's any ordered extent in the range.
+ * We do this because:
*
* 1) When delalloc is flushed, the file range is locked, we clear the
- * EXTENT_DELALLOC bit from the io tree and create an extent map for
- * an allocated extent. So we might just have been called after
- * delalloc is flushed and before the ordered extent completes and
- * inserts the new file extent item in the subvolume's btree;
+ * EXTENT_DELALLOC bit from the io tree and create an extent map and
+ * an ordered extent for the write. So we might just have been called
+ * after delalloc is flushed and before the ordered extent completes
+ * and inserts the new file extent item in the subvolume's btree;
*
- * 2) We may have an extent map created by flushing delalloc for a
+ * 2) We may have an ordered extent created by flushing delalloc for a
* subrange that starts before the subrange we found marked with
* EXTENT_DELALLOC in the io tree.
+ *
+ * We could also use the extent map tree to find such delalloc that is
+ * being flushed, but using the ordered extents tree is more efficient
+ * because it's usually much smaller as ordered extents are removed from
+ * the tree once they complete. With the extent maps, we mau have them
+ * in the extent map tree for a very long time, and they were either
+ * created by previous writes or loaded by read operations.
*/
- read_lock(&em_tree->lock);
- em = lookup_extent_mapping(em_tree, start, len);
- read_unlock(&em_tree->lock);
-
- /* extent_map_end() returns a non-inclusive end offset. */
- em_end = em ? extent_map_end(em) : 0;
-
- /*
- * If we have a hole/prealloc extent map, check the next one if this one
- * ends before our range's end.
- */
- if (em && (em->block_start == EXTENT_MAP_HOLE ||
- test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) && em_end < end) {
- struct extent_map *next_em;
-
- read_lock(&em_tree->lock);
- next_em = lookup_extent_mapping(em_tree, em_end, len - em_end);
- read_unlock(&em_tree->lock);
-
- free_extent_map(em);
- em_end = next_em ? extent_map_end(next_em) : 0;
- em = next_em;
- }
+ oe = btrfs_lookup_first_ordered_range(inode, start, len);
+ if (!oe)
+ return (delalloc_len > 0);
- if (em && (em->block_start == EXTENT_MAP_HOLE ||
- test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
- free_extent_map(em);
- em = NULL;
- }
+ /* The ordered extent may span beyond our search range. */
+ oe_start = max(oe->file_offset, start);
+ oe_end = min(oe->file_offset + oe->num_bytes - 1, end);
- /*
- * No extent map or one for a hole or prealloc extent. Use the delalloc
- * range we found in the io tree if we have one.
- */
- if (!em)
- return (delalloc_len > 0);
+ btrfs_put_ordered_extent(oe);
- /*
- * We don't have any range as EXTENT_DELALLOC in the io tree, so the
- * extent map is the only subrange representing delalloc.
- */
+ /* Don't have unflushed delalloc, return the ordered extent range. */
if (delalloc_len == 0) {
- *delalloc_start_ret = em->start;
- *delalloc_end_ret = min(end, em_end - 1);
- free_extent_map(em);
+ *delalloc_start_ret = oe_start;
+ *delalloc_end_ret = oe_end;
return true;
}
/*
- * The extent map represents a delalloc range that starts before the
- * delalloc range we found in the io tree.
+ * We have both unflushed delalloc (io_tree) and an ordered extent.
+ * If the ranges are adjacent returned a combined range, otherwise
+ * return the leftmost range.
*/
- if (em->start < *delalloc_start_ret) {
- *delalloc_start_ret = em->start;
- /*
- * If the ranges are adjacent, return a combined range.
- * Otherwise return the extent map's range.
- */
- if (em_end < *delalloc_start_ret)
- *delalloc_end_ret = min(end, em_end - 1);
-
- free_extent_map(em);
- return true;
+ if (oe_start < *delalloc_start_ret) {
+ if (oe_end < *delalloc_start_ret)
+ *delalloc_end_ret = oe_end;
+ *delalloc_start_ret = oe_start;
+ } else if (*delalloc_end_ret + 1 == oe_start) {
+ *delalloc_end_ret = oe_end;
}
- /*
- * The extent map starts after the delalloc range we found in the io
- * tree. If it's adjacent, return a combined range, otherwise return
- * the range found in the io tree.
- */
- if (*delalloc_end_ret + 1 == em->start)
- *delalloc_end_ret = min(end, em_end - 1);
-
- free_extent_map(em);
return true;
}
@@ -3648,6 +3333,8 @@ static bool find_delalloc_subrange(struct btrfs_inode *inode, u64 start, u64 end
* sector size aligned.
* @end: The end offset (inclusive value) of the search range.
* It does not need to be sector size aligned.
+ * @cached_state: Extent state record used for speeding up delalloc
+ * searches in the inode's io_tree. Can be NULL.
* @delalloc_start_ret: Output argument, set to the start offset of the
* subrange found with delalloc (may not be sector size
* aligned).
@@ -3659,10 +3346,12 @@ static bool find_delalloc_subrange(struct btrfs_inode *inode, u64 start, u64 end
* end offsets of the subrange.
*/
bool btrfs_find_delalloc_in_range(struct btrfs_inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state,
u64 *delalloc_start_ret, u64 *delalloc_end_ret)
{
u64 cur_offset = round_down(start, inode->root->fs_info->sectorsize);
u64 prev_delalloc_end = 0;
+ bool search_io_tree = true;
bool ret = false;
while (cur_offset < end) {
@@ -3671,6 +3360,7 @@ bool btrfs_find_delalloc_in_range(struct btrfs_inode *inode, u64 start, u64 end,
bool delalloc;
delalloc = find_delalloc_subrange(inode, cur_offset, end,
+ cached_state, &search_io_tree,
&delalloc_start,
&delalloc_end);
if (!delalloc)
@@ -3716,13 +3406,14 @@ bool btrfs_find_delalloc_in_range(struct btrfs_inode *inode, u64 start, u64 end,
* is found, it updates @start_ret with the start of the subrange.
*/
static bool find_desired_extent_in_hole(struct btrfs_inode *inode, int whence,
+ struct extent_state **cached_state,
u64 start, u64 end, u64 *start_ret)
{
u64 delalloc_start;
u64 delalloc_end;
bool delalloc;
- delalloc = btrfs_find_delalloc_in_range(inode, start, end,
+ delalloc = btrfs_find_delalloc_in_range(inode, start, end, cached_state,
&delalloc_start, &delalloc_end);
if (delalloc && whence == SEEK_DATA) {
*start_ret = delalloc_start;
@@ -3765,11 +3456,13 @@ static bool find_desired_extent_in_hole(struct btrfs_inode *inode, int whence,
return false;
}
-static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,
- int whence)
+static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
{
+ struct btrfs_inode *inode = BTRFS_I(file->f_mapping->host);
+ struct btrfs_file_private *private = file->private_data;
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct extent_state *cached_state = NULL;
+ struct extent_state **delalloc_cached_state;
const loff_t i_size = i_size_read(&inode->vfs_inode);
const u64 ino = btrfs_ino(inode);
struct btrfs_root *root = inode->root;
@@ -3794,6 +3487,22 @@ static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,
inode_get_bytes(&inode->vfs_inode) == i_size)
return i_size;
+ if (!private) {
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
+ /*
+ * No worries if memory allocation failed.
+ * The private structure is used only for speeding up multiple
+ * lseek SEEK_HOLE/DATA calls to a file when there's delalloc,
+ * so everything will still be correct.
+ */
+ file->private_data = private;
+ }
+
+ if (private)
+ delalloc_cached_state = &private->llseek_cached_state;
+ else
+ delalloc_cached_state = NULL;
+
/*
* offset can be negative, in this case we start finding DATA/HOLE from
* the very start of the file.
@@ -3871,6 +3580,7 @@ static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,
search_start = offset;
found = find_desired_extent_in_hole(inode, whence,
+ delalloc_cached_state,
search_start,
key.offset - 1,
&found_start);
@@ -3905,6 +3615,7 @@ static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,
search_start = offset;
found = find_desired_extent_in_hole(inode, whence,
+ delalloc_cached_state,
search_start,
extent_end - 1,
&found_start);
@@ -3946,7 +3657,8 @@ static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,
/* We have an implicit hole from the last extent found up to i_size. */
if (!found && start < i_size) {
- found = find_desired_extent_in_hole(inode, whence, start,
+ found = find_desired_extent_in_hole(inode, whence,
+ delalloc_cached_state, start,
i_size - 1, &start);
if (!found)
start = i_size;
@@ -3974,9 +3686,9 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
return generic_file_llseek(file, offset, whence);
case SEEK_DATA:
case SEEK_HOLE:
- btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
- offset = find_desired_extent(BTRFS_I(inode), offset, whence);
- btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
+ offset = find_desired_extent(file, offset, whence);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
break;
}
@@ -4031,7 +3743,7 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos))
return 0;
- btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
again:
/*
* This is similar to what we do for direct IO writes, see the comment
@@ -4080,7 +3792,7 @@ again:
goto again;
}
}
- btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
return ret < 0 ? ret : read;
}
@@ -4117,23 +3829,6 @@ const struct file_operations btrfs_file_operations = {
.remap_file_range = btrfs_remap_file_range,
};
-void __cold btrfs_auto_defrag_exit(void)
-{
- kmem_cache_destroy(btrfs_inode_defrag_cachep);
-}
-
-int __init btrfs_auto_defrag_init(void)
-{
- btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
- sizeof(struct inode_defrag), 0,
- SLAB_MEM_SPREAD,
- NULL);
- if (!btrfs_inode_defrag_cachep)
- return -ENOMEM;
-
- return 0;
-}
-
int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end)
{
int ret;
diff --git a/fs/btrfs/file.h b/fs/btrfs/file.h
new file mode 100644
index 000000000000..82b34fbb295f
--- /dev/null
+++ b/fs/btrfs/file.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_FILE_H
+#define BTRFS_FILE_H
+
+extern const struct file_operations btrfs_file_operations;
+
+int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
+int btrfs_drop_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_inode *inode,
+ struct btrfs_drop_extents_args *args);
+int btrfs_replace_file_extents(struct btrfs_inode *inode,
+ struct btrfs_path *path, const u64 start,
+ const u64 end,
+ struct btrfs_replace_extent_info *extent_info,
+ struct btrfs_trans_handle **trans_out);
+int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *inode, u64 start, u64 end);
+ssize_t btrfs_do_write_iter(struct kiocb *iocb, struct iov_iter *from,
+ const struct btrfs_ioctl_encoded_io_args *encoded);
+int btrfs_release_file(struct inode *inode, struct file *file);
+int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages,
+ size_t num_pages, loff_t pos, size_t write_bytes,
+ struct extent_state **cached, bool noreserve);
+int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
+int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
+ size_t *write_bytes, bool nowait);
+void btrfs_check_nocow_unlock(struct btrfs_inode *inode);
+bool btrfs_find_delalloc_in_range(struct btrfs_inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state,
+ u64 *delalloc_start_ret, u64 *delalloc_end_ret);
+
+#endif
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index f4023651dd68..0d250d052487 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -11,8 +11,10 @@
#include <linux/ratelimit.h>
#include <linux/error-injection.h>
#include <linux/sched/mm.h>
-#include "misc.h"
#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
+#include "misc.h"
#include "free-space-cache.h"
#include "transaction.h"
#include "disk-io.h"
@@ -24,11 +26,18 @@
#include "discard.h"
#include "subpage.h"
#include "inode-item.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "file.h"
+#include "super.h"
#define BITS_PER_BITMAP (PAGE_SIZE * 8UL)
#define MAX_CACHE_BYTES_PER_GIG SZ_64K
#define FORCE_EXTENT_THRESHOLD SZ_1M
+static struct kmem_cache *btrfs_free_space_cachep;
+static struct kmem_cache *btrfs_free_space_bitmap_cachep;
+
struct btrfs_trim_range {
u64 start;
u64 bytes;
@@ -251,7 +260,7 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
}
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
if (ret) {
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
goto out;
}
clear_nlink(inode);
@@ -265,7 +274,7 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
spin_unlock(&block_group->lock);
}
/* One for the lookup ref */
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
key.type = 0;
@@ -1363,8 +1372,8 @@ int btrfs_wait_cache_io(struct btrfs_trans_handle *trans,
path, block_group->start);
}
-/**
- * Write out cached info to an inode
+/*
+ * Write out cached info to an inode.
*
* @root: root the inode belongs to
* @inode: freespace inode we are writing out
@@ -2717,8 +2726,7 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
btrfs_mark_bg_unused(block_group);
} else if (bg_reclaim_threshold &&
reclaimable_unusable >=
- div_factor_fine(block_group->zone_capacity,
- bg_reclaim_threshold)) {
+ mult_perc(block_group->zone_capacity, bg_reclaim_threshold)) {
btrfs_mark_bg_to_reclaim(block_group);
}
@@ -3028,10 +3036,7 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group *block_group)
}
-/**
- * btrfs_is_free_space_trimmed - see if everything is trimmed
- * @block_group: block_group of interest
- *
+/*
* Walk @block_group's free space rb_tree to determine if everything is trimmed.
*/
bool btrfs_is_free_space_trimmed(struct btrfs_block_group *block_group)
@@ -4132,6 +4137,31 @@ out:
return ret;
}
+int __init btrfs_free_space_init(void)
+{
+ btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space",
+ sizeof(struct btrfs_free_space), 0,
+ SLAB_MEM_SPREAD, NULL);
+ if (!btrfs_free_space_cachep)
+ return -ENOMEM;
+
+ btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
+ PAGE_SIZE, PAGE_SIZE,
+ SLAB_MEM_SPREAD, NULL);
+ if (!btrfs_free_space_bitmap_cachep) {
+ kmem_cache_destroy(btrfs_free_space_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void __cold btrfs_free_space_exit(void)
+{
+ kmem_cache_destroy(btrfs_free_space_cachep);
+ kmem_cache_destroy(btrfs_free_space_bitmap_cachep);
+}
+
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
/*
* Use this if you need to make a bitmap or extent entry specifically, it
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index 6d419ba53e95..a855e0483e03 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -43,6 +43,17 @@ static inline bool btrfs_free_space_trimming_bitmap(
return (info->trim_state == BTRFS_TRIM_STATE_TRIMMING);
}
+/*
+ * Deltas are an effective way to populate global statistics. Give macro names
+ * to make it clear what we're doing. An example is discard_extents in
+ * btrfs_free_space_ctl.
+ */
+enum {
+ BTRFS_STAT_CURR,
+ BTRFS_STAT_PREV,
+ BTRFS_STAT_NR_ENTRIES,
+};
+
struct btrfs_free_space_ctl {
spinlock_t tree_lock;
struct rb_root free_space_offset;
@@ -79,6 +90,8 @@ struct btrfs_io_ctl {
int bitmaps;
};
+int __init btrfs_free_space_init(void);
+void __cold btrfs_free_space_exit(void);
struct inode *lookup_free_space_inode(struct btrfs_block_group *block_group,
struct btrfs_path *path);
int create_free_space_inode(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 367bcfcf68f5..c667e878ef1a 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -5,12 +5,17 @@
#include <linux/kernel.h>
#include <linux/sched/mm.h>
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "locking.h"
#include "free-space-tree.h"
#include "transaction.h"
#include "block-group.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group,
@@ -803,7 +808,7 @@ int __remove_from_free_space_tree(struct btrfs_trans_handle *trans,
u32 flags;
int ret;
- if (block_group->needs_free_space) {
+ if (test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &block_group->runtime_flags)) {
ret = __add_block_group_free_space(trans, block_group, path);
if (ret)
return ret;
@@ -996,7 +1001,7 @@ int __add_to_free_space_tree(struct btrfs_trans_handle *trans,
u32 flags;
int ret;
- if (block_group->needs_free_space) {
+ if (test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &block_group->runtime_flags)) {
ret = __add_block_group_free_space(trans, block_group, path);
if (ret)
return ret;
@@ -1299,7 +1304,7 @@ static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
{
int ret;
- block_group->needs_free_space = 0;
+ clear_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &block_group->runtime_flags);
ret = add_new_free_space_info(trans, block_group, path);
if (ret)
@@ -1321,7 +1326,7 @@ int add_block_group_free_space(struct btrfs_trans_handle *trans,
return 0;
mutex_lock(&block_group->free_space_lock);
- if (!block_group->needs_free_space)
+ if (!test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &block_group->runtime_flags))
goto out;
path = btrfs_alloc_path();
@@ -1354,7 +1359,7 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans,
if (!btrfs_fs_compat_ro(trans->fs_info, FREE_SPACE_TREE))
return 0;
- if (block_group->needs_free_space) {
+ if (test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &block_group->runtime_flags)) {
/* We never added this block group to the free space tree. */
return 0;
}
diff --git a/fs/btrfs/fs.c b/fs/btrfs/fs.c
new file mode 100644
index 000000000000..5553e1f8afe8
--- /dev/null
+++ b/fs/btrfs/fs.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "messages.h"
+#include "ctree.h"
+#include "fs.h"
+#include "accessors.h"
+
+void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_incompat_flags(disk_super);
+ if (!(features & flag)) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_incompat_flags(disk_super);
+ if (!(features & flag)) {
+ features |= flag;
+ btrfs_set_super_incompat_flags(disk_super, features);
+ btrfs_info(fs_info,
+ "setting incompat feature flag for %s (0x%llx)",
+ name, flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
+void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_incompat_flags(disk_super);
+ if (features & flag) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_incompat_flags(disk_super);
+ if (features & flag) {
+ features &= ~flag;
+ btrfs_set_super_incompat_flags(disk_super, features);
+ btrfs_info(fs_info,
+ "clearing incompat feature flag for %s (0x%llx)",
+ name, flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
+void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (!(features & flag)) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (!(features & flag)) {
+ features |= flag;
+ btrfs_set_super_compat_ro_flags(disk_super, features);
+ btrfs_info(fs_info,
+ "setting compat-ro feature flag for %s (0x%llx)",
+ name, flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
+void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (features & flag) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (features & flag) {
+ features &= ~flag;
+ btrfs_set_super_compat_ro_flags(disk_super, features);
+ btrfs_info(fs_info,
+ "clearing compat-ro feature flag for %s (0x%llx)",
+ name, flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
new file mode 100644
index 000000000000..a749367e5ae2
--- /dev/null
+++ b/fs/btrfs/fs.h
@@ -0,0 +1,976 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_FS_H
+#define BTRFS_FS_H
+
+#include <linux/fs.h>
+#include <linux/btrfs_tree.h>
+#include <linux/sizes.h>
+#include "extent-io-tree.h"
+#include "extent_map.h"
+#include "async-thread.h"
+#include "block-rsv.h"
+
+#define BTRFS_MAX_EXTENT_SIZE SZ_128M
+
+#define BTRFS_OLDEST_GENERATION 0ULL
+
+#define BTRFS_EMPTY_DIR_SIZE 0
+
+#define BTRFS_DIRTY_METADATA_THRESH SZ_32M
+
+#define BTRFS_SUPER_INFO_OFFSET SZ_64K
+#define BTRFS_SUPER_INFO_SIZE 4096
+static_assert(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE);
+
+/*
+ * The reserved space at the beginning of each device. It covers the primary
+ * super block and leaves space for potential use by other tools like
+ * bootloaders or to lower potential damage of accidental overwrite.
+ */
+#define BTRFS_DEVICE_RANGE_RESERVED (SZ_1M)
+/*
+ * Runtime (in-memory) states of filesystem
+ */
+enum {
+ /* Global indicator of serious filesystem errors */
+ BTRFS_FS_STATE_ERROR,
+ /*
+ * Filesystem is being remounted, allow to skip some operations, like
+ * defrag
+ */
+ BTRFS_FS_STATE_REMOUNTING,
+ /* Filesystem in RO mode */
+ BTRFS_FS_STATE_RO,
+ /* Track if a transaction abort has been reported on this filesystem */
+ BTRFS_FS_STATE_TRANS_ABORTED,
+ /*
+ * Bio operations should be blocked on this filesystem because a source
+ * or target device is being destroyed as part of a device replace
+ */
+ BTRFS_FS_STATE_DEV_REPLACING,
+ /* The btrfs_fs_info created for self-tests */
+ BTRFS_FS_STATE_DUMMY_FS_INFO,
+
+ BTRFS_FS_STATE_NO_CSUMS,
+
+ /* Indicates there was an error cleaning up a log tree. */
+ BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
+
+ BTRFS_FS_STATE_COUNT
+};
+
+enum {
+ BTRFS_FS_CLOSING_START,
+ BTRFS_FS_CLOSING_DONE,
+ BTRFS_FS_LOG_RECOVERING,
+ BTRFS_FS_OPEN,
+ BTRFS_FS_QUOTA_ENABLED,
+ BTRFS_FS_UPDATE_UUID_TREE_GEN,
+ BTRFS_FS_CREATING_FREE_SPACE_TREE,
+ BTRFS_FS_BTREE_ERR,
+ BTRFS_FS_LOG1_ERR,
+ BTRFS_FS_LOG2_ERR,
+ BTRFS_FS_QUOTA_OVERRIDE,
+ /* Used to record internally whether fs has been frozen */
+ BTRFS_FS_FROZEN,
+ /*
+ * Indicate that balance has been set up from the ioctl and is in the
+ * main phase. The fs_info::balance_ctl is initialized.
+ */
+ BTRFS_FS_BALANCE_RUNNING,
+
+ /*
+ * Indicate that relocation of a chunk has started, it's set per chunk
+ * and is toggled between chunks.
+ */
+ BTRFS_FS_RELOC_RUNNING,
+
+ /* Indicate that the cleaner thread is awake and doing something. */
+ BTRFS_FS_CLEANER_RUNNING,
+
+ /*
+ * The checksumming has an optimized version and is considered fast,
+ * so we don't need to offload checksums to workqueues.
+ */
+ BTRFS_FS_CSUM_IMPL_FAST,
+
+ /* Indicate that the discard workqueue can service discards. */
+ BTRFS_FS_DISCARD_RUNNING,
+
+ /* Indicate that we need to cleanup space cache v1 */
+ BTRFS_FS_CLEANUP_SPACE_CACHE_V1,
+
+ /* Indicate that we can't trust the free space tree for caching yet */
+ BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED,
+
+ /* Indicate whether there are any tree modification log users */
+ BTRFS_FS_TREE_MOD_LOG_USERS,
+
+ /* Indicate that we want the transaction kthread to commit right now. */
+ BTRFS_FS_COMMIT_TRANS,
+
+ /* Indicate we have half completed snapshot deletions pending. */
+ BTRFS_FS_UNFINISHED_DROPS,
+
+ /* Indicate we have to finish a zone to do next allocation. */
+ BTRFS_FS_NEED_ZONE_FINISH,
+
+ /* Indicate that we want to commit the transaction. */
+ BTRFS_FS_NEED_TRANS_COMMIT,
+
+#if BITS_PER_LONG == 32
+ /* Indicate if we have error/warn message printed on 32bit systems */
+ BTRFS_FS_32BIT_ERROR,
+ BTRFS_FS_32BIT_WARN,
+#endif
+};
+
+/*
+ * Flags for mount options.
+ *
+ * Note: don't forget to add new options to btrfs_show_options()
+ */
+enum {
+ BTRFS_MOUNT_NODATASUM = (1UL << 0),
+ BTRFS_MOUNT_NODATACOW = (1UL << 1),
+ BTRFS_MOUNT_NOBARRIER = (1UL << 2),
+ BTRFS_MOUNT_SSD = (1UL << 3),
+ BTRFS_MOUNT_DEGRADED = (1UL << 4),
+ BTRFS_MOUNT_COMPRESS = (1UL << 5),
+ BTRFS_MOUNT_NOTREELOG = (1UL << 6),
+ BTRFS_MOUNT_FLUSHONCOMMIT = (1UL << 7),
+ BTRFS_MOUNT_SSD_SPREAD = (1UL << 8),
+ BTRFS_MOUNT_NOSSD = (1UL << 9),
+ BTRFS_MOUNT_DISCARD_SYNC = (1UL << 10),
+ BTRFS_MOUNT_FORCE_COMPRESS = (1UL << 11),
+ BTRFS_MOUNT_SPACE_CACHE = (1UL << 12),
+ BTRFS_MOUNT_CLEAR_CACHE = (1UL << 13),
+ BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED = (1UL << 14),
+ BTRFS_MOUNT_ENOSPC_DEBUG = (1UL << 15),
+ BTRFS_MOUNT_AUTO_DEFRAG = (1UL << 16),
+ BTRFS_MOUNT_USEBACKUPROOT = (1UL << 17),
+ BTRFS_MOUNT_SKIP_BALANCE = (1UL << 18),
+ BTRFS_MOUNT_CHECK_INTEGRITY = (1UL << 19),
+ BTRFS_MOUNT_CHECK_INTEGRITY_DATA = (1UL << 20),
+ BTRFS_MOUNT_PANIC_ON_FATAL_ERROR = (1UL << 21),
+ BTRFS_MOUNT_RESCAN_UUID_TREE = (1UL << 22),
+ BTRFS_MOUNT_FRAGMENT_DATA = (1UL << 23),
+ BTRFS_MOUNT_FRAGMENT_METADATA = (1UL << 24),
+ BTRFS_MOUNT_FREE_SPACE_TREE = (1UL << 25),
+ BTRFS_MOUNT_NOLOGREPLAY = (1UL << 26),
+ BTRFS_MOUNT_REF_VERIFY = (1UL << 27),
+ BTRFS_MOUNT_DISCARD_ASYNC = (1UL << 28),
+ BTRFS_MOUNT_IGNOREBADROOTS = (1UL << 29),
+ BTRFS_MOUNT_IGNOREDATACSUMS = (1UL << 30),
+ BTRFS_MOUNT_NODISCARD = (1UL << 31),
+};
+
+/*
+ * Compat flags that we support. If any incompat flags are set other than the
+ * ones specified below then we will fail to mount
+ */
+#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
+#define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL
+#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL
+
+#define BTRFS_FEATURE_COMPAT_RO_SUPP \
+ (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \
+ BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID | \
+ BTRFS_FEATURE_COMPAT_RO_VERITY | \
+ BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE)
+
+#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
+#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL
+
+#ifdef CONFIG_BTRFS_DEBUG
+/*
+ * Extent tree v2 supported only with CONFIG_BTRFS_DEBUG
+ */
+#define BTRFS_FEATURE_INCOMPAT_SUPP \
+ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
+ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
+ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
+ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
+ BTRFS_FEATURE_INCOMPAT_RAID56 | \
+ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
+ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
+ BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
+ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
+ BTRFS_FEATURE_INCOMPAT_ZONED | \
+ BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2)
+#else
+#define BTRFS_FEATURE_INCOMPAT_SUPP \
+ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
+ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
+ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
+ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
+ BTRFS_FEATURE_INCOMPAT_RAID56 | \
+ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
+ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
+ BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
+ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
+ BTRFS_FEATURE_INCOMPAT_ZONED)
+#endif
+
+#define BTRFS_FEATURE_INCOMPAT_SAFE_SET \
+ (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
+#define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL
+
+#define BTRFS_DEFAULT_COMMIT_INTERVAL (30)
+#define BTRFS_DEFAULT_MAX_INLINE (2048)
+
+struct btrfs_dev_replace {
+ /* See #define above */
+ u64 replace_state;
+ /* Seconds since 1-Jan-1970 */
+ time64_t time_started;
+ /* Seconds since 1-Jan-1970 */
+ time64_t time_stopped;
+ atomic64_t num_write_errors;
+ atomic64_t num_uncorrectable_read_errors;
+
+ u64 cursor_left;
+ u64 committed_cursor_left;
+ u64 cursor_left_last_write_of_item;
+ u64 cursor_right;
+
+ /* See #define above */
+ u64 cont_reading_from_srcdev_mode;
+
+ int is_valid;
+ int item_needs_writeback;
+ struct btrfs_device *srcdev;
+ struct btrfs_device *tgtdev;
+
+ struct mutex lock_finishing_cancel_unmount;
+ struct rw_semaphore rwsem;
+
+ struct btrfs_scrub_progress scrub_progress;
+
+ struct percpu_counter bio_counter;
+ wait_queue_head_t replace_wait;
+};
+
+/*
+ * Free clusters are used to claim free space in relatively large chunks,
+ * allowing us to do less seeky writes. They are used for all metadata
+ * allocations. In ssd_spread mode they are also used for data allocations.
+ */
+struct btrfs_free_cluster {
+ spinlock_t lock;
+ spinlock_t refill_lock;
+ struct rb_root root;
+
+ /* Largest extent in this cluster */
+ u64 max_size;
+
+ /* First extent starting offset */
+ u64 window_start;
+
+ /* We did a full search and couldn't create a cluster */
+ bool fragmented;
+
+ struct btrfs_block_group *block_group;
+ /*
+ * When a cluster is allocated from a block group, we put the cluster
+ * onto a list in the block group so that it can be freed before the
+ * block group is freed.
+ */
+ struct list_head block_group_list;
+};
+
+/* Discard control. */
+/*
+ * Async discard uses multiple lists to differentiate the discard filter
+ * parameters. Index 0 is for completely free block groups where we need to
+ * ensure the entire block group is trimmed without being lossy. Indices
+ * afterwards represent monotonically decreasing discard filter sizes to
+ * prioritize what should be discarded next.
+ */
+#define BTRFS_NR_DISCARD_LISTS 3
+#define BTRFS_DISCARD_INDEX_UNUSED 0
+#define BTRFS_DISCARD_INDEX_START 1
+
+struct btrfs_discard_ctl {
+ struct workqueue_struct *discard_workers;
+ struct delayed_work work;
+ spinlock_t lock;
+ struct btrfs_block_group *block_group;
+ struct list_head discard_list[BTRFS_NR_DISCARD_LISTS];
+ u64 prev_discard;
+ u64 prev_discard_time;
+ atomic_t discardable_extents;
+ atomic64_t discardable_bytes;
+ u64 max_discard_size;
+ u64 delay_ms;
+ u32 iops_limit;
+ u32 kbps_limit;
+ u64 discard_extent_bytes;
+ u64 discard_bitmap_bytes;
+ atomic64_t discard_bytes_saved;
+};
+
+/*
+ * Exclusive operations (device replace, resize, device add/remove, balance)
+ */
+enum btrfs_exclusive_operation {
+ BTRFS_EXCLOP_NONE,
+ BTRFS_EXCLOP_BALANCE_PAUSED,
+ BTRFS_EXCLOP_BALANCE,
+ BTRFS_EXCLOP_DEV_ADD,
+ BTRFS_EXCLOP_DEV_REMOVE,
+ BTRFS_EXCLOP_DEV_REPLACE,
+ BTRFS_EXCLOP_RESIZE,
+ BTRFS_EXCLOP_SWAP_ACTIVATE,
+};
+
+/* Store data about transaction commits, exported via sysfs. */
+struct btrfs_commit_stats {
+ /* Total number of commits */
+ u64 commit_count;
+ /* The maximum commit duration so far in ns */
+ u64 max_commit_dur;
+ /* The last commit duration in ns */
+ u64 last_commit_dur;
+ /* The total commit duration in ns */
+ u64 total_commit_dur;
+};
+
+struct btrfs_fs_info {
+ u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
+ unsigned long flags;
+ struct btrfs_root *tree_root;
+ struct btrfs_root *chunk_root;
+ struct btrfs_root *dev_root;
+ struct btrfs_root *fs_root;
+ struct btrfs_root *quota_root;
+ struct btrfs_root *uuid_root;
+ struct btrfs_root *data_reloc_root;
+ struct btrfs_root *block_group_root;
+
+ /* The log root tree is a directory of all the other log roots */
+ struct btrfs_root *log_root_tree;
+
+ /* The tree that holds the global roots (csum, extent, etc) */
+ rwlock_t global_root_lock;
+ struct rb_root global_root_tree;
+
+ spinlock_t fs_roots_radix_lock;
+ struct radix_tree_root fs_roots_radix;
+
+ /* Block group cache stuff */
+ rwlock_t block_group_cache_lock;
+ struct rb_root_cached block_group_cache_tree;
+
+ /* Keep track of unallocated space */
+ atomic64_t free_chunk_space;
+
+ /* Track ranges which are used by log trees blocks/logged data extents */
+ struct extent_io_tree excluded_extents;
+
+ /* logical->physical extent mapping */
+ struct extent_map_tree mapping_tree;
+
+ /*
+ * Block reservation for extent, checksum, root tree and delayed dir
+ * index item.
+ */
+ struct btrfs_block_rsv global_block_rsv;
+ /* Block reservation for metadata operations */
+ struct btrfs_block_rsv trans_block_rsv;
+ /* Block reservation for chunk tree */
+ struct btrfs_block_rsv chunk_block_rsv;
+ /* Block reservation for delayed operations */
+ struct btrfs_block_rsv delayed_block_rsv;
+ /* Block reservation for delayed refs */
+ struct btrfs_block_rsv delayed_refs_rsv;
+
+ struct btrfs_block_rsv empty_block_rsv;
+
+ u64 generation;
+ u64 last_trans_committed;
+ /*
+ * Generation of the last transaction used for block group relocation
+ * since the filesystem was last mounted (or 0 if none happened yet).
+ * Must be written and read while holding btrfs_fs_info::commit_root_sem.
+ */
+ u64 last_reloc_trans;
+ u64 avg_delayed_ref_runtime;
+
+ /*
+ * This is updated to the current trans every time a full commit is
+ * required instead of the faster short fsync log commits
+ */
+ u64 last_trans_log_full_commit;
+ unsigned long mount_opt;
+
+ unsigned long compress_type:4;
+ unsigned int compress_level;
+ u32 commit_interval;
+ /*
+ * It is a suggestive number, the read side is safe even it gets a
+ * wrong number because we will write out the data into a regular
+ * extent. The write side(mount/remount) is under ->s_umount lock,
+ * so it is also safe.
+ */
+ u64 max_inline;
+
+ struct btrfs_transaction *running_transaction;
+ wait_queue_head_t transaction_throttle;
+ wait_queue_head_t transaction_wait;
+ wait_queue_head_t transaction_blocked_wait;
+ wait_queue_head_t async_submit_wait;
+
+ /*
+ * Used to protect the incompat_flags, compat_flags, compat_ro_flags
+ * when they are updated.
+ *
+ * Because we do not clear the flags for ever, so we needn't use
+ * the lock on the read side.
+ *
+ * We also needn't use the lock when we mount the fs, because
+ * there is no other task which will update the flag.
+ */
+ spinlock_t super_lock;
+ struct btrfs_super_block *super_copy;
+ struct btrfs_super_block *super_for_commit;
+ struct super_block *sb;
+ struct inode *btree_inode;
+ struct mutex tree_log_mutex;
+ struct mutex transaction_kthread_mutex;
+ struct mutex cleaner_mutex;
+ struct mutex chunk_mutex;
+
+ /*
+ * This is taken to make sure we don't set block groups ro after the
+ * free space cache has been allocated on them.
+ */
+ struct mutex ro_block_group_mutex;
+
+ /*
+ * This is used during read/modify/write to make sure no two ios are
+ * trying to mod the same stripe at the same time.
+ */
+ struct btrfs_stripe_hash_table *stripe_hash_table;
+
+ /*
+ * This protects the ordered operations list only while we are
+ * processing all of the entries on it. This way we make sure the
+ * commit code doesn't find the list temporarily empty because another
+ * function happens to be doing non-waiting preflush before jumping
+ * into the main commit.
+ */
+ struct mutex ordered_operations_mutex;
+
+ struct rw_semaphore commit_root_sem;
+
+ struct rw_semaphore cleanup_work_sem;
+
+ struct rw_semaphore subvol_sem;
+
+ spinlock_t trans_lock;
+ /*
+ * The reloc mutex goes with the trans lock, it is taken during commit
+ * to protect us from the relocation code.
+ */
+ struct mutex reloc_mutex;
+
+ struct list_head trans_list;
+ struct list_head dead_roots;
+ struct list_head caching_block_groups;
+
+ spinlock_t delayed_iput_lock;
+ struct list_head delayed_iputs;
+ atomic_t nr_delayed_iputs;
+ wait_queue_head_t delayed_iputs_wait;
+
+ atomic64_t tree_mod_seq;
+
+ /* This protects tree_mod_log and tree_mod_seq_list */
+ rwlock_t tree_mod_log_lock;
+ struct rb_root tree_mod_log;
+ struct list_head tree_mod_seq_list;
+
+ atomic_t async_delalloc_pages;
+
+ /* This is used to protect the following list -- ordered_roots. */
+ spinlock_t ordered_root_lock;
+
+ /*
+ * All fs/file tree roots in which there are data=ordered extents
+ * pending writeback are added into this list.
+ *
+ * These can span multiple transactions and basically include every
+ * dirty data page that isn't from nodatacow.
+ */
+ struct list_head ordered_roots;
+
+ struct mutex delalloc_root_mutex;
+ spinlock_t delalloc_root_lock;
+ /* All fs/file tree roots that have delalloc inodes. */
+ struct list_head delalloc_roots;
+
+ /*
+ * There is a pool of worker threads for checksumming during writes and
+ * a pool for checksumming after reads. This is because readers can
+ * run with FS locks held, and the writers may be waiting for those
+ * locks. We don't want ordering in the pending list to cause
+ * deadlocks, and so the two are serviced separately.
+ *
+ * A third pool does submit_bio to avoid deadlocking with the other two.
+ */
+ struct btrfs_workqueue *workers;
+ struct btrfs_workqueue *hipri_workers;
+ struct btrfs_workqueue *delalloc_workers;
+ struct btrfs_workqueue *flush_workers;
+ struct workqueue_struct *endio_workers;
+ struct workqueue_struct *endio_meta_workers;
+ struct workqueue_struct *rmw_workers;
+ struct workqueue_struct *compressed_write_workers;
+ struct btrfs_workqueue *endio_write_workers;
+ struct btrfs_workqueue *endio_freespace_worker;
+ struct btrfs_workqueue *caching_workers;
+
+ /*
+ * Fixup workers take dirty pages that didn't properly go through the
+ * cow mechanism and make them safe to write. It happens for the
+ * sys_munmap function call path.
+ */
+ struct btrfs_workqueue *fixup_workers;
+ struct btrfs_workqueue *delayed_workers;
+
+ struct task_struct *transaction_kthread;
+ struct task_struct *cleaner_kthread;
+ u32 thread_pool_size;
+
+ struct kobject *space_info_kobj;
+ struct kobject *qgroups_kobj;
+ struct kobject *discard_kobj;
+
+ /* Used to keep from writing metadata until there is a nice batch */
+ struct percpu_counter dirty_metadata_bytes;
+ struct percpu_counter delalloc_bytes;
+ struct percpu_counter ordered_bytes;
+ s32 dirty_metadata_batch;
+ s32 delalloc_batch;
+
+ struct list_head dirty_cowonly_roots;
+
+ struct btrfs_fs_devices *fs_devices;
+
+ /*
+ * The space_info list is effectively read only after initial setup.
+ * It is populated at mount time and cleaned up after all block groups
+ * are removed. RCU is used to protect it.
+ */
+ struct list_head space_info;
+
+ struct btrfs_space_info *data_sinfo;
+
+ struct reloc_control *reloc_ctl;
+
+ /* data_alloc_cluster is only used in ssd_spread mode */
+ struct btrfs_free_cluster data_alloc_cluster;
+
+ /* All metadata allocations go through this cluster. */
+ struct btrfs_free_cluster meta_alloc_cluster;
+
+ /* Auto defrag inodes go here. */
+ spinlock_t defrag_inodes_lock;
+ struct rb_root defrag_inodes;
+ atomic_t defrag_running;
+
+ /* Used to protect avail_{data, metadata, system}_alloc_bits */
+ seqlock_t profiles_lock;
+ /*
+ * These three are in extended format (availability of single chunks is
+ * denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other types are denoted
+ * by corresponding BTRFS_BLOCK_GROUP_* bits)
+ */
+ u64 avail_data_alloc_bits;
+ u64 avail_metadata_alloc_bits;
+ u64 avail_system_alloc_bits;
+
+ /* Balance state */
+ spinlock_t balance_lock;
+ struct mutex balance_mutex;
+ atomic_t balance_pause_req;
+ atomic_t balance_cancel_req;
+ struct btrfs_balance_control *balance_ctl;
+ wait_queue_head_t balance_wait_q;
+
+ /* Cancellation requests for chunk relocation */
+ atomic_t reloc_cancel_req;
+
+ u32 data_chunk_allocations;
+ u32 metadata_ratio;
+
+ void *bdev_holder;
+
+ /* Private scrub information */
+ struct mutex scrub_lock;
+ atomic_t scrubs_running;
+ atomic_t scrub_pause_req;
+ atomic_t scrubs_paused;
+ atomic_t scrub_cancel_req;
+ wait_queue_head_t scrub_pause_wait;
+ /*
+ * The worker pointers are NULL iff the refcount is 0, ie. scrub is not
+ * running.
+ */
+ refcount_t scrub_workers_refcnt;
+ struct workqueue_struct *scrub_workers;
+ struct workqueue_struct *scrub_wr_completion_workers;
+ struct workqueue_struct *scrub_parity_workers;
+ struct btrfs_subpage_info *subpage_info;
+
+ struct btrfs_discard_ctl discard_ctl;
+
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+ u32 check_integrity_print_mask;
+#endif
+ /* Is qgroup tracking in a consistent state? */
+ u64 qgroup_flags;
+
+ /* Holds configuration and tracking. Protected by qgroup_lock. */
+ struct rb_root qgroup_tree;
+ spinlock_t qgroup_lock;
+
+ /*
+ * Used to avoid frequently calling ulist_alloc()/ulist_free()
+ * when doing qgroup accounting, it must be protected by qgroup_lock.
+ */
+ struct ulist *qgroup_ulist;
+
+ /*
+ * Protect user change for quota operations. If a transaction is needed,
+ * it must be started before locking this lock.
+ */
+ struct mutex qgroup_ioctl_lock;
+
+ /* List of dirty qgroups to be written at next commit. */
+ struct list_head dirty_qgroups;
+
+ /* Used by qgroup for an efficient tree traversal. */
+ u64 qgroup_seq;
+
+ /* Qgroup rescan items. */
+ /* Protects the progress item */
+ struct mutex qgroup_rescan_lock;
+ struct btrfs_key qgroup_rescan_progress;
+ struct btrfs_workqueue *qgroup_rescan_workers;
+ struct completion qgroup_rescan_completion;
+ struct btrfs_work qgroup_rescan_work;
+ /* Protected by qgroup_rescan_lock */
+ bool qgroup_rescan_running;
+ u8 qgroup_drop_subtree_thres;
+
+ /* Filesystem state */
+ unsigned long fs_state;
+
+ struct btrfs_delayed_root *delayed_root;
+
+ /* Extent buffer radix tree */
+ spinlock_t buffer_lock;
+ /* Entries are eb->start / sectorsize */
+ struct radix_tree_root buffer_radix;
+
+ /* Next backup root to be overwritten */
+ int backup_root_index;
+
+ /* Device replace state */
+ struct btrfs_dev_replace dev_replace;
+
+ struct semaphore uuid_tree_rescan_sem;
+
+ /* Used to reclaim the metadata space in the background. */
+ struct work_struct async_reclaim_work;
+ struct work_struct async_data_reclaim_work;
+ struct work_struct preempt_reclaim_work;
+
+ /* Reclaim partially filled block groups in the background */
+ struct work_struct reclaim_bgs_work;
+ struct list_head reclaim_bgs;
+ int bg_reclaim_threshold;
+
+ spinlock_t unused_bgs_lock;
+ struct list_head unused_bgs;
+ struct mutex unused_bg_unpin_mutex;
+ /* Protect block groups that are going to be deleted */
+ struct mutex reclaim_bgs_lock;
+
+ /* Cached block sizes */
+ u32 nodesize;
+ u32 sectorsize;
+ /* ilog2 of sectorsize, use to avoid 64bit division */
+ u32 sectorsize_bits;
+ u32 csum_size;
+ u32 csums_per_leaf;
+ u32 stripesize;
+
+ /*
+ * Maximum size of an extent. BTRFS_MAX_EXTENT_SIZE on regular
+ * filesystem, on zoned it depends on the device constraints.
+ */
+ u64 max_extent_size;
+
+ /* Block groups and devices containing active swapfiles. */
+ spinlock_t swapfile_pins_lock;
+ struct rb_root swapfile_pins;
+
+ struct crypto_shash *csum_shash;
+
+ /* Type of exclusive operation running, protected by super_lock */
+ enum btrfs_exclusive_operation exclusive_operation;
+
+ /*
+ * Zone size > 0 when in ZONED mode, otherwise it's used for a check
+ * if the mode is enabled
+ */
+ u64 zone_size;
+
+ /* Max size to emit ZONE_APPEND write command */
+ u64 max_zone_append_size;
+ struct mutex zoned_meta_io_lock;
+ spinlock_t treelog_bg_lock;
+ u64 treelog_bg;
+
+ /*
+ * Start of the dedicated data relocation block group, protected by
+ * relocation_bg_lock.
+ */
+ spinlock_t relocation_bg_lock;
+ u64 data_reloc_bg;
+ struct mutex zoned_data_reloc_io_lock;
+
+ u64 nr_global_roots;
+
+ spinlock_t zone_active_bgs_lock;
+ struct list_head zone_active_bgs;
+
+ /* Updates are not protected by any lock */
+ struct btrfs_commit_stats commit_stats;
+
+ /*
+ * Last generation where we dropped a non-relocation root.
+ * Use btrfs_set_last_root_drop_gen() and btrfs_get_last_root_drop_gen()
+ * to change it and to read it, respectively.
+ */
+ u64 last_root_drop_gen;
+
+ /*
+ * Annotations for transaction events (structures are empty when
+ * compiled without lockdep).
+ */
+ struct lockdep_map btrfs_trans_num_writers_map;
+ struct lockdep_map btrfs_trans_num_extwriters_map;
+ struct lockdep_map btrfs_state_change_map[4];
+ struct lockdep_map btrfs_trans_pending_ordered_map;
+ struct lockdep_map btrfs_ordered_extent_map;
+
+#ifdef CONFIG_BTRFS_FS_REF_VERIFY
+ spinlock_t ref_verify_lock;
+ struct rb_root block_tree;
+#endif
+
+#ifdef CONFIG_BTRFS_DEBUG
+ struct kobject *debug_kobj;
+ struct list_head allocated_roots;
+
+ spinlock_t eb_leak_lock;
+ struct list_head allocated_ebs;
+#endif
+};
+
+static inline void btrfs_set_last_root_drop_gen(struct btrfs_fs_info *fs_info,
+ u64 gen)
+{
+ WRITE_ONCE(fs_info->last_root_drop_gen, gen);
+}
+
+static inline u64 btrfs_get_last_root_drop_gen(const struct btrfs_fs_info *fs_info)
+{
+ return READ_ONCE(fs_info->last_root_drop_gen);
+}
+
+/*
+ * Take the number of bytes to be checksummed and figure out how many leaves
+ * it would require to store the csums for that many bytes.
+ */
+static inline u64 btrfs_csum_bytes_to_leaves(
+ const struct btrfs_fs_info *fs_info, u64 csum_bytes)
+{
+ const u64 num_csums = csum_bytes >> fs_info->sectorsize_bits;
+
+ return DIV_ROUND_UP_ULL(num_csums, fs_info->csums_per_leaf);
+}
+
+/*
+ * Use this if we would be adding new items, as we could split nodes as we cow
+ * down the tree.
+ */
+static inline u64 btrfs_calc_insert_metadata_size(struct btrfs_fs_info *fs_info,
+ unsigned num_items)
+{
+ return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items;
+}
+
+/*
+ * Doing a truncate or a modification won't result in new nodes or leaves, just
+ * what we need for COW.
+ */
+static inline u64 btrfs_calc_metadata_size(struct btrfs_fs_info *fs_info,
+ unsigned num_items)
+{
+ return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;
+}
+
+#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \
+ sizeof(struct btrfs_item))
+
+static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info)
+{
+ return fs_info->zone_size > 0;
+}
+
+/*
+ * Count how many fs_info->max_extent_size cover the @size
+ */
+static inline u32 count_max_extents(struct btrfs_fs_info *fs_info, u64 size)
+{
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+ if (!fs_info)
+ return div_u64(size + BTRFS_MAX_EXTENT_SIZE - 1, BTRFS_MAX_EXTENT_SIZE);
+#endif
+
+ return div_u64(size + fs_info->max_extent_size - 1, fs_info->max_extent_size);
+}
+
+bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
+ enum btrfs_exclusive_operation type);
+bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
+ enum btrfs_exclusive_operation type);
+void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
+void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
+void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
+ enum btrfs_exclusive_operation op);
+
+/* Compatibility and incompatibility defines */
+void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name);
+void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name);
+void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name);
+void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
+ const char *name);
+
+#define __btrfs_fs_incompat(fs_info, flags) \
+ (!!(btrfs_super_incompat_flags((fs_info)->super_copy) & (flags)))
+
+#define __btrfs_fs_compat_ro(fs_info, flags) \
+ (!!(btrfs_super_compat_ro_flags((fs_info)->super_copy) & (flags)))
+
+#define btrfs_set_fs_incompat(__fs_info, opt) \
+ __btrfs_set_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, #opt)
+
+#define btrfs_clear_fs_incompat(__fs_info, opt) \
+ __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, #opt)
+
+#define btrfs_fs_incompat(fs_info, opt) \
+ __btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
+
+#define btrfs_set_fs_compat_ro(__fs_info, opt) \
+ __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, #opt)
+
+#define btrfs_clear_fs_compat_ro(__fs_info, opt) \
+ __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, #opt)
+
+#define btrfs_fs_compat_ro(fs_info, opt) \
+ __btrfs_fs_compat_ro((fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+
+#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
+#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
+#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt)
+#define btrfs_test_opt(fs_info, opt) ((fs_info)->mount_opt & \
+ BTRFS_MOUNT_##opt)
+
+#define btrfs_set_and_info(fs_info, opt, fmt, args...) \
+do { \
+ if (!btrfs_test_opt(fs_info, opt)) \
+ btrfs_info(fs_info, fmt, ##args); \
+ btrfs_set_opt(fs_info->mount_opt, opt); \
+} while (0)
+
+#define btrfs_clear_and_info(fs_info, opt, fmt, args...) \
+do { \
+ if (btrfs_test_opt(fs_info, opt)) \
+ btrfs_info(fs_info, fmt, ##args); \
+ btrfs_clear_opt(fs_info->mount_opt, opt); \
+} while (0)
+
+static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
+{
+ /* Do it this way so we only ever do one test_bit in the normal case. */
+ if (test_bit(BTRFS_FS_CLOSING_START, &fs_info->flags)) {
+ if (test_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags))
+ return 2;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * If we remount the fs to be R/O or umount the fs, the cleaner needn't do
+ * anything except sleeping. This function is used to check the status of
+ * the fs.
+ * We check for BTRFS_FS_STATE_RO to avoid races with a concurrent remount,
+ * since setting and checking for SB_RDONLY in the superblock's flags is not
+ * atomic.
+ */
+static inline int btrfs_need_cleaner_sleep(struct btrfs_fs_info *fs_info)
+{
+ return test_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state) ||
+ btrfs_fs_closing(fs_info);
+}
+
+static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
+{
+ clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
+}
+
+#define BTRFS_FS_ERROR(fs_info) (unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
+ &(fs_info)->fs_state)))
+#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info) \
+ (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR, \
+ &(fs_info)->fs_state)))
+
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+
+#define EXPORT_FOR_TESTS
+
+static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)
+{
+ return test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
+}
+
+void btrfs_test_destroy_inode(struct inode *inode);
+
+#else
+
+#define EXPORT_FOR_TESTS static
+
+static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index 0eeb5ea87894..b65c45b5d681 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -4,14 +4,20 @@
*/
#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
#include "inode-item.h"
#include "disk-io.h"
#include "transaction.h"
#include "print-tree.h"
+#include "space-info.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "file-item.h"
struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
- int slot, const char *name,
- int name_len)
+ int slot,
+ const struct fscrypt_str *name)
{
struct btrfs_inode_ref *ref;
unsigned long ptr;
@@ -27,9 +33,10 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
len = btrfs_inode_ref_name_len(leaf, ref);
name_ptr = (unsigned long)(ref + 1);
cur_offset += len + sizeof(*ref);
- if (len != name_len)
+ if (len != name->len)
continue;
- if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
+ if (memcmp_extent_buffer(leaf, name->name, name_ptr,
+ name->len) == 0)
return ref;
}
return NULL;
@@ -37,7 +44,7 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
struct extent_buffer *leaf, int slot, u64 ref_objectid,
- const char *name, int name_len)
+ const struct fscrypt_str *name)
{
struct btrfs_inode_extref *extref;
unsigned long ptr;
@@ -60,9 +67,10 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
name_ptr = (unsigned long)(&extref->name);
ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
- if (ref_name_len == name_len &&
+ if (ref_name_len == name->len &&
btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
- (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0))
+ (memcmp_extent_buffer(leaf, name->name, name_ptr,
+ name->len) == 0))
return extref;
cur_offset += ref_name_len + sizeof(*extref);
@@ -75,7 +83,7 @@ struct btrfs_inode_extref *
btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid, int ins_len,
int cow)
{
@@ -84,7 +92,7 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
key.objectid = inode_objectid;
key.type = BTRFS_INODE_EXTREF_KEY;
- key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+ key.offset = btrfs_extref_hash(ref_objectid, name->name, name->len);
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
if (ret < 0)
@@ -92,13 +100,13 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
if (ret > 0)
return NULL;
return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
- ref_objectid, name, name_len);
+ ref_objectid, name);
}
static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid,
u64 *index)
{
@@ -107,14 +115,14 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_inode_extref *extref;
struct extent_buffer *leaf;
int ret;
- int del_len = name_len + sizeof(*extref);
+ int del_len = name->len + sizeof(*extref);
unsigned long ptr;
unsigned long item_start;
u32 item_size;
key.objectid = inode_objectid;
key.type = BTRFS_INODE_EXTREF_KEY;
- key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+ key.offset = btrfs_extref_hash(ref_objectid, name->name, name->len);
path = btrfs_alloc_path();
if (!path)
@@ -132,7 +140,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
* readonly.
*/
extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
- ref_objectid, name, name_len);
+ ref_objectid, name);
if (!extref) {
btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
ret = -EROFS;
@@ -168,8 +176,7 @@ out:
}
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- const char *name, int name_len,
+ struct btrfs_root *root, const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid, u64 *index)
{
struct btrfs_path *path;
@@ -182,7 +189,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
u32 sub_item_len;
int ret;
int search_ext_refs = 0;
- int del_len = name_len + sizeof(*ref);
+ int del_len = name->len + sizeof(*ref);
key.objectid = inode_objectid;
key.offset = ref_objectid;
@@ -201,8 +208,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
goto out;
}
- ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name,
- name_len);
+ ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name);
if (!ref) {
ret = -ENOENT;
search_ext_refs = 1;
@@ -219,7 +225,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
goto out;
}
ptr = (unsigned long)ref;
- sub_item_len = name_len + sizeof(*ref);
+ sub_item_len = name->len + sizeof(*ref);
item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
item_size - (ptr + sub_item_len - item_start));
@@ -233,7 +239,7 @@ out:
* name in our ref array. Find and remove the extended
* inode ref then.
*/
- return btrfs_del_inode_extref(trans, root, name, name_len,
+ return btrfs_del_inode_extref(trans, root, name,
inode_objectid, ref_objectid, index);
}
@@ -247,12 +253,13 @@ out:
*/
static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
- u64 inode_objectid, u64 ref_objectid, u64 index)
+ const struct fscrypt_str *name,
+ u64 inode_objectid, u64 ref_objectid,
+ u64 index)
{
struct btrfs_inode_extref *extref;
int ret;
- int ins_len = name_len + sizeof(*extref);
+ int ins_len = name->len + sizeof(*extref);
unsigned long ptr;
struct btrfs_path *path;
struct btrfs_key key;
@@ -260,7 +267,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
key.objectid = inode_objectid;
key.type = BTRFS_INODE_EXTREF_KEY;
- key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+ key.offset = btrfs_extref_hash(ref_objectid, name->name, name->len);
path = btrfs_alloc_path();
if (!path)
@@ -272,7 +279,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
if (btrfs_find_name_in_ext_backref(path->nodes[0],
path->slots[0],
ref_objectid,
- name, name_len))
+ name))
goto out;
btrfs_extend_item(path, ins_len);
@@ -286,12 +293,12 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
ptr += btrfs_item_size(leaf, path->slots[0]) - ins_len;
extref = (struct btrfs_inode_extref *)ptr;
- btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
+ btrfs_set_inode_extref_name_len(path->nodes[0], extref, name->len);
btrfs_set_inode_extref_index(path->nodes[0], extref, index);
btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
ptr = (unsigned long)&extref->name;
- write_extent_buffer(path->nodes[0], name, ptr, name_len);
+ write_extent_buffer(path->nodes[0], name->name, ptr, name->len);
btrfs_mark_buffer_dirty(path->nodes[0]);
out:
@@ -301,8 +308,7 @@ out:
/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- const char *name, int name_len,
+ struct btrfs_root *root, const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid, u64 index)
{
struct btrfs_fs_info *fs_info = root->fs_info;
@@ -311,7 +317,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_inode_ref *ref;
unsigned long ptr;
int ret;
- int ins_len = name_len + sizeof(*ref);
+ int ins_len = name->len + sizeof(*ref);
key.objectid = inode_objectid;
key.offset = ref_objectid;
@@ -327,7 +333,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
if (ret == -EEXIST) {
u32 old_size;
ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
- name, name_len);
+ name);
if (ref)
goto out;
@@ -336,7 +342,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_ref);
ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
- btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
+ btrfs_set_inode_ref_name_len(path->nodes[0], ref, name->len);
btrfs_set_inode_ref_index(path->nodes[0], ref, index);
ptr = (unsigned long)(ref + 1);
ret = 0;
@@ -344,7 +350,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
if (ret == -EOVERFLOW) {
if (btrfs_find_name_in_backref(path->nodes[0],
path->slots[0],
- name, name_len))
+ name))
ret = -EEXIST;
else
ret = -EMLINK;
@@ -353,11 +359,11 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
} else {
ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_ref);
- btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
+ btrfs_set_inode_ref_name_len(path->nodes[0], ref, name->len);
btrfs_set_inode_ref_index(path->nodes[0], ref, index);
ptr = (unsigned long)(ref + 1);
}
- write_extent_buffer(path->nodes[0], name, ptr, name_len);
+ write_extent_buffer(path->nodes[0], name->name, ptr, name->len);
btrfs_mark_buffer_dirty(path->nodes[0]);
out:
@@ -370,7 +376,6 @@ out:
if (btrfs_super_incompat_flags(disk_super)
& BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
ret = btrfs_insert_inode_extref(trans, root, name,
- name_len,
inode_objectid,
ref_objectid, index);
}
diff --git a/fs/btrfs/inode-item.h b/fs/btrfs/inode-item.h
index a8fc16d0147f..b80aeb715701 100644
--- a/fs/btrfs/inode-item.h
+++ b/fs/btrfs/inode-item.h
@@ -64,33 +64,31 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_truncate_control *control);
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- const char *name, int name_len,
+ struct btrfs_root *root, const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid, u64 index);
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- const char *name, int name_len,
- u64 inode_objectid, u64 ref_objectid, u64 *index);
+ struct btrfs_root *root, const struct fscrypt_str *name,
+ u64 inode_objectid, u64 ref_objectid, u64 *index);
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 objectid);
-int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path,
+int btrfs_lookup_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *location, int mod);
struct btrfs_inode_extref *btrfs_lookup_inode_extref(
struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
u64 inode_objectid, u64 ref_objectid, int ins_len,
int cow);
struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
- int slot, const char *name,
- int name_len);
+ int slot,
+ const struct fscrypt_str *name);
struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
struct extent_buffer *leaf, int slot, u64 ref_objectid,
- const char *name, int name_len);
+ const struct fscrypt_str *name);
#endif
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0e516aefbf51..8bcad9940154 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -43,7 +43,7 @@
#include "ordered-data.h"
#include "xattr.h"
#include "tree-log.h"
-#include "volumes.h"
+#include "bio.h"
#include "compression.h"
#include "locking.h"
#include "free-space-cache.h"
@@ -55,6 +55,21 @@
#include "zoned.h"
#include "subpage.h"
#include "inode-item.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "defrag.h"
+#include "dir-item.h"
+#include "file-item.h"
+#include "uuid-tree.h"
+#include "ioctl.h"
+#include "file.h"
+#include "acl.h"
+#include "relocation.h"
+#include "verity.h"
+#include "super.h"
+#include "orphan.h"
struct btrfs_iget_args {
u64 ino;
@@ -69,7 +84,7 @@ struct btrfs_dio_data {
};
struct btrfs_dio_private {
- struct inode *inode;
+ struct btrfs_inode *inode;
/*
* Since DIO can use anonymous page, we cannot use page_offset() to
@@ -107,13 +122,9 @@ static const struct address_space_operations btrfs_aops;
static const struct file_operations btrfs_dir_file_operations;
static struct kmem_cache *btrfs_inode_cachep;
-struct kmem_cache *btrfs_trans_handle_cachep;
-struct kmem_cache *btrfs_path_cachep;
-struct kmem_cache *btrfs_free_space_cachep;
-struct kmem_cache *btrfs_free_space_bitmap_cachep;
static int btrfs_setsize(struct inode *inode, struct iattr *attr);
-static int btrfs_truncate(struct inode *inode, bool skip_writeback);
+static int btrfs_truncate(struct btrfs_inode *inode, bool skip_writeback);
static noinline int cow_file_range(struct btrfs_inode *inode,
struct page *locked_page,
u64 start, u64 end, int *page_started,
@@ -125,6 +136,32 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
u64 ram_bytes, int compress_type,
int type);
+static void __cold btrfs_print_data_csum_error(struct btrfs_inode *inode,
+ u64 logical_start, u8 *csum, u8 *csum_expected, int mirror_num)
+{
+ struct btrfs_root *root = inode->root;
+ const u32 csum_size = root->fs_info->csum_size;
+
+ /* Output without objectid, which is more meaningful */
+ if (root->root_key.objectid >= BTRFS_LAST_FREE_OBJECTID) {
+ btrfs_warn_rl(root->fs_info,
+"csum failed root %lld ino %lld off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
+ root->root_key.objectid, btrfs_ino(inode),
+ logical_start,
+ CSUM_FMT_VALUE(csum_size, csum),
+ CSUM_FMT_VALUE(csum_size, csum_expected),
+ mirror_num);
+ } else {
+ btrfs_warn_rl(root->fs_info,
+"csum failed root %llu ino %llu off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
+ root->root_key.objectid, btrfs_ino(inode),
+ logical_start,
+ CSUM_FMT_VALUE(csum_size, csum),
+ CSUM_FMT_VALUE(csum_size, csum_expected),
+ mirror_num);
+ }
+}
+
/*
* btrfs_inode_lock - lock inode i_rwsem based on arguments passed
*
@@ -135,27 +172,27 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
* return -EAGAIN
* BTRFS_ILOCK_MMAP - acquire a write lock on the i_mmap_lock
*/
-int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags)
+int btrfs_inode_lock(struct btrfs_inode *inode, unsigned int ilock_flags)
{
if (ilock_flags & BTRFS_ILOCK_SHARED) {
if (ilock_flags & BTRFS_ILOCK_TRY) {
- if (!inode_trylock_shared(inode))
+ if (!inode_trylock_shared(&inode->vfs_inode))
return -EAGAIN;
else
return 0;
}
- inode_lock_shared(inode);
+ inode_lock_shared(&inode->vfs_inode);
} else {
if (ilock_flags & BTRFS_ILOCK_TRY) {
- if (!inode_trylock(inode))
+ if (!inode_trylock(&inode->vfs_inode))
return -EAGAIN;
else
return 0;
}
- inode_lock(inode);
+ inode_lock(&inode->vfs_inode);
}
if (ilock_flags & BTRFS_ILOCK_MMAP)
- down_write(&BTRFS_I(inode)->i_mmap_lock);
+ down_write(&inode->i_mmap_lock);
return 0;
}
@@ -165,14 +202,14 @@ int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags)
* ilock_flags should contain the same bits set as passed to btrfs_inode_lock()
* to decide whether the lock acquired is shared or exclusive.
*/
-void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags)
+void btrfs_inode_unlock(struct btrfs_inode *inode, unsigned int ilock_flags)
{
if (ilock_flags & BTRFS_ILOCK_MMAP)
- up_write(&BTRFS_I(inode)->i_mmap_lock);
+ up_write(&inode->i_mmap_lock);
if (ilock_flags & BTRFS_ILOCK_SHARED)
- inode_unlock_shared(inode);
+ inode_unlock_shared(&inode->vfs_inode);
else
- inode_unlock(inode);
+ inode_unlock(&inode->vfs_inode);
}
/*
@@ -249,7 +286,7 @@ static inline void btrfs_cleanup_ordered_extents(struct btrfs_inode *inode,
return btrfs_mark_ordered_io_finished(inode, NULL, offset, bytes, false);
}
-static int btrfs_dirty_inode(struct inode *inode);
+static int btrfs_dirty_inode(struct btrfs_inode *inode);
static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
struct btrfs_new_inode_args *args)
@@ -483,7 +520,7 @@ struct async_extent {
};
struct async_chunk {
- struct inode *inode;
+ struct btrfs_inode *inode;
struct page *locked_page;
u64 start;
u64 end;
@@ -611,8 +648,8 @@ static inline void inode_should_defrag(struct btrfs_inode *inode,
*/
static noinline int compress_file_range(struct async_chunk *async_chunk)
{
- struct inode *inode = async_chunk->inode;
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_inode *inode = async_chunk->inode;
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 blocksize = fs_info->sectorsize;
u64 start = async_chunk->start;
u64 end = async_chunk->end;
@@ -629,8 +666,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
int compressed_extents = 0;
int redirty = 0;
- inode_should_defrag(BTRFS_I(inode), start, end, end - start + 1,
- SZ_16K);
+ inode_should_defrag(inode, start, end, end - start + 1, SZ_16K);
/*
* We need to save i_size before now because it could change in between
@@ -642,7 +678,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
* does that for us.
*/
barrier();
- i_size = i_size_read(inode);
+ i_size = i_size_read(&inode->vfs_inode);
barrier();
actual_end = min_t(u64, i_size, end + 1);
again:
@@ -671,7 +707,7 @@ again:
* isn't an inline extent, since it doesn't save disk space at all.
*/
if (total_compressed <= blocksize &&
- (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
+ (start > 0 || end + 1 < inode->disk_i_size))
goto cleanup_and_bail_uncompressed;
/*
@@ -695,7 +731,7 @@ again:
* inode has not been flagged as nocompress. This flag can
* change at any time if we discover bad compression ratios.
*/
- if (inode_need_compress(BTRFS_I(inode), start, end)) {
+ if (inode_need_compress(inode, start, end)) {
WARN_ON(pages);
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
if (!pages) {
@@ -704,10 +740,10 @@ again:
goto cont;
}
- if (BTRFS_I(inode)->defrag_compress)
- compress_type = BTRFS_I(inode)->defrag_compress;
- else if (BTRFS_I(inode)->prop_compress)
- compress_type = BTRFS_I(inode)->prop_compress;
+ if (inode->defrag_compress)
+ compress_type = inode->defrag_compress;
+ else if (inode->prop_compress)
+ compress_type = inode->prop_compress;
/*
* we need to call clear_page_dirty_for_io on each
@@ -722,14 +758,14 @@ again:
* has moved, the end is the original one.
*/
if (!redirty) {
- extent_range_clear_dirty_for_io(inode, start, end);
+ extent_range_clear_dirty_for_io(&inode->vfs_inode, start, end);
redirty = 1;
}
/* Compression level is applied here and only here */
ret = btrfs_compress_pages(
compress_type | (fs_info->compress_level << 4),
- inode->i_mapping, start,
+ inode->vfs_inode.i_mapping, start,
pages,
&nr_pages,
&total_in,
@@ -758,12 +794,12 @@ cont:
/* we didn't compress the entire range, try
* to make an uncompressed inline extent.
*/
- ret = cow_file_range_inline(BTRFS_I(inode), actual_end,
+ ret = cow_file_range_inline(inode, actual_end,
0, BTRFS_COMPRESS_NONE,
NULL, false);
} else {
/* try making a compressed inline extent */
- ret = cow_file_range_inline(BTRFS_I(inode), actual_end,
+ ret = cow_file_range_inline(inode, actual_end,
total_compressed,
compress_type, pages,
false);
@@ -786,7 +822,7 @@ cont:
* our outstanding extent for clearing delalloc for this
* range.
*/
- extent_clear_unlock_delalloc(BTRFS_I(inode), start, end,
+ extent_clear_unlock_delalloc(inode, start, end,
NULL,
clear_flags,
PAGE_UNLOCK |
@@ -861,8 +897,8 @@ cont:
/* flag the file so we don't compress in the future */
if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) &&
- !(BTRFS_I(inode)->prop_compress)) {
- BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
+ !(inode->prop_compress)) {
+ inode->flags |= BTRFS_INODE_NOCOMPRESS;
}
}
cleanup_and_bail_uncompressed:
@@ -880,7 +916,7 @@ cleanup_and_bail_uncompressed:
}
if (redirty)
- extent_range_redirty_for_io(inode, start, end);
+ extent_range_redirty_for_io(&inode->vfs_inode, start, end);
add_async_extent(async_chunk, start, end - start + 1, 0, NULL, 0,
BTRFS_COMPRESS_NONE);
compressed_extents++;
@@ -1076,7 +1112,7 @@ out_free:
*/
static noinline void submit_compressed_extents(struct async_chunk *async_chunk)
{
- struct btrfs_inode *inode = BTRFS_I(async_chunk->inode);
+ struct btrfs_inode *inode = async_chunk->inode;
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct async_extent *async_extent;
u64 alloc_hint = 0;
@@ -1565,7 +1601,7 @@ static int cow_file_range_async(struct btrfs_inode *inode,
*/
ihold(&inode->vfs_inode);
async_chunk[i].async_cow = ctx;
- async_chunk[i].inode = &inode->vfs_inode;
+ async_chunk[i].inode = inode;
async_chunk[i].start = start;
async_chunk[i].end = cur_end;
async_chunk[i].write_flags = write_flags;
@@ -1673,9 +1709,8 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,
int ret;
LIST_HEAD(list);
- ret = btrfs_lookup_csums_range(csum_root, bytenr,
- bytenr + num_bytes - 1, &list, 0,
- nowait);
+ ret = btrfs_lookup_csums_list(csum_root, bytenr, bytenr + num_bytes - 1,
+ &list, 0, nowait);
if (ret == 0 && list_empty(&list))
return 0;
@@ -1733,7 +1768,7 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
* when starting writeback.
*/
count = count_range_bits(io_tree, &range_start, end, range_bytes,
- EXTENT_NORESERVE, 0);
+ EXTENT_NORESERVE, 0, NULL);
if (count > 0 || is_space_ino || is_reloc_ino) {
u64 bytes = count;
struct btrfs_fs_info *fs_info = inode->root->fs_info;
@@ -2240,10 +2275,10 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
return ret;
}
-void btrfs_split_delalloc_extent(struct inode *inode,
+void btrfs_split_delalloc_extent(struct btrfs_inode *inode,
struct extent_state *orig, u64 split)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 size;
/* not delalloc, ignore it */
@@ -2267,9 +2302,9 @@ void btrfs_split_delalloc_extent(struct inode *inode,
return;
}
- spin_lock(&BTRFS_I(inode)->lock);
- btrfs_mod_outstanding_extents(BTRFS_I(inode), 1);
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_lock(&inode->lock);
+ btrfs_mod_outstanding_extents(inode, 1);
+ spin_unlock(&inode->lock);
}
/*
@@ -2277,10 +2312,10 @@ void btrfs_split_delalloc_extent(struct inode *inode,
* that are just merged onto old extents, such as when we are doing sequential
* writes, so we can properly account for the metadata space we'll need.
*/
-void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new,
+void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state *new,
struct extent_state *other)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 new_size, old_size;
u32 num_extents;
@@ -2295,9 +2330,9 @@ void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new,
/* we're not bigger than the max, unreserve the space and go */
if (new_size <= fs_info->max_extent_size) {
- spin_lock(&BTRFS_I(inode)->lock);
- btrfs_mod_outstanding_extents(BTRFS_I(inode), -1);
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_lock(&inode->lock);
+ btrfs_mod_outstanding_extents(inode, -1);
+ spin_unlock(&inode->lock);
return;
}
@@ -2326,22 +2361,20 @@ void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new,
if (count_max_extents(fs_info, new_size) >= num_extents)
return;
- spin_lock(&BTRFS_I(inode)->lock);
- btrfs_mod_outstanding_extents(BTRFS_I(inode), -1);
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_lock(&inode->lock);
+ btrfs_mod_outstanding_extents(inode, -1);
+ spin_unlock(&inode->lock);
}
static void btrfs_add_delalloc_inodes(struct btrfs_root *root,
- struct inode *inode)
+ struct btrfs_inode *inode)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
spin_lock(&root->delalloc_lock);
- if (list_empty(&BTRFS_I(inode)->delalloc_inodes)) {
- list_add_tail(&BTRFS_I(inode)->delalloc_inodes,
- &root->delalloc_inodes);
- set_bit(BTRFS_INODE_IN_DELALLOC_LIST,
- &BTRFS_I(inode)->runtime_flags);
+ if (list_empty(&inode->delalloc_inodes)) {
+ list_add_tail(&inode->delalloc_inodes, &root->delalloc_inodes);
+ set_bit(BTRFS_INODE_IN_DELALLOC_LIST, &inode->runtime_flags);
root->nr_delalloc_inodes++;
if (root->nr_delalloc_inodes == 1) {
spin_lock(&fs_info->delalloc_root_lock);
@@ -2354,7 +2387,6 @@ static void btrfs_add_delalloc_inodes(struct btrfs_root *root,
spin_unlock(&root->delalloc_lock);
}
-
void __btrfs_del_delalloc_inode(struct btrfs_root *root,
struct btrfs_inode *inode)
{
@@ -2387,10 +2419,10 @@ static void btrfs_del_delalloc_inode(struct btrfs_root *root,
* Properly track delayed allocation bytes in the inode and to maintain the
* list of inodes that have pending delalloc work to be done.
*/
-void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
+void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *state,
u32 bits)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
if ((bits & EXTENT_DEFRAG) && !(bits & EXTENT_DELALLOC))
WARN_ON(1);
@@ -2400,14 +2432,14 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
* bit, which is only set or cleared with irqs on
*/
if (!(state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
- struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_root *root = inode->root;
u64 len = state->end + 1 - state->start;
u32 num_extents = count_max_extents(fs_info, len);
- bool do_list = !btrfs_is_free_space_inode(BTRFS_I(inode));
+ bool do_list = !btrfs_is_free_space_inode(inode);
- spin_lock(&BTRFS_I(inode)->lock);
- btrfs_mod_outstanding_extents(BTRFS_I(inode), num_extents);
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_lock(&inode->lock);
+ btrfs_mod_outstanding_extents(inode, num_extents);
+ spin_unlock(&inode->lock);
/* For sanity tests */
if (btrfs_is_testing(fs_info))
@@ -2415,22 +2447,21 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
percpu_counter_add_batch(&fs_info->delalloc_bytes, len,
fs_info->delalloc_batch);
- spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->delalloc_bytes += len;
+ spin_lock(&inode->lock);
+ inode->delalloc_bytes += len;
if (bits & EXTENT_DEFRAG)
- BTRFS_I(inode)->defrag_bytes += len;
+ inode->defrag_bytes += len;
if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST,
- &BTRFS_I(inode)->runtime_flags))
+ &inode->runtime_flags))
btrfs_add_delalloc_inodes(root, inode);
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_unlock(&inode->lock);
}
if (!(state->state & EXTENT_DELALLOC_NEW) &&
(bits & EXTENT_DELALLOC_NEW)) {
- spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->new_delalloc_bytes += state->end + 1 -
- state->start;
- spin_unlock(&BTRFS_I(inode)->lock);
+ spin_lock(&inode->lock);
+ inode->new_delalloc_bytes += state->end + 1 - state->start;
+ spin_unlock(&inode->lock);
}
}
@@ -2438,11 +2469,10 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
* Once a range is no longer delalloc this function ensures that proper
* accounting happens.
*/
-void btrfs_clear_delalloc_extent(struct inode *vfs_inode,
+void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
struct extent_state *state, u32 bits)
{
- struct btrfs_inode *inode = BTRFS_I(vfs_inode);
- struct btrfs_fs_info *fs_info = btrfs_sb(vfs_inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 len = state->end + 1 - state->start;
u32 num_extents = count_max_extents(fs_info, len);
@@ -2513,10 +2543,9 @@ void btrfs_clear_delalloc_extent(struct inode *vfs_inode,
* At IO completion time the cums attached on the ordered extent record
* are inserted into the btree
*/
-static blk_status_t btrfs_submit_bio_start(struct inode *inode, struct bio *bio,
- u64 dio_file_offset)
+blk_status_t btrfs_submit_bio_start(struct btrfs_inode *inode, struct bio *bio)
{
- return btrfs_csum_one_bio(BTRFS_I(inode), bio, (u64)-1, false);
+ return btrfs_csum_one_bio(inode, bio, (u64)-1, false);
}
/*
@@ -2694,14 +2723,13 @@ out:
return errno_to_blk_status(ret);
}
-void btrfs_submit_data_write_bio(struct inode *inode, struct bio *bio, int mirror_num)
+void btrfs_submit_data_write_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_inode *bi = BTRFS_I(inode);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
blk_status_t ret;
if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
- ret = extract_ordered_extent(bi, bio,
+ ret = extract_ordered_extent(inode, bio,
page_offset(bio_first_bvec_all(bio)->bv_page));
if (ret) {
btrfs_bio_end_io(btrfs_bio(bio), ret);
@@ -2717,15 +2745,14 @@ void btrfs_submit_data_write_bio(struct inode *inode, struct bio *bio, int mirro
* Csum items for reloc roots have already been cloned at this point,
* so they are handled as part of the no-checksum case.
*/
- if (!(bi->flags & BTRFS_INODE_NODATASUM) &&
+ if (!(inode->flags & BTRFS_INODE_NODATASUM) &&
!test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state) &&
- !btrfs_is_data_reloc_root(bi->root)) {
- if (!atomic_read(&bi->sync_writers) &&
- btrfs_wq_submit_bio(inode, bio, mirror_num, 0,
- btrfs_submit_bio_start))
+ !btrfs_is_data_reloc_root(inode->root)) {
+ if (!atomic_read(&inode->sync_writers) &&
+ btrfs_wq_submit_bio(inode, bio, mirror_num, 0, WQ_SUBMIT_DATA))
return;
- ret = btrfs_csum_one_bio(bi, bio, (u64)-1, false);
+ ret = btrfs_csum_one_bio(inode, bio, (u64)-1, false);
if (ret) {
btrfs_bio_end_io(btrfs_bio(bio), ret);
return;
@@ -2734,10 +2761,10 @@ void btrfs_submit_data_write_bio(struct inode *inode, struct bio *bio, int mirro
btrfs_submit_bio(fs_info, bio, mirror_num);
}
-void btrfs_submit_data_read_bio(struct inode *inode, struct bio *bio,
+void btrfs_submit_data_read_bio(struct btrfs_inode *inode, struct bio *bio,
int mirror_num, enum btrfs_compression_type compress_type)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
blk_status_t ret;
if (compress_type != BTRFS_COMPRESS_NONE) {
@@ -2745,7 +2772,7 @@ void btrfs_submit_data_read_bio(struct inode *inode, struct bio *bio,
* btrfs_submit_compressed_read will handle completing the bio
* if there were any errors, so just return here.
*/
- btrfs_submit_compressed_read(inode, bio, mirror_num);
+ btrfs_submit_compressed_read(&inode->vfs_inode, bio, mirror_num);
return;
}
@@ -2756,7 +2783,7 @@ void btrfs_submit_data_read_bio(struct inode *inode, struct bio *bio,
* Lookup bio sums does extra checks around whether we need to csum or
* not, which is why we ignore skip_sum here.
*/
- ret = btrfs_lookup_bio_sums(inode, bio, NULL);
+ ret = btrfs_lookup_bio_sums(&inode->vfs_inode, bio, NULL);
if (ret) {
btrfs_bio_end_io(btrfs_bio(bio), ret);
return;
@@ -2859,7 +2886,7 @@ int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
/* see btrfs_writepage_start_hook for details on why this is required */
struct btrfs_writepage_fixup {
struct page *page;
- struct inode *inode;
+ struct btrfs_inode *inode;
struct btrfs_work work;
};
@@ -2878,7 +2905,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
fixup = container_of(work, struct btrfs_writepage_fixup, work);
page = fixup->page;
- inode = BTRFS_I(fixup->inode);
+ inode = fixup->inode;
page_start = page_offset(page);
page_end = page_offset(page) + PAGE_SIZE - 1;
@@ -2988,7 +3015,7 @@ out_page:
* that could need flushing space. Recursing back to fixup worker would
* deadlock.
*/
- btrfs_add_delayed_iput(&inode->vfs_inode);
+ btrfs_add_delayed_iput(inode);
}
/*
@@ -3037,7 +3064,7 @@ int btrfs_writepage_cow_fixup(struct page *page)
get_page(page);
btrfs_init_work(&fixup->work, btrfs_writepage_fixup_worker, NULL, NULL);
fixup->page = page;
- fixup->inode = inode;
+ fixup->inode = BTRFS_I(inode);
btrfs_queue_work(fs_info->fixup_workers, &fixup->work);
return -EAGAIN;
@@ -3459,10 +3486,10 @@ static u8 *btrfs_csum_ptr(const struct btrfs_fs_info *fs_info, u8 *csums, u64 of
* When csum mismatch is detected, we will also report the error and fill the
* corrupted range with zero. (Thus it needs the extra parameters)
*/
-int btrfs_check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
+int btrfs_check_data_csum(struct btrfs_inode *inode, struct btrfs_bio *bbio,
u32 bio_offset, struct page *page, u32 pgoff)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
u32 len = fs_info->sectorsize;
u8 *csum_expected;
u8 csum[BTRFS_CSUM_SIZE];
@@ -3476,8 +3503,7 @@ int btrfs_check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
return 0;
zeroit:
- btrfs_print_data_csum_error(BTRFS_I(inode),
- bbio->file_offset + bio_offset,
+ btrfs_print_data_csum_error(inode, bbio->file_offset + bio_offset,
csum, csum_expected, bbio->mirror_num);
if (bbio->device)
btrfs_dev_stat_inc_and_print(bbio->device,
@@ -3502,10 +3528,10 @@ unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
u32 bio_offset, struct page *page,
u64 start, u64 end)
{
- struct inode *inode = page->mapping->host;
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
- struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
+ struct btrfs_root *root = inode->root;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct extent_io_tree *io_tree = &inode->io_tree;
const u32 sectorsize = root->fs_info->sectorsize;
u32 pg_off;
unsigned int result = 0;
@@ -3518,7 +3544,7 @@ unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
if (bbio->csum == NULL)
return 0;
- if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
+ if (inode->flags & BTRFS_INODE_NODATASUM)
return 0;
if (unlikely(test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state)))
@@ -3563,18 +3589,17 @@ unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
* the inode to the delayed iput machinery. Delayed iputs are processed at
* transaction commit time/superblock commit/cleaner kthread.
*/
-void btrfs_add_delayed_iput(struct inode *inode)
+void btrfs_add_delayed_iput(struct btrfs_inode *inode)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_inode *binode = BTRFS_I(inode);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
- if (atomic_add_unless(&inode->i_count, -1, 1))
+ if (atomic_add_unless(&inode->vfs_inode.i_count, -1, 1))
return;
atomic_inc(&fs_info->nr_delayed_iputs);
spin_lock(&fs_info->delayed_iput_lock);
- ASSERT(list_empty(&binode->delayed_iput));
- list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
+ ASSERT(list_empty(&inode->delayed_iput));
+ list_add_tail(&inode->delayed_iput, &fs_info->delayed_iputs);
spin_unlock(&fs_info->delayed_iput_lock);
if (!test_bit(BTRFS_FS_CLEANER_RUNNING, &fs_info->flags))
wake_up_process(fs_info->cleaner_kthread);
@@ -3617,7 +3642,7 @@ void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
spin_unlock(&fs_info->delayed_iput_lock);
}
-/**
+/*
* Wait for flushing all delayed iputs
*
* @fs_info: the filesystem
@@ -4262,7 +4287,7 @@ int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_rename_ctx *rename_ctx)
{
struct btrfs_root *root = dir->root;
@@ -4280,8 +4305,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
goto out;
}
- di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
- name, name_len, -1);
+ di = btrfs_lookup_dir_item(trans, root, path, dir_ino, name, -1);
if (IS_ERR_OR_NULL(di)) {
ret = di ? PTR_ERR(di) : -ENOENT;
goto err;
@@ -4309,12 +4333,11 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
}
}
- ret = btrfs_del_inode_ref(trans, root, name, name_len, ino,
- dir_ino, &index);
+ ret = btrfs_del_inode_ref(trans, root, name, ino, dir_ino, &index);
if (ret) {
btrfs_info(fs_info,
"failed to delete reference to %.*s, inode %llu parent %llu",
- name_len, name, ino, dir_ino);
+ name->len, name->name, ino, dir_ino);
btrfs_abort_transaction(trans, ret);
goto err;
}
@@ -4335,10 +4358,8 @@ skip_backref:
* operations on the log tree, increasing latency for applications.
*/
if (!rename_ctx) {
- btrfs_del_inode_ref_in_log(trans, root, name, name_len, inode,
- dir_ino);
- btrfs_del_dir_entries_in_log(trans, root, name, name_len, dir,
- index);
+ btrfs_del_inode_ref_in_log(trans, root, name, inode, dir_ino);
+ btrfs_del_dir_entries_in_log(trans, root, name, dir, index);
}
/*
@@ -4356,7 +4377,7 @@ err:
if (ret)
goto out;
- btrfs_i_size_write(dir, dir->vfs_inode.i_size - name_len * 2);
+ btrfs_i_size_write(dir, dir->vfs_inode.i_size - name->len * 2);
inode_inc_iversion(&inode->vfs_inode);
inode_inc_iversion(&dir->vfs_inode);
inode->vfs_inode.i_ctime = current_time(&inode->vfs_inode);
@@ -4369,10 +4390,11 @@ out:
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir, struct btrfs_inode *inode,
- const char *name, int name_len)
+ const struct fscrypt_str *name)
{
int ret;
- ret = __btrfs_unlink_inode(trans, dir, inode, name, name_len, NULL);
+
+ ret = __btrfs_unlink_inode(trans, dir, inode, name, NULL);
if (!ret) {
drop_nlink(&inode->vfs_inode);
ret = btrfs_update_inode(trans, inode->root, inode);
@@ -4388,9 +4410,9 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
* plenty of slack room in the global reserve to migrate, otherwise we cannot
* allow the unlink to occur.
*/
-static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
+static struct btrfs_trans_handle *__unlink_start_trans(struct btrfs_inode *dir)
{
- struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_root *root = dir->root;
/*
* 1 for the possible orphan item
@@ -4408,47 +4430,62 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
struct btrfs_trans_handle *trans;
struct inode *inode = d_inode(dentry);
int ret;
+ struct fscrypt_name fname;
- trans = __unlink_start_trans(dir);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ ret = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname);
+ if (ret)
+ return ret;
+
+ /* This needs to handle no-key deletions later on */
+
+ trans = __unlink_start_trans(BTRFS_I(dir));
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto fscrypt_free;
+ }
btrfs_record_unlink_dir(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)),
0);
- ret = btrfs_unlink_inode(trans, BTRFS_I(dir),
- BTRFS_I(d_inode(dentry)), dentry->d_name.name,
- dentry->d_name.len);
+ ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)),
+ &fname.disk_name);
if (ret)
- goto out;
+ goto end_trans;
if (inode->i_nlink == 0) {
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
if (ret)
- goto out;
+ goto end_trans;
}
-out:
+end_trans:
btrfs_end_transaction(trans);
btrfs_btree_balance_dirty(BTRFS_I(dir)->root->fs_info);
+fscrypt_free:
+ fscrypt_free_filename(&fname);
return ret;
}
static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
- struct inode *dir, struct dentry *dentry)
+ struct btrfs_inode *dir, struct dentry *dentry)
{
- struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_root *root = dir->root;
struct btrfs_inode *inode = BTRFS_I(d_inode(dentry));
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_dir_item *di;
struct btrfs_key key;
- const char *name = dentry->d_name.name;
- int name_len = dentry->d_name.len;
u64 index;
int ret;
u64 objectid;
- u64 dir_ino = btrfs_ino(BTRFS_I(dir));
+ u64 dir_ino = btrfs_ino(dir);
+ struct fscrypt_name fname;
+
+ ret = fscrypt_setup_filename(&dir->vfs_inode, &dentry->d_name, 1, &fname);
+ if (ret)
+ return ret;
+
+ /* This needs to handle no-key deletions later on */
if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) {
objectid = inode->root->root_key.objectid;
@@ -4456,15 +4493,18 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
objectid = inode->location.objectid;
} else {
WARN_ON(1);
+ fscrypt_free_filename(&fname);
return -EINVAL;
}
path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
- name, name_len, -1);
+ &fname.disk_name, -1);
if (IS_ERR_OR_NULL(di)) {
ret = di ? PTR_ERR(di) : -ENOENT;
goto out;
@@ -4490,8 +4530,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
* call btrfs_del_root_ref, and it _shouldn't_ fail.
*/
if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) {
- di = btrfs_search_dir_index_item(root, path, dir_ino,
- name, name_len);
+ di = btrfs_search_dir_index_item(root, path, dir_ino, &fname.disk_name);
if (IS_ERR_OR_NULL(di)) {
if (!di)
ret = -ENOENT;
@@ -4508,28 +4547,29 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
} else {
ret = btrfs_del_root_ref(trans, objectid,
root->root_key.objectid, dir_ino,
- &index, name, name_len);
+ &index, &fname.disk_name);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
}
}
- ret = btrfs_delete_delayed_dir_index(trans, BTRFS_I(dir), index);
+ ret = btrfs_delete_delayed_dir_index(trans, dir, index);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
}
- btrfs_i_size_write(BTRFS_I(dir), dir->i_size - name_len * 2);
- inode_inc_iversion(dir);
- dir->i_mtime = current_time(dir);
- dir->i_ctime = dir->i_mtime;
- ret = btrfs_update_inode_fallback(trans, root, BTRFS_I(dir));
+ btrfs_i_size_write(dir, dir->vfs_inode.i_size - fname.disk_name.len * 2);
+ inode_inc_iversion(&dir->vfs_inode);
+ dir->vfs_inode.i_mtime = current_time(&dir->vfs_inode);
+ dir->vfs_inode.i_ctime = dir->vfs_inode.i_mtime;
+ ret = btrfs_update_inode_fallback(trans, root, dir);
if (ret)
btrfs_abort_transaction(trans, ret);
out:
btrfs_free_path(path);
+ fscrypt_free_filename(&fname);
return ret;
}
@@ -4543,6 +4583,7 @@ static noinline int may_destroy_subvol(struct btrfs_root *root)
struct btrfs_path *path;
struct btrfs_dir_item *di;
struct btrfs_key key;
+ struct fscrypt_str name = FSTR_INIT("default", 7);
u64 dir_id;
int ret;
@@ -4553,7 +4594,7 @@ static noinline int may_destroy_subvol(struct btrfs_root *root)
/* Make sure this root isn't set as the default subvol */
dir_id = btrfs_super_root_dir(fs_info->super_copy);
di = btrfs_lookup_dir_item(NULL, fs_info->tree_root, path,
- dir_id, "default", 7, 0);
+ dir_id, &name, 0);
if (di && !IS_ERR(di)) {
btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key);
if (key.objectid == root->root_key.objectid) {
@@ -4652,10 +4693,10 @@ again:
spin_unlock(&root->inode_lock);
}
-int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
+int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
{
struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
- struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_root *root = dir->root;
struct inode *inode = d_inode(dentry);
struct btrfs_root *dest = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
@@ -4712,7 +4753,7 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
trans->block_rsv = &block_rsv;
trans->bytes_reserved = block_rsv.size;
- btrfs_record_snapshot_destroy(trans, BTRFS_I(dir));
+ btrfs_record_snapshot_destroy(trans, dir);
ret = btrfs_unlink_subvol(trans, dir, dentry);
if (ret) {
@@ -4792,6 +4833,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
int err = 0;
struct btrfs_trans_handle *trans;
u64 last_unlink_trans;
+ struct fscrypt_name fname;
if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
return -ENOTEMPTY;
@@ -4801,15 +4843,23 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
"extent tree v2 doesn't support snapshot deletion yet");
return -EOPNOTSUPP;
}
- return btrfs_delete_subvolume(dir, dentry);
+ return btrfs_delete_subvolume(BTRFS_I(dir), dentry);
}
- trans = __unlink_start_trans(dir);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname);
+ if (err)
+ return err;
+
+ /* This needs to handle no-key deletions later on */
+
+ trans = __unlink_start_trans(BTRFS_I(dir));
+ if (IS_ERR(trans)) {
+ err = PTR_ERR(trans);
+ goto out_notrans;
+ }
if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
- err = btrfs_unlink_subvol(trans, dir, dentry);
+ err = btrfs_unlink_subvol(trans, BTRFS_I(dir), dentry);
goto out;
}
@@ -4820,9 +4870,8 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
/* now the directory is empty */
- err = btrfs_unlink_inode(trans, BTRFS_I(dir),
- BTRFS_I(d_inode(dentry)), dentry->d_name.name,
- dentry->d_name.len);
+ err = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)),
+ &fname.disk_name);
if (!err) {
btrfs_i_size_write(BTRFS_I(inode), 0);
/*
@@ -4841,7 +4890,9 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
}
out:
btrfs_end_transaction(trans);
+out_notrans:
btrfs_btree_balance_dirty(fs_info);
+ fscrypt_free_filename(&fname);
return err;
}
@@ -5210,7 +5261,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
inode_dio_wait(inode);
- ret = btrfs_truncate(inode, newsize == oldsize);
+ ret = btrfs_truncate(BTRFS_I(inode), newsize == oldsize);
if (ret && inode->i_nlink) {
int err;
@@ -5253,10 +5304,10 @@ static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentr
if (attr->ia_valid) {
setattr_copy(mnt_userns, inode, attr);
inode_inc_iversion(inode);
- err = btrfs_dirty_inode(inode);
+ err = btrfs_dirty_inode(BTRFS_I(inode));
if (!err && attr->ia_valid & ATTR_MODE)
- err = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
+ err = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
}
return err;
@@ -5511,22 +5562,27 @@ no_delete:
* If no dir entries were found, returns -ENOENT.
* If found a corrupted location in dir entry, returns -EUCLEAN.
*/
-static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
+static int btrfs_inode_by_name(struct btrfs_inode *dir, struct dentry *dentry,
struct btrfs_key *location, u8 *type)
{
- const char *name = dentry->d_name.name;
- int namelen = dentry->d_name.len;
struct btrfs_dir_item *di;
struct btrfs_path *path;
- struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_root *root = dir->root;
int ret = 0;
+ struct fscrypt_name fname;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)),
- name, namelen, 0);
+ ret = fscrypt_setup_filename(&dir->vfs_inode, &dentry->d_name, 1, &fname);
+ if (ret)
+ goto out;
+
+ /* This needs to handle no-key deletions later on */
+
+ di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir),
+ &fname.disk_name, 0);
if (IS_ERR_OR_NULL(di)) {
ret = di ? PTR_ERR(di) : -ENOENT;
goto out;
@@ -5538,12 +5594,13 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
ret = -EUCLEAN;
btrfs_warn(root->fs_info,
"%s gets something invalid in DIR_ITEM (name %s, directory ino %llu, location(%llu %u %llu))",
- __func__, name, btrfs_ino(BTRFS_I(dir)),
+ __func__, fname.disk_name.name, btrfs_ino(dir),
location->objectid, location->type, location->offset);
}
if (!ret)
- *type = btrfs_dir_type(path->nodes[0], di);
+ *type = btrfs_dir_ftype(path->nodes[0], di);
out:
+ fscrypt_free_filename(&fname);
btrfs_free_path(path);
return ret;
}
@@ -5554,7 +5611,7 @@ out:
* is kind of like crossing a mount point.
*/
static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
- struct inode *dir,
+ struct btrfs_inode *dir,
struct dentry *dentry,
struct btrfs_key *location,
struct btrfs_root **sub_root)
@@ -5566,6 +5623,11 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
struct btrfs_key key;
int ret;
int err = 0;
+ struct fscrypt_name fname;
+
+ ret = fscrypt_setup_filename(&dir->vfs_inode, &dentry->d_name, 0, &fname);
+ if (ret)
+ return ret;
path = btrfs_alloc_path();
if (!path) {
@@ -5574,7 +5636,7 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
}
err = -ENOENT;
- key.objectid = BTRFS_I(dir)->root->root_key.objectid;
+ key.objectid = dir->root->root_key.objectid;
key.type = BTRFS_ROOT_REF_KEY;
key.offset = location->objectid;
@@ -5587,13 +5649,12 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
leaf = path->nodes[0];
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
- if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(BTRFS_I(dir)) ||
- btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len)
+ if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(dir) ||
+ btrfs_root_ref_name_len(leaf, ref) != fname.disk_name.len)
goto out;
- ret = memcmp_extent_buffer(leaf, dentry->d_name.name,
- (unsigned long)(ref + 1),
- dentry->d_name.len);
+ ret = memcmp_extent_buffer(leaf, fname.disk_name.name,
+ (unsigned long)(ref + 1), fname.disk_name.len);
if (ret)
goto out;
@@ -5612,19 +5673,20 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
err = 0;
out:
btrfs_free_path(path);
+ fscrypt_free_filename(&fname);
return err;
}
-static void inode_tree_add(struct inode *inode)
+static void inode_tree_add(struct btrfs_inode *inode)
{
- struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_root *root = inode->root;
struct btrfs_inode *entry;
struct rb_node **p;
struct rb_node *parent;
- struct rb_node *new = &BTRFS_I(inode)->rb_node;
- u64 ino = btrfs_ino(BTRFS_I(inode));
+ struct rb_node *new = &inode->rb_node;
+ u64 ino = btrfs_ino(inode);
- if (inode_unhashed(inode))
+ if (inode_unhashed(&inode->vfs_inode))
return;
parent = NULL;
spin_lock(&root->inode_lock);
@@ -5736,7 +5798,7 @@ struct inode *btrfs_iget_path(struct super_block *s, u64 ino,
ret = btrfs_read_locked_inode(inode, path);
if (!ret) {
- inode_tree_add(inode);
+ inode_tree_add(BTRFS_I(inode));
unlock_new_inode(inode);
} else {
iget_failed(inode);
@@ -5816,7 +5878,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
if (dentry->d_name.len > BTRFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- ret = btrfs_inode_by_name(dir, dentry, &location, &di_type);
+ ret = btrfs_inode_by_name(BTRFS_I(dir), dentry, &location, &di_type);
if (ret < 0)
return ERR_PTR(ret);
@@ -5837,7 +5899,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
return inode;
}
- ret = fixup_tree_root_location(fs_info, dir, dentry,
+ ret = fixup_tree_root_location(fs_info, BTRFS_I(dir), dentry,
&location, &sub_root);
if (ret < 0) {
if (ret != -ENOENT)
@@ -5985,6 +6047,7 @@ again:
btrfs_for_each_slot(root, &key, &found_key, path, ret) {
struct dir_entry *entry;
struct extent_buffer *leaf = path->nodes[0];
+ u8 ftype;
if (found_key.objectid != key.objectid)
break;
@@ -6008,13 +6071,13 @@ again:
goto again;
}
+ ftype = btrfs_dir_flags_to_ftype(btrfs_dir_flags(leaf, di));
entry = addr;
- put_unaligned(name_len, &entry->name_len);
name_ptr = (char *)(entry + 1);
- read_extent_buffer(leaf, name_ptr, (unsigned long)(di + 1),
- name_len);
- put_unaligned(fs_ftype_to_dtype(btrfs_dir_type(leaf, di)),
- &entry->type);
+ read_extent_buffer(leaf, name_ptr,
+ (unsigned long)(di + 1), name_len);
+ put_unaligned(name_len, &entry->name_len);
+ put_unaligned(fs_ftype_to_dtype(ftype), &entry->type);
btrfs_dir_item_key_to_cpu(leaf, di, &location);
put_unaligned(location.objectid, &entry->ino);
put_unaligned(found_key.offset, &entry->offset);
@@ -6072,21 +6135,21 @@ err:
* FIXME, needs more benchmarking...there are no reasons other than performance
* to keep or drop this code.
*/
-static int btrfs_dirty_inode(struct inode *inode)
+static int btrfs_dirty_inode(struct btrfs_inode *inode)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_root *root = inode->root;
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_trans_handle *trans;
int ret;
- if (test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags))
+ if (test_bit(BTRFS_INODE_DUMMY, &inode->runtime_flags))
return 0;
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
- ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
+ ret = btrfs_update_inode(trans, root, inode);
if (ret && (ret == -ENOSPC || ret == -EDQUOT)) {
/* whoops, lets try again with the full transaction */
btrfs_end_transaction(trans);
@@ -6094,10 +6157,10 @@ static int btrfs_dirty_inode(struct inode *inode)
if (IS_ERR(trans))
return PTR_ERR(trans);
- ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
+ ret = btrfs_update_inode(trans, root, inode);
}
btrfs_end_transaction(trans);
- if (BTRFS_I(inode)->delayed_node)
+ if (inode->delayed_node)
btrfs_balance_delayed_items(fs_info);
return ret;
@@ -6124,7 +6187,7 @@ static int btrfs_update_time(struct inode *inode, struct timespec64 *now,
inode->i_mtime = *now;
if (flags & S_ATIME)
inode->i_atime = *now;
- return dirty ? btrfs_dirty_inode(inode) : 0;
+ return dirty ? btrfs_dirty_inode(BTRFS_I(inode)) : 0;
}
/*
@@ -6220,9 +6283,18 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
struct inode *inode = args->inode;
int ret;
+ if (!args->orphan) {
+ ret = fscrypt_setup_filename(dir, &args->dentry->d_name, 0,
+ &args->fname);
+ if (ret)
+ return ret;
+ }
+
ret = posix_acl_create(dir, &inode->i_mode, &args->default_acl, &args->acl);
- if (ret)
+ if (ret) {
+ fscrypt_free_filename(&args->fname);
return ret;
+ }
/* 1 to add inode item */
*trans_num_items = 1;
@@ -6262,6 +6334,7 @@ void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args)
{
posix_acl_release(args->acl);
posix_acl_release(args->default_acl);
+ fscrypt_free_filename(&args->fname);
}
/*
@@ -6269,27 +6342,27 @@ void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args)
*
* Currently only the compression flags and the cow flags are inherited.
*/
-static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
+static void btrfs_inherit_iflags(struct btrfs_inode *inode, struct btrfs_inode *dir)
{
unsigned int flags;
- flags = BTRFS_I(dir)->flags;
+ flags = dir->flags;
if (flags & BTRFS_INODE_NOCOMPRESS) {
- BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
- BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
+ inode->flags &= ~BTRFS_INODE_COMPRESS;
+ inode->flags |= BTRFS_INODE_NOCOMPRESS;
} else if (flags & BTRFS_INODE_COMPRESS) {
- BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
- BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
+ inode->flags &= ~BTRFS_INODE_NOCOMPRESS;
+ inode->flags |= BTRFS_INODE_COMPRESS;
}
if (flags & BTRFS_INODE_NODATACOW) {
- BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
- if (S_ISREG(inode->i_mode))
- BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+ inode->flags |= BTRFS_INODE_NODATACOW;
+ if (S_ISREG(inode->vfs_inode.i_mode))
+ inode->flags |= BTRFS_INODE_NODATASUM;
}
- btrfs_sync_inode_flags_to_i_flags(inode);
+ btrfs_sync_inode_flags_to_i_flags(&inode->vfs_inode);
}
int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
@@ -6297,8 +6370,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
{
struct inode *dir = args->dir;
struct inode *inode = args->inode;
- const char *name = args->orphan ? NULL : args->dentry->d_name.name;
- int name_len = args->orphan ? 0 : args->dentry->d_name.len;
+ const struct fscrypt_str *name = args->orphan ? NULL : &args->fname.disk_name;
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
struct btrfs_root *root;
struct btrfs_inode_item *inode_item;
@@ -6349,7 +6421,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
* change it now without compatibility issues.
*/
if (!args->subvol)
- btrfs_inherit_iflags(inode, dir);
+ btrfs_inherit_iflags(BTRFS_I(inode), BTRFS_I(dir));
if (S_ISREG(inode->i_mode)) {
if (btrfs_test_opt(fs_info, NODATASUM))
@@ -6399,7 +6471,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
sizes[1] = 2 + sizeof(*ref);
} else {
key[1].offset = btrfs_ino(BTRFS_I(dir));
- sizes[1] = name_len + sizeof(*ref);
+ sizes[1] = name->len + sizeof(*ref);
}
}
@@ -6438,10 +6510,12 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
btrfs_set_inode_ref_index(path->nodes[0], ref, 0);
write_extent_buffer(path->nodes[0], "..", ptr, 2);
} else {
- btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
+ btrfs_set_inode_ref_name_len(path->nodes[0], ref,
+ name->len);
btrfs_set_inode_ref_index(path->nodes[0], ref,
BTRFS_I(inode)->dir_index);
- write_extent_buffer(path->nodes[0], name, ptr, name_len);
+ write_extent_buffer(path->nodes[0], name->name, ptr,
+ name->len);
}
}
@@ -6491,7 +6565,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
}
}
- inode_tree_add(inode);
+ inode_tree_add(BTRFS_I(inode));
trace_btrfs_inode_new(inode);
btrfs_set_inode_last_trans(trans, BTRFS_I(inode));
@@ -6502,7 +6576,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
} else {
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
- name_len, 0, BTRFS_I(inode)->dir_index);
+ 0, BTRFS_I(inode)->dir_index);
}
if (ret) {
btrfs_abort_transaction(trans, ret);
@@ -6531,7 +6605,7 @@ out:
*/
int btrfs_add_link(struct btrfs_trans_handle *trans,
struct btrfs_inode *parent_inode, struct btrfs_inode *inode,
- const char *name, int name_len, int add_backref, u64 index)
+ const struct fscrypt_str *name, int add_backref, u64 index)
{
int ret = 0;
struct btrfs_key key;
@@ -6550,17 +6624,17 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
ret = btrfs_add_root_ref(trans, key.objectid,
root->root_key.objectid, parent_ino,
- index, name, name_len);
+ index, name);
} else if (add_backref) {
- ret = btrfs_insert_inode_ref(trans, root, name, name_len, ino,
- parent_ino, index);
+ ret = btrfs_insert_inode_ref(trans, root, name,
+ ino, parent_ino, index);
}
/* Nothing to clean up yet */
if (ret)
return ret;
- ret = btrfs_insert_dir_item(trans, name, name_len, parent_inode, &key,
+ ret = btrfs_insert_dir_item(trans, name, parent_inode, &key,
btrfs_inode_type(&inode->vfs_inode), index);
if (ret == -EEXIST || ret == -EOVERFLOW)
goto fail_dir_item;
@@ -6570,7 +6644,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
}
btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size +
- name_len * 2);
+ name->len * 2);
inode_inc_iversion(&parent_inode->vfs_inode);
/*
* If we are replaying a log tree, we do not want to update the mtime
@@ -6595,15 +6669,15 @@ fail_dir_item:
int err;
err = btrfs_del_root_ref(trans, key.objectid,
root->root_key.objectid, parent_ino,
- &local_index, name, name_len);
+ &local_index, name);
if (err)
btrfs_abort_transaction(trans, err);
} else if (add_backref) {
u64 local_index;
int err;
- err = btrfs_del_inode_ref(trans, root, name, name_len,
- ino, parent_ino, &local_index);
+ err = btrfs_del_inode_ref(trans, root, name, ino, parent_ino,
+ &local_index);
if (err)
btrfs_abort_transaction(trans, err);
}
@@ -6686,6 +6760,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
struct btrfs_root *root = BTRFS_I(dir)->root;
struct inode *inode = d_inode(old_dentry);
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct fscrypt_name fname;
u64 index;
int err;
int drop_inode = 0;
@@ -6697,6 +6772,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
if (inode->i_nlink >= BTRFS_LINK_MAX)
return -EMLINK;
+ err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname);
+ if (err)
+ goto fail;
+
err = btrfs_set_inode_index(BTRFS_I(dir), &index);
if (err)
goto fail;
@@ -6723,7 +6802,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
- dentry->d_name.name, dentry->d_name.len, 1, index);
+ &fname.disk_name, 1, index);
if (err) {
drop_inode = 1;
@@ -6747,6 +6826,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
}
fail:
+ fscrypt_free_filename(&fname);
if (trans)
btrfs_end_transaction(trans);
if (drop_inode) {
@@ -6773,7 +6853,6 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
static noinline int uncompress_inline(struct btrfs_path *path,
struct page *page,
- size_t pg_offset, u64 extent_offset,
struct btrfs_file_extent_item *item)
{
int ret;
@@ -6784,7 +6863,6 @@ static noinline int uncompress_inline(struct btrfs_path *path,
unsigned long ptr;
int compress_type;
- WARN_ON(pg_offset != 0);
compress_type = btrfs_file_extent_compression(leaf, item);
max_size = btrfs_file_extent_ram_bytes(leaf, item);
inline_size = btrfs_file_extent_inline_item_len(leaf, path->slots[0]);
@@ -6796,8 +6874,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
read_extent_buffer(leaf, tmp, ptr, inline_size);
max_size = min_t(unsigned long, PAGE_SIZE, max_size);
- ret = btrfs_decompress(compress_type, tmp, page,
- extent_offset, inline_size, max_size);
+ ret = btrfs_decompress(compress_type, tmp, page, 0, inline_size, max_size);
/*
* decompression code contains a memset to fill in any space between the end
@@ -6807,25 +6884,52 @@ static noinline int uncompress_inline(struct btrfs_path *path,
* cover that region here.
*/
- if (max_size + pg_offset < PAGE_SIZE)
- memzero_page(page, pg_offset + max_size,
- PAGE_SIZE - max_size - pg_offset);
+ if (max_size < PAGE_SIZE)
+ memzero_page(page, max_size, PAGE_SIZE - max_size);
kfree(tmp);
return ret;
}
-/**
- * btrfs_get_extent - Lookup the first extent overlapping a range in a file.
+static int read_inline_extent(struct btrfs_inode *inode, struct btrfs_path *path,
+ struct page *page)
+{
+ struct btrfs_file_extent_item *fi;
+ void *kaddr;
+ size_t copy_size;
+
+ if (!page || PageUptodate(page))
+ return 0;
+
+ ASSERT(page_offset(page) == 0);
+
+ fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_file_extent_item);
+ if (btrfs_file_extent_compression(path->nodes[0], fi) != BTRFS_COMPRESS_NONE)
+ return uncompress_inline(path, page, fi);
+
+ copy_size = min_t(u64, PAGE_SIZE,
+ btrfs_file_extent_ram_bytes(path->nodes[0], fi));
+ kaddr = kmap_local_page(page);
+ read_extent_buffer(path->nodes[0], kaddr,
+ btrfs_file_extent_inline_start(fi), copy_size);
+ kunmap_local(kaddr);
+ if (copy_size < PAGE_SIZE)
+ memzero_page(page, copy_size, PAGE_SIZE - copy_size);
+ return 0;
+}
+
+/*
+ * Lookup the first extent overlapping a range in a file.
+ *
* @inode: file to search in
* @page: page to read extent data into if the extent is inline
* @pg_offset: offset into @page to copy to
* @start: file offset
* @len: length of range starting at @start
*
- * This returns the first &struct extent_map which overlaps with the given
- * range, reading it from the B-tree and caching it if necessary. Note that
- * there may be more extents which overlap the given range after the returned
- * extent_map.
+ * Return the first &struct extent_map which overlaps the given range, reading
+ * it from the B-tree and caching it if necessary. Note that there may be more
+ * extents which overlap the given range after the returned extent_map.
*
* If @page is not NULL and the extent is inline, this also reads the extent
* data directly into the page and marks the extent up to date in the io_tree.
@@ -6966,51 +7070,33 @@ next:
goto insert;
}
- btrfs_extent_item_to_extent_map(inode, path, item, !page, em);
+ btrfs_extent_item_to_extent_map(inode, path, item, em);
if (extent_type == BTRFS_FILE_EXTENT_REG ||
extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
goto insert;
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
- unsigned long ptr;
- char *map;
- size_t size;
- size_t extent_offset;
- size_t copy_size;
-
- if (!page)
- goto out;
+ /*
+ * Inline extent can only exist at file offset 0. This is
+ * ensured by tree-checker and inline extent creation path.
+ * Thus all members representing file offsets should be zero.
+ */
+ ASSERT(pg_offset == 0);
+ ASSERT(extent_start == 0);
+ ASSERT(em->start == 0);
- size = btrfs_file_extent_ram_bytes(leaf, item);
- extent_offset = page_offset(page) + pg_offset - extent_start;
- copy_size = min_t(u64, PAGE_SIZE - pg_offset,
- size - extent_offset);
- em->start = extent_start + extent_offset;
- em->len = ALIGN(copy_size, fs_info->sectorsize);
- em->orig_block_len = em->len;
- em->orig_start = em->start;
- ptr = btrfs_file_extent_inline_start(item) + extent_offset;
+ /*
+ * btrfs_extent_item_to_extent_map() should have properly
+ * initialized em members already.
+ *
+ * Other members are not utilized for inline extents.
+ */
+ ASSERT(em->block_start == EXTENT_MAP_INLINE);
+ ASSERT(em->len = fs_info->sectorsize);
- if (!PageUptodate(page)) {
- if (btrfs_file_extent_compression(leaf, item) !=
- BTRFS_COMPRESS_NONE) {
- ret = uncompress_inline(path, page, pg_offset,
- extent_offset, item);
- if (ret)
- goto out;
- } else {
- map = kmap_local_page(page);
- read_extent_buffer(leaf, map + pg_offset, ptr,
- copy_size);
- if (pg_offset + copy_size < PAGE_SIZE) {
- memset(map + pg_offset + copy_size, 0,
- PAGE_SIZE - pg_offset -
- copy_size);
- }
- kunmap_local(map);
- }
- flush_dcache_page(page);
- }
+ ret = read_inline_extent(inode, path, page);
+ if (ret < 0)
+ goto out;
goto insert;
}
not_found:
@@ -7255,7 +7341,8 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
while (1) {
if (nowait) {
- if (!try_lock_extent(io_tree, lockstart, lockend))
+ if (!try_lock_extent(io_tree, lockstart, lockend,
+ cached_state))
return -EAGAIN;
} else {
lock_extent(io_tree, lockstart, lockend, cached_state);
@@ -7811,11 +7898,11 @@ static void btrfs_dio_private_put(struct btrfs_dio_private *dip)
return;
if (btrfs_op(&dip->bio) == BTRFS_MAP_WRITE) {
- btrfs_mark_ordered_io_finished(BTRFS_I(dip->inode), NULL,
+ btrfs_mark_ordered_io_finished(dip->inode, NULL,
dip->file_offset, dip->bytes,
!dip->bio.bi_status);
} else {
- unlock_extent(&BTRFS_I(dip->inode)->io_tree,
+ unlock_extent(&dip->inode->io_tree,
dip->file_offset,
dip->file_offset + dip->bytes - 1, NULL);
}
@@ -7824,24 +7911,21 @@ static void btrfs_dio_private_put(struct btrfs_dio_private *dip)
bio_endio(&dip->bio);
}
-static void submit_dio_repair_bio(struct inode *inode, struct bio *bio,
- int mirror_num,
- enum btrfs_compression_type compress_type)
+void btrfs_submit_dio_repair_bio(struct btrfs_inode *inode, struct bio *bio, int mirror_num)
{
struct btrfs_dio_private *dip = btrfs_bio(bio)->private;
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
BUG_ON(bio_op(bio) == REQ_OP_WRITE);
refcount_inc(&dip->refs);
- btrfs_submit_bio(fs_info, bio, mirror_num);
+ btrfs_submit_bio(inode->root->fs_info, bio, mirror_num);
}
static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
struct btrfs_bio *bbio,
const bool uptodate)
{
- struct inode *inode = dip->inode;
+ struct inode *inode = &dip->inode->vfs_inode;
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
const bool csum = !(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM);
blk_status_t err = BLK_STS_OK;
@@ -7853,16 +7937,15 @@ static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
u64 start = bbio->file_offset + offset;
if (uptodate &&
- (!csum || !btrfs_check_data_csum(inode, bbio, offset, bv.bv_page,
- bv.bv_offset))) {
+ (!csum || !btrfs_check_data_csum(BTRFS_I(inode), bbio, offset,
+ bv.bv_page, bv.bv_offset))) {
btrfs_clean_io_failure(BTRFS_I(inode), start,
bv.bv_page, bv.bv_offset);
} else {
int ret;
- ret = btrfs_repair_one_sector(inode, bbio, offset,
- bv.bv_page, bv.bv_offset,
- submit_dio_repair_bio);
+ ret = btrfs_repair_one_sector(BTRFS_I(inode), bbio, offset,
+ bv.bv_page, bv.bv_offset, false);
if (ret)
err = errno_to_blk_status(ret);
}
@@ -7871,11 +7954,11 @@ static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
return err;
}
-static blk_status_t btrfs_submit_bio_start_direct_io(struct inode *inode,
- struct bio *bio,
- u64 dio_file_offset)
+blk_status_t btrfs_submit_bio_start_direct_io(struct btrfs_inode *inode,
+ struct bio *bio,
+ u64 dio_file_offset)
{
- return btrfs_csum_one_bio(BTRFS_I(inode), bio, dio_file_offset, false);
+ return btrfs_csum_one_bio(inode, bio, dio_file_offset, false);
}
static void btrfs_end_dio_bio(struct btrfs_bio *bbio)
@@ -7885,9 +7968,9 @@ static void btrfs_end_dio_bio(struct btrfs_bio *bbio)
blk_status_t err = bio->bi_status;
if (err)
- btrfs_warn(BTRFS_I(dip->inode)->root->fs_info,
+ btrfs_warn(dip->inode->root->fs_info,
"direct IO failed ino %llu rw %d,%u sector %#Lx len %u err no %d",
- btrfs_ino(BTRFS_I(dip->inode)), bio_op(bio),
+ btrfs_ino(dip->inode), bio_op(bio),
bio->bi_opf, bio->bi_iter.bi_sector,
bio->bi_iter.bi_size, err);
@@ -7897,16 +7980,16 @@ static void btrfs_end_dio_bio(struct btrfs_bio *bbio)
if (err)
dip->bio.bi_status = err;
- btrfs_record_physical_zoned(dip->inode, bbio->file_offset, bio);
+ btrfs_record_physical_zoned(&dip->inode->vfs_inode, bbio->file_offset, bio);
bio_put(bio);
btrfs_dio_private_put(dip);
}
-static void btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
+static void btrfs_submit_dio_bio(struct bio *bio, struct btrfs_inode *inode,
u64 file_offset, int async_submit)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_dio_private *dip = btrfs_bio(bio)->private;
blk_status_t ret;
@@ -7914,21 +7997,21 @@ static void btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
if (btrfs_op(bio) == BTRFS_MAP_READ)
btrfs_bio(bio)->iter = bio->bi_iter;
- if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
+ if (inode->flags & BTRFS_INODE_NODATASUM)
goto map;
if (btrfs_op(bio) == BTRFS_MAP_WRITE) {
/* Check btrfs_submit_data_write_bio() for async submit rules */
- if (async_submit && !atomic_read(&BTRFS_I(inode)->sync_writers) &&
+ if (async_submit && !atomic_read(&inode->sync_writers) &&
btrfs_wq_submit_bio(inode, bio, 0, file_offset,
- btrfs_submit_bio_start_direct_io))
+ WQ_SUBMIT_DATA_DIO))
return;
/*
* If we aren't doing async submit, calculate the csum of the
* bio now.
*/
- ret = btrfs_csum_one_bio(BTRFS_I(inode), bio, file_offset, false);
+ ret = btrfs_csum_one_bio(inode, bio, file_offset, false);
if (ret) {
btrfs_bio_end_io(btrfs_bio(bio), ret);
return;
@@ -7964,7 +8047,7 @@ static void btrfs_submit_direct(const struct iomap_iter *iter,
struct btrfs_dio_data *dio_data = iter->private;
struct extent_map *em = NULL;
- dip->inode = inode;
+ dip->inode = BTRFS_I(inode);
dip->file_offset = file_offset;
dip->bytes = dio_bio->bi_iter.bi_size;
refcount_set(&dip->refs, 1);
@@ -8050,7 +8133,7 @@ static void btrfs_submit_direct(const struct iomap_iter *iter,
async_submit = 1;
}
- btrfs_submit_dio_bio(bio, inode, file_offset, async_submit);
+ btrfs_submit_dio_bio(bio, BTRFS_I(inode), file_offset, async_submit);
dio_data->submitted += clone_len;
clone_offset += clone_len;
@@ -8540,16 +8623,16 @@ out_noreserve:
return ret;
}
-static int btrfs_truncate(struct inode *inode, bool skip_writeback)
+static int btrfs_truncate(struct btrfs_inode *inode, bool skip_writeback)
{
struct btrfs_truncate_control control = {
- .inode = BTRFS_I(inode),
- .ino = btrfs_ino(BTRFS_I(inode)),
+ .inode = inode,
+ .ino = btrfs_ino(inode),
.min_type = BTRFS_EXTENT_DATA_KEY,
.clear_extent_range = true,
};
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_root *root = inode->root;
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_block_rsv *rsv;
int ret;
struct btrfs_trans_handle *trans;
@@ -8557,7 +8640,8 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
u64 min_size = btrfs_calc_metadata_size(fs_info, 1);
if (!skip_writeback) {
- ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
+ ret = btrfs_wait_ordered_range(&inode->vfs_inode,
+ inode->vfs_inode.i_size & (~mask),
(u64)-1);
if (ret)
return ret;
@@ -8616,34 +8700,32 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
while (1) {
struct extent_state *cached_state = NULL;
- const u64 new_size = inode->i_size;
+ const u64 new_size = inode->vfs_inode.i_size;
const u64 lock_start = ALIGN_DOWN(new_size, fs_info->sectorsize);
control.new_size = new_size;
- lock_extent(&BTRFS_I(inode)->io_tree, lock_start, (u64)-1,
- &cached_state);
+ lock_extent(&inode->io_tree, lock_start, (u64)-1, &cached_state);
/*
* We want to drop from the next block forward in case this new
* size is not block aligned since we will be keeping the last
* block of the extent just the way it is.
*/
- btrfs_drop_extent_map_range(BTRFS_I(inode),
+ btrfs_drop_extent_map_range(inode,
ALIGN(new_size, fs_info->sectorsize),
(u64)-1, false);
ret = btrfs_truncate_inode_items(trans, root, &control);
- inode_sub_bytes(inode, control.sub_bytes);
- btrfs_inode_safe_disk_i_size_write(BTRFS_I(inode), control.last_size);
+ inode_sub_bytes(&inode->vfs_inode, control.sub_bytes);
+ btrfs_inode_safe_disk_i_size_write(inode, control.last_size);
- unlock_extent(&BTRFS_I(inode)->io_tree, lock_start, (u64)-1,
- &cached_state);
+ unlock_extent(&inode->io_tree, lock_start, (u64)-1, &cached_state);
trans->block_rsv = &fs_info->trans_block_rsv;
if (ret != -ENOSPC && ret != -EAGAIN)
break;
- ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
+ ret = btrfs_update_inode(trans, root, inode);
if (ret)
break;
@@ -8674,7 +8756,7 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
btrfs_end_transaction(trans);
btrfs_btree_balance_dirty(fs_info);
- ret = btrfs_truncate_block(BTRFS_I(inode), inode->i_size, 0, 0);
+ ret = btrfs_truncate_block(inode, inode->vfs_inode.i_size, 0, 0);
if (ret)
goto out;
trans = btrfs_start_transaction(root, 1);
@@ -8682,14 +8764,14 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
ret = PTR_ERR(trans);
goto out;
}
- btrfs_inode_safe_disk_i_size_write(BTRFS_I(inode), 0);
+ btrfs_inode_safe_disk_i_size_write(inode, 0);
}
if (trans) {
int ret2;
trans->block_rsv = &fs_info->trans_block_rsv;
- ret2 = btrfs_update_inode(trans, root, BTRFS_I(inode));
+ ret2 = btrfs_update_inode(trans, root, inode);
if (ret2 && !ret)
ret = ret2;
@@ -8715,7 +8797,7 @@ out:
* extents beyond i_size to drop.
*/
if (control.extents_found > 0)
- btrfs_set_inode_full_sync(BTRFS_I(inode));
+ btrfs_set_inode_full_sync(inode);
return ret;
}
@@ -8784,9 +8866,10 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
inode = &ei->vfs_inode;
extent_map_tree_init(&ei->extent_tree);
- extent_io_tree_init(fs_info, &ei->io_tree, IO_TREE_INODE_IO, inode);
+ extent_io_tree_init(fs_info, &ei->io_tree, IO_TREE_INODE_IO);
+ ei->io_tree.inode = ei;
extent_io_tree_init(fs_info, &ei->file_extent_tree,
- IO_TREE_INODE_FILE_EXTENT, NULL);
+ IO_TREE_INODE_FILE_EXTENT);
ei->io_failure_tree = RB_ROOT;
atomic_set(&ei->sync_writers, 0);
mutex_init(&ei->log_mutex);
@@ -8899,10 +8982,6 @@ void __cold btrfs_destroy_cachep(void)
rcu_barrier();
bioset_exit(&btrfs_dio_bioset);
kmem_cache_destroy(btrfs_inode_cachep);
- kmem_cache_destroy(btrfs_trans_handle_cachep);
- kmem_cache_destroy(btrfs_path_cachep);
- kmem_cache_destroy(btrfs_free_space_cachep);
- kmem_cache_destroy(btrfs_free_space_bitmap_cachep);
}
int __init btrfs_init_cachep(void)
@@ -8914,30 +8993,6 @@ int __init btrfs_init_cachep(void)
if (!btrfs_inode_cachep)
goto fail;
- btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle",
- sizeof(struct btrfs_trans_handle), 0,
- SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
- if (!btrfs_trans_handle_cachep)
- goto fail;
-
- btrfs_path_cachep = kmem_cache_create("btrfs_path",
- sizeof(struct btrfs_path), 0,
- SLAB_MEM_SPREAD, NULL);
- if (!btrfs_path_cachep)
- goto fail;
-
- btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space",
- sizeof(struct btrfs_free_space), 0,
- SLAB_MEM_SPREAD, NULL);
- if (!btrfs_free_space_cachep)
- goto fail;
-
- btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
- PAGE_SIZE, PAGE_SIZE,
- SLAB_MEM_SPREAD, NULL);
- if (!btrfs_free_space_bitmap_cachep)
- goto fail;
-
if (bioset_init(&btrfs_dio_bioset, BIO_POOL_SIZE,
offsetof(struct btrfs_dio_private, bio),
BIOSET_NEED_BVECS))
@@ -9013,6 +9068,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
int ret;
int ret2;
bool need_abort = false;
+ struct fscrypt_name old_fname, new_fname;
+ struct fscrypt_str *old_name, *new_name;
/*
* For non-subvolumes allow exchange only within one subvolume, in the
@@ -9024,6 +9081,19 @@ static int btrfs_rename_exchange(struct inode *old_dir,
new_ino != BTRFS_FIRST_FREE_OBJECTID))
return -EXDEV;
+ ret = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_fname);
+ if (ret)
+ return ret;
+
+ ret = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_fname);
+ if (ret) {
+ fscrypt_free_filename(&old_fname);
+ return ret;
+ }
+
+ old_name = &old_fname.disk_name;
+ new_name = &new_fname.disk_name;
+
/* close the race window with snapshot create/destroy ioctl */
if (old_ino == BTRFS_FIRST_FREE_OBJECTID ||
new_ino == BTRFS_FIRST_FREE_OBJECTID)
@@ -9091,10 +9161,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
/* force full log commit if subvolume involved. */
btrfs_set_log_full_commit(trans);
} else {
- ret = btrfs_insert_inode_ref(trans, dest,
- new_dentry->d_name.name,
- new_dentry->d_name.len,
- old_ino,
+ ret = btrfs_insert_inode_ref(trans, dest, new_name, old_ino,
btrfs_ino(BTRFS_I(new_dir)),
old_idx);
if (ret)
@@ -9107,10 +9174,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
/* force full log commit if subvolume involved. */
btrfs_set_log_full_commit(trans);
} else {
- ret = btrfs_insert_inode_ref(trans, root,
- old_dentry->d_name.name,
- old_dentry->d_name.len,
- new_ino,
+ ret = btrfs_insert_inode_ref(trans, root, old_name, new_ino,
btrfs_ino(BTRFS_I(old_dir)),
new_idx);
if (ret) {
@@ -9141,13 +9205,11 @@ static int btrfs_rename_exchange(struct inode *old_dir,
/* src is a subvolume */
if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
- ret = btrfs_unlink_subvol(trans, old_dir, old_dentry);
+ ret = btrfs_unlink_subvol(trans, BTRFS_I(old_dir), old_dentry);
} else { /* src is an inode */
ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir),
BTRFS_I(old_dentry->d_inode),
- old_dentry->d_name.name,
- old_dentry->d_name.len,
- &old_rename_ctx);
+ old_name, &old_rename_ctx);
if (!ret)
ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode));
}
@@ -9158,13 +9220,11 @@ static int btrfs_rename_exchange(struct inode *old_dir,
/* dest is a subvolume */
if (new_ino == BTRFS_FIRST_FREE_OBJECTID) {
- ret = btrfs_unlink_subvol(trans, new_dir, new_dentry);
+ ret = btrfs_unlink_subvol(trans, BTRFS_I(new_dir), new_dentry);
} else { /* dest is an inode */
ret = __btrfs_unlink_inode(trans, BTRFS_I(new_dir),
BTRFS_I(new_dentry->d_inode),
- new_dentry->d_name.name,
- new_dentry->d_name.len,
- &new_rename_ctx);
+ new_name, &new_rename_ctx);
if (!ret)
ret = btrfs_update_inode(trans, dest, BTRFS_I(new_inode));
}
@@ -9174,16 +9234,14 @@ static int btrfs_rename_exchange(struct inode *old_dir,
}
ret = btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode),
- new_dentry->d_name.name,
- new_dentry->d_name.len, 0, old_idx);
+ new_name, 0, old_idx);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out_fail;
}
ret = btrfs_add_link(trans, BTRFS_I(old_dir), BTRFS_I(new_inode),
- old_dentry->d_name.name,
- old_dentry->d_name.len, 0, new_idx);
+ old_name, 0, new_idx);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out_fail;
@@ -9226,6 +9284,8 @@ out_notrans:
old_ino == BTRFS_FIRST_FREE_OBJECTID)
up_read(&fs_info->subvol_sem);
+ fscrypt_free_filename(&new_fname);
+ fscrypt_free_filename(&old_fname);
return ret;
}
@@ -9265,6 +9325,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
int ret;
int ret2;
u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
+ struct fscrypt_name old_fname, new_fname;
if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
return -EPERM;
@@ -9281,22 +9342,28 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
new_inode->i_size > BTRFS_EMPTY_DIR_SIZE)
return -ENOTEMPTY;
+ ret = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_fname);
+ if (ret)
+ return ret;
- /* check for collisions, even if the name isn't there */
- ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino,
- new_dentry->d_name.name,
- new_dentry->d_name.len);
+ ret = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_fname);
+ if (ret) {
+ fscrypt_free_filename(&old_fname);
+ return ret;
+ }
+ /* check for collisions, even if the name isn't there */
+ ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, &new_fname.disk_name);
if (ret) {
if (ret == -EEXIST) {
/* we shouldn't get
* eexist without a new_inode */
if (WARN_ON(!new_inode)) {
- return ret;
+ goto out_fscrypt_names;
}
} else {
/* maybe -EOVERFLOW */
- return ret;
+ goto out_fscrypt_names;
}
}
ret = 0;
@@ -9379,11 +9446,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
/* force full log commit if subvolume involved. */
btrfs_set_log_full_commit(trans);
} else {
- ret = btrfs_insert_inode_ref(trans, dest,
- new_dentry->d_name.name,
- new_dentry->d_name.len,
- old_ino,
- btrfs_ino(BTRFS_I(new_dir)), index);
+ ret = btrfs_insert_inode_ref(trans, dest, &new_fname.disk_name,
+ old_ino, btrfs_ino(BTRFS_I(new_dir)),
+ index);
if (ret)
goto out_fail;
}
@@ -9402,13 +9467,11 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
BTRFS_I(old_inode), 1);
if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
- ret = btrfs_unlink_subvol(trans, old_dir, old_dentry);
+ ret = btrfs_unlink_subvol(trans, BTRFS_I(old_dir), old_dentry);
} else {
ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir),
- BTRFS_I(d_inode(old_dentry)),
- old_dentry->d_name.name,
- old_dentry->d_name.len,
- &rename_ctx);
+ BTRFS_I(d_inode(old_dentry)),
+ &old_fname.disk_name, &rename_ctx);
if (!ret)
ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode));
}
@@ -9422,13 +9485,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
new_inode->i_ctime = current_time(new_inode);
if (unlikely(btrfs_ino(BTRFS_I(new_inode)) ==
BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
- ret = btrfs_unlink_subvol(trans, new_dir, new_dentry);
+ ret = btrfs_unlink_subvol(trans, BTRFS_I(new_dir), new_dentry);
BUG_ON(new_inode->i_nlink == 0);
} else {
ret = btrfs_unlink_inode(trans, BTRFS_I(new_dir),
BTRFS_I(d_inode(new_dentry)),
- new_dentry->d_name.name,
- new_dentry->d_name.len);
+ &new_fname.disk_name);
}
if (!ret && new_inode->i_nlink == 0)
ret = btrfs_orphan_add(trans,
@@ -9440,8 +9502,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
}
ret = btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode),
- new_dentry->d_name.name,
- new_dentry->d_name.len, 0, index);
+ &new_fname.disk_name, 0, index);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out_fail;
@@ -9476,6 +9537,9 @@ out_notrans:
out_whiteout_inode:
if (flags & RENAME_WHITEOUT)
iput(whiteout_args.inode);
+out_fscrypt_names:
+ fscrypt_free_filename(&old_fname);
+ fscrypt_free_filename(&new_fname);
return ret;
}
@@ -9595,7 +9659,7 @@ static int start_delalloc_inodes(struct btrfs_root *root,
&work->work);
} else {
ret = filemap_fdatawrite_wbc(inode->i_mapping, wbc);
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
if (ret || wbc->nr_to_write <= 0)
goto out;
}
@@ -10205,7 +10269,7 @@ static ssize_t btrfs_encoded_read_inline(
read_extent_buffer(leaf, tmp, ptr, count);
btrfs_release_path(path);
unlock_extent(io_tree, start, lockend, cached_state);
- btrfs_inode_unlock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
*unlocked = true;
ret = copy_to_iter(tmp, count, iter);
@@ -10265,7 +10329,7 @@ static blk_status_t btrfs_encoded_read_verify_csum(struct btrfs_bio *bbio)
pgoff = bvec->bv_offset;
for (i = 0; i < nr_sectors; i++) {
ASSERT(pgoff < PAGE_SIZE);
- if (btrfs_check_data_csum(&inode->vfs_inode, bbio, bio_offset,
+ if (btrfs_check_data_csum(inode, bbio, bio_offset,
bvec->bv_page, pgoff))
return BLK_STS_IOERR;
bio_offset += sectorsize;
@@ -10408,7 +10472,7 @@ static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
goto out;
unlock_extent(io_tree, start, lockend, cached_state);
- btrfs_inode_unlock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
*unlocked = true;
if (compressed) {
@@ -10457,10 +10521,10 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
file_accessed(iocb->ki_filp);
- btrfs_inode_lock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
if (iocb->ki_pos >= inode->vfs_inode.i_size) {
- btrfs_inode_unlock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
return 0;
}
start = ALIGN_DOWN(iocb->ki_pos, fs_info->sectorsize);
@@ -10558,7 +10622,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
if (disk_bytenr == EXTENT_MAP_HOLE) {
unlock_extent(io_tree, start, lockend, &cached_state);
- btrfs_inode_unlock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
unlocked = true;
ret = iov_iter_zero(count, iter);
if (ret != count)
@@ -10581,7 +10645,7 @@ out_unlock_extent:
unlock_extent(io_tree, start, lockend, &cached_state);
out_unlock_inode:
if (!unlocked)
- btrfs_inode_unlock(&inode->vfs_inode, BTRFS_ILOCK_SHARED);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
return ret;
}
@@ -11247,7 +11311,7 @@ void btrfs_update_inode_bytes(struct btrfs_inode *inode,
spin_unlock(&inode->lock);
}
-/**
+/*
* Verify that there are no ordered extents for a given file range.
*
* @inode: The target inode.
@@ -11296,7 +11360,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.mknod = btrfs_mknod,
.listxattr = btrfs_listxattr,
.permission = btrfs_permission,
- .get_acl = btrfs_get_acl,
+ .get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
.tmpfile = btrfs_tmpfile,
@@ -11349,7 +11413,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
.listxattr = btrfs_listxattr,
.permission = btrfs_permission,
.fiemap = btrfs_fiemap,
- .get_acl = btrfs_get_acl,
+ .get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
.fileattr_get = btrfs_fileattr_get,
@@ -11360,7 +11424,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.setattr = btrfs_setattr,
.permission = btrfs_permission,
.listxattr = btrfs_listxattr,
- .get_acl = btrfs_get_acl,
+ .get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
};
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d5dd8bed1488..7e348bd2ccde 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -50,6 +50,17 @@
#include "delalloc-space.h"
#include "block-group.h"
#include "subpage.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "defrag.h"
+#include "dir-item.h"
+#include "uuid-tree.h"
+#include "ioctl.h"
+#include "file.h"
+#include "scrub.h"
+#include "super.h"
#ifdef CONFIG_64BIT
/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
@@ -949,6 +960,7 @@ static noinline int btrfs_mksubvol(const struct path *parent,
struct inode *dir = d_inode(parent->dentry);
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
struct dentry *dentry;
+ struct fscrypt_str name_str = FSTR_INIT((char *)name, namelen);
int error;
error = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT);
@@ -969,8 +981,7 @@ static noinline int btrfs_mksubvol(const struct path *parent,
* check for them now when we can safely fail
*/
error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
- dir->i_ino, name,
- namelen);
+ dir->i_ino, &name_str);
if (error)
goto out_dput;
@@ -991,7 +1002,7 @@ out_up_read:
out_dput:
dput(dentry);
out_unlock:
- btrfs_inode_unlock(dir, 0);
+ btrfs_inode_unlock(BTRFS_I(dir), 0);
return error;
}
@@ -1036,908 +1047,6 @@ out:
}
/*
- * Defrag specific helper to get an extent map.
- *
- * Differences between this and btrfs_get_extent() are:
- *
- * - No extent_map will be added to inode->extent_tree
- * To reduce memory usage in the long run.
- *
- * - Extra optimization to skip file extents older than @newer_than
- * By using btrfs_search_forward() we can skip entire file ranges that
- * have extents created in past transactions, because btrfs_search_forward()
- * will not visit leaves and nodes with a generation smaller than given
- * minimal generation threshold (@newer_than).
- *
- * Return valid em if we find a file extent matching the requirement.
- * Return NULL if we can not find a file extent matching the requirement.
- *
- * Return ERR_PTR() for error.
- */
-static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
- u64 start, u64 newer_than)
-{
- struct btrfs_root *root = inode->root;
- struct btrfs_file_extent_item *fi;
- struct btrfs_path path = { 0 };
- struct extent_map *em;
- struct btrfs_key key;
- u64 ino = btrfs_ino(inode);
- int ret;
-
- em = alloc_extent_map();
- if (!em) {
- ret = -ENOMEM;
- goto err;
- }
-
- key.objectid = ino;
- key.type = BTRFS_EXTENT_DATA_KEY;
- key.offset = start;
-
- if (newer_than) {
- ret = btrfs_search_forward(root, &key, &path, newer_than);
- if (ret < 0)
- goto err;
- /* Can't find anything newer */
- if (ret > 0)
- goto not_found;
- } else {
- ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
- if (ret < 0)
- goto err;
- }
- if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
- /*
- * If btrfs_search_slot() makes path to point beyond nritems,
- * we should not have an empty leaf, as this inode must at
- * least have its INODE_ITEM.
- */
- ASSERT(btrfs_header_nritems(path.nodes[0]));
- path.slots[0] = btrfs_header_nritems(path.nodes[0]) - 1;
- }
- btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
- /* Perfect match, no need to go one slot back */
- if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY &&
- key.offset == start)
- goto iterate;
-
- /* We didn't find a perfect match, needs to go one slot back */
- if (path.slots[0] > 0) {
- btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
- if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY)
- path.slots[0]--;
- }
-
-iterate:
- /* Iterate through the path to find a file extent covering @start */
- while (true) {
- u64 extent_end;
-
- if (path.slots[0] >= btrfs_header_nritems(path.nodes[0]))
- goto next;
-
- btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
-
- /*
- * We may go one slot back to INODE_REF/XATTR item, then
- * need to go forward until we reach an EXTENT_DATA.
- * But we should still has the correct ino as key.objectid.
- */
- if (WARN_ON(key.objectid < ino) || key.type < BTRFS_EXTENT_DATA_KEY)
- goto next;
-
- /* It's beyond our target range, definitely not extent found */
- if (key.objectid > ino || key.type > BTRFS_EXTENT_DATA_KEY)
- goto not_found;
-
- /*
- * | |<- File extent ->|
- * \- start
- *
- * This means there is a hole between start and key.offset.
- */
- if (key.offset > start) {
- em->start = start;
- em->orig_start = start;
- em->block_start = EXTENT_MAP_HOLE;
- em->len = key.offset - start;
- break;
- }
-
- fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
- struct btrfs_file_extent_item);
- extent_end = btrfs_file_extent_end(&path);
-
- /*
- * |<- file extent ->| |
- * \- start
- *
- * We haven't reached start, search next slot.
- */
- if (extent_end <= start)
- goto next;
-
- /* Now this extent covers @start, convert it to em */
- btrfs_extent_item_to_extent_map(inode, &path, fi, false, em);
- break;
-next:
- ret = btrfs_next_item(root, &path);
- if (ret < 0)
- goto err;
- if (ret > 0)
- goto not_found;
- }
- btrfs_release_path(&path);
- return em;
-
-not_found:
- btrfs_release_path(&path);
- free_extent_map(em);
- return NULL;
-
-err:
- btrfs_release_path(&path);
- free_extent_map(em);
- return ERR_PTR(ret);
-}
-
-static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
- u64 newer_than, bool locked)
-{
- struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
- struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
- struct extent_map *em;
- const u32 sectorsize = BTRFS_I(inode)->root->fs_info->sectorsize;
-
- /*
- * hopefully we have this extent in the tree already, try without
- * the full extent lock
- */
- read_lock(&em_tree->lock);
- em = lookup_extent_mapping(em_tree, start, sectorsize);
- read_unlock(&em_tree->lock);
-
- /*
- * We can get a merged extent, in that case, we need to re-search
- * tree to get the original em for defrag.
- *
- * If @newer_than is 0 or em::generation < newer_than, we can trust
- * this em, as either we don't care about the generation, or the
- * merged extent map will be rejected anyway.
- */
- if (em && test_bit(EXTENT_FLAG_MERGED, &em->flags) &&
- newer_than && em->generation >= newer_than) {
- free_extent_map(em);
- em = NULL;
- }
-
- if (!em) {
- struct extent_state *cached = NULL;
- u64 end = start + sectorsize - 1;
-
- /* get the big lock and read metadata off disk */
- if (!locked)
- lock_extent(io_tree, start, end, &cached);
- em = defrag_get_extent(BTRFS_I(inode), start, newer_than);
- if (!locked)
- unlock_extent(io_tree, start, end, &cached);
-
- if (IS_ERR(em))
- return NULL;
- }
-
- return em;
-}
-
-static u32 get_extent_max_capacity(const struct btrfs_fs_info *fs_info,
- const struct extent_map *em)
-{
- if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
- return BTRFS_MAX_COMPRESSED;
- return fs_info->max_extent_size;
-}
-
-static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
- u32 extent_thresh, u64 newer_than, bool locked)
-{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct extent_map *next;
- bool ret = false;
-
- /* this is the last extent */
- if (em->start + em->len >= i_size_read(inode))
- return false;
-
- /*
- * Here we need to pass @newer_then when checking the next extent, or
- * we will hit a case we mark current extent for defrag, but the next
- * one will not be a target.
- * This will just cause extra IO without really reducing the fragments.
- */
- next = defrag_lookup_extent(inode, em->start + em->len, newer_than, locked);
- /* No more em or hole */
- if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)
- goto out;
- if (test_bit(EXTENT_FLAG_PREALLOC, &next->flags))
- goto out;
- /*
- * If the next extent is at its max capacity, defragging current extent
- * makes no sense, as the total number of extents won't change.
- */
- if (next->len >= get_extent_max_capacity(fs_info, em))
- goto out;
- /* Skip older extent */
- if (next->generation < newer_than)
- goto out;
- /* Also check extent size */
- if (next->len >= extent_thresh)
- goto out;
-
- ret = true;
-out:
- free_extent_map(next);
- return ret;
-}
-
-/*
- * Prepare one page to be defragged.
- *
- * This will ensure:
- *
- * - Returned page is locked and has been set up properly.
- * - No ordered extent exists in the page.
- * - The page is uptodate.
- *
- * NOTE: Caller should also wait for page writeback after the cluster is
- * prepared, here we don't do writeback wait for each page.
- */
-static struct page *defrag_prepare_one_page(struct btrfs_inode *inode,
- pgoff_t index)
-{
- struct address_space *mapping = inode->vfs_inode.i_mapping;
- gfp_t mask = btrfs_alloc_write_mask(mapping);
- u64 page_start = (u64)index << PAGE_SHIFT;
- u64 page_end = page_start + PAGE_SIZE - 1;
- struct extent_state *cached_state = NULL;
- struct page *page;
- int ret;
-
-again:
- page = find_or_create_page(mapping, index, mask);
- if (!page)
- return ERR_PTR(-ENOMEM);
-
- /*
- * Since we can defragment files opened read-only, we can encounter
- * transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS). We
- * can't do I/O using huge pages yet, so return an error for now.
- * Filesystem transparent huge pages are typically only used for
- * executables that explicitly enable them, so this isn't very
- * restrictive.
- */
- if (PageCompound(page)) {
- unlock_page(page);
- put_page(page);
- return ERR_PTR(-ETXTBSY);
- }
-
- ret = set_page_extent_mapped(page);
- if (ret < 0) {
- unlock_page(page);
- put_page(page);
- return ERR_PTR(ret);
- }
-
- /* Wait for any existing ordered extent in the range */
- while (1) {
- struct btrfs_ordered_extent *ordered;
-
- lock_extent(&inode->io_tree, page_start, page_end, &cached_state);
- ordered = btrfs_lookup_ordered_range(inode, page_start, PAGE_SIZE);
- unlock_extent(&inode->io_tree, page_start, page_end,
- &cached_state);
- if (!ordered)
- break;
-
- unlock_page(page);
- btrfs_start_ordered_extent(ordered, 1);
- btrfs_put_ordered_extent(ordered);
- lock_page(page);
- /*
- * We unlocked the page above, so we need check if it was
- * released or not.
- */
- if (page->mapping != mapping || !PagePrivate(page)) {
- unlock_page(page);
- put_page(page);
- goto again;
- }
- }
-
- /*
- * Now the page range has no ordered extent any more. Read the page to
- * make it uptodate.
- */
- if (!PageUptodate(page)) {
- btrfs_read_folio(NULL, page_folio(page));
- lock_page(page);
- if (page->mapping != mapping || !PagePrivate(page)) {
- unlock_page(page);
- put_page(page);
- goto again;
- }
- if (!PageUptodate(page)) {
- unlock_page(page);
- put_page(page);
- return ERR_PTR(-EIO);
- }
- }
- return page;
-}
-
-struct defrag_target_range {
- struct list_head list;
- u64 start;
- u64 len;
-};
-
-/*
- * Collect all valid target extents.
- *
- * @start: file offset to lookup
- * @len: length to lookup
- * @extent_thresh: file extent size threshold, any extent size >= this value
- * will be ignored
- * @newer_than: only defrag extents newer than this value
- * @do_compress: whether the defrag is doing compression
- * if true, @extent_thresh will be ignored and all regular
- * file extents meeting @newer_than will be targets.
- * @locked: if the range has already held extent lock
- * @target_list: list of targets file extents
- */
-static int defrag_collect_targets(struct btrfs_inode *inode,
- u64 start, u64 len, u32 extent_thresh,
- u64 newer_than, bool do_compress,
- bool locked, struct list_head *target_list,
- u64 *last_scanned_ret)
-{
- struct btrfs_fs_info *fs_info = inode->root->fs_info;
- bool last_is_target = false;
- u64 cur = start;
- int ret = 0;
-
- while (cur < start + len) {
- struct extent_map *em;
- struct defrag_target_range *new;
- bool next_mergeable = true;
- u64 range_len;
-
- last_is_target = false;
- em = defrag_lookup_extent(&inode->vfs_inode, cur,
- newer_than, locked);
- if (!em)
- break;
-
- /*
- * If the file extent is an inlined one, we may still want to
- * defrag it (fallthrough) if it will cause a regular extent.
- * This is for users who want to convert inline extents to
- * regular ones through max_inline= mount option.
- */
- if (em->block_start == EXTENT_MAP_INLINE &&
- em->len <= inode->root->fs_info->max_inline)
- goto next;
-
- /* Skip hole/delalloc/preallocated extents */
- if (em->block_start == EXTENT_MAP_HOLE ||
- em->block_start == EXTENT_MAP_DELALLOC ||
- test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
- goto next;
-
- /* Skip older extent */
- if (em->generation < newer_than)
- goto next;
-
- /* This em is under writeback, no need to defrag */
- if (em->generation == (u64)-1)
- goto next;
-
- /*
- * Our start offset might be in the middle of an existing extent
- * map, so take that into account.
- */
- range_len = em->len - (cur - em->start);
- /*
- * If this range of the extent map is already flagged for delalloc,
- * skip it, because:
- *
- * 1) We could deadlock later, when trying to reserve space for
- * delalloc, because in case we can't immediately reserve space
- * the flusher can start delalloc and wait for the respective
- * ordered extents to complete. The deadlock would happen
- * because we do the space reservation while holding the range
- * locked, and starting writeback, or finishing an ordered
- * extent, requires locking the range;
- *
- * 2) If there's delalloc there, it means there's dirty pages for
- * which writeback has not started yet (we clean the delalloc
- * flag when starting writeback and after creating an ordered
- * extent). If we mark pages in an adjacent range for defrag,
- * then we will have a larger contiguous range for delalloc,
- * very likely resulting in a larger extent after writeback is
- * triggered (except in a case of free space fragmentation).
- */
- if (test_range_bit(&inode->io_tree, cur, cur + range_len - 1,
- EXTENT_DELALLOC, 0, NULL))
- goto next;
-
- /*
- * For do_compress case, we want to compress all valid file
- * extents, thus no @extent_thresh or mergeable check.
- */
- if (do_compress)
- goto add;
-
- /* Skip too large extent */
- if (range_len >= extent_thresh)
- goto next;
-
- /*
- * Skip extents already at its max capacity, this is mostly for
- * compressed extents, which max cap is only 128K.
- */
- if (em->len >= get_extent_max_capacity(fs_info, em))
- goto next;
-
- /*
- * Normally there are no more extents after an inline one, thus
- * @next_mergeable will normally be false and not defragged.
- * So if an inline extent passed all above checks, just add it
- * for defrag, and be converted to regular extents.
- */
- if (em->block_start == EXTENT_MAP_INLINE)
- goto add;
-
- next_mergeable = defrag_check_next_extent(&inode->vfs_inode, em,
- extent_thresh, newer_than, locked);
- if (!next_mergeable) {
- struct defrag_target_range *last;
-
- /* Empty target list, no way to merge with last entry */
- if (list_empty(target_list))
- goto next;
- last = list_entry(target_list->prev,
- struct defrag_target_range, list);
- /* Not mergeable with last entry */
- if (last->start + last->len != cur)
- goto next;
-
- /* Mergeable, fall through to add it to @target_list. */
- }
-
-add:
- last_is_target = true;
- range_len = min(extent_map_end(em), start + len) - cur;
- /*
- * This one is a good target, check if it can be merged into
- * last range of the target list.
- */
- if (!list_empty(target_list)) {
- struct defrag_target_range *last;
-
- last = list_entry(target_list->prev,
- struct defrag_target_range, list);
- ASSERT(last->start + last->len <= cur);
- if (last->start + last->len == cur) {
- /* Mergeable, enlarge the last entry */
- last->len += range_len;
- goto next;
- }
- /* Fall through to allocate a new entry */
- }
-
- /* Allocate new defrag_target_range */
- new = kmalloc(sizeof(*new), GFP_NOFS);
- if (!new) {
- free_extent_map(em);
- ret = -ENOMEM;
- break;
- }
- new->start = cur;
- new->len = range_len;
- list_add_tail(&new->list, target_list);
-
-next:
- cur = extent_map_end(em);
- free_extent_map(em);
- }
- if (ret < 0) {
- struct defrag_target_range *entry;
- struct defrag_target_range *tmp;
-
- list_for_each_entry_safe(entry, tmp, target_list, list) {
- list_del_init(&entry->list);
- kfree(entry);
- }
- }
- if (!ret && last_scanned_ret) {
- /*
- * If the last extent is not a target, the caller can skip to
- * the end of that extent.
- * Otherwise, we can only go the end of the specified range.
- */
- if (!last_is_target)
- *last_scanned_ret = max(cur, *last_scanned_ret);
- else
- *last_scanned_ret = max(start + len, *last_scanned_ret);
- }
- return ret;
-}
-
-#define CLUSTER_SIZE (SZ_256K)
-static_assert(IS_ALIGNED(CLUSTER_SIZE, PAGE_SIZE));
-
-/*
- * Defrag one contiguous target range.
- *
- * @inode: target inode
- * @target: target range to defrag
- * @pages: locked pages covering the defrag range
- * @nr_pages: number of locked pages
- *
- * Caller should ensure:
- *
- * - Pages are prepared
- * Pages should be locked, no ordered extent in the pages range,
- * no writeback.
- *
- * - Extent bits are locked
- */
-static int defrag_one_locked_target(struct btrfs_inode *inode,
- struct defrag_target_range *target,
- struct page **pages, int nr_pages,
- struct extent_state **cached_state)
-{
- struct btrfs_fs_info *fs_info = inode->root->fs_info;
- struct extent_changeset *data_reserved = NULL;
- const u64 start = target->start;
- const u64 len = target->len;
- unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
- unsigned long start_index = start >> PAGE_SHIFT;
- unsigned long first_index = page_index(pages[0]);
- int ret = 0;
- int i;
-
- ASSERT(last_index - first_index + 1 <= nr_pages);
-
- ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len);
- if (ret < 0)
- return ret;
- clear_extent_bit(&inode->io_tree, start, start + len - 1,
- EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
- EXTENT_DEFRAG, cached_state);
- set_extent_defrag(&inode->io_tree, start, start + len - 1, cached_state);
-
- /* Update the page status */
- for (i = start_index - first_index; i <= last_index - first_index; i++) {
- ClearPageChecked(pages[i]);
- btrfs_page_clamp_set_dirty(fs_info, pages[i], start, len);
- }
- btrfs_delalloc_release_extents(inode, len);
- extent_changeset_free(data_reserved);
-
- return ret;
-}
-
-static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
- u32 extent_thresh, u64 newer_than, bool do_compress,
- u64 *last_scanned_ret)
-{
- struct extent_state *cached_state = NULL;
- struct defrag_target_range *entry;
- struct defrag_target_range *tmp;
- LIST_HEAD(target_list);
- struct page **pages;
- const u32 sectorsize = inode->root->fs_info->sectorsize;
- u64 last_index = (start + len - 1) >> PAGE_SHIFT;
- u64 start_index = start >> PAGE_SHIFT;
- unsigned int nr_pages = last_index - start_index + 1;
- int ret = 0;
- int i;
-
- ASSERT(nr_pages <= CLUSTER_SIZE / PAGE_SIZE);
- ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(len, sectorsize));
-
- pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
- if (!pages)
- return -ENOMEM;
-
- /* Prepare all pages */
- for (i = 0; i < nr_pages; i++) {
- pages[i] = defrag_prepare_one_page(inode, start_index + i);
- if (IS_ERR(pages[i])) {
- ret = PTR_ERR(pages[i]);
- pages[i] = NULL;
- goto free_pages;
- }
- }
- for (i = 0; i < nr_pages; i++)
- wait_on_page_writeback(pages[i]);
-
- /* Lock the pages range */
- lock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
- (last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
- &cached_state);
- /*
- * Now we have a consistent view about the extent map, re-check
- * which range really needs to be defragged.
- *
- * And this time we have extent locked already, pass @locked = true
- * so that we won't relock the extent range and cause deadlock.
- */
- ret = defrag_collect_targets(inode, start, len, extent_thresh,
- newer_than, do_compress, true,
- &target_list, last_scanned_ret);
- if (ret < 0)
- goto unlock_extent;
-
- list_for_each_entry(entry, &target_list, list) {
- ret = defrag_one_locked_target(inode, entry, pages, nr_pages,
- &cached_state);
- if (ret < 0)
- break;
- }
-
- list_for_each_entry_safe(entry, tmp, &target_list, list) {
- list_del_init(&entry->list);
- kfree(entry);
- }
-unlock_extent:
- unlock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
- (last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
- &cached_state);
-free_pages:
- for (i = 0; i < nr_pages; i++) {
- if (pages[i]) {
- unlock_page(pages[i]);
- put_page(pages[i]);
- }
- }
- kfree(pages);
- return ret;
-}
-
-static int defrag_one_cluster(struct btrfs_inode *inode,
- struct file_ra_state *ra,
- u64 start, u32 len, u32 extent_thresh,
- u64 newer_than, bool do_compress,
- unsigned long *sectors_defragged,
- unsigned long max_sectors,
- u64 *last_scanned_ret)
-{
- const u32 sectorsize = inode->root->fs_info->sectorsize;
- struct defrag_target_range *entry;
- struct defrag_target_range *tmp;
- LIST_HEAD(target_list);
- int ret;
-
- ret = defrag_collect_targets(inode, start, len, extent_thresh,
- newer_than, do_compress, false,
- &target_list, NULL);
- if (ret < 0)
- goto out;
-
- list_for_each_entry(entry, &target_list, list) {
- u32 range_len = entry->len;
-
- /* Reached or beyond the limit */
- if (max_sectors && *sectors_defragged >= max_sectors) {
- ret = 1;
- break;
- }
-
- if (max_sectors)
- range_len = min_t(u32, range_len,
- (max_sectors - *sectors_defragged) * sectorsize);
-
- /*
- * If defrag_one_range() has updated last_scanned_ret,
- * our range may already be invalid (e.g. hole punched).
- * Skip if our range is before last_scanned_ret, as there is
- * no need to defrag the range anymore.
- */
- if (entry->start + range_len <= *last_scanned_ret)
- continue;
-
- if (ra)
- page_cache_sync_readahead(inode->vfs_inode.i_mapping,
- ra, NULL, entry->start >> PAGE_SHIFT,
- ((entry->start + range_len - 1) >> PAGE_SHIFT) -
- (entry->start >> PAGE_SHIFT) + 1);
- /*
- * Here we may not defrag any range if holes are punched before
- * we locked the pages.
- * But that's fine, it only affects the @sectors_defragged
- * accounting.
- */
- ret = defrag_one_range(inode, entry->start, range_len,
- extent_thresh, newer_than, do_compress,
- last_scanned_ret);
- if (ret < 0)
- break;
- *sectors_defragged += range_len >>
- inode->root->fs_info->sectorsize_bits;
- }
-out:
- list_for_each_entry_safe(entry, tmp, &target_list, list) {
- list_del_init(&entry->list);
- kfree(entry);
- }
- if (ret >= 0)
- *last_scanned_ret = max(*last_scanned_ret, start + len);
- return ret;
-}
-
-/*
- * Entry point to file defragmentation.
- *
- * @inode: inode to be defragged
- * @ra: readahead state (can be NUL)
- * @range: defrag options including range and flags
- * @newer_than: minimum transid to defrag
- * @max_to_defrag: max number of sectors to be defragged, if 0, the whole inode
- * will be defragged.
- *
- * Return <0 for error.
- * Return >=0 for the number of sectors defragged, and range->start will be updated
- * to indicate the file offset where next defrag should be started at.
- * (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
- * defragging all the range).
- */
-int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
- struct btrfs_ioctl_defrag_range_args *range,
- u64 newer_than, unsigned long max_to_defrag)
-{
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- unsigned long sectors_defragged = 0;
- u64 isize = i_size_read(inode);
- u64 cur;
- u64 last_byte;
- bool do_compress = range->flags & BTRFS_DEFRAG_RANGE_COMPRESS;
- bool ra_allocated = false;
- int compress_type = BTRFS_COMPRESS_ZLIB;
- int ret = 0;
- u32 extent_thresh = range->extent_thresh;
- pgoff_t start_index;
-
- if (isize == 0)
- return 0;
-
- if (range->start >= isize)
- return -EINVAL;
-
- if (do_compress) {
- if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES)
- return -EINVAL;
- if (range->compress_type)
- compress_type = range->compress_type;
- }
-
- if (extent_thresh == 0)
- extent_thresh = SZ_256K;
-
- if (range->start + range->len > range->start) {
- /* Got a specific range */
- last_byte = min(isize, range->start + range->len);
- } else {
- /* Defrag until file end */
- last_byte = isize;
- }
-
- /* Align the range */
- cur = round_down(range->start, fs_info->sectorsize);
- last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
-
- /*
- * If we were not given a ra, allocate a readahead context. As
- * readahead is just an optimization, defrag will work without it so
- * we don't error out.
- */
- if (!ra) {
- ra_allocated = true;
- ra = kzalloc(sizeof(*ra), GFP_KERNEL);
- if (ra)
- file_ra_state_init(ra, inode->i_mapping);
- }
-
- /*
- * Make writeback start from the beginning of the range, so that the
- * defrag range can be written sequentially.
- */
- start_index = cur >> PAGE_SHIFT;
- if (start_index < inode->i_mapping->writeback_index)
- inode->i_mapping->writeback_index = start_index;
-
- while (cur < last_byte) {
- const unsigned long prev_sectors_defragged = sectors_defragged;
- u64 last_scanned = cur;
- u64 cluster_end;
-
- if (btrfs_defrag_cancelled(fs_info)) {
- ret = -EAGAIN;
- break;
- }
-
- /* We want the cluster end at page boundary when possible */
- cluster_end = (((cur >> PAGE_SHIFT) +
- (SZ_256K >> PAGE_SHIFT)) << PAGE_SHIFT) - 1;
- cluster_end = min(cluster_end, last_byte);
-
- btrfs_inode_lock(inode, 0);
- if (IS_SWAPFILE(inode)) {
- ret = -ETXTBSY;
- btrfs_inode_unlock(inode, 0);
- break;
- }
- if (!(inode->i_sb->s_flags & SB_ACTIVE)) {
- btrfs_inode_unlock(inode, 0);
- break;
- }
- if (do_compress)
- BTRFS_I(inode)->defrag_compress = compress_type;
- ret = defrag_one_cluster(BTRFS_I(inode), ra, cur,
- cluster_end + 1 - cur, extent_thresh,
- newer_than, do_compress, &sectors_defragged,
- max_to_defrag, &last_scanned);
-
- if (sectors_defragged > prev_sectors_defragged)
- balance_dirty_pages_ratelimited(inode->i_mapping);
-
- btrfs_inode_unlock(inode, 0);
- if (ret < 0)
- break;
- cur = max(cluster_end + 1, last_scanned);
- if (ret > 0) {
- ret = 0;
- break;
- }
- cond_resched();
- }
-
- if (ra_allocated)
- kfree(ra);
- /*
- * Update range.start for autodefrag, this will indicate where to start
- * in next run.
- */
- range->start = cur;
- if (sectors_defragged) {
- /*
- * We have defragged some sectors, for compression case they
- * need to be written back immediately.
- */
- if (range->flags & BTRFS_DEFRAG_RANGE_START_IO) {
- filemap_flush(inode->i_mapping);
- if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
- &BTRFS_I(inode)->runtime_flags))
- filemap_flush(inode->i_mapping);
- }
- if (range->compress_type == BTRFS_COMPRESS_LZO)
- btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
- else if (range->compress_type == BTRFS_COMPRESS_ZSTD)
- btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
- ret = sectors_defragged;
- }
- if (do_compress) {
- btrfs_inode_lock(inode, 0);
- BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE;
- btrfs_inode_unlock(inode, 0);
- }
- return ret;
-}
-
-/*
* Try to start exclusive operation @type or cancel it if it's running.
*
* Return:
@@ -2119,7 +1228,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
if (ret == 0 && new_size != old_size)
btrfs_info_in_rcu(fs_info,
"resize device %s (devid %llu) from %llu to %llu",
- rcu_str_deref(device->name), device->devid,
+ btrfs_dev_name(device), device->devid,
old_size, new_size);
out_finish:
btrfs_exclop_finish(fs_info);
@@ -3105,6 +2214,8 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp)
}
}
+ btrfs_free_path(path);
+ path = NULL;
if (copy_to_user(argp, subvol_info, sizeof(*subvol_info)))
ret = -EFAULT;
@@ -3194,6 +2305,8 @@ static int btrfs_ioctl_get_subvol_rootref(struct btrfs_root *root,
}
out:
+ btrfs_free_path(path);
+
if (!ret || ret == -EOVERFLOW) {
rootrefs->num_items = found;
/* update min_treeid for next search */
@@ -3205,7 +2318,6 @@ out:
}
kfree(rootrefs);
- btrfs_free_path(path);
return ret;
}
@@ -3271,7 +2383,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
dentry = btrfs_get_dentry(fs_info->sb,
BTRFS_FIRST_FREE_OBJECTID,
- vol_args2->subvolid, 0, 0);
+ vol_args2->subvolid, 0);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out_drop_write;
@@ -3416,16 +2528,16 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
goto out_dput;
}
- btrfs_inode_lock(inode, 0);
- err = btrfs_delete_subvolume(dir, dentry);
- btrfs_inode_unlock(inode, 0);
+ btrfs_inode_lock(BTRFS_I(inode), 0);
+ err = btrfs_delete_subvolume(BTRFS_I(dir), dentry);
+ btrfs_inode_unlock(BTRFS_I(inode), 0);
if (!err)
d_delete_notify(dir, dentry);
out_dput:
dput(dentry);
out_unlock_dir:
- btrfs_inode_unlock(dir, 0);
+ btrfs_inode_unlock(BTRFS_I(dir), 0);
free_subvol_name:
kfree(subvol_name_ptr);
free_parent:
@@ -3747,13 +2859,10 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
di_args->bytes_used = btrfs_device_get_bytes_used(dev);
di_args->total_bytes = btrfs_device_get_total_bytes(dev);
memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
- if (dev->name) {
- strncpy(di_args->path, rcu_str_deref(dev->name),
- sizeof(di_args->path) - 1);
- di_args->path[sizeof(di_args->path) - 1] = 0;
- } else {
+ if (dev->name)
+ strscpy(di_args->path, btrfs_dev_name(dev), sizeof(di_args->path));
+ else
di_args->path[0] = '\0';
- }
out:
rcu_read_unlock();
@@ -3774,6 +2883,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
struct btrfs_trans_handle *trans;
struct btrfs_path *path = NULL;
struct btrfs_disk_key disk_key;
+ struct fscrypt_str name = FSTR_INIT("default", 7);
u64 objectid = 0;
u64 dir_id;
int ret;
@@ -3817,7 +2927,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
dir_id = btrfs_super_root_dir(fs_info->super_copy);
di = btrfs_lookup_dir_item(trans, fs_info->tree_root, path,
- dir_id, "default", 7, 1);
+ dir_id, &name, 1);
if (IS_ERR_OR_NULL(di)) {
btrfs_release_path(path);
btrfs_end_transaction(trans);
@@ -4231,6 +3341,8 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
ipath->fspath->val[i] = rel_ptr;
}
+ btrfs_free_path(path);
+ path = NULL;
ret = copy_to_user((void __user *)(unsigned long)ipa->fspath,
ipath->fspath, size);
if (ret) {
@@ -4281,21 +3393,20 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
size = min_t(u32, loi->size, SZ_16M);
}
- path = btrfs_alloc_path();
- if (!path) {
- ret = -ENOMEM;
- goto out;
- }
-
inodes = init_data_container(size);
if (IS_ERR(inodes)) {
ret = PTR_ERR(inodes);
- inodes = NULL;
- goto out;
+ goto out_loi;
}
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
ret = iterate_inodes_from_logical(loi->logical, fs_info, path,
inodes, ignore_offset);
+ btrfs_free_path(path);
if (ret == -EINVAL)
ret = -ENOENT;
if (ret < 0)
@@ -4307,7 +3418,6 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
ret = -EFAULT;
out:
- btrfs_free_path(path);
kvfree(inodes);
out_loi:
kfree(loi);
@@ -4338,7 +3448,7 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
spin_unlock(&fs_info->balance_lock);
}
-/**
+/*
* Try to acquire fs_info::balance_mutex as well as set BTRFS_EXLCOP_BALANCE as
* required.
*
@@ -5283,7 +4393,7 @@ static int btrfs_ioctl_encoded_read(struct file *file, void __user *argp,
goto out_acct;
}
- ret = import_iovec(READ, args.iov, args.iovcnt, ARRAY_SIZE(iovstack),
+ ret = import_iovec(ITER_DEST, args.iov, args.iovcnt, ARRAY_SIZE(iovstack),
&iov, &iter);
if (ret < 0)
goto out_acct;
@@ -5382,7 +4492,7 @@ static int btrfs_ioctl_encoded_write(struct file *file, void __user *argp, bool
if (args.len > args.unencoded_len - args.unencoded_offset)
goto out_acct;
- ret = import_iovec(WRITE, args.iov, args.iovcnt, ARRAY_SIZE(iovstack),
+ ret = import_iovec(ITER_SOURCE, args.iov, args.iovcnt, ARRAY_SIZE(iovstack),
&iov, &iter);
if (ret < 0)
goto out_acct;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
new file mode 100644
index 000000000000..8a855d5ac2fa
--- /dev/null
+++ b/fs/btrfs/ioctl.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_IOCTL_H
+#define BTRFS_IOCTL_H
+
+long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
+int btrfs_fileattr_set(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct fileattr *fa);
+int btrfs_ioctl_get_supported_features(void __user *arg);
+void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
+int __pure btrfs_is_empty_uuid(u8 *uuid);
+void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
+ struct btrfs_ioctl_balance_args *bargs);
+
+#endif
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c
index 0eab3cb274a1..870528d87526 100644
--- a/fs/btrfs/locking.c
+++ b/fs/btrfs/locking.c
@@ -12,6 +12,7 @@
#include "ctree.h"
#include "extent_io.h"
#include "locking.h"
+#include "accessors.h"
/*
* Lockdep class keys for extent_buffer->lock's in this root. For a given
diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h
index 490c7a79e995..11c2269b4b6f 100644
--- a/fs/btrfs/locking.h
+++ b/fs/btrfs/locking.h
@@ -78,6 +78,82 @@ enum btrfs_lock_nesting {
BTRFS_NESTING_MAX,
};
+enum btrfs_lockdep_trans_states {
+ BTRFS_LOCKDEP_TRANS_COMMIT_START,
+ BTRFS_LOCKDEP_TRANS_UNBLOCKED,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED,
+ BTRFS_LOCKDEP_TRANS_COMPLETED,
+};
+
+/*
+ * Lockdep annotation for wait events.
+ *
+ * @owner: The struct where the lockdep map is defined
+ * @lock: The lockdep map corresponding to a wait event
+ *
+ * This macro is used to annotate a wait event. In this case a thread acquires
+ * the lockdep map as writer (exclusive lock) because it has to block until all
+ * the threads that hold the lock as readers signal the condition for the wait
+ * event and release their locks.
+ */
+#define btrfs_might_wait_for_event(owner, lock) \
+ do { \
+ rwsem_acquire(&owner->lock##_map, 0, 0, _THIS_IP_); \
+ rwsem_release(&owner->lock##_map, _THIS_IP_); \
+ } while (0)
+
+/*
+ * Protection for the resource/condition of a wait event.
+ *
+ * @owner: The struct where the lockdep map is defined
+ * @lock: The lockdep map corresponding to a wait event
+ *
+ * Many threads can modify the condition for the wait event at the same time
+ * and signal the threads that block on the wait event. The threads that modify
+ * the condition and do the signaling acquire the lock as readers (shared
+ * lock).
+ */
+#define btrfs_lockdep_acquire(owner, lock) \
+ rwsem_acquire_read(&owner->lock##_map, 0, 0, _THIS_IP_)
+
+/*
+ * Used after signaling the condition for a wait event to release the lockdep
+ * map held by a reader thread.
+ */
+#define btrfs_lockdep_release(owner, lock) \
+ rwsem_release(&owner->lock##_map, _THIS_IP_)
+
+/*
+ * Macros for the transaction states wait events, similar to the generic wait
+ * event macros.
+ */
+#define btrfs_might_wait_for_state(owner, i) \
+ do { \
+ rwsem_acquire(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_); \
+ rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_); \
+ } while (0)
+
+#define btrfs_trans_state_lockdep_acquire(owner, i) \
+ rwsem_acquire_read(&owner->btrfs_state_change_map[i], 0, 0, _THIS_IP_)
+
+#define btrfs_trans_state_lockdep_release(owner, i) \
+ rwsem_release(&owner->btrfs_state_change_map[i], _THIS_IP_)
+
+/* Initialization of the lockdep map */
+#define btrfs_lockdep_init_map(owner, lock) \
+ do { \
+ static struct lock_class_key lock##_key; \
+ lockdep_init_map(&owner->lock##_map, #lock, &lock##_key, 0); \
+ } while (0)
+
+/* Initialization of the transaction states lockdep maps. */
+#define btrfs_state_lockdep_init_map(owner, lock, state) \
+ do { \
+ static struct lock_class_key lock##_key; \
+ lockdep_init_map(&owner->btrfs_state_change_map[state], #lock, \
+ &lock##_key, 0); \
+ } while (0)
+
static_assert(BTRFS_NESTING_MAX <= MAX_LOCKDEP_SUBCLASSES,
"too many lock subclasses defined");
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 89bc5f825e0a..d5e78cbc8fbc 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -13,8 +13,10 @@
#include <linux/bio.h>
#include <linux/lzo.h>
#include <linux/refcount.h>
+#include "messages.h"
#include "compression.h"
#include "ctree.h"
+#include "super.h"
#define LZO_LEN 4
@@ -425,7 +427,7 @@ out:
return ret;
}
-int lzo_decompress(struct list_head *ws, unsigned char *data_in,
+int lzo_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen)
{
diff --git a/fs/btrfs/messages.c b/fs/btrfs/messages.c
new file mode 100644
index 000000000000..625bbbbb2608
--- /dev/null
+++ b/fs/btrfs/messages.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "fs.h"
+#include "messages.h"
+#include "discard.h"
+#include "transaction.h"
+#include "space-info.h"
+#include "super.h"
+
+#ifdef CONFIG_PRINTK
+
+#define STATE_STRING_PREFACE ": state "
+#define STATE_STRING_BUF_LEN (sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT)
+
+/*
+ * Characters to print to indicate error conditions or uncommon filesystem state.
+ * RO is not an error.
+ */
+static const char fs_state_chars[] = {
+ [BTRFS_FS_STATE_ERROR] = 'E',
+ [BTRFS_FS_STATE_REMOUNTING] = 'M',
+ [BTRFS_FS_STATE_RO] = 0,
+ [BTRFS_FS_STATE_TRANS_ABORTED] = 'A',
+ [BTRFS_FS_STATE_DEV_REPLACING] = 'R',
+ [BTRFS_FS_STATE_DUMMY_FS_INFO] = 0,
+ [BTRFS_FS_STATE_NO_CSUMS] = 'C',
+ [BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L',
+};
+
+static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf)
+{
+ unsigned int bit;
+ bool states_printed = false;
+ unsigned long fs_state = READ_ONCE(info->fs_state);
+ char *curr = buf;
+
+ memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE));
+ curr += sizeof(STATE_STRING_PREFACE) - 1;
+
+ for_each_set_bit(bit, &fs_state, sizeof(fs_state)) {
+ WARN_ON_ONCE(bit >= BTRFS_FS_STATE_COUNT);
+ if ((bit < BTRFS_FS_STATE_COUNT) && fs_state_chars[bit]) {
+ *curr++ = fs_state_chars[bit];
+ states_printed = true;
+ }
+ }
+
+ /* If no states were printed, reset the buffer */
+ if (!states_printed)
+ curr = buf;
+
+ *curr++ = 0;
+}
+#endif
+
+/*
+ * Generally the error codes correspond to their respective errors, but there
+ * are a few special cases.
+ *
+ * EUCLEAN: Any sort of corruption that we encounter. The tree-checker for
+ * instance will return EUCLEAN if any of the blocks are corrupted in
+ * a way that is problematic. We want to reserve EUCLEAN for these
+ * sort of corruptions.
+ *
+ * EROFS: If we check BTRFS_FS_STATE_ERROR and fail out with a return error, we
+ * need to use EROFS for this case. We will have no idea of the
+ * original failure, that will have been reported at the time we tripped
+ * over the error. Each subsequent error that doesn't have any context
+ * of the original error should use EROFS when handling BTRFS_FS_STATE_ERROR.
+ */
+const char * __attribute_const__ btrfs_decode_error(int errno)
+{
+ char *errstr = "unknown";
+
+ switch (errno) {
+ case -ENOENT: /* -2 */
+ errstr = "No such entry";
+ break;
+ case -EIO: /* -5 */
+ errstr = "IO failure";
+ break;
+ case -ENOMEM: /* -12*/
+ errstr = "Out of memory";
+ break;
+ case -EEXIST: /* -17 */
+ errstr = "Object already exists";
+ break;
+ case -ENOSPC: /* -28 */
+ errstr = "No space left";
+ break;
+ case -EROFS: /* -30 */
+ errstr = "Readonly filesystem";
+ break;
+ case -EOPNOTSUPP: /* -95 */
+ errstr = "Operation not supported";
+ break;
+ case -EUCLEAN: /* -117 */
+ errstr = "Filesystem corrupted";
+ break;
+ case -EDQUOT: /* -122 */
+ errstr = "Quota exceeded";
+ break;
+ }
+
+ return errstr;
+}
+
+/*
+ * __btrfs_handle_fs_error decodes expected errors from the caller and
+ * invokes the appropriate error response.
+ */
+__cold
+void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno, const char *fmt, ...)
+{
+ struct super_block *sb = fs_info->sb;
+#ifdef CONFIG_PRINTK
+ char statestr[STATE_STRING_BUF_LEN];
+ const char *errstr;
+#endif
+
+#ifdef CONFIG_PRINTK_INDEX
+ printk_index_subsys_emit(
+ "BTRFS: error (device %s%s) in %s:%d: errno=%d %s", KERN_CRIT, fmt);
+#endif
+
+ /*
+ * Special case: if the error is EROFS, and we're already under
+ * SB_RDONLY, then it is safe here.
+ */
+ if (errno == -EROFS && sb_rdonly(sb))
+ return;
+
+#ifdef CONFIG_PRINTK
+ errstr = btrfs_decode_error(errno);
+ btrfs_state_to_string(fs_info, statestr);
+ if (fmt) {
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s (%pV)\n",
+ sb->s_id, statestr, function, line, errno, errstr, &vaf);
+ va_end(args);
+ } else {
+ pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s\n",
+ sb->s_id, statestr, function, line, errno, errstr);
+ }
+#endif
+
+ /*
+ * Today we only save the error info to memory. Long term we'll also
+ * send it down to the disk.
+ */
+ set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
+
+ /* Don't go through full error handling during mount. */
+ if (!(sb->s_flags & SB_BORN))
+ return;
+
+ if (sb_rdonly(sb))
+ return;
+
+ btrfs_discard_stop(fs_info);
+
+ /* Handle error by forcing the filesystem readonly. */
+ btrfs_set_sb_rdonly(sb);
+ btrfs_info(fs_info, "forced readonly");
+ /*
+ * Note that a running device replace operation is not canceled here
+ * although there is no way to update the progress. It would add the
+ * risk of a deadlock, therefore the canceling is omitted. The only
+ * penalty is that some I/O remains active until the procedure
+ * completes. The next time when the filesystem is mounted writable
+ * again, the device replace operation continues.
+ */
+}
+
+#ifdef CONFIG_PRINTK
+static const char * const logtypes[] = {
+ "emergency",
+ "alert",
+ "critical",
+ "error",
+ "warning",
+ "notice",
+ "info",
+ "debug",
+};
+
+/*
+ * Use one ratelimit state per log level so that a flood of less important
+ * messages doesn't cause more important ones to be dropped.
+ */
+static struct ratelimit_state printk_limits[] = {
+ RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100),
+ RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100),
+};
+
+void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+ char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0";
+ struct va_format vaf;
+ va_list args;
+ int kern_level;
+ const char *type = logtypes[4];
+ struct ratelimit_state *ratelimit = &printk_limits[4];
+
+#ifdef CONFIG_PRINTK_INDEX
+ printk_index_subsys_emit("%sBTRFS %s (device %s): ", NULL, fmt);
+#endif
+
+ va_start(args, fmt);
+
+ while ((kern_level = printk_get_level(fmt)) != 0) {
+ size_t size = printk_skip_level(fmt) - fmt;
+
+ if (kern_level >= '0' && kern_level <= '7') {
+ memcpy(lvl, fmt, size);
+ lvl[size] = '\0';
+ type = logtypes[kern_level - '0'];
+ ratelimit = &printk_limits[kern_level - '0'];
+ }
+ fmt += size;
+ }
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ if (__ratelimit(ratelimit)) {
+ if (fs_info) {
+ char statestr[STATE_STRING_BUF_LEN];
+
+ btrfs_state_to_string(fs_info, statestr);
+ _printk("%sBTRFS %s (device %s%s): %pV\n", lvl, type,
+ fs_info->sb->s_id, statestr, &vaf);
+ } else {
+ _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf);
+ }
+ }
+
+ va_end(args);
+}
+#endif
+
+#ifdef CONFIG_BTRFS_ASSERT
+void __cold btrfs_assertfail(const char *expr, const char *file, int line)
+{
+ pr_err("assertion failed: %s, in %s:%d\n", expr, file, line);
+ BUG();
+}
+#endif
+
+void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info)
+{
+ btrfs_err(fs_info,
+"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel");
+}
+
+#if BITS_PER_LONG == 32
+void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info)
+{
+ if (!test_and_set_bit(BTRFS_FS_32BIT_WARN, &fs_info->flags)) {
+ btrfs_warn(fs_info, "reaching 32bit limit for logical addresses");
+ btrfs_warn(fs_info,
+"due to page cache limit on 32bit systems, btrfs can't access metadata at or beyond %lluT",
+ BTRFS_32BIT_MAX_FILE_SIZE >> 40);
+ btrfs_warn(fs_info,
+ "please consider upgrading to 64bit kernel/hardware");
+ }
+}
+
+void __cold btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info)
+{
+ if (!test_and_set_bit(BTRFS_FS_32BIT_ERROR, &fs_info->flags)) {
+ btrfs_err(fs_info, "reached 32bit limit for logical addresses");
+ btrfs_err(fs_info,
+"due to page cache limit on 32bit systems, metadata beyond %lluT can't be accessed",
+ BTRFS_32BIT_MAX_FILE_SIZE >> 40);
+ btrfs_err(fs_info,
+ "please consider upgrading to 64bit kernel/hardware");
+ }
+}
+#endif
+
+/*
+ * We only mark the transaction aborted and then set the file system read-only.
+ * This will prevent new transactions from starting or trying to join this
+ * one.
+ *
+ * This means that error recovery at the call site is limited to freeing
+ * any local memory allocations and passing the error code up without
+ * further cleanup. The transaction should complete as it normally would
+ * in the call path but will return -EIO.
+ *
+ * We'll complete the cleanup in btrfs_end_transaction and
+ * btrfs_commit_transaction.
+ */
+__cold
+void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
+ const char *function,
+ unsigned int line, int errno, bool first_hit)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+
+ WRITE_ONCE(trans->aborted, errno);
+ WRITE_ONCE(trans->transaction->aborted, errno);
+ if (first_hit && errno == -ENOSPC)
+ btrfs_dump_space_info_for_trans_abort(fs_info);
+ /* Wake up anybody who may be waiting on this transaction */
+ wake_up(&fs_info->transaction_wait);
+ wake_up(&fs_info->transaction_blocked_wait);
+ __btrfs_handle_fs_error(fs_info, function, line, errno, NULL);
+}
+
+/*
+ * __btrfs_panic decodes unexpected, fatal errors from the caller, issues an
+ * alert, and either panics or BUGs, depending on mount options.
+ */
+__cold
+void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno, const char *fmt, ...)
+{
+ char *s_id = "<unknown>";
+ const char *errstr;
+ struct va_format vaf = { .fmt = fmt };
+ va_list args;
+
+ if (fs_info)
+ s_id = fs_info->sb->s_id;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+
+ errstr = btrfs_decode_error(errno);
+ if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR)))
+ panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n",
+ s_id, function, line, &vaf, errno, errstr);
+
+ btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)",
+ function, line, &vaf, errno, errstr);
+ va_end(args);
+ /* Caller calls BUG() */
+}
diff --git a/fs/btrfs/messages.h b/fs/btrfs/messages.h
new file mode 100644
index 000000000000..190af1f698d9
--- /dev/null
+++ b/fs/btrfs/messages.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_MESSAGES_H
+#define BTRFS_MESSAGES_H
+
+#include <linux/types.h>
+
+struct btrfs_fs_info;
+struct btrfs_trans_handle;
+
+static inline __printf(2, 3) __cold
+void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+}
+
+#ifdef CONFIG_PRINTK
+
+#define btrfs_printk(fs_info, fmt, args...) \
+ _btrfs_printk(fs_info, fmt, ##args)
+
+__printf(2, 3)
+__cold
+void _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...);
+
+#else
+
+#define btrfs_printk(fs_info, fmt, args...) \
+ btrfs_no_printk(fs_info, fmt, ##args)
+#endif
+
+#define btrfs_emerg(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_INFO fmt, ##args)
+
+/*
+ * Wrappers that use printk_in_rcu
+ */
+#define btrfs_emerg_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_INFO fmt, ##args)
+
+/*
+ * Wrappers that use a ratelimited printk_in_rcu
+ */
+#define btrfs_emerg_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_INFO fmt, ##args)
+
+/*
+ * Wrappers that use a ratelimited printk
+ */
+#define btrfs_emerg_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_INFO fmt, ##args)
+
+#if defined(CONFIG_DYNAMIC_DEBUG)
+#define btrfs_debug(fs_info, fmt, args...) \
+ _dynamic_func_call_no_desc(fmt, btrfs_printk, \
+ fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
+ _dynamic_func_call_no_desc(fmt, btrfs_printk_in_rcu, \
+ fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
+ _dynamic_func_call_no_desc(fmt, btrfs_printk_rl_in_rcu, \
+ fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl(fs_info, fmt, args...) \
+ _dynamic_func_call_no_desc(fmt, btrfs_printk_ratelimited, \
+ fs_info, KERN_DEBUG fmt, ##args)
+#elif defined(DEBUG)
+#define btrfs_debug(fs_info, fmt, args...) \
+ btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl(fs_info, fmt, args...) \
+ btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, ##args)
+#else
+#define btrfs_debug(fs_info, fmt, args...) \
+ btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
+ btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
+ btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl(fs_info, fmt, args...) \
+ btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
+#endif
+
+#define btrfs_printk_in_rcu(fs_info, fmt, args...) \
+do { \
+ rcu_read_lock(); \
+ btrfs_printk(fs_info, fmt, ##args); \
+ rcu_read_unlock(); \
+} while (0)
+
+#define btrfs_no_printk_in_rcu(fs_info, fmt, args...) \
+do { \
+ rcu_read_lock(); \
+ btrfs_no_printk(fs_info, fmt, ##args); \
+ rcu_read_unlock(); \
+} while (0)
+
+#define btrfs_printk_ratelimited(fs_info, fmt, args...) \
+do { \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ DEFAULT_RATELIMIT_INTERVAL, \
+ DEFAULT_RATELIMIT_BURST); \
+ if (__ratelimit(&_rs)) \
+ btrfs_printk(fs_info, fmt, ##args); \
+} while (0)
+
+#define btrfs_printk_rl_in_rcu(fs_info, fmt, args...) \
+do { \
+ rcu_read_lock(); \
+ btrfs_printk_ratelimited(fs_info, fmt, ##args); \
+ rcu_read_unlock(); \
+} while (0)
+
+#ifdef CONFIG_BTRFS_ASSERT
+void __cold btrfs_assertfail(const char *expr, const char *file, int line);
+
+#define ASSERT(expr) \
+ (likely(expr) ? (void)0 : btrfs_assertfail(#expr, __FILE__, __LINE__))
+#else
+#define ASSERT(expr) (void)(expr)
+#endif
+
+void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info);
+
+__printf(5, 6)
+__cold
+void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno, const char *fmt, ...);
+
+const char * __attribute_const__ btrfs_decode_error(int errno);
+
+__cold
+void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
+ const char *function,
+ unsigned int line, int errno, bool first_hit);
+
+bool __cold abort_should_print_stack(int errno);
+
+/*
+ * Call btrfs_abort_transaction as early as possible when an error condition is
+ * detected, that way the exact stack trace is reported for some errors.
+ */
+#define btrfs_abort_transaction(trans, errno) \
+do { \
+ bool first = false; \
+ /* Report first abort since mount */ \
+ if (!test_and_set_bit(BTRFS_FS_STATE_TRANS_ABORTED, \
+ &((trans)->fs_info->fs_state))) { \
+ first = true; \
+ if (WARN(abort_should_print_stack(errno), \
+ KERN_ERR \
+ "BTRFS: Transaction aborted (error %d)\n", \
+ (errno))) { \
+ /* Stack trace printed. */ \
+ } else { \
+ btrfs_err((trans)->fs_info, \
+ "Transaction aborted (error %d)", \
+ (errno)); \
+ } \
+ } \
+ __btrfs_abort_transaction((trans), __func__, \
+ __LINE__, (errno), first); \
+} while (0)
+
+#define btrfs_handle_fs_error(fs_info, errno, fmt, args...) \
+ __btrfs_handle_fs_error((fs_info), __func__, __LINE__, \
+ (errno), fmt, ##args)
+
+__printf(5, 6)
+__cold
+void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno, const char *fmt, ...);
+/*
+ * If BTRFS_MOUNT_PANIC_ON_FATAL_ERROR is in mount_opt, __btrfs_panic
+ * will panic(). Otherwise we BUG() here.
+ */
+#define btrfs_panic(fs_info, errno, fmt, args...) \
+do { \
+ __btrfs_panic(fs_info, __func__, __LINE__, errno, fmt, ##args); \
+ BUG(); \
+} while (0)
+
+#if BITS_PER_LONG == 32
+#define BTRFS_32BIT_MAX_FILE_SIZE (((u64)ULONG_MAX + 1) << PAGE_SHIFT)
+/*
+ * The warning threshold is 5/8th of the MAX_LFS_FILESIZE that limits the logical
+ * addresses of extents.
+ *
+ * For 4K page size it's about 10T, for 64K it's 160T.
+ */
+#define BTRFS_32BIT_EARLY_WARN_THRESHOLD (BTRFS_32BIT_MAX_FILE_SIZE * 5 / 8)
+void btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info);
+void btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info);
+#endif
+
+#endif
diff --git a/fs/btrfs/misc.h b/fs/btrfs/misc.h
index f9850edfd726..768583a440e1 100644
--- a/fs/btrfs/misc.h
+++ b/fs/btrfs/misc.h
@@ -10,6 +10,14 @@
#define in_range(b, first, len) ((b) >= (first) && (b) < (first) + (len))
+/*
+ * Enumerate bits using enum autoincrement. Define the @name as the n-th bit.
+ */
+#define ENUM_BIT(name) \
+ __ ## name ## _BIT, \
+ name = (1U << __ ## name ## _BIT), \
+ __ ## name ## _SEQ = __ ## name ## _BIT
+
static inline void cond_wake_up(struct wait_queue_head *wq)
{
/*
@@ -32,22 +40,10 @@ static inline void cond_wake_up_nomb(struct wait_queue_head *wq)
wake_up(wq);
}
-static inline u64 div_factor(u64 num, int factor)
+static inline u64 mult_perc(u64 num, u32 percent)
{
- if (factor == 10)
- return num;
- num *= factor;
- return div_u64(num, 10);
+ return div_u64(num * percent, 100);
}
-
-static inline u64 div_factor_fine(u64 num, int factor)
-{
- if (factor == 100)
- return num;
- num *= factor;
- return div_u64(num, 100);
-}
-
/* Copy of is_power_of_two that is 64bit safe */
static inline bool is_power_of_two_u64(u64 n)
{
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index e54f8280031f..57d8c72737e1 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -7,6 +7,7 @@
#include <linux/blkdev.h>
#include <linux/writeback.h>
#include <linux/sched/mm.h>
+#include "messages.h"
#include "misc.h"
#include "ctree.h"
#include "transaction.h"
@@ -17,6 +18,8 @@
#include "delalloc-space.h"
#include "qgroup.h"
#include "subpage.h"
+#include "file.h"
+#include "super.h"
static struct kmem_cache *btrfs_ordered_extent_cache;
@@ -143,7 +146,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
return ret;
}
-/**
+/*
* Add an ordered extent to the per-inode tree.
*
* @inode: Inode that this extent is for.
@@ -501,7 +504,7 @@ void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
ASSERT(list_empty(&entry->log_list));
ASSERT(RB_EMPTY_NODE(&entry->rb_node));
if (entry->inode)
- btrfs_add_delayed_iput(entry->inode);
+ btrfs_add_delayed_iput(BTRFS_I(entry->inode));
while (!list_empty(&entry->list)) {
cur = entry->list.next;
sum = list_entry(cur, struct btrfs_ordered_sum, list);
@@ -761,11 +764,11 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
struct btrfs_ordered_extent *ordered;
if (start + len < start) {
- orig_end = INT_LIMIT(loff_t);
+ orig_end = OFFSET_MAX;
} else {
orig_end = start + len - 1;
- if (orig_end > INT_LIMIT(loff_t))
- orig_end = INT_LIMIT(loff_t);
+ if (orig_end > OFFSET_MAX)
+ orig_end = OFFSET_MAX;
}
/* start IO across the range first to instantiate any delalloc
@@ -1019,17 +1022,18 @@ out:
}
/*
- * btrfs_flush_ordered_range - Lock the passed range and ensures all pending
- * ordered extents in it are run to completion.
+ * Lock the passed range and ensures all pending ordered extents in it are run
+ * to completion.
*
* @inode: Inode whose ordered tree is to be searched
* @start: Beginning of range to flush
* @end: Last byte of range to lock
* @cached_state: If passed, will return the extent state responsible for the
- * locked range. It's the caller's responsibility to free the cached state.
+ * locked range. It's the caller's responsibility to free the
+ * cached state.
*
- * This function always returns with the given range locked, ensuring after it's
- * called no order extent can be pending.
+ * Always return with the given range locked, ensuring after it's called no
+ * order extent can be pending.
*/
void btrfs_lock_and_flush_ordered_range(struct btrfs_inode *inode, u64 start,
u64 end,
@@ -1069,11 +1073,12 @@ void btrfs_lock_and_flush_ordered_range(struct btrfs_inode *inode, u64 start,
* Return true if btrfs_lock_ordered_range does not return any extents,
* otherwise false.
*/
-bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end)
+bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state)
{
struct btrfs_ordered_extent *ordered;
- if (!try_lock_extent(&inode->io_tree, start, end))
+ if (!try_lock_extent(&inode->io_tree, start, end, cached_state))
return false;
ordered = btrfs_lookup_ordered_range(inode, start, end - start + 1);
@@ -1081,7 +1086,7 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end)
return true;
btrfs_put_ordered_extent(ordered);
- unlock_extent(&inode->io_tree, start, end, NULL);
+ unlock_extent(&inode->io_tree, start, end, cached_state);
return false;
}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index f59f2dbdb25e..89f82b78f590 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -206,7 +206,8 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
void btrfs_lock_and_flush_ordered_range(struct btrfs_inode *inode, u64 start,
u64 end,
struct extent_state **cached_state);
-bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end);
+bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state);
int btrfs_split_ordered_extent(struct btrfs_ordered_extent *ordered, u64 pre,
u64 post);
int __init ordered_data_init(void);
diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c
index aa534108c1e2..7a1b021b5669 100644
--- a/fs/btrfs/orphan.c
+++ b/fs/btrfs/orphan.c
@@ -5,6 +5,7 @@
#include "ctree.h"
#include "disk-io.h"
+#include "orphan.h"
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset)
diff --git a/fs/btrfs/orphan.h b/fs/btrfs/orphan.h
new file mode 100644
index 000000000000..3faab5cbb59a
--- /dev/null
+++ b/fs/btrfs/orphan.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_ORPHAN_H
+#define BTRFS_ORPHAN_H
+
+int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 offset);
+int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 offset);
+
+#endif
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index dd8777872143..b93c96213304 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -3,9 +3,12 @@
* Copyright (C) 2007 Oracle. All rights reserved.
*/
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "accessors.h"
+#include "tree-checker.h"
struct root_name_map {
u64 id;
@@ -240,9 +243,9 @@ void btrfs_print_leaf(struct extent_buffer *l)
case BTRFS_DIR_ITEM_KEY:
di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
btrfs_dir_item_key_to_cpu(l, di, &found_key);
- pr_info("\t\tdir oid %llu type %u\n",
+ pr_info("\t\tdir oid %llu flags %u\n",
found_key.objectid,
- btrfs_dir_type(l, di));
+ btrfs_dir_flags(l, di));
break;
case BTRFS_ROOT_ITEM_KEY:
ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
@@ -384,14 +387,16 @@ void btrfs_print_tree(struct extent_buffer *c, bool follow)
if (!follow)
return;
for (i = 0; i < nr; i++) {
- struct btrfs_key first_key;
+ struct btrfs_tree_parent_check check = {
+ .level = level - 1,
+ .transid = btrfs_node_ptr_generation(c, i),
+ .owner_root = btrfs_header_owner(c),
+ .has_first_key = true
+ };
struct extent_buffer *next;
- btrfs_node_key_to_cpu(c, &first_key, i);
- next = read_tree_block(fs_info, btrfs_node_blockptr(c, i),
- btrfs_header_owner(c),
- btrfs_node_ptr_generation(c, i),
- level - 1, &first_key);
+ btrfs_node_key_to_cpu(c, &check.first_key, i);
+ next = read_tree_block(fs_info, btrfs_node_blockptr(c, i), &check);
if (IS_ERR(next))
continue;
if (!extent_buffer_uptodate(next)) {
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index 055a631276ce..0755af0e53e3 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -4,12 +4,17 @@
*/
#include <linux/hashtable.h>
+#include "messages.h"
#include "props.h"
#include "btrfs_inode.h"
#include "transaction.h"
#include "ctree.h"
#include "xattr.h"
#include "compression.h"
+#include "space-info.h"
+#include "fs.h"
+#include "accessors.h"
+#include "super.h"
#define BTRFS_PROP_HANDLERS_HT_BITS 8
static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
@@ -453,7 +458,7 @@ int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
return 0;
}
-void __init btrfs_props_init(void)
+int __init btrfs_props_init(void)
{
int i;
@@ -463,5 +468,6 @@ void __init btrfs_props_init(void)
hash_add(prop_handlers_ht, &p->node, h);
}
+ return 0;
}
diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h
index ca9dd3df129b..6e283196e38a 100644
--- a/fs/btrfs/props.h
+++ b/fs/btrfs/props.h
@@ -8,7 +8,7 @@
#include "ctree.h"
-void __init btrfs_props_init(void);
+int __init btrfs_props_init(void);
int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
const char *name, const char *value, size_t value_len,
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 9334c3157c22..5c636e00d77d 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -24,6 +24,11 @@
#include "block-group.h"
#include "sysfs.h"
#include "tree-mod-log.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "tree-checker.h"
/*
* Helpers to access qgroup reservation
@@ -1790,8 +1795,7 @@ int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info,
int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
struct btrfs_qgroup_extent_record *qrecord)
{
- struct ulist *old_root;
- u64 bytenr = qrecord->bytenr;
+ struct btrfs_backref_walk_ctx ctx = { 0 };
int ret;
/*
@@ -1818,8 +1822,10 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
if (trans->fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)
return 0;
- ret = btrfs_find_all_roots(NULL, trans->fs_info, bytenr, 0, &old_root,
- true);
+ ctx.bytenr = qrecord->bytenr;
+ ctx.fs_info = trans->fs_info;
+
+ ret = btrfs_find_all_roots(&ctx, true);
if (ret < 0) {
qgroup_mark_inconsistent(trans->fs_info);
btrfs_warn(trans->fs_info,
@@ -1835,12 +1841,12 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
*
* So modifying qrecord->old_roots is safe here
*/
- qrecord->old_roots = old_root;
+ qrecord->old_roots = ctx.roots;
return 0;
}
int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
- u64 num_bytes, gfp_t gfp_flag)
+ u64 num_bytes)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_qgroup_extent_record *record;
@@ -1850,7 +1856,7 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)
|| bytenr == 0 || num_bytes == 0)
return 0;
- record = kzalloc(sizeof(*record), gfp_flag);
+ record = kzalloc(sizeof(*record), GFP_NOFS);
if (!record)
return -ENOMEM;
@@ -1902,8 +1908,7 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans,
num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi);
- ret = btrfs_qgroup_trace_extent(trans, bytenr, num_bytes,
- GFP_NOFS);
+ ret = btrfs_qgroup_trace_extent(trans, bytenr, num_bytes);
if (ret)
return ret;
}
@@ -2102,12 +2107,11 @@ static int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans,
* blocks for qgroup accounting.
*/
ret = btrfs_qgroup_trace_extent(trans, src_path->nodes[dst_level]->start,
- nodesize, GFP_NOFS);
+ nodesize);
if (ret < 0)
goto out;
- ret = btrfs_qgroup_trace_extent(trans,
- dst_path->nodes[dst_level]->start,
- nodesize, GFP_NOFS);
+ ret = btrfs_qgroup_trace_extent(trans, dst_path->nodes[dst_level]->start,
+ nodesize);
if (ret < 0)
goto out;
@@ -2336,7 +2340,13 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
}
if (!extent_buffer_uptodate(root_eb)) {
- ret = btrfs_read_extent_buffer(root_eb, root_gen, root_level, NULL);
+ struct btrfs_tree_parent_check check = {
+ .has_first_key = false,
+ .transid = root_gen,
+ .level = root_level
+ };
+
+ ret = btrfs_read_extent_buffer(root_eb, &check);
if (ret)
goto out;
}
@@ -2391,8 +2401,7 @@ walk_down:
path->locks[level] = BTRFS_READ_LOCK;
ret = btrfs_qgroup_trace_extent(trans, child_bytenr,
- fs_info->nodesize,
- GFP_NOFS);
+ fs_info->nodesize);
if (ret)
goto out;
}
@@ -2749,17 +2758,22 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
if (!ret && !(fs_info->qgroup_flags &
BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)) {
+ struct btrfs_backref_walk_ctx ctx = { 0 };
+
+ ctx.bytenr = record->bytenr;
+ ctx.fs_info = fs_info;
+
/*
* Old roots should be searched when inserting qgroup
* extent record
*/
if (WARN_ON(!record->old_roots)) {
/* Search commit root to find old_roots */
- ret = btrfs_find_all_roots(NULL, fs_info,
- record->bytenr, 0,
- &record->old_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret < 0)
goto cleanup;
+ record->old_roots = ctx.roots;
+ ctx.roots = NULL;
}
/* Free the reserved data space */
@@ -2772,10 +2786,11 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
* which doesn't lock tree or delayed_refs and search
* current root. It's safe inside commit_transaction().
*/
- ret = btrfs_find_all_roots(trans, fs_info,
- record->bytenr, BTRFS_SEQ_LAST, &new_roots, false);
+ ctx.trans = trans;
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret < 0)
goto cleanup;
+ new_roots = ctx.roots;
if (qgroup_to_skip) {
ulist_del(new_roots, qgroup_to_skip, 0);
ulist_del(record->old_roots, qgroup_to_skip,
@@ -2951,14 +2966,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
dstgroup->rsv_excl = inherit->lim.rsv_excl;
- ret = update_qgroup_limit_item(trans, dstgroup);
- if (ret) {
- qgroup_mark_inconsistent(fs_info);
- btrfs_info(fs_info,
- "unable to update quota limit for %llu",
- dstgroup->qgroupid);
- goto unlock;
- }
+ qgroup_dirty(fs_info, dstgroup);
}
if (srcid) {
@@ -3248,7 +3256,6 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root;
struct btrfs_key found;
struct extent_buffer *scratch_leaf = NULL;
- struct ulist *roots = NULL;
u64 num_bytes;
bool done;
int slot;
@@ -3298,6 +3305,8 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
mutex_unlock(&fs_info->qgroup_rescan_lock);
for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) {
+ struct btrfs_backref_walk_ctx ctx = { 0 };
+
btrfs_item_key_to_cpu(scratch_leaf, &found, slot);
if (found.type != BTRFS_EXTENT_ITEM_KEY &&
found.type != BTRFS_METADATA_ITEM_KEY)
@@ -3307,13 +3316,15 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
else
num_bytes = found.offset;
- ret = btrfs_find_all_roots(NULL, fs_info, found.objectid, 0,
- &roots, false);
+ ctx.bytenr = found.objectid;
+ ctx.fs_info = fs_info;
+
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret < 0)
goto out;
/* For rescan, just pass old_roots as NULL */
ret = btrfs_qgroup_account_extent(trans, found.objectid,
- num_bytes, NULL, roots);
+ num_bytes, NULL, ctx.roots);
if (ret < 0)
goto out;
}
@@ -4299,6 +4310,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
struct extent_buffer *subvol_eb)
{
struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_tree_parent_check check = { 0 };
struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks;
struct btrfs_qgroup_swapped_block *block;
struct extent_buffer *reloc_eb = NULL;
@@ -4347,10 +4359,13 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
blocks->swapped = swapped;
spin_unlock(&blocks->lock);
+ check.level = block->level;
+ check.transid = block->reloc_generation;
+ check.has_first_key = true;
+ memcpy(&check.first_key, &block->first_key, sizeof(check.first_key));
+
/* Read out reloc subtree root */
- reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, 0,
- block->reloc_generation, block->level,
- &block->first_key);
+ reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, &check);
if (IS_ERR(reloc_eb)) {
ret = PTR_ERR(reloc_eb);
reloc_eb = NULL;
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 578c77e94200..7bffa10589d6 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -11,6 +11,7 @@
#include <linux/kobject.h>
#include "ulist.h"
#include "delayed-ref.h"
+#include "misc.h"
/*
* Btrfs qgroup overview
@@ -242,9 +243,11 @@ static inline u64 btrfs_qgroup_subvolid(u64 qgroupid)
/*
* For qgroup event trace points only
*/
-#define QGROUP_RESERVE (1<<0)
-#define QGROUP_RELEASE (1<<1)
-#define QGROUP_FREE (1<<2)
+enum {
+ ENUM_BIT(QGROUP_RESERVE),
+ ENUM_BIT(QGROUP_RELEASE),
+ ENUM_BIT(QGROUP_FREE),
+};
int btrfs_quota_enable(struct btrfs_fs_info *fs_info);
int btrfs_quota_disable(struct btrfs_fs_info *fs_info);
@@ -318,7 +321,7 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
* (NULL trans)
*/
int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
- u64 num_bytes, gfp_t gfp_flag);
+ u64 num_bytes);
/*
* Inform qgroup to trace all leaf items of data
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 82c8e991300e..2d90a6b5eb00 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -13,12 +13,15 @@
#include <linux/list_sort.h>
#include <linux/raid/xor.h>
#include <linux/mm.h>
+#include "messages.h"
#include "misc.h"
#include "ctree.h"
#include "disk-io.h"
#include "volumes.h"
#include "raid56.h"
#include "async-thread.h"
+#include "file-item.h"
+#include "btrfs_inode.h"
/* set when additional merges to this rbio are not allowed */
#define RBIO_RMW_LOCKED_BIT 1
@@ -63,19 +66,45 @@ struct sector_ptr {
unsigned int uptodate:8;
};
-static int __raid56_parity_recover(struct btrfs_raid_bio *rbio);
-static noinline void finish_rmw(struct btrfs_raid_bio *rbio);
-static void rmw_work(struct work_struct *work);
-static void read_rebuild_work(struct work_struct *work);
-static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio);
-static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed);
-static void __free_raid_bio(struct btrfs_raid_bio *rbio);
+static void rmw_rbio_work(struct work_struct *work);
+static void rmw_rbio_work_locked(struct work_struct *work);
static void index_rbio_pages(struct btrfs_raid_bio *rbio);
static int alloc_rbio_pages(struct btrfs_raid_bio *rbio);
-static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
- int need_check);
-static void scrub_parity_work(struct work_struct *work);
+static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check);
+static void scrub_rbio_work_locked(struct work_struct *work);
+
+static void free_raid_bio_pointers(struct btrfs_raid_bio *rbio)
+{
+ bitmap_free(rbio->error_bitmap);
+ kfree(rbio->stripe_pages);
+ kfree(rbio->bio_sectors);
+ kfree(rbio->stripe_sectors);
+ kfree(rbio->finish_pointers);
+}
+
+static void free_raid_bio(struct btrfs_raid_bio *rbio)
+{
+ int i;
+
+ if (!refcount_dec_and_test(&rbio->refs))
+ return;
+
+ WARN_ON(!list_empty(&rbio->stripe_cache));
+ WARN_ON(!list_empty(&rbio->hash_list));
+ WARN_ON(!bio_list_empty(&rbio->bio_list));
+
+ for (i = 0; i < rbio->nr_pages; i++) {
+ if (rbio->stripe_pages[i]) {
+ __free_page(rbio->stripe_pages[i]);
+ rbio->stripe_pages[i] = NULL;
+ }
+ }
+
+ btrfs_put_bioc(rbio->bioc);
+ free_raid_bio_pointers(rbio);
+ kfree(rbio);
+}
static void start_async_work(struct btrfs_raid_bio *rbio, work_func_t work_func)
{
@@ -146,8 +175,16 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)
for (i = 0; i < rbio->nr_sectors; i++) {
/* Some range not covered by bio (partial write), skip it */
- if (!rbio->bio_sectors[i].page)
+ if (!rbio->bio_sectors[i].page) {
+ /*
+ * Even if the sector is not covered by bio, if it is
+ * a data sector it should still be uptodate as it is
+ * read from disk.
+ */
+ if (i < rbio->nr_data * rbio->stripe_nsectors)
+ ASSERT(rbio->stripe_sectors[i].uptodate);
continue;
+ }
ASSERT(rbio->stripe_sectors[i].page);
memcpy_page(rbio->stripe_sectors[i].page,
@@ -234,6 +271,21 @@ static void steal_rbio_page(struct btrfs_raid_bio *src,
dest->stripe_sectors[i].uptodate = true;
}
+static bool is_data_stripe_page(struct btrfs_raid_bio *rbio, int page_nr)
+{
+ const int sector_nr = (page_nr << PAGE_SHIFT) >>
+ rbio->bioc->fs_info->sectorsize_bits;
+
+ /*
+ * We have ensured PAGE_SIZE is aligned with sectorsize, thus
+ * we won't have a page which is half data half parity.
+ *
+ * Thus if the first sector of the page belongs to data stripes, then
+ * the full page belongs to data stripes.
+ */
+ return (sector_nr < rbio->nr_data * rbio->stripe_nsectors);
+}
+
/*
* Stealing an rbio means taking all the uptodate pages from the stripe array
* in the source rbio and putting them into the destination rbio.
@@ -244,16 +296,26 @@ static void steal_rbio_page(struct btrfs_raid_bio *src,
static void steal_rbio(struct btrfs_raid_bio *src, struct btrfs_raid_bio *dest)
{
int i;
- struct page *s;
if (!test_bit(RBIO_CACHE_READY_BIT, &src->flags))
return;
for (i = 0; i < dest->nr_pages; i++) {
- s = src->stripe_pages[i];
- if (!s || !full_page_sectors_uptodate(src, i))
+ struct page *p = src->stripe_pages[i];
+
+ /*
+ * We don't need to steal P/Q pages as they will always be
+ * regenerated for RMW or full write anyway.
+ */
+ if (!is_data_stripe_page(src, i))
continue;
+ /*
+ * If @src already has RBIO_CACHE_READY_BIT, it should have
+ * all data stripe pages present and uptodate.
+ */
+ ASSERT(p);
+ ASSERT(full_page_sectors_uptodate(src, i));
steal_rbio_page(src, dest, i);
}
index_stripe_sectors(dest);
@@ -336,7 +398,7 @@ static void __remove_rbio_from_cache(struct btrfs_raid_bio *rbio)
spin_unlock(&h->lock);
if (freeit)
- __free_raid_bio(rbio);
+ free_raid_bio(rbio);
}
/*
@@ -526,28 +588,10 @@ static int rbio_can_merge(struct btrfs_raid_bio *last,
if (last->operation == BTRFS_RBIO_PARITY_SCRUB)
return 0;
- if (last->operation == BTRFS_RBIO_REBUILD_MISSING)
+ if (last->operation == BTRFS_RBIO_REBUILD_MISSING ||
+ last->operation == BTRFS_RBIO_READ_REBUILD)
return 0;
- if (last->operation == BTRFS_RBIO_READ_REBUILD) {
- int fa = last->faila;
- int fb = last->failb;
- int cur_fa = cur->faila;
- int cur_fb = cur->failb;
-
- if (last->faila >= last->failb) {
- fa = last->failb;
- fb = last->faila;
- }
-
- if (cur->faila >= cur->failb) {
- cur_fa = cur->failb;
- cur_fb = cur->faila;
- }
-
- if (fa != cur_fa || fb != cur_fb)
- return 0;
- }
return 1;
}
@@ -684,10 +728,12 @@ out:
if (cache_drop)
remove_rbio_from_cache(cache_drop);
if (freeit)
- __free_raid_bio(freeit);
+ free_raid_bio(freeit);
return ret;
}
+static void recover_rbio_work_locked(struct work_struct *work);
+
/*
* called as rmw or parity rebuild is completed. If the plug list has more
* rbios waiting for this stripe, the next one on the list will be started
@@ -745,16 +791,16 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio)
spin_unlock_irqrestore(&h->lock, flags);
if (next->operation == BTRFS_RBIO_READ_REBUILD)
- start_async_work(next, read_rebuild_work);
+ start_async_work(next, recover_rbio_work_locked);
else if (next->operation == BTRFS_RBIO_REBUILD_MISSING) {
steal_rbio(rbio, next);
- start_async_work(next, read_rebuild_work);
+ start_async_work(next, recover_rbio_work_locked);
} else if (next->operation == BTRFS_RBIO_WRITE) {
steal_rbio(rbio, next);
- start_async_work(next, rmw_work);
+ start_async_work(next, rmw_rbio_work_locked);
} else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) {
steal_rbio(rbio, next);
- start_async_work(next, scrub_parity_work);
+ start_async_work(next, scrub_rbio_work_locked);
}
goto done_nolock;
@@ -769,28 +815,6 @@ done_nolock:
remove_rbio_from_cache(rbio);
}
-static void __free_raid_bio(struct btrfs_raid_bio *rbio)
-{
- int i;
-
- if (!refcount_dec_and_test(&rbio->refs))
- return;
-
- WARN_ON(!list_empty(&rbio->stripe_cache));
- WARN_ON(!list_empty(&rbio->hash_list));
- WARN_ON(!bio_list_empty(&rbio->bio_list));
-
- for (i = 0; i < rbio->nr_pages; i++) {
- if (rbio->stripe_pages[i]) {
- __free_page(rbio->stripe_pages[i]);
- rbio->stripe_pages[i] = NULL;
- }
- }
-
- btrfs_put_bioc(rbio->bioc);
- kfree(rbio);
-}
-
static void rbio_endio_bio_list(struct bio *cur, blk_status_t err)
{
struct bio *next;
@@ -813,6 +837,11 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
struct bio *cur = bio_list_get(&rbio->bio_list);
struct bio *extra;
+ kfree(rbio->csum_buf);
+ bitmap_free(rbio->csum_bitmap);
+ rbio->csum_buf = NULL;
+ rbio->csum_bitmap = NULL;
+
/*
* Clear the data bitmap, as the rbio may be cached for later usage.
* do this before before unlock_stripe() so there will be no new bio
@@ -830,7 +859,7 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
*/
unlock_stripe(rbio);
extra = bio_list_get(&rbio->bio_list);
- __free_raid_bio(rbio);
+ free_raid_bio(rbio);
rbio_endio_bio_list(cur, err);
if (extra)
@@ -838,36 +867,7 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
}
/*
- * end io function used by finish_rmw. When we finally
- * get here, we've written a full stripe
- */
-static void raid_write_end_io(struct bio *bio)
-{
- struct btrfs_raid_bio *rbio = bio->bi_private;
- blk_status_t err = bio->bi_status;
- int max_errors;
-
- if (err)
- fail_bio_stripe(rbio, bio);
-
- bio_put(bio);
-
- if (!atomic_dec_and_test(&rbio->stripes_pending))
- return;
-
- err = BLK_STS_OK;
-
- /* OK, we have read all the stripes we need to. */
- max_errors = (rbio->operation == BTRFS_RBIO_PARITY_SCRUB) ?
- 0 : rbio->bioc->max_errors;
- if (atomic_read(&rbio->error) > max_errors)
- err = BLK_STS_IOERR;
-
- rbio_orig_end_io(rbio, err);
-}
-
-/**
- * Get a sector pointer specified by its @stripe_nr and @sector_nr
+ * Get a sector pointer specified by its @stripe_nr and @sector_nr.
*
* @rbio: The raid bio
* @stripe_nr: Stripe number, valid range [0, real_stripe)
@@ -919,7 +919,6 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits;
const unsigned int num_sectors = stripe_nsectors * real_stripes;
struct btrfs_raid_bio *rbio;
- void *p;
/* PAGE_SIZE must also be aligned to sectorsize for subpage support */
ASSERT(IS_ALIGNED(PAGE_SIZE, fs_info->sectorsize));
@@ -929,16 +928,27 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
*/
ASSERT(stripe_nsectors <= BITS_PER_LONG);
- rbio = kzalloc(sizeof(*rbio) +
- sizeof(*rbio->stripe_pages) * num_pages +
- sizeof(*rbio->bio_sectors) * num_sectors +
- sizeof(*rbio->stripe_sectors) * num_sectors +
- sizeof(*rbio->finish_pointers) * real_stripes,
- GFP_NOFS);
+ rbio = kzalloc(sizeof(*rbio), GFP_NOFS);
if (!rbio)
return ERR_PTR(-ENOMEM);
+ rbio->stripe_pages = kcalloc(num_pages, sizeof(struct page *),
+ GFP_NOFS);
+ rbio->bio_sectors = kcalloc(num_sectors, sizeof(struct sector_ptr),
+ GFP_NOFS);
+ rbio->stripe_sectors = kcalloc(num_sectors, sizeof(struct sector_ptr),
+ GFP_NOFS);
+ rbio->finish_pointers = kcalloc(real_stripes, sizeof(void *), GFP_NOFS);
+ rbio->error_bitmap = bitmap_zalloc(num_sectors, GFP_NOFS);
+
+ if (!rbio->stripe_pages || !rbio->bio_sectors || !rbio->stripe_sectors ||
+ !rbio->finish_pointers || !rbio->error_bitmap) {
+ free_raid_bio_pointers(rbio);
+ kfree(rbio);
+ return ERR_PTR(-ENOMEM);
+ }
bio_list_init(&rbio->bio_list);
+ init_waitqueue_head(&rbio->io_wait);
INIT_LIST_HEAD(&rbio->plug_list);
spin_lock_init(&rbio->bio_list_lock);
INIT_LIST_HEAD(&rbio->stripe_cache);
@@ -950,27 +960,9 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
rbio->real_stripes = real_stripes;
rbio->stripe_npages = stripe_npages;
rbio->stripe_nsectors = stripe_nsectors;
- rbio->faila = -1;
- rbio->failb = -1;
refcount_set(&rbio->refs, 1);
- atomic_set(&rbio->error, 0);
atomic_set(&rbio->stripes_pending, 0);
- /*
- * The stripe_pages, bio_sectors, etc arrays point to the extra memory
- * we allocated past the end of the rbio.
- */
- p = rbio + 1;
-#define CONSUME_ALLOC(ptr, count) do { \
- ptr = p; \
- p = (unsigned char *)p + sizeof(*(ptr)) * (count); \
- } while (0)
- CONSUME_ALLOC(rbio->stripe_pages, num_pages);
- CONSUME_ALLOC(rbio->bio_sectors, num_sectors);
- CONSUME_ALLOC(rbio->stripe_sectors, num_sectors);
- CONSUME_ALLOC(rbio->finish_pointers, real_stripes);
-#undef CONSUME_ALLOC
-
ASSERT(btrfs_nr_parity_stripes(bioc->map_type));
rbio->nr_data = real_stripes - btrfs_nr_parity_stripes(bioc->map_type);
@@ -1006,6 +998,45 @@ static int alloc_rbio_parity_pages(struct btrfs_raid_bio *rbio)
}
/*
+ * Return the total numer of errors found in the vertical stripe of @sector_nr.
+ *
+ * @faila and @failb will also be updated to the first and second stripe
+ * number of the errors.
+ */
+static int get_rbio_veritical_errors(struct btrfs_raid_bio *rbio, int sector_nr,
+ int *faila, int *failb)
+{
+ int stripe_nr;
+ int found_errors = 0;
+
+ if (faila || failb) {
+ /*
+ * Both @faila and @failb should be valid pointers if any of
+ * them is specified.
+ */
+ ASSERT(faila && failb);
+ *faila = -1;
+ *failb = -1;
+ }
+
+ for (stripe_nr = 0; stripe_nr < rbio->real_stripes; stripe_nr++) {
+ int total_sector_nr = stripe_nr * rbio->stripe_nsectors + sector_nr;
+
+ if (test_bit(total_sector_nr, rbio->error_bitmap)) {
+ found_errors++;
+ if (faila) {
+ /* Update faila and failb. */
+ if (*faila < 0)
+ *faila = stripe_nr;
+ else if (*failb < 0)
+ *failb = stripe_nr;
+ }
+ }
+ }
+ return found_errors;
+}
+
+/*
* Add a single sector @sector into our list of bios for IO.
*
* Return 0 if everything went well.
@@ -1038,8 +1069,19 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
disk_start = stripe->physical + sector_nr * sectorsize;
/* if the device is missing, just fail this stripe */
- if (!stripe->dev->bdev)
- return fail_rbio_index(rbio, stripe_nr);
+ if (!stripe->dev->bdev) {
+ int found_errors;
+
+ set_bit(stripe_nr * rbio->stripe_nsectors + sector_nr,
+ rbio->error_bitmap);
+
+ /* Check if we have reached tolerance early. */
+ found_errors = get_rbio_veritical_errors(rbio, sector_nr,
+ NULL, NULL);
+ if (found_errors > rbio->bioc->max_errors)
+ return -EIO;
+ return 0;
+ }
/* see if we can add this page onto our existing bio */
if (last) {
@@ -1071,23 +1113,6 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
return 0;
}
-/*
- * while we're doing the read/modify/write cycle, we could
- * have errors in reading pages off the disk. This checks
- * for errors and if we're not able to read the page it'll
- * trigger parity reconstruction. The rmw will be finished
- * after we've reconstructed the failed stripes
- */
-static void validate_rbio_for_rmw(struct btrfs_raid_bio *rbio)
-{
- if (rbio->faila >= 0 || rbio->failb >= 0) {
- BUG_ON(rbio->faila == rbio->real_stripes - 1);
- __raid56_parity_recover(rbio);
- } else {
- finish_rmw(rbio);
- }
-}
-
static void index_one_bio(struct btrfs_raid_bio *rbio, struct bio *bio)
{
const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
@@ -1158,109 +1183,71 @@ not_found:
trace_info->stripe_nr = -1;
}
-/*
- * this is called from one of two situations. We either
- * have a full stripe from the higher layers, or we've read all
- * the missing bits off disk.
- *
- * This will calculate the parity and then send down any
- * changed blocks.
- */
-static noinline void finish_rmw(struct btrfs_raid_bio *rbio)
+/* Generate PQ for one veritical stripe. */
+static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
{
- struct btrfs_io_context *bioc = rbio->bioc;
- const u32 sectorsize = bioc->fs_info->sectorsize;
void **pointers = rbio->finish_pointers;
- int nr_data = rbio->nr_data;
+ const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
+ struct sector_ptr *sector;
+ int stripe;
+ const bool has_qstripe = rbio->bioc->map_type & BTRFS_BLOCK_GROUP_RAID6;
+
+ /* First collect one sector from each data stripe */
+ for (stripe = 0; stripe < rbio->nr_data; stripe++) {
+ sector = sector_in_rbio(rbio, stripe, sectornr, 0);
+ pointers[stripe] = kmap_local_page(sector->page) +
+ sector->pgoff;
+ }
+
+ /* Then add the parity stripe */
+ sector = rbio_pstripe_sector(rbio, sectornr);
+ sector->uptodate = 1;
+ pointers[stripe++] = kmap_local_page(sector->page) + sector->pgoff;
+
+ if (has_qstripe) {
+ /*
+ * RAID6, add the qstripe and call the library function
+ * to fill in our p/q
+ */
+ sector = rbio_qstripe_sector(rbio, sectornr);
+ sector->uptodate = 1;
+ pointers[stripe++] = kmap_local_page(sector->page) +
+ sector->pgoff;
+
+ raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
+ pointers);
+ } else {
+ /* raid5 */
+ memcpy(pointers[rbio->nr_data], pointers[0], sectorsize);
+ run_xor(pointers + 1, rbio->nr_data - 1, sectorsize);
+ }
+ for (stripe = stripe - 1; stripe >= 0; stripe--)
+ kunmap_local(pointers[stripe]);
+}
+
+static int rmw_assemble_write_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
+{
+ struct bio *bio;
/* The total sector number inside the full stripe. */
int total_sector_nr;
- int stripe;
- /* Sector number inside a stripe. */
int sectornr;
- bool has_qstripe;
- struct bio_list bio_list;
- struct bio *bio;
+ int stripe;
int ret;
- bio_list_init(&bio_list);
-
- if (rbio->real_stripes - rbio->nr_data == 1)
- has_qstripe = false;
- else if (rbio->real_stripes - rbio->nr_data == 2)
- has_qstripe = true;
- else
- BUG();
+ ASSERT(bio_list_size(bio_list) == 0);
/* We should have at least one data sector. */
ASSERT(bitmap_weight(&rbio->dbitmap, rbio->stripe_nsectors));
- /* at this point we either have a full stripe,
- * or we've read the full stripe from the drive.
- * recalculate the parity and write the new results.
- *
- * We're not allowed to add any new bios to the
- * bio list here, anyone else that wants to
- * change this stripe needs to do their own rmw.
- */
- spin_lock_irq(&rbio->bio_list_lock);
- set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags);
- spin_unlock_irq(&rbio->bio_list_lock);
-
- atomic_set(&rbio->error, 0);
-
/*
- * now that we've set rmw_locked, run through the
- * bio list one last time and map the page pointers
- *
- * We don't cache full rbios because we're assuming
- * the higher layers are unlikely to use this area of
- * the disk again soon. If they do use it again,
- * hopefully they will send another full bio.
+ * Reset errors, as we may have errors inherited from from degraded
+ * write.
*/
- index_rbio_pages(rbio);
- if (!rbio_is_full(rbio))
- cache_rbio_pages(rbio);
- else
- clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
-
- for (sectornr = 0; sectornr < rbio->stripe_nsectors; sectornr++) {
- struct sector_ptr *sector;
-
- /* First collect one sector from each data stripe */
- for (stripe = 0; stripe < nr_data; stripe++) {
- sector = sector_in_rbio(rbio, stripe, sectornr, 0);
- pointers[stripe] = kmap_local_page(sector->page) +
- sector->pgoff;
- }
-
- /* Then add the parity stripe */
- sector = rbio_pstripe_sector(rbio, sectornr);
- sector->uptodate = 1;
- pointers[stripe++] = kmap_local_page(sector->page) + sector->pgoff;
-
- if (has_qstripe) {
- /*
- * RAID6, add the qstripe and call the library function
- * to fill in our p/q
- */
- sector = rbio_qstripe_sector(rbio, sectornr);
- sector->uptodate = 1;
- pointers[stripe++] = kmap_local_page(sector->page) +
- sector->pgoff;
-
- raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
- pointers);
- } else {
- /* raid5 */
- memcpy(pointers[nr_data], pointers[0], sectorsize);
- run_xor(pointers + 1, nr_data - 1, sectorsize);
- }
- for (stripe = stripe - 1; stripe >= 0; stripe--)
- kunmap_local(pointers[stripe]);
- }
+ bitmap_clear(rbio->error_bitmap, 0, rbio->nr_sectors);
/*
- * Start writing. Make bios for everything from the higher layers (the
+ * Start assembly. Make bios for everything from the higher layers (the
* bio_list in our rbio) and our P/Q. Ignore everything else.
*/
for (total_sector_nr = 0; total_sector_nr < rbio->nr_sectors;
@@ -1282,15 +1269,16 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)
sector = rbio_stripe_sector(rbio, stripe, sectornr);
}
- ret = rbio_add_io_sector(rbio, &bio_list, sector, stripe,
+ ret = rbio_add_io_sector(rbio, bio_list, sector, stripe,
sectornr, REQ_OP_WRITE);
if (ret)
- goto cleanup;
+ goto error;
}
- if (likely(!bioc->num_tgtdevs))
- goto write_data;
+ if (likely(!rbio->bioc->num_tgtdevs))
+ return 0;
+ /* Make a copy for the replace target device. */
for (total_sector_nr = 0; total_sector_nr < rbio->nr_sectors;
total_sector_nr++) {
struct sector_ptr *sector;
@@ -1298,7 +1286,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)
stripe = total_sector_nr / rbio->stripe_nsectors;
sectornr = total_sector_nr % rbio->stripe_nsectors;
- if (!bioc->tgtdev_map[stripe]) {
+ if (!rbio->bioc->tgtdev_map[stripe]) {
/*
* We can skip the whole stripe completely, note
* total_sector_nr will be increased by one anyway.
@@ -1320,125 +1308,52 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)
sector = rbio_stripe_sector(rbio, stripe, sectornr);
}
- ret = rbio_add_io_sector(rbio, &bio_list, sector,
+ ret = rbio_add_io_sector(rbio, bio_list, sector,
rbio->bioc->tgtdev_map[stripe],
sectornr, REQ_OP_WRITE);
if (ret)
- goto cleanup;
- }
-
-write_data:
- atomic_set(&rbio->stripes_pending, bio_list_size(&bio_list));
- BUG_ON(atomic_read(&rbio->stripes_pending) == 0);
-
- while ((bio = bio_list_pop(&bio_list))) {
- bio->bi_end_io = raid_write_end_io;
-
- if (trace_raid56_write_stripe_enabled()) {
- struct raid56_bio_trace_info trace_info = { 0 };
-
- bio_get_trace_info(rbio, bio, &trace_info);
- trace_raid56_write_stripe(rbio, bio, &trace_info);
- }
- submit_bio(bio);
+ goto error;
}
- return;
-cleanup:
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
-
- while ((bio = bio_list_pop(&bio_list)))
+ return 0;
+error:
+ while ((bio = bio_list_pop(bio_list)))
bio_put(bio);
+ return -EIO;
}
-/*
- * helper to find the stripe number for a given bio. Used to figure out which
- * stripe has failed. This expects the bio to correspond to a physical disk,
- * so it looks up based on physical sector numbers.
- */
-static int find_bio_stripe(struct btrfs_raid_bio *rbio,
- struct bio *bio)
-{
- u64 physical = bio->bi_iter.bi_sector;
- int i;
- struct btrfs_io_stripe *stripe;
-
- physical <<= 9;
-
- for (i = 0; i < rbio->bioc->num_stripes; i++) {
- stripe = &rbio->bioc->stripes[i];
- if (in_range(physical, stripe->physical, BTRFS_STRIPE_LEN) &&
- stripe->dev->bdev && bio->bi_bdev == stripe->dev->bdev) {
- return i;
- }
- }
- return -1;
-}
-
-/*
- * helper to find the stripe number for a given
- * bio (before mapping). Used to figure out which stripe has
- * failed. This looks up based on logical block numbers.
- */
-static int find_logical_bio_stripe(struct btrfs_raid_bio *rbio,
- struct bio *bio)
-{
- u64 logical = bio->bi_iter.bi_sector << 9;
- int i;
-
- for (i = 0; i < rbio->nr_data; i++) {
- u64 stripe_start = rbio->bioc->raid_map[i];
-
- if (in_range(logical, stripe_start, BTRFS_STRIPE_LEN))
- return i;
- }
- return -1;
-}
-
-/*
- * returns -EIO if we had too many failures
- */
-static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed)
+static void set_rbio_range_error(struct btrfs_raid_bio *rbio, struct bio *bio)
{
- unsigned long flags;
- int ret = 0;
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ u32 offset = (bio->bi_iter.bi_sector << SECTOR_SHIFT) -
+ rbio->bioc->raid_map[0];
+ int total_nr_sector = offset >> fs_info->sectorsize_bits;
- spin_lock_irqsave(&rbio->bio_list_lock, flags);
+ ASSERT(total_nr_sector < rbio->nr_data * rbio->stripe_nsectors);
- /* we already know this stripe is bad, move on */
- if (rbio->faila == failed || rbio->failb == failed)
- goto out;
+ bitmap_set(rbio->error_bitmap, total_nr_sector,
+ bio->bi_iter.bi_size >> fs_info->sectorsize_bits);
- if (rbio->faila == -1) {
- /* first failure on this rbio */
- rbio->faila = failed;
- atomic_inc(&rbio->error);
- } else if (rbio->failb == -1) {
- /* second failure on this rbio */
- rbio->failb = failed;
- atomic_inc(&rbio->error);
- } else {
- ret = -EIO;
+ /*
+ * Special handling for raid56_alloc_missing_rbio() used by
+ * scrub/replace. Unlike call path in raid56_parity_recover(), they
+ * pass an empty bio here. Thus we have to find out the missing device
+ * and mark the stripe error instead.
+ */
+ if (bio->bi_iter.bi_size == 0) {
+ bool found_missing = false;
+ int stripe_nr;
+
+ for (stripe_nr = 0; stripe_nr < rbio->real_stripes; stripe_nr++) {
+ if (!rbio->bioc->stripes[stripe_nr].dev->bdev) {
+ found_missing = true;
+ bitmap_set(rbio->error_bitmap,
+ stripe_nr * rbio->stripe_nsectors,
+ rbio->stripe_nsectors);
+ }
+ }
+ ASSERT(found_missing);
}
-out:
- spin_unlock_irqrestore(&rbio->bio_list_lock, flags);
-
- return ret;
-}
-
-/*
- * helper to fail a stripe based on a physical disk
- * bio.
- */
-static int fail_bio_stripe(struct btrfs_raid_bio *rbio,
- struct bio *bio)
-{
- int failed = find_bio_stripe(rbio, bio);
-
- if (failed < 0)
- return -EIO;
-
- return fail_rbio_index(rbio, failed);
}
/*
@@ -1486,191 +1401,163 @@ static void set_bio_pages_uptodate(struct btrfs_raid_bio *rbio, struct bio *bio)
}
}
-static void raid56_bio_end_io(struct bio *bio)
+static int get_bio_sector_nr(struct btrfs_raid_bio *rbio, struct bio *bio)
{
- struct btrfs_raid_bio *rbio = bio->bi_private;
-
- if (bio->bi_status)
- fail_bio_stripe(rbio, bio);
- else
- set_bio_pages_uptodate(rbio, bio);
+ struct bio_vec *bv = bio_first_bvec_all(bio);
+ int i;
- bio_put(bio);
+ for (i = 0; i < rbio->nr_sectors; i++) {
+ struct sector_ptr *sector;
- if (atomic_dec_and_test(&rbio->stripes_pending))
- queue_work(rbio->bioc->fs_info->endio_raid56_workers,
- &rbio->end_io_work);
+ sector = &rbio->stripe_sectors[i];
+ if (sector->page == bv->bv_page && sector->pgoff == bv->bv_offset)
+ break;
+ sector = &rbio->bio_sectors[i];
+ if (sector->page == bv->bv_page && sector->pgoff == bv->bv_offset)
+ break;
+ }
+ ASSERT(i < rbio->nr_sectors);
+ return i;
}
-/*
- * End io handler for the read phase of the RMW cycle. All the bios here are
- * physical stripe bios we've read from the disk so we can recalculate the
- * parity of the stripe.
- *
- * This will usually kick off finish_rmw once all the bios are read in, but it
- * may trigger parity reconstruction if we had any errors along the way
- */
-static void raid56_rmw_end_io_work(struct work_struct *work)
+static void rbio_update_error_bitmap(struct btrfs_raid_bio *rbio, struct bio *bio)
{
- struct btrfs_raid_bio *rbio =
- container_of(work, struct btrfs_raid_bio, end_io_work);
+ int total_sector_nr = get_bio_sector_nr(rbio, bio);
+ u32 bio_size = 0;
+ struct bio_vec *bvec;
+ struct bvec_iter_all iter_all;
- if (atomic_read(&rbio->error) > rbio->bioc->max_errors) {
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
- return;
- }
+ bio_for_each_segment_all(bvec, bio, iter_all)
+ bio_size += bvec->bv_len;
- /*
- * This will normally call finish_rmw to start our write but if there
- * are any failed stripes we'll reconstruct from parity first.
- */
- validate_rbio_for_rmw(rbio);
+ bitmap_set(rbio->error_bitmap, total_sector_nr,
+ bio_size >> rbio->bioc->fs_info->sectorsize_bits);
}
-/*
- * the stripe must be locked by the caller. It will
- * unlock after all the writes are done
- */
-static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio)
+/* Verify the data sectors at read time. */
+static void verify_bio_data_sectors(struct btrfs_raid_bio *rbio,
+ struct bio *bio)
{
- int bios_to_read = 0;
- struct bio_list bio_list;
- const int nr_data_sectors = rbio->stripe_nsectors * rbio->nr_data;
- int ret;
- int total_sector_nr;
- struct bio *bio;
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ int total_sector_nr = get_bio_sector_nr(rbio, bio);
+ struct bio_vec *bvec;
+ struct bvec_iter_all iter_all;
- bio_list_init(&bio_list);
+ /* No data csum for the whole stripe, no need to verify. */
+ if (!rbio->csum_bitmap || !rbio->csum_buf)
+ return;
- ret = alloc_rbio_pages(rbio);
- if (ret)
- goto cleanup;
+ /* P/Q stripes, they have no data csum to verify against. */
+ if (total_sector_nr >= rbio->nr_data * rbio->stripe_nsectors)
+ return;
- index_rbio_pages(rbio);
+ bio_for_each_segment_all(bvec, bio, iter_all) {
+ int bv_offset;
+
+ for (bv_offset = bvec->bv_offset;
+ bv_offset < bvec->bv_offset + bvec->bv_len;
+ bv_offset += fs_info->sectorsize, total_sector_nr++) {
+ u8 csum_buf[BTRFS_CSUM_SIZE];
+ u8 *expected_csum = rbio->csum_buf +
+ total_sector_nr * fs_info->csum_size;
+ int ret;
- atomic_set(&rbio->error, 0);
- /* Build a list of bios to read all the missing data sectors. */
- for (total_sector_nr = 0; total_sector_nr < nr_data_sectors;
- total_sector_nr++) {
- struct sector_ptr *sector;
- int stripe = total_sector_nr / rbio->stripe_nsectors;
- int sectornr = total_sector_nr % rbio->stripe_nsectors;
+ /* No csum for this sector, skip to the next sector. */
+ if (!test_bit(total_sector_nr, rbio->csum_bitmap))
+ continue;
- /*
- * We want to find all the sectors missing from the rbio and
- * read them from the disk. If sector_in_rbio() finds a page
- * in the bio list we don't need to read it off the stripe.
- */
- sector = sector_in_rbio(rbio, stripe, sectornr, 1);
- if (sector)
- continue;
+ ret = btrfs_check_sector_csum(fs_info, bvec->bv_page,
+ bv_offset, csum_buf, expected_csum);
+ if (ret < 0)
+ set_bit(total_sector_nr, rbio->error_bitmap);
+ }
+ }
+}
- sector = rbio_stripe_sector(rbio, stripe, sectornr);
- /*
- * The bio cache may have handed us an uptodate page. If so,
- * use it.
- */
- if (sector->uptodate)
- continue;
+static void raid_wait_read_end_io(struct bio *bio)
+{
+ struct btrfs_raid_bio *rbio = bio->bi_private;
- ret = rbio_add_io_sector(rbio, &bio_list, sector,
- stripe, sectornr, REQ_OP_READ);
- if (ret)
- goto cleanup;
+ if (bio->bi_status) {
+ rbio_update_error_bitmap(rbio, bio);
+ } else {
+ set_bio_pages_uptodate(rbio, bio);
+ verify_bio_data_sectors(rbio, bio);
}
- bios_to_read = bio_list_size(&bio_list);
- if (!bios_to_read) {
- /*
- * this can happen if others have merged with
- * us, it means there is nothing left to read.
- * But if there are missing devices it may not be
- * safe to do the full stripe write yet.
- */
- goto finish;
- }
+ bio_put(bio);
+ if (atomic_dec_and_test(&rbio->stripes_pending))
+ wake_up(&rbio->io_wait);
+}
- /*
- * The bioc may be freed once we submit the last bio. Make sure not to
- * touch it after that.
- */
- atomic_set(&rbio->stripes_pending, bios_to_read);
- INIT_WORK(&rbio->end_io_work, raid56_rmw_end_io_work);
- while ((bio = bio_list_pop(&bio_list))) {
- bio->bi_end_io = raid56_bio_end_io;
+static void submit_read_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
+{
+ struct bio *bio;
+
+ atomic_set(&rbio->stripes_pending, bio_list_size(bio_list));
+ while ((bio = bio_list_pop(bio_list))) {
+ bio->bi_end_io = raid_wait_read_end_io;
- if (trace_raid56_read_partial_enabled()) {
+ if (trace_raid56_scrub_read_recover_enabled()) {
struct raid56_bio_trace_info trace_info = { 0 };
bio_get_trace_info(rbio, bio, &trace_info);
- trace_raid56_read_partial(rbio, bio, &trace_info);
+ trace_raid56_scrub_read_recover(rbio, bio, &trace_info);
}
submit_bio(bio);
}
- /* the actual write will happen once the reads are done */
- return 0;
+}
-cleanup:
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
+static int rmw_assemble_read_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
+{
+ struct bio *bio;
+ int total_sector_nr;
+ int ret = 0;
- while ((bio = bio_list_pop(&bio_list)))
- bio_put(bio);
+ ASSERT(bio_list_size(bio_list) == 0);
- return -EIO;
+ /*
+ * Build a list of bios to read all sectors (including data and P/Q).
+ *
+ * This behaviro is to compensate the later csum verification and
+ * recovery.
+ */
+ for (total_sector_nr = 0; total_sector_nr < rbio->nr_sectors;
+ total_sector_nr++) {
+ struct sector_ptr *sector;
+ int stripe = total_sector_nr / rbio->stripe_nsectors;
+ int sectornr = total_sector_nr % rbio->stripe_nsectors;
-finish:
- validate_rbio_for_rmw(rbio);
+ sector = rbio_stripe_sector(rbio, stripe, sectornr);
+ ret = rbio_add_io_sector(rbio, bio_list, sector,
+ stripe, sectornr, REQ_OP_READ);
+ if (ret)
+ goto cleanup;
+ }
return 0;
+
+cleanup:
+ while ((bio = bio_list_pop(bio_list)))
+ bio_put(bio);
+ return ret;
}
-/*
- * if the upper layers pass in a full stripe, we thank them by only allocating
- * enough pages to hold the parity, and sending it all down quickly.
- */
-static int full_stripe_write(struct btrfs_raid_bio *rbio)
+static int alloc_rbio_data_pages(struct btrfs_raid_bio *rbio)
{
+ const int data_pages = rbio->nr_data * rbio->stripe_npages;
int ret;
- ret = alloc_rbio_parity_pages(rbio);
- if (ret)
+ ret = btrfs_alloc_page_array(data_pages, rbio->stripe_pages);
+ if (ret < 0)
return ret;
- ret = lock_stripe_add(rbio);
- if (ret == 0)
- finish_rmw(rbio);
- return 0;
-}
-
-/*
- * partial stripe writes get handed over to async helpers.
- * We're really hoping to merge a few more writes into this
- * rbio before calculating new parity
- */
-static int partial_stripe_write(struct btrfs_raid_bio *rbio)
-{
- int ret;
-
- ret = lock_stripe_add(rbio);
- if (ret == 0)
- start_async_work(rbio, rmw_work);
+ index_stripe_sectors(rbio);
return 0;
}
/*
- * sometimes while we were reading from the drive to
- * recalculate parity, enough new bios come into create
- * a full stripe. So we do a check here to see if we can
- * go directly to finish_rmw
- */
-static int __raid56_parity_write(struct btrfs_raid_bio *rbio)
-{
- /* head off into rmw land if we don't have a full stripe */
- if (!rbio_is_full(rbio))
- return partial_stripe_write(rbio);
- return full_stripe_write(rbio);
-}
-
-/*
* We use plugging call backs to collect full stripes.
* Any time we get a partial stripe write while plugged
* we collect it into a list. When the unplug comes down,
@@ -1704,71 +1591,39 @@ static int plug_cmp(void *priv, const struct list_head *a,
return 0;
}
-static void run_plug(struct btrfs_plug_cb *plug)
+static void raid_unplug(struct blk_plug_cb *cb, bool from_schedule)
{
+ struct btrfs_plug_cb *plug = container_of(cb, struct btrfs_plug_cb, cb);
struct btrfs_raid_bio *cur;
struct btrfs_raid_bio *last = NULL;
- /*
- * sort our plug list then try to merge
- * everything we can in hopes of creating full
- * stripes.
- */
list_sort(NULL, &plug->rbio_list, plug_cmp);
+
while (!list_empty(&plug->rbio_list)) {
cur = list_entry(plug->rbio_list.next,
struct btrfs_raid_bio, plug_list);
list_del_init(&cur->plug_list);
if (rbio_is_full(cur)) {
- int ret;
-
- /* we have a full stripe, send it down */
- ret = full_stripe_write(cur);
- BUG_ON(ret);
+ /* We have a full stripe, queue it down. */
+ start_async_work(cur, rmw_rbio_work);
continue;
}
if (last) {
if (rbio_can_merge(last, cur)) {
merge_rbio(last, cur);
- __free_raid_bio(cur);
+ free_raid_bio(cur);
continue;
-
}
- __raid56_parity_write(last);
+ start_async_work(last, rmw_rbio_work);
}
last = cur;
}
- if (last) {
- __raid56_parity_write(last);
- }
+ if (last)
+ start_async_work(last, rmw_rbio_work);
kfree(plug);
}
-/*
- * if the unplug comes from schedule, we have to push the
- * work off to a helper thread
- */
-static void unplug_work(struct work_struct *work)
-{
- struct btrfs_plug_cb *plug;
- plug = container_of(work, struct btrfs_plug_cb, work);
- run_plug(plug);
-}
-
-static void btrfs_raid_unplug(struct blk_plug_cb *cb, bool from_schedule)
-{
- struct btrfs_plug_cb *plug;
- plug = container_of(cb, struct btrfs_plug_cb, cb);
-
- if (from_schedule) {
- INIT_WORK(&plug->work, unplug_work);
- queue_work(plug->info->rmw_workers, &plug->work);
- return;
- }
- run_plug(plug);
-}
-
/* Add the original bio into rbio->bio_list, and update rbio::dbitmap. */
static void rbio_add_bio(struct btrfs_raid_bio *rbio, struct bio *orig_bio)
{
@@ -1816,19 +1671,13 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc)
rbio_add_bio(rbio, bio);
/*
- * don't plug on full rbios, just get them out the door
+ * Don't plug on full rbios, just get them out the door
* as quickly as we can
*/
- if (rbio_is_full(rbio)) {
- ret = full_stripe_write(rbio);
- if (ret) {
- __free_raid_bio(rbio);
- goto fail;
- }
- return;
- }
+ if (rbio_is_full(rbio))
+ goto queue_rbio;
- cb = blk_check_plugged(btrfs_raid_unplug, fs_info, sizeof(*plug));
+ cb = blk_check_plugged(raid_unplug, fs_info, sizeof(*plug));
if (cb) {
plug = container_of(cb, struct btrfs_plug_cb, cb);
if (!plug->info) {
@@ -1836,13 +1685,14 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc)
INIT_LIST_HEAD(&plug->rbio_list);
}
list_add_tail(&rbio->plug_list, &plug->rbio_list);
- } else {
- ret = __raid56_parity_write(rbio);
- if (ret) {
- __free_raid_bio(rbio);
- goto fail;
- }
+ return;
}
+queue_rbio:
+ /*
+ * Either we don't have any existing plug, or we're doing a full stripe,
+ * can queue the rmw work now.
+ */
+ start_async_work(rbio, rmw_rbio_work);
return;
@@ -1851,268 +1701,254 @@ fail:
bio_endio(bio);
}
-/*
- * all parity reconstruction happens here. We've read in everything
- * we can find from the drives and this does the heavy lifting of
- * sorting the good from the bad.
- */
-static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)
+static int verify_one_sector(struct btrfs_raid_bio *rbio,
+ int stripe_nr, int sector_nr)
{
- const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
- int sectornr, stripe;
- void **pointers;
- void **unmap_array;
- int faila = -1, failb = -1;
- blk_status_t err;
- int i;
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ struct sector_ptr *sector;
+ u8 csum_buf[BTRFS_CSUM_SIZE];
+ u8 *csum_expected;
+ int ret;
- /*
- * This array stores the pointer for each sector, thus it has the extra
- * pgoff value added from each sector
- */
- pointers = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
- if (!pointers) {
- err = BLK_STS_RESOURCE;
- goto cleanup_io;
- }
+ if (!rbio->csum_bitmap || !rbio->csum_buf)
+ return 0;
+ /* No way to verify P/Q as they are not covered by data csum. */
+ if (stripe_nr >= rbio->nr_data)
+ return 0;
/*
- * Store copy of pointers that does not get reordered during
- * reconstruction so that kunmap_local works.
+ * If we're rebuilding a read, we have to use pages from the
+ * bio list if possible.
*/
- unmap_array = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
- if (!unmap_array) {
- err = BLK_STS_RESOURCE;
- goto cleanup_pointers;
+ if ((rbio->operation == BTRFS_RBIO_READ_REBUILD ||
+ rbio->operation == BTRFS_RBIO_REBUILD_MISSING)) {
+ sector = sector_in_rbio(rbio, stripe_nr, sector_nr, 0);
+ } else {
+ sector = rbio_stripe_sector(rbio, stripe_nr, sector_nr);
}
- faila = rbio->faila;
- failb = rbio->failb;
+ ASSERT(sector->page);
- if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
- rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
- spin_lock_irq(&rbio->bio_list_lock);
- set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags);
- spin_unlock_irq(&rbio->bio_list_lock);
- }
+ csum_expected = rbio->csum_buf +
+ (stripe_nr * rbio->stripe_nsectors + sector_nr) *
+ fs_info->csum_size;
+ ret = btrfs_check_sector_csum(fs_info, sector->page, sector->pgoff,
+ csum_buf, csum_expected);
+ return ret;
+}
- index_rbio_pages(rbio);
+/*
+ * Recover a vertical stripe specified by @sector_nr.
+ * @*pointers are the pre-allocated pointers by the caller, so we don't
+ * need to allocate/free the pointers again and again.
+ */
+static int recover_vertical(struct btrfs_raid_bio *rbio, int sector_nr,
+ void **pointers, void **unmap_array)
+{
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ struct sector_ptr *sector;
+ const u32 sectorsize = fs_info->sectorsize;
+ int found_errors;
+ int faila;
+ int failb;
+ int stripe_nr;
+ int ret = 0;
- for (sectornr = 0; sectornr < rbio->stripe_nsectors; sectornr++) {
- struct sector_ptr *sector;
+ /*
+ * Now we just use bitmap to mark the horizontal stripes in
+ * which we have data when doing parity scrub.
+ */
+ if (rbio->operation == BTRFS_RBIO_PARITY_SCRUB &&
+ !test_bit(sector_nr, &rbio->dbitmap))
+ return 0;
- /*
- * Now we just use bitmap to mark the horizontal stripes in
- * which we have data when doing parity scrub.
- */
- if (rbio->operation == BTRFS_RBIO_PARITY_SCRUB &&
- !test_bit(sectornr, &rbio->dbitmap))
- continue;
+ found_errors = get_rbio_veritical_errors(rbio, sector_nr, &faila,
+ &failb);
+ /*
+ * No errors in the veritical stripe, skip it. Can happen for recovery
+ * which only part of a stripe failed csum check.
+ */
+ if (!found_errors)
+ return 0;
+ if (found_errors > rbio->bioc->max_errors)
+ return -EIO;
+
+ /*
+ * Setup our array of pointers with sectors from each stripe
+ *
+ * NOTE: store a duplicate array of pointers to preserve the
+ * pointer order.
+ */
+ for (stripe_nr = 0; stripe_nr < rbio->real_stripes; stripe_nr++) {
/*
- * Setup our array of pointers with sectors from each stripe
- *
- * NOTE: store a duplicate array of pointers to preserve the
- * pointer order
+ * If we're rebuilding a read, we have to use pages from the
+ * bio list if possible.
*/
- for (stripe = 0; stripe < rbio->real_stripes; stripe++) {
- /*
- * If we're rebuilding a read, we have to use
- * pages from the bio list
- */
- if ((rbio->operation == BTRFS_RBIO_READ_REBUILD ||
- rbio->operation == BTRFS_RBIO_REBUILD_MISSING) &&
- (stripe == faila || stripe == failb)) {
- sector = sector_in_rbio(rbio, stripe, sectornr, 0);
- } else {
- sector = rbio_stripe_sector(rbio, stripe, sectornr);
- }
- ASSERT(sector->page);
- pointers[stripe] = kmap_local_page(sector->page) +
- sector->pgoff;
- unmap_array[stripe] = pointers[stripe];
+ if ((rbio->operation == BTRFS_RBIO_READ_REBUILD ||
+ rbio->operation == BTRFS_RBIO_REBUILD_MISSING)) {
+ sector = sector_in_rbio(rbio, stripe_nr, sector_nr, 0);
+ } else {
+ sector = rbio_stripe_sector(rbio, stripe_nr, sector_nr);
}
+ ASSERT(sector->page);
+ pointers[stripe_nr] = kmap_local_page(sector->page) +
+ sector->pgoff;
+ unmap_array[stripe_nr] = pointers[stripe_nr];
+ }
- /* All raid6 handling here */
- if (rbio->bioc->map_type & BTRFS_BLOCK_GROUP_RAID6) {
- /* Single failure, rebuild from parity raid5 style */
- if (failb < 0) {
- if (faila == rbio->nr_data) {
- /*
- * Just the P stripe has failed, without
- * a bad data or Q stripe.
- * TODO, we should redo the xor here.
- */
- err = BLK_STS_IOERR;
- goto cleanup;
- }
+ /* All raid6 handling here */
+ if (rbio->bioc->map_type & BTRFS_BLOCK_GROUP_RAID6) {
+ /* Single failure, rebuild from parity raid5 style */
+ if (failb < 0) {
+ if (faila == rbio->nr_data)
/*
- * a single failure in raid6 is rebuilt
- * in the pstripe code below
+ * Just the P stripe has failed, without
+ * a bad data or Q stripe.
+ * We have nothing to do, just skip the
+ * recovery for this stripe.
*/
- goto pstripe;
- }
-
- /* make sure our ps and qs are in order */
- if (faila > failb)
- swap(faila, failb);
-
- /* if the q stripe is failed, do a pstripe reconstruction
- * from the xors.
- * If both the q stripe and the P stripe are failed, we're
- * here due to a crc mismatch and we can't give them the
- * data they want
+ goto cleanup;
+ /*
+ * a single failure in raid6 is rebuilt
+ * in the pstripe code below
*/
- if (rbio->bioc->raid_map[failb] == RAID6_Q_STRIPE) {
- if (rbio->bioc->raid_map[faila] ==
- RAID5_P_STRIPE) {
- err = BLK_STS_IOERR;
- goto cleanup;
- }
+ goto pstripe;
+ }
+
+ /*
+ * If the q stripe is failed, do a pstripe reconstruction from
+ * the xors.
+ * If both the q stripe and the P stripe are failed, we're
+ * here due to a crc mismatch and we can't give them the
+ * data they want.
+ */
+ if (rbio->bioc->raid_map[failb] == RAID6_Q_STRIPE) {
+ if (rbio->bioc->raid_map[faila] ==
+ RAID5_P_STRIPE)
/*
- * otherwise we have one bad data stripe and
- * a good P stripe. raid5!
+ * Only P and Q are corrupted.
+ * We only care about data stripes recovery,
+ * can skip this vertical stripe.
*/
- goto pstripe;
- }
+ goto cleanup;
+ /*
+ * Otherwise we have one bad data stripe and
+ * a good P stripe. raid5!
+ */
+ goto pstripe;
+ }
- if (rbio->bioc->raid_map[failb] == RAID5_P_STRIPE) {
- raid6_datap_recov(rbio->real_stripes,
- sectorsize, faila, pointers);
- } else {
- raid6_2data_recov(rbio->real_stripes,
- sectorsize, faila, failb,
- pointers);
- }
+ if (rbio->bioc->raid_map[failb] == RAID5_P_STRIPE) {
+ raid6_datap_recov(rbio->real_stripes, sectorsize,
+ faila, pointers);
} else {
- void *p;
+ raid6_2data_recov(rbio->real_stripes, sectorsize,
+ faila, failb, pointers);
+ }
+ } else {
+ void *p;
- /* rebuild from P stripe here (raid5 or raid6) */
- BUG_ON(failb != -1);
+ /* Rebuild from P stripe here (raid5 or raid6). */
+ ASSERT(failb == -1);
pstripe:
- /* Copy parity block into failed block to start with */
- memcpy(pointers[faila], pointers[rbio->nr_data], sectorsize);
+ /* Copy parity block into failed block to start with */
+ memcpy(pointers[faila], pointers[rbio->nr_data], sectorsize);
- /* rearrange the pointer array */
- p = pointers[faila];
- for (stripe = faila; stripe < rbio->nr_data - 1; stripe++)
- pointers[stripe] = pointers[stripe + 1];
- pointers[rbio->nr_data - 1] = p;
+ /* Rearrange the pointer array */
+ p = pointers[faila];
+ for (stripe_nr = faila; stripe_nr < rbio->nr_data - 1;
+ stripe_nr++)
+ pointers[stripe_nr] = pointers[stripe_nr + 1];
+ pointers[rbio->nr_data - 1] = p;
- /* xor in the rest */
- run_xor(pointers, rbio->nr_data - 1, sectorsize);
- }
- /* if we're doing this rebuild as part of an rmw, go through
- * and set all of our private rbio pages in the
- * failed stripes as uptodate. This way finish_rmw will
- * know they can be trusted. If this was a read reconstruction,
- * other endio functions will fiddle the uptodate bits
- */
- if (rbio->operation == BTRFS_RBIO_WRITE) {
- for (i = 0; i < rbio->stripe_nsectors; i++) {
- if (faila != -1) {
- sector = rbio_stripe_sector(rbio, faila, i);
- sector->uptodate = 1;
- }
- if (failb != -1) {
- sector = rbio_stripe_sector(rbio, failb, i);
- sector->uptodate = 1;
- }
- }
- }
- for (stripe = rbio->real_stripes - 1; stripe >= 0; stripe--)
- kunmap_local(unmap_array[stripe]);
+ /* Xor in the rest */
+ run_xor(pointers, rbio->nr_data - 1, sectorsize);
+
+ }
+
+ /*
+ * No matter if this is a RMW or recovery, we should have all
+ * failed sectors repaired in the vertical stripe, thus they are now
+ * uptodate.
+ * Especially if we determine to cache the rbio, we need to
+ * have at least all data sectors uptodate.
+ *
+ * If possible, also check if the repaired sector matches its data
+ * checksum.
+ */
+ if (faila >= 0) {
+ ret = verify_one_sector(rbio, faila, sector_nr);
+ if (ret < 0)
+ goto cleanup;
+
+ sector = rbio_stripe_sector(rbio, faila, sector_nr);
+ sector->uptodate = 1;
+ }
+ if (failb >= 0) {
+ ret = verify_one_sector(rbio, faila, sector_nr);
+ if (ret < 0)
+ goto cleanup;
+
+ sector = rbio_stripe_sector(rbio, failb, sector_nr);
+ sector->uptodate = 1;
}
- err = BLK_STS_OK;
cleanup:
- kfree(unmap_array);
-cleanup_pointers:
- kfree(pointers);
+ for (stripe_nr = rbio->real_stripes - 1; stripe_nr >= 0; stripe_nr--)
+ kunmap_local(unmap_array[stripe_nr]);
+ return ret;
+}
+
+static int recover_sectors(struct btrfs_raid_bio *rbio)
+{
+ void **pointers = NULL;
+ void **unmap_array = NULL;
+ int sectornr;
+ int ret = 0;
-cleanup_io:
/*
- * Similar to READ_REBUILD, REBUILD_MISSING at this point also has a
- * valid rbio which is consistent with ondisk content, thus such a
- * valid rbio can be cached to avoid further disk reads.
+ * @pointers array stores the pointer for each sector.
+ *
+ * @unmap_array stores copy of pointers that does not get reordered
+ * during reconstruction so that kunmap_local works.
*/
+ pointers = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
+ unmap_array = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
+ if (!pointers || !unmap_array) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
- /*
- * - In case of two failures, where rbio->failb != -1:
- *
- * Do not cache this rbio since the above read reconstruction
- * (raid6_datap_recov() or raid6_2data_recov()) may have
- * changed some content of stripes which are not identical to
- * on-disk content any more, otherwise, a later write/recover
- * may steal stripe_pages from this rbio and end up with
- * corruptions or rebuild failures.
- *
- * - In case of single failure, where rbio->failb == -1:
- *
- * Cache this rbio iff the above read reconstruction is
- * executed without problems.
- */
- if (err == BLK_STS_OK && rbio->failb < 0)
- cache_rbio_pages(rbio);
- else
- clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
+ spin_lock_irq(&rbio->bio_list_lock);
+ set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags);
+ spin_unlock_irq(&rbio->bio_list_lock);
+ }
- rbio_orig_end_io(rbio, err);
- } else if (err == BLK_STS_OK) {
- rbio->faila = -1;
- rbio->failb = -1;
+ index_rbio_pages(rbio);
- if (rbio->operation == BTRFS_RBIO_WRITE)
- finish_rmw(rbio);
- else if (rbio->operation == BTRFS_RBIO_PARITY_SCRUB)
- finish_parity_scrub(rbio, 0);
- else
- BUG();
- } else {
- rbio_orig_end_io(rbio, err);
+ for (sectornr = 0; sectornr < rbio->stripe_nsectors; sectornr++) {
+ ret = recover_vertical(rbio, sectornr, pointers, unmap_array);
+ if (ret < 0)
+ break;
}
-}
-
-/*
- * This is called only for stripes we've read from disk to reconstruct the
- * parity.
- */
-static void raid_recover_end_io_work(struct work_struct *work)
-{
- struct btrfs_raid_bio *rbio =
- container_of(work, struct btrfs_raid_bio, end_io_work);
- if (atomic_read(&rbio->error) > rbio->bioc->max_errors)
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
- else
- __raid_recover_end_io(rbio);
+out:
+ kfree(pointers);
+ kfree(unmap_array);
+ return ret;
}
-/*
- * reads everything we need off the disk to reconstruct
- * the parity. endio handlers trigger final reconstruction
- * when the IO is done.
- *
- * This is used both for reads from the higher layers and for
- * parity construction required to finish a rmw cycle.
- */
-static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
+static int recover_assemble_read_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
{
- int bios_to_read = 0;
- struct bio_list bio_list;
- int ret;
- int total_sector_nr;
struct bio *bio;
+ int total_sector_nr;
+ int ret = 0;
- bio_list_init(&bio_list);
-
- ret = alloc_rbio_pages(rbio);
- if (ret)
- goto cleanup;
-
- atomic_set(&rbio->error, 0);
-
+ ASSERT(bio_list_size(bio_list) == 0);
/*
* Read everything that hasn't failed. However this time we will
* not trust any cached sector.
@@ -2127,64 +1963,139 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
int sectornr = total_sector_nr % rbio->stripe_nsectors;
struct sector_ptr *sector;
- if (rbio->faila == stripe || rbio->failb == stripe) {
- atomic_inc(&rbio->error);
- /* Skip the current stripe. */
- ASSERT(sectornr == 0);
- total_sector_nr += rbio->stripe_nsectors - 1;
+ /*
+ * Skip the range which has error. It can be a range which is
+ * marked error (for csum mismatch), or it can be a missing
+ * device.
+ */
+ if (!rbio->bioc->stripes[stripe].dev->bdev ||
+ test_bit(total_sector_nr, rbio->error_bitmap)) {
+ /*
+ * Also set the error bit for missing device, which
+ * may not yet have its error bit set.
+ */
+ set_bit(total_sector_nr, rbio->error_bitmap);
continue;
}
+
sector = rbio_stripe_sector(rbio, stripe, sectornr);
- ret = rbio_add_io_sector(rbio, &bio_list, sector, stripe,
+ ret = rbio_add_io_sector(rbio, bio_list, sector, stripe,
sectornr, REQ_OP_READ);
if (ret < 0)
- goto cleanup;
+ goto error;
}
+ return 0;
+error:
+ while ((bio = bio_list_pop(bio_list)))
+ bio_put(bio);
- bios_to_read = bio_list_size(&bio_list);
- if (!bios_to_read) {
- /*
- * we might have no bios to read just because the pages
- * were up to date, or we might have no bios to read because
- * the devices were gone.
- */
- if (atomic_read(&rbio->error) <= rbio->bioc->max_errors) {
- __raid_recover_end_io(rbio);
- return 0;
- } else {
- goto cleanup;
- }
- }
+ return -EIO;
+}
+
+static int recover_rbio(struct btrfs_raid_bio *rbio)
+{
+ struct bio_list bio_list;
+ struct bio *bio;
+ int ret;
/*
- * The bioc may be freed once we submit the last bio. Make sure not to
- * touch it after that.
+ * Either we're doing recover for a read failure or degraded write,
+ * caller should have set error bitmap correctly.
*/
- atomic_set(&rbio->stripes_pending, bios_to_read);
- INIT_WORK(&rbio->end_io_work, raid_recover_end_io_work);
- while ((bio = bio_list_pop(&bio_list))) {
- bio->bi_end_io = raid56_bio_end_io;
+ ASSERT(bitmap_weight(rbio->error_bitmap, rbio->nr_sectors));
+ bio_list_init(&bio_list);
- if (trace_raid56_scrub_read_recover_enabled()) {
- struct raid56_bio_trace_info trace_info = { 0 };
+ /* For recovery, we need to read all sectors including P/Q. */
+ ret = alloc_rbio_pages(rbio);
+ if (ret < 0)
+ goto out;
- bio_get_trace_info(rbio, bio, &trace_info);
- trace_raid56_scrub_read_recover(rbio, bio, &trace_info);
- }
- submit_bio(bio);
- }
+ index_rbio_pages(rbio);
- return 0;
+ ret = recover_assemble_read_bios(rbio, &bio_list);
+ if (ret < 0)
+ goto out;
-cleanup:
- if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
- rbio->operation == BTRFS_RBIO_REBUILD_MISSING)
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
+ submit_read_bios(rbio, &bio_list);
+ wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
+
+ ret = recover_sectors(rbio);
+out:
while ((bio = bio_list_pop(&bio_list)))
bio_put(bio);
- return -EIO;
+ return ret;
+}
+
+static void recover_rbio_work(struct work_struct *work)
+{
+ struct btrfs_raid_bio *rbio;
+ int ret;
+
+ rbio = container_of(work, struct btrfs_raid_bio, work);
+
+ ret = lock_stripe_add(rbio);
+ if (ret == 0) {
+ ret = recover_rbio(rbio);
+ rbio_orig_end_io(rbio, errno_to_blk_status(ret));
+ }
+}
+
+static void recover_rbio_work_locked(struct work_struct *work)
+{
+ struct btrfs_raid_bio *rbio;
+ int ret;
+
+ rbio = container_of(work, struct btrfs_raid_bio, work);
+
+ ret = recover_rbio(rbio);
+ rbio_orig_end_io(rbio, errno_to_blk_status(ret));
+}
+
+static void set_rbio_raid6_extra_error(struct btrfs_raid_bio *rbio, int mirror_num)
+{
+ bool found = false;
+ int sector_nr;
+
+ /*
+ * This is for RAID6 extra recovery tries, thus mirror number should
+ * be large than 2.
+ * Mirror 1 means read from data stripes. Mirror 2 means rebuild using
+ * RAID5 methods.
+ */
+ ASSERT(mirror_num > 2);
+ for (sector_nr = 0; sector_nr < rbio->stripe_nsectors; sector_nr++) {
+ int found_errors;
+ int faila;
+ int failb;
+
+ found_errors = get_rbio_veritical_errors(rbio, sector_nr,
+ &faila, &failb);
+ /* This vertical stripe doesn't have errors. */
+ if (!found_errors)
+ continue;
+
+ /*
+ * If we found errors, there should be only one error marked
+ * by previous set_rbio_range_error().
+ */
+ ASSERT(found_errors == 1);
+ found = true;
+
+ /* Now select another stripe to mark as error. */
+ failb = rbio->real_stripes - (mirror_num - 1);
+ if (failb <= faila)
+ failb--;
+
+ /* Set the extra bit in error bitmap. */
+ if (failb >= 0)
+ set_bit(failb * rbio->stripe_nsectors + sector_nr,
+ rbio->error_bitmap);
+ }
+
+ /* We should found at least one vertical stripe with error.*/
+ ASSERT(found);
}
/*
@@ -2202,68 +2113,284 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
rbio = alloc_rbio(fs_info, bioc);
if (IS_ERR(rbio)) {
bio->bi_status = errno_to_blk_status(PTR_ERR(rbio));
- goto out_end_bio;
+ bio_endio(bio);
+ return;
}
rbio->operation = BTRFS_RBIO_READ_REBUILD;
rbio_add_bio(rbio, bio);
- rbio->faila = find_logical_bio_stripe(rbio, bio);
- if (rbio->faila == -1) {
- btrfs_warn(fs_info,
-"%s could not find the bad stripe in raid56 so that we cannot recover any more (bio has logical %llu len %llu, bioc has map_type %llu)",
- __func__, bio->bi_iter.bi_sector << 9,
- (u64)bio->bi_iter.bi_size, bioc->map_type);
- __free_raid_bio(rbio);
- bio->bi_status = BLK_STS_IOERR;
- goto out_end_bio;
- }
+ set_rbio_range_error(rbio, bio);
/*
* Loop retry:
* for 'mirror == 2', reconstruct from all other stripes.
* for 'mirror_num > 2', select a stripe to fail on every retry.
*/
- if (mirror_num > 2) {
+ if (mirror_num > 2)
+ set_rbio_raid6_extra_error(rbio, mirror_num);
+
+ start_async_work(rbio, recover_rbio_work);
+}
+
+static void fill_data_csums(struct btrfs_raid_bio *rbio)
+{
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ struct btrfs_root *csum_root = btrfs_csum_root(fs_info,
+ rbio->bioc->raid_map[0]);
+ const u64 start = rbio->bioc->raid_map[0];
+ const u32 len = (rbio->nr_data * rbio->stripe_nsectors) <<
+ fs_info->sectorsize_bits;
+ int ret;
+
+ /* The rbio should not have its csum buffer initialized. */
+ ASSERT(!rbio->csum_buf && !rbio->csum_bitmap);
+
+ /*
+ * Skip the csum search if:
+ *
+ * - The rbio doesn't belong to data block groups
+ * Then we are doing IO for tree blocks, no need to search csums.
+ *
+ * - The rbio belongs to mixed block groups
+ * This is to avoid deadlock, as we're already holding the full
+ * stripe lock, if we trigger a metadata read, and it needs to do
+ * raid56 recovery, we will deadlock.
+ */
+ if (!(rbio->bioc->map_type & BTRFS_BLOCK_GROUP_DATA) ||
+ rbio->bioc->map_type & BTRFS_BLOCK_GROUP_METADATA)
+ return;
+
+ rbio->csum_buf = kzalloc(rbio->nr_data * rbio->stripe_nsectors *
+ fs_info->csum_size, GFP_NOFS);
+ rbio->csum_bitmap = bitmap_zalloc(rbio->nr_data * rbio->stripe_nsectors,
+ GFP_NOFS);
+ if (!rbio->csum_buf || !rbio->csum_bitmap) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = btrfs_lookup_csums_bitmap(csum_root, start, start + len - 1,
+ rbio->csum_buf, rbio->csum_bitmap);
+ if (ret < 0)
+ goto error;
+ if (bitmap_empty(rbio->csum_bitmap, len >> fs_info->sectorsize_bits))
+ goto no_csum;
+ return;
+
+error:
+ /*
+ * We failed to allocate memory or grab the csum, but it's not fatal,
+ * we can still continue. But better to warn users that RMW is no
+ * longer safe for this particular sub-stripe write.
+ */
+ btrfs_warn_rl(fs_info,
+"sub-stripe write for full stripe %llu is not safe, failed to get csum: %d",
+ rbio->bioc->raid_map[0], ret);
+no_csum:
+ kfree(rbio->csum_buf);
+ bitmap_free(rbio->csum_bitmap);
+ rbio->csum_buf = NULL;
+ rbio->csum_bitmap = NULL;
+}
+
+static int rmw_read_wait_recover(struct btrfs_raid_bio *rbio)
+{
+ struct bio_list bio_list;
+ struct bio *bio;
+ int ret;
+
+ bio_list_init(&bio_list);
+
+ /*
+ * Fill the data csums we need for data verification. We need to fill
+ * the csum_bitmap/csum_buf first, as our endio function will try to
+ * verify the data sectors.
+ */
+ fill_data_csums(rbio);
+
+ ret = rmw_assemble_read_bios(rbio, &bio_list);
+ if (ret < 0)
+ goto out;
+
+ submit_read_bios(rbio, &bio_list);
+ wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
+
+ /*
+ * We may or may not have any corrupted sectors (including missing dev
+ * and csum mismatch), just let recover_sectors() to handle them all.
+ */
+ ret = recover_sectors(rbio);
+ return ret;
+out:
+ while ((bio = bio_list_pop(&bio_list)))
+ bio_put(bio);
+
+ return ret;
+}
+
+static void raid_wait_write_end_io(struct bio *bio)
+{
+ struct btrfs_raid_bio *rbio = bio->bi_private;
+ blk_status_t err = bio->bi_status;
+
+ if (err)
+ rbio_update_error_bitmap(rbio, bio);
+ bio_put(bio);
+ if (atomic_dec_and_test(&rbio->stripes_pending))
+ wake_up(&rbio->io_wait);
+}
+
+static void submit_write_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
+{
+ struct bio *bio;
+
+ atomic_set(&rbio->stripes_pending, bio_list_size(bio_list));
+ while ((bio = bio_list_pop(bio_list))) {
+ bio->bi_end_io = raid_wait_write_end_io;
+
+ if (trace_raid56_write_stripe_enabled()) {
+ struct raid56_bio_trace_info trace_info = { 0 };
+
+ bio_get_trace_info(rbio, bio, &trace_info);
+ trace_raid56_write_stripe(rbio, bio, &trace_info);
+ }
+ submit_bio(bio);
+ }
+}
+
+/*
+ * To determine if we need to read any sector from the disk.
+ * Should only be utilized in RMW path, to skip cached rbio.
+ */
+static bool need_read_stripe_sectors(struct btrfs_raid_bio *rbio)
+{
+ int i;
+
+ for (i = 0; i < rbio->nr_data * rbio->stripe_nsectors; i++) {
+ struct sector_ptr *sector = &rbio->stripe_sectors[i];
+
/*
- * 'mirror == 3' is to fail the p stripe and
- * reconstruct from the q stripe. 'mirror > 3' is to
- * fail a data stripe and reconstruct from p+q stripe.
+ * We have a sector which doesn't have page nor uptodate,
+ * thus this rbio can not be cached one, as cached one must
+ * have all its data sectors present and uptodate.
*/
- rbio->failb = rbio->real_stripes - (mirror_num - 1);
- ASSERT(rbio->failb > 0);
- if (rbio->failb <= rbio->faila)
- rbio->failb--;
+ if (!sector->page || !sector->uptodate)
+ return true;
}
+ return false;
+}
- if (lock_stripe_add(rbio))
- return;
+static int rmw_rbio(struct btrfs_raid_bio *rbio)
+{
+ struct bio_list bio_list;
+ int sectornr;
+ int ret = 0;
/*
- * This adds our rbio to the list of rbios that will be handled after
- * the current lock owner is done.
+ * Allocate the pages for parity first, as P/Q pages will always be
+ * needed for both full-stripe and sub-stripe writes.
*/
- __raid56_parity_recover(rbio);
- return;
+ ret = alloc_rbio_parity_pages(rbio);
+ if (ret < 0)
+ return ret;
-out_end_bio:
- bio_endio(bio);
+ /*
+ * Either full stripe write, or we have every data sector already
+ * cached, can go to write path immediately.
+ */
+ if (rbio_is_full(rbio) || !need_read_stripe_sectors(rbio))
+ goto write;
+
+ /*
+ * Now we're doing sub-stripe write, also need all data stripes to do
+ * the full RMW.
+ */
+ ret = alloc_rbio_data_pages(rbio);
+ if (ret < 0)
+ return ret;
+
+ index_rbio_pages(rbio);
+
+ ret = rmw_read_wait_recover(rbio);
+ if (ret < 0)
+ return ret;
+
+write:
+ /*
+ * At this stage we're not allowed to add any new bios to the
+ * bio list any more, anyone else that wants to change this stripe
+ * needs to do their own rmw.
+ */
+ spin_lock_irq(&rbio->bio_list_lock);
+ set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags);
+ spin_unlock_irq(&rbio->bio_list_lock);
+
+ bitmap_clear(rbio->error_bitmap, 0, rbio->nr_sectors);
+
+ index_rbio_pages(rbio);
+
+ /*
+ * We don't cache full rbios because we're assuming
+ * the higher layers are unlikely to use this area of
+ * the disk again soon. If they do use it again,
+ * hopefully they will send another full bio.
+ */
+ if (!rbio_is_full(rbio))
+ cache_rbio_pages(rbio);
+ else
+ clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
+
+ for (sectornr = 0; sectornr < rbio->stripe_nsectors; sectornr++)
+ generate_pq_vertical(rbio, sectornr);
+
+ bio_list_init(&bio_list);
+ ret = rmw_assemble_write_bios(rbio, &bio_list);
+ if (ret < 0)
+ return ret;
+
+ /* We should have at least one bio assembled. */
+ ASSERT(bio_list_size(&bio_list));
+ submit_write_bios(rbio, &bio_list);
+ wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
+
+ /* We may have more errors than our tolerance during the read. */
+ for (sectornr = 0; sectornr < rbio->stripe_nsectors; sectornr++) {
+ int found_errors;
+
+ found_errors = get_rbio_veritical_errors(rbio, sectornr, NULL, NULL);
+ if (found_errors > rbio->bioc->max_errors) {
+ ret = -EIO;
+ break;
+ }
+ }
+ return ret;
}
-static void rmw_work(struct work_struct *work)
+static void rmw_rbio_work(struct work_struct *work)
{
struct btrfs_raid_bio *rbio;
+ int ret;
rbio = container_of(work, struct btrfs_raid_bio, work);
- raid56_rmw_stripe(rbio);
+
+ ret = lock_stripe_add(rbio);
+ if (ret == 0) {
+ ret = rmw_rbio(rbio);
+ rbio_orig_end_io(rbio, errno_to_blk_status(ret));
+ }
}
-static void read_rebuild_work(struct work_struct *work)
+static void rmw_rbio_work_locked(struct work_struct *work)
{
struct btrfs_raid_bio *rbio;
+ int ret;
rbio = container_of(work, struct btrfs_raid_bio, work);
- __raid56_parity_recover(rbio);
+
+ ret = rmw_rbio(rbio);
+ rbio_orig_end_io(rbio, errno_to_blk_status(ret));
}
/*
@@ -2358,8 +2485,7 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio)
return 0;
}
-static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
- int need_check)
+static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check)
{
struct btrfs_io_context *bioc = rbio->bioc;
const u32 sectorsize = bioc->fs_info->sectorsize;
@@ -2402,7 +2528,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
p_sector.page = alloc_page(GFP_NOFS);
if (!p_sector.page)
- goto cleanup;
+ return -ENOMEM;
p_sector.pgoff = 0;
p_sector.uptodate = 1;
@@ -2412,14 +2538,14 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
if (!q_sector.page) {
__free_page(p_sector.page);
p_sector.page = NULL;
- goto cleanup;
+ return -ENOMEM;
}
q_sector.pgoff = 0;
q_sector.uptodate = 1;
pointers[rbio->real_stripes - 1] = kmap_local_page(q_sector.page);
}
- atomic_set(&rbio->error, 0);
+ bitmap_clear(rbio->error_bitmap, 0, rbio->nr_sectors);
/* Map the parity stripe just once */
pointers[nr_data] = kmap_local_page(p_sector.page);
@@ -2499,33 +2625,13 @@ writeback:
}
submit_write:
- nr_data = bio_list_size(&bio_list);
- if (!nr_data) {
- /* Every parity is right */
- rbio_orig_end_io(rbio, BLK_STS_OK);
- return;
- }
-
- atomic_set(&rbio->stripes_pending, nr_data);
-
- while ((bio = bio_list_pop(&bio_list))) {
- bio->bi_end_io = raid_write_end_io;
-
- if (trace_raid56_scrub_write_stripe_enabled()) {
- struct raid56_bio_trace_info trace_info = { 0 };
-
- bio_get_trace_info(rbio, bio, &trace_info);
- trace_raid56_scrub_write_stripe(rbio, bio, &trace_info);
- }
- submit_bio(bio);
- }
- return;
+ submit_write_bios(rbio, &bio_list);
+ return 0;
cleanup:
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
-
while ((bio = bio_list_pop(&bio_list)))
bio_put(bio);
+ return ret;
}
static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe)
@@ -2535,102 +2641,99 @@ static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe)
return 0;
}
-/*
- * While we're doing the parity check and repair, we could have errors
- * in reading pages off the disk. This checks for errors and if we're
- * not able to read the page it'll trigger parity reconstruction. The
- * parity scrub will be finished after we've reconstructed the failed
- * stripes
- */
-static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio)
+static int recover_scrub_rbio(struct btrfs_raid_bio *rbio)
{
- if (atomic_read(&rbio->error) > rbio->bioc->max_errors)
- goto cleanup;
+ void **pointers = NULL;
+ void **unmap_array = NULL;
+ int sector_nr;
+ int ret;
+
+ /*
+ * @pointers array stores the pointer for each sector.
+ *
+ * @unmap_array stores copy of pointers that does not get reordered
+ * during reconstruction so that kunmap_local works.
+ */
+ pointers = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
+ unmap_array = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS);
+ if (!pointers || !unmap_array) {
+ ret = -ENOMEM;
+ goto out;
+ }
- if (rbio->faila >= 0 || rbio->failb >= 0) {
+ for (sector_nr = 0; sector_nr < rbio->stripe_nsectors; sector_nr++) {
int dfail = 0, failp = -1;
+ int faila;
+ int failb;
+ int found_errors;
+
+ found_errors = get_rbio_veritical_errors(rbio, sector_nr,
+ &faila, &failb);
+ if (found_errors > rbio->bioc->max_errors) {
+ ret = -EIO;
+ goto out;
+ }
+ if (found_errors == 0)
+ continue;
- if (is_data_stripe(rbio, rbio->faila))
- dfail++;
- else if (is_parity_stripe(rbio->faila))
- failp = rbio->faila;
+ /* We should have at least one error here. */
+ ASSERT(faila >= 0 || failb >= 0);
- if (is_data_stripe(rbio, rbio->failb))
+ if (is_data_stripe(rbio, faila))
dfail++;
- else if (is_parity_stripe(rbio->failb))
- failp = rbio->failb;
+ else if (is_parity_stripe(faila))
+ failp = faila;
+ if (is_data_stripe(rbio, failb))
+ dfail++;
+ else if (is_parity_stripe(failb))
+ failp = failb;
/*
- * Because we can not use a scrubbing parity to repair
- * the data, so the capability of the repair is declined.
- * (In the case of RAID5, we can not repair anything)
+ * Because we can not use a scrubbing parity to repair the
+ * data, so the capability of the repair is declined. (In the
+ * case of RAID5, we can not repair anything.)
*/
- if (dfail > rbio->bioc->max_errors - 1)
- goto cleanup;
-
+ if (dfail > rbio->bioc->max_errors - 1) {
+ ret = -EIO;
+ goto out;
+ }
/*
- * If all data is good, only parity is correctly, just
- * repair the parity.
+ * If all data is good, only parity is correctly, just repair
+ * the parity, no need to recover data stripes.
*/
- if (dfail == 0) {
- finish_parity_scrub(rbio, 0);
- return;
- }
+ if (dfail == 0)
+ continue;
/*
* Here means we got one corrupted data stripe and one
- * corrupted parity on RAID6, if the corrupted parity
- * is scrubbing parity, luckily, use the other one to repair
- * the data, or we can not repair the data stripe.
+ * corrupted parity on RAID6, if the corrupted parity is
+ * scrubbing parity, luckily, use the other one to repair the
+ * data, or we can not repair the data stripe.
*/
- if (failp != rbio->scrubp)
- goto cleanup;
+ if (failp != rbio->scrubp) {
+ ret = -EIO;
+ goto out;
+ }
- __raid_recover_end_io(rbio);
- } else {
- finish_parity_scrub(rbio, 1);
+ ret = recover_vertical(rbio, sector_nr, pointers, unmap_array);
+ if (ret < 0)
+ goto out;
}
- return;
-
-cleanup:
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
-}
-
-/*
- * end io for the read phase of the rmw cycle. All the bios here are physical
- * stripe bios we've read from the disk so we can recalculate the parity of the
- * stripe.
- *
- * This will usually kick off finish_rmw once all the bios are read in, but it
- * may trigger parity reconstruction if we had any errors along the way
- */
-static void raid56_parity_scrub_end_io_work(struct work_struct *work)
-{
- struct btrfs_raid_bio *rbio =
- container_of(work, struct btrfs_raid_bio, end_io_work);
-
- /*
- * This will normally call finish_rmw to start our write, but if there
- * are any failed stripes we'll reconstruct from parity first
- */
- validate_rbio_for_parity_scrub(rbio);
+out:
+ kfree(pointers);
+ kfree(unmap_array);
+ return ret;
}
-static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio)
+static int scrub_assemble_read_bios(struct btrfs_raid_bio *rbio,
+ struct bio_list *bio_list)
{
- int bios_to_read = 0;
- struct bio_list bio_list;
- int ret;
- int total_sector_nr;
struct bio *bio;
+ int total_sector_nr;
+ int ret = 0;
- bio_list_init(&bio_list);
-
- ret = alloc_rbio_essential_pages(rbio);
- if (ret)
- goto cleanup;
+ ASSERT(bio_list_size(bio_list) == 0);
- atomic_set(&rbio->error, 0);
/* Build a list of bios to read all the missing parts. */
for (total_sector_nr = 0; total_sector_nr < rbio->nr_sectors;
total_sector_nr++) {
@@ -2659,67 +2762,84 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio)
if (sector->uptodate)
continue;
- ret = rbio_add_io_sector(rbio, &bio_list, sector, stripe,
+ ret = rbio_add_io_sector(rbio, bio_list, sector, stripe,
sectornr, REQ_OP_READ);
if (ret)
- goto cleanup;
+ goto error;
}
+ return 0;
+error:
+ while ((bio = bio_list_pop(bio_list)))
+ bio_put(bio);
+ return ret;
+}
- bios_to_read = bio_list_size(&bio_list);
- if (!bios_to_read) {
- /*
- * this can happen if others have merged with
- * us, it means there is nothing left to read.
- * But if there are missing devices it may not be
- * safe to do the full stripe write yet.
- */
- goto finish;
- }
+static int scrub_rbio(struct btrfs_raid_bio *rbio)
+{
+ bool need_check = false;
+ struct bio_list bio_list;
+ int sector_nr;
+ int ret;
+ struct bio *bio;
- /*
- * The bioc may be freed once we submit the last bio. Make sure not to
- * touch it after that.
- */
- atomic_set(&rbio->stripes_pending, bios_to_read);
- INIT_WORK(&rbio->end_io_work, raid56_parity_scrub_end_io_work);
- while ((bio = bio_list_pop(&bio_list))) {
- bio->bi_end_io = raid56_bio_end_io;
+ bio_list_init(&bio_list);
- if (trace_raid56_scrub_read_enabled()) {
- struct raid56_bio_trace_info trace_info = { 0 };
+ ret = alloc_rbio_essential_pages(rbio);
+ if (ret)
+ goto cleanup;
- bio_get_trace_info(rbio, bio, &trace_info);
- trace_raid56_scrub_read(rbio, bio, &trace_info);
+ bitmap_clear(rbio->error_bitmap, 0, rbio->nr_sectors);
+
+ ret = scrub_assemble_read_bios(rbio, &bio_list);
+ if (ret < 0)
+ goto cleanup;
+
+ submit_read_bios(rbio, &bio_list);
+ wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
+
+ /* We may have some failures, recover the failed sectors first. */
+ ret = recover_scrub_rbio(rbio);
+ if (ret < 0)
+ goto cleanup;
+
+ /*
+ * We have every sector properly prepared. Can finish the scrub
+ * and writeback the good content.
+ */
+ ret = finish_parity_scrub(rbio, need_check);
+ wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
+ for (sector_nr = 0; sector_nr < rbio->stripe_nsectors; sector_nr++) {
+ int found_errors;
+
+ found_errors = get_rbio_veritical_errors(rbio, sector_nr, NULL, NULL);
+ if (found_errors > rbio->bioc->max_errors) {
+ ret = -EIO;
+ break;
}
- submit_bio(bio);
}
- /* the actual write will happen once the reads are done */
- return;
+ return ret;
cleanup:
- rbio_orig_end_io(rbio, BLK_STS_IOERR);
-
while ((bio = bio_list_pop(&bio_list)))
bio_put(bio);
- return;
-
-finish:
- validate_rbio_for_parity_scrub(rbio);
+ return ret;
}
-static void scrub_parity_work(struct work_struct *work)
+static void scrub_rbio_work_locked(struct work_struct *work)
{
struct btrfs_raid_bio *rbio;
+ int ret;
rbio = container_of(work, struct btrfs_raid_bio, work);
- raid56_parity_scrub_stripe(rbio);
+ ret = scrub_rbio(rbio);
+ rbio_orig_end_io(rbio, errno_to_blk_status(ret));
}
void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio)
{
if (!lock_stripe_add(rbio))
- start_async_work(rbio, scrub_parity_work);
+ start_async_work(rbio, scrub_rbio_work_locked);
}
/* The following code is used for dev replace of a missing RAID 5/6 device. */
@@ -2742,20 +2862,12 @@ raid56_alloc_missing_rbio(struct bio *bio, struct btrfs_io_context *bioc)
*/
ASSERT(!bio->bi_iter.bi_size);
- rbio->faila = find_logical_bio_stripe(rbio, bio);
- if (rbio->faila == -1) {
- btrfs_warn_rl(fs_info,
- "can not determine the failed stripe number for full stripe %llu",
- bioc->raid_map[0]);
- __free_raid_bio(rbio);
- return NULL;
- }
+ set_rbio_range_error(rbio, bio);
return rbio;
}
void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio)
{
- if (!lock_stripe_add(rbio))
- start_async_work(rbio, read_rebuild_work);
+ start_async_work(rbio, recover_rbio_work);
}
diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h
index 91d5c0adad15..7c73a443939e 100644
--- a/fs/btrfs/raid56.h
+++ b/fs/btrfs/raid56.h
@@ -74,12 +74,6 @@ struct btrfs_raid_bio {
/* How many sectors there are for each stripe */
u8 stripe_nsectors;
- /* First bad stripe, -1 means no corruption */
- s8 faila;
-
- /* Second bad stripe (for RAID6 use) */
- s8 failb;
-
/* Stripe number that we're scrubbing */
u8 scrubp;
@@ -93,9 +87,7 @@ struct btrfs_raid_bio {
atomic_t stripes_pending;
- atomic_t error;
-
- struct work_struct end_io_work;
+ wait_queue_head_t io_wait;
/* Bitmap to record which horizontal stripe has data */
unsigned long dbitmap;
@@ -126,6 +118,29 @@ struct btrfs_raid_bio {
/* Allocated with real_stripes-many pointers for finish_*() calls */
void **finish_pointers;
+
+ /*
+ * The bitmap recording where IO errors happened.
+ * Each bit is corresponding to one sector in either bio_sectors[] or
+ * stripe_sectors[] array.
+ *
+ * The reason we don't use another bit in sector_ptr is, we have two
+ * arrays of sectors, and a lot of IO can use sectors in both arrays.
+ * Thus making it much harder to iterate.
+ */
+ unsigned long *error_bitmap;
+
+ /*
+ * Checksum buffer if the rbio is for data. The buffer should cover
+ * all data sectors (exlcuding P/Q sectors).
+ */
+ u8 *csum_buf;
+
+ /*
+ * Each bit represents if the corresponding sector has data csum found.
+ * Should only cover data sectors (excluding P/Q sectors).
+ */
+ unsigned long *csum_bitmap;
};
/*
diff --git a/fs/btrfs/rcu-string.h b/fs/btrfs/rcu-string.h
index 5c1a617eb25d..5c2b66d155ef 100644
--- a/fs/btrfs/rcu-string.h
+++ b/fs/btrfs/rcu-string.h
@@ -18,7 +18,11 @@ static inline struct rcu_string *rcu_string_strdup(const char *src, gfp_t mask)
(len * sizeof(char)), mask);
if (!ret)
return ret;
- strncpy(ret->str, src, len);
+ /* Warn if the source got unexpectedly truncated. */
+ if (WARN_ON(strscpy(ret->str, src, len) < 0)) {
+ kfree(ret);
+ return NULL;
+ }
return ret;
}
diff --git a/fs/btrfs/ref-verify.c b/fs/btrfs/ref-verify.c
index a248f46cfe72..95d28497de7c 100644
--- a/fs/btrfs/ref-verify.c
+++ b/fs/btrfs/ref-verify.c
@@ -5,11 +5,14 @@
#include <linux/sched.h>
#include <linux/stacktrace.h>
+#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
#include "locking.h"
#include "delayed-ref.h"
#include "ref-verify.h"
+#include "fs.h"
+#include "accessors.h"
/*
* Used to keep track the roots and number of refs each root has for a given
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index f50586ff85c8..0474bbe39da7 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -2,13 +2,19 @@
#include <linux/blkdev.h>
#include <linux/iversion.h>
-#include "compression.h"
#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
+#include "compression.h"
#include "delalloc-space.h"
#include "disk-io.h"
#include "reflink.h"
#include "transaction.h"
#include "subpage.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "file.h"
+#include "super.h"
#define BTRFS_MAX_DEDUPE_LEN SZ_16M
@@ -318,16 +324,16 @@ copy_to_page:
goto out;
}
-/**
- * btrfs_clone() - clone a range from inode file to another
+/*
+ * Clone a range from inode file to another.
*
- * @src: Inode to clone from
- * @inode: Inode to clone to
- * @off: Offset within source to start clone from
- * @olen: Original length, passed by user, of range to clone
- * @olen_aligned: Block-aligned value of olen
- * @destoff: Offset within @inode to start clone
- * @no_time_update: Whether to update mtime/ctime on the target inode
+ * @src: Inode to clone from
+ * @inode: Inode to clone to
+ * @off: Offset within source to start clone from
+ * @olen: Original length, passed by user, of range to clone
+ * @olen_aligned: Block-aligned value of olen
+ * @destoff: Offset within @inode to start clone
+ * @no_time_update: Whether to update mtime/ctime on the target inode
*/
static int btrfs_clone(struct inode *src, struct inode *inode,
const u64 off, const u64 olen, const u64 olen_aligned,
@@ -887,7 +893,7 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
return -EINVAL;
if (same_inode) {
- btrfs_inode_lock(src_inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_lock(BTRFS_I(src_inode), BTRFS_ILOCK_MMAP);
} else {
lock_two_nondirectories(src_inode, dst_inode);
btrfs_double_mmap_lock(src_inode, dst_inode);
@@ -905,7 +911,7 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
out_unlock:
if (same_inode) {
- btrfs_inode_unlock(src_inode, BTRFS_ILOCK_MMAP);
+ btrfs_inode_unlock(BTRFS_I(src_inode), BTRFS_ILOCK_MMAP);
} else {
btrfs_double_mmap_unlock(src_inode, dst_inode);
unlock_two_nondirectories(src_inode, dst_inode);
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 666a37a0ee89..31ec4a7658ce 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -27,6 +27,15 @@
#include "subpage.h"
#include "zoned.h"
#include "inode-item.h"
+#include "space-info.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "file-item.h"
+#include "relocation.h"
+#include "super.h"
+#include "tree-checker.h"
/*
* Relocation overview
@@ -470,7 +479,7 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
int ret;
int err = 0;
- iter = btrfs_backref_iter_alloc(rc->extent_root->fs_info, GFP_NOFS);
+ iter = btrfs_backref_iter_alloc(rc->extent_root->fs_info);
if (!iter)
return ERR_PTR(-ENOMEM);
path = btrfs_alloc_path();
@@ -1109,10 +1118,12 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
inode = find_next_inode(root, key.objectid);
first = 0;
} else if (inode && btrfs_ino(BTRFS_I(inode)) < key.objectid) {
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
inode = find_next_inode(root, key.objectid);
}
if (inode && btrfs_ino(BTRFS_I(inode)) == key.objectid) {
+ struct extent_state *cached_state = NULL;
+
end = key.offset +
btrfs_file_extent_num_bytes(leaf, fi);
WARN_ON(!IS_ALIGNED(key.offset,
@@ -1120,14 +1131,15 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
WARN_ON(!IS_ALIGNED(end, fs_info->sectorsize));
end--;
ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
- key.offset, end);
+ key.offset, end,
+ &cached_state);
if (!ret)
continue;
btrfs_drop_extent_map_range(BTRFS_I(inode),
key.offset, end, true);
unlock_extent(&BTRFS_I(inode)->io_tree,
- key.offset, end, NULL);
+ key.offset, end, &cached_state);
}
}
@@ -1170,7 +1182,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
if (dirty)
btrfs_mark_buffer_dirty(leaf);
if (inode)
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
return ret;
}
@@ -1516,6 +1528,8 @@ static int invalidate_extent_cache(struct btrfs_root *root,
objectid = min_key->objectid;
while (1) {
+ struct extent_state *cached_state = NULL;
+
cond_resched();
iput(inode);
@@ -1566,9 +1580,9 @@ static int invalidate_extent_cache(struct btrfs_root *root,
}
/* the lock_extent waits for read_folio to complete */
- lock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
+ lock_extent(&BTRFS_I(inode)->io_tree, start, end, &cached_state);
btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, true);
- unlock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
+ unlock_extent(&BTRFS_I(inode)->io_tree, start, end, &cached_state);
}
return 0;
}
@@ -2597,10 +2611,14 @@ static int tree_block_processed(u64 bytenr, struct reloc_control *rc)
static int get_tree_block_key(struct btrfs_fs_info *fs_info,
struct tree_block *block)
{
+ struct btrfs_tree_parent_check check = {
+ .level = block->level,
+ .owner_root = block->owner,
+ .transid = block->key.offset
+ };
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, block->bytenr, block->owner,
- block->key.offset, block->level, NULL);
+ eb = read_tree_block(fs_info, block->bytenr, &check);
if (IS_ERR(eb))
return PTR_ERR(eb);
if (!extent_buffer_uptodate(eb)) {
@@ -2861,25 +2879,27 @@ static noinline_for_stack int prealloc_file_extent_cluster(
if (ret)
return ret;
- btrfs_inode_lock(&inode->vfs_inode, 0);
+ btrfs_inode_lock(inode, 0);
for (nr = 0; nr < cluster->nr; nr++) {
+ struct extent_state *cached_state = NULL;
+
start = cluster->boundary[nr] - offset;
if (nr + 1 < cluster->nr)
end = cluster->boundary[nr + 1] - 1 - offset;
else
end = cluster->end - offset;
- lock_extent(&inode->io_tree, start, end, NULL);
+ lock_extent(&inode->io_tree, start, end, &cached_state);
num_bytes = end + 1 - start;
ret = btrfs_prealloc_file_range(&inode->vfs_inode, 0, start,
num_bytes, num_bytes,
end + 1, &alloc_hint);
cur_offset = end + 1;
- unlock_extent(&inode->io_tree, start, end, NULL);
+ unlock_extent(&inode->io_tree, start, end, &cached_state);
if (ret)
break;
}
- btrfs_inode_unlock(&inode->vfs_inode, 0);
+ btrfs_inode_unlock(inode, 0);
if (cur_offset < prealloc_end)
btrfs_free_reserved_data_space_noquota(inode->root->fs_info,
@@ -2891,6 +2911,7 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inod
u64 start, u64 end, u64 block_start)
{
struct extent_map *em;
+ struct extent_state *cached_state = NULL;
int ret = 0;
em = alloc_extent_map();
@@ -2903,9 +2924,9 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inod
em->block_start = block_start;
set_bit(EXTENT_FLAG_PINNED, &em->flags);
- lock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
+ lock_extent(&BTRFS_I(inode)->io_tree, start, end, &cached_state);
ret = btrfs_replace_extent_map_range(BTRFS_I(inode), em, false);
- unlock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
+ unlock_extent(&BTRFS_I(inode)->io_tree, start, end, &cached_state);
free_extent_map(em);
return ret;
@@ -2983,6 +3004,7 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra,
*/
cur = max(page_start, cluster->boundary[*cluster_nr] - offset);
while (cur <= page_end) {
+ struct extent_state *cached_state = NULL;
u64 extent_start = cluster->boundary[*cluster_nr] - offset;
u64 extent_end = get_cluster_boundary_end(cluster,
*cluster_nr) - offset;
@@ -2998,13 +3020,15 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra,
goto release_page;
/* Mark the range delalloc and dirty for later writeback */
- lock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end, NULL);
+ lock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end,
+ &cached_state);
ret = btrfs_set_extent_delalloc(BTRFS_I(inode), clamped_start,
- clamped_end, 0, NULL);
+ clamped_end, 0, &cached_state);
if (ret) {
- clear_extent_bits(&BTRFS_I(inode)->io_tree,
- clamped_start, clamped_end,
- EXTENT_LOCKED | EXTENT_BOUNDARY);
+ clear_extent_bit(&BTRFS_I(inode)->io_tree,
+ clamped_start, clamped_end,
+ EXTENT_LOCKED | EXTENT_BOUNDARY,
+ &cached_state);
btrfs_delalloc_release_metadata(BTRFS_I(inode),
clamped_len, true);
btrfs_delalloc_release_extents(BTRFS_I(inode),
@@ -3031,7 +3055,8 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra,
boundary_start, boundary_end,
EXTENT_BOUNDARY);
}
- unlock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end, NULL);
+ unlock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end,
+ &cached_state);
btrfs_delalloc_release_extents(BTRFS_I(inode), clamped_len);
cur += clamped_len;
@@ -3388,24 +3413,28 @@ int add_data_references(struct reloc_control *rc,
struct btrfs_path *path,
struct rb_root *blocks)
{
- struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
- struct ulist *leaves = NULL;
+ struct btrfs_backref_walk_ctx ctx = { 0 };
struct ulist_iterator leaf_uiter;
struct ulist_node *ref_node = NULL;
- const u32 blocksize = fs_info->nodesize;
+ const u32 blocksize = rc->extent_root->fs_info->nodesize;
int ret = 0;
btrfs_release_path(path);
- ret = btrfs_find_all_leafs(NULL, fs_info, extent_key->objectid,
- 0, &leaves, NULL, true);
+
+ ctx.bytenr = extent_key->objectid;
+ ctx.ignore_extent_item_pos = true;
+ ctx.fs_info = rc->extent_root->fs_info;
+
+ ret = btrfs_find_all_leafs(&ctx);
if (ret < 0)
return ret;
ULIST_ITER_INIT(&leaf_uiter);
- while ((ref_node = ulist_next(leaves, &leaf_uiter))) {
+ while ((ref_node = ulist_next(ctx.refs, &leaf_uiter))) {
+ struct btrfs_tree_parent_check check = { 0 };
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, ref_node->val, 0, 0, 0, NULL);
+ eb = read_tree_block(ctx.fs_info, ref_node->val, &check);
if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
break;
@@ -3421,7 +3450,7 @@ int add_data_references(struct reloc_control *rc,
}
if (ret < 0)
free_block_list(blocks);
- ulist_free(leaves);
+ ulist_free(ctx.refs);
return ret;
}
@@ -3905,8 +3934,7 @@ static struct reloc_control *alloc_reloc_control(struct btrfs_fs_info *fs_info)
INIT_LIST_HEAD(&rc->dirty_subvol_roots);
btrfs_backref_init_cache(fs_info, &rc->backref_cache, 1);
mapping_tree_init(&rc->reloc_root_tree);
- extent_io_tree_init(fs_info, &rc->processed_blocks,
- IO_TREE_RELOC_BLOCKS, NULL);
+ extent_io_tree_init(fs_info, &rc->processed_blocks, IO_TREE_RELOC_BLOCKS);
return rc;
}
@@ -4330,8 +4358,8 @@ int btrfs_reloc_clone_csums(struct btrfs_inode *inode, u64 file_pos, u64 len)
disk_bytenr = file_pos + inode->index_cnt;
csum_root = btrfs_csum_root(fs_info, disk_bytenr);
- ret = btrfs_lookup_csums_range(csum_root, disk_bytenr,
- disk_bytenr + len - 1, &list, 0, false);
+ ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
+ disk_bytenr + len - 1, &list, 0, false);
if (ret)
goto out;
diff --git a/fs/btrfs/relocation.h b/fs/btrfs/relocation.h
new file mode 100644
index 000000000000..2041a86186de
--- /dev/null
+++ b/fs/btrfs/relocation.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_RELOCATION_H
+#define BTRFS_RELOCATION_H
+
+int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start);
+int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, struct btrfs_root *root);
+int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+int btrfs_recover_relocation(struct btrfs_fs_info *fs_info);
+int btrfs_reloc_clone_csums(struct btrfs_inode *inode, u64 file_pos, u64 len);
+int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct extent_buffer *buf,
+ struct extent_buffer *cow);
+void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending,
+ u64 *bytes_to_reserve);
+int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
+ struct btrfs_pending_snapshot *pending);
+int btrfs_should_cancel_balance(struct btrfs_fs_info *fs_info);
+struct btrfs_root *find_reloc_root(struct btrfs_fs_info *fs_info, u64 bytenr);
+int btrfs_should_ignore_reloc_root(struct btrfs_root *root);
+
+#endif
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index e1f599d7a916..859874579456 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -6,11 +6,16 @@
#include <linux/err.h>
#include <linux/uuid.h>
#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
#include "transaction.h"
#include "disk-io.h"
#include "print-tree.h"
#include "qgroup.h"
#include "space-info.h"
+#include "accessors.h"
+#include "root-tree.h"
+#include "orphan.h"
/*
* Read a root item from the tree. In case we detect a root item smaller then
@@ -327,9 +332,8 @@ out:
}
int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
- u64 ref_id, u64 dirid, u64 *sequence, const char *name,
- int name_len)
-
+ u64 ref_id, u64 dirid, u64 *sequence,
+ const struct fscrypt_str *name)
{
struct btrfs_root *tree_root = trans->fs_info->tree_root;
struct btrfs_path *path;
@@ -356,8 +360,8 @@ again:
struct btrfs_root_ref);
ptr = (unsigned long)(ref + 1);
if ((btrfs_root_ref_dirid(leaf, ref) != dirid) ||
- (btrfs_root_ref_name_len(leaf, ref) != name_len) ||
- memcmp_extent_buffer(leaf, name, ptr, name_len)) {
+ (btrfs_root_ref_name_len(leaf, ref) != name->len) ||
+ memcmp_extent_buffer(leaf, name->name, ptr, name->len)) {
ret = -ENOENT;
goto out;
}
@@ -400,8 +404,8 @@ out:
* Will return 0, -ENOMEM, or anything from the CoW path
*/
int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
- u64 ref_id, u64 dirid, u64 sequence, const char *name,
- int name_len)
+ u64 ref_id, u64 dirid, u64 sequence,
+ const struct fscrypt_str *name)
{
struct btrfs_root *tree_root = trans->fs_info->tree_root;
struct btrfs_key key;
@@ -420,7 +424,7 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
key.offset = ref_id;
again:
ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
- sizeof(*ref) + name_len);
+ sizeof(*ref) + name->len);
if (ret) {
btrfs_abort_transaction(trans, ret);
btrfs_free_path(path);
@@ -431,9 +435,9 @@ again:
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
btrfs_set_root_ref_dirid(leaf, ref, dirid);
btrfs_set_root_ref_sequence(leaf, ref, sequence);
- btrfs_set_root_ref_name_len(leaf, ref, name_len);
+ btrfs_set_root_ref_name_len(leaf, ref, name->len);
ptr = (unsigned long)(ref + 1);
- write_extent_buffer(leaf, name, ptr, name_len);
+ write_extent_buffer(leaf, name->name, ptr, name->len);
btrfs_mark_buffer_dirty(leaf);
if (key.type == BTRFS_ROOT_BACKREF_KEY) {
diff --git a/fs/btrfs/root-tree.h b/fs/btrfs/root-tree.h
new file mode 100644
index 000000000000..cbbaca32126e
--- /dev/null
+++ b/fs/btrfs/root-tree.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_ROOT_TREE_H
+#define BTRFS_ROOT_TREE_H
+
+int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
+ struct btrfs_block_rsv *rsv,
+ int nitems, bool use_global_rsv);
+void btrfs_subvolume_release_metadata(struct btrfs_root *root,
+ struct btrfs_block_rsv *rsv);
+int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
+ u64 ref_id, u64 dirid, u64 sequence,
+ const struct fscrypt_str *name);
+int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
+ u64 ref_id, u64 dirid, u64 *sequence,
+ const struct fscrypt_str *name);
+int btrfs_del_root(struct btrfs_trans_handle *trans, const struct btrfs_key *key);
+int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ const struct btrfs_key *key,
+ struct btrfs_root_item *item);
+int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_key *key,
+ struct btrfs_root_item *item);
+int btrfs_find_root(struct btrfs_root *root, const struct btrfs_key *search_key,
+ struct btrfs_path *path, struct btrfs_root_item *root_item,
+ struct btrfs_key *root_key);
+int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info);
+void btrfs_set_root_node(struct btrfs_root_item *item,
+ struct extent_buffer *node);
+void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
+void btrfs_update_root_times(struct btrfs_trans_handle *trans, struct btrfs_root *root);
+
+#endif
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index f260c53829e5..52b346795f66 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -17,10 +17,13 @@
#include "extent_io.h"
#include "dev-replace.h"
#include "check-integrity.h"
-#include "rcu-string.h"
#include "raid56.h"
#include "block-group.h"
#include "zoned.h"
+#include "fs.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "scrub.h"
/*
* This is only the first step towards a full-features scrub. It reads all
@@ -56,6 +59,17 @@ struct scrub_ctx;
#define SCRUB_MAX_PAGES (DIV_ROUND_UP(BTRFS_MAX_METADATA_BLOCKSIZE, PAGE_SIZE))
+/*
+ * Maximum number of mirrors that can be available for all profiles counting
+ * the target device of dev-replace as one. During an active device replace
+ * procedure, the target device of the copy operation is a mirror for the
+ * filesystem data as well that can be used to read data in order to repair
+ * read errors on other disks.
+ *
+ * Current value is derived from RAID1C4 with 4 copies.
+ */
+#define BTRFS_MAX_MIRRORS (4 + 1)
+
struct scrub_recover {
refcount_t refs;
struct btrfs_io_context *bioc;
@@ -284,7 +298,7 @@ static struct scrub_block *alloc_scrub_block(struct scrub_ctx *sctx,
* Will also allocate new pages for @sblock if needed.
*/
static struct scrub_sector *alloc_scrub_sector(struct scrub_block *sblock,
- u64 logical, gfp_t gfp)
+ u64 logical)
{
const pgoff_t page_index = (logical - sblock->logical) >> PAGE_SHIFT;
struct scrub_sector *ssector;
@@ -292,7 +306,7 @@ static struct scrub_sector *alloc_scrub_sector(struct scrub_block *sblock,
/* We must never have scrub_block exceed U32_MAX in size. */
ASSERT(logical - sblock->logical < U32_MAX);
- ssector = kzalloc(sizeof(*ssector), gfp);
+ ssector = kzalloc(sizeof(*ssector), GFP_KERNEL);
if (!ssector)
return NULL;
@@ -300,7 +314,7 @@ static struct scrub_sector *alloc_scrub_sector(struct scrub_block *sblock,
if (!sblock->pages[page_index]) {
int ret;
- sblock->pages[page_index] = alloc_page(gfp);
+ sblock->pages[page_index] = alloc_page(GFP_KERNEL);
if (!sblock->pages[page_index]) {
kfree(ssector);
return NULL;
@@ -794,8 +808,8 @@ nomem:
return ERR_PTR(-ENOMEM);
}
-static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
- void *warn_ctx)
+static int scrub_print_warning_inode(u64 inum, u64 offset, u64 num_bytes,
+ u64 root, void *warn_ctx)
{
u32 nlink;
int ret;
@@ -862,7 +876,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
btrfs_warn_in_rcu(fs_info,
"%s at logical %llu on dev %s, physical %llu, root %llu, inode %llu, offset %llu, length %u, links %u (path: %s)",
swarn->errstr, swarn->logical,
- rcu_str_deref(swarn->dev->name),
+ btrfs_dev_name(swarn->dev),
swarn->physical,
root, inum, offset,
fs_info->sectorsize, nlink,
@@ -876,7 +890,7 @@ err:
btrfs_warn_in_rcu(fs_info,
"%s at logical %llu on dev %s, physical %llu, root %llu, inode %llu, offset %llu: path resolving failed with ret=%d",
swarn->errstr, swarn->logical,
- rcu_str_deref(swarn->dev->name),
+ btrfs_dev_name(swarn->dev),
swarn->physical,
root, inum, offset, ret);
@@ -894,7 +908,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
struct btrfs_extent_item *ei;
struct scrub_warning swarn;
unsigned long ptr = 0;
- u64 extent_item_pos;
u64 flags = 0;
u64 ref_root;
u32 item_size;
@@ -908,8 +921,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
/* Super block error, no need to search extent tree. */
if (sblock->sectors[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
btrfs_warn_in_rcu(fs_info, "%s on device %s, physical %llu",
- errstr, rcu_str_deref(dev->name),
- sblock->physical);
+ errstr, btrfs_dev_name(dev), sblock->physical);
return;
}
path = btrfs_alloc_path();
@@ -926,7 +938,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
if (ret < 0)
goto out;
- extent_item_pos = swarn.logical - found_key.objectid;
swarn.extent_item_size = found_key.offset;
eb = path->nodes[0];
@@ -941,7 +952,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
btrfs_warn_in_rcu(fs_info,
"%s at logical %llu on dev %s, physical %llu: metadata %s (level %d) in tree %llu",
errstr, swarn.logical,
- rcu_str_deref(dev->name),
+ btrfs_dev_name(dev),
swarn.physical,
ref_level ? "node" : "leaf",
ret < 0 ? -1 : ref_level,
@@ -949,12 +960,18 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
} while (ret != 1);
btrfs_release_path(path);
} else {
+ struct btrfs_backref_walk_ctx ctx = { 0 };
+
btrfs_release_path(path);
+
+ ctx.bytenr = found_key.objectid;
+ ctx.extent_item_pos = swarn.logical - found_key.objectid;
+ ctx.fs_info = fs_info;
+
swarn.path = path;
swarn.dev = dev;
- iterate_extent_inodes(fs_info, found_key.objectid,
- extent_item_pos, 1,
- scrub_print_warning_inode, &swarn, false);
+
+ iterate_extent_inodes(&ctx, true, scrub_print_warning_inode, &swarn);
}
out:
@@ -1358,7 +1375,7 @@ corrected_error:
spin_unlock(&sctx->stat_lock);
btrfs_err_rl_in_rcu(fs_info,
"fixed up error at logical %llu on dev %s",
- logical, rcu_str_deref(dev->name));
+ logical, btrfs_dev_name(dev));
}
} else {
did_not_correct_error:
@@ -1367,7 +1384,7 @@ did_not_correct_error:
spin_unlock(&sctx->stat_lock);
btrfs_err_rl_in_rcu(fs_info,
"unable to fixup (regular) error at logical %llu on dev %s",
- logical, rcu_str_deref(dev->name));
+ logical, btrfs_dev_name(dev));
}
out:
@@ -1480,7 +1497,7 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
return -EIO;
}
- recover = kzalloc(sizeof(struct scrub_recover), GFP_NOFS);
+ recover = kzalloc(sizeof(struct scrub_recover), GFP_KERNEL);
if (!recover) {
btrfs_put_bioc(bioc);
btrfs_bio_counter_dec(fs_info);
@@ -1503,7 +1520,7 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
sblock = sblocks_for_recheck[mirror_index];
sblock->sctx = sctx;
- sector = alloc_scrub_sector(sblock, logical, GFP_NOFS);
+ sector = alloc_scrub_sector(sblock, logical);
if (!sector) {
spin_lock(&sctx->stat_lock);
sctx->stat.malloc_errors++;
@@ -2313,14 +2330,14 @@ static void scrub_missing_raid56_worker(struct work_struct *work)
spin_unlock(&sctx->stat_lock);
btrfs_err_rl_in_rcu(fs_info,
"IO error rebuilding logical %llu for dev %s",
- logical, rcu_str_deref(dev->name));
+ logical, btrfs_dev_name(dev));
} 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,
"failed to rebuild valid logical %llu for dev %s",
- logical, rcu_str_deref(dev->name));
+ logical, btrfs_dev_name(dev));
} else {
scrub_write_block_to_dev_replace(sblock);
}
@@ -2425,7 +2442,7 @@ static int scrub_sectors(struct scrub_ctx *sctx, u64 logical, u32 len,
*/
u32 l = min(sectorsize, len);
- sector = alloc_scrub_sector(sblock, logical, GFP_KERNEL);
+ sector = alloc_scrub_sector(sblock, logical);
if (!sector) {
spin_lock(&sctx->stat_lock);
sctx->stat.malloc_errors++;
@@ -2672,17 +2689,11 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
u8 csum[BTRFS_CSUM_SIZE];
u32 blocksize;
- /*
- * Block size determines how many scrub_block will be allocated. Here
- * we use BTRFS_STRIPE_LEN (64KiB) as default limit, so we won't
- * allocate too many scrub_block, while still won't cause too large
- * bios for large extents.
- */
if (flags & BTRFS_EXTENT_FLAG_DATA) {
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
blocksize = map->stripe_len;
else
- blocksize = BTRFS_STRIPE_LEN;
+ blocksize = sctx->fs_info->sectorsize;
spin_lock(&sctx->stat_lock);
sctx->stat.data_extents_scrubbed++;
sctx->stat.data_bytes_scrubbed += len;
@@ -2762,7 +2773,7 @@ static int scrub_sectors_for_parity(struct scrub_parity *sparity,
for (index = 0; len > 0; index++) {
struct scrub_sector *sector;
- sector = alloc_scrub_sector(sblock, logical, GFP_KERNEL);
+ sector = alloc_scrub_sector(sblock, logical);
if (!sector) {
spin_lock(&sctx->stat_lock);
sctx->stat.malloc_errors++;
@@ -3227,9 +3238,9 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
extent_dev = bioc->stripes[0].dev;
btrfs_put_bioc(bioc);
- ret = btrfs_lookup_csums_range(csum_root, extent_start,
- extent_start + extent_size - 1,
- &sctx->csum_list, 1, false);
+ ret = btrfs_lookup_csums_list(csum_root, extent_start,
+ extent_start + extent_size - 1,
+ &sctx->csum_list, 1, false);
if (ret) {
scrub_parity_mark_sectors_error(sparity, extent_start,
extent_size);
@@ -3453,7 +3464,7 @@ static int scrub_simple_mirror(struct scrub_ctx *sctx,
cur_logical;
if (extent_flags & BTRFS_EXTENT_FLAG_DATA) {
- ret = btrfs_lookup_csums_range(csum_root, cur_logical,
+ ret = btrfs_lookup_csums_list(csum_root, cur_logical,
cur_logical + scrub_len - 1,
&sctx->csum_list, 1, false);
if (ret)
@@ -3917,7 +3928,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
if (sctx->is_dev_replace && btrfs_is_zoned(fs_info)) {
if (!test_bit(BLOCK_GROUP_FLAG_TO_COPY, &cache->runtime_flags)) {
- spin_unlock(&cache->lock);
btrfs_put_block_group(cache);
goto skip;
}
@@ -4291,7 +4301,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
btrfs_err_in_rcu(fs_info,
"scrub on devid %llu: filesystem on %s is not writable",
- devid, rcu_str_deref(dev->name));
+ devid, btrfs_dev_name(dev));
ret = -EROFS;
goto out;
}
diff --git a/fs/btrfs/scrub.h b/fs/btrfs/scrub.h
new file mode 100644
index 000000000000..7639103ebf9d
--- /dev/null
+++ b/fs/btrfs/scrub.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_SCRUB_H
+#define BTRFS_SCRUB_H
+
+int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+ u64 end, struct btrfs_scrub_progress *progress,
+ int readonly, int is_dev_replace);
+void btrfs_scrub_pause(struct btrfs_fs_info *fs_info);
+void btrfs_scrub_continue(struct btrfs_fs_info *fs_info);
+int btrfs_scrub_cancel(struct btrfs_fs_info *info);
+int btrfs_scrub_cancel_dev(struct btrfs_device *dev);
+int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid,
+ struct btrfs_scrub_progress *progress);
+
+#endif
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 145c84b44fd0..67f7c698ade3 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -27,6 +27,11 @@
#include "compression.h"
#include "xattr.h"
#include "print-tree.h"
+#include "accessors.h"
+#include "dir-item.h"
+#include "file-item.h"
+#include "ioctl.h"
+#include "verity.h"
/*
* Maximum number of references an extent can have in order for us to attempt to
@@ -34,7 +39,7 @@
* avoid hitting limitations of the backreference walking code (taking a lot of
* time and using too much memory for extents with large number of references).
*/
-#define SEND_MAX_EXTENT_REFS 64
+#define SEND_MAX_EXTENT_REFS 1024
/*
* A fs_path is a helper to dynamically build path names with unknown size.
@@ -71,13 +76,46 @@ struct clone_root {
struct btrfs_root *root;
u64 ino;
u64 offset;
-
- u64 found_refs;
+ u64 num_bytes;
+ bool found_ref;
};
#define SEND_CTX_MAX_NAME_CACHE_SIZE 128
#define SEND_CTX_NAME_CACHE_CLEAN_SIZE (SEND_CTX_MAX_NAME_CACHE_SIZE * 2)
+/*
+ * Limit the root_ids array of struct backref_cache_entry to 12 elements.
+ * This makes the size of a cache entry to be exactly 128 bytes on x86_64.
+ * The most common case is to have a single root for cloning, which corresponds
+ * to the send root. Having the user specify more than 11 clone roots is not
+ * common, and in such rare cases we simply don't use caching if the number of
+ * cloning roots that lead down to a leaf is more than 12.
+ */
+#define SEND_MAX_BACKREF_CACHE_ROOTS 12
+
+/*
+ * Max number of entries in the cache.
+ * With SEND_MAX_BACKREF_CACHE_ROOTS as 12, the size in bytes, excluding
+ * maple tree's internal nodes, is 16K.
+ */
+#define SEND_MAX_BACKREF_CACHE_SIZE 128
+
+/*
+ * A backref cache entry maps a leaf to a list of IDs of roots from which the
+ * leaf is accessible and we can use for clone operations.
+ * With SEND_MAX_BACKREF_CACHE_ROOTS as 12, each cache entry is 128 bytes (on
+ * x86_64).
+ */
+struct backref_cache_entry {
+ /* List to link to the cache's lru list. */
+ struct list_head list;
+ /* The key for this entry in the cache. */
+ u64 key;
+ u64 root_ids[SEND_MAX_BACKREF_CACHE_ROOTS];
+ /* Number of valid elements in the root_ids array. */
+ int num_roots;
+};
+
struct send_ctx {
struct file *send_filp;
loff_t send_off;
@@ -246,6 +284,14 @@ struct send_ctx {
struct rb_root rbtree_new_refs;
struct rb_root rbtree_deleted_refs;
+
+ struct {
+ u64 last_reloc_trans;
+ struct list_head lru_list;
+ struct maple_tree entries;
+ /* Number of entries stored in the cache. */
+ int size;
+ } backref_cache;
};
struct pending_dir_move {
@@ -1093,7 +1139,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
data_len = btrfs_dir_data_len(eb, di);
btrfs_dir_item_key_to_cpu(eb, di, &di_key);
- if (btrfs_dir_type(eb, di) == BTRFS_FT_XATTR) {
+ if (btrfs_dir_ftype(eb, di) == BTRFS_FT_XATTR) {
if (name_len > XATTR_NAME_MAX) {
ret = -ENAMETOOLONG;
goto out;
@@ -1236,8 +1282,12 @@ struct backref_ctx {
/* may be truncated in case it's the last extent in a file */
u64 extent_len;
- /* Just to check for bugs in backref resolving */
- int found_itself;
+ /* The bytenr the file extent item we are processing refers to. */
+ u64 bytenr;
+ /* The owner (root id) of the data backref for the current extent. */
+ u64 backref_owner;
+ /* The offset of the data backref for the current extent. */
+ u64 backref_offset;
};
static int __clone_root_cmp_bsearch(const void *key, const void *elt)
@@ -1266,32 +1316,33 @@ static int __clone_root_cmp_sort(const void *e1, const void *e2)
/*
* Called for every backref that is found for the current extent.
- * Results are collected in sctx->clone_roots->ino/offset/found_refs
+ * Results are collected in sctx->clone_roots->ino/offset.
*/
-static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
+static int iterate_backrefs(u64 ino, u64 offset, u64 num_bytes, u64 root_id,
+ void *ctx_)
{
struct backref_ctx *bctx = ctx_;
- struct clone_root *found;
+ struct clone_root *clone_root;
/* First check if the root is in the list of accepted clone sources */
- found = bsearch((void *)(uintptr_t)root, bctx->sctx->clone_roots,
- bctx->sctx->clone_roots_cnt,
- sizeof(struct clone_root),
- __clone_root_cmp_bsearch);
- if (!found)
+ clone_root = bsearch((void *)(uintptr_t)root_id, bctx->sctx->clone_roots,
+ bctx->sctx->clone_roots_cnt,
+ sizeof(struct clone_root),
+ __clone_root_cmp_bsearch);
+ if (!clone_root)
return 0;
- if (found->root == bctx->sctx->send_root &&
+ /* This is our own reference, bail out as we can't clone from it. */
+ if (clone_root->root == bctx->sctx->send_root &&
ino == bctx->cur_objectid &&
- offset == bctx->cur_offset) {
- bctx->found_itself = 1;
- }
+ offset == bctx->cur_offset)
+ return 0;
/*
* Make sure we don't consider clones from send_root that are
* behind the current inode/offset.
*/
- if (found->root == bctx->sctx->send_root) {
+ if (clone_root->root == bctx->sctx->send_root) {
/*
* If the source inode was not yet processed we can't issue a
* clone operation, as the source extent does not exist yet at
@@ -1312,21 +1363,217 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
}
bctx->found++;
- found->found_refs++;
- if (ino < found->ino) {
- found->ino = ino;
- found->offset = offset;
- } else if (found->ino == ino) {
+ clone_root->found_ref = true;
+
+ /*
+ * If the given backref refers to a file extent item with a larger
+ * number of bytes than what we found before, use the new one so that
+ * we clone more optimally and end up doing less writes and getting
+ * less exclusive, non-shared extents at the destination.
+ */
+ if (num_bytes > clone_root->num_bytes) {
+ clone_root->ino = ino;
+ clone_root->offset = offset;
+ clone_root->num_bytes = num_bytes;
+
/*
- * same extent found more then once in the same file.
+ * Found a perfect candidate, so there's no need to continue
+ * backref walking.
*/
- if (found->offset > offset + bctx->extent_len)
- found->offset = offset;
+ if (num_bytes >= bctx->extent_len)
+ return BTRFS_ITERATE_EXTENT_INODES_STOP;
}
return 0;
}
+static void empty_backref_cache(struct send_ctx *sctx)
+{
+ struct backref_cache_entry *entry;
+ struct backref_cache_entry *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &sctx->backref_cache.lru_list, list)
+ kfree(entry);
+
+ INIT_LIST_HEAD(&sctx->backref_cache.lru_list);
+ mtree_destroy(&sctx->backref_cache.entries);
+ sctx->backref_cache.size = 0;
+}
+
+static bool lookup_backref_cache(u64 leaf_bytenr, void *ctx,
+ const u64 **root_ids_ret, int *root_count_ret)
+{
+ struct backref_ctx *bctx = ctx;
+ struct send_ctx *sctx = bctx->sctx;
+ struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
+ const u64 key = leaf_bytenr >> fs_info->sectorsize_bits;
+ struct backref_cache_entry *entry;
+
+ if (sctx->backref_cache.size == 0)
+ return false;
+
+ /*
+ * If relocation happened since we first filled the cache, then we must
+ * empty the cache and can not use it, because even though we operate on
+ * read-only roots, their leaves and nodes may have been reallocated and
+ * now be used for different nodes/leaves of the same tree or some other
+ * tree.
+ *
+ * We are called from iterate_extent_inodes() while either holding a
+ * transaction handle or holding fs_info->commit_root_sem, so no need
+ * to take any lock here.
+ */
+ if (fs_info->last_reloc_trans > sctx->backref_cache.last_reloc_trans) {
+ empty_backref_cache(sctx);
+ return false;
+ }
+
+ entry = mtree_load(&sctx->backref_cache.entries, key);
+ if (!entry)
+ return false;
+
+ *root_ids_ret = entry->root_ids;
+ *root_count_ret = entry->num_roots;
+ list_move_tail(&entry->list, &sctx->backref_cache.lru_list);
+
+ return true;
+}
+
+static void store_backref_cache(u64 leaf_bytenr, const struct ulist *root_ids,
+ void *ctx)
+{
+ struct backref_ctx *bctx = ctx;
+ struct send_ctx *sctx = bctx->sctx;
+ struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
+ struct backref_cache_entry *new_entry;
+ struct ulist_iterator uiter;
+ struct ulist_node *node;
+ int ret;
+
+ /*
+ * We're called while holding a transaction handle or while holding
+ * fs_info->commit_root_sem (at iterate_extent_inodes()), so must do a
+ * NOFS allocation.
+ */
+ new_entry = kmalloc(sizeof(struct backref_cache_entry), GFP_NOFS);
+ /* No worries, cache is optional. */
+ if (!new_entry)
+ return;
+
+ new_entry->key = leaf_bytenr >> fs_info->sectorsize_bits;
+ new_entry->num_roots = 0;
+ ULIST_ITER_INIT(&uiter);
+ while ((node = ulist_next(root_ids, &uiter)) != NULL) {
+ const u64 root_id = node->val;
+ struct clone_root *root;
+
+ root = bsearch((void *)(uintptr_t)root_id, sctx->clone_roots,
+ sctx->clone_roots_cnt, sizeof(struct clone_root),
+ __clone_root_cmp_bsearch);
+ if (!root)
+ continue;
+
+ /* Too many roots, just exit, no worries as caching is optional. */
+ if (new_entry->num_roots >= SEND_MAX_BACKREF_CACHE_ROOTS) {
+ kfree(new_entry);
+ return;
+ }
+
+ new_entry->root_ids[new_entry->num_roots] = root_id;
+ new_entry->num_roots++;
+ }
+
+ /*
+ * We may have not added any roots to the new cache entry, which means
+ * none of the roots is part of the list of roots from which we are
+ * allowed to clone. Cache the new entry as it's still useful to avoid
+ * backref walking to determine which roots have a path to the leaf.
+ */
+
+ if (sctx->backref_cache.size >= SEND_MAX_BACKREF_CACHE_SIZE) {
+ struct backref_cache_entry *lru_entry;
+ struct backref_cache_entry *mt_entry;
+
+ lru_entry = list_first_entry(&sctx->backref_cache.lru_list,
+ struct backref_cache_entry, list);
+ mt_entry = mtree_erase(&sctx->backref_cache.entries, lru_entry->key);
+ ASSERT(mt_entry == lru_entry);
+ list_del(&mt_entry->list);
+ kfree(mt_entry);
+ sctx->backref_cache.size--;
+ }
+
+ ret = mtree_insert(&sctx->backref_cache.entries, new_entry->key,
+ new_entry, GFP_NOFS);
+ ASSERT(ret == 0 || ret == -ENOMEM);
+ if (ret) {
+ /* Caching is optional, no worries. */
+ kfree(new_entry);
+ return;
+ }
+
+ list_add_tail(&new_entry->list, &sctx->backref_cache.lru_list);
+
+ /*
+ * We are called from iterate_extent_inodes() while either holding a
+ * transaction handle or holding fs_info->commit_root_sem, so no need
+ * to take any lock here.
+ */
+ if (sctx->backref_cache.size == 0)
+ sctx->backref_cache.last_reloc_trans = fs_info->last_reloc_trans;
+
+ sctx->backref_cache.size++;
+}
+
+static int check_extent_item(u64 bytenr, const struct btrfs_extent_item *ei,
+ const struct extent_buffer *leaf, void *ctx)
+{
+ const u64 refs = btrfs_extent_refs(leaf, ei);
+ const struct backref_ctx *bctx = ctx;
+ const struct send_ctx *sctx = bctx->sctx;
+
+ if (bytenr == bctx->bytenr) {
+ const u64 flags = btrfs_extent_flags(leaf, ei);
+
+ if (WARN_ON(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK))
+ return -EUCLEAN;
+
+ /*
+ * If we have only one reference and only the send root as a
+ * clone source - meaning no clone roots were given in the
+ * struct btrfs_ioctl_send_args passed to the send ioctl - then
+ * it's our reference and there's no point in doing backref
+ * walking which is expensive, so exit early.
+ */
+ if (refs == 1 && sctx->clone_roots_cnt == 1)
+ return -ENOENT;
+ }
+
+ /*
+ * Backreference walking (iterate_extent_inodes() below) is currently
+ * too expensive when an extent has a large number of references, both
+ * in time spent and used memory. So for now just fallback to write
+ * operations instead of clone operations when an extent has more than
+ * a certain amount of references.
+ */
+ if (refs > SEND_MAX_EXTENT_REFS)
+ return -ENOENT;
+
+ return 0;
+}
+
+static bool skip_self_data_ref(u64 root, u64 ino, u64 offset, void *ctx)
+{
+ const struct backref_ctx *bctx = ctx;
+
+ if (ino == bctx->cur_objectid &&
+ root == bctx->backref_owner &&
+ offset == bctx->backref_offset)
+ return true;
+
+ return false;
+}
+
/*
* Given an inode, offset and extent item, it finds a good clone for a clone
* instruction. Returns -ENOENT when none could be found. The function makes
@@ -1348,79 +1595,36 @@ static int find_extent_clone(struct send_ctx *sctx,
u64 logical;
u64 disk_byte;
u64 num_bytes;
- u64 extent_item_pos;
- u64 flags = 0;
struct btrfs_file_extent_item *fi;
struct extent_buffer *eb = path->nodes[0];
- struct backref_ctx backref_ctx = {0};
+ struct backref_ctx backref_ctx = { 0 };
+ struct btrfs_backref_walk_ctx backref_walk_ctx = { 0 };
struct clone_root *cur_clone_root;
- struct btrfs_key found_key;
- struct btrfs_path *tmp_path;
- struct btrfs_extent_item *ei;
int compressed;
u32 i;
- tmp_path = alloc_path_for_send();
- if (!tmp_path)
- return -ENOMEM;
+ /*
+ * With fallocate we can get prealloc extents beyond the inode's i_size,
+ * so we don't do anything here because clone operations can not clone
+ * to a range beyond i_size without increasing the i_size of the
+ * destination inode.
+ */
+ if (data_offset >= ino_size)
+ return 0;
- /* We only use this path under the commit sem */
- tmp_path->need_commit_sem = 0;
+ fi = btrfs_item_ptr(eb, path->slots[0], struct btrfs_file_extent_item);
+ extent_type = btrfs_file_extent_type(eb, fi);
+ if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+ return -ENOENT;
- if (data_offset >= ino_size) {
- /*
- * There may be extents that lie behind the file's size.
- * I at least had this in combination with snapshotting while
- * writing large files.
- */
- ret = 0;
- goto out;
- }
+ disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
+ if (disk_byte == 0)
+ return -ENOENT;
- fi = btrfs_item_ptr(eb, path->slots[0],
- struct btrfs_file_extent_item);
- extent_type = btrfs_file_extent_type(eb, fi);
- if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
- ret = -ENOENT;
- goto out;
- }
compressed = btrfs_file_extent_compression(eb, fi);
-
num_bytes = btrfs_file_extent_num_bytes(eb, fi);
- disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
- if (disk_byte == 0) {
- ret = -ENOENT;
- goto out;
- }
logical = disk_byte + btrfs_file_extent_offset(eb, fi);
- down_read(&fs_info->commit_root_sem);
- ret = extent_from_logical(fs_info, disk_byte, tmp_path,
- &found_key, &flags);
- up_read(&fs_info->commit_root_sem);
-
- if (ret < 0)
- goto out;
- if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
- ret = -EIO;
- goto out;
- }
-
- ei = btrfs_item_ptr(tmp_path->nodes[0], tmp_path->slots[0],
- struct btrfs_extent_item);
- /*
- * Backreference walking (iterate_extent_inodes() below) is currently
- * too expensive when an extent has a large number of references, both
- * in time spent and used memory. So for now just fallback to write
- * operations instead of clone operations when an extent has more than
- * a certain amount of references.
- */
- if (btrfs_extent_refs(tmp_path->nodes[0], ei) > SEND_MAX_EXTENT_REFS) {
- ret = -ENOENT;
- goto out;
- }
- btrfs_release_path(tmp_path);
-
/*
* Setup the clone roots.
*/
@@ -1428,37 +1632,59 @@ static int find_extent_clone(struct send_ctx *sctx,
cur_clone_root = sctx->clone_roots + i;
cur_clone_root->ino = (u64)-1;
cur_clone_root->offset = 0;
- cur_clone_root->found_refs = 0;
+ cur_clone_root->num_bytes = 0;
+ cur_clone_root->found_ref = false;
}
backref_ctx.sctx = sctx;
- backref_ctx.found = 0;
backref_ctx.cur_objectid = ino;
backref_ctx.cur_offset = data_offset;
- backref_ctx.found_itself = 0;
- backref_ctx.extent_len = num_bytes;
+ backref_ctx.bytenr = disk_byte;
+ /*
+ * Use the header owner and not the send root's id, because in case of a
+ * snapshot we can have shared subtrees.
+ */
+ backref_ctx.backref_owner = btrfs_header_owner(eb);
+ backref_ctx.backref_offset = data_offset - btrfs_file_extent_offset(eb, fi);
/*
* The last extent of a file may be too large due to page alignment.
* We need to adjust extent_len in this case so that the checks in
- * __iterate_backrefs work.
+ * iterate_backrefs() work.
*/
if (data_offset + num_bytes >= ino_size)
backref_ctx.extent_len = ino_size - data_offset;
+ else
+ backref_ctx.extent_len = num_bytes;
/*
* Now collect all backrefs.
*/
+ backref_walk_ctx.bytenr = disk_byte;
if (compressed == BTRFS_COMPRESS_NONE)
- extent_item_pos = logical - found_key.objectid;
- else
- extent_item_pos = 0;
- ret = iterate_extent_inodes(fs_info, found_key.objectid,
- extent_item_pos, 1, __iterate_backrefs,
- &backref_ctx, false);
+ backref_walk_ctx.extent_item_pos = btrfs_file_extent_offset(eb, fi);
+ backref_walk_ctx.fs_info = fs_info;
+ backref_walk_ctx.cache_lookup = lookup_backref_cache;
+ backref_walk_ctx.cache_store = store_backref_cache;
+ backref_walk_ctx.indirect_ref_iterator = iterate_backrefs;
+ backref_walk_ctx.check_extent_item = check_extent_item;
+ backref_walk_ctx.user_ctx = &backref_ctx;
+
+ /*
+ * If have a single clone root, then it's the send root and we can tell
+ * the backref walking code to skip our own backref and not resolve it,
+ * since we can not use it for cloning - the source and destination
+ * ranges can't overlap and in case the leaf is shared through a subtree
+ * due to snapshots, we can't use those other roots since they are not
+ * in the list of clone roots.
+ */
+ if (sctx->clone_roots_cnt == 1)
+ backref_walk_ctx.skip_data_ref = skip_self_data_ref;
+ ret = iterate_extent_inodes(&backref_walk_ctx, true, iterate_backrefs,
+ &backref_ctx);
if (ret < 0)
- goto out;
+ return ret;
down_read(&fs_info->commit_root_sem);
if (fs_info->last_reloc_trans > sctx->last_reloc_trans) {
@@ -1475,37 +1701,42 @@ static int find_extent_clone(struct send_ctx *sctx,
* was already reallocated after the relocation.
*/
up_read(&fs_info->commit_root_sem);
- ret = -ENOENT;
- goto out;
+ return -ENOENT;
}
up_read(&fs_info->commit_root_sem);
- if (!backref_ctx.found_itself) {
- /* found a bug in backref code? */
- ret = -EIO;
- btrfs_err(fs_info,
- "did not find backref in send_root. inode=%llu, offset=%llu, disk_byte=%llu found extent=%llu",
- ino, data_offset, disk_byte, found_key.objectid);
- goto out;
- }
-
btrfs_debug(fs_info,
"find_extent_clone: data_offset=%llu, ino=%llu, num_bytes=%llu, logical=%llu",
data_offset, ino, num_bytes, logical);
- if (!backref_ctx.found)
+ if (!backref_ctx.found) {
btrfs_debug(fs_info, "no clones found");
+ return -ENOENT;
+ }
cur_clone_root = NULL;
for (i = 0; i < sctx->clone_roots_cnt; i++) {
- if (sctx->clone_roots[i].found_refs) {
- if (!cur_clone_root)
- cur_clone_root = sctx->clone_roots + i;
- else if (sctx->clone_roots[i].root == sctx->send_root)
- /* prefer clones from send_root over others */
- cur_clone_root = sctx->clone_roots + i;
- }
+ struct clone_root *clone_root = &sctx->clone_roots[i];
+ if (!clone_root->found_ref)
+ continue;
+
+ /*
+ * Choose the root from which we can clone more bytes, to
+ * minimize write operations and therefore have more extent
+ * sharing at the destination (the same as in the source).
+ */
+ if (!cur_clone_root ||
+ clone_root->num_bytes > cur_clone_root->num_bytes) {
+ cur_clone_root = clone_root;
+
+ /*
+ * We found an optimal clone candidate (any inode from
+ * any root is fine), so we're done.
+ */
+ if (clone_root->num_bytes >= backref_ctx.extent_len)
+ break;
+ }
}
if (cur_clone_root) {
@@ -1515,8 +1746,6 @@ static int find_extent_clone(struct send_ctx *sctx,
ret = -ENOENT;
}
-out:
- btrfs_free_path(tmp_path);
return ret;
}
@@ -1596,13 +1825,17 @@ static int gen_unique_name(struct send_ctx *sctx,
return -ENOMEM;
while (1) {
+ struct fscrypt_str tmp_name;
+
len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu",
ino, gen, idx);
ASSERT(len < sizeof(tmp));
+ tmp_name.name = tmp;
+ tmp_name.len = strlen(tmp);
di = btrfs_lookup_dir_item(NULL, sctx->send_root,
path, BTRFS_FIRST_FREE_OBJECTID,
- tmp, strlen(tmp), 0);
+ &tmp_name, 0);
btrfs_release_path(path);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
@@ -1622,7 +1855,7 @@ static int gen_unique_name(struct send_ctx *sctx,
di = btrfs_lookup_dir_item(NULL, sctx->parent_root,
path, BTRFS_FIRST_FREE_OBJECTID,
- tmp, strlen(tmp), 0);
+ &tmp_name, 0);
btrfs_release_path(path);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
@@ -1752,13 +1985,13 @@ static int lookup_dir_item_inode(struct btrfs_root *root,
struct btrfs_dir_item *di;
struct btrfs_key key;
struct btrfs_path *path;
+ struct fscrypt_str name_str = FSTR_INIT((char *)name, name_len);
path = alloc_path_for_send();
if (!path)
return -ENOMEM;
- di = btrfs_lookup_dir_item(NULL, root, path,
- dir, name, name_len, 0);
+ di = btrfs_lookup_dir_item(NULL, root, path, dir, &name_str, 0);
if (IS_ERR_OR_NULL(di)) {
ret = di ? PTR_ERR(di) : -ENOENT;
goto out;
@@ -5702,6 +5935,7 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
u64 ext_len;
u64 clone_len;
u64 clone_data_offset;
+ bool crossed_src_i_size = false;
if (slot >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(clone_root->root, path);
@@ -5759,8 +5993,10 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
if (key.offset >= clone_src_i_size)
break;
- if (key.offset + ext_len > clone_src_i_size)
+ if (key.offset + ext_len > clone_src_i_size) {
ext_len = clone_src_i_size - key.offset;
+ crossed_src_i_size = true;
+ }
clone_data_offset = btrfs_file_extent_offset(leaf, ei);
if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte) {
@@ -5821,6 +6057,25 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
ret = send_clone(sctx, offset, clone_len,
clone_root);
}
+ } else if (crossed_src_i_size && clone_len < len) {
+ /*
+ * If we are at i_size of the clone source inode and we
+ * can not clone from it, terminate the loop. This is
+ * to avoid sending two write operations, one with a
+ * length matching clone_len and the final one after
+ * this loop with a length of len - clone_len.
+ *
+ * When using encoded writes (BTRFS_SEND_FLAG_COMPRESSED
+ * was passed to the send ioctl), this helps avoid
+ * sending an encoded write for an offset that is not
+ * sector size aligned, in case the i_size of the source
+ * inode is not sector size aligned. That will make the
+ * receiver fallback to decompression of the data and
+ * writing it using regular buffered IO, therefore while
+ * not incorrect, it's not optimal due decompression and
+ * possible re-compression at the receiver.
+ */
+ break;
} else {
ret = send_extent_data(sctx, dst_path, offset,
clone_len);
@@ -7841,6 +8096,9 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL);
INIT_LIST_HEAD(&sctx->name_cache_list);
+ INIT_LIST_HEAD(&sctx->backref_cache.lru_list);
+ mt_init(&sctx->backref_cache.entries);
+
sctx->flags = arg->flags;
if (arg->flags & BTRFS_SEND_FLAG_VERSION) {
@@ -7879,7 +8137,7 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
if (sctx->proto >= 2) {
u32 send_buf_num_pages;
- sctx->send_max_size = ALIGN(SZ_16K + BTRFS_MAX_COMPRESSED, PAGE_SIZE);
+ sctx->send_max_size = BTRFS_SEND_BUF_SIZE_V2;
sctx->send_buf = vmalloc(sctx->send_max_size);
if (!sctx->send_buf) {
ret = -ENOMEM;
@@ -8103,6 +8361,8 @@ out:
close_current_inode(sctx);
+ empty_backref_cache(sctx);
+
kfree(sctx);
}
diff --git a/fs/btrfs/send.h b/fs/btrfs/send.h
index f7585cfa7e52..4f5509cb1803 100644
--- a/fs/btrfs/send.h
+++ b/fs/btrfs/send.h
@@ -18,10 +18,12 @@
#endif
/*
- * In send stream v1, no command is larger than 64K. In send stream v2, no limit
- * should be assumed.
+ * In send stream v1, no command is larger than 64K. In send stream v2, no
+ * limit should be assumed, the buffer size is set to be a header with
+ * compressed extent size.
*/
#define BTRFS_SEND_BUF_SIZE_V1 SZ_64K
+#define BTRFS_SEND_BUF_SIZE_V2 ALIGN(SZ_16K + BTRFS_MAX_COMPRESSED, PAGE_SIZE)
struct inode;
struct btrfs_ioctl_send_args;
diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
index f171bf875633..d28ee4e36f3d 100644
--- a/fs/btrfs/space-info.c
+++ b/fs/btrfs/space-info.c
@@ -10,6 +10,9 @@
#include "transaction.h"
#include "block-group.h"
#include "zoned.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
/*
* HOW DOES SPACE RESERVATION WORK
@@ -856,7 +859,7 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
u64 thresh;
u64 used;
- thresh = div_factor_fine(total, 90);
+ thresh = mult_perc(total, 90);
lockdep_assert_held(&space_info->lock);
@@ -974,7 +977,7 @@ static bool steal_from_global_rsv(struct btrfs_fs_info *fs_info,
return false;
spin_lock(&global_rsv->lock);
- min_bytes = div_factor(global_rsv->size, 1);
+ min_bytes = mult_perc(global_rsv->size, 10);
if (global_rsv->reserved < min_bytes + ticket->bytes) {
spin_unlock(&global_rsv->lock);
return false;
@@ -1490,8 +1493,8 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info,
spin_unlock(&space_info->lock);
}
-/**
- * Do the appropriate flushing and waiting for a ticket
+/*
+ * Do the appropriate flushing and waiting for a ticket.
*
* @fs_info: the filesystem
* @space_info: space info for the reservation
@@ -1583,8 +1586,18 @@ static inline bool can_steal(enum btrfs_reserve_flush_enum flush)
flush == BTRFS_RESERVE_FLUSH_EVICT);
}
-/**
- * Try to reserve bytes from the block_rsv's space
+/*
+ * NO_FLUSH and FLUSH_EMERGENCY don't want to create a ticket, they just want to
+ * fail as quickly as possible.
+ */
+static inline bool can_ticket(enum btrfs_reserve_flush_enum flush)
+{
+ return (flush != BTRFS_RESERVE_NO_FLUSH &&
+ flush != BTRFS_RESERVE_FLUSH_EMERGENCY);
+}
+
+/*
+ * Try to reserve bytes from the block_rsv's space.
*
* @fs_info: the filesystem
* @space_info: space info we want to allocate from
@@ -1645,13 +1658,28 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info,
}
/*
+ * Things are dire, we need to make a reservation so we don't abort. We
+ * will let this reservation go through as long as we have actual space
+ * left to allocate for the block.
+ */
+ if (ret && unlikely(flush == BTRFS_RESERVE_FLUSH_EMERGENCY)) {
+ used = btrfs_space_info_used(space_info, false);
+ if (used + orig_bytes <=
+ writable_total_bytes(fs_info, space_info)) {
+ btrfs_space_info_update_bytes_may_use(fs_info, space_info,
+ orig_bytes);
+ ret = 0;
+ }
+ }
+
+ /*
* If we couldn't make a reservation then setup our reservation ticket
* and kick the async worker if it's not already running.
*
* If we are a priority flusher then we just need to add our ticket to
* the list and we will do our own flushing further down.
*/
- if (ret && flush != BTRFS_RESERVE_NO_FLUSH) {
+ if (ret && can_ticket(flush)) {
ticket.bytes = orig_bytes;
ticket.error = 0;
space_info->reclaim_size += ticket.bytes;
@@ -1701,15 +1729,15 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info,
}
}
spin_unlock(&space_info->lock);
- if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
+ if (!ret || !can_ticket(flush))
return ret;
return handle_reserve_ticket(fs_info, space_info, &ticket, start_ns,
orig_bytes, flush);
}
-/**
- * Trye to reserve metadata bytes from the block_rsv's space
+/*
+ * Try to reserve metadata bytes from the block_rsv's space.
*
* @fs_info: the filesystem
* @block_rsv: block_rsv we're allocating for
@@ -1743,8 +1771,8 @@ int btrfs_reserve_metadata_bytes(struct btrfs_fs_info *fs_info,
return ret;
}
-/**
- * Try to reserve data bytes for an allocation
+/*
+ * Try to reserve data bytes for an allocation.
*
* @fs_info: the filesystem
* @bytes: number of bytes we need
@@ -1787,3 +1815,37 @@ __cold void btrfs_dump_space_info_for_trans_abort(struct btrfs_fs_info *fs_info)
}
dump_global_block_rsv(fs_info);
}
+
+/*
+ * Account the unused space of all the readonly block group in the space_info.
+ * takes mirrors into account.
+ */
+u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
+{
+ struct btrfs_block_group *block_group;
+ u64 free_bytes = 0;
+ int factor;
+
+ /* It's df, we don't care if it's racy */
+ if (list_empty(&sinfo->ro_bgs))
+ return 0;
+
+ spin_lock(&sinfo->lock);
+ list_for_each_entry(block_group, &sinfo->ro_bgs, ro_list) {
+ spin_lock(&block_group->lock);
+
+ if (!block_group->ro) {
+ spin_unlock(&block_group->lock);
+ continue;
+ }
+
+ factor = btrfs_bg_type_to_factor(block_group->flags);
+ free_bytes += (block_group->length -
+ block_group->used) * factor;
+
+ spin_unlock(&block_group->lock);
+ }
+ spin_unlock(&sinfo->lock);
+
+ return free_bytes;
+}
diff --git a/fs/btrfs/space-info.h b/fs/btrfs/space-info.h
index ce66023a9eb8..fc99ea2b0c34 100644
--- a/fs/btrfs/space-info.h
+++ b/fs/btrfs/space-info.h
@@ -5,6 +5,83 @@
#include "volumes.h"
+/*
+ * Different levels for to flush space when doing space reservations.
+ *
+ * The higher the level, the more methods we try to reclaim space.
+ */
+enum btrfs_reserve_flush_enum {
+ /* If we are in the transaction, we can't flush anything.*/
+ BTRFS_RESERVE_NO_FLUSH,
+
+ /*
+ * Flush space by:
+ * - Running delayed inode items
+ * - Allocating a new chunk
+ */
+ BTRFS_RESERVE_FLUSH_LIMIT,
+
+ /*
+ * Flush space by:
+ * - Running delayed inode items
+ * - Running delayed refs
+ * - Running delalloc and waiting for ordered extents
+ * - Allocating a new chunk
+ */
+ BTRFS_RESERVE_FLUSH_EVICT,
+
+ /*
+ * Flush space by above mentioned methods and by:
+ * - Running delayed iputs
+ * - Committing transaction
+ *
+ * Can be interrupted by a fatal signal.
+ */
+ BTRFS_RESERVE_FLUSH_DATA,
+ BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE,
+ BTRFS_RESERVE_FLUSH_ALL,
+
+ /*
+ * Pretty much the same as FLUSH_ALL, but can also steal space from
+ * global rsv.
+ *
+ * Can be interrupted by a fatal signal.
+ */
+ BTRFS_RESERVE_FLUSH_ALL_STEAL,
+
+ /*
+ * This is for btrfs_use_block_rsv only. We have exhausted our block
+ * rsv and our global block rsv. This can happen for things like
+ * delalloc where we are overwriting a lot of extents with a single
+ * extent and didn't reserve enough space. Alternatively it can happen
+ * with delalloc where we reserve 1 extents worth for a large extent but
+ * fragmentation leads to multiple extents being created. This will
+ * give us the reservation in the case of
+ *
+ * if (num_bytes < (space_info->total_bytes -
+ * btrfs_space_info_used(space_info, false))
+ *
+ * Which ignores bytes_may_use. This is potentially dangerous, but our
+ * reservation system is generally pessimistic so is able to absorb this
+ * style of mistake.
+ */
+ BTRFS_RESERVE_FLUSH_EMERGENCY,
+};
+
+enum btrfs_flush_state {
+ FLUSH_DELAYED_ITEMS_NR = 1,
+ FLUSH_DELAYED_ITEMS = 2,
+ FLUSH_DELAYED_REFS_NR = 3,
+ FLUSH_DELAYED_REFS = 4,
+ FLUSH_DELALLOC = 5,
+ FLUSH_DELALLOC_WAIT = 6,
+ FLUSH_DELALLOC_FULL = 7,
+ ALLOC_CHUNK = 8,
+ ALLOC_CHUNK_FORCE = 9,
+ RUN_DELAYED_IPUTS = 10,
+ COMMIT_TRANS = 11,
+};
+
struct btrfs_space_info {
spinlock_t lock;
@@ -159,5 +236,6 @@ int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
enum btrfs_reserve_flush_enum flush);
void btrfs_dump_space_info_for_trans_abort(struct btrfs_fs_info *fs_info);
void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info);
+u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
#endif /* BTRFS_SPACE_INFO_H */
diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c
index 9a176af847d7..dd46b978ac2c 100644
--- a/fs/btrfs/subpage.c
+++ b/fs/btrfs/subpage.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/slab.h>
+#include "messages.h"
#include "ctree.h"
#include "subpage.h"
#include "btrfs_inode.h"
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 5942b9384088..93f52ee85f6f 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -26,6 +26,7 @@
#include <linux/ratelimit.h>
#include <linux/crc32c.h>
#include <linux/btrfs.h>
+#include "messages.h"
#include "delayed-inode.h"
#include "ctree.h"
#include "disk-io.h"
@@ -34,7 +35,7 @@
#include "print-tree.h"
#include "props.h"
#include "xattr.h"
-#include "volumes.h"
+#include "bio.h"
#include "export.h"
#include "compression.h"
#include "rcu-string.h"
@@ -49,6 +50,14 @@
#include "discard.h"
#include "qgroup.h"
#include "raid56.h"
+#include "fs.h"
+#include "accessors.h"
+#include "defrag.h"
+#include "dir-item.h"
+#include "ioctl.h"
+#include "scrub.h"
+#include "verity.h"
+#include "super.h"
#define CREATE_TRACE_POINTS
#include <trace/events/btrfs.h>
@@ -67,328 +76,6 @@ static struct file_system_type btrfs_root_fs_type;
static int btrfs_remount(struct super_block *sb, int *flags, char *data);
-#ifdef CONFIG_PRINTK
-
-#define STATE_STRING_PREFACE ": state "
-#define STATE_STRING_BUF_LEN (sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT)
-
-/*
- * Characters to print to indicate error conditions or uncommon filesystem state.
- * RO is not an error.
- */
-static const char fs_state_chars[] = {
- [BTRFS_FS_STATE_ERROR] = 'E',
- [BTRFS_FS_STATE_REMOUNTING] = 'M',
- [BTRFS_FS_STATE_RO] = 0,
- [BTRFS_FS_STATE_TRANS_ABORTED] = 'A',
- [BTRFS_FS_STATE_DEV_REPLACING] = 'R',
- [BTRFS_FS_STATE_DUMMY_FS_INFO] = 0,
- [BTRFS_FS_STATE_NO_CSUMS] = 'C',
- [BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L',
-};
-
-static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf)
-{
- unsigned int bit;
- bool states_printed = false;
- unsigned long fs_state = READ_ONCE(info->fs_state);
- char *curr = buf;
-
- memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE));
- curr += sizeof(STATE_STRING_PREFACE) - 1;
-
- for_each_set_bit(bit, &fs_state, sizeof(fs_state)) {
- WARN_ON_ONCE(bit >= BTRFS_FS_STATE_COUNT);
- if ((bit < BTRFS_FS_STATE_COUNT) && fs_state_chars[bit]) {
- *curr++ = fs_state_chars[bit];
- states_printed = true;
- }
- }
-
- /* If no states were printed, reset the buffer */
- if (!states_printed)
- curr = buf;
-
- *curr++ = 0;
-}
-#endif
-
-/*
- * Generally the error codes correspond to their respective errors, but there
- * are a few special cases.
- *
- * EUCLEAN: Any sort of corruption that we encounter. The tree-checker for
- * instance will return EUCLEAN if any of the blocks are corrupted in
- * a way that is problematic. We want to reserve EUCLEAN for these
- * sort of corruptions.
- *
- * EROFS: If we check BTRFS_FS_STATE_ERROR and fail out with a return error, we
- * need to use EROFS for this case. We will have no idea of the
- * original failure, that will have been reported at the time we tripped
- * over the error. Each subsequent error that doesn't have any context
- * of the original error should use EROFS when handling BTRFS_FS_STATE_ERROR.
- */
-const char * __attribute_const__ btrfs_decode_error(int errno)
-{
- char *errstr = "unknown";
-
- switch (errno) {
- case -ENOENT: /* -2 */
- errstr = "No such entry";
- break;
- case -EIO: /* -5 */
- errstr = "IO failure";
- break;
- case -ENOMEM: /* -12*/
- errstr = "Out of memory";
- break;
- case -EEXIST: /* -17 */
- errstr = "Object already exists";
- break;
- case -ENOSPC: /* -28 */
- errstr = "No space left";
- break;
- case -EROFS: /* -30 */
- errstr = "Readonly filesystem";
- break;
- case -EOPNOTSUPP: /* -95 */
- errstr = "Operation not supported";
- break;
- case -EUCLEAN: /* -117 */
- errstr = "Filesystem corrupted";
- break;
- case -EDQUOT: /* -122 */
- errstr = "Quota exceeded";
- break;
- }
-
- return errstr;
-}
-
-/*
- * __btrfs_handle_fs_error decodes expected errors from the caller and
- * invokes the appropriate error response.
- */
-__cold
-void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
- unsigned int line, int errno, const char *fmt, ...)
-{
- struct super_block *sb = fs_info->sb;
-#ifdef CONFIG_PRINTK
- char statestr[STATE_STRING_BUF_LEN];
- const char *errstr;
-#endif
-
- /*
- * Special case: if the error is EROFS, and we're already
- * under SB_RDONLY, then it is safe here.
- */
- if (errno == -EROFS && sb_rdonly(sb))
- return;
-
-#ifdef CONFIG_PRINTK
- errstr = btrfs_decode_error(errno);
- btrfs_state_to_string(fs_info, statestr);
- if (fmt) {
- struct va_format vaf;
- va_list args;
-
- va_start(args, fmt);
- vaf.fmt = fmt;
- vaf.va = &args;
-
- pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s (%pV)\n",
- sb->s_id, statestr, function, line, errno, errstr, &vaf);
- va_end(args);
- } else {
- pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s\n",
- sb->s_id, statestr, function, line, errno, errstr);
- }
-#endif
-
- /*
- * Today we only save the error info to memory. Long term we'll
- * also send it down to the disk
- */
- set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
-
- /* Don't go through full error handling during mount */
- if (!(sb->s_flags & SB_BORN))
- return;
-
- if (sb_rdonly(sb))
- return;
-
- btrfs_discard_stop(fs_info);
-
- /* btrfs handle error by forcing the filesystem readonly */
- btrfs_set_sb_rdonly(sb);
- btrfs_info(fs_info, "forced readonly");
- /*
- * Note that a running device replace operation is not canceled here
- * although there is no way to update the progress. It would add the
- * risk of a deadlock, therefore the canceling is omitted. The only
- * penalty is that some I/O remains active until the procedure
- * completes. The next time when the filesystem is mounted writable
- * again, the device replace operation continues.
- */
-}
-
-#ifdef CONFIG_PRINTK
-static const char * const logtypes[] = {
- "emergency",
- "alert",
- "critical",
- "error",
- "warning",
- "notice",
- "info",
- "debug",
-};
-
-
-/*
- * Use one ratelimit state per log level so that a flood of less important
- * messages doesn't cause more important ones to be dropped.
- */
-static struct ratelimit_state printk_limits[] = {
- RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100),
- RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100),
-};
-
-void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
-{
- char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0";
- struct va_format vaf;
- va_list args;
- int kern_level;
- const char *type = logtypes[4];
- struct ratelimit_state *ratelimit = &printk_limits[4];
-
- va_start(args, fmt);
-
- while ((kern_level = printk_get_level(fmt)) != 0) {
- size_t size = printk_skip_level(fmt) - fmt;
-
- if (kern_level >= '0' && kern_level <= '7') {
- memcpy(lvl, fmt, size);
- lvl[size] = '\0';
- type = logtypes[kern_level - '0'];
- ratelimit = &printk_limits[kern_level - '0'];
- }
- fmt += size;
- }
-
- vaf.fmt = fmt;
- vaf.va = &args;
-
- if (__ratelimit(ratelimit)) {
- if (fs_info) {
- char statestr[STATE_STRING_BUF_LEN];
-
- btrfs_state_to_string(fs_info, statestr);
- _printk("%sBTRFS %s (device %s%s): %pV\n", lvl, type,
- fs_info->sb->s_id, statestr, &vaf);
- } else {
- _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf);
- }
- }
-
- va_end(args);
-}
-#endif
-
-#if BITS_PER_LONG == 32
-void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info)
-{
- if (!test_and_set_bit(BTRFS_FS_32BIT_WARN, &fs_info->flags)) {
- btrfs_warn(fs_info, "reaching 32bit limit for logical addresses");
- btrfs_warn(fs_info,
-"due to page cache limit on 32bit systems, btrfs can't access metadata at or beyond %lluT",
- BTRFS_32BIT_MAX_FILE_SIZE >> 40);
- btrfs_warn(fs_info,
- "please consider upgrading to 64bit kernel/hardware");
- }
-}
-
-void __cold btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info)
-{
- if (!test_and_set_bit(BTRFS_FS_32BIT_ERROR, &fs_info->flags)) {
- btrfs_err(fs_info, "reached 32bit limit for logical addresses");
- btrfs_err(fs_info,
-"due to page cache limit on 32bit systems, metadata beyond %lluT can't be accessed",
- BTRFS_32BIT_MAX_FILE_SIZE >> 40);
- btrfs_err(fs_info,
- "please consider upgrading to 64bit kernel/hardware");
- }
-}
-#endif
-
-/*
- * We only mark the transaction aborted and then set the file system read-only.
- * This will prevent new transactions from starting or trying to join this
- * one.
- *
- * This means that error recovery at the call site is limited to freeing
- * any local memory allocations and passing the error code up without
- * further cleanup. The transaction should complete as it normally would
- * in the call path but will return -EIO.
- *
- * We'll complete the cleanup in btrfs_end_transaction and
- * btrfs_commit_transaction.
- */
-__cold
-void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
- const char *function,
- unsigned int line, int errno, bool first_hit)
-{
- struct btrfs_fs_info *fs_info = trans->fs_info;
-
- WRITE_ONCE(trans->aborted, errno);
- WRITE_ONCE(trans->transaction->aborted, errno);
- if (first_hit && errno == -ENOSPC)
- btrfs_dump_space_info_for_trans_abort(fs_info);
- /* Wake up anybody who may be waiting on this transaction */
- wake_up(&fs_info->transaction_wait);
- wake_up(&fs_info->transaction_blocked_wait);
- __btrfs_handle_fs_error(fs_info, function, line, errno, NULL);
-}
-/*
- * __btrfs_panic decodes unexpected, fatal errors from the caller,
- * issues an alert, and either panics or BUGs, depending on mount options.
- */
-__cold
-void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
- unsigned int line, int errno, const char *fmt, ...)
-{
- char *s_id = "<unknown>";
- const char *errstr;
- struct va_format vaf = { .fmt = fmt };
- va_list args;
-
- if (fs_info)
- s_id = fs_info->sb->s_id;
-
- va_start(args, fmt);
- vaf.va = &args;
-
- errstr = btrfs_decode_error(errno);
- if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR)))
- panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n",
- s_id, function, line, &vaf, errno, errstr);
-
- btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)",
- function, line, &vaf, errno, errstr);
- va_end(args);
- /* Caller calls BUG() */
-}
-
static void btrfs_put_super(struct super_block *sb)
{
close_ctree(btrfs_sb(sb));
@@ -918,12 +605,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
ret = -EINVAL;
goto out;
}
+ btrfs_clear_opt(info->mount_opt, NODISCARD);
break;
case Opt_nodiscard:
btrfs_clear_and_info(info, DISCARD_SYNC,
"turning off discard");
btrfs_clear_and_info(info, DISCARD_ASYNC,
"turning off async discard");
+ btrfs_set_opt(info->mount_opt, NODISCARD);
break;
case Opt_space_cache:
case Opt_space_cache_version:
@@ -1394,6 +1083,7 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec
struct btrfs_dir_item *di;
struct btrfs_path *path;
struct btrfs_key location;
+ struct fscrypt_str name = FSTR_INIT("default", 7);
u64 dir_id;
path = btrfs_alloc_path();
@@ -1406,7 +1096,7 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec
* to mount.
*/
dir_id = btrfs_super_root_dir(fs_info->super_copy);
- di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
+ di = btrfs_lookup_dir_item(NULL, root, path, dir_id, &name, 0);
if (IS_ERR(di)) {
btrfs_free_path(path);
return PTR_ERR(di);
@@ -1507,7 +1197,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
* Exit unless we have some pending changes
* that need to go through commit
*/
- if (fs_info->pending_changes == 0)
+ if (!test_bit(BTRFS_FS_NEED_TRANS_COMMIT,
+ &fs_info->flags))
return 0;
/*
* A non-blocking test if the fs is frozen. We must not
@@ -2645,7 +2336,7 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
* the end of RCU grace period.
*/
rcu_read_lock();
- seq_escape(m, rcu_str_deref(fs_info->fs_devices->latest_dev->name), " \t\n\\");
+ seq_escape(m, btrfs_dev_name(fs_info->fs_devices->latest_dev), " \t\n\\");
rcu_read_unlock();
return 0;
@@ -2694,7 +2385,7 @@ static __cold void btrfs_interface_exit(void)
misc_deregister(&btrfs_misc);
}
-static void __init btrfs_print_mod_info(void)
+static int __init btrfs_print_mod_info(void)
{
static const char options[] = ""
#ifdef CONFIG_BTRFS_DEBUG
@@ -2721,122 +2412,125 @@ static void __init btrfs_print_mod_info(void)
#endif
;
pr_info("Btrfs loaded, crc32c=%s%s\n", crc32c_impl(), options);
+ return 0;
}
-static int __init init_btrfs_fs(void)
+static int register_btrfs(void)
{
- int err;
-
- btrfs_props_init();
-
- err = btrfs_init_sysfs();
- if (err)
- return err;
-
- btrfs_init_compress();
-
- err = btrfs_init_cachep();
- if (err)
- goto free_compress;
-
- err = extent_state_init_cachep();
- if (err)
- goto free_cachep;
-
- err = extent_buffer_init_cachep();
- if (err)
- goto free_extent_cachep;
-
- err = btrfs_bioset_init();
- if (err)
- goto free_eb_cachep;
-
- err = extent_map_init();
- if (err)
- goto free_bioset;
-
- err = ordered_data_init();
- if (err)
- goto free_extent_map;
-
- err = btrfs_delayed_inode_init();
- if (err)
- goto free_ordered_data;
-
- err = btrfs_auto_defrag_init();
- if (err)
- goto free_delayed_inode;
-
- err = btrfs_delayed_ref_init();
- if (err)
- goto free_auto_defrag;
-
- err = btrfs_prelim_ref_init();
- if (err)
- goto free_delayed_ref;
-
- err = btrfs_interface_init();
- if (err)
- goto free_prelim_ref;
+ return register_filesystem(&btrfs_fs_type);
+}
- btrfs_print_mod_info();
+static void unregister_btrfs(void)
+{
+ unregister_filesystem(&btrfs_fs_type);
+}
- err = btrfs_run_sanity_tests();
- if (err)
- goto unregister_ioctl;
+/* Helper structure for long init/exit functions. */
+struct init_sequence {
+ int (*init_func)(void);
+ /* Can be NULL if the init_func doesn't need cleanup. */
+ void (*exit_func)(void);
+};
- err = register_filesystem(&btrfs_fs_type);
- if (err)
- goto unregister_ioctl;
+static const struct init_sequence mod_init_seq[] = {
+ {
+ .init_func = btrfs_props_init,
+ .exit_func = NULL,
+ }, {
+ .init_func = btrfs_init_sysfs,
+ .exit_func = btrfs_exit_sysfs,
+ }, {
+ .init_func = btrfs_init_compress,
+ .exit_func = btrfs_exit_compress,
+ }, {
+ .init_func = btrfs_init_cachep,
+ .exit_func = btrfs_destroy_cachep,
+ }, {
+ .init_func = btrfs_transaction_init,
+ .exit_func = btrfs_transaction_exit,
+ }, {
+ .init_func = btrfs_ctree_init,
+ .exit_func = btrfs_ctree_exit,
+ }, {
+ .init_func = btrfs_free_space_init,
+ .exit_func = btrfs_free_space_exit,
+ }, {
+ .init_func = extent_state_init_cachep,
+ .exit_func = extent_state_free_cachep,
+ }, {
+ .init_func = extent_buffer_init_cachep,
+ .exit_func = extent_buffer_free_cachep,
+ }, {
+ .init_func = btrfs_bioset_init,
+ .exit_func = btrfs_bioset_exit,
+ }, {
+ .init_func = extent_map_init,
+ .exit_func = extent_map_exit,
+ }, {
+ .init_func = ordered_data_init,
+ .exit_func = ordered_data_exit,
+ }, {
+ .init_func = btrfs_delayed_inode_init,
+ .exit_func = btrfs_delayed_inode_exit,
+ }, {
+ .init_func = btrfs_auto_defrag_init,
+ .exit_func = btrfs_auto_defrag_exit,
+ }, {
+ .init_func = btrfs_delayed_ref_init,
+ .exit_func = btrfs_delayed_ref_exit,
+ }, {
+ .init_func = btrfs_prelim_ref_init,
+ .exit_func = btrfs_prelim_ref_exit,
+ }, {
+ .init_func = btrfs_interface_init,
+ .exit_func = btrfs_interface_exit,
+ }, {
+ .init_func = btrfs_print_mod_info,
+ .exit_func = NULL,
+ }, {
+ .init_func = btrfs_run_sanity_tests,
+ .exit_func = NULL,
+ }, {
+ .init_func = register_btrfs,
+ .exit_func = unregister_btrfs,
+ }
+};
- return 0;
+static bool mod_init_result[ARRAY_SIZE(mod_init_seq)];
-unregister_ioctl:
- btrfs_interface_exit();
-free_prelim_ref:
- btrfs_prelim_ref_exit();
-free_delayed_ref:
- btrfs_delayed_ref_exit();
-free_auto_defrag:
- btrfs_auto_defrag_exit();
-free_delayed_inode:
- btrfs_delayed_inode_exit();
-free_ordered_data:
- ordered_data_exit();
-free_extent_map:
- extent_map_exit();
-free_bioset:
- btrfs_bioset_exit();
-free_eb_cachep:
- extent_buffer_free_cachep();
-free_extent_cachep:
- extent_state_free_cachep();
-free_cachep:
- btrfs_destroy_cachep();
-free_compress:
- btrfs_exit_compress();
- btrfs_exit_sysfs();
+static __always_inline void btrfs_exit_btrfs_fs(void)
+{
+ int i;
- return err;
+ for (i = ARRAY_SIZE(mod_init_seq) - 1; i >= 0; i--) {
+ if (!mod_init_result[i])
+ continue;
+ if (mod_init_seq[i].exit_func)
+ mod_init_seq[i].exit_func();
+ mod_init_result[i] = false;
+ }
}
static void __exit exit_btrfs_fs(void)
{
- btrfs_destroy_cachep();
- btrfs_delayed_ref_exit();
- btrfs_auto_defrag_exit();
- btrfs_delayed_inode_exit();
- btrfs_prelim_ref_exit();
- ordered_data_exit();
- extent_map_exit();
- btrfs_bioset_exit();
- extent_state_free_cachep();
- extent_buffer_free_cachep();
- btrfs_interface_exit();
- unregister_filesystem(&btrfs_fs_type);
- btrfs_exit_sysfs();
- btrfs_cleanup_fs_uuids();
- btrfs_exit_compress();
+ btrfs_exit_btrfs_fs();
+}
+
+static int __init init_btrfs_fs(void)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mod_init_seq); i++) {
+ ASSERT(!mod_init_result[i]);
+ ret = mod_init_seq[i].init_func();
+ if (ret < 0) {
+ btrfs_exit_btrfs_fs();
+ return ret;
+ }
+ mod_init_result[i] = true;
+ }
+ return 0;
}
late_initcall(init_btrfs_fs);
diff --git a/fs/btrfs/super.h b/fs/btrfs/super.h
new file mode 100644
index 000000000000..8dbb909b364f
--- /dev/null
+++ b/fs/btrfs/super.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_SUPER_H
+#define BTRFS_SUPER_H
+
+int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
+ unsigned long new_flags);
+int btrfs_sync_fs(struct super_block *sb, int wait);
+char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
+ u64 subvol_objectid);
+
+static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+static inline void btrfs_set_sb_rdonly(struct super_block *sb)
+{
+ sb->s_flags |= SB_RDONLY;
+ set_bit(BTRFS_FS_STATE_RO, &btrfs_sb(sb)->fs_state);
+}
+
+static inline void btrfs_clear_sb_rdonly(struct super_block *sb)
+{
+ sb->s_flags &= ~SB_RDONLY;
+ clear_bit(BTRFS_FS_STATE_RO, &btrfs_sb(sb)->fs_state);
+}
+
+#endif
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 699b54b3acaa..45615ce36498 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -10,7 +10,7 @@
#include <linux/completion.h>
#include <linux/bug.h>
#include <crypto/hash.h>
-
+#include "messages.h"
#include "ctree.h"
#include "discard.h"
#include "disk-io.h"
@@ -22,6 +22,8 @@
#include "block-group.h"
#include "qgroup.h"
#include "misc.h"
+#include "fs.h"
+#include "accessors.h"
/*
* Structure name Path
@@ -248,7 +250,7 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
/*
* We don't want to do full transaction commit from inside sysfs
*/
- btrfs_set_pending(fs_info, COMMIT);
+ set_bit(BTRFS_FS_NEED_TRANS_COMMIT, &fs_info->flags);
wake_up_process(fs_info->transaction_kthread);
return count;
@@ -762,7 +764,7 @@ static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
val = min(val, BTRFS_MAX_DATA_CHUNK_SIZE);
/* Limit stripe size to 10% of available space. */
- val = min(div_factor(fs_info->fs_devices->total_rw_bytes, 1), val);
+ val = min(mult_perc(fs_info->fs_devices->total_rw_bytes, 10), val);
/* Must be multiple of 256M. */
val &= ~((u64)SZ_256M - 1);
@@ -959,7 +961,7 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
/*
* We don't want to do full transaction commit from inside sysfs
*/
- btrfs_set_pending(fs_info, COMMIT);
+ set_bit(BTRFS_FS_NEED_TRANS_COMMIT, &fs_info->flags);
wake_up_process(fs_info->transaction_kthread);
return len;
@@ -1160,16 +1162,16 @@ static ssize_t btrfs_read_policy_show(struct kobject *kobj,
for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
if (fs_devices->read_policy == i)
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s[%s]",
+ ret += sysfs_emit_at(buf, ret, "%s[%s]",
(ret == 0 ? "" : " "),
btrfs_read_policy_name[i]);
else
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
+ ret += sysfs_emit_at(buf, ret, "%s%s",
(ret == 0 ? "" : " "),
btrfs_read_policy_name[i]);
}
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
+ ret += sysfs_emit_at(buf, ret, "\n");
return ret;
}
@@ -2321,8 +2323,11 @@ int __init btrfs_init_sysfs(void)
#ifdef CONFIG_BTRFS_DEBUG
ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
- if (ret)
- goto out2;
+ if (ret) {
+ sysfs_unmerge_group(&btrfs_kset->kobj,
+ &btrfs_static_feature_attr_group);
+ goto out_remove_group;
+ }
#endif
return 0;
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 9c478fa256f6..181469fc0bb3 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -16,6 +16,7 @@
#include "../disk-io.h"
#include "../qgroup.h"
#include "../block-group.h"
+#include "../fs.h"
static struct vfsmount *test_mnt = NULL;
@@ -101,7 +102,7 @@ struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info)
if (!dev)
return ERR_PTR(-ENOMEM);
- extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL);
+ extent_io_tree_init(NULL, &dev->alloc_state, 0);
INIT_LIST_HEAD(&dev->dev_list);
list_add(&dev->dev_list, &fs_info->fs_devices->devices);
@@ -200,7 +201,7 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
void btrfs_free_dummy_root(struct btrfs_root *root)
{
- if (!root)
+ if (IS_ERR_OR_NULL(root))
return;
/* Will be freed by btrfs_free_fs_roots */
if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
diff --git a/fs/btrfs/tests/extent-buffer-tests.c b/fs/btrfs/tests/extent-buffer-tests.c
index b7d181a08eab..5ef0b90e25c3 100644
--- a/fs/btrfs/tests/extent-buffer-tests.c
+++ b/fs/btrfs/tests/extent-buffer-tests.c
@@ -8,6 +8,7 @@
#include "../ctree.h"
#include "../extent_io.h"
#include "../disk-io.h"
+#include "../accessors.h"
static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
{
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
index 350da449db08..dfc5c7fa6038 100644
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -132,7 +132,7 @@ static int test_find_delalloc(u32 sectorsize)
* Passing NULL as we don't have fs_info but tracepoints are not used
* at this point
*/
- extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST, NULL);
+ extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST);
/*
* First go through and create and mark all of our pages dirty, we pin
@@ -489,7 +489,7 @@ static int test_find_first_clear_extent_bit(void)
test_msg("running find_first_clear_extent_bit test");
- extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST, NULL);
+ extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST);
/* Test correct handling of empty tree */
find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED);
diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c
index 13734ed43bfc..b61972046feb 100644
--- a/fs/btrfs/tests/free-space-tree-tests.c
+++ b/fs/btrfs/tests/free-space-tree-tests.c
@@ -10,6 +10,7 @@
#include "../free-space-tree.h"
#include "../transaction.h"
#include "../block-group.h"
+#include "../accessors.h"
struct free_space_extent {
u64 start;
@@ -470,7 +471,7 @@ static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize,
}
cache->bitmap_low_thresh = 0;
cache->bitmap_high_thresh = (u32)-1;
- cache->needs_free_space = 1;
+ set_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE, &cache->runtime_flags);
cache->fs_info = root->fs_info;
btrfs_init_dummy_trans(&trans, root->fs_info);
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
index 625f7d398368..05b03f5eab83 100644
--- a/fs/btrfs/tests/inode-tests.c
+++ b/fs/btrfs/tests/inode-tests.c
@@ -11,6 +11,7 @@
#include "../extent_io.h"
#include "../volumes.h"
#include "../compression.h"
+#include "../accessors.h"
static void insert_extent(struct btrfs_root *root, u64 start, u64 len,
u64 ram_bytes, u64 offset, u64 disk_bytenr,
@@ -72,8 +73,8 @@ static void insert_inode_item_key(struct btrfs_root *root)
* diagram of how the extents will look though this may not be possible we still
* want to make sure everything acts normally (the last number is not inclusive)
*
- * [0 - 5][5 - 6][ 6 - 4096 ][ 4096 - 4100][4100 - 8195][8195 - 12291]
- * [hole ][inline][hole but no extent][ hole ][ regular ][regular1 split]
+ * [0 - 6][ 6 - 4096 ][ 4096 - 4100][4100 - 8195][8195 - 12291]
+ * [inline][hole but no extent][ hole ][ regular ][regular1 split]
*
* [12291 - 16387][16387 - 24579][24579 - 28675][ 28675 - 32771][32771 - 36867 ]
* [ hole ][regular1 split][ prealloc ][ prealloc1 ][prealloc1 written]
@@ -90,19 +91,12 @@ static void setup_file_extents(struct btrfs_root *root, u32 sectorsize)
u64 disk_bytenr = SZ_1M;
u64 offset = 0;
- /* First we want a hole */
- insert_extent(root, offset, 5, 5, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0,
- slot);
- slot++;
- offset += 5;
-
/*
- * Now we want an inline extent, I don't think this is possible but hey
- * why not? Also keep in mind if we have an inline extent it counts as
- * the whole first page. If we were to expand it we would have to cow
- * and we wouldn't have an inline extent anymore.
+ * Tree-checker has strict limits on inline extents that they can only
+ * exist at file offset 0, thus we can only have one inline file extent
+ * at most.
*/
- insert_extent(root, offset, 1, 1, 0, 0, 0, BTRFS_FILE_EXTENT_INLINE, 0,
+ insert_extent(root, offset, 6, 6, 0, 0, 0, BTRFS_FILE_EXTENT_INLINE, 0,
slot);
slot++;
offset = sectorsize;
@@ -281,37 +275,25 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
test_err("got an error when we shouldn't have");
goto out;
}
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_err("expected a hole, got %llu", em->block_start);
- goto out;
- }
- if (em->start != 0 || em->len != 5) {
- test_err(
- "unexpected extent wanted start 0 len 5, got start %llu len %llu",
- em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_err("unexpected flags set, want 0 have %lu", em->flags);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
- if (IS_ERR(em)) {
- test_err("got an error when we shouldn't have");
- goto out;
- }
if (em->block_start != EXTENT_MAP_INLINE) {
test_err("expected an inline, got %llu", em->block_start);
goto out;
}
- if (em->start != offset || em->len != (sectorsize - 5)) {
+ /*
+ * For inline extent, we always round up the em to sectorsize, as
+ * they are either:
+ *
+ * a) a hidden hole
+ * The range will be zeroed at inline extent read time.
+ *
+ * b) a file extent with unaligned bytenr
+ * Tree checker will reject it.
+ */
+ if (em->start != 0 || em->len != sectorsize) {
test_err(
- "unexpected extent wanted start %llu len 1, got start %llu len %llu",
- offset, em->start, em->len);
+ "unexpected extent wanted start 0 len %u, got start %llu len %llu",
+ sectorsize, em->start, em->len);
goto out;
}
if (em->flags != 0) {
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index 63676ea19f29..3fc8dc3fd980 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -10,6 +10,8 @@
#include "../disk-io.h"
#include "../qgroup.h"
#include "../backref.h"
+#include "../fs.h"
+#include "../accessors.h"
static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
u64 num_bytes, u64 parent, u64 root_objectid)
@@ -203,6 +205,7 @@ static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
static int test_no_shared_qgroup(struct btrfs_root *root,
u32 sectorsize, u32 nodesize)
{
+ struct btrfs_backref_walk_ctx ctx = { 0 };
struct btrfs_trans_handle trans;
struct btrfs_fs_info *fs_info = root->fs_info;
struct ulist *old_roots = NULL;
@@ -218,16 +221,22 @@ static int test_no_shared_qgroup(struct btrfs_root *root,
return ret;
}
+ ctx.bytenr = nodesize;
+ ctx.trans = &trans;
+ ctx.fs_info = fs_info;
+
/*
* Since the test trans doesn't have the complicated delayed refs,
* we can only call btrfs_qgroup_account_extent() directly to test
* quota.
*/
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ old_roots = ctx.roots;
+ ctx.roots = NULL;
ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
BTRFS_FS_TREE_OBJECTID);
@@ -236,12 +245,14 @@ static int test_no_shared_qgroup(struct btrfs_root *root,
return ret;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
ulist_free(old_roots);
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ new_roots = ctx.roots;
+ ctx.roots = NULL;
ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
new_roots);
@@ -260,11 +271,13 @@ static int test_no_shared_qgroup(struct btrfs_root *root,
return -EINVAL;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ old_roots = ctx.roots;
+ ctx.roots = NULL;
ret = remove_extent_item(root, nodesize, nodesize);
if (ret) {
@@ -272,12 +285,14 @@ static int test_no_shared_qgroup(struct btrfs_root *root,
return -EINVAL;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
ulist_free(old_roots);
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ new_roots = ctx.roots;
+ ctx.roots = NULL;
ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
new_roots);
@@ -302,6 +317,7 @@ static int test_no_shared_qgroup(struct btrfs_root *root,
static int test_multiple_refs(struct btrfs_root *root,
u32 sectorsize, u32 nodesize)
{
+ struct btrfs_backref_walk_ctx ctx = { 0 };
struct btrfs_trans_handle trans;
struct btrfs_fs_info *fs_info = root->fs_info;
struct ulist *old_roots = NULL;
@@ -322,11 +338,17 @@ static int test_multiple_refs(struct btrfs_root *root,
return ret;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
+ ctx.bytenr = nodesize;
+ ctx.trans = &trans;
+ ctx.fs_info = fs_info;
+
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ old_roots = ctx.roots;
+ ctx.roots = NULL;
ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
BTRFS_FS_TREE_OBJECTID);
@@ -335,12 +357,14 @@ static int test_multiple_refs(struct btrfs_root *root,
return ret;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
ulist_free(old_roots);
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ new_roots = ctx.roots;
+ ctx.roots = NULL;
ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
new_roots);
@@ -355,11 +379,13 @@ static int test_multiple_refs(struct btrfs_root *root,
return -EINVAL;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ old_roots = ctx.roots;
+ ctx.roots = NULL;
ret = add_tree_ref(root, nodesize, nodesize, 0,
BTRFS_FIRST_FREE_OBJECTID);
@@ -368,12 +394,14 @@ static int test_multiple_refs(struct btrfs_root *root,
return ret;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
ulist_free(old_roots);
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ new_roots = ctx.roots;
+ ctx.roots = NULL;
ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
new_roots);
@@ -394,11 +422,13 @@ static int test_multiple_refs(struct btrfs_root *root,
return -EINVAL;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ old_roots = ctx.roots;
+ ctx.roots = NULL;
ret = remove_extent_ref(root, nodesize, nodesize, 0,
BTRFS_FIRST_FREE_OBJECTID);
@@ -407,12 +437,14 @@ static int test_multiple_refs(struct btrfs_root *root,
return ret;
}
- ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots, false);
+ ret = btrfs_find_all_roots(&ctx, false);
if (ret) {
ulist_free(old_roots);
test_err("couldn't find old roots: %d", ret);
return ret;
}
+ new_roots = ctx.roots;
+ ctx.roots = NULL;
ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
new_roots);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index d1f1da6820fb..b8c52e89688c 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -6,6 +6,7 @@
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/sched/mm.h>
#include <linux/writeback.h>
#include <linux/pagemap.h>
#include <linux/blkdev.h>
@@ -23,6 +24,18 @@
#include "block-group.h"
#include "space-info.h"
#include "zoned.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "defrag.h"
+#include "dir-item.h"
+#include "uuid-tree.h"
+#include "ioctl.h"
+#include "relocation.h"
+#include "scrub.h"
+
+static struct kmem_cache *btrfs_trans_handle_cachep;
#define BTRFS_ROOT_TRANS_TAG 0
@@ -365,9 +378,9 @@ loop:
spin_lock_init(&cur_trans->releasing_ebs_lock);
list_add_tail(&cur_trans->list, &fs_info->trans_list);
extent_io_tree_init(fs_info, &cur_trans->dirty_pages,
- IO_TREE_TRANS_DIRTY_PAGES, NULL);
+ IO_TREE_TRANS_DIRTY_PAGES);
extent_io_tree_init(fs_info, &cur_trans->pinned_extents,
- IO_TREE_FS_PINNED_EXTENTS, NULL);
+ IO_TREE_FS_PINNED_EXTENTS);
fs_info->generation++;
cur_trans->transid = fs_info->generation;
fs_info->running_transaction = cur_trans;
@@ -936,7 +949,7 @@ static bool should_end_transaction(struct btrfs_trans_handle *trans)
if (btrfs_check_space_for_delayed_refs(fs_info))
return true;
- return !!btrfs_block_rsv_check(&fs_info->global_block_rsv, 5);
+ return !!btrfs_block_rsv_check(&fs_info->global_block_rsv, 50);
}
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
@@ -1607,10 +1620,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *root = pending->root;
struct btrfs_root *parent_root;
struct btrfs_block_rsv *rsv;
- struct inode *parent_inode;
+ struct inode *parent_inode = pending->dir;
struct btrfs_path *path;
struct btrfs_dir_item *dir_item;
- struct dentry *dentry;
struct extent_buffer *tmp;
struct extent_buffer *old;
struct timespec64 cur_time;
@@ -1619,6 +1631,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
u64 index = 0;
u64 objectid;
u64 root_flags;
+ unsigned int nofs_flags;
+ struct fscrypt_name fname;
ASSERT(pending->path);
path = pending->path;
@@ -1626,9 +1640,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
ASSERT(pending->root_item);
new_root_item = pending->root_item;
+ /*
+ * We're inside a transaction and must make sure that any potential
+ * allocations with GFP_KERNEL in fscrypt won't recurse back to
+ * filesystem.
+ */
+ nofs_flags = memalloc_nofs_save();
+ pending->error = fscrypt_setup_filename(parent_inode,
+ &pending->dentry->d_name, 0,
+ &fname);
+ memalloc_nofs_restore(nofs_flags);
+ if (pending->error)
+ goto free_pending;
+
pending->error = btrfs_get_free_objectid(tree_root, &objectid);
if (pending->error)
- goto no_free_objectid;
+ goto free_fname;
/*
* Make qgroup to skip current new snapshot's qgroupid, as it is
@@ -1657,8 +1684,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
trace_btrfs_space_reservation(fs_info, "transaction",
trans->transid,
trans->bytes_reserved, 1);
- dentry = pending->dentry;
- parent_inode = pending->dir;
parent_root = BTRFS_I(parent_inode)->root;
ret = record_root_in_trans(trans, parent_root, 0);
if (ret)
@@ -1674,8 +1699,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
/* check if there is a file/dir which has the same name. */
dir_item = btrfs_lookup_dir_item(NULL, parent_root, path,
btrfs_ino(BTRFS_I(parent_inode)),
- dentry->d_name.name,
- dentry->d_name.len, 0);
+ &fname.disk_name, 0);
if (dir_item != NULL && !IS_ERR(dir_item)) {
pending->error = -EEXIST;
goto dir_item_existed;
@@ -1770,7 +1794,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
ret = btrfs_add_root_ref(trans, objectid,
parent_root->root_key.objectid,
btrfs_ino(BTRFS_I(parent_inode)), index,
- dentry->d_name.name, dentry->d_name.len);
+ &fname.disk_name);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
@@ -1802,9 +1826,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
if (ret < 0)
goto fail;
- ret = btrfs_insert_dir_item(trans, dentry->d_name.name,
- dentry->d_name.len, BTRFS_I(parent_inode),
- &key, BTRFS_FT_DIR, index);
+ ret = btrfs_insert_dir_item(trans, &fname.disk_name,
+ BTRFS_I(parent_inode), &key, BTRFS_FT_DIR,
+ index);
/* We have check then name at the beginning, so it is impossible. */
BUG_ON(ret == -EEXIST || ret == -EOVERFLOW);
if (ret) {
@@ -1813,7 +1837,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
}
btrfs_i_size_write(BTRFS_I(parent_inode), parent_inode->i_size +
- dentry->d_name.len * 2);
+ fname.disk_name.len * 2);
parent_inode->i_mtime = current_time(parent_inode);
parent_inode->i_ctime = parent_inode->i_mtime;
ret = btrfs_update_inode_fallback(trans, parent_root, BTRFS_I(parent_inode));
@@ -1845,7 +1869,9 @@ dir_item_existed:
trans->bytes_reserved = 0;
clear_skip_qgroup:
btrfs_clear_skip_qgroup(trans);
-no_free_objectid:
+free_fname:
+ fscrypt_free_filename(&fname);
+free_pending:
kfree(new_root_item);
pending->root_item = NULL;
btrfs_free_path(path);
@@ -2101,6 +2127,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
ASSERT(refcount_read(&trans->use_count) == 1);
btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
+ clear_bit(BTRFS_FS_NEED_TRANS_COMMIT, &fs_info->flags);
+
/* Stop the commit early if ->aborted is set */
if (TRANS_ABORTED(cur_trans)) {
ret = cur_trans->aborted;
@@ -2354,12 +2382,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (ret)
goto unlock_reloc;
- /*
- * Since the transaction is done, we can apply the pending changes
- * before the next transaction.
- */
- btrfs_apply_pending_changes(fs_info);
-
/* commit_fs_roots gets rid of all the tree log roots, it is now
* safe to free the root of tree log roots
*/
@@ -2582,21 +2604,17 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_fs_info *fs_info)
return (ret < 0) ? 0 : 1;
}
-void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
+int __init btrfs_transaction_init(void)
{
- unsigned long prev;
- unsigned long bit;
-
- prev = xchg(&fs_info->pending_changes, 0);
- if (!prev)
- return;
-
- bit = 1 << BTRFS_PENDING_COMMIT;
- if (prev & bit)
- btrfs_debug(fs_info, "pending commit done");
- prev &= ~bit;
+ btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle",
+ sizeof(struct btrfs_trans_handle), 0,
+ SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+ if (!btrfs_trans_handle_cachep)
+ return -ENOMEM;
+ return 0;
+}
- if (prev)
- btrfs_warn(fs_info,
- "unknown pending changes left 0x%lx, ignoring", prev);
+void __cold btrfs_transaction_exit(void)
+{
+ kmem_cache_destroy(btrfs_trans_handle_cachep);
}
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 970ff316069d..97f6c39f59c8 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -10,6 +10,7 @@
#include "btrfs_inode.h"
#include "delayed-ref.h"
#include "ctree.h"
+#include "misc.h"
enum btrfs_trans_state {
TRANS_STATE_RUNNING,
@@ -98,14 +99,15 @@ struct btrfs_transaction {
struct list_head releasing_ebs;
};
-#define __TRANS_FREEZABLE (1U << 0)
-
-#define __TRANS_START (1U << 9)
-#define __TRANS_ATTACH (1U << 10)
-#define __TRANS_JOIN (1U << 11)
-#define __TRANS_JOIN_NOLOCK (1U << 12)
-#define __TRANS_DUMMY (1U << 13)
-#define __TRANS_JOIN_NOSTART (1U << 14)
+enum {
+ ENUM_BIT(__TRANS_FREEZABLE),
+ ENUM_BIT(__TRANS_START),
+ ENUM_BIT(__TRANS_ATTACH),
+ ENUM_BIT(__TRANS_JOIN),
+ ENUM_BIT(__TRANS_JOIN_NOLOCK),
+ ENUM_BIT(__TRANS_DUMMY),
+ ENUM_BIT(__TRANS_JOIN_NOSTART),
+};
#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE)
#define TRANS_ATTACH (__TRANS_ATTACH)
@@ -231,9 +233,11 @@ int btrfs_wait_tree_log_extents(struct btrfs_root *root, int mark);
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
void btrfs_put_transaction(struct btrfs_transaction *transaction);
-void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
+int __init btrfs_transaction_init(void);
+void __cold btrfs_transaction_exit(void);
+
#endif
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 43f905ab0a18..baad1ed7e111 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/error-injection.h>
+#include "messages.h"
#include "ctree.h"
#include "tree-checker.h"
#include "disk-io.h"
@@ -25,6 +26,9 @@
#include "volumes.h"
#include "misc.h"
#include "btrfs_inode.h"
+#include "fs.h"
+#include "accessors.h"
+#include "file-item.h"
/*
* Error message should follow the following format:
@@ -528,7 +532,7 @@ static int check_dir_item(struct extent_buffer *leaf,
}
/* dir type check */
- dir_type = btrfs_dir_type(leaf, di);
+ dir_type = btrfs_dir_ftype(leaf, di);
if (unlikely(dir_type >= BTRFS_FT_MAX)) {
dir_item_err(leaf, slot,
"invalid dir item type, have %u expect [0, %u)",
@@ -1780,10 +1784,10 @@ static int check_leaf(struct extent_buffer *leaf, bool check_item_data)
/* Also check if the item pointer overlaps with btrfs item. */
if (unlikely(btrfs_item_ptr_offset(leaf, slot) <
- btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item))) {
+ btrfs_item_nr_offset(leaf, slot) + sizeof(struct btrfs_item))) {
generic_err(leaf, slot,
"slot overlaps with its data, item end %lu data start %lu",
- btrfs_item_nr_offset(slot) +
+ btrfs_item_nr_offset(leaf, slot) +
sizeof(struct btrfs_item),
btrfs_item_ptr_offset(leaf, slot));
return -EUCLEAN;
diff --git a/fs/btrfs/tree-checker.h b/fs/btrfs/tree-checker.h
index ece497e26558..bfb5efa4e01f 100644
--- a/fs/btrfs/tree-checker.h
+++ b/fs/btrfs/tree-checker.h
@@ -6,8 +6,39 @@
#ifndef BTRFS_TREE_CHECKER_H
#define BTRFS_TREE_CHECKER_H
-#include "ctree.h"
-#include "extent_io.h"
+#include <uapi/linux/btrfs_tree.h>
+
+struct extent_buffer;
+struct btrfs_chunk;
+
+/* All the extra info needed to verify the parentness of a tree block. */
+struct btrfs_tree_parent_check {
+ /*
+ * The owner check against the tree block.
+ *
+ * Can be 0 to skip the owner check.
+ */
+ u64 owner_root;
+
+ /*
+ * Expected transid, can be 0 to skip the check, but such skip
+ * should only be utlized for backref walk related code.
+ */
+ u64 transid;
+
+ /*
+ * The expected first key.
+ *
+ * This check can be skipped if @has_first_key is false, such skip
+ * can happen for case where we don't have the parent node key,
+ * e.g. reading the tree root, doing backref walk.
+ */
+ struct btrfs_key first_key;
+ bool has_first_key;
+
+ /* The expected level. Should always be set. */
+ u8 level;
+};
/*
* Comprehensive leaf checker.
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
deleted file mode 100644
index b6cf39f4e7e4..000000000000
--- a/fs/btrfs/tree-defrag.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2007 Oracle. All rights reserved.
- */
-
-#include <linux/sched.h>
-#include "ctree.h"
-#include "disk-io.h"
-#include "print-tree.h"
-#include "transaction.h"
-#include "locking.h"
-
-/*
- * Defrag all the leaves in a given btree.
- * Read all the leaves and try to get key order to
- * better reflect disk order
- */
-
-int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- struct btrfs_path *path = NULL;
- struct btrfs_key key;
- int ret = 0;
- int wret;
- int level;
- int next_key_ret = 0;
- u64 last_ret = 0;
-
- if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
- goto out;
-
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
-
- level = btrfs_header_level(root->node);
-
- if (level == 0)
- goto out;
-
- if (root->defrag_progress.objectid == 0) {
- struct extent_buffer *root_node;
- u32 nritems;
-
- root_node = btrfs_lock_root_node(root);
- nritems = btrfs_header_nritems(root_node);
- root->defrag_max.objectid = 0;
- /* from above we know this is not a leaf */
- btrfs_node_key_to_cpu(root_node, &root->defrag_max,
- nritems - 1);
- btrfs_tree_unlock(root_node);
- free_extent_buffer(root_node);
- memset(&key, 0, sizeof(key));
- } else {
- memcpy(&key, &root->defrag_progress, sizeof(key));
- }
-
- path->keep_locks = 1;
-
- ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
- if (ret < 0)
- goto out;
- if (ret > 0) {
- ret = 0;
- goto out;
- }
- btrfs_release_path(path);
- /*
- * We don't need a lock on a leaf. btrfs_realloc_node() will lock all
- * leafs from path->nodes[1], so set lowest_level to 1 to avoid later
- * a deadlock (attempting to write lock an already write locked leaf).
- */
- path->lowest_level = 1;
- wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
-
- if (wret < 0) {
- ret = wret;
- goto out;
- }
- if (!path->nodes[1]) {
- ret = 0;
- goto out;
- }
- /*
- * The node at level 1 must always be locked when our path has
- * keep_locks set and lowest_level is 1, regardless of the value of
- * path->slots[1].
- */
- BUG_ON(path->locks[1] == 0);
- ret = btrfs_realloc_node(trans, root,
- path->nodes[1], 0,
- &last_ret,
- &root->defrag_progress);
- if (ret) {
- WARN_ON(ret == -EAGAIN);
- goto out;
- }
- /*
- * Now that we reallocated the node we can find the next key. Note that
- * btrfs_find_next_key() can release our path and do another search
- * without COWing, this is because even with path->keep_locks = 1,
- * btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a
- * node when path->slots[node_level - 1] does not point to the last
- * item or a slot beyond the last item (ctree.c:unlock_up()). Therefore
- * we search for the next key after reallocating our node.
- */
- path->slots[1] = btrfs_header_nritems(path->nodes[1]);
- next_key_ret = btrfs_find_next_key(root, path, &key, 1,
- BTRFS_OLDEST_GENERATION);
- if (next_key_ret == 0) {
- memcpy(&root->defrag_progress, &key, sizeof(key));
- ret = -EAGAIN;
- }
-out:
- btrfs_free_path(path);
- if (ret == -EAGAIN) {
- if (root->defrag_max.objectid > root->defrag_progress.objectid)
- goto done;
- if (root->defrag_max.type > root->defrag_progress.type)
- goto done;
- if (root->defrag_max.offset > root->defrag_progress.offset)
- goto done;
- ret = 0;
- }
-done:
- if (ret != -EAGAIN)
- memset(&root->defrag_progress, 0,
- sizeof(root->defrag_progress));
-
- return ret;
-}
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 813986e38258..a3c43f0b1c95 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -21,6 +21,15 @@
#include "space-info.h"
#include "zoned.h"
#include "inode-item.h"
+#include "fs.h"
+#include "accessors.h"
+#include "extent-tree.h"
+#include "root-tree.h"
+#include "dir-item.h"
+#include "file-item.h"
+#include "file.h"
+#include "orphan.h"
+#include "tree-checker.h"
#define MAX_CONFLICT_INODES 10
@@ -333,7 +342,12 @@ static int process_one_buffer(struct btrfs_root *log,
* pin down any logged extents, so we have to read the block.
*/
if (btrfs_fs_incompat(fs_info, MIXED_GROUPS)) {
- ret = btrfs_read_extent_buffer(eb, gen, level, NULL);
+ struct btrfs_tree_parent_check check = {
+ .level = level,
+ .transid = gen
+ };
+
+ ret = btrfs_read_extent_buffer(eb, &check);
if (ret)
return ret;
}
@@ -351,11 +365,25 @@ static int process_one_buffer(struct btrfs_root *log,
return ret;
}
-static int do_overwrite_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct extent_buffer *eb, int slot,
- struct btrfs_key *key)
+/*
+ * Item overwrite used by replay and tree logging. eb, slot and key all refer
+ * to the src data we are copying out.
+ *
+ * root is the tree we are copying into, and path is a scratch
+ * path for use in this function (it should be released on entry and
+ * will be released on exit).
+ *
+ * If the key is already in the destination tree the existing item is
+ * overwritten. If the existing item isn't big enough, it is extended.
+ * If it is too large, it is truncated.
+ *
+ * If the key isn't in the destination yet, a new item is inserted.
+ */
+static int overwrite_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct extent_buffer *eb, int slot,
+ struct btrfs_key *key)
{
int ret;
u32 item_size;
@@ -363,31 +391,24 @@ static int do_overwrite_item(struct btrfs_trans_handle *trans,
int save_old_i_size = 0;
unsigned long src_ptr;
unsigned long dst_ptr;
- int overwrite_root = 0;
bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
- if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
- overwrite_root = 1;
+ /*
+ * This is only used during log replay, so the root is always from a
+ * fs/subvolume tree. In case we ever need to support a log root, then
+ * we'll have to clone the leaf in the path, release the path and use
+ * the leaf before writing into the log tree. See the comments at
+ * copy_items() for more details.
+ */
+ ASSERT(root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID);
item_size = btrfs_item_size(eb, slot);
src_ptr = btrfs_item_ptr_offset(eb, slot);
- /* Our caller must have done a search for the key for us. */
- ASSERT(path->nodes[0] != NULL);
-
- /*
- * And the slot must point to the exact key or the slot where the key
- * should be at (the first item with a key greater than 'key')
- */
- if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
- struct btrfs_key found_key;
-
- btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
- ret = btrfs_comp_cpu_keys(&found_key, key);
- ASSERT(ret >= 0);
- } else {
- ret = 1;
- }
+ /* Look for the key in the destination tree. */
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ if (ret < 0)
+ return ret;
if (ret == 0) {
char *src_copy;
@@ -532,8 +553,7 @@ insert:
goto no_copy;
}
- if (overwrite_root &&
- S_ISDIR(btrfs_inode_mode(eb, src_item)) &&
+ if (S_ISDIR(btrfs_inode_mode(eb, src_item)) &&
S_ISDIR(btrfs_inode_mode(path->nodes[0], dst_item))) {
save_old_i_size = 1;
saved_i_size = btrfs_inode_size(path->nodes[0],
@@ -565,34 +585,19 @@ no_copy:
return 0;
}
-/*
- * Item overwrite used by replay and tree logging. eb, slot and key all refer
- * to the src data we are copying out.
- *
- * root is the tree we are copying into, and path is a scratch
- * path for use in this function (it should be released on entry and
- * will be released on exit).
- *
- * If the key is already in the destination tree the existing item is
- * overwritten. If the existing item isn't big enough, it is extended.
- * If it is too large, it is truncated.
- *
- * If the key isn't in the destination yet, a new item is inserted.
- */
-static int overwrite_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct extent_buffer *eb, int slot,
- struct btrfs_key *key)
+static int read_alloc_one_name(struct extent_buffer *eb, void *start, int len,
+ struct fscrypt_str *name)
{
- int ret;
+ char *buf;
- /* Look for the key in the destination tree. */
- ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
- if (ret < 0)
- return ret;
+ buf = kmalloc(len, GFP_NOFS);
+ if (!buf)
+ return -ENOMEM;
- return do_overwrite_item(trans, root, path, eb, slot, key);
+ read_extent_buffer(eb, buf, (unsigned long)start, len);
+ name->name = buf;
+ name->len = len;
+ return 0;
}
/*
@@ -747,8 +752,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
*/
ret = btrfs_qgroup_trace_extent(trans,
btrfs_file_extent_disk_bytenr(eb, item),
- btrfs_file_extent_disk_num_bytes(eb, item),
- GFP_NOFS);
+ btrfs_file_extent_disk_num_bytes(eb, item));
if (ret < 0)
goto out;
@@ -799,7 +803,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
btrfs_file_extent_num_bytes(eb, item);
}
- ret = btrfs_lookup_csums_range(root->log_root,
+ ret = btrfs_lookup_csums_list(root->log_root,
csum_start, csum_end - 1,
&ordered_sums, 0, false);
if (ret)
@@ -901,12 +905,11 @@ out:
static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
- const char *name,
- int name_len)
+ const struct fscrypt_str *name)
{
int ret;
- ret = btrfs_unlink_inode(trans, dir, inode, name, name_len);
+ ret = btrfs_unlink_inode(trans, dir, inode, name);
if (ret)
return ret;
/*
@@ -933,8 +936,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
{
struct btrfs_root *root = dir->root;
struct inode *inode;
- char *name;
- int name_len;
+ struct fscrypt_str name;
struct extent_buffer *leaf;
struct btrfs_key location;
int ret;
@@ -942,12 +944,10 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
btrfs_dir_item_key_to_cpu(leaf, di, &location);
- name_len = btrfs_dir_name_len(leaf, di);
- name = kmalloc(name_len, GFP_NOFS);
- if (!name)
+ ret = read_alloc_one_name(leaf, di + 1, btrfs_dir_name_len(leaf, di), &name);
+ if (ret)
return -ENOMEM;
- read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
btrfs_release_path(path);
inode = read_one_inode(root, location.objectid);
@@ -960,10 +960,9 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
if (ret)
goto out;
- ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), name,
- name_len);
+ ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), &name);
out:
- kfree(name);
+ kfree(name.name);
iput(inode);
return ret;
}
@@ -978,14 +977,14 @@ out:
static noinline int inode_in_dir(struct btrfs_root *root,
struct btrfs_path *path,
u64 dirid, u64 objectid, u64 index,
- const char *name, int name_len)
+ struct fscrypt_str *name)
{
struct btrfs_dir_item *di;
struct btrfs_key location;
int ret = 0;
di = btrfs_lookup_dir_index_item(NULL, root, path, dirid,
- index, name, name_len, 0);
+ index, name, 0);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
goto out;
@@ -998,7 +997,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
}
btrfs_release_path(path);
- di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
+ di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, 0);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
goto out;
@@ -1025,7 +1024,7 @@ out:
static noinline int backref_in_log(struct btrfs_root *log,
struct btrfs_key *key,
u64 ref_objectid,
- const char *name, int namelen)
+ const struct fscrypt_str *name)
{
struct btrfs_path *path;
int ret;
@@ -1045,12 +1044,10 @@ static noinline int backref_in_log(struct btrfs_root *log,
if (key->type == BTRFS_INODE_EXTREF_KEY)
ret = !!btrfs_find_name_in_ext_backref(path->nodes[0],
path->slots[0],
- ref_objectid,
- name, namelen);
+ ref_objectid, name);
else
ret = !!btrfs_find_name_in_backref(path->nodes[0],
- path->slots[0],
- name, namelen);
+ path->slots[0], name);
out:
btrfs_free_path(path);
return ret;
@@ -1063,11 +1060,9 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
u64 inode_objectid, u64 parent_objectid,
- u64 ref_index, char *name, int namelen)
+ u64 ref_index, struct fscrypt_str *name)
{
int ret;
- char *victim_name;
- int victim_name_len;
struct extent_buffer *leaf;
struct btrfs_dir_item *di;
struct btrfs_key search_key;
@@ -1099,43 +1094,40 @@ again:
ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
ptr_end = ptr + btrfs_item_size(leaf, path->slots[0]);
while (ptr < ptr_end) {
- victim_ref = (struct btrfs_inode_ref *)ptr;
- victim_name_len = btrfs_inode_ref_name_len(leaf,
- victim_ref);
- victim_name = kmalloc(victim_name_len, GFP_NOFS);
- if (!victim_name)
- return -ENOMEM;
+ struct fscrypt_str victim_name;
- read_extent_buffer(leaf, victim_name,
- (unsigned long)(victim_ref + 1),
- victim_name_len);
+ victim_ref = (struct btrfs_inode_ref *)ptr;
+ ret = read_alloc_one_name(leaf, (victim_ref + 1),
+ btrfs_inode_ref_name_len(leaf, victim_ref),
+ &victim_name);
+ if (ret)
+ return ret;
ret = backref_in_log(log_root, &search_key,
- parent_objectid, victim_name,
- victim_name_len);
+ parent_objectid, &victim_name);
if (ret < 0) {
- kfree(victim_name);
+ kfree(victim_name.name);
return ret;
} else if (!ret) {
inc_nlink(&inode->vfs_inode);
btrfs_release_path(path);
ret = unlink_inode_for_log_replay(trans, dir, inode,
- victim_name, victim_name_len);
- kfree(victim_name);
+ &victim_name);
+ kfree(victim_name.name);
if (ret)
return ret;
goto again;
}
- kfree(victim_name);
+ kfree(victim_name.name);
- ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
+ ptr = (unsigned long)(victim_ref + 1) + victim_name.len;
}
}
btrfs_release_path(path);
/* Same search but for extended refs */
- extref = btrfs_lookup_inode_extref(NULL, root, path, name, namelen,
+ extref = btrfs_lookup_inode_extref(NULL, root, path, name,
inode_objectid, parent_objectid, 0,
0);
if (IS_ERR(extref)) {
@@ -1152,29 +1144,28 @@ again:
base = btrfs_item_ptr_offset(leaf, path->slots[0]);
while (cur_offset < item_size) {
- extref = (struct btrfs_inode_extref *)(base + cur_offset);
+ struct fscrypt_str victim_name;
- victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
+ extref = (struct btrfs_inode_extref *)(base + cur_offset);
if (btrfs_inode_extref_parent(leaf, extref) != parent_objectid)
goto next;
- victim_name = kmalloc(victim_name_len, GFP_NOFS);
- if (!victim_name)
- return -ENOMEM;
- read_extent_buffer(leaf, victim_name, (unsigned long)&extref->name,
- victim_name_len);
+ ret = read_alloc_one_name(leaf, &extref->name,
+ btrfs_inode_extref_name_len(leaf, extref),
+ &victim_name);
+ if (ret)
+ return ret;
search_key.objectid = inode_objectid;
search_key.type = BTRFS_INODE_EXTREF_KEY;
search_key.offset = btrfs_extref_hash(parent_objectid,
- victim_name,
- victim_name_len);
+ victim_name.name,
+ victim_name.len);
ret = backref_in_log(log_root, &search_key,
- parent_objectid, victim_name,
- victim_name_len);
+ parent_objectid, &victim_name);
if (ret < 0) {
- kfree(victim_name);
+ kfree(victim_name.name);
return ret;
} else if (!ret) {
ret = -ENOENT;
@@ -1186,26 +1177,24 @@ again:
ret = unlink_inode_for_log_replay(trans,
BTRFS_I(victim_parent),
- inode,
- victim_name,
- victim_name_len);
+ inode, &victim_name);
}
iput(victim_parent);
- kfree(victim_name);
+ kfree(victim_name.name);
if (ret)
return ret;
goto again;
}
- kfree(victim_name);
+ kfree(victim_name.name);
next:
- cur_offset += victim_name_len + sizeof(*extref);
+ cur_offset += victim_name.len + sizeof(*extref);
}
}
btrfs_release_path(path);
/* look for a conflicting sequence number */
di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
- ref_index, name, namelen, 0);
+ ref_index, name, 0);
if (IS_ERR(di)) {
return PTR_ERR(di);
} else if (di) {
@@ -1216,8 +1205,7 @@ next:
btrfs_release_path(path);
/* look for a conflicting name */
- di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),
- name, namelen, 0);
+ di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir), name, 0);
if (IS_ERR(di)) {
return PTR_ERR(di);
} else if (di) {
@@ -1231,20 +1219,18 @@ next:
}
static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
- u32 *namelen, char **name, u64 *index,
+ struct fscrypt_str *name, u64 *index,
u64 *parent_objectid)
{
struct btrfs_inode_extref *extref;
+ int ret;
extref = (struct btrfs_inode_extref *)ref_ptr;
- *namelen = btrfs_inode_extref_name_len(eb, extref);
- *name = kmalloc(*namelen, GFP_NOFS);
- if (*name == NULL)
- return -ENOMEM;
-
- read_extent_buffer(eb, *name, (unsigned long)&extref->name,
- *namelen);
+ ret = read_alloc_one_name(eb, &extref->name,
+ btrfs_inode_extref_name_len(eb, extref), name);
+ if (ret)
+ return ret;
if (index)
*index = btrfs_inode_extref_index(eb, extref);
@@ -1255,18 +1241,17 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
}
static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
- u32 *namelen, char **name, u64 *index)
+ struct fscrypt_str *name, u64 *index)
{
struct btrfs_inode_ref *ref;
+ int ret;
ref = (struct btrfs_inode_ref *)ref_ptr;
- *namelen = btrfs_inode_ref_name_len(eb, ref);
- *name = kmalloc(*namelen, GFP_NOFS);
- if (*name == NULL)
- return -ENOMEM;
-
- read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
+ ret = read_alloc_one_name(eb, ref + 1, btrfs_inode_ref_name_len(eb, ref),
+ name);
+ if (ret)
+ return ret;
if (index)
*index = btrfs_inode_ref_index(eb, ref);
@@ -1308,28 +1293,24 @@ again:
ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
ref_end = ref_ptr + btrfs_item_size(eb, path->slots[0]);
while (ref_ptr < ref_end) {
- char *name = NULL;
- int namelen;
+ struct fscrypt_str name;
u64 parent_id;
if (key->type == BTRFS_INODE_EXTREF_KEY) {
- ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
+ ret = extref_get_fields(eb, ref_ptr, &name,
NULL, &parent_id);
} else {
parent_id = key->offset;
- ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
- NULL);
+ ret = ref_get_fields(eb, ref_ptr, &name, NULL);
}
if (ret)
goto out;
if (key->type == BTRFS_INODE_EXTREF_KEY)
ret = !!btrfs_find_name_in_ext_backref(log_eb, log_slot,
- parent_id, name,
- namelen);
+ parent_id, &name);
else
- ret = !!btrfs_find_name_in_backref(log_eb, log_slot,
- name, namelen);
+ ret = !!btrfs_find_name_in_backref(log_eb, log_slot, &name);
if (!ret) {
struct inode *dir;
@@ -1338,20 +1319,20 @@ again:
dir = read_one_inode(root, parent_id);
if (!dir) {
ret = -ENOENT;
- kfree(name);
+ kfree(name.name);
goto out;
}
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir),
- inode, name, namelen);
- kfree(name);
+ inode, &name);
+ kfree(name.name);
iput(dir);
if (ret)
goto out;
goto again;
}
- kfree(name);
- ref_ptr += namelen;
+ kfree(name.name);
+ ref_ptr += name.len;
if (key->type == BTRFS_INODE_EXTREF_KEY)
ref_ptr += sizeof(struct btrfs_inode_extref);
else
@@ -1380,8 +1361,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
struct inode *inode = NULL;
unsigned long ref_ptr;
unsigned long ref_end;
- char *name = NULL;
- int namelen;
+ struct fscrypt_str name;
int ret;
int log_ref_ver = 0;
u64 parent_objectid;
@@ -1425,7 +1405,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
while (ref_ptr < ref_end) {
if (log_ref_ver) {
- ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
+ ret = extref_get_fields(eb, ref_ptr, &name,
&ref_index, &parent_objectid);
/*
* parent object can change from one array
@@ -1438,15 +1418,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
goto out;
}
} else {
- ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
- &ref_index);
+ ret = ref_get_fields(eb, ref_ptr, &name, &ref_index);
}
if (ret)
goto out;
ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)),
- btrfs_ino(BTRFS_I(inode)), ref_index,
- name, namelen);
+ btrfs_ino(BTRFS_I(inode)), ref_index, &name);
if (ret < 0) {
goto out;
} else if (ret == 0) {
@@ -1460,7 +1438,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ret = __add_inode_ref(trans, root, path, log,
BTRFS_I(dir), BTRFS_I(inode),
inode_objectid, parent_objectid,
- ref_index, name, namelen);
+ ref_index, &name);
if (ret) {
if (ret == 1)
ret = 0;
@@ -1469,7 +1447,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
/* insert our name */
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
- name, namelen, 0, ref_index);
+ &name, 0, ref_index);
if (ret)
goto out;
@@ -1479,9 +1457,9 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
}
/* Else, ret == 1, we already have a perfect match, we're done. */
- ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
- kfree(name);
- name = NULL;
+ ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + name.len;
+ kfree(name.name);
+ name.name = NULL;
if (log_ref_ver) {
iput(dir);
dir = NULL;
@@ -1505,7 +1483,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ret = overwrite_item(trans, root, path, eb, slot, key);
out:
btrfs_release_path(path);
- kfree(name);
+ kfree(name.name);
iput(dir);
iput(inode);
return ret;
@@ -1777,7 +1755,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
static noinline int insert_one_name(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 dirid, u64 index,
- char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_key *location)
{
struct inode *inode;
@@ -1795,7 +1773,7 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
}
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
- name_len, 1, index);
+ 1, index);
/* FIXME, put inode into FIXUP list */
@@ -1809,7 +1787,7 @@ static int delete_conflicting_dir_entry(struct btrfs_trans_handle *trans,
struct btrfs_path *path,
struct btrfs_dir_item *dst_di,
const struct btrfs_key *log_key,
- u8 log_type,
+ u8 log_flags,
bool exists)
{
struct btrfs_key found_key;
@@ -1819,7 +1797,7 @@ static int delete_conflicting_dir_entry(struct btrfs_trans_handle *trans,
if (found_key.objectid == log_key->objectid &&
found_key.type == log_key->type &&
found_key.offset == log_key->offset &&
- btrfs_dir_type(path->nodes[0], dst_di) == log_type)
+ btrfs_dir_flags(path->nodes[0], dst_di) == log_flags)
return 1;
/*
@@ -1855,8 +1833,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
struct btrfs_dir_item *di,
struct btrfs_key *key)
{
- char *name;
- int name_len;
+ struct fscrypt_str name;
struct btrfs_dir_item *dir_dst_di;
struct btrfs_dir_item *index_dst_di;
bool dir_dst_matches = false;
@@ -1864,7 +1841,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
struct btrfs_key log_key;
struct btrfs_key search_key;
struct inode *dir;
- u8 log_type;
+ u8 log_flags;
bool exists;
int ret;
bool update_size = true;
@@ -1874,17 +1851,11 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
if (!dir)
return -EIO;
- name_len = btrfs_dir_name_len(eb, di);
- name = kmalloc(name_len, GFP_NOFS);
- if (!name) {
- ret = -ENOMEM;
+ ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name);
+ if (ret)
goto out;
- }
-
- log_type = btrfs_dir_type(eb, di);
- read_extent_buffer(eb, name, (unsigned long)(di + 1),
- name_len);
+ log_flags = btrfs_dir_flags(eb, di);
btrfs_dir_item_key_to_cpu(eb, di, &log_key);
ret = btrfs_lookup_inode(trans, root, path, &log_key, 0);
btrfs_release_path(path);
@@ -1894,14 +1865,14 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
ret = 0;
dir_dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
- name, name_len, 1);
+ &name, 1);
if (IS_ERR(dir_dst_di)) {
ret = PTR_ERR(dir_dst_di);
goto out;
} else if (dir_dst_di) {
ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
- dir_dst_di, &log_key, log_type,
- exists);
+ dir_dst_di, &log_key,
+ log_flags, exists);
if (ret < 0)
goto out;
dir_dst_matches = (ret == 1);
@@ -1911,14 +1882,14 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
index_dst_di = btrfs_lookup_dir_index_item(trans, root, path,
key->objectid, key->offset,
- name, name_len, 1);
+ &name, 1);
if (IS_ERR(index_dst_di)) {
ret = PTR_ERR(index_dst_di);
goto out;
} else if (index_dst_di) {
ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
index_dst_di, &log_key,
- log_type, exists);
+ log_flags, exists);
if (ret < 0)
goto out;
index_dst_matches = (ret == 1);
@@ -1939,7 +1910,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
search_key.objectid = log_key.objectid;
search_key.type = BTRFS_INODE_REF_KEY;
search_key.offset = key->objectid;
- ret = backref_in_log(root->log_root, &search_key, 0, name, name_len);
+ ret = backref_in_log(root->log_root, &search_key, 0, &name);
if (ret < 0) {
goto out;
} else if (ret) {
@@ -1952,8 +1923,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
search_key.objectid = log_key.objectid;
search_key.type = BTRFS_INODE_EXTREF_KEY;
search_key.offset = key->objectid;
- ret = backref_in_log(root->log_root, &search_key, key->objectid, name,
- name_len);
+ ret = backref_in_log(root->log_root, &search_key, key->objectid, &name);
if (ret < 0) {
goto out;
} else if (ret) {
@@ -1964,7 +1934,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
}
btrfs_release_path(path);
ret = insert_one_name(trans, root, key->objectid, key->offset,
- name, name_len, &log_key);
+ &name, &log_key);
if (ret && ret != -ENOENT && ret != -EEXIST)
goto out;
if (!ret)
@@ -1974,10 +1944,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
out:
if (!ret && update_size) {
- btrfs_i_size_write(BTRFS_I(dir), dir->i_size + name_len * 2);
+ btrfs_i_size_write(BTRFS_I(dir), dir->i_size + name.len * 2);
ret = btrfs_update_inode(trans, root, BTRFS_I(dir));
}
- kfree(name);
+ kfree(name.name);
iput(dir);
if (!ret && name_added)
ret = 1;
@@ -2028,7 +1998,7 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
* to ever delete the parent directory has it would result in stale
* dentries that can never be deleted.
*/
- if (ret == 1 && btrfs_dir_type(eb, di) != BTRFS_FT_DIR) {
+ if (ret == 1 && btrfs_dir_ftype(eb, di) != BTRFS_FT_DIR) {
struct btrfs_path *fixup_path;
struct btrfs_key di_key;
@@ -2143,8 +2113,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
struct extent_buffer *eb;
int slot;
struct btrfs_dir_item *di;
- int name_len;
- char *name;
+ struct fscrypt_str name;
struct inode *inode = NULL;
struct btrfs_key location;
@@ -2159,22 +2128,16 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
eb = path->nodes[0];
slot = path->slots[0];
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
- name_len = btrfs_dir_name_len(eb, di);
- name = kmalloc(name_len, GFP_NOFS);
- if (!name) {
- ret = -ENOMEM;
+ ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name);
+ if (ret)
goto out;
- }
-
- read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len);
if (log) {
struct btrfs_dir_item *log_di;
log_di = btrfs_lookup_dir_index_item(trans, log, log_path,
dir_key->objectid,
- dir_key->offset,
- name, name_len, 0);
+ dir_key->offset, &name, 0);
if (IS_ERR(log_di)) {
ret = PTR_ERR(log_di);
goto out;
@@ -2200,7 +2163,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
inc_nlink(inode);
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode),
- name, name_len);
+ &name);
/*
* Unlike dir item keys, dir index keys can only have one name (entry) in
* them, as there are no key collisions since each key has a unique offset
@@ -2209,7 +2172,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
out:
btrfs_release_path(path);
btrfs_release_path(log_path);
- kfree(name);
+ kfree(name.name);
iput(inode);
return ret;
}
@@ -2430,13 +2393,17 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
struct walk_control *wc, u64 gen, int level)
{
int nritems;
+ struct btrfs_tree_parent_check check = {
+ .transid = gen,
+ .level = level
+ };
struct btrfs_path *path;
struct btrfs_root *root = wc->replay_dest;
struct btrfs_key key;
int i;
int ret;
- ret = btrfs_read_extent_buffer(eb, gen, level, NULL);
+ ret = btrfs_read_extent_buffer(eb, &check);
if (ret)
return ret;
@@ -2616,7 +2583,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
int ret = 0;
while (*level > 0) {
- struct btrfs_key first_key;
+ struct btrfs_tree_parent_check check = { 0 };
cur = path->nodes[*level];
@@ -2628,7 +2595,10 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
- btrfs_node_key_to_cpu(cur, &first_key, path->slots[*level]);
+ check.transid = ptr_gen;
+ check.level = *level - 1;
+ check.has_first_key = true;
+ btrfs_node_key_to_cpu(cur, &check.first_key, path->slots[*level]);
blocksize = fs_info->nodesize;
next = btrfs_find_create_tree_block(fs_info, bytenr,
@@ -2647,8 +2617,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
path->slots[*level]++;
if (wc->free) {
- ret = btrfs_read_extent_buffer(next, ptr_gen,
- *level - 1, &first_key);
+ ret = btrfs_read_extent_buffer(next, &check);
if (ret) {
free_extent_buffer(next);
return ret;
@@ -2676,7 +2645,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
free_extent_buffer(next);
continue;
}
- ret = btrfs_read_extent_buffer(next, ptr_gen, *level - 1, &first_key);
+ ret = btrfs_read_extent_buffer(next, &check);
if (ret) {
free_extent_buffer(next);
return ret;
@@ -3448,7 +3417,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans,
struct btrfs_root *log,
struct btrfs_path *path,
u64 dir_ino,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
u64 index)
{
struct btrfs_dir_item *di;
@@ -3458,7 +3427,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans,
* for dir item keys.
*/
di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino,
- index, name, name_len, -1);
+ index, name, -1);
if (IS_ERR(di))
return PTR_ERR(di);
else if (!di)
@@ -3495,7 +3464,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans,
*/
void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_inode *dir, u64 index)
{
struct btrfs_path *path;
@@ -3522,7 +3491,7 @@ void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
}
ret = del_logged_dentry(trans, root->log_root, path, btrfs_ino(dir),
- name, name_len, index);
+ name, index);
btrfs_free_path(path);
out_unlock:
mutex_unlock(&dir->log_mutex);
@@ -3534,7 +3503,7 @@ out_unlock:
/* see comments for btrfs_del_dir_entries_in_log */
void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_inode *inode, u64 dirid)
{
struct btrfs_root *log;
@@ -3555,7 +3524,7 @@ void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
log = root->log_root;
mutex_lock(&inode->log_mutex);
- ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode),
+ ret = btrfs_del_inode_ref(trans, log, name, btrfs_ino(inode),
dirid, &index);
mutex_unlock(&inode->log_mutex);
if (ret < 0 && ret != -ENOENT)
@@ -3694,15 +3663,29 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
u64 *last_old_dentry_offset)
{
struct btrfs_root *log = inode->root->log_root;
- struct extent_buffer *src = path->nodes[0];
- const int nritems = btrfs_header_nritems(src);
+ struct extent_buffer *src;
+ const int nritems = btrfs_header_nritems(path->nodes[0]);
const u64 ino = btrfs_ino(inode);
bool last_found = false;
int batch_start = 0;
int batch_size = 0;
int i;
- for (i = path->slots[0]; i < nritems; i++) {
+ /*
+ * We need to clone the leaf, release the read lock on it, and use the
+ * clone before modifying the log tree. See the comment at copy_items()
+ * about why we need to do this.
+ */
+ src = btrfs_clone_extent_buffer(path->nodes[0]);
+ if (!src)
+ return -ENOMEM;
+
+ i = path->slots[0];
+ btrfs_release_path(path);
+ path->nodes[0] = src;
+ path->slots[0] = i;
+
+ for (; i < nritems; i++) {
struct btrfs_dir_item *di;
struct btrfs_key key;
int ret;
@@ -4303,7 +4286,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
{
struct btrfs_root *log = inode->root->log_root;
struct btrfs_file_extent_item *extent;
- struct extent_buffer *src = src_path->nodes[0];
+ struct extent_buffer *src;
int ret = 0;
struct btrfs_key *ins_keys;
u32 *ins_sizes;
@@ -4314,6 +4297,43 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
const bool skip_csum = (inode->flags & BTRFS_INODE_NODATASUM);
const u64 i_size = i_size_read(&inode->vfs_inode);
+ /*
+ * To keep lockdep happy and avoid deadlocks, clone the source leaf and
+ * use the clone. This is because otherwise we would be changing the log
+ * tree, to insert items from the subvolume tree or insert csum items,
+ * while holding a read lock on a leaf from the subvolume tree, which
+ * creates a nasty lock dependency when COWing log tree nodes/leaves:
+ *
+ * 1) Modifying the log tree triggers an extent buffer allocation while
+ * holding a write lock on a parent extent buffer from the log tree.
+ * Allocating the pages for an extent buffer, or the extent buffer
+ * struct, can trigger inode eviction and finally the inode eviction
+ * will trigger a release/remove of a delayed node, which requires
+ * taking the delayed node's mutex;
+ *
+ * 2) Allocating a metadata extent for a log tree can trigger the async
+ * reclaim thread and make us wait for it to release enough space and
+ * unblock our reservation ticket. The reclaim thread can start
+ * flushing delayed items, and that in turn results in the need to
+ * lock delayed node mutexes and in the need to write lock extent
+ * buffers of a subvolume tree - all this while holding a write lock
+ * on the parent extent buffer in the log tree.
+ *
+ * So one task in scenario 1) running in parallel with another task in
+ * scenario 2) could lead to a deadlock, one wanting to lock a delayed
+ * node mutex while having a read lock on a leaf from the subvolume,
+ * while the other is holding the delayed node's mutex and wants to
+ * write lock the same subvolume leaf for flushing delayed items.
+ */
+ src = btrfs_clone_extent_buffer(src_path->nodes[0]);
+ if (!src)
+ return -ENOMEM;
+
+ i = src_path->slots[0];
+ btrfs_release_path(src_path);
+ src_path->nodes[0] = src;
+ src_path->slots[0] = i;
+
ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
nr * sizeof(u32), GFP_NOFS);
if (!ins_data)
@@ -4400,9 +4420,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
csum_root = btrfs_csum_root(trans->fs_info, disk_bytenr);
disk_bytenr += extent_offset;
- ret = btrfs_lookup_csums_range(csum_root, disk_bytenr,
- disk_bytenr + extent_num_bytes - 1,
- &ordered_sums, 0, false);
+ ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
+ disk_bytenr + extent_num_bytes - 1,
+ &ordered_sums, 0, false);
if (ret)
goto out;
@@ -4595,10 +4615,9 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
/* block start is already adjusted for the file extent offset. */
csum_root = btrfs_csum_root(trans->fs_info, em->block_start);
- ret = btrfs_lookup_csums_range(csum_root,
- em->block_start + csum_offset,
- em->block_start + csum_offset +
- csum_len - 1, &ordered_sums, 0, false);
+ ret = btrfs_lookup_csums_list(csum_root, em->block_start + csum_offset,
+ em->block_start + csum_offset +
+ csum_len - 1, &ordered_sums, 0, false);
if (ret)
return ret;
@@ -5218,6 +5237,7 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb,
u32 this_len;
unsigned long name_ptr;
struct btrfs_dir_item *di;
+ struct fscrypt_str name_str;
if (key->type == BTRFS_INODE_REF_KEY) {
struct btrfs_inode_ref *iref;
@@ -5251,8 +5271,11 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb,
}
read_extent_buffer(eb, name, name_ptr, this_name_len);
+
+ name_str.name = name;
+ name_str.len = this_name_len;
di = btrfs_lookup_dir_item(NULL, inode->root, search_path,
- parent, name, this_name_len, 0);
+ parent, &name_str, 0);
if (di && !IS_ERR(di)) {
struct btrfs_key di_key;
@@ -5359,7 +5382,7 @@ struct btrfs_dir_list {
* has a size that doesn't match the sum of the lengths of all the logged
* names - this is ok, not a problem, because at log replay time we set the
* directory's i_size to the correct value (see replay_one_name() and
- * do_overwrite_item()).
+ * overwrite_item()).
*/
static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
struct btrfs_inode *start_inode,
@@ -5422,7 +5445,7 @@ again:
}
di = btrfs_item_ptr(leaf, i, struct btrfs_dir_item);
- type = btrfs_dir_type(leaf, di);
+ type = btrfs_dir_ftype(leaf, di);
if (btrfs_dir_transid(leaf, di) < trans->transid)
continue;
btrfs_dir_item_key_to_cpu(leaf, di, &di_key);
@@ -5437,7 +5460,7 @@ again:
}
if (!need_log_inode(trans, BTRFS_I(di_inode))) {
- btrfs_add_delayed_iput(di_inode);
+ btrfs_add_delayed_iput(BTRFS_I(di_inode));
break;
}
@@ -5446,7 +5469,7 @@ again:
log_mode = LOG_INODE_ALL;
ret = btrfs_log_inode(trans, BTRFS_I(di_inode),
log_mode, ctx);
- btrfs_add_delayed_iput(di_inode);
+ btrfs_add_delayed_iput(BTRFS_I(di_inode));
if (ret)
goto out;
if (ctx->log_new_dentries) {
@@ -5640,11 +5663,11 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
* so that the log ends up with the new name and without the old name.
*/
if (!need_log_inode(trans, BTRFS_I(inode))) {
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
return 0;
}
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
ino_elem = kmalloc(sizeof(*ino_elem), GFP_NOFS);
if (!ino_elem)
@@ -5719,7 +5742,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
*/
ret = btrfs_log_inode(trans, BTRFS_I(inode),
LOG_INODE_ALL, ctx);
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
if (ret)
break;
continue;
@@ -5736,7 +5759,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
* that, we can avoid doing it again.
*/
if (!need_log_inode(trans, BTRFS_I(inode))) {
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
continue;
}
@@ -5748,7 +5771,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
* log with the new name before we unpin it.
*/
ret = btrfs_log_inode(trans, BTRFS_I(inode), LOG_INODE_EXISTS, ctx);
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
if (ret)
break;
}
@@ -6258,11 +6281,11 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
}
if (!need_log_inode(trans, BTRFS_I(di_inode))) {
- btrfs_add_delayed_iput(di_inode);
+ btrfs_add_delayed_iput(BTRFS_I(di_inode));
continue;
}
- if (btrfs_stack_dir_type(dir_item) == BTRFS_FT_DIR)
+ if (btrfs_stack_dir_ftype(dir_item) == BTRFS_FT_DIR)
log_mode = LOG_INODE_ALL;
ctx->log_new_dentries = false;
@@ -6271,7 +6294,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
if (!ret && ctx->log_new_dentries)
ret = log_new_dir_dentries(trans, BTRFS_I(di_inode), ctx);
- btrfs_add_delayed_iput(di_inode);
+ btrfs_add_delayed_iput(BTRFS_I(di_inode));
if (ret)
break;
@@ -6732,7 +6755,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
}
if (!need_log_inode(trans, BTRFS_I(dir_inode))) {
- btrfs_add_delayed_iput(dir_inode);
+ btrfs_add_delayed_iput(BTRFS_I(dir_inode));
continue;
}
@@ -6742,7 +6765,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
if (!ret && ctx->log_new_dentries)
ret = log_new_dir_dentries(trans,
BTRFS_I(dir_inode), ctx);
- btrfs_add_delayed_iput(dir_inode);
+ btrfs_add_delayed_iput(BTRFS_I(dir_inode));
if (ret)
goto out;
}
@@ -6787,7 +6810,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
need_log_inode(trans, BTRFS_I(inode)))
ret = btrfs_log_inode(trans, BTRFS_I(inode),
LOG_INODE_EXISTS, ctx);
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(BTRFS_I(inode));
if (ret)
return ret;
@@ -7349,7 +7372,7 @@ void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans,
mutex_unlock(&dir->log_mutex);
}
-/**
+/*
* Update the log after adding a new name for an inode.
*
* @trans: Transaction handle.
@@ -7416,9 +7439,14 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans,
if (old_dir && old_dir->logged_trans == trans->transid) {
struct btrfs_root *log = old_dir->root->log_root;
struct btrfs_path *path;
+ struct fscrypt_name fname;
ASSERT(old_dir_index >= BTRFS_DIR_START_INDEX);
+ ret = fscrypt_setup_filename(&old_dir->vfs_inode,
+ &old_dentry->d_name, 0, &fname);
+ if (ret)
+ goto out;
/*
* We have two inodes to update in the log, the old directory and
* the inode that got renamed, so we must pin the log to prevent
@@ -7438,6 +7466,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
+ fscrypt_free_filename(&fname);
goto out;
}
@@ -7453,8 +7482,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans,
*/
mutex_lock(&old_dir->log_mutex);
ret = del_logged_dentry(trans, log, path, btrfs_ino(old_dir),
- old_dentry->d_name.name,
- old_dentry->d_name.len, old_dir_index);
+ &fname.disk_name, old_dir_index);
if (ret > 0) {
/*
* The dentry does not exist in the log, so record its
@@ -7468,6 +7496,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans,
mutex_unlock(&old_dir->log_mutex);
btrfs_free_path(path);
+ fscrypt_free_filename(&fname);
if (ret < 0)
goto out;
}
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index aed1e05e9879..85b43075ac58 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -6,6 +6,7 @@
#ifndef BTRFS_TREE_LOG_H
#define BTRFS_TREE_LOG_H
+#include "messages.h"
#include "ctree.h"
#include "transaction.h"
@@ -86,11 +87,11 @@ int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_log_ctx *ctx);
void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_inode *dir, u64 index);
void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- const char *name, int name_len,
+ const struct fscrypt_str *name,
struct btrfs_inode *inode, u64 dirid);
void btrfs_end_log_trans(struct btrfs_root *root);
void btrfs_pin_log_trans(struct btrfs_root *root);
diff --git a/fs/btrfs/tree-mod-log.c b/fs/btrfs/tree-mod-log.c
index 8a3a14686d3e..a555baa0143a 100644
--- a/fs/btrfs/tree-mod-log.c
+++ b/fs/btrfs/tree-mod-log.c
@@ -1,7 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
+#include "messages.h"
#include "tree-mod-log.h"
#include "disk-io.h"
+#include "fs.h"
+#include "accessors.h"
+#include "tree-checker.h"
struct tree_mod_root {
u64 logical;
@@ -197,12 +201,11 @@ static inline bool tree_mod_need_log(const struct btrfs_fs_info *fs_info,
static struct tree_mod_elem *alloc_tree_mod_elem(struct extent_buffer *eb,
int slot,
- enum btrfs_mod_log_op op,
- gfp_t flags)
+ enum btrfs_mod_log_op op)
{
struct tree_mod_elem *tm;
- tm = kzalloc(sizeof(*tm), flags);
+ tm = kzalloc(sizeof(*tm), GFP_NOFS);
if (!tm)
return NULL;
@@ -220,7 +223,7 @@ static struct tree_mod_elem *alloc_tree_mod_elem(struct extent_buffer *eb,
}
int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot,
- enum btrfs_mod_log_op op, gfp_t flags)
+ enum btrfs_mod_log_op op)
{
struct tree_mod_elem *tm;
int ret;
@@ -228,7 +231,7 @@ int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot,
if (!tree_mod_need_log(eb->fs_info, eb))
return 0;
- tm = alloc_tree_mod_elem(eb, slot, op, flags);
+ tm = alloc_tree_mod_elem(eb, slot, op);
if (!tm)
return -ENOMEM;
@@ -276,7 +279,7 @@ int btrfs_tree_mod_log_insert_move(struct extent_buffer *eb,
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot,
- BTRFS_MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REMOVE_WHILE_MOVING);
if (!tm_list[i]) {
ret = -ENOMEM;
goto free_tms;
@@ -364,7 +367,7 @@ int btrfs_tree_mod_log_insert_root(struct extent_buffer *old_root,
}
for (i = 0; i < nritems; i++) {
tm_list[i] = alloc_tree_mod_elem(old_root, i,
- BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING);
if (!tm_list[i]) {
ret = -ENOMEM;
goto free_tms;
@@ -502,14 +505,14 @@ int btrfs_tree_mod_log_eb_copy(struct extent_buffer *dst,
tm_list_rem = tm_list + nr_items;
for (i = 0; i < nr_items; i++) {
tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset,
- BTRFS_MOD_LOG_KEY_REMOVE, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REMOVE);
if (!tm_list_rem[i]) {
ret = -ENOMEM;
goto free_tms;
}
tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset,
- BTRFS_MOD_LOG_KEY_ADD, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_ADD);
if (!tm_list_add[i]) {
ret = -ENOMEM;
goto free_tms;
@@ -564,7 +567,7 @@ int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb)
for (i = 0; i < nritems; i++) {
tm_list[i] = alloc_tree_mod_elem(eb, i,
- BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
+ BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING);
if (!tm_list[i]) {
ret = -ENOMEM;
goto free_tms;
@@ -694,8 +697,8 @@ static void tree_mod_log_rewind(struct btrfs_fs_info *fs_info,
n--;
break;
case BTRFS_MOD_LOG_MOVE_KEYS:
- o_dst = btrfs_node_key_ptr_offset(tm->slot);
- o_src = btrfs_node_key_ptr_offset(tm->move.dst_slot);
+ o_dst = btrfs_node_key_ptr_offset(eb, tm->slot);
+ o_src = btrfs_node_key_ptr_offset(eb, tm->move.dst_slot);
memmove_extent_buffer(eb, o_dst, o_src,
tm->move.nr_items * p_size);
break;
@@ -819,10 +822,15 @@ struct extent_buffer *btrfs_get_old_root(struct btrfs_root *root, u64 time_seq)
tm = tree_mod_log_search(fs_info, logical, time_seq);
if (old_root && tm && tm->op != BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
+ struct btrfs_tree_parent_check check = { 0 };
+
btrfs_tree_read_unlock(eb_root);
free_extent_buffer(eb_root);
- old = read_tree_block(fs_info, logical, root->root_key.objectid,
- 0, level, NULL);
+
+ check.level = level;
+ check.owner_root = root->root_key.objectid;
+
+ old = read_tree_block(fs_info, logical, &check);
if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) {
if (!IS_ERR(old))
free_extent_buffer(old);
diff --git a/fs/btrfs/tree-mod-log.h b/fs/btrfs/tree-mod-log.h
index 12605d19621b..94f10afeee97 100644
--- a/fs/btrfs/tree-mod-log.h
+++ b/fs/btrfs/tree-mod-log.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef BTRFS_TREE_MOD_LOG_H
#define BTRFS_TREE_MOD_LOG_H
@@ -32,7 +32,7 @@ int btrfs_tree_mod_log_insert_root(struct extent_buffer *old_root,
struct extent_buffer *new_root,
bool log_removal);
int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot,
- enum btrfs_mod_log_op op, gfp_t flags);
+ enum btrfs_mod_log_op op);
int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb);
struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
index 3374c9e9be67..33606025513d 100644
--- a/fs/btrfs/ulist.c
+++ b/fs/btrfs/ulist.c
@@ -5,6 +5,7 @@
*/
#include <linux/slab.h>
+#include "messages.h"
#include "ulist.h"
#include "ctree.h"
@@ -37,8 +38,9 @@
* loop would be similar to the above.
*/
-/**
- * ulist_init - freshly initialize a ulist
+/*
+ * Freshly initialize a ulist.
+ *
* @ulist: the ulist to initialize
*
* Note: don't use this function to init an already used ulist, use
@@ -51,8 +53,9 @@ void ulist_init(struct ulist *ulist)
ulist->nnodes = 0;
}
-/**
- * ulist_release - free up additionally allocated memory for the ulist
+/*
+ * Free up additionally allocated memory for the ulist.
+ *
* @ulist: the ulist from which to free the additional memory
*
* This is useful in cases where the base 'struct ulist' has been statically
@@ -70,8 +73,9 @@ void ulist_release(struct ulist *ulist)
INIT_LIST_HEAD(&ulist->nodes);
}
-/**
- * ulist_reinit - prepare a ulist for reuse
+/*
+ * Prepare a ulist for reuse.
+ *
* @ulist: ulist to be reused
*
* Free up all additional memory allocated for the list elements and reinit
@@ -83,8 +87,9 @@ void ulist_reinit(struct ulist *ulist)
ulist_init(ulist);
}
-/**
- * ulist_alloc - dynamically allocate a ulist
+/*
+ * Dynamically allocate a ulist.
+ *
* @gfp_mask: allocation flags to for base allocation
*
* The allocated ulist will be returned in an initialized state.
@@ -101,8 +106,9 @@ struct ulist *ulist_alloc(gfp_t gfp_mask)
return ulist;
}
-/**
- * ulist_free - free dynamically allocated ulist
+/*
+ * Free dynamically allocated ulist.
+ *
* @ulist: ulist to free
*
* It is not necessary to call ulist_release before.
@@ -163,8 +169,9 @@ static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins)
return 0;
}
-/**
- * ulist_add - add an element to the ulist
+/*
+ * Add an element to the ulist.
+ *
* @ulist: ulist to add the element to
* @val: value to add to ulist
* @aux: auxiliary value to store along with val
@@ -242,8 +249,9 @@ int ulist_del(struct ulist *ulist, u64 val, u64 aux)
return 0;
}
-/**
- * ulist_next - iterate ulist
+/*
+ * Iterate ulist.
+ *
* @ulist: ulist to iterate
* @uiter: iterator variable, initialized with ULIST_ITER_INIT(&iterator)
*
@@ -258,7 +266,7 @@ int ulist_del(struct ulist *ulist, u64 val, u64 aux)
* It is allowed to call ulist_add during an enumeration. Newly added items
* are guaranteed to show up in the running enumeration.
*/
-struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter)
+struct ulist_node *ulist_next(const struct ulist *ulist, struct ulist_iterator *uiter)
{
struct ulist_node *node;
diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
index 02fda0a2d4ce..b2cef187ea8e 100644
--- a/fs/btrfs/ulist.h
+++ b/fs/btrfs/ulist.h
@@ -66,7 +66,7 @@ static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux,
#endif
}
-struct ulist_node *ulist_next(struct ulist *ulist,
+struct ulist_node *ulist_next(const struct ulist *ulist,
struct ulist_iterator *uiter);
#define ULIST_ITER_INIT(uiter) ((uiter)->cur_list = NULL)
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c
index b458452a1aaf..7c7001f42b14 100644
--- a/fs/btrfs/uuid-tree.c
+++ b/fs/btrfs/uuid-tree.c
@@ -5,11 +5,14 @@
#include <linux/uuid.h>
#include <asm/unaligned.h>
+#include "messages.h"
#include "ctree.h"
#include "transaction.h"
#include "disk-io.h"
#include "print-tree.h"
-
+#include "fs.h"
+#include "accessors.h"
+#include "uuid-tree.h"
static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key)
{
diff --git a/fs/btrfs/uuid-tree.h b/fs/btrfs/uuid-tree.h
new file mode 100644
index 000000000000..5350c87fe2ca
--- /dev/null
+++ b/fs/btrfs/uuid-tree.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_UUID_TREE_H
+#define BTRFS_UUID_TREE_H
+
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
+ u64 subid);
+int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
+ u64 subid);
+int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info);
+
+#endif
diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c
index ee00e33c309e..bf9eb693a6a7 100644
--- a/fs/btrfs/verity.c
+++ b/fs/btrfs/verity.c
@@ -10,11 +10,17 @@
#include <linux/iversion.h>
#include <linux/fsverity.h>
#include <linux/sched/mm.h>
+#include "messages.h"
#include "ctree.h"
#include "btrfs_inode.h"
#include "transaction.h"
#include "disk-io.h"
#include "locking.h"
+#include "fs.h"
+#include "accessors.h"
+#include "ioctl.h"
+#include "verity.h"
+#include "orphan.h"
/*
* Implementation of the interface defined in struct fsverity_operations.
diff --git a/fs/btrfs/verity.h b/fs/btrfs/verity.h
new file mode 100644
index 000000000000..91c10f7d0a46
--- /dev/null
+++ b/fs/btrfs/verity.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_VERITY_H
+#define BTRFS_VERITY_H
+
+#ifdef CONFIG_FS_VERITY
+
+extern const struct fsverity_operations btrfs_verityops;
+
+int btrfs_drop_verity_items(struct btrfs_inode *inode);
+int btrfs_get_verity_descriptor(struct inode *inode, void *buf, size_t buf_size);
+
+#else
+
+static inline int btrfs_drop_verity_items(struct btrfs_inode *inode)
+{
+ return 0;
+}
+
+static inline int btrfs_get_verity_descriptor(struct inode *inode, void *buf,
+ size_t buf_size)
+{
+ return -EPERM;
+}
+
+#endif
+
+#endif
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a8d4bc6a1937..aa25fa335d3e 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -5,12 +5,9 @@
#include <linux/sched.h>
#include <linux/sched/mm.h>
-#include <linux/bio.h>
#include <linux/slab.h>
-#include <linux/blkdev.h>
#include <linux/ratelimit.h>
#include <linux/kthread.h>
-#include <linux/raid/pq.h>
#include <linux/semaphore.h>
#include <linux/uuid.h>
#include <linux/list_sort.h>
@@ -23,8 +20,6 @@
#include "print-tree.h"
#include "volumes.h"
#include "raid56.h"
-#include "async-thread.h"
-#include "check-integrity.h"
#include "rcu-string.h"
#include "dev-replace.h"
#include "sysfs.h"
@@ -33,8 +28,13 @@
#include "block-group.h"
#include "discard.h"
#include "zoned.h"
-
-static struct bio_set btrfs_bioset;
+#include "fs.h"
+#include "accessors.h"
+#include "uuid-tree.h"
+#include "ioctl.h"
+#include "relocation.h"
+#include "scrub.h"
+#include "super.h"
#define BTRFS_BLOCK_GROUP_STRIPE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \
BTRFS_BLOCK_GROUP_RAID10 | \
@@ -248,11 +248,6 @@ out_overflow:;
static int init_first_rw_device(struct btrfs_trans_handle *trans);
static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info);
static void btrfs_dev_stat_print_on_load(struct btrfs_device *device);
-static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
- enum btrfs_map_op op, u64 logical, u64 *length,
- struct btrfs_io_context **bioc_ret,
- struct btrfs_io_stripe *smap,
- int *mirror_num_ret, int need_raid_map);
/*
* Device locking
@@ -529,14 +524,14 @@ error:
return ret;
}
-/**
- * Search and remove all stale devices (which are not mounted).
- * When both inputs are NULL, it will search and release all stale devices.
+/*
+ * Search and remove all stale devices (which are not mounted). When both
+ * inputs are NULL, it will search and release all stale devices.
*
- * @devt: Optional. When provided will it release all unmounted devices
- * matching this devt only.
+ * @devt: Optional. When provided will it release all unmounted devices
+ * matching this devt only.
* @skip_device: Optional. Will skip this device when searching for the stale
- * devices.
+ * devices.
*
* Return: 0 for success or if @devt is 0.
* -EBUSY if @devt is a mounted device.
@@ -641,6 +636,9 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
if (!bdev_nonrot(bdev))
fs_devices->rotating = true;
+ if (bdev_max_discard_sectors(bdev))
+ fs_devices->discardable = true;
+
device->bdev = bdev;
clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
device->mode = flags;
@@ -835,26 +833,23 @@ static noinline struct btrfs_device *device_list_add(const char *path,
}
if (!device) {
+ unsigned int nofs_flag;
+
if (fs_devices->opened) {
mutex_unlock(&fs_devices->device_list_mutex);
return ERR_PTR(-EBUSY);
}
+ nofs_flag = memalloc_nofs_save();
device = btrfs_alloc_device(NULL, &devid,
- disk_super->dev_item.uuid);
+ disk_super->dev_item.uuid, path);
+ memalloc_nofs_restore(nofs_flag);
if (IS_ERR(device)) {
mutex_unlock(&fs_devices->device_list_mutex);
/* we can safely leave the fs_devices entry around */
return device;
}
- name = rcu_string_strdup(path, GFP_NOFS);
- if (!name) {
- btrfs_free_device(device);
- mutex_unlock(&fs_devices->device_list_mutex);
- return ERR_PTR(-ENOMEM);
- }
- rcu_assign_pointer(device->name, name);
device->devt = path_devt;
list_add_rcu(&device->dev_list, &fs_devices->devices);
@@ -934,7 +929,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
}
btrfs_info_in_rcu(NULL,
"devid %llu device path %s changed to %s scanned by %s (%d)",
- devid, rcu_str_deref(device->name),
+ devid, btrfs_dev_name(device),
path, current->comm,
task_pid_nr(current));
}
@@ -987,28 +982,32 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
fs_devices->total_devices = orig->total_devices;
list_for_each_entry(orig_dev, &orig->devices, dev_list) {
- struct rcu_string *name;
+ const char *dev_path = NULL;
+
+ /*
+ * This is ok to do without RCU read locked because we hold the
+ * uuid mutex so nothing we touch in here is going to disappear.
+ */
+ if (orig_dev->name)
+ dev_path = orig_dev->name->str;
device = btrfs_alloc_device(NULL, &orig_dev->devid,
- orig_dev->uuid);
+ orig_dev->uuid, dev_path);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
goto error;
}
- /*
- * This is ok to do without rcu read locked because we hold the
- * uuid mutex so nothing we touch in here is going to disappear.
- */
- if (orig_dev->name) {
- name = rcu_string_strdup(orig_dev->name->str,
- GFP_KERNEL);
- if (!name) {
+ if (orig_dev->zone_info) {
+ struct btrfs_zoned_device_info *zone_info;
+
+ zone_info = btrfs_clone_dev_zone_info(orig_dev);
+ if (!zone_info) {
btrfs_free_device(device);
ret = -ENOMEM;
goto error;
}
- rcu_assign_pointer(device->name, name);
+ device->zone_info = zone_info;
}
list_add(&device->dev_list, &fs_devices->devices);
@@ -1461,8 +1460,9 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device,
return changed;
}
-/**
- * dev_extent_hole_check - check if specified hole is suitable for allocation
+/*
+ * Check if specified hole is suitable for allocation.
+ *
* @device: the device which we have the hole
* @hole_start: starting position of the hole
* @hole_size: the size of the hole
@@ -1516,7 +1516,8 @@ static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
}
/*
- * find_free_dev_extent_start - find free space in the specified device
+ * Find free space in the specified device.
+ *
* @device: the device which we search the free space in
* @num_bytes: the size of the free space that we need
* @search_start: the position from which to begin the search
@@ -1524,9 +1525,8 @@ static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
* @len: the size of the free space. that we find, or the size
* of the max free space if we don't find suitable free space
*
- * this uses a pretty simple search, the expectation is that it is
- * called very infrequently and that a given device has a small number
- * of extents
+ * This does a pretty simple search, the expectation is that it is called very
+ * infrequently and that a given device has a small number of extents.
*
* @start is used to store the start of the free space if we find. But if we
* don't find suitable free space, it will be used to store the start position
@@ -2089,7 +2089,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
if (btrfs_pinned_by_swapfile(fs_info, device)) {
btrfs_warn_in_rcu(fs_info,
"cannot remove device %s (devid %llu) due to active swapfile",
- rcu_str_deref(device->name), device->devid);
+ btrfs_dev_name(device), device->devid);
return -ETXTBSY;
}
@@ -2305,8 +2305,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
btrfs_free_device(tgtdev);
}
-/**
- * Populate args from device at path
+/*
+ * Populate args from device at path.
*
* @fs_info: the filesystem
* @args: the args to populate
@@ -2581,7 +2581,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
struct btrfs_device *device;
struct block_device *bdev;
struct super_block *sb = fs_info->sb;
- struct rcu_string *name;
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
struct btrfs_fs_devices *seed_devices;
u64 orig_super_total_bytes;
@@ -2622,20 +2621,13 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
}
rcu_read_unlock();
- device = btrfs_alloc_device(fs_info, NULL, NULL);
+ device = btrfs_alloc_device(fs_info, NULL, NULL, device_path);
if (IS_ERR(device)) {
/* we can safely leave the fs_devices entry around */
ret = PTR_ERR(device);
goto error;
}
- name = rcu_string_strdup(device_path, GFP_KERNEL);
- if (!name) {
- ret = -ENOMEM;
- goto error_free_device;
- }
- rcu_assign_pointer(device->name, name);
-
device->fs_info = fs_info;
device->bdev = bdev;
ret = lookup_bdev(device_path, &device->devt);
@@ -3591,16 +3583,14 @@ static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_off
if (bargs->usage_min == 0)
user_thresh_min = 0;
else
- user_thresh_min = div_factor_fine(cache->length,
- bargs->usage_min);
+ user_thresh_min = mult_perc(cache->length, bargs->usage_min);
if (bargs->usage_max == 0)
user_thresh_max = 1;
else if (bargs->usage_max > 100)
user_thresh_max = cache->length;
else
- user_thresh_max = div_factor_fine(cache->length,
- bargs->usage_max);
+ user_thresh_max = mult_perc(cache->length, bargs->usage_max);
if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max)
ret = 0;
@@ -3624,7 +3614,7 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info,
else if (bargs->usage > 100)
user_thresh = cache->length;
else
- user_thresh = div_factor_fine(cache->length, bargs->usage);
+ user_thresh = mult_perc(cache->length, bargs->usage);
if (chunk_used < user_thresh)
ret = 0;
@@ -4014,10 +4004,11 @@ error:
return ret;
}
-/**
- * alloc_profile_is_valid - see if a given profile is valid and reduced
- * @flags: profile to validate
- * @extended: if true @flags is treated as an extended profile
+/*
+ * See if a given profile is valid and reduced.
+ *
+ * @flags: profile to validate
+ * @extended: if true @flags is treated as an extended profile
*/
static int alloc_profile_is_valid(u64 flags, int extended)
{
@@ -5089,7 +5080,7 @@ static void init_alloc_chunk_ctl_policy_regular(
ctl->devs_max = min_t(int, ctl->devs_max, BTRFS_MAX_DEVS_SYS_CHUNK);
/* We don't want a chunk larger than 10% of writable space */
- ctl->max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
+ ctl->max_chunk_size = min(mult_perc(fs_devices->total_rw_bytes, 10),
ctl->max_chunk_size);
ctl->dev_extent_min = BTRFS_STRIPE_LEN * ctl->dev_stripes;
}
@@ -5120,7 +5111,7 @@ static void init_alloc_chunk_ctl_policy_zoned(
}
/* We don't want a chunk larger than 10% of writable space */
- limit = max(round_down(div_factor(fs_devices->total_rw_bytes, 1),
+ limit = max(round_down(mult_perc(fs_devices->total_rw_bytes, 10),
zone_size),
min_chunk_size);
ctl->max_chunk_size = min(limit, ctl->max_chunk_size);
@@ -5896,7 +5887,10 @@ static struct btrfs_io_context *alloc_btrfs_io_context(struct btrfs_fs_info *fs_
* and the stripes.
*/
sizeof(u64) * (total_stripes),
- GFP_NOFS|__GFP_NOFAIL);
+ GFP_NOFS);
+
+ if (!bioc)
+ return NULL;
refcount_set(&bioc->refs, 1);
@@ -6358,11 +6352,11 @@ static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
stripe_offset + stripe_nr * map->stripe_len;
}
-static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
- enum btrfs_map_op op, u64 logical, u64 *length,
- struct btrfs_io_context **bioc_ret,
- struct btrfs_io_stripe *smap,
- int *mirror_num_ret, int need_raid_map)
+int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
+ u64 logical, u64 *length,
+ struct btrfs_io_context **bioc_ret,
+ struct btrfs_io_stripe *smap, int *mirror_num_ret,
+ int need_raid_map)
{
struct extent_map *em;
struct map_lookup *map;
@@ -6645,266 +6639,6 @@ int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
NULL, NULL, 1);
}
-/*
- * Initialize a btrfs_bio structure. This skips the embedded bio itself as it
- * is already initialized by the block layer.
- */
-static inline void btrfs_bio_init(struct btrfs_bio *bbio,
- btrfs_bio_end_io_t end_io, void *private)
-{
- memset(bbio, 0, offsetof(struct btrfs_bio, bio));
- bbio->end_io = end_io;
- bbio->private = private;
-}
-
-/*
- * Allocate a btrfs_bio structure. The btrfs_bio is the main I/O container for
- * btrfs, and is used for all I/O submitted through btrfs_submit_bio.
- *
- * Just like the underlying bio_alloc_bioset it will not fail as it is backed by
- * a mempool.
- */
-struct bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
- btrfs_bio_end_io_t end_io, void *private)
-{
- struct bio *bio;
-
- bio = bio_alloc_bioset(NULL, nr_vecs, opf, GFP_NOFS, &btrfs_bioset);
- btrfs_bio_init(btrfs_bio(bio), end_io, private);
- return bio;
-}
-
-struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
- btrfs_bio_end_io_t end_io, void *private)
-{
- struct bio *bio;
- struct btrfs_bio *bbio;
-
- ASSERT(offset <= UINT_MAX && size <= UINT_MAX);
-
- bio = bio_alloc_clone(orig->bi_bdev, orig, GFP_NOFS, &btrfs_bioset);
- bbio = btrfs_bio(bio);
- btrfs_bio_init(bbio, end_io, private);
-
- bio_trim(bio, offset >> 9, size >> 9);
- bbio->iter = bio->bi_iter;
- return bio;
-}
-
-static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
-{
- if (!dev || !dev->bdev)
- return;
- if (bio->bi_status != BLK_STS_IOERR && bio->bi_status != BLK_STS_TARGET)
- return;
-
- if (btrfs_op(bio) == BTRFS_MAP_WRITE)
- btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
- if (!(bio->bi_opf & REQ_RAHEAD))
- btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
- if (bio->bi_opf & REQ_PREFLUSH)
- btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_FLUSH_ERRS);
-}
-
-static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_fs_info *fs_info,
- struct bio *bio)
-{
- if (bio->bi_opf & REQ_META)
- return fs_info->endio_meta_workers;
- return fs_info->endio_workers;
-}
-
-static void btrfs_end_bio_work(struct work_struct *work)
-{
- struct btrfs_bio *bbio =
- container_of(work, struct btrfs_bio, end_io_work);
-
- bbio->end_io(bbio);
-}
-
-static void btrfs_simple_end_io(struct bio *bio)
-{
- struct btrfs_fs_info *fs_info = bio->bi_private;
- struct btrfs_bio *bbio = btrfs_bio(bio);
-
- btrfs_bio_counter_dec(fs_info);
-
- if (bio->bi_status)
- btrfs_log_dev_io_error(bio, bbio->device);
-
- if (bio_op(bio) == REQ_OP_READ) {
- INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
- queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
- } else {
- bbio->end_io(bbio);
- }
-}
-
-static void btrfs_raid56_end_io(struct bio *bio)
-{
- struct btrfs_io_context *bioc = bio->bi_private;
- struct btrfs_bio *bbio = btrfs_bio(bio);
-
- btrfs_bio_counter_dec(bioc->fs_info);
- bbio->mirror_num = bioc->mirror_num;
- bbio->end_io(bbio);
-
- btrfs_put_bioc(bioc);
-}
-
-static void btrfs_orig_write_end_io(struct bio *bio)
-{
- struct btrfs_io_stripe *stripe = bio->bi_private;
- struct btrfs_io_context *bioc = stripe->bioc;
- struct btrfs_bio *bbio = btrfs_bio(bio);
-
- btrfs_bio_counter_dec(bioc->fs_info);
-
- if (bio->bi_status) {
- atomic_inc(&bioc->error);
- btrfs_log_dev_io_error(bio, stripe->dev);
- }
-
- /*
- * Only send an error to the higher layers if it is beyond the tolerance
- * threshold.
- */
- if (atomic_read(&bioc->error) > bioc->max_errors)
- bio->bi_status = BLK_STS_IOERR;
- else
- bio->bi_status = BLK_STS_OK;
-
- bbio->end_io(bbio);
- btrfs_put_bioc(bioc);
-}
-
-static void btrfs_clone_write_end_io(struct bio *bio)
-{
- struct btrfs_io_stripe *stripe = bio->bi_private;
-
- if (bio->bi_status) {
- atomic_inc(&stripe->bioc->error);
- btrfs_log_dev_io_error(bio, stripe->dev);
- }
-
- /* Pass on control to the original bio this one was cloned from */
- bio_endio(stripe->bioc->orig_bio);
- bio_put(bio);
-}
-
-static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio)
-{
- if (!dev || !dev->bdev ||
- test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) ||
- (btrfs_op(bio) == BTRFS_MAP_WRITE &&
- !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state))) {
- bio_io_error(bio);
- return;
- }
-
- bio_set_dev(bio, dev->bdev);
-
- /*
- * For zone append writing, bi_sector must point the beginning of the
- * zone
- */
- if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
- u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;
-
- if (btrfs_dev_is_sequential(dev, physical)) {
- u64 zone_start = round_down(physical,
- dev->fs_info->zone_size);
-
- bio->bi_iter.bi_sector = zone_start >> SECTOR_SHIFT;
- } else {
- bio->bi_opf &= ~REQ_OP_ZONE_APPEND;
- bio->bi_opf |= REQ_OP_WRITE;
- }
- }
- btrfs_debug_in_rcu(dev->fs_info,
- "%s: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u",
- __func__, bio_op(bio), bio->bi_opf, bio->bi_iter.bi_sector,
- (unsigned long)dev->bdev->bd_dev, rcu_str_deref(dev->name),
- dev->devid, bio->bi_iter.bi_size);
-
- btrfsic_check_bio(bio);
- submit_bio(bio);
-}
-
-static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr)
-{
- struct bio *orig_bio = bioc->orig_bio, *bio;
-
- ASSERT(bio_op(orig_bio) != REQ_OP_READ);
-
- /* Reuse the bio embedded into the btrfs_bio for the last mirror */
- if (dev_nr == bioc->num_stripes - 1) {
- bio = orig_bio;
- bio->bi_end_io = btrfs_orig_write_end_io;
- } else {
- bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &fs_bio_set);
- bio_inc_remaining(orig_bio);
- bio->bi_end_io = btrfs_clone_write_end_io;
- }
-
- bio->bi_private = &bioc->stripes[dev_nr];
- bio->bi_iter.bi_sector = bioc->stripes[dev_nr].physical >> SECTOR_SHIFT;
- bioc->stripes[dev_nr].bioc = bioc;
- btrfs_submit_dev_bio(bioc->stripes[dev_nr].dev, bio);
-}
-
-void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num)
-{
- u64 logical = bio->bi_iter.bi_sector << 9;
- u64 length = bio->bi_iter.bi_size;
- u64 map_length = length;
- struct btrfs_io_context *bioc = NULL;
- struct btrfs_io_stripe smap;
- int ret;
-
- btrfs_bio_counter_inc_blocked(fs_info);
- ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
- &bioc, &smap, &mirror_num, 1);
- if (ret) {
- btrfs_bio_counter_dec(fs_info);
- btrfs_bio_end_io(btrfs_bio(bio), errno_to_blk_status(ret));
- return;
- }
-
- if (map_length < length) {
- btrfs_crit(fs_info,
- "mapping failed logical %llu bio len %llu len %llu",
- logical, length, map_length);
- BUG();
- }
-
- if (!bioc) {
- /* Single mirror read/write fast path */
- btrfs_bio(bio)->mirror_num = mirror_num;
- btrfs_bio(bio)->device = smap.dev;
- bio->bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
- bio->bi_private = fs_info;
- bio->bi_end_io = btrfs_simple_end_io;
- btrfs_submit_dev_bio(smap.dev, bio);
- } else if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
- /* Parity RAID write or read recovery */
- bio->bi_private = bioc;
- bio->bi_end_io = btrfs_raid56_end_io;
- if (bio_op(bio) == REQ_OP_READ)
- raid56_parity_recover(bio, bioc, mirror_num);
- else
- raid56_parity_write(bio, bioc);
- } else {
- /* Write to multiple mirrors */
- int total_devs = bioc->num_stripes;
- int dev_nr;
-
- bioc->orig_bio = bio;
- for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
- btrfs_submit_mirrored_bio(bioc, dev_nr);
- }
-}
-
static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,
const struct btrfs_fs_devices *fs_devices)
{
@@ -6918,18 +6652,18 @@ static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,
static bool dev_args_match_device(const struct btrfs_dev_lookup_args *args,
const struct btrfs_device *device)
{
- ASSERT((args->devid != (u64)-1) || args->missing);
+ if (args->missing) {
+ if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state) &&
+ !device->bdev)
+ return true;
+ return false;
+ }
- if ((args->devid != (u64)-1) && device->devid != args->devid)
+ if (device->devid != args->devid)
return false;
if (args->uuid && memcmp(device->uuid, args->uuid, BTRFS_UUID_SIZE) != 0)
return false;
- if (!args->missing)
- return true;
- if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state) &&
- !device->bdev)
- return true;
- return false;
+ return true;
}
/*
@@ -6976,8 +6710,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
* always do NOFS because we use it in a lot of other GFP_KERNEL safe
* places.
*/
+
nofs_flag = memalloc_nofs_save();
- device = btrfs_alloc_device(NULL, &devid, dev_uuid);
+ device = btrfs_alloc_device(NULL, &devid, dev_uuid, NULL);
memalloc_nofs_restore(nofs_flag);
if (IS_ERR(device))
return device;
@@ -6992,22 +6727,24 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
return device;
}
-/**
- * btrfs_alloc_device - allocate struct btrfs_device
+/*
+ * Allocate new device struct, set up devid and UUID.
+ *
* @fs_info: used only for generating a new devid, can be NULL if
* devid is provided (i.e. @devid != NULL).
* @devid: a pointer to devid for this device. If NULL a new devid
* is generated.
* @uuid: a pointer to UUID for this device. If NULL a new UUID
* is generated.
+ * @path: a pointer to device path if available, NULL otherwise.
*
* Return: a pointer to a new &struct btrfs_device on success; ERR_PTR()
* on error. Returned struct is not linked onto any lists and must be
* destroyed with btrfs_free_device.
*/
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
- const u64 *devid,
- const u8 *uuid)
+ const u64 *devid, const u8 *uuid,
+ const char *path)
{
struct btrfs_device *dev;
u64 tmp;
@@ -7025,8 +6762,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
atomic_set(&dev->dev_stats_ccnt, 0);
btrfs_device_data_ordered_init(dev);
- extent_io_tree_init(fs_info, &dev->alloc_state,
- IO_TREE_DEVICE_ALLOC_STATE, NULL);
+ extent_io_tree_init(fs_info, &dev->alloc_state, IO_TREE_DEVICE_ALLOC_STATE);
if (devid)
tmp = *devid;
@@ -7046,6 +6782,17 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
else
generate_random_uuid(dev->uuid);
+ if (path) {
+ struct rcu_string *name;
+
+ name = rcu_string_strdup(path, GFP_KERNEL);
+ if (!name) {
+ btrfs_free_device(dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ rcu_assign_pointer(dev->name, name);
+ }
+
return dev;
}
@@ -7229,8 +6976,9 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
map->stripes[i].dev = handle_missing_device(fs_info,
devid, uuid);
if (IS_ERR(map->stripes[i].dev)) {
+ ret = PTR_ERR(map->stripes[i].dev);
free_extent_map(em);
- return PTR_ERR(map->stripes[i].dev);
+ return ret;
}
}
@@ -7744,10 +7492,11 @@ error:
return ret;
}
-void btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
+int btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
{
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices, *seed_devs;
struct btrfs_device *device;
+ int ret = 0;
fs_devices->fs_info = fs_info;
@@ -7756,12 +7505,18 @@ void btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
device->fs_info = fs_info;
list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
- list_for_each_entry(device, &seed_devs->devices, dev_list)
+ list_for_each_entry(device, &seed_devs->devices, dev_list) {
device->fs_info = fs_info;
+ ret = btrfs_get_dev_zone_info(device, false);
+ if (ret)
+ break;
+ }
seed_devs->fs_info = fs_info;
}
mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
}
static u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
@@ -7885,7 +7640,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
if (ret < 0) {
btrfs_warn_in_rcu(fs_info,
"error %d while searching for dev_stats item for device %s",
- ret, rcu_str_deref(device->name));
+ ret, btrfs_dev_name(device));
goto out;
}
@@ -7896,7 +7651,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
if (ret != 0) {
btrfs_warn_in_rcu(fs_info,
"delete too small dev_stats item for device %s failed %d",
- rcu_str_deref(device->name), ret);
+ btrfs_dev_name(device), ret);
goto out;
}
ret = 1;
@@ -7910,7 +7665,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
if (ret < 0) {
btrfs_warn_in_rcu(fs_info,
"insert dev_stats item for device %s failed %d",
- rcu_str_deref(device->name), ret);
+ btrfs_dev_name(device), ret);
goto out;
}
}
@@ -7975,7 +7730,7 @@ void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index)
return;
btrfs_err_rl_in_rcu(dev->fs_info,
"bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u",
- rcu_str_deref(dev->name),
+ btrfs_dev_name(dev),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
@@ -7995,7 +7750,7 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
btrfs_info_in_rcu(dev->fs_info,
"bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u",
- rcu_str_deref(dev->name),
+ btrfs_dev_name(dev),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
@@ -8414,17 +8169,3 @@ bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical)
return true;
}
-
-int __init btrfs_bioset_init(void)
-{
- if (bioset_init(&btrfs_bioset, BIO_POOL_SIZE,
- offsetof(struct btrfs_bio, bio),
- BIOSET_NEED_BVECS))
- return -ENOMEM;
- return 0;
-}
-
-void __cold btrfs_bioset_exit(void)
-{
- bioset_exit(&btrfs_bioset);
-}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index f8b668dc8bf8..6b7a05f6cf82 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -6,10 +6,12 @@
#ifndef BTRFS_VOLUMES_H
#define BTRFS_VOLUMES_H
-#include <linux/bio.h>
#include <linux/sort.h>
#include <linux/btrfs.h>
#include "async-thread.h"
+#include "messages.h"
+#include "tree-checker.h"
+#include "rcu-string.h"
#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
@@ -354,6 +356,8 @@ struct btrfs_fs_devices {
* nonrot flag set
*/
bool rotating;
+ /* Devices support TRIM/discard commands */
+ bool discardable;
struct btrfs_fs_info *fs_info;
/* sysfs kobjects */
@@ -368,8 +372,6 @@ struct btrfs_fs_devices {
enum btrfs_read_policy read_policy;
};
-#define BTRFS_BIO_INLINE_CSUM_SIZE 64
-
#define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info) \
- sizeof(struct btrfs_chunk)) \
/ sizeof(struct btrfs_stripe) + 1)
@@ -379,89 +381,6 @@ struct btrfs_fs_devices {
- 2 * sizeof(struct btrfs_chunk)) \
/ sizeof(struct btrfs_stripe) + 1)
-/*
- * Maximum number of sectors for a single bio to limit the size of the
- * checksum array. This matches the number of bio_vecs per bio and thus the
- * I/O size for buffered I/O.
- */
-#define BTRFS_MAX_BIO_SECTORS (256)
-
-typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio);
-
-/*
- * Additional info to pass along bio.
- *
- * Mostly for btrfs specific features like csum and mirror_num.
- */
-struct btrfs_bio {
- unsigned int mirror_num;
- struct bvec_iter iter;
-
- /* for direct I/O */
- u64 file_offset;
-
- /* @device is for stripe IO submission. */
- struct btrfs_device *device;
- u8 *csum;
- u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
-
- /* End I/O information supplied to btrfs_bio_alloc */
- btrfs_bio_end_io_t end_io;
- void *private;
-
- /* For read end I/O handling */
- struct work_struct end_io_work;
-
- /*
- * This member must come last, bio_alloc_bioset will allocate enough
- * bytes for entire btrfs_bio but relies on bio being last.
- */
- struct bio bio;
-};
-
-static inline struct btrfs_bio *btrfs_bio(struct bio *bio)
-{
- return container_of(bio, struct btrfs_bio, bio);
-}
-
-int __init btrfs_bioset_init(void);
-void __cold btrfs_bioset_exit(void);
-
-struct bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
- btrfs_bio_end_io_t end_io, void *private);
-struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
- btrfs_bio_end_io_t end_io, void *private);
-
-static inline void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
-{
- bbio->bio.bi_status = status;
- bbio->end_io(bbio);
-}
-
-static inline void btrfs_bio_free_csum(struct btrfs_bio *bbio)
-{
- if (bbio->csum != bbio->csum_inline) {
- kfree(bbio->csum);
- bbio->csum = NULL;
- }
-}
-
-/*
- * Iterate through a btrfs_bio (@bbio) on a per-sector basis.
- *
- * bvl - struct bio_vec
- * bbio - struct btrfs_bio
- * iters - struct bvec_iter
- * bio_offset - unsigned int
- */
-#define btrfs_bio_for_each_sector(fs_info, bvl, bbio, iter, bio_offset) \
- for ((iter) = (bbio)->iter, (bio_offset) = 0; \
- (iter).bi_size && \
- (((bvl) = bio_iter_iovec((&(bbio)->bio), (iter))), 1); \
- (bio_offset) += fs_info->sectorsize, \
- bio_advance_iter_single(&(bbio)->bio, &(iter), \
- (fs_info)->sectorsize))
-
struct btrfs_io_stripe {
struct btrfs_device *dev;
union {
@@ -603,6 +522,13 @@ static inline enum btrfs_map_op btrfs_op(struct bio *bio)
}
}
+static inline unsigned long btrfs_chunk_item_size(int num_stripes)
+{
+ ASSERT(num_stripes);
+ return sizeof(struct btrfs_chunk) +
+ sizeof(struct btrfs_stripe) * (num_stripes - 1);
+}
+
void btrfs_get_bioc(struct btrfs_io_context *bioc);
void btrfs_put_bioc(struct btrfs_io_context *bioc);
int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
@@ -611,6 +537,11 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
u64 logical, u64 *length,
struct btrfs_io_context **bioc_ret);
+int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
+ u64 logical, u64 *length,
+ struct btrfs_io_context **bioc_ret,
+ struct btrfs_io_stripe *smap, int *mirror_num_ret,
+ int need_raid_map);
struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
u64 logical, u64 *length_ret,
u32 *num_stripes);
@@ -622,7 +553,6 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
u64 type);
void btrfs_mapping_tree_free(struct extent_map_tree *tree);
-void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num);
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
fmode_t flags, void *holder);
struct btrfs_device *btrfs_scan_one_device(const char *path,
@@ -639,8 +569,8 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
struct btrfs_dev_lookup_args *args,
const char *path);
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
- const u64 *devid,
- const u8 *uuid);
+ const u64 *devid, const u8 *uuid,
+ const char *path);
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
void btrfs_free_device(struct btrfs_device *device);
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
@@ -671,7 +601,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info,
struct btrfs_ioctl_get_dev_stats *stats);
-void btrfs_init_devices_late(struct btrfs_fs_info *fs_info);
+int btrfs_init_devices_late(struct btrfs_fs_info *fs_info);
int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev);
@@ -741,6 +671,14 @@ static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
atomic_inc(&dev->dev_stats_ccnt);
}
+static inline const char *btrfs_dev_name(const struct btrfs_device *device)
+{
+ if (!device || test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
+ return "<missing disk>";
+ else
+ return rcu_str_deref(device->name);
+}
+
void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
struct list_head * __attribute_const__ btrfs_get_fs_uuids(void);
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 5bb8d8c86311..0ed4b119a7ca 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -13,12 +13,16 @@
#include <linux/iversion.h>
#include <linux/sched/mm.h>
#include "ctree.h"
+#include "fs.h"
+#include "messages.h"
#include "btrfs_inode.h"
#include "transaction.h"
#include "xattr.h"
#include "disk-io.h"
#include "props.h"
#include "locking.h"
+#include "accessors.h"
+#include "dir-item.h"
int btrfs_getxattr(struct inode *inode, const char *name,
void *buffer, size_t size)
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index b4f44662cda7..01a13de11832 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -155,8 +155,8 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
in_page = find_get_page(mapping,
start >> PAGE_SHIFT);
data_in = kmap_local_page(in_page);
- memcpy(workspace->buf + i * PAGE_SIZE,
- data_in, PAGE_SIZE);
+ copy_page(workspace->buf + i * PAGE_SIZE,
+ data_in);
start += PAGE_SIZE;
}
workspace->strm.next_in = workspace->buf;
@@ -355,7 +355,7 @@ done:
return ret;
}
-int zlib_decompress(struct list_head *ws, unsigned char *data_in,
+int zlib_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen)
{
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index e2d073b08a7d..a759668477bb 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -15,6 +15,8 @@
#include "transaction.h"
#include "dev-replace.h"
#include "space-info.h"
+#include "fs.h"
+#include "accessors.h"
/* Maximum number of zones to report per blkdev_report_zones() call */
#define BTRFS_REPORT_NR_ZONES 4096
@@ -134,7 +136,8 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones,
super[i] = page_address(page[i]);
}
- if (super[0]->generation > super[1]->generation)
+ if (btrfs_super_generation(super[0]) >
+ btrfs_super_generation(super[1]))
sector = zones[1].start;
else
sector = zones[0].start;
@@ -391,8 +394,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
zone_sectors = bdev_zone_sectors(bdev);
}
- /* Check if it's power of 2 (see is_power_of_2) */
- ASSERT(zone_sectors != 0 && (zone_sectors & (zone_sectors - 1)) == 0);
+ ASSERT(is_power_of_two_u64(zone_sectors));
zone_info->zone_size = zone_sectors << SECTOR_SHIFT;
/* We reject devices with a zone size larger than 8GB */
@@ -466,7 +468,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
goto out;
}
- zones = kcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL);
+ zones = kvcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL);
if (!zones) {
ret = -ENOMEM;
goto out;
@@ -585,7 +587,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
}
- kfree(zones);
+ kvfree(zones);
switch (bdev_zoned_model(bdev)) {
case BLK_ZONED_HM:
@@ -617,7 +619,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
return 0;
out:
- kfree(zones);
+ kvfree(zones);
out_free_zone_info:
btrfs_destroy_dev_zone_info(device);
@@ -639,6 +641,46 @@ void btrfs_destroy_dev_zone_info(struct btrfs_device *device)
device->zone_info = NULL;
}
+struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info(struct btrfs_device *orig_dev)
+{
+ struct btrfs_zoned_device_info *zone_info;
+
+ zone_info = kmemdup(orig_dev->zone_info, sizeof(*zone_info), GFP_KERNEL);
+ if (!zone_info)
+ return NULL;
+
+ zone_info->seq_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
+ if (!zone_info->seq_zones)
+ goto out;
+
+ bitmap_copy(zone_info->seq_zones, orig_dev->zone_info->seq_zones,
+ zone_info->nr_zones);
+
+ zone_info->empty_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
+ if (!zone_info->empty_zones)
+ goto out;
+
+ bitmap_copy(zone_info->empty_zones, orig_dev->zone_info->empty_zones,
+ zone_info->nr_zones);
+
+ zone_info->active_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
+ if (!zone_info->active_zones)
+ goto out;
+
+ bitmap_copy(zone_info->active_zones, orig_dev->zone_info->active_zones,
+ zone_info->nr_zones);
+ zone_info->zone_cache = NULL;
+
+ return zone_info;
+
+out:
+ bitmap_free(zone_info->seq_zones);
+ bitmap_free(zone_info->empty_zones);
+ bitmap_free(zone_info->active_zones);
+ kfree(zone_info);
+ return NULL;
+}
+
int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
struct blk_zone *zone)
{
@@ -977,8 +1019,8 @@ int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
zone_sectors * BTRFS_NR_SB_LOG_ZONES, GFP_NOFS);
}
-/**
- * btrfs_find_allocatable_zones - find allocatable zones within a given region
+/*
+ * Find allocatable zones within a given region.
*
* @device: the device to allocate a region on
* @hole_start: the position of the hole to allocate the region
@@ -1395,7 +1437,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
}
if (num_sequential > 0)
- cache->seq_zone = true;
+ set_bit(BLOCK_GROUP_FLAG_SEQUENTIAL_ZONE, &cache->runtime_flags);
if (num_conventional > 0) {
/* Zone capacity is always zone size in emulation */
@@ -1607,7 +1649,7 @@ bool btrfs_use_zone_append(struct btrfs_inode *inode, u64 start)
if (!cache)
return false;
- ret = cache->seq_zone;
+ ret = !!test_bit(BLOCK_GROUP_FLAG_SEQUENTIAL_ZONE, &cache->runtime_flags);
btrfs_put_block_group(cache);
return ret;
@@ -1821,7 +1863,7 @@ struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
return device;
}
-/**
+/*
* Activate block group and underlying device zones
*
* @block_group: the block group to activate
@@ -2112,7 +2154,8 @@ static void btrfs_zone_finish_endio_workfn(struct work_struct *work)
void btrfs_schedule_zone_finish_bg(struct btrfs_block_group *bg,
struct extent_buffer *eb)
{
- if (!bg->seq_zone || eb->start + eb->len * 2 <= bg->start + bg->zone_capacity)
+ if (!test_bit(BLOCK_GROUP_FLAG_SEQUENTIAL_ZONE, &bg->runtime_flags) ||
+ eb->start + eb->len * 2 <= bg->start + bg->zone_capacity)
return;
if (WARN_ON(bg->zone_finish_work.func == btrfs_zone_finish_endio_workfn)) {
diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index e17462db3a84..f43990985d80 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/blkdev.h>
+#include "messages.h"
#include "volumes.h"
#include "disk-io.h"
#include "block-group.h"
@@ -36,6 +37,7 @@ int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info);
int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache);
void btrfs_destroy_dev_zone_info(struct btrfs_device *device);
+struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info(struct btrfs_device *orig_dev);
int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info);
int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info);
int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw,
@@ -103,6 +105,16 @@ static inline int btrfs_get_dev_zone_info(struct btrfs_device *device,
static inline void btrfs_destroy_dev_zone_info(struct btrfs_device *device) { }
+/*
+ * In case the kernel is compiled without CONFIG_BLK_DEV_ZONED we'll never call
+ * into btrfs_clone_dev_zone_info() so it's safe to return NULL here.
+ */
+static inline struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info(
+ struct btrfs_device *orig_dev)
+{
+ return NULL;
+}
+
static inline int btrfs_check_zoned_mode(const struct btrfs_fs_info *fs_info)
{
if (!btrfs_is_zoned(fs_info))
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index 35a0224d4eb7..e34f1ab99d56 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -94,7 +94,7 @@ static inline struct workspace *list_to_workspace(struct list_head *list)
void zstd_free_workspace(struct list_head *ws);
struct list_head *zstd_alloc_workspace(unsigned int level);
-/**
+/*
* Timer callback to free unused workspaces.
*
* @t: timer
@@ -616,7 +616,7 @@ done:
return ret;
}
-int zstd_decompress(struct list_head *ws, unsigned char *data_in,
+int zstd_decompress(struct list_head *ws, const u8 *data_in,
struct page *dest_page, unsigned long start_byte, size_t srclen,
size_t destlen)
{
diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c
index 000a28f46e59..175a25fcade8 100644
--- a/fs/cachefiles/io.c
+++ b/fs/cachefiles/io.c
@@ -385,38 +385,35 @@ static int cachefiles_write(struct netfs_cache_resources *cres,
term_func, term_func_priv);
}
-/*
- * Prepare a read operation, shortening it to a cached/uncached
- * boundary as appropriate.
- */
-static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *subreq,
- loff_t i_size)
+static inline enum netfs_io_source
+cachefiles_do_prepare_read(struct netfs_cache_resources *cres,
+ loff_t start, size_t *_len, loff_t i_size,
+ unsigned long *_flags, ino_t netfs_ino)
{
enum cachefiles_prepare_read_trace why;
- struct netfs_io_request *rreq = subreq->rreq;
- struct netfs_cache_resources *cres = &rreq->cache_resources;
- struct cachefiles_object *object;
+ struct cachefiles_object *object = NULL;
struct cachefiles_cache *cache;
struct fscache_cookie *cookie = fscache_cres_cookie(cres);
const struct cred *saved_cred;
struct file *file = cachefiles_cres_file(cres);
enum netfs_io_source ret = NETFS_DOWNLOAD_FROM_SERVER;
+ size_t len = *_len;
loff_t off, to;
ino_t ino = file ? file_inode(file)->i_ino : 0;
int rc;
- _enter("%zx @%llx/%llx", subreq->len, subreq->start, i_size);
+ _enter("%zx @%llx/%llx", len, start, i_size);
- if (subreq->start >= i_size) {
+ if (start >= i_size) {
ret = NETFS_FILL_WITH_ZEROES;
why = cachefiles_trace_read_after_eof;
goto out_no_object;
}
if (test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags)) {
- __set_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags);
+ __set_bit(NETFS_SREQ_COPY_TO_CACHE, _flags);
why = cachefiles_trace_read_no_data;
- if (!test_bit(NETFS_SREQ_ONDEMAND, &subreq->flags))
+ if (!test_bit(NETFS_SREQ_ONDEMAND, _flags))
goto out_no_object;
}
@@ -437,7 +434,7 @@ static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *
retry:
off = cachefiles_inject_read_error();
if (off == 0)
- off = vfs_llseek(file, subreq->start, SEEK_DATA);
+ off = vfs_llseek(file, start, SEEK_DATA);
if (off < 0 && off >= (loff_t)-MAX_ERRNO) {
if (off == (loff_t)-ENXIO) {
why = cachefiles_trace_read_seek_nxio;
@@ -449,21 +446,22 @@ retry:
goto out;
}
- if (off >= subreq->start + subreq->len) {
+ if (off >= start + len) {
why = cachefiles_trace_read_found_hole;
goto download_and_store;
}
- if (off > subreq->start) {
+ if (off > start) {
off = round_up(off, cache->bsize);
- subreq->len = off - subreq->start;
+ len = off - start;
+ *_len = len;
why = cachefiles_trace_read_found_part;
goto download_and_store;
}
to = cachefiles_inject_read_error();
if (to == 0)
- to = vfs_llseek(file, subreq->start, SEEK_HOLE);
+ to = vfs_llseek(file, start, SEEK_HOLE);
if (to < 0 && to >= (loff_t)-MAX_ERRNO) {
trace_cachefiles_io_error(object, file_inode(file), to,
cachefiles_trace_seek_error);
@@ -471,12 +469,13 @@ retry:
goto out;
}
- if (to < subreq->start + subreq->len) {
- if (subreq->start + subreq->len >= i_size)
+ if (to < start + len) {
+ if (start + len >= i_size)
to = round_up(to, cache->bsize);
else
to = round_down(to, cache->bsize);
- subreq->len = to - subreq->start;
+ len = to - start;
+ *_len = len;
}
why = cachefiles_trace_read_have_data;
@@ -484,12 +483,11 @@ retry:
goto out;
download_and_store:
- __set_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags);
- if (test_bit(NETFS_SREQ_ONDEMAND, &subreq->flags)) {
- rc = cachefiles_ondemand_read(object, subreq->start,
- subreq->len);
+ __set_bit(NETFS_SREQ_COPY_TO_CACHE, _flags);
+ if (test_bit(NETFS_SREQ_ONDEMAND, _flags)) {
+ rc = cachefiles_ondemand_read(object, start, len);
if (!rc) {
- __clear_bit(NETFS_SREQ_ONDEMAND, &subreq->flags);
+ __clear_bit(NETFS_SREQ_ONDEMAND, _flags);
goto retry;
}
ret = NETFS_INVALID_READ;
@@ -497,11 +495,35 @@ download_and_store:
out:
cachefiles_end_secure(cache, saved_cred);
out_no_object:
- trace_cachefiles_prep_read(subreq, ret, why, ino);
+ trace_cachefiles_prep_read(object, start, len, *_flags, ret, why, ino, netfs_ino);
return ret;
}
/*
+ * Prepare a read operation, shortening it to a cached/uncached
+ * boundary as appropriate.
+ */
+static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *subreq,
+ loff_t i_size)
+{
+ return cachefiles_do_prepare_read(&subreq->rreq->cache_resources,
+ subreq->start, &subreq->len, i_size,
+ &subreq->flags, subreq->rreq->inode->i_ino);
+}
+
+/*
+ * Prepare an on-demand read operation, shortening it to a cached/uncached
+ * boundary as appropriate.
+ */
+static enum netfs_io_source
+cachefiles_prepare_ondemand_read(struct netfs_cache_resources *cres,
+ loff_t start, size_t *_len, loff_t i_size,
+ unsigned long *_flags, ino_t ino)
+{
+ return cachefiles_do_prepare_read(cres, start, _len, i_size, _flags, ino);
+}
+
+/*
* Prepare for a write to occur.
*/
int __cachefiles_prepare_write(struct cachefiles_object *object,
@@ -621,6 +643,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
.write = cachefiles_write,
.prepare_read = cachefiles_prepare_read,
.prepare_write = cachefiles_prepare_write,
+ .prepare_ondemand_read = cachefiles_prepare_ondemand_read,
.query_occupancy = cachefiles_query_occupancy,
};
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index f4fc8e0b847c..c7e8dd5b58d4 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -85,13 +85,14 @@ retry:
return acl;
}
-int ceph_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ceph_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int ret = 0, size = 0;
const char *name = NULL;
char *value = NULL;
struct iattr newattrs;
+ struct inode *inode = d_inode(dentry);
struct timespec64 old_ctime = inode->i_ctime;
umode_t new_mode = inode->i_mode, old_mode = inode->i_mode;
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index dcf701b05cc1..61f47debec5a 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -288,7 +288,7 @@ static bool ceph_netfs_issue_op_inline(struct netfs_io_subrequest *subreq)
}
len = min_t(size_t, iinfo->inline_len - subreq->start, subreq->len);
- iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, subreq->start, len);
+ iov_iter_xarray(&iter, ITER_DEST, &rreq->mapping->i_pages, subreq->start, len);
err = copy_to_iter(iinfo->inline_data + subreq->start, len, &iter);
if (err == 0)
err = -EFAULT;
@@ -327,7 +327,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
}
dout("%s: pos=%llu orig_len=%zu len=%llu\n", __func__, subreq->start, subreq->len, len);
- iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, subreq->start, len);
+ iov_iter_xarray(&iter, ITER_DEST, &rreq->mapping->i_pages, subreq->start, len);
err = iov_iter_get_pages_alloc2(&iter, &pages, len, &page_off);
if (err < 0) {
dout("%s: iov_ter_get_pages_alloc returned %d\n", __func__, err);
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index fb023f9fafcb..e54814d0c2f7 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2248,7 +2248,6 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_request *req1 = NULL, *req2 = NULL;
- unsigned int max_sessions;
int ret, err = 0;
spin_lock(&ci->i_unsafe_lock);
@@ -2267,27 +2266,23 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
spin_unlock(&ci->i_unsafe_lock);
/*
- * The mdsc->max_sessions is unlikely to be changed
- * mostly, here we will retry it by reallocating the
- * sessions array memory to get rid of the mdsc->mutex
- * lock.
- */
-retry:
- max_sessions = mdsc->max_sessions;
-
- /*
* Trigger to flush the journal logs in all the relevant MDSes
* manually, or in the worst case we must wait at most 5 seconds
* to wait the journal logs to be flushed by the MDSes periodically.
*/
- if ((req1 || req2) && likely(max_sessions)) {
- struct ceph_mds_session **sessions = NULL;
- struct ceph_mds_session *s;
+ if (req1 || req2) {
struct ceph_mds_request *req;
+ struct ceph_mds_session **sessions;
+ struct ceph_mds_session *s;
+ unsigned int max_sessions;
int i;
+ mutex_lock(&mdsc->mutex);
+ max_sessions = mdsc->max_sessions;
+
sessions = kcalloc(max_sessions, sizeof(s), GFP_KERNEL);
if (!sessions) {
+ mutex_unlock(&mdsc->mutex);
err = -ENOMEM;
goto out;
}
@@ -2299,16 +2294,6 @@ retry:
s = req->r_session;
if (!s)
continue;
- if (unlikely(s->s_mds >= max_sessions)) {
- spin_unlock(&ci->i_unsafe_lock);
- for (i = 0; i < max_sessions; i++) {
- s = sessions[i];
- if (s)
- ceph_put_mds_session(s);
- }
- kfree(sessions);
- goto retry;
- }
if (!sessions[s->s_mds]) {
s = ceph_get_mds_session(s);
sessions[s->s_mds] = s;
@@ -2321,16 +2306,6 @@ retry:
s = req->r_session;
if (!s)
continue;
- if (unlikely(s->s_mds >= max_sessions)) {
- spin_unlock(&ci->i_unsafe_lock);
- for (i = 0; i < max_sessions; i++) {
- s = sessions[i];
- if (s)
- ceph_put_mds_session(s);
- }
- kfree(sessions);
- goto retry;
- }
if (!sessions[s->s_mds]) {
s = ceph_get_mds_session(s);
sessions[s->s_mds] = s;
@@ -2342,11 +2317,12 @@ retry:
/* the auth MDS */
spin_lock(&ci->i_ceph_lock);
if (ci->i_auth_cap) {
- s = ci->i_auth_cap->session;
- if (!sessions[s->s_mds])
- sessions[s->s_mds] = ceph_get_mds_session(s);
+ s = ci->i_auth_cap->session;
+ if (!sessions[s->s_mds])
+ sessions[s->s_mds] = ceph_get_mds_session(s);
}
spin_unlock(&ci->i_ceph_lock);
+ mutex_unlock(&mdsc->mutex);
/* send flush mdlog request to MDSes */
for (i = 0; i < max_sessions; i++) {
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index e7e2ebac330d..6c7026cc8988 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -2033,7 +2033,7 @@ const struct inode_operations ceph_dir_iops = {
.getattr = ceph_getattr,
.setattr = ceph_setattr,
.listxattr = ceph_listxattr,
- .get_acl = ceph_get_acl,
+ .get_inode_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
.mknod = ceph_mknod,
.symlink = ceph_symlink,
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 04fd34557de8..6f9580defb2b 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1161,7 +1161,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
aio_req->total_len = rc + zlen;
}
- iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs,
+ iov_iter_bvec(&i, ITER_DEST, osd_data->bvec_pos.bvecs,
osd_data->num_bvecs, len);
iov_iter_advance(&i, rc);
iov_iter_zero(zlen, &i);
@@ -1400,7 +1400,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
int zlen = min_t(size_t, len - ret,
size - pos - ret);
- iov_iter_bvec(&i, READ, bvecs, num_pages, len);
+ iov_iter_bvec(&i, ITER_DEST, bvecs, num_pages, len);
iov_iter_advance(&i, ret);
iov_iter_zero(zlen, &i);
ret += zlen;
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 4af5e55abc15..f23c5a6edc6f 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -126,7 +126,7 @@ const struct inode_operations ceph_file_iops = {
.setattr = ceph_setattr,
.getattr = ceph_getattr,
.listxattr = ceph_listxattr,
- .get_acl = ceph_get_acl,
+ .get_inode_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
};
@@ -362,7 +362,7 @@ static int ceph_fill_fragtree(struct inode *inode,
if (nsplits != ci->i_fragtree_nsplits) {
update = true;
} else if (nsplits) {
- i = prandom_u32_max(nsplits);
+ i = get_random_u32_below(nsplits);
id = le32_to_cpu(fragtree->splits[i].frag);
if (!__ceph_find_frag(ci, id))
update = true;
@@ -2255,7 +2255,7 @@ int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
err = __ceph_setattr(inode, attr);
if (err >= 0 && (attr->ia_valid & ATTR_MODE))
- err = posix_acl_chmod(&init_user_ns, inode, attr->ia_mode);
+ err = posix_acl_chmod(&init_user_ns, dentry, attr->ia_mode);
return err;
}
@@ -2492,7 +2492,7 @@ int ceph_getattr(struct user_namespace *mnt_userns, const struct path *path,
struct inode *parent;
parent = ceph_lookup_inode(sb, ceph_ino(inode));
- if (!parent)
+ if (IS_ERR(parent))
return PTR_ERR(parent);
pci = ceph_inode(parent);
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index 3e2843e86e27..f3b461c708a8 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -364,7 +364,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
*fcntl_count = 0;
*flock_count = 0;
- ctx = inode->i_flctx;
+ ctx = locks_inode_context(inode);
if (ctx) {
spin_lock(&ctx->flc_lock);
list_for_each_entry(lock, &ctx->flc_posix, fl_list)
@@ -418,7 +418,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
int num_fcntl_locks, int num_flock_locks)
{
struct file_lock *lock;
- struct file_lock_context *ctx = inode->i_flctx;
+ struct file_lock_context *ctx = locks_inode_context(inode);
int err = 0;
int seen_fcntl = 0;
int seen_flock = 0;
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
index 3fbabc98e1f7..7dac21ee6ce7 100644
--- a/fs/ceph/mdsmap.c
+++ b/fs/ceph/mdsmap.c
@@ -29,7 +29,7 @@ static int __mdsmap_get_random_mds(struct ceph_mdsmap *m, bool ignore_laggy)
return -1;
/* pick */
- n = prandom_u32_max(n);
+ n = get_random_u32_below(n);
for (j = 0, i = 0; i < m->possible_max_rank; i++) {
if (CEPH_MDS_IS_READY(i, ignore_laggy))
j++;
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 864cdaa0d2bd..e4151852184e 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -763,7 +763,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
struct ceph_mds_snap_realm *ri; /* encoded */
__le64 *snaps; /* encoded */
__le64 *prior_parent_snaps; /* encoded */
- struct ceph_snap_realm *realm = NULL;
+ struct ceph_snap_realm *realm;
struct ceph_snap_realm *first_realm = NULL;
struct ceph_snap_realm *realm_to_rebuild = NULL;
int rebuild_snapcs;
@@ -774,6 +774,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
dout("%s deletion=%d\n", __func__, deletion);
more:
+ realm = NULL;
rebuild_snapcs = 0;
ceph_decode_need(&p, e, sizeof(*ri), bad);
ri = p;
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 40630e6f691c..50e57a1fa32f 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1117,7 +1117,7 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx);
struct posix_acl *ceph_get_acl(struct inode *, int, bool);
int ceph_set_acl(struct user_namespace *mnt_userns,
- struct inode *inode, struct posix_acl *acl, int type);
+ struct dentry *dentry, struct posix_acl *acl, int type);
int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
struct ceph_acl_sec_ctx *as_ctx);
void ceph_init_inode_acls(struct inode *inode,
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index fa480d62f313..c647f0d56518 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -13,6 +13,9 @@
#include <linux/string.h>
#include <linux/keyctl.h>
#include <linux/key-type.h>
+#include <uapi/linux/posix_acl.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#include <keys/user-type.h>
#include "cifspdu.h"
#include "cifsglob.h"
@@ -20,6 +23,8 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "fs_context.h"
+#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
/* security id for everyone/world system group */
static const struct cifs_sid sid_everyone = {
@@ -1668,3 +1673,137 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
kfree(pntsd);
return rc;
}
+
+struct posix_acl *cifs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type)
+{
+#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX)
+ struct posix_acl *acl = NULL;
+ ssize_t rc = -EOPNOTSUPP;
+ unsigned int xid;
+ struct super_block *sb = dentry->d_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct tcon_link *tlink;
+ struct cifs_tcon *pTcon;
+ const char *full_path;
+ void *page;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return ERR_CAST(tlink);
+ pTcon = tlink_tcon(tlink);
+
+ xid = get_xid();
+ page = alloc_dentry_path();
+
+ full_path = build_path_from_dentry(dentry, page);
+ if (IS_ERR(full_path)) {
+ acl = ERR_CAST(full_path);
+ goto out;
+ }
+
+ /* return alt name if available as pseudo attr */
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ if (sb->s_flags & SB_POSIXACL)
+ rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
+ ACL_TYPE_ACCESS,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (sb->s_flags & SB_POSIXACL)
+ rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
+ ACL_TYPE_DEFAULT,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ break;
+ }
+
+ if (rc < 0) {
+ if (rc == -EINVAL)
+ acl = ERR_PTR(-EOPNOTSUPP);
+ else
+ acl = ERR_PTR(rc);
+ }
+
+out:
+ free_dentry_path(page);
+ free_xid(xid);
+ cifs_put_tlink(tlink);
+ return acl;
+#else
+ return ERR_PTR(-EOPNOTSUPP);
+#endif
+}
+
+int cifs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type)
+{
+#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX)
+ int rc = -EOPNOTSUPP;
+ unsigned int xid;
+ struct super_block *sb = dentry->d_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct tcon_link *tlink;
+ struct cifs_tcon *pTcon;
+ const char *full_path;
+ void *page;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ pTcon = tlink_tcon(tlink);
+
+ xid = get_xid();
+ page = alloc_dentry_path();
+
+ full_path = build_path_from_dentry(dentry, page);
+ if (IS_ERR(full_path)) {
+ rc = PTR_ERR(full_path);
+ goto out;
+ }
+
+ if (!acl)
+ goto out;
+
+ /* return dos attributes as pseudo xattr */
+ /* return alt name if available as pseudo attr */
+
+ /* if proc/fs/cifs/streamstoxattr is set then
+ search server for EAs or streams to
+ returns as xattrs */
+ if (posix_acl_xattr_size(acl->a_count) > CIFSMaxBufSize) {
+ cifs_dbg(FYI, "size of EA value too large\n");
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ if (sb->s_flags & SB_POSIXACL)
+ rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
+ ACL_TYPE_ACCESS,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (sb->s_flags & SB_POSIXACL)
+ rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
+ ACL_TYPE_DEFAULT,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ break;
+ }
+
+out:
+ free_dentry_path(page);
+ free_xid(xid);
+ cifs_put_tlink(tlink);
+ return rc;
+#else
+ return -EOPNOTSUPP;
+#endif
+}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index fe220686bba4..040267ed8a64 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1133,6 +1133,8 @@ const struct inode_operations cifs_dir_inode_ops = {
.symlink = cifs_symlink,
.mknod = cifs_mknod,
.listxattr = cifs_listxattr,
+ .get_acl = cifs_get_acl,
+ .set_acl = cifs_set_acl,
};
const struct inode_operations cifs_file_inode_ops = {
@@ -1141,6 +1143,8 @@ const struct inode_operations cifs_file_inode_ops = {
.permission = cifs_permission,
.listxattr = cifs_listxattr,
.fiemap = cifs_fiemap,
+ .get_acl = cifs_get_acl,
+ .set_acl = cifs_set_acl,
};
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
@@ -1281,7 +1285,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
rc = filemap_write_and_wait_range(src_inode->i_mapping, off,
off + len - 1);
if (rc)
- goto out;
+ goto unlock;
/* should we flush first and last page first */
truncate_inode_pages(&target_inode->i_data, 0);
@@ -1297,6 +1301,8 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
* that target is updated on the server
*/
CIFS_I(target_inode)->time = 0;
+
+unlock:
/* although unlocking in the reverse order from locking is not
* strictly necessary here it is a little cleaner to be consistent
*/
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 83e83d8beabb..f50f96e4ec30 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -224,6 +224,10 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *, u32);
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
const struct cifs_fid *, u32 *, u32);
+extern struct posix_acl *cifs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type);
+extern int cifs_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct posix_acl *acl, int type);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *, int);
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);
@@ -537,14 +541,14 @@ extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
struct cifs_ntsd *, __u32, int);
-extern int CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *searchName,
- char *acl_inf, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *fileName,
- const char *local_acl, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage, int remap_special_chars);
+extern int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName,
+ struct posix_acl **acl, const int acl_type,
+ const struct nls_table *nls_codepage, int remap);
+extern int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *fileName,
+ const struct posix_acl *acl, const int acl_type,
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1724066c1536..23f10e0d6e7e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2914,32 +2914,57 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
#ifdef CONFIG_CIFS_POSIX
-/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
-static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
- struct cifs_posix_ace *cifs_ace)
+#ifdef CONFIG_FS_POSIX_ACL
+/**
+ * cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format
+ * @ace: POSIX ACL entry to store converted ACL into
+ * @cifs_ace: ACL in cifs format
+ *
+ * Convert an Access Control Entry from wire format to local POSIX xattr
+ * format.
+ *
+ * Note that the @cifs_uid member is used to store both {g,u}id_t.
+ */
+static void cifs_init_posix_acl(struct posix_acl_entry *ace,
+ struct cifs_posix_ace *cifs_ace)
{
/* u8 cifs fields do not need le conversion */
- ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
- ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
- ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
-/*
- cifs_dbg(FYI, "perm %d tag %d id %d\n",
- ace->e_perm, ace->e_tag, ace->e_id);
-*/
+ ace->e_perm = cifs_ace->cifs_e_perm;
+ ace->e_tag = cifs_ace->cifs_e_tag;
+ switch (ace->e_tag) {
+ case ACL_USER:
+ ace->e_uid = make_kuid(&init_user_ns,
+ le64_to_cpu(cifs_ace->cifs_uid));
+ break;
+ case ACL_GROUP:
+ ace->e_gid = make_kgid(&init_user_ns,
+ le64_to_cpu(cifs_ace->cifs_uid));
+ break;
+ }
return;
}
-/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
- const int acl_type, const int size_of_data_area)
+/**
+ * cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format
+ * @acl: ACLs returned in POSIX ACL format
+ * @src: ACLs in cifs format
+ * @acl_type: type of POSIX ACL requested
+ * @size_of_data_area: size of SMB we got
+ *
+ * This function converts ACLs from cifs format to POSIX ACL format.
+ * If @acl is NULL then the size of the buffer required to store POSIX ACLs in
+ * their uapi format is returned.
+ */
+static int cifs_to_posix_acl(struct posix_acl **acl, char *src,
+ const int acl_type, const int size_of_data_area)
{
int size = 0;
- int i;
__u16 count;
struct cifs_posix_ace *pACE;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
- struct posix_acl_xattr_header *local_acl = (void *)trgt;
+ struct posix_acl *kacl = NULL;
+ struct posix_acl_entry *pa, *pe;
if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
return -EOPNOTSUPP;
@@ -2959,7 +2984,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
count = le16_to_cpu(cifs_acl->access_entry_count);
size = sizeof(struct cifs_posix_acl);
size += sizeof(struct cifs_posix_ace) * count;
-/* skip past access ACEs to get to default ACEs */
+ /* skip past access ACEs to get to default ACEs */
pACE = &cifs_acl->ace_array[count];
count = le16_to_cpu(cifs_acl->default_entry_count);
size += sizeof(struct cifs_posix_ace) * count;
@@ -2971,62 +2996,75 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
return -EINVAL;
}
- size = posix_acl_xattr_size(count);
- if ((buflen == 0) || (local_acl == NULL)) {
- /* used to query ACL EA size */
- } else if (size > buflen) {
- return -ERANGE;
- } else /* buffer big enough */ {
- struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
-
- local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
- for (i = 0; i < count ; i++) {
- cifs_convert_ace(&ace[i], pACE);
- pACE++;
- }
+ /* Allocate number of POSIX ACLs to store in VFS format. */
+ kacl = posix_acl_alloc(count, GFP_NOFS);
+ if (!kacl)
+ return -ENOMEM;
+
+ FOREACH_ACL_ENTRY(pa, kacl, pe) {
+ cifs_init_posix_acl(pa, pACE);
+ pACE++;
}
- return size;
+
+ *acl = kacl;
+ return 0;
}
-static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
- const struct posix_acl_xattr_entry *local_ace)
+/**
+ * cifs_init_ace - convert ACL entry from POSIX ACL to cifs format
+ * @cifs_ace: the cifs ACL entry to store into
+ * @local_ace: the POSIX ACL entry to convert
+ */
+static void cifs_init_ace(struct cifs_posix_ace *cifs_ace,
+ const struct posix_acl_entry *local_ace)
{
- cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
- cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
- /* BB is there a better way to handle the large uid? */
- if (local_ace->e_id == cpu_to_le32(-1)) {
- /* Probably no need to le convert -1 on any arch but can not hurt */
+ cifs_ace->cifs_e_perm = local_ace->e_perm;
+ cifs_ace->cifs_e_tag = local_ace->e_tag;
+
+ switch (local_ace->e_tag) {
+ case ACL_USER:
+ cifs_ace->cifs_uid =
+ cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid));
+ break;
+ case ACL_GROUP:
+ cifs_ace->cifs_uid =
+ cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid));
+ break;
+ default:
cifs_ace->cifs_uid = cpu_to_le64(-1);
- } else
- cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
-/*
- cifs_dbg(FYI, "perm %d tag %d id %d\n",
- ace->e_perm, ace->e_tag, ace->e_id);
-*/
+ }
}
-/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
-static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
- const int buflen, const int acl_type)
+/**
+ * posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format
+ * @parm_data: ACLs in cifs format to conver to
+ * @acl: ACLs in POSIX ACL format to convert from
+ * @acl_type: the type of POSIX ACLs stored in @acl
+ *
+ * Return: the number cifs ACL entries after conversion
+ */
+static __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl,
+ const int acl_type)
{
__u16 rc = 0;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
- struct posix_acl_xattr_header *local_acl = (void *)pACL;
- struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
+ const struct posix_acl_entry *pa, *pe;
int count;
- int i;
+ int i = 0;
- if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
+ if ((acl == NULL) || (cifs_acl == NULL))
return 0;
- count = posix_acl_xattr_count((size_t)buflen);
- cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
- count, buflen, le32_to_cpu(local_acl->a_version));
- if (le32_to_cpu(local_acl->a_version) != 2) {
- cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
- le32_to_cpu(local_acl->a_version));
- return 0;
- }
+ count = acl->a_count;
+ cifs_dbg(FYI, "setting acl with %d entries\n", count);
+
+ /*
+ * Note that the uapi POSIX ACL version is verified by the VFS and is
+ * independent of the cifs ACL version. Changing the POSIX ACL version
+ * is a uapi change and if it's changed we will pass down the POSIX ACL
+ * version in struct posix_acl from the VFS. For now there's really
+ * only one that all filesystems know how to deal with.
+ */
cifs_acl->version = cpu_to_le16(1);
if (acl_type == ACL_TYPE_ACCESS) {
cifs_acl->access_entry_count = cpu_to_le16(count);
@@ -3038,8 +3076,9 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
return 0;
}
- for (i = 0; i < count; i++)
- convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
+ FOREACH_ACL_ENTRY(pa, acl, pe) {
+ cifs_init_ace(&cifs_acl->ace_array[i++], pa);
+ }
if (rc == 0) {
rc = (__u16)(count * sizeof(struct cifs_posix_ace));
rc += sizeof(struct cifs_posix_acl);
@@ -3048,11 +3087,10 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
return rc;
}
-int
-CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *searchName,
- char *acl_inf, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage, int remap)
+int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName, struct posix_acl **acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap)
{
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3124,23 +3162,26 @@ queryAclRetry:
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- rc = cifs_copy_posix_acl(acl_inf,
+ rc = cifs_to_posix_acl(acl,
(char *)&pSMBr->hdr.Protocol+data_offset,
- buflen, acl_type, count);
+ acl_type, count);
}
}
cifs_buf_release(pSMB);
+ /*
+ * The else branch after SendReceive() doesn't return EAGAIN so if we
+ * allocated @acl in cifs_to_posix_acl() we are guaranteed to return
+ * here and don't leak POSIX ACLs.
+ */
if (rc == -EAGAIN)
goto queryAclRetry;
return rc;
}
-int
-CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
- const unsigned char *fileName,
- const char *local_acl, const int buflen,
- const int acl_type,
- const struct nls_table *nls_codepage, int remap)
+int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *fileName, const struct posix_acl *acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -3181,7 +3222,7 @@ setAclRetry:
pSMB->ParameterOffset = cpu_to_le16(param_offset);
/* convert to on the wire format for POSIX ACL */
- data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
+ data_count = posix_acl_to_cifs(parm_data, acl, acl_type);
if (data_count == 0) {
rc = -EOPNOTSUPP;
@@ -3211,6 +3252,23 @@ setACLerrorExit:
goto setAclRetry;
return rc;
}
+#else
+int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *searchName, struct posix_acl **acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap)
+{
+ return -EOPNOTSUPP;
+}
+
+int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ const unsigned char *fileName, const struct posix_acl *acl,
+ const int acl_type, const struct nls_table *nls_codepage,
+ int remap)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_FS_POSIX_ACL */
int
CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 1cc47dd3b4d6..e80252a83225 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -759,7 +759,7 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
{
struct msghdr smb_msg = {};
struct kvec iov = {.iov_base = buf, .iov_len = to_read};
- iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
+ iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read);
return cifs_readv_from_socket(server, &smb_msg);
}
@@ -774,7 +774,7 @@ cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read)
* and cifs_readv_from_socket sets msg_control and msg_controllen
* so little to initialize in struct msghdr
*/
- iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
+ iov_iter_discard(&smb_msg.msg_iter, ITER_DEST, to_read);
return cifs_readv_from_socket(server, &smb_msg);
}
@@ -786,7 +786,7 @@ cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
struct msghdr smb_msg = {};
struct bio_vec bv = {
.bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
- iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
+ iov_iter_bvec(&smb_msg.msg_iter, ITER_DEST, &bv, 1, to_read);
return cifs_readv_from_socket(server, &smb_msg);
}
@@ -3855,9 +3855,13 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
uuid_copy(&cifs_sb->dfs_mount_id, &mnt_ctx.mount_id);
out:
- free_xid(mnt_ctx.xid);
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
- return mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
+ rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
+ if (rc)
+ goto error;
+
+ free_xid(mnt_ctx.xid);
+ return rc;
error:
dfs_cache_put_refsrv_sessions(&mnt_ctx.mount_id);
@@ -3884,8 +3888,12 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
goto error;
}
+ rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
+ if (rc)
+ goto error;
+
free_xid(mnt_ctx.xid);
- return mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
+ return rc;
error:
mount_put_conns(&mnt_ctx);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index cd9698209930..87b56b1ae117 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1413,7 +1413,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
struct inode *inode = d_inode(cfile->dentry);
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct file_lock *flock;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
unsigned int count = 0, i;
int rc = 0, xid, type;
struct list_head locks_to_send, *el;
@@ -3532,7 +3532,7 @@ static ssize_t __cifs_writev(
ctx->iter = *from;
ctx->len = len;
} else {
- rc = setup_aio_ctx_iter(ctx, from, WRITE);
+ rc = setup_aio_ctx_iter(ctx, from, ITER_SOURCE);
if (rc) {
kref_put(&ctx->refcount, cifs_aio_ctx_release);
return rc;
@@ -4276,7 +4276,7 @@ static ssize_t __cifs_readv(
ctx->iter = *to;
ctx->len = len;
} else {
- rc = setup_aio_ctx_iter(ctx, to, READ);
+ rc = setup_aio_ctx_iter(ctx, to, ITER_DEST);
if (rc) {
kref_put(&ctx->refcount, cifs_aio_ctx_release);
return rc;
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c
index a1751b956318..f6f3a6b75601 100644
--- a/fs/cifs/fscache.c
+++ b/fs/cifs/fscache.c
@@ -150,7 +150,7 @@ static int fscache_fallback_read_page(struct inode *inode, struct page *page)
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
- iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+ iov_iter_bvec(&iter, ITER_DEST, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
ret = fscache_begin_read_operation(&cres, cookie);
if (ret < 0)
@@ -180,7 +180,7 @@ static int fscache_fallback_write_page(struct inode *inode, struct page *page,
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
- iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+ iov_iter_bvec(&iter, ITER_SOURCE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
ret = fscache_begin_write_operation(&cres, cookie);
if (ret < 0)
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 89d5fa887364..6419ec47c2a8 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -343,7 +343,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = put_user(ExtAttrBits &
FS_FL_USER_VISIBLE,
(int __user *)arg);
- if (rc != EOPNOTSUPP)
+ if (rc != -EOPNOTSUPP)
break;
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -373,7 +373,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
* pSMBFile->fid.netfid,
* extAttrBits,
* &ExtAttrMask);
- * if (rc != EOPNOTSUPP)
+ * if (rc != -EOPNOTSUPP)
* break;
*/
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 92e4278ec35d..9e7d9f0baa18 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -302,14 +302,14 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
/* now drop the ref to the current iface */
if (old_iface && iface) {
- kref_put(&old_iface->refcount, release_iface);
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
&old_iface->sockaddr,
&iface->sockaddr);
- } else if (old_iface) {
kref_put(&old_iface->refcount, release_iface);
+ } else if (old_iface) {
cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
&old_iface->sockaddr);
+ kref_put(&old_iface->refcount, release_iface);
} else {
WARN_ON(!iface);
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 880cd494afea..32b3877b538a 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1116,6 +1116,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid,
FILE_FULL_EA_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size);
+ if (rc)
+ goto sea_exit;
smb2_set_next_command(tcon, &rqst[1]);
smb2_set_related(&rqst[1]);
@@ -1126,6 +1128,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
rqst[2].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
+ if (rc)
+ goto sea_exit;
smb2_set_related(&rqst[2]);
rc = compound_send_recv(xid, ses, server,
@@ -4719,13 +4723,13 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
return 0;
}
- iov_iter_bvec(&iter, WRITE, bvec, npages, data_len);
+ iov_iter_bvec(&iter, ITER_SOURCE, bvec, npages, data_len);
} else if (buf_len >= data_offset + data_len) {
/* read response payload is in buf */
WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
iov.iov_base = buf + data_offset;
iov.iov_len = data_len;
- iov_iter_kvec(&iter, WRITE, &iov, 1, data_len);
+ iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, data_len);
} else {
/* read response payload cannot be in both buf and pages */
WARN_ONCE(1, "buf can not contain only a part of read data");
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 575fa8f58342..3851d0aaa288 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -347,7 +347,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
.iov_base = &rfc1002_marker,
.iov_len = 4
};
- iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4);
+ iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
goto unmask;
@@ -368,7 +368,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
size += iov[i].iov_len;
}
- iov_iter_kvec(&smb_msg.msg_iter, WRITE, iov, n_vec, size);
+ iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
@@ -384,7 +384,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
&bvec.bv_offset);
- iov_iter_bvec(&smb_msg.msg_iter, WRITE,
+ iov_iter_bvec(&smb_msg.msg_iter, ITER_SOURCE,
&bvec, 1, bvec.bv_len);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 998fa51f9b68..5f2fb2fd2e37 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -200,32 +200,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
}
break;
}
-
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- case XATTR_ACL_ACCESS:
-#ifdef CONFIG_CIFS_POSIX
- if (!value)
- goto out;
- if (sb->s_flags & SB_POSIXACL)
- rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
- value, (const int)size,
- ACL_TYPE_ACCESS, cifs_sb->local_nls,
- cifs_remap(cifs_sb));
-#endif /* CONFIG_CIFS_POSIX */
- break;
-
- case XATTR_ACL_DEFAULT:
-#ifdef CONFIG_CIFS_POSIX
- if (!value)
- goto out;
- if (sb->s_flags & SB_POSIXACL)
- rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
- value, (const int)size,
- ACL_TYPE_DEFAULT, cifs_sb->local_nls,
- cifs_remap(cifs_sb));
-#endif /* CONFIG_CIFS_POSIX */
- break;
-#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
}
out:
@@ -366,27 +340,6 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
}
break;
}
-#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- case XATTR_ACL_ACCESS:
-#ifdef CONFIG_CIFS_POSIX
- if (sb->s_flags & SB_POSIXACL)
- rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
- value, size, ACL_TYPE_ACCESS,
- cifs_sb->local_nls,
- cifs_remap(cifs_sb));
-#endif /* CONFIG_CIFS_POSIX */
- break;
-
- case XATTR_ACL_DEFAULT:
-#ifdef CONFIG_CIFS_POSIX
- if (sb->s_flags & SB_POSIXACL)
- rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
- value, size, ACL_TYPE_DEFAULT,
- cifs_sb->local_nls,
- cifs_remap(cifs_sb));
-#endif /* CONFIG_CIFS_POSIX */
- break;
-#endif /* ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
}
/* We could add an additional check for streams ie
@@ -525,21 +478,6 @@ static const struct xattr_handler smb3_ntsd_full_xattr_handler = {
.set = cifs_xattr_set,
};
-
-static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
- .name = XATTR_NAME_POSIX_ACL_ACCESS,
- .flags = XATTR_ACL_ACCESS,
- .get = cifs_xattr_get,
- .set = cifs_xattr_set,
-};
-
-static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
- .name = XATTR_NAME_POSIX_ACL_DEFAULT,
- .flags = XATTR_ACL_DEFAULT,
- .get = cifs_xattr_get,
- .set = cifs_xattr_set,
-};
-
const struct xattr_handler *cifs_xattr_handlers[] = {
&cifs_user_xattr_handler,
&cifs_os2_xattr_handler,
@@ -549,7 +487,9 @@ const struct xattr_handler *cifs_xattr_handlers[] = {
&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
&cifs_cifs_ntsd_full_xattr_handler,
&smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */
- &cifs_posix_acl_access_xattr_handler,
- &cifs_posix_acl_default_xattr_handler,
+#ifdef CONFIG_FS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
+#endif
NULL
};
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index d1f9d2632202..ec6519e1ca3b 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -316,6 +316,7 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry,
return 0;
out_remove:
+ configfs_put(dentry->d_fsdata);
configfs_remove_dirent(dentry);
return PTR_ERR(inode);
}
@@ -382,6 +383,7 @@ int configfs_create_link(struct configfs_dirent *target, struct dentry *parent,
return 0;
out_remove:
+ configfs_put(dentry->d_fsdata);
configfs_remove_dirent(dentry);
return PTR_ERR(inode);
}
diff --git a/fs/coredump.c b/fs/coredump.c
index 7bad7785e8e6..a4c30bb900fe 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -325,6 +325,10 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm,
err = cn_printf(cn, "%lu",
rlimit(RLIMIT_CORE));
break;
+ /* CPU the task ran on */
+ case 'C':
+ err = cn_printf(cn, "%d", cprm->cpu);
+ break;
default:
break;
}
@@ -525,7 +529,6 @@ void do_coredump(const kernel_siginfo_t *siginfo)
static atomic_t core_dump_count = ATOMIC_INIT(0);
struct coredump_params cprm = {
.siginfo = siginfo,
- .regs = signal_pt_regs(),
.limit = rlimit(RLIMIT_CORE),
/*
* We must use the same mm->flags while dumping core to avoid
@@ -534,6 +537,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
*/
.mm_flags = mm->flags,
.vma_meta = NULL,
+ .cpu = raw_smp_processor_id(),
};
audit_core_dumps(siginfo->si_signo);
@@ -716,8 +720,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
* filesystem.
*/
mnt_userns = file_mnt_user_ns(cprm.file);
- if (!uid_eq(i_uid_into_mnt(mnt_userns, inode),
- current_fsuid())) {
+ if (!vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode),
+ current_fsuid())) {
pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
cn.corename);
goto close_fail;
@@ -853,7 +857,7 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page)
if (dump_interrupted())
return 0;
pos = file->f_pos;
- iov_iter_bvec(&iter, WRITE, &bvec, 1, PAGE_SIZE);
+ iov_iter_bvec(&iter, ITER_SOURCE, &bvec, 1, PAGE_SIZE);
n = __kernel_write_iter(cprm->file, &iter, &pos);
if (n != PAGE_SIZE)
return 0;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index d5f68a0c5d15..316a778cec0f 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -439,13 +439,7 @@ struct fscrypt_master_key_secret {
struct fscrypt_master_key {
/*
- * Back-pointer to the super_block of the filesystem to which this
- * master key has been added. Only valid if ->mk_active_refs > 0.
- */
- struct super_block *mk_sb;
-
- /*
- * Link in ->mk_sb->s_master_keys->key_hashtable.
+ * Link in ->s_master_keys->key_hashtable.
* Only valid if ->mk_active_refs > 0.
*/
struct hlist_node mk_node;
@@ -456,7 +450,7 @@ struct fscrypt_master_key {
/*
* Active and structural reference counts. An active ref guarantees
* that the struct continues to exist, continues to be in the keyring
- * ->mk_sb->s_master_keys, and that any embedded subkeys (e.g.
+ * ->s_master_keys, and that any embedded subkeys (e.g.
* ->mk_direct_keys) that have been prepared continue to exist.
* A structural ref only guarantees that the struct continues to exist.
*
@@ -569,7 +563,8 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
void fscrypt_put_master_key(struct fscrypt_master_key *mk);
-void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk);
+void fscrypt_put_master_key_activeref(struct super_block *sb,
+ struct fscrypt_master_key *mk);
struct fscrypt_master_key *
fscrypt_find_master_key(struct super_block *sb,
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index cea8b14007e6..8bfb3ce86476 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -12,7 +12,7 @@
* provides the key and IV to use.
*/
-#include <linux/blk-crypto-profile.h>
+#include <linux/blk-crypto.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/sched/mm.h>
@@ -77,10 +77,8 @@ static void fscrypt_log_blk_crypto_impl(struct fscrypt_mode *mode,
unsigned int i;
for (i = 0; i < num_devs; i++) {
- struct request_queue *q = bdev_get_queue(devs[i]);
-
if (!IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) ||
- __blk_crypto_cfg_supported(q->crypto_profile, cfg)) {
+ blk_crypto_config_supported_natively(devs[i], cfg)) {
if (!xchg(&mode->logged_blk_crypto_native, 1))
pr_info("fscrypt: %s using blk-crypto (native)\n",
mode->friendly_name);
@@ -139,8 +137,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
return PTR_ERR(devs);
for (i = 0; i < num_devs; i++) {
- if (!blk_crypto_config_supported(bdev_get_queue(devs[i]),
- &crypto_cfg))
+ if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
goto out_free_devs;
}
@@ -184,8 +181,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
goto fail;
}
for (i = 0; i < num_devs; i++) {
- err = blk_crypto_start_using_key(blk_key,
- bdev_get_queue(devs[i]));
+ err = blk_crypto_start_using_key(devs[i], blk_key);
if (err)
break;
}
@@ -224,7 +220,7 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
devs = fscrypt_get_devices(sb, &num_devs);
if (!IS_ERR(devs)) {
for (i = 0; i < num_devs; i++)
- blk_crypto_evict_key(bdev_get_queue(devs[i]), blk_key);
+ blk_crypto_evict_key(devs[i], blk_key);
kfree(devs);
}
kfree_sensitive(blk_key);
diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
index 2a24b1f0ae68..78dd2ff306bd 100644
--- a/fs/crypto/keyring.c
+++ b/fs/crypto/keyring.c
@@ -79,10 +79,9 @@ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
}
-void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk)
+void fscrypt_put_master_key_activeref(struct super_block *sb,
+ struct fscrypt_master_key *mk)
{
- struct super_block *sb = mk->mk_sb;
- struct fscrypt_keyring *keyring = sb->s_master_keys;
size_t i;
if (!refcount_dec_and_test(&mk->mk_active_refs))
@@ -93,9 +92,9 @@ void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk)
* destroying any subkeys embedded in it.
*/
- spin_lock(&keyring->lock);
+ spin_lock(&sb->s_master_keys->lock);
hlist_del_rcu(&mk->mk_node);
- spin_unlock(&keyring->lock);
+ spin_unlock(&sb->s_master_keys->lock);
/*
* ->mk_active_refs == 0 implies that ->mk_secret is not present and
@@ -243,7 +242,7 @@ void fscrypt_destroy_keyring(struct super_block *sb)
WARN_ON(refcount_read(&mk->mk_struct_refs) != 1);
WARN_ON(!is_master_key_secret_present(&mk->mk_secret));
wipe_master_key_secret(&mk->mk_secret);
- fscrypt_put_master_key_activeref(mk);
+ fscrypt_put_master_key_activeref(sb, mk);
}
}
kfree_sensitive(keyring);
@@ -424,7 +423,6 @@ static int add_new_master_key(struct super_block *sb,
if (!mk)
return -ENOMEM;
- mk->mk_sb = sb;
init_rwsem(&mk->mk_sem);
refcount_set(&mk->mk_struct_refs, 1);
mk->mk_spec = *mk_spec;
@@ -1068,7 +1066,7 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
err = -ENOKEY;
if (is_master_key_secret_present(&mk->mk_secret)) {
wipe_master_key_secret(&mk->mk_secret);
- fscrypt_put_master_key_activeref(mk);
+ fscrypt_put_master_key_activeref(sb, mk);
err = 0;
}
inodes_remain = refcount_read(&mk->mk_active_refs) > 0;
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index f7407071a952..94757ccd3056 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -44,6 +44,21 @@ struct fscrypt_mode fscrypt_modes[] = {
.security_strength = 16,
.ivsize = 16,
},
+ [FSCRYPT_MODE_SM4_XTS] = {
+ .friendly_name = "SM4-XTS",
+ .cipher_str = "xts(sm4)",
+ .keysize = 32,
+ .security_strength = 16,
+ .ivsize = 16,
+ .blk_crypto_mode = BLK_ENCRYPTION_MODE_SM4_XTS,
+ },
+ [FSCRYPT_MODE_SM4_CTS] = {
+ .friendly_name = "SM4-CTS-CBC",
+ .cipher_str = "cts(cbc(sm4))",
+ .keysize = 16,
+ .security_strength = 16,
+ .ivsize = 16,
+ },
[FSCRYPT_MODE_ADIANTUM] = {
.friendly_name = "Adiantum",
.cipher_str = "adiantum(xchacha12,aes)",
@@ -509,7 +524,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
spin_lock(&mk->mk_decrypted_inodes_lock);
list_del(&ci->ci_master_key_link);
spin_unlock(&mk->mk_decrypted_inodes_lock);
- fscrypt_put_master_key_activeref(mk);
+ fscrypt_put_master_key_activeref(ci->ci_inode->i_sb, mk);
}
memzero_explicit(ci, sizeof(*ci));
kmem_cache_free(fscrypt_info_cachep, ci);
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index 46757c3052ef..893661b52376 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -61,6 +61,13 @@ fscrypt_get_dummy_policy(struct super_block *sb)
return sb->s_cop->get_dummy_policy(sb);
}
+/*
+ * Return %true if the given combination of encryption modes is supported for v1
+ * (and later) encryption policies.
+ *
+ * Do *not* add anything new here, since v1 encryption policies are deprecated.
+ * New combinations of modes should go in fscrypt_valid_enc_modes_v2() only.
+ */
static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode)
{
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
@@ -83,6 +90,11 @@ static bool fscrypt_valid_enc_modes_v2(u32 contents_mode, u32 filenames_mode)
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
filenames_mode == FSCRYPT_MODE_AES_256_HCTR2)
return true;
+
+ if (contents_mode == FSCRYPT_MODE_SM4_XTS &&
+ filenames_mode == FSCRYPT_MODE_SM4_CTS)
+ return true;
+
return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode);
}
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index ddb3fc258df9..b54f470e0d03 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -378,8 +378,8 @@ ssize_t debugfs_attr_read(struct file *file, char __user *buf,
}
EXPORT_SYMBOL_GPL(debugfs_attr_read);
-ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
+static ssize_t debugfs_attr_write_xsigned(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos, bool is_signed)
{
struct dentry *dentry = F_DENTRY(file);
ssize_t ret;
@@ -387,12 +387,28 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
ret = debugfs_file_get(dentry);
if (unlikely(ret))
return ret;
- ret = simple_attr_write(file, buf, len, ppos);
+ if (is_signed)
+ ret = simple_attr_write_signed(file, buf, len, ppos);
+ else
+ ret = simple_attr_write(file, buf, len, ppos);
debugfs_file_put(dentry);
return ret;
}
+
+ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return debugfs_attr_write_xsigned(file, buf, len, ppos, false);
+}
EXPORT_SYMBOL_GPL(debugfs_attr_write);
+ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return debugfs_attr_write_xsigned(file, buf, len, ppos, true);
+}
+EXPORT_SYMBOL_GPL(debugfs_attr_write_signed);
+
static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
struct dentry *parent, void *value,
const struct file_operations *fops,
@@ -738,11 +754,11 @@ static int debugfs_atomic_t_get(void *data, u64 *val)
*val = atomic_read((atomic_t *)data);
return 0;
}
-DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t, debugfs_atomic_t_get,
debugfs_atomic_t_set, "%lld\n");
-DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL,
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_ro, debugfs_atomic_t_get, NULL,
"%lld\n");
-DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
"%lld\n");
/**
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index d60a8d8f109d..26fef9945cc9 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -12,55 +12,67 @@
#include <trace/events/dlm.h>
#include "dlm_internal.h"
+#include "memory.h"
#include "lock.h"
#include "user.h"
#include "ast.h"
-static uint64_t dlm_cb_seq;
-static DEFINE_SPINLOCK(dlm_cb_seq_spin);
+void dlm_release_callback(struct kref *ref)
+{
+ struct dlm_callback *cb = container_of(ref, struct dlm_callback, ref);
+
+ dlm_free_cb(cb);
+}
+
+void dlm_callback_set_last_ptr(struct dlm_callback **from,
+ struct dlm_callback *to)
+{
+ if (*from)
+ kref_put(&(*from)->ref, dlm_release_callback);
+
+ if (to)
+ kref_get(&to->ref);
+
+ *from = to;
+}
-static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
+void dlm_purge_lkb_callbacks(struct dlm_lkb *lkb)
{
- int i;
-
- log_print("last_bast %x %llu flags %x mode %d sb %d %x",
- lkb->lkb_id,
- (unsigned long long)lkb->lkb_last_bast.seq,
- lkb->lkb_last_bast.flags,
- lkb->lkb_last_bast.mode,
- lkb->lkb_last_bast.sb_status,
- lkb->lkb_last_bast.sb_flags);
-
- log_print("last_cast %x %llu flags %x mode %d sb %d %x",
- lkb->lkb_id,
- (unsigned long long)lkb->lkb_last_cast.seq,
- lkb->lkb_last_cast.flags,
- lkb->lkb_last_cast.mode,
- lkb->lkb_last_cast.sb_status,
- lkb->lkb_last_cast.sb_flags);
-
- for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
- log_print("cb %x %llu flags %x mode %d sb %d %x",
- lkb->lkb_id,
- (unsigned long long)lkb->lkb_callbacks[i].seq,
- lkb->lkb_callbacks[i].flags,
- lkb->lkb_callbacks[i].mode,
- lkb->lkb_callbacks[i].sb_status,
- lkb->lkb_callbacks[i].sb_flags);
+ struct dlm_callback *cb, *safe;
+
+ list_for_each_entry_safe(cb, safe, &lkb->lkb_callbacks, list) {
+ list_del(&cb->list);
+ kref_put(&cb->ref, dlm_release_callback);
}
+
+ lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
+
+ /* invalidate */
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cast, NULL);
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cb, NULL);
+ lkb->lkb_last_bast_mode = -1;
}
-int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
- int status, uint32_t sbflags, uint64_t seq)
+int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
- uint64_t prev_seq;
+ int rv = DLM_ENQUEUE_CALLBACK_SUCCESS;
+ struct dlm_callback *cb;
int prev_mode;
- int i, rv;
- for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
- if (lkb->lkb_callbacks[i].seq)
- continue;
+ if (flags & DLM_CB_BAST) {
+ /* if cb is a bast, it should be skipped if the blocking mode is
+ * compatible with the last granted mode
+ */
+ if (lkb->lkb_last_cast) {
+ if (dlm_modes_compat(mode, lkb->lkb_last_cast->mode)) {
+ log_debug(ls, "skip %x bast mode %d for cast mode %d",
+ lkb->lkb_id, mode,
+ lkb->lkb_last_cast->mode);
+ goto out;
+ }
+ }
/*
* Suppress some redundant basts here, do more on removal.
@@ -68,148 +80,95 @@ int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
* is a bast for the same mode or a more restrictive mode.
* (the addional > PR check is needed for PR/CW inversion)
*/
-
- if ((i > 0) && (flags & DLM_CB_BAST) &&
- (lkb->lkb_callbacks[i-1].flags & DLM_CB_BAST)) {
-
- prev_seq = lkb->lkb_callbacks[i-1].seq;
- prev_mode = lkb->lkb_callbacks[i-1].mode;
+ if (lkb->lkb_last_cb && lkb->lkb_last_cb->flags & DLM_CB_BAST) {
+ prev_mode = lkb->lkb_last_cb->mode;
if ((prev_mode == mode) ||
(prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
-
- log_debug(ls, "skip %x add bast %llu mode %d "
- "for bast %llu mode %d",
- lkb->lkb_id,
- (unsigned long long)seq,
- mode,
- (unsigned long long)prev_seq,
- prev_mode);
- rv = 0;
+ log_debug(ls, "skip %x add bast mode %d for bast mode %d",
+ lkb->lkb_id, mode, prev_mode);
goto out;
}
}
-
- lkb->lkb_callbacks[i].seq = seq;
- lkb->lkb_callbacks[i].flags = flags;
- lkb->lkb_callbacks[i].mode = mode;
- lkb->lkb_callbacks[i].sb_status = status;
- lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF);
- rv = 0;
- break;
}
- if (i == DLM_CALLBACKS_SIZE) {
- log_error(ls, "no callbacks %x %llu flags %x mode %d sb %d %x",
- lkb->lkb_id, (unsigned long long)seq,
- flags, mode, status, sbflags);
- dlm_dump_lkb_callbacks(lkb);
- rv = -1;
+ cb = dlm_allocate_cb();
+ if (!cb) {
+ rv = DLM_ENQUEUE_CALLBACK_FAILURE;
goto out;
}
- out:
- return rv;
-}
-
-int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
- struct dlm_callback *cb, int *resid)
-{
- int i, rv;
-
- *resid = 0;
-
- if (!lkb->lkb_callbacks[0].seq) {
- rv = -ENOENT;
- goto out;
- }
-
- /* oldest undelivered cb is callbacks[0] */
-
- memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback));
- memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback));
- /* shift others down */
-
- for (i = 1; i < DLM_CALLBACKS_SIZE; i++) {
- if (!lkb->lkb_callbacks[i].seq)
- break;
- memcpy(&lkb->lkb_callbacks[i-1], &lkb->lkb_callbacks[i],
- sizeof(struct dlm_callback));
- memset(&lkb->lkb_callbacks[i], 0, sizeof(struct dlm_callback));
- (*resid)++;
+ cb->flags = flags;
+ cb->mode = mode;
+ cb->sb_status = status;
+ cb->sb_flags = (sbflags & 0x000000FF);
+ kref_init(&cb->ref);
+ if (!(lkb->lkb_flags & DLM_IFL_CB_PENDING)) {
+ lkb->lkb_flags |= DLM_IFL_CB_PENDING;
+ rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED;
}
+ list_add_tail(&cb->list, &lkb->lkb_callbacks);
- /* if cb is a bast, it should be skipped if the blocking mode is
- compatible with the last granted mode */
-
- if ((cb->flags & DLM_CB_BAST) && lkb->lkb_last_cast.seq) {
- if (dlm_modes_compat(cb->mode, lkb->lkb_last_cast.mode)) {
- cb->flags |= DLM_CB_SKIP;
-
- log_debug(ls, "skip %x bast %llu mode %d "
- "for cast %llu mode %d",
- lkb->lkb_id,
- (unsigned long long)cb->seq,
- cb->mode,
- (unsigned long long)lkb->lkb_last_cast.seq,
- lkb->lkb_last_cast.mode);
- rv = 0;
- goto out;
- }
- }
+ if (flags & DLM_CB_CAST)
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cast, cb);
- if (cb->flags & DLM_CB_CAST) {
- memcpy(&lkb->lkb_last_cast, cb, sizeof(struct dlm_callback));
- lkb->lkb_last_cast_time = ktime_get();
- }
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cb, cb);
- if (cb->flags & DLM_CB_BAST) {
- memcpy(&lkb->lkb_last_bast, cb, sizeof(struct dlm_callback));
- lkb->lkb_last_bast_time = ktime_get();
- }
- rv = 0;
out:
return rv;
}
+int dlm_dequeue_lkb_callback(struct dlm_lkb *lkb, struct dlm_callback **cb)
+{
+ /* oldest undelivered cb is callbacks first entry */
+ *cb = list_first_entry_or_null(&lkb->lkb_callbacks,
+ struct dlm_callback, list);
+ if (!*cb)
+ return DLM_DEQUEUE_CALLBACK_EMPTY;
+
+ /* remove it from callbacks so shift others down */
+ list_del(&(*cb)->list);
+ if (list_empty(&lkb->lkb_callbacks))
+ return DLM_DEQUEUE_CALLBACK_LAST;
+
+ return DLM_DEQUEUE_CALLBACK_SUCCESS;
+}
+
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
uint32_t sbflags)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
- uint64_t new_seq, prev_seq;
int rv;
- spin_lock(&dlm_cb_seq_spin);
- new_seq = ++dlm_cb_seq;
- if (!dlm_cb_seq)
- new_seq = ++dlm_cb_seq;
- spin_unlock(&dlm_cb_seq_spin);
-
if (lkb->lkb_flags & DLM_IFL_USER) {
- dlm_user_add_ast(lkb, flags, mode, status, sbflags, new_seq);
+ dlm_user_add_ast(lkb, flags, mode, status, sbflags);
return;
}
- mutex_lock(&lkb->lkb_cb_mutex);
- prev_seq = lkb->lkb_callbacks[0].seq;
-
- rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, new_seq);
- if (rv < 0)
- goto out;
-
- if (!prev_seq) {
+ spin_lock(&lkb->lkb_cb_lock);
+ rv = dlm_enqueue_lkb_callback(lkb, flags, mode, status, sbflags);
+ switch (rv) {
+ case DLM_ENQUEUE_CALLBACK_NEED_SCHED:
kref_get(&lkb->lkb_ref);
- mutex_lock(&ls->ls_cb_mutex);
+ spin_lock(&ls->ls_cb_lock);
if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) {
list_add(&lkb->lkb_cb_list, &ls->ls_cb_delay);
} else {
queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
}
- mutex_unlock(&ls->ls_cb_mutex);
+ spin_unlock(&ls->ls_cb_lock);
+ break;
+ case DLM_ENQUEUE_CALLBACK_FAILURE:
+ WARN_ON_ONCE(1);
+ break;
+ case DLM_ENQUEUE_CALLBACK_SUCCESS:
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
}
- out:
- mutex_unlock(&lkb->lkb_cb_mutex);
+ spin_unlock(&lkb->lkb_cb_lock);
}
void dlm_callback_work(struct work_struct *work)
@@ -218,53 +177,46 @@ void dlm_callback_work(struct work_struct *work)
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
void (*castfn) (void *astparam);
void (*bastfn) (void *astparam, int mode);
- struct dlm_callback callbacks[DLM_CALLBACKS_SIZE];
- int i, rv, resid;
-
- memset(&callbacks, 0, sizeof(callbacks));
+ struct dlm_callback *cb;
+ int rv;
- mutex_lock(&lkb->lkb_cb_mutex);
- if (!lkb->lkb_callbacks[0].seq) {
- /* no callback work exists, shouldn't happen */
- log_error(ls, "dlm_callback_work %x no work", lkb->lkb_id);
- dlm_print_lkb(lkb);
- dlm_dump_lkb_callbacks(lkb);
- }
+ spin_lock(&lkb->lkb_cb_lock);
+ rv = dlm_dequeue_lkb_callback(lkb, &cb);
+ spin_unlock(&lkb->lkb_cb_lock);
- for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
- rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid);
- if (rv < 0)
- break;
- }
+ if (WARN_ON_ONCE(rv == DLM_DEQUEUE_CALLBACK_EMPTY))
+ goto out;
- if (resid) {
- /* cbs remain, loop should have removed all, shouldn't happen */
- log_error(ls, "dlm_callback_work %x resid %d", lkb->lkb_id,
- resid);
- dlm_print_lkb(lkb);
- dlm_dump_lkb_callbacks(lkb);
- }
- mutex_unlock(&lkb->lkb_cb_mutex);
+ for (;;) {
+ castfn = lkb->lkb_astfn;
+ bastfn = lkb->lkb_bastfn;
+
+ if (cb->flags & DLM_CB_BAST) {
+ trace_dlm_bast(ls, lkb, cb->mode);
+ lkb->lkb_last_bast_time = ktime_get();
+ lkb->lkb_last_bast_mode = cb->mode;
+ bastfn(lkb->lkb_astparam, cb->mode);
+ } else if (cb->flags & DLM_CB_CAST) {
+ lkb->lkb_lksb->sb_status = cb->sb_status;
+ lkb->lkb_lksb->sb_flags = cb->sb_flags;
+ trace_dlm_ast(ls, lkb);
+ lkb->lkb_last_cast_time = ktime_get();
+ castfn(lkb->lkb_astparam);
+ }
- castfn = lkb->lkb_astfn;
- bastfn = lkb->lkb_bastfn;
+ kref_put(&cb->ref, dlm_release_callback);
- for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
- if (!callbacks[i].seq)
+ spin_lock(&lkb->lkb_cb_lock);
+ rv = dlm_dequeue_lkb_callback(lkb, &cb);
+ if (rv == DLM_DEQUEUE_CALLBACK_EMPTY) {
+ lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
+ spin_unlock(&lkb->lkb_cb_lock);
break;
- if (callbacks[i].flags & DLM_CB_SKIP) {
- continue;
- } else if (callbacks[i].flags & DLM_CB_BAST) {
- trace_dlm_bast(ls, lkb, callbacks[i].mode);
- bastfn(lkb->lkb_astparam, callbacks[i].mode);
- } else if (callbacks[i].flags & DLM_CB_CAST) {
- lkb->lkb_lksb->sb_status = callbacks[i].sb_status;
- lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags;
- trace_dlm_ast(ls, lkb);
- castfn(lkb->lkb_astparam);
}
+ spin_unlock(&lkb->lkb_cb_lock);
}
+out:
/* undo kref_get from dlm_add_callback, may cause lkb to be freed */
dlm_put_lkb(lkb);
}
@@ -289,9 +241,9 @@ void dlm_callback_stop(struct dlm_ls *ls)
void dlm_callback_suspend(struct dlm_ls *ls)
{
if (ls->ls_callback_wq) {
- mutex_lock(&ls->ls_cb_mutex);
+ spin_lock(&ls->ls_cb_lock);
set_bit(LSFL_CB_DELAY, &ls->ls_flags);
- mutex_unlock(&ls->ls_cb_mutex);
+ spin_unlock(&ls->ls_cb_lock);
flush_workqueue(ls->ls_callback_wq);
}
@@ -308,10 +260,8 @@ void dlm_callback_resume(struct dlm_ls *ls)
if (!ls->ls_callback_wq)
return;
- clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
-
more:
- mutex_lock(&ls->ls_cb_mutex);
+ spin_lock(&ls->ls_cb_lock);
list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) {
list_del_init(&lkb->lkb_cb_list);
queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
@@ -320,7 +270,9 @@ more:
break;
}
empty = list_empty(&ls->ls_cb_delay);
- mutex_unlock(&ls->ls_cb_mutex);
+ if (empty)
+ clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
+ spin_unlock(&ls->ls_cb_lock);
sum += count;
if (!empty) {
diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h
index e5e05fcc5813..880b11882495 100644
--- a/fs/dlm/ast.h
+++ b/fs/dlm/ast.h
@@ -11,13 +11,22 @@
#ifndef __ASTD_DOT_H__
#define __ASTD_DOT_H__
-int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
- int status, uint32_t sbflags, uint64_t seq);
-int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
- struct dlm_callback *cb, int *resid);
+#define DLM_ENQUEUE_CALLBACK_NEED_SCHED 1
+#define DLM_ENQUEUE_CALLBACK_SUCCESS 0
+#define DLM_ENQUEUE_CALLBACK_FAILURE -1
+int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags);
+#define DLM_DEQUEUE_CALLBACK_EMPTY 2
+#define DLM_DEQUEUE_CALLBACK_LAST 1
+#define DLM_DEQUEUE_CALLBACK_SUCCESS 0
+int dlm_dequeue_lkb_callback(struct dlm_lkb *lkb, struct dlm_callback **cb);
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
uint32_t sbflags);
+void dlm_callback_set_last_ptr(struct dlm_callback **from,
+ struct dlm_callback *to);
+void dlm_release_callback(struct kref *ref);
+void dlm_purge_lkb_callbacks(struct dlm_lkb *lkb);
void dlm_callback_work(struct work_struct *work);
int dlm_callback_start(struct dlm_ls *ls);
void dlm_callback_stop(struct dlm_ls *ls);
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index ac8b62106ce0..20b60709eccf 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -183,7 +183,7 @@ static int dlm_check_protocol_and_dlm_running(unsigned int x)
return -EINVAL;
}
- if (dlm_allow_conn)
+ if (dlm_lowcomms_is_running())
return -EBUSY;
return 0;
@@ -194,7 +194,7 @@ static int dlm_check_zero_and_dlm_running(unsigned int x)
if (!x)
return -EINVAL;
- if (dlm_allow_conn)
+ if (dlm_lowcomms_is_running())
return -EBUSY;
return 0;
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
index 8fb04ebbafb5..8a0e1b1f74ad 100644
--- a/fs/dlm/debug_fs.c
+++ b/fs/dlm/debug_fs.c
@@ -246,7 +246,7 @@ static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
lkb->lkb_status,
lkb->lkb_grmode,
lkb->lkb_rqmode,
- lkb->lkb_last_bast.mode,
+ lkb->lkb_last_bast_mode,
rsb_lookup,
lkb->lkb_wait_type,
lkb->lkb_lvbseq,
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index e34c3d2639a5..ab1a55337a6e 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -211,6 +211,7 @@ struct dlm_args {
#endif
#define DLM_IFL_DEADLOCK_CANCEL 0x01000000
#define DLM_IFL_STUB_MS 0x02000000 /* magic number for m_flags */
+#define DLM_IFL_CB_PENDING 0x04000000
/* least significant 2 bytes are message changed, they are full transmitted
* but at receive side only the 2 bytes LSB will be set.
*
@@ -222,18 +223,17 @@ struct dlm_args {
#define DLM_IFL_USER 0x00000001
#define DLM_IFL_ORPHAN 0x00000002
-#define DLM_CALLBACKS_SIZE 6
-
#define DLM_CB_CAST 0x00000001
#define DLM_CB_BAST 0x00000002
-#define DLM_CB_SKIP 0x00000004
struct dlm_callback {
- uint64_t seq;
uint32_t flags; /* DLM_CBF_ */
int sb_status; /* copy to lksb status */
uint8_t sb_flags; /* copy to lksb flags */
int8_t mode; /* rq mode of bast, gr mode of cast */
+
+ struct list_head list;
+ struct kref ref;
};
struct dlm_lkb {
@@ -268,12 +268,13 @@ struct dlm_lkb {
unsigned long lkb_timeout_cs;
#endif
- struct mutex lkb_cb_mutex;
+ spinlock_t lkb_cb_lock;
struct work_struct lkb_cb_work;
struct list_head lkb_cb_list; /* for ls_cb_delay or proc->asts */
- struct dlm_callback lkb_callbacks[DLM_CALLBACKS_SIZE];
- struct dlm_callback lkb_last_cast;
- struct dlm_callback lkb_last_bast;
+ struct list_head lkb_callbacks;
+ struct dlm_callback *lkb_last_cast;
+ struct dlm_callback *lkb_last_cb;
+ int lkb_last_bast_mode;
ktime_t lkb_last_cast_time; /* for debugging */
ktime_t lkb_last_bast_time; /* for debugging */
@@ -591,11 +592,7 @@ struct dlm_ls {
int ls_new_rsb_count;
struct list_head ls_new_rsb; /* new rsb structs */
- spinlock_t ls_remove_spin;
- wait_queue_head_t ls_remove_wait;
- char ls_remove_name[DLM_RESNAME_MAXLEN+1];
char *ls_remove_names[DLM_REMOVE_NAMES_MAX];
- int ls_remove_len;
int ls_remove_lens[DLM_REMOVE_NAMES_MAX];
struct list_head ls_nodes; /* current nodes in ls */
@@ -631,7 +628,7 @@ struct dlm_ls {
/* recovery related */
- struct mutex ls_cb_mutex;
+ spinlock_t ls_cb_lock;
struct list_head ls_cb_delay; /* save for queue_work later */
struct timer_list ls_timer;
struct task_struct *ls_recoverd_task;
@@ -670,7 +667,7 @@ struct dlm_ls {
void *ls_ops_arg;
int ls_namelen;
- char ls_name[1];
+ char ls_name[DLM_LOCKSPACE_LEN + 1];
};
/*
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 94a72ede5764..e1adfa5aed05 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -1209,6 +1209,7 @@ static int _create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret,
if (!lkb)
return -ENOMEM;
+ lkb->lkb_last_bast_mode = -1;
lkb->lkb_nodeid = -1;
lkb->lkb_grmode = DLM_LOCK_IV;
kref_init(&lkb->lkb_ref);
@@ -1218,7 +1219,8 @@ static int _create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret,
INIT_LIST_HEAD(&lkb->lkb_time_list);
#endif
INIT_LIST_HEAD(&lkb->lkb_cb_list);
- mutex_init(&lkb->lkb_cb_mutex);
+ INIT_LIST_HEAD(&lkb->lkb_callbacks);
+ spin_lock_init(&lkb->lkb_cb_lock);
INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work);
idr_preload(GFP_NOFS);
@@ -1587,37 +1589,6 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
return error;
}
-/* If there's an rsb for the same resource being removed, ensure
- * that the remove message is sent before the new lookup message.
- */
-
-#define DLM_WAIT_PENDING_COND(ls, r) \
- (ls->ls_remove_len && \
- !rsb_cmp(r, ls->ls_remove_name, \
- ls->ls_remove_len))
-
-static void wait_pending_remove(struct dlm_rsb *r)
-{
- struct dlm_ls *ls = r->res_ls;
- restart:
- spin_lock(&ls->ls_remove_spin);
- if (DLM_WAIT_PENDING_COND(ls, r)) {
- log_debug(ls, "delay lookup for remove dir %d %s",
- r->res_dir_nodeid, r->res_name);
- spin_unlock(&ls->ls_remove_spin);
- wait_event(ls->ls_remove_wait, !DLM_WAIT_PENDING_COND(ls, r));
- goto restart;
- }
- spin_unlock(&ls->ls_remove_spin);
-}
-
-/*
- * ls_remove_spin protects ls_remove_name and ls_remove_len which are
- * read by other threads in wait_pending_remove. ls_remove_names
- * and ls_remove_lens are only used by the scan thread, so they do
- * not need protection.
- */
-
static void shrink_bucket(struct dlm_ls *ls, int b)
{
struct rb_node *n, *next;
@@ -1699,11 +1670,6 @@ static void shrink_bucket(struct dlm_ls *ls, int b)
* list and sending the removal. Keeping this gap small is
* important to keep us (the master node) from being out of sync
* with the remote dir node for very long.
- *
- * From the time the rsb is removed from toss until just after
- * send_remove, the rsb name is saved in ls_remove_name. A new
- * lookup checks this to ensure that a new lookup message for the
- * same resource name is not sent just before the remove message.
*/
for (i = 0; i < remote_count; i++) {
@@ -1750,22 +1716,8 @@ static void shrink_bucket(struct dlm_ls *ls, int b)
}
rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
-
- /* block lookup of same name until we've sent remove */
- spin_lock(&ls->ls_remove_spin);
- ls->ls_remove_len = len;
- memcpy(ls->ls_remove_name, name, DLM_RESNAME_MAXLEN);
- spin_unlock(&ls->ls_remove_spin);
- spin_unlock(&ls->ls_rsbtbl[b].lock);
-
send_remove(r);
-
- /* allow lookup of name again */
- spin_lock(&ls->ls_remove_spin);
- ls->ls_remove_len = 0;
- memset(ls->ls_remove_name, 0, DLM_RESNAME_MAXLEN);
- spin_unlock(&ls->ls_remove_spin);
- wake_up(&ls->ls_remove_wait);
+ spin_unlock(&ls->ls_rsbtbl[b].lock);
dlm_free_rsb(r);
}
@@ -2716,8 +2668,6 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
return 0;
}
- wait_pending_remove(r);
-
r->res_first_lkid = lkb->lkb_id;
send_lookup(r, lkb);
return 1;
@@ -3552,7 +3502,8 @@ int dlm_unlock(dlm_lockspace_t *lockspace,
static int _create_message(struct dlm_ls *ls, int mb_len,
int to_nodeid, int mstype,
struct dlm_message **ms_ret,
- struct dlm_mhandle **mh_ret)
+ struct dlm_mhandle **mh_ret,
+ gfp_t allocation)
{
struct dlm_message *ms;
struct dlm_mhandle *mh;
@@ -3562,7 +3513,7 @@ static int _create_message(struct dlm_ls *ls, int mb_len,
pass into midcomms_commit and a message buffer (mb) that we
write our data into */
- mh = dlm_midcomms_get_mhandle(to_nodeid, mb_len, GFP_NOFS, &mb);
+ mh = dlm_midcomms_get_mhandle(to_nodeid, mb_len, allocation, &mb);
if (!mh)
return -ENOBUFS;
@@ -3584,7 +3535,8 @@ static int _create_message(struct dlm_ls *ls, int mb_len,
static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
int to_nodeid, int mstype,
struct dlm_message **ms_ret,
- struct dlm_mhandle **mh_ret)
+ struct dlm_mhandle **mh_ret,
+ gfp_t allocation)
{
int mb_len = sizeof(struct dlm_message);
@@ -3605,15 +3557,16 @@ static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
}
return _create_message(r->res_ls, mb_len, to_nodeid, mstype,
- ms_ret, mh_ret);
+ ms_ret, mh_ret, allocation);
}
/* further lowcomms enhancements or alternate implementations may make
the return value from this function useful at some point */
-static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)
+static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms,
+ const void *name, int namelen)
{
- dlm_midcomms_commit_mhandle(mh);
+ dlm_midcomms_commit_mhandle(mh, name, namelen);
return 0;
}
@@ -3673,13 +3626,13 @@ static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
if (error)
return error;
- error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh, GFP_NOFS);
if (error)
goto fail;
send_args(r, lkb, ms);
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
if (error)
goto fail;
return 0;
@@ -3734,7 +3687,8 @@ static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
to_nodeid = lkb->lkb_nodeid;
- error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh);
+ error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh,
+ GFP_NOFS);
if (error)
goto out;
@@ -3742,7 +3696,7 @@ static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
ms->m_result = 0;
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
out:
return error;
}
@@ -3755,7 +3709,8 @@ static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
to_nodeid = lkb->lkb_nodeid;
- error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh);
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh,
+ GFP_NOFS);
if (error)
goto out;
@@ -3763,7 +3718,7 @@ static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
ms->m_bastmode = cpu_to_le32(mode);
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
out:
return error;
}
@@ -3780,13 +3735,14 @@ static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
if (error)
return error;
- error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh,
+ GFP_NOFS);
if (error)
goto fail;
send_args(r, lkb, ms);
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
if (error)
goto fail;
return 0;
@@ -3804,14 +3760,15 @@ static int send_remove(struct dlm_rsb *r)
to_nodeid = dlm_dir_nodeid(r);
- error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh);
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh,
+ GFP_ATOMIC);
if (error)
goto out;
memcpy(ms->m_extra, r->res_name, r->res_length);
ms->m_hash = cpu_to_le32(r->res_hash);
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
out:
return error;
}
@@ -3825,7 +3782,7 @@ static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
to_nodeid = lkb->lkb_nodeid;
- error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh, GFP_NOFS);
if (error)
goto out;
@@ -3833,7 +3790,7 @@ static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
ms->m_result = cpu_to_le32(to_dlm_errno(rv));
- error = send_message(mh, ms);
+ error = send_message(mh, ms, r->res_name, r->res_length);
out:
return error;
}
@@ -3866,7 +3823,8 @@ static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
struct dlm_mhandle *mh;
int error, nodeid = le32_to_cpu(ms_in->m_header.h_nodeid);
- error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh);
+ error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh,
+ GFP_NOFS);
if (error)
goto out;
@@ -3874,7 +3832,7 @@ static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
ms->m_result = cpu_to_le32(to_dlm_errno(rv));
ms->m_nodeid = cpu_to_le32(ret_nodeid);
- error = send_message(mh, ms);
+ error = send_message(mh, ms, ms_in->m_extra, receive_extralen(ms_in));
out:
return error;
}
@@ -4044,66 +4002,6 @@ out:
return error;
}
-static void send_repeat_remove(struct dlm_ls *ls, char *ms_name, int len)
-{
- char name[DLM_RESNAME_MAXLEN + 1];
- struct dlm_message *ms;
- struct dlm_mhandle *mh;
- struct dlm_rsb *r;
- uint32_t hash, b;
- int rv, dir_nodeid;
-
- memset(name, 0, sizeof(name));
- memcpy(name, ms_name, len);
-
- hash = jhash(name, len, 0);
- b = hash & (ls->ls_rsbtbl_size - 1);
-
- dir_nodeid = dlm_hash2nodeid(ls, hash);
-
- log_error(ls, "send_repeat_remove dir %d %s", dir_nodeid, name);
-
- spin_lock(&ls->ls_rsbtbl[b].lock);
- rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
- if (!rv) {
- spin_unlock(&ls->ls_rsbtbl[b].lock);
- log_error(ls, "repeat_remove on keep %s", name);
- return;
- }
-
- rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
- if (!rv) {
- spin_unlock(&ls->ls_rsbtbl[b].lock);
- log_error(ls, "repeat_remove on toss %s", name);
- return;
- }
-
- /* use ls->remove_name2 to avoid conflict with shrink? */
-
- spin_lock(&ls->ls_remove_spin);
- ls->ls_remove_len = len;
- memcpy(ls->ls_remove_name, name, DLM_RESNAME_MAXLEN);
- spin_unlock(&ls->ls_remove_spin);
- spin_unlock(&ls->ls_rsbtbl[b].lock);
-
- rv = _create_message(ls, sizeof(struct dlm_message) + len,
- dir_nodeid, DLM_MSG_REMOVE, &ms, &mh);
- if (rv)
- goto out;
-
- memcpy(ms->m_extra, name, len);
- ms->m_hash = cpu_to_le32(hash);
-
- send_message(mh, ms);
-
-out:
- spin_lock(&ls->ls_remove_spin);
- ls->ls_remove_len = 0;
- memset(ls->ls_remove_name, 0, DLM_RESNAME_MAXLEN);
- spin_unlock(&ls->ls_remove_spin);
- wake_up(&ls->ls_remove_wait);
-}
-
static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
@@ -4173,25 +4071,11 @@ static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
ENOTBLK request failures when the lookup reply designating us
as master is delayed. */
- /* We could repeatedly return -EBADR here if our send_remove() is
- delayed in being sent/arriving/being processed on the dir node.
- Another node would repeatedly lookup up the master, and the dir
- node would continue returning our nodeid until our send_remove
- took effect.
-
- We send another remove message in case our previous send_remove
- was lost/ignored/missed somehow. */
-
if (error != -ENOTBLK) {
log_limit(ls, "receive_request %x from %d %d",
le32_to_cpu(ms->m_lkid), from_nodeid, error);
}
- if (namelen && error == -EBADR) {
- send_repeat_remove(ls, ms->m_extra, namelen);
- msleep(1000);
- }
-
setup_stub_lkb(ls, ms);
send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
return error;
@@ -6294,8 +6178,7 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
}
list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_cb_list) {
- memset(&lkb->lkb_callbacks, 0,
- sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE);
+ dlm_purge_lkb_callbacks(lkb);
list_del_init(&lkb->lkb_cb_list);
dlm_put_lkb(lkb);
}
@@ -6336,8 +6219,7 @@ static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
spin_lock(&proc->asts_spin);
list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_cb_list) {
- memset(&lkb->lkb_callbacks, 0,
- sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE);
+ dlm_purge_lkb_callbacks(lkb);
list_del_init(&lkb->lkb_cb_list);
dlm_put_lkb(lkb);
}
@@ -6368,13 +6250,13 @@ static int send_purge(struct dlm_ls *ls, int nodeid, int pid)
int error;
error = _create_message(ls, sizeof(struct dlm_message), nodeid,
- DLM_MSG_PURGE, &ms, &mh);
+ DLM_MSG_PURGE, &ms, &mh, GFP_NOFS);
if (error)
return error;
ms->m_nodeid = cpu_to_le32(nodeid);
ms->m_pid = cpu_to_le32(pid);
- return send_message(mh, ms);
+ return send_message(mh, ms, NULL, 0);
}
int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index bae050df7abf..d0b4e2181a5f 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -17,7 +17,6 @@
#include "recoverd.h"
#include "dir.h"
#include "midcomms.h"
-#include "lowcomms.h"
#include "config.h"
#include "memory.h"
#include "lock.h"
@@ -391,7 +390,7 @@ static int threads_start(void)
/* Thread for sending/receiving messages for all lockspace's */
error = dlm_midcomms_start();
if (error) {
- log_print("cannot start dlm lowcomms %d", error);
+ log_print("cannot start dlm midcomms %d", error);
goto scand_fail;
}
@@ -473,7 +472,7 @@ static int new_lockspace(const char *name, const char *cluster,
error = -ENOMEM;
- ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_NOFS);
+ ls = kzalloc(sizeof(*ls), GFP_NOFS);
if (!ls)
goto out;
memcpy(ls->ls_name, name, namelen);
@@ -524,9 +523,6 @@ static int new_lockspace(const char *name, const char *cluster,
spin_lock_init(&ls->ls_rsbtbl[i].lock);
}
- spin_lock_init(&ls->ls_remove_spin);
- init_waitqueue_head(&ls->ls_remove_wait);
-
for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) {
ls->ls_remove_names[i] = kzalloc(DLM_RESNAME_MAXLEN+1,
GFP_KERNEL);
@@ -567,7 +563,7 @@ static int new_lockspace(const char *name, const char *cluster,
init_completion(&ls->ls_recovery_done);
ls->ls_recovery_result = -1;
- mutex_init(&ls->ls_cb_mutex);
+ spin_lock_init(&ls->ls_cb_lock);
INIT_LIST_HEAD(&ls->ls_cb_delay);
ls->ls_recoverd_task = NULL;
@@ -726,7 +722,7 @@ static int __dlm_new_lockspace(const char *name, const char *cluster,
if (!ls_count) {
dlm_scand_stop();
dlm_midcomms_shutdown();
- dlm_lowcomms_stop();
+ dlm_midcomms_stop();
}
out:
mutex_unlock(&ls_lock);
@@ -929,7 +925,7 @@ int dlm_release_lockspace(void *lockspace, int force)
if (!error)
ls_count--;
if (!ls_count)
- dlm_lowcomms_stop();
+ dlm_midcomms_stop();
mutex_unlock(&ls_lock);
return error;
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 59f64c596233..8b80ca0cd65f 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -63,41 +63,49 @@
#define NEEDED_RMEM (4*1024*1024)
-/* Number of messages to send before rescheduling */
-#define MAX_SEND_MSG_COUNT 25
-#define DLM_SHUTDOWN_WAIT_TIMEOUT msecs_to_jiffies(10000)
-
struct connection {
struct socket *sock; /* NULL if not connected */
uint32_t nodeid; /* So we know who we are in the list */
- struct mutex sock_mutex;
+ /* this semaphore is used to allow parallel recv/send in read
+ * lock mode. When we release a sock we need to held the write lock.
+ *
+ * However this is locking code and not nice. When we remove the
+ * othercon handling we can look into other mechanism to synchronize
+ * io handling to call sock_release() at the right time.
+ */
+ struct rw_semaphore sock_lock;
unsigned long flags;
-#define CF_READ_PENDING 1
-#define CF_WRITE_PENDING 2
-#define CF_INIT_PENDING 4
+#define CF_APP_LIMITED 0
+#define CF_RECV_PENDING 1
+#define CF_SEND_PENDING 2
+#define CF_RECV_INTR 3
+#define CF_IO_STOP 4
#define CF_IS_OTHERCON 5
-#define CF_CLOSE 6
-#define CF_APP_LIMITED 7
-#define CF_CLOSING 8
-#define CF_SHUTDOWN 9
-#define CF_CONNECTED 10
-#define CF_RECONNECT 11
-#define CF_DELAY_CONNECT 12
-#define CF_EOF 13
struct list_head writequeue; /* List of outgoing writequeue_entries */
spinlock_t writequeue_lock;
- atomic_t writequeue_cnt;
int retries;
-#define MAX_CONNECT_RETRIES 3
struct hlist_node list;
+ /* due some connect()/accept() races we currently have this cross over
+ * connection attempt second connection for one node.
+ *
+ * There is a solution to avoid the race by introducing a connect
+ * rule as e.g. our_nodeid > nodeid_to_connect who is allowed to
+ * connect. Otherside can connect but will only be considered that
+ * the other side wants to have a reconnect.
+ *
+ * However changing to this behaviour will break backwards compatible.
+ * In a DLM protocol major version upgrade we should remove this!
+ */
struct connection *othercon;
- struct connection *sendcon;
- struct work_struct rwork; /* Receive workqueue */
- struct work_struct swork; /* Send workqueue */
- wait_queue_head_t shutdown_wait; /* wait for graceful shutdown */
- unsigned char *rx_buf;
- int rx_buflen;
+ struct work_struct rwork; /* receive worker */
+ struct work_struct swork; /* send worker */
+ unsigned char rx_leftover_buf[DLM_MAX_SOCKET_BUFSIZE];
int rx_leftover;
+ int mark;
+ int addr_count;
+ int curr_addr_index;
+ struct sockaddr_storage addr[DLM_MAX_ADDR_COUNT];
+ spinlock_t addrs_lock;
struct rcu_head rcu;
};
#define sock2con(x) ((struct connection *)(x)->sk_user_data)
@@ -136,13 +144,12 @@ struct dlm_msg {
struct kref ref;
};
-struct dlm_node_addr {
- struct list_head list;
+struct processqueue_entry {
+ unsigned char *buf;
int nodeid;
- int mark;
- int addr_count;
- int curr_addr_index;
- struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+ int buflen;
+
+ struct list_head list;
};
struct dlm_proto_ops {
@@ -157,10 +164,6 @@ struct dlm_proto_ops {
int (*listen_validate)(void);
void (*listen_sockopts)(struct socket *sock);
int (*listen_bind)(struct socket *sock);
- /* What to do to shutdown */
- void (*shutdown_action)(struct connection *con);
- /* What to do to eof check */
- bool (*eof_condition)(struct connection *con);
};
static struct listen_sock_callbacks {
@@ -170,17 +173,13 @@ static struct listen_sock_callbacks {
void (*sk_write_space)(struct sock *);
} listen_sock;
-static LIST_HEAD(dlm_node_addrs);
-static DEFINE_SPINLOCK(dlm_node_addrs_spin);
-
static struct listen_connection listen_con;
-static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
+static struct sockaddr_storage dlm_local_addr[DLM_MAX_ADDR_COUNT];
static int dlm_local_count;
-int dlm_allow_conn;
/* Work queues */
-static struct workqueue_struct *recv_workqueue;
-static struct workqueue_struct *send_workqueue;
+static struct workqueue_struct *io_workqueue;
+static struct workqueue_struct *process_workqueue;
static struct hlist_head connection_hash[CONN_HASH_SIZE];
static DEFINE_SPINLOCK(connections_lock);
@@ -188,8 +187,45 @@ DEFINE_STATIC_SRCU(connections_srcu);
static const struct dlm_proto_ops *dlm_proto_ops;
+#define DLM_IO_SUCCESS 0
+#define DLM_IO_END 1
+#define DLM_IO_EOF 2
+#define DLM_IO_RESCHED 3
+
static void process_recv_sockets(struct work_struct *work);
static void process_send_sockets(struct work_struct *work);
+static void process_dlm_messages(struct work_struct *work);
+
+static DECLARE_WORK(process_work, process_dlm_messages);
+static DEFINE_SPINLOCK(processqueue_lock);
+static bool process_dlm_messages_pending;
+static LIST_HEAD(processqueue);
+
+bool dlm_lowcomms_is_running(void)
+{
+ return !!listen_con.sock;
+}
+
+static void lowcomms_queue_swork(struct connection *con)
+{
+ assert_spin_locked(&con->writequeue_lock);
+
+ if (!test_bit(CF_IO_STOP, &con->flags) &&
+ !test_bit(CF_APP_LIMITED, &con->flags) &&
+ !test_and_set_bit(CF_SEND_PENDING, &con->flags))
+ queue_work(io_workqueue, &con->swork);
+}
+
+static void lowcomms_queue_rwork(struct connection *con)
+{
+#ifdef CONFIG_LOCKDEP
+ WARN_ON_ONCE(!lockdep_sock_is_held(con->sock->sk));
+#endif
+
+ if (!test_bit(CF_IO_STOP, &con->flags) &&
+ !test_and_set_bit(CF_RECV_PENDING, &con->flags))
+ queue_work(io_workqueue, &con->rwork);
+}
static void writequeue_entry_ctor(void *data)
{
@@ -214,15 +250,12 @@ static struct writequeue_entry *con_next_wq(struct connection *con)
{
struct writequeue_entry *e;
- if (list_empty(&con->writequeue))
- return NULL;
-
- e = list_first_entry(&con->writequeue, struct writequeue_entry,
- list);
+ e = list_first_entry_or_null(&con->writequeue, struct writequeue_entry,
+ list);
/* if len is zero nothing is to send, if there are users filling
* buffers we wait until the users are done so we can send more.
*/
- if (e->users || e->len == 0)
+ if (!e || e->users || e->len == 0)
return NULL;
return e;
@@ -240,28 +273,15 @@ static struct connection *__find_con(int nodeid, int r)
return NULL;
}
-static bool tcp_eof_condition(struct connection *con)
-{
- return atomic_read(&con->writequeue_cnt);
-}
-
-static int dlm_con_init(struct connection *con, int nodeid)
+static void dlm_con_init(struct connection *con, int nodeid)
{
- con->rx_buflen = dlm_config.ci_buffer_size;
- con->rx_buf = kmalloc(con->rx_buflen, GFP_NOFS);
- if (!con->rx_buf)
- return -ENOMEM;
-
con->nodeid = nodeid;
- mutex_init(&con->sock_mutex);
+ init_rwsem(&con->sock_lock);
INIT_LIST_HEAD(&con->writequeue);
spin_lock_init(&con->writequeue_lock);
- atomic_set(&con->writequeue_cnt, 0);
INIT_WORK(&con->swork, process_send_sockets);
INIT_WORK(&con->rwork, process_recv_sockets);
- init_waitqueue_head(&con->shutdown_wait);
-
- return 0;
+ spin_lock_init(&con->addrs_lock);
}
/*
@@ -271,7 +291,7 @@ static int dlm_con_init(struct connection *con, int nodeid)
static struct connection *nodeid2con(int nodeid, gfp_t alloc)
{
struct connection *con, *tmp;
- int r, ret;
+ int r;
r = nodeid_hash(nodeid);
con = __find_con(nodeid, r);
@@ -282,11 +302,7 @@ static struct connection *nodeid2con(int nodeid, gfp_t alloc)
if (!con)
return NULL;
- ret = dlm_con_init(con, nodeid);
- if (ret) {
- kfree(con);
- return NULL;
- }
+ dlm_con_init(con, nodeid);
spin_lock(&connections_lock);
/* Because multiple workqueues/threads calls this function it can
@@ -298,7 +314,6 @@ static struct connection *nodeid2con(int nodeid, gfp_t alloc)
tmp = __find_con(nodeid, r);
if (tmp) {
spin_unlock(&connections_lock);
- kfree(con->rx_buf);
kfree(con);
return tmp;
}
@@ -309,29 +324,6 @@ static struct connection *nodeid2con(int nodeid, gfp_t alloc)
return con;
}
-/* Loop round all connections */
-static void foreach_conn(void (*conn_func)(struct connection *c))
-{
- int i;
- struct connection *con;
-
- for (i = 0; i < CONN_HASH_SIZE; i++) {
- hlist_for_each_entry_rcu(con, &connection_hash[i], list)
- conn_func(con);
- }
-}
-
-static struct dlm_node_addr *find_node_addr(int nodeid)
-{
- struct dlm_node_addr *na;
-
- list_for_each_entry(na, &dlm_node_addrs, list) {
- if (na->nodeid == nodeid)
- return na;
- }
- return NULL;
-}
-
static int addr_compare(const struct sockaddr_storage *x,
const struct sockaddr_storage *y)
{
@@ -365,40 +357,47 @@ static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
unsigned int *mark)
{
struct sockaddr_storage sas;
- struct dlm_node_addr *na;
+ struct connection *con;
+ int idx;
if (!dlm_local_count)
return -1;
- spin_lock(&dlm_node_addrs_spin);
- na = find_node_addr(nodeid);
- if (na && na->addr_count) {
- memcpy(&sas, na->addr[na->curr_addr_index],
- sizeof(struct sockaddr_storage));
+ idx = srcu_read_lock(&connections_srcu);
+ con = nodeid2con(nodeid, 0);
+ if (!con) {
+ srcu_read_unlock(&connections_srcu, idx);
+ return -ENOENT;
+ }
- if (try_new_addr) {
- na->curr_addr_index++;
- if (na->curr_addr_index == na->addr_count)
- na->curr_addr_index = 0;
- }
+ spin_lock(&con->addrs_lock);
+ if (!con->addr_count) {
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
+ return -ENOENT;
}
- spin_unlock(&dlm_node_addrs_spin);
- if (!na)
- return -EEXIST;
+ memcpy(&sas, &con->addr[con->curr_addr_index],
+ sizeof(struct sockaddr_storage));
- if (!na->addr_count)
- return -ENOENT;
+ if (try_new_addr) {
+ con->curr_addr_index++;
+ if (con->curr_addr_index == con->addr_count)
+ con->curr_addr_index = 0;
+ }
- *mark = na->mark;
+ *mark = con->mark;
+ spin_unlock(&con->addrs_lock);
if (sas_out)
memcpy(sas_out, &sas, sizeof(struct sockaddr_storage));
- if (!sa_out)
+ if (!sa_out) {
+ srcu_read_unlock(&connections_srcu, idx);
return 0;
+ }
- if (dlm_local_addr[0]->ss_family == AF_INET) {
+ if (dlm_local_addr[0].ss_family == AF_INET) {
struct sockaddr_in *in4 = (struct sockaddr_in *) &sas;
struct sockaddr_in *ret4 = (struct sockaddr_in *) sa_out;
ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
@@ -408,43 +407,46 @@ static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
ret6->sin6_addr = in6->sin6_addr;
}
+ srcu_read_unlock(&connections_srcu, idx);
return 0;
}
static int addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid,
unsigned int *mark)
{
- struct dlm_node_addr *na;
- int rv = -EEXIST;
- int addr_i;
-
- spin_lock(&dlm_node_addrs_spin);
- list_for_each_entry(na, &dlm_node_addrs, list) {
- if (!na->addr_count)
- continue;
-
- for (addr_i = 0; addr_i < na->addr_count; addr_i++) {
- if (addr_compare(na->addr[addr_i], addr)) {
- *nodeid = na->nodeid;
- *mark = na->mark;
- rv = 0;
- goto unlock;
+ struct connection *con;
+ int i, idx, addr_i;
+
+ idx = srcu_read_lock(&connections_srcu);
+ for (i = 0; i < CONN_HASH_SIZE; i++) {
+ hlist_for_each_entry_rcu(con, &connection_hash[i], list) {
+ WARN_ON_ONCE(!con->addr_count);
+
+ spin_lock(&con->addrs_lock);
+ for (addr_i = 0; addr_i < con->addr_count; addr_i++) {
+ if (addr_compare(&con->addr[addr_i], addr)) {
+ *nodeid = con->nodeid;
+ *mark = con->mark;
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
+ return 0;
+ }
}
+ spin_unlock(&con->addrs_lock);
}
}
-unlock:
- spin_unlock(&dlm_node_addrs_spin);
- return rv;
+ srcu_read_unlock(&connections_srcu, idx);
+
+ return -ENOENT;
}
-/* caller need to held dlm_node_addrs_spin lock */
-static bool dlm_lowcomms_na_has_addr(const struct dlm_node_addr *na,
- const struct sockaddr_storage *addr)
+static bool dlm_lowcomms_con_has_addr(const struct connection *con,
+ const struct sockaddr_storage *addr)
{
int i;
- for (i = 0; i < na->addr_count; i++) {
- if (addr_compare(na->addr[i], addr))
+ for (i = 0; i < con->addr_count; i++) {
+ if (addr_compare(&con->addr[i], addr))
return true;
}
@@ -453,118 +455,82 @@ static bool dlm_lowcomms_na_has_addr(const struct dlm_node_addr *na,
int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len)
{
- struct sockaddr_storage *new_addr;
- struct dlm_node_addr *new_node, *na;
- bool ret;
-
- new_node = kzalloc(sizeof(struct dlm_node_addr), GFP_NOFS);
- if (!new_node)
- return -ENOMEM;
+ struct connection *con;
+ bool ret, idx;
- new_addr = kzalloc(sizeof(struct sockaddr_storage), GFP_NOFS);
- if (!new_addr) {
- kfree(new_node);
+ idx = srcu_read_lock(&connections_srcu);
+ con = nodeid2con(nodeid, GFP_NOFS);
+ if (!con) {
+ srcu_read_unlock(&connections_srcu, idx);
return -ENOMEM;
}
- memcpy(new_addr, addr, len);
-
- spin_lock(&dlm_node_addrs_spin);
- na = find_node_addr(nodeid);
- if (!na) {
- new_node->nodeid = nodeid;
- new_node->addr[0] = new_addr;
- new_node->addr_count = 1;
- new_node->mark = dlm_config.ci_mark;
- list_add(&new_node->list, &dlm_node_addrs);
- spin_unlock(&dlm_node_addrs_spin);
+ spin_lock(&con->addrs_lock);
+ if (!con->addr_count) {
+ memcpy(&con->addr[0], addr, sizeof(*addr));
+ con->addr_count = 1;
+ con->mark = dlm_config.ci_mark;
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
return 0;
}
- ret = dlm_lowcomms_na_has_addr(na, addr);
+ ret = dlm_lowcomms_con_has_addr(con, addr);
if (ret) {
- spin_unlock(&dlm_node_addrs_spin);
- kfree(new_addr);
- kfree(new_node);
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
return -EEXIST;
}
- if (na->addr_count >= DLM_MAX_ADDR_COUNT) {
- spin_unlock(&dlm_node_addrs_spin);
- kfree(new_addr);
- kfree(new_node);
+ if (con->addr_count >= DLM_MAX_ADDR_COUNT) {
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
return -ENOSPC;
}
- na->addr[na->addr_count++] = new_addr;
- spin_unlock(&dlm_node_addrs_spin);
- kfree(new_node);
+ memcpy(&con->addr[con->addr_count++], addr, sizeof(*addr));
+ srcu_read_unlock(&connections_srcu, idx);
+ spin_unlock(&con->addrs_lock);
return 0;
}
/* Data available on socket or listen socket received a connect */
static void lowcomms_data_ready(struct sock *sk)
{
- struct connection *con;
-
- con = sock2con(sk);
- if (con && !test_and_set_bit(CF_READ_PENDING, &con->flags))
- queue_work(recv_workqueue, &con->rwork);
-}
-
-static void lowcomms_listen_data_ready(struct sock *sk)
-{
- if (!dlm_allow_conn)
- return;
+ struct connection *con = sock2con(sk);
- queue_work(recv_workqueue, &listen_con.rwork);
+ set_bit(CF_RECV_INTR, &con->flags);
+ lowcomms_queue_rwork(con);
}
static void lowcomms_write_space(struct sock *sk)
{
- struct connection *con;
-
- con = sock2con(sk);
- if (!con)
- return;
-
- if (!test_and_set_bit(CF_CONNECTED, &con->flags)) {
- log_print("connected to node %d", con->nodeid);
- queue_work(send_workqueue, &con->swork);
- return;
- }
+ struct connection *con = sock2con(sk);
clear_bit(SOCK_NOSPACE, &con->sock->flags);
+ spin_lock_bh(&con->writequeue_lock);
if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
con->sock->sk->sk_write_pending--;
clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags);
}
- queue_work(send_workqueue, &con->swork);
-}
-
-static inline void lowcomms_connect_sock(struct connection *con)
-{
- if (test_bit(CF_CLOSE, &con->flags))
- return;
- queue_work(send_workqueue, &con->swork);
- cond_resched();
+ lowcomms_queue_swork(con);
+ spin_unlock_bh(&con->writequeue_lock);
}
static void lowcomms_state_change(struct sock *sk)
{
/* SCTP layer is not calling sk_data_ready when the connection
- * is done, so we catch the signal through here. Also, it
- * doesn't switch socket state when entering shutdown, so we
- * skip the write in that case.
+ * is done, so we catch the signal through here.
*/
- if (sk->sk_shutdown) {
- if (sk->sk_shutdown == RCV_SHUTDOWN)
- lowcomms_data_ready(sk);
- } else if (sk->sk_state == TCP_ESTABLISHED) {
- lowcomms_write_space(sk);
- }
+ if (sk->sk_shutdown == RCV_SHUTDOWN)
+ lowcomms_data_ready(sk);
+}
+
+static void lowcomms_listen_data_ready(struct sock *sk)
+{
+ queue_work(io_workqueue, &listen_con.rwork);
}
int dlm_lowcomms_connect_node(int nodeid)
@@ -576,47 +542,49 @@ int dlm_lowcomms_connect_node(int nodeid)
return 0;
idx = srcu_read_lock(&connections_srcu);
- con = nodeid2con(nodeid, GFP_NOFS);
- if (!con) {
+ con = nodeid2con(nodeid, 0);
+ if (WARN_ON_ONCE(!con)) {
srcu_read_unlock(&connections_srcu, idx);
- return -ENOMEM;
+ return -ENOENT;
}
- lowcomms_connect_sock(con);
+ down_read(&con->sock_lock);
+ if (!con->sock) {
+ spin_lock_bh(&con->writequeue_lock);
+ lowcomms_queue_swork(con);
+ spin_unlock_bh(&con->writequeue_lock);
+ }
+ up_read(&con->sock_lock);
srcu_read_unlock(&connections_srcu, idx);
+ cond_resched();
return 0;
}
int dlm_lowcomms_nodes_set_mark(int nodeid, unsigned int mark)
{
- struct dlm_node_addr *na;
+ struct connection *con;
+ int idx;
- spin_lock(&dlm_node_addrs_spin);
- na = find_node_addr(nodeid);
- if (!na) {
- spin_unlock(&dlm_node_addrs_spin);
+ idx = srcu_read_lock(&connections_srcu);
+ con = nodeid2con(nodeid, 0);
+ if (!con) {
+ srcu_read_unlock(&connections_srcu, idx);
return -ENOENT;
}
- na->mark = mark;
- spin_unlock(&dlm_node_addrs_spin);
-
+ spin_lock(&con->addrs_lock);
+ con->mark = mark;
+ spin_unlock(&con->addrs_lock);
+ srcu_read_unlock(&connections_srcu, idx);
return 0;
}
static void lowcomms_error_report(struct sock *sk)
{
- struct connection *con;
- void (*orig_report)(struct sock *) = NULL;
+ struct connection *con = sock2con(sk);
struct inet_sock *inet;
- con = sock2con(sk);
- if (con == NULL)
- goto out;
-
- orig_report = listen_sock.sk_error_report;
-
inet = inet_sk(sk);
switch (sk->sk_family) {
case AF_INET:
@@ -642,66 +610,25 @@ static void lowcomms_error_report(struct sock *sk)
"invalid socket family %d set, "
"sk_err=%d/%d\n", dlm_our_nodeid(),
sk->sk_family, sk->sk_err, sk->sk_err_soft);
- goto out;
- }
-
- /* below sendcon only handling */
- if (test_bit(CF_IS_OTHERCON, &con->flags))
- con = con->sendcon;
-
- switch (sk->sk_err) {
- case ECONNREFUSED:
- set_bit(CF_DELAY_CONNECT, &con->flags);
- break;
- default:
break;
}
- if (!test_and_set_bit(CF_RECONNECT, &con->flags))
- queue_work(send_workqueue, &con->swork);
+ dlm_midcomms_unack_msg_resend(con->nodeid);
-out:
- if (orig_report)
- orig_report(sk);
+ listen_sock.sk_error_report(sk);
}
-/* Note: sk_callback_lock must be locked before calling this function. */
-static void save_listen_callbacks(struct socket *sock)
+static void restore_callbacks(struct sock *sk)
{
- struct sock *sk = sock->sk;
-
- listen_sock.sk_data_ready = sk->sk_data_ready;
- listen_sock.sk_state_change = sk->sk_state_change;
- listen_sock.sk_write_space = sk->sk_write_space;
- listen_sock.sk_error_report = sk->sk_error_report;
-}
-
-static void restore_callbacks(struct socket *sock)
-{
- struct sock *sk = sock->sk;
+#ifdef CONFIG_LOCKDEP
+ WARN_ON_ONCE(!lockdep_sock_is_held(sk));
+#endif
- lock_sock(sk);
sk->sk_user_data = NULL;
sk->sk_data_ready = listen_sock.sk_data_ready;
sk->sk_state_change = listen_sock.sk_state_change;
sk->sk_write_space = listen_sock.sk_write_space;
sk->sk_error_report = listen_sock.sk_error_report;
- release_sock(sk);
-}
-
-static void add_listen_sock(struct socket *sock, struct listen_connection *con)
-{
- struct sock *sk = sock->sk;
-
- lock_sock(sk);
- save_listen_callbacks(sock);
- con->sock = sock;
-
- sk->sk_user_data = con;
- sk->sk_allocation = GFP_NOFS;
- /* Install a data_ready callback */
- sk->sk_data_ready = lowcomms_listen_data_ready;
- release_sock(sk);
}
/* Make a socket active */
@@ -713,10 +640,10 @@ static void add_sock(struct socket *sock, struct connection *con)
con->sock = sock;
sk->sk_user_data = con;
- /* Install a data_ready callback */
sk->sk_data_ready = lowcomms_data_ready;
sk->sk_write_space = lowcomms_write_space;
- sk->sk_state_change = lowcomms_state_change;
+ if (dlm_config.ci_protocol == DLM_PROTO_SCTP)
+ sk->sk_state_change = lowcomms_state_change;
sk->sk_allocation = GFP_NOFS;
sk->sk_error_report = lowcomms_error_report;
release_sock(sk);
@@ -727,7 +654,7 @@ static void add_sock(struct socket *sock, struct connection *con)
static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
int *addr_len)
{
- saddr->ss_family = dlm_local_addr[0]->ss_family;
+ saddr->ss_family = dlm_local_addr[0].ss_family;
if (saddr->ss_family == AF_INET) {
struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
in4_addr->sin_port = cpu_to_be16(port);
@@ -773,43 +700,67 @@ static void free_entry(struct writequeue_entry *e)
}
list_del(&e->list);
- atomic_dec(&e->con->writequeue_cnt);
kref_put(&e->ref, dlm_page_release);
}
static void dlm_close_sock(struct socket **sock)
{
- if (*sock) {
- restore_callbacks(*sock);
- sock_release(*sock);
- *sock = NULL;
+ lock_sock((*sock)->sk);
+ restore_callbacks((*sock)->sk);
+ release_sock((*sock)->sk);
+
+ sock_release(*sock);
+ *sock = NULL;
+}
+
+static void allow_connection_io(struct connection *con)
+{
+ if (con->othercon)
+ clear_bit(CF_IO_STOP, &con->othercon->flags);
+ clear_bit(CF_IO_STOP, &con->flags);
+}
+
+static void stop_connection_io(struct connection *con)
+{
+ if (con->othercon)
+ stop_connection_io(con->othercon);
+
+ down_write(&con->sock_lock);
+ if (con->sock) {
+ lock_sock(con->sock->sk);
+ restore_callbacks(con->sock->sk);
+
+ spin_lock_bh(&con->writequeue_lock);
+ set_bit(CF_IO_STOP, &con->flags);
+ spin_unlock_bh(&con->writequeue_lock);
+ release_sock(con->sock->sk);
+ } else {
+ spin_lock_bh(&con->writequeue_lock);
+ set_bit(CF_IO_STOP, &con->flags);
+ spin_unlock_bh(&con->writequeue_lock);
}
+ up_write(&con->sock_lock);
+
+ cancel_work_sync(&con->swork);
+ cancel_work_sync(&con->rwork);
}
/* Close a remote connection and tidy up */
-static void close_connection(struct connection *con, bool and_other,
- bool tx, bool rx)
+static void close_connection(struct connection *con, bool and_other)
{
- bool closing = test_and_set_bit(CF_CLOSING, &con->flags);
struct writequeue_entry *e;
- if (tx && !closing && cancel_work_sync(&con->swork)) {
- log_print("canceled swork for node %d", con->nodeid);
- clear_bit(CF_WRITE_PENDING, &con->flags);
- }
- if (rx && !closing && cancel_work_sync(&con->rwork)) {
- log_print("canceled rwork for node %d", con->nodeid);
- clear_bit(CF_READ_PENDING, &con->flags);
+ if (con->othercon && and_other)
+ close_connection(con->othercon, false);
+
+ down_write(&con->sock_lock);
+ if (!con->sock) {
+ up_write(&con->sock_lock);
+ return;
}
- mutex_lock(&con->sock_mutex);
dlm_close_sock(&con->sock);
- if (con->othercon && and_other) {
- /* Will only re-enter once. */
- close_connection(con->othercon, false, tx, rx);
- }
-
/* if we send a writequeue entry only a half way, we drop the
* whole entry because reconnection and that we not start of the
* middle of a msg which will confuse the other end.
@@ -821,200 +772,209 @@ static void close_connection(struct connection *con, bool and_other,
* our policy is to start on a clean state when disconnects, we don't
* know what's send/received on transport layer in this case.
*/
- spin_lock(&con->writequeue_lock);
+ spin_lock_bh(&con->writequeue_lock);
if (!list_empty(&con->writequeue)) {
e = list_first_entry(&con->writequeue, struct writequeue_entry,
list);
if (e->dirty)
free_entry(e);
}
- spin_unlock(&con->writequeue_lock);
+ spin_unlock_bh(&con->writequeue_lock);
con->rx_leftover = 0;
con->retries = 0;
clear_bit(CF_APP_LIMITED, &con->flags);
- clear_bit(CF_CONNECTED, &con->flags);
- clear_bit(CF_DELAY_CONNECT, &con->flags);
- clear_bit(CF_RECONNECT, &con->flags);
- clear_bit(CF_EOF, &con->flags);
- mutex_unlock(&con->sock_mutex);
- clear_bit(CF_CLOSING, &con->flags);
+ clear_bit(CF_RECV_PENDING, &con->flags);
+ clear_bit(CF_SEND_PENDING, &con->flags);
+ up_write(&con->sock_lock);
}
-static void shutdown_connection(struct connection *con)
+static struct processqueue_entry *new_processqueue_entry(int nodeid,
+ int buflen)
{
- int ret;
-
- flush_work(&con->swork);
+ struct processqueue_entry *pentry;
- mutex_lock(&con->sock_mutex);
- /* nothing to shutdown */
- if (!con->sock) {
- mutex_unlock(&con->sock_mutex);
- return;
- }
+ pentry = kmalloc(sizeof(*pentry), GFP_NOFS);
+ if (!pentry)
+ return NULL;
- set_bit(CF_SHUTDOWN, &con->flags);
- ret = kernel_sock_shutdown(con->sock, SHUT_WR);
- mutex_unlock(&con->sock_mutex);
- if (ret) {
- log_print("Connection %p failed to shutdown: %d will force close",
- con, ret);
- goto force_close;
- } else {
- ret = wait_event_timeout(con->shutdown_wait,
- !test_bit(CF_SHUTDOWN, &con->flags),
- DLM_SHUTDOWN_WAIT_TIMEOUT);
- if (ret == 0) {
- log_print("Connection %p shutdown timed out, will force close",
- con);
- goto force_close;
- }
+ pentry->buf = kmalloc(buflen, GFP_NOFS);
+ if (!pentry->buf) {
+ kfree(pentry);
+ return NULL;
}
- return;
+ pentry->nodeid = nodeid;
+ return pentry;
+}
-force_close:
- clear_bit(CF_SHUTDOWN, &con->flags);
- close_connection(con, false, true, true);
+static void free_processqueue_entry(struct processqueue_entry *pentry)
+{
+ kfree(pentry->buf);
+ kfree(pentry);
}
-static void dlm_tcp_shutdown(struct connection *con)
+struct dlm_processed_nodes {
+ int nodeid;
+
+ struct list_head list;
+};
+
+static void add_processed_node(int nodeid, struct list_head *processed_nodes)
{
- if (con->othercon)
- shutdown_connection(con->othercon);
- shutdown_connection(con);
+ struct dlm_processed_nodes *n;
+
+ list_for_each_entry(n, processed_nodes, list) {
+ /* we already remembered this node */
+ if (n->nodeid == nodeid)
+ return;
+ }
+
+ /* if it's fails in worst case we simple don't send an ack back.
+ * We try it next time.
+ */
+ n = kmalloc(sizeof(*n), GFP_NOFS);
+ if (!n)
+ return;
+
+ n->nodeid = nodeid;
+ list_add(&n->list, processed_nodes);
}
-static int con_realloc_receive_buf(struct connection *con, int newlen)
+static void process_dlm_messages(struct work_struct *work)
{
- unsigned char *newbuf;
+ struct dlm_processed_nodes *n, *n_tmp;
+ struct processqueue_entry *pentry;
+ LIST_HEAD(processed_nodes);
- newbuf = kmalloc(newlen, GFP_NOFS);
- if (!newbuf)
- return -ENOMEM;
+ spin_lock(&processqueue_lock);
+ pentry = list_first_entry_or_null(&processqueue,
+ struct processqueue_entry, list);
+ if (WARN_ON_ONCE(!pentry)) {
+ spin_unlock(&processqueue_lock);
+ return;
+ }
- /* copy any leftover from last receive */
- if (con->rx_leftover)
- memmove(newbuf, con->rx_buf, con->rx_leftover);
+ list_del(&pentry->list);
+ spin_unlock(&processqueue_lock);
- /* swap to new buffer space */
- kfree(con->rx_buf);
- con->rx_buflen = newlen;
- con->rx_buf = newbuf;
+ for (;;) {
+ dlm_process_incoming_buffer(pentry->nodeid, pentry->buf,
+ pentry->buflen);
+ add_processed_node(pentry->nodeid, &processed_nodes);
+ free_processqueue_entry(pentry);
+
+ spin_lock(&processqueue_lock);
+ pentry = list_first_entry_or_null(&processqueue,
+ struct processqueue_entry, list);
+ if (!pentry) {
+ process_dlm_messages_pending = false;
+ spin_unlock(&processqueue_lock);
+ break;
+ }
- return 0;
+ list_del(&pentry->list);
+ spin_unlock(&processqueue_lock);
+ }
+
+ /* send ack back after we processed couple of messages */
+ list_for_each_entry_safe(n, n_tmp, &processed_nodes, list) {
+ list_del(&n->list);
+ dlm_midcomms_receive_done(n->nodeid);
+ kfree(n);
+ }
}
/* Data received from remote end */
-static int receive_from_sock(struct connection *con)
+static int receive_from_sock(struct connection *con, int buflen)
{
+ struct processqueue_entry *pentry;
+ int ret, buflen_real;
struct msghdr msg;
struct kvec iov;
- int ret, buflen;
- mutex_lock(&con->sock_mutex);
+ pentry = new_processqueue_entry(con->nodeid, buflen);
+ if (!pentry)
+ return DLM_IO_RESCHED;
- if (con->sock == NULL) {
- ret = -EAGAIN;
- goto out_close;
- }
-
- /* realloc if we get new buffer size to read out */
- buflen = dlm_config.ci_buffer_size;
- if (con->rx_buflen != buflen && con->rx_leftover <= buflen) {
- ret = con_realloc_receive_buf(con, buflen);
- if (ret < 0)
- goto out_resched;
- }
+ memcpy(pentry->buf, con->rx_leftover_buf, con->rx_leftover);
- for (;;) {
- /* calculate new buffer parameter regarding last receive and
- * possible leftover bytes
- */
- iov.iov_base = con->rx_buf + con->rx_leftover;
- iov.iov_len = con->rx_buflen - con->rx_leftover;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
- ret = kernel_recvmsg(con->sock, &msg, &iov, 1, iov.iov_len,
- msg.msg_flags);
- trace_dlm_recv(con->nodeid, ret);
- if (ret == -EAGAIN)
- break;
- else if (ret <= 0)
- goto out_close;
-
- /* new buflen according readed bytes and leftover from last receive */
- buflen = ret + con->rx_leftover;
- ret = dlm_process_incoming_buffer(con->nodeid, con->rx_buf, buflen);
- if (ret < 0)
- goto out_close;
-
- /* calculate leftover bytes from process and put it into begin of
- * the receive buffer, so next receive we have the full message
- * at the start address of the receive buffer.
- */
- con->rx_leftover = buflen - ret;
- if (con->rx_leftover) {
- memmove(con->rx_buf, con->rx_buf + ret,
- con->rx_leftover);
+ /* calculate new buffer parameter regarding last receive and
+ * possible leftover bytes
+ */
+ iov.iov_base = pentry->buf + con->rx_leftover;
+ iov.iov_len = buflen - con->rx_leftover;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
+ clear_bit(CF_RECV_INTR, &con->flags);
+again:
+ ret = kernel_recvmsg(con->sock, &msg, &iov, 1, iov.iov_len,
+ msg.msg_flags);
+ trace_dlm_recv(con->nodeid, ret);
+ if (ret == -EAGAIN) {
+ lock_sock(con->sock->sk);
+ if (test_and_clear_bit(CF_RECV_INTR, &con->flags)) {
+ release_sock(con->sock->sk);
+ goto again;
}
+
+ clear_bit(CF_RECV_PENDING, &con->flags);
+ release_sock(con->sock->sk);
+ free_processqueue_entry(pentry);
+ return DLM_IO_END;
+ } else if (ret == 0) {
+ /* close will clear CF_RECV_PENDING */
+ free_processqueue_entry(pentry);
+ return DLM_IO_EOF;
+ } else if (ret < 0) {
+ free_processqueue_entry(pentry);
+ return ret;
}
- dlm_midcomms_receive_done(con->nodeid);
- mutex_unlock(&con->sock_mutex);
- return 0;
+ /* new buflen according readed bytes and leftover from last receive */
+ buflen_real = ret + con->rx_leftover;
+ ret = dlm_validate_incoming_buffer(con->nodeid, pentry->buf,
+ buflen_real);
+ if (ret < 0) {
+ free_processqueue_entry(pentry);
+ return ret;
+ }
-out_resched:
- if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
- queue_work(recv_workqueue, &con->rwork);
- mutex_unlock(&con->sock_mutex);
- return -EAGAIN;
-
-out_close:
- if (ret == 0) {
- log_print("connection %p got EOF from %d",
- con, con->nodeid);
-
- if (dlm_proto_ops->eof_condition &&
- dlm_proto_ops->eof_condition(con)) {
- set_bit(CF_EOF, &con->flags);
- mutex_unlock(&con->sock_mutex);
- } else {
- mutex_unlock(&con->sock_mutex);
- close_connection(con, false, true, false);
+ pentry->buflen = ret;
- /* handling for tcp shutdown */
- clear_bit(CF_SHUTDOWN, &con->flags);
- wake_up(&con->shutdown_wait);
- }
+ /* calculate leftover bytes from process and put it into begin of
+ * the receive buffer, so next receive we have the full message
+ * at the start address of the receive buffer.
+ */
+ con->rx_leftover = buflen_real - ret;
+ memmove(con->rx_leftover_buf, pentry->buf + ret,
+ con->rx_leftover);
- /* signal to breaking receive worker */
- ret = -1;
- } else {
- mutex_unlock(&con->sock_mutex);
+ spin_lock(&processqueue_lock);
+ list_add_tail(&pentry->list, &processqueue);
+ if (!process_dlm_messages_pending) {
+ process_dlm_messages_pending = true;
+ queue_work(process_workqueue, &process_work);
}
- return ret;
+ spin_unlock(&processqueue_lock);
+
+ return DLM_IO_SUCCESS;
}
/* Listening socket is busy, accept a connection */
-static int accept_from_sock(struct listen_connection *con)
+static int accept_from_sock(void)
{
- int result;
struct sockaddr_storage peeraddr;
- struct socket *newsock;
- int len, idx;
- int nodeid;
+ int len, idx, result, nodeid;
struct connection *newcon;
- struct connection *addcon;
+ struct socket *newsock;
unsigned int mark;
- if (!con->sock)
- return -ENOTCONN;
-
- result = kernel_accept(con->sock, &newsock, O_NONBLOCK);
- if (result < 0)
+ result = kernel_accept(listen_con.sock, &newsock, O_NONBLOCK);
+ if (result == -EAGAIN)
+ return DLM_IO_END;
+ else if (result < 0)
goto accept_err;
/* Get the connected socket's peer */
@@ -1062,16 +1022,16 @@ static int accept_from_sock(struct listen_connection *con)
* In this case we store the incoming one in "othercon"
*/
idx = srcu_read_lock(&connections_srcu);
- newcon = nodeid2con(nodeid, GFP_NOFS);
- if (!newcon) {
+ newcon = nodeid2con(nodeid, 0);
+ if (WARN_ON_ONCE(!newcon)) {
srcu_read_unlock(&connections_srcu, idx);
- result = -ENOMEM;
+ result = -ENOENT;
goto accept_err;
}
sock_set_mark(newsock->sk, mark);
- mutex_lock(&newcon->sock_mutex);
+ down_write(&newcon->sock_lock);
if (newcon->sock) {
struct connection *othercon = newcon->othercon;
@@ -1079,63 +1039,50 @@ static int accept_from_sock(struct listen_connection *con)
othercon = kzalloc(sizeof(*othercon), GFP_NOFS);
if (!othercon) {
log_print("failed to allocate incoming socket");
- mutex_unlock(&newcon->sock_mutex);
+ up_write(&newcon->sock_lock);
srcu_read_unlock(&connections_srcu, idx);
result = -ENOMEM;
goto accept_err;
}
- result = dlm_con_init(othercon, nodeid);
- if (result < 0) {
- kfree(othercon);
- mutex_unlock(&newcon->sock_mutex);
- srcu_read_unlock(&connections_srcu, idx);
- goto accept_err;
- }
-
- lockdep_set_subclass(&othercon->sock_mutex, 1);
- set_bit(CF_IS_OTHERCON, &othercon->flags);
+ dlm_con_init(othercon, nodeid);
+ lockdep_set_subclass(&othercon->sock_lock, 1);
newcon->othercon = othercon;
- othercon->sendcon = newcon;
+ set_bit(CF_IS_OTHERCON, &othercon->flags);
} else {
/* close other sock con if we have something new */
- close_connection(othercon, false, true, false);
+ close_connection(othercon, false);
}
- mutex_lock(&othercon->sock_mutex);
+ down_write(&othercon->sock_lock);
add_sock(newsock, othercon);
- addcon = othercon;
- mutex_unlock(&othercon->sock_mutex);
+
+ /* check if we receved something while adding */
+ lock_sock(othercon->sock->sk);
+ lowcomms_queue_rwork(othercon);
+ release_sock(othercon->sock->sk);
+ up_write(&othercon->sock_lock);
}
else {
/* accept copies the sk after we've saved the callbacks, so we
don't want to save them a second time or comm errors will
result in calling sk_error_report recursively. */
add_sock(newsock, newcon);
- addcon = newcon;
- }
-
- set_bit(CF_CONNECTED, &addcon->flags);
- mutex_unlock(&newcon->sock_mutex);
-
- /*
- * Add it to the active queue in case we got data
- * between processing the accept adding the socket
- * to the read_sockets list
- */
- if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
- queue_work(recv_workqueue, &addcon->rwork);
+ /* check if we receved something while adding */
+ lock_sock(newcon->sock->sk);
+ lowcomms_queue_rwork(newcon);
+ release_sock(newcon->sock->sk);
+ }
+ up_write(&newcon->sock_lock);
srcu_read_unlock(&connections_srcu, idx);
- return 0;
+ return DLM_IO_SUCCESS;
accept_err:
if (newsock)
sock_release(newsock);
- if (result != -EAGAIN)
- log_print("error accepting connection from node: %d", result);
return result;
}
@@ -1167,7 +1114,7 @@ static int sctp_bind_addrs(struct socket *sock, uint16_t port)
int i, addr_len, result = 0;
for (i = 0; i < dlm_local_count; i++) {
- memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
+ memcpy(&localaddr, &dlm_local_addr[i], sizeof(localaddr));
make_sockaddr(&localaddr, port, &addr_len);
if (!i)
@@ -1187,7 +1134,7 @@ static int sctp_bind_addrs(struct socket *sock, uint16_t port)
/* Get local addresses */
static void init_local(void)
{
- struct sockaddr_storage sas, *addr;
+ struct sockaddr_storage sas;
int i;
dlm_local_count = 0;
@@ -1195,21 +1142,10 @@ static void init_local(void)
if (dlm_our_addr(&sas, i))
break;
- addr = kmemdup(&sas, sizeof(*addr), GFP_NOFS);
- if (!addr)
- break;
- dlm_local_addr[dlm_local_count++] = addr;
+ memcpy(&dlm_local_addr[dlm_local_count++], &sas, sizeof(sas));
}
}
-static void deinit_local(void)
-{
- int i;
-
- for (i = 0; i < dlm_local_count; i++)
- kfree(dlm_local_addr[i]);
-}
-
static struct writequeue_entry *new_writequeue_entry(struct connection *con)
{
struct writequeue_entry *entry;
@@ -1240,7 +1176,7 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len,
{
struct writequeue_entry *e;
- spin_lock(&con->writequeue_lock);
+ spin_lock_bh(&con->writequeue_lock);
if (!list_empty(&con->writequeue)) {
e = list_last_entry(&con->writequeue, struct writequeue_entry, list);
if (DLM_WQ_REMAIN_BYTES(e) >= len) {
@@ -1263,14 +1199,13 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len,
kref_get(&e->ref);
*ppc = page_address(e->page);
e->end += len;
- atomic_inc(&con->writequeue_cnt);
if (cb)
cb(data);
list_add_tail(&e->list, &con->writequeue);
out:
- spin_unlock(&con->writequeue_lock);
+ spin_unlock_bh(&con->writequeue_lock);
return e;
};
@@ -1319,13 +1254,13 @@ struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation,
len < sizeof(struct dlm_header)) {
BUILD_BUG_ON(PAGE_SIZE < DLM_MAX_SOCKET_BUFSIZE);
log_print("failed to allocate a buffer of size %d", len);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return NULL;
}
idx = srcu_read_lock(&connections_srcu);
- con = nodeid2con(nodeid, allocation);
- if (!con) {
+ con = nodeid2con(nodeid, 0);
+ if (WARN_ON_ONCE(!con)) {
srcu_read_unlock(&connections_srcu, idx);
return NULL;
}
@@ -1350,7 +1285,7 @@ static void _dlm_lowcomms_commit_msg(struct dlm_msg *msg)
struct connection *con = e->con;
int users;
- spin_lock(&con->writequeue_lock);
+ spin_lock_bh(&con->writequeue_lock);
kref_get(&msg->ref);
list_add(&msg->list, &e->msgs);
@@ -1359,13 +1294,11 @@ static void _dlm_lowcomms_commit_msg(struct dlm_msg *msg)
goto out;
e->len = DLM_WQ_LENGTH_BYTES(e);
- spin_unlock(&con->writequeue_lock);
- queue_work(send_workqueue, &con->swork);
- return;
+ lowcomms_queue_swork(con);
out:
- spin_unlock(&con->writequeue_lock);
+ spin_unlock_bh(&con->writequeue_lock);
return;
}
@@ -1387,7 +1320,7 @@ void dlm_lowcomms_put_msg(struct dlm_msg *msg)
kref_put(&msg->ref, dlm_msg_release);
}
-/* does not held connections_srcu, usage workqueue only */
+/* does not held connections_srcu, usage lowcomms_error_report only */
int dlm_lowcomms_resend_msg(struct dlm_msg *msg)
{
struct dlm_msg *msg_resend;
@@ -1413,90 +1346,79 @@ int dlm_lowcomms_resend_msg(struct dlm_msg *msg)
}
/* Send a message */
-static void send_to_sock(struct connection *con)
+static int send_to_sock(struct connection *con)
{
const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
struct writequeue_entry *e;
int len, offset, ret;
- int count = 0;
- mutex_lock(&con->sock_mutex);
- if (con->sock == NULL)
- goto out_connect;
-
- spin_lock(&con->writequeue_lock);
- for (;;) {
- e = con_next_wq(con);
- if (!e)
- break;
+ spin_lock_bh(&con->writequeue_lock);
+ e = con_next_wq(con);
+ if (!e) {
+ clear_bit(CF_SEND_PENDING, &con->flags);
+ spin_unlock_bh(&con->writequeue_lock);
+ return DLM_IO_END;
+ }
- len = e->len;
- offset = e->offset;
- BUG_ON(len == 0 && e->users == 0);
- spin_unlock(&con->writequeue_lock);
-
- ret = kernel_sendpage(con->sock, e->page, offset, len,
- msg_flags);
- trace_dlm_send(con->nodeid, ret);
- if (ret == -EAGAIN || ret == 0) {
- if (ret == -EAGAIN &&
- 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.
- */
- set_bit(SOCK_NOSPACE, &con->sock->flags);
- con->sock->sk->sk_write_pending++;
- }
- cond_resched();
- goto out;
- } else if (ret < 0)
- goto out;
+ len = e->len;
+ offset = e->offset;
+ WARN_ON_ONCE(len == 0 && e->users == 0);
+ spin_unlock_bh(&con->writequeue_lock);
- /* Don't starve people filling buffers */
- if (++count >= MAX_SEND_MSG_COUNT) {
- cond_resched();
- count = 0;
+ ret = kernel_sendpage(con->sock, e->page, offset, len,
+ msg_flags);
+ trace_dlm_send(con->nodeid, ret);
+ if (ret == -EAGAIN || ret == 0) {
+ lock_sock(con->sock->sk);
+ spin_lock_bh(&con->writequeue_lock);
+ if (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.
+ */
+ set_bit(SOCK_NOSPACE, &con->sock->sk->sk_socket->flags);
+ con->sock->sk->sk_write_pending++;
+
+ clear_bit(CF_SEND_PENDING, &con->flags);
+ spin_unlock_bh(&con->writequeue_lock);
+ release_sock(con->sock->sk);
+
+ /* wait for write_space() event */
+ return DLM_IO_END;
}
+ spin_unlock_bh(&con->writequeue_lock);
+ release_sock(con->sock->sk);
- spin_lock(&con->writequeue_lock);
- writequeue_entry_complete(e, ret);
- }
- spin_unlock(&con->writequeue_lock);
-
- /* close if we got EOF */
- if (test_and_clear_bit(CF_EOF, &con->flags)) {
- mutex_unlock(&con->sock_mutex);
- close_connection(con, false, false, true);
-
- /* handling for tcp shutdown */
- clear_bit(CF_SHUTDOWN, &con->flags);
- wake_up(&con->shutdown_wait);
- } else {
- mutex_unlock(&con->sock_mutex);
+ return DLM_IO_RESCHED;
+ } else if (ret < 0) {
+ return ret;
}
- return;
-
-out:
- mutex_unlock(&con->sock_mutex);
- return;
+ spin_lock_bh(&con->writequeue_lock);
+ writequeue_entry_complete(e, ret);
+ spin_unlock_bh(&con->writequeue_lock);
-out_connect:
- mutex_unlock(&con->sock_mutex);
- queue_work(send_workqueue, &con->swork);
- cond_resched();
+ return DLM_IO_SUCCESS;
}
static void clean_one_writequeue(struct connection *con)
{
struct writequeue_entry *e, *safe;
- spin_lock(&con->writequeue_lock);
+ spin_lock_bh(&con->writequeue_lock);
list_for_each_entry_safe(e, safe, &con->writequeue, list) {
free_entry(e);
}
- spin_unlock(&con->writequeue_lock);
+ spin_unlock_bh(&con->writequeue_lock);
+}
+
+static void connection_release(struct rcu_head *rcu)
+{
+ struct connection *con = container_of(rcu, struct connection, rcu);
+
+ WARN_ON_ONCE(!list_empty(&con->writequeue));
+ WARN_ON_ONCE(con->sock);
+ kfree(con);
}
/* Called from recovery when it knows that a node has
@@ -1504,286 +1426,311 @@ static void clean_one_writequeue(struct connection *con)
int dlm_lowcomms_close(int nodeid)
{
struct connection *con;
- struct dlm_node_addr *na;
int idx;
log_print("closing connection to node %d", nodeid);
+
idx = srcu_read_lock(&connections_srcu);
con = nodeid2con(nodeid, 0);
- if (con) {
- set_bit(CF_CLOSE, &con->flags);
- close_connection(con, true, true, true);
- clean_one_writequeue(con);
+ if (WARN_ON_ONCE(!con)) {
+ srcu_read_unlock(&connections_srcu, idx);
+ return -ENOENT;
+ }
+
+ stop_connection_io(con);
+ log_print("io handling for node: %d stopped", nodeid);
+ close_connection(con, true);
+
+ spin_lock(&connections_lock);
+ hlist_del_rcu(&con->list);
+ spin_unlock(&connections_lock);
+
+ clean_one_writequeue(con);
+ call_srcu(&connections_srcu, &con->rcu, connection_release);
+ if (con->othercon) {
+ clean_one_writequeue(con->othercon);
if (con->othercon)
- clean_one_writequeue(con->othercon);
+ call_srcu(&connections_srcu, &con->othercon->rcu, connection_release);
}
srcu_read_unlock(&connections_srcu, idx);
- spin_lock(&dlm_node_addrs_spin);
- na = find_node_addr(nodeid);
- if (na) {
- list_del(&na->list);
- while (na->addr_count--)
- kfree(na->addr[na->addr_count]);
- kfree(na);
- }
- spin_unlock(&dlm_node_addrs_spin);
+ /* for debugging we print when we are done to compare with other
+ * messages in between. This function need to be correctly synchronized
+ * with io handling
+ */
+ log_print("closing connection to node %d done", nodeid);
return 0;
}
-/* Receive workqueue function */
+/* Receive worker function */
static void process_recv_sockets(struct work_struct *work)
{
struct connection *con = container_of(work, struct connection, rwork);
+ int ret, buflen;
+
+ down_read(&con->sock_lock);
+ if (!con->sock) {
+ up_read(&con->sock_lock);
+ return;
+ }
+
+ buflen = READ_ONCE(dlm_config.ci_buffer_size);
+ do {
+ ret = receive_from_sock(con, buflen);
+ } while (ret == DLM_IO_SUCCESS);
+ up_read(&con->sock_lock);
- clear_bit(CF_READ_PENDING, &con->flags);
- receive_from_sock(con);
+ switch (ret) {
+ case DLM_IO_END:
+ /* CF_RECV_PENDING cleared */
+ break;
+ case DLM_IO_EOF:
+ close_connection(con, false);
+ /* CF_RECV_PENDING cleared */
+ break;
+ case DLM_IO_RESCHED:
+ cond_resched();
+ queue_work(io_workqueue, &con->rwork);
+ /* CF_RECV_PENDING not cleared */
+ break;
+ default:
+ if (ret < 0) {
+ if (test_bit(CF_IS_OTHERCON, &con->flags)) {
+ close_connection(con, false);
+ } else {
+ spin_lock_bh(&con->writequeue_lock);
+ lowcomms_queue_swork(con);
+ spin_unlock_bh(&con->writequeue_lock);
+ }
+
+ /* CF_RECV_PENDING cleared for othercon
+ * we trigger send queue if not already done
+ * and process_send_sockets will handle it
+ */
+ break;
+ }
+
+ WARN_ON_ONCE(1);
+ break;
+ }
}
static void process_listen_recv_socket(struct work_struct *work)
{
- accept_from_sock(&listen_con);
+ int ret;
+
+ if (WARN_ON_ONCE(!listen_con.sock))
+ return;
+
+ do {
+ ret = accept_from_sock();
+ } while (ret == DLM_IO_SUCCESS);
+
+ if (ret < 0)
+ log_print("critical error accepting connection: %d", ret);
}
-static void dlm_connect(struct connection *con)
+static int dlm_connect(struct connection *con)
{
struct sockaddr_storage addr;
int result, addr_len;
struct socket *sock;
unsigned int mark;
- /* Some odd races can cause double-connects, ignore them */
- if (con->retries++ > MAX_CONNECT_RETRIES)
- return;
-
- if (con->sock) {
- log_print("node %d already connected.", con->nodeid);
- return;
- }
-
memset(&addr, 0, sizeof(addr));
result = nodeid_to_addr(con->nodeid, &addr, NULL,
dlm_proto_ops->try_new_addr, &mark);
if (result < 0) {
log_print("no address for nodeid %d", con->nodeid);
- return;
+ return result;
}
/* Create a socket to communicate with */
- result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
+ result = sock_create_kern(&init_net, dlm_local_addr[0].ss_family,
SOCK_STREAM, dlm_proto_ops->proto, &sock);
if (result < 0)
- goto socket_err;
+ return result;
sock_set_mark(sock->sk, mark);
dlm_proto_ops->sockopts(sock);
- add_sock(sock, con);
-
result = dlm_proto_ops->bind(sock);
- if (result < 0)
- goto add_sock_err;
+ if (result < 0) {
+ sock_release(sock);
+ return result;
+ }
+
+ add_sock(sock, con);
log_print_ratelimited("connecting to %d", con->nodeid);
make_sockaddr(&addr, dlm_config.ci_tcp_port, &addr_len);
result = dlm_proto_ops->connect(con, sock, (struct sockaddr *)&addr,
addr_len);
- if (result < 0)
- goto add_sock_err;
-
- return;
-
-add_sock_err:
- dlm_close_sock(&con->sock);
+ switch (result) {
+ case -EINPROGRESS:
+ /* not an error */
+ fallthrough;
+ case 0:
+ break;
+ default:
+ if (result < 0)
+ dlm_close_sock(&con->sock);
-socket_err:
- /*
- * Some errors are fatal and this list might need adjusting. For other
- * errors we try again until the max number of retries is reached.
- */
- if (result != -EHOSTUNREACH &&
- result != -ENETUNREACH &&
- result != -ENETDOWN &&
- result != -EINVAL &&
- result != -EPROTONOSUPPORT) {
- log_print("connect %d try %d error %d", con->nodeid,
- con->retries, result);
- msleep(1000);
- lowcomms_connect_sock(con);
+ break;
}
+
+ return result;
}
-/* Send workqueue function */
+/* Send worker function */
static void process_send_sockets(struct work_struct *work)
{
struct connection *con = container_of(work, struct connection, swork);
+ int ret;
- WARN_ON(test_bit(CF_IS_OTHERCON, &con->flags));
-
- clear_bit(CF_WRITE_PENDING, &con->flags);
+ WARN_ON_ONCE(test_bit(CF_IS_OTHERCON, &con->flags));
- if (test_and_clear_bit(CF_RECONNECT, &con->flags)) {
- close_connection(con, false, false, true);
- dlm_midcomms_unack_msg_resend(con->nodeid);
+ down_read(&con->sock_lock);
+ if (!con->sock) {
+ up_read(&con->sock_lock);
+ down_write(&con->sock_lock);
+ if (!con->sock) {
+ ret = dlm_connect(con);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ /* avoid spamming resched on connection
+ * we might can switch to a state_change
+ * event based mechanism if established
+ */
+ msleep(100);
+ break;
+ default:
+ /* CF_SEND_PENDING not cleared */
+ up_write(&con->sock_lock);
+ log_print("connect to node %d try %d error %d",
+ con->nodeid, con->retries++, ret);
+ msleep(1000);
+ /* For now we try forever to reconnect. In
+ * future we should send a event to cluster
+ * manager to fence itself after certain amount
+ * of retries.
+ */
+ queue_work(io_workqueue, &con->swork);
+ return;
+ }
+ }
+ downgrade_write(&con->sock_lock);
}
- if (con->sock == NULL) {
- if (test_and_clear_bit(CF_DELAY_CONNECT, &con->flags))
- msleep(1000);
+ do {
+ ret = send_to_sock(con);
+ } while (ret == DLM_IO_SUCCESS);
+ up_read(&con->sock_lock);
- mutex_lock(&con->sock_mutex);
- dlm_connect(con);
- mutex_unlock(&con->sock_mutex);
- }
+ switch (ret) {
+ case DLM_IO_END:
+ /* CF_SEND_PENDING cleared */
+ break;
+ case DLM_IO_RESCHED:
+ /* CF_SEND_PENDING not cleared */
+ cond_resched();
+ queue_work(io_workqueue, &con->swork);
+ break;
+ default:
+ if (ret < 0) {
+ close_connection(con, false);
+
+ /* CF_SEND_PENDING cleared */
+ spin_lock_bh(&con->writequeue_lock);
+ lowcomms_queue_swork(con);
+ spin_unlock_bh(&con->writequeue_lock);
+ break;
+ }
- if (!list_empty(&con->writequeue))
- send_to_sock(con);
+ WARN_ON_ONCE(1);
+ break;
+ }
}
static void work_stop(void)
{
- if (recv_workqueue) {
- destroy_workqueue(recv_workqueue);
- recv_workqueue = NULL;
+ if (io_workqueue) {
+ destroy_workqueue(io_workqueue);
+ io_workqueue = NULL;
}
- if (send_workqueue) {
- destroy_workqueue(send_workqueue);
- send_workqueue = NULL;
+ if (process_workqueue) {
+ destroy_workqueue(process_workqueue);
+ process_workqueue = NULL;
}
}
static int work_start(void)
{
- recv_workqueue = alloc_ordered_workqueue("dlm_recv", WQ_MEM_RECLAIM);
- if (!recv_workqueue) {
- log_print("can't start dlm_recv");
+ io_workqueue = alloc_workqueue("dlm_io", WQ_HIGHPRI | WQ_MEM_RECLAIM,
+ 0);
+ if (!io_workqueue) {
+ log_print("can't start dlm_io");
return -ENOMEM;
}
- send_workqueue = alloc_ordered_workqueue("dlm_send", WQ_MEM_RECLAIM);
- if (!send_workqueue) {
- log_print("can't start dlm_send");
- destroy_workqueue(recv_workqueue);
- recv_workqueue = NULL;
+ /* ordered dlm message process queue,
+ * should be converted to a tasklet
+ */
+ process_workqueue = alloc_ordered_workqueue("dlm_process",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM);
+ if (!process_workqueue) {
+ log_print("can't start dlm_process");
+ destroy_workqueue(io_workqueue);
+ io_workqueue = NULL;
return -ENOMEM;
}
return 0;
}
-static void shutdown_conn(struct connection *con)
-{
- if (dlm_proto_ops->shutdown_action)
- dlm_proto_ops->shutdown_action(con);
-}
-
void dlm_lowcomms_shutdown(void)
{
- int idx;
-
- /* Set all the flags to prevent any
- * socket activity.
- */
- dlm_allow_conn = 0;
-
- if (recv_workqueue)
- flush_workqueue(recv_workqueue);
- if (send_workqueue)
- flush_workqueue(send_workqueue);
+ /* stop lowcomms_listen_data_ready calls */
+ lock_sock(listen_con.sock->sk);
+ listen_con.sock->sk->sk_data_ready = listen_sock.sk_data_ready;
+ release_sock(listen_con.sock->sk);
+ cancel_work_sync(&listen_con.rwork);
dlm_close_sock(&listen_con.sock);
- idx = srcu_read_lock(&connections_srcu);
- foreach_conn(shutdown_conn);
- srcu_read_unlock(&connections_srcu, idx);
-}
-
-static void _stop_conn(struct connection *con, bool and_other)
-{
- mutex_lock(&con->sock_mutex);
- set_bit(CF_CLOSE, &con->flags);
- set_bit(CF_READ_PENDING, &con->flags);
- set_bit(CF_WRITE_PENDING, &con->flags);
- if (con->sock && con->sock->sk) {
- lock_sock(con->sock->sk);
- con->sock->sk->sk_user_data = NULL;
- release_sock(con->sock->sk);
- }
- if (con->othercon && and_other)
- _stop_conn(con->othercon, false);
- mutex_unlock(&con->sock_mutex);
-}
-
-static void stop_conn(struct connection *con)
-{
- _stop_conn(con, true);
+ flush_workqueue(process_workqueue);
}
-static void connection_release(struct rcu_head *rcu)
+void dlm_lowcomms_shutdown_node(int nodeid, bool force)
{
- struct connection *con = container_of(rcu, struct connection, rcu);
-
- kfree(con->rx_buf);
- kfree(con);
-}
+ struct connection *con;
+ int idx;
-static void free_conn(struct connection *con)
-{
- close_connection(con, true, true, true);
- spin_lock(&connections_lock);
- hlist_del_rcu(&con->list);
- spin_unlock(&connections_lock);
- if (con->othercon) {
- clean_one_writequeue(con->othercon);
- call_srcu(&connections_srcu, &con->othercon->rcu,
- connection_release);
+ idx = srcu_read_lock(&connections_srcu);
+ con = nodeid2con(nodeid, 0);
+ if (WARN_ON_ONCE(!con)) {
+ srcu_read_unlock(&connections_srcu, idx);
+ return;
}
- clean_one_writequeue(con);
- call_srcu(&connections_srcu, &con->rcu, connection_release);
-}
-static void work_flush(void)
-{
- int ok;
- int i;
- struct connection *con;
-
- do {
- ok = 1;
- foreach_conn(stop_conn);
- if (recv_workqueue)
- flush_workqueue(recv_workqueue);
- if (send_workqueue)
- flush_workqueue(send_workqueue);
- for (i = 0; i < CONN_HASH_SIZE && ok; i++) {
- hlist_for_each_entry_rcu(con, &connection_hash[i],
- list) {
- ok &= test_bit(CF_READ_PENDING, &con->flags);
- ok &= test_bit(CF_WRITE_PENDING, &con->flags);
- if (con->othercon) {
- ok &= test_bit(CF_READ_PENDING,
- &con->othercon->flags);
- ok &= test_bit(CF_WRITE_PENDING,
- &con->othercon->flags);
- }
- }
- }
- } while (!ok);
+ flush_work(&con->swork);
+ stop_connection_io(con);
+ WARN_ON_ONCE(!force && !list_empty(&con->writequeue));
+ close_connection(con, true);
+ clean_one_writequeue(con);
+ if (con->othercon)
+ clean_one_writequeue(con->othercon);
+ allow_connection_io(con);
+ srcu_read_unlock(&connections_srcu, idx);
}
void dlm_lowcomms_stop(void)
{
- int idx;
-
- idx = srcu_read_lock(&connections_srcu);
- work_flush();
- foreach_conn(free_conn);
- srcu_read_unlock(&connections_srcu, idx);
work_stop();
- deinit_local();
-
dlm_proto_ops = NULL;
}
@@ -1799,7 +1746,7 @@ static int dlm_listen_for_all(void)
if (result < 0)
return result;
- result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
+ result = sock_create_kern(&init_net, dlm_local_addr[0].ss_family,
SOCK_STREAM, dlm_proto_ops->proto, &sock);
if (result < 0) {
log_print("Can't create comms socket: %d", result);
@@ -1813,14 +1760,22 @@ static int dlm_listen_for_all(void)
if (result < 0)
goto out;
- save_listen_callbacks(sock);
- add_listen_sock(sock, &listen_con);
+ lock_sock(sock->sk);
+ listen_sock.sk_data_ready = sock->sk->sk_data_ready;
+ listen_sock.sk_write_space = sock->sk->sk_write_space;
+ listen_sock.sk_error_report = sock->sk->sk_error_report;
+ listen_sock.sk_state_change = sock->sk->sk_state_change;
+
+ listen_con.sock = sock;
+
+ sock->sk->sk_allocation = GFP_NOFS;
+ sock->sk->sk_data_ready = lowcomms_listen_data_ready;
+ release_sock(sock->sk);
- INIT_WORK(&listen_con.rwork, process_listen_recv_socket);
result = sock->ops->listen(sock, 5);
if (result < 0) {
dlm_close_sock(&listen_con.sock);
- goto out;
+ return result;
}
return 0;
@@ -1838,7 +1793,7 @@ static int dlm_tcp_bind(struct socket *sock)
/* Bind to our cluster-known address connecting to avoid
* routing problems.
*/
- memcpy(&src_addr, dlm_local_addr[0], sizeof(src_addr));
+ memcpy(&src_addr, &dlm_local_addr[0], sizeof(src_addr));
make_sockaddr(&src_addr, 0, &addr_len);
result = sock->ops->bind(sock, (struct sockaddr *)&src_addr,
@@ -1854,17 +1809,7 @@ static int dlm_tcp_bind(struct socket *sock)
static int dlm_tcp_connect(struct connection *con, struct socket *sock,
struct sockaddr *addr, int addr_len)
{
- int ret;
-
- ret = sock->ops->connect(sock, addr, addr_len, O_NONBLOCK);
- switch (ret) {
- case -EINPROGRESS:
- fallthrough;
- case 0:
- return 0;
- }
-
- return ret;
+ return sock->ops->connect(sock, addr, addr_len, O_NONBLOCK);
}
static int dlm_tcp_listen_validate(void)
@@ -1895,8 +1840,8 @@ static int dlm_tcp_listen_bind(struct socket *sock)
int addr_len;
/* Bind to our port */
- make_sockaddr(dlm_local_addr[0], dlm_config.ci_tcp_port, &addr_len);
- return sock->ops->bind(sock, (struct sockaddr *)dlm_local_addr[0],
+ make_sockaddr(&dlm_local_addr[0], dlm_config.ci_tcp_port, &addr_len);
+ return sock->ops->bind(sock, (struct sockaddr *)&dlm_local_addr[0],
addr_len);
}
@@ -1909,8 +1854,6 @@ static const struct dlm_proto_ops dlm_tcp_ops = {
.listen_validate = dlm_tcp_listen_validate,
.listen_sockopts = dlm_tcp_listen_sockopts,
.listen_bind = dlm_tcp_listen_bind,
- .shutdown_action = dlm_tcp_shutdown,
- .eof_condition = tcp_eof_condition,
};
static int dlm_sctp_bind(struct socket *sock)
@@ -1931,13 +1874,7 @@ static int dlm_sctp_connect(struct connection *con, struct socket *sock,
sock_set_sndtimeo(sock->sk, 5);
ret = sock->ops->connect(sock, addr, addr_len, 0);
sock_set_sndtimeo(sock->sk, 0);
- if (ret < 0)
- return ret;
-
- if (!test_and_set_bit(CF_CONNECTED, &con->flags))
- log_print("connected to node %d", con->nodeid);
-
- return 0;
+ return ret;
}
static int dlm_sctp_listen_validate(void)
@@ -1977,11 +1914,7 @@ static const struct dlm_proto_ops dlm_sctp_ops = {
int dlm_lowcomms_start(void)
{
- int error = -EINVAL;
- int i;
-
- for (i = 0; i < CONN_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&connection_hash[i]);
+ int error;
init_local();
if (!dlm_local_count) {
@@ -1990,13 +1923,9 @@ int dlm_lowcomms_start(void)
goto fail;
}
- INIT_WORK(&listen_con.rwork, process_listen_recv_socket);
-
error = work_start();
if (error)
- goto fail_local;
-
- dlm_allow_conn = 1;
+ goto fail;
/* Start listening */
switch (dlm_config.ci_protocol) {
@@ -2022,25 +1951,38 @@ int dlm_lowcomms_start(void)
fail_listen:
dlm_proto_ops = NULL;
fail_proto_ops:
- dlm_allow_conn = 0;
- dlm_close_sock(&listen_con.sock);
work_stop();
-fail_local:
- deinit_local();
fail:
return error;
}
+void dlm_lowcomms_init(void)
+{
+ int i;
+
+ for (i = 0; i < CONN_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&connection_hash[i]);
+
+ INIT_WORK(&listen_con.rwork, process_listen_recv_socket);
+}
+
void dlm_lowcomms_exit(void)
{
- struct dlm_node_addr *na, *safe;
+ struct connection *con;
+ int i, idx;
- spin_lock(&dlm_node_addrs_spin);
- list_for_each_entry_safe(na, safe, &dlm_node_addrs, list) {
- list_del(&na->list);
- while (na->addr_count--)
- kfree(na->addr[na->addr_count]);
- kfree(na);
+ idx = srcu_read_lock(&connections_srcu);
+ for (i = 0; i < CONN_HASH_SIZE; i++) {
+ hlist_for_each_entry_rcu(con, &connection_hash[i], list) {
+ spin_lock(&connections_lock);
+ hlist_del_rcu(&con->list);
+ spin_unlock(&connections_lock);
+
+ if (con->othercon)
+ call_srcu(&connections_srcu, &con->othercon->rcu,
+ connection_release);
+ call_srcu(&connections_srcu, &con->rcu, connection_release);
+ }
}
- spin_unlock(&dlm_node_addrs_spin);
+ srcu_read_unlock(&connections_srcu, idx);
}
diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
index 29369feea991..3e8dca66183b 100644
--- a/fs/dlm/lowcomms.h
+++ b/fs/dlm/lowcomms.h
@@ -29,12 +29,14 @@ static inline int nodeid_hash(int nodeid)
return nodeid & (CONN_HASH_SIZE-1);
}
-/* switch to check if dlm is running */
-extern int dlm_allow_conn;
+/* check if dlm is running */
+bool dlm_lowcomms_is_running(void);
int dlm_lowcomms_start(void);
void dlm_lowcomms_shutdown(void);
+void dlm_lowcomms_shutdown_node(int nodeid, bool force);
void dlm_lowcomms_stop(void);
+void dlm_lowcomms_init(void);
void dlm_lowcomms_exit(void);
int dlm_lowcomms_close(int nodeid);
struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation,
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
index 1c5be4b70ac1..a77338be3237 100644
--- a/fs/dlm/main.c
+++ b/fs/dlm/main.c
@@ -17,7 +17,7 @@
#include "user.h"
#include "memory.h"
#include "config.h"
-#include "lowcomms.h"
+#include "midcomms.h"
#define CREATE_TRACE_POINTS
#include <trace/events/dlm.h>
@@ -30,6 +30,8 @@ static int __init init_dlm(void)
if (error)
goto out;
+ dlm_midcomms_init();
+
error = dlm_lockspace_init();
if (error)
goto out_mem;
@@ -66,6 +68,7 @@ static int __init init_dlm(void)
out_lockspace:
dlm_lockspace_exit();
out_mem:
+ dlm_midcomms_exit();
dlm_memory_exit();
out:
return error;
@@ -79,7 +82,7 @@ static void __exit exit_dlm(void)
dlm_config_exit();
dlm_memory_exit();
dlm_lockspace_exit();
- dlm_lowcomms_exit();
+ dlm_midcomms_exit();
dlm_unregister_debugfs();
}
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index 2af2ccfe43a9..923c01a8a0aa 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -573,7 +573,10 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
node = &rv->nodes[i];
if (dlm_is_member(ls, node->nodeid))
continue;
- dlm_add_member(ls, node);
+ error = dlm_add_member(ls, node);
+ if (error)
+ return error;
+
log_rinfo(ls, "add member %d", node->nodeid);
}
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
index ce35c3c19aeb..eb7a08641fcf 100644
--- a/fs/dlm/memory.c
+++ b/fs/dlm/memory.c
@@ -14,12 +14,14 @@
#include "lowcomms.h"
#include "config.h"
#include "memory.h"
+#include "ast.h"
static struct kmem_cache *writequeue_cache;
static struct kmem_cache *mhandle_cache;
static struct kmem_cache *msg_cache;
static struct kmem_cache *lkb_cache;
static struct kmem_cache *rsb_cache;
+static struct kmem_cache *cb_cache;
int __init dlm_memory_init(void)
@@ -46,8 +48,16 @@ int __init dlm_memory_init(void)
if (!rsb_cache)
goto rsb;
+ cb_cache = kmem_cache_create("dlm_cb", sizeof(struct dlm_callback),
+ __alignof__(struct dlm_callback), 0,
+ NULL);
+ if (!rsb_cache)
+ goto cb;
+
return 0;
+cb:
+ kmem_cache_destroy(rsb_cache);
rsb:
kmem_cache_destroy(msg_cache);
msg:
@@ -67,6 +77,7 @@ void dlm_memory_exit(void)
kmem_cache_destroy(msg_cache);
kmem_cache_destroy(lkb_cache);
kmem_cache_destroy(rsb_cache);
+ kmem_cache_destroy(cb_cache);
}
char *dlm_allocate_lvb(struct dlm_ls *ls)
@@ -115,12 +126,17 @@ void dlm_free_lkb(struct dlm_lkb *lkb)
kfree(ua);
}
}
+
+ /* drop references if they are set */
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cast, NULL);
+ dlm_callback_set_last_ptr(&lkb->lkb_last_cb, NULL);
+
kmem_cache_free(lkb_cache, lkb);
}
-struct dlm_mhandle *dlm_allocate_mhandle(void)
+struct dlm_mhandle *dlm_allocate_mhandle(gfp_t allocation)
{
- return kmem_cache_alloc(mhandle_cache, GFP_NOFS);
+ return kmem_cache_alloc(mhandle_cache, allocation);
}
void dlm_free_mhandle(struct dlm_mhandle *mhandle)
@@ -147,3 +163,13 @@ void dlm_free_msg(struct dlm_msg *msg)
{
kmem_cache_free(msg_cache, msg);
}
+
+struct dlm_callback *dlm_allocate_cb(void)
+{
+ return kmem_cache_alloc(cb_cache, GFP_ATOMIC);
+}
+
+void dlm_free_cb(struct dlm_callback *cb)
+{
+ kmem_cache_free(cb_cache, cb);
+}
diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h
index 7bd3f1a391ca..6b29563d24f7 100644
--- a/fs/dlm/memory.h
+++ b/fs/dlm/memory.h
@@ -20,12 +20,14 @@ struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls);
void dlm_free_lkb(struct dlm_lkb *l);
char *dlm_allocate_lvb(struct dlm_ls *ls);
void dlm_free_lvb(char *l);
-struct dlm_mhandle *dlm_allocate_mhandle(void);
+struct dlm_mhandle *dlm_allocate_mhandle(gfp_t allocation);
void dlm_free_mhandle(struct dlm_mhandle *mhandle);
struct writequeue_entry *dlm_allocate_writequeue(void);
void dlm_free_writequeue(struct writequeue_entry *writequeue);
struct dlm_msg *dlm_allocate_msg(gfp_t allocation);
void dlm_free_msg(struct dlm_msg *msg);
+struct dlm_callback *dlm_allocate_cb(void);
+void dlm_free_cb(struct dlm_callback *cb);
#endif /* __MEMORY_DOT_H__ */
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
index 6489bc22ad61..fc015a6abe17 100644
--- a/fs/dlm/midcomms.c
+++ b/fs/dlm/midcomms.c
@@ -132,6 +132,7 @@
*/
#define DLM_DEBUG_FENCE_TERMINATION 0
+#include <trace/events/dlm.h>
#include <net/tcp.h>
#include "dlm_internal.h"
@@ -194,7 +195,7 @@ struct midcomms_node {
};
struct dlm_mhandle {
- const struct dlm_header *inner_hd;
+ const union dlm_packet *inner_p;
struct midcomms_node *node;
struct dlm_opts *opts;
struct dlm_msg *msg;
@@ -305,11 +306,11 @@ static void dlm_send_queue_flush(struct midcomms_node *node)
pr_debug("flush midcomms send queue of node %d\n", node->nodeid);
rcu_read_lock();
- spin_lock(&node->send_queue_lock);
+ spin_lock_bh(&node->send_queue_lock);
list_for_each_entry_rcu(mh, &node->send_queue, list) {
dlm_mhandle_delete(node, mh);
}
- spin_unlock(&node->send_queue_lock);
+ spin_unlock_bh(&node->send_queue_lock);
rcu_read_unlock();
}
@@ -415,7 +416,7 @@ static int dlm_send_fin(struct midcomms_node *node,
m_header->h_cmd = DLM_FIN;
pr_debug("sending fin msg to node %d\n", node->nodeid);
- dlm_midcomms_commit_mhandle(mh);
+ dlm_midcomms_commit_mhandle(mh, NULL, 0);
set_bit(DLM_NODE_FLAG_STOP_TX, &node->flags);
return 0;
@@ -436,7 +437,7 @@ static void dlm_receive_ack(struct midcomms_node *node, uint32_t seq)
}
}
- spin_lock(&node->send_queue_lock);
+ spin_lock_bh(&node->send_queue_lock);
list_for_each_entry_rcu(mh, &node->send_queue, list) {
if (before(mh->seq, seq)) {
dlm_mhandle_delete(node, mh);
@@ -445,7 +446,7 @@ static void dlm_receive_ack(struct midcomms_node *node, uint32_t seq)
break;
}
}
- spin_unlock(&node->send_queue_lock);
+ spin_unlock_bh(&node->send_queue_lock);
rcu_read_unlock();
}
@@ -468,12 +469,26 @@ static void dlm_pas_fin_ack_rcv(struct midcomms_node *node)
spin_unlock(&node->state_lock);
log_print("%s: unexpected state: %d\n",
__func__, node->state);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return;
}
spin_unlock(&node->state_lock);
}
+static void dlm_receive_buffer_3_2_trace(uint32_t seq, union dlm_packet *p)
+{
+ switch (p->header.h_cmd) {
+ case DLM_MSG:
+ trace_dlm_recv_message(dlm_our_nodeid(), seq, &p->message);
+ break;
+ case DLM_RCOM:
+ trace_dlm_recv_rcom(dlm_our_nodeid(), seq, &p->rcom);
+ break;
+ default:
+ break;
+ }
+}
+
static void dlm_midcomms_receive_buffer(union dlm_packet *p,
struct midcomms_node *node,
uint32_t seq)
@@ -525,7 +540,7 @@ static void dlm_midcomms_receive_buffer(union dlm_packet *p,
spin_unlock(&node->state_lock);
log_print("%s: unexpected state: %d\n",
__func__, node->state);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return;
}
spin_unlock(&node->state_lock);
@@ -533,7 +548,8 @@ static void dlm_midcomms_receive_buffer(union dlm_packet *p,
set_bit(DLM_NODE_FLAG_STOP_RX, &node->flags);
break;
default:
- WARN_ON(test_bit(DLM_NODE_FLAG_STOP_RX, &node->flags));
+ WARN_ON_ONCE(test_bit(DLM_NODE_FLAG_STOP_RX, &node->flags));
+ dlm_receive_buffer_3_2_trace(seq, p);
dlm_receive_buffer(p, node->nodeid);
set_bit(DLM_NODE_ULP_DELIVERED, &node->flags);
break;
@@ -754,7 +770,7 @@ static void dlm_midcomms_receive_buffer_3_2(union dlm_packet *p, int nodeid)
goto out;
}
- WARN_ON(test_bit(DLM_NODE_FLAG_STOP_RX, &node->flags));
+ WARN_ON_ONCE(test_bit(DLM_NODE_FLAG_STOP_RX, &node->flags));
dlm_receive_buffer(p, nodeid);
break;
case DLM_OPTS:
@@ -874,12 +890,7 @@ static void dlm_midcomms_receive_buffer_3_1(union dlm_packet *p, int nodeid)
dlm_receive_buffer(p, nodeid);
}
-/*
- * Called from the low-level comms layer to process a buffer of
- * commands.
- */
-
-int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
+int dlm_validate_incoming_buffer(int nodeid, unsigned char *buf, int len)
{
const unsigned char *ptr = buf;
const struct dlm_header *hd;
@@ -914,6 +925,32 @@ int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
if (msglen > len)
break;
+ ret += msglen;
+ len -= msglen;
+ ptr += msglen;
+ }
+
+ return ret;
+}
+
+/*
+ * Called from the low-level comms layer to process a buffer of
+ * commands.
+ */
+int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
+{
+ const unsigned char *ptr = buf;
+ const struct dlm_header *hd;
+ uint16_t msglen;
+ int ret = 0;
+
+ while (len >= sizeof(struct dlm_header)) {
+ hd = (struct dlm_header *)ptr;
+
+ msglen = le16_to_cpu(hd->h_length);
+ if (msglen > len)
+ break;
+
switch (hd->h_version) {
case cpu_to_le32(DLM_VERSION_3_1):
dlm_midcomms_receive_buffer_3_1((union dlm_packet *)ptr, nodeid);
@@ -1030,9 +1067,9 @@ static void midcomms_new_msg_cb(void *data)
atomic_inc(&mh->node->send_queue_cnt);
- spin_lock(&mh->node->send_queue_lock);
+ spin_lock_bh(&mh->node->send_queue_lock);
list_add_tail_rcu(&mh->list, &mh->node->send_queue);
- spin_unlock(&mh->node->send_queue_lock);
+ spin_unlock_bh(&mh->node->send_queue_lock);
mh->seq = mh->node->seq_send++;
}
@@ -1055,7 +1092,7 @@ static struct dlm_msg *dlm_midcomms_get_msg_3_2(struct dlm_mhandle *mh, int node
dlm_fill_opts_header(opts, len, mh->seq);
*ppc += sizeof(*opts);
- mh->inner_hd = (const struct dlm_header *)*ppc;
+ mh->inner_p = (const union dlm_packet *)*ppc;
return msg;
}
@@ -1079,9 +1116,9 @@ struct dlm_mhandle *dlm_midcomms_get_mhandle(int nodeid, int len,
}
/* this is a bug, however we going on and hope it will be resolved */
- WARN_ON(test_bit(DLM_NODE_FLAG_STOP_TX, &node->flags));
+ WARN_ON_ONCE(test_bit(DLM_NODE_FLAG_STOP_TX, &node->flags));
- mh = dlm_allocate_mhandle();
+ mh = dlm_allocate_mhandle(allocation);
if (!mh)
goto err;
@@ -1111,7 +1148,7 @@ struct dlm_mhandle *dlm_midcomms_get_mhandle(int nodeid, int len,
break;
default:
dlm_free_mhandle(mh);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
goto err;
}
@@ -1130,11 +1167,32 @@ err:
}
#endif
-static void dlm_midcomms_commit_msg_3_2(struct dlm_mhandle *mh)
+static void dlm_midcomms_commit_msg_3_2_trace(const struct dlm_mhandle *mh,
+ const void *name, int namelen)
+{
+ switch (mh->inner_p->header.h_cmd) {
+ case DLM_MSG:
+ trace_dlm_send_message(mh->node->nodeid, mh->seq,
+ &mh->inner_p->message,
+ name, namelen);
+ break;
+ case DLM_RCOM:
+ trace_dlm_send_rcom(mh->node->nodeid, mh->seq,
+ &mh->inner_p->rcom);
+ break;
+ default:
+ /* nothing to trace */
+ break;
+ }
+}
+
+static void dlm_midcomms_commit_msg_3_2(struct dlm_mhandle *mh,
+ const void *name, int namelen)
{
/* nexthdr chain for fast lookup */
- mh->opts->o_nextcmd = mh->inner_hd->h_cmd;
+ mh->opts->o_nextcmd = mh->inner_p->header.h_cmd;
mh->committed = true;
+ dlm_midcomms_commit_msg_3_2_trace(mh, name, namelen);
dlm_lowcomms_commit_msg(mh->msg);
}
@@ -1142,8 +1200,10 @@ static void dlm_midcomms_commit_msg_3_2(struct dlm_mhandle *mh)
* dlm_midcomms_get_mhandle
*/
#ifndef __CHECKER__
-void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh)
+void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh,
+ const void *name, int namelen)
{
+
switch (mh->node->version) {
case DLM_VERSION_3_1:
srcu_read_unlock(&nodes_srcu, mh->idx);
@@ -1154,12 +1214,12 @@ void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh)
dlm_free_mhandle(mh);
break;
case DLM_VERSION_3_2:
- dlm_midcomms_commit_msg_3_2(mh);
+ dlm_midcomms_commit_msg_3_2(mh, name, namelen);
srcu_read_unlock(&nodes_srcu, mh->idx);
break;
default:
srcu_read_unlock(&nodes_srcu, mh->idx);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
break;
}
}
@@ -1167,12 +1227,27 @@ void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh)
int dlm_midcomms_start(void)
{
+ return dlm_lowcomms_start();
+}
+
+void dlm_midcomms_stop(void)
+{
+ dlm_lowcomms_stop();
+}
+
+void dlm_midcomms_init(void)
+{
int i;
for (i = 0; i < CONN_HASH_SIZE; i++)
INIT_HLIST_HEAD(&node_hash[i]);
- return dlm_lowcomms_start();
+ dlm_lowcomms_init();
+}
+
+void dlm_midcomms_exit(void)
+{
+ dlm_lowcomms_exit();
}
static void dlm_act_fin_ack_rcv(struct midcomms_node *node)
@@ -1201,7 +1276,7 @@ static void dlm_act_fin_ack_rcv(struct midcomms_node *node)
spin_unlock(&node->state_lock);
log_print("%s: unexpected state: %d\n",
__func__, node->state);
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return;
}
spin_unlock(&node->state_lock);
@@ -1319,7 +1394,7 @@ static void midcomms_node_release(struct rcu_head *rcu)
{
struct midcomms_node *node = container_of(rcu, struct midcomms_node, rcu);
- WARN_ON(atomic_read(&node->send_queue_cnt));
+ WARN_ON_ONCE(atomic_read(&node->send_queue_cnt));
kfree(node);
}
@@ -1372,11 +1447,13 @@ static void midcomms_shutdown(struct midcomms_node *node)
pr_debug("active shutdown timed out for node %d with state %s\n",
node->nodeid, dlm_state_str(node->state));
midcomms_node_reset(node);
+ dlm_lowcomms_shutdown_node(node->nodeid, true);
return;
}
pr_debug("active shutdown done for node %d with state %s\n",
node->nodeid, dlm_state_str(node->state));
+ dlm_lowcomms_shutdown_node(node->nodeid, false);
}
void dlm_midcomms_shutdown(void)
@@ -1384,6 +1461,8 @@ void dlm_midcomms_shutdown(void)
struct midcomms_node *node;
int i, idx;
+ dlm_lowcomms_shutdown();
+
mutex_lock(&close_lock);
idx = srcu_read_lock(&nodes_srcu);
for (i = 0; i < CONN_HASH_SIZE; i++) {
@@ -1401,8 +1480,6 @@ void dlm_midcomms_shutdown(void)
}
srcu_read_unlock(&nodes_srcu, idx);
mutex_unlock(&close_lock);
-
- dlm_lowcomms_shutdown();
}
int dlm_midcomms_close(int nodeid)
diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h
index 82bcd9661922..bea1cee4279c 100644
--- a/fs/dlm/midcomms.h
+++ b/fs/dlm/midcomms.h
@@ -14,12 +14,17 @@
struct midcomms_node;
+int dlm_validate_incoming_buffer(int nodeid, unsigned char *buf, int len);
int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int buflen);
struct dlm_mhandle *dlm_midcomms_get_mhandle(int nodeid, int len,
gfp_t allocation, char **ppc);
-void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh);
+void dlm_midcomms_commit_mhandle(struct dlm_mhandle *mh, const void *name,
+ int namelen);
int dlm_midcomms_close(int nodeid);
int dlm_midcomms_start(void);
+void dlm_midcomms_stop(void);
+void dlm_midcomms_init(void);
+void dlm_midcomms_exit(void);
void dlm_midcomms_shutdown(void);
void dlm_midcomms_add_member(int nodeid);
void dlm_midcomms_remove_member(int nodeid);
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index f19860315043..b76d52e2f6bd 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -91,7 +91,7 @@ static int create_rcom_stateless(struct dlm_ls *ls, int to_nodeid, int type,
static void send_rcom(struct dlm_mhandle *mh, struct dlm_rcom *rc)
{
- dlm_midcomms_commit_mhandle(mh);
+ dlm_midcomms_commit_mhandle(mh, NULL, 0);
}
static void send_rcom_stateless(struct dlm_msg *msg, struct dlm_rcom *rc)
@@ -516,7 +516,7 @@ int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
rf = (struct rcom_config *) rc->rc_buf;
rf->rf_lvblen = cpu_to_le32(~0U);
- dlm_midcomms_commit_mhandle(mh);
+ dlm_midcomms_commit_mhandle(mh, NULL, 0);
return 0;
}
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index 036a9a0078f6..8be2893ad15b 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -44,7 +44,8 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms)
e->recover_seq = ls->ls_recover_seq & 0xFFFFFFFF;
e->nodeid = nodeid;
- memcpy(&e->request, ms, le16_to_cpu(ms->m_header.h_length));
+ memcpy(&e->request, ms, sizeof(*ms));
+ memcpy(&e->request.m_extra, ms->m_extra, length);
atomic_inc(&ls->ls_requestqueue_cnt);
mutex_lock(&ls->ls_requestqueue_mutex);
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index c5d27bccc3dc..35129505ddda 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -25,6 +25,7 @@
#include "user.h"
#include "ast.h"
#include "config.h"
+#include "memory.h"
static const char name_prefix[] = "dlm";
static const struct file_operations device_fops;
@@ -175,7 +176,7 @@ static int lkb_is_endoflife(int mode, int status)
being removed and then remove that lkb from the orphans list and free it */
void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
- int status, uint32_t sbflags, uint64_t seq)
+ int status, uint32_t sbflags)
{
struct dlm_ls *ls;
struct dlm_user_args *ua;
@@ -209,16 +210,22 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
spin_lock(&proc->asts_spin);
- rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
- if (rv < 0) {
+ rv = dlm_enqueue_lkb_callback(lkb, flags, mode, status, sbflags);
+ switch (rv) {
+ case DLM_ENQUEUE_CALLBACK_FAILURE:
spin_unlock(&proc->asts_spin);
+ WARN_ON_ONCE(1);
goto out;
- }
-
- if (list_empty(&lkb->lkb_cb_list)) {
+ case DLM_ENQUEUE_CALLBACK_NEED_SCHED:
kref_get(&lkb->lkb_ref);
list_add_tail(&lkb->lkb_cb_list, &proc->asts);
wake_up_interruptible(&proc->wait);
+ break;
+ case DLM_ENQUEUE_CALLBACK_SUCCESS:
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
}
spin_unlock(&proc->asts_spin);
@@ -800,8 +807,8 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
struct dlm_user_proc *proc = file->private_data;
struct dlm_lkb *lkb;
DECLARE_WAITQUEUE(wait, current);
- struct dlm_callback cb;
- int rv, resid, copy_lvb = 0;
+ struct dlm_callback *cb;
+ int rv, copy_lvb = 0;
int old_mode, new_mode;
if (count == sizeof(struct dlm_device_version)) {
@@ -857,53 +864,58 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
without removing lkb_cb_list; so empty lkb_cb_list is always
consistent with empty lkb_callbacks */
- lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_cb_list);
+ lkb = list_first_entry(&proc->asts, struct dlm_lkb, lkb_cb_list);
/* rem_lkb_callback sets a new lkb_last_cast */
- old_mode = lkb->lkb_last_cast.mode;
+ old_mode = lkb->lkb_last_cast->mode;
- rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid);
- if (rv < 0) {
+ rv = dlm_dequeue_lkb_callback(lkb, &cb);
+ switch (rv) {
+ case DLM_DEQUEUE_CALLBACK_EMPTY:
/* this shouldn't happen; lkb should have been removed from
- list when resid was zero */
+ * list when last item was dequeued
+ */
log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id);
list_del_init(&lkb->lkb_cb_list);
spin_unlock(&proc->asts_spin);
/* removes ref for proc->asts, may cause lkb to be freed */
dlm_put_lkb(lkb);
+ WARN_ON_ONCE(1);
goto try_another;
- }
- if (!resid)
+ case DLM_DEQUEUE_CALLBACK_LAST:
list_del_init(&lkb->lkb_cb_list);
- spin_unlock(&proc->asts_spin);
-
- if (cb.flags & DLM_CB_SKIP) {
- /* removes ref for proc->asts, may cause lkb to be freed */
- if (!resid)
- dlm_put_lkb(lkb);
- goto try_another;
+ lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
+ break;
+ case DLM_DEQUEUE_CALLBACK_SUCCESS:
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
}
+ spin_unlock(&proc->asts_spin);
- if (cb.flags & DLM_CB_BAST) {
- trace_dlm_bast(lkb->lkb_resource->res_ls, lkb, cb.mode);
- } else if (cb.flags & DLM_CB_CAST) {
- new_mode = cb.mode;
+ if (cb->flags & DLM_CB_BAST) {
+ trace_dlm_bast(lkb->lkb_resource->res_ls, lkb, cb->mode);
+ } else if (cb->flags & DLM_CB_CAST) {
+ new_mode = cb->mode;
- if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
+ if (!cb->sb_status && lkb->lkb_lksb->sb_lvbptr &&
dlm_lvb_operations[old_mode + 1][new_mode + 1])
copy_lvb = 1;
- lkb->lkb_lksb->sb_status = cb.sb_status;
- lkb->lkb_lksb->sb_flags = cb.sb_flags;
+ lkb->lkb_lksb->sb_status = cb->sb_status;
+ lkb->lkb_lksb->sb_flags = cb->sb_flags;
trace_dlm_ast(lkb->lkb_resource->res_ls, lkb);
}
rv = copy_result_to_user(lkb->lkb_ua,
test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
- cb.flags, cb.mode, copy_lvb, buf, count);
+ cb->flags, cb->mode, copy_lvb, buf, count);
+
+ kref_put(&cb->ref, dlm_release_callback);
/* removes ref for proc->asts, may cause lkb to be freed */
- if (!resid)
+ if (rv == DLM_DEQUEUE_CALLBACK_LAST)
dlm_put_lkb(lkb);
return rv;
diff --git a/fs/dlm/user.h b/fs/dlm/user.h
index 6b9bce6b96e0..33059452d79e 100644
--- a/fs/dlm/user.h
+++ b/fs/dlm/user.h
@@ -7,7 +7,7 @@
#define __USER_DOT_H__
void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
- int status, uint32_t sbflags, uint64_t seq);
+ int status, uint32_t sbflags);
int dlm_user_init(void);
void dlm_user_exit(void);
int dlm_device_deregister(struct dlm_ls *ls);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index c214fe0981bd..f3cd00fac9c3 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -18,6 +18,8 @@
#include <linux/fs_stack.h>
#include <linux/slab.h>
#include <linux/xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#include <linux/fileattr.h>
#include <asm/unaligned.h>
#include "ecryptfs_kernel.h"
@@ -1120,6 +1122,28 @@ static int ecryptfs_fileattr_set(struct user_namespace *mnt_userns,
return rc;
}
+static struct posix_acl *ecryptfs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type)
+{
+ return vfs_get_acl(mnt_userns, ecryptfs_dentry_to_lower(dentry),
+ posix_acl_xattr_name(type));
+}
+
+static int ecryptfs_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct posix_acl *acl,
+ int type)
+{
+ int rc;
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_inode = d_inode(lower_dentry);
+
+ rc = vfs_set_acl(&init_user_ns, lower_dentry,
+ posix_acl_xattr_name(type), acl);
+ if (!rc)
+ fsstack_copy_attr_all(d_inode(dentry), lower_inode);
+ return rc;
+}
+
const struct inode_operations ecryptfs_symlink_iops = {
.get_link = ecryptfs_get_link,
.permission = ecryptfs_permission,
@@ -1143,6 +1167,8 @@ const struct inode_operations ecryptfs_dir_iops = {
.listxattr = ecryptfs_listxattr,
.fileattr_get = ecryptfs_fileattr_get,
.fileattr_set = ecryptfs_fileattr_set,
+ .get_acl = ecryptfs_get_acl,
+ .set_acl = ecryptfs_set_acl,
};
const struct inode_operations ecryptfs_main_iops = {
@@ -1152,6 +1178,8 @@ const struct inode_operations ecryptfs_main_iops = {
.listxattr = ecryptfs_listxattr,
.fileattr_get = ecryptfs_fileattr_get,
.fileattr_set = ecryptfs_fileattr_set,
+ .get_acl = ecryptfs_get_acl,
+ .set_acl = ecryptfs_set_acl,
};
static int ecryptfs_xattr_get(const struct xattr_handler *handler,
@@ -1182,6 +1210,10 @@ static const struct xattr_handler ecryptfs_xattr_handler = {
};
const struct xattr_handler *ecryptfs_xattr_handlers[] = {
+#ifdef CONFIG_FS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
+#endif
&ecryptfs_xattr_handler,
NULL
};
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index fe8ac0e163f7..f57f921683d7 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -13,9 +13,7 @@
void erofs_unmap_metabuf(struct erofs_buf *buf)
{
if (buf->kmap_type == EROFS_KMAP)
- kunmap(buf->page);
- else if (buf->kmap_type == EROFS_KMAP_ATOMIC)
- kunmap_atomic(buf->base);
+ kunmap_local(buf->base);
buf->base = NULL;
buf->kmap_type = EROFS_NO_KMAP;
}
@@ -54,9 +52,7 @@ void *erofs_bread(struct erofs_buf *buf, struct inode *inode,
}
if (buf->kmap_type == EROFS_NO_KMAP) {
if (type == EROFS_KMAP)
- buf->base = kmap(page);
- else if (type == EROFS_KMAP_ATOMIC)
- buf->base = kmap_atomic(page);
+ buf->base = kmap_local_page(page);
buf->kmap_type = type;
} else if (buf->kmap_type != type) {
DBG_BUGON(1);
@@ -403,6 +399,8 @@ const struct address_space_operations erofs_raw_access_aops = {
.readahead = erofs_readahead,
.bmap = erofs_bmap,
.direct_IO = noop_direct_IO,
+ .release_folio = iomap_release_folio,
+ .invalidate_folio = iomap_invalidate_folio,
};
#ifdef CONFIG_FS_DAX
diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c
index fe05bc51f9f2..014e20962376 100644
--- a/fs/erofs/fscache.c
+++ b/fs/erofs/fscache.c
@@ -11,261 +11,201 @@ static DEFINE_MUTEX(erofs_domain_cookies_lock);
static LIST_HEAD(erofs_domain_list);
static struct vfsmount *erofs_pseudo_mnt;
-static struct netfs_io_request *erofs_fscache_alloc_request(struct address_space *mapping,
+struct erofs_fscache_request {
+ struct erofs_fscache_request *primary;
+ struct netfs_cache_resources cache_resources;
+ struct address_space *mapping; /* The mapping being accessed */
+ loff_t start; /* Start position */
+ size_t len; /* Length of the request */
+ size_t submitted; /* Length of submitted */
+ short error; /* 0 or error that occurred */
+ refcount_t ref;
+};
+
+static struct erofs_fscache_request *erofs_fscache_req_alloc(struct address_space *mapping,
loff_t start, size_t len)
{
- struct netfs_io_request *rreq;
+ struct erofs_fscache_request *req;
- rreq = kzalloc(sizeof(struct netfs_io_request), GFP_KERNEL);
- if (!rreq)
+ req = kzalloc(sizeof(struct erofs_fscache_request), GFP_KERNEL);
+ if (!req)
return ERR_PTR(-ENOMEM);
- rreq->start = start;
- rreq->len = len;
- rreq->mapping = mapping;
- rreq->inode = mapping->host;
- INIT_LIST_HEAD(&rreq->subrequests);
- refcount_set(&rreq->ref, 1);
- return rreq;
-}
+ req->mapping = mapping;
+ req->start = start;
+ req->len = len;
+ refcount_set(&req->ref, 1);
-static void erofs_fscache_put_request(struct netfs_io_request *rreq)
-{
- if (!refcount_dec_and_test(&rreq->ref))
- return;
- if (rreq->cache_resources.ops)
- rreq->cache_resources.ops->end_operation(&rreq->cache_resources);
- kfree(rreq);
+ return req;
}
-static void erofs_fscache_put_subrequest(struct netfs_io_subrequest *subreq)
+static struct erofs_fscache_request *erofs_fscache_req_chain(struct erofs_fscache_request *primary,
+ size_t len)
{
- if (!refcount_dec_and_test(&subreq->ref))
- return;
- erofs_fscache_put_request(subreq->rreq);
- kfree(subreq);
-}
+ struct erofs_fscache_request *req;
-static void erofs_fscache_clear_subrequests(struct netfs_io_request *rreq)
-{
- struct netfs_io_subrequest *subreq;
+ /* use primary request for the first submission */
+ if (!primary->submitted) {
+ refcount_inc(&primary->ref);
+ return primary;
+ }
- while (!list_empty(&rreq->subrequests)) {
- subreq = list_first_entry(&rreq->subrequests,
- struct netfs_io_subrequest, rreq_link);
- list_del(&subreq->rreq_link);
- erofs_fscache_put_subrequest(subreq);
+ req = erofs_fscache_req_alloc(primary->mapping,
+ primary->start + primary->submitted, len);
+ if (!IS_ERR(req)) {
+ req->primary = primary;
+ refcount_inc(&primary->ref);
}
+ return req;
}
-static void erofs_fscache_rreq_unlock_folios(struct netfs_io_request *rreq)
+static void erofs_fscache_req_complete(struct erofs_fscache_request *req)
{
- struct netfs_io_subrequest *subreq;
struct folio *folio;
- unsigned int iopos = 0;
- pgoff_t start_page = rreq->start / PAGE_SIZE;
- pgoff_t last_page = ((rreq->start + rreq->len) / PAGE_SIZE) - 1;
- bool subreq_failed = false;
+ bool failed = req->error;
+ pgoff_t start_page = req->start / PAGE_SIZE;
+ pgoff_t last_page = ((req->start + req->len) / PAGE_SIZE) - 1;
- XA_STATE(xas, &rreq->mapping->i_pages, start_page);
-
- subreq = list_first_entry(&rreq->subrequests,
- struct netfs_io_subrequest, rreq_link);
- subreq_failed = (subreq->error < 0);
+ XA_STATE(xas, &req->mapping->i_pages, start_page);
rcu_read_lock();
xas_for_each(&xas, folio, last_page) {
- unsigned int pgpos =
- (folio_index(folio) - start_page) * PAGE_SIZE;
- unsigned int pgend = pgpos + folio_size(folio);
- bool pg_failed = false;
-
- for (;;) {
- if (!subreq) {
- pg_failed = true;
- break;
- }
-
- pg_failed |= subreq_failed;
- if (pgend < iopos + subreq->len)
- break;
-
- iopos += subreq->len;
- if (!list_is_last(&subreq->rreq_link,
- &rreq->subrequests)) {
- subreq = list_next_entry(subreq, rreq_link);
- subreq_failed = (subreq->error < 0);
- } else {
- subreq = NULL;
- subreq_failed = false;
- }
- if (pgend == iopos)
- break;
- }
-
- if (!pg_failed)
+ if (xas_retry(&xas, folio))
+ continue;
+ if (!failed)
folio_mark_uptodate(folio);
-
folio_unlock(folio);
}
rcu_read_unlock();
}
-static void erofs_fscache_rreq_complete(struct netfs_io_request *rreq)
+static void erofs_fscache_req_put(struct erofs_fscache_request *req)
{
- erofs_fscache_rreq_unlock_folios(rreq);
- erofs_fscache_clear_subrequests(rreq);
- erofs_fscache_put_request(rreq);
+ if (refcount_dec_and_test(&req->ref)) {
+ if (req->cache_resources.ops)
+ req->cache_resources.ops->end_operation(&req->cache_resources);
+ if (!req->primary)
+ erofs_fscache_req_complete(req);
+ else
+ erofs_fscache_req_put(req->primary);
+ kfree(req);
+ }
}
-static void erofc_fscache_subreq_complete(void *priv,
+static void erofs_fscache_subreq_complete(void *priv,
ssize_t transferred_or_error, bool was_async)
{
- struct netfs_io_subrequest *subreq = priv;
- struct netfs_io_request *rreq = subreq->rreq;
-
- if (IS_ERR_VALUE(transferred_or_error))
- subreq->error = transferred_or_error;
+ struct erofs_fscache_request *req = priv;
- if (atomic_dec_and_test(&rreq->nr_outstanding))
- erofs_fscache_rreq_complete(rreq);
-
- erofs_fscache_put_subrequest(subreq);
+ if (IS_ERR_VALUE(transferred_or_error)) {
+ if (req->primary)
+ req->primary->error = transferred_or_error;
+ else
+ req->error = transferred_or_error;
+ }
+ erofs_fscache_req_put(req);
}
/*
- * Read data from fscache and fill the read data into page cache described by
- * @rreq, which shall be both aligned with PAGE_SIZE. @pstart describes
- * the start physical address in the cache file.
+ * Read data from fscache (cookie, pstart, len), and fill the read data into
+ * page cache described by (req->mapping, lstart, len). @pstart describeis the
+ * start physical address in the cache file.
*/
static int erofs_fscache_read_folios_async(struct fscache_cookie *cookie,
- struct netfs_io_request *rreq, loff_t pstart)
+ struct erofs_fscache_request *req, loff_t pstart, size_t len)
{
enum netfs_io_source source;
- struct super_block *sb = rreq->mapping->host->i_sb;
- struct netfs_io_subrequest *subreq;
- struct netfs_cache_resources *cres = &rreq->cache_resources;
+ struct super_block *sb = req->mapping->host->i_sb;
+ struct netfs_cache_resources *cres = &req->cache_resources;
struct iov_iter iter;
- loff_t start = rreq->start;
- size_t len = rreq->len;
+ loff_t lstart = req->start + req->submitted;
size_t done = 0;
int ret;
- atomic_set(&rreq->nr_outstanding, 1);
+ DBG_BUGON(len > req->len - req->submitted);
ret = fscache_begin_read_operation(cres, cookie);
if (ret)
- goto out;
+ return ret;
while (done < len) {
- subreq = kzalloc(sizeof(struct netfs_io_subrequest),
- GFP_KERNEL);
- if (subreq) {
- INIT_LIST_HEAD(&subreq->rreq_link);
- refcount_set(&subreq->ref, 2);
- subreq->rreq = rreq;
- refcount_inc(&rreq->ref);
- } else {
- ret = -ENOMEM;
- goto out;
- }
-
- subreq->start = pstart + done;
- subreq->len = len - done;
- subreq->flags = 1 << NETFS_SREQ_ONDEMAND;
+ loff_t sstart = pstart + done;
+ size_t slen = len - done;
+ unsigned long flags = 1 << NETFS_SREQ_ONDEMAND;
- list_add_tail(&subreq->rreq_link, &rreq->subrequests);
-
- source = cres->ops->prepare_read(subreq, LLONG_MAX);
- if (WARN_ON(subreq->len == 0))
+ source = cres->ops->prepare_ondemand_read(cres,
+ sstart, &slen, LLONG_MAX, &flags, 0);
+ if (WARN_ON(slen == 0))
source = NETFS_INVALID_READ;
if (source != NETFS_READ_FROM_CACHE) {
- erofs_err(sb, "failed to fscache prepare_read (source %d)",
- source);
- ret = -EIO;
- subreq->error = ret;
- erofs_fscache_put_subrequest(subreq);
- goto out;
+ erofs_err(sb, "failed to fscache prepare_read (source %d)", source);
+ return -EIO;
}
- atomic_inc(&rreq->nr_outstanding);
+ refcount_inc(&req->ref);
+ iov_iter_xarray(&iter, ITER_DEST, &req->mapping->i_pages,
+ lstart + done, slen);
- iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages,
- start + done, subreq->len);
-
- ret = fscache_read(cres, subreq->start, &iter,
- NETFS_READ_HOLE_FAIL,
- erofc_fscache_subreq_complete, subreq);
+ ret = fscache_read(cres, sstart, &iter, NETFS_READ_HOLE_FAIL,
+ erofs_fscache_subreq_complete, req);
if (ret == -EIOCBQUEUED)
ret = 0;
if (ret) {
erofs_err(sb, "failed to fscache_read (ret %d)", ret);
- goto out;
+ return ret;
}
- done += subreq->len;
+ done += slen;
}
-out:
- if (atomic_dec_and_test(&rreq->nr_outstanding))
- erofs_fscache_rreq_complete(rreq);
-
- return ret;
+ DBG_BUGON(done != len);
+ return 0;
}
static int erofs_fscache_meta_read_folio(struct file *data, struct folio *folio)
{
int ret;
struct super_block *sb = folio_mapping(folio)->host->i_sb;
- struct netfs_io_request *rreq;
+ struct erofs_fscache_request *req;
struct erofs_map_dev mdev = {
.m_deviceid = 0,
.m_pa = folio_pos(folio),
};
ret = erofs_map_dev(sb, &mdev);
- if (ret)
- goto out;
+ if (ret) {
+ folio_unlock(folio);
+ return ret;
+ }
- rreq = erofs_fscache_alloc_request(folio_mapping(folio),
+ req = erofs_fscache_req_alloc(folio_mapping(folio),
folio_pos(folio), folio_size(folio));
- if (IS_ERR(rreq)) {
- ret = PTR_ERR(rreq);
- goto out;
+ if (IS_ERR(req)) {
+ folio_unlock(folio);
+ return PTR_ERR(req);
}
- return erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
- rreq, mdev.m_pa);
-out:
- folio_unlock(folio);
+ ret = erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
+ req, mdev.m_pa, folio_size(folio));
+ if (ret)
+ req->error = ret;
+
+ erofs_fscache_req_put(req);
return ret;
}
-/*
- * Read into page cache in the range described by (@pos, @len).
- *
- * On return, the caller is responsible for page unlocking if the output @unlock
- * is true, or the callee will take this responsibility through netfs_io_request
- * interface.
- *
- * The return value is the number of bytes successfully handled, or negative
- * error code on failure. The only exception is that, the length of the range
- * instead of the error code is returned on failure after netfs_io_request is
- * allocated, so that .readahead() could advance rac accordingly.
- */
-static int erofs_fscache_data_read(struct address_space *mapping,
- loff_t pos, size_t len, bool *unlock)
+static int erofs_fscache_data_read_slice(struct erofs_fscache_request *primary)
{
+ struct address_space *mapping = primary->mapping;
struct inode *inode = mapping->host;
struct super_block *sb = inode->i_sb;
- struct netfs_io_request *rreq;
+ struct erofs_fscache_request *req;
struct erofs_map_blocks map;
struct erofs_map_dev mdev;
struct iov_iter iter;
+ loff_t pos = primary->start + primary->submitted;
size_t count;
int ret;
- *unlock = true;
-
map.m_la = pos;
ret = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW);
if (ret)
@@ -286,23 +226,28 @@ static int erofs_fscache_data_read(struct address_space *mapping,
if (IS_ERR(src))
return PTR_ERR(src);
- iov_iter_xarray(&iter, READ, &mapping->i_pages, pos, PAGE_SIZE);
- if (copy_to_iter(src + offset, size, &iter) != size)
+ iov_iter_xarray(&iter, ITER_DEST, &mapping->i_pages, pos, PAGE_SIZE);
+ if (copy_to_iter(src + offset, size, &iter) != size) {
+ erofs_put_metabuf(&buf);
return -EFAULT;
+ }
iov_iter_zero(PAGE_SIZE - size, &iter);
erofs_put_metabuf(&buf);
- return PAGE_SIZE;
+ primary->submitted += PAGE_SIZE;
+ return 0;
}
- count = min_t(size_t, map.m_llen - (pos - map.m_la), len);
- DBG_BUGON(!count || count % PAGE_SIZE);
-
+ count = primary->len - primary->submitted;
if (!(map.m_flags & EROFS_MAP_MAPPED)) {
- iov_iter_xarray(&iter, READ, &mapping->i_pages, pos, count);
+ iov_iter_xarray(&iter, ITER_DEST, &mapping->i_pages, pos, count);
iov_iter_zero(count, &iter);
- return count;
+ primary->submitted += count;
+ return 0;
}
+ count = min_t(size_t, map.m_llen - (pos - map.m_la), count);
+ DBG_BUGON(!count || count % PAGE_SIZE);
+
mdev = (struct erofs_map_dev) {
.m_deviceid = map.m_deviceid,
.m_pa = map.m_pa,
@@ -311,64 +256,65 @@ static int erofs_fscache_data_read(struct address_space *mapping,
if (ret)
return ret;
- rreq = erofs_fscache_alloc_request(mapping, pos, count);
- if (IS_ERR(rreq))
- return PTR_ERR(rreq);
+ req = erofs_fscache_req_chain(primary, count);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
- *unlock = false;
- erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
- rreq, mdev.m_pa + (pos - map.m_la));
- return count;
+ ret = erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
+ req, mdev.m_pa + (pos - map.m_la), count);
+ erofs_fscache_req_put(req);
+ primary->submitted += count;
+ return ret;
}
-static int erofs_fscache_read_folio(struct file *file, struct folio *folio)
+static int erofs_fscache_data_read(struct erofs_fscache_request *req)
{
- bool unlock;
int ret;
- DBG_BUGON(folio_size(folio) != EROFS_BLKSIZ);
+ do {
+ ret = erofs_fscache_data_read_slice(req);
+ if (ret)
+ req->error = ret;
+ } while (!ret && req->submitted < req->len);
- ret = erofs_fscache_data_read(folio_mapping(folio), folio_pos(folio),
- folio_size(folio), &unlock);
- if (unlock) {
- if (ret > 0)
- folio_mark_uptodate(folio);
+ return ret;
+}
+
+static int erofs_fscache_read_folio(struct file *file, struct folio *folio)
+{
+ struct erofs_fscache_request *req;
+ int ret;
+
+ req = erofs_fscache_req_alloc(folio_mapping(folio),
+ folio_pos(folio), folio_size(folio));
+ if (IS_ERR(req)) {
folio_unlock(folio);
+ return PTR_ERR(req);
}
- return ret < 0 ? ret : 0;
+
+ ret = erofs_fscache_data_read(req);
+ erofs_fscache_req_put(req);
+ return ret;
}
static void erofs_fscache_readahead(struct readahead_control *rac)
{
- struct folio *folio;
- size_t len, done = 0;
- loff_t start, pos;
- bool unlock;
- int ret, size;
+ struct erofs_fscache_request *req;
if (!readahead_count(rac))
return;
- start = readahead_pos(rac);
- len = readahead_length(rac);
+ req = erofs_fscache_req_alloc(rac->mapping,
+ readahead_pos(rac), readahead_length(rac));
+ if (IS_ERR(req))
+ return;
- do {
- pos = start + done;
- ret = erofs_fscache_data_read(rac->mapping, pos,
- len - done, &unlock);
- if (ret <= 0)
- return;
+ /* The request completion will drop refs on the folios. */
+ while (readahead_folio(rac))
+ ;
- size = ret;
- while (size) {
- folio = readahead_folio(rac);
- size -= folio_size(folio);
- if (unlock) {
- folio_mark_uptodate(folio);
- folio_unlock(folio);
- }
- }
- } while ((done += ret) < len);
+ erofs_fscache_data_read(req);
+ erofs_fscache_req_put(req);
}
static const struct address_space_operations erofs_fscache_meta_aops = {
@@ -403,13 +349,13 @@ static void erofs_fscache_domain_put(struct erofs_domain *domain)
static int erofs_fscache_register_volume(struct super_block *sb)
{
struct erofs_sb_info *sbi = EROFS_SB(sb);
- char *domain_id = sbi->opt.domain_id;
+ char *domain_id = sbi->domain_id;
struct fscache_volume *volume;
char *name;
int ret = 0;
name = kasprintf(GFP_KERNEL, "erofs,%s",
- domain_id ? domain_id : sbi->opt.fsid);
+ domain_id ? domain_id : sbi->fsid);
if (!name)
return -ENOMEM;
@@ -435,7 +381,7 @@ static int erofs_fscache_init_domain(struct super_block *sb)
if (!domain)
return -ENOMEM;
- domain->domain_id = kstrdup(sbi->opt.domain_id, GFP_KERNEL);
+ domain->domain_id = kstrdup(sbi->domain_id, GFP_KERNEL);
if (!domain->domain_id) {
kfree(domain);
return -ENOMEM;
@@ -472,7 +418,7 @@ static int erofs_fscache_register_domain(struct super_block *sb)
mutex_lock(&erofs_domain_list_lock);
list_for_each_entry(domain, &erofs_domain_list, list) {
- if (!strcmp(domain->domain_id, sbi->opt.domain_id)) {
+ if (!strcmp(domain->domain_id, sbi->domain_id)) {
sbi->domain = domain;
sbi->volume = domain->volume;
refcount_inc(&domain->ref);
@@ -487,7 +433,8 @@ static int erofs_fscache_register_domain(struct super_block *sb)
static
struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb,
- char *name, bool need_inode)
+ char *name,
+ unsigned int flags)
{
struct fscache_volume *volume = EROFS_SB(sb)->volume;
struct erofs_fscache *ctx;
@@ -509,7 +456,7 @@ struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb,
fscache_use_cookie(cookie, false);
ctx->cookie = cookie;
- if (need_inode) {
+ if (flags & EROFS_REG_COOKIE_NEED_INODE) {
struct inode *const inode = new_inode(sb);
if (!inode) {
@@ -547,14 +494,15 @@ static void erofs_fscache_relinquish_cookie(struct erofs_fscache *ctx)
static
struct erofs_fscache *erofs_fscache_domain_init_cookie(struct super_block *sb,
- char *name, bool need_inode)
+ char *name,
+ unsigned int flags)
{
int err;
struct inode *inode;
struct erofs_fscache *ctx;
struct erofs_domain *domain = EROFS_SB(sb)->domain;
- ctx = erofs_fscache_acquire_cookie(sb, name, need_inode);
+ ctx = erofs_fscache_acquire_cookie(sb, name, flags);
if (IS_ERR(ctx))
return ctx;
@@ -582,7 +530,8 @@ out:
static
struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
- char *name, bool need_inode)
+ char *name,
+ unsigned int flags)
{
struct inode *inode;
struct erofs_fscache *ctx;
@@ -595,23 +544,30 @@ struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
ctx = inode->i_private;
if (!ctx || ctx->domain != domain || strcmp(ctx->name, name))
continue;
- igrab(inode);
+ if (!(flags & EROFS_REG_COOKIE_NEED_NOEXIST)) {
+ igrab(inode);
+ } else {
+ erofs_err(sb, "%s already exists in domain %s", name,
+ domain->domain_id);
+ ctx = ERR_PTR(-EEXIST);
+ }
spin_unlock(&psb->s_inode_list_lock);
mutex_unlock(&erofs_domain_cookies_lock);
return ctx;
}
spin_unlock(&psb->s_inode_list_lock);
- ctx = erofs_fscache_domain_init_cookie(sb, name, need_inode);
+ ctx = erofs_fscache_domain_init_cookie(sb, name, flags);
mutex_unlock(&erofs_domain_cookies_lock);
return ctx;
}
struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
- char *name, bool need_inode)
+ char *name,
+ unsigned int flags)
{
- if (EROFS_SB(sb)->opt.domain_id)
- return erofs_domain_register_cookie(sb, name, need_inode);
- return erofs_fscache_acquire_cookie(sb, name, need_inode);
+ if (EROFS_SB(sb)->domain_id)
+ return erofs_domain_register_cookie(sb, name, flags);
+ return erofs_fscache_acquire_cookie(sb, name, flags);
}
void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
@@ -640,16 +596,29 @@ int erofs_fscache_register_fs(struct super_block *sb)
int ret;
struct erofs_sb_info *sbi = EROFS_SB(sb);
struct erofs_fscache *fscache;
+ unsigned int flags;
- if (sbi->opt.domain_id)
+ if (sbi->domain_id)
ret = erofs_fscache_register_domain(sb);
else
ret = erofs_fscache_register_volume(sb);
if (ret)
return ret;
- /* acquired domain/volume will be relinquished in kill_sb() on error */
- fscache = erofs_fscache_register_cookie(sb, sbi->opt.fsid, true);
+ /*
+ * When shared domain is enabled, using NEED_NOEXIST to guarantee
+ * the primary data blob (aka fsid) is unique in the shared domain.
+ *
+ * For non-shared-domain case, fscache_acquire_volume() invoked by
+ * erofs_fscache_register_volume() has already guaranteed
+ * the uniqueness of primary data blob.
+ *
+ * Acquired domain/volume will be relinquished in kill_sb() on error.
+ */
+ flags = EROFS_REG_COOKIE_NEED_INODE;
+ if (sbi->domain_id)
+ flags |= EROFS_REG_COOKIE_NEED_NOEXIST;
+ fscache = erofs_fscache_register_cookie(sb, sbi->fsid, flags);
if (IS_ERR(fscache))
return PTR_ERR(fscache);
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index ad2a82f2eb4c..d3b8736fa124 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -268,6 +268,7 @@ static int erofs_fill_inode(struct inode *inode)
case S_IFDIR:
inode->i_op = &erofs_dir_iops;
inode->i_fop = &erofs_dir_fops;
+ inode_nohighmem(inode);
break;
case S_IFLNK:
err = erofs_fill_symlink(inode, kaddr, ofs);
@@ -295,6 +296,7 @@ static int erofs_fill_inode(struct inode *inode)
goto out_unlock;
}
inode->i_mapping->a_ops = &erofs_raw_access_aops;
+ mapping_set_large_folios(inode->i_mapping);
#ifdef CONFIG_EROFS_FS_ONDEMAND
if (erofs_is_fscache_mode(inode->i_sb))
inode->i_mapping->a_ops = &erofs_fscache_access_aops;
@@ -371,7 +373,7 @@ int erofs_getattr(struct user_namespace *mnt_userns, const struct path *path,
const struct inode_operations erofs_generic_iops = {
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
- .get_acl = erofs_get_acl,
+ .get_inode_acl = erofs_get_acl,
.fiemap = erofs_fiemap,
};
@@ -379,12 +381,12 @@ const struct inode_operations erofs_symlink_iops = {
.get_link = page_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
- .get_acl = erofs_get_acl,
+ .get_inode_acl = erofs_get_acl,
};
const struct inode_operations erofs_fast_symlink_iops = {
.get_link = simple_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
- .get_acl = erofs_get_acl,
+ .get_inode_acl = erofs_get_acl,
};
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 1701df48c446..bb8501c0ff5b 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -75,8 +75,6 @@ struct erofs_mount_opts {
unsigned int max_sync_decompress_pages;
#endif
unsigned int mount_opt;
- char *fsid;
- char *domain_id;
};
struct erofs_dev_context {
@@ -89,6 +87,8 @@ struct erofs_dev_context {
struct erofs_fs_context {
struct erofs_mount_opts opt;
struct erofs_dev_context *devs;
+ char *fsid;
+ char *domain_id;
};
/* all filesystem-wide lz4 configurations */
@@ -170,6 +170,8 @@ struct erofs_sb_info {
struct fscache_volume *volume;
struct erofs_fscache *s_fscache;
struct erofs_domain *domain;
+ char *fsid;
+ char *domain_id;
};
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
@@ -253,8 +255,7 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
enum erofs_kmap_type {
EROFS_NO_KMAP, /* don't map the buffer */
- EROFS_KMAP, /* use kmap() to map the buffer */
- EROFS_KMAP_ATOMIC, /* use kmap_atomic() to map the buffer */
+ EROFS_KMAP, /* use kmap_local_page() to map the buffer */
};
struct erofs_buf {
@@ -602,13 +603,18 @@ static inline int z_erofs_load_lzma_config(struct super_block *sb,
}
#endif /* !CONFIG_EROFS_FS_ZIP */
+/* flags for erofs_fscache_register_cookie() */
+#define EROFS_REG_COOKIE_NEED_INODE 1
+#define EROFS_REG_COOKIE_NEED_NOEXIST 2
+
/* fscache.c */
#ifdef CONFIG_EROFS_FS_ONDEMAND
int erofs_fscache_register_fs(struct super_block *sb);
void erofs_fscache_unregister_fs(struct super_block *sb);
struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
- char *name, bool need_inode);
+ char *name,
+ unsigned int flags);
void erofs_fscache_unregister_cookie(struct erofs_fscache *fscache);
extern const struct address_space_operations erofs_fscache_access_aops;
@@ -621,7 +627,8 @@ static inline void erofs_fscache_unregister_fs(struct super_block *sb) {}
static inline
struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
- char *name, bool need_inode)
+ char *name,
+ unsigned int flags)
{
return ERR_PTR(-EOPNOTSUPP);
}
diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c
index 0dc34721080c..b64a108fac92 100644
--- a/fs/erofs/namei.c
+++ b/fs/erofs/namei.c
@@ -228,6 +228,6 @@ const struct inode_operations erofs_dir_iops = {
.lookup = erofs_lookup,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
- .get_acl = erofs_get_acl,
+ .get_inode_acl = erofs_get_acl,
.fiemap = erofs_fiemap,
};
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 2cf96ce1c32e..481788c24a68 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -245,7 +245,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
}
if (erofs_is_fscache_mode(sb)) {
- fscache = erofs_fscache_register_cookie(sb, dif->path, false);
+ fscache = erofs_fscache_register_cookie(sb, dif->path, 0);
if (IS_ERR(fscache))
return PTR_ERR(fscache);
dif->fscache = fscache;
@@ -579,9 +579,9 @@ static int erofs_fc_parse_param(struct fs_context *fc,
break;
case Opt_fsid:
#ifdef CONFIG_EROFS_FS_ONDEMAND
- kfree(ctx->opt.fsid);
- ctx->opt.fsid = kstrdup(param->string, GFP_KERNEL);
- if (!ctx->opt.fsid)
+ kfree(ctx->fsid);
+ ctx->fsid = kstrdup(param->string, GFP_KERNEL);
+ if (!ctx->fsid)
return -ENOMEM;
#else
errorfc(fc, "fsid option not supported");
@@ -589,9 +589,9 @@ static int erofs_fc_parse_param(struct fs_context *fc,
break;
case Opt_domain_id:
#ifdef CONFIG_EROFS_FS_ONDEMAND
- kfree(ctx->opt.domain_id);
- ctx->opt.domain_id = kstrdup(param->string, GFP_KERNEL);
- if (!ctx->opt.domain_id)
+ kfree(ctx->domain_id);
+ ctx->domain_id = kstrdup(param->string, GFP_KERNEL);
+ if (!ctx->domain_id)
return -ENOMEM;
#else
errorfc(fc, "domain_id option not supported");
@@ -728,10 +728,12 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_fs_info = sbi;
sbi->opt = ctx->opt;
- ctx->opt.fsid = NULL;
- ctx->opt.domain_id = NULL;
sbi->devs = ctx->devs;
ctx->devs = NULL;
+ sbi->fsid = ctx->fsid;
+ ctx->fsid = NULL;
+ sbi->domain_id = ctx->domain_id;
+ ctx->domain_id = NULL;
if (erofs_is_fscache_mode(sb)) {
sb->s_blocksize = EROFS_BLKSIZ;
@@ -820,7 +822,7 @@ static int erofs_fc_get_tree(struct fs_context *fc)
{
struct erofs_fs_context *ctx = fc->fs_private;
- if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && ctx->opt.fsid)
+ if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && ctx->fsid)
return get_tree_nodev(fc, erofs_fc_fill_super);
return get_tree_bdev(fc, erofs_fc_fill_super);
@@ -834,6 +836,9 @@ static int erofs_fc_reconfigure(struct fs_context *fc)
DBG_BUGON(!sb_rdonly(sb));
+ if (ctx->fsid || ctx->domain_id)
+ erofs_info(sb, "ignoring reconfiguration for fsid|domain_id.");
+
if (test_opt(&ctx->opt, POSIX_ACL))
fc->sb_flags |= SB_POSIXACL;
else
@@ -873,8 +878,8 @@ static void erofs_fc_free(struct fs_context *fc)
struct erofs_fs_context *ctx = fc->fs_private;
erofs_free_dev_context(ctx->devs);
- kfree(ctx->opt.fsid);
- kfree(ctx->opt.domain_id);
+ kfree(ctx->fsid);
+ kfree(ctx->domain_id);
kfree(ctx);
}
@@ -944,8 +949,8 @@ static void erofs_kill_sb(struct super_block *sb)
erofs_free_dev_context(sbi->devs);
fs_put_dax(sbi->dax_dev, NULL);
erofs_fscache_unregister_fs(sb);
- kfree(sbi->opt.fsid);
- kfree(sbi->opt.domain_id);
+ kfree(sbi->fsid);
+ kfree(sbi->domain_id);
kfree(sbi);
sb->s_fs_info = NULL;
}
@@ -1098,10 +1103,10 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
if (test_opt(opt, DAX_NEVER))
seq_puts(seq, ",dax=never");
#ifdef CONFIG_EROFS_FS_ONDEMAND
- if (opt->fsid)
- seq_printf(seq, ",fsid=%s", opt->fsid);
- if (opt->domain_id)
- seq_printf(seq, ",domain_id=%s", opt->domain_id);
+ if (sbi->fsid)
+ seq_printf(seq, ",fsid=%s", sbi->fsid);
+ if (sbi->domain_id)
+ seq_printf(seq, ",domain_id=%s", sbi->domain_id);
#endif
return 0;
}
diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c
index 783bb7b21b51..fd476961f742 100644
--- a/fs/erofs/sysfs.c
+++ b/fs/erofs/sysfs.c
@@ -210,14 +210,14 @@ int erofs_register_sysfs(struct super_block *sb)
int err;
if (erofs_is_fscache_mode(sb)) {
- if (sbi->opt.domain_id) {
- str = kasprintf(GFP_KERNEL, "%s,%s", sbi->opt.domain_id,
- sbi->opt.fsid);
+ if (sbi->domain_id) {
+ str = kasprintf(GFP_KERNEL, "%s,%s", sbi->domain_id,
+ sbi->fsid);
if (!str)
return -ENOMEM;
name = str;
} else {
- name = sbi->opt.fsid;
+ name = sbi->fsid;
}
} else {
name = sb->s_id;
diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c
index 8106bcb5a38d..a62fb8a3318a 100644
--- a/fs/erofs/xattr.c
+++ b/fs/erofs/xattr.c
@@ -148,7 +148,7 @@ static inline int xattr_iter_fixup(struct xattr_iter *it)
it->blkaddr += erofs_blknr(it->ofs);
it->kaddr = erofs_read_metabuf(&it->buf, it->sb, it->blkaddr,
- EROFS_KMAP_ATOMIC);
+ EROFS_KMAP);
if (IS_ERR(it->kaddr))
return PTR_ERR(it->kaddr);
it->ofs = erofs_blkoff(it->ofs);
@@ -174,7 +174,7 @@ static int inline_xattr_iter_begin(struct xattr_iter *it,
it->ofs = erofs_blkoff(iloc(sbi, vi->nid) + inline_xattr_ofs);
it->kaddr = erofs_read_metabuf(&it->buf, inode->i_sb, it->blkaddr,
- EROFS_KMAP_ATOMIC);
+ EROFS_KMAP);
if (IS_ERR(it->kaddr))
return PTR_ERR(it->kaddr);
return vi->xattr_isize - xattr_header_sz;
@@ -368,7 +368,7 @@ static int shared_getxattr(struct inode *inode, struct getxattr_iter *it)
it->it.ofs = xattrblock_offset(sbi, vi->xattr_shared_xattrs[i]);
it->it.kaddr = erofs_read_metabuf(&it->it.buf, sb, blkaddr,
- EROFS_KMAP_ATOMIC);
+ EROFS_KMAP);
if (IS_ERR(it->it.kaddr))
return PTR_ERR(it->it.kaddr);
it->it.blkaddr = blkaddr;
@@ -580,7 +580,7 @@ static int shared_listxattr(struct listxattr_iter *it)
it->it.ofs = xattrblock_offset(sbi, vi->xattr_shared_xattrs[i]);
it->it.kaddr = erofs_read_metabuf(&it->it.buf, sb, blkaddr,
- EROFS_KMAP_ATOMIC);
+ EROFS_KMAP);
if (IS_ERR(it->it.kaddr))
return PTR_ERR(it->it.kaddr);
it->it.blkaddr = blkaddr;
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index c7f24fc7efd5..ccf7c55d477f 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -175,16 +175,6 @@ static void z_erofs_free_pcluster(struct z_erofs_pcluster *pcl)
DBG_BUGON(1);
}
-/* how to allocate cached pages for a pcluster */
-enum z_erofs_cache_alloctype {
- DONTALLOC, /* don't allocate any cached pages */
- /*
- * try to use cached I/O if page allocation succeeds or fallback
- * to in-place I/O instead to avoid any direct reclaim.
- */
- TRYALLOC,
-};
-
/*
* tagged pointer with 1-bit tag for all compressed pages
* tag 0 - the page is just found with an extra page reference
@@ -292,12 +282,29 @@ struct z_erofs_decompress_frontend {
.inode = __i, .owned_head = Z_EROFS_PCLUSTER_TAIL, \
.mode = Z_EROFS_PCLUSTER_FOLLOWED, .backmost = true }
+static bool z_erofs_should_alloc_cache(struct z_erofs_decompress_frontend *fe)
+{
+ unsigned int cachestrategy = EROFS_I_SB(fe->inode)->opt.cache_strategy;
+
+ if (cachestrategy <= EROFS_ZIP_CACHE_DISABLED)
+ return false;
+
+ if (fe->backmost)
+ return true;
+
+ if (cachestrategy >= EROFS_ZIP_CACHE_READAROUND &&
+ fe->map.m_la < fe->headoffset)
+ return true;
+
+ return false;
+}
+
static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
- enum z_erofs_cache_alloctype type,
struct page **pagepool)
{
struct address_space *mc = MNGD_MAPPING(EROFS_I_SB(fe->inode));
struct z_erofs_pcluster *pcl = fe->pcl;
+ bool shouldalloc = z_erofs_should_alloc_cache(fe);
bool standalone = true;
/*
* optimistic allocation without direct reclaim since inplace I/O
@@ -326,18 +333,19 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
} else {
/* I/O is needed, no possible to decompress directly */
standalone = false;
- switch (type) {
- case TRYALLOC:
- newpage = erofs_allocpage(pagepool, gfp);
- if (!newpage)
- continue;
- set_page_private(newpage,
- Z_EROFS_PREALLOCATED_PAGE);
- t = tag_compressed_page_justfound(newpage);
- break;
- default: /* DONTALLOC */
+ if (!shouldalloc)
continue;
- }
+
+ /*
+ * try to use cached I/O if page allocation
+ * succeeds or fallback to in-place I/O instead
+ * to avoid any direct reclaim.
+ */
+ newpage = erofs_allocpage(pagepool, gfp);
+ if (!newpage)
+ continue;
+ set_page_private(newpage, Z_EROFS_PREALLOCATED_PAGE);
+ t = tag_compressed_page_justfound(newpage);
}
if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL,
@@ -488,7 +496,8 @@ static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe)
struct erofs_workgroup *grp;
int err;
- if (!(map->m_flags & EROFS_MAP_ENCODED)) {
+ if (!(map->m_flags & EROFS_MAP_ENCODED) ||
+ (!ztailpacking && !(map->m_pa >> PAGE_SHIFT))) {
DBG_BUGON(1);
return -EFSCORRUPTED;
}
@@ -637,20 +646,6 @@ static bool z_erofs_collector_end(struct z_erofs_decompress_frontend *fe)
return true;
}
-static bool should_alloc_managed_pages(struct z_erofs_decompress_frontend *fe,
- unsigned int cachestrategy,
- erofs_off_t la)
-{
- if (cachestrategy <= EROFS_ZIP_CACHE_DISABLED)
- return false;
-
- if (fe->backmost)
- return true;
-
- return cachestrategy >= EROFS_ZIP_CACHE_READAROUND &&
- la < fe->headoffset;
-}
-
static int z_erofs_read_fragment(struct inode *inode, erofs_off_t pos,
struct page *page, unsigned int pageofs,
unsigned int len)
@@ -660,6 +655,9 @@ static int z_erofs_read_fragment(struct inode *inode, erofs_off_t pos,
u8 *src, *dst;
unsigned int i, cnt;
+ if (!packed_inode)
+ return -EFSCORRUPTED;
+
pos += EROFS_I(inode)->z_fragmentoff;
for (i = 0; i < len; i += cnt) {
cnt = min_t(unsigned int, len - i,
@@ -684,12 +682,9 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
struct page *page, struct page **pagepool)
{
struct inode *const inode = fe->inode;
- struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
struct erofs_map_blocks *const map = &fe->map;
const loff_t offset = page_offset(page);
bool tight = true, exclusive;
-
- enum z_erofs_cache_alloctype cache_strategy;
unsigned int cur, end, spiltted;
int err = 0;
@@ -743,13 +738,7 @@ repeat:
fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
} else {
/* bind cache first when cached decompression is preferred */
- if (should_alloc_managed_pages(fe, sbi->opt.cache_strategy,
- map->m_la))
- cache_strategy = TRYALLOC;
- else
- cache_strategy = DONTALLOC;
-
- z_erofs_bind_cache(fe, cache_strategy, pagepool);
+ z_erofs_bind_cache(fe, pagepool);
}
hitted:
/*
@@ -1412,8 +1401,8 @@ static void z_erofs_submit_queue(struct z_erofs_decompress_frontend *f,
struct block_device *last_bdev;
unsigned int nr_bios = 0;
struct bio *bio = NULL;
- /* initialize to 1 to make skip psi_memstall_leave unless needed */
- unsigned long pflags = 1;
+ unsigned long pflags;
+ int memstall = 0;
bi_private = jobqueueset_init(sb, q, fgq, force_fg);
qtail[JQ_BYPASS] = &q[JQ_BYPASS]->head;
@@ -1463,14 +1452,18 @@ static void z_erofs_submit_queue(struct z_erofs_decompress_frontend *f,
if (bio && (cur != last_index + 1 ||
last_bdev != mdev.m_bdev)) {
submit_bio_retry:
- if (!pflags)
- psi_memstall_leave(&pflags);
submit_bio(bio);
+ if (memstall) {
+ psi_memstall_leave(&pflags);
+ memstall = 0;
+ }
bio = NULL;
}
- if (unlikely(PageWorkingset(page)))
+ if (unlikely(PageWorkingset(page)) && !memstall) {
psi_memstall_enter(&pflags);
+ memstall = 1;
+ }
if (!bio) {
bio = bio_alloc(mdev.m_bdev, BIO_MAX_VECS,
@@ -1500,9 +1493,9 @@ submit_bio_retry:
} while (owned_head != Z_EROFS_PCLUSTER_TAIL);
if (bio) {
- if (!pflags)
- psi_memstall_leave(&pflags);
submit_bio(bio);
+ if (memstall)
+ psi_memstall_leave(&pflags);
}
/*
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index 0bb66927e3d0..0150570c33aa 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -178,7 +178,7 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
unsigned int advise, type;
m->kaddr = erofs_read_metabuf(&m->map->buf, inode->i_sb,
- erofs_blknr(pos), EROFS_KMAP_ATOMIC);
+ erofs_blknr(pos), EROFS_KMAP);
if (IS_ERR(m->kaddr))
return PTR_ERR(m->kaddr);
@@ -416,7 +416,7 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
out:
pos += lcn * (1 << amortizedshift);
m->kaddr = erofs_read_metabuf(&m->map->buf, inode->i_sb,
- erofs_blknr(pos), EROFS_KMAP_ATOMIC);
+ erofs_blknr(pos), EROFS_KMAP);
if (IS_ERR(m->kaddr))
return PTR_ERR(m->kaddr);
return unpack_compacted_index(m, amortizedshift, pos, lookahead);
@@ -694,10 +694,15 @@ static int z_erofs_do_map_blocks(struct inode *inode,
map->m_pa = blknr_to_addr(m.pblk);
err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
if (err)
- goto out;
+ goto unmap_out;
}
if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN) {
+ if (map->m_llen > map->m_plen) {
+ DBG_BUGON(1);
+ err = -EFSCORRUPTED;
+ goto unmap_out;
+ }
if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
map->m_algorithmformat =
Z_EROFS_COMPRESSION_INTERLACED;
@@ -718,14 +723,12 @@ static int z_erofs_do_map_blocks(struct inode *inode,
if (!err)
map->m_flags |= EROFS_MAP_FULL_MAPPED;
}
+
unmap_out:
erofs_unmap_metabuf(&m.map->buf);
-
-out:
erofs_dbg("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
__func__, map->m_la, map->m_pa,
map->m_llen, map->m_plen, map->m_flags);
-
return err;
}
diff --git a/fs/eventfd.c b/fs/eventfd.c
index c0ffee99ad23..249ca6c0b784 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -43,21 +43,7 @@ struct eventfd_ctx {
int id;
};
-/**
- * eventfd_signal - Adds @n to the eventfd counter.
- * @ctx: [in] Pointer to the eventfd context.
- * @n: [in] Value of the counter to be added to the eventfd internal counter.
- * The value cannot be negative.
- *
- * This function is supposed to be called by the kernel in paths that do not
- * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
- * value, and we signal this as overflow condition by returning a EPOLLERR
- * to poll(2).
- *
- * Returns the amount by which the counter was incremented. This will be less
- * than @n if the counter has overflowed.
- */
-__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
+__u64 eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n, unsigned mask)
{
unsigned long flags;
@@ -78,12 +64,31 @@ __u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
n = ULLONG_MAX - ctx->count;
ctx->count += n;
if (waitqueue_active(&ctx->wqh))
- wake_up_locked_poll(&ctx->wqh, EPOLLIN);
+ wake_up_locked_poll(&ctx->wqh, EPOLLIN | mask);
current->in_eventfd = 0;
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return n;
}
+
+/**
+ * eventfd_signal - Adds @n to the eventfd counter.
+ * @ctx: [in] Pointer to the eventfd context.
+ * @n: [in] Value of the counter to be added to the eventfd internal counter.
+ * The value cannot be negative.
+ *
+ * This function is supposed to be called by the kernel in paths that do not
+ * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
+ * value, and we signal this as overflow condition by returning a EPOLLERR
+ * to poll(2).
+ *
+ * Returns the amount by which the counter was incremented. This will be less
+ * than @n if the counter has overflowed.
+ */
+__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
+{
+ return eventfd_signal_mask(ctx, n, 0);
+}
EXPORT_SYMBOL_GPL(eventfd_signal);
static void eventfd_free_ctx(struct eventfd_ctx *ctx)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 52954d4637b5..64659b110973 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -491,7 +491,8 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
-static void ep_poll_safewake(struct eventpoll *ep, struct epitem *epi)
+static void ep_poll_safewake(struct eventpoll *ep, struct epitem *epi,
+ unsigned pollflags)
{
struct eventpoll *ep_src;
unsigned long flags;
@@ -522,16 +523,17 @@ static void ep_poll_safewake(struct eventpoll *ep, struct epitem *epi)
}
spin_lock_irqsave_nested(&ep->poll_wait.lock, flags, nests);
ep->nests = nests + 1;
- wake_up_locked_poll(&ep->poll_wait, EPOLLIN);
+ wake_up_locked_poll(&ep->poll_wait, EPOLLIN | pollflags);
ep->nests = 0;
spin_unlock_irqrestore(&ep->poll_wait.lock, flags);
}
#else
-static void ep_poll_safewake(struct eventpoll *ep, struct epitem *epi)
+static void ep_poll_safewake(struct eventpoll *ep, struct epitem *epi,
+ unsigned pollflags)
{
- wake_up_poll(&ep->poll_wait, EPOLLIN);
+ wake_up_poll(&ep->poll_wait, EPOLLIN | pollflags);
}
#endif
@@ -742,7 +744,7 @@ static void ep_free(struct eventpoll *ep)
/* We need to release all tasks waiting for these file */
if (waitqueue_active(&ep->poll_wait))
- ep_poll_safewake(ep, NULL);
+ ep_poll_safewake(ep, NULL, 0);
/*
* We need to lock this because we could be hit by
@@ -1208,7 +1210,7 @@ out_unlock:
/* We have to call this outside the lock */
if (pwake)
- ep_poll_safewake(ep, epi);
+ ep_poll_safewake(ep, epi, pollflags & EPOLL_URING_WAKE);
if (!(epi->event.events & EPOLLEXCLUSIVE))
ewake = 1;
@@ -1553,7 +1555,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
/* We have to call this outside the lock */
if (pwake)
- ep_poll_safewake(ep, NULL);
+ ep_poll_safewake(ep, NULL, 0);
return 0;
}
@@ -1629,7 +1631,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi,
/* We have to call this outside the lock */
if (pwake)
- ep_poll_safewake(ep, NULL);
+ ep_poll_safewake(ep, NULL, 0);
return 0;
}
diff --git a/fs/exec.c b/fs/exec.c
index a0b1f0337a62..ab913243a367 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -64,6 +64,7 @@
#include <linux/io_uring.h>
#include <linux/syscall_user_dispatch.h>
#include <linux/coredump.h>
+#include <linux/time_namespace.h>
#include <linux/uaccess.h>
#include <asm/mmu_context.h>
@@ -171,7 +172,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
exit:
fput(file);
out:
- return error;
+ return error;
}
#endif /* #ifdef CONFIG_USELIB */
@@ -199,7 +200,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
{
struct page *page;
int ret;
- unsigned int gup_flags = FOLL_FORCE;
+ unsigned int gup_flags = 0;
#ifdef CONFIG_STACK_GROWSUP
if (write) {
@@ -842,16 +843,13 @@ int setup_arg_pages(struct linux_binprm *bprm,
* will align it up.
*/
rlim_stack = bprm->rlim_stack.rlim_cur & PAGE_MASK;
+
+ stack_expand = min(rlim_stack, stack_size + stack_expand);
+
#ifdef CONFIG_STACK_GROWSUP
- if (stack_size + stack_expand > rlim_stack)
- stack_base = vma->vm_start + rlim_stack;
- else
- stack_base = vma->vm_end + stack_expand;
+ stack_base = vma->vm_start + stack_expand;
#else
- if (stack_size + stack_expand > rlim_stack)
- stack_base = vma->vm_end - rlim_stack;
- else
- stack_base = vma->vm_start - stack_expand;
+ stack_base = vma->vm_end - stack_expand;
#endif
current->mm->start_stack = bprm->p;
ret = expand_stack(vma, stack_base);
@@ -1297,6 +1295,10 @@ int begin_new_exec(struct linux_binprm * bprm)
bprm->mm = NULL;
+ retval = exec_task_namespaces();
+ if (retval)
+ goto out_unlock;
+
#ifdef CONFIG_POSIX_TIMERS
spin_lock_irq(&me->sighand->siglock);
posix_cpu_timers_exit(me);
@@ -1568,6 +1570,12 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
if (task_no_new_privs(current))
bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
+ /*
+ * If another task is sharing our fs, we cannot safely
+ * suid exec because the differently privileged task
+ * will be able to manipulate the current directory, etc.
+ * It would be nice to force an unshare instead...
+ */
t = p;
n_fs = 1;
spin_lock(&p->fs->lock);
@@ -1591,8 +1599,8 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
struct user_namespace *mnt_userns;
struct inode *inode = file_inode(file);
unsigned int mode;
- kuid_t uid;
- kgid_t gid;
+ vfsuid_t vfsuid;
+ vfsgid_t vfsgid;
if (!mnt_may_suid(file->f_path.mnt))
return;
@@ -1611,23 +1619,23 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
/* reload atomically mode/uid/gid now that lock held */
mode = inode->i_mode;
- uid = i_uid_into_mnt(mnt_userns, inode);
- gid = i_gid_into_mnt(mnt_userns, inode);
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
inode_unlock(inode);
/* We ignore suid/sgid if there are no mappings for them in the ns */
- if (!kuid_has_mapping(bprm->cred->user_ns, uid) ||
- !kgid_has_mapping(bprm->cred->user_ns, gid))
+ if (!vfsuid_has_mapping(bprm->cred->user_ns, vfsuid) ||
+ !vfsgid_has_mapping(bprm->cred->user_ns, vfsgid))
return;
if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
- bprm->cred->euid = uid;
+ bprm->cred->euid = vfsuid_into_kuid(vfsuid);
}
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
- bprm->cred->egid = gid;
+ bprm->cred->egid = vfsgid_into_kgid(vfsgid);
}
}
@@ -1748,6 +1756,7 @@ static int search_binary_handler(struct linux_binprm *bprm)
return retval;
}
+/* binfmt handlers will call back into begin_new_exec() on success. */
static int exec_binprm(struct linux_binprm *bprm)
{
pid_t old_pid, old_vpid;
@@ -1806,6 +1815,11 @@ static int bprm_execve(struct linux_binprm *bprm,
if (retval)
return retval;
+ /*
+ * Check for unsafe execution states before exec_binprm(), which
+ * will call back into begin_new_exec(), into bprm_creds_from_file(),
+ * where setuid-ness is evaluated.
+ */
check_unsafe_exec(bprm);
current->in_execve = 1;
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index c648a493faf2..3204bd33e4e8 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -18,7 +18,7 @@
#include <linux/sched.h>
#include <linux/cred.h>
-#define dprintk(fmt, args...) do{}while(0)
+#define dprintk(fmt, args...) pr_debug(fmt, ##args)
static int get_name(const struct path *path, char *name, struct dentry *child);
@@ -132,8 +132,8 @@ static struct dentry *reconnect_one(struct vfsmount *mnt,
inode_unlock(dentry->d_inode);
if (IS_ERR(parent)) {
- dprintk("%s: get_parent of %ld failed, err %d\n",
- __func__, dentry->d_inode->i_ino, PTR_ERR(parent));
+ dprintk("get_parent of %lu failed, err %ld\n",
+ dentry->d_inode->i_ino, PTR_ERR(parent));
return parent;
}
@@ -147,7 +147,7 @@ static struct dentry *reconnect_one(struct vfsmount *mnt,
dprintk("%s: found name: %s\n", __func__, nbuf);
tmp = lookup_one_unlocked(mnt_user_ns(mnt), nbuf, parent, strlen(nbuf));
if (IS_ERR(tmp)) {
- dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
+ dprintk("lookup failed: %ld\n", PTR_ERR(tmp));
err = PTR_ERR(tmp);
goto out_err;
}
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index bf298967c5b8..440d5f1e9d47 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -219,11 +219,12 @@ __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
* inode->i_mutex: down
*/
int
-ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+ext2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
int update_mode = 0;
+ struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
if (type == ACL_TYPE_ACCESS && acl) {
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h
index 925ab6287d35..3841becb94ff 100644
--- a/fs/ext2/acl.h
+++ b/fs/ext2/acl.h
@@ -56,7 +56,7 @@ static inline int ext2_acl_count(size_t size)
/* acl.c */
extern struct posix_acl *ext2_get_acl(struct inode *inode, int type, bool rcu);
-extern int ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+extern int ext2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ext2_init_acl (struct inode *, struct inode *);
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 5dc0a31f4a08..eca60b747c6b 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -667,7 +667,7 @@ ext2_try_to_allocate(struct super_block *sb, int group,
{
ext2_fsblk_t group_first_block = ext2_group_first_block_no(sb, group);
ext2_fsblk_t group_last_block = ext2_group_last_block_no(sb, group);
- ext2_grpblk_t start, end;
+ ext2_grpblk_t start, end;
unsigned long num = 0;
start = 0;
@@ -1481,11 +1481,11 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
desc_count, bitmap_count);
return bitmap_count;
#else
- for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
- desc = ext2_get_group_desc (sb, i, NULL);
- if (!desc)
- continue;
- desc_count += le16_to_cpu(desc->bg_free_blocks_count);
+ for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
+ desc = ext2_get_group_desc(sb, i, NULL);
+ if (!desc)
+ continue;
+ desc_count += le16_to_cpu(desc->bg_free_blocks_count);
}
return desc_count;
#endif
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 8f597753ac12..e5cbc27ba459 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -81,11 +81,10 @@ ext2_last_byte(struct inode *inode, unsigned long page_nr)
return last_byte;
}
-static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
+static void ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
{
struct address_space *mapping = page->mapping;
struct inode *dir = mapping->host;
- int err = 0;
inode_inc_iversion(dir);
block_write_end(NULL, mapping, pos, len, len, page, NULL);
@@ -94,16 +93,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
i_size_write(dir, pos+len);
mark_inode_dirty(dir);
}
-
- if (IS_DIRSYNC(dir)) {
- err = write_one_page(page);
- if (!err)
- err = sync_inode_metadata(dir, 1);
- } else {
- unlock_page(page);
- }
-
- return err;
+ unlock_page(page);
}
static bool ext2_check_page(struct page *page, int quiet, char *kaddr)
@@ -413,7 +403,7 @@ found:
return de;
}
-/**
+/*
* Return the '..' directory entry and the page in which the entry was found
* (as a parameter - p).
*
@@ -460,6 +450,17 @@ static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
return __block_write_begin(page, pos, len, ext2_get_block);
}
+
+static int ext2_handle_dirsync(struct inode *dir)
+{
+ int err;
+
+ err = filemap_write_and_wait(dir->i_mapping);
+ if (!err)
+ err = sync_inode_metadata(dir, 1);
+ return err;
+}
+
void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
struct page *page, void *page_addr, struct inode *inode,
int update_times)
@@ -474,11 +475,12 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
BUG_ON(err);
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(de, inode);
- err = ext2_commit_chunk(page, pos, len);
+ ext2_commit_chunk(page, pos, len);
if (update_times)
dir->i_mtime = dir->i_ctime = current_time(dir);
EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
+ ext2_handle_dirsync(dir);
}
/*
@@ -566,10 +568,11 @@ got_it:
memcpy(de->name, name, namelen);
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type (de, inode);
- err = ext2_commit_chunk(page, pos, rec_len);
+ ext2_commit_chunk(page, pos, rec_len);
dir->i_mtime = dir->i_ctime = current_time(dir);
EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
+ err = ext2_handle_dirsync(dir);
/* OFFSET_CACHE */
out_put:
ext2_put_page(page, page_addr);
@@ -615,10 +618,11 @@ int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
if (pde)
pde->rec_len = ext2_rec_len_to_disk(to - from);
dir->inode = 0;
- err = ext2_commit_chunk(page, pos, to - from);
+ ext2_commit_chunk(page, pos, to - from);
inode->i_ctime = inode->i_mtime = current_time(inode);
EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(inode);
+ err = ext2_handle_dirsync(inode);
out:
return err;
}
@@ -658,7 +662,8 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
memcpy (de->name, "..\0", 4);
ext2_set_de_type (de, inode);
kunmap_atomic(kaddr);
- err = ext2_commit_chunk(page, 0, chunk_size);
+ ext2_commit_chunk(page, 0, chunk_size);
+ err = ext2_handle_dirsync(inode);
fail:
put_page(page);
return err;
@@ -679,7 +684,7 @@ int ext2_empty_dir (struct inode * inode)
page = ext2_get_page(inode, i, 0, &page_addr);
if (IS_ERR(page))
- goto not_empty;
+ return 0;
kaddr = page_addr;
de = (ext2_dirent *)kaddr;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index eb97aa3d700e..6b4bebe982ca 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -200,7 +200,7 @@ const struct inode_operations ext2_file_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
- .get_acl = ext2_get_acl,
+ .get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
.fiemap = ext2_fiemap,
.fileattr_get = ext2_fileattr_get,
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index f4944c4dee60..78b8686d9a4a 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -277,7 +277,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
int best_ndir = inodes_per_group;
int best_group = -1;
- parent_group = prandom_u32_max(ngroups);
+ parent_group = get_random_u32_below(ngroups);
for (i = 0; i < ngroups; i++) {
group = (parent_group + i) % ngroups;
desc = ext2_get_group_desc (sb, group, NULL);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 918ab2f9e4c0..69aed9e2359e 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -869,11 +869,6 @@ int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
return ret;
}
-static int ext2_writepage(struct page *page, struct writeback_control *wbc)
-{
- return block_write_full_page(page, ext2_get_block, wbc);
-}
-
static int ext2_read_folio(struct file *file, struct folio *folio)
{
return mpage_read_folio(folio, ext2_get_block);
@@ -948,7 +943,6 @@ const struct address_space_operations ext2_aops = {
.invalidate_folio = block_invalidate_folio,
.read_folio = ext2_read_folio,
.readahead = ext2_readahead,
- .writepage = ext2_writepage,
.write_begin = ext2_write_begin,
.write_end = ext2_write_end,
.bmap = ext2_bmap,
@@ -1652,7 +1646,7 @@ int ext2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
}
setattr_copy(&init_user_ns, inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
- error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
+ error = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
mark_inode_dirty(inode);
return error;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 9125eab85146..c056957221a2 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -427,7 +427,7 @@ const struct inode_operations ext2_dir_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
- .get_acl = ext2_get_acl,
+ .get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
.tmpfile = ext2_tmpfile,
.fileattr_get = ext2_fileattr_get,
@@ -438,6 +438,6 @@ const struct inode_operations ext2_special_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
- .get_acl = ext2_get_acl,
+ .get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
};
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 03f2af98b1b4..69c88facfe90 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1648,7 +1648,7 @@ static int __init init_ext2_fs(void)
err = init_inodecache();
if (err)
return err;
- err = register_filesystem(&ext2_fs_type);
+ err = register_filesystem(&ext2_fs_type);
if (err)
goto out;
return 0;
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 57e82e25f8e2..a9f89539aeee 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -225,12 +225,13 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
}
int
-ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+ext4_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
handle_t *handle;
int error, credits, retries = 0;
size_t acl_size = acl ? ext4_acl_size(acl->a_count) : 0;
+ struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
int update_mode = 0;
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
index 3219669732bf..09c4a8a3b716 100644
--- a/fs/ext4/acl.h
+++ b/fs/ext4/acl.h
@@ -56,7 +56,7 @@ static inline int ext4_acl_count(size_t size)
/* acl.c */
struct posix_acl *ext4_get_acl(struct inode *inode, int type, bool rcu);
-int ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ext4_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 8d5453852f98..140e1eb300d1 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -558,7 +558,7 @@ enum {
*
* It's not paranoia if the Murphy's Law really *is* out to get you. :-)
*/
-#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG))
+#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1U << EXT4_INODE_##FLAG))
#define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG))
static inline void ext4_check_flag_values(void)
@@ -2964,7 +2964,8 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode,
typedef enum {
EXT4_IGET_NORMAL = 0,
EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */
- EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
+ EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */
+ EXT4_IGET_BAD = 0x0004 /* Allow to iget a bad inode */
} ext4_iget_flags;
extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
@@ -2999,6 +3000,7 @@ extern void ext4_set_inode_flags(struct inode *, bool init);
extern int ext4_alloc_da_blocks(struct inode *inode);
extern void ext4_set_aops(struct inode *inode);
extern int ext4_writepage_trans_blocks(struct inode *);
+extern int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode);
extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
loff_t lstart, loff_t lend);
@@ -3619,8 +3621,8 @@ extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
unsigned int blocksize);
extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,
struct buffer_head *bh);
-extern int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name,
- struct inode *inode);
+extern int __ext4_unlink(struct inode *dir, const struct qstr *d_name,
+ struct inode *inode, struct dentry *dentry);
extern int __ext4_link(struct inode *dir, struct inode *inode,
struct dentry *dentry);
@@ -3756,8 +3758,7 @@ extern void ext4_end_io_rsv_work(struct work_struct *work);
extern void ext4_io_submit(struct ext4_io_submit *io);
extern int ext4_bio_write_page(struct ext4_io_submit *io,
struct page *page,
- int len,
- bool keep_towrite);
+ int len);
extern struct ext4_io_end_vec *ext4_alloc_io_end_vec(ext4_io_end_t *io_end);
extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end);
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 8e1fb18f465e..77f318ec8abb 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -86,15 +86,21 @@ static int ext4_journal_check_start(struct super_block *sb)
return 0;
}
-handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
+handle_t *__ext4_journal_start_sb(struct inode *inode,
+ struct super_block *sb, unsigned int line,
int type, int blocks, int rsv_blocks,
int revoke_creds)
{
journal_t *journal;
int err;
-
- trace_ext4_journal_start(sb, blocks, rsv_blocks, revoke_creds,
- _RET_IP_);
+ if (inode)
+ trace_ext4_journal_start_inode(inode, blocks, rsv_blocks,
+ revoke_creds, type,
+ _RET_IP_);
+ else
+ trace_ext4_journal_start_sb(sb, blocks, rsv_blocks,
+ revoke_creds, type,
+ _RET_IP_);
err = ext4_journal_check_start(sb);
if (err < 0)
return ERR_PTR(err);
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index db2ae4a2b38d..0c77697d5e90 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -261,9 +261,9 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
__ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
(bh))
-handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
- int type, int blocks, int rsv_blocks,
- int revoke_creds);
+handle_t *__ext4_journal_start_sb(struct inode *inode, struct super_block *sb,
+ unsigned int line, int type, int blocks,
+ int rsv_blocks, int revoke_creds);
int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);
#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096)
@@ -303,7 +303,7 @@ static inline int ext4_trans_default_revoke_credits(struct super_block *sb)
}
#define ext4_journal_start_sb(sb, type, nblocks) \
- __ext4_journal_start_sb((sb), __LINE__, (type), (nblocks), 0, \
+ __ext4_journal_start_sb(NULL, (sb), __LINE__, (type), (nblocks), 0,\
ext4_trans_default_revoke_credits(sb))
#define ext4_journal_start(inode, type, nblocks) \
@@ -323,7 +323,7 @@ static inline handle_t *__ext4_journal_start(struct inode *inode,
int blocks, int rsv_blocks,
int revoke_creds)
{
- return __ext4_journal_start_sb(inode->i_sb, line, type, blocks,
+ return __ext4_journal_start_sb(inode, inode->i_sb, line, type, blocks,
rsv_blocks, revoke_creds);
}
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index f1956288307f..9de1c9d1a13d 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2635,9 +2635,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
unwritten, ex_ee_len);
path[depth].p_ext = ex;
- a = ex_ee_block > start ? ex_ee_block : start;
- b = ex_ee_block+ex_ee_len - 1 < end ?
- ex_ee_block+ex_ee_len - 1 : end;
+ a = max(ex_ee_block, start);
+ b = min(ex_ee_block + ex_ee_len - 1, end);
ext_debug(inode, " border %u:%u\n", a, b);
@@ -5184,6 +5183,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
* and it is decreased till we reach start.
*/
again:
+ ret = 0;
if (SHIFT == SHIFT_LEFT)
iterator = &start;
else
@@ -5227,14 +5227,21 @@ again:
ext4_ext_get_actual_len(extent);
} else {
extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
- if (le32_to_cpu(extent->ee_block) > 0)
+ if (le32_to_cpu(extent->ee_block) > start)
*iterator = le32_to_cpu(extent->ee_block) - 1;
- else
- /* Beginning is reached, end of the loop */
+ else if (le32_to_cpu(extent->ee_block) == start)
iterator = NULL;
- /* Update path extent in case we need to stop */
- while (le32_to_cpu(extent->ee_block) < start)
+ else {
+ extent = EXT_LAST_EXTENT(path[depth].p_hdr);
+ while (le32_to_cpu(extent->ee_block) >= start)
+ extent--;
+
+ if (extent == EXT_LAST_EXTENT(path[depth].p_hdr))
+ break;
+
extent++;
+ iterator = NULL;
+ }
path[depth].p_ext = extent;
}
ret = ext4_ext_shift_path_extents(path, shift, inode,
@@ -5559,8 +5566,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
* ee_start_lblk to shift extents
*/
ret = ext4_ext_shift_extents(inode, handle,
- ee_start_lblk > offset_lblk ? ee_start_lblk : offset_lblk,
- len_lblk, SHIFT_RIGHT);
+ max(ee_start_lblk, offset_lblk), len_lblk, SHIFT_RIGHT);
up_write(&EXT4_I(inode)->i_data_sem);
if (IS_SYNC(inode))
@@ -5791,6 +5797,14 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
struct ext4_extent *extent;
ext4_lblk_t first_lblk, first_lclu, last_lclu;
+ /*
+ * if data can be stored inline, the logical cluster isn't
+ * mapped - no physical clusters have been allocated, and the
+ * file has no extents
+ */
+ if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
+ return 0;
+
/* search for the extent closest to the first block in the cluster */
path = ext4_find_extent(inode, EXT4_C2B(sbi, lclu), NULL, 0);
if (IS_ERR(path)) {
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index cd0a861853e3..7bc221038c6c 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -155,9 +155,7 @@ static void __revise_pending(struct inode *inode, ext4_lblk_t lblk,
int __init ext4_init_es(void)
{
- ext4_es_cachep = kmem_cache_create("ext4_extent_status",
- sizeof(struct extent_status),
- 0, (SLAB_RECLAIM_ACCOUNT), NULL);
+ ext4_es_cachep = KMEM_CACHE(extent_status, SLAB_RECLAIM_ACCOUNT);
if (ext4_es_cachep == NULL)
return -ENOMEM;
return 0;
@@ -1371,7 +1369,7 @@ retry:
if (count_reserved)
count_rsvd(inode, lblk, orig_es.es_len - len1 - len2,
&orig_es, &rc);
- goto out;
+ goto out_get_reserved;
}
if (len1 > 0) {
@@ -1413,6 +1411,7 @@ retry:
}
}
+out_get_reserved:
if (count_reserved)
*reserved = get_rsvd(inode, end, es, &rc);
out:
@@ -1807,9 +1806,7 @@ static void ext4_print_pending_tree(struct inode *inode)
int __init ext4_init_pending(void)
{
- ext4_pending_cachep = kmem_cache_create("ext4_pending_reservation",
- sizeof(struct pending_reservation),
- 0, (SLAB_RECLAIM_ACCOUNT), NULL);
+ ext4_pending_cachep = KMEM_CACHE(pending_reservation, SLAB_RECLAIM_ACCOUNT);
if (ext4_pending_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
index 0f6d0a80467d..4594b62f147b 100644
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -420,25 +420,34 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
struct __track_dentry_update_args *dentry_update =
(struct __track_dentry_update_args *)arg;
struct dentry *dentry = dentry_update->dentry;
- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
mutex_unlock(&ei->i_fc_lock);
+
+ if (IS_ENCRYPTED(dir)) {
+ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_ENCRYPTED_FILENAME,
+ NULL);
+ mutex_lock(&ei->i_fc_lock);
+ return -EOPNOTSUPP;
+ }
+
node = kmem_cache_alloc(ext4_fc_dentry_cachep, GFP_NOFS);
if (!node) {
- ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
+ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, NULL);
mutex_lock(&ei->i_fc_lock);
return -ENOMEM;
}
node->fcd_op = dentry_update->op;
- node->fcd_parent = dentry->d_parent->d_inode->i_ino;
+ node->fcd_parent = dir->i_ino;
node->fcd_ino = inode->i_ino;
if (dentry->d_name.len > DNAME_INLINE_LEN) {
node->fcd_name.name = kmalloc(dentry->d_name.len, GFP_NOFS);
if (!node->fcd_name.name) {
kmem_cache_free(ext4_fc_dentry_cachep, node);
- ext4_fc_mark_ineligible(inode->i_sb,
- EXT4_FC_REASON_NOMEM, NULL);
+ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, NULL);
mutex_lock(&ei->i_fc_lock);
return -ENOMEM;
}
@@ -666,18 +675,6 @@ static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
/* Ext4 commit path routines */
-/* memzero and update CRC */
-static void *ext4_fc_memzero(struct super_block *sb, void *dst, int len,
- u32 *crc)
-{
- void *ret;
-
- ret = memset(dst, 0, len);
- if (crc)
- *crc = ext4_chksum(EXT4_SB(sb), *crc, dst, len);
- return ret;
-}
-
/*
* Allocate len bytes on a fast commit buffer.
*
@@ -691,62 +688,60 @@ static void *ext4_fc_memzero(struct super_block *sb, void *dst, int len,
*/
static u8 *ext4_fc_reserve_space(struct super_block *sb, int len, u32 *crc)
{
- struct ext4_fc_tl *tl;
+ struct ext4_fc_tl tl;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct buffer_head *bh;
int bsize = sbi->s_journal->j_blocksize;
int ret, off = sbi->s_fc_bytes % bsize;
- int pad_len;
+ int remaining;
+ u8 *dst;
/*
- * After allocating len, we should have space at least for a 0 byte
- * padding.
+ * If 'len' is too long to fit in any block alongside a PAD tlv, then we
+ * cannot fulfill the request.
*/
- if (len + EXT4_FC_TAG_BASE_LEN > bsize)
+ if (len > bsize - EXT4_FC_TAG_BASE_LEN)
return NULL;
- if (bsize - off - 1 > len + EXT4_FC_TAG_BASE_LEN) {
- /*
- * Only allocate from current buffer if we have enough space for
- * this request AND we have space to add a zero byte padding.
- */
- if (!sbi->s_fc_bh) {
- ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh);
- if (ret)
- return NULL;
- sbi->s_fc_bh = bh;
- }
+ if (!sbi->s_fc_bh) {
+ ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh);
+ if (ret)
+ return NULL;
+ sbi->s_fc_bh = bh;
+ }
+ dst = sbi->s_fc_bh->b_data + off;
+
+ /*
+ * Allocate the bytes in the current block if we can do so while still
+ * leaving enough space for a PAD tlv.
+ */
+ remaining = bsize - EXT4_FC_TAG_BASE_LEN - off;
+ if (len <= remaining) {
sbi->s_fc_bytes += len;
- return sbi->s_fc_bh->b_data + off;
+ return dst;
}
- /* Need to add PAD tag */
- tl = (struct ext4_fc_tl *)(sbi->s_fc_bh->b_data + off);
- tl->fc_tag = cpu_to_le16(EXT4_FC_TAG_PAD);
- pad_len = bsize - off - 1 - EXT4_FC_TAG_BASE_LEN;
- tl->fc_len = cpu_to_le16(pad_len);
- if (crc)
- *crc = ext4_chksum(sbi, *crc, tl, EXT4_FC_TAG_BASE_LEN);
- if (pad_len > 0)
- ext4_fc_memzero(sb, tl + 1, pad_len, crc);
+
+ /*
+ * Else, terminate the current block with a PAD tlv, then allocate a new
+ * block and allocate the bytes at the start of that new block.
+ */
+
+ tl.fc_tag = cpu_to_le16(EXT4_FC_TAG_PAD);
+ tl.fc_len = cpu_to_le16(remaining);
+ memcpy(dst, &tl, EXT4_FC_TAG_BASE_LEN);
+ memset(dst + EXT4_FC_TAG_BASE_LEN, 0, remaining);
+ *crc = ext4_chksum(sbi, *crc, sbi->s_fc_bh->b_data, bsize);
+
ext4_fc_submit_bh(sb, false);
ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh);
if (ret)
return NULL;
sbi->s_fc_bh = bh;
- sbi->s_fc_bytes = (sbi->s_fc_bytes / bsize + 1) * bsize + len;
+ sbi->s_fc_bytes += bsize - off + len;
return sbi->s_fc_bh->b_data;
}
-/* memcpy to fc reserved space and update CRC */
-static void *ext4_fc_memcpy(struct super_block *sb, void *dst, const void *src,
- int len, u32 *crc)
-{
- if (crc)
- *crc = ext4_chksum(EXT4_SB(sb), *crc, src, len);
- return memcpy(dst, src, len);
-}
-
/*
* Complete a fast commit by writing tail tag.
*
@@ -774,16 +769,20 @@ static int ext4_fc_write_tail(struct super_block *sb, u32 crc)
off = sbi->s_fc_bytes % bsize;
tl.fc_tag = cpu_to_le16(EXT4_FC_TAG_TAIL);
- tl.fc_len = cpu_to_le16(bsize - off - 1 + sizeof(struct ext4_fc_tail));
+ tl.fc_len = cpu_to_le16(bsize - off + sizeof(struct ext4_fc_tail));
sbi->s_fc_bytes = round_up(sbi->s_fc_bytes, bsize);
- ext4_fc_memcpy(sb, dst, &tl, EXT4_FC_TAG_BASE_LEN, &crc);
+ memcpy(dst, &tl, EXT4_FC_TAG_BASE_LEN);
dst += EXT4_FC_TAG_BASE_LEN;
tail.fc_tid = cpu_to_le32(sbi->s_journal->j_running_transaction->t_tid);
- ext4_fc_memcpy(sb, dst, &tail.fc_tid, sizeof(tail.fc_tid), &crc);
+ memcpy(dst, &tail.fc_tid, sizeof(tail.fc_tid));
dst += sizeof(tail.fc_tid);
+ crc = ext4_chksum(sbi, crc, sbi->s_fc_bh->b_data,
+ dst - (u8 *)sbi->s_fc_bh->b_data);
tail.fc_crc = cpu_to_le32(crc);
- ext4_fc_memcpy(sb, dst, &tail.fc_crc, sizeof(tail.fc_crc), NULL);
+ memcpy(dst, &tail.fc_crc, sizeof(tail.fc_crc));
+ dst += sizeof(tail.fc_crc);
+ memset(dst, 0, bsize - off); /* Don't leak uninitialized memory. */
ext4_fc_submit_bh(sb, true);
@@ -807,8 +806,8 @@ static bool ext4_fc_add_tlv(struct super_block *sb, u16 tag, u16 len, u8 *val,
tl.fc_tag = cpu_to_le16(tag);
tl.fc_len = cpu_to_le16(len);
- ext4_fc_memcpy(sb, dst, &tl, EXT4_FC_TAG_BASE_LEN, crc);
- ext4_fc_memcpy(sb, dst + EXT4_FC_TAG_BASE_LEN, val, len, crc);
+ memcpy(dst, &tl, EXT4_FC_TAG_BASE_LEN);
+ memcpy(dst + EXT4_FC_TAG_BASE_LEN, val, len);
return true;
}
@@ -830,11 +829,11 @@ static bool ext4_fc_add_dentry_tlv(struct super_block *sb, u32 *crc,
fcd.fc_ino = cpu_to_le32(fc_dentry->fcd_ino);
tl.fc_tag = cpu_to_le16(fc_dentry->fcd_op);
tl.fc_len = cpu_to_le16(sizeof(fcd) + dlen);
- ext4_fc_memcpy(sb, dst, &tl, EXT4_FC_TAG_BASE_LEN, crc);
+ memcpy(dst, &tl, EXT4_FC_TAG_BASE_LEN);
dst += EXT4_FC_TAG_BASE_LEN;
- ext4_fc_memcpy(sb, dst, &fcd, sizeof(fcd), crc);
+ memcpy(dst, &fcd, sizeof(fcd));
dst += sizeof(fcd);
- ext4_fc_memcpy(sb, dst, fc_dentry->fcd_name.name, dlen, crc);
+ memcpy(dst, fc_dentry->fcd_name.name, dlen);
return true;
}
@@ -872,15 +871,11 @@ static int ext4_fc_write_inode(struct inode *inode, u32 *crc)
if (!dst)
goto err;
- if (!ext4_fc_memcpy(inode->i_sb, dst, &tl, EXT4_FC_TAG_BASE_LEN, crc))
- goto err;
+ memcpy(dst, &tl, EXT4_FC_TAG_BASE_LEN);
dst += EXT4_FC_TAG_BASE_LEN;
- if (!ext4_fc_memcpy(inode->i_sb, dst, &fc_inode, sizeof(fc_inode), crc))
- goto err;
+ memcpy(dst, &fc_inode, sizeof(fc_inode));
dst += sizeof(fc_inode);
- if (!ext4_fc_memcpy(inode->i_sb, dst, (u8 *)ext4_raw_inode(&iloc),
- inode_len, crc))
- goto err;
+ memcpy(dst, (u8 *)ext4_raw_inode(&iloc), inode_len);
ret = 0;
err:
brelse(iloc.bh);
@@ -986,7 +981,7 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
finish_wait(&ei->i_fc_wait, &wait);
}
spin_unlock(&sbi->s_fc_lock);
- ret = jbd2_submit_inode_data(ei->jinode);
+ ret = jbd2_submit_inode_data(journal, ei->jinode);
if (ret)
return ret;
spin_lock(&sbi->s_fc_lock);
@@ -1388,7 +1383,7 @@ static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl,
return 0;
}
- ret = __ext4_unlink(NULL, old_parent, &entry, inode);
+ ret = __ext4_unlink(old_parent, &entry, inode, NULL);
/* -ENOENT ok coz it might not exist anymore. */
if (ret == -ENOENT)
ret = 0;
@@ -1977,32 +1972,31 @@ void ext4_fc_replay_cleanup(struct super_block *sb)
kfree(sbi->s_fc_replay_state.fc_modified_inodes);
}
-static inline bool ext4_fc_tag_len_isvalid(struct ext4_fc_tl *tl,
- u8 *val, u8 *end)
+static bool ext4_fc_value_len_isvalid(struct ext4_sb_info *sbi,
+ int tag, int len)
{
- if (val + tl->fc_len > end)
- return false;
-
- /* Here only check ADD_RANGE/TAIL/HEAD which will read data when do
- * journal rescan before do CRC check. Other tags length check will
- * rely on CRC check.
- */
- switch (tl->fc_tag) {
+ switch (tag) {
case EXT4_FC_TAG_ADD_RANGE:
- return (sizeof(struct ext4_fc_add_range) == tl->fc_len);
- case EXT4_FC_TAG_TAIL:
- return (sizeof(struct ext4_fc_tail) <= tl->fc_len);
- case EXT4_FC_TAG_HEAD:
- return (sizeof(struct ext4_fc_head) == tl->fc_len);
+ return len == sizeof(struct ext4_fc_add_range);
case EXT4_FC_TAG_DEL_RANGE:
+ return len == sizeof(struct ext4_fc_del_range);
+ case EXT4_FC_TAG_CREAT:
case EXT4_FC_TAG_LINK:
case EXT4_FC_TAG_UNLINK:
- case EXT4_FC_TAG_CREAT:
+ len -= sizeof(struct ext4_fc_dentry_info);
+ return len >= 1 && len <= EXT4_NAME_LEN;
case EXT4_FC_TAG_INODE:
+ len -= sizeof(struct ext4_fc_inode);
+ return len >= EXT4_GOOD_OLD_INODE_SIZE &&
+ len <= sbi->s_inode_size;
case EXT4_FC_TAG_PAD:
- default:
- return true;
+ return true; /* padding can have any length */
+ case EXT4_FC_TAG_TAIL:
+ return len >= sizeof(struct ext4_fc_tail);
+ case EXT4_FC_TAG_HEAD:
+ return len == sizeof(struct ext4_fc_head);
}
+ return false;
}
/*
@@ -2040,7 +2034,7 @@ static int ext4_fc_replay_scan(journal_t *journal,
state = &sbi->s_fc_replay_state;
start = (u8 *)bh->b_data;
- end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
+ end = start + journal->j_blocksize;
if (state->fc_replay_expected_off == 0) {
state->fc_cur_tag = 0;
@@ -2061,11 +2055,12 @@ static int ext4_fc_replay_scan(journal_t *journal,
}
state->fc_replay_expected_off++;
- for (cur = start; cur < end - EXT4_FC_TAG_BASE_LEN;
+ for (cur = start; cur <= end - EXT4_FC_TAG_BASE_LEN;
cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {
ext4_fc_get_tl(&tl, cur);
val = cur + EXT4_FC_TAG_BASE_LEN;
- if (!ext4_fc_tag_len_isvalid(&tl, val, end)) {
+ if (tl.fc_len > end - val ||
+ !ext4_fc_value_len_isvalid(sbi, tl.fc_tag, tl.fc_len)) {
ret = state->fc_replay_num_tags ?
JBD2_FC_REPLAY_STOP : -ECANCELED;
goto out_err;
@@ -2178,9 +2173,9 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
#endif
start = (u8 *)bh->b_data;
- end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
+ end = start + journal->j_blocksize;
- for (cur = start; cur < end - EXT4_FC_TAG_BASE_LEN;
+ for (cur = start; cur <= end - EXT4_FC_TAG_BASE_LEN;
cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {
ext4_fc_get_tl(&tl, cur);
val = cur + EXT4_FC_TAG_BASE_LEN;
@@ -2249,17 +2244,17 @@ void ext4_fc_init(struct super_block *sb, journal_t *journal)
journal->j_fc_cleanup_callback = ext4_fc_cleanup;
}
-static const char *fc_ineligible_reasons[] = {
- "Extended attributes changed",
- "Cross rename",
- "Journal flag changed",
- "Insufficient memory",
- "Swap boot",
- "Resize",
- "Dir renamed",
- "Falloc range op",
- "Data journalling",
- "FC Commit Failed"
+static const char * const fc_ineligible_reasons[] = {
+ [EXT4_FC_REASON_XATTR] = "Extended attributes changed",
+ [EXT4_FC_REASON_CROSS_RENAME] = "Cross rename",
+ [EXT4_FC_REASON_JOURNAL_FLAG_CHANGE] = "Journal flag changed",
+ [EXT4_FC_REASON_NOMEM] = "Insufficient memory",
+ [EXT4_FC_REASON_SWAP_BOOT] = "Swap boot",
+ [EXT4_FC_REASON_RESIZE] = "Resize",
+ [EXT4_FC_REASON_RENAME_DIR] = "Dir renamed",
+ [EXT4_FC_REASON_FALLOC_RANGE] = "Falloc range op",
+ [EXT4_FC_REASON_INODE_JOURNAL_DATA] = "Data journalling",
+ [EXT4_FC_REASON_ENCRYPTED_FILENAME] = "Encrypted filename",
};
int ext4_fc_info_show(struct seq_file *seq, void *v)
diff --git a/fs/ext4/fast_commit.h b/fs/ext4/fast_commit.h
index a6154c3ed135..2fadb2c4780c 100644
--- a/fs/ext4/fast_commit.h
+++ b/fs/ext4/fast_commit.h
@@ -58,7 +58,7 @@ struct ext4_fc_dentry_info {
__u8 fc_dname[];
};
-/* Value structure for EXT4_FC_TAG_INODE and EXT4_FC_TAG_INODE_PARTIAL. */
+/* Value structure for EXT4_FC_TAG_INODE. */
struct ext4_fc_inode {
__le32 fc_ino;
__u8 fc_raw_inode[];
@@ -96,6 +96,7 @@ enum {
EXT4_FC_REASON_RENAME_DIR,
EXT4_FC_REASON_FALLOC_RANGE,
EXT4_FC_REASON_INODE_JOURNAL_DATA,
+ EXT4_FC_REASON_ENCRYPTED_FILENAME,
EXT4_FC_REASON_MAX
};
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index a7a597c727e6..7ac0a81bd371 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -955,7 +955,7 @@ const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_file_getattr,
.listxattr = ext4_listxattr,
- .get_acl = ext4_get_acl,
+ .get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
.fileattr_get = ext4_fileattr_get,
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index e9bc46684106..63f9bb6e8851 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -465,7 +465,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
ext4fs_dirhash(parent, qstr->name, qstr->len, &hinfo);
parent_group = hinfo.hash % ngroups;
} else
- parent_group = prandom_u32_max(ngroups);
+ parent_group = get_random_u32_below(ngroups);
for (i = 0; i < ngroups; i++) {
g = (parent_group + i) % ngroups;
get_orlov_stats(sb, g, flex_size, &stats);
@@ -870,7 +870,7 @@ static int ext4_xattr_credits_for_new_inode(struct inode *dir, mode_t mode,
struct super_block *sb = dir->i_sb;
int nblocks = 0;
#ifdef CONFIG_EXT4_FS_POSIX_ACL
- struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);
+ struct posix_acl *p = get_inode_acl(dir, ACL_TYPE_DEFAULT);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -1076,8 +1076,8 @@ repeat_in_this_group:
if ((!(sbi->s_mount_state & EXT4_FC_REPLAY)) && !handle) {
BUG_ON(nblocks <= 0);
- handle = __ext4_journal_start_sb(dir->i_sb, line_no,
- handle_type, nblocks, 0,
+ handle = __ext4_journal_start_sb(NULL, dir->i_sb,
+ line_no, handle_type, nblocks, 0,
ext4_trans_default_revoke_credits(sb));
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index 860fc5119009..c68bebe7ff4b 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -148,6 +148,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
struct super_block *sb = inode->i_sb;
Indirect *p = chain;
struct buffer_head *bh;
+ unsigned int key;
int ret = -EIO;
*err = 0;
@@ -156,7 +157,13 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
if (!p->key)
goto no_block;
while (--depth) {
- bh = sb_getblk(sb, le32_to_cpu(p->key));
+ key = le32_to_cpu(p->key);
+ if (key > ext4_blocks_count(EXT4_SB(sb)->s_es)) {
+ /* the block was out of range */
+ ret = -EFSCORRUPTED;
+ goto failure;
+ }
+ bh = sb_getblk(sb, key);
if (unlikely(!bh)) {
ret = -ENOMEM;
goto failure;
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index a4fbe825694b..2b42ececa46d 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -180,8 +180,7 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
BUG_ON(len > EXT4_I(inode)->i_inline_size);
- cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ?
- len : EXT4_MIN_INLINE_DATA_SIZE;
+ cp_len = min_t(unsigned int, len, EXT4_MIN_INLINE_DATA_SIZE);
raw_inode = ext4_raw_inode(iloc);
memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2b5ef1b64249..9d9f414f99fe 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -222,13 +222,13 @@ void ext4_evict_inode(struct inode *inode)
/*
* For inodes with journalled data, transaction commit could have
- * dirtied the inode. Flush worker is ignoring it because of I_FREEING
- * flag but we still need to remove the inode from the writeback lists.
+ * dirtied the inode. And for inodes with dioread_nolock, unwritten
+ * extents converting worker could merge extents and also have dirtied
+ * the inode. Flush worker is ignoring it because of I_FREEING flag but
+ * we still need to remove the inode from the writeback lists.
*/
- if (!list_empty_careful(&inode->i_io_list)) {
- WARN_ON_ONCE(!ext4_should_journal_data(inode));
+ if (!list_empty_careful(&inode->i_io_list))
inode_io_list_del(inode);
- }
/*
* Protect us against freezing - iput() caller didn't have to have any
@@ -335,6 +335,12 @@ stop_handle:
ext4_xattr_inode_array_free(ea_inode_array);
return;
no_delete:
+ /*
+ * Check out some where else accidentally dirty the evicting inode,
+ * which may probably cause inode use-after-free issues later.
+ */
+ WARN_ON_ONCE(!list_empty_careful(&inode->i_io_list));
+
if (!list_empty(&EXT4_I(inode)->i_fc_list))
ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
@@ -1309,7 +1315,8 @@ static int ext4_write_end(struct file *file,
trace_ext4_write_end(inode, pos, len, copied);
- if (ext4_has_inline_data(inode))
+ if (ext4_has_inline_data(inode) &&
+ ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
return ext4_write_inline_data_end(inode, pos, len, copied, page);
copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
@@ -1543,9 +1550,12 @@ void ext4_da_release_space(struct inode *inode, int to_free)
*/
struct mpage_da_data {
+ /* These are input fields for ext4_do_writepages() */
struct inode *inode;
struct writeback_control *wbc;
+ unsigned int can_map:1; /* Can writepages call map blocks? */
+ /* These are internal state of ext4_do_writepages() */
pgoff_t first_page; /* The first page to write */
pgoff_t next_page; /* Current page to examine */
pgoff_t last_page; /* Last page to examine */
@@ -2009,7 +2019,6 @@ static int ext4_writepage(struct page *page,
struct buffer_head *page_bufs = NULL;
struct inode *inode = page->mapping->host;
struct ext4_io_submit io_submit;
- bool keep_towrite = false;
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) {
folio_invalidate(folio, 0, folio_size(folio));
@@ -2067,7 +2076,6 @@ static int ext4_writepage(struct page *page,
unlock_page(page);
return 0;
}
- keep_towrite = true;
}
if (PageChecked(page) && ext4_should_journal_data(inode))
@@ -2084,7 +2092,7 @@ static int ext4_writepage(struct page *page,
unlock_page(page);
return -ENOMEM;
}
- ret = ext4_bio_write_page(&io_submit, page, len, keep_towrite);
+ ret = ext4_bio_write_page(&io_submit, page, len);
ext4_io_submit(&io_submit);
/* Drop io_end reference we got from init */
ext4_put_io_end_defer(io_submit.io_end);
@@ -2118,7 +2126,7 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
len = size & ~PAGE_MASK;
else
len = PAGE_SIZE;
- err = ext4_bio_write_page(&mpd->io_submit, page, len, false);
+ err = ext4_bio_write_page(&mpd->io_submit, page, len);
if (!err)
mpd->wbc->nr_to_write--;
mpd->first_page++;
@@ -2551,18 +2559,33 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp);
}
+/* Return true if the page needs to be written as part of transaction commit */
+static bool ext4_page_nomap_can_writeout(struct page *page)
+{
+ struct buffer_head *bh, *head;
+
+ bh = head = page_buffers(page);
+ do {
+ if (buffer_dirty(bh) && buffer_mapped(bh) && !buffer_delay(bh))
+ return true;
+ } while ((bh = bh->b_this_page) != head);
+ return false;
+}
+
/*
* mpage_prepare_extent_to_map - find & lock contiguous range of dirty pages
- * and underlying extent to map
+ * needing mapping, submit mapped pages
*
* @mpd - where to look for pages
*
* Walk dirty pages in the mapping. If they are fully mapped, submit them for
- * IO immediately. When we find a page which isn't mapped we start accumulating
- * extent of buffers underlying these pages that needs mapping (formed by
- * either delayed or unwritten buffers). We also lock the pages containing
- * these buffers. The extent found is returned in @mpd structure (starting at
- * mpd->lblk with length mpd->len blocks).
+ * IO immediately. If we cannot map blocks, we submit just already mapped
+ * buffers in the page for IO and keep page dirty. When we can map blocks and
+ * we find a page which isn't mapped we start accumulating extent of buffers
+ * underlying these pages that needs mapping (formed by either delayed or
+ * unwritten buffers). We also lock the pages containing these buffers. The
+ * extent found is returned in @mpd structure (starting at mpd->lblk with
+ * length mpd->len blocks).
*
* Note that this function can attach bios to one io_end structure which are
* neither logically nor physically contiguous. Although it may seem as an
@@ -2653,14 +2676,30 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
if (mpd->map.m_len == 0)
mpd->first_page = page->index;
mpd->next_page = page->index + 1;
- /* Add all dirty buffers to mpd */
- lblk = ((ext4_lblk_t)page->index) <<
- (PAGE_SHIFT - blkbits);
- head = page_buffers(page);
- err = mpage_process_page_bufs(mpd, head, head, lblk);
- if (err <= 0)
- goto out;
- err = 0;
+ /*
+ * Writeout for transaction commit where we cannot
+ * modify metadata is simple. Just submit the page.
+ */
+ if (!mpd->can_map) {
+ if (ext4_page_nomap_can_writeout(page)) {
+ err = mpage_submit_page(mpd, page);
+ if (err < 0)
+ goto out;
+ } else {
+ unlock_page(page);
+ mpd->first_page++;
+ }
+ } else {
+ /* Add all dirty buffers to mpd */
+ lblk = ((ext4_lblk_t)page->index) <<
+ (PAGE_SHIFT - blkbits);
+ head = page_buffers(page);
+ err = mpage_process_page_bufs(mpd, head, head,
+ lblk);
+ if (err <= 0)
+ goto out;
+ err = 0;
+ }
left--;
}
pagevec_release(&pvec);
@@ -2673,25 +2712,27 @@ out:
return err;
}
-static int ext4_writepages(struct address_space *mapping,
- struct writeback_control *wbc)
+static int ext4_writepage_cb(struct page *page, struct writeback_control *wbc,
+ void *data)
{
+ return ext4_writepage(page, wbc);
+}
+
+static int ext4_do_writepages(struct mpage_da_data *mpd)
+{
+ struct writeback_control *wbc = mpd->wbc;
pgoff_t writeback_index = 0;
long nr_to_write = wbc->nr_to_write;
int range_whole = 0;
int cycled = 1;
handle_t *handle = NULL;
- struct mpage_da_data mpd;
- struct inode *inode = mapping->host;
+ struct inode *inode = mpd->inode;
+ struct address_space *mapping = inode->i_mapping;
int needed_blocks, rsv_blocks = 0, ret = 0;
struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
struct blk_plug plug;
bool give_up_on_write = false;
- if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
- return -EIO;
-
- percpu_down_read(&sbi->s_writepages_rwsem);
trace_ext4_writepages(inode, wbc);
/*
@@ -2703,7 +2744,9 @@ static int ext4_writepages(struct address_space *mapping,
goto out_writepages;
if (ext4_should_journal_data(inode)) {
- ret = generic_writepages(mapping, wbc);
+ blk_start_plug(&plug);
+ ret = write_cache_pages(mapping, wbc, ext4_writepage_cb, NULL);
+ blk_finish_plug(&plug);
goto out_writepages;
}
@@ -2757,19 +2800,18 @@ static int ext4_writepages(struct address_space *mapping,
writeback_index = mapping->writeback_index;
if (writeback_index)
cycled = 0;
- mpd.first_page = writeback_index;
- mpd.last_page = -1;
+ mpd->first_page = writeback_index;
+ mpd->last_page = -1;
} else {
- mpd.first_page = wbc->range_start >> PAGE_SHIFT;
- mpd.last_page = wbc->range_end >> PAGE_SHIFT;
+ mpd->first_page = wbc->range_start >> PAGE_SHIFT;
+ mpd->last_page = wbc->range_end >> PAGE_SHIFT;
}
- mpd.inode = inode;
- mpd.wbc = wbc;
- ext4_io_submit_init(&mpd.io_submit, wbc);
+ ext4_io_submit_init(&mpd->io_submit, wbc);
retry:
if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
- tag_pages_for_writeback(mapping, mpd.first_page, mpd.last_page);
+ tag_pages_for_writeback(mapping, mpd->first_page,
+ mpd->last_page);
blk_start_plug(&plug);
/*
@@ -2778,31 +2820,32 @@ retry:
* in the block layer on device congestion while having transaction
* started.
*/
- mpd.do_map = 0;
- mpd.scanned_until_end = 0;
- mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
- if (!mpd.io_submit.io_end) {
+ mpd->do_map = 0;
+ mpd->scanned_until_end = 0;
+ mpd->io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
+ if (!mpd->io_submit.io_end) {
ret = -ENOMEM;
goto unplug;
}
- ret = mpage_prepare_extent_to_map(&mpd);
+ ret = mpage_prepare_extent_to_map(mpd);
/* Unlock pages we didn't use */
- mpage_release_unused_pages(&mpd, false);
+ mpage_release_unused_pages(mpd, false);
/* Submit prepared bio */
- ext4_io_submit(&mpd.io_submit);
- ext4_put_io_end_defer(mpd.io_submit.io_end);
- mpd.io_submit.io_end = NULL;
+ ext4_io_submit(&mpd->io_submit);
+ ext4_put_io_end_defer(mpd->io_submit.io_end);
+ mpd->io_submit.io_end = NULL;
if (ret < 0)
goto unplug;
- while (!mpd.scanned_until_end && wbc->nr_to_write > 0) {
+ while (!mpd->scanned_until_end && wbc->nr_to_write > 0) {
/* For each extent of pages we use new io_end */
- mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
- if (!mpd.io_submit.io_end) {
+ mpd->io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
+ if (!mpd->io_submit.io_end) {
ret = -ENOMEM;
break;
}
+ WARN_ON_ONCE(!mpd->can_map);
/*
* We have two constraints: We find one extent to map and we
* must always write out whole page (makes a difference when
@@ -2822,16 +2865,16 @@ retry:
"%ld pages, ino %lu; err %d", __func__,
wbc->nr_to_write, inode->i_ino, ret);
/* Release allocated io_end */
- ext4_put_io_end(mpd.io_submit.io_end);
- mpd.io_submit.io_end = NULL;
+ ext4_put_io_end(mpd->io_submit.io_end);
+ mpd->io_submit.io_end = NULL;
break;
}
- mpd.do_map = 1;
+ mpd->do_map = 1;
- trace_ext4_da_write_pages(inode, mpd.first_page, mpd.wbc);
- ret = mpage_prepare_extent_to_map(&mpd);
- if (!ret && mpd.map.m_len)
- ret = mpage_map_and_submit_extent(handle, &mpd,
+ trace_ext4_da_write_pages(inode, mpd->first_page, wbc);
+ ret = mpage_prepare_extent_to_map(mpd);
+ if (!ret && mpd->map.m_len)
+ ret = mpage_map_and_submit_extent(handle, mpd,
&give_up_on_write);
/*
* Caution: If the handle is synchronous,
@@ -2846,12 +2889,12 @@ retry:
if (!ext4_handle_valid(handle) || handle->h_sync == 0) {
ext4_journal_stop(handle);
handle = NULL;
- mpd.do_map = 0;
+ mpd->do_map = 0;
}
/* Unlock pages we didn't use */
- mpage_release_unused_pages(&mpd, give_up_on_write);
+ mpage_release_unused_pages(mpd, give_up_on_write);
/* Submit prepared bio */
- ext4_io_submit(&mpd.io_submit);
+ ext4_io_submit(&mpd->io_submit);
/*
* Drop our io_end reference we got from init. We have
@@ -2861,11 +2904,11 @@ retry:
* up doing unwritten extent conversion.
*/
if (handle) {
- ext4_put_io_end_defer(mpd.io_submit.io_end);
+ ext4_put_io_end_defer(mpd->io_submit.io_end);
ext4_journal_stop(handle);
} else
- ext4_put_io_end(mpd.io_submit.io_end);
- mpd.io_submit.io_end = NULL;
+ ext4_put_io_end(mpd->io_submit.io_end);
+ mpd->io_submit.io_end = NULL;
if (ret == -ENOSPC && sbi->s_journal) {
/*
@@ -2885,8 +2928,8 @@ unplug:
blk_finish_plug(&plug);
if (!ret && !cycled && wbc->nr_to_write > 0) {
cycled = 1;
- mpd.last_page = writeback_index - 1;
- mpd.first_page = 0;
+ mpd->last_page = writeback_index - 1;
+ mpd->first_page = 0;
goto retry;
}
@@ -2896,15 +2939,51 @@ unplug:
* Set the writeback_index so that range_cyclic
* mode will write it back later
*/
- mapping->writeback_index = mpd.first_page;
+ mapping->writeback_index = mpd->first_page;
out_writepages:
trace_ext4_writepages_result(inode, wbc, ret,
nr_to_write - wbc->nr_to_write);
- percpu_up_read(&sbi->s_writepages_rwsem);
return ret;
}
+static int ext4_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct super_block *sb = mapping->host->i_sb;
+ struct mpage_da_data mpd = {
+ .inode = mapping->host,
+ .wbc = wbc,
+ .can_map = 1,
+ };
+ int ret;
+
+ if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+ return -EIO;
+
+ percpu_down_read(&EXT4_SB(sb)->s_writepages_rwsem);
+ ret = ext4_do_writepages(&mpd);
+ percpu_up_read(&EXT4_SB(sb)->s_writepages_rwsem);
+
+ return ret;
+}
+
+int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode)
+{
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_ALL,
+ .nr_to_write = LONG_MAX,
+ .range_start = jinode->i_dirty_start,
+ .range_end = jinode->i_dirty_end,
+ };
+ struct mpage_da_data mpd = {
+ .inode = jinode->i_vfs_inode,
+ .wbc = &wbc,
+ .can_map = 0,
+ };
+ return ext4_do_writepages(&mpd);
+}
+
static int ext4_dax_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
@@ -3646,7 +3725,6 @@ static int ext4_iomap_swap_activate(struct swap_info_struct *sis,
static const struct address_space_operations ext4_aops = {
.read_folio = ext4_read_folio,
.readahead = ext4_readahead,
- .writepage = ext4_writepage,
.writepages = ext4_writepages,
.write_begin = ext4_write_begin,
.write_end = ext4_write_end,
@@ -3664,7 +3742,6 @@ static const struct address_space_operations ext4_aops = {
static const struct address_space_operations ext4_journalled_aops = {
.read_folio = ext4_read_folio,
.readahead = ext4_readahead,
- .writepage = ext4_writepage,
.writepages = ext4_writepages,
.write_begin = ext4_write_begin,
.write_end = ext4_journalled_write_end,
@@ -3673,6 +3750,7 @@ static const struct address_space_operations ext4_journalled_aops = {
.invalidate_folio = ext4_journalled_invalidate_folio,
.release_folio = ext4_release_folio,
.direct_IO = noop_direct_IO,
+ .migrate_folio = buffer_migrate_folio_norefs,
.is_partially_uptodate = block_is_partially_uptodate,
.error_remove_page = generic_error_remove_page,
.swap_activate = ext4_iomap_swap_activate,
@@ -3681,7 +3759,6 @@ static const struct address_space_operations ext4_journalled_aops = {
static const struct address_space_operations ext4_da_aops = {
.read_folio = ext4_read_folio,
.readahead = ext4_readahead,
- .writepage = ext4_writepage,
.writepages = ext4_writepages,
.write_begin = ext4_da_write_begin,
.write_end = ext4_da_write_end,
@@ -4225,7 +4302,8 @@ int ext4_truncate(struct inode *inode)
/* If we zero-out tail of the page, we have to create jinode for jbd2 */
if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
- if (ext4_inode_attach_jinode(inode) < 0)
+ err = ext4_inode_attach_jinode(inode);
+ if (err)
goto out_trace;
}
@@ -4473,9 +4551,17 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino,
inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
inode_offset = ((ino - 1) %
EXT4_INODES_PER_GROUP(sb));
- block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block);
iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
+ block = ext4_inode_table(sb, gdp);
+ if ((block <= le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) ||
+ (block >= ext4_blocks_count(EXT4_SB(sb)->s_es))) {
+ ext4_error(sb, "Invalid inode table block %llu in "
+ "block_group %u", block, iloc->block_group);
+ return -EFSCORRUPTED;
+ }
+ block += (inode_offset / inodes_per_block);
+
bh = sb_getblk(sb, block);
if (unlikely(!bh))
return -ENOMEM;
@@ -5044,8 +5130,14 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb))
ext4_error_inode(inode, function, line, 0,
"casefold flag without casefold feature");
- brelse(iloc.bh);
+ if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
+ ext4_error_inode(inode, function, line, 0,
+ "bad inode without EXT4_IGET_BAD flag");
+ ret = -EUCLEAN;
+ goto bad_inode;
+ }
+ brelse(iloc.bh);
unlock_new_inode(inode);
return inode;
@@ -5550,7 +5642,7 @@ out_mmap_sem:
ext4_orphan_del(NULL, inode);
if (!error && (ia_valid & ATTR_MODE))
- rc = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
+ rc = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
err_out:
if (error)
@@ -5853,6 +5945,14 @@ static int __ext4_expand_extra_isize(struct inode *inode,
return 0;
}
+ /*
+ * We may need to allocate external xattr block so we need quotas
+ * initialized. Here we can be called with various locks held so we
+ * cannot affort to initialize quotas ourselves. So just bail.
+ */
+ if (dquot_initialize_needed(inode))
+ return -EAGAIN;
+
/* try to expand with EAs present */
error = ext4_expand_extra_isize_ea(inode, new_extra_isize,
raw_inode, handle);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 95dfea28bf4e..8067ccda34e4 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -374,7 +374,8 @@ static long swap_inode_boot_loader(struct super_block *sb,
blkcnt_t blocks;
unsigned short bytes;
- inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
+ inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO,
+ EXT4_IGET_SPECIAL | EXT4_IGET_BAD);
if (IS_ERR(inode_bl))
return PTR_ERR(inode_bl);
ei_bl = EXT4_I(inode_bl);
@@ -424,7 +425,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
/* Protect extent tree against block allocations via delalloc */
ext4_double_down_write_data_sem(inode, inode_bl);
- if (inode_bl->i_nlink == 0) {
+ if (is_bad_inode(inode_bl) || !S_ISREG(inode_bl->i_mode)) {
/* this inode has never been used as a BOOT_LOADER */
set_nlink(inode_bl, 1);
i_uid_write(inode_bl, 0);
@@ -731,6 +732,10 @@ static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
if (ext4_is_quota_file(inode))
return err;
+ err = dquot_initialize(inode);
+ if (err)
+ return err;
+
err = ext4_get_inode_loc(inode, &iloc);
if (err)
return err;
@@ -746,10 +751,6 @@ static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
brelse(iloc.bh);
}
- err = dquot_initialize(inode);
- if (err)
- return err;
-
handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
EXT4_QUOTA_INIT_BLOCKS(sb) +
EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
@@ -1153,19 +1154,22 @@ static int ext4_ioctl_getuuid(struct ext4_sb_info *sbi,
if (fsuuid.fsu_len == 0) {
fsuuid.fsu_len = UUID_SIZE;
- if (copy_to_user(ufsuuid, &fsuuid, sizeof(fsuuid.fsu_len)))
+ if (copy_to_user(&ufsuuid->fsu_len, &fsuuid.fsu_len,
+ sizeof(fsuuid.fsu_len)))
return -EFAULT;
- return -EINVAL;
+ return 0;
}
- if (fsuuid.fsu_len != UUID_SIZE || fsuuid.fsu_flags != 0)
+ if (fsuuid.fsu_len < UUID_SIZE || fsuuid.fsu_flags != 0)
return -EINVAL;
lock_buffer(sbi->s_sbh);
memcpy(uuid, sbi->s_es->s_uuid, UUID_SIZE);
unlock_buffer(sbi->s_sbh);
- if (copy_to_user(&ufsuuid->fsu_uuid[0], uuid, UUID_SIZE))
+ fsuuid.fsu_len = UUID_SIZE;
+ if (copy_to_user(ufsuuid, &fsuuid, sizeof(fsuuid)) ||
+ copy_to_user(&ufsuuid->fsu_uuid[0], uuid, UUID_SIZE))
return -EFAULT;
return 0;
}
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 9dad93059945..5b2ae37a8b80 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -5204,7 +5204,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
mutex_lock(&ac->ac_lg->lg_mutex);
}
-static noinline_for_stack int
+static noinline_for_stack void
ext4_mb_initialize_context(struct ext4_allocation_context *ac,
struct ext4_allocation_request *ar)
{
@@ -5253,8 +5253,6 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
(unsigned) ar->lleft, (unsigned) ar->pleft,
(unsigned) ar->lright, (unsigned) ar->pright,
inode_is_open_for_write(ar->inode) ? "" : "non-");
- return 0;
-
}
static noinline_for_stack void
@@ -5591,11 +5589,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
goto out;
}
- *errp = ext4_mb_initialize_context(ac, ar);
- if (*errp) {
- ar->len = 0;
- goto out;
- }
+ ext4_mb_initialize_context(ac, ar);
ac->ac_op = EXT4_MB_HISTORY_PREALLOC;
seq = this_cpu_read(discard_pa_seq);
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
index 588cb09c5291..4681fff6665f 100644
--- a/fs/ext4/mmp.c
+++ b/fs/ext4/mmp.c
@@ -262,13 +262,7 @@ void ext4_stop_mmpd(struct ext4_sb_info *sbi)
*/
static unsigned int mmp_new_seq(void)
{
- u32 new_seq;
-
- do {
- new_seq = get_random_u32();
- } while (new_seq > EXT4_MMP_SEQ_MAX);
-
- return new_seq;
+ return get_random_u32_below(EXT4_MMP_SEQ_MAX + 1);
}
/*
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index c08c0aba1883..dd28453d6ea3 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3204,14 +3204,20 @@ end_rmdir:
return retval;
}
-int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name,
- struct inode *inode)
+int __ext4_unlink(struct inode *dir, const struct qstr *d_name,
+ struct inode *inode,
+ struct dentry *dentry /* NULL during fast_commit recovery */)
{
int retval = -ENOENT;
struct buffer_head *bh;
struct ext4_dir_entry_2 *de;
+ handle_t *handle;
int skip_remove_dentry = 0;
+ /*
+ * Keep this outside the transaction; it may have to set up the
+ * directory's encryption key, which isn't GFP_NOFS-safe.
+ */
bh = ext4_find_entry(dir, d_name, &de, NULL);
if (IS_ERR(bh))
return PTR_ERR(bh);
@@ -3228,7 +3234,14 @@ int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name
if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
skip_remove_dentry = 1;
else
- goto out;
+ goto out_bh;
+ }
+
+ handle = ext4_journal_start(dir, EXT4_HT_DIR,
+ EXT4_DATA_TRANS_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle)) {
+ retval = PTR_ERR(handle);
+ goto out_bh;
}
if (IS_DIRSYNC(dir))
@@ -3237,12 +3250,12 @@ int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name
if (!skip_remove_dentry) {
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
- goto out;
+ goto out_handle;
dir->i_ctime = dir->i_mtime = current_time(dir);
ext4_update_dx_flag(dir);
retval = ext4_mark_inode_dirty(handle, dir);
if (retval)
- goto out;
+ goto out_handle;
} else {
retval = 0;
}
@@ -3255,15 +3268,17 @@ int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name
ext4_orphan_add(handle, inode);
inode->i_ctime = current_time(inode);
retval = ext4_mark_inode_dirty(handle, inode);
-
-out:
+ if (dentry && !retval)
+ ext4_fc_track_unlink(handle, dentry);
+out_handle:
+ ext4_journal_stop(handle);
+out_bh:
brelse(bh);
return retval;
}
static int ext4_unlink(struct inode *dir, struct dentry *dentry)
{
- handle_t *handle;
int retval;
if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
@@ -3281,16 +3296,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
if (retval)
goto out_trace;
- handle = ext4_journal_start(dir, EXT4_HT_DIR,
- EXT4_DATA_TRANS_BLOCKS(dir->i_sb));
- if (IS_ERR(handle)) {
- retval = PTR_ERR(handle);
- goto out_trace;
- }
-
- retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry));
- if (!retval)
- ext4_fc_track_unlink(handle, dentry);
+ retval = __ext4_unlink(dir, &dentry->d_name, d_inode(dentry), dentry);
#if IS_ENABLED(CONFIG_UNICODE)
/* VFS negative dentries are incompatible with Encoding and
* Case-insensitiveness. Eventually we'll want avoid
@@ -3301,8 +3307,6 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
if (IS_CASEFOLDED(dir))
d_invalidate(dentry);
#endif
- if (handle)
- ext4_journal_stop(handle);
out_trace:
trace_ext4_unlink_exit(dentry, retval);
@@ -3794,6 +3798,9 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
retval = dquot_initialize(old.dir);
if (retval)
return retval;
+ retval = dquot_initialize(old.inode);
+ if (retval)
+ return retval;
retval = dquot_initialize(new.dir);
if (retval)
return retval;
@@ -4194,7 +4201,7 @@ const struct inode_operations ext4_dir_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
- .get_acl = ext4_get_acl,
+ .get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
.fileattr_get = ext4_fileattr_get,
@@ -4205,6 +4212,6 @@ const struct inode_operations ext4_special_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
- .get_acl = ext4_get_acl,
+ .get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
};
diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
index 69a9cf9137a6..e5b47dda3317 100644
--- a/fs/ext4/orphan.c
+++ b/fs/ext4/orphan.c
@@ -412,7 +412,7 @@ void ext4_orphan_cleanup(struct super_block *sb, struct ext4_super_block *es)
/* don't clear list on RO mount w/ errors */
if (es->s_last_orphan && !(s_flags & SB_RDONLY)) {
ext4_msg(sb, KERN_INFO, "Errors on filesystem, "
- "clearing orphan list.\n");
+ "clearing orphan list.");
es->s_last_orphan = 0;
}
ext4_debug("Skipping orphan recovery on fs with errors.\n");
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 97fa7b4c645f..beaec6d81074 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -430,25 +430,20 @@ submit_and_retry:
int ext4_bio_write_page(struct ext4_io_submit *io,
struct page *page,
- int len,
- bool keep_towrite)
+ int len)
{
struct page *bounce_page = NULL;
struct inode *inode = page->mapping->host;
unsigned block_start;
struct buffer_head *bh, *head;
int ret = 0;
- int nr_submitted = 0;
int nr_to_submit = 0;
struct writeback_control *wbc = io->io_wbc;
+ bool keep_towrite = false;
BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page));
- if (keep_towrite)
- set_page_writeback_keepwrite(page);
- else
- set_page_writeback(page);
ClearPageError(page);
/*
@@ -482,16 +477,31 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
/* A hole? We can safely clear the dirty bit */
if (!buffer_mapped(bh))
clear_buffer_dirty(bh);
- if (io->io_bio)
- ext4_io_submit(io);
+ /*
+ * Keeping dirty some buffer we cannot write? Make sure
+ * to redirty the page and keep TOWRITE tag so that
+ * racing WB_SYNC_ALL writeback does not skip the page.
+ * This happens e.g. when doing writeout for
+ * transaction commit.
+ */
+ if (buffer_dirty(bh)) {
+ if (!PageDirty(page))
+ redirty_page_for_writepage(wbc, page);
+ keep_towrite = true;
+ }
continue;
}
if (buffer_new(bh))
clear_buffer_new(bh);
set_buffer_async_write(bh);
+ clear_buffer_dirty(bh);
nr_to_submit++;
} while ((bh = bh->b_this_page) != head);
+ /* Nothing to submit? Just unlock the page... */
+ if (!nr_to_submit)
+ goto unlock;
+
bh = head = page_buffers(page);
/*
@@ -532,27 +542,29 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret);
redirty_page_for_writepage(wbc, page);
do {
- clear_buffer_async_write(bh);
+ if (buffer_async_write(bh)) {
+ clear_buffer_async_write(bh);
+ set_buffer_dirty(bh);
+ }
bh = bh->b_this_page;
} while (bh != head);
goto unlock;
}
}
+ if (keep_towrite)
+ set_page_writeback_keepwrite(page);
+ else
+ set_page_writeback(page);
+
/* Now submit buffers to write */
do {
if (!buffer_async_write(bh))
continue;
io_submit_add_bh(io, inode,
bounce_page ? bounce_page : page, bh);
- nr_submitted++;
- clear_buffer_dirty(bh);
} while ((bh = bh->b_this_page) != head);
-
unlock:
unlock_page(page);
- /* Nothing submitted - we have to end page writeback */
- if (!nr_submitted)
- end_page_writeback(page);
return ret;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 3d21eae267fc..d5266932ce6c 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -75,14 +75,10 @@ static void __read_end_io(struct bio *bio)
bio_for_each_segment_all(bv, bio, iter_all) {
page = bv->bv_page;
- /* PG_error was set if verity failed. */
- if (bio->bi_status || PageError(page)) {
+ if (bio->bi_status)
ClearPageUptodate(page);
- /* will re-read again later */
- ClearPageError(page);
- } else {
+ else
SetPageUptodate(page);
- }
unlock_page(page);
}
if (bio->bi_private)
@@ -410,9 +406,8 @@ int ext4_mpage_readpages(struct inode *inode,
int __init ext4_init_post_read_processing(void)
{
- bio_post_read_ctx_cache =
- kmem_cache_create("ext4_bio_post_read_ctx",
- sizeof(struct bio_post_read_ctx), 0, 0, NULL);
+ bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, SLAB_RECLAIM_ACCOUNT);
+
if (!bio_post_read_ctx_cache)
goto fail;
bio_post_read_ctx_pool =
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 46b87ffeb304..6b91443d6bf3 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1110,6 +1110,16 @@ exit_free:
return err;
}
+static inline void ext4_set_block_group_nr(struct super_block *sb, char *data,
+ ext4_group_t group)
+{
+ struct ext4_super_block *es = (struct ext4_super_block *) data;
+
+ es->s_block_group_nr = cpu_to_le16(group);
+ if (ext4_has_metadata_csum(sb))
+ es->s_checksum = ext4_superblock_csum(sb, es);
+}
+
/*
* Update the backup copies of the ext4 metadata. These don't need to be part
* of the main resize transaction, because e2fsck will re-write them if there
@@ -1158,7 +1168,8 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
while (group < sbi->s_groups_count) {
struct buffer_head *bh;
ext4_fsblk_t backup_block;
- struct ext4_super_block *es;
+ int has_super = ext4_bg_has_super(sb, group);
+ ext4_fsblk_t first_block = ext4_group_first_block_no(sb, group);
/* Out of journal space, and can't get more - abort - so sad */
err = ext4_resize_ensure_credits_batch(handle, 1);
@@ -1168,8 +1179,7 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
if (meta_bg == 0)
backup_block = ((ext4_fsblk_t)group) * bpg + blk_off;
else
- backup_block = (ext4_group_first_block_no(sb, group) +
- ext4_bg_has_super(sb, group));
+ backup_block = first_block + has_super;
bh = sb_getblk(sb, backup_block);
if (unlikely(!bh)) {
@@ -1187,10 +1197,8 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
memcpy(bh->b_data, data, size);
if (rest)
memset(bh->b_data + size, 0, rest);
- es = (struct ext4_super_block *) bh->b_data;
- es->s_block_group_nr = cpu_to_le16(group);
- if (ext4_has_metadata_csum(sb))
- es->s_checksum = ext4_superblock_csum(sb, es);
+ if (has_super && (backup_block == first_block))
+ ext4_set_block_group_nr(sb, bh->b_data, group);
set_buffer_uptodate(bh);
unlock_buffer(bh);
err = ext4_handle_dirty_metadata(handle, NULL, bh);
@@ -1476,8 +1484,6 @@ static void ext4_update_super(struct super_block *sb,
* active. */
ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
reserved_blocks);
- ext4_superblock_csum_set(sb);
- unlock_buffer(sbi->s_sbh);
/* Update the free space counts */
percpu_counter_add(&sbi->s_freeclusters_counter,
@@ -1513,6 +1519,8 @@ static void ext4_update_super(struct super_block *sb,
ext4_calculate_overhead(sb);
es->s_overhead_clusters = cpu_to_le32(sbi->s_overhead);
+ ext4_superblock_csum_set(sb);
+ unlock_buffer(sbi->s_sbh);
if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT4-fs: added group %u:"
"%llu blocks(%llu free %llu reserved)\n", flex_gd->count,
@@ -1596,8 +1604,8 @@ exit_journal:
int meta_bg = ext4_has_feature_meta_bg(sb);
sector_t old_gdb = 0;
- update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
- sizeof(struct ext4_super_block), 0);
+ update_backups(sb, ext4_group_first_block_no(sb, 0),
+ (char *)es, sizeof(struct ext4_super_block), 0);
for (; gdb_num <= gdb_num_end; gdb_num++) {
struct buffer_head *gdb_bh;
@@ -1808,7 +1816,7 @@ errout:
if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT4-fs: extended group to %llu "
"blocks\n", ext4_blocks_count(es));
- update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr,
+ update_backups(sb, ext4_group_first_block_no(sb, 0),
(char *)es, sizeof(struct ext4_super_block), 0);
}
return err;
@@ -1831,7 +1839,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
ext4_grpblk_t last;
ext4_grpblk_t add;
struct buffer_head *bh;
- int err;
ext4_group_t group;
o_blocks_count = ext4_blocks_count(es);
@@ -1886,8 +1893,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
}
brelse(bh);
- err = ext4_group_extend_no_check(sb, o_blocks_count, add);
- return err;
+ return ext4_group_extend_no_check(sb, o_blocks_count, add);
} /* ext4_group_extend */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 7cdd2138c897..16a343e8047d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -540,8 +540,7 @@ static int ext4_journal_submit_inode_data_buffers(struct jbd2_inode *jinode)
if (ext4_should_journal_data(jinode->i_vfs_inode))
ret = ext4_journalled_submit_inode_data_buffers(jinode);
else
- ret = jbd2_journal_submit_inode_data_buffers(jinode);
-
+ ret = ext4_normal_submit_inode_data_buffers(jinode);
return ret;
}
@@ -1206,7 +1205,8 @@ static void ext4_put_super(struct super_block *sb)
ext4_unregister_sysfs(sb);
if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs unmount"))
- ext4_msg(sb, KERN_INFO, "unmounting filesystem.");
+ ext4_msg(sb, KERN_INFO, "unmounting filesystem %pU.",
+ &sb->s_uuid);
ext4_unregister_li_request(sb);
ext4_quota_off_umount(sb);
@@ -1323,6 +1323,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
return NULL;
inode_set_iversion(&ei->vfs_inode, 1);
+ ei->i_flags = 0;
spin_lock_init(&ei->i_raw_lock);
INIT_LIST_HEAD(&ei->i_prealloc_list);
atomic_set(&ei->i_prealloc_active, 0);
@@ -2247,7 +2248,7 @@ static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param)
return -EINVAL;
}
- error = fs_lookup_param(fc, param, 1, &path);
+ error = fs_lookup_param(fc, param, 1, LOOKUP_FOLLOW, &path);
if (error) {
ext4_msg(NULL, KERN_ERR, "error: could not find "
"journal device path");
@@ -3778,7 +3779,7 @@ cont_thread:
}
if (!progress) {
elr->lr_next_sched = jiffies +
- prandom_u32_max(EXT4_DEF_LI_MAX_START_DELAY * HZ);
+ get_random_u32_below(EXT4_DEF_LI_MAX_START_DELAY * HZ);
}
if (time_before(elr->lr_next_sched, next_wakeup))
next_wakeup = elr->lr_next_sched;
@@ -3925,8 +3926,7 @@ static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
* spread the inode table initialization requests
* better.
*/
- elr->lr_next_sched = jiffies + prandom_u32_max(
- EXT4_DEF_LI_MAX_START_DELAY * HZ);
+ elr->lr_next_sched = jiffies + get_random_u32_below(EXT4_DEF_LI_MAX_START_DELAY * HZ);
return elr;
}
@@ -5287,14 +5287,15 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
goto failed_mount3a;
} else {
/* Nojournal mode, all journal mount options are illegal */
- if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
+ if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
ext4_msg(sb, KERN_ERR, "can't mount with "
- "journal_checksum, fs mounted w/o journal");
+ "journal_async_commit, fs mounted w/o journal");
goto failed_mount3a;
}
- if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+
+ if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
ext4_msg(sb, KERN_ERR, "can't mount with "
- "journal_async_commit, fs mounted w/o journal");
+ "journal_checksum, fs mounted w/o journal");
goto failed_mount3a;
}
if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
@@ -5655,8 +5656,9 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
descr = "out journal";
if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
- ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
- "Quota mode: %s.", descr, ext4_quota_mode(sb));
+ ext4_msg(sb, KERN_INFO, "mounted filesystem %pU with%s. "
+ "Quota mode: %s.", &sb->s_uuid, descr,
+ ext4_quota_mode(sb));
/* Update the s_overhead_clusters if necessary */
ext4_update_overhead(sb, false);
@@ -5723,7 +5725,7 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb,
ext4_debug("Journal inode found at %p: %lld bytes\n",
journal_inode, journal_inode->i_size);
- if (!S_ISREG(journal_inode->i_mode)) {
+ if (!S_ISREG(journal_inode->i_mode) || IS_ENCRYPTED(journal_inode)) {
ext4_msg(sb, KERN_ERR, "invalid journal inode");
iput(journal_inode);
return NULL;
@@ -6611,8 +6613,8 @@ static int ext4_reconfigure(struct fs_context *fc)
if (ret < 0)
return ret;
- ext4_msg(sb, KERN_INFO, "re-mounted. Quota mode: %s.",
- ext4_quota_mode(sb));
+ ext4_msg(sb, KERN_INFO, "re-mounted %pU. Quota mode: %s.",
+ &sb->s_uuid, ext4_quota_mode(sb));
return 0;
}
@@ -6886,6 +6888,20 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
return err;
}
+static inline bool ext4_check_quota_inum(int type, unsigned long qf_inum)
+{
+ switch (type) {
+ case USRQUOTA:
+ return qf_inum == EXT4_USR_QUOTA_INO;
+ case GRPQUOTA:
+ return qf_inum == EXT4_GRP_QUOTA_INO;
+ case PRJQUOTA:
+ return qf_inum >= EXT4_GOOD_OLD_FIRST_INO;
+ default:
+ BUG();
+ }
+}
+
static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
unsigned int flags)
{
@@ -6902,9 +6918,16 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
if (!qf_inums[type])
return -EPERM;
+ if (!ext4_check_quota_inum(type, qf_inums[type])) {
+ ext4_error(sb, "Bad quota inum: %lu, type: %d",
+ qf_inums[type], type);
+ return -EUCLEAN;
+ }
+
qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL);
if (IS_ERR(qf_inode)) {
- ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]);
+ ext4_error(sb, "Bad quota inode: %lu, type: %d",
+ qf_inums[type], type);
return PTR_ERR(qf_inode);
}
@@ -6943,8 +6966,9 @@ int ext4_enable_quotas(struct super_block *sb)
if (err) {
ext4_warning(sb,
"Failed to enable quota tracking "
- "(type=%d, err=%d). Please run "
- "e2fsck to fix.", type, err);
+ "(type=%d, err=%d, ino=%lu). "
+ "Please run e2fsck to fix.", type,
+ err, qf_inums[type]);
for (type--; type >= 0; type--) {
struct inode *inode;
@@ -7031,8 +7055,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
len = i_size-off;
toread = len;
while (toread > 0) {
- tocopy = sb->s_blocksize - offset < toread ?
- sb->s_blocksize - offset : toread;
+ tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
bh = ext4_bread(NULL, inode, blk, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c
index 3c640bd7ecae..30e3b65798b5 100644
--- a/fs/ext4/verity.c
+++ b/fs/ext4/verity.c
@@ -79,7 +79,7 @@ static int pagecache_write(struct inode *inode, const void *buf, size_t count,
size_t n = min_t(size_t, count,
PAGE_SIZE - offset_in_page(pos));
struct page *page;
- void *fsdata;
+ void *fsdata = NULL;
int res;
res = aops->write_begin(NULL, mapping, pos, n, &page, &fsdata);
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 36d6ba7190b6..7decaaf27e82 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1281,7 +1281,7 @@ retry_ref:
ce = mb_cache_entry_get(ea_block_cache, hash,
bh->b_blocknr);
if (ce) {
- ce->e_reusable = 1;
+ set_bit(MBE_REUSABLE_B, &ce->e_flags);
mb_cache_entry_put(ea_block_cache, ce);
}
}
@@ -1441,6 +1441,9 @@ static struct inode *ext4_xattr_inode_create(handle_t *handle,
if (!err)
err = ext4_inode_attach_jinode(ea_inode);
if (err) {
+ if (ext4_xattr_inode_dec_ref(handle, ea_inode))
+ ext4_warning_inode(ea_inode,
+ "cleanup dec ref error %d", err);
iput(ea_inode);
return ERR_PTR(err);
}
@@ -1540,7 +1543,8 @@ static int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode,
err = ext4_xattr_inode_write(handle, ea_inode, value, value_len);
if (err) {
- ext4_xattr_inode_dec_ref(handle, ea_inode);
+ if (ext4_xattr_inode_dec_ref(handle, ea_inode))
+ ext4_warning_inode(ea_inode, "cleanup dec ref error %d", err);
iput(ea_inode);
return err;
}
@@ -2042,7 +2046,7 @@ inserted:
}
BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
if (ref == EXT4_XATTR_REFCOUNT_MAX)
- ce->e_reusable = 0;
+ clear_bit(MBE_REUSABLE_B, &ce->e_flags);
ea_bdebug(new_bh, "reusing; refcount now=%d",
ref);
ext4_xattr_block_csum_set(inode, new_bh);
@@ -2070,19 +2074,11 @@ inserted:
goal = ext4_group_first_block_no(sb,
EXT4_I(inode)->i_block_group);
-
- /* non-extent files can't have physical blocks past 2^32 */
- if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
- goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
-
block = ext4_new_meta_blocks(handle, inode, goal, 0,
NULL, &error);
if (error)
goto cleanup;
- if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
- BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS);
-
ea_idebug(inode, "creating block %llu",
(unsigned long long)block);
@@ -2555,7 +2551,7 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
- buffer = kmalloc(value_size, GFP_NOFS);
+ buffer = kvmalloc(value_size, GFP_NOFS);
b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
if (!is || !bs || !buffer || !b_entry_name) {
error = -ENOMEM;
@@ -2607,7 +2603,7 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
error = 0;
out:
kfree(b_entry_name);
- kfree(buffer);
+ kvfree(buffer);
if (is)
brelse(is->iloc.bh);
if (bs)
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 5bbc44a5216e..c1c74aa658ae 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -276,9 +276,11 @@ static int __f2fs_set_acl(struct user_namespace *mnt_userns,
return error;
}
-int f2fs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int f2fs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
+ struct inode *inode = d_inode(dentry);
+
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h
index a26e33cab4ff..ea2bbb3f264b 100644
--- a/fs/f2fs/acl.h
+++ b/fs/f2fs/acl.h
@@ -34,7 +34,7 @@ struct f2fs_acl_header {
#ifdef CONFIG_F2FS_FS_POSIX_ACL
extern struct posix_acl *f2fs_get_acl(struct inode *, int, bool);
-extern int f2fs_set_acl(struct user_namespace *, struct inode *,
+extern int f2fs_set_acl(struct user_namespace *, struct dentry *,
struct posix_acl *, int);
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
struct page *);
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index d315c2de136f..2b7a5cc4ed66 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1711,50 +1711,27 @@ static void f2fs_put_dic(struct decompress_io_ctx *dic, bool in_task)
}
}
-/*
- * Update and unlock the cluster's pagecache pages, and release the reference to
- * the decompress_io_ctx that was being held for I/O completion.
- */
-static void __f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
- bool in_task)
+static void f2fs_verify_cluster(struct work_struct *work)
{
+ struct decompress_io_ctx *dic =
+ container_of(work, struct decompress_io_ctx, verity_work);
int i;
+ /* Verify, update, and unlock the decompressed pages. */
for (i = 0; i < dic->cluster_size; i++) {
struct page *rpage = dic->rpages[i];
if (!rpage)
continue;
- /* PG_error was set if verity failed. */
- if (failed || PageError(rpage)) {
- ClearPageUptodate(rpage);
- /* will re-read again later */
- ClearPageError(rpage);
- } else {
+ if (fsverity_verify_page(rpage))
SetPageUptodate(rpage);
- }
+ else
+ ClearPageUptodate(rpage);
unlock_page(rpage);
}
- f2fs_put_dic(dic, in_task);
-}
-
-static void f2fs_verify_cluster(struct work_struct *work)
-{
- struct decompress_io_ctx *dic =
- container_of(work, struct decompress_io_ctx, verity_work);
- int i;
-
- /* Verify the cluster's decompressed pages with fs-verity. */
- for (i = 0; i < dic->cluster_size; i++) {
- struct page *rpage = dic->rpages[i];
-
- if (rpage && !fsverity_verify_page(rpage))
- SetPageError(rpage);
- }
-
- __f2fs_decompress_end_io(dic, false, true);
+ f2fs_put_dic(dic, true);
}
/*
@@ -1764,6 +1741,8 @@ static void f2fs_verify_cluster(struct work_struct *work)
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
bool in_task)
{
+ int i;
+
if (!failed && dic->need_verity) {
/*
* Note that to avoid deadlocks, the verity work can't be done
@@ -1773,9 +1752,28 @@ void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
*/
INIT_WORK(&dic->verity_work, f2fs_verify_cluster);
fsverity_enqueue_verify_work(&dic->verity_work);
- } else {
- __f2fs_decompress_end_io(dic, failed, in_task);
+ return;
+ }
+
+ /* Update and unlock the cluster's pagecache pages. */
+ for (i = 0; i < dic->cluster_size; i++) {
+ struct page *rpage = dic->rpages[i];
+
+ if (!rpage)
+ continue;
+
+ if (failed)
+ ClearPageUptodate(rpage);
+ else
+ SetPageUptodate(rpage);
+ unlock_page(rpage);
}
+
+ /*
+ * Release the reference to the decompress_io_ctx that was being held
+ * for I/O completion.
+ */
+ f2fs_put_dic(dic, in_task);
}
/*
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index a71e818cd67b..7af75041bd81 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -116,43 +116,56 @@ struct bio_post_read_ctx {
struct f2fs_sb_info *sbi;
struct work_struct work;
unsigned int enabled_steps;
+ /*
+ * decompression_attempted keeps track of whether
+ * f2fs_end_read_compressed_page() has been called on the pages in the
+ * bio that belong to a compressed cluster yet.
+ */
+ bool decompression_attempted;
block_t fs_blkaddr;
};
+/*
+ * Update and unlock a bio's pages, and free the bio.
+ *
+ * This marks pages up-to-date only if there was no error in the bio (I/O error,
+ * decryption error, or verity error), as indicated by bio->bi_status.
+ *
+ * "Compressed pages" (pagecache pages backed by a compressed cluster on-disk)
+ * aren't marked up-to-date here, as decompression is done on a per-compression-
+ * cluster basis rather than a per-bio basis. Instead, we only must do two
+ * things for each compressed page here: call f2fs_end_read_compressed_page()
+ * with failed=true if an error occurred before it would have normally gotten
+ * called (i.e., I/O error or decryption error, but *not* verity error), and
+ * release the bio's reference to the decompress_io_ctx of the page's cluster.
+ */
static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
{
struct bio_vec *bv;
struct bvec_iter_all iter_all;
+ struct bio_post_read_ctx *ctx = bio->bi_private;
- /*
- * Update and unlock the bio's pagecache pages, and put the
- * decompression context for any compressed pages.
- */
bio_for_each_segment_all(bv, bio, iter_all) {
struct page *page = bv->bv_page;
if (f2fs_is_compressed_page(page)) {
- if (bio->bi_status)
+ if (ctx && !ctx->decompression_attempted)
f2fs_end_read_compressed_page(page, true, 0,
in_task);
f2fs_put_page_dic(page, in_task);
continue;
}
- /* PG_error was set if verity failed. */
- if (bio->bi_status || PageError(page)) {
+ if (bio->bi_status)
ClearPageUptodate(page);
- /* will re-read again later */
- ClearPageError(page);
- } else {
+ else
SetPageUptodate(page);
- }
dec_page_count(F2FS_P_SB(page), __read_io_type(page));
unlock_page(page);
}
- if (bio->bi_private)
- mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+ if (ctx)
+ mempool_free(ctx, bio_post_read_ctx_pool);
bio_put(bio);
}
@@ -185,8 +198,10 @@ static void f2fs_verify_bio(struct work_struct *work)
struct page *page = bv->bv_page;
if (!f2fs_is_compressed_page(page) &&
- !fsverity_verify_page(page))
- SetPageError(page);
+ !fsverity_verify_page(page)) {
+ bio->bi_status = BLK_STS_IOERR;
+ break;
+ }
}
} else {
fsverity_verify_bio(bio);
@@ -245,6 +260,8 @@ static void f2fs_handle_step_decompress(struct bio_post_read_ctx *ctx,
blkaddr++;
}
+ ctx->decompression_attempted = true;
+
/*
* Optimization: if all the bio's pages are compressed, then scheduling
* the per-bio verity work is unnecessary, as verity will be fully
@@ -1062,6 +1079,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
ctx->sbi = sbi;
ctx->enabled_steps = post_read_steps;
ctx->fs_blkaddr = blkaddr;
+ ctx->decompression_attempted = false;
bio->bi_private = ctx;
}
iostat_alloc_and_bind_ctx(sbi, bio, ctx);
@@ -1089,7 +1107,6 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
bio_put(bio);
return -EFAULT;
}
- ClearPageError(page);
inc_page_count(sbi, F2FS_RD_DATA);
f2fs_update_iostat(sbi, NULL, FS_DATA_READ_IO, F2FS_BLKSIZE);
__submit_bio(sbi, bio, DATA);
@@ -2141,7 +2158,6 @@ submit_and_realloc:
inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
f2fs_update_iostat(F2FS_I_SB(inode), NULL, FS_DATA_READ_IO,
F2FS_BLKSIZE);
- ClearPageError(page);
*last_block_in_bio = block_nr;
goto out;
out:
@@ -2289,7 +2305,6 @@ submit_and_realloc:
inc_page_count(sbi, F2FS_RD_DATA);
f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE);
- ClearPageError(page);
*last_block_in_bio = blkaddr;
}
@@ -2306,7 +2321,6 @@ out:
for (i = 0; i < cc->cluster_size; i++) {
if (cc->rpages[i]) {
ClearPageUptodate(cc->rpages[i]);
- ClearPageError(cc->rpages[i]);
unlock_page(cc->rpages[i]);
}
}
@@ -2403,7 +2417,6 @@ read_single_page:
#ifdef CONFIG_F2FS_FS_COMPRESSION
set_error_page:
#endif
- SetPageError(page);
zero_user_segment(page, 0, PAGE_SIZE);
unlock_page(page);
}
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 82cda1258227..83df6f6173d3 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1025,7 +1025,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
__setattr_copy(mnt_userns, inode, attr);
if (attr->ia_valid & ATTR_MODE) {
- err = posix_acl_chmod(mnt_userns, inode, f2fs_get_inode_mode(inode));
+ err = posix_acl_chmod(mnt_userns, dentry, f2fs_get_inode_mode(inode));
if (is_inode_flag_set(inode, FI_ACL_MODE)) {
if (!err)
@@ -1046,7 +1046,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const struct inode_operations f2fs_file_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
- .get_acl = f2fs_get_acl,
+ .get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
.fiemap = f2fs_fiemap,
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 4546e01b2ee0..536d332d9e2e 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -282,7 +282,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
/* let's select beginning hot/small space first in no_heap mode*/
if (f2fs_need_rand_seg(sbi))
- p->offset = prandom_u32_max(MAIN_SECS(sbi) * sbi->segs_per_sec);
+ p->offset = get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec);
else if (test_opt(sbi, NOHEAP) &&
(type == CURSEG_HOT_DATA || IS_NODESEG(type)))
p->offset = 0;
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index a389772fd212..c227113b0f26 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -1379,7 +1379,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
.tmpfile = f2fs_tmpfile,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
- .get_acl = f2fs_get_acl,
+ .get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
.fiemap = f2fs_fiemap,
@@ -1397,7 +1397,7 @@ const struct inode_operations f2fs_symlink_inode_operations = {
const struct inode_operations f2fs_special_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
- .get_acl = f2fs_get_acl,
+ .get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
};
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index acf3d3fa4363..b304692c0cf5 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2534,7 +2534,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
sanity_check_seg_type(sbi, seg_type);
if (f2fs_need_rand_seg(sbi))
- return prandom_u32_max(MAIN_SECS(sbi) * sbi->segs_per_sec);
+ return get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec);
/* if segs_per_sec is large than 1, we need to keep original policy. */
if (__is_large_section(sbi))
@@ -2588,7 +2588,7 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
curseg->alloc_type = LFS;
if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
curseg->fragment_remained_chunk =
- prandom_u32_max(sbi->max_fragment_chunk) + 1;
+ get_random_u32_inclusive(1, sbi->max_fragment_chunk);
}
static int __next_free_blkoff(struct f2fs_sb_info *sbi,
@@ -2625,9 +2625,9 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
/* To allocate block chunks in different sizes, use random number */
if (--seg->fragment_remained_chunk <= 0) {
seg->fragment_remained_chunk =
- prandom_u32_max(sbi->max_fragment_chunk) + 1;
+ get_random_u32_inclusive(1, sbi->max_fragment_chunk);
seg->next_blkoff +=
- prandom_u32_max(sbi->max_fragment_hole) + 1;
+ get_random_u32_inclusive(1, sbi->max_fragment_hole);
}
}
}
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c
index af191371c352..3626eb585a98 100644
--- a/fs/fat/nfs.c
+++ b/fs/fat/nfs.c
@@ -17,7 +17,7 @@ struct fat_fid {
#define FAT_FID_SIZE_WITHOUT_PARENT 3
#define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32))
-/**
+/*
* Look up a directory inode given its starting cluster.
*/
static struct inode *fat_dget(struct super_block *sb, int i_logstart)
@@ -135,7 +135,7 @@ fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp,
return type;
}
-/**
+/*
* Map a NFS file handle to a corresponding dentry.
* The dentry may or may not be connected to the filesystem root.
*/
diff --git a/fs/file.c b/fs/file.c
index 5f9c802a5d8d..c942c89ca4cd 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -1003,7 +1003,16 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask)
struct files_struct *files = current->files;
struct file *file;
- if (atomic_read(&files->count) == 1) {
+ /*
+ * If another thread is concurrently calling close_fd() followed
+ * by put_files_struct(), we must not observe the old table
+ * entry combined with the new refcount - otherwise we could
+ * return a file that is concurrently being freed.
+ *
+ * atomic_read_acquire() pairs with atomic_dec_and_test() in
+ * put_files_struct().
+ */
+ if (atomic_read_acquire(&files->count) == 1) {
file = files_lookup_fd_raw(files, fd);
if (!file || unlikely(file->f_mode & mask))
return 0;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 443f83382b9b..9958d4020771 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1712,18 +1712,26 @@ static int writeback_single_inode(struct inode *inode,
wb = inode_to_wb_and_lock_list(inode);
spin_lock(&inode->i_lock);
/*
- * If the inode is now fully clean, then it can be safely removed from
- * its writeback list (if any). Otherwise the flusher threads are
- * responsible for the writeback lists.
+ * If the inode is freeing, its i_io_list shoudn't be updated
+ * as it can be finally deleted at this moment.
*/
- if (!(inode->i_state & I_DIRTY_ALL))
- inode_cgwb_move_to_attached(inode, wb);
- else if (!(inode->i_state & I_SYNC_QUEUED)) {
- if ((inode->i_state & I_DIRTY))
- redirty_tail_locked(inode, wb);
- else if (inode->i_state & I_DIRTY_TIME) {
- inode->dirtied_when = jiffies;
- inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
+ if (!(inode->i_state & I_FREEING)) {
+ /*
+ * If the inode is now fully clean, then it can be safely
+ * removed from its writeback list (if any). Otherwise the
+ * flusher threads are responsible for the writeback lists.
+ */
+ if (!(inode->i_state & I_DIRTY_ALL))
+ inode_cgwb_move_to_attached(inode, wb);
+ else if (!(inode->i_state & I_SYNC_QUEUED)) {
+ if ((inode->i_state & I_DIRTY))
+ redirty_tail_locked(inode, wb);
+ else if (inode->i_state & I_DIRTY_TIME) {
+ inode->dirtied_when = jiffies;
+ inode_io_list_move_locked(inode,
+ wb,
+ &wb->b_dirty_time);
+ }
}
}
diff --git a/fs/fs_parser.c b/fs/fs_parser.c
index ed40ce5742fd..edb3712dcfa5 100644
--- a/fs/fs_parser.c
+++ b/fs/fs_parser.c
@@ -138,15 +138,16 @@ EXPORT_SYMBOL(__fs_parse);
* @fc: The filesystem context to log errors through.
* @param: The parameter.
* @want_bdev: T if want a blockdev
+ * @flags: Pathwalk flags passed to filename_lookup()
* @_path: The result of the lookup
*/
int fs_lookup_param(struct fs_context *fc,
struct fs_parameter *param,
bool want_bdev,
+ unsigned int flags,
struct path *_path)
{
struct filename *f;
- unsigned int flags = 0;
bool put_f;
int ret;
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index 451d8a077e12..bce2492186d0 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -605,6 +605,14 @@ again:
set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
queue = true;
}
+ /*
+ * We could race with cookie_lru which may set LRU_DISCARD bit
+ * but has yet to run the cookie state machine. If this happens
+ * and another thread tries to use the cookie, clear LRU_DISCARD
+ * so we don't end up withdrawing the cookie while in use.
+ */
+ if (test_and_clear_bit(FSCACHE_COOKIE_DO_LRU_DISCARD, &cookie->flags))
+ fscache_see_cookie(cookie, fscache_cookie_see_lru_discard_clear);
break;
case FSCACHE_COOKIE_STATE_FAILED:
diff --git a/fs/fscache/io.c b/fs/fscache/io.c
index 3af3b08a9bb3..0d2b8dec8f82 100644
--- a/fs/fscache/io.c
+++ b/fs/fscache/io.c
@@ -286,7 +286,7 @@ void __fscache_write_to_cache(struct fscache_cookie *cookie,
* taken into account.
*/
- iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len);
+ iov_iter_xarray(&iter, ITER_SOURCE, &mapping->i_pages, start, len);
fscache_write(cres, start, &iter, fscache_wreq_done, wreq);
return;
diff --git a/fs/fscache/volume.c b/fs/fscache/volume.c
index a058e0136bfe..ab8ceddf9efa 100644
--- a/fs/fscache/volume.c
+++ b/fs/fscache/volume.c
@@ -203,7 +203,11 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
struct fscache_volume *volume;
struct fscache_cache *cache;
size_t klen, hlen;
- char *key;
+ u8 *key;
+
+ klen = strlen(volume_key);
+ if (klen > NAME_MAX)
+ return NULL;
if (!coherency_data)
coherency_len = 0;
@@ -229,7 +233,6 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
/* Stick the length on the front of the key and pad it out to make
* hashing easier.
*/
- klen = strlen(volume_key);
hlen = round_up(1 + klen + 1, sizeof(__le32));
key = kzalloc(hlen, GFP_KERNEL);
if (!key)
diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c
index 337cb29a8dd5..a4850aee2639 100644
--- a/fs/fuse/acl.c
+++ b/fs/fuse/acl.c
@@ -53,9 +53,10 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu)
return acl;
}
-int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
+ struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
const char *name;
int ret;
@@ -98,7 +99,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
return ret;
}
- if (!in_group_p(i_gid_into_mnt(&init_user_ns, inode)) &&
+ if (!vfsgid_in_group_p(i_gid_into_vfsgid(&init_user_ns, inode)) &&
!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID))
extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index c7d882a9fe33..a06fbb1a8a5b 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -545,7 +545,6 @@ static int cuse_channel_release(struct inode *inode, struct file *file)
{
struct fuse_dev *fud = file->private_data;
struct cuse_conn *cc = fc_to_cc(fud->fc);
- int rc;
/* remove from the conntbl, no more access from this point on */
mutex_lock(&cuse_lock);
@@ -560,9 +559,7 @@ static int cuse_channel_release(struct inode *inode, struct file *file)
cdev_del(cc->cdev);
}
- rc = fuse_dev_release(inode, file); /* puts the base reference */
-
- return rc;
+ return fuse_dev_release(inode, file);
}
static struct file_operations cuse_channel_fops; /* initialized during init */
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index b4a6e0a1b945..c73d9c4132f6 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1498,7 +1498,7 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
buf[outarg.namelen] = 0;
down_read(&fc->killsb);
- err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name);
+ err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags);
up_read(&fc->killsb);
kfree(buf);
return err;
@@ -1546,7 +1546,7 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
buf[outarg.namelen] = 0;
down_read(&fc->killsb);
- err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name);
+ err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0);
up_read(&fc->killsb);
kfree(buf);
return err;
@@ -2267,8 +2267,7 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
* Check against file->f_op because CUSE
* uses the same ioctl handler.
*/
- if (old->f_op == file->f_op &&
- old->f_cred->user_ns == file->f_cred->user_ns)
+ if (old->f_op == file->f_op)
fud = fuse_get_dev(old);
if (fud) {
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index bb97a384dc5d..cd1a071b625a 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -214,7 +214,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
if (inode && fuse_is_bad(inode))
goto invalid;
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
- (flags & (LOOKUP_EXCL | LOOKUP_REVAL))) {
+ (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) {
struct fuse_entry_out outarg;
FUSE_ARGS(args);
struct fuse_forget_link *forget;
@@ -1170,7 +1170,7 @@ int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
}
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
- u64 child_nodeid, struct qstr *name)
+ u64 child_nodeid, struct qstr *name, u32 flags)
{
int err = -ENOTDIR;
struct inode *parent;
@@ -1197,7 +1197,9 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
goto unlock;
fuse_dir_changed(parent);
- fuse_invalidate_entry(entry);
+ if (!(flags & FUSE_EXPIRE_ONLY))
+ d_invalidate(entry);
+ fuse_invalidate_entry_cache(entry);
if (child_nodeid != 0 && d_really_is_positive(entry)) {
inode_lock(d_inode(entry));
@@ -1235,6 +1237,18 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
return err;
}
+static inline bool fuse_permissible_uidgid(struct fuse_conn *fc)
+{
+ const struct cred *cred = current_cred();
+
+ return (uid_eq(cred->euid, fc->user_id) &&
+ uid_eq(cred->suid, fc->user_id) &&
+ uid_eq(cred->uid, fc->user_id) &&
+ gid_eq(cred->egid, fc->group_id) &&
+ gid_eq(cred->sgid, fc->group_id) &&
+ gid_eq(cred->gid, fc->group_id));
+}
+
/*
* Calling into a user-controlled filesystem gives the filesystem
* daemon ptrace-like capabilities over the current process. This
@@ -1248,26 +1262,19 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
* for which the owner of the mount has ptrace privilege. This
* excludes processes started by other users, suid or sgid processes.
*/
-int fuse_allow_current_process(struct fuse_conn *fc)
+bool fuse_allow_current_process(struct fuse_conn *fc)
{
- const struct cred *cred;
-
- if (allow_sys_admin_access && capable(CAP_SYS_ADMIN))
- return 1;
+ bool allow;
if (fc->allow_other)
- return current_in_userns(fc->user_ns);
+ allow = current_in_userns(fc->user_ns);
+ else
+ allow = fuse_permissible_uidgid(fc);
- cred = current_cred();
- if (uid_eq(cred->euid, fc->user_id) &&
- uid_eq(cred->suid, fc->user_id) &&
- uid_eq(cred->uid, fc->user_id) &&
- gid_eq(cred->egid, fc->group_id) &&
- gid_eq(cred->sgid, fc->group_id) &&
- gid_eq(cred->gid, fc->group_id))
- return 1;
+ if (!allow && allow_sys_admin_access && capable(CAP_SYS_ADMIN))
+ allow = true;
- return 0;
+ return allow;
}
static int fuse_access(struct inode *inode, int mask)
@@ -1935,7 +1942,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.permission = fuse_permission,
.getattr = fuse_getattr,
.listxattr = fuse_listxattr,
- .get_acl = fuse_get_acl,
+ .get_inode_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
.fileattr_get = fuse_fileattr_get,
.fileattr_set = fuse_fileattr_set,
@@ -1957,7 +1964,7 @@ static const struct inode_operations fuse_common_inode_operations = {
.permission = fuse_permission,
.getattr = fuse_getattr,
.listxattr = fuse_listxattr,
- .get_acl = fuse_get_acl,
+ .get_inode_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
.fileattr_get = fuse_fileattr_get,
.fileattr_set = fuse_fileattr_set,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 71bfb663aac5..875314ee6f59 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1313,7 +1313,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
return err;
if (fc->handle_killpriv_v2 &&
- should_remove_suid(file_dentry(file))) {
+ setattr_should_drop_suidgid(&init_user_ns, file_inode(file))) {
goto writethrough;
}
@@ -1563,14 +1563,47 @@ static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
return res;
}
+static bool fuse_direct_write_extending_i_size(struct kiocb *iocb,
+ struct iov_iter *iter)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+
+ return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
+}
+
static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
+ struct file *file = iocb->ki_filp;
+ struct fuse_file *ff = file->private_data;
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
ssize_t res;
+ bool exclusive_lock =
+ !(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
+ iocb->ki_flags & IOCB_APPEND ||
+ fuse_direct_write_extending_i_size(iocb, from);
+
+ /*
+ * Take exclusive lock if
+ * - Parallel direct writes are disabled - a user space decision
+ * - Parallel direct writes are enabled and i_size is being extended.
+ * This might not be needed at all, but needs further investigation.
+ */
+ if (exclusive_lock)
+ inode_lock(inode);
+ else {
+ inode_lock_shared(inode);
+
+ /* A race with truncate might have come up as the decision for
+ * the lock type was done without holding the lock, check again.
+ */
+ if (fuse_direct_write_extending_i_size(iocb, from)) {
+ inode_unlock_shared(inode);
+ inode_lock(inode);
+ exclusive_lock = true;
+ }
+ }
- /* Don't allow parallel writes to the same file */
- inode_lock(inode);
res = generic_write_checks(iocb, from);
if (res > 0) {
if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
@@ -1581,7 +1614,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
fuse_write_update_attr(inode, iocb->ki_pos, res);
}
}
- inode_unlock(inode);
+ if (exclusive_lock)
+ inode_unlock(inode);
+ else
+ inode_unlock_shared(inode);
return res;
}
@@ -2931,6 +2967,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
if (iov_iter_rw(iter) == WRITE) {
fuse_write_update_attr(inode, pos, ret);
+ /* For extending writes we already hold exclusive lock */
if (ret < 0 && offset + count > i_size)
fuse_do_truncate(file);
}
@@ -2963,11 +3000,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
.mode = mode
};
int err;
- bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
- (mode & (FALLOC_FL_PUNCH_HOLE |
- FALLOC_FL_ZERO_RANGE));
-
- bool block_faults = FUSE_IS_DAX(inode) && lock_inode;
+ bool block_faults = FUSE_IS_DAX(inode) &&
+ (!(mode & FALLOC_FL_KEEP_SIZE) ||
+ (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)));
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_ZERO_RANGE))
@@ -2976,22 +3011,20 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
if (fm->fc->no_fallocate)
return -EOPNOTSUPP;
- if (lock_inode) {
- inode_lock(inode);
- if (block_faults) {
- filemap_invalidate_lock(inode->i_mapping);
- err = fuse_dax_break_layouts(inode, 0, 0);
- if (err)
- goto out;
- }
+ inode_lock(inode);
+ if (block_faults) {
+ filemap_invalidate_lock(inode->i_mapping);
+ err = fuse_dax_break_layouts(inode, 0, 0);
+ if (err)
+ goto out;
+ }
- if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
- loff_t endbyte = offset + length - 1;
+ if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
+ loff_t endbyte = offset + length - 1;
- err = fuse_writeback_range(inode, offset, endbyte);
- if (err)
- goto out;
- }
+ err = fuse_writeback_range(inode, offset, endbyte);
+ if (err)
+ goto out;
}
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
@@ -3039,8 +3072,7 @@ out:
if (block_faults)
filemap_invalidate_unlock(inode->i_mapping);
- if (lock_inode)
- inode_unlock(inode);
+ inode_unlock(inode);
fuse_flush_time_update(inode);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 98a9cf531873..c673faefdcb9 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1179,7 +1179,7 @@ bool fuse_invalid_attr(struct fuse_attr *attr);
/**
* Is current process allowed to perform filesystem operation?
*/
-int fuse_allow_current_process(struct fuse_conn *fc);
+bool fuse_allow_current_process(struct fuse_conn *fc);
u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
@@ -1220,7 +1220,7 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
* then the dentry is unhashed (d_delete()).
*/
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
- u64 child_nodeid, struct qstr *name);
+ u64 child_nodeid, struct qstr *name, u32 flags);
int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
bool isdir);
@@ -1269,7 +1269,7 @@ extern const struct xattr_handler *fuse_no_acl_xattr_handlers[];
struct posix_acl;
struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu);
-int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
/* readdir.c */
diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c
index 61d8afcb10a3..fcce94ace2c2 100644
--- a/fs/fuse/ioctl.c
+++ b/fs/fuse/ioctl.c
@@ -255,7 +255,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
ap.args.in_pages = true;
err = -EFAULT;
- iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size);
+ iov_iter_init(&ii, ITER_SOURCE, in_iov, in_iovs, in_size);
for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
if (c != PAGE_SIZE && iov_iter_count(&ii))
@@ -324,7 +324,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
goto out;
err = -EFAULT;
- iov_iter_init(&ii, READ, out_iov, out_iovs, transferred);
+ iov_iter_init(&ii, ITER_DEST, out_iov, out_iovs, transferred);
for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
if (c != PAGE_SIZE && iov_iter_count(&ii))
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index e8deaacf1832..dc603479b30e 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -547,9 +547,9 @@ retry_locked:
* Contents of the page are now protected against changing by holding
* the page lock.
*/
- addr = kmap(page);
+ addr = kmap_local_page(page);
res = fuse_parse_cache(ff, addr, size, ctx);
- kunmap(page);
+ kunmap_local(addr);
unlock_page(page);
put_page(page);
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 734d1f05d823..3dcde4912413 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -109,9 +109,10 @@ out:
return error;
}
-int gfs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int gfs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
+ struct inode *inode = d_inode(dentry);
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
bool need_unlock = false;
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
index cd180ca7c959..b8de8c148f5c 100644
--- a/fs/gfs2/acl.h
+++ b/fs/gfs2/acl.h
@@ -13,7 +13,7 @@
extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type, bool rcu);
extern int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int gfs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+extern int gfs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
#endif /* __ACL_DOT_H__ */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 04a201584fa7..1371e067d2a7 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1997,7 +1997,7 @@ static int gfs2_setattr(struct user_namespace *mnt_userns,
else {
error = gfs2_setattr_simple(inode, attr);
if (!error && attr->ia_valid & ATTR_MODE)
- error = posix_acl_chmod(&init_user_ns, inode,
+ error = posix_acl_chmod(&init_user_ns, dentry,
inode->i_mode);
}
@@ -2149,7 +2149,7 @@ static const struct inode_operations gfs2_file_iops = {
.getattr = gfs2_getattr,
.listxattr = gfs2_listxattr,
.fiemap = gfs2_fiemap,
- .get_acl = gfs2_get_acl,
+ .get_inode_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
.update_time = gfs2_update_time,
.fileattr_get = gfs2_fileattr_get,
@@ -2171,7 +2171,7 @@ static const struct inode_operations gfs2_dir_iops = {
.getattr = gfs2_getattr,
.listxattr = gfs2_listxattr,
.fiemap = gfs2_fiemap,
- .get_acl = gfs2_get_acl,
+ .get_inode_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
.update_time = gfs2_update_time,
.atomic_open = gfs2_atomic_open,
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index c4526f16355d..a0746be3c1de 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -458,6 +458,8 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
/* panic? */
return -EIO;
+ if (HFS_I(main_inode)->cat_key.CName.len > HFS_NAMELEN)
+ return -EIO;
fd.search_key->cat = HFS_I(main_inode)->cat_key;
if (hfs_brec_find(&fd))
/* panic? */
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c
index 39f5e343bf4d..fdb0edb8a607 100644
--- a/fs/hfs/trans.c
+++ b/fs/hfs/trans.c
@@ -109,7 +109,7 @@ void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, const struct qstr
if (nls_io) {
wchar_t ch;
- while (srclen > 0) {
+ while (srclen > 0 && dstlen > 0) {
size = nls_io->char2uni(src, srclen, &ch);
if (size < 0) {
ch = '?';
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index a5db2e3b2980..6aa919e59483 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -198,6 +198,8 @@ struct hfsplus_sb_info {
#define HFSPLUS_SB_HFSX 3
#define HFSPLUS_SB_CASEFOLD 4
#define HFSPLUS_SB_NOBARRIER 5
+#define HFSPLUS_SB_UID 6
+#define HFSPLUS_SB_GID 7
static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
{
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index aeab83ed1c9c..b675581aa9d0 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -192,11 +192,11 @@ static void hfsplus_get_perms(struct inode *inode,
mode = be16_to_cpu(perms->mode);
i_uid_write(inode, be32_to_cpu(perms->owner));
- if (!i_uid_read(inode) && !mode)
+ if ((test_bit(HFSPLUS_SB_UID, &sbi->flags)) || (!i_uid_read(inode) && !mode))
inode->i_uid = sbi->uid;
i_gid_write(inode, be32_to_cpu(perms->group));
- if (!i_gid_read(inode) && !mode)
+ if ((test_bit(HFSPLUS_SB_GID, &sbi->flags)) || (!i_gid_read(inode) && !mode))
inode->i_gid = sbi->gid;
if (dir) {
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 047e05c57560..c94a58762ad6 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -140,6 +140,8 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
if (!uid_valid(sbi->uid)) {
pr_err("invalid uid specified\n");
return 0;
+ } else {
+ set_bit(HFSPLUS_SB_UID, &sbi->flags);
}
break;
case opt_gid:
@@ -151,6 +153,8 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
if (!gid_valid(sbi->gid)) {
pr_err("invalid gid specified\n");
return 0;
+ } else {
+ set_bit(HFSPLUS_SB_GID, &sbi->flags);
}
break;
case opt_part:
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index dd54f67e47fd..df7772335dc0 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -328,6 +328,12 @@ static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
} else {
unlock_page(page);
+ if (PageHWPoison(page)) {
+ put_page(page);
+ retval = -EIO;
+ break;
+ }
+
/*
* We have the page, copy it to user space buffer.
*/
@@ -1111,13 +1117,6 @@ static int hugetlbfs_migrate_folio(struct address_space *mapping,
static int hugetlbfs_error_remove_page(struct address_space *mapping,
struct page *page)
{
- struct inode *inode = mapping->host;
- pgoff_t index = page->index;
-
- hugetlb_delete_from_page_cache(page);
- if (unlikely(hugetlb_unreserve_pages(inode, index, index + 1, 1)))
- hugetlb_fix_reserve_counts(inode);
-
return 0;
}
diff --git a/fs/inode.c b/fs/inode.c
index b608528efd3a..f453eb58fd03 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1949,40 +1949,12 @@ skip_update:
EXPORT_SYMBOL(touch_atime);
/*
- * The logic we want is
- *
- * if suid or (sgid and xgrp)
- * remove privs
- */
-int should_remove_suid(struct dentry *dentry)
-{
- umode_t mode = d_inode(dentry)->i_mode;
- int kill = 0;
-
- /* suid always must be killed */
- if (unlikely(mode & S_ISUID))
- kill = ATTR_KILL_SUID;
-
- /*
- * sgid without any exec bits is just a mandatory locking mark; leave
- * it alone. If some exec bits are set, it's a real sgid; kill it.
- */
- if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
- kill |= ATTR_KILL_SGID;
-
- if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
- return kill;
-
- return 0;
-}
-EXPORT_SYMBOL(should_remove_suid);
-
-/*
* Return mask of changes for notify_change() that need to be done as a
* response to write or truncate. Return 0 if nothing has to be changed.
* Negative value on error (change should be denied).
*/
-int dentry_needs_remove_privs(struct dentry *dentry)
+int dentry_needs_remove_privs(struct user_namespace *mnt_userns,
+ struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
int mask = 0;
@@ -1991,7 +1963,7 @@ int dentry_needs_remove_privs(struct dentry *dentry)
if (IS_NOSEC(inode))
return 0;
- mask = should_remove_suid(dentry);
+ mask = setattr_should_drop_suidgid(mnt_userns, inode);
ret = security_inode_need_killpriv(dentry);
if (ret < 0)
return ret;
@@ -2023,7 +1995,7 @@ static int __file_remove_privs(struct file *file, unsigned int flags)
if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
return 0;
- kill = dentry_needs_remove_privs(dentry);
+ kill = dentry_needs_remove_privs(file_mnt_user_ns(file), dentry);
if (kill < 0)
return kill;
@@ -2071,9 +2043,6 @@ static int inode_needs_update_time(struct inode *inode, struct timespec64 *now)
if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
sync_it |= S_VERSION;
- if (!sync_it)
- return 0;
-
return sync_it;
}
@@ -2354,15 +2323,15 @@ EXPORT_SYMBOL(inode_init_owner);
bool inode_owner_or_capable(struct user_namespace *mnt_userns,
const struct inode *inode)
{
- kuid_t i_uid;
+ vfsuid_t vfsuid;
struct user_namespace *ns;
- i_uid = i_uid_into_mnt(mnt_userns, inode);
- if (uid_eq(current_fsuid(), i_uid))
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
return true;
ns = current_user_ns();
- if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER))
+ if (vfsuid_has_mapping(ns, vfsuid) && ns_capable(ns, CAP_FOWNER))
return true;
return false;
}
@@ -2488,6 +2457,28 @@ struct timespec64 current_time(struct inode *inode)
EXPORT_SYMBOL(current_time);
/**
+ * in_group_or_capable - check whether caller is CAP_FSETID privileged
+ * @mnt_userns: user namespace of the mount @inode was found from
+ * @inode: inode to check
+ * @vfsgid: the new/current vfsgid of @inode
+ *
+ * Check wether @vfsgid is in the caller's group list or if the caller is
+ * privileged with CAP_FSETID over @inode. This can be used to determine
+ * whether the setgid bit can be kept or must be dropped.
+ *
+ * Return: true if the caller is sufficiently privileged, false if not.
+ */
+bool in_group_or_capable(struct user_namespace *mnt_userns,
+ const struct inode *inode, vfsgid_t vfsgid)
+{
+ if (vfsgid_in_group_p(vfsgid))
+ return true;
+ if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
+ return true;
+ return false;
+}
+
+/**
* mode_strip_sgid - handle the sgid bit for non-directories
* @mnt_userns: User namespace of the mount the inode was created from
* @dir: parent directory inode
@@ -2508,11 +2499,9 @@ umode_t mode_strip_sgid(struct user_namespace *mnt_userns,
return mode;
if (S_ISDIR(mode) || !dir || !(dir->i_mode & S_ISGID))
return mode;
- if (in_group_p(i_gid_into_mnt(mnt_userns, dir)))
- return mode;
- if (capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
+ if (in_group_or_capable(mnt_userns, dir,
+ i_gid_into_vfsgid(mnt_userns, dir)))
return mode;
-
return mode & ~S_ISGID;
}
EXPORT_SYMBOL(mode_strip_sgid);
diff --git a/fs/internal.h b/fs/internal.h
index 6f0386b34fae..a803cc3cf716 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -150,7 +150,9 @@ extern int vfs_open(const struct path *, struct file *);
* inode.c
*/
extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
-extern int dentry_needs_remove_privs(struct dentry *dentry);
+int dentry_needs_remove_privs(struct user_namespace *, struct dentry *dentry);
+bool in_group_or_capable(struct user_namespace *mnt_userns,
+ const struct inode *inode, vfsgid_t vfsgid);
/*
* fs-writeback.c
@@ -225,12 +227,39 @@ struct xattr_ctx {
};
-ssize_t do_getxattr(struct user_namespace *mnt_userns,
+ssize_t do_getxattr(struct mnt_idmap *idmap,
struct dentry *d,
struct xattr_ctx *ctx);
int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
-int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct xattr_ctx *ctx);
+int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode);
+
+#ifdef CONFIG_FS_POSIX_ACL
+int do_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, const void *kvalue, size_t size);
+ssize_t do_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, void *kvalue, size_t size);
+#else
+static inline int do_set_acl(struct mnt_idmap *idmap,
+ struct dentry *dentry, const char *acl_name,
+ const void *kvalue, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+static inline ssize_t do_get_acl(struct mnt_idmap *idmap,
+ struct dentry *dentry, const char *acl_name,
+ void *kvalue, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+#endif
ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos);
+
+/*
+ * fs/attr.c
+ */
+int setattr_should_drop_sgid(struct user_namespace *mnt_userns,
+ const struct inode *inode);
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 4eb559a16c9e..9804714b1751 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -240,7 +240,6 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
{
const struct iomap *iomap = &iter->iomap;
struct inode *inode = iter->inode;
- unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
unsigned int fs_block_size = i_blocksize(inode), pad;
loff_t length = iomap_length(iter);
loff_t pos = iter->pos;
@@ -252,7 +251,7 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
size_t copied = 0;
size_t orig_count;
- if ((pos | length) & ((1 << blkbits) - 1) ||
+ if ((pos | length) & (bdev_logical_block_size(iomap->bdev) - 1) ||
!bdev_iter_is_aligned(iomap->bdev, dio->submit.iter))
return -EINVAL;
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 885a7a6cc53e..4810438b7856 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -207,14 +207,13 @@ int jbd2_journal_submit_inode_data_buffers(struct jbd2_inode *jinode)
}
/* Send all the data buffers related to an inode */
-int jbd2_submit_inode_data(struct jbd2_inode *jinode)
+int jbd2_submit_inode_data(journal_t *journal, struct jbd2_inode *jinode)
{
-
if (!jinode || !(jinode->i_flags & JI_WRITE_DATA))
return 0;
trace_jbd2_submit_inode_data(jinode->i_vfs_inode);
- return jbd2_journal_submit_inode_data_buffers(jinode);
+ return journal->j_submit_inode_data_buffers(jinode);
}
EXPORT_SYMBOL(jbd2_submit_inode_data);
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index e945e3484788..8bb58ce5c06c 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -229,10 +229,11 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a
return rc;
}
-int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int jffs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int rc, xprefix;
+ struct inode *inode = d_inode(dentry);
switch (type) {
case ACL_TYPE_ACCESS:
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index 9d9fb7cf093e..ca36a6eca594 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -28,7 +28,7 @@ struct jffs2_acl_header {
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
struct posix_acl *jffs2_get_acl(struct inode *inode, int type, bool rcu);
-int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int jffs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *);
extern int jffs2_init_acl_post(struct inode *);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c0aabbcbfd58..f399b390b5f6 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -62,7 +62,7 @@ const struct inode_operations jffs2_dir_inode_operations =
.rmdir = jffs2_rmdir,
.mknod = jffs2_mknod,
.rename = jffs2_rename,
- .get_acl = jffs2_get_acl,
+ .get_inode_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
.listxattr = jffs2_listxattr,
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index ba86acbe12d3..3cf71befa475 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -64,7 +64,7 @@ const struct file_operations jffs2_file_operations =
const struct inode_operations jffs2_file_inode_operations =
{
- .get_acl = jffs2_get_acl,
+ .get_inode_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
.listxattr = jffs2_listxattr,
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 39cec28096a7..66af51c41619 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -202,7 +202,7 @@ int jffs2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
rc = jffs2_do_setattr(inode, iattr);
if (!rc && (iattr->ia_valid & ATTR_MODE))
- rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
+ rc = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
return rc;
}
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index a653f34c6e26..3b667eccc73b 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -94,12 +94,13 @@ out:
return rc;
}
-int jfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int jfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int rc;
tid_t tid;
int update_mode = 0;
+ struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
tid = txBegin(inode->i_sb, 0);
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 332dc9ac47a9..88663465aecd 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -123,7 +123,7 @@ int jfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE)
- rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
+ rc = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
return rc;
}
@@ -133,7 +133,7 @@ const struct inode_operations jfs_file_inode_operations = {
.fileattr_get = jfs_fileattr_get,
.fileattr_set = jfs_fileattr_set,
#ifdef CONFIG_JFS_POSIX_ACL
- .get_acl = jfs_get_acl,
+ .get_inode_acl = jfs_get_acl,
.set_acl = jfs_set_acl,
#endif
};
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index 3de40286d31f..f0704a25835f 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -8,7 +8,7 @@
#ifdef CONFIG_JFS_POSIX_ACL
struct posix_acl *jfs_get_acl(struct inode *inode, int type, bool rcu);
-int jfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int jfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int jfs_init_acl(tid_t, struct inode *, struct inode *);
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 6b838d3ae7c2..765838578a72 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -155,7 +155,7 @@ int dbMount(struct inode *ipbmap)
struct bmap *bmp;
struct dbmap_disk *dbmp_le;
struct metapage *mp;
- int i;
+ int i, err;
/*
* allocate/initialize the in-memory bmap descriptor
@@ -170,8 +170,8 @@ int dbMount(struct inode *ipbmap)
BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
PSIZE, 0);
if (mp == NULL) {
- kfree(bmp);
- return -EIO;
+ err = -EIO;
+ goto err_kfree_bmp;
}
/* copy the on-disk bmap descriptor to its in-memory version. */
@@ -181,9 +181,8 @@ int dbMount(struct inode *ipbmap)
bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
if (!bmp->db_numag) {
- release_metapage(mp);
- kfree(bmp);
- return -EINVAL;
+ err = -EINVAL;
+ goto err_release_metapage;
}
bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
@@ -194,6 +193,16 @@ int dbMount(struct inode *ipbmap)
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
+ if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) {
+ err = -EINVAL;
+ goto err_release_metapage;
+ }
+
+ if (((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) {
+ err = -EINVAL;
+ goto err_release_metapage;
+ }
+
for (i = 0; i < MAXAG; i++)
bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]);
bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize);
@@ -214,6 +223,12 @@ int dbMount(struct inode *ipbmap)
BMAP_LOCK_INIT(bmp);
return (0);
+
+err_release_metapage:
+ release_metapage(mp);
+err_kfree_bmp:
+ kfree(bmp);
+ return err;
}
diff --git a/fs/jfs/jfs_extent.h b/fs/jfs/jfs_extent.h
index 1c984214e95e..a0ee4ccea66e 100644
--- a/fs/jfs/jfs_extent.h
+++ b/fs/jfs/jfs_extent.h
@@ -10,9 +10,7 @@
(addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1)
extern int extAlloc(struct inode *, s64, s64, xad_t *, bool);
-extern int extFill(struct inode *, xad_t *);
extern int extHint(struct inode *, s64, xad_t *);
-extern int extRealloc(struct inode *, s64, xad_t *, bool);
extern int extRecord(struct inode *, xad_t *);
#endif /* _H_JFS_EXTENT */
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index 799d3837e7c2..390cbfce391f 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -310,8 +310,8 @@ int diRead(struct inode *ip)
iagno = INOTOIAG(ip->i_ino);
/* read the iag */
- imap = JFS_IP(ipimap)->i_imap;
IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
+ imap = JFS_IP(ipimap)->i_imap;
rc = diIAGRead(imap, iagno, &mp);
IREAD_UNLOCK(ipimap);
if (rc) {
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 48d1f70f786c..b83aae56a1f2 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -234,11 +234,15 @@ int jfs_mount_rw(struct super_block *sb, int remount)
truncate_inode_pages(sbi->ipimap->i_mapping, 0);
truncate_inode_pages(sbi->ipbmap->i_mapping, 0);
+
+ IWRITE_LOCK(sbi->ipimap, RDWRLOCK_IMAP);
diUnmount(sbi->ipimap, 1);
if ((rc = diMount(sbi->ipimap))) {
+ IWRITE_UNLOCK(sbi->ipimap);
jfs_err("jfs_mount_rw: diMount failed!");
return rc;
}
+ IWRITE_UNLOCK(sbi->ipimap);
dbUnmount(sbi->ipbmap, 1);
if ((rc = dbMount(sbi->ipbmap))) {
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 3e8b13e6aa01..8ec43f53f686 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -68,7 +68,6 @@ int jfs_umount(struct super_block *sb)
/*
* close secondary aggregate inode allocation map
*/
- ipaimap2 = sbi->ipaimap2;
if (ipaimap2) {
diUnmount(ipaimap2, 0);
diFreeSpecial(ipaimap2);
@@ -78,7 +77,6 @@ int jfs_umount(struct super_block *sb)
/*
* close aggregate inode allocation map
*/
- ipaimap = sbi->ipaimap;
diUnmount(ipaimap, 0);
diFreeSpecial(ipaimap);
sbi->ipaimap = NULL;
@@ -89,7 +87,7 @@ int jfs_umount(struct super_block *sb)
dbUnmount(ipbmap, 0);
diFreeSpecial(ipbmap);
- sbi->ipimap = NULL;
+ sbi->ipbmap = NULL;
/*
* Make sure all metadata makes it to disk before we mark
diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
index c50167a7bc50..0d33816d251d 100644
--- a/fs/jfs/jfs_xattr.h
+++ b/fs/jfs/jfs_xattr.h
@@ -25,7 +25,7 @@ struct jfs_ea_list {
struct jfs_ea ea[]; /* Variable length list */
};
-/* Macros for defining maxiumum number of bytes supported for EAs */
+/* Macros for defining maximum number of bytes supported for EAs */
#define MAXEASIZE 65535
#define MAXEALISTSIZE MAXEASIZE
diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
index 142caafc73b1..ad7592191d76 100644
--- a/fs/jfs/jfs_xtree.h
+++ b/fs/jfs/jfs_xtree.h
@@ -96,12 +96,8 @@ extern int xtInsert(tid_t tid, struct inode *ip,
extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen,
int flag);
extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad);
-extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen,
- int flag);
extern s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int type);
extern s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size);
-extern int xtRelocate(tid_t tid, struct inode *ip,
- xad_t * oxad, s64 nxaddr, int xtype);
extern int xtAppend(tid_t tid,
struct inode *ip, int xflag, s64 xoff, int maxblocks,
int *xlenp, s64 * xaddrp, int flag);
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 9db4f5789c0e..a38d14eed047 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -946,7 +946,7 @@ static int jfs_symlink(struct user_namespace *mnt_userns, struct inode *dip,
if (ssize <= IDATASIZE) {
ip->i_op = &jfs_fast_symlink_inode_operations;
- ip->i_link = JFS_IP(ip)->i_inline;
+ ip->i_link = JFS_IP(ip)->i_inline_all;
memcpy(ip->i_link, name, ssize);
ip->i_size = ssize - 1;
@@ -1525,7 +1525,7 @@ const struct inode_operations jfs_dir_inode_operations = {
.fileattr_get = jfs_fileattr_get,
.fileattr_set = jfs_fileattr_set,
#ifdef CONFIG_JFS_POSIX_ACL
- .get_acl = jfs_get_acl,
+ .get_inode_acl = jfs_get_acl,
.set_acl = jfs_set_acl,
#endif
};
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 85d4f44f2ac4..d2f82cb7db1b 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -745,8 +745,7 @@ static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
len = i_size-off;
toread = len;
while (toread > 0) {
- tocopy = sb->s_blocksize - offset < toread ?
- sb->s_blocksize - offset : toread;
+ tocopy = min_t(size_t, sb->s_blocksize - offset, toread);
tmp_bh.b_state = 0;
tmp_bh.b_size = i_blocksize(inode);
@@ -785,8 +784,7 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type,
inode_lock(inode);
while (towrite > 0) {
- tocopy = sb->s_blocksize - offset < towrite ?
- sb->s_blocksize - offset : towrite;
+ tocopy = min_t(size_t, sb->s_blocksize - offset, towrite);
tmp_bh.b_state = 0;
tmp_bh.b_size = i_blocksize(inode);
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 3990f3e270cb..f33b3baad07c 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -31,10 +31,15 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */
#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
+static bool __kernfs_active(struct kernfs_node *kn)
+{
+ return atomic_read(&kn->active) >= 0;
+}
+
static bool kernfs_active(struct kernfs_node *kn)
{
lockdep_assert_held(&kernfs_root(kn)->kernfs_rwsem);
- return atomic_read(&kn->active) >= 0;
+ return __kernfs_active(kn);
}
static bool kernfs_lockdep(struct kernfs_node *kn)
@@ -705,7 +710,12 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
goto err_unlock;
}
- if (unlikely(!kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
+ /*
+ * We should fail if @kn has never been activated and guarantee success
+ * if the caller knows that @kn is active. Both can be achieved by
+ * __kernfs_active() which tests @kn->active without kernfs_rwsem.
+ */
+ if (unlikely(!__kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
goto err_unlock;
spin_unlock(&kernfs_idr_lock);
diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
index b2fc85d440d0..9306e10753f9 100644
--- a/fs/ksmbd/smb2pdu.c
+++ b/fs/ksmbd/smb2pdu.c
@@ -2487,9 +2487,9 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr,
fattr->cf_dacls = NULL;
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
- fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS);
+ fattr->cf_acls = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (S_ISDIR(inode->i_mode))
- fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT);
+ fattr->cf_dacls = get_inode_acl(inode, ACL_TYPE_DEFAULT);
}
}
@@ -2956,7 +2956,7 @@ int smb2_open(struct ksmbd_work *work)
struct inode *inode = d_inode(path.dentry);
posix_acl_rc = ksmbd_vfs_inherit_posix_acl(user_ns,
- inode,
+ path.dentry,
d_inode(path.dentry->d_parent));
if (posix_acl_rc)
ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
@@ -2972,7 +2972,7 @@ int smb2_open(struct ksmbd_work *work)
if (rc) {
if (posix_acl_rc)
ksmbd_vfs_set_init_posix_acl(user_ns,
- inode);
+ path.dentry);
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_ACL_XATTR)) {
diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c
index b05ff9b146b5..ab5c68cc0e13 100644
--- a/fs/ksmbd/smbacl.c
+++ b/fs/ksmbd/smbacl.c
@@ -1289,7 +1289,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
}
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
- posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
+ posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
if (posix_acls && !found) {
unsigned int id = -1;
@@ -1386,14 +1386,14 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry);
/* Update posix acls */
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
- rc = set_posix_acl(user_ns, inode,
+ rc = set_posix_acl(user_ns, path->dentry,
ACL_TYPE_ACCESS, fattr.cf_acls);
if (rc < 0)
ksmbd_debug(SMB,
"Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) {
- rc = set_posix_acl(user_ns, inode,
+ rc = set_posix_acl(user_ns, path->dentry,
ACL_TYPE_DEFAULT, fattr.cf_dacls);
if (rc)
ksmbd_debug(SMB,
diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
index 8de970d6146f..ff0e7a4fcd4d 100644
--- a/fs/ksmbd/vfs.c
+++ b/fs/ksmbd/vfs.c
@@ -321,7 +321,7 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,
unsigned char type)
{
struct file_lock *flock;
- struct file_lock_context *ctx = file_inode(filp)->i_flctx;
+ struct file_lock_context *ctx = locks_inode_context(file_inode(filp));
int error = 0;
if (!ctx || list_empty_careful(&ctx->flc_posix))
@@ -1321,7 +1321,7 @@ int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||
!strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
- err = ksmbd_vfs_remove_xattr(user_ns, dentry, name);
+ err = vfs_remove_acl(user_ns, dentry, name);
if (err)
ksmbd_debug(SMB,
"remove acl xattr failed : %s\n", name);
@@ -1375,7 +1375,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct user_namespac
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
return NULL;
- posix_acls = get_acl(inode, acl_type);
+ posix_acls = get_inode_acl(inode, acl_type);
if (!posix_acls)
return NULL;
@@ -1794,9 +1794,9 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
ret = vfs_copy_file_range(src_fp->filp, src_off,
dst_fp->filp, dst_off, len, 0);
if (ret == -EOPNOTSUPP || ret == -EXDEV)
- ret = generic_copy_file_range(src_fp->filp, src_off,
- dst_fp->filp, dst_off,
- len, 0);
+ ret = vfs_copy_file_range(src_fp->filp, src_off,
+ dst_fp->filp, dst_off, len,
+ COPY_FILE_SPLICE);
if (ret < 0)
return ret;
@@ -1824,10 +1824,11 @@ void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock)
}
int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
- struct inode *inode)
+ struct dentry *dentry)
{
struct posix_acl_state acl_state;
struct posix_acl *acls;
+ struct inode *inode = d_inode(dentry);
int rc;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
@@ -1856,14 +1857,13 @@ int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
return -ENOMEM;
}
posix_state_to_acl(&acl_state, acls->a_entries);
- rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls);
+ rc = set_posix_acl(user_ns, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
else if (S_ISDIR(inode->i_mode)) {
posix_state_to_acl(&acl_state, acls->a_entries);
- rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT,
- acls);
+ rc = set_posix_acl(user_ns, dentry, ACL_TYPE_DEFAULT, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc);
@@ -1874,16 +1874,17 @@ int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
}
int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
- struct inode *inode, struct inode *parent_inode)
+ struct dentry *dentry, struct inode *parent_inode)
{
struct posix_acl *acls;
struct posix_acl_entry *pace;
+ struct inode *inode = d_inode(dentry);
int rc, i;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
return -EOPNOTSUPP;
- acls = get_acl(parent_inode, ACL_TYPE_DEFAULT);
+ acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
if (!acls)
return -ENOENT;
pace = acls->a_entries;
@@ -1895,12 +1896,12 @@ int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
}
}
- rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls);
+ rc = set_posix_acl(user_ns, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
if (S_ISDIR(inode->i_mode)) {
- rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT,
+ rc = set_posix_acl(user_ns, dentry, ACL_TYPE_DEFAULT,
acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
diff --git a/fs/ksmbd/vfs.h b/fs/ksmbd/vfs.h
index 593059ca8511..0d73d735cc39 100644
--- a/fs/ksmbd/vfs.h
+++ b/fs/ksmbd/vfs.h
@@ -160,8 +160,8 @@ int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns,
struct dentry *dentry,
struct xattr_dos_attrib *da);
int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
- struct inode *inode);
+ struct dentry *dentry);
int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
- struct inode *inode,
+ struct dentry *dentry,
struct inode *parent_inode);
#endif /* __KSMBD_VFS_H__ */
diff --git a/fs/libfs.c b/fs/libfs.c
index 682d56345a1c..aada4e7c8713 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -995,8 +995,8 @@ out:
EXPORT_SYMBOL_GPL(simple_attr_read);
/* interpret the buffer as a number to call the set function with */
-ssize_t simple_attr_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
+static ssize_t simple_attr_write_xsigned(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos, bool is_signed)
{
struct simple_attr *attr;
unsigned long long val;
@@ -1017,7 +1017,10 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
goto out;
attr->set_buf[size] = '\0';
- ret = kstrtoull(attr->set_buf, 0, &val);
+ if (is_signed)
+ ret = kstrtoll(attr->set_buf, 0, &val);
+ else
+ ret = kstrtoull(attr->set_buf, 0, &val);
if (ret)
goto out;
ret = attr->set(attr->data, val);
@@ -1027,8 +1030,21 @@ out:
mutex_unlock(&attr->mutex);
return ret;
}
+
+ssize_t simple_attr_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return simple_attr_write_xsigned(file, buf, len, ppos, false);
+}
EXPORT_SYMBOL_GPL(simple_attr_write);
+ssize_t simple_attr_write_signed(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return simple_attr_write_xsigned(file, buf, len, ppos, true);
+}
+EXPORT_SYMBOL_GPL(simple_attr_write_signed);
+
/**
* generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
* @sb: filesystem to do the file handle conversion on
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 284b019cb652..b72023a6b4c1 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -52,6 +52,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
*filp = file;
/* Set up the missing parts of the file_lock structure */
+ lock->fl.fl_flags = FL_POSIX;
lock->fl.fl_file = file->f_file[mode];
lock->fl.fl_pid = current->tgid;
lock->fl.fl_start = (loff_t)lock->lock_start;
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 9c1aa75441e1..4e30f3c50970 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -659,11 +659,13 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
nlmsvc_cancel_blocked(net, file, lock);
lock->fl.fl_type = F_UNLCK;
- if (file->f_file[O_RDONLY])
- error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK,
+ lock->fl.fl_file = file->f_file[O_RDONLY];
+ if (lock->fl.fl_file)
+ error = vfs_lock_file(lock->fl.fl_file, F_SETLK,
&lock->fl, NULL);
- if (file->f_file[O_WRONLY])
- error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK,
+ lock->fl.fl_file = file->f_file[O_WRONLY];
+ if (lock->fl.fl_file)
+ error |= vfs_lock_file(lock->fl.fl_file, F_SETLK,
&lock->fl, NULL);
return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
@@ -697,9 +699,10 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l
block = nlmsvc_lookup_block(file, lock);
mutex_unlock(&file->f_mutex);
if (block != NULL) {
- mode = lock_to_openmode(&lock->fl);
- vfs_cancel_lock(block->b_file->f_file[mode],
- &block->b_call->a_args.lock.fl);
+ struct file_lock *fl = &block->b_call->a_args.lock.fl;
+
+ mode = lock_to_openmode(fl);
+ vfs_cancel_lock(block->b_file->f_file[mode], fl);
status = nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
}
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index e35c05e27806..32784f508c81 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -77,6 +77,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Set up the missing parts of the file_lock structure */
mode = lock_to_openmode(&lock->fl);
+ lock->fl.fl_flags = FL_POSIX;
lock->fl.fl_file = file->f_file[mode];
lock->fl.fl_pid = current->tgid;
lock->fl.fl_lmops = &nlmsvc_lock_operations;
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index e1c4617de771..e3b6229e7ae5 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file)
}
}
-static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner)
+static int nlm_unlock_files(struct nlm_file *file, const struct file_lock *fl)
{
struct file_lock lock;
@@ -184,12 +184,15 @@ static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner)
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
- lock.fl_owner = owner;
- if (file->f_file[O_RDONLY] &&
- vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
+ lock.fl_owner = fl->fl_owner;
+ lock.fl_pid = fl->fl_pid;
+ lock.fl_flags = FL_POSIX;
+
+ lock.fl_file = file->f_file[O_RDONLY];
+ if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL))
goto out_err;
- if (file->f_file[O_WRONLY] &&
- vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL))
+ lock.fl_file = file->f_file[O_WRONLY];
+ if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL))
goto out_err;
return 0;
out_err:
@@ -207,7 +210,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
struct nlm_host *lockhost;
if (!flctx || list_empty_careful(&flctx->flc_posix))
@@ -226,7 +229,7 @@ again:
if (match(lockhost, host)) {
spin_unlock(&flctx->flc_lock);
- if (nlm_unlock_files(file, fl->fl_owner))
+ if (nlm_unlock_files(file, fl))
return 1;
goto again;
}
@@ -262,7 +265,7 @@ nlm_file_inuse(struct nlm_file *file)
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
return 1;
diff --git a/fs/locks.c b/fs/locks.c
index 607f94a0e789..8f01bee17715 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -175,7 +175,7 @@ locks_get_lock_context(struct inode *inode, int type)
struct file_lock_context *ctx;
/* paired with cmpxchg() below */
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (likely(ctx) || type == F_UNLCK)
goto out;
@@ -194,7 +194,7 @@ locks_get_lock_context(struct inode *inode, int type)
*/
if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
kmem_cache_free(flctx_cache, ctx);
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
}
out:
trace_locks_get_lock_context(inode, type, ctx);
@@ -247,7 +247,7 @@ locks_check_ctx_file_list(struct file *filp, struct list_head *list,
void
locks_free_lock_context(struct inode *inode)
{
- struct file_lock_context *ctx = inode->i_flctx;
+ struct file_lock_context *ctx = locks_inode_context(inode);
if (unlikely(ctx)) {
locks_check_ctx_lists(inode);
@@ -891,7 +891,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
void *owner;
void (*func)(void);
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (!ctx || list_empty_careful(&ctx->flc_posix)) {
fl->fl_type = F_UNLCK;
return;
@@ -1483,7 +1483,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
new_fl->fl_flags = type;
/* typically we will check that ctx is non-NULL before calling */
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (!ctx) {
WARN_ON_ONCE(1);
goto free_lock;
@@ -1588,7 +1588,7 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time)
struct file_lock_context *ctx;
struct file_lock *fl;
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (ctx && !list_empty_careful(&ctx->flc_lease)) {
spin_lock(&ctx->flc_lock);
fl = list_first_entry_or_null(&ctx->flc_lease,
@@ -1634,7 +1634,7 @@ int fcntl_getlease(struct file *filp)
int type = F_UNLCK;
LIST_HEAD(dispose);
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (ctx && !list_empty_careful(&ctx->flc_lease)) {
percpu_down_read(&file_rwsem);
spin_lock(&ctx->flc_lock);
@@ -1823,7 +1823,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
struct file_lock_context *ctx;
LIST_HEAD(dispose);
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (!ctx) {
trace_generic_delete_lease(inode, NULL);
return error;
@@ -2096,7 +2096,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
* throw a warning to let people know that they don't actually work.
*/
if (cmd & LOCK_MAND) {
- pr_warn_once("Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n");
+ pr_warn_once("%s(%d): Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n", current->comm, current->pid);
return 0;
}
@@ -2146,6 +2146,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
*/
int vfs_test_lock(struct file *filp, struct file_lock *fl)
{
+ WARN_ON_ONCE(filp != fl->fl_file);
if (filp->f_op->lock)
return filp->f_op->lock(filp, F_GETLK, fl);
posix_test_lock(filp, fl);
@@ -2295,6 +2296,7 @@ out:
*/
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
{
+ WARN_ON_ONCE(filp != fl->fl_file);
if (filp->f_op->lock)
return filp->f_op->lock(filp, cmd, fl);
else
@@ -2561,7 +2563,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (!ctx || list_empty(&ctx->flc_posix))
return;
@@ -2634,7 +2636,7 @@ void locks_remove_file(struct file *filp)
{
struct file_lock_context *ctx;
- ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
+ ctx = locks_inode_context(locks_inode(filp));
if (!ctx)
return;
@@ -2663,12 +2665,36 @@ void locks_remove_file(struct file *filp)
*/
int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
{
+ WARN_ON_ONCE(filp != fl->fl_file);
if (filp->f_op->lock)
return filp->f_op->lock(filp, F_CANCELLK, fl);
return 0;
}
EXPORT_SYMBOL_GPL(vfs_cancel_lock);
+/**
+ * vfs_inode_has_locks - are any file locks held on @inode?
+ * @inode: inode to check for locks
+ *
+ * Return true if there are any FL_POSIX or FL_FLOCK locks currently
+ * set on @inode.
+ */
+bool vfs_inode_has_locks(struct inode *inode)
+{
+ struct file_lock_context *ctx;
+ bool ret;
+
+ ctx = locks_inode_context(inode);
+ if (!ctx)
+ return false;
+
+ spin_lock(&ctx->flc_lock);
+ ret = !list_empty(&ctx->flc_posix) || !list_empty(&ctx->flc_flock);
+ spin_unlock(&ctx->flc_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vfs_inode_has_locks);
+
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -2839,7 +2865,7 @@ void show_fd_locks(struct seq_file *f,
struct file_lock_context *ctx;
int id = 0;
- ctx = smp_load_acquire(&inode->i_flctx);
+ ctx = locks_inode_context(inode);
if (!ctx)
return;
diff --git a/fs/mbcache.c b/fs/mbcache.c
index e272ad738faf..2a4b8b549e93 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -100,8 +100,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
atomic_set(&entry->e_refcnt, 2);
entry->e_key = key;
entry->e_value = value;
- entry->e_reusable = reusable;
- entry->e_referenced = 0;
+ entry->e_flags = 0;
+ if (reusable)
+ set_bit(MBE_REUSABLE_B, &entry->e_flags);
head = mb_cache_entry_head(cache, key);
hlist_bl_lock(head);
hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
@@ -165,7 +166,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
while (node) {
entry = hlist_bl_entry(node, struct mb_cache_entry,
e_hash_list);
- if (entry->e_key == key && entry->e_reusable &&
+ if (entry->e_key == key &&
+ test_bit(MBE_REUSABLE_B, &entry->e_flags) &&
atomic_inc_not_zero(&entry->e_refcnt))
goto out;
node = node->next;
@@ -284,7 +286,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get);
void mb_cache_entry_touch(struct mb_cache *cache,
struct mb_cache_entry *entry)
{
- entry->e_referenced = 1;
+ set_bit(MBE_REFERENCED_B, &entry->e_flags);
}
EXPORT_SYMBOL(mb_cache_entry_touch);
@@ -309,9 +311,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
entry = list_first_entry(&cache->c_list,
struct mb_cache_entry, e_list);
/* Drop initial hash reference if there is no user */
- if (entry->e_referenced ||
+ if (test_bit(MBE_REFERENCED_B, &entry->e_flags) ||
atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) {
- entry->e_referenced = 0;
+ clear_bit(MBE_REFERENCED_B, &entry->e_flags);
list_move_tail(&entry->e_list, &cache->c_list);
continue;
}
diff --git a/fs/namei.c b/fs/namei.c
index 578c2110df02..309ae6fc8c99 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -297,13 +297,13 @@ static int check_acl(struct user_namespace *mnt_userns,
acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS);
if (!acl)
return -EAGAIN;
- /* no ->get_acl() calls in RCU mode... */
+ /* no ->get_inode_acl() calls in RCU mode... */
if (is_uncached_acl(acl))
return -ECHILD;
return posix_acl_permission(mnt_userns, inode, acl, mask);
}
- acl = get_acl(inode, ACL_TYPE_ACCESS);
+ acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
@@ -336,11 +336,11 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
struct inode *inode, int mask)
{
unsigned int mode = inode->i_mode;
- kuid_t i_uid;
+ vfsuid_t vfsuid;
/* Are we the owner? If so, ACL's don't matter */
- i_uid = i_uid_into_mnt(mnt_userns, inode);
- if (likely(uid_eq(current_fsuid(), i_uid))) {
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) {
mask &= 7;
mode >>= 6;
return (mask & ~mode) ? -EACCES : 0;
@@ -362,8 +362,8 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
* about? Need to check group ownership if so.
*/
if (mask & (mode ^ (mode >> 3))) {
- kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
- if (in_group_p(kgid))
+ vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+ if (vfsgid_in_group_p(vfsgid))
mode >>= 3;
}
@@ -581,7 +581,7 @@ struct nameidata {
struct nameidata *saved;
unsigned root_seq;
int dfd;
- kuid_t dir_uid;
+ vfsuid_t dir_vfsuid;
umode_t dir_mode;
} __randomize_layout;
@@ -1095,15 +1095,15 @@ fs_initcall(init_fs_namei_sysctls);
static inline int may_follow_link(struct nameidata *nd, const struct inode *inode)
{
struct user_namespace *mnt_userns;
- kuid_t i_uid;
+ vfsuid_t vfsuid;
if (!sysctl_protected_symlinks)
return 0;
mnt_userns = mnt_user_ns(nd->path.mnt);
- i_uid = i_uid_into_mnt(mnt_userns, inode);
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
/* Allowed if owner and follower match. */
- if (uid_eq(current_cred()->fsuid, i_uid))
+ if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
return 0;
/* Allowed if parent directory not sticky and world-writable. */
@@ -1111,7 +1111,7 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod
return 0;
/* Allowed if parent directory and link owner match. */
- if (uid_valid(nd->dir_uid) && uid_eq(nd->dir_uid, i_uid))
+ if (vfsuid_valid(nd->dir_vfsuid) && vfsuid_eq(nd->dir_vfsuid, vfsuid))
return 0;
if (nd->flags & LOOKUP_RCU)
@@ -1183,8 +1183,8 @@ int may_linkat(struct user_namespace *mnt_userns, const struct path *link)
struct inode *inode = link->dentry->d_inode;
/* Inode writeback is not safe when the uid or gid are invalid. */
- if (!uid_valid(i_uid_into_mnt(mnt_userns, inode)) ||
- !gid_valid(i_gid_into_mnt(mnt_userns, inode)))
+ if (!vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)) ||
+ !vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
return -EOVERFLOW;
if (!sysctl_protected_hardlinks)
@@ -1232,13 +1232,13 @@ static int may_create_in_sticky(struct user_namespace *mnt_userns,
struct nameidata *nd, struct inode *const inode)
{
umode_t dir_mode = nd->dir_mode;
- kuid_t dir_uid = nd->dir_uid;
+ vfsuid_t dir_vfsuid = nd->dir_vfsuid;
if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
(!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
likely(!(dir_mode & S_ISVTX)) ||
- uid_eq(i_uid_into_mnt(mnt_userns, inode), dir_uid) ||
- uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)))
+ vfsuid_eq(i_uid_into_vfsuid(mnt_userns, inode), dir_vfsuid) ||
+ vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), current_fsuid()))
return 0;
if (likely(dir_mode & 0002) ||
@@ -2307,7 +2307,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
OK:
/* pathname or trailing symlink, done */
if (!depth) {
- nd->dir_uid = i_uid_into_mnt(mnt_userns, nd->inode);
+ nd->dir_vfsuid = i_uid_into_vfsuid(mnt_userns, nd->inode);
nd->dir_mode = nd->inode->i_mode;
nd->flags &= ~LOOKUP_PARENT;
return 0;
@@ -2885,9 +2885,9 @@ int __check_sticky(struct user_namespace *mnt_userns, struct inode *dir,
{
kuid_t fsuid = current_fsuid();
- if (uid_eq(i_uid_into_mnt(mnt_userns, inode), fsuid))
+ if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), fsuid))
return 0;
- if (uid_eq(i_uid_into_mnt(mnt_userns, dir), fsuid))
+ if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, dir), fsuid))
return 0;
return !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FOWNER);
}
@@ -2926,8 +2926,8 @@ static int may_delete(struct user_namespace *mnt_userns, struct inode *dir,
BUG_ON(victim->d_parent->d_inode != dir);
/* Inode writeback is not safe when the uid or gid are invalid. */
- if (!uid_valid(i_uid_into_mnt(mnt_userns, inode)) ||
- !gid_valid(i_gid_into_mnt(mnt_userns, inode)))
+ if (!vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)) ||
+ !vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
return -EOVERFLOW;
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
@@ -3211,7 +3211,7 @@ static int handle_truncate(struct user_namespace *mnt_userns, struct file *filp)
if (error)
return error;
- error = security_path_truncate(path);
+ error = security_file_truncate(filp);
if (!error) {
error = do_truncate(mnt_userns, path->dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
@@ -3591,6 +3591,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
struct inode *dir = d_inode(parentpath->dentry);
struct inode *inode;
int error;
+ int open_flag = file->f_flags;
/* we want directory to be writable */
error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
@@ -3613,7 +3614,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
if (error)
return error;
inode = file_inode(file);
- if (!(file->f_flags & O_EXCL)) {
+ if (!(open_flag & O_EXCL)) {
spin_lock(&inode->i_lock);
inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock);
diff --git a/fs/namespace.c b/fs/namespace.c
index df137ba19d37..ab467ee58341 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -75,6 +75,22 @@ static DECLARE_RWSEM(namespace_sem);
static HLIST_HEAD(unmounted); /* protected by namespace_sem */
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
+struct mnt_idmap {
+ struct user_namespace *owner;
+ refcount_t count;
+};
+
+/*
+ * Carries the initial idmapping of 0:0:4294967295 which is an identity
+ * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is
+ * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...].
+ */
+struct mnt_idmap nop_mnt_idmap = {
+ .owner = &init_user_ns,
+ .count = REFCOUNT_INIT(1),
+};
+EXPORT_SYMBOL_GPL(nop_mnt_idmap);
+
struct mount_kattr {
unsigned int attr_set;
unsigned int attr_clr;
@@ -82,6 +98,7 @@ struct mount_kattr {
unsigned int lookup_flags;
bool recurse;
struct user_namespace *mnt_userns;
+ struct mnt_idmap *mnt_idmap;
};
/* /sys/fs */
@@ -193,6 +210,104 @@ int mnt_get_count(struct mount *mnt)
#endif
}
+/**
+ * mnt_idmap_owner - retrieve owner of the mount's idmapping
+ * @idmap: mount idmapping
+ *
+ * This helper will go away once the conversion to use struct mnt_idmap
+ * everywhere has finished at which point the helper will be unexported.
+ *
+ * Only code that needs to perform permission checks based on the owner of the
+ * idmapping will get access to it. All other code will solely rely on
+ * idmappings. This will get us type safety so it's impossible to conflate
+ * filesystems idmappings with mount idmappings.
+ *
+ * Return: The owner of the idmapping.
+ */
+struct user_namespace *mnt_idmap_owner(const struct mnt_idmap *idmap)
+{
+ return idmap->owner;
+}
+EXPORT_SYMBOL_GPL(mnt_idmap_owner);
+
+/**
+ * mnt_user_ns - retrieve owner of an idmapped mount
+ * @mnt: the relevant vfsmount
+ *
+ * This helper will go away once the conversion to use struct mnt_idmap
+ * everywhere has finished at which point the helper will be unexported.
+ *
+ * Only code that needs to perform permission checks based on the owner of the
+ * idmapping will get access to it. All other code will solely rely on
+ * idmappings. This will get us type safety so it's impossible to conflate
+ * filesystems idmappings with mount idmappings.
+ *
+ * Return: The owner of the idmapped.
+ */
+struct user_namespace *mnt_user_ns(const struct vfsmount *mnt)
+{
+ struct mnt_idmap *idmap = mnt_idmap(mnt);
+
+ /* Return the actual owner of the filesystem instead of the nop. */
+ if (idmap == &nop_mnt_idmap &&
+ !initial_idmapping(mnt->mnt_sb->s_user_ns))
+ return mnt->mnt_sb->s_user_ns;
+ return mnt_idmap_owner(idmap);
+}
+EXPORT_SYMBOL_GPL(mnt_user_ns);
+
+/**
+ * alloc_mnt_idmap - allocate a new idmapping for the mount
+ * @mnt_userns: owning userns of the idmapping
+ *
+ * Allocate a new struct mnt_idmap which carries the idmapping of the mount.
+ *
+ * Return: On success a new idmap, on error an error pointer is returned.
+ */
+static struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns)
+{
+ struct mnt_idmap *idmap;
+
+ idmap = kzalloc(sizeof(struct mnt_idmap), GFP_KERNEL_ACCOUNT);
+ if (!idmap)
+ return ERR_PTR(-ENOMEM);
+
+ idmap->owner = get_user_ns(mnt_userns);
+ refcount_set(&idmap->count, 1);
+ return idmap;
+}
+
+/**
+ * mnt_idmap_get - get a reference to an idmapping
+ * @idmap: the idmap to bump the reference on
+ *
+ * If @idmap is not the @nop_mnt_idmap bump the reference count.
+ *
+ * Return: @idmap with reference count bumped if @not_mnt_idmap isn't passed.
+ */
+static inline struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap)
+{
+ if (idmap != &nop_mnt_idmap)
+ refcount_inc(&idmap->count);
+
+ return idmap;
+}
+
+/**
+ * mnt_idmap_put - put a reference to an idmapping
+ * @idmap: the idmap to put the reference on
+ *
+ * If this is a non-initial idmapping, put the reference count when a mount is
+ * released and free it if we're the last user.
+ */
+static inline void mnt_idmap_put(struct mnt_idmap *idmap)
+{
+ if (idmap != &nop_mnt_idmap && refcount_dec_and_test(&idmap->count)) {
+ put_user_ns(idmap->owner);
+ kfree(idmap);
+ }
+}
+
static struct mount *alloc_vfsmnt(const char *name)
{
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
@@ -232,7 +347,7 @@ static struct mount *alloc_vfsmnt(const char *name)
INIT_HLIST_NODE(&mnt->mnt_mp_list);
INIT_LIST_HEAD(&mnt->mnt_umounting);
INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
- mnt->mnt.mnt_userns = &init_user_ns;
+ mnt->mnt.mnt_idmap = &nop_mnt_idmap;
}
return mnt;
@@ -602,11 +717,7 @@ int sb_prepare_remount_readonly(struct super_block *sb)
static void free_vfsmnt(struct mount *mnt)
{
- struct user_namespace *mnt_userns;
-
- mnt_userns = mnt_user_ns(&mnt->mnt);
- if (!initial_idmapping(mnt_userns))
- put_user_ns(mnt_userns);
+ mnt_idmap_put(mnt_idmap(&mnt->mnt));
kfree_const(mnt->mnt_devname);
#ifdef CONFIG_SMP
free_percpu(mnt->mnt_pcp);
@@ -1009,7 +1120,6 @@ static struct mount *skip_mnt_tree(struct mount *p)
struct vfsmount *vfs_create_mount(struct fs_context *fc)
{
struct mount *mnt;
- struct user_namespace *fs_userns;
if (!fc->root)
return ERR_PTR(-EINVAL);
@@ -1027,10 +1137,6 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc)
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
mnt->mnt_parent = mnt;
- fs_userns = mnt->mnt.mnt_sb->s_user_ns;
- if (!initial_idmapping(fs_userns))
- mnt->mnt.mnt_userns = get_user_ns(fs_userns);
-
lock_mount_hash();
list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts);
unlock_mount_hash();
@@ -1120,9 +1226,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
atomic_inc(&sb->s_active);
- mnt->mnt.mnt_userns = mnt_user_ns(&old->mnt);
- if (!initial_idmapping(mnt->mnt.mnt_userns))
- mnt->mnt.mnt_userns = get_user_ns(mnt->mnt.mnt_userns);
+ mnt->mnt.mnt_idmap = mnt_idmap_get(mnt_idmap(&old->mnt));
+
mnt->mnt.mnt_sb = sb;
mnt->mnt.mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
@@ -3515,8 +3620,9 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
q = next_mnt(q, new);
if (!q)
break;
+ // an mntns binding we'd skipped?
while (p->mnt.mnt_root != q->mnt.mnt_root)
- p = next_mnt(p, old);
+ p = next_mnt(skip_mnt_tree(p), old);
}
namespace_unlock();
@@ -3981,14 +4087,14 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
struct vfsmount *m = &mnt->mnt;
struct user_namespace *fs_userns = m->mnt_sb->s_user_ns;
- if (!kattr->mnt_userns)
+ if (!kattr->mnt_idmap)
return 0;
/*
* Creating an idmapped mount with the filesystem wide idmapping
* doesn't make sense so block that. We don't allow mushy semantics.
*/
- if (kattr->mnt_userns == fs_userns)
+ if (mnt_idmap_owner(kattr->mnt_idmap) == fs_userns)
return -EINVAL;
/*
@@ -4028,7 +4134,7 @@ static inline bool mnt_allow_writers(const struct mount_kattr *kattr,
{
return (!(kattr->attr_set & MNT_READONLY) ||
(mnt->mnt.mnt_flags & MNT_READONLY)) &&
- !kattr->mnt_userns;
+ !kattr->mnt_idmap;
}
static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt)
@@ -4082,27 +4188,18 @@ static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt)
static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
{
- struct user_namespace *mnt_userns, *old_mnt_userns;
-
- if (!kattr->mnt_userns)
+ if (!kattr->mnt_idmap)
return;
/*
- * We're the only ones able to change the mount's idmapping. So
- * mnt->mnt.mnt_userns is stable and we can retrieve it directly.
- */
- old_mnt_userns = mnt->mnt.mnt_userns;
-
- mnt_userns = get_user_ns(kattr->mnt_userns);
- /* Pairs with smp_load_acquire() in mnt_user_ns(). */
- smp_store_release(&mnt->mnt.mnt_userns, mnt_userns);
-
- /*
- * If this is an idmapped filesystem drop the reference we've taken
- * in vfs_create_mount() before.
+ * Pairs with smp_load_acquire() in mnt_idmap().
+ *
+ * Since we only allow a mount to change the idmapping once and
+ * verified this in can_idmap_mount() we know that the mount has
+ * @nop_mnt_idmap attached to it. So there's no need to drop any
+ * references.
*/
- if (!initial_idmapping(old_mnt_userns))
- put_user_ns(old_mnt_userns);
+ smp_store_release(&mnt->mnt.mnt_idmap, mnt_idmap_get(kattr->mnt_idmap));
}
static void mount_setattr_commit(struct mount_kattr *kattr, struct mount *mnt)
@@ -4136,6 +4233,15 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr)
if (path->dentry != mnt->mnt.mnt_root)
return -EINVAL;
+ if (kattr->mnt_userns) {
+ struct mnt_idmap *mnt_idmap;
+
+ mnt_idmap = alloc_mnt_idmap(kattr->mnt_userns);
+ if (IS_ERR(mnt_idmap))
+ return PTR_ERR(mnt_idmap);
+ kattr->mnt_idmap = mnt_idmap;
+ }
+
if (kattr->propagation) {
/*
* Only take namespace_lock() if we're actually changing
@@ -4323,6 +4429,9 @@ static void finish_mount_kattr(struct mount_kattr *kattr)
{
put_user_ns(kattr->mnt_userns);
kattr->mnt_userns = NULL;
+
+ if (kattr->mnt_idmap)
+ mnt_idmap_put(kattr->mnt_idmap);
}
SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 0ce535852151..7679a68e8193 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -17,9 +17,9 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
{
struct netfs_io_subrequest *subreq;
struct folio *folio;
- unsigned int iopos, account = 0;
pgoff_t start_page = rreq->start / PAGE_SIZE;
pgoff_t last_page = ((rreq->start + rreq->len) / PAGE_SIZE) - 1;
+ size_t account = 0;
bool subreq_failed = false;
XA_STATE(xas, &rreq->mapping->i_pages, start_page);
@@ -39,18 +39,23 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
*/
subreq = list_first_entry(&rreq->subrequests,
struct netfs_io_subrequest, rreq_link);
- iopos = 0;
subreq_failed = (subreq->error < 0);
trace_netfs_rreq(rreq, netfs_rreq_trace_unlock);
rcu_read_lock();
xas_for_each(&xas, folio, last_page) {
- unsigned int pgpos = (folio_index(folio) - start_page) * PAGE_SIZE;
- unsigned int pgend = pgpos + folio_size(folio);
+ loff_t pg_end;
bool pg_failed = false;
+ if (xas_retry(&xas, folio))
+ continue;
+
+ pg_end = folio_pos(folio) + folio_size(folio) - 1;
+
for (;;) {
+ loff_t sreq_end;
+
if (!subreq) {
pg_failed = true;
break;
@@ -58,11 +63,11 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags))
folio_start_fscache(folio);
pg_failed |= subreq_failed;
- if (pgend < iopos + subreq->len)
+ sreq_end = subreq->start + subreq->len - 1;
+ if (pg_end < sreq_end)
break;
account += subreq->transferred;
- iopos += subreq->len;
if (!list_is_last(&subreq->rreq_link, &rreq->subrequests)) {
subreq = list_next_entry(subreq, rreq_link);
subreq_failed = (subreq->error < 0);
@@ -70,7 +75,8 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
subreq = NULL;
subreq_failed = false;
}
- if (pgend == iopos)
+
+ if (pg_end == sreq_end)
break;
}
diff --git a/fs/netfs/io.c b/fs/netfs/io.c
index 428925899282..7f753380e047 100644
--- a/fs/netfs/io.c
+++ b/fs/netfs/io.c
@@ -23,7 +23,7 @@ static void netfs_clear_unread(struct netfs_io_subrequest *subreq)
{
struct iov_iter iter;
- iov_iter_xarray(&iter, READ, &subreq->rreq->mapping->i_pages,
+ iov_iter_xarray(&iter, ITER_DEST, &subreq->rreq->mapping->i_pages,
subreq->start + subreq->transferred,
subreq->len - subreq->transferred);
iov_iter_zero(iov_iter_count(&iter), &iter);
@@ -49,7 +49,7 @@ static void netfs_read_from_cache(struct netfs_io_request *rreq,
struct iov_iter iter;
netfs_stat(&netfs_n_rh_read);
- iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages,
+ iov_iter_xarray(&iter, ITER_DEST, &rreq->mapping->i_pages,
subreq->start + subreq->transferred,
subreq->len - subreq->transferred);
@@ -121,6 +121,9 @@ static void netfs_rreq_unmark_after_write(struct netfs_io_request *rreq,
XA_STATE(xas, &rreq->mapping->i_pages, subreq->start / PAGE_SIZE);
xas_for_each(&xas, folio, (subreq->start + subreq->len - 1) / PAGE_SIZE) {
+ if (xas_retry(&xas, folio))
+ continue;
+
/* We might have multiple writes from the same huge
* folio, but we mustn't unlock a folio more than once.
*/
@@ -205,7 +208,7 @@ static void netfs_rreq_do_write_to_cache(struct netfs_io_request *rreq)
continue;
}
- iov_iter_xarray(&iter, WRITE, &rreq->mapping->i_pages,
+ iov_iter_xarray(&iter, ITER_SOURCE, &rreq->mapping->i_pages,
subreq->start, subreq->len);
atomic_inc(&rreq->nr_copy_ops);
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 14a72224b657..1ead5bd740c2 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -209,8 +209,8 @@ config NFS_DISABLE_UDP_SUPPORT
config NFS_V4_2_READ_PLUS
bool "NFS: Enable support for the NFSv4.2 READ_PLUS operation"
depends on NFS_V4_2
- default n
+ default y
help
- This is intended for developers only. The READ_PLUS operation has
- been shown to have issues under specific conditions and should not
- be used in production.
+ Choose Y here to enable the use of READ_PLUS over NFS v4.2. READ_PLUS
+ attempts to improve read performance by compressing out sparse holes
+ in the file contents.
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index ead8a0e06abf..cf7365581031 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -146,7 +146,7 @@ static int nfs_delegation_claim_locks(struct nfs4_state *state, const nfs4_state
{
struct inode *inode = state->inode;
struct file_lock *fl;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
struct list_head *list;
int status = 0;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f594dac436a7..ea1ceffa1d3a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1074,6 +1074,8 @@ static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
return res;
}
+#define NFS_READDIR_CACHE_MISS_THRESHOLD (16UL)
+
/*
* Once we've found the start of the dirent within a page: fill 'er up...
*/
@@ -1083,6 +1085,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
struct file *file = desc->file;
struct nfs_cache_array *array;
unsigned int i;
+ bool first_emit = !desc->dir_cookie;
array = kmap_local_page(desc->page);
for (i = desc->cache_entry_index; i < array->size; i++) {
@@ -1106,6 +1109,10 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
desc->ctx->pos = desc->dir_cookie;
else
desc->ctx->pos++;
+ if (first_emit && i > NFS_READDIR_CACHE_MISS_THRESHOLD + 1) {
+ desc->eob = true;
+ break;
+ }
}
if (array->page_is_eof)
desc->eof = !desc->eob;
@@ -1187,8 +1194,6 @@ out:
return status;
}
-#define NFS_READDIR_CACHE_MISS_THRESHOLD (16UL)
-
static bool nfs_readdir_handle_cache_misses(struct inode *inode,
struct nfs_readdir_descriptor *desc,
unsigned int cache_misses,
@@ -2948,9 +2953,28 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, co
return NULL;
}
+static u64 nfs_access_login_time(const struct task_struct *task,
+ const struct cred *cred)
+{
+ const struct task_struct *parent;
+ u64 ret;
+
+ rcu_read_lock();
+ for (;;) {
+ parent = rcu_dereference(task->real_parent);
+ if (parent == task || cred_fscmp(parent->cred, cred) != 0)
+ break;
+ task = parent;
+ }
+ ret = task->start_time;
+ rcu_read_unlock();
+ return ret;
+}
+
static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, u32 *mask, bool may_block)
{
struct nfs_inode *nfsi = NFS_I(inode);
+ u64 login_time = nfs_access_login_time(current, cred);
struct nfs_access_entry *cache;
bool retry = true;
int err;
@@ -2978,6 +3002,9 @@ static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *
spin_lock(&inode->i_lock);
retry = false;
}
+ err = -ENOENT;
+ if ((s64)(login_time - cache->timestamp) > 0)
+ goto out;
*mask = cache->mask;
list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru);
err = 0;
@@ -3057,6 +3084,7 @@ static void nfs_access_add_rbtree(struct inode *inode,
else
goto found;
}
+ set->timestamp = ktime_get_ns();
rb_link_node(&set->rb_node, parent, p);
rb_insert_color(&set->rb_node, root_node);
list_add_tail(&set->lru, &nfsi->access_cache_entry_lru);
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 09833ec102fc..9bcd53d5c7d4 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -684,6 +684,8 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
return ret;
break;
case Opt_vers:
+ if (!param->string)
+ goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
ret = nfs_parse_version_string(fc, param->string);
if (ret < 0)
@@ -696,6 +698,8 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
break;
case Opt_proto:
+ if (!param->string)
+ goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
protofamily = AF_INET;
switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
@@ -732,6 +736,8 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
break;
case Opt_mountproto:
+ if (!param->string)
+ goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
mountfamily = AF_INET;
switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index e861d7bae305..e731c00a9fcb 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -252,7 +252,7 @@ static int fscache_fallback_read_page(struct inode *inode, struct page *page)
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
- iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+ iov_iter_bvec(&iter, ITER_DEST, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
ret = fscache_begin_read_operation(&cres, cookie);
if (ret < 0)
@@ -282,7 +282,7 @@ static int fscache_fallback_write_page(struct inode *inode, struct page *page,
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
- iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+ iov_iter_bvec(&iter, ITER_SOURCE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
ret = fscache_begin_write_operation(&cres, cookie);
if (ret < 0)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6b2cfa59a1a2..e98ee7599eeb 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1168,7 +1168,8 @@ int nfs_open(struct inode *inode, struct file *filp)
{
struct nfs_open_context *ctx;
- ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp);
+ ctx = alloc_nfs_open_context(file_dentry(filp),
+ flags_to_mode(filp->f_flags), filp);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
nfs_file_set_open_context(filp, ctx);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 647fc3f547cb..ae7d4a8c728c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -739,12 +739,10 @@ unsigned long nfs_io_size(unsigned long iosize, enum xprt_transports proto)
iosize = NFS_DEF_FILE_IO_SIZE;
else if (iosize >= NFS_MAX_FILE_IO_SIZE)
iosize = NFS_MAX_FILE_IO_SIZE;
- else
- iosize = iosize & PAGE_MASK;
- if (proto == XPRT_TRANSPORT_UDP)
+ if (proto == XPRT_TRANSPORT_UDP || iosize < PAGE_SIZE)
return nfs_block_bits(iosize, NULL);
- return iosize;
+ return iosize & PAGE_MASK;
}
/*
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 2f336ace7555..b0ef7e7ddb30 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -147,7 +147,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
struct nfs_fs_context *ctx;
struct fs_context *fc;
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
- struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));
+ struct nfs_server *server = NFS_SB(path->dentry->d_sb);
struct nfs_client *client = server->nfs_client;
int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
int ret;
@@ -354,7 +354,7 @@ static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
num = (num + (HZ - 1)) / HZ;
} else
num = -1;
- return scnprintf(buffer, PAGE_SIZE, "%li\n", num);
+ return sysfs_emit(buffer, "%li\n", num);
}
static const struct kernel_param_ops param_ops_nfs_timeout = {
diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
index 03a4e679fd99..df9ca56db347 100644
--- a/fs/nfs/nfs3_fs.h
+++ b/fs/nfs/nfs3_fs.h
@@ -12,7 +12,7 @@
*/
#ifdef CONFIG_NFS_V3_ACL
extern struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu);
-extern int nfs3_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+extern int nfs3_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
struct posix_acl *dfacl);
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 93de0b58647a..74d11e3c4205 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -255,23 +255,24 @@ int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
}
-int nfs3_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int nfs3_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
+ struct inode *inode = d_inode(dentry);
int status;
if (S_ISDIR(inode->i_mode)) {
switch(type) {
case ACL_TYPE_ACCESS:
- alloc = get_acl(inode, ACL_TYPE_DEFAULT);
+ alloc = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(alloc))
goto fail;
dfacl = alloc;
break;
case ACL_TYPE_DEFAULT:
- alloc = get_acl(inode, ACL_TYPE_ACCESS);
+ alloc = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(alloc))
goto fail;
dfacl = acl;
@@ -312,7 +313,7 @@ nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
struct posix_acl *acl;
char *p = data + *result;
- acl = get_acl(inode, type);
+ acl = get_inode_acl(inode, type);
if (IS_ERR_OR_NULL(acl))
return 0;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 2e7579626cf0..4bf208a0a8e9 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -998,7 +998,7 @@ static const struct inode_operations nfs3_dir_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
- .get_acl = nfs3_get_acl,
+ .get_inode_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
};
@@ -1009,7 +1009,7 @@ static const struct inode_operations nfs3_file_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
- .get_acl = nfs3_get_acl,
+ .get_inode_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
};
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index fe1aeb0f048f..d80ee88ca996 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -47,13 +47,14 @@
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
#define encode_read_plus_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + 3)
-#define NFS42_READ_PLUS_SEGMENT_SIZE (1 /* data_content4 */ + \
+#define NFS42_READ_PLUS_DATA_SEGMENT_SIZE \
+ (1 /* data_content4 */ + \
2 /* data_info4.di_offset */ + \
- 2 /* data_info4.di_length */)
+ 1 /* data_info4.di_length */)
#define decode_read_plus_maxsz (op_decode_hdr_maxsz + \
1 /* rpr_eof */ + \
1 /* rpr_contents count */ + \
- 2 * NFS42_READ_PLUS_SEGMENT_SIZE)
+ NFS42_READ_PLUS_DATA_SEGMENT_SIZE)
#define encode_seek_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + \
2 /* offset */ + \
@@ -1142,7 +1143,7 @@ static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res)
if (!segs)
return -ENOMEM;
- xdr_set_scratch_buffer(xdr, &scratch_buf, 32);
+ xdr_set_scratch_buffer(xdr, &scratch_buf, sizeof(scratch_buf));
status = -EIO;
for (i = 0; i < segments; i++) {
status = decode_read_plus_segment(xdr, &segs[i]);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index cfef738d765e..5edd1704f735 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -149,6 +149,7 @@ struct nfs4_lock_state {
struct nfs4_state * ls_state; /* Pointer to open state */
#define NFS_LOCK_INITIALIZED 0
#define NFS_LOCK_LOST 1
+#define NFS_LOCK_UNLOCKING 2
unsigned long ls_flags;
struct nfs_seqid_counter ls_seqid;
nfs4_stateid ls_stateid;
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 9eb181287879..2563ed8580f3 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -32,7 +32,6 @@ nfs4_file_open(struct inode *inode, struct file *filp)
struct dentry *parent = NULL;
struct inode *dir;
unsigned openflags = filp->f_flags;
- fmode_t f_mode;
struct iattr attr;
int err;
@@ -51,17 +50,14 @@ nfs4_file_open(struct inode *inode, struct file *filp)
if (err)
return err;
- f_mode = filp->f_mode;
- if ((openflags & O_ACCMODE) == 3)
- f_mode |= flags_to_mode(openflags);
-
/* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL);
parent = dget_parent(dentry);
dir = d_inode(parent);
- ctx = alloc_nfs_open_context(file_dentry(filp), f_mode, filp);
+ ctx = alloc_nfs_open_context(file_dentry(filp),
+ flags_to_mode(openflags), filp);
err = PTR_ERR(ctx);
if (IS_ERR(ctx))
goto out;
@@ -366,8 +362,8 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
goto out_free_name;
}
- ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode,
- filep);
+ ctx = alloc_nfs_open_context(filep->f_path.dentry,
+ flags_to_mode(filep->f_flags), filep);
if (IS_ERR(ctx)) {
res = ERR_CAST(ctx);
goto out_filep;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 86ed5c0142c3..40d749f29ed3 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -122,6 +122,11 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
return NULL;
+ label->lfs = 0;
+ label->pi = 0;
+ label->len = 0;
+ label->label = NULL;
+
err = security_dentry_init_security(dentry, sattr->ia_mode,
&dentry->d_name, NULL,
(void **)&label->label, &label->len);
@@ -2126,18 +2131,18 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
}
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
- fmode_t fmode)
+ fmode_t fmode)
{
struct nfs4_state *newstate;
+ struct nfs_server *server = NFS_SB(opendata->dentry->d_sb);
+ int openflags = opendata->o_arg.open_flags;
int ret;
if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
return 0;
- opendata->o_arg.open_flags = 0;
opendata->o_arg.fmode = fmode;
- opendata->o_arg.share_access = nfs4_map_atomic_open_share(
- NFS_SB(opendata->dentry->d_sb),
- fmode, 0);
+ opendata->o_arg.share_access =
+ nfs4_map_atomic_open_share(server, fmode, openflags);
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
nfs4_init_opendata_res(opendata);
@@ -2625,8 +2630,7 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
*/
static int nfs4_opendata_access(const struct cred *cred,
struct nfs4_opendata *opendata,
- struct nfs4_state *state, fmode_t fmode,
- int openflags)
+ struct nfs4_state *state, fmode_t fmode)
{
struct nfs_access_entry cache;
u32 mask, flags;
@@ -2637,11 +2641,7 @@ static int nfs4_opendata_access(const struct cred *cred,
return 0;
mask = 0;
- /*
- * Use openflags to check for exec, because fmode won't
- * always have FMODE_EXEC set when file open for exec.
- */
- if (openflags & __FMODE_EXEC) {
+ if (fmode & FMODE_EXEC) {
/* ONLY check for exec rights */
if (S_ISDIR(state->inode->i_mode))
mask = NFS4_ACCESS_LOOKUP;
@@ -2719,10 +2719,15 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
struct nfs4_opendata *opendata;
int ret;
- opendata = nfs4_open_recoverdata_alloc(ctx, state,
- NFS4_OPEN_CLAIM_FH);
+ opendata = nfs4_open_recoverdata_alloc(ctx, state, NFS4_OPEN_CLAIM_FH);
if (IS_ERR(opendata))
return PTR_ERR(opendata);
+ /*
+ * We're not recovering a delegation, so ask for no delegation.
+ * Otherwise the recovery thread could deadlock with an outstanding
+ * delegation return.
+ */
+ opendata->o_arg.open_flags = O_DIRECT;
ret = nfs4_open_recover(opendata, state);
if (ret == -ESTALE)
d_drop(ctx->dentry);
@@ -3024,7 +3029,7 @@ static unsigned nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
}
static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
- int flags, struct nfs_open_context *ctx)
+ struct nfs_open_context *ctx)
{
struct nfs4_state_owner *sp = opendata->owner;
struct nfs_server *server = sp->so_server;
@@ -3085,8 +3090,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
/* Parse layoutget results before we check for access */
pnfs_parse_lgopen(state->inode, opendata->lgp, ctx);
- ret = nfs4_opendata_access(sp->so_cred, opendata, state,
- acc_mode, flags);
+ ret = nfs4_opendata_access(sp->so_cred, opendata, state, acc_mode);
if (ret != 0)
goto out;
@@ -3160,7 +3164,7 @@ static int _nfs4_do_open(struct inode *dir,
if (d_really_is_positive(dentry))
opendata->state = nfs4_get_open_state(d_inode(dentry), sp);
- status = _nfs4_open_and_get_state(opendata, flags, ctx);
+ status = _nfs4_open_and_get_state(opendata, ctx);
if (status != 0)
goto err_opendata_put;
state = ctx->state;
@@ -3796,7 +3800,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
int open_flags, struct iattr *attr, int *opened)
{
struct nfs4_state *state;
- struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
+ struct nfs4_label l, *label;
label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
@@ -4013,7 +4017,7 @@ static int _nfs4_discover_trunking(struct nfs_server *server,
page = alloc_page(GFP_KERNEL);
if (!page)
- return -ENOMEM;
+ goto out_put_cred;
locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
if (!locations)
goto out_free;
@@ -4035,6 +4039,8 @@ out_free_2:
kfree(locations);
out_free:
__free_page(page);
+out_put_cred:
+ put_cred(cred);
return status;
}
@@ -4682,7 +4688,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags)
{
struct nfs_server *server = NFS_SERVER(dir);
- struct nfs4_label l, *ilabel = NULL;
+ struct nfs4_label l, *ilabel;
struct nfs_open_context *ctx;
struct nfs4_state *state;
int status = 0;
@@ -5033,7 +5039,7 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct nfs4_exception exception = {
.interruptible = true,
};
- struct nfs4_label l, *label = NULL;
+ struct nfs4_label l, *label;
int err;
label = nfs4_label_init_security(dir, dentry, sattr, &l);
@@ -5074,7 +5080,7 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct nfs4_exception exception = {
.interruptible = true,
};
- struct nfs4_label l, *label = NULL;
+ struct nfs4_label l, *label;
int err;
label = nfs4_label_init_security(dir, dentry, sattr, &l);
@@ -5193,7 +5199,7 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct nfs4_exception exception = {
.interruptible = true,
};
- struct nfs4_label l, *label = NULL;
+ struct nfs4_label l, *label;
int err;
label = nfs4_label_init_security(dir, dentry, sattr, &l);
@@ -7017,12 +7023,13 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
mutex_unlock(&sp->so_delegreturn_mutex);
goto out;
}
+ lsp = request->fl_u.nfs4_fl.owner;
+ set_bit(NFS_LOCK_UNLOCKING, &lsp->ls_flags);
up_read(&nfsi->rwsem);
mutex_unlock(&sp->so_delegreturn_mutex);
if (status != 0)
goto out;
/* Is this a delegated lock? */
- lsp = request->fl_u.nfs4_fl.owner;
if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
goto out;
alloc_seqid = NFS_SERVER(inode)->nfs_client->cl_mvops->alloc_seqid;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index a2d2d5d1b088..2a0ca5c7f082 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1230,6 +1230,8 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
if (IS_ERR(task)) {
printk(KERN_ERR "%s: kthread_run: %ld\n",
__func__, PTR_ERR(task));
+ if (!nfs_client_init_is_complete(clp))
+ nfs_mark_client_ready(clp, PTR_ERR(task));
nfs4_clear_state_manager_bit(clp);
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
nfs_put_client(clp);
@@ -1501,7 +1503,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
struct file_lock *fl;
struct nfs4_lock_state *lsp;
int status = 0;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
struct list_head *list;
if (flctx == NULL)
@@ -1619,7 +1621,8 @@ static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_st
spin_lock(&state->state_lock);
list_for_each_entry(lock, &state->lock_states, ls_locks) {
trace_nfs4_state_lock_reclaim(state, lock);
- if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
+ if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags) &&
+ !test_bit(NFS_LOCK_UNLOCKING, &lock->ls_flags))
*lost_locks += 1;
}
spin_unlock(&state->state_lock);
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 2cff5901c689..214bc56f92d2 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -9,10 +9,10 @@
#define _TRACE_NFS4_H
#include <linux/tracepoint.h>
-#include <trace/events/sunrpc_base.h>
+#include <trace/misc/sunrpc.h>
-#include <trace/events/fs.h>
-#include <trace/events/nfs.h>
+#include <trace/misc/fs.h>
+#include <trace/misc/nfs.h>
#define show_nfs_fattr_flags(valid) \
__print_flags((unsigned long)valid, "|", \
@@ -1815,7 +1815,7 @@ TRACE_EVENT(pnfs_update_layout,
__entry->count = count;
__entry->iomode = iomode;
__entry->reason = reason;
- if (lo != NULL) {
+ if (lo != NULL && pnfs_layout_is_valid(lo)) {
__entry->layoutstateid_seq =
be32_to_cpu(lo->plh_stateid.seqid);
__entry->layoutstateid_hash =
@@ -1869,7 +1869,7 @@ DECLARE_EVENT_CLASS(pnfs_layout_event,
__entry->pos = pos;
__entry->count = count;
__entry->iomode = iomode;
- if (lo != NULL) {
+ if (lo != NULL && pnfs_layout_is_valid(lo)) {
__entry->layoutstateid_seq =
be32_to_cpu(lo->plh_stateid.seqid);
__entry->layoutstateid_hash =
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index acfe5f4bda48..deec76cf5afe 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4234,19 +4234,17 @@ static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
p = xdr_inline_decode(xdr, len);
if (unlikely(!p))
return -EIO;
+ bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
if (len < NFS4_MAXLABELLEN) {
- if (label) {
- if (label->len) {
- if (label->len < len)
- return -ERANGE;
- memcpy(label->label, p, len);
- }
+ if (label && label->len) {
+ if (label->len < len)
+ return -ERANGE;
+ memcpy(label->label, p, len);
label->len = len;
label->pi = pi;
label->lfs = lfs;
status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
}
- bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
} else
printk(KERN_WARNING "%s: label too long (%u)!\n",
__func__, len);
@@ -4755,12 +4753,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
if (status < 0)
goto xdr_error;
- if (fattr->label) {
- status = decode_attr_security_label(xdr, bitmap, fattr->label);
- if (status < 0)
- goto xdr_error;
- fattr->valid |= status;
- }
+ status = decode_attr_security_label(xdr, bitmap, fattr->label);
+ if (status < 0)
+ goto xdr_error;
+ fattr->valid |= status;
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index 8c6cc58679ff..642f6921852f 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -11,9 +11,9 @@
#include <linux/tracepoint.h>
#include <linux/iversion.h>
-#include <trace/events/fs.h>
-#include <trace/events/nfs.h>
-#include <trace/events/sunrpc_base.h>
+#include <trace/misc/fs.h>
+#include <trace/misc/nfs.h>
+#include <trace/misc/sunrpc.h>
#define nfs_show_cache_validity(v) \
__print_flags(v, "|", \
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 317cedfa52bf..16be6dae524f 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -1055,7 +1055,7 @@ static unsigned int nfs_coalesce_size(struct nfs_page *prev,
if (prev) {
if (!nfs_match_open_context(nfs_req_openctx(req), nfs_req_openctx(prev)))
return 0;
- flctx = d_inode(nfs_req_openctx(req)->dentry)->i_flctx;
+ flctx = locks_inode_context(d_inode(nfs_req_openctx(req)->dentry));
if (flctx != NULL &&
!(list_empty_careful(&flctx->flc_posix) &&
list_empty_careful(&flctx->flc_flock)) &&
diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
index a6f740366963..26f8ece2a997 100644
--- a/fs/nfs/sysfs.c
+++ b/fs/nfs/sysfs.c
@@ -82,7 +82,7 @@ static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
ssize_t ret;
rcu_read_lock();
- ret = scnprintf(buf, PAGE_SIZE, "%s\n", rcu_dereference(c->identifier));
+ ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier));
rcu_read_unlock();
return ret;
}
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 9697cd5d2561..150a953a8be9 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -139,6 +139,7 @@ static int nfs_call_unlink(struct dentry *dentry, struct inode *inode, struct nf
*/
spin_lock(&alias->d_lock);
if (d_really_is_positive(alias) &&
+ !nfs_compare_fh(NFS_FH(inode), NFS_FH(d_inode(alias))) &&
!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
devname_garbage = alias->d_fsdata;
alias->d_fsdata = data;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f41d24b54fd1..80c240e50952 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1185,7 +1185,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct nfs_lock_context *l_ctx;
- struct file_lock_context *flctx = file_inode(file)->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(file_inode(file));
struct nfs_page *req;
int do_flush, status;
/*
@@ -1321,7 +1321,7 @@ static int nfs_can_extend_write(struct file *file, struct page *page,
struct inode *inode, unsigned int pagelen)
{
int ret;
- struct file_lock_context *flctx = inode->i_flctx;
+ struct file_lock_context *flctx = locks_inode_context(inode);
struct file_lock *fl;
if (file->f_flags & O_DSYNC)
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index f6a2fd3015e7..7c441f2bd444 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -8,6 +8,7 @@ config NFSD
select SUNRPC
select EXPORTFS
select NFS_ACL_SUPPORT if NFSD_V2_ACL
+ select NFS_ACL_SUPPORT if NFSD_V3_ACL
depends on MULTIUSER
help
Choose Y here if you want to allow other computers to access
@@ -26,19 +27,29 @@ config NFSD
Below you can choose which versions of the NFS protocol are
available to clients mounting the NFS server on this system.
- Support for NFS version 2 (RFC 1094) is always available when
+ Support for NFS version 3 (RFC 1813) is always available when
CONFIG_NFSD is selected.
If unsure, say N.
-config NFSD_V2_ACL
- bool
+config NFSD_V2
+ bool "NFS server support for NFS version 2 (DEPRECATED)"
depends on NFSD
+ default n
+ help
+ NFSv2 (RFC 1094) was the first publicly-released version of NFS.
+ Unless you are hosting ancient (1990's era) NFS clients, you don't
+ need this.
+
+ If unsure, say N.
+
+config NFSD_V2_ACL
+ bool "NFS server support for the NFSv2 ACL protocol extension"
+ depends on NFSD_V2
config NFSD_V3_ACL
bool "NFS server support for the NFSv3 ACL protocol extension"
depends on NFSD
- select NFSD_V2_ACL
help
Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
never became an official part of the NFS version 3 protocol.
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 805c06d5f1b4..6fffc8f03f74 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -10,9 +10,10 @@ obj-$(CONFIG_NFSD) += nfsd.o
# this one should be compiled first, as the tracing macros can easily blow up
nfsd-y += trace.o
-nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
- export.o auth.o lockd.o nfscache.o nfsxdr.o \
+nfsd-y += nfssvc.o nfsctl.o nfsfh.o vfs.o \
+ export.o auth.o lockd.o nfscache.o \
stats.o filecache.o nfs3proc.o nfs3xdr.o
+nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index b6d01d51a746..04697f8dc37d 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -12,6 +12,7 @@
#include "blocklayoutxdr.h"
#include "pnfs.h"
#include "filecache.h"
+#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PNFS
diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c
index 442543304930..8e9c1a0f8d38 100644
--- a/fs/nfsd/blocklayoutxdr.c
+++ b/fs/nfsd/blocklayoutxdr.c
@@ -9,6 +9,7 @@
#include "nfsd.h"
#include "blocklayoutxdr.h"
+#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PNFS
diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
index ee0e3aba4a6e..d03f7f6a8642 100644
--- a/fs/nfsd/export.h
+++ b/fs/nfsd/export.h
@@ -115,7 +115,6 @@ struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *);
int exp_rootfh(struct net *, struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize);
__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
-__be32 nfserrno(int errno);
static inline void exp_put(struct svc_export *exp)
{
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index adc4e87a71d2..1998b4d5f692 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -1,7 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Open file cache.
+ * The NFSD open file cache.
*
* (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
+ *
+ * An nfsd_file object is a per-file collection of open state that binds
+ * together:
+ * - a struct file *
+ * - a user credential
+ * - a network namespace
+ * - a read-ahead context
+ * - monitoring for writeback errors
+ *
+ * nfsd_file objects are reference-counted. Consumers acquire a new
+ * object via the nfsd_file_acquire API. They manage their interest in
+ * the acquired object, and hence the object's reference count, via
+ * nfsd_file_get and nfsd_file_put. There are two varieties of nfsd_file
+ * object:
+ *
+ * * non-garbage-collected: When a consumer wants to precisely control
+ * the lifetime of a file's open state, it acquires a non-garbage-
+ * collected nfsd_file. The final nfsd_file_put releases the open
+ * state immediately.
+ *
+ * * garbage-collected: When a consumer does not control the lifetime
+ * of open state, it acquires a garbage-collected nfsd_file. The
+ * final nfsd_file_put allows the open state to linger for a period
+ * during which it may be re-used.
*/
#include <linux/hash.h>
@@ -33,7 +58,6 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
-static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed);
static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
struct nfsd_fcache_disposal {
@@ -63,6 +87,7 @@ struct nfsd_file_lookup_key {
struct net *net;
const struct cred *cred;
unsigned char need;
+ bool gc;
enum nfsd_file_lookup_type type;
};
@@ -162,6 +187,8 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
return 1;
if (!nfsd_match_cred(nf->nf_cred, key->cred))
return 1;
+ if (!!test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc)
+ return 1;
if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
return 1;
break;
@@ -184,12 +211,9 @@ static const struct rhashtable_params nfsd_file_rhash_params = {
static void
nfsd_file_schedule_laundrette(void)
{
- if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) ||
- test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
- return;
-
- queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
- NFSD_LAUNDRETTE_DELAY);
+ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags))
+ queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
+ NFSD_LAUNDRETTE_DELAY);
}
static void
@@ -297,6 +321,8 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)
nf->nf_flags = 0;
__set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
__set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
+ if (key->gc)
+ __set_bit(NFSD_FILE_GC, &nf->nf_flags);
nf->nf_inode = key->inode;
/* nf_ref is pre-incremented for hash table */
refcount_set(&nf->nf_ref, 2);
@@ -306,16 +332,62 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)
return nf;
}
+static void
+nfsd_file_fsync(struct nfsd_file *nf)
+{
+ struct file *file = nf->nf_file;
+ int ret;
+
+ if (!file || !(file->f_mode & FMODE_WRITE))
+ return;
+ ret = vfs_fsync(file, 1);
+ trace_nfsd_file_fsync(nf, ret);
+ if (ret)
+ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
+}
+
+static int
+nfsd_file_check_write_error(struct nfsd_file *nf)
+{
+ struct file *file = nf->nf_file;
+
+ if (!file || !(file->f_mode & FMODE_WRITE))
+ return 0;
+ return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err));
+}
+
+static void
+nfsd_file_hash_remove(struct nfsd_file *nf)
+{
+ trace_nfsd_file_unhash(nf);
+
+ if (nfsd_file_check_write_error(nf))
+ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
+ rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash,
+ nfsd_file_rhash_params);
+}
+
+static bool
+nfsd_file_unhash(struct nfsd_file *nf)
+{
+ if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+ nfsd_file_hash_remove(nf);
+ return true;
+ }
+ return false;
+}
+
static bool
nfsd_file_free(struct nfsd_file *nf)
{
s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
bool flush = false;
+ trace_nfsd_file_free(nf);
+
this_cpu_inc(nfsd_file_releases);
this_cpu_add(nfsd_file_total_age, age);
- trace_nfsd_file_put_final(nf);
if (nf->nf_mark)
nfsd_file_mark_put(nf->nf_mark);
if (nf->nf_file) {
@@ -349,28 +421,6 @@ nfsd_file_check_writeback(struct nfsd_file *nf)
mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
}
-static int
-nfsd_file_check_write_error(struct nfsd_file *nf)
-{
- struct file *file = nf->nf_file;
-
- if (!file || !(file->f_mode & FMODE_WRITE))
- return 0;
- return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err));
-}
-
-static void
-nfsd_file_flush(struct nfsd_file *nf)
-{
- struct file *file = nf->nf_file;
-
- if (!file || !(file->f_mode & FMODE_WRITE))
- return;
- this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages);
- if (vfs_fsync(file, 1) != 0)
- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
-}
-
static void nfsd_file_lru_add(struct nfsd_file *nf)
{
set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
@@ -384,31 +434,18 @@ static void nfsd_file_lru_remove(struct nfsd_file *nf)
trace_nfsd_file_lru_del(nf);
}
-static void
-nfsd_file_hash_remove(struct nfsd_file *nf)
-{
- trace_nfsd_file_unhash(nf);
-
- if (nfsd_file_check_write_error(nf))
- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
- rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash,
- nfsd_file_rhash_params);
-}
-
-static bool
-nfsd_file_unhash(struct nfsd_file *nf)
+struct nfsd_file *
+nfsd_file_get(struct nfsd_file *nf)
{
- if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
- nfsd_file_hash_remove(nf);
- return true;
- }
- return false;
+ if (likely(refcount_inc_not_zero(&nf->nf_ref)))
+ return nf;
+ return NULL;
}
static void
-nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
+nfsd_file_unhash_and_queue(struct nfsd_file *nf, struct list_head *dispose)
{
- trace_nfsd_file_unhash_and_dispose(nf);
+ trace_nfsd_file_unhash_and_queue(nf);
if (nfsd_file_unhash(nf)) {
/* caller must call nfsd_file_dispose_list() later */
nfsd_file_lru_remove(nf);
@@ -428,48 +465,33 @@ nfsd_file_put_noref(struct nfsd_file *nf)
}
}
+static void
+nfsd_file_unhash_and_put(struct nfsd_file *nf)
+{
+ if (nfsd_file_unhash(nf))
+ nfsd_file_put_noref(nf);
+}
+
void
nfsd_file_put(struct nfsd_file *nf)
{
might_sleep();
- nfsd_file_lru_add(nf);
- if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) {
- nfsd_file_flush(nf);
+ if (test_bit(NFSD_FILE_GC, &nf->nf_flags))
+ nfsd_file_lru_add(nf);
+ else if (refcount_read(&nf->nf_ref) == 2)
+ nfsd_file_unhash_and_put(nf);
+
+ if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+ nfsd_file_fsync(nf);
nfsd_file_put_noref(nf);
- } else if (nf->nf_file) {
+ } else if (nf->nf_file && test_bit(NFSD_FILE_GC, &nf->nf_flags)) {
nfsd_file_put_noref(nf);
nfsd_file_schedule_laundrette();
} else
nfsd_file_put_noref(nf);
}
-/**
- * nfsd_file_close - Close an nfsd_file
- * @nf: nfsd_file to close
- *
- * If this is the final reference for @nf, free it immediately.
- * This reflects an on-the-wire CLOSE or DELEGRETURN into the
- * VFS and exported filesystem.
- */
-void nfsd_file_close(struct nfsd_file *nf)
-{
- nfsd_file_put(nf);
- if (refcount_dec_if_one(&nf->nf_ref)) {
- nfsd_file_unhash(nf);
- nfsd_file_lru_remove(nf);
- nfsd_file_free(nf);
- }
-}
-
-struct nfsd_file *
-nfsd_file_get(struct nfsd_file *nf)
-{
- if (likely(refcount_inc_not_zero(&nf->nf_ref)))
- return nf;
- return NULL;
-}
-
static void
nfsd_file_dispose_list(struct list_head *dispose)
{
@@ -478,7 +500,7 @@ nfsd_file_dispose_list(struct list_head *dispose)
while(!list_empty(dispose)) {
nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
list_del_init(&nf->nf_lru);
- nfsd_file_flush(nf);
+ nfsd_file_fsync(nf);
nfsd_file_put_noref(nf);
}
}
@@ -492,7 +514,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose)
while(!list_empty(dispose)) {
nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
list_del_init(&nf->nf_lru);
- nfsd_file_flush(nf);
+ nfsd_file_fsync(nf);
if (!refcount_dec_and_test(&nf->nf_ref))
continue;
if (nfsd_file_free(nf))
@@ -644,7 +666,8 @@ static void
nfsd_file_gc_worker(struct work_struct *work)
{
nfsd_file_gc();
- nfsd_file_schedule_laundrette();
+ if (list_lru_count(&nfsd_file_lru))
+ nfsd_file_schedule_laundrette();
}
static unsigned long
@@ -692,7 +715,7 @@ __nfsd_file_close_inode(struct inode *inode, struct list_head *dispose)
nfsd_file_rhash_params);
if (!nf)
break;
- nfsd_file_unhash_and_dispose(nf, dispose);
+ nfsd_file_unhash_and_queue(nf, dispose);
count++;
} while (1);
rcu_read_unlock();
@@ -894,7 +917,7 @@ __nfsd_file_cache_purge(struct net *net)
nf = rhashtable_walk_next(&iter);
while (!IS_ERR_OR_NULL(nf)) {
if (!net || nf->nf_net == net)
- nfsd_file_unhash_and_dispose(nf, &dispose);
+ nfsd_file_unhash_and_queue(nf, &dispose);
nf = rhashtable_walk_next(&iter);
}
@@ -1000,7 +1023,6 @@ nfsd_file_cache_shutdown(void)
per_cpu(nfsd_file_acquisitions, i) = 0;
per_cpu(nfsd_file_releases, i) = 0;
per_cpu(nfsd_file_total_age, i) = 0;
- per_cpu(nfsd_file_pages_flushed, i) = 0;
per_cpu(nfsd_file_evictions, i) = 0;
}
}
@@ -1034,12 +1056,14 @@ nfsd_file_is_cached(struct inode *inode)
static __be32
nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
- unsigned int may_flags, struct nfsd_file **pnf, bool open)
+ unsigned int may_flags, struct nfsd_file **pnf,
+ bool open, bool want_gc)
{
struct nfsd_file_lookup_key key = {
.type = NFSD_FILE_KEY_FULL,
.need = may_flags & NFSD_FILE_MAY_MASK,
.net = SVC_NET(rqstp),
+ .gc = want_gc,
};
bool open_retry = true;
struct nfsd_file *nf;
@@ -1076,6 +1100,7 @@ retry:
goto open_file;
nfsd_file_slab_free(&nf->nf_rcu);
+ nf = NULL;
if (ret == -EEXIST)
goto retry;
trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret);
@@ -1134,8 +1159,7 @@ open_file:
* then unhash.
*/
if (status != nfs_ok || key.inode->i_nlink == 0)
- if (nfsd_file_unhash(nf))
- nfsd_file_put_noref(nf);
+ nfsd_file_unhash_and_put(nf);
clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags);
smp_mb__after_atomic();
wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
@@ -1143,12 +1167,38 @@ open_file:
}
/**
+ * nfsd_file_acquire_gc - Get a struct nfsd_file with an open file
+ * @rqstp: the RPC transaction being executed
+ * @fhp: the NFS filehandle of the file to be opened
+ * @may_flags: NFSD_MAY_ settings for the file
+ * @pnf: OUT: new or found "struct nfsd_file" object
+ *
+ * The nfsd_file object returned by this API is reference-counted
+ * and garbage-collected. The object is retained for a few
+ * seconds after the final nfsd_file_put() in case the caller
+ * wants to re-use it.
+ *
+ * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
+ * network byte order is returned.
+ */
+__be32
+nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ unsigned int may_flags, struct nfsd_file **pnf)
+{
+ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, true);
+}
+
+/**
* nfsd_file_acquire - Get a struct nfsd_file with an open file
* @rqstp: the RPC transaction being executed
* @fhp: the NFS filehandle of the file to be opened
* @may_flags: NFSD_MAY_ settings for the file
* @pnf: OUT: new or found "struct nfsd_file" object
*
+ * The nfsd_file_object returned by this API is reference-counted
+ * but not garbage-collected. The object is unhashed after the
+ * final nfsd_file_put().
+ *
* Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
* network byte order is returned.
*/
@@ -1156,7 +1206,7 @@ __be32
nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true);
+ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, false);
}
/**
@@ -1166,6 +1216,10 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
* @may_flags: NFSD_MAY_ settings for the file
* @pnf: OUT: new or found "struct nfsd_file" object
*
+ * The nfsd_file_object returned by this API is reference-counted
+ * but not garbage-collected. The object is released immediately
+ * one RCU grace period after the final nfsd_file_put().
+ *
* Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
* network byte order is returned.
*/
@@ -1173,7 +1227,7 @@ __be32
nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false);
+ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, false);
}
/*
@@ -1183,7 +1237,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
{
- unsigned long releases = 0, pages_flushed = 0, evictions = 0;
+ unsigned long releases = 0, evictions = 0;
unsigned long hits = 0, acquisitions = 0;
unsigned int i, count = 0, buckets = 0;
unsigned long lru = 0, total_age = 0;
@@ -1211,7 +1265,6 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
releases += per_cpu(nfsd_file_releases, i);
total_age += per_cpu(nfsd_file_total_age, i);
evictions += per_cpu(nfsd_file_evictions, i);
- pages_flushed += per_cpu(nfsd_file_pages_flushed, i);
}
seq_printf(m, "total entries: %u\n", count);
@@ -1225,6 +1278,5 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
seq_printf(m, "mean age (ms): %ld\n", total_age / releases);
else
seq_printf(m, "mean age (ms): -\n");
- seq_printf(m, "pages flushed: %lu\n", pages_flushed);
return 0;
}
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index 357832bac736..b7efb2c3ddb1 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -38,6 +38,7 @@ struct nfsd_file {
#define NFSD_FILE_HASHED (0)
#define NFSD_FILE_PENDING (1)
#define NFSD_FILE_REFERENCED (2)
+#define NFSD_FILE_GC (3)
unsigned long nf_flags;
struct inode *nf_inode; /* don't deref */
refcount_t nf_ref;
@@ -52,10 +53,11 @@ void nfsd_file_cache_shutdown(void);
int nfsd_file_cache_start_net(struct net *net);
void nfsd_file_cache_shutdown_net(struct net *net);
void nfsd_file_put(struct nfsd_file *nf);
-void nfsd_file_close(struct nfsd_file *nf);
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
void nfsd_file_close_inode_sync(struct inode *inode);
bool nfsd_file_is_cached(struct inode *inode);
+__be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ unsigned int may_flags, struct nfsd_file **nfp);
__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **nfp);
__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c
index 070f90ed09b6..3ca5304440ff 100644
--- a/fs/nfsd/flexfilelayout.c
+++ b/fs/nfsd/flexfilelayout.c
@@ -15,6 +15,7 @@
#include "flexfilelayoutxdr.h"
#include "pnfs.h"
+#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PNFS
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 13e6e6897f6c..1457f59f447a 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -55,7 +55,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
goto out;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
- acl = get_acl(inode, ACL_TYPE_ACCESS);
+ acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@@ -69,7 +69,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL
of a non-directory! */
- acl = get_acl(inode, ACL_TYPE_DEFAULT);
+ acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
@@ -113,11 +113,11 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
inode_lock(inode);
- error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
+ error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_ACCESS,
argp->acl_access);
if (error)
goto out_drop_lock;
- error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
+ error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_DEFAULT,
argp->acl_default);
if (error)
goto out_drop_lock;
@@ -246,7 +246,6 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
struct nfsd3_getaclres *resp = rqstp->rq_resp;
struct dentry *dentry = resp->fh.fh_dentry;
struct inode *inode;
- int w;
if (!svcxdr_encode_stat(xdr, resp->status))
return false;
@@ -260,15 +259,6 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
return false;
- rqstp->rq_res.page_len = w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
- while (w > 0) {
- if (!*(rqstp->rq_next_page++))
- return true;
- w -= PAGE_SIZE;
- }
-
if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
resp->mask & NFS_ACL, 0))
return false;
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 2fb9ee356455..647108138e8a 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -47,7 +47,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
resp->mask = argp->mask;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
- acl = get_acl(inode, ACL_TYPE_ACCESS);
+ acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@@ -61,7 +61,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL
of a non-directory! */
- acl = get_acl(inode, ACL_TYPE_DEFAULT);
+ acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
@@ -103,11 +103,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
inode_lock(inode);
- error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
+ error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_ACCESS,
argp->acl_access);
if (error)
goto out_drop_lock;
- error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
+ error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_DEFAULT,
argp->acl_default);
out_drop_lock:
@@ -171,11 +171,7 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
struct nfsd3_getaclres *resp = rqstp->rq_resp;
struct dentry *dentry = resp->fh.fh_dentry;
- struct kvec *head = rqstp->rq_res.head;
struct inode *inode;
- unsigned int base;
- int n;
- int w;
if (!svcxdr_encode_nfsstat3(xdr, resp->status))
return false;
@@ -187,26 +183,12 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
return false;
- base = (char *)xdr->p - (char *)head->iov_base;
-
- rqstp->rq_res.page_len = w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
- while (w > 0) {
- if (!*(rqstp->rq_next_page++))
- return false;
- w -= PAGE_SIZE;
- }
-
- n = nfsacl_encode(&rqstp->rq_res, base, inode,
- resp->acl_access,
- resp->mask & NFS_ACL, 0);
- if (n > 0)
- n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
- resp->acl_default,
- resp->mask & NFS_DFACL,
- NFS_ACL_DEFAULT);
- if (n <= 0)
+ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
+ resp->mask & NFS_ACL, 0))
+ return false;
+ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
+ resp->mask & NFS_DFACL,
+ NFS_ACL_DEFAULT))
return false;
break;
default:
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 923d9a80df92..d01b29aba662 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -13,6 +13,7 @@
#include "cache.h"
#include "xdr3.h"
#include "vfs.h"
+#include "filecache.h"
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -763,6 +764,7 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
{
struct nfsd3_commitargs *argp = rqstp->rq_argp;
struct nfsd3_commitres *resp = rqstp->rq_resp;
+ struct nfsd_file *nf;
dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
SVCFH_fmt(&argp->fh),
@@ -770,8 +772,14 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
(unsigned long long) argp->offset);
fh_copy(&resp->fh, &argp->fh);
- resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
+ resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE |
+ NFSD_MAY_NOT_BREAK_LEASE, &nf);
+ if (resp->status)
+ goto out;
+ resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset,
argp->count, resp->verf);
+ nfsd_file_put(nf);
+out:
return rpc_success;
}
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index bb8e2f6d7d03..518203821790 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -135,7 +135,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
unsigned int flags = 0;
int size = 0;
- pacl = get_acl(inode, ACL_TYPE_ACCESS);
+ pacl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (!pacl)
pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@@ -147,7 +147,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
if (S_ISDIR(inode->i_mode)) {
flags = NFS4_ACL_DIR;
- dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
+ dpacl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(dpacl)) {
error = PTR_ERR(dpacl);
goto rel_pacl;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index f0e69edf5f0f..1b57f2c2f0bb 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -76,6 +76,17 @@ static __be32 *xdr_encode_empty_array(__be32 *p)
* 1 Protocol"
*/
+static void encode_uint32(struct xdr_stream *xdr, u32 n)
+{
+ WARN_ON_ONCE(xdr_stream_encode_u32(xdr, n) < 0);
+}
+
+static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap,
+ size_t len)
+{
+ WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0);
+}
+
/*
* nfs_cb_opnum4
*
@@ -329,6 +340,24 @@ static void encode_cb_recall4args(struct xdr_stream *xdr,
}
/*
+ * CB_RECALLANY4args
+ *
+ * struct CB_RECALLANY4args {
+ * uint32_t craa_objects_to_keep;
+ * bitmap4 craa_type_mask;
+ * };
+ */
+static void
+encode_cb_recallany4args(struct xdr_stream *xdr,
+ struct nfs4_cb_compound_hdr *hdr, struct nfsd4_cb_recall_any *ra)
+{
+ encode_nfs_cb_opnum4(xdr, OP_CB_RECALL_ANY);
+ encode_uint32(xdr, ra->ra_keep);
+ encode_bitmap4(xdr, ra->ra_bmval, ARRAY_SIZE(ra->ra_bmval));
+ hdr->nops++;
+}
+
+/*
* CB_SEQUENCE4args
*
* struct CB_SEQUENCE4args {
@@ -482,6 +511,26 @@ static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_cb_nops(&hdr);
}
+/*
+ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects
+ */
+static void
+nfs4_xdr_enc_cb_recall_any(struct rpc_rqst *req,
+ struct xdr_stream *xdr, const void *data)
+{
+ const struct nfsd4_callback *cb = data;
+ struct nfsd4_cb_recall_any *ra;
+ struct nfs4_cb_compound_hdr hdr = {
+ .ident = cb->cb_clp->cl_cb_ident,
+ .minorversion = cb->cb_clp->cl_minorversion,
+ };
+
+ ra = container_of(cb, struct nfsd4_cb_recall_any, ra_cb);
+ encode_cb_compound4args(xdr, &hdr);
+ encode_cb_sequence4args(xdr, cb, &hdr);
+ encode_cb_recallany4args(xdr, &hdr, ra);
+ encode_cb_nops(&hdr);
+}
/*
* NFSv4.0 and NFSv4.1 XDR decode functions
@@ -520,6 +569,28 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
}
+/*
+ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects
+ */
+static int
+nfs4_xdr_dec_cb_recall_any(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ void *data)
+{
+ struct nfsd4_callback *cb = data;
+ struct nfs4_cb_compound_hdr hdr;
+ int status;
+
+ status = decode_cb_compound4res(xdr, &hdr);
+ if (unlikely(status))
+ return status;
+ status = decode_cb_sequence4res(xdr, cb);
+ if (unlikely(status || cb->cb_seq_status))
+ return status;
+ status = decode_cb_op_status(xdr, OP_CB_RECALL_ANY, &cb->cb_status);
+ return status;
+}
+
#ifdef CONFIG_NFSD_PNFS
/*
* CB_LAYOUTRECALL4args
@@ -783,6 +854,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[] = {
#endif
PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock),
PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload),
+ PROC(CB_RECALL_ANY, COMPOUND, cb_recall_any, cb_recall_any),
};
static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)];
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index e70a1a2999b7..5e9809aff37e 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -41,6 +41,7 @@
#include "idmap.h"
#include "nfsd.h"
#include "netns.h"
+#include "vfs.h"
/*
* Turn off idmapping when using AUTH_SYS.
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8beb2bc4c328..73ed32ad23a2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -731,10 +731,19 @@ nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
union nfsd4_op_u *u)
{
struct nfsd4_commit *commit = &u->commit;
+ struct nfsd_file *nf;
+ __be32 status;
+
+ status = nfsd_file_acquire(rqstp, &cstate->current_fh, NFSD_MAY_WRITE |
+ NFSD_MAY_NOT_BREAK_LEASE, &nf);
+ if (status != nfs_ok)
+ return status;
- return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
+ status = nfsd_commit(rqstp, &cstate->current_fh, nf, commit->co_offset,
commit->co_count,
(__be32 *)commit->co_verf.data);
+ nfsd_file_put(nf);
+ return status;
}
static __be32
@@ -934,12 +943,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&read->rd_stateid, RD_STATE,
&read->rd_nf, NULL);
- if (status) {
- dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
- goto out;
- }
- status = nfs_ok;
-out:
+
read->rd_rqstp = rqstp;
read->rd_fhp = &cstate->current_fh;
return status;
@@ -1108,10 +1112,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_stateid_op(rqstp, cstate,
&cstate->current_fh, &setattr->sa_stateid,
WR_STATE, NULL, NULL);
- if (status) {
- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
+ if (status)
return status;
- }
}
err = fh_want_write(&cstate->current_fh);
if (err)
@@ -1133,6 +1135,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
0, (time64_t)0);
if (!status)
status = nfserrno(attrs.na_labelerr);
+ if (!status)
+ status = nfserrno(attrs.na_aclerr);
out:
nfsd_attrs_free(&attrs);
fh_drop_write(&cstate->current_fh);
@@ -1159,10 +1163,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
write->wr_offset, cnt);
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
stateid, WR_STATE, &nf, NULL);
- if (status) {
- dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
+ if (status)
return status;
- }
write->wr_how_written = write->wr_stable_how;
@@ -1193,17 +1195,13 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
src_stateid, RD_STATE, src, NULL);
- if (status) {
- dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
+ if (status)
goto out;
- }
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
dst_stateid, WR_STATE, dst, NULL);
- if (status) {
- dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
+ if (status)
goto out_put_src;
- }
/* fix up for NFS-specific error code */
if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) ||
@@ -1644,6 +1642,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy,
u64 src_pos = copy->cp_src_pos;
u64 dst_pos = copy->cp_dst_pos;
int status;
+ loff_t end;
/* See RFC 7862 p.67: */
if (bytes_total == 0)
@@ -1663,8 +1662,8 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy,
/* for a non-zero asynchronous copy do a commit of data */
if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) {
since = READ_ONCE(dst->f_wb_err);
- status = vfs_fsync_range(dst, copy->cp_dst_pos,
- copy->cp_res.wr_bytes_written, 0);
+ end = copy->cp_dst_pos + copy->cp_res.wr_bytes_written - 1;
+ status = vfs_fsync_range(dst, copy->cp_dst_pos, end, 0);
if (!status)
status = filemap_check_wb_err(dst->f_mapping, since);
if (!status)
@@ -1948,10 +1947,8 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&fallocate->falloc_stateid,
WR_STATE, &nf, NULL);
- if (status != nfs_ok) {
- dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
+ if (status != nfs_ok)
return status;
- }
status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file,
fallocate->falloc_offset,
@@ -2007,10 +2004,8 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&seek->seek_stateid,
RD_STATE, &nf, NULL);
- if (status) {
- dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
+ if (status)
return status;
- }
switch (seek->seek_whence) {
case NFS4_CONTENT_DATA:
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4e718500a00c..7b2ee535ade8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -44,7 +44,9 @@
#include <linux/jhash.h>
#include <linux/string_helpers.h>
#include <linux/fsnotify.h>
+#include <linux/rhashtable.h>
#include <linux/nfs_ssc.h>
+
#include "xdr4.h"
#include "xdr4cb.h"
#include "vfs.h"
@@ -84,6 +86,7 @@ static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
void nfsd4_end_grace(struct nfsd_net *nn);
static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
+static void nfsd4_file_hash_remove(struct nfs4_file *fi);
/* Locking: */
@@ -588,11 +591,8 @@ static void nfsd4_free_file_rcu(struct rcu_head *rcu)
void
put_nfs4_file(struct nfs4_file *fi)
{
- might_lock(&state_lock);
-
- if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
- hlist_del_rcu(&fi->fi_hash);
- spin_unlock(&state_lock);
+ if (refcount_dec_and_test(&fi->fi_ref)) {
+ nfsd4_file_hash_remove(fi);
WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
@@ -675,15 +675,26 @@ find_any_file(struct nfs4_file *f)
return ret;
}
-static struct nfsd_file *find_deleg_file(struct nfs4_file *f)
+static struct nfsd_file *find_any_file_locked(struct nfs4_file *f)
{
- struct nfsd_file *ret = NULL;
+ lockdep_assert_held(&f->fi_lock);
+
+ if (f->fi_fds[O_RDWR])
+ return f->fi_fds[O_RDWR];
+ if (f->fi_fds[O_WRONLY])
+ return f->fi_fds[O_WRONLY];
+ if (f->fi_fds[O_RDONLY])
+ return f->fi_fds[O_RDONLY];
+ return NULL;
+}
+
+static struct nfsd_file *find_deleg_file_locked(struct nfs4_file *f)
+{
+ lockdep_assert_held(&f->fi_lock);
- spin_lock(&f->fi_lock);
if (f->fi_deleg_file)
- ret = nfsd_file_get(f->fi_deleg_file);
- spin_unlock(&f->fi_lock);
- return ret;
+ return f->fi_deleg_file;
+ return NULL;
}
static atomic_long_t num_delegations;
@@ -706,19 +717,20 @@ static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
return ret & OWNER_HASH_MASK;
}
-/* hash table for nfs4_file */
-#define FILE_HASH_BITS 8
-#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
-
-static unsigned int file_hashval(struct svc_fh *fh)
-{
- struct inode *inode = d_inode(fh->fh_dentry);
+static struct rhltable nfs4_file_rhltable ____cacheline_aligned_in_smp;
- /* XXX: why not (here & in file cache) use inode? */
- return (unsigned int)hash_long(inode->i_ino, FILE_HASH_BITS);
-}
+static const struct rhashtable_params nfs4_file_rhash_params = {
+ .key_len = sizeof_field(struct nfs4_file, fi_inode),
+ .key_offset = offsetof(struct nfs4_file, fi_inode),
+ .head_offset = offsetof(struct nfs4_file, fi_rlist),
-static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
+ /*
+ * Start with a single page hash table to reduce resizing churn
+ * on light workloads.
+ */
+ .min_size = 256,
+ .automatic_shrinking = true,
+};
/*
* Check if courtesy clients have conflicting access and resolve it if possible
@@ -831,9 +843,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
swap(f2, fp->fi_fds[O_RDWR]);
spin_unlock(&fp->fi_lock);
if (f1)
- nfsd_file_close(f1);
+ nfsd_file_put(f1);
if (f2)
- nfsd_file_close(f2);
+ nfsd_file_put(f2);
}
}
@@ -1355,6 +1367,8 @@ static void revoke_delegation(struct nfs4_delegation *dp)
WARN_ON(!list_empty(&dp->dl_recall_lru));
+ trace_nfsd_stid_revoke(&dp->dl_stid);
+
if (clp->cl_minorversion) {
dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
refcount_inc(&dp->dl_stid.sc_count);
@@ -1819,13 +1833,12 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
int numslots = fattrs->maxreqs;
int slotsize = slot_bytes(fattrs);
struct nfsd4_session *new;
- int mem, i;
+ int i;
- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
- + sizeof(struct nfsd4_session) > PAGE_SIZE);
- mem = numslots * sizeof(struct nfsd4_slot *);
+ BUILD_BUG_ON(struct_size(new, se_slots, NFSD_MAX_SLOTS_PER_SESSION)
+ > PAGE_SIZE);
- new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
+ new = kzalloc(struct_size(new, se_slots, numslots), GFP_KERNEL);
if (!new)
return NULL;
/* allocate each struct nfsd4_slot and data cache in one piece */
@@ -2131,6 +2144,7 @@ static void __free_client(struct kref *k)
kfree(clp->cl_nii_domain.data);
kfree(clp->cl_nii_name.data);
idr_destroy(&clp->cl_stateids);
+ kfree(clp->cl_ra);
kmem_cache_free(client_slab, clp);
}
@@ -2613,9 +2627,11 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
ols = openlockstateid(st);
oo = ols->st_stateowner;
nf = st->sc_file;
- file = find_any_file(nf);
+
+ spin_lock(&nf->fi_lock);
+ file = find_any_file_locked(nf);
if (!file)
- return 0;
+ goto out;
seq_printf(s, "- ");
nfs4_show_stateid(s, &st->sc_stateid);
@@ -2637,8 +2653,8 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
seq_printf(s, ", ");
nfs4_show_owner(s, oo);
seq_printf(s, " }\n");
- nfsd_file_put(file);
-
+out:
+ spin_unlock(&nf->fi_lock);
return 0;
}
@@ -2652,9 +2668,10 @@ static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st)
ols = openlockstateid(st);
oo = ols->st_stateowner;
nf = st->sc_file;
- file = find_any_file(nf);
+ spin_lock(&nf->fi_lock);
+ file = find_any_file_locked(nf);
if (!file)
- return 0;
+ goto out;
seq_printf(s, "- ");
nfs4_show_stateid(s, &st->sc_stateid);
@@ -2674,8 +2691,8 @@ static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st)
seq_printf(s, ", ");
nfs4_show_owner(s, oo);
seq_printf(s, " }\n");
- nfsd_file_put(file);
-
+out:
+ spin_unlock(&nf->fi_lock);
return 0;
}
@@ -2687,9 +2704,10 @@ static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st)
ds = delegstateid(st);
nf = st->sc_file;
- file = find_deleg_file(nf);
+ spin_lock(&nf->fi_lock);
+ file = find_deleg_file_locked(nf);
if (!file)
- return 0;
+ goto out;
seq_printf(s, "- ");
nfs4_show_stateid(s, &st->sc_stateid);
@@ -2705,8 +2723,8 @@ static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st)
seq_printf(s, ", ");
nfs4_show_fname(s, file);
seq_printf(s, " }\n");
- nfsd_file_put(file);
-
+out:
+ spin_unlock(&nf->fi_lock);
return 0;
}
@@ -2854,6 +2872,37 @@ static const struct tree_descr client_files[] = {
[3] = {""},
};
+static int
+nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
+ struct rpc_task *task)
+{
+ trace_nfsd_cb_recall_any_done(cb, task);
+ switch (task->tk_status) {
+ case -NFS4ERR_DELAY:
+ rpc_delay(task, 2 * HZ);
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static void
+nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
+{
+ struct nfs4_client *clp = cb->cb_clp;
+ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+ spin_lock(&nn->client_lock);
+ clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
+ put_client_renew_locked(clp);
+ spin_unlock(&nn->client_lock);
+}
+
+static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
+ .done = nfsd4_cb_recall_any_done,
+ .release = nfsd4_cb_recall_any_release,
+};
+
static struct nfs4_client *create_client(struct xdr_netobj name,
struct svc_rqst *rqstp, nfs4_verifier *verf)
{
@@ -2891,6 +2940,14 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
free_client(clp);
return NULL;
}
+ clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL);
+ if (!clp->cl_ra) {
+ free_client(clp);
+ return NULL;
+ }
+ clp->cl_ra_time = 0;
+ nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops,
+ NFSPROC4_CLNT_CB_RECALL_ANY);
return clp;
}
@@ -4260,11 +4317,9 @@ static struct nfs4_file *nfsd4_alloc_file(void)
}
/* OPEN Share state helper functions */
-static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval,
- struct nfs4_file *fp)
-{
- lockdep_assert_held(&state_lock);
+static void nfsd4_file_init(const struct svc_fh *fh, struct nfs4_file *fp)
+{
refcount_set(&fp->fi_ref, 1);
spin_lock_init(&fp->fi_lock);
INIT_LIST_HEAD(&fp->fi_stateids);
@@ -4282,7 +4337,6 @@ static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval,
INIT_LIST_HEAD(&fp->fi_lo_states);
atomic_set(&fp->fi_lo_recalls, 0);
#endif
- hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
}
void
@@ -4347,20 +4401,22 @@ out:
}
static unsigned long
-nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc)
+nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
{
- int cnt;
+ int count;
struct nfsd_net *nn = container_of(shrink,
struct nfsd_net, nfsd_client_shrinker);
- cnt = atomic_read(&nn->nfsd_courtesy_clients);
- if (cnt > 0)
+ count = atomic_read(&nn->nfsd_courtesy_clients);
+ if (!count)
+ count = atomic_long_read(&num_delegations);
+ if (count)
mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
- return (unsigned long)cnt;
+ return (unsigned long)count;
}
static unsigned long
-nfsd_courtesy_client_scan(struct shrinker *shrink, struct shrink_control *sc)
+nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
{
return SHRINK_STOP;
}
@@ -4387,8 +4443,8 @@ nfsd4_init_leases_net(struct nfsd_net *nn)
nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
atomic_set(&nn->nfsd_courtesy_clients, 0);
- nn->nfsd_client_shrinker.scan_objects = nfsd_courtesy_client_scan;
- nn->nfsd_client_shrinker.count_objects = nfsd_courtesy_client_count;
+ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
+ nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client");
}
@@ -4667,71 +4723,80 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
nfs4_put_stid(&last->st_stid);
}
-/* search file_hashtbl[] for file */
-static struct nfs4_file *
-find_file_locked(struct svc_fh *fh, unsigned int hashval)
+static noinline_for_stack struct nfs4_file *
+nfsd4_file_hash_lookup(const struct svc_fh *fhp)
{
- struct nfs4_file *fp;
+ struct inode *inode = d_inode(fhp->fh_dentry);
+ struct rhlist_head *tmp, *list;
+ struct nfs4_file *fi;
- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash,
- lockdep_is_held(&state_lock)) {
- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) {
- if (refcount_inc_not_zero(&fp->fi_ref))
- return fp;
+ rcu_read_lock();
+ list = rhltable_lookup(&nfs4_file_rhltable, &inode,
+ nfs4_file_rhash_params);
+ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) {
+ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
+ if (refcount_inc_not_zero(&fi->fi_ref)) {
+ rcu_read_unlock();
+ return fi;
+ }
}
}
+ rcu_read_unlock();
return NULL;
}
-static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh,
- unsigned int hashval)
+/*
+ * On hash insertion, identify entries with the same inode but
+ * distinct filehandles. They will all be on the list returned
+ * by rhltable_lookup().
+ *
+ * inode->i_lock prevents racing insertions from adding an entry
+ * for the same inode/fhp pair twice.
+ */
+static noinline_for_stack struct nfs4_file *
+nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp)
{
- struct nfs4_file *fp;
+ struct inode *inode = d_inode(fhp->fh_dentry);
+ struct rhlist_head *tmp, *list;
struct nfs4_file *ret = NULL;
bool alias_found = false;
+ struct nfs4_file *fi;
+ int err;
- spin_lock(&state_lock);
- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash,
- lockdep_is_held(&state_lock)) {
- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) {
- if (refcount_inc_not_zero(&fp->fi_ref))
- ret = fp;
- } else if (d_inode(fh->fh_dentry) == fp->fi_inode)
- fp->fi_aliased = alias_found = true;
- }
- if (likely(ret == NULL)) {
- nfsd4_init_file(fh, hashval, new);
- new->fi_aliased = alias_found;
- ret = new;
+ rcu_read_lock();
+ spin_lock(&inode->i_lock);
+
+ list = rhltable_lookup(&nfs4_file_rhltable, &inode,
+ nfs4_file_rhash_params);
+ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) {
+ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
+ if (refcount_inc_not_zero(&fi->fi_ref))
+ ret = fi;
+ } else
+ fi->fi_aliased = alias_found = true;
}
- spin_unlock(&state_lock);
- return ret;
-}
+ if (ret)
+ goto out_unlock;
-static struct nfs4_file * find_file(struct svc_fh *fh)
-{
- struct nfs4_file *fp;
- unsigned int hashval = file_hashval(fh);
+ nfsd4_file_init(fhp, new);
+ err = rhltable_insert(&nfs4_file_rhltable, &new->fi_rlist,
+ nfs4_file_rhash_params);
+ if (err)
+ goto out_unlock;
- rcu_read_lock();
- fp = find_file_locked(fh, hashval);
+ new->fi_aliased = alias_found;
+ ret = new;
+
+out_unlock:
+ spin_unlock(&inode->i_lock);
rcu_read_unlock();
- return fp;
+ return ret;
}
-static struct nfs4_file *
-find_or_add_file(struct nfs4_file *new, struct svc_fh *fh)
+static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi)
{
- struct nfs4_file *fp;
- unsigned int hashval = file_hashval(fh);
-
- rcu_read_lock();
- fp = find_file_locked(fh, hashval);
- rcu_read_unlock();
- if (fp)
- return fp;
-
- return insert_file(new, fh, hashval);
+ rhltable_remove(&nfs4_file_rhltable, &fi->fi_rlist,
+ nfs4_file_rhash_params);
}
/*
@@ -4744,9 +4809,10 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
struct nfs4_file *fp;
__be32 ret = nfs_ok;
- fp = find_file(current_fh);
+ fp = nfsd4_file_hash_lookup(current_fh);
if (!fp)
return ret;
+
/* Check for conflicting share reservations */
spin_lock(&fp->fi_lock);
if (fp->fi_share_deny & deny_type)
@@ -4758,7 +4824,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
static bool nfsd4_deleg_present(const struct inode *inode)
{
- struct file_lock_context *ctx = smp_load_acquire(&inode->i_flctx);
+ struct file_lock_context *ctx = locks_inode_context(inode);
return ctx && !list_empty_careful(&ctx->flc_lease);
}
@@ -5382,6 +5448,7 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
if (err)
return -EAGAIN;
+ exp_put(exp);
dput(child);
if (child != file_dentry(fp->fi_deleg_file->nf_file))
return -EAGAIN;
@@ -5619,7 +5686,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
* and check for delegations in the process of being recalled.
* If not found, create the nfs4_file struct
*/
- fp = find_or_add_file(open->op_file, current_fh);
+ fp = nfsd4_file_hash_insert(open->op_file, current_fh);
+ if (unlikely(!fp))
+ return nfserr_jukebox;
if (fp != open->op_file) {
status = nfs4_check_deleg(cl, open, &dp);
if (status)
@@ -5896,7 +5965,7 @@ nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo)
list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) {
nf = stp->st_stid.sc_file;
- ctx = nf->fi_inode->i_flctx;
+ ctx = locks_inode_context(nf->fi_inode);
if (!ctx)
continue;
if (locks_owner_has_blockers(ctx, lo))
@@ -6124,17 +6193,64 @@ laundromat_main(struct work_struct *laundry)
}
static void
-courtesy_client_reaper(struct work_struct *reaper)
+courtesy_client_reaper(struct nfsd_net *nn)
{
struct list_head reaplist;
- struct delayed_work *dwork = to_delayed_work(reaper);
- struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
- nfsd_shrinker_work);
nfs4_get_courtesy_client_reaplist(nn, &reaplist);
nfs4_process_client_reaplist(&reaplist);
}
+static void
+deleg_reaper(struct nfsd_net *nn)
+{
+ struct list_head *pos, *next;
+ struct nfs4_client *clp;
+ struct list_head cblist;
+
+ INIT_LIST_HEAD(&cblist);
+ spin_lock(&nn->client_lock);
+ list_for_each_safe(pos, next, &nn->client_lru) {
+ clp = list_entry(pos, struct nfs4_client, cl_lru);
+ if (clp->cl_state != NFSD4_ACTIVE ||
+ list_empty(&clp->cl_delegations) ||
+ atomic_read(&clp->cl_delegs_in_recall) ||
+ test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
+ (ktime_get_boottime_seconds() -
+ clp->cl_ra_time < 5)) {
+ continue;
+ }
+ list_add(&clp->cl_ra_cblist, &cblist);
+
+ /* release in nfsd4_cb_recall_any_release */
+ atomic_inc(&clp->cl_rpc_users);
+ set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
+ clp->cl_ra_time = ktime_get_boottime_seconds();
+ }
+ spin_unlock(&nn->client_lock);
+
+ while (!list_empty(&cblist)) {
+ clp = list_first_entry(&cblist, struct nfs4_client,
+ cl_ra_cblist);
+ list_del_init(&clp->cl_ra_cblist);
+ clp->cl_ra->ra_keep = 0;
+ clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG);
+ trace_nfsd_cb_recall_any(clp->cl_ra);
+ nfsd4_run_cb(&clp->cl_ra->ra_cb);
+ }
+}
+
+static void
+nfsd4_state_shrinker_worker(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
+ nfsd_shrinker_work);
+
+ courtesy_client_reaper(nn);
+ deleg_reaper(nn);
+}
+
static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
{
if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
@@ -6901,6 +7017,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status)
goto put_stateid;
+ trace_nfsd_deleg_return(stateid);
wake_up_var(d_inode(cstate->current_fh.fh_dentry));
destroy_delegation(dp);
put_stateid:
@@ -7712,7 +7829,7 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
}
inode = locks_inode(nf->nf_file);
- flctx = inode->i_flctx;
+ flctx = locks_inode_context(inode);
if (flctx && !list_empty_careful(&flctx->flc_posix)) {
spin_lock(&flctx->flc_lock);
@@ -7957,7 +8074,7 @@ static int nfs4_state_create_net(struct net *net)
INIT_LIST_HEAD(&nn->blocked_locks_lru);
INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
- INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, courtesy_client_reaper);
+ INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
get_net(net);
return 0;
@@ -8033,10 +8150,16 @@ nfs4_state_start(void)
{
int ret;
- ret = nfsd4_create_callback_queue();
+ ret = rhltable_init(&nfs4_file_rhltable, &nfs4_file_rhash_params);
if (ret)
return ret;
+ ret = nfsd4_create_callback_queue();
+ if (ret) {
+ rhltable_destroy(&nfs4_file_rhltable);
+ return ret;
+ }
+
set_max_delegations();
return 0;
}
@@ -8067,6 +8190,7 @@ nfs4_state_shutdown_net(struct net *net)
nfsd4_client_tracking_exit(net);
nfs4_state_destroy_net(net);
+ rhltable_destroy(&nfs4_file_rhltable);
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
nfsd4_ssc_shutdown_umount(nn);
#endif
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bcfeb1a922c0..2b4ae858c89b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -770,16 +770,18 @@ nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
static __be32
nfsd4_decode_access(struct nfsd4_compoundargs *argp,
- struct nfsd4_access *access)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_access *access = &u->access;
if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0)
return nfserr_bad_xdr;
return nfs_ok;
}
static __be32
-nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
+nfsd4_decode_close(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_close *close = &u->close;
if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0)
return nfserr_bad_xdr;
return nfsd4_decode_stateid4(argp, &close->cl_stateid);
@@ -787,8 +789,9 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
static __be32
-nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
+nfsd4_decode_commit(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_commit *commit = &u->commit;
if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0)
return nfserr_bad_xdr;
if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0)
@@ -798,8 +801,9 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit
}
static __be32
-nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
+nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_create *create = &u->create;
__be32 *p, status;
memset(create, 0, sizeof(*create));
@@ -844,22 +848,25 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
}
static inline __be32
-nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
+nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_delegreturn *dr = &u->delegreturn;
return nfsd4_decode_stateid4(argp, &dr->dr_stateid);
}
static inline __be32
-nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
+nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_getattr *getattr = &u->getattr;
memset(getattr, 0, sizeof(*getattr));
return nfsd4_decode_bitmap4(argp, getattr->ga_bmval,
ARRAY_SIZE(getattr->ga_bmval));
}
static __be32
-nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
+nfsd4_decode_link(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_link *link = &u->link;
memset(link, 0, sizeof(*link));
return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen);
}
@@ -907,8 +914,9 @@ nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
}
static __be32
-nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
+nfsd4_decode_lock(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_lock *lock = &u->lock;
memset(lock, 0, sizeof(*lock));
if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0)
return nfserr_bad_xdr;
@@ -924,8 +932,9 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
}
static __be32
-nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
+nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_lockt *lockt = &u->lockt;
memset(lockt, 0, sizeof(*lockt));
if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0)
return nfserr_bad_xdr;
@@ -940,8 +949,9 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
}
static __be32
-nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
+nfsd4_decode_locku(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_locku *locku = &u->locku;
__be32 status;
if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0)
@@ -962,8 +972,9 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
}
static __be32
-nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
+nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_lookup *lookup = &u->lookup;
return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len);
}
@@ -1143,8 +1154,9 @@ nfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp,
}
static __be32
-nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
+nfsd4_decode_open(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_open *open = &u->open;
__be32 status;
u32 dummy;
@@ -1171,8 +1183,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
}
static __be32
-nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
+nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_open_confirm *open_conf = &u->open_confirm;
__be32 status;
if (argp->minorversion >= 1)
@@ -1190,8 +1204,10 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
}
static __be32
-nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
+nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_open_downgrade *open_down = &u->open_downgrade;
__be32 status;
memset(open_down, 0, sizeof(*open_down));
@@ -1209,8 +1225,9 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
}
static __be32
-nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
+nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_putfh *putfh = &u->putfh;
__be32 *p;
if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0)
@@ -1229,7 +1246,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
}
static __be32
-nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
+nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
{
if (argp->minorversion == 0)
return nfs_ok;
@@ -1237,8 +1254,9 @@ nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
}
static __be32
-nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
+nfsd4_decode_read(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_read *read = &u->read;
__be32 status;
memset(read, 0, sizeof(*read));
@@ -1254,8 +1272,9 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
}
static __be32
-nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
+nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_readdir *readdir = &u->readdir;
__be32 status;
memset(readdir, 0, sizeof(*readdir));
@@ -1276,15 +1295,17 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read
}
static __be32
-nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
+nfsd4_decode_remove(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_remove *remove = &u->remove;
memset(&remove->rm_cinfo, 0, sizeof(remove->rm_cinfo));
return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen);
}
static __be32
-nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
+nfsd4_decode_rename(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_rename *rename = &u->rename;
__be32 status;
memset(rename, 0, sizeof(*rename));
@@ -1295,22 +1316,25 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename
}
static __be32
-nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
+nfsd4_decode_renew(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ clientid_t *clientid = &u->renew;
return nfsd4_decode_clientid4(argp, clientid);
}
static __be32
nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
- struct nfsd4_secinfo *secinfo)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_secinfo *secinfo = &u->secinfo;
secinfo->si_exp = NULL;
return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen);
}
static __be32
-nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
+nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_setattr *setattr = &u->setattr;
__be32 status;
memset(setattr, 0, sizeof(*setattr));
@@ -1324,8 +1348,9 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
}
static __be32
-nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
+nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_setclientid *setclientid = &u->setclientid;
__be32 *p, status;
memset(setclientid, 0, sizeof(*setclientid));
@@ -1367,8 +1392,10 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
}
static __be32
-nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
+nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_setclientid_confirm *scd_c = &u->setclientid_confirm;
__be32 status;
if (argp->minorversion >= 1)
@@ -1382,8 +1409,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
/* Also used for NVERIFY */
static __be32
-nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
+nfsd4_decode_verify(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_verify *verify = &u->verify;
__be32 *p, status;
memset(verify, 0, sizeof(*verify));
@@ -1409,8 +1437,9 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
}
static __be32
-nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
+nfsd4_decode_write(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_write *write = &u->write;
__be32 status;
status = nfsd4_decode_stateid4(argp, &write->wr_stateid);
@@ -1434,8 +1463,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
}
static __be32
-nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
+nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
__be32 status;
if (argp->minorversion >= 1)
@@ -1452,16 +1483,20 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
return nfs_ok;
}
-static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc)
+static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
memset(bc, 0, sizeof(*bc));
if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0)
return nfserr_bad_xdr;
return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
}
-static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
+static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
u32 use_conn_in_rdma_mode;
__be32 status;
@@ -1603,8 +1638,9 @@ nfsd4_decode_nfs_impl_id4(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
- struct nfsd4_exchange_id *exid)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_exchange_id *exid = &u->exchange_id;
__be32 status;
memset(exid, 0, sizeof(*exid));
@@ -1656,8 +1692,9 @@ nfsd4_decode_channel_attrs4(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
- struct nfsd4_create_session *sess)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_create_session *sess = &u->create_session;
__be32 status;
memset(sess, 0, sizeof(*sess));
@@ -1681,23 +1718,26 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
- struct nfsd4_destroy_session *destroy_session)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_destroy_session *destroy_session = &u->destroy_session;
return nfsd4_decode_sessionid4(argp, &destroy_session->sessionid);
}
static __be32
nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
- struct nfsd4_free_stateid *free_stateid)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
}
#ifdef CONFIG_NFSD_PNFS
static __be32
nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
- struct nfsd4_getdeviceinfo *gdev)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
__be32 status;
memset(gdev, 0, sizeof(*gdev));
@@ -1717,8 +1757,9 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
- struct nfsd4_layoutcommit *lcp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
__be32 *p, status;
memset(lcp, 0, sizeof(*lcp));
@@ -1753,8 +1794,9 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
- struct nfsd4_layoutget *lgp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutget *lgp = &u->layoutget;
__be32 status;
memset(lgp, 0, sizeof(*lgp));
@@ -1781,8 +1823,9 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
- struct nfsd4_layoutreturn *lrp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
memset(lrp, 0, sizeof(*lrp));
if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0)
return nfserr_bad_xdr;
@@ -1795,8 +1838,9 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
#endif /* CONFIG_NFSD_PNFS */
static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
- struct nfsd4_secinfo_no_name *sin)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_secinfo_no_name *sin = &u->secinfo_no_name;
if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0)
return nfserr_bad_xdr;
@@ -1806,8 +1850,9 @@ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
- struct nfsd4_sequence *seq)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_sequence *seq = &u->sequence;
__be32 *p, status;
status = nfsd4_decode_sessionid4(argp, &seq->sessionid);
@@ -1826,8 +1871,10 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
}
static __be32
-nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
+nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
struct nfsd4_test_stateid_id *stateid;
__be32 status;
u32 i;
@@ -1852,14 +1899,16 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta
}
static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp,
- struct nfsd4_destroy_clientid *dc)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
return nfsd4_decode_clientid4(argp, &dc->clientid);
}
static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp,
- struct nfsd4_reclaim_complete *rc)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
if (xdr_stream_decode_bool(argp->xdr, &rc->rca_one_fs) < 0)
return nfserr_bad_xdr;
return nfs_ok;
@@ -1867,8 +1916,9 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
- struct nfsd4_fallocate *fallocate)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_fallocate *fallocate = &u->allocate;
__be32 status;
status = nfsd4_decode_stateid4(argp, &fallocate->falloc_stateid);
@@ -1924,8 +1974,9 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
}
static __be32
-nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
+nfsd4_decode_copy(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_copy *copy = &u->copy;
u32 consecutive, i, count, sync;
struct nl4_server *ns_dummy;
__be32 status;
@@ -1982,8 +2033,9 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
static __be32
nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
- struct nfsd4_copy_notify *cn)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_copy_notify *cn = &u->copy_notify;
__be32 status;
memset(cn, 0, sizeof(*cn));
@@ -2002,16 +2054,18 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp,
- struct nfsd4_offload_status *os)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_offload_status *os = &u->offload_status;
os->count = 0;
os->status = 0;
return nfsd4_decode_stateid4(argp, &os->stateid);
}
static __be32
-nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
+nfsd4_decode_seek(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_seek *seek = &u->seek;
__be32 status;
status = nfsd4_decode_stateid4(argp, &seek->seek_stateid);
@@ -2028,8 +2082,9 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
}
static __be32
-nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
+nfsd4_decode_clone(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
{
+ struct nfsd4_clone *clone = &u->clone;
__be32 status;
status = nfsd4_decode_stateid4(argp, &clone->cl_src_stateid);
@@ -2154,8 +2209,9 @@ nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep)
*/
static __be32
nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp,
- struct nfsd4_getxattr *getxattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_getxattr *getxattr = &u->getxattr;
__be32 status;
u32 maxcount;
@@ -2173,8 +2229,9 @@ nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp,
- struct nfsd4_setxattr *setxattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_setxattr *setxattr = &u->setxattr;
u32 flags, maxcount, size;
__be32 status;
@@ -2214,8 +2271,9 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp,
- struct nfsd4_listxattrs *listxattrs)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
u32 maxcount;
memset(listxattrs, 0, sizeof(*listxattrs));
@@ -2245,113 +2303,114 @@ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp,
- struct nfsd4_removexattr *removexattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_removexattr *removexattr = &u->removexattr;
memset(removexattr, 0, sizeof(*removexattr));
return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name);
}
static __be32
-nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
+nfsd4_decode_noop(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
{
return nfs_ok;
}
static __be32
-nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
+nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
{
return nfserr_notsupp;
}
-typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
+typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u);
static const nfsd4_dec nfsd4_dec_ops[] = {
- [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
- [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
- [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
- [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
- [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
- [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
- [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
- [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
- [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
- [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
- [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
- [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
- [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
- [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
- [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
- [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh,
- [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
- [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
- [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
- [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
- [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
- [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
- [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
- [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
- [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
- [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
- [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
+ [OP_ACCESS] = nfsd4_decode_access,
+ [OP_CLOSE] = nfsd4_decode_close,
+ [OP_COMMIT] = nfsd4_decode_commit,
+ [OP_CREATE] = nfsd4_decode_create,
+ [OP_DELEGPURGE] = nfsd4_decode_notsupp,
+ [OP_DELEGRETURN] = nfsd4_decode_delegreturn,
+ [OP_GETATTR] = nfsd4_decode_getattr,
+ [OP_GETFH] = nfsd4_decode_noop,
+ [OP_LINK] = nfsd4_decode_link,
+ [OP_LOCK] = nfsd4_decode_lock,
+ [OP_LOCKT] = nfsd4_decode_lockt,
+ [OP_LOCKU] = nfsd4_decode_locku,
+ [OP_LOOKUP] = nfsd4_decode_lookup,
+ [OP_LOOKUPP] = nfsd4_decode_noop,
+ [OP_NVERIFY] = nfsd4_decode_verify,
+ [OP_OPEN] = nfsd4_decode_open,
+ [OP_OPENATTR] = nfsd4_decode_notsupp,
+ [OP_OPEN_CONFIRM] = nfsd4_decode_open_confirm,
+ [OP_OPEN_DOWNGRADE] = nfsd4_decode_open_downgrade,
+ [OP_PUTFH] = nfsd4_decode_putfh,
+ [OP_PUTPUBFH] = nfsd4_decode_putpubfh,
+ [OP_PUTROOTFH] = nfsd4_decode_noop,
+ [OP_READ] = nfsd4_decode_read,
+ [OP_READDIR] = nfsd4_decode_readdir,
+ [OP_READLINK] = nfsd4_decode_noop,
+ [OP_REMOVE] = nfsd4_decode_remove,
+ [OP_RENAME] = nfsd4_decode_rename,
+ [OP_RENEW] = nfsd4_decode_renew,
+ [OP_RESTOREFH] = nfsd4_decode_noop,
+ [OP_SAVEFH] = nfsd4_decode_noop,
+ [OP_SECINFO] = nfsd4_decode_secinfo,
+ [OP_SETATTR] = nfsd4_decode_setattr,
+ [OP_SETCLIENTID] = nfsd4_decode_setclientid,
+ [OP_SETCLIENTID_CONFIRM] = nfsd4_decode_setclientid_confirm,
+ [OP_VERIFY] = nfsd4_decode_verify,
+ [OP_WRITE] = nfsd4_decode_write,
+ [OP_RELEASE_LOCKOWNER] = nfsd4_decode_release_lockowner,
/* new operations for NFSv4.1 */
- [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
- [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
- [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
- [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
- [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
- [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_BACKCHANNEL_CTL] = nfsd4_decode_backchannel_ctl,
+ [OP_BIND_CONN_TO_SESSION] = nfsd4_decode_bind_conn_to_session,
+ [OP_EXCHANGE_ID] = nfsd4_decode_exchange_id,
+ [OP_CREATE_SESSION] = nfsd4_decode_create_session,
+ [OP_DESTROY_SESSION] = nfsd4_decode_destroy_session,
+ [OP_FREE_STATEID] = nfsd4_decode_free_stateid,
+ [OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp,
#ifdef CONFIG_NFSD_PNFS
- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo,
- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit,
- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget,
- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn,
+ [OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo,
+ [OP_GETDEVICELIST] = nfsd4_decode_notsupp,
+ [OP_LAYOUTCOMMIT] = nfsd4_decode_layoutcommit,
+ [OP_LAYOUTGET] = nfsd4_decode_layoutget,
+ [OP_LAYOUTRETURN] = nfsd4_decode_layoutreturn,
#else
- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_GETDEVICEINFO] = nfsd4_decode_notsupp,
+ [OP_GETDEVICELIST] = nfsd4_decode_notsupp,
+ [OP_LAYOUTCOMMIT] = nfsd4_decode_notsupp,
+ [OP_LAYOUTGET] = nfsd4_decode_notsupp,
+ [OP_LAYOUTRETURN] = nfsd4_decode_notsupp,
#endif
- [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
- [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
- [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
- [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
- [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
+ [OP_SECINFO_NO_NAME] = nfsd4_decode_secinfo_no_name,
+ [OP_SEQUENCE] = nfsd4_decode_sequence,
+ [OP_SET_SSV] = nfsd4_decode_notsupp,
+ [OP_TEST_STATEID] = nfsd4_decode_test_stateid,
+ [OP_WANT_DELEGATION] = nfsd4_decode_notsupp,
+ [OP_DESTROY_CLIENTID] = nfsd4_decode_destroy_clientid,
+ [OP_RECLAIM_COMPLETE] = nfsd4_decode_reclaim_complete,
/* new operations for NFSv4.2 */
- [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
- [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy,
- [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify,
- [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
- [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
- [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
- [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
- [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
- [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
+ [OP_ALLOCATE] = nfsd4_decode_fallocate,
+ [OP_COPY] = nfsd4_decode_copy,
+ [OP_COPY_NOTIFY] = nfsd4_decode_copy_notify,
+ [OP_DEALLOCATE] = nfsd4_decode_fallocate,
+ [OP_IO_ADVISE] = nfsd4_decode_notsupp,
+ [OP_LAYOUTERROR] = nfsd4_decode_notsupp,
+ [OP_LAYOUTSTATS] = nfsd4_decode_notsupp,
+ [OP_OFFLOAD_CANCEL] = nfsd4_decode_offload_status,
+ [OP_OFFLOAD_STATUS] = nfsd4_decode_offload_status,
+ [OP_READ_PLUS] = nfsd4_decode_read,
+ [OP_SEEK] = nfsd4_decode_seek,
+ [OP_WRITE_SAME] = nfsd4_decode_notsupp,
+ [OP_CLONE] = nfsd4_decode_clone,
/* RFC 8276 extended atributes operations */
- [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr,
- [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr,
- [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs,
- [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr,
+ [OP_GETXATTR] = nfsd4_decode_getxattr,
+ [OP_SETXATTR] = nfsd4_decode_setxattr,
+ [OP_LISTXATTRS] = nfsd4_decode_listxattrs,
+ [OP_REMOVEXATTR] = nfsd4_decode_removexattr,
};
static inline bool
@@ -3630,8 +3689,10 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
}
static __be32
-nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
+nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_access *access = &u->access;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3643,8 +3704,10 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
return 0;
}
-static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
+static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3660,8 +3723,10 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,
}
static __be32
-nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
+nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_close *close = &u->close;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_encode_stateid(xdr, &close->cl_stateid);
@@ -3669,8 +3734,10 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
static __be32
-nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
+nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_commit *commit = &u->commit;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3683,8 +3750,10 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
}
static __be32
-nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
+nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_create *create = &u->create;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3697,8 +3766,10 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
}
static __be32
-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
+nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_getattr *getattr = &u->getattr;
struct svc_fh *fhp = getattr->ga_fhp;
struct xdr_stream *xdr = resp->xdr;
@@ -3707,8 +3778,10 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
}
static __be32
-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
+nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct svc_fh **fhpp = &u->getfh;
struct xdr_stream *xdr = resp->xdr;
struct svc_fh *fhp = *fhpp;
unsigned int len;
@@ -3762,8 +3835,10 @@ again:
}
static __be32
-nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
+nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_lock *lock = &u->lock;
struct xdr_stream *xdr = resp->xdr;
if (!nfserr)
@@ -3775,8 +3850,10 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
}
static __be32
-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
+nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_lockt *lockt = &u->lockt;
struct xdr_stream *xdr = resp->xdr;
if (nfserr == nfserr_denied)
@@ -3785,8 +3862,10 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
}
static __be32
-nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
+nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_locku *locku = &u->locku;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
@@ -3794,8 +3873,10 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
static __be32
-nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
+nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_link *link = &u->link;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3808,8 +3889,10 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
static __be32
-nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
+nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_open *open = &u->open;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -3902,16 +3985,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
}
static __be32
-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
+nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_open_confirm *oc = &u->open_confirm;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
}
static __be32
-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
+nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_open_downgrade *od = &u->open_downgrade;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_encode_stateid(xdr, &od->od_stateid);
@@ -4010,8 +4097,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
static __be32
nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_read *read)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_read *read = &u->read;
bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
unsigned long maxcount;
struct xdr_stream *xdr = resp->xdr;
@@ -4052,8 +4140,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
}
static __be32
-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
+nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_readlink *readlink = &u->readlink;
__be32 *p, *maxcount_p, zero = xdr_zero;
struct xdr_stream *xdr = resp->xdr;
int length_offset = xdr->buf->len;
@@ -4097,8 +4187,10 @@ out_err:
}
static __be32
-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
+nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_readdir *readdir = &u->readdir;
int maxcount;
int bytes_left;
loff_t offset;
@@ -4188,8 +4280,10 @@ err_no_verf:
}
static __be32
-nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
+nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_remove *remove = &u->remove;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4201,8 +4295,10 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
}
static __be32
-nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
+nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_rename *rename = &u->rename;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4284,8 +4380,9 @@ nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp)
static __be32
nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_secinfo *secinfo)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_secinfo *secinfo = &u->secinfo;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
@@ -4293,8 +4390,9 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_secinfo_no_name *secinfo)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_secinfo_no_name *secinfo = &u->secinfo_no_name;
struct xdr_stream *xdr = resp->xdr;
return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
@@ -4305,8 +4403,10 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
* regardless of the error status.
*/
static __be32
-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
+nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_setattr *setattr = &u->setattr;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4329,8 +4429,10 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
}
static __be32
-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
+nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_setclientid *scd = &u->setclientid;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4353,8 +4455,10 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
}
static __be32
-nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
+nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *u)
{
+ struct nfsd4_write *write = &u->write;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4370,8 +4474,9 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
static __be32
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_exchange_id *exid)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_exchange_id *exid = &u->exchange_id;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
char *major_id;
@@ -4448,8 +4553,9 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_create_session *sess)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_create_session *sess = &u->create_session;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4501,8 +4607,9 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_sequence *seq)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_sequence *seq = &u->sequence;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4524,8 +4631,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_test_stateid *test_stateid)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
struct xdr_stream *xdr = resp->xdr;
struct nfsd4_test_stateid_id *stateid, *next;
__be32 *p;
@@ -4545,8 +4653,9 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
#ifdef CONFIG_NFSD_PNFS
static __be32
nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_getdeviceinfo *gdev)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
struct xdr_stream *xdr = resp->xdr;
const struct nfsd4_layout_ops *ops;
u32 starting_len = xdr->buf->len, needed_len;
@@ -4601,8 +4710,9 @@ toosmall:
static __be32
nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_layoutget *lgp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutget *lgp = &u->layoutget;
struct xdr_stream *xdr = resp->xdr;
const struct nfsd4_layout_ops *ops;
__be32 *p;
@@ -4628,8 +4738,9 @@ nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_layoutcommit *lcp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4649,8 +4760,9 @@ nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_layoutreturn *lrp)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4735,8 +4847,9 @@ nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
static __be32
nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_copy *copy)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_copy *copy = &u->copy;
__be32 *p;
nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
@@ -4752,8 +4865,9 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_offload_status *os)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_offload_status *os = &u->offload_status;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4767,156 +4881,83 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
- struct nfsd4_read *read,
- unsigned long *maxcount, u32 *eof,
- loff_t *pos)
+ struct nfsd4_read *read)
{
- struct xdr_stream *xdr = resp->xdr;
+ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
struct file *file = read->rd_nf->nf_file;
- int starting_len = xdr->buf->len;
- loff_t hole_pos;
- __be32 nfserr;
- __be32 *p, tmp;
- __be64 tmp64;
-
- hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE);
- if (hole_pos > read->rd_offset)
- *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset);
- *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len));
+ struct xdr_stream *xdr = resp->xdr;
+ unsigned long maxcount;
+ __be32 nfserr, *p;
/* Content type, offset, byte count */
p = xdr_reserve_space(xdr, 4 + 8 + 4);
if (!p)
- return nfserr_resource;
+ return nfserr_io;
+ if (resp->xdr->buf->page_len && splice_ok) {
+ WARN_ON_ONCE(splice_ok);
+ return nfserr_serverfault;
+ }
- read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount);
- if (read->rd_vlen < 0)
- return nfserr_resource;
+ maxcount = min_t(unsigned long, read->rd_length,
+ (xdr->buf->buflen - xdr->buf->len));
- nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
- resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
+ if (file->f_op->splice_read && splice_ok)
+ nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
+ else
+ nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
if (nfserr)
return nfserr;
- xdr_truncate_encode(xdr, starting_len + 16 + xdr_align_size(*maxcount));
-
- tmp = htonl(NFS4_CONTENT_DATA);
- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
- tmp64 = cpu_to_be64(read->rd_offset);
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
- tmp = htonl(*maxcount);
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
-
- tmp = xdr_zero;
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 16 + *maxcount, &tmp,
- xdr_pad_size(*maxcount));
- return nfs_ok;
-}
-
-static __be32
-nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
- struct nfsd4_read *read,
- unsigned long *maxcount, u32 *eof)
-{
- struct file *file = read->rd_nf->nf_file;
- loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
- loff_t f_size = i_size_read(file_inode(file));
- unsigned long count;
- __be32 *p;
-
- if (data_pos == -ENXIO)
- data_pos = f_size;
- else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE))
- return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size);
- count = data_pos - read->rd_offset;
- /* Content type, offset, byte count */
- p = xdr_reserve_space(resp->xdr, 4 + 8 + 8);
- if (!p)
- return nfserr_resource;
-
- *p++ = htonl(NFS4_CONTENT_HOLE);
+ *p++ = cpu_to_be32(NFS4_CONTENT_DATA);
p = xdr_encode_hyper(p, read->rd_offset);
- p = xdr_encode_hyper(p, count);
+ *p = cpu_to_be32(read->rd_length);
- *eof = (read->rd_offset + count) >= f_size;
- *maxcount = min_t(unsigned long, count, *maxcount);
return nfs_ok;
}
static __be32
nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_read *read)
+ union nfsd4_op_u *u)
{
- unsigned long maxcount, count;
+ struct nfsd4_read *read = &u->read;
+ struct file *file = read->rd_nf->nf_file;
struct xdr_stream *xdr = resp->xdr;
- struct file *file;
int starting_len = xdr->buf->len;
- int last_segment = xdr->buf->len;
- int segments = 0;
- __be32 *p, tmp;
- bool is_data;
- loff_t pos;
- u32 eof;
+ u32 segments = 0;
+ __be32 *p;
if (nfserr)
return nfserr;
- file = read->rd_nf->nf_file;
/* eof flag, segment count */
p = xdr_reserve_space(xdr, 4 + 4);
if (!p)
- return nfserr_resource;
+ return nfserr_io;
xdr_commit_encode(xdr);
- maxcount = min_t(unsigned long, read->rd_length,
- (xdr->buf->buflen - xdr->buf->len));
- count = maxcount;
-
- eof = read->rd_offset >= i_size_read(file_inode(file));
- if (eof)
+ read->rd_eof = read->rd_offset >= i_size_read(file_inode(file));
+ if (read->rd_eof)
goto out;
- pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
- is_data = pos > read->rd_offset;
-
- while (count > 0 && !eof) {
- maxcount = count;
- if (is_data)
- nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof,
- segments == 0 ? &pos : NULL);
- else
- nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof);
- if (nfserr)
- goto out;
- count -= maxcount;
- read->rd_offset += maxcount;
- is_data = !is_data;
- last_segment = xdr->buf->len;
- segments++;
- }
-
-out:
- if (nfserr && segments == 0)
+ nfserr = nfsd4_encode_read_plus_data(resp, read);
+ if (nfserr) {
xdr_truncate_encode(xdr, starting_len);
- else {
- if (nfserr) {
- xdr_truncate_encode(xdr, last_segment);
- nfserr = nfs_ok;
- eof = 0;
- }
- tmp = htonl(eof);
- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
- tmp = htonl(segments);
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
+ return nfserr;
}
+ segments++;
+
+out:
+ p = xdr_encode_bool(p, read->rd_eof);
+ *p = cpu_to_be32(segments);
return nfserr;
}
static __be32
nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_copy_notify *cn)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_copy_notify *cn = &u->copy_notify;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -4950,8 +4991,9 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_seek *seek)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_seek *seek = &u->seek;
__be32 *p;
p = xdr_reserve_space(resp->xdr, 4 + 8);
@@ -4962,7 +5004,8 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
}
static __be32
-nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
+nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr,
+ union nfsd4_op_u *p)
{
return nfserr;
}
@@ -5013,8 +5056,9 @@ nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen)
static __be32
nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_getxattr *getxattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_getxattr *getxattr = &u->getxattr;
struct xdr_stream *xdr = resp->xdr;
__be32 *p, err;
@@ -5037,8 +5081,9 @@ nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32
nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_setxattr *setxattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_setxattr *setxattr = &u->setxattr;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -5078,8 +5123,9 @@ nfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs,
static __be32
nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_listxattrs *listxattrs)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
struct xdr_stream *xdr = resp->xdr;
u32 cookie_offset, count_offset, eof;
u32 left, xdrleft, slen, count;
@@ -5189,8 +5235,9 @@ out:
static __be32
nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_removexattr *removexattr)
+ union nfsd4_op_u *u)
{
+ struct nfsd4_removexattr *removexattr = &u->removexattr;
struct xdr_stream *xdr = resp->xdr;
__be32 *p;
@@ -5202,7 +5249,7 @@ nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
return 0;
}
-typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
+typedef __be32(*nfsd4_enc)(struct nfsd4_compoundres *, __be32, union nfsd4_op_u *u);
/*
* Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
@@ -5210,93 +5257,93 @@ typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
* done in the decoding phase.
*/
static const nfsd4_enc nfsd4_enc_ops[] = {
- [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
- [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
- [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
- [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
- [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
- [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
- [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
- [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
- [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
- [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
- [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
- [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
- [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
- [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
- [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
- [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
- [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
- [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
- [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
- [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
- [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
- [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
- [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_ACCESS] = nfsd4_encode_access,
+ [OP_CLOSE] = nfsd4_encode_close,
+ [OP_COMMIT] = nfsd4_encode_commit,
+ [OP_CREATE] = nfsd4_encode_create,
+ [OP_DELEGPURGE] = nfsd4_encode_noop,
+ [OP_DELEGRETURN] = nfsd4_encode_noop,
+ [OP_GETATTR] = nfsd4_encode_getattr,
+ [OP_GETFH] = nfsd4_encode_getfh,
+ [OP_LINK] = nfsd4_encode_link,
+ [OP_LOCK] = nfsd4_encode_lock,
+ [OP_LOCKT] = nfsd4_encode_lockt,
+ [OP_LOCKU] = nfsd4_encode_locku,
+ [OP_LOOKUP] = nfsd4_encode_noop,
+ [OP_LOOKUPP] = nfsd4_encode_noop,
+ [OP_NVERIFY] = nfsd4_encode_noop,
+ [OP_OPEN] = nfsd4_encode_open,
+ [OP_OPENATTR] = nfsd4_encode_noop,
+ [OP_OPEN_CONFIRM] = nfsd4_encode_open_confirm,
+ [OP_OPEN_DOWNGRADE] = nfsd4_encode_open_downgrade,
+ [OP_PUTFH] = nfsd4_encode_noop,
+ [OP_PUTPUBFH] = nfsd4_encode_noop,
+ [OP_PUTROOTFH] = nfsd4_encode_noop,
+ [OP_READ] = nfsd4_encode_read,
+ [OP_READDIR] = nfsd4_encode_readdir,
+ [OP_READLINK] = nfsd4_encode_readlink,
+ [OP_REMOVE] = nfsd4_encode_remove,
+ [OP_RENAME] = nfsd4_encode_rename,
+ [OP_RENEW] = nfsd4_encode_noop,
+ [OP_RESTOREFH] = nfsd4_encode_noop,
+ [OP_SAVEFH] = nfsd4_encode_noop,
+ [OP_SECINFO] = nfsd4_encode_secinfo,
+ [OP_SETATTR] = nfsd4_encode_setattr,
+ [OP_SETCLIENTID] = nfsd4_encode_setclientid,
+ [OP_SETCLIENTID_CONFIRM] = nfsd4_encode_noop,
+ [OP_VERIFY] = nfsd4_encode_noop,
+ [OP_WRITE] = nfsd4_encode_write,
+ [OP_RELEASE_LOCKOWNER] = nfsd4_encode_noop,
/* NFSv4.1 operations */
- [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
- [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
- [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
- [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_BACKCHANNEL_CTL] = nfsd4_encode_noop,
+ [OP_BIND_CONN_TO_SESSION] = nfsd4_encode_bind_conn_to_session,
+ [OP_EXCHANGE_ID] = nfsd4_encode_exchange_id,
+ [OP_CREATE_SESSION] = nfsd4_encode_create_session,
+ [OP_DESTROY_SESSION] = nfsd4_encode_noop,
+ [OP_FREE_STATEID] = nfsd4_encode_noop,
+ [OP_GET_DIR_DELEGATION] = nfsd4_encode_noop,
#ifdef CONFIG_NFSD_PNFS
- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo,
- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit,
- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget,
- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn,
+ [OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo,
+ [OP_GETDEVICELIST] = nfsd4_encode_noop,
+ [OP_LAYOUTCOMMIT] = nfsd4_encode_layoutcommit,
+ [OP_LAYOUTGET] = nfsd4_encode_layoutget,
+ [OP_LAYOUTRETURN] = nfsd4_encode_layoutreturn,
#else
- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_GETDEVICEINFO] = nfsd4_encode_noop,
+ [OP_GETDEVICELIST] = nfsd4_encode_noop,
+ [OP_LAYOUTCOMMIT] = nfsd4_encode_noop,
+ [OP_LAYOUTGET] = nfsd4_encode_noop,
+ [OP_LAYOUTRETURN] = nfsd4_encode_noop,
#endif
- [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
- [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
- [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
- [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_SECINFO_NO_NAME] = nfsd4_encode_secinfo_no_name,
+ [OP_SEQUENCE] = nfsd4_encode_sequence,
+ [OP_SET_SSV] = nfsd4_encode_noop,
+ [OP_TEST_STATEID] = nfsd4_encode_test_stateid,
+ [OP_WANT_DELEGATION] = nfsd4_encode_noop,
+ [OP_DESTROY_CLIENTID] = nfsd4_encode_noop,
+ [OP_RECLAIM_COMPLETE] = nfsd4_encode_noop,
/* NFSv4.2 operations */
- [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy,
- [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify,
- [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
- [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
- [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
- [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_ALLOCATE] = nfsd4_encode_noop,
+ [OP_COPY] = nfsd4_encode_copy,
+ [OP_COPY_NOTIFY] = nfsd4_encode_copy_notify,
+ [OP_DEALLOCATE] = nfsd4_encode_noop,
+ [OP_IO_ADVISE] = nfsd4_encode_noop,
+ [OP_LAYOUTERROR] = nfsd4_encode_noop,
+ [OP_LAYOUTSTATS] = nfsd4_encode_noop,
+ [OP_OFFLOAD_CANCEL] = nfsd4_encode_noop,
+ [OP_OFFLOAD_STATUS] = nfsd4_encode_offload_status,
+ [OP_READ_PLUS] = nfsd4_encode_read_plus,
+ [OP_SEEK] = nfsd4_encode_seek,
+ [OP_WRITE_SAME] = nfsd4_encode_noop,
+ [OP_CLONE] = nfsd4_encode_noop,
/* RFC 8276 extended atributes operations */
- [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr,
- [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr,
- [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs,
- [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr,
+ [OP_GETXATTR] = nfsd4_encode_getxattr,
+ [OP_SETXATTR] = nfsd4_encode_setxattr,
+ [OP_LISTXATTRS] = nfsd4_encode_listxattrs,
+ [OP_REMOVEXATTR] = nfsd4_encode_removexattr,
};
/*
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index dc74a947a440..d1e581a60480 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -581,7 +581,9 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET;
switch(num) {
+#ifdef CONFIG_NFSD_V2
case 2:
+#endif
case 3:
nfsd_vers(nn, num, cmd);
break;
@@ -601,7 +603,9 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
}
break;
default:
- return -EINVAL;
+ /* Ignore requests to disable non-existent versions */
+ if (cmd == NFSD_SET)
+ return -EINVAL;
}
vers += len + 1;
} while ((len = qword_get(&mesg, vers, size)) > 0);
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 09726c5b9a31..93b42ef9ed91 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -64,8 +64,7 @@ struct readdir_cd {
extern struct svc_program nfsd_program;
-extern const struct svc_version nfsd_version2, nfsd_version3,
- nfsd_version4;
+extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
extern struct mutex nfsd_mutex;
extern spinlock_t nfsd_drc_lock;
extern unsigned long nfsd_drc_max_mem;
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index c3ae6414fc5c..513e028b0bbe 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -220,7 +220,7 @@ __be32 fh_update(struct svc_fh *);
void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
-fh_copy(struct svc_fh *dst, struct svc_fh *src)
+fh_copy(struct svc_fh *dst, const struct svc_fh *src)
{
WARN_ON(src->fh_dentry);
@@ -229,7 +229,7 @@ fh_copy(struct svc_fh *dst, struct svc_fh *src)
}
static inline void
-fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
+fh_copy_shallow(struct knfsd_fh *dst, const struct knfsd_fh *src)
{
dst->fh_size = src->fh_size;
memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size);
@@ -243,7 +243,8 @@ fh_init(struct svc_fh *fhp, int maxsize)
return fhp;
}
-static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
+static inline bool fh_match(const struct knfsd_fh *fh1,
+ const struct knfsd_fh *fh2)
{
if (fh1->fh_size != fh2->fh_size)
return false;
@@ -252,7 +253,8 @@ static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
return true;
}
-static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
+static inline bool fh_fsid_match(const struct knfsd_fh *fh1,
+ const struct knfsd_fh *fh2)
{
if (fh1->fh_fsid_type != fh2->fh_fsid_type)
return false;
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 82b3ddeacc33..a5570cf75f3f 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
if (resp->status == nfs_ok)
resp->status = fh_getattr(&resp->fh, &resp->stat);
else if (resp->status == nfserr_jukebox)
- return rpc_drop_reply;
+ __set_bit(RQ_DROPME, &rqstp->rq_flags);
return rpc_success;
}
@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
if (resp->status == nfs_ok)
resp->status = fh_getattr(&resp->fh, &resp->stat);
else if (resp->status == nfserr_jukebox)
- return rpc_drop_reply;
+ __set_bit(RQ_DROPME, &rqstp->rq_flags);
return rpc_success;
}
@@ -848,65 +848,3 @@ const struct svc_version nfsd_version2 = {
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS2_SVC_XDRSIZE,
};
-
-/*
- * Map errnos to NFS errnos.
- */
-__be32
-nfserrno (int errno)
-{
- static struct {
- __be32 nfserr;
- int syserr;
- } nfs_errtbl[] = {
- { nfs_ok, 0 },
- { nfserr_perm, -EPERM },
- { nfserr_noent, -ENOENT },
- { nfserr_io, -EIO },
- { nfserr_nxio, -ENXIO },
- { nfserr_fbig, -E2BIG },
- { nfserr_stale, -EBADF },
- { nfserr_acces, -EACCES },
- { nfserr_exist, -EEXIST },
- { nfserr_xdev, -EXDEV },
- { nfserr_mlink, -EMLINK },
- { nfserr_nodev, -ENODEV },
- { nfserr_notdir, -ENOTDIR },
- { nfserr_isdir, -EISDIR },
- { nfserr_inval, -EINVAL },
- { nfserr_fbig, -EFBIG },
- { nfserr_nospc, -ENOSPC },
- { nfserr_rofs, -EROFS },
- { nfserr_mlink, -EMLINK },
- { nfserr_nametoolong, -ENAMETOOLONG },
- { nfserr_notempty, -ENOTEMPTY },
-#ifdef EDQUOT
- { nfserr_dquot, -EDQUOT },
-#endif
- { nfserr_stale, -ESTALE },
- { nfserr_jukebox, -ETIMEDOUT },
- { nfserr_jukebox, -ERESTARTSYS },
- { nfserr_jukebox, -EAGAIN },
- { nfserr_jukebox, -EWOULDBLOCK },
- { nfserr_jukebox, -ENOMEM },
- { nfserr_io, -ETXTBSY },
- { nfserr_notsupp, -EOPNOTSUPP },
- { nfserr_toosmall, -ETOOSMALL },
- { nfserr_serverfault, -ESERVERFAULT },
- { nfserr_serverfault, -ENFILE },
- { nfserr_io, -EREMOTEIO },
- { nfserr_stale, -EOPENSTALE },
- { nfserr_io, -EUCLEAN },
- { nfserr_perm, -ENOKEY },
- { nfserr_no_grace, -ENOGRACE},
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
- if (nfs_errtbl[i].syserr == errno)
- return nfs_errtbl[i].nfserr;
- }
- WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
- return nfserr_io;
-}
-
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index bfbd9f672f59..56fba1cba3af 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -91,8 +91,12 @@ unsigned long nfsd_drc_mem_used;
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static struct svc_stat nfsd_acl_svcstats;
static const struct svc_version *nfsd_acl_version[] = {
+# if defined(CONFIG_NFSD_V2_ACL)
[2] = &nfsd_acl_version2,
+# endif
+# if defined(CONFIG_NFSD_V3_ACL)
[3] = &nfsd_acl_version3,
+# endif
};
#define NFSD_ACL_MINVERS 2
@@ -116,7 +120,9 @@ static struct svc_stat nfsd_acl_svcstats = {
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
static const struct svc_version *nfsd_version[] = {
+#if defined(CONFIG_NFSD_V2)
[2] = &nfsd_version2,
+#endif
[3] = &nfsd_version3,
#if defined(CONFIG_NFSD_V4)
[4] = &nfsd_version4,
@@ -1054,7 +1060,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
svcxdr_init_encode(rqstp);
*statp = proc->pc_func(rqstp);
- if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
+ if (test_bit(RQ_DROPME, &rqstp->rq_flags))
goto out_update_drop;
if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream))
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e2daef3cc003..e94634d30591 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -368,6 +368,7 @@ struct nfs4_client {
#define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
1 << NFSD4_CLIENT_CB_KILL)
+#define NFSD4_CLIENT_CB_RECALL_ANY (6)
unsigned long cl_flags;
const struct cred *cl_cb_cred;
struct rpc_clnt *cl_cb_client;
@@ -411,6 +412,10 @@ struct nfs4_client {
unsigned int cl_state;
atomic_t cl_delegs_in_recall;
+
+ struct nfsd4_cb_recall_any *cl_ra;
+ time64_t cl_ra_time;
+ struct list_head cl_ra_cblist;
};
/* struct nfs4_client_reset
@@ -536,16 +541,13 @@ struct nfs4_clnt_odstate {
* inode can have multiple filehandles associated with it, so there is
* (potentially) a many to one relationship between this struct and struct
* inode.
- *
- * These are hashed by filehandle in the file_hashtbl, which is protected by
- * the global state_lock spinlock.
*/
struct nfs4_file {
refcount_t fi_ref;
struct inode * fi_inode;
bool fi_aliased;
spinlock_t fi_lock;
- struct hlist_node fi_hash; /* hash on fi_fhandle */
+ struct rhlist_head fi_rlist;
struct list_head fi_stateids;
union {
struct list_head fi_delegations;
@@ -639,6 +641,7 @@ enum nfsd4_cb_op {
NFSPROC4_CLNT_CB_OFFLOAD,
NFSPROC4_CLNT_CB_SEQUENCE,
NFSPROC4_CLNT_CB_NOTIFY_LOCK,
+ NFSPROC4_CLNT_CB_RECALL_ANY,
};
/* Returns true iff a is later than b: */
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 06a96e955bd0..46b8f68a2497 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -9,9 +9,12 @@
#define _NFSD_TRACE_H
#include <linux/tracepoint.h>
+#include <linux/sunrpc/xprt.h>
+#include <trace/misc/nfs.h>
#include "export.h"
#include "nfsfh.h"
+#include "xdr4.h"
#define NFSD_TRACE_PROC_RES_FIELDS \
__field(unsigned int, netns_ino) \
@@ -254,7 +257,10 @@ TRACE_EVENT_CONDITION(nfsd_fh_verify_err,
rqstp->rq_xprt->xpt_remotelen);
__entry->xid = be32_to_cpu(rqstp->rq_xid);
__entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
- __entry->inode = d_inode(fhp->fh_dentry);
+ if (fhp->fh_dentry)
+ __entry->inode = d_inode(fhp->fh_dentry);
+ else
+ __entry->inode = NULL;
__entry->type = type;
__entry->access = access;
__entry->error = be32_to_cpu(error);
@@ -601,6 +607,7 @@ DEFINE_STATEID_EVENT(layout_recall_release);
DEFINE_STATEID_EVENT(open);
DEFINE_STATEID_EVENT(deleg_read);
+DEFINE_STATEID_EVENT(deleg_return);
DEFINE_STATEID_EVENT(deleg_recall);
DECLARE_EVENT_CLASS(nfsd_stateseqid_class,
@@ -633,6 +640,61 @@ DEFINE_EVENT(nfsd_stateseqid_class, nfsd_##name, \
DEFINE_STATESEQID_EVENT(preprocess);
DEFINE_STATESEQID_EVENT(open_confirm);
+TRACE_DEFINE_ENUM(NFS4_OPEN_STID);
+TRACE_DEFINE_ENUM(NFS4_LOCK_STID);
+TRACE_DEFINE_ENUM(NFS4_DELEG_STID);
+TRACE_DEFINE_ENUM(NFS4_CLOSED_STID);
+TRACE_DEFINE_ENUM(NFS4_REVOKED_DELEG_STID);
+TRACE_DEFINE_ENUM(NFS4_CLOSED_DELEG_STID);
+TRACE_DEFINE_ENUM(NFS4_LAYOUT_STID);
+
+#define show_stid_type(x) \
+ __print_flags(x, "|", \
+ { NFS4_OPEN_STID, "OPEN" }, \
+ { NFS4_LOCK_STID, "LOCK" }, \
+ { NFS4_DELEG_STID, "DELEG" }, \
+ { NFS4_CLOSED_STID, "CLOSED" }, \
+ { NFS4_REVOKED_DELEG_STID, "REVOKED" }, \
+ { NFS4_CLOSED_DELEG_STID, "CLOSED_DELEG" }, \
+ { NFS4_LAYOUT_STID, "LAYOUT" })
+
+DECLARE_EVENT_CLASS(nfsd_stid_class,
+ TP_PROTO(
+ const struct nfs4_stid *stid
+ ),
+ TP_ARGS(stid),
+ TP_STRUCT__entry(
+ __field(unsigned long, sc_type)
+ __field(int, sc_count)
+ __field(u32, cl_boot)
+ __field(u32, cl_id)
+ __field(u32, si_id)
+ __field(u32, si_generation)
+ ),
+ TP_fast_assign(
+ const stateid_t *stp = &stid->sc_stateid;
+
+ __entry->sc_type = stid->sc_type;
+ __entry->sc_count = refcount_read(&stid->sc_count);
+ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot;
+ __entry->cl_id = stp->si_opaque.so_clid.cl_id;
+ __entry->si_id = stp->si_opaque.so_id;
+ __entry->si_generation = stp->si_generation;
+ ),
+ TP_printk("client %08x:%08x stateid %08x:%08x ref=%d type=%s",
+ __entry->cl_boot, __entry->cl_id,
+ __entry->si_id, __entry->si_generation,
+ __entry->sc_count, show_stid_type(__entry->sc_type)
+ )
+);
+
+#define DEFINE_STID_EVENT(name) \
+DEFINE_EVENT(nfsd_stid_class, nfsd_stid_##name, \
+ TP_PROTO(const struct nfs4_stid *stid), \
+ TP_ARGS(stid))
+
+DEFINE_STID_EVENT(revoke);
+
DECLARE_EVENT_CLASS(nfsd_clientid_class,
TP_PROTO(const clientid_t *clid),
TP_ARGS(clid),
@@ -814,7 +876,8 @@ DEFINE_CLID_EVENT(confirmed_r);
__print_flags(val, "|", \
{ 1 << NFSD_FILE_HASHED, "HASHED" }, \
{ 1 << NFSD_FILE_PENDING, "PENDING" }, \
- { 1 << NFSD_FILE_REFERENCED, "REFERENCED"})
+ { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}, \
+ { 1 << NFSD_FILE_GC, "GC"})
DECLARE_EVENT_CLASS(nfsd_file_class,
TP_PROTO(struct nfsd_file *nf),
@@ -846,10 +909,10 @@ DEFINE_EVENT(nfsd_file_class, name, \
TP_PROTO(struct nfsd_file *nf), \
TP_ARGS(nf))
-DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final);
+DEFINE_NFSD_FILE_EVENT(nfsd_file_free);
DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash);
DEFINE_NFSD_FILE_EVENT(nfsd_file_put);
-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose);
+DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_queue);
TRACE_EVENT(nfsd_file_alloc,
TP_PROTO(
@@ -1178,6 +1241,37 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name, \
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
+TRACE_EVENT(nfsd_file_fsync,
+ TP_PROTO(
+ const struct nfsd_file *nf,
+ int ret
+ ),
+ TP_ARGS(nf, ret),
+ TP_STRUCT__entry(
+ __field(void *, nf_inode)
+ __field(int, nf_ref)
+ __field(int, ret)
+ __field(unsigned long, nf_flags)
+ __field(unsigned char, nf_may)
+ __field(struct file *, nf_file)
+ ),
+ TP_fast_assign(
+ __entry->nf_inode = nf->nf_inode;
+ __entry->nf_ref = refcount_read(&nf->nf_ref);
+ __entry->ret = ret;
+ __entry->nf_flags = nf->nf_flags;
+ __entry->nf_may = nf->nf_may;
+ __entry->nf_file = nf->nf_file;
+ ),
+ TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p ret=%d",
+ __entry->nf_inode,
+ __entry->nf_ref,
+ show_nf_flags(__entry->nf_flags),
+ show_nfsd_may_flags(__entry->nf_may),
+ __entry->nf_file, __entry->ret
+ )
+);
+
#include "cache.h"
TRACE_DEFINE_ENUM(RC_DROPIT);
@@ -1471,6 +1565,32 @@ TRACE_EVENT(nfsd_cb_offload,
__entry->fh_hash, __entry->count, __entry->status)
);
+TRACE_EVENT(nfsd_cb_recall_any,
+ TP_PROTO(
+ const struct nfsd4_cb_recall_any *ra
+ ),
+ TP_ARGS(ra),
+ TP_STRUCT__entry(
+ __field(u32, cl_boot)
+ __field(u32, cl_id)
+ __field(u32, keep)
+ __field(unsigned long, bmval0)
+ __sockaddr(addr, ra->ra_cb.cb_clp->cl_cb_conn.cb_addrlen)
+ ),
+ TP_fast_assign(
+ __entry->cl_boot = ra->ra_cb.cb_clp->cl_clientid.cl_boot;
+ __entry->cl_id = ra->ra_cb.cb_clp->cl_clientid.cl_id;
+ __entry->keep = ra->ra_keep;
+ __entry->bmval0 = ra->ra_bmval[0];
+ __assign_sockaddr(addr, &ra->ra_cb.cb_clp->cl_addr,
+ ra->ra_cb.cb_clp->cl_cb_conn.cb_addrlen);
+ ),
+ TP_printk("addr=%pISpc client %08x:%08x keep=%u bmval0=%s",
+ __get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
+ __entry->keep, show_rca_mask(__entry->bmval0)
+ )
+);
+
DECLARE_EVENT_CLASS(nfsd_cb_done_class,
TP_PROTO(
const stateid_t *stp,
@@ -1510,6 +1630,27 @@ DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_notify_lock_done);
DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_layout_done);
DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_offload_done);
+TRACE_EVENT(nfsd_cb_recall_any_done,
+ TP_PROTO(
+ const struct nfsd4_callback *cb,
+ const struct rpc_task *task
+ ),
+ TP_ARGS(cb, task),
+ TP_STRUCT__entry(
+ __field(u32, cl_boot)
+ __field(u32, cl_id)
+ __field(int, status)
+ ),
+ TP_fast_assign(
+ __entry->status = task->tk_status;
+ __entry->cl_boot = cb->cb_clp->cl_clientid.cl_boot;
+ __entry->cl_id = cb->cb_clp->cl_clientid.cl_id;
+ ),
+ TP_printk("client %08x:%08x status=%d",
+ __entry->cl_boot, __entry->cl_id, __entry->status
+ )
+);
+
#endif /* _NFSD_TRACE_H */
#undef TRACE_INCLUDE_PATH
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f650afedd67f..4c3a0d84043c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -49,6 +49,69 @@
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
+/**
+ * nfserrno - Map Linux errnos to NFS errnos
+ * @errno: POSIX(-ish) error code to be mapped
+ *
+ * Returns the appropriate (net-endian) nfserr_* (or nfs_ok if errno is 0). If
+ * it's an error we don't expect, log it once and return nfserr_io.
+ */
+__be32
+nfserrno (int errno)
+{
+ static struct {
+ __be32 nfserr;
+ int syserr;
+ } nfs_errtbl[] = {
+ { nfs_ok, 0 },
+ { nfserr_perm, -EPERM },
+ { nfserr_noent, -ENOENT },
+ { nfserr_io, -EIO },
+ { nfserr_nxio, -ENXIO },
+ { nfserr_fbig, -E2BIG },
+ { nfserr_stale, -EBADF },
+ { nfserr_acces, -EACCES },
+ { nfserr_exist, -EEXIST },
+ { nfserr_xdev, -EXDEV },
+ { nfserr_mlink, -EMLINK },
+ { nfserr_nodev, -ENODEV },
+ { nfserr_notdir, -ENOTDIR },
+ { nfserr_isdir, -EISDIR },
+ { nfserr_inval, -EINVAL },
+ { nfserr_fbig, -EFBIG },
+ { nfserr_nospc, -ENOSPC },
+ { nfserr_rofs, -EROFS },
+ { nfserr_mlink, -EMLINK },
+ { nfserr_nametoolong, -ENAMETOOLONG },
+ { nfserr_notempty, -ENOTEMPTY },
+ { nfserr_dquot, -EDQUOT },
+ { nfserr_stale, -ESTALE },
+ { nfserr_jukebox, -ETIMEDOUT },
+ { nfserr_jukebox, -ERESTARTSYS },
+ { nfserr_jukebox, -EAGAIN },
+ { nfserr_jukebox, -EWOULDBLOCK },
+ { nfserr_jukebox, -ENOMEM },
+ { nfserr_io, -ETXTBSY },
+ { nfserr_notsupp, -EOPNOTSUPP },
+ { nfserr_toosmall, -ETOOSMALL },
+ { nfserr_serverfault, -ESERVERFAULT },
+ { nfserr_serverfault, -ENFILE },
+ { nfserr_io, -EREMOTEIO },
+ { nfserr_stale, -EOPENSTALE },
+ { nfserr_io, -EUCLEAN },
+ { nfserr_perm, -ENOKEY },
+ { nfserr_no_grace, -ENOGRACE},
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
+ if (nfs_errtbl[i].syserr == errno)
+ return nfs_errtbl[i].nfserr;
+ }
+ WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
+ return nfserr_io;
+}
+
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
@@ -480,12 +543,12 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
attr->na_seclabel->data, attr->na_seclabel->len);
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
attr->na_aclerr = set_posix_acl(&init_user_ns,
- inode, ACL_TYPE_ACCESS,
+ dentry, ACL_TYPE_ACCESS,
attr->na_pacl);
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
!attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
attr->na_aclerr = set_posix_acl(&init_user_ns,
- inode, ACL_TYPE_DEFAULT,
+ dentry, ACL_TYPE_DEFAULT,
attr->na_dpacl);
inode_unlock(inode);
if (size_change)
@@ -596,8 +659,8 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
if (ret == -EOPNOTSUPP || ret == -EXDEV)
- ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
- count, 0);
+ ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count,
+ COPY_FILE_SPLICE);
return ret;
}
@@ -871,10 +934,11 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct svc_rqst *rqstp = sd->u.data;
struct page *page = buf->page; // may be a compound one
unsigned offset = buf->offset;
+ struct page *last_page;
- page += offset / PAGE_SIZE;
- for (int i = sd->len; i > 0; i -= PAGE_SIZE)
- svc_rqst_replace_page(rqstp, page++);
+ last_page = page + (offset + sd->len - 1) / PAGE_SIZE;
+ for (page += offset / PAGE_SIZE; page <= last_page; page++)
+ svc_rqst_replace_page(rqstp, page);
if (rqstp->rq_res.page_len == 0) // first call
rqstp->rq_res.page_base = offset % PAGE_SIZE;
rqstp->rq_res.page_len += sd->len;
@@ -942,7 +1006,7 @@ __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
ssize_t host_err;
trace_nfsd_read_vector(rqstp, fhp, offset, *count);
- iov_iter_kvec(&iter, READ, vec, vlen, *count);
+ iov_iter_kvec(&iter, ITER_DEST, vec, vlen, *count);
host_err = vfs_iter_read(file, &iter, &ppos, 0);
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
}
@@ -1032,7 +1096,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
if (stable && !use_wgather)
flags |= RWF_SYNC;
- iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
+ iov_iter_kvec(&iter, ITER_SOURCE, vec, vlen, *cnt);
since = READ_ONCE(file->f_wb_err);
if (verf)
nfsd_copy_write_verifier(verf, nn);
@@ -1084,7 +1148,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 err;
trace_nfsd_read_start(rqstp, fhp, offset, *count);
- err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
+ err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_READ, &nf);
if (err)
return err;
@@ -1116,7 +1180,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
trace_nfsd_write_start(rqstp, fhp, offset, *cnt);
- err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf);
+ err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_WRITE, &nf);
if (err)
goto out;
@@ -1132,6 +1196,7 @@ out:
* nfsd_commit - Commit pending writes to stable storage
* @rqstp: RPC request being processed
* @fhp: NFS filehandle
+ * @nf: target file
* @offset: raw offset from beginning of file
* @count: raw count of bytes to sync
* @verf: filled in with the server's current write verifier
@@ -1148,19 +1213,13 @@ out:
* An nfsstat value in network byte order.
*/
__be32
-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
- u32 count, __be32 *verf)
+nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
+ u64 offset, u32 count, __be32 *verf)
{
+ __be32 err = nfs_ok;
u64 maxbytes;
loff_t start, end;
struct nfsd_net *nn;
- struct nfsd_file *nf;
- __be32 err;
-
- err = nfsd_file_acquire(rqstp, fhp,
- NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
- if (err)
- goto out;
/*
* Convert the client-provided (offset, count) range to a
@@ -1201,8 +1260,6 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
} else
nfsd_copy_write_verifier(verf, nn);
- nfsd_file_put(nf);
-out:
return err;
}
@@ -1304,7 +1361,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
iap->ia_mode &= ~current_umask();
err = 0;
- host_err = 0;
switch (type) {
case S_IFREG:
host_err = vfs_create(&init_user_ns, dirp, dchild, iap->ia_mode, true);
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 120521bc7b24..dbdfef7ae85b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -60,6 +60,7 @@ static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
posix_acl_release(attrs->na_dpacl);
}
+__be32 nfserrno (int errno);
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
@@ -88,7 +89,8 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
__be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct svc_fh *resfhp, struct nfsd_attrs *iap);
__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
- u64 offset, u32 count, __be32 *verf);
+ struct nfsd_file *nf, u64 offset, u32 count,
+ __be32 *verf);
#ifdef CONFIG_NFSD_V4
__be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *name, void **bufp, int *lenp);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 0eb00105d845..4fd2cf6d1d2d 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -896,5 +896,10 @@ struct nfsd4_operation {
union nfsd4_op_u *);
};
+struct nfsd4_cb_recall_any {
+ struct nfsd4_callback ra_cb;
+ u32 ra_keep;
+ u32 ra_bmval[1];
+};
#endif
diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h
index 547cf07cf4e0..0d39af1b00a0 100644
--- a/fs/nfsd/xdr4cb.h
+++ b/fs/nfsd/xdr4cb.h
@@ -48,3 +48,9 @@
#define NFS4_dec_cb_offload_sz (cb_compound_dec_hdr_sz + \
cb_sequence_dec_sz + \
op_dec_sz)
+#define NFS4_enc_cb_recall_any_sz (cb_compound_enc_hdr_sz + \
+ cb_sequence_enc_sz + \
+ 1 + 1 + 1)
+#define NFS4_dec_cb_recall_any_sz (cb_compound_dec_hdr_sz + \
+ cb_sequence_dec_sz + \
+ op_dec_sz)
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c
index 3b55e239705f..9930fa901039 100644
--- a/fs/nilfs2/dat.c
+++ b/fs/nilfs2/dat.c
@@ -111,6 +111,13 @@ static void nilfs_dat_commit_free(struct inode *dat,
kunmap_atomic(kaddr);
nilfs_dat_commit_entry(dat, req);
+
+ if (unlikely(req->pr_desc_bh == NULL || req->pr_bitmap_bh == NULL)) {
+ nilfs_error(dat->i_sb,
+ "state inconsistency probably due to duplicate use of vblocknr = %llu",
+ (unsigned long long)req->pr_entry_nr);
+ return;
+ }
nilfs_palloc_commit_free_entry(dat, req);
}
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index b4cebad21b48..3335ef352915 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -317,7 +317,7 @@ void nilfs_relax_pressure_in_lock(struct super_block *sb)
struct the_nilfs *nilfs = sb->s_fs_info;
struct nilfs_sc_info *sci = nilfs->ns_writer;
- if (!sci || !sci->sc_flush_request)
+ if (sb_rdonly(sb) || unlikely(!sci) || !sci->sc_flush_request)
return;
set_bit(NILFS_SC_PRIOR_FLUSH, &sci->sc_flags);
@@ -2242,7 +2242,7 @@ int nilfs_construct_segment(struct super_block *sb)
struct nilfs_sc_info *sci = nilfs->ns_writer;
struct nilfs_transaction_info *ti;
- if (!sci)
+ if (sb_rdonly(sb) || unlikely(!sci))
return -EROFS;
/* A call inside transactions causes a deadlock. */
@@ -2280,7 +2280,7 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
struct nilfs_transaction_info ti;
int err = 0;
- if (!sci)
+ if (sb_rdonly(sb) || unlikely(!sci))
return -EROFS;
nilfs_transaction_lock(sb, &ti, 0);
@@ -2776,11 +2776,12 @@ int nilfs_attach_log_writer(struct super_block *sb, struct nilfs_root *root)
if (nilfs->ns_writer) {
/*
- * This happens if the filesystem was remounted
- * read/write after nilfs_error degenerated it into a
- * read-only mount.
+ * This happens if the filesystem is made read-only by
+ * __nilfs_error or nilfs_remount and then remounted
+ * read/write. In these cases, reuse the existing
+ * writer.
*/
- nilfs_detach_log_writer(sb);
+ return 0;
}
nilfs->ns_writer = nilfs_segctor_new(sb, root);
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
index 77ff8e95421f..dc359b56fdfa 100644
--- a/fs/nilfs2/sufile.c
+++ b/fs/nilfs2/sufile.c
@@ -495,14 +495,22 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
{
struct buffer_head *bh;
+ void *kaddr;
+ struct nilfs_segment_usage *su;
int ret;
+ down_write(&NILFS_MDT(sufile)->mi_sem);
ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
if (!ret) {
mark_buffer_dirty(bh);
nilfs_mdt_mark_dirty(sufile);
+ kaddr = kmap_atomic(bh->b_page);
+ su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
+ nilfs_segment_usage_set_dirty(su);
+ kunmap_atomic(kaddr);
brelse(bh);
}
+ up_write(&NILFS_MDT(sufile)->mi_sem);
return ret;
}
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index ba108f915391..6edb6e0dd61f 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1133,8 +1133,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
goto out;
if (*flags & SB_RDONLY) {
- /* Shutting down log writer */
- nilfs_detach_log_writer(sb);
sb->s_flags |= SB_RDONLY;
/*
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 3b4a079c9617..2064e6473d30 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -13,6 +13,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/random.h>
+#include <linux/log2.h>
#include <linux/crc32.h>
#include "nilfs.h"
#include "segment.h"
@@ -193,6 +194,34 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
}
/**
+ * nilfs_get_blocksize - get block size from raw superblock data
+ * @sb: super block instance
+ * @sbp: superblock raw data buffer
+ * @blocksize: place to store block size
+ *
+ * nilfs_get_blocksize() calculates the block size from the block size
+ * exponent information written in @sbp and stores it in @blocksize,
+ * or aborts with an error message if it's too large.
+ *
+ * Return Value: On success, 0 is returned. If the block size is too
+ * large, -EINVAL is returned.
+ */
+static int nilfs_get_blocksize(struct super_block *sb,
+ struct nilfs_super_block *sbp, int *blocksize)
+{
+ unsigned int shift_bits = le32_to_cpu(sbp->s_log_block_size);
+
+ if (unlikely(shift_bits >
+ ilog2(NILFS_MAX_BLOCK_SIZE) - BLOCK_SIZE_BITS)) {
+ nilfs_err(sb, "too large filesystem blocksize: 2 ^ %u KiB",
+ shift_bits);
+ return -EINVAL;
+ }
+ *blocksize = BLOCK_SIZE << shift_bits;
+ return 0;
+}
+
+/**
* load_nilfs - load and recover the nilfs
* @nilfs: the_nilfs structure to be released
* @sb: super block instance used to recover past segment
@@ -245,11 +274,15 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
/* verify consistency between two super blocks */
- blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
+ err = nilfs_get_blocksize(sb, sbp[0], &blocksize);
+ if (err)
+ goto scan_error;
+
if (blocksize != nilfs->ns_blocksize) {
nilfs_warn(sb,
"blocksize differs between two super blocks (%d != %d)",
blocksize, nilfs->ns_blocksize);
+ err = -EINVAL;
goto scan_error;
}
@@ -443,11 +476,33 @@ static int nilfs_valid_sb(struct nilfs_super_block *sbp)
return crc == le32_to_cpu(sbp->s_sum);
}
-static int nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset)
+/**
+ * nilfs_sb2_bad_offset - check the location of the second superblock
+ * @sbp: superblock raw data buffer
+ * @offset: byte offset of second superblock calculated from device size
+ *
+ * nilfs_sb2_bad_offset() checks if the position on the second
+ * superblock is valid or not based on the filesystem parameters
+ * stored in @sbp. If @offset points to a location within the segment
+ * area, or if the parameters themselves are not normal, it is
+ * determined to be invalid.
+ *
+ * Return Value: true if invalid, false if valid.
+ */
+static bool nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset)
{
- return offset < ((le64_to_cpu(sbp->s_nsegments) *
- le32_to_cpu(sbp->s_blocks_per_segment)) <<
- (le32_to_cpu(sbp->s_log_block_size) + 10));
+ unsigned int shift_bits = le32_to_cpu(sbp->s_log_block_size);
+ u32 blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment);
+ u64 nsegments = le64_to_cpu(sbp->s_nsegments);
+ u64 index;
+
+ if (blocks_per_segment < NILFS_SEG_MIN_BLOCKS ||
+ shift_bits > ilog2(NILFS_MAX_BLOCK_SIZE) - BLOCK_SIZE_BITS)
+ return true;
+
+ index = offset >> (shift_bits + BLOCK_SIZE_BITS);
+ do_div(index, blocks_per_segment);
+ return index < nsegments;
}
static void nilfs_release_super_block(struct the_nilfs *nilfs)
@@ -586,9 +641,11 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
if (err)
goto failed_sbh;
- blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
- if (blocksize < NILFS_MIN_BLOCK_SIZE ||
- blocksize > NILFS_MAX_BLOCK_SIZE) {
+ err = nilfs_get_blocksize(sb, sbp, &blocksize);
+ if (err)
+ goto failed_sbh;
+
+ if (blocksize < NILFS_MIN_BLOCK_SIZE) {
nilfs_err(sb,
"couldn't mount because of unsupported filesystem blocksize %d",
blocksize);
@@ -690,9 +747,7 @@ int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
{
unsigned long ncleansegs;
- down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile);
- up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
*nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment;
return 0;
}
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 4f2ffc7ef296..c5e4a886593d 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -802,7 +802,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
setattr_copy(mnt_userns, inode, attr);
if (mode != inode->i_mode) {
- err = ntfs_acl_chmod(mnt_userns, inode);
+ err = ntfs_acl_chmod(mnt_userns, dentry);
if (err)
goto out;
@@ -1255,7 +1255,7 @@ const struct inode_operations ntfs_file_inode_operations = {
.setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr,
.permission = ntfs_permission,
- .get_acl = ntfs_get_acl,
+ .get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
.fiemap = ntfs_fiemap,
};
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
index bc22cc321a74..053cc0e0f8b5 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -367,7 +367,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
.mknod = ntfs_mknod,
.rename = ntfs_rename,
.permission = ntfs_permission,
- .get_acl = ntfs_get_acl,
+ .get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
.setattr = ntfs3_setattr,
.getattr = ntfs_getattr,
@@ -379,7 +379,7 @@ const struct inode_operations ntfs_special_inode_operations = {
.setattr = ntfs3_setattr,
.getattr = ntfs_getattr,
.listxattr = ntfs_listxattr,
- .get_acl = ntfs_get_acl,
+ .get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
};
// clang-format on
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
index 2c791222c4e2..a4d292809a33 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -843,7 +843,7 @@ int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
/* globals from xattr.c */
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu);
-int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ntfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
struct inode *dir);
@@ -852,7 +852,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
#define ntfs_set_acl NULL
#endif
-int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode);
+int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry);
int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
int mask);
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c
index 7de8718c68a9..aafe98ee0b21 100644
--- a/fs/ntfs3/xattr.c
+++ b/fs/ntfs3/xattr.c
@@ -619,10 +619,10 @@ out:
/*
* ntfs_set_acl - inode_operations::set_acl
*/
-int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ntfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
- return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false);
+ return ntfs_set_acl_ex(mnt_userns, d_inode(dentry), acl, type, false);
}
/*
@@ -664,8 +664,9 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
/*
* ntfs_acl_chmod - Helper for ntfs3_setattr().
*/
-int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
+int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry)
{
+ struct inode *inode = d_inode(dentry);
struct super_block *sb = inode->i_sb;
if (!(sb->s_flags & SB_POSIXACL))
@@ -674,7 +675,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
- return posix_acl_chmod(mnt_userns, inode, inode->i_mode);
+ return posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
}
/*
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index 23a72a423955..9f19cf9a5a9f 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -260,12 +260,13 @@ static int ocfs2_set_acl(handle_t *handle,
return ret;
}
-int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct buffer_head *bh = NULL;
int status, had_lock;
struct ocfs2_lock_holder oh;
+ struct inode *inode = d_inode(dentry);
had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
if (had_lock < 0)
diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h
index 95a57c888ab6..a897c4e41b26 100644
--- a/fs/ocfs2/acl.h
+++ b/fs/ocfs2/acl.h
@@ -17,7 +17,7 @@ struct ocfs2_acl_entry {
};
struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu);
-int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ocfs2_acl_chmod(struct inode *, struct buffer_head *);
extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index b13d344d40b6..60b97c92e2b2 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -335,7 +335,7 @@ static void o2hb_arm_timeout(struct o2hb_region *reg)
/* negotiate timeout must be less than write timeout. */
schedule_delayed_work(&reg->hr_nego_timeout_work,
msecs_to_jiffies(O2HB_NEGO_TIMEOUT_MS));
- memset(reg->hr_nego_node_bitmap, 0, sizeof(reg->hr_nego_node_bitmap));
+ bitmap_zero(reg->hr_nego_node_bitmap, O2NM_MAX_NODES);
}
static void o2hb_disarm_timeout(struct o2hb_region *reg)
@@ -375,7 +375,7 @@ static void o2hb_nego_timeout(struct work_struct *work)
if (reg->hr_last_hb_status)
return;
- o2hb_fill_node_map(live_node_bitmap, sizeof(live_node_bitmap));
+ o2hb_fill_node_map(live_node_bitmap, O2NM_MAX_NODES);
/* lowest node as master node to make negotiate decision. */
master_node = find_first_bit(live_node_bitmap, O2NM_MAX_NODES);
@@ -386,8 +386,8 @@ static void o2hb_nego_timeout(struct work_struct *work)
config_item_name(&reg->hr_item), reg->hr_bdev);
set_bit(master_node, reg->hr_nego_node_bitmap);
}
- if (memcmp(reg->hr_nego_node_bitmap, live_node_bitmap,
- sizeof(reg->hr_nego_node_bitmap))) {
+ if (!bitmap_equal(reg->hr_nego_node_bitmap, live_node_bitmap,
+ O2NM_MAX_NODES)) {
/* check negotiate bitmap every second to do timeout
* approve decision.
*/
@@ -856,8 +856,8 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg)
* live nodes heartbeat on it. In other words, the region has been
* added to all nodes.
*/
- if (memcmp(reg->hr_live_node_bitmap, o2hb_live_node_bitmap,
- sizeof(o2hb_live_node_bitmap)))
+ if (!bitmap_equal(reg->hr_live_node_bitmap, o2hb_live_node_bitmap,
+ O2NM_MAX_NODES))
goto unlock;
printk(KERN_NOTICE "o2hb: Region %s (%pg) is now a quorum device\n",
@@ -1087,7 +1087,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
* If a node is not configured but is in the livemap, we still need
* to read the slot so as to be able to remove it from the livemap.
*/
- o2hb_fill_node_map(live_node_bitmap, sizeof(live_node_bitmap));
+ o2hb_fill_node_map(live_node_bitmap, O2NM_MAX_NODES);
i = -1;
while ((i = find_next_bit(live_node_bitmap,
O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {
@@ -1437,11 +1437,11 @@ void o2hb_init(void)
for (i = 0; i < ARRAY_SIZE(o2hb_live_slots); i++)
INIT_LIST_HEAD(&o2hb_live_slots[i]);
- memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap));
- memset(o2hb_region_bitmap, 0, sizeof(o2hb_region_bitmap));
- memset(o2hb_live_region_bitmap, 0, sizeof(o2hb_live_region_bitmap));
- memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap));
- memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap));
+ bitmap_zero(o2hb_live_node_bitmap, O2NM_MAX_NODES);
+ bitmap_zero(o2hb_region_bitmap, O2NM_MAX_REGIONS);
+ bitmap_zero(o2hb_live_region_bitmap, O2NM_MAX_REGIONS);
+ bitmap_zero(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS);
+ bitmap_zero(o2hb_failed_region_bitmap, O2NM_MAX_REGIONS);
o2hb_dependent_users = 0;
@@ -1450,23 +1450,21 @@ void o2hb_init(void)
/* if we're already in a callback then we're already serialized by the sem */
static void o2hb_fill_node_map_from_callback(unsigned long *map,
- unsigned bytes)
+ unsigned int bits)
{
- BUG_ON(bytes < (BITS_TO_LONGS(O2NM_MAX_NODES) * sizeof(unsigned long)));
-
- memcpy(map, &o2hb_live_node_bitmap, bytes);
+ bitmap_copy(map, o2hb_live_node_bitmap, bits);
}
/*
* get a map of all nodes that are heartbeating in any regions
*/
-void o2hb_fill_node_map(unsigned long *map, unsigned bytes)
+void o2hb_fill_node_map(unsigned long *map, unsigned int bits)
{
/* callers want to serialize this map and callbacks so that they
* can trust that they don't miss nodes coming to the party */
down_read(&o2hb_callback_sem);
spin_lock(&o2hb_live_lock);
- o2hb_fill_node_map_from_callback(map, bytes);
+ o2hb_fill_node_map_from_callback(map, bits);
spin_unlock(&o2hb_live_lock);
up_read(&o2hb_callback_sem);
}
@@ -2460,7 +2458,7 @@ int o2hb_check_node_heartbeating_no_sem(u8 node_num)
unsigned long testing_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
spin_lock(&o2hb_live_lock);
- o2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
+ o2hb_fill_node_map_from_callback(testing_map, O2NM_MAX_NODES);
spin_unlock(&o2hb_live_lock);
if (!test_bit(node_num, testing_map)) {
mlog(ML_HEARTBEAT,
@@ -2477,7 +2475,7 @@ int o2hb_check_node_heartbeating_from_callback(u8 node_num)
{
unsigned long testing_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
- o2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
+ o2hb_fill_node_map_from_callback(testing_map, O2NM_MAX_NODES);
if (!test_bit(node_num, testing_map)) {
mlog(ML_HEARTBEAT,
"node (%u) does not have heartbeating enabled.\n",
diff --git a/fs/ocfs2/cluster/heartbeat.h b/fs/ocfs2/cluster/heartbeat.h
index 1d4100abf6f8..8ef8c1b9eeb7 100644
--- a/fs/ocfs2/cluster/heartbeat.h
+++ b/fs/ocfs2/cluster/heartbeat.h
@@ -59,7 +59,7 @@ int o2hb_register_callback(const char *region_uuid,
void o2hb_unregister_callback(const char *region_uuid,
struct o2hb_callback_func *hc);
void o2hb_fill_node_map(unsigned long *map,
- unsigned bytes);
+ unsigned int bits);
void o2hb_exit(void);
void o2hb_init(void);
int o2hb_check_node_heartbeating_no_sem(u8 node_num);
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c
index 7524994e3199..35c05c18de59 100644
--- a/fs/ocfs2/cluster/netdebug.c
+++ b/fs/ocfs2/cluster/netdebug.c
@@ -438,7 +438,7 @@ static int o2net_fill_bitmap(char *buf, int len)
unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
int i = -1, out = 0;
- o2net_fill_node_map(map, sizeof(map));
+ o2net_fill_node_map(map, O2NM_MAX_NODES);
while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
out += scnprintf(buf + out, PAGE_SIZE - out, "%d ", i);
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 27fee68f860a..2f61d39e4e50 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -54,7 +54,7 @@ int o2nm_configured_node_map(unsigned long *map, unsigned bytes)
return -EINVAL;
read_lock(&cluster->cl_nodes_lock);
- memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
+ bitmap_copy(map, cluster->cl_nodes_bitmap, O2NM_MAX_NODES);
read_unlock(&cluster->cl_nodes_lock);
return 0;
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index f660c0dbdb63..37d222bdfc8c 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -900,7 +900,7 @@ static int o2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
{
struct kvec vec = { .iov_len = len, .iov_base = data, };
struct msghdr msg = { .msg_flags = MSG_DONTWAIT, };
- iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, len);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, len);
return sock_recvmsg(sock, &msg, MSG_DONTWAIT);
}
@@ -990,14 +990,12 @@ static int o2net_tx_can_proceed(struct o2net_node *nn,
}
/* Get a map of all nodes to which this node is currently connected to */
-void o2net_fill_node_map(unsigned long *map, unsigned bytes)
+void o2net_fill_node_map(unsigned long *map, unsigned int bits)
{
struct o2net_sock_container *sc;
int node, ret;
- BUG_ON(bytes < (BITS_TO_LONGS(O2NM_MAX_NODES) * sizeof(unsigned long)));
-
- memset(map, 0, bytes);
+ bitmap_zero(map, bits);
for (node = 0; node < O2NM_MAX_NODES; ++node) {
if (!o2net_tx_can_proceed(o2net_nn_from_num(node), &sc, &ret))
continue;
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index fd2022712167..20f790a47484 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -1094,7 +1094,7 @@ static inline enum dlm_status dlm_err_to_dlm_status(int err)
static inline void dlm_node_iter_init(unsigned long *map,
struct dlm_node_iter *iter)
{
- memcpy(iter->node_map, map, sizeof(iter->node_map));
+ bitmap_copy(iter->node_map, map, O2NM_MAX_NODES);
iter->curnode = -1;
}
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index c4eccd499db8..5c04dde99981 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -1576,8 +1576,8 @@ static int dlm_should_restart_join(struct dlm_ctxt *dlm,
spin_lock(&dlm->spinlock);
/* For now, we restart the process if the node maps have
* changed at all */
- ret = memcmp(ctxt->live_map, dlm->live_nodes_map,
- sizeof(dlm->live_nodes_map));
+ ret = !bitmap_equal(ctxt->live_map, dlm->live_nodes_map,
+ O2NM_MAX_NODES);
spin_unlock(&dlm->spinlock);
if (ret)
@@ -1604,13 +1604,11 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
/* group sem locking should work for us here -- we're already
* registered for heartbeat events so filling this should be
* atomic wrt getting those handlers called. */
- o2hb_fill_node_map(dlm->live_nodes_map, sizeof(dlm->live_nodes_map));
+ o2hb_fill_node_map(dlm->live_nodes_map, O2NM_MAX_NODES);
spin_lock(&dlm->spinlock);
- memcpy(ctxt->live_map, dlm->live_nodes_map, sizeof(ctxt->live_map));
-
+ bitmap_copy(ctxt->live_map, dlm->live_nodes_map, O2NM_MAX_NODES);
__dlm_set_joining_node(dlm, dlm->node_num);
-
spin_unlock(&dlm->spinlock);
node = -1;
@@ -1643,8 +1641,7 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
* yes_resp_map. Copy that into our domain map and send a join
* assert message to clean up everyone elses state. */
spin_lock(&dlm->spinlock);
- memcpy(dlm->domain_map, ctxt->yes_resp_map,
- sizeof(ctxt->yes_resp_map));
+ bitmap_copy(dlm->domain_map, ctxt->yes_resp_map, O2NM_MAX_NODES);
set_bit(dlm->node_num, dlm->domain_map);
spin_unlock(&dlm->spinlock);
@@ -2009,9 +2006,9 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
mlog(0, "dlm->recovery_map=%p, &(dlm->recovery_map[0])=%p\n",
dlm->recovery_map, &(dlm->recovery_map[0]));
- memset(dlm->recovery_map, 0, sizeof(dlm->recovery_map));
- memset(dlm->live_nodes_map, 0, sizeof(dlm->live_nodes_map));
- memset(dlm->domain_map, 0, sizeof(dlm->domain_map));
+ bitmap_zero(dlm->recovery_map, O2NM_MAX_NODES);
+ bitmap_zero(dlm->live_nodes_map, O2NM_MAX_NODES);
+ bitmap_zero(dlm->domain_map, O2NM_MAX_NODES);
dlm->dlm_thread_task = NULL;
dlm->dlm_reco_thread_task = NULL;
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 227da5b1b6ab..d610da8e2f24 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -258,12 +258,12 @@ static void dlm_init_mle(struct dlm_master_list_entry *mle,
mle->type = type;
INIT_HLIST_NODE(&mle->master_hash_node);
INIT_LIST_HEAD(&mle->hb_events);
- memset(mle->maybe_map, 0, sizeof(mle->maybe_map));
+ bitmap_zero(mle->maybe_map, O2NM_MAX_NODES);
spin_lock_init(&mle->spinlock);
init_waitqueue_head(&mle->wq);
atomic_set(&mle->woken, 0);
kref_init(&mle->mle_refs);
- memset(mle->response_map, 0, sizeof(mle->response_map));
+ bitmap_zero(mle->response_map, O2NM_MAX_NODES);
mle->master = O2NM_MAX_NODES;
mle->new_master = O2NM_MAX_NODES;
mle->inuse = 0;
@@ -290,8 +290,8 @@ static void dlm_init_mle(struct dlm_master_list_entry *mle,
atomic_inc(&dlm->mle_cur_count[mle->type]);
/* copy off the node_map and register hb callbacks on our copy */
- memcpy(mle->node_map, dlm->domain_map, sizeof(mle->node_map));
- memcpy(mle->vote_map, dlm->domain_map, sizeof(mle->vote_map));
+ bitmap_copy(mle->node_map, dlm->domain_map, O2NM_MAX_NODES);
+ bitmap_copy(mle->vote_map, dlm->domain_map, O2NM_MAX_NODES);
clear_bit(dlm->node_num, mle->vote_map);
clear_bit(dlm->node_num, mle->node_map);
@@ -572,7 +572,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm,
spin_unlock(&dlm->track_lock);
memset(res->lvb, 0, DLM_LVB_LEN);
- memset(res->refmap, 0, sizeof(res->refmap));
+ bitmap_zero(res->refmap, O2NM_MAX_NODES);
}
struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
@@ -1036,10 +1036,10 @@ recheck:
spin_lock(&mle->spinlock);
m = mle->master;
- map_changed = (memcmp(mle->vote_map, mle->node_map,
- sizeof(mle->vote_map)) != 0);
- voting_done = (memcmp(mle->vote_map, mle->response_map,
- sizeof(mle->vote_map)) == 0);
+ map_changed = !bitmap_equal(mle->vote_map, mle->node_map,
+ O2NM_MAX_NODES);
+ voting_done = bitmap_equal(mle->vote_map, mle->response_map,
+ O2NM_MAX_NODES);
/* restart if we hit any errors */
if (map_changed) {
@@ -1277,11 +1277,11 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm,
/* now blank out everything, as if we had never
* contacted anyone */
- memset(mle->maybe_map, 0, sizeof(mle->maybe_map));
- memset(mle->response_map, 0, sizeof(mle->response_map));
+ bitmap_zero(mle->maybe_map, O2NM_MAX_NODES);
+ bitmap_zero(mle->response_map, O2NM_MAX_NODES);
/* reset the vote_map to the current node_map */
- memcpy(mle->vote_map, mle->node_map,
- sizeof(mle->node_map));
+ bitmap_copy(mle->vote_map, mle->node_map,
+ O2NM_MAX_NODES);
/* put myself into the maybe map */
if (mle->type != DLM_MLE_BLOCK)
set_bit(dlm->node_num, mle->maybe_map);
@@ -2094,7 +2094,7 @@ static void dlm_assert_master_worker(struct dlm_work_item *item, void *data)
flags = item->u.am.flags;
spin_lock(&dlm->spinlock);
- memcpy(nodemap, dlm->domain_map, sizeof(nodemap));
+ bitmap_copy(nodemap, dlm->domain_map, O2NM_MAX_NODES);
spin_unlock(&dlm->spinlock);
clear_bit(dlm->node_num, nodemap);
@@ -3447,7 +3447,7 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
ret = 0;
}
- memset(iter.node_map, 0, sizeof(iter.node_map));
+ bitmap_zero(iter.node_map, O2NM_MAX_NODES);
set_bit(old_master, iter.node_map);
mlog(0, "doing assert master of %.*s back to %u\n",
res->lockname.len, res->lockname.name, old_master);
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 52ad342fec3e..50da8af988c1 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -733,7 +733,7 @@ static int dlm_init_recovery_area(struct dlm_ctxt *dlm, u8 dead_node)
struct dlm_reco_node_data *ndata;
spin_lock(&dlm->spinlock);
- memcpy(dlm->reco.node_map, dlm->domain_map, sizeof(dlm->domain_map));
+ bitmap_copy(dlm->reco.node_map, dlm->domain_map, O2NM_MAX_NODES);
/* nodes can only be removed (by dying) after dropping
* this lock, and death will be trapped later, so this should do */
spin_unlock(&dlm->spinlock);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 9c67edd215d5..5c60b6bc85bf 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1991,7 +1991,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
}
}
- if (file && should_remove_suid(file->f_path.dentry)) {
+ if (file && setattr_should_drop_suidgid(&init_user_ns, file_inode(file))) {
ret = __ocfs2_write_remove_suid(inode, di_bh);
if (ret) {
mlog_errno(ret);
@@ -2279,7 +2279,7 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
* inode. There's also the dinode i_size state which
* can be lost via setattr during extending writes (we
* set inode->i_size at the end of a write. */
- if (should_remove_suid(dentry)) {
+ if (setattr_should_drop_suidgid(&init_user_ns, inode)) {
if (meta_level == 0) {
ocfs2_inode_unlock_for_extent_tree(inode,
&di_bh,
@@ -2712,7 +2712,7 @@ const struct inode_operations ocfs2_file_iops = {
.permission = ocfs2_permission,
.listxattr = ocfs2_listxattr,
.fiemap = ocfs2_fiemap,
- .get_acl = ocfs2_iop_get_acl,
+ .get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
.fileattr_get = ocfs2_fileattr_get,
.fileattr_set = ocfs2_fileattr_set,
@@ -2722,7 +2722,7 @@ const struct inode_operations ocfs2_special_file_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
- .get_acl = ocfs2_iop_get_acl,
+ .get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
};
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 126671e6caed..3fb98b4569a2 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -157,7 +157,7 @@ static void ocfs2_queue_replay_slots(struct ocfs2_super *osb,
replay_map->rm_state = REPLAY_DONE;
}
-static void ocfs2_free_replay_slots(struct ocfs2_super *osb)
+void ocfs2_free_replay_slots(struct ocfs2_super *osb)
{
struct ocfs2_replay_map *replay_map = osb->replay_map;
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 969d0aa28718..41c382f68529 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -150,6 +150,7 @@ int ocfs2_recovery_init(struct ocfs2_super *osb);
void ocfs2_recovery_exit(struct ocfs2_super *osb);
int ocfs2_compute_replay_slots(struct ocfs2_super *osb);
+void ocfs2_free_replay_slots(struct ocfs2_super *osb);
/*
* Journal Control:
* Initialize, Load, Shutdown, Wipe a journal.
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 05f32989bad6..a8fd51afb794 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -2915,7 +2915,7 @@ const struct inode_operations ocfs2_dir_iops = {
.permission = ocfs2_permission,
.listxattr = ocfs2_listxattr,
.fiemap = ocfs2_fiemap,
- .get_acl = ocfs2_iop_get_acl,
+ .get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
.fileattr_get = ocfs2_fileattr_get,
.fileattr_set = ocfs2_fileattr_set,
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 740b64238312..a503c553bab2 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -560,8 +560,7 @@ static inline unsigned int ocfs2_read_links_count(struct ocfs2_dinode *di)
u32 nlink = le16_to_cpu(di->i_links_count);
u32 hi = le16_to_cpu(di->i_links_count_hi);
- if (di->i_dyn_features & cpu_to_le16(OCFS2_INDEXED_DIR_FL))
- nlink |= (hi << OCFS2_LINKS_HI_SHIFT);
+ nlink |= (hi << OCFS2_LINKS_HI_SHIFT);
return nlink;
}
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c
index 88f75f7f02d7..c973c03f6fd8 100644
--- a/fs/ocfs2/stack_o2cb.c
+++ b/fs/ocfs2/stack_o2cb.c
@@ -273,17 +273,17 @@ static int o2cb_cluster_check(void)
*/
#define O2CB_MAP_STABILIZE_COUNT 60
for (i = 0; i < O2CB_MAP_STABILIZE_COUNT; ++i) {
- o2hb_fill_node_map(hbmap, sizeof(hbmap));
+ o2hb_fill_node_map(hbmap, O2NM_MAX_NODES);
if (!test_bit(node_num, hbmap)) {
printk(KERN_ERR "o2cb: %s heartbeat has not been "
"started.\n", (o2hb_global_heartbeat_active() ?
"Global" : "Local"));
return -EINVAL;
}
- o2net_fill_node_map(netmap, sizeof(netmap));
+ o2net_fill_node_map(netmap, O2NM_MAX_NODES);
/* Force set the current node to allow easy compare */
set_bit(node_num, netmap);
- if (!memcmp(hbmap, netmap, sizeof(hbmap)))
+ if (bitmap_equal(hbmap, netmap, O2NM_MAX_NODES))
return 0;
if (i < O2CB_MAP_STABILIZE_COUNT - 1)
msleep(1000);
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 317126261523..a8d5ca98fa57 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -669,6 +669,8 @@ static struct ctl_table_header *ocfs2_table_header;
static int __init ocfs2_stack_glue_init(void)
{
+ int ret;
+
strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
ocfs2_table_header = register_sysctl("fs/ocfs2/nm", ocfs2_nm_table);
@@ -678,7 +680,11 @@ static int __init ocfs2_stack_glue_init(void)
return -ENOMEM; /* or something. */
}
- return ocfs2_sysfs_init();
+ ret = ocfs2_sysfs_init();
+ if (ret)
+ unregister_sysctl_table(ocfs2_table_header);
+
+ return ret;
}
static void __exit ocfs2_stack_glue_exit(void)
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 42c993e53924..0b0e6a132101 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1159,6 +1159,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
out_dismount:
atomic_set(&osb->vol_state, VOLUME_DISABLED);
wake_up(&osb->osb_mount_event);
+ ocfs2_free_replay_slots(osb);
ocfs2_dismount_volume(sb, 1);
goto out;
@@ -1822,12 +1823,14 @@ static int ocfs2_mount_volume(struct super_block *sb)
status = ocfs2_truncate_log_init(osb);
if (status < 0) {
mlog_errno(status);
- goto out_system_inodes;
+ goto out_check_volume;
}
ocfs2_super_unlock(osb, 1);
return 0;
+out_check_volume:
+ ocfs2_free_replay_slots(osb);
out_system_inodes:
if (osb->local_alloc_state == OCFS2_LA_ENABLED)
ocfs2_shutdown_local_alloc(osb);
diff --git a/fs/open.c b/fs/open.c
index a81319b6177f..82c1a28b3308 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -54,7 +54,7 @@ int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
}
/* Remove suid, sgid, and file capabilities on truncate too */
- ret = dentry_needs_remove_privs(dentry);
+ ret = dentry_needs_remove_privs(mnt_userns, dentry);
if (ret < 0)
return ret;
if (ret)
@@ -188,7 +188,7 @@ long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
if (IS_APPEND(file_inode(f.file)))
goto out_putf;
sb_start_write(inode->i_sb);
- error = security_path_truncate(&f.file->f_path);
+ error = security_file_truncate(f.file);
if (!error)
error = do_truncate(file_mnt_user_ns(f.file), dentry, length,
ATTR_MTIME | ATTR_CTIME, f.file);
@@ -723,10 +723,10 @@ retry_deleg:
return -EINVAL;
if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
return -EINVAL;
- if (!S_ISDIR(inode->i_mode))
- newattrs.ia_valid |=
- ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
inode_lock(inode);
+ if (!S_ISDIR(inode->i_mode))
+ newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
+ setattr_should_drop_sgid(mnt_userns, inode);
/* Continue to send actual fs values, not the mount values. */
error = security_path_chown(
path,
diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c
index 605e5a3506ec..c5da2091cefb 100644
--- a/fs/orangefs/acl.c
+++ b/fs/orangefs/acl.c
@@ -64,8 +64,7 @@ struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu)
return acl;
}
-static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
- int type)
+int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
int error = 0;
void *value = NULL;
@@ -119,12 +118,13 @@ out:
return error;
}
-int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int orangefs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
struct iattr iattr;
int rc;
+ struct inode *inode = d_inode(dentry);
memset(&iattr, 0, sizeof iattr);
@@ -153,46 +153,7 @@ int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
rc = __orangefs_set_acl(inode, acl, type);
if (!rc && (iattr.ia_valid == ATTR_MODE))
- rc = __orangefs_setattr(inode, &iattr);
+ rc = __orangefs_setattr_mode(dentry, &iattr);
return rc;
}
-
-int orangefs_init_acl(struct inode *inode, struct inode *dir)
-{
- struct posix_acl *default_acl, *acl;
- umode_t mode = inode->i_mode;
- struct iattr iattr;
- int error = 0;
-
- error = posix_acl_create(dir, &mode, &default_acl, &acl);
- if (error)
- return error;
-
- if (default_acl) {
- error = __orangefs_set_acl(inode, default_acl,
- ACL_TYPE_DEFAULT);
- posix_acl_release(default_acl);
- } else {
- inode->i_default_acl = NULL;
- }
-
- if (acl) {
- if (!error)
- error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
- posix_acl_release(acl);
- } else {
- inode->i_acl = NULL;
- }
-
- /* If mode of the inode was changed, then do a forcible ->setattr */
- if (mode != inode->i_mode) {
- memset(&iattr, 0, sizeof iattr);
- inode->i_mode = mode;
- iattr.ia_mode = mode;
- iattr.ia_valid |= ATTR_MODE;
- __orangefs_setattr(inode, &iattr);
- }
-
- return error;
-}
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 7a8c0c6e698d..370bd3bbf5e4 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -53,7 +53,7 @@ static int orangefs_writepage_locked(struct page *page,
bv.bv_len = wlen;
bv.bv_offset = off % PAGE_SIZE;
WARN_ON(wlen == 0);
- iov_iter_bvec(&iter, WRITE, &bv, 1, wlen);
+ iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, wlen);
ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
len, wr, NULL, NULL);
@@ -112,7 +112,7 @@ static int orangefs_writepages_work(struct orangefs_writepages *ow,
else
ow->bv[i].bv_offset = 0;
}
- iov_iter_bvec(&iter, WRITE, ow->bv, ow->npages, ow->len);
+ iov_iter_bvec(&iter, ITER_SOURCE, ow->bv, ow->npages, ow->len);
WARN_ON(ow->off >= len);
if (ow->off + ow->len > len)
@@ -270,7 +270,7 @@ static void orangefs_readahead(struct readahead_control *rac)
offset = readahead_pos(rac);
i_pages = &rac->mapping->i_pages;
- iov_iter_xarray(&iter, READ, i_pages, offset, readahead_length(rac));
+ iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac));
/* read in the pages. */
if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode,
@@ -303,7 +303,7 @@ static int orangefs_read_folio(struct file *file, struct folio *folio)
bv.bv_page = &folio->page;
bv.bv_len = folio_size(folio);
bv.bv_offset = 0;
- iov_iter_bvec(&iter, READ, &bv, 1, folio_size(folio));
+ iov_iter_bvec(&iter, ITER_DEST, &bv, 1, folio_size(folio));
ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &off, &iter,
folio_size(folio), inode->i_size, NULL, NULL, file);
@@ -828,15 +828,23 @@ again:
spin_unlock(&inode->i_lock);
mark_inode_dirty(inode);
- if (iattr->ia_valid & ATTR_MODE)
- /* change mod on a file that has ACLs */
- ret = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
-
ret = 0;
out:
return ret;
}
+int __orangefs_setattr_mode(struct dentry *dentry, struct iattr *iattr)
+{
+ int ret;
+ struct inode *inode = d_inode(dentry);
+
+ ret = __orangefs_setattr(inode, iattr);
+ /* change mode on a file that has ACLs */
+ if (!ret && (iattr->ia_valid & ATTR_MODE))
+ ret = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
+ return ret;
+}
+
/*
* Change attributes of an object referenced by dentry.
*/
@@ -849,7 +857,7 @@ int orangefs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
ret = setattr_prepare(&init_user_ns, dentry, iattr);
if (ret)
goto out;
- ret = __orangefs_setattr(d_inode(dentry), iattr);
+ ret = __orangefs_setattr_mode(dentry, iattr);
sync_inode_metadata(d_inode(dentry), 1);
out:
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n",
@@ -967,7 +975,7 @@ static int orangefs_fileattr_set(struct user_namespace *mnt_userns,
/* ORANGEFS2 implementation of VFS inode operations for files */
static const struct inode_operations orangefs_file_inode_operations = {
- .get_acl = orangefs_get_acl,
+ .get_inode_acl = orangefs_get_acl,
.set_acl = orangefs_set_acl,
.setattr = orangefs_setattr,
.getattr = orangefs_getattr,
@@ -1097,8 +1105,9 @@ struct inode *orangefs_iget(struct super_block *sb,
* Allocate an inode for a newly created file and insert it into the inode hash.
*/
struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
- int mode, dev_t dev, struct orangefs_object_kref *ref)
+ umode_t mode, dev_t dev, struct orangefs_object_kref *ref)
{
+ struct posix_acl *acl = NULL, *default_acl = NULL;
unsigned long hash = orangefs_handle_hash(ref);
struct inode *inode;
int error;
@@ -1115,6 +1124,10 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
if (!inode)
return ERR_PTR(-ENOMEM);
+ error = posix_acl_create(dir, &mode, &default_acl, &acl);
+ if (error)
+ goto out_iput;
+
orangefs_set_inode(inode, ref);
inode->i_ino = hash; /* needed for stat etc */
@@ -1125,6 +1138,19 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
orangefs_init_iops(inode);
inode->i_rdev = dev;
+ if (default_acl) {
+ error = __orangefs_set_acl(inode, default_acl,
+ ACL_TYPE_DEFAULT);
+ if (error)
+ goto out_iput;
+ }
+
+ if (acl) {
+ error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+ if (error)
+ goto out_iput;
+ }
+
error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref);
if (error < 0)
goto out_iput;
@@ -1132,10 +1158,22 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
gossip_debug(GOSSIP_INODE_DEBUG,
"Initializing ACL's for inode %pU\n",
get_khandle_from_ino(inode));
- orangefs_init_acl(inode, dir);
+ if (mode != inode->i_mode) {
+ struct iattr iattr = {
+ .ia_mode = mode,
+ .ia_valid = ATTR_MODE,
+ };
+ inode->i_mode = mode;
+ __orangefs_setattr(inode, &iattr);
+ __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+ }
+ posix_acl_release(acl);
+ posix_acl_release(default_acl);
return inode;
out_iput:
iput(inode);
+ posix_acl_release(acl);
+ posix_acl_release(default_acl);
return ERR_PTR(error);
}
diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c
index 600e8eee541f..75c1a3dcf68c 100644
--- a/fs/orangefs/namei.c
+++ b/fs/orangefs/namei.c
@@ -430,7 +430,7 @@ static int orangefs_rename(struct user_namespace *mnt_userns,
/* ORANGEFS implementation of VFS inode operations for directories */
const struct inode_operations orangefs_dir_inode_operations = {
.lookup = orangefs_lookup,
- .get_acl = orangefs_get_acl,
+ .get_inode_acl = orangefs_get_acl,
.set_acl = orangefs_set_acl,
.create = orangefs_create,
.unlink = orangefs_unlink,
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index b5940ec1836a..6e0cc01b3a14 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -103,13 +103,13 @@ enum orangefs_vfs_op_states {
#define ORANGEFS_CACHE_CREATE_FLAGS 0
#endif
-extern int orangefs_init_acl(struct inode *inode, struct inode *dir);
extern const struct xattr_handler *orangefs_xattr_handlers[];
extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu);
extern int orangefs_set_acl(struct user_namespace *mnt_userns,
- struct inode *inode, struct posix_acl *acl,
+ struct dentry *dentry, struct posix_acl *acl,
int type);
+int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
/*
* orangefs data structures
@@ -356,11 +356,12 @@ void fsid_key_table_finalize(void);
vm_fault_t orangefs_page_mkwrite(struct vm_fault *);
struct inode *orangefs_new_inode(struct super_block *sb,
struct inode *dir,
- int mode,
+ umode_t mode,
dev_t dev,
struct orangefs_object_kref *ref);
int __orangefs_setattr(struct inode *, struct iattr *);
+int __orangefs_setattr_mode(struct dentry *dentry, struct iattr *iattr);
int orangefs_setattr(struct user_namespace *, struct dentry *, struct iattr *);
int orangefs_getattr(struct user_namespace *mnt_userns, const struct path *path,
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
index dd188c7996b3..6708e54b0e30 100644
--- a/fs/overlayfs/Kconfig
+++ b/fs/overlayfs/Kconfig
@@ -96,7 +96,7 @@ config OVERLAY_FS_XINO_AUTO
depends on 64BIT
help
If this config option is enabled then overlay filesystems will use
- unused high bits in undelying filesystem inode numbers to map all
+ unused high bits in underlying filesystem inode numbers to map all
inodes to a unified address space. The mapped 64bit inode numbers
might not be compatible with applications that expect 32bit inodes.
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index f436d8847f08..6e4e65ee050d 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -44,6 +44,35 @@ static bool ovl_must_copy_xattr(const char *name)
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
}
+static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path,
+ struct dentry *dentry, const char *acl_name)
+{
+ int err;
+ struct posix_acl *clone, *real_acl = NULL;
+
+ real_acl = ovl_get_acl_path(path, acl_name, false);
+ if (!real_acl)
+ return 0;
+
+ if (IS_ERR(real_acl)) {
+ err = PTR_ERR(real_acl);
+ if (err == -ENODATA || err == -EOPNOTSUPP)
+ return 0;
+ return err;
+ }
+
+ clone = posix_acl_clone(real_acl, GFP_KERNEL);
+ posix_acl_release(real_acl); /* release original acl */
+ if (!clone)
+ return -ENOMEM;
+
+ err = ovl_do_set_acl(ofs, dentry, acl_name, clone);
+
+ /* release cloned acl */
+ posix_acl_release(clone);
+ return err;
+}
+
int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct dentry *new)
{
struct dentry *old = oldpath->dentry;
@@ -93,6 +122,15 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
error = 0;
continue; /* Discard */
}
+
+ if (is_posix_acl_xattr(name)) {
+ error = ovl_copy_acl(OVL_FS(sb), oldpath, new, name);
+ if (!error)
+ continue;
+ /* POSIX ACLs must be copied. */
+ break;
+ }
+
retry:
size = ovl_do_getxattr(oldpath, name, value, value_size);
if (size == -ERANGE)
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 6b03457f72bb..f61e37f4c8ff 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -435,28 +435,12 @@ out:
}
static int ovl_set_upper_acl(struct ovl_fs *ofs, struct dentry *upperdentry,
- const char *name, const struct posix_acl *acl)
+ const char *acl_name, struct posix_acl *acl)
{
- void *buffer;
- size_t size;
- int err;
-
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl)
return 0;
- size = posix_acl_xattr_size(acl->a_count);
- buffer = kmalloc(size, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
- if (err < 0)
- goto out_free;
-
- err = ovl_do_setxattr(ofs, upperdentry, name, buffer, size, XATTR_CREATE);
-out_free:
- kfree(buffer);
- return err;
+ return ovl_do_set_acl(ofs, upperdentry, acl_name, acl);
}
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
@@ -592,28 +576,42 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
goto out_revert_creds;
}
- err = -ENOMEM;
- override_cred = prepare_creds();
- if (override_cred) {
+ if (!attr->hardlink) {
+ err = -ENOMEM;
+ override_cred = prepare_creds();
+ if (!override_cred)
+ goto out_revert_creds;
+ /*
+ * In the creation cases(create, mkdir, mknod, symlink),
+ * ovl should transfer current's fs{u,g}id to underlying
+ * fs. Because underlying fs want to initialize its new
+ * inode owner using current's fs{u,g}id. And in this
+ * case, the @inode is a new inode that is initialized
+ * in inode_init_owner() to current's fs{u,g}id. So use
+ * the inode's i_{u,g}id to override the cred's fs{u,g}id.
+ *
+ * But in the other hardlink case, ovl_link() does not
+ * create a new inode, so just use the ovl mounter's
+ * fs{u,g}id.
+ */
override_cred->fsuid = inode->i_uid;
override_cred->fsgid = inode->i_gid;
- if (!attr->hardlink) {
- err = security_dentry_create_files_as(dentry,
- attr->mode, &dentry->d_name, old_cred,
- override_cred);
- if (err) {
- put_cred(override_cred);
- goto out_revert_creds;
- }
+ err = security_dentry_create_files_as(dentry,
+ attr->mode, &dentry->d_name, old_cred,
+ override_cred);
+ if (err) {
+ put_cred(override_cred);
+ goto out_revert_creds;
}
put_cred(override_creds(override_cred));
put_cred(override_cred);
-
- if (!ovl_dentry_is_whiteout(dentry))
- err = ovl_create_upper(dentry, inode, attr);
- else
- err = ovl_create_over_whiteout(dentry, inode, attr);
}
+
+ if (!ovl_dentry_is_whiteout(dentry))
+ err = ovl_create_upper(dentry, inode, attr);
+ else
+ err = ovl_create_over_whiteout(dentry, inode, attr);
+
out_revert_creds:
revert_creds(old_cred);
return err;
@@ -1311,7 +1309,9 @@ const struct inode_operations ovl_dir_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
+ .get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
+ .set_acl = ovl_set_acl,
.update_time = ovl_update_time,
.fileattr_get = ovl_fileattr_get,
.fileattr_set = ovl_fileattr_set,
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index e065a5b9a442..a25bb3453dde 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -339,7 +339,7 @@ out_iput:
return dentry;
}
-/* Get the upper or lower dentry in stach whose on layer @idx */
+/* Get the upper or lower dentry in stack whose on layer @idx */
static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
{
struct ovl_entry *oe = dentry->d_fsdata;
@@ -463,7 +463,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
/* Get connected upper overlay dir from index */
if (index) {
- struct dentry *upper = ovl_index_upper(ofs, index);
+ struct dentry *upper = ovl_index_upper(ofs, index, true);
dput(index);
if (IS_ERR_OR_NULL(upper))
@@ -739,7 +739,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
/* Then try to get a connected upper dir by index */
if (index && d_is_dir(index)) {
- struct dentry *upper = ovl_index_upper(ofs, index);
+ struct dentry *upper = ovl_index_upper(ofs, index, true);
err = PTR_ERR(upper);
if (IS_ERR_OR_NULL(upper))
@@ -796,7 +796,7 @@ static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
return ERR_PTR(-ENOMEM);
/* Copy unaligned inner fh into aligned buffer */
- memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
+ memcpy(fh->buf, fid, buflen - OVL_FH_WIRE_OFFSET);
return fh;
}
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index a1a22f58ba18..c9d0c362c7ef 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -34,7 +34,7 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
return 'm';
}
-/* No atime modificaton nor notify on underlying */
+/* No atime modification nor notify on underlying */
#define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
static struct file *ovl_open_realfile(const struct file *file,
@@ -96,6 +96,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
spin_lock(&file->f_lock);
file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
+ file->f_iocb_flags = iocb_flags(file);
spin_unlock(&file->f_lock);
return 0;
@@ -517,9 +518,16 @@ static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len
const struct cred *old_cred;
int ret;
+ inode_lock(inode);
+ /* Update mode */
+ ovl_copyattr(inode);
+ ret = file_remove_privs(file);
+ if (ret)
+ goto out_unlock;
+
ret = ovl_real_fdget(file, &real);
if (ret)
- return ret;
+ goto out_unlock;
old_cred = ovl_override_creds(file_inode(file)->i_sb);
ret = vfs_fallocate(real.file, mode, offset, len);
@@ -530,6 +538,9 @@ static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len
fdput(real);
+out_unlock:
+ inode_unlock(inode);
+
return ret;
}
@@ -567,14 +578,23 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
const struct cred *old_cred;
loff_t ret;
+ inode_lock(inode_out);
+ if (op != OVL_DEDUPE) {
+ /* Update mode */
+ ovl_copyattr(inode_out);
+ ret = file_remove_privs(file_out);
+ if (ret)
+ goto out_unlock;
+ }
+
ret = ovl_real_fdget(file_out, &real_out);
if (ret)
- return ret;
+ goto out_unlock;
ret = ovl_real_fdget(file_in, &real_in);
if (ret) {
fdput(real_out);
- return ret;
+ goto out_unlock;
}
old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
@@ -603,6 +623,9 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
fdput(real_in);
fdput(real_out);
+out_unlock:
+ inode_unlock(inode_out);
+
return ret;
}
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 9e61511de7a7..ee6dfa577c93 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -14,6 +14,8 @@
#include <linux/fileattr.h>
#include <linux/security.h>
#include <linux/namei.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#include "overlayfs.h"
@@ -460,7 +462,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
* of the POSIX ACLs retrieved from the lower layer to this function to not
* alter the POSIX ACLs for the underlying filesystem.
*/
-static void ovl_idmap_posix_acl(struct inode *realinode,
+static void ovl_idmap_posix_acl(const struct inode *realinode,
struct user_namespace *mnt_userns,
struct posix_acl *acl)
{
@@ -485,6 +487,64 @@ static void ovl_idmap_posix_acl(struct inode *realinode,
}
/*
+ * The @noperm argument is used to skip permission checking and is a temporary
+ * measure. Quoting Miklos from an earlier discussion:
+ *
+ * > So there are two paths to getting an acl:
+ * > 1) permission checking and 2) retrieving the value via getxattr(2).
+ * > This is a similar situation as reading a symlink vs. following it.
+ * > When following a symlink overlayfs always reads the link on the
+ * > underlying fs just as if it was a readlink(2) call, calling
+ * > security_inode_readlink() instead of security_inode_follow_link().
+ * > This is logical: we are reading the link from the underlying storage,
+ * > and following it on overlayfs.
+ * >
+ * > Applying the same logic to acl: we do need to call the
+ * > security_inode_getxattr() on the underlying fs, even if just want to
+ * > check permissions on overlay. This is currently not done, which is an
+ * > inconsistency.
+ * >
+ * > Maybe adding the check to ovl_get_acl() is the right way to go, but
+ * > I'm a little afraid of a performance regression. Will look into that.
+ *
+ * Until we have made a decision allow this helper to take the @noperm
+ * argument. We should hopefully be able to remove it soon.
+ */
+struct posix_acl *ovl_get_acl_path(const struct path *path,
+ const char *acl_name, bool noperm)
+{
+ struct posix_acl *real_acl, *clone;
+ struct user_namespace *mnt_userns;
+ struct inode *realinode = d_inode(path->dentry);
+
+ mnt_userns = mnt_user_ns(path->mnt);
+
+ if (noperm)
+ real_acl = get_inode_acl(realinode, posix_acl_type(acl_name));
+ else
+ real_acl = vfs_get_acl(mnt_userns, path->dentry, acl_name);
+ if (IS_ERR_OR_NULL(real_acl))
+ return real_acl;
+
+ if (!is_idmapped_mnt(path->mnt))
+ return real_acl;
+
+ /*
+ * We cannot alter the ACLs returned from the relevant layer as that
+ * would alter the cached values filesystem wide for the lower
+ * filesystem. Instead we can clone the ACLs and then apply the
+ * relevant idmapping of the layer.
+ */
+ clone = posix_acl_clone(real_acl, GFP_KERNEL);
+ posix_acl_release(real_acl); /* release original acl */
+ if (!clone)
+ return ERR_PTR(-ENOMEM);
+
+ ovl_idmap_posix_acl(realinode, mnt_userns, clone);
+ return clone;
+}
+
+/*
* When the relevant layer is an idmapped mount we need to take the idmapping
* of the layer into account and translate any ACL_{GROUP,USER} values
* according to the idmapped mount.
@@ -495,10 +555,12 @@ static void ovl_idmap_posix_acl(struct inode *realinode,
*
* This is obviously only relevant when idmapped layers are used.
*/
-struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
+struct posix_acl *do_ovl_get_acl(struct user_namespace *mnt_userns,
+ struct inode *inode, int type,
+ bool rcu, bool noperm)
{
struct inode *realinode = ovl_inode_real(inode);
- struct posix_acl *acl, *clone;
+ struct posix_acl *acl;
struct path realpath;
if (!IS_POSIXACL(realinode))
@@ -512,40 +574,115 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
}
if (rcu) {
+ /*
+ * If the layer is idmapped drop out of RCU path walk
+ * so we can clone the ACLs.
+ */
+ if (is_idmapped_mnt(realpath.mnt))
+ return ERR_PTR(-ECHILD);
+
acl = get_cached_acl_rcu(realinode, type);
} else {
const struct cred *old_cred;
old_cred = ovl_override_creds(inode->i_sb);
- acl = get_acl(realinode, type);
+ acl = ovl_get_acl_path(&realpath, posix_acl_xattr_name(type), noperm);
revert_creds(old_cred);
}
- /*
- * If there are no POSIX ACLs, or we encountered an error,
- * or the layer isn't idmapped we don't need to do anything.
- */
- if (!is_idmapped_mnt(realpath.mnt) || IS_ERR_OR_NULL(acl))
- return acl;
+
+ return acl;
+}
+
+static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
+ struct posix_acl *acl, int type)
+{
+ int err;
+ struct path realpath;
+ const char *acl_name;
+ const struct cred *old_cred;
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ struct dentry *upperdentry = ovl_dentry_upper(dentry);
+ struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
+
+ err = ovl_want_write(dentry);
+ if (err)
+ return err;
/*
- * We only get here if the layer is idmapped. So drop out of RCU path
- * walk so we can clone the ACLs. There's no need to release the ACLs
- * since get_cached_acl_rcu() doesn't take a reference on the ACLs.
+ * If ACL is to be removed from a lower file, check if it exists in
+ * the first place before copying it up.
*/
- if (rcu)
- return ERR_PTR(-ECHILD);
+ acl_name = posix_acl_xattr_name(type);
+ if (!acl && !upperdentry) {
+ struct posix_acl *real_acl;
- clone = posix_acl_clone(acl, GFP_KERNEL);
- if (!clone)
- clone = ERR_PTR(-ENOMEM);
+ ovl_path_lower(dentry, &realpath);
+ old_cred = ovl_override_creds(dentry->d_sb);
+ real_acl = vfs_get_acl(mnt_user_ns(realpath.mnt), realdentry,
+ acl_name);
+ revert_creds(old_cred);
+ if (IS_ERR(real_acl)) {
+ err = PTR_ERR(real_acl);
+ goto out_drop_write;
+ }
+ posix_acl_release(real_acl);
+ }
+
+ if (!upperdentry) {
+ err = ovl_copy_up(dentry);
+ if (err)
+ goto out_drop_write;
+
+ realdentry = ovl_dentry_upper(dentry);
+ }
+
+ old_cred = ovl_override_creds(dentry->d_sb);
+ if (acl)
+ err = ovl_do_set_acl(ofs, realdentry, acl_name, acl);
else
- ovl_idmap_posix_acl(realinode, mnt_user_ns(realpath.mnt), clone);
+ err = ovl_do_remove_acl(ofs, realdentry, acl_name);
+ revert_creds(old_cred);
+
+ /* copy c/mtime */
+ ovl_copyattr(inode);
+
+out_drop_write:
+ ovl_drop_write(dentry);
+ return err;
+}
+
+int ovl_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type)
+{
+ int err;
+ struct inode *inode = d_inode(dentry);
+ struct dentry *workdir = ovl_workdir(dentry);
+ struct inode *realinode = ovl_inode_real(inode);
+
+ if (!IS_POSIXACL(d_inode(workdir)))
+ return -EOPNOTSUPP;
+ if (!realinode->i_op->set_acl)
+ return -EOPNOTSUPP;
+ if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+ return acl ? -EACCES : 0;
+ if (!inode_owner_or_capable(&init_user_ns, inode))
+ return -EPERM;
+
/*
- * Since we're not in RCU path walk we always need to release the
- * original ACLs.
+ * Check if sgid bit needs to be cleared (actual setacl operation will
+ * be done with mounter's capabilities and so that won't do it for us).
*/
- posix_acl_release(acl);
- return clone;
+ if (unlikely(inode->i_mode & S_ISGID) && type == ACL_TYPE_ACCESS &&
+ !in_group_p(inode->i_gid) &&
+ !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
+ struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
+
+ err = ovl_setattr(&init_user_ns, dentry, &iattr);
+ if (err)
+ return err;
+ }
+
+ return ovl_set_or_remove_acl(dentry, inode, acl, type);
}
#endif
@@ -721,7 +858,9 @@ static const struct inode_operations ovl_file_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
+ .get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
+ .set_acl = ovl_set_acl,
.update_time = ovl_update_time,
.fiemap = ovl_fiemap,
.fileattr_get = ovl_fileattr_get,
@@ -741,7 +880,9 @@ static const struct inode_operations ovl_special_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
+ .get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
+ .set_acl = ovl_set_acl,
.update_time = ovl_update_time,
};
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 0fd1d5fdfc72..46753134533a 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -487,7 +487,8 @@ fail:
}
/* Get upper dentry from index */
-struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
+struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
+ bool connected)
{
struct ovl_fh *fh;
struct dentry *upper;
@@ -499,7 +500,7 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
if (IS_ERR_OR_NULL(fh))
return ERR_CAST(fh);
- upper = ovl_decode_real_fh(ofs, fh, ovl_upper_mnt(ofs), true);
+ upper = ovl_decode_real_fh(ofs, fh, ovl_upper_mnt(ofs), connected);
kfree(fh);
if (IS_ERR_OR_NULL(upper))
@@ -572,7 +573,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
* directly from the index dentry, but for dir index we first need to
* decode the upper directory.
*/
- upper = ovl_index_upper(ofs, index);
+ upper = ovl_index_upper(ofs, index, false);
if (IS_ERR_OR_NULL(upper)) {
err = PTR_ERR(upper);
/*
@@ -1085,6 +1086,11 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
.mnt = ovl_upper_mnt(ofs),
};
+ /*
+ * It's safe to assign upperredirect here: the previous
+ * assignment of happens only if upperdentry is non-NULL, and
+ * this one only if upperdentry is NULL.
+ */
upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0);
if (IS_ERR(upperredirect)) {
err = PTR_ERR(upperredirect);
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index eee8f08d32b6..1df7f850ff3b 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -8,6 +8,8 @@
#include <linux/uuid.h>
#include <linux/fs.h>
#include <linux/namei.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#include "ovl_entry.h"
#undef pr_fmt
@@ -108,7 +110,7 @@ struct ovl_fh {
u8 padding[3]; /* make sure fb.fid is 32bit aligned */
union {
struct ovl_fb fb;
- u8 buf[0];
+ DECLARE_FLEX_ARRAY(u8, buf);
};
} __packed;
@@ -278,6 +280,18 @@ static inline int ovl_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
return ovl_do_removexattr(ofs, dentry, ovl_xattr(ofs, ox));
}
+static inline int ovl_do_set_acl(struct ovl_fs *ofs, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *acl)
+{
+ return vfs_set_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name, acl);
+}
+
+static inline int ovl_do_remove_acl(struct ovl_fs *ofs, struct dentry *dentry,
+ const char *acl_name)
+{
+ return vfs_remove_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name);
+}
+
static inline int ovl_do_rename(struct ovl_fs *ofs, struct inode *olddir,
struct dentry *olddentry, struct inode *newdir,
struct dentry *newdentry, unsigned int flags)
@@ -401,7 +415,7 @@ const char *ovl_dentry_get_redirect(struct dentry *dentry);
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
void ovl_dir_modified(struct dentry *dentry, bool impurity);
-u64 ovl_dentry_version_get(struct dentry *dentry);
+u64 ovl_inode_version_get(struct inode *inode);
bool ovl_is_whiteout(struct dentry *dentry);
struct file *ovl_path_open(const struct path *path, int flags);
int ovl_copy_up_start(struct dentry *dentry, int flags);
@@ -525,7 +539,8 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
enum ovl_xattr ox, struct dentry *real, bool is_upper,
bool set);
-struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index);
+struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
+ bool connected);
int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);
int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
struct qstr *name);
@@ -570,9 +585,9 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs);
* lower dir was removed under it and possibly before it was rotated from upper
* to lower layer.
*/
-static inline bool ovl_dir_is_real(struct dentry *dir)
+static inline bool ovl_dir_is_real(struct inode *dir)
{
- return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
+ return !ovl_test_flag(OVL_WHITEOUTS, dir);
}
/* inode.c */
@@ -594,9 +609,33 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
#ifdef CONFIG_FS_POSIX_ACL
-struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu);
+struct posix_acl *do_ovl_get_acl(struct user_namespace *mnt_userns,
+ struct inode *inode, int type,
+ bool rcu, bool noperm);
+static inline struct posix_acl *ovl_get_inode_acl(struct inode *inode, int type,
+ bool rcu)
+{
+ return do_ovl_get_acl(&init_user_ns, inode, type, rcu, true);
+}
+static inline struct posix_acl *ovl_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, int type)
+{
+ return do_ovl_get_acl(mnt_userns, d_inode(dentry), type, false, false);
+}
+int ovl_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct posix_acl *acl, int type);
+struct posix_acl *ovl_get_acl_path(const struct path *path,
+ const char *acl_name, bool noperm);
#else
-#define ovl_get_acl NULL
+#define ovl_get_inode_acl NULL
+#define ovl_get_acl NULL
+#define ovl_set_acl NULL
+static inline struct posix_acl *ovl_get_acl_path(const struct path *path,
+ const char *acl_name,
+ bool noperm)
+{
+ return NULL;
+}
#endif
int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 2b210640036c..8cd2b9947de1 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -235,15 +235,15 @@ void ovl_dir_cache_free(struct inode *inode)
}
}
-static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry)
+static void ovl_cache_put(struct ovl_dir_file *od, struct inode *inode)
{
struct ovl_dir_cache *cache = od->cache;
WARN_ON(cache->refcount <= 0);
cache->refcount--;
if (!cache->refcount) {
- if (ovl_dir_cache(d_inode(dentry)) == cache)
- ovl_set_dir_cache(d_inode(dentry), NULL);
+ if (ovl_dir_cache(inode) == cache)
+ ovl_set_dir_cache(inode, NULL);
ovl_cache_free(&cache->entries);
kfree(cache);
@@ -323,15 +323,15 @@ static void ovl_dir_reset(struct file *file)
{
struct ovl_dir_file *od = file->private_data;
struct ovl_dir_cache *cache = od->cache;
- struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = file_inode(file);
bool is_real;
- if (cache && ovl_dentry_version_get(dentry) != cache->version) {
- ovl_cache_put(od, dentry);
+ if (cache && ovl_inode_version_get(inode) != cache->version) {
+ ovl_cache_put(od, inode);
od->cache = NULL;
od->cursor = NULL;
}
- is_real = ovl_dir_is_real(dentry);
+ is_real = ovl_dir_is_real(inode);
if (od->is_real != is_real) {
/* is_real can only become false when dir is copied up */
if (WARN_ON(is_real))
@@ -394,9 +394,10 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
{
int res;
struct ovl_dir_cache *cache;
+ struct inode *inode = d_inode(dentry);
- cache = ovl_dir_cache(d_inode(dentry));
- if (cache && ovl_dentry_version_get(dentry) == cache->version) {
+ cache = ovl_dir_cache(inode);
+ if (cache && ovl_inode_version_get(inode) == cache->version) {
WARN_ON(!cache->refcount);
cache->refcount++;
return cache;
@@ -418,8 +419,8 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
return ERR_PTR(res);
}
- cache->version = ovl_dentry_version_get(dentry);
- ovl_set_dir_cache(d_inode(dentry), cache);
+ cache->version = ovl_inode_version_get(inode);
+ ovl_set_dir_cache(inode, cache);
return cache;
}
@@ -596,16 +597,17 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
{
int res;
struct dentry *dentry = path->dentry;
+ struct inode *inode = d_inode(dentry);
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
struct ovl_dir_cache *cache;
- cache = ovl_dir_cache(d_inode(dentry));
- if (cache && ovl_dentry_version_get(dentry) == cache->version)
+ cache = ovl_dir_cache(inode);
+ if (cache && ovl_inode_version_get(inode) == cache->version)
return cache;
/* Impure cache is not refcounted, free it here */
- ovl_dir_cache_free(d_inode(dentry));
- ovl_set_dir_cache(d_inode(dentry), NULL);
+ ovl_dir_cache_free(inode);
+ ovl_set_dir_cache(inode, NULL);
cache = kzalloc(sizeof(struct ovl_dir_cache), GFP_KERNEL);
if (!cache)
@@ -627,13 +629,13 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
OVL_XATTR_IMPURE);
ovl_drop_write(dentry);
}
- ovl_clear_flag(OVL_IMPURE, d_inode(dentry));
+ ovl_clear_flag(OVL_IMPURE, inode);
kfree(cache);
return NULL;
}
- cache->version = ovl_dentry_version_get(dentry);
- ovl_set_dir_cache(d_inode(dentry), cache);
+ cache->version = ovl_inode_version_get(inode);
+ ovl_set_dir_cache(inode, cache);
return cache;
}
@@ -675,7 +677,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
static bool ovl_is_impure_dir(struct file *file)
{
struct ovl_dir_file *od = file->private_data;
- struct inode *dir = d_inode(file->f_path.dentry);
+ struct inode *dir = file_inode(file);
/*
* Only upper dir can be impure, but if we are in the middle of
@@ -893,7 +895,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
struct file *realfile;
int err;
- err = ovl_sync_status(OVL_FS(file->f_path.dentry->d_sb));
+ err = ovl_sync_status(OVL_FS(file_inode(file)->i_sb));
if (err <= 0)
return err;
@@ -913,7 +915,7 @@ static int ovl_dir_release(struct inode *inode, struct file *file)
if (od->cache) {
inode_lock(inode);
- ovl_cache_put(od, file->f_path.dentry);
+ ovl_cache_put(od, inode);
inode_unlock(inode);
}
fput(od->realfile);
@@ -942,7 +944,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
return PTR_ERR(realfile);
}
od->realfile = realfile;
- od->is_real = ovl_dir_is_real(file->f_path.dentry);
+ od->is_real = ovl_dir_is_real(inode);
od->is_upper = OVL_TYPE_UPPER(type);
file->private_data = od;
@@ -1071,14 +1073,10 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
int err;
struct inode *dir = path->dentry->d_inode;
LIST_HEAD(list);
- struct rb_root root = RB_ROOT;
struct ovl_cache_entry *p;
struct ovl_readdir_data rdd = {
- .ctx.actor = ovl_fill_merge,
- .dentry = NULL,
+ .ctx.actor = ovl_fill_plain,
.list = &list,
- .root = &root,
- .is_lowest = false,
};
bool incompat = false;
@@ -1159,14 +1157,10 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
struct inode *dir = indexdir->d_inode;
struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = indexdir };
LIST_HEAD(list);
- struct rb_root root = RB_ROOT;
struct ovl_cache_entry *p;
struct ovl_readdir_data rdd = {
- .ctx.actor = ovl_fill_merge,
- .dentry = NULL,
+ .ctx.actor = ovl_fill_plain,
.list = &list,
- .root = &root,
- .is_lowest = false,
};
err = ovl_dir_read(&path, &rdd);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index a29a8afe9b26..85b891152a2c 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -139,11 +139,16 @@ static int ovl_dentry_revalidate_common(struct dentry *dentry,
unsigned int flags, bool weak)
{
struct ovl_entry *oe = dentry->d_fsdata;
+ struct inode *inode = d_inode_rcu(dentry);
struct dentry *upper;
unsigned int i;
int ret = 1;
- upper = ovl_dentry_upper(dentry);
+ /* Careful in RCU mode */
+ if (!inode)
+ return -ECHILD;
+
+ upper = ovl_i_dentry_upper(inode);
if (upper)
ret = ovl_revalidate_real(upper, flags, weak);
@@ -813,13 +818,11 @@ retry:
* allowed as upper are limited to "normal" ones, where checking
* for the above two errors is sufficient.
*/
- err = ovl_do_removexattr(ofs, work,
- XATTR_NAME_POSIX_ACL_DEFAULT);
+ err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_DEFAULT);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
- err = ovl_do_removexattr(ofs, work,
- XATTR_NAME_POSIX_ACL_ACCESS);
+ err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_ACCESS);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
@@ -1001,83 +1004,6 @@ static unsigned int ovl_split_lowerdirs(char *str)
return ctr;
}
-static int __maybe_unused
-ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
- struct dentry *dentry, struct inode *inode,
- const char *name, void *buffer, size_t size)
-{
- return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
-}
-
-static int __maybe_unused
-ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
- struct user_namespace *mnt_userns,
- struct dentry *dentry, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
-{
- struct dentry *workdir = ovl_workdir(dentry);
- struct inode *realinode = ovl_inode_real(inode);
- struct posix_acl *acl = NULL;
- int err;
-
- /* Check that everything is OK before copy-up */
- if (value) {
- /* The above comment can be understood in two ways:
- *
- * 1. We just want to check whether the basic POSIX ACL format
- * is ok. For example, if the header is correct and the size
- * is sane.
- * 2. We want to know whether the ACL_{GROUP,USER} entries can
- * be mapped according to the underlying filesystem.
- *
- * Currently, we only check 1. If we wanted to check 2. we
- * would need to pass the mnt_userns and the fs_userns of the
- * underlying filesystem. But frankly, I think checking 1. is
- * enough to start the copy-up.
- */
- acl = vfs_set_acl_prepare(&init_user_ns, &init_user_ns, value, size);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- }
- err = -EOPNOTSUPP;
- if (!IS_POSIXACL(d_inode(workdir)))
- goto out_acl_release;
- if (!realinode->i_op->set_acl)
- goto out_acl_release;
- if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
- err = acl ? -EACCES : 0;
- goto out_acl_release;
- }
- err = -EPERM;
- if (!inode_owner_or_capable(&init_user_ns, inode))
- goto out_acl_release;
-
- posix_acl_release(acl);
-
- /*
- * Check if sgid bit needs to be cleared (actual setacl operation will
- * be done with mounter's capabilities and so that won't do it for us).
- */
- if (unlikely(inode->i_mode & S_ISGID) &&
- handler->flags == ACL_TYPE_ACCESS &&
- !in_group_p(inode->i_gid) &&
- !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
- struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
-
- err = ovl_setattr(&init_user_ns, dentry, &iattr);
- if (err)
- return err;
- }
-
- err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
- return err;
-
-out_acl_release:
- posix_acl_release(acl);
- return err;
-}
-
static int ovl_own_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
@@ -1110,22 +1036,6 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
return ovl_xattr_set(dentry, inode, name, value, size, flags);
}
-static const struct xattr_handler __maybe_unused
-ovl_posix_acl_access_xattr_handler = {
- .name = XATTR_NAME_POSIX_ACL_ACCESS,
- .flags = ACL_TYPE_ACCESS,
- .get = ovl_posix_acl_xattr_get,
- .set = ovl_posix_acl_xattr_set,
-};
-
-static const struct xattr_handler __maybe_unused
-ovl_posix_acl_default_xattr_handler = {
- .name = XATTR_NAME_POSIX_ACL_DEFAULT,
- .flags = ACL_TYPE_DEFAULT,
- .get = ovl_posix_acl_xattr_get,
- .set = ovl_posix_acl_xattr_set,
-};
-
static const struct xattr_handler ovl_own_trusted_xattr_handler = {
.prefix = OVL_XATTR_TRUSTED_PREFIX,
.get = ovl_own_xattr_get,
@@ -1146,8 +1056,8 @@ static const struct xattr_handler ovl_other_xattr_handler = {
static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL
- &ovl_posix_acl_access_xattr_handler,
- &ovl_posix_acl_default_xattr_handler,
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
#endif
&ovl_own_trusted_xattr_handler,
&ovl_other_xattr_handler,
@@ -1156,8 +1066,8 @@ static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
static const struct xattr_handler *ovl_user_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL
- &ovl_posix_acl_access_xattr_handler,
- &ovl_posix_acl_default_xattr_handler,
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
#endif
&ovl_own_user_xattr_handler,
&ovl_other_xattr_handler,
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 81a57a8d80d9..bde291623c8c 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -463,7 +463,7 @@ static void ovl_dir_version_inc(struct dentry *dentry, bool impurity)
* which have been copied up and have origins), so only need to note
* changes to impure entries.
*/
- if (!ovl_dir_is_real(dentry) || impurity)
+ if (!ovl_dir_is_real(inode) || impurity)
OVL_I(inode)->version++;
}
@@ -475,10 +475,8 @@ void ovl_dir_modified(struct dentry *dentry, bool impurity)
ovl_dir_version_inc(dentry, impurity);
}
-u64 ovl_dentry_version_get(struct dentry *dentry)
+u64 ovl_inode_version_get(struct inode *inode)
{
- struct inode *inode = d_inode(dentry);
-
WARN_ON(!inode_is_locked(inode));
return OVL_I(inode)->version;
}
@@ -1104,13 +1102,18 @@ void ovl_copyattr(struct inode *inode)
struct path realpath;
struct inode *realinode;
struct user_namespace *real_mnt_userns;
+ vfsuid_t vfsuid;
+ vfsgid_t vfsgid;
ovl_i_path_real(inode, &realpath);
realinode = d_inode(realpath.dentry);
real_mnt_userns = mnt_user_ns(realpath.mnt);
- inode->i_uid = i_uid_into_mnt(real_mnt_userns, realinode);
- inode->i_gid = i_gid_into_mnt(real_mnt_userns, realinode);
+ vfsuid = i_uid_into_vfsuid(real_mnt_userns, realinode);
+ vfsgid = i_gid_into_vfsgid(real_mnt_userns, realinode);
+
+ inode->i_uid = vfsuid_into_kuid(vfsuid);
+ inode->i_gid = vfsgid_into_kgid(vfsgid);
inode->i_mode = realinode->i_mode;
inode->i_atime = realinode->i_atime;
inode->i_mtime = realinode->i_mtime;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 74dc0f571dc9..d7bc81fc0840 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -25,6 +25,11 @@
#include <linux/namei.h>
#include <linux/mnt_idmapping.h>
#include <linux/iversion.h>
+#include <linux/security.h>
+#include <linux/evm.h>
+#include <linux/fsnotify.h>
+
+#include "internal.h"
static struct posix_acl **acl_by_type(struct inode *inode, int type)
{
@@ -64,7 +69,7 @@ struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type)
if (acl == ACL_DONT_CACHE) {
struct posix_acl *ret;
- ret = inode->i_op->get_acl(inode, type, LOOKUP_RCU);
+ ret = inode->i_op->get_inode_acl(inode, type, LOOKUP_RCU);
if (!IS_ERR(ret))
acl = ret;
}
@@ -106,15 +111,17 @@ void forget_all_cached_acls(struct inode *inode)
}
EXPORT_SYMBOL(forget_all_cached_acls);
-struct posix_acl *get_acl(struct inode *inode, int type)
+static struct posix_acl *__get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct inode *inode,
+ int type)
{
- void *sentinel;
+ struct posix_acl *sentinel;
struct posix_acl **p;
struct posix_acl *acl;
/*
* The sentinel is used to detect when another operation like
- * set_cached_acl() or forget_cached_acl() races with get_acl().
+ * set_cached_acl() or forget_cached_acl() races with get_inode_acl().
* It is guaranteed that is_uncached_acl(sentinel) is true.
*/
@@ -133,25 +140,27 @@ struct posix_acl *get_acl(struct inode *inode, int type)
* current value of the ACL will not be ACL_NOT_CACHED and so our own
* sentinel will not be set; another task will update the cache. We
* could wait for that other task to complete its job, but it's easier
- * to just call ->get_acl to fetch the ACL ourself. (This is going to
- * be an unlikely race.)
+ * to just call ->get_inode_acl to fetch the ACL ourself. (This is
+ * going to be an unlikely race.)
*/
cmpxchg(p, ACL_NOT_CACHED, sentinel);
/*
- * Normally, the ACL returned by ->get_acl will be cached.
+ * Normally, the ACL returned by ->get{_inode}_acl will be cached.
* A filesystem can prevent that by calling
- * forget_cached_acl(inode, type) in ->get_acl.
+ * forget_cached_acl(inode, type) in ->get{_inode}_acl.
*
- * If the filesystem doesn't have a get_acl() function at all, we'll
- * just create the negative cache entry.
+ * If the filesystem doesn't have a get{_inode}_ acl() function at all,
+ * we'll just create the negative cache entry.
*/
- if (!inode->i_op->get_acl) {
+ if (dentry && inode->i_op->get_acl) {
+ acl = inode->i_op->get_acl(mnt_userns, dentry, type);
+ } else if (inode->i_op->get_inode_acl) {
+ acl = inode->i_op->get_inode_acl(inode, type, false);
+ } else {
set_cached_acl(inode, type, NULL);
return NULL;
}
- acl = inode->i_op->get_acl(inode, type, false);
-
if (IS_ERR(acl)) {
/*
* Remove our sentinel so that we don't block future attempts
@@ -169,7 +178,12 @@ struct posix_acl *get_acl(struct inode *inode, int type)
posix_acl_release(acl);
return acl;
}
-EXPORT_SYMBOL(get_acl);
+
+struct posix_acl *get_inode_acl(struct inode *inode, int type)
+{
+ return __get_acl(&init_user_ns, NULL, inode, type);
+}
+EXPORT_SYMBOL(get_inode_acl);
/*
* Init a fresh posix_acl
@@ -578,19 +592,20 @@ EXPORT_SYMBOL(__posix_acl_chmod);
* posix_acl_chmod - chmod a posix acl
*
* @mnt_userns: user namespace of the mount @inode was found from
- * @inode: inode to check permissions on
+ * @dentry: dentry to check permissions on
* @mode: the new mode of @inode
*
- * If the inode has been found through an idmapped mount the user namespace of
+ * If the dentry has been found through an idmapped mount the user namespace of
* the vfsmount must be passed through @mnt_userns. This function will then
* take care to map the inode according to @mnt_userns before checking
* permissions. On non-idmapped mounts or if permission checking is to be
* performed on the raw inode simply passs init_user_ns.
*/
int
- posix_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode,
+ posix_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry,
umode_t mode)
{
+ struct inode *inode = d_inode(dentry);
struct posix_acl *acl;
int ret = 0;
@@ -599,7 +614,7 @@ int
if (!inode->i_op->set_acl)
return -EOPNOTSUPP;
- acl = get_acl(inode, ACL_TYPE_ACCESS);
+ acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR_OR_NULL(acl)) {
if (acl == ERR_PTR(-EOPNOTSUPP))
return 0;
@@ -609,7 +624,7 @@ int
ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
if (ret)
return ret;
- ret = inode->i_op->set_acl(mnt_userns, inode, acl, ACL_TYPE_ACCESS);
+ ret = inode->i_op->set_acl(mnt_userns, dentry, acl, ACL_TYPE_ACCESS);
posix_acl_release(acl);
return ret;
}
@@ -629,7 +644,7 @@ posix_acl_create(struct inode *dir, umode_t *mode,
if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
return 0;
- p = get_acl(dir, ACL_TYPE_DEFAULT);
+ p = get_inode_acl(dir, ACL_TYPE_DEFAULT);
if (!p || p == ERR_PTR(-EOPNOTSUPP)) {
*mode &= ~current_umask();
return 0;
@@ -732,118 +747,32 @@ static int posix_acl_fix_xattr_common(const void *value, size_t size)
return count;
}
-void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
- const struct inode *inode,
- void *value, size_t size)
-{
- struct posix_acl_xattr_header *header = value;
- struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
- struct user_namespace *fs_userns = i_user_ns(inode);
- int count;
- vfsuid_t vfsuid;
- vfsgid_t vfsgid;
- kuid_t uid;
- kgid_t gid;
-
- if (no_idmapping(mnt_userns, i_user_ns(inode)))
- return;
-
- count = posix_acl_fix_xattr_common(value, size);
- if (count <= 0)
- return;
-
- for (end = entry + count; entry != end; entry++) {
- switch (le16_to_cpu(entry->e_tag)) {
- case ACL_USER:
- uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
- vfsuid = make_vfsuid(mnt_userns, fs_userns, uid);
- entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
- vfsuid_into_kuid(vfsuid)));
- break;
- case ACL_GROUP:
- gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
- vfsgid = make_vfsgid(mnt_userns, fs_userns, gid);
- entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
- vfsgid_into_kgid(vfsgid)));
- break;
- default:
- break;
- }
- }
-}
-
-static void posix_acl_fix_xattr_userns(
- struct user_namespace *to, struct user_namespace *from,
- void *value, size_t size)
-{
- struct posix_acl_xattr_header *header = value;
- struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
- int count;
- kuid_t uid;
- kgid_t gid;
-
- count = posix_acl_fix_xattr_common(value, size);
- if (count <= 0)
- return;
-
- for (end = entry + count; entry != end; entry++) {
- switch(le16_to_cpu(entry->e_tag)) {
- case ACL_USER:
- uid = make_kuid(from, le32_to_cpu(entry->e_id));
- entry->e_id = cpu_to_le32(from_kuid(to, uid));
- break;
- case ACL_GROUP:
- gid = make_kgid(from, le32_to_cpu(entry->e_id));
- entry->e_id = cpu_to_le32(from_kgid(to, gid));
- break;
- default:
- break;
- }
- }
-}
-
-void posix_acl_fix_xattr_from_user(void *value, size_t size)
-{
- struct user_namespace *user_ns = current_user_ns();
- if (user_ns == &init_user_ns)
- return;
- posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
-}
-
-void posix_acl_fix_xattr_to_user(void *value, size_t size)
-{
- struct user_namespace *user_ns = current_user_ns();
- if (user_ns == &init_user_ns)
- return;
- posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
-}
-
/**
- * make_posix_acl - convert POSIX ACLs from uapi to VFS format using the
- * provided callbacks to map ACL_{GROUP,USER} entries into the
- * appropriate format
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
+ * posix_acl_from_xattr - convert POSIX ACLs from backing store to VFS format
+ * @userns: the filesystem's idmapping
* @value: the uapi representation of POSIX ACLs
* @size: the size of @void
- * @uid_cb: callback to use for mapping the uid stored in ACL_USER entries
- * @gid_cb: callback to use for mapping the gid stored in ACL_GROUP entries
*
- * The make_posix_acl() helper is an abstraction to translate from uapi format
- * into the VFS format allowing the caller to specific callbacks to map
- * ACL_{GROUP,USER} entries into the expected format. This is used in
- * posix_acl_from_xattr() and vfs_set_acl_prepare() and avoids pointless code
- * duplication.
+ * Filesystems that store POSIX ACLs in the unaltered uapi format should use
+ * posix_acl_from_xattr() when reading them from the backing store and
+ * converting them into the struct posix_acl VFS format. The helper is
+ * specifically intended to be called from the acl inode operation.
+ *
+ * The posix_acl_from_xattr() function will map the raw {g,u}id values stored
+ * in ACL_{GROUP,USER} entries into idmapping in @userns.
+ *
+ * Note that posix_acl_from_xattr() does not take idmapped mounts into account.
+ * If it did it calling it from the get acl inode operation would return POSIX
+ * ACLs mapped according to an idmapped mount which would mean that the value
+ * couldn't be cached for the filesystem. Idmapped mounts are taken into
+ * account on the fly during permission checking or right at the VFS -
+ * userspace boundary before reporting them to the user.
*
* Return: Allocated struct posix_acl on success, NULL for a valid header but
* without actual POSIX ACL entries, or ERR_PTR() encoded error code.
*/
-static struct posix_acl *make_posix_acl(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns, const void *value, size_t size,
- kuid_t (*uid_cb)(struct user_namespace *, struct user_namespace *,
- const struct posix_acl_xattr_entry *),
- kgid_t (*gid_cb)(struct user_namespace *, struct user_namespace *,
- const struct posix_acl_xattr_entry *))
+struct posix_acl *posix_acl_from_xattr(struct user_namespace *userns,
+ const void *value, size_t size)
{
const struct posix_acl_xattr_header *header = value;
const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end;
@@ -874,12 +803,14 @@ static struct posix_acl *make_posix_acl(struct user_namespace *mnt_userns,
break;
case ACL_USER:
- acl_e->e_uid = uid_cb(mnt_userns, fs_userns, entry);
+ acl_e->e_uid = make_kuid(userns,
+ le32_to_cpu(entry->e_id));
if (!uid_valid(acl_e->e_uid))
goto fail;
break;
case ACL_GROUP:
- acl_e->e_gid = gid_cb(mnt_userns, fs_userns, entry);
+ acl_e->e_gid = make_kgid(userns,
+ le32_to_cpu(entry->e_id));
if (!gid_valid(acl_e->e_gid))
goto fail;
break;
@@ -894,181 +825,6 @@ fail:
posix_acl_release(acl);
return ERR_PTR(-EINVAL);
}
-
-/**
- * vfs_set_acl_prepare_kuid - map ACL_USER uid according to mount- and
- * filesystem idmapping
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
- * @e: a ACL_USER entry in POSIX ACL uapi format
- *
- * The uid stored as ACL_USER entry in @e is a kuid_t stored as a raw {g,u}id
- * value. The vfs_set_acl_prepare_kuid() will recover the kuid_t through
- * KUIDT_INIT() and then map it according to the idmapped mount. The resulting
- * kuid_t is the value which the filesystem can map up into a raw backing store
- * id in the filesystem's idmapping.
- *
- * This is used in vfs_set_acl_prepare() to generate the proper VFS
- * representation of POSIX ACLs with ACL_USER entries during setxattr().
- *
- * Return: A kuid in @fs_userns for the uid stored in @e.
- */
-static inline kuid_t
-vfs_set_acl_prepare_kuid(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const struct posix_acl_xattr_entry *e)
-{
- kuid_t kuid = KUIDT_INIT(le32_to_cpu(e->e_id));
- return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
-}
-
-/**
- * vfs_set_acl_prepare_kgid - map ACL_GROUP gid according to mount- and
- * filesystem idmapping
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
- * @e: a ACL_GROUP entry in POSIX ACL uapi format
- *
- * The gid stored as ACL_GROUP entry in @e is a kgid_t stored as a raw {g,u}id
- * value. The vfs_set_acl_prepare_kgid() will recover the kgid_t through
- * KGIDT_INIT() and then map it according to the idmapped mount. The resulting
- * kgid_t is the value which the filesystem can map up into a raw backing store
- * id in the filesystem's idmapping.
- *
- * This is used in vfs_set_acl_prepare() to generate the proper VFS
- * representation of POSIX ACLs with ACL_GROUP entries during setxattr().
- *
- * Return: A kgid in @fs_userns for the gid stored in @e.
- */
-static inline kgid_t
-vfs_set_acl_prepare_kgid(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const struct posix_acl_xattr_entry *e)
-{
- kgid_t kgid = KGIDT_INIT(le32_to_cpu(e->e_id));
- return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
-}
-
-/**
- * vfs_set_acl_prepare - convert POSIX ACLs from uapi to VFS format taking
- * mount and filesystem idmappings into account
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
- * @value: the uapi representation of POSIX ACLs
- * @size: the size of @void
- *
- * When setting POSIX ACLs with ACL_{GROUP,USER} entries they need to be
- * mapped according to the relevant mount- and filesystem idmapping. It is
- * important that the ACL_{GROUP,USER} entries in struct posix_acl will be
- * mapped into k{g,u}id_t that are supposed to be mapped up in the filesystem
- * idmapping. This is crucial since the resulting struct posix_acl might be
- * cached filesystem wide. The vfs_set_acl_prepare() function will take care to
- * perform all necessary idmappings.
- *
- * Note, that since basically forever the {g,u}id values encoded as
- * ACL_{GROUP,USER} entries in the uapi POSIX ACLs passed via @value contain
- * values that have been mapped according to the caller's idmapping. In other
- * words, POSIX ACLs passed in uapi format as @value during setxattr() contain
- * {g,u}id values in their ACL_{GROUP,USER} entries that should actually have
- * been stored as k{g,u}id_t.
- *
- * This means, vfs_set_acl_prepare() needs to first recover the k{g,u}id_t by
- * calling K{G,U}IDT_INIT(). Afterwards they can be interpreted as vfs{g,u}id_t
- * through from_vfs{g,u}id() to account for any idmapped mounts. The
- * vfs_set_acl_prepare_k{g,u}id() helpers will take care to generate the
- * correct k{g,u}id_t.
- *
- * The filesystem will then receive the POSIX ACLs ready to be cached
- * filesystem wide and ready to be written to the backing store taking the
- * filesystem's idmapping into account.
- *
- * Return: Allocated struct posix_acl on success, NULL for a valid header but
- * without actual POSIX ACL entries, or ERR_PTR() encoded error code.
- */
-struct posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const void *value, size_t size)
-{
- return make_posix_acl(mnt_userns, fs_userns, value, size,
- vfs_set_acl_prepare_kuid,
- vfs_set_acl_prepare_kgid);
-}
-EXPORT_SYMBOL(vfs_set_acl_prepare);
-
-/**
- * posix_acl_from_xattr_kuid - map ACL_USER uid into filesystem idmapping
- * @mnt_userns: unused
- * @fs_userns: the filesystem's idmapping
- * @e: a ACL_USER entry in POSIX ACL uapi format
- *
- * Map the uid stored as ACL_USER entry in @e into the filesystem's idmapping.
- * This is used in posix_acl_from_xattr() to generate the proper VFS
- * representation of POSIX ACLs with ACL_USER entries.
- *
- * Return: A kuid in @fs_userns for the uid stored in @e.
- */
-static inline kuid_t
-posix_acl_from_xattr_kuid(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const struct posix_acl_xattr_entry *e)
-{
- return make_kuid(fs_userns, le32_to_cpu(e->e_id));
-}
-
-/**
- * posix_acl_from_xattr_kgid - map ACL_GROUP gid into filesystem idmapping
- * @mnt_userns: unused
- * @fs_userns: the filesystem's idmapping
- * @e: a ACL_GROUP entry in POSIX ACL uapi format
- *
- * Map the gid stored as ACL_GROUP entry in @e into the filesystem's idmapping.
- * This is used in posix_acl_from_xattr() to generate the proper VFS
- * representation of POSIX ACLs with ACL_GROUP entries.
- *
- * Return: A kgid in @fs_userns for the gid stored in @e.
- */
-static inline kgid_t
-posix_acl_from_xattr_kgid(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const struct posix_acl_xattr_entry *e)
-{
- return make_kgid(fs_userns, le32_to_cpu(e->e_id));
-}
-
-/**
- * posix_acl_from_xattr - convert POSIX ACLs from backing store to VFS format
- * @fs_userns: the filesystem's idmapping
- * @value: the uapi representation of POSIX ACLs
- * @size: the size of @void
- *
- * Filesystems that store POSIX ACLs in the unaltered uapi format should use
- * posix_acl_from_xattr() when reading them from the backing store and
- * converting them into the struct posix_acl VFS format. The helper is
- * specifically intended to be called from the ->get_acl() inode operation.
- *
- * The posix_acl_from_xattr() function will map the raw {g,u}id values stored
- * in ACL_{GROUP,USER} entries into the filesystem idmapping in @fs_userns. The
- * posix_acl_from_xattr_k{g,u}id() helpers will take care to generate the
- * correct k{g,u}id_t. The returned struct posix_acl can be cached.
- *
- * Note that posix_acl_from_xattr() does not take idmapped mounts into account.
- * If it did it calling is from the ->get_acl() inode operation would return
- * POSIX ACLs mapped according to an idmapped mount which would mean that the
- * value couldn't be cached for the filesystem. Idmapped mounts are taken into
- * account on the fly during permission checking or right at the VFS -
- * userspace boundary before reporting them to the user.
- *
- * Return: Allocated struct posix_acl on success, NULL for a valid header but
- * without actual POSIX ACL entries, or ERR_PTR() encoded error code.
- */
-struct posix_acl *
-posix_acl_from_xattr(struct user_namespace *fs_userns,
- const void *value, size_t size)
-{
- return make_posix_acl(&init_user_ns, fs_userns, value, size,
- posix_acl_from_xattr_kuid,
- posix_acl_from_xattr_kgid);
-}
EXPORT_SYMBOL (posix_acl_from_xattr);
/*
@@ -1113,35 +869,76 @@ 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(const struct xattr_handler *handler,
- struct dentry *unused, struct inode *inode,
- const char *name, void *value, size_t size)
-{
- struct posix_acl *acl;
- int error;
+/**
+ * vfs_posix_acl_to_xattr - convert from kernel to userspace representation
+ * @idmap: idmap of the mount
+ * @inode: inode the posix acls are set on
+ * @acl: the posix acls as represented by the vfs
+ * @buffer: the buffer into which to convert @acl
+ * @size: size of @buffer
+ *
+ * This converts @acl from the VFS representation in the filesystem idmapping
+ * to the uapi form reportable to userspace. And mount and caller idmappings
+ * are handled appropriately.
+ *
+ * Return: On success, the size of the stored uapi posix acls, on error a
+ * negative errno.
+ */
+static ssize_t vfs_posix_acl_to_xattr(struct mnt_idmap *idmap,
+ struct inode *inode,
+ const struct posix_acl *acl, void *buffer,
+ size_t size)
- if (!IS_POSIXACL(inode))
- return -EOPNOTSUPP;
- if (S_ISLNK(inode->i_mode))
- return -EOPNOTSUPP;
+{
+ struct posix_acl_xattr_header *ext_acl = buffer;
+ struct posix_acl_xattr_entry *ext_entry;
+ struct user_namespace *fs_userns, *caller_userns;
+ struct user_namespace *mnt_userns;
+ ssize_t real_size, n;
+ vfsuid_t vfsuid;
+ vfsgid_t vfsgid;
- acl = get_acl(inode, handler->flags);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (acl == NULL)
- return -ENODATA;
+ real_size = posix_acl_xattr_size(acl->a_count);
+ if (!buffer)
+ return real_size;
+ if (real_size > size)
+ return -ERANGE;
- error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
- posix_acl_release(acl);
+ ext_entry = (void *)(ext_acl + 1);
+ ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
- return error;
+ fs_userns = i_user_ns(inode);
+ caller_userns = current_user_ns();
+ mnt_userns = mnt_idmap_owner(idmap);
+ for (n=0; n < acl->a_count; n++, ext_entry++) {
+ const struct posix_acl_entry *acl_e = &acl->a_entries[n];
+ ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
+ ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
+ switch(acl_e->e_tag) {
+ case ACL_USER:
+ vfsuid = make_vfsuid(mnt_userns, fs_userns, acl_e->e_uid);
+ ext_entry->e_id = cpu_to_le32(from_kuid(
+ caller_userns, vfsuid_into_kuid(vfsuid)));
+ break;
+ case ACL_GROUP:
+ vfsgid = make_vfsgid(mnt_userns, fs_userns, acl_e->e_gid);
+ ext_entry->e_id = cpu_to_le32(from_kgid(
+ caller_userns, vfsgid_into_kgid(vfsgid)));
+ break;
+ default:
+ ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
+ break;
+ }
+ }
+ return real_size;
}
int
-set_posix_acl(struct user_namespace *mnt_userns, struct inode *inode,
+set_posix_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
int type, struct posix_acl *acl)
{
+ struct inode *inode = d_inode(dentry);
+
if (!IS_POSIXACL(inode))
return -EOPNOTSUPP;
if (!inode->i_op->set_acl)
@@ -1157,40 +954,10 @@ set_posix_acl(struct user_namespace *mnt_userns, struct inode *inode,
if (ret)
return ret;
}
- return inode->i_op->set_acl(mnt_userns, inode, acl, type);
+ return inode->i_op->set_acl(mnt_userns, dentry, acl, type);
}
EXPORT_SYMBOL(set_posix_acl);
-static int
-posix_acl_xattr_set(const struct xattr_handler *handler,
- struct user_namespace *mnt_userns,
- struct dentry *unused, struct inode *inode,
- const char *name, const void *value, size_t size,
- int flags)
-{
- struct posix_acl *acl = NULL;
- int ret;
-
- if (value) {
- /*
- * By the time we end up here the {g,u}ids stored in
- * ACL_{GROUP,USER} have already been mapped according to the
- * caller's idmapping. The vfs_set_acl_prepare() helper will
- * recover them and take idmapped mounts into account. The
- * filesystem will receive the POSIX ACLs in the correct
- * format ready to be cached or written to the backing store
- * taking the filesystem idmapping into account.
- */
- acl = vfs_set_acl_prepare(mnt_userns, i_user_ns(inode),
- value, size);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- }
- ret = set_posix_acl(mnt_userns, inode, handler->flags, acl);
- posix_acl_release(acl);
- return ret;
-}
-
static bool
posix_acl_xattr_list(struct dentry *dentry)
{
@@ -1201,8 +968,6 @@ const struct xattr_handler posix_acl_access_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = posix_acl_xattr_list,
- .get = posix_acl_xattr_get,
- .set = posix_acl_xattr_set,
};
EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
@@ -1210,15 +975,14 @@ const struct xattr_handler posix_acl_default_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = posix_acl_xattr_list,
- .get = posix_acl_xattr_get,
- .set = posix_acl_xattr_set,
};
EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler);
-int simple_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int simple_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
+ struct inode *inode = d_inode(dentry);
if (type == ACL_TYPE_ACCESS) {
error = posix_acl_update_mode(mnt_userns, inode,
@@ -1252,3 +1016,252 @@ int simple_acl_create(struct inode *dir, struct inode *inode)
posix_acl_release(acl);
return 0;
}
+
+static int vfs_set_acl_idmapped_mnt(struct user_namespace *mnt_userns,
+ struct user_namespace *fs_userns,
+ struct posix_acl *acl)
+{
+ for (int n = 0; n < acl->a_count; n++) {
+ struct posix_acl_entry *acl_e = &acl->a_entries[n];
+
+ switch (acl_e->e_tag) {
+ case ACL_USER:
+ acl_e->e_uid = from_vfsuid(mnt_userns, fs_userns,
+ VFSUIDT_INIT(acl_e->e_uid));
+ break;
+ case ACL_GROUP:
+ acl_e->e_gid = from_vfsgid(mnt_userns, fs_userns,
+ VFSGIDT_INIT(acl_e->e_gid));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * vfs_set_acl - set posix acls
+ * @mnt_userns: user namespace of the mount
+ * @dentry: the dentry based on which to set the posix acls
+ * @acl_name: the name of the posix acl
+ * @kacl: the posix acls in the appropriate VFS format
+ *
+ * This function sets @kacl. The caller must all posix_acl_release() on @kacl
+ * afterwards.
+ *
+ * Return: On success 0, on error negative errno.
+ */
+int vfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
+{
+ int acl_type;
+ int error;
+ struct inode *inode = d_inode(dentry);
+ struct inode *delegated_inode = NULL;
+
+ acl_type = posix_acl_type(acl_name);
+ if (acl_type < 0)
+ return -EINVAL;
+
+ if (kacl) {
+ /*
+ * If we're on an idmapped mount translate from mount specific
+ * vfs{g,u}id_t into global filesystem k{g,u}id_t.
+ * Afterwards we can cache the POSIX ACLs filesystem wide and -
+ * if this is a filesystem with a backing store - ultimately
+ * translate them to backing store values.
+ */
+ error = vfs_set_acl_idmapped_mnt(mnt_userns, i_user_ns(inode), kacl);
+ if (error)
+ return error;
+ }
+
+retry_deleg:
+ inode_lock(inode);
+
+ /*
+ * We only care about restrictions the inode struct itself places upon
+ * us otherwise POSIX ACLs aren't subject to any VFS restrictions.
+ */
+ error = may_write_xattr(mnt_userns, inode);
+ if (error)
+ goto out_inode_unlock;
+
+ error = security_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
+ if (error)
+ goto out_inode_unlock;
+
+ error = try_break_deleg(inode, &delegated_inode);
+ if (error)
+ goto out_inode_unlock;
+
+ if (inode->i_opflags & IOP_XATTR)
+ error = set_posix_acl(mnt_userns, dentry, acl_type, kacl);
+ else if (unlikely(is_bad_inode(inode)))
+ error = -EIO;
+ else
+ error = -EOPNOTSUPP;
+ if (!error) {
+ fsnotify_xattr(dentry);
+ evm_inode_post_set_acl(dentry, acl_name, kacl);
+ }
+
+out_inode_unlock:
+ inode_unlock(inode);
+
+ if (delegated_inode) {
+ error = break_deleg_wait(&delegated_inode);
+ if (!error)
+ goto retry_deleg;
+ }
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(vfs_set_acl);
+
+/**
+ * vfs_get_acl - get posix acls
+ * @mnt_userns: user namespace of the mount
+ * @dentry: the dentry based on which to retrieve the posix acls
+ * @acl_name: the name of the posix acl
+ *
+ * This function retrieves @kacl from the filesystem. The caller must all
+ * posix_acl_release() on @kacl.
+ *
+ * Return: On success POSIX ACLs in VFS format, on error negative errno.
+ */
+struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ struct inode *inode = d_inode(dentry);
+ struct posix_acl *acl;
+ int acl_type, error;
+
+ acl_type = posix_acl_type(acl_name);
+ if (acl_type < 0)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * The VFS has no restrictions on reading POSIX ACLs so calling
+ * something like xattr_permission() isn't needed. Only LSMs get a say.
+ */
+ error = security_inode_get_acl(mnt_userns, dentry, acl_name);
+ if (error)
+ return ERR_PTR(error);
+
+ if (!IS_POSIXACL(inode))
+ return ERR_PTR(-EOPNOTSUPP);
+ if (S_ISLNK(inode->i_mode))
+ return ERR_PTR(-EOPNOTSUPP);
+
+ acl = __get_acl(mnt_userns, dentry, inode, acl_type);
+ if (IS_ERR(acl))
+ return acl;
+ if (!acl)
+ return ERR_PTR(-ENODATA);
+
+ return acl;
+}
+EXPORT_SYMBOL_GPL(vfs_get_acl);
+
+/**
+ * vfs_remove_acl - remove posix acls
+ * @mnt_userns: user namespace of the mount
+ * @dentry: the dentry based on which to retrieve the posix acls
+ * @acl_name: the name of the posix acl
+ *
+ * This function removes posix acls.
+ *
+ * Return: On success 0, on error negative errno.
+ */
+int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name)
+{
+ int acl_type;
+ int error;
+ struct inode *inode = d_inode(dentry);
+ struct inode *delegated_inode = NULL;
+
+ acl_type = posix_acl_type(acl_name);
+ if (acl_type < 0)
+ return -EINVAL;
+
+retry_deleg:
+ inode_lock(inode);
+
+ /*
+ * We only care about restrictions the inode struct itself places upon
+ * us otherwise POSIX ACLs aren't subject to any VFS restrictions.
+ */
+ error = may_write_xattr(mnt_userns, inode);
+ if (error)
+ goto out_inode_unlock;
+
+ error = security_inode_remove_acl(mnt_userns, dentry, acl_name);
+ if (error)
+ goto out_inode_unlock;
+
+ error = try_break_deleg(inode, &delegated_inode);
+ if (error)
+ goto out_inode_unlock;
+
+ if (inode->i_opflags & IOP_XATTR)
+ error = set_posix_acl(mnt_userns, dentry, acl_type, NULL);
+ else if (unlikely(is_bad_inode(inode)))
+ error = -EIO;
+ else
+ error = -EOPNOTSUPP;
+ if (!error) {
+ fsnotify_xattr(dentry);
+ evm_inode_post_remove_acl(mnt_userns, dentry, acl_name);
+ }
+
+out_inode_unlock:
+ inode_unlock(inode);
+
+ if (delegated_inode) {
+ error = break_deleg_wait(&delegated_inode);
+ if (!error)
+ goto retry_deleg;
+ }
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(vfs_remove_acl);
+
+int do_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, const void *kvalue, size_t size)
+{
+ int error;
+ struct posix_acl *acl = NULL;
+
+ if (size) {
+ /*
+ * Note that posix_acl_from_xattr() uses GFP_NOFS when it
+ * probably doesn't need to here.
+ */
+ acl = posix_acl_from_xattr(current_user_ns(), kvalue, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ }
+
+ error = vfs_set_acl(mnt_idmap_owner(idmap), dentry, acl_name, acl);
+ posix_acl_release(acl);
+ return error;
+}
+
+ssize_t do_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, void *kvalue, size_t size)
+{
+ ssize_t error;
+ struct posix_acl *acl;
+
+ acl = vfs_get_acl(mnt_idmap_owner(idmap), dentry, acl_name);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ error = vfs_posix_acl_to_xattr(idmap, d_inode(dentry),
+ acl, kvalue, size);
+ posix_acl_release(acl);
+ return error;
+}
diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c
index fa762c5fbcb2..91fe1597af7b 100644
--- a/fs/proc/cmdline.c
+++ b/fs/proc/cmdline.c
@@ -3,6 +3,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include "internal.h"
static int cmdline_proc_show(struct seq_file *m, void *v)
{
@@ -13,7 +14,10 @@ static int cmdline_proc_show(struct seq_file *m, void *v)
static int __init proc_cmdline_init(void)
{
- proc_create_single("cmdline", 0, NULL, cmdline_proc_show);
+ struct proc_dir_entry *pde;
+
+ pde = proc_create_single("cmdline", 0, NULL, cmdline_proc_show);
+ pde->size = saved_command_line_len + 1;
return 0;
}
fs_initcall(proc_cmdline_init);
diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index dfe6ce3505ce..e0758fe7936d 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -33,7 +33,16 @@ static int show_console_dev(struct seq_file *m, void *v)
if (con->device) {
const struct tty_driver *driver;
int index;
+
+ /*
+ * Take console_lock to serialize device() callback with
+ * other console operations. For example, fg_console is
+ * modified under console_lock when switching vt.
+ */
+ console_lock();
driver = con->device(con, &index);
+ console_unlock();
+
if (driver) {
dev = MKDEV(driver->major, driver->minor_start);
dev += index;
@@ -63,7 +72,12 @@ static void *c_start(struct seq_file *m, loff_t *pos)
struct console *con;
loff_t off = 0;
- console_lock();
+ /*
+ * Hold the console_list_lock to guarantee safe traversal of the
+ * console list. SRCU cannot be used because there is no
+ * place to store the SRCU cookie.
+ */
+ console_list_lock();
for_each_console(con)
if (off++ == *pos)
break;
@@ -74,13 +88,14 @@ static void *c_start(struct seq_file *m, loff_t *pos)
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
struct console *con = v;
+
++*pos;
- return con->next;
+ return hlist_entry_safe(con->node.next, struct console, node);
}
static void c_stop(struct seq_file *m, void *v)
{
- console_unlock();
+ console_list_unlock();
}
static const struct seq_operations consoles_op = {
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 913bef0d2a36..fc46d6fe080c 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -7,6 +7,7 @@
#include <linux/namei.h>
#include <linux/pid.h>
#include <linux/ptrace.h>
+#include <linux/bitmap.h>
#include <linux/security.h>
#include <linux/file.h>
#include <linux/seq_file.h>
@@ -279,6 +280,30 @@ out:
return 0;
}
+static int proc_readfd_count(struct inode *inode, loff_t *count)
+{
+ struct task_struct *p = get_proc_task(inode);
+ struct fdtable *fdt;
+
+ if (!p)
+ return -ENOENT;
+
+ task_lock(p);
+ if (p->files) {
+ rcu_read_lock();
+
+ fdt = files_fdtable(p->files);
+ *count = bitmap_weight(fdt->open_fds, fdt->max_fds);
+
+ rcu_read_unlock();
+ }
+ task_unlock(p);
+
+ put_task_struct(p);
+
+ return 0;
+}
+
static int proc_readfd(struct file *file, struct dir_context *ctx)
{
return proc_readfd_common(file, ctx, proc_fd_instantiate);
@@ -319,9 +344,29 @@ int proc_fd_permission(struct user_namespace *mnt_userns,
return rv;
}
+static int proc_fd_getattr(struct user_namespace *mnt_userns,
+ const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int query_flags)
+{
+ struct inode *inode = d_inode(path->dentry);
+ int rv = 0;
+
+ generic_fillattr(&init_user_ns, inode, stat);
+
+ /* If it's a directory, put the number of open fds there */
+ if (S_ISDIR(inode->i_mode)) {
+ rv = proc_readfd_count(inode, &stat->size);
+ if (rv < 0)
+ return rv;
+ }
+
+ return rv;
+}
+
const struct inode_operations proc_fd_inode_operations = {
.lookup = proc_lookupfd,
.permission = proc_fd_permission,
+ .getattr = proc_fd_getattr,
.setattr = proc_setattr,
};
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 5101131e6047..440960110a42 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -115,7 +115,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
#endif
show_val_kb(m, "PageTables: ",
global_node_page_state(NR_PAGETABLE));
- show_val_kb(m, "SecPageTables: ",
+ show_val_kb(m, "SecPageTables: ",
global_node_page_state(NR_SECONDARY_PAGETABLE));
show_val_kb(m, "NFS_Unstable: ", 0);
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index f2aa86c421f2..09a81e4b1273 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -199,7 +199,7 @@ ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
struct kvec kvec = { .iov_base = buf, .iov_len = count };
struct iov_iter iter;
- iov_iter_kvec(&iter, READ, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
return read_from_oldmem(&iter, count, ppos, false);
}
@@ -212,7 +212,7 @@ ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
struct kvec kvec = { .iov_base = buf, .iov_len = count };
struct iov_iter iter;
- iov_iter_kvec(&iter, READ, &kvec, 1, count);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
return read_from_oldmem(&iter, count, ppos,
cc_platform_has(CC_ATTR_MEM_ENCRYPT));
@@ -437,7 +437,7 @@ static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
offset = (loff_t) index << PAGE_SHIFT;
kvec.iov_base = page_address(page);
kvec.iov_len = PAGE_SIZE;
- iov_iter_kvec(&iter, READ, &kvec, 1, PAGE_SIZE);
+ iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, PAGE_SIZE);
rc = __read_vmcore(&iter, &offset);
if (rc < 0) {
@@ -1567,6 +1567,7 @@ static int __init vmcore_init(void)
return rc;
rc = parse_crash_elf_headers();
if (rc) {
+ elfcorehdr_free(elfcorehdr_addr);
pr_warn("Kdump: vmcore not initialized\n");
return rc;
}
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 0c034ea39954..cbc0b468c1ab 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -89,6 +89,11 @@ static char *compress =
module_param(compress, charp, 0444);
MODULE_PARM_DESC(compress, "compression to use");
+/* How much of the kernel log to snapshot */
+unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
+module_param(kmsg_bytes, ulong, 0444);
+MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
+
/* Compression parameters */
static struct crypto_comp *tfm;
@@ -100,9 +105,6 @@ struct pstore_zbackend {
static char *big_oops_buf;
static size_t big_oops_buf_sz;
-/* How much of the console log to snapshot */
-unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
-
void pstore_set_kmsg_bytes(int bytes)
{
kmsg_bytes = bytes;
@@ -391,6 +393,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
const char *why;
unsigned int part = 1;
unsigned long flags = 0;
+ int saved_ret = 0;
int ret;
why = kmsg_dump_reason_str(reason);
@@ -461,12 +464,21 @@ static void pstore_dump(struct kmsg_dumper *dumper,
if (ret == 0 && reason == KMSG_DUMP_OOPS) {
pstore_new_entry = 1;
pstore_timer_kick();
+ } else {
+ /* Preserve only the first non-zero returned value. */
+ if (!saved_ret)
+ saved_ret = ret;
}
total += record.size;
part++;
}
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
+
+ if (saved_ret) {
+ pr_err_once("backend (%s) writing error (%d)\n", psinfo->name,
+ saved_ret);
+ }
}
static struct kmsg_dumper pstore_dumper = {
@@ -562,8 +574,9 @@ out:
int pstore_register(struct pstore_info *psi)
{
if (backend && strcmp(backend, psi->name)) {
- pr_warn("ignoring unexpected backend '%s'\n", psi->name);
- return -EPERM;
+ pr_warn("backend '%s' already in use: ignoring '%s'\n",
+ backend, psi->name);
+ return -EBUSY;
}
/* Sanity check flags. */
@@ -662,6 +675,8 @@ void pstore_unregister(struct pstore_info *psi)
psinfo = NULL;
kfree(backend);
backend = NULL;
+
+ pr_info("Unregistered %s as persistent store backend\n", psi->name);
mutex_unlock(&psinfo_lock);
}
EXPORT_SYMBOL_GPL(pstore_unregister);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index fefe3d391d3a..9a5052431fd3 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -18,10 +18,11 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/compiler.h>
-#include <linux/pstore_ram.h>
#include <linux/of.h>
#include <linux/of_address.h>
+
#include "internal.h"
+#include "ram_internal.h"
#define RAMOOPS_KERNMSG_HDR "===="
#define MIN_MEM_SIZE 4096UL
@@ -451,20 +452,28 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
{
int i;
+ /* Free pmsg PRZ */
+ persistent_ram_free(&cxt->mprz);
+
+ /* Free console PRZ */
+ persistent_ram_free(&cxt->cprz);
+
/* Free dump PRZs */
if (cxt->dprzs) {
for (i = 0; i < cxt->max_dump_cnt; i++)
- persistent_ram_free(cxt->dprzs[i]);
+ persistent_ram_free(&cxt->dprzs[i]);
kfree(cxt->dprzs);
+ cxt->dprzs = NULL;
cxt->max_dump_cnt = 0;
}
/* Free ftrace PRZs */
if (cxt->fprzs) {
for (i = 0; i < cxt->max_ftrace_cnt; i++)
- persistent_ram_free(cxt->fprzs[i]);
+ persistent_ram_free(&cxt->fprzs[i]);
kfree(cxt->fprzs);
+ cxt->fprzs = NULL;
cxt->max_ftrace_cnt = 0;
}
}
@@ -548,9 +557,10 @@ static int ramoops_init_przs(const char *name,
while (i > 0) {
i--;
- persistent_ram_free(prz_ar[i]);
+ persistent_ram_free(&prz_ar[i]);
}
kfree(prz_ar);
+ prz_ar = NULL;
goto fail;
}
*paddr += zone_sz;
@@ -735,6 +745,7 @@ static int ramoops_probe(struct platform_device *pdev)
/* Make sure we didn't get bogus platform data pointer. */
if (!pdata) {
pr_err("NULL platform data\n");
+ err = -EINVAL;
goto fail_out;
}
@@ -742,6 +753,7 @@ static int ramoops_probe(struct platform_device *pdev)
!pdata->ftrace_size && !pdata->pmsg_size)) {
pr_err("The memory size and the record/console size must be "
"non-zero\n");
+ err = -EINVAL;
goto fail_out;
}
@@ -772,12 +784,17 @@ static int ramoops_probe(struct platform_device *pdev)
dump_mem_sz, cxt->record_size,
&cxt->max_dump_cnt, 0, 0);
if (err)
- goto fail_out;
+ goto fail_init;
err = ramoops_init_prz("console", dev, cxt, &cxt->cprz, &paddr,
cxt->console_size, 0);
if (err)
- goto fail_init_cprz;
+ goto fail_init;
+
+ err = ramoops_init_prz("pmsg", dev, cxt, &cxt->mprz, &paddr,
+ cxt->pmsg_size, 0);
+ if (err)
+ goto fail_init;
cxt->max_ftrace_cnt = (cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)
? nr_cpu_ids
@@ -788,12 +805,7 @@ static int ramoops_probe(struct platform_device *pdev)
(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)
? PRZ_FLAG_NO_LOCK : 0);
if (err)
- goto fail_init_fprz;
-
- err = ramoops_init_prz("pmsg", dev, cxt, &cxt->mprz, &paddr,
- cxt->pmsg_size, 0);
- if (err)
- goto fail_init_mprz;
+ goto fail_init;
cxt->pstore.data = cxt;
/*
@@ -857,11 +869,7 @@ fail_buf:
kfree(cxt->pstore.buf);
fail_clear:
cxt->pstore.bufsize = 0;
- persistent_ram_free(cxt->mprz);
-fail_init_mprz:
-fail_init_fprz:
- persistent_ram_free(cxt->cprz);
-fail_init_cprz:
+fail_init:
ramoops_free_przs(cxt);
fail_out:
return err;
@@ -876,8 +884,6 @@ static int ramoops_remove(struct platform_device *pdev)
kfree(cxt->pstore.buf);
cxt->pstore.bufsize = 0;
- persistent_ram_free(cxt->mprz);
- persistent_ram_free(cxt->cprz);
ramoops_free_przs(cxt);
return 0;
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index a89e33719fcf..966191d3a5ba 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -13,13 +13,14 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/memblock.h>
-#include <linux/pstore_ram.h>
#include <linux/rslib.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/page.h>
+#include "ram_internal.h"
+
/**
* struct persistent_ram_buffer - persistent circular RAM buffer
*
@@ -439,7 +440,11 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size,
phys_addr_t addr = page_start + i * PAGE_SIZE;
pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
}
- vaddr = vmap(pages, page_count, VM_MAP, prot);
+ /*
+ * VM_IOREMAP used here to bypass this region during vread()
+ * and kmap_atomic() (i.e. kcore) to avoid __va() failures.
+ */
+ vaddr = vmap(pages, page_count, VM_MAP | VM_IOREMAP, prot);
kfree(pages);
/*
@@ -543,8 +548,14 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
return 0;
}
-void persistent_ram_free(struct persistent_ram_zone *prz)
+void persistent_ram_free(struct persistent_ram_zone **_prz)
{
+ struct persistent_ram_zone *prz;
+
+ if (!_prz)
+ return;
+
+ prz = *_prz;
if (!prz)
return;
@@ -568,6 +579,7 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
persistent_ram_free_old(prz);
kfree(prz->label);
kfree(prz);
+ *_prz = NULL;
}
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
@@ -604,6 +616,6 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
return prz;
err:
- persistent_ram_free(prz);
+ persistent_ram_free(&prz);
return ERR_PTR(ret);
}
diff --git a/fs/pstore/ram_internal.h b/fs/pstore/ram_internal.h
new file mode 100644
index 000000000000..5f694698351f
--- /dev/null
+++ b/fs/pstore/ram_internal.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ * Copyright (C) 2011 Google, Inc.
+ */
+
+#include <linux/pstore_ram.h>
+
+/*
+ * Choose whether access to the RAM zone requires locking or not. If a zone
+ * can be written to from different CPUs like with ftrace for example, then
+ * PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
+ */
+#define PRZ_FLAG_NO_LOCK BIT(0)
+/*
+ * If a PRZ should only have a single-boot lifetime, this marks it as
+ * getting wiped after its contents get copied out after boot.
+ */
+#define PRZ_FLAG_ZAP_OLD BIT(1)
+
+/**
+ * struct persistent_ram_zone - Details of a persistent RAM zone (PRZ)
+ * used as a pstore backend
+ *
+ * @paddr: physical address of the mapped RAM area
+ * @size: size of mapping
+ * @label: unique name of this PRZ
+ * @type: frontend type for this PRZ
+ * @flags: holds PRZ_FLAGS_* bits
+ *
+ * @buffer_lock:
+ * locks access to @buffer "size" bytes and "start" offset
+ * @buffer:
+ * pointer to actual RAM area managed by this PRZ
+ * @buffer_size:
+ * bytes in @buffer->data (not including any trailing ECC bytes)
+ *
+ * @par_buffer:
+ * pointer into @buffer->data containing ECC bytes for @buffer->data
+ * @par_header:
+ * pointer into @buffer->data containing ECC bytes for @buffer header
+ * (i.e. all fields up to @data)
+ * @rs_decoder:
+ * RSLIB instance for doing ECC calculations
+ * @corrected_bytes:
+ * ECC corrected bytes accounting since boot
+ * @bad_blocks:
+ * ECC uncorrectable bytes accounting since boot
+ * @ecc_info:
+ * ECC configuration details
+ *
+ * @old_log:
+ * saved copy of @buffer->data prior to most recent wipe
+ * @old_log_size:
+ * bytes contained in @old_log
+ *
+ */
+struct persistent_ram_zone {
+ phys_addr_t paddr;
+ size_t size;
+ void *vaddr;
+ char *label;
+ enum pstore_type_id type;
+ u32 flags;
+
+ raw_spinlock_t buffer_lock;
+ struct persistent_ram_buffer *buffer;
+ size_t buffer_size;
+
+ char *par_buffer;
+ char *par_header;
+ struct rs_control *rs_decoder;
+ int corrected_bytes;
+ int bad_blocks;
+ struct persistent_ram_ecc_info ecc_info;
+
+ char *old_log;
+ size_t old_log_size;
+};
+
+struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
+ u32 sig, struct persistent_ram_ecc_info *ecc_info,
+ unsigned int memtype, u32 flags, char *label);
+void persistent_ram_free(struct persistent_ram_zone **_prz);
+void persistent_ram_zap(struct persistent_ram_zone *prz);
+
+int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
+ unsigned int count);
+int persistent_ram_write_user(struct persistent_ram_zone *prz,
+ const void __user *s, unsigned int count);
+
+void persistent_ram_save_old(struct persistent_ram_zone *prz);
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
+void *persistent_ram_old(struct persistent_ram_zone *prz);
+void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+ char *str, size_t len);
diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c
index 017d0d4ad329..2770746bb7aa 100644
--- a/fs/pstore/zone.c
+++ b/fs/pstore/zone.c
@@ -761,7 +761,7 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt,
/* avoid destroying old data, allocate a new one */
len = zone->buffer_size + sizeof(*zone->buffer);
zone->oldbuf = zone->buffer;
- zone->buffer = kzalloc(len, GFP_KERNEL);
+ zone->buffer = kzalloc(len, GFP_ATOMIC);
if (!zone->buffer) {
zone->buffer = zone->oldbuf;
return -ENOMEM;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 0427b44bfee5..f27faf5db554 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2324,6 +2324,8 @@ static int vfs_setup_quota_inode(struct inode *inode, int type)
struct super_block *sb = inode->i_sb;
struct quota_info *dqopt = sb_dqopt(sb);
+ if (is_bad_inode(inode))
+ return -EUCLEAN;
if (!S_ISREG(inode->i_mode))
return -EACCES;
if (IS_RDONLY(inode))
diff --git a/fs/read_write.c b/fs/read_write.c
index 328ce8cf9a85..7a2ff6157eda 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -384,7 +384,7 @@ static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = (ppos ? *ppos : 0);
- iov_iter_ubuf(&iter, READ, buf, len);
+ iov_iter_ubuf(&iter, ITER_DEST, buf, len);
ret = call_read_iter(filp, &kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
@@ -424,7 +424,7 @@ ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
init_sync_kiocb(&kiocb, file);
kiocb.ki_pos = pos ? *pos : 0;
- iov_iter_kvec(&iter, READ, &iov, 1, iov.iov_len);
+ iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len);
ret = file->f_op->read_iter(&kiocb, &iter);
if (ret > 0) {
if (pos)
@@ -486,7 +486,7 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = (ppos ? *ppos : 0);
- iov_iter_ubuf(&iter, WRITE, (void __user *)buf, len);
+ iov_iter_ubuf(&iter, ITER_SOURCE, (void __user *)buf, len);
ret = call_write_iter(filp, &kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
@@ -533,7 +533,7 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
.iov_len = min_t(size_t, count, MAX_RW_COUNT),
};
struct iov_iter iter;
- iov_iter_kvec(&iter, WRITE, &iov, 1, iov.iov_len);
+ iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len);
return __kernel_write_iter(file, &iter, pos);
}
/*
@@ -911,7 +911,7 @@ static ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
struct iov_iter iter;
ssize_t ret;
- ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+ ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
if (ret >= 0) {
ret = do_iter_read(file, &iter, pos, flags);
kfree(iov);
@@ -928,7 +928,7 @@ static ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
struct iov_iter iter;
ssize_t ret;
- ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+ ret = import_iovec(ITER_SOURCE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
if (ret >= 0) {
file_start_write(file);
ret = do_iter_write(file, &iter, pos, flags);
@@ -1388,6 +1388,8 @@ ssize_t generic_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)
{
+ lockdep_assert(sb_write_started(file_inode(file_out)->i_sb));
+
return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
}
@@ -1424,7 +1426,9 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
* and several different sets of file_operations, but they all end up
* using the same ->copy_file_range() function pointer.
*/
- if (file_out->f_op->copy_file_range) {
+ if (flags & COPY_FILE_SPLICE) {
+ /* cross sb splice is allowed */
+ } else if (file_out->f_op->copy_file_range) {
if (file_in->f_op->copy_file_range !=
file_out->f_op->copy_file_range)
return -EXDEV;
@@ -1474,8 +1478,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
size_t len, unsigned int flags)
{
ssize_t ret;
+ bool splice = flags & COPY_FILE_SPLICE;
- if (flags != 0)
+ if (flags & ~COPY_FILE_SPLICE)
return -EINVAL;
ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
@@ -1501,14 +1506,14 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
* same sb using clone, but for filesystems where both clone and copy
* are supported (e.g. nfs,cifs), we only call the copy method.
*/
- if (file_out->f_op->copy_file_range) {
+ if (!splice && 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);
goto done;
}
- if (file_in->f_op->remap_file_range &&
+ if (!splice && file_in->f_op->remap_file_range &&
file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
ret = file_in->f_op->remap_file_range(file_in, pos_in,
file_out, pos_out,
@@ -1528,6 +1533,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
* consistent story about which filesystems support copy_file_range()
* and which filesystems do not, that will allow userspace tools to
* make consistent desicions w.r.t using copy_file_range().
+ *
+ * We also get here if caller (e.g. nfsd) requested COPY_FILE_SPLICE.
*/
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
flags);
@@ -1582,6 +1589,10 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
pos_out = f_out.file->f_pos;
}
+ ret = -EINVAL;
+ if (flags != 0)
+ goto out;
+
ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
flags);
if (ret > 0) {
diff --git a/fs/reiserfs/acl.h b/fs/reiserfs/acl.h
index d9052b8ce6dd..29c503a06db4 100644
--- a/fs/reiserfs/acl.h
+++ b/fs/reiserfs/acl.h
@@ -49,9 +49,9 @@ static inline int reiserfs_acl_count(size_t size)
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type, bool rcu);
-int reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+int reiserfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
-int reiserfs_acl_chmod(struct inode *inode);
+int reiserfs_acl_chmod(struct dentry *dentry);
int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
struct inode *dir, struct dentry *dentry,
struct inode *inode);
@@ -63,7 +63,7 @@ int reiserfs_cache_default_acl(struct inode *dir);
#define reiserfs_get_acl NULL
#define reiserfs_set_acl NULL
-static inline int reiserfs_acl_chmod(struct inode *inode)
+static inline int reiserfs_acl_chmod(struct dentry *dentry)
{
return 0;
}
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 6e228bfbe7ef..467d13da198f 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -256,7 +256,7 @@ const struct inode_operations reiserfs_file_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
- .get_acl = reiserfs_get_acl,
+ .get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
.fileattr_get = reiserfs_fileattr_get,
.fileattr_set = reiserfs_fileattr_set,
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index b9580a6515ee..c7d1fa526dea 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -3404,7 +3404,7 @@ int reiserfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
if (!error && reiserfs_posixacl(inode->i_sb)) {
if (attr->ia_valid & ATTR_MODE)
- error = reiserfs_acl_chmod(inode);
+ error = reiserfs_acl_chmod(dentry);
}
out:
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 3d7a35d6a18b..0b8aa99749f1 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -696,6 +696,7 @@ static int reiserfs_create(struct user_namespace *mnt_userns, struct inode *dir,
out_failed:
reiserfs_write_unlock(dir->i_sb);
+ reiserfs_security_free(&security);
return retval;
}
@@ -779,6 +780,7 @@ static int reiserfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
out_failed:
reiserfs_write_unlock(dir->i_sb);
+ reiserfs_security_free(&security);
return retval;
}
@@ -878,6 +880,7 @@ static int reiserfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
retval = journal_end(&th);
out_failed:
reiserfs_write_unlock(dir->i_sb);
+ reiserfs_security_free(&security);
return retval;
}
@@ -1194,6 +1197,7 @@ static int reiserfs_symlink(struct user_namespace *mnt_userns,
retval = journal_end(&th);
out_failed:
reiserfs_write_unlock(parent_dir->i_sb);
+ reiserfs_security_free(&security);
return retval;
}
@@ -1659,7 +1663,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
- .get_acl = reiserfs_get_acl,
+ .get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
.fileattr_get = reiserfs_fileattr_get,
.fileattr_set = reiserfs_fileattr_set,
@@ -1683,6 +1687,6 @@ const struct inode_operations reiserfs_special_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
- .get_acl = reiserfs_get_acl,
+ .get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
};
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index d6fcddc46f5b..93fe414fed18 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -18,7 +18,7 @@ static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th,
int
-reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+reiserfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error, error2;
@@ -26,6 +26,7 @@ reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
size_t jcreate_blocks;
int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;
int update_mode = 0;
+ struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
/*
@@ -371,7 +372,7 @@ int reiserfs_cache_default_acl(struct inode *inode)
if (IS_PRIVATE(inode))
return 0;
- acl = get_acl(inode, ACL_TYPE_DEFAULT);
+ acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (acl && !IS_ERR(acl)) {
int size = reiserfs_acl_size(acl->a_count);
@@ -396,13 +397,15 @@ int reiserfs_cache_default_acl(struct inode *inode)
/*
* Called under i_mutex
*/
-int reiserfs_acl_chmod(struct inode *inode)
+int reiserfs_acl_chmod(struct dentry *dentry)
{
+ struct inode *inode = d_inode(dentry);
+
if (IS_PRIVATE(inode))
return 0;
if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
!reiserfs_posixacl(inode->i_sb))
return 0;
- return posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
+ return posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
}
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c
index 8965c8e5e172..857a65b05726 100644
--- a/fs/reiserfs/xattr_security.c
+++ b/fs/reiserfs/xattr_security.c
@@ -50,6 +50,7 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode,
int error;
sec->name = NULL;
+ sec->value = NULL;
/* Don't add selinux attributes on xattrs - they'll never get used */
if (IS_PRIVATE(dir))
@@ -95,7 +96,6 @@ int reiserfs_security_write(struct reiserfs_transaction_handle *th,
void reiserfs_security_free(struct reiserfs_security_handle *sec)
{
- kfree(sec->name);
kfree(sec->value);
sec->name = NULL;
sec->value = NULL;
diff --git a/fs/remap_range.c b/fs/remap_range.c
index 654912d06862..41f60477bb41 100644
--- a/fs/remap_range.c
+++ b/fs/remap_range.c
@@ -304,7 +304,7 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
/* Check that we don't violate system file offset limits. */
ret = generic_remap_checks(file_in, pos_in, file_out, pos_out, len,
remap_flags);
- if (ret)
+ if (ret || *len == 0)
return ret;
/* Wait for the completion of any pending IOs on both files */
@@ -328,9 +328,6 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
if (remap_flags & REMAP_FILE_DEDUP) {
bool is_same = false;
- if (*len == 0)
- return 0;
-
if (!IS_DAX(inode_in))
ret = vfs_dedupe_file_range_compare(file_in, pos_in,
file_out, pos_out, *len, &is_same);
@@ -348,7 +345,7 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
ret = generic_remap_check_len(inode_in, inode_out, pos_out, len,
remap_flags);
- if (ret)
+ if (ret || *len == 0)
return ret;
/* If can't alter the file contents, we're done. */
@@ -429,7 +426,7 @@ static bool allow_file_dedupe(struct file *file)
return true;
if (file->f_mode & FMODE_WRITE)
return true;
- if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)))
+ if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), current_fsuid()))
return true;
if (!inode_permission(mnt_userns, inode, MAY_WRITE))
return true;
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 9456a2032224..f5fdaf3b1572 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -156,7 +156,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
ssize_t ret;
init_sync_kiocb(&kiocb, file);
- iov_iter_init(&iter, READ, &iov, 1, size);
+ iov_iter_init(&iter, ITER_DEST, &iov, 1, size);
kiocb.ki_pos = *ppos;
ret = seq_read_iter(&kiocb, &iter);
diff --git a/fs/splice.c b/fs/splice.c
index 0878b852b355..5969b7a1d353 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -303,7 +303,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
struct kiocb kiocb;
int ret;
- iov_iter_pipe(&to, READ, pipe, len);
+ iov_iter_pipe(&to, ITER_DEST, pipe, len);
init_sync_kiocb(&kiocb, in);
kiocb.ki_pos = *ppos;
ret = call_read_iter(in, &kiocb, &to);
@@ -682,7 +682,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
n++;
}
- iov_iter_bvec(&from, WRITE, array, n, sd.total_len - left);
+ iov_iter_bvec(&from, ITER_SOURCE, array, n, sd.total_len - left);
ret = vfs_iter_write(out, &from, &sd.pos, 0);
if (ret <= 0)
break;
@@ -1263,9 +1263,9 @@ static int vmsplice_type(struct fd f, int *type)
if (!f.file)
return -EBADF;
if (f.file->f_mode & FMODE_WRITE) {
- *type = WRITE;
+ *type = ITER_SOURCE;
} else if (f.file->f_mode & FMODE_READ) {
- *type = READ;
+ *type = ITER_DEST;
} else {
fdput(f);
return -EBADF;
@@ -1314,7 +1314,7 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
if (!iov_iter_count(&iter))
error = 0;
- else if (iov_iter_rw(&iter) == WRITE)
+ else if (type == ITER_SOURCE)
error = vmsplice_to_pipe(f.file, &iter, flags);
else
error = vmsplice_to_user(f.file, &iter, flags);
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index 916e78fabcaa..60fc98bdf421 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -54,9 +54,35 @@ config SQUASHFS_FILE_DIRECT
endchoice
+config SQUASHFS_DECOMP_SINGLE
+ depends on SQUASHFS
+ def_bool n
+
+config SQUASHFS_DECOMP_MULTI
+ depends on SQUASHFS
+ def_bool n
+
+config SQUASHFS_DECOMP_MULTI_PERCPU
+ depends on SQUASHFS
+ def_bool n
+
+config SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+ bool "Select the parallel decompression mode during mount"
+ depends on SQUASHFS
+ default n
+ select SQUASHFS_DECOMP_SINGLE
+ select SQUASHFS_DECOMP_MULTI
+ select SQUASHFS_DECOMP_MULTI_PERCPU
+ select SQUASHFS_MOUNT_DECOMP_THREADS
+ help
+ Compile all parallel decompression modes and specify the
+ decompression mode by setting "threads=" during mount.
+ default Decompressor parallelisation is SQUASHFS_DECOMP_SINGLE
+
choice
- prompt "Decompressor parallelisation options"
+ prompt "Select decompression parallel mode at compile time"
depends on SQUASHFS
+ depends on !SQUASHFS_CHOICE_DECOMP_BY_MOUNT
help
Squashfs now supports three parallelisation options for
decompression. Each one exhibits various trade-offs between
@@ -64,15 +90,17 @@ choice
If in doubt, select "Single threaded compression"
-config SQUASHFS_DECOMP_SINGLE
+config SQUASHFS_COMPILE_DECOMP_SINGLE
bool "Single threaded compression"
+ select SQUASHFS_DECOMP_SINGLE
help
Traditionally Squashfs has used single-threaded decompression.
Only one block (data or metadata) can be decompressed at any
one time. This limits CPU and memory usage to a minimum.
-config SQUASHFS_DECOMP_MULTI
+config SQUASHFS_COMPILE_DECOMP_MULTI
bool "Use multiple decompressors for parallel I/O"
+ select SQUASHFS_DECOMP_MULTI
help
By default Squashfs uses a single decompressor but it gives
poor performance on parallel I/O workloads when using multiple CPU
@@ -85,8 +113,9 @@ config SQUASHFS_DECOMP_MULTI
decompressors per core. It dynamically allocates decompressors
on a demand basis.
-config SQUASHFS_DECOMP_MULTI_PERCPU
+config SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU
bool "Use percpu multiple decompressors for parallel I/O"
+ select SQUASHFS_DECOMP_MULTI_PERCPU
help
By default Squashfs uses a single decompressor but it gives
poor performance on parallel I/O workloads when using multiple CPU
@@ -95,9 +124,21 @@ config SQUASHFS_DECOMP_MULTI_PERCPU
This decompressor implementation uses a maximum of one
decompressor per core. It uses percpu variables to ensure
decompression is load-balanced across the cores.
-
endchoice
+config SQUASHFS_MOUNT_DECOMP_THREADS
+ bool "Add the mount parameter 'threads=' for squashfs"
+ depends on SQUASHFS
+ depends on SQUASHFS_DECOMP_MULTI
+ default n
+ help
+ Use threads= to set the decompression parallel mode and the number of threads.
+ If SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y
+ threads=<single|multi|percpu|1|2|3|...>
+ else
+ threads=<2|3|...>
+ The upper limit is num_online_cpus() * 2.
+
config SQUASHFS_XATTR
bool "Squashfs XATTR support"
depends on SQUASHFS
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 833aca92301f..bed3bb8b27fa 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -216,7 +216,7 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length,
res = -EIO;
goto out_free_bio;
}
- res = squashfs_decompress(msblk, bio, offset, length, output);
+ res = msblk->thread_ops->decompress(msblk, bio, offset, length, output);
} else {
res = copy_bio_to_actor(bio, output, offset, length);
}
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
index d57bef91ab08..8893cb9b4198 100644
--- a/fs/squashfs/decompressor.c
+++ b/fs/squashfs/decompressor.c
@@ -134,7 +134,7 @@ void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags)
if (IS_ERR(comp_opts))
return comp_opts;
- stream = squashfs_decompressor_create(msblk, comp_opts);
+ stream = msblk->thread_ops->create(msblk, comp_opts);
if (IS_ERR(stream))
kfree(comp_opts);
diff --git a/fs/squashfs/decompressor_multi.c b/fs/squashfs/decompressor_multi.c
index db9f12a3ea05..416c53eedbd1 100644
--- a/fs/squashfs/decompressor_multi.c
+++ b/fs/squashfs/decompressor_multi.c
@@ -29,12 +29,11 @@
#define MAX_DECOMPRESSOR (num_online_cpus() * 2)
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
{
return MAX_DECOMPRESSOR;
}
-
struct squashfs_stream {
void *comp_opts;
struct list_head strm_list;
@@ -59,7 +58,7 @@ static void put_decomp_stream(struct decomp_stream *decomp_strm,
wake_up(&stream->wait);
}
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
void *comp_opts)
{
struct squashfs_stream *stream;
@@ -103,7 +102,7 @@ out:
}
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
{
struct squashfs_stream *stream = msblk->stream;
if (stream) {
@@ -145,7 +144,7 @@ static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk,
* If there is no available decomp and already full,
* let's wait for releasing decomp from other users.
*/
- if (stream->avail_decomp >= MAX_DECOMPRESSOR)
+ if (stream->avail_decomp >= msblk->max_thread_num)
goto wait;
/* Let's allocate new decomp */
@@ -161,7 +160,7 @@ static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk,
}
stream->avail_decomp++;
- WARN_ON(stream->avail_decomp > MAX_DECOMPRESSOR);
+ WARN_ON(stream->avail_decomp > msblk->max_thread_num);
mutex_unlock(&stream->mutex);
break;
@@ -180,7 +179,7 @@ wait:
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
int offset, int length,
struct squashfs_page_actor *output)
{
@@ -195,3 +194,10 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
msblk->decompressor->name);
return res;
}
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi = {
+ .create = squashfs_decompressor_create,
+ .destroy = squashfs_decompressor_destroy,
+ .decompress = squashfs_decompress,
+ .max_decompressors = squashfs_max_decompressors,
+};
diff --git a/fs/squashfs/decompressor_multi_percpu.c b/fs/squashfs/decompressor_multi_percpu.c
index b881b9283b7f..1dfadf76ed9a 100644
--- a/fs/squashfs/decompressor_multi_percpu.c
+++ b/fs/squashfs/decompressor_multi_percpu.c
@@ -25,7 +25,7 @@ struct squashfs_stream {
local_lock_t lock;
};
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
void *comp_opts)
{
struct squashfs_stream *stream;
@@ -59,7 +59,7 @@ out:
return ERR_PTR(err);
}
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
{
struct squashfs_stream __percpu *percpu =
(struct squashfs_stream __percpu *) msblk->stream;
@@ -75,19 +75,21 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
int offset, int length, struct squashfs_page_actor *output)
{
struct squashfs_stream *stream;
+ struct squashfs_stream __percpu *percpu =
+ (struct squashfs_stream __percpu *) msblk->stream;
int res;
- local_lock(&msblk->stream->lock);
- stream = this_cpu_ptr(msblk->stream);
+ local_lock(&percpu->lock);
+ stream = this_cpu_ptr(percpu);
res = msblk->decompressor->decompress(msblk, stream->stream, bio,
offset, length, output);
- local_unlock(&msblk->stream->lock);
+ local_unlock(&percpu->lock);
if (res < 0)
ERROR("%s decompression failed, data probably corrupt\n",
@@ -96,7 +98,14 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
return res;
}
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
{
return num_possible_cpus();
}
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu = {
+ .create = squashfs_decompressor_create,
+ .destroy = squashfs_decompressor_destroy,
+ .decompress = squashfs_decompress,
+ .max_decompressors = squashfs_max_decompressors,
+};
diff --git a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c
index 4eb3d083d45e..6f161887710b 100644
--- a/fs/squashfs/decompressor_single.c
+++ b/fs/squashfs/decompressor_single.c
@@ -24,7 +24,7 @@ struct squashfs_stream {
struct mutex mutex;
};
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
void *comp_opts)
{
struct squashfs_stream *stream;
@@ -49,7 +49,7 @@ out:
return ERR_PTR(err);
}
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
{
struct squashfs_stream *stream = msblk->stream;
@@ -59,7 +59,7 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
int offset, int length,
struct squashfs_page_actor *output)
{
@@ -78,7 +78,14 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
return res;
}
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
{
return 1;
}
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_single = {
+ .create = squashfs_decompressor_create,
+ .destroy = squashfs_decompressor_destroy,
+ .decompress = squashfs_decompress,
+ .max_decompressors = squashfs_max_decompressors,
+};
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 9783e01c8100..a6164fdf9435 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -38,11 +38,24 @@ extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
extern void *squashfs_decompressor_setup(struct super_block *, unsigned short);
/* decompressor_xxx.c */
-extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
-extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
-extern int squashfs_decompress(struct squashfs_sb_info *, struct bio *,
- int, int, struct squashfs_page_actor *);
-extern int squashfs_max_decompressors(void);
+
+struct squashfs_decompressor_thread_ops {
+ void * (*create)(struct squashfs_sb_info *msblk, void *comp_opts);
+ void (*destroy)(struct squashfs_sb_info *msblk);
+ int (*decompress)(struct squashfs_sb_info *msblk, struct bio *bio,
+ int offset, int length, struct squashfs_page_actor *output);
+ int (*max_decompressors)(void);
+};
+
+#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_single;
+#endif
+#ifdef CONFIG_SQUASHFS_DECOMP_MULTI
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi;
+#endif
+#ifdef CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu;
+#endif
/* export.c */
extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
index 1e90c2575f9b..659082e9e51d 100644
--- a/fs/squashfs/squashfs_fs_sb.h
+++ b/fs/squashfs/squashfs_fs_sb.h
@@ -53,7 +53,7 @@ struct squashfs_sb_info {
__le64 *xattr_id_table;
struct mutex meta_index_mutex;
struct meta_index *meta_index;
- struct squashfs_stream *stream;
+ void *stream;
__le64 *inode_lookup_table;
u64 inode_table;
u64 directory_table;
@@ -66,5 +66,7 @@ struct squashfs_sb_info {
int xattr_ids;
unsigned int ids;
bool panic_on_errors;
+ const struct squashfs_decompressor_thread_ops *thread_ops;
+ int max_thread_num;
};
#endif
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 32565dafa7f3..e090fae48e68 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -47,10 +47,13 @@ enum Opt_errors {
enum squashfs_param {
Opt_errors,
+ Opt_threads,
};
struct squashfs_mount_opts {
enum Opt_errors errors;
+ const struct squashfs_decompressor_thread_ops *thread_ops;
+ int thread_num;
};
static const struct constant_table squashfs_param_errors[] = {
@@ -61,9 +64,66 @@ static const struct constant_table squashfs_param_errors[] = {
static const struct fs_parameter_spec squashfs_fs_parameters[] = {
fsparam_enum("errors", Opt_errors, squashfs_param_errors),
+ fsparam_string("threads", Opt_threads),
{}
};
+
+static int squashfs_parse_param_threads_str(const char *str, struct squashfs_mount_opts *opts)
+{
+#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+ if (strcmp(str, "single") == 0) {
+ opts->thread_ops = &squashfs_decompressor_single;
+ return 0;
+ }
+ if (strcmp(str, "multi") == 0) {
+ opts->thread_ops = &squashfs_decompressor_multi;
+ return 0;
+ }
+ if (strcmp(str, "percpu") == 0) {
+ opts->thread_ops = &squashfs_decompressor_percpu;
+ return 0;
+ }
+#endif
+ return -EINVAL;
+}
+
+static int squashfs_parse_param_threads_num(const char *str, struct squashfs_mount_opts *opts)
+{
+#ifdef CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS
+ int ret;
+ unsigned long num;
+
+ ret = kstrtoul(str, 0, &num);
+ if (ret != 0)
+ return -EINVAL;
+ if (num > 1) {
+ opts->thread_ops = &squashfs_decompressor_multi;
+ if (num > opts->thread_ops->max_decompressors())
+ return -EINVAL;
+ opts->thread_num = (int)num;
+ return 0;
+ }
+#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE
+ if (num == 1) {
+ opts->thread_ops = &squashfs_decompressor_single;
+ opts->thread_num = 1;
+ return 0;
+ }
+#endif
+#endif /* !CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS */
+ return -EINVAL;
+}
+
+static int squashfs_parse_param_threads(const char *str, struct squashfs_mount_opts *opts)
+{
+ int ret = squashfs_parse_param_threads_str(str, opts);
+
+ if (ret == 0)
+ return ret;
+ return squashfs_parse_param_threads_num(str, opts);
+}
+
static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct squashfs_mount_opts *opts = fc->fs_private;
@@ -78,6 +138,10 @@ static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *para
case Opt_errors:
opts->errors = result.uint_32;
break;
+ case Opt_threads:
+ if (squashfs_parse_param_threads(param->string, opts) != 0)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -133,6 +197,7 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
return -ENOMEM;
}
msblk = sb->s_fs_info;
+ msblk->thread_ops = opts->thread_ops;
msblk->panic_on_errors = (opts->errors == Opt_errors_panic);
@@ -168,6 +233,12 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
goto failed_mount;
}
+ if (opts->thread_num == 0) {
+ msblk->max_thread_num = msblk->thread_ops->max_decompressors();
+ } else {
+ msblk->max_thread_num = opts->thread_num;
+ }
+
/* Check the MAJOR & MINOR versions and lookup compression type */
msblk->decompressor = supported_squashfs_filesystem(
fc,
@@ -252,7 +323,7 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
/* Allocate read_page block */
msblk->read_page = squashfs_cache_init("data",
- squashfs_max_decompressors(), msblk->block_size);
+ msblk->max_thread_num, msblk->block_size);
if (msblk->read_page == NULL) {
errorf(fc, "Failed to allocate read_page block");
goto failed_mount;
@@ -383,7 +454,7 @@ failed_mount:
squashfs_cache_delete(msblk->block_cache);
squashfs_cache_delete(msblk->fragment_cache);
squashfs_cache_delete(msblk->read_page);
- squashfs_decompressor_destroy(msblk);
+ msblk->thread_ops->destroy(msblk);
kfree(msblk->inode_lookup_table);
kfree(msblk->fragment_index);
kfree(msblk->id_table);
@@ -435,6 +506,19 @@ static int squashfs_show_options(struct seq_file *s, struct dentry *root)
else
seq_puts(s, ",errors=continue");
+#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+ if (msblk->thread_ops == &squashfs_decompressor_single) {
+ seq_puts(s, ",threads=single");
+ return 0;
+ }
+ if (msblk->thread_ops == &squashfs_decompressor_percpu) {
+ seq_puts(s, ",threads=percpu");
+ return 0;
+ }
+#endif
+#ifdef CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS
+ seq_printf(s, ",threads=%d", msblk->max_thread_num);
+#endif
return 0;
}
@@ -446,6 +530,16 @@ static int squashfs_init_fs_context(struct fs_context *fc)
if (!opts)
return -ENOMEM;
+#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE
+ opts->thread_ops = &squashfs_decompressor_single;
+#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI)
+ opts->thread_ops = &squashfs_decompressor_multi;
+#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU)
+ opts->thread_ops = &squashfs_decompressor_percpu;
+#else
+#error "fail: unknown squashfs decompression thread mode?"
+#endif
+ opts->thread_num = 0;
fc->fs_private = opts;
fc->ops = &squashfs_context_ops;
return 0;
@@ -478,7 +572,7 @@ static void squashfs_put_super(struct super_block *sb)
squashfs_cache_delete(sbi->block_cache);
squashfs_cache_delete(sbi->fragment_cache);
squashfs_cache_delete(sbi->read_page);
- squashfs_decompressor_destroy(sbi);
+ sbi->thread_ops->destroy(sbi);
kfree(sbi->id_table);
kfree(sbi->fragment_index);
kfree(sbi->meta_index);
@@ -568,7 +662,7 @@ static struct file_system_type squashfs_fs_type = {
.init_fs_context = squashfs_init_fs_context,
.parameters = squashfs_fs_parameters,
.kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV
+ .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
};
MODULE_ALIAS_FS("squashfs");
diff --git a/fs/stat.c b/fs/stat.c
index ef50573c72a2..d6cc74ca8486 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -44,12 +44,15 @@
void generic_fillattr(struct user_namespace *mnt_userns, struct inode *inode,
struct kstat *stat)
{
+ vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+
stat->dev = inode->i_sb->s_dev;
stat->ino = inode->i_ino;
stat->mode = inode->i_mode;
stat->nlink = inode->i_nlink;
- stat->uid = i_uid_into_mnt(mnt_userns, inode);
- stat->gid = i_gid_into_mnt(mnt_userns, inode);
+ stat->uid = vfsuid_into_kuid(vfsuid);
+ stat->gid = vfsgid_into_kgid(vfsgid);
stat->rdev = inode->i_rdev;
stat->size = i_size_read(inode);
stat->atime = inode->i_atime;
diff --git a/fs/super.c b/fs/super.c
index 8d39e4f11cfa..12c08cb20405 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1112,55 +1112,14 @@ static int test_single_super(struct super_block *s, struct fs_context *fc)
return 1;
}
-/**
- * vfs_get_super - Get a superblock with a search key set in s_fs_info.
- * @fc: The filesystem context holding the parameters
- * @keying: How to distinguish superblocks
- * @fill_super: Helper to initialise a new superblock
- *
- * Search for a superblock and create a new one if not found. The search
- * criterion is controlled by @keying. If the search fails, a new superblock
- * is created and @fill_super() is called to initialise it.
- *
- * @keying can take one of a number of values:
- *
- * (1) vfs_get_single_super - Only one superblock of this type may exist on the
- * system. This is typically used for special system filesystems.
- *
- * (2) vfs_get_keyed_super - Multiple superblocks may exist, but they must have
- * distinct keys (where the key is in s_fs_info). Searching for the same
- * key again will turn up the superblock for that key.
- *
- * (3) vfs_get_independent_super - Multiple superblocks may exist and are
- * unkeyed. Each call will get a new superblock.
- *
- * A permissions check is made by sget_fc() unless we're getting a superblock
- * for a kernel-internal mount or a submount.
- */
-int vfs_get_super(struct fs_context *fc,
- enum vfs_get_super_keying keying,
- int (*fill_super)(struct super_block *sb,
- struct fs_context *fc))
+static int vfs_get_super(struct fs_context *fc, bool reconf,
+ int (*test)(struct super_block *, struct fs_context *),
+ int (*fill_super)(struct super_block *sb,
+ struct fs_context *fc))
{
- int (*test)(struct super_block *, struct fs_context *);
struct super_block *sb;
int err;
- switch (keying) {
- case vfs_get_single_super:
- case vfs_get_single_reconf_super:
- test = test_single_super;
- break;
- case vfs_get_keyed_super:
- test = test_keyed_super;
- break;
- case vfs_get_independent_super:
- test = NULL;
- break;
- default:
- BUG();
- }
-
sb = sget_fc(fc, test, set_anon_super_fc);
if (IS_ERR(sb))
return PTR_ERR(sb);
@@ -1174,7 +1133,7 @@ int vfs_get_super(struct fs_context *fc,
fc->root = dget(sb->s_root);
} else {
fc->root = dget(sb->s_root);
- if (keying == vfs_get_single_reconf_super) {
+ if (reconf) {
err = reconfigure_super(fc);
if (err < 0) {
dput(fc->root);
@@ -1190,13 +1149,12 @@ error:
deactivate_locked_super(sb);
return err;
}
-EXPORT_SYMBOL(vfs_get_super);
int get_tree_nodev(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
- return vfs_get_super(fc, vfs_get_independent_super, fill_super);
+ return vfs_get_super(fc, false, NULL, fill_super);
}
EXPORT_SYMBOL(get_tree_nodev);
@@ -1204,7 +1162,7 @@ int get_tree_single(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
- return vfs_get_super(fc, vfs_get_single_super, fill_super);
+ return vfs_get_super(fc, false, test_single_super, fill_super);
}
EXPORT_SYMBOL(get_tree_single);
@@ -1212,7 +1170,7 @@ int get_tree_single_reconf(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
- return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super);
+ return vfs_get_super(fc, true, test_single_super, fill_super);
}
EXPORT_SYMBOL(get_tree_single_reconf);
@@ -1222,7 +1180,7 @@ int get_tree_keyed(struct fs_context *fc,
void *key)
{
fc->s_fs_info = key;
- return vfs_get_super(fc, vfs_get_keyed_super, fill_super);
+ return vfs_get_super(fc, false, test_keyed_super, fill_super);
}
EXPORT_SYMBOL(get_tree_keyed);
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
index d4ec9bb97de9..3b8567564e7e 100644
--- a/fs/sysv/itree.c
+++ b/fs/sysv/itree.c
@@ -438,7 +438,7 @@ static unsigned sysv_nblocks(struct super_block *s, loff_t size)
res += blocks;
direct = 1;
}
- return blocks;
+ return res;
}
int sysv_getattr(struct user_namespace *mnt_userns, const struct path *path,
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 3f128b9fdfbb..9c9d3f0e36a4 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -2467,7 +2467,7 @@ error_dump:
static inline int chance(unsigned int n, unsigned int out_of)
{
- return !!(prandom_u32_max(out_of) + 1 <= n);
+ return !!(get_random_u32_below(out_of) + 1 <= n);
}
@@ -2485,13 +2485,13 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
if (chance(1, 2)) {
d->pc_delay = 1;
/* Fail within 1 minute */
- delay = prandom_u32_max(60000);
+ delay = get_random_u32_below(60000);
d->pc_timeout = jiffies;
d->pc_timeout += msecs_to_jiffies(delay);
ubifs_warn(c, "failing after %lums", delay);
} else {
d->pc_delay = 2;
- delay = prandom_u32_max(10000);
+ delay = get_random_u32_below(10000);
/* Fail within 10000 operations */
d->pc_cnt_max = delay;
ubifs_warn(c, "failing after %lu calls", delay);
@@ -2571,7 +2571,7 @@ static int corrupt_data(const struct ubifs_info *c, const void *buf,
unsigned int from, to, ffs = chance(1, 2);
unsigned char *p = (void *)buf;
- from = prandom_u32_max(len);
+ from = get_random_u32_below(len);
/* Corruption span max to end of write unit */
to = min(len, ALIGN(from + 1, c->max_write_size));
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index cfbc31f709f4..c4d079328b92 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -1970,28 +1970,28 @@ static int dbg_populate_lsave(struct ubifs_info *c)
if (!dbg_is_chk_gen(c))
return 0;
- if (prandom_u32_max(4))
+ if (get_random_u32_below(4))
return 0;
for (i = 0; i < c->lsave_cnt; i++)
c->lsave[i] = c->main_first;
list_for_each_entry(lprops, &c->empty_list, list)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = lprops->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = lprops->lnum;
list_for_each_entry(lprops, &c->freeable_list, list)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = lprops->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = lprops->lnum;
list_for_each_entry(lprops, &c->frdi_idx_list, list)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = lprops->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = lprops->lnum;
heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = heap->arr[i]->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum;
heap = &c->lpt_heap[LPROPS_DIRTY - 1];
for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = heap->arr[i]->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum;
heap = &c->lpt_heap[LPROPS_FREE - 1];
for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32_max(c->lsave_cnt)] = heap->arr[i]->lnum;
+ c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum;
return 1;
}
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
index 01362ad5f804..a55e04822d16 100644
--- a/fs/ubifs/tnc_commit.c
+++ b/fs/ubifs/tnc_commit.c
@@ -700,7 +700,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
c->ilebs[c->ileb_cnt++] = lnum;
dbg_cmt("LEB %d", lnum);
}
- if (dbg_is_chk_index(c) && !prandom_u32_max(8))
+ if (dbg_is_chk_index(c) && !get_random_u32_below(8))
return -ENOSPC;
return 0;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index dce6ae9ae306..1d7c2a812fc1 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -182,11 +182,6 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
}
}
-static int udf_writepage(struct page *page, struct writeback_control *wbc)
-{
- return block_write_full_page(page, udf_get_block, wbc);
-}
-
static int udf_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
@@ -239,12 +234,12 @@ const struct address_space_operations udf_aops = {
.invalidate_folio = block_invalidate_folio,
.read_folio = udf_read_folio,
.readahead = udf_readahead,
- .writepage = udf_writepage,
.writepages = udf_writepages,
.write_begin = udf_write_begin,
.write_end = generic_write_end,
.direct_IO = udf_direct_IO,
.bmap = udf_bmap,
+ .migrate_folio = buffer_migrate_folio,
};
/*
@@ -439,6 +434,12 @@ static int udf_get_block(struct inode *inode, sector_t block,
iinfo->i_next_alloc_goal++;
}
+ /*
+ * Block beyond EOF and prealloc extents? Just discard preallocation
+ * as it is not useful and complicates things.
+ */
+ if (((loff_t)block) << inode->i_blkbits > iinfo->i_lenExtents)
+ udf_discard_prealloc(inode);
udf_clear_extent_cache(inode);
phys = inode_getblk(inode, block, &err, &new);
if (!phys)
@@ -488,8 +489,6 @@ static int udf_do_extend_file(struct inode *inode,
uint32_t add;
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
struct super_block *sb = inode->i_sb;
- struct kernel_lb_addr prealloc_loc = {};
- uint32_t prealloc_len = 0;
struct udf_inode_info *iinfo;
int err;
@@ -510,19 +509,6 @@ static int udf_do_extend_file(struct inode *inode,
~(sb->s_blocksize - 1);
}
- /* Last extent are just preallocated blocks? */
- if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
- EXT_NOT_RECORDED_ALLOCATED) {
- /* Save the extent so that we can reattach it to the end */
- prealloc_loc = last_ext->extLocation;
- prealloc_len = last_ext->extLength;
- /* Mark the extent as a hole */
- last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
- last_ext->extLocation.logicalBlockNum = 0;
- last_ext->extLocation.partitionReferenceNum = 0;
- }
-
/* Can we merge with the previous extent? */
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
EXT_NOT_RECORDED_NOT_ALLOCATED) {
@@ -550,7 +536,7 @@ static int udf_do_extend_file(struct inode *inode,
* more extents, we may need to enter possible following
* empty indirect extent.
*/
- if (new_block_bytes || prealloc_len)
+ if (new_block_bytes)
udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0);
}
@@ -584,17 +570,6 @@ static int udf_do_extend_file(struct inode *inode,
}
out:
- /* Do we have some preallocated blocks saved? */
- if (prealloc_len) {
- err = udf_add_aext(inode, last_pos, &prealloc_loc,
- prealloc_len, 1);
- if (err)
- return err;
- last_ext->extLocation = prealloc_loc;
- last_ext->extLength = prealloc_len;
- count++;
- }
-
/* last_pos should point to the last written extent... */
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
last_pos->offset -= sizeof(struct short_ad);
@@ -610,13 +585,17 @@ out:
static void udf_do_extend_final_block(struct inode *inode,
struct extent_position *last_pos,
struct kernel_long_ad *last_ext,
- uint32_t final_block_len)
+ uint32_t new_elen)
{
- struct super_block *sb = inode->i_sb;
uint32_t added_bytes;
- added_bytes = final_block_len -
- (last_ext->extLength & (sb->s_blocksize - 1));
+ /*
+ * Extent already large enough? It may be already rounded up to block
+ * size...
+ */
+ if (new_elen <= (last_ext->extLength & UDF_EXTENT_LENGTH_MASK))
+ return;
+ added_bytes = (last_ext->extLength & UDF_EXTENT_LENGTH_MASK) - new_elen;
last_ext->extLength += added_bytes;
UDF_I(inode)->i_lenExtents += added_bytes;
@@ -633,12 +612,12 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
int8_t etype;
struct super_block *sb = inode->i_sb;
sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
- unsigned long partial_final_block;
+ loff_t new_elen;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
struct kernel_long_ad extent;
int err = 0;
- int within_final_block;
+ bool within_last_ext;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
@@ -647,8 +626,17 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
else
BUG();
+ /*
+ * When creating hole in file, just don't bother with preserving
+ * preallocation. It likely won't be very useful anyway.
+ */
+ udf_discard_prealloc(inode);
+
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
- within_final_block = (etype != -1);
+ within_last_ext = (etype != -1);
+ /* We don't expect extents past EOF... */
+ WARN_ON_ONCE(within_last_ext &&
+ elen > ((loff_t)offset + 1) << inode->i_blkbits);
if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
(epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
@@ -664,19 +652,17 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
extent.extLength |= etype << 30;
}
- partial_final_block = newsize & (sb->s_blocksize - 1);
+ new_elen = ((loff_t)offset << inode->i_blkbits) |
+ (newsize & (sb->s_blocksize - 1));
/* File has extent covering the new size (could happen when extending
* inside a block)?
*/
- if (within_final_block) {
+ if (within_last_ext) {
/* Extending file within the last file block */
- udf_do_extend_final_block(inode, &epos, &extent,
- partial_final_block);
+ udf_do_extend_final_block(inode, &epos, &extent, new_elen);
} else {
- loff_t add = ((loff_t)offset << sb->s_blocksize_bits) |
- partial_final_block;
- err = udf_do_extend_file(inode, &epos, &extent, add);
+ err = udf_do_extend_file(inode, &epos, &extent, new_elen);
}
if (err < 0)
@@ -777,10 +763,11 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
goto out_free;
}
- /* Are we beyond EOF? */
+ /* Are we beyond EOF and preallocated extent? */
if (etype == -1) {
int ret;
loff_t hole_len;
+
isBeyondEOF = true;
if (count) {
if (c)
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index fb4c30e05245..7c95c549dd64 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -240,7 +240,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
poffset - lfi);
else {
if (!copy_name) {
- copy_name = kmalloc(UDF_NAME_LEN,
+ copy_name = kmalloc(UDF_NAME_LEN_CS0,
GFP_NOFS);
if (!copy_name) {
fi = ERR_PTR(-ENOMEM);
@@ -1091,8 +1091,9 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
return -EINVAL;
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
- if (IS_ERR(ofi)) {
- retval = PTR_ERR(ofi);
+ if (!ofi || IS_ERR(ofi)) {
+ if (IS_ERR(ofi))
+ retval = PTR_ERR(ofi);
goto end_rename;
}
@@ -1101,8 +1102,7 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
brelse(ofibh.sbh);
tloc = lelb_to_cpu(ocfi.icb.extLocation);
- if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0)
- != old_inode->i_ino)
+ if (udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino)
goto end_rename;
nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi);
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 4042d9739fb7..06eda8177b5f 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -162,7 +162,7 @@ static void udf_free_in_core_inode(struct inode *inode)
static void init_once(void *foo)
{
- struct udf_inode_info *ei = (struct udf_inode_info *)foo;
+ struct udf_inode_info *ei = foo;
ei->i_data = NULL;
inode_init_once(&ei->vfs_inode);
@@ -820,7 +820,7 @@ static int udf_find_fileset(struct super_block *sb,
struct kernel_lb_addr *fileset,
struct kernel_lb_addr *root)
{
- struct buffer_head *bh = NULL;
+ struct buffer_head *bh;
uint16_t ident;
int ret;
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 532cda99644e..036ebd892b85 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -120,60 +120,42 @@ void udf_truncate_tail_extent(struct inode *inode)
void udf_discard_prealloc(struct inode *inode)
{
- struct extent_position epos = { NULL, 0, {0, 0} };
+ struct extent_position epos = {};
+ struct extent_position prev_epos = {};
struct kernel_lb_addr eloc;
uint32_t elen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
- int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
+ int bsize = 1 << inode->i_blkbits;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
- inode->i_size == iinfo->i_lenExtents)
+ ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize))
return;
- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(struct short_ad);
- else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(struct long_ad);
- else
- adsize = 0;
-
epos.block = iinfo->i_location;
/* Find the last extent in the file */
- while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
- etype = netype;
+ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
+ brelse(prev_epos.bh);
+ prev_epos = epos;
+ if (prev_epos.bh)
+ get_bh(prev_epos.bh);
+
+ etype = udf_next_aext(inode, &epos, &eloc, &elen, 1);
lbcount += elen;
}
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
- epos.offset -= adsize;
lbcount -= elen;
- extent_trunc(inode, &epos, &eloc, etype, elen, 0);
- if (!epos.bh) {
- iinfo->i_lenAlloc =
- epos.offset -
- udf_file_entry_alloc_offset(inode);
- mark_inode_dirty(inode);
- } else {
- struct allocExtDesc *aed =
- (struct allocExtDesc *)(epos.bh->b_data);
- aed->lengthAllocDescs =
- cpu_to_le32(epos.offset -
- sizeof(struct allocExtDesc));
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
- UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
- udf_update_tag(epos.bh->b_data, epos.offset);
- else
- udf_update_tag(epos.bh->b_data,
- sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(epos.bh, inode);
- }
+ udf_delete_aext(inode, prev_epos);
+ udf_free_blocks(inode->i_sb, inode, &eloc, 0,
+ DIV_ROUND_UP(elen, 1 << inode->i_blkbits));
}
/* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */
iinfo->i_lenExtents = lbcount;
brelse(epos.bh);
+ brelse(prev_epos.bh);
}
static void udf_update_alloc_ext_desc(struct inode *inode,
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 4fa620543d30..291b56dd011e 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -6,7 +6,11 @@
#include <linux/bitops.h>
#include <linux/magic.h>
-#define UDF_MAX_READ_VERSION 0x0250
+/*
+ * Even UDF 2.6 media should have version <= 0x250 but apparently there are
+ * some broken filesystems with version set to 0x260. Accommodate those.
+ */
+#define UDF_MAX_READ_VERSION 0x0260
#define UDF_MAX_WRITE_VERSION 0x0201
#define UDF_FLAG_USE_EXTENDED_FE 0
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 07c81ab3fd4d..98ac37e34e3d 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1630,17 +1630,20 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
NULL_VM_UFFD_CTX, anon_vma_name(vma));
if (prev) {
vma = prev;
+ mas_pause(&mas);
goto next;
}
if (vma->vm_start < start) {
ret = split_vma(mm, vma, start, 1);
if (ret)
break;
+ mas_pause(&mas);
}
if (vma->vm_end > end) {
ret = split_vma(mm, vma, end, 0);
if (ret)
break;
+ mas_pause(&mas);
}
next:
/*
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index dbe1ce5b450a..c7fcb855e068 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -32,6 +32,11 @@ struct fsverity_hash_alg {
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
mempool_t req_pool; /* mempool with a preallocated hash request */
+ /*
+ * The HASH_ALGO_* constant for this algorithm. This is different from
+ * FS_VERITY_HASH_ALG_*, which uses a different numbering scheme.
+ */
+ enum hash_algo algo_id;
};
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
diff --git a/fs/verity/hash_algs.c b/fs/verity/hash_algs.c
index 71d0fccb6d4c..6f8170cf4ae7 100644
--- a/fs/verity/hash_algs.c
+++ b/fs/verity/hash_algs.c
@@ -16,11 +16,13 @@ struct fsverity_hash_alg fsverity_hash_algs[] = {
.name = "sha256",
.digest_size = SHA256_DIGEST_SIZE,
.block_size = SHA256_BLOCK_SIZE,
+ .algo_id = HASH_ALGO_SHA256,
},
[FS_VERITY_HASH_ALG_SHA512] = {
.name = "sha512",
.digest_size = SHA512_DIGEST_SIZE,
.block_size = SHA512_BLOCK_SIZE,
+ .algo_id = HASH_ALGO_SHA512,
},
};
@@ -324,5 +326,9 @@ void __init fsverity_check_hash_algs(void)
*/
BUG_ON(!is_power_of_2(alg->digest_size));
BUG_ON(!is_power_of_2(alg->block_size));
+
+ /* Verify that there is a valid mapping to HASH_ALGO_*. */
+ BUG_ON(alg->algo_id == 0);
+ BUG_ON(alg->digest_size != hash_digest_size[alg->algo_id]);
}
}
diff --git a/fs/verity/measure.c b/fs/verity/measure.c
index e99c00350c28..5c79ea1b2468 100644
--- a/fs/verity/measure.c
+++ b/fs/verity/measure.c
@@ -65,8 +65,7 @@ EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
* @alg: (out) pointer to the hash algorithm enumeration
*
* Return the file hash algorithm and digest of an fsverity protected file.
- * Assumption: before calling fsverity_get_digest(), the file must have been
- * opened.
+ * Assumption: before calling this, the file must have been opened.
*
* Return: 0 on success, -errno on failure
*/
@@ -76,27 +75,13 @@ int fsverity_get_digest(struct inode *inode,
{
const struct fsverity_info *vi;
const struct fsverity_hash_alg *hash_alg;
- int i;
vi = fsverity_get_info(inode);
if (!vi)
return -ENODATA; /* not a verity file */
hash_alg = vi->tree_params.hash_alg;
- memset(digest, 0, FS_VERITY_MAX_DIGEST_SIZE);
-
- /* convert the verity hash algorithm name to a hash_algo_name enum */
- i = match_string(hash_algo_name, HASH_ALGO__LAST, hash_alg->name);
- if (i < 0)
- return -EINVAL;
- *alg = i;
-
- if (WARN_ON_ONCE(hash_alg->digest_size != hash_digest_size[*alg]))
- return -EINVAL;
memcpy(digest, vi->file_digest, hash_alg->digest_size);
-
- pr_debug("file digest %s:%*phN\n", hash_algo_name[*alg],
- hash_digest_size[*alg], digest);
-
+ *alg = hash_alg->algo_id;
return 0;
}
diff --git a/fs/verity/verify.c b/fs/verity/verify.c
index bde8c9b7d25f..961ba248021f 100644
--- a/fs/verity/verify.c
+++ b/fs/verity/verify.c
@@ -200,9 +200,8 @@ EXPORT_SYMBOL_GPL(fsverity_verify_page);
* @bio: the bio to verify
*
* Verify a set of pages that have just been read from a verity file. The pages
- * must be pagecache pages that are still locked and not yet uptodate. Pages
- * that fail verification are set to the Error state. Verification is skipped
- * for pages already in the Error state, e.g. due to fscrypt decryption failure.
+ * must be pagecache pages that are still locked and not yet uptodate. If a
+ * page fails verification, then bio->bi_status is set to an error status.
*
* This is a helper function for use by the ->readahead() method of filesystems
* that issue bios to read data directly into the page cache. Filesystems that
@@ -244,9 +243,10 @@ void fsverity_verify_bio(struct bio *bio)
unsigned long level0_ra_pages =
min(max_ra_pages, params->level0_blocks - level0_index);
- if (!PageError(page) &&
- !verify_page(inode, vi, req, page, level0_ra_pages))
- SetPageError(page);
+ if (!verify_page(inode, vi, req, page, level0_ra_pages)) {
+ bio->bi_status = BLK_STS_IOERR;
+ break;
+ }
}
fsverity_free_hash_request(params->hash_alg, req);
diff --git a/fs/xattr.c b/fs/xattr.c
index 61107b6bbed2..adab9a70b536 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -80,6 +80,31 @@ xattr_resolve_name(struct inode *inode, const char **name)
return ERR_PTR(-EOPNOTSUPP);
}
+/**
+ * may_write_xattr - check whether inode allows writing xattr
+ * @mnt_userns: User namespace of the mount the inode was found from
+ * @inode: the inode on which to set an xattr
+ *
+ * Check whether the inode allows writing xattrs. Specifically, we can never
+ * set or remove an extended attribute on a read-only filesystem or on an
+ * immutable / append-only inode.
+ *
+ * We also need to ensure that the inode has a mapping in the mount to
+ * not risk writing back invalid i_{g,u}id values.
+ *
+ * Return: On success zero is returned. On error a negative errno is returned.
+ */
+int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode)
+{
+ if (IS_IMMUTABLE(inode))
+ return -EPERM;
+ if (IS_APPEND(inode))
+ return -EPERM;
+ if (HAS_UNMAPPED_ID(mnt_userns, inode))
+ return -EPERM;
+ return 0;
+}
+
/*
* Check permissions for extended attribute access. This is a bit complicated
* because different namespaces have very different rules.
@@ -88,20 +113,12 @@ static int
xattr_permission(struct user_namespace *mnt_userns, struct inode *inode,
const char *name, int mask)
{
- /*
- * We can never set or remove an extended attribute on a read-only
- * filesystem or on an immutable / append-only inode.
- */
if (mask & MAY_WRITE) {
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- return -EPERM;
- /*
- * Updating an xattr will likely cause i_uid and i_gid
- * to be writen back improperly if their true value is
- * unknown to the vfs.
- */
- if (HAS_UNMAPPED_ID(mnt_userns, inode))
- return -EPERM;
+ int ret;
+
+ ret = may_write_xattr(mnt_userns, inode);
+ if (ret)
+ return ret;
}
/*
@@ -172,6 +189,9 @@ __vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
{
const struct xattr_handler *handler;
+ if (is_posix_acl_xattr(name))
+ return -EOPNOTSUPP;
+
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@@ -282,12 +302,6 @@ out:
}
EXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
-static inline bool is_posix_acl_xattr(const char *name)
-{
- return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
- (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
-}
-
int
vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, const void *value, size_t size, int flags)
@@ -354,11 +368,12 @@ out_noalloc:
* vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
*
* Allocate memory, if not already allocated, or re-allocate correct size,
- * before retrieving the extended attribute.
+ * before retrieving the extended attribute. The xattr value buffer should
+ * always be freed by the caller, even on error.
*
* Returns the result of alloc, if failed, or the getxattr operation.
*/
-ssize_t
+int
vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, char **xattr_value, size_t xattr_size,
gfp_t flags)
@@ -399,6 +414,9 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
{
const struct xattr_handler *handler;
+ if (is_posix_acl_xattr(name))
+ return -EOPNOTSUPP;
+
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@@ -437,10 +455,7 @@ vfs_getxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
return ret;
}
nolsm:
- error = __vfs_getxattr(dentry, inode, name, value, size);
- if (error > 0 && is_posix_acl_xattr(name))
- posix_acl_getxattr_idmapped_mnt(mnt_userns, inode, value, size);
- return error;
+ return __vfs_getxattr(dentry, inode, name, value, size);
}
EXPORT_SYMBOL_GPL(vfs_getxattr);
@@ -471,6 +486,9 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct inode *inode = d_inode(dentry);
const struct xattr_handler *handler;
+ if (is_posix_acl_xattr(name))
+ return -EOPNOTSUPP;
+
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@@ -580,23 +598,19 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
return error;
}
-static void setxattr_convert(struct user_namespace *mnt_userns,
- struct dentry *d, struct xattr_ctx *ctx)
-{
- if (ctx->size && is_posix_acl_xattr(ctx->kname->name))
- posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
-}
-
-int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct xattr_ctx *ctx)
{
- setxattr_convert(mnt_userns, dentry, ctx);
- return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
+ if (is_posix_acl_xattr(ctx->kname->name))
+ return do_set_acl(idmap, dentry, ctx->kname->name,
+ ctx->kvalue, ctx->size);
+
+ return vfs_setxattr(mnt_idmap_owner(idmap), dentry, ctx->kname->name,
ctx->kvalue, ctx->size, ctx->flags);
}
static long
-setxattr(struct user_namespace *mnt_userns, struct dentry *d,
+setxattr(struct mnt_idmap *idmap, struct dentry *d,
const char __user *name, const void __user *value, size_t size,
int flags)
{
@@ -614,7 +628,7 @@ setxattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error)
return error;
- error = do_setxattr(mnt_userns, d, &ctx);
+ error = do_setxattr(idmap, d, &ctx);
kvfree(ctx.kvalue);
return error;
@@ -633,7 +647,7 @@ retry:
return error;
error = mnt_want_write(path.mnt);
if (!error) {
- error = setxattr(mnt_user_ns(path.mnt), path.dentry, name,
+ error = setxattr(mnt_idmap(path.mnt), path.dentry, name,
value, size, flags);
mnt_drop_write(path.mnt);
}
@@ -670,7 +684,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
audit_file(f.file);
error = mnt_want_write_file(f.file);
if (!error) {
- error = setxattr(file_mnt_user_ns(f.file),
+ error = setxattr(file_mnt_idmap(f.file),
f.file->f_path.dentry, name,
value, size, flags);
mnt_drop_write_file(f.file);
@@ -683,7 +697,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
* Extended attribute GET operations
*/
ssize_t
-do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
+do_getxattr(struct mnt_idmap *idmap, struct dentry *d,
struct xattr_ctx *ctx)
{
ssize_t error;
@@ -697,10 +711,12 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
return -ENOMEM;
}
- error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
+ if (is_posix_acl_xattr(ctx->kname->name))
+ error = do_get_acl(idmap, d, kname, ctx->kvalue, ctx->size);
+ else
+ error = vfs_getxattr(mnt_idmap_owner(idmap), d, kname,
+ ctx->kvalue, ctx->size);
if (error > 0) {
- if (is_posix_acl_xattr(kname))
- posix_acl_fix_xattr_to_user(ctx->kvalue, error);
if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
error = -EFAULT;
} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
@@ -713,7 +729,7 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
}
static ssize_t
-getxattr(struct user_namespace *mnt_userns, struct dentry *d,
+getxattr(struct mnt_idmap *idmap, struct dentry *d,
const char __user *name, void __user *value, size_t size)
{
ssize_t error;
@@ -732,7 +748,7 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0)
return error;
- error = do_getxattr(mnt_userns, d, &ctx);
+ error = do_getxattr(idmap, d, &ctx);
kvfree(ctx.kvalue);
return error;
@@ -748,7 +764,7 @@ retry:
error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
if (error)
return error;
- error = getxattr(mnt_user_ns(path.mnt), path.dentry, name, value, size);
+ error = getxattr(mnt_idmap(path.mnt), path.dentry, name, value, size);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
@@ -778,7 +794,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
if (!f.file)
return error;
audit_file(f.file);
- error = getxattr(file_mnt_user_ns(f.file), f.file->f_path.dentry,
+ error = getxattr(file_mnt_idmap(f.file), f.file->f_path.dentry,
name, value, size);
fdput(f);
return error;
@@ -863,7 +879,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
* Extended attribute REMOVE operations
*/
static long
-removexattr(struct user_namespace *mnt_userns, struct dentry *d,
+removexattr(struct mnt_idmap *idmap, struct dentry *d,
const char __user *name)
{
int error;
@@ -875,7 +891,10 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0)
return error;
- return vfs_removexattr(mnt_userns, d, kname);
+ if (is_posix_acl_xattr(kname))
+ return vfs_remove_acl(mnt_idmap_owner(idmap), d, kname);
+
+ return vfs_removexattr(mnt_idmap_owner(idmap), d, kname);
}
static int path_removexattr(const char __user *pathname,
@@ -889,7 +908,7 @@ retry:
return error;
error = mnt_want_write(path.mnt);
if (!error) {
- error = removexattr(mnt_user_ns(path.mnt), path.dentry, name);
+ error = removexattr(mnt_idmap(path.mnt), path.dentry, name);
mnt_drop_write(path.mnt);
}
path_put(&path);
@@ -922,7 +941,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
audit_file(f.file);
error = mnt_want_write_file(f.file);
if (!error) {
- error = removexattr(file_mnt_user_ns(f.file),
+ error = removexattr(file_mnt_idmap(f.file),
f.file->f_path.dentry, name);
mnt_drop_write_file(f.file);
}
@@ -992,8 +1011,29 @@ const char *xattr_full_name(const struct xattr_handler *handler,
}
EXPORT_SYMBOL(xattr_full_name);
-/*
- * Allocate new xattr and copy in the value; but leave the name to callers.
+/**
+ * free_simple_xattr - free an xattr object
+ * @xattr: the xattr object
+ *
+ * Free the xattr object. Can handle @xattr being NULL.
+ */
+static inline void free_simple_xattr(struct simple_xattr *xattr)
+{
+ if (xattr)
+ kfree(xattr->name);
+ kvfree(xattr);
+}
+
+/**
+ * simple_xattr_alloc - allocate new xattr object
+ * @value: value of the xattr object
+ * @size: size of @value
+ *
+ * Allocate a new xattr object and initialize respective members. The caller is
+ * responsible for handling the name of the xattr.
+ *
+ * Return: On success a new xattr object is returned. On failure NULL is
+ * returned.
*/
struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
{
@@ -1014,20 +1054,69 @@ struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
return new_xattr;
}
-/*
- * xattr GET operation for in-memory/pseudo filesystems
+/**
+ * rbtree_simple_xattr_cmp - compare xattr name with current rbtree xattr entry
+ * @key: xattr name
+ * @node: current node
+ *
+ * Compare the xattr name with the xattr name attached to @node in the rbtree.
+ *
+ * Return: Negative value if continuing left, positive if continuing right, 0
+ * if the xattr attached to @node matches @key.
+ */
+static int rbtree_simple_xattr_cmp(const void *key, const struct rb_node *node)
+{
+ const char *xattr_name = key;
+ const struct simple_xattr *xattr;
+
+ xattr = rb_entry(node, struct simple_xattr, rb_node);
+ return strcmp(xattr->name, xattr_name);
+}
+
+/**
+ * rbtree_simple_xattr_node_cmp - compare two xattr rbtree nodes
+ * @new_node: new node
+ * @node: current node
+ *
+ * Compare the xattr attached to @new_node with the xattr attached to @node.
+ *
+ * Return: Negative value if continuing left, positive if continuing right, 0
+ * if the xattr attached to @new_node matches the xattr attached to @node.
+ */
+static int rbtree_simple_xattr_node_cmp(struct rb_node *new_node,
+ const struct rb_node *node)
+{
+ struct simple_xattr *xattr;
+ xattr = rb_entry(new_node, struct simple_xattr, rb_node);
+ return rbtree_simple_xattr_cmp(xattr->name, node);
+}
+
+/**
+ * simple_xattr_get - get an xattr object
+ * @xattrs: the header of the xattr object
+ * @name: the name of the xattr to retrieve
+ * @buffer: the buffer to store the value into
+ * @size: the size of @buffer
+ *
+ * Try to find and retrieve the xattr object associated with @name.
+ * If @buffer is provided store the value of @xattr in @buffer
+ * otherwise just return the length. The size of @buffer is limited
+ * to XATTR_SIZE_MAX which currently is 65536.
+ *
+ * Return: On success the length of the xattr value is returned. On error a
+ * negative error code is returned.
*/
int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
void *buffer, size_t size)
{
- struct simple_xattr *xattr;
+ struct simple_xattr *xattr = NULL;
+ struct rb_node *rbp;
int ret = -ENODATA;
- spin_lock(&xattrs->lock);
- list_for_each_entry(xattr, &xattrs->head, list) {
- if (strcmp(name, xattr->name))
- continue;
-
+ read_lock(&xattrs->lock);
+ rbp = rb_find(name, &xattrs->rb_root, rbtree_simple_xattr_cmp);
+ if (rbp) {
+ xattr = rb_entry(rbp, struct simple_xattr, rb_node);
ret = xattr->size;
if (buffer) {
if (size < xattr->size)
@@ -1035,34 +1124,44 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
else
memcpy(buffer, xattr->value, xattr->size);
}
- break;
}
- spin_unlock(&xattrs->lock);
+ read_unlock(&xattrs->lock);
return ret;
}
/**
- * 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}
- * @removed_size: returns size of the removed xattr, -1 if none removed
+ * simple_xattr_set - set an xattr object
+ * @xattrs: the header of the xattr object
+ * @name: the name of the xattr to retrieve
+ * @value: the value to store along the xattr
+ * @size: the size of @value
+ * @flags: the flags determining how to set the xattr
+ * @removed_size: the size of the removed xattr
+ *
+ * Set a new xattr object.
+ * If @value is passed a new xattr object will be allocated. If XATTR_REPLACE
+ * is specified in @flags a matching xattr object for @name must already exist.
+ * If it does it will be replaced with the new xattr object. If it doesn't we
+ * fail. If XATTR_CREATE is specified and a matching xattr does already exist
+ * we fail. If it doesn't we create a new xattr. If @flags is zero we simply
+ * insert the new xattr replacing any existing one.
*
- * %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.
+ * If @value is empty and a matching xattr object is found we delete it if
+ * XATTR_REPLACE is specified in @flags or @flags is zero.
*
- * Returns 0 on success, -errno on failure.
+ * If @value is empty and no matching xattr object for @name is found we do
+ * nothing if XATTR_CREATE is specified in @flags or @flags is zero. For
+ * XATTR_REPLACE we fail as mentioned above.
+ *
+ * Return: On success zero and on error a negative error code is returned.
*/
int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
const void *value, size_t size, int flags,
ssize_t *removed_size)
{
- struct simple_xattr *xattr;
- struct simple_xattr *new_xattr = NULL;
- int err = 0;
+ struct simple_xattr *xattr = NULL, *new_xattr = NULL;
+ struct rb_node *parent = NULL, **rbp;
+ int err = 0, ret;
if (removed_size)
*removed_size = -1;
@@ -1075,42 +1174,68 @@ int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
new_xattr->name = kstrdup(name, GFP_KERNEL);
if (!new_xattr->name) {
- kvfree(new_xattr);
+ free_simple_xattr(new_xattr);
return -ENOMEM;
}
}
- spin_lock(&xattrs->lock);
- list_for_each_entry(xattr, &xattrs->head, list) {
- if (!strcmp(name, xattr->name)) {
- if (flags & XATTR_CREATE) {
- xattr = new_xattr;
- err = -EEXIST;
- } else if (new_xattr) {
- list_replace(&xattr->list, &new_xattr->list);
- if (removed_size)
- *removed_size = xattr->size;
- } else {
- list_del(&xattr->list);
- if (removed_size)
- *removed_size = xattr->size;
- }
- goto out;
- }
- }
- if (flags & XATTR_REPLACE) {
- xattr = new_xattr;
- err = -ENODATA;
- } else {
- list_add(&new_xattr->list, &xattrs->head);
- xattr = NULL;
+ write_lock(&xattrs->lock);
+ rbp = &xattrs->rb_root.rb_node;
+ while (*rbp) {
+ parent = *rbp;
+ ret = rbtree_simple_xattr_cmp(name, *rbp);
+ if (ret < 0)
+ rbp = &(*rbp)->rb_left;
+ else if (ret > 0)
+ rbp = &(*rbp)->rb_right;
+ else
+ xattr = rb_entry(*rbp, struct simple_xattr, rb_node);
+ if (xattr)
+ break;
}
-out:
- spin_unlock(&xattrs->lock);
+
if (xattr) {
- kfree(xattr->name);
- kvfree(xattr);
+ /* Fail if XATTR_CREATE is requested and the xattr exists. */
+ if (flags & XATTR_CREATE) {
+ err = -EEXIST;
+ goto out_unlock;
+ }
+
+ if (new_xattr)
+ rb_replace_node(&xattr->rb_node, &new_xattr->rb_node,
+ &xattrs->rb_root);
+ else
+ rb_erase(&xattr->rb_node, &xattrs->rb_root);
+ if (!err && removed_size)
+ *removed_size = xattr->size;
+ } else {
+ /* Fail if XATTR_REPLACE is requested but no xattr is found. */
+ if (flags & XATTR_REPLACE) {
+ err = -ENODATA;
+ goto out_unlock;
+ }
+
+ /*
+ * If XATTR_CREATE or no flags are specified together with a
+ * new value simply insert it.
+ */
+ if (new_xattr) {
+ rb_link_node(&new_xattr->rb_node, parent, rbp);
+ rb_insert_color(&new_xattr->rb_node, &xattrs->rb_root);
+ }
+
+ /*
+ * If XATTR_CREATE or no flags are specified and neither an
+ * old or new xattr exist then we don't need to do anything.
+ */
}
+
+out_unlock:
+ write_unlock(&xattrs->lock);
+ if (err)
+ free_simple_xattr(new_xattr);
+ else
+ free_simple_xattr(xattr);
return err;
}
@@ -1134,14 +1259,31 @@ static int xattr_list_one(char **buffer, ssize_t *remaining_size,
return 0;
}
-/*
- * xattr LIST operation for in-memory/pseudo filesystems
+/**
+ * simple_xattr_list - list all xattr objects
+ * @inode: inode from which to get the xattrs
+ * @xattrs: the header of the xattr object
+ * @buffer: the buffer to store all xattrs into
+ * @size: the size of @buffer
+ *
+ * List all xattrs associated with @inode. If @buffer is NULL we returned
+ * the required size of the buffer. If @buffer is provided we store the
+ * xattrs value into it provided it is big enough.
+ *
+ * Note, the number of xattr names that can be listed with listxattr(2) is
+ * limited to XATTR_LIST_MAX aka 65536 bytes. If a larger buffer is passed
+ * then vfs_listxattr() caps it to XATTR_LIST_MAX and if more xattr names
+ * are found it will return -E2BIG.
+ *
+ * Return: On success the required size or the size of the copied xattrs is
+ * returned. On error a negative error code is returned.
*/
ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
char *buffer, size_t size)
{
- bool trusted = capable(CAP_SYS_ADMIN);
+ bool trusted = ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
struct simple_xattr *xattr;
+ struct rb_node *rbp;
ssize_t remaining_size = size;
int err = 0;
@@ -1162,8 +1304,10 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
}
#endif
- spin_lock(&xattrs->lock);
- list_for_each_entry(xattr, &xattrs->head, list) {
+ read_lock(&xattrs->lock);
+ for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) {
+ xattr = rb_entry(rbp, struct simple_xattr, rb_node);
+
/* skip "trusted." attributes for unprivileged callers */
if (!trusted && xattr_is_trusted(xattr->name))
continue;
@@ -1172,18 +1316,76 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
if (err)
break;
}
- spin_unlock(&xattrs->lock);
+ read_unlock(&xattrs->lock);
return err ? err : size - remaining_size;
}
-/*
- * Adds an extended attribute to the list
+/**
+ * rbtree_simple_xattr_less - compare two xattr rbtree nodes
+ * @new_node: new node
+ * @node: current node
+ *
+ * Compare the xattr attached to @new_node with the xattr attached to @node.
+ * Note that this function technically tolerates duplicate entries.
+ *
+ * Return: True if insertion point in the rbtree is found.
+ */
+static bool rbtree_simple_xattr_less(struct rb_node *new_node,
+ const struct rb_node *node)
+{
+ return rbtree_simple_xattr_node_cmp(new_node, node) < 0;
+}
+
+/**
+ * simple_xattr_add - add xattr objects
+ * @xattrs: the header of the xattr object
+ * @new_xattr: the xattr object to add
+ *
+ * Add an xattr object to @xattrs. This assumes no replacement or removal
+ * of matching xattrs is wanted. Should only be called during inode
+ * initialization when a few distinct initial xattrs are supposed to be set.
+ */
+void simple_xattr_add(struct simple_xattrs *xattrs,
+ struct simple_xattr *new_xattr)
+{
+ write_lock(&xattrs->lock);
+ rb_add(&new_xattr->rb_node, &xattrs->rb_root, rbtree_simple_xattr_less);
+ write_unlock(&xattrs->lock);
+}
+
+/**
+ * simple_xattrs_init - initialize new xattr header
+ * @xattrs: header to initialize
+ *
+ * Initialize relevant fields of a an xattr header.
*/
-void simple_xattr_list_add(struct simple_xattrs *xattrs,
- struct simple_xattr *new_xattr)
+void simple_xattrs_init(struct simple_xattrs *xattrs)
{
- spin_lock(&xattrs->lock);
- list_add(&new_xattr->list, &xattrs->head);
- spin_unlock(&xattrs->lock);
+ xattrs->rb_root = RB_ROOT;
+ rwlock_init(&xattrs->lock);
+}
+
+/**
+ * simple_xattrs_free - free xattrs
+ * @xattrs: xattr header whose xattrs to destroy
+ *
+ * Destroy all xattrs in @xattr. When this is called no one can hold a
+ * reference to any of the xattrs anymore.
+ */
+void simple_xattrs_free(struct simple_xattrs *xattrs)
+{
+ struct rb_node *rbp;
+
+ rbp = rb_first(&xattrs->rb_root);
+ while (rbp) {
+ struct simple_xattr *xattr;
+ struct rb_node *rbp_next;
+
+ rbp_next = rb_next(rbp);
+ xattr = rb_entry(rbp, struct simple_xattr, rb_node);
+ rb_erase(&xattr->rb_node, &xattrs->rb_root);
+ free_simple_xattr(xattr);
+ rbp = rbp_next;
+ }
}
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index de79f5d07f65..989cf341779b 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -1516,7 +1516,7 @@ xfs_alloc_ag_vextent_lastblock(
#ifdef DEBUG
/* Randomly don't execute the first algorithm. */
- if (prandom_u32_max(2))
+ if (get_random_u32_below(2))
return 0;
#endif
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 94db50eb706a..5118dedf9267 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -636,7 +636,7 @@ xfs_ialloc_ag_alloc(
/* randomly do sparse inode allocations */
if (xfs_has_sparseinodes(tp->t_mountp) &&
igeo->ialloc_min_blks < igeo->ialloc_blks)
- do_sparse = prandom_u32_max(2);
+ do_sparse = get_random_u32_below(2);
#endif
/*
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index b744c62052b6..a05f44eb8178 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -242,12 +242,13 @@ xfs_acl_set_mode(
}
int
-xfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+xfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
umode_t mode;
bool set_mode = false;
int error = 0;
+ struct inode *inode = d_inode(dentry);
if (!acl)
goto set_acl;
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 263404d0bfda..dcd176149c7a 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -11,7 +11,7 @@ struct posix_acl;
#ifdef CONFIG_XFS_POSIX_ACL
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type, bool rcu);
-extern int xfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+extern int xfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
void xfs_forget_acl(struct inode *inode, const char *name);
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index c6b2aabd6f18..822e6a0e9d1a 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -279,7 +279,7 @@ xfs_errortag_test(
ASSERT(error_tag < XFS_ERRTAG_MAX);
randfactor = mp->m_errortag[error_tag];
- if (!randfactor || prandom_u32_max(randfactor))
+ if (!randfactor || get_random_u32_below(randfactor))
return false;
xfs_warn_ratelimited(mp,
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 2e10e1c66ad6..712238305bc3 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -651,6 +651,7 @@ xfs_vn_change_ok(
static int
xfs_setattr_nonsize(
struct user_namespace *mnt_userns,
+ struct dentry *dentry,
struct xfs_inode *ip,
struct iattr *iattr)
{
@@ -757,7 +758,7 @@ xfs_setattr_nonsize(
* Posix ACL code seems to care about this issue either.
*/
if (mask & ATTR_MODE) {
- error = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
+ error = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
if (error)
return error;
}
@@ -779,6 +780,7 @@ out_dqrele:
STATIC int
xfs_setattr_size(
struct user_namespace *mnt_userns,
+ struct dentry *dentry,
struct xfs_inode *ip,
struct iattr *iattr)
{
@@ -810,7 +812,7 @@ xfs_setattr_size(
* Use the regular setattr path to update the timestamps.
*/
iattr->ia_valid &= ~ATTR_SIZE;
- return xfs_setattr_nonsize(mnt_userns, ip, iattr);
+ return xfs_setattr_nonsize(mnt_userns, dentry, ip, iattr);
}
/*
@@ -987,7 +989,7 @@ xfs_vn_setattr_size(
error = xfs_vn_change_ok(mnt_userns, dentry, iattr);
if (error)
return error;
- return xfs_setattr_size(mnt_userns, ip, iattr);
+ return xfs_setattr_size(mnt_userns, dentry, ip, iattr);
}
STATIC int
@@ -1019,7 +1021,7 @@ xfs_vn_setattr(
error = xfs_vn_change_ok(mnt_userns, dentry, iattr);
if (!error)
- error = xfs_setattr_nonsize(mnt_userns, ip, iattr);
+ error = xfs_setattr_nonsize(mnt_userns, dentry, ip, iattr);
}
return error;
@@ -1101,7 +1103,7 @@ xfs_vn_tmpfile(
}
static const struct inode_operations xfs_inode_operations = {
- .get_acl = xfs_get_acl,
+ .get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
@@ -1128,7 +1130,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
.rename = xfs_vn_rename,
- .get_acl = xfs_get_acl,
+ .get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
@@ -1155,7 +1157,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
.rename = xfs_vn_rename,
- .get_acl = xfs_get_acl,
+ .get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
index 860f0b1032c6..2c53fbb8d918 100644
--- a/fs/zonefs/super.c
+++ b/fs/zonefs/super.c
@@ -41,6 +41,13 @@ static void zonefs_account_active(struct inode *inode)
return;
/*
+ * For zones that transitioned to the offline or readonly condition,
+ * we only need to clear the active state.
+ */
+ if (zi->i_flags & (ZONEFS_ZONE_OFFLINE | ZONEFS_ZONE_READONLY))
+ goto out;
+
+ /*
* If the zone is active, that is, if it is explicitly open or
* partially written, check if it was already accounted as active.
*/
@@ -53,6 +60,7 @@ static void zonefs_account_active(struct inode *inode)
return;
}
+out:
/* The zone is not active. If it was, update the active count */
if (zi->i_flags & ZONEFS_ZONE_ACTIVE) {
zi->i_flags &= ~ZONEFS_ZONE_ACTIVE;
@@ -324,6 +332,7 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
inode->i_flags |= S_IMMUTABLE;
inode->i_mode &= ~0777;
zone->wp = zone->start;
+ zi->i_flags |= ZONEFS_ZONE_OFFLINE;
return 0;
case BLK_ZONE_COND_READONLY:
/*
@@ -342,8 +351,10 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
zone->cond = BLK_ZONE_COND_OFFLINE;
inode->i_mode &= ~0777;
zone->wp = zone->start;
+ zi->i_flags |= ZONEFS_ZONE_OFFLINE;
return 0;
}
+ zi->i_flags |= ZONEFS_ZONE_READONLY;
inode->i_mode &= ~0222;
return i_size_read(inode);
case BLK_ZONE_COND_FULL:
@@ -478,8 +489,7 @@ static void __zonefs_io_error(struct inode *inode, bool write)
struct super_block *sb = inode->i_sb;
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
unsigned int noio_flag;
- unsigned int nr_zones =
- zi->i_zone_size >> (sbi->s_zone_sectors_shift + SECTOR_SHIFT);
+ unsigned int nr_zones = 1;
struct zonefs_ioerr_data err = {
.inode = inode,
.write = write,
@@ -487,6 +497,15 @@ static void __zonefs_io_error(struct inode *inode, bool write)
int ret;
/*
+ * The only files that have more than one zone are conventional zone
+ * files with aggregated conventional zones, for which the inode zone
+ * size is always larger than the device zone size.
+ */
+ if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev))
+ nr_zones = zi->i_zone_size >>
+ (sbi->s_zone_sectors_shift + SECTOR_SHIFT);
+
+ /*
* Memory allocations in blkdev_report_zones() can trigger a memory
* reclaim which may in turn cause a recursion into zonefs as well as
* struct request allocations for the same device. The former case may
@@ -1407,6 +1426,14 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
zi->i_ztype = type;
zi->i_zsector = zone->start;
zi->i_zone_size = zone->len << SECTOR_SHIFT;
+ if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT &&
+ !(sbi->s_features & ZONEFS_F_AGGRCNV)) {
+ zonefs_err(sb,
+ "zone size %llu doesn't match device's zone sectors %llu\n",
+ zi->i_zone_size,
+ bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT);
+ return -EINVAL;
+ }
zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
zone->capacity << SECTOR_SHIFT);
@@ -1456,11 +1483,11 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
struct inode *dir = d_inode(parent);
struct dentry *dentry;
struct inode *inode;
- int ret;
+ int ret = -ENOMEM;
dentry = d_alloc_name(parent, name);
if (!dentry)
- return NULL;
+ return ERR_PTR(ret);
inode = new_inode(parent->d_sb);
if (!inode)
@@ -1485,7 +1512,7 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
dput:
dput(dentry);
- return NULL;
+ return ERR_PTR(ret);
}
struct zonefs_zone_data {
@@ -1505,7 +1532,7 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
struct blk_zone *zone, *next, *end;
const char *zgroup_name;
char *file_name;
- struct dentry *dir;
+ struct dentry *dir, *dent;
unsigned int n = 0;
int ret;
@@ -1523,8 +1550,8 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
zgroup_name = "seq";
dir = zonefs_create_inode(sb->s_root, zgroup_name, NULL, type);
- if (!dir) {
- ret = -ENOMEM;
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
goto free;
}
@@ -1570,8 +1597,9 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
* Use the file number within its group as file name.
*/
snprintf(file_name, ZONEFS_NAME_MAX - 1, "%u", n);
- if (!zonefs_create_inode(dir, file_name, zone, type)) {
- ret = -ENOMEM;
+ dent = zonefs_create_inode(dir, file_name, zone, type);
+ if (IS_ERR(dent)) {
+ ret = PTR_ERR(dent);
goto free;
}
@@ -1905,18 +1933,18 @@ static int __init zonefs_init(void)
if (ret)
return ret;
- ret = register_filesystem(&zonefs_type);
+ ret = zonefs_sysfs_init();
if (ret)
goto destroy_inodecache;
- ret = zonefs_sysfs_init();
+ ret = register_filesystem(&zonefs_type);
if (ret)
- goto unregister_fs;
+ goto sysfs_exit;
return 0;
-unregister_fs:
- unregister_filesystem(&zonefs_type);
+sysfs_exit:
+ zonefs_sysfs_exit();
destroy_inodecache:
zonefs_destroy_inodecache();
@@ -1925,9 +1953,9 @@ destroy_inodecache:
static void __exit zonefs_exit(void)
{
+ unregister_filesystem(&zonefs_type);
zonefs_sysfs_exit();
zonefs_destroy_inodecache();
- unregister_filesystem(&zonefs_type);
}
MODULE_AUTHOR("Damien Le Moal");
diff --git a/fs/zonefs/sysfs.c b/fs/zonefs/sysfs.c
index 9cb6755ce39a..9920689dc098 100644
--- a/fs/zonefs/sysfs.c
+++ b/fs/zonefs/sysfs.c
@@ -15,11 +15,6 @@ struct zonefs_sysfs_attr {
ssize_t (*show)(struct zonefs_sb_info *sbi, char *buf);
};
-static inline struct zonefs_sysfs_attr *to_attr(struct attribute *attr)
-{
- return container_of(attr, struct zonefs_sysfs_attr, attr);
-}
-
#define ZONEFS_SYSFS_ATTR_RO(name) \
static struct zonefs_sysfs_attr zonefs_sysfs_attr_##name = __ATTR_RO(name)
diff --git a/fs/zonefs/zonefs.h b/fs/zonefs/zonefs.h
index 4b3de66c3233..1dbe78119ff1 100644
--- a/fs/zonefs/zonefs.h
+++ b/fs/zonefs/zonefs.h
@@ -39,8 +39,10 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
return ZONEFS_ZTYPE_SEQ;
}
-#define ZONEFS_ZONE_OPEN (1 << 0)
-#define ZONEFS_ZONE_ACTIVE (1 << 1)
+#define ZONEFS_ZONE_OPEN (1U << 0)
+#define ZONEFS_ZONE_ACTIVE (1U << 1)
+#define ZONEFS_ZONE_OFFLINE (1U << 2)
+#define ZONEFS_ZONE_READONLY (1U << 3)
/*
* In-memory inode data.
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index c3ae3ea88e17..151e40385673 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -190,6 +190,8 @@
#define ACPI_PRM_INPUT_BUFFER_SIZE 26
+#define ACPI_FFH_INPUT_BUFFER_SIZE 256
+
/* _sx_d and _sx_w control methods */
#define ACPI_NUM_sx_d_METHODS 4
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c09d72986968..cd3b75e08ec3 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -149,7 +149,7 @@ struct acpi_hotplug_context {
*/
typedef int (*acpi_op_add) (struct acpi_device * device);
-typedef int (*acpi_op_remove) (struct acpi_device * device);
+typedef void (*acpi_op_remove) (struct acpi_device *device);
typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
struct acpi_device_ops {
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 67c0b9e734b6..9e49b37fc869 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20220331
+#define ACPI_CA_VERSION 0x20221020
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 15c78678c5d3..4175dce3967c 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -45,6 +45,7 @@
#define ACPI_SIG_HMAT "HMAT" /* Heterogeneous Memory Attributes Table */
#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */
#define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */
+#define ACPI_SIG_MSCT "MSCT" /* Maximum System Characteristics Table */
#define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */
#define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */
@@ -305,10 +306,123 @@ struct acpi_table_boot {
/*******************************************************************************
*
+ * CDAT - Coherent Device Attribute Table
+ * Version 1
+ *
+ * Conforms to the "Coherent Device Attribute Table (CDAT) Specification
+ " (Revision 1.01, October 2020.)
+ *
+ ******************************************************************************/
+
+struct acpi_table_cdat {
+ u32 length; /* Length of table in bytes, including this header */
+ u8 revision; /* ACPI Specification minor version number */
+ u8 checksum; /* To make sum of entire table == 0 */
+ u8 reserved[6];
+ u32 sequence; /* Used to detect runtime CDAT table changes */
+};
+
+/* CDAT common subtable header */
+
+struct acpi_cdat_header {
+ u8 type;
+ u8 reserved;
+ u16 length;
+};
+
+/* Values for Type field above */
+
+enum acpi_cdat_type {
+ ACPI_CDAT_TYPE_DSMAS = 0,
+ ACPI_CDAT_TYPE_DSLBIS = 1,
+ ACPI_CDAT_TYPE_DSMSCIS = 2,
+ ACPI_CDAT_TYPE_DSIS = 3,
+ ACPI_CDAT_TYPE_DSEMTS = 4,
+ ACPI_CDAT_TYPE_SSLBIS = 5,
+ ACPI_CDAT_TYPE_RESERVED = 6 /* 6 through 0xFF are reserved */
+};
+
+/* Subtable 0: Device Scoped Memory Affinity Structure (DSMAS) */
+
+struct acpi_cadt_dsmas {
+ u8 dsmad_handle;
+ u8 flags;
+ u16 reserved;
+ u64 dpa_base_address;
+ u64 dpa_length;
+};
+
+/* Flags for subtable above */
+
+#define ACPI_CEDT_DSMAS_NON_VOLATILE (1 << 2)
+
+/* Subtable 1: Device scoped Latency and Bandwidth Information Structure (DSLBIS) */
+
+struct acpi_cdat_dslbis {
+ u8 handle;
+ u8 flags; /* If Handle matches a DSMAS handle, the definition of this field matches
+ * Flags field in HMAT System Locality Latency */
+ u8 data_type;
+ u8 reserved;
+ u64 entry_base_unit;
+ u16 entry[3];
+ u16 reserved2;
+};
+
+/* Subtable 2: Device Scoped Memory Side Cache Information Structure (DSMSCIS) */
+
+struct acpi_cdat_dsmscis {
+ u8 dsmas_handle;
+ u8 reserved[3];
+ u64 side_cache_size;
+ u32 cache_attributes;
+};
+
+/* Subtable 3: Device Scoped Initiator Structure (DSIS) */
+
+struct acpi_cdat_dsis {
+ u8 flags;
+ u8 handle;
+ u16 reserved;
+};
+
+/* Flags for above subtable */
+
+#define ACPI_CDAT_DSIS_MEM_ATTACHED (1 << 0)
+
+/* Subtable 4: Device Scoped EFI Memory Type Structure (DSEMTS) */
+
+struct acpi_cdat_dsemts {
+ u8 dsmas_handle;
+ u8 memory_type;
+ u16 reserved;
+ u64 dpa_offset;
+ u64 range_length;
+};
+
+/* Subtable 5: Switch Scoped Latency and Bandwidth Information Structure (SSLBIS) */
+
+struct acpi_cdat_sslbis {
+ u8 data_type;
+ u8 reserved[3];
+ u64 entry_base_unit;
+};
+
+/* Sub-subtable for above, sslbe_entries field */
+
+struct acpi_cdat_sslbe {
+ u16 portx_id;
+ u16 porty_id;
+ u16 latency_or_bandwidth;
+ u16 reserved;
+};
+
+/*******************************************************************************
+ *
* CEDT - CXL Early Discovery Table
* Version 1
*
- * Conforms to the "CXL Early Discovery Table" (CXL 2.0)
+ * Conforms to the "CXL Early Discovery Table" (CXL 2.0, October 2020)
*
******************************************************************************/
@@ -329,7 +443,9 @@ struct acpi_cedt_header {
enum acpi_cedt_type {
ACPI_CEDT_TYPE_CHBS = 0,
ACPI_CEDT_TYPE_CFMWS = 1,
- ACPI_CEDT_TYPE_RESERVED = 2,
+ ACPI_CEDT_TYPE_CXIMS = 2,
+ ACPI_CEDT_TYPE_RDPAS = 3,
+ ACPI_CEDT_TYPE_RESERVED = 4,
};
/* Values for version field above */
@@ -380,6 +496,7 @@ struct acpi_cedt_cfmws_target_element {
/* Values for Interleave Arithmetic field above */
#define ACPI_CEDT_CFMWS_ARITHMETIC_MODULO (0)
+#define ACPI_CEDT_CFMWS_ARITHMETIC_XOR (1)
/* Values for Restrictions field above */
@@ -389,6 +506,36 @@ struct acpi_cedt_cfmws_target_element {
#define ACPI_CEDT_CFMWS_RESTRICT_PMEM (1<<3)
#define ACPI_CEDT_CFMWS_RESTRICT_FIXED (1<<4)
+/* 2: CXL XOR Interleave Math Structure */
+
+struct acpi_cedt_cxims {
+ struct acpi_cedt_header header;
+ u16 reserved1;
+ u8 hbig;
+ u8 nr_xormaps;
+ u64 xormap_list[];
+};
+
+/* 3: CXL RCEC Downstream Port Association Structure */
+
+struct acpi_cedt_rdpas {
+ struct acpi_cedt_header header;
+ u8 reserved1;
+ u16 length;
+ u16 segment;
+ u16 bdf;
+ u8 protocol;
+ u64 address;
+};
+
+/* Masks for bdf field above */
+#define ACPI_CEDT_RDPAS_BUS_MASK 0xff00
+#define ACPI_CEDT_RDPAS_DEVICE_MASK 0x00f8
+#define ACPI_CEDT_RDPAS_FUNCTION_MASK 0x0007
+
+#define ACPI_CEDT_RDPAS_PROTOCOL_IO (0)
+#define ACPI_CEDT_RDPAS_PROTOCOL_CACHEMEM (1)
+
/*******************************************************************************
*
* CPEP - Corrected Platform Error Polling table (ACPI 4.0)
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 655102bc6d14..b2973dbe37ee 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -27,6 +27,8 @@
#define ACPI_SIG_AGDI "AGDI" /* Arm Generic Diagnostic Dump and Reset Device Interface */
#define ACPI_SIG_APMT "APMT" /* Arm Performance Monitoring Unit table */
#define ACPI_SIG_BDAT "BDAT" /* BIOS Data ACPI Table */
+#define ACPI_SIG_CCEL "CCEL" /* CC Event Log Table */
+#define ACPI_SIG_CDAT "CDAT" /* Coherent Device Attribute Table */
#define ACPI_SIG_IORT "IORT" /* IO Remapping Table */
#define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */
#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */
@@ -34,7 +36,6 @@
#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */
#define ACPI_SIG_MPST "MPST" /* Memory Power State Table */
-#define ACPI_SIG_MSCT "MSCT" /* Maximum System Characteristics Table */
#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */
#define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */
#define ACPI_SIG_NHLT "NHLT" /* Non HD Audio Link Table */
@@ -354,10 +355,27 @@ struct acpi_table_bdat {
/*******************************************************************************
*
+ * CCEL - CC-Event Log
+ * From: "Guest-Host-Communication Interface (GHCI) for Intel
+ * Trust Domain Extensions (Intel TDX)". Feb 2022
+ *
+ ******************************************************************************/
+
+struct acpi_table_ccel {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 CCtype;
+ u8 Ccsub_type;
+ u16 reserved;
+ u64 log_area_minimum_length;
+ u64 log_area_start_address;
+};
+
+/*******************************************************************************
+ *
* IORT - IO Remapping Table
*
* Conforms to "IO Remapping Table System Software on ARM Platforms",
- * Document number: ARM DEN 0049E.d, Feb 2022
+ * Document number: ARM DEN 0049E.e, Sep 2022
*
******************************************************************************/
@@ -528,6 +546,7 @@ struct acpi_iort_smmu_v3 {
#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1)
#define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (3<<1)
#define ACPI_IORT_SMMU_V3_PXM_VALID (1<<3)
+#define ACPI_IORT_SMMU_V3_DEVICEID_VALID (1<<4)
struct acpi_iort_pmcg {
u64 page0_base_address;
@@ -865,7 +884,14 @@ enum acpi_madt_type {
ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14,
ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15,
ACPI_MADT_TYPE_MULTIPROC_WAKEUP = 16,
- ACPI_MADT_TYPE_RESERVED = 17, /* 17 to 0x7F are reserved */
+ ACPI_MADT_TYPE_CORE_PIC = 17,
+ ACPI_MADT_TYPE_LIO_PIC = 18,
+ ACPI_MADT_TYPE_HT_PIC = 19,
+ ACPI_MADT_TYPE_EIO_PIC = 20,
+ ACPI_MADT_TYPE_MSI_PIC = 21,
+ ACPI_MADT_TYPE_BIO_PIC = 22,
+ ACPI_MADT_TYPE_LPC_PIC = 23,
+ ACPI_MADT_TYPE_RESERVED = 24, /* 24 to 0x7F are reserved */
ACPI_MADT_TYPE_OEM_RESERVED = 0x80 /* 0x80 to 0xFF are reserved for OEM use */
};
@@ -1096,7 +1122,135 @@ struct acpi_madt_multiproc_wakeup_mailbox {
#define ACPI_MP_WAKE_COMMAND_WAKEUP 1
-/* 17: OEM data */
+/* 17: CPU Core Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_core_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u32 processor_id;
+ u32 core_id;
+ u32 flags;
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_core_pic_version {
+ ACPI_MADT_CORE_PIC_VERSION_NONE = 0,
+ ACPI_MADT_CORE_PIC_VERSION_V1 = 1,
+ ACPI_MADT_CORE_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 18: Legacy I/O Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_lio_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u64 address;
+ u16 size;
+ u8 cascade[2];
+ u32 cascade_map[2];
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_lio_pic_version {
+ ACPI_MADT_LIO_PIC_VERSION_NONE = 0,
+ ACPI_MADT_LIO_PIC_VERSION_V1 = 1,
+ ACPI_MADT_LIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 19: HT Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_ht_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u64 address;
+ u16 size;
+ u8 cascade[8];
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_ht_pic_version {
+ ACPI_MADT_HT_PIC_VERSION_NONE = 0,
+ ACPI_MADT_HT_PIC_VERSION_V1 = 1,
+ ACPI_MADT_HT_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 20: Extend I/O Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_eio_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u8 cascade;
+ u8 node;
+ u64 node_map;
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_eio_pic_version {
+ ACPI_MADT_EIO_PIC_VERSION_NONE = 0,
+ ACPI_MADT_EIO_PIC_VERSION_V1 = 1,
+ ACPI_MADT_EIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 21: MSI Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_msi_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u64 msg_address;
+ u32 start;
+ u32 count;
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_msi_pic_version {
+ ACPI_MADT_MSI_PIC_VERSION_NONE = 0,
+ ACPI_MADT_MSI_PIC_VERSION_V1 = 1,
+ ACPI_MADT_MSI_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 22: Bridge I/O Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_bio_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u64 address;
+ u16 size;
+ u16 id;
+ u16 gsi_base;
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_bio_pic_version {
+ ACPI_MADT_BIO_PIC_VERSION_NONE = 0,
+ ACPI_MADT_BIO_PIC_VERSION_V1 = 1,
+ ACPI_MADT_BIO_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 23: LPC Interrupt Controller (ACPI 6.5) */
+
+struct acpi_madt_lpc_pic {
+ struct acpi_subtable_header header;
+ u8 version;
+ u64 address;
+ u16 size;
+ u8 cascade;
+};
+
+/* Values for Version field above */
+
+enum acpi_madt_lpc_pic_version {
+ ACPI_MADT_LPC_PIC_VERSION_NONE = 0,
+ ACPI_MADT_LPC_PIC_VERSION_V1 = 1,
+ ACPI_MADT_LPC_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+/* 80: OEM data */
struct acpi_madt_oem_data {
u8 oem_data[0];
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 3491e454b2ab..95e4f56f9754 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -723,7 +723,8 @@ typedef u32 acpi_event_type;
#define ACPI_EVENT_POWER_BUTTON 2
#define ACPI_EVENT_SLEEP_BUTTON 3
#define ACPI_EVENT_RTC 4
-#define ACPI_EVENT_MAX 4
+#define ACPI_EVENT_PCIE_WAKE 5
+#define ACPI_EVENT_MAX 5
#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1
/*
@@ -1115,6 +1116,13 @@ struct acpi_pcc_info {
u8 *internal_buffer;
};
+/* Special Context data for FFH Opregion (ACPI 6.5) */
+
+struct acpi_ffh_info {
+ u64 offset;
+ u64 length;
+};
+
typedef
acpi_status (*acpi_adr_space_setup) (acpi_handle region_handle,
u32 function,
diff --git a/include/acpi/acuuid.h b/include/acpi/acuuid.h
index 8f1e7c489df5..171bb0b708a2 100644
--- a/include/acpi/acuuid.h
+++ b/include/acpi/acuuid.h
@@ -69,5 +69,6 @@
#define UUID_HIERARCHICAL_DATA_EXTENSION "dbb8e3e6-5886-4ba6-8795-1319f52a966b"
#define UUID_CORESIGHT_GRAPH "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"
#define UUID_USB4_CAPABILITIES "23a0d13a-26ab-486c-9c5f-0ffa525a575a"
-
+#define UUID_1ST_FUNCTION_ID "893f00a6-660c-494e-bcfd-3043f4fb67c0"
+#define UUID_2ND_FUNCTION_ID "107ededd-d381-4fd7-8da9-08e9a6c79644"
#endif /* __ACUUID_H__ */
diff --git a/include/acpi/battery.h b/include/acpi/battery.h
index b8d56b702c7a..611a2561a014 100644
--- a/include/acpi/battery.h
+++ b/include/acpi/battery.h
@@ -12,8 +12,8 @@
struct acpi_battery_hook {
const char *name;
- int (*add_battery)(struct power_supply *battery);
- int (*remove_battery)(struct power_supply *battery);
+ int (*add_battery)(struct power_supply *battery, struct acpi_battery_hook *hook);
+ int (*remove_battery)(struct power_supply *battery, struct acpi_battery_hook *hook);
struct list_head list;
};
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 292a5c40bd0c..3c8bba9f1114 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -27,6 +27,8 @@ struct ghes {
struct timer_list timer;
unsigned int irq;
};
+ struct device *dev;
+ struct list_head elist;
};
struct ghes_estatus_node {
@@ -69,35 +71,14 @@ int ghes_register_vendor_record_notifier(struct notifier_block *nb);
* @nb: pointer to the notifier_block structure of the vendor record handler.
*/
void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
-#endif
-
-int ghes_estatus_pool_init(unsigned int num_ghes);
-
-/* From drivers/edac/ghes_edac.c */
-
-#ifdef CONFIG_EDAC_GHES
-void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
-
-int ghes_edac_register(struct ghes *ghes, struct device *dev);
-
-void ghes_edac_unregister(struct ghes *ghes);
+struct list_head *ghes_get_devices(void);
#else
-static inline void ghes_edac_report_mem_error(int sev,
- struct cper_sec_mem_err *mem_err)
-{
-}
-
-static inline int ghes_edac_register(struct ghes *ghes, struct device *dev)
-{
- return -ENODEV;
-}
-
-static inline void ghes_edac_unregister(struct ghes *ghes)
-{
-}
+static inline struct list_head *ghes_get_devices(void) { return NULL; }
#endif
+int ghes_estatus_pool_init(unsigned int num_ghes);
+
static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
{
return gdata->revision >> 8;
@@ -145,4 +126,7 @@ int ghes_notify_sea(void);
static inline int ghes_notify_sea(void) { return -ENOENT; }
#endif
+struct notifier_block;
+extern void ghes_register_report_chain(struct notifier_block *nb);
+extern void ghes_unregister_report_chain(struct notifier_block *nb);
#endif /* GHES_H */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 9fa49686957a..94181fe9780a 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -460,4 +460,14 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
}
#endif /* CONFIG_CPU_FREQ */
+#ifdef CONFIG_ACPI_PROCESSOR_IDLE
+extern int acpi_processor_ffh_lpi_probe(unsigned int cpu);
+extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
+#endif
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+extern int arch_register_cpu(int cpu);
+extern void arch_unregister_cpu(int cpu);
+#endif
+
#endif
diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
index fdce7a4cfc6f..b17c6eeb9afa 100644
--- a/include/asm-generic/hyperv-tlfs.h
+++ b/include/asm-generic/hyperv-tlfs.h
@@ -102,6 +102,15 @@ struct ms_hyperv_tsc_page {
volatile s64 tsc_offset;
} __packed;
+union hv_reference_tsc_msr {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 reserved:11;
+ u64 pfn:52;
+ } __packed;
+};
+
/*
* The guest OS needs to register the guest ID with the hypervisor.
* The guest ID is a 64 bit entity and the structure of this ID is
diff --git a/include/asm-generic/msi.h b/include/asm-generic/msi.h
index bf910d47e900..124c734ca5d9 100644
--- a/include/asm-generic/msi.h
+++ b/include/asm-generic/msi.h
@@ -4,7 +4,7 @@
#include <linux/types.h>
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
#ifndef NUM_MSI_ALLOC_SCRATCHPAD_REGS
# define NUM_MSI_ALLOC_SCRATCHPAD_REGS 2
@@ -36,6 +36,6 @@ typedef struct msi_alloc_info {
#define GENERIC_MSI_DOMAIN_OPS 1
-#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
+#endif /* CONFIG_GENERIC_MSI_IRQ */
#endif
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 492dce43236e..cab7cfebf40b 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -222,12 +222,16 @@ extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
#define tlb_needs_table_invalidate() (true)
#endif
+void tlb_remove_table_sync_one(void);
+
#else
#ifdef tlb_needs_table_invalidate
#error tlb_needs_table_invalidate() requires MMU_GATHER_RCU_TABLE_FREE
#endif
+static inline void tlb_remove_table_sync_one(void) { }
+
#endif /* CONFIG_MMU_GATHER_RCU_TABLE_FREE */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index d06ada2341cb..c8ab800652b5 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -347,6 +347,7 @@
#define DATA_DATA \
*(.xiptext) \
*(DATA_MAIN) \
+ *(.data..decrypted) \
*(.ref.data) \
*(.data..shared_aligned) /* percpu related */ \
MEM_KEEP(init.data*) \
@@ -995,7 +996,6 @@
#ifdef CONFIG_AMD_MEM_ENCRYPT
#define PERCPU_DECRYPTED_SECTION \
. = ALIGN(PAGE_SIZE); \
- *(.data..decrypted) \
*(.data..percpu..decrypted) \
. = ALIGN(PAGE_SIZE);
#else
@@ -1027,14 +1027,19 @@
* keep any .init_array.* sections.
* https://bugs.llvm.org/show_bug.cgi?id=46478
*/
+#ifdef CONFIG_UNWIND_TABLES
+#define DISCARD_EH_FRAME
+#else
+#define DISCARD_EH_FRAME *(.eh_frame)
+#endif
#if defined(CONFIG_GCOV_KERNEL) || defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN)
# ifdef CONFIG_CONSTRUCTORS
# define SANITIZER_DISCARDS \
- *(.eh_frame)
+ DISCARD_EH_FRAME
# else
# define SANITIZER_DISCARDS \
*(.init_array) *(.init_array.*) \
- *(.eh_frame)
+ DISCARD_EH_FRAME
# endif
#else
# define SANITIZER_DISCARDS
diff --git a/include/clocksource/hyperv_timer.h b/include/clocksource/hyperv_timer.h
index b3f5d73ae1d6..536f897375d0 100644
--- a/include/clocksource/hyperv_timer.h
+++ b/include/clocksource/hyperv_timer.h
@@ -15,13 +15,15 @@
#include <linux/clocksource.h>
#include <linux/math64.h>
-#include <asm/mshyperv.h>
+#include <asm/hyperv-tlfs.h>
#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
#define HV_MIN_DELTA_TICKS 1
#ifdef CONFIG_HYPERV_TIMER
+#include <asm/hyperv_timer.h>
+
/* Routines called by the VMbus driver */
extern int hv_stimer_alloc(bool have_percpu_irqs);
extern int hv_stimer_cleanup(unsigned int cpu);
@@ -31,7 +33,9 @@ extern void hv_stimer_global_cleanup(void);
extern void hv_stimer0_isr(void);
extern void hv_init_clocksource(void);
+extern void hv_remap_tsc_clocksource(void);
+extern unsigned long hv_get_tsc_pfn(void);
extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
static inline notrace u64
@@ -90,6 +94,11 @@ hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
}
#else /* CONFIG_HYPERV_TIMER */
+static inline unsigned long hv_get_tsc_pfn(void)
+{
+ return 0;
+}
+
static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
{
return NULL;
diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h
index 77eceeae708c..dcc1712f75e7 100644
--- a/include/clocksource/timer-ti-dm.h
+++ b/include/clocksource/timer-ti-dm.h
@@ -62,8 +62,6 @@
struct omap_dm_timer {
};
-int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
-
u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
/*
diff --git a/include/drm/drm_accel.h b/include/drm/drm_accel.h
new file mode 100644
index 000000000000..65c0affbd306
--- /dev/null
+++ b/include/drm/drm_accel.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2022 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+#ifndef DRM_ACCEL_H_
+#define DRM_ACCEL_H_
+
+#include <drm/drm_file.h>
+
+#define ACCEL_MAJOR 261
+#define ACCEL_MAX_MINORS 256
+
+/**
+ * DRM_ACCEL_FOPS - Default drm accelerators file operations
+ *
+ * This macro provides a shorthand for setting the accelerator file ops in the
+ * &file_operations structure. If all you need are the default ops, use
+ * DEFINE_DRM_ACCEL_FOPS instead.
+ */
+#define DRM_ACCEL_FOPS \
+ .open = accel_open,\
+ .release = drm_release,\
+ .unlocked_ioctl = drm_ioctl,\
+ .compat_ioctl = drm_compat_ioctl,\
+ .poll = drm_poll,\
+ .read = drm_read,\
+ .llseek = noop_llseek
+
+/**
+ * DEFINE_DRM_ACCEL_FOPS() - macro to generate file operations for accelerators drivers
+ * @name: name for the generated structure
+ *
+ * This macro autogenerates a suitable &struct file_operations for accelerators based
+ * drivers, which can be assigned to &drm_driver.fops. Note that this structure
+ * cannot be shared between drivers, because it contains a reference to the
+ * current module using THIS_MODULE.
+ *
+ * Note that the declaration is already marked as static - if you need a
+ * non-static version of this you're probably doing it wrong and will break the
+ * THIS_MODULE reference by accident.
+ */
+#define DEFINE_DRM_ACCEL_FOPS(name) \
+ static const struct file_operations name = {\
+ .owner = THIS_MODULE,\
+ DRM_ACCEL_FOPS,\
+ }
+
+#if IS_ENABLED(CONFIG_DRM_ACCEL)
+
+void accel_core_exit(void);
+int accel_core_init(void);
+void accel_minor_remove(int index);
+int accel_minor_alloc(void);
+void accel_minor_replace(struct drm_minor *minor, int index);
+void accel_set_device_instance_params(struct device *kdev, int index);
+int accel_open(struct inode *inode, struct file *filp);
+void accel_debugfs_init(struct drm_minor *minor, int minor_id);
+
+#else
+
+static inline void accel_core_exit(void)
+{
+}
+
+static inline int __init accel_core_init(void)
+{
+ /* Return 0 to allow drm_core_init to complete successfully */
+ return 0;
+}
+
+static inline void accel_minor_remove(int index)
+{
+}
+
+static inline int accel_minor_alloc(void)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void accel_minor_replace(struct drm_minor *minor, int index)
+{
+}
+
+static inline void accel_set_device_instance_params(struct device *kdev, int index)
+{
+}
+
+static inline void accel_debugfs_init(struct drm_minor *minor, int minor_id)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_DRM_ACCEL) */
+
+#endif /* DRM_ACCEL_H_ */
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 06d8902a8097..33f982cd1a27 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -58,10 +58,9 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
int max_scale,
bool can_position,
bool can_update_disabled);
-int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state,
- bool can_disable_primary_plane);
int drm_atomic_helper_check_planes(struct drm_device *dev,
struct drm_atomic_state *state);
+int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state);
int drm_atomic_helper_check(struct drm_device *dev,
struct drm_atomic_state *state);
void drm_atomic_helper_commit_tail(struct drm_atomic_state *state);
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 3f8f1d627f7c..192766656b88 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -70,7 +70,7 @@ void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state);
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
-void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
+void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector);
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 56aee949c6fa..565cf9d3c550 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -656,6 +656,12 @@ struct drm_display_info {
* @mso_pixel_overlap: eDP MSO segment pixel overlap, 0-8 pixels.
*/
u8 mso_pixel_overlap;
+
+ /**
+ * @max_dsc_bpp: Maximum DSC target bitrate, if it is set to 0 the
+ * monitor's default value is used instead.
+ */
+ u32 max_dsc_bpp;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,
@@ -692,7 +698,8 @@ struct drm_connector_tv_margins {
/**
* struct drm_tv_connector_state - TV connector related states
- * @subconnector: selected subconnector
+ * @select_subconnector: selected subconnector
+ * @subconnector: detected subconnector
* @margins: TV margins
* @mode: TV mode
* @brightness: brightness in percent
@@ -703,6 +710,7 @@ struct drm_connector_tv_margins {
* @hue: hue in percent
*/
struct drm_tv_connector_state {
+ enum drm_mode_subconnector select_subconnector;
enum drm_mode_subconnector subconnector;
struct drm_connector_tv_margins margins;
unsigned int mode;
@@ -1211,6 +1219,13 @@ struct drm_cmdline_mode {
bool bpp_specified;
/**
+ * @pixel_clock:
+ *
+ * Pixel Clock in kHz. Optional.
+ */
+ unsigned int pixel_clock;
+
+ /**
* @xres:
*
* Active resolution on the X axis, in pixels.
@@ -1548,12 +1563,20 @@ struct drm_connector {
struct drm_cmdline_mode cmdline_mode;
/** @force: a DRM_FORCE_<foo> state for forced mode sets */
enum drm_connector_force force;
+
+ /**
+ * @edid_override: Override EDID set via debugfs.
+ *
+ * Do not modify or access outside of the drm_edid_override_* family of
+ * functions.
+ */
+ const struct drm_edid *edid_override;
+
/**
- * @override_edid: has the EDID been overwritten through debugfs for
- * testing? Do not modify outside of drm_edid_override_set() and
- * drm_edid_override_reset().
+ * @edid_override_mutex: Protect access to edid_override.
*/
- bool override_edid;
+ struct mutex edid_override_mutex;
+
/** @epoch_counter: used to detect any other changes in connector, besides status */
u64 epoch_counter;
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index a6d520d5b6ca..1840db247f69 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -50,6 +50,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y,
struct drm_framebuffer *old_fb);
+int drm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state);
bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 9923c7a6885e..933ce2048e20 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -93,6 +93,9 @@ struct drm_device {
/** @render: Render node */
struct drm_minor *render;
+ /** @accel: Compute Acceleration node */
+ struct drm_minor *accel;
+
/**
* @registered:
*
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index f6159acb8856..d7c521e8860f 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -30,6 +30,8 @@
#include <linux/list.h>
#include <linux/irqreturn.h>
+#include <video/nomodeset.h>
+
#include <drm/drm_device.h>
struct drm_file;
@@ -94,6 +96,14 @@ enum drm_driver_feature {
* synchronization of command submission.
*/
DRIVER_SYNCOBJ_TIMELINE = BIT(6),
+ /**
+ * @DRIVER_COMPUTE_ACCEL:
+ *
+ * Driver supports compute acceleration devices. This flag is mutually exclusive with
+ * @DRIVER_RENDER and @DRIVER_MODESET. Devices that support both graphics and compute
+ * acceleration should be handled by two drivers that are connected using auxiliary bus.
+ */
+ DRIVER_COMPUTE_ACCEL = BIT(7),
/* IMPORTANT: Below are all the legacy flags, add new ones above. */
@@ -602,6 +612,10 @@ static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev)
int drm_dev_set_unique(struct drm_device *dev, const char *name);
-extern bool drm_firmware_drivers_only(void);
+/* TODO: Inline drm_firmware_drivers_only() in all its callers. */
+static inline bool drm_firmware_drivers_only(void)
+{
+ return video_firmware_drivers_only();
+}
#endif
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 1ed61e2b30a4..372963600f1d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -97,10 +97,13 @@ struct detailed_data_string {
#define DRM_EDID_RANGE_OFFSET_MIN_HFREQ (1 << 2) /* 1.4 */
#define DRM_EDID_RANGE_OFFSET_MAX_HFREQ (1 << 3) /* 1.4 */
-#define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00
-#define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01
-#define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02
-#define DRM_EDID_CVT_SUPPORT_FLAG 0x04
+#define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 /* 1.3 */
+#define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 /* 1.4 */
+#define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 /* 1.3 */
+#define DRM_EDID_CVT_SUPPORT_FLAG 0x04 /* 1.4 */
+
+#define DRM_EDID_CVT_FLAGS_STANDARD_BLANKING (1 << 3)
+#define DRM_EDID_CVT_FLAGS_REDUCED_BLANKING (1 << 4)
struct detailed_data_monitor_range {
u8 min_vfreq;
@@ -206,7 +209,8 @@ struct detailed_timing {
#define DRM_EDID_DIGITAL_TYPE_DP (5 << 0) /* 1.4 */
#define DRM_EDID_DIGITAL_DFP_1_X (1 << 0) /* 1.3 */
-#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0)
+#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) /* 1.2 */
+#define DRM_EDID_FEATURE_CONTINUOUS_FREQ (1 << 0) /* 1.4 */
#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
#define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2)
/* If analog */
@@ -384,15 +388,8 @@ int drm_av_sync_delay(struct drm_connector *connector,
const struct drm_display_mode *mode);
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
-struct edid *drm_load_edid_firmware(struct drm_connector *connector);
int __drm_set_edid_firmware_path(const char *path);
int __drm_get_edid_firmware_path(char *buf, size_t bufsize);
-#else
-static inline struct edid *
-drm_load_edid_firmware(struct drm_connector *connector)
-{
- return ERR_PTR(-ENOENT);
-}
#endif
bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2);
@@ -573,7 +570,7 @@ struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
struct i2c_adapter *adapter);
struct edid *drm_edid_duplicate(const struct edid *edid);
int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
-int drm_add_override_edid_modes(struct drm_connector *connector);
+int drm_edid_override_connector_update(struct drm_connector *connector);
u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
bool drm_detect_hdmi_monitor(const struct edid *edid);
@@ -602,6 +599,7 @@ drm_display_mode_from_cea_vic(struct drm_device *dev,
const struct drm_edid *drm_edid_alloc(const void *edid, size_t size);
const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid);
void drm_edid_free(const struct drm_edid *drm_edid);
+bool drm_edid_valid(const struct drm_edid *drm_edid);
const struct edid *drm_edid_raw(const struct drm_edid *drm_edid);
const struct drm_edid *drm_edid_read(struct drm_connector *connector);
const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector,
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index fddd0d1af689..b111dc7ada78 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,13 +30,12 @@
#ifndef DRM_FB_HELPER_H
#define DRM_FB_HELPER_H
+struct drm_clip_rect;
struct drm_fb_helper;
-#include <drm/drm_client.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_device.h>
#include <linux/fb.h>
-#include <linux/kgdb.h>
+
+#include <drm/drm_client.h>
enum mode_set_atomic {
LEAVE_ATOMIC_MODE_SET,
@@ -91,6 +90,20 @@ struct drm_fb_helper_funcs {
*/
int (*fb_probe)(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes);
+
+ /**
+ * @fb_dirty:
+ *
+ * Driver callback to update the framebuffer memory. If set, fbdev
+ * emulation will invoke this callback in regular intervals after
+ * the framebuffer has been written.
+ *
+ * This callback is optional.
+ *
+ * Returns:
+ * 0 on success, or an error code otherwise.
+ */
+ int (*fb_dirty)(struct drm_fb_helper *helper, struct drm_clip_rect *clip);
};
/**
@@ -98,7 +111,7 @@ struct drm_fb_helper_funcs {
* @fb: Scanout framebuffer object
* @dev: DRM device
* @funcs: driver callbacks for fb helper
- * @fbdev: emulated fbdev device info struct
+ * @info: emulated fbdev device info struct
* @pseudo_palette: fake palette of 16 colors
* @damage_clip: clip rectangle used with deferred_io to accumulate damage to
* the screen buffer
@@ -129,7 +142,7 @@ struct drm_fb_helper {
struct drm_framebuffer *fb;
struct drm_device *dev;
const struct drm_fb_helper_funcs *funcs;
- struct fb_info *fbdev;
+ struct fb_info *info;
u32 pseudo_palette[17];
struct drm_clip_rect damage_clip;
spinlock_t damage_lock;
@@ -186,6 +199,15 @@ struct drm_fb_helper {
* See also: @deferred_setup
*/
int preferred_bpp;
+
+ /**
+ * @hint_leak_smem_start:
+ *
+ * Hint to the fbdev emulation to store the framebuffer's physical
+ * address in struct &fb_info.fix.smem_start. If the hint is unset,
+ * the smem_start field should always be cleared to zero.
+ */
+ bool hint_leak_smem_start;
};
static inline struct drm_fb_helper *
@@ -224,8 +246,8 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper);
-struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper);
-void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper);
+struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper);
+void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper);
void drm_fb_helper_fill_info(struct fb_info *info,
struct drm_fb_helper *fb_helper,
struct drm_fb_helper_surface_size *sizes);
@@ -244,6 +266,11 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
void drm_fb_helper_sys_imageblit(struct fb_info *info,
const struct fb_image *image);
+ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos);
+ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos);
+
void drm_fb_helper_cfb_fillrect(struct fb_info *info,
const struct fb_fillrect *rect);
void drm_fb_helper_cfb_copyarea(struct fb_info *info,
@@ -267,9 +294,6 @@ int drm_fb_helper_debug_leave(struct fb_info *info);
void drm_fb_helper_lastclose(struct drm_device *dev);
void drm_fb_helper_output_poll_changed(struct drm_device *dev);
-
-void drm_fbdev_generic_setup(struct drm_device *dev,
- unsigned int preferred_bpp);
#else
static inline void drm_fb_helper_prepare(struct drm_device *dev,
struct drm_fb_helper *helper,
@@ -322,12 +346,12 @@ drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
}
static inline struct fb_info *
-drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
+drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
{
return NULL;
}
-static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
+static inline void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper)
{
}
@@ -389,6 +413,18 @@ static inline void drm_fb_helper_sys_imageblit(struct fb_info *info,
{
}
+static inline ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -ENODEV;
+}
+
+static inline ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -ENODEV;
+}
+
static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
@@ -442,12 +478,6 @@ static inline void drm_fb_helper_lastclose(struct drm_device *dev)
static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev)
{
}
-
-static inline void
-drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
-{
-}
-
#endif
#endif
diff --git a/include/drm/drm_fbdev_generic.h b/include/drm/drm_fbdev_generic.h
new file mode 100644
index 000000000000..75799342098d
--- /dev/null
+++ b/include/drm/drm_fbdev_generic.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_FBDEV_GENERIC_H
+#define DRM_FBDEV_GENERIC_H
+
+struct drm_device;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+void drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp);
+#else
+static inline void drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{ }
+#endif
+
+#endif
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index d780fd151789..0d1f853092ab 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -51,11 +51,15 @@ struct file;
/* Note that the order of this enum is ABI (it determines
* /dev/dri/renderD* numbers).
+ *
+ * Setting DRM_MINOR_ACCEL to 32 gives enough space for more drm minors to
+ * be implemented before we hit any future
*/
enum drm_minor_type {
DRM_MINOR_PRIMARY,
DRM_MINOR_CONTROL,
DRM_MINOR_RENDER,
+ DRM_MINOR_ACCEL = 32,
};
/**
@@ -70,7 +74,7 @@ enum drm_minor_type {
struct drm_minor {
/* private: */
int index; /* Minor device number */
- int type; /* Control or render */
+ int type; /* Control or render or accel */
struct device *kdev; /* Linux device */
struct drm_device *dev;
@@ -397,7 +401,22 @@ static inline bool drm_is_render_client(const struct drm_file *file_priv)
return file_priv->minor->type == DRM_MINOR_RENDER;
}
+/**
+ * drm_is_accel_client - is this an open file of the compute acceleration node
+ * @file_priv: DRM file
+ *
+ * Returns true if this is an open file of the compute acceleration node, i.e.
+ * &drm_file.minor of @file_priv is a accel minor.
+ *
+ * See also the :ref:`section on accel nodes <drm_accel_node>`.
+ */
+static inline bool drm_is_accel_client(const struct drm_file *file_priv)
+{
+ return file_priv->minor->type == DRM_MINOR_ACCEL;
+}
+
int drm_open(struct inode *inode, struct file *filp);
+int drm_open_helper(struct file *filp, struct drm_minor *minor);
ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset);
int drm_release(struct inode *inode, struct file *filp);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index bd42f25e449c..a17c2f903f81 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -457,6 +457,9 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj);
void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
bool dirty, bool accessed);
+int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
+void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
+
int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles,
int count, struct drm_gem_object ***objs_out);
struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle);
diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h
index 6e3319e9001a..6970ccb787e2 100644
--- a/include/drm/drm_gem_atomic_helper.h
+++ b/include/drm/drm_gem_atomic_helper.h
@@ -103,8 +103,8 @@ void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane,
.atomic_duplicate_state = drm_gem_duplicate_shadow_plane_state, \
.atomic_destroy_state = drm_gem_destroy_shadow_plane_state
-int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state);
-void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state);
+int drm_gem_begin_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state);
+void drm_gem_end_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state);
/**
* DRM_GEM_SHADOW_PLANE_HELPER_FUNCS -
@@ -115,13 +115,13 @@ void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *
* functions.
*/
#define DRM_GEM_SHADOW_PLANE_HELPER_FUNCS \
- .prepare_fb = drm_gem_prepare_shadow_fb, \
- .cleanup_fb = drm_gem_cleanup_shadow_fb
+ .begin_fb_access = drm_gem_begin_shadow_fb_access, \
+ .end_fb_access = drm_gem_end_shadow_fb_access
-int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state);
-void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state);
+int drm_gem_simple_kms_begin_shadow_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state);
+void drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state);
void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe);
struct drm_plane_state *
drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe);
@@ -137,8 +137,8 @@ void drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pip
* functions.
*/
#define DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS \
- .prepare_fb = drm_gem_simple_kms_prepare_shadow_fb, \
- .cleanup_fb = drm_gem_simple_kms_cleanup_shadow_fb, \
+ .begin_fb_access = drm_gem_simple_kms_begin_shadow_fb_access, \
+ .end_fb_access = drm_gem_simple_kms_end_shadow_fb_access, \
.reset_plane = drm_gem_simple_kms_reset_shadow_plane, \
.duplicate_plane_state = drm_gem_simple_kms_duplicate_shadow_plane_state, \
.destroy_plane_state = drm_gem_simple_kms_destroy_shadow_plane_state
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 6b5e01295348..5362702fffe1 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -345,7 +345,6 @@ struct drm_mode_config_funcs {
* @max_width: maximum fb pixel width on this device
* @max_height: maximum fb pixel height on this device
* @funcs: core driver provided mode setting functions
- * @fb_base: base address of the framebuffer
* @poll_enabled: track polling support for this device
* @poll_running: track polling status for this device
* @delayed_event: track delayed poll uevent deliver for this device
@@ -542,7 +541,6 @@ struct drm_mode_config {
int min_width, min_height;
int max_width, max_height;
const struct drm_mode_config_funcs *funcs;
- resource_size_t fb_base;
/* output poll support */
bool poll_enabled;
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index fafa70ac1337..d9f2254a039a 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1184,11 +1184,20 @@ struct drm_plane_helper_funcs {
* can call drm_gem_plane_helper_prepare_fb() from their @prepare_fb
* hook.
*
+ * The resources acquired in @prepare_fb persist after the end of
+ * the atomic commit. Resources that can be release at the commit's end
+ * should be acquired in @begin_fb_access and released in @end_fb_access.
+ * For example, a GEM buffer's pin operation belongs into @prepare_fb to
+ * keep the buffer pinned after the commit. But a vmap operation for
+ * shadow-plane helpers belongs into @begin_fb_access, so that atomic
+ * helpers remove the mapping at the end of the commit.
+ *
* The helpers will call @cleanup_fb with matching arguments for every
* successful call to this hook.
*
* This callback is used by the atomic modeset helpers and by the
- * transitional plane helpers, but it is optional.
+ * transitional plane helpers, but it is optional. See @begin_fb_access
+ * for preparing per-commit resources.
*
* RETURNS:
*
@@ -1212,6 +1221,36 @@ struct drm_plane_helper_funcs {
struct drm_plane_state *old_state);
/**
+ * @begin_fb_access:
+ *
+ * This hook prepares the plane for access during an atomic commit.
+ * In contrast to @prepare_fb, resources acquired in @begin_fb_access,
+ * are released at the end of the atomic commit in @end_fb_access.
+ *
+ * For example, with shadow-plane helpers, the GEM buffer's vmap
+ * operation belongs into @begin_fb_access, so that the buffer's
+ * memory will be unmapped at the end of the commit in @end_fb_access.
+ * But a GEM buffer's pin operation belongs into @prepare_fb
+ * to keep the buffer pinned after the commit.
+ *
+ * The callback is used by the atomic modeset helpers, but it is optional.
+ * See @end_fb_cleanup for undoing the effects of @begin_fb_access and
+ * @prepare_fb for acquiring resources until the next pageflip.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+ int (*begin_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state);
+
+ /**
+ * @end_fb_access:
+ *
+ * This hook cleans up resources allocated by @begin_fb_access. It it called
+ * at the end of a commit for the new plane state.
+ */
+ void (*end_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state);
+
+ /**
* @atomic_check:
*
* Drivers should check plane specific constraints in this hook.
diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h
index 0b3647e614dd..2298fe3af4cd 100644
--- a/include/drm/drm_simple_kms_helper.h
+++ b/include/drm/drm_simple_kms_helper.h
@@ -136,6 +136,26 @@ struct drm_simple_display_pipe_funcs {
struct drm_plane_state *plane_state);
/**
+ * @begin_fb_access:
+ *
+ * Optional, called by &drm_plane_helper_funcs.begin_fb_access. Please read
+ * the documentation for the &drm_plane_helper_funcs.begin_fb_access hook for
+ * more details.
+ */
+ int (*begin_fb_access)(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *new_plane_state);
+
+ /**
+ * @end_fb_access:
+ *
+ * Optional, called by &drm_plane_helper_funcs.end_fb_access. Please read
+ * the documentation for the &drm_plane_helper_funcs.end_fb_access hook for
+ * more details.
+ */
+ void (*end_fb_access)(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state);
+
+ /**
* @enable_vblank:
*
* Optional, called by &drm_crtc_funcs.enable_vblank. Please read
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 2ae4fd62e01c..ca857ec9e7eb 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -41,6 +41,8 @@
*/
#define DRM_SCHED_FENCE_DONT_PIPELINE DMA_FENCE_FLAG_USER_BITS
+enum dma_resv_usage;
+struct dma_resv;
struct drm_gem_object;
struct drm_gpu_scheduler;
@@ -59,6 +61,12 @@ enum drm_sched_priority {
DRM_SCHED_PRIORITY_UNSET = -2
};
+/* Used to chose between FIFO and RR jobs scheduling */
+extern int drm_sched_policy;
+
+#define DRM_SCHED_POLICY_RR 0
+#define DRM_SCHED_POLICY_FIFO 1
+
/**
* struct drm_sched_entity - A wrapper around a job queue (typically
* attached to the DRM file_priv).
@@ -205,6 +213,21 @@ struct drm_sched_entity {
* drm_sched_entity_fini().
*/
struct completion entity_idle;
+
+ /**
+ * @oldest_job_waiting:
+ *
+ * Marks earliest job waiting in SW queue
+ */
+ ktime_t oldest_job_waiting;
+
+ /**
+ * @rb_tree_node:
+ *
+ * The node used to insert this entity into time based priority queue
+ */
+ struct rb_node rb_tree_node;
+
};
/**
@@ -214,6 +237,7 @@ struct drm_sched_entity {
* @sched: the scheduler to which this rq belongs to.
* @entities: list of the entities to be scheduled.
* @current_entity: the entity which is to be scheduled.
+ * @rb_tree_root: root of time based priory queue of entities for FIFO scheduling
*
* Run queue is a set of entities scheduling command submissions for
* one specific ring. It implements the scheduling policy that selects
@@ -224,6 +248,7 @@ struct drm_sched_rq {
struct drm_gpu_scheduler *sched;
struct list_head entities;
struct drm_sched_entity *current_entity;
+ struct rb_root_cached rb_tree_root;
};
/**
@@ -304,7 +329,7 @@ struct drm_sched_job {
*/
union {
struct dma_fence_cb finish_cb;
- struct work_struct work;
+ struct work_struct work;
};
uint64_t id;
@@ -323,6 +348,13 @@ struct drm_sched_job {
/** @last_dependency: tracks @dependencies as they signal */
unsigned long last_dependency;
+
+ /**
+ * @submit_ts:
+ *
+ * When the job was pushed into the entity queue.
+ */
+ ktime_t submit_ts;
};
static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job,
@@ -345,18 +377,17 @@ enum drm_gpu_sched_stat {
*/
struct drm_sched_backend_ops {
/**
- * @dependency:
+ * @prepare_job:
*
* Called when the scheduler is considering scheduling this job next, to
* get another struct dma_fence for this job to block on. Once it
* returns NULL, run_job() may be called.
*
- * If a driver exclusively uses drm_sched_job_add_dependency() and
- * drm_sched_job_add_implicit_dependencies() this can be ommitted and
- * left as NULL.
+ * Can be NULL if no additional preparation to the dependencies are
+ * necessary. Skipped when jobs are killed instead of run.
*/
- struct dma_fence *(*dependency)(struct drm_sched_job *sched_job,
- struct drm_sched_entity *s_entity);
+ struct dma_fence *(*prepare_job)(struct drm_sched_job *sched_job,
+ struct drm_sched_entity *s_entity);
/**
* @run_job: Called to execute the job once all of the dependencies
@@ -484,6 +515,9 @@ int drm_sched_job_init(struct drm_sched_job *job,
void drm_sched_job_arm(struct drm_sched_job *job);
int drm_sched_job_add_dependency(struct drm_sched_job *job,
struct dma_fence *fence);
+int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job,
+ struct dma_resv *resv,
+ enum dma_resv_usage usage);
int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
struct drm_gem_object *obj,
bool write);
@@ -498,7 +532,6 @@ void drm_sched_wakeup(struct drm_gpu_scheduler *sched);
void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad);
void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery);
void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched);
-void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max);
void drm_sched_increase_karma(struct drm_sched_job *bad);
void drm_sched_reset_karma(struct drm_sched_job *bad);
void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type);
@@ -512,6 +545,8 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq,
void drm_sched_rq_remove_entity(struct drm_sched_rq *rq,
struct drm_sched_entity *entity);
+void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts);
+
int drm_sched_entity_init(struct drm_sched_entity *entity,
enum drm_sched_priority priority,
struct drm_gpu_scheduler **sched_list,
diff --git a/include/drm/i915_pxp_tee_interface.h b/include/drm/i915_pxp_tee_interface.h
index af593ec64469..a702b6ec17f7 100644
--- a/include/drm/i915_pxp_tee_interface.h
+++ b/include/drm/i915_pxp_tee_interface.h
@@ -8,6 +8,7 @@
#include <linux/mutex.h>
#include <linux/device.h>
+struct scatterlist;
/**
* struct i915_pxp_component_ops - ops for PXP services.
@@ -23,6 +24,10 @@ struct i915_pxp_component_ops {
int (*send)(struct device *dev, const void *message, size_t size);
int (*recv)(struct device *dev, void *buffer, size_t size);
+ ssize_t (*gsc_command)(struct device *dev, u8 client_id, u32 fence_id,
+ struct scatterlist *sg_in, size_t total_in_len,
+ struct scatterlist *sg_out);
+
};
/**
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
index 5afc6d664fde..78a226eba953 100644
--- a/include/drm/ttm/ttm_resource.h
+++ b/include/drm/ttm/ttm_resource.h
@@ -197,7 +197,7 @@ struct ttm_bus_placement {
* struct ttm_resource
*
* @start: Start of the allocation.
- * @num_pages: Actual size of resource in pages.
+ * @size: Actual size of resource in bytes.
* @mem_type: Resource type of the allocation.
* @placement: Placement flags.
* @bus: Placement on io bus accessible to the CPU
@@ -208,7 +208,7 @@ struct ttm_bus_placement {
*/
struct ttm_resource {
unsigned long start;
- unsigned long num_pages;
+ size_t size;
uint32_t mem_type;
uint32_t placement;
struct ttm_bus_placement bus;
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index 17a0310e8aaa..b7d3f3843f1e 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -88,7 +88,7 @@ struct ttm_tt {
#define TTM_TT_FLAG_EXTERNAL (1 << 2)
#define TTM_TT_FLAG_EXTERNAL_MAPPABLE (1 << 3)
-#define TTM_TT_FLAG_PRIV_POPULATED (1 << 31)
+#define TTM_TT_FLAG_PRIV_POPULATED (1U << 31)
uint32_t page_flags;
/** @num_pages: Number of pages in the page array. */
uint32_t num_pages;
diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h
new file mode 100644
index 000000000000..f7aef3f310d7
--- /dev/null
+++ b/include/dt-bindings/arm/qcom,ids.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org> based on previous work of Kumar Gala.
+ */
+#ifndef _DT_BINDINGS_ARM_QCOM_IDS_H
+#define _DT_BINDINGS_ARM_QCOM_IDS_H
+
+/*
+ * The MSM chipset and hardware revision used by Qualcomm bootloaders, DTS for
+ * older chipsets (qcom,msm-id) and in socinfo driver:
+ */
+#define QCOM_ID_MSM8960 87
+#define QCOM_ID_APQ8064 109
+#define QCOM_ID_MSM8660A 122
+#define QCOM_ID_MSM8260A 123
+#define QCOM_ID_APQ8060A 124
+#define QCOM_ID_MSM8974 126
+#define QCOM_ID_MPQ8064 130
+#define QCOM_ID_MSM8960AB 138
+#define QCOM_ID_APQ8060AB 139
+#define QCOM_ID_MSM8260AB 140
+#define QCOM_ID_MSM8660AB 141
+#define QCOM_ID_MSM8626 145
+#define QCOM_ID_MSM8610 147
+#define QCOM_ID_APQ8064AB 153
+#define QCOM_ID_MSM8226 158
+#define QCOM_ID_MSM8526 159
+#define QCOM_ID_MSM8110 161
+#define QCOM_ID_MSM8210 162
+#define QCOM_ID_MSM8810 163
+#define QCOM_ID_MSM8212 164
+#define QCOM_ID_MSM8612 165
+#define QCOM_ID_MSM8112 166
+#define QCOM_ID_MSM8225Q 168
+#define QCOM_ID_MSM8625Q 169
+#define QCOM_ID_MSM8125Q 170
+#define QCOM_ID_APQ8064AA 172
+#define QCOM_ID_APQ8084 178
+#define QCOM_ID_APQ8074 184
+#define QCOM_ID_MSM8274 185
+#define QCOM_ID_MSM8674 186
+#define QCOM_ID_MSM8974PRO_AC 194
+#define QCOM_ID_MSM8126 198
+#define QCOM_ID_APQ8026 199
+#define QCOM_ID_MSM8926 200
+#define QCOM_ID_MSM8326 205
+#define QCOM_ID_MSM8916 206
+#define QCOM_ID_MSM8994 207
+#define QCOM_ID_APQ8074PRO_AA 208
+#define QCOM_ID_APQ8074PRO_AB 209
+#define QCOM_ID_APQ8074PRO_AC 210
+#define QCOM_ID_MSM8274PRO_AA 211
+#define QCOM_ID_MSM8274PRO_AB 212
+#define QCOM_ID_MSM8274PRO_AC 213
+#define QCOM_ID_MSM8674PRO_AA 214
+#define QCOM_ID_MSM8674PRO_AB 215
+#define QCOM_ID_MSM8674PRO_AC 216
+#define QCOM_ID_MSM8974PRO_AA 217
+#define QCOM_ID_MSM8974PRO_AB 218
+#define QCOM_ID_APQ8028 219
+#define QCOM_ID_MSM8128 220
+#define QCOM_ID_MSM8228 221
+#define QCOM_ID_MSM8528 222
+#define QCOM_ID_MSM8628 223
+#define QCOM_ID_MSM8928 224
+#define QCOM_ID_MSM8510 225
+#define QCOM_ID_MSM8512 226
+#define QCOM_ID_MSM8936 233
+#define QCOM_ID_MSM8939 239
+#define QCOM_ID_APQ8036 240
+#define QCOM_ID_APQ8039 241
+#define QCOM_ID_MSM8996 246
+#define QCOM_ID_APQ8016 247
+#define QCOM_ID_MSM8216 248
+#define QCOM_ID_MSM8116 249
+#define QCOM_ID_MSM8616 250
+#define QCOM_ID_MSM8992 251
+#define QCOM_ID_APQ8094 253
+#define QCOM_ID_MSM8956 266
+#define QCOM_ID_MSM8976 278
+#define QCOM_ID_MDM9607 290
+#define QCOM_ID_APQ8096 291
+#define QCOM_ID_MSM8998 292
+#define QCOM_ID_MSM8953 293
+#define QCOM_ID_MDM8207 296
+#define QCOM_ID_MDM9207 297
+#define QCOM_ID_MDM9307 298
+#define QCOM_ID_MDM9628 299
+#define QCOM_ID_APQ8053 304
+#define QCOM_ID_MSM8996SG 305
+#define QCOM_ID_MSM8996AU 310
+#define QCOM_ID_APQ8096AU 311
+#define QCOM_ID_APQ8096SG 312
+#define QCOM_ID_SDM660 317
+#define QCOM_ID_SDM630 318
+#define QCOM_ID_APQ8098 319
+#define QCOM_ID_SDM845 321
+#define QCOM_ID_MDM9206 322
+#define QCOM_ID_IPQ8074 323
+#define QCOM_ID_SDA660 324
+#define QCOM_ID_SDM658 325
+#define QCOM_ID_SDA658 326
+#define QCOM_ID_SDA630 327
+#define QCOM_ID_SDM450 338
+#define QCOM_ID_SM8150 339
+#define QCOM_ID_SDA845 341
+#define QCOM_ID_IPQ8072 342
+#define QCOM_ID_IPQ8076 343
+#define QCOM_ID_IPQ8078 344
+#define QCOM_ID_SDM636 345
+#define QCOM_ID_SDA636 346
+#define QCOM_ID_SDM632 349
+#define QCOM_ID_SDA632 350
+#define QCOM_ID_SDA450 351
+#define QCOM_ID_SM8250 356
+#define QCOM_ID_SA8155 362
+#define QCOM_ID_IPQ8070 375
+#define QCOM_ID_IPQ8071 376
+#define QCOM_ID_IPQ8072A 389
+#define QCOM_ID_IPQ8074A 390
+#define QCOM_ID_IPQ8076A 391
+#define QCOM_ID_IPQ8078A 392
+#define QCOM_ID_SM6125 394
+#define QCOM_ID_IPQ8070A 395
+#define QCOM_ID_IPQ8071A 396
+#define QCOM_ID_IPQ6018 402
+#define QCOM_ID_IPQ6028 403
+#define QCOM_ID_SM4250 417
+#define QCOM_ID_IPQ6000 421
+#define QCOM_ID_IPQ6010 422
+#define QCOM_ID_SC7180 425
+#define QCOM_ID_SM6350 434
+#define QCOM_ID_SM8350 439
+#define QCOM_ID_SM6115 444
+#define QCOM_ID_SC8280XP 449
+#define QCOM_ID_IPQ6005 453
+#define QCOM_ID_QRB5165 455
+#define QCOM_ID_SM8450 457
+#define QCOM_ID_SM7225 459
+#define QCOM_ID_SA8295P 460
+#define QCOM_ID_SA8540P 461
+#define QCOM_ID_QCM4290 469
+#define QCOM_ID_QCS4290 470
+#define QCOM_ID_SM8450_2 480
+#define QCOM_ID_SM8450_3 482
+#define QCOM_ID_SC7280 487
+#define QCOM_ID_SC7180P 495
+#define QCOM_ID_SM6375 507
+#define QCOM_ID_SM8550 519
+#define QCOM_ID_QRU1000 539
+#define QCOM_ID_QDU1000 545
+#define QCOM_ID_QDU1010 587
+#define QCOM_ID_QRU1032 588
+#define QCOM_ID_QRU1052 589
+#define QCOM_ID_QRU1062 590
+
+/*
+ * The board type and revision information, used by Qualcomm bootloaders and
+ * DTS for older chipsets (qcom,board-id):
+ */
+#define QCOM_BOARD_ID(a, major, minor) \
+ (((major & 0xff) << 16) | ((minor & 0xff) << 8) | QCOM_BOARD_ID_##a)
+
+#define QCOM_BOARD_ID_MTP 8
+#define QCOM_BOARD_ID_DRAGONBOARD 10
+#define QCOM_BOARD_ID_SBC 24
+
+#endif /* _DT_BINDINGS_ARM_QCOM_IDS_H */
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
index 44e0a319f077..39169d94a44e 100644
--- a/include/dt-bindings/clock/rk3399-cru.h
+++ b/include/dt-bindings/clock/rk3399-cru.h
@@ -547,8 +547,8 @@
#define SRST_H_PERILP0 171
#define SRST_H_PERILP0_NOC 172
#define SRST_ROM 173
-#define SRST_CRYPTO_S 174
-#define SRST_CRYPTO_M 175
+#define SRST_CRYPTO0_S 174
+#define SRST_CRYPTO0_M 175
/* cru_softrst_con11 */
#define SRST_P_DCF 176
@@ -556,7 +556,7 @@
#define SRST_CM0S 178
#define SRST_CM0S_DBG 179
#define SRST_CM0S_PO 180
-#define SRST_CRYPTO 181
+#define SRST_CRYPTO0 181
#define SRST_P_PERILP1_SGRF 182
#define SRST_P_PERILP1_GRF 183
#define SRST_CRYPTO1_S 184
diff --git a/include/dt-bindings/clock/tegra234-clock.h b/include/dt-bindings/clock/tegra234-clock.h
index 173364a93381..c360455d02ee 100644
--- a/include/dt-bindings/clock/tegra234-clock.h
+++ b/include/dt-bindings/clock/tegra234-clock.h
@@ -9,6 +9,12 @@
* @defgroup bpmp_clock_ids Clock ID's
* @{
*/
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON */
+#define TEGRA234_CLK_ACTMON 1U
+/** @brief output of gate CLK_ENB_ADSP */
+#define TEGRA234_CLK_ADSP 2U
+/** @brief output of gate CLK_ENB_ADSPNEON */
+#define TEGRA234_CLK_ADSPNEON 3U
/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AHUB */
#define TEGRA234_CLK_AHUB 4U
/** @brief output of gate CLK_ENB_APB2APE */
@@ -17,6 +23,18 @@
#define TEGRA234_CLK_APE 6U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AUD_MCLK */
#define TEGRA234_CLK_AUD_MCLK 7U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AXI_CBB */
+#define TEGRA234_CLK_AXI_CBB 8U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN1 */
+#define TEGRA234_CLK_CAN1 9U
+/** @brief output of gate CLK_ENB_CAN1_HOST */
+#define TEGRA234_CLK_CAN1_HOST 10U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN2 */
+#define TEGRA234_CLK_CAN2 11U
+/** @brief output of gate CLK_ENB_CAN2_HOST */
+#define TEGRA234_CLK_CAN2_HOST 12U
+/** @brief output of divider CLK_RST_CONTROLLER_CLK_M_DIVIDE */
+#define TEGRA234_CLK_CLK_M 14U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC1 */
#define TEGRA234_CLK_DMIC1 15U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC2 */
@@ -25,6 +43,28 @@
#define TEGRA234_CLK_DMIC3 17U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC4 */
#define TEGRA234_CLK_DMIC4 18U
+/** @brief output of gate CLK_ENB_DPAUX */
+#define TEGRA234_CLK_DPAUX 19U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG1 */
+#define TEGRA234_CLK_NVJPG1 20U
+/**
+ * @brief output of mux controlled by CLK_RST_CONTROLLER_ACLK_BURST_POLICY
+ * divided by the divider controlled by ACLK_CLK_DIVISOR in
+ * CLK_RST_CONTROLLER_SUPER_ACLK_DIVIDER
+ */
+#define TEGRA234_CLK_ACLK 21U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_MSS_ENCRYPT switch divider output */
+#define TEGRA234_CLK_MSS_ENCRYPT 22U
+/** @brief clock recovered from EAVB input */
+#define TEGRA234_CLK_EQOS_RX_INPUT 23U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_AON_APB switch divider output */
+#define TEGRA234_CLK_AON_APB 25U
+/** @brief CLK_RST_CONTROLLER_AON_NIC_RATE divider output */
+#define TEGRA234_CLK_AON_NIC 26U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_AON_CPU_NIC switch divider output */
+#define TEGRA234_CLK_AON_CPU_NIC 27U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLA1_BASE for use by audio clocks */
+#define TEGRA234_CLK_PLLA1 28U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK1 */
#define TEGRA234_CLK_DSPK1 29U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK2 */
@@ -38,10 +78,33 @@
* throughput and memory controller power.
*/
#define TEGRA234_CLK_EMC 31U
-/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X */
-#define TEGRA234_CLK_HOST1X 46U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_AXI_CLK_0 divider gated output */
+#define TEGRA234_CLK_EQOS_AXI 32U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_PTP_REF_CLK_0 divider gated output */
+#define TEGRA234_CLK_EQOS_PTP_REF 33U
+/** @brief output of gate CLK_ENB_EQOS_RX */
+#define TEGRA234_CLK_EQOS_RX 34U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_TX_CLK divider gated output */
+#define TEGRA234_CLK_EQOS_TX 35U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 */
+#define TEGRA234_CLK_EXTPERIPH1 36U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 */
+#define TEGRA234_CLK_EXTPERIPH2 37U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH3 */
+#define TEGRA234_CLK_EXTPERIPH3 38U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH4 */
+#define TEGRA234_CLK_EXTPERIPH4 39U
/** @brief output of gate CLK_ENB_FUSE */
#define TEGRA234_CLK_FUSE 40U
+/** @brief output of GPU GPC0 clkGen (in 1x mode same rate as GPC0 MUX2 out) */
+#define TEGRA234_CLK_GPC0CLK 41U
+/** @brief TODO */
+#define TEGRA234_CLK_GPU_PWR 42U
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HDA2CODEC_2X */
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X */
+#define TEGRA234_CLK_HOST1X 46U
+/** @brief xusb_hs_hsicp_clk */
+#define TEGRA234_CLK_XUSB_HS_HSICP 47U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 */
#define TEGRA234_CLK_I2C1 48U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 */
@@ -82,10 +145,66 @@
#define TEGRA234_CLK_I2S6 66U
/** @brief clock recovered from I2S6 input */
#define TEGRA234_CLK_I2S6_SYNC_INPUT 67U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_ISP */
+#define TEGRA234_CLK_ISP 69U
+/** @brief Monitored branch of EQOS_RX clock */
+#define TEGRA234_CLK_EQOS_RX_M 70U
+/** @brief CLK_RST_CONTROLLER_MAUDCLK_OUT_SWITCH_DIVIDER switch divider output (maudclk) */
+#define TEGRA234_CLK_MAUD 71U
+/** @brief output of gate CLK_ENB_MIPI_CAL */
+#define TEGRA234_CLK_MIPI_CAL 72U
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_CORE_PLL_FIXED */
+#define TEGRA234_CLK_MPHY_CORE_PLL_FIXED 73U
+/** @brief output of gate CLK_ENB_MPHY_L0_RX_ANA */
+#define TEGRA234_CLK_MPHY_L0_RX_ANA 74U
+/** @brief output of gate CLK_ENB_MPHY_L0_RX_LS_BIT */
+#define TEGRA234_CLK_MPHY_L0_RX_LS_BIT 75U
+/** @brief output of gate CLK_ENB_MPHY_L0_RX_SYMB */
+#define TEGRA234_CLK_MPHY_L0_RX_SYMB 76U
+/** @brief output of gate CLK_ENB_MPHY_L0_TX_LS_3XBIT */
+#define TEGRA234_CLK_MPHY_L0_TX_LS_3XBIT 77U
+/** @brief output of gate CLK_ENB_MPHY_L0_TX_SYMB */
+#define TEGRA234_CLK_MPHY_L0_TX_SYMB 78U
+/** @brief output of gate CLK_ENB_MPHY_L1_RX_ANA */
+#define TEGRA234_CLK_MPHY_L1_RX_ANA 79U
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_TX_1MHZ_REF */
+#define TEGRA234_CLK_MPHY_TX_1MHZ_REF 80U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSI */
+#define TEGRA234_CLK_NVCSI 81U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSILP */
+#define TEGRA234_CLK_NVCSILP 82U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC */
+#define TEGRA234_CLK_NVDEC 83U
+/** @brief CLK_RST_CONTROLLER_HUBCLK_OUT_SWITCH_DIVIDER switch divider output (hubclk) */
+#define TEGRA234_CLK_HUB 84U
+/** @brief CLK_RST_CONTROLLER_DISPCLK_SWITCH_DIVIDER switch divider output (dispclk) */
+#define TEGRA234_CLK_DISP 85U
+/** @brief RG_CLK_CTRL__0_DIV divider output (nvdisplay_p0_clk) */
+#define TEGRA234_CLK_NVDISPLAY_P0 86U
+/** @brief RG_CLK_CTRL__1_DIV divider output (nvdisplay_p1_clk) */
+#define TEGRA234_CLK_NVDISPLAY_P1 87U
+/** @brief DSC_CLK (DISPCLK ÷ 3) */
+#define TEGRA234_CLK_DSC 88U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVENC */
+#define TEGRA234_CLK_NVENC 89U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG */
+#define TEGRA234_CLK_NVJPG 90U
+/** @brief input from Tegra's XTAL_IN */
+#define TEGRA234_CLK_OSC 91U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_AON_TOUCH switch divider output */
+#define TEGRA234_CLK_AON_TOUCH 92U
/** PLL controlled by CLK_RST_CONTROLLER_PLLA_BASE for use by audio clocks */
#define TEGRA234_CLK_PLLA 93U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLAON_BASE for use by IP blocks in the AON domain */
+#define TEGRA234_CLK_PLLAON 94U
+/** Fixed 100MHz PLL for PCIe, SATA and superspeed USB */
+#define TEGRA234_CLK_PLLE 100U
+/** @brief PLLP vco output */
+#define TEGRA234_CLK_PLLP 101U
/** @brief PLLP clk output */
#define TEGRA234_CLK_PLLP_OUT0 102U
+/** Fixed frequency 960MHz PLL for USB and EAVB */
+#define TEGRA234_CLK_UTMIP_PLL 103U
/** @brief output of the divider CLK_RST_CONTROLLER_PLLA_OUT */
#define TEGRA234_CLK_PLLA_OUT0 104U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM1 */
@@ -104,8 +223,50 @@
#define TEGRA234_CLK_PWM7 111U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM8 */
#define TEGRA234_CLK_PWM8 112U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_RCE_CPU_NIC output */
+#define TEGRA234_CLK_RCE_CPU_NIC 113U
+/** @brief CLK_RST_CONTROLLER_RCE_NIC_RATE divider output */
+#define TEGRA234_CLK_RCE_NIC 114U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_AON_I2C_SLOW switch divider output */
+#define TEGRA234_CLK_AON_I2C_SLOW 117U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SCE_CPU_NIC */
+#define TEGRA234_CLK_SCE_CPU_NIC 118U
+/** @brief output of divider CLK_RST_CONTROLLER_SCE_NIC_RATE */
+#define TEGRA234_CLK_SCE_NIC 119U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 */
+#define TEGRA234_CLK_SDMMC1 120U
+/** @brief Logical clk for setting the UPHY PLL3 rate */
+#define TEGRA234_CLK_UPHY_PLL3 121U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 */
#define TEGRA234_CLK_SDMMC4 123U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SE switch divider gated output */
+#define TEGRA234_CLK_SE 124U
+/** @brief VPLL select for sor0_ref clk driven by disp_2clk_sor0_head_sel signal */
+#define TEGRA234_CLK_SOR0_PLL_REF 125U
+/** @brief Output of mux controlled by disp_2clk_sor0_pll_ref_clk_safe signal (sor0_ref_clk) */
+#define TEGRA234_CLK_SOR0_REF 126U
+/** @brief VPLL select for sor1_ref clk driven by disp_2clk_sor0_head_sel signal */
+#define TEGRA234_CLK_SOR1_PLL_REF 127U
+/** @brief SOR_PLL_REF_CLK_CTRL__0_DIV divider output */
+#define TEGRA234_CLK_PRE_SOR0_REF 128U
+/** @brief Output of mux controlled by disp_2clk_sor1_pll_ref_clk_safe signal (sor1_ref_clk) */
+#define TEGRA234_CLK_SOR1_REF 129U
+/** @brief SOR_PLL_REF_CLK_CTRL__1_DIV divider output */
+#define TEGRA234_CLK_PRE_SOR1_REF 130U
+/** @brief output of gate CLK_ENB_SOR_SAFE */
+#define TEGRA234_CLK_SOR_SAFE 131U
+/** @brief SOR_CLK_CTRL__0_DIV divider output */
+#define TEGRA234_CLK_SOR0_DIV 132U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC5 */
+#define TEGRA234_CLK_DMIC5 134U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI1 */
+#define TEGRA234_CLK_SPI1 135U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI2 */
+#define TEGRA234_CLK_SPI2 136U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI3 */
+#define TEGRA234_CLK_SPI3 137U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C_SLOW */
+#define TEGRA234_CLK_I2C_SLOW 138U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC1 */
#define TEGRA234_CLK_SYNC_DMIC1 139U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC2 */
@@ -130,28 +291,132 @@
#define TEGRA234_CLK_SYNC_I2S5 149U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S6 */
#define TEGRA234_CLK_SYNC_I2S6 150U
+/** @brief controls MPHY_FORCE_LS_MODE upon enable & disable */
+#define TEGRA234_CLK_MPHY_FORCE_LS_MODE 151U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TACH0 */
+#define TEGRA234_CLK_TACH0 152U
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSEC */
+#define TEGRA234_CLK_TSEC 153U
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PKA */
+#define TEGRA234_CLK_TSEC_PKA 154U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTA */
#define TEGRA234_CLK_UARTA 155U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTB */
+#define TEGRA234_CLK_UARTB 156U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTC */
+#define TEGRA234_CLK_UARTC 157U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTD */
+#define TEGRA234_CLK_UARTD 158U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTE */
+#define TEGRA234_CLK_UARTE 159U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTF */
+#define TEGRA234_CLK_UARTF 160U
/** @brief output of gate CLK_ENB_PEX1_CORE_6 */
#define TEGRA234_CLK_PEX1_C6_CORE 161U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL */
+#define TEGRA234_CLK_UART_FST_MIPI_CAL 162U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSDEV_REF */
+#define TEGRA234_CLK_UFSDEV_REF 163U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSHC_CG_SYS */
+#define TEGRA234_CLK_UFSHC 164U
+/** @brief output of gate CLK_ENB_USB2_TRK */
+#define TEGRA234_CLK_USB2_TRK 165U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VI */
+#define TEGRA234_CLK_VI 166U
/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VIC */
-#define TEGRA234_CLK_VIC 167U
+#define TEGRA234_CLK_VIC 167U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_CSITE switch divider output */
+#define TEGRA234_CLK_CSITE 168U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_IST switch divider output */
+#define TEGRA234_CLK_IST 169U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_IST_JTAG_REG_CLK_SEL */
+#define TEGRA234_CLK_JTAG_INTFC_PRE_CG 170U
/** @brief output of gate CLK_ENB_PEX2_CORE_7 */
#define TEGRA234_CLK_PEX2_C7_CORE 171U
/** @brief output of gate CLK_ENB_PEX2_CORE_8 */
#define TEGRA234_CLK_PEX2_C8_CORE 172U
/** @brief output of gate CLK_ENB_PEX2_CORE_9 */
#define TEGRA234_CLK_PEX2_C9_CORE 173U
+/** @brief dla0_falcon_clk */
+#define TEGRA234_CLK_DLA0_FALCON 174U
+/** @brief dla0_core_clk */
+#define TEGRA234_CLK_DLA0_CORE 175U
+/** @brief dla1_falcon_clk */
+#define TEGRA234_CLK_DLA1_FALCON 176U
+/** @brief dla1_core_clk */
+#define TEGRA234_CLK_DLA1_CORE 177U
+/** @brief Output of mux controlled by disp_2clk_sor0_clk_safe signal (sor0_clk) */
+#define TEGRA234_CLK_SOR0 178U
+/** @brief Output of mux controlled by disp_2clk_sor1_clk_safe signal (sor1_clk) */
+#define TEGRA234_CLK_SOR1 179U
+/** @brief DP macro feedback clock (same as LINKA_SYM CLKOUT) */
+#define TEGRA234_CLK_SOR_PAD_INPUT 180U
+/** @brief Output of mux controlled by disp_2clk_h0_dsi_sel signal in sf0_clk path */
+#define TEGRA234_CLK_PRE_SF0 181U
+/** @brief Output of mux controlled by disp_2clk_sf0_clk_safe signal (sf0_clk) */
+#define TEGRA234_CLK_SF0 182U
+/** @brief Output of mux controlled by disp_2clk_sf1_clk_safe signal (sf1_clk) */
+#define TEGRA234_CLK_SF1 183U
+/** @brief CLKOUT_AB output from DSI BRICK A (dsi_clkout_ab) */
+#define TEGRA234_CLK_DSI_PAD_INPUT 184U
/** @brief output of gate CLK_ENB_PEX2_CORE_10 */
#define TEGRA234_CLK_PEX2_C10_CORE 187U
-/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_QSPI0 switch divider output */
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_UARTI switch divider output (uarti_r_clk) */
+#define TEGRA234_CLK_UARTI 188U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_UARTJ switch divider output (uartj_r_clk) */
+#define TEGRA234_CLK_UARTJ 189U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_UARTH switch divider output */
+#define TEGRA234_CLK_UARTH 190U
+/** @brief ungated version of fuse clk */
+#define TEGRA234_CLK_FUSE_SERIAL 191U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_QSPI0 switch divider output (qspi0_2x_pm_clk) */
#define TEGRA234_CLK_QSPI0_2X_PM 192U
-/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_QSPI1 switch divider output */
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_QSPI1 switch divider output (qspi1_2x_pm_clk) */
#define TEGRA234_CLK_QSPI1_2X_PM 193U
-/** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI0 */
+/** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI0 (qspi0_pm_clk) */
#define TEGRA234_CLK_QSPI0_PM 194U
-/** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI1 */
+/** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI1 (qspi1_pm_clk) */
#define TEGRA234_CLK_QSPI1_PM 195U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_VI_CONST switch divider output */
+#define TEGRA234_CLK_VI_CONST 196U
+/** @brief NAFLL clock source for BPMP */
+#define TEGRA234_CLK_NAFLL_BPMP 197U
+/** @brief NAFLL clock source for SCE */
+#define TEGRA234_CLK_NAFLL_SCE 198U
+/** @brief NAFLL clock source for NVDEC */
+#define TEGRA234_CLK_NAFLL_NVDEC 199U
+/** @brief NAFLL clock source for NVJPG */
+#define TEGRA234_CLK_NAFLL_NVJPG 200U
+/** @brief NAFLL clock source for TSEC */
+#define TEGRA234_CLK_NAFLL_TSEC 201U
+/** @brief NAFLL clock source for VI */
+#define TEGRA234_CLK_NAFLL_VI 203U
+/** @brief NAFLL clock source for SE */
+#define TEGRA234_CLK_NAFLL_SE 204U
+/** @brief NAFLL clock source for NVENC */
+#define TEGRA234_CLK_NAFLL_NVENC 205U
+/** @brief NAFLL clock source for ISP */
+#define TEGRA234_CLK_NAFLL_ISP 206U
+/** @brief NAFLL clock source for VIC */
+#define TEGRA234_CLK_NAFLL_VIC 207U
+/** @brief NAFLL clock source for AXICBB */
+#define TEGRA234_CLK_NAFLL_AXICBB 209U
+/** @brief NAFLL clock source for NVJPG1 */
+#define TEGRA234_CLK_NAFLL_NVJPG1 210U
+/** @brief NAFLL clock source for PVA core */
+#define TEGRA234_CLK_NAFLL_PVA0_CORE 211U
+/** @brief NAFLL clock source for PVA VPS */
+#define TEGRA234_CLK_NAFLL_PVA0_VPS 212U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_DBGAPB_0 switch divider output (dbgapb_clk) */
+#define TEGRA234_CLK_DBGAPB 213U
+/** @brief NAFLL clock source for RCE */
+#define TEGRA234_CLK_NAFLL_RCE 214U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_LA switch divider output (la_r_clk) */
+#define TEGRA234_CLK_LA 215U
+/** @brief output of the divider CLK_RST_CONTROLLER_PLLP_OUTD */
+#define TEGRA234_CLK_PLLP_OUT_JTAG 216U
+/** @brief AXI_CBB branch sharing gate control with SDMMC4 */
+#define TEGRA234_CLK_SDMMC4_AXICIF 217U
/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM switch divider output */
#define TEGRA234_CLK_SDMMC_LEGACY_TM 219U
/** @brief output of gate CLK_ENB_PEX0_CORE_0 */
@@ -166,8 +431,42 @@
#define TEGRA234_CLK_PEX0_C4_CORE 224U
/** @brief output of gate CLK_ENB_PEX1_CORE_5 */
#define TEGRA234_CLK_PEX1_C5_CORE 225U
+/** @brief Monitored branch of PEX0_C0_CORE clock */
+#define TEGRA234_CLK_PEX0_C0_CORE_M 229U
+/** @brief Monitored branch of PEX0_C1_CORE clock */
+#define TEGRA234_CLK_PEX0_C1_CORE_M 230U
+/** @brief Monitored branch of PEX0_C2_CORE clock */
+#define TEGRA234_CLK_PEX0_C2_CORE_M 231U
+/** @brief Monitored branch of PEX0_C3_CORE clock */
+#define TEGRA234_CLK_PEX0_C3_CORE_M 232U
+/** @brief Monitored branch of PEX0_C4_CORE clock */
+#define TEGRA234_CLK_PEX0_C4_CORE_M 233U
+/** @brief Monitored branch of PEX1_C5_CORE clock */
+#define TEGRA234_CLK_PEX1_C5_CORE_M 234U
+/** @brief Monitored branch of PEX1_C6_CORE clock */
+#define TEGRA234_CLK_PEX1_C6_CORE_M 235U
+/** @brief output of GPU GPC1 clkGen (in 1x mode same rate as GPC1 MUX2 out) */
+#define TEGRA234_CLK_GPC1CLK 236U
/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */
#define TEGRA234_CLK_PLLC4 237U
+/** @brief PLLC4 VCO followed by DIV3 path */
+#define TEGRA234_CLK_PLLC4_OUT1 239U
+/** @brief PLLC4 VCO followed by DIV5 path */
+#define TEGRA234_CLK_PLLC4_OUT2 240U
+/** @brief output of the mux controlled by PLLC4_CLK_SEL */
+#define TEGRA234_CLK_PLLC4_MUXED 241U
+/** @brief PLLC4 VCO followed by DIV2 path */
+#define TEGRA234_CLK_PLLC4_VCO_DIV2 242U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLNVHS_BASE */
+#define TEGRA234_CLK_PLLNVHS 243U
+/** @brief Monitored branch of PEX2_C7_CORE clock */
+#define TEGRA234_CLK_PEX2_C7_CORE_M 244U
+/** @brief Monitored branch of PEX2_C8_CORE clock */
+#define TEGRA234_CLK_PEX2_C8_CORE_M 245U
+/** @brief Monitored branch of PEX2_C9_CORE clock */
+#define TEGRA234_CLK_PEX2_C9_CORE_M 246U
+/** @brief Monitored branch of PEX2_C10_CORE clock */
+#define TEGRA234_CLK_PEX2_C10_CORE_M 247U
/** @brief RX clock recovered from MGBE0 lane input */
#define TEGRA234_CLK_MGBE0_RX_INPUT 248U
/** @brief RX clock recovered from MGBE1 lane input */
@@ -176,8 +475,185 @@
#define TEGRA234_CLK_MGBE2_RX_INPUT 250U
/** @brief RX clock recovered from MGBE3 lane input */
#define TEGRA234_CLK_MGBE3_RX_INPUT 251U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PEX_SATA_USB_RX_BYP switch divider output */
+#define TEGRA234_CLK_PEX_SATA_USB_RX_BYP 254U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL0_MGMT switch divider output */
+#define TEGRA234_CLK_PEX_USB_PAD_PLL0_MGMT 255U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL1_MGMT switch divider output */
+#define TEGRA234_CLK_PEX_USB_PAD_PLL1_MGMT 256U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL2_MGMT switch divider output */
+#define TEGRA234_CLK_PEX_USB_PAD_PLL2_MGMT 257U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL3_MGMT switch divider output */
+#define TEGRA234_CLK_PEX_USB_PAD_PLL3_MGMT 258U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_NVHS_RX_BYP switch divider output */
+#define TEGRA234_CLK_NVHS_RX_BYP_REF 263U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_NVHS_PLL0_MGMT switch divider output */
+#define TEGRA234_CLK_NVHS_PLL0_MGMT 264U
+/** @brief xusb_core_dev_clk */
+#define TEGRA234_CLK_XUSB_CORE_DEV 265U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_HOST switch divider output */
+#define TEGRA234_CLK_XUSB_CORE_MUX 266U
+/** @brief xusb_core_host_clk */
+#define TEGRA234_CLK_XUSB_CORE_HOST 267U
+/** @brief xusb_core_superspeed_clk */
+#define TEGRA234_CLK_XUSB_CORE_SS 268U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FALCON switch divider output */
+#define TEGRA234_CLK_XUSB_FALCON 269U
+/** @brief xusb_falcon_host_clk */
+#define TEGRA234_CLK_XUSB_FALCON_HOST 270U
+/** @brief xusb_falcon_superspeed_clk */
+#define TEGRA234_CLK_XUSB_FALCON_SS 271U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS switch divider output */
+#define TEGRA234_CLK_XUSB_FS 272U
+/** @brief xusb_fs_host_clk */
+#define TEGRA234_CLK_XUSB_FS_HOST 273U
+/** @brief xusb_fs_dev_clk */
+#define TEGRA234_CLK_XUSB_FS_DEV 274U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS switch divider output */
+#define TEGRA234_CLK_XUSB_SS 275U
+/** @brief xusb_ss_dev_clk */
+#define TEGRA234_CLK_XUSB_SS_DEV 276U
+/** @brief xusb_ss_superspeed_clk */
+#define TEGRA234_CLK_XUSB_SS_SUPERSPEED 277U
+/** @brief NAFLL clock source for CPU cluster 0 */
+#define TEGRA234_CLK_NAFLL_CLUSTER0 280U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER0_CORE 280U
+/** @brief NAFLL clock source for CPU cluster 1 */
+#define TEGRA234_CLK_NAFLL_CLUSTER1 281U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER1_CORE 281U
+/** @brief NAFLL clock source for CPU cluster 2 */
+#define TEGRA234_CLK_NAFLL_CLUSTER2 282U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER2_CORE 282U
+/** @brief CLK_RST_CONTROLLER_CAN1_CORE_RATE divider output */
+#define TEGRA234_CLK_CAN1_CORE 284U
+/** @brief CLK_RST_CONTROLLER_CAN2_CORE_RATE divider outputt */
+#define TEGRA234_CLK_CAN2_CORE 285U
+/** @brief CLK_RST_CONTROLLER_PLLA1_OUT1 switch divider output */
+#define TEGRA234_CLK_PLLA1_OUT1 286U
+/** @brief NVHS PLL hardware power sequencer (overrides 'manual' programming of PLL) */
+#define TEGRA234_CLK_PLLNVHS_HPS 287U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLREFE_BASE */
+#define TEGRA234_CLK_PLLREFE_VCOOUT 288U
/** @brief 32K input clock provided by PMIC */
#define TEGRA234_CLK_CLK_32K 289U
+/** @brief Fixed 48MHz clock divided down from utmipll */
+#define TEGRA234_CLK_UTMIPLL_CLKOUT48 291U
+/** @brief Fixed 480MHz clock divided down from utmipll */
+#define TEGRA234_CLK_UTMIPLL_CLKOUT480 292U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLNVCSI_BASE */
+#define TEGRA234_CLK_PLLNVCSI 294U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PVA0_CPU_AXI switch divider output */
+#define TEGRA234_CLK_PVA0_CPU_AXI 295U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_PVA0_VPS switch divider output */
+#define TEGRA234_CLK_PVA0_VPS 297U
+/** @brief DLA0_CORE_NAFLL */
+#define TEGRA234_CLK_NAFLL_DLA0_CORE 299U
+/** @brief DLA0_FALCON_NAFLL */
+#define TEGRA234_CLK_NAFLL_DLA0_FALCON 300U
+/** @brief DLA1_CORE_NAFLL */
+#define TEGRA234_CLK_NAFLL_DLA1_CORE 301U
+/** @brief DLA1_FALCON_NAFLL */
+#define TEGRA234_CLK_NAFLL_DLA1_FALCON 302U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_UART_FST_MIPI_CAL */
+#define TEGRA234_CLK_AON_UART_FST_MIPI_CAL 303U
+/** @brief GPU system clock */
+#define TEGRA234_CLK_GPUSYS 304U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 */
+#define TEGRA234_CLK_I2C5 305U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SE switch divider free running clk */
+#define TEGRA234_CLK_FR_SE 306U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_BPMP_CPU_NIC switch divider output */
+#define TEGRA234_CLK_BPMP_CPU_NIC 307U
+/** @brief output of gate CLK_ENB_BPMP_CPU */
+#define TEGRA234_CLK_BPMP_CPU 308U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_TSC switch divider output */
+#define TEGRA234_CLK_TSC 309U
+/** @brief output of mem pll A sync mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EMC */
+#define TEGRA234_CLK_EMCSA_MPLL 310U
+/** @brief output of mem pll B sync mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EMCSB */
+#define TEGRA234_CLK_EMCSB_MPLL 311U
+/** @brief output of mem pll C sync mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EMCSC */
+#define TEGRA234_CLK_EMCSC_MPLL 312U
+/** @brief output of mem pll D sync mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EMCSD */
+#define TEGRA234_CLK_EMCSD_MPLL 313U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC_BASE */
+#define TEGRA234_CLK_PLLC 314U
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC2_BASE */
+#define TEGRA234_CLK_PLLC2 315U
+/** @brief CLK_RST_CONTROLLER_TSC_HS_SUPER_CLK_DIVIDER skip divider output */
+#define TEGRA234_CLK_TSC_REF 317U
+/** @brief Dummy clock to ensure minimum SoC voltage for fuse burning */
+#define TEGRA234_CLK_FUSE_BURN 318U
+/** @brief GBE PLL */
+#define TEGRA234_CLK_PLLGBE 319U
+/** @brief GBE PLL hardware power sequencer */
+#define TEGRA234_CLK_PLLGBE_HPS 320U
+/** @brief output of EMC CDB side A fixed (DIV4) divider */
+#define TEGRA234_CLK_EMCSA_EMC 321U
+/** @brief output of EMC CDB side B fixed (DIV4) divider */
+#define TEGRA234_CLK_EMCSB_EMC 322U
+/** @brief output of EMC CDB side C fixed (DIV4) divider */
+#define TEGRA234_CLK_EMCSC_EMC 323U
+/** @brief output of EMC CDB side D fixed (DIV4) divider */
+#define TEGRA234_CLK_EMCSD_EMC 324U
+/** @brief PLLE hardware power sequencer (overrides 'manual' programming of PLL) */
+#define TEGRA234_CLK_PLLE_HPS 326U
+/** @brief CLK_ENB_PLLREFE_OUT gate output */
+#define TEGRA234_CLK_PLLREFE_VCOOUT_GATED 327U
+/** @brief TEGRA234_CLK_SOR_SAFE clk source (PLLP_OUT0 divided by 17) */
+#define TEGRA234_CLK_PLLP_DIV17 328U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SOC_THERM switch divider output */
+#define TEGRA234_CLK_SOC_THERM 329U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_TSENSE switch divider output */
+#define TEGRA234_CLK_TSENSE 330U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SEU1 switch divider free running clk */
+#define TEGRA234_CLK_FR_SEU1 331U
+/** @brief NAFLL clock source for OFA */
+#define TEGRA234_CLK_NAFLL_OFA 333U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_OFA switch divider output */
+#define TEGRA234_CLK_OFA 334U
+/** @brief NAFLL clock source for SEU1 */
+#define TEGRA234_CLK_NAFLL_SEU1 335U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_SEU1 switch divider gated output */
+#define TEGRA234_CLK_SEU1 336U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI4 */
+#define TEGRA234_CLK_SPI4 337U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI5 */
+#define TEGRA234_CLK_SPI5 338U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DCE_CPU_NIC */
+#define TEGRA234_CLK_DCE_CPU_NIC 339U
+/** @brief output of divider CLK_RST_CONTROLLER_DCE_NIC_RATE */
+#define TEGRA234_CLK_DCE_NIC 340U
+/** @brief NAFLL clock source for DCE */
+#define TEGRA234_CLK_NAFLL_DCE 341U
+/** @brief Monitored branch of MPHY_L0_RX_ANA clock */
+#define TEGRA234_CLK_MPHY_L0_RX_ANA_M 342U
+/** @brief Monitored branch of MPHY_L1_RX_ANA clock */
+#define TEGRA234_CLK_MPHY_L1_RX_ANA_M 343U
+/** @brief ungated version of TX symbol clock after fixed 1/2 divider */
+#define TEGRA234_CLK_MPHY_L0_TX_PRE_SYMB 344U
+/** @brief output of divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_TX_LS_SYMB */
+#define TEGRA234_CLK_MPHY_L0_TX_LS_SYMB_DIV 345U
+/** @brief output of gate CLK_ENB_MPHY_L0_TX_2X_SYMB */
+#define TEGRA234_CLK_MPHY_L0_TX_2X_SYMB 346U
+/** @brief output of SW_MPHY_L0_TX_HS_SYMB divider in CLK_RST_CONTROLLER_MPHY_L0_TX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_TX_HS_SYMB_DIV 347U
+/** @brief output of SW_MPHY_L0_TX_LS_3XBIT divider in CLK_RST_CONTROLLER_MPHY_L0_TX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_TX_LS_3XBIT_DIV 348U
+/** @brief LS/HS divider mux SW_MPHY_L0_TX_LS_HS_SEL in CLK_RST_CONTROLLER_MPHY_L0_TX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_TX_MUX_SYMB_DIV 349U
+/** @brief Monitored branch of MPHY_L0_TX_SYMB clock */
+#define TEGRA234_CLK_MPHY_L0_TX_SYMB_M 350U
+/** @brief output of divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_RX_LS_SYMB */
+#define TEGRA234_CLK_MPHY_L0_RX_LS_SYMB_DIV 351U
+/** @brief output of SW_MPHY_L0_RX_HS_SYMB divider in CLK_RST_CONTROLLER_MPHY_L0_RX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_RX_HS_SYMB_DIV 352U
+/** @brief output of SW_MPHY_L0_RX_LS_BIT divider in CLK_RST_CONTROLLER_MPHY_L0_RX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_RX_LS_BIT_DIV 353U
+/** @brief LS/HS divider mux SW_MPHY_L0_RX_LS_HS_SEL in CLK_RST_CONTROLLER_MPHY_L0_RX_CLK_CTRL_0 */
+#define TEGRA234_CLK_MPHY_L0_RX_MUX_SYMB_DIV 354U
+/** @brief Monitored branch of MPHY_L0_RX_SYMB clock */
+#define TEGRA234_CLK_MPHY_L0_RX_SYMB_M 355U
/** @brief Monitored branch of MBGE0 RX input clock */
#define TEGRA234_CLK_MGBE0_RX_INPUT_M 357U
/** @brief Monitored branch of MBGE1 RX input clock */
@@ -194,6 +670,14 @@
#define TEGRA234_CLK_MGBE2_RX_PCS_M 363U
/** @brief Monitored branch of MGBE3 RX PCS mux output */
#define TEGRA234_CLK_MGBE3_RX_PCS_M 364U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TACH1 */
+#define TEGRA234_CLK_TACH1 365U
+/** @brief GBE_UPHY_MGBES_APP_CLK switch divider gated output */
+#define TEGRA234_CLK_MGBES_APP 366U
+/** @brief Logical clk for setting GBE UPHY PLL2 TX_REF rate */
+#define TEGRA234_CLK_UPHY_GBE_PLL2_TX_REF 367U
+/** @brief Logical clk for setting GBE UPHY PLL2 XDIG rate */
+#define TEGRA234_CLK_UPHY_GBE_PLL2_XDIG 368U
/** @brief RX PCS clock recovered from MGBE0 lane input */
#define TEGRA234_CLK_MGBE0_RX_PCS_INPUT 369U
/** @brief RX PCS clock recovered from MGBE1 lane input */
@@ -230,6 +714,8 @@
#define TEGRA234_CLK_MGBE1_MAC_DIVIDER 385U
/** @brief GBE_UPHY_MGBE1_MAC_CLK gate output */
#define TEGRA234_CLK_MGBE1_MAC 386U
+/** @brief GBE_UPHY_MGBE1_MACSEC_CLK gate output */
+#define TEGRA234_CLK_MGBE1_MACSEC 387U
/** @brief GBE_UPHY_MGBE1_EEE_PCS_CLK gate output */
#define TEGRA234_CLK_MGBE1_EEE_PCS 388U
/** @brief GBE_UPHY_MGBE1_APP_CLK gate output */
@@ -246,6 +732,8 @@
#define TEGRA234_CLK_MGBE2_MAC_DIVIDER 394U
/** @brief GBE_UPHY_MGBE2_MAC_CLK gate output */
#define TEGRA234_CLK_MGBE2_MAC 395U
+/** @brief GBE_UPHY_MGBE2_MACSEC_CLK gate output */
+#define TEGRA234_CLK_MGBE2_MACSEC 396U
/** @brief GBE_UPHY_MGBE2_EEE_PCS_CLK gate output */
#define TEGRA234_CLK_MGBE2_EEE_PCS 397U
/** @brief GBE_UPHY_MGBE2_APP_CLK gate output */
@@ -270,9 +758,146 @@
#define TEGRA234_CLK_MGBE3_APP 407U
/** @brief GBE_UPHY_MGBE3_PTP_REF_CLK divider gated output */
#define TEGRA234_CLK_MGBE3_PTP_REF 408U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_GBE_RX_BYP switch divider output */
+#define TEGRA234_CLK_GBE_RX_BYP_REF 409U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_GBE_PLL0_MGMT switch divider output */
+#define TEGRA234_CLK_GBE_PLL0_MGMT 410U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_GBE_PLL1_MGMT switch divider output */
+#define TEGRA234_CLK_GBE_PLL1_MGMT 411U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_GBE_PLL2_MGMT switch divider output */
+#define TEGRA234_CLK_GBE_PLL2_MGMT 412U
+/** @brief output of gate CLK_ENB_EQOS_MACSEC_RX */
+#define TEGRA234_CLK_EQOS_MACSEC_RX 413U
+/** @brief output of gate CLK_ENB_EQOS_MACSEC_TX */
+#define TEGRA234_CLK_EQOS_MACSEC_TX 414U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_TX_CLK divider ungated output */
+#define TEGRA234_CLK_EQOS_TX_DIVIDER 415U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_NVHS_PLL1_MGMT switch divider output */
+#define TEGRA234_CLK_NVHS_PLL1_MGMT 416U
+/** @brief CLK_RST_CONTROLLER_CLK_SOURCE_EMCHUB mux output */
+#define TEGRA234_CLK_EMCHUB 417U
+/** @brief clock recovered from I2S7 input */
+#define TEGRA234_CLK_I2S7_SYNC_INPUT 418U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S7 */
+#define TEGRA234_CLK_SYNC_I2S7 419U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S7 */
+#define TEGRA234_CLK_I2S7 420U
+/** @brief Monitored output of I2S7 pad macro mux */
+#define TEGRA234_CLK_I2S7_PAD_M 421U
+/** @brief clock recovered from I2S8 input */
+#define TEGRA234_CLK_I2S8_SYNC_INPUT 422U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S8 */
+#define TEGRA234_CLK_SYNC_I2S8 423U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S8 */
+#define TEGRA234_CLK_I2S8 424U
+/** @brief Monitored output of I2S8 pad macro mux */
+#define TEGRA234_CLK_I2S8_PAD_M 425U
+/** @brief NAFLL clock source for GPU GPC0 */
+#define TEGRA234_CLK_NAFLL_GPC0 426U
+/** @brief NAFLL clock source for GPU GPC1 */
+#define TEGRA234_CLK_NAFLL_GPC1 427U
+/** @brief NAFLL clock source for GPU SYSCLK */
+#define TEGRA234_CLK_NAFLL_GPUSYS 428U
+/** @brief NAFLL clock source for CPU cluster 0 DSUCLK */
+#define TEGRA234_CLK_NAFLL_DSU0 429U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER0_DSU 429U
+/** @brief NAFLL clock source for CPU cluster 1 DSUCLK */
+#define TEGRA234_CLK_NAFLL_DSU1 430U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER1_DSU 430U
+/** @brief NAFLL clock source for CPU cluster 2 DSUCLK */
+#define TEGRA234_CLK_NAFLL_DSU2 431U /* TODO: remove */
+#define TEGRA234_CLK_NAFLL_CLUSTER2_DSU 431U
+/** @brief output of gate CLK_ENB_SCE_CPU */
+#define TEGRA234_CLK_SCE_CPU 432U
+/** @brief output of gate CLK_ENB_RCE_CPU */
+#define TEGRA234_CLK_RCE_CPU 433U
+/** @brief output of gate CLK_ENB_DCE_CPU */
+#define TEGRA234_CLK_DCE_CPU 434U
+/** @brief DSIPLL VCO output */
+#define TEGRA234_CLK_DSIPLL_VCO 435U
+/** @brief DSIPLL SYNC_CLKOUTP/N differential output */
+#define TEGRA234_CLK_DSIPLL_CLKOUTPN 436U
+/** @brief DSIPLL SYNC_CLKOUTA output */
+#define TEGRA234_CLK_DSIPLL_CLKOUTA 437U
+/** @brief SPPLL0 VCO output */
+#define TEGRA234_CLK_SPPLL0_VCO 438U
+/** @brief SPPLL0 SYNC_CLKOUTP/N differential output */
+#define TEGRA234_CLK_SPPLL0_CLKOUTPN 439U
+/** @brief SPPLL0 SYNC_CLKOUTA output */
+#define TEGRA234_CLK_SPPLL0_CLKOUTA 440U
+/** @brief SPPLL0 SYNC_CLKOUTB output */
+#define TEGRA234_CLK_SPPLL0_CLKOUTB 441U
+/** @brief SPPLL0 CLKOUT_DIVBY10 output */
+#define TEGRA234_CLK_SPPLL0_DIV10 442U
+/** @brief SPPLL0 CLKOUT_DIVBY25 output */
+#define TEGRA234_CLK_SPPLL0_DIV25 443U
+/** @brief SPPLL0 CLKOUT_DIVBY27P/N differential output */
+#define TEGRA234_CLK_SPPLL0_DIV27PN 444U
+/** @brief SPPLL1 VCO output */
+#define TEGRA234_CLK_SPPLL1_VCO 445U
+/** @brief SPPLL1 SYNC_CLKOUTP/N differential output */
+#define TEGRA234_CLK_SPPLL1_CLKOUTPN 446U
+/** @brief SPPLL1 CLKOUT_DIVBY27P/N differential output */
+#define TEGRA234_CLK_SPPLL1_DIV27PN 447U
+/** @brief VPLL0 reference clock */
+#define TEGRA234_CLK_VPLL0_REF 448U
+/** @brief VPLL0 */
+#define TEGRA234_CLK_VPLL0 449U
+/** @brief VPLL1 */
+#define TEGRA234_CLK_VPLL1 450U
+/** @brief NVDISPLAY_P0_CLK reference select */
+#define TEGRA234_CLK_NVDISPLAY_P0_REF 451U
+/** @brief RG0_PCLK */
+#define TEGRA234_CLK_RG0 452U
+/** @brief RG1_PCLK */
+#define TEGRA234_CLK_RG1 453U
+/** @brief DISPPLL output */
+#define TEGRA234_CLK_DISPPLL 454U
+/** @brief DISPHUBPLL output */
+#define TEGRA234_CLK_DISPHUBPLL 455U
+/** @brief CLK_RST_CONTROLLER_DSI_LP_SWITCH_DIVIDER switch divider output (dsi_lp_clk) */
+#define TEGRA234_CLK_DSI_LP 456U
/** @brief CLK_RST_CONTROLLER_AZA2XBITCLK_OUT_SWITCH_DIVIDER switch divider output (aza_2xbitclk) */
#define TEGRA234_CLK_AZA_2XBIT 457U
/** @brief aza_2xbitclk / 2 (aza_bitclk) */
#define TEGRA234_CLK_AZA_BIT 458U
+/** @brief SWITCH_DSI_CORE_PIXEL_MISC_DSI_CORE_CLK_SRC switch output (dsi_core_clk) */
+#define TEGRA234_CLK_DSI_CORE 459U
+/** @brief Output of mux controlled by pkt_wr_fifo_signal from dsi (dsi_pixel_clk) */
+#define TEGRA234_CLK_DSI_PIXEL 460U
+/** @brief Output of mux controlled by disp_2clk_sor0_dp_sel (pre_sor0_clk) */
+#define TEGRA234_CLK_PRE_SOR0 461U
+/** @brief Output of mux controlled by disp_2clk_sor1_dp_sel (pre_sor1_clk) */
+#define TEGRA234_CLK_PRE_SOR1 462U
+/** @brief CLK_RST_CONTROLLER_LINK_REFCLK_CFG__0 output */
+#define TEGRA234_CLK_DP_LINK_REF 463U
+/** @brief Link clock input from DP macro brick PLL */
+#define TEGRA234_CLK_SOR_LINKA_INPUT 464U
+/** @brief SOR AFIFO clock outut */
+#define TEGRA234_CLK_SOR_LINKA_AFIFO 465U
+/** @brief Monitored branch of linka_afifo_clk */
+#define TEGRA234_CLK_SOR_LINKA_AFIFO_M 466U
+/** @brief Monitored branch of rg0_pclk */
+#define TEGRA234_CLK_RG0_M 467U
+/** @brief Monitored branch of rg1_pclk */
+#define TEGRA234_CLK_RG1_M 468U
+/** @brief Monitored branch of sor0_clk */
+#define TEGRA234_CLK_SOR0_M 469U
+/** @brief Monitored branch of sor1_clk */
+#define TEGRA234_CLK_SOR1_M 470U
+/** @brief EMC PLLHUB output */
+#define TEGRA234_CLK_PLLHUB 471U
+/** @brief output of fixed (DIV2) MC HUB divider */
+#define TEGRA234_CLK_MCHUB 472U
+/** @brief output of divider controlled by EMC side A MC_EMC_SAFE_SAME_FREQ */
+#define TEGRA234_CLK_EMCSA_MC 473U
+/** @brief output of divider controlled by EMC side B MC_EMC_SAFE_SAME_FREQ */
+#define TEGRA234_CLK_EMCSB_MC 474U
+/** @brief output of divider controlled by EMC side C MC_EMC_SAFE_SAME_FREQ */
+#define TEGRA234_CLK_EMCSC_MC 475U
+/** @brief output of divider controlled by EMC side D MC_EMC_SAFE_SAME_FREQ */
+#define TEGRA234_CLK_EMCSD_MC 476U
+
+/** @} */
#endif
diff --git a/include/dt-bindings/firmware/imx/rsrc.h b/include/dt-bindings/firmware/imx/rsrc.h
index 1675de05ad33..1a8c025d77b8 100644
--- a/include/dt-bindings/firmware/imx/rsrc.h
+++ b/include/dt-bindings/firmware/imx/rsrc.h
@@ -13,30 +13,30 @@
* never be changed or removed (only added to at the end of the list).
*/
-#define IMX_SC_R_A53 0
-#define IMX_SC_R_A53_0 1
-#define IMX_SC_R_A53_1 2
-#define IMX_SC_R_A53_2 3
-#define IMX_SC_R_A53_3 4
-#define IMX_SC_R_A72 5
-#define IMX_SC_R_A72_0 6
-#define IMX_SC_R_A72_1 7
-#define IMX_SC_R_A72_2 8
-#define IMX_SC_R_A72_3 9
+#define IMX_SC_R_AP_0 0
+#define IMX_SC_R_AP_0_0 1
+#define IMX_SC_R_AP_0_1 2
+#define IMX_SC_R_AP_0_2 3
+#define IMX_SC_R_AP_0_3 4
+#define IMX_SC_R_AP_1 5
+#define IMX_SC_R_AP_1_0 6
+#define IMX_SC_R_AP_1_1 7
+#define IMX_SC_R_AP_1_2 8
+#define IMX_SC_R_AP_1_3 9
#define IMX_SC_R_CCI 10
#define IMX_SC_R_DB 11
#define IMX_SC_R_DRC_0 12
#define IMX_SC_R_DRC_1 13
#define IMX_SC_R_GIC_SMMU 14
-#define IMX_SC_R_IRQSTR_M4_0 15
-#define IMX_SC_R_IRQSTR_M4_1 16
-#define IMX_SC_R_SMMU 17
-#define IMX_SC_R_GIC 18
+#define IMX_SC_R_IRQSTR_MCU_0 15
+#define IMX_SC_R_IRQSTR_MCU_1 16
+#define IMX_SC_R_SMMU_0 17
+#define IMX_SC_R_GIC_0 18
#define IMX_SC_R_DC_0_BLIT0 19
#define IMX_SC_R_DC_0_BLIT1 20
#define IMX_SC_R_DC_0_BLIT2 21
#define IMX_SC_R_DC_0_BLIT_OUT 22
-#define IMX_SC_R_PERF 23
+#define IMX_SC_R_PERF_0 23
#define IMX_SC_R_USB_1_PHY 24
#define IMX_SC_R_DC_0_WARP 25
#define IMX_SC_R_V2X_MU_0 26
@@ -56,11 +56,14 @@
#define IMX_SC_R_V2X_MU_3 40
#define IMX_SC_R_V2X_MU_4 41
#define IMX_SC_R_DC_1_WARP 42
+#define IMX_SC_R_STM 43
#define IMX_SC_R_SECVIO 44
#define IMX_SC_R_DC_1_VIDEO0 45
#define IMX_SC_R_DC_1_VIDEO1 46
#define IMX_SC_R_DC_1_FRAC0 47
+#define IMX_SC_R_V2X 48
#define IMX_SC_R_DC_1 49
+#define IMX_SC_R_UNUSED14 50
#define IMX_SC_R_DC_1_PLL_0 51
#define IMX_SC_R_DC_1_PLL_1 52
#define IMX_SC_R_SPI_0 53
@@ -151,10 +154,10 @@
#define IMX_SC_R_DMA_1_CH29 137
#define IMX_SC_R_DMA_1_CH30 138
#define IMX_SC_R_DMA_1_CH31 139
-#define IMX_SC_R_UNUSED1 140
-#define IMX_SC_R_UNUSED2 141
-#define IMX_SC_R_UNUSED3 142
-#define IMX_SC_R_UNUSED4 143
+#define IMX_SC_R_V2X_PID0 140
+#define IMX_SC_R_V2X_PID1 141
+#define IMX_SC_R_V2X_PID2 142
+#define IMX_SC_R_V2X_PID3 143
#define IMX_SC_R_GPU_0_PID0 144
#define IMX_SC_R_GPU_0_PID1 145
#define IMX_SC_R_GPU_0_PID2 146
@@ -183,7 +186,7 @@
#define IMX_SC_R_PCIE_B 169
#define IMX_SC_R_SATA_0 170
#define IMX_SC_R_SERDES_1 171
-#define IMX_SC_R_HSIO_GPIO 172
+#define IMX_SC_R_HSIO_GPIO_0 172
#define IMX_SC_R_MATCH_15 173
#define IMX_SC_R_MATCH_16 174
#define IMX_SC_R_MATCH_17 175
@@ -250,15 +253,15 @@
#define IMX_SC_R_ROM_0 236
#define IMX_SC_R_FSPI_0 237
#define IMX_SC_R_FSPI_1 238
-#define IMX_SC_R_IEE 239
-#define IMX_SC_R_IEE_R0 240
-#define IMX_SC_R_IEE_R1 241
-#define IMX_SC_R_IEE_R2 242
-#define IMX_SC_R_IEE_R3 243
-#define IMX_SC_R_IEE_R4 244
-#define IMX_SC_R_IEE_R5 245
-#define IMX_SC_R_IEE_R6 246
-#define IMX_SC_R_IEE_R7 247
+#define IMX_SC_R_IEE_0 239
+#define IMX_SC_R_IEE_0_R0 240
+#define IMX_SC_R_IEE_0_R1 241
+#define IMX_SC_R_IEE_0_R2 242
+#define IMX_SC_R_IEE_0_R3 243
+#define IMX_SC_R_IEE_0_R4 244
+#define IMX_SC_R_IEE_0_R5 245
+#define IMX_SC_R_IEE_0_R6 246
+#define IMX_SC_R_IEE_0_R7 247
#define IMX_SC_R_SDHC_0 248
#define IMX_SC_R_SDHC_1 249
#define IMX_SC_R_SDHC_2 250
@@ -289,46 +292,50 @@
#define IMX_SC_R_LVDS_2_PWM_0 275
#define IMX_SC_R_LVDS_2_I2C_0 276
#define IMX_SC_R_LVDS_2_I2C_1 277
-#define IMX_SC_R_M4_0_PID0 278
-#define IMX_SC_R_M4_0_PID1 279
-#define IMX_SC_R_M4_0_PID2 280
-#define IMX_SC_R_M4_0_PID3 281
-#define IMX_SC_R_M4_0_PID4 282
-#define IMX_SC_R_M4_0_RGPIO 283
-#define IMX_SC_R_M4_0_SEMA42 284
-#define IMX_SC_R_M4_0_TPM 285
-#define IMX_SC_R_M4_0_PIT 286
-#define IMX_SC_R_M4_0_UART 287
-#define IMX_SC_R_M4_0_I2C 288
-#define IMX_SC_R_M4_0_INTMUX 289
-#define IMX_SC_R_M4_0_MU_0B 292
-#define IMX_SC_R_M4_0_MU_0A0 293
-#define IMX_SC_R_M4_0_MU_0A1 294
-#define IMX_SC_R_M4_0_MU_0A2 295
-#define IMX_SC_R_M4_0_MU_0A3 296
-#define IMX_SC_R_M4_0_MU_1A 297
-#define IMX_SC_R_M4_1_PID0 298
-#define IMX_SC_R_M4_1_PID1 299
-#define IMX_SC_R_M4_1_PID2 300
-#define IMX_SC_R_M4_1_PID3 301
-#define IMX_SC_R_M4_1_PID4 302
-#define IMX_SC_R_M4_1_RGPIO 303
-#define IMX_SC_R_M4_1_SEMA42 304
-#define IMX_SC_R_M4_1_TPM 305
-#define IMX_SC_R_M4_1_PIT 306
-#define IMX_SC_R_M4_1_UART 307
-#define IMX_SC_R_M4_1_I2C 308
-#define IMX_SC_R_M4_1_INTMUX 309
-#define IMX_SC_R_M4_1_MU_0B 312
-#define IMX_SC_R_M4_1_MU_0A0 313
-#define IMX_SC_R_M4_1_MU_0A1 314
-#define IMX_SC_R_M4_1_MU_0A2 315
-#define IMX_SC_R_M4_1_MU_0A3 316
-#define IMX_SC_R_M4_1_MU_1A 317
+#define IMX_SC_R_MCU_0_PID0 278
+#define IMX_SC_R_MCU_0_PID1 279
+#define IMX_SC_R_MCU_0_PID2 280
+#define IMX_SC_R_MCU_0_PID3 281
+#define IMX_SC_R_MCU_0_PID4 282
+#define IMX_SC_R_MCU_0_RGPIO 283
+#define IMX_SC_R_MCU_0_SEMA42 284
+#define IMX_SC_R_MCU_0_TPM 285
+#define IMX_SC_R_MCU_0_PIT 286
+#define IMX_SC_R_MCU_0_UART 287
+#define IMX_SC_R_MCU_0_I2C 288
+#define IMX_SC_R_MCU_0_INTMUX 289
+#define IMX_SC_R_ENET_0_A0 290
+#define IMX_SC_R_ENET_0_A1 291
+#define IMX_SC_R_MCU_0_MU_0B 292
+#define IMX_SC_R_MCU_0_MU_0A0 293
+#define IMX_SC_R_MCU_0_MU_0A1 294
+#define IMX_SC_R_MCU_0_MU_0A2 295
+#define IMX_SC_R_MCU_0_MU_0A3 296
+#define IMX_SC_R_MCU_0_MU_1A 297
+#define IMX_SC_R_MCU_1_PID0 298
+#define IMX_SC_R_MCU_1_PID1 299
+#define IMX_SC_R_MCU_1_PID2 300
+#define IMX_SC_R_MCU_1_PID3 301
+#define IMX_SC_R_MCU_1_PID4 302
+#define IMX_SC_R_MCU_1_RGPIO 303
+#define IMX_SC_R_MCU_1_SEMA42 304
+#define IMX_SC_R_MCU_1_TPM 305
+#define IMX_SC_R_MCU_1_PIT 306
+#define IMX_SC_R_MCU_1_UART 307
+#define IMX_SC_R_MCU_1_I2C 308
+#define IMX_SC_R_MCU_1_INTMUX 309
+#define IMX_SC_R_UNUSED17 310
+#define IMX_SC_R_UNUSED18 311
+#define IMX_SC_R_MCU_1_MU_0B 312
+#define IMX_SC_R_MCU_1_MU_0A0 313
+#define IMX_SC_R_MCU_1_MU_0A1 314
+#define IMX_SC_R_MCU_1_MU_0A2 315
+#define IMX_SC_R_MCU_1_MU_0A3 316
+#define IMX_SC_R_MCU_1_MU_1A 317
#define IMX_SC_R_SAI_0 318
#define IMX_SC_R_SAI_1 319
#define IMX_SC_R_SAI_2 320
-#define IMX_SC_R_IRQSTR_SCU2 321
+#define IMX_SC_R_IRQSTR_AP_0 321
#define IMX_SC_R_IRQSTR_DSP 322
#define IMX_SC_R_ELCDIF_PLL 323
#define IMX_SC_R_OCRAM 324
@@ -373,33 +380,33 @@
#define IMX_SC_R_VPU_PID5 363
#define IMX_SC_R_VPU_PID6 364
#define IMX_SC_R_VPU_PID7 365
-#define IMX_SC_R_VPU_UART 366
-#define IMX_SC_R_VPUCORE 367
-#define IMX_SC_R_VPUCORE_0 368
-#define IMX_SC_R_VPUCORE_1 369
-#define IMX_SC_R_VPUCORE_2 370
-#define IMX_SC_R_VPUCORE_3 371
+#define IMX_SC_R_ENET_0_A2 366
+#define IMX_SC_R_ENET_1_A0 367
+#define IMX_SC_R_ENET_1_A1 368
+#define IMX_SC_R_ENET_1_A2 369
+#define IMX_SC_R_ENET_1_A3 370
+#define IMX_SC_R_ENET_1_A4 371
#define IMX_SC_R_DMA_4_CH0 372
#define IMX_SC_R_DMA_4_CH1 373
#define IMX_SC_R_DMA_4_CH2 374
#define IMX_SC_R_DMA_4_CH3 375
#define IMX_SC_R_DMA_4_CH4 376
-#define IMX_SC_R_ISI_CH0 377
-#define IMX_SC_R_ISI_CH1 378
-#define IMX_SC_R_ISI_CH2 379
-#define IMX_SC_R_ISI_CH3 380
-#define IMX_SC_R_ISI_CH4 381
-#define IMX_SC_R_ISI_CH5 382
-#define IMX_SC_R_ISI_CH6 383
-#define IMX_SC_R_ISI_CH7 384
-#define IMX_SC_R_MJPEG_DEC_S0 385
-#define IMX_SC_R_MJPEG_DEC_S1 386
-#define IMX_SC_R_MJPEG_DEC_S2 387
-#define IMX_SC_R_MJPEG_DEC_S3 388
-#define IMX_SC_R_MJPEG_ENC_S0 389
-#define IMX_SC_R_MJPEG_ENC_S1 390
-#define IMX_SC_R_MJPEG_ENC_S2 391
-#define IMX_SC_R_MJPEG_ENC_S3 392
+#define IMX_SC_R_ISI_0_CH0 377
+#define IMX_SC_R_ISI_0_CH1 378
+#define IMX_SC_R_ISI_0_CH2 379
+#define IMX_SC_R_ISI_0_CH3 380
+#define IMX_SC_R_ISI_0_CH4 381
+#define IMX_SC_R_ISI_0_CH5 382
+#define IMX_SC_R_ISI_0_CH6 383
+#define IMX_SC_R_ISI_0_CH7 384
+#define IMX_SC_R_MJPEG_0_DEC_S0 385
+#define IMX_SC_R_MJPEG_0_DEC_S1 386
+#define IMX_SC_R_MJPEG_0_DEC_S2 387
+#define IMX_SC_R_MJPEG_0_DEC_S3 388
+#define IMX_SC_R_MJPEG_0_ENC_S0 389
+#define IMX_SC_R_MJPEG_0_ENC_S1 390
+#define IMX_SC_R_MJPEG_0_ENC_S2 391
+#define IMX_SC_R_MJPEG_0_ENC_S3 392
#define IMX_SC_R_MIPI_0 393
#define IMX_SC_R_MIPI_0_PWM_0 394
#define IMX_SC_R_MIPI_0_I2C_0 395
@@ -514,11 +521,11 @@
#define IMX_SC_R_SECO_MU_3 504
#define IMX_SC_R_SECO_MU_4 505
#define IMX_SC_R_HDMI_RX_PWM_0 506
-#define IMX_SC_R_A35 507
-#define IMX_SC_R_A35_0 508
-#define IMX_SC_R_A35_1 509
-#define IMX_SC_R_A35_2 510
-#define IMX_SC_R_A35_3 511
+#define IMX_SC_R_AP_2 507
+#define IMX_SC_R_AP_2_0 508
+#define IMX_SC_R_AP_2_1 509
+#define IMX_SC_R_AP_2_2 510
+#define IMX_SC_R_AP_2_3 511
#define IMX_SC_R_DSP 512
#define IMX_SC_R_DSP_RAM 513
#define IMX_SC_R_CAAM_JR1_OUT 514
@@ -539,8 +546,8 @@
#define IMX_SC_R_BOARD_R5 529
#define IMX_SC_R_BOARD_R6 530
#define IMX_SC_R_BOARD_R7 531
-#define IMX_SC_R_MJPEG_DEC_MP 532
-#define IMX_SC_R_MJPEG_ENC_MP 533
+#define IMX_SC_R_MJPEG_0_DEC_MP 532
+#define IMX_SC_R_MJPEG_0_ENC_MP 533
#define IMX_SC_R_VPU_TS_0 534
#define IMX_SC_R_VPU_MU_0 535
#define IMX_SC_R_VPU_MU_1 536
@@ -573,6 +580,105 @@
#define IMX_SC_PM_CLK_BYPASS 4 /* Bypass clock */
/*
+ * Compatibility defines for sc_rsrc_t
+ */
+#define IMX_SC_R_A35 IMX_SC_R_AP_2
+#define IMX_SC_R_A35_0 IMX_SC_R_AP_2_0
+#define IMX_SC_R_A35_1 IMX_SC_R_AP_2_1
+#define IMX_SC_R_A35_2 IMX_SC_R_AP_2_2
+#define IMX_SC_R_A35_3 IMX_SC_R_AP_2_3
+#define IMX_SC_R_A53 IMX_SC_R_AP_0
+#define IMX_SC_R_A53_0 IMX_SC_R_AP_0_0
+#define IMX_SC_R_A53_1 IMX_SC_R_AP_0_1
+#define IMX_SC_R_A53_2 IMX_SC_R_AP_0_2
+#define IMX_SC_R_A53_3 IMX_SC_R_AP_0_3
+#define IMX_SC_R_A72 IMX_SC_R_AP_1
+#define IMX_SC_R_A72_0 IMX_SC_R_AP_1_0
+#define IMX_SC_R_A72_1 IMX_SC_R_AP_1_1
+#define IMX_SC_R_A72_2 IMX_SC_R_AP_1_2
+#define IMX_SC_R_A72_3 IMX_SC_R_AP_1_3
+#define IMX_SC_R_GIC IMX_SC_R_GIC_0
+#define IMX_SC_R_HSIO_GPIO IMX_SC_R_HSIO_GPIO_0
+#define IMX_SC_R_IEE IMX_SC_R_IEE_0
+#define IMX_SC_R_IEE_R0 IMX_SC_R_IEE_0_R0
+#define IMX_SC_R_IEE_R1 IMX_SC_R_IEE_0_R1
+#define IMX_SC_R_IEE_R2 IMX_SC_R_IEE_0_R2
+#define IMX_SC_R_IEE_R3 IMX_SC_R_IEE_0_R3
+#define IMX_SC_R_IEE_R4 IMX_SC_R_IEE_0_R4
+#define IMX_SC_R_IEE_R5 IMX_SC_R_IEE_0_R5
+#define IMX_SC_R_IEE_R6 IMX_SC_R_IEE_0_R6
+#define IMX_SC_R_IEE_R7 IMX_SC_R_IEE_0_R7
+#define IMX_SC_R_IRQSTR_M4_0 IMX_SC_R_IRQSTR_MCU_0
+#define IMX_SC_R_IRQSTR_M4_1 IMX_SC_R_IRQSTR_MCU_1
+#define IMX_SC_R_IRQSTR_SCU2 IMX_SC_R_IRQSTR_AP_0
+#define IMX_SC_R_ISI_CH0 IMX_SC_R_ISI_0_CH0
+#define IMX_SC_R_ISI_CH1 IMX_SC_R_ISI_0_CH1
+#define IMX_SC_R_ISI_CH2 IMX_SC_R_ISI_0_CH2
+#define IMX_SC_R_ISI_CH3 IMX_SC_R_ISI_0_CH3
+#define IMX_SC_R_ISI_CH4 IMX_SC_R_ISI_0_CH4
+#define IMX_SC_R_ISI_CH5 IMX_SC_R_ISI_0_CH5
+#define IMX_SC_R_ISI_CH6 IMX_SC_R_ISI_0_CH6
+#define IMX_SC_R_ISI_CH7 IMX_SC_R_ISI_0_CH7
+#define IMX_SC_R_M4_0_I2C IMX_SC_R_MCU_0_I2C
+#define IMX_SC_R_M4_0_INTMUX IMX_SC_R_MCU_0_INTMUX
+#define IMX_SC_R_M4_0_MU_0A0 IMX_SC_R_MCU_0_MU_0A0
+#define IMX_SC_R_M4_0_MU_0A1 IMX_SC_R_MCU_0_MU_0A1
+#define IMX_SC_R_M4_0_MU_0A2 IMX_SC_R_MCU_0_MU_0A2
+#define IMX_SC_R_M4_0_MU_0A3 IMX_SC_R_MCU_0_MU_0A3
+#define IMX_SC_R_M4_0_MU_0B IMX_SC_R_MCU_0_MU_0B
+#define IMX_SC_R_M4_0_MU_1A IMX_SC_R_MCU_0_MU_1A
+#define IMX_SC_R_M4_0_PID0 IMX_SC_R_MCU_0_PID0
+#define IMX_SC_R_M4_0_PID1 IMX_SC_R_MCU_0_PID1
+#define IMX_SC_R_M4_0_PID2 IMX_SC_R_MCU_0_PID2
+#define IMX_SC_R_M4_0_PID3 IMX_SC_R_MCU_0_PID3
+#define IMX_SC_R_M4_0_PID4 IMX_SC_R_MCU_0_PID4
+#define IMX_SC_R_M4_0_PIT IMX_SC_R_MCU_0_PIT
+#define IMX_SC_R_M4_0_RGPIO IMX_SC_R_MCU_0_RGPIO
+#define IMX_SC_R_M4_0_SEMA42 IMX_SC_R_MCU_0_SEMA42
+#define IMX_SC_R_M4_0_TPM IMX_SC_R_MCU_0_TPM
+#define IMX_SC_R_M4_0_UART IMX_SC_R_MCU_0_UART
+#define IMX_SC_R_M4_1_I2C IMX_SC_R_MCU_1_I2C
+#define IMX_SC_R_M4_1_INTMUX IMX_SC_R_MCU_1_INTMUX
+#define IMX_SC_R_M4_1_MU_0A0 IMX_SC_R_MCU_1_MU_0A0
+#define IMX_SC_R_M4_1_MU_0A1 IMX_SC_R_MCU_1_MU_0A1
+#define IMX_SC_R_M4_1_MU_0A2 IMX_SC_R_MCU_1_MU_0A2
+#define IMX_SC_R_M4_1_MU_0A3 IMX_SC_R_MCU_1_MU_0A3
+#define IMX_SC_R_M4_1_MU_0B IMX_SC_R_MCU_1_MU_0B
+#define IMX_SC_R_M4_1_MU_1A IMX_SC_R_MCU_1_MU_1A
+#define IMX_SC_R_M4_1_PID0 IMX_SC_R_MCU_1_PID0
+#define IMX_SC_R_M4_1_PID1 IMX_SC_R_MCU_1_PID1
+#define IMX_SC_R_M4_1_PID2 IMX_SC_R_MCU_1_PID2
+#define IMX_SC_R_M4_1_PID3 IMX_SC_R_MCU_1_PID3
+#define IMX_SC_R_M4_1_PID4 IMX_SC_R_MCU_1_PID4
+#define IMX_SC_R_M4_1_PIT IMX_SC_R_MCU_1_PIT
+#define IMX_SC_R_M4_1_RGPIO IMX_SC_R_MCU_1_RGPIO
+#define IMX_SC_R_M4_1_SEMA42 IMX_SC_R_MCU_1_SEMA42
+#define IMX_SC_R_M4_1_TPM IMX_SC_R_MCU_1_TPM
+#define IMX_SC_R_M4_1_UART IMX_SC_R_MCU_1_UART
+#define IMX_SC_R_MJPEG_DEC_MP IMX_SC_R_MJPEG_0_DEC_MP
+#define IMX_SC_R_MJPEG_DEC_S0 IMX_SC_R_MJPEG_0_DEC_S0
+#define IMX_SC_R_MJPEG_DEC_S1 IMX_SC_R_MJPEG_0_DEC_S1
+#define IMX_SC_R_MJPEG_DEC_S2 IMX_SC_R_MJPEG_0_DEC_S2
+#define IMX_SC_R_MJPEG_DEC_S3 IMX_SC_R_MJPEG_0_DEC_S3
+#define IMX_SC_R_MJPEG_ENC_MP IMX_SC_R_MJPEG_0_ENC_MP
+#define IMX_SC_R_MJPEG_ENC_S0 IMX_SC_R_MJPEG_0_ENC_S0
+#define IMX_SC_R_MJPEG_ENC_S1 IMX_SC_R_MJPEG_0_ENC_S1
+#define IMX_SC_R_MJPEG_ENC_S2 IMX_SC_R_MJPEG_0_ENC_S2
+#define IMX_SC_R_MJPEG_ENC_S3 IMX_SC_R_MJPEG_0_ENC_S3
+#define IMX_SC_R_PERF IMX_SC_R_PERF_0
+#define IMX_SC_R_SMMU IMX_SC_R_SMMU_0
+#define IMX_SC_R_VPU_UART IMX_SC_R_ENET_0_A2
+#define IMX_SC_R_VPUCORE IMX_SC_R_ENET_1_A0
+#define IMX_SC_R_VPUCORE_0 IMX_SC_R_ENET_1_A1
+#define IMX_SC_R_VPUCORE_1 IMX_SC_R_ENET_1_A2
+#define IMX_SC_R_VPUCORE_2 IMX_SC_R_ENET_1_A3
+#define IMX_SC_R_VPUCORE_3 IMX_SC_R_ENET_1_A4
+#define IMX_SC_R_UNUSED1 IMX_SC_R_V2X_PID0
+#define IMX_SC_R_UNUSED2 IMX_SC_R_V2X_PID1
+#define IMX_SC_R_UNUSED3 IMX_SC_R_V2X_PID2
+#define IMX_SC_R_UNUSED4 IMX_SC_R_V2X_PID3
+
+/*
* Defines for SC CONTROL
*/
#define IMX_SC_C_TEMP 0
@@ -637,6 +743,10 @@
#define IMX_SC_C_INTF_SEL 59
#define IMX_SC_C_RXC_DLY 60
#define IMX_SC_C_TIMER_SEL 61
-#define IMX_SC_C_LAST 62
+#define IMX_SC_C_MISC0 62
+#define IMX_SC_C_MISC1 63
+#define IMX_SC_C_MISC2 64
+#define IMX_SC_C_MISC3 65
+#define IMX_SC_C_LAST 66
#endif /* __DT_BINDINGS_RSCRC_IMX_H */
diff --git a/include/dt-bindings/iio/qcom,spmi-adc7-pm8350.h b/include/dt-bindings/iio/qcom,spmi-adc7-pm8350.h
index 9426f27a1946..09fd169ad18e 100644
--- a/include/dt-bindings/iio/qcom,spmi-adc7-pm8350.h
+++ b/include/dt-bindings/iio/qcom,spmi-adc7-pm8350.h
@@ -6,62 +6,58 @@
#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_PM8350_H
#define _DT_BINDINGS_QCOM_SPMI_VADC_PM8350_H
-#ifndef PM8350_SID
-#define PM8350_SID 1
-#endif
-
/* ADC channels for PM8350_ADC for PMIC7 */
-#define PM8350_ADC7_REF_GND (PM8350_SID << 8 | 0x0)
-#define PM8350_ADC7_1P25VREF (PM8350_SID << 8 | 0x01)
-#define PM8350_ADC7_VREF_VADC (PM8350_SID << 8 | 0x02)
-#define PM8350_ADC7_DIE_TEMP (PM8350_SID << 8 | 0x03)
-
-#define PM8350_ADC7_AMUX_THM1 (PM8350_SID << 8 | 0x04)
-#define PM8350_ADC7_AMUX_THM2 (PM8350_SID << 8 | 0x05)
-#define PM8350_ADC7_AMUX_THM3 (PM8350_SID << 8 | 0x06)
-#define PM8350_ADC7_AMUX_THM4 (PM8350_SID << 8 | 0x07)
-#define PM8350_ADC7_AMUX_THM5 (PM8350_SID << 8 | 0x08)
-#define PM8350_ADC7_GPIO1 (PM8350_SID << 8 | 0x0a)
-#define PM8350_ADC7_GPIO2 (PM8350_SID << 8 | 0x0b)
-#define PM8350_ADC7_GPIO3 (PM8350_SID << 8 | 0x0c)
-#define PM8350_ADC7_GPIO4 (PM8350_SID << 8 | 0x0d)
+#define PM8350_ADC7_REF_GND(sid) ((sid) << 8 | 0x0)
+#define PM8350_ADC7_1P25VREF(sid) ((sid) << 8 | 0x01)
+#define PM8350_ADC7_VREF_VADC(sid) ((sid) << 8 | 0x02)
+#define PM8350_ADC7_DIE_TEMP(sid) ((sid) << 8 | 0x03)
+
+#define PM8350_ADC7_AMUX_THM1(sid) ((sid) << 8 | 0x04)
+#define PM8350_ADC7_AMUX_THM2(sid) ((sid) << 8 | 0x05)
+#define PM8350_ADC7_AMUX_THM3(sid) ((sid) << 8 | 0x06)
+#define PM8350_ADC7_AMUX_THM4(sid) ((sid) << 8 | 0x07)
+#define PM8350_ADC7_AMUX_THM5(sid) ((sid) << 8 | 0x08)
+#define PM8350_ADC7_GPIO1(sid) ((sid) << 8 | 0x0a)
+#define PM8350_ADC7_GPIO2(sid) ((sid) << 8 | 0x0b)
+#define PM8350_ADC7_GPIO3(sid) ((sid) << 8 | 0x0c)
+#define PM8350_ADC7_GPIO4(sid) ((sid) << 8 | 0x0d)
/* 30k pull-up1 */
-#define PM8350_ADC7_AMUX_THM1_30K_PU (PM8350_SID << 8 | 0x24)
-#define PM8350_ADC7_AMUX_THM2_30K_PU (PM8350_SID << 8 | 0x25)
-#define PM8350_ADC7_AMUX_THM3_30K_PU (PM8350_SID << 8 | 0x26)
-#define PM8350_ADC7_AMUX_THM4_30K_PU (PM8350_SID << 8 | 0x27)
-#define PM8350_ADC7_AMUX_THM5_30K_PU (PM8350_SID << 8 | 0x28)
-#define PM8350_ADC7_GPIO1_30K_PU (PM8350_SID << 8 | 0x2a)
-#define PM8350_ADC7_GPIO2_30K_PU (PM8350_SID << 8 | 0x2b)
-#define PM8350_ADC7_GPIO3_30K_PU (PM8350_SID << 8 | 0x2c)
-#define PM8350_ADC7_GPIO4_30K_PU (PM8350_SID << 8 | 0x2d)
+#define PM8350_ADC7_AMUX_THM1_30K_PU(sid) ((sid) << 8 | 0x24)
+#define PM8350_ADC7_AMUX_THM2_30K_PU(sid) ((sid) << 8 | 0x25)
+#define PM8350_ADC7_AMUX_THM3_30K_PU(sid) ((sid) << 8 | 0x26)
+#define PM8350_ADC7_AMUX_THM4_30K_PU(sid) ((sid) << 8 | 0x27)
+#define PM8350_ADC7_AMUX_THM5_30K_PU(sid) ((sid) << 8 | 0x28)
+#define PM8350_ADC7_GPIO1_30K_PU(sid) ((sid) << 8 | 0x2a)
+#define PM8350_ADC7_GPIO2_30K_PU(sid) ((sid) << 8 | 0x2b)
+#define PM8350_ADC7_GPIO3_30K_PU(sid) ((sid) << 8 | 0x2c)
+#define PM8350_ADC7_GPIO4_30K_PU(sid) ((sid) << 8 | 0x2d)
/* 100k pull-up2 */
-#define PM8350_ADC7_AMUX_THM1_100K_PU (PM8350_SID << 8 | 0x44)
-#define PM8350_ADC7_AMUX_THM2_100K_PU (PM8350_SID << 8 | 0x45)
-#define PM8350_ADC7_AMUX_THM3_100K_PU (PM8350_SID << 8 | 0x46)
-#define PM8350_ADC7_AMUX_THM4_100K_PU (PM8350_SID << 8 | 0x47)
-#define PM8350_ADC7_AMUX_THM5_100K_PU (PM8350_SID << 8 | 0x48)
-#define PM8350_ADC7_GPIO1_100K_PU (PM8350_SID << 8 | 0x4a)
-#define PM8350_ADC7_GPIO2_100K_PU (PM8350_SID << 8 | 0x4b)
-#define PM8350_ADC7_GPIO3_100K_PU (PM8350_SID << 8 | 0x4c)
-#define PM8350_ADC7_GPIO4_100K_PU (PM8350_SID << 8 | 0x4d)
+#define PM8350_ADC7_AMUX_THM1_100K_PU(sid) ((sid) << 8 | 0x44)
+#define PM8350_ADC7_AMUX_THM2_100K_PU(sid) ((sid) << 8 | 0x45)
+#define PM8350_ADC7_AMUX_THM3_100K_PU(sid) ((sid) << 8 | 0x46)
+#define PM8350_ADC7_AMUX_THM4_100K_PU(sid) ((sid) << 8 | 0x47)
+#define PM8350_ADC7_AMUX_THM5_100K_PU(sid) ((sid) << 8 | 0x48)
+#define PM8350_ADC7_GPIO1_100K_PU(sid) ((sid) << 8 | 0x4a)
+#define PM8350_ADC7_GPIO2_100K_PU(sid) ((sid) << 8 | 0x4b)
+#define PM8350_ADC7_GPIO3_100K_PU(sid) ((sid) << 8 | 0x4c)
+#define PM8350_ADC7_GPIO4_100K_PU(sid) ((sid) << 8 | 0x4d)
/* 400k pull-up3 */
-#define PM8350_ADC7_AMUX_THM1_400K_PU (PM8350_SID << 8 | 0x64)
-#define PM8350_ADC7_AMUX_THM2_400K_PU (PM8350_SID << 8 | 0x65)
-#define PM8350_ADC7_AMUX_THM3_400K_PU (PM8350_SID << 8 | 0x66)
-#define PM8350_ADC7_AMUX_THM4_400K_PU (PM8350_SID << 8 | 0x67)
-#define PM8350_ADC7_AMUX_THM5_400K_PU (PM8350_SID << 8 | 0x68)
-#define PM8350_ADC7_GPIO1_400K_PU (PM8350_SID << 8 | 0x6a)
-#define PM8350_ADC7_GPIO2_400K_PU (PM8350_SID << 8 | 0x6b)
-#define PM8350_ADC7_GPIO3_400K_PU (PM8350_SID << 8 | 0x6c)
-#define PM8350_ADC7_GPIO4_400K_PU (PM8350_SID << 8 | 0x6d)
+#define PM8350_ADC7_AMUX_THM1_400K_PU(sid) ((sid) << 8 | 0x64)
+#define PM8350_ADC7_AMUX_THM2_400K_PU(sid) ((sid) << 8 | 0x65)
+#define PM8350_ADC7_AMUX_THM3_400K_PU(sid) ((sid) << 8 | 0x66)
+#define PM8350_ADC7_AMUX_THM4_400K_PU(sid) ((sid) << 8 | 0x67)
+#define PM8350_ADC7_AMUX_THM5_400K_PU(sid) ((sid) << 8 | 0x68)
+#define PM8350_ADC7_GPIO1_400K_PU(sid) ((sid) << 8 | 0x6a)
+#define PM8350_ADC7_GPIO2_400K_PU(sid) ((sid) << 8 | 0x6b)
+#define PM8350_ADC7_GPIO3_400K_PU(sid) ((sid) << 8 | 0x6c)
+#define PM8350_ADC7_GPIO4_400K_PU(sid) ((sid) << 8 | 0x6d)
/* 1/3 Divider */
-#define PM8350_ADC7_GPIO4_DIV3 (PM8350_SID << 8 | 0x8d)
+#define PM8350_ADC7_GPIO4_DIV3(sid) ((sid) << 8 | 0x8d)
-#define PM8350_ADC7_VPH_PWR (PM8350_SID << 8 | 0x8e)
+#define PM8350_ADC7_VPH_PWR(sid) ((sid) << 8 | 0x8e)
#endif /* _DT_BINDINGS_QCOM_SPMI_VADC_PM8350_H */
diff --git a/include/dt-bindings/media/video-interfaces.h b/include/dt-bindings/media/video-interfaces.h
new file mode 100644
index 000000000000..68ac4e05e37f
--- /dev/null
+++ b/include/dt-bindings/media/video-interfaces.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2022 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#ifndef __DT_BINDINGS_MEDIA_VIDEO_INTERFACES_H__
+#define __DT_BINDINGS_MEDIA_VIDEO_INTERFACES_H__
+
+#define MEDIA_BUS_TYPE_CSI2_CPHY 1
+#define MEDIA_BUS_TYPE_CSI1 2
+#define MEDIA_BUS_TYPE_CCP2 3
+#define MEDIA_BUS_TYPE_CSI2_DPHY 4
+#define MEDIA_BUS_TYPE_PARALLEL 5
+#define MEDIA_BUS_TYPE_BT656 6
+
+#endif /* __DT_BINDINGS_MEDIA_VIDEO_INTERFACES_H__ */
diff --git a/include/dt-bindings/memory/tegra234-mc.h b/include/dt-bindings/memory/tegra234-mc.h
index bd71cc1d7990..347e55e89a2a 100644
--- a/include/dt-bindings/memory/tegra234-mc.h
+++ b/include/dt-bindings/memory/tegra234-mc.h
@@ -8,31 +8,158 @@
#define TEGRA234_SID_INVALID 0x00
#define TEGRA234_SID_PASSTHROUGH 0x7f
+/* ISO stream IDs */
+#define TEGRA234_SID_ISO_NVDISPLAY 0x01
+#define TEGRA234_SID_ISO_VI 0x02
+#define TEGRA234_SID_ISO_VIFALC 0x03
+#define TEGRA234_SID_ISO_VI2 0x04
+#define TEGRA234_SID_ISO_VI2FALC 0x05
+#define TEGRA234_SID_ISO_VI_VM2 0x06
+#define TEGRA234_SID_ISO_VI2_VM2 0x07
+
/* NISO0 stream IDs */
-#define TEGRA234_SID_APE 0x02
-#define TEGRA234_SID_HDA 0x03
-#define TEGRA234_SID_GPCDMA 0x04
-#define TEGRA234_SID_MGBE 0x06
-#define TEGRA234_SID_PCIE0 0x12
-#define TEGRA234_SID_PCIE4 0x13
-#define TEGRA234_SID_PCIE5 0x14
-#define TEGRA234_SID_PCIE6 0x15
-#define TEGRA234_SID_PCIE9 0x1f
-#define TEGRA234_SID_MGBE_VF1 0x49
-#define TEGRA234_SID_MGBE_VF2 0x4a
-#define TEGRA234_SID_MGBE_VF3 0x4b
+#define TEGRA234_SID_AON 0x01
+#define TEGRA234_SID_APE 0x02
+#define TEGRA234_SID_HDA 0x03
+#define TEGRA234_SID_GPCDMA 0x04
+#define TEGRA234_SID_ETR 0x05
+#define TEGRA234_SID_MGBE 0x06
+#define TEGRA234_SID_NVDISPLAY 0x07
+#define TEGRA234_SID_DCE 0x08
+#define TEGRA234_SID_PSC 0x09
+#define TEGRA234_SID_RCE 0x0a
+#define TEGRA234_SID_SCE 0x0b
+#define TEGRA234_SID_UFSHC 0x0c
+#define TEGRA234_SID_APE_1 0x0d
+#define TEGRA234_SID_GPCDMA_1 0x0e
+#define TEGRA234_SID_GPCDMA_2 0x0f
+#define TEGRA234_SID_GPCDMA_3 0x10
+#define TEGRA234_SID_GPCDMA_4 0x11
+#define TEGRA234_SID_PCIE0 0x12
+#define TEGRA234_SID_PCIE4 0x13
+#define TEGRA234_SID_PCIE5 0x14
+#define TEGRA234_SID_PCIE6 0x15
+#define TEGRA234_SID_RCE_VM2 0x16
+#define TEGRA234_SID_RCE_SERVER 0x17
+#define TEGRA234_SID_SMMU_TEST 0x18
+#define TEGRA234_SID_UFS_1 0x19
+#define TEGRA234_SID_UFS_2 0x1a
+#define TEGRA234_SID_UFS_3 0x1b
+#define TEGRA234_SID_UFS_4 0x1c
+#define TEGRA234_SID_UFS_5 0x1d
+#define TEGRA234_SID_UFS_6 0x1e
+#define TEGRA234_SID_PCIE9 0x1f
+#define TEGRA234_SID_VSE_GPCDMA_VM0 0x20
+#define TEGRA234_SID_VSE_GPCDMA_VM1 0x21
+#define TEGRA234_SID_VSE_GPCDMA_VM2 0x22
+#define TEGRA234_SID_NVDLA1 0x23
+#define TEGRA234_SID_NVENC 0x24
+#define TEGRA234_SID_NVJPG1 0x25
+#define TEGRA234_SID_OFA 0x26
+#define TEGRA234_SID_MGBE_VF1 0x49
+#define TEGRA234_SID_MGBE_VF2 0x4a
+#define TEGRA234_SID_MGBE_VF3 0x4b
+#define TEGRA234_SID_MGBE_VF4 0x4c
+#define TEGRA234_SID_MGBE_VF5 0x4d
+#define TEGRA234_SID_MGBE_VF6 0x4e
+#define TEGRA234_SID_MGBE_VF7 0x4f
+#define TEGRA234_SID_MGBE_VF8 0x50
+#define TEGRA234_SID_MGBE_VF9 0x51
+#define TEGRA234_SID_MGBE_VF10 0x52
+#define TEGRA234_SID_MGBE_VF11 0x53
+#define TEGRA234_SID_MGBE_VF12 0x54
+#define TEGRA234_SID_MGBE_VF13 0x55
+#define TEGRA234_SID_MGBE_VF14 0x56
+#define TEGRA234_SID_MGBE_VF15 0x57
+#define TEGRA234_SID_MGBE_VF16 0x58
+#define TEGRA234_SID_MGBE_VF17 0x59
+#define TEGRA234_SID_MGBE_VF18 0x5a
+#define TEGRA234_SID_MGBE_VF19 0x5b
+#define TEGRA234_SID_MGBE_VF20 0x5c
+#define TEGRA234_SID_APE_2 0x5e
+#define TEGRA234_SID_APE_3 0x5f
+#define TEGRA234_SID_UFS_7 0x60
+#define TEGRA234_SID_UFS_8 0x61
+#define TEGRA234_SID_UFS_9 0x62
+#define TEGRA234_SID_UFS_10 0x63
+#define TEGRA234_SID_UFS_11 0x64
+#define TEGRA234_SID_UFS_12 0x65
+#define TEGRA234_SID_UFS_13 0x66
+#define TEGRA234_SID_UFS_14 0x67
+#define TEGRA234_SID_UFS_15 0x68
+#define TEGRA234_SID_UFS_16 0x69
+#define TEGRA234_SID_UFS_17 0x6a
+#define TEGRA234_SID_UFS_18 0x6b
+#define TEGRA234_SID_UFS_19 0x6c
+#define TEGRA234_SID_UFS_20 0x6d
+#define TEGRA234_SID_GPCDMA_5 0x6e
+#define TEGRA234_SID_GPCDMA_6 0x6f
+#define TEGRA234_SID_GPCDMA_7 0x70
+#define TEGRA234_SID_GPCDMA_8 0x71
+#define TEGRA234_SID_GPCDMA_9 0x72
/* NISO1 stream IDs */
-#define TEGRA234_SID_SDMMC4 0x02
-#define TEGRA234_SID_PCIE1 0x05
-#define TEGRA234_SID_PCIE2 0x06
-#define TEGRA234_SID_PCIE3 0x07
-#define TEGRA234_SID_PCIE7 0x08
-#define TEGRA234_SID_PCIE8 0x09
-#define TEGRA234_SID_PCIE10 0x0b
-#define TEGRA234_SID_BPMP 0x10
-#define TEGRA234_SID_HOST1X 0x27
-#define TEGRA234_SID_VIC 0x34
+#define TEGRA234_SID_SDMMC1A 0x01
+#define TEGRA234_SID_SDMMC4 0x02
+#define TEGRA234_SID_EQOS 0x03
+#define TEGRA234_SID_HWMP_PMA 0x04
+#define TEGRA234_SID_PCIE1 0x05
+#define TEGRA234_SID_PCIE2 0x06
+#define TEGRA234_SID_PCIE3 0x07
+#define TEGRA234_SID_PCIE7 0x08
+#define TEGRA234_SID_PCIE8 0x09
+#define TEGRA234_SID_PCIE10 0x0b
+#define TEGRA234_SID_QSPI0 0x0c
+#define TEGRA234_SID_QSPI1 0x0d
+#define TEGRA234_SID_XUSB_HOST 0x0e
+#define TEGRA234_SID_XUSB_DEV 0x0f
+#define TEGRA234_SID_BPMP 0x10
+#define TEGRA234_SID_FSI 0x11
+#define TEGRA234_SID_PVA0_VM0 0x12
+#define TEGRA234_SID_PVA0_VM1 0x13
+#define TEGRA234_SID_PVA0_VM2 0x14
+#define TEGRA234_SID_PVA0_VM3 0x15
+#define TEGRA234_SID_PVA0_VM4 0x16
+#define TEGRA234_SID_PVA0_VM5 0x17
+#define TEGRA234_SID_PVA0_VM6 0x18
+#define TEGRA234_SID_PVA0_VM7 0x19
+#define TEGRA234_SID_XUSB_VF0 0x1a
+#define TEGRA234_SID_XUSB_VF1 0x1b
+#define TEGRA234_SID_XUSB_VF2 0x1c
+#define TEGRA234_SID_XUSB_VF3 0x1d
+#define TEGRA234_SID_EQOS_VF1 0x1e
+#define TEGRA234_SID_EQOS_VF2 0x1f
+#define TEGRA234_SID_EQOS_VF3 0x20
+#define TEGRA234_SID_EQOS_VF4 0x21
+#define TEGRA234_SID_ISP_VM2 0x22
+#define TEGRA234_SID_HOST1X 0x27
+#define TEGRA234_SID_ISP 0x28
+#define TEGRA234_SID_NVDEC 0x29
+#define TEGRA234_SID_NVJPG 0x2a
+#define TEGRA234_SID_NVDLA0 0x2b
+#define TEGRA234_SID_PVA0 0x2c
+#define TEGRA234_SID_SES_SE0 0x2d
+#define TEGRA234_SID_SES_SE1 0x2e
+#define TEGRA234_SID_SES_SE2 0x2f
+#define TEGRA234_SID_SEU1_SE0 0x30
+#define TEGRA234_SID_SEU1_SE1 0x31
+#define TEGRA234_SID_SEU1_SE2 0x32
+#define TEGRA234_SID_TSEC 0x33
+#define TEGRA234_SID_VIC 0x34
+#define TEGRA234_SID_HC_VM0 0x3d
+#define TEGRA234_SID_HC_VM1 0x3e
+#define TEGRA234_SID_HC_VM2 0x3f
+#define TEGRA234_SID_HC_VM3 0x40
+#define TEGRA234_SID_HC_VM4 0x41
+#define TEGRA234_SID_HC_VM5 0x42
+#define TEGRA234_SID_HC_VM6 0x43
+#define TEGRA234_SID_HC_VM7 0x44
+#define TEGRA234_SID_SE_VM0 0x45
+#define TEGRA234_SID_SE_VM1 0x46
+#define TEGRA234_SID_SE_VM2 0x47
+#define TEGRA234_SID_ISPFALC 0x48
+#define TEGRA234_SID_NISO1_SMMU_TEST 0x49
+#define TEGRA234_SID_TSEC_VM0 0x4a
/* Shared stream IDs */
#define TEGRA234_SID_HOST1X_CTX0 0x35
@@ -48,21 +175,81 @@
* memory client IDs
*/
+/* Misses from System Memory Management Unit (SMMU) Page Table Cache (PTC) */
+#define TEGRA234_MEMORY_CLIENT_PTCR 0x00
+/* MSS internal memqual MIU7 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU7R 0x01
+/* MSS internal memqual MIU7 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU7W 0x02
+/* MSS internal memqual MIU8 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU8R 0x03
+/* MSS internal memqual MIU8 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU8W 0x04
+/* MSS internal memqual MIU9 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU9R 0x05
+/* MSS internal memqual MIU9 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU9W 0x06
+/* MSS internal memqual MIU10 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU10R 0x07
+/* MSS internal memqual MIU10 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU10W 0x08
+/* MSS internal memqual MIU11 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU11R 0x09
+/* MSS internal memqual MIU11 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU11W 0x0a
+/* MSS internal memqual MIU12 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU12R 0x0b
+/* MSS internal memqual MIU12 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU12W 0x0c
+/* MSS internal memqual MIU13 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU13R 0x0d
+/* MSS internal memqual MIU13 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU13W 0x0e
+#define TEGRA234_MEMORY_CLIENT_NVL5RHP 0x13
+#define TEGRA234_MEMORY_CLIENT_NVL5R 0x14
/* High-definition audio (HDA) read clients */
#define TEGRA234_MEMORY_CLIENT_HDAR 0x15
+/* Host channel data read clients */
#define TEGRA234_MEMORY_CLIENT_HOST1XDMAR 0x16
+#define TEGRA234_MEMORY_CLIENT_NVL5W 0x17
+#define TEGRA234_MEMORY_CLIENT_NVL6RHP 0x18
+#define TEGRA234_MEMORY_CLIENT_NVL6R 0x19
+#define TEGRA234_MEMORY_CLIENT_NVL6W 0x1a
+#define TEGRA234_MEMORY_CLIENT_NVL7RHP 0x1b
+#define TEGRA234_MEMORY_CLIENT_NVENCSRD 0x1c
+#define TEGRA234_MEMORY_CLIENT_NVL7R 0x1d
+#define TEGRA234_MEMORY_CLIENT_NVL7W 0x1e
+#define TEGRA234_MEMORY_CLIENT_NVL8RHP 0x20
+#define TEGRA234_MEMORY_CLIENT_NVL8R 0x21
+#define TEGRA234_MEMORY_CLIENT_NVL8W 0x22
+#define TEGRA234_MEMORY_CLIENT_NVL9RHP 0x23
+#define TEGRA234_MEMORY_CLIENT_NVL9R 0x24
+#define TEGRA234_MEMORY_CLIENT_NVL9W 0x25
/* PCIE6 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE6AR 0x28
/* PCIE6 write clients */
#define TEGRA234_MEMORY_CLIENT_PCIE6AW 0x29
/* PCIE7 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE7AR 0x2a
+#define TEGRA234_MEMORY_CLIENT_NVENCSWR 0x2b
+/* DLA0ARDB read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0RDB 0x2c
+/* DLA0ARDB1 read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0RDB1 0x2d
+/* DLA0 writes */
+#define TEGRA234_MEMORY_CLIENT_DLA0WRB 0x2e
+/* DLA1ARDB read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1RDB 0x2f
/* PCIE7 write clients */
#define TEGRA234_MEMORY_CLIENT_PCIE7AW 0x30
/* PCIE8 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE8AR 0x32
/* High-definition audio (HDA) write clients */
#define TEGRA234_MEMORY_CLIENT_HDAW 0x35
+/* Writes from Cortex-A9 4 CPU cores via the L2 cache */
+#define TEGRA234_MEMORY_CLIENT_MPCOREW 0x39
+/* OFAA client */
+#define TEGRA234_MEMORY_CLIENT_OFAR1 0x3a
/* PCIE8 write clients */
#define TEGRA234_MEMORY_CLIENT_PCIE8AW 0x3b
/* PCIE9 read clients */
@@ -75,10 +262,32 @@
#define TEGRA234_MEMORY_CLIENT_PCIE10AR 0x3f
/* PCIE10 write clients */
#define TEGRA234_MEMORY_CLIENT_PCIE10AW 0x40
+/* ISP read client for Crossbar A */
+#define TEGRA234_MEMORY_CLIENT_ISPRA 0x44
+/* ISP read client 1 for Crossbar A */
+#define TEGRA234_MEMORY_CLIENT_ISPFALR 0x45
+/* ISP Write client for Crossbar A */
+#define TEGRA234_MEMORY_CLIENT_ISPWA 0x46
+/* ISP Write client Crossbar B */
+#define TEGRA234_MEMORY_CLIENT_ISPWB 0x47
/* PCIE10r1 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE10AR1 0x48
/* PCIE7r1 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE7AR1 0x49
+/* XUSB_HOST read clients */
+#define TEGRA234_MEMORY_CLIENT_XUSB_HOSTR 0x4a
+/* XUSB_HOST write clients */
+#define TEGRA234_MEMORY_CLIENT_XUSB_HOSTW 0x4b
+/* XUSB read clients */
+#define TEGRA234_MEMORY_CLIENT_XUSB_DEVR 0x4c
+/* XUSB_DEV write clients */
+#define TEGRA234_MEMORY_CLIENT_XUSB_DEVW 0x4d
+/* TSEC Memory Return Data Client Description */
+#define TEGRA234_MEMORY_CLIENT_TSECSRD 0x54
+/* TSEC Memory Write Client Description */
+#define TEGRA234_MEMORY_CLIENT_TSECSWR 0x55
+/* XSPI writes */
+#define TEGRA234_MEMORY_CLIENT_XSPI1W 0x56
/* MGBE0 read client */
#define TEGRA234_MEMORY_CLIENT_MGBEARD 0x58
/* MGBEB read client */
@@ -89,18 +298,86 @@
#define TEGRA234_MEMORY_CLIENT_MGBEDRD 0x5b
/* MGBE0 write client */
#define TEGRA234_MEMORY_CLIENT_MGBEAWR 0x5c
+/* OFAA client */
+#define TEGRA234_MEMORY_CLIENT_OFAR 0x5d
+/* OFAA writes */
+#define TEGRA234_MEMORY_CLIENT_OFAW 0x5e
/* MGBEB write client */
#define TEGRA234_MEMORY_CLIENT_MGBEBWR 0x5f
+/* sdmmca memory read client */
+#define TEGRA234_MEMORY_CLIENT_SDMMCRA 0x60
/* MGBEC write client */
#define TEGRA234_MEMORY_CLIENT_MGBECWR 0x61
/* sdmmcd memory read client */
#define TEGRA234_MEMORY_CLIENT_SDMMCRAB 0x63
+/* sdmmca memory write client */
+#define TEGRA234_MEMORY_CLIENT_SDMMCWA 0x64
/* MGBED write client */
#define TEGRA234_MEMORY_CLIENT_MGBEDWR 0x65
/* sdmmcd memory write client */
#define TEGRA234_MEMORY_CLIENT_SDMMCWAB 0x67
+/* SE Memory Return Data Client Description */
+#define TEGRA234_MEMORY_CLIENT_SEU1RD 0x68
+/* SE Memory Write Client Description */
+#define TEGRA234_MEMORY_CLIENT_SUE1WR 0x69
#define TEGRA234_MEMORY_CLIENT_VICSRD 0x6c
#define TEGRA234_MEMORY_CLIENT_VICSWR 0x6d
+/* DLA1ARDB1 read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1RDB1 0x6e
+/* DLA1 writes */
+#define TEGRA234_MEMORY_CLIENT_DLA1WRB 0x6f
+/* VI FLACON read clients */
+#define TEGRA234_MEMORY_CLIENT_VI2FALR 0x71
+/* VI Write client */
+#define TEGRA234_MEMORY_CLIENT_VI2W 0x70
+/* VI Write client */
+#define TEGRA234_MEMORY_CLIENT_VIW 0x72
+/* NISO display read client */
+#define TEGRA234_MEMORY_CLIENT_NVDISPNISOR 0x73
+/* NVDISPNISO writes */
+#define TEGRA234_MEMORY_CLIENT_NVDISPNISOW 0x74
+/* XSPI client */
+#define TEGRA234_MEMORY_CLIENT_XSPI0R 0x75
+/* XSPI writes */
+#define TEGRA234_MEMORY_CLIENT_XSPI0W 0x76
+/* XSPI client */
+#define TEGRA234_MEMORY_CLIENT_XSPI1R 0x77
+#define TEGRA234_MEMORY_CLIENT_NVDECSRD 0x78
+#define TEGRA234_MEMORY_CLIENT_NVDECSWR 0x79
+/* Audio Processing (APE) engine read clients */
+#define TEGRA234_MEMORY_CLIENT_APER 0x7a
+/* Audio Processing (APE) engine write clients */
+#define TEGRA234_MEMORY_CLIENT_APEW 0x7b
+/* VI2FAL writes */
+#define TEGRA234_MEMORY_CLIENT_VI2FALW 0x7c
+#define TEGRA234_MEMORY_CLIENT_NVJPGSRD 0x7e
+#define TEGRA234_MEMORY_CLIENT_NVJPGSWR 0x7f
+/* SE Memory Return Data Client Description */
+#define TEGRA234_MEMORY_CLIENT_SESRD 0x80
+/* SE Memory Write Client Description */
+#define TEGRA234_MEMORY_CLIENT_SESWR 0x81
+/* AXI AP and DFD-AUX0/1 read clients Both share the same interface on the on MSS */
+#define TEGRA234_MEMORY_CLIENT_AXIAPR 0x82
+/* AXI AP and DFD-AUX0/1 write clients Both sahre the same interface on MSS */
+#define TEGRA234_MEMORY_CLIENT_AXIAPW 0x83
+/* ETR read clients */
+#define TEGRA234_MEMORY_CLIENT_ETRR 0x84
+/* ETR write clients */
+#define TEGRA234_MEMORY_CLIENT_ETRW 0x85
+/* AXI Switch read client */
+#define TEGRA234_MEMORY_CLIENT_AXISR 0x8c
+/* AXI Switch write client */
+#define TEGRA234_MEMORY_CLIENT_AXISW 0x8d
+/* EQOS read client */
+#define TEGRA234_MEMORY_CLIENT_EQOSR 0x8e
+/* EQOS write client */
+#define TEGRA234_MEMORY_CLIENT_EQOSW 0x8f
+/* UFSHC read client */
+#define TEGRA234_MEMORY_CLIENT_UFSHCR 0x90
+/* UFSHC write client */
+#define TEGRA234_MEMORY_CLIENT_UFSHCW 0x91
+/* NVDISPLAY read client */
+#define TEGRA234_MEMORY_CLIENT_NVDISPLAYR 0x92
/* BPMP read client */
#define TEGRA234_MEMORY_CLIENT_BPMPR 0x93
/* BPMP write client */
@@ -109,10 +386,97 @@
#define TEGRA234_MEMORY_CLIENT_BPMPDMAR 0x95
/* BPMPDMA write client */
#define TEGRA234_MEMORY_CLIENT_BPMPDMAW 0x96
+/* AON read client */
+#define TEGRA234_MEMORY_CLIENT_AONR 0x97
+/* AON write client */
+#define TEGRA234_MEMORY_CLIENT_AONW 0x98
+/* AONDMA read client */
+#define TEGRA234_MEMORY_CLIENT_AONDMAR 0x99
+/* AONDMA write client */
+#define TEGRA234_MEMORY_CLIENT_AONDMAW 0x9a
+/* SCE read client */
+#define TEGRA234_MEMORY_CLIENT_SCER 0x9b
+/* SCE write client */
+#define TEGRA234_MEMORY_CLIENT_SCEW 0x9c
+/* SCEDMA read client */
+#define TEGRA234_MEMORY_CLIENT_SCEDMAR 0x9d
+/* SCEDMA write client */
+#define TEGRA234_MEMORY_CLIENT_SCEDMAW 0x9e
/* APEDMA read client */
#define TEGRA234_MEMORY_CLIENT_APEDMAR 0x9f
/* APEDMA write client */
#define TEGRA234_MEMORY_CLIENT_APEDMAW 0xa0
+/* NVDISPLAY read client instance 2 */
+#define TEGRA234_MEMORY_CLIENT_NVDISPLAYR1 0xa1
+#define TEGRA234_MEMORY_CLIENT_VICSRD1 0xa2
+/* MSS internal memqual MIU0 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU0R 0xa6
+/* MSS internal memqual MIU0 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU0W 0xa7
+/* MSS internal memqual MIU1 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU1R 0xa8
+/* MSS internal memqual MIU1 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU1W 0xa9
+/* MSS internal memqual MIU2 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU2R 0xae
+/* MSS internal memqual MIU2 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU2W 0xaf
+/* MSS internal memqual MIU3 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU3R 0xb0
+/* MSS internal memqual MIU3 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU3W 0xb1
+/* MSS internal memqual MIU4 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU4R 0xb2
+/* MSS internal memqual MIU4 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU4W 0xb3
+#define TEGRA234_MEMORY_CLIENT_DPMUR 0xb4
+#define TEGRA234_MEMORY_CLIENT_DPMUW 0xb5
+#define TEGRA234_MEMORY_CLIENT_NVL0R 0xb6
+#define TEGRA234_MEMORY_CLIENT_NVL0W 0xb7
+#define TEGRA234_MEMORY_CLIENT_NVL1R 0xb8
+#define TEGRA234_MEMORY_CLIENT_NVL1W 0xb9
+#define TEGRA234_MEMORY_CLIENT_NVL2R 0xba
+#define TEGRA234_MEMORY_CLIENT_NVL2W 0xbb
+/* VI FLACON read clients */
+#define TEGRA234_MEMORY_CLIENT_VIFALR 0xbc
+/* VIFAL write clients */
+#define TEGRA234_MEMORY_CLIENT_VIFALW 0xbd
+/* DLA0ARDA read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0RDA 0xbe
+/* DLA0 Falcon read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0FALRDB 0xbf
+/* DLA0 write clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0WRA 0xc0
+/* DLA0 write clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0FALWRB 0xc1
+/* DLA1ARDA read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1RDA 0xc2
+/* DLA1 Falcon read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1FALRDB 0xc3
+/* DLA1 write clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1WRA 0xc4
+/* DLA1 write clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1FALWRB 0xc5
+/* PVA0RDA read clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0RDA 0xc6
+/* PVA0RDB read clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0RDB 0xc7
+/* PVA0RDC read clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0RDC 0xc8
+/* PVA0WRA write clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0WRA 0xc9
+/* PVA0WRB write clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0WRB 0xca
+/* PVA0WRC write clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0WRC 0xcb
+/* RCE read client */
+#define TEGRA234_MEMORY_CLIENT_RCER 0xd2
+/* RCE write client */
+#define TEGRA234_MEMORY_CLIENT_RCEW 0xd3
+/* RCEDMA read client */
+#define TEGRA234_MEMORY_CLIENT_RCEDMAR 0xd4
+/* RCEDMA write client */
+#define TEGRA234_MEMORY_CLIENT_RCEDMAW 0xd5
/* PCIE0 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE0R 0xd8
/* PCIE0 write clients */
@@ -137,7 +501,39 @@
#define TEGRA234_MEMORY_CLIENT_PCIE5R 0xe2
/* PCIE5 write clients */
#define TEGRA234_MEMORY_CLIENT_PCIE5W 0xe3
+/* ISP read client 1 for Crossbar A */
+#define TEGRA234_MEMORY_CLIENT_ISPFALW 0xe4
+#define TEGRA234_MEMORY_CLIENT_NVL3R 0xe5
+#define TEGRA234_MEMORY_CLIENT_NVL3W 0xe6
+#define TEGRA234_MEMORY_CLIENT_NVL4R 0xe7
+#define TEGRA234_MEMORY_CLIENT_NVL4W 0xe8
+/* DLA0ARDA1 read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA0RDA1 0xe9
+/* DLA1ARDA1 read clients */
+#define TEGRA234_MEMORY_CLIENT_DLA1RDA1 0xea
+/* PVA0RDA1 read clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0RDA1 0xeb
+/* PVA0RDB1 read clients */
+#define TEGRA234_MEMORY_CLIENT_PVA0RDB1 0xec
/* PCIE5r1 read clients */
#define TEGRA234_MEMORY_CLIENT_PCIE5R1 0xef
+#define TEGRA234_MEMORY_CLIENT_NVENCSRD1 0xf0
+/* ISP read client for Crossbar A */
+#define TEGRA234_MEMORY_CLIENT_ISPRA1 0xf2
+#define TEGRA234_MEMORY_CLIENT_NVL0RHP 0xf4
+#define TEGRA234_MEMORY_CLIENT_NVL1RHP 0xf5
+#define TEGRA234_MEMORY_CLIENT_NVL2RHP 0xf6
+#define TEGRA234_MEMORY_CLIENT_NVL3RHP 0xf7
+#define TEGRA234_MEMORY_CLIENT_NVL4RHP 0xf8
+/* MSS internal memqual MIU5 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU5R 0xfc
+/* MSS internal memqual MIU5 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU5W 0xfd
+/* MSS internal memqual MIU6 read clients */
+#define TEGRA234_MEMORY_CLIENT_MIU6R 0xfe
+/* MSS internal memqual MIU6 write clients */
+#define TEGRA234_MEMORY_CLIENT_MIU6W 0xff
+#define TEGRA234_MEMORY_CLIENT_NVJPG1SRD 0x123
+#define TEGRA234_MEMORY_CLIENT_NVJPG1SWR 0x124
#endif
diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h
index f5f82dde7399..1e19e258a74d 100644
--- a/include/dt-bindings/power/qcom-rpmpd.h
+++ b/include/dt-bindings/power/qcom-rpmpd.h
@@ -4,6 +4,16 @@
#ifndef _DT_BINDINGS_POWER_QCOM_RPMPD_H
#define _DT_BINDINGS_POWER_QCOM_RPMPD_H
+/* SDM670 Power Domain Indexes */
+#define SDM670_MX 0
+#define SDM670_MX_AO 1
+#define SDM670_CX 2
+#define SDM670_CX_AO 3
+#define SDM670_LMX 4
+#define SDM670_LCX 5
+#define SDM670_GFX 6
+#define SDM670_MSS 7
+
/* SDM845 Power Domain Indexes */
#define SDM845_EBI 0
#define SDM845_MX 1
@@ -103,6 +113,28 @@
#define SM8450_MXC_AO 11
#define SM8450_MSS 12
+/* SM8550 Power Domain Indexes */
+#define SM8550_CX 0
+#define SM8550_CX_AO 1
+#define SM8550_EBI 2
+#define SM8550_GFX 3
+#define SM8550_LCX 4
+#define SM8550_LMX 5
+#define SM8550_MMCX 6
+#define SM8550_MMCX_AO 7
+#define SM8550_MX 8
+#define SM8550_MX_AO 9
+#define SM8550_MXC 10
+#define SM8550_MXC_AO 11
+#define SM8550_MSS 12
+#define SM8550_NSP 13
+
+/* QDU1000/QRU1000 Power Domain Indexes */
+#define QDU1000_EBI 0
+#define QDU1000_MSS 1
+#define QDU1000_CX 2
+#define QDU1000_MX 3
+
/* SC7180 Power Domain Indexes */
#define SC7180_CX 0
#define SC7180_CX_AO 1
@@ -274,6 +306,16 @@
#define SDM660_SSCMX 8
#define SDM660_SSCMX_VFL 9
+/* SM4250 Power Domains */
+#define SM4250_VDDCX 0
+#define SM4250_VDDCX_AO 1
+#define SM4250_VDDCX_VFL 2
+#define SM4250_VDDMX 3
+#define SM4250_VDDMX_AO 4
+#define SM4250_VDDMX_VFL 5
+#define SM4250_VDD_LPI_CX 6
+#define SM4250_VDD_LPI_MX 7
+
/* SM6115 Power Domains */
#define SM6115_VDDCX 0
#define SM6115_VDDCX_AO 1
diff --git a/include/dt-bindings/power/tegra234-powergate.h b/include/dt-bindings/power/tegra234-powergate.h
index ae9286cef85c..b0fec2ddec84 100644
--- a/include/dt-bindings/power/tegra234-powergate.h
+++ b/include/dt-bindings/power/tegra234-powergate.h
@@ -4,6 +4,7 @@
#ifndef __ABI_MACH_T234_POWERGATE_T234_H_
#define __ABI_MACH_T234_POWERGATE_T234_H_
+#define TEGRA234_POWER_DOMAIN_OFA 1U
#define TEGRA234_POWER_DOMAIN_AUD 2U
#define TEGRA234_POWER_DOMAIN_DISP 3U
#define TEGRA234_POWER_DOMAIN_PCIEX8A 5U
@@ -11,6 +12,9 @@
#define TEGRA234_POWER_DOMAIN_PCIEX4BA 7U
#define TEGRA234_POWER_DOMAIN_PCIEX4BB 8U
#define TEGRA234_POWER_DOMAIN_PCIEX1A 9U
+#define TEGRA234_POWER_DOMAIN_XUSBA 10U
+#define TEGRA234_POWER_DOMAIN_XUSBB 11U
+#define TEGRA234_POWER_DOMAIN_XUSBC 12U
#define TEGRA234_POWER_DOMAIN_PCIEX4CA 13U
#define TEGRA234_POWER_DOMAIN_PCIEX4CB 14U
#define TEGRA234_POWER_DOMAIN_PCIEX4CC 15U
@@ -19,6 +23,17 @@
#define TEGRA234_POWER_DOMAIN_MGBEB 18U
#define TEGRA234_POWER_DOMAIN_MGBEC 19U
#define TEGRA234_POWER_DOMAIN_MGBED 20U
+#define TEGRA234_POWER_DOMAIN_ISPA 22U
+#define TEGRA234_POWER_DOMAIN_NVDEC 23U
+#define TEGRA234_POWER_DOMAIN_NVJPGA 24U
+#define TEGRA234_POWER_DOMAIN_NVENC 25U
+#define TEGRA234_POWER_DOMAIN_VI 28U
#define TEGRA234_POWER_DOMAIN_VIC 29U
+#define TEGRA234_POWER_DOMAIN_PVA 30U
+#define TEGRA234_POWER_DOMAIN_DLAA 32U
+#define TEGRA234_POWER_DOMAIN_DLAB 33U
+#define TEGRA234_POWER_DOMAIN_CV 34U
+#define TEGRA234_POWER_DOMAIN_GPU 35U
+#define TEGRA234_POWER_DOMAIN_NVJPGB 36U
#endif
diff --git a/include/dt-bindings/reset/tegra234-reset.h b/include/dt-bindings/reset/tegra234-reset.h
index d48d22b2bc7f..85cc423a7bdf 100644
--- a/include/dt-bindings/reset/tegra234-reset.h
+++ b/include/dt-bindings/reset/tegra234-reset.h
@@ -10,14 +10,29 @@
* @brief Identifiers for Resets controllable by firmware
* @{
*/
+#define TEGRA234_RESET_ACTMON 1U
+#define TEGRA234_RESET_ADSP_ALL 2U
+#define TEGRA234_RESET_DSI_CORE 3U
+#define TEGRA234_RESET_CAN1 4U
+#define TEGRA234_RESET_CAN2 5U
+#define TEGRA234_RESET_DLA0 6U
+#define TEGRA234_RESET_DLA1 7U
+#define TEGRA234_RESET_DPAUX 8U
+#define TEGRA234_RESET_OFA 9U
+#define TEGRA234_RESET_NVJPG1 10U
#define TEGRA234_RESET_PEX1_CORE_6 11U
#define TEGRA234_RESET_PEX1_CORE_6_APB 12U
#define TEGRA234_RESET_PEX1_COMMON_APB 13U
#define TEGRA234_RESET_PEX2_CORE_7 14U
#define TEGRA234_RESET_PEX2_CORE_7_APB 15U
+#define TEGRA234_RESET_NVDISPLAY 16U
+#define TEGRA234_RESET_EQOS 17U
#define TEGRA234_RESET_GPCDMA 18U
+#define TEGRA234_RESET_GPU 19U
#define TEGRA234_RESET_HDA 20U
#define TEGRA234_RESET_HDACODEC 21U
+#define TEGRA234_RESET_EQOS_MACSEC 22U
+#define TEGRA234_RESET_EQOS_MACSEC_SECURE 23U
#define TEGRA234_RESET_I2C1 24U
#define TEGRA234_RESET_PEX2_CORE_8 25U
#define TEGRA234_RESET_PEX2_CORE_8_APB 26U
@@ -30,15 +45,36 @@
#define TEGRA234_RESET_I2C7 33U
#define TEGRA234_RESET_I2C8 34U
#define TEGRA234_RESET_I2C9 35U
+#define TEGRA234_RESET_ISP 36U
+#define TEGRA234_RESET_MIPI_CAL 37U
+#define TEGRA234_RESET_MPHY_CLK_CTL 38U
+#define TEGRA234_RESET_MPHY_L0_RX 39U
+#define TEGRA234_RESET_MPHY_L0_TX 40U
+#define TEGRA234_RESET_MPHY_L1_RX 41U
+#define TEGRA234_RESET_MPHY_L1_TX 42U
+#define TEGRA234_RESET_NVCSI 43U
+#define TEGRA234_RESET_NVDEC 44U
#define TEGRA234_RESET_MGBE0_PCS 45U
#define TEGRA234_RESET_MGBE0_MAC 46U
+#define TEGRA234_RESET_MGBE0_MACSEC 47U
+#define TEGRA234_RESET_MGBE0_MACSEC_SECURE 48U
#define TEGRA234_RESET_MGBE1_PCS 49U
#define TEGRA234_RESET_MGBE1_MAC 50U
+#define TEGRA234_RESET_MGBE1_MACSEC 51U
+#define TEGRA234_RESET_MGBE1_MACSEC_SECURE 52U
#define TEGRA234_RESET_MGBE2_PCS 53U
#define TEGRA234_RESET_MGBE2_MAC 54U
+#define TEGRA234_RESET_MGBE2_MACSEC 55U
#define TEGRA234_RESET_PEX2_CORE_10 56U
#define TEGRA234_RESET_PEX2_CORE_10_APB 57U
#define TEGRA234_RESET_PEX2_COMMON_APB 58U
+#define TEGRA234_RESET_NVENC 59U
+#define TEGRA234_RESET_MGBE2_MACSEC_SECURE 60U
+#define TEGRA234_RESET_NVJPG 61U
+#define TEGRA234_RESET_LA 64U
+#define TEGRA234_RESET_HWPM 65U
+#define TEGRA234_RESET_PVA0_ALL 66U
+#define TEGRA234_RESET_CEC 67U
#define TEGRA234_RESET_PWM1 68U
#define TEGRA234_RESET_PWM2 69U
#define TEGRA234_RESET_PWM3 70U
@@ -49,11 +85,43 @@
#define TEGRA234_RESET_PWM8 75U
#define TEGRA234_RESET_QSPI0 76U
#define TEGRA234_RESET_QSPI1 77U
+#define TEGRA234_RESET_I2S7 78U
+#define TEGRA234_RESET_I2S8 79U
+#define TEGRA234_RESET_SCE_ALL 80U
+#define TEGRA234_RESET_RCE_ALL 81U
+#define TEGRA234_RESET_SDMMC1 82U
+#define TEGRA234_RESET_RSVD_83 83U
+#define TEGRA234_RESET_RSVD_84 84U
#define TEGRA234_RESET_SDMMC4 85U
#define TEGRA234_RESET_MGBE3_PCS 87U
#define TEGRA234_RESET_MGBE3_MAC 88U
+#define TEGRA234_RESET_MGBE3_MACSEC 89U
+#define TEGRA234_RESET_MGBE3_MACSEC_SECURE 90U
+#define TEGRA234_RESET_SPI1 91U
+#define TEGRA234_RESET_SPI2 92U
+#define TEGRA234_RESET_SPI3 93U
+#define TEGRA234_RESET_SPI4 94U
+#define TEGRA234_RESET_TACH0 95U
+#define TEGRA234_RESET_TACH1 96U
+#define TEGRA234_RESET_SPI5 97U
+#define TEGRA234_RESET_TSEC 98U
+#define TEGRA234_RESET_UARTI 99U
#define TEGRA234_RESET_UARTA 100U
-#define TEGRA234_RESET_VIC 113U
+#define TEGRA234_RESET_UARTB 101U
+#define TEGRA234_RESET_UARTC 102U
+#define TEGRA234_RESET_UARTD 103U
+#define TEGRA234_RESET_UARTE 104U
+#define TEGRA234_RESET_UARTF 105U
+#define TEGRA234_RESET_UARTJ 106U
+#define TEGRA234_RESET_UARTH 107U
+#define TEGRA234_RESET_UFSHC 108U
+#define TEGRA234_RESET_UFSHC_AXI_M 109U
+#define TEGRA234_RESET_UFSHC_LP_SEQ 110U
+#define TEGRA234_RESET_RSVD_111 111U
+#define TEGRA234_RESET_VI 112U
+#define TEGRA234_RESET_VIC 113U
+#define TEGRA234_RESET_XUSB_PADCTL 114U
+#define TEGRA234_RESET_VI2 115U
#define TEGRA234_RESET_PEX0_CORE_0 116U
#define TEGRA234_RESET_PEX0_CORE_1 117U
#define TEGRA234_RESET_PEX0_CORE_2 118U
@@ -65,8 +133,49 @@
#define TEGRA234_RESET_PEX0_CORE_3_APB 124U
#define TEGRA234_RESET_PEX0_CORE_4_APB 125U
#define TEGRA234_RESET_PEX0_COMMON_APB 126U
+#define TEGRA234_RESET_RSVD_127 127U
+#define TEGRA234_RESET_NVHS_UPHY_PLL1 128U
#define TEGRA234_RESET_PEX1_CORE_5 129U
#define TEGRA234_RESET_PEX1_CORE_5_APB 130U
+#define TEGRA234_RESET_GBE_UPHY 131U
+#define TEGRA234_RESET_GBE_UPHY_PM 132U
+#define TEGRA234_RESET_NVHS_UPHY 133U
+#define TEGRA234_RESET_NVHS_UPHY_PLL0 134U
+#define TEGRA234_RESET_NVHS_UPHY_L0 135U
+#define TEGRA234_RESET_NVHS_UPHY_L1 136U
+#define TEGRA234_RESET_NVHS_UPHY_L2 137U
+#define TEGRA234_RESET_NVHS_UPHY_L3 138U
+#define TEGRA234_RESET_NVHS_UPHY_L4 139U
+#define TEGRA234_RESET_NVHS_UPHY_L5 140U
+#define TEGRA234_RESET_NVHS_UPHY_L6 141U
+#define TEGRA234_RESET_NVHS_UPHY_L7 142U
+#define TEGRA234_RESET_NVHS_UPHY_PM 143U
+#define TEGRA234_RESET_DMIC5 144U
+#define TEGRA234_RESET_APE 145U
+#define TEGRA234_RESET_PEX_USB_UPHY 146U
+#define TEGRA234_RESET_PEX_USB_UPHY_L0 147U
+#define TEGRA234_RESET_PEX_USB_UPHY_L1 148U
+#define TEGRA234_RESET_PEX_USB_UPHY_L2 149U
+#define TEGRA234_RESET_PEX_USB_UPHY_L3 150U
+#define TEGRA234_RESET_PEX_USB_UPHY_L4 151U
+#define TEGRA234_RESET_PEX_USB_UPHY_L5 152U
+#define TEGRA234_RESET_PEX_USB_UPHY_L6 153U
+#define TEGRA234_RESET_PEX_USB_UPHY_L7 154U
+#define TEGRA234_RESET_PEX_USB_UPHY_PLL0 159U
+#define TEGRA234_RESET_PEX_USB_UPHY_PLL1 160U
+#define TEGRA234_RESET_PEX_USB_UPHY_PLL2 161U
+#define TEGRA234_RESET_PEX_USB_UPHY_PLL3 162U
+#define TEGRA234_RESET_GBE_UPHY_L0 163U
+#define TEGRA234_RESET_GBE_UPHY_L1 164U
+#define TEGRA234_RESET_GBE_UPHY_L2 165U
+#define TEGRA234_RESET_GBE_UPHY_L3 166U
+#define TEGRA234_RESET_GBE_UPHY_L4 167U
+#define TEGRA234_RESET_GBE_UPHY_L5 168U
+#define TEGRA234_RESET_GBE_UPHY_L6 169U
+#define TEGRA234_RESET_GBE_UPHY_L7 170U
+#define TEGRA234_RESET_GBE_UPHY_PLL0 171U
+#define TEGRA234_RESET_GBE_UPHY_PLL1 172U
+#define TEGRA234_RESET_GBE_UPHY_PLL2 173U
/** @} */
diff --git a/include/kunit/assert.h b/include/kunit/assert.h
index ace3de8d1ee7..24c2b9fa61e8 100644
--- a/include/kunit/assert.h
+++ b/include/kunit/assert.h
@@ -91,19 +91,6 @@ void kunit_unary_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
- * KUNIT_INIT_UNARY_ASSERT_STRUCT() - Initializes &struct kunit_unary_assert.
- * @cond: A string representation of the expression asserted true or false.
- * @expect_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise.
- *
- * Initializes a &struct kunit_unary_assert. Intended to be used in
- * KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
- */
-#define KUNIT_INIT_UNARY_ASSERT_STRUCT(cond, expect_true) { \
- .condition = cond, \
- .expected_true = expect_true \
-}
-
-/**
* struct kunit_ptr_not_err_assert - An expectation/assertion that a pointer is
* not NULL and not a -errno.
* @assert: The parent of this type.
@@ -124,20 +111,6 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
- * KUNIT_INIT_PTR_NOT_ERR_ASSERT_STRUCT() - Initializes a
- * &struct kunit_ptr_not_err_assert.
- * @txt: A string representation of the expression passed to the expectation.
- * @val: The actual evaluated pointer value of the expression.
- *
- * Initializes a &struct kunit_ptr_not_err_assert. Intended to be used in
- * KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
- */
-#define KUNIT_INIT_PTR_NOT_ERR_STRUCT(txt, val) { \
- .text = txt, \
- .value = val \
-}
-
-/**
* struct kunit_binary_assert_text - holds strings for &struct
* kunit_binary_assert and friends to try and make the structs smaller.
* @operation: A string representation of the comparison operator (e.g. "==").
@@ -174,27 +147,6 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
- * KUNIT_INIT_BINARY_ASSERT_STRUCT() - Initializes a binary assert like
- * kunit_binary_assert, kunit_binary_ptr_assert, etc.
- *
- * @text_: Pointer to a kunit_binary_assert_text.
- * @left_val: The actual evaluated value of the expression in the left slot.
- * @right_val: The actual evaluated value of the expression in the right slot.
- *
- * Initializes a binary assert like kunit_binary_assert,
- * kunit_binary_ptr_assert, etc. This relies on these structs having the same
- * fields but with different types for left_val/right_val.
- * This is ultimately used by binary assertion macros like KUNIT_EXPECT_EQ, etc.
- */
-#define KUNIT_INIT_BINARY_ASSERT_STRUCT(text_, \
- left_val, \
- right_val) { \
- .text = text_, \
- .left_value = left_val, \
- .right_value = right_val \
-}
-
-/**
* struct kunit_binary_ptr_assert - An expectation/assertion that compares two
* pointer values (for example, KUNIT_EXPECT_PTR_EQ(test, foo, bar)).
* @assert: The parent of this type.
@@ -240,4 +192,30 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream);
+/**
+ * struct kunit_mem_assert - An expectation/assertion that compares two
+ * memory blocks.
+ * @assert: The parent of this type.
+ * @text: Holds the textual representations of the operands and comparator.
+ * @left_value: The actual evaluated value of the expression in the left slot.
+ * @right_value: The actual evaluated value of the expression in the right slot.
+ * @size: Size of the memory block analysed in bytes.
+ *
+ * Represents an expectation/assertion that compares two memory blocks. For
+ * example, to expect that the first three bytes of foo is equal to the
+ * first three bytes of bar, you can use the expectation
+ * KUNIT_EXPECT_MEMEQ(test, foo, bar, 3);
+ */
+struct kunit_mem_assert {
+ struct kunit_assert assert;
+ const struct kunit_binary_assert_text *text;
+ const void *left_value;
+ const void *right_value;
+ const size_t size;
+};
+
+void kunit_mem_assert_format(const struct kunit_assert *assert,
+ const struct va_format *message,
+ struct string_stream *stream);
+
#endif /* _KUNIT_ASSERT_H */
diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
index 5fc58081d511..c1b2e14eab64 100644
--- a/include/kunit/test-bug.h
+++ b/include/kunit/test-bug.h
@@ -9,16 +9,63 @@
#ifndef _KUNIT_TEST_BUG_H
#define _KUNIT_TEST_BUG_H
-#define kunit_fail_current_test(fmt, ...) \
- __kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
-
#if IS_BUILTIN(CONFIG_KUNIT)
+#include <linux/jump_label.h> /* For static branch */
+#include <linux/sched.h>
+
+/* Static key if KUnit is running any tests. */
+DECLARE_STATIC_KEY_FALSE(kunit_running);
+
+/**
+ * kunit_get_current_test() - Return a pointer to the currently running
+ * KUnit test.
+ *
+ * If a KUnit test is running in the current task, returns a pointer to its
+ * associated struct kunit. This pointer can then be passed to any KUnit
+ * function or assertion. If no test is running (or a test is running in a
+ * different task), returns NULL.
+ *
+ * This function is safe to call even when KUnit is disabled. If CONFIG_KUNIT
+ * is not enabled, it will compile down to nothing and will return quickly no
+ * test is running.
+ */
+static inline struct kunit *kunit_get_current_test(void)
+{
+ if (!static_branch_unlikely(&kunit_running))
+ return NULL;
+
+ return current->kunit_test;
+}
+
+
+/**
+ * kunit_fail_current_test() - If a KUnit test is running, fail it.
+ *
+ * If a KUnit test is running in the current task, mark that test as failed.
+ *
+ * This macro will only work if KUnit is built-in (though the tests
+ * themselves can be modules). Otherwise, it compiles down to nothing.
+ */
+#define kunit_fail_current_test(fmt, ...) do { \
+ if (static_branch_unlikely(&kunit_running)) { \
+ __kunit_fail_current_test(__FILE__, __LINE__, \
+ fmt, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+
extern __printf(3, 4) void __kunit_fail_current_test(const char *file, int line,
const char *fmt, ...);
#else
+static inline struct kunit *kunit_get_current_test(void) { return NULL; }
+
+/* We define this with an empty helper function so format string warnings work */
+#define kunit_fail_current_test(fmt, ...) \
+ __kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
+
static inline __printf(3, 4) void __kunit_fail_current_test(const char *file, int line,
const char *fmt, ...)
{
diff --git a/include/kunit/test.h b/include/kunit/test.h
index b1ab6b32216d..87ea90576b50 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -16,6 +16,7 @@
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/init.h>
+#include <linux/jump_label.h>
#include <linux/kconfig.h>
#include <linux/kref.h>
#include <linux/list.h>
@@ -27,6 +28,9 @@
#include <asm/rwonce.h>
+/* Static key: true if any KUnit tests are currently running */
+DECLARE_STATIC_KEY_FALSE(kunit_running);
+
struct kunit;
/* Size of log associated with test. */
@@ -515,22 +519,25 @@ void kunit_do_failed_assertion(struct kunit *test,
fmt, \
##__VA_ARGS__)
+/* Helper to safely pass around an initializer list to other macros. */
+#define KUNIT_INIT_ASSERT(initializers...) { initializers }
+
#define KUNIT_UNARY_ASSERTION(test, \
assert_type, \
- condition, \
- expected_true, \
+ condition_, \
+ expected_true_, \
fmt, \
...) \
do { \
- if (likely(!!(condition) == !!expected_true)) \
+ if (likely(!!(condition_) == !!expected_true_)) \
break; \
\
_KUNIT_FAILED(test, \
assert_type, \
kunit_unary_assert, \
kunit_unary_assert_format, \
- KUNIT_INIT_UNARY_ASSERT_STRUCT(#condition, \
- expected_true), \
+ KUNIT_INIT_ASSERT(.condition = #condition_, \
+ .expected_true = expected_true_), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -590,9 +597,9 @@ do { \
assert_type, \
assert_class, \
format_func, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
+ KUNIT_INIT_ASSERT(.text = &__text, \
+ .left_value = __left, \
+ .right_value = __right), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -651,9 +658,42 @@ do { \
assert_type, \
kunit_binary_str_assert, \
kunit_binary_str_assert_format, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
+ KUNIT_INIT_ASSERT(.text = &__text, \
+ .left_value = __left, \
+ .right_value = __right), \
+ fmt, \
+ ##__VA_ARGS__); \
+} while (0)
+
+#define KUNIT_MEM_ASSERTION(test, \
+ assert_type, \
+ left, \
+ op, \
+ right, \
+ size_, \
+ fmt, \
+ ...) \
+do { \
+ const void *__left = (left); \
+ const void *__right = (right); \
+ const size_t __size = (size_); \
+ static const struct kunit_binary_assert_text __text = { \
+ .operation = #op, \
+ .left_text = #left, \
+ .right_text = #right, \
+ }; \
+ \
+ if (likely(memcmp(__left, __right, __size) op 0)) \
+ break; \
+ \
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ kunit_mem_assert, \
+ kunit_mem_assert_format, \
+ KUNIT_INIT_ASSERT(.text = &__text, \
+ .left_value = __left, \
+ .right_value = __right, \
+ .size = __size), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -673,7 +713,7 @@ do { \
assert_type, \
kunit_ptr_not_err_assert, \
kunit_ptr_not_err_assert_format, \
- KUNIT_INIT_PTR_NOT_ERR_STRUCT(#ptr, __ptr), \
+ KUNIT_INIT_ASSERT(.text = #ptr, .value = __ptr), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -929,6 +969,60 @@ do { \
##__VA_ARGS__)
/**
+ * KUNIT_EXPECT_MEMEQ() - Expects that the first @size bytes of @left and @right are equal.
+ * @test: The test context object.
+ * @left: An arbitrary expression that evaluates to the specified size.
+ * @right: An arbitrary expression that evaluates to the specified size.
+ * @size: Number of bytes compared.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, !memcmp((@left), (@right), (@size))). See
+ * KUNIT_EXPECT_TRUE() for more information.
+ *
+ * Although this expectation works for any memory block, it is not recommended
+ * for comparing more structured data, such as structs. This expectation is
+ * recommended for comparing, for example, data arrays.
+ */
+#define KUNIT_EXPECT_MEMEQ(test, left, right, size) \
+ KUNIT_EXPECT_MEMEQ_MSG(test, left, right, size, NULL)
+
+#define KUNIT_EXPECT_MEMEQ_MSG(test, left, right, size, fmt, ...) \
+ KUNIT_MEM_ASSERTION(test, \
+ KUNIT_EXPECTATION, \
+ left, ==, right, \
+ size, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_MEMNEQ() - Expects that the first @size bytes of @left and @right are not equal.
+ * @test: The test context object.
+ * @left: An arbitrary expression that evaluates to the specified size.
+ * @right: An arbitrary expression that evaluates to the specified size.
+ * @size: Number of bytes compared.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * not equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, memcmp((@left), (@right), (@size))). See
+ * KUNIT_EXPECT_TRUE() for more information.
+ *
+ * Although this expectation works for any memory block, it is not recommended
+ * for comparing more structured data, such as structs. This expectation is
+ * recommended for comparing, for example, data arrays.
+ */
+#define KUNIT_EXPECT_MEMNEQ(test, left, right, size) \
+ KUNIT_EXPECT_MEMNEQ_MSG(test, left, right, size, NULL)
+
+#define KUNIT_EXPECT_MEMNEQ_MSG(test, left, right, size, fmt, ...) \
+ KUNIT_MEM_ASSERTION(test, \
+ KUNIT_EXPECTATION, \
+ left, !=, right, \
+ size, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
* KUNIT_EXPECT_NULL() - Expects that @ptr is null.
* @test: The test context object.
* @ptr: an arbitrary pointer.
diff --git a/include/kunit/visibility.h b/include/kunit/visibility.h
new file mode 100644
index 000000000000..0dfe35feeec6
--- /dev/null
+++ b/include/kunit/visibility.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit API to allow symbols to be conditionally visible during KUnit
+ * testing
+ *
+ * Copyright (C) 2022, Google LLC.
+ * Author: Rae Moar <rmoar@google.com>
+ */
+
+#ifndef _KUNIT_VISIBILITY_H
+#define _KUNIT_VISIBILITY_H
+
+#if IS_ENABLED(CONFIG_KUNIT)
+ /**
+ * VISIBLE_IF_KUNIT - A macro that sets symbols to be static if
+ * CONFIG_KUNIT is not enabled. Otherwise if CONFIG_KUNIT is enabled
+ * there is no change to the symbol definition.
+ */
+ #define VISIBLE_IF_KUNIT
+ /**
+ * EXPORT_SYMBOL_IF_KUNIT(symbol) - Exports symbol into
+ * EXPORTED_FOR_KUNIT_TESTING namespace only if CONFIG_KUNIT is
+ * enabled. Must use MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING)
+ * in test file in order to use symbols.
+ */
+ #define EXPORT_SYMBOL_IF_KUNIT(symbol) EXPORT_SYMBOL_NS(symbol, \
+ EXPORTED_FOR_KUNIT_TESTING)
+#else
+ #define VISIBLE_IF_KUNIT static
+ #define EXPORT_SYMBOL_IF_KUNIT(symbol)
+#endif
+
+#endif /* _KUNIT_VISIBILITY_H */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 3015235d65e3..5e6a876e17ba 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -586,6 +586,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
#define OSC_SB_CPC_FLEXIBLE_ADR_SPACE 0x00004000
#define OSC_SB_NATIVE_USB4_SUPPORT 0x00040000
#define OSC_SB_PRM_SUPPORT 0x00200000
+#define OSC_SB_FFH_OPR_SUPPORT 0x00400000
extern bool osc_sb_apei_support_acked;
extern bool osc_pc_lpi_support_confirmed;
@@ -1136,6 +1137,7 @@ int acpi_subsys_freeze(struct device *dev);
int acpi_subsys_poweroff(struct device *dev);
void acpi_ec_mark_gpe_for_wake(void);
void acpi_ec_set_gpe_wake_mask(u8 action);
+int acpi_subsys_restore_early(struct device *dev);
#else
static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
static inline void acpi_subsys_complete(struct device *dev) {}
@@ -1144,6 +1146,7 @@ static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; }
static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
static inline int acpi_subsys_poweroff(struct device *dev) { return 0; }
+static inline int acpi_subsys_restore_early(struct device *dev) { return 0; }
static inline void acpi_ec_mark_gpe_for_wake(void) {}
static inline void acpi_ec_set_gpe_wake_mask(u8 action) {}
#endif
@@ -1488,6 +1491,16 @@ void acpi_init_pcc(void);
static inline void acpi_init_pcc(void) { }
#endif
+#ifdef CONFIG_ACPI_FFH
+void acpi_init_ffh(void);
+extern int acpi_ffh_address_space_arch_setup(void *handler_ctxt,
+ void **region_ctxt);
+extern int acpi_ffh_address_space_arch_handler(acpi_integer *value,
+ void *region_context);
+#else
+static inline void acpi_init_ffh(void) { }
+#endif
+
#ifdef CONFIG_ACPI
extern void acpi_device_notify(struct device *dev);
extern void acpi_device_notify_remove(struct device *dev);
diff --git a/include/linux/acpi_apmt.h b/include/linux/acpi_apmt.h
new file mode 100644
index 000000000000..40bd634d082f
--- /dev/null
+++ b/include/linux/acpi_apmt.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * ARM CoreSight PMU driver.
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
+ *
+ */
+
+#ifndef __ACPI_APMT_H__
+#define __ACPI_APMT_H__
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_APMT
+void acpi_apmt_init(void);
+#else
+static inline void acpi_apmt_init(void) { }
+#endif /* CONFIG_ACPI_APMT */
+
+#endif /* __ACPI_APMT_H__ */
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index 5f02d2e6b9d9..c87aeecaa9b2 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -11,6 +11,89 @@
#include <linux/types.h>
#include <linux/uuid.h>
+#define FFA_SMC(calling_convention, func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \
+ ARM_SMCCC_OWNER_STANDARD, (func_num))
+
+#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
+#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
+
+#define FFA_ERROR FFA_SMC_32(0x60)
+#define FFA_SUCCESS FFA_SMC_32(0x61)
+#define FFA_INTERRUPT FFA_SMC_32(0x62)
+#define FFA_VERSION FFA_SMC_32(0x63)
+#define FFA_FEATURES FFA_SMC_32(0x64)
+#define FFA_RX_RELEASE FFA_SMC_32(0x65)
+#define FFA_RXTX_MAP FFA_SMC_32(0x66)
+#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66)
+#define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
+#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
+#define FFA_ID_GET FFA_SMC_32(0x69)
+#define FFA_MSG_POLL FFA_SMC_32(0x6A)
+#define FFA_MSG_WAIT FFA_SMC_32(0x6B)
+#define FFA_YIELD FFA_SMC_32(0x6C)
+#define FFA_RUN FFA_SMC_32(0x6D)
+#define FFA_MSG_SEND FFA_SMC_32(0x6E)
+#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F)
+#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F)
+#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70)
+#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70)
+#define FFA_MEM_DONATE FFA_SMC_32(0x71)
+#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71)
+#define FFA_MEM_LEND FFA_SMC_32(0x72)
+#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72)
+#define FFA_MEM_SHARE FFA_SMC_32(0x73)
+#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73)
+#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74)
+#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74)
+#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75)
+#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76)
+#define FFA_MEM_RECLAIM FFA_SMC_32(0x77)
+#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78)
+#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79)
+#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A)
+#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B)
+#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C)
+
+/*
+ * For some calls it is necessary to use SMC64 to pass or return 64-bit values.
+ * For such calls FFA_FN_NATIVE(name) will choose the appropriate
+ * (native-width) function ID.
+ */
+#ifdef CONFIG_64BIT
+#define FFA_FN_NATIVE(name) FFA_FN64_##name
+#else
+#define FFA_FN_NATIVE(name) FFA_##name
+#endif
+
+/* FFA error codes. */
+#define FFA_RET_SUCCESS (0)
+#define FFA_RET_NOT_SUPPORTED (-1)
+#define FFA_RET_INVALID_PARAMETERS (-2)
+#define FFA_RET_NO_MEMORY (-3)
+#define FFA_RET_BUSY (-4)
+#define FFA_RET_INTERRUPTED (-5)
+#define FFA_RET_DENIED (-6)
+#define FFA_RET_RETRY (-7)
+#define FFA_RET_ABORTED (-8)
+
+/* FFA version encoding */
+#define FFA_MAJOR_VERSION_MASK GENMASK(30, 16)
+#define FFA_MINOR_VERSION_MASK GENMASK(15, 0)
+#define FFA_MAJOR_VERSION(x) ((u16)(FIELD_GET(FFA_MAJOR_VERSION_MASK, (x))))
+#define FFA_MINOR_VERSION(x) ((u16)(FIELD_GET(FFA_MINOR_VERSION_MASK, (x))))
+#define FFA_PACK_VERSION_INFO(major, minor) \
+ (FIELD_PREP(FFA_MAJOR_VERSION_MASK, (major)) | \
+ FIELD_PREP(FFA_MINOR_VERSION_MASK, (minor)))
+#define FFA_VERSION_1_0 FFA_PACK_VERSION_INFO(1, 0)
+
+/**
+ * FF-A specification mentions explicitly about '4K pages'. This should
+ * not be confused with the kernel PAGE_SIZE, which is the translation
+ * granule kernel is configured and may be one among 4K, 16K and 64K.
+ */
+#define FFA_PAGE_SIZE SZ_4K
+
/* FFA Bus/Device/Driver related */
struct ffa_device {
int vm_id;
@@ -161,11 +244,11 @@ struct ffa_mem_region_attributes {
*/
#define FFA_MEM_RETRIEVE_SELF_BORROWER BIT(0)
u8 flag;
- u32 composite_off;
/*
* Offset in bytes from the start of the outer `ffa_memory_region` to
* an `struct ffa_mem_region_addr_range`.
*/
+ u32 composite_off;
u64 reserved;
};
diff --git a/include/linux/ata.h b/include/linux/ata.h
index e3050e153a71..0c18499f60b6 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -615,15 +615,6 @@ static inline bool ata_id_has_flush(const u16 *id)
return id[ATA_ID_COMMAND_SET_2] & (1 << 12);
}
-static inline bool ata_id_flush_enabled(const u16 *id)
-{
- if (ata_id_has_flush(id) == 0)
- return false;
- if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
- return false;
- return id[ATA_ID_CFS_ENABLE_2] & (1 << 12);
-}
-
static inline bool ata_id_has_flush_ext(const u16 *id)
{
if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -631,19 +622,6 @@ static inline bool ata_id_has_flush_ext(const u16 *id)
return id[ATA_ID_COMMAND_SET_2] & (1 << 13);
}
-static inline bool ata_id_flush_ext_enabled(const u16 *id)
-{
- if (ata_id_has_flush_ext(id) == 0)
- return false;
- if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
- return false;
- /*
- * some Maxtor disks have bit 13 defined incorrectly
- * so check bit 10 too
- */
- return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
-}
-
static inline u32 ata_id_logical_sector_size(const u16 *id)
{
/* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
@@ -698,15 +676,6 @@ static inline bool ata_id_has_lba48(const u16 *id)
return id[ATA_ID_COMMAND_SET_2] & (1 << 10);
}
-static inline bool ata_id_lba48_enabled(const u16 *id)
-{
- if (ata_id_has_lba48(id) == 0)
- return false;
- if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
- return false;
- return id[ATA_ID_CFS_ENABLE_2] & (1 << 10);
-}
-
static inline bool ata_id_hpa_enabled(const u16 *id)
{
/* Yes children, word 83 valid bits cover word 82 data */
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
index 53b31f69b74a..7615f8d7b1ed 100644
--- a/include/linux/bcm47xx_nvram.h
+++ b/include/linux/bcm47xx_nvram.h
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#ifdef CONFIG_BCM47XX_NVRAM
+int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size);
int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
int bcm47xx_nvram_gpio_pin(const char *name);
@@ -20,6 +21,11 @@ static inline void bcm47xx_nvram_release_contents(char *nvram)
vfree(nvram);
};
#else
+static inline int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start,
+ size_t res_size)
+{
+ return -ENOTSUPP;
+}
static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
{
return -ENOTSUPP;
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2c5806997bbf..b231a665682a 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -475,8 +475,6 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty);
extern void bio_set_pages_dirty(struct bio *bio);
extern void bio_check_pages_dirty(struct bio *bio);
-extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
- struct bio *src, struct bvec_iter *src_iter);
extern void bio_copy_data(struct bio *dst, struct bio *src);
extern void bio_free_pages(struct bio *bio);
void guard_bio_eod(struct bio *bio);
diff --git a/include/linux/blk-crypto-profile.h b/include/linux/blk-crypto-profile.h
index bbab65bd5428..e6802b69cdd6 100644
--- a/include/linux/blk-crypto-profile.h
+++ b/include/linux/blk-crypto-profile.h
@@ -138,18 +138,6 @@ int devm_blk_crypto_profile_init(struct device *dev,
unsigned int blk_crypto_keyslot_index(struct blk_crypto_keyslot *slot);
-blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile,
- const struct blk_crypto_key *key,
- struct blk_crypto_keyslot **slot_ptr);
-
-void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot);
-
-bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,
- const struct blk_crypto_config *cfg);
-
-int __blk_crypto_evict_key(struct blk_crypto_profile *profile,
- const struct blk_crypto_key *key);
-
void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile);
void blk_crypto_profile_destroy(struct blk_crypto_profile *profile);
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
index 69b24fe92cbf..1e3e5d0adf12 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -13,6 +13,7 @@ enum blk_crypto_mode_num {
BLK_ENCRYPTION_MODE_AES_256_XTS,
BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV,
BLK_ENCRYPTION_MODE_ADIANTUM,
+ BLK_ENCRYPTION_MODE_SM4_XTS,
BLK_ENCRYPTION_MODE_MAX,
};
@@ -71,9 +72,6 @@ struct bio_crypt_ctx {
#include <linux/blk_types.h>
#include <linux/blkdev.h>
-struct request;
-struct request_queue;
-
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
static inline bool bio_has_crypt_ctx(struct bio *bio)
@@ -94,13 +92,15 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key, const u8 *raw_key,
unsigned int dun_bytes,
unsigned int data_unit_size);
-int blk_crypto_start_using_key(const struct blk_crypto_key *key,
- struct request_queue *q);
+int blk_crypto_start_using_key(struct block_device *bdev,
+ const struct blk_crypto_key *key);
-int blk_crypto_evict_key(struct request_queue *q,
+int blk_crypto_evict_key(struct block_device *bdev,
const struct blk_crypto_key *key);
-bool blk_crypto_config_supported(struct request_queue *q,
+bool blk_crypto_config_supported_natively(struct block_device *bdev,
+ const struct blk_crypto_config *cfg);
+bool blk_crypto_config_supported(struct block_device *bdev,
const struct blk_crypto_config *cfg);
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index d6119c5d1069..779fba613bd0 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -7,6 +7,7 @@
#include <linux/lockdep.h>
#include <linux/scatterlist.h>
#include <linux/prefetch.h>
+#include <linux/srcu.h>
struct blk_mq_tags;
struct blk_flush_queue;
@@ -140,7 +141,6 @@ struct request {
struct blk_crypto_keyslot *crypt_keyslot;
#endif
- unsigned short write_hint;
unsigned short ioprio;
enum mq_rq_state state;
@@ -501,6 +501,8 @@ enum hctx_type {
* @tag_list_lock: Serializes tag_list accesses.
* @tag_list: List of the request queues that use this tag set. See also
* request_queue.tag_set_list.
+ * @srcu: Use as lock when type of the request queue is blocking
+ * (BLK_MQ_F_BLOCKING).
*/
struct blk_mq_tag_set {
struct blk_mq_queue_map map[HCTX_MAX_TYPES];
@@ -521,6 +523,7 @@ struct blk_mq_tag_set {
struct mutex tag_list_lock;
struct list_head tag_list;
+ struct srcu_struct *srcu;
};
/**
@@ -878,7 +881,9 @@ void blk_mq_start_hw_queues(struct request_queue *q);
void blk_mq_start_stopped_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async);
void blk_mq_quiesce_queue(struct request_queue *q);
-void blk_mq_wait_quiesce_done(struct request_queue *q);
+void blk_mq_wait_quiesce_done(struct blk_mq_tag_set *set);
+void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set);
+void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set);
void blk_mq_unquiesce_queue(struct request_queue *q);
void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index e0b098089ef2..99be590f952f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -472,13 +472,6 @@ static inline enum req_op bio_op(const struct bio *bio)
return bio->bi_opf & REQ_OP_MASK;
}
-/* obsolete, don't use in new code */
-static inline void bio_set_op_attrs(struct bio *bio, enum req_op op,
- blk_opf_t op_flags)
-{
- bio->bi_opf = op | op_flags;
-}
-
static inline bool op_is_write(blk_opf_t op)
{
return !!(op & (__force blk_opf_t)1);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 50e358a19d98..301cf1cf4f2f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -22,7 +22,6 @@
#include <linux/blkzoned.h>
#include <linux/sched.h>
#include <linux/sbitmap.h>
-#include <linux/srcu.h>
#include <linux/uuid.h>
#include <linux/xarray.h>
@@ -156,6 +155,7 @@ struct gendisk {
unsigned open_partitions; /* number of open partitions */
struct backing_dev_info *bdi;
+ struct kobject queue_kobj; /* the queue/ directory */
struct kobject *slave_dir;
#ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
struct list_head slave_bdevs;
@@ -311,6 +311,13 @@ struct queue_limits {
unsigned char discard_misaligned;
unsigned char raid_partial_stripes_expensive;
enum blk_zoned_model zoned;
+
+ /*
+ * Drivers that set dma_alignment to less than 511 must be prepared to
+ * handle individual bvec's that are not a multiple of a SECTOR_SIZE
+ * due to possible offsets.
+ */
+ unsigned int dma_alignment;
};
typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
@@ -431,10 +438,7 @@ struct request_queue {
struct gendisk *disk;
- /*
- * queue kobject
- */
- struct kobject kobj;
+ refcount_t refs;
/*
* mq queue kobject
@@ -456,12 +460,6 @@ struct request_queue {
unsigned long nr_requests; /* Max # of requests */
unsigned int dma_pad_mask;
- /*
- * Drivers that set dma_alignment to less than 511 must be prepared to
- * handle individual bvec's that are not a multiple of a SECTOR_SIZE
- * due to possible offsets.
- */
- unsigned int dma_alignment;
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
struct blk_crypto_profile *crypto_profile;
@@ -543,18 +541,11 @@ struct request_queue {
struct mutex debugfs_mutex;
bool mq_sysfs_init_done;
-
- /**
- * @srcu: Sleepable RCU. Use as lock when type of the request queue
- * is blocking (BLK_MQ_F_BLOCKING). Must be the last member
- */
- struct srcu_struct srcu[];
};
/* Keep blk_queue_flag_name[] in sync with the definitions below */
#define QUEUE_FLAG_STOPPED 0 /* queue is stopped */
#define QUEUE_FLAG_DYING 1 /* queue being torn down */
-#define QUEUE_FLAG_HAS_SRCU 2 /* SRCU is allocated */
#define QUEUE_FLAG_NOMERGES 3 /* disable merge attempts */
#define QUEUE_FLAG_SAME_COMP 4 /* complete on same CPU-group */
#define QUEUE_FLAG_FAIL_IO 5 /* fake timeout */
@@ -579,6 +570,7 @@ struct request_queue {
#define QUEUE_FLAG_HCTX_ACTIVE 28 /* at least one blk-mq hctx is active */
#define QUEUE_FLAG_NOWAIT 29 /* device supports NOWAIT */
#define QUEUE_FLAG_SQ_SCHED 30 /* single queue style io dispatch */
+#define QUEUE_FLAG_SKIP_TAGSET_QUIESCE 31 /* quiesce_tagset skip the queue*/
#define QUEUE_FLAG_MQ_DEFAULT ((1UL << QUEUE_FLAG_IO_STAT) | \
(1UL << QUEUE_FLAG_SAME_COMP) | \
@@ -590,7 +582,6 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
#define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
#define blk_queue_dying(q) test_bit(QUEUE_FLAG_DYING, &(q)->queue_flags)
-#define blk_queue_has_srcu(q) test_bit(QUEUE_FLAG_HAS_SRCU, &(q)->queue_flags)
#define blk_queue_init_done(q) test_bit(QUEUE_FLAG_INIT_DONE, &(q)->queue_flags)
#define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
#define blk_queue_noxmerges(q) \
@@ -619,6 +610,8 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
#define blk_queue_pm_only(q) atomic_read(&(q)->pm_only)
#define blk_queue_registered(q) test_bit(QUEUE_FLAG_REGISTERED, &(q)->queue_flags)
#define blk_queue_sq_sched(q) test_bit(QUEUE_FLAG_SQ_SCHED, &(q)->queue_flags)
+#define blk_queue_skip_tagset_quiesce(q) \
+ test_bit(QUEUE_FLAG_SKIP_TAGSET_QUIESCE, &(q)->queue_flags)
extern void blk_set_pm_only(struct request_queue *q);
extern void blk_clear_pm_only(struct request_queue *q);
@@ -839,7 +832,6 @@ void set_capacity(struct gendisk *disk, sector_t size);
#ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk);
-int bd_register_pending_holders(struct gendisk *disk);
#else
static inline int bd_link_disk_holder(struct block_device *bdev,
struct gendisk *disk)
@@ -850,10 +842,6 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev,
struct gendisk *disk)
{
}
-static inline int bd_register_pending_holders(struct gendisk *disk)
-{
- return 0;
-}
#endif /* CONFIG_BLOCK_HOLDER_DEPRECATED */
dev_t part_devt(struct gendisk *disk, u8 partno);
@@ -944,7 +932,6 @@ extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
extern void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt);
extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
extern void blk_set_queue_depth(struct request_queue *q, unsigned int depth);
-extern void blk_set_default_limits(struct queue_limits *lim);
extern void blk_set_stacking_limits(struct queue_limits *lim);
extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
sector_t offset);
@@ -1324,7 +1311,7 @@ static inline sector_t bdev_zone_sectors(struct block_device *bdev)
static inline int queue_dma_alignment(const struct request_queue *q)
{
- return q ? q->dma_alignment : 511;
+ return q ? q->limits.dma_alignment : 511;
}
static inline unsigned int bdev_dma_alignment(struct block_device *bdev)
@@ -1349,12 +1336,7 @@ static inline int blk_rq_aligned(struct request_queue *q, unsigned long addr,
/* assumes size > 256 */
static inline unsigned int blksize_bits(unsigned int size)
{
- unsigned int bits = 8;
- do {
- bits++;
- size >>= 1;
- } while (size > 256);
- return bits;
+ return order_base_2(size >> SECTOR_SHIFT) + SECTOR_SHIFT;
}
static inline unsigned int block_size(struct block_device *bdev)
@@ -1413,7 +1395,6 @@ struct block_device_operations {
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
int (*report_zones)(struct gendisk *, sector_t sector,
unsigned int nr_zones, report_zones_cb cb, void *data);
- char *(*devnode)(struct gendisk *disk, umode_t *mode);
/* returns the length of the identifier or a negative errno: */
int (*get_unique_id)(struct gendisk *disk, u8 id[16],
enum blk_unique_id id_type);
@@ -1458,7 +1439,6 @@ unsigned long bdev_start_io_acct(struct block_device *bdev,
void bdev_end_io_acct(struct block_device *bdev, enum req_op op,
unsigned long start_time);
-void bio_start_io_acct_time(struct bio *bio, unsigned long start_time);
unsigned long bio_start_io_acct(struct bio *bio);
void bio_end_io_acct_remapped(struct bio *bio, unsigned long start_time,
struct block_device *orig_bdev);
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0566705c1d4e..c1bd1bd10506 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -27,7 +27,7 @@
#include <linux/bpfptr.h>
#include <linux/btf.h>
#include <linux/rcupdate_trace.h>
-#include <linux/init.h>
+#include <linux/static_call.h>
struct bpf_verifier_env;
struct bpf_verifier_log;
@@ -315,7 +315,7 @@ static inline void __copy_map_value(struct bpf_map *map, void *dst, void *src, b
u32 next_off = map->off_arr->field_off[i];
memcpy(dst + curr_off, src + curr_off, next_off - curr_off);
- curr_off += map->off_arr->field_sz[i];
+ curr_off = next_off + map->off_arr->field_sz[i];
}
memcpy(dst + curr_off, src + curr_off, map->value_size - curr_off);
}
@@ -344,7 +344,7 @@ static inline void zero_map_value(struct bpf_map *map, void *dst)
u32 next_off = map->off_arr->field_off[i];
memset(dst + curr_off, 0, next_off - curr_off);
- curr_off += map->off_arr->field_sz[i];
+ curr_off = next_off + map->off_arr->field_sz[i];
}
memset(dst + curr_off, 0, map->value_size - curr_off);
}
@@ -954,6 +954,10 @@ struct bpf_dispatcher {
void *rw_image;
u32 image_off;
struct bpf_ksym ksym;
+#ifdef CONFIG_HAVE_STATIC_CALL
+ struct static_call_key *sc_key;
+ void *sc_tramp;
+#endif
};
static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func(
@@ -971,7 +975,33 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
struct bpf_attach_target_info *tgt_info);
void bpf_trampoline_put(struct bpf_trampoline *tr);
int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_funcs);
-int __init bpf_arch_init_dispatcher_early(void *ip);
+
+/*
+ * When the architecture supports STATIC_CALL replace the bpf_dispatcher_fn
+ * indirection with a direct call to the bpf program. If the architecture does
+ * not have STATIC_CALL, avoid a double-indirection.
+ */
+#ifdef CONFIG_HAVE_STATIC_CALL
+
+#define __BPF_DISPATCHER_SC_INIT(_name) \
+ .sc_key = &STATIC_CALL_KEY(_name), \
+ .sc_tramp = STATIC_CALL_TRAMP_ADDR(_name),
+
+#define __BPF_DISPATCHER_SC(name) \
+ DEFINE_STATIC_CALL(bpf_dispatcher_##name##_call, bpf_dispatcher_nop_func)
+
+#define __BPF_DISPATCHER_CALL(name) \
+ static_call(bpf_dispatcher_##name##_call)(ctx, insnsi, bpf_func)
+
+#define __BPF_DISPATCHER_UPDATE(_d, _new) \
+ __static_call_update((_d)->sc_key, (_d)->sc_tramp, (_new))
+
+#else
+#define __BPF_DISPATCHER_SC_INIT(name)
+#define __BPF_DISPATCHER_SC(name)
+#define __BPF_DISPATCHER_CALL(name) bpf_func(ctx, insnsi)
+#define __BPF_DISPATCHER_UPDATE(_d, _new)
+#endif
#define BPF_DISPATCHER_INIT(_name) { \
.mutex = __MUTEX_INITIALIZER(_name.mutex), \
@@ -984,34 +1014,21 @@ int __init bpf_arch_init_dispatcher_early(void *ip);
.name = #_name, \
.lnode = LIST_HEAD_INIT(_name.ksym.lnode), \
}, \
+ __BPF_DISPATCHER_SC_INIT(_name##_call) \
}
-#define BPF_DISPATCHER_INIT_CALL(_name) \
- static int __init _name##_init(void) \
- { \
- return bpf_arch_init_dispatcher_early(_name##_func); \
- } \
- early_initcall(_name##_init)
-
-#ifdef CONFIG_X86_64
-#define BPF_DISPATCHER_ATTRIBUTES __attribute__((patchable_function_entry(5)))
-#else
-#define BPF_DISPATCHER_ATTRIBUTES
-#endif
-
#define DEFINE_BPF_DISPATCHER(name) \
- notrace BPF_DISPATCHER_ATTRIBUTES \
+ __BPF_DISPATCHER_SC(name); \
noinline __nocfi unsigned int bpf_dispatcher_##name##_func( \
const void *ctx, \
const struct bpf_insn *insnsi, \
bpf_func_t bpf_func) \
{ \
- return bpf_func(ctx, insnsi); \
+ return __BPF_DISPATCHER_CALL(name); \
} \
EXPORT_SYMBOL(bpf_dispatcher_##name##_func); \
struct bpf_dispatcher bpf_dispatcher_##name = \
- BPF_DISPATCHER_INIT(bpf_dispatcher_##name); \
- BPF_DISPATCHER_INIT_CALL(bpf_dispatcher_##name);
+ BPF_DISPATCHER_INIT(bpf_dispatcher_##name);
#define DECLARE_BPF_DISPATCHER(name) \
unsigned int bpf_dispatcher_##name##_func( \
@@ -1019,6 +1036,7 @@ int __init bpf_arch_init_dispatcher_early(void *ip);
const struct bpf_insn *insnsi, \
bpf_func_t bpf_func); \
extern struct bpf_dispatcher bpf_dispatcher_##name;
+
#define BPF_DISPATCHER_FUNC(name) bpf_dispatcher_##name##_func
#define BPF_DISPATCHER_PTR(name) (&bpf_dispatcher_##name)
void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 58f5431a5559..982ba245eb41 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -152,6 +152,22 @@ static inline bool can_is_canxl_dev_mtu(unsigned int mtu)
return (mtu >= CANXL_MIN_MTU && mtu <= CANXL_MAX_MTU);
}
+/* drop skb if it does not contain a valid CAN frame for sending */
+static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ struct can_priv *priv = netdev_priv(dev);
+
+ if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ netdev_info_once(dev,
+ "interface in listen only mode, dropping skb\n");
+ kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return true;
+ }
+
+ return can_dropped_invalid_skb(dev, skb);
+}
+
void can_setup(struct net_device *dev);
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
diff --git a/include/linux/can/platform/sja1000.h b/include/linux/can/platform/sja1000.h
index 5755ae5a4712..6a869682c120 100644
--- a/include/linux/can/platform/sja1000.h
+++ b/include/linux/can/platform/sja1000.h
@@ -14,7 +14,7 @@
#define OCR_MODE_TEST 0x01
#define OCR_MODE_NORMAL 0x02
#define OCR_MODE_CLOCK 0x03
-#define OCR_MODE_MASK 0x07
+#define OCR_MODE_MASK 0x03
#define OCR_TX0_INVERT 0x04
#define OCR_TX0_PULLDOWN 0x08
#define OCR_TX0_PULLUP 0x10
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 528bd44b59e2..3410aecffdb4 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -68,6 +68,7 @@ struct css_task_iter {
struct list_head iters_node; /* css_set->task_iters */
};
+extern struct file_system_type cgroup_fs_type;
extern struct cgroup_root cgrp_dfl_root;
extern struct css_set init_css_set;
@@ -309,72 +310,25 @@ void css_task_iter_end(struct css_task_iter *it);
* Inline functions.
*/
+#ifdef CONFIG_DEBUG_CGROUP_REF
+void css_get(struct cgroup_subsys_state *css);
+void css_get_many(struct cgroup_subsys_state *css, unsigned int n);
+bool css_tryget(struct cgroup_subsys_state *css);
+bool css_tryget_online(struct cgroup_subsys_state *css);
+void css_put(struct cgroup_subsys_state *css);
+void css_put_many(struct cgroup_subsys_state *css, unsigned int n);
+#else
+#define CGROUP_REF_FN_ATTRS static inline
+#define CGROUP_REF_EXPORT(fn)
+#include <linux/cgroup_refcnt.h>
+#endif
+
static inline u64 cgroup_id(const struct cgroup *cgrp)
{
return cgrp->kn->id;
}
/**
- * css_get - obtain a reference on the specified css
- * @css: target css
- *
- * The caller must already have a reference.
- */
-static inline void css_get(struct cgroup_subsys_state *css)
-{
- if (!(css->flags & CSS_NO_REF))
- percpu_ref_get(&css->refcnt);
-}
-
-/**
- * css_get_many - obtain references on the specified css
- * @css: target css
- * @n: number of references to get
- *
- * The caller must already have a reference.
- */
-static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
-{
- if (!(css->flags & CSS_NO_REF))
- percpu_ref_get_many(&css->refcnt, n);
-}
-
-/**
- * css_tryget - try to obtain a reference on the specified css
- * @css: target css
- *
- * Obtain a reference on @css unless it already has reached zero and is
- * being released. This function doesn't care whether @css is on or
- * offline. The caller naturally needs to ensure that @css is accessible
- * but doesn't have to be holding a reference on it - IOW, RCU protected
- * access is good enough for this function. Returns %true if a reference
- * count was successfully obtained; %false otherwise.
- */
-static inline bool css_tryget(struct cgroup_subsys_state *css)
-{
- if (!(css->flags & CSS_NO_REF))
- return percpu_ref_tryget(&css->refcnt);
- return true;
-}
-
-/**
- * css_tryget_online - try to obtain a reference on the specified css if online
- * @css: target css
- *
- * Obtain a reference on @css if it's online. The caller naturally needs
- * to ensure that @css is accessible but doesn't have to be holding a
- * reference on it - IOW, RCU protected access is good enough for this
- * function. Returns %true if a reference count was successfully obtained;
- * %false otherwise.
- */
-static inline bool css_tryget_online(struct cgroup_subsys_state *css)
-{
- if (!(css->flags & CSS_NO_REF))
- return percpu_ref_tryget_live(&css->refcnt);
- return true;
-}
-
-/**
* css_is_dying - test whether the specified css is dying
* @css: target css
*
@@ -394,31 +348,6 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css)
return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
}
-/**
- * css_put - put a css reference
- * @css: target css
- *
- * Put a reference obtained via css_get() and css_tryget_online().
- */
-static inline void css_put(struct cgroup_subsys_state *css)
-{
- if (!(css->flags & CSS_NO_REF))
- percpu_ref_put(&css->refcnt);
-}
-
-/**
- * css_put_many - put css references
- * @css: target css
- * @n: number of references to put
- *
- * Put references obtained via css_get() and css_tryget_online().
- */
-static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
-{
- if (!(css->flags & CSS_NO_REF))
- percpu_ref_put_many(&css->refcnt, n);
-}
-
static inline void cgroup_get(struct cgroup *cgrp)
{
css_get(&cgrp->self);
diff --git a/include/linux/cgroup_refcnt.h b/include/linux/cgroup_refcnt.h
new file mode 100644
index 000000000000..2eea0a69ecfc
--- /dev/null
+++ b/include/linux/cgroup_refcnt.h
@@ -0,0 +1,96 @@
+/**
+ * css_get - obtain a reference on the specified css
+ * @css: target css
+ *
+ * The caller must already have a reference.
+ */
+CGROUP_REF_FN_ATTRS
+void css_get(struct cgroup_subsys_state *css)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_get(&css->refcnt);
+}
+CGROUP_REF_EXPORT(css_get)
+
+/**
+ * css_get_many - obtain references on the specified css
+ * @css: target css
+ * @n: number of references to get
+ *
+ * The caller must already have a reference.
+ */
+CGROUP_REF_FN_ATTRS
+void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_get_many(&css->refcnt, n);
+}
+CGROUP_REF_EXPORT(css_get_many)
+
+/**
+ * css_tryget - try to obtain a reference on the specified css
+ * @css: target css
+ *
+ * Obtain a reference on @css unless it already has reached zero and is
+ * being released. This function doesn't care whether @css is on or
+ * offline. The caller naturally needs to ensure that @css is accessible
+ * but doesn't have to be holding a reference on it - IOW, RCU protected
+ * access is good enough for this function. Returns %true if a reference
+ * count was successfully obtained; %false otherwise.
+ */
+CGROUP_REF_FN_ATTRS
+bool css_tryget(struct cgroup_subsys_state *css)
+{
+ if (!(css->flags & CSS_NO_REF))
+ return percpu_ref_tryget(&css->refcnt);
+ return true;
+}
+CGROUP_REF_EXPORT(css_tryget)
+
+/**
+ * css_tryget_online - try to obtain a reference on the specified css if online
+ * @css: target css
+ *
+ * Obtain a reference on @css if it's online. The caller naturally needs
+ * to ensure that @css is accessible but doesn't have to be holding a
+ * reference on it - IOW, RCU protected access is good enough for this
+ * function. Returns %true if a reference count was successfully obtained;
+ * %false otherwise.
+ */
+CGROUP_REF_FN_ATTRS
+bool css_tryget_online(struct cgroup_subsys_state *css)
+{
+ if (!(css->flags & CSS_NO_REF))
+ return percpu_ref_tryget_live(&css->refcnt);
+ return true;
+}
+CGROUP_REF_EXPORT(css_tryget_online)
+
+/**
+ * css_put - put a css reference
+ * @css: target css
+ *
+ * Put a reference obtained via css_get() and css_tryget_online().
+ */
+CGROUP_REF_FN_ATTRS
+void css_put(struct cgroup_subsys_state *css)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_put(&css->refcnt);
+}
+CGROUP_REF_EXPORT(css_put)
+
+/**
+ * css_put_many - put css references
+ * @css: target css
+ * @n: number of references to put
+ *
+ * Put references obtained via css_get() and css_tryget_online().
+ */
+CGROUP_REF_FN_ATTRS
+void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_put_many(&css->refcnt, n);
+}
+CGROUP_REF_EXPORT(css_put_many)
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 594357881b0b..44b1736c95b5 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -126,11 +126,9 @@ struct compat_tms {
#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
-#ifndef compat_sigset_t
typedef struct {
compat_sigset_word sig[_COMPAT_NSIG_WORDS];
} compat_sigset_t;
-#endif
int set_compat_user_sigmask(const compat_sigset_t __user *umask,
size_t sigsetsize);
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 97cfd13bae51..2606711adb18 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -204,8 +204,6 @@ static struct configfs_bin_attribute _pfx##attr_##_name = { \
* group children. default_groups may coexist alongsize make_group() or
* make_item(), but if the group wishes to have only default_groups
* children (disallowing mkdir(2)), it need not provide either function.
- * If the group has commit(), it supports pending and committed (active)
- * items.
*/
struct configfs_item_operations {
void (*release)(struct config_item *);
@@ -216,7 +214,6 @@ struct configfs_item_operations {
struct configfs_group_operations {
struct config_item *(*make_item)(struct config_group *group, const char *name);
struct config_group *(*make_group)(struct config_group *group, const char *name);
- int (*commit_item)(struct config_item *item);
void (*disconnect_notify)(struct config_group *group, struct config_item *item);
void (*drop_item)(struct config_group *group, struct config_item *item);
};
diff --git a/include/linux/console.h b/include/linux/console.h
index 8c1686e2c233..9cea254b34b8 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -15,6 +15,7 @@
#define _LINUX_CONSOLE_H_ 1
#include <linux/atomic.h>
+#include <linux/rculist.h>
#include <linux/types.h>
struct vc_data;
@@ -154,14 +155,132 @@ struct console {
u64 seq;
unsigned long dropped;
void *data;
- struct console *next;
+ struct hlist_node node;
};
+#ifdef CONFIG_LOCKDEP
+extern void lockdep_assert_console_list_lock_held(void);
+#else
+static inline void lockdep_assert_console_list_lock_held(void)
+{
+}
+#endif
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern bool console_srcu_read_lock_is_held(void);
+#else
+static inline bool console_srcu_read_lock_is_held(void)
+{
+ return 1;
+}
+#endif
+
+extern int console_srcu_read_lock(void);
+extern void console_srcu_read_unlock(int cookie);
+
+extern void console_list_lock(void) __acquires(console_mutex);
+extern void console_list_unlock(void) __releases(console_mutex);
+
+extern struct hlist_head console_list;
+
+/**
+ * console_srcu_read_flags - Locklessly read the console flags
+ * @con: struct console pointer of console to read flags from
+ *
+ * This function provides the necessary READ_ONCE() and data_race()
+ * notation for locklessly reading the console flags. The READ_ONCE()
+ * in this function matches the WRITE_ONCE() when @flags are modified
+ * for registered consoles with console_srcu_write_flags().
+ *
+ * Only use this function to read console flags when locklessly
+ * iterating the console list via srcu.
+ *
+ * Context: Any context.
+ */
+static inline short console_srcu_read_flags(const struct console *con)
+{
+ WARN_ON_ONCE(!console_srcu_read_lock_is_held());
+
+ /*
+ * Locklessly reading console->flags provides a consistent
+ * read value because there is at most one CPU modifying
+ * console->flags and that CPU is using only read-modify-write
+ * operations to do so.
+ */
+ return data_race(READ_ONCE(con->flags));
+}
+
+/**
+ * console_srcu_write_flags - Write flags for a registered console
+ * @con: struct console pointer of console to write flags to
+ * @flags: new flags value to write
+ *
+ * Only use this function to write flags for registered consoles. It
+ * requires holding the console_list_lock.
+ *
+ * Context: Any context.
+ */
+static inline void console_srcu_write_flags(struct console *con, short flags)
+{
+ lockdep_assert_console_list_lock_held();
+
+ /* This matches the READ_ONCE() in console_srcu_read_flags(). */
+ WRITE_ONCE(con->flags, flags);
+}
+
+/* Variant of console_is_registered() when the console_list_lock is held. */
+static inline bool console_is_registered_locked(const struct console *con)
+{
+ lockdep_assert_console_list_lock_held();
+ return !hlist_unhashed(&con->node);
+}
+
/*
- * for_each_console() allows you to iterate on each console
+ * console_is_registered - Check if the console is registered
+ * @con: struct console pointer of console to check
+ *
+ * Context: Process context. May sleep while acquiring console list lock.
+ * Return: true if the console is in the console list, otherwise false.
+ *
+ * If false is returned for a console that was previously registered, it
+ * can be assumed that the console's unregistration is fully completed,
+ * including the exit() callback after console list removal.
+ */
+static inline bool console_is_registered(const struct console *con)
+{
+ bool ret;
+
+ console_list_lock();
+ ret = console_is_registered_locked(con);
+ console_list_unlock();
+ return ret;
+}
+
+/**
+ * for_each_console_srcu() - Iterator over registered consoles
+ * @con: struct console pointer used as loop cursor
+ *
+ * Although SRCU guarantees the console list will be consistent, the
+ * struct console fields may be updated by other CPUs while iterating.
+ *
+ * Requires console_srcu_read_lock to be held. Can be invoked from
+ * any context.
+ */
+#define for_each_console_srcu(con) \
+ hlist_for_each_entry_srcu(con, &console_list, node, \
+ console_srcu_read_lock_is_held())
+
+/**
+ * for_each_console() - Iterator over registered consoles
+ * @con: struct console pointer used as loop cursor
+ *
+ * The console list and the console->flags are immutable while iterating.
+ *
+ * Requires console_list_lock to be held.
*/
-#define for_each_console(con) \
- for (con = console_drivers; con != NULL; con = con->next)
+#define for_each_console(con) \
+ lockdep_assert_console_list_lock_held(); \
+ hlist_for_each_entry(con, &console_list, node)
extern int console_set_on_cmdline;
extern struct console *early_console;
@@ -172,9 +291,9 @@ enum con_flush_mode {
};
extern int add_preferred_console(char *name, int idx, char *options);
+extern void console_force_preferred_locked(struct console *con);
extern void register_console(struct console *);
extern int unregister_console(struct console *);
-extern struct console *console_drivers;
extern void console_lock(void);
extern int console_trylock(void);
extern void console_unlock(void);
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 08a1d3e7e46d..d3eba4360150 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -18,10 +18,10 @@ struct core_vma_metadata {
struct coredump_params {
const kernel_siginfo_t *siginfo;
- struct pt_regs *regs;
struct file *file;
unsigned long limit;
unsigned long mm_flags;
+ int cpu;
loff_t written;
loff_t pos;
loff_t to_skip;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d5595d57f4e5..6a94a6eaad27 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1110,10 +1110,10 @@ cpufreq_table_set_inefficient(struct cpufreq_policy *policy,
}
static inline int parse_perf_domain(int cpu, const char *list_name,
- const char *cell_name)
+ const char *cell_name,
+ struct of_phandle_args *args)
{
struct device_node *cpu_np;
- struct of_phandle_args args;
int ret;
cpu_np = of_cpu_device_node_get(cpu);
@@ -1121,41 +1121,44 @@ static inline int parse_perf_domain(int cpu, const char *list_name,
return -ENODEV;
ret = of_parse_phandle_with_args(cpu_np, list_name, cell_name, 0,
- &args);
+ args);
if (ret < 0)
return ret;
of_node_put(cpu_np);
- return args.args[0];
+ return 0;
}
static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_name,
- const char *cell_name, struct cpumask *cpumask)
+ const char *cell_name, struct cpumask *cpumask,
+ struct of_phandle_args *pargs)
{
- int target_idx;
int cpu, ret;
+ struct of_phandle_args args;
- ret = parse_perf_domain(pcpu, list_name, cell_name);
+ ret = parse_perf_domain(pcpu, list_name, cell_name, pargs);
if (ret < 0)
return ret;
- target_idx = ret;
cpumask_set_cpu(pcpu, cpumask);
for_each_possible_cpu(cpu) {
if (cpu == pcpu)
continue;
- ret = parse_perf_domain(cpu, list_name, cell_name);
+ ret = parse_perf_domain(cpu, list_name, cell_name, &args);
if (ret < 0)
continue;
- if (target_idx == ret)
+ if (pargs->np == args.np && pargs->args_count == args.args_count &&
+ !memcmp(pargs->args, args.args, sizeof(args.args[0]) * args.args_count))
cpumask_set_cpu(cpu, cpumask);
+
+ of_node_put(args.np);
}
- return target_idx;
+ return 0;
}
#else
static inline int cpufreq_boost_trigger_state(int state)
@@ -1185,7 +1188,8 @@ cpufreq_table_set_inefficient(struct cpufreq_policy *policy,
}
static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_name,
- const char *cell_name, struct cpumask *cpumask)
+ const char *cell_name, struct cpumask *cpumask,
+ struct of_phandle_args *pargs)
{
return -EOPNOTSUPP;
}
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 620ada094c3b..84525b9cdf6e 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -21,7 +21,7 @@
/* Get a random number in [l, r) */
static inline unsigned long damon_rand(unsigned long l, unsigned long r)
{
- return l + prandom_u32_max(r - l);
+ return l + get_random_u32_below(r - l);
}
/**
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index f60674692d36..ea2d919fd9c7 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -45,7 +45,7 @@ struct debugfs_u32_array {
extern struct dentry *arch_debugfs_dir;
-#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
+#define DEFINE_DEBUGFS_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, __is_signed) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
__simple_attr_check_format(__fmt, 0ull); \
@@ -56,10 +56,16 @@ static const struct file_operations __fops = { \
.open = __fops ## _open, \
.release = simple_attr_release, \
.read = debugfs_attr_read, \
- .write = debugfs_attr_write, \
+ .write = (__is_signed) ? debugfs_attr_write_signed : debugfs_attr_write, \
.llseek = no_llseek, \
}
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
+ DEFINE_DEBUGFS_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, false)
+
+#define DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(__fops, __get, __set, __fmt) \
+ DEFINE_DEBUGFS_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, true)
+
typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
#if defined(CONFIG_DEBUG_FS)
@@ -102,6 +108,8 @@ ssize_t debugfs_attr_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos);
ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos);
+ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos);
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
struct dentry *new_dir, const char *new_name);
@@ -254,6 +262,13 @@ static inline ssize_t debugfs_attr_write(struct file *file,
return -ENODEV;
}
+static inline ssize_t debugfs_attr_write_signed(struct file *file,
+ const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return -ENODEV;
+}
+
static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
struct dentry *new_dir, char *new_name)
{
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 34aab4dd336c..4dc7cda4fd46 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -152,8 +152,8 @@ struct devfreq_stats {
* @max_state: count of entry present in the frequency table.
* @previous_freq: previously configured frequency value.
* @last_status: devfreq user device info, performance statistics
- * @data: Private data of the governor. The devfreq framework does not
- * touch this.
+ * @data: devfreq driver pass to governors, governor should not change it.
+ * @governor_data: private data for governors, devfreq core doesn't touch it.
* @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
* @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs)
* @scaling_min_freq: Limit minimum frequency requested by OPP interface
@@ -193,7 +193,8 @@ struct devfreq {
unsigned long previous_freq;
struct devfreq_dev_status last_status;
- void *data; /* private data for governors */
+ void *data;
+ void *governor_data;
struct dev_pm_qos_request user_min_freq_req;
struct dev_pm_qos_request user_max_freq_req;
diff --git a/include/linux/device.h b/include/linux/device.h
index 424b55df0272..c90a444be1c4 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -378,10 +378,8 @@ struct dev_links_info {
* @data: Pointer to MSI device data
*/
struct dev_msi_info {
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
- struct irq_domain *domain;
-#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
+ struct irq_domain *domain;
struct msi_device_data *data;
#endif
};
@@ -742,7 +740,7 @@ static inline void set_dev_node(struct device *dev, int node)
static inline struct irq_domain *dev_get_msi_domain(const struct device *dev)
{
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
return dev->msi.domain;
#else
return NULL;
@@ -751,7 +749,7 @@ static inline struct irq_domain *dev_get_msi_domain(const struct device *dev)
static inline void dev_set_msi_domain(struct device *dev, struct irq_domain *d)
{
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
dev->msi.domain = d;
#endif
}
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index 71731796c8c3..6fa8d4e29719 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -327,15 +327,6 @@ struct dma_buf {
const struct dma_buf_ops *ops;
/**
- * @lock:
- *
- * Used internally to serialize list manipulation, attach/detach and
- * vmap/unmap. Note that in many cases this is superseeded by
- * dma_resv_lock() on @resv.
- */
- struct mutex lock;
-
- /**
* @vmapping_counter:
*
* Used internally to refcnt the vmaps returned by dma_buf_vmap().
@@ -627,9 +618,17 @@ int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction dir);
int dma_buf_end_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction dir);
+struct sg_table *
+dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach,
+ enum dma_data_direction direction);
+void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach,
+ struct sg_table *sg_table,
+ enum dma_data_direction direction);
int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
unsigned long);
int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map);
void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map);
+int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map);
+void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map);
#endif /* __DMA_BUF_H__ */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 929d559ad41d..7603fc58c47c 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -389,6 +389,7 @@ void efi_native_runtime_setup(void);
#define EFI_LOAD_FILE2_PROTOCOL_GUID EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e, 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d)
#define EFI_RT_PROPERTIES_TABLE_GUID EFI_GUID(0xeb66918a, 0x7eef, 0x402a, 0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
#define EFI_DXE_SERVICES_TABLE_GUID EFI_GUID(0x05ad34ba, 0x6f02, 0x4214, 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
+#define EFI_SMBIOS_PROTOCOL_GUID EFI_GUID(0x03583ff6, 0xcb36, 0x4940, 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7)
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index 346a8b56cdc8..9ec81290e3c8 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -88,22 +88,13 @@ static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t*
{
#if defined (ELF_CORE_COPY_TASK_REGS)
return ELF_CORE_COPY_TASK_REGS(t, elfregs);
-#elif defined (task_pt_regs)
+#else
elf_core_copy_regs(elfregs, task_pt_regs(t));
#endif
return 0;
}
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-
-static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_regs *regs, elf_fpregset_t *fpu)
-{
-#ifdef ELF_CORE_COPY_FPREGS
- return ELF_CORE_COPY_FPREGS(t, fpu);
-#else
- return dump_fpu(regs, fpu);
-#endif
-}
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
#ifdef CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS
/*
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
index 30eb30d6909b..36a486505b08 100644
--- a/include/linux/eventfd.h
+++ b/include/linux/eventfd.h
@@ -40,6 +40,7 @@ struct file *eventfd_fget(int fd);
struct eventfd_ctx *eventfd_ctx_fdget(int fd);
struct eventfd_ctx *eventfd_ctx_fileget(struct file *file);
__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n);
+__u64 eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n, unsigned mask);
int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *wait,
__u64 *cnt);
void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt);
@@ -61,7 +62,13 @@ static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd)
return ERR_PTR(-ENOSYS);
}
-static inline int eventfd_signal(struct eventfd_ctx *ctx, int n)
+static inline int eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
+{
+ return -ENOSYS;
+}
+
+static inline int eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n,
+ unsigned mask)
{
return -ENOSYS;
}
diff --git a/include/linux/evm.h b/include/linux/evm.h
index aa63e0b3c0a2..7a9ee2157f69 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -35,6 +35,27 @@ extern int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
+static inline void evm_inode_post_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ evm_inode_post_removexattr(dentry, acl_name);
+}
+extern int evm_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl);
+static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return evm_inode_set_acl(mnt_userns, dentry, acl_name, NULL);
+}
+static inline void evm_inode_post_set_acl(struct dentry *dentry,
+ const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
+}
extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);
@@ -108,6 +129,34 @@ static inline void evm_inode_post_removexattr(struct dentry *dentry,
return;
}
+static inline void evm_inode_post_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return;
+}
+
+static inline int evm_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return 0;
+}
+
+static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return 0;
+}
+
+static inline void evm_inode_post_set_acl(struct dentry *dentry,
+ const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return;
+}
+
static inline int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm)
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index 9f6e25467844..444236dadcf0 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -20,7 +20,6 @@ struct fault_attr {
atomic_t space;
unsigned long verbose;
bool task_filter;
- bool no_warn;
unsigned long stacktrace_depth;
unsigned long require_start;
unsigned long require_end;
@@ -32,6 +31,10 @@ struct fault_attr {
struct dentry *dname;
};
+enum fault_flags {
+ FAULT_NOWARN = 1 << 0,
+};
+
#define FAULT_ATTR_INITIALIZER { \
.interval = 1, \
.times = ATOMIC_INIT(1), \
@@ -40,11 +43,11 @@ struct fault_attr {
.ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \
.verbose = 2, \
.dname = NULL, \
- .no_warn = false, \
}
#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
int setup_fault_attr(struct fault_attr *attr, char *str);
+bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags);
bool should_fail(struct fault_attr *attr, ssize_t size);
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
diff --git a/include/linux/fb.h b/include/linux/fb.h
index bcb8658f5b64..96b96323e9cb 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -803,6 +803,15 @@ extern int fb_find_mode(struct fb_var_screeninfo *var,
const struct fb_videomode *default_mode,
unsigned int default_bpp);
+#if defined(CONFIG_VIDEO_NOMODESET)
+bool fb_modesetting_disabled(const char *drvname);
+#else
+static inline bool fb_modesetting_disabled(const char *drvname)
+{
+ return false;
+}
+#endif
+
/* Convenience logging macros */
#define fb_err(fb_info, fmt, ...) \
pr_err("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e654435f1651..066555ad1bf8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -560,8 +560,8 @@ struct posix_acl;
#define ACL_NOT_CACHED ((void *)(-1))
/*
* ACL_DONT_CACHE is for stacked filesystems, that rely on underlying fs to
- * cache the ACL. This also means that ->get_acl() can be called in RCU mode
- * with the LOOKUP_RCU flag.
+ * cache the ACL. This also means that ->get_inode_acl() can be called in RCU
+ * mode with the LOOKUP_RCU flag.
*/
#define ACL_DONT_CACHE ((void *)(-3))
@@ -1131,9 +1131,8 @@ struct file_lock_context {
/* The following constant reflects the upper bound of the file/locking space */
#ifndef OFFSET_MAX
-#define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1)))
-#define OFFSET_MAX INT_LIMIT(loff_t)
-#define OFFT_OFFSET_MAX INT_LIMIT(off_t)
+#define OFFSET_MAX type_max(loff_t)
+#define OFFT_OFFSET_MAX type_max(off_t)
#endif
extern void send_sigio(struct fown_struct *fown, int fd, int band);
@@ -1170,6 +1169,7 @@ extern int locks_delete_block(struct file_lock *);
extern int vfs_test_lock(struct file *, struct file_lock *);
extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
+bool vfs_inode_has_locks(struct inode *inode);
extern int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
extern void lease_get_mtime(struct inode *, struct timespec64 *time);
@@ -1186,6 +1186,13 @@ extern void show_fd_locks(struct seq_file *f,
struct file *filp, struct files_struct *files);
extern bool locks_owner_has_blockers(struct file_lock_context *flctx,
fl_owner_t owner);
+
+static inline struct file_lock_context *
+locks_inode_context(const struct inode *inode)
+{
+ return smp_load_acquire(&inode->i_flctx);
+}
+
#else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, unsigned int cmd,
struct flock __user *user)
@@ -1284,6 +1291,11 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
return 0;
}
+static inline bool vfs_inode_has_locks(struct inode *inode)
+{
+ return false;
+}
+
static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)
{
return -ENOLCK;
@@ -1326,6 +1338,13 @@ static inline bool locks_owner_has_blockers(struct file_lock_context *flctx,
{
return false;
}
+
+static inline struct file_lock_context *
+locks_inode_context(const struct inode *inode)
+{
+ return NULL;
+}
+
#endif /* !CONFIG_FILE_LOCKING */
static inline struct inode *file_inode(const struct file *f)
@@ -1613,23 +1632,6 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
}
/**
- * i_uid_into_mnt - map an inode's i_uid down into a mnt_userns
- * @mnt_userns: user namespace of the mount the inode was found from
- * @inode: inode to map
- *
- * Note, this will eventually be removed completely in favor of the type-safe
- * i_uid_into_vfsuid().
- *
- * Return: the inode's i_uid mapped down according to @mnt_userns.
- * If the inode's i_uid has no mapping INVALID_UID is returned.
- */
-static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns,
- const struct inode *inode)
-{
- return AS_KUIDT(make_vfsuid(mnt_userns, i_user_ns(inode), inode->i_uid));
-}
-
-/**
* i_uid_into_vfsuid - map an inode's i_uid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode to map
@@ -1682,23 +1684,6 @@ static inline void i_uid_update(struct user_namespace *mnt_userns,
}
/**
- * i_gid_into_mnt - map an inode's i_gid down into a mnt_userns
- * @mnt_userns: user namespace of the mount the inode was found from
- * @inode: inode to map
- *
- * Note, this will eventually be removed completely in favor of the type-safe
- * i_gid_into_vfsgid().
- *
- * Return: the inode's i_gid mapped down according to @mnt_userns.
- * If the inode's i_gid has no mapping INVALID_GID is returned.
- */
-static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns,
- const struct inode *inode)
-{
- return AS_KGIDT(make_vfsgid(mnt_userns, i_user_ns(inode), inode->i_gid));
-}
-
-/**
* i_gid_into_vfsgid - map an inode's i_gid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode to map
@@ -2089,6 +2074,14 @@ struct dir_context {
*/
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
+/*
+ * These flags control the behavior of vfs_copy_file_range().
+ * They are not available to the user via syscall.
+ *
+ * COPY_FILE_SPLICE: call splice direct instead of fs clone/copy ops
+ */
+#define COPY_FILE_SPLICE (1 << 0)
+
struct iov_iter;
struct io_uring_cmd;
@@ -2142,7 +2135,7 @@ struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
- struct posix_acl * (*get_acl)(struct inode *, int, bool);
+ struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*readlink) (struct dentry *, char __user *,int);
@@ -2172,7 +2165,9 @@ struct inode_operations {
umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *,
struct file *, umode_t);
- int (*set_acl)(struct user_namespace *, struct inode *,
+ struct posix_acl *(*get_acl)(struct user_namespace *, struct dentry *,
+ int);
+ int (*set_acl)(struct user_namespace *, struct dentry *,
struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
@@ -2732,18 +2727,22 @@ static inline struct user_namespace *file_mnt_user_ns(struct file *file)
return mnt_user_ns(file->f_path.mnt);
}
+static inline struct mnt_idmap *file_mnt_idmap(struct file *file)
+{
+ return mnt_idmap(file->f_path.mnt);
+}
+
/**
* is_idmapped_mnt - check whether a mount is mapped
* @mnt: the mount to check
*
- * If @mnt has an idmapping attached different from the
- * filesystem's idmapping then @mnt is mapped.
+ * If @mnt has an non @nop_mnt_idmap attached to it then @mnt is mapped.
*
* Return: true if mount is mapped, false if not.
*/
static inline bool is_idmapped_mnt(const struct vfsmount *mnt)
{
- return mnt_user_ns(mnt) != mnt->mnt_sb->s_user_ns;
+ return mnt_idmap(mnt) != &nop_mnt_idmap;
}
extern long vfs_truncate(const struct path *, loff_t);
@@ -3104,7 +3103,7 @@ extern void __destroy_inode(struct inode *);
extern struct inode *new_inode_pseudo(struct super_block *sb);
extern struct inode *new_inode(struct super_block *sb);
extern void free_inode_nonrcu(struct inode *inode);
-extern int should_remove_suid(struct dentry *);
+extern int setattr_should_drop_suidgid(struct user_namespace *, struct inode *);
extern int file_remove_privs(struct file *);
/*
@@ -3485,7 +3484,7 @@ void simple_transaction_set(struct file *file, size_t n);
* All attributes contain a text representation of a numeric value
* that are accessed with the get() and set() functions.
*/
-#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
+#define DEFINE_SIMPLE_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, __is_signed) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
__simple_attr_check_format(__fmt, 0ull); \
@@ -3496,10 +3495,16 @@ static const struct file_operations __fops = { \
.open = __fops ## _open, \
.release = simple_attr_release, \
.read = simple_attr_read, \
- .write = simple_attr_write, \
+ .write = (__is_signed) ? simple_attr_write_signed : simple_attr_write, \
.llseek = generic_file_llseek, \
}
+#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
+ DEFINE_SIMPLE_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, false)
+
+#define DEFINE_SIMPLE_ATTRIBUTE_SIGNED(__fops, __get, __set, __fmt) \
+ DEFINE_SIMPLE_ATTRIBUTE_XSIGNED(__fops, __get, __set, __fmt, true)
+
static inline __printf(1, 2)
void __simple_attr_check_format(const char *fmt, ...)
{
@@ -3514,6 +3519,8 @@ ssize_t simple_attr_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos);
ssize_t simple_attr_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos);
+ssize_t simple_attr_write_signed(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos);
struct ctl_table;
int __init list_bdev_fs_names(char *buf, size_t size);
@@ -3527,7 +3534,7 @@ int __init list_bdev_fs_names(char *buf, size_t size);
static inline bool is_sxid(umode_t mode)
{
- return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
+ return mode & (S_ISUID | S_ISGID);
}
static inline int check_sticky(struct user_namespace *mnt_userns,
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index 13fa6f3df8e4..5469ffee21c7 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -99,7 +99,7 @@ struct fs_context {
const struct cred *cred; /* The mounter's credentials */
struct p_log log; /* Logging buffer */
const char *source; /* The source name (eg. dev path) */
- void *security; /* Linux S&M options */
+ void *security; /* LSM options */
void *s_fs_info; /* Proposed s_fs_info */
unsigned int sb_flags; /* Proposed superblock flags (SB_*) */
unsigned int sb_flags_mask; /* Superblock flags that were changed */
@@ -145,20 +145,6 @@ extern void fc_drop_locked(struct fs_context *fc);
int reconfigure_single(struct super_block *s,
int flags, void *data);
-/*
- * sget() wrappers to be called from the ->get_tree() op.
- */
-enum vfs_get_super_keying {
- vfs_get_single_super, /* Only one such superblock may exist */
- vfs_get_single_reconf_super, /* As above, but reconfigure if it exists */
- vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */
- vfs_get_independent_super, /* Multiple independent superblocks may exist */
-};
-extern int vfs_get_super(struct fs_context *fc,
- enum vfs_get_super_keying keying,
- int (*fill_super)(struct super_block *sb,
- struct fs_context *fc));
-
extern int get_tree_nodev(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc));
diff --git a/include/linux/fs_parser.h b/include/linux/fs_parser.h
index f103c91139d4..01542c4b87a2 100644
--- a/include/linux/fs_parser.h
+++ b/include/linux/fs_parser.h
@@ -76,6 +76,7 @@ static inline int fs_parse(struct fs_context *fc,
extern int fs_lookup_param(struct fs_context *fc,
struct fs_parameter *param,
bool want_bdev,
+ unsigned int flags,
struct path *_path);
extern int lookup_constant(const struct constant_table tbl[], const char *name, int not_found);
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index 36e5dd84cf59..8e312c8323a8 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -75,7 +75,7 @@ struct fscache_volume {
atomic_t n_accesses; /* Number of cache accesses in progress */
unsigned int debug_id;
unsigned int key_hash; /* Hash of key string */
- char *key; /* Volume ID, eg. "afs@example.com@1234" */
+ u8 *key; /* Volume ID, eg. "afs@example.com@1234" */
struct list_head proc_link; /* Link in /proc/fs/fscache/volumes */
struct hlist_bl_node hash_link; /* Link in hash table */
struct work_struct work;
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 62557d4bffc2..99f1146614c0 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -37,9 +37,10 @@ extern void ftrace_boot_snapshot(void);
static inline void ftrace_boot_snapshot(void) { }
#endif
-#ifdef CONFIG_FUNCTION_TRACER
struct ftrace_ops;
struct ftrace_regs;
+
+#ifdef CONFIG_FUNCTION_TRACER
/*
* If the arch's mcount caller does not support all of ftrace's
* features, then it must call an indirect function that
@@ -110,12 +111,11 @@ struct ftrace_regs {
#define arch_ftrace_get_regs(fregs) (&(fregs)->regs)
/*
- * ftrace_instruction_pointer_set() is to be defined by the architecture
- * if to allow setting of the instruction pointer from the ftrace_regs
- * when HAVE_DYNAMIC_FTRACE_WITH_ARGS is set and it supports
- * live kernel patching.
+ * ftrace_regs_set_instruction_pointer() is to be defined by the architecture
+ * if to allow setting of the instruction pointer from the ftrace_regs when
+ * HAVE_DYNAMIC_FTRACE_WITH_ARGS is set and it supports live kernel patching.
*/
-#define ftrace_instruction_pointer_set(fregs, ip) do { } while (0)
+#define ftrace_regs_set_instruction_pointer(fregs, ip) do { } while (0)
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs)
@@ -126,6 +126,35 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs
return arch_ftrace_get_regs(fregs);
}
+/*
+ * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs.
+ * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs.
+ */
+static __always_inline bool ftrace_regs_has_args(struct ftrace_regs *fregs)
+{
+ if (IS_ENABLED(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS))
+ return true;
+
+ return ftrace_get_regs(fregs) != NULL;
+}
+
+#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
+#define ftrace_regs_get_instruction_pointer(fregs) \
+ instruction_pointer(ftrace_get_regs(fregs))
+#define ftrace_regs_get_argument(fregs, n) \
+ regs_get_kernel_argument(ftrace_get_regs(fregs), n)
+#define ftrace_regs_get_stack_pointer(fregs) \
+ kernel_stack_pointer(ftrace_get_regs(fregs))
+#define ftrace_regs_return_value(fregs) \
+ regs_return_value(ftrace_get_regs(fregs))
+#define ftrace_regs_set_return_value(fregs, ret) \
+ regs_set_return_value(ftrace_get_regs(fregs), ret)
+#define ftrace_override_function_with_return(fregs) \
+ override_function_with_return(ftrace_get_regs(fregs))
+#define ftrace_regs_query_register_offset(name) \
+ regs_query_register_offset(name)
+#endif
+
typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct ftrace_regs *fregs);
@@ -427,9 +456,7 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
{
return -ENODEV;
}
-#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
-#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
/*
* This must be implemented by the architecture.
* It is the way the ftrace direct_ops helper, when called
@@ -443,9 +470,9 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
* the return from the trampoline jump to the direct caller
* instead of going back to the function it just traced.
*/
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs,
+static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
unsigned long addr) { }
-#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
#ifdef CONFIG_STACK_TRACER
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index ef4aea3b356e..65a78773dcca 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -210,6 +210,20 @@ alloc_pages_bulk_array_node(gfp_t gfp, int nid, unsigned long nr_pages, struct p
return __alloc_pages_bulk(gfp, nid, NULL, nr_pages, NULL, page_array);
}
+static inline void warn_if_node_offline(int this_node, gfp_t gfp_mask)
+{
+ gfp_t warn_gfp = gfp_mask & (__GFP_THISNODE|__GFP_NOWARN);
+
+ if (warn_gfp != (__GFP_THISNODE|__GFP_NOWARN))
+ return;
+
+ if (node_online(this_node))
+ return;
+
+ pr_warn("%pGg allocation from offline node %d\n", &gfp_mask, this_node);
+ dump_stack();
+}
+
/*
* Allocate pages, preferring the node given as nid. The node must be valid and
* online. For more general interface, see alloc_pages_node().
@@ -218,7 +232,7 @@ static inline struct page *
__alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order)
{
VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
- VM_WARN_ON((gfp_mask & __GFP_THISNODE) && !node_online(nid));
+ warn_if_node_offline(nid, gfp_mask);
return __alloc_pages(gfp_mask, order, nid, NULL);
}
@@ -227,7 +241,7 @@ static inline
struct folio *__folio_alloc_node(gfp_t gfp, unsigned int order, int nid)
{
VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
- VM_WARN_ON((gfp & __GFP_THISNODE) && !node_online(nid));
+ warn_if_node_offline(nid, gfp);
return __folio_alloc(gfp, order, nid, NULL);
}
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 6aeea1071b1b..88ae4513abb5 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -27,7 +27,7 @@ struct gpio_chip;
union gpio_irq_fwspec {
struct irq_fwspec fwspec;
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
msi_alloc_info_t msiinfo;
#endif
};
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index cb2100d9b0ff..dc55d9d3b94f 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -469,11 +469,13 @@ struct host1x_memory_context {
#ifdef CONFIG_IOMMU_API
struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
+ struct device *dev,
struct pid *pid);
void host1x_memory_context_get(struct host1x_memory_context *cd);
void host1x_memory_context_put(struct host1x_memory_context *cd);
#else
static inline struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
+ struct device *dev,
struct pid *pid)
{
return NULL;
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 3b42264333ef..85f7c5a63aa6 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -969,7 +969,7 @@ struct vmbus_channel {
* mechanism improves throughput by:
*
* A) Making the host more efficient - each time it wakes up,
- * potentially it will process morev number of packets. The
+ * potentially it will process more number of packets. The
* monitor latency allows a batch to build up.
* B) By deferring the hypercall to signal, we will also minimize
* the interrupts.
@@ -1341,6 +1341,8 @@ struct hv_ring_buffer_debug_info {
int hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info);
+bool hv_ringbuffer_spinlock_busy(struct vmbus_channel *channel);
+
/* Vmbus interface */
#define vmbus_driver_register(driver) \
__vmbus_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 81708ca0ebc7..5a0b2a285a18 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -187,6 +187,15 @@ extern void ima_inode_post_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry);
extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len);
+extern int ima_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl);
+static inline int ima_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return ima_inode_set_acl(mnt_userns, dentry, acl_name, NULL);
+}
extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
#else
static inline bool is_ima_appraise_enabled(void)
@@ -208,11 +217,26 @@ static inline int ima_inode_setxattr(struct dentry *dentry,
return 0;
}
+static inline int ima_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+
+ return 0;
+}
+
static inline int ima_inode_removexattr(struct dentry *dentry,
const char *xattr_name)
{
return 0;
}
+
+static inline int ima_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return 0;
+}
#endif /* CONFIG_IMA_APPRAISE */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
diff --git a/include/linux/init.h b/include/linux/init.h
index 077d7f93b402..c5fe6d26f5b1 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -2,7 +2,9 @@
#ifndef _LINUX_INIT_H
#define _LINUX_INIT_H
+#include <linux/build_bug.h>
#include <linux/compiler.h>
+#include <linux/stringify.h>
#include <linux/types.h>
/* Built-in __init functions needn't be compiled with retpoline */
@@ -143,6 +145,7 @@ struct file_system_type;
extern int do_one_initcall(initcall_t fn);
extern char __initdata boot_command_line[];
extern char *saved_command_line;
+extern unsigned int saved_command_line_len;
extern unsigned int reset_devices;
/* used by init/main.c */
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 66a774d2710e..09d4f17c8d3b 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -213,7 +213,7 @@ io_mapping_free(struct io_mapping *iomap)
kfree(iomap);
}
-#endif /* _LINUX_IO_MAPPING_H */
-
int io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma,
unsigned long addr, unsigned long pfn, unsigned long size);
+
+#endif /* _LINUX_IO_MAPPING_H */
diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h
index 43bc8a2edccf..934e5dd4ccc0 100644
--- a/include/linux/io_uring.h
+++ b/include/linux/io_uring.h
@@ -9,13 +9,17 @@
enum io_uring_cmd_flags {
IO_URING_F_COMPLETE_DEFER = 1,
IO_URING_F_UNLOCKED = 2,
+ /* the request is executed from poll, it should not be freed */
+ IO_URING_F_MULTISHOT = 4,
+ /* executed by io-wq */
+ IO_URING_F_IOWQ = 8,
/* int's last bit, sign checks are usually faster than a bit test */
IO_URING_F_NONBLOCK = INT_MIN,
/* ctx state flags, for URING_CMD */
- IO_URING_F_SQE128 = 4,
- IO_URING_F_CQE32 = 8,
- IO_URING_F_IOPOLL = 16,
+ IO_URING_F_SQE128 = (1 << 8),
+ IO_URING_F_CQE32 = (1 << 9),
+ IO_URING_F_IOPOLL = (1 << 10),
};
struct io_uring_cmd {
diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
index f5b687a787a3..dcd8a563ab52 100644
--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -174,7 +174,9 @@ struct io_submit_state {
bool plug_started;
bool need_plug;
unsigned short submit_nr;
+ unsigned int cqes_count;
struct blk_plug plug;
+ struct io_uring_cqe cqes[16];
};
struct io_ev_fd {
@@ -206,6 +208,8 @@ struct io_ring_ctx {
unsigned int drain_disabled: 1;
unsigned int has_evfd: 1;
unsigned int syscall_iopoll: 1;
+ /* all CQEs should be posted only by the submitter task */
+ unsigned int task_complete: 1;
} ____cacheline_aligned_in_smp;
/* submission data */
@@ -324,6 +328,7 @@ struct io_ring_ctx {
struct io_rsrc_data *buf_data;
struct delayed_work rsrc_put_work;
+ struct callback_head rsrc_put_tw;
struct llist_head rsrc_put_llist;
struct list_head rsrc_ref_list;
spinlock_t rsrc_ref_lock;
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 27642ca15d93..4ae3c541ea6f 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -318,6 +318,8 @@ extern void __devm_release_region(struct device *dev, struct resource *parent,
resource_size_t start, resource_size_t n);
extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
extern bool iomem_is_exclusive(u64 addr);
+extern bool resource_is_exclusive(struct resource *resource, u64 addr,
+ resource_size_t size);
extern int
walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 00d577f90883..a372086750ca 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -31,6 +31,7 @@
#define _LINUX_IRQDOMAIN_H
#include <linux/types.h>
+#include <linux/irqdomain_defs.h>
#include <linux/irqhandler.h>
#include <linux/of.h>
#include <linux/mutex.h>
@@ -45,6 +46,7 @@ struct irq_desc;
struct cpumask;
struct seq_file;
struct irq_affinity_desc;
+struct msi_parent_ops;
#define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16
@@ -68,27 +70,6 @@ struct irq_fwspec {
void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
unsigned int count, struct irq_fwspec *fwspec);
-/*
- * Should several domains have the same device node, but serve
- * different purposes (for example one domain is for PCI/MSI, and the
- * other for wired IRQs), they can be distinguished using a
- * bus-specific token. Most domains are expected to only carry
- * DOMAIN_BUS_ANY.
- */
-enum irq_domain_bus_token {
- DOMAIN_BUS_ANY = 0,
- DOMAIN_BUS_WIRED,
- DOMAIN_BUS_GENERIC_MSI,
- DOMAIN_BUS_PCI_MSI,
- DOMAIN_BUS_PLATFORM_MSI,
- DOMAIN_BUS_NEXUS,
- DOMAIN_BUS_IPI,
- DOMAIN_BUS_FSL_MC_MSI,
- DOMAIN_BUS_TI_SCI_INTA_MSI,
- DOMAIN_BUS_WAKEUP,
- DOMAIN_BUS_VMD_MSI,
-};
-
/**
* struct irq_domain_ops - Methods for irq_domain objects
* @match: Match an interrupt controller device node to a host, returns
@@ -137,53 +118,61 @@ struct irq_domain_chip_generic;
/**
* struct irq_domain - Hardware interrupt number translation object
- * @link: Element in global irq_domain list.
- * @name: Name of interrupt domain
- * @ops: pointer to irq_domain methods
- * @host_data: private data pointer for use by owner. Not touched by irq_domain
- * core code.
- * @flags: host per irq_domain flags
- * @mapcount: The number of mapped interrupts
+ * @link: Element in global irq_domain list.
+ * @name: Name of interrupt domain
+ * @ops: Pointer to irq_domain methods
+ * @host_data: Private data pointer for use by owner. Not touched by irq_domain
+ * core code.
+ * @flags: Per irq_domain flags
+ * @mapcount: The number of mapped interrupts
*
- * Optional elements
- * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy
- * to swap it for the of_node via the irq_domain_get_of_node accessor
- * @gc: Pointer to a list of generic chips. There is a helper function for
- * setting up one or more generic chips for interrupt controllers
- * drivers using the generic chip library which uses this pointer.
- * @dev: Pointer to a device that the domain represent, and that will be
- * used for power management purposes.
- * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
+ * Optional elements:
+ * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy
+ * to swap it for the of_node via the irq_domain_get_of_node accessor
+ * @gc: Pointer to a list of generic chips. There is a helper function for
+ * setting up one or more generic chips for interrupt controllers
+ * drivers using the generic chip library which uses this pointer.
+ * @dev: Pointer to the device which instantiated the irqdomain
+ * With per device irq domains this is not necessarily the same
+ * as @pm_dev.
+ * @pm_dev: Pointer to a device that can be utilized for power management
+ * purposes related to the irq domain.
+ * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
+ * @msi_parent_ops: Pointer to MSI parent domain methods for per device domain init
*
- * Revmap data, used internally by irq_domain
- * @revmap_size: Size of the linear map table @revmap[]
- * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
- * @revmap_mutex: Lock for the revmap
- * @revmap: Linear table of irq_data pointers
+ * Revmap data, used internally by the irq domain code:
+ * @revmap_size: Size of the linear map table @revmap[]
+ * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
+ * @revmap_mutex: Lock for the revmap
+ * @revmap: Linear table of irq_data pointers
*/
struct irq_domain {
- struct list_head link;
- const char *name;
- const struct irq_domain_ops *ops;
- void *host_data;
- unsigned int flags;
- unsigned int mapcount;
+ struct list_head link;
+ const char *name;
+ const struct irq_domain_ops *ops;
+ void *host_data;
+ unsigned int flags;
+ unsigned int mapcount;
/* Optional data */
- struct fwnode_handle *fwnode;
- enum irq_domain_bus_token bus_token;
- struct irq_domain_chip_generic *gc;
- struct device *dev;
+ struct fwnode_handle *fwnode;
+ enum irq_domain_bus_token bus_token;
+ struct irq_domain_chip_generic *gc;
+ struct device *dev;
+ struct device *pm_dev;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
- struct irq_domain *parent;
+ struct irq_domain *parent;
+#endif
+#ifdef CONFIG_GENERIC_MSI_IRQ
+ const struct msi_parent_ops *msi_parent_ops;
#endif
/* reverse map data. The linear map gets appended to the irq_domain */
- irq_hw_number_t hwirq_max;
- unsigned int revmap_size;
- struct radix_tree_root revmap_tree;
- struct mutex revmap_mutex;
- struct irq_data __rcu *revmap[];
+ irq_hw_number_t hwirq_max;
+ unsigned int revmap_size;
+ struct radix_tree_root revmap_tree;
+ struct mutex revmap_mutex;
+ struct irq_data __rcu *revmap[];
};
/* Irq domain flags */
@@ -206,15 +195,14 @@ enum {
/* Irq domain implements MSI remapping */
IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5),
- /*
- * Quirk to handle MSI implementations which do not provide
- * masking. Currently known to affect x86, but partially
- * handled in core code.
- */
- IRQ_DOMAIN_MSI_NOMASK_QUIRK = (1 << 6),
-
/* Irq domain doesn't translate anything */
- IRQ_DOMAIN_FLAG_NO_MAP = (1 << 7),
+ IRQ_DOMAIN_FLAG_NO_MAP = (1 << 6),
+
+ /* Irq domain is a MSI parent domain */
+ IRQ_DOMAIN_FLAG_MSI_PARENT = (1 << 8),
+
+ /* Irq domain is a MSI device domain */
+ IRQ_DOMAIN_FLAG_MSI_DEVICE = (1 << 9),
/*
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
@@ -233,7 +221,7 @@ static inline void irq_domain_set_pm_device(struct irq_domain *d,
struct device *dev)
{
if (d)
- d->dev = dev;
+ d->pm_dev = dev;
}
#ifdef CONFIG_IRQ_DOMAIN
@@ -578,6 +566,16 @@ static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
+static inline bool irq_domain_is_msi_parent(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT;
+}
+
+static inline bool irq_domain_is_msi_device(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_MSI_DEVICE;
+}
+
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
unsigned int nr_irqs, int node, void *arg)
@@ -623,6 +621,17 @@ irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
{
return false;
}
+
+static inline bool irq_domain_is_msi_parent(struct irq_domain *domain)
+{
+ return false;
+}
+
+static inline bool irq_domain_is_msi_device(struct irq_domain *domain)
+{
+ return false;
+}
+
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
#else /* CONFIG_IRQ_DOMAIN */
diff --git a/include/linux/irqdomain_defs.h b/include/linux/irqdomain_defs.h
new file mode 100644
index 000000000000..c29921fd8cd1
--- /dev/null
+++ b/include/linux/irqdomain_defs.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_IRQDOMAIN_DEFS_H
+#define _LINUX_IRQDOMAIN_DEFS_H
+
+/*
+ * Should several domains have the same device node, but serve
+ * different purposes (for example one domain is for PCI/MSI, and the
+ * other for wired IRQs), they can be distinguished using a
+ * bus-specific token. Most domains are expected to only carry
+ * DOMAIN_BUS_ANY.
+ */
+enum irq_domain_bus_token {
+ DOMAIN_BUS_ANY = 0,
+ DOMAIN_BUS_WIRED,
+ DOMAIN_BUS_GENERIC_MSI,
+ DOMAIN_BUS_PCI_MSI,
+ DOMAIN_BUS_PLATFORM_MSI,
+ DOMAIN_BUS_NEXUS,
+ DOMAIN_BUS_IPI,
+ DOMAIN_BUS_FSL_MC_MSI,
+ DOMAIN_BUS_TI_SCI_INTA_MSI,
+ DOMAIN_BUS_WAKEUP,
+ DOMAIN_BUS_VMD_MSI,
+ DOMAIN_BUS_PCI_DEVICE_MSI,
+ DOMAIN_BUS_PCI_DEVICE_MSIX,
+ DOMAIN_BUS_DMAR,
+ DOMAIN_BUS_AMDVI,
+ DOMAIN_BUS_PCI_DEVICE_IMS,
+};
+
+#endif /* _LINUX_IRQDOMAIN_DEFS_H */
diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h
index bd4c066ad39b..d426c7ad92bf 100644
--- a/include/linux/irqreturn.h
+++ b/include/linux/irqreturn.h
@@ -3,10 +3,10 @@
#define _LINUX_IRQRETURN_H
/**
- * enum irqreturn
- * @IRQ_NONE interrupt was not from this device or was not handled
- * @IRQ_HANDLED interrupt was handled by this device
- * @IRQ_WAKE_THREAD handler requests to wake the handler thread
+ * enum irqreturn - irqreturn type values
+ * @IRQ_NONE: interrupt was not from this device or was not handled
+ * @IRQ_HANDLED: interrupt was handled by this device
+ * @IRQ_WAKE_THREAD: handler requests to wake the handler thread
*/
enum irqreturn {
IRQ_NONE = (0 << 0),
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 0b7242370b56..2170e0cc279d 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1662,7 +1662,7 @@ int jbd2_fc_begin_commit(journal_t *journal, tid_t tid);
int jbd2_fc_end_commit(journal_t *journal);
int jbd2_fc_end_commit_fallback(journal_t *journal);
int jbd2_fc_get_buf(journal_t *journal, struct buffer_head **bh_out);
-int jbd2_submit_inode_data(struct jbd2_inode *jinode);
+int jbd2_submit_inode_data(journal_t *journal, struct jbd2_inode *jinode);
int jbd2_wait_inode_data(journal_t *journal, struct jbd2_inode *jinode);
int jbd2_fc_wait_bufs(journal_t *journal, int num_blks);
int jbd2_fc_release_bufs(journal_t *journal);
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index d811b3d7d2a1..96c9d56e5510 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -302,7 +302,7 @@ static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
#ifdef CONFIG_KASAN_GENERIC
-size_t kasan_metadata_size(struct kmem_cache *cache);
+size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object);
slab_flags_t kasan_never_merge(void);
void kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
slab_flags_t *flags);
@@ -315,7 +315,8 @@ void kasan_record_aux_stack_noalloc(void *ptr);
#else /* CONFIG_KASAN_GENERIC */
/* Tag-based KASAN modes do not use per-object metadata. */
-static inline size_t kasan_metadata_size(struct kmem_cache *cache)
+static inline size_t kasan_metadata_size(struct kmem_cache *cache,
+ bool in_object)
{
return 0;
}
diff --git a/include/linux/kcov.h b/include/linux/kcov.h
index 55dc338f6bcd..ee04256f28af 100644
--- a/include/linux/kcov.h
+++ b/include/linux/kcov.h
@@ -56,7 +56,7 @@ static inline void kcov_remote_start_usb(u64 id)
/*
* The softirq flavor of kcov_remote_*() functions is introduced as a temporary
* work around for kcov's lack of nested remote coverage sections support in
- * task context. Adding suport for nested sections is tracked in:
+ * task context. Adding support for nested sections is tracked in:
* https://bugzilla.kernel.org/show_bug.cgi?id=210337
*/
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 41a686996aaa..5dd4343c1bbe 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -17,6 +17,7 @@
#include <linux/crash_core.h>
#include <asm/io.h>
+#include <linux/range.h>
#include <uapi/linux/kexec.h>
#include <linux/verification.h>
@@ -240,14 +241,10 @@ static inline int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf)
/* Alignment required for elf header segment */
#define ELF_CORE_HEADER_ALIGN 4096
-struct crash_mem_range {
- u64 start, end;
-};
-
struct crash_mem {
unsigned int max_nr_ranges;
unsigned int nr_ranges;
- struct crash_mem_range ranges[];
+ struct range ranges[];
};
extern int crash_exclude_mem_range(struct crash_mem *mem,
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 18592bdf4c1b..915142abdf76 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -416,7 +416,7 @@ static __always_inline void guest_context_enter_irqoff(void)
*/
if (!context_tracking_guest_enter()) {
instrumentation_begin();
- rcu_virt_note_context_switch(smp_processor_id());
+ rcu_virt_note_context_switch();
instrumentation_end();
}
}
@@ -776,6 +776,7 @@ struct kvm {
struct srcu_struct srcu;
struct srcu_struct irq_srcu;
pid_t userspace_pid;
+ bool override_halt_poll_ns;
unsigned int max_halt_poll_ns;
u32 dirty_ring_size;
bool vm_bugged;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index fe990176e6ee..c9149ebe7423 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1043,6 +1043,11 @@ static inline int ata_port_is_dummy(struct ata_port *ap)
return ap->ops == &ata_dummy_port_ops;
}
+static inline bool ata_port_is_frozen(const struct ata_port *ap)
+{
+ return ap->pflags & ATA_PFLAG_FROZEN;
+}
+
extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link));
@@ -1913,8 +1918,6 @@ extern void ata_sff_dev_select(struct ata_port *ap, unsigned int device);
extern u8 ata_sff_check_status(struct ata_port *ap);
extern void ata_sff_pause(struct ata_port *ap);
extern void ata_sff_dma_pause(struct ata_port *ap);
-extern int ata_sff_busy_sleep(struct ata_port *ap,
- unsigned long timeout_pat, unsigned long timeout);
extern int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline);
extern void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
extern void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index c74acfa1a3fe..af38252ad704 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -35,6 +35,11 @@ enum {
NDD_WORK_PENDING = 4,
/* dimm supports namespace labels */
NDD_LABELING = 6,
+ /*
+ * dimm contents have changed requiring invalidation of CPU caches prior
+ * to activation of a region that includes this device
+ */
+ NDD_INCOHERENT = 7,
/* need to set a limit somewhere, but yes, this is likely overkill */
ND_IOCTL_MAX_BUFLEN = SZ_4M,
@@ -183,6 +188,8 @@ struct nvdimm_security_ops {
int (*overwrite)(struct nvdimm *nvdimm,
const struct nvdimm_key_data *key_data);
int (*query_overwrite)(struct nvdimm *nvdimm);
+ int (*disable_master)(struct nvdimm *nvdimm,
+ const struct nvdimm_key_data *key_data);
};
enum nvdimm_fwa_state {
diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h
index 07add7882a5d..c9afcdd9324c 100644
--- a/include/linux/lru_cache.h
+++ b/include/linux/lru_cache.h
@@ -199,7 +199,6 @@ struct lru_cache {
unsigned long flags;
- void *lc_private;
const char *name;
/* nr_elements there */
@@ -241,7 +240,6 @@ extern struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
unsigned e_count, size_t e_size, size_t e_off);
extern void lc_reset(struct lru_cache *lc);
extern void lc_destroy(struct lru_cache *lc);
-extern void lc_set(struct lru_cache *lc, unsigned int enr, int index);
extern void lc_del(struct lru_cache *lc, struct lc_element *element);
extern struct lc_element *lc_get_cumulative(struct lru_cache *lc, unsigned int enr);
@@ -297,6 +295,5 @@ extern bool lc_is_used(struct lru_cache *lc, unsigned int enr);
container_of(ptr, type, member)
extern struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i);
-extern unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e);
#endif
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index ec119da1d89b..ed6cb2ac55fa 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -145,6 +145,12 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
LSM_HOOK(int, 0, inode_removexattr, struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name)
+LSM_HOOK(int, 0, inode_set_acl, struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
+LSM_HOOK(int, 0, inode_get_acl, struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+LSM_HOOK(int, 0, inode_remove_acl, struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
LSM_HOOK(int, 0, inode_killpriv, struct user_namespace *mnt_userns,
struct dentry *dentry)
@@ -177,6 +183,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
struct fown_struct *fown, int sig)
LSM_HOOK(int, 0, file_receive, struct file *file)
LSM_HOOK(int, 0, file_open, struct file *file)
+LSM_HOOK(int, 0, file_truncate, struct file *file)
LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
unsigned long clone_flags)
LSM_HOOK(void, LSM_RET_VOID, task_free, struct task_struct *task)
@@ -302,7 +309,7 @@ LSM_HOOK(int, 0, socket_setsockopt, struct socket *sock, int level, int optname)
LSM_HOOK(int, 0, socket_shutdown, struct socket *sock, int how)
LSM_HOOK(int, 0, socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
LSM_HOOK(int, 0, socket_getpeersec_stream, struct socket *sock,
- char __user *optval, int __user *optlen, unsigned len)
+ sockptr_t optval, sockptr_t optlen, unsigned int len)
LSM_HOOK(int, 0, socket_getpeersec_dgram, struct socket *sock,
struct sk_buff *skb, u32 *secid)
LSM_HOOK(int, 0, sk_alloc_security, struct sock *sk, int family, gfp_t priority)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 4ec80b96c22e..0a5ba81f7367 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -92,13 +92,14 @@
* is initialised to NULL by the caller.
* @fc indicates the new filesystem context.
* @src_fc indicates the original filesystem context.
+ * Return 0 on success or a negative error code on failure.
* @fs_context_parse_param:
* Userspace provided a parameter to configure a superblock. The LSM may
* reject it with an error and may use it for itself, in which case it
* should return 0; otherwise it should return -ENOPARAM to pass it on to
* the filesystem.
* @fc indicates the filesystem context.
- * @param The parameter
+ * @param The parameter.
*
* Security hooks for filesystem operations.
*
@@ -118,6 +119,7 @@
* Free memory associated with @mnt_ops.
* @sb_eat_lsm_opts:
* Eat (scan @orig options) and save them in @mnt_opts.
+ * Return 0 on success, negative values on failure.
* @sb_statfs:
* Check permission before obtaining filesystem statistics for the @mnt
* mountpoint.
@@ -136,31 +138,24 @@
* @flags contains the mount flags.
* @data contains the filesystem-specific data.
* Return 0 if permission is granted.
- * @sb_copy_data:
- * Allow mount option data to be copied prior to parsing by the filesystem,
- * so that the security module can extract security-specific mount
- * options cleanly (a filesystem may modify the data e.g. with strsep()).
- * This also allows the original mount data to be stripped of security-
- * specific options to avoid having to make filesystems aware of them.
- * @orig the original mount data copied from userspace.
- * @copy copied data which will be passed to the security module.
- * Returns 0 if the copy was successful.
* @sb_mnt_opts_compat:
* Determine if the new mount options in @mnt_opts are allowed given
* the existing mounted filesystem at @sb.
- * @sb superblock being compared
- * @mnt_opts new mount options
+ * @sb superblock being compared.
+ * @mnt_opts new mount options.
* Return 0 if options are compatible.
* @sb_remount:
* Extracts security system specific mount options and verifies no changes
* are being made to those options.
- * @sb superblock being remounted
+ * @sb superblock being remounted.
* @data contains the filesystem-specific data.
* Return 0 if permission is granted.
* @sb_kern_mount:
- * Mount this @sb if allowed by permissions.
+ * Mount this @sb if allowed by permissions.
+ * Return 0 if permission is granted.
* @sb_show_options:
* Show (print on @m) mount options for this @sb.
+ * Return 0 on success, negative values on failure.
* @sb_umount:
* Check permission before the @mnt file system is unmounted.
* @mnt contains the mounted file system.
@@ -174,31 +169,31 @@
* Return 0 if permission is granted.
* @sb_set_mnt_opts:
* Set the security relevant mount options used for a superblock
- * @sb the superblock to set security mount options for
- * @opts binary data structure containing all lsm mount data
+ * @sb the superblock to set security mount options for.
+ * @opts binary data structure containing all lsm mount data.
+ * Return 0 on success, error on failure.
* @sb_clone_mnt_opts:
* Copy all security options from a given superblock to another
- * @oldsb old superblock which contain information to clone
- * @newsb new superblock which needs filled in
- * @sb_parse_opts_str:
- * Parse a string of security data filling in the opts structure
- * @options string containing all mount options known by the LSM
- * @opts binary data structure usable by the LSM
+ * @oldsb old superblock which contain information to clone.
+ * @newsb new superblock which needs filled in.
+ * Return 0 on success, error on failure.
* @move_mount:
* Check permission before a mount is moved.
* @from_path indicates the mount that is going to be moved.
* @to_path indicates the mountpoint that will be mounted upon.
+ * Return 0 if permission is granted.
* @dentry_init_security:
* Compute a context for a dentry as the inode is not yet available
* since NFSv4 has no label backed by an EA anyway.
* @dentry dentry to use in calculating the context.
* @mode mode used to determine resource type.
- * @name name of the last path component used to create file
+ * @name name of the last path component used to create file.
* @xattr_name pointer to place the pointer to security xattr name.
* Caller does not have to free the resulting pointer. Its
* a pointer to static string.
* @ctx pointer to place the pointer to the resulting context in.
* @ctxlen point to place the length of the resulting context.
+ * Return 0 on success, negative values on failure.
* @dentry_create_files_as:
* Compute a context for a dentry as the inode is not yet available
* and set that context in passed in creds so that new files are
@@ -206,9 +201,10 @@
* passed in creds and not the creds of the caller.
* @dentry dentry to use in calculating the context.
* @mode mode used to determine resource type.
- * @name name of the last path component used to create file
- * @old creds which should be used for context calculation
- * @new creds to modify
+ * @name name of the last path component used to create file.
+ * @old creds which should be used for context calculation.
+ * @new creds to modify.
+ * Return 0 on success, error on failure.
*
*
* Security hooks for inode operations.
@@ -236,7 +232,7 @@
* then it should return -EOPNOTSUPP to skip this processing.
* @inode contains the inode structure of the newly created inode.
* @dir contains the inode structure of the parent directory.
- * @qstr contains the last path component of the new object
+ * @qstr contains the last path component of the new object.
* @name will be set to the allocated name suffix (e.g. selinux).
* @value will be set to the allocated attribute value.
* @len will be set to the length of the value.
@@ -247,9 +243,9 @@
* Set up the incore security field for the new anonymous inode
* and return whether the inode creation is permitted by the security
* module or not.
- * @inode contains the inode structure
- * @name name of the anonymous inode class
- * @context_inode optional related inode
+ * @inode contains the inode structure.
+ * @name name of the anonymous inode class.
+ * @context_inode optional related inode.
* Returns 0 on success, -EACCES if the security module denies the
* creation of this inode, or another -errno upon other errors.
* @inode_create:
@@ -365,7 +361,7 @@
* mode is specified in @mode.
* @path contains the path structure of the file to change the mode.
* @mode contains the new DAC's permission, which is a bitmask of
- * constants from <include/uapi/linux/stat.h>
+ * constants from <include/uapi/linux/stat.h>.
* Return 0 if permission is granted.
* @path_chown:
* Check for permission to change owner/group of a file or directory.
@@ -380,6 +376,7 @@
* @path_notify:
* Check permissions before setting a watch on events as defined by @mask,
* on an object at @path, whose type is defined by @obj_type.
+ * Return 0 if permission is granted.
* @inode_readlink:
* Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link.
@@ -387,7 +384,7 @@
* @inode_follow_link:
* Check permission to follow a symbolic link when looking up a pathname.
* @dentry contains the dentry structure for the link.
- * @inode contains the inode, which itself is not stable in RCU-walk
+ * @inode contains the inode, which itself is not stable in RCU-walk.
* @rcu indicates whether we are in RCU-walk mode.
* Return 0 if permission is granted.
* @inode_permission:
@@ -409,7 +406,9 @@
* @attr is the iattr structure containing the new file attributes.
* Return 0 if permission is granted.
* @path_truncate:
- * Check permission before truncating a file.
+ * Check permission before truncating the file indicated by path.
+ * Note that truncation permissions may also be checked based on
+ * already opened files, using the @file_truncate hook.
* @path contains the path structure for the file.
* Return 0 if permission is granted.
* @inode_getattr:
@@ -435,13 +434,25 @@
* Check permission before removing the extended attribute
* identified by @name for @dentry.
* Return 0 if permission is granted.
+ * @inode_set_acl:
+ * Check permission before setting posix acls
+ * The posix acls in @kacl are identified by @acl_name.
+ * Return 0 if permission is granted.
+ * @inode_get_acl:
+ * Check permission before getting osix acls
+ * The posix acls are identified by @acl_name.
+ * Return 0 if permission is granted.
+ * @inode_remove_acl:
+ * Check permission before removing posix acls
+ * The posix acls are identified by @acl_name.
+ * Return 0 if permission is granted.
* @inode_getsecurity:
* Retrieve a copy of the extended attribute representation of the
* security label associated with @name for @inode via @buffer. Note that
* @name is the remainder of the attribute name after the security prefix
- * has been removed. @alloc is used to specify of the call should return a
- * value via the buffer or just the value length Return size of buffer on
- * success.
+ * has been removed. @alloc is used to specify if the call should return a
+ * value via the buffer or just the value length.
+ * Return size of buffer on success.
* @inode_setsecurity:
* Set the security label associated with @name for @inode from the
* extended attribute value @value. @size indicates the size of the
@@ -464,7 +475,7 @@
* @inode_killpriv:
* The setuid bit is being removed. Remove similar security labels.
* Called with the dentry->d_inode->i_mutex held.
- * @mnt_userns: user namespace of the mount
+ * @mnt_userns: user namespace of the mount.
* @dentry is the dentry being changed.
* Return 0 on success. If error is returned, then the operation
* causing setuid bit removal is failed.
@@ -491,20 +502,22 @@
* to abort the copy up. Note that the caller is responsible for reading
* and writing the xattrs as this hook is merely a filter.
* @d_instantiate:
- * Fill in @inode security information for a @dentry if allowed.
+ * Fill in @inode security information for a @dentry if allowed.
* @getprocattr:
- * Read attribute @name for process @p and store it into @value if allowed.
+ * Read attribute @name for process @p and store it into @value if allowed.
+ * Return the length of @value on success, a negative value otherwise.
* @setprocattr:
- * Write (set) attribute @name to @value, size @size if allowed.
+ * Write (set) attribute @name to @value, size @size if allowed.
+ * Return written bytes on success, a negative value otherwise.
*
* Security hooks for kernfs node operations
*
* @kernfs_init_security:
* Initialize the security context of a newly created kernfs node based
* on its own and its parent's attributes.
- *
- * @kn_dir the parent kernfs node
- * @kn the new child kernfs node
+ * @kn_dir the parent kernfs node.
+ * @kn the new child kernfs node.
+ * Return 0 if permission is granted.
*
* Security hooks for file operations
*
@@ -543,11 +556,11 @@
* simple integer value. When @arg represents a user space pointer, it
* should never be used by the security module.
* Return 0 if permission is granted.
- * @mmap_addr :
+ * @mmap_addr:
* Check permissions for a mmap operation at @addr.
* @addr contains virtual address that will be used for the operation.
* Return 0 if permission is granted.
- * @mmap_file :
+ * @mmap_file:
* Check permissions for a mmap operation. The @file may be NULL, e.g.
* if mapping anonymous memory.
* @file contains the file structure for file to map (may be NULL).
@@ -598,10 +611,17 @@
* to receive an open file descriptor via socket IPC.
* @file contains the file structure being received.
* Return 0 if permission is granted.
+ * @file_truncate:
+ * Check permission before truncating a file, i.e. using ftruncate.
+ * Note that truncation permission may also be checked based on the path,
+ * using the @path_truncate hook.
+ * @file contains the file structure for the file.
+ * Return 0 if permission is granted.
* @file_open:
* Save open-time permission checking state for later use upon
* file_permission, and recheck access if anything has changed
* since inode_permission.
+ * Return 0 if permission is granted.
*
* Security hooks for task operations.
*
@@ -619,6 +639,7 @@
* @gfp indicates the atomicity of any memory allocations.
* Only allocate sufficient memory and attach to @cred such that
* cred_transfer() will not get ENOMEM.
+ * Return 0 on success, negative values on failure.
* @cred_free:
* @cred points to the credentials.
* Deallocate and clear the cred->security field in a set of credentials.
@@ -627,6 +648,7 @@
* @old points to the original credentials.
* @gfp indicates the atomicity of any memory allocations.
* Prepare a new set of credentials by copying the data from the old set.
+ * Return 0 on success, negative values on failure.
* @cred_transfer:
* @new points to the new credentials.
* @old points to the original credentials.
@@ -638,7 +660,7 @@
* @kernel_act_as:
* Set the credentials for a kernel service to act as (subjective context).
* @new points to the credentials to be modified.
- * @secid specifies the security ID to be set
+ * @secid specifies the security ID to be set.
* The current task must be the one that nominated @secid.
* Return 0 if successful.
* @kernel_create_files_as:
@@ -651,19 +673,19 @@
* @kernel_module_request:
* Ability to trigger the kernel to automatically upcall to userspace for
* userspace to load a kernel module with the given name.
- * @kmod_name name of the module requested by the kernel
+ * @kmod_name name of the module requested by the kernel.
* Return 0 if successful.
* @kernel_load_data:
* Load data provided by userspace.
- * @id kernel load data identifier
+ * @id kernel load data identifier.
* @contents if a subsequent @kernel_post_load_data will be called.
* Return 0 if permission is granted.
* @kernel_post_load_data:
* Load data provided by a non-file source (usually userspace buffer).
* @buf pointer to buffer containing the data contents.
* @size length of the data contents.
- * @id kernel load data identifier
- * @description a text description of what was loaded, @id-specific
+ * @id kernel load data identifier.
+ * @description a text description of what was loaded, @id-specific.
* Return 0 if permission is granted.
* This must be paired with a prior @kernel_load_data call that had
* @contents set to true.
@@ -671,7 +693,7 @@
* Read a file specified by userspace.
* @file contains the file structure pointing to the file being read
* by the kernel.
- * @id kernel read file identifier
+ * @id kernel read file identifier.
* @contents if a subsequent @kernel_post_read_file will be called.
* Return 0 if permission is granted.
* @kernel_post_read_file:
@@ -680,7 +702,7 @@
* by the kernel.
* @buf pointer to buffer containing the file contents.
* @size length of the file contents.
- * @id kernel read file identifier
+ * @id kernel read file identifier.
* This must be paired with a prior @kernel_read_file call that had
* @contents set to true.
* Return 0 if permission is granted.
@@ -690,7 +712,7 @@
* indicates which of the set*uid system calls invoked this hook. If
* @new is the set of credentials that will be installed. Modifications
* should be made to this rather than to @current->cred.
- * @old is the set of credentials that are being replaces
+ * @old is the set of credentials that are being replaced.
* @flags contains one of the LSM_SETID_* values.
* Return 0 on success.
* @task_fix_setgid:
@@ -742,7 +764,7 @@
* @task_setioprio:
* Check permission before setting the ioprio value of @p to @ioprio.
* @p contains the task_struct of process.
- * @ioprio contains the new ioprio value
+ * @ioprio contains the new ioprio value.
* Return 0 if permission is granted.
* @task_getioprio:
* Check permission before getting the ioprio value of @p.
@@ -873,6 +895,7 @@
* @type contains the requested communications type.
* @protocol contains the requested protocol.
* @kern set to 1 if a kernel socket.
+ * Return 0 if permission is granted.
* @socket_socketpair:
* Check permissions before creating a fresh pair of sockets.
* @socka contains the first socket structure.
@@ -956,14 +979,15 @@
* Must not sleep inside this hook because some callers hold spinlocks.
* @sk contains the sock (not socket) associated with the incoming sk_buff.
* @skb contains the incoming network data.
+ * Return 0 if permission is granted.
* @socket_getpeersec_stream:
* This hook allows the security module to provide peer socket security
* state for unix or connected tcp sockets to userspace via getsockopt
* SO_GETPEERSEC. For tcp sockets this can be meaningful if the
* socket is associated with an ipsec SA.
* @sock is the local socket.
- * @optval userspace memory where the security state is to be copied.
- * @optlen userspace int where the module should copy the actual length
+ * @optval memory where the security state is to be copied.
+ * @optlen memory where the module should copy the actual length
* of the security state.
* @len as input is the maximum length to copy to userspace provided
* by the caller.
@@ -983,6 +1007,7 @@
* @sk_alloc_security:
* Allocate and attach a security structure to the sk->sk_security field,
* which is used to copy security attributes between local stream sockets.
+ * Return 0 on success, error on failure.
* @sk_free_security:
* Deallocate security structure.
* @sk_clone_security:
@@ -995,17 +1020,19 @@
* @inet_conn_request:
* Sets the openreq's sid to socket's sid with MLS portion taken
* from peer sid.
+ * Return 0 if permission is granted.
* @inet_csk_clone:
* Sets the new child socket's sid to the openreq sid.
* @inet_conn_established:
* Sets the connection's peersid to the secmark on skb.
* @secmark_relabel_packet:
- * check if the process should be allowed to relabel packets to
- * the given secid
+ * Check if the process should be allowed to relabel packets to
+ * the given secid.
+ * Return 0 if permission is granted.
* @secmark_refcount_inc:
- * tells the LSM to increment the number of secmark labeling rules loaded
+ * Tells the LSM to increment the number of secmark labeling rules loaded.
* @secmark_refcount_dec:
- * tells the LSM to decrement the number of secmark labeling rules loaded
+ * Tells the LSM to decrement the number of secmark labeling rules loaded.
* @req_classify_flow:
* Sets the flow's sid to the openreq sid.
* @tun_dev_alloc_security:
@@ -1016,21 +1043,25 @@
* @tun_dev_free_security:
* This hook allows a module to free the security structure for a TUN
* device.
- * @security pointer to the TUN device's security structure
+ * @security pointer to the TUN device's security structure.
* @tun_dev_create:
* Check permissions prior to creating a new TUN device.
+ * Return 0 if permission is granted.
* @tun_dev_attach_queue:
* Check permissions prior to attaching to a TUN device queue.
* @security pointer to the TUN device's security structure.
+ * Return 0 if permission is granted.
* @tun_dev_attach:
* This hook can be used by the module to update any security state
* associated with the TUN device's sock structure.
* @sk contains the existing sock structure.
* @security pointer to the TUN device's security structure.
+ * Return 0 if permission is granted.
* @tun_dev_open:
* This hook can be used by the module to update any security state
* associated with the TUN device's security structure.
* @security pointer to the TUN devices's security structure.
+ * Return 0 if permission is granted.
*
* Security hooks for SCTP
*
@@ -1063,6 +1094,7 @@
* to the security module.
* @asoc pointer to sctp association structure.
* @skb pointer to skbuff of association packet.
+ * Return 0 if permission is granted.
*
* Security hooks for Infiniband
*
@@ -1071,15 +1103,17 @@
* @subnet_prefix the subnet prefix of the port being used.
* @pkey the pkey to be accessed.
* @sec pointer to a security structure.
+ * Return 0 if permission is granted.
* @ib_endport_manage_subnet:
* Check permissions to send and receive SMPs on a end port.
* @dev_name the IB device name (i.e. mlx4_0).
* @port_num the port number.
* @sec pointer to a security structure.
+ * Return 0 if permission is granted.
* @ib_alloc_security:
* Allocate a security structure for Infiniband objects.
* @sec pointer to a security structure pointer.
- * Returns 0 on success, non-zero on failure
+ * Returns 0 on success, non-zero on failure.
* @ib_free_security:
* Deallocate an Infiniband security structure.
* @sec contains the security structure to be freed.
@@ -1091,10 +1125,11 @@
* Database used by the XFRM system.
* @sec_ctx contains the security context information being provided by
* the user-level policy update program (e.g., setkey).
+ * @gfp is to specify the context for the allocation.
* Allocate a security structure to the xp->security field; the security
* field is initialized to NULL when the xfrm_policy is allocated.
- * Return 0 if operation was successful (memory to allocate, legal context)
- * @gfp is to specify the context for the allocation
+ * Return 0 if operation was successful (memory to allocate, legal
+ * context).
* @xfrm_policy_clone_security:
* @old_ctx contains an existing xfrm_sec_ctx.
* @new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@@ -1102,11 +1137,12 @@
* information from the old_ctx structure.
* Return 0 if operation was successful (memory to allocate).
* @xfrm_policy_free_security:
- * @ctx contains the xfrm_sec_ctx
+ * @ctx contains the xfrm_sec_ctx.
* Deallocate xp->security.
* @xfrm_policy_delete_security:
* @ctx contains the xfrm_sec_ctx.
* Authorize deletion of xp->security.
+ * Return 0 if permission is granted.
* @xfrm_state_alloc:
* @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system.
@@ -1132,6 +1168,7 @@
* @xfrm_state_delete_security:
* @x contains the xfrm_state.
* Authorize deletion of x->security.
+ * Return 0 if permission is granted.
* @xfrm_policy_lookup:
* @ctx contains the xfrm_sec_ctx for which the access control is being
* checked.
@@ -1160,7 +1197,7 @@
* Permit allocation of a key and assign security data. Note that key does
* not have a serial number assigned at this point.
* @key points to the key.
- * @flags is the allocation flags
+ * @flags is the allocation flags.
* Return 0 if permission is granted, -ve error otherwise.
* @key_free:
* Notification of destruction; free security data.
@@ -1190,8 +1227,8 @@
*
* @ipc_permission:
* Check permissions for access to IPC
- * @ipcp contains the kernel IPC permission structure
- * @flag contains the desired (requested) permission set
+ * @ipcp contains the kernel IPC permission structure.
+ * @flag contains the desired (requested) permission set.
* Return 0 if permission is granted.
* @ipc_getsecid:
* Get the secid associated with the ipc object.
@@ -1336,15 +1373,18 @@
* to @to.
* @from contains the struct cred for the sending process.
* @to contains the struct cred for the receiving process.
+ * Return 0 if permission is granted.
* @binder_transfer_binder:
* Check whether @from is allowed to transfer a binder reference to @to.
* @from contains the struct cred for the sending process.
* @to contains the struct cred for the receiving process.
+ * Return 0 if permission is granted.
* @binder_transfer_file:
* Check whether @from is allowed to transfer @file to @to.
* @from contains the struct cred for the sending process.
* @file contains the struct file being transferred.
* @to contains the struct cred for the receiving process.
+ * Return 0 if permission is granted.
*
* @ptrace_access_check:
* Check permission before allowing the current process to trace the
@@ -1386,32 +1426,39 @@
* Check whether the @tsk process has the @cap capability in the indicated
* credentials.
* @cred contains the credentials to use.
- * @ns contains the user namespace we want the capability in
+ * @ns contains the user namespace we want the capability in.
* @cap contains the capability <include/linux/capability.h>.
- * @opts contains options for the capable check <include/linux/security.h>
+ * @opts contains options for the capable check <include/linux/security.h>.
* Return 0 if the capability is granted for @tsk.
* @quotactl:
- * Check whether the quotactl syscall is allowed for this @sb.
+ * Check whether the quotactl syscall is allowed for this @sb.
+ * Return 0 if permission is granted.
* @quota_on:
- * Check whether QUOTAON is allowed for this @dentry.
+ * Check whether QUOTAON is allowed for this @dentry.
+ * Return 0 if permission is granted.
* @syslog:
* Check permission before accessing the kernel message ring or changing
* logging to the console.
* See the syslog(2) manual page for an explanation of the @type values.
- * @type contains the SYSLOG_ACTION_* constant from <include/linux/syslog.h>
+ * @type contains the SYSLOG_ACTION_* constant from
+ * <include/linux/syslog.h>.
* Return 0 if permission is granted.
* @settime:
* Check permission to change the system time.
* struct timespec64 is defined in <include/linux/time64.h> and timezone
* is defined in <include/linux/time.h>
- * @ts contains new time
- * @tz contains new timezone
+ * @ts contains new time.
+ * @tz contains new timezone.
* Return 0 if permission is granted.
* @vm_enough_memory:
* Check permissions for allocating a new virtual mapping.
* @mm contains the mm struct it is being added to.
* @pages contains the number of pages.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted by the LSM infrastructure to the
+ * caller. If all LSMs return a positive value, __vm_enough_memory() will
+ * be called with cap_sys_admin set. If at least one LSM returns 0 or
+ * negative, __vm_enough_memory() will be called with cap_sys_admin
+ * cleared.
*
* @ismaclabel:
* Check if the extended attribute specified by @name
@@ -1429,11 +1476,13 @@
* @secid contains the security ID.
* @secdata contains the pointer that stores the converted security
* context.
- * @seclen pointer which contains the length of the data
+ * @seclen pointer which contains the length of the data.
+ * Return 0 on success, error on failure.
* @secctx_to_secid:
* Convert security context to secid.
* @secid contains the pointer to the generated security ID.
* @secdata contains the security context.
+ * Return 0 on success, error on failure.
*
* @release_secctx:
* Release the security context.
@@ -1470,7 +1519,7 @@
* @audit_rule_free:
* Deallocate the LSM audit rule structure previously allocated by
* audit_rule_init.
- * @lsmrule contains the allocated rule
+ * @lsmrule contains the allocated rule.
*
* @inode_invalidate_secctx:
* Notify the security module that it must revalidate the security context
@@ -1487,6 +1536,7 @@
* @inode we wish to set the security context of.
* @ctx contains the string which we wish to set in the inode.
* @ctxlen contains the length of @ctx.
+ * Return 0 on success, error on failure.
*
* @inode_setsecctx:
* Change the security context of an inode. Updates the
@@ -1500,6 +1550,7 @@
* @dentry contains the inode we wish to set the security context of.
* @ctx contains the string which we wish to set in the inode.
* @ctxlen contains the length of @ctx.
+ * Return 0 on success, error on failure.
*
* @inode_getsecctx:
* On success, returns 0 and fills out @ctx and @ctxlen with the security
@@ -1507,6 +1558,7 @@
* @inode we wish to get the security context of.
* @ctx is a pointer in which to place the allocated security context.
* @ctxlen points to the place to put the length of @ctx.
+ * Return 0 on success, error on failure.
*
* Security hooks for the general notification queue:
*
@@ -1514,13 +1566,15 @@
* Check to see if a watch notification can be posted to a particular
* queue.
* @w_cred: The credentials of the whoever set the watch.
- * @cred: The event-triggerer's credentials
- * @n: The notification being posted
+ * @cred: The event-triggerer's credentials.
+ * @n: The notification being posted.
+ * Return 0 if permission is granted.
*
* @watch_key:
* Check to see if a process is allowed to watch for event notifications
* from a key or keyring.
* @key: The key to watch.
+ * Return 0 if permission is granted.
*
* Security hooks for using the eBPF maps and programs functionalities through
* eBPF syscalls.
@@ -1529,65 +1583,74 @@
* Do a initial check for all bpf syscalls after the attribute is copied
* into the kernel. The actual security module can implement their own
* rules to check the specific cmd they need.
+ * Return 0 if permission is granted.
*
* @bpf_map:
* Do a check when the kernel generate and return a file descriptor for
* eBPF maps.
- *
- * @map: bpf map that we want to access
- * @mask: the access flags
+ * @map: bpf map that we want to access.
+ * @mask: the access flags.
+ * Return 0 if permission is granted.
*
* @bpf_prog:
* Do a check when the kernel generate and return a file descriptor for
* eBPF programs.
- *
* @prog: bpf prog that userspace want to use.
+ * Return 0 if permission is granted.
*
* @bpf_map_alloc_security:
* Initialize the security field inside bpf map.
+ * Return 0 on success, error on failure.
*
* @bpf_map_free_security:
* Clean up the security information stored inside bpf map.
*
* @bpf_prog_alloc_security:
* Initialize the security field inside bpf program.
+ * Return 0 on success, error on failure.
*
* @bpf_prog_free_security:
* Clean up the security information stored inside bpf prog.
*
* @locked_down:
- * Determine whether a kernel feature that potentially enables arbitrary
- * code execution in kernel space should be permitted.
- *
- * @what: kernel feature being accessed
+ * Determine whether a kernel feature that potentially enables arbitrary
+ * code execution in kernel space should be permitted.
+ * @what: kernel feature being accessed.
+ * Return 0 if permission is granted.
*
* Security hooks for perf events
*
* @perf_event_open:
- * Check whether the @type of perf_event_open syscall is allowed.
+ * Check whether the @type of perf_event_open syscall is allowed.
+ * Return 0 if permission is granted.
* @perf_event_alloc:
- * Allocate and save perf_event security info.
+ * Allocate and save perf_event security info.
+ * Return 0 on success, error on failure.
* @perf_event_free:
- * Release (free) perf_event security info.
+ * Release (free) perf_event security info.
* @perf_event_read:
- * Read perf_event security info if allowed.
+ * Read perf_event security info if allowed.
+ * Return 0 if permission is granted.
* @perf_event_write:
- * Write perf_event security info if allowed.
+ * Write perf_event security info if allowed.
+ * Return 0 if permission is granted.
*
* Security hooks for io_uring
*
* @uring_override_creds:
- * Check if the current task, executing an io_uring operation, is allowed
- * to override it's credentials with @new.
- *
- * @new: the new creds to use
+ * Check if the current task, executing an io_uring operation, is allowed
+ * to override it's credentials with @new.
+ * @new: the new creds to use.
+ * Return 0 if permission is granted.
*
* @uring_sqpoll:
- * Check whether the current task is allowed to spawn a io_uring polling
- * thread (IORING_SETUP_SQPOLL).
+ * Check whether the current task is allowed to spawn a io_uring polling
+ * thread (IORING_SETUP_SQPOLL).
+ * Return 0 if permission is granted.
*
* @uring_cmd:
- * Check whether the file_operations uring_cmd is allowed to run.
+ * Check whether the file_operations uring_cmd is allowed to run.
+ * Return 0 if permission is granted.
*
*/
union security_list_options {
diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h
index 2effab72add1..e594db58a0f1 100644
--- a/include/linux/maple_tree.h
+++ b/include/linux/maple_tree.h
@@ -638,6 +638,12 @@ static inline void mt_set_in_rcu(struct maple_tree *mt)
}
}
+static inline unsigned int mt_height(const struct maple_tree *mt)
+
+{
+ return (mt->ma_flags & MT_FLAGS_HEIGHT_MASK) >> MT_FLAGS_HEIGHT_OFFSET;
+}
+
void *mt_find(struct maple_tree *mt, unsigned long *index, unsigned long max);
void *mt_find_after(struct maple_tree *mt, unsigned long *index,
unsigned long max);
@@ -664,6 +670,7 @@ extern atomic_t maple_tree_tests_passed;
void mt_dump(const struct maple_tree *mt);
void mt_validate(struct maple_tree *mt);
+void mt_cache_shrink(void);
#define MT_BUG_ON(__tree, __x) do { \
atomic_inc(&maple_tree_tests_run); \
if (__x) { \
diff --git a/include/linux/math64.h b/include/linux/math64.h
index a14f40de1dca..8958f4c005c1 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -29,7 +29,7 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
return dividend / divisor;
}
-/*
+/**
* div_s64_rem - signed 64bit divide with 32bit divisor with remainder
* @dividend: signed 64bit dividend
* @divisor: signed 32bit divisor
@@ -43,7 +43,7 @@ static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
return dividend / divisor;
}
-/*
+/**
* div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
* @dividend: unsigned 64bit dividend
* @divisor: unsigned 64bit divisor
@@ -57,7 +57,7 @@ static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
return dividend / divisor;
}
-/*
+/**
* div64_u64 - unsigned 64bit divide with 64bit divisor
* @dividend: unsigned 64bit dividend
* @divisor: unsigned 64bit divisor
@@ -69,7 +69,7 @@ static inline u64 div64_u64(u64 dividend, u64 divisor)
return dividend / divisor;
}
-/*
+/**
* div64_s64 - signed 64bit divide with 64bit divisor
* @dividend: signed 64bit dividend
* @divisor: signed 64bit divisor
@@ -120,6 +120,8 @@ extern s64 div64_s64(s64 dividend, s64 divisor);
* This is the most common 64bit divide and should be used if possible,
* as many 32bit archs can optimize this variant better than a full 64bit
* divide.
+ *
+ * Return: dividend / divisor
*/
#ifndef div_u64
static inline u64 div_u64(u64 dividend, u32 divisor)
@@ -133,6 +135,8 @@ static inline u64 div_u64(u64 dividend, u32 divisor)
* div_s64 - signed 64bit divide with 32bit divisor
* @dividend: signed 64bit dividend
* @divisor: signed 32bit divisor
+ *
+ * Return: dividend / divisor
*/
#ifndef div_s64
static inline s64 div_s64(s64 dividend, s32 divisor)
@@ -284,6 +288,16 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor)
u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
+/**
+ * DIV64_U64_ROUND_UP - unsigned 64bit divide with 64bit divisor rounded up
+ * @ll: unsigned 64bit dividend
+ * @d: unsigned 64bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 64bit divisor
+ * and round up.
+ *
+ * Return: dividend / divisor rounded up
+ */
#define DIV64_U64_ROUND_UP(ll, d) \
({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); })
@@ -300,7 +314,7 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
#define DIV64_U64_ROUND_CLOSEST(dividend, divisor) \
({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
-/*
+/**
* DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
* @dividend: unsigned 64bit dividend
* @divisor: unsigned 32bit divisor
@@ -313,7 +327,7 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
#define DIV_U64_ROUND_CLOSEST(dividend, divisor) \
({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
-/*
+/**
* DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
* @dividend: signed 64bit dividend
* @divisor: signed 32bit divisor
diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h
index 2da63fd7b98f..97e64184767d 100644
--- a/include/linux/mbcache.h
+++ b/include/linux/mbcache.h
@@ -10,6 +10,12 @@
struct mb_cache;
+/* Cache entry flags */
+enum {
+ MBE_REFERENCED_B = 0,
+ MBE_REUSABLE_B
+};
+
struct mb_cache_entry {
/* List of entries in cache - protected by cache->c_list_lock */
struct list_head e_list;
@@ -26,8 +32,7 @@ struct mb_cache_entry {
atomic_t e_refcnt;
/* Key in hash - stable during lifetime of the entry */
u32 e_key;
- u32 e_referenced:1;
- u32 e_reusable:1;
+ unsigned long e_flags;
/* User provided value - stable during lifetime of the entry */
u64 e_value;
};
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index df1fab44ea5c..fd6e0620658d 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -11,6 +11,7 @@
struct mei_cl_device;
struct mei_device;
+struct scatterlist;
typedef void (*mei_cldev_cb_t)(struct mei_cl_device *cldev);
@@ -116,6 +117,11 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data);
int mei_cldev_enable(struct mei_cl_device *cldev);
int mei_cldev_disable(struct mei_cl_device *cldev);
bool mei_cldev_enabled(const struct mei_cl_device *cldev);
+ssize_t mei_cldev_send_gsc_command(struct mei_cl_device *cldev,
+ u8 client_id, u32 fence_id,
+ struct scatterlist *sg_in,
+ size_t total_in_len,
+ struct scatterlist *sg_out);
void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size);
int mei_cldev_dma_unmap(struct mei_cl_device *cldev);
diff --git a/include/linux/mempool.h b/include/linux/mempool.h
index 0c964ac107c2..4aae6c06c5f2 100644
--- a/include/linux/mempool.h
+++ b/include/linux/mempool.h
@@ -30,6 +30,11 @@ static inline bool mempool_initialized(mempool_t *pool)
return pool->elements != NULL;
}
+static inline bool mempool_is_saturated(mempool_t *pool)
+{
+ return READ_ONCE(pool->curr_nr) >= pool->min_nr;
+}
+
void mempool_exit(mempool_t *pool);
int mempool_init_node(mempool_t *pool, int min_nr, mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn, void *pool_data,
diff --git a/include/linux/memregion.h b/include/linux/memregion.h
index c04c4fd2e209..bf83363807ac 100644
--- a/include/linux/memregion.h
+++ b/include/linux/memregion.h
@@ -3,6 +3,7 @@
#define _MEMREGION_H_
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/bug.h>
struct memregion_info {
int target_node;
@@ -20,4 +21,41 @@ static inline void memregion_free(int id)
{
}
#endif
+
+/**
+ * cpu_cache_invalidate_memregion - drop any CPU cached data for
+ * memregions described by @res_desc
+ * @res_desc: one of the IORES_DESC_* types
+ *
+ * Perform cache maintenance after a memory event / operation that
+ * changes the contents of physical memory in a cache-incoherent manner.
+ * For example, device memory technologies like NVDIMM and CXL have
+ * device secure erase, and dynamic region provision that can replace
+ * the memory mapped to a given physical address.
+ *
+ * Limit the functionality to architectures that have an efficient way
+ * to writeback and invalidate potentially terabytes of address space at
+ * once. Note that this routine may or may not write back any dirty
+ * contents while performing the invalidation. It is only exported for
+ * the explicit usage of the NVDIMM and CXL modules in the 'DEVMEM'
+ * symbol namespace on bare platforms.
+ *
+ * Returns 0 on success or negative error code on a failure to perform
+ * the cache maintenance.
+ */
+#ifdef CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
+int cpu_cache_invalidate_memregion(int res_desc);
+bool cpu_cache_has_invalidate_memregion(void);
+#else
+static inline bool cpu_cache_has_invalidate_memregion(void)
+{
+ return false;
+}
+
+static inline int cpu_cache_invalidate_memregion(int res_desc)
+{
+ WARN_ON_ONCE("CPU cache invalidation required");
+ return -ENXIO;
+}
+#endif
#endif /* _MEMREGION_H_ */
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 5433c08fcc68..396df1121bff 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -37,6 +37,28 @@
__cmp(x, y, op), \
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
+#define __clamp(val, lo, hi) \
+ ((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val)))
+
+#define __clamp_once(val, lo, hi, unique_val, unique_lo, unique_hi) ({ \
+ typeof(val) unique_val = (val); \
+ typeof(lo) unique_lo = (lo); \
+ typeof(hi) unique_hi = (hi); \
+ __clamp(unique_val, unique_lo, unique_hi); })
+
+#define __clamp_input_check(lo, hi) \
+ (BUILD_BUG_ON_ZERO(__builtin_choose_expr( \
+ __is_constexpr((lo) > (hi)), (lo) > (hi), false)))
+
+#define __careful_clamp(val, lo, hi) ({ \
+ __clamp_input_check(lo, hi) + \
+ __builtin_choose_expr(__typecheck(val, lo) && __typecheck(val, hi) && \
+ __typecheck(hi, lo) && __is_constexpr(val) && \
+ __is_constexpr(lo) && __is_constexpr(hi), \
+ __clamp(val, lo, hi), \
+ __clamp_once(val, lo, hi, __UNIQUE_ID(__val), \
+ __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); })
+
/**
* min - return minimum of two values of the same or compatible types
* @x: first value
@@ -86,7 +108,7 @@
* This macro does strict typechecking of @lo/@hi to make sure they are of the
* same type as @val. See the unnecessary pointer comparisons.
*/
-#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
+#define clamp(val, lo, hi) __careful_clamp(val, lo, hi)
/*
* ..and if you can't take the strict
@@ -121,7 +143,7 @@
* This macro does no typechecking and uses temporary variables of type
* @type to make all the comparisons.
*/
-#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
+#define clamp_t(type, val, lo, hi) __careful_clamp((type)(val), (type)(lo), (type)(hi))
/**
* clamp_val - return a value clamped to a given range using val's type
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index af2ceb4160bc..06cbad166225 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -981,6 +981,7 @@ struct mlx5_async_work {
struct mlx5_async_ctx *ctx;
mlx5_async_cbk_t user_callback;
u16 opcode; /* cmd opcode */
+ u16 op_mod; /* cmd op_mod */
void *out; /* pointer to the cmd output buffer */
};
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 8bbcccbc5565..6a05a3bc0a28 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1129,7 +1129,7 @@ static inline void get_page(struct page *page)
folio_get(page_folio(page));
}
-bool __must_check try_grab_page(struct page *page, unsigned int flags);
+int __must_check try_grab_page(struct page *page, unsigned int flags);
static inline __must_check bool try_get_page(struct page *page)
{
@@ -1852,6 +1852,25 @@ static void __maybe_unused show_free_areas(unsigned int flags, nodemask_t *nodem
__show_free_areas(flags, nodemask, MAX_NR_ZONES - 1);
}
+/*
+ * Parameter block passed down to zap_pte_range in exceptional cases.
+ */
+struct zap_details {
+ struct folio *single_folio; /* Locked folio to be unmapped */
+ bool even_cows; /* Zap COWed private pages too? */
+ zap_flags_t zap_flags; /* Extra flags for zapping */
+};
+
+/*
+ * Whether to drop the pte markers, for example, the uffd-wp information for
+ * file-backed memory. This should only be specified when we will completely
+ * drop the page in the mm, either by truncation or unmapping of the vma. By
+ * default, the flag is not set.
+ */
+#define ZAP_FLAG_DROP_MARKER ((__force zap_flags_t) BIT(0))
+/* Set in unmap_vmas() to indicate a final unmap call. Only used by hugetlb */
+#define ZAP_FLAG_UNMAP ((__force zap_flags_t) BIT(1))
+
#ifdef CONFIG_MMU
extern bool can_do_mlock(void);
#else
@@ -1869,6 +1888,8 @@ void zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
unsigned long size);
void zap_page_range(struct vm_area_struct *vma, unsigned long address,
unsigned long size);
+void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
+ unsigned long size, struct zap_details *details);
void unmap_vmas(struct mmu_gather *tlb, struct maple_tree *mt,
struct vm_area_struct *start_vma, unsigned long start,
unsigned long end);
@@ -2958,6 +2979,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
#define FOLL_SPLIT_PMD 0x20000 /* split huge pmd before returning */
#define FOLL_PIN 0x40000 /* pages must be released via unpin_user_page */
#define FOLL_FAST_ONLY 0x80000 /* gup_fast: prevent fall-back to slow gup */
+#define FOLL_PCI_P2PDMA 0x100000 /* allow returning PCI P2PDMA pages */
/*
* FOLL_PIN and FOLL_LONGTERM may be used in various combinations with each
@@ -3467,12 +3489,4 @@ madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
}
#endif
-/*
- * Whether to drop the pte markers, for example, the uffd-wp information for
- * file-backed memory. This should only be specified when we will completely
- * drop the page in the mm, either by truncation or unmapping of the vma. By
- * default, the flag is not set.
- */
-#define ZAP_FLAG_DROP_MARKER ((__force zap_flags_t) BIT(0))
-
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 9c50bc40f8ff..6f7993803ee7 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -451,7 +451,7 @@ static inline bool mmc_ready_for_data(u32 status)
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
#define MMC_SECURE_ARGS 0x80000000
-#define MMC_TRIM_ARGS 0x00008001
+#define MMC_TRIM_OR_DISCARD_ARGS 0x00008003
#define mmc_driver_type_mask(n) (1 << (n))
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 5f74891556f3..9c49ec5d0e25 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -986,6 +986,25 @@ static inline bool is_zone_device_page(const struct page *page)
{
return page_zonenum(page) == ZONE_DEVICE;
}
+
+/*
+ * Consecutive zone device pages should not be merged into the same sgl
+ * or bvec segment with other types of pages or if they belong to different
+ * pgmaps. Otherwise getting the pgmap of a given segment is not possible
+ * without scanning the entire segment. This helper returns true either if
+ * both pages are not zone device pages or both pages are zone device pages
+ * with the same pgmap.
+ */
+static inline bool zone_device_pages_have_same_pgmap(const struct page *a,
+ const struct page *b)
+{
+ if (is_zone_device_page(a) != is_zone_device_page(b))
+ return false;
+ if (!is_zone_device_page(a))
+ return true;
+ return a->pgmap == b->pgmap;
+}
+
extern void memmap_init_zone_device(struct zone *, unsigned long,
unsigned long, struct dev_pagemap *);
#else
@@ -993,6 +1012,11 @@ static inline bool is_zone_device_page(const struct page *page)
{
return false;
}
+static inline bool zone_device_pages_have_same_pgmap(const struct page *a,
+ const struct page *b)
+{
+ return true;
+}
#endif
static inline bool folio_is_zone_device(const struct folio *folio)
diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h
index f6e5369d2928..092c52aa6c2c 100644
--- a/include/linux/mnt_idmapping.h
+++ b/include/linux/mnt_idmapping.h
@@ -5,12 +5,10 @@
#include <linux/types.h>
#include <linux/uidgid.h>
+struct mnt_idmap;
struct user_namespace;
-/*
- * Carries the initial idmapping of 0:0:4294967295 which is an identity
- * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is
- * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...].
- */
+
+extern struct mnt_idmap nop_mnt_idmap;
extern struct user_namespace init_user_ns;
typedef struct {
@@ -98,6 +96,26 @@ static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid);
}
+static inline bool vfsuid_gt_kuid(vfsuid_t vfsuid, kuid_t kuid)
+{
+ return __vfsuid_val(vfsuid) > __kuid_val(kuid);
+}
+
+static inline bool vfsgid_gt_kgid(vfsgid_t vfsgid, kgid_t kgid)
+{
+ return __vfsgid_val(vfsgid) > __kgid_val(kgid);
+}
+
+static inline bool vfsuid_lt_kuid(vfsuid_t vfsuid, kuid_t kuid)
+{
+ return __vfsuid_val(vfsuid) < __kuid_val(kuid);
+}
+
+static inline bool vfsgid_lt_kgid(vfsgid_t vfsgid, kgid_t kgid)
+{
+ return __vfsgid_val(vfsgid) < __kgid_val(kgid);
+}
+
/*
* vfs{g,u}ids are created from k{g,u}ids.
* We don't allow them to be created from regular {u,g}id.
@@ -208,13 +226,6 @@ static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns,
return VFSUIDT_INIT(make_kuid(mnt_userns, uid));
}
-static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- kuid_t kuid)
-{
- return AS_KUIDT(make_vfsuid(mnt_userns, fs_userns, kuid));
-}
-
/**
* make_vfsgid - map a filesystem kgid into a mnt_userns
* @mnt_userns: the mount's idmapping
@@ -253,13 +264,6 @@ static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
return VFSGIDT_INIT(make_kgid(mnt_userns, gid));
}
-static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- kgid_t kgid)
-{
- return AS_KGIDT(make_vfsgid(mnt_userns, fs_userns, kgid));
-}
-
/**
* from_vfsuid - map a vfsuid into the filesystem idmapping
* @mnt_userns: the mount's idmapping
@@ -288,33 +292,6 @@ static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
}
/**
- * mapped_kuid_user - map a user kuid into a mnt_userns
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
- * @kuid : kuid to be mapped
- *
- * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
- * function when preparing a @kuid to be written to disk or inode.
- *
- * If no_idmapping() determines that this is not an idmapped mount we can
- * simply return @kuid unchanged.
- * If initial_idmapping() tells us that the filesystem is not mounted with an
- * idmapping we know the value of @kuid won't change when calling
- * make_kuid() so we can simply retrieve the value via KUIDT_INIT()
- * directly.
- *
- * Return: @kuid mapped according to @mnt_userns.
- * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
- * returned.
- */
-static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- kuid_t kuid)
-{
- return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
-}
-
-/**
* vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
@@ -333,6 +310,12 @@ static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
}
+static inline bool vfsuid_has_mapping(struct user_namespace *userns,
+ vfsuid_t vfsuid)
+{
+ return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1;
+}
+
/**
* vfsuid_into_kuid - convert vfsuid into kuid
* @vfsuid: the vfsuid to convert
@@ -374,33 +357,6 @@ static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
}
/**
- * mapped_kgid_user - map a user kgid into a mnt_userns
- * @mnt_userns: the mount's idmapping
- * @fs_userns: the filesystem's idmapping
- * @kgid : kgid to be mapped
- *
- * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
- * function when preparing a @kgid to be written to disk or inode.
- *
- * If no_idmapping() determines that this is not an idmapped mount we can
- * simply return @kgid unchanged.
- * If initial_idmapping() tells us that the filesystem is not mounted with an
- * idmapping we know the value of @kgid won't change when calling
- * make_kgid() so we can simply retrieve the value via KGIDT_INIT()
- * directly.
- *
- * Return: @kgid mapped according to @mnt_userns.
- * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
- * returned.
- */
-static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- kgid_t kgid)
-{
- return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
-}
-
-/**
* vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
@@ -419,6 +375,12 @@ static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
}
+static inline bool vfsgid_has_mapping(struct user_namespace *userns,
+ vfsgid_t vfsgid)
+{
+ return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1;
+}
+
/**
* vfsgid_into_kgid - convert vfsgid into kgid
* @vfsgid: the vfsgid to convert
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 55a4abaf6715..62475996fac6 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -16,6 +16,7 @@
struct super_block;
struct dentry;
struct user_namespace;
+struct mnt_idmap;
struct file_system_type;
struct fs_context;
struct file;
@@ -70,13 +71,15 @@ struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
int mnt_flags;
- struct user_namespace *mnt_userns;
+ struct mnt_idmap *mnt_idmap;
} __randomize_layout;
-static inline struct user_namespace *mnt_user_ns(const struct vfsmount *mnt)
+struct user_namespace *mnt_user_ns(const struct vfsmount *mnt);
+struct user_namespace *mnt_idmap_owner(const struct mnt_idmap *idmap);
+static inline struct mnt_idmap *mnt_idmap(const struct vfsmount *mnt)
{
/* Pairs with smp_store_release() in do_idmap_mount(). */
- return smp_load_acquire(&mnt->mnt_userns);
+ return smp_load_acquire(&mnt->mnt_idmap);
}
extern int mnt_want_write(struct vfsmount *mnt);
diff --git a/include/linux/msi.h b/include/linux/msi.h
index fc918a658d48..a112b913fff9 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -13,13 +13,20 @@
*
* Regular device drivers have no business with any of these functions and
* especially storing MSI descriptor pointers in random code is considered
- * abuse. The only function which is relevant for drivers is msi_get_virq().
+ * abuse.
+ *
+ * Device driver relevant functions are available in <linux/msi_api.h>
*/
+#include <linux/irqdomain_defs.h>
#include <linux/cpumask.h>
+#include <linux/msi_api.h>
#include <linux/xarray.h>
#include <linux/mutex.h>
#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/bits.h>
+
#include <asm/msi.h>
/* Dummy shadow structures if an architecture does not define them */
@@ -68,19 +75,18 @@ struct msi_msg {
extern int pci_msi_ignore_mask;
/* Helper functions */
-struct irq_data;
struct msi_desc;
struct pci_dev;
struct platform_msi_priv_data;
struct device_attribute;
+struct irq_domain;
+struct irq_affinity_desc;
void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
#ifdef CONFIG_GENERIC_MSI_IRQ
void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
#else
-static inline void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
-}
+static inline void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) { }
#endif
typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc,
@@ -120,6 +126,38 @@ struct pci_msi_desc {
};
};
+/**
+ * union msi_domain_cookie - Opaque MSI domain specific data
+ * @value: u64 value store
+ * @ptr: Pointer to domain specific data
+ * @iobase: Domain specific IOmem pointer
+ *
+ * The content of this data is implementation defined and used by the MSI
+ * domain to store domain specific information which is requried for
+ * interrupt chip callbacks.
+ */
+union msi_domain_cookie {
+ u64 value;
+ void *ptr;
+ void __iomem *iobase;
+};
+
+/**
+ * struct msi_desc_data - Generic MSI descriptor data
+ * @dcookie: Cookie for MSI domain specific data which is required
+ * for irq_chip callbacks
+ * @icookie: Cookie for the MSI interrupt instance provided by
+ * the usage site to the allocation function
+ *
+ * The content of this data is implementation defined, e.g. PCI/IMS
+ * implementations define the meaning of the data. The MSI core ignores
+ * this data completely.
+ */
+struct msi_desc_data {
+ union msi_domain_cookie dcookie;
+ union msi_instance_cookie icookie;
+};
+
#define MSI_MAX_INDEX ((unsigned int)USHRT_MAX)
/**
@@ -137,6 +175,7 @@ struct pci_msi_desc {
*
* @msi_index: Index of the msi descriptor
* @pci: PCI specific msi descriptor data
+ * @data: Generic MSI descriptor data
*/
struct msi_desc {
/* Shared device/bus type independent data */
@@ -156,7 +195,10 @@ struct msi_desc {
void *write_msi_msg_data;
u16 msi_index;
- struct pci_msi_desc pci;
+ union {
+ struct pci_msi_desc pci;
+ struct msi_desc_data data;
+ };
};
/*
@@ -171,33 +213,80 @@ enum msi_desc_filter {
MSI_DESC_ASSOCIATED,
};
+
+/**
+ * struct msi_dev_domain - The internals of MSI domain info per device
+ * @store: Xarray for storing MSI descriptor pointers
+ * @irqdomain: Pointer to a per device interrupt domain
+ */
+struct msi_dev_domain {
+ struct xarray store;
+ struct irq_domain *domain;
+};
+
/**
* msi_device_data - MSI per device data
* @properties: MSI properties which are interesting to drivers
* @platform_data: Platform-MSI specific data
* @mutex: Mutex protecting the MSI descriptor store
- * @__store: Xarray for storing MSI descriptor pointers
+ * @__domains: Internal data for per device MSI domains
* @__iter_idx: Index to search the next entry for iterators
*/
struct msi_device_data {
unsigned long properties;
struct platform_msi_priv_data *platform_data;
struct mutex mutex;
- struct xarray __store;
+ struct msi_dev_domain __domains[MSI_MAX_DEVICE_IRQDOMAINS];
unsigned long __iter_idx;
};
int msi_setup_device_data(struct device *dev);
-unsigned int msi_get_virq(struct device *dev, unsigned int index);
void msi_lock_descs(struct device *dev);
void msi_unlock_descs(struct device *dev);
-struct msi_desc *msi_first_desc(struct device *dev, enum msi_desc_filter filter);
-struct msi_desc *msi_next_desc(struct device *dev, enum msi_desc_filter filter);
+struct msi_desc *msi_domain_first_desc(struct device *dev, unsigned int domid,
+ enum msi_desc_filter filter);
/**
- * msi_for_each_desc - Iterate the MSI descriptors
+ * msi_first_desc - Get the first MSI descriptor of the default irqdomain
+ * @dev: Device to operate on
+ * @filter: Descriptor state filter
+ *
+ * Must be called with the MSI descriptor mutex held, i.e. msi_lock_descs()
+ * must be invoked before the call.
+ *
+ * Return: Pointer to the first MSI descriptor matching the search
+ * criteria, NULL if none found.
+ */
+static inline struct msi_desc *msi_first_desc(struct device *dev,
+ enum msi_desc_filter filter)
+{
+ return msi_domain_first_desc(dev, MSI_DEFAULT_DOMAIN, filter);
+}
+
+struct msi_desc *msi_next_desc(struct device *dev, unsigned int domid,
+ enum msi_desc_filter filter);
+
+/**
+ * msi_domain_for_each_desc - Iterate the MSI descriptors in a specific domain
+ *
+ * @desc: struct msi_desc pointer used as iterator
+ * @dev: struct device pointer - device to iterate
+ * @domid: The id of the interrupt domain which should be walked.
+ * @filter: Filter for descriptor selection
+ *
+ * Notes:
+ * - The loop must be protected with a msi_lock_descs()/msi_unlock_descs()
+ * pair.
+ * - It is safe to remove a retrieved MSI descriptor in the loop.
+ */
+#define msi_domain_for_each_desc(desc, dev, domid, filter) \
+ for ((desc) = msi_domain_first_desc((dev), (domid), (filter)); (desc); \
+ (desc) = msi_next_desc((dev), (domid), (filter)))
+
+/**
+ * msi_for_each_desc - Iterate the MSI descriptors in the default irqdomain
*
* @desc: struct msi_desc pointer used as iterator
* @dev: struct device pointer - device to iterate
@@ -208,9 +297,8 @@ struct msi_desc *msi_next_desc(struct device *dev, enum msi_desc_filter filter);
* pair.
* - It is safe to remove a retrieved MSI descriptor in the loop.
*/
-#define msi_for_each_desc(desc, dev, filter) \
- for ((desc) = msi_first_desc((dev), (filter)); (desc); \
- (desc) = msi_next_desc((dev), (filter)))
+#define msi_for_each_desc(desc, dev, filter) \
+ msi_domain_for_each_desc((desc), (dev), MSI_DEFAULT_DOMAIN, (filter))
#define msi_desc_to_dev(desc) ((desc)->dev)
@@ -237,34 +325,47 @@ static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc,
}
#endif
-#ifdef CONFIG_PCI_MSI
-struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc);
-void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
-#else /* CONFIG_PCI_MSI */
-static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
+int msi_domain_insert_msi_desc(struct device *dev, unsigned int domid,
+ struct msi_desc *init_desc);
+/**
+ * msi_insert_msi_desc - Allocate and initialize a MSI descriptor in the
+ * default irqdomain and insert it at @init_desc->msi_index
+ * @dev: Pointer to the device for which the descriptor is allocated
+ * @init_desc: Pointer to an MSI descriptor to initialize the new descriptor
+ *
+ * Return: 0 on success or an appropriate failure code.
+ */
+static inline int msi_insert_msi_desc(struct device *dev, struct msi_desc *init_desc)
{
+ return msi_domain_insert_msi_desc(dev, MSI_DEFAULT_DOMAIN, init_desc);
}
-#endif /* CONFIG_PCI_MSI */
-int msi_add_msi_desc(struct device *dev, struct msi_desc *init_desc);
-void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
- unsigned int first_index, unsigned int last_index);
+void msi_domain_free_msi_descs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last);
+
+/**
+ * msi_free_msi_descs_range - Free a range of MSI descriptors of a device
+ * in the default irqdomain
+ *
+ * @dev: Device for which to free the descriptors
+ * @first: Index to start freeing from (inclusive)
+ * @last: Last index to be freed (inclusive)
+ */
+static inline void msi_free_msi_descs_range(struct device *dev, unsigned int first,
+ unsigned int last)
+{
+ msi_domain_free_msi_descs_range(dev, MSI_DEFAULT_DOMAIN, first, last);
+}
/**
- * msi_free_msi_descs - Free MSI descriptors of a device
+ * msi_free_msi_descs - Free all MSI descriptors of a device in the default irqdomain
* @dev: Device to free the descriptors
*/
static inline void msi_free_msi_descs(struct device *dev)
{
- msi_free_msi_descs_range(dev, MSI_DESC_ALL, 0, MSI_MAX_INDEX);
+ msi_free_msi_descs_range(dev, 0, MSI_MAX_INDEX);
}
-void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-
-void pci_msi_mask_irq(struct irq_data *data);
-void pci_msi_unmask_irq(struct irq_data *data);
-
/*
* The arch hooks to setup up msi irqs. Default functions are implemented
* as weak symbols so that they /can/ be overriden by architecture specific
@@ -293,7 +394,7 @@ static inline void msi_device_destroy_sysfs(struct device *dev) { }
*/
bool arch_restore_msi_irqs(struct pci_dev *dev);
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+#ifdef CONFIG_GENERIC_MSI_IRQ
#include <linux/irqhandler.h>
@@ -309,19 +410,22 @@ struct msi_domain_info;
* @get_hwirq: Retrieve the resulting hw irq number
* @msi_init: Domain specific init function for MSI interrupts
* @msi_free: Domain specific function to free a MSI interrupts
- * @msi_check: Callback for verification of the domain/info/dev data
* @msi_prepare: Prepare the allocation of the interrupts in the domain
+ * @prepare_desc: Optional function to prepare the allocated MSI descriptor
+ * in the domain
* @set_desc: Set the msi descriptor for an interrupt
* @domain_alloc_irqs: Optional function to override the default allocation
* function.
* @domain_free_irqs: Optional function to override the default free
* function.
+ * @msi_post_free: Optional function which is invoked after freeing
+ * all interrupts.
*
* @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying
* irqdomain.
*
- * @msi_check, @msi_prepare and @set_desc are callbacks used by
- * msi_domain_alloc/free_irqs().
+ * @msi_check, @msi_prepare, @prepare_desc and @set_desc are callbacks used by the
+ * msi_domain_alloc/free_irqs*() variants.
*
* @domain_alloc_irqs, @domain_free_irqs can be used to override the
* default allocation/free functions (__msi_domain_alloc/free_irqs). This
@@ -329,15 +433,6 @@ struct msi_domain_info;
* be wrapped into the regular irq domains concepts by mere mortals. This
* allows to universally use msi_domain_alloc/free_irqs without having to
* special case XEN all over the place.
- *
- * Contrary to other operations @domain_alloc_irqs and @domain_free_irqs
- * are set to the default implementation if NULL and even when
- * MSI_FLAG_USE_DEF_DOM_OPS is not set to avoid breaking existing users and
- * because these callbacks are obviously mandatory.
- *
- * This is NOT meant to be abused, but it can be useful to build wrappers
- * for specialized MSI irq domains which need extra work before and after
- * calling __msi_domain_alloc_irqs()/__msi_domain_free_irqs().
*/
struct msi_domain_ops {
irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
@@ -349,23 +444,29 @@ struct msi_domain_ops {
void (*msi_free)(struct irq_domain *domain,
struct msi_domain_info *info,
unsigned int virq);
- int (*msi_check)(struct irq_domain *domain,
- struct msi_domain_info *info,
- struct device *dev);
int (*msi_prepare)(struct irq_domain *domain,
struct device *dev, int nvec,
msi_alloc_info_t *arg);
+ void (*prepare_desc)(struct irq_domain *domain, msi_alloc_info_t *arg,
+ struct msi_desc *desc);
void (*set_desc)(msi_alloc_info_t *arg,
struct msi_desc *desc);
int (*domain_alloc_irqs)(struct irq_domain *domain,
struct device *dev, int nvec);
void (*domain_free_irqs)(struct irq_domain *domain,
struct device *dev);
+ void (*msi_post_free)(struct irq_domain *domain,
+ struct device *dev);
};
/**
* struct msi_domain_info - MSI interrupt domain data
* @flags: Flags to decribe features and capabilities
+ * @bus_token: The domain bus token
+ * @hwsize: The hardware table size or the software index limit.
+ * If 0 then the size is considered unlimited and
+ * gets initialized to the maximum software index limit
+ * by the domain creation code.
* @ops: The callback data structure
* @chip: Optional: associated interrupt chip
* @chip_data: Optional: associated interrupt chip data
@@ -375,17 +476,42 @@ struct msi_domain_ops {
* @data: Optional: domain specific data
*/
struct msi_domain_info {
- u32 flags;
- struct msi_domain_ops *ops;
- struct irq_chip *chip;
- void *chip_data;
- irq_flow_handler_t handler;
- void *handler_data;
- const char *handler_name;
- void *data;
+ u32 flags;
+ enum irq_domain_bus_token bus_token;
+ unsigned int hwsize;
+ struct msi_domain_ops *ops;
+ struct irq_chip *chip;
+ void *chip_data;
+ irq_flow_handler_t handler;
+ void *handler_data;
+ const char *handler_name;
+ void *data;
};
-/* Flags for msi_domain_info */
+/**
+ * struct msi_domain_template - Template for MSI device domains
+ * @name: Storage for the resulting name. Filled in by the core.
+ * @chip: Interrupt chip for this domain
+ * @ops: MSI domain ops
+ * @info: MSI domain info data
+ */
+struct msi_domain_template {
+ char name[48];
+ struct irq_chip chip;
+ struct msi_domain_ops ops;
+ struct msi_domain_info info;
+};
+
+/*
+ * Flags for msi_domain_info
+ *
+ * Bit 0-15: Generic MSI functionality which is not subject to restriction
+ * by parent domains
+ *
+ * Bit 16-31: Functionality which depends on the underlying parent domain and
+ * can be masked out by msi_parent_ops::init_dev_msi_info() when
+ * a device MSI domain is initialized.
+ */
enum {
/*
* Init non implemented ops callbacks with default MSI domain
@@ -397,44 +523,100 @@ enum {
* callbacks.
*/
MSI_FLAG_USE_DEF_CHIP_OPS = (1 << 1),
- /* Support multiple PCI MSI interrupts */
- MSI_FLAG_MULTI_PCI_MSI = (1 << 2),
- /* Support PCI MSIX interrupts */
- MSI_FLAG_PCI_MSIX = (1 << 3),
/* Needs early activate, required for PCI */
- MSI_FLAG_ACTIVATE_EARLY = (1 << 4),
+ MSI_FLAG_ACTIVATE_EARLY = (1 << 2),
/*
* Must reactivate when irq is started even when
* MSI_FLAG_ACTIVATE_EARLY has been set.
*/
- MSI_FLAG_MUST_REACTIVATE = (1 << 5),
- /* Is level-triggered capable, using two messages */
- MSI_FLAG_LEVEL_CAPABLE = (1 << 6),
+ MSI_FLAG_MUST_REACTIVATE = (1 << 3),
/* Populate sysfs on alloc() and destroy it on free() */
- MSI_FLAG_DEV_SYSFS = (1 << 7),
- /* MSI-X entries must be contiguous */
- MSI_FLAG_MSIX_CONTIGUOUS = (1 << 8),
+ MSI_FLAG_DEV_SYSFS = (1 << 4),
/* Allocate simple MSI descriptors */
- MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 9),
+ MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 5),
/* Free MSI descriptors */
- MSI_FLAG_FREE_MSI_DESCS = (1 << 10),
+ MSI_FLAG_FREE_MSI_DESCS = (1 << 6),
+ /*
+ * Quirk to handle MSI implementations which do not provide
+ * masking. Currently known to affect x86, but has to be partially
+ * handled in the core MSI code.
+ */
+ MSI_FLAG_NOMASK_QUIRK = (1 << 7),
+
+ /* Mask for the generic functionality */
+ MSI_GENERIC_FLAGS_MASK = GENMASK(15, 0),
+
+ /* Mask for the domain specific functionality */
+ MSI_DOMAIN_FLAGS_MASK = GENMASK(31, 16),
+
+ /* Support multiple PCI MSI interrupts */
+ MSI_FLAG_MULTI_PCI_MSI = (1 << 16),
+ /* Support PCI MSIX interrupts */
+ MSI_FLAG_PCI_MSIX = (1 << 17),
+ /* Is level-triggered capable, using two messages */
+ MSI_FLAG_LEVEL_CAPABLE = (1 << 18),
+ /* MSI-X entries must be contiguous */
+ MSI_FLAG_MSIX_CONTIGUOUS = (1 << 19),
+ /* PCI/MSI-X vectors can be dynamically allocated/freed post MSI-X enable */
+ MSI_FLAG_PCI_MSIX_ALLOC_DYN = (1 << 20),
+ /* Support for PCI/IMS */
+ MSI_FLAG_PCI_IMS = (1 << 21),
};
+/**
+ * struct msi_parent_ops - MSI parent domain callbacks and configuration info
+ *
+ * @supported_flags: Required: The supported MSI flags of the parent domain
+ * @prefix: Optional: Prefix for the domain and chip name
+ * @init_dev_msi_info: Required: Callback for MSI parent domains to setup parent
+ * domain specific domain flags, domain ops and interrupt chip
+ * callbacks when a per device domain is created.
+ */
+struct msi_parent_ops {
+ u32 supported_flags;
+ const char *prefix;
+ bool (*init_dev_msi_info)(struct device *dev, struct irq_domain *domain,
+ struct irq_domain *msi_parent_domain,
+ struct msi_domain_info *msi_child_info);
+};
+
+bool msi_parent_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+ struct irq_domain *msi_parent_domain,
+ struct msi_domain_info *msi_child_info);
+
int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
bool force);
struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent);
-int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
- int nvec);
-int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device *dev,
- int nvec);
-int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
- int nvec);
-void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
-void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device *dev);
-void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
+
+bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
+ const struct msi_domain_template *template,
+ unsigned int hwsize, void *domain_data,
+ void *chip_data);
+void msi_remove_device_irq_domain(struct device *dev, unsigned int domid);
+
+bool msi_match_device_irq_domain(struct device *dev, unsigned int domid,
+ enum irq_domain_bus_token bus_token);
+
+int msi_domain_alloc_irqs_range_locked(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last);
+int msi_domain_alloc_irqs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last);
+int msi_domain_alloc_irqs_all_locked(struct device *dev, unsigned int domid, int nirqs);
+
+struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index,
+ const struct irq_affinity_desc *affdesc,
+ union msi_instance_cookie *cookie);
+
+void msi_domain_free_irqs_range_locked(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last);
+void msi_domain_free_irqs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last);
+void msi_domain_free_irqs_all_locked(struct device *dev, unsigned int domid);
+void msi_domain_free_irqs_all(struct device *dev, unsigned int domid);
+
struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
@@ -467,20 +649,27 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir
void platform_msi_device_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 */
+#endif /* CONFIG_GENERIC_MSI_IRQ */
-#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+/* PCI specific interfaces */
+#ifdef CONFIG_PCI_MSI
+struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc);
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
+void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void pci_msi_mask_irq(struct irq_data *data);
+void pci_msi_unmask_irq(struct irq_data *data);
struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent);
u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev);
struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev);
-bool pci_dev_has_special_msi_domain(struct pci_dev *pdev);
-#else
+#else /* CONFIG_PCI_MSI */
static inline struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
{
return NULL;
}
-#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
+static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg) { }
+#endif /* !CONFIG_PCI_MSI */
#endif /* LINUX_MSI_H */
diff --git a/include/linux/msi_api.h b/include/linux/msi_api.h
new file mode 100644
index 000000000000..391087ad99b1
--- /dev/null
+++ b/include/linux/msi_api.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LINUX_MSI_API_H
+#define LINUX_MSI_API_H
+
+/*
+ * APIs which are relevant for device driver code for allocating and
+ * freeing MSI interrupts and querying the associations between
+ * hardware/software MSI indices and the Linux interrupt number.
+ */
+
+struct device;
+
+/*
+ * Per device interrupt domain related constants.
+ */
+enum msi_domain_ids {
+ MSI_DEFAULT_DOMAIN,
+ MSI_SECONDARY_DOMAIN,
+ MSI_MAX_DEVICE_IRQDOMAINS,
+};
+
+/**
+ * union msi_instance_cookie - MSI instance cookie
+ * @value: u64 value store
+ * @ptr: Pointer to usage site specific data
+ *
+ * This cookie is handed to the IMS allocation function and stored in the
+ * MSI descriptor for the interrupt chip callbacks.
+ *
+ * The content of this cookie is MSI domain implementation defined. For
+ * PCI/IMS implementations this could be a PASID or a pointer to queue
+ * memory.
+ */
+union msi_instance_cookie {
+ u64 value;
+ void *ptr;
+};
+
+/**
+ * msi_map - Mapping between MSI index and Linux interrupt number
+ * @index: The MSI index, e.g. slot in the MSI-X table or
+ * a software managed index if >= 0. If negative
+ * the allocation function failed and it contains
+ * the error code.
+ * @virq: The associated Linux interrupt number
+ */
+struct msi_map {
+ int index;
+ int virq;
+};
+
+/*
+ * Constant to be used for dynamic allocations when the allocation is any
+ * free MSI index, which is either an entry in a hardware table or a
+ * software managed index.
+ */
+#define MSI_ANY_INDEX UINT_MAX
+
+unsigned int msi_domain_get_virq(struct device *dev, unsigned int domid, unsigned int index);
+
+/**
+ * msi_get_virq - Lookup the Linux interrupt number for a MSI index on the default interrupt domain
+ * @dev: Device for which the lookup happens
+ * @index: The MSI index to lookup
+ *
+ * Return: The Linux interrupt number on success (> 0), 0 if not found
+ */
+static inline unsigned int msi_get_virq(struct device *dev, unsigned int index)
+{
+ return msi_domain_get_virq(dev, MSI_DEFAULT_DOMAIN, index);
+}
+
+#endif
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c3693bb87b4c..b2996dc987ff 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -999,7 +999,6 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
-int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
/* ECC related functions */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 42218a1164f6..25765556223a 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -349,6 +349,8 @@ struct spi_nor_flash_parameter;
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
* layer is not DMA-able
* @bouncebuf_size: size of the bounce buffer
+ * @id: The flash's ID bytes. Always contains
+ * SPI_NOR_MAX_ID_LEN bytes.
* @info: SPI NOR part JEDEC MFR ID and other info
* @manufacturer: SPI NOR manufacturer
* @addr_nbytes: number of address bytes
@@ -379,6 +381,7 @@ struct spi_nor {
struct spi_mem *spimem;
u8 *bouncebuf;
size_t bouncebuf_size;
+ u8 *id;
const struct flash_info *info;
const struct spi_nor_manufacturer *manufacturer;
u8 addr_nbytes;
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index f2402ddeafbf..4c76ddfb6a67 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -267,6 +267,14 @@ struct netfs_cache_ops {
loff_t *_start, size_t *_len, loff_t i_size,
bool no_space_allocated_yet);
+ /* Prepare an on-demand read operation, shortening it to a cached/uncached
+ * boundary as appropriate.
+ */
+ enum netfs_io_source (*prepare_ondemand_read)(struct netfs_cache_resources *cres,
+ loff_t start, size_t *_len,
+ loff_t i_size,
+ unsigned long *_flags, ino_t ino);
+
/* Query the occupancy of the cache in a region, returning where the
* next chunk of data starts and how long it is.
*/
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 8d04b6a5964c..730003c4f4af 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -732,4 +732,17 @@ enum nfs4_setxattr_options {
SETXATTR4_CREATE = 1,
SETXATTR4_REPLACE = 2,
};
+
+enum {
+ RCA4_TYPE_MASK_RDATA_DLG = 0,
+ RCA4_TYPE_MASK_WDATA_DLG = 1,
+ RCA4_TYPE_MASK_DIR_DLG = 2,
+ RCA4_TYPE_MASK_FILE_LAYOUT = 3,
+ RCA4_TYPE_MASK_BLK_LAYOUT = 4,
+ RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8,
+ RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9,
+ RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12,
+ RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15,
+};
+
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 7931fa472561..d92fdfd2444c 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -59,6 +59,7 @@ struct nfs_access_entry {
kuid_t fsuid;
kgid_t fsgid;
struct group_info *group_info;
+ u64 timestamp;
__u32 mask;
struct rcu_head rcu_head;
};
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index efef68c9352a..bb0ee80526b2 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -516,7 +516,7 @@ static inline int node_random(const nodemask_t *maskp)
bit = first_node(*maskp);
break;
default:
- bit = find_nth_bit(maskp->bits, MAX_NUMNODES, prandom_u32_max(w));
+ bit = find_nth_bit(maskp->bits, MAX_NUMNODES, get_random_u32_below(w));
break;
}
return bit;
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index cdb171efc7cb..fee881cded01 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -94,6 +94,7 @@ static inline struct cred *nsset_cred(struct nsset *set)
int copy_namespaces(unsigned long flags, struct task_struct *tsk);
void exit_task_namespaces(struct task_struct *tsk);
void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new);
+int exec_task_namespaces(void);
void free_nsproxy(struct nsproxy *ns);
int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
struct cred *, struct fs_struct *);
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 050d7d0cd81b..d6be2a686100 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -797,6 +797,7 @@ enum nvme_opcode {
nvme_cmd_zone_mgmt_send = 0x79,
nvme_cmd_zone_mgmt_recv = 0x7a,
nvme_cmd_zone_append = 0x7d,
+ nvme_cmd_vendor_start = 0x80,
};
#define nvme_opcode_name(opcode) { opcode, #opcode }
@@ -963,6 +964,7 @@ enum {
NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12,
NVME_RW_PRINFO_PRACT = 1 << 13,
NVME_RW_DTYPE_STREAMS = 1 << 4,
+ NVME_WZ_DEAC = 1 << 9,
};
struct nvme_dsm_cmd {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2bda4a4e47e8..c0d939f3169c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -38,6 +38,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/resource_ext.h>
+#include <linux/msi_api.h>
#include <uapi/linux/pci.h>
#include <linux/pci_ids.h>
@@ -409,6 +410,7 @@ struct pci_dev {
*/
unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
+ struct resource driver_exclusive_resource; /* driver exclusive resource ranges */
bool match_driver; /* Skip attaching driver */
@@ -843,6 +845,9 @@ struct pci_error_handlers {
/* Device driver may resume normal operations */
void (*resume)(struct pci_dev *dev);
+
+ /* Allow device driver to record more details of a correctable error */
+ void (*cor_error_detected)(struct pci_dev *dev);
};
@@ -1407,6 +1412,21 @@ int pci_request_selected_regions(struct pci_dev *, int, const char *);
int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
void pci_release_selected_regions(struct pci_dev *, int);
+static inline __must_check struct resource *
+pci_request_config_region_exclusive(struct pci_dev *pdev, unsigned int offset,
+ unsigned int len, const char *name)
+{
+ return __request_region(&pdev->driver_exclusive_resource, offset, len,
+ name, IORESOURCE_EXCLUSIVE);
+}
+
+static inline void pci_release_config_region(struct pci_dev *pdev,
+ unsigned int offset,
+ unsigned int len)
+{
+ __release_region(&pdev->driver_exclusive_resource, offset, len);
+}
+
/* drivers/pci/bus.c */
void pci_add_resource(struct list_head *resources, struct resource *res);
void pci_add_resource_offset(struct list_head *resources, struct resource *res,
@@ -1553,10 +1573,17 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev,
return rc;
return 0;
}
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags);
int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
unsigned int max_vecs, unsigned int flags,
struct irq_affinity *affd);
+bool pci_msix_can_alloc_dyn(struct pci_dev *dev);
+struct msi_map pci_msix_alloc_irq_at(struct pci_dev *dev, unsigned int index,
+ const struct irq_affinity_desc *affdesc);
+void pci_msix_free_irq(struct pci_dev *pdev, struct msi_map map);
+
void pci_free_irq_vectors(struct pci_dev *dev);
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
@@ -1586,6 +1613,13 @@ pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
return 1;
return -ENOSPC;
}
+static inline int
+pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags)
+{
+ return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs,
+ flags, NULL);
+}
static inline void pci_free_irq_vectors(struct pci_dev *dev)
{
@@ -1898,15 +1932,13 @@ pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
{
return -ENOSPC;
}
-#endif /* CONFIG_PCI */
-
static inline int
pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
unsigned int max_vecs, unsigned int flags)
{
- return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs, flags,
- NULL);
+ return -ENOSPC;
}
+#endif /* CONFIG_PCI */
/* Include architecture-dependent settings and functions */
@@ -2474,6 +2506,14 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev)
void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
#endif
+struct msi_domain_template;
+
+bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
+ unsigned int hwsize, void *data);
+struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev, union msi_instance_cookie *icookie,
+ const struct irq_affinity_desc *affdesc);
+void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map);
+
#include <linux/dma-mapping.h>
#define pci_printk(level, pdev, fmt, arg...) \
@@ -2484,6 +2524,7 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
#define pci_crit(pdev, fmt, arg...) dev_crit(&(pdev)->dev, fmt, ##arg)
#define pci_err(pdev, fmt, arg...) dev_err(&(pdev)->dev, fmt, ##arg)
#define pci_warn(pdev, fmt, arg...) dev_warn(&(pdev)->dev, fmt, ##arg)
+#define pci_warn_once(pdev, fmt, arg...) dev_warn_once(&(pdev)->dev, fmt, ##arg)
#define pci_notice(pdev, fmt, arg...) dev_notice(&(pdev)->dev, fmt, ##arg)
#define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg)
#define pci_dbg(pdev, fmt, arg...) dev_dbg(&(pdev)->dev, fmt, ##arg)
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index f1ec5ad1351c..1338ea2aa720 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -37,12 +37,11 @@
/*
* Percpu allocator can serve percpu allocations before slab is
* initialized which allows slab to depend on the percpu allocator.
- * The following two parameters decide how much resource to
- * preallocate for this. Keep PERCPU_DYNAMIC_RESERVE equal to or
- * larger than PERCPU_DYNAMIC_EARLY_SIZE.
+ * The following parameter decide how much resource to preallocate
+ * for this. Keep PERCPU_DYNAMIC_RESERVE equal to or larger than
+ * PERCPU_DYNAMIC_EARLY_SIZE.
*/
-#define PERCPU_DYNAMIC_EARLY_SLOTS 128
-#define PERCPU_DYNAMIC_EARLY_SIZE (12 << 10)
+#define PERCPU_DYNAMIC_EARLY_SIZE (20 << 10)
/*
* PERCPU_DYNAMIC_RESERVE indicates the amount of free area to piggy
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 0356cb6a215d..ef914a600087 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -100,7 +100,7 @@ struct arm_pmu {
void (*stop)(struct arm_pmu *);
void (*reset)(void *);
int (*map_event)(struct perf_event *event);
- int (*filter_match)(struct perf_event *event);
+ bool (*filter)(struct pmu *pmu, int cpu);
int num_events;
bool secure_access; /* 32-bit ARM only */
#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
@@ -174,7 +174,6 @@ void kvm_host_pmu_init(struct arm_pmu *pmu);
/* Internal functions only for core arm_pmu code */
struct arm_pmu *armpmu_alloc(void);
-struct arm_pmu *armpmu_alloc_atomic(void);
void armpmu_free(struct arm_pmu *pmu);
int armpmu_register(struct arm_pmu *pmu);
int armpmu_request_irq(int irq, int cpu);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0031f7b4d9ab..c6a3bac76966 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -266,6 +266,7 @@ struct hw_perf_event {
};
struct perf_event;
+struct perf_event_pmu_context;
/*
* Common implementation detail of pmu::{start,commit,cancel}_txn
@@ -308,7 +309,7 @@ struct pmu {
int capabilities;
int __percpu *pmu_disable_count;
- struct perf_cpu_context __percpu *pmu_cpu_context;
+ struct perf_cpu_pmu_context __percpu *cpu_pmu_context;
atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */
int task_ctx_nr;
int hrtimer_interval_ms;
@@ -443,7 +444,7 @@ struct pmu {
/*
* context-switches callback
*/
- void (*sched_task) (struct perf_event_context *ctx,
+ void (*sched_task) (struct perf_event_pmu_context *pmu_ctx,
bool sched_in);
/*
@@ -457,8 +458,8 @@ struct pmu {
* implementation and Perf core context switch handling callbacks for usage
* examples.
*/
- void (*swap_task_ctx) (struct perf_event_context *prev,
- struct perf_event_context *next);
+ void (*swap_task_ctx) (struct perf_event_pmu_context *prev_epc,
+ struct perf_event_pmu_context *next_epc);
/* optional */
/*
@@ -522,9 +523,10 @@ struct pmu {
/* optional */
/*
- * Filter events for PMU-specific reasons.
+ * Skip programming this PMU on the given CPU. Typically needed for
+ * big.LITTLE things.
*/
- int (*filter_match) (struct perf_event *event); /* optional */
+ bool (*filter) (struct pmu *pmu, int cpu); /* optional */
/*
* Check period value for PERF_EVENT_IOC_PERIOD ioctl.
@@ -695,6 +697,11 @@ struct perf_event {
int group_caps;
struct perf_event *group_leader;
+ /*
+ * event->pmu will always point to pmu in which this event belongs.
+ * Whereas event->pmu_ctx->pmu may point to other pmu when group of
+ * different pmu events is created.
+ */
struct pmu *pmu;
void *pmu_private;
@@ -720,6 +727,12 @@ struct perf_event {
struct hw_perf_event hw;
struct perf_event_context *ctx;
+ /*
+ * event->pmu_ctx points to perf_event_pmu_context in which the event
+ * is added. This pmu_ctx can be of other pmu for sw event when that
+ * sw event is part of a group which also contains non-sw events.
+ */
+ struct perf_event_pmu_context *pmu_ctx;
atomic_long_t refcount;
/*
@@ -812,19 +825,69 @@ struct perf_event {
#endif /* CONFIG_PERF_EVENTS */
};
+/*
+ * ,-----------------------[1:n]----------------------.
+ * V V
+ * perf_event_context <-[1:n]-> perf_event_pmu_context <--- perf_event
+ * ^ ^ | |
+ * `--------[1:n]---------' `-[n:1]-> pmu <-[1:n]-'
+ *
+ *
+ * struct perf_event_pmu_context lifetime is refcount based and RCU freed
+ * (similar to perf_event_context). Locking is as if it were a member of
+ * perf_event_context; specifically:
+ *
+ * modification, both: ctx->mutex && ctx->lock
+ * reading, either: ctx->mutex || ctx->lock
+ *
+ * There is one exception to this; namely put_pmu_ctx() isn't always called
+ * with ctx->mutex held; this means that as long as we can guarantee the epc
+ * has events the above rules hold.
+ *
+ * Specificially, sys_perf_event_open()'s group_leader case depends on
+ * ctx->mutex pinning the configuration. Since we hold a reference on
+ * group_leader (through the filedesc) it can't go away, therefore it's
+ * associated pmu_ctx must exist and cannot change due to ctx->mutex.
+ */
+struct perf_event_pmu_context {
+ struct pmu *pmu;
+ struct perf_event_context *ctx;
+
+ struct list_head pmu_ctx_entry;
+
+ struct list_head pinned_active;
+ struct list_head flexible_active;
+
+ /* Used to avoid freeing per-cpu perf_event_pmu_context */
+ unsigned int embedded : 1;
+
+ unsigned int nr_events;
+
+ atomic_t refcount; /* event <-> epc */
+ struct rcu_head rcu_head;
+
+ void *task_ctx_data; /* pmu specific data */
+ /*
+ * Set when one or more (plausibly active) event can't be scheduled
+ * due to pmu overcommit or pmu constraints, except tolerant to
+ * events not necessary to be active due to scheduling constraints,
+ * such as cgroups.
+ */
+ int rotate_necessary;
+};
struct perf_event_groups {
struct rb_root tree;
u64 index;
};
+
/**
* struct perf_event_context - event context structure
*
* Used as a container for task events and CPU events as well:
*/
struct perf_event_context {
- struct pmu *pmu;
/*
* Protect the states of the events in the list,
* nr_active, and the list:
@@ -837,27 +900,21 @@ struct perf_event_context {
*/
struct mutex mutex;
- struct list_head active_ctx_list;
+ struct list_head pmu_ctx_list;
struct perf_event_groups pinned_groups;
struct perf_event_groups flexible_groups;
struct list_head event_list;
- struct list_head pinned_active;
- struct list_head flexible_active;
-
int nr_events;
- int nr_active;
int nr_user;
int is_active;
+
+ int nr_task_data;
int nr_stat;
int nr_freq;
int rotate_disable;
- /*
- * Set when nr_events != nr_active, except tolerant to events not
- * necessary to be active due to scheduling constraints, such as cgroups.
- */
- int rotate_necessary;
- refcount_t refcount;
+
+ refcount_t refcount; /* event <-> ctx */
struct task_struct *task;
/*
@@ -878,7 +935,6 @@ struct perf_event_context {
#ifdef CONFIG_CGROUP_PERF
int nr_cgroups; /* cgroup evts */
#endif
- void *task_ctx_data; /* pmu specific data */
struct rcu_head rcu_head;
/*
@@ -896,12 +952,13 @@ struct perf_event_context {
*/
#define PERF_NR_CONTEXTS 4
-/**
- * struct perf_cpu_context - per cpu event context structure
- */
-struct perf_cpu_context {
- struct perf_event_context ctx;
- struct perf_event_context *task_ctx;
+struct perf_cpu_pmu_context {
+ struct perf_event_pmu_context epc;
+ struct perf_event_pmu_context *task_epc;
+
+ struct list_head sched_cb_entry;
+ int sched_cb_usage;
+
int active_oncpu;
int exclusive;
@@ -909,16 +966,20 @@ struct perf_cpu_context {
struct hrtimer hrtimer;
ktime_t hrtimer_interval;
unsigned int hrtimer_active;
+};
+
+/**
+ * struct perf_event_cpu_context - per cpu event context structure
+ */
+struct perf_cpu_context {
+ struct perf_event_context ctx;
+ struct perf_event_context *task_ctx;
+ int online;
#ifdef CONFIG_CGROUP_PERF
struct perf_cgroup *cgrp;
- struct list_head cgrp_cpuctx_entry;
#endif
- struct list_head sched_cb_entry;
- int sched_cb_usage;
-
- int online;
/*
* Per-CPU storage for iterators used in visit_groups_merge. The default
* storage is of size 2 to hold the CPU and any CPU event iterators.
@@ -982,6 +1043,8 @@ perf_cgroup_from_task(struct task_struct *task, struct perf_event_context *ctx)
#ifdef CONFIG_PERF_EVENTS
+extern struct perf_event_context *perf_cpu_task_ctx(void);
+
extern void *perf_aux_output_begin(struct perf_output_handle *handle,
struct perf_event *event);
extern void perf_aux_output_end(struct perf_output_handle *handle,
@@ -1187,7 +1250,7 @@ static inline int is_software_event(struct perf_event *event)
*/
static inline int in_software_context(struct perf_event *event)
{
- return event->ctx->pmu->task_ctx_nr == perf_sw_context;
+ return event->pmu_ctx->pmu->task_ctx_nr == perf_sw_context;
}
static inline int is_exclusive_pmu(struct pmu *pmu)
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index a108b60a6962..5f0d7d0b9471 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -165,6 +165,13 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr);
}
+#ifndef pmd_young
+static inline int pmd_young(pmd_t pmd)
+{
+ return 0;
+}
+#endif
+
#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
extern int ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep,
@@ -260,6 +267,17 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
+#ifndef arch_has_hw_nonleaf_pmd_young
+/*
+ * Return whether the accessed bit in non-leaf PMD entries is supported on the
+ * local CPU.
+ */
+static inline bool arch_has_hw_nonleaf_pmd_young(void)
+{
+ return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG);
+}
+#endif
+
#ifndef arch_has_hw_pte_young
/*
* Return whether the accessed bit is supported on the local CPU.
diff --git a/include/linux/phy/phy-mipi-dphy.h b/include/linux/phy/phy-mipi-dphy.h
index a877ffee845d..1ac128d78dfe 100644
--- a/include/linux/phy/phy-mipi-dphy.h
+++ b/include/linux/phy/phy-mipi-dphy.h
@@ -279,6 +279,9 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
unsigned int bpp,
unsigned int lanes,
struct phy_configure_opts_mipi_dphy *cfg);
+int phy_mipi_dphy_get_default_config_for_hsclk(unsigned long long hs_clk_rate,
+ unsigned int lanes,
+ struct phy_configure_opts_mipi_dphy *cfg);
int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg);
#endif /* __PHY_MIPI_DPHY_H_ */
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
deleted file mode 100644
index f9c5ac80d59b..000000000000
--- a/include/linux/pktcdvd.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
- * DVD-RW devices.
- *
- */
-#ifndef __PKTCDVD_H
-#define __PKTCDVD_H
-
-#include <linux/blkdev.h>
-#include <linux/completion.h>
-#include <linux/cdrom.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/mempool.h>
-#include <uapi/linux/pktcdvd.h>
-
-/* default bio write queue congestion marks */
-#define PKT_WRITE_CONGESTION_ON 10000
-#define PKT_WRITE_CONGESTION_OFF 9000
-
-
-struct packet_settings
-{
- __u32 size; /* packet size in (512 byte) sectors */
- __u8 fp; /* fixed packets */
- __u8 link_loss; /* the rest is specified
- * as per Mt Fuji */
- __u8 write_type;
- __u8 track_mode;
- __u8 block_mode;
-};
-
-/*
- * Very crude stats for now
- */
-struct packet_stats
-{
- unsigned long pkt_started;
- unsigned long pkt_ended;
- unsigned long secs_w;
- unsigned long secs_rg;
- unsigned long secs_r;
-};
-
-struct packet_cdrw
-{
- struct list_head pkt_free_list;
- struct list_head pkt_active_list;
- spinlock_t active_list_lock; /* Serialize access to pkt_active_list */
- struct task_struct *thread;
- atomic_t pending_bios;
-};
-
-/*
- * Switch to high speed reading after reading this many kilobytes
- * with no interspersed writes.
- */
-#define HI_SPEED_SWITCH 512
-
-struct packet_iosched
-{
- atomic_t attention; /* Set to non-zero when queue processing is needed */
- int writing; /* Non-zero when writing, zero when reading */
- spinlock_t lock; /* Protecting read/write queue manipulations */
- struct bio_list read_queue;
- struct bio_list write_queue;
- sector_t last_write; /* The sector where the last write ended */
- int successive_reads;
-};
-
-/*
- * 32 buffers of 2048 bytes
- */
-#if (PAGE_SIZE % CD_FRAMESIZE) != 0
-#error "PAGE_SIZE must be a multiple of CD_FRAMESIZE"
-#endif
-#define PACKET_MAX_SIZE 128
-#define FRAMES_PER_PAGE (PAGE_SIZE / CD_FRAMESIZE)
-#define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9)
-
-enum packet_data_state {
- PACKET_IDLE_STATE, /* Not used at the moment */
- PACKET_WAITING_STATE, /* Waiting for more bios to arrive, so */
- /* we don't have to do as much */
- /* data gathering */
- PACKET_READ_WAIT_STATE, /* Waiting for reads to fill in holes */
- PACKET_WRITE_WAIT_STATE, /* Waiting for the write to complete */
- PACKET_RECOVERY_STATE, /* Recover after read/write errors */
- PACKET_FINISHED_STATE, /* After write has finished */
-
- PACKET_NUM_STATES /* Number of possible states */
-};
-
-/*
- * Information needed for writing a single packet
- */
-struct pktcdvd_device;
-
-struct packet_data
-{
- struct list_head list;
-
- spinlock_t lock; /* Lock protecting state transitions and */
- /* orig_bios list */
-
- struct bio_list orig_bios; /* Original bios passed to pkt_make_request */
- /* that will be handled by this packet */
- int write_size; /* Total size of all bios in the orig_bios */
- /* list, measured in number of frames */
-
- struct bio *w_bio; /* The bio we will send to the real CD */
- /* device once we have all data for the */
- /* packet we are going to write */
- sector_t sector; /* First sector in this packet */
- int frames; /* Number of frames in this packet */
-
- enum packet_data_state state; /* Current state */
- atomic_t run_sm; /* Incremented whenever the state */
- /* machine needs to be run */
- long sleep_time; /* Set this to non-zero to make the state */
- /* machine run after this many jiffies. */
-
- atomic_t io_wait; /* Number of pending IO operations */
- atomic_t io_errors; /* Number of read/write errors during IO */
-
- struct bio *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */
- struct page *pages[PACKET_MAX_SIZE / FRAMES_PER_PAGE];
-
- int cache_valid; /* If non-zero, the data for the zone defined */
- /* by the sector variable is completely cached */
- /* in the pages[] vector. */
-
- int id; /* ID number for debugging */
- struct pktcdvd_device *pd;
-};
-
-struct pkt_rb_node {
- struct rb_node rb_node;
- struct bio *bio;
-};
-
-struct packet_stacked_data
-{
- struct bio *bio; /* Original read request bio */
- struct pktcdvd_device *pd;
-};
-#define PSD_POOL_SIZE 64
-
-struct pktcdvd_device
-{
- struct block_device *bdev; /* dev attached */
- dev_t pkt_dev; /* our dev */
- char name[20];
- struct packet_settings settings;
- struct packet_stats stats;
- int refcnt; /* Open count */
- int write_speed; /* current write speed, kB/s */
- int read_speed; /* current read speed, kB/s */
- unsigned long offset; /* start offset */
- __u8 mode_offset; /* 0 / 8 */
- __u8 type;
- unsigned long flags;
- __u16 mmc3_profile;
- __u32 nwa; /* next writable address */
- __u32 lra; /* last recorded address */
- struct packet_cdrw cdrw;
- wait_queue_head_t wqueue;
-
- spinlock_t lock; /* Serialize access to bio_queue */
- struct rb_root bio_queue; /* Work queue of bios we need to handle */
- int bio_queue_size; /* Number of nodes in bio_queue */
- bool congested; /* Someone is waiting for bio_queue_size
- * to drop. */
- sector_t current_sector; /* Keep track of where the elevator is */
- atomic_t scan_queue; /* Set to non-zero when pkt_handle_queue */
- /* needs to be run. */
- mempool_t rb_pool; /* mempool for pkt_rb_node allocations */
-
- struct packet_iosched iosched;
- struct gendisk *disk;
-
- int write_congestion_off;
- int write_congestion_on;
-
- struct device *dev; /* sysfs pktcdvd[0-7] dev */
-
- struct dentry *dfs_d_root; /* debugfs: devname directory */
- struct dentry *dfs_f_info; /* debugfs: info file */
-};
-
-#endif /* __PKTCDVD_H */
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index c9cc4e32435d..dcca6c5e23bb 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -136,6 +136,13 @@ struct gpmc_device_timings {
#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
+/* Wait pin polarity values */
+#define GPMC_WAITPINPOLARITY_INVALID UINT_MAX
+#define GPMC_WAITPINPOLARITY_ACTIVE_LOW 0
+#define GPMC_WAITPINPOLARITY_ACTIVE_HIGH 1
+
+#define GPMC_WAITPIN_INVALID UINT_MAX
+
struct gpmc_settings {
bool burst_wrap; /* enables wrap bursting */
bool burst_read; /* enables read page/burst mode */
@@ -149,6 +156,7 @@ struct gpmc_settings {
u32 device_width; /* device bus width (8 or 16 bit) */
u32 mux_add_data; /* multiplex address & data */
u32 wait_pin; /* wait-pin to be used */
+ u32 wait_pin_polarity;
};
/* Data for each chip select */
diff --git a/include/linux/platform_data/st33zp24.h b/include/linux/platform_data/st33zp24.h
deleted file mode 100644
index 61db674f36cc..000000000000
--- a/include/linux/platform_data/st33zp24.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24
- * Copyright (C) 2009 - 2016 STMicroelectronics
- */
-#ifndef __ST33ZP24_H__
-#define __ST33ZP24_H__
-
-#define TPM_ST33_I2C "st33zp24-i2c"
-#define TPM_ST33_SPI "st33zp24-spi"
-
-struct st33zp24_platform_data {
- int io_lpcpd;
-};
-
-#endif /* __ST33ZP24_H__ */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index ebc351698090..1cd41bdf73cf 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -17,6 +17,7 @@
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/time64.h>
/*
* Flags to control the behaviour of a genpd.
@@ -95,6 +96,7 @@ struct genpd_governor_data {
s64 max_off_time_ns;
bool max_off_time_changed;
ktime_t next_wakeup;
+ ktime_t next_hrtimer;
bool cached_power_down_ok;
bool cached_power_down_state_idx;
};
@@ -232,6 +234,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_genpd_remove_notifier(struct device *dev);
void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next);
+ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
extern struct dev_power_governor simple_qos_governor;
extern struct dev_power_governor pm_domain_always_on_gov;
@@ -293,6 +296,10 @@ static inline int dev_pm_genpd_remove_notifier(struct device *dev)
static inline void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
{ }
+static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
+{
+ return KTIME_MAX;
+}
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
#endif
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index 7d1e604c1325..ee608d22ecb9 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -69,21 +69,21 @@ extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
extern struct posix_acl *get_posix_acl(struct inode *, int);
-extern int set_posix_acl(struct user_namespace *, struct inode *, int,
- struct posix_acl *);
+int set_posix_acl(struct user_namespace *, struct dentry *, int,
+ struct posix_acl *);
struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
struct posix_acl *posix_acl_clone(const struct posix_acl *acl, gfp_t flags);
#ifdef CONFIG_FS_POSIX_ACL
-int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t);
+int posix_acl_chmod(struct user_namespace *, struct dentry *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
struct posix_acl **);
int posix_acl_update_mode(struct user_namespace *, struct inode *, umode_t *,
struct posix_acl **);
-extern int simple_set_acl(struct user_namespace *, struct inode *,
- struct posix_acl *, int);
+int simple_set_acl(struct user_namespace *, struct dentry *,
+ struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *);
struct posix_acl *get_cached_acl(struct inode *inode, int type);
@@ -99,9 +99,16 @@ static inline void cache_no_acl(struct inode *inode)
inode->i_acl = NULL;
inode->i_default_acl = NULL;
}
+
+int vfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl);
+struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name);
+int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name);
#else
static inline int posix_acl_chmod(struct user_namespace *mnt_userns,
- struct inode *inode, umode_t mode)
+ struct dentry *dentry, umode_t mode)
{
return 0;
}
@@ -126,8 +133,28 @@ static inline int posix_acl_create(struct inode *inode, umode_t *mode,
static inline void forget_all_cached_acls(struct inode *inode)
{
}
+
+static inline int vfs_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *name,
+ struct posix_acl *acl)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline int vfs_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_FS_POSIX_ACL */
-struct posix_acl *get_acl(struct inode *inode, int type);
+struct posix_acl *get_inode_acl(struct inode *inode, int type);
#endif /* __LINUX_POSIX_ACL_H */
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
index 8163dd48c430..54cd7a14330d 100644
--- a/include/linux/posix_acl_xattr.h
+++ b/include/linux/posix_acl_xattr.h
@@ -33,33 +33,40 @@ posix_acl_xattr_count(size_t size)
}
#ifdef CONFIG_FS_POSIX_ACL
-void posix_acl_fix_xattr_from_user(void *value, size_t size);
-void posix_acl_fix_xattr_to_user(void *value, size_t size);
-void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
- const struct inode *inode,
- void *value, size_t size);
+struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
+ const void *value, size_t size);
#else
-static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
-{
-}
-static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
-{
-}
-static inline void
-posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
- const struct inode *inode, void *value,
- size_t size)
+static inline struct posix_acl *
+posix_acl_from_xattr(struct user_namespace *user_ns, const void *value,
+ size_t size)
{
+ return ERR_PTR(-EOPNOTSUPP);
}
#endif
-struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
- const void *value, size_t size);
int posix_acl_to_xattr(struct user_namespace *user_ns,
const struct posix_acl *acl, void *buffer, size_t size);
-struct posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns,
- const void *value, size_t size);
+static inline const char *posix_acl_xattr_name(int type)
+{
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ return XATTR_NAME_POSIX_ACL_ACCESS;
+ case ACL_TYPE_DEFAULT:
+ return XATTR_NAME_POSIX_ACL_DEFAULT;
+ }
+
+ return "";
+}
+
+static inline int posix_acl_type(const char *name)
+{
+ if (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0)
+ return ACL_TYPE_ACCESS;
+ else if (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)
+ return ACL_TYPE_DEFAULT;
+
+ return -1;
+}
extern const struct xattr_handler posix_acl_access_xattr_handler;
extern const struct xattr_handler posix_acl_default_xattr_handler;
diff --git a/include/linux/prandom.h b/include/linux/prandom.h
index e0a0759dd09c..c94c02ba065c 100644
--- a/include/linux/prandom.h
+++ b/include/linux/prandom.h
@@ -9,6 +9,7 @@
#define _LINUX_PRANDOM_H
#include <linux/types.h>
+#include <linux/once.h>
#include <linux/percpu.h>
#include <linux/random.h>
@@ -23,24 +24,10 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
#define prandom_init_once(pcpu_state) \
DO_ONCE(prandom_seed_full_state, (pcpu_state))
-/**
- * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
- * @ep_ro: right open interval endpoint
- *
- * Returns a pseudo-random number that is in interval [0, ep_ro). This is
- * useful when requesting a random index of an array containing ep_ro elements,
- * for example. The result is somewhat biased when ep_ro is not a power of 2,
- * so do not use this for cryptographic purposes.
- *
- * Returns: pseudo-random number in interval [0, ep_ro)
- */
+/* Deprecated: use get_random_u32_below() instead. */
static inline u32 prandom_u32_max(u32 ep_ro)
{
- if (__builtin_constant_p(ep_ro <= 1U << 8) && ep_ro <= 1U << 8)
- return (get_random_u8() * ep_ro) >> 8;
- if (__builtin_constant_p(ep_ro <= 1U << 16) && ep_ro <= 1U << 16)
- return (get_random_u16() * ep_ro) >> 16;
- return ((u64)get_random_u32() * ep_ro) >> 32;
+ return get_random_u32_below(ep_ro);
}
/*
diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h
index 6e4372735068..1e0a0d7ace3a 100644
--- a/include/linux/psi_types.h
+++ b/include/linux/psi_types.h
@@ -72,6 +72,9 @@ enum psi_states {
/* Use one bit in the state mask to track TSK_ONCPU */
#define PSI_ONCPU (1 << NR_PSI_STATES)
+/* Flag whether to re-arm avgs_work, see details in get_recent_times() */
+#define PSI_STATE_RESCHEDULE (1 << (NR_PSI_STATES + 1))
+
enum psi_aggregators {
PSI_AVGS = 0,
PSI_POLL,
@@ -177,6 +180,7 @@ struct psi_group {
struct timer_list poll_timer;
wait_queue_head_t poll_wait;
atomic_t poll_wakeup;
+ atomic_t poll_scheduled;
/* Protects data used by the monitor */
struct mutex trigger_lock;
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 9f16afec7290..9d65ff94e216 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -8,28 +8,7 @@
#ifndef __LINUX_PSTORE_RAM_H__
#define __LINUX_PSTORE_RAM_H__
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
#include <linux/pstore.h>
-#include <linux/types.h>
-
-/*
- * Choose whether access to the RAM zone requires locking or not. If a zone
- * can be written to from different CPUs like with ftrace for example, then
- * PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
- */
-#define PRZ_FLAG_NO_LOCK BIT(0)
-/*
- * If a PRZ should only have a single-boot lifetime, this marks it as
- * getting wiped after its contents get copied out after boot.
- */
-#define PRZ_FLAG_ZAP_OLD BIT(1)
-
-struct persistent_ram_buffer;
-struct rs_control;
struct persistent_ram_ecc_info {
int block_size;
@@ -39,84 +18,6 @@ struct persistent_ram_ecc_info {
uint16_t *par;
};
-/**
- * struct persistent_ram_zone - Details of a persistent RAM zone (PRZ)
- * used as a pstore backend
- *
- * @paddr: physical address of the mapped RAM area
- * @size: size of mapping
- * @label: unique name of this PRZ
- * @type: frontend type for this PRZ
- * @flags: holds PRZ_FLAGS_* bits
- *
- * @buffer_lock:
- * locks access to @buffer "size" bytes and "start" offset
- * @buffer:
- * pointer to actual RAM area managed by this PRZ
- * @buffer_size:
- * bytes in @buffer->data (not including any trailing ECC bytes)
- *
- * @par_buffer:
- * pointer into @buffer->data containing ECC bytes for @buffer->data
- * @par_header:
- * pointer into @buffer->data containing ECC bytes for @buffer header
- * (i.e. all fields up to @data)
- * @rs_decoder:
- * RSLIB instance for doing ECC calculations
- * @corrected_bytes:
- * ECC corrected bytes accounting since boot
- * @bad_blocks:
- * ECC uncorrectable bytes accounting since boot
- * @ecc_info:
- * ECC configuration details
- *
- * @old_log:
- * saved copy of @buffer->data prior to most recent wipe
- * @old_log_size:
- * bytes contained in @old_log
- *
- */
-struct persistent_ram_zone {
- phys_addr_t paddr;
- size_t size;
- void *vaddr;
- char *label;
- enum pstore_type_id type;
- u32 flags;
-
- raw_spinlock_t buffer_lock;
- struct persistent_ram_buffer *buffer;
- size_t buffer_size;
-
- char *par_buffer;
- char *par_header;
- struct rs_control *rs_decoder;
- int corrected_bytes;
- int bad_blocks;
- struct persistent_ram_ecc_info ecc_info;
-
- char *old_log;
- size_t old_log_size;
-};
-
-struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
- u32 sig, struct persistent_ram_ecc_info *ecc_info,
- unsigned int memtype, u32 flags, char *label);
-void persistent_ram_free(struct persistent_ram_zone *prz);
-void persistent_ram_zap(struct persistent_ram_zone *prz);
-
-int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
- unsigned int count);
-int persistent_ram_write_user(struct persistent_ram_zone *prz,
- const void __user *s, unsigned int count);
-
-void persistent_ram_save_old(struct persistent_ram_zone *prz);
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
-void *persistent_ram_old(struct persistent_ram_zone *prz);
-void persistent_ram_free_old(struct persistent_ram_zone *prz);
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
- char *str, size_t len);
-
/*
* Ramoops platform data
* @mem_size memory size for ramoops
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index c952c5ba8fab..eaaef3ffec22 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -389,15 +389,6 @@ static inline void user_single_step_report(struct pt_regs *regs)
#define current_pt_regs() task_pt_regs(current)
#endif
-/*
- * unlike current_pt_regs(), this one is equal to task_pt_regs(current)
- * on *all* architectures; the only reason to have a per-arch definition
- * is optimisation.
- */
-#ifndef signal_pt_regs
-#define signal_pt_regs() task_pt_regs(current)
-#endif
-
#ifndef current_user_stack_pointer
#define current_user_stack_pointer() user_stack_pointer(current_pt_regs())
#endif
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index d6e5a1feb947..f29aaaf2eb21 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -10,17 +10,9 @@
#ifdef __KERNEL__
-/* Set to 1 to use kernel-wide empty_zero_page */
-#define RAID6_USE_EMPTY_ZERO_PAGE 0
#include <linux/blkdev.h>
-/* We need a pre-zeroed page... if we don't want to use the kernel-provided
- one define it here */
-#if RAID6_USE_EMPTY_ZERO_PAGE
-# define raid6_empty_zero_page empty_zero_page
-#else
extern const char raid6_empty_zero_page[PAGE_SIZE];
-#endif
#else /* ! __KERNEL__ */
/* Used for testing in user space */
diff --git a/include/linux/random.h b/include/linux/random.h
index 147a5e0d0b8e..4a2a1de423cd 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -6,7 +6,6 @@
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/once.h>
#include <uapi/linux/random.h>
@@ -17,16 +16,16 @@ void __init add_bootloader_randomness(const void *buf, size_t len);
void add_input_randomness(unsigned int type, unsigned int code,
unsigned int value) __latent_entropy;
void add_interrupt_randomness(int irq) __latent_entropy;
-void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
+void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy, bool sleep_after);
-#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
static inline void add_latent_entropy(void)
{
+#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy));
-}
#else
-static inline void add_latent_entropy(void) { }
+ add_device_randomness(NULL, 0);
#endif
+}
#if IS_ENABLED(CONFIG_VMGENID)
void add_vmfork_randomness(const void *unique_vm_id, size_t len);
@@ -51,29 +50,76 @@ static inline unsigned long get_random_long(void)
#endif
}
+u32 __get_random_u32_below(u32 ceil);
+
/*
- * On 64-bit architectures, protect against non-terminated C string overflows
- * by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
+ * Returns a random integer in the interval [0, ceil), with uniform
+ * distribution, suitable for all uses. Fastest when ceil is a constant, but
+ * still fast for variable ceil as well.
*/
-#ifdef CONFIG_64BIT
-# ifdef __LITTLE_ENDIAN
-# define CANARY_MASK 0xffffffffffffff00UL
-# else /* big endian, 64 bits: */
-# define CANARY_MASK 0x00ffffffffffffffUL
-# endif
-#else /* 32 bits: */
-# define CANARY_MASK 0xffffffffUL
-#endif
+static inline u32 get_random_u32_below(u32 ceil)
+{
+ if (!__builtin_constant_p(ceil))
+ return __get_random_u32_below(ceil);
+
+ /*
+ * For the fast path, below, all operations on ceil are precomputed by
+ * the compiler, so this incurs no overhead for checking pow2, doing
+ * divisions, or branching based on integer size. The resultant
+ * algorithm does traditional reciprocal multiplication (typically
+ * optimized by the compiler into shifts and adds), rejecting samples
+ * whose lower half would indicate a range indivisible by ceil.
+ */
+ BUILD_BUG_ON_MSG(!ceil, "get_random_u32_below() must take ceil > 0");
+ if (ceil <= 1)
+ return 0;
+ for (;;) {
+ if (ceil <= 1U << 8) {
+ u32 mult = ceil * get_random_u8();
+ if (likely(is_power_of_2(ceil) || (u8)mult >= (1U << 8) % ceil))
+ return mult >> 8;
+ } else if (ceil <= 1U << 16) {
+ u32 mult = ceil * get_random_u16();
+ if (likely(is_power_of_2(ceil) || (u16)mult >= (1U << 16) % ceil))
+ return mult >> 16;
+ } else {
+ u64 mult = (u64)ceil * get_random_u32();
+ if (likely(is_power_of_2(ceil) || (u32)mult >= -ceil % ceil))
+ return mult >> 32;
+ }
+ }
+}
+
+/*
+ * Returns a random integer in the interval (floor, U32_MAX], with uniform
+ * distribution, suitable for all uses. Fastest when floor is a constant, but
+ * still fast for variable floor as well.
+ */
+static inline u32 get_random_u32_above(u32 floor)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && floor == U32_MAX,
+ "get_random_u32_above() must take floor < U32_MAX");
+ return floor + 1 + get_random_u32_below(U32_MAX - floor);
+}
-static inline unsigned long get_random_canary(void)
+/*
+ * Returns a random integer in the interval [floor, ceil], with uniform
+ * distribution, suitable for all uses. Fastest when floor and ceil are
+ * constant, but still fast for variable floor and ceil as well.
+ */
+static inline u32 get_random_u32_inclusive(u32 floor, u32 ceil)
{
- return get_random_long() & CANARY_MASK;
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && __builtin_constant_p(ceil) &&
+ (floor > ceil || ceil - floor == U32_MAX),
+ "get_random_u32_inclusive() must take floor <= ceil");
+ return floor + get_random_u32_below(ceil - floor + 1);
}
void __init random_init_early(const char *command_line);
void __init random_init(void);
bool rng_is_initialized(void);
int wait_for_random_bytes(void);
+int execute_with_initialized_rng(struct notifier_block *nb);
/* Calls wait_for_random_bytes() and then calls get_random_bytes(buf, nbytes).
* Returns the result of the call to wait_for_random_bytes. */
@@ -108,26 +154,6 @@ declare_get_random_var_wait(long, unsigned long)
#include <asm/archrandom.h>
-/*
- * Called from the boot CPU during startup; not valid to call once
- * secondary CPUs are up and preemption is possible.
- */
-#ifndef arch_get_random_seed_longs_early
-static inline size_t __init arch_get_random_seed_longs_early(unsigned long *v, size_t max_longs)
-{
- WARN_ON(system_state != SYSTEM_BOOTING);
- return arch_get_random_seed_longs(v, max_longs);
-}
-#endif
-
-#ifndef arch_get_random_longs_early
-static inline bool __init arch_get_random_longs_early(unsigned long *v, size_t max_longs)
-{
- WARN_ON(system_state != SYSTEM_BOOTING);
- return arch_get_random_longs(v, max_longs);
-}
-#endif
-
#ifdef CONFIG_SMP
int random_prepare_cpu(unsigned int cpu);
int random_online_cpu(unsigned int cpu);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 08605ce7379d..4da98ca6273e 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -108,6 +108,15 @@ static inline int rcu_preempt_depth(void)
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+#ifdef CONFIG_RCU_LAZY
+void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func);
+#else
+static inline void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func)
+{
+ call_rcu(head, func);
+}
+#endif
+
/* Internal to kernel */
void rcu_init(void);
extern int rcu_scheduler_active;
@@ -340,6 +349,11 @@ static inline int rcu_read_lock_any_held(void)
return !preemptible();
}
+static inline int debug_lockdep_rcu_enabled(void)
+{
+ return 0;
+}
+
#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
#ifdef CONFIG_PROVE_RCU
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 768196a5f39d..68f9070aa111 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -142,23 +142,17 @@ static inline int rcu_needs_cpu(void)
* Take advantage of the fact that there is only one CPU, which
* allows us to ignore virtualization-based context switches.
*/
-static inline void rcu_virt_note_context_switch(int cpu) { }
+static inline void rcu_virt_note_context_switch(void) { }
static inline void rcu_cpu_stall_reset(void) { }
static inline int rcu_jiffies_till_stall_check(void) { return 21 * HZ; }
static inline void rcu_irq_exit_check_preempt(void) { }
-#define rcu_is_idle_cpu(cpu) \
- (is_idle_task(current) && !in_nmi() && !in_hardirq() && !in_serving_softirq())
static inline void exit_rcu(void) { }
static inline bool rcu_preempt_need_deferred_qs(struct task_struct *t)
{
return false;
}
static inline void rcu_preempt_deferred_qs(struct task_struct *t) { }
-#ifdef CONFIG_SRCU
void rcu_scheduler_starting(void);
-#else /* #ifndef CONFIG_SRCU */
-static inline void rcu_scheduler_starting(void) { }
-#endif /* #else #ifndef CONFIG_SRCU */
static inline void rcu_end_inkernel_boot(void) { }
static inline bool rcu_inkernel_boot_has_ended(void) { return true; }
static inline bool rcu_is_watching(void) { return true; }
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 5efb51486e8a..4003bf6cfa1c 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -27,7 +27,7 @@ void rcu_cpu_stall_reset(void);
* wrapper around rcu_note_context_switch(), which allows TINY_RCU
* to save a few bytes. The caller must have disabled interrupts.
*/
-static inline void rcu_virt_note_context_switch(int cpu)
+static inline void rcu_virt_note_context_switch(void)
{
rcu_note_context_switch(false);
}
@@ -87,8 +87,6 @@ bool poll_state_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp);
void cond_synchronize_rcu(unsigned long oldstate);
void cond_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp);
-bool rcu_is_idle_cpu(int cpu);
-
#ifdef CONFIG_PROVE_RCU
void rcu_irq_exit_check_preempt(void);
#else
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index ca3434dca3a0..a3bc695bcca0 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -24,6 +24,7 @@ struct module;
struct clk;
struct device;
struct device_node;
+struct fsi_device;
struct i2c_client;
struct i3c_device;
struct irq_domain;
@@ -628,6 +629,10 @@ struct regmap *__regmap_init_spi_avmm(struct spi_device *spi,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
+struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key,
+ const char *lock_name);
struct regmap *__devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
@@ -693,6 +698,11 @@ struct regmap *__devm_regmap_init_spi_avmm(struct spi_device *spi,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
+struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key,
+ const char *lock_name);
+
/*
* Wrapper for regmap_init macros to include a unique lockdep key and name
* for each call. No-op if CONFIG_LOCKDEP is not set.
@@ -920,6 +930,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
spi, config)
/**
+ * regmap_init_fsi() - Initialise register map
+ *
+ * @fsi_dev: 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.
+ */
+#define regmap_init_fsi(fsi_dev, config) \
+ __regmap_lockdep_wrapper(__regmap_init_fsi, #config, fsi_dev, \
+ config)
+
+/**
* devm_regmap_init() - Initialise managed register map
*
* @dev: Device that will be interacted with
@@ -1148,6 +1171,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
__regmap_lockdep_wrapper(__devm_regmap_init_spi_avmm, #config, \
spi, config)
+/**
+ * devm_regmap_init_fsi() - Initialise managed register map
+ *
+ * @fsi_dev: 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_fsi(fsi_dev, config) \
+ __regmap_lockdep_wrapper(__devm_regmap_init_fsi, #config, \
+ fsi_dev, config)
+
int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk);
void regmap_mmio_detach_clk(struct regmap *map);
void regmap_exit(struct regmap *map);
@@ -1219,6 +1256,7 @@ static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map);
+bool regmap_might_sleep(struct regmap *map);
int regmap_async_complete(struct regmap *map);
bool regmap_can_raw_write(struct regmap *map);
size_t regmap_get_raw_read_max(struct regmap *map);
@@ -1542,6 +1580,8 @@ struct regmap_irq_chip_data;
* before regmap_irq_handler process the interrupts.
* @handle_post_irq: Driver specific callback to handle interrupt from device
* after handling the interrupts in regmap_irq_handler().
+ * @handle_mask_sync: Callback used to handle IRQ mask syncs. The index will be
+ * in the range [0, num_regs)
* @set_type_virt: Driver specific callback to extend regmap_irq_set_type()
* and configure virt regs. Deprecated, use @set_type_config
* callback and config registers instead.
@@ -1603,6 +1643,9 @@ struct regmap_irq_chip {
int (*handle_pre_irq)(void *irq_drv_data);
int (*handle_post_irq)(void *irq_drv_data);
+ int (*handle_mask_sync)(struct regmap *map, int index,
+ unsigned int mask_buf_def,
+ unsigned int mask_buf, void *irq_drv_data);
int (*set_type_virt)(unsigned int **buf, unsigned int type,
unsigned long hwirq, int reg);
int (*set_type_config)(unsigned int **buf, unsigned int type,
@@ -1905,6 +1948,12 @@ static inline int regmap_get_reg_stride(struct regmap *map)
return -EINVAL;
}
+static inline bool regmap_might_sleep(struct regmap *map)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return true;
+}
+
static inline int regcache_sync(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");
diff --git a/include/linux/regset.h b/include/linux/regset.h
index a00765f0e8cf..9061266dd8de 100644
--- a/include/linux/regset.h
+++ b/include/linux/regset.h
@@ -275,15 +275,15 @@ static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
return 0;
}
-static inline int user_regset_copyin_ignore(unsigned int *pos,
- unsigned int *count,
- const void **kbuf,
- const void __user **ubuf,
- const int start_pos,
- const int end_pos)
+static inline void user_regset_copyin_ignore(unsigned int *pos,
+ unsigned int *count,
+ const void **kbuf,
+ const void __user **ubuf,
+ const int start_pos,
+ const int end_pos)
{
if (*count == 0)
- return 0;
+ return;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
@@ -295,7 +295,6 @@ static inline int user_regset_copyin_ignore(unsigned int *pos,
*pos += copy;
*count -= copy;
}
- return 0;
}
extern int regset_get(struct task_struct *target,
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 0cf5b20c6ddf..0cee154abc9f 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -89,11 +89,12 @@ struct rdt_domain {
/**
* struct resctrl_cache - Cache allocation related data
* @cbm_len: Length of the cache bit mask
- * @min_cbm_bits: Minimum number of consecutive bits to be set
+ * @min_cbm_bits: Minimum number of consecutive bits to be set.
+ * The value 0 means the architecture can support
+ * zero CBM.
* @shareable_bits: Bitmask of shareable resource with other
* executing entities
* @arch_has_sparse_bitmaps: True if a bitmap like f00f is valid.
- * @arch_has_empty_bitmaps: True if the '0' bitmap is valid.
* @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache
* level has CPU scope.
*/
@@ -102,7 +103,6 @@ struct resctrl_cache {
unsigned int min_cbm_bits;
unsigned int shareable_bits;
bool arch_has_sparse_bitmaps;
- bool arch_has_empty_bitmaps;
bool arch_has_per_cpu_cfg;
};
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 2504df9a0453..3c7d295746f6 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -100,7 +100,7 @@ __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *k
int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full);
__poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
- struct file *filp, poll_table *poll_table);
+ struct file *filp, poll_table *poll_table, int full);
void ring_buffer_wake_waiters(struct trace_buffer *buffer, int cpu);
#define RING_BUFFER_ALL_CPUS -1
diff --git a/include/linux/sbitmap.h b/include/linux/sbitmap.h
index 4d2d5205ab58..d662cf136021 100644
--- a/include/linux/sbitmap.h
+++ b/include/linux/sbitmap.h
@@ -87,11 +87,6 @@ struct sbitmap {
*/
struct sbq_wait_state {
/**
- * @wait_cnt: Number of frees remaining before we wake up.
- */
- atomic_t wait_cnt;
-
- /**
* @wait: Wait queue.
*/
wait_queue_head_t wait;
@@ -138,6 +133,17 @@ struct sbitmap_queue {
* sbitmap_queue_get_shallow()
*/
unsigned int min_shallow_depth;
+
+ /**
+ * @completion_cnt: Number of bits cleared passed to the
+ * wakeup function.
+ */
+ atomic_t completion_cnt;
+
+ /**
+ * @wakeup_cnt: Number of thread wake ups issued.
+ */
+ atomic_t wakeup_cnt;
};
/**
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ffb6eb55cd13..5affff14993d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -888,9 +888,6 @@ struct task_struct {
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned sched_migrated:1;
-#ifdef CONFIG_PSI
- unsigned sched_psi_wake_requeue:1;
-#endif
/* Force alignment to the next boundary: */
unsigned :0;
@@ -1243,7 +1240,7 @@ struct task_struct {
unsigned int futex_state;
#endif
#ifdef CONFIG_PERF_EVENTS
- struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
+ struct perf_event_context *perf_event_ctxp;
struct mutex perf_event_mutex;
struct list_head perf_event_list;
#endif
diff --git a/include/linux/scs.h b/include/linux/scs.h
index 18122d9e17ff..4ab5bdc898cf 100644
--- a/include/linux/scs.h
+++ b/include/linux/scs.h
@@ -53,6 +53,22 @@ static inline bool task_scs_end_corrupted(struct task_struct *tsk)
return sz >= SCS_SIZE - 1 || READ_ONCE_NOCHECK(*magic) != SCS_END_MAGIC;
}
+DECLARE_STATIC_KEY_FALSE(dynamic_scs_enabled);
+
+static inline bool scs_is_dynamic(void)
+{
+ if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
+ return false;
+ return static_branch_likely(&dynamic_scs_enabled);
+}
+
+static inline bool scs_is_enabled(void)
+{
+ if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
+ return true;
+ return scs_is_dynamic();
+}
+
#else /* CONFIG_SHADOW_CALL_STACK */
static inline void *scs_alloc(int node) { return NULL; }
@@ -62,6 +78,8 @@ static inline void scs_task_reset(struct task_struct *tsk) {}
static inline int scs_prepare(struct task_struct *tsk, int node) { return 0; }
static inline void scs_release(struct task_struct *tsk) {}
static inline bool task_scs_end_corrupted(struct task_struct *tsk) { return false; }
+static inline bool scs_is_enabled(void) { return false; }
+static inline bool scs_is_dynamic(void) { return false; }
#endif /* CONFIG_SHADOW_CALL_STACK */
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index d31d76be4982..175079552f68 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -27,6 +27,7 @@ struct seccomp_filter;
*
* @mode: indicates one of the valid values above for controlled
* system calls available to a process.
+ * @filter_count: number of seccomp filters
* @filter: must always point to a valid seccomp-filter or NULL as it is
* accessed without locking during system call entry.
*
diff --git a/include/linux/security.h b/include/linux/security.h
index ca1b7109c0db..5b67f208f7de 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/sockptr.h>
struct linux_binprm;
struct cred;
@@ -361,6 +362,13 @@ int security_inode_getattr(const struct path *path);
int security_inode_setxattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
+int security_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl);
+int security_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name);
+int security_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name);
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
int security_inode_getxattr(struct dentry *dentry, const char *name);
@@ -396,6 +404,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_file_open(struct file *file);
+int security_file_truncate(struct file *file);
int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
void security_task_free(struct task_struct *task);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
@@ -872,6 +881,28 @@ static inline int security_inode_setxattr(struct user_namespace *mnt_userns,
return cap_inode_setxattr(dentry, name, value, size, flags);
}
+static inline int security_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return 0;
+}
+
+static inline int security_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return 0;
+}
+
+static inline int security_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ return 0;
+}
+
static inline void security_inode_post_setxattr(struct dentry *dentry,
const char *name, const void *value, size_t size, int flags)
{ }
@@ -1014,6 +1045,11 @@ static inline int security_file_open(struct file *file)
return 0;
}
+static inline int security_file_truncate(struct file *file)
+{
+ return 0;
+}
+
static inline int security_task_alloc(struct task_struct *task,
unsigned long clone_flags)
{
@@ -1411,8 +1447,8 @@ int security_socket_getsockopt(struct socket *sock, int level, int optname);
int security_socket_setsockopt(struct socket *sock, int level, int optname);
int security_socket_shutdown(struct socket *sock, int how);
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
-int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len);
+int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
+ sockptr_t optlen, unsigned int len);
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
void security_sk_free(struct sock *sk);
@@ -1548,8 +1584,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
return 0;
}
-static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock,
+ sockptr_t optval,
+ sockptr_t optlen,
+ unsigned int len)
{
return -ENOPROTOOPT;
}
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 6f837bb6c715..31ac562a17d7 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -11,7 +11,8 @@
#define LINUX_OPAL_H
#include <uapi/linux/sed-opal.h>
-#include <linux/kernel.h>
+#include <linux/compiler_types.h>
+#include <linux/types.h>
struct opal_dev;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index d657f2a42a7b..91871464b99d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -743,9 +743,15 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
static inline int setup_earlycon(char *buf) { return 0; }
#endif
-static inline bool uart_console_enabled(struct uart_port *port)
+/* Variant of uart_console_registered() when the console_list_lock is held. */
+static inline bool uart_console_registered_locked(struct uart_port *port)
{
- return uart_console(port) && (port->cons->flags & CON_ENABLED);
+ return uart_console(port) && console_is_registered_locked(port->cons);
+}
+
+static inline bool uart_console_registered(struct uart_port *port)
+{
+ return uart_console(port) && console_is_registered(port->cons);
}
struct uart_port *uart_get_console(struct uart_port *ports, int nr,
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
index 48f4b645193b..70d6cb94e580 100644
--- a/include/linux/skmsg.h
+++ b/include/linux/skmsg.h
@@ -376,7 +376,7 @@ static inline void sk_psock_report_error(struct sk_psock *psock, int err)
}
struct sk_psock *sk_psock_init(struct sock *sk, int node);
-void sk_psock_stop(struct sk_psock *psock, bool wait);
+void sk_psock_stop(struct sk_psock *psock);
#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock);
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 90877fcde70b..45af70315a94 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -76,6 +76,17 @@
* rcu_read_lock before reading the address, then rcu_read_unlock after
* taking the spinlock within the structure expected at that address.
*
+ * Note that it is not possible to acquire a lock within a structure
+ * allocated with SLAB_TYPESAFE_BY_RCU without first acquiring a reference
+ * as described above. The reason is that SLAB_TYPESAFE_BY_RCU pages
+ * are not zeroed before being given to the slab, which means that any
+ * locks must be initialized after each and every kmem_struct_alloc().
+ * Alternatively, make the ctor passed to kmem_cache_create() initialize
+ * the locks at page-allocation time, as is done in __i915_request_ctor(),
+ * sighand_ctor(), and anon_vma_ctor(). Such a ctor permits readers
+ * to safely acquire those ctor-initialized locks under rcu_read_lock()
+ * protection.
+ *
* Note that SLAB_TYPESAFE_BY_RCU was originally named SLAB_DESTROY_BY_RCU.
*/
/* Defer freeing slabs to RCU */
@@ -129,7 +140,11 @@
/* The following flags affect the page allocator grouping pages by mobility */
/* Objects are reclaimable */
+#ifndef CONFIG_SLUB_TINY
#define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0x00020000U)
+#else
+#define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0)
+#endif
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
/*
@@ -336,13 +351,18 @@ enum kmalloc_cache_type {
#endif
#ifndef CONFIG_MEMCG_KMEM
KMALLOC_CGROUP = KMALLOC_NORMAL,
-#else
- KMALLOC_CGROUP,
#endif
+#ifdef CONFIG_SLUB_TINY
+ KMALLOC_RECLAIM = KMALLOC_NORMAL,
+#else
KMALLOC_RECLAIM,
+#endif
#ifdef CONFIG_ZONE_DMA
KMALLOC_DMA,
#endif
+#ifdef CONFIG_MEMCG_KMEM
+ KMALLOC_CGROUP,
+#endif
NR_KMALLOC_TYPES
};
@@ -441,7 +461,18 @@ static_assert(PAGE_SHIFT <= 20);
#endif /* !CONFIG_SLOB */
void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __alloc_size(1);
-void *kmem_cache_alloc(struct kmem_cache *s, gfp_t flags) __assume_slab_alignment __malloc;
+
+/**
+ * kmem_cache_alloc - Allocate an object
+ * @cachep: The cache to allocate from.
+ * @flags: See kmalloc().
+ *
+ * Allocate an object from this cache.
+ * See kmem_cache_zalloc() for a shortcut of adding __GFP_ZERO to flags.
+ *
+ * Return: pointer to the new object or %NULL in case of error
+ */
+void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) __assume_slab_alignment __malloc;
void *kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
gfp_t gfpflags) __assume_slab_alignment __malloc;
void kmem_cache_free(struct kmem_cache *s, void *objp);
@@ -470,35 +501,12 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignm
void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node) __assume_slab_alignment
__malloc;
-#ifdef CONFIG_TRACING
void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size)
__assume_kmalloc_alignment __alloc_size(3);
void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
int node, size_t size) __assume_kmalloc_alignment
__alloc_size(4);
-#else /* CONFIG_TRACING */
-/* Save a function call when CONFIG_TRACING=n */
-static __always_inline __alloc_size(3)
-void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size)
-{
- void *ret = kmem_cache_alloc(s, flags);
-
- ret = kasan_kmalloc(s, ret, size, flags);
- return ret;
-}
-
-static __always_inline __alloc_size(4)
-void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
- int node, size_t size)
-{
- void *ret = kmem_cache_alloc_node(s, gfpflags, node);
-
- ret = kasan_kmalloc(s, ret, size, gfpflags);
- return ret;
-}
-#endif /* CONFIG_TRACING */
-
void *kmalloc_large(size_t size, gfp_t flags) __assume_page_alignment
__alloc_size(1);
@@ -506,9 +514,9 @@ void *kmalloc_large_node(size_t size, gfp_t flags, int node) __assume_page_align
__alloc_size(1);
/**
- * kmalloc - allocate memory
+ * kmalloc - allocate kernel memory
* @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
+ * @flags: describe the allocation context
*
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
@@ -535,12 +543,12 @@ void *kmalloc_large_node(size_t size, gfp_t flags, int node) __assume_page_align
* %GFP_ATOMIC
* Allocation will not sleep. May use emergency pools.
*
- * %GFP_HIGHUSER
- * Allocate memory from high memory on behalf of user.
- *
* Also it is possible to set different flags by OR'ing
* in one or more of the following additional @flags:
*
+ * %__GFP_ZERO
+ * Zero the allocated memory before returning. Also see kzalloc().
+ *
* %__GFP_HIGH
* This allocation has high priority and may use emergency pools.
*
@@ -559,42 +567,42 @@ void *kmalloc_large_node(size_t size, gfp_t flags, int node) __assume_page_align
* Try really hard to succeed the allocation but fail
* eventually.
*/
+#ifndef CONFIG_SLOB
static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
{
- if (__builtin_constant_p(size)) {
-#ifndef CONFIG_SLOB
+ if (__builtin_constant_p(size) && size) {
unsigned int index;
-#endif
+
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
-#ifndef CONFIG_SLOB
- index = kmalloc_index(size);
-
- if (!index)
- return ZERO_SIZE_PTR;
+ index = kmalloc_index(size);
return kmalloc_trace(
kmalloc_caches[kmalloc_type(flags)][index],
flags, size);
-#endif
}
return __kmalloc(size, flags);
}
+#else
+static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size) && size > KMALLOC_MAX_CACHE_SIZE)
+ return kmalloc_large(size, flags);
+
+ return __kmalloc(size, flags);
+}
+#endif
#ifndef CONFIG_SLOB
static __always_inline __alloc_size(1) void *kmalloc_node(size_t size, gfp_t flags, int node)
{
- if (__builtin_constant_p(size)) {
+ if (__builtin_constant_p(size) && size) {
unsigned int index;
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large_node(size, flags, node);
index = kmalloc_index(size);
-
- if (!index)
- return ZERO_SIZE_PTR;
-
return kmalloc_node_trace(
kmalloc_caches[kmalloc_type(flags)][index],
flags, node, size);
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index f0ffad6a3365..5834bad8ad78 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -80,8 +80,10 @@ struct kmem_cache {
unsigned int *random_seq;
#endif
+#ifdef CONFIG_HARDENED_USERCOPY
unsigned int useroffset; /* Usercopy region offset */
unsigned int usersize; /* Usercopy region size */
+#endif
struct kmem_cache_node *node[MAX_NUMNODES];
};
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index f9c68a9dac04..aa0ee1678d29 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -41,6 +41,7 @@ enum stat_item {
CPU_PARTIAL_DRAIN, /* Drain cpu partial to node partial */
NR_SLUB_STAT_ITEMS };
+#ifndef CONFIG_SLUB_TINY
/*
* When changing the layout, make sure freelist and tid are still compatible
* with this_cpu_cmpxchg_double() alignment requirements.
@@ -57,6 +58,7 @@ struct kmem_cache_cpu {
unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
+#endif /* CONFIG_SLUB_TINY */
#ifdef CONFIG_SLUB_CPU_PARTIAL
#define slub_percpu_partial(c) ((c)->partial)
@@ -88,7 +90,9 @@ struct kmem_cache_order_objects {
* Slab cache management.
*/
struct kmem_cache {
+#ifndef CONFIG_SLUB_TINY
struct kmem_cache_cpu __percpu *cpu_slab;
+#endif
/* Used for retrieving partial slabs, etc. */
slab_flags_t flags;
unsigned long min_partial;
@@ -136,13 +140,15 @@ struct kmem_cache {
struct kasan_cache kasan_info;
#endif
+#ifdef CONFIG_HARDENED_USERCOPY
unsigned int useroffset; /* Usercopy region offset */
unsigned int usersize; /* Usercopy region size */
+#endif
struct kmem_cache_node *node[MAX_NUMNODES];
};
-#ifdef CONFIG_SYSFS
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_SLUB_TINY)
#define SLAB_SUPPORTS_SYSFS
void sysfs_slab_unlink(struct kmem_cache *);
void sysfs_slab_release(struct kmem_cache *);
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index d2b02bb43768..b85f66db33e1 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -9,6 +9,13 @@
enum mtk_ddp_comp_id;
struct device;
+enum mtk_dpi_out_format_con {
+ MTK_DPI_RGB888_SDR_CON,
+ MTK_DPI_RGB888_DDR_CON,
+ MTK_DPI_RGB565_SDR_CON,
+ MTK_DPI_RGB565_DDR_CON
+};
+
enum mtk_ddp_comp_id {
DDP_COMPONENT_AAL0,
DDP_COMPONENT_AAL1,
diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h
index bc2fb8343a94..ad1fd718169d 100644
--- a/include/linux/soc/qcom/llcc-qcom.h
+++ b/include/linux/soc/qcom/llcc-qcom.h
@@ -42,7 +42,19 @@
#define LLCC_CPUHWT 36
#define LLCC_MDMCLAD2 37
#define LLCC_CAMEXP1 38
+#define LLCC_CMPTHCP 39
+#define LLCC_LCPDARE 40
#define LLCC_AENPU 45
+#define LLCC_ISLAND1 46
+#define LLCC_ISLAND2 47
+#define LLCC_ISLAND3 48
+#define LLCC_ISLAND4 49
+#define LLCC_CAMEXP2 50
+#define LLCC_CAMEXP3 51
+#define LLCC_CAMEXP4 52
+#define LLCC_DISP_WB 53
+#define LLCC_DISP_1 54
+#define LLCC_VIDVSP 64
/**
* struct llcc_slice_desc - Cache slice descriptor
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
index 2e9fd91572d4..d2f581feed67 100644
--- a/include/linux/soundwire/sdw_intel.h
+++ b/include/linux/soundwire/sdw_intel.h
@@ -286,8 +286,6 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx);
void sdw_intel_exit(struct sdw_intel_ctx *ctx);
-void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);
-
irqreturn_t sdw_intel_thread(int irq, void *dev_id);
#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 01226e4d960a..9b9d0bbf1d3c 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -47,11 +47,8 @@ int init_srcu_struct(struct srcu_struct *ssp);
#include <linux/srcutiny.h>
#elif defined(CONFIG_TREE_SRCU)
#include <linux/srcutree.h>
-#elif defined(CONFIG_SRCU)
-#error "Unknown SRCU implementation specified to kernel configuration"
#else
-/* Dummy definition for things like notifiers. Actual use gets link error. */
-struct srcu_struct { };
+#error "Unknown SRCU implementation specified to kernel configuration"
#endif
void call_srcu(struct srcu_struct *ssp, struct rcu_head *head,
@@ -64,11 +61,21 @@ unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp);
unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp);
bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie);
-#ifdef CONFIG_SRCU
+#ifdef CONFIG_NEED_SRCU_NMI_SAFE
+int __srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp);
+void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx) __releases(ssp);
+#else
+static inline int __srcu_read_lock_nmisafe(struct srcu_struct *ssp)
+{
+ return __srcu_read_lock(ssp);
+}
+static inline void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx)
+{
+ __srcu_read_unlock(ssp, idx);
+}
+#endif /* CONFIG_NEED_SRCU_NMI_SAFE */
+
void srcu_init(void);
-#else /* #ifdef CONFIG_SRCU */
-static inline void srcu_init(void) { }
-#endif /* #else #ifdef CONFIG_SRCU */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -104,6 +111,18 @@ static inline int srcu_read_lock_held(const struct srcu_struct *ssp)
#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
+#define SRCU_NMI_UNKNOWN 0x0
+#define SRCU_NMI_UNSAFE 0x1
+#define SRCU_NMI_SAFE 0x2
+
+#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_TREE_SRCU)
+void srcu_check_nmi_safety(struct srcu_struct *ssp, bool nmi_safe);
+#else
+static inline void srcu_check_nmi_safety(struct srcu_struct *ssp,
+ bool nmi_safe) { }
+#endif
+
+
/**
* srcu_dereference_check - fetch SRCU-protected pointer for later dereferencing
* @p: the pointer to fetch and protect for later dereferencing
@@ -161,17 +180,36 @@ static inline int srcu_read_lock(struct srcu_struct *ssp) __acquires(ssp)
{
int retval;
+ srcu_check_nmi_safety(ssp, false);
retval = __srcu_read_lock(ssp);
rcu_lock_acquire(&(ssp)->dep_map);
return retval;
}
+/**
+ * srcu_read_lock_nmisafe - register a new reader for an SRCU-protected structure.
+ * @ssp: srcu_struct in which to register the new reader.
+ *
+ * Enter an SRCU read-side critical section, but in an NMI-safe manner.
+ * See srcu_read_lock() for more information.
+ */
+static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp)
+{
+ int retval;
+
+ srcu_check_nmi_safety(ssp, true);
+ retval = __srcu_read_lock_nmisafe(ssp);
+ rcu_lock_acquire(&(ssp)->dep_map);
+ return retval;
+}
+
/* Used by tracing, cannot be traced and cannot invoke lockdep. */
static inline notrace int
srcu_read_lock_notrace(struct srcu_struct *ssp) __acquires(ssp)
{
int retval;
+ srcu_check_nmi_safety(ssp, false);
retval = __srcu_read_lock(ssp);
return retval;
}
@@ -187,14 +225,32 @@ static inline void srcu_read_unlock(struct srcu_struct *ssp, int idx)
__releases(ssp)
{
WARN_ON_ONCE(idx & ~0x1);
+ srcu_check_nmi_safety(ssp, false);
rcu_lock_release(&(ssp)->dep_map);
__srcu_read_unlock(ssp, idx);
}
+/**
+ * srcu_read_unlock_nmisafe - unregister a old reader from an SRCU-protected structure.
+ * @ssp: srcu_struct in which to unregister the old reader.
+ * @idx: return value from corresponding srcu_read_lock().
+ *
+ * Exit an SRCU read-side critical section, but in an NMI-safe manner.
+ */
+static inline void srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx)
+ __releases(ssp)
+{
+ WARN_ON_ONCE(idx & ~0x1);
+ srcu_check_nmi_safety(ssp, true);
+ rcu_lock_release(&(ssp)->dep_map);
+ __srcu_read_unlock_nmisafe(ssp, idx);
+}
+
/* Used by tracing, cannot be traced and cannot call lockdep. */
static inline notrace void
srcu_read_unlock_notrace(struct srcu_struct *ssp, int idx) __releases(ssp)
{
+ srcu_check_nmi_safety(ssp, false);
__srcu_read_unlock(ssp, idx);
}
diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h
index e3014319d1ad..c689a81752c9 100644
--- a/include/linux/srcutree.h
+++ b/include/linux/srcutree.h
@@ -23,8 +23,9 @@ struct srcu_struct;
*/
struct srcu_data {
/* Read-side state. */
- unsigned long srcu_lock_count[2]; /* Locks per CPU. */
- unsigned long srcu_unlock_count[2]; /* Unlocks per CPU. */
+ atomic_long_t srcu_lock_count[2]; /* Locks per CPU. */
+ atomic_long_t srcu_unlock_count[2]; /* Unlocks per CPU. */
+ int srcu_nmi_safety; /* NMI-safe srcu_struct structure? */
/* Update-side state. */
spinlock_t __private lock ____cacheline_internodealigned_in_smp;
diff --git a/include/linux/stackprotector.h b/include/linux/stackprotector.h
index 4c678c4fec58..9c88707d9a0f 100644
--- a/include/linux/stackprotector.h
+++ b/include/linux/stackprotector.h
@@ -6,6 +6,25 @@
#include <linux/sched.h>
#include <linux/random.h>
+/*
+ * On 64-bit architectures, protect against non-terminated C string overflows
+ * by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
+ */
+#ifdef CONFIG_64BIT
+# ifdef __LITTLE_ENDIAN
+# define CANARY_MASK 0xffffffffffffff00UL
+# else /* big endian, 64 bits: */
+# define CANARY_MASK 0x00ffffffffffffffUL
+# endif
+#else /* 32 bits: */
+# define CANARY_MASK 0xffffffffUL
+#endif
+
+static inline unsigned long get_random_canary(void)
+{
+ return get_random_long() & CANARY_MASK;
+}
+
#if defined(CONFIG_STACKPROTECTOR) || defined(CONFIG_ARM64_PTR_AUTH)
# include <asm/stackprotector.h>
#else
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 88de45491376..ed722dd33b46 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -220,13 +220,6 @@ static inline __be32 svc_getu32(struct kvec *iov)
return val;
}
-static inline void svc_ungetu32(struct kvec *iov)
-{
- __be32 *vp = (__be32 *)iov->iov_base;
- iov->iov_base = (void *)(vp - 1);
- iov->iov_len += sizeof(*vp);
-}
-
static inline void svc_putu32(struct kvec *iov, __be32 val)
{
__be32 *vp = iov->iov_base + iov->iov_len;
@@ -311,7 +304,6 @@ struct svc_rqst {
struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
struct svc_cacherep * rq_cacherep; /* cache info */
struct task_struct *rq_task; /* service thread */
- spinlock_t rq_lock; /* per-request lock */
struct net *rq_bc_net; /* pointer to backchannel's
* net namespace
*/
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 86b95ccb81bb..b07b277d6a16 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -33,11 +33,13 @@
* can use the extra bits to store other information besides PFN.
*/
#ifdef MAX_PHYSMEM_BITS
-#define SWP_PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define SWP_PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
#else /* MAX_PHYSMEM_BITS */
-#define SWP_PFN_BITS (BITS_PER_LONG - PAGE_SHIFT)
+#define SWP_PFN_BITS min_t(int, \
+ sizeof(phys_addr_t) * 8 - PAGE_SHIFT, \
+ SWP_TYPE_SHIFT)
#endif /* MAX_PHYSMEM_BITS */
-#define SWP_PFN_MASK (BIT(SWP_PFN_BITS) - 1)
+#define SWP_PFN_MASK (BIT(SWP_PFN_BITS) - 1)
/**
* Migration swap entry specific bitfield definitions. Layout:
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a34b0f9a9972..33a0ee3bcb2e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -264,6 +264,7 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
#define SC_VAL64(type, name) ((type) name##_hi << 32 | name##_lo)
#ifdef CONFIG_COMPAT
+#define SYSCALL32_DEFINE0 COMPAT_SYSCALL_DEFINE0
#define SYSCALL32_DEFINE1 COMPAT_SYSCALL_DEFINE1
#define SYSCALL32_DEFINE2 COMPAT_SYSCALL_DEFINE2
#define SYSCALL32_DEFINE3 COMPAT_SYSCALL_DEFINE3
@@ -271,6 +272,7 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
#define SYSCALL32_DEFINE5 COMPAT_SYSCALL_DEFINE5
#define SYSCALL32_DEFINE6 COMPAT_SYSCALL_DEFINE6
#else
+#define SYSCALL32_DEFINE0 SYSCALL_DEFINE0
#define SYSCALL32_DEFINE1 SYSCALL_DEFINE1
#define SYSCALL32_DEFINE2 SYSCALL_DEFINE2
#define SYSCALL32_DEFINE3 SYSCALL_DEFINE3
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 9ecc128944a1..5e093602e8fc 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -100,6 +100,7 @@ struct thermal_cooling_device_ops {
struct thermal_cooling_device {
int id;
char *type;
+ unsigned long max_state;
struct device device;
struct device_node *np;
void *devdata;
diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h
index 3146f1c056c9..bb9d3f5542f8 100644
--- a/include/linux/time_namespace.h
+++ b/include/linux/time_namespace.h
@@ -45,6 +45,7 @@ struct time_namespace *copy_time_ns(unsigned long flags,
void free_time_ns(struct time_namespace *ns);
void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk);
struct vdso_data *arch_get_vdso_data(void *vvar_page);
+struct page *find_timens_vvar_page(struct vm_area_struct *vma);
static inline void put_time_ns(struct time_namespace *ns)
{
@@ -141,6 +142,11 @@ static inline void timens_on_fork(struct nsproxy *nsproxy,
return;
}
+static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
+{
+ return NULL;
+}
+
static inline void timens_add_monotonic(struct timespec64 *ts) { }
static inline void timens_add_boottime(struct timespec64 *ts) { }
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 648f00105f58..9162f275819a 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -169,7 +169,6 @@ static inline int timer_pending(const struct timer_list * timer)
}
extern void add_timer_on(struct timer_list *timer, int cpu);
-extern int del_timer(struct timer_list * timer);
extern int mod_timer(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
extern int timer_reduce(struct timer_list *timer, unsigned long expires);
@@ -183,14 +182,36 @@ extern int timer_reduce(struct timer_list *timer, unsigned long expires);
extern void add_timer(struct timer_list *timer);
extern int try_to_del_timer_sync(struct timer_list *timer);
+extern int timer_delete_sync(struct timer_list *timer);
+extern int timer_delete(struct timer_list *timer);
+extern int timer_shutdown_sync(struct timer_list *timer);
+extern int timer_shutdown(struct timer_list *timer);
-#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
- extern int del_timer_sync(struct timer_list *timer);
-#else
-# define del_timer_sync(t) del_timer(t)
-#endif
+/**
+ * del_timer_sync - Delete a pending timer and wait for a running callback
+ * @timer: The timer to be deleted
+ *
+ * See timer_delete_sync() for detailed explanation.
+ *
+ * Do not use in new code. Use timer_delete_sync() instead.
+ */
+static inline int del_timer_sync(struct timer_list *timer)
+{
+ return timer_delete_sync(timer);
+}
-#define del_singleshot_timer_sync(t) del_timer_sync(t)
+/**
+ * del_timer - Delete a pending timer
+ * @timer: The timer to be deleted
+ *
+ * See timer_delete() for detailed explanation.
+ *
+ * Do not use in new code. Use timer_delete() instead.
+ */
+static inline int del_timer(struct timer_list *timer)
+{
+ return timer_delete(timer);
+}
extern void init_timers(void);
struct hrtimer;
diff --git a/include/linux/timerqueue.h b/include/linux/timerqueue.h
index 93884086f392..adc80e29168e 100644
--- a/include/linux/timerqueue.h
+++ b/include/linux/timerqueue.h
@@ -35,7 +35,7 @@ struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
{
struct rb_node *leftmost = rb_first_cached(&head->rb_root);
- return rb_entry(leftmost, struct timerqueue_node, node);
+ return rb_entry_safe(leftmost, struct timerqueue_node, node);
}
static inline void timerqueue_init(struct timerqueue_node *node)
diff --git a/include/linux/trace.h b/include/linux/trace.h
index b5e16e438448..80ffda871749 100644
--- a/include/linux/trace.h
+++ b/include/linux/trace.h
@@ -26,13 +26,13 @@ struct trace_export {
int flags;
};
+struct trace_array;
+
#ifdef CONFIG_TRACING
int register_ftrace_export(struct trace_export *export);
int unregister_ftrace_export(struct trace_export *export);
-struct trace_array;
-
void trace_printk_init_buffers(void);
__printf(3, 4)
int trace_array_printk(struct trace_array *tr, unsigned long ip,
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 2e3134b14ffd..9f158238edba 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -29,6 +29,9 @@ enum iter_type {
ITER_UBUF,
};
+#define ITER_SOURCE 1 // == WRITE
+#define ITER_DEST 0 // == READ
+
struct iov_iter_state {
size_t iov_offset;
size_t count;
@@ -247,8 +250,14 @@ void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
void iov_iter_xarray(struct iov_iter *i, unsigned int direction, struct xarray *xarray,
loff_t start, size_t count);
+ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
+ size_t maxsize, unsigned maxpages, size_t *start,
+ unsigned gup_flags);
ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start);
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+ struct page ***pages, size_t maxsize, size_t *start,
+ unsigned gup_flags);
ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i, struct page ***pages,
size_t maxsize, size_t *start);
int iov_iter_npages(const struct iov_iter *i, int maxpages);
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e7cebeb875dd..fdd393f70b19 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -189,6 +189,7 @@ int vfio_register_emulated_iommu_dev(struct vfio_device *device);
void vfio_unregister_group_dev(struct vfio_device *device);
int vfio_assign_device_set(struct vfio_device *device, void *set_id);
+unsigned int vfio_device_set_open_count(struct vfio_device_set *dev_set);
int vfio_mig_get_next_state(struct vfio_device *device,
enum vfio_device_mig_state cur_fsm,
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 7f5a51aae0a7..a0307b516b09 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -209,7 +209,7 @@ __remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq
list_del(&wq_entry->entry);
}
-void __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key);
+int __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key);
void __wake_up_locked_key(struct wait_queue_head *wq_head, unsigned int mode, void *key);
void __wake_up_locked_key_bookmark(struct wait_queue_head *wq_head,
unsigned int mode, void *key, wait_queue_entry_t *bookmark);
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 4c379d23ec6e..2e7dd44926e4 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -22,6 +22,12 @@
struct inode;
struct dentry;
+static inline bool is_posix_acl_xattr(const char *name)
+{
+ return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
+}
+
/*
* struct xattr_handler: When @name is set, match attributes with exactly that
* name. When @prefix is set instead, match attributes with that prefix and
@@ -68,9 +74,9 @@ int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
int vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
-ssize_t vfs_getxattr_alloc(struct user_namespace *mnt_userns,
- struct dentry *dentry, const char *name,
- char **xattr_value, size_t size, gfp_t flags);
+int vfs_getxattr_alloc(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *name,
+ char **xattr_value, size_t size, gfp_t flags);
int xattr_supported_namespace(struct inode *inode, const char *prefix);
@@ -80,48 +86,28 @@ static inline const char *xattr_prefix(const struct xattr_handler *handler)
}
struct simple_xattrs {
- struct list_head head;
- spinlock_t lock;
+ struct rb_root rb_root;
+ rwlock_t lock;
};
struct simple_xattr {
- struct list_head list;
+ struct rb_node rb_node;
char *name;
size_t size;
char value[];
};
-/*
- * initialize the simple_xattrs structure
- */
-static inline void simple_xattrs_init(struct simple_xattrs *xattrs)
-{
- INIT_LIST_HEAD(&xattrs->head);
- spin_lock_init(&xattrs->lock);
-}
-
-/*
- * free all the xattrs
- */
-static inline void simple_xattrs_free(struct simple_xattrs *xattrs)
-{
- struct simple_xattr *xattr, *node;
-
- list_for_each_entry_safe(xattr, node, &xattrs->head, list) {
- kfree(xattr->name);
- kvfree(xattr);
- }
-}
-
+void simple_xattrs_init(struct simple_xattrs *xattrs);
+void simple_xattrs_free(struct simple_xattrs *xattrs);
struct simple_xattr *simple_xattr_alloc(const void *value, size_t size);
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,
ssize_t *removed_size);
-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);
+ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
+ char *buffer, size_t size);
+void simple_xattr_add(struct simple_xattrs *xattrs,
+ struct simple_xattr *new_xattr);
#endif /* _LINUX_XATTR_H */
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
index e74a93475d21..646c4b48b29d 100644
--- a/include/media/davinci/vpbe.h
+++ b/include/media/davinci/vpbe.h
@@ -28,7 +28,7 @@ struct vpbe_output {
*/
char *subdev_name;
/*
- * defualt_mode identifies the default timings set at the venc or
+ * default_mode identifies the default timings set at the venc or
* external encoder.
*/
char *default_mode;
diff --git a/include/media/dvb_ringbuffer.h b/include/media/dvb_ringbuffer.h
index 8ed6bcc3a56e..029c8b615e49 100644
--- a/include/media/dvb_ringbuffer.h
+++ b/include/media/dvb_ringbuffer.h
@@ -214,7 +214,7 @@ extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
* @buf: Buffer to write.
* @len: Length of buffer (currently limited to 65535 bytes max).
*
- * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
+ * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EINVAL.
*/
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
size_t len);
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index 2f6b0861322a..29d25c8a6f13 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -87,7 +87,11 @@ struct dvb_frontend;
* @device: pointer to struct device
* @module: pointer to struct module
* @mfe_shared: indicates mutually exclusive frontends.
- * Use of this flag is currently deprecated.
+ * 1 = legacy exclusion behavior: blocking any open() call
+ * 2 = enhanced exclusion behavior, emulating the standard
+ * behavior of busy frontends: allowing read-only sharing
+ * and otherwise returning immediately with -EBUSY when any
+ * of the frontends is already opened with write access.
* @mfe_dvbdev: Frontend device in use, in the case of MFE
* @mfe_lock: Lock to prevent using the other frontends when MFE is
* used.
@@ -126,6 +130,7 @@ struct dvb_adapter {
* struct dvb_device - represents a DVB device node
*
* @list_head: List head with all DVB devices
+ * @ref: reference counter
* @fops: pointer to struct file_operations
* @adapter: pointer to the adapter that holds this device node
* @type: type of the device, as defined by &enum dvb_device_type.
@@ -156,6 +161,7 @@ struct dvb_adapter {
*/
struct dvb_device {
struct list_head list_head;
+ struct kref ref;
const struct file_operations *fops;
struct dvb_adapter *adapter;
enum dvb_device_type type;
@@ -188,6 +194,20 @@ struct dvb_device {
};
/**
+ * dvb_device_get - Increase dvb_device reference
+ *
+ * @dvbdev: pointer to struct dvb_device
+ */
+struct dvb_device *dvb_device_get(struct dvb_device *dvbdev);
+
+/**
+ * dvb_device_put - Decrease dvb_device reference
+ *
+ * @dvbdev: pointer to struct dvb_device
+ */
+void dvb_device_put(struct dvb_device *dvbdev);
+
+/**
* dvb_register_adapter - Registers a new DVB adapter
*
* @adap: pointer to struct dvb_adapter
@@ -231,29 +251,17 @@ int dvb_register_device(struct dvb_adapter *adap,
/**
* dvb_remove_device - Remove a registered DVB device
*
- * This does not free memory. To do that, call dvb_free_device().
+ * This does not free memory. dvb_free_device() will do that when
+ * reference counter is empty
*
* @dvbdev: pointer to struct dvb_device
*/
void dvb_remove_device(struct dvb_device *dvbdev);
-/**
- * dvb_free_device - Free memory occupied by a DVB device.
- *
- * Call dvb_unregister_device() before calling this function.
- *
- * @dvbdev: pointer to struct dvb_device
- */
-void dvb_free_device(struct dvb_device *dvbdev);
/**
* dvb_unregister_device - Unregisters a DVB device
*
- * This is a combination of dvb_remove_device() and dvb_free_device().
- * Using this function is usually a mistake, and is often an indicator
- * for a use-after-free bug (when a userspace process keeps a file
- * handle to a detached device).
- *
* @dvbdev: pointer to struct dvb_device
*/
void dvb_unregister_device(struct dvb_device *dvbdev);
diff --git a/include/media/frame_vector.h b/include/media/frame_vector.h
index bfed1710dc24..541c71a2c7be 100644
--- a/include/media/frame_vector.h
+++ b/include/media/frame_vector.h
@@ -16,7 +16,7 @@ struct frame_vector {
struct frame_vector *frame_vector_create(unsigned int nr_frames);
void frame_vector_destroy(struct frame_vector *vec);
int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
- struct frame_vector *vec);
+ bool write, struct frame_vector *vec);
void put_vaddr_frames(struct frame_vector *vec);
int frame_vector_to_pages(struct frame_vector *vec);
void frame_vector_to_pfns(struct frame_vector *vec);
diff --git a/include/media/i2c/ov9650.h b/include/media/i2c/ov9650.h
deleted file mode 100644
index 3ec7e06955b4..000000000000
--- a/include/media/i2c/ov9650.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * OV9650/OV9652 camera sensors driver
- *
- * Copyright (C) 2013 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
- */
-#ifndef OV9650_H_
-#define OV9650_H_
-
-/**
- * struct ov9650_platform_data - ov9650 driver platform data
- * @mclk_frequency: the sensor's master clock frequency in Hz
- * @gpio_pwdn: number of a GPIO connected to OV965X PWDN pin
- * @gpio_reset: number of a GPIO connected to OV965X RESET pin
- *
- * If any of @gpio_pwdn or @gpio_reset are unused then they should be
- * set to a negative value. @mclk_frequency must always be specified.
- */
-struct ov9650_platform_data {
- unsigned long mclk_frequency;
- int gpio_pwdn;
- int gpio_reset;
-};
-#endif /* OV9650_H_ */
diff --git a/include/media/i2c/s5c73m3.h b/include/media/i2c/s5c73m3.h
index a51f1025ba1c..df0769d64523 100644
--- a/include/media/i2c/s5c73m3.h
+++ b/include/media/i2c/s5c73m3.h
@@ -21,20 +21,8 @@
#include <media/v4l2-mediabus.h>
/**
- * struct s5c73m3_gpio - data structure describing a GPIO
- * @gpio: GPIO number
- * @level: indicates active state of the @gpio
- */
-struct s5c73m3_gpio {
- int gpio;
- int level;
-};
-
-/**
* struct s5c73m3_platform_data - s5c73m3 driver platform data
* @mclk_frequency: sensor's master clock frequency in Hz
- * @gpio_reset: GPIO driving RESET pin
- * @gpio_stby: GPIO driving STBY pin
* @bus_type: bus type
* @nlanes: maximum number of MIPI-CSI lanes used
* @horiz_flip: default horizontal image flip value, non zero to enable
@@ -44,9 +32,6 @@ struct s5c73m3_gpio {
struct s5c73m3_platform_data {
unsigned long mclk_frequency;
- struct s5c73m3_gpio gpio_reset;
- struct s5c73m3_gpio gpio_stby;
-
enum v4l2_mbus_type bus_type;
u8 nlanes;
u8 horiz_flip;
diff --git a/include/media/i2c/s5k4ecgx.h b/include/media/i2c/s5k4ecgx.h
deleted file mode 100644
index 92202eb35249..000000000000
--- a/include/media/i2c/s5k4ecgx.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * S5K4ECGX image sensor header file
- *
- * Copyright (C) 2012, Linaro
- * Copyright (C) 2012, Samsung Electronics Co., Ltd.
- */
-
-#ifndef S5K4ECGX_H
-#define S5K4ECGX_H
-
-/**
- * struct s5k4ecgx_gpio - data structure describing a GPIO
- * @gpio: GPIO number
- * @level: indicates active state of the @gpio
- */
-struct s5k4ecgx_gpio {
- int gpio;
- int level;
-};
-
-/**
- * struct s5k4ecgx_platform_data - s5k4ecgx driver platform data
- * @gpio_reset: GPIO driving RESET pin
- * @gpio_stby: GPIO driving STBY pin
- */
-
-struct s5k4ecgx_platform_data {
- struct s5k4ecgx_gpio gpio_reset;
- struct s5k4ecgx_gpio gpio_stby;
-};
-
-#endif /* S5K4ECGX_H */
diff --git a/include/media/i2c/ths7303.h b/include/media/i2c/ths7303.h
index 95492d12786d..fee2818c558d 100644
--- a/include/media/i2c/ths7303.h
+++ b/include/media/i2c/ths7303.h
@@ -10,8 +10,8 @@
* Martin Bugge <marbugge@cisco.com>
*/
-#ifndef THS7353_H
-#define THS7353_H
+#ifndef THS7303_H
+#define THS7303_H
/**
* struct ths7303_platform_data - Platform dependent data
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 28c9de8a1f34..85ed08ddee9d 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -237,7 +237,7 @@ struct media_pad {
* @link_validate: Return whether a link is valid from the entity point of
* view. The media_pipeline_start() function
* validates all links by calling this operation. Optional.
- * @has_pad_interdep: Return whether a two pads inside the entity are
+ * @has_pad_interdep: Return whether two pads of the entity are
* interdependent. If two pads are interdependent they are
* part of the same pipeline and enabling one of the pads
* means that the other pad will become "locked" and
@@ -1144,7 +1144,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
* media_pipeline_stop - Mark a pipeline as not streaming
* @pad: Starting pad
*
- * Mark all pads connected to a given pads through enabled links, either
+ * Mark all pads connected to a given pad through enabled links, either
* directly or indirectly, as not streaming. The media_pad pipe field is
* reset to %NULL.
*
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index f67a74daf799..5bce6e423e94 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -54,17 +54,18 @@
#define V4L2_MBUS_VSYNC_ACTIVE_LOW BIT(5)
#define V4L2_MBUS_PCLK_SAMPLE_RISING BIT(6)
#define V4L2_MBUS_PCLK_SAMPLE_FALLING BIT(7)
-#define V4L2_MBUS_DATA_ACTIVE_HIGH BIT(8)
-#define V4L2_MBUS_DATA_ACTIVE_LOW BIT(9)
+#define V4L2_MBUS_PCLK_SAMPLE_DUALEDGE BIT(8)
+#define V4L2_MBUS_DATA_ACTIVE_HIGH BIT(9)
+#define V4L2_MBUS_DATA_ACTIVE_LOW BIT(10)
/* FIELD = 0/1 - Field1 (odd)/Field2 (even) */
-#define V4L2_MBUS_FIELD_EVEN_HIGH BIT(10)
+#define V4L2_MBUS_FIELD_EVEN_HIGH BIT(11)
/* FIELD = 1/0 - Field1 (odd)/Field2 (even) */
-#define V4L2_MBUS_FIELD_EVEN_LOW BIT(11)
+#define V4L2_MBUS_FIELD_EVEN_LOW BIT(12)
/* Active state of Sync-on-green (SoG) signal, 0/1 for LOW/HIGH respectively. */
-#define V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH BIT(12)
-#define V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW BIT(13)
-#define V4L2_MBUS_DATA_ENABLE_HIGH BIT(14)
-#define V4L2_MBUS_DATA_ENABLE_LOW BIT(15)
+#define V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH BIT(13)
+#define V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW BIT(14)
+#define V4L2_MBUS_DATA_ENABLE_HIGH BIT(15)
+#define V4L2_MBUS_DATA_ENABLE_LOW BIT(16)
/* Serial flags */
/* Clock non-continuous mode support. */
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 2f80c9c818ed..b15fa9930f30 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -176,7 +176,10 @@ struct v4l2_subdev_io_pin_config {
* @s_register: callback for VIDIOC_DBG_S_REGISTER() ioctl handler code.
*
* @s_power: puts subdevice in power saving mode (on == 0) or normal operation
- * mode (on == 1).
+ * mode (on == 1). DEPRECATED. See
+ * Documentation/driver-api/media/camera-sensor.rst . pre_streamon and
+ * post_streamoff callbacks can be used for e.g. setting the bus to LP-11
+ * mode before s_stream is called.
*
* @interrupt_service_routine: Called by the bridge chip's interrupt service
* handler, when an interrupt status has be raised due to this subdev,
@@ -437,8 +440,10 @@ enum v4l2_subdev_pre_streamon_flags {
* @g_input_status: get input status. Same as the status field in the
* &struct v4l2_input
*
- * @s_stream: used to notify the driver that a video stream will start or has
- * stopped.
+ * @s_stream: start (enabled == 1) or stop (enabled == 0) streaming on the
+ * sub-device. Failure on stop will remove any resources acquired in
+ * streaming start, while the error code is still returned by the driver.
+ * Also see call_s_stream wrapper in v4l2-subdev.c.
*
* @g_pixelaspect: callback to return the pixelaspect ratio.
*
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 3253bd2f6fee..4b6a9d2ea372 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -386,6 +386,12 @@ struct vb2_buffer {
* the buffer contents will be ignored anyway.
* @buf_cleanup: called once before the buffer is freed; drivers may
* perform any additional cleanup; optional.
+ * @prepare_streaming: called once to prepare for 'streaming' state; this is
+ * where validation can be done to verify everything is
+ * okay and streaming resources can be claimed. It is
+ * called when the VIDIOC_STREAMON ioctl is called. The
+ * actual streaming starts when @start_streaming is called.
+ * Optional.
* @start_streaming: called once to enter 'streaming' state; the driver may
* receive buffers with @buf_queue callback
* before @start_streaming is called; the driver gets the
@@ -405,6 +411,10 @@ struct vb2_buffer {
* callback by calling vb2_buffer_done() with either
* %VB2_BUF_STATE_DONE or %VB2_BUF_STATE_ERROR; may use
* vb2_wait_for_all_buffers() function
+ * @unprepare_streaming:called as counterpart to @prepare_streaming; any claimed
+ * streaming resources can be released here. It is
+ * called when the VIDIOC_STREAMOFF ioctls is called or
+ * when the streaming filehandle is closed. Optional.
* @buf_queue: passes buffer vb to the driver; driver may start
* hardware operation on this buffer; driver should give
* the buffer back by calling vb2_buffer_done() function;
@@ -432,8 +442,10 @@ struct vb2_ops {
void (*buf_finish)(struct vb2_buffer *vb);
void (*buf_cleanup)(struct vb2_buffer *vb);
+ int (*prepare_streaming)(struct vb2_queue *q);
int (*start_streaming)(struct vb2_queue *q, unsigned int count);
void (*stop_streaming)(struct vb2_queue *q);
+ void (*unprepare_streaming)(struct vb2_queue *q);
void (*buf_queue)(struct vb2_buffer *vb);
@@ -641,8 +653,10 @@ struct vb2_queue {
u32 cnt_queue_setup;
u32 cnt_wait_prepare;
u32 cnt_wait_finish;
+ u32 cnt_prepare_streaming;
u32 cnt_start_streaming;
u32 cnt_stop_streaming;
+ u32 cnt_unprepare_streaming;
#endif
};
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index cd4a46331531..4b5b84f93538 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -34,7 +34,8 @@ struct vb2_vmarea_handler {
extern const struct vm_operations_struct vb2_common_vm_ops;
struct frame_vector *vb2_create_framevec(unsigned long start,
- unsigned long length);
+ unsigned long length,
+ bool write);
void vb2_destroy_framevec(struct frame_vector *vec);
#endif
diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h
index 9c0ad64b8d29..862eff613dc7 100644
--- a/include/memory/renesas-rpc-if.h
+++ b/include/memory/renesas-rpc-if.h
@@ -59,6 +59,7 @@ struct rpcif_op {
enum rpcif_type {
RPCIF_RCAR_GEN3,
+ RPCIF_RCAR_GEN4,
RPCIF_RZ_G2L,
};
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index e004ba04a9ae..684f1cd28730 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -228,6 +228,17 @@ enum {
*/
HCI_QUIRK_VALID_LE_STATES,
+ /* When this quirk is set, then erroneous data reporting
+ * is ignored. This is mainly due to the fact that the HCI
+ * Read Default Erroneous Data Reporting command is advertised,
+ * but not supported; these controllers often reply with unknown
+ * command and tend to lock up randomly. Needing a hard reset.
+ *
+ * This quirk can be set before hci_register_dev is called or
+ * during the hdev->setup vendor callback.
+ */
+ HCI_QUIRK_BROKEN_ERR_DATA_REPORTING,
+
/*
* When this quirk is set, then the hci_suspend_notifier is not
* registered. This is intended for devices which drop completely
@@ -1424,7 +1435,6 @@ struct hci_std_codecs_v2 {
} __packed;
struct hci_vnd_codec_v2 {
- __u8 id;
__le16 cid;
__le16 vid;
__u8 transport;
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 3af1e927247d..69174093078f 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -281,7 +281,8 @@ inet_bhash2_addr_any_hashbucket(const struct sock *sk, const struct net *net, in
* sk_v6_rcv_saddr (ipv6) changes after it has been binded. The socket's
* rcv_saddr field should already have been updated when this is called.
*/
-int inet_bhash2_update_saddr(struct inet_bind_hashbucket *prev_saddr, struct sock *sk);
+int inet_bhash2_update_saddr(struct sock *sk, void *saddr, int family);
+void inet_bhash2_reset_saddr(struct sock *sk);
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
struct inet_bind2_bucket *tb2, unsigned short port);
diff --git a/include/net/ip.h b/include/net/ip.h
index 038097c2a152..144bdfbb25af 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -563,7 +563,7 @@ static inline void iph_to_flow_copy_v4addrs(struct flow_keys *flow,
BUILD_BUG_ON(offsetof(typeof(flow->addrs), v4addrs.dst) !=
offsetof(typeof(flow->addrs), v4addrs.src) +
sizeof(flow->addrs.v4addrs.src));
- memcpy(&flow->addrs.v4addrs, &iph->saddr, sizeof(flow->addrs.v4addrs));
+ memcpy(&flow->addrs.v4addrs, &iph->addrs, sizeof(flow->addrs.v4addrs));
flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
}
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 37943ba3a73c..d383c895592a 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -897,7 +897,7 @@ static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) !=
offsetof(typeof(flow->addrs), v6addrs.src) +
sizeof(flow->addrs.v6addrs.src));
- memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs));
+ memcpy(&flow->addrs.v6addrs, &iph->addrs, sizeof(flow->addrs.v6addrs));
flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
}
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 20745cf7ae1a..2f2a6023fb0e 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -83,7 +83,7 @@ struct neigh_parms {
struct rcu_head rcu_head;
int reachable_time;
- int qlen;
+ u32 qlen;
int data[NEIGH_VAR_DATA_MAX];
DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
};
diff --git a/include/net/ping.h b/include/net/ping.h
index e4ff3911cbf5..9233ad3de0ad 100644
--- a/include/net/ping.h
+++ b/include/net/ping.h
@@ -16,9 +16,6 @@
#define PING_HTABLE_SIZE 64
#define PING_HTABLE_MASK (PING_HTABLE_SIZE-1)
-#define ping_portaddr_for_each_entry(__sk, node, list) \
- hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node)
-
/*
* gid_t is either uint or ushort. We want to pass it to
* proc_dointvec_minmax(), so it must not be larger than MAX_INT
diff --git a/include/net/sctp/stream_sched.h b/include/net/sctp/stream_sched.h
index 01a70b27e026..65058faea4db 100644
--- a/include/net/sctp/stream_sched.h
+++ b/include/net/sctp/stream_sched.h
@@ -26,6 +26,8 @@ struct sctp_sched_ops {
int (*init)(struct sctp_stream *stream);
/* Init a stream */
int (*init_sid)(struct sctp_stream *stream, __u16 sid, gfp_t gfp);
+ /* free a stream */
+ void (*free_sid)(struct sctp_stream *stream, __u16 sid);
/* Frees the entire thing */
void (*free)(struct sctp_stream *stream);
diff --git a/include/net/sock.h b/include/net/sock.h
index 5db02546941c..e0517ecc6531 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -323,7 +323,7 @@ struct sk_filter;
* @sk_tskey: counter to disambiguate concurrent tstamp requests
* @sk_zckey: counter to order MSG_ZEROCOPY notifications
* @sk_socket: Identd and reporting IO signals
- * @sk_user_data: RPC layer private data
+ * @sk_user_data: RPC layer private data. Write-protected by @sk_callback_lock.
* @sk_frag: cached page frag
* @sk_peek_off: current peek_offset value
* @sk_send_head: front of stuff to transmit
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
index c03e35fc382c..919ed4137f9a 100644
--- a/include/scsi/scsi_proto.h
+++ b/include/scsi/scsi_proto.h
@@ -205,10 +205,10 @@ enum sam_status {
};
#define STATUS_MASK 0xfe
+
/*
* SENSE KEYS
*/
-
#define NO_SENSE 0x00
#define RECOVERED_ERROR 0x01
#define NOT_READY 0x02
@@ -223,7 +223,7 @@ enum sam_status {
#define ABORTED_COMMAND 0x0b
#define VOLUME_OVERFLOW 0x0d
#define MISCOMPARE 0x0e
-
+#define COMPLETED 0x0f
/*
* DEVICE TYPES
diff --git a/include/soc/amlogic/meson_ddr_pmu.h b/include/soc/amlogic/meson_ddr_pmu.h
new file mode 100644
index 000000000000..4a33e4ab8ada
--- /dev/null
+++ b/include/soc/amlogic/meson_ddr_pmu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __MESON_DDR_PMU_H__
+#define __MESON_DDR_PMU_H__
+
+#define MAX_CHANNEL_NUM 8
+
+enum {
+ ALL_CHAN_COUNTER_ID,
+ CHAN1_COUNTER_ID,
+ CHAN2_COUNTER_ID,
+ CHAN3_COUNTER_ID,
+ CHAN4_COUNTER_ID,
+ CHAN5_COUNTER_ID,
+ CHAN6_COUNTER_ID,
+ CHAN7_COUNTER_ID,
+ CHAN8_COUNTER_ID,
+ COUNTER_MAX_ID,
+};
+
+struct dmc_info;
+
+struct dmc_counter {
+ u64 all_cnt; /* The count of all requests come in/out ddr controller */
+ union {
+ u64 all_req;
+ struct {
+ u64 all_idle_cnt;
+ u64 all_16bit_cnt;
+ };
+ };
+ u64 channel_cnt[MAX_CHANNEL_NUM]; /* To save a DMC bandwidth-monitor channel counter */
+};
+
+struct dmc_hw_info {
+ void (*enable)(struct dmc_info *info);
+ void (*disable)(struct dmc_info *info);
+ /* Bind an axi line to a bandwidth-monitor channel */
+ void (*set_axi_filter)(struct dmc_info *info, int axi_id, int chann);
+ int (*irq_handler)(struct dmc_info *info,
+ struct dmc_counter *counter);
+ void (*get_counters)(struct dmc_info *info,
+ struct dmc_counter *counter);
+
+ int dmc_nr; /* The number of dmc controller */
+ int chann_nr; /* The number of dmc bandwidth monitor channels */
+ struct attribute **fmt_attr;
+ const u64 capability[2];
+};
+
+struct dmc_info {
+ const struct dmc_hw_info *hw_info;
+
+ void __iomem *ddr_reg[4];
+ unsigned long timer_value; /* Timer value in TIMER register */
+ void __iomem *pll_reg;
+ int irq_num; /* irq vector number */
+};
+
+int meson_ddr_pmu_create(struct platform_device *pdev);
+int meson_ddr_pmu_remove(struct platform_device *pdev);
+
+#endif /* __MESON_DDR_PMU_H__ */
diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h
index 6ce3bd22f6c6..5ad7ac2e3a7c 100644
--- a/include/soc/at91/sama7-ddr.h
+++ b/include/soc/at91/sama7-ddr.h
@@ -26,7 +26,10 @@
#define DDR3PHY_PGSR (0x0C) /* DDR3PHY PHY General Status Register */
#define DDR3PHY_PGSR_IDONE (1 << 0) /* Initialization Done */
-#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */
+#define DDR3PHY_ACDLLCR (0x14) /* DDR3PHY AC DLL Control Register */
+#define DDR3PHY_ACDLLCR_DLLSRST (1 << 30) /* DLL Soft Reset */
+
+#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */
#define DDR3PHY_ACIOCR_CSPDD_CS0 (1 << 18) /* CS#[0] Power Down Driver */
#define DDR3PHY_ACIOCR_CKPDD_CK0 (1 << 8) /* CK[0] Power Down Driver */
#define DDR3PHY_ACIORC_ACPDD (1 << 3) /* AC Power Down Driver */
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
index 811ea668c4a1..ab955591cb72 100644
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -136,12 +136,52 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
};
+enum rpi_firmware_clk_id {
+ RPI_FIRMWARE_EMMC_CLK_ID = 1,
+ RPI_FIRMWARE_UART_CLK_ID,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ RPI_FIRMWARE_CORE_CLK_ID,
+ RPI_FIRMWARE_V3D_CLK_ID,
+ RPI_FIRMWARE_H264_CLK_ID,
+ RPI_FIRMWARE_ISP_CLK_ID,
+ RPI_FIRMWARE_SDRAM_CLK_ID,
+ RPI_FIRMWARE_PIXEL_CLK_ID,
+ RPI_FIRMWARE_PWM_CLK_ID,
+ RPI_FIRMWARE_HEVC_CLK_ID,
+ RPI_FIRMWARE_EMMC2_CLK_ID,
+ RPI_FIRMWARE_M2MC_CLK_ID,
+ RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
+ RPI_FIRMWARE_VEC_CLK_ID,
+ RPI_FIRMWARE_NUM_CLK_ID,
+};
+
+/**
+ * struct rpi_firmware_clk_rate_request - Firmware Request for a rate
+ * @id: ID of the clock being queried
+ * @rate: Rate in Hertz. Set by the firmware.
+ *
+ * Used by @RPI_FIRMWARE_GET_CLOCK_RATE, @RPI_FIRMWARE_GET_CLOCK_MEASURED,
+ * @RPI_FIRMWARE_GET_MAX_CLOCK_RATE and @RPI_FIRMWARE_GET_MIN_CLOCK_RATE.
+ */
+struct rpi_firmware_clk_rate_request {
+ __le32 id;
+ __le32 rate;
+} __packed;
+
+#define RPI_FIRMWARE_CLK_RATE_REQUEST(_id) \
+ { \
+ .id = _id, \
+ }
+
#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
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);
void rpi_firmware_put(struct rpi_firmware *fw);
+unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw,
+ unsigned int id);
+struct device_node *rpi_firmware_find_node(void);
struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node);
struct rpi_firmware *devm_rpi_firmware_get(struct device *dev,
struct device_node *firmware_node);
@@ -159,6 +199,18 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw,
}
static inline void rpi_firmware_put(struct rpi_firmware *fw) { }
+
+static inline unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw,
+ unsigned int id)
+{
+ return UINT_MAX;
+}
+
+static inline struct device_node *rpi_firmware_find_node(void)
+{
+ return NULL;
+}
+
static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
{
return NULL;
diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h
index b02e9fe69146..eb5079904cc8 100644
--- a/include/soc/fsl/qe/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -172,14 +172,15 @@ static inline int par_io_data_set(u8 port, u8 pin, u8 val) { return -ENOSYS; }
/*
* Pin multiplexing functions.
*/
+struct device;
struct qe_pin;
#ifdef CONFIG_QE_GPIO
-extern struct qe_pin *qe_pin_request(struct device_node *np, int index);
+extern struct qe_pin *qe_pin_request(struct device *dev, int index);
extern void qe_pin_free(struct qe_pin *qe_pin);
extern void qe_pin_set_gpio(struct qe_pin *qe_pin);
extern void qe_pin_set_dedicated(struct qe_pin *pin);
#else
-static inline struct qe_pin *qe_pin_request(struct device_node *np, int index)
+static inline struct qe_pin *qe_pin_request(struct device *dev, int index)
{
return ERR_PTR(-ENOSYS);
}
diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h
index 72398ff44719..c47cc71a999e 100644
--- a/include/soc/qcom/qcom-spmi-pmic.h
+++ b/include/soc/qcom/qcom-spmi-pmic.h
@@ -26,18 +26,29 @@
#define PM8901_SUBTYPE 0x0f
#define PM8950_SUBTYPE 0x10
#define PMI8950_SUBTYPE 0x11
+#define PMK8001_SUBTYPE 0x12
+#define PMI8996_SUBTYPE 0x13
#define PM8998_SUBTYPE 0x14
#define PMI8998_SUBTYPE 0x15
#define PM8005_SUBTYPE 0x18
-#define PM660L_SUBTYPE 0x1A
-#define PM660_SUBTYPE 0x1B
-#define PM8150_SUBTYPE 0x1E
+#define PM660L_SUBTYPE 0x1a
+#define PM660_SUBTYPE 0x1b
+#define PM8150_SUBTYPE 0x1e
#define PM8150L_SUBTYPE 0x1f
#define PM8150B_SUBTYPE 0x20
#define PMK8002_SUBTYPE 0x21
#define PM8009_SUBTYPE 0x24
+#define PMI632_SUBTYPE 0x25
#define PM8150C_SUBTYPE 0x26
+#define PM6150_SUBTYPE 0x28
#define SMB2351_SUBTYPE 0x29
+#define PM8008_SUBTYPE 0x2c
+#define PM6125_SUBTYPE 0x2d
+#define PM7250B_SUBTYPE 0x2e
+#define PMK8350_SUBTYPE 0x2f
+#define PMR735B_SUBTYPE 0x34
+#define PM6350_SUBTYPE 0x36
+#define PM2250_SUBTYPE 0x37
#define PMI8998_FAB_ID_SMIC 0x11
#define PMI8998_FAB_ID_GF 0x30
diff --git a/include/soc/tegra/bpmp-abi.h b/include/soc/tegra/bpmp-abi.h
index 53171e324d1c..ecefcaec7e66 100644
--- a/include/soc/tegra/bpmp-abi.h
+++ b/include/soc/tegra/bpmp-abi.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved.
*/
#ifndef ABI_BPMP_ABI_H
@@ -74,6 +74,32 @@
/**
* @ingroup MRQ_Format
+ * Request an answer from the peer.
+ * This should be set in mrq_request::flags for all requests targetted
+ * at BPMP. For requests originating in BPMP, this flag is optional except
+ * for messages targeting MCE, for which the field must be set.
+ * When this flag is not set, the remote peer must not send a response
+ * back.
+ */
+#define BPMP_MAIL_DO_ACK (1U << 0U)
+
+/**
+ * @ingroup MRQ_Format
+ * Ring the sender's doorbell when responding. This should be set unless
+ * the sender wants to poll the underlying communications layer directly.
+ *
+ * An optional direction that can be specified in mrq_request::flags.
+ */
+#define BPMP_MAIL_RING_DB (1U << 1U)
+
+/**
+ * @ingroup MRQ_Format
+ * CRC present
+ */
+#define BPMP_MAIL_CRC_PRESENT (1U << 2U)
+
+/**
+ * @ingroup MRQ_Format
* @brief Header for an MRQ message
*
* Provides the MRQ number for the MRQ message: #mrq. The remainder of
@@ -85,12 +111,139 @@ struct mrq_request {
uint32_t mrq;
/**
- * @brief Flags providing follow up directions to the receiver
+ * @brief 32bit word containing a number of fields as follows:
+ *
+ * struct {
+ * uint8_t options:4;
+ * uint8_t xid:4;
+ * uint8_t payload_length;
+ * uint16_t crc16;
+ * };
+ *
+ * **options** directions to the receiver and indicates CRC presence.
+ *
+ * #BPMP_MAIL_DO_ACK and #BPMP_MAIL_RING_DB see documentation of respective options.
+ * #BPMP_MAIL_CRC_PRESENT is supported on T234 and later platforms. It indicates the
+ * crc16, xid and length fields are present when set.
+ * Some platform configurations, especially when targeted to applications requiring
+ * functional safety, mandate this option being set or otherwise will respond with
+ * -BPMP_EBADMSG and ignore the request.
+ *
+ * **xid** is a transaction ID.
+ *
+ * Only used when #BPMP_MAIL_CRC_PRESENT is set.
+ *
+ * **payload_length** of the message expressed in bytes without the size of this header.
+ * See table below for minimum accepted payload lengths for each MRQ.
+ * Note: For DMCE communication, this field expresses the length as a multiple of 4 bytes
+ * rather than bytes.
+ *
+ * Only used when #BPMP_MAIL_CRC_PRESENT is set.
+ *
+ * | MRQ | CMD | minimum payload length
+ * | -------------------- | ------------------------------------ | ------------------------------------------ |
+ * | MRQ_PING | | 4 |
+ * | MRQ_THREADED_PING | | 4 |
+ * | MRQ_RESET | any | 8 |
+ * | MRQ_I2C | | 12 + cmd_i2c_xfer_request.data_size |
+ * | MRQ_CLK | CMD_CLK_GET_RATE | 4 |
+ * | MRQ_CLK | CMD_CLK_SET_RATE | 16 |
+ * | MRQ_CLK | CMD_CLK_ROUND_RATE | 16 |
+ * | MRQ_CLK | CMD_CLK_GET_PARENT | 4 |
+ * | MRQ_CLK | CMD_CLK_SET_PARENT | 8 |
+ * | MRQ_CLK | CMD_CLK_ENABLE | 4 |
+ * | MRQ_CLK | CMD_CLK_DISABLE | 4 |
+ * | MRQ_CLK | CMD_CLK_IS_ENABLED | 4 |
+ * | MRQ_CLK | CMD_CLK_GET_ALL_INFO | 4 |
+ * | MRQ_CLK | CMD_CLK_GET_MAX_CLK_ID | 4 |
+ * | MRQ_CLK | CMD_CLK_GET_FMAX_AT_VMIN | 4 |
+ * | MRQ_QUERY_ABI | | 4 |
+ * | MRQ_PG | CMD_PG_QUERY_ABI | 12 |
+ * | MRQ_PG | CMD_PG_SET_STATE | 12 |
+ * | MRQ_PG | CMD_PG_GET_STATE | 8 |
+ * | MRQ_PG | CMD_PG_GET_NAME | 8 |
+ * | MRQ_PG | CMD_PG_GET_MAX_ID | 8 |
+ * | MRQ_THERMAL | CMD_THERMAL_QUERY_ABI | 8 |
+ * | MRQ_THERMAL | CMD_THERMAL_GET_TEMP | 8 |
+ * | MRQ_THERMAL | CMD_THERMAL_SET_TRIP | 20 |
+ * | MRQ_THERMAL | CMD_THERMAL_GET_NUM_ZONES | 4 |
+ * | MRQ_THERMAL | CMD_THERMAL_GET_THERMTRIP | 8 |
+ * | MRQ_CPU_VHINT | | 8 |
+ * | MRQ_ABI_RATCHET | | 2 |
+ * | MRQ_EMC_DVFS_LATENCY | | 8 |
+ * | MRQ_EMC_DVFS_EMCHUB | | 8 |
+ * | MRQ_EMC_DISP_RFL | | 4 |
+ * | MRQ_BWMGR | CMD_BWMGR_QUERY_ABI | 8 |
+ * | MRQ_BWMGR | CMD_BWMGR_CALC_RATE | 8 + 8 * bwmgr_rate_req.num_iso_clients |
+ * | MRQ_ISO_CLIENT | CMD_ISO_CLIENT_QUERY_ABI | 8 |
+ * | MRQ_ISO_CLIENT | CMD_ISO_CLIENT_CALCULATE_LA | 16 |
+ * | MRQ_ISO_CLIENT | CMD_ISO_CLIENT_SET_LA | 16 |
+ * | MRQ_ISO_CLIENT | CMD_ISO_CLIENT_GET_MAX_BW | 8 |
+ * | MRQ_CPU_NDIV_LIMITS | | 4 |
+ * | MRQ_CPU_AUTO_CC3 | | 4 |
+ * | MRQ_RINGBUF_CONSOLE | CMD_RINGBUF_CONSOLE_QUERY_ABI | 8 |
+ * | MRQ_RINGBUF_CONSOLE | CMD_RINGBUF_CONSOLE_READ | 5 |
+ * | MRQ_RINGBUF_CONSOLE | CMD_RINGBUF_CONSOLE_WRITE | 5 + cmd_ringbuf_console_write_req.len |
+ * | MRQ_RINGBUF_CONSOLE | CMD_RINGBUF_CONSOLE_GET_FIFO | 4 |
+ * | MRQ_STRAP | STRAP_SET | 12 |
+ * | MRQ_UPHY | CMD_UPHY_PCIE_LANE_MARGIN_CONTROL | 24 |
+ * | MRQ_UPHY | CMD_UPHY_PCIE_LANE_MARGIN_STATUS | 4 |
+ * | MRQ_UPHY | CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT | 5 |
+ * | MRQ_UPHY | CMD_UPHY_PCIE_CONTROLLER_STATE | 6 |
+ * | MRQ_UPHY | CMD_UPHY_PCIE_EP_CONTROLLER_PLL_OFF | 5 |
+ * | MRQ_FMON | CMD_FMON_GEAR_CLAMP | 16 |
+ * | MRQ_FMON | CMD_FMON_GEAR_FREE | 4 |
+ * | MRQ_FMON | CMD_FMON_GEAR_GET | 4 |
+ * | MRQ_FMON | CMD_FMON_FAULT_STS_GET | 8 |
+ * | MRQ_EC | CMD_EC_STATUS_EX_GET | 12 |
+ * | MRQ_QUERY_FW_TAG | | 0 |
+ * | MRQ_DEBUG | CMD_DEBUG_OPEN_RO | 4 + length of cmd_debug_fopen_request.name |
+ * | MRQ_DEBUG | CMD_DEBUG_OPEN_WO | 4 + length of cmd_debug_fopen_request.name |
+ * | MRQ_DEBUG | CMD_DEBUG_READ | 8 |
+ * | MRQ_DEBUG | CMD_DEBUG_WRITE | 12 + cmd_debug_fwrite_request.datalen |
+ * | MRQ_DEBUG | CMD_DEBUG_CLOSE | 8 |
+ * | MRQ_TELEMETRY | | 8 |
+ * | MRQ_PWR_LIMIT | CMD_PWR_LIMIT_QUERY_ABI | 8 |
+ * | MRQ_PWR_LIMIT | CMD_PWR_LIMIT_SET | 20 |
+ * | MRQ_PWR_LIMIT | CMD_PWR_LIMIT_GET | 16 |
+ * | MRQ_PWR_LIMIT | CMD_PWR_LIMIT_CURR_CAP | 8 |
+ * | MRQ_GEARS | | 0 |
+ * | MRQ_BWMGR_INT | CMD_BWMGR_INT_QUERY_ABI | 8 |
+ * | MRQ_BWMGR_INT | CMD_BWMGR_INT_CALC_AND_SET | 16 |
+ * | MRQ_BWMGR_INT | CMD_BWMGR_INT_CAP_SET | 8 |
+ * | MRQ_OC_STATUS | | 0 |
+ *
+ * **crc16**
+ *
+ * CRC16 using polynomial x^16 + x^14 + x^12 + x^11 + x^8 + x^5 + x^4 + x^2 + 1
+ * and initialization value 0x4657. The CRC is calculated over all bytes of the message
+ * including this header. However the crc16 field is considered to be set to 0 when
+ * calculating the CRC. Only used when #BPMP_MAIL_CRC_PRESENT is set. If
+ * #BPMP_MAIL_CRC_PRESENT is set and this field does not match the CRC as
+ * calculated by BPMP, -BPMP_EBADMSG will be returned and the request will
+ * be ignored. See code snippet below on how to calculate the CRC.
*
- * | Bit | Description |
- * |-----|--------------------------------------------|
- * | 1 | ring the sender's doorbell when responding |
- * | 0 | should be 1 |
+ * @code
+ * uint16_t calc_crc_digest(uint16_t crc, uint8_t *data, size_t size)
+ * {
+ * for (size_t i = 0; i < size; i++) {
+ * crc ^= data[i] << 8;
+ * for (size_t j = 0; j < 8; j++) {
+ * if ((crc & 0x8000) == 0x8000) {
+ * crc = (crc << 1) ^ 0xAC9A;
+ * } else {
+ * crc = (crc << 1);
+ * }
+ * }
+ * }
+ * return crc;
+ * }
+ *
+ * uint16_t calc_crc(uint8_t *data, size_t size)
+ * {
+ * return calc_crc_digest(0x4657, data, size);
+ * }
+ * @endcode
*/
uint32_t flags;
} BPMP_ABI_PACKED;
@@ -107,7 +260,35 @@ struct mrq_request {
struct mrq_response {
/** @brief Error code for the MRQ request itself */
int32_t err;
- /** @brief Reserved for future use */
+
+ /**
+ * @brief 32bit word containing a number of fields as follows:
+ *
+ * struct {
+ * uint8_t options:4;
+ * uint8_t xid:4;
+ * uint8_t payload_length;
+ * uint16_t crc16;
+ * };
+ *
+ * **options** indicates CRC presence.
+ *
+ * #BPMP_MAIL_CRC_PRESENT is supported on T234 and later platforms and
+ * indicates the crc16 related fields are present when set.
+ *
+ * **xid** is the transaction ID as sent by the requestor.
+ *
+ * **length** of the message expressed in bytes without the size of this header.
+ * Note: For DMCE communication, this field expresses the length as a multiple of 4 bytes
+ * rather than bytes.
+ *
+ * **crc16**
+ *
+ * CRC16 using polynomial x^16 + x^14 + x^12 + x^11 + x^8 + x^5 + x^4 + x^2 + 1
+ * and initialization value 0x4657. The CRC is calculated over all bytes of the message
+ * including this header. However the crc16 field is considered to be set to 0 when
+ * calculating the CRC. Only used when #BPMP_MAIL_CRC_PRESENT is set.
+ */
uint32_t flags;
} BPMP_ABI_PACKED;
@@ -131,24 +312,16 @@ struct mrq_response {
#define MRQ_PING 0U
#define MRQ_QUERY_TAG 1U
-#define MRQ_MODULE_LOAD 4U
-#define MRQ_MODULE_UNLOAD 5U
-#define MRQ_TRACE_MODIFY 7U
-#define MRQ_WRITE_TRACE 8U
#define MRQ_THREADED_PING 9U
-#define MRQ_MODULE_MAIL 11U
#define MRQ_DEBUGFS 19U
#define MRQ_RESET 20U
#define MRQ_I2C 21U
#define MRQ_CLK 22U
#define MRQ_QUERY_ABI 23U
-#define MRQ_PG_READ_STATE 25U
-#define MRQ_PG_UPDATE_STATE 26U
#define MRQ_THERMAL 27U
#define MRQ_CPU_VHINT 28U
#define MRQ_ABI_RATCHET 29U
#define MRQ_EMC_DVFS_LATENCY 31U
-#define MRQ_TRACE_ITER 64U
#define MRQ_RINGBUF_CONSOLE 65U
#define MRQ_PG 66U
#define MRQ_CPU_NDIV_LIMITS 67U
@@ -159,6 +332,40 @@ struct mrq_response {
#define MRQ_FMON 72U
#define MRQ_EC 73U
#define MRQ_DEBUG 75U
+#define MRQ_EMC_DVFS_EMCHUB 76U
+#define MRQ_BWMGR 77U
+#define MRQ_ISO_CLIENT 78U
+#define MRQ_EMC_DISP_RFL 79U
+#define MRQ_TELEMETRY 80U
+#define MRQ_PWR_LIMIT 81U
+#define MRQ_GEARS 82U
+#define MRQ_BWMGR_INT 83U
+#define MRQ_OC_STATUS 84U
+
+/** @cond DEPRECATED */
+#define MRQ_RESERVED_2 2U
+#define MRQ_RESERVED_3 3U
+#define MRQ_RESERVED_4 4U
+#define MRQ_RESERVED_5 5U
+#define MRQ_RESERVED_6 6U
+#define MRQ_RESERVED_7 7U
+#define MRQ_RESERVED_8 8U
+#define MRQ_RESERVED_10 10U
+#define MRQ_RESERVED_11 11U
+#define MRQ_RESERVED_12 12U
+#define MRQ_RESERVED_13 13U
+#define MRQ_RESERVED_14 14U
+#define MRQ_RESERVED_15 15U
+#define MRQ_RESERVED_16 16U
+#define MRQ_RESERVED_17 17U
+#define MRQ_RESERVED_18 18U
+#define MRQ_RESERVED_24 24U
+#define MRQ_RESERVED_25 25U
+#define MRQ_RESERVED_26 26U
+#define MRQ_RESERVED_30 30U
+#define MRQ_RESERVED_64 64U
+#define MRQ_RESERVED_74 74U
+/** @endcond DEPRECATED */
/** @} */
@@ -167,7 +374,7 @@ struct mrq_response {
* @brief Maximum MRQ code to be sent by CPU software to
* BPMP. Subject to change in future
*/
-#define MAX_CPU_MRQ_ID 75U
+#define MAX_CPU_MRQ_ID 84U
/**
* @addtogroup MRQ_Payloads
@@ -183,8 +390,11 @@ struct mrq_response {
* @defgroup ABI_info ABI Info
* @defgroup Powergating Power Gating
* @defgroup Thermal Thermal
+ * @defgroup OC_status OC status
* @defgroup Vhint CPU Voltage hint
* @defgroup EMC EMC
+ * @defgroup BWMGR BWMGR
+ * @defgroup ISO_CLIENT ISO_CLIENT
* @defgroup CPU NDIV Limits
* @defgroup RingbufConsole Ring Buffer Console
* @defgroup Strap Straps
@@ -192,8 +402,11 @@ struct mrq_response {
* @defgroup CC3 Auto-CC3
* @defgroup FMON FMON
* @defgroup EC EC
- * @defgroup Fbvolt_status Fuse Burn Voltage Status
- * @}
+ * @defgroup Telemetry Telemetry
+ * @defgroup Pwrlimit PWR_LIMIT
+ * @defgroup Gears Gears
+ * @defgroup BWMGR_INT Bandwidth Manager Integrated
+ * @} MRQ_Payloads
*/
/**
@@ -304,190 +517,6 @@ struct mrq_query_fw_tag_response {
uint8_t tag[32];
} BPMP_ABI_PACKED;
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_MODULE_LOAD
- * @brief Dynamically load a BPMP code module
- *
- * * Platforms: T210, T210B01, T186
- * @cond (bpmp_t210 || bpmp_t210b01 || bpmp_t186)
- * * Initiators: CCPLEX
- * * Targets: BPMP
- * * Request Payload: @ref mrq_module_load_request
- * * Response Payload: @ref mrq_module_load_response
- *
- * @note This MRQ is disabled on production systems
- *
- */
-
-/**
- * @ingroup Module
- * @brief Request with #MRQ_MODULE_LOAD
- *
- * Used by #MRQ_MODULE_LOAD calls to ask the recipient to dynamically
- * load the code located at #phys_addr and having size #size
- * bytes. #phys_addr is treated as a void pointer.
- *
- * The recipient copies the code from #phys_addr to locally allocated
- * memory prior to responding to this message.
- *
- * @todo document the module header format
- *
- * The sender is responsible for ensuring that the code is mapped in
- * the recipient's address map.
- *
- */
-struct mrq_module_load_request {
- /** @brief Base address of the code to load */
- uint32_t phys_addr;
- /** @brief Size in bytes of code to load */
- uint32_t size;
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup Module
- * @brief Response to #MRQ_MODULE_LOAD
- *
- * @todo document mrq_response::err
- */
-struct mrq_module_load_response {
- /** @brief Handle to the loaded module */
- uint32_t base;
-} BPMP_ABI_PACKED;
-/** @endcond*/
-
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_MODULE_UNLOAD
- * @brief Unload a previously loaded code module
- *
- * * Platforms: T210, T210B01, T186
- * @cond (bpmp_t210 || bpmp_t210b01 || bpmp_t186)
- * * Initiators: CCPLEX
- * * Targets: BPMP
- * * Request Payload: @ref mrq_module_unload_request
- * * Response Payload: N/A
- *
- * @note This MRQ is disabled on production systems
- */
-
-/**
- * @ingroup Module
- * @brief Request with #MRQ_MODULE_UNLOAD
- *
- * Used by #MRQ_MODULE_UNLOAD calls to request that a previously loaded
- * module be unloaded.
- */
-struct mrq_module_unload_request {
- /** @brief Handle of the module to unload */
- uint32_t base;
-} BPMP_ABI_PACKED;
-/** @endcond*/
-
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_TRACE_MODIFY
- * @brief Modify the set of enabled trace events
- *
- * @deprecated
- *
- * * Platforms: All
- * * Initiators: CCPLEX
- * * Targets: BPMP
- * * Request Payload: @ref mrq_trace_modify_request
- * * Response Payload: @ref mrq_trace_modify_response
- *
- * @note This MRQ is disabled on production systems
- */
-
-/**
- * @ingroup Trace
- * @brief Request with #MRQ_TRACE_MODIFY
- *
- * Used by %MRQ_TRACE_MODIFY calls to enable or disable specify trace
- * events. #set takes precedence for any bit set in both #set and
- * #clr.
- */
-struct mrq_trace_modify_request {
- /** @brief Bit mask of trace events to disable */
- uint32_t clr;
- /** @brief Bit mask of trace events to enable */
- uint32_t set;
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup Trace
- * @brief Response to #MRQ_TRACE_MODIFY
- *
- * Sent in repsonse to an #MRQ_TRACE_MODIFY message. #mask reflects the
- * state of which events are enabled after the recipient acted on the
- * message.
- *
- */
-struct mrq_trace_modify_response {
- /** @brief Bit mask of trace event enable states */
- uint32_t mask;
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_WRITE_TRACE
- * @brief Write trace data to a buffer
- *
- * @deprecated
- *
- * * Platforms: All
- * * Initiators: CCPLEX
- * * Targets: BPMP
- * * Request Payload: @ref mrq_write_trace_request
- * * Response Payload: @ref mrq_write_trace_response
- *
- * mrq_response::err depends on the @ref mrq_write_trace_request field
- * values. err is -#BPMP_EINVAL if size is zero or area is NULL or
- * area is in an illegal range. A positive value for err indicates the
- * number of bytes written to area.
- *
- * @note This MRQ is disabled on production systems
- */
-
-/**
- * @ingroup Trace
- * @brief Request with #MRQ_WRITE_TRACE
- *
- * Used by MRQ_WRITE_TRACE calls to ask the recipient to copy trace
- * data from the recipient's local buffer to the output buffer. #area
- * is treated as a byte-aligned pointer in the recipient's address
- * space.
- *
- * The sender is responsible for ensuring that the output
- * buffer is mapped in the recipient's address map. The recipient is
- * responsible for protecting its own code and data from accidental
- * overwrites.
- */
-struct mrq_write_trace_request {
- /** @brief Base address of output buffer */
- uint32_t area;
- /** @brief Size in bytes of the output buffer */
- uint32_t size;
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup Trace
- * @brief Response to #MRQ_WRITE_TRACE
- *
- * Once this response is sent, the respondent will not access the
- * output buffer further.
- */
-struct mrq_write_trace_response {
- /**
- * @brief Flag whether more data remains in local buffer
- *
- * Value is 1 if the entire local trace buffer has been
- * drained to the outputbuffer. Value is 0 otherwise.
- */
- uint32_t eof;
-} BPMP_ABI_PACKED;
-
/** @private */
struct mrq_threaded_ping_request {
uint32_t challenge;
@@ -500,50 +529,6 @@ struct mrq_threaded_ping_response {
/**
* @ingroup MRQ_Codes
- * @def MRQ_MODULE_MAIL
- * @brief Send a message to a loadable module
- *
- * * Platforms: T210, T210B01, T186
- * @cond (bpmp_t210 || bpmp_t210b01 || bpmp_t186)
- * * Initiators: Any
- * * Targets: BPMP
- * * Request Payload: @ref mrq_module_mail_request
- * * Response Payload: @ref mrq_module_mail_response
- *
- * @note This MRQ is disabled on production systems
- */
-
-/**
- * @ingroup Module
- * @brief Request with #MRQ_MODULE_MAIL
- */
-struct mrq_module_mail_request {
- /** @brief Handle to the previously loaded module */
- uint32_t base;
- /** @brief Module-specific mail payload
- *
- * The length of data[ ] is unknown to the BPMP core firmware
- * but it is limited to the size of an IPC message.
- */
- uint8_t data[BPMP_ABI_EMPTY_ARRAY];
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup Module
- * @brief Response to #MRQ_MODULE_MAIL
- */
-struct mrq_module_mail_response {
- /** @brief Module-specific mail payload
- *
- * The length of data[ ] is unknown to the BPMP core firmware
- * but it is limited to the size of an IPC message.
- */
- uint8_t data[BPMP_ABI_EMPTY_ARRAY];
-} BPMP_ABI_PACKED;
-/** @endcond */
-
-/**
- * @ingroup MRQ_Codes
* @def MRQ_DEBUGFS
* @brief Interact with BPMP's debugfs file nodes
*
@@ -686,7 +671,7 @@ struct mrq_debugfs_response {
#define DEBUGFS_S_ISDIR (1 << 9)
#define DEBUGFS_S_IRUSR (1 << 8)
#define DEBUGFS_S_IWUSR (1 << 7)
-/** @} */
+/** @} Debugfs */
/**
* @ingroup MRQ_Codes
@@ -931,7 +916,7 @@ enum mrq_reset_commands {
* @brief Request with MRQ_RESET
*
* Used by the sender of an #MRQ_RESET message to request BPMP to
- * assert or deassert a given reset line.
+ * assert or or deassert a given reset line.
*/
struct mrq_reset_request {
/** @brief Reset action to perform (@ref mrq_reset_commands) */
@@ -970,7 +955,7 @@ struct mrq_reset_response {
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
+/** @} Reset */
/**
* @ingroup MRQ_Codes
@@ -1032,7 +1017,17 @@ struct serial_i2c_request {
* @brief Trigger one or more i2c transactions
*/
struct cmd_i2c_xfer_request {
- /** @brief Valid bus number from @ref bpmp_i2c_ids*/
+ /**
+ * @brief Tegra PWR_I2C bus identifier
+ *
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_t194)
+ * Must be set to 5.
+ * @endcond (bpmp_t234 || bpmp_t239 || bpmp_t194)
+ * @cond bpmp_th500
+ * Must be set to 1.
+ * @endcond bpmp_th500
+ *
+ */
uint32_t bus_id;
/** @brief Count of valid bytes in #data_buf*/
@@ -1084,7 +1079,7 @@ struct mrq_i2c_response {
struct cmd_i2c_xfer_response xfer;
} BPMP_ABI_PACKED;
-/** @} */
+/** @} I2C */
/**
* @ingroup MRQ_Codes
@@ -1109,6 +1104,13 @@ enum {
CMD_CLK_IS_ENABLED = 6,
CMD_CLK_ENABLE = 7,
CMD_CLK_DISABLE = 8,
+/** @cond DEPRECATED */
+ CMD_CLK_PROPERTIES = 9,
+ CMD_CLK_POSSIBLE_PARENTS = 10,
+ CMD_CLK_NUM_POSSIBLE_PARENTS = 11,
+ CMD_CLK_GET_POSSIBLE_PARENT = 12,
+ CMD_CLK_RESET_REFCOUNTS = 13,
+/** @endcond DEPRECATED */
CMD_CLK_GET_ALL_INFO = 14,
CMD_CLK_GET_MAX_CLK_ID = 15,
CMD_CLK_GET_FMAX_AT_VMIN = 16,
@@ -1119,6 +1121,21 @@ enum {
#define BPMP_CLK_HAS_SET_RATE (1U << 1U)
#define BPMP_CLK_IS_ROOT (1U << 2U)
#define BPMP_CLK_IS_VAR_ROOT (1U << 3U)
+/**
+ * @brief Protection against rate and parent changes
+ *
+ * #MRQ_CLK command #CMD_CLK_SET_RATE or #MRQ_CLK command #CMD_CLK_SET_PARENT will return
+ * -#BPMP_EACCES.
+ */
+#define BPMP_CLK_RATE_PARENT_CHANGE_DENIED (1U << 30)
+
+/**
+ * @brief Protection against state changes
+ *
+ * #MRQ_CLK command #CMD_CLK_ENABLE or #MRQ_CLK command #CMD_CLK_DISABLE will return
+ * -#BPMP_EACCES.
+ */
+#define BPMP_CLK_STATE_CHANGE_DENIED (1U << 31)
#define MRQ_CLK_NAME_MAXLEN 40U
#define MRQ_CLK_MAX_PARENTS 16U
@@ -1210,6 +1227,46 @@ struct cmd_clk_disable_response {
BPMP_ABI_EMPTY
} BPMP_ABI_PACKED;
+/** @cond DEPRECATED */
+/** @private */
+struct cmd_clk_properties_request {
+ BPMP_ABI_EMPTY
+} BPMP_ABI_PACKED;
+
+/** @todo flags need to be spelled out here */
+struct cmd_clk_properties_response {
+ uint32_t flags;
+} BPMP_ABI_PACKED;
+
+/** @private */
+struct cmd_clk_possible_parents_request {
+ BPMP_ABI_EMPTY
+} BPMP_ABI_PACKED;
+
+struct cmd_clk_possible_parents_response {
+ uint8_t num_parents;
+ uint8_t reserved[3];
+ uint32_t parent_id[MRQ_CLK_MAX_PARENTS];
+} BPMP_ABI_PACKED;
+
+/** @private */
+struct cmd_clk_num_possible_parents_request {
+ BPMP_ABI_EMPTY
+} BPMP_ABI_PACKED;
+
+struct cmd_clk_num_possible_parents_response {
+ uint8_t num_parents;
+} BPMP_ABI_PACKED;
+
+struct cmd_clk_get_possible_parent_request {
+ uint8_t parent_idx;
+} BPMP_ABI_PACKED;
+
+struct cmd_clk_get_possible_parent_response {
+ uint32_t parent_id;
+} BPMP_ABI_PACKED;
+/** @endcond DEPRECATED */
+
/** @private */
struct cmd_clk_get_all_info_request {
BPMP_ABI_EMPTY
@@ -1241,6 +1298,7 @@ struct cmd_clk_get_fmax_at_vmin_response {
int64_t rate;
} BPMP_ABI_PACKED;
+
/**
* @ingroup Clocks
* @brief Request with #MRQ_CLK
@@ -1267,6 +1325,17 @@ struct cmd_clk_get_fmax_at_vmin_response {
*
*/
+/** @cond DEPRECATED
+ *
+ * Older versions of firmware also supported following sub-commands:
+ * |CMD_CLK_PROPERTIES |- |
+ * |CMD_CLK_POSSIBLE_PARENTS |- |
+ * |CMD_CLK_NUM_POSSIBLE_PARENTS|- |
+ * |CMD_CLK_GET_POSSIBLE_PARENT |clk_get_possible_parent|
+ * |CMD_CLK_RESET_REFCOUNTS |- |
+ *
+ * @endcond DEPRECATED */
+
struct mrq_clk_request {
/** @brief Sub-command and clock id concatenated to 32-bit word.
* - bits[31..24] is the sub-cmd.
@@ -1288,6 +1357,15 @@ struct mrq_clk_request {
struct cmd_clk_disable_request clk_disable;
/** @private */
struct cmd_clk_is_enabled_request clk_is_enabled;
+ /** @cond DEPRECATED */
+ /** @private */
+ struct cmd_clk_properties_request clk_properties;
+ /** @private */
+ struct cmd_clk_possible_parents_request clk_possible_parents;
+ /** @private */
+ struct cmd_clk_num_possible_parents_request clk_num_possible_parents;
+ struct cmd_clk_get_possible_parent_request clk_get_possible_parent;
+ /** @endcond DEPRECATED */
/** @private */
struct cmd_clk_get_all_info_request clk_get_all_info;
/** @private */
@@ -1321,6 +1399,17 @@ struct mrq_clk_request {
*
*/
+/** @cond DEPRECATED
+ *
+ * Older versions of firmware also supported following sub-commands:
+ * |CMD_CLK_PROPERTIES |clk_properties |
+ * |CMD_CLK_POSSIBLE_PARENTS |clk_possible_parents |
+ * |CMD_CLK_NUM_POSSIBLE_PARENTS|clk_num_possible_parents|
+ * |CMD_CLK_GET_POSSIBLE_PARENT |clk_get_possible_parents|
+ * |CMD_CLK_RESET_REFCOUNTS |- |
+ *
+ * @endcond DEPRECATED */
+
struct mrq_clk_response {
union {
struct cmd_clk_get_rate_response clk_get_rate;
@@ -1333,13 +1422,19 @@ struct mrq_clk_response {
/** @private */
struct cmd_clk_disable_response clk_disable;
struct cmd_clk_is_enabled_response clk_is_enabled;
+ /** @cond DEPRECATED */
+ struct cmd_clk_properties_response clk_properties;
+ struct cmd_clk_possible_parents_response clk_possible_parents;
+ struct cmd_clk_num_possible_parents_response clk_num_possible_parents;
+ struct cmd_clk_get_possible_parent_response clk_get_possible_parent;
+ /** @endcond DEPRECATED */
struct cmd_clk_get_all_info_response clk_get_all_info;
struct cmd_clk_get_max_clk_id_response clk_get_max_clk_id;
struct cmd_clk_get_fmax_at_vmin_response clk_get_fmax_at_vmin;
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
+/** @} Clocks */
/**
* @ingroup MRQ_Codes
@@ -1378,107 +1473,20 @@ struct mrq_query_abi_response {
} BPMP_ABI_PACKED;
/**
- * @ingroup MRQ_Codes
- * @def MRQ_PG_READ_STATE
- * @brief Read the power-gating state of a partition
*
- * * Platforms: T186
- * @cond bpmp_t186
- * * Initiators: Any
- * * Targets: BPMP
- * * Request Payload: @ref mrq_pg_read_state_request
- * * Response Payload: @ref mrq_pg_read_state_response
- */
-
-/**
- * @ingroup Powergating
- * @brief Request with #MRQ_PG_READ_STATE
- *
- * Used by MRQ_PG_READ_STATE call to read the current state of a
- * partition.
- */
-struct mrq_pg_read_state_request {
- /** @brief ID of partition */
- uint32_t partition_id;
-} BPMP_ABI_PACKED;
-
-/**
- * @ingroup Powergating
- * @brief Response to MRQ_PG_READ_STATE
- * @todo define possible errors.
- */
-struct mrq_pg_read_state_response {
- /** @brief Read as don't care */
- uint32_t sram_state;
- /** @brief State of power partition
- * * 0 : off
- * * 1 : on
- */
- uint32_t logic_state;
-} BPMP_ABI_PACKED;
-/** @endcond*/
-/** @} */
-
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_PG_UPDATE_STATE
- * @brief Modify the power-gating state of a partition. In contrast to
- * MRQ_PG calls, the operations that change state (on/off) of power
- * partition are reference counted.
- *
- * * Platforms: T186
- * @cond bpmp_t186
- * * Initiators: Any
- * * Targets: BPMP
- * * Request Payload: @ref mrq_pg_update_state_request
- * * Response Payload: N/A
- */
-
-/**
- * @ingroup Powergating
- * @brief Request with mrq_pg_update_state_request
- *
- * Used by #MRQ_PG_UPDATE_STATE call to request BPMP to change the
- * state of a power partition #partition_id.
- */
-struct mrq_pg_update_state_request {
- /** @brief ID of partition */
- uint32_t partition_id;
- /** @brief Secondary control of power partition
- * @details Ignored by many versions of the BPMP
- * firmware. For maximum compatibility, set the value
- * according to @ref logic_state
- * * 0x1: power ON partition (@ref logic_state == 0x3)
- * * 0x3: power OFF partition (@ref logic_state == 0x1)
- */
- uint32_t sram_state;
- /** @brief Controls state of power partition, legal values are
- * * 0x1 : power OFF partition
- * * 0x3 : power ON partition
- */
- uint32_t logic_state;
- /** @brief Change state of clocks of the power partition, legal values
- * * 0x0 : do not change clock state
- * * 0x1 : disable partition clocks (only applicable when
- * @ref logic_state == 0x1)
- * * 0x3 : enable partition clocks (only applicable when
- * @ref logic_state == 0x3)
- */
- uint32_t clock_state;
-} BPMP_ABI_PACKED;
-/** @endcond*/
-
-/**
* @ingroup MRQ_Codes
* @def MRQ_PG
* @brief Control power-gating state of a partition. In contrast to
* MRQ_PG_UPDATE_STATE, operations that change the power partition
* state are NOT reference counted
*
- * @note BPMP-FW forcefully turns off some partitions as part of SC7 entry
- * because their state cannot be adequately restored on exit. Therefore,
- * it is recommended to power off all domains via MRQ_PG prior to SC7 entry.
+ * @cond (bpmp_t194 || bpmp_t186)
+ * @note On T194 and earlier BPMP-FW forcefully turns off some partitions as
+ * part of SC7 entry because their state cannot be adequately restored on exit.
+ * Therefore, it is recommended to power off all domains via MRQ_PG prior to SC7
+ * entry.
* See @ref bpmp_pdomain_ids for further detail.
+ * @endcond (bpmp_t194 || bpmp_t186)
*
* * Platforms: T186, T194
* * Initiators: Any
@@ -1643,7 +1651,7 @@ struct mrq_pg_response {
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
+/** @} Powergating */
/**
* @ingroup MRQ_Codes
@@ -1889,7 +1897,44 @@ union mrq_thermal_bpmp_to_host_response {
struct cmd_thermal_get_thermtrip_response get_thermtrip;
struct cmd_thermal_get_num_zones_response get_num_zones;
} BPMP_ABI_PACKED;
-/** @} */
+
+/** @} Thermal */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_OC_STATUS
+ * @brief Query over current status
+ *
+ * * Platforms: T234
+ * @cond bpmp_t234
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_oc_status_response
+ *
+ * @addtogroup OC_status
+ * @{
+ */
+
+#define OC_STATUS_MAX_SIZE 24U
+
+/*
+ * @brief Response to #MRQ_OC_STATUS
+ *
+ * throt_en: Value for each OC alarm where zero signifies throttle is
+ * disabled, and non-zero throttle is enabled.
+ * event_cnt: Total number of OC events for each OC alarm.
+ *
+ * mrq_response::err is 0 if the operation was successful and
+ * -#BPMP_ENODEV otherwise.
+ */
+struct mrq_oc_status_response {
+ uint8_t throt_en[OC_STATUS_MAX_SIZE];
+ uint32_t event_cnt[OC_STATUS_MAX_SIZE];
+} BPMP_ABI_PACKED;
+
+/** @} OC_status */
+/** @endcond bpmp_t234 */
/**
* @ingroup MRQ_Codes
@@ -1948,8 +1993,9 @@ struct cpu_vhint_data {
/** reserved for future use */
uint16_t reserved[328];
} BPMP_ABI_PACKED;
-/** @endcond */
-/** @} */
+
+/** @} Vhint */
+/** @endcond bpmp_t186 */
/**
* @ingroup MRQ_Codes
@@ -2016,14 +2062,15 @@ struct mrq_abi_ratchet_response {
/** @brief BPMP's ratchet value */
uint16_t ratchet;
};
-/** @} */
+
+/** @} ABI_info */
/**
* @ingroup MRQ_Codes
* @def MRQ_EMC_DVFS_LATENCY
* @brief Query frequency dependent EMC DVFS latency
*
- * * Platforms: T186, T194
+ * * Platforms: T186, T194, T234
* * Initiators: CCPLEX
* * Targets: BPMP
* * Request Payload: N/A
@@ -2053,7 +2100,543 @@ struct mrq_emc_dvfs_latency_response {
struct emc_dvfs_latency pairs[EMC_DVFS_LATENCY_MAX_SIZE];
} BPMP_ABI_PACKED;
-/** @} */
+/** @} EMC */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_EMC_DVFS_EMCHUB
+ * @brief Query EMC HUB frequencies
+ *
+ * * Platforms: T234 onwards
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_th500)
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_emc_dvfs_emchub_response
+ * @addtogroup EMC
+ * @{
+ */
+
+/**
+ * @brief Used by @ref mrq_emc_dvfs_emchub_response
+ */
+struct emc_dvfs_emchub {
+ /** @brief EMC DVFS node frequency in kHz */
+ uint32_t freq;
+ /** @brief EMC HUB frequency in kHz */
+ uint32_t hub_freq;
+} BPMP_ABI_PACKED;
+
+#define EMC_DVFS_EMCHUB_MAX_SIZE EMC_DVFS_LATENCY_MAX_SIZE
+/**
+ * @brief Response to #MRQ_EMC_DVFS_EMCHUB
+ */
+struct mrq_emc_dvfs_emchub_response {
+ /** @brief The number valid entries in #pairs */
+ uint32_t num_pairs;
+ /** @brief EMC DVFS node <frequency, hub frequency> information */
+ struct emc_dvfs_emchub pairs[EMC_DVFS_EMCHUB_MAX_SIZE];
+} BPMP_ABI_PACKED;
+
+/** @} EMC */
+/** @endcond (bpmp_t234 || bpmp_t239 || bpmp_th500) */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_EMC_DISP_RFL
+ * @brief Set EMC display RFL handshake mode of operations
+ *
+ * * Platforms: T234 onwards
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_th500)
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_emc_disp_rfl_request
+ * * Response Payload: N/A
+ *
+ * @addtogroup EMC
+ * @{
+ */
+
+enum mrq_emc_disp_rfl_mode {
+ /** @brief EMC display RFL handshake disabled */
+ EMC_DISP_RFL_MODE_DISABLED = 0,
+ /** @brief EMC display RFL handshake enabled */
+ EMC_DISP_RFL_MODE_ENABLED = 1,
+};
+
+/**
+ * @ingroup EMC
+ * @brief Request with #MRQ_EMC_DISP_RFL
+ *
+ * Used by the sender of an #MRQ_EMC_DISP_RFL message to
+ * request the mode of EMC display RFL handshake.
+ *
+ * mrq_response::err is
+ * * 0: RFL mode is set successfully
+ * * -#BPMP_EINVAL: invalid mode requested
+ * * -#BPMP_ENOSYS: RFL handshake is not supported
+ * * -#BPMP_EACCES: Permission denied
+ * * -#BPMP_ENODEV: if disp rfl mrq is not supported by BPMP-FW
+ */
+struct mrq_emc_disp_rfl_request {
+ /** @brief EMC display RFL mode (@ref mrq_emc_disp_rfl_mode) */
+ uint32_t mode;
+} BPMP_ABI_PACKED;
+
+/** @} EMC */
+/** @endcond (bpmp_t234 || bpmp_t239 || bpmp_th500) */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_BWMGR
+ * @brief bwmgr requests
+ *
+ * * Platforms: T234 onwards
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_th500)
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_bwmgr_request
+ * * Response Payload: @ref mrq_bwmgr_response
+ *
+ * @addtogroup BWMGR
+ *
+ * @{
+ */
+
+enum mrq_bwmgr_cmd {
+ /**
+ * @brief Check whether the BPMP driver supports the specified
+ * request type
+ *
+ * mrq_response::err is 0 if the specified request is
+ * supported and -#BPMP_ENODEV otherwise.
+ */
+ CMD_BWMGR_QUERY_ABI = 0,
+
+ /**
+ * @brief Determine dram rate to satisfy iso/niso bw requests
+ *
+ * mrq_response::err is
+ * * 0: calc_rate succeeded.
+ * * -#BPMP_EINVAL: Invalid request parameters.
+ * * -#BPMP_ENOTSUP: Requested bw is not available.
+ */
+ CMD_BWMGR_CALC_RATE = 1
+};
+
+/*
+ * request data for request type CMD_BWMGR_QUERY_ABI
+ *
+ * type: Request type for which to check existence.
+ */
+struct cmd_bwmgr_query_abi_request {
+ uint32_t type;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Used by @ref cmd_bwmgr_calc_rate_request
+ */
+struct iso_req {
+ /* @brief bwmgr client ID @ref bpmp_bwmgr_ids */
+ uint32_t id;
+ /* @brief bw in kBps requested by client */
+ uint32_t iso_bw;
+} BPMP_ABI_PACKED;
+
+#define MAX_ISO_CLIENTS 13U
+/*
+ * request data for request type CMD_BWMGR_CALC_RATE
+ */
+struct cmd_bwmgr_calc_rate_request {
+ /* @brief total bw in kBps requested by all niso clients */
+ uint32_t sum_niso_bw;
+ /* @brief The number of iso clients */
+ uint32_t num_iso_clients;
+ /* @brief iso_req <id, iso_bw> information */
+ struct iso_req isobw_reqs[MAX_ISO_CLIENTS];
+} BPMP_ABI_PACKED;
+
+/*
+ * response data for request type CMD_BWMGR_CALC_RATE
+ *
+ * iso_rate_min: min dram data clk rate in kHz to satisfy all iso bw reqs
+ * total_rate_min: min dram data clk rate in kHz to satisfy all bw reqs
+ */
+struct cmd_bwmgr_calc_rate_response {
+ uint32_t iso_rate_min;
+ uint32_t total_rate_min;
+} BPMP_ABI_PACKED;
+
+/*
+ * @brief Request with #MRQ_BWMGR
+ *
+ *
+ * |sub-command |payload |
+ * |----------------------------|------------------------------|
+ * |CMD_BWMGR_QUERY_ABI | cmd_bwmgr_query_abi_request |
+ * |CMD_BWMGR_CALC_RATE | cmd_bwmgr_calc_rate_request |
+ *
+ */
+struct mrq_bwmgr_request {
+ uint32_t cmd;
+ union {
+ struct cmd_bwmgr_query_abi_request query_abi;
+ struct cmd_bwmgr_calc_rate_request bwmgr_rate_req;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/*
+ * @brief Response to MRQ_BWMGR
+ *
+ * |sub-command |payload |
+ * |----------------------------|------------------------------|
+ * |CMD_BWMGR_CALC_RATE | cmd_bwmgr_calc_rate_response |
+ */
+struct mrq_bwmgr_response {
+ union {
+ struct cmd_bwmgr_calc_rate_response bwmgr_rate_resp;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/** @} BWMGR */
+/** @endcond (bpmp_t234 || bpmp_t239 || bpmp_th500) */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_BWMGR_INT
+ * @brief bpmp-integrated bwmgr requests
+ *
+ * * Platforms: T234 onwards
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_th500)
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_bwmgr_int_request
+ * * Response Payload: @ref mrq_bwmgr_int_response
+ *
+ * @addtogroup BWMGR_INT
+ * @{
+ */
+
+enum mrq_bwmgr_int_cmd {
+ /**
+ * @brief Check whether the BPMP-FW supports the specified
+ * request type
+ *
+ * mrq_response::err is 0 if the specified request is
+ * supported and -#BPMP_ENODEV otherwise.
+ */
+ CMD_BWMGR_INT_QUERY_ABI = 1,
+
+ /**
+ * @brief Determine and set dram rate to satisfy iso/niso bw request
+ *
+ * mrq_response::err is
+ * * 0: request succeeded.
+ * * -#BPMP_EINVAL: Invalid request parameters.
+ * set_frequency in @ref cmd_bwmgr_int_calc_and_set_response
+ * will not be set.
+ * * -#BPMP_ENOTSUP: Requested bw is not available.
+ * set_frequency in @ref cmd_bwmgr_int_calc_and_set_response
+ * will be current dram-clk rate.
+ */
+ CMD_BWMGR_INT_CALC_AND_SET = 2,
+
+ /**
+ * @brief Set a max DRAM frequency for the bandwidth-manager
+ *
+ * mrq_response::err is
+ * * 0: request succeeded.
+ * * -#BPMP_ENOTSUP: Requested cap frequency is not possible.
+ */
+ CMD_BWMGR_INT_CAP_SET = 3
+};
+
+/*
+ * request structure for request type CMD_BWMGR_QUERY_ABI
+ *
+ * type: Request type for which to check existence.
+ */
+struct cmd_bwmgr_int_query_abi_request {
+ /* @brief request type determined by @ref mrq_bwmgr_int_cmd */
+ uint32_t type;
+} BPMP_ABI_PACKED;
+
+/**
+ * @defgroup bwmgr_int_unit_type BWMGR_INT floor unit-types
+ * @addtogroup bwmgr_int_unit_type
+ * @{
+ */
+/** @brief kilobytes per second unit-type */
+#define BWMGR_INT_UNIT_KBPS 0U
+/** @brief kilohertz unit-type */
+#define BWMGR_INT_UNIT_KHZ 1U
+
+/** @} bwmgr_int_unit_type */
+
+/*
+ * request data for request type CMD_BWMGR_INT_CALC_AND_SET
+ */
+struct cmd_bwmgr_int_calc_and_set_request {
+ /* @brief bwmgr client ID @ref bpmp_bwmgr_ids */
+ uint32_t client_id;
+ /* @brief average niso bw usage in kBps requested by client. */
+ uint32_t niso_bw;
+ /*
+ * @brief average iso bw usage in kBps requested by client.
+ * Value is ignored if client is niso. Determined by client_id.
+ */
+ uint32_t iso_bw;
+ /*
+ * @brief memory clock floor requested by client.
+ * Unit determined by floor_unit.
+ */
+ uint32_t mc_floor;
+ /*
+ * @brief toggle to determine the unit-type of floor value.
+ * See @ref bwmgr_int_unit_type definitions for unit-type mappings.
+ */
+ uint8_t floor_unit;
+} BPMP_ABI_PACKED;
+
+struct cmd_bwmgr_int_cap_set_request {
+ /* @brief requested cap frequency in Hz. */
+ uint64_t rate;
+} BPMP_ABI_PACKED;
+
+/*
+ * response data for request type CMD_BWMGR_CALC_AND_SET
+ */
+struct cmd_bwmgr_int_calc_and_set_response {
+ /* @brief current set memory clock frequency in Hz */
+ uint64_t rate;
+} BPMP_ABI_PACKED;
+
+/*
+ * @brief Request with #MRQ_BWMGR_INT
+ *
+ *
+ * |sub-command |payload |
+ * |----------------------------|-----------------------------------|
+ * |CMD_BWMGR_INT_QUERY_ABI | cmd_bwmgr_int_query_abi_request |
+ * |CMD_BWMGR_INT_CALC_AND_SET | cmd_bwmgr_int_calc_and_set_request|
+ * |CMD_BWMGR_INT_CAP_SET | cmd_bwmgr_int_cap_set_request |
+ *
+ */
+struct mrq_bwmgr_int_request {
+ uint32_t cmd;
+ union {
+ struct cmd_bwmgr_int_query_abi_request query_abi;
+ struct cmd_bwmgr_int_calc_and_set_request bwmgr_calc_set_req;
+ struct cmd_bwmgr_int_cap_set_request bwmgr_cap_set_req;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/*
+ * @brief Response to MRQ_BWMGR_INT
+ *
+ * |sub-command |payload |
+ * |----------------------------|---------------------------------------|
+ * |CMD_BWMGR_INT_CALC_AND_SET | cmd_bwmgr_int_calc_and_set_response |
+ */
+struct mrq_bwmgr_int_response {
+ union {
+ struct cmd_bwmgr_int_calc_and_set_response bwmgr_calc_set_resp;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/** @} BWMGR_INT */
+/** @endcond (bpmp_t234 || bpmp_t239 || bpmp_th500) */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_ISO_CLIENT
+ * @brief ISO client requests
+ *
+ * * Platforms: T234 onwards
+ * @cond (bpmp_t234 || bpmp_t239 || bpmp_th500)
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_iso_client_request
+ * * Response Payload: @ref mrq_iso_client_response
+ *
+ * @addtogroup ISO_CLIENT
+ * @{
+ */
+
+enum mrq_iso_client_cmd {
+ /**
+ * @brief Check whether the BPMP driver supports the specified
+ * request type
+ *
+ * mrq_response::err is 0 if the specified request is
+ * supported and -#BPMP_ENODEV otherwise.
+ */
+ CMD_ISO_CLIENT_QUERY_ABI = 0,
+
+ /*
+ * @brief check for legal LA for the iso client. Without programming
+ * LA MC registers, calculate and ensure that legal LA is possible for
+ * iso bw requested by the ISO client.
+ *
+ * mrq_response::err is
+ * * 0: check la succeeded.
+ * * -#BPMP_EINVAL: Invalid request parameters.
+ * * -#BPMP_EFAULT: Legal LA is not possible for client requested iso_bw
+ */
+ CMD_ISO_CLIENT_CALCULATE_LA = 1,
+
+ /*
+ * @brief set LA for the iso client. Calculate and program the LA/PTSA
+ * MC registers corresponding to the client making bw request
+ *
+ * mrq_response::err is
+ * * 0: set la succeeded.
+ * * -#BPMP_EINVAL: Invalid request parameters.
+ * * -#BPMP_EFAULT: Failed to calculate or program MC registers.
+ */
+ CMD_ISO_CLIENT_SET_LA = 2,
+
+ /*
+ * @brief Get max possible bw for iso client
+ *
+ * mrq_response::err is
+ * * 0: get_max_bw succeeded.
+ * * -#BPMP_EINVAL: Invalid request parameters.
+ */
+ CMD_ISO_CLIENT_GET_MAX_BW = 3
+};
+
+/*
+ * request data for request type CMD_ISO_CLIENT_QUERY_ABI
+ *
+ * type: Request type for which to check existence.
+ */
+struct cmd_iso_client_query_abi_request {
+ uint32_t type;
+} BPMP_ABI_PACKED;
+
+/*
+ * request data for request type CMD_ISO_CLIENT_CALCULATE_LA
+ *
+ * id: client ID in @ref bpmp_bwmgr_ids
+ * bw: bw requested in kBps by client ID.
+ * init_bw_floor: initial dram_bw_floor in kBps passed by client ID.
+ * ISO client will perform mempool allocation and DVFS buffering based
+ * on this dram_bw_floor.
+ */
+struct cmd_iso_client_calculate_la_request {
+ uint32_t id;
+ uint32_t bw;
+ uint32_t init_bw_floor;
+} BPMP_ABI_PACKED;
+
+/*
+ * request data for request type CMD_ISO_CLIENT_SET_LA
+ *
+ * id: client ID in @ref bpmp_bwmgr_ids
+ * bw: bw requested in kBps by client ID.
+ * final_bw_floor: final dram_bw_floor in kBps.
+ * Sometimes the initial dram_bw_floor passed by ISO client may need to be
+ * updated by considering higher dram freq's. This is the final dram_bw_floor
+ * used to calculate and program MC registers.
+ */
+struct cmd_iso_client_set_la_request {
+ uint32_t id;
+ uint32_t bw;
+ uint32_t final_bw_floor;
+} BPMP_ABI_PACKED;
+
+/*
+ * request data for request type CMD_ISO_CLIENT_GET_MAX_BW
+ *
+ * id: client ID in @ref bpmp_bwmgr_ids
+ */
+struct cmd_iso_client_get_max_bw_request {
+ uint32_t id;
+} BPMP_ABI_PACKED;
+
+/*
+ * response data for request type CMD_ISO_CLIENT_CALCULATE_LA
+ *
+ * la_rate_floor: minimum dram_rate_floor in kHz at which a legal la is possible
+ * iso_client_only_rate: Minimum dram freq in kHz required to satisfy this clients
+ * iso bw request, assuming all other iso clients are inactive
+ */
+struct cmd_iso_client_calculate_la_response {
+ uint32_t la_rate_floor;
+ uint32_t iso_client_only_rate;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Used by @ref cmd_iso_client_get_max_bw_response
+ */
+struct iso_max_bw {
+ /* @brief dram frequency in kHz */
+ uint32_t freq;
+ /* @brief max possible iso-bw in kBps */
+ uint32_t iso_bw;
+} BPMP_ABI_PACKED;
+
+#define ISO_MAX_BW_MAX_SIZE 14U
+/*
+ * response data for request type CMD_ISO_CLIENT_GET_MAX_BW
+ */
+struct cmd_iso_client_get_max_bw_response {
+ /* @brief The number valid entries in iso_max_bw pairs */
+ uint32_t num_pairs;
+ /* @brief max ISOBW <dram freq, max bw> information */
+ struct iso_max_bw pairs[ISO_MAX_BW_MAX_SIZE];
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Request with #MRQ_ISO_CLIENT
+ *
+ * Used by the sender of an #MRQ_ISO_CLIENT message.
+ *
+ * |sub-command |payload |
+ * |------------------------------------ |----------------------------------------|
+ * |CMD_ISO_CLIENT_QUERY_ABI |cmd_iso_client_query_abi_request |
+ * |CMD_ISO_CLIENT_CALCULATE_LA |cmd_iso_client_calculate_la_request |
+ * |CMD_ISO_CLIENT_SET_LA |cmd_iso_client_set_la_request |
+ * |CMD_ISO_CLIENT_GET_MAX_BW |cmd_iso_client_get_max_bw_request |
+ *
+ */
+
+struct mrq_iso_client_request {
+ /* Type of request. Values listed in enum mrq_iso_client_cmd */
+ uint32_t cmd;
+ union {
+ struct cmd_iso_client_query_abi_request query_abi;
+ struct cmd_iso_client_calculate_la_request calculate_la_req;
+ struct cmd_iso_client_set_la_request set_la_req;
+ struct cmd_iso_client_get_max_bw_request max_isobw_req;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Response to MRQ_ISO_CLIENT
+ *
+ * Each sub-command supported by @ref mrq_iso_client_request may return
+ * sub-command-specific data. Some do and some do not as indicated in
+ * the following table
+ *
+ * |sub-command |payload |
+ * |---------------------------- |------------------------------------|
+ * |CMD_ISO_CLIENT_CALCULATE_LA |cmd_iso_client_calculate_la_response|
+ * |CMD_ISO_CLIENT_SET_LA |N/A |
+ * |CMD_ISO_CLIENT_GET_MAX_BW |cmd_iso_client_get_max_bw_response |
+ *
+ */
+
+struct mrq_iso_client_response {
+ union {
+ struct cmd_iso_client_calculate_la_response calculate_la_resp;
+ struct cmd_iso_client_get_max_bw_response max_isobw_resp;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/** @} ISO_CLIENT */
+/** @endcond (bpmp_t234 || bpmp_t239 || bpmp_th500) */
/**
* @ingroup MRQ_Codes
@@ -2061,7 +2644,7 @@ struct mrq_emc_dvfs_latency_response {
* @brief CPU freq. limits in ndiv
*
* * Platforms: T194 onwards
- * @cond bpmp_t194
+ * @cond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500)
* * Initiators: CCPLEX
* * Targets: BPMP
* * Request Payload: @ref mrq_cpu_ndiv_limits_request
@@ -2094,15 +2677,15 @@ struct mrq_cpu_ndiv_limits_response {
uint16_t ndiv_min;
} BPMP_ABI_PACKED;
-/** @} */
-/** @endcond */
+/** @} CPU */
+/** @endcond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500) */
/**
* @ingroup MRQ_Codes
* @def MRQ_CPU_AUTO_CC3
* @brief Query CPU cluster auto-CC3 configuration
*
- * * Platforms: T194 onwards
+ * * Platforms: T194
* @cond bpmp_t194
* * Initiators: CCPLEX
* * Targets: BPMP
@@ -2140,40 +2723,8 @@ struct mrq_cpu_auto_cc3_response {
uint32_t auto_cc3_config;
} BPMP_ABI_PACKED;
-/** @} */
-/** @endcond */
-
-/**
- * @ingroup MRQ_Codes
- * @def MRQ_TRACE_ITER
- * @brief Manage the trace iterator
- *
- * @deprecated
- *
- * * Platforms: All
- * * Initiators: CCPLEX
- * * Targets: BPMP
- * * Request Payload: N/A
- * * Response Payload: @ref mrq_trace_iter_request
- * @addtogroup Trace
- * @{
- */
-enum {
- /** @brief (re)start the tracing now. Ignore older events */
- TRACE_ITER_INIT = 0,
- /** @brief Clobber all events in the trace buffer */
- TRACE_ITER_CLEAN = 1
-};
-
-/**
- * @brief Request with #MRQ_TRACE_ITER
- */
-struct mrq_trace_iter_request {
- /** @brief TRACE_ITER_INIT or TRACE_ITER_CLEAN */
- uint32_t cmd;
-} BPMP_ABI_PACKED;
-
-/** @} */
+/** @} CC3 */
+/** @endcond bpmp_t194 */
/**
* @ingroup MRQ_Codes
@@ -2351,7 +2902,8 @@ union mrq_ringbuf_console_bpmp_to_host_response {
struct cmd_ringbuf_console_write_resp write;
struct cmd_ringbuf_console_get_fifo_resp get_fifo;
} BPMP_ABI_PACKED;
-/** @} */
+
+/** @} RingbufConsole */
/**
* @ingroup MRQ_Codes
@@ -2359,7 +2911,7 @@ union mrq_ringbuf_console_bpmp_to_host_response {
* @brief Set a strap value controlled by BPMP
*
* * Platforms: T194 onwards
- * @cond bpmp_t194
+ * @cond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500)
* * Initiators: CCPLEX
* * Targets: BPMP
* * Request Payload: @ref mrq_strap_request
@@ -2390,17 +2942,14 @@ enum mrq_strap_cmd {
struct mrq_strap_request {
/** @brief @ref mrq_strap_cmd */
uint32_t cmd;
- /** @brief Strap ID from @ref Strap_Ids */
+ /** @brief Strap ID from @ref Strap_Identifiers */
uint32_t id;
/** @brief Desired value for strap (if cmd is #STRAP_SET) */
uint32_t value;
} BPMP_ABI_PACKED;
-/**
- * @defgroup Strap_Ids Strap Identifiers
- * @}
- */
-/** @endcond */
+/** @} Strap */
+/** @endcond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500) */
/**
* @ingroup MRQ_Codes
@@ -2408,7 +2957,7 @@ struct mrq_strap_request {
* @brief Perform a UPHY operation
*
* * Platforms: T194 onwards
- * @cond bpmp_t194
+ * @cond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500)
* * Initiators: CCPLEX
* * Targets: BPMP
* * Request Payload: @ref mrq_uphy_request
@@ -2423,6 +2972,9 @@ enum {
CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT = 3,
CMD_UPHY_PCIE_CONTROLLER_STATE = 4,
CMD_UPHY_PCIE_EP_CONTROLLER_PLL_OFF = 5,
+ CMD_UPHY_DISPLAY_PORT_INIT = 6,
+ CMD_UPHY_DISPLAY_PORT_OFF = 7,
+ CMD_UPHY_XUSB_DYN_LANES_RESTORE = 8,
CMD_UPHY_MAX,
};
@@ -2445,28 +2997,41 @@ struct cmd_uphy_margin_status_response {
} BPMP_ABI_PACKED;
struct cmd_uphy_ep_controller_pll_init_request {
- /** @brief EP controller number, valid: 0, 4, 5 */
+ /** @brief EP controller number, T194 valid: 0, 4, 5; T234 valid: 5, 6, 7, 10; T239 valid: 0 */
uint8_t ep_controller;
} BPMP_ABI_PACKED;
struct cmd_uphy_pcie_controller_state_request {
- /** @brief PCIE controller number, valid: 0, 1, 2, 3, 4 */
+ /** @brief PCIE controller number, T194 valid: 0-4; T234 valid: 0-10; T239 valid: 0-3 */
uint8_t pcie_controller;
uint8_t enable;
} BPMP_ABI_PACKED;
struct cmd_uphy_ep_controller_pll_off_request {
- /** @brief EP controller number, valid: 0, 4, 5 */
+ /** @brief EP controller number, T194 valid: 0, 4, 5; T234 valid: 5, 6, 7, 10; T239 valid: 0 */
uint8_t ep_controller;
} BPMP_ABI_PACKED;
+struct cmd_uphy_display_port_init_request {
+ /** @brief DisplayPort link rate, T239 valid: 1620, 2700, 5400, 8100, 2160, 2430, 3240, 4320, 6750 */
+ uint16_t link_rate;
+ /** @brief 1: lane 0; 2: lane 1; 3: lane 0 and 1 */
+ uint16_t lanes_bitmap;
+} BPMP_ABI_PACKED;
+
+struct cmd_uphy_xusb_dyn_lanes_restore_request {
+ /** @brief 1: lane 0; 2: lane 1; 3: lane 0 and 1 */
+ uint16_t lanes_bitmap;
+} BPMP_ABI_PACKED;
+
/**
* @ingroup UPHY
* @brief Request with #MRQ_UPHY
*
- * Used by the sender of an #MRQ_UPHY message to control UPHY Lane RX margining.
- * The uphy_request is split into several sub-commands. Some sub-commands
- * require no additional data. Others have a sub-command specific payload
+ * Used by the sender of an #MRQ_UPHY message to control UPHY.
+ * The uphy_request is split into several sub-commands. CMD_UPHY_PCIE_LANE_MARGIN_STATUS
+ * requires no additional data. Others have a sub-command specific payload. Below table
+ * shows sub-commands with their corresponding payload data.
*
* |sub-command |payload |
* |------------------------------------ |----------------------------------------|
@@ -2475,6 +3040,9 @@ struct cmd_uphy_ep_controller_pll_off_request {
* |CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT |cmd_uphy_ep_controller_pll_init_request |
* |CMD_UPHY_PCIE_CONTROLLER_STATE |cmd_uphy_pcie_controller_state_request |
* |CMD_UPHY_PCIE_EP_CONTROLLER_PLL_OFF |cmd_uphy_ep_controller_pll_off_request |
+ * |CMD_UPHY_PCIE_DISPLAY_PORT_INIT |cmd_uphy_display_port_init_request |
+ * |CMD_UPHY_PCIE_DISPLAY_PORT_OFF | |
+ * |CMD_UPHY_XUSB_DYN_LANES_RESTORE |cmd_uphy_xusb_dyn_lanes_restore_request |
*
*/
@@ -2489,6 +3057,8 @@ struct mrq_uphy_request {
struct cmd_uphy_ep_controller_pll_init_request ep_ctrlr_pll_init;
struct cmd_uphy_pcie_controller_state_request controller_state;
struct cmd_uphy_ep_controller_pll_off_request ep_ctrlr_pll_off;
+ struct cmd_uphy_display_port_init_request display_port_init;
+ struct cmd_uphy_xusb_dyn_lanes_restore_request xusb_dyn_lanes_restore;
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
@@ -2513,8 +3083,8 @@ struct mrq_uphy_response {
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
-/** @endcond */
+/** @} UPHY */
+/** @endcond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500) */
/**
* @ingroup MRQ_Codes
@@ -2522,14 +3092,16 @@ struct mrq_uphy_response {
* @brief Perform a frequency monitor configuration operations
*
* * Platforms: T194 onwards
- * @cond bpmp_t194
+ * @cond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500)
* * Initiators: CCPLEX
* * Targets: BPMP
* * Request Payload: @ref mrq_fmon_request
* * Response Payload: @ref mrq_fmon_response
+ * @endcond (bpmp_t194 || bpmp_t234 || bpmp_t239 || bpmp_th500)
*
* @addtogroup FMON
* @{
+ * @cond (bpmp_t194 || bpmp_t234)
*/
enum {
/**
@@ -2538,6 +3110,20 @@ enum {
* The monitored clock must be running for clamp to succeed. If
* clamped, FMON configuration is preserved when clock rate
* and/or state is changed.
+ *
+ * mrq_response::err is 0 if the operation was successful, or @n
+ * -#BPMP_EACCES: FMON access error @n
+ * -#BPMP_EBADCMD if subcommand is not supported @n
+ * -#BPMP_EBADSLT: clamp FMON on cluster with auto-CC3 enabled @n
+ * -#BPMP_EBUSY: fmon is already clamped at different rate @n
+ * -#BPMP_EFAULT: self-diagnostic error @n
+ * -#BPMP_EINVAL: invalid FMON configuration @n
+ * -#BPMP_EOPNOTSUPP: not in production mode @n
+ * -#BPMP_ENODEV: invalid clk_id @n
+ * -#BPMP_ENOENT: no calibration data, uninitialized @n
+ * -#BPMP_ENOTSUP: avfs config not set @n
+ * -#BPMP_ENOSYS: clamp FMON on cluster clock w/ no NAFLL @n
+ * -#BPMP_ETIMEDOUT: operation timed out @n
*/
CMD_FMON_GEAR_CLAMP = 1,
/**
@@ -2545,6 +3131,13 @@ enum {
*
* Allow FMON configuration to follow monitored clock rate
* and/or state changes.
+ *
+ * mrq_response::err is 0 if the operation was successful, or @n
+ * -#BPMP_EBADCMD if subcommand is not supported @n
+ * -#BPMP_ENODEV: invalid clk_id @n
+ * -#BPMP_ENOENT: no calibration data, uninitialized @n
+ * -#BPMP_ENOTSUP: avfs config not set @n
+ * -#BPMP_EOPNOTSUPP: not in production mode @n
*/
CMD_FMON_GEAR_FREE = 2,
/**
@@ -2553,11 +3146,54 @@ enum {
*
* Inherently racy, since clamp state can be changed
* concurrently. Useful for testing.
+ *
+ * mrq_response::err is 0 if the operation was successful, or @n
+ * -#BPMP_EBADCMD if subcommand is not supported @n
+ * -#BPMP_ENODEV: invalid clk_id @n
+ * -#BPMP_ENOENT: no calibration data, uninitialized @n
+ * -#BPMP_ENOTSUP: avfs config not set @n
+ * -#BPMP_EOPNOTSUPP: not in production mode @n
*/
CMD_FMON_GEAR_GET = 3,
- CMD_FMON_NUM,
+ /**
+ * @brief Return current status of FMON faults detected by FMON
+ * h/w or s/w since last invocation of this command.
+ * Clears fault status.
+ *
+ * mrq_response::err is 0 if the operation was successful, or @n
+ * -#BPMP_EBADCMD if subcommand is not supported @n
+ * -#BPMP_EINVAL: invalid fault type @n
+ * -#BPMP_ENODEV: invalid clk_id @n
+ * -#BPMP_ENOENT: no calibration data, uninitialized @n
+ * -#BPMP_ENOTSUP: avfs config not set @n
+ * -#BPMP_EOPNOTSUPP: not in production mode @n
+ */
+ CMD_FMON_FAULT_STS_GET = 4,
};
+/**
+ * @cond DEPRECATED
+ * Kept for backward compatibility
+ */
+#define CMD_FMON_NUM 4
+
+/** @endcond DEPRECATED */
+
+/**
+ * @defgroup fmon_fault_type FMON fault type
+ * @addtogroup fmon_fault_type
+ * @{
+ */
+/** @brief All detected FMON faults (h/w or s/w) */
+#define FMON_FAULT_TYPE_ALL 0U
+/** @brief FMON faults detected by h/w */
+#define FMON_FAULT_TYPE_HW 1U
+/** @brief FMON faults detected by s/w */
+#define FMON_FAULT_TYPE_SW 2U
+
+/** @} fmon_fault_type */
+
+
struct cmd_fmon_gear_clamp_request {
int32_t unused;
int64_t rate;
@@ -2587,6 +3223,14 @@ struct cmd_fmon_gear_get_response {
int64_t rate;
} BPMP_ABI_PACKED;
+struct cmd_fmon_fault_sts_get_request {
+ uint32_t fault_type; /**< @ref fmon_fault_type */
+} BPMP_ABI_PACKED;
+
+struct cmd_fmon_fault_sts_get_response {
+ uint32_t fault_sts;
+} BPMP_ABI_PACKED;
+
/**
* @ingroup FMON
* @brief Request with #MRQ_FMON
@@ -2601,9 +3245,9 @@ struct cmd_fmon_gear_get_response {
* |CMD_FMON_GEAR_CLAMP |fmon_gear_clamp |
* |CMD_FMON_GEAR_FREE |- |
* |CMD_FMON_GEAR_GET |- |
+ * |CMD_FMON_FAULT_STS_GET |fmon_fault_sts_get |
*
*/
-
struct mrq_fmon_request {
/** @brief Sub-command and clock id concatenated to 32-bit word.
* - bits[31..24] is the sub-cmd.
@@ -2618,6 +3262,7 @@ struct mrq_fmon_request {
struct cmd_fmon_gear_free_request fmon_gear_free;
/** @private */
struct cmd_fmon_gear_get_request fmon_gear_get;
+ struct cmd_fmon_fault_sts_get_request fmon_fault_sts_get;
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
@@ -2633,6 +3278,7 @@ struct mrq_fmon_request {
* |CMD_FMON_GEAR_CLAMP |- |
* |CMD_FMON_GEAR_FREE |- |
* |CMD_FMON_GEAR_GET |fmon_gear_get |
+ * |CMD_FMON_FAULT_STS_GET |fmon_fault_sts_get |
*
*/
@@ -2643,11 +3289,12 @@ struct mrq_fmon_response {
/** @private */
struct cmd_fmon_gear_free_response fmon_gear_free;
struct cmd_fmon_gear_get_response fmon_gear_get;
+ struct cmd_fmon_fault_sts_get_response fmon_fault_sts_get;
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
-/** @endcond */
+/** @endcond (bpmp_t194 || bpmp_t234) */
+/** @} FMON */
/**
* @ingroup MRQ_Codes
@@ -2655,7 +3302,7 @@ struct mrq_fmon_response {
* @brief Provide status information on faults reported by Error
* Collator (EC) to HSM.
*
- * * Platforms: T194 onwards
+ * * Platforms: T194
* @cond bpmp_t194
* * Initiators: CCPLEX
* * Targets: BPMP
@@ -2664,8 +3311,10 @@ struct mrq_fmon_response {
*
* @note This MRQ ABI is under construction, and subject to change
*
+ * @endcond bpmp_t194
* @addtogroup EC
* @{
+ * @cond bpmp_t194
*/
enum {
/**
@@ -2676,7 +3325,7 @@ enum {
* -#BPMP_ENODEV if target EC is not owned by BPMP @n
* -#BPMP_EACCES if target EC power domain is turned off @n
* -#BPMP_EBADCMD if subcommand is not supported
- * @endcond
+ * @endcond DEPRECATED
*/
CMD_EC_STATUS_GET = 1, /* deprecated */
@@ -2787,7 +3436,8 @@ enum ec_registers_group {
#define EC_STATUS_FLAG_LAST_ERROR 0x0002U
/** @brief EC latent error flag */
#define EC_STATUS_FLAG_LATENT_ERROR 0x0004U
-/** @} */
+
+/** @} bpmp_ec_status_flags */
/**
* @defgroup bpmp_ec_desc_flags EC Descriptor Flags
@@ -2798,7 +3448,8 @@ enum ec_registers_group {
#define EC_DESC_FLAG_RESOLVED 0x0001U
/** @brief EC descriptor failed to retrieve id flag */
#define EC_DESC_FLAG_NO_ID 0x0002U
-/** @} */
+
+/** @} bpmp_ec_desc_flags */
/**
* |error type | fmon_clk_id values |
@@ -2810,14 +3461,18 @@ struct ec_err_fmon_desc {
uint16_t desc_flags;
/** @brief FMON monitored clock id */
uint16_t fmon_clk_id;
- /** @brief Bitmask of @ref bpmp_fmon_faults_flags */
+ /**
+ * @brief Bitmask of fault flags
+ *
+ * @ref bpmp_fmon_faults_flags
+ */
uint32_t fmon_faults;
/** @brief FMON faults access error */
int32_t fmon_access_error;
} BPMP_ABI_PACKED;
/**
- * |error type | vmon_adc_id values |
+ * | error type | vmon_adc_id values |
* |---------------------------------|---------------------------|
* |@ref EC_ERR_TYPE_VOLTAGE_MONITOR |@ref bpmp_adc_ids |
*/
@@ -2826,16 +3481,16 @@ struct ec_err_vmon_desc {
uint16_t desc_flags;
/** @brief VMON rail adc id */
uint16_t vmon_adc_id;
- /** @brief Bitmask of @ref bpmp_vmon_faults_flags */
+ /** @brief Bitmask of bpmp_vmon_faults_flags */
uint32_t vmon_faults;
/** @brief VMON faults access error */
int32_t vmon_access_error;
} BPMP_ABI_PACKED;
/**
- * |error type | reg_id values |
- * |---------------------------------|---------------------------|
- * |@ref EC_ERR_TYPE_REGISTER_PARITY |@ref bpmp_ec_registers_ids |
+ * |error type | reg_id values |
+ * |---------------------------------|-----------------------|
+ * |@ref EC_ERR_TYPE_REGISTER_PARITY | bpmp_ec_registers_ids |
*/
struct ec_err_reg_parity_desc {
/** @brief Bitmask of @ref bpmp_ec_desc_flags */
@@ -2847,10 +3502,10 @@ struct ec_err_reg_parity_desc {
} BPMP_ABI_PACKED;
/**
- * |error type | err_source_id values |
- * |--------------------------------- |--------------------------|
- * |@ref EC_ERR_TYPE_SW_CORRECTABLE | @ref bpmp_ec_ce_swd_ids |
- * |@ref EC_ERR_TYPE_SW_UNCORRECTABLE | @ref bpmp_ec_ue_swd_ids |
+ * |error type | err_source_id values |
+ * |--------------------------------- |----------------------|
+ * |@ref EC_ERR_TYPE_SW_CORRECTABLE | bpmp_ec_ce_swd_ids |
+ * |@ref EC_ERR_TYPE_SW_UNCORRECTABLE | bpmp_ec_ue_swd_ids |
*/
struct ec_err_sw_error_desc {
/** @brief Bitmask of @ref bpmp_ec_desc_flags */
@@ -2862,15 +3517,15 @@ struct ec_err_sw_error_desc {
} BPMP_ABI_PACKED;
/**
- * |error type | err_source_id values |
- * |----------------------------------------|---------------------------|
- * |@ref EC_ERR_TYPE_PARITY_INTERNAL |@ref bpmp_ec_ipath_ids |
- * |@ref EC_ERR_TYPE_ECC_SEC_INTERNAL |@ref bpmp_ec_ipath_ids |
- * |@ref EC_ERR_TYPE_ECC_DED_INTERNAL |@ref bpmp_ec_ipath_ids |
- * |@ref EC_ERR_TYPE_COMPARATOR |@ref bpmp_ec_comparator_ids|
- * |@ref EC_ERR_TYPE_PARITY_SRAM |@ref bpmp_clock_ids |
- * |@ref EC_ERR_TYPE_OTHER_HW_CORRECTABLE |@ref bpmp_ec_misc_hwd_ids |
- * |@ref EC_ERR_TYPE_OTHER_HW_UNCORRECTABLE |@ref bpmp_ec_misc_hwd_ids |
+ * |error type | err_source_id values |
+ * |----------------------------------------|------------------------|
+ * |@ref EC_ERR_TYPE_PARITY_INTERNAL | bpmp_ec_ipath_ids |
+ * |@ref EC_ERR_TYPE_ECC_SEC_INTERNAL | bpmp_ec_ipath_ids |
+ * |@ref EC_ERR_TYPE_ECC_DED_INTERNAL | bpmp_ec_ipath_ids |
+ * |@ref EC_ERR_TYPE_COMPARATOR | bpmp_ec_comparator_ids|
+ * |@ref EC_ERR_TYPE_OTHER_HW_CORRECTABLE | bpmp_ec_misc_hwd_ids |
+ * |@ref EC_ERR_TYPE_OTHER_HW_UNCORRECTABLE | bpmp_ec_misc_hwd_ids |
+ * |@ref EC_ERR_TYPE_PARITY_SRAM | bpmp_clock_ids |
*/
struct ec_err_simple_desc {
/** @brief Bitmask of @ref bpmp_ec_desc_flags */
@@ -2917,7 +3572,7 @@ struct cmd_ec_status_get_response {
/** @brief EC error descriptors */
union ec_err_desc error_descs[EC_ERR_STATUS_DESC_MAX_NUM];
} BPMP_ABI_PACKED;
-/** @endcond */
+/** @endcond DEPRECATED */
struct cmd_ec_status_ex_get_response {
/** @brief Target EC id (the same id received with request). */
@@ -2955,7 +3610,7 @@ struct cmd_ec_status_ex_get_response {
* |sub-command |payload |
* |----------------------------|-----------------------|
* |@ref CMD_EC_STATUS_GET |ec_status_get |
- * @endcond
+ * @endcond DEPRECATED
*
* |sub-command |payload |
* |----------------------------|-----------------------|
@@ -2983,7 +3638,7 @@ struct mrq_ec_request {
* |sub-command |payload |
* |----------------------------|------------------------|
* |@ref CMD_EC_STATUS_GET |ec_status_get |
- * @endcond
+ * @endcond DEPRECATED
*
* |sub-command |payload |
* |----------------------------|------------------------|
@@ -2997,13 +3652,264 @@ struct mrq_ec_response {
* @cond DEPRECATED
*/
struct cmd_ec_status_get_response ec_status_get;
- /** @endcond */
+ /** @endcond DEPRECATED */
struct cmd_ec_status_ex_get_response ec_status_ex_get;
} BPMP_UNION_ANON;
} BPMP_ABI_PACKED;
-/** @} */
-/** @endcond */
+/** @endcond bpmp_t194 */
+/** @} EC */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_TELEMETRY
+ * @brief Get address of memory buffer refreshed with recently sampled
+ * telemetry data
+ *
+ * * Platforms: TH500 onwards
+ * @cond bpmp_th500
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_telemetry_response
+ * @addtogroup Telemetry
+ * @{
+ */
+
+/**
+ * @brief Response to #MRQ_TELEMETRY
+ *
+ * mrq_response::err is
+ * * 0: Telemetry data is available at returned address
+ * * -#BPMP_EACCES: MRQ master is not allowed to request buffer refresh
+ * * -#BPMP_ENAVAIL: Telemetry buffer cannot be refreshed via this MRQ channel
+ * * -#BPMP_ENOTSUP: Telemetry buffer is not supported by BPMP-FW
+ * * -#BPMP_ENODEV: Telemetry mrq is not supported by BPMP-FW
+ */
+struct mrq_telemetry_response {
+ /** @brief Physical address of telemetry data buffer */
+ uint64_t data_buf_addr; /**< see @ref bpmp_telemetry_layout */
+} BPMP_ABI_PACKED;
+
+/** @} Telemetry */
+/** @endcond bpmp_th500 */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_PWR_LIMIT
+ * @brief Control power limits.
+ *
+ * * Platforms: TH500 onwards
+ * @cond bpmp_th500
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_pwr_limit_request
+ * * Response Payload: @ref mrq_pwr_limit_response
+ *
+ * @addtogroup Pwrlimit
+ * @{
+ */
+enum mrq_pwr_limit_cmd {
+ /**
+ * @brief Check whether the BPMP-FW supports the specified
+ * command
+ *
+ * mrq_response::err is 0 if the specified request is
+ * supported and -#BPMP_ENODEV otherwise.
+ */
+ CMD_PWR_LIMIT_QUERY_ABI = 0,
+
+ /**
+ * @brief Set power limit
+ *
+ * mrq_response:err is
+ * * 0: Success
+ * * -#BPMP_ENODEV: Pwr limit mrq is not supported by BPMP-FW
+ * * -#BPMP_ENAVAIL: Invalid request parameters
+ * * -#BPMP_EACCES: Request is not accepted
+ */
+ CMD_PWR_LIMIT_SET = 1,
+
+ /**
+ * @brief Get power limit setting
+ *
+ * mrq_response:err is
+ * * 0: Success
+ * * -#BPMP_ENODEV: Pwr limit mrq is not supported by BPMP-FW
+ * * -#BPMP_ENAVAIL: Invalid request parameters
+ */
+ CMD_PWR_LIMIT_GET = 2,
+
+ /**
+ * @brief Get current power cap
+ *
+ * mrq_response:err is
+ * * 0: Success
+ * * -#BPMP_ENODEV: Pwr limit mrq is not supported by BPMP-FW
+ * * -#BPMP_ENAVAIL: Invalid request parameters
+ */
+ CMD_PWR_LIMIT_CURR_CAP = 3,
+};
+
+/**
+ * @defgroup bpmp_pwr_limit_type PWR_LIMIT TYPEs
+ * @{
+ */
+/** @brief Limit value specifies traget cap */
+#define PWR_LIMIT_TYPE_TARGET_CAP 0U
+/** @brief Limit value specifies maximum possible target cap */
+#define PWR_LIMIT_TYPE_BOUND_MAX 1U
+/** @brief Limit value specifies minimum possible target cap */
+#define PWR_LIMIT_TYPE_BOUND_MIN 2U
+/** @brief Number of limit types supported by mrq interface */
+#define PWR_LIMIT_TYPE_NUM 3U
+
+/** @} bpmp_pwr_limit_type */
+
+/**
+ * @brief Request data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_QUERY_ABI
+ */
+struct cmd_pwr_limit_query_abi_request {
+ uint32_t cmd_code; /**< @ref mrq_pwr_limit_cmd */
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Request data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_SET
+ *
+ * Set specified limit of specified type from specified source. The success of
+ * the request means that specified value is accepted as input to arbitration
+ * with other sources settings for the same limit of the same type. Zero limit
+ * is ignored by the arbitration (i.e., indicates "no limit set").
+ */
+struct cmd_pwr_limit_set_request {
+ uint32_t limit_id; /**< @ref bpmp_pwr_limit_id */
+ uint32_t limit_src; /**< @ref bpmp_pwr_limit_src */
+ uint32_t limit_type; /**< @ref bpmp_pwr_limit_type */
+ uint32_t limit_setting;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Request data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_GET
+ *
+ * Get previously set from specified source specified limit value of specified
+ * type.
+ */
+struct cmd_pwr_limit_get_request {
+ uint32_t limit_id; /**< @ref bpmp_pwr_limit_id */
+ uint32_t limit_src; /**< @ref bpmp_pwr_limit_src */
+ uint32_t limit_type; /**< @ref bpmp_pwr_limit_type */
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Response data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_GET
+ */
+struct cmd_pwr_limit_get_response {
+ uint32_t limit_setting;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Request data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_CURR_CAP
+ *
+ * For specified limit get current power cap aggregated from all sources.
+ */
+struct cmd_pwr_limit_curr_cap_request {
+ uint32_t limit_id; /**< @ref bpmp_pwr_limit_id */
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Response data for #MRQ_PWR_LIMIT command CMD_PWR_LIMIT_CURR_CAP
+ */
+struct cmd_pwr_limit_curr_cap_response {
+ uint32_t curr_cap;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Request with #MRQ_PWR_LIMIT
+ *
+ * |sub-command |payload |
+ * |----------------------------|---------------------------------|
+ * |CMD_PWR_LIMIT_QUERY_ABI | cmd_pwr_limit_query_abi_request |
+ * |CMD_PWR_LIMIT_SET | cmd_pwr_limit_set_request |
+ * |CMD_PWR_LIMIT_GET | cmd_pwr_limit_get_request |
+ * |CMD_PWR_LIMIT_CURR_CAP | cmd_pwr_limit_curr_cap_request |
+ */
+struct mrq_pwr_limit_request {
+ uint32_t cmd;
+ union {
+ struct cmd_pwr_limit_query_abi_request pwr_limit_query_abi_req;
+ struct cmd_pwr_limit_set_request pwr_limit_set_req;
+ struct cmd_pwr_limit_get_request pwr_limit_get_req;
+ struct cmd_pwr_limit_curr_cap_request pwr_limit_curr_cap_req;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/**
+ * @brief Response to MRQ_PWR_LIMIT
+ *
+ * |sub-command |payload |
+ * |----------------------------|---------------------------------|
+ * |CMD_PWR_LIMIT_QUERY_ABI | - |
+ * |CMD_PWR_LIMIT_SET | - |
+ * |CMD_PWR_LIMIT_GET | cmd_pwr_limit_get_response |
+ * |CMD_PWR_LIMIT_CURR_CAP | cmd_pwr_limit_curr_cap_response |
+ */
+struct mrq_pwr_limit_response {
+ union {
+ struct cmd_pwr_limit_get_response pwr_limit_get_rsp;
+ struct cmd_pwr_limit_curr_cap_response pwr_limit_curr_cap_rsp;
+ } BPMP_UNION_ANON;
+} BPMP_ABI_PACKED;
+
+/** @} PwrLimit */
+/** @endcond bpmp_th500 */
+
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_GEARS
+ * @brief Get thresholds for NDIV offset switching
+ *
+ * * Platforms: TH500 onwards
+ * @cond bpmp_th500
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_gears_response
+ * @addtogroup Gears
+ * @{
+ */
+
+/**
+ * @brief Response to #MRQ_GEARS
+ *
+ * Used by the sender of an #MRQ_GEARS message to request thresholds
+ * for NDIV offset switching.
+ *
+ * The mrq_gears_response::ncpu array defines four thresholds in units
+ * of number of online CPUS to be used for choosing between five different
+ * NDIV offset settings for CCPLEX cluster NAFLLs
+ *
+ * 1. If number of online CPUs < ncpu[0] use offset0
+ * 2. If number of online CPUs < ncpu[1] use offset1
+ * 3. If number of online CPUs < ncpu[2] use offset2
+ * 4. If number of online CPUs < ncpu[3] use offset3
+ * 5. If number of online CPUs >= ncpu[3] disable offsetting
+ *
+ * For TH500 mrq_gears_response::ncpu array has four valid entries.
+ *
+ * mrq_response::err is
+ * * 0: gears defined and response data valid
+ * * -#BPMP_ENODEV: MRQ is not supported by BPMP-FW
+ * * -#BPMP_EACCES: Operation not permitted for the MRQ master
+ * * -#BPMP_ENAVAIL: NDIV offsetting is disabled
+ */
+struct mrq_gears_response {
+ /** @brief number of online CPUs for each gear */
+ uint32_t ncpu[16];
+} BPMP_ABI_PACKED;
+
+/** @} Gears */
+/** @endcond bpmp_th500 */
/**
* @addtogroup Error_Codes
@@ -3047,12 +3953,18 @@ struct mrq_ec_response {
#define BPMP_ENOSYS 38
/** @brief Invalid slot */
#define BPMP_EBADSLT 57
+/** @brief Invalid message */
+#define BPMP_EBADMSG 77
+/** @brief Operation not supported */
+#define BPMP_EOPNOTSUPP 95
+/** @brief Targeted resource not available */
+#define BPMP_ENAVAIL 119
/** @brief Not supported */
#define BPMP_ENOTSUP 134
/** @brief No such device or address */
#define BPMP_ENXIO 140
-/** @} */
+/** @} Error_Codes */
#if defined(BPMP_ABI_CHECKS)
#include "bpmp_abi_checks.h"
diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h
index f2604e99af09..5842e38bb288 100644
--- a/include/soc/tegra/bpmp.h
+++ b/include/soc/tegra/bpmp.h
@@ -6,6 +6,7 @@
#ifndef __SOC_TEGRA_BPMP_H
#define __SOC_TEGRA_BPMP_H
+#include <linux/iosys-map.h>
#include <linux/mailbox_client.h>
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
@@ -36,10 +37,22 @@ struct tegra_bpmp_mb_data {
u8 data[MSG_DATA_MIN_SZ];
} __packed;
+#define tegra_bpmp_mb_read(dst, mb, size) \
+ iosys_map_memcpy_from(dst, mb, offsetof(struct tegra_bpmp_mb_data, data), size)
+
+#define tegra_bpmp_mb_write(mb, src, size) \
+ iosys_map_memcpy_to(mb, offsetof(struct tegra_bpmp_mb_data, data), src, size)
+
+#define tegra_bpmp_mb_read_field(mb, field) \
+ iosys_map_rd_field(mb, 0, struct tegra_bpmp_mb_data, field)
+
+#define tegra_bpmp_mb_write_field(mb, field, value) \
+ iosys_map_wr_field(mb, 0, struct tegra_bpmp_mb_data, field, value)
+
struct tegra_bpmp_channel {
struct tegra_bpmp *bpmp;
- struct tegra_bpmp_mb_data *ib;
- struct tegra_bpmp_mb_data *ob;
+ struct iosys_map ib;
+ struct iosys_map ob;
struct completion completion;
struct tegra_ivc *ivc;
unsigned int index;
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h
index 977c334136e9..a63de5da8124 100644
--- a/include/soc/tegra/fuse.h
+++ b/include/soc/tegra/fuse.h
@@ -34,6 +34,20 @@ enum tegra_revision {
TEGRA_REVISION_MAX,
};
+enum tegra_platform {
+ TEGRA_PLATFORM_SILICON = 0,
+ TEGRA_PLATFORM_QT,
+ TEGRA_PLATFORM_SYSTEM_FPGA,
+ TEGRA_PLATFORM_UNIT_FPGA,
+ TEGRA_PLATFORM_ASIM_QT,
+ TEGRA_PLATFORM_ASIM_LINSIM,
+ TEGRA_PLATFORM_DSIM_ASIM_LINSIM,
+ TEGRA_PLATFORM_VERIFICATION_SIMULATION,
+ TEGRA_PLATFORM_VDK,
+ TEGRA_PLATFORM_VSP,
+ TEGRA_PLATFORM_MAX,
+};
+
struct tegra_sku_info {
int sku_id;
int cpu_process_id;
@@ -47,6 +61,7 @@ struct tegra_sku_info {
int gpu_speedo_id;
int gpu_speedo_value;
enum tegra_revision revision;
+ enum tegra_platform platform;
};
#ifdef CONFIG_ARCH_TEGRA
diff --git a/include/soc/tegra/ivc.h b/include/soc/tegra/ivc.h
index 4aeb77cc22c5..be45d5f5adea 100644
--- a/include/soc/tegra/ivc.h
+++ b/include/soc/tegra/ivc.h
@@ -4,9 +4,11 @@
*/
#ifndef __TEGRA_IVC_H
+#define __TEGRA_IVC_H
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/iosys-map.h>
#include <linux/types.h>
struct tegra_ivc_header;
@@ -15,7 +17,7 @@ struct tegra_ivc {
struct device *peer;
struct {
- struct tegra_ivc_header *channel;
+ struct iosys_map map;
unsigned int position;
dma_addr_t phys;
} rx, tx;
@@ -36,7 +38,7 @@ struct tegra_ivc {
*
* Returns a pointer to the frame, or an error encoded pointer.
*/
-void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc);
+int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map);
/**
* tegra_ivc_read_advance - Advance the read queue
@@ -56,7 +58,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc);
*
* Returns a pointer to the frame, or an error encoded pointer.
*/
-void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc);
+int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map);
/**
* tegra_ivc_write_advance - Advance the write queue
@@ -91,8 +93,8 @@ void tegra_ivc_reset(struct tegra_ivc *ivc);
size_t tegra_ivc_align(size_t size);
unsigned tegra_ivc_total_queue_size(unsigned queue_size);
-int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
- dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
+int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, const struct iosys_map *rx,
+ dma_addr_t rx_phys, const struct iosys_map *tx, dma_addr_t tx_phys,
unsigned int num_frames, size_t frame_size,
void (*notify)(struct tegra_ivc *ivc, void *data),
void *data);
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index 47ce6d434427..51a2263e1bc5 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -193,6 +193,8 @@ struct tegra_mc_soc {
unsigned int num_address_bits;
unsigned int atom_size;
+ unsigned int num_carveouts;
+
u16 client_id_mask;
u8 num_channels;
@@ -244,6 +246,8 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
#ifdef CONFIG_TEGRA_MC
struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev);
int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev);
+int tegra_mc_get_carveout_info(struct tegra_mc *mc, unsigned int id,
+ phys_addr_t *base, u64 *size);
#else
static inline struct tegra_mc *
devm_tegra_memory_controller_get(struct device *dev)
@@ -256,6 +260,13 @@ tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
{
return -ENODEV;
}
+
+static inline int
+tegra_mc_get_carveout_info(struct tegra_mc *mc, unsigned int id,
+ phys_addr_t *base, u64 *size)
+{
+ return -ENODEV;
+}
#endif
#endif /* __SOC_TEGRA_MC_H__ */
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index d186bccd125d..aadb845d281d 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -118,9 +118,9 @@ enum tegra_io_pad {
TEGRA_IO_PAD_PEX_CLK_2,
TEGRA_IO_PAD_PEX_CNTRL,
TEGRA_IO_PAD_PEX_CTL2,
- TEGRA_IO_PAD_PEX_L0_RST_N,
- TEGRA_IO_PAD_PEX_L1_RST_N,
- TEGRA_IO_PAD_PEX_L5_RST_N,
+ TEGRA_IO_PAD_PEX_L0_RST,
+ TEGRA_IO_PAD_PEX_L1_RST,
+ TEGRA_IO_PAD_PEX_L5_RST,
TEGRA_IO_PAD_PWR_CTL,
TEGRA_IO_PAD_SDMMC1,
TEGRA_IO_PAD_SDMMC1_HV,
diff --git a/include/sound/acp62_chip_offset_byte.h b/include/sound/acp63_chip_offset_byte.h
index f03992f81168..c9260e1640ae 100644
--- a/include/sound/acp62_chip_offset_byte.h
+++ b/include/sound/acp63_chip_offset_byte.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * AMD ACP 6.2 Register Documentation
+ * AMD ACP 6.3 Register Documentation
*
* Copyright 2022 Advanced Micro Devices, Inc.
*/
@@ -131,6 +131,23 @@
#define ACP_I2S_WAKE_EN 0x000145C
#define ACP_SW1_WAKE_EN 0x0001460
+#define ACP_SW_I2S_ERROR_REASON 0x00018B4
+#define ACP_SW_POS_TRACK_I2S_TX_CTRL 0x00018B8
+#define ACP_SW_I2S_TX_DMA_POS 0x00018BC
+#define ACP_SW_POS_TRACK_BT_TX_CTRL 0x00018C0
+#define ACP_SW_BT_TX_DMA_POS 0x00018C4
+#define ACP_SW_POS_TRACK_HS_TX_CTRL 0x00018C8
+#define ACP_SW_HS_TX_DMA_POS 0x00018CC
+#define ACP_SW_POS_TRACK_I2S_RX_CTRL 0x00018D0
+#define ACP_SW_I2S_RX_DMA_POS 0x00018D4
+#define ACP_SW_POS_TRACK_BT_RX_CTRL 0x00018D8
+#define ACP_SW_BT_RX_DMA_POS 0x00018DC
+#define ACP_SW_POS_TRACK_HS_RX_CTRL 0x00018E0
+#define ACP_SW_HS_RX_DMA_POS 0x00018E4
+#define ACP_ERROR_INTR_MASK1 0X0001974
+#define ACP_ERROR_INTR_MASK2 0X0001978
+#define ACP_ERROR_INTR_MASK3 0X000197C
+
/* Registers from ACP_P1_MISC block */
#define ACP_EXTERNAL_INTR_ENB 0x0001A00
#define ACP_EXTERNAL_INTR_CNTL 0x0001A04
@@ -154,6 +171,8 @@
#define ACP_P1_SW_BT_RX_DMA_POS 0x0001A9C
#define ACP_P1_SW_POS_TRACK_HS_RX_CTRL 0x0001AA0
#define ACP_P1_SW_HS_RX_DMA_POS 0x0001AA4
+#define ACP_ERROR_INTR_MASK4 0X0001AEC
+#define ACP_ERROR_INTR_MASK5 0X0001AF0
/* Registers from ACP_AUDIO_BUFFERS block */
#define ACP_I2S_RX_RINGBUFADDR 0x0002000
@@ -210,6 +229,24 @@
#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x00020CC
#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x00020D0
#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x00020D4
+#define ACP_AUDIO_RX_RINGBUFADDR ACP_I2S_RX_RINGBUFADDR
+#define ACP_AUDIO_RX_RINGBUFSIZE ACP_I2S_RX_RINGBUFSIZE
+#define ACP_AUDIO_RX_LINKPOSITIONCNTR ACP_I2S_RX_LINKPOSITIONCNTR
+#define ACP_AUDIO_RX_FIFOADDR ACP_I2S_RX_FIFOADDR
+#define ACP_AUDIO_RX_FIFOSIZE ACP_I2S_RX_FIFOSIZE
+#define ACP_AUDIO_RX_DMA_SIZE ACP_I2S_RX_DMA_SIZE
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_HIGH ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_LOW ACP_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_RX_INTR_WATERMARK_SIZE ACP_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_AUDIO_TX_RINGBUFADDR ACP_I2S_TX_RINGBUFADDR
+#define ACP_AUDIO_TX_RINGBUFSIZE ACP_I2S_TX_RINGBUFSIZE
+#define ACP_AUDIO_TX_LINKPOSITIONCNTR ACP_I2S_TX_LINKPOSITIONCNTR
+#define ACP_AUDIO_TX_FIFOADDR ACP_I2S_TX_FIFOADDR
+#define ACP_AUDIO_TX_FIFOSIZE ACP_I2S_TX_FIFOSIZE
+#define ACP_AUDIO_TX_DMA_SIZE ACP_I2S_TX_DMA_SIZE
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_HIGH ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_LOW ACP_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_TX_INTR_WATERMARK_SIZE ACP_I2S_TX_INTR_WATERMARK_SIZE
/* Registers from ACP_I2S_TDM block */
#define ACP_I2STDM_IER 0x0002400
@@ -255,6 +292,102 @@
#define ACP_WOV_ERROR_STATUS_REGISTER 0x0002C68
#define ACP_PDM_CLKDIV 0x0002C6C
+/* Registers from ACP_SW_SWCLK block */
+#define ACP_SW_EN 0x0003000
+#define ACP_SW_EN_STATUS 0x0003004
+#define ACP_SW_FRAMESIZE 0x0003008
+#define ACP_SW_SSP_COUNTER 0x000300C
+#define ACP_SW_AUDIO_TX_EN 0x0003010
+#define ACP_SW_AUDIO_TX_EN_STATUS 0x0003014
+#define ACP_SW_AUDIO_TX_FRAME_FORMAT 0x0003018
+#define ACP_SW_AUDIO_TX_SAMPLEINTERVAL 0x000301C
+#define ACP_SW_AUDIO_TX_HCTRL_DP0 0x0003020
+#define ACP_SW_AUDIO_TX_HCTRL_DP1 0x0003024
+#define ACP_SW_AUDIO_TX_HCTRL_DP2 0x0003028
+#define ACP_SW_AUDIO_TX_HCTRL_DP3 0x000302C
+#define ACP_SW_AUDIO_TX_OFFSET_DP0 0x0003030
+#define ACP_SW_AUDIO_TX_OFFSET_DP1 0x0003034
+#define ACP_SW_AUDIO_TX_OFFSET_DP2 0x0003038
+#define ACP_SW_AUDIO_TX_OFFSET_DP3 0x000303C
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP0 0x0003040
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP1 0x0003044
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP2 0x0003048
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP3 0x000304C
+#define ACP_SW_BT_TX_EN 0x0003050
+#define ACP_SW_BT_TX_EN_STATUS 0x0003054
+#define ACP_SW_BT_TX_FRAME_FORMAT 0x0003058
+#define ACP_SW_BT_TX_SAMPLEINTERVAL 0x000305C
+#define ACP_SW_BT_TX_HCTRL 0x0003060
+#define ACP_SW_BT_TX_OFFSET 0x0003064
+#define ACP_SW_BT_TX_CHANNEL_ENABLE_DP0 0x0003068
+#define ACP_SW_HEADSET_TX_EN 0x000306C
+#define ACP_SW_HEADSET_TX_EN_STATUS 0x0003070
+#define ACP_SW_HEADSET_TX_FRAME_FORMAT 0x0003074
+#define ACP_SW_HEADSET_TX_SAMPLEINTERVAL 0x0003078
+#define ACP_SW_HEADSET_TX_HCTRL 0x000307C
+#define ACP_SW_HEADSET_TX_OFFSET 0x0003080
+#define ACP_SW_HEADSET_TX_CHANNEL_ENABLE_DP0 0x0003084
+#define ACP_SW_AUDIO_RX_EN 0x0003088
+#define ACP_SW_AUDIO_RX_EN_STATUS 0x000308C
+#define ACP_SW_AUDIO_RX_FRAME_FORMAT 0x0003090
+#define ACP_SW_AUDIO_RX_SAMPLEINTERVAL 0x0003094
+#define ACP_SW_AUDIO_RX_HCTRL_DP0 0x0003098
+#define ACP_SW_AUDIO_RX_HCTRL_DP1 0x000309C
+#define ACP_SW_AUDIO_RX_HCTRL_DP2 0x0003100
+#define ACP_SW_AUDIO_RX_HCTRL_DP3 0x0003104
+#define ACP_SW_AUDIO_RX_OFFSET_DP0 0x0003108
+#define ACP_SW_AUDIO_RX_OFFSET_DP1 0x000310C
+#define ACP_SW_AUDIO_RX_OFFSET_DP2 0x0003110
+#define ACP_SW_AUDIO_RX_OFFSET_DP3 0x0003114
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP0 0x0003118
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP1 0x000311C
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP2 0x0003120
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP3 0x0003124
+#define ACP_SW_BT_RX_EN 0x0003128
+#define ACP_SW_BT_RX_EN_STATUS 0x000312C
+#define ACP_SW_BT_RX_FRAME_FORMAT 0x0003130
+#define ACP_SW_BT_RX_SAMPLEINTERVAL 0x0003134
+#define ACP_SW_BT_RX_HCTRL 0x0003138
+#define ACP_SW_BT_RX_OFFSET 0x000313C
+#define ACP_SW_BT_RX_CHANNEL_ENABLE_DP0 0x0003140
+#define ACP_SW_HEADSET_RX_EN 0x0003144
+#define ACP_SW_HEADSET_RX_EN_STATUS 0x0003148
+#define ACP_SW_HEADSET_RX_FRAME_FORMAT 0x000314C
+#define ACP_SW_HEADSET_RX_SAMPLEINTERVAL 0x0003150
+#define ACP_SW_HEADSET_RX_HCTRL 0x0003154
+#define ACP_SW_HEADSET_RX_OFFSET 0x0003158
+#define ACP_SW_HEADSET_RX_CHANNEL_ENABLE_DP0 0x000315C
+#define ACP_SW_BPT_PORT_EN 0x0003160
+#define ACP_SW_BPT_PORT_EN_STATUS 0x0003164
+#define ACP_SW_BPT_PORT_FRAME_FORMAT 0x0003168
+#define ACP_SW_BPT_PORT_SAMPLEINTERVAL 0x000316C
+#define ACP_SW_BPT_PORT_HCTRL 0x0003170
+#define ACP_SW_BPT_PORT_OFFSET 0x0003174
+#define ACP_SW_BPT_PORT_CHANNEL_ENABLE 0x0003178
+#define ACP_SW_BPT_PORT_FIRST_BYTE_ADDR 0x000317C
+#define ACP_SW_CLK_RESUME_CTRL 0x0003180
+#define ACP_SW_CLK_RESUME_DELAY_CNTR 0x0003184
+#define ACP_SW_BUS_RESET_CTRL 0x0003188
+#define ACP_SW_PRBS_ERR_STATUS 0x000318C
+#define SW_IMM_CMD_UPPER_WORD 0x0003230
+#define SW_IMM_CMD_LOWER_QWORD 0x0003234
+#define SW_IMM_RESP_UPPER_WORD 0x0003238
+#define SW_IMM_RESP_LOWER_QWORD 0x000323C
+#define SW_IMM_CMD_STS 0x0003240
+#define SW_BRA_BASE_ADDRESS 0x0003244
+#define SW_BRA_TRANSFER_SIZE 0x0003248
+#define SW_BRA_DMA_BUSY 0x000324C
+#define SW_BRA_RESP 0x0003250
+#define SW_BRA_RESP_FRAME_ADDR 0x0003254
+#define SW_BRA_CURRENT_TRANSFER_SIZE 0x0003258
+#define SW_STATE_CHANGE_STATUS_0TO7 0x000325C
+#define SW_STATE_CHANGE_STATUS_8TO11 0x0003260
+#define SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003264
+#define SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003268
+#define SW_CLK_FREQUENCY_CTRL 0x000326C
+#define SW_ERROR_INTR_MASK 0x0003270
+#define SW_PHY_TEST_MODE_DATA_OFF 0x0003274
+
/* Registers from ACP_P1_AUDIO_BUFFERS block */
#define ACP_P1_I2S_RX_RINGBUFADDR 0x0003A00
#define ACP_P1_I2S_RX_RINGBUFSIZE 0x0003A04
@@ -310,6 +443,87 @@
#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_HIGH 0x0003ACC
#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_LOW 0x0003AD0
#define ACP_P1_HS_TX_INTR_WATERMARK_SIZE 0x0003AD4
+#define ACP_P1_AUDIO_RX_RINGBUFADDR ACP_P1_I2S_RX_RINGBUFADDR
+#define ACP_P1_AUDIO_RX_RINGBUFSIZE ACP_P1_I2S_RX_RINGBUFSIZE
+#define ACP_P1_AUDIO_RX_LINKPOSITIONCNTR ACP_P1_I2S_RX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_RX_FIFOADDR ACP_P1_I2S_RX_FIFOADDR
+#define ACP_P1_AUDIO_RX_FIFOSIZE ACP_P1_I2S_RX_FIFOSIZE
+#define ACP_P1_AUDIO_RX_DMA_SIZE ACP_P1_I2S_RX_DMA_SIZE
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_HIGH ACP_P1_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_LOW ACP_P1_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_RX_INTR_WATERMARK_SIZE ACP_P1_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_P1_AUDIO_TX_RINGBUFADDR ACP_P1_I2S_TX_RINGBUFADDR
+#define ACP_P1_AUDIO_TX_RINGBUFSIZE ACP_P1_I2S_TX_RINGBUFSIZE
+#define ACP_P1_AUDIO_TX_LINKPOSITIONCNTR ACP_P1_I2S_TX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_TX_FIFOADDR ACP_P1_I2S_TX_FIFOADDR
+#define ACP_P1_AUDIO_TX_FIFOSIZE ACP_P1_I2S_TX_FIFOSIZE
+#define ACP_P1_AUDIO_TX_DMA_SIZE ACP_P1_I2S_TX_DMA_SIZE
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_HIGH ACP_P1_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_LOW ACP_P1_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_TX_INTR_WATERMARK_SIZE ACP_P1_I2S_TX_INTR_WATERMARK_SIZE
+
+/* Registers from ACP_P1_SW_SWCLK block */
+#define ACP_P1_SW_EN 0x0003C00
+#define ACP_P1_SW_EN_STATUS 0x0003C04
+#define ACP_P1_SW_FRAMESIZE 0x0003C08
+#define ACP_P1_SW_SSP_COUNTER 0x0003C0C
+#define ACP_P1_SW_BT_TX_EN 0x0003C50
+#define ACP_P1_SW_BT_TX_EN_STATUS 0x0003C54
+#define ACP_P1_SW_BT_TX_FRAME_FORMAT 0x0003C58
+#define ACP_P1_SW_BT_TX_SAMPLEINTERVAL 0x0003C5C
+#define ACP_P1_SW_BT_TX_HCTRL 0x0003C60
+#define ACP_P1_SW_BT_TX_OFFSET 0x0003C64
+#define ACP_P1_SW_BT_TX_CHANNEL_ENABLE_DP0 0x0003C68
+#define ACP_P1_SW_BT_RX_EN 0x0003D28
+#define ACP_P1_SW_BT_RX_EN_STATUS 0x0003D2C
+#define ACP_P1_SW_BT_RX_FRAME_FORMAT 0x0003D30
+#define ACP_P1_SW_BT_RX_SAMPLEINTERVAL 0x0003D34
+#define ACP_P1_SW_BT_RX_HCTRL 0x0003D38
+#define ACP_P1_SW_BT_RX_OFFSET 0x0003D3C
+#define ACP_P1_SW_BT_RX_CHANNEL_ENABLE_DP0 0x0003D40
+#define ACP_P1_SW_BPT_PORT_EN 0x0003D60
+#define ACP_P1_SW_BPT_PORT_EN_STATUS 0x0003D64
+#define ACP_P1_SW_BPT_PORT_FRAME_FORMAT 0x0003D68
+#define ACP_P1_SW_BPT_PORT_SAMPLEINTERVAL 0x0003D6C
+#define ACP_P1_SW_BPT_PORT_HCTRL 0x0003D70
+#define ACP_P1_SW_BPT_PORT_OFFSET 0x0003D74
+#define ACP_P1_SW_BPT_PORT_CHANNEL_ENABLE 0x0003D78
+#define ACP_P1_SW_BPT_PORT_FIRST_BYTE_ADDR 0x0003D7C
+#define ACP_P1_SW_CLK_RESUME_CTRL 0x0003D80
+#define ACP_P1_SW_CLK_RESUME_DELAY_CNTR 0x0003D84
+#define ACP_P1_SW_BUS_RESET_CTRL 0x0003D88
+#define ACP_P1_SW_PRBS_ERR_STATUS 0x0003D8C
+
+/* Registers from ACP_P1_SW_ACLK block */
+#define P1_SW_CORB_BASE_ADDRESS 0x0003E00
+#define P1_SW_CORB_WRITE_POINTER 0x0003E04
+#define P1_SW_CORB_READ_POINTER 0x0003E08
+#define P1_SW_CORB_CONTROL 0x0003E0C
+#define P1_SW_CORB_SIZE 0x0003E14
+#define P1_SW_RIRB_BASE_ADDRESS 0x0003E18
+#define P1_SW_RIRB_WRITE_POINTER 0x0003E1C
+#define P1_SW_RIRB_RESPONSE_INTERRUPT_COUNT 0x0003E20
+#define P1_SW_RIRB_CONTROL 0x0003E24
+#define P1_SW_RIRB_SIZE 0x0003E28
+#define P1_SW_RIRB_FIFO_MIN_THDL 0x0003E2C
+#define P1_SW_IMM_CMD_UPPER_WORD 0x0003E30
+#define P1_SW_IMM_CMD_LOWER_QWORD 0x0003E34
+#define P1_SW_IMM_RESP_UPPER_WORD 0x0003E38
+#define P1_SW_IMM_RESP_LOWER_QWORD 0x0003E3C
+#define P1_SW_IMM_CMD_STS 0x0003E40
+#define P1_SW_BRA_BASE_ADDRESS 0x0003E44
+#define P1_SW_BRA_TRANSFER_SIZE 0x0003E48
+#define P1_SW_BRA_DMA_BUSY 0x0003E4C
+#define P1_SW_BRA_RESP 0x0003E50
+#define P1_SW_BRA_RESP_FRAME_ADDR 0x0003E54
+#define P1_SW_BRA_CURRENT_TRANSFER_SIZE 0x0003E58
+#define P1_SW_STATE_CHANGE_STATUS_0TO7 0x0003E5C
+#define P1_SW_STATE_CHANGE_STATUS_8TO11 0x0003E60
+#define P1_SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003E64
+#define P1_SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003E68
+#define P1_SW_CLK_FREQUENCY_CTRL 0x0003E6C
+#define P1_SW_ERROR_INTR_MASK 0x0003E70
+#define P1_SW_PHY_TEST_MODE_DATA_OFF 0x0003E74
/* Registers from ACP_SCRATCH block */
#define ACP_SCRATCH_REG_0 0x0010000
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 35778f953a3f..a6872537724d 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -495,6 +495,13 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
snd_hdac_chip_writeb(chip, reg, \
(snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val))
+/* update register macro */
+#define snd_hdac_updatel(addr, reg, mask, val) \
+ writel(((readl(addr + reg) & ~(mask)) | (val)), addr + reg)
+
+#define snd_hdac_updatew(addr, reg, mask, val) \
+ writew(((readw(addr + reg) & ~(mask)) | (val)), addr + reg)
+
/*
* HD-audio stream
*/
@@ -511,6 +518,13 @@ struct hdac_stream {
void __iomem *sd_addr; /* stream descriptor pointer */
+ void __iomem *spib_addr; /* software position in buffers stream pointer */
+ void __iomem *fifo_addr; /* software position Max fifos stream pointer */
+
+ void __iomem *dpibr_addr; /* DMA position in buffer resume pointer */
+ u32 dpib; /* DMA position in buffer */
+ u32 lpib; /* Linear position in buffer */
+
u32 sd_int_sta_mask; /* stream int status mask */
/* pcm support */
@@ -575,6 +589,19 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
struct snd_pcm_substream *substream);
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *chip,
+ bool enable, int index);
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev);
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+ bool enable, int index);
+int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev);
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value);
+
/*
* macros for easy use
*/
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 83aed26ab143..68ab89211de2 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -23,13 +23,10 @@ void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus);
void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable);
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
- bool enable, int index);
-
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus);
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr);
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
- const char *codec_name);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+ const char *codec_name);
enum hdac_ext_stream_type {
HDAC_EXT_STREAM_TYPE_COUPLED = 0,
@@ -43,11 +40,6 @@ enum hdac_ext_stream_type {
* @hstream: hdac_stream
* @pphc_addr: processing pipe host stream pointer
* @pplc_addr: processing pipe link stream pointer
- * @spib_addr: software position in buffers stream pointer
- * @fifo_addr: software position Max fifos stream pointer
- * @dpibr_addr: DMA position in buffer resume pointer
- * @dpib: DMA position in buffer
- * @lpib: Linear position in buffer
* @decoupled: stream host and link is decoupled
* @link_locked: link is locked
* @link_prepared: link is prepared
@@ -59,13 +51,11 @@ struct hdac_ext_stream {
void __iomem *pphc_addr;
void __iomem *pplc_addr;
- void __iomem *spib_addr;
- void __iomem *fifo_addr;
-
- void __iomem *dpibr_addr;
+ u32 pphcllpl;
+ u32 pphcllpu;
+ u32 pphcldpl;
+ u32 pphcldpu;
- u32 dpib;
- u32 lpib;
bool decoupled:1;
bool link_locked:1;
bool link_prepared;
@@ -80,7 +70,7 @@ struct hdac_ext_stream {
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir);
void snd_hdac_ext_stream_free_all(struct hdac_bus *bus);
-void snd_hdac_link_free_all(struct hdac_bus *bus);
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus);
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream,
int type);
@@ -90,20 +80,10 @@ void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
struct hdac_ext_stream *azx_dev, bool decouple);
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
- bool enable, int index);
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value);
-
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream);
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream);
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
struct hdac_ext_link {
struct hdac_bus *bus;
@@ -117,29 +97,20 @@ struct hdac_ext_link {
struct list_head list;
};
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink);
int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus);
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
- int stream);
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
- int stream);
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *hlink,
+ int stream);
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *hlink,
+ int stream);
-int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink);
void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
-/* update register macro */
-#define snd_hdac_updatel(addr, reg, mask, val) \
- writel(((readl(addr + reg) & ~(mask)) | (val)), \
- addr + reg)
-
-#define snd_hdac_updatew(addr, reg, mask, val) \
- writew(((readw(addr + reg) & ~(mask)) | (val)), \
- addr + reg)
-
#define snd_hdac_adsp_writeb(chip, reg, value) \
snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value)
#define snd_hdac_adsp_readb(chip, reg) \
diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h
index 48ad33aba393..9b162ac1e08e 100644
--- a/include/sound/hdmi-codec.h
+++ b/include/sound/hdmi-codec.h
@@ -124,7 +124,11 @@ struct hdmi_codec_ops {
struct hdmi_codec_pdata {
const struct hdmi_codec_ops *ops;
uint i2s:1;
+ uint no_i2s_playback:1;
+ uint no_i2s_capture:1;
uint spdif:1;
+ uint no_spdif_playback:1;
+ uint no_spdif_capture:1;
int max_i2s_channels;
void *data;
};
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 7b1a022910e8..27040b472a4f 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -106,24 +106,24 @@ struct snd_pcm_ops {
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
/* If you change this don't forget to change rates[] table in pcm_native.c */
-#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
-#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
-#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
-#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
-#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
-#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
-#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
-#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
-#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
-#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
-#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
-#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
-#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
-#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */
-#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */
-
-#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
-#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
+#define SNDRV_PCM_RATE_5512 (1U<<0) /* 5512Hz */
+#define SNDRV_PCM_RATE_8000 (1U<<1) /* 8000Hz */
+#define SNDRV_PCM_RATE_11025 (1U<<2) /* 11025Hz */
+#define SNDRV_PCM_RATE_16000 (1U<<3) /* 16000Hz */
+#define SNDRV_PCM_RATE_22050 (1U<<4) /* 22050Hz */
+#define SNDRV_PCM_RATE_32000 (1U<<5) /* 32000Hz */
+#define SNDRV_PCM_RATE_44100 (1U<<6) /* 44100Hz */
+#define SNDRV_PCM_RATE_48000 (1U<<7) /* 48000Hz */
+#define SNDRV_PCM_RATE_64000 (1U<<8) /* 64000Hz */
+#define SNDRV_PCM_RATE_88200 (1U<<9) /* 88200Hz */
+#define SNDRV_PCM_RATE_96000 (1U<<10) /* 96000Hz */
+#define SNDRV_PCM_RATE_176400 (1U<<11) /* 176400Hz */
+#define SNDRV_PCM_RATE_192000 (1U<<12) /* 192000Hz */
+#define SNDRV_PCM_RATE_352800 (1U<<13) /* 352800Hz */
+#define SNDRV_PCM_RATE_384000 (1U<<14) /* 384000Hz */
+
+#define SNDRV_PCM_RATE_CONTINUOUS (1U<<30) /* continuous range */
+#define SNDRV_PCM_RATE_KNOT (1U<<31) /* supports more non-continuos rates */
#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\
diff --git a/include/sound/sdw.h b/include/sound/sdw.h
new file mode 100644
index 000000000000..6dcdb3228dba
--- /dev/null
+++ b/include/sound/sdw.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * linux/sound/sdw.h -- SoundWire helpers for ALSA/ASoC
+ *
+ * Copyright (c) 2022 Cirrus Logic Inc.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#include <linux/soundwire/sdw.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#ifndef __INCLUDE_SOUND_SDW_H
+#define __INCLUDE_SOUND_SDW_H
+
+/**
+ * snd_sdw_params_to_config() - Conversion from hw_params to SoundWire config
+ *
+ * @substream: Pointer to the PCM substream structure
+ * @params: Pointer to the hardware params structure
+ * @stream_config: Stream configuration for the SoundWire audio stream
+ * @port_config: Port configuration for the SoundWire audio stream
+ *
+ * This function provides a basic conversion from the hw_params structure to
+ * SoundWire configuration structures. The user will at a minimum need to also
+ * set the port number in the port config, but may also override more of the
+ * setup, or in the case of a complex user, not use this helper at all and
+ * open-code everything.
+ */
+static inline void snd_sdw_params_to_config(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct sdw_stream_config *stream_config,
+ struct sdw_port_config *port_config)
+{
+ stream_config->frame_rate = params_rate(params);
+ stream_config->ch_count = params_channels(params);
+ stream_config->bps = snd_pcm_format_width(params_format(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ stream_config->direction = SDW_DATA_DIR_RX;
+ else
+ stream_config->direction = SDW_DATA_DIR_TX;
+
+ port_config->ch_mask = GENMASK(stream_config->ch_count - 1, 0);
+}
+
+#endif
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 25e049f44178..38590f1ae9ee 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -173,8 +173,6 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
void asoc_simple_clean_reference(struct snd_soc_card *card);
-void asoc_simple_convert_fixup(struct asoc_simple_data *data,
- struct snd_pcm_hw_params *params);
void asoc_simple_parse_convert(struct device_node *np, char *prefix,
struct asoc_simple_data *data);
bool asoc_simple_is_convert_required(const struct asoc_simple_data *data);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index ebb8e7a7fc29..77495e5988c1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -341,31 +341,27 @@ struct soc_enum;
#define SND_SOC_DAPM_STREAM_STOP 0x2
#define SND_SOC_DAPM_STREAM_SUSPEND 0x4
#define SND_SOC_DAPM_STREAM_RESUME 0x8
-#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
/* dapm event types */
-#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
-#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
-#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
-#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
-#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
-#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
-#define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */
-#define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
-#define SND_SOC_DAPM_PRE_POST_PMD \
- (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
-#define SND_SOC_DAPM_PRE_POST_PMU \
- (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
+#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
+#define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */
+#define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
+#define SND_SOC_DAPM_PRE_POST_PMD (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
+#define SND_SOC_DAPM_PRE_POST_PMU (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
/* convenience event type detection */
-#define SND_SOC_DAPM_EVENT_ON(e) \
- (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
-#define SND_SOC_DAPM_EVENT_OFF(e) \
- (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+#define SND_SOC_DAPM_EVENT_ON(e) (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e) (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
/* regulator widget flags */
-#define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
+#define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
struct snd_soc_dapm_widget;
enum snd_soc_dapm_type;
@@ -396,18 +392,13 @@ enum snd_soc_bias_level {
SND_SOC_BIAS_ON = 3,
};
-int dapm_regulator_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
-int dapm_clock_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
-int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
+int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
/* dapm controls */
-int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
@@ -419,30 +410,24 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget,
- int num);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
- struct snd_soc_dapm_context *dapm,
+ const struct snd_soc_dapm_widget *widget, int num);
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(
- struct snd_soc_dapm_context *dapm,
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
-int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dai *dai);
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai);
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai);
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
- struct snd_soc_card *card,
- struct snd_soc_component *component);
+ struct snd_soc_card *card, struct snd_soc_component *component);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
@@ -450,49 +435,36 @@ 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,
- int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event);
void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream);
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
- struct snd_kcontrol *kcontrol, int connect,
- struct snd_soc_dapm_update *update);
+ struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update);
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
struct snd_soc_dapm_update *update);
/* dapm sys fs - used by the core */
extern struct attribute *soc_dapm_dev_attrs[];
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
- struct dentry *parent);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent);
/* dapm audio pin control and status */
-int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
-int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin);
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
/* Mostly internal - should not normally be used */
@@ -501,40 +473,35 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
/* dapm path query */
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_widget_list **list,
- bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
- enum snd_soc_dapm_direction));
+ bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction));
void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list);
-struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
- struct snd_kcontrol *kcontrol);
-
-struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
- struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol);
-int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level);
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level);
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
- snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
- snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
- snd_soc_dapm_mixer, /* mixes several analog signals together */
- snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
- snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
- snd_soc_dapm_out_drv, /* output driver */
- snd_soc_dapm_adc, /* analog to digital converter */
- snd_soc_dapm_dac, /* digital to analog converter */
+ snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
+ snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
+ snd_soc_dapm_mixer, /* mixes several analog signals together */
+ snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
+ snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
+ snd_soc_dapm_out_drv, /* output driver */
+ snd_soc_dapm_adc, /* analog to digital converter */
+ snd_soc_dapm_dac, /* digital to analog converter */
snd_soc_dapm_micbias, /* microphone bias (power) - DEPRECATED: use snd_soc_dapm_supply */
- snd_soc_dapm_mic, /* microphone */
- snd_soc_dapm_hp, /* headphones */
- snd_soc_dapm_spk, /* speaker */
- snd_soc_dapm_line, /* line input/output */
+ snd_soc_dapm_mic, /* microphone */
+ snd_soc_dapm_hp, /* headphones */
+ snd_soc_dapm_spk, /* speaker */
+ snd_soc_dapm_line, /* line input/output */
snd_soc_dapm_switch, /* analog switch */
- snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
- snd_soc_dapm_pre, /* machine specific pre widget - exec first */
- snd_soc_dapm_post, /* machine specific post widget - exec last */
+ snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
+ snd_soc_dapm_pre, /* machine specific pre widget - exec first */
+ snd_soc_dapm_post, /* machine specific post widget - exec last */
snd_soc_dapm_supply, /* power/clock supply */
snd_soc_dapm_pinctrl, /* pinctrl */
snd_soc_dapm_regulator_supply, /* external regulator */
@@ -600,9 +567,9 @@ struct snd_soc_dapm_path {
};
/* status */
- u32 connect:1; /* source and sink widgets are connected */
- u32 walking:1; /* path is in the process of being walked */
- u32 weak:1; /* path ignored for power management */
+ u32 connect:1; /* source and sink widgets are connected */
+ u32 walking:1; /* path is in the process of being walked */
+ u32 weak:1; /* path ignored for power management */
u32 is_supply:1; /* At least one of the connected widgets is a supply */
int (*connected)(struct snd_soc_dapm_widget *source,
@@ -616,8 +583,8 @@ struct snd_soc_dapm_path {
/* dapm widget */
struct snd_soc_dapm_widget {
enum snd_soc_dapm_type id;
- const char *name; /* widget name */
- const char *sname; /* stream name */
+ const char *name; /* widget name */
+ const char *sname; /* stream name */
struct list_head list;
struct snd_soc_dapm_context *dapm;
@@ -636,7 +603,7 @@ struct snd_soc_dapm_widget {
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
unsigned char force:1; /* force state */
- unsigned char ignore_suspend:1; /* kept enabled over suspend */
+ unsigned char ignore_suspend:1; /* kept enabled over suspend */
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
unsigned char is_supply:1; /* Widget is a supply type widget */
@@ -680,27 +647,24 @@ struct snd_soc_dapm_update {
bool has_second_set;
};
-struct snd_soc_dapm_wcache {
- struct snd_soc_dapm_widget *widget;
-};
-
/* DAPM context */
struct snd_soc_dapm_context {
enum snd_soc_bias_level bias_level;
- unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
- /* Go to BIAS_OFF in suspend if the DAPM context is idle */
- unsigned int suspend_bias_off:1;
- struct device *dev; /* from parent - for debug */
- struct snd_soc_component *component; /* parent component */
- struct snd_soc_card *card; /* parent card */
+ /* bit field */
+ unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+ unsigned int suspend_bias_off:1; /* Use BIAS_OFF in suspend if the DAPM is idle */
+
+ struct device *dev; /* from parent - for debug */
+ struct snd_soc_component *component; /* parent component */
+ struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
enum snd_soc_bias_level target_bias_level;
struct list_head list;
- struct snd_soc_dapm_wcache path_sink_cache;
- struct snd_soc_dapm_wcache path_source_cache;
+ struct snd_soc_dapm_widget *wcache_sink;
+ struct snd_soc_dapm_widget *wcache_source;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
@@ -767,11 +731,11 @@ enum snd_soc_dapm_direction {
#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
-#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
-#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
+#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
+#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
/**
- * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the
* specified direction of a widget
* @w: The widget
* @dir: Whether to iterate over the paths where the specified widget is the
@@ -782,7 +746,7 @@ enum snd_soc_dapm_direction {
list_for_each_entry(p, &w->edges[dir], list_node[dir])
/**
- * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path_safe - Iterates over all paths in the
* specified direction of a widget
* @w: The widget
* @dir: Whether to iterate over the paths where the specified widget is the
@@ -790,7 +754,7 @@ enum snd_soc_dapm_direction {
* @p: The path iterator variable
* @next_p: Temporary storage for the next path
*
- * This function works like snd_soc_dapm_widget_for_each_sink_path, expect that
+ * This function works like snd_soc_dapm_widget_for_each_path, expect that
* it is safe to remove the current path from the list while iterating
*/
#define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index 5b689c663290..2864aed72998 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -78,8 +78,6 @@ struct snd_soc_dpcm {
struct list_head list_be;
struct list_head list_fe;
- /* hw params for this link - may be different for each link */
- struct snd_pcm_hw_params hw_params;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_state;
#endif
diff --git a/include/sound/sof.h b/include/sound/sof.h
index 341fef19e612..266e66318f9c 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -59,15 +59,11 @@ enum sof_ipc_type {
* SOF Platform data.
*/
struct snd_sof_pdata {
- const struct firmware *fw;
const char *name;
const char *platform;
struct device *dev;
- /* indicate how many first bytes shouldn't be loaded into DSP memory. */
- size_t fw_offset;
-
/*
* notification callback used if the hardware initialization
* can take time or is handled in a workqueue. This callback
@@ -86,6 +82,9 @@ struct snd_sof_pdata {
const char *tplg_filename_prefix;
const char *tplg_filename;
+ /* loadable external libraries available under this directory */
+ const char *fw_lib_prefix;
+
/* machine */
struct platform_device *pdev_mach;
const struct snd_soc_acpi_mach *machine;
@@ -131,8 +130,9 @@ struct sof_dev_desc {
unsigned int ipc_supported_mask;
enum sof_ipc_type ipc_default;
- /* defaults paths for firmware and topology files */
+ /* defaults paths for firmware, library and topology files */
const char *default_fw_path[SOF_IPC_TYPE_COUNT];
+ const char *default_lib_path[SOF_IPC_TYPE_COUNT];
const char *default_tplg_path[SOF_IPC_TYPE_COUNT];
/* default firmware name */
diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h
index 92f45c180b7c..9df7ac824efe 100644
--- a/include/sound/sof/dai-amd.h
+++ b/include/sound/sof/dai-amd.h
@@ -17,6 +17,7 @@ struct sof_ipc_dai_acp_params {
uint32_t fsync_rate; /* FSYNC frequency in Hz */
uint32_t tdm_slots;
+ uint32_t tdm_mode;
} __packed;
/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 83fd81c82e4c..3041f5805b7b 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -84,8 +84,10 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_BT, /**< AMD ACP BT*/
SOF_DAI_AMD_SP, /**< AMD ACP SP */
SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */
- SOF_DAI_AMD_HS, /**< Amd HS */
SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */
+ SOF_DAI_AMD_HS, /**< Amd HS */
+ SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */
+ SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
};
/* general purpose DAI configuration */
diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h
index 65e86e4e9fd8..75193850ead0 100644
--- a/include/sound/sof/info.h
+++ b/include/sound/sof/info.h
@@ -36,6 +36,10 @@ enum sof_ipc_ext_data {
SOF_IPC_EXT_USER_ABI_INFO = 4,
};
+/* Build u32 number in format MMmmmppp */
+#define SOF_FW_VER(MAJOR, MINOR, PATCH) ((uint32_t)( \
+ ((MAJOR) << 24) | ((MINOR) << 12) | (PATCH)))
+
/* FW version - SOF_IPC_GLB_VERSION */
struct sof_ipc_fw_version {
struct sof_ipc_hdr hdr;
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index 99efe0ef1784..622193be7ac4 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -185,6 +185,10 @@ enum sof_ipc4_pipeline_state {
#define SOF_IPC4_GLB_PIPE_STATE_MASK GENMASK(15, 0)
#define SOF_IPC4_GLB_PIPE_STATE(x) ((x) << SOF_IPC4_GLB_PIPE_STATE_SHIFT)
+/* load library ipc msg */
+#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT 16
+#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(x) ((x) << SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT)
+
enum sof_ipc4_channel_config {
/* one channel only. */
SOF_IPC4_CHANNEL_CONFIG_MONO,
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
deleted file mode 100644
index b660a9ed05ec..000000000000
--- a/include/sound/tlv320aic3x.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Platform data for Texas Instruments TLV320AIC3x codec
- *
- * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
- */
-#ifndef __TLV320AIC3x_H__
-#define __TLV320AIC3x_H__
-
-/* GPIO API */
-enum {
- AIC3X_GPIO1_FUNC_DISABLED = 0,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
- AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
- AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
- AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
- AIC3X_GPIO1_FUNC_INPUT = 8,
- AIC3X_GPIO1_FUNC_OUTPUT = 9,
- AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
- AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
- AIC3X_GPIO1_FUNC_ALL_IRQ = 16
-};
-
-enum {
- AIC3X_GPIO2_FUNC_DISABLED = 0,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
- AIC3X_GPIO2_FUNC_INPUT = 3,
- AIC3X_GPIO2_FUNC_OUTPUT = 4,
- AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
- AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
- AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
- AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
- AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
- AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
-};
-
-enum aic3x_micbias_voltage {
- AIC3X_MICBIAS_OFF = 0,
- AIC3X_MICBIAS_2_0V = 1,
- AIC3X_MICBIAS_2_5V = 2,
- AIC3X_MICBIAS_AVDDV = 3,
-};
-
-struct aic3x_setup_data {
- unsigned int gpio_func[2];
-};
-
-struct aic3x_pdata {
- int gpio_reset; /* < 0 if not used */
- struct aic3x_setup_data *setup;
-
- /* Selects the micbias voltage */
- enum aic3x_micbias_voltage micbias_vg;
-};
-
-#endif
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index ed50e81174bf..0bce0b4ff2fa 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -1993,12 +1993,11 @@ TRACE_EVENT(btrfs_set_extent_bit,
TP_fast_assign_btrfs(tree->fs_info,
__entry->owner = tree->owner;
- if (tree->private_data) {
- const struct inode *inode = tree->private_data;
+ if (tree->inode) {
+ const struct btrfs_inode *inode = tree->inode;
- __entry->ino = btrfs_ino(BTRFS_I(inode));
- __entry->rootid =
- BTRFS_I(inode)->root->root_key.objectid;
+ __entry->ino = btrfs_ino(inode);
+ __entry->rootid = inode->root->root_key.objectid;
} else {
__entry->ino = 0;
__entry->rootid = 0;
@@ -2032,12 +2031,11 @@ TRACE_EVENT(btrfs_clear_extent_bit,
TP_fast_assign_btrfs(tree->fs_info,
__entry->owner = tree->owner;
- if (tree->private_data) {
- const struct inode *inode = tree->private_data;
+ if (tree->inode) {
+ const struct btrfs_inode *inode = tree->inode;
- __entry->ino = btrfs_ino(BTRFS_I(inode));
- __entry->rootid =
- BTRFS_I(inode)->root->root_key.objectid;
+ __entry->ino = btrfs_ino(inode);
+ __entry->rootid = inode->root->root_key.objectid;
} else {
__entry->ino = 0;
__entry->rootid = 0;
@@ -2072,12 +2070,11 @@ TRACE_EVENT(btrfs_convert_extent_bit,
TP_fast_assign_btrfs(tree->fs_info,
__entry->owner = tree->owner;
- if (tree->private_data) {
- const struct inode *inode = tree->private_data;
+ if (tree->inode) {
+ const struct btrfs_inode *inode = tree->inode;
- __entry->ino = btrfs_ino(BTRFS_I(inode));
- __entry->rootid =
- BTRFS_I(inode)->root->root_key.objectid;
+ __entry->ino = btrfs_ino(inode);
+ __entry->rootid = inode->root->root_key.objectid;
} else {
__entry->ino = 0;
__entry->rootid = 0;
diff --git a/include/trace/events/cachefiles.h b/include/trace/events/cachefiles.h
index d8d4d73fe7b6..cf4b98b9a9ed 100644
--- a/include/trace/events/cachefiles.h
+++ b/include/trace/events/cachefiles.h
@@ -428,16 +428,18 @@ TRACE_EVENT(cachefiles_vol_coherency,
);
TRACE_EVENT(cachefiles_prep_read,
- TP_PROTO(struct netfs_io_subrequest *sreq,
+ TP_PROTO(struct cachefiles_object *obj,
+ loff_t start,
+ size_t len,
+ unsigned short flags,
enum netfs_io_source source,
enum cachefiles_prepare_read_trace why,
- ino_t cache_inode),
+ ino_t cache_inode, ino_t netfs_inode),
- TP_ARGS(sreq, source, why, cache_inode),
+ TP_ARGS(obj, start, len, flags, source, why, cache_inode, netfs_inode),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(unsigned short, index )
+ __field(unsigned int, obj )
__field(unsigned short, flags )
__field(enum netfs_io_source, source )
__field(enum cachefiles_prepare_read_trace, why )
@@ -448,19 +450,18 @@ TRACE_EVENT(cachefiles_prep_read,
),
TP_fast_assign(
- __entry->rreq = sreq->rreq->debug_id;
- __entry->index = sreq->debug_index;
- __entry->flags = sreq->flags;
+ __entry->obj = obj ? obj->debug_id : 0;
+ __entry->flags = flags;
__entry->source = source;
__entry->why = why;
- __entry->len = sreq->len;
- __entry->start = sreq->start;
- __entry->netfs_inode = sreq->rreq->inode->i_ino;
+ __entry->len = len;
+ __entry->start = start;
+ __entry->netfs_inode = netfs_inode;
__entry->cache_inode = cache_inode;
),
- TP_printk("R=%08x[%u] %s %s f=%02x s=%llx %zx ni=%x B=%x",
- __entry->rreq, __entry->index,
+ TP_printk("o=%08x %s %s f=%02x s=%llx %zx ni=%x B=%x",
+ __entry->obj,
__print_symbolic(__entry->source, netfs_sreq_sources),
__print_symbolic(__entry->why, cachefiles_prepare_read_traces),
__entry->flags,
diff --git a/include/trace/events/cxl.h b/include/trace/events/cxl.h
new file mode 100644
index 000000000000..ad085a2534ef
--- /dev/null
+++ b/include/trace/events/cxl.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cxl
+
+#if !defined(_CXL_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CXL_EVENTS_H
+
+#include <linux/tracepoint.h>
+
+#define CXL_HEADERLOG_SIZE SZ_512
+#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
+
+#define CXL_RAS_UC_CACHE_DATA_PARITY BIT(0)
+#define CXL_RAS_UC_CACHE_ADDR_PARITY BIT(1)
+#define CXL_RAS_UC_CACHE_BE_PARITY BIT(2)
+#define CXL_RAS_UC_CACHE_DATA_ECC BIT(3)
+#define CXL_RAS_UC_MEM_DATA_PARITY BIT(4)
+#define CXL_RAS_UC_MEM_ADDR_PARITY BIT(5)
+#define CXL_RAS_UC_MEM_BE_PARITY BIT(6)
+#define CXL_RAS_UC_MEM_DATA_ECC BIT(7)
+#define CXL_RAS_UC_REINIT_THRESH BIT(8)
+#define CXL_RAS_UC_RSVD_ENCODE BIT(9)
+#define CXL_RAS_UC_POISON BIT(10)
+#define CXL_RAS_UC_RECV_OVERFLOW BIT(11)
+#define CXL_RAS_UC_INTERNAL_ERR BIT(14)
+#define CXL_RAS_UC_IDE_TX_ERR BIT(15)
+#define CXL_RAS_UC_IDE_RX_ERR BIT(16)
+
+#define show_uc_errs(status) __print_flags(status, " | ", \
+ { CXL_RAS_UC_CACHE_DATA_PARITY, "Cache Data Parity Error" }, \
+ { CXL_RAS_UC_CACHE_ADDR_PARITY, "Cache Address Parity Error" }, \
+ { CXL_RAS_UC_CACHE_BE_PARITY, "Cache Byte Enable Parity Error" }, \
+ { CXL_RAS_UC_CACHE_DATA_ECC, "Cache Data ECC Error" }, \
+ { CXL_RAS_UC_MEM_DATA_PARITY, "Memory Data Parity Error" }, \
+ { CXL_RAS_UC_MEM_ADDR_PARITY, "Memory Address Parity Error" }, \
+ { CXL_RAS_UC_MEM_BE_PARITY, "Memory Byte Enable Parity Error" }, \
+ { CXL_RAS_UC_MEM_DATA_ECC, "Memory Data ECC Error" }, \
+ { CXL_RAS_UC_REINIT_THRESH, "REINIT Threshold Hit" }, \
+ { CXL_RAS_UC_RSVD_ENCODE, "Received Unrecognized Encoding" }, \
+ { CXL_RAS_UC_POISON, "Received Poison From Peer" }, \
+ { CXL_RAS_UC_RECV_OVERFLOW, "Receiver Overflow" }, \
+ { CXL_RAS_UC_INTERNAL_ERR, "Component Specific Error" }, \
+ { CXL_RAS_UC_IDE_TX_ERR, "IDE Tx Error" }, \
+ { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \
+)
+
+TRACE_EVENT(cxl_aer_uncorrectable_error,
+ TP_PROTO(const struct device *dev, u32 status, u32 fe, u32 *hl),
+ TP_ARGS(dev, status, fe, hl),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(dev))
+ __field(u32, status)
+ __field(u32, first_error)
+ __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name, dev_name(dev));
+ __entry->status = status;
+ __entry->first_error = fe;
+ /*
+ * Embed the 512B headerlog data for user app retrieval and
+ * parsing, but no need to print this in the trace buffer.
+ */
+ memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
+ ),
+ TP_printk("%s: status: '%s' first_error: '%s'",
+ __get_str(dev_name),
+ show_uc_errs(__entry->status),
+ show_uc_errs(__entry->first_error)
+ )
+);
+
+#define CXL_RAS_CE_CACHE_DATA_ECC BIT(0)
+#define CXL_RAS_CE_MEM_DATA_ECC BIT(1)
+#define CXL_RAS_CE_CRC_THRESH BIT(2)
+#define CLX_RAS_CE_RETRY_THRESH BIT(3)
+#define CXL_RAS_CE_CACHE_POISON BIT(4)
+#define CXL_RAS_CE_MEM_POISON BIT(5)
+#define CXL_RAS_CE_PHYS_LAYER_ERR BIT(6)
+
+#define show_ce_errs(status) __print_flags(status, " | ", \
+ { CXL_RAS_CE_CACHE_DATA_ECC, "Cache Data ECC Error" }, \
+ { CXL_RAS_CE_MEM_DATA_ECC, "Memory Data ECC Error" }, \
+ { CXL_RAS_CE_CRC_THRESH, "CRC Threshold Hit" }, \
+ { CLX_RAS_CE_RETRY_THRESH, "Retry Threshold" }, \
+ { CXL_RAS_CE_CACHE_POISON, "Received Cache Poison From Peer" }, \
+ { CXL_RAS_CE_MEM_POISON, "Received Memory Poison From Peer" }, \
+ { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \
+)
+
+TRACE_EVENT(cxl_aer_correctable_error,
+ TP_PROTO(const struct device *dev, u32 status),
+ TP_ARGS(dev, status),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(dev))
+ __field(u32, status)
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name, dev_name(dev));
+ __entry->status = status;
+ ),
+ TP_printk("%s: status: '%s'",
+ __get_str(dev_name), show_ce_errs(__entry->status)
+ )
+);
+
+#endif /* _CXL_EVENTS_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE cxl
+#include <trace/define_trace.h>
diff --git a/include/trace/events/dlm.h b/include/trace/events/dlm.h
index da0eaae98fa3..37eb79e29b28 100644
--- a/include/trace/events/dlm.h
+++ b/include/trace/events/dlm.h
@@ -46,6 +46,56 @@
{ DLM_SBF_VALNOTVALID, "VALNOTVALID" }, \
{ DLM_SBF_ALTMODE, "ALTMODE" })
+#define show_lkb_flags(flags) __print_flags(flags, "|", \
+ { DLM_IFL_MSTCPY, "MSTCPY" }, \
+ { DLM_IFL_RESEND, "RESEND" }, \
+ { DLM_IFL_DEAD, "DEAD" }, \
+ { DLM_IFL_OVERLAP_UNLOCK, "OVERLAP_UNLOCK" }, \
+ { DLM_IFL_OVERLAP_CANCEL, "OVERLAP_CANCEL" }, \
+ { DLM_IFL_ENDOFLIFE, "ENDOFLIFE" }, \
+ { DLM_IFL_DEADLOCK_CANCEL, "DEADLOCK_CANCEL" }, \
+ { DLM_IFL_STUB_MS, "STUB_MS" }, \
+ { DLM_IFL_USER, "USER" }, \
+ { DLM_IFL_ORPHAN, "ORPHAN" })
+
+#define show_header_cmd(cmd) __print_symbolic(cmd, \
+ { DLM_MSG, "MSG"}, \
+ { DLM_RCOM, "RCOM"}, \
+ { DLM_OPTS, "OPTS"}, \
+ { DLM_ACK, "ACK"}, \
+ { DLM_FIN, "FIN"})
+
+#define show_message_version(version) __print_symbolic(version, \
+ { DLM_VERSION_3_1, "3.1"}, \
+ { DLM_VERSION_3_2, "3.2"})
+
+#define show_message_type(type) __print_symbolic(type, \
+ { DLM_MSG_REQUEST, "REQUEST"}, \
+ { DLM_MSG_CONVERT, "CONVERT"}, \
+ { DLM_MSG_UNLOCK, "UNLOCK"}, \
+ { DLM_MSG_CANCEL, "CANCEL"}, \
+ { DLM_MSG_REQUEST_REPLY, "REQUEST_REPLY"}, \
+ { DLM_MSG_CONVERT_REPLY, "CONVERT_REPLY"}, \
+ { DLM_MSG_UNLOCK_REPLY, "UNLOCK_REPLY"}, \
+ { DLM_MSG_CANCEL_REPLY, "CANCEL_REPLY"}, \
+ { DLM_MSG_GRANT, "GRANT"}, \
+ { DLM_MSG_BAST, "BAST"}, \
+ { DLM_MSG_LOOKUP, "LOOKUP"}, \
+ { DLM_MSG_REMOVE, "REMOVE"}, \
+ { DLM_MSG_LOOKUP_REPLY, "LOOKUP_REPLY"}, \
+ { DLM_MSG_PURGE, "PURGE"})
+
+#define show_rcom_type(type) __print_symbolic(type, \
+ { DLM_RCOM_STATUS, "STATUS"}, \
+ { DLM_RCOM_NAMES, "NAMES"}, \
+ { DLM_RCOM_LOOKUP, "LOOKUP"}, \
+ { DLM_RCOM_LOCK, "LOCK"}, \
+ { DLM_RCOM_STATUS_REPLY, "STATUS_REPLY"}, \
+ { DLM_RCOM_NAMES_REPLY, "NAMES_REPLY"}, \
+ { DLM_RCOM_LOOKUP_REPLY, "LOOKUP_REPLY"}, \
+ { DLM_RCOM_LOCK_REPLY, "LOCK_REPLY"})
+
+
/* note: we begin tracing dlm_lock_start() only if ls and lkb are found */
TRACE_EVENT(dlm_lock_start,
@@ -290,6 +340,259 @@ TRACE_EVENT(dlm_unlock_end,
);
+DECLARE_EVENT_CLASS(dlm_rcom_template,
+
+ TP_PROTO(uint32_t dst, uint32_t h_seq, const struct dlm_rcom *rc),
+
+ TP_ARGS(dst, h_seq, rc),
+
+ TP_STRUCT__entry(
+ __field(uint32_t, dst)
+ __field(uint32_t, h_seq)
+ __field(uint32_t, h_version)
+ __field(uint32_t, h_lockspace)
+ __field(uint32_t, h_nodeid)
+ __field(uint16_t, h_length)
+ __field(uint8_t, h_cmd)
+ __field(uint32_t, rc_type)
+ __field(int32_t, rc_result)
+ __field(uint64_t, rc_id)
+ __field(uint64_t, rc_seq)
+ __field(uint64_t, rc_seq_reply)
+ __dynamic_array(unsigned char, rc_buf,
+ le16_to_cpu(rc->rc_header.h_length) - sizeof(*rc))
+ ),
+
+ TP_fast_assign(
+ __entry->dst = dst;
+ __entry->h_seq = h_seq;
+ __entry->h_version = le32_to_cpu(rc->rc_header.h_version);
+ __entry->h_lockspace = le32_to_cpu(rc->rc_header.u.h_lockspace);
+ __entry->h_nodeid = le32_to_cpu(rc->rc_header.h_nodeid);
+ __entry->h_length = le16_to_cpu(rc->rc_header.h_length);
+ __entry->h_cmd = rc->rc_header.h_cmd;
+ __entry->rc_type = le32_to_cpu(rc->rc_type);
+ __entry->rc_result = le32_to_cpu(rc->rc_result);
+ __entry->rc_id = le64_to_cpu(rc->rc_id);
+ __entry->rc_seq = le64_to_cpu(rc->rc_seq);
+ __entry->rc_seq_reply = le64_to_cpu(rc->rc_seq_reply);
+ memcpy(__get_dynamic_array(rc_buf), rc->rc_buf,
+ __get_dynamic_array_len(rc_buf));
+ ),
+
+ TP_printk("dst=%u h_seq=%u h_version=%s h_lockspace=%u h_nodeid=%u "
+ "h_length=%u h_cmd=%s rc_type=%s rc_result=%d "
+ "rc_id=%llu rc_seq=%llu rc_seq_reply=%llu "
+ "rc_buf=0x%s", __entry->dst, __entry->h_seq,
+ show_message_version(__entry->h_version),
+ __entry->h_lockspace, __entry->h_nodeid, __entry->h_length,
+ show_header_cmd(__entry->h_cmd),
+ show_rcom_type(__entry->rc_type),
+ __entry->rc_result, __entry->rc_id, __entry->rc_seq,
+ __entry->rc_seq_reply,
+ __print_hex_str(__get_dynamic_array(rc_buf),
+ __get_dynamic_array_len(rc_buf)))
+
+);
+
+DEFINE_EVENT(dlm_rcom_template, dlm_send_rcom,
+ TP_PROTO(uint32_t dst, uint32_t h_seq, const struct dlm_rcom *rc),
+ TP_ARGS(dst, h_seq, rc));
+
+DEFINE_EVENT(dlm_rcom_template, dlm_recv_rcom,
+ TP_PROTO(uint32_t dst, uint32_t h_seq, const struct dlm_rcom *rc),
+ TP_ARGS(dst, h_seq, rc));
+
+TRACE_EVENT(dlm_send_message,
+
+ TP_PROTO(uint32_t dst, uint32_t h_seq, const struct dlm_message *ms,
+ const void *name, int namelen),
+
+ TP_ARGS(dst, h_seq, ms, name, namelen),
+
+ TP_STRUCT__entry(
+ __field(uint32_t, dst)
+ __field(uint32_t, h_seq)
+ __field(uint32_t, h_version)
+ __field(uint32_t, h_lockspace)
+ __field(uint32_t, h_nodeid)
+ __field(uint16_t, h_length)
+ __field(uint8_t, h_cmd)
+ __field(uint32_t, m_type)
+ __field(uint32_t, m_nodeid)
+ __field(uint32_t, m_pid)
+ __field(uint32_t, m_lkid)
+ __field(uint32_t, m_remid)
+ __field(uint32_t, m_parent_lkid)
+ __field(uint32_t, m_parent_remid)
+ __field(uint32_t, m_exflags)
+ __field(uint32_t, m_sbflags)
+ __field(uint32_t, m_flags)
+ __field(uint32_t, m_lvbseq)
+ __field(uint32_t, m_hash)
+ __field(int32_t, m_status)
+ __field(int32_t, m_grmode)
+ __field(int32_t, m_rqmode)
+ __field(int32_t, m_bastmode)
+ __field(int32_t, m_asts)
+ __field(int32_t, m_result)
+ __dynamic_array(unsigned char, m_extra,
+ le16_to_cpu(ms->m_header.h_length) - sizeof(*ms))
+ __dynamic_array(unsigned char, res_name, namelen)
+ ),
+
+ TP_fast_assign(
+ __entry->dst = dst;
+ __entry->h_seq = h_seq;
+ __entry->h_version = le32_to_cpu(ms->m_header.h_version);
+ __entry->h_lockspace = le32_to_cpu(ms->m_header.u.h_lockspace);
+ __entry->h_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
+ __entry->h_length = le16_to_cpu(ms->m_header.h_length);
+ __entry->h_cmd = ms->m_header.h_cmd;
+ __entry->m_type = le32_to_cpu(ms->m_type);
+ __entry->m_nodeid = le32_to_cpu(ms->m_nodeid);
+ __entry->m_pid = le32_to_cpu(ms->m_pid);
+ __entry->m_lkid = le32_to_cpu(ms->m_lkid);
+ __entry->m_remid = le32_to_cpu(ms->m_remid);
+ __entry->m_parent_lkid = le32_to_cpu(ms->m_parent_lkid);
+ __entry->m_parent_remid = le32_to_cpu(ms->m_parent_remid);
+ __entry->m_exflags = le32_to_cpu(ms->m_exflags);
+ __entry->m_sbflags = le32_to_cpu(ms->m_sbflags);
+ __entry->m_flags = le32_to_cpu(ms->m_flags);
+ __entry->m_lvbseq = le32_to_cpu(ms->m_lvbseq);
+ __entry->m_hash = le32_to_cpu(ms->m_hash);
+ __entry->m_status = le32_to_cpu(ms->m_status);
+ __entry->m_grmode = le32_to_cpu(ms->m_grmode);
+ __entry->m_rqmode = le32_to_cpu(ms->m_rqmode);
+ __entry->m_bastmode = le32_to_cpu(ms->m_bastmode);
+ __entry->m_asts = le32_to_cpu(ms->m_asts);
+ __entry->m_result = le32_to_cpu(ms->m_result);
+ memcpy(__get_dynamic_array(m_extra), ms->m_extra,
+ __get_dynamic_array_len(m_extra));
+ memcpy(__get_dynamic_array(res_name), name,
+ __get_dynamic_array_len(res_name));
+ ),
+
+ TP_printk("dst=%u h_seq=%u h_version=%s h_lockspace=%u h_nodeid=%u "
+ "h_length=%u h_cmd=%s m_type=%s m_nodeid=%u "
+ "m_pid=%u m_lkid=%u m_remid=%u m_parent_lkid=%u "
+ "m_parent_remid=%u m_exflags=%s m_sbflags=%s m_flags=%s "
+ "m_lvbseq=%u m_hash=%u m_status=%d m_grmode=%s "
+ "m_rqmode=%s m_bastmode=%s m_asts=%d m_result=%d "
+ "m_extra=0x%s res_name=0x%s", __entry->dst,
+ __entry->h_seq, show_message_version(__entry->h_version),
+ __entry->h_lockspace, __entry->h_nodeid, __entry->h_length,
+ show_header_cmd(__entry->h_cmd),
+ show_message_type(__entry->m_type),
+ __entry->m_nodeid, __entry->m_pid, __entry->m_lkid,
+ __entry->m_remid, __entry->m_parent_lkid,
+ __entry->m_parent_remid, show_lock_flags(__entry->m_exflags),
+ show_dlm_sb_flags(__entry->m_sbflags),
+ show_lkb_flags(__entry->m_flags), __entry->m_lvbseq,
+ __entry->m_hash, __entry->m_status,
+ show_lock_mode(__entry->m_grmode),
+ show_lock_mode(__entry->m_rqmode),
+ show_lock_mode(__entry->m_bastmode),
+ __entry->m_asts, __entry->m_result,
+ __print_hex_str(__get_dynamic_array(m_extra),
+ __get_dynamic_array_len(m_extra)),
+ __print_hex_str(__get_dynamic_array(res_name),
+ __get_dynamic_array_len(res_name)))
+
+);
+
+TRACE_EVENT(dlm_recv_message,
+
+ TP_PROTO(uint32_t dst, uint32_t h_seq, const struct dlm_message *ms),
+
+ TP_ARGS(dst, h_seq, ms),
+
+ TP_STRUCT__entry(
+ __field(uint32_t, dst)
+ __field(uint32_t, h_seq)
+ __field(uint32_t, h_version)
+ __field(uint32_t, h_lockspace)
+ __field(uint32_t, h_nodeid)
+ __field(uint16_t, h_length)
+ __field(uint8_t, h_cmd)
+ __field(uint32_t, m_type)
+ __field(uint32_t, m_nodeid)
+ __field(uint32_t, m_pid)
+ __field(uint32_t, m_lkid)
+ __field(uint32_t, m_remid)
+ __field(uint32_t, m_parent_lkid)
+ __field(uint32_t, m_parent_remid)
+ __field(uint32_t, m_exflags)
+ __field(uint32_t, m_sbflags)
+ __field(uint32_t, m_flags)
+ __field(uint32_t, m_lvbseq)
+ __field(uint32_t, m_hash)
+ __field(int32_t, m_status)
+ __field(int32_t, m_grmode)
+ __field(int32_t, m_rqmode)
+ __field(int32_t, m_bastmode)
+ __field(int32_t, m_asts)
+ __field(int32_t, m_result)
+ __dynamic_array(unsigned char, m_extra,
+ le16_to_cpu(ms->m_header.h_length) - sizeof(*ms))
+ ),
+
+ TP_fast_assign(
+ __entry->dst = dst;
+ __entry->h_seq = h_seq;
+ __entry->h_version = le32_to_cpu(ms->m_header.h_version);
+ __entry->h_lockspace = le32_to_cpu(ms->m_header.u.h_lockspace);
+ __entry->h_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
+ __entry->h_length = le16_to_cpu(ms->m_header.h_length);
+ __entry->h_cmd = ms->m_header.h_cmd;
+ __entry->m_type = le32_to_cpu(ms->m_type);
+ __entry->m_nodeid = le32_to_cpu(ms->m_nodeid);
+ __entry->m_pid = le32_to_cpu(ms->m_pid);
+ __entry->m_lkid = le32_to_cpu(ms->m_lkid);
+ __entry->m_remid = le32_to_cpu(ms->m_remid);
+ __entry->m_parent_lkid = le32_to_cpu(ms->m_parent_lkid);
+ __entry->m_parent_remid = le32_to_cpu(ms->m_parent_remid);
+ __entry->m_exflags = le32_to_cpu(ms->m_exflags);
+ __entry->m_sbflags = le32_to_cpu(ms->m_sbflags);
+ __entry->m_flags = le32_to_cpu(ms->m_flags);
+ __entry->m_lvbseq = le32_to_cpu(ms->m_lvbseq);
+ __entry->m_hash = le32_to_cpu(ms->m_hash);
+ __entry->m_status = le32_to_cpu(ms->m_status);
+ __entry->m_grmode = le32_to_cpu(ms->m_grmode);
+ __entry->m_rqmode = le32_to_cpu(ms->m_rqmode);
+ __entry->m_bastmode = le32_to_cpu(ms->m_bastmode);
+ __entry->m_asts = le32_to_cpu(ms->m_asts);
+ __entry->m_result = le32_to_cpu(ms->m_result);
+ memcpy(__get_dynamic_array(m_extra), ms->m_extra,
+ __get_dynamic_array_len(m_extra));
+ ),
+
+ TP_printk("dst=%u h_seq=%u h_version=%s h_lockspace=%u h_nodeid=%u "
+ "h_length=%u h_cmd=%s m_type=%s m_nodeid=%u "
+ "m_pid=%u m_lkid=%u m_remid=%u m_parent_lkid=%u "
+ "m_parent_remid=%u m_exflags=%s m_sbflags=%s m_flags=%s "
+ "m_lvbseq=%u m_hash=%u m_status=%d m_grmode=%s "
+ "m_rqmode=%s m_bastmode=%s m_asts=%d m_result=%d "
+ "m_extra=0x%s", __entry->dst,
+ __entry->h_seq, show_message_version(__entry->h_version),
+ __entry->h_lockspace, __entry->h_nodeid, __entry->h_length,
+ show_header_cmd(__entry->h_cmd),
+ show_message_type(__entry->m_type),
+ __entry->m_nodeid, __entry->m_pid, __entry->m_lkid,
+ __entry->m_remid, __entry->m_parent_lkid,
+ __entry->m_parent_remid, show_lock_flags(__entry->m_exflags),
+ show_dlm_sb_flags(__entry->m_sbflags),
+ show_lkb_flags(__entry->m_flags), __entry->m_lvbseq,
+ __entry->m_hash, __entry->m_status,
+ show_lock_mode(__entry->m_grmode),
+ show_lock_mode(__entry->m_rqmode),
+ show_lock_mode(__entry->m_bastmode),
+ __entry->m_asts, __entry->m_result,
+ __print_hex_str(__get_dynamic_array(m_extra),
+ __get_dynamic_array_len(m_extra)))
+
+);
+
TRACE_EVENT(dlm_send,
TP_PROTO(int nodeid, int ret),
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 229e8fae66a3..77b426ae0064 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -104,6 +104,7 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_RESIZE);
TRACE_DEFINE_ENUM(EXT4_FC_REASON_RENAME_DIR);
TRACE_DEFINE_ENUM(EXT4_FC_REASON_FALLOC_RANGE);
TRACE_DEFINE_ENUM(EXT4_FC_REASON_INODE_JOURNAL_DATA);
+TRACE_DEFINE_ENUM(EXT4_FC_REASON_ENCRYPTED_FILENAME);
TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX);
#define show_fc_reason(reason) \
@@ -116,7 +117,8 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX);
{ EXT4_FC_REASON_RESIZE, "RESIZE"}, \
{ EXT4_FC_REASON_RENAME_DIR, "RENAME_DIR"}, \
{ EXT4_FC_REASON_FALLOC_RANGE, "FALLOC_RANGE"}, \
- { EXT4_FC_REASON_INODE_JOURNAL_DATA, "INODE_JOURNAL_DATA"})
+ { EXT4_FC_REASON_INODE_JOURNAL_DATA, "INODE_JOURNAL_DATA"}, \
+ { EXT4_FC_REASON_ENCRYPTED_FILENAME, "ENCRYPTED_FILENAME"})
TRACE_EVENT(ext4_other_inode_update_time,
TP_PROTO(struct inode *inode, ino_t orig_ino),
@@ -1744,18 +1746,19 @@ TRACE_EVENT(ext4_load_inode,
(unsigned long) __entry->ino)
);
-TRACE_EVENT(ext4_journal_start,
+TRACE_EVENT(ext4_journal_start_sb,
TP_PROTO(struct super_block *sb, int blocks, int rsv_blocks,
- int revoke_creds, unsigned long IP),
+ int revoke_creds, int type, unsigned long IP),
- TP_ARGS(sb, blocks, rsv_blocks, revoke_creds, IP),
+ TP_ARGS(sb, blocks, rsv_blocks, revoke_creds, type, IP),
TP_STRUCT__entry(
- __field( dev_t, dev )
- __field(unsigned long, ip )
- __field( int, blocks )
- __field( int, rsv_blocks )
- __field( int, revoke_creds )
+ __field( dev_t, dev )
+ __field( unsigned long, ip )
+ __field( int, blocks )
+ __field( int, rsv_blocks )
+ __field( int, revoke_creds )
+ __field( int, type )
),
TP_fast_assign(
@@ -1764,11 +1767,45 @@ TRACE_EVENT(ext4_journal_start,
__entry->blocks = blocks;
__entry->rsv_blocks = rsv_blocks;
__entry->revoke_creds = revoke_creds;
+ __entry->type = type;
+ ),
+
+ TP_printk("dev %d,%d blocks %d, rsv_blocks %d, revoke_creds %d,"
+ " type %d, caller %pS", MAJOR(__entry->dev),
+ MINOR(__entry->dev), __entry->blocks, __entry->rsv_blocks,
+ __entry->revoke_creds, __entry->type, (void *)__entry->ip)
+);
+
+TRACE_EVENT(ext4_journal_start_inode,
+ TP_PROTO(struct inode *inode, int blocks, int rsv_blocks,
+ int revoke_creds, int type, unsigned long IP),
+
+ TP_ARGS(inode, blocks, rsv_blocks, revoke_creds, type, IP),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, ino )
+ __field( dev_t, dev )
+ __field( unsigned long, ip )
+ __field( int, blocks )
+ __field( int, rsv_blocks )
+ __field( int, revoke_creds )
+ __field( int, type )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ip = IP;
+ __entry->blocks = blocks;
+ __entry->rsv_blocks = rsv_blocks;
+ __entry->revoke_creds = revoke_creds;
+ __entry->type = type;
+ __entry->ino = inode->i_ino;
),
- TP_printk("dev %d,%d blocks %d, rsv_blocks %d, revoke_creds %d, "
- "caller %pS", MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->blocks, __entry->rsv_blocks, __entry->revoke_creds,
+ TP_printk("dev %d,%d blocks %d, rsv_blocks %d, revoke_creds %d,"
+ " type %d, ino %lu, caller %pS", MAJOR(__entry->dev),
+ MINOR(__entry->dev), __entry->blocks, __entry->rsv_blocks,
+ __entry->revoke_creds, __entry->type, __entry->ino,
(void *)__entry->ip)
);
@@ -2764,7 +2801,7 @@ TRACE_EVENT(ext4_fc_stats,
),
TP_printk("dev %d,%d fc ineligible reasons:\n"
- "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u "
+ "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u"
"num_commits:%lu, ineligible: %lu, numblks: %lu",
MAJOR(__entry->dev), MINOR(__entry->dev),
FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR),
@@ -2776,6 +2813,7 @@ TRACE_EVENT(ext4_fc_stats,
FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR),
FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE),
FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA),
+ FC_REASON_NAME_STAT(EXT4_FC_REASON_ENCRYPTED_FILENAME),
__entry->fc_commits, __entry->fc_ineligible_commits,
__entry->fc_numblks)
);
diff --git a/include/trace/events/fscache.h b/include/trace/events/fscache.h
index c078c48a8e6d..a6190aa1b406 100644
--- a/include/trace/events/fscache.h
+++ b/include/trace/events/fscache.h
@@ -66,6 +66,7 @@ enum fscache_cookie_trace {
fscache_cookie_put_work,
fscache_cookie_see_active,
fscache_cookie_see_lru_discard,
+ fscache_cookie_see_lru_discard_clear,
fscache_cookie_see_lru_do_one,
fscache_cookie_see_relinquish,
fscache_cookie_see_withdraw,
@@ -149,6 +150,7 @@ enum fscache_access_trace {
EM(fscache_cookie_put_work, "PQ work ") \
EM(fscache_cookie_see_active, "- activ") \
EM(fscache_cookie_see_lru_discard, "- x-lru") \
+ EM(fscache_cookie_see_lru_discard_clear,"- lrudc") \
EM(fscache_cookie_see_lru_do_one, "- lrudo") \
EM(fscache_cookie_see_relinquish, "- x-rlq") \
EM(fscache_cookie_see_withdraw, "- x-wth") \
diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
index 935af4947917..760455dfa860 100644
--- a/include/trace/events/huge_memory.h
+++ b/include/trace/events/huge_memory.h
@@ -171,15 +171,15 @@ TRACE_EVENT(mm_collapse_huge_page_swapin,
TRACE_EVENT(mm_khugepaged_scan_file,
- TP_PROTO(struct mm_struct *mm, struct page *page, const char *filename,
+ TP_PROTO(struct mm_struct *mm, struct page *page, struct file *file,
int present, int swap, int result),
- TP_ARGS(mm, page, filename, present, swap, result),
+ TP_ARGS(mm, page, file, present, swap, result),
TP_STRUCT__entry(
__field(struct mm_struct *, mm)
__field(unsigned long, pfn)
- __string(filename, filename)
+ __string(filename, file->f_path.dentry->d_iname)
__field(int, present)
__field(int, swap)
__field(int, result)
@@ -188,7 +188,7 @@ TRACE_EVENT(mm_khugepaged_scan_file,
TP_fast_assign(
__entry->mm = mm;
__entry->pfn = page ? page_to_pfn(page) : -1;
- __assign_str(filename, filename);
+ __assign_str(filename, file->f_path.dentry->d_iname);
__entry->present = present;
__entry->swap = swap;
__entry->result = result;
diff --git a/include/trace/events/iocost.h b/include/trace/events/iocost.h
index 6d1626e7a4ce..af8bfed528fc 100644
--- a/include/trace/events/iocost.h
+++ b/include/trace/events/iocost.h
@@ -38,7 +38,7 @@ DECLARE_EVENT_CLASS(iocost_iocg_state,
__assign_str(cgroup, path);
__entry->now = now->now;
__entry->vnow = now->vnow;
- __entry->vrate = now->vrate;
+ __entry->vrate = iocg->ioc->vtime_base_rate;
__entry->last_period = last_period;
__entry->cur_period = cur_period;
__entry->vtime = vtime;
@@ -160,7 +160,7 @@ TRACE_EVENT(iocost_ioc_vrate_adj,
TP_fast_assign(
__assign_str(devname, ioc_name(ioc));
- __entry->old_vrate = atomic64_read(&ioc->vtime_rate);
+ __entry->old_vrate = ioc->vtime_base_rate;
__entry->new_vrate = new_vrate;
__entry->busy_level = ioc->busy_level;
__entry->read_missed_ppm = missed_ppm[READ];
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
index 99f783c384bb..8f5ee380d309 100644
--- a/include/trace/events/jbd2.h
+++ b/include/trace/events/jbd2.h
@@ -40,7 +40,7 @@ DECLARE_EVENT_CLASS(jbd2_commit,
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
- __field( int, transaction )
+ __field( tid_t, transaction )
),
TP_fast_assign(
@@ -49,7 +49,7 @@ DECLARE_EVENT_CLASS(jbd2_commit,
__entry->transaction = commit_transaction->t_tid;
),
- TP_printk("dev %d,%d transaction %d sync %d",
+ TP_printk("dev %d,%d transaction %u sync %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit)
);
@@ -97,8 +97,8 @@ TRACE_EVENT(jbd2_end_commit,
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
- __field( int, transaction )
- __field( int, head )
+ __field( tid_t, transaction )
+ __field( tid_t, head )
),
TP_fast_assign(
@@ -108,7 +108,7 @@ TRACE_EVENT(jbd2_end_commit,
__entry->head = journal->j_tail_sequence;
),
- TP_printk("dev %d,%d transaction %d sync %d head %d",
+ TP_printk("dev %d,%d transaction %u sync %d head %u",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit, __entry->head)
);
@@ -134,14 +134,14 @@ TRACE_EVENT(jbd2_submit_inode_data,
);
DECLARE_EVENT_CLASS(jbd2_handle_start_class,
- TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
+ TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
unsigned int line_no, int requested_blocks),
TP_ARGS(dev, tid, type, line_no, requested_blocks),
TP_STRUCT__entry(
__field( dev_t, dev )
- __field( unsigned long, tid )
+ __field( tid_t, tid )
__field( unsigned int, type )
__field( unsigned int, line_no )
__field( int, requested_blocks)
@@ -155,28 +155,28 @@ DECLARE_EVENT_CLASS(jbd2_handle_start_class,
__entry->requested_blocks = requested_blocks;
),
- TP_printk("dev %d,%d tid %lu type %u line_no %u "
+ TP_printk("dev %d,%d tid %u type %u line_no %u "
"requested_blocks %d",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
__entry->type, __entry->line_no, __entry->requested_blocks)
);
DEFINE_EVENT(jbd2_handle_start_class, jbd2_handle_start,
- TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
+ TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
unsigned int line_no, int requested_blocks),
TP_ARGS(dev, tid, type, line_no, requested_blocks)
);
DEFINE_EVENT(jbd2_handle_start_class, jbd2_handle_restart,
- TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
+ TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
unsigned int line_no, int requested_blocks),
TP_ARGS(dev, tid, type, line_no, requested_blocks)
);
TRACE_EVENT(jbd2_handle_extend,
- TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
+ TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
unsigned int line_no, int buffer_credits,
int requested_blocks),
@@ -184,7 +184,7 @@ TRACE_EVENT(jbd2_handle_extend,
TP_STRUCT__entry(
__field( dev_t, dev )
- __field( unsigned long, tid )
+ __field( tid_t, tid )
__field( unsigned int, type )
__field( unsigned int, line_no )
__field( int, buffer_credits )
@@ -200,7 +200,7 @@ TRACE_EVENT(jbd2_handle_extend,
__entry->requested_blocks = requested_blocks;
),
- TP_printk("dev %d,%d tid %lu type %u line_no %u "
+ TP_printk("dev %d,%d tid %u type %u line_no %u "
"buffer_credits %d requested_blocks %d",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
__entry->type, __entry->line_no, __entry->buffer_credits,
@@ -208,7 +208,7 @@ TRACE_EVENT(jbd2_handle_extend,
);
TRACE_EVENT(jbd2_handle_stats,
- TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
+ TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
unsigned int line_no, int interval, int sync,
int requested_blocks, int dirtied_blocks),
@@ -217,7 +217,7 @@ TRACE_EVENT(jbd2_handle_stats,
TP_STRUCT__entry(
__field( dev_t, dev )
- __field( unsigned long, tid )
+ __field( tid_t, tid )
__field( unsigned int, type )
__field( unsigned int, line_no )
__field( int, interval )
@@ -237,7 +237,7 @@ TRACE_EVENT(jbd2_handle_stats,
__entry->dirtied_blocks = dirtied_blocks;
),
- TP_printk("dev %d,%d tid %lu type %u line_no %u interval %d "
+ TP_printk("dev %d,%d tid %u type %u line_no %u interval %d "
"sync %d requested_blocks %d dirtied_blocks %d",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
__entry->type, __entry->line_no, __entry->interval,
@@ -246,14 +246,14 @@ TRACE_EVENT(jbd2_handle_stats,
);
TRACE_EVENT(jbd2_run_stats,
- TP_PROTO(dev_t dev, unsigned long tid,
+ TP_PROTO(dev_t dev, tid_t tid,
struct transaction_run_stats_s *stats),
TP_ARGS(dev, tid, stats),
TP_STRUCT__entry(
__field( dev_t, dev )
- __field( unsigned long, tid )
+ __field( tid_t, tid )
__field( unsigned long, wait )
__field( unsigned long, request_delay )
__field( unsigned long, running )
@@ -279,7 +279,7 @@ TRACE_EVENT(jbd2_run_stats,
__entry->blocks_logged = stats->rs_blocks_logged;
),
- TP_printk("dev %d,%d tid %lu wait %u request_delay %u running %u "
+ TP_printk("dev %d,%d tid %u wait %u request_delay %u running %u "
"locked %u flushing %u logging %u handle_count %u "
"blocks %u blocks_logged %u",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
@@ -294,14 +294,14 @@ TRACE_EVENT(jbd2_run_stats,
);
TRACE_EVENT(jbd2_checkpoint_stats,
- TP_PROTO(dev_t dev, unsigned long tid,
+ TP_PROTO(dev_t dev, tid_t tid,
struct transaction_chp_stats_s *stats),
TP_ARGS(dev, tid, stats),
TP_STRUCT__entry(
__field( dev_t, dev )
- __field( unsigned long, tid )
+ __field( tid_t, tid )
__field( unsigned long, chp_time )
__field( __u32, forced_to_close )
__field( __u32, written )
@@ -317,7 +317,7 @@ TRACE_EVENT(jbd2_checkpoint_stats,
__entry->dropped = stats->cs_dropped;
),
- TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u "
+ TP_printk("dev %d,%d tid %u chp_time %u forced_to_close %u "
"written %u dropped %u",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
jiffies_to_msecs(__entry->chp_time),
diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h
index c9048f3e471b..3f121eed369e 100644
--- a/include/trace/events/rpcgss.h
+++ b/include/trace/events/rpcgss.h
@@ -13,7 +13,7 @@
#include <linux/tracepoint.h>
-#include <trace/events/sunrpc_base.h>
+#include <trace/misc/sunrpc.h>
/**
** GSS-API related trace events
diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h
index fcd3b3f1020a..8f461e04e5f0 100644
--- a/include/trace/events/rpcrdma.h
+++ b/include/trace/events/rpcrdma.h
@@ -15,8 +15,8 @@
#include <linux/tracepoint.h>
#include <rdma/ib_cm.h>
-#include <trace/events/rdma.h>
-#include <trace/events/sunrpc_base.h>
+#include <trace/misc/rdma.h>
+#include <trace/misc/sunrpc.h>
/**
** Event classes
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
index f48f2ab9d238..37604e0e5963 100644
--- a/include/trace/events/sunrpc.h
+++ b/include/trace/events/sunrpc.h
@@ -14,7 +14,7 @@
#include <linux/net.h>
#include <linux/tracepoint.h>
-#include <trace/events/sunrpc_base.h>
+#include <trace/misc/sunrpc.h>
TRACE_DEFINE_ENUM(SOCK_STREAM);
TRACE_DEFINE_ENUM(SOCK_DGRAM);
@@ -1666,11 +1666,13 @@ TRACE_DEFINE_ENUM(SVC_COMPLETE);
#define SVC_RQST_ENDPOINT_VARARGS \
__entry->xid, __get_sockaddr(server), __get_sockaddr(client)
-TRACE_EVENT(svc_authenticate,
+TRACE_EVENT_CONDITION(svc_authenticate,
TP_PROTO(const struct svc_rqst *rqst, int auth_res),
TP_ARGS(rqst, auth_res),
+ TP_CONDITION(auth_res != SVC_OK && auth_res != SVC_COMPLETE),
+
TP_STRUCT__entry(
SVC_RQST_ENDPOINT_FIELDS(rqst)
diff --git a/include/trace/events/fs.h b/include/trace/misc/fs.h
index 738b97f22f36..738b97f22f36 100644
--- a/include/trace/events/fs.h
+++ b/include/trace/misc/fs.h
diff --git a/include/trace/events/nfs.h b/include/trace/misc/nfs.h
index 09ffdbb04134..0d9d48dca38a 100644
--- a/include/trace/events/nfs.h
+++ b/include/trace/misc/nfs.h
@@ -360,6 +360,18 @@ TRACE_DEFINE_ENUM(IOMODE_ANY);
{ IOMODE_RW, "RW" }, \
{ IOMODE_ANY, "ANY" })
+#define show_rca_mask(x) \
+ __print_flags(x, "|", \
+ { BIT(RCA4_TYPE_MASK_RDATA_DLG), "RDATA_DLG" }, \
+ { BIT(RCA4_TYPE_MASK_WDATA_DLG), "WDATA_DLG" }, \
+ { BIT(RCA4_TYPE_MASK_DIR_DLG), "DIR_DLG" }, \
+ { BIT(RCA4_TYPE_MASK_FILE_LAYOUT), "FILE_LAYOUT" }, \
+ { BIT(RCA4_TYPE_MASK_BLK_LAYOUT), "BLK_LAYOUT" }, \
+ { BIT(RCA4_TYPE_MASK_OBJ_LAYOUT_MIN), "OBJ_LAYOUT_MIN" }, \
+ { BIT(RCA4_TYPE_MASK_OBJ_LAYOUT_MAX), "OBJ_LAYOUT_MAX" }, \
+ { BIT(RCA4_TYPE_MASK_OTHER_LAYOUT_MIN), "OTHER_LAYOUT_MIN" }, \
+ { BIT(RCA4_TYPE_MASK_OTHER_LAYOUT_MAX), "OTHER_LAYOUT_MAX" })
+
#define show_nfs4_seq4_status(x) \
__print_flags(x, "|", \
{ SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
diff --git a/include/trace/events/rdma.h b/include/trace/misc/rdma.h
index 81bb454fc288..81bb454fc288 100644
--- a/include/trace/events/rdma.h
+++ b/include/trace/misc/rdma.h
diff --git a/include/trace/events/sunrpc_base.h b/include/trace/misc/sunrpc.h
index 588557d07ea8..588557d07ea8 100644
--- a/include/trace/events/sunrpc_base.h
+++ b/include/trace/misc/sunrpc.h
diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
index 0d93ec132ebb..4038abe8505a 100644
--- a/include/uapi/drm/amdgpu_drm.h
+++ b/include/uapi/drm/amdgpu_drm.h
@@ -144,6 +144,20 @@ extern "C" {
* content.
*/
#define AMDGPU_GEM_CREATE_DISCARDABLE (1 << 12)
+/* Flag that BO is shared coherently between multiple devices or CPU threads.
+ * May depend on GPU instructions to flush caches explicitly
+ *
+ * This influences the choice of MTYPE in the PTEs on GFXv9 and later GPUs and
+ * may override the MTYPE selected in AMDGPU_VA_OP_MAP.
+ */
+#define AMDGPU_GEM_CREATE_COHERENT (1 << 13)
+/* Flag that BO should not be cached by GPU. Coherent without having to flush
+ * GPU caches explicitly
+ *
+ * This influences the choice of MTYPE in the PTEs on GFXv9 and later GPUs and
+ * may override the MTYPE selected in AMDGPU_VA_OP_MAP.
+ */
+#define AMDGPU_GEM_CREATE_UNCACHED (1 << 14)
struct drm_amdgpu_gem_create_in {
/** the requested memory size */
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 868d6909b718..bc056f2d537d 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -744,6 +744,35 @@ extern "C" {
*/
#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
+/*
+ * Vivante TS (tile-status) buffer modifiers. They can be combined with all of
+ * the color buffer tiling modifiers defined above. When TS is present it's a
+ * separate buffer containing the clear/compression status of each tile. The
+ * modifiers are defined as VIVANTE_MOD_TS_c_s, where c is the color buffer
+ * tile size in bytes covered by one entry in the status buffer and s is the
+ * number of status bits per entry.
+ * We reserve the top 8 bits of the Vivante modifier space for tile status
+ * clear/compression modifiers, as future cores might add some more TS layout
+ * variations.
+ */
+#define VIVANTE_MOD_TS_64_4 (1ULL << 48)
+#define VIVANTE_MOD_TS_64_2 (2ULL << 48)
+#define VIVANTE_MOD_TS_128_4 (3ULL << 48)
+#define VIVANTE_MOD_TS_256_4 (4ULL << 48)
+#define VIVANTE_MOD_TS_MASK (0xfULL << 48)
+
+/*
+ * Vivante compression modifiers. Those depend on a TS modifier being present
+ * as the TS bits get reinterpreted as compression tags instead of simple
+ * clear markers when compression is enabled.
+ */
+#define VIVANTE_MOD_COMP_DEC400 (1ULL << 52)
+#define VIVANTE_MOD_COMP_MASK (0xfULL << 52)
+
+/* Masking out the extension bits will yield the base modifier. */
+#define VIVANTE_MOD_EXT_MASK (VIVANTE_MOD_TS_MASK | \
+ VIVANTE_MOD_COMP_MASK)
+
/* NVIDIA frame buffer modifiers */
/*
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index fa953309d9ce..46becedf5b2f 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -935,12 +935,31 @@ struct hdr_output_metadata {
};
};
+/**
+ * DRM_MODE_PAGE_FLIP_EVENT
+ *
+ * Request that the kernel sends back a vblank event (see
+ * struct drm_event_vblank) with the &DRM_EVENT_FLIP_COMPLETE type when the
+ * page-flip is done.
+ */
#define DRM_MODE_PAGE_FLIP_EVENT 0x01
+/**
+ * DRM_MODE_PAGE_FLIP_ASYNC
+ *
+ * Request that the page-flip is performed as soon as possible, ie. with no
+ * delay due to waiting for vblank. This may cause tearing to be visible on
+ * the screen.
+ */
#define DRM_MODE_PAGE_FLIP_ASYNC 0x02
#define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4
#define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8
#define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \
DRM_MODE_PAGE_FLIP_TARGET_RELATIVE)
+/**
+ * DRM_MODE_PAGE_FLIP_FLAGS
+ *
+ * Bitmask of flags suitable for &drm_mode_crtc_page_flip_target.flags.
+ */
#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \
DRM_MODE_PAGE_FLIP_ASYNC | \
DRM_MODE_PAGE_FLIP_TARGET)
@@ -1034,11 +1053,53 @@ struct drm_mode_destroy_dumb {
__u32 handle;
};
-/* page-flip flags are valid, plus: */
+/**
+ * DRM_MODE_ATOMIC_TEST_ONLY
+ *
+ * Do not apply the atomic commit, instead check whether the hardware supports
+ * this configuration.
+ *
+ * See &drm_mode_config_funcs.atomic_check for more details on test-only
+ * commits.
+ */
#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
+/**
+ * DRM_MODE_ATOMIC_NONBLOCK
+ *
+ * Do not block while applying the atomic commit. The &DRM_IOCTL_MODE_ATOMIC
+ * IOCTL returns immediately instead of waiting for the changes to be applied
+ * in hardware. Note, the driver will still check that the update can be
+ * applied before retuning.
+ */
#define DRM_MODE_ATOMIC_NONBLOCK 0x0200
+/**
+ * DRM_MODE_ATOMIC_ALLOW_MODESET
+ *
+ * Allow the update to result in temporary or transient visible artifacts while
+ * the update is being applied. Applying the update may also take significantly
+ * more time than a page flip. All visual artifacts will disappear by the time
+ * the update is completed, as signalled through the vblank event's timestamp
+ * (see struct drm_event_vblank).
+ *
+ * This flag must be set when the KMS update might cause visible artifacts.
+ * Without this flag such KMS update will return a EINVAL error. What kind of
+ * update may cause visible artifacts depends on the driver and the hardware.
+ * User-space that needs to know beforehand if an update might cause visible
+ * artifacts can use &DRM_MODE_ATOMIC_TEST_ONLY without
+ * &DRM_MODE_ATOMIC_ALLOW_MODESET to see if it fails.
+ *
+ * To the best of the driver's knowledge, visual artifacts are guaranteed to
+ * not appear when this flag is not set. Some sinks might display visual
+ * artifacts outside of the driver's control.
+ */
#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
+/**
+ * DRM_MODE_ATOMIC_FLAGS
+ *
+ * Bitfield of flags accepted by the &DRM_IOCTL_MODE_ATOMIC IOCTL in
+ * &drm_mode_atomic.flags.
+ */
#define DRM_MODE_ATOMIC_FLAGS (\
DRM_MODE_PAGE_FLIP_EVENT |\
DRM_MODE_PAGE_FLIP_ASYNC |\
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 520ad2691a99..8df261c5ab9b 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -645,6 +645,22 @@ typedef struct drm_i915_irq_wait {
*/
#define I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP (1ul << 5)
+/*
+ * Query the status of HuC load.
+ *
+ * The query can fail in the following scenarios with the listed error codes:
+ * -ENODEV if HuC is not present on this platform,
+ * -EOPNOTSUPP if HuC firmware usage is disabled,
+ * -ENOPKG if HuC firmware fetch failed,
+ * -ENOEXEC if HuC firmware is invalid or mismatched,
+ * -ENOMEM if i915 failed to prepare the FW objects for transfer to the uC,
+ * -EIO if the FW transfer or the FW authentication failed.
+ *
+ * If the IOCTL is successful, the returned parameter will be set to one of the
+ * following values:
+ * * 0 if HuC firmware load is not complete,
+ * * 1 if HuC firmware is authenticated and running.
+ */
#define I915_PARAM_HUC_STATUS 42
/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of
@@ -749,6 +765,12 @@ typedef struct drm_i915_irq_wait {
/* Query if the kernel supports the I915_USERPTR_PROBE flag. */
#define I915_PARAM_HAS_USERPTR_PROBE 56
+/*
+ * Frequency of the timestamps in OA reports. This used to be the same as the CS
+ * timestamp frequency, but differs on some platforms.
+ */
+#define I915_PARAM_OA_TIMESTAMP_FREQUENCY 57
+
/* Must be kept compact -- no holes and well documented */
/**
@@ -2650,6 +2672,10 @@ enum drm_i915_oa_format {
I915_OA_FORMAT_A12_B8_C8,
I915_OA_FORMAT_A32u40_A4u32_B8_C8,
+ /* DG2 */
+ I915_OAR_FORMAT_A32u40_A4u32_B8_C8,
+ I915_OA_FORMAT_A24u40_A14u32_B8_C8,
+
I915_OA_FORMAT_MAX /* non-ABI */
};
@@ -3493,27 +3519,13 @@ struct drm_i915_gem_create_ext {
*
* The (page-aligned) allocated size for the object will be returned.
*
- * DG2 64K min page size implications:
- *
- * On discrete platforms, starting from DG2, we have to contend with GTT
- * page size restrictions when dealing with I915_MEMORY_CLASS_DEVICE
- * objects. Specifically the hardware only supports 64K or larger GTT
- * page sizes for such memory. The kernel will already ensure that all
- * I915_MEMORY_CLASS_DEVICE memory is allocated using 64K or larger page
- * sizes underneath.
- *
- * Note that the returned size here will always reflect any required
- * rounding up done by the kernel, i.e 4K will now become 64K on devices
- * such as DG2. The kernel will always select the largest minimum
- * page-size for the set of possible placements as the value to use when
- * rounding up the @size.
- *
- * Special DG2 GTT address alignment requirement:
- *
- * The GTT alignment will also need to be at least 2M for such objects.
+ * On platforms like DG2/ATS the kernel will always use 64K or larger
+ * pages for I915_MEMORY_CLASS_DEVICE. The kernel also requires a
+ * minimum of 64K GTT alignment for such objects.
*
- * Note that due to how the hardware implements 64K GTT page support, we
- * have some further complications:
+ * NOTE: Previously the ABI here required a minimum GTT alignment of 2M
+ * on DG2/ATS, due to how the hardware implemented 64K GTT page support,
+ * where we had the following complications:
*
* 1) The entire PDE (which covers a 2MB virtual address range), must
* contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same
@@ -3522,12 +3534,10 @@ struct drm_i915_gem_create_ext {
* 2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM
* objects.
*
- * To keep things simple for userland, we mandate that any GTT mappings
- * must be aligned to and rounded up to 2MB. The kernel will internally
- * pad them out to the next 2MB boundary. As this only wastes virtual
- * address space and avoids userland having to copy any needlessly
- * complicated PDE sharing scheme (coloring) and only affects DG2, this
- * is deemed to be a good compromise.
+ * However on actual production HW this was completely changed to now
+ * allow setting a TLB hint at the PTE level (see PS64), which is a lot
+ * more flexible than the above. With this the 2M restriction was
+ * dropped where we now only require 64K.
*/
__u64 size;
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 3c7b097c4e3d..f54b48ef6a2d 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -138,6 +138,7 @@ struct drm_msm_gem_new {
#define MSM_INFO_SET_NAME 0x02 /* set the debug name (by pointer) */
#define MSM_INFO_GET_NAME 0x03 /* get debug name, returned by pointer */
#define MSM_INFO_SET_IOVA 0x04 /* set the iova, passed by value */
+#define MSM_INFO_GET_FLAGS 0x05 /* get the MSM_BO_x flags */
struct drm_msm_gem_info {
__u32 handle; /* in */
diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h
index 6f93c915cc88..9f231d40a146 100644
--- a/include/uapi/drm/panfrost_drm.h
+++ b/include/uapi/drm/panfrost_drm.h
@@ -254,7 +254,7 @@ struct panfrost_dump_object_header {
__u64 nbos;
} reghdr;
- struct pan_bomap_hdr {
+ struct {
__u32 valid;
__u64 iova;
__u32 data[2];
diff --git a/include/uapi/linux/aspeed-video.h b/include/uapi/linux/aspeed-video.h
new file mode 100644
index 000000000000..6586a65548c4
--- /dev/null
+++ b/include/uapi/linux/aspeed-video.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2021 ASPEED Technology Inc.
+ */
+
+#ifndef _UAPI_LINUX_ASPEED_VIDEO_H
+#define _UAPI_LINUX_ASPEED_VIDEO_H
+
+#include <linux/v4l2-controls.h>
+
+#define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 1)
+#define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 2)
+
+#endif /* _UAPI_LINUX_ASPEED_VIDEO_H */
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 7c1dc818b1d5..d676ed2b246e 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -187,7 +187,7 @@
#define AUDIT_MAX_KEY_LEN 256
#define AUDIT_BITMASK_SIZE 64
#define AUDIT_WORD(nr) ((__u32)((nr)/32))
-#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
+#define AUDIT_BIT(nr) (1U << ((nr) - AUDIT_WORD(nr)*32))
#define AUDIT_SYSCALL_CLASSES 16
#define AUDIT_CLASS_DIR_WRITE 0
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 5655e89b962b..b4f0f9531119 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -19,8 +19,14 @@
#ifndef _UAPI_LINUX_BTRFS_H
#define _UAPI_LINUX_BTRFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <linux/types.h>
#include <linux/ioctl.h>
+#include <linux/fs.h>
#define BTRFS_IOCTL_MAGIC 0x94
#define BTRFS_VOL_NAME_MAX 255
@@ -333,6 +339,12 @@ struct btrfs_ioctl_feature_flags {
*/
struct btrfs_balance_args {
__u64 profiles;
+
+ /*
+ * usage filter
+ * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N'
+ * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max
+ */
union {
__u64 usage;
struct {
@@ -549,7 +561,7 @@ struct btrfs_ioctl_search_header {
__u64 offset;
__u32 type;
__u32 len;
-};
+} __attribute__ ((__may_alias__));
#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
/*
@@ -562,6 +574,10 @@ struct btrfs_ioctl_search_args {
char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
};
+/*
+ * Extended version of TREE_SEARCH ioctl that can return more than 4k of bytes.
+ * The allocated size of the buffer is set in buf_size.
+ */
struct btrfs_ioctl_search_args_v2 {
struct btrfs_ioctl_search_key key; /* in/out - search parameters */
__u64 buf_size; /* in - size of buffer
@@ -570,10 +586,11 @@ struct btrfs_ioctl_search_args_v2 {
__u64 buf[]; /* out - found items */
};
+/* With a @src_length of zero, the range from @src_offset->EOF is cloned! */
struct btrfs_ioctl_clone_range_args {
- __s64 src_fd;
- __u64 src_offset, src_length;
- __u64 dest_offset;
+ __s64 src_fd;
+ __u64 src_offset, src_length;
+ __u64 dest_offset;
};
/*
@@ -677,8 +694,11 @@ struct btrfs_ioctl_logical_ino_args {
/* struct btrfs_data_container *inodes; out */
__u64 inodes;
};
-/* Return every ref to the extent, not just those containing logical block.
- * Requires logical == extent bytenr. */
+
+/*
+ * Return every ref to the extent, not just those containing logical block.
+ * Requires logical == extent bytenr.
+ */
#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0)
enum btrfs_dev_stat_values {
@@ -1144,4 +1164,8 @@ enum btrfs_err_code {
#define BTRFS_IOC_ENCODED_WRITE _IOW(BTRFS_IOCTL_MAGIC, 64, \
struct btrfs_ioctl_encoded_io_args)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _UAPI_LINUX_BTRFS_H */
diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h
index 1f7a38ec6ac3..ab38d0f411fa 100644
--- a/include/uapi/linux/btrfs_tree.h
+++ b/include/uapi/linux/btrfs_tree.h
@@ -10,6 +10,23 @@
#include <stddef.h>
#endif
+/* ASCII for _BHRfS_M, no terminating nul */
+#define BTRFS_MAGIC 0x4D5F53665248425FULL
+
+#define BTRFS_MAX_LEVEL 8
+
+/*
+ * We can actually store much bigger names, but lets not confuse the rest of
+ * linux.
+ */
+#define BTRFS_NAME_LEN 255
+
+/*
+ * Theoretical limit is larger, but we keep this down to a sane value. That
+ * should limit greatly the possibility of collisions on inode ref items.
+ */
+#define BTRFS_LINK_MAX 65535U
+
/*
* This header contains the structure definitions and constants used
* by file system objects that can be retrieved using
@@ -359,6 +376,50 @@ enum btrfs_csum_type {
#define BTRFS_FT_SYMLINK 7
#define BTRFS_FT_XATTR 8
#define BTRFS_FT_MAX 9
+/* Directory contains encrypted data */
+#define BTRFS_FT_ENCRYPTED 0x80
+
+static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
+{
+ return flags & ~BTRFS_FT_ENCRYPTED;
+}
+
+/*
+ * Inode flags
+ */
+#define BTRFS_INODE_NODATASUM (1U << 0)
+#define BTRFS_INODE_NODATACOW (1U << 1)
+#define BTRFS_INODE_READONLY (1U << 2)
+#define BTRFS_INODE_NOCOMPRESS (1U << 3)
+#define BTRFS_INODE_PREALLOC (1U << 4)
+#define BTRFS_INODE_SYNC (1U << 5)
+#define BTRFS_INODE_IMMUTABLE (1U << 6)
+#define BTRFS_INODE_APPEND (1U << 7)
+#define BTRFS_INODE_NODUMP (1U << 8)
+#define BTRFS_INODE_NOATIME (1U << 9)
+#define BTRFS_INODE_DIRSYNC (1U << 10)
+#define BTRFS_INODE_COMPRESS (1U << 11)
+
+#define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31)
+
+#define BTRFS_INODE_FLAG_MASK \
+ (BTRFS_INODE_NODATASUM | \
+ BTRFS_INODE_NODATACOW | \
+ BTRFS_INODE_READONLY | \
+ BTRFS_INODE_NOCOMPRESS | \
+ BTRFS_INODE_PREALLOC | \
+ BTRFS_INODE_SYNC | \
+ BTRFS_INODE_IMMUTABLE | \
+ BTRFS_INODE_APPEND | \
+ BTRFS_INODE_NODUMP | \
+ BTRFS_INODE_NOATIME | \
+ BTRFS_INODE_DIRSYNC | \
+ BTRFS_INODE_COMPRESS | \
+ BTRFS_INODE_ROOT_ITEM_INIT)
+
+#define BTRFS_INODE_RO_VERITY (1U << 0)
+
+#define BTRFS_INODE_RO_FLAG_MASK (BTRFS_INODE_RO_VERITY)
/*
* The key defines the order in the tree, and so it also defines (optimal)
@@ -389,6 +450,109 @@ struct btrfs_key {
__u64 offset;
} __attribute__ ((__packed__));
+/*
+ * Every tree block (leaf or node) starts with this header.
+ */
+struct btrfs_header {
+ /* These first four must match the super block */
+ __u8 csum[BTRFS_CSUM_SIZE];
+ /* FS specific uuid */
+ __u8 fsid[BTRFS_FSID_SIZE];
+ /* Which block this node is supposed to live in */
+ __le64 bytenr;
+ __le64 flags;
+
+ /* Allowed to be different from the super from here on down */
+ __u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
+ __le64 generation;
+ __le64 owner;
+ __le32 nritems;
+ __u8 level;
+} __attribute__ ((__packed__));
+
+/*
+ * This is a very generous portion of the super block, giving us room to
+ * translate 14 chunks with 3 stripes each.
+ */
+#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
+
+/*
+ * Just in case we somehow lose the roots and are not able to mount, we store
+ * an array of the roots from previous transactions in the super.
+ */
+#define BTRFS_NUM_BACKUP_ROOTS 4
+struct btrfs_root_backup {
+ __le64 tree_root;
+ __le64 tree_root_gen;
+
+ __le64 chunk_root;
+ __le64 chunk_root_gen;
+
+ __le64 extent_root;
+ __le64 extent_root_gen;
+
+ __le64 fs_root;
+ __le64 fs_root_gen;
+
+ __le64 dev_root;
+ __le64 dev_root_gen;
+
+ __le64 csum_root;
+ __le64 csum_root_gen;
+
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le64 num_devices;
+ /* future */
+ __le64 unused_64[4];
+
+ __u8 tree_root_level;
+ __u8 chunk_root_level;
+ __u8 extent_root_level;
+ __u8 fs_root_level;
+ __u8 dev_root_level;
+ __u8 csum_root_level;
+ /* future and to align */
+ __u8 unused_8[10];
+} __attribute__ ((__packed__));
+
+/*
+ * A leaf is full of items. offset and size tell us where to find the item in
+ * the leaf (relative to the start of the data area)
+ */
+struct btrfs_item {
+ struct btrfs_disk_key key;
+ __le32 offset;
+ __le32 size;
+} __attribute__ ((__packed__));
+
+/*
+ * Leaves have an item area and a data area:
+ * [item0, item1....itemN] [free space] [dataN...data1, data0]
+ *
+ * The data is separate from the items to get the keys closer together during
+ * searches.
+ */
+struct btrfs_leaf {
+ struct btrfs_header header;
+ struct btrfs_item items[];
+} __attribute__ ((__packed__));
+
+/*
+ * All non-leaf blocks are nodes, they hold only keys and pointers to other
+ * blocks.
+ */
+struct btrfs_key_ptr {
+ struct btrfs_disk_key key;
+ __le64 blockptr;
+ __le64 generation;
+} __attribute__ ((__packed__));
+
+struct btrfs_node {
+ struct btrfs_header header;
+ struct btrfs_key_ptr ptrs[];
+} __attribute__ ((__packed__));
+
struct btrfs_dev_item {
/* the internal btrfs device id */
__le64 devid;
@@ -472,6 +636,69 @@ struct btrfs_chunk {
/* additional stripes go here */
} __attribute__ ((__packed__));
+/*
+ * The super block basically lists the main trees of the FS.
+ */
+struct btrfs_super_block {
+ /* The first 4 fields must match struct btrfs_header */
+ __u8 csum[BTRFS_CSUM_SIZE];
+ /* FS specific UUID, visible to user */
+ __u8 fsid[BTRFS_FSID_SIZE];
+ /* This block number */
+ __le64 bytenr;
+ __le64 flags;
+
+ /* Allowed to be different from the btrfs_header from here own down */
+ __le64 magic;
+ __le64 generation;
+ __le64 root;
+ __le64 chunk_root;
+ __le64 log_root;
+
+ /*
+ * This member has never been utilized since the very beginning, thus
+ * it's always 0 regardless of kernel version. We always use
+ * generation + 1 to read log tree root. So here we mark it deprecated.
+ */
+ __le64 __unused_log_root_transid;
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le64 root_dir_objectid;
+ __le64 num_devices;
+ __le32 sectorsize;
+ __le32 nodesize;
+ __le32 __unused_leafsize;
+ __le32 stripesize;
+ __le32 sys_chunk_array_size;
+ __le64 chunk_root_generation;
+ __le64 compat_flags;
+ __le64 compat_ro_flags;
+ __le64 incompat_flags;
+ __le16 csum_type;
+ __u8 root_level;
+ __u8 chunk_root_level;
+ __u8 log_root_level;
+ struct btrfs_dev_item dev_item;
+
+ char label[BTRFS_LABEL_SIZE];
+
+ __le64 cache_generation;
+ __le64 uuid_tree_generation;
+
+ /* The UUID written into btree blocks */
+ __u8 metadata_uuid[BTRFS_FSID_SIZE];
+
+ __u64 nr_global_roots;
+
+ /* Future expansion */
+ __le64 reserved[27];
+ __u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
+ struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
+
+ /* Padded to 4096 bytes */
+ __u8 padding[565];
+} __attribute__ ((__packed__));
+
#define BTRFS_FREE_SPACE_EXTENT 1
#define BTRFS_FREE_SPACE_BITMAP 2
@@ -526,6 +753,14 @@ struct btrfs_extent_item_v0 {
/* use full backrefs for extent pointers in the block */
#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8)
+#define BTRFS_BACKREF_REV_MAX 256
+#define BTRFS_BACKREF_REV_SHIFT 56
+#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \
+ BTRFS_BACKREF_REV_SHIFT)
+
+#define BTRFS_OLD_BACKREF_REV 0
+#define BTRFS_MIXED_BACKREF_REV 1
+
/*
* this flag is only used internally by scrub and may be changed at any time
* it is only declared here to avoid collisions
diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
index 463d1ba2232a..3d61a0ae055d 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -426,7 +426,7 @@ struct vfs_ns_cap_data {
*/
#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */
-#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */
+#define CAP_TO_MASK(x) (1U << ((x) & 31)) /* mask for indexed __u32 */
#endif /* _UAPI_LINUX_CAPABILITY_H */
diff --git a/include/uapi/linux/dvb/audio.h b/include/uapi/linux/dvb/audio.h
index 2f869da69171..77fb866890b4 100644
--- a/include/uapi/linux/dvb/audio.h
+++ b/include/uapi/linux/dvb/audio.h
@@ -7,21 +7,6 @@
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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 _DVBAUDIO_H_
diff --git a/include/uapi/linux/dvb/ca.h b/include/uapi/linux/dvb/ca.h
index dffa59e95ebb..4244b187cc4d 100644
--- a/include/uapi/linux/dvb/ca.h
+++ b/include/uapi/linux/dvb/ca.h
@@ -5,21 +5,6 @@
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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 _DVBCA_H_
diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h
index b4112f0b6dd3..7b16375f94e2 100644
--- a/include/uapi/linux/dvb/dmx.h
+++ b/include/uapi/linux/dvb/dmx.h
@@ -5,21 +5,6 @@
* Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 Lesser 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 _UAPI_DVBDMX_H_
diff --git a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h
index 4f9b4551c534..326f6a53f1f2 100644
--- a/include/uapi/linux/dvb/frontend.h
+++ b/include/uapi/linux/dvb/frontend.h
@@ -7,21 +7,6 @@
* Holger Waechtler <holger@convergence.de>
* Andre Draszik <ad@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 Lesser 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 _DVBFRONTEND_H_
@@ -282,7 +267,6 @@ enum fe_spectral_inversion {
/**
* enum fe_code_rate - Type of Forward Error Correction (FEC)
*
- *
* @FEC_NONE: No Forward Error Correction Code
* @FEC_1_2: Forward Error Correction Code 1/2
* @FEC_2_3: Forward Error Correction Code 2/3
@@ -296,6 +280,22 @@ enum fe_spectral_inversion {
* @FEC_3_5: Forward Error Correction Code 3/5
* @FEC_9_10: Forward Error Correction Code 9/10
* @FEC_2_5: Forward Error Correction Code 2/5
+ * @FEC_1_3: Forward Error Correction Code 1/3
+ * @FEC_1_4: Forward Error Correction Code 1/4
+ * @FEC_5_9: Forward Error Correction Code 5/9
+ * @FEC_7_9: Forward Error Correction Code 7/9
+ * @FEC_8_15: Forward Error Correction Code 8/15
+ * @FEC_11_15: Forward Error Correction Code 11/15
+ * @FEC_13_18: Forward Error Correction Code 13/18
+ * @FEC_9_20: Forward Error Correction Code 9/20
+ * @FEC_11_20: Forward Error Correction Code 11/20
+ * @FEC_23_36: Forward Error Correction Code 23/36
+ * @FEC_25_36: Forward Error Correction Code 25/36
+ * @FEC_13_45: Forward Error Correction Code 13/45
+ * @FEC_26_45: Forward Error Correction Code 26/45
+ * @FEC_28_45: Forward Error Correction Code 28/45
+ * @FEC_32_45: Forward Error Correction Code 32/45
+ * @FEC_77_90: Forward Error Correction Code 77/90
*
* Please note that not all FEC types are supported by a given standard.
*/
@@ -313,6 +313,22 @@ enum fe_code_rate {
FEC_3_5,
FEC_9_10,
FEC_2_5,
+ FEC_1_3,
+ FEC_1_4,
+ FEC_5_9,
+ FEC_7_9,
+ FEC_8_15,
+ FEC_11_15,
+ FEC_13_18,
+ FEC_9_20,
+ FEC_11_20,
+ FEC_23_36,
+ FEC_25_36,
+ FEC_13_45,
+ FEC_26_45,
+ FEC_28_45,
+ FEC_32_45,
+ FEC_77_90,
};
/**
@@ -331,6 +347,13 @@ enum fe_code_rate {
* @APSK_32: 32-APSK modulation
* @DQPSK: DQPSK modulation
* @QAM_4_NR: 4-QAM-NR modulation
+ * @QAM_1024: 1024-QAM modulation
+ * @QAM_4096: 4096-QAM modulation
+ * @APSK_8_L: 8APSK-L modulation
+ * @APSK_16_L: 16APSK-L modulation
+ * @APSK_32_L: 32APSK-L modulation
+ * @APSK_64: 64APSK modulation
+ * @APSK_64_L: 64APSK-L modulation
*
* Please note that not all modulations are supported by a given standard.
*
@@ -350,6 +373,13 @@ enum fe_modulation {
APSK_32,
DQPSK,
QAM_4_NR,
+ QAM_1024,
+ QAM_4096,
+ APSK_8_L,
+ APSK_16_L,
+ APSK_32_L,
+ APSK_64,
+ APSK_64_L,
};
/**
@@ -404,6 +434,7 @@ enum fe_transmit_mode {
* @GUARD_INTERVAL_PN420: PN length 420 (1/4)
* @GUARD_INTERVAL_PN595: PN length 595 (1/6)
* @GUARD_INTERVAL_PN945: PN length 945 (1/9)
+ * @GUARD_INTERVAL_1_64: Guard interval 1/64
*
* Please note that not all guard intervals are supported by a given standard.
*/
@@ -419,6 +450,7 @@ enum fe_guard_interval {
GUARD_INTERVAL_PN420,
GUARD_INTERVAL_PN595,
GUARD_INTERVAL_PN945,
+ GUARD_INTERVAL_1_64,
};
/**
@@ -571,6 +603,9 @@ enum fe_pilot {
* @ROLLOFF_20: Roloff factor: α=20%
* @ROLLOFF_25: Roloff factor: α=25%
* @ROLLOFF_AUTO: Auto-detect the roloff factor.
+ * @ROLLOFF_15: Rolloff factor: α=15%
+ * @ROLLOFF_10: Rolloff factor: α=10%
+ * @ROLLOFF_5: Rolloff factor: α=5%
*
* .. note:
*
@@ -581,6 +616,9 @@ enum fe_rolloff {
ROLLOFF_20,
ROLLOFF_25,
ROLLOFF_AUTO,
+ ROLLOFF_15,
+ ROLLOFF_10,
+ ROLLOFF_5,
};
/**
@@ -594,6 +632,8 @@ enum fe_rolloff {
* Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM)
* @SYS_DVBC_ANNEX_C:
* Cable TV: DVB-C following ITU-T J.83 Annex C spec
+ * @SYS_DVBC2:
+ * Cable TV: DVB-C2
* @SYS_ISDBC:
* Cable TV: ISDB-C (no drivers yet)
* @SYS_DVBT:
@@ -611,7 +651,7 @@ enum fe_rolloff {
* @SYS_DVBS:
* Satellite TV: DVB-S
* @SYS_DVBS2:
- * Satellite TV: DVB-S2
+ * Satellite TV: DVB-S2 and DVB-S2X
* @SYS_TURBO:
* Satellite TV: DVB-S Turbo
* @SYS_ISDBS:
@@ -645,6 +685,7 @@ enum fe_delivery_system {
SYS_DVBT2,
SYS_TURBO,
SYS_DVBC_ANNEX_C,
+ SYS_DVBC2,
};
/* backward compatibility definitions for delivery systems */
@@ -720,7 +761,7 @@ enum atscmh_rs_frame_mode {
};
/**
- * enum atscmh_rs_code_mode
+ * enum atscmh_rs_code_mode - ATSC-M/H Reed Solomon modes
* @ATSCMH_RSCODE_211_187: Reed Solomon code (211,187).
* @ATSCMH_RSCODE_223_187: Reed Solomon code (223,187).
* @ATSCMH_RSCODE_235_187: Reed Solomon code (235,187).
diff --git a/include/uapi/linux/dvb/net.h b/include/uapi/linux/dvb/net.h
index 0c550ef93f2c..7cbb47ac38ef 100644
--- a/include/uapi/linux/dvb/net.h
+++ b/include/uapi/linux/dvb/net.h
@@ -5,21 +5,6 @@
* Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 Lesser 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 _DVBNET_H_
diff --git a/include/uapi/linux/dvb/osd.h b/include/uapi/linux/dvb/osd.h
index 858997c74043..6003b108ba45 100644
--- a/include/uapi/linux/dvb/osd.h
+++ b/include/uapi/linux/dvb/osd.h
@@ -7,21 +7,6 @@
* Copyright (C) 2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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 _DVBOSD_H_
diff --git a/include/uapi/linux/dvb/version.h b/include/uapi/linux/dvb/version.h
index 2c5cffe6d2a0..1a8cd038aa0b 100644
--- a/include/uapi/linux/dvb/version.h
+++ b/include/uapi/linux/dvb/version.h
@@ -4,21 +4,6 @@
*
* Copyright (C) 2000 Holger Waechtler <holger@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 Lesser 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 _DVBVERSION_H_
diff --git a/include/uapi/linux/dvb/video.h b/include/uapi/linux/dvb/video.h
index 179f1ec60af6..9910b73737e0 100644
--- a/include/uapi/linux/dvb/video.h
+++ b/include/uapi/linux/dvb/video.h
@@ -7,21 +7,6 @@
* Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 Lesser 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 _UAPI_DVBVIDEO_H_
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index c7b056af9ef0..4c6a8fa5e7ed 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -91,7 +91,7 @@ typedef __s64 Elf64_Sxword;
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
-#define DT_RPATH 15
+#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
@@ -140,9 +140,9 @@ typedef __s64 Elf64_Sxword;
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
-typedef struct dynamic{
+typedef struct dynamic {
Elf32_Sword d_tag;
- union{
+ union {
Elf32_Sword d_val;
Elf32_Addr d_ptr;
} d_un;
@@ -173,7 +173,7 @@ typedef struct elf64_rel {
Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel;
-typedef struct elf32_rela{
+typedef struct elf32_rela {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
@@ -185,7 +185,7 @@ typedef struct elf64_rela {
Elf64_Sxword r_addend; /* Constant addend used to compute value */
} Elf64_Rela;
-typedef struct elf32_sym{
+typedef struct elf32_sym {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
@@ -206,7 +206,7 @@ typedef struct elf64_sym {
#define EI_NIDENT 16
-typedef struct elf32_hdr{
+typedef struct elf32_hdr {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
@@ -246,7 +246,7 @@ typedef struct elf64_hdr {
#define PF_W 0x2
#define PF_X 0x1
-typedef struct elf32_phdr{
+typedef struct elf32_phdr {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
diff --git a/include/uapi/linux/eventpoll.h b/include/uapi/linux/eventpoll.h
index 8a3432d0f0dc..e687658843b1 100644
--- a/include/uapi/linux/eventpoll.h
+++ b/include/uapi/linux/eventpoll.h
@@ -41,6 +41,12 @@
#define EPOLLMSG (__force __poll_t)0x00000400
#define EPOLLRDHUP (__force __poll_t)0x00002000
+/*
+ * Internal flag - wakeup generated by io_uring, used to detect recursion back
+ * into the io_uring poll handler.
+ */
+#define EPOLL_URING_WAKE ((__force __poll_t)(1U << 27))
+
/* Set exclusive wakeup mode for the target file descriptor */
#define EPOLLEXCLUSIVE ((__force __poll_t)(1U << 28))
diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h
index a756b29afcc2..fd1fb0d5389d 100644
--- a/include/uapi/linux/fscrypt.h
+++ b/include/uapi/linux/fscrypt.h
@@ -26,6 +26,8 @@
#define FSCRYPT_MODE_AES_256_CTS 4
#define FSCRYPT_MODE_AES_128_CBC 5
#define FSCRYPT_MODE_AES_128_CTS 6
+#define FSCRYPT_MODE_SM4_XTS 7
+#define FSCRYPT_MODE_SM4_CTS 8
#define FSCRYPT_MODE_ADIANTUM 9
#define FSCRYPT_MODE_AES_256_HCTR2 10
/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
@@ -185,8 +187,6 @@ struct fscrypt_get_key_status_arg {
#define FS_ENCRYPTION_MODE_AES_256_CTS FSCRYPT_MODE_AES_256_CTS
#define FS_ENCRYPTION_MODE_AES_128_CBC FSCRYPT_MODE_AES_128_CBC
#define FS_ENCRYPTION_MODE_AES_128_CTS FSCRYPT_MODE_AES_128_CTS
-#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* removed */
-#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* removed */
#define FS_ENCRYPTION_MODE_ADIANTUM FSCRYPT_MODE_ADIANTUM
#define FS_KEY_DESC_PREFIX FSCRYPT_KEY_DESC_PREFIX
#define FS_KEY_DESC_PREFIX_SIZE FSCRYPT_KEY_DESC_PREFIX_SIZE
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 76ee8f9e024a..e3c54109bae9 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -197,6 +197,10 @@
*
* 7.37
* - add FUSE_TMPFILE
+ *
+ * 7.38
+ * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry
+ * - add FOPEN_PARALLEL_DIRECT_WRITES
*/
#ifndef _LINUX_FUSE_H
@@ -232,7 +236,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 37
+#define FUSE_KERNEL_MINOR_VERSION 38
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -304,6 +308,7 @@ struct fuse_file_lock {
* FOPEN_CACHE_DIR: allow caching this directory
* FOPEN_STREAM: the file is stream-like (no file position at all)
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
+ * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
@@ -311,6 +316,7 @@ struct fuse_file_lock {
#define FOPEN_CACHE_DIR (1 << 3)
#define FOPEN_STREAM (1 << 4)
#define FOPEN_NOFLUSH (1 << 5)
+#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
/**
* INIT request/reply flags
@@ -491,6 +497,12 @@ struct fuse_file_lock {
*/
#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0)
+/**
+ * notify_inval_entry flags
+ * FUSE_EXPIRE_ONLY
+ */
+#define FUSE_EXPIRE_ONLY (1 << 0)
+
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
@@ -919,7 +931,7 @@ struct fuse_notify_inval_inode_out {
struct fuse_notify_inval_entry_out {
uint64_t parent;
uint32_t namelen;
- uint32_t padding;
+ uint32_t flags;
};
struct fuse_notify_delete_out {
diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h
index 095299c75828..2b9e7feba3f3 100644
--- a/include/uapi/linux/idxd.h
+++ b/include/uapi/linux/idxd.h
@@ -29,6 +29,7 @@ enum idxd_scmd_stat {
IDXD_SCMD_WQ_NO_SIZE = 0x800e0000,
IDXD_SCMD_WQ_NO_PRIV = 0x800f0000,
IDXD_SCMD_WQ_IRQ_ERR = 0x80100000,
+ IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000,
};
#define IDXD_SCMD_SOFTERR_MASK 0x80000000
diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index f243ce665f74..07a4cb149305 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -20,6 +20,7 @@
#define _UAPI_LINUX_IN_H
#include <linux/types.h>
+#include <linux/stddef.h>
#include <linux/libc-compat.h>
#include <linux/socket.h>
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index ab7458033ee3..9d4c4078e8d0 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -222,7 +222,7 @@ enum io_uring_op {
/*
* sqe->uring_cmd_flags
- * IORING_URING_CMD_FIXED use registered buffer; pass thig flag
+ * IORING_URING_CMD_FIXED use registered buffer; pass this flag
* along with setting sqe->buf_index.
*/
#define IORING_URING_CMD_FIXED (1U << 0)
@@ -296,10 +296,28 @@ enum io_uring_op {
*
* IORING_RECVSEND_FIXED_BUF Use registered buffers, the index is stored in
* the buf_index field.
+ *
+ * IORING_SEND_ZC_REPORT_USAGE
+ * If set, SEND[MSG]_ZC should report
+ * the zerocopy usage in cqe.res
+ * for the IORING_CQE_F_NOTIF cqe.
+ * 0 is reported if zerocopy was actually possible.
+ * IORING_NOTIF_USAGE_ZC_COPIED if data was copied
+ * (at least partially).
*/
#define IORING_RECVSEND_POLL_FIRST (1U << 0)
#define IORING_RECV_MULTISHOT (1U << 1)
#define IORING_RECVSEND_FIXED_BUF (1U << 2)
+#define IORING_SEND_ZC_REPORT_USAGE (1U << 3)
+
+/*
+ * cqe.res for IORING_CQE_F_NOTIF if
+ * IORING_SEND_ZC_REPORT_USAGE was requested
+ *
+ * It should be treated as a flag, all other
+ * bits of cqe.res should be treated as reserved!
+ */
+#define IORING_NOTIF_USAGE_ZC_COPIED (1U << 31)
/*
* accept flags stored in sqe->ioprio
diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
index 961ec16a26b8..874a92349bf5 100644
--- a/include/uapi/linux/ip.h
+++ b/include/uapi/linux/ip.h
@@ -100,8 +100,10 @@ struct iphdr {
__u8 ttl;
__u8 protocol;
__sum16 check;
- __be32 saddr;
- __be32 daddr;
+ __struct_group(/* no tag */, addrs, /* no attrs */,
+ __be32 saddr;
+ __be32 daddr;
+ );
/*The options start here. */
};
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 03cdbe798fe3..81f4243bebb1 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -130,8 +130,10 @@ struct ipv6hdr {
__u8 nexthdr;
__u8 hop_limit;
- struct in6_addr saddr;
- struct in6_addr daddr;
+ __struct_group(/* no tag */, addrs, /* no attrs */,
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+ );
};
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 9c4bcc37a455..f3223f964691 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -95,8 +95,19 @@ struct landlock_path_beneath_attr {
* A file can only receive these access rights:
*
* - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file.
- * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access.
+ * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that
+ * you might additionally need the %LANDLOCK_ACCESS_FS_TRUNCATE right in order
+ * to overwrite files with :manpage:`open(2)` using ``O_TRUNC`` or
+ * :manpage:`creat(2)`.
* - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access.
+ * - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`,
+ * :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
+ * ``O_TRUNC``. Whether an opened file can be truncated with
+ * :manpage:`ftruncate(2)` is determined during :manpage:`open(2)`, in the
+ * same way as read and write permissions are checked during
+ * :manpage:`open(2)` using %LANDLOCK_ACCESS_FS_READ_FILE and
+ * %LANDLOCK_ACCESS_FS_WRITE_FILE. This access right is available since the
+ * third version of the Landlock ABI.
*
* A directory can receive access rights related to files or directories. The
* following access right is applied to the directory itself, and the
@@ -139,10 +150,9 @@ struct landlock_path_beneath_attr {
*
* It is currently not possible to restrict some file-related actions
* accessible through these syscall families: :manpage:`chdir(2)`,
- * :manpage:`truncate(2)`, :manpage:`stat(2)`, :manpage:`flock(2)`,
- * :manpage:`chmod(2)`, :manpage:`chown(2)`, :manpage:`setxattr(2)`,
- * :manpage:`utime(2)`, :manpage:`ioctl(2)`, :manpage:`fcntl(2)`,
- * :manpage:`access(2)`.
+ * :manpage:`stat(2)`, :manpage:`flock(2)`, :manpage:`chmod(2)`,
+ * :manpage:`chown(2)`, :manpage:`setxattr(2)`, :manpage:`utime(2)`,
+ * :manpage:`ioctl(2)`, :manpage:`fcntl(2)`, :manpage:`access(2)`.
* Future Landlock evolutions will enable to restrict them.
*/
/* clang-format off */
@@ -160,6 +170,7 @@ struct landlock_path_beneath_attr {
#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
+#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
/* clang-format on */
#endif /* _UAPI_LINUX_LANDLOCK_H */
diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h
index ec3323dbb927..ca9a24c874da 100644
--- a/include/uapi/linux/media-bus-format.h
+++ b/include/uapi/linux/media-bus-format.h
@@ -69,7 +69,7 @@
#define MEDIA_BUS_FMT_RGB121212_1X36 0x1019
#define MEDIA_BUS_FMT_RGB161616_1X48 0x101a
-/* YUV (including grey) - next is 0x202e */
+/* YUV (including grey) - next is 0x202f */
#define MEDIA_BUS_FMT_Y8_1X8 0x2001
#define MEDIA_BUS_FMT_UV8_1X8 0x2015
#define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002
@@ -92,6 +92,7 @@
#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e
#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f
#define MEDIA_BUS_FMT_Y14_1X14 0x202d
+#define MEDIA_BUS_FMT_Y16_1X16 0x202e
#define MEDIA_BUS_FMT_UYVY8_1X16 0x200f
#define MEDIA_BUS_FMT_VYUY8_1X16 0x2010
#define MEDIA_BUS_FMT_YUYV8_1X16 0x2011
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 57b8e2ffb1dd..82a03ea954af 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1119,6 +1119,7 @@
#define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */
#define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */
#define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */
+#define PCI_DOE_CAP_SIZEOF 0x18 /* Size of DOE register block */
/* DOE Data Object - note not actually registers */
#define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff
diff --git a/include/uapi/linux/pktcdvd.h b/include/uapi/linux/pktcdvd.h
deleted file mode 100644
index 9cbb55d21c94..000000000000
--- a/include/uapi/linux/pktcdvd.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
- * DVD-RW devices.
- *
- */
-#ifndef _UAPI__PKTCDVD_H
-#define _UAPI__PKTCDVD_H
-
-#include <linux/types.h>
-
-/*
- * 1 for normal debug messages, 2 is very verbose. 0 to turn it off.
- */
-#define PACKET_DEBUG 1
-
-#define MAX_WRITERS 8
-
-#define PKT_RB_POOL_SIZE 512
-
-/*
- * How long we should hold a non-full packet before starting data gathering.
- */
-#define PACKET_WAIT_TIME (HZ * 5 / 1000)
-
-/*
- * use drive write caching -- we need deferred error handling to be
- * able to successfully recover with this option (drive will return good
- * status as soon as the cdb is validated).
- */
-#if defined(CONFIG_CDROM_PKTCDVD_WCACHE)
-#define USE_WCACHING 1
-#else
-#define USE_WCACHING 0
-#endif
-
-/*
- * No user-servicable parts beyond this point ->
- */
-
-/*
- * device types
- */
-#define PACKET_CDR 1
-#define PACKET_CDRW 2
-#define PACKET_DVDR 3
-#define PACKET_DVDRW 4
-
-/*
- * flags
- */
-#define PACKET_WRITABLE 1 /* pd is writable */
-#define PACKET_NWA_VALID 2 /* next writable address valid */
-#define PACKET_LRA_VALID 3 /* last recorded address valid */
-#define PACKET_MERGE_SEGS 4 /* perform segment merging to keep */
- /* underlying cdrom device happy */
-
-/*
- * Disc status -- from READ_DISC_INFO
- */
-#define PACKET_DISC_EMPTY 0
-#define PACKET_DISC_INCOMPLETE 1
-#define PACKET_DISC_COMPLETE 2
-#define PACKET_DISC_OTHER 3
-
-/*
- * write type, and corresponding data block type
- */
-#define PACKET_MODE1 1
-#define PACKET_MODE2 2
-#define PACKET_BLOCK_MODE1 8
-#define PACKET_BLOCK_MODE2 10
-
-/*
- * Last session/border status
- */
-#define PACKET_SESSION_EMPTY 0
-#define PACKET_SESSION_INCOMPLETE 1
-#define PACKET_SESSION_RESERVED 2
-#define PACKET_SESSION_COMPLETE 3
-
-#define PACKET_MCN "4a656e734178626f65323030300000"
-
-#undef PACKET_USE_LS
-
-#define PKT_CTRL_CMD_SETUP 0
-#define PKT_CTRL_CMD_TEARDOWN 1
-#define PKT_CTRL_CMD_STATUS 2
-
-struct pkt_ctrl_command {
- __u32 command; /* in: Setup, teardown, status */
- __u32 dev_index; /* in/out: Device index */
- __u32 dev; /* in/out: Device nr for cdrw device */
- __u32 pkt_dev; /* in/out: Device nr for packet device */
- __u32 num_devices; /* out: Largest device index + 1 */
- __u32 padding; /* Not used */
-};
-
-/*
- * packet ioctls
- */
-#define PACKET_IOCTL_MAGIC ('X')
-#define PACKET_CTRL_CMD _IOWR(PACKET_IOCTL_MAGIC, 1, struct pkt_ctrl_command)
-
-
-#endif /* _UAPI__PKTCDVD_H */
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index 2573772e2fb3..1fed3c9294fc 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -44,6 +44,11 @@ enum opal_lock_state {
OPAL_LK = 0x04, /* 0100 */
};
+enum opal_lock_flags {
+ /* IOC_OPAL_SAVE will also store the provided key for locking */
+ OPAL_SAVE_FOR_LOCK = 0x01,
+};
+
struct opal_key {
__u8 lr;
__u8 key_len;
@@ -76,7 +81,8 @@ struct opal_user_lr_setup {
struct opal_lock_unlock {
struct opal_session_info session;
__u32 l_state;
- __u8 __align[4];
+ __u16 flags;
+ __u8 __align[2];
};
struct opal_new_pw {
diff --git a/include/uapi/linux/tdx-guest.h b/include/uapi/linux/tdx-guest.h
new file mode 100644
index 000000000000..a6a2098c08ff
--- /dev/null
+++ b/include/uapi/linux/tdx-guest.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Userspace interface for TDX guest driver
+ *
+ * Copyright (C) 2022 Intel Corporation
+ */
+
+#ifndef _UAPI_LINUX_TDX_GUEST_H_
+#define _UAPI_LINUX_TDX_GUEST_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* Length of the REPORTDATA used in TDG.MR.REPORT TDCALL */
+#define TDX_REPORTDATA_LEN 64
+
+/* Length of TDREPORT used in TDG.MR.REPORT TDCALL */
+#define TDX_REPORT_LEN 1024
+
+/**
+ * struct tdx_report_req - Request struct for TDX_CMD_GET_REPORT0 IOCTL.
+ *
+ * @reportdata: User buffer with REPORTDATA to be included into TDREPORT.
+ * Typically it can be some nonce provided by attestation
+ * service, so the generated TDREPORT can be uniquely verified.
+ * @tdreport: User buffer to store TDREPORT output from TDCALL[TDG.MR.REPORT].
+ */
+struct tdx_report_req {
+ __u8 reportdata[TDX_REPORTDATA_LEN];
+ __u8 tdreport[TDX_REPORT_LEN];
+};
+
+/*
+ * TDX_CMD_GET_REPORT0 - Get TDREPORT0 (a.k.a. TDREPORT subtype 0) using
+ * TDCALL[TDG.MR.REPORT]
+ *
+ * Return 0 on success, -EIO on TDCALL execution failure, and
+ * standard errno on other general error cases.
+ */
+#define TDX_CMD_GET_REPORT0 _IOWR('T', 1, struct tdx_report_req)
+
+#endif /* _UAPI_LINUX_TDX_GUEST_H_ */
diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h
index 7d21c1634b4d..5a23a15d78ac 100644
--- a/include/uapi/linux/v4l2-common.h
+++ b/include/uapi/linux/v4l2-common.h
@@ -10,45 +10,6 @@
*
* Copyright (C) 2012 Nokia Corporation
* Contact: Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. The names of its contributors may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
*/
#ifndef __V4L2_COMMON__
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index b5e7d082b8ad..b73a8ba7df6c 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -4,44 +4,6 @@
*
* Copyright (C) 1999-2012 the contributors
*
- * This 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.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. The names of its contributors may not 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.
- *
* The contents of this header was split off from videodev2.h. All control
* definitions should be added to this header, which is included by
* videodev2.h.
@@ -231,6 +193,12 @@ enum v4l2_colorfx {
*/
#define V4L2_CID_USER_DW100_BASE (V4L2_CID_USER_BASE + 0x1190)
+/*
+ * The base for Aspeed driver controls.
+ * We reserve 16 controls for this driver.
+ */
+#define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
@@ -1019,6 +987,8 @@ enum v4l2_auto_focus_range {
#define V4L2_CID_CAMERA_SENSOR_ROTATION (V4L2_CID_CAMERA_CLASS_BASE+35)
+#define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
+
/* FM Modulator class control IDs */
#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h
index b52b67c62562..ef0128c7369c 100644
--- a/include/uapi/linux/v4l2-dv-timings.h
+++ b/include/uapi/linux/v4l2-dv-timings.h
@@ -3,15 +3,6 @@
* V4L2 DV timings header.
*
* Copyright (C) 2012-2016 Hans Verkuil <hans.verkuil@cisco.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.
*/
#ifndef _V4L2_DV_TIMINGS_H
diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h
index 903e67b16711..6b07b73473b5 100644
--- a/include/uapi/linux/v4l2-mediabus.h
+++ b/include/uapi/linux/v4l2-mediabus.h
@@ -3,10 +3,6 @@
* Media Bus API header
*
* Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef __LINUX_V4L2_MEDIABUS_H
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index 658106f5b5dc..ecce4c79f5c5 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -6,19 +6,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_V4L2_SUBDEV_H
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 29da1f4b4578..1befd181a4cc 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -654,6 +654,8 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV12_16L16 v4l2_fourcc('H', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */
#define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 32x32 tiles */
#define V4L2_PIX_FMT_P010_4L4 v4l2_fourcc('T', '0', '1', '0') /* 12 Y/CbCr 4:2:0 10-bit 4x4 macroblocks */
+#define V4L2_PIX_FMT_NV12_8L128 v4l2_fourcc('A', 'T', '1', '2') /* Y/CbCr 4:2:0 8x128 tiles */
+#define V4L2_PIX_FMT_NV12_10BE_8L128 v4l2_fourcc_be('A', 'X', '1', '2') /* Y/CbCr 4:2:0 10-bit 8x128 tiles */
/* Tiled YUV formats, non contiguous planes */
#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 tiles */
@@ -775,6 +777,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */
#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */
#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */
+#define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */
/* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */
#define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */
@@ -1780,6 +1783,8 @@ struct v4l2_ext_control {
__u8 __user *p_u8;
__u16 __user *p_u16;
__u32 __user *p_u32;
+ __u32 __user *p_s32;
+ __u32 __user *p_s64;
struct v4l2_area __user *p_area;
struct v4l2_ctrl_h264_sps __user *p_h264_sps;
struct v4l2_ctrl_h264_pps *p_h264_pps;
diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h
index 6d4a2c60808d..00d2703e8fca 100644
--- a/include/uapi/sound/asequencer.h
+++ b/include/uapi/sound/asequencer.h
@@ -328,10 +328,10 @@ typedef int __bitwise snd_seq_client_type_t;
#define KERNEL_CLIENT ((__force snd_seq_client_type_t) 2)
/* event filter flags */
-#define SNDRV_SEQ_FILTER_BROADCAST (1<<0) /* accept broadcast messages */
-#define SNDRV_SEQ_FILTER_MULTICAST (1<<1) /* accept multicast messages */
-#define SNDRV_SEQ_FILTER_BOUNCE (1<<2) /* accept bounce event in error */
-#define SNDRV_SEQ_FILTER_USE_EVENT (1<<31) /* use event filter */
+#define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */
+#define SNDRV_SEQ_FILTER_MULTICAST (1U<<1) /* accept multicast messages */
+#define SNDRV_SEQ_FILTER_BOUNCE (1U<<2) /* accept bounce event in error */
+#define SNDRV_SEQ_FILTER_USE_EVENT (1U<<31) /* use event filter */
struct snd_seq_client_info {
int client; /* client number to inquire */
diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h
index 440c0725660b..b9b9093b4396 100644
--- a/include/uapi/sound/snd_ar_tokens.h
+++ b/include/uapi/sound/snd_ar_tokens.h
@@ -191,6 +191,33 @@ enum ar_event_types {
#define AR_TKN_U32_MODULE_SRC_INSTANCE_ID 208
#define AR_TKN_U32_MODULE_DST_INSTANCE_ID 209
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID1 210
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID1 211
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID1 212
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID2 213
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID2 214
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID2 215
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID3 216
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID3 217
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID3 218
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID4 219
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID4 220
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID4 221
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID5 222
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID5 223
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID5 224
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID6 225
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID6 226
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID6 227
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID7 228
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID7 229
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID7 230
#define AR_TKN_U32_MODULE_HW_IF_IDX 250
#define AR_TKN_U32_MODULE_HW_IF_TYPE 251
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index 5caf75cadaf8..bacaf8a6317e 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -88,6 +88,15 @@
#define SOF_TKN_COMP_CPC 406
#define SOF_TKN_COMP_IS_PAGES 409
#define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410
+#define SOF_TKN_COMP_NUM_SINK_PINS 411
+#define SOF_TKN_COMP_NUM_SOURCE_PINS 412
+/*
+ * The token for sink/source pin binding, it specifies the widget
+ * name that the sink/source pin is connected from/to.
+ */
+#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME 413
+#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME 414
+
/* SSP */
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
@@ -189,4 +198,9 @@
/* COPIER */
#define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980
+/* ACP I2S */
+#define SOF_TKN_AMD_ACPI2S_RATE 1700
+#define SOF_TKN_AMD_ACPI2S_CH 1701
+#define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702
+
#endif
diff --git a/include/video/nomodeset.h b/include/video/nomodeset.h
new file mode 100644
index 000000000000..8f8688b8beab
--- /dev/null
+++ b/include/video/nomodeset.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef VIDEO_NOMODESET_H
+#define VIDEO_NOMODESET_H
+
+bool video_firmware_drivers_only(void);
+
+#endif
diff --git a/include/xen/arm/xen-ops.h b/include/xen/arm/xen-ops.h
index b0766a660338..70073f5a2b54 100644
--- a/include/xen/arm/xen-ops.h
+++ b/include/xen/arm/xen-ops.h
@@ -8,9 +8,7 @@
static inline void xen_setup_dma_ops(struct device *dev)
{
#ifdef CONFIG_XEN
- if (xen_is_grant_dma_device(dev))
- xen_grant_setup_dma_ops(dev);
- else if (xen_swiotlb_detect())
+ if (xen_swiotlb_detect())
dev->dma_ops = &xen_swiotlb_dma_ops;
#endif
}
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index a34f4271a2e9..47f11bec5e90 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -216,26 +216,10 @@ static inline void xen_preemptible_hcall_end(void) { }
#endif /* CONFIG_XEN_PV && !CONFIG_PREEMPTION */
#ifdef CONFIG_XEN_GRANT_DMA_OPS
-void xen_grant_setup_dma_ops(struct device *dev);
-bool xen_is_grant_dma_device(struct device *dev);
-bool xen_virtio_mem_acc(struct virtio_device *dev);
bool xen_virtio_restricted_mem_acc(struct virtio_device *dev);
#else
-static inline void xen_grant_setup_dma_ops(struct device *dev)
-{
-}
-static inline bool xen_is_grant_dma_device(struct device *dev)
-{
- return false;
-}
-
struct virtio_device;
-static inline bool xen_virtio_mem_acc(struct virtio_device *dev)
-{
- return false;
-}
-
static inline bool xen_virtio_restricted_mem_acc(struct virtio_device *dev)
{
return false;
diff --git a/include/xen/xen.h b/include/xen/xen.h
index a99bab817523..7adf59837c25 100644
--- a/include/xen/xen.h
+++ b/include/xen/xen.h
@@ -2,6 +2,8 @@
#ifndef _XEN_XEN_H
#define _XEN_XEN_H
+#include <linux/types.h>
+
enum xen_domain_type {
XEN_NATIVE, /* running on bare hardware */
XEN_PV_DOMAIN, /* running in a PV domain */
@@ -25,8 +27,6 @@ extern bool xen_pvh;
#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
#define xen_pvh_domain() (xen_pvh)
-#include <linux/types.h>
-
extern uint32_t xen_start_flags;
#include <xen/interface/hvm/start_info.h>
diff --git a/init/Kconfig b/init/Kconfig
index abf65098f1b6..94125d3b6893 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -87,7 +87,7 @@ config CC_HAS_ASM_GOTO_OUTPUT
config CC_HAS_ASM_GOTO_TIED_OUTPUT
depends on CC_HAS_ASM_GOTO_OUTPUT
# Detect buggy gcc and clang, fixed in gcc-11 clang-14.
- def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
+ def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
config TOOLS_SUPPORT_RELR
def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
diff --git a/init/initramfs.c b/init/initramfs.c
index 2f5bfb7d7652..62321883fe61 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -461,7 +461,7 @@ static long __init write_buffer(char *buf, unsigned long len)
static long __init flush_buffer(void *bufv, unsigned long len)
{
- char *buf = (char *) bufv;
+ char *buf = bufv;
long written;
long origLen = len;
if (message)
diff --git a/init/main.c b/init/main.c
index aa21add5f7c5..d213371cc067 100644
--- a/init/main.c
+++ b/init/main.c
@@ -145,7 +145,8 @@ void (*__initdata late_time_init)(void);
/* Untouched command line saved by arch-specific code. */
char __initdata boot_command_line[COMMAND_LINE_SIZE];
/* Untouched saved command line (eg. for /proc) */
-char *saved_command_line;
+char *saved_command_line __ro_after_init;
+unsigned int saved_command_line_len __ro_after_init;
/* Command line for parameter parsing */
static char *static_command_line;
/* Untouched extra command line */
@@ -667,6 +668,8 @@ static void __init setup_command_line(char *command_line)
strcpy(saved_command_line + len, extra_init_args);
}
}
+
+ saved_command_line_len = strlen(saved_command_line);
}
/*
@@ -1379,7 +1382,7 @@ static void __init do_initcall_level(int level, char *command_line)
static void __init do_initcalls(void)
{
int level;
- size_t len = strlen(saved_command_line) + 1;
+ size_t len = saved_command_line_len + 1;
char *command_line;
command_line = kzalloc(len, GFP_KERNEL);
diff --git a/io_uring/filetable.c b/io_uring/filetable.c
index 7b473259f3f4..68dfc6936aa7 100644
--- a/io_uring/filetable.c
+++ b/io_uring/filetable.c
@@ -101,8 +101,6 @@ static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
err:
if (needs_switch)
io_rsrc_node_switch(ctx, ctx->file_data);
- if (ret)
- fput(file);
return ret;
}
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index ac8c488e3077..b521186efa5c 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -149,6 +149,7 @@ static void io_clean_op(struct io_kiocb *req);
static void io_queue_sqe(struct io_kiocb *req);
static void io_move_task_work_from_local(struct io_ring_ctx *ctx);
static void __io_submit_flush_completions(struct io_ring_ctx *ctx);
+static __cold void io_fallback_tw(struct io_uring_task *tctx);
static struct kmem_cache *req_cachep;
@@ -167,7 +168,8 @@ EXPORT_SYMBOL(io_uring_get_socket);
static inline void io_submit_flush_completions(struct io_ring_ctx *ctx)
{
- if (!wq_list_empty(&ctx->submit_state.compl_reqs))
+ if (!wq_list_empty(&ctx->submit_state.compl_reqs) ||
+ ctx->submit_state.cqes_count)
__io_submit_flush_completions(ctx);
}
@@ -176,6 +178,11 @@ static inline unsigned int __io_cqring_events(struct io_ring_ctx *ctx)
return ctx->cached_cq_tail - READ_ONCE(ctx->rings->cq.head);
}
+static inline unsigned int __io_cqring_events_user(struct io_ring_ctx *ctx)
+{
+ return READ_ONCE(ctx->rings->cq.tail) - READ_ONCE(ctx->rings->cq.head);
+}
+
static bool io_match_linked(struct io_kiocb *head)
{
struct io_kiocb *req;
@@ -320,6 +327,7 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
spin_lock_init(&ctx->rsrc_ref_lock);
INIT_LIST_HEAD(&ctx->rsrc_ref_list);
INIT_DELAYED_WORK(&ctx->rsrc_put_work, io_rsrc_put_work);
+ init_task_work(&ctx->rsrc_put_tw, io_rsrc_put_tw);
init_llist_head(&ctx->rsrc_put_llist);
init_llist_head(&ctx->work_llist);
INIT_LIST_HEAD(&ctx->tctx_list);
@@ -490,7 +498,7 @@ static void io_eventfd_ops(struct rcu_head *rcu)
int ops = atomic_xchg(&ev_fd->ops, 0);
if (ops & BIT(IO_EVENTFD_OP_SIGNAL_BIT))
- eventfd_signal(ev_fd->cq_ev_fd, 1);
+ eventfd_signal_mask(ev_fd->cq_ev_fd, 1, EPOLL_URING_WAKE);
/* IO_EVENTFD_OP_FREE_BIT may not be set here depending on callback
* ordering in a race but if references are 0 we know we have to free
@@ -526,7 +534,7 @@ static void io_eventfd_signal(struct io_ring_ctx *ctx)
goto out;
if (likely(eventfd_signal_allowed())) {
- eventfd_signal(ev_fd->cq_ev_fd, 1);
+ eventfd_signal_mask(ev_fd->cq_ev_fd, 1, EPOLL_URING_WAKE);
} else {
atomic_inc(&ev_fd->refs);
if (!atomic_fetch_or(BIT(IO_EVENTFD_OP_SIGNAL_BIT), &ev_fd->ops))
@@ -576,33 +584,63 @@ void __io_commit_cqring_flush(struct io_ring_ctx *ctx)
io_eventfd_flush_signal(ctx);
}
-static inline void io_cqring_ev_posted(struct io_ring_ctx *ctx)
+static inline void __io_cq_lock(struct io_ring_ctx *ctx)
+ __acquires(ctx->completion_lock)
+{
+ if (!ctx->task_complete)
+ spin_lock(&ctx->completion_lock);
+}
+
+static inline void __io_cq_unlock(struct io_ring_ctx *ctx)
{
+ if (!ctx->task_complete)
+ spin_unlock(&ctx->completion_lock);
+}
+
+/* keep it inlined for io_submit_flush_completions() */
+static inline void __io_cq_unlock_post(struct io_ring_ctx *ctx)
+ __releases(ctx->completion_lock)
+{
+ io_commit_cqring(ctx);
+ __io_cq_unlock(ctx);
io_commit_cqring_flush(ctx);
io_cqring_wake(ctx);
}
-static inline void __io_cq_unlock_post(struct io_ring_ctx *ctx)
+void io_cq_unlock_post(struct io_ring_ctx *ctx)
__releases(ctx->completion_lock)
{
io_commit_cqring(ctx);
spin_unlock(&ctx->completion_lock);
- io_cqring_ev_posted(ctx);
+ io_commit_cqring_flush(ctx);
+ io_cqring_wake(ctx);
}
-void io_cq_unlock_post(struct io_ring_ctx *ctx)
+/* Returns true if there are no backlogged entries after the flush */
+static void io_cqring_overflow_kill(struct io_ring_ctx *ctx)
{
- __io_cq_unlock_post(ctx);
+ struct io_overflow_cqe *ocqe;
+ LIST_HEAD(list);
+
+ io_cq_lock(ctx);
+ list_splice_init(&ctx->cq_overflow_list, &list);
+ clear_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
+ io_cq_unlock(ctx);
+
+ while (!list_empty(&list)) {
+ ocqe = list_first_entry(&list, struct io_overflow_cqe, list);
+ list_del(&ocqe->list);
+ kfree(ocqe);
+ }
}
/* Returns true if there are no backlogged entries after the flush */
-static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
+static void __io_cqring_overflow_flush(struct io_ring_ctx *ctx)
{
- bool all_flushed;
size_t cqe_size = sizeof(struct io_uring_cqe);
- if (!force && __io_cqring_events(ctx) == ctx->cq_entries)
- return false;
+ if (__io_cqring_events(ctx) == ctx->cq_entries)
+ return;
if (ctx->flags & IORING_SETUP_CQE32)
cqe_size <<= 1;
@@ -612,43 +650,32 @@ static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
struct io_uring_cqe *cqe = io_get_cqe_overflow(ctx, true);
struct io_overflow_cqe *ocqe;
- if (!cqe && !force)
+ if (!cqe)
break;
ocqe = list_first_entry(&ctx->cq_overflow_list,
struct io_overflow_cqe, list);
- if (cqe)
- memcpy(cqe, &ocqe->cqe, cqe_size);
- else
- io_account_cq_overflow(ctx);
-
+ memcpy(cqe, &ocqe->cqe, cqe_size);
list_del(&ocqe->list);
kfree(ocqe);
}
- all_flushed = list_empty(&ctx->cq_overflow_list);
- if (all_flushed) {
+ if (list_empty(&ctx->cq_overflow_list)) {
clear_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
atomic_andnot(IORING_SQ_CQ_OVERFLOW, &ctx->rings->sq_flags);
}
-
io_cq_unlock_post(ctx);
- return all_flushed;
}
-static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx)
+static void io_cqring_overflow_flush(struct io_ring_ctx *ctx)
{
- bool ret = true;
-
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
/* iopoll syncs against uring_lock, not completion_lock */
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_lock(&ctx->uring_lock);
- ret = __io_cqring_overflow_flush(ctx, false);
+ __io_cqring_overflow_flush(ctx);
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_unlock(&ctx->uring_lock);
}
-
- return ret;
}
void __io_put_task(struct task_struct *task, int nr)
@@ -773,11 +800,14 @@ struct io_uring_cqe *__io_get_cqe(struct io_ring_ctx *ctx, bool overflow)
return &rings->cqes[off];
}
-bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
- bool allow_overflow)
+static bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res,
+ u32 cflags)
{
struct io_uring_cqe *cqe;
+ if (!ctx->task_complete)
+ lockdep_assert_held(&ctx->completion_lock);
+
ctx->cq_extra++;
/*
@@ -799,34 +829,100 @@ bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags
}
return true;
}
-
- if (allow_overflow)
- return io_cqring_event_overflow(ctx, user_data, res, cflags, 0, 0);
-
return false;
}
-bool io_post_aux_cqe(struct io_ring_ctx *ctx,
- u64 user_data, s32 res, u32 cflags,
- bool allow_overflow)
+static void __io_flush_post_cqes(struct io_ring_ctx *ctx)
+ __must_hold(&ctx->uring_lock)
+{
+ struct io_submit_state *state = &ctx->submit_state;
+ unsigned int i;
+
+ lockdep_assert_held(&ctx->uring_lock);
+ for (i = 0; i < state->cqes_count; i++) {
+ struct io_uring_cqe *cqe = &state->cqes[i];
+
+ if (!io_fill_cqe_aux(ctx, cqe->user_data, cqe->res, cqe->flags)) {
+ if (ctx->task_complete) {
+ spin_lock(&ctx->completion_lock);
+ io_cqring_event_overflow(ctx, cqe->user_data,
+ cqe->res, cqe->flags, 0, 0);
+ spin_unlock(&ctx->completion_lock);
+ } else {
+ io_cqring_event_overflow(ctx, cqe->user_data,
+ cqe->res, cqe->flags, 0, 0);
+ }
+ }
+ }
+ state->cqes_count = 0;
+}
+
+static bool __io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
+ bool allow_overflow)
{
bool filled;
io_cq_lock(ctx);
- filled = io_fill_cqe_aux(ctx, user_data, res, cflags, allow_overflow);
+ filled = io_fill_cqe_aux(ctx, user_data, res, cflags);
+ if (!filled && allow_overflow)
+ filled = io_cqring_event_overflow(ctx, user_data, res, cflags, 0, 0);
+
io_cq_unlock_post(ctx);
return filled;
}
-static void __io_req_complete_put(struct io_kiocb *req)
+bool io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags)
{
+ return __io_post_aux_cqe(ctx, user_data, res, cflags, true);
+}
+
+bool io_aux_cqe(struct io_ring_ctx *ctx, bool defer, u64 user_data, s32 res, u32 cflags,
+ bool allow_overflow)
+{
+ struct io_uring_cqe *cqe;
+ unsigned int length;
+
+ if (!defer)
+ return __io_post_aux_cqe(ctx, user_data, res, cflags, allow_overflow);
+
+ length = ARRAY_SIZE(ctx->submit_state.cqes);
+
+ lockdep_assert_held(&ctx->uring_lock);
+
+ if (ctx->submit_state.cqes_count == length) {
+ __io_cq_lock(ctx);
+ __io_flush_post_cqes(ctx);
+ /* no need to flush - flush is deferred */
+ __io_cq_unlock_post(ctx);
+ }
+
+ /* For defered completions this is not as strict as it is otherwise,
+ * however it's main job is to prevent unbounded posted completions,
+ * and in that it works just as well.
+ */
+ if (!allow_overflow && test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq))
+ return false;
+
+ cqe = &ctx->submit_state.cqes[ctx->submit_state.cqes_count++];
+ cqe->user_data = user_data;
+ cqe->res = res;
+ cqe->flags = cflags;
+ return true;
+}
+
+static void __io_req_complete_post(struct io_kiocb *req)
+{
+ struct io_ring_ctx *ctx = req->ctx;
+
+ io_cq_lock(ctx);
+ if (!(req->flags & REQ_F_CQE_SKIP))
+ __io_fill_cqe_req(ctx, req);
+
/*
* If we're the last reference to this request, add to our locked
* free_list cache.
*/
if (req_ref_put_and_test(req)) {
- struct io_ring_ctx *ctx = req->ctx;
-
if (req->flags & IO_REQ_LINK_FLAGS) {
if (req->flags & IO_DISARM_MASK)
io_disarm_next(req);
@@ -847,38 +943,38 @@ static void __io_req_complete_put(struct io_kiocb *req)
wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
ctx->locked_free_nr++;
}
-}
-
-void __io_req_complete_post(struct io_kiocb *req)
-{
- if (!(req->flags & REQ_F_CQE_SKIP))
- __io_fill_cqe_req(req->ctx, req);
- __io_req_complete_put(req);
-}
-
-void io_req_complete_post(struct io_kiocb *req)
-{
- struct io_ring_ctx *ctx = req->ctx;
-
- io_cq_lock(ctx);
- __io_req_complete_post(req);
io_cq_unlock_post(ctx);
}
-inline void __io_req_complete(struct io_kiocb *req, unsigned issue_flags)
+void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
{
- io_req_complete_post(req);
+ if (req->ctx->task_complete && (issue_flags & IO_URING_F_IOWQ)) {
+ req->io_task_work.func = io_req_task_complete;
+ io_req_task_work_add(req);
+ } else if (!(issue_flags & IO_URING_F_UNLOCKED) ||
+ !(req->ctx->flags & IORING_SETUP_IOPOLL)) {
+ __io_req_complete_post(req);
+ } else {
+ struct io_ring_ctx *ctx = req->ctx;
+
+ mutex_lock(&ctx->uring_lock);
+ __io_req_complete_post(req);
+ mutex_unlock(&ctx->uring_lock);
+ }
}
-void io_req_complete_failed(struct io_kiocb *req, s32 res)
+void io_req_defer_failed(struct io_kiocb *req, s32 res)
+ __must_hold(&ctx->uring_lock)
{
const struct io_op_def *def = &io_op_defs[req->opcode];
+ lockdep_assert_held(&req->ctx->uring_lock);
+
req_set_fail(req);
io_req_set_res(req, res, io_put_kbuf(req, IO_URING_F_UNLOCKED));
if (def->fail)
def->fail(req);
- io_req_complete_post(req);
+ io_req_complete_defer(req);
}
/*
@@ -1079,10 +1175,17 @@ void tctx_task_work(struct callback_head *cb)
struct io_uring_task *tctx = container_of(cb, struct io_uring_task,
task_work);
struct llist_node fake = {};
- struct llist_node *node = io_llist_xchg(&tctx->task_list, &fake);
+ struct llist_node *node;
unsigned int loops = 1;
- unsigned int count = handle_tw_list(node, &ctx, &uring_locked, NULL);
+ unsigned int count;
+ if (unlikely(current->flags & PF_EXITING)) {
+ io_fallback_tw(tctx);
+ return;
+ }
+
+ node = io_llist_xchg(&tctx->task_list, &fake);
+ count = handle_tw_list(node, &ctx, &uring_locked, NULL);
node = io_llist_cmpxchg(&tctx->task_list, &fake, NULL);
while (node != &fake) {
loops++;
@@ -1100,6 +1203,20 @@ void tctx_task_work(struct callback_head *cb)
trace_io_uring_task_work_run(tctx, count, loops);
}
+static __cold void io_fallback_tw(struct io_uring_task *tctx)
+{
+ struct llist_node *node = llist_del_all(&tctx->task_list);
+ struct io_kiocb *req;
+
+ while (node) {
+ req = container_of(node, struct io_kiocb, io_task_work.node);
+ node = node->next;
+ if (llist_add(&req->io_task_work.node,
+ &req->ctx->fallback_llist))
+ schedule_delayed_work(&req->ctx->fallback_work, 1);
+ }
+}
+
static void io_req_local_work_add(struct io_kiocb *req)
{
struct io_ring_ctx *ctx = req->ctx;
@@ -1122,11 +1239,10 @@ static void io_req_local_work_add(struct io_kiocb *req)
__io_cqring_wake(ctx);
}
-static inline void __io_req_task_work_add(struct io_kiocb *req, bool allow_local)
+void __io_req_task_work_add(struct io_kiocb *req, bool allow_local)
{
struct io_uring_task *tctx = req->task->io_uring;
struct io_ring_ctx *ctx = req->ctx;
- struct llist_node *node;
if (allow_local && ctx->flags & IORING_SETUP_DEFER_TASKRUN) {
io_req_local_work_add(req);
@@ -1143,20 +1259,7 @@ static inline void __io_req_task_work_add(struct io_kiocb *req, bool allow_local
if (likely(!task_work_add(req->task, &tctx->task_work, ctx->notify_method)))
return;
- node = llist_del_all(&tctx->task_list);
-
- while (node) {
- req = container_of(node, struct io_kiocb, io_task_work.node);
- node = node->next;
- if (llist_add(&req->io_task_work.node,
- &req->ctx->fallback_llist))
- schedule_delayed_work(&req->ctx->fallback_work, 1);
- }
-}
-
-void io_req_task_work_add(struct io_kiocb *req)
-{
- __io_req_task_work_add(req, true);
+ io_fallback_tw(tctx);
}
static void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx)
@@ -1232,23 +1335,10 @@ int io_run_local_work(struct io_ring_ctx *ctx)
return ret;
}
-static void io_req_tw_post(struct io_kiocb *req, bool *locked)
-{
- io_req_complete_post(req);
-}
-
-void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags)
-{
- io_req_set_res(req, res, cflags);
- req->io_task_work.func = io_req_tw_post;
- io_req_task_work_add(req);
-}
-
static void io_req_task_cancel(struct io_kiocb *req, bool *locked)
{
- /* not needed for normal modes, but SQPOLL depends on it */
io_tw_lock(req->ctx, locked);
- io_req_complete_failed(req, req->cqe.res);
+ io_req_defer_failed(req, req->cqe.res);
}
void io_req_task_submit(struct io_kiocb *req, bool *locked)
@@ -1258,7 +1348,7 @@ void io_req_task_submit(struct io_kiocb *req, bool *locked)
if (likely(!(req->task->flags & PF_EXITING)))
io_queue_sqe(req);
else
- io_req_complete_failed(req, -EFAULT);
+ io_req_defer_failed(req, -EFAULT);
}
void io_req_task_queue_fail(struct io_kiocb *req, int ret)
@@ -1338,18 +1428,31 @@ static void __io_submit_flush_completions(struct io_ring_ctx *ctx)
struct io_wq_work_node *node, *prev;
struct io_submit_state *state = &ctx->submit_state;
- io_cq_lock(ctx);
+ __io_cq_lock(ctx);
+ /* must come first to preserve CQE ordering in failure cases */
+ if (state->cqes_count)
+ __io_flush_post_cqes(ctx);
wq_list_for_each(node, prev, &state->compl_reqs) {
struct io_kiocb *req = container_of(node, struct io_kiocb,
comp_list);
- if (!(req->flags & REQ_F_CQE_SKIP))
- __io_fill_cqe_req(ctx, req);
+ if (!(req->flags & REQ_F_CQE_SKIP) &&
+ unlikely(!__io_fill_cqe_req(ctx, req))) {
+ if (ctx->task_complete) {
+ spin_lock(&ctx->completion_lock);
+ io_req_cqe_overflow(req);
+ spin_unlock(&ctx->completion_lock);
+ } else {
+ io_req_cqe_overflow(req);
+ }
+ }
}
__io_cq_unlock_post(ctx);
- io_free_batch_list(ctx, state->compl_reqs.first);
- INIT_WQ_LIST(&state->compl_reqs);
+ if (!wq_list_empty(&ctx->submit_state.compl_reqs)) {
+ io_free_batch_list(ctx, state->compl_reqs.first);
+ INIT_WQ_LIST(&state->compl_reqs);
+ }
}
/*
@@ -1415,7 +1518,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
check_cq = READ_ONCE(ctx->check_cq);
if (unlikely(check_cq)) {
if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
- __io_cqring_overflow_flush(ctx, false);
+ __io_cqring_overflow_flush(ctx);
/*
* Similarly do not spin if we have not informed the user of any
* dropped CQE.
@@ -1471,16 +1574,10 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
void io_req_task_complete(struct io_kiocb *req, bool *locked)
{
- if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
- unsigned issue_flags = *locked ? 0 : IO_URING_F_UNLOCKED;
-
- req->cqe.flags |= io_put_kbuf(req, issue_flags);
- }
-
if (*locked)
io_req_complete_defer(req);
else
- io_req_complete_post(req);
+ io_req_complete_post(req, IO_URING_F_UNLOCKED);
}
/*
@@ -1630,6 +1727,7 @@ static u32 io_get_sequence(struct io_kiocb *req)
}
static __cold void io_drain_req(struct io_kiocb *req)
+ __must_hold(&ctx->uring_lock)
{
struct io_ring_ctx *ctx = req->ctx;
struct io_defer_entry *de;
@@ -1650,7 +1748,7 @@ queue:
ret = io_req_prep_async(req);
if (ret) {
fail:
- io_req_complete_failed(req, ret);
+ io_req_defer_failed(req, ret);
return;
}
io_prep_async_link(req);
@@ -1747,12 +1845,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
if (issue_flags & IO_URING_F_COMPLETE_DEFER)
io_req_complete_defer(req);
else
- io_req_complete_post(req);
+ io_req_complete_post(req, issue_flags);
} else if (ret != IOU_ISSUE_SKIP_COMPLETE)
return ret;
/* If the op doesn't have a file, we're not polling for it */
- if ((req->ctx->flags & IORING_SETUP_IOPOLL) && req->file)
+ if ((req->ctx->flags & IORING_SETUP_IOPOLL) && def->iopoll_queue)
io_iopoll_req_issued(req, issue_flags);
return 0;
@@ -1761,9 +1859,8 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
int io_poll_issue(struct io_kiocb *req, bool *locked)
{
io_tw_lock(req->ctx, locked);
- if (unlikely(req->task->flags & PF_EXITING))
- return -EFAULT;
- return io_issue_sqe(req, IO_URING_F_NONBLOCK);
+ return io_issue_sqe(req, IO_URING_F_NONBLOCK|IO_URING_F_MULTISHOT|
+ IO_URING_F_COMPLETE_DEFER);
}
struct io_wq_work *io_wq_free_work(struct io_wq_work *work)
@@ -1778,11 +1875,11 @@ void io_wq_submit_work(struct io_wq_work *work)
{
struct io_kiocb *req = container_of(work, struct io_kiocb, work);
const struct io_op_def *def = &io_op_defs[req->opcode];
- unsigned int issue_flags = IO_URING_F_UNLOCKED;
+ unsigned int issue_flags = IO_URING_F_UNLOCKED | IO_URING_F_IOWQ;
bool needs_poll = false;
int ret = 0, err = -ECANCELED;
- /* one will be dropped by ->io_free_work() after returning to io-wq */
+ /* one will be dropped by ->io_wq_free_work() after returning to io-wq */
if (!(req->flags & REQ_F_REFCOUNT))
__io_req_set_refcount(req, 2);
else
@@ -1880,7 +1977,7 @@ static void io_queue_async(struct io_kiocb *req, int ret)
struct io_kiocb *linked_timeout;
if (ret != -EAGAIN || (req->flags & REQ_F_NOWAIT)) {
- io_req_complete_failed(req, ret);
+ io_req_defer_failed(req, ret);
return;
}
@@ -1930,14 +2027,14 @@ static void io_queue_sqe_fallback(struct io_kiocb *req)
*/
req->flags &= ~REQ_F_HARDLINK;
req->flags |= REQ_F_LINK;
- io_req_complete_failed(req, req->cqe.res);
+ io_req_defer_failed(req, req->cqe.res);
} else if (unlikely(req->ctx->drain_active)) {
io_drain_req(req);
} else {
int ret = io_req_prep_async(req);
if (unlikely(ret))
- io_req_complete_failed(req, ret);
+ io_req_defer_failed(req, ret);
else
io_queue_iowq(req, NULL);
}
@@ -2315,7 +2412,7 @@ static inline bool io_has_work(struct io_ring_ctx *ctx)
static inline bool io_should_wake(struct io_wait_queue *iowq)
{
struct io_ring_ctx *ctx = iowq->ctx;
- int dist = ctx->cached_cq_tail - (int) iowq->cq_tail;
+ int dist = READ_ONCE(ctx->rings->cq.tail) - (int) iowq->cq_tail;
/*
* Wake up if we have enough events, or if a timeout occurred since we
@@ -2399,7 +2496,8 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
return ret;
io_cqring_overflow_flush(ctx);
- if (io_cqring_events(ctx) >= min_events)
+ /* if user messes with these they will just get an early return */
+ if (__io_cqring_events_user(ctx) >= min_events)
return 0;
} while (ret > 0);
@@ -2433,11 +2531,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
trace_io_uring_cqring_wait(ctx, min_events);
do {
- /* if we can't even flush overflow, don't wait for more */
- if (!io_cqring_overflow_flush(ctx)) {
- ret = -EBUSY;
- break;
- }
+ io_cqring_overflow_flush(ctx);
prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
TASK_INTERRUPTIBLE);
ret = io_cqring_wait_schedule(ctx, &iowq, timeout);
@@ -2588,8 +2682,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
__io_sqe_buffers_unregister(ctx);
if (ctx->file_data)
__io_sqe_files_unregister(ctx);
- if (ctx->rings)
- __io_cqring_overflow_flush(ctx, true);
+ io_cqring_overflow_kill(ctx);
io_eventfd_unregister(ctx);
io_alloc_cache_free(&ctx->apoll_cache, io_apoll_cache_free);
io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free);
@@ -2664,7 +2757,7 @@ static __poll_t io_uring_poll(struct file *file, poll_table *wait)
* lock(&ep->mtx);
*
* Users may get EPOLLIN meanwhile seeing nothing in cqring, this
- * pushs them to do the flush.
+ * pushes them to do the flush.
*/
if (io_cqring_events(ctx) || io_has_work(ctx))
@@ -2701,8 +2794,10 @@ static __cold void io_tctx_exit_cb(struct callback_head *cb)
/*
* When @in_idle, we're in cancellation and it's racy to remove the
* node. It'll be removed by the end of cancellation, just ignore it.
+ * tctx can be NULL if the queueing of this task_work raced with
+ * work cancelation off the exec path.
*/
- if (!atomic_read(&tctx->in_idle))
+ if (tctx && !atomic_read(&tctx->in_idle))
io_uring_del_tctx_node((unsigned long)work->ctx);
complete(&work->completion);
}
@@ -2730,6 +2825,12 @@ static __cold void io_ring_exit_work(struct work_struct *work)
* as nobody else will be looking for them.
*/
do {
+ if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
+ mutex_lock(&ctx->uring_lock);
+ io_cqring_overflow_kill(ctx);
+ mutex_unlock(&ctx->uring_lock);
+ }
+
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
io_move_task_work_from_local(ctx);
@@ -2795,8 +2896,6 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
mutex_lock(&ctx->uring_lock);
percpu_ref_kill(&ctx->refs);
- if (ctx->rings)
- __io_cqring_overflow_flush(ctx, true);
xa_for_each(&ctx->personalities, index, creds)
io_unregister_personality(ctx, index);
if (ctx->rings)
@@ -2863,7 +2962,7 @@ static __cold bool io_cancel_defer_files(struct io_ring_ctx *ctx,
while (!list_empty(&list)) {
de = list_first_entry(&list, struct io_defer_entry, list);
list_del_init(&de->list);
- io_req_complete_failed(de->req, -ECANCELED);
+ io_req_task_queue_fail(de->req, -ECANCELED);
kfree(de);
}
return true;
@@ -3438,6 +3537,11 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
if (!ctx)
return -ENOMEM;
+ if ((ctx->flags & IORING_SETUP_DEFER_TASKRUN) &&
+ !(ctx->flags & IORING_SETUP_IOPOLL) &&
+ !(ctx->flags & IORING_SETUP_SQPOLL))
+ ctx->task_complete = true;
+
/*
* When SETUP_IOPOLL and SETUP_SQPOLL are both enabled, user
* space applications don't need to do io completion events
@@ -4056,8 +4160,6 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
ctx = f.file->private_data;
- io_run_task_work_ctx(ctx);
-
mutex_lock(&ctx->uring_lock);
ret = __io_uring_register(ctx, opcode, arg, nr_args);
mutex_unlock(&ctx->uring_lock);
diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h
index e99a79f2df9b..1b2f0b2cc888 100644
--- a/io_uring/io_uring.h
+++ b/io_uring/io_uring.h
@@ -4,6 +4,7 @@
#include <linux/errno.h>
#include <linux/lockdep.h>
#include <linux/io_uring_types.h>
+#include <uapi/linux/eventpoll.h>
#include "io-wq.h"
#include "slist.h"
#include "filetable.h"
@@ -17,8 +18,8 @@ enum {
IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
/*
- * Intended only when both REQ_F_POLLED and REQ_F_APOLL_MULTISHOT
- * are set to indicate to the poll runner that multishot should be
+ * Intended only when both IO_URING_F_MULTISHOT is passed
+ * to indicate to the poll runner that multishot should be
* removed and the result is set on req->cqe.res.
*/
IOU_STOP_MULTISHOT = -ECANCELED,
@@ -29,14 +30,11 @@ bool io_req_cqe_overflow(struct io_kiocb *req);
int io_run_task_work_sig(struct io_ring_ctx *ctx);
int __io_run_local_work(struct io_ring_ctx *ctx, bool *locked);
int io_run_local_work(struct io_ring_ctx *ctx);
-void io_req_complete_failed(struct io_kiocb *req, s32 res);
-void __io_req_complete(struct io_kiocb *req, unsigned issue_flags);
-void io_req_complete_post(struct io_kiocb *req);
-void __io_req_complete_post(struct io_kiocb *req);
-bool io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
- bool allow_overflow);
-bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
- bool allow_overflow);
+void io_req_defer_failed(struct io_kiocb *req, s32 res);
+void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags);
+bool io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags);
+bool io_aux_cqe(struct io_ring_ctx *ctx, bool defer, u64 user_data, s32 res, u32 cflags,
+ bool allow_overflow);
void __io_commit_cqring_flush(struct io_ring_ctx *ctx);
struct page **io_pin_pages(unsigned long ubuf, unsigned long len, int *npages);
@@ -50,10 +48,9 @@ static inline bool io_req_ffs_set(struct io_kiocb *req)
return req->flags & REQ_F_FIXED_FILE;
}
+void __io_req_task_work_add(struct io_kiocb *req, bool allow_local);
bool io_is_uring_fops(struct file *file);
bool io_alloc_async_data(struct io_kiocb *req);
-void io_req_task_work_add(struct io_kiocb *req);
-void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags);
void io_req_task_queue(struct io_kiocb *req);
void io_queue_iowq(struct io_kiocb *req, bool *dont_use);
void io_req_task_complete(struct io_kiocb *req, bool *locked);
@@ -82,6 +79,11 @@ bool __io_alloc_req_refill(struct io_ring_ctx *ctx);
bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
bool cancel_all);
+static inline void io_req_task_work_add(struct io_kiocb *req)
+{
+ __io_req_task_work_add(req, true);
+}
+
#define io_for_each_link(pos, head) \
for (pos = (head); pos; pos = pos->link)
@@ -91,6 +93,11 @@ static inline void io_cq_lock(struct io_ring_ctx *ctx)
spin_lock(&ctx->completion_lock);
}
+static inline void io_cq_unlock(struct io_ring_ctx *ctx)
+{
+ spin_unlock(&ctx->completion_lock);
+}
+
void io_cq_unlock_post(struct io_ring_ctx *ctx);
static inline struct io_uring_cqe *io_get_cqe_overflow(struct io_ring_ctx *ctx,
@@ -126,7 +133,7 @@ static inline bool __io_fill_cqe_req(struct io_ring_ctx *ctx,
*/
cqe = io_get_cqe(ctx);
if (unlikely(!cqe))
- return io_req_cqe_overflow(req);
+ return false;
trace_io_uring_complete(req->ctx, req, req->cqe.user_data,
req->cqe.res, req->cqe.flags,
@@ -149,6 +156,14 @@ static inline bool __io_fill_cqe_req(struct io_ring_ctx *ctx,
return true;
}
+static inline bool io_fill_cqe_req(struct io_ring_ctx *ctx,
+ struct io_kiocb *req)
+{
+ if (likely(__io_fill_cqe_req(ctx, req)))
+ return true;
+ return io_req_cqe_overflow(req);
+}
+
static inline void req_set_fail(struct io_kiocb *req)
{
req->flags |= REQ_F_FAIL;
@@ -207,12 +222,18 @@ static inline void io_commit_cqring(struct io_ring_ctx *ctx)
static inline void __io_cqring_wake(struct io_ring_ctx *ctx)
{
/*
- * wake_up_all() may seem excessive, but io_wake_function() and
- * io_should_wake() handle the termination of the loop and only
- * wake as many waiters as we need to.
+ * Trigger waitqueue handler on all waiters on our waitqueue. This
+ * won't necessarily wake up all the tasks, io_should_wake() will make
+ * that decision.
+ *
+ * Pass in EPOLLIN|EPOLL_URING_WAKE as the poll wakeup key. The latter
+ * set in the mask so that if we recurse back into our own poll
+ * waitqueue handlers, we know we have a dependency between eventfd or
+ * epoll and should terminate multishot poll at that point.
*/
if (waitqueue_active(&ctx->cq_wait))
- wake_up_all(&ctx->cq_wait);
+ __wake_up(&ctx->cq_wait, TASK_NORMAL, 0,
+ poll_to_key(EPOLL_URING_WAKE | EPOLLIN));
}
static inline void io_cqring_wake(struct io_ring_ctx *ctx)
@@ -238,9 +259,14 @@ static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
static inline int io_run_task_work(void)
{
+ /*
+ * Always check-and-clear the task_work notification signal. With how
+ * signaling works for task_work, we can find it set with nothing to
+ * run. We need to clear it for that case, like get_signal() does.
+ */
+ if (test_thread_flag(TIF_NOTIFY_SIGNAL))
+ clear_notify_signal();
if (task_work_pending(current)) {
- if (test_thread_flag(TIF_NOTIFY_SIGNAL))
- clear_notify_signal();
__set_current_state(TASK_RUNNING);
task_work_run();
return 1;
@@ -364,4 +390,11 @@ static inline bool io_allowed_run_tw(struct io_ring_ctx *ctx)
ctx->submitter_task == current);
}
+static inline void io_req_queue_tw_complete(struct io_kiocb *req, s32 res)
+{
+ io_req_set_res(req, res, 0);
+ req->io_task_work.func = io_req_task_complete;
+ io_req_task_work_add(req);
+}
+
#endif
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index 25cd724ade18..4a6401080c1f 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -306,14 +306,11 @@ int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
if (!bl->buf_nr_pages)
ret = __io_remove_buffers(ctx, bl, p->nbufs);
}
+ io_ring_submit_unlock(ctx, issue_flags);
if (ret < 0)
req_set_fail(req);
-
- /* complete before unlock, IOPOLL may need the lock */
io_req_set_res(req, ret, 0);
- __io_req_complete(req, issue_flags);
- io_ring_submit_unlock(ctx, issue_flags);
- return IOU_ISSUE_SKIP_COMPLETE;
+ return IOU_OK;
}
int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -346,6 +343,8 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
tmp = READ_ONCE(sqe->off);
if (tmp > USHRT_MAX)
return -E2BIG;
+ if (tmp + p->nbufs >= USHRT_MAX)
+ return -EINVAL;
p->bid = tmp;
return 0;
}
@@ -456,13 +455,12 @@ int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
ret = io_add_buffers(ctx, p, bl);
err:
+ io_ring_submit_unlock(ctx, issue_flags);
+
if (ret < 0)
req_set_fail(req);
- /* complete before unlock, IOPOLL may need the lock */
io_req_set_res(req, ret, 0);
- __io_req_complete(req, issue_flags);
- io_ring_submit_unlock(ctx, issue_flags);
- return IOU_ISSUE_SKIP_COMPLETE;
+ return IOU_OK;
}
int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
index 90d2fc6fd80e..2d3cd945a531 100644
--- a/io_uring/msg_ring.c
+++ b/io_uring/msg_ring.c
@@ -15,6 +15,8 @@
struct io_msg {
struct file *file;
+ struct file *src_file;
+ struct callback_head tw;
u64 user_data;
u32 len;
u32 cmd;
@@ -23,6 +25,34 @@ struct io_msg {
u32 flags;
};
+void io_msg_ring_cleanup(struct io_kiocb *req)
+{
+ struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+
+ if (WARN_ON_ONCE(!msg->src_file))
+ return;
+
+ fput(msg->src_file);
+ msg->src_file = NULL;
+}
+
+static void io_msg_tw_complete(struct callback_head *head)
+{
+ struct io_msg *msg = container_of(head, struct io_msg, tw);
+ struct io_kiocb *req = cmd_to_io_kiocb(msg);
+ struct io_ring_ctx *target_ctx = req->file->private_data;
+ int ret = 0;
+
+ if (current->flags & PF_EXITING)
+ ret = -EOWNERDEAD;
+ else if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
+ ret = -EOVERFLOW;
+
+ if (ret < 0)
+ req_set_fail(req);
+ io_req_queue_tw_complete(req, ret);
+}
+
static int io_msg_ring_data(struct io_kiocb *req)
{
struct io_ring_ctx *target_ctx = req->file->private_data;
@@ -31,23 +61,29 @@ static int io_msg_ring_data(struct io_kiocb *req)
if (msg->src_fd || msg->dst_fd || msg->flags)
return -EINVAL;
- if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0, true))
+ if (target_ctx->task_complete && current != target_ctx->submitter_task) {
+ init_task_work(&msg->tw, io_msg_tw_complete);
+ if (task_work_add(target_ctx->submitter_task, &msg->tw,
+ TWA_SIGNAL_NO_IPI))
+ return -EOWNERDEAD;
+
+ atomic_or(IORING_SQ_TASKRUN, &target_ctx->rings->sq_flags);
+ return IOU_ISSUE_SKIP_COMPLETE;
+ }
+
+ if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
return 0;
return -EOVERFLOW;
}
-static void io_double_unlock_ctx(struct io_ring_ctx *ctx,
- struct io_ring_ctx *octx,
+static void io_double_unlock_ctx(struct io_ring_ctx *octx,
unsigned int issue_flags)
{
- if (issue_flags & IO_URING_F_UNLOCKED)
- mutex_unlock(&ctx->uring_lock);
mutex_unlock(&octx->uring_lock);
}
-static int io_double_lock_ctx(struct io_ring_ctx *ctx,
- struct io_ring_ctx *octx,
+static int io_double_lock_ctx(struct io_ring_ctx *octx,
unsigned int issue_flags)
{
/*
@@ -60,69 +96,103 @@ static int io_double_lock_ctx(struct io_ring_ctx *ctx,
return -EAGAIN;
return 0;
}
-
- /* Always grab smallest value ctx first. We know ctx != octx. */
- if (ctx < octx) {
- mutex_lock(&ctx->uring_lock);
- mutex_lock(&octx->uring_lock);
- } else {
- mutex_lock(&octx->uring_lock);
- mutex_lock(&ctx->uring_lock);
- }
-
+ mutex_lock(&octx->uring_lock);
return 0;
}
-static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
+static struct file *io_msg_grab_file(struct io_kiocb *req, unsigned int issue_flags)
{
- struct io_ring_ctx *target_ctx = req->file->private_data;
struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
struct io_ring_ctx *ctx = req->ctx;
+ struct file *file = NULL;
unsigned long file_ptr;
- struct file *src_file;
- int ret;
-
- if (target_ctx == ctx)
- return -EINVAL;
-
- ret = io_double_lock_ctx(ctx, target_ctx, issue_flags);
- if (unlikely(ret))
- return ret;
-
- ret = -EBADF;
- if (unlikely(msg->src_fd >= ctx->nr_user_files))
- goto out_unlock;
+ int idx = msg->src_fd;
+
+ io_ring_submit_lock(ctx, issue_flags);
+ if (likely(idx < ctx->nr_user_files)) {
+ idx = array_index_nospec(idx, ctx->nr_user_files);
+ file_ptr = io_fixed_file_slot(&ctx->file_table, idx)->file_ptr;
+ file = (struct file *) (file_ptr & FFS_MASK);
+ if (file)
+ get_file(file);
+ }
+ io_ring_submit_unlock(ctx, issue_flags);
+ return file;
+}
- msg->src_fd = array_index_nospec(msg->src_fd, ctx->nr_user_files);
- file_ptr = io_fixed_file_slot(&ctx->file_table, msg->src_fd)->file_ptr;
- if (!file_ptr)
- goto out_unlock;
+static int io_msg_install_complete(struct io_kiocb *req, unsigned int issue_flags)
+{
+ struct io_ring_ctx *target_ctx = req->file->private_data;
+ struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+ struct file *src_file = msg->src_file;
+ int ret;
- src_file = (struct file *) (file_ptr & FFS_MASK);
- get_file(src_file);
+ if (unlikely(io_double_lock_ctx(target_ctx, issue_flags)))
+ return -EAGAIN;
ret = __io_fixed_fd_install(target_ctx, src_file, msg->dst_fd);
- if (ret < 0) {
- fput(src_file);
+ if (ret < 0)
goto out_unlock;
- }
+
+ msg->src_file = NULL;
+ req->flags &= ~REQ_F_NEED_CLEANUP;
if (msg->flags & IORING_MSG_RING_CQE_SKIP)
goto out_unlock;
-
/*
* If this fails, the target still received the file descriptor but
* wasn't notified of the fact. This means that if this request
* completes with -EOVERFLOW, then the sender must ensure that a
* later IORING_OP_MSG_RING delivers the message.
*/
- if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0, true))
+ if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
ret = -EOVERFLOW;
out_unlock:
- io_double_unlock_ctx(ctx, target_ctx, issue_flags);
+ io_double_unlock_ctx(target_ctx, issue_flags);
return ret;
}
+static void io_msg_tw_fd_complete(struct callback_head *head)
+{
+ struct io_msg *msg = container_of(head, struct io_msg, tw);
+ struct io_kiocb *req = cmd_to_io_kiocb(msg);
+ int ret = -EOWNERDEAD;
+
+ if (!(current->flags & PF_EXITING))
+ ret = io_msg_install_complete(req, IO_URING_F_UNLOCKED);
+ if (ret < 0)
+ req_set_fail(req);
+ io_req_queue_tw_complete(req, ret);
+}
+
+static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
+{
+ struct io_ring_ctx *target_ctx = req->file->private_data;
+ struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+ struct io_ring_ctx *ctx = req->ctx;
+ struct file *src_file = msg->src_file;
+
+ if (target_ctx == ctx)
+ return -EINVAL;
+ if (!src_file) {
+ src_file = io_msg_grab_file(req, issue_flags);
+ if (!src_file)
+ return -EBADF;
+ msg->src_file = src_file;
+ req->flags |= REQ_F_NEED_CLEANUP;
+ }
+
+ if (target_ctx->task_complete && current != target_ctx->submitter_task) {
+ init_task_work(&msg->tw, io_msg_tw_fd_complete);
+ if (task_work_add(target_ctx->submitter_task, &msg->tw,
+ TWA_SIGNAL))
+ return -EOWNERDEAD;
+
+ return IOU_ISSUE_SKIP_COMPLETE;
+ }
+ return io_msg_install_complete(req, issue_flags);
+}
+
int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
@@ -130,6 +200,7 @@ int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
if (unlikely(sqe->buf_index || sqe->personality))
return -EINVAL;
+ msg->src_file = NULL;
msg->user_data = READ_ONCE(sqe->off);
msg->len = READ_ONCE(sqe->len);
msg->cmd = READ_ONCE(sqe->addr);
@@ -164,12 +235,11 @@ int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
}
done:
- if (ret < 0)
+ if (ret < 0) {
+ if (ret == -EAGAIN || ret == IOU_ISSUE_SKIP_COMPLETE)
+ return ret;
req_set_fail(req);
+ }
io_req_set_res(req, ret, 0);
- /* put file to avoid an attempt to IOPOLL the req */
- if (!(req->flags & REQ_F_FIXED_FILE))
- io_put_file(req->file);
- req->file = NULL;
return IOU_OK;
}
diff --git a/io_uring/msg_ring.h b/io_uring/msg_ring.h
index fb9601f202d0..3987ee6c0e5f 100644
--- a/io_uring/msg_ring.h
+++ b/io_uring/msg_ring.h
@@ -2,3 +2,4 @@
int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags);
+void io_msg_ring_cleanup(struct io_kiocb *req);
diff --git a/io_uring/net.c b/io_uring/net.c
index 15dea91625e2..5229976cb582 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -67,7 +67,18 @@ struct io_sr_msg {
struct io_kiocb *notif;
};
-#define IO_APOLL_MULTI_POLLED (REQ_F_APOLL_MULTISHOT | REQ_F_POLLED)
+static inline bool io_check_multishot(struct io_kiocb *req,
+ unsigned int issue_flags)
+{
+ /*
+ * When ->locked_cq is set we only allow to post CQEs from the original
+ * task context. Usual request completions will be handled in other
+ * generic paths but multipoll may decide to post extra cqes.
+ */
+ return !(issue_flags & IO_URING_F_IOWQ) ||
+ !(issue_flags & IO_URING_F_MULTISHOT) ||
+ !req->ctx->task_complete;
+}
int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
@@ -127,13 +138,15 @@ static struct io_async_msghdr *io_msg_alloc_async(struct io_kiocb *req,
struct io_cache_entry *entry;
struct io_async_msghdr *hdr;
- if (!(issue_flags & IO_URING_F_UNLOCKED) &&
- (entry = io_alloc_cache_get(&ctx->netmsg_cache)) != NULL) {
- hdr = container_of(entry, struct io_async_msghdr, cache);
- hdr->free_iov = NULL;
- req->flags |= REQ_F_ASYNC_DATA;
- req->async_data = hdr;
- return hdr;
+ if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+ entry = io_alloc_cache_get(&ctx->netmsg_cache);
+ if (entry) {
+ hdr = container_of(entry, struct io_async_msghdr, cache);
+ hdr->free_iov = NULL;
+ req->flags |= REQ_F_ASYNC_DATA;
+ req->async_data = hdr;
+ return hdr;
+ }
}
if (!io_alloc_async_data(req)) {
@@ -365,7 +378,7 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(!sock))
return -ENOTSOCK;
- ret = import_single_range(WRITE, sr->buf, sr->len, &iov, &msg.msg_iter);
+ ret = import_single_range(ITER_SOURCE, sr->buf, sr->len, &iov, &msg.msg_iter);
if (unlikely(ret))
return ret;
@@ -451,7 +464,7 @@ static int __io_recvmsg_copy_hdr(struct io_kiocb *req,
}
} else {
iomsg->free_iov = iomsg->fast_iov;
- ret = __import_iovec(READ, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
+ ret = __import_iovec(ITER_DEST, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
&iomsg->free_iov, &iomsg->msg.msg_iter,
false);
if (ret > 0)
@@ -503,7 +516,7 @@ static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
}
} else {
iomsg->free_iov = iomsg->fast_iov;
- ret = __import_iovec(READ, (struct iovec __user *)uiov, msg.msg_iovlen,
+ ret = __import_iovec(ITER_DEST, (struct iovec __user *)uiov, msg.msg_iovlen,
UIO_FASTIOV, &iomsg->free_iov,
&iomsg->msg.msg_iter, true);
if (ret < 0)
@@ -591,7 +604,8 @@ static inline void io_recv_prep_retry(struct io_kiocb *req)
* again (for multishot).
*/
static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
- unsigned int cflags, bool mshot_finished)
+ unsigned int cflags, bool mshot_finished,
+ unsigned issue_flags)
{
if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
io_req_set_res(req, *ret, cflags);
@@ -600,21 +614,17 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
}
if (!mshot_finished) {
- if (io_post_aux_cqe(req->ctx, req->cqe.user_data, *ret,
- cflags | IORING_CQE_F_MORE, false)) {
+ if (io_aux_cqe(req->ctx, issue_flags & IO_URING_F_COMPLETE_DEFER,
+ req->cqe.user_data, *ret, cflags | IORING_CQE_F_MORE, true)) {
io_recv_prep_retry(req);
return false;
}
- /*
- * Otherwise stop multishot but use the current result.
- * Probably will end up going into overflow, but this means
- * we cannot trust the ordering anymore
- */
+ /* Otherwise stop multishot but use the current result. */
}
io_req_set_res(req, *ret, cflags);
- if (req->flags & REQ_F_POLLED)
+ if (issue_flags & IO_URING_F_MULTISHOT)
*ret = IOU_STOP_MULTISHOT;
else
*ret = IOU_OK;
@@ -733,6 +743,9 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
(sr->flags & IORING_RECVSEND_POLL_FIRST))
return io_setup_async_msg(req, kmsg, issue_flags);
+ if (!io_check_multishot(req, issue_flags))
+ return io_setup_async_msg(req, kmsg, issue_flags);
+
retry_multishot:
if (io_do_buffer_select(req)) {
void __user *buf;
@@ -752,7 +765,7 @@ retry_multishot:
kmsg->fast_iov[0].iov_base = buf;
kmsg->fast_iov[0].iov_len = len;
- iov_iter_init(&kmsg->msg.msg_iter, READ, kmsg->fast_iov, 1,
+ iov_iter_init(&kmsg->msg.msg_iter, ITER_DEST, kmsg->fast_iov, 1,
len);
}
@@ -773,8 +786,7 @@ retry_multishot:
if (ret < min_ret) {
if (ret == -EAGAIN && force_nonblock) {
ret = io_setup_async_msg(req, kmsg, issue_flags);
- if (ret == -EAGAIN && (req->flags & IO_APOLL_MULTI_POLLED) ==
- IO_APOLL_MULTI_POLLED) {
+ if (ret == -EAGAIN && (issue_flags & IO_URING_F_MULTISHOT)) {
io_kbuf_recycle(req, issue_flags);
return IOU_ISSUE_SKIP_COMPLETE;
}
@@ -803,7 +815,7 @@ retry_multishot:
if (kmsg->msg.msg_inq)
cflags |= IORING_CQE_F_SOCK_NONEMPTY;
- if (!io_recv_finish(req, &ret, cflags, mshot_finished))
+ if (!io_recv_finish(req, &ret, cflags, mshot_finished, issue_flags))
goto retry_multishot;
if (mshot_finished) {
@@ -833,6 +845,9 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
(sr->flags & IORING_RECVSEND_POLL_FIRST))
return -EAGAIN;
+ if (!io_check_multishot(req, issue_flags))
+ return -EAGAIN;
+
sock = sock_from_file(req->file);
if (unlikely(!sock))
return -ENOTSOCK;
@@ -847,7 +862,7 @@ retry_multishot:
sr->buf = buf;
}
- ret = import_single_range(READ, sr->buf, len, &iov, &msg.msg_iter);
+ ret = import_single_range(ITER_DEST, sr->buf, len, &iov, &msg.msg_iter);
if (unlikely(ret))
goto out_free;
@@ -869,7 +884,7 @@ retry_multishot:
ret = sock_recvmsg(sock, &msg, flags);
if (ret < min_ret) {
if (ret == -EAGAIN && force_nonblock) {
- if ((req->flags & IO_APOLL_MULTI_POLLED) == IO_APOLL_MULTI_POLLED) {
+ if (issue_flags & IO_URING_F_MULTISHOT) {
io_kbuf_recycle(req, issue_flags);
return IOU_ISSUE_SKIP_COMPLETE;
}
@@ -902,7 +917,7 @@ out_free:
if (msg.msg_inq)
cflags |= IORING_CQE_F_SOCK_NONEMPTY;
- if (!io_recv_finish(req, &ret, cflags, ret <= 0))
+ if (!io_recv_finish(req, &ret, cflags, ret <= 0, issue_flags))
goto retry_multishot;
return ret;
@@ -925,6 +940,9 @@ void io_send_zc_cleanup(struct io_kiocb *req)
}
}
+#define IO_ZC_FLAGS_COMMON (IORING_RECVSEND_POLL_FIRST | IORING_RECVSEND_FIXED_BUF)
+#define IO_ZC_FLAGS_VALID (IO_ZC_FLAGS_COMMON | IORING_SEND_ZC_REPORT_USAGE)
+
int io_send_zc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_sr_msg *zc = io_kiocb_to_cmd(req, struct io_sr_msg);
@@ -937,10 +955,6 @@ int io_send_zc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
if (req->flags & REQ_F_CQE_SKIP)
return -EINVAL;
- zc->flags = READ_ONCE(sqe->ioprio);
- if (zc->flags & ~(IORING_RECVSEND_POLL_FIRST |
- IORING_RECVSEND_FIXED_BUF))
- return -EINVAL;
notif = zc->notif = io_alloc_notif(ctx);
if (!notif)
return -ENOMEM;
@@ -948,6 +962,17 @@ int io_send_zc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
notif->cqe.res = 0;
notif->cqe.flags = IORING_CQE_F_NOTIF;
req->flags |= REQ_F_NEED_CLEANUP;
+
+ zc->flags = READ_ONCE(sqe->ioprio);
+ if (unlikely(zc->flags & ~IO_ZC_FLAGS_COMMON)) {
+ if (zc->flags & ~IO_ZC_FLAGS_VALID)
+ return -EINVAL;
+ if (zc->flags & IORING_SEND_ZC_REPORT_USAGE) {
+ io_notif_set_extended(notif);
+ io_notif_to_data(notif)->zc_report = true;
+ }
+ }
+
if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
unsigned idx = READ_ONCE(sqe->buf_index);
@@ -1083,13 +1108,14 @@ int io_send_zc(struct io_kiocb *req, unsigned int issue_flags)
return io_setup_async_addr(req, &__address, issue_flags);
if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
- ret = io_import_fixed(WRITE, &msg.msg_iter, req->imu,
+ ret = io_import_fixed(ITER_SOURCE, &msg.msg_iter, req->imu,
(u64)(uintptr_t)zc->buf, zc->len);
if (unlikely(ret))
return ret;
msg.sg_from_iter = io_sg_from_iter;
} else {
- ret = import_single_range(WRITE, zc->buf, zc->len, &iov,
+ io_notif_set_extended(zc->notif);
+ ret = import_single_range(ITER_SOURCE, zc->buf, zc->len, &iov,
&msg.msg_iter);
if (unlikely(ret))
return ret;
@@ -1150,6 +1176,8 @@ int io_sendmsg_zc(struct io_kiocb *req, unsigned int issue_flags)
unsigned flags;
int ret, min_ret = 0;
+ io_notif_set_extended(sr->notif);
+
sock = sock_from_file(req->file);
if (unlikely(!sock))
return -ENOTSOCK;
@@ -1271,6 +1299,8 @@ int io_accept(struct io_kiocb *req, unsigned int issue_flags)
struct file *file;
int ret, fd;
+ if (!io_check_multishot(req, issue_flags))
+ return -EAGAIN;
retry:
if (!fixed) {
fd = __get_unused_fd_flags(accept->flags, accept->nofile);
@@ -1289,8 +1319,7 @@ retry:
* return EAGAIN to arm the poll infra since it
* has already been done
*/
- if ((req->flags & IO_APOLL_MULTI_POLLED) ==
- IO_APOLL_MULTI_POLLED)
+ if (issue_flags & IO_URING_F_MULTISHOT)
ret = IOU_ISSUE_SKIP_COMPLETE;
return ret;
}
@@ -1310,14 +1339,13 @@ retry:
return IOU_OK;
}
- if (ret >= 0 &&
- io_post_aux_cqe(ctx, req->cqe.user_data, ret, IORING_CQE_F_MORE, false))
+ if (ret < 0)
+ return ret;
+ if (io_aux_cqe(ctx, issue_flags & IO_URING_F_COMPLETE_DEFER,
+ req->cqe.user_data, ret, IORING_CQE_F_MORE, true))
goto retry;
- io_req_set_res(req, ret, 0);
- if (req->flags & REQ_F_POLLED)
- return IOU_STOP_MULTISHOT;
- return IOU_OK;
+ return -ECANCELED;
}
int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
diff --git a/io_uring/notif.c b/io_uring/notif.c
index e37c6569d82e..c4bb793ebf0e 100644
--- a/io_uring/notif.c
+++ b/io_uring/notif.c
@@ -9,11 +9,14 @@
#include "notif.h"
#include "rsrc.h"
-static void __io_notif_complete_tw(struct io_kiocb *notif, bool *locked)
+static void io_notif_complete_tw_ext(struct io_kiocb *notif, bool *locked)
{
struct io_notif_data *nd = io_notif_to_data(notif);
struct io_ring_ctx *ctx = notif->ctx;
+ if (nd->zc_report && (nd->zc_copied || !nd->zc_used))
+ notif->cqe.res |= IORING_NOTIF_USAGE_ZC_COPIED;
+
if (nd->account_pages && ctx->user) {
__io_unaccount_mem(ctx->user, nd->account_pages);
nd->account_pages = 0;
@@ -21,16 +24,41 @@ static void __io_notif_complete_tw(struct io_kiocb *notif, bool *locked)
io_req_task_complete(notif, locked);
}
-static void io_uring_tx_zerocopy_callback(struct sk_buff *skb,
- struct ubuf_info *uarg,
- bool success)
+static void io_tx_ubuf_callback(struct sk_buff *skb, struct ubuf_info *uarg,
+ bool success)
{
struct io_notif_data *nd = container_of(uarg, struct io_notif_data, uarg);
struct io_kiocb *notif = cmd_to_io_kiocb(nd);
- if (refcount_dec_and_test(&uarg->refcnt)) {
- notif->io_task_work.func = __io_notif_complete_tw;
+ if (refcount_dec_and_test(&uarg->refcnt))
io_req_task_work_add(notif);
+}
+
+static void io_tx_ubuf_callback_ext(struct sk_buff *skb, struct ubuf_info *uarg,
+ bool success)
+{
+ struct io_notif_data *nd = container_of(uarg, struct io_notif_data, uarg);
+
+ if (nd->zc_report) {
+ if (success && !nd->zc_used && skb)
+ WRITE_ONCE(nd->zc_used, true);
+ else if (!success && !nd->zc_copied)
+ WRITE_ONCE(nd->zc_copied, true);
+ }
+ io_tx_ubuf_callback(skb, uarg, success);
+}
+
+void io_notif_set_extended(struct io_kiocb *notif)
+{
+ struct io_notif_data *nd = io_notif_to_data(notif);
+
+ if (nd->uarg.callback != io_tx_ubuf_callback_ext) {
+ nd->account_pages = 0;
+ nd->zc_report = false;
+ nd->zc_used = false;
+ nd->zc_copied = false;
+ nd->uarg.callback = io_tx_ubuf_callback_ext;
+ notif->io_task_work.func = io_notif_complete_tw_ext;
}
}
@@ -49,24 +77,11 @@ struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)
notif->task = current;
io_get_task_refs(1);
notif->rsrc_node = NULL;
- io_req_set_rsrc_node(notif, ctx, 0);
+ notif->io_task_work.func = io_req_task_complete;
nd = io_notif_to_data(notif);
- nd->account_pages = 0;
nd->uarg.flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
- nd->uarg.callback = io_uring_tx_zerocopy_callback;
+ nd->uarg.callback = io_tx_ubuf_callback;
refcount_set(&nd->uarg.refcnt, 1);
return notif;
}
-
-void io_notif_flush(struct io_kiocb *notif)
- __must_hold(&slot->notif->ctx->uring_lock)
-{
- struct io_notif_data *nd = io_notif_to_data(notif);
-
- /* drop slot's master ref */
- if (refcount_dec_and_test(&nd->uarg.refcnt)) {
- notif->io_task_work.func = __io_notif_complete_tw;
- io_req_task_work_add(notif);
- }
-}
diff --git a/io_uring/notif.h b/io_uring/notif.h
index 5b4d710c8ca5..c88c800cd89d 100644
--- a/io_uring/notif.h
+++ b/io_uring/notif.h
@@ -13,16 +13,29 @@ struct io_notif_data {
struct file *file;
struct ubuf_info uarg;
unsigned long account_pages;
+ bool zc_report;
+ bool zc_used;
+ bool zc_copied;
};
-void io_notif_flush(struct io_kiocb *notif);
struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx);
+void io_notif_set_extended(struct io_kiocb *notif);
static inline struct io_notif_data *io_notif_to_data(struct io_kiocb *notif)
{
return io_kiocb_to_cmd(notif, struct io_notif_data);
}
+static inline void io_notif_flush(struct io_kiocb *notif)
+ __must_hold(&notif->ctx->uring_lock)
+{
+ struct io_notif_data *nd = io_notif_to_data(notif);
+
+ /* drop slot's master ref */
+ if (refcount_dec_and_test(&nd->uarg.refcnt))
+ io_req_task_work_add(notif);
+}
+
static inline int io_notif_account_mem(struct io_kiocb *notif, unsigned len)
{
struct io_ring_ctx *ctx = notif->ctx;
diff --git a/io_uring/opdef.c b/io_uring/opdef.c
index 83dc0f9ad3b2..3aa0d65c50e3 100644
--- a/io_uring/opdef.c
+++ b/io_uring/opdef.c
@@ -63,6 +63,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "READV",
.prep = io_prep_rw,
@@ -80,6 +81,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "WRITEV",
.prep = io_prep_rw,
@@ -103,6 +105,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "READ_FIXED",
.prep = io_prep_rw,
@@ -118,6 +121,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "WRITE_FIXED",
.prep = io_prep_rw,
@@ -277,6 +281,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "READ",
.prep = io_prep_rw,
@@ -292,6 +297,7 @@ const struct io_op_def io_op_defs[] = {
.audit_skip = 1,
.ioprio = 1,
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = sizeof(struct io_async_rw),
.name = "WRITE",
.prep = io_prep_rw,
@@ -439,6 +445,7 @@ const struct io_op_def io_op_defs[] = {
.name = "MSG_RING",
.prep = io_msg_ring_prep,
.issue = io_msg_ring,
+ .cleanup = io_msg_ring_cleanup,
},
[IORING_OP_FSETXATTR] = {
.needs_file = 1,
@@ -481,6 +488,7 @@ const struct io_op_def io_op_defs[] = {
.plug = 1,
.name = "URING_CMD",
.iopoll = 1,
+ .iopoll_queue = 1,
.async_size = uring_cmd_pdu_size(1),
.prep = io_uring_cmd_prep,
.issue = io_uring_cmd,
diff --git a/io_uring/opdef.h b/io_uring/opdef.h
index 3efe06d25473..df7e13d9bfba 100644
--- a/io_uring/opdef.h
+++ b/io_uring/opdef.h
@@ -25,6 +25,8 @@ struct io_op_def {
unsigned ioprio : 1;
/* supports iopoll */
unsigned iopoll : 1;
+ /* have to be put into the iopoll list */
+ unsigned iopoll_queue : 1;
/* opcode specific path will handle ->async_data allocation if needed */
unsigned manual_alloc : 1;
/* size of async data needed, if any */
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 0d9f49c575e0..ee7da6150ec4 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -40,7 +40,14 @@ struct io_poll_table {
};
#define IO_POLL_CANCEL_FLAG BIT(31)
-#define IO_POLL_REF_MASK GENMASK(30, 0)
+#define IO_POLL_RETRY_FLAG BIT(30)
+#define IO_POLL_REF_MASK GENMASK(29, 0)
+
+/*
+ * We usually have 1-2 refs taken, 128 is more than enough and we want to
+ * maximise the margin between this amount and the moment when it overflows.
+ */
+#define IO_POLL_REF_BIAS 128
#define IO_WQE_F_DOUBLE 1
@@ -58,6 +65,21 @@ static inline bool wqe_is_double(struct wait_queue_entry *wqe)
return priv & IO_WQE_F_DOUBLE;
}
+static bool io_poll_get_ownership_slowpath(struct io_kiocb *req)
+{
+ int v;
+
+ /*
+ * poll_refs are already elevated and we don't have much hope for
+ * grabbing the ownership. Instead of incrementing set a retry flag
+ * to notify the loop that there might have been some change.
+ */
+ v = atomic_fetch_or(IO_POLL_RETRY_FLAG, &req->poll_refs);
+ if (v & IO_POLL_REF_MASK)
+ return false;
+ return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
+}
+
/*
* If refs part of ->poll_refs (see IO_POLL_REF_MASK) is 0, it's free. We can
* bump it and acquire ownership. It's disallowed to modify requests while not
@@ -66,6 +88,8 @@ static inline bool wqe_is_double(struct wait_queue_entry *wqe)
*/
static inline bool io_poll_get_ownership(struct io_kiocb *req)
{
+ if (unlikely(atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
+ return io_poll_get_ownership_slowpath(req);
return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
}
@@ -116,6 +140,8 @@ static void io_poll_req_insert_locked(struct io_kiocb *req)
struct io_hash_table *table = &req->ctx->cancel_table_locked;
u32 index = hash_long(req->cqe.user_data, table->hash_bits);
+ lockdep_assert_held(&req->ctx->uring_lock);
+
hlist_add_head(&req->hash_node, &table->hbs[index].list);
}
@@ -211,7 +237,6 @@ enum {
*/
static int io_poll_check_events(struct io_kiocb *req, bool *locked)
{
- struct io_ring_ctx *ctx = req->ctx;
int v, ret;
/* req->task == current here, checking PF_EXITING is safe */
@@ -221,11 +246,31 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
do {
v = atomic_read(&req->poll_refs);
- /* tw handler should be the owner, and so have some references */
- if (WARN_ON_ONCE(!(v & IO_POLL_REF_MASK)))
- return IOU_POLL_DONE;
- if (v & IO_POLL_CANCEL_FLAG)
- return -ECANCELED;
+ if (unlikely(v != 1)) {
+ /* tw should be the owner and so have some refs */
+ if (WARN_ON_ONCE(!(v & IO_POLL_REF_MASK)))
+ return IOU_POLL_NO_ACTION;
+ if (v & IO_POLL_CANCEL_FLAG)
+ return -ECANCELED;
+ /*
+ * cqe.res contains only events of the first wake up
+ * and all others are to be lost. Redo vfs_poll() to get
+ * up to date state.
+ */
+ if ((v & IO_POLL_REF_MASK) != 1)
+ req->cqe.res = 0;
+
+ if (v & IO_POLL_RETRY_FLAG) {
+ req->cqe.res = 0;
+ /*
+ * We won't find new events that came in between
+ * vfs_poll and the ref put unless we clear the
+ * flag in advance.
+ */
+ atomic_andnot(IO_POLL_RETRY_FLAG, &req->poll_refs);
+ v &= ~IO_POLL_RETRY_FLAG;
+ }
+ }
/* the mask was stashed in __io_poll_execute */
if (!req->cqe.res) {
@@ -243,8 +288,8 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
__poll_t mask = mangle_poll(req->cqe.res &
req->apoll_events);
- if (!io_post_aux_cqe(ctx, req->cqe.user_data,
- mask, IORING_CQE_F_MORE, false)) {
+ if (!io_aux_cqe(req->ctx, *locked, req->cqe.user_data,
+ mask, IORING_CQE_F_MORE, false)) {
io_req_set_res(req, mask, 0);
return IOU_POLL_REMOVE_POLL_USE_RES;
}
@@ -256,11 +301,15 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
return ret;
}
+ /* force the next iteration to vfs_poll() */
+ req->cqe.res = 0;
+
/*
* Release all references, retry if someone tried to restart
* task_work while we were executing it.
*/
- } while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs));
+ } while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs) &
+ IO_POLL_REF_MASK);
return IOU_POLL_NO_ACTION;
}
@@ -272,54 +321,38 @@ static void io_poll_task_func(struct io_kiocb *req, bool *locked)
ret = io_poll_check_events(req, locked);
if (ret == IOU_POLL_NO_ACTION)
return;
-
- if (ret == IOU_POLL_DONE) {
- struct io_poll *poll = io_kiocb_to_cmd(req, struct io_poll);
- req->cqe.res = mangle_poll(req->cqe.res & poll->events);
- } else if (ret != IOU_POLL_REMOVE_POLL_USE_RES) {
- req->cqe.res = ret;
- req_set_fail(req);
- }
-
io_poll_remove_entries(req);
io_poll_tw_hash_eject(req, locked);
- io_req_set_res(req, req->cqe.res, 0);
- io_req_task_complete(req, locked);
-}
-
-static void io_apoll_task_func(struct io_kiocb *req, bool *locked)
-{
- int ret;
-
- ret = io_poll_check_events(req, locked);
- if (ret == IOU_POLL_NO_ACTION)
- return;
+ if (req->opcode == IORING_OP_POLL_ADD) {
+ if (ret == IOU_POLL_DONE) {
+ struct io_poll *poll;
- io_poll_remove_entries(req);
- io_poll_tw_hash_eject(req, locked);
+ poll = io_kiocb_to_cmd(req, struct io_poll);
+ req->cqe.res = mangle_poll(req->cqe.res & poll->events);
+ } else if (ret != IOU_POLL_REMOVE_POLL_USE_RES) {
+ req->cqe.res = ret;
+ req_set_fail(req);
+ }
- if (ret == IOU_POLL_REMOVE_POLL_USE_RES)
- io_req_complete_post(req);
- else if (ret == IOU_POLL_DONE)
- io_req_task_submit(req, locked);
- else
- io_req_complete_failed(req, ret);
+ io_req_set_res(req, req->cqe.res, 0);
+ io_req_task_complete(req, locked);
+ } else {
+ io_tw_lock(req->ctx, locked);
+
+ if (ret == IOU_POLL_REMOVE_POLL_USE_RES)
+ io_req_task_complete(req, locked);
+ else if (ret == IOU_POLL_DONE)
+ io_req_task_submit(req, locked);
+ else
+ io_req_defer_failed(req, ret);
+ }
}
static void __io_poll_execute(struct io_kiocb *req, int mask)
{
io_req_set_res(req, mask, 0);
- /*
- * This is useful for poll that is armed on behalf of another
- * request, and where the wakeup path could be on a different
- * CPU. We want to avoid pulling in req->apoll->events for that
- * case.
- */
- if (req->opcode == IORING_OP_POLL_ADD)
- req->io_task_work.func = io_poll_task_func;
- else
- req->io_task_work.func = io_apoll_task_func;
+ req->io_task_work.func = io_poll_task_func;
trace_io_uring_task_add(req, mask);
io_req_task_work_add(req);
@@ -380,6 +413,14 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
return 0;
if (io_poll_get_ownership(req)) {
+ /*
+ * If we trigger a multishot poll off our own wakeup path,
+ * disable multishot as there is a circular dependency between
+ * CQ posting and triggering the event.
+ */
+ if (mask & EPOLL_URING_WAKE)
+ poll->events |= EPOLLONESHOT;
+
/* optional, saves extra locking for removal in tw handler */
if (mask && poll->events & EPOLLONESHOT) {
list_del_init(&poll->wait.entry);
@@ -394,7 +435,8 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
return 1;
}
-static void io_poll_double_prepare(struct io_kiocb *req)
+/* fails only when polling is already completing by the first entry */
+static bool io_poll_double_prepare(struct io_kiocb *req)
{
struct wait_queue_head *head;
struct io_poll *poll = io_poll_get_single(req);
@@ -403,20 +445,20 @@ static void io_poll_double_prepare(struct io_kiocb *req)
rcu_read_lock();
head = smp_load_acquire(&poll->head);
/*
- * poll arm may not hold ownership and so race with
- * io_poll_wake() by modifying req->flags. There is only one
- * poll entry queued, serialise with it by taking its head lock.
+ * poll arm might not hold ownership and so race for req->flags with
+ * io_poll_wake(). There is only one poll entry queued, serialise with
+ * it by taking its head lock. As we're still arming the tw hanlder
+ * is not going to be run, so there are no races with it.
*/
- if (head)
+ if (head) {
spin_lock_irq(&head->lock);
-
- req->flags |= REQ_F_DOUBLE_POLL;
- if (req->opcode == IORING_OP_POLL_ADD)
- req->flags |= REQ_F_ASYNC_DATA;
-
- if (head)
+ req->flags |= REQ_F_DOUBLE_POLL;
+ if (req->opcode == IORING_OP_POLL_ADD)
+ req->flags |= REQ_F_ASYNC_DATA;
spin_unlock_irq(&head->lock);
+ }
rcu_read_unlock();
+ return !!head;
}
static void __io_queue_proc(struct io_poll *poll, struct io_poll_table *pt,
@@ -454,7 +496,11 @@ static void __io_queue_proc(struct io_poll *poll, struct io_poll_table *pt,
/* mark as double wq entry */
wqe_private |= IO_WQE_F_DOUBLE;
io_init_poll_iocb(poll, first->events, first->wait.func);
- io_poll_double_prepare(req);
+ if (!io_poll_double_prepare(req)) {
+ /* the request is completing, just back off */
+ kfree(poll);
+ return;
+ }
*poll_ptr = poll;
} else {
/* fine to modify, there is no poll queued to race with us */
@@ -499,7 +545,6 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
unsigned issue_flags)
{
struct io_ring_ctx *ctx = req->ctx;
- int v;
INIT_HLIST_NODE(&req->hash_node);
req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
@@ -567,11 +612,10 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
if (ipt->owning) {
/*
- * Release ownership. If someone tried to queue a tw while it was
- * locked, kick it off for them.
+ * Try to release ownership. If we see a change of state, e.g.
+ * poll was waken up, queue up a tw, it'll deal with it.
*/
- v = atomic_dec_return(&req->poll_refs);
- if (unlikely(v & IO_POLL_REF_MASK))
+ if (atomic_cmpxchg(&req->poll_refs, 1, 0) != 1)
__io_poll_execute(req, 0);
}
return 0;
@@ -596,10 +640,13 @@ static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req,
if (req->flags & REQ_F_POLLED) {
apoll = req->apoll;
kfree(apoll->double_poll);
- } else if (!(issue_flags & IO_URING_F_UNLOCKED) &&
- (entry = io_alloc_cache_get(&ctx->apoll_cache)) != NULL) {
+ } else if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+ entry = io_alloc_cache_get(&ctx->apoll_cache);
+ if (entry == NULL)
+ goto alloc_apoll;
apoll = container_of(entry, struct async_poll, cache);
} else {
+alloc_apoll:
apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
if (unlikely(!apoll))
return NULL;
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index 55d4ab96fb92..18de10c68a15 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -170,10 +170,10 @@ static void __io_rsrc_put_work(struct io_rsrc_node *ref_node)
if (prsrc->tag) {
if (ctx->flags & IORING_SETUP_IOPOLL) {
mutex_lock(&ctx->uring_lock);
- io_post_aux_cqe(ctx, prsrc->tag, 0, 0, true);
+ io_post_aux_cqe(ctx, prsrc->tag, 0, 0);
mutex_unlock(&ctx->uring_lock);
} else {
- io_post_aux_cqe(ctx, prsrc->tag, 0, 0, true);
+ io_post_aux_cqe(ctx, prsrc->tag, 0, 0);
}
}
@@ -204,6 +204,14 @@ void io_rsrc_put_work(struct work_struct *work)
}
}
+void io_rsrc_put_tw(struct callback_head *cb)
+{
+ struct io_ring_ctx *ctx = container_of(cb, struct io_ring_ctx,
+ rsrc_put_tw);
+
+ io_rsrc_put_work(&ctx->rsrc_put_work.work);
+}
+
void io_wait_rsrc_data(struct io_rsrc_data *data)
{
if (data && !atomic_dec_and_test(&data->refs))
@@ -242,8 +250,15 @@ static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
}
spin_unlock_irqrestore(&ctx->rsrc_ref_lock, flags);
- if (first_add)
- mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
+ if (!first_add)
+ return;
+
+ if (ctx->submitter_task) {
+ if (!task_work_add(ctx->submitter_task, &ctx->rsrc_put_tw,
+ ctx->notify_method))
+ return;
+ }
+ mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
}
static struct io_rsrc_node *io_rsrc_node_alloc(void)
@@ -309,41 +324,41 @@ __cold static int io_rsrc_ref_quiesce(struct io_rsrc_data *data,
/* As we may drop ->uring_lock, other task may have started quiesce */
if (data->quiesce)
return -ENXIO;
+ ret = io_rsrc_node_switch_start(ctx);
+ if (ret)
+ return ret;
+ io_rsrc_node_switch(ctx, data);
+
+ /* kill initial ref, already quiesced if zero */
+ if (atomic_dec_and_test(&data->refs))
+ return 0;
data->quiesce = true;
+ mutex_unlock(&ctx->uring_lock);
do {
- ret = io_rsrc_node_switch_start(ctx);
- if (ret)
+ ret = io_run_task_work_sig(ctx);
+ if (ret < 0) {
+ atomic_inc(&data->refs);
+ /* wait for all works potentially completing data->done */
+ flush_delayed_work(&ctx->rsrc_put_work);
+ reinit_completion(&data->done);
+ mutex_lock(&ctx->uring_lock);
break;
- io_rsrc_node_switch(ctx, data);
+ }
- /* kill initial ref, already quiesced if zero */
- if (atomic_dec_and_test(&data->refs))
- break;
- mutex_unlock(&ctx->uring_lock);
flush_delayed_work(&ctx->rsrc_put_work);
ret = wait_for_completion_interruptible(&data->done);
if (!ret) {
mutex_lock(&ctx->uring_lock);
- if (atomic_read(&data->refs) > 0) {
- /*
- * it has been revived by another thread while
- * we were unlocked
- */
- mutex_unlock(&ctx->uring_lock);
- } else {
+ if (atomic_read(&data->refs) <= 0)
break;
- }
+ /*
+ * it has been revived by another thread while
+ * we were unlocked
+ */
+ mutex_unlock(&ctx->uring_lock);
}
-
- atomic_inc(&data->refs);
- /* wait for all works potentially completing data->done */
- flush_delayed_work(&ctx->rsrc_put_work);
- reinit_completion(&data->done);
-
- ret = io_run_task_work_sig(ctx);
- mutex_lock(&ctx->uring_lock);
- } while (ret >= 0);
+ } while (1);
data->quiesce = false;
return ret;
diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h
index 81445a477622..2b8743645efc 100644
--- a/io_uring/rsrc.h
+++ b/io_uring/rsrc.h
@@ -53,6 +53,7 @@ struct io_mapped_ubuf {
struct bio_vec bvec[];
};
+void io_rsrc_put_tw(struct callback_head *cb);
void io_rsrc_put_work(struct work_struct *work);
void io_rsrc_refs_refill(struct io_ring_ctx *ctx);
void io_wait_rsrc_data(struct io_rsrc_data *data);
diff --git a/io_uring/rw.c b/io_uring/rw.c
index bb47cc4da713..b9cac5706e8d 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -286,6 +286,12 @@ static inline int io_fixup_rw_res(struct io_kiocb *req, long res)
static void io_req_rw_complete(struct io_kiocb *req, bool *locked)
{
io_req_io_end(req);
+
+ if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
+ unsigned issue_flags = *locked ? 0 : IO_URING_F_UNLOCKED;
+
+ req->cqe.flags |= io_put_kbuf(req, issue_flags);
+ }
io_req_task_complete(req, locked);
}
@@ -548,12 +554,12 @@ static inline int io_rw_prep_async(struct io_kiocb *req, int rw)
int io_readv_prep_async(struct io_kiocb *req)
{
- return io_rw_prep_async(req, READ);
+ return io_rw_prep_async(req, ITER_DEST);
}
int io_writev_prep_async(struct io_kiocb *req)
{
- return io_rw_prep_async(req, WRITE);
+ return io_rw_prep_async(req, ITER_SOURCE);
}
/*
@@ -665,6 +671,7 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode)
ret = kiocb_set_rw_flags(kiocb, rw->flags);
if (unlikely(ret))
return ret;
+ kiocb->ki_flags |= IOCB_ALLOC_CACHE;
/*
* If the file is marked O_NONBLOCK, still allow retry for it if it
@@ -680,7 +687,7 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode)
return -EOPNOTSUPP;
kiocb->private = NULL;
- kiocb->ki_flags |= IOCB_HIPRI | IOCB_ALLOC_CACHE;
+ kiocb->ki_flags |= IOCB_HIPRI;
kiocb->ki_complete = io_complete_rw_iopoll;
req->iopoll_completed = 0;
} else {
@@ -704,7 +711,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
loff_t *ppos;
if (!req_has_async_data(req)) {
- ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
+ ret = io_import_iovec(ITER_DEST, req, &iovec, s, issue_flags);
if (unlikely(ret < 0))
return ret;
} else {
@@ -716,7 +723,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
* buffers, as we dropped the selected one before retry.
*/
if (io_do_buffer_select(req)) {
- ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
+ ret = io_import_iovec(ITER_DEST, req, &iovec, s, issue_flags);
if (unlikely(ret < 0))
return ret;
}
@@ -851,7 +858,7 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
loff_t *ppos;
if (!req_has_async_data(req)) {
- ret = io_import_iovec(WRITE, req, &iovec, s, issue_flags);
+ ret = io_import_iovec(ITER_SOURCE, req, &iovec, s, issue_flags);
if (unlikely(ret < 0))
return ret;
} else {
diff --git a/io_uring/timeout.c b/io_uring/timeout.c
index e8a8c2099480..5b4bc93fd6e0 100644
--- a/io_uring/timeout.c
+++ b/io_uring/timeout.c
@@ -63,7 +63,7 @@ static bool io_kill_timeout(struct io_kiocb *req, int status)
atomic_set(&req->ctx->cq_timeouts,
atomic_read(&req->ctx->cq_timeouts) + 1);
list_del_init(&timeout->list);
- io_req_tw_post_queue(req, status, 0);
+ io_req_queue_tw_complete(req, status);
return true;
}
return false;
@@ -159,7 +159,7 @@ void io_disarm_next(struct io_kiocb *req)
req->flags &= ~REQ_F_ARM_LTIMEOUT;
if (link && link->opcode == IORING_OP_LINK_TIMEOUT) {
io_remove_next_linked(req);
- io_req_tw_post_queue(link, -ECANCELED, 0);
+ io_req_queue_tw_complete(link, -ECANCELED);
}
} else if (req->flags & REQ_F_LINK_TIMEOUT) {
struct io_ring_ctx *ctx = req->ctx;
@@ -168,7 +168,7 @@ void io_disarm_next(struct io_kiocb *req)
link = io_disarm_linked_timeout(req);
spin_unlock_irq(&ctx->timeout_lock);
if (link)
- io_req_tw_post_queue(link, -ECANCELED, 0);
+ io_req_queue_tw_complete(link, -ECANCELED);
}
if (unlikely((req->flags & REQ_F_FAIL) &&
!(req->flags & REQ_F_HARDLINK)))
@@ -282,11 +282,11 @@ static void io_req_task_link_timeout(struct io_kiocb *req, bool *locked)
ret = io_try_cancel(req->task->io_uring, &cd, issue_flags);
}
io_req_set_res(req, ret ?: -ETIME, 0);
- io_req_complete_post(req);
+ io_req_task_complete(req, locked);
io_put_req(prev);
} else {
io_req_set_res(req, -ETIME, 0);
- io_req_complete_post(req);
+ io_req_task_complete(req, locked);
}
}
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index e50de0b6b9f8..446a189b78b0 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -56,7 +56,7 @@ void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2)
/* order with io_iopoll_req_issued() checking ->iopoll_complete */
smp_store_release(&req->iopoll_completed, 1);
else
- __io_req_complete(req, 0);
+ io_req_complete_post(req, 0);
}
EXPORT_SYMBOL_GPL(io_uring_cmd_done);
diff --git a/io_uring/xattr.c b/io_uring/xattr.c
index 99df641594d7..6201a9f442c6 100644
--- a/io_uring/xattr.c
+++ b/io_uring/xattr.c
@@ -112,7 +112,7 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
if (issue_flags & IO_URING_F_NONBLOCK)
return -EAGAIN;
- ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt),
+ ret = do_getxattr(mnt_idmap(req->file->f_path.mnt),
req->file->f_path.dentry,
&ix->ctx);
@@ -133,9 +133,7 @@ int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
retry:
ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
if (!ret) {
- ret = do_getxattr(mnt_user_ns(path.mnt),
- path.dentry,
- &ix->ctx);
+ ret = do_getxattr(mnt_idmap(path.mnt), path.dentry, &ix->ctx);
path_put(&path);
if (retry_estale(ret, lookup_flags)) {
@@ -213,7 +211,7 @@ static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
ret = mnt_want_write(path->mnt);
if (!ret) {
- ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx);
+ ret = do_setxattr(mnt_idmap(path->mnt), path->dentry, &ix->ctx);
mnt_drop_write(path->mnt);
}
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 467a194b8a2e..d09aa1c1e3e6 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1726,7 +1726,8 @@ static int __init init_mqueue_fs(void)
if (!setup_mq_sysctls(&init_ipc_ns)) {
pr_warn("sysctl registration failed\n");
- return -ENOMEM;
+ error = -ENOMEM;
+ goto out_kmem;
}
error = register_filesystem(&mqueue_fs_type);
@@ -1744,8 +1745,9 @@ static int __init init_mqueue_fs(void)
out_filesystem:
unregister_filesystem(&mqueue_fs_type);
out_sysctl:
- kmem_cache_destroy(mqueue_inode_cachep);
retire_mq_sysctls(&init_ipc_ns);
+out_kmem:
+ kmem_cache_destroy(mqueue_inode_cachep);
return error;
}
diff --git a/ipc/sem.c b/ipc/sem.c
index c8496f98b139..00f88aa01ac5 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -2179,14 +2179,15 @@ long __do_semtimedop(int semid, struct sembuf *sops,
* scenarios where we were awakened externally, during the
* window between wake_q_add() and wake_up_q().
*/
+ rcu_read_lock();
error = READ_ONCE(queue.status);
if (error != -EINTR) {
/* see SEM_BARRIER_2 for purpose/pairing */
smp_acquire__after_ctrl_dep();
+ rcu_read_unlock();
goto out;
}
- rcu_read_lock();
locknum = sem_lock(sma, sops, nsops);
if (!ipc_valid_object(&sma->sem_perm))
diff --git a/ipc/shm.c b/ipc/shm.c
index 7d86f058fb86..bd2fcc4d454e 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -275,10 +275,8 @@ static inline void shm_rmid(struct shmid_kernel *s)
}
-static int __shm_open(struct vm_area_struct *vma)
+static int __shm_open(struct shm_file_data *sfd)
{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
struct shmid_kernel *shp;
shp = shm_lock(sfd->ns, sfd->id);
@@ -302,7 +300,15 @@ static int __shm_open(struct vm_area_struct *vma)
/* This is called by fork, once for every shm attach. */
static void shm_open(struct vm_area_struct *vma)
{
- int err = __shm_open(vma);
+ struct file *file = vma->vm_file;
+ struct shm_file_data *sfd = shm_file_data(file);
+ int err;
+
+ /* Always call underlying open if present */
+ if (sfd->vm_ops->open)
+ sfd->vm_ops->open(vma);
+
+ err = __shm_open(sfd);
/*
* We raced in the idr lookup or with shm_destroy().
* Either way, the ID is busted.
@@ -359,10 +365,8 @@ static bool shm_may_destroy(struct shmid_kernel *shp)
* The descriptor has already been removed from the current->mm->mmap list
* and will later be kfree()d.
*/
-static void shm_close(struct vm_area_struct *vma)
+static void __shm_close(struct shm_file_data *sfd)
{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
struct shmid_kernel *shp;
struct ipc_namespace *ns = sfd->ns;
@@ -388,6 +392,18 @@ done:
up_write(&shm_ids(ns).rwsem);
}
+static void shm_close(struct vm_area_struct *vma)
+{
+ struct file *file = vma->vm_file;
+ struct shm_file_data *sfd = shm_file_data(file);
+
+ /* Always call underlying close if present */
+ if (sfd->vm_ops->close)
+ sfd->vm_ops->close(vma);
+
+ __shm_close(sfd);
+}
+
/* Called with ns->shm_ids(ns).rwsem locked */
static int shm_try_destroy_orphaned(int id, void *p, void *data)
{
@@ -583,13 +599,13 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma)
* IPC ID that was removed, and possibly even reused by another shm
* segment already. Propagate this case as an error to caller.
*/
- ret = __shm_open(vma);
+ ret = __shm_open(sfd);
if (ret)
return ret;
ret = call_mmap(sfd->file, vma);
if (ret) {
- shm_close(vma);
+ __shm_close(sfd);
return ret;
}
sfd->vm_ops = vma->vm_ops;
diff --git a/kernel/acct.c b/kernel/acct.c
index 62200d799b9b..010667ce6080 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -320,7 +320,7 @@ void acct_exit_ns(struct pid_namespace *ns)
}
/*
- * encode an unsigned long into a comp_t
+ * encode an u64 into a comp_t
*
* This routine has been adopted from the encode_comp_t() function in
* the kern_acct.c file of the FreeBSD operating system. The encoding
@@ -331,7 +331,7 @@ void acct_exit_ns(struct pid_namespace *ns)
#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
-static comp_t encode_comp_t(unsigned long value)
+static comp_t encode_comp_t(u64 value)
{
int exp, rnd;
@@ -350,6 +350,8 @@ static comp_t encode_comp_t(unsigned long value)
exp++;
}
+ if (exp > (((comp_t) ~0U) >> MANTSIZE))
+ return (comp_t) ~0U;
/*
* Clean it up and polish it off.
*/
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 9f8c05228d6d..547c88be8a28 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -806,30 +806,53 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
}
/**
- * audit_filter_uring - apply filters to an io_uring operation
+ * __audit_filter_op - common filter helper for operations (syscall/uring/etc)
* @tsk: associated task
* @ctx: audit context
+ * @list: audit filter list
+ * @name: audit_name (can be NULL)
+ * @op: current syscall/uring_op
+ *
+ * Run the udit filters specified in @list against @tsk using @ctx,
+ * @name, and @op, as necessary; the caller is responsible for ensuring
+ * that the call is made while the RCU read lock is held. The @name
+ * parameter can be NULL, but all others must be specified.
+ * Returns 1/true if the filter finds a match, 0/false if none are found.
*/
-static void audit_filter_uring(struct task_struct *tsk,
- struct audit_context *ctx)
+static int __audit_filter_op(struct task_struct *tsk,
+ struct audit_context *ctx,
+ struct list_head *list,
+ struct audit_names *name,
+ unsigned long op)
{
struct audit_entry *e;
enum audit_state state;
+ list_for_each_entry_rcu(e, list, list) {
+ if (audit_in_mask(&e->rule, op) &&
+ audit_filter_rules(tsk, &e->rule, ctx, name,
+ &state, false)) {
+ ctx->current_state = state;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * audit_filter_uring - apply filters to an io_uring operation
+ * @tsk: associated task
+ * @ctx: audit context
+ */
+static void audit_filter_uring(struct task_struct *tsk,
+ struct audit_context *ctx)
+{
if (auditd_test_task(tsk))
return;
rcu_read_lock();
- list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
- list) {
- if (audit_in_mask(&e->rule, ctx->uring_op) &&
- audit_filter_rules(tsk, &e->rule, ctx, NULL, &state,
- false)) {
- rcu_read_unlock();
- ctx->current_state = state;
- return;
- }
- }
+ __audit_filter_op(tsk, ctx, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
+ NULL, ctx->uring_op);
rcu_read_unlock();
}
@@ -841,24 +864,13 @@ static void audit_filter_uring(struct task_struct *tsk,
static void audit_filter_syscall(struct task_struct *tsk,
struct audit_context *ctx)
{
- struct audit_entry *e;
- enum audit_state state;
-
if (auditd_test_task(tsk))
return;
rcu_read_lock();
- list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_EXIT], list) {
- if (audit_in_mask(&e->rule, ctx->major) &&
- audit_filter_rules(tsk, &e->rule, ctx, NULL,
- &state, false)) {
- rcu_read_unlock();
- ctx->current_state = state;
- return;
- }
- }
+ __audit_filter_op(tsk, ctx, &audit_filter_list[AUDIT_FILTER_EXIT],
+ NULL, ctx->major);
rcu_read_unlock();
- return;
}
/*
@@ -870,17 +882,8 @@ static int audit_filter_inode_name(struct task_struct *tsk,
struct audit_context *ctx) {
int h = audit_hash_ino((u32)n->ino);
struct list_head *list = &audit_inode_hash[h];
- struct audit_entry *e;
- enum audit_state state;
- list_for_each_entry_rcu(e, list, list) {
- if (audit_in_mask(&e->rule, ctx->major) &&
- audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
- ctx->current_state = state;
- return 1;
- }
- }
- return 0;
+ return __audit_filter_op(tsk, ctx, list, n, ctx->major);
}
/* At syscall exit time, this filter is called if any audit_names have been
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 802fc15b0d73..f27fa5ba7d72 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -74,7 +74,7 @@ bpf_selem_alloc(struct bpf_local_storage_map *smap, void *owner,
gfp_flags | __GFP_NOWARN);
if (selem) {
if (value)
- memcpy(SDATA(selem)->data, value, smap->map.value_size);
+ copy_map_value(&smap->map, SDATA(selem)->data, value);
return selem;
}
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 25a54e04560e..38159f39e2af 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1032,7 +1032,7 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
hdr->size = size;
hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)),
PAGE_SIZE - sizeof(*hdr));
- start = prandom_u32_max(hole) & ~(alignment - 1);
+ start = get_random_u32_below(hole) & ~(alignment - 1);
/* Leave a random number of instructions before BPF code. */
*image_ptr = &hdr->image[start];
@@ -1094,7 +1094,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
hole = min_t(unsigned int, size - (proglen + sizeof(*ro_header)),
BPF_PROG_CHUNK_SIZE - sizeof(*ro_header));
- start = prandom_u32_max(hole) & ~(alignment - 1);
+ start = get_random_u32_below(hole) & ~(alignment - 1);
*image_ptr = &ro_header->image[start];
*rw_image = &(*rw_header)->image[start];
diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c
index 04f0a045dcaa..c19719f48ce0 100644
--- a/kernel/bpf/dispatcher.c
+++ b/kernel/bpf/dispatcher.c
@@ -4,7 +4,7 @@
#include <linux/hash.h>
#include <linux/bpf.h>
#include <linux/filter.h>
-#include <linux/init.h>
+#include <linux/static_call.h>
/* The BPF dispatcher is a multiway branch code generator. The
* dispatcher is a mechanism to avoid the performance penalty of an
@@ -91,11 +91,6 @@ int __weak arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int n
return -ENOTSUPP;
}
-int __weak __init bpf_arch_init_dispatcher_early(void *ip)
-{
- return -ENOTSUPP;
-}
-
static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image, void *buf)
{
s64 ips[BPF_DISPATCHER_MAX] = {}, *ipsp = &ips[0];
@@ -110,17 +105,11 @@ static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image, void *b
static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)
{
- void *old, *new, *tmp;
- u32 noff;
- int err;
-
- if (!prev_num_progs) {
- old = NULL;
- noff = 0;
- } else {
- old = d->image + d->image_off;
+ void *new, *tmp;
+ u32 noff = 0;
+
+ if (prev_num_progs)
noff = d->image_off ^ (PAGE_SIZE / 2);
- }
new = d->num_progs ? d->image + noff : NULL;
tmp = d->num_progs ? d->rw_image + noff : NULL;
@@ -134,11 +123,10 @@ static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)
return;
}
- err = bpf_arch_text_poke(d->func, BPF_MOD_JUMP, old, new);
- if (err || !new)
- return;
+ __BPF_DISPATCHER_UPDATE(d, new ?: (void *)&bpf_dispatcher_nop_func);
- d->image_off = noff;
+ if (new)
+ d->image_off = noff;
}
void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
diff --git a/kernel/bpf/percpu_freelist.c b/kernel/bpf/percpu_freelist.c
index b6e7f5c5b9ab..034cf87b54e9 100644
--- a/kernel/bpf/percpu_freelist.c
+++ b/kernel/bpf/percpu_freelist.c
@@ -100,22 +100,21 @@ void pcpu_freelist_populate(struct pcpu_freelist *s, void *buf, u32 elem_size,
u32 nr_elems)
{
struct pcpu_freelist_head *head;
- int i, cpu, pcpu_entries;
+ unsigned int cpu, cpu_idx, i, j, n, m;
- pcpu_entries = nr_elems / num_possible_cpus() + 1;
- i = 0;
+ n = nr_elems / num_possible_cpus();
+ m = nr_elems % num_possible_cpus();
+ cpu_idx = 0;
for_each_possible_cpu(cpu) {
-again:
head = per_cpu_ptr(s->freelist, cpu);
- /* No locking required as this is not visible yet. */
- pcpu_freelist_push_node(head, buf);
- i++;
- buf += elem_size;
- if (i == nr_elems)
- break;
- if (i % pcpu_entries)
- goto again;
+ j = n + (cpu_idx < m ? 1 : 0);
+ for (i = 0; i < j; i++) {
+ /* No locking required as this is not visible yet. */
+ pcpu_freelist_push_node(head, buf);
+ buf += elem_size;
+ }
+ cpu_idx++;
}
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7f0a9f6cb889..264b3dc714cc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1027,12 +1027,17 @@ out:
*/
static void *realloc_array(void *arr, size_t old_n, size_t new_n, size_t size)
{
+ void *new_arr;
+
if (!new_n || old_n == new_n)
goto out;
- arr = krealloc_array(arr, new_n, size, GFP_KERNEL);
- if (!arr)
+ new_arr = krealloc_array(arr, new_n, size, GFP_KERNEL);
+ if (!new_arr) {
+ kfree(arr);
return NULL;
+ }
+ arr = new_arr;
if (new_n > old_n)
memset(arr + old_n * size, 0, (new_n - old_n) * size);
@@ -6618,8 +6623,12 @@ static int release_reference(struct bpf_verifier_env *env,
return err;
bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
- if (reg->ref_obj_id == ref_obj_id)
- __mark_reg_unknown(env, reg);
+ if (reg->ref_obj_id == ref_obj_id) {
+ if (!env->allow_ptr_leaks)
+ __mark_reg_not_init(env, reg);
+ else
+ __mark_reg_unknown(env, reg);
+ }
}));
return 0;
@@ -6736,11 +6745,11 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn
/* Transfer references to the callee */
err = copy_reference_state(callee, caller);
if (err)
- return err;
+ goto err_out;
err = set_callee_state_cb(env, caller, callee, *insn_idx);
if (err)
- return err;
+ goto err_out;
clear_caller_saved_regs(env, caller->regs);
@@ -6757,6 +6766,11 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn
print_verifier_state(env, callee, true);
}
return 0;
+
+err_out:
+ free_func_state(callee);
+ state->frame[state->curframe + 1] = NULL;
+ return err;
}
int map_set_for_each_callback_args(struct bpf_verifier_env *env,
@@ -6970,8 +6984,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
return -EINVAL;
}
- state->curframe--;
- caller = state->frame[state->curframe];
+ caller = state->frame[state->curframe - 1];
if (callee->in_callback_fn) {
/* enforce R0 return value range [0, 1]. */
struct tnum range = callee->callback_ret_range;
@@ -7010,7 +7023,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
}
/* clear everything in the callee */
free_func_state(callee);
- state->frame[state->curframe + 1] = NULL;
+ state->frame[state->curframe--] = NULL;
return 0;
}
diff --git a/kernel/capability.c b/kernel/capability.c
index 765194f5d678..860fd22117c1 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -489,8 +489,8 @@ bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
struct user_namespace *mnt_userns,
const struct inode *inode)
{
- return kuid_has_mapping(ns, i_uid_into_mnt(mnt_userns, inode)) &&
- kgid_has_mapping(ns, i_gid_into_mnt(mnt_userns, inode));
+ return vfsuid_has_mapping(ns, i_uid_into_vfsuid(mnt_userns, inode)) &&
+ vfsgid_has_mapping(ns, i_gid_into_vfsgid(mnt_userns, inode));
}
/**
diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h
index fd4020835ec6..367b0a42ada9 100644
--- a/kernel/cgroup/cgroup-internal.h
+++ b/kernel/cgroup/cgroup-internal.h
@@ -167,7 +167,6 @@ struct cgroup_mgctx {
extern spinlock_t css_set_lock;
extern struct cgroup_subsys *cgroup_subsys[];
extern struct list_head cgroup_roots;
-extern struct file_system_type cgroup_fs_type;
/* iterate across the hierarchies */
#define for_each_root(root) \
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 2319946715e0..15cc26513596 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -248,6 +248,12 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css,
struct cgroup *cgrp, struct cftype cfts[],
bool is_add);
+#ifdef CONFIG_DEBUG_CGROUP_REF
+#define CGROUP_REF_FN_ATTRS noinline
+#define CGROUP_REF_EXPORT(fn) EXPORT_SYMBOL_GPL(fn);
+#include <linux/cgroup_refcnt.h>
+#endif
+
/**
* cgroup_ssid_enabled - cgroup subsys enabled test by subsys ID
* @ssid: subsys ID of interest
@@ -2860,14 +2866,12 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup,
* take an rcu_read_lock.
*/
spin_lock_irq(&css_set_lock);
- rcu_read_lock();
task = leader;
do {
cgroup_migrate_add_task(task, mgctx);
if (!threadgroup)
break;
} while_each_thread(leader, task);
- rcu_read_unlock();
spin_unlock_irq(&css_set_lock);
return cgroup_migrate_execute(mgctx);
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b474289c15b8..589827ccda8b 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -550,11 +550,15 @@ static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask)
/*
* update task's spread flag if cpuset's page/slab spread flag is set
*
- * Call with callback_lock or cpuset_rwsem held.
+ * Call with callback_lock or cpuset_rwsem held. The check can be skipped
+ * if on default hierarchy.
*/
-static void cpuset_update_task_spread_flag(struct cpuset *cs,
+static void cpuset_update_task_spread_flags(struct cpuset *cs,
struct task_struct *tsk)
{
+ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys))
+ return;
+
if (is_spread_page(cs))
task_set_spread_page(tsk);
else
@@ -2153,7 +2157,7 @@ static void update_tasks_flags(struct cpuset *cs)
css_task_iter_start(&cs->css, 0, &it);
while ((task = css_task_iter_next(&it)))
- cpuset_update_task_spread_flag(cs, task);
+ cpuset_update_task_spread_flags(cs, task);
css_task_iter_end(&it);
}
@@ -2509,12 +2513,28 @@ static void cpuset_attach(struct cgroup_taskset *tset)
struct cgroup_subsys_state *css;
struct cpuset *cs;
struct cpuset *oldcs = cpuset_attach_old_cs;
+ bool cpus_updated, mems_updated;
cgroup_taskset_first(tset, &css);
cs = css_cs(css);
lockdep_assert_cpus_held(); /* see cgroup_attach_lock() */
percpu_down_write(&cpuset_rwsem);
+ cpus_updated = !cpumask_equal(cs->effective_cpus,
+ oldcs->effective_cpus);
+ mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
+
+ /*
+ * In the default hierarchy, enabling cpuset in the child cgroups
+ * will trigger a number of cpuset_attach() calls with no change
+ * in effective cpus and mems. In that case, we can optimize out
+ * by skipping the task iteration and update.
+ */
+ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
+ !cpus_updated && !mems_updated) {
+ cpuset_attach_nodemask_to = cs->effective_mems;
+ goto out;
+ }
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
@@ -2530,14 +2550,19 @@ static void cpuset_attach(struct cgroup_taskset *tset)
WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach));
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
- cpuset_update_task_spread_flag(cs, task);
+ cpuset_update_task_spread_flags(cs, task);
}
/*
* Change mm for all threadgroup leaders. This is expensive and may
- * sleep and should be moved outside migration path proper.
+ * sleep and should be moved outside migration path proper. Skip it
+ * if there is no change in effective_mems and CS_MEMORY_MIGRATE is
+ * not set.
*/
cpuset_attach_nodemask_to = cs->effective_mems;
+ if (!is_memory_migrate(cs) && !mems_updated)
+ goto out;
+
cgroup_taskset_for_each_leader(leader, css, tset) {
struct mm_struct *mm = get_task_mm(leader);
@@ -2560,6 +2585,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
}
}
+out:
cs->old_mems_allowed = cpuset_attach_nodemask_to;
cs->attach_in_progress--;
@@ -3046,11 +3072,15 @@ static struct cftype dfl_files[] = {
};
-/*
- * cpuset_css_alloc - allocate a cpuset css
- * cgrp: control group that the new cpuset will be part of
+/**
+ * cpuset_css_alloc - Allocate a cpuset css
+ * @parent_css: Parent css of the control group that the new cpuset will be
+ * part of
+ * Return: cpuset css on success, -ENOMEM on failure.
+ *
+ * Allocate and initialize a new cpuset css, for non-NULL @parent_css, return
+ * top cpuset css otherwise.
*/
-
static struct cgroup_subsys_state *
cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
{
diff --git a/kernel/configs/tiny.config b/kernel/configs/tiny.config
index 8a44b93da0f3..c2f9c912df1c 100644
--- a/kernel/configs/tiny.config
+++ b/kernel/configs/tiny.config
@@ -7,5 +7,6 @@ CONFIG_KERNEL_XZ=y
# CONFIG_KERNEL_LZO is not set
# CONFIG_KERNEL_LZ4 is not set
# CONFIG_SLAB is not set
-# CONFIG_SLUB is not set
-CONFIG_SLOB=y
+# CONFIG_SLOB_DEPRECATED is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_TINY=y
diff --git a/kernel/cpu.c b/kernel/cpu.c
index bbad5e375d3b..6c0a92ca6bb5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -663,21 +663,51 @@ static bool cpuhp_next_state(bool bringup,
return true;
}
-static int cpuhp_invoke_callback_range(bool bringup,
- unsigned int cpu,
- struct cpuhp_cpu_state *st,
- enum cpuhp_state target)
+static int __cpuhp_invoke_callback_range(bool bringup,
+ unsigned int cpu,
+ struct cpuhp_cpu_state *st,
+ enum cpuhp_state target,
+ bool nofail)
{
enum cpuhp_state state;
- int err = 0;
+ int ret = 0;
while (cpuhp_next_state(bringup, &state, st, target)) {
+ int err;
+
err = cpuhp_invoke_callback(cpu, state, bringup, NULL, NULL);
- if (err)
+ if (!err)
+ continue;
+
+ if (nofail) {
+ pr_warn("CPU %u %s state %s (%d) failed (%d)\n",
+ cpu, bringup ? "UP" : "DOWN",
+ cpuhp_get_step(st->state)->name,
+ st->state, err);
+ ret = -1;
+ } else {
+ ret = err;
break;
+ }
}
- return err;
+ return ret;
+}
+
+static inline int cpuhp_invoke_callback_range(bool bringup,
+ unsigned int cpu,
+ struct cpuhp_cpu_state *st,
+ enum cpuhp_state target)
+{
+ return __cpuhp_invoke_callback_range(bringup, cpu, st, target, false);
+}
+
+static inline void cpuhp_invoke_callback_range_nofail(bool bringup,
+ unsigned int cpu,
+ struct cpuhp_cpu_state *st,
+ enum cpuhp_state target)
+{
+ __cpuhp_invoke_callback_range(bringup, cpu, st, target, true);
}
static inline bool can_rollback_cpu(struct cpuhp_cpu_state *st)
@@ -999,7 +1029,6 @@ static int take_cpu_down(void *_param)
struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE);
int err, cpu = smp_processor_id();
- int ret;
/* Ensure this CPU doesn't handle any more interrupts. */
err = __cpu_disable();
@@ -1012,13 +1041,10 @@ static int take_cpu_down(void *_param)
*/
WARN_ON(st->state != (CPUHP_TEARDOWN_CPU - 1));
- /* Invoke the former CPU_DYING callbacks */
- ret = cpuhp_invoke_callback_range(false, cpu, st, target);
-
/*
- * DYING must not fail!
+ * Invoke the former CPU_DYING callbacks. DYING must not fail!
*/
- WARN_ON_ONCE(ret);
+ cpuhp_invoke_callback_range_nofail(false, cpu, st, target);
/* Give up timekeeping duties */
tick_handover_do_timer();
@@ -1296,16 +1322,14 @@ void notify_cpu_starting(unsigned int cpu)
{
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE);
- int ret;
rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */
cpumask_set_cpu(cpu, &cpus_booted_once_mask);
- ret = cpuhp_invoke_callback_range(true, cpu, st, target);
/*
* STARTING must not fail!
*/
- WARN_ON_ONCE(ret);
+ cpuhp_invoke_callback_range_nofail(true, cpu, st, target);
}
/*
@@ -2326,8 +2350,10 @@ static ssize_t target_store(struct device *dev, struct device_attribute *attr,
if (st->state < target)
ret = cpu_up(dev->id, target);
- else
+ else if (st->state > target)
ret = cpu_down(dev->id, target);
+ else if (WARN_ON(st->target != target))
+ st->target = target;
out:
unlock_device_hotplug();
return ret ? ret : count;
@@ -2688,6 +2714,7 @@ void __init boot_cpu_hotplug_init(void)
cpumask_set_cpu(smp_processor_id(), &cpus_booted_once_mask);
#endif
this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
+ this_cpu_write(cpuhp_state.target, CPUHP_ONLINE);
}
/*
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index a0eb4d5cf557..87ef6096823f 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -383,6 +383,9 @@ void vmcoreinfo_append_str(const char *fmt, ...)
memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
vmcoreinfo_size += r;
+
+ WARN_ONCE(vmcoreinfo_size == VMCOREINFO_BYTES,
+ "vmcoreinfo data exceeds allocated size, truncating");
}
/*
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 67d3c48a1522..5c7e9ba7cd6b 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -545,6 +545,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
{
struct console *c;
const char *cp;
+ int cookie;
int len;
if (msg_len == 0)
@@ -558,8 +559,20 @@ static void kdb_msg_write(const char *msg, int msg_len)
cp++;
}
- for_each_console(c) {
- if (!(c->flags & CON_ENABLED))
+ /*
+ * The console_srcu_read_lock() only provides safe console list
+ * traversal. The use of the ->write() callback relies on all other
+ * CPUs being stopped at the moment and console drivers being able to
+ * handle reentrance when @oops_in_progress is set.
+ *
+ * There is no guarantee that every console driver can handle
+ * reentrance in this way; the developer deploying the debugger
+ * is responsible for ensuring that the console drivers they
+ * have selected handle reentrance appropriately.
+ */
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+ if (!(console_srcu_read_flags(c) & CON_ENABLED))
continue;
if (c == dbg_io_ops->cons)
continue;
@@ -577,6 +590,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
--oops_in_progress;
touch_nmi_watchdog();
}
+ console_srcu_read_unlock(cookie);
}
int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 33437d620644..c026a5a5e046 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -498,6 +498,14 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
WARN_ON_ONCE(!dev->coherent_dma_mask);
+ /*
+ * DMA allocations can never be turned back into a page pointer, so
+ * requesting compound pages doesn't make sense (and can't even be
+ * supported at all by various backends).
+ */
+ if (WARN_ON_ONCE(flag & __GFP_COMP))
+ return NULL;
+
if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr))
return cpu_addr;
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index 339a990554e7..a34c38bbe28f 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -300,6 +300,37 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start,
return;
}
+static void *swiotlb_memblock_alloc(unsigned long nslabs, unsigned int flags,
+ int (*remap)(void *tlb, unsigned long nslabs))
+{
+ size_t bytes = PAGE_ALIGN(nslabs << IO_TLB_SHIFT);
+ void *tlb;
+
+ /*
+ * By default allocate the bounce buffer memory from low memory, but
+ * allow to pick a location everywhere for hypervisors with guest
+ * memory encryption.
+ */
+ if (flags & SWIOTLB_ANY)
+ tlb = memblock_alloc(bytes, PAGE_SIZE);
+ else
+ tlb = memblock_alloc_low(bytes, PAGE_SIZE);
+
+ if (!tlb) {
+ pr_warn("%s: Failed to allocate %zu bytes tlb structure\n",
+ __func__, bytes);
+ return NULL;
+ }
+
+ if (remap && remap(tlb, nslabs) < 0) {
+ memblock_free(tlb, PAGE_ALIGN(bytes));
+ pr_warn("%s: Failed to remap %zu bytes\n", __func__, bytes);
+ return NULL;
+ }
+
+ return tlb;
+}
+
/*
* Statically reserve bounce buffer space and initialize bounce buffer data
* structures for the software IO TLB used to implement the DMA API.
@@ -310,7 +341,6 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
struct io_tlb_mem *mem = &io_tlb_default_mem;
unsigned long nslabs;
size_t alloc_size;
- size_t bytes;
void *tlb;
if (!addressing_limit && !swiotlb_force_bounce)
@@ -326,31 +356,16 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
swiotlb_adjust_nareas(num_possible_cpus());
nslabs = default_nslabs;
- /*
- * By default allocate the bounce buffer memory from low memory, but
- * allow to pick a location everywhere for hypervisors with guest
- * memory encryption.
- */
-retry:
- bytes = PAGE_ALIGN(nslabs << IO_TLB_SHIFT);
- if (flags & SWIOTLB_ANY)
- tlb = memblock_alloc(bytes, PAGE_SIZE);
- else
- tlb = memblock_alloc_low(bytes, PAGE_SIZE);
- if (!tlb) {
- pr_warn("%s: failed to allocate tlb structure\n", __func__);
- return;
- }
-
- if (remap && remap(tlb, nslabs) < 0) {
- memblock_free(tlb, PAGE_ALIGN(bytes));
-
+ while ((tlb = swiotlb_memblock_alloc(nslabs, flags, remap)) == NULL) {
+ if (nslabs <= IO_TLB_MIN_SLABS)
+ return;
nslabs = ALIGN(nslabs >> 1, IO_TLB_SEGSIZE);
- if (nslabs >= IO_TLB_MIN_SLABS)
- goto retry;
+ }
- pr_warn("%s: Failed to remap %zu bytes\n", __func__, bytes);
- return;
+ if (default_nslabs != nslabs) {
+ pr_info("SWIOTLB bounce buffer size adjusted %lu -> %lu slabs",
+ default_nslabs, nslabs);
+ default_nslabs = nslabs;
}
alloc_size = PAGE_ALIGN(array_size(sizeof(*mem->slots), nslabs));
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 4ec3717003d5..e47914ac8732 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -155,12 +155,6 @@ static int cpu_function_call(int cpu, remote_function_f func, void *info)
return data.ret;
}
-static inline struct perf_cpu_context *
-__get_cpu_context(struct perf_event_context *ctx)
-{
- return this_cpu_ptr(ctx->pmu->pmu_cpu_context);
-}
-
static void perf_ctx_lock(struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx)
{
@@ -184,6 +178,14 @@ static bool is_kernel_event(struct perf_event *event)
return READ_ONCE(event->owner) == TASK_TOMBSTONE;
}
+static DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context);
+
+struct perf_event_context *perf_cpu_task_ctx(void)
+{
+ lockdep_assert_irqs_disabled();
+ return this_cpu_ptr(&perf_cpu_context)->task_ctx;
+}
+
/*
* On task ctx scheduling...
*
@@ -217,7 +219,7 @@ static int event_function(void *info)
struct event_function_struct *efs = info;
struct perf_event *event = efs->event;
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct perf_event_context *task_ctx = cpuctx->task_ctx;
int ret = 0;
@@ -314,7 +316,7 @@ again:
static void event_function_local(struct perf_event *event, event_f func, void *data)
{
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct task_struct *task = READ_ONCE(ctx->task);
struct perf_event_context *task_ctx = NULL;
@@ -388,7 +390,6 @@ static DEFINE_MUTEX(perf_sched_mutex);
static atomic_t perf_sched_count;
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
-static DEFINE_PER_CPU(int, perf_sched_cb_usages);
static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
static atomic_t nr_mmap_events __read_mostly;
@@ -448,7 +449,7 @@ static void update_perf_cpu_limits(void)
WRITE_ONCE(perf_sample_allowed_ns, tmp);
}
-static bool perf_rotate_context(struct perf_cpu_context *cpuctx);
+static bool perf_rotate_context(struct perf_cpu_pmu_context *cpc);
int perf_proc_update_handler(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -571,12 +572,6 @@ void perf_sample_event_took(u64 sample_len_ns)
static atomic64_t perf_event_id;
-static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
- enum event_type_t event_type);
-
-static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
- enum event_type_t event_type);
-
static void update_context_time(struct perf_event_context *ctx);
static u64 perf_event_time(struct perf_event *event);
@@ -691,13 +686,31 @@ do { \
___p; \
})
+static void perf_ctx_disable(struct perf_event_context *ctx)
+{
+ struct perf_event_pmu_context *pmu_ctx;
+
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry)
+ perf_pmu_disable(pmu_ctx->pmu);
+}
+
+static void perf_ctx_enable(struct perf_event_context *ctx)
+{
+ struct perf_event_pmu_context *pmu_ctx;
+
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry)
+ perf_pmu_enable(pmu_ctx->pmu);
+}
+
+static void ctx_sched_out(struct perf_event_context *ctx, enum event_type_t event_type);
+static void ctx_sched_in(struct perf_event_context *ctx, enum event_type_t event_type);
+
#ifdef CONFIG_CGROUP_PERF
static inline bool
perf_cgroup_match(struct perf_event *event)
{
- struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
/* @event doesn't care about cgroup */
if (!event->cgrp)
@@ -823,54 +836,39 @@ perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx)
}
}
-static DEFINE_PER_CPU(struct list_head, cgrp_cpuctx_list);
-
/*
* reschedule events based on the cgroup constraint of task.
*/
static void perf_cgroup_switch(struct task_struct *task)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct perf_cgroup *cgrp;
- struct perf_cpu_context *cpuctx, *tmp;
- struct list_head *list;
- unsigned long flags;
-
- /*
- * Disable interrupts and preemption to avoid this CPU's
- * cgrp_cpuctx_entry to change under us.
- */
- local_irq_save(flags);
cgrp = perf_cgroup_from_task(task, NULL);
- list = this_cpu_ptr(&cgrp_cpuctx_list);
- list_for_each_entry_safe(cpuctx, tmp, list, cgrp_cpuctx_entry) {
- WARN_ON_ONCE(cpuctx->ctx.nr_cgroups == 0);
- if (READ_ONCE(cpuctx->cgrp) == cgrp)
- continue;
-
- perf_ctx_lock(cpuctx, cpuctx->task_ctx);
- perf_pmu_disable(cpuctx->ctx.pmu);
+ WARN_ON_ONCE(cpuctx->ctx.nr_cgroups == 0);
+ if (READ_ONCE(cpuctx->cgrp) == cgrp)
+ return;
- cpu_ctx_sched_out(cpuctx, EVENT_ALL);
- /*
- * must not be done before ctxswout due
- * to update_cgrp_time_from_cpuctx() in
- * ctx_sched_out()
- */
- cpuctx->cgrp = cgrp;
- /*
- * set cgrp before ctxsw in to allow
- * perf_cgroup_set_timestamp() in ctx_sched_in()
- * to not have to pass task around
- */
- cpu_ctx_sched_in(cpuctx, EVENT_ALL);
+ perf_ctx_lock(cpuctx, cpuctx->task_ctx);
+ perf_ctx_disable(&cpuctx->ctx);
- perf_pmu_enable(cpuctx->ctx.pmu);
- perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
- }
+ ctx_sched_out(&cpuctx->ctx, EVENT_ALL);
+ /*
+ * must not be done before ctxswout due
+ * to update_cgrp_time_from_cpuctx() in
+ * ctx_sched_out()
+ */
+ cpuctx->cgrp = cgrp;
+ /*
+ * set cgrp before ctxsw in to allow
+ * perf_cgroup_set_timestamp() in ctx_sched_in()
+ * to not have to pass task around
+ */
+ ctx_sched_in(&cpuctx->ctx, EVENT_ALL);
- local_irq_restore(flags);
+ perf_ctx_enable(&cpuctx->ctx);
+ perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
}
static int perf_cgroup_ensure_storage(struct perf_event *event,
@@ -888,7 +886,7 @@ static int perf_cgroup_ensure_storage(struct perf_event *event,
heap_size++;
for_each_possible_cpu(cpu) {
- cpuctx = per_cpu_ptr(event->pmu->pmu_cpu_context, cpu);
+ cpuctx = per_cpu_ptr(&perf_cpu_context, cpu);
if (heap_size <= cpuctx->heap_size)
continue;
@@ -972,8 +970,6 @@ perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ct
return;
cpuctx->cgrp = perf_cgroup_from_task(current, ctx);
- list_add(&cpuctx->cgrp_cpuctx_entry,
- per_cpu_ptr(&cgrp_cpuctx_list, event->cpu));
}
static inline void
@@ -994,7 +990,6 @@ perf_cgroup_event_disable(struct perf_event *event, struct perf_event_context *c
return;
cpuctx->cgrp = NULL;
- list_del(&cpuctx->cgrp_cpuctx_entry);
}
#else /* !CONFIG_CGROUP_PERF */
@@ -1069,34 +1064,30 @@ static void perf_cgroup_switch(struct task_struct *task)
*/
static enum hrtimer_restart perf_mux_hrtimer_handler(struct hrtimer *hr)
{
- struct perf_cpu_context *cpuctx;
+ struct perf_cpu_pmu_context *cpc;
bool rotations;
lockdep_assert_irqs_disabled();
- cpuctx = container_of(hr, struct perf_cpu_context, hrtimer);
- rotations = perf_rotate_context(cpuctx);
+ cpc = container_of(hr, struct perf_cpu_pmu_context, hrtimer);
+ rotations = perf_rotate_context(cpc);
- raw_spin_lock(&cpuctx->hrtimer_lock);
+ raw_spin_lock(&cpc->hrtimer_lock);
if (rotations)
- hrtimer_forward_now(hr, cpuctx->hrtimer_interval);
+ hrtimer_forward_now(hr, cpc->hrtimer_interval);
else
- cpuctx->hrtimer_active = 0;
- raw_spin_unlock(&cpuctx->hrtimer_lock);
+ cpc->hrtimer_active = 0;
+ raw_spin_unlock(&cpc->hrtimer_lock);
return rotations ? HRTIMER_RESTART : HRTIMER_NORESTART;
}
-static void __perf_mux_hrtimer_init(struct perf_cpu_context *cpuctx, int cpu)
+static void __perf_mux_hrtimer_init(struct perf_cpu_pmu_context *cpc, int cpu)
{
- struct hrtimer *timer = &cpuctx->hrtimer;
- struct pmu *pmu = cpuctx->ctx.pmu;
+ struct hrtimer *timer = &cpc->hrtimer;
+ struct pmu *pmu = cpc->epc.pmu;
u64 interval;
- /* no multiplexing needed for SW PMU */
- if (pmu->task_ctx_nr == perf_sw_context)
- return;
-
/*
* check default is sane, if not set then force to
* default interval (1/tick)
@@ -1105,34 +1096,34 @@ static void __perf_mux_hrtimer_init(struct perf_cpu_context *cpuctx, int cpu)
if (interval < 1)
interval = pmu->hrtimer_interval_ms = PERF_CPU_HRTIMER;
- cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * interval);
+ cpc->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * interval);
- raw_spin_lock_init(&cpuctx->hrtimer_lock);
+ raw_spin_lock_init(&cpc->hrtimer_lock);
hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
timer->function = perf_mux_hrtimer_handler;
}
-static int perf_mux_hrtimer_restart(struct perf_cpu_context *cpuctx)
+static int perf_mux_hrtimer_restart(struct perf_cpu_pmu_context *cpc)
{
- struct hrtimer *timer = &cpuctx->hrtimer;
- struct pmu *pmu = cpuctx->ctx.pmu;
+ struct hrtimer *timer = &cpc->hrtimer;
unsigned long flags;
- /* not for SW PMU */
- if (pmu->task_ctx_nr == perf_sw_context)
- return 0;
-
- raw_spin_lock_irqsave(&cpuctx->hrtimer_lock, flags);
- if (!cpuctx->hrtimer_active) {
- cpuctx->hrtimer_active = 1;
- hrtimer_forward_now(timer, cpuctx->hrtimer_interval);
+ raw_spin_lock_irqsave(&cpc->hrtimer_lock, flags);
+ if (!cpc->hrtimer_active) {
+ cpc->hrtimer_active = 1;
+ hrtimer_forward_now(timer, cpc->hrtimer_interval);
hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED_HARD);
}
- raw_spin_unlock_irqrestore(&cpuctx->hrtimer_lock, flags);
+ raw_spin_unlock_irqrestore(&cpc->hrtimer_lock, flags);
return 0;
}
+static int perf_mux_hrtimer_restart_ipi(void *arg)
+{
+ return perf_mux_hrtimer_restart(arg);
+}
+
void perf_pmu_disable(struct pmu *pmu)
{
int *count = this_cpu_ptr(pmu->pmu_disable_count);
@@ -1147,32 +1138,9 @@ void perf_pmu_enable(struct pmu *pmu)
pmu->pmu_enable(pmu);
}
-static DEFINE_PER_CPU(struct list_head, active_ctx_list);
-
-/*
- * perf_event_ctx_activate(), perf_event_ctx_deactivate(), and
- * perf_event_task_tick() are fully serialized because they're strictly cpu
- * affine and perf_event_ctx{activate,deactivate} are called with IRQs
- * disabled, while perf_event_task_tick is called from IRQ context.
- */
-static void perf_event_ctx_activate(struct perf_event_context *ctx)
-{
- struct list_head *head = this_cpu_ptr(&active_ctx_list);
-
- lockdep_assert_irqs_disabled();
-
- WARN_ON(!list_empty(&ctx->active_ctx_list));
-
- list_add(&ctx->active_ctx_list, head);
-}
-
-static void perf_event_ctx_deactivate(struct perf_event_context *ctx)
+static void perf_assert_pmu_disabled(struct pmu *pmu)
{
- lockdep_assert_irqs_disabled();
-
- WARN_ON(list_empty(&ctx->active_ctx_list));
-
- list_del_init(&ctx->active_ctx_list);
+ WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0);
}
static void get_ctx(struct perf_event_context *ctx)
@@ -1199,7 +1167,6 @@ static void free_ctx(struct rcu_head *head)
struct perf_event_context *ctx;
ctx = container_of(head, struct perf_event_context, rcu_head);
- free_task_ctx_data(ctx->pmu, ctx->task_ctx_data);
kfree(ctx);
}
@@ -1384,7 +1351,7 @@ static u64 primary_event_id(struct perf_event *event)
* the context could get moved to another task.
*/
static struct perf_event_context *
-perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags)
+perf_lock_task_context(struct task_struct *task, unsigned long *flags)
{
struct perf_event_context *ctx;
@@ -1400,7 +1367,7 @@ retry:
*/
local_irq_save(*flags);
rcu_read_lock();
- ctx = rcu_dereference(task->perf_event_ctxp[ctxn]);
+ ctx = rcu_dereference(task->perf_event_ctxp);
if (ctx) {
/*
* If this context is a clone of another, it might
@@ -1413,7 +1380,7 @@ retry:
* can't get swapped on us any more.
*/
raw_spin_lock(&ctx->lock);
- if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) {
+ if (ctx != rcu_dereference(task->perf_event_ctxp)) {
raw_spin_unlock(&ctx->lock);
rcu_read_unlock();
local_irq_restore(*flags);
@@ -1440,12 +1407,12 @@ retry:
* reference count so that the context can't get freed.
*/
static struct perf_event_context *
-perf_pin_task_context(struct task_struct *task, int ctxn)
+perf_pin_task_context(struct task_struct *task)
{
struct perf_event_context *ctx;
unsigned long flags;
- ctx = perf_lock_task_context(task, ctxn, &flags);
+ ctx = perf_lock_task_context(task, &flags);
if (ctx) {
++ctx->pin_count;
raw_spin_unlock_irqrestore(&ctx->lock, flags);
@@ -1593,14 +1560,22 @@ static inline struct cgroup *event_cgroup(const struct perf_event *event)
* which provides ordering when rotating groups for the same CPU.
*/
static __always_inline int
-perf_event_groups_cmp(const int left_cpu, const struct cgroup *left_cgroup,
- const u64 left_group_index, const struct perf_event *right)
+perf_event_groups_cmp(const int left_cpu, const struct pmu *left_pmu,
+ const struct cgroup *left_cgroup, const u64 left_group_index,
+ const struct perf_event *right)
{
if (left_cpu < right->cpu)
return -1;
if (left_cpu > right->cpu)
return 1;
+ if (left_pmu) {
+ if (left_pmu < right->pmu_ctx->pmu)
+ return -1;
+ if (left_pmu > right->pmu_ctx->pmu)
+ return 1;
+ }
+
#ifdef CONFIG_CGROUP_PERF
{
const struct cgroup *right_cgroup = event_cgroup(right);
@@ -1643,12 +1618,13 @@ perf_event_groups_cmp(const int left_cpu, const struct cgroup *left_cgroup,
static inline bool __group_less(struct rb_node *a, const struct rb_node *b)
{
struct perf_event *e = __node_2_pe(a);
- return perf_event_groups_cmp(e->cpu, event_cgroup(e), e->group_index,
- __node_2_pe(b)) < 0;
+ return perf_event_groups_cmp(e->cpu, e->pmu_ctx->pmu, event_cgroup(e),
+ e->group_index, __node_2_pe(b)) < 0;
}
struct __group_key {
int cpu;
+ struct pmu *pmu;
struct cgroup *cgroup;
};
@@ -1657,14 +1633,25 @@ static inline int __group_cmp(const void *key, const struct rb_node *node)
const struct __group_key *a = key;
const struct perf_event *b = __node_2_pe(node);
- /* partial/subtree match: @cpu, @cgroup; ignore: @group_index */
- return perf_event_groups_cmp(a->cpu, a->cgroup, b->group_index, b);
+ /* partial/subtree match: @cpu, @pmu, @cgroup; ignore: @group_index */
+ return perf_event_groups_cmp(a->cpu, a->pmu, a->cgroup, b->group_index, b);
+}
+
+static inline int
+__group_cmp_ignore_cgroup(const void *key, const struct rb_node *node)
+{
+ const struct __group_key *a = key;
+ const struct perf_event *b = __node_2_pe(node);
+
+ /* partial/subtree match: @cpu, @pmu, ignore: @cgroup, @group_index */
+ return perf_event_groups_cmp(a->cpu, a->pmu, event_cgroup(b),
+ b->group_index, b);
}
/*
- * Insert @event into @groups' tree; using {@event->cpu, ++@groups->index} for
- * key (see perf_event_groups_less). This places it last inside the CPU
- * subtree.
+ * Insert @event into @groups' tree; using
+ * {@event->cpu, @event->pmu_ctx->pmu, event_cgroup(@event), ++@groups->index}
+ * as key. This places it last inside the {cpu,pmu,cgroup} subtree.
*/
static void
perf_event_groups_insert(struct perf_event_groups *groups,
@@ -1714,14 +1701,15 @@ del_event_from_groups(struct perf_event *event, struct perf_event_context *ctx)
}
/*
- * Get the leftmost event in the cpu/cgroup subtree.
+ * Get the leftmost event in the {cpu,pmu,cgroup} subtree.
*/
static struct perf_event *
perf_event_groups_first(struct perf_event_groups *groups, int cpu,
- struct cgroup *cgrp)
+ struct pmu *pmu, struct cgroup *cgrp)
{
struct __group_key key = {
.cpu = cpu,
+ .pmu = pmu,
.cgroup = cgrp,
};
struct rb_node *node;
@@ -1733,14 +1721,12 @@ perf_event_groups_first(struct perf_event_groups *groups, int cpu,
return NULL;
}
-/*
- * Like rb_entry_next_safe() for the @cpu subtree.
- */
static struct perf_event *
-perf_event_groups_next(struct perf_event *event)
+perf_event_groups_next(struct perf_event *event, struct pmu *pmu)
{
struct __group_key key = {
.cpu = event->cpu,
+ .pmu = pmu,
.cgroup = event_cgroup(event),
};
struct rb_node *next;
@@ -1752,6 +1738,10 @@ perf_event_groups_next(struct perf_event *event)
return NULL;
}
+#define perf_event_groups_for_cpu_pmu(event, groups, cpu, pmu) \
+ for (event = perf_event_groups_first(groups, cpu, pmu, NULL); \
+ event; event = perf_event_groups_next(event, pmu))
+
/*
* Iterate through the whole groups tree.
*/
@@ -1796,6 +1786,7 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
perf_cgroup_event_enable(event, ctx);
ctx->generation++;
+ event->pmu_ctx->nr_events++;
}
/*
@@ -1941,7 +1932,8 @@ static void perf_group_attach(struct perf_event *event)
lockdep_assert_held(&event->ctx->lock);
/*
- * We can have double attach due to group movement in perf_event_open.
+ * We can have double attach due to group movement (move_group) in
+ * perf_event_open().
*/
if (event->attach_state & PERF_ATTACH_GROUP)
return;
@@ -2006,6 +1998,7 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
}
ctx->generation++;
+ event->pmu_ctx->nr_events--;
}
static int
@@ -2022,13 +2015,11 @@ perf_aux_output_match(struct perf_event *event, struct perf_event *aux_event)
static void put_event(struct perf_event *event);
static void event_sched_out(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx);
static void perf_put_aux_event(struct perf_event *event)
{
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
struct perf_event *iter;
/*
@@ -2057,7 +2048,7 @@ static void perf_put_aux_event(struct perf_event *event)
* state so that we don't try to schedule it again. Note
* that perf_event_enable() will clear the ERROR status.
*/
- event_sched_out(iter, cpuctx, ctx);
+ event_sched_out(iter, ctx);
perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
}
}
@@ -2108,8 +2099,8 @@ static int perf_get_aux_event(struct perf_event *event,
static inline struct list_head *get_event_list(struct perf_event *event)
{
- struct perf_event_context *ctx = event->ctx;
- return event->attr.pinned ? &ctx->pinned_active : &ctx->flexible_active;
+ return event->attr.pinned ? &event->pmu_ctx->pinned_active :
+ &event->pmu_ctx->flexible_active;
}
/*
@@ -2120,10 +2111,7 @@ static inline struct list_head *get_event_list(struct perf_event *event)
*/
static inline void perf_remove_sibling_event(struct perf_event *event)
{
- struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
-
- event_sched_out(event, cpuctx, ctx);
+ event_sched_out(event, event->ctx);
perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
}
@@ -2212,53 +2200,22 @@ static bool is_orphaned_event(struct perf_event *event)
return event->state == PERF_EVENT_STATE_DEAD;
}
-static inline int __pmu_filter_match(struct perf_event *event)
-{
- struct pmu *pmu = event->pmu;
- return pmu->filter_match ? pmu->filter_match(event) : 1;
-}
-
-/*
- * Check whether we should attempt to schedule an event group based on
- * PMU-specific filtering. An event group can consist of HW and SW events,
- * potentially with a SW leader, so we must check all the filters, to
- * determine whether a group is schedulable:
- */
-static inline int pmu_filter_match(struct perf_event *event)
-{
- struct perf_event *sibling;
- unsigned long flags;
- int ret = 1;
-
- if (!__pmu_filter_match(event))
- return 0;
-
- local_irq_save(flags);
- for_each_sibling_event(sibling, event) {
- if (!__pmu_filter_match(sibling)) {
- ret = 0;
- break;
- }
- }
- local_irq_restore(flags);
-
- return ret;
-}
-
static inline int
event_filter_match(struct perf_event *event)
{
return (event->cpu == -1 || event->cpu == smp_processor_id()) &&
- perf_cgroup_match(event) && pmu_filter_match(event);
+ perf_cgroup_match(event);
}
static void
-event_sched_out(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
+event_sched_out(struct perf_event *event, struct perf_event_context *ctx)
{
+ struct perf_event_pmu_context *epc = event->pmu_ctx;
+ struct perf_cpu_pmu_context *cpc = this_cpu_ptr(epc->pmu->cpu_pmu_context);
enum perf_event_state state = PERF_EVENT_STATE_INACTIVE;
+ // XXX cpc serialization, probably per-cpu IRQ disabled
+
WARN_ON_ONCE(event->ctx != ctx);
lockdep_assert_held(&ctx->lock);
@@ -2291,6 +2248,7 @@ event_sched_out(struct perf_event *event,
!event->pending_work) {
event->pending_work = 1;
dec = false;
+ WARN_ON_ONCE(!atomic_long_inc_not_zero(&event->refcount));
task_work_add(current, &event->pending_task, TWA_RESUME);
}
if (dec)
@@ -2300,42 +2258,37 @@ event_sched_out(struct perf_event *event,
perf_event_set_state(event, state);
if (!is_software_event(event))
- cpuctx->active_oncpu--;
- if (!--ctx->nr_active)
- perf_event_ctx_deactivate(ctx);
+ cpc->active_oncpu--;
if (event->attr.freq && event->attr.sample_freq)
ctx->nr_freq--;
- if (event->attr.exclusive || !cpuctx->active_oncpu)
- cpuctx->exclusive = 0;
+ if (event->attr.exclusive || !cpc->active_oncpu)
+ cpc->exclusive = 0;
perf_pmu_enable(event->pmu);
}
static void
-group_sched_out(struct perf_event *group_event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
+group_sched_out(struct perf_event *group_event, struct perf_event_context *ctx)
{
struct perf_event *event;
if (group_event->state != PERF_EVENT_STATE_ACTIVE)
return;
- perf_pmu_disable(ctx->pmu);
+ perf_assert_pmu_disabled(group_event->pmu_ctx->pmu);
- event_sched_out(group_event, cpuctx, ctx);
+ event_sched_out(group_event, ctx);
/*
* Schedule out siblings (if any):
*/
for_each_sibling_event(event, group_event)
- event_sched_out(event, cpuctx, ctx);
-
- perf_pmu_enable(ctx->pmu);
+ event_sched_out(event, ctx);
}
#define DETACH_GROUP 0x01UL
#define DETACH_CHILD 0x02UL
+#define DETACH_DEAD 0x04UL
/*
* Cross CPU call to remove a performance event
@@ -2349,6 +2302,7 @@ __perf_remove_from_context(struct perf_event *event,
struct perf_event_context *ctx,
void *info)
{
+ struct perf_event_pmu_context *pmu_ctx = event->pmu_ctx;
unsigned long flags = (unsigned long)info;
if (ctx->is_active & EVENT_TIME) {
@@ -2356,19 +2310,38 @@ __perf_remove_from_context(struct perf_event *event,
update_cgrp_time_from_cpuctx(cpuctx, false);
}
- event_sched_out(event, cpuctx, ctx);
+ /*
+ * Ensure event_sched_out() switches to OFF, at the very least
+ * this avoids raising perf_pending_task() at this time.
+ */
+ if (flags & DETACH_DEAD)
+ event->pending_disable = 1;
+ event_sched_out(event, ctx);
if (flags & DETACH_GROUP)
perf_group_detach(event);
if (flags & DETACH_CHILD)
perf_child_detach(event);
list_del_event(event, ctx);
+ if (flags & DETACH_DEAD)
+ event->state = PERF_EVENT_STATE_DEAD;
+
+ if (!pmu_ctx->nr_events) {
+ pmu_ctx->rotate_necessary = 0;
+
+ if (ctx->task && ctx->is_active) {
+ struct perf_cpu_pmu_context *cpc;
+
+ cpc = this_cpu_ptr(pmu_ctx->pmu->cpu_pmu_context);
+ WARN_ON_ONCE(cpc->task_epc && cpc->task_epc != pmu_ctx);
+ cpc->task_epc = NULL;
+ }
+ }
if (!ctx->nr_events && ctx->is_active) {
if (ctx == &cpuctx->ctx)
update_cgrp_time_from_cpuctx(cpuctx, true);
ctx->is_active = 0;
- ctx->rotate_necessary = 0;
if (ctx->task) {
WARN_ON_ONCE(cpuctx->task_ctx != ctx);
cpuctx->task_ctx = NULL;
@@ -2398,12 +2371,8 @@ static void perf_remove_from_context(struct perf_event *event, unsigned long fla
* event_function_call() user.
*/
raw_spin_lock_irq(&ctx->lock);
- /*
- * Cgroup events are per-cpu events, and must IPI because of
- * cgrp_cpuctx_list.
- */
- if (!ctx->is_active && !is_cgroup_event(event)) {
- __perf_remove_from_context(event, __get_cpu_context(ctx),
+ if (!ctx->is_active) {
+ __perf_remove_from_context(event, this_cpu_ptr(&perf_cpu_context),
ctx, (void *)flags);
raw_spin_unlock_irq(&ctx->lock);
return;
@@ -2429,13 +2398,17 @@ static void __perf_event_disable(struct perf_event *event,
update_cgrp_time_from_event(event);
}
+ perf_pmu_disable(event->pmu_ctx->pmu);
+
if (event == event->group_leader)
- group_sched_out(event, cpuctx, ctx);
+ group_sched_out(event, ctx);
else
- event_sched_out(event, cpuctx, ctx);
+ event_sched_out(event, ctx);
perf_event_set_state(event, PERF_EVENT_STATE_OFF);
perf_cgroup_event_disable(event, ctx);
+
+ perf_pmu_enable(event->pmu_ctx->pmu);
}
/*
@@ -2497,10 +2470,10 @@ static void perf_log_throttle(struct perf_event *event, int enable);
static void perf_log_itrace_start(struct perf_event *event);
static int
-event_sched_in(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
+event_sched_in(struct perf_event *event, struct perf_event_context *ctx)
{
+ struct perf_event_pmu_context *epc = event->pmu_ctx;
+ struct perf_cpu_pmu_context *cpc = this_cpu_ptr(epc->pmu->cpu_pmu_context);
int ret = 0;
WARN_ON_ONCE(event->ctx != ctx);
@@ -2541,14 +2514,12 @@ event_sched_in(struct perf_event *event,
}
if (!is_software_event(event))
- cpuctx->active_oncpu++;
- if (!ctx->nr_active++)
- perf_event_ctx_activate(ctx);
+ cpc->active_oncpu++;
if (event->attr.freq && event->attr.sample_freq)
ctx->nr_freq++;
if (event->attr.exclusive)
- cpuctx->exclusive = 1;
+ cpc->exclusive = 1;
out:
perf_pmu_enable(event->pmu);
@@ -2557,26 +2528,24 @@ out:
}
static int
-group_sched_in(struct perf_event *group_event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
+group_sched_in(struct perf_event *group_event, struct perf_event_context *ctx)
{
struct perf_event *event, *partial_group = NULL;
- struct pmu *pmu = ctx->pmu;
+ struct pmu *pmu = group_event->pmu_ctx->pmu;
if (group_event->state == PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
- if (event_sched_in(group_event, cpuctx, ctx))
+ if (event_sched_in(group_event, ctx))
goto error;
/*
* Schedule in siblings as one group (if any):
*/
for_each_sibling_event(event, group_event) {
- if (event_sched_in(event, cpuctx, ctx)) {
+ if (event_sched_in(event, ctx)) {
partial_group = event;
goto group_error;
}
@@ -2595,9 +2564,9 @@ group_error:
if (event == partial_group)
break;
- event_sched_out(event, cpuctx, ctx);
+ event_sched_out(event, ctx);
}
- event_sched_out(group_event, cpuctx, ctx);
+ event_sched_out(group_event, ctx);
error:
pmu->cancel_txn(pmu);
@@ -2607,10 +2576,11 @@ error:
/*
* Work out whether we can put this event group on the CPU now.
*/
-static int group_can_go_on(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- int can_add_hw)
+static int group_can_go_on(struct perf_event *event, int can_add_hw)
{
+ struct perf_event_pmu_context *epc = event->pmu_ctx;
+ struct perf_cpu_pmu_context *cpc = this_cpu_ptr(epc->pmu->cpu_pmu_context);
+
/*
* Groups consisting entirely of software events can always go on.
*/
@@ -2620,7 +2590,7 @@ static int group_can_go_on(struct perf_event *event,
* If an exclusive group is already on, no other hardware
* events can go on.
*/
- if (cpuctx->exclusive)
+ if (cpc->exclusive)
return 0;
/*
* If this group is exclusive and there are already
@@ -2642,36 +2612,29 @@ static void add_event_to_ctx(struct perf_event *event,
perf_group_attach(event);
}
-static void ctx_sched_out(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx,
- enum event_type_t event_type);
-static void
-ctx_sched_in(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx,
- enum event_type_t event_type);
-
-static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx,
- enum event_type_t event_type)
+static void task_ctx_sched_out(struct perf_event_context *ctx,
+ enum event_type_t event_type)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+
if (!cpuctx->task_ctx)
return;
if (WARN_ON_ONCE(ctx != cpuctx->task_ctx))
return;
- ctx_sched_out(ctx, cpuctx, event_type);
+ ctx_sched_out(ctx, event_type);
}
static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx)
{
- cpu_ctx_sched_in(cpuctx, EVENT_PINNED);
+ ctx_sched_in(&cpuctx->ctx, EVENT_PINNED);
if (ctx)
- ctx_sched_in(ctx, cpuctx, EVENT_PINNED);
- cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE);
+ ctx_sched_in(ctx, EVENT_PINNED);
+ ctx_sched_in(&cpuctx->ctx, EVENT_FLEXIBLE);
if (ctx)
- ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE);
+ ctx_sched_in(ctx, EVENT_FLEXIBLE);
}
/*
@@ -2689,11 +2652,15 @@ static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
* event_type is a bit mask of the types of events involved. For CPU events,
* event_type is only either EVENT_PINNED or EVENT_FLEXIBLE.
*/
+/*
+ * XXX: ctx_resched() reschedule entire perf_event_context while adding new
+ * event to the context or enabling existing event in the context. We can
+ * probably optimize it by rescheduling only affected pmu_ctx.
+ */
static void ctx_resched(struct perf_cpu_context *cpuctx,
struct perf_event_context *task_ctx,
enum event_type_t event_type)
{
- enum event_type_t ctx_event_type;
bool cpu_event = !!(event_type & EVENT_CPU);
/*
@@ -2703,11 +2670,13 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
if (event_type & EVENT_PINNED)
event_type |= EVENT_FLEXIBLE;
- ctx_event_type = event_type & EVENT_ALL;
+ event_type &= EVENT_ALL;
- perf_pmu_disable(cpuctx->ctx.pmu);
- if (task_ctx)
- task_ctx_sched_out(cpuctx, task_ctx, event_type);
+ perf_ctx_disable(&cpuctx->ctx);
+ if (task_ctx) {
+ perf_ctx_disable(task_ctx);
+ task_ctx_sched_out(task_ctx, event_type);
+ }
/*
* Decide which cpu ctx groups to schedule out based on the types
@@ -2717,17 +2686,20 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
* - otherwise, do nothing more.
*/
if (cpu_event)
- cpu_ctx_sched_out(cpuctx, ctx_event_type);
- else if (ctx_event_type & EVENT_PINNED)
- cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
+ ctx_sched_out(&cpuctx->ctx, event_type);
+ else if (event_type & EVENT_PINNED)
+ ctx_sched_out(&cpuctx->ctx, EVENT_FLEXIBLE);
perf_event_sched_in(cpuctx, task_ctx);
- perf_pmu_enable(cpuctx->ctx.pmu);
+
+ perf_ctx_enable(&cpuctx->ctx);
+ if (task_ctx)
+ perf_ctx_enable(task_ctx);
}
void perf_pmu_resched(struct pmu *pmu)
{
- struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct perf_event_context *task_ctx = cpuctx->task_ctx;
perf_ctx_lock(cpuctx, task_ctx);
@@ -2745,7 +2717,7 @@ static int __perf_install_in_context(void *info)
{
struct perf_event *event = info;
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct perf_event_context *task_ctx = cpuctx->task_ctx;
bool reprogram = true;
int ret = 0;
@@ -2787,7 +2759,7 @@ static int __perf_install_in_context(void *info)
#endif
if (reprogram) {
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_out(ctx, EVENT_TIME);
add_event_to_ctx(event, ctx);
ctx_resched(cpuctx, task_ctx, get_event_type(event));
} else {
@@ -2820,7 +2792,7 @@ perf_install_in_context(struct perf_event_context *ctx,
WARN_ON_ONCE(!exclusive_event_installable(event, ctx));
if (event->cpu != -1)
- event->cpu = cpu;
+ WARN_ON_ONCE(event->cpu != cpu);
/*
* Ensures that if we can observe event->ctx, both the event and ctx
@@ -2832,8 +2804,6 @@ perf_install_in_context(struct perf_event_context *ctx,
* perf_event_attr::disabled events will not run and can be initialized
* without IPI. Except when this is the first event for the context, in
* that case we need the magic of the IPI to set ctx->is_active.
- * Similarly, cgroup events for the context also needs the IPI to
- * manipulate the cgrp_cpuctx_list.
*
* The IOC_ENABLE that is sure to follow the creation of a disabled
* event will issue the IPI and reprogram the hardware.
@@ -2935,7 +2905,7 @@ static void __perf_event_enable(struct perf_event *event,
return;
if (ctx->is_active)
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_out(ctx, EVENT_TIME);
perf_event_set_state(event, PERF_EVENT_STATE_INACTIVE);
perf_cgroup_event_enable(event, ctx);
@@ -2944,7 +2914,7 @@ static void __perf_event_enable(struct perf_event *event,
return;
if (!event_filter_match(event)) {
- ctx_sched_in(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_in(ctx, EVENT_TIME);
return;
}
@@ -2953,7 +2923,7 @@ static void __perf_event_enable(struct perf_event *event,
* then don't put it on unless the group is on.
*/
if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE) {
- ctx_sched_in(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_in(ctx, EVENT_TIME);
return;
}
@@ -3222,11 +3192,52 @@ out:
return err;
}
-static void ctx_sched_out(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx,
- enum event_type_t event_type)
+static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
+ enum event_type_t event_type)
{
+ struct perf_event_context *ctx = pmu_ctx->ctx;
struct perf_event *event, *tmp;
+ struct pmu *pmu = pmu_ctx->pmu;
+
+ if (ctx->task && !ctx->is_active) {
+ struct perf_cpu_pmu_context *cpc;
+
+ cpc = this_cpu_ptr(pmu->cpu_pmu_context);
+ WARN_ON_ONCE(cpc->task_epc && cpc->task_epc != pmu_ctx);
+ cpc->task_epc = NULL;
+ }
+
+ if (!event_type)
+ return;
+
+ perf_pmu_disable(pmu);
+ if (event_type & EVENT_PINNED) {
+ list_for_each_entry_safe(event, tmp,
+ &pmu_ctx->pinned_active,
+ active_list)
+ group_sched_out(event, ctx);
+ }
+
+ if (event_type & EVENT_FLEXIBLE) {
+ list_for_each_entry_safe(event, tmp,
+ &pmu_ctx->flexible_active,
+ active_list)
+ group_sched_out(event, ctx);
+ /*
+ * Since we cleared EVENT_FLEXIBLE, also clear
+ * rotate_necessary, is will be reset by
+ * ctx_flexible_sched_in() when needed.
+ */
+ pmu_ctx->rotate_necessary = 0;
+ }
+ perf_pmu_enable(pmu);
+}
+
+static void
+ctx_sched_out(struct perf_event_context *ctx, enum event_type_t event_type)
+{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct perf_event_pmu_context *pmu_ctx;
int is_active = ctx->is_active;
lockdep_assert_held(&ctx->lock);
@@ -3274,27 +3285,8 @@ static void ctx_sched_out(struct perf_event_context *ctx,
is_active ^= ctx->is_active; /* changed bits */
- if (!ctx->nr_active || !(is_active & EVENT_ALL))
- return;
-
- perf_pmu_disable(ctx->pmu);
- if (is_active & EVENT_PINNED) {
- list_for_each_entry_safe(event, tmp, &ctx->pinned_active, active_list)
- group_sched_out(event, cpuctx, ctx);
- }
-
- if (is_active & EVENT_FLEXIBLE) {
- list_for_each_entry_safe(event, tmp, &ctx->flexible_active, active_list)
- group_sched_out(event, cpuctx, ctx);
-
- /*
- * Since we cleared EVENT_FLEXIBLE, also clear
- * rotate_necessary, is will be reset by
- * ctx_flexible_sched_in() when needed.
- */
- ctx->rotate_necessary = 0;
- }
- perf_pmu_enable(ctx->pmu);
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry)
+ __pmu_ctx_sched_out(pmu_ctx, is_active);
}
/*
@@ -3399,26 +3391,68 @@ static void perf_event_sync_stat(struct perf_event_context *ctx,
}
}
-static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
- struct task_struct *next)
+#define double_list_for_each_entry(pos1, pos2, head1, head2, member) \
+ for (pos1 = list_first_entry(head1, typeof(*pos1), member), \
+ pos2 = list_first_entry(head2, typeof(*pos2), member); \
+ !list_entry_is_head(pos1, head1, member) && \
+ !list_entry_is_head(pos2, head2, member); \
+ pos1 = list_next_entry(pos1, member), \
+ pos2 = list_next_entry(pos2, member))
+
+static void perf_event_swap_task_ctx_data(struct perf_event_context *prev_ctx,
+ struct perf_event_context *next_ctx)
{
- struct perf_event_context *ctx = task->perf_event_ctxp[ctxn];
+ struct perf_event_pmu_context *prev_epc, *next_epc;
+
+ if (!prev_ctx->nr_task_data)
+ return;
+
+ double_list_for_each_entry(prev_epc, next_epc,
+ &prev_ctx->pmu_ctx_list, &next_ctx->pmu_ctx_list,
+ pmu_ctx_entry) {
+
+ if (WARN_ON_ONCE(prev_epc->pmu != next_epc->pmu))
+ continue;
+
+ /*
+ * PMU specific parts of task perf context can require
+ * additional synchronization. As an example of such
+ * synchronization see implementation details of Intel
+ * LBR call stack data profiling;
+ */
+ if (prev_epc->pmu->swap_task_ctx)
+ prev_epc->pmu->swap_task_ctx(prev_epc, next_epc);
+ else
+ swap(prev_epc->task_ctx_data, next_epc->task_ctx_data);
+ }
+}
+
+static void perf_ctx_sched_task_cb(struct perf_event_context *ctx, bool sched_in)
+{
+ struct perf_event_pmu_context *pmu_ctx;
+ struct perf_cpu_pmu_context *cpc;
+
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry) {
+ cpc = this_cpu_ptr(pmu_ctx->pmu->cpu_pmu_context);
+
+ if (cpc->sched_cb_usage && pmu_ctx->pmu->sched_task)
+ pmu_ctx->pmu->sched_task(pmu_ctx, sched_in);
+ }
+}
+
+static void
+perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
+{
+ struct perf_event_context *ctx = task->perf_event_ctxp;
struct perf_event_context *next_ctx;
struct perf_event_context *parent, *next_parent;
- struct perf_cpu_context *cpuctx;
int do_switch = 1;
- struct pmu *pmu;
if (likely(!ctx))
return;
- pmu = ctx->pmu;
- cpuctx = __get_cpu_context(ctx);
- if (!cpuctx->task_ctx)
- return;
-
rcu_read_lock();
- next_ctx = next->perf_event_ctxp[ctxn];
+ next_ctx = rcu_dereference(next->perf_event_ctxp);
if (!next_ctx)
goto unlock;
@@ -3443,7 +3477,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING);
if (context_equiv(ctx, next_ctx)) {
- perf_pmu_disable(pmu);
+ perf_ctx_disable(ctx);
/* PMIs are disabled; ctx->nr_pending is stable. */
if (local_read(&ctx->nr_pending) ||
@@ -3460,21 +3494,10 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
WRITE_ONCE(ctx->task, next);
WRITE_ONCE(next_ctx->task, task);
- if (cpuctx->sched_cb_usage && pmu->sched_task)
- pmu->sched_task(ctx, false);
+ perf_ctx_sched_task_cb(ctx, false);
+ perf_event_swap_task_ctx_data(ctx, next_ctx);
- /*
- * PMU specific parts of task perf context can require
- * additional synchronization. As an example of such
- * synchronization see implementation details of Intel
- * LBR call stack data profiling;
- */
- if (pmu->swap_task_ctx)
- pmu->swap_task_ctx(ctx, next_ctx);
- else
- swap(ctx->task_ctx_data, next_ctx->task_ctx_data);
-
- perf_pmu_enable(pmu);
+ perf_ctx_enable(ctx);
/*
* RCU_INIT_POINTER here is safe because we've not
@@ -3483,8 +3506,8 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
* since those values are always verified under
* ctx->lock which we're now holding.
*/
- RCU_INIT_POINTER(task->perf_event_ctxp[ctxn], next_ctx);
- RCU_INIT_POINTER(next->perf_event_ctxp[ctxn], ctx);
+ RCU_INIT_POINTER(task->perf_event_ctxp, next_ctx);
+ RCU_INIT_POINTER(next->perf_event_ctxp, ctx);
do_switch = 0;
@@ -3498,38 +3521,40 @@ unlock:
if (do_switch) {
raw_spin_lock(&ctx->lock);
- perf_pmu_disable(pmu);
+ perf_ctx_disable(ctx);
inside_switch:
- if (cpuctx->sched_cb_usage && pmu->sched_task)
- pmu->sched_task(ctx, false);
- task_ctx_sched_out(cpuctx, ctx, EVENT_ALL);
+ perf_ctx_sched_task_cb(ctx, false);
+ task_ctx_sched_out(ctx, EVENT_ALL);
- perf_pmu_enable(pmu);
+ perf_ctx_enable(ctx);
raw_spin_unlock(&ctx->lock);
}
}
static DEFINE_PER_CPU(struct list_head, sched_cb_list);
+static DEFINE_PER_CPU(int, perf_sched_cb_usages);
void perf_sched_cb_dec(struct pmu *pmu)
{
- struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+ struct perf_cpu_pmu_context *cpc = this_cpu_ptr(pmu->cpu_pmu_context);
this_cpu_dec(perf_sched_cb_usages);
+ barrier();
- if (!--cpuctx->sched_cb_usage)
- list_del(&cpuctx->sched_cb_entry);
+ if (!--cpc->sched_cb_usage)
+ list_del(&cpc->sched_cb_entry);
}
void perf_sched_cb_inc(struct pmu *pmu)
{
- struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+ struct perf_cpu_pmu_context *cpc = this_cpu_ptr(pmu->cpu_pmu_context);
- if (!cpuctx->sched_cb_usage++)
- list_add(&cpuctx->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
+ if (!cpc->sched_cb_usage++)
+ list_add(&cpc->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
+ barrier();
this_cpu_inc(perf_sched_cb_usages);
}
@@ -3541,19 +3566,21 @@ void perf_sched_cb_inc(struct pmu *pmu)
* PEBS requires this to provide PID/TID information. This requires we flush
* all queued PEBS records before we context switch to a new task.
*/
-static void __perf_pmu_sched_task(struct perf_cpu_context *cpuctx, bool sched_in)
+static void __perf_pmu_sched_task(struct perf_cpu_pmu_context *cpc, bool sched_in)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct pmu *pmu;
- pmu = cpuctx->ctx.pmu; /* software PMUs will not have sched_task */
+ pmu = cpc->epc.pmu;
+ /* software PMUs will not have sched_task */
if (WARN_ON_ONCE(!pmu->sched_task))
return;
perf_ctx_lock(cpuctx, cpuctx->task_ctx);
perf_pmu_disable(pmu);
- pmu->sched_task(cpuctx->task_ctx, sched_in);
+ pmu->sched_task(cpc->task_epc, sched_in);
perf_pmu_enable(pmu);
perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
@@ -3563,26 +3590,20 @@ static void perf_pmu_sched_task(struct task_struct *prev,
struct task_struct *next,
bool sched_in)
{
- struct perf_cpu_context *cpuctx;
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct perf_cpu_pmu_context *cpc;
- if (prev == next)
+ /* cpuctx->task_ctx will be handled in perf_event_context_sched_in/out */
+ if (prev == next || cpuctx->task_ctx)
return;
- list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
- /* will be handled in perf_event_context_sched_in/out */
- if (cpuctx->task_ctx)
- continue;
-
- __perf_pmu_sched_task(cpuctx, sched_in);
- }
+ list_for_each_entry(cpc, this_cpu_ptr(&sched_cb_list), sched_cb_entry)
+ __perf_pmu_sched_task(cpc, sched_in);
}
static void perf_event_switch(struct task_struct *task,
struct task_struct *next_prev, bool sched_in);
-#define for_each_task_context_nr(ctxn) \
- for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
-
/*
* Called from scheduler to remove the events of the current task,
* with interrupts disabled.
@@ -3597,16 +3618,13 @@ static void perf_event_switch(struct task_struct *task,
void __perf_event_task_sched_out(struct task_struct *task,
struct task_struct *next)
{
- int ctxn;
-
if (__this_cpu_read(perf_sched_cb_usages))
perf_pmu_sched_task(task, next, false);
if (atomic_read(&nr_switch_events))
perf_event_switch(task, next, false);
- for_each_task_context_nr(ctxn)
- perf_event_context_sched_out(task, ctxn, next);
+ perf_event_context_sched_out(task, next);
/*
* if cgroup events exist on this CPU, then we need
@@ -3617,15 +3635,6 @@ void __perf_event_task_sched_out(struct task_struct *task,
perf_cgroup_switch(next);
}
-/*
- * Called with IRQs disabled
- */
-static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
- enum event_type_t event_type)
-{
- ctx_sched_out(&cpuctx->ctx, cpuctx, event_type);
-}
-
static bool perf_less_group_idx(const void *l, const void *r)
{
const struct perf_event *le = *(const struct perf_event **)l;
@@ -3657,21 +3666,39 @@ static void __heap_add(struct min_heap *heap, struct perf_event *event)
}
}
-static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
+static void __link_epc(struct perf_event_pmu_context *pmu_ctx)
+{
+ struct perf_cpu_pmu_context *cpc;
+
+ if (!pmu_ctx->ctx->task)
+ return;
+
+ cpc = this_cpu_ptr(pmu_ctx->pmu->cpu_pmu_context);
+ WARN_ON_ONCE(cpc->task_epc && cpc->task_epc != pmu_ctx);
+ cpc->task_epc = pmu_ctx;
+}
+
+static noinline int visit_groups_merge(struct perf_event_context *ctx,
struct perf_event_groups *groups, int cpu,
+ struct pmu *pmu,
int (*func)(struct perf_event *, void *),
void *data)
{
#ifdef CONFIG_CGROUP_PERF
struct cgroup_subsys_state *css = NULL;
#endif
+ struct perf_cpu_context *cpuctx = NULL;
/* Space for per CPU and/or any CPU event iterators. */
struct perf_event *itrs[2];
struct min_heap event_heap;
struct perf_event **evt;
int ret;
- if (cpuctx) {
+ if (pmu->filter && pmu->filter(pmu, cpu))
+ return 0;
+
+ if (!ctx->task) {
+ cpuctx = this_cpu_ptr(&perf_cpu_context);
event_heap = (struct min_heap){
.data = cpuctx->heap,
.nr = 0,
@@ -3691,17 +3718,22 @@ static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
.size = ARRAY_SIZE(itrs),
};
/* Events not within a CPU context may be on any CPU. */
- __heap_add(&event_heap, perf_event_groups_first(groups, -1, NULL));
+ __heap_add(&event_heap, perf_event_groups_first(groups, -1, pmu, NULL));
}
evt = event_heap.data;
- __heap_add(&event_heap, perf_event_groups_first(groups, cpu, NULL));
+ __heap_add(&event_heap, perf_event_groups_first(groups, cpu, pmu, NULL));
#ifdef CONFIG_CGROUP_PERF
for (; css; css = css->parent)
- __heap_add(&event_heap, perf_event_groups_first(groups, cpu, css->cgroup));
+ __heap_add(&event_heap, perf_event_groups_first(groups, cpu, pmu, css->cgroup));
#endif
+ if (event_heap.nr) {
+ __link_epc((*evt)->pmu_ctx);
+ perf_assert_pmu_disabled((*evt)->pmu_ctx->pmu);
+ }
+
min_heapify_all(&event_heap, &perf_min_heap);
while (event_heap.nr) {
@@ -3709,7 +3741,7 @@ static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
if (ret)
return ret;
- *evt = perf_event_groups_next(*evt);
+ *evt = perf_event_groups_next(*evt, pmu);
if (*evt)
min_heapify(&event_heap, 0, &perf_min_heap);
else
@@ -3751,7 +3783,6 @@ static inline void group_update_userpage(struct perf_event *group_event)
static int merge_sched_in(struct perf_event *event, void *data)
{
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
int *can_add_hw = data;
if (event->state <= PERF_EVENT_STATE_OFF)
@@ -3760,8 +3791,8 @@ static int merge_sched_in(struct perf_event *event, void *data)
if (!event_filter_match(event))
return 0;
- if (group_can_go_on(event, cpuctx, *can_add_hw)) {
- if (!group_sched_in(event, cpuctx, ctx))
+ if (group_can_go_on(event, *can_add_hw)) {
+ if (!group_sched_in(event, ctx))
list_add_tail(&event->active_list, get_event_list(event));
}
@@ -3771,8 +3802,11 @@ static int merge_sched_in(struct perf_event *event, void *data)
perf_cgroup_event_disable(event, ctx);
perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
} else {
- ctx->rotate_necessary = 1;
- perf_mux_hrtimer_restart(cpuctx);
+ struct perf_cpu_pmu_context *cpc;
+
+ event->pmu_ctx->rotate_necessary = 1;
+ cpc = this_cpu_ptr(event->pmu_ctx->pmu->cpu_pmu_context);
+ perf_mux_hrtimer_restart(cpc);
group_update_userpage(event);
}
}
@@ -3780,39 +3814,53 @@ static int merge_sched_in(struct perf_event *event, void *data)
return 0;
}
-static void
-ctx_pinned_sched_in(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx)
+static void ctx_pinned_sched_in(struct perf_event_context *ctx, struct pmu *pmu)
{
+ struct perf_event_pmu_context *pmu_ctx;
int can_add_hw = 1;
- if (ctx != &cpuctx->ctx)
- cpuctx = NULL;
-
- visit_groups_merge(cpuctx, &ctx->pinned_groups,
- smp_processor_id(),
- merge_sched_in, &can_add_hw);
+ if (pmu) {
+ visit_groups_merge(ctx, &ctx->pinned_groups,
+ smp_processor_id(), pmu,
+ merge_sched_in, &can_add_hw);
+ } else {
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry) {
+ can_add_hw = 1;
+ visit_groups_merge(ctx, &ctx->pinned_groups,
+ smp_processor_id(), pmu_ctx->pmu,
+ merge_sched_in, &can_add_hw);
+ }
+ }
}
-static void
-ctx_flexible_sched_in(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx)
+static void ctx_flexible_sched_in(struct perf_event_context *ctx, struct pmu *pmu)
{
+ struct perf_event_pmu_context *pmu_ctx;
int can_add_hw = 1;
- if (ctx != &cpuctx->ctx)
- cpuctx = NULL;
+ if (pmu) {
+ visit_groups_merge(ctx, &ctx->flexible_groups,
+ smp_processor_id(), pmu,
+ merge_sched_in, &can_add_hw);
+ } else {
+ list_for_each_entry(pmu_ctx, &ctx->pmu_ctx_list, pmu_ctx_entry) {
+ can_add_hw = 1;
+ visit_groups_merge(ctx, &ctx->flexible_groups,
+ smp_processor_id(), pmu_ctx->pmu,
+ merge_sched_in, &can_add_hw);
+ }
+ }
+}
- visit_groups_merge(cpuctx, &ctx->flexible_groups,
- smp_processor_id(),
- merge_sched_in, &can_add_hw);
+static void __pmu_ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu)
+{
+ ctx_flexible_sched_in(ctx, pmu);
}
static void
-ctx_sched_in(struct perf_event_context *ctx,
- struct perf_cpu_context *cpuctx,
- enum event_type_t event_type)
+ctx_sched_in(struct perf_event_context *ctx, enum event_type_t event_type)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
int is_active = ctx->is_active;
lockdep_assert_held(&ctx->lock);
@@ -3846,39 +3894,32 @@ ctx_sched_in(struct perf_event_context *ctx,
* in order to give them the best chance of going on.
*/
if (is_active & EVENT_PINNED)
- ctx_pinned_sched_in(ctx, cpuctx);
+ ctx_pinned_sched_in(ctx, NULL);
/* Then walk through the lower prio flexible groups */
if (is_active & EVENT_FLEXIBLE)
- ctx_flexible_sched_in(ctx, cpuctx);
+ ctx_flexible_sched_in(ctx, NULL);
}
-static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
- enum event_type_t event_type)
+static void perf_event_context_sched_in(struct task_struct *task)
{
- struct perf_event_context *ctx = &cpuctx->ctx;
-
- ctx_sched_in(ctx, cpuctx, event_type);
-}
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct perf_event_context *ctx;
-static void perf_event_context_sched_in(struct perf_event_context *ctx,
- struct task_struct *task)
-{
- struct perf_cpu_context *cpuctx;
- struct pmu *pmu;
+ rcu_read_lock();
+ ctx = rcu_dereference(task->perf_event_ctxp);
+ if (!ctx)
+ goto rcu_unlock;
- cpuctx = __get_cpu_context(ctx);
+ if (cpuctx->task_ctx == ctx) {
+ perf_ctx_lock(cpuctx, ctx);
+ perf_ctx_disable(ctx);
- /*
- * HACK: for HETEROGENEOUS the task context might have switched to a
- * different PMU, force (re)set the context,
- */
- pmu = ctx->pmu = cpuctx->ctx.pmu;
+ perf_ctx_sched_task_cb(ctx, true);
- if (cpuctx->task_ctx == ctx) {
- if (cpuctx->sched_cb_usage)
- __perf_pmu_sched_task(cpuctx, true);
- return;
+ perf_ctx_enable(ctx);
+ perf_ctx_unlock(cpuctx, ctx);
+ goto rcu_unlock;
}
perf_ctx_lock(cpuctx, ctx);
@@ -3889,7 +3930,7 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
if (!ctx->nr_events)
goto unlock;
- perf_pmu_disable(pmu);
+ perf_ctx_disable(ctx);
/*
* We want to keep the following priority order:
* cpu pinned (that don't need to move), task pinned,
@@ -3898,17 +3939,24 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
* However, if task's ctx is not carrying any pinned
* events, no need to flip the cpuctx's events around.
*/
- if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree))
- cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
+ if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree)) {
+ perf_ctx_disable(&cpuctx->ctx);
+ ctx_sched_out(&cpuctx->ctx, EVENT_FLEXIBLE);
+ }
+
perf_event_sched_in(cpuctx, ctx);
- if (cpuctx->sched_cb_usage && pmu->sched_task)
- pmu->sched_task(cpuctx->task_ctx, true);
+ perf_ctx_sched_task_cb(cpuctx->task_ctx, true);
- perf_pmu_enable(pmu);
+ if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree))
+ perf_ctx_enable(&cpuctx->ctx);
+
+ perf_ctx_enable(ctx);
unlock:
perf_ctx_unlock(cpuctx, ctx);
+rcu_unlock:
+ rcu_read_unlock();
}
/*
@@ -3925,16 +3973,7 @@ unlock:
void __perf_event_task_sched_in(struct task_struct *prev,
struct task_struct *task)
{
- struct perf_event_context *ctx;
- int ctxn;
-
- for_each_task_context_nr(ctxn) {
- ctx = task->perf_event_ctxp[ctxn];
- if (likely(!ctx))
- continue;
-
- perf_event_context_sched_in(ctx, task);
- }
+ perf_event_context_sched_in(task);
if (atomic_read(&nr_switch_events))
perf_event_switch(task, prev, true);
@@ -4053,8 +4092,8 @@ static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count, bo
* events. At the same time, make sure, having freq events does not change
* the rate of unthrottling as that would introduce bias.
*/
-static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
- int needs_unthr)
+static void
+perf_adjust_freq_unthr_context(struct perf_event_context *ctx, bool unthrottle)
{
struct perf_event *event;
struct hw_perf_event *hwc;
@@ -4066,16 +4105,16 @@ static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
* - context have events in frequency mode (needs freq adjust)
* - there are events to unthrottle on this cpu
*/
- if (!(ctx->nr_freq || needs_unthr))
+ if (!(ctx->nr_freq || unthrottle))
return;
raw_spin_lock(&ctx->lock);
- perf_pmu_disable(ctx->pmu);
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
if (event->state != PERF_EVENT_STATE_ACTIVE)
continue;
+ // XXX use visit thingy to avoid the -1,cpu match
if (!event_filter_match(event))
continue;
@@ -4116,7 +4155,6 @@ static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
perf_pmu_enable(event->pmu);
}
- perf_pmu_enable(ctx->pmu);
raw_spin_unlock(&ctx->lock);
}
@@ -4138,72 +4176,109 @@ static void rotate_ctx(struct perf_event_context *ctx, struct perf_event *event)
/* pick an event from the flexible_groups to rotate */
static inline struct perf_event *
-ctx_event_to_rotate(struct perf_event_context *ctx)
+ctx_event_to_rotate(struct perf_event_pmu_context *pmu_ctx)
{
struct perf_event *event;
+ struct rb_node *node;
+ struct rb_root *tree;
+ struct __group_key key = {
+ .pmu = pmu_ctx->pmu,
+ };
/* pick the first active flexible event */
- event = list_first_entry_or_null(&ctx->flexible_active,
+ event = list_first_entry_or_null(&pmu_ctx->flexible_active,
struct perf_event, active_list);
+ if (event)
+ goto out;
/* if no active flexible event, pick the first event */
- if (!event) {
- event = rb_entry_safe(rb_first(&ctx->flexible_groups.tree),
- typeof(*event), group_node);
+ tree = &pmu_ctx->ctx->flexible_groups.tree;
+
+ if (!pmu_ctx->ctx->task) {
+ key.cpu = smp_processor_id();
+
+ node = rb_find_first(&key, tree, __group_cmp_ignore_cgroup);
+ if (node)
+ event = __node_2_pe(node);
+ goto out;
}
+ key.cpu = -1;
+ node = rb_find_first(&key, tree, __group_cmp_ignore_cgroup);
+ if (node) {
+ event = __node_2_pe(node);
+ goto out;
+ }
+
+ key.cpu = smp_processor_id();
+ node = rb_find_first(&key, tree, __group_cmp_ignore_cgroup);
+ if (node)
+ event = __node_2_pe(node);
+
+out:
/*
* Unconditionally clear rotate_necessary; if ctx_flexible_sched_in()
* finds there are unschedulable events, it will set it again.
*/
- ctx->rotate_necessary = 0;
+ pmu_ctx->rotate_necessary = 0;
return event;
}
-static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
+static bool perf_rotate_context(struct perf_cpu_pmu_context *cpc)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct perf_event_pmu_context *cpu_epc, *task_epc = NULL;
struct perf_event *cpu_event = NULL, *task_event = NULL;
- struct perf_event_context *task_ctx = NULL;
int cpu_rotate, task_rotate;
+ struct pmu *pmu;
/*
* Since we run this from IRQ context, nobody can install new
* events, thus the event count values are stable.
*/
- cpu_rotate = cpuctx->ctx.rotate_necessary;
- task_ctx = cpuctx->task_ctx;
- task_rotate = task_ctx ? task_ctx->rotate_necessary : 0;
+ cpu_epc = &cpc->epc;
+ pmu = cpu_epc->pmu;
+ task_epc = cpc->task_epc;
+
+ cpu_rotate = cpu_epc->rotate_necessary;
+ task_rotate = task_epc ? task_epc->rotate_necessary : 0;
if (!(cpu_rotate || task_rotate))
return false;
perf_ctx_lock(cpuctx, cpuctx->task_ctx);
- perf_pmu_disable(cpuctx->ctx.pmu);
+ perf_pmu_disable(pmu);
if (task_rotate)
- task_event = ctx_event_to_rotate(task_ctx);
+ task_event = ctx_event_to_rotate(task_epc);
if (cpu_rotate)
- cpu_event = ctx_event_to_rotate(&cpuctx->ctx);
+ cpu_event = ctx_event_to_rotate(cpu_epc);
/*
* As per the order given at ctx_resched() first 'pop' task flexible
* and then, if needed CPU flexible.
*/
- if (task_event || (task_ctx && cpu_event))
- ctx_sched_out(task_ctx, cpuctx, EVENT_FLEXIBLE);
- if (cpu_event)
- cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
+ if (task_event || (task_epc && cpu_event)) {
+ update_context_time(task_epc->ctx);
+ __pmu_ctx_sched_out(task_epc, EVENT_FLEXIBLE);
+ }
- if (task_event)
- rotate_ctx(task_ctx, task_event);
- if (cpu_event)
+ if (cpu_event) {
+ update_context_time(&cpuctx->ctx);
+ __pmu_ctx_sched_out(cpu_epc, EVENT_FLEXIBLE);
rotate_ctx(&cpuctx->ctx, cpu_event);
+ __pmu_ctx_sched_in(&cpuctx->ctx, pmu);
+ }
- perf_event_sched_in(cpuctx, task_ctx);
+ if (task_event)
+ rotate_ctx(task_epc->ctx, task_event);
+
+ if (task_event || (task_epc && cpu_event))
+ __pmu_ctx_sched_in(task_epc->ctx, pmu);
- perf_pmu_enable(cpuctx->ctx.pmu);
+ perf_pmu_enable(pmu);
perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
return true;
@@ -4211,8 +4286,8 @@ static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
void perf_event_task_tick(void)
{
- struct list_head *head = this_cpu_ptr(&active_ctx_list);
- struct perf_event_context *ctx, *tmp;
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct perf_event_context *ctx;
int throttled;
lockdep_assert_irqs_disabled();
@@ -4221,8 +4296,13 @@ void perf_event_task_tick(void)
throttled = __this_cpu_xchg(perf_throttled_count, 0);
tick_dep_clear_cpu(smp_processor_id(), TICK_DEP_BIT_PERF_EVENTS);
- list_for_each_entry_safe(ctx, tmp, head, active_ctx_list)
- perf_adjust_freq_unthr_context(ctx, throttled);
+ perf_adjust_freq_unthr_context(&cpuctx->ctx, !!throttled);
+
+ rcu_read_lock();
+ ctx = rcu_dereference(current->perf_event_ctxp);
+ if (ctx)
+ perf_adjust_freq_unthr_context(ctx, !!throttled);
+ rcu_read_unlock();
}
static int event_enable_on_exec(struct perf_event *event,
@@ -4244,9 +4324,9 @@ 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(int ctxn)
+static void perf_event_enable_on_exec(struct perf_event_context *ctx)
{
- struct perf_event_context *ctx, *clone_ctx = NULL;
+ struct perf_event_context *clone_ctx = NULL;
enum event_type_t event_type = 0;
struct perf_cpu_context *cpuctx;
struct perf_event *event;
@@ -4254,13 +4334,16 @@ static void perf_event_enable_on_exec(int ctxn)
int enabled = 0;
local_irq_save(flags);
- ctx = current->perf_event_ctxp[ctxn];
- if (!ctx || !ctx->nr_events)
+ if (WARN_ON_ONCE(current->perf_event_ctxp != ctx))
goto out;
- cpuctx = __get_cpu_context(ctx);
+ if (!ctx->nr_events)
+ goto out;
+
+ cpuctx = this_cpu_ptr(&perf_cpu_context);
perf_ctx_lock(cpuctx, ctx);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_out(ctx, EVENT_TIME);
+
list_for_each_entry(event, &ctx->event_list, event_entry) {
enabled |= event_enable_on_exec(event, ctx);
event_type |= get_event_type(event);
@@ -4273,7 +4356,7 @@ static void perf_event_enable_on_exec(int ctxn)
clone_ctx = unclone_ctx(ctx);
ctx_resched(cpuctx, ctx, event_type);
} else {
- ctx_sched_in(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_in(ctx, EVENT_TIME);
}
perf_ctx_unlock(cpuctx, ctx);
@@ -4292,17 +4375,13 @@ static void perf_event_exit_event(struct perf_event *event,
* Removes all events from the current task that have been marked
* remove-on-exec, and feeds their values back to parent events.
*/
-static void perf_event_remove_on_exec(int ctxn)
+static void perf_event_remove_on_exec(struct perf_event_context *ctx)
{
- struct perf_event_context *ctx, *clone_ctx = NULL;
+ struct perf_event_context *clone_ctx = NULL;
struct perf_event *event, *next;
unsigned long flags;
bool modified = false;
- ctx = perf_pin_task_context(current, ctxn);
- if (!ctx)
- return;
-
mutex_lock(&ctx->mutex);
if (WARN_ON_ONCE(ctx->task != current))
@@ -4323,13 +4402,11 @@ static void perf_event_remove_on_exec(int ctxn)
raw_spin_lock_irqsave(&ctx->lock, flags);
if (modified)
clone_ctx = unclone_ctx(ctx);
- --ctx->pin_count;
raw_spin_unlock_irqrestore(&ctx->lock, flags);
unlock:
mutex_unlock(&ctx->mutex);
- put_ctx(ctx);
if (clone_ctx)
put_ctx(clone_ctx);
}
@@ -4365,7 +4442,7 @@ static void __perf_event_read(void *info)
struct perf_read_data *data = info;
struct perf_event *sub, *event = data->event;
struct perf_event_context *ctx = event->ctx;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct pmu *pmu = event->pmu;
/*
@@ -4591,17 +4668,25 @@ static void __perf_event_init_context(struct perf_event_context *ctx)
{
raw_spin_lock_init(&ctx->lock);
mutex_init(&ctx->mutex);
- INIT_LIST_HEAD(&ctx->active_ctx_list);
+ INIT_LIST_HEAD(&ctx->pmu_ctx_list);
perf_event_groups_init(&ctx->pinned_groups);
perf_event_groups_init(&ctx->flexible_groups);
INIT_LIST_HEAD(&ctx->event_list);
- INIT_LIST_HEAD(&ctx->pinned_active);
- INIT_LIST_HEAD(&ctx->flexible_active);
refcount_set(&ctx->refcount, 1);
}
+static void
+__perf_init_event_pmu_context(struct perf_event_pmu_context *epc, struct pmu *pmu)
+{
+ epc->pmu = pmu;
+ INIT_LIST_HEAD(&epc->pmu_ctx_entry);
+ INIT_LIST_HEAD(&epc->pinned_active);
+ INIT_LIST_HEAD(&epc->flexible_active);
+ atomic_set(&epc->refcount, 1);
+}
+
static struct perf_event_context *
-alloc_perf_context(struct pmu *pmu, struct task_struct *task)
+alloc_perf_context(struct task_struct *task)
{
struct perf_event_context *ctx;
@@ -4612,7 +4697,6 @@ alloc_perf_context(struct pmu *pmu, struct task_struct *task)
__perf_event_init_context(ctx);
if (task)
ctx->task = get_task_struct(task);
- ctx->pmu = pmu;
return ctx;
}
@@ -4641,15 +4725,12 @@ find_lively_task_by_vpid(pid_t vpid)
* Returns a matching context with refcount and pincount.
*/
static struct perf_event_context *
-find_get_context(struct pmu *pmu, struct task_struct *task,
- struct perf_event *event)
+find_get_context(struct task_struct *task, struct perf_event *event)
{
struct perf_event_context *ctx, *clone_ctx = NULL;
struct perf_cpu_context *cpuctx;
- void *task_ctx_data = NULL;
unsigned long flags;
- int ctxn, err;
- int cpu = event->cpu;
+ int err;
if (!task) {
/* Must be root to operate on a CPU event: */
@@ -4657,7 +4738,7 @@ find_get_context(struct pmu *pmu, struct task_struct *task,
if (err)
return ERR_PTR(err);
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+ cpuctx = per_cpu_ptr(&perf_cpu_context, event->cpu);
ctx = &cpuctx->ctx;
get_ctx(ctx);
raw_spin_lock_irqsave(&ctx->lock, flags);
@@ -4668,43 +4749,22 @@ find_get_context(struct pmu *pmu, struct task_struct *task,
}
err = -EINVAL;
- ctxn = pmu->task_ctx_nr;
- if (ctxn < 0)
- goto errout;
-
- if (event->attach_state & PERF_ATTACH_TASK_DATA) {
- task_ctx_data = alloc_task_ctx_data(pmu);
- if (!task_ctx_data) {
- err = -ENOMEM;
- goto errout;
- }
- }
-
retry:
- ctx = perf_lock_task_context(task, ctxn, &flags);
+ ctx = perf_lock_task_context(task, &flags);
if (ctx) {
clone_ctx = unclone_ctx(ctx);
++ctx->pin_count;
- if (task_ctx_data && !ctx->task_ctx_data) {
- ctx->task_ctx_data = task_ctx_data;
- task_ctx_data = NULL;
- }
raw_spin_unlock_irqrestore(&ctx->lock, flags);
if (clone_ctx)
put_ctx(clone_ctx);
} else {
- ctx = alloc_perf_context(pmu, task);
+ ctx = alloc_perf_context(task);
err = -ENOMEM;
if (!ctx)
goto errout;
- if (task_ctx_data) {
- ctx->task_ctx_data = task_ctx_data;
- task_ctx_data = NULL;
- }
-
err = 0;
mutex_lock(&task->perf_event_mutex);
/*
@@ -4713,12 +4773,12 @@ retry:
*/
if (task->flags & PF_EXITING)
err = -ESRCH;
- else if (task->perf_event_ctxp[ctxn])
+ else if (task->perf_event_ctxp)
err = -EAGAIN;
else {
get_ctx(ctx);
++ctx->pin_count;
- rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx);
+ rcu_assign_pointer(task->perf_event_ctxp, ctx);
}
mutex_unlock(&task->perf_event_mutex);
@@ -4731,21 +4791,146 @@ retry:
}
}
- free_task_ctx_data(pmu, task_ctx_data);
return ctx;
errout:
- free_task_ctx_data(pmu, task_ctx_data);
return ERR_PTR(err);
}
+static struct perf_event_pmu_context *
+find_get_pmu_context(struct pmu *pmu, struct perf_event_context *ctx,
+ struct perf_event *event)
+{
+ struct perf_event_pmu_context *new = NULL, *epc;
+ void *task_ctx_data = NULL;
+
+ if (!ctx->task) {
+ struct perf_cpu_pmu_context *cpc;
+
+ cpc = per_cpu_ptr(pmu->cpu_pmu_context, event->cpu);
+ epc = &cpc->epc;
+
+ if (!epc->ctx) {
+ atomic_set(&epc->refcount, 1);
+ epc->embedded = 1;
+ raw_spin_lock_irq(&ctx->lock);
+ list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
+ epc->ctx = ctx;
+ raw_spin_unlock_irq(&ctx->lock);
+ } else {
+ WARN_ON_ONCE(epc->ctx != ctx);
+ atomic_inc(&epc->refcount);
+ }
+
+ return epc;
+ }
+
+ new = kzalloc(sizeof(*epc), GFP_KERNEL);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+
+ if (event->attach_state & PERF_ATTACH_TASK_DATA) {
+ task_ctx_data = alloc_task_ctx_data(pmu);
+ if (!task_ctx_data) {
+ kfree(new);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ __perf_init_event_pmu_context(new, pmu);
+
+ /*
+ * XXX
+ *
+ * lockdep_assert_held(&ctx->mutex);
+ *
+ * can't because perf_event_init_task() doesn't actually hold the
+ * child_ctx->mutex.
+ */
+
+ raw_spin_lock_irq(&ctx->lock);
+ list_for_each_entry(epc, &ctx->pmu_ctx_list, pmu_ctx_entry) {
+ if (epc->pmu == pmu) {
+ WARN_ON_ONCE(epc->ctx != ctx);
+ atomic_inc(&epc->refcount);
+ goto found_epc;
+ }
+ }
+
+ epc = new;
+ new = NULL;
+
+ list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
+ epc->ctx = ctx;
+
+found_epc:
+ if (task_ctx_data && !epc->task_ctx_data) {
+ epc->task_ctx_data = task_ctx_data;
+ task_ctx_data = NULL;
+ ctx->nr_task_data++;
+ }
+ raw_spin_unlock_irq(&ctx->lock);
+
+ free_task_ctx_data(pmu, task_ctx_data);
+ kfree(new);
+
+ return epc;
+}
+
+static void get_pmu_ctx(struct perf_event_pmu_context *epc)
+{
+ WARN_ON_ONCE(!atomic_inc_not_zero(&epc->refcount));
+}
+
+static void free_epc_rcu(struct rcu_head *head)
+{
+ struct perf_event_pmu_context *epc = container_of(head, typeof(*epc), rcu_head);
+
+ kfree(epc->task_ctx_data);
+ kfree(epc);
+}
+
+static void put_pmu_ctx(struct perf_event_pmu_context *epc)
+{
+ unsigned long flags;
+
+ if (!atomic_dec_and_test(&epc->refcount))
+ return;
+
+ if (epc->ctx) {
+ struct perf_event_context *ctx = epc->ctx;
+
+ /*
+ * XXX
+ *
+ * lockdep_assert_held(&ctx->mutex);
+ *
+ * can't because of the call-site in _free_event()/put_event()
+ * which isn't always called under ctx->mutex.
+ */
+
+ WARN_ON_ONCE(list_empty(&epc->pmu_ctx_entry));
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+ list_del_init(&epc->pmu_ctx_entry);
+ epc->ctx = NULL;
+ raw_spin_unlock_irqrestore(&ctx->lock, flags);
+ }
+
+ WARN_ON_ONCE(!list_empty(&epc->pinned_active));
+ WARN_ON_ONCE(!list_empty(&epc->flexible_active));
+
+ if (epc->embedded)
+ return;
+
+ call_rcu(&epc->rcu_head, free_epc_rcu);
+}
+
static void perf_event_free_filter(struct perf_event *event);
static void free_event_rcu(struct rcu_head *head)
{
- struct perf_event *event;
+ struct perf_event *event = container_of(head, typeof(*event), rcu_head);
- event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
perf_event_free_filter(event);
@@ -4883,7 +5068,7 @@ static void perf_sched_delayed(struct work_struct *work)
*
* 1) cpu-wide events in the presence of per-task events,
* 2) per-task events in the presence of cpu-wide events,
- * 3) two matching events on the same context.
+ * 3) two matching events on the same perf_event_context.
*
* The former two cases are handled in the allocation path (perf_event_alloc(),
* _free_event()), the latter -- before the first perf_install_in_context().
@@ -5007,6 +5192,9 @@ static void _free_event(struct perf_event *event)
if (event->hw.target)
put_task_struct(event->hw.target);
+ if (event->pmu_ctx)
+ put_pmu_ctx(event->pmu_ctx);
+
/*
* perf_event_free_task() relies on put_ctx() being 'last', in particular
* all task references must be cleaned up.
@@ -5107,8 +5295,8 @@ int perf_event_release_kernel(struct perf_event *event)
LIST_HEAD(free_list);
/*
- * If we got here through err_file: fput(event_file); we will not have
- * attached to a context yet.
+ * If we got here through err_alloc: free_event(event); we will not
+ * have attached to a context yet.
*/
if (!ctx) {
WARN_ON_ONCE(event->attach_state &
@@ -5121,9 +5309,7 @@ int perf_event_release_kernel(struct perf_event *event)
ctx = perf_event_ctx_lock(event);
WARN_ON_ONCE(ctx->parent_ctx);
- perf_remove_from_context(event, DETACH_GROUP);
- raw_spin_lock_irq(&ctx->lock);
/*
* Mark this event as STATE_DEAD, there is no external reference to it
* anymore.
@@ -5135,8 +5321,7 @@ int perf_event_release_kernel(struct perf_event *event)
* Thus this guarantees that we will in fact observe and kill _ALL_
* child events.
*/
- event->state = PERF_EVENT_STATE_DEAD;
- raw_spin_unlock_irq(&ctx->lock);
+ perf_remove_from_context(event, DETACH_GROUP|DETACH_DEAD);
perf_event_ctx_unlock(event, ctx);
@@ -5543,7 +5728,7 @@ static void __perf_event_period(struct perf_event *event,
active = (event->state == PERF_EVENT_STATE_ACTIVE);
if (active) {
- perf_pmu_disable(ctx->pmu);
+ perf_pmu_disable(event->pmu);
/*
* We could be throttled; unthrottle now to avoid the tick
* trying to unthrottle while we already re-started the event.
@@ -5559,7 +5744,7 @@ static void __perf_event_period(struct perf_event *event,
if (active) {
event->pmu->start(event, PERF_EF_RELOAD);
- perf_pmu_enable(ctx->pmu);
+ perf_pmu_enable(event->pmu);
}
}
@@ -6577,6 +6762,8 @@ static void perf_pending_task(struct callback_head *head)
if (rctx >= 0)
perf_swevent_put_recursion_context(rctx);
preempt_enable_notrace();
+
+ put_event(event);
}
#ifdef CONFIG_GUEST_PERF_EVENTS
@@ -7720,7 +7907,6 @@ perf_iterate_sb(perf_iterate_f output, void *data,
struct perf_event_context *task_ctx)
{
struct perf_event_context *ctx;
- int ctxn;
rcu_read_lock();
preempt_disable();
@@ -7737,11 +7923,9 @@ perf_iterate_sb(perf_iterate_f output, void *data,
perf_iterate_sb_cpu(output, data);
- for_each_task_context_nr(ctxn) {
- ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
- if (ctx)
- perf_iterate_ctx(ctx, output, data, false);
- }
+ ctx = rcu_dereference(current->perf_event_ctxp);
+ if (ctx)
+ perf_iterate_ctx(ctx, output, data, false);
done:
preempt_enable();
rcu_read_unlock();
@@ -7783,20 +7967,17 @@ static void perf_event_addr_filters_exec(struct perf_event *event, void *data)
void perf_event_exec(void)
{
struct perf_event_context *ctx;
- int ctxn;
- for_each_task_context_nr(ctxn) {
- perf_event_enable_on_exec(ctxn);
- perf_event_remove_on_exec(ctxn);
+ ctx = perf_pin_task_context(current);
+ if (!ctx)
+ return;
- rcu_read_lock();
- ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
- if (ctx) {
- perf_iterate_ctx(ctx, perf_event_addr_filters_exec,
- NULL, true);
- }
- rcu_read_unlock();
- }
+ perf_event_enable_on_exec(ctx);
+ perf_event_remove_on_exec(ctx);
+ perf_iterate_ctx(ctx, perf_event_addr_filters_exec, NULL, true);
+
+ perf_unpin_context(ctx);
+ put_ctx(ctx);
}
struct remote_output {
@@ -7836,8 +8017,7 @@ static void __perf_event_output_stop(struct perf_event *event, void *data)
static int __perf_pmu_output_stop(void *info)
{
struct perf_event *event = info;
- struct pmu *pmu = event->ctx->pmu;
- struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct remote_output ro = {
.rb = event->rb,
};
@@ -8626,7 +8806,6 @@ static void __perf_addr_filters_adjust(struct perf_event *event, void *data)
static void perf_addr_filters_adjust(struct vm_area_struct *vma)
{
struct perf_event_context *ctx;
- int ctxn;
/*
* Data tracing isn't supported yet and as such there is no need
@@ -8636,13 +8815,9 @@ static void perf_addr_filters_adjust(struct vm_area_struct *vma)
return;
rcu_read_lock();
- for_each_task_context_nr(ctxn) {
- ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
- if (!ctx)
- continue;
-
+ ctx = rcu_dereference(current->perf_event_ctxp);
+ if (ctx)
perf_iterate_ctx(ctx, __perf_addr_filters_adjust, vma, true);
- }
rcu_read_unlock();
}
@@ -9030,7 +9205,7 @@ static void perf_event_bpf_emit_ksymbols(struct bpf_prog *prog,
PERF_RECORD_KSYMBOL_TYPE_BPF,
(u64)(unsigned long)subprog->bpf_func,
subprog->jited_len, unregister,
- prog->aux->ksym.name);
+ subprog->aux->ksym.name);
}
}
}
@@ -9273,6 +9448,19 @@ int perf_event_account_interrupt(struct perf_event *event)
return __perf_event_account_interrupt(event, 1);
}
+static inline bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
+{
+ /*
+ * Due to interrupt latency (AKA "skid"), we may enter the
+ * kernel before taking an overflow, even if the PMU is only
+ * counting user events.
+ */
+ if (event->attr.exclude_kernel && !user_mode(regs))
+ return false;
+
+ return true;
+}
+
/*
* Generic event overflow handling, sampling.
*/
@@ -9307,15 +9495,38 @@ static int __perf_event_overflow(struct perf_event *event,
if (event->attr.sigtrap) {
/*
- * Should not be able to return to user space without processing
- * pending_sigtrap (kernel events can overflow multiple times).
+ * The desired behaviour of sigtrap vs invalid samples is a bit
+ * tricky; on the one hand, one should not loose the SIGTRAP if
+ * it is the first event, on the other hand, we should also not
+ * trigger the WARN or override the data address.
*/
- WARN_ON_ONCE(event->pending_sigtrap && event->attr.exclude_kernel);
+ bool valid_sample = sample_is_allowed(event, regs);
+ unsigned int pending_id = 1;
+
+ if (regs)
+ pending_id = hash32_ptr((void *)instruction_pointer(regs)) ?: 1;
if (!event->pending_sigtrap) {
- event->pending_sigtrap = 1;
+ event->pending_sigtrap = pending_id;
local_inc(&event->ctx->nr_pending);
+ } else if (event->attr.exclude_kernel && valid_sample) {
+ /*
+ * Should not be able to return to user space without
+ * consuming pending_sigtrap; with exceptions:
+ *
+ * 1. Where !exclude_kernel, events can overflow again
+ * in the kernel without returning to user space.
+ *
+ * 2. Events that can overflow again before the IRQ-
+ * work without user space progress (e.g. hrtimer).
+ * To approximate progress (with false negatives),
+ * check 32-bit hash of the current IP.
+ */
+ WARN_ON_ONCE(event->pending_sigtrap != pending_id);
}
- event->pending_addr = data->addr;
+
+ event->pending_addr = 0;
+ if (valid_sample && (data->sample_flags & PERF_SAMPLE_ADDR))
+ event->pending_addr = data->addr;
irq_work_queue(&event->pending_irq);
}
@@ -9781,6 +9992,44 @@ static struct pmu perf_swevent = {
#ifdef CONFIG_EVENT_TRACING
+static void tp_perf_event_destroy(struct perf_event *event)
+{
+ perf_trace_destroy(event);
+}
+
+static int perf_tp_event_init(struct perf_event *event)
+{
+ int err;
+
+ if (event->attr.type != PERF_TYPE_TRACEPOINT)
+ return -ENOENT;
+
+ /*
+ * no branch sampling for tracepoint events
+ */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ err = perf_trace_init(event);
+ if (err)
+ return err;
+
+ event->destroy = tp_perf_event_destroy;
+
+ return 0;
+}
+
+static struct pmu perf_tracepoint = {
+ .task_ctx_nr = perf_sw_context,
+
+ .event_init = perf_tp_event_init,
+ .add = perf_trace_add,
+ .del = perf_trace_del,
+ .start = perf_swevent_start,
+ .stop = perf_swevent_stop,
+ .read = perf_swevent_read,
+};
+
static int perf_tp_filter_match(struct perf_event *event,
struct perf_sample_data *data)
{
@@ -9830,6 +10079,44 @@ void perf_trace_run_bpf_submit(void *raw_data, int size, int rctx,
}
EXPORT_SYMBOL_GPL(perf_trace_run_bpf_submit);
+static void __perf_tp_event_target_task(u64 count, void *record,
+ struct pt_regs *regs,
+ struct perf_sample_data *data,
+ struct perf_event *event)
+{
+ struct trace_entry *entry = record;
+
+ if (event->attr.config != entry->type)
+ return;
+ /* Cannot deliver synchronous signal to other task. */
+ if (event->attr.sigtrap)
+ return;
+ if (perf_tp_event_match(event, data, regs))
+ perf_swevent_event(event, count, data, regs);
+}
+
+static void perf_tp_event_target_task(u64 count, void *record,
+ struct pt_regs *regs,
+ struct perf_sample_data *data,
+ struct perf_event_context *ctx)
+{
+ unsigned int cpu = smp_processor_id();
+ struct pmu *pmu = &perf_tracepoint;
+ struct perf_event *event, *sibling;
+
+ perf_event_groups_for_cpu_pmu(event, &ctx->pinned_groups, cpu, pmu) {
+ __perf_tp_event_target_task(count, record, regs, data, event);
+ for_each_sibling_event(sibling, event)
+ __perf_tp_event_target_task(count, record, regs, data, sibling);
+ }
+
+ perf_event_groups_for_cpu_pmu(event, &ctx->flexible_groups, cpu, pmu) {
+ __perf_tp_event_target_task(count, record, regs, data, event);
+ for_each_sibling_event(sibling, event)
+ __perf_tp_event_target_task(count, record, regs, data, sibling);
+ }
+}
+
void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,
struct pt_regs *regs, struct hlist_head *head, int rctx,
struct task_struct *task)
@@ -9861,26 +10148,15 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,
*/
if (task && task != current) {
struct perf_event_context *ctx;
- struct trace_entry *entry = record;
rcu_read_lock();
- ctx = rcu_dereference(task->perf_event_ctxp[perf_sw_context]);
+ ctx = rcu_dereference(task->perf_event_ctxp);
if (!ctx)
goto unlock;
- list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
- if (event->cpu != smp_processor_id())
- continue;
- if (event->attr.type != PERF_TYPE_TRACEPOINT)
- continue;
- if (event->attr.config != entry->type)
- continue;
- /* Cannot deliver synchronous signal to other task. */
- if (event->attr.sigtrap)
- continue;
- if (perf_tp_event_match(event, &data, regs))
- perf_swevent_event(event, count, &data, regs);
- }
+ raw_spin_lock(&ctx->lock);
+ perf_tp_event_target_task(count, record, regs, &data, ctx);
+ raw_spin_unlock(&ctx->lock);
unlock:
rcu_read_unlock();
}
@@ -9889,44 +10165,6 @@ unlock:
}
EXPORT_SYMBOL_GPL(perf_tp_event);
-static void tp_perf_event_destroy(struct perf_event *event)
-{
- perf_trace_destroy(event);
-}
-
-static int perf_tp_event_init(struct perf_event *event)
-{
- int err;
-
- if (event->attr.type != PERF_TYPE_TRACEPOINT)
- return -ENOENT;
-
- /*
- * no branch sampling for tracepoint events
- */
- if (has_branch_stack(event))
- return -EOPNOTSUPP;
-
- err = perf_trace_init(event);
- if (err)
- return err;
-
- event->destroy = tp_perf_event_destroy;
-
- return 0;
-}
-
-static struct pmu perf_tracepoint = {
- .task_ctx_nr = perf_sw_context,
-
- .event_init = perf_tp_event_init,
- .add = perf_trace_add,
- .del = perf_trace_del,
- .start = perf_swevent_start,
- .stop = perf_swevent_stop,
- .read = perf_swevent_read,
-};
-
#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
/*
* Flags in config, used by dynamic PMU kprobe and uprobe
@@ -11013,36 +11251,9 @@ static int perf_event_idx_default(struct perf_event *event)
return 0;
}
-/*
- * Ensures all contexts with the same task_ctx_nr have the same
- * pmu_cpu_context too.
- */
-static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
-{
- struct pmu *pmu;
-
- if (ctxn < 0)
- return NULL;
-
- list_for_each_entry(pmu, &pmus, entry) {
- if (pmu->task_ctx_nr == ctxn)
- return pmu->pmu_cpu_context;
- }
-
- return NULL;
-}
-
static void free_pmu_context(struct pmu *pmu)
{
- /*
- * Static contexts such as perf_sw_context have a global lifetime
- * and may be shared between different PMUs. Avoid freeing them
- * when a single PMU is going away.
- */
- if (pmu->task_ctx_nr > perf_invalid_context)
- return;
-
- free_percpu(pmu->pmu_cpu_context);
+ free_percpu(pmu->cpu_pmu_context);
}
/*
@@ -11106,12 +11317,11 @@ perf_event_mux_interval_ms_store(struct device *dev,
/* update all cpuctx for this PMU */
cpus_read_lock();
for_each_online_cpu(cpu) {
- struct perf_cpu_context *cpuctx;
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
- cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer);
+ struct perf_cpu_pmu_context *cpc;
+ cpc = per_cpu_ptr(pmu->cpu_pmu_context, cpu);
+ cpc->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer);
- cpu_function_call(cpu,
- (remote_function_f)perf_mux_hrtimer_restart, cpuctx);
+ cpu_function_call(cpu, perf_mux_hrtimer_restart_ipi, cpc);
}
cpus_read_unlock();
mutex_unlock(&mux_interval_mutex);
@@ -11148,13 +11358,15 @@ static int pmu_dev_alloc(struct pmu *pmu)
pmu->dev->groups = pmu->attr_groups;
device_initialize(pmu->dev);
- ret = dev_set_name(pmu->dev, "%s", pmu->name);
- if (ret)
- goto free_dev;
dev_set_drvdata(pmu->dev, pmu);
pmu->dev->bus = &pmu_bus;
pmu->dev->release = pmu_dev_release;
+
+ ret = dev_set_name(pmu->dev, "%s", pmu->name);
+ if (ret)
+ goto free_dev;
+
ret = device_add(pmu->dev);
if (ret)
goto free_dev;
@@ -11222,47 +11434,19 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type)
}
skip_type:
- if (pmu->task_ctx_nr == perf_hw_context) {
- static int hw_context_taken = 0;
-
- /*
- * Other than systems with heterogeneous CPUs, it never makes
- * sense for two PMUs to share perf_hw_context. PMUs which are
- * uncore must use perf_invalid_context.
- */
- if (WARN_ON_ONCE(hw_context_taken &&
- !(pmu->capabilities & PERF_PMU_CAP_HETEROGENEOUS_CPUS)))
- pmu->task_ctx_nr = perf_invalid_context;
-
- hw_context_taken = 1;
- }
-
- pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);
- if (pmu->pmu_cpu_context)
- goto got_cpu_context;
-
ret = -ENOMEM;
- pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
- if (!pmu->pmu_cpu_context)
+ pmu->cpu_pmu_context = alloc_percpu(struct perf_cpu_pmu_context);
+ if (!pmu->cpu_pmu_context)
goto free_dev;
for_each_possible_cpu(cpu) {
- struct perf_cpu_context *cpuctx;
-
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
- __perf_event_init_context(&cpuctx->ctx);
- lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
- lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
- cpuctx->ctx.pmu = pmu;
- cpuctx->online = cpumask_test_cpu(cpu, perf_online_mask);
-
- __perf_mux_hrtimer_init(cpuctx, cpu);
+ struct perf_cpu_pmu_context *cpc;
- cpuctx->heap_size = ARRAY_SIZE(cpuctx->heap_default);
- cpuctx->heap = cpuctx->heap_default;
+ cpc = per_cpu_ptr(pmu->cpu_pmu_context, cpu);
+ __perf_init_event_pmu_context(&cpc->epc, pmu);
+ __perf_mux_hrtimer_init(cpc, cpu);
}
-got_cpu_context:
if (!pmu->start_txn) {
if (pmu->pmu_enable) {
/*
@@ -11741,10 +11925,11 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
}
/*
- * Disallow uncore-cgroup events, they don't make sense as the cgroup will
- * be different on other CPUs in the uncore mask.
+ * Disallow uncore-task events. Similarly, disallow uncore-cgroup
+ * events (they don't make sense as the cgroup will be different
+ * on other CPUs in the uncore mask).
*/
- if (pmu->task_ctx_nr == perf_invalid_context && cgroup_fd != -1) {
+ if (pmu->task_ctx_nr == perf_invalid_context && (task || cgroup_fd != -1)) {
err = -EINVAL;
goto err_pmu;
}
@@ -12091,37 +12276,6 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
return 0;
}
-/*
- * Variation on perf_event_ctx_lock_nested(), except we take two context
- * mutexes.
- */
-static struct perf_event_context *
-__perf_event_ctx_lock_double(struct perf_event *group_leader,
- struct perf_event_context *ctx)
-{
- struct perf_event_context *gctx;
-
-again:
- rcu_read_lock();
- gctx = READ_ONCE(group_leader->ctx);
- if (!refcount_inc_not_zero(&gctx->refcount)) {
- rcu_read_unlock();
- goto again;
- }
- rcu_read_unlock();
-
- mutex_lock_double(&gctx->mutex, &ctx->mutex);
-
- if (group_leader->ctx != gctx) {
- mutex_unlock(&ctx->mutex);
- mutex_unlock(&gctx->mutex);
- put_ctx(gctx);
- goto again;
- }
-
- return gctx;
-}
-
static bool
perf_check_permission(struct perf_event_attr *attr, struct task_struct *task)
{
@@ -12167,9 +12321,10 @@ SYSCALL_DEFINE5(perf_event_open,
pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
{
struct perf_event *group_leader = NULL, *output_event = NULL;
+ struct perf_event_pmu_context *pmu_ctx;
struct perf_event *event, *sibling;
struct perf_event_attr attr;
- struct perf_event_context *ctx, *gctx;
+ struct perf_event_context *ctx;
struct file *event_file = NULL;
struct fd group = {NULL, 0};
struct task_struct *task = NULL;
@@ -12299,42 +12454,53 @@ SYSCALL_DEFINE5(perf_event_open,
if (pmu->task_ctx_nr == perf_sw_context)
event->event_caps |= PERF_EV_CAP_SOFTWARE;
- if (group_leader) {
- if (is_software_event(event) &&
- !in_software_context(group_leader)) {
- /*
- * If the event is a sw event, but the group_leader
- * is on hw context.
- *
- * Allow the addition of software events to hw
- * groups, this is safe because software events
- * never fail to schedule.
- */
- pmu = group_leader->ctx->pmu;
- } else if (!is_software_event(event) &&
- is_software_event(group_leader) &&
- (group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
- /*
- * In case the group is a pure software group, and we
- * try to add a hardware event, move the whole group to
- * the hardware context.
- */
- move_group = 1;
- }
+ if (task) {
+ err = down_read_interruptible(&task->signal->exec_update_lock);
+ if (err)
+ goto err_alloc;
+
+ /*
+ * We must hold exec_update_lock across this and any potential
+ * perf_install_in_context() call for this new event to
+ * serialize against exec() altering our credentials (and the
+ * perf_event_exit_task() that could imply).
+ */
+ err = -EACCES;
+ if (!perf_check_permission(&attr, task))
+ goto err_cred;
}
/*
* Get the target context (task or percpu):
*/
- ctx = find_get_context(pmu, task, event);
+ ctx = find_get_context(task, event);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
- goto err_alloc;
+ goto err_cred;
+ }
+
+ mutex_lock(&ctx->mutex);
+
+ if (ctx->task == TASK_TOMBSTONE) {
+ err = -ESRCH;
+ goto err_locked;
+ }
+
+ if (!task) {
+ /*
+ * Check if the @cpu we're creating an event for is online.
+ *
+ * We use the perf_cpu_context::ctx::mutex to serialize against
+ * the hotplug notifiers. See perf_event_{init,exit}_cpu().
+ */
+ struct perf_cpu_context *cpuctx = per_cpu_ptr(&perf_cpu_context, event->cpu);
+
+ if (!cpuctx->online) {
+ err = -ENODEV;
+ goto err_locked;
+ }
}
- /*
- * Look up the group leader (we will attach this event to it):
- */
if (group_leader) {
err = -EINVAL;
@@ -12343,11 +12509,11 @@ SYSCALL_DEFINE5(perf_event_open,
* becoming part of another group-sibling):
*/
if (group_leader->group_leader != group_leader)
- goto err_context;
+ goto err_locked;
/* All events in a group should have the same clock */
if (group_leader->clock != event->clock)
- goto err_context;
+ goto err_locked;
/*
* Make sure we're both events for the same CPU;
@@ -12355,145 +12521,76 @@ SYSCALL_DEFINE5(perf_event_open,
* you can never concurrently schedule them anyhow.
*/
if (group_leader->cpu != event->cpu)
- goto err_context;
-
- /*
- * Make sure we're both on the same task, or both
- * per-CPU events.
- */
- if (group_leader->ctx->task != ctx->task)
- goto err_context;
+ goto err_locked;
/*
- * Do not allow to attach to a group in a different task
- * or CPU context. If we're moving SW events, we'll fix
- * this up later, so allow that.
- *
- * Racy, not holding group_leader->ctx->mutex, see comment with
- * perf_event_ctx_lock().
+ * Make sure we're both on the same context; either task or cpu.
*/
- if (!move_group && group_leader->ctx != ctx)
- goto err_context;
+ if (group_leader->ctx != ctx)
+ goto err_locked;
/*
* Only a group leader can be exclusive or pinned
*/
if (attr.exclusive || attr.pinned)
- goto err_context;
- }
-
- if (output_event) {
- err = perf_event_set_output(event, output_event);
- if (err)
- goto err_context;
- }
-
- event_file = anon_inode_getfile("[perf_event]", &perf_fops, event,
- f_flags);
- if (IS_ERR(event_file)) {
- err = PTR_ERR(event_file);
- event_file = NULL;
- goto err_context;
- }
-
- if (task) {
- err = down_read_interruptible(&task->signal->exec_update_lock);
- if (err)
- goto err_file;
-
- /*
- * We must hold exec_update_lock across this and any potential
- * perf_install_in_context() call for this new event to
- * serialize against exec() altering our credentials (and the
- * perf_event_exit_task() that could imply).
- */
- err = -EACCES;
- if (!perf_check_permission(&attr, task))
- goto err_cred;
- }
-
- if (move_group) {
- gctx = __perf_event_ctx_lock_double(group_leader, ctx);
-
- if (gctx->task == TASK_TOMBSTONE) {
- err = -ESRCH;
goto err_locked;
- }
- /*
- * Check if we raced against another sys_perf_event_open() call
- * moving the software group underneath us.
- */
- if (!(group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
+ if (is_software_event(event) &&
+ !in_software_context(group_leader)) {
/*
- * If someone moved the group out from under us, check
- * if this new event wound up on the same ctx, if so
- * its the regular !move_group case, otherwise fail.
+ * If the event is a sw event, but the group_leader
+ * is on hw context.
+ *
+ * Allow the addition of software events to hw
+ * groups, this is safe because software events
+ * never fail to schedule.
+ *
+ * Note the comment that goes with struct
+ * perf_event_pmu_context.
*/
- if (gctx != ctx) {
- err = -EINVAL;
- goto err_locked;
- } else {
- perf_event_ctx_unlock(group_leader, gctx);
- move_group = 0;
- goto not_move_group;
+ pmu = group_leader->pmu_ctx->pmu;
+ } else if (!is_software_event(event)) {
+ if (is_software_event(group_leader) &&
+ (group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
+ /*
+ * In case the group is a pure software group, and we
+ * try to add a hardware event, move the whole group to
+ * the hardware context.
+ */
+ move_group = 1;
}
- }
-
- /*
- * Failure to create exclusive events returns -EBUSY.
- */
- err = -EBUSY;
- if (!exclusive_event_installable(group_leader, ctx))
- goto err_locked;
- for_each_sibling_event(sibling, group_leader) {
- if (!exclusive_event_installable(sibling, ctx))
+ /* Don't allow group of multiple hw events from different pmus */
+ if (!in_software_context(group_leader) &&
+ group_leader->pmu_ctx->pmu != pmu)
goto err_locked;
}
- } else {
- mutex_lock(&ctx->mutex);
-
- /*
- * Now that we hold ctx->lock, (re)validate group_leader->ctx == ctx,
- * see the group_leader && !move_group test earlier.
- */
- if (group_leader && group_leader->ctx != ctx) {
- err = -EINVAL;
- goto err_locked;
- }
}
-not_move_group:
- if (ctx->task == TASK_TOMBSTONE) {
- err = -ESRCH;
+ /*
+ * Now that we're certain of the pmu; find the pmu_ctx.
+ */
+ pmu_ctx = find_get_pmu_context(pmu, ctx, event);
+ if (IS_ERR(pmu_ctx)) {
+ err = PTR_ERR(pmu_ctx);
goto err_locked;
}
+ event->pmu_ctx = pmu_ctx;
- if (!perf_event_validate_size(event)) {
- err = -E2BIG;
- goto err_locked;
+ if (output_event) {
+ err = perf_event_set_output(event, output_event);
+ if (err)
+ goto err_context;
}
- if (!task) {
- /*
- * Check if the @cpu we're creating an event for is online.
- *
- * We use the perf_cpu_context::ctx::mutex to serialize against
- * the hotplug notifiers. See perf_event_{init,exit}_cpu().
- */
- struct perf_cpu_context *cpuctx =
- container_of(ctx, struct perf_cpu_context, ctx);
-
- if (!cpuctx->online) {
- err = -ENODEV;
- goto err_locked;
- }
+ if (!perf_event_validate_size(event)) {
+ err = -E2BIG;
+ goto err_context;
}
if (perf_need_aux_event(event) && !perf_get_aux_event(event, group_leader)) {
err = -EINVAL;
- goto err_locked;
+ goto err_context;
}
/*
@@ -12502,36 +12599,33 @@ not_move_group:
*/
if (!exclusive_event_installable(event, ctx)) {
err = -EBUSY;
- goto err_locked;
+ goto err_context;
}
WARN_ON_ONCE(ctx->parent_ctx);
+ event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, f_flags);
+ if (IS_ERR(event_file)) {
+ err = PTR_ERR(event_file);
+ event_file = NULL;
+ goto err_context;
+ }
+
/*
* This is the point on no return; we cannot fail hereafter. This is
* where we start modifying current state.
*/
if (move_group) {
- /*
- * See perf_event_ctx_lock() for comments on the details
- * of swizzling perf_event::ctx.
- */
perf_remove_from_context(group_leader, 0);
- put_ctx(gctx);
+ put_pmu_ctx(group_leader->pmu_ctx);
for_each_sibling_event(sibling, group_leader) {
perf_remove_from_context(sibling, 0);
- put_ctx(gctx);
+ put_pmu_ctx(sibling->pmu_ctx);
}
/*
- * Wait for everybody to stop referencing the events through
- * the old lists, before installing it on new lists.
- */
- synchronize_rcu();
-
- /*
* Install the group siblings before the group leader.
*
* Because a group leader will try and install the entire group
@@ -12542,9 +12636,10 @@ not_move_group:
* reachable through the group lists.
*/
for_each_sibling_event(sibling, group_leader) {
+ sibling->pmu_ctx = pmu_ctx;
+ get_pmu_ctx(pmu_ctx);
perf_event__state_init(sibling);
perf_install_in_context(ctx, sibling, sibling->cpu);
- get_ctx(ctx);
}
/*
@@ -12552,9 +12647,10 @@ not_move_group:
* event. What we want here is event in the initial
* startup state, ready to be add into new context.
*/
+ group_leader->pmu_ctx = pmu_ctx;
+ get_pmu_ctx(pmu_ctx);
perf_event__state_init(group_leader);
perf_install_in_context(ctx, group_leader, group_leader->cpu);
- get_ctx(ctx);
}
/*
@@ -12571,8 +12667,6 @@ not_move_group:
perf_install_in_context(ctx, event, event->cpu);
perf_unpin_context(ctx);
- if (move_group)
- perf_event_ctx_unlock(group_leader, gctx);
mutex_unlock(&ctx->mutex);
if (task) {
@@ -12594,25 +12688,17 @@ not_move_group:
fd_install(event_fd, event_file);
return event_fd;
+err_context:
+ /* event->pmu_ctx freed by free_event() */
err_locked:
- if (move_group)
- perf_event_ctx_unlock(group_leader, gctx);
mutex_unlock(&ctx->mutex);
+ perf_unpin_context(ctx);
+ put_ctx(ctx);
err_cred:
if (task)
up_read(&task->signal->exec_update_lock);
-err_file:
- fput(event_file);
-err_context:
- perf_unpin_context(ctx);
- put_ctx(ctx);
err_alloc:
- /*
- * If event_file is set, the fput() above will have called ->release()
- * and that will take care of freeing the event.
- */
- if (!event_file)
- free_event(event);
+ free_event(event);
err_task:
if (task)
put_task_struct(task);
@@ -12638,8 +12724,10 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
perf_overflow_handler_t overflow_handler,
void *context)
{
+ struct perf_event_pmu_context *pmu_ctx;
struct perf_event_context *ctx;
struct perf_event *event;
+ struct pmu *pmu;
int err;
/*
@@ -12658,14 +12746,18 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
/* Mark owner so we could distinguish it from user events. */
event->owner = TASK_TOMBSTONE;
+ pmu = event->pmu;
+
+ if (pmu->task_ctx_nr == perf_sw_context)
+ event->event_caps |= PERF_EV_CAP_SOFTWARE;
/*
* Get the target context (task or percpu):
*/
- ctx = find_get_context(event->pmu, task, event);
+ ctx = find_get_context(task, event);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
- goto err_free;
+ goto err_alloc;
}
WARN_ON_ONCE(ctx->parent_ctx);
@@ -12675,6 +12767,13 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
goto err_unlock;
}
+ pmu_ctx = find_get_pmu_context(pmu, ctx, event);
+ if (IS_ERR(pmu_ctx)) {
+ err = PTR_ERR(pmu_ctx);
+ goto err_unlock;
+ }
+ event->pmu_ctx = pmu_ctx;
+
if (!task) {
/*
* Check if the @cpu we're creating an event for is online.
@@ -12686,13 +12785,13 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
container_of(ctx, struct perf_cpu_context, ctx);
if (!cpuctx->online) {
err = -ENODEV;
- goto err_unlock;
+ goto err_pmu_ctx;
}
}
if (!exclusive_event_installable(event, ctx)) {
err = -EBUSY;
- goto err_unlock;
+ goto err_pmu_ctx;
}
perf_install_in_context(ctx, event, event->cpu);
@@ -12701,44 +12800,61 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
return event;
+err_pmu_ctx:
+ put_pmu_ctx(pmu_ctx);
err_unlock:
mutex_unlock(&ctx->mutex);
perf_unpin_context(ctx);
put_ctx(ctx);
-err_free:
+err_alloc:
free_event(event);
err:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
-void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
+static void __perf_pmu_remove(struct perf_event_context *ctx,
+ int cpu, struct pmu *pmu,
+ struct perf_event_groups *groups,
+ struct list_head *events)
{
- struct perf_event_context *src_ctx;
- struct perf_event_context *dst_ctx;
- struct perf_event *event, *tmp;
- LIST_HEAD(events);
-
- src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx;
- dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx;
+ struct perf_event *event, *sibling;
- /*
- * See perf_event_ctx_lock() for comments on the details
- * of swizzling perf_event::ctx.
- */
- mutex_lock_double(&src_ctx->mutex, &dst_ctx->mutex);
- list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
- event_entry) {
+ perf_event_groups_for_cpu_pmu(event, groups, cpu, pmu) {
perf_remove_from_context(event, 0);
- unaccount_event_cpu(event, src_cpu);
- put_ctx(src_ctx);
- list_add(&event->migrate_entry, &events);
+ unaccount_event_cpu(event, cpu);
+ put_pmu_ctx(event->pmu_ctx);
+ list_add(&event->migrate_entry, events);
+
+ for_each_sibling_event(sibling, event) {
+ perf_remove_from_context(sibling, 0);
+ unaccount_event_cpu(sibling, cpu);
+ put_pmu_ctx(sibling->pmu_ctx);
+ list_add(&sibling->migrate_entry, events);
+ }
}
+}
- /*
- * Wait for the events to quiesce before re-instating them.
- */
- synchronize_rcu();
+static void __perf_pmu_install_event(struct pmu *pmu,
+ struct perf_event_context *ctx,
+ int cpu, struct perf_event *event)
+{
+ struct perf_event_pmu_context *epc;
+
+ event->cpu = cpu;
+ epc = find_get_pmu_context(pmu, ctx, event);
+ event->pmu_ctx = epc;
+
+ if (event->state >= PERF_EVENT_STATE_OFF)
+ event->state = PERF_EVENT_STATE_INACTIVE;
+ account_event_cpu(event, cpu);
+ perf_install_in_context(ctx, event, cpu);
+}
+
+static void __perf_pmu_install(struct perf_event_context *ctx,
+ int cpu, struct pmu *pmu, struct list_head *events)
+{
+ struct perf_event *event, *tmp;
/*
* Re-instate events in 2 passes.
@@ -12748,30 +12864,48 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
* leader will enable its siblings, even if those are still on the old
* context.
*/
- list_for_each_entry_safe(event, tmp, &events, migrate_entry) {
+ list_for_each_entry_safe(event, tmp, events, migrate_entry) {
if (event->group_leader == event)
continue;
list_del(&event->migrate_entry);
- if (event->state >= PERF_EVENT_STATE_OFF)
- event->state = PERF_EVENT_STATE_INACTIVE;
- account_event_cpu(event, dst_cpu);
- perf_install_in_context(dst_ctx, event, dst_cpu);
- get_ctx(dst_ctx);
+ __perf_pmu_install_event(pmu, ctx, cpu, event);
}
/*
* Once all the siblings are setup properly, install the group leaders
* to make it go.
*/
- list_for_each_entry_safe(event, tmp, &events, migrate_entry) {
+ list_for_each_entry_safe(event, tmp, events, migrate_entry) {
list_del(&event->migrate_entry);
- if (event->state >= PERF_EVENT_STATE_OFF)
- event->state = PERF_EVENT_STATE_INACTIVE;
- account_event_cpu(event, dst_cpu);
- perf_install_in_context(dst_ctx, event, dst_cpu);
- get_ctx(dst_ctx);
+ __perf_pmu_install_event(pmu, ctx, cpu, event);
}
+}
+
+void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
+{
+ struct perf_event_context *src_ctx, *dst_ctx;
+ LIST_HEAD(events);
+
+ src_ctx = &per_cpu_ptr(&perf_cpu_context, src_cpu)->ctx;
+ dst_ctx = &per_cpu_ptr(&perf_cpu_context, dst_cpu)->ctx;
+
+ /*
+ * See perf_event_ctx_lock() for comments on the details
+ * of swizzling perf_event::ctx.
+ */
+ mutex_lock_double(&src_ctx->mutex, &dst_ctx->mutex);
+
+ __perf_pmu_remove(src_ctx, src_cpu, pmu, &src_ctx->pinned_groups, &events);
+ __perf_pmu_remove(src_ctx, src_cpu, pmu, &src_ctx->flexible_groups, &events);
+
+ /*
+ * Wait for the events to quiesce before re-instating them.
+ */
+ synchronize_rcu();
+
+ __perf_pmu_install(dst_ctx, dst_cpu, pmu, &events);
+
mutex_unlock(&dst_ctx->mutex);
mutex_unlock(&src_ctx->mutex);
}
@@ -12851,14 +12985,14 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
perf_event_wakeup(event);
}
-static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
+static void perf_event_exit_task_context(struct task_struct *child)
{
struct perf_event_context *child_ctx, *clone_ctx = NULL;
struct perf_event *child_event, *next;
WARN_ON_ONCE(child != current);
- child_ctx = perf_pin_task_context(child, ctxn);
+ child_ctx = perf_pin_task_context(child);
if (!child_ctx)
return;
@@ -12880,13 +13014,13 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
* in.
*/
raw_spin_lock_irq(&child_ctx->lock);
- task_ctx_sched_out(__get_cpu_context(child_ctx), child_ctx, EVENT_ALL);
+ task_ctx_sched_out(child_ctx, EVENT_ALL);
/*
* Now that the context is inactive, destroy the task <-> ctx relation
* and mark the context dead.
*/
- RCU_INIT_POINTER(child->perf_event_ctxp[ctxn], NULL);
+ RCU_INIT_POINTER(child->perf_event_ctxp, NULL);
put_ctx(child_ctx); /* cannot be last */
WRITE_ONCE(child_ctx->task, TASK_TOMBSTONE);
put_task_struct(current); /* cannot be last */
@@ -12921,7 +13055,6 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
void perf_event_exit_task(struct task_struct *child)
{
struct perf_event *event, *tmp;
- int ctxn;
mutex_lock(&child->perf_event_mutex);
list_for_each_entry_safe(event, tmp, &child->perf_event_list,
@@ -12937,8 +13070,7 @@ void perf_event_exit_task(struct task_struct *child)
}
mutex_unlock(&child->perf_event_mutex);
- for_each_task_context_nr(ctxn)
- perf_event_exit_task_context(child, ctxn);
+ perf_event_exit_task_context(child);
/*
* The perf_event_exit_task_context calls perf_event_task
@@ -12981,56 +13113,51 @@ void perf_event_free_task(struct task_struct *task)
{
struct perf_event_context *ctx;
struct perf_event *event, *tmp;
- int ctxn;
- for_each_task_context_nr(ctxn) {
- ctx = task->perf_event_ctxp[ctxn];
- if (!ctx)
- continue;
+ ctx = rcu_access_pointer(task->perf_event_ctxp);
+ if (!ctx)
+ return;
- mutex_lock(&ctx->mutex);
- raw_spin_lock_irq(&ctx->lock);
- /*
- * Destroy the task <-> ctx relation and mark the context dead.
- *
- * This is important because even though the task hasn't been
- * exposed yet the context has been (through child_list).
- */
- RCU_INIT_POINTER(task->perf_event_ctxp[ctxn], NULL);
- WRITE_ONCE(ctx->task, TASK_TOMBSTONE);
- put_task_struct(task); /* cannot be last */
- raw_spin_unlock_irq(&ctx->lock);
+ mutex_lock(&ctx->mutex);
+ raw_spin_lock_irq(&ctx->lock);
+ /*
+ * Destroy the task <-> ctx relation and mark the context dead.
+ *
+ * This is important because even though the task hasn't been
+ * exposed yet the context has been (through child_list).
+ */
+ RCU_INIT_POINTER(task->perf_event_ctxp, NULL);
+ WRITE_ONCE(ctx->task, TASK_TOMBSTONE);
+ put_task_struct(task); /* cannot be last */
+ raw_spin_unlock_irq(&ctx->lock);
- list_for_each_entry_safe(event, tmp, &ctx->event_list, event_entry)
- perf_free_event(event, ctx);
- mutex_unlock(&ctx->mutex);
+ list_for_each_entry_safe(event, tmp, &ctx->event_list, event_entry)
+ perf_free_event(event, ctx);
- /*
- * perf_event_release_kernel() could've stolen some of our
- * child events and still have them on its free_list. In that
- * case we must wait for these events to have been freed (in
- * particular all their references to this task must've been
- * dropped).
- *
- * Without this copy_process() will unconditionally free this
- * task (irrespective of its reference count) and
- * _free_event()'s put_task_struct(event->hw.target) will be a
- * use-after-free.
- *
- * Wait for all events to drop their context reference.
- */
- wait_var_event(&ctx->refcount, refcount_read(&ctx->refcount) == 1);
- put_ctx(ctx); /* must be last */
- }
+ mutex_unlock(&ctx->mutex);
+
+ /*
+ * perf_event_release_kernel() could've stolen some of our
+ * child events and still have them on its free_list. In that
+ * case we must wait for these events to have been freed (in
+ * particular all their references to this task must've been
+ * dropped).
+ *
+ * Without this copy_process() will unconditionally free this
+ * task (irrespective of its reference count) and
+ * _free_event()'s put_task_struct(event->hw.target) will be a
+ * use-after-free.
+ *
+ * Wait for all events to drop their context reference.
+ */
+ wait_var_event(&ctx->refcount, refcount_read(&ctx->refcount) == 1);
+ put_ctx(ctx); /* must be last */
}
void perf_event_delayed_put(struct task_struct *task)
{
- int ctxn;
-
- for_each_task_context_nr(ctxn)
- WARN_ON_ONCE(task->perf_event_ctxp[ctxn]);
+ WARN_ON_ONCE(task->perf_event_ctxp);
}
struct file *perf_event_get(unsigned int fd)
@@ -13080,6 +13207,7 @@ inherit_event(struct perf_event *parent_event,
struct perf_event_context *child_ctx)
{
enum perf_event_state parent_state = parent_event->state;
+ struct perf_event_pmu_context *pmu_ctx;
struct perf_event *child_event;
unsigned long flags;
@@ -13100,17 +13228,12 @@ inherit_event(struct perf_event *parent_event,
if (IS_ERR(child_event))
return child_event;
-
- if ((child_event->attach_state & PERF_ATTACH_TASK_DATA) &&
- !child_ctx->task_ctx_data) {
- struct pmu *pmu = child_event->pmu;
-
- child_ctx->task_ctx_data = alloc_task_ctx_data(pmu);
- if (!child_ctx->task_ctx_data) {
- free_event(child_event);
- return ERR_PTR(-ENOMEM);
- }
+ pmu_ctx = find_get_pmu_context(child_event->pmu, child_ctx, child_event);
+ if (IS_ERR(pmu_ctx)) {
+ free_event(child_event);
+ return NULL;
}
+ child_event->pmu_ctx = pmu_ctx;
/*
* is_orphaned_event() and list_add_tail(&parent_event->child_list)
@@ -13233,11 +13356,11 @@ static int inherit_group(struct perf_event *parent_event,
static int
inherit_task_group(struct perf_event *event, struct task_struct *parent,
struct perf_event_context *parent_ctx,
- struct task_struct *child, int ctxn,
+ struct task_struct *child,
u64 clone_flags, int *inherited_all)
{
- int ret;
struct perf_event_context *child_ctx;
+ int ret;
if (!event->attr.inherit ||
(event->attr.inherit_thread && !(clone_flags & CLONE_THREAD)) ||
@@ -13247,7 +13370,7 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
return 0;
}
- child_ctx = child->perf_event_ctxp[ctxn];
+ child_ctx = child->perf_event_ctxp;
if (!child_ctx) {
/*
* This is executed from the parent task context, so
@@ -13255,16 +13378,14 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
* First allocate and initialize a context for the
* child.
*/
- child_ctx = alloc_perf_context(parent_ctx->pmu, child);
+ child_ctx = alloc_perf_context(child);
if (!child_ctx)
return -ENOMEM;
- child->perf_event_ctxp[ctxn] = child_ctx;
+ child->perf_event_ctxp = child_ctx;
}
- ret = inherit_group(event, parent, parent_ctx,
- child, child_ctx);
-
+ ret = inherit_group(event, parent, parent_ctx, child, child_ctx);
if (ret)
*inherited_all = 0;
@@ -13274,8 +13395,7 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
/*
* Initialize the perf_event context in task_struct
*/
-static int perf_event_init_context(struct task_struct *child, int ctxn,
- u64 clone_flags)
+static int perf_event_init_context(struct task_struct *child, u64 clone_flags)
{
struct perf_event_context *child_ctx, *parent_ctx;
struct perf_event_context *cloned_ctx;
@@ -13285,14 +13405,14 @@ static int perf_event_init_context(struct task_struct *child, int ctxn,
unsigned long flags;
int ret = 0;
- if (likely(!parent->perf_event_ctxp[ctxn]))
+ if (likely(!parent->perf_event_ctxp))
return 0;
/*
* If the parent's context is a clone, pin it so it won't get
* swapped under us.
*/
- parent_ctx = perf_pin_task_context(parent, ctxn);
+ parent_ctx = perf_pin_task_context(parent);
if (!parent_ctx)
return 0;
@@ -13315,8 +13435,7 @@ static int perf_event_init_context(struct task_struct *child, int ctxn,
*/
perf_event_groups_for_each(event, &parent_ctx->pinned_groups) {
ret = inherit_task_group(event, parent, parent_ctx,
- child, ctxn, clone_flags,
- &inherited_all);
+ child, clone_flags, &inherited_all);
if (ret)
goto out_unlock;
}
@@ -13332,8 +13451,7 @@ static int perf_event_init_context(struct task_struct *child, int ctxn,
perf_event_groups_for_each(event, &parent_ctx->flexible_groups) {
ret = inherit_task_group(event, parent, parent_ctx,
- child, ctxn, clone_flags,
- &inherited_all);
+ child, clone_flags, &inherited_all);
if (ret)
goto out_unlock;
}
@@ -13341,7 +13459,7 @@ static int perf_event_init_context(struct task_struct *child, int ctxn,
raw_spin_lock_irqsave(&parent_ctx->lock, flags);
parent_ctx->rotate_disable = 0;
- child_ctx = child->perf_event_ctxp[ctxn];
+ child_ctx = child->perf_event_ctxp;
if (child_ctx && inherited_all) {
/*
@@ -13377,18 +13495,16 @@ out_unlock:
*/
int perf_event_init_task(struct task_struct *child, u64 clone_flags)
{
- int ctxn, ret;
+ int ret;
- memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp));
+ child->perf_event_ctxp = NULL;
mutex_init(&child->perf_event_mutex);
INIT_LIST_HEAD(&child->perf_event_list);
- for_each_task_context_nr(ctxn) {
- ret = perf_event_init_context(child, ctxn, clone_flags);
- if (ret) {
- perf_event_free_task(child);
- return ret;
- }
+ ret = perf_event_init_context(child, clone_flags);
+ if (ret) {
+ perf_event_free_task(child);
+ return ret;
}
return 0;
@@ -13397,6 +13513,7 @@ int perf_event_init_task(struct task_struct *child, u64 clone_flags)
static void __init perf_event_init_all_cpus(void)
{
struct swevent_htable *swhash;
+ struct perf_cpu_context *cpuctx;
int cpu;
zalloc_cpumask_var(&perf_online_mask, GFP_KERNEL);
@@ -13404,15 +13521,19 @@ static void __init perf_event_init_all_cpus(void)
for_each_possible_cpu(cpu) {
swhash = &per_cpu(swevent_htable, cpu);
mutex_init(&swhash->hlist_mutex);
- INIT_LIST_HEAD(&per_cpu(active_ctx_list, cpu));
INIT_LIST_HEAD(&per_cpu(pmu_sb_events.list, cpu));
raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu));
-#ifdef CONFIG_CGROUP_PERF
- INIT_LIST_HEAD(&per_cpu(cgrp_cpuctx_list, cpu));
-#endif
INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
+
+ cpuctx = per_cpu_ptr(&perf_cpu_context, cpu);
+ __perf_event_init_context(&cpuctx->ctx);
+ lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
+ lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
+ cpuctx->online = cpumask_test_cpu(cpu, perf_online_mask);
+ cpuctx->heap_size = ARRAY_SIZE(cpuctx->heap_default);
+ cpuctx->heap = cpuctx->heap_default;
}
}
@@ -13434,12 +13555,12 @@ static void perf_swevent_init_cpu(unsigned int cpu)
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
static void __perf_event_exit_context(void *__info)
{
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
struct perf_event *event;
raw_spin_lock(&ctx->lock);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+ ctx_sched_out(ctx, EVENT_TIME);
list_for_each_entry(event, &ctx->event_list, event_entry)
__perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
raw_spin_unlock(&ctx->lock);
@@ -13449,18 +13570,16 @@ static void perf_event_exit_cpu_context(int cpu)
{
struct perf_cpu_context *cpuctx;
struct perf_event_context *ctx;
- struct pmu *pmu;
+ // XXX simplify cpuctx->online
mutex_lock(&pmus_lock);
- list_for_each_entry(pmu, &pmus, entry) {
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
- ctx = &cpuctx->ctx;
+ cpuctx = per_cpu_ptr(&perf_cpu_context, cpu);
+ ctx = &cpuctx->ctx;
- mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
- cpuctx->online = 0;
- mutex_unlock(&ctx->mutex);
- }
+ mutex_lock(&ctx->mutex);
+ smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ cpuctx->online = 0;
+ mutex_unlock(&ctx->mutex);
cpumask_clear_cpu(cpu, perf_online_mask);
mutex_unlock(&pmus_lock);
}
@@ -13474,20 +13593,17 @@ int perf_event_init_cpu(unsigned int cpu)
{
struct perf_cpu_context *cpuctx;
struct perf_event_context *ctx;
- struct pmu *pmu;
perf_swevent_init_cpu(cpu);
mutex_lock(&pmus_lock);
cpumask_set_cpu(cpu, perf_online_mask);
- list_for_each_entry(pmu, &pmus, entry) {
- cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
- ctx = &cpuctx->ctx;
+ cpuctx = per_cpu_ptr(&perf_cpu_context, cpu);
+ ctx = &cpuctx->ctx;
- mutex_lock(&ctx->mutex);
- cpuctx->online = 1;
- mutex_unlock(&ctx->mutex);
- }
+ mutex_lock(&ctx->mutex);
+ cpuctx->online = 1;
+ mutex_unlock(&ctx->mutex);
mutex_unlock(&pmus_lock);
return 0;
@@ -13624,9 +13740,12 @@ static int perf_cgroup_css_online(struct cgroup_subsys_state *css)
static int __perf_cgroup_move(void *info)
{
struct task_struct *task = info;
- rcu_read_lock();
- perf_cgroup_switch(task);
- rcu_read_unlock();
+
+ preempt_disable();
+ if (atomic_read(this_cpu_ptr(&perf_cgroup_events)))
+ perf_cgroup_switch(task);
+ preempt_enable();
+
return 0;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 08969f5aa38d..89b8b6c08592 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -75,7 +75,6 @@
#include <linux/freezer.h>
#include <linux/delayacct.h>
#include <linux/taskstats_kern.h>
-#include <linux/random.h>
#include <linux/tty.h>
#include <linux/fs_struct.h>
#include <linux/magic.h>
@@ -97,6 +96,7 @@
#include <linux/scs.h>
#include <linux/io_uring.h>
#include <linux/bpf.h>
+#include <linux/stackprotector.h>
#include <asm/pgalloc.h>
#include <linux/uaccess.h>
@@ -535,6 +535,9 @@ void put_task_stack(struct task_struct *tsk)
void free_task(struct task_struct *tsk)
{
+#ifdef CONFIG_SECCOMP
+ WARN_ON_ONCE(tsk->seccomp.filter);
+#endif
release_user_cpus_ptr(tsk);
scs_release(tsk);
@@ -2043,15 +2046,6 @@ static __latent_entropy struct task_struct *copy_process(
return ERR_PTR(-EINVAL);
}
- /*
- * If the new process will be in a different time namespace
- * do not allow it to share VM or a thread group with the forking task.
- */
- if (clone_flags & (CLONE_THREAD | CLONE_VM)) {
- if (nsp->time_ns != nsp->time_ns_for_children)
- return ERR_PTR(-EINVAL);
- }
-
if (clone_flags & CLONE_PIDFD) {
/*
* - CLONE_DETACHED is blocked so that we can potentially
@@ -2406,12 +2400,6 @@ static __latent_entropy struct task_struct *copy_process(
spin_lock(&current->sighand->siglock);
- /*
- * Copy seccomp details explicitly here, in case they were changed
- * before holding sighand lock.
- */
- copy_seccomp(p);
-
rv_task_fork(p);
rseq_fork(p, clone_flags);
@@ -2428,6 +2416,14 @@ static __latent_entropy struct task_struct *copy_process(
goto bad_fork_cancel_cgroup;
}
+ /* No more failure paths after this point. */
+
+ /*
+ * Copy seccomp details explicitly here, in case they were changed
+ * before holding sighand lock.
+ */
+ copy_seccomp(p);
+
init_task_pid_links(p);
if (likely(p->pid)) {
ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index b22ef1efe751..514e4582b863 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -638,6 +638,7 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
bool pi, bool pending_op)
{
u32 uval, nval, mval;
+ pid_t owner;
int err;
/* Futex address must be 32bit aligned */
@@ -659,6 +660,10 @@ retry:
* 2. A woken up waiter is killed before it can acquire the
* futex in user space.
*
+ * In the second case, the wake up notification could be generated
+ * by the unlock path in user space after setting the futex value
+ * to zero or by the kernel after setting the OWNER_DIED bit below.
+ *
* In both cases the TID validation below prevents a wakeup of
* potential waiters which can cause these waiters to block
* forever.
@@ -667,24 +672,27 @@ retry:
*
* 1) task->robust_list->list_op_pending != NULL
* @pending_op == true
- * 2) User space futex value == 0
+ * 2) The owner part of user space futex value == 0
* 3) Regular futex: @pi == false
*
* If these conditions are met, it is safe to attempt waking up a
* potential waiter without touching the user space futex value and
- * trying to set the OWNER_DIED bit. The user space futex value is
- * uncontended and the rest of the user space mutex state is
- * consistent, so a woken waiter will just take over the
- * uncontended futex. Setting the OWNER_DIED bit would create
- * inconsistent state and malfunction of the user space owner died
- * handling.
+ * trying to set the OWNER_DIED bit. If the futex value is zero,
+ * the rest of the user space mutex state is consistent, so a woken
+ * waiter will just take over the uncontended futex. Setting the
+ * OWNER_DIED bit would create inconsistent state and malfunction
+ * of the user space owner died handling. Otherwise, the OWNER_DIED
+ * bit is already set, and the woken waiter is expected to deal with
+ * this.
*/
- if (pending_op && !pi && !uval) {
+ owner = uval & FUTEX_TID_MASK;
+
+ if (pending_op && !pi && !owner) {
futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
return 0;
}
- if ((uval & FUTEX_TID_MASK) != task_pid_vnr(curr))
+ if (owner != task_pid_vnr(curr))
return 0;
/*
diff --git a/kernel/gcov/clang.c b/kernel/gcov/clang.c
index cbb0bed958ab..7670a811a565 100644
--- a/kernel/gcov/clang.c
+++ b/kernel/gcov/clang.c
@@ -280,6 +280,8 @@ void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
for (i = 0; i < sfn_ptr->num_counters; i++)
dfn_ptr->counters[i] += sfn_ptr->counters[i];
+
+ sfn_ptr = list_next_entry(sfn_ptr, head);
}
}
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index db3d174c53d4..b64c44ae4c25 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -86,15 +86,10 @@ config GENERIC_IRQ_IPI
depends on SMP
select IRQ_DOMAIN_HIERARCHY
-# Generic MSI interrupt support
-config GENERIC_MSI_IRQ
- bool
-
# Generic MSI hierarchical interrupt domain support
-config GENERIC_MSI_IRQ_DOMAIN
+config GENERIC_MSI_IRQ
bool
select IRQ_DOMAIN_HIERARCHY
- select GENERIC_MSI_IRQ
config IRQ_MSI_IOMMU
bool
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 8ac37e8e738a..49e7bc871fec 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1561,10 +1561,10 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
return 0;
}
-static struct device *irq_get_parent_device(struct irq_data *data)
+static struct device *irq_get_pm_device(struct irq_data *data)
{
if (data->domain)
- return data->domain->dev;
+ return data->domain->pm_dev;
return NULL;
}
@@ -1578,7 +1578,7 @@ static struct device *irq_get_parent_device(struct irq_data *data)
*/
int irq_chip_pm_get(struct irq_data *data)
{
- struct device *dev = irq_get_parent_device(data);
+ struct device *dev = irq_get_pm_device(data);
int retval = 0;
if (IS_ENABLED(CONFIG_PM) && dev)
@@ -1597,7 +1597,7 @@ int irq_chip_pm_get(struct irq_data *data)
*/
int irq_chip_pm_put(struct irq_data *data)
{
- struct device *dev = irq_get_parent_device(data);
+ struct device *dev = irq_get_pm_device(data);
int retval = 0;
if (IS_ENABLED(CONFIG_PM) && dev)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index f09c60393e55..5fdc0b557579 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -52,6 +52,7 @@ enum {
* IRQS_PENDING - irq is pending and replayed later
* IRQS_SUSPENDED - irq is suspended
* IRQS_NMI - irq line is used to deliver NMIs
+ * IRQS_SYSFS - descriptor has been added to sysfs
*/
enum {
IRQS_AUTODETECT = 0x00000001,
@@ -64,6 +65,7 @@ enum {
IRQS_SUSPENDED = 0x00000800,
IRQS_TIMINGS = 0x00001000,
IRQS_NMI = 0x00002000,
+ IRQS_SYSFS = 0x00004000,
};
#include "debug.h"
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index a91f9001103c..fd0996274401 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -288,22 +288,25 @@ static void irq_sysfs_add(int irq, struct irq_desc *desc)
if (irq_kobj_base) {
/*
* Continue even in case of failure as this is nothing
- * crucial.
+ * crucial and failures in the late irq_sysfs_init()
+ * cannot be rolled back.
*/
if (kobject_add(&desc->kobj, irq_kobj_base, "%d", irq))
pr_warn("Failed to add kobject for irq %d\n", irq);
+ else
+ desc->istate |= IRQS_SYSFS;
}
}
static void irq_sysfs_del(struct irq_desc *desc)
{
/*
- * If irq_sysfs_init() has not yet been invoked (early boot), then
- * irq_kobj_base is NULL and the descriptor was never added.
- * kobject_del() complains about a object with no parent, so make
- * it conditional.
+ * Only invoke kobject_del() when kobject_add() was successfully
+ * invoked for the descriptor. This covers both early boot, where
+ * sysfs is not initialized yet, and the case of a failed
+ * kobject_add() invocation.
*/
- if (irq_kobj_base)
+ if (desc->istate & IRQS_SYSFS)
kobject_del(&desc->kobj);
}
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 40fe7806cc8c..5b7cf28df290 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -321,7 +321,7 @@ static int irq_try_set_affinity(struct irq_data *data,
}
static bool irq_set_affinity_deactivated(struct irq_data *data,
- const struct cpumask *mask, bool force)
+ const struct cpumask *mask)
{
struct irq_desc *desc = irq_data_to_desc(data);
@@ -354,7 +354,7 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
if (!chip || !chip->irq_set_affinity)
return -EINVAL;
- if (irq_set_affinity_deactivated(data, mask, force))
+ if (irq_set_affinity_deactivated(data, mask))
return 0;
if (irq_can_move_pcntxt(data) && !irqd_is_setaffinity_pending(data)) {
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index a9ee535293eb..bd4d4dd626b4 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -19,8 +19,31 @@
#include "internals.h"
+/**
+ * struct msi_ctrl - MSI internal management control structure
+ * @domid: ID of the domain on which management operations should be done
+ * @first: First (hardware) slot index to operate on
+ * @last: Last (hardware) slot index to operate on
+ * @nirqs: The number of Linux interrupts to allocate. Can be larger
+ * than the range due to PCI/multi-MSI.
+ */
+struct msi_ctrl {
+ unsigned int domid;
+ unsigned int first;
+ unsigned int last;
+ unsigned int nirqs;
+};
+
+/* Invalid Xarray index which is outside of any searchable range */
+#define MSI_XA_MAX_INDEX (ULONG_MAX - 1)
+/* The maximum domain size */
+#define MSI_XA_DOMAIN_SIZE (MSI_MAX_INDEX + 1)
+
+static void msi_domain_free_locked(struct device *dev, struct msi_ctrl *ctrl);
+static unsigned int msi_domain_get_hwsize(struct device *dev, unsigned int domid);
static inline int msi_sysfs_create_group(struct device *dev);
+
/**
* msi_alloc_desc - Allocate an initialized msi_desc
* @dev: Pointer to the device for which this is allocated
@@ -33,7 +56,7 @@ static inline int msi_sysfs_create_group(struct device *dev);
* Return: pointer to allocated &msi_desc on success or %NULL on failure
*/
static struct msi_desc *msi_alloc_desc(struct device *dev, int nvec,
- const struct irq_affinity_desc *affinity)
+ const struct irq_affinity_desc *affinity)
{
struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL);
@@ -58,25 +81,56 @@ static void msi_free_desc(struct msi_desc *desc)
kfree(desc);
}
-static int msi_insert_desc(struct msi_device_data *md, struct msi_desc *desc, unsigned int index)
+static int msi_insert_desc(struct device *dev, struct msi_desc *desc,
+ unsigned int domid, unsigned int index)
{
+ struct msi_device_data *md = dev->msi.data;
+ struct xarray *xa = &md->__domains[domid].store;
+ unsigned int hwsize;
int ret;
- desc->msi_index = index;
- ret = xa_insert(&md->__store, index, desc, GFP_KERNEL);
- if (ret)
- msi_free_desc(desc);
+ hwsize = msi_domain_get_hwsize(dev, domid);
+
+ if (index == MSI_ANY_INDEX) {
+ struct xa_limit limit = { .min = 0, .max = hwsize - 1 };
+ unsigned int index;
+
+ /* Let the xarray allocate a free index within the limit */
+ ret = xa_alloc(xa, &index, desc, limit, GFP_KERNEL);
+ if (ret)
+ goto fail;
+
+ desc->msi_index = index;
+ return 0;
+ } else {
+ if (index >= hwsize) {
+ ret = -ERANGE;
+ goto fail;
+ }
+
+ desc->msi_index = index;
+ ret = xa_insert(xa, index, desc, GFP_KERNEL);
+ if (ret)
+ goto fail;
+ return 0;
+ }
+fail:
+ msi_free_desc(desc);
return ret;
}
/**
- * msi_add_msi_desc - Allocate and initialize a MSI descriptor
+ * msi_domain_insert_msi_desc - Allocate and initialize a MSI descriptor and
+ * insert it at @init_desc->msi_index
+ *
* @dev: Pointer to the device for which the descriptor is allocated
+ * @domid: The id of the interrupt domain to which the desriptor is added
* @init_desc: Pointer to an MSI descriptor to initialize the new descriptor
*
* Return: 0 on success or an appropriate failure code.
*/
-int msi_add_msi_desc(struct device *dev, struct msi_desc *init_desc)
+int msi_domain_insert_msi_desc(struct device *dev, unsigned int domid,
+ struct msi_desc *init_desc)
{
struct msi_desc *desc;
@@ -88,40 +142,8 @@ int msi_add_msi_desc(struct device *dev, struct msi_desc *init_desc)
/* Copy type specific data to the new descriptor. */
desc->pci = init_desc->pci;
- return msi_insert_desc(dev->msi.data, desc, init_desc->msi_index);
-}
-/**
- * msi_add_simple_msi_descs - Allocate and initialize MSI descriptors
- * @dev: Pointer to the device for which the descriptors are allocated
- * @index: Index for the first MSI descriptor
- * @ndesc: Number of descriptors to allocate
- *
- * Return: 0 on success or an appropriate failure code.
- */
-static int msi_add_simple_msi_descs(struct device *dev, unsigned int index, unsigned int ndesc)
-{
- unsigned int idx, last = index + ndesc - 1;
- struct msi_desc *desc;
- int ret;
-
- lockdep_assert_held(&dev->msi.data->mutex);
-
- for (idx = index; idx <= last; idx++) {
- desc = msi_alloc_desc(dev, 1, NULL);
- if (!desc)
- goto fail_mem;
- ret = msi_insert_desc(dev->msi.data, desc, idx);
- if (ret)
- goto fail;
- }
- return 0;
-
-fail_mem:
- ret = -ENOMEM;
-fail:
- msi_free_msi_descs_range(dev, MSI_DESC_NOTASSOCIATED, index, last);
- return ret;
+ return msi_insert_desc(dev, desc, domid, init_desc->msi_index);
}
static bool msi_desc_match(struct msi_desc *desc, enum msi_desc_filter filter)
@@ -138,28 +160,96 @@ static bool msi_desc_match(struct msi_desc *desc, enum msi_desc_filter filter)
return false;
}
+static bool msi_ctrl_valid(struct device *dev, struct msi_ctrl *ctrl)
+{
+ unsigned int hwsize;
+
+ if (WARN_ON_ONCE(ctrl->domid >= MSI_MAX_DEVICE_IRQDOMAINS ||
+ !dev->msi.data->__domains[ctrl->domid].domain))
+ return false;
+
+ hwsize = msi_domain_get_hwsize(dev, ctrl->domid);
+ if (WARN_ON_ONCE(ctrl->first > ctrl->last ||
+ ctrl->first >= hwsize ||
+ ctrl->last >= hwsize))
+ return false;
+ return true;
+}
+
+static void msi_domain_free_descs(struct device *dev, struct msi_ctrl *ctrl)
+{
+ struct msi_desc *desc;
+ struct xarray *xa;
+ unsigned long idx;
+
+ lockdep_assert_held(&dev->msi.data->mutex);
+
+ if (!msi_ctrl_valid(dev, ctrl))
+ return;
+
+ xa = &dev->msi.data->__domains[ctrl->domid].store;
+ xa_for_each_range(xa, idx, desc, ctrl->first, ctrl->last) {
+ xa_erase(xa, idx);
+
+ /* Leak the descriptor when it is still referenced */
+ if (WARN_ON_ONCE(msi_desc_match(desc, MSI_DESC_ASSOCIATED)))
+ continue;
+ msi_free_desc(desc);
+ }
+}
+
/**
- * msi_free_msi_descs_range - Free MSI descriptors of a device
- * @dev: Device to free the descriptors
- * @filter: Descriptor state filter
- * @first_index: Index to start freeing from
- * @last_index: Last index to be freed
+ * msi_domain_free_msi_descs_range - Free a range of MSI descriptors of a device in an irqdomain
+ * @dev: Device for which to free the descriptors
+ * @domid: Id of the domain to operate on
+ * @first: Index to start freeing from (inclusive)
+ * @last: Last index to be freed (inclusive)
*/
-void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
- unsigned int first_index, unsigned int last_index)
+void msi_domain_free_msi_descs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last)
+{
+ struct msi_ctrl ctrl = {
+ .domid = domid,
+ .first = first,
+ .last = last,
+ };
+
+ msi_domain_free_descs(dev, &ctrl);
+}
+
+/**
+ * msi_domain_add_simple_msi_descs - Allocate and initialize MSI descriptors
+ * @dev: Pointer to the device for which the descriptors are allocated
+ * @ctrl: Allocation control struct
+ *
+ * Return: 0 on success or an appropriate failure code.
+ */
+static int msi_domain_add_simple_msi_descs(struct device *dev, struct msi_ctrl *ctrl)
{
- struct xarray *xa = &dev->msi.data->__store;
struct msi_desc *desc;
- unsigned long idx;
+ unsigned int idx;
+ int ret;
lockdep_assert_held(&dev->msi.data->mutex);
- xa_for_each_range(xa, idx, desc, first_index, last_index) {
- if (msi_desc_match(desc, filter)) {
- xa_erase(xa, idx);
- msi_free_desc(desc);
- }
+ if (!msi_ctrl_valid(dev, ctrl))
+ return -EINVAL;
+
+ for (idx = ctrl->first; idx <= ctrl->last; idx++) {
+ desc = msi_alloc_desc(dev, 1, NULL);
+ if (!desc)
+ goto fail_mem;
+ ret = msi_insert_desc(dev, desc, ctrl->domid, idx);
+ if (ret)
+ goto fail;
}
+ return 0;
+
+fail_mem:
+ ret = -ENOMEM;
+fail:
+ msi_domain_free_descs(dev, ctrl);
+ return ret;
}
void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
@@ -178,9 +268,13 @@ EXPORT_SYMBOL_GPL(get_cached_msi_msg);
static void msi_device_data_release(struct device *dev, void *res)
{
struct msi_device_data *md = res;
+ int i;
- WARN_ON_ONCE(!xa_empty(&md->__store));
- xa_destroy(&md->__store);
+ for (i = 0; i < MSI_MAX_DEVICE_IRQDOMAINS; i++) {
+ msi_remove_device_irq_domain(dev, i);
+ WARN_ON_ONCE(!xa_empty(&md->__domains[i].store));
+ xa_destroy(&md->__domains[i].store);
+ }
dev->msi.data = NULL;
}
@@ -197,7 +291,7 @@ static void msi_device_data_release(struct device *dev, void *res)
int msi_setup_device_data(struct device *dev)
{
struct msi_device_data *md;
- int ret;
+ int ret, i;
if (dev->msi.data)
return 0;
@@ -212,7 +306,18 @@ int msi_setup_device_data(struct device *dev)
return ret;
}
- xa_init(&md->__store);
+ for (i = 0; i < MSI_MAX_DEVICE_IRQDOMAINS; i++)
+ xa_init_flags(&md->__domains[i].store, XA_FLAGS_ALLOC);
+
+ /*
+ * If @dev::msi::domain is set and is a global MSI domain, copy the
+ * pointer into the domain array so all code can operate on domain
+ * ids. The NULL pointer check is required to keep the legacy
+ * architecture specific PCI/MSI support working.
+ */
+ if (dev->msi.domain && !irq_domain_is_msi_parent(dev->msi.domain))
+ md->__domains[MSI_DEFAULT_DOMAIN].domain = dev->msi.domain;
+
mutex_init(&md->mutex);
dev->msi.data = md;
devres_add(dev, md);
@@ -235,27 +340,30 @@ EXPORT_SYMBOL_GPL(msi_lock_descs);
*/
void msi_unlock_descs(struct device *dev)
{
- /* Invalidate the index wich was cached by the iterator */
- dev->msi.data->__iter_idx = MSI_MAX_INDEX;
+ /* Invalidate the index which was cached by the iterator */
+ dev->msi.data->__iter_idx = MSI_XA_MAX_INDEX;
mutex_unlock(&dev->msi.data->mutex);
}
EXPORT_SYMBOL_GPL(msi_unlock_descs);
-static struct msi_desc *msi_find_desc(struct msi_device_data *md, enum msi_desc_filter filter)
+static struct msi_desc *msi_find_desc(struct msi_device_data *md, unsigned int domid,
+ enum msi_desc_filter filter)
{
+ struct xarray *xa = &md->__domains[domid].store;
struct msi_desc *desc;
- xa_for_each_start(&md->__store, md->__iter_idx, desc, md->__iter_idx) {
+ xa_for_each_start(xa, md->__iter_idx, desc, md->__iter_idx) {
if (msi_desc_match(desc, filter))
return desc;
}
- md->__iter_idx = MSI_MAX_INDEX;
+ md->__iter_idx = MSI_XA_MAX_INDEX;
return NULL;
}
/**
- * msi_first_desc - Get the first MSI descriptor of a device
+ * msi_domain_first_desc - Get the first MSI descriptor of an irqdomain associated to a device
* @dev: Device to operate on
+ * @domid: The id of the interrupt domain which should be walked.
* @filter: Descriptor state filter
*
* Must be called with the MSI descriptor mutex held, i.e. msi_lock_descs()
@@ -264,23 +372,26 @@ static struct msi_desc *msi_find_desc(struct msi_device_data *md, enum msi_desc_
* Return: Pointer to the first MSI descriptor matching the search
* criteria, NULL if none found.
*/
-struct msi_desc *msi_first_desc(struct device *dev, enum msi_desc_filter filter)
+struct msi_desc *msi_domain_first_desc(struct device *dev, unsigned int domid,
+ enum msi_desc_filter filter)
{
struct msi_device_data *md = dev->msi.data;
- if (WARN_ON_ONCE(!md))
+ if (WARN_ON_ONCE(!md || domid >= MSI_MAX_DEVICE_IRQDOMAINS))
return NULL;
lockdep_assert_held(&md->mutex);
md->__iter_idx = 0;
- return msi_find_desc(md, filter);
+ return msi_find_desc(md, domid, filter);
}
-EXPORT_SYMBOL_GPL(msi_first_desc);
+EXPORT_SYMBOL_GPL(msi_domain_first_desc);
/**
* msi_next_desc - Get the next MSI descriptor of a device
* @dev: Device to operate on
+ * @domid: The id of the interrupt domain which should be walked.
+ * @filter: Descriptor state filter
*
* The first invocation of msi_next_desc() has to be preceeded by a
* successful invocation of __msi_first_desc(). Consecutive invocations are
@@ -290,11 +401,12 @@ EXPORT_SYMBOL_GPL(msi_first_desc);
* Return: Pointer to the next MSI descriptor matching the search
* criteria, NULL if none found.
*/
-struct msi_desc *msi_next_desc(struct device *dev, enum msi_desc_filter filter)
+struct msi_desc *msi_next_desc(struct device *dev, unsigned int domid,
+ enum msi_desc_filter filter)
{
struct msi_device_data *md = dev->msi.data;
- if (WARN_ON_ONCE(!md))
+ if (WARN_ON_ONCE(!md || domid >= MSI_MAX_DEVICE_IRQDOMAINS))
return NULL;
lockdep_assert_held(&md->mutex);
@@ -303,30 +415,38 @@ struct msi_desc *msi_next_desc(struct device *dev, enum msi_desc_filter filter)
return NULL;
md->__iter_idx++;
- return msi_find_desc(md, filter);
+ return msi_find_desc(md, domid, filter);
}
EXPORT_SYMBOL_GPL(msi_next_desc);
/**
- * msi_get_virq - Return Linux interrupt number of a MSI interrupt
+ * msi_domain_get_virq - Lookup the Linux interrupt number for a MSI index on a interrupt domain
* @dev: Device to operate on
+ * @domid: Domain ID of the interrupt domain associated to the device
* @index: MSI interrupt index to look for (0-based)
*
* Return: The Linux interrupt number on success (> 0), 0 if not found
*/
-unsigned int msi_get_virq(struct device *dev, unsigned int index)
+unsigned int msi_domain_get_virq(struct device *dev, unsigned int domid, unsigned int index)
{
struct msi_desc *desc;
unsigned int ret = 0;
- bool pcimsi;
+ bool pcimsi = false;
+ struct xarray *xa;
if (!dev->msi.data)
return 0;
- pcimsi = dev_is_pci(dev) ? to_pci_dev(dev)->msi_enabled : false;
+ if (WARN_ON_ONCE(index > MSI_MAX_INDEX || domid >= MSI_MAX_DEVICE_IRQDOMAINS))
+ return 0;
+
+ /* This check is only valid for the PCI default MSI domain */
+ if (dev_is_pci(dev) && domid == MSI_DEFAULT_DOMAIN)
+ pcimsi = to_pci_dev(dev)->msi_enabled;
msi_lock_descs(dev);
- desc = xa_load(&dev->msi.data->__store, pcimsi ? 0 : index);
+ xa = &dev->msi.data->__domains[domid].store;
+ desc = xa_load(xa, pcimsi ? 0 : index);
if (desc && desc->irq) {
/*
* PCI-MSI has only one descriptor for multiple interrupts.
@@ -340,10 +460,11 @@ unsigned int msi_get_virq(struct device *dev, unsigned int index)
ret = desc->irq;
}
}
+
msi_unlock_descs(dev);
return ret;
}
-EXPORT_SYMBOL_GPL(msi_get_virq);
+EXPORT_SYMBOL_GPL(msi_domain_get_virq);
#ifdef CONFIG_SYSFS
static struct attribute *msi_dev_attrs[] = {
@@ -459,7 +580,39 @@ static inline int msi_sysfs_populate_desc(struct device *dev, struct msi_desc *d
static inline void msi_sysfs_remove_desc(struct device *dev, struct msi_desc *desc) { }
#endif /* !CONFIG_SYSFS */
-#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+static struct irq_domain *msi_get_device_domain(struct device *dev, unsigned int domid)
+{
+ struct irq_domain *domain;
+
+ lockdep_assert_held(&dev->msi.data->mutex);
+
+ if (WARN_ON_ONCE(domid >= MSI_MAX_DEVICE_IRQDOMAINS))
+ return NULL;
+
+ domain = dev->msi.data->__domains[domid].domain;
+ if (!domain)
+ return NULL;
+
+ if (WARN_ON_ONCE(irq_domain_is_msi_parent(domain)))
+ return NULL;
+
+ return domain;
+}
+
+static unsigned int msi_domain_get_hwsize(struct device *dev, unsigned int domid)
+{
+ struct msi_domain_info *info;
+ struct irq_domain *domain;
+
+ domain = msi_get_device_domain(dev, domid);
+ if (domain) {
+ info = domain->host_data;
+ return info->hwsize;
+ }
+ /* No domain, no size... */
+ return 0;
+}
+
static inline void irq_chip_write_msi_msg(struct irq_data *data,
struct msi_msg *msg)
{
@@ -613,21 +766,11 @@ static int msi_domain_ops_init(struct irq_domain *domain,
return 0;
}
-static int msi_domain_ops_check(struct irq_domain *domain,
- struct msi_domain_info *info,
- struct device *dev)
-{
- return 0;
-}
-
static struct msi_domain_ops msi_domain_ops_default = {
.get_hwirq = msi_domain_ops_get_hwirq,
.msi_init = msi_domain_ops_init,
- .msi_check = msi_domain_ops_check,
.msi_prepare = msi_domain_ops_prepare,
.set_desc = msi_domain_ops_set_desc,
- .domain_alloc_irqs = __msi_domain_alloc_irqs,
- .domain_free_irqs = __msi_domain_free_irqs,
};
static void msi_domain_update_dom_ops(struct msi_domain_info *info)
@@ -639,11 +782,6 @@ static void msi_domain_update_dom_ops(struct msi_domain_info *info)
return;
}
- if (ops->domain_alloc_irqs == NULL)
- ops->domain_alloc_irqs = msi_domain_ops_default.domain_alloc_irqs;
- if (ops->domain_free_irqs == NULL)
- ops->domain_free_irqs = msi_domain_ops_default.domain_free_irqs;
-
if (!(info->flags & MSI_FLAG_USE_DEF_DOM_OPS))
return;
@@ -651,8 +789,6 @@ static void msi_domain_update_dom_ops(struct msi_domain_info *info)
ops->get_hwirq = msi_domain_ops_default.get_hwirq;
if (ops->msi_init == NULL)
ops->msi_init = msi_domain_ops_default.msi_init;
- if (ops->msi_check == NULL)
- ops->msi_check = msi_domain_ops_default.msi_check;
if (ops->msi_prepare == NULL)
ops->msi_prepare = msi_domain_ops_default.msi_prepare;
if (ops->set_desc == NULL)
@@ -668,6 +804,40 @@ static void msi_domain_update_chip_ops(struct msi_domain_info *info)
chip->irq_set_affinity = msi_domain_set_affinity;
}
+static struct irq_domain *__msi_create_irq_domain(struct fwnode_handle *fwnode,
+ struct msi_domain_info *info,
+ unsigned int flags,
+ struct irq_domain *parent)
+{
+ struct irq_domain *domain;
+
+ if (info->hwsize > MSI_XA_DOMAIN_SIZE)
+ return NULL;
+
+ /*
+ * Hardware size 0 is valid for backwards compatibility and for
+ * domains which are not backed by a hardware table. Grant the
+ * maximum index space.
+ */
+ if (!info->hwsize)
+ info->hwsize = MSI_XA_DOMAIN_SIZE;
+
+ msi_domain_update_dom_ops(info);
+ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+ msi_domain_update_chip_ops(info);
+
+ domain = irq_domain_create_hierarchy(parent, flags | IRQ_DOMAIN_FLAG_MSI, 0,
+ fwnode, &msi_domain_ops, info);
+
+ if (domain) {
+ if (!domain->name && info->chip)
+ domain->name = info->chip->name;
+ irq_domain_update_bus_token(domain, info->bus_token);
+ }
+
+ return domain;
+}
+
/**
* msi_create_irq_domain - Create an MSI interrupt domain
* @fwnode: Optional fwnode of the interrupt controller
@@ -680,19 +850,210 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent)
{
+ return __msi_create_irq_domain(fwnode, info, 0, parent);
+}
+
+/**
+ * msi_parent_init_dev_msi_info - Delegate initialization of device MSI info down
+ * in the domain hierarchy
+ * @dev: The device for which the domain should be created
+ * @domain: The domain in the hierarchy this op is being called on
+ * @msi_parent_domain: The IRQ_DOMAIN_FLAG_MSI_PARENT domain for the child to
+ * be created
+ * @msi_child_info: The MSI domain info of the IRQ_DOMAIN_FLAG_MSI_DEVICE
+ * domain to be created
+ *
+ * Return: true on success, false otherwise
+ *
+ * This is the most complex problem of per device MSI domains and the
+ * underlying interrupt domain hierarchy:
+ *
+ * The device domain to be initialized requests the broadest feature set
+ * possible and the underlying domain hierarchy puts restrictions on it.
+ *
+ * That's trivial for a simple parent->child relationship, but it gets
+ * interesting with an intermediate domain: root->parent->child. The
+ * intermediate 'parent' can expand the capabilities which the 'root'
+ * domain is providing. So that creates a classic hen and egg problem:
+ * Which entity is doing the restrictions/expansions?
+ *
+ * One solution is to let the root domain handle the initialization that's
+ * why there is the @domain and the @msi_parent_domain pointer.
+ */
+bool msi_parent_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+ struct irq_domain *msi_parent_domain,
+ struct msi_domain_info *msi_child_info)
+{
+ struct irq_domain *parent = domain->parent;
+
+ if (WARN_ON_ONCE(!parent || !parent->msi_parent_ops ||
+ !parent->msi_parent_ops->init_dev_msi_info))
+ return false;
+
+ return parent->msi_parent_ops->init_dev_msi_info(dev, parent, msi_parent_domain,
+ msi_child_info);
+}
+
+/**
+ * msi_create_device_irq_domain - Create a device MSI interrupt domain
+ * @dev: Pointer to the device
+ * @domid: Domain id
+ * @template: MSI domain info bundle used as template
+ * @hwsize: Maximum number of MSI table entries (0 if unknown or unlimited)
+ * @domain_data: Optional pointer to domain specific data which is set in
+ * msi_domain_info::data
+ * @chip_data: Optional pointer to chip specific data which is set in
+ * msi_domain_info::chip_data
+ *
+ * Return: True on success, false otherwise
+ *
+ * There is no firmware node required for this interface because the per
+ * device domains are software constructs which are actually closer to the
+ * hardware reality than any firmware can describe them.
+ *
+ * The domain name and the irq chip name for a MSI device domain are
+ * composed by: "$(PREFIX)$(CHIPNAME)-$(DEVNAME)"
+ *
+ * $PREFIX: Optional prefix provided by the underlying MSI parent domain
+ * via msi_parent_ops::prefix. If that pointer is NULL the prefix
+ * is empty.
+ * $CHIPNAME: The name of the irq_chip in @template
+ * $DEVNAME: The name of the device
+ *
+ * This results in understandable chip names and hardware interrupt numbers
+ * in e.g. /proc/interrupts
+ *
+ * PCI-MSI-0000:00:1c.0 0-edge Parent domain has no prefix
+ * IR-PCI-MSI-0000:00:1c.4 0-edge Same with interrupt remapping prefix 'IR-'
+ *
+ * IR-PCI-MSIX-0000:3d:00.0 0-edge Hardware interrupt numbers reflect
+ * IR-PCI-MSIX-0000:3d:00.0 1-edge the real MSI-X index on that device
+ * IR-PCI-MSIX-0000:3d:00.0 2-edge
+ *
+ * On IMS domains the hardware interrupt number is either a table entry
+ * index or a purely software managed index but it is guaranteed to be
+ * unique.
+ *
+ * The domain pointer is stored in @dev::msi::data::__irqdomains[]. All
+ * subsequent operations on the domain depend on the domain id.
+ *
+ * The domain is automatically freed when the device is removed via devres
+ * in the context of @dev::msi::data freeing, but it can also be
+ * independently removed via @msi_remove_device_irq_domain().
+ */
+bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
+ const struct msi_domain_template *template,
+ unsigned int hwsize, void *domain_data,
+ void *chip_data)
+{
+ struct irq_domain *domain, *parent = dev->msi.domain;
+ const struct msi_parent_ops *pops;
+ struct msi_domain_template *bundle;
+ struct fwnode_handle *fwnode;
+
+ if (!irq_domain_is_msi_parent(parent))
+ return false;
+
+ if (domid >= MSI_MAX_DEVICE_IRQDOMAINS)
+ return false;
+
+ bundle = kmemdup(template, sizeof(*bundle), GFP_KERNEL);
+ if (!bundle)
+ return false;
+
+ bundle->info.hwsize = hwsize;
+ bundle->info.chip = &bundle->chip;
+ bundle->info.ops = &bundle->ops;
+ bundle->info.data = domain_data;
+ bundle->info.chip_data = chip_data;
+
+ pops = parent->msi_parent_ops;
+ snprintf(bundle->name, sizeof(bundle->name), "%s%s-%s",
+ pops->prefix ? : "", bundle->chip.name, dev_name(dev));
+ bundle->chip.name = bundle->name;
+
+ fwnode = irq_domain_alloc_named_fwnode(bundle->name);
+ if (!fwnode)
+ goto free_bundle;
+
+ if (msi_setup_device_data(dev))
+ goto free_fwnode;
+
+ msi_lock_descs(dev);
+
+ if (WARN_ON_ONCE(msi_get_device_domain(dev, domid)))
+ goto fail;
+
+ if (!pops->init_dev_msi_info(dev, parent, parent, &bundle->info))
+ goto fail;
+
+ domain = __msi_create_irq_domain(fwnode, &bundle->info, IRQ_DOMAIN_FLAG_MSI_DEVICE, parent);
+ if (!domain)
+ goto fail;
+
+ domain->dev = dev;
+ dev->msi.data->__domains[domid].domain = domain;
+ msi_unlock_descs(dev);
+ return true;
+
+fail:
+ msi_unlock_descs(dev);
+free_fwnode:
+ kfree(fwnode);
+free_bundle:
+ kfree(bundle);
+ return false;
+}
+
+/**
+ * msi_remove_device_irq_domain - Free a device MSI interrupt domain
+ * @dev: Pointer to the device
+ * @domid: Domain id
+ */
+void msi_remove_device_irq_domain(struct device *dev, unsigned int domid)
+{
+ struct msi_domain_info *info;
struct irq_domain *domain;
- msi_domain_update_dom_ops(info);
- if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
- msi_domain_update_chip_ops(info);
+ msi_lock_descs(dev);
- domain = irq_domain_create_hierarchy(parent, IRQ_DOMAIN_FLAG_MSI, 0,
- fwnode, &msi_domain_ops, info);
+ domain = msi_get_device_domain(dev, domid);
- if (domain && !domain->name && info->chip)
- domain->name = info->chip->name;
+ if (!domain || !irq_domain_is_msi_device(domain))
+ goto unlock;
- return domain;
+ dev->msi.data->__domains[domid].domain = NULL;
+ info = domain->host_data;
+ irq_domain_remove(domain);
+ kfree(container_of(info, struct msi_domain_template, info));
+
+unlock:
+ msi_unlock_descs(dev);
+}
+
+/**
+ * msi_match_device_irq_domain - Match a device irq domain against a bus token
+ * @dev: Pointer to the device
+ * @domid: Domain id
+ * @bus_token: Bus token to match against the domain bus token
+ *
+ * Return: True if device domain exists and bus tokens match.
+ */
+bool msi_match_device_irq_domain(struct device *dev, unsigned int domid,
+ enum irq_domain_bus_token bus_token)
+{
+ struct msi_domain_info *info;
+ struct irq_domain *domain;
+ bool ret = false;
+
+ msi_lock_descs(dev);
+ domain = msi_get_device_domain(dev, domid);
+ if (domain && irq_domain_is_msi_device(domain)) {
+ info = domain->host_data;
+ ret = info->bus_token == bus_token;
+ }
+ msi_unlock_descs(dev);
+ return ret;
}
int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
@@ -700,13 +1061,8 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
{
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;
+ return ops->msi_prepare(domain, dev, nvec, arg);
}
int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
@@ -714,16 +1070,27 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
{
struct msi_domain_info *info = domain->host_data;
struct msi_domain_ops *ops = info->ops;
+ struct msi_ctrl ctrl = {
+ .domid = MSI_DEFAULT_DOMAIN,
+ .first = virq_base,
+ .last = virq_base + nvec - 1,
+ };
struct msi_desc *desc;
+ struct xarray *xa;
int ret, virq;
+ if (!msi_ctrl_valid(dev, &ctrl))
+ return -EINVAL;
+
msi_lock_descs(dev);
- ret = msi_add_simple_msi_descs(dev, virq_base, nvec);
+ ret = msi_domain_add_simple_msi_descs(dev, &ctrl);
if (ret)
goto unlock;
+ xa = &dev->msi.data->__domains[ctrl.domid].store;
+
for (virq = virq_base; virq < virq_base + nvec; virq++) {
- desc = xa_load(&dev->msi.data->__store, virq);
+ desc = xa_load(xa, virq);
desc->irq = virq;
ops->set_desc(arg, desc);
@@ -739,7 +1106,7 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
fail:
for (--virq; virq >= virq_base; virq--)
irq_domain_free_irqs_common(domain, virq, 1);
- msi_free_msi_descs_range(dev, MSI_DESC_ALL, virq_base, virq_base + nvec - 1);
+ msi_domain_free_descs(dev, &ctrl);
unlock:
msi_unlock_descs(dev);
return ret;
@@ -764,6 +1131,8 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
switch(domain->bus_token) {
case DOMAIN_BUS_PCI_MSI:
+ case DOMAIN_BUS_PCI_DEVICE_MSI:
+ case DOMAIN_BUS_PCI_DEVICE_MSIX:
case DOMAIN_BUS_VMD_MSI:
break;
default:
@@ -789,6 +1158,8 @@ static int msi_handle_pci_fail(struct irq_domain *domain, struct msi_desc *desc,
{
switch(domain->bus_token) {
case DOMAIN_BUS_PCI_MSI:
+ case DOMAIN_BUS_PCI_DEVICE_MSI:
+ case DOMAIN_BUS_PCI_DEVICE_MSIX:
case DOMAIN_BUS_VMD_MSI:
if (IS_ENABLED(CONFIG_PCI_MSI))
break;
@@ -850,18 +1221,19 @@ static int msi_init_virq(struct irq_domain *domain, int virq, unsigned int vflag
return 0;
}
-int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
- int nvec)
+static int __msi_domain_alloc_irqs(struct device *dev, struct irq_domain *domain,
+ struct msi_ctrl *ctrl)
{
+ struct xarray *xa = &dev->msi.data->__domains[ctrl->domid].store;
struct msi_domain_info *info = domain->host_data;
struct msi_domain_ops *ops = info->ops;
+ unsigned int vflags = 0, allocated = 0;
msi_alloc_info_t arg = { };
- unsigned int vflags = 0;
struct msi_desc *desc;
- int allocated = 0;
+ unsigned long idx;
int i, ret, virq;
- ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
+ ret = msi_domain_prepare_irqs(domain, dev, ctrl->nirqs, &arg);
if (ret)
return ret;
@@ -883,11 +1255,21 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
* MSI affinity setting requires a special quirk (X86) when
* reservation mode is active.
*/
- if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK)
+ if (info->flags & MSI_FLAG_NOMASK_QUIRK)
vflags |= VIRQ_NOMASK_QUIRK;
}
- msi_for_each_desc(desc, dev, MSI_DESC_NOTASSOCIATED) {
+ xa_for_each_range(xa, idx, desc, ctrl->first, ctrl->last) {
+ if (!msi_desc_match(desc, MSI_DESC_NOTASSOCIATED))
+ continue;
+
+ /* This should return -ECONFUSED... */
+ if (WARN_ON_ONCE(allocated >= ctrl->nirqs))
+ return -EINVAL;
+
+ if (ops->prepare_desc)
+ ops->prepare_desc(domain, &arg, desc);
+
ops->set_desc(&arg, desc);
virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
@@ -913,76 +1295,213 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
return 0;
}
-static int msi_domain_add_simple_msi_descs(struct msi_domain_info *info,
- struct device *dev,
- unsigned int num_descs)
+static int msi_domain_alloc_simple_msi_descs(struct device *dev,
+ struct msi_domain_info *info,
+ struct msi_ctrl *ctrl)
{
if (!(info->flags & MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS))
return 0;
- return msi_add_simple_msi_descs(dev, 0, num_descs);
+ return msi_domain_add_simple_msi_descs(dev, ctrl);
+}
+
+static int __msi_domain_alloc_locked(struct device *dev, struct msi_ctrl *ctrl)
+{
+ struct msi_domain_info *info;
+ struct msi_domain_ops *ops;
+ struct irq_domain *domain;
+ int ret;
+
+ if (!msi_ctrl_valid(dev, ctrl))
+ return -EINVAL;
+
+ domain = msi_get_device_domain(dev, ctrl->domid);
+ if (!domain)
+ return -ENODEV;
+
+ info = domain->host_data;
+
+ ret = msi_domain_alloc_simple_msi_descs(dev, info, ctrl);
+ if (ret)
+ return ret;
+
+ ops = info->ops;
+ if (ops->domain_alloc_irqs)
+ return ops->domain_alloc_irqs(domain, dev, ctrl->nirqs);
+
+ return __msi_domain_alloc_irqs(dev, domain, ctrl);
+}
+
+static int msi_domain_alloc_locked(struct device *dev, struct msi_ctrl *ctrl)
+{
+ int ret = __msi_domain_alloc_locked(dev, ctrl);
+
+ if (ret)
+ msi_domain_free_locked(dev, ctrl);
+ return ret;
}
/**
- * msi_domain_alloc_irqs_descs_locked - Allocate interrupts from a MSI interrupt domain
- * @domain: The domain to allocate from
+ * msi_domain_alloc_irqs_range_locked - Allocate interrupts from a MSI interrupt domain
* @dev: Pointer to device struct of the device for which the interrupts
* are allocated
- * @nvec: The number of interrupts to allocate
+ * @domid: Id of the interrupt domain to operate on
+ * @first: First index to allocate (inclusive)
+ * @last: Last index to allocate (inclusive)
*
* Must be invoked from within a msi_lock_descs() / msi_unlock_descs()
- * pair. Use this for MSI irqdomains which implement their own vector
+ * pair. Use this for MSI irqdomains which implement their own descriptor
* allocation/free.
*
* Return: %0 on success or an error code.
*/
-int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device *dev,
- int nvec)
+int msi_domain_alloc_irqs_range_locked(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last)
{
- struct msi_domain_info *info = domain->host_data;
- struct msi_domain_ops *ops = info->ops;
- int ret;
-
- lockdep_assert_held(&dev->msi.data->mutex);
+ struct msi_ctrl ctrl = {
+ .domid = domid,
+ .first = first,
+ .last = last,
+ .nirqs = last + 1 - first,
+ };
+
+ return msi_domain_alloc_locked(dev, &ctrl);
+}
- ret = msi_domain_add_simple_msi_descs(info, dev, nvec);
- if (ret)
- return ret;
+/**
+ * msi_domain_alloc_irqs_range - Allocate interrupts from a MSI interrupt domain
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are allocated
+ * @domid: Id of the interrupt domain to operate on
+ * @first: First index to allocate (inclusive)
+ * @last: Last index to allocate (inclusive)
+ *
+ * Return: %0 on success or an error code.
+ */
+int msi_domain_alloc_irqs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last)
+{
+ int ret;
- ret = ops->domain_alloc_irqs(domain, dev, nvec);
- if (ret)
- msi_domain_free_irqs_descs_locked(domain, dev);
+ msi_lock_descs(dev);
+ ret = msi_domain_alloc_irqs_range_locked(dev, domid, first, last);
+ msi_unlock_descs(dev);
return ret;
}
/**
- * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
- * @domain: The domain to allocate from
+ * msi_domain_alloc_irqs_all_locked - Allocate all interrupts from a MSI interrupt domain
+ *
* @dev: Pointer to device struct of the device for which the interrupts
* are allocated
- * @nvec: The number of interrupts to allocate
+ * @domid: Id of the interrupt domain to operate on
+ * @nirqs: The number of interrupts to allocate
+ *
+ * This function scans all MSI descriptors of the MSI domain and allocates interrupts
+ * for all unassigned ones. That function is to be used for MSI domain usage where
+ * the descriptor allocation is handled at the call site, e.g. PCI/MSI[X].
*
* Return: %0 on success or an error code.
*/
-int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, int nvec)
+int msi_domain_alloc_irqs_all_locked(struct device *dev, unsigned int domid, int nirqs)
{
+ struct msi_ctrl ctrl = {
+ .domid = domid,
+ .first = 0,
+ .last = msi_domain_get_hwsize(dev, domid) - 1,
+ .nirqs = nirqs,
+ };
+
+ return msi_domain_alloc_locked(dev, &ctrl);
+}
+
+/**
+ * msi_domain_alloc_irq_at - Allocate an interrupt from a MSI interrupt domain at
+ * a given index - or at the next free index
+ *
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are allocated
+ * @domid: Id of the interrupt domain to operate on
+ * @index: Index for allocation. If @index == %MSI_ANY_INDEX the allocation
+ * uses the next free index.
+ * @affdesc: Optional pointer to an interrupt affinity descriptor structure
+ * @icookie: Optional pointer to a domain specific per instance cookie. If
+ * non-NULL the content of the cookie is stored in msi_desc::data.
+ * Must be NULL for MSI-X allocations
+ *
+ * This requires a MSI interrupt domain which lets the core code manage the
+ * MSI descriptors.
+ *
+ * Return: struct msi_map
+ *
+ * On success msi_map::index contains the allocated index number and
+ * msi_map::virq the corresponding Linux interrupt number
+ *
+ * On failure msi_map::index contains the error code and msi_map::virq
+ * is %0.
+ */
+struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index,
+ const struct irq_affinity_desc *affdesc,
+ union msi_instance_cookie *icookie)
+{
+ struct msi_ctrl ctrl = { .domid = domid, .nirqs = 1, };
+ struct irq_domain *domain;
+ struct msi_map map = { };
+ struct msi_desc *desc;
int ret;
msi_lock_descs(dev);
- ret = msi_domain_alloc_irqs_descs_locked(domain, dev, nvec);
+ domain = msi_get_device_domain(dev, domid);
+ if (!domain) {
+ map.index = -ENODEV;
+ goto unlock;
+ }
+
+ desc = msi_alloc_desc(dev, 1, affdesc);
+ if (!desc) {
+ map.index = -ENOMEM;
+ goto unlock;
+ }
+
+ if (icookie)
+ desc->data.icookie = *icookie;
+
+ ret = msi_insert_desc(dev, desc, domid, index);
+ if (ret) {
+ map.index = ret;
+ goto unlock;
+ }
+
+ ctrl.first = ctrl.last = desc->msi_index;
+
+ ret = __msi_domain_alloc_irqs(dev, domain, &ctrl);
+ if (ret) {
+ map.index = ret;
+ msi_domain_free_locked(dev, &ctrl);
+ } else {
+ map.index = desc->msi_index;
+ map.virq = desc->irq;
+ }
+unlock:
msi_unlock_descs(dev);
- return ret;
+ return map;
}
-void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
+static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain,
+ struct msi_ctrl *ctrl)
{
+ struct xarray *xa = &dev->msi.data->__domains[ctrl->domid].store;
struct msi_domain_info *info = domain->host_data;
struct irq_data *irqd;
struct msi_desc *desc;
+ unsigned long idx;
int i;
- /* Only handle MSI entries which have an interrupt associated */
- msi_for_each_desc(desc, dev, MSI_DESC_ASSOCIATED) {
+ xa_for_each_range(xa, idx, desc, ctrl->first, ctrl->last) {
+ /* Only handle MSI entries which have an interrupt associated */
+ if (!msi_desc_match(desc, MSI_DESC_ASSOCIATED))
+ continue;
+
/* Make sure all interrupts are deactivated */
for (i = 0; i < desc->nvec_used; i++) {
irqd = irq_domain_get_irq_data(domain, desc->irq + i);
@@ -997,44 +1516,99 @@ void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
}
}
-static void msi_domain_free_msi_descs(struct msi_domain_info *info,
- struct device *dev)
+static void msi_domain_free_locked(struct device *dev, struct msi_ctrl *ctrl)
{
+ struct msi_domain_info *info;
+ struct msi_domain_ops *ops;
+ struct irq_domain *domain;
+
+ if (!msi_ctrl_valid(dev, ctrl))
+ return;
+
+ domain = msi_get_device_domain(dev, ctrl->domid);
+ if (!domain)
+ return;
+
+ info = domain->host_data;
+ ops = info->ops;
+
+ if (ops->domain_free_irqs)
+ ops->domain_free_irqs(domain, dev);
+ else
+ __msi_domain_free_irqs(dev, domain, ctrl);
+
+ if (ops->msi_post_free)
+ ops->msi_post_free(domain, dev);
+
if (info->flags & MSI_FLAG_FREE_MSI_DESCS)
- msi_free_msi_descs(dev);
+ msi_domain_free_descs(dev, ctrl);
}
/**
- * msi_domain_free_irqs_descs_locked - Free interrupts from a MSI interrupt @domain associated to @dev
- * @domain: The domain to managing the interrupts
+ * msi_domain_free_irqs_range_locked - Free a range of interrupts from a MSI interrupt domain
+ * associated to @dev with msi_lock held
* @dev: Pointer to device struct of the device for which the interrupts
- * are free
+ * are freed
+ * @domid: Id of the interrupt domain to operate on
+ * @first: First index to free (inclusive)
+ * @last: Last index to free (inclusive)
+ */
+void msi_domain_free_irqs_range_locked(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last)
+{
+ struct msi_ctrl ctrl = {
+ .domid = domid,
+ .first = first,
+ .last = last,
+ };
+ msi_domain_free_locked(dev, &ctrl);
+}
+
+/**
+ * msi_domain_free_irqs_range - Free a range of interrupts from a MSI interrupt domain
+ * associated to @dev
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are freed
+ * @domid: Id of the interrupt domain to operate on
+ * @first: First index to free (inclusive)
+ * @last: Last index to free (inclusive)
+ */
+void msi_domain_free_irqs_range(struct device *dev, unsigned int domid,
+ unsigned int first, unsigned int last)
+{
+ msi_lock_descs(dev);
+ msi_domain_free_irqs_range_locked(dev, domid, first, last);
+ msi_unlock_descs(dev);
+}
+
+/**
+ * msi_domain_free_irqs_all_locked - Free all interrupts from a MSI interrupt domain
+ * associated to a device
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are freed
+ * @domid: The id of the domain to operate on
*
* Must be invoked from within a msi_lock_descs() / msi_unlock_descs()
* pair. Use this for MSI irqdomains which implement their own vector
* allocation.
*/
-void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device *dev)
+void msi_domain_free_irqs_all_locked(struct device *dev, unsigned int domid)
{
- struct msi_domain_info *info = domain->host_data;
- struct msi_domain_ops *ops = info->ops;
-
- lockdep_assert_held(&dev->msi.data->mutex);
-
- ops->domain_free_irqs(domain, dev);
- msi_domain_free_msi_descs(info, dev);
+ msi_domain_free_irqs_range_locked(dev, domid, 0,
+ msi_domain_get_hwsize(dev, domid) - 1);
}
/**
- * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated to @dev
- * @domain: The domain to managing the interrupts
+ * msi_domain_free_irqs_all - Free all interrupts from a MSI interrupt domain
+ * associated to a device
* @dev: Pointer to device struct of the device for which the interrupts
- * are free
+ * are freed
+ * @domid: The id of the domain to operate on
*/
-void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
+void msi_domain_free_irqs_all(struct device *dev, unsigned int domid)
{
msi_lock_descs(dev);
- msi_domain_free_irqs_descs_locked(domain, dev);
+ msi_domain_free_irqs_all_locked(dev, domid);
msi_unlock_descs(dev);
}
@@ -1048,5 +1622,3 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
{
return (struct msi_domain_info *)domain->host_data;
}
-
-#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 714ac4c3b556..4d6c6f5f60db 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -115,8 +115,6 @@ EXPORT_SYMBOL_GPL(static_key_count);
void static_key_slow_inc_cpuslocked(struct static_key *key)
{
- int v, v1;
-
STATIC_KEY_CHECK_USE(key);
lockdep_assert_cpus_held();
@@ -132,11 +130,9 @@ void static_key_slow_inc_cpuslocked(struct static_key *key)
* so it counts as "enabled" in jump_label_update(). Note that
* atomic_inc_unless_negative() checks >= 0, so roll our own.
*/
- for (v = atomic_read(&key->enabled); v > 0; v = v1) {
- v1 = atomic_cmpxchg(&key->enabled, v, v + 1);
- if (likely(v1 == v))
+ for (int v = atomic_read(&key->enabled); v > 0; )
+ if (likely(atomic_try_cmpxchg(&key->enabled, &v, v + 1)))
return;
- }
jump_label_lock();
if (atomic_read(&key->enabled) == 0) {
diff --git a/kernel/kcsan/Makefile b/kernel/kcsan/Makefile
index 4f35d1bced6a..8cf70f068d92 100644
--- a/kernel/kcsan/Makefile
+++ b/kernel/kcsan/Makefile
@@ -17,4 +17,5 @@ KCSAN_INSTRUMENT_BARRIERS_selftest.o := y
obj-$(CONFIG_KCSAN_SELFTEST) += selftest.o
CFLAGS_kcsan_test.o := $(CFLAGS_KCSAN) -g -fno-omit-frame-pointer
+CFLAGS_kcsan_test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_KCSAN_KUNIT_TEST) += kcsan_test.o
diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c
index fe12dfe254ec..54d077e1a2dc 100644
--- a/kernel/kcsan/core.c
+++ b/kernel/kcsan/core.c
@@ -14,10 +14,12 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/minmax.h>
#include <linux/moduleparam.h>
#include <linux/percpu.h>
#include <linux/preempt.h>
#include <linux/sched.h>
+#include <linux/string.h>
#include <linux/uaccess.h>
#include "encoding.h"
@@ -1308,3 +1310,51 @@ noinline void __tsan_atomic_signal_fence(int memorder)
}
}
EXPORT_SYMBOL(__tsan_atomic_signal_fence);
+
+#ifdef __HAVE_ARCH_MEMSET
+void *__tsan_memset(void *s, int c, size_t count);
+noinline void *__tsan_memset(void *s, int c, size_t count)
+{
+ /*
+ * Instead of not setting up watchpoints where accessed size is greater
+ * than MAX_ENCODABLE_SIZE, truncate checked size to MAX_ENCODABLE_SIZE.
+ */
+ size_t check_len = min_t(size_t, count, MAX_ENCODABLE_SIZE);
+
+ check_access(s, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+ return memset(s, c, count);
+}
+#else
+void *__tsan_memset(void *s, int c, size_t count) __alias(memset);
+#endif
+EXPORT_SYMBOL(__tsan_memset);
+
+#ifdef __HAVE_ARCH_MEMMOVE
+void *__tsan_memmove(void *dst, const void *src, size_t len);
+noinline void *__tsan_memmove(void *dst, const void *src, size_t len)
+{
+ size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
+
+ check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+ check_access(src, check_len, 0, _RET_IP_);
+ return memmove(dst, src, len);
+}
+#else
+void *__tsan_memmove(void *dst, const void *src, size_t len) __alias(memmove);
+#endif
+EXPORT_SYMBOL(__tsan_memmove);
+
+#ifdef __HAVE_ARCH_MEMCPY
+void *__tsan_memcpy(void *dst, const void *src, size_t len);
+noinline void *__tsan_memcpy(void *dst, const void *src, size_t len)
+{
+ size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
+
+ check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+ check_access(src, check_len, 0, _RET_IP_);
+ return memcpy(dst, src, len);
+}
+#else
+void *__tsan_memcpy(void *dst, const void *src, size_t len) __alias(memcpy);
+#endif
+EXPORT_SYMBOL(__tsan_memcpy);
diff --git a/kernel/kcsan/selftest.c b/kernel/kcsan/selftest.c
index 00cdf8fa5693..8679322450f2 100644
--- a/kernel/kcsan/selftest.c
+++ b/kernel/kcsan/selftest.c
@@ -22,13 +22,6 @@
#define ITERS_PER_TEST 2000
-/* Test requirements. */
-static bool __init test_requires(void)
-{
- /* random should be initialized for the below tests */
- return get_random_u32() + get_random_u32() != 0;
-}
-
/*
* Test watchpoint encode and decode: check that encoding some access's info,
* and then subsequent decode preserves the access's info.
@@ -38,8 +31,8 @@ static bool __init test_encode_decode(void)
int i;
for (i = 0; i < ITERS_PER_TEST; ++i) {
- size_t size = prandom_u32_max(MAX_ENCODABLE_SIZE) + 1;
- bool is_write = !!prandom_u32_max(2);
+ size_t size = get_random_u32_inclusive(1, MAX_ENCODABLE_SIZE);
+ bool is_write = !!get_random_u32_below(2);
unsigned long verif_masked_addr;
long encoded_watchpoint;
bool verif_is_write;
@@ -259,7 +252,6 @@ static int __init kcsan_selftest(void)
pr_err("selftest: " #do_test " failed"); \
} while (0)
- RUN_TEST(test_requires);
RUN_TEST(test_encode_decode);
RUN_TEST(test_matching_access);
RUN_TEST(test_barrier);
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index ca2743f9c634..969e8f52f7da 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -561,23 +561,17 @@ static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
static int kimage_set_destination(struct kimage *image,
unsigned long destination)
{
- int result;
-
destination &= PAGE_MASK;
- result = kimage_add_entry(image, destination | IND_DESTINATION);
- return result;
+ return kimage_add_entry(image, destination | IND_DESTINATION);
}
static int kimage_add_page(struct kimage *image, unsigned long page)
{
- int result;
-
page &= PAGE_MASK;
- result = kimage_add_entry(image, page | IND_SOURCE);
- return result;
+ return kimage_add_entry(image, page | IND_SOURCE);
}
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 45637511e0de..dd5983010b7b 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -1141,7 +1141,7 @@ int crash_exclude_mem_range(struct crash_mem *mem,
{
int i, j;
unsigned long long start, end, p_start, p_end;
- struct crash_mem_range temp_range = {0, 0};
+ struct range temp_range = {0, 0};
for (i = 0; i < mem->nr_ranges; i++) {
start = mem->ranges[i].start;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index cd9f5a66a690..3050631e528d 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1766,7 +1766,13 @@ static int __unregister_kprobe_top(struct kprobe *p)
if ((list_p != p) && (list_p->post_handler))
goto noclean;
}
- ap->post_handler = NULL;
+ /*
+ * For the kprobe-on-ftrace case, we keep the
+ * post_handler setting to identify this aggrprobe
+ * armed with kprobe_ipmodify_ops.
+ */
+ if (!kprobe_ftrace(ap))
+ ap->post_handler = NULL;
}
noclean:
/*
diff --git a/kernel/livepatch/patch.c b/kernel/livepatch/patch.c
index 4c4f5a776d80..4152c71507e2 100644
--- a/kernel/livepatch/patch.c
+++ b/kernel/livepatch/patch.c
@@ -118,7 +118,7 @@ static void notrace klp_ftrace_handler(unsigned long ip,
if (func->nop)
goto unlock;
- ftrace_instruction_pointer_set(fregs, (unsigned long)func->new_func);
+ ftrace_regs_set_instruction_pointer(fregs, (unsigned long)func->new_func);
unlock:
ftrace_test_recursion_unlock(bit);
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index 30187b1d8275..f1b25ec581e0 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -196,36 +196,36 @@ static int klp_check_stack_func(struct klp_func *func, unsigned long *entries,
struct klp_ops *ops;
int i;
- for (i = 0; i < nr_entries; i++) {
- address = entries[i];
+ if (klp_target_state == KLP_UNPATCHED) {
+ /*
+ * Check for the to-be-unpatched function
+ * (the func itself).
+ */
+ func_addr = (unsigned long)func->new_func;
+ func_size = func->new_size;
+ } else {
+ /*
+ * Check for the to-be-patched function
+ * (the previous func).
+ */
+ ops = klp_find_ops(func->old_func);
- if (klp_target_state == KLP_UNPATCHED) {
- /*
- * Check for the to-be-unpatched function
- * (the func itself).
- */
- func_addr = (unsigned long)func->new_func;
- func_size = func->new_size;
+ if (list_is_singular(&ops->func_stack)) {
+ /* original function */
+ func_addr = (unsigned long)func->old_func;
+ func_size = func->old_size;
} else {
- /*
- * Check for the to-be-patched function
- * (the previous func).
- */
- ops = klp_find_ops(func->old_func);
-
- if (list_is_singular(&ops->func_stack)) {
- /* original function */
- func_addr = (unsigned long)func->old_func;
- func_size = func->old_size;
- } else {
- /* previously patched function */
- struct klp_func *prev;
-
- prev = list_next_entry(func, stack_node);
- func_addr = (unsigned long)prev->new_func;
- func_size = prev->new_size;
- }
+ /* previously patched function */
+ struct klp_func *prev;
+
+ prev = list_next_entry(func, stack_node);
+ func_addr = (unsigned long)prev->new_func;
+ func_size = prev->new_size;
}
+ }
+
+ for (i = 0; i < nr_entries; i++) {
+ address = entries[i];
if (address >= func_addr && address < func_addr + func_size)
return -EAGAIN;
diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c
index 43efb2a04160..29dc253d03af 100644
--- a/kernel/locking/test-ww_mutex.c
+++ b/kernel/locking/test-ww_mutex.c
@@ -399,7 +399,7 @@ static int *get_random_order(int count)
order[n] = n;
for (n = count - 1; n > 1; n--) {
- r = prandom_u32_max(n + 1);
+ r = get_random_u32_below(n + 1);
if (r != n) {
tmp = order[n];
order[n] = order[r];
@@ -538,7 +538,7 @@ static void stress_one_work(struct work_struct *work)
{
struct stress *stress = container_of(work, typeof(*stress), work);
const int nlocks = stress->nlocks;
- struct ww_mutex *lock = stress->locks + prandom_u32_max(nlocks);
+ struct ww_mutex *lock = stress->locks + get_random_u32_below(nlocks);
int err;
do {
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 0d5bd62c480e..ab75637fd904 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -62,7 +62,7 @@ static int notifier_chain_unregister(struct notifier_block **nl,
* value of this parameter is -1.
* @nr_calls: Records the number of notifications sent. Don't care
* value of this field is NULL.
- * @returns: notifier_call_chain returns the value returned by the
+ * Return: notifier_call_chain returns the value returned by the
* last notifier function called.
*/
static int notifier_call_chain(struct notifier_block **nl,
@@ -105,13 +105,13 @@ NOKPROBE_SYMBOL(notifier_call_chain);
* @val_up: Value passed unmodified to the notifier function
* @val_down: Value passed unmodified to the notifier function when recovering
* from an error on @val_up
- * @v Pointer passed unmodified to the notifier function
+ * @v: Pointer passed unmodified to the notifier function
*
* NOTE: It is important the @nl chain doesn't change between the two
* invocations of notifier_call_chain() such that we visit the
* exact same notifier callbacks; this rules out any RCU usage.
*
- * Returns: the return value of the @val_up call.
+ * Return: the return value of the @val_up call.
*/
static int notifier_call_chain_robust(struct notifier_block **nl,
unsigned long val_up, unsigned long val_down,
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index eec72ca962e2..a487ff24129b 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -157,7 +157,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
CLONE_NEWPID | CLONE_NEWNET |
CLONE_NEWCGROUP | CLONE_NEWTIME)))) {
- if (likely(old_ns->time_ns_for_children == old_ns->time_ns)) {
+ if ((flags & CLONE_VM) ||
+ likely(old_ns->time_ns_for_children == old_ns->time_ns)) {
get_nsproxy(old_ns);
return 0;
}
@@ -179,7 +180,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
if (IS_ERR(new_ns))
return PTR_ERR(new_ns);
- timens_on_fork(new_ns, tsk);
+ if ((flags & CLONE_VM) == 0)
+ timens_on_fork(new_ns, tsk);
tsk->nsproxy = new_ns;
return 0;
@@ -254,6 +256,23 @@ void exit_task_namespaces(struct task_struct *p)
switch_task_namespaces(p, NULL);
}
+int exec_task_namespaces(void)
+{
+ struct task_struct *tsk = current;
+ struct nsproxy *new;
+
+ if (tsk->nsproxy->time_ns_for_children == tsk->nsproxy->time_ns)
+ return 0;
+
+ new = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+
+ timens_on_fork(new, tsk);
+ switch_task_namespaces(tsk, new);
+ return 0;
+}
+
static int check_setns_flags(unsigned long flags)
{
if (!flags || (flags & ~(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
diff --git a/kernel/panic.c b/kernel/panic.c
index da323209f583..75fe389e8814 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -25,6 +25,7 @@
#include <linux/kexec.h>
#include <linux/panic_notifier.h>
#include <linux/sched.h>
+#include <linux/string_helpers.h>
#include <linux/sysrq.h>
#include <linux/init.h>
#include <linux/nmi.h>
@@ -744,8 +745,8 @@ static int __init panic_on_taint_setup(char *s)
if (s && !strcmp(s, "nousertaint"))
panic_on_taint_nousertaint = true;
- pr_info("panic_on_taint: bitmask=0x%lx nousertaint_mode=%sabled\n",
- panic_on_taint, panic_on_taint_nousertaint ? "en" : "dis");
+ pr_info("panic_on_taint: bitmask=0x%lx nousertaint_mode=%s\n",
+ panic_on_taint, str_enabled_disabled(panic_on_taint_nousertaint));
return 0;
}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index ddd9988327fe..6c1c7e566d35 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -27,6 +27,8 @@ unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC;
static int try_to_freeze_tasks(bool user_only)
{
+ const char *what = user_only ? "user space processes" :
+ "remaining freezable tasks";
struct task_struct *g, *p;
unsigned long end_time;
unsigned int todo;
@@ -36,6 +38,8 @@ static int try_to_freeze_tasks(bool user_only)
bool wakeup = false;
int sleep_usecs = USEC_PER_MSEC;
+ pr_info("Freezing %s\n", what);
+
start = ktime_get_boottime();
end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs);
@@ -82,9 +86,8 @@ static int try_to_freeze_tasks(bool user_only)
elapsed_msecs = ktime_to_ms(elapsed);
if (todo) {
- pr_cont("\n");
- pr_err("Freezing of tasks %s after %d.%03d seconds "
- "(%d tasks refusing to freeze, wq_busy=%d):\n",
+ pr_err("Freezing %s %s after %d.%03d seconds "
+ "(%d tasks refusing to freeze, wq_busy=%d):\n", what,
wakeup ? "aborted" : "failed",
elapsed_msecs / 1000, elapsed_msecs % 1000,
todo - wq_busy, wq_busy);
@@ -101,8 +104,8 @@ static int try_to_freeze_tasks(bool user_only)
read_unlock(&tasklist_lock);
}
} else {
- pr_cont("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
- elapsed_msecs % 1000);
+ pr_info("Freezing %s completed (elapsed %d.%03d seconds)\n",
+ what, elapsed_msecs / 1000, elapsed_msecs % 1000);
}
return todo ? -EBUSY : 0;
@@ -130,14 +133,11 @@ int freeze_processes(void)
static_branch_inc(&freezer_active);
pm_wakeup_clear(0);
- pr_info("Freezing user space processes ... ");
pm_freezing = true;
error = try_to_freeze_tasks(true);
- if (!error) {
+ if (!error)
__usermodehelper_set_disable_depth(UMH_DISABLED);
- pr_cont("done.");
- }
- pr_cont("\n");
+
BUG_ON(in_atomic());
/*
@@ -166,14 +166,9 @@ int freeze_kernel_threads(void)
{
int error;
- pr_info("Freezing remaining freezable tasks ... ");
-
pm_nosig_freezing = true;
error = try_to_freeze_tasks(false);
- if (!error)
- pr_cont("done.");
- pr_cont("\n");
BUG_ON(in_atomic());
if (error)
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 2a406753af90..cd8b7b35f1e8 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1723,8 +1723,8 @@ static unsigned long minimum_image_size(unsigned long saveable)
* /sys/power/reserved_size, respectively). To make this happen, we compute the
* total number of available page frames and allocate at least
*
- * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2
- * + 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE)
+ * ([page frames total] - PAGES_FOR_IO - [metadata pages]) / 2
+ * - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE)
*
* of them, which corresponds to the maximum size of a hibernation image.
*
@@ -2259,10 +2259,14 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
if (unlikely(buf[j] == BM_END_OF_MAP))
break;
- if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j]))
+ if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j])) {
memory_bm_set_bit(bm, buf[j]);
- else
+ } else {
+ if (!pfn_valid(buf[j]))
+ pr_err(FW_BUG "Memory map mismatch at 0x%llx after hibernation\n",
+ (unsigned long long)PFN_PHYS(buf[j]));
return -EFAULT;
+ }
}
return 0;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e4f1e7478b52..7decf1e9c486 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -79,13 +79,20 @@ int oops_in_progress;
EXPORT_SYMBOL(oops_in_progress);
/*
- * console_sem protects the console_drivers list, and also
- * provides serialisation for access to the entire console
- * driver system.
+ * console_mutex protects console_list updates and console->flags updates.
+ * The flags are synchronized only for consoles that are registered, i.e.
+ * accessible via the console list.
+ */
+static DEFINE_MUTEX(console_mutex);
+
+/*
+ * console_sem protects updates to console->seq and console_suspended,
+ * and also provides serialization for console printing.
*/
static DEFINE_SEMAPHORE(console_sem);
-struct console *console_drivers;
-EXPORT_SYMBOL_GPL(console_drivers);
+HLIST_HEAD(console_list);
+EXPORT_SYMBOL_GPL(console_list);
+DEFINE_STATIC_SRCU(console_srcu);
/*
* System may need to suppress printk message under certain
@@ -103,6 +110,19 @@ static int __read_mostly suppress_panic_printk;
static struct lockdep_map console_lock_dep_map = {
.name = "console_lock"
};
+
+void lockdep_assert_console_list_lock_held(void)
+{
+ lockdep_assert_held(&console_mutex);
+}
+EXPORT_SYMBOL(lockdep_assert_console_list_lock_held);
+#endif
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+bool console_srcu_read_lock_is_held(void)
+{
+ return srcu_read_lock_held(&console_srcu);
+}
#endif
enum devkmsg_log_bits {
@@ -220,6 +240,69 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
}
#endif /* CONFIG_PRINTK && CONFIG_SYSCTL */
+/**
+ * console_list_lock - Lock the console list
+ *
+ * For console list or console->flags updates
+ */
+void console_list_lock(void)
+{
+ /*
+ * In unregister_console() and console_force_preferred_locked(),
+ * synchronize_srcu() is called with the console_list_lock held.
+ * Therefore it is not allowed that the console_list_lock is taken
+ * with the srcu_lock held.
+ *
+ * Detecting if this context is really in the read-side critical
+ * section is only possible if the appropriate debug options are
+ * enabled.
+ */
+ WARN_ON_ONCE(debug_lockdep_rcu_enabled() &&
+ srcu_read_lock_held(&console_srcu));
+
+ mutex_lock(&console_mutex);
+}
+EXPORT_SYMBOL(console_list_lock);
+
+/**
+ * console_list_unlock - Unlock the console list
+ *
+ * Counterpart to console_list_lock()
+ */
+void console_list_unlock(void)
+{
+ mutex_unlock(&console_mutex);
+}
+EXPORT_SYMBOL(console_list_unlock);
+
+/**
+ * console_srcu_read_lock - Register a new reader for the
+ * SRCU-protected console list
+ *
+ * Use for_each_console_srcu() to iterate the console list
+ *
+ * Context: Any context.
+ * Return: A cookie to pass to console_srcu_read_unlock().
+ */
+int console_srcu_read_lock(void)
+{
+ return srcu_read_lock_nmisafe(&console_srcu);
+}
+EXPORT_SYMBOL(console_srcu_read_lock);
+
+/**
+ * console_srcu_read_unlock - Unregister an old reader from
+ * the SRCU-protected console list
+ * @cookie: cookie returned from console_srcu_read_lock()
+ *
+ * Counterpart to console_srcu_read_lock()
+ */
+void console_srcu_read_unlock(int cookie)
+{
+ srcu_read_unlock_nmisafe(&console_srcu, cookie);
+}
+EXPORT_SYMBOL(console_srcu_read_unlock);
+
/*
* Helper macros to handle lockdep when locking/unlocking console_sem. We use
* macros instead of functions so that _RET_IP_ contains useful information.
@@ -1814,13 +1897,13 @@ static void console_lock_spinning_enable(void)
* safe to start busy waiting for the lock. Second, it checks if
* there is a busy waiter and passes the lock rights to her.
*
- * Important: Callers lose the lock if there was a busy waiter.
- * They must not touch items synchronized by console_lock
- * in this case.
+ * Important: Callers lose both the console_lock and the SRCU read lock if
+ * there was a busy waiter. They must not touch items synchronized by
+ * console_lock or SRCU read lock in this case.
*
* Return: 1 if the lock rights were passed, 0 otherwise.
*/
-static int console_lock_spinning_disable_and_check(void)
+static int console_lock_spinning_disable_and_check(int cookie)
{
int waiter;
@@ -1840,6 +1923,12 @@ static int console_lock_spinning_disable_and_check(void)
spin_release(&console_owner_dep_map, _THIS_IP_);
/*
+ * Preserve lockdep lock ordering. Release the SRCU read lock before
+ * releasing the console_lock.
+ */
+ console_srcu_read_unlock(cookie);
+
+ /*
* Hand off console_lock to waiter. The waiter will perform
* the up(). After this, the waiter is the console_lock owner.
*/
@@ -2322,7 +2411,7 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
char *text, size_t text_len,
struct dev_printk_info *dev_info) { return 0; }
static void console_lock_spinning_enable(void) { }
-static int console_lock_spinning_disable_and_check(void) { return 0; }
+static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
static void call_console_driver(struct console *con, const char *text, size_t len,
char *dropped_text)
{
@@ -2391,7 +2480,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
return -E2BIG;
if (!brl_options)
preferred_console = i;
- strlcpy(c->name, name, sizeof(c->name));
+ strscpy(c->name, name, sizeof(c->name));
c->options = options;
set_user_specified(c, user_specified);
braille_set_options(c, brl_options);
@@ -2553,10 +2642,10 @@ static int console_cpu_notify(unsigned int cpu)
}
/**
- * console_lock - lock the console system for exclusive use.
+ * console_lock - block the console subsystem from printing
*
- * Acquires a lock which guarantees that the caller has
- * exclusive access to the console system and the console_drivers list.
+ * Acquires a lock which guarantees that no consoles will
+ * be in or enter their write() callback.
*
* Can sleep, returns nothing.
*/
@@ -2573,10 +2662,10 @@ void console_lock(void)
EXPORT_SYMBOL(console_lock);
/**
- * console_trylock - try to lock the console system for exclusive use.
+ * console_trylock - try to block the console subsystem from printing
*
- * Try to acquire a lock which guarantees that the caller has exclusive
- * access to the console system and the console_drivers list.
+ * Try to acquire a lock which guarantees that no consoles will
+ * be in or enter their write() callback.
*
* returns 1 on success, and 0 on failure to acquire the lock.
*/
@@ -2623,11 +2712,13 @@ static bool abandon_console_lock_in_panic(void)
* Check if the given console is currently capable and allowed to print
* records.
*
- * Requires the console_lock.
+ * Requires the console_srcu_read_lock.
*/
static inline bool console_is_usable(struct console *con)
{
- if (!(con->flags & CON_ENABLED))
+ short flags = console_srcu_read_flags(con);
+
+ if (!(flags & CON_ENABLED))
return false;
if (!con->write)
@@ -2638,8 +2729,7 @@ static inline bool console_is_usable(struct console *con)
* allocated. So unless they're explicitly marked as being able to
* cope (CON_ANYTIME) don't call them until this CPU is officially up.
*/
- if (!cpu_online(raw_smp_processor_id()) &&
- !(con->flags & CON_ANYTIME))
+ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
return false;
return true;
@@ -2664,16 +2754,18 @@ static void __console_unlock(void)
* DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL.
*
* @handover will be set to true if a printk waiter has taken over the
- * console_lock, in which case the caller is no longer holding the
- * console_lock. Otherwise it is set to false.
+ * console_lock, in which case the caller is no longer holding both the
+ * console_lock and the SRCU read lock. Otherwise it is set to false.
+ *
+ * @cookie is the cookie from the SRCU read lock.
*
* Returns false if the given console has no next record to print, otherwise
* true.
*
- * Requires the console_lock.
+ * Requires the console_lock and the SRCU read lock.
*/
static bool console_emit_next_record(struct console *con, char *text, char *ext_text,
- char *dropped_text, bool *handover)
+ char *dropped_text, bool *handover, int cookie)
{
static int panic_console_dropped;
struct printk_info info;
@@ -2733,7 +2825,7 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
con->seq++;
- *handover = console_lock_spinning_disable_and_check();
+ *handover = console_lock_spinning_disable_and_check(cookie);
printk_safe_exit_irqrestore(flags);
skip:
return true;
@@ -2770,6 +2862,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
bool any_usable = false;
struct console *con;
bool any_progress;
+ int cookie;
*next_seq = 0;
*handover = false;
@@ -2777,23 +2870,29 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
do {
any_progress = false;
- for_each_console(con) {
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(con) {
bool progress;
if (!console_is_usable(con))
continue;
any_usable = true;
- if (con->flags & CON_EXTENDED) {
+ if (console_srcu_read_flags(con) & CON_EXTENDED) {
/* Extended consoles do not print "dropped messages". */
progress = console_emit_next_record(con, &text[0],
&ext_text[0], NULL,
- handover);
+ handover, cookie);
} else {
progress = console_emit_next_record(con, &text[0],
NULL, &dropped_text[0],
- handover);
+ handover, cookie);
}
+
+ /*
+ * If a handover has occurred, the SRCU read lock
+ * is already released.
+ */
if (*handover)
return false;
@@ -2807,21 +2906,26 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
/* Allow panic_cpu to take over the consoles safely. */
if (abandon_console_lock_in_panic())
- return false;
+ goto abandon;
if (do_cond_resched)
cond_resched();
}
+ console_srcu_read_unlock(cookie);
} while (any_progress);
return any_usable;
+
+abandon:
+ console_srcu_read_unlock(cookie);
+ return false;
}
/**
- * console_unlock - unlock the console system
+ * console_unlock - unblock the console subsystem from printing
*
- * Releases the console_lock which the caller holds on the console system
- * and the console driver list.
+ * Releases the console_lock which the caller holds to block printing of
+ * the console subsystem.
*
* While the console_lock was held, console output may have been buffered
* by printk(). If this is the case, console_unlock(); emits
@@ -2899,10 +3003,14 @@ EXPORT_SYMBOL(console_conditional_schedule);
void console_unblank(void)
{
struct console *c;
+ int cookie;
/*
- * console_unblank can no longer be called in interrupt context unless
- * oops_in_progress is set to 1..
+ * Stop console printing because the unblank() callback may
+ * assume the console is not within its write() callback.
+ *
+ * If @oops_in_progress is set, this may be an atomic context.
+ * In that case, attempt a trylock as best-effort.
*/
if (oops_in_progress) {
if (down_trylock_console_sem() != 0)
@@ -2912,9 +3020,14 @@ void console_unblank(void)
console_locked = 1;
console_may_schedule = 0;
- for_each_console(c)
- if ((c->flags & CON_ENABLED) && c->unblank)
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+ if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank)
c->unblank();
+ }
+ console_srcu_read_unlock(cookie);
+
console_unlock();
if (!oops_in_progress)
@@ -2941,11 +3054,21 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL) {
struct console *c;
+ int cookie;
u64 seq;
seq = prb_first_valid_seq(prb);
- for_each_console(c)
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+ /*
+ * If the above console_trylock() failed, this is an
+ * unsynchronized assignment. But in that case, the
+ * kernel is in "hope and pray" mode anyway.
+ */
c->seq = seq;
+ }
+ console_srcu_read_unlock(cookie);
}
console_unlock();
}
@@ -2957,15 +3080,25 @@ struct tty_driver *console_device(int *index)
{
struct console *c;
struct tty_driver *driver = NULL;
+ int cookie;
+ /*
+ * Take console_lock to serialize device() callback with
+ * other console operations. For example, fg_console is
+ * modified under console_lock when switching vt.
+ */
console_lock();
- for_each_console(c) {
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
if (!c->device)
continue;
driver = c->device(c, index);
if (driver)
break;
}
+ console_srcu_read_unlock(cookie);
+
console_unlock();
return driver;
}
@@ -2978,17 +3111,25 @@ struct tty_driver *console_device(int *index)
void console_stop(struct console *console)
{
__pr_flush(console, 1000, true);
- console_lock();
- console->flags &= ~CON_ENABLED;
- console_unlock();
+ console_list_lock();
+ console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
+ console_list_unlock();
+
+ /*
+ * Ensure that all SRCU list walks have completed. All contexts must
+ * be able to see that this console is disabled so that (for example)
+ * the caller can suspend the port without risk of another context
+ * using the port.
+ */
+ synchronize_srcu(&console_srcu);
}
EXPORT_SYMBOL(console_stop);
void console_start(struct console *console)
{
- console_lock();
- console->flags |= CON_ENABLED;
- console_unlock();
+ console_list_lock();
+ console_srcu_write_flags(console, console->flags | CON_ENABLED);
+ console_list_unlock();
__pr_flush(console, 1000, true);
}
EXPORT_SYMBOL(console_start);
@@ -3081,6 +3222,72 @@ static void try_enable_default_console(struct console *newcon)
(con->flags & CON_BOOT) ? "boot" : "", \
con->name, con->index, ##__VA_ARGS__)
+static void console_init_seq(struct console *newcon, bool bootcon_registered)
+{
+ struct console *con;
+ bool handover;
+
+ if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
+ /* Get a consistent copy of @syslog_seq. */
+ mutex_lock(&syslog_lock);
+ newcon->seq = syslog_seq;
+ mutex_unlock(&syslog_lock);
+ } else {
+ /* Begin with next message added to ringbuffer. */
+ newcon->seq = prb_next_seq(prb);
+
+ /*
+ * If any enabled boot consoles are due to be unregistered
+ * shortly, some may not be caught up and may be the same
+ * device as @newcon. Since it is not known which boot console
+ * is the same device, flush all consoles and, if necessary,
+ * start with the message of the enabled boot console that is
+ * the furthest behind.
+ */
+ if (bootcon_registered && !keep_bootcon) {
+ /*
+ * Hold the console_lock to stop console printing and
+ * guarantee safe access to console->seq.
+ */
+ console_lock();
+
+ /*
+ * Flush all consoles and set the console to start at
+ * the next unprinted sequence number.
+ */
+ if (!console_flush_all(true, &newcon->seq, &handover)) {
+ /*
+ * Flushing failed. Just choose the lowest
+ * sequence of the enabled boot consoles.
+ */
+
+ /*
+ * If there was a handover, this context no
+ * longer holds the console_lock.
+ */
+ if (handover)
+ console_lock();
+
+ newcon->seq = prb_next_seq(prb);
+ for_each_console(con) {
+ if ((con->flags & CON_BOOT) &&
+ (con->flags & CON_ENABLED) &&
+ con->seq < newcon->seq) {
+ newcon->seq = con->seq;
+ }
+ }
+ }
+
+ console_unlock();
+ }
+ }
+}
+
+#define console_first() \
+ hlist_entry(console_list.first, struct console, node)
+
+static int unregister_console_locked(struct console *console);
+
/*
* The console driver calls this routine during kernel initialization
* to register the console printing procedure with printk() and to
@@ -3103,28 +3310,29 @@ static void try_enable_default_console(struct console *newcon)
void register_console(struct console *newcon)
{
struct console *con;
- bool bootcon_enabled = false;
- bool realcon_enabled = false;
+ bool bootcon_registered = false;
+ bool realcon_registered = false;
int err;
+ console_list_lock();
+
for_each_console(con) {
if (WARN(con == newcon, "console '%s%d' already registered\n",
- con->name, con->index))
- return;
- }
+ con->name, con->index)) {
+ goto unlock;
+ }
- for_each_console(con) {
if (con->flags & CON_BOOT)
- bootcon_enabled = true;
+ bootcon_registered = true;
else
- realcon_enabled = true;
+ realcon_registered = true;
}
/* Do not register boot consoles when there already is a real one. */
- if (newcon->flags & CON_BOOT && realcon_enabled) {
+ if ((newcon->flags & CON_BOOT) && realcon_registered) {
pr_info("Too late to register bootconsole %s%d\n",
newcon->name, newcon->index);
- return;
+ goto unlock;
}
/*
@@ -3140,8 +3348,8 @@ void register_console(struct console *newcon)
* flag set and will be first in the list.
*/
if (preferred_console < 0) {
- if (!console_drivers || !console_drivers->device ||
- console_drivers->flags & CON_BOOT) {
+ if (hlist_empty(&console_list) || !console_first()->device ||
+ console_first()->flags & CON_BOOT) {
try_enable_default_console(newcon);
}
}
@@ -3155,7 +3363,7 @@ void register_console(struct console *newcon)
/* printk() messages are not printed to the Braille console. */
if (err || newcon->flags & CON_BRL)
- return;
+ goto unlock;
/*
* If we have a bootconsole, and are switching to a real console,
@@ -3163,39 +3371,38 @@ void register_console(struct console *newcon)
* the real console are the same physical device, it's annoying to
* see the beginning boot messages twice
*/
- if (bootcon_enabled &&
+ if (bootcon_registered &&
((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
newcon->flags &= ~CON_PRINTBUFFER;
}
+ newcon->dropped = 0;
+ console_init_seq(newcon, bootcon_registered);
+
/*
- * Put this console in the list - keep the
- * preferred driver at the head of the list.
+ * Put this console in the list - keep the
+ * preferred driver at the head of the list.
*/
- console_lock();
- if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
- newcon->next = console_drivers;
- console_drivers = newcon;
- if (newcon->next)
- newcon->next->flags &= ~CON_CONSDEV;
- /* Ensure this flag is always set for the head of the list */
+ if (hlist_empty(&console_list)) {
+ /* Ensure CON_CONSDEV is always set for the head. */
newcon->flags |= CON_CONSDEV;
- } else {
- newcon->next = console_drivers->next;
- console_drivers->next = newcon;
- }
+ hlist_add_head_rcu(&newcon->node, &console_list);
+
+ } else if (newcon->flags & CON_CONSDEV) {
+ /* Only the new head can have CON_CONSDEV set. */
+ console_srcu_write_flags(console_first(), console_first()->flags & ~CON_CONSDEV);
+ hlist_add_head_rcu(&newcon->node, &console_list);
- newcon->dropped = 0;
- if (newcon->flags & CON_PRINTBUFFER) {
- /* Get a consistent copy of @syslog_seq. */
- mutex_lock(&syslog_lock);
- newcon->seq = syslog_seq;
- mutex_unlock(&syslog_lock);
} else {
- /* Begin with next message. */
- newcon->seq = prb_next_seq(prb);
+ hlist_add_behind_rcu(&newcon->node, console_list.first);
}
- console_unlock();
+
+ /*
+ * No need to synchronize SRCU here! The caller does not rely
+ * on all contexts being able to see the new console before
+ * register_console() completes.
+ */
+
console_sysfs_notify();
/*
@@ -3206,21 +3413,28 @@ void register_console(struct console *newcon)
* went to the bootconsole (that they do not see on the real console)
*/
con_printk(KERN_INFO, newcon, "enabled\n");
- if (bootcon_enabled &&
+ if (bootcon_registered &&
((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
!keep_bootcon) {
- for_each_console(con)
+ struct hlist_node *tmp;
+
+ hlist_for_each_entry_safe(con, tmp, &console_list, node) {
if (con->flags & CON_BOOT)
- unregister_console(con);
+ unregister_console_locked(con);
+ }
}
+unlock:
+ console_list_unlock();
}
EXPORT_SYMBOL(register_console);
-int unregister_console(struct console *console)
+/* Must be called under console_list_lock(). */
+static int unregister_console_locked(struct console *console)
{
- struct console *con;
int res;
+ lockdep_assert_console_list_lock_held();
+
con_printk(KERN_INFO, console, "disabled\n");
res = _braille_unregister_console(console);
@@ -3229,48 +3443,94 @@ int unregister_console(struct console *console)
if (res > 0)
return 0;
- res = -ENODEV;
- console_lock();
- if (console_drivers == console) {
- console_drivers=console->next;
- res = 0;
- } else {
- for_each_console(con) {
- if (con->next == console) {
- con->next = console->next;
- res = 0;
- break;
- }
- }
- }
+ /* Disable it unconditionally */
+ console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
+
+ if (!console_is_registered_locked(console))
+ return -ENODEV;
- if (res)
- goto out_disable_unlock;
+ hlist_del_init_rcu(&console->node);
/*
+ * <HISTORICAL>
* If this isn't the last console and it has CON_CONSDEV set, we
* need to set it on the next preferred console.
+ * </HISTORICAL>
+ *
+ * The above makes no sense as there is no guarantee that the next
+ * console has any device attached. Oh well....
*/
- if (console_drivers != NULL && console->flags & CON_CONSDEV)
- console_drivers->flags |= CON_CONSDEV;
+ if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV)
+ console_srcu_write_flags(console_first(), console_first()->flags | CON_CONSDEV);
+
+ /*
+ * Ensure that all SRCU list walks have completed. All contexts
+ * must not be able to see this console in the list so that any
+ * exit/cleanup routines can be performed safely.
+ */
+ synchronize_srcu(&console_srcu);
- console->flags &= ~CON_ENABLED;
- console_unlock();
console_sysfs_notify();
if (console->exit)
res = console->exit(console);
return res;
+}
-out_disable_unlock:
- console->flags &= ~CON_ENABLED;
- console_unlock();
+int unregister_console(struct console *console)
+{
+ int res;
+ console_list_lock();
+ res = unregister_console_locked(console);
+ console_list_unlock();
return res;
}
EXPORT_SYMBOL(unregister_console);
+/**
+ * console_force_preferred_locked - force a registered console preferred
+ * @con: The registered console to force preferred.
+ *
+ * Must be called under console_list_lock().
+ */
+void console_force_preferred_locked(struct console *con)
+{
+ struct console *cur_pref_con;
+
+ if (!console_is_registered_locked(con))
+ return;
+
+ cur_pref_con = console_first();
+
+ /* Already preferred? */
+ if (cur_pref_con == con)
+ return;
+
+ /*
+ * Delete, but do not re-initialize the entry. This allows the console
+ * to continue to appear registered (via any hlist_unhashed_lockless()
+ * checks), even though it was briefly removed from the console list.
+ */
+ hlist_del_rcu(&con->node);
+
+ /*
+ * Ensure that all SRCU list walks have completed so that the console
+ * can be added to the beginning of the console list and its forward
+ * list pointer can be re-initialized.
+ */
+ synchronize_srcu(&console_srcu);
+
+ con->flags |= CON_CONSDEV;
+ WARN_ON(!con->device);
+
+ /* Only the new head can have CON_CONSDEV set. */
+ console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
+ hlist_add_head_rcu(&con->node, &console_list);
+}
+EXPORT_SYMBOL(console_force_preferred_locked);
+
/*
* Initialize the console device. This is called *early*, so
* we can't necessarily depend on lots of kernel help here.
@@ -3317,10 +3577,12 @@ void __init console_init(void)
*/
static int __init printk_late_init(void)
{
+ struct hlist_node *tmp;
struct console *con;
int ret;
- for_each_console(con) {
+ console_list_lock();
+ hlist_for_each_entry_safe(con, tmp, &console_list, node) {
if (!(con->flags & CON_BOOT))
continue;
@@ -3337,9 +3599,11 @@ static int __init printk_late_init(void)
*/
pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n",
con->name, con->index);
- unregister_console(con);
+ unregister_console_locked(con);
}
}
+ console_list_unlock();
+
ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL,
console_cpu_notify);
WARN_ON(ret < 0);
@@ -3359,6 +3623,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
struct console *c;
u64 last_diff = 0;
u64 printk_seq;
+ int cookie;
u64 diff;
u64 seq;
@@ -3369,9 +3634,15 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
for (;;) {
diff = 0;
+ /*
+ * Hold the console_lock to guarantee safe access to
+ * console->seq and to prevent changes to @console_suspended
+ * until all consoles have been processed.
+ */
console_lock();
- for_each_console(c) {
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
if (con && con != c)
continue;
if (!console_is_usable(c))
@@ -3380,6 +3651,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
if (printk_seq < seq)
diff += seq - printk_seq;
}
+ console_srcu_read_unlock(cookie);
/*
* If consoles are suspended, it cannot be expected that they
diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c
index 2b7b6ddab4f7..2dc4d5a1f1ff 100644
--- a/kernel/printk/printk_ringbuffer.c
+++ b/kernel/printk/printk_ringbuffer.c
@@ -203,7 +203,7 @@
* prb_rec_init_wr(&r, 5);
*
* // try to extend, but only if it does not exceed 32 bytes
- * if (prb_reserve_in_last(&e, &test_rb, &r, printk_caller_id()), 32) {
+ * if (prb_reserve_in_last(&e, &test_rb, &r, printk_caller_id(), 32)) {
* snprintf(&r.text_buf[r.info->text_len],
* r.text_buf_size - r.info->text_len, "hello");
*
diff --git a/kernel/rcu/Kconfig b/kernel/rcu/Kconfig
index d471d22a5e21..ab62074174c3 100644
--- a/kernel/rcu/Kconfig
+++ b/kernel/rcu/Kconfig
@@ -54,27 +54,25 @@ config RCU_EXPERT
Say N if you are unsure.
config SRCU
- bool
- help
- This option selects the sleepable version of RCU. This version
- permits arbitrary sleeping or blocking within RCU read-side critical
- sections.
+ def_bool y
config TINY_SRCU
bool
- default y if SRCU && TINY_RCU
+ default y if TINY_RCU
help
This option selects the single-CPU non-preemptible version of SRCU.
config TREE_SRCU
bool
- default y if SRCU && !TINY_RCU
+ default y if !TINY_RCU
help
This option selects the full-fledged version of SRCU.
+config NEED_SRCU_NMI_SAFE
+ def_bool HAVE_NMI && !ARCH_HAS_NMI_SAFE_THIS_CPU_OPS && !TINY_SRCU
+
config TASKS_RCU_GENERIC
def_bool TASKS_RCU || TASKS_RUDE_RCU || TASKS_TRACE_RCU
- select SRCU
help
This option enables generic infrastructure code supporting
task-based RCU implementations. Not for manual selection.
@@ -311,4 +309,12 @@ config TASKS_TRACE_RCU_READ_MB
Say N here if you hate read-side memory barriers.
Take the default if you are unsure.
+config RCU_LAZY
+ bool "RCU callback lazy invocation functionality"
+ depends on RCU_NOCB_CPU
+ default n
+ help
+ To save power, batch RCU callbacks and flush after delay, memory
+ pressure, or callback list growing too big.
+
endmenu # "RCU Subsystem"
diff --git a/kernel/rcu/Kconfig.debug b/kernel/rcu/Kconfig.debug
index 1b0c41d490f0..232e29fe3e5e 100644
--- a/kernel/rcu/Kconfig.debug
+++ b/kernel/rcu/Kconfig.debug
@@ -27,7 +27,6 @@ config RCU_SCALE_TEST
tristate "performance tests for RCU"
depends on DEBUG_KERNEL
select TORTURE_TEST
- select SRCU
default n
help
This option provides a kernel module that runs performance
@@ -43,7 +42,6 @@ config RCU_TORTURE_TEST
tristate "torture tests for RCU"
depends on DEBUG_KERNEL
select TORTURE_TEST
- select SRCU
default n
help
This option provides a kernel module that runs torture tests
@@ -59,7 +57,6 @@ config RCU_REF_SCALE_TEST
tristate "Scalability tests for read-side synchronization (RCU and others)"
depends on DEBUG_KERNEL
select TORTURE_TEST
- select SRCU
default n
help
This option provides a kernel module that runs performance tests
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index be5979da07f5..c5aa934de59b 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -286,7 +286,7 @@ void rcu_test_sync_prims(void);
*/
extern void resched_cpu(int cpu);
-#if defined(CONFIG_SRCU) || !defined(CONFIG_TINY_RCU)
+#if !defined(CONFIG_TINY_RCU)
#include <linux/rcu_node_tree.h>
@@ -375,6 +375,10 @@ extern void rcu_init_geometry(void);
(cpu) <= rnp->grphi; \
(cpu) = rcu_find_next_bit((rnp), (cpu) + 1 - (rnp->grplo), (mask)))
+#endif /* !defined(CONFIG_TINY_RCU) */
+
+#if !defined(CONFIG_TINY_RCU) || defined(CONFIG_TASKS_RCU_GENERIC)
+
/*
* Wrappers for the rcu_node::lock acquire and release.
*
@@ -437,7 +441,7 @@ do { \
#define raw_lockdep_assert_held_rcu_node(p) \
lockdep_assert_held(&ACCESS_PRIVATE(p, lock))
-#endif /* #if defined(CONFIG_SRCU) || !defined(CONFIG_TINY_RCU) */
+#endif // #if !defined(CONFIG_TINY_RCU) || defined(CONFIG_TASKS_RCU_GENERIC)
#ifdef CONFIG_TINY_RCU
/* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */
@@ -474,6 +478,14 @@ enum rcutorture_type {
INVALID_RCU_FLAVOR
};
+#if defined(CONFIG_RCU_LAZY)
+unsigned long rcu_lazy_get_jiffies_till_flush(void);
+void rcu_lazy_set_jiffies_till_flush(unsigned long j);
+#else
+static inline unsigned long rcu_lazy_get_jiffies_till_flush(void) { return 0; }
+static inline void rcu_lazy_set_jiffies_till_flush(unsigned long j) { }
+#endif
+
#if defined(CONFIG_TREE_RCU)
void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags,
unsigned long *gp_seq);
diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
index 3ef02d4a8108..91fb5905a008 100644
--- a/kernel/rcu/rcuscale.c
+++ b/kernel/rcu/rcuscale.c
@@ -95,6 +95,7 @@ torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() scale test?");
torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.");
+torture_param(int, kfree_by_call_rcu, 0, "Use call_rcu() to emulate kfree_rcu()?");
static char *scale_type = "rcu";
module_param(scale_type, charp, 0444);
@@ -175,7 +176,7 @@ static struct rcu_scale_ops rcu_ops = {
.get_gp_seq = rcu_get_gp_seq,
.gp_diff = rcu_seq_diff,
.exp_completed = rcu_exp_batches_completed,
- .async = call_rcu,
+ .async = call_rcu_hurry,
.gp_barrier = rcu_barrier,
.sync = synchronize_rcu,
.exp_sync = synchronize_rcu_expedited,
@@ -659,6 +660,14 @@ struct kfree_obj {
struct rcu_head rh;
};
+/* Used if doing RCU-kfree'ing via call_rcu(). */
+static void kfree_call_rcu(struct rcu_head *rh)
+{
+ struct kfree_obj *obj = container_of(rh, struct kfree_obj, rh);
+
+ kfree(obj);
+}
+
static int
kfree_scale_thread(void *arg)
{
@@ -696,6 +705,11 @@ kfree_scale_thread(void *arg)
if (!alloc_ptr)
return -ENOMEM;
+ if (kfree_by_call_rcu) {
+ call_rcu(&(alloc_ptr->rh), kfree_call_rcu);
+ continue;
+ }
+
// By default kfree_rcu_test_single and kfree_rcu_test_double are
// initialized to false. If both have the same value (false or true)
// both are randomly tested, otherwise only the one with value true
@@ -767,11 +781,58 @@ kfree_scale_shutdown(void *arg)
return -EINVAL;
}
+// Used if doing RCU-kfree'ing via call_rcu().
+static unsigned long jiffies_at_lazy_cb;
+static struct rcu_head lazy_test1_rh;
+static int rcu_lazy_test1_cb_called;
+static void call_rcu_lazy_test1(struct rcu_head *rh)
+{
+ jiffies_at_lazy_cb = jiffies;
+ WRITE_ONCE(rcu_lazy_test1_cb_called, 1);
+}
+
static int __init
kfree_scale_init(void)
{
- long i;
int firsterr = 0;
+ long i;
+ unsigned long jif_start;
+ unsigned long orig_jif;
+
+ // Also, do a quick self-test to ensure laziness is as much as
+ // expected.
+ if (kfree_by_call_rcu && !IS_ENABLED(CONFIG_RCU_LAZY)) {
+ pr_alert("CONFIG_RCU_LAZY is disabled, falling back to kfree_rcu() for delayed RCU kfree'ing\n");
+ kfree_by_call_rcu = 0;
+ }
+
+ if (kfree_by_call_rcu) {
+ /* do a test to check the timeout. */
+ orig_jif = rcu_lazy_get_jiffies_till_flush();
+
+ rcu_lazy_set_jiffies_till_flush(2 * HZ);
+ rcu_barrier();
+
+ jif_start = jiffies;
+ jiffies_at_lazy_cb = 0;
+ call_rcu(&lazy_test1_rh, call_rcu_lazy_test1);
+
+ smp_cond_load_relaxed(&rcu_lazy_test1_cb_called, VAL == 1);
+
+ rcu_lazy_set_jiffies_till_flush(orig_jif);
+
+ if (WARN_ON_ONCE(jiffies_at_lazy_cb - jif_start < 2 * HZ)) {
+ pr_alert("ERROR: call_rcu() CBs are not being lazy as expected!\n");
+ WARN_ON_ONCE(1);
+ return -1;
+ }
+
+ if (WARN_ON_ONCE(jiffies_at_lazy_cb - jif_start > 3 * HZ)) {
+ pr_alert("ERROR: call_rcu() CBs are being too lazy!\n");
+ WARN_ON_ONCE(1);
+ return -1;
+ }
+ }
kfree_nrealthreads = compute_real(kfree_nthreads);
/* Start up the kthreads. */
@@ -784,7 +845,9 @@ kfree_scale_init(void)
schedule_timeout_uninterruptible(1);
}
- pr_alert("kfree object size=%zu\n", kfree_mult * sizeof(struct kfree_obj));
+ pr_alert("kfree object size=%zu, kfree_by_call_rcu=%d\n",
+ kfree_mult * sizeof(struct kfree_obj),
+ kfree_by_call_rcu);
kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
GFP_KERNEL);
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 503c2aa845a4..634df26a2c27 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -357,6 +357,10 @@ struct rcu_torture_ops {
bool (*poll_gp_state_exp)(unsigned long oldstate);
void (*cond_sync_exp)(unsigned long oldstate);
void (*cond_sync_exp_full)(struct rcu_gp_oldstate *rgosp);
+ unsigned long (*get_comp_state)(void);
+ void (*get_comp_state_full)(struct rcu_gp_oldstate *rgosp);
+ bool (*same_gp_state)(unsigned long oldstate1, unsigned long oldstate2);
+ bool (*same_gp_state_full)(struct rcu_gp_oldstate *rgosp1, struct rcu_gp_oldstate *rgosp2);
unsigned long (*get_gp_state)(void);
void (*get_gp_state_full)(struct rcu_gp_oldstate *rgosp);
unsigned long (*get_gp_completed)(void);
@@ -510,7 +514,7 @@ static unsigned long rcu_no_completed(void)
static void rcu_torture_deferred_free(struct rcu_torture *p)
{
- call_rcu(&p->rtort_rcu, rcu_torture_cb);
+ call_rcu_hurry(&p->rtort_rcu, rcu_torture_cb);
}
static void rcu_sync_torture_init(void)
@@ -535,6 +539,10 @@ static struct rcu_torture_ops rcu_ops = {
.deferred_free = rcu_torture_deferred_free,
.sync = synchronize_rcu,
.exp_sync = synchronize_rcu_expedited,
+ .same_gp_state = same_state_synchronize_rcu,
+ .same_gp_state_full = same_state_synchronize_rcu_full,
+ .get_comp_state = get_completed_synchronize_rcu,
+ .get_comp_state_full = get_completed_synchronize_rcu_full,
.get_gp_state = get_state_synchronize_rcu,
.get_gp_state_full = get_state_synchronize_rcu_full,
.get_gp_completed = get_completed_synchronize_rcu,
@@ -551,7 +559,7 @@ static struct rcu_torture_ops rcu_ops = {
.start_gp_poll_exp_full = start_poll_synchronize_rcu_expedited_full,
.poll_gp_state_exp = poll_state_synchronize_rcu,
.cond_sync_exp = cond_synchronize_rcu_expedited,
- .call = call_rcu,
+ .call = call_rcu_hurry,
.cb_barrier = rcu_barrier,
.fqs = rcu_force_quiescent_state,
.stats = NULL,
@@ -615,10 +623,14 @@ static struct rcu_torture_ops rcu_busted_ops = {
DEFINE_STATIC_SRCU(srcu_ctl);
static struct srcu_struct srcu_ctld;
static struct srcu_struct *srcu_ctlp = &srcu_ctl;
+static struct rcu_torture_ops srcud_ops;
static int srcu_torture_read_lock(void) __acquires(srcu_ctlp)
{
- return srcu_read_lock(srcu_ctlp);
+ if (cur_ops == &srcud_ops)
+ return srcu_read_lock_nmisafe(srcu_ctlp);
+ else
+ return srcu_read_lock(srcu_ctlp);
}
static void
@@ -642,7 +654,10 @@ srcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
static void srcu_torture_read_unlock(int idx) __releases(srcu_ctlp)
{
- srcu_read_unlock(srcu_ctlp, idx);
+ if (cur_ops == &srcud_ops)
+ srcu_read_unlock_nmisafe(srcu_ctlp, idx);
+ else
+ srcu_read_unlock(srcu_ctlp, idx);
}
static int torture_srcu_read_lock_held(void)
@@ -848,7 +863,7 @@ static void rcu_tasks_torture_deferred_free(struct rcu_torture *p)
static void synchronize_rcu_mult_test(void)
{
- synchronize_rcu_mult(call_rcu_tasks, call_rcu);
+ synchronize_rcu_mult(call_rcu_tasks, call_rcu_hurry);
}
static struct rcu_torture_ops tasks_ops = {
@@ -1258,13 +1273,15 @@ static void rcu_torture_write_types(void)
} else if (gp_normal && !cur_ops->deferred_free) {
pr_alert("%s: gp_normal without primitives.\n", __func__);
}
- if (gp_poll1 && cur_ops->start_gp_poll && cur_ops->poll_gp_state) {
+ if (gp_poll1 && cur_ops->get_comp_state && cur_ops->same_gp_state &&
+ cur_ops->start_gp_poll && cur_ops->poll_gp_state) {
synctype[nsynctypes++] = RTWS_POLL_GET;
pr_info("%s: Testing polling GPs.\n", __func__);
} else if (gp_poll && (!cur_ops->start_gp_poll || !cur_ops->poll_gp_state)) {
pr_alert("%s: gp_poll without primitives.\n", __func__);
}
- if (gp_poll_full1 && cur_ops->start_gp_poll_full && cur_ops->poll_gp_state_full) {
+ if (gp_poll_full1 && cur_ops->get_comp_state_full && cur_ops->same_gp_state_full
+ && cur_ops->start_gp_poll_full && cur_ops->poll_gp_state_full) {
synctype[nsynctypes++] = RTWS_POLL_GET_FULL;
pr_info("%s: Testing polling full-state GPs.\n", __func__);
} else if (gp_poll_full && (!cur_ops->start_gp_poll_full || !cur_ops->poll_gp_state_full)) {
@@ -1339,14 +1356,18 @@ rcu_torture_writer(void *arg)
struct rcu_gp_oldstate cookie_full;
int expediting = 0;
unsigned long gp_snap;
+ unsigned long gp_snap1;
struct rcu_gp_oldstate gp_snap_full;
+ struct rcu_gp_oldstate gp_snap1_full;
int i;
int idx;
int oldnice = task_nice(current);
+ struct rcu_gp_oldstate rgo[NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE];
struct rcu_torture *rp;
struct rcu_torture *old_rp;
static DEFINE_TORTURE_RANDOM(rand);
bool stutter_waited;
+ unsigned long ulo[NUM_ACTIVE_RCU_POLL_OLDSTATE];
VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
if (!can_expedite)
@@ -1463,20 +1484,43 @@ rcu_torture_writer(void *arg)
break;
case RTWS_POLL_GET:
rcu_torture_writer_state = RTWS_POLL_GET;
+ for (i = 0; i < ARRAY_SIZE(ulo); i++)
+ ulo[i] = cur_ops->get_comp_state();
gp_snap = cur_ops->start_gp_poll();
rcu_torture_writer_state = RTWS_POLL_WAIT;
- while (!cur_ops->poll_gp_state(gp_snap))
+ while (!cur_ops->poll_gp_state(gp_snap)) {
+ gp_snap1 = cur_ops->get_gp_state();
+ for (i = 0; i < ARRAY_SIZE(ulo); i++)
+ if (cur_ops->poll_gp_state(ulo[i]) ||
+ cur_ops->same_gp_state(ulo[i], gp_snap1)) {
+ ulo[i] = gp_snap1;
+ break;
+ }
+ WARN_ON_ONCE(i >= ARRAY_SIZE(ulo));
torture_hrtimeout_jiffies(torture_random(&rand) % 16,
&rand);
+ }
rcu_torture_pipe_update(old_rp);
break;
case RTWS_POLL_GET_FULL:
rcu_torture_writer_state = RTWS_POLL_GET_FULL;
+ for (i = 0; i < ARRAY_SIZE(rgo); i++)
+ cur_ops->get_comp_state_full(&rgo[i]);
cur_ops->start_gp_poll_full(&gp_snap_full);
rcu_torture_writer_state = RTWS_POLL_WAIT_FULL;
- while (!cur_ops->poll_gp_state_full(&gp_snap_full))
+ while (!cur_ops->poll_gp_state_full(&gp_snap_full)) {
+ cur_ops->get_gp_state_full(&gp_snap1_full);
+ for (i = 0; i < ARRAY_SIZE(rgo); i++)
+ if (cur_ops->poll_gp_state_full(&rgo[i]) ||
+ cur_ops->same_gp_state_full(&rgo[i],
+ &gp_snap1_full)) {
+ rgo[i] = gp_snap1_full;
+ break;
+ }
+ WARN_ON_ONCE(i >= ARRAY_SIZE(rgo));
torture_hrtimeout_jiffies(torture_random(&rand) % 16,
&rand);
+ }
rcu_torture_pipe_update(old_rp);
break;
case RTWS_POLL_GET_EXP:
@@ -3388,13 +3432,13 @@ static void rcu_test_debug_objects(void)
/* Try to queue the rh2 pair of callbacks for the same grace period. */
preempt_disable(); /* Prevent preemption from interrupting test. */
rcu_read_lock(); /* Make it impossible to finish a grace period. */
- call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
+ call_rcu_hurry(&rh1, rcu_torture_leak_cb); /* Start grace period. */
local_irq_disable(); /* Make it harder to start a new grace period. */
- call_rcu(&rh2, rcu_torture_leak_cb);
- call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
+ call_rcu_hurry(&rh2, rcu_torture_leak_cb);
+ call_rcu_hurry(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
if (rhp) {
- call_rcu(rhp, rcu_torture_leak_cb);
- call_rcu(rhp, rcu_torture_err_cb); /* Another duplicate callback. */
+ call_rcu_hurry(rhp, rcu_torture_leak_cb);
+ call_rcu_hurry(rhp, rcu_torture_err_cb); /* Another duplicate callback. */
}
local_irq_enable();
rcu_read_unlock();
diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c
index 33adafdad261..b12fb0cec44d 100644
--- a/kernel/rcu/srcutiny.c
+++ b/kernel/rcu/srcutiny.c
@@ -197,6 +197,16 @@ void synchronize_srcu(struct srcu_struct *ssp)
{
struct rcu_synchronize rs;
+ RCU_LOCKDEP_WARN(lockdep_is_held(ssp) ||
+ lock_is_held(&rcu_bh_lock_map) ||
+ lock_is_held(&rcu_lock_map) ||
+ lock_is_held(&rcu_sched_lock_map),
+ "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section");
+
+ if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
+ return;
+
+ might_sleep();
init_rcu_head_on_stack(&rs.head);
init_completion(&rs.completion);
call_srcu(ssp, &rs.head, wakeme_after_rcu);
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index 1c304fec89c0..ca4b5dcec675 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -417,7 +417,7 @@ static unsigned long srcu_readers_lock_idx(struct srcu_struct *ssp, int idx)
for_each_possible_cpu(cpu) {
struct srcu_data *cpuc = per_cpu_ptr(ssp->sda, cpu);
- sum += READ_ONCE(cpuc->srcu_lock_count[idx]);
+ sum += atomic_long_read(&cpuc->srcu_lock_count[idx]);
}
return sum;
}
@@ -429,13 +429,18 @@ static unsigned long srcu_readers_lock_idx(struct srcu_struct *ssp, int idx)
static unsigned long srcu_readers_unlock_idx(struct srcu_struct *ssp, int idx)
{
int cpu;
+ unsigned long mask = 0;
unsigned long sum = 0;
for_each_possible_cpu(cpu) {
struct srcu_data *cpuc = per_cpu_ptr(ssp->sda, cpu);
- sum += READ_ONCE(cpuc->srcu_unlock_count[idx]);
+ sum += atomic_long_read(&cpuc->srcu_unlock_count[idx]);
+ if (IS_ENABLED(CONFIG_PROVE_RCU))
+ mask = mask | READ_ONCE(cpuc->srcu_nmi_safety);
}
+ WARN_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && (mask & (mask >> 1)),
+ "Mixed NMI-safe readers for srcu_struct at %ps.\n", ssp);
return sum;
}
@@ -503,10 +508,10 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
for_each_possible_cpu(cpu) {
struct srcu_data *cpuc = per_cpu_ptr(ssp->sda, cpu);
- sum += READ_ONCE(cpuc->srcu_lock_count[0]);
- sum += READ_ONCE(cpuc->srcu_lock_count[1]);
- sum -= READ_ONCE(cpuc->srcu_unlock_count[0]);
- sum -= READ_ONCE(cpuc->srcu_unlock_count[1]);
+ sum += atomic_long_read(&cpuc->srcu_lock_count[0]);
+ sum += atomic_long_read(&cpuc->srcu_lock_count[1]);
+ sum -= atomic_long_read(&cpuc->srcu_unlock_count[0]);
+ sum -= atomic_long_read(&cpuc->srcu_unlock_count[1]);
}
return sum;
}
@@ -626,6 +631,29 @@ void cleanup_srcu_struct(struct srcu_struct *ssp)
}
EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
+#ifdef CONFIG_PROVE_RCU
+/*
+ * Check for consistent NMI safety.
+ */
+void srcu_check_nmi_safety(struct srcu_struct *ssp, bool nmi_safe)
+{
+ int nmi_safe_mask = 1 << nmi_safe;
+ int old_nmi_safe_mask;
+ struct srcu_data *sdp;
+
+ /* NMI-unsafe use in NMI is a bad sign */
+ WARN_ON_ONCE(!nmi_safe && in_nmi());
+ sdp = raw_cpu_ptr(ssp->sda);
+ old_nmi_safe_mask = READ_ONCE(sdp->srcu_nmi_safety);
+ if (!old_nmi_safe_mask) {
+ WRITE_ONCE(sdp->srcu_nmi_safety, nmi_safe_mask);
+ return;
+ }
+ WARN_ONCE(old_nmi_safe_mask != nmi_safe_mask, "CPU %d old state %d new state %d\n", sdp->cpu, old_nmi_safe_mask, nmi_safe_mask);
+}
+EXPORT_SYMBOL_GPL(srcu_check_nmi_safety);
+#endif /* CONFIG_PROVE_RCU */
+
/*
* Counts the new reader in the appropriate per-CPU element of the
* srcu_struct.
@@ -636,7 +664,7 @@ int __srcu_read_lock(struct srcu_struct *ssp)
int idx;
idx = READ_ONCE(ssp->srcu_idx) & 0x1;
- this_cpu_inc(ssp->sda->srcu_lock_count[idx]);
+ this_cpu_inc(ssp->sda->srcu_lock_count[idx].counter);
smp_mb(); /* B */ /* Avoid leaking the critical section. */
return idx;
}
@@ -650,10 +678,45 @@ EXPORT_SYMBOL_GPL(__srcu_read_lock);
void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
{
smp_mb(); /* C */ /* Avoid leaking the critical section. */
- this_cpu_inc(ssp->sda->srcu_unlock_count[idx]);
+ this_cpu_inc(ssp->sda->srcu_unlock_count[idx].counter);
}
EXPORT_SYMBOL_GPL(__srcu_read_unlock);
+#ifdef CONFIG_NEED_SRCU_NMI_SAFE
+
+/*
+ * Counts the new reader in the appropriate per-CPU element of the
+ * srcu_struct, but in an NMI-safe manner using RMW atomics.
+ * Returns an index that must be passed to the matching srcu_read_unlock().
+ */
+int __srcu_read_lock_nmisafe(struct srcu_struct *ssp)
+{
+ int idx;
+ struct srcu_data *sdp = raw_cpu_ptr(ssp->sda);
+
+ idx = READ_ONCE(ssp->srcu_idx) & 0x1;
+ atomic_long_inc(&sdp->srcu_lock_count[idx]);
+ smp_mb__after_atomic(); /* B */ /* Avoid leaking the critical section. */
+ return idx;
+}
+EXPORT_SYMBOL_GPL(__srcu_read_lock_nmisafe);
+
+/*
+ * Removes the count for the old reader from the appropriate per-CPU
+ * element of the srcu_struct. Note that this may well be a different
+ * CPU than that which was incremented by the corresponding srcu_read_lock().
+ */
+void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx)
+{
+ struct srcu_data *sdp = raw_cpu_ptr(ssp->sda);
+
+ smp_mb__before_atomic(); /* C */ /* Avoid leaking the critical section. */
+ atomic_long_inc(&sdp->srcu_unlock_count[idx]);
+}
+EXPORT_SYMBOL_GPL(__srcu_read_unlock_nmisafe);
+
+#endif // CONFIG_NEED_SRCU_NMI_SAFE
+
/*
* Start an SRCU grace period.
*/
@@ -1090,7 +1153,12 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
int ss_state;
check_init_srcu_struct(ssp);
- idx = srcu_read_lock(ssp);
+ /*
+ * While starting a new grace period, make sure we are in an
+ * SRCU read-side critical section so that the grace-period
+ * sequence number cannot wrap around in the meantime.
+ */
+ idx = __srcu_read_lock_nmisafe(ssp);
ss_state = smp_load_acquire(&ssp->srcu_size_state);
if (ss_state < SRCU_SIZE_WAIT_CALL)
sdp = per_cpu_ptr(ssp->sda, 0);
@@ -1123,7 +1191,7 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
srcu_funnel_gp_start(ssp, sdp, s, do_norm);
else if (needexp)
srcu_funnel_exp_start(ssp, sdp_mynode, s);
- srcu_read_unlock(ssp, idx);
+ __srcu_read_unlock_nmisafe(ssp, idx);
return s;
}
@@ -1427,13 +1495,13 @@ void srcu_barrier(struct srcu_struct *ssp)
/* Initial count prevents reaching zero until all CBs are posted. */
atomic_set(&ssp->srcu_barrier_cpu_cnt, 1);
- idx = srcu_read_lock(ssp);
+ idx = __srcu_read_lock_nmisafe(ssp);
if (smp_load_acquire(&ssp->srcu_size_state) < SRCU_SIZE_WAIT_BARRIER)
srcu_barrier_one_cpu(ssp, per_cpu_ptr(ssp->sda, 0));
else
for_each_possible_cpu(cpu)
srcu_barrier_one_cpu(ssp, per_cpu_ptr(ssp->sda, cpu));
- srcu_read_unlock(ssp, idx);
+ __srcu_read_unlock_nmisafe(ssp, idx);
/* Remove the initial count, at which point reaching zero can happen. */
if (atomic_dec_and_test(&ssp->srcu_barrier_cpu_cnt))
@@ -1687,8 +1755,8 @@ void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf)
struct srcu_data *sdp;
sdp = per_cpu_ptr(ssp->sda, cpu);
- u0 = data_race(sdp->srcu_unlock_count[!idx]);
- u1 = data_race(sdp->srcu_unlock_count[idx]);
+ u0 = data_race(atomic_long_read(&sdp->srcu_unlock_count[!idx]));
+ u1 = data_race(atomic_long_read(&sdp->srcu_unlock_count[idx]));
/*
* Make sure that a lock is always counted if the corresponding
@@ -1696,8 +1764,8 @@ void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf)
*/
smp_rmb();
- l0 = data_race(sdp->srcu_lock_count[!idx]);
- l1 = data_race(sdp->srcu_lock_count[idx]);
+ l0 = data_race(atomic_long_read(&sdp->srcu_lock_count[!idx]));
+ l1 = data_race(atomic_long_read(&sdp->srcu_lock_count[idx]));
c0 = l0 - u0;
c1 = l1 - u1;
diff --git a/kernel/rcu/sync.c b/kernel/rcu/sync.c
index 5cefc702158f..e550f97779b8 100644
--- a/kernel/rcu/sync.c
+++ b/kernel/rcu/sync.c
@@ -44,7 +44,7 @@ static void rcu_sync_func(struct rcu_head *rhp);
static void rcu_sync_call(struct rcu_sync *rsp)
{
- call_rcu(&rsp->cb_head, rcu_sync_func);
+ call_rcu_hurry(&rsp->cb_head, rcu_sync_func);
}
/**
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index f5bf6fb430da..b0b885e071fa 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -728,7 +728,7 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
if (rtsi > 0 && !reported && time_after(j, lastinfo + rtsi)) {
lastinfo = j;
rtsi = rtsi * rcu_task_stall_info_mult;
- pr_info("%s: %s grace period %lu is %lu jiffies old.\n",
+ pr_info("%s: %s grace period number %lu (since boot) is %lu jiffies old.\n",
__func__, rtp->kname, rtp->tasks_gp_seq, j - rtp->gp_start);
}
}
diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index a33a8d4942c3..72913ce21258 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -44,7 +44,7 @@ static struct rcu_ctrlblk rcu_ctrlblk = {
void rcu_barrier(void)
{
- wait_rcu_gp(call_rcu);
+ wait_rcu_gp(call_rcu_hurry);
}
EXPORT_SYMBOL(rcu_barrier);
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 93416afebd59..d04f2192f02c 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -301,12 +301,6 @@ static bool rcu_dynticks_in_eqs(int snap)
return !(snap & RCU_DYNTICKS_IDX);
}
-/* Return true if the specified CPU is currently idle from an RCU viewpoint. */
-bool rcu_is_idle_cpu(int cpu)
-{
- return rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu));
-}
-
/*
* Return true if the CPU corresponding to the specified rcu_data
* structure has spent some time in an extended quiescent state since
@@ -2108,7 +2102,7 @@ int rcutree_dying_cpu(unsigned int cpu)
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
return 0;
- blkd = !!(rnp->qsmask & rdp->grpmask);
+ blkd = !!(READ_ONCE(rnp->qsmask) & rdp->grpmask);
trace_rcu_grace_period(rcu_state.name, READ_ONCE(rnp->gp_seq),
blkd ? TPS("cpuofl-bgp") : TPS("cpuofl"));
return 0;
@@ -2418,7 +2412,7 @@ void rcu_force_quiescent_state(void)
struct rcu_node *rnp_old = NULL;
/* Funnel through hierarchy to reduce memory contention. */
- rnp = __this_cpu_read(rcu_data.mynode);
+ rnp = raw_cpu_read(rcu_data.mynode);
for (; rnp != NULL; rnp = rnp->parent) {
ret = (READ_ONCE(rcu_state.gp_flags) & RCU_GP_FLAG_FQS) ||
!raw_spin_trylock(&rnp->fqslock);
@@ -2730,47 +2724,8 @@ static void check_cb_ovld(struct rcu_data *rdp)
raw_spin_unlock_rcu_node(rnp);
}
-/**
- * call_rcu() - Queue an RCU callback for invocation after a grace period.
- * @head: structure to be used for queueing the RCU updates.
- * @func: actual callback function to be invoked after the grace period
- *
- * The callback function will be invoked some time after a full grace
- * period elapses, in other words after all pre-existing RCU read-side
- * critical sections have completed. However, the callback function
- * might well execute concurrently with RCU read-side critical sections
- * that started after call_rcu() was invoked.
- *
- * RCU read-side critical sections are delimited by rcu_read_lock()
- * and rcu_read_unlock(), and may be nested. In addition, but only in
- * v5.0 and later, regions of code across which interrupts, preemption,
- * or softirqs have been disabled also serve as RCU read-side critical
- * sections. This includes hardware interrupt handlers, softirq handlers,
- * and NMI handlers.
- *
- * Note that all CPUs must agree that the grace period extended beyond
- * all pre-existing RCU read-side critical section. On systems with more
- * than one CPU, this means that when "func()" is invoked, each CPU is
- * guaranteed to have executed a full memory barrier since the end of its
- * last RCU read-side critical section whose beginning preceded the call
- * to call_rcu(). It also means that each CPU executing an RCU read-side
- * critical section that continues beyond the start of "func()" must have
- * executed a memory barrier after the call_rcu() but before the beginning
- * of that RCU read-side critical section. Note that these guarantees
- * include CPUs that are offline, idle, or executing in user mode, as
- * well as CPUs that are executing in the kernel.
- *
- * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the
- * resulting RCU callback function "func()", then both CPU A and CPU B are
- * guaranteed to execute a full memory barrier during the time interval
- * between the call to call_rcu() and the invocation of "func()" -- even
- * if CPU A and CPU B are the same CPU (but again only if the system has
- * more than one CPU).
- *
- * Implementation of these memory-ordering guarantees is described here:
- * Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst.
- */
-void call_rcu(struct rcu_head *head, rcu_callback_t func)
+static void
+__call_rcu_common(struct rcu_head *head, rcu_callback_t func, bool lazy)
{
static atomic_t doublefrees;
unsigned long flags;
@@ -2811,7 +2766,7 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func)
}
check_cb_ovld(rdp);
- if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags))
+ if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags, lazy))
return; // Enqueued onto ->nocb_bypass, so just leave.
// If no-CBs CPU gets here, rcu_nocb_try_bypass() acquired ->nocb_lock.
rcu_segcblist_enqueue(&rdp->cblist, head);
@@ -2833,8 +2788,84 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func)
local_irq_restore(flags);
}
}
-EXPORT_SYMBOL_GPL(call_rcu);
+#ifdef CONFIG_RCU_LAZY
+/**
+ * call_rcu_hurry() - Queue RCU callback for invocation after grace period, and
+ * flush all lazy callbacks (including the new one) to the main ->cblist while
+ * doing so.
+ *
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual callback function to be invoked after the grace period
+ *
+ * The callback function will be invoked some time after a full grace
+ * period elapses, in other words after all pre-existing RCU read-side
+ * critical sections have completed.
+ *
+ * Use this API instead of call_rcu() if you don't want the callback to be
+ * invoked after very long periods of time, which can happen on systems without
+ * memory pressure and on systems which are lightly loaded or mostly idle.
+ * This function will cause callbacks to be invoked sooner than later at the
+ * expense of extra power. Other than that, this function is identical to, and
+ * reuses call_rcu()'s logic. Refer to call_rcu() for more details about memory
+ * ordering and other functionality.
+ */
+void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func)
+{
+ return __call_rcu_common(head, func, false);
+}
+EXPORT_SYMBOL_GPL(call_rcu_hurry);
+#endif
+
+/**
+ * call_rcu() - Queue an RCU callback for invocation after a grace period.
+ * By default the callbacks are 'lazy' and are kept hidden from the main
+ * ->cblist to prevent starting of grace periods too soon.
+ * If you desire grace periods to start very soon, use call_rcu_hurry().
+ *
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual callback function to be invoked after the grace period
+ *
+ * The callback function will be invoked some time after a full grace
+ * period elapses, in other words after all pre-existing RCU read-side
+ * critical sections have completed. However, the callback function
+ * might well execute concurrently with RCU read-side critical sections
+ * that started after call_rcu() was invoked.
+ *
+ * RCU read-side critical sections are delimited by rcu_read_lock()
+ * and rcu_read_unlock(), and may be nested. In addition, but only in
+ * v5.0 and later, regions of code across which interrupts, preemption,
+ * or softirqs have been disabled also serve as RCU read-side critical
+ * sections. This includes hardware interrupt handlers, softirq handlers,
+ * and NMI handlers.
+ *
+ * Note that all CPUs must agree that the grace period extended beyond
+ * all pre-existing RCU read-side critical section. On systems with more
+ * than one CPU, this means that when "func()" is invoked, each CPU is
+ * guaranteed to have executed a full memory barrier since the end of its
+ * last RCU read-side critical section whose beginning preceded the call
+ * to call_rcu(). It also means that each CPU executing an RCU read-side
+ * critical section that continues beyond the start of "func()" must have
+ * executed a memory barrier after the call_rcu() but before the beginning
+ * of that RCU read-side critical section. Note that these guarantees
+ * include CPUs that are offline, idle, or executing in user mode, as
+ * well as CPUs that are executing in the kernel.
+ *
+ * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the
+ * resulting RCU callback function "func()", then both CPU A and CPU B are
+ * guaranteed to execute a full memory barrier during the time interval
+ * between the call to call_rcu() and the invocation of "func()" -- even
+ * if CPU A and CPU B are the same CPU (but again only if the system has
+ * more than one CPU).
+ *
+ * Implementation of these memory-ordering guarantees is described here:
+ * Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst.
+ */
+void call_rcu(struct rcu_head *head, rcu_callback_t func)
+{
+ return __call_rcu_common(head, func, IS_ENABLED(CONFIG_RCU_LAZY));
+}
+EXPORT_SYMBOL_GPL(call_rcu);
/* Maximum number of jiffies to wait before draining a batch. */
#define KFREE_DRAIN_JIFFIES (5 * HZ)
@@ -3509,7 +3540,7 @@ void synchronize_rcu(void)
if (rcu_gp_is_expedited())
synchronize_rcu_expedited();
else
- wait_rcu_gp(call_rcu);
+ wait_rcu_gp(call_rcu_hurry);
return;
}
@@ -3896,6 +3927,8 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
{
unsigned long gseq = READ_ONCE(rcu_state.barrier_sequence);
unsigned long lseq = READ_ONCE(rdp->barrier_seq_snap);
+ bool wake_nocb = false;
+ bool was_alldone = false;
lockdep_assert_held(&rcu_state.barrier_lock);
if (rcu_seq_state(lseq) || !rcu_seq_state(gseq) || rcu_seq_ctr(lseq) != rcu_seq_ctr(gseq))
@@ -3904,7 +3937,14 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
rdp->barrier_head.func = rcu_barrier_callback;
debug_rcu_head_queue(&rdp->barrier_head);
rcu_nocb_lock(rdp);
- WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies));
+ /*
+ * Flush bypass and wakeup rcuog if we add callbacks to an empty regular
+ * queue. This way we don't wait for bypass timer that can reach seconds
+ * if it's fully lazy.
+ */
+ was_alldone = rcu_rdp_is_offloaded(rdp) && !rcu_segcblist_pend_cbs(&rdp->cblist);
+ WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies, false));
+ wake_nocb = was_alldone && rcu_segcblist_pend_cbs(&rdp->cblist);
if (rcu_segcblist_entrain(&rdp->cblist, &rdp->barrier_head)) {
atomic_inc(&rcu_state.barrier_cpu_count);
} else {
@@ -3912,6 +3952,8 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
rcu_barrier_trace(TPS("IRQNQ"), -1, rcu_state.barrier_sequence);
}
rcu_nocb_unlock(rdp);
+ if (wake_nocb)
+ wake_nocb_gp(rdp, false);
smp_store_release(&rdp->barrier_seq_snap, gseq);
}
@@ -4278,8 +4320,6 @@ void rcu_report_dead(unsigned int cpu)
// Do any dangling deferred wakeups.
do_nocb_deferred_wakeup(rdp);
- /* QS for any half-done expedited grace period. */
- rcu_report_exp_rdp(rdp);
rcu_preempt_deferred_qs(current);
/* Remove outgoing CPU from mask in the leaf rcu_node structure. */
@@ -4327,7 +4367,7 @@ void rcutree_migrate_callbacks(int cpu)
my_rdp = this_cpu_ptr(&rcu_data);
my_rnp = my_rdp->mynode;
rcu_nocb_lock(my_rdp); /* irqs already disabled. */
- WARN_ON_ONCE(!rcu_nocb_flush_bypass(my_rdp, NULL, jiffies));
+ WARN_ON_ONCE(!rcu_nocb_flush_bypass(my_rdp, NULL, jiffies, false));
raw_spin_lock_rcu_node(my_rnp); /* irqs already disabled. */
/* Leverage recent GPs and set GP for new callbacks. */
needwake = rcu_advance_cbs(my_rnp, rdp) ||
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index d4a97e40ea9c..fcb5d696eb17 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -263,14 +263,16 @@ struct rcu_data {
unsigned long last_fqs_resched; /* Time of last rcu_resched(). */
unsigned long last_sched_clock; /* Jiffies of last rcu_sched_clock_irq(). */
+ long lazy_len; /* Length of buffered lazy callbacks. */
int cpu;
};
/* Values for nocb_defer_wakeup field in struct rcu_data. */
#define RCU_NOCB_WAKE_NOT 0
#define RCU_NOCB_WAKE_BYPASS 1
-#define RCU_NOCB_WAKE 2
-#define RCU_NOCB_WAKE_FORCE 3
+#define RCU_NOCB_WAKE_LAZY 2
+#define RCU_NOCB_WAKE 3
+#define RCU_NOCB_WAKE_FORCE 4
#define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500))
/* For jiffies_till_first_fqs and */
@@ -439,10 +441,12 @@ static void zero_cpu_stall_ticks(struct rcu_data *rdp);
static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp);
static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq);
static void rcu_init_one_nocb(struct rcu_node *rnp);
+static bool wake_nocb_gp(struct rcu_data *rdp, bool force);
static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- unsigned long j);
+ unsigned long j, bool lazy);
static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- bool *was_alldone, unsigned long flags);
+ bool *was_alldone, unsigned long flags,
+ bool lazy);
static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_empty,
unsigned long flags);
static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp, int level);
diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index 18e9b4cd78ef..ed6c3cce28f2 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -937,7 +937,7 @@ void synchronize_rcu_expedited(void)
/* If expedited grace periods are prohibited, fall back to normal. */
if (rcu_gp_is_normal()) {
- wait_rcu_gp(call_rcu);
+ wait_rcu_gp(call_rcu_hurry);
return;
}
diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index 0a5f0ef41484..9e1c8caec5ce 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -257,6 +257,31 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
}
/*
+ * LAZY_FLUSH_JIFFIES decides the maximum amount of time that
+ * can elapse before lazy callbacks are flushed. Lazy callbacks
+ * could be flushed much earlier for a number of other reasons
+ * however, LAZY_FLUSH_JIFFIES will ensure no lazy callbacks are
+ * left unsubmitted to RCU after those many jiffies.
+ */
+#define LAZY_FLUSH_JIFFIES (10 * HZ)
+static unsigned long jiffies_till_flush = LAZY_FLUSH_JIFFIES;
+
+#ifdef CONFIG_RCU_LAZY
+// To be called only from test code.
+void rcu_lazy_set_jiffies_till_flush(unsigned long jif)
+{
+ jiffies_till_flush = jif;
+}
+EXPORT_SYMBOL(rcu_lazy_set_jiffies_till_flush);
+
+unsigned long rcu_lazy_get_jiffies_till_flush(void)
+{
+ return jiffies_till_flush;
+}
+EXPORT_SYMBOL(rcu_lazy_get_jiffies_till_flush);
+#endif
+
+/*
* Arrange to wake the GP kthread for this NOCB group at some future
* time when it is safe to do so.
*/
@@ -269,10 +294,14 @@ static void wake_nocb_gp_defer(struct rcu_data *rdp, int waketype,
raw_spin_lock_irqsave(&rdp_gp->nocb_gp_lock, flags);
/*
- * Bypass wakeup overrides previous deferments. In case
- * of callback storm, no need to wake up too early.
+ * Bypass wakeup overrides previous deferments. In case of
+ * callback storms, no need to wake up too early.
*/
- if (waketype == RCU_NOCB_WAKE_BYPASS) {
+ if (waketype == RCU_NOCB_WAKE_LAZY &&
+ rdp->nocb_defer_wakeup == RCU_NOCB_WAKE_NOT) {
+ mod_timer(&rdp_gp->nocb_timer, jiffies + jiffies_till_flush);
+ WRITE_ONCE(rdp_gp->nocb_defer_wakeup, waketype);
+ } else if (waketype == RCU_NOCB_WAKE_BYPASS) {
mod_timer(&rdp_gp->nocb_timer, jiffies + 2);
WRITE_ONCE(rdp_gp->nocb_defer_wakeup, waketype);
} else {
@@ -293,12 +322,16 @@ static void wake_nocb_gp_defer(struct rcu_data *rdp, int waketype,
* proves to be initially empty, just return false because the no-CB GP
* kthread may need to be awakened in this case.
*
+ * Return true if there was something to be flushed and it succeeded, otherwise
+ * false.
+ *
* Note that this function always returns true if rhp is NULL.
*/
-static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- unsigned long j)
+static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp_in,
+ unsigned long j, bool lazy)
{
struct rcu_cblist rcl;
+ struct rcu_head *rhp = rhp_in;
WARN_ON_ONCE(!rcu_rdp_is_offloaded(rdp));
rcu_lockdep_assert_cblist_protected(rdp);
@@ -310,7 +343,20 @@ static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
/* Note: ->cblist.len already accounts for ->nocb_bypass contents. */
if (rhp)
rcu_segcblist_inc_len(&rdp->cblist); /* Must precede enqueue. */
+
+ /*
+ * If the new CB requested was a lazy one, queue it onto the main
+ * ->cblist so that we can take advantage of the grace-period that will
+ * happen regardless. But queue it onto the bypass list first so that
+ * the lazy CB is ordered with the existing CBs in the bypass list.
+ */
+ if (lazy && rhp) {
+ rcu_cblist_enqueue(&rdp->nocb_bypass, rhp);
+ rhp = NULL;
+ }
rcu_cblist_flush_enqueue(&rcl, &rdp->nocb_bypass, rhp);
+ WRITE_ONCE(rdp->lazy_len, 0);
+
rcu_segcblist_insert_pend_cbs(&rdp->cblist, &rcl);
WRITE_ONCE(rdp->nocb_bypass_first, j);
rcu_nocb_bypass_unlock(rdp);
@@ -326,13 +372,13 @@ static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
* Note that this function always returns true if rhp is NULL.
*/
static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- unsigned long j)
+ unsigned long j, bool lazy)
{
if (!rcu_rdp_is_offloaded(rdp))
return true;
rcu_lockdep_assert_cblist_protected(rdp);
rcu_nocb_bypass_lock(rdp);
- return rcu_nocb_do_flush_bypass(rdp, rhp, j);
+ return rcu_nocb_do_flush_bypass(rdp, rhp, j, lazy);
}
/*
@@ -345,7 +391,7 @@ static void rcu_nocb_try_flush_bypass(struct rcu_data *rdp, unsigned long j)
if (!rcu_rdp_is_offloaded(rdp) ||
!rcu_nocb_bypass_trylock(rdp))
return;
- WARN_ON_ONCE(!rcu_nocb_do_flush_bypass(rdp, NULL, j));
+ WARN_ON_ONCE(!rcu_nocb_do_flush_bypass(rdp, NULL, j, false));
}
/*
@@ -367,12 +413,14 @@ static void rcu_nocb_try_flush_bypass(struct rcu_data *rdp, unsigned long j)
* there is only one CPU in operation.
*/
static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- bool *was_alldone, unsigned long flags)
+ bool *was_alldone, unsigned long flags,
+ bool lazy)
{
unsigned long c;
unsigned long cur_gp_seq;
unsigned long j = jiffies;
long ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
+ bool bypass_is_lazy = (ncbs == READ_ONCE(rdp->lazy_len));
lockdep_assert_irqs_disabled();
@@ -417,24 +465,29 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
// If there hasn't yet been all that many ->cblist enqueues
// this jiffy, tell the caller to enqueue onto ->cblist. But flush
// ->nocb_bypass first.
- if (rdp->nocb_nobypass_count < nocb_nobypass_lim_per_jiffy) {
+ // Lazy CBs throttle this back and do immediate bypass queuing.
+ if (rdp->nocb_nobypass_count < nocb_nobypass_lim_per_jiffy && !lazy) {
rcu_nocb_lock(rdp);
*was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
if (*was_alldone)
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
TPS("FirstQ"));
- WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, j));
+
+ WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, j, false));
WARN_ON_ONCE(rcu_cblist_n_cbs(&rdp->nocb_bypass));
return false; // Caller must enqueue the callback.
}
// If ->nocb_bypass has been used too long or is too full,
// flush ->nocb_bypass to ->cblist.
- if ((ncbs && j != READ_ONCE(rdp->nocb_bypass_first)) ||
+ if ((ncbs && !bypass_is_lazy && j != READ_ONCE(rdp->nocb_bypass_first)) ||
+ (ncbs && bypass_is_lazy &&
+ (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush))) ||
ncbs >= qhimark) {
rcu_nocb_lock(rdp);
- if (!rcu_nocb_flush_bypass(rdp, rhp, j)) {
- *was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
+ *was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
+
+ if (!rcu_nocb_flush_bypass(rdp, rhp, j, lazy)) {
if (*was_alldone)
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
TPS("FirstQ"));
@@ -447,7 +500,12 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
rcu_advance_cbs_nowake(rdp->mynode, rdp);
rdp->nocb_gp_adv_time = j;
}
- rcu_nocb_unlock_irqrestore(rdp, flags);
+
+ // The flush succeeded and we moved CBs into the regular list.
+ // Don't wait for the wake up timer as it may be too far ahead.
+ // Wake up the GP thread now instead, if the cblist was empty.
+ __call_rcu_nocb_wake(rdp, *was_alldone, flags);
+
return true; // Callback already enqueued.
}
@@ -457,13 +515,24 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
rcu_segcblist_inc_len(&rdp->cblist); /* Must precede enqueue. */
rcu_cblist_enqueue(&rdp->nocb_bypass, rhp);
+
+ if (lazy)
+ WRITE_ONCE(rdp->lazy_len, rdp->lazy_len + 1);
+
if (!ncbs) {
WRITE_ONCE(rdp->nocb_bypass_first, j);
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("FirstBQ"));
}
rcu_nocb_bypass_unlock(rdp);
smp_mb(); /* Order enqueue before wake. */
- if (ncbs) {
+ // A wake up of the grace period kthread or timer adjustment
+ // needs to be done only if:
+ // 1. Bypass list was fully empty before (this is the first
+ // bypass list entry), or:
+ // 2. Both of these conditions are met:
+ // a. The bypass list previously had only lazy CBs, and:
+ // b. The new CB is non-lazy.
+ if (ncbs && (!bypass_is_lazy || lazy)) {
local_irq_restore(flags);
} else {
// No-CBs GP kthread might be indefinitely asleep, if so, wake.
@@ -491,8 +560,10 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
unsigned long flags)
__releases(rdp->nocb_lock)
{
+ long bypass_len;
unsigned long cur_gp_seq;
unsigned long j;
+ long lazy_len;
long len;
struct task_struct *t;
@@ -506,9 +577,16 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
}
// Need to actually to a wakeup.
len = rcu_segcblist_n_cbs(&rdp->cblist);
+ bypass_len = rcu_cblist_n_cbs(&rdp->nocb_bypass);
+ lazy_len = READ_ONCE(rdp->lazy_len);
if (was_alldone) {
rdp->qlen_last_fqs_check = len;
- if (!irqs_disabled_flags(flags)) {
+ // Only lazy CBs in bypass list
+ if (lazy_len && bypass_len == lazy_len) {
+ rcu_nocb_unlock_irqrestore(rdp, flags);
+ wake_nocb_gp_defer(rdp, RCU_NOCB_WAKE_LAZY,
+ TPS("WakeLazy"));
+ } else if (!irqs_disabled_flags(flags)) {
/* ... if queue was empty ... */
rcu_nocb_unlock_irqrestore(rdp, flags);
wake_nocb_gp(rdp, false);
@@ -599,12 +677,12 @@ static void nocb_gp_sleep(struct rcu_data *my_rdp, int cpu)
static void nocb_gp_wait(struct rcu_data *my_rdp)
{
bool bypass = false;
- long bypass_ncbs;
int __maybe_unused cpu = my_rdp->cpu;
unsigned long cur_gp_seq;
unsigned long flags;
bool gotcbs = false;
unsigned long j = jiffies;
+ bool lazy = false;
bool needwait_gp = false; // This prevents actual uninitialized use.
bool needwake;
bool needwake_gp;
@@ -634,24 +712,43 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
* won't be ignored for long.
*/
list_for_each_entry(rdp, &my_rdp->nocb_head_rdp, nocb_entry_rdp) {
+ long bypass_ncbs;
+ bool flush_bypass = false;
+ long lazy_ncbs;
+
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("Check"));
rcu_nocb_lock_irqsave(rdp, flags);
lockdep_assert_held(&rdp->nocb_lock);
bypass_ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
- if (bypass_ncbs &&
+ lazy_ncbs = READ_ONCE(rdp->lazy_len);
+
+ if (bypass_ncbs && (lazy_ncbs == bypass_ncbs) &&
+ (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush) ||
+ bypass_ncbs > 2 * qhimark)) {
+ flush_bypass = true;
+ } else if (bypass_ncbs && (lazy_ncbs != bypass_ncbs) &&
(time_after(j, READ_ONCE(rdp->nocb_bypass_first) + 1) ||
bypass_ncbs > 2 * qhimark)) {
- // Bypass full or old, so flush it.
- (void)rcu_nocb_try_flush_bypass(rdp, j);
- bypass_ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
+ flush_bypass = true;
} else if (!bypass_ncbs && rcu_segcblist_empty(&rdp->cblist)) {
rcu_nocb_unlock_irqrestore(rdp, flags);
continue; /* No callbacks here, try next. */
}
+
+ if (flush_bypass) {
+ // Bypass full or old, so flush it.
+ (void)rcu_nocb_try_flush_bypass(rdp, j);
+ bypass_ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
+ lazy_ncbs = READ_ONCE(rdp->lazy_len);
+ }
+
if (bypass_ncbs) {
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
- TPS("Bypass"));
- bypass = true;
+ bypass_ncbs == lazy_ncbs ? TPS("Lazy") : TPS("Bypass"));
+ if (bypass_ncbs == lazy_ncbs)
+ lazy = true;
+ else
+ bypass = true;
}
rnp = rdp->mynode;
@@ -699,12 +796,20 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
my_rdp->nocb_gp_gp = needwait_gp;
my_rdp->nocb_gp_seq = needwait_gp ? wait_gp_seq : 0;
- if (bypass && !rcu_nocb_poll) {
- // At least one child with non-empty ->nocb_bypass, so set
- // timer in order to avoid stranding its callbacks.
- wake_nocb_gp_defer(my_rdp, RCU_NOCB_WAKE_BYPASS,
- TPS("WakeBypassIsDeferred"));
+ // At least one child with non-empty ->nocb_bypass, so set
+ // timer in order to avoid stranding its callbacks.
+ if (!rcu_nocb_poll) {
+ // If bypass list only has lazy CBs. Add a deferred lazy wake up.
+ if (lazy && !bypass) {
+ wake_nocb_gp_defer(my_rdp, RCU_NOCB_WAKE_LAZY,
+ TPS("WakeLazyIsDeferred"));
+ // Otherwise add a deferred bypass wake up.
+ } else if (bypass) {
+ wake_nocb_gp_defer(my_rdp, RCU_NOCB_WAKE_BYPASS,
+ TPS("WakeBypassIsDeferred"));
+ }
}
+
if (rcu_nocb_poll) {
/* Polling, so trace if first poll in the series. */
if (gotcbs)
@@ -1030,7 +1135,7 @@ static long rcu_nocb_rdp_deoffload(void *arg)
* return false, which means that future calls to rcu_nocb_try_bypass()
* will refuse to put anything into the bypass.
*/
- WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies));
+ WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies, false));
/*
* Start with invoking rcu_core() early. This way if the current thread
* happens to preempt an ongoing call to rcu_core() in the middle,
@@ -1207,47 +1312,87 @@ int rcu_nocb_cpu_offload(int cpu)
}
EXPORT_SYMBOL_GPL(rcu_nocb_cpu_offload);
-void __init rcu_init_nohz(void)
+static unsigned long
+lazy_rcu_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
{
int cpu;
- bool need_rcu_nocb_mask = false;
- bool offload_all = false;
- struct rcu_data *rdp;
+ unsigned long count = 0;
-#if defined(CONFIG_RCU_NOCB_CPU_DEFAULT_ALL)
- if (!rcu_state.nocb_is_setup) {
- need_rcu_nocb_mask = true;
- offload_all = true;
+ /* Snapshot count of all CPUs */
+ for_each_possible_cpu(cpu) {
+ struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
+
+ count += READ_ONCE(rdp->lazy_len);
}
-#endif /* #if defined(CONFIG_RCU_NOCB_CPU_DEFAULT_ALL) */
-#if defined(CONFIG_NO_HZ_FULL)
- if (tick_nohz_full_running && !cpumask_empty(tick_nohz_full_mask)) {
- need_rcu_nocb_mask = true;
- offload_all = false; /* NO_HZ_FULL has its own mask. */
+ return count ? count : SHRINK_EMPTY;
+}
+
+static unsigned long
+lazy_rcu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+{
+ int cpu;
+ unsigned long flags;
+ unsigned long count = 0;
+
+ /* Snapshot count of all CPUs */
+ for_each_possible_cpu(cpu) {
+ struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
+ int _count = READ_ONCE(rdp->lazy_len);
+
+ if (_count == 0)
+ continue;
+ rcu_nocb_lock_irqsave(rdp, flags);
+ WRITE_ONCE(rdp->lazy_len, 0);
+ rcu_nocb_unlock_irqrestore(rdp, flags);
+ wake_nocb_gp(rdp, false);
+ sc->nr_to_scan -= _count;
+ count += _count;
+ if (sc->nr_to_scan <= 0)
+ break;
}
-#endif /* #if defined(CONFIG_NO_HZ_FULL) */
+ return count ? count : SHRINK_STOP;
+}
+
+static struct shrinker lazy_rcu_shrinker = {
+ .count_objects = lazy_rcu_shrink_count,
+ .scan_objects = lazy_rcu_shrink_scan,
+ .batch = 0,
+ .seeks = DEFAULT_SEEKS,
+};
+
+void __init rcu_init_nohz(void)
+{
+ int cpu;
+ struct rcu_data *rdp;
+ const struct cpumask *cpumask = NULL;
+
+#if defined(CONFIG_NO_HZ_FULL)
+ if (tick_nohz_full_running && !cpumask_empty(tick_nohz_full_mask))
+ cpumask = tick_nohz_full_mask;
+#endif
- if (need_rcu_nocb_mask) {
+ if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_DEFAULT_ALL) &&
+ !rcu_state.nocb_is_setup && !cpumask)
+ cpumask = cpu_possible_mask;
+
+ if (cpumask) {
if (!cpumask_available(rcu_nocb_mask)) {
if (!zalloc_cpumask_var(&rcu_nocb_mask, GFP_KERNEL)) {
pr_info("rcu_nocb_mask allocation failed, callback offloading disabled.\n");
return;
}
}
+
+ cpumask_or(rcu_nocb_mask, rcu_nocb_mask, cpumask);
rcu_state.nocb_is_setup = true;
}
if (!rcu_state.nocb_is_setup)
return;
-#if defined(CONFIG_NO_HZ_FULL)
- if (tick_nohz_full_running)
- cpumask_or(rcu_nocb_mask, rcu_nocb_mask, tick_nohz_full_mask);
-#endif /* #if defined(CONFIG_NO_HZ_FULL) */
-
- if (offload_all)
- cpumask_setall(rcu_nocb_mask);
+ if (register_shrinker(&lazy_rcu_shrinker, "rcu-lazy"))
+ pr_err("Failed to register lazy_rcu shrinker!\n");
if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
pr_info("\tNote: kernel parameter 'rcu_nocbs=', 'nohz_full', or 'isolcpus=' contains nonexistent CPUs.\n");
@@ -1284,6 +1429,7 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
raw_spin_lock_init(&rdp->nocb_gp_lock);
timer_setup(&rdp->nocb_timer, do_nocb_deferred_wakeup_timer, 0);
rcu_cblist_init(&rdp->nocb_bypass);
+ WRITE_ONCE(rdp->lazy_len, 0);
mutex_init(&rdp->nocb_gp_kthread_mutex);
}
@@ -1564,14 +1710,19 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
{
}
+static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
+{
+ return false;
+}
+
static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- unsigned long j)
+ unsigned long j, bool lazy)
{
return true;
}
static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
- bool *was_alldone, unsigned long flags)
+ bool *was_alldone, unsigned long flags, bool lazy)
{
return false;
}
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index e3142ee35fc6..7b0fe741a088 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -1221,11 +1221,13 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
* We don't include outgoingcpu in the affinity set, use -1 if there is
* no outgoing CPU. If there are no CPUs left in the affinity set,
* this function allows the kthread to execute on any CPU.
+ *
+ * Any future concurrent calls are serialized via ->boost_kthread_mutex.
*/
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
{
struct task_struct *t = rnp->boost_kthread_task;
- unsigned long mask = rcu_rnp_online_cpus(rnp);
+ unsigned long mask;
cpumask_var_t cm;
int cpu;
@@ -1234,6 +1236,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
return;
mutex_lock(&rnp->boost_kthread_mutex);
+ mask = rcu_rnp_online_cpus(rnp);
for_each_leaf_node_possible_cpu(rnp, cpu)
if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
cpu != outgoingcpu)
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 738842c4886b..f5e6a2f95a2a 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -224,7 +224,7 @@ void rcu_test_sync_prims(void)
synchronize_rcu_expedited();
}
-#if !defined(CONFIG_TINY_RCU) || defined(CONFIG_SRCU)
+#if !defined(CONFIG_TINY_RCU)
/*
* Switch to run-time mode once RCU has fully initialized.
@@ -239,7 +239,7 @@ static int __init rcu_set_runtime_mode(void)
}
core_initcall(rcu_set_runtime_mode);
-#endif /* #if !defined(CONFIG_TINY_RCU) || defined(CONFIG_SRCU) */
+#endif /* #if !defined(CONFIG_TINY_RCU) */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key rcu_lock_key;
@@ -559,10 +559,8 @@ static void early_boot_test_call_rcu(void)
struct early_boot_kfree_rcu *rhp;
call_rcu(&head, test_callback);
- if (IS_ENABLED(CONFIG_SRCU)) {
- early_srcu_cookie = start_poll_synchronize_srcu(&early_srcu);
- call_srcu(&early_srcu, &shead, test_callback);
- }
+ early_srcu_cookie = start_poll_synchronize_srcu(&early_srcu);
+ call_srcu(&early_srcu, &shead, test_callback);
rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
if (!WARN_ON_ONCE(!rhp))
kfree_rcu(rhp, rh);
@@ -585,11 +583,9 @@ static int rcu_verify_early_boot_tests(void)
if (rcu_self_test) {
early_boot_test_counter++;
rcu_barrier();
- if (IS_ENABLED(CONFIG_SRCU)) {
- early_boot_test_counter++;
- srcu_barrier(&early_srcu);
- WARN_ON_ONCE(!poll_state_synchronize_srcu(&early_srcu, early_srcu_cookie));
- }
+ early_boot_test_counter++;
+ srcu_barrier(&early_srcu);
+ WARN_ON_ONCE(!poll_state_synchronize_srcu(&early_srcu, early_srcu_cookie));
}
if (rcu_self_test_counter != early_boot_test_counter) {
WARN_ON(1);
diff --git a/kernel/relay.c b/kernel/relay.c
index d7edc934c56d..ef12532168d9 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -148,13 +148,13 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan)
{
struct rchan_buf *buf;
- if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *))
+ if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t))
return NULL;
buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
if (!buf)
return NULL;
- buf->padding = kmalloc_array(chan->n_subbufs, sizeof(size_t *),
+ buf->padding = kmalloc_array(chan->n_subbufs, sizeof(size_t),
GFP_KERNEL);
if (!buf->padding)
goto free_buf;
@@ -507,7 +507,7 @@ struct rchan *relay_open(const char *base_filename,
chan->private_data = private_data;
if (base_filename) {
chan->has_base_filename = 1;
- strlcpy(chan->base_filename, base_filename, NAME_MAX);
+ strscpy(chan->base_filename, base_filename, NAME_MAX);
}
chan->cb = cb;
kref_init(&chan->kref);
@@ -578,7 +578,7 @@ int relay_late_setup_files(struct rchan *chan,
if (!chan || !base_filename)
return -EINVAL;
- strlcpy(chan->base_filename, base_filename, NAME_MAX);
+ strscpy(chan->base_filename, base_filename, NAME_MAX);
mutex_lock(&relay_channels_mutex);
/* Is chan already set up? */
diff --git a/kernel/resource.c b/kernel/resource.c
index 4c5e80b92f2f..82ed54cd1f0d 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1707,18 +1707,15 @@ static int strict_iomem_checks;
*
* Returns true if exclusive to the kernel, otherwise returns false.
*/
-bool iomem_is_exclusive(u64 addr)
+bool resource_is_exclusive(struct resource *root, u64 addr, resource_size_t size)
{
const unsigned int exclusive_system_ram = IORESOURCE_SYSTEM_RAM |
IORESOURCE_EXCLUSIVE;
bool skip_children = false, err = false;
- int size = PAGE_SIZE;
struct resource *p;
- addr = addr & PAGE_MASK;
-
read_lock(&resource_lock);
- for_each_resource(&iomem_resource, p, skip_children) {
+ for_each_resource(root, p, skip_children) {
if (p->start >= addr + size)
break;
if (p->end < addr) {
@@ -1757,6 +1754,12 @@ bool iomem_is_exclusive(u64 addr)
return err;
}
+bool iomem_is_exclusive(u64 addr)
+{
+ return resource_is_exclusive(&iomem_resource, addr & PAGE_MASK,
+ PAGE_SIZE);
+}
+
struct resource_entry *resource_list_create_entry(struct resource *res,
size_t extra_size)
{
diff --git a/kernel/rseq.c b/kernel/rseq.c
index bda8175f8f99..d38ab944105d 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -171,12 +171,27 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
return 0;
}
+static bool rseq_warn_flags(const char *str, u32 flags)
+{
+ u32 test_flags;
+
+ if (!flags)
+ return false;
+ test_flags = flags & RSEQ_CS_NO_RESTART_FLAGS;
+ if (test_flags)
+ pr_warn_once("Deprecated flags (%u) in %s ABI structure", test_flags, str);
+ test_flags = flags & ~RSEQ_CS_NO_RESTART_FLAGS;
+ if (test_flags)
+ pr_warn_once("Unknown flags (%u) in %s ABI structure", test_flags, str);
+ return true;
+}
+
static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
{
u32 flags, event_mask;
int ret;
- if (WARN_ON_ONCE(cs_flags & RSEQ_CS_NO_RESTART_FLAGS) || cs_flags)
+ if (rseq_warn_flags("rseq_cs", cs_flags))
return -EINVAL;
/* Get thread flags. */
@@ -184,7 +199,7 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
if (ret)
return ret;
- if (WARN_ON_ONCE(flags & RSEQ_CS_NO_RESTART_FLAGS) || flags)
+ if (rseq_warn_flags("rseq", flags))
return -EINVAL;
/*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index cb2aa2b54c7a..78b2d5cabcc5 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1392,7 +1392,7 @@ static inline void uclamp_idle_reset(struct rq *rq, enum uclamp_id clamp_id,
if (!(rq->uclamp_flags & UCLAMP_FLAG_IDLE))
return;
- WRITE_ONCE(rq->uclamp[clamp_id].value, clamp_value);
+ uclamp_rq_set(rq, clamp_id, clamp_value);
}
static inline
@@ -1543,8 +1543,8 @@ static inline void uclamp_rq_inc_id(struct rq *rq, struct task_struct *p,
if (bucket->tasks == 1 || uc_se->value > bucket->value)
bucket->value = uc_se->value;
- if (uc_se->value > READ_ONCE(uc_rq->value))
- WRITE_ONCE(uc_rq->value, uc_se->value);
+ if (uc_se->value > uclamp_rq_get(rq, clamp_id))
+ uclamp_rq_set(rq, clamp_id, uc_se->value);
}
/*
@@ -1610,7 +1610,7 @@ static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
if (likely(bucket->tasks))
return;
- rq_clamp = READ_ONCE(uc_rq->value);
+ rq_clamp = uclamp_rq_get(rq, clamp_id);
/*
* Defensive programming: this should never happen. If it happens,
* e.g. due to future modification, warn and fixup the expected value.
@@ -1618,7 +1618,7 @@ static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
SCHED_WARN_ON(bucket->value > rq_clamp);
if (bucket->value >= rq_clamp) {
bkt_clamp = uclamp_rq_max_value(rq, clamp_id, uc_se->value);
- WRITE_ONCE(uc_rq->value, bkt_clamp);
+ uclamp_rq_set(rq, clamp_id, bkt_clamp);
}
}
@@ -2053,7 +2053,7 @@ static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
if (!(flags & ENQUEUE_RESTORE)) {
sched_info_enqueue(rq, p);
- psi_enqueue(p, flags & ENQUEUE_WAKEUP);
+ psi_enqueue(p, (flags & ENQUEUE_WAKEUP) && !(flags & ENQUEUE_MIGRATED));
}
uclamp_rq_inc(rq, p);
@@ -2189,14 +2189,18 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
#ifdef CONFIG_SMP
static void
-__do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32 flags);
+__do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx);
static int __set_cpus_allowed_ptr(struct task_struct *p,
- const struct cpumask *new_mask,
- u32 flags);
+ struct affinity_context *ctx);
static void migrate_disable_switch(struct rq *rq, struct task_struct *p)
{
+ struct affinity_context ac = {
+ .new_mask = cpumask_of(rq->cpu),
+ .flags = SCA_MIGRATE_DISABLE,
+ };
+
if (likely(!p->migration_disabled))
return;
@@ -2206,7 +2210,7 @@ static void migrate_disable_switch(struct rq *rq, struct task_struct *p)
/*
* Violates locking rules! see comment in __do_set_cpus_allowed().
*/
- __do_set_cpus_allowed(p, cpumask_of(rq->cpu), SCA_MIGRATE_DISABLE);
+ __do_set_cpus_allowed(p, &ac);
}
void migrate_disable(void)
@@ -2228,6 +2232,10 @@ EXPORT_SYMBOL_GPL(migrate_disable);
void migrate_enable(void)
{
struct task_struct *p = current;
+ struct affinity_context ac = {
+ .new_mask = &p->cpus_mask,
+ .flags = SCA_MIGRATE_ENABLE,
+ };
if (p->migration_disabled > 1) {
p->migration_disabled--;
@@ -2243,7 +2251,7 @@ void migrate_enable(void)
*/
preempt_disable();
if (p->cpus_ptr != &p->cpus_mask)
- __set_cpus_allowed_ptr(p, &p->cpus_mask, SCA_MIGRATE_ENABLE);
+ __set_cpus_allowed_ptr(p, &ac);
/*
* Mustn't clear migration_disabled() until cpus_ptr points back at the
* regular cpus_mask, otherwise things that race (eg.
@@ -2523,19 +2531,25 @@ out_unlock:
* sched_class::set_cpus_allowed must do the below, but is not required to
* actually call this function.
*/
-void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask, u32 flags)
+void set_cpus_allowed_common(struct task_struct *p, struct affinity_context *ctx)
{
- if (flags & (SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) {
- p->cpus_ptr = new_mask;
+ if (ctx->flags & (SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) {
+ p->cpus_ptr = ctx->new_mask;
return;
}
- cpumask_copy(&p->cpus_mask, new_mask);
- p->nr_cpus_allowed = cpumask_weight(new_mask);
+ cpumask_copy(&p->cpus_mask, ctx->new_mask);
+ p->nr_cpus_allowed = cpumask_weight(ctx->new_mask);
+
+ /*
+ * Swap in a new user_cpus_ptr if SCA_USER flag set
+ */
+ if (ctx->flags & SCA_USER)
+ swap(p->user_cpus_ptr, ctx->user_mask);
}
static void
-__do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32 flags)
+__do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx)
{
struct rq *rq = task_rq(p);
bool queued, running;
@@ -2552,7 +2566,7 @@ __do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32
*
* XXX do further audits, this smells like something putrid.
*/
- if (flags & SCA_MIGRATE_DISABLE)
+ if (ctx->flags & SCA_MIGRATE_DISABLE)
SCHED_WARN_ON(!p->on_cpu);
else
lockdep_assert_held(&p->pi_lock);
@@ -2571,7 +2585,7 @@ __do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32
if (running)
put_prev_task(rq, p);
- p->sched_class->set_cpus_allowed(p, new_mask, flags);
+ p->sched_class->set_cpus_allowed(p, ctx);
if (queued)
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
@@ -2579,14 +2593,27 @@ __do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32
set_next_task(rq, p);
}
+/*
+ * Used for kthread_bind() and select_fallback_rq(), in both cases the user
+ * affinity (if any) should be destroyed too.
+ */
void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
{
- __do_set_cpus_allowed(p, new_mask, 0);
+ struct affinity_context ac = {
+ .new_mask = new_mask,
+ .user_mask = NULL,
+ .flags = SCA_USER, /* clear the user requested mask */
+ };
+
+ __do_set_cpus_allowed(p, &ac);
+ kfree(ac.user_mask);
}
int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
int node)
{
+ unsigned long flags;
+
if (!src->user_cpus_ptr)
return 0;
@@ -2594,7 +2621,10 @@ int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
if (!dst->user_cpus_ptr)
return -ENOMEM;
+ /* Use pi_lock to protect content of user_cpus_ptr */
+ raw_spin_lock_irqsave(&src->pi_lock, flags);
cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
+ raw_spin_unlock_irqrestore(&src->pi_lock, flags);
return 0;
}
@@ -2690,6 +2720,8 @@ void release_user_cpus_ptr(struct task_struct *p)
*/
static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flags *rf,
int dest_cpu, unsigned int flags)
+ __releases(rq->lock)
+ __releases(p->pi_lock)
{
struct set_affinity_pending my_pending = { }, *pending = NULL;
bool stop_pending, complete = false;
@@ -2832,8 +2864,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
* Called with both p->pi_lock and rq->lock held; drops both before returning.
*/
static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
- const struct cpumask *new_mask,
- u32 flags,
+ struct affinity_context *ctx,
struct rq *rq,
struct rq_flags *rf)
__releases(rq->lock)
@@ -2842,7 +2873,6 @@ static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
const struct cpumask *cpu_allowed_mask = task_cpu_possible_mask(p);
const struct cpumask *cpu_valid_mask = cpu_active_mask;
bool kthread = p->flags & PF_KTHREAD;
- struct cpumask *user_mask = NULL;
unsigned int dest_cpu;
int ret = 0;
@@ -2862,7 +2892,7 @@ static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
cpu_valid_mask = cpu_online_mask;
}
- if (!kthread && !cpumask_subset(new_mask, cpu_allowed_mask)) {
+ if (!kthread && !cpumask_subset(ctx->new_mask, cpu_allowed_mask)) {
ret = -EINVAL;
goto out;
}
@@ -2871,18 +2901,18 @@ static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
* Must re-check here, to close a race against __kthread_bind(),
* sched_setaffinity() is not guaranteed to observe the flag.
*/
- if ((flags & SCA_CHECK) && (p->flags & PF_NO_SETAFFINITY)) {
+ if ((ctx->flags & SCA_CHECK) && (p->flags & PF_NO_SETAFFINITY)) {
ret = -EINVAL;
goto out;
}
- if (!(flags & SCA_MIGRATE_ENABLE)) {
- if (cpumask_equal(&p->cpus_mask, new_mask))
+ if (!(ctx->flags & SCA_MIGRATE_ENABLE)) {
+ if (cpumask_equal(&p->cpus_mask, ctx->new_mask))
goto out;
if (WARN_ON_ONCE(p == current &&
is_migration_disabled(p) &&
- !cpumask_test_cpu(task_cpu(p), new_mask))) {
+ !cpumask_test_cpu(task_cpu(p), ctx->new_mask))) {
ret = -EBUSY;
goto out;
}
@@ -2893,22 +2923,15 @@ static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
* for groups of tasks (ie. cpuset), so that load balancing is not
* immediately required to distribute the tasks within their new mask.
*/
- dest_cpu = cpumask_any_and_distribute(cpu_valid_mask, new_mask);
+ dest_cpu = cpumask_any_and_distribute(cpu_valid_mask, ctx->new_mask);
if (dest_cpu >= nr_cpu_ids) {
ret = -EINVAL;
goto out;
}
- __do_set_cpus_allowed(p, new_mask, flags);
-
- if (flags & SCA_USER)
- user_mask = clear_user_cpus_ptr(p);
+ __do_set_cpus_allowed(p, ctx);
- ret = affine_move_task(rq, p, rf, dest_cpu, flags);
-
- kfree(user_mask);
-
- return ret;
+ return affine_move_task(rq, p, rf, dest_cpu, ctx->flags);
out:
task_rq_unlock(rq, p, rf);
@@ -2926,25 +2949,41 @@ out:
* call is not atomic; no spinlocks may be held.
*/
static int __set_cpus_allowed_ptr(struct task_struct *p,
- const struct cpumask *new_mask, u32 flags)
+ struct affinity_context *ctx)
{
struct rq_flags rf;
struct rq *rq;
rq = task_rq_lock(p, &rf);
- return __set_cpus_allowed_ptr_locked(p, new_mask, flags, rq, &rf);
+ /*
+ * Masking should be skipped if SCA_USER or any of the SCA_MIGRATE_*
+ * flags are set.
+ */
+ if (p->user_cpus_ptr &&
+ !(ctx->flags & (SCA_USER | SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) &&
+ cpumask_and(rq->scratch_mask, ctx->new_mask, p->user_cpus_ptr))
+ ctx->new_mask = rq->scratch_mask;
+
+ return __set_cpus_allowed_ptr_locked(p, ctx, rq, &rf);
}
int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
{
- return __set_cpus_allowed_ptr(p, new_mask, 0);
+ struct affinity_context ac = {
+ .new_mask = new_mask,
+ .flags = 0,
+ };
+
+ return __set_cpus_allowed_ptr(p, &ac);
}
EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
/*
* Change a given task's CPU affinity to the intersection of its current
- * affinity mask and @subset_mask, writing the resulting mask to @new_mask
- * and pointing @p->user_cpus_ptr to a copy of the old mask.
+ * affinity mask and @subset_mask, writing the resulting mask to @new_mask.
+ * If user_cpus_ptr is defined, use it as the basis for restricting CPU
+ * affinity or use cpu_online_mask instead.
+ *
* If the resulting mask is empty, leave the affinity unchanged and return
* -EINVAL.
*/
@@ -2952,17 +2991,14 @@ static int restrict_cpus_allowed_ptr(struct task_struct *p,
struct cpumask *new_mask,
const struct cpumask *subset_mask)
{
- struct cpumask *user_mask = NULL;
+ struct affinity_context ac = {
+ .new_mask = new_mask,
+ .flags = 0,
+ };
struct rq_flags rf;
struct rq *rq;
int err;
- if (!p->user_cpus_ptr) {
- user_mask = kmalloc(cpumask_size(), GFP_KERNEL);
- if (!user_mask)
- return -ENOMEM;
- }
-
rq = task_rq_lock(p, &rf);
/*
@@ -2975,31 +3011,21 @@ static int restrict_cpus_allowed_ptr(struct task_struct *p,
goto err_unlock;
}
- if (!cpumask_and(new_mask, &p->cpus_mask, subset_mask)) {
+ if (!cpumask_and(new_mask, task_user_cpus(p), subset_mask)) {
err = -EINVAL;
goto err_unlock;
}
- /*
- * We're about to butcher the task affinity, so keep track of what
- * the user asked for in case we're able to restore it later on.
- */
- if (user_mask) {
- cpumask_copy(user_mask, p->cpus_ptr);
- p->user_cpus_ptr = user_mask;
- }
-
- return __set_cpus_allowed_ptr_locked(p, new_mask, 0, rq, &rf);
+ return __set_cpus_allowed_ptr_locked(p, &ac, rq, &rf);
err_unlock:
task_rq_unlock(rq, p, &rf);
- kfree(user_mask);
return err;
}
/*
* Restrict the CPU affinity of task @p so that it is a subset of
- * task_cpu_possible_mask() and point @p->user_cpu_ptr to a copy of the
+ * task_cpu_possible_mask() and point @p->user_cpus_ptr to a copy of the
* old affinity mask. If the resulting mask is empty, we warn and walk
* up the cpuset hierarchy until we find a suitable mask.
*/
@@ -3043,34 +3069,29 @@ out_free_mask:
}
static int
-__sched_setaffinity(struct task_struct *p, const struct cpumask *mask);
+__sched_setaffinity(struct task_struct *p, struct affinity_context *ctx);
/*
* Restore the affinity of a task @p which was previously restricted by a
- * call to force_compatible_cpus_allowed_ptr(). This will clear (and free)
- * @p->user_cpus_ptr.
+ * call to force_compatible_cpus_allowed_ptr().
*
* It is the caller's responsibility to serialise this with any calls to
* force_compatible_cpus_allowed_ptr(@p).
*/
void relax_compatible_cpus_allowed_ptr(struct task_struct *p)
{
- struct cpumask *user_mask = p->user_cpus_ptr;
- unsigned long flags;
+ struct affinity_context ac = {
+ .new_mask = task_user_cpus(p),
+ .flags = 0,
+ };
+ int ret;
/*
- * Try to restore the old affinity mask. If this fails, then
- * we free the mask explicitly to avoid it being inherited across
- * a subsequent fork().
+ * Try to restore the old affinity mask with __sched_setaffinity().
+ * Cpuset masking will be done there too.
*/
- if (!user_mask || !__sched_setaffinity(p, user_mask))
- return;
-
- raw_spin_lock_irqsave(&p->pi_lock, flags);
- user_mask = clear_user_cpus_ptr(p);
- raw_spin_unlock_irqrestore(&p->pi_lock, flags);
-
- kfree(user_mask);
+ ret = __sched_setaffinity(p, &ac);
+ WARN_ON_ONCE(ret);
}
void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
@@ -3548,10 +3569,9 @@ void sched_set_stop_task(int cpu, struct task_struct *stop)
#else /* CONFIG_SMP */
static inline int __set_cpus_allowed_ptr(struct task_struct *p,
- const struct cpumask *new_mask,
- u32 flags)
+ struct affinity_context *ctx)
{
- return set_cpus_allowed_ptr(p, new_mask);
+ return set_cpus_allowed_ptr(p, ctx->new_mask);
}
static inline void migrate_disable_switch(struct rq *rq, struct task_struct *p) { }
@@ -3719,13 +3739,6 @@ void sched_ttwu_pending(void *arg)
if (!llist)
return;
- /*
- * rq::ttwu_pending racy indication of out-standing wakeups.
- * Races such that false-negatives are possible, since they
- * are shorter lived that false-positives would be.
- */
- WRITE_ONCE(rq->ttwu_pending, 0);
-
rq_lock_irqsave(rq, &rf);
update_rq_clock(rq);
@@ -3739,6 +3752,17 @@ void sched_ttwu_pending(void *arg)
ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0, &rf);
}
+ /*
+ * Must be after enqueueing at least once task such that
+ * idle_cpu() does not observe a false-negative -- if it does,
+ * it is possible for select_idle_siblings() to stack a number
+ * of tasks on this CPU during that window.
+ *
+ * It is ok to clear ttwu_pending when another task pending.
+ * We will receive IPI after local irq enabled and then enqueue it.
+ * Since now nr_running > 0, idle_cpu() will always get correct result.
+ */
+ WRITE_ONCE(rq->ttwu_pending, 0);
rq_unlock_irqrestore(rq, &rf);
}
@@ -4200,6 +4224,40 @@ out:
return success;
}
+static bool __task_needs_rq_lock(struct task_struct *p)
+{
+ unsigned int state = READ_ONCE(p->__state);
+
+ /*
+ * Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
+ * the task is blocked. Make sure to check @state since ttwu() can drop
+ * locks at the end, see ttwu_queue_wakelist().
+ */
+ if (state == TASK_RUNNING || state == TASK_WAKING)
+ return true;
+
+ /*
+ * Ensure we load p->on_rq after p->__state, otherwise it would be
+ * possible to, falsely, observe p->on_rq == 0.
+ *
+ * See try_to_wake_up() for a longer comment.
+ */
+ smp_rmb();
+ if (p->on_rq)
+ return true;
+
+#ifdef CONFIG_SMP
+ /*
+ * Ensure the task has finished __schedule() and will not be referenced
+ * anymore. Again, see try_to_wake_up() for a longer comment.
+ */
+ smp_rmb();
+ smp_cond_load_acquire(&p->on_cpu, !VAL);
+#endif
+
+ return false;
+}
+
/**
* task_call_func - Invoke a function on task in fixed state
* @p: Process for which the function is to be invoked, can be @current.
@@ -4217,28 +4275,12 @@ out:
int task_call_func(struct task_struct *p, task_call_f func, void *arg)
{
struct rq *rq = NULL;
- unsigned int state;
struct rq_flags rf;
int ret;
raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
- state = READ_ONCE(p->__state);
-
- /*
- * Ensure we load p->on_rq after p->__state, otherwise it would be
- * possible to, falsely, observe p->on_rq == 0.
- *
- * See try_to_wake_up() for a longer comment.
- */
- smp_rmb();
-
- /*
- * Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
- * the task is blocked. Make sure to check @state since ttwu() can drop
- * locks at the end, see ttwu_queue_wakelist().
- */
- if (state == TASK_RUNNING || state == TASK_WAKING || p->on_rq)
+ if (__task_needs_rq_lock(p))
rq = __task_rq_lock(p, &rf);
/*
@@ -8088,7 +8130,7 @@ int dl_task_check_affinity(struct task_struct *p, const struct cpumask *mask)
#endif
static int
-__sched_setaffinity(struct task_struct *p, const struct cpumask *mask)
+__sched_setaffinity(struct task_struct *p, struct affinity_context *ctx)
{
int retval;
cpumask_var_t cpus_allowed, new_mask;
@@ -8102,13 +8144,16 @@ __sched_setaffinity(struct task_struct *p, const struct cpumask *mask)
}
cpuset_cpus_allowed(p, cpus_allowed);
- cpumask_and(new_mask, mask, cpus_allowed);
+ cpumask_and(new_mask, ctx->new_mask, cpus_allowed);
+
+ ctx->new_mask = new_mask;
+ ctx->flags |= SCA_CHECK;
retval = dl_task_check_affinity(p, new_mask);
if (retval)
goto out_free_new_mask;
-again:
- retval = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK | SCA_USER);
+
+ retval = __set_cpus_allowed_ptr(p, ctx);
if (retval)
goto out_free_new_mask;
@@ -8119,7 +8164,24 @@ again:
* Just reset the cpumask to the cpuset's cpus_allowed.
*/
cpumask_copy(new_mask, cpus_allowed);
- goto again;
+
+ /*
+ * If SCA_USER is set, a 2nd call to __set_cpus_allowed_ptr()
+ * will restore the previous user_cpus_ptr value.
+ *
+ * In the unlikely event a previous user_cpus_ptr exists,
+ * we need to further restrict the mask to what is allowed
+ * by that old user_cpus_ptr.
+ */
+ if (unlikely((ctx->flags & SCA_USER) && ctx->user_mask)) {
+ bool empty = !cpumask_and(new_mask, new_mask,
+ ctx->user_mask);
+
+ if (WARN_ON_ONCE(empty))
+ cpumask_copy(new_mask, cpus_allowed);
+ }
+ __set_cpus_allowed_ptr(p, ctx);
+ retval = -EINVAL;
}
out_free_new_mask:
@@ -8131,6 +8193,8 @@ out_free_cpus_allowed:
long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
{
+ struct affinity_context ac;
+ struct cpumask *user_mask;
struct task_struct *p;
int retval;
@@ -8165,7 +8229,21 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
if (retval)
goto out_put_task;
- retval = __sched_setaffinity(p, in_mask);
+ user_mask = kmalloc(cpumask_size(), GFP_KERNEL);
+ if (!user_mask) {
+ retval = -ENOMEM;
+ goto out_put_task;
+ }
+ cpumask_copy(user_mask, in_mask);
+ ac = (struct affinity_context){
+ .new_mask = in_mask,
+ .user_mask = user_mask,
+ .flags = SCA_USER,
+ };
+
+ retval = __sched_setaffinity(p, &ac);
+ kfree(ac.user_mask);
+
out_put_task:
put_task_struct(p);
return retval;
@@ -8946,6 +9024,12 @@ void show_state_filter(unsigned int state_filter)
*/
void __init init_idle(struct task_struct *idle, int cpu)
{
+#ifdef CONFIG_SMP
+ struct affinity_context ac = (struct affinity_context) {
+ .new_mask = cpumask_of(cpu),
+ .flags = 0,
+ };
+#endif
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
@@ -8970,7 +9054,7 @@ void __init init_idle(struct task_struct *idle, int cpu)
*
* And since this is boot we can forgo the serialization.
*/
- set_cpus_allowed_common(idle, cpumask_of(cpu), 0);
+ set_cpus_allowed_common(idle, &ac);
#endif
/*
* We're having a chicken and egg problem, even though we are
@@ -9757,6 +9841,7 @@ void __init sched_init(void)
rq->core_cookie = 0UL;
#endif
+ zalloc_cpumask_var_node(&rq->scratch_mask, GFP_KERNEL, cpu_to_node(i));
}
set_load_weight(&init_task, false);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 9161d1136d01..1207c78f85c1 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -25,9 +25,6 @@ struct sugov_policy {
unsigned int next_freq;
unsigned int cached_raw_freq;
- /* max CPU capacity, which is equal for all CPUs in freq. domain */
- unsigned long max;
-
/* The next fields are only needed if fast switch cannot be used: */
struct irq_work irq_work;
struct kthread_work work;
@@ -51,6 +48,7 @@ struct sugov_cpu {
unsigned long util;
unsigned long bw_dl;
+ unsigned long max;
/* The field below is for single-CPU policies only: */
#ifdef CONFIG_NO_HZ_COMMON
@@ -160,6 +158,7 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu)
{
struct rq *rq = cpu_rq(sg_cpu->cpu);
+ sg_cpu->max = arch_scale_cpu_capacity(sg_cpu->cpu);
sg_cpu->bw_dl = cpu_bw_dl(rq);
sg_cpu->util = effective_cpu_util(sg_cpu->cpu, cpu_util_cfs(sg_cpu->cpu),
FREQUENCY_UTIL, NULL);
@@ -254,7 +253,6 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
*/
static void sugov_iowait_apply(struct sugov_cpu *sg_cpu, u64 time)
{
- struct sugov_policy *sg_policy = sg_cpu->sg_policy;
unsigned long boost;
/* No boost currently required */
@@ -282,8 +280,7 @@ static void sugov_iowait_apply(struct sugov_cpu *sg_cpu, u64 time)
* sg_cpu->util is already in capacity scale; convert iowait_boost
* into the same scale so we can compare.
*/
- boost = sg_cpu->iowait_boost * sg_policy->max;
- boost >>= SCHED_CAPACITY_SHIFT;
+ boost = (sg_cpu->iowait_boost * sg_cpu->max) >> SCHED_CAPACITY_SHIFT;
boost = uclamp_rq_util_with(cpu_rq(sg_cpu->cpu), boost, NULL);
if (sg_cpu->util < boost)
sg_cpu->util = boost;
@@ -340,7 +337,7 @@ static void sugov_update_single_freq(struct update_util_data *hook, u64 time,
if (!sugov_update_single_common(sg_cpu, time, flags))
return;
- next_f = get_next_freq(sg_policy, sg_cpu->util, sg_policy->max);
+ next_f = get_next_freq(sg_policy, sg_cpu->util, sg_cpu->max);
/*
* Do not reduce the frequency if the CPU has not been idle
* recently, as the reduction is likely to be premature then.
@@ -376,7 +373,6 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
unsigned int flags)
{
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
- struct sugov_policy *sg_policy = sg_cpu->sg_policy;
unsigned long prev_util = sg_cpu->util;
/*
@@ -403,8 +399,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
sg_cpu->util = prev_util;
cpufreq_driver_adjust_perf(sg_cpu->cpu, map_util_perf(sg_cpu->bw_dl),
- map_util_perf(sg_cpu->util),
- sg_policy->max);
+ map_util_perf(sg_cpu->util), sg_cpu->max);
sg_cpu->sg_policy->last_freq_update_time = time;
}
@@ -413,19 +408,25 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time)
{
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
struct cpufreq_policy *policy = sg_policy->policy;
- unsigned long util = 0;
+ unsigned long util = 0, max = 1;
unsigned int j;
for_each_cpu(j, policy->cpus) {
struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j);
+ unsigned long j_util, j_max;
sugov_get_util(j_sg_cpu);
sugov_iowait_apply(j_sg_cpu, time);
+ j_util = j_sg_cpu->util;
+ j_max = j_sg_cpu->max;
- util = max(j_sg_cpu->util, util);
+ if (j_util * max > j_max * util) {
+ util = j_util;
+ max = j_max;
+ }
}
- return get_next_freq(sg_policy, util, sg_policy->max);
+ return get_next_freq(sg_policy, util, max);
}
static void
@@ -751,7 +752,7 @@ static int sugov_start(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
void (*uu)(struct update_util_data *data, u64 time, unsigned int flags);
- unsigned int cpu = cpumask_first(policy->cpus);
+ unsigned int cpu;
sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
sg_policy->last_freq_update_time = 0;
@@ -759,7 +760,6 @@ static int sugov_start(struct cpufreq_policy *policy)
sg_policy->work_in_progress = false;
sg_policy->limits_changed = false;
sg_policy->cached_raw_freq = 0;
- sg_policy->max = arch_scale_cpu_capacity(cpu);
sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS);
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 9ae8f41e3372..0d97d54276cc 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -2485,8 +2485,7 @@ static void task_woken_dl(struct rq *rq, struct task_struct *p)
}
static void set_cpus_allowed_dl(struct task_struct *p,
- const struct cpumask *new_mask,
- u32 flags)
+ struct affinity_context *ctx)
{
struct root_domain *src_rd;
struct rq *rq;
@@ -2501,7 +2500,7 @@ static void set_cpus_allowed_dl(struct task_struct *p,
* update. We already made space for us in the destination
* domain (see cpuset_can_attach()).
*/
- if (!cpumask_intersects(src_rd->span, new_mask)) {
+ if (!cpumask_intersects(src_rd->span, ctx->new_mask)) {
struct dl_bw *src_dl_b;
src_dl_b = dl_bw_of(cpu_of(rq));
@@ -2515,7 +2514,7 @@ static void set_cpus_allowed_dl(struct task_struct *p,
raw_spin_unlock(&src_dl_b->lock);
}
- set_cpus_allowed_common(p, new_mask, flags);
+ set_cpus_allowed_common(p, ctx);
}
/* Assumes rq->lock is held */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e4a0b8bd941c..0cd1d0f7c1bd 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2964,7 +2964,7 @@ static void task_numa_work(struct callback_head *work)
}
next_scan = now + msecs_to_jiffies(p->numa_scan_period);
- if (cmpxchg(&mm->numa_next_scan, migrate, next_scan) != migrate)
+ if (!try_cmpxchg(&mm->numa_next_scan, &migrate, next_scan))
return;
/*
@@ -4280,14 +4280,16 @@ static inline unsigned long task_util_est(struct task_struct *p)
}
#ifdef CONFIG_UCLAMP_TASK
-static inline unsigned long uclamp_task_util(struct task_struct *p)
+static inline unsigned long uclamp_task_util(struct task_struct *p,
+ unsigned long uclamp_min,
+ unsigned long uclamp_max)
{
- return clamp(task_util_est(p),
- uclamp_eff_value(p, UCLAMP_MIN),
- uclamp_eff_value(p, UCLAMP_MAX));
+ return clamp(task_util_est(p), uclamp_min, uclamp_max);
}
#else
-static inline unsigned long uclamp_task_util(struct task_struct *p)
+static inline unsigned long uclamp_task_util(struct task_struct *p,
+ unsigned long uclamp_min,
+ unsigned long uclamp_max)
{
return task_util_est(p);
}
@@ -4426,10 +4428,139 @@ done:
trace_sched_util_est_se_tp(&p->se);
}
-static inline int task_fits_capacity(struct task_struct *p,
- unsigned long capacity)
+static inline int util_fits_cpu(unsigned long util,
+ unsigned long uclamp_min,
+ unsigned long uclamp_max,
+ int cpu)
{
- return fits_capacity(uclamp_task_util(p), capacity);
+ unsigned long capacity_orig, capacity_orig_thermal;
+ unsigned long capacity = capacity_of(cpu);
+ bool fits, uclamp_max_fits;
+
+ /*
+ * Check if the real util fits without any uclamp boost/cap applied.
+ */
+ fits = fits_capacity(util, capacity);
+
+ if (!uclamp_is_used())
+ return fits;
+
+ /*
+ * We must use capacity_orig_of() for comparing against uclamp_min and
+ * uclamp_max. We only care about capacity pressure (by using
+ * capacity_of()) for comparing against the real util.
+ *
+ * If a task is boosted to 1024 for example, we don't want a tiny
+ * pressure to skew the check whether it fits a CPU or not.
+ *
+ * Similarly if a task is capped to capacity_orig_of(little_cpu), it
+ * should fit a little cpu even if there's some pressure.
+ *
+ * Only exception is for thermal pressure since it has a direct impact
+ * on available OPP of the system.
+ *
+ * We honour it for uclamp_min only as a drop in performance level
+ * could result in not getting the requested minimum performance level.
+ *
+ * For uclamp_max, we can tolerate a drop in performance level as the
+ * goal is to cap the task. So it's okay if it's getting less.
+ *
+ * In case of capacity inversion we should honour the inverted capacity
+ * for both uclamp_min and uclamp_max all the time.
+ */
+ capacity_orig = cpu_in_capacity_inversion(cpu);
+ if (capacity_orig) {
+ capacity_orig_thermal = capacity_orig;
+ } else {
+ capacity_orig = capacity_orig_of(cpu);
+ capacity_orig_thermal = capacity_orig - arch_scale_thermal_pressure(cpu);
+ }
+
+ /*
+ * We want to force a task to fit a cpu as implied by uclamp_max.
+ * But we do have some corner cases to cater for..
+ *
+ *
+ * C=z
+ * | ___
+ * | C=y | |
+ * |_ _ _ _ _ _ _ _ _ ___ _ _ _ | _ | _ _ _ _ _ uclamp_max
+ * | C=x | | | |
+ * | ___ | | | |
+ * | | | | | | | (util somewhere in this region)
+ * | | | | | | |
+ * | | | | | | |
+ * +----------------------------------------
+ * cpu0 cpu1 cpu2
+ *
+ * In the above example if a task is capped to a specific performance
+ * point, y, then when:
+ *
+ * * util = 80% of x then it does not fit on cpu0 and should migrate
+ * to cpu1
+ * * util = 80% of y then it is forced to fit on cpu1 to honour
+ * uclamp_max request.
+ *
+ * which is what we're enforcing here. A task always fits if
+ * uclamp_max <= capacity_orig. But when uclamp_max > capacity_orig,
+ * the normal upmigration rules should withhold still.
+ *
+ * Only exception is when we are on max capacity, then we need to be
+ * careful not to block overutilized state. This is so because:
+ *
+ * 1. There's no concept of capping at max_capacity! We can't go
+ * beyond this performance level anyway.
+ * 2. The system is being saturated when we're operating near
+ * max capacity, it doesn't make sense to block overutilized.
+ */
+ uclamp_max_fits = (capacity_orig == SCHED_CAPACITY_SCALE) && (uclamp_max == SCHED_CAPACITY_SCALE);
+ uclamp_max_fits = !uclamp_max_fits && (uclamp_max <= capacity_orig);
+ fits = fits || uclamp_max_fits;
+
+ /*
+ *
+ * C=z
+ * | ___ (region a, capped, util >= uclamp_max)
+ * | C=y | |
+ * |_ _ _ _ _ _ _ _ _ ___ _ _ _ | _ | _ _ _ _ _ uclamp_max
+ * | C=x | | | |
+ * | ___ | | | | (region b, uclamp_min <= util <= uclamp_max)
+ * |_ _ _|_ _|_ _ _ _| _ | _ _ _| _ | _ _ _ _ _ uclamp_min
+ * | | | | | | |
+ * | | | | | | | (region c, boosted, util < uclamp_min)
+ * +----------------------------------------
+ * cpu0 cpu1 cpu2
+ *
+ * a) If util > uclamp_max, then we're capped, we don't care about
+ * actual fitness value here. We only care if uclamp_max fits
+ * capacity without taking margin/pressure into account.
+ * See comment above.
+ *
+ * b) If uclamp_min <= util <= uclamp_max, then the normal
+ * fits_capacity() rules apply. Except we need to ensure that we
+ * enforce we remain within uclamp_max, see comment above.
+ *
+ * c) If util < uclamp_min, then we are boosted. Same as (b) but we
+ * need to take into account the boosted value fits the CPU without
+ * taking margin/pressure into account.
+ *
+ * Cases (a) and (b) are handled in the 'fits' variable already. We
+ * just need to consider an extra check for case (c) after ensuring we
+ * handle the case uclamp_min > uclamp_max.
+ */
+ uclamp_min = min(uclamp_min, uclamp_max);
+ if (util < uclamp_min && capacity_orig != SCHED_CAPACITY_SCALE)
+ fits = fits && (uclamp_min <= capacity_orig_thermal);
+
+ return fits;
+}
+
+static inline int task_fits_cpu(struct task_struct *p, int cpu)
+{
+ unsigned long uclamp_min = uclamp_eff_value(p, UCLAMP_MIN);
+ unsigned long uclamp_max = uclamp_eff_value(p, UCLAMP_MAX);
+ unsigned long util = task_util_est(p);
+ return util_fits_cpu(util, uclamp_min, uclamp_max, cpu);
}
static inline void update_misfit_status(struct task_struct *p, struct rq *rq)
@@ -4442,7 +4573,7 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq)
return;
}
- if (task_fits_capacity(p, capacity_of(cpu_of(rq)))) {
+ if (task_fits_cpu(p, cpu_of(rq))) {
rq->misfit_task_load = 0;
return;
}
@@ -5862,7 +5993,10 @@ static inline void hrtick_update(struct rq *rq)
#ifdef CONFIG_SMP
static inline bool cpu_overutilized(int cpu)
{
- return !fits_capacity(cpu_util_cfs(cpu), capacity_of(cpu));
+ unsigned long rq_util_min = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MIN);
+ unsigned long rq_util_max = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MAX);
+
+ return !util_fits_cpu(cpu_util_cfs(cpu), rq_util_min, rq_util_max, cpu);
}
static inline void update_overutilized_status(struct rq *rq)
@@ -6654,21 +6788,23 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
static int
select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
{
- unsigned long task_util, best_cap = 0;
+ unsigned long task_util, util_min, util_max, best_cap = 0;
int cpu, best_cpu = -1;
struct cpumask *cpus;
cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
cpumask_and(cpus, sched_domain_span(sd), p->cpus_ptr);
- task_util = uclamp_task_util(p);
+ task_util = task_util_est(p);
+ util_min = uclamp_eff_value(p, UCLAMP_MIN);
+ util_max = uclamp_eff_value(p, UCLAMP_MAX);
for_each_cpu_wrap(cpu, cpus, target) {
unsigned long cpu_cap = capacity_of(cpu);
if (!available_idle_cpu(cpu) && !sched_idle_cpu(cpu))
continue;
- if (fits_capacity(task_util, cpu_cap))
+ if (util_fits_cpu(task_util, util_min, util_max, cpu))
return cpu;
if (cpu_cap > best_cap) {
@@ -6680,10 +6816,13 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
return best_cpu;
}
-static inline bool asym_fits_capacity(unsigned long task_util, int cpu)
+static inline bool asym_fits_cpu(unsigned long util,
+ unsigned long util_min,
+ unsigned long util_max,
+ int cpu)
{
if (sched_asym_cpucap_active())
- return fits_capacity(task_util, capacity_of(cpu));
+ return util_fits_cpu(util, util_min, util_max, cpu);
return true;
}
@@ -6695,7 +6834,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
{
bool has_idle_core = false;
struct sched_domain *sd;
- unsigned long task_util;
+ unsigned long task_util, util_min, util_max;
int i, recent_used_cpu;
/*
@@ -6704,7 +6843,9 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
*/
if (sched_asym_cpucap_active()) {
sync_entity_load_avg(&p->se);
- task_util = uclamp_task_util(p);
+ task_util = task_util_est(p);
+ util_min = uclamp_eff_value(p, UCLAMP_MIN);
+ util_max = uclamp_eff_value(p, UCLAMP_MAX);
}
/*
@@ -6713,7 +6854,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
lockdep_assert_irqs_disabled();
if ((available_idle_cpu(target) || sched_idle_cpu(target)) &&
- asym_fits_capacity(task_util, target))
+ asym_fits_cpu(task_util, util_min, util_max, target))
return target;
/*
@@ -6721,7 +6862,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
*/
if (prev != target && cpus_share_cache(prev, target) &&
(available_idle_cpu(prev) || sched_idle_cpu(prev)) &&
- asym_fits_capacity(task_util, prev))
+ asym_fits_cpu(task_util, util_min, util_max, prev))
return prev;
/*
@@ -6736,7 +6877,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
in_task() &&
prev == smp_processor_id() &&
this_rq()->nr_running <= 1 &&
- asym_fits_capacity(task_util, prev)) {
+ asym_fits_cpu(task_util, util_min, util_max, prev)) {
return prev;
}
@@ -6748,7 +6889,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
cpus_share_cache(recent_used_cpu, target) &&
(available_idle_cpu(recent_used_cpu) || sched_idle_cpu(recent_used_cpu)) &&
cpumask_test_cpu(p->recent_used_cpu, p->cpus_ptr) &&
- asym_fits_capacity(task_util, recent_used_cpu)) {
+ asym_fits_cpu(task_util, util_min, util_max, recent_used_cpu)) {
return recent_used_cpu;
}
@@ -7044,6 +7185,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
{
struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX;
+ unsigned long p_util_min = uclamp_is_used() ? uclamp_eff_value(p, UCLAMP_MIN) : 0;
+ unsigned long p_util_max = uclamp_is_used() ? uclamp_eff_value(p, UCLAMP_MAX) : 1024;
struct root_domain *rd = this_rq()->rd;
int cpu, best_energy_cpu, target = -1;
struct sched_domain *sd;
@@ -7068,7 +7211,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
target = prev_cpu;
sync_entity_load_avg(&p->se);
- if (!task_util_est(p))
+ if (!uclamp_task_util(p, p_util_min, p_util_max))
goto unlock;
eenv_task_busy_time(&eenv, p, prev_cpu);
@@ -7076,7 +7219,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
for (; pd; pd = pd->next) {
unsigned long cpu_cap, cpu_thermal_cap, util;
unsigned long cur_delta, max_spare_cap = 0;
- bool compute_prev_delta = false;
+ unsigned long rq_util_min, rq_util_max;
+ unsigned long util_min, util_max;
+ unsigned long prev_spare_cap = 0;
int max_spare_cap_cpu = -1;
unsigned long base_energy;
@@ -7112,26 +7257,45 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
* much capacity we can get out of the CPU; this is
* aligned with sched_cpu_util().
*/
- util = uclamp_rq_util_with(cpu_rq(cpu), util, p);
- if (!fits_capacity(util, cpu_cap))
+ if (uclamp_is_used()) {
+ if (uclamp_rq_is_idle(cpu_rq(cpu))) {
+ util_min = p_util_min;
+ util_max = p_util_max;
+ } else {
+ /*
+ * Open code uclamp_rq_util_with() except for
+ * the clamp() part. Ie: apply max aggregation
+ * only. util_fits_cpu() logic requires to
+ * operate on non clamped util but must use the
+ * max-aggregated uclamp_{min, max}.
+ */
+ rq_util_min = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MIN);
+ rq_util_max = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MAX);
+
+ util_min = max(rq_util_min, p_util_min);
+ util_max = max(rq_util_max, p_util_max);
+ }
+ }
+ if (!util_fits_cpu(util, util_min, util_max, cpu))
continue;
lsub_positive(&cpu_cap, util);
if (cpu == prev_cpu) {
/* Always use prev_cpu as a candidate. */
- compute_prev_delta = true;
+ prev_spare_cap = cpu_cap;
} else if (cpu_cap > max_spare_cap) {
/*
* Find the CPU with the maximum spare capacity
- * in the performance domain.
+ * among the remaining CPUs in the performance
+ * domain.
*/
max_spare_cap = cpu_cap;
max_spare_cap_cpu = cpu;
}
}
- if (max_spare_cap_cpu < 0 && !compute_prev_delta)
+ if (max_spare_cap_cpu < 0 && prev_spare_cap == 0)
continue;
eenv_pd_busy_time(&eenv, cpus, p);
@@ -7139,7 +7303,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
base_energy = compute_energy(&eenv, pd, cpus, p, -1);
/* Evaluate the energy impact of using prev_cpu. */
- if (compute_prev_delta) {
+ if (prev_spare_cap > 0) {
prev_delta = compute_energy(&eenv, pd, cpus, p,
prev_cpu);
/* CPU utilization has changed */
@@ -7150,7 +7314,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
}
/* Evaluate the energy impact of using max_spare_cap_cpu. */
- if (max_spare_cap_cpu >= 0) {
+ if (max_spare_cap_cpu >= 0 && max_spare_cap > prev_spare_cap) {
cur_delta = compute_energy(&eenv, pd, cpus, p,
max_spare_cap_cpu);
/* CPU utilization has changed */
@@ -8276,7 +8440,7 @@ static int detach_tasks(struct lb_env *env)
case migrate_misfit:
/* This is not a misfit task */
- if (task_fits_capacity(p, capacity_of(env->src_cpu)))
+ if (task_fits_cpu(p, env->src_cpu))
goto next;
env->imbalance = 0;
@@ -8665,16 +8829,73 @@ static unsigned long scale_rt_capacity(int cpu)
static void update_cpu_capacity(struct sched_domain *sd, int cpu)
{
+ unsigned long capacity_orig = arch_scale_cpu_capacity(cpu);
unsigned long capacity = scale_rt_capacity(cpu);
struct sched_group *sdg = sd->groups;
+ struct rq *rq = cpu_rq(cpu);
- cpu_rq(cpu)->cpu_capacity_orig = arch_scale_cpu_capacity(cpu);
+ rq->cpu_capacity_orig = capacity_orig;
if (!capacity)
capacity = 1;
- cpu_rq(cpu)->cpu_capacity = capacity;
- trace_sched_cpu_capacity_tp(cpu_rq(cpu));
+ rq->cpu_capacity = capacity;
+
+ /*
+ * Detect if the performance domain is in capacity inversion state.
+ *
+ * Capacity inversion happens when another perf domain with equal or
+ * lower capacity_orig_of() ends up having higher capacity than this
+ * domain after subtracting thermal pressure.
+ *
+ * We only take into account thermal pressure in this detection as it's
+ * the only metric that actually results in *real* reduction of
+ * capacity due to performance points (OPPs) being dropped/become
+ * unreachable due to thermal throttling.
+ *
+ * We assume:
+ * * That all cpus in a perf domain have the same capacity_orig
+ * (same uArch).
+ * * Thermal pressure will impact all cpus in this perf domain
+ * equally.
+ */
+ if (static_branch_unlikely(&sched_asym_cpucapacity)) {
+ unsigned long inv_cap = capacity_orig - thermal_load_avg(rq);
+ struct perf_domain *pd = rcu_dereference(rq->rd->pd);
+
+ rq->cpu_capacity_inverted = 0;
+
+ for (; pd; pd = pd->next) {
+ struct cpumask *pd_span = perf_domain_span(pd);
+ unsigned long pd_cap_orig, pd_cap;
+
+ cpu = cpumask_any(pd_span);
+ pd_cap_orig = arch_scale_cpu_capacity(cpu);
+
+ if (capacity_orig < pd_cap_orig)
+ continue;
+
+ /*
+ * handle the case of multiple perf domains have the
+ * same capacity_orig but one of them is under higher
+ * thermal pressure. We record it as capacity
+ * inversion.
+ */
+ if (capacity_orig == pd_cap_orig) {
+ pd_cap = pd_cap_orig - thermal_load_avg(cpu_rq(cpu));
+
+ if (pd_cap > inv_cap) {
+ rq->cpu_capacity_inverted = inv_cap;
+ break;
+ }
+ } else if (pd_cap_orig > inv_cap) {
+ rq->cpu_capacity_inverted = inv_cap;
+ break;
+ }
+ }
+ }
+
+ trace_sched_cpu_capacity_tp(rq);
sdg->sgc->capacity = capacity;
sdg->sgc->min_capacity = capacity;
@@ -9281,6 +9502,10 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd,
memset(sgs, 0, sizeof(*sgs));
+ /* Assume that task can't fit any CPU of the group */
+ if (sd->flags & SD_ASYM_CPUCAPACITY)
+ sgs->group_misfit_task_load = 1;
+
for_each_cpu(i, sched_group_span(group)) {
struct rq *rq = cpu_rq(i);
unsigned int local;
@@ -9300,12 +9525,12 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd,
if (!nr_running && idle_cpu_without(i, p))
sgs->idle_cpus++;
- }
+ /* Check if task fits in the CPU */
+ if (sd->flags & SD_ASYM_CPUCAPACITY &&
+ sgs->group_misfit_task_load &&
+ task_fits_cpu(p, i))
+ sgs->group_misfit_task_load = 0;
- /* Check if task fits in the group */
- if (sd->flags & SD_ASYM_CPUCAPACITY &&
- !task_fits_capacity(p, group->sgc->max_capacity)) {
- sgs->group_misfit_task_load = 1;
}
sgs->group_capacity = group->sgc->capacity;
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
index ee2ecc081422..8ac8b81bfee6 100644
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -189,6 +189,7 @@ static void group_init(struct psi_group *group)
INIT_DELAYED_WORK(&group->avgs_work, psi_avgs_work);
mutex_init(&group->avgs_lock);
/* Init trigger-related members */
+ atomic_set(&group->poll_scheduled, 0);
mutex_init(&group->trigger_lock);
INIT_LIST_HEAD(&group->triggers);
group->poll_min_period = U32_MAX;
@@ -242,6 +243,8 @@ static void get_recent_times(struct psi_group *group, int cpu,
u32 *pchanged_states)
{
struct psi_group_cpu *groupc = per_cpu_ptr(group->pcpu, cpu);
+ int current_cpu = raw_smp_processor_id();
+ unsigned int tasks[NR_PSI_TASK_COUNTS];
u64 now, state_start;
enum psi_states s;
unsigned int seq;
@@ -256,6 +259,8 @@ static void get_recent_times(struct psi_group *group, int cpu,
memcpy(times, groupc->times, sizeof(groupc->times));
state_mask = groupc->state_mask;
state_start = groupc->state_start;
+ if (cpu == current_cpu)
+ memcpy(tasks, groupc->tasks, sizeof(groupc->tasks));
} while (read_seqcount_retry(&groupc->seq, seq));
/* Calculate state time deltas against the previous snapshot */
@@ -280,6 +285,28 @@ static void get_recent_times(struct psi_group *group, int cpu,
if (delta)
*pchanged_states |= (1 << s);
}
+
+ /*
+ * When collect_percpu_times() from the avgs_work, we don't want to
+ * re-arm avgs_work when all CPUs are IDLE. But the current CPU running
+ * this avgs_work is never IDLE, cause avgs_work can't be shut off.
+ * So for the current CPU, we need to re-arm avgs_work only when
+ * (NR_RUNNING > 1 || NR_IOWAIT > 0 || NR_MEMSTALL > 0), for other CPUs
+ * we can just check PSI_NONIDLE delta.
+ */
+ if (current_work() == &group->avgs_work.work) {
+ bool reschedule;
+
+ if (cpu == current_cpu)
+ reschedule = tasks[NR_RUNNING] +
+ tasks[NR_IOWAIT] +
+ tasks[NR_MEMSTALL] > 1;
+ else
+ reschedule = *pchanged_states & (1 << PSI_NONIDLE);
+
+ if (reschedule)
+ *pchanged_states |= PSI_STATE_RESCHEDULE;
+ }
}
static void calc_avgs(unsigned long avg[3], int missed_periods,
@@ -415,7 +442,6 @@ static void psi_avgs_work(struct work_struct *work)
struct delayed_work *dwork;
struct psi_group *group;
u32 changed_states;
- bool nonidle;
u64 now;
dwork = to_delayed_work(work);
@@ -426,7 +452,6 @@ static void psi_avgs_work(struct work_struct *work)
now = sched_clock();
collect_percpu_times(group, PSI_AVGS, &changed_states);
- nonidle = changed_states & (1 << PSI_NONIDLE);
/*
* If there is task activity, periodically fold the per-cpu
* times and feed samples into the running averages. If things
@@ -437,7 +462,7 @@ static void psi_avgs_work(struct work_struct *work)
if (now >= group->avg_next_update)
group->avg_next_update = update_averages(group, now);
- if (nonidle) {
+ if (changed_states & PSI_STATE_RESCHEDULE) {
schedule_delayed_work(dwork, nsecs_to_jiffies(
group->avg_next_update - now) + 1);
}
@@ -539,10 +564,12 @@ static u64 update_triggers(struct psi_group *group, u64 now)
/* Calculate growth since last update */
growth = window_update(&t->win, now, total[t->state]);
- if (growth < t->threshold)
- continue;
+ if (!t->pending_event) {
+ if (growth < t->threshold)
+ continue;
- t->pending_event = true;
+ t->pending_event = true;
+ }
}
/* Limit event signaling to once per window */
if (now < t->last_event_time + t->win.size)
@@ -563,18 +590,17 @@ static u64 update_triggers(struct psi_group *group, u64 now)
return now + group->poll_min_period;
}
-/* Schedule polling if it's not already scheduled. */
-static void psi_schedule_poll_work(struct psi_group *group, unsigned long delay)
+/* Schedule polling if it's not already scheduled or forced. */
+static void psi_schedule_poll_work(struct psi_group *group, unsigned long delay,
+ bool force)
{
struct task_struct *task;
/*
- * Do not reschedule if already scheduled.
- * Possible race with a timer scheduled after this check but before
- * mod_timer below can be tolerated because group->polling_next_update
- * will keep updates on schedule.
+ * atomic_xchg should be called even when !force to provide a
+ * full memory barrier (see the comment inside psi_poll_work).
*/
- if (timer_pending(&group->poll_timer))
+ if (atomic_xchg(&group->poll_scheduled, 1) && !force)
return;
rcu_read_lock();
@@ -586,12 +612,15 @@ static void psi_schedule_poll_work(struct psi_group *group, unsigned long delay)
*/
if (likely(task))
mod_timer(&group->poll_timer, jiffies + delay);
+ else
+ atomic_set(&group->poll_scheduled, 0);
rcu_read_unlock();
}
static void psi_poll_work(struct psi_group *group)
{
+ bool force_reschedule = false;
u32 changed_states;
u64 now;
@@ -599,6 +628,43 @@ static void psi_poll_work(struct psi_group *group)
now = sched_clock();
+ if (now > group->polling_until) {
+ /*
+ * We are either about to start or might stop polling if no
+ * state change was recorded. Resetting poll_scheduled leaves
+ * a small window for psi_group_change to sneak in and schedule
+ * an immediate poll_work before we get to rescheduling. One
+ * potential extra wakeup at the end of the polling window
+ * should be negligible and polling_next_update still keeps
+ * updates correctly on schedule.
+ */
+ atomic_set(&group->poll_scheduled, 0);
+ /*
+ * A task change can race with the poll worker that is supposed to
+ * report on it. To avoid missing events, ensure ordering between
+ * poll_scheduled and the task state accesses, such that if the poll
+ * worker misses the state update, the task change is guaranteed to
+ * reschedule the poll worker:
+ *
+ * poll worker:
+ * atomic_set(poll_scheduled, 0)
+ * smp_mb()
+ * LOAD states
+ *
+ * task change:
+ * STORE states
+ * if atomic_xchg(poll_scheduled, 1) == 0:
+ * schedule poll worker
+ *
+ * The atomic_xchg() implies a full barrier.
+ */
+ smp_mb();
+ } else {
+ /* Polling window is not over, keep rescheduling */
+ force_reschedule = true;
+ }
+
+
collect_percpu_times(group, PSI_POLL, &changed_states);
if (changed_states & group->poll_states) {
@@ -624,7 +690,8 @@ static void psi_poll_work(struct psi_group *group)
group->polling_next_update = update_triggers(group, now);
psi_schedule_poll_work(group,
- nsecs_to_jiffies(group->polling_next_update - now) + 1);
+ nsecs_to_jiffies(group->polling_next_update - now) + 1,
+ force_reschedule);
out:
mutex_unlock(&group->trigger_lock);
@@ -785,7 +852,7 @@ static void psi_group_change(struct psi_group *group, int cpu,
write_seqcount_end(&groupc->seq);
if (state_mask & group->poll_states)
- psi_schedule_poll_work(group, 1);
+ psi_schedule_poll_work(group, 1, false);
if (wake_clock && !delayed_work_pending(&group->avgs_work))
schedule_delayed_work(&group->avgs_work, PSI_FREQ);
@@ -939,7 +1006,7 @@ void psi_account_irqtime(struct task_struct *task, u32 delta)
write_seqcount_end(&groupc->seq);
if (group->poll_states & (1 << PSI_IRQ_FULL))
- psi_schedule_poll_work(group, 1);
+ psi_schedule_poll_work(group, 1, false);
} while ((group = group->parent));
}
#endif
@@ -1325,6 +1392,7 @@ void psi_trigger_destroy(struct psi_trigger *t)
* can no longer be found through group->poll_task.
*/
kthread_stop(task_to_destroy);
+ atomic_set(&group->poll_scheduled, 0);
}
kfree(t);
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index a4a20046e586..771f8ddb7053 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1041,6 +1041,7 @@ struct rq {
unsigned long cpu_capacity;
unsigned long cpu_capacity_orig;
+ unsigned long cpu_capacity_inverted;
struct balance_callback *balance_callback;
@@ -1150,6 +1151,9 @@ struct rq {
unsigned int core_forceidle_occupation;
u64 core_forceidle_start;
#endif
+
+ /* Scratch cpumask to be temporarily used under rq_lock */
+ cpumask_var_t scratch_mask;
};
#ifdef CONFIG_FAIR_GROUP_SCHED
@@ -1877,6 +1881,13 @@ static inline void dirty_sched_domain_sysctl(int cpu)
#endif
extern int sched_update_scaling(void);
+
+static inline const struct cpumask *task_user_cpus(struct task_struct *p)
+{
+ if (!p->user_cpus_ptr)
+ return cpu_possible_mask; /* &init_task.cpus_mask */
+ return p->user_cpus_ptr;
+}
#endif /* CONFIG_SMP */
#include "stats.h"
@@ -2144,6 +2155,12 @@ extern const u32 sched_prio_to_wmult[40];
#define RETRY_TASK ((void *)-1UL)
+struct affinity_context {
+ const struct cpumask *new_mask;
+ struct cpumask *user_mask;
+ unsigned int flags;
+};
+
struct sched_class {
#ifdef CONFIG_UCLAMP_TASK
@@ -2172,9 +2189,7 @@ struct sched_class {
void (*task_woken)(struct rq *this_rq, struct task_struct *task);
- void (*set_cpus_allowed)(struct task_struct *p,
- const struct cpumask *newmask,
- u32 flags);
+ void (*set_cpus_allowed)(struct task_struct *p, struct affinity_context *ctx);
void (*rq_online)(struct rq *rq);
void (*rq_offline)(struct rq *rq);
@@ -2285,7 +2300,7 @@ extern void update_group_capacity(struct sched_domain *sd, int cpu);
extern void trigger_load_balance(struct rq *rq);
-extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask, u32 flags);
+extern void set_cpus_allowed_common(struct task_struct *p, struct affinity_context *ctx);
static inline struct task_struct *get_push_task(struct rq *rq)
{
@@ -2878,6 +2893,24 @@ static inline unsigned long capacity_orig_of(int cpu)
return cpu_rq(cpu)->cpu_capacity_orig;
}
+/*
+ * Returns inverted capacity if the CPU is in capacity inversion state.
+ * 0 otherwise.
+ *
+ * Capacity inversion detection only considers thermal impact where actual
+ * performance points (OPPs) gets dropped.
+ *
+ * Capacity inversion state happens when another performance domain that has
+ * equal or lower capacity_orig_of() becomes effectively larger than the perf
+ * domain this CPU belongs to due to thermal pressure throttling it hard.
+ *
+ * See comment in update_cpu_capacity().
+ */
+static inline unsigned long cpu_in_capacity_inversion(int cpu)
+{
+ return cpu_rq(cpu)->cpu_capacity_inverted;
+}
+
/**
* enum cpu_util_type - CPU utilization type
* @FREQUENCY_UTIL: Utilization used to select frequency
@@ -2979,6 +3012,23 @@ static inline unsigned long cpu_util_rt(struct rq *rq)
#ifdef CONFIG_UCLAMP_TASK
unsigned long uclamp_eff_value(struct task_struct *p, enum uclamp_id clamp_id);
+static inline unsigned long uclamp_rq_get(struct rq *rq,
+ enum uclamp_id clamp_id)
+{
+ return READ_ONCE(rq->uclamp[clamp_id].value);
+}
+
+static inline void uclamp_rq_set(struct rq *rq, enum uclamp_id clamp_id,
+ unsigned int value)
+{
+ WRITE_ONCE(rq->uclamp[clamp_id].value, value);
+}
+
+static inline bool uclamp_rq_is_idle(struct rq *rq)
+{
+ return rq->uclamp_flags & UCLAMP_FLAG_IDLE;
+}
+
/**
* uclamp_rq_util_with - clamp @util with @rq and @p effective uclamp values.
* @rq: The rq to clamp against. Must not be NULL.
@@ -3014,12 +3064,12 @@ unsigned long uclamp_rq_util_with(struct rq *rq, unsigned long util,
* Ignore last runnable task's max clamp, as this task will
* reset it. Similarly, no need to read the rq's min clamp.
*/
- if (rq->uclamp_flags & UCLAMP_FLAG_IDLE)
+ if (uclamp_rq_is_idle(rq))
goto out;
}
- min_util = max_t(unsigned long, min_util, READ_ONCE(rq->uclamp[UCLAMP_MIN].value));
- max_util = max_t(unsigned long, max_util, READ_ONCE(rq->uclamp[UCLAMP_MAX].value));
+ min_util = max_t(unsigned long, min_util, uclamp_rq_get(rq, UCLAMP_MIN));
+ max_util = max_t(unsigned long, max_util, uclamp_rq_get(rq, UCLAMP_MAX));
out:
/*
* Since CPU's {min,max}_util clamps are MAX aggregated considering
@@ -3060,6 +3110,15 @@ static inline bool uclamp_is_used(void)
return static_branch_likely(&sched_uclamp_used);
}
#else /* CONFIG_UCLAMP_TASK */
+static inline unsigned long uclamp_eff_value(struct task_struct *p,
+ enum uclamp_id clamp_id)
+{
+ if (clamp_id == UCLAMP_MIN)
+ return 0;
+
+ return SCHED_CAPACITY_SCALE;
+}
+
static inline
unsigned long uclamp_rq_util_with(struct rq *rq, unsigned long util,
struct task_struct *p)
@@ -3073,6 +3132,25 @@ static inline bool uclamp_is_used(void)
{
return false;
}
+
+static inline unsigned long uclamp_rq_get(struct rq *rq,
+ enum uclamp_id clamp_id)
+{
+ if (clamp_id == UCLAMP_MIN)
+ return 0;
+
+ return SCHED_CAPACITY_SCALE;
+}
+
+static inline void uclamp_rq_set(struct rq *rq, enum uclamp_id clamp_id,
+ unsigned int value)
+{
+}
+
+static inline bool uclamp_rq_is_idle(struct rq *rq)
+{
+ return false;
+}
#endif /* CONFIG_UCLAMP_TASK */
#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h
index 84a188913cc9..38f3698f5e5b 100644
--- a/kernel/sched/stats.h
+++ b/kernel/sched/stats.h
@@ -128,11 +128,9 @@ static inline void psi_enqueue(struct task_struct *p, bool wakeup)
if (p->in_memstall)
set |= TSK_MEMSTALL_RUNNING;
- if (!wakeup || p->sched_psi_wake_requeue) {
+ if (!wakeup) {
if (p->in_memstall)
set |= TSK_MEMSTALL;
- if (p->sched_psi_wake_requeue)
- p->sched_psi_wake_requeue = 0;
} else {
if (p->in_iowait)
clear |= TSK_IOWAIT;
@@ -143,8 +141,6 @@ static inline void psi_enqueue(struct task_struct *p, bool wakeup)
static inline void psi_dequeue(struct task_struct *p, bool sleep)
{
- int clear = TSK_RUNNING;
-
if (static_branch_likely(&psi_disabled))
return;
@@ -157,10 +153,7 @@ static inline void psi_dequeue(struct task_struct *p, bool sleep)
if (sleep)
return;
- if (p->in_memstall)
- clear |= (TSK_MEMSTALL | TSK_MEMSTALL_RUNNING);
-
- psi_task_change(p, clear, 0);
+ psi_task_change(p, p->psi_flags, 0);
}
static inline void psi_ttwu_dequeue(struct task_struct *p)
@@ -172,19 +165,12 @@ static inline void psi_ttwu_dequeue(struct task_struct *p)
* deregister its sleep-persistent psi states from the old
* queue, and let psi_enqueue() know it has to requeue.
*/
- if (unlikely(p->in_iowait || p->in_memstall)) {
+ if (unlikely(p->psi_flags)) {
struct rq_flags rf;
struct rq *rq;
- int clear = 0;
-
- if (p->in_iowait)
- clear |= TSK_IOWAIT;
- if (p->in_memstall)
- clear |= TSK_MEMSTALL;
rq = __task_rq_lock(p, &rf);
- psi_task_change(p, clear, 0);
- p->sched_psi_wake_requeue = 1;
+ psi_task_change(p, p->psi_flags, 0);
__task_rq_unlock(rq, &rf);
}
}
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 9860bb9a847c..133b74730738 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -121,11 +121,12 @@ static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
return nr_exclusive;
}
-static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode,
+static int __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
unsigned long flags;
wait_queue_entry_t bookmark;
+ int remaining = nr_exclusive;
bookmark.flags = 0;
bookmark.private = NULL;
@@ -134,10 +135,12 @@ static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int
do {
spin_lock_irqsave(&wq_head->lock, flags);
- nr_exclusive = __wake_up_common(wq_head, mode, nr_exclusive,
+ remaining = __wake_up_common(wq_head, mode, remaining,
wake_flags, key, &bookmark);
spin_unlock_irqrestore(&wq_head->lock, flags);
} while (bookmark.flags & WQ_FLAG_BOOKMARK);
+
+ return nr_exclusive - remaining;
}
/**
@@ -147,13 +150,14 @@ static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int
* @nr_exclusive: how many wake-one or wake-many threads to wake up
* @key: is directly passed to the wakeup function
*
- * If this function wakes up a task, it executes a full memory barrier before
- * accessing the task state.
+ * If this function wakes up a task, it executes a full memory barrier
+ * before accessing the task state. Returns the number of exclusive
+ * tasks that were awaken.
*/
-void __wake_up(struct wait_queue_head *wq_head, unsigned int mode,
- int nr_exclusive, void *key)
+int __wake_up(struct wait_queue_head *wq_head, unsigned int mode,
+ int nr_exclusive, void *key)
{
- __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);
+ return __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);
}
EXPORT_SYMBOL(__wake_up);
diff --git a/kernel/scs.c b/kernel/scs.c
index b7e1b096d906..d7809affe740 100644
--- a/kernel/scs.c
+++ b/kernel/scs.c
@@ -12,6 +12,10 @@
#include <linux/vmalloc.h>
#include <linux/vmstat.h>
+#ifdef CONFIG_DYNAMIC_SCS
+DEFINE_STATIC_KEY_FALSE(dynamic_scs_enabled);
+#endif
+
static void __scs_account(void *s, int account)
{
struct page *scs_page = vmalloc_to_page(s);
@@ -101,14 +105,20 @@ static int scs_cleanup(unsigned int cpu)
void __init scs_init(void)
{
+ if (!scs_is_enabled())
+ return;
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
scs_cleanup);
}
int scs_prepare(struct task_struct *tsk, int node)
{
- void *s = scs_alloc(node);
+ void *s;
+ if (!scs_is_enabled())
+ return 0;
+
+ s = scs_alloc(node);
if (!s)
return -ENOMEM;
@@ -148,7 +158,7 @@ void scs_release(struct task_struct *tsk)
{
void *s = task_scs(tsk);
- if (!s)
+ if (!scs_is_enabled() || !s)
return;
WARN(task_scs_end_corrupted(tsk),
diff --git a/kernel/signal.c b/kernel/signal.c
index d140672185a4..848d5c282d35 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1255,7 +1255,7 @@ int send_signal_locked(int sig, struct kernel_siginfo *info,
static void print_fatal_signal(int signr)
{
- struct pt_regs *regs = signal_pt_regs();
+ struct pt_regs *regs = task_pt_regs(current);
pr_info("potentially unexpected fatal signal %d.\n", signr);
#if defined(__i386__) && !defined(__arch_um__)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 188c305aeb8b..c6d9dec11b74 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -267,13 +267,14 @@ int proc_dostring(struct ctl_table *table, int write,
ppos);
}
-static size_t proc_skip_spaces(char **buf)
+static void proc_skip_spaces(char **buf, size_t *size)
{
- size_t ret;
- char *tmp = skip_spaces(*buf);
- ret = tmp - *buf;
- *buf = tmp;
- return ret;
+ while (*size) {
+ if (!isspace(**buf))
+ break;
+ (*size)--;
+ (*buf)++;
+ }
}
static void proc_skip_char(char **buf, size_t *size, const char v)
@@ -342,13 +343,12 @@ static int proc_get_long(char **buf, size_t *size,
unsigned long *val, bool *neg,
const char *perm_tr, unsigned perm_tr_len, char *tr)
{
- int len;
char *p, tmp[TMPBUFLEN];
+ ssize_t len = *size;
- if (!*size)
+ if (len <= 0)
return -EINVAL;
- len = *size;
if (len > TMPBUFLEN - 1)
len = TMPBUFLEN - 1;
@@ -521,7 +521,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
bool neg;
if (write) {
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left)
break;
@@ -548,7 +548,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
if (!write && !first && left && !err)
proc_put_char(&buffer, &left, '\n');
if (write && !err && left)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (write && first)
return err ? : -EINVAL;
*lenp -= left;
@@ -590,7 +590,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data,
if (left > PAGE_SIZE - 1)
left = PAGE_SIZE - 1;
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left) {
err = -EINVAL;
goto out_free;
@@ -610,7 +610,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data,
}
if (!err && left)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
out_free:
if (err)
@@ -1075,7 +1075,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
if (write) {
bool neg;
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left)
break;
@@ -1104,7 +1104,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
if (!write && !first && left && !err)
proc_put_char(&buffer, &left, '\n');
if (write && !err)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (write && first)
return err ? : -EINVAL;
*lenp -= left;
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 5d85014d59b5..960143b183cd 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -76,7 +76,7 @@ static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
}
/**
- * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
+ * clockevent_delta2ns - Convert a latch value (device ticks) to nanoseconds
* @latch: value to convert
* @evt: pointer to clock event device descriptor
*
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 8058bec87ace..9cf32ccda715 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -310,7 +310,7 @@ static void clocksource_verify_choose_cpus(void)
* CPUs that are currently online.
*/
for (i = 1; i < n; i++) {
- cpu = prandom_u32_max(nr_cpu_ids);
+ cpu = get_random_u32_below(nr_cpu_ids);
cpu = cpumask_next(cpu - 1, cpu_online_mask);
if (cpu >= nr_cpu_ids)
cpu = cpumask_first(cpu_online_mask);
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index aec832801c26..0775b9ec952a 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -192,6 +192,24 @@ static void timens_setup_vdso_data(struct vdso_data *vdata,
offset[CLOCK_BOOTTIME_ALARM] = boottime;
}
+struct page *find_timens_vvar_page(struct vm_area_struct *vma)
+{
+ if (likely(vma->vm_mm == current->mm))
+ return current->nsproxy->time_ns->vvar_page;
+
+ /*
+ * VM_PFNMAP | VM_IO protect .fault() handler from being called
+ * through interfaces like /proc/$pid/mem or
+ * process_vm_{readv,writev}() as long as there's no .access()
+ * in special_mapping_vmops().
+ * For more details check_vma_flags() and __access_remote_vm()
+ */
+
+ WARN(1, "vvar_page accessed remotely");
+
+ return NULL;
+}
+
/*
* Protects possibly multiple offsets writers racing each other
* and tasks entering the namespace.
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 717fcb9fb14a..63a8ce7177dd 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1017,7 +1017,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
unsigned int idx = UINT_MAX;
int ret = 0;
- BUG_ON(!timer->function);
+ debug_assert_init(timer);
/*
* This is a common optimization triggered by the networking code - if
@@ -1044,6 +1044,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* dequeue/enqueue dance.
*/
base = lock_timer_base(timer, &flags);
+ /*
+ * Has @timer been shutdown? This needs to be evaluated
+ * while holding base lock to prevent a race against the
+ * shutdown code.
+ */
+ if (!timer->function)
+ goto out_unlock;
+
forward_timer_base(base);
if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
@@ -1070,6 +1078,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
}
} else {
base = lock_timer_base(timer, &flags);
+ /*
+ * Has @timer been shutdown? This needs to be evaluated
+ * while holding base lock to prevent a race against the
+ * shutdown code.
+ */
+ if (!timer->function)
+ goto out_unlock;
+
forward_timer_base(base);
}
@@ -1083,7 +1099,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
/*
* We are trying to schedule the timer on the new base.
* However we can't change timer's base while it is running,
- * otherwise del_timer_sync() can't detect that the timer's
+ * otherwise timer_delete_sync() can't detect that the timer's
* handler yet has not finished. This also guarantees that the
* timer is serialized wrt itself.
*/
@@ -1121,14 +1137,20 @@ out_unlock:
}
/**
- * mod_timer_pending - modify a pending timer's timeout
- * @timer: the pending timer to be modified
- * @expires: new timeout in jiffies
+ * mod_timer_pending - Modify a pending timer's timeout
+ * @timer: The pending timer to be modified
+ * @expires: New absolute timeout in jiffies
+ *
+ * mod_timer_pending() is the same for pending timers as mod_timer(), but
+ * will not activate inactive timers.
*
- * mod_timer_pending() is the same for pending timers as mod_timer(),
- * but will not re-activate and modify already deleted timers.
+ * If @timer->function == NULL then the start operation is silently
+ * discarded.
*
- * It is useful for unserialized use of timers.
+ * Return:
+ * * %0 - The timer was inactive and not modified or was in
+ * shutdown state and the operation was discarded
+ * * %1 - The timer was active and requeued to expire at @expires
*/
int mod_timer_pending(struct timer_list *timer, unsigned long expires)
{
@@ -1137,24 +1159,31 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(mod_timer_pending);
/**
- * mod_timer - modify a timer's timeout
- * @timer: the timer to be modified
- * @expires: new timeout in jiffies
- *
- * mod_timer() is a more efficient way to update the expire field of an
- * active timer (if the timer is inactive it will be activated)
+ * mod_timer - Modify a timer's timeout
+ * @timer: The timer to be modified
+ * @expires: New absolute timeout in jiffies
*
* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
*
+ * mod_timer() is more efficient than the above open coded sequence. In
+ * case that the timer is inactive, the del_timer() part is a NOP. The
+ * timer is in any case activated with the new expiry time @expires.
+ *
* Note that if there are multiple unserialized concurrent users of the
* same timer, then mod_timer() is the only safe way to modify the timeout,
* since add_timer() cannot modify an already running timer.
*
- * The function returns whether it has modified a pending timer or not.
- * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
- * active timer returns 1.)
+ * If @timer->function == NULL then the start operation is silently
+ * discarded. In this case the return value is 0 and meaningless.
+ *
+ * Return:
+ * * %0 - The timer was inactive and started or was in shutdown
+ * state and the operation was discarded
+ * * %1 - The timer was active and requeued to expire at @expires or
+ * the timer was active and not modified because @expires did
+ * not change the effective expiry time
*/
int mod_timer(struct timer_list *timer, unsigned long expires)
{
@@ -1165,11 +1194,22 @@ EXPORT_SYMBOL(mod_timer);
/**
* timer_reduce - Modify a timer's timeout if it would reduce the timeout
* @timer: The timer to be modified
- * @expires: New timeout in jiffies
+ * @expires: New absolute timeout in jiffies
*
* timer_reduce() is very similar to mod_timer(), except that it will only
- * modify a running timer if that would reduce the expiration time (it will
- * start a timer that isn't running).
+ * modify an enqueued timer if that would reduce the expiration time. If
+ * @timer is not enqueued it starts the timer.
+ *
+ * If @timer->function == NULL then the start operation is silently
+ * discarded.
+ *
+ * Return:
+ * * %0 - The timer was inactive and started or was in shutdown
+ * state and the operation was discarded
+ * * %1 - The timer was active and requeued to expire at @expires or
+ * the timer was active and not modified because @expires
+ * did not change the effective expiry time such that the
+ * timer would expire earlier than already scheduled
*/
int timer_reduce(struct timer_list *timer, unsigned long expires)
{
@@ -1178,39 +1218,51 @@ int timer_reduce(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(timer_reduce);
/**
- * add_timer - start a timer
- * @timer: the timer to be added
+ * add_timer - Start a timer
+ * @timer: The timer to be started
*
- * The kernel will do a ->function(@timer) callback from the
- * timer interrupt at the ->expires point in the future. The
- * current time is 'jiffies'.
+ * Start @timer to expire at @timer->expires in the future. @timer->expires
+ * is the absolute expiry time measured in 'jiffies'. When the timer expires
+ * timer->function(timer) will be invoked from soft interrupt context.
*
- * The timer's ->expires, ->function fields must be set prior calling this
- * function.
+ * The @timer->expires and @timer->function fields must be set prior
+ * to calling this function.
*
- * Timers with an ->expires field in the past will be executed in the next
- * timer tick.
+ * If @timer->function == NULL then the start operation is silently
+ * discarded.
+ *
+ * If @timer->expires is already in the past @timer will be queued to
+ * expire at the next timer tick.
+ *
+ * This can only operate on an inactive timer. Attempts to invoke this on
+ * an active timer are rejected with a warning.
*/
void add_timer(struct timer_list *timer)
{
- BUG_ON(timer_pending(timer));
+ if (WARN_ON_ONCE(timer_pending(timer)))
+ return;
__mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
}
EXPORT_SYMBOL(add_timer);
/**
- * add_timer_on - start a timer on a particular CPU
- * @timer: the timer to be added
- * @cpu: the CPU to start it on
+ * add_timer_on - Start a timer on a particular CPU
+ * @timer: The timer to be started
+ * @cpu: The CPU to start it on
+ *
+ * Same as add_timer() except that it starts the timer on the given CPU.
*
- * This is not very scalable on SMP. Double adds are not possible.
+ * See add_timer() for further details.
*/
void add_timer_on(struct timer_list *timer, int cpu)
{
struct timer_base *new_base, *base;
unsigned long flags;
- BUG_ON(timer_pending(timer) || !timer->function);
+ debug_assert_init(timer);
+
+ if (WARN_ON_ONCE(timer_pending(timer)))
+ return;
new_base = get_timer_cpu_base(timer->flags, cpu);
@@ -1220,6 +1272,13 @@ void add_timer_on(struct timer_list *timer, int cpu)
* wrong base locked. See lock_timer_base().
*/
base = lock_timer_base(timer, &flags);
+ /*
+ * Has @timer been shutdown? This needs to be evaluated while
+ * holding base lock to prevent a race against the shutdown code.
+ */
+ if (!timer->function)
+ goto out_unlock;
+
if (base != new_base) {
timer->flags |= TIMER_MIGRATING;
@@ -1233,22 +1292,27 @@ void add_timer_on(struct timer_list *timer, int cpu)
debug_timer_activate(timer);
internal_add_timer(base, timer);
+out_unlock:
raw_spin_unlock_irqrestore(&base->lock, flags);
}
EXPORT_SYMBOL_GPL(add_timer_on);
/**
- * del_timer - deactivate a timer.
- * @timer: the timer to be deactivated
- *
- * del_timer() deactivates a timer - this works on both active and inactive
- * timers.
- *
- * The function returns whether it has deactivated a pending timer or not.
- * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
- * active timer returns 1.)
+ * __timer_delete - Internal function: Deactivate a timer
+ * @timer: The timer to be deactivated
+ * @shutdown: If true, this indicates that the timer is about to be
+ * shutdown permanently.
+ *
+ * If @shutdown is true then @timer->function is set to NULL under the
+ * timer base lock which prevents further rearming of the time. In that
+ * case any attempt to rearm @timer after this function returns will be
+ * silently ignored.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
*/
-int del_timer(struct timer_list *timer)
+static int __timer_delete(struct timer_list *timer, bool shutdown)
{
struct timer_base *base;
unsigned long flags;
@@ -1256,24 +1320,90 @@ int del_timer(struct timer_list *timer)
debug_assert_init(timer);
- if (timer_pending(timer)) {
+ /*
+ * If @shutdown is set then the lock has to be taken whether the
+ * timer is pending or not to protect against a concurrent rearm
+ * which might hit between the lockless pending check and the lock
+ * aquisition. By taking the lock it is ensured that such a newly
+ * enqueued timer is dequeued and cannot end up with
+ * timer->function == NULL in the expiry code.
+ *
+ * If timer->function is currently executed, then this makes sure
+ * that the callback cannot requeue the timer.
+ */
+ if (timer_pending(timer) || shutdown) {
base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true);
+ if (shutdown)
+ timer->function = NULL;
raw_spin_unlock_irqrestore(&base->lock, flags);
}
return ret;
}
-EXPORT_SYMBOL(del_timer);
/**
- * try_to_del_timer_sync - Try to deactivate a timer
- * @timer: timer to delete
+ * timer_delete - Deactivate a timer
+ * @timer: The timer to be deactivated
+ *
+ * The function only deactivates a pending timer, but contrary to
+ * timer_delete_sync() it does not take into account whether the timer's
+ * callback function is concurrently executed on a different CPU or not.
+ * It neither prevents rearming of the timer. If @timer can be rearmed
+ * concurrently then the return value of this function is meaningless.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
+ */
+int timer_delete(struct timer_list *timer)
+{
+ return __timer_delete(timer, false);
+}
+EXPORT_SYMBOL(timer_delete);
+
+/**
+ * timer_shutdown - Deactivate a timer and prevent rearming
+ * @timer: The timer to be deactivated
*
- * This function tries to deactivate a timer. Upon successful (ret >= 0)
- * exit the timer is not queued and the handler is not running on any CPU.
+ * The function does not wait for an eventually running timer callback on a
+ * different CPU but it prevents rearming of the timer. Any attempt to arm
+ * @timer after this function returns will be silently ignored.
+ *
+ * This function is useful for teardown code and should only be used when
+ * timer_shutdown_sync() cannot be invoked due to locking or context constraints.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending
*/
-int try_to_del_timer_sync(struct timer_list *timer)
+int timer_shutdown(struct timer_list *timer)
+{
+ return __timer_delete(timer, true);
+}
+EXPORT_SYMBOL_GPL(timer_shutdown);
+
+/**
+ * __try_to_del_timer_sync - Internal function: Try to deactivate a timer
+ * @timer: Timer to deactivate
+ * @shutdown: If true, this indicates that the timer is about to be
+ * shutdown permanently.
+ *
+ * If @shutdown is true then @timer->function is set to NULL under the
+ * timer base lock which prevents further rearming of the timer. Any
+ * attempt to rearm @timer after this function returns will be silently
+ * ignored.
+ *
+ * This function cannot guarantee that the timer cannot be rearmed
+ * right after dropping the base lock if @shutdown is false. That
+ * needs to be prevented by the calling code if necessary.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
+ * * %-1 - The timer callback function is running on a different CPU
+ */
+static int __try_to_del_timer_sync(struct timer_list *timer, bool shutdown)
{
struct timer_base *base;
unsigned long flags;
@@ -1285,11 +1415,34 @@ int try_to_del_timer_sync(struct timer_list *timer)
if (base->running_timer != timer)
ret = detach_if_pending(timer, base, true);
+ if (shutdown)
+ timer->function = NULL;
raw_spin_unlock_irqrestore(&base->lock, flags);
return ret;
}
+
+/**
+ * try_to_del_timer_sync - Try to deactivate a timer
+ * @timer: Timer to deactivate
+ *
+ * This function tries to deactivate a timer. On success the timer is not
+ * queued and the timer callback function is not running on any CPU.
+ *
+ * This function does not guarantee that the timer cannot be rearmed right
+ * after dropping the base lock. That needs to be prevented by the calling
+ * code if necessary.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
+ * * %-1 - The timer callback function is running on a different CPU
+ */
+int try_to_del_timer_sync(struct timer_list *timer)
+{
+ return __try_to_del_timer_sync(timer, false);
+}
EXPORT_SYMBOL(try_to_del_timer_sync);
#ifdef CONFIG_PREEMPT_RT
@@ -1365,44 +1518,29 @@ static inline void timer_sync_wait_running(struct timer_base *base) { }
static inline void del_timer_wait_running(struct timer_list *timer) { }
#endif
-#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
/**
- * del_timer_sync - deactivate a timer and wait for the handler to finish.
- * @timer: the timer to be deactivated
- *
- * This function only differs from del_timer() on SMP: besides deactivating
- * the timer it also makes sure the handler has finished executing on other
- * CPUs.
- *
- * Synchronization rules: Callers must prevent restarting of the timer,
- * otherwise this function is meaningless. It must not be called from
- * interrupt contexts unless the timer is an irqsafe one. The caller must
- * not hold locks which would prevent completion of the timer's
- * handler. The timer's handler must not call add_timer_on(). Upon exit the
- * timer is not queued and the handler is not running on any CPU.
- *
- * Note: For !irqsafe timers, you must not hold locks that are held in
- * interrupt context while calling this function. Even if the lock has
- * nothing to do with the timer in question. Here's why::
- *
- * CPU0 CPU1
- * ---- ----
- * <SOFTIRQ>
- * call_timer_fn();
- * base->running_timer = mytimer;
- * spin_lock_irq(somelock);
- * <IRQ>
- * spin_lock(somelock);
- * del_timer_sync(mytimer);
- * while (base->running_timer == mytimer);
- *
- * Now del_timer_sync() will never return and never release somelock.
- * The interrupt on the other CPU is waiting to grab somelock but
- * it has interrupted the softirq that CPU0 is waiting to finish.
- *
- * The function returns whether it has deactivated a pending timer or not.
+ * __timer_delete_sync - Internal function: Deactivate a timer and wait
+ * for the handler to finish.
+ * @timer: The timer to be deactivated
+ * @shutdown: If true, @timer->function will be set to NULL under the
+ * timer base lock which prevents rearming of @timer
+ *
+ * If @shutdown is not set the timer can be rearmed later. If the timer can
+ * be rearmed concurrently, i.e. after dropping the base lock then the
+ * return value is meaningless.
+ *
+ * If @shutdown is set then @timer->function is set to NULL under timer
+ * base lock which prevents rearming of the timer. Any attempt to rearm
+ * a shutdown timer is silently ignored.
+ *
+ * If the timer should be reused after shutdown it has to be initialized
+ * again.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
*/
-int del_timer_sync(struct timer_list *timer)
+static int __timer_delete_sync(struct timer_list *timer, bool shutdown)
{
int ret;
@@ -1422,7 +1560,7 @@ int del_timer_sync(struct timer_list *timer)
* don't use it in hardirq context, because it
* could lead to deadlock.
*/
- WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE));
+ WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE));
/*
* Must be able to sleep on PREEMPT_RT because of the slowpath in
@@ -1432,7 +1570,7 @@ int del_timer_sync(struct timer_list *timer)
lockdep_assert_preemption_enabled();
do {
- ret = try_to_del_timer_sync(timer);
+ ret = __try_to_del_timer_sync(timer, shutdown);
if (unlikely(ret < 0)) {
del_timer_wait_running(timer);
@@ -1442,8 +1580,96 @@ int del_timer_sync(struct timer_list *timer)
return ret;
}
-EXPORT_SYMBOL(del_timer_sync);
-#endif
+
+/**
+ * timer_delete_sync - Deactivate a timer and wait for the handler to finish.
+ * @timer: The timer to be deactivated
+ *
+ * Synchronization rules: Callers must prevent restarting of the timer,
+ * otherwise this function is meaningless. It must not be called from
+ * interrupt contexts unless the timer is an irqsafe one. The caller must
+ * not hold locks which would prevent completion of the timer's callback
+ * function. The timer's handler must not call add_timer_on(). Upon exit
+ * the timer is not queued and the handler is not running on any CPU.
+ *
+ * For !irqsafe timers, the caller must not hold locks that are held in
+ * interrupt context. Even if the lock has nothing to do with the timer in
+ * question. Here's why::
+ *
+ * CPU0 CPU1
+ * ---- ----
+ * <SOFTIRQ>
+ * call_timer_fn();
+ * base->running_timer = mytimer;
+ * spin_lock_irq(somelock);
+ * <IRQ>
+ * spin_lock(somelock);
+ * timer_delete_sync(mytimer);
+ * while (base->running_timer == mytimer);
+ *
+ * Now timer_delete_sync() will never return and never release somelock.
+ * The interrupt on the other CPU is waiting to grab somelock but it has
+ * interrupted the softirq that CPU0 is waiting to finish.
+ *
+ * This function cannot guarantee that the timer is not rearmed again by
+ * some concurrent or preempting code, right after it dropped the base
+ * lock. If there is the possibility of a concurrent rearm then the return
+ * value of the function is meaningless.
+ *
+ * If such a guarantee is needed, e.g. for teardown situations then use
+ * timer_shutdown_sync() instead.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending and deactivated
+ */
+int timer_delete_sync(struct timer_list *timer)
+{
+ return __timer_delete_sync(timer, false);
+}
+EXPORT_SYMBOL(timer_delete_sync);
+
+/**
+ * timer_shutdown_sync - Shutdown a timer and prevent rearming
+ * @timer: The timer to be shutdown
+ *
+ * When the function returns it is guaranteed that:
+ * - @timer is not queued
+ * - The callback function of @timer is not running
+ * - @timer cannot be enqueued again. Any attempt to rearm
+ * @timer is silently ignored.
+ *
+ * See timer_delete_sync() for synchronization rules.
+ *
+ * This function is useful for final teardown of an infrastructure where
+ * the timer is subject to a circular dependency problem.
+ *
+ * A common pattern for this is a timer and a workqueue where the timer can
+ * schedule work and work can arm the timer. On shutdown the workqueue must
+ * be destroyed and the timer must be prevented from rearming. Unless the
+ * code has conditionals like 'if (mything->in_shutdown)' to prevent that
+ * there is no way to get this correct with timer_delete_sync().
+ *
+ * timer_shutdown_sync() is solving the problem. The correct ordering of
+ * calls in this case is:
+ *
+ * timer_shutdown_sync(&mything->timer);
+ * workqueue_destroy(&mything->workqueue);
+ *
+ * After this 'mything' can be safely freed.
+ *
+ * This obviously implies that the timer is not required to be functional
+ * for the rest of the shutdown operation.
+ *
+ * Return:
+ * * %0 - The timer was not pending
+ * * %1 - The timer was pending
+ */
+int timer_shutdown_sync(struct timer_list *timer)
+{
+ return __timer_delete_sync(timer, true);
+}
+EXPORT_SYMBOL_GPL(timer_shutdown_sync);
static void call_timer_fn(struct timer_list *timer,
void (*fn)(struct timer_list *),
@@ -1465,8 +1691,8 @@ static void call_timer_fn(struct timer_list *timer,
#endif
/*
* Couple the lock chain with the lock chain at
- * del_timer_sync() by acquiring the lock_map around the fn()
- * call here and in del_timer_sync().
+ * timer_delete_sync() by acquiring the lock_map around the fn()
+ * call here and in timer_delete_sync().
*/
lock_map_acquire(&lockdep_map);
@@ -1509,6 +1735,12 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
fn = timer->function;
+ if (WARN_ON_ONCE(!fn)) {
+ /* Should never happen. Emphasis on should! */
+ base->running_timer = NULL;
+ continue;
+ }
+
if (timer->flags & TIMER_IRQSAFE) {
raw_spin_unlock(&base->lock);
call_timer_fn(timer, fn, baseclk);
@@ -1933,7 +2165,7 @@ signed long __sched schedule_timeout(signed long timeout)
timer_setup_on_stack(&timer.timer, process_timeout, 0);
__mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING);
schedule();
- del_singleshot_timer_sync(&timer.timer);
+ del_timer_sync(&timer.timer);
/* Remove the timer from the object tracker */
destroy_timer_on_stack(&timer.timer);
@@ -2017,8 +2249,6 @@ int timers_dead_cpu(unsigned int cpu)
struct timer_base *new_base;
int b, i;
- BUG_ON(cpu_online(cpu));
-
for (b = 0; b < NR_BASES; b++) {
old_base = per_cpu_ptr(&timer_bases[b], cpu);
new_base = get_cpu_ptr(&timer_bases[b]);
@@ -2035,7 +2265,8 @@ int timers_dead_cpu(unsigned int cpu)
*/
forward_timer_base(new_base);
- BUG_ON(old_base->running_timer);
+ WARN_ON_ONCE(old_base->running_timer);
+ old_base->running_timer = NULL;
for (i = 0; i < WHEEL_SIZE; i++)
migrate_timer_list(new_base, old_base->vectors + i);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index e9e95c790b8e..2c6611c13f99 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -46,10 +46,10 @@ config HAVE_DYNAMIC_FTRACE_WITH_ARGS
bool
help
If this is set, then arguments and stack can be found from
- the pt_regs passed into the function callback regs parameter
+ the ftrace_regs passed into the function callback regs parameter
by default, even without setting the REGS flag in the ftrace_ops.
- This allows for use of regs_get_kernel_argument() and
- kernel_stack_pointer().
+ This allows for use of ftrace_regs_get_argument() and
+ ftrace_regs_get_stack_pointer().
config HAVE_DYNAMIC_FTRACE_NO_PATCHABLE
bool
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index a995ea1ef849..918a7d12df8f 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -721,7 +721,7 @@ EXPORT_SYMBOL_GPL(blk_trace_startstop);
*/
/**
- * blk_trace_ioctl: - handle the ioctls associated with tracing
+ * blk_trace_ioctl - handle the ioctls associated with tracing
* @bdev: the block device
* @cmd: the ioctl cmd
* @arg: the argument data, if any
@@ -769,7 +769,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
}
/**
- * blk_trace_shutdown: - stop and cleanup trace structures
+ * blk_trace_shutdown - stop and cleanup trace structures
* @q: the request queue associated with the device
*
**/
@@ -1548,7 +1548,8 @@ blk_trace_event_print_binary(struct trace_iterator *iter, int flags,
static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter)
{
- if (!(blk_tracer_flags.val & TRACE_BLK_OPT_CLASSIC))
+ if ((iter->ent->type != TRACE_BLK) ||
+ !(blk_tracer_flags.val & TRACE_BLK_OPT_CLASSIC))
return TRACE_TYPE_UNHANDLED;
return print_one_line(iter, true);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7dc023641bf1..acfa4e029bcc 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1289,6 +1289,7 @@ static int ftrace_add_mod(struct trace_array *tr,
if (!ftrace_mod)
return -ENOMEM;
+ INIT_LIST_HEAD(&ftrace_mod->list);
ftrace_mod->func = kstrdup(func, GFP_KERNEL);
ftrace_mod->module = kstrdup(module, GFP_KERNEL);
ftrace_mod->enable = enable;
@@ -2487,14 +2488,13 @@ ftrace_add_rec_direct(unsigned long ip, unsigned long addr,
static void call_direct_funcs(unsigned long ip, unsigned long pip,
struct ftrace_ops *ops, struct ftrace_regs *fregs)
{
- struct pt_regs *regs = ftrace_get_regs(fregs);
unsigned long addr;
addr = ftrace_find_rec_direct(ip);
if (!addr)
return;
- arch_ftrace_set_direct_caller(regs, addr);
+ arch_ftrace_set_direct_caller(fregs, addr);
}
struct ftrace_ops direct_ops = {
@@ -3190,7 +3190,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
/* if we can't allocate this size, try something smaller */
if (!order)
return -ENOMEM;
- order >>= 1;
+ order--;
goto again;
}
@@ -7391,7 +7391,7 @@ void __init ftrace_init(void)
}
pr_info("ftrace: allocating %ld entries in %ld pages\n",
- count, count / ENTRIES_PER_PAGE + 1);
+ count, DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
ret = ftrace_process_locs(NULL,
__start_mcount_loc,
diff --git a/kernel/trace/kprobe_event_gen_test.c b/kernel/trace/kprobe_event_gen_test.c
index d81f7c51025c..c736487fc0e4 100644
--- a/kernel/trace/kprobe_event_gen_test.c
+++ b/kernel/trace/kprobe_event_gen_test.c
@@ -73,6 +73,10 @@ static struct trace_event_file *gen_kretprobe_test;
#define KPROBE_GEN_TEST_ARG3 NULL
#endif
+static bool trace_event_file_is_valid(struct trace_event_file *input)
+{
+ return input && !IS_ERR(input);
+}
/*
* Test to make sure we can create a kprobe event, then add more
@@ -139,6 +143,8 @@ static int __init test_gen_kprobe_cmd(void)
kfree(buf);
return ret;
delete:
+ if (trace_event_file_is_valid(gen_kprobe_test))
+ gen_kprobe_test = NULL;
/* We got an error after creating the event, delete it */
ret = kprobe_event_delete("gen_kprobe_test");
goto out;
@@ -202,6 +208,8 @@ static int __init test_gen_kretprobe_cmd(void)
kfree(buf);
return ret;
delete:
+ if (trace_event_file_is_valid(gen_kretprobe_test))
+ gen_kretprobe_test = NULL;
/* We got an error after creating the event, delete it */
ret = kprobe_event_delete("gen_kretprobe_test");
goto out;
@@ -217,10 +225,12 @@ static int __init kprobe_event_gen_test_init(void)
ret = test_gen_kretprobe_cmd();
if (ret) {
- WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
- "kprobes",
- "gen_kretprobe_test", false));
- trace_put_event_file(gen_kretprobe_test);
+ if (trace_event_file_is_valid(gen_kretprobe_test)) {
+ WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
+ "kprobes",
+ "gen_kretprobe_test", false));
+ trace_put_event_file(gen_kretprobe_test);
+ }
WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
}
@@ -229,24 +239,30 @@ static int __init kprobe_event_gen_test_init(void)
static void __exit kprobe_event_gen_test_exit(void)
{
- /* Disable the event or you can't remove it */
- WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr,
- "kprobes",
- "gen_kprobe_test", false));
+ if (trace_event_file_is_valid(gen_kprobe_test)) {
+ /* Disable the event or you can't remove it */
+ WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr,
+ "kprobes",
+ "gen_kprobe_test", false));
+
+ /* Now give the file and instance back */
+ trace_put_event_file(gen_kprobe_test);
+ }
- /* Now give the file and instance back */
- trace_put_event_file(gen_kprobe_test);
/* Now unregister and free the event */
WARN_ON(kprobe_event_delete("gen_kprobe_test"));
- /* Disable the event or you can't remove it */
- WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
- "kprobes",
- "gen_kretprobe_test", false));
+ if (trace_event_file_is_valid(gen_kretprobe_test)) {
+ /* Disable the event or you can't remove it */
+ WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
+ "kprobes",
+ "gen_kretprobe_test", false));
+
+ /* Now give the file and instance back */
+ trace_put_event_file(gen_kretprobe_test);
+ }
- /* Now give the file and instance back */
- trace_put_event_file(gen_kretprobe_test);
/* Now unregister and free the event */
WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
diff --git a/kernel/trace/rethook.c b/kernel/trace/rethook.c
index c69d82273ce7..32c3dfdb4d6a 100644
--- a/kernel/trace/rethook.c
+++ b/kernel/trace/rethook.c
@@ -83,8 +83,10 @@ struct rethook *rethook_alloc(void *data, rethook_handler_t handler)
{
struct rethook *rh = kzalloc(sizeof(struct rethook), GFP_KERNEL);
- if (!rh || !handler)
+ if (!rh || !handler) {
+ kfree(rh);
return NULL;
+ }
rh->data = data;
rh->handler = handler;
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 9712083832f4..b21bf14bae9b 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -519,6 +519,7 @@ struct ring_buffer_per_cpu {
local_t committing;
local_t commits;
local_t pages_touched;
+ local_t pages_lost;
local_t pages_read;
long last_pages_touch;
size_t shortest_full;
@@ -894,10 +895,18 @@ size_t ring_buffer_nr_pages(struct trace_buffer *buffer, int cpu)
size_t ring_buffer_nr_dirty_pages(struct trace_buffer *buffer, int cpu)
{
size_t read;
+ size_t lost;
size_t cnt;
read = local_read(&buffer->buffers[cpu]->pages_read);
+ lost = local_read(&buffer->buffers[cpu]->pages_lost);
cnt = local_read(&buffer->buffers[cpu]->pages_touched);
+
+ if (WARN_ON_ONCE(cnt < lost))
+ return 0;
+
+ cnt -= lost;
+
/* The reader can read an empty page, but not more than that */
if (cnt < read) {
WARN_ON_ONCE(read > cnt + 1);
@@ -907,6 +916,21 @@ size_t ring_buffer_nr_dirty_pages(struct trace_buffer *buffer, int cpu)
return cnt - read;
}
+static __always_inline bool full_hit(struct trace_buffer *buffer, int cpu, int full)
+{
+ struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
+ size_t nr_pages;
+ size_t dirty;
+
+ nr_pages = cpu_buffer->nr_pages;
+ if (!nr_pages || !full)
+ return true;
+
+ dirty = ring_buffer_nr_dirty_pages(buffer, cpu);
+
+ return (dirty * 100) > (full * nr_pages);
+}
+
/*
* rb_wake_up_waiters - wake up tasks waiting for ring buffer input
*
@@ -1046,22 +1070,20 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full)
!ring_buffer_empty_cpu(buffer, cpu)) {
unsigned long flags;
bool pagebusy;
- size_t nr_pages;
- size_t dirty;
+ bool done;
if (!full)
break;
raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
pagebusy = cpu_buffer->reader_page == cpu_buffer->commit_page;
- nr_pages = cpu_buffer->nr_pages;
- dirty = ring_buffer_nr_dirty_pages(buffer, cpu);
+ done = !pagebusy && full_hit(buffer, cpu, full);
+
if (!cpu_buffer->shortest_full ||
cpu_buffer->shortest_full > full)
cpu_buffer->shortest_full = full;
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
- if (!pagebusy &&
- (!nr_pages || (dirty * 100) > full * nr_pages))
+ if (done)
break;
}
@@ -1087,6 +1109,7 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full)
* @cpu: the cpu buffer to wait on
* @filp: the file descriptor
* @poll_table: The poll descriptor
+ * @full: wait until the percentage of pages are available, if @cpu != RING_BUFFER_ALL_CPUS
*
* If @cpu == RING_BUFFER_ALL_CPUS then the task will wake up as soon
* as data is added to any of the @buffer's cpu buffers. Otherwise
@@ -1096,14 +1119,15 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full)
* zero otherwise.
*/
__poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
- struct file *filp, poll_table *poll_table)
+ struct file *filp, poll_table *poll_table, int full)
{
struct ring_buffer_per_cpu *cpu_buffer;
struct rb_irq_work *work;
- if (cpu == RING_BUFFER_ALL_CPUS)
+ if (cpu == RING_BUFFER_ALL_CPUS) {
work = &buffer->irq_work;
- else {
+ full = 0;
+ } else {
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return -EINVAL;
@@ -1111,8 +1135,14 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
work = &cpu_buffer->irq_work;
}
- poll_wait(filp, &work->waiters, poll_table);
- work->waiters_pending = true;
+ if (full) {
+ poll_wait(filp, &work->full_waiters, poll_table);
+ work->full_waiters_pending = true;
+ } else {
+ poll_wait(filp, &work->waiters, poll_table);
+ work->waiters_pending = true;
+ }
+
/*
* There's a tight race between setting the waiters_pending and
* checking if the ring buffer is empty. Once the waiters_pending bit
@@ -1128,6 +1158,9 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
*/
smp_mb();
+ if (full)
+ return full_hit(buffer, cpu, full) ? EPOLLIN | EPOLLRDNORM : 0;
+
if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
(cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
return EPOLLIN | EPOLLRDNORM;
@@ -1769,9 +1802,9 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
free_buffer_page(cpu_buffer->reader_page);
- rb_head_page_deactivate(cpu_buffer);
-
if (head) {
+ rb_head_page_deactivate(cpu_buffer);
+
list_for_each_entry_safe(bpage, tmp, head, list) {
list_del_init(&bpage->list);
free_buffer_page(bpage);
@@ -2007,6 +2040,7 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned long nr_pages)
*/
local_add(page_entries, &cpu_buffer->overrun);
local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+ local_inc(&cpu_buffer->pages_lost);
}
/*
@@ -2491,6 +2525,7 @@ rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer,
*/
local_add(entries, &cpu_buffer->overrun);
local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+ local_inc(&cpu_buffer->pages_lost);
/*
* The entries will be zeroed out when we move the
@@ -3155,10 +3190,6 @@ static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
static __always_inline void
rb_wakeups(struct trace_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
{
- size_t nr_pages;
- size_t dirty;
- size_t full;
-
if (buffer->irq_work.waiters_pending) {
buffer->irq_work.waiters_pending = false;
/* irq_work_queue() supplies it's own memory barriers */
@@ -3182,10 +3213,7 @@ rb_wakeups(struct trace_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer->last_pages_touch = local_read(&cpu_buffer->pages_touched);
- full = cpu_buffer->shortest_full;
- nr_pages = cpu_buffer->nr_pages;
- dirty = ring_buffer_nr_dirty_pages(buffer, cpu_buffer->cpu);
- if (full && nr_pages && (dirty * 100) <= full * nr_pages)
+ if (!full_hit(buffer, cpu_buffer->cpu, cpu_buffer->shortest_full))
return;
cpu_buffer->irq_work.wakeup_full = true;
@@ -5248,6 +5276,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
local_set(&cpu_buffer->committing, 0);
local_set(&cpu_buffer->commits, 0);
local_set(&cpu_buffer->pages_touched, 0);
+ local_set(&cpu_buffer->pages_lost, 0);
local_set(&cpu_buffer->pages_read, 0);
cpu_buffer->last_pages_touch = 0;
cpu_buffer->shortest_full = 0;
diff --git a/kernel/trace/synth_event_gen_test.c b/kernel/trace/synth_event_gen_test.c
index 0b15e975d2c2..8d77526892f4 100644
--- a/kernel/trace/synth_event_gen_test.c
+++ b/kernel/trace/synth_event_gen_test.c
@@ -120,15 +120,13 @@ static int __init test_gen_synth_cmd(void)
/* Now generate a gen_synth_test event */
ret = synth_event_trace_array(gen_synth_test, vals, ARRAY_SIZE(vals));
- out:
+ free:
+ kfree(buf);
return ret;
delete:
/* We got an error after creating the event, delete it */
synth_event_delete("gen_synth_test");
- free:
- kfree(buf);
-
- goto out;
+ goto free;
}
/*
@@ -227,15 +225,13 @@ static int __init test_empty_synth_event(void)
/* Now trace an empty_synth_test event */
ret = synth_event_trace_array(empty_synth_test, vals, ARRAY_SIZE(vals));
- out:
+ free:
+ kfree(buf);
return ret;
delete:
/* We got an error after creating the event, delete it */
synth_event_delete("empty_synth_test");
- free:
- kfree(buf);
-
- goto out;
+ goto free;
}
static struct synth_field_desc create_synth_test_fields[] = {
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 47a44b055a1d..5cfc95a52bc3 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2180,10 +2180,12 @@ void tracing_reset_online_cpus(struct array_buffer *buf)
}
/* Must have trace_types_lock held */
-void tracing_reset_all_online_cpus(void)
+void tracing_reset_all_online_cpus_unlocked(void)
{
struct trace_array *tr;
+ lockdep_assert_held(&trace_types_lock);
+
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
if (!tr->clear_trace)
continue;
@@ -2195,6 +2197,13 @@ void tracing_reset_all_online_cpus(void)
}
}
+void tracing_reset_all_online_cpus(void)
+{
+ mutex_lock(&trace_types_lock);
+ tracing_reset_all_online_cpus_unlocked();
+ mutex_unlock(&trace_types_lock);
+}
+
/*
* The tgid_map array maps from pid to tgid; i.e. the value stored at index i
* is the tgid last observed corresponding to pid=i.
@@ -6657,6 +6666,7 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
mutex_unlock(&trace_types_lock);
free_cpumask_var(iter->started);
+ kfree(iter->fmt);
mutex_destroy(&iter->mutex);
kfree(iter);
@@ -6681,7 +6691,7 @@ trace_poll(struct trace_iterator *iter, struct file *filp, poll_table *poll_tabl
return EPOLLIN | EPOLLRDNORM;
else
return ring_buffer_poll_wait(iter->array_buffer->buffer, iter->cpu_file,
- filp, poll_table);
+ filp, poll_table, iter->tr->buffer_percent);
}
static __poll_t
@@ -7802,6 +7812,7 @@ static struct tracing_log_err *get_tracing_log_err(struct trace_array *tr,
int len)
{
struct tracing_log_err *err;
+ char *cmd;
if (tr->n_err_log_entries < TRACING_LOG_ERRS_MAX) {
err = alloc_tracing_log_err(len);
@@ -7810,12 +7821,12 @@ static struct tracing_log_err *get_tracing_log_err(struct trace_array *tr,
return err;
}
-
+ cmd = kzalloc(len, GFP_KERNEL);
+ if (!cmd)
+ return ERR_PTR(-ENOMEM);
err = list_first_entry(&tr->err_log, struct tracing_log_err, list);
kfree(err->cmd);
- err->cmd = kzalloc(len, GFP_KERNEL);
- if (!err->cmd)
- return ERR_PTR(-ENOMEM);
+ err->cmd = cmd;
list_del(&err->list);
return err;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 54ee5711c729..d42e24507152 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -580,6 +580,7 @@ int tracing_is_enabled(void);
void tracing_reset_online_cpus(struct array_buffer *buf);
void tracing_reset_current(int cpu);
void tracing_reset_all_online_cpus(void);
+void tracing_reset_all_online_cpus_unlocked(void);
int tracing_open_generic(struct inode *inode, struct file *filp);
int tracing_open_generic_tr(struct inode *inode, struct file *filp);
bool tracing_is_disabled(void);
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index 154996684fb5..4376887e0d8a 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -118,6 +118,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
if (ret)
break;
}
+ tracing_reset_all_online_cpus();
mutex_unlock(&event_mutex);
out:
argv_free(argv);
@@ -214,6 +215,7 @@ int dyn_events_release_all(struct dyn_event_operations *type)
break;
}
out:
+ tracing_reset_all_online_cpus();
mutex_unlock(&event_mutex);
return ret;
diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c
index 5dd0617e5df6..352b65e2b910 100644
--- a/kernel/trace/trace_eprobe.c
+++ b/kernel/trace/trace_eprobe.c
@@ -52,6 +52,7 @@ static void trace_event_probe_cleanup(struct trace_eprobe *ep)
kfree(ep->event_system);
if (ep->event)
trace_event_put_ref(ep->event);
+ kfree(ep->filter_str);
kfree(ep);
}
@@ -563,6 +564,9 @@ static void eprobe_trigger_func(struct event_trigger_data *data,
{
struct eprobe_data *edata = data->private_data;
+ if (unlikely(!rec))
+ return;
+
__eprobe_trace_func(edata, rec);
}
@@ -642,7 +646,7 @@ new_eprobe_trigger(struct trace_eprobe *ep, struct trace_event_file *file)
INIT_LIST_HEAD(&trigger->list);
if (ep->filter_str) {
- ret = create_event_filter(file->tr, file->event_call,
+ ret = create_event_filter(file->tr, ep->event,
ep->filter_str, false, &filter);
if (ret)
goto error;
@@ -900,7 +904,7 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
static int trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, const char *argv[])
{
- struct event_filter *dummy;
+ struct event_filter *dummy = NULL;
int i, ret, len = 0;
char *p;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 0356cae0cf74..f71ea6e79b3c 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2880,7 +2880,10 @@ static int probe_remove_event_call(struct trace_event_call *call)
* TRACE_REG_UNREGISTER.
*/
if (file->flags & EVENT_FILE_FL_ENABLED)
- return -EBUSY;
+ goto busy;
+
+ if (file->flags & EVENT_FILE_FL_WAS_ENABLED)
+ tr->clear_trace = true;
/*
* The do_for_each_event_file_safe() is
* a double loop. After finding the call for this
@@ -2893,6 +2896,12 @@ static int probe_remove_event_call(struct trace_event_call *call)
__trace_remove_event_call(call);
return 0;
+ busy:
+ /* No need to clear the trace now */
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ tr->clear_trace = false;
+ }
+ return -EBUSY;
}
/* Remove an event_call */
@@ -2972,7 +2981,7 @@ static void trace_module_remove_events(struct module *mod)
* over from this module may be passed to the new module events and
* unexpected results may occur.
*/
- tracing_reset_all_online_cpus();
+ tracing_reset_all_online_cpus_unlocked();
}
static int trace_module_notify(struct notifier_block *self,
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 48465f7e97b4..1c82478e8dff 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -983,7 +983,7 @@ static struct hist_field *find_any_var_ref(struct hist_trigger_data *hist_data,
* A trigger can define one or more variables. If any one of them is
* currently referenced by any other trigger, this function will
* determine that.
-
+ *
* Typically used to determine whether or not a trigger can be removed
* - if there are any references to a trigger's variables, it cannot.
*
@@ -3226,7 +3226,7 @@ static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
* events. However, for convenience, users are allowed to directly
* specify an event field in an action, which will be automatically
* converted into a variable on their behalf.
-
+ *
* This function creates a field variable with the name var_name on
* the hist trigger currently being defined on the target event. If
* subsys_name and event_name are specified, this function simply
@@ -5143,6 +5143,9 @@ static void event_hist_trigger(struct event_trigger_data *data,
void *key = NULL;
unsigned int i;
+ if (unlikely(!rbe))
+ return;
+
memset(compound_key, 0, hist_data->key_size);
for_each_hist_key_field(i, hist_data) {
diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index e310052dc83c..c3b582d19b62 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -828,10 +828,9 @@ static int register_synth_event(struct synth_event *event)
}
ret = set_synth_event_print_fmt(call);
- if (ret < 0) {
+ /* unregister_trace_event() will be called inside */
+ if (ret < 0)
trace_remove_event_call(call);
- goto err;
- }
out:
return ret;
err:
@@ -1426,7 +1425,6 @@ int synth_event_delete(const char *event_name)
mutex_unlock(&event_mutex);
if (mod) {
- mutex_lock(&trace_types_lock);
/*
* It is safest to reset the ring buffer if the module
* being unloaded registered any events that were
@@ -1438,7 +1436,6 @@ int synth_event_delete(const char *event_name)
* occur.
*/
tracing_reset_all_online_cpus();
- mutex_unlock(&trace_types_lock);
}
return ret;
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index ae78c2d53c8a..a93ed1c49b08 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -1100,8 +1100,10 @@ static int user_event_create(const char *raw_command)
group = current_user_event_group();
- if (!group)
+ if (!group) {
+ kfree(name);
return -ENOENT;
+ }
mutex_lock(&group->reg_mutex);
@@ -1486,7 +1488,7 @@ static ssize_t user_events_write(struct file *file, const char __user *ubuf,
if (unlikely(*ppos != 0))
return -EFAULT;
- if (unlikely(import_single_range(WRITE, (char __user *)ubuf,
+ if (unlikely(import_single_range(ITER_SOURCE, (char __user *)ubuf,
count, &iov, &i)))
return -EFAULT;
diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c
index 78d536d3ff3d..4300c5dc4e5d 100644
--- a/kernel/trace/trace_osnoise.c
+++ b/kernel/trace/trace_osnoise.c
@@ -917,7 +917,7 @@ void osnoise_trace_irq_entry(int id)
void osnoise_trace_irq_exit(int id, const char *desc)
{
struct osnoise_variables *osn_var = this_cpu_osn_var();
- int duration;
+ s64 duration;
if (!osn_var->sampling)
return;
@@ -1048,7 +1048,7 @@ static void trace_softirq_entry_callback(void *data, unsigned int vec_nr)
static void trace_softirq_exit_callback(void *data, unsigned int vec_nr)
{
struct osnoise_variables *osn_var = this_cpu_osn_var();
- int duration;
+ s64 duration;
if (!osn_var->sampling)
return;
@@ -1144,7 +1144,7 @@ thread_entry(struct osnoise_variables *osn_var, struct task_struct *t)
static void
thread_exit(struct osnoise_variables *osn_var, struct task_struct *t)
{
- int duration;
+ s64 duration;
if (!osn_var->sampling)
return;
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index b69e207012c9..942ddbdace4a 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -201,8 +201,6 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
return trace_handle_return(s);
}
-extern char *__bad_type_size(void);
-
#define SYSCALL_FIELD(_type, _name) { \
.type = #_type, .name = #_name, \
.size = sizeof(_type), .align = __alignof__(_type), \
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 7cd5f5e7e0a1..07895deca271 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1771,7 +1771,7 @@ bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
rwork->wq = wq;
- call_rcu(&rwork->rcu, rcu_work_rcufn);
+ call_rcu_hurry(&rwork->rcu, rcu_work_rcufn);
return true;
}
diff --git a/lib/Kconfig b/lib/Kconfig
index 9bbf8a4b2108..e69c2d819c44 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -529,8 +529,8 @@ config CPUMASK_OFFSTACK
stack overflow.
config FORCE_NR_CPUS
- bool "NR_CPUS is set to an actual number of CPUs"
- depends on SMP
+ bool "Set number of CPUs at compile time"
+ depends on SMP && EXPERT && !COMPILE_TEST
help
Say Yes if you have NR_CPUS set to an actual number of possible
CPUs in your system, not to a default value. This forces the core
@@ -672,6 +672,9 @@ config ARCH_HAS_PMEM_API
config MEMREGION
bool
+config ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
+ bool
+
config ARCH_HAS_MEMREMAP_COMPAT_ALIGN
bool
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 29280072dc0e..9dc5066654fd 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -395,12 +395,13 @@ endif # DEBUG_INFO
config FRAME_WARN
int "Warn for stack frames larger than"
range 0 8192
+ default 0 if KMSAN
default 2048 if GCC_PLUGIN_LATENT_ENTROPY
default 2048 if PARISC
default 1536 if (!64BIT && XTENSA)
+ default 1280 if KASAN && !64BIT
default 1024 if !64BIT
default 2048 if 64BIT
- default 0 if KMSAN
help
Tell the compiler to warn at build time for stack frames larger than this.
Setting this too low will cause a lot of warnings.
@@ -1716,6 +1717,16 @@ config LATENCYTOP
Enable this option if you want to use the LatencyTOP tool
to find out which userspace is blocking on what kernel operations.
+config DEBUG_CGROUP_REF
+ bool "Disable inlining of cgroup css reference count functions"
+ depends on DEBUG_KERNEL
+ depends on CGROUPS
+ depends on KPROBES
+ default n
+ help
+ Force cgroup css reference count functions to not be inlined so
+ that they can be kprobed for debugging.
+
source "kernel/trace/Kconfig"
config PROVIDE_OHCI1394_DMA_INIT
@@ -1874,8 +1885,14 @@ config NETDEV_NOTIFIER_ERROR_INJECT
If unsure, say N.
config FUNCTION_ERROR_INJECTION
- def_bool y
+ bool "Fault-injections of functions"
depends on HAVE_FUNCTION_ERROR_INJECTION && KPROBES
+ help
+ Add fault injections into various functions that are annotated with
+ ALLOW_ERROR_INJECTION() in the kernel. BPF may also modify the return
+ value of theses functions. This is useful to test error paths of code.
+
+ If unsure, say N
config FAULT_INJECTION
bool "Fault-injection framework"
@@ -2107,6 +2124,7 @@ config KPROBES_SANITY_TEST
depends on DEBUG_KERNEL
depends on KPROBES
depends on KUNIT
+ select STACKTRACE if ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
default KUNIT_ALL_TESTS
help
This option provides for testing basic kprobes functionality on
@@ -2241,6 +2259,10 @@ config TEST_UUID
config TEST_XARRAY
tristate "Test the XArray code at runtime"
+config TEST_MAPLE_TREE
+ select DEBUG_MAPLE_TREE
+ tristate "Test the Maple Tree code at runtime"
+
config TEST_RHASHTABLE
tristate "Perform selftest on resizable hash table"
help
@@ -2801,6 +2823,22 @@ config RUST_OVERFLOW_CHECKS
If unsure, say Y.
+config RUST_BUILD_ASSERT_ALLOW
+ bool "Allow unoptimized build-time assertions"
+ depends on RUST
+ help
+ Controls how are `build_error!` and `build_assert!` handled during build.
+
+ If calls to them exist in the binary, it may indicate a violated invariant
+ or that the optimizer failed to verify the invariant during compilation.
+
+ This should not happen, thus by default the build is aborted. However,
+ as an escape hatch, you can choose Y here to ignore them during build
+ and let the check be carried at runtime (with `panic!` being called if
+ the check fails).
+
+ If unsure, say N.
+
endmenu # "Rust"
source "Documentation/Kconfig"
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index ca09b1cf8ee9..836f70393e22 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -37,7 +37,7 @@ menuconfig KASAN
(HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS)) && \
CC_HAS_WORKING_NOSANITIZE_ADDRESS) || \
HAVE_ARCH_KASAN_HW_TAGS
- depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB)
+ depends on (SLUB && SYSFS && !SLUB_TINY) || (SLAB && !DEBUG_SLAB)
select STACKDEPOT_ALWAYS_INIT
help
Enables KASAN (Kernel Address Sanitizer) - a dynamic memory safety
diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan
index 47a693c45864..375575a5a0e3 100644
--- a/lib/Kconfig.kcsan
+++ b/lib/Kconfig.kcsan
@@ -125,7 +125,7 @@ config KCSAN_SKIP_WATCH
default 4000
help
The number of per-CPU memory operations to skip, before another
- watchpoint is set up, i.e. one in KCSAN_WATCH_SKIP per-CPU
+ watchpoint is set up, i.e. one in KCSAN_SKIP_WATCH per-CPU
memory operations are used to set up a watchpoint. A smaller value
results in more aggressive race detection, whereas a larger value
improves system performance at the cost of missing some races.
@@ -135,8 +135,8 @@ config KCSAN_SKIP_WATCH_RANDOMIZE
default y
help
If instruction skip count should be randomized, where the maximum is
- KCSAN_WATCH_SKIP. If false, the chosen value is always
- KCSAN_WATCH_SKIP.
+ KCSAN_SKIP_WATCH. If false, the chosen value is always
+ KCSAN_SKIP_WATCH.
config KCSAN_INTERRUPT_WATCHER
bool "Interruptible watchers" if !KCSAN_STRICT
diff --git a/lib/Kconfig.kmsan b/lib/Kconfig.kmsan
index b2489dd6503f..ef2c8f256c57 100644
--- a/lib/Kconfig.kmsan
+++ b/lib/Kconfig.kmsan
@@ -12,6 +12,7 @@ config KMSAN
bool "KMSAN: detector of uninitialized values use"
depends on HAVE_ARCH_KMSAN && HAVE_KMSAN_COMPILER
depends on SLUB && DEBUG_KERNEL && !KASAN && !KCSAN
+ depends on !PREEMPT_RT
select STACKDEPOT
select STACKDEPOT_ALWAYS_INIT
help
diff --git a/lib/Makefile b/lib/Makefile
index 161d6a724ff7..59bd7c2f793a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
obj-$(CONFIG_TEST_STRSCPY) += test_strscpy.o
obj-$(CONFIG_TEST_UUID) += test_uuid.o
obj-$(CONFIG_TEST_XARRAY) += test_xarray.o
+obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o
obj-$(CONFIG_TEST_PARMAN) += test_parman.o
obj-$(CONFIG_TEST_KMOD) += test_kmod.o
obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index 337d797a7141..df86e649d8be 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -437,6 +437,7 @@ static int object_cpu_offline(unsigned int cpu)
struct debug_percpu_free *percpu_pool;
struct hlist_node *tmp;
struct debug_obj *obj;
+ unsigned long flags;
/* Remote access is safe as the CPU is dead already */
percpu_pool = per_cpu_ptr(&percpu_obj_pool, cpu);
@@ -444,6 +445,12 @@ static int object_cpu_offline(unsigned int cpu)
hlist_del(&obj->node);
kmem_cache_free(obj_cache, obj);
}
+
+ raw_spin_lock_irqsave(&pool_lock, flags);
+ obj_pool_used -= percpu_pool->obj_free;
+ debug_objects_freed += percpu_pool->obj_free;
+ raw_spin_unlock_irqrestore(&pool_lock, flags);
+
percpu_pool->obj_free = 0;
return 0;
@@ -500,9 +507,9 @@ static void debug_print_object(struct debug_obj *obj, char *msg)
descr->debug_hint(obj->object) : NULL;
limit++;
WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
- "object type: %s hint: %pS\n",
+ "object: %p object type: %s hint: %pS\n",
msg, obj_states[obj->state], obj->astate,
- descr->name, hint);
+ obj->object, descr->name, hint);
}
debug_objects_warnings++;
}
@@ -1318,6 +1325,8 @@ static int __init debug_objects_replace_static_objects(void)
hlist_add_head(&obj->node, &objects);
}
+ debug_objects_allocated += i;
+
/*
* debug_objects_mem_init() is now called early that only one CPU is up
* and interrupts have been disabled, so it is safe to replace the
@@ -1386,6 +1395,7 @@ void __init debug_objects_mem_init(void)
debug_objects_enabled = 0;
kmem_cache_destroy(obj_cache);
pr_warn("out of memory.\n");
+ return;
} else
debug_objects_selftest();
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index 96e092de5b72..1421818c9ef7 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -41,9 +41,6 @@ EXPORT_SYMBOL_GPL(setup_fault_attr);
static void fail_dump(struct fault_attr *attr)
{
- if (attr->no_warn)
- return;
-
if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
"name %pd, interval %lu, probability %lu, "
@@ -103,7 +100,7 @@ static inline bool fail_stacktrace(struct fault_attr *attr)
* http://www.nongnu.org/failmalloc/
*/
-bool should_fail(struct fault_attr *attr, ssize_t size)
+bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags)
{
if (in_task()) {
unsigned int fail_nth = READ_ONCE(current->fail_nth);
@@ -139,20 +136,26 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
return false;
}
- if (attr->probability <= prandom_u32_max(100))
+ if (attr->probability <= get_random_u32_below(100))
return false;
if (!fail_stacktrace(attr))
return false;
fail:
- fail_dump(attr);
+ if (!(flags & FAULT_NOWARN))
+ fail_dump(attr);
if (atomic_read(&attr->times) != -1)
atomic_dec_not_zero(&attr->times);
return true;
}
+
+bool should_fail(struct fault_attr *attr, ssize_t size)
+{
+ return should_fail_ex(attr, size, 0);
+}
EXPORT_SYMBOL_GPL(should_fail);
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
diff --git a/lib/find_bit_benchmark.c b/lib/find_bit_benchmark.c
index 7c3c011abd29..d3fb09e6eff1 100644
--- a/lib/find_bit_benchmark.c
+++ b/lib/find_bit_benchmark.c
@@ -174,8 +174,8 @@ static int __init find_bit_test(void)
bitmap_zero(bitmap2, BITMAP_LEN);
while (nbits--) {
- __set_bit(prandom_u32_max(BITMAP_LEN), bitmap);
- __set_bit(prandom_u32_max(BITMAP_LEN), bitmap2);
+ __set_bit(get_random_u32_below(BITMAP_LEN), bitmap);
+ __set_bit(get_random_u32_below(BITMAP_LEN), bitmap2);
}
test_find_next_bit(bitmap, BITMAP_LEN);
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 5f4b07b56cd9..973866438608 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -135,8 +135,8 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
if (res > 20)
c += 20 - res;
- if ((font_w & (1 << (f->width - 1))) &&
- (font_h & (1 << (f->height - 1))))
+ if ((font_w & (1U << (f->width - 1))) &&
+ (font_h & (1U << (f->height - 1))))
c += 1000;
if (c > cc) {
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index c3ca28ca68a6..f9a3ff37ecd1 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -520,6 +520,8 @@ static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes,
size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
{
+ if (WARN_ON_ONCE(i->data_source))
+ return 0;
if (unlikely(iov_iter_is_pipe(i)))
return copy_pipe_to_iter(addr, bytes, i);
if (user_backed_iter(i))
@@ -606,6 +608,8 @@ static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes,
*/
size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
{
+ if (WARN_ON_ONCE(i->data_source))
+ return 0;
if (unlikely(iov_iter_is_pipe(i)))
return copy_mc_pipe_to_iter(addr, bytes, i);
if (user_backed_iter(i))
@@ -622,10 +626,9 @@ EXPORT_SYMBOL_GPL(_copy_mc_to_iter);
size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
{
- if (unlikely(iov_iter_is_pipe(i))) {
- WARN_ON(1);
+ if (WARN_ON_ONCE(!i->data_source))
return 0;
- }
+
if (user_backed_iter(i))
might_fault();
iterate_and_advance(i, bytes, base, len, off,
@@ -639,10 +642,9 @@ EXPORT_SYMBOL(_copy_from_iter);
size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
{
- if (unlikely(iov_iter_is_pipe(i))) {
- WARN_ON(1);
+ if (WARN_ON_ONCE(!i->data_source))
return 0;
- }
+
iterate_and_advance(i, bytes, base, len, off,
__copy_from_user_inatomic_nocache(addr + off, base, len),
memcpy(addr + off, base, len)
@@ -671,10 +673,9 @@ EXPORT_SYMBOL(_copy_from_iter_nocache);
*/
size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i)
{
- if (unlikely(iov_iter_is_pipe(i))) {
- WARN_ON(1);
+ if (WARN_ON_ONCE(!i->data_source))
return 0;
- }
+
iterate_and_advance(i, bytes, base, len, off,
__copy_from_user_flushcache(addr + off, base, len),
memcpy_flushcache(addr + off, base, len)
@@ -703,17 +704,18 @@ static inline bool page_copy_sane(struct page *page, size_t offset, size_t n)
head = compound_head(page);
v += (page - head) << PAGE_SHIFT;
- if (likely(n <= v && v <= (page_size(head))))
- return true;
- WARN_ON(1);
- return false;
+ if (WARN_ON(n > v || v > page_size(head)))
+ return false;
+ return true;
}
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
size_t res = 0;
- if (unlikely(!page_copy_sane(page, offset, bytes)))
+ if (!page_copy_sane(page, offset, bytes))
+ return 0;
+ if (WARN_ON_ONCE(i->data_source))
return 0;
if (unlikely(iov_iter_is_pipe(i)))
return copy_page_to_iter_pipe(page, offset, bytes, i);
@@ -808,13 +810,12 @@ size_t copy_page_from_iter_atomic(struct page *page, unsigned offset, size_t byt
struct iov_iter *i)
{
char *kaddr = kmap_atomic(page), *p = kaddr + offset;
- if (unlikely(!page_copy_sane(page, offset, bytes))) {
+ if (!page_copy_sane(page, offset, bytes)) {
kunmap_atomic(kaddr);
return 0;
}
- if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
+ if (WARN_ON_ONCE(!i->data_source)) {
kunmap_atomic(kaddr);
- WARN_ON(1);
return 0;
}
iterate_and_advance(i, bytes, base, len, off,
@@ -1430,7 +1431,8 @@ static struct page *first_bvec_segment(const struct iov_iter *i,
static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,
struct page ***pages, size_t maxsize,
- unsigned int maxpages, size_t *start)
+ unsigned int maxpages, size_t *start,
+ unsigned int gup_flags)
{
unsigned int n;
@@ -1442,7 +1444,6 @@ static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,
maxsize = MAX_RW_COUNT;
if (likely(user_backed_iter(i))) {
- unsigned int gup_flags = 0;
unsigned long addr;
int res;
@@ -1492,33 +1493,49 @@ static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,
return -EFAULT;
}
-ssize_t iov_iter_get_pages2(struct iov_iter *i,
+ssize_t iov_iter_get_pages(struct iov_iter *i,
struct page **pages, size_t maxsize, unsigned maxpages,
- size_t *start)
+ size_t *start, unsigned gup_flags)
{
if (!maxpages)
return 0;
BUG_ON(!pages);
- return __iov_iter_get_pages_alloc(i, &pages, maxsize, maxpages, start);
+ return __iov_iter_get_pages_alloc(i, &pages, maxsize, maxpages,
+ start, gup_flags);
+}
+EXPORT_SYMBOL_GPL(iov_iter_get_pages);
+
+ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages,
+ size_t maxsize, unsigned maxpages, size_t *start)
+{
+ return iov_iter_get_pages(i, pages, maxsize, maxpages, start, 0);
}
EXPORT_SYMBOL(iov_iter_get_pages2);
-ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i,
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
struct page ***pages, size_t maxsize,
- size_t *start)
+ size_t *start, unsigned gup_flags)
{
ssize_t len;
*pages = NULL;
- len = __iov_iter_get_pages_alloc(i, pages, maxsize, ~0U, start);
+ len = __iov_iter_get_pages_alloc(i, pages, maxsize, ~0U, start,
+ gup_flags);
if (len <= 0) {
kvfree(*pages);
*pages = NULL;
}
return len;
}
+EXPORT_SYMBOL_GPL(iov_iter_get_pages_alloc);
+
+ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i,
+ struct page ***pages, size_t maxsize, size_t *start)
+{
+ return iov_iter_get_pages_alloc(i, pages, maxsize, start, 0);
+}
EXPORT_SYMBOL(iov_iter_get_pages_alloc2);
size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
@@ -1526,10 +1543,9 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
{
__wsum sum, next;
sum = *csum;
- if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
- WARN_ON(1);
+ if (WARN_ON_ONCE(!i->data_source))
return 0;
- }
+
iterate_and_advance(i, bytes, base, len, off, ({
next = csum_and_copy_from_user(base, addr + off, len);
sum = csum_block_add(sum, next, off);
@@ -1549,9 +1565,15 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *_csstate,
struct csum_state *csstate = _csstate;
__wsum sum, next;
- if (unlikely(iov_iter_is_discard(i))) {
- WARN_ON(1); /* for now */
+ if (WARN_ON_ONCE(i->data_source))
return 0;
+ if (unlikely(iov_iter_is_discard(i))) {
+ // can't use csum_memcpy() for that one - data is not copied
+ csstate->csum = csum_block_add(csstate->csum,
+ csum_partial(addr, bytes, 0),
+ csstate->off);
+ csstate->off += bytes;
+ return bytes;
}
sum = csum_shift(csstate->csum, csstate->off);
diff --git a/lib/is_signed_type_kunit.c b/lib/is_signed_type_kunit.c
index 207207522925..0a7f6ae62839 100644
--- a/lib/is_signed_type_kunit.c
+++ b/lib/is_signed_type_kunit.c
@@ -21,11 +21,7 @@ static void is_signed_type_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, is_signed_type(bool), false);
KUNIT_EXPECT_EQ(test, is_signed_type(signed char), true);
KUNIT_EXPECT_EQ(test, is_signed_type(unsigned char), false);
-#ifdef __CHAR_UNSIGNED__
KUNIT_EXPECT_EQ(test, is_signed_type(char), false);
-#else
- KUNIT_EXPECT_EQ(test, is_signed_type(char), true);
-#endif
KUNIT_EXPECT_EQ(test, is_signed_type(int), true);
KUNIT_EXPECT_EQ(test, is_signed_type(unsigned int), false);
KUNIT_EXPECT_EQ(test, is_signed_type(long), true);
diff --git a/lib/kobject.c b/lib/kobject.c
index a0b2dbfcfa23..af1f5f2954d4 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -694,7 +694,7 @@ static void kobject_release(struct kref *kref)
{
struct kobject *kobj = container_of(kref, struct kobject, kref);
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
- unsigned long delay = HZ + HZ * prandom_u32_max(4);
+ unsigned long delay = HZ + HZ * get_random_u32_below(4);
pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n",
kobject_name(kobj), kobj, __func__, kobj->parent, delay);
INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
index d00d6d181ee8..f5b50babe38d 100644
--- a/lib/kunit/assert.c
+++ b/lib/kunit/assert.c
@@ -127,13 +127,15 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
binary_assert->text->right_text);
if (!is_literal(stream->test, binary_assert->text->left_text,
binary_assert->left_value, stream->gfp))
- string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld\n",
+ string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n",
binary_assert->text->left_text,
+ binary_assert->left_value,
binary_assert->left_value);
if (!is_literal(stream->test, binary_assert->text->right_text,
binary_assert->right_value, stream->gfp))
- string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld",
+ string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)",
binary_assert->text->right_text,
+ binary_assert->right_value,
binary_assert->right_value);
kunit_assert_print_msg(message, stream);
}
@@ -204,3 +206,59 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert,
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format);
+
+/* Adds a hexdump of a buffer to a string_stream comparing it with
+ * a second buffer. The different bytes are marked with <>.
+ */
+static void kunit_assert_hexdump(struct string_stream *stream,
+ const void *buf,
+ const void *compared_buf,
+ const size_t len)
+{
+ size_t i;
+ const u8 *buf1 = buf;
+ const u8 *buf2 = compared_buf;
+
+ string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT);
+
+ for (i = 0; i < len; ++i) {
+ if (!(i % 16) && i)
+ string_stream_add(stream, "\n" KUNIT_SUBSUBTEST_INDENT);
+
+ if (buf1[i] != buf2[i])
+ string_stream_add(stream, "<%02x>", buf1[i]);
+ else
+ string_stream_add(stream, " %02x ", buf1[i]);
+ }
+}
+
+void kunit_mem_assert_format(const struct kunit_assert *assert,
+ const struct va_format *message,
+ struct string_stream *stream)
+{
+ struct kunit_mem_assert *mem_assert;
+
+ mem_assert = container_of(assert, struct kunit_mem_assert,
+ assert);
+
+ string_stream_add(stream,
+ KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
+ mem_assert->text->left_text,
+ mem_assert->text->operation,
+ mem_assert->text->right_text);
+
+ string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
+ mem_assert->text->left_text);
+ kunit_assert_hexdump(stream, mem_assert->left_value,
+ mem_assert->right_value, mem_assert->size);
+
+ string_stream_add(stream, "\n");
+
+ string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
+ mem_assert->text->right_text);
+ kunit_assert_hexdump(stream, mem_assert->right_value,
+ mem_assert->left_value, mem_assert->size);
+
+ kunit_assert_print_msg(message, stream);
+}
+EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
index 1048ef1b8d6e..de0ee2e03ed6 100644
--- a/lib/kunit/debugfs.c
+++ b/lib/kunit/debugfs.c
@@ -63,7 +63,7 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
kunit_suite_for_each_test_case(suite, test_case)
debugfs_print_result(seq, suite, test_case);
- seq_printf(seq, "%s %d - %s\n",
+ seq_printf(seq, "%s %d %s\n",
kunit_status_to_ok_not_ok(success), 1, suite->name);
return 0;
}
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 9bbc422c284b..74982b83707c 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -166,7 +166,7 @@ static void kunit_exec_run_tests(struct suite_set *suite_set)
{
size_t num_suites = suite_set->end - suite_set->start;
- pr_info("TAP version 14\n");
+ pr_info("KTAP version 1\n");
pr_info("1..%zu\n", num_suites);
__kunit_test_suites_init(suite_set->start, num_suites);
@@ -177,8 +177,8 @@ static void kunit_exec_list_tests(struct suite_set *suite_set)
struct kunit_suite * const *suites;
struct kunit_case *test_case;
- /* Hack: print a tap header so kunit.py can find the start of KUnit output. */
- pr_info("TAP version 14\n");
+ /* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
+ pr_info("KTAP version 1\n");
for (suites = suite_set->start; suites < suite_set->end; suites++)
kunit_suite_for_each_test_case((*suites), test_case) {
diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index f8fe582c9e36..66cc4e2365ec 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -86,6 +86,9 @@ static void example_mark_skipped_test(struct kunit *test)
*/
static void example_all_expect_macros_test(struct kunit *test)
{
+ const u32 array1[] = { 0x0F, 0xFF };
+ const u32 array2[] = { 0x1F, 0xFF };
+
/* Boolean assertions */
KUNIT_EXPECT_TRUE(test, true);
KUNIT_EXPECT_FALSE(test, false);
@@ -109,6 +112,10 @@ static void example_all_expect_macros_test(struct kunit *test)
KUNIT_EXPECT_STREQ(test, "hi", "hi");
KUNIT_EXPECT_STRNEQ(test, "hi", "bye");
+ /* Memory block assertions */
+ KUNIT_EXPECT_MEMEQ(test, array1, array1, sizeof(array1));
+ KUNIT_EXPECT_MEMNEQ(test, array1, array2, sizeof(array1));
+
/*
* There are also ASSERT variants of all of the above that abort test
* execution if they fail. Useful for memory allocations, etc.
diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index a608746020a9..f5f51166d8c2 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -131,11 +131,6 @@ bool string_stream_is_empty(struct string_stream *stream)
return list_empty(&stream->fragments);
}
-struct string_stream_alloc_context {
- struct kunit *test;
- gfp_t gfp;
-};
-
struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
{
struct string_stream *stream;
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 2a6992fe7c3e..c9ebf975e56b 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -20,6 +20,8 @@
#include "string-stream.h"
#include "try-catch-impl.h"
+DEFINE_STATIC_KEY_FALSE(kunit_running);
+
#if IS_BUILTIN(CONFIG_KUNIT)
/*
* Fail the current test and print an error message to the log.
@@ -149,6 +151,7 @@ EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases);
static void kunit_print_suite_start(struct kunit_suite *suite)
{
+ kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "KTAP version 1\n");
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s",
suite->name);
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd",
@@ -175,13 +178,13 @@ static void kunit_print_ok_not_ok(void *test_or_suite,
* representation.
*/
if (suite)
- pr_info("%s %zd - %s%s%s\n",
+ pr_info("%s %zd %s%s%s\n",
kunit_status_to_ok_not_ok(status),
test_number, description, directive_header,
(status == KUNIT_SKIPPED) ? directive : "");
else
kunit_log(KERN_INFO, test,
- KUNIT_SUBTEST_INDENT "%s %zd - %s%s%s",
+ KUNIT_SUBTEST_INDENT "%s %zd %s%s%s",
kunit_status_to_ok_not_ok(status),
test_number, description, directive_header,
(status == KUNIT_SKIPPED) ? directive : "");
@@ -543,6 +546,8 @@ int kunit_run_tests(struct kunit_suite *suite)
param_desc[0] = '\0';
test.param_value = test_case->generate_params(NULL, param_desc);
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
+ "KTAP version 1\n");
+ kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
"# Subtest: %s", test_case->name);
while (test.param_value) {
@@ -555,7 +560,7 @@ int kunit_run_tests(struct kunit_suite *suite)
kunit_log(KERN_INFO, &test,
KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
- "%s %d - %s",
+ "%s %d %s",
kunit_status_to_ok_not_ok(test.status),
test.param_index + 1, param_desc);
@@ -612,10 +617,14 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_
return 0;
}
+ static_branch_inc(&kunit_running);
+
for (i = 0; i < num_suites; i++) {
kunit_init_suite(suites[i]);
kunit_run_tests(suites[i]);
}
+
+ static_branch_dec(&kunit_running);
return 0;
}
EXPORT_SYMBOL_GPL(__kunit_test_suites_init);
diff --git a/lib/llist.c b/lib/llist.c
index 7d78b736e8af..6e668fa5a2c6 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -26,10 +26,10 @@
bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
struct llist_head *head)
{
- struct llist_node *first;
+ struct llist_node *first = READ_ONCE(head->first);
do {
- new_last->next = first = READ_ONCE(head->first);
+ new_last->next = first;
} while (!try_cmpxchg(&head->first, &first, new_first));
return !first;
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
index dc35464216d3..b3d9187611de 100644
--- a/lib/lru_cache.c
+++ b/lib/lru_cache.c
@@ -60,17 +60,6 @@ int lc_try_lock(struct lru_cache *lc)
} while (unlikely (val == LC_PARANOIA));
/* Spin until no-one is inside a PARANOIA_ENTRY()/RETURN() section. */
return 0 == val;
-#if 0
- /* Alternative approach, spin in case someone enters or leaves a
- * PARANOIA_ENTRY()/RETURN() section. */
- unsigned long old, new, val;
- do {
- old = lc->flags & LC_PARANOIA;
- new = old | LC_LOCKED;
- val = cmpxchg(&lc->flags, old, new);
- } while (unlikely (val == (old ^ LC_PARANOIA)));
- return old == val;
-#endif
}
/**
@@ -364,7 +353,7 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsig
struct lc_element *e;
PARANOIA_ENTRY();
- if (lc->flags & LC_STARVING) {
+ if (test_bit(__LC_STARVING, &lc->flags)) {
++lc->starving;
RETURN(NULL);
}
@@ -417,7 +406,7 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsig
* the LRU element, we have to wait ...
*/
if (!lc_unused_element_available(lc)) {
- __set_bit(__LC_STARVING, &lc->flags);
+ set_bit(__LC_STARVING, &lc->flags);
RETURN(NULL);
}
@@ -586,48 +575,6 @@ struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
}
/**
- * lc_index_of
- * @lc: the lru cache to operate on
- * @e: the element to query for its index position in lc->element
- */
-unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
-{
- PARANOIA_LC_ELEMENT(lc, e);
- return e->lc_index;
-}
-
-/**
- * lc_set - associate index with label
- * @lc: the lru cache to operate on
- * @enr: the label to set
- * @index: the element index to associate label with.
- *
- * Used to initialize the active set to some previously recorded state.
- */
-void lc_set(struct lru_cache *lc, unsigned int enr, int index)
-{
- struct lc_element *e;
- struct list_head *lh;
-
- if (index < 0 || index >= lc->nr_elements)
- return;
-
- e = lc_element_by_index(lc, index);
- BUG_ON(e->lc_number != e->lc_new_number);
- BUG_ON(e->refcnt != 0);
-
- e->lc_number = e->lc_new_number = enr;
- hlist_del_init(&e->colision);
- if (enr == LC_FREE)
- lh = &lc->free;
- else {
- hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
- lh = &lc->lru;
- }
- list_move(&e->list, lh);
-}
-
-/**
* lc_seq_dump_details - Dump a complete LRU cache to seq in textual form.
* @lc: the lru cache to operate on
* @seq: the &struct seq_file pointer to seq_printf into
@@ -661,7 +608,6 @@ void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext
EXPORT_SYMBOL(lc_create);
EXPORT_SYMBOL(lc_reset);
EXPORT_SYMBOL(lc_destroy);
-EXPORT_SYMBOL(lc_set);
EXPORT_SYMBOL(lc_del);
EXPORT_SYMBOL(lc_try_get);
EXPORT_SYMBOL(lc_find);
@@ -669,7 +615,6 @@ EXPORT_SYMBOL(lc_get);
EXPORT_SYMBOL(lc_put);
EXPORT_SYMBOL(lc_committed);
EXPORT_SYMBOL(lc_element_by_index);
-EXPORT_SYMBOL(lc_index_of);
EXPORT_SYMBOL(lc_seq_printf_stats);
EXPORT_SYMBOL(lc_seq_dump_details);
EXPORT_SYMBOL(lc_try_lock);
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index fbde494444b8..df352f6ccc24 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -183,10 +183,6 @@ static void ma_free_rcu(struct maple_node *node)
call_rcu(&node->rcu, mt_free_rcu);
}
-static unsigned int mt_height(const struct maple_tree *mt)
-{
- return (mt->ma_flags & MT_FLAGS_HEIGHT_MASK) >> MT_FLAGS_HEIGHT_OFFSET;
-}
static void mas_set_height(struct ma_state *mas)
{
@@ -1209,7 +1205,6 @@ done:
static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
{
struct maple_alloc *node;
- struct maple_alloc **nodep = &mas->alloc;
unsigned long allocated = mas_allocated(mas);
unsigned long success = allocated;
unsigned int requested = mas_alloc_req(mas);
@@ -1263,8 +1258,7 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
node->node_count--;
success += count;
- nodep = &node->slot[0];
- node = *nodep;
+ node = node->slot[0];
requested -= count;
}
mas->alloc->total = success;
@@ -1357,6 +1351,7 @@ static inline struct maple_enode *mas_start(struct ma_state *mas)
root = mas_root(mas);
/* Tree with nodes */
if (likely(xa_is_node(root))) {
+ mas->depth = 1;
mas->node = mte_safe_root(root);
return NULL;
}
@@ -3608,8 +3603,7 @@ static inline int mas_commit_b_node(struct ma_wr_state *wr_mas,
node = mas_pop_node(wr_mas->mas);
node->parent = mas_mn(wr_mas->mas)->parent;
wr_mas->mas->node = mt_mk_node(node, b_type);
- mab_mas_cp(b_node, 0, b_end, wr_mas->mas, true);
-
+ mab_mas_cp(b_node, 0, b_end, wr_mas->mas, false);
mas_replace(wr_mas->mas, false);
reuse_node:
mas_update_gap(wr_mas->mas);
@@ -3733,7 +3727,6 @@ static bool mas_is_span_wr(struct ma_wr_state *wr_mas)
static inline void mas_wr_walk_descend(struct ma_wr_state *wr_mas)
{
- wr_mas->mas->depth++;
wr_mas->type = mte_node_type(wr_mas->mas->node);
mas_wr_node_walk(wr_mas);
wr_mas->slots = ma_slots(wr_mas->node, wr_mas->type);
@@ -3745,6 +3738,7 @@ static inline void mas_wr_walk_traverse(struct ma_wr_state *wr_mas)
wr_mas->mas->min = wr_mas->r_min;
wr_mas->mas->node = wr_mas->content;
wr_mas->mas->offset = 0;
+ wr_mas->mas->depth++;
}
/*
* mas_wr_walk() - Walk the tree for a write.
@@ -4970,8 +4964,9 @@ static inline bool mas_anode_descend(struct ma_state *mas, unsigned long size)
{
enum maple_type type = mte_node_type(mas->node);
unsigned long pivot, min, gap = 0;
- unsigned char count, offset;
- unsigned long *gaps = NULL, *pivots = ma_pivots(mas_mn(mas), type);
+ unsigned char offset;
+ unsigned long *gaps;
+ unsigned long *pivots = ma_pivots(mas_mn(mas), type);
void __rcu **slots = ma_slots(mas_mn(mas), type);
bool found = false;
@@ -4982,9 +4977,8 @@ static inline bool mas_anode_descend(struct ma_state *mas, unsigned long size)
gaps = ma_gaps(mte_to_node(mas->node), type);
offset = mas->offset;
- count = mt_slots[type];
min = mas_safe_min(mas, pivots, offset);
- for (; offset < count; offset++) {
+ for (; offset < mt_slots[type]; offset++) {
pivot = mas_safe_pivot(mas, pivots, offset, type);
if (offset && !pivot)
break;
@@ -5010,8 +5004,6 @@ static inline bool mas_anode_descend(struct ma_state *mas, unsigned long size)
mas->min = min;
mas->max = pivot;
offset = 0;
- type = mte_node_type(mas->node);
- count = mt_slots[type];
break;
}
}
@@ -5065,6 +5057,7 @@ retry:
return entry;
}
+EXPORT_SYMBOL_GPL(mas_walk);
static inline bool mas_rewind_node(struct ma_state *mas)
{
@@ -5276,6 +5269,7 @@ int mas_empty_area(struct ma_state *mas, unsigned long min,
mas->last = mas->index + size - 1;
return 0;
}
+EXPORT_SYMBOL_GPL(mas_empty_area);
/*
* mas_empty_area_rev() - Get the highest address within the range that is
@@ -5339,6 +5333,7 @@ int mas_empty_area_rev(struct ma_state *mas, unsigned long min,
mas->index = mas->last - size + 1;
return 0;
}
+EXPORT_SYMBOL_GPL(mas_empty_area_rev);
static inline int mas_alloc(struct ma_state *mas, void *entry,
unsigned long size, unsigned long *index)
@@ -5660,6 +5655,7 @@ void *mas_store(struct ma_state *mas, void *entry)
mas_wr_store_entry(&wr_mas);
return wr_mas.content;
}
+EXPORT_SYMBOL_GPL(mas_store);
/**
* mas_store_gfp() - Store a value into the tree.
@@ -5686,6 +5682,7 @@ retry:
return 0;
}
+EXPORT_SYMBOL_GPL(mas_store_gfp);
/**
* mas_store_prealloc() - Store a value into the tree using memory
@@ -5703,6 +5700,7 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)
BUG_ON(mas_is_err(mas));
mas_destroy(mas);
}
+EXPORT_SYMBOL_GPL(mas_store_prealloc);
/**
* mas_preallocate() - Preallocate enough nodes for a store operation
@@ -5772,6 +5770,7 @@ void mas_destroy(struct ma_state *mas)
}
mas->alloc = NULL;
}
+EXPORT_SYMBOL_GPL(mas_destroy);
/*
* mas_expected_entries() - Set the expected number of entries that will be inserted.
@@ -5833,6 +5832,7 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
return ret;
}
+EXPORT_SYMBOL_GPL(mas_expected_entries);
/**
* mas_next() - Get the next entry.
@@ -6013,6 +6013,7 @@ void *mas_find(struct ma_state *mas, unsigned long max)
/* Retries on dead nodes handled by mas_next_entry */
return mas_next_entry(mas, max);
}
+EXPORT_SYMBOL_GPL(mas_find);
/**
* mas_find_rev: On the first call, find the first non-null entry at or below
@@ -6059,7 +6060,7 @@ void *mas_find_rev(struct ma_state *mas, unsigned long min)
/* Retries on dead nodes handled by mas_next_entry */
return mas_prev_entry(mas, min);
}
-EXPORT_SYMBOL_GPL(mas_find);
+EXPORT_SYMBOL_GPL(mas_find_rev);
/**
* mas_erase() - Find the range in which index resides and erase the entire
@@ -6541,8 +6542,27 @@ static inline int mas_dead_node(struct ma_state *mas, unsigned long index)
mas_rewalk(mas, index);
return 1;
}
-#endif /* not defined __KERNEL__ */
+void mt_cache_shrink(void)
+{
+}
+#else
+/*
+ * mt_cache_shrink() - For testing, don't use this.
+ *
+ * Certain testcases can trigger an OOM when combined with other memory
+ * debugging configuration options. This function is used to reduce the
+ * possibility of an out of memory even due to kmem_cache objects remaining
+ * around for longer than usual.
+ */
+void mt_cache_shrink(void)
+{
+ kmem_cache_shrink(maple_node_cache);
+
+}
+EXPORT_SYMBOL_GPL(mt_cache_shrink);
+
+#endif /* not defined __KERNEL__ */
/*
* mas_get_slot() - Get the entry in the maple state node stored at @offset.
* @mas: The maple state
@@ -6816,6 +6836,7 @@ void mt_dump(const struct maple_tree *mt)
else if (entry)
mt_dump_node(mt, entry, 0, mt_max[mte_node_type(entry)], 0);
}
+EXPORT_SYMBOL_GPL(mt_dump);
/*
* Calculate the maximum gap in a node and check if that's what is reported in
@@ -7126,5 +7147,6 @@ done:
rcu_read_unlock();
}
+EXPORT_SYMBOL_GPL(mt_validate);
#endif /* CONFIG_DEBUG_MAPLE_TREE */
diff --git a/lib/math/div64.c b/lib/math/div64.c
index 46866394fc84..55a81782e271 100644
--- a/lib/math/div64.c
+++ b/lib/math/div64.c
@@ -63,12 +63,6 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
EXPORT_SYMBOL(__div64_32);
#endif
-/**
- * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
- * @dividend: 64bit dividend
- * @divisor: 64bit divisor
- * @remainder: 64bit remainder
- */
#ifndef div_s64_rem
s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
{
@@ -89,7 +83,7 @@ s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
EXPORT_SYMBOL(div_s64_rem);
#endif
-/**
+/*
* div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
* @dividend: 64bit dividend
* @divisor: 64bit divisor
@@ -129,7 +123,7 @@ u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
EXPORT_SYMBOL(div64_u64_rem);
#endif
-/**
+/*
* div64_u64 - unsigned 64bit divide with 64bit divisor
* @dividend: 64bit dividend
* @divisor: 64bit divisor
@@ -163,11 +157,6 @@ u64 div64_u64(u64 dividend, u64 divisor)
EXPORT_SYMBOL(div64_u64);
#endif
-/**
- * div64_s64 - signed 64bit divide with 64bit divisor
- * @dividend: 64bit dividend
- * @divisor: 64bit divisor
- */
#ifndef div64_s64
s64 div64_s64(s64 dividend, s64 divisor)
{
diff --git a/lib/notifier-error-inject.c b/lib/notifier-error-inject.c
index 21016b32d313..2b24ea6c9497 100644
--- a/lib/notifier-error-inject.c
+++ b/lib/notifier-error-inject.c
@@ -15,7 +15,7 @@ static int debugfs_errno_get(void *data, u64 *val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
+DEFINE_SIMPLE_ATTRIBUTE_SIGNED(fops_errno, debugfs_errno_get, debugfs_errno_set,
"%lld\n");
static struct dentry *debugfs_create_errno(const char *name, umode_t mode,
diff --git a/lib/oid_registry.c b/lib/oid_registry.c
index e592d48b1974..fe6705cfd780 100644
--- a/lib/oid_registry.c
+++ b/lib/oid_registry.c
@@ -146,7 +146,6 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
bufsize -= count;
while (v < end) {
- num = 0;
n = *v++;
if (!(n & 0x80)) {
num = n;
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index e5c5315da274..668f6aa6a75d 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -230,7 +230,8 @@ static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref,
percpu_ref_noop_confirm_switch;
percpu_ref_get(ref); /* put after confirmation */
- call_rcu(&ref->data->rcu, percpu_ref_switch_to_atomic_rcu);
+ call_rcu_hurry(&ref->data->rcu,
+ percpu_ref_switch_to_atomic_rcu);
}
static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 3c78e1e8b2ad..049ba132f7ef 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1029,7 +1029,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
{
struct radix_tree_node *node, *parent;
unsigned long maxindex;
- int offset;
+ int offset = 0;
radix_tree_load_root(root, &node, &maxindex);
if (index > maxindex)
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 39b74221f4a7..a22a05c9af8a 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -18,12 +18,10 @@
#else
#include <linux/module.h>
#include <linux/gfp.h>
-#if !RAID6_USE_EMPTY_ZERO_PAGE
/* In .bss so it's zeroed */
const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
EXPORT_SYMBOL(raid6_empty_zero_page);
#endif
-#endif
struct raid6_calls raid6_call;
EXPORT_SYMBOL_GPL(raid6_call);
diff --git a/lib/raid6/s390vx.uc b/lib/raid6/s390vx.uc
index 9e597e1f91a4..b25dfc9c7759 100644
--- a/lib/raid6/s390vx.uc
+++ b/lib/raid6/s390vx.uc
@@ -13,8 +13,7 @@
#include <linux/raid/pq.h>
#include <asm/fpu/api.h>
-
-asm(".include \"asm/vx-insn.h\"\n");
+#include <asm/vx-insn.h>
#define NSIZE 16
diff --git a/lib/reed_solomon/test_rslib.c b/lib/reed_solomon/test_rslib.c
index 848e7eb5da92..75cb1adac884 100644
--- a/lib/reed_solomon/test_rslib.c
+++ b/lib/reed_solomon/test_rslib.c
@@ -183,7 +183,7 @@ static int get_rcw_we(struct rs_control *rs, struct wspace *ws,
do {
/* Must not choose the same location twice */
- errloc = prandom_u32_max(len);
+ errloc = get_random_u32_below(len);
} while (errlocs[errloc] != 0);
errlocs[errloc] = 1;
@@ -194,12 +194,12 @@ static int get_rcw_we(struct rs_control *rs, struct wspace *ws,
for (i = 0; i < eras; i++) {
do {
/* Must not choose the same location twice */
- errloc = prandom_u32_max(len);
+ errloc = get_random_u32_below(len);
} while (errlocs[errloc] != 0);
derrlocs[i] = errloc;
- if (ewsc && prandom_u32_max(2)) {
+ if (ewsc && get_random_u32_below(2)) {
/* Erasure with the symbol intact */
errlocs[errloc] = 2;
} else {
diff --git a/lib/sbitmap.c b/lib/sbitmap.c
index 7280ae8ca88c..1fcede228fa2 100644
--- a/lib/sbitmap.c
+++ b/lib/sbitmap.c
@@ -21,7 +21,7 @@ static int init_alloc_hint(struct sbitmap *sb, gfp_t flags)
int i;
for_each_possible_cpu(i)
- *per_cpu_ptr(sb->alloc_hint, i) = prandom_u32_max(depth);
+ *per_cpu_ptr(sb->alloc_hint, i) = get_random_u32_below(depth);
}
return 0;
}
@@ -33,7 +33,7 @@ static inline unsigned update_alloc_hint_before_get(struct sbitmap *sb,
hint = this_cpu_read(*sb->alloc_hint);
if (unlikely(hint >= depth)) {
- hint = depth ? prandom_u32_max(depth) : 0;
+ hint = depth ? get_random_u32_below(depth) : 0;
this_cpu_write(*sb->alloc_hint, hint);
}
@@ -434,6 +434,8 @@ int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
sbq->wake_batch = sbq_calc_wake_batch(sbq, depth);
atomic_set(&sbq->wake_index, 0);
atomic_set(&sbq->ws_active, 0);
+ atomic_set(&sbq->completion_cnt, 0);
+ atomic_set(&sbq->wakeup_cnt, 0);
sbq->ws = kzalloc_node(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags, node);
if (!sbq->ws) {
@@ -441,40 +443,21 @@ int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
return -ENOMEM;
}
- for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+ for (i = 0; i < SBQ_WAIT_QUEUES; i++)
init_waitqueue_head(&sbq->ws[i].wait);
- atomic_set(&sbq->ws[i].wait_cnt, sbq->wake_batch);
- }
return 0;
}
EXPORT_SYMBOL_GPL(sbitmap_queue_init_node);
-static inline void __sbitmap_queue_update_wake_batch(struct sbitmap_queue *sbq,
- unsigned int wake_batch)
-{
- int i;
-
- if (sbq->wake_batch != wake_batch) {
- WRITE_ONCE(sbq->wake_batch, wake_batch);
- /*
- * Pairs with the memory barrier in sbitmap_queue_wake_up()
- * to ensure that the batch size is updated before the wait
- * counts.
- */
- smp_mb();
- for (i = 0; i < SBQ_WAIT_QUEUES; i++)
- atomic_set(&sbq->ws[i].wait_cnt, 1);
- }
-}
-
static void sbitmap_queue_update_wake_batch(struct sbitmap_queue *sbq,
unsigned int depth)
{
unsigned int wake_batch;
wake_batch = sbq_calc_wake_batch(sbq, depth);
- __sbitmap_queue_update_wake_batch(sbq, wake_batch);
+ if (sbq->wake_batch != wake_batch)
+ WRITE_ONCE(sbq->wake_batch, wake_batch);
}
void sbitmap_queue_recalculate_wake_batch(struct sbitmap_queue *sbq,
@@ -488,7 +471,8 @@ void sbitmap_queue_recalculate_wake_batch(struct sbitmap_queue *sbq,
wake_batch = clamp_val(depth / SBQ_WAIT_QUEUES,
min_batch, SBQ_WAKE_BATCH);
- __sbitmap_queue_update_wake_batch(sbq, wake_batch);
+
+ WRITE_ONCE(sbq->wake_batch, wake_batch);
}
EXPORT_SYMBOL_GPL(sbitmap_queue_recalculate_wake_batch);
@@ -576,106 +560,56 @@ void sbitmap_queue_min_shallow_depth(struct sbitmap_queue *sbq,
}
EXPORT_SYMBOL_GPL(sbitmap_queue_min_shallow_depth);
-static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
+static void __sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr)
{
int i, wake_index;
if (!atomic_read(&sbq->ws_active))
- return NULL;
+ return;
wake_index = atomic_read(&sbq->wake_index);
for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
struct sbq_wait_state *ws = &sbq->ws[wake_index];
- if (waitqueue_active(&ws->wait) && atomic_read(&ws->wait_cnt)) {
- if (wake_index != atomic_read(&sbq->wake_index))
- atomic_set(&sbq->wake_index, wake_index);
- return ws;
- }
-
+ /*
+ * Advance the index before checking the current queue.
+ * It improves fairness, by ensuring the queue doesn't
+ * need to be fully emptied before trying to wake up
+ * from the next one.
+ */
wake_index = sbq_index_inc(wake_index);
+
+ /*
+ * It is sufficient to wake up at least one waiter to
+ * guarantee forward progress.
+ */
+ if (waitqueue_active(&ws->wait) &&
+ wake_up_nr(&ws->wait, nr))
+ break;
}
- return NULL;
+ if (wake_index != atomic_read(&sbq->wake_index))
+ atomic_set(&sbq->wake_index, wake_index);
}
-static bool __sbq_wake_up(struct sbitmap_queue *sbq, int *nr)
+void sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr)
{
- struct sbq_wait_state *ws;
- unsigned int wake_batch;
- int wait_cnt, cur, sub;
- bool ret;
+ unsigned int wake_batch = READ_ONCE(sbq->wake_batch);
+ unsigned int wakeups;
- if (*nr <= 0)
- return false;
+ if (!atomic_read(&sbq->ws_active))
+ return;
- ws = sbq_wake_ptr(sbq);
- if (!ws)
- return false;
+ atomic_add(nr, &sbq->completion_cnt);
+ wakeups = atomic_read(&sbq->wakeup_cnt);
- cur = atomic_read(&ws->wait_cnt);
do {
- /*
- * For concurrent callers of this, callers should call this
- * function again to wakeup a new batch on a different 'ws'.
- */
- if (cur == 0)
- return true;
- sub = min(*nr, cur);
- wait_cnt = cur - sub;
- } while (!atomic_try_cmpxchg(&ws->wait_cnt, &cur, wait_cnt));
-
- /*
- * If we decremented queue without waiters, retry to avoid lost
- * wakeups.
- */
- if (wait_cnt > 0)
- return !waitqueue_active(&ws->wait);
-
- *nr -= sub;
-
- /*
- * When wait_cnt == 0, we have to be particularly careful as we are
- * responsible to reset wait_cnt regardless whether we've actually
- * woken up anybody. But in case we didn't wakeup anybody, we still
- * need to retry.
- */
- ret = !waitqueue_active(&ws->wait);
- wake_batch = READ_ONCE(sbq->wake_batch);
-
- /*
- * Wake up first in case that concurrent callers decrease wait_cnt
- * while waitqueue is empty.
- */
- wake_up_nr(&ws->wait, wake_batch);
+ if (atomic_read(&sbq->completion_cnt) - wakeups < wake_batch)
+ return;
+ } while (!atomic_try_cmpxchg(&sbq->wakeup_cnt,
+ &wakeups, wakeups + wake_batch));
- /*
- * Pairs with the memory barrier in sbitmap_queue_resize() to
- * ensure that we see the batch size update before the wait
- * count is reset.
- *
- * Also pairs with the implicit barrier between decrementing wait_cnt
- * and checking for waitqueue_active() to make sure waitqueue_active()
- * sees result of the wakeup if atomic_dec_return() has seen the result
- * of atomic_set().
- */
- smp_mb__before_atomic();
-
- /*
- * Increase wake_index before updating wait_cnt, otherwise concurrent
- * callers can see valid wait_cnt in old waitqueue, which can cause
- * invalid wakeup on the old waitqueue.
- */
- sbq_index_atomic_inc(&sbq->wake_index);
- atomic_set(&ws->wait_cnt, wake_batch);
-
- return ret || *nr;
-}
-
-void sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr)
-{
- while (__sbq_wake_up(sbq, &nr))
- ;
+ __sbitmap_queue_wake_up(sbq, wake_batch);
}
EXPORT_SYMBOL_GPL(sbitmap_queue_wake_up);
@@ -792,9 +726,7 @@ void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m)
seq_puts(m, "ws={\n");
for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
struct sbq_wait_state *ws = &sbq->ws[i];
-
- seq_printf(m, "\t{.wait_cnt=%d, .wait=%s},\n",
- atomic_read(&ws->wait_cnt),
+ seq_printf(m, "\t{.wait=%s},\n",
waitqueue_active(&ws->wait) ? "active" : "inactive");
}
seq_puts(m, "}\n");
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index c8c3d675845c..a0ad2a7959b5 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -410,6 +410,15 @@ static struct scatterlist *get_next_sg(struct sg_append_table *table,
return new_sg;
}
+static bool pages_are_mergeable(struct page *a, struct page *b)
+{
+ if (page_to_pfn(a) != page_to_pfn(b) + 1)
+ return false;
+ if (!zone_device_pages_have_same_pgmap(a, b))
+ return false;
+ return true;
+}
+
/**
* sg_alloc_append_table_from_pages - Allocate and initialize an append sg
* table from an array of pages
@@ -447,6 +456,7 @@ int sg_alloc_append_table_from_pages(struct sg_append_table *sgt_append,
unsigned int chunks, cur_page, seg_len, i, prv_len = 0;
unsigned int added_nents = 0;
struct scatterlist *s = sgt_append->prv;
+ struct page *last_pg;
/*
* The algorithm below requires max_segment to be aligned to PAGE_SIZE
@@ -460,21 +470,17 @@ int sg_alloc_append_table_from_pages(struct sg_append_table *sgt_append,
return -EOPNOTSUPP;
if (sgt_append->prv) {
- unsigned long paddr =
- (page_to_pfn(sg_page(sgt_append->prv)) * PAGE_SIZE +
- sgt_append->prv->offset + sgt_append->prv->length) /
- PAGE_SIZE;
-
if (WARN_ON(offset))
return -EINVAL;
/* Merge contiguous pages into the last SG */
prv_len = sgt_append->prv->length;
- while (n_pages && page_to_pfn(pages[0]) == paddr) {
+ last_pg = sg_page(sgt_append->prv);
+ while (n_pages && pages_are_mergeable(last_pg, pages[0])) {
if (sgt_append->prv->length + PAGE_SIZE > max_segment)
break;
sgt_append->prv->length += PAGE_SIZE;
- paddr++;
+ last_pg = pages[0];
pages++;
n_pages--;
}
@@ -488,7 +494,7 @@ int sg_alloc_append_table_from_pages(struct sg_append_table *sgt_append,
for (i = 1; i < n_pages; i++) {
seg_len += PAGE_SIZE;
if (seg_len >= max_segment ||
- page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
+ !pages_are_mergeable(pages[i], pages[i - 1])) {
chunks++;
seg_len = 0;
}
@@ -504,8 +510,7 @@ int sg_alloc_append_table_from_pages(struct sg_append_table *sgt_append,
for (j = cur_page + 1; j < n_pages; j++) {
seg_len += PAGE_SIZE;
if (seg_len >= max_segment ||
- page_to_pfn(pages[j]) !=
- page_to_pfn(pages[j - 1]) + 1)
+ !pages_are_mergeable(pages[j], pages[j - 1]))
break;
}
diff --git a/lib/slub_kunit.c b/lib/slub_kunit.c
index 7a0564d7cb7a..d4a3730b08fa 100644
--- a/lib/slub_kunit.c
+++ b/lib/slub_kunit.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <kunit/test.h>
+#include <kunit/test-bug.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -9,10 +10,25 @@
static struct kunit_resource resource;
static int slab_errors;
+/*
+ * Wrapper function for kmem_cache_create(), which reduces 2 parameters:
+ * 'align' and 'ctor', and sets SLAB_SKIP_KFENCE flag to avoid getting an
+ * object from kfence pool, where the operation could be caught by both
+ * our test and kfence sanity check.
+ */
+static struct kmem_cache *test_kmem_cache_create(const char *name,
+ unsigned int size, slab_flags_t flags)
+{
+ struct kmem_cache *s = kmem_cache_create(name, size, 0,
+ (flags | SLAB_NO_USER_FLAGS), NULL);
+ s->flags |= SLAB_SKIP_KFENCE;
+ return s;
+}
+
static void test_clobber_zone(struct kunit *test)
{
- struct kmem_cache *s = kmem_cache_create("TestSlub_RZ_alloc", 64, 0,
- SLAB_RED_ZONE|SLAB_NO_USER_FLAGS, NULL);
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_alloc", 64,
+ SLAB_RED_ZONE);
u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
kasan_disable_current();
@@ -29,8 +45,8 @@ static void test_clobber_zone(struct kunit *test)
#ifndef CONFIG_KASAN
static void test_next_pointer(struct kunit *test)
{
- struct kmem_cache *s = kmem_cache_create("TestSlub_next_ptr_free", 64, 0,
- SLAB_POISON|SLAB_NO_USER_FLAGS, NULL);
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_next_ptr_free",
+ 64, SLAB_POISON);
u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
unsigned long tmp;
unsigned long *ptr_addr;
@@ -74,8 +90,8 @@ static void test_next_pointer(struct kunit *test)
static void test_first_word(struct kunit *test)
{
- struct kmem_cache *s = kmem_cache_create("TestSlub_1th_word_free", 64, 0,
- SLAB_POISON|SLAB_NO_USER_FLAGS, NULL);
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_1th_word_free",
+ 64, SLAB_POISON);
u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
kmem_cache_free(s, p);
@@ -89,8 +105,8 @@ static void test_first_word(struct kunit *test)
static void test_clobber_50th_byte(struct kunit *test)
{
- struct kmem_cache *s = kmem_cache_create("TestSlub_50th_word_free", 64, 0,
- SLAB_POISON|SLAB_NO_USER_FLAGS, NULL);
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_50th_word_free",
+ 64, SLAB_POISON);
u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
kmem_cache_free(s, p);
@@ -105,8 +121,8 @@ static void test_clobber_50th_byte(struct kunit *test)
static void test_clobber_redzone_free(struct kunit *test)
{
- struct kmem_cache *s = kmem_cache_create("TestSlub_RZ_free", 64, 0,
- SLAB_RED_ZONE|SLAB_NO_USER_FLAGS, NULL);
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_free", 64,
+ SLAB_RED_ZONE);
u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
kasan_disable_current();
@@ -120,6 +136,27 @@ static void test_clobber_redzone_free(struct kunit *test)
kmem_cache_destroy(s);
}
+static void test_kmalloc_redzone_access(struct kunit *test)
+{
+ struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_kmalloc", 32,
+ SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE);
+ u8 *p = kmalloc_trace(s, GFP_KERNEL, 18);
+
+ kasan_disable_current();
+
+ /* Suppress the -Warray-bounds warning */
+ OPTIMIZER_HIDE_VAR(p);
+ p[18] = 0xab;
+ p[19] = 0xab;
+
+ validate_slab_cache(s);
+ KUNIT_EXPECT_EQ(test, 2, slab_errors);
+
+ kasan_enable_current();
+ kmem_cache_free(s, p);
+ kmem_cache_destroy(s);
+}
+
static int test_init(struct kunit *test)
{
slab_errors = 0;
@@ -139,6 +176,7 @@ static struct kunit_case test_cases[] = {
#endif
KUNIT_CASE(test_clobber_redzone_free),
+ KUNIT_CASE(test_kmalloc_redzone_access),
{}
};
diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c
index 86fadd3ba08c..41d3447bc3b4 100644
--- a/lib/test-string_helpers.c
+++ b/lib/test-string_helpers.c
@@ -587,7 +587,7 @@ static int __init test_string_helpers_init(void)
for (i = 0; i < UNESCAPE_ALL_MASK + 1; i++)
test_string_unescape("unescape", i, false);
test_string_unescape("unescape inplace",
- prandom_u32_max(UNESCAPE_ANY + 1), true);
+ get_random_u32_below(UNESCAPE_ANY + 1), true);
/* Without dictionary */
for (i = 0; i < ESCAPE_ALL_MASK + 1; i++)
diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c
index e0381b3ec410..1fb56cf5e5ce 100644
--- a/lib/test_fprobe.c
+++ b/lib/test_fprobe.c
@@ -144,10 +144,7 @@ static unsigned long get_ftrace_location(void *func)
static int fprobe_test_init(struct kunit *test)
{
- do {
- rand1 = get_random_u32();
- } while (rand1 <= div_factor);
-
+ rand1 = get_random_u32_above(div_factor);
target = fprobe_selftest_target;
target2 = fprobe_selftest_target2;
target_ip = get_ftrace_location(target);
diff --git a/lib/test_hexdump.c b/lib/test_hexdump.c
index 0927f44cd478..b916801f23a8 100644
--- a/lib/test_hexdump.c
+++ b/lib/test_hexdump.c
@@ -149,7 +149,7 @@ static void __init test_hexdump(size_t len, int rowsize, int groupsize,
static void __init test_hexdump_set(int rowsize, bool ascii)
{
size_t d = min_t(size_t, sizeof(data_b), rowsize);
- size_t len = prandom_u32_max(d) + 1;
+ size_t len = get_random_u32_inclusive(1, d);
test_hexdump(len, rowsize, 4, ascii);
test_hexdump(len, rowsize, 2, ascii);
@@ -208,11 +208,11 @@ static void __init test_hexdump_overflow(size_t buflen, size_t len,
static void __init test_hexdump_overflow_set(size_t buflen, bool ascii)
{
unsigned int i = 0;
- int rs = (prandom_u32_max(2) + 1) * 16;
+ int rs = get_random_u32_inclusive(1, 2) * 16;
do {
int gs = 1 << i;
- size_t len = prandom_u32_max(rs) + gs;
+ size_t len = get_random_u32_below(rs) + gs;
test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, ascii);
} while (i++ < 3);
@@ -223,11 +223,11 @@ static int __init test_hexdump_init(void)
unsigned int i;
int rowsize;
- rowsize = (prandom_u32_max(2) + 1) * 16;
+ rowsize = get_random_u32_inclusive(1, 2) * 16;
for (i = 0; i < 16; i++)
test_hexdump_set(rowsize, false);
- rowsize = (prandom_u32_max(2) + 1) * 16;
+ rowsize = get_random_u32_inclusive(1, 2) * 16;
for (i = 0; i < 16; i++)
test_hexdump_set(rowsize, true);
diff --git a/lib/test_kprobes.c b/lib/test_kprobes.c
index eeb1d728d974..1c95e5719802 100644
--- a/lib/test_kprobes.c
+++ b/lib/test_kprobes.c
@@ -339,10 +339,7 @@ static int kprobes_test_init(struct kunit *test)
stacktrace_target = kprobe_stacktrace_target;
internal_target = kprobe_stacktrace_internal_target;
stacktrace_driver = kprobe_stacktrace_driver;
-
- do {
- rand1 = get_random_u32();
- } while (rand1 <= div_factor);
+ rand1 = get_random_u32_above(div_factor);
return 0;
}
diff --git a/lib/test_list_sort.c b/lib/test_list_sort.c
index 19ff229b9c3a..cc5f335f29b5 100644
--- a/lib/test_list_sort.c
+++ b/lib/test_list_sort.c
@@ -71,7 +71,7 @@ static void list_sort_test(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, el);
/* force some equivalencies */
- el->value = prandom_u32_max(TEST_LIST_LEN / 3);
+ el->value = get_random_u32_below(TEST_LIST_LEN / 3);
el->serial = i;
el->poison1 = TEST_POISON1;
el->poison2 = TEST_POISON2;
diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c
index 4f69e009a015..f425f169ef08 100644
--- a/lib/test_maple_tree.c
+++ b/lib/test_maple_tree.c
@@ -1,24 +1,35 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* test_maple_tree.c: Test the maple tree API
- * Copyright (c) 2018 Liam R. Howlett
+ * Copyright (c) 2018-2022 Oracle Corporation
* Author: Liam R. Howlett <Liam.Howlett@Oracle.com>
+ *
+ * Any tests that only require the interface of the tree.
*/
#include <linux/maple_tree.h>
#include <linux/module.h>
-#include <stdlib.h>
-#include <time.h>
#define MTREE_ALLOC_MAX 0x2000000000000Ul
+#ifndef CONFIG_DEBUG_MAPLE_TREE
#define CONFIG_DEBUG_MAPLE_TREE
+#endif
#define CONFIG_MAPLE_SEARCH
+#define MAPLE_32BIT (MAPLE_NODE_SLOTS > 31)
+
/* #define BENCH_SLOT_STORE */
/* #define BENCH_NODE_STORE */
/* #define BENCH_AWALK */
/* #define BENCH_WALK */
/* #define BENCH_MT_FOR_EACH */
/* #define BENCH_FORK */
+
+#ifdef __KERNEL__
+#define mt_set_non_kernel(x) do {} while (0)
+#define mt_zero_nr_tallocated(x) do {} while (0)
+#else
+#define cond_resched() do {} while (0)
+#endif
static
int mtree_insert_index(struct maple_tree *mt, unsigned long index, gfp_t gfp)
{
@@ -65,6 +76,7 @@ static void *mtree_test_erase(struct maple_tree *mt, unsigned long index)
return mtree_erase(mt, index);
}
+#if defined(CONFIG_64BIT)
static noinline void check_mtree_alloc_range(struct maple_tree *mt,
unsigned long start, unsigned long end, unsigned long size,
unsigned long expected, int eret, void *ptr)
@@ -98,6 +110,7 @@ static noinline void check_mtree_alloc_rrange(struct maple_tree *mt,
MT_BUG_ON(mt, result != expected);
}
+#endif
static noinline void check_load(struct maple_tree *mt, unsigned long index,
void *ptr)
@@ -150,12 +163,6 @@ static noinline void check_insert(struct maple_tree *mt, unsigned long index,
MT_BUG_ON(mt, ret != 0);
}
-static noinline void check_erase(struct maple_tree *mt, unsigned long index,
- void *ptr)
-{
- MT_BUG_ON(mt, mtree_test_erase(mt, index) != ptr);
-}
-
static noinline void check_dup_insert(struct maple_tree *mt,
unsigned long index, void *ptr)
{
@@ -172,41 +179,6 @@ void check_index_load(struct maple_tree *mt, unsigned long index)
return check_load(mt, index, xa_mk_value(index & LONG_MAX));
}
-static noinline void check_nomem(struct maple_tree *mt)
-{
- MA_STATE(ms, mt, 1, 1);
-
- MT_BUG_ON(mt, !mtree_empty(mt));
- /* Ensure no bypassing of allocation failures */
- mt_set_non_kernel(0);
-
- /* Storing something at 1 requires memory allocation */
- MT_BUG_ON(mt, mtree_insert(mt, 1, &ms, GFP_ATOMIC) != -ENOMEM);
- /* Storing something at 0 does not */
- MT_BUG_ON(mt, mtree_insert(mt, 0, &ms, GFP_ATOMIC) != 0);
-
- /*
- * Simulate two threads racing; the first one fails to allocate
- * memory to insert an entry at 1, then the second one succeeds
- * in allocating memory to insert an entry at 2. The first one
- * then needs to free the node it allocated. LeakSanitizer will
- * notice this, as will the 'nr_allocated' debugging aid in the
- * userspace test suite.
- */
- mtree_lock(mt);
- mas_store(&ms, &ms); /* insert 1 -> &ms, fails. */
- MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM));
- mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */
- MT_BUG_ON(mt, ms.node != MAS_START);
- mtree_unlock(mt);
- MT_BUG_ON(mt, mtree_insert(mt, 2, mt, GFP_KERNEL) != 0);
- mtree_lock(mt);
- mas_store(&ms, &ms); /* insert 1 -> &ms */
- mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */
- mtree_unlock(mt);
- mtree_destroy(mt);
-}
-
static inline int not_empty(struct maple_node *node)
{
int i;
@@ -221,350 +193,6 @@ static inline int not_empty(struct maple_node *node)
return 0;
}
-static noinline void check_new_node(struct maple_tree *mt)
-{
-
- struct maple_node *mn, *mn2, *mn3;
- struct maple_alloc *smn;
- struct maple_node *nodes[100];
- int i, j, total;
-
- MA_STATE(mas, mt, 0, 0);
-
- /* Try allocating 3 nodes */
- mtree_lock(mt);
- /* request 3 nodes to be allocated. */
- mas_node_count(&mas, 3);
- /* Allocation request of 3. */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 3);
- /* Allocate failed. */
- MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
-
- MT_BUG_ON(mt, mas_allocated(&mas) != 3);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, mas.alloc == NULL);
- MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
- mas_push_node(&mas, mn);
- mas_nomem(&mas, GFP_KERNEL); /* free */
- mtree_unlock(mt);
-
-
- /* Try allocating 1 node, then 2 more */
- mtree_lock(mt);
- /* Set allocation request to 1. */
- mas_set_alloc_req(&mas, 1);
- /* Check Allocation request of 1. */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
- mas_set_err(&mas, -ENOMEM);
- /* Validate allocation request. */
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- /* Eat the requested node. */
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, mn->slot[0] != NULL);
- MT_BUG_ON(mt, mn->slot[1] != NULL);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
-
- ma_free_rcu(mn);
- mas.node = MAS_START;
- mas_nomem(&mas, GFP_KERNEL);
- /* Allocate 3 nodes, will fail. */
- mas_node_count(&mas, 3);
- /* Drop the lock and allocate 3 nodes. */
- mas_nomem(&mas, GFP_KERNEL);
- /* Ensure 3 are allocated. */
- MT_BUG_ON(mt, mas_allocated(&mas) != 3);
- /* Allocation request of 0. */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 0);
-
- MT_BUG_ON(mt, mas.alloc == NULL);
- MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
- MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
- /* Ensure we counted 3. */
- MT_BUG_ON(mt, mas_allocated(&mas) != 3);
- /* Free. */
- mas_nomem(&mas, GFP_KERNEL);
-
- /* Set allocation request to 1. */
- mas_set_alloc_req(&mas, 1);
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
- mas_set_err(&mas, -ENOMEM);
- /* Validate allocation request. */
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- MT_BUG_ON(mt, mas_allocated(&mas) != 1);
- /* Check the node is only one node. */
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, mn->slot[0] != NULL);
- MT_BUG_ON(mt, mn->slot[1] != NULL);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- mas_push_node(&mas, mn);
- MT_BUG_ON(mt, mas_allocated(&mas) != 1);
- MT_BUG_ON(mt, mas.alloc->node_count);
-
- mas_set_alloc_req(&mas, 2); /* request 2 more. */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 2);
- mas_set_err(&mas, -ENOMEM);
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- MT_BUG_ON(mt, mas_allocated(&mas) != 3);
- MT_BUG_ON(mt, mas.alloc == NULL);
- MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
- MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
- for (i = 2; i >= 0; i--) {
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != i);
- MT_BUG_ON(mt, !mn);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- }
-
- total = 64;
- mas_set_alloc_req(&mas, total); /* request 2 more. */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != total);
- mas_set_err(&mas, -ENOMEM);
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- for (i = total; i > 0; i--) {
- unsigned int e = 0; /* expected node_count */
-
- if (i >= 35)
- e = i - 35;
- else if (i >= 5)
- e = i - 5;
- else if (i >= 2)
- e = i - 2;
- MT_BUG_ON(mt, mas.alloc->node_count != e);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mas_allocated(&mas) != i - 1);
- MT_BUG_ON(mt, !mn);
- ma_free_rcu(mn);
- }
-
- total = 100;
- for (i = 1; i < total; i++) {
- mas_set_alloc_req(&mas, i);
- mas_set_err(&mas, -ENOMEM);
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- for (j = i; j > 0; j--) {
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
- MT_BUG_ON(mt, !mn);
- MT_BUG_ON(mt, not_empty(mn));
- mas_push_node(&mas, mn);
- MT_BUG_ON(mt, mas_allocated(&mas) != j);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
- ma_free_rcu(mn);
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
-
- mas_set_alloc_req(&mas, i);
- mas_set_err(&mas, -ENOMEM);
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- for (j = 0; j <= i/2; j++) {
- MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
- nodes[j] = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
- }
-
- while (j) {
- j--;
- mas_push_node(&mas, nodes[j]);
- MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != i);
- for (j = 0; j <= i/2; j++) {
- MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
- }
- MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL));
-
- }
-
- /* Set allocation request. */
- total = 500;
- mas_node_count(&mas, total);
- /* Drop the lock and allocate the nodes. */
- mas_nomem(&mas, GFP_KERNEL);
- MT_BUG_ON(mt, !mas.alloc);
- i = 1;
- smn = mas.alloc;
- while (i < total) {
- for (j = 0; j < MAPLE_ALLOC_SLOTS; j++) {
- i++;
- MT_BUG_ON(mt, !smn->slot[j]);
- if (i == total)
- break;
- }
- smn = smn->slot[0]; /* next. */
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != total);
- mas_nomem(&mas, GFP_KERNEL); /* Free. */
-
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- for (i = 1; i < 128; i++) {
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
- for (j = i; j > 0; j--) { /*Free the requests */
- mn = mas_pop_node(&mas); /* get the next node. */
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- }
-
- for (i = 1; i < MAPLE_NODE_MASK + 1; i++) {
- MA_STATE(mas2, mt, 0, 0);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
- for (j = 1; j <= i; j++) { /* Move the allocations to mas2 */
- mn = mas_pop_node(&mas); /* get the next node. */
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, not_empty(mn));
- mas_push_node(&mas2, mn);
- MT_BUG_ON(mt, mas_allocated(&mas2) != j);
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- MT_BUG_ON(mt, mas_allocated(&mas2) != i);
-
- for (j = i; j > 0; j--) { /*Free the requests */
- MT_BUG_ON(mt, mas_allocated(&mas2) != j);
- mn = mas_pop_node(&mas2); /* get the next node. */
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- }
- MT_BUG_ON(mt, mas_allocated(&mas2) != 0);
- }
-
-
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 1); /* Request */
- MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
- MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
-
- mn = mas_pop_node(&mas); /* get the next node. */
- MT_BUG_ON(mt, mn == NULL);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS);
- MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 2);
-
- mas_push_node(&mas, mn);
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
- MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
-
- /* Check the limit of pop/push/pop */
- mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 2); /* Request */
- MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
- MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
- MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
- MT_BUG_ON(mt, mas_alloc_req(&mas));
- MT_BUG_ON(mt, mas.alloc->node_count);
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
- MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
- mas_push_node(&mas, mn);
- MT_BUG_ON(mt, mas.alloc->node_count);
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- for (i = 1; i <= MAPLE_ALLOC_SLOTS + 1; i++) {
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, not_empty(mn));
- ma_free_rcu(mn);
- }
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
-
-
- for (i = 3; i < MAPLE_NODE_MASK * 3; i++) {
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mn = mas_pop_node(&mas); /* get the next node. */
- mas_push_node(&mas, mn); /* put it back */
- mas_destroy(&mas);
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mn = mas_pop_node(&mas); /* get the next node. */
- mn2 = mas_pop_node(&mas); /* get the next node. */
- mas_push_node(&mas, mn); /* put them back */
- mas_push_node(&mas, mn2);
- mas_destroy(&mas);
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mn = mas_pop_node(&mas); /* get the next node. */
- mn2 = mas_pop_node(&mas); /* get the next node. */
- mn3 = mas_pop_node(&mas); /* get the next node. */
- mas_push_node(&mas, mn); /* put them back */
- mas_push_node(&mas, mn2);
- mas_push_node(&mas, mn3);
- mas_destroy(&mas);
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mn = mas_pop_node(&mas); /* get the next node. */
- ma_free_rcu(mn);
- mas_destroy(&mas);
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, i); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mn = mas_pop_node(&mas); /* get the next node. */
- ma_free_rcu(mn);
- mn = mas_pop_node(&mas); /* get the next node. */
- ma_free_rcu(mn);
- mn = mas_pop_node(&mas); /* get the next node. */
- ma_free_rcu(mn);
- mas_destroy(&mas);
- }
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, 5); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- MT_BUG_ON(mt, mas_allocated(&mas) != 5);
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, 10); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mas.node = MAS_START;
- MT_BUG_ON(mt, mas_allocated(&mas) != 10);
- mas_destroy(&mas);
-
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, MAPLE_ALLOC_SLOTS - 1); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS - 1);
- mas.node = MA_ERROR(-ENOMEM);
- mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */
- mas_nomem(&mas, GFP_KERNEL); /* Fill request */
- mas.node = MAS_START;
- MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1);
- mas_destroy(&mas);
-
- mtree_unlock(mt);
-}
static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max,
bool verbose)
@@ -588,6 +216,7 @@ static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max,
}
check_load(mt, max + 1, NULL);
+#ifndef __KERNEL__
if (verbose) {
rcu_barrier();
mt_dump(mt);
@@ -595,6 +224,7 @@ static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max,
__func__, max, mt_get_alloc_size()/1024, mt_nr_allocated(),
mt_nr_tallocated());
}
+#endif
}
static noinline void check_seq(struct maple_tree *mt, unsigned long max,
@@ -614,6 +244,8 @@ static noinline void check_seq(struct maple_tree *mt, unsigned long max,
MT_BUG_ON(mt, !mt_height(mt));
check_load(mt, i + 1, NULL);
}
+
+#ifndef __KERNEL__
if (verbose) {
rcu_barrier();
mt_dump(mt);
@@ -621,6 +253,7 @@ static noinline void check_seq(struct maple_tree *mt, unsigned long max,
max, mt_get_alloc_size()/1024, mt_nr_allocated(),
mt_nr_tallocated());
}
+#endif
}
static noinline void check_lb_not_empty(struct maple_tree *mt)
@@ -651,10 +284,15 @@ static noinline void check_lower_bound_split(struct maple_tree *mt)
static noinline void check_upper_bound_split(struct maple_tree *mt)
{
unsigned long i, j;
- unsigned long huge = 4000UL * 1000 * 1000;
+ unsigned long huge;
MT_BUG_ON(mt, !mtree_empty(mt));
+ if (MAPLE_32BIT)
+ huge = 2147483647UL;
+ else
+ huge = 4000UL * 1000 * 1000;
+
i = 4096;
while (i < huge) {
check_insert(mt, i, (void *) i);
@@ -687,6 +325,7 @@ static noinline void check_rev_find(struct maple_tree *mt)
mtree_store_range(mt, i*10, i*10 + 5,
xa_mk_value(i), GFP_KERNEL);
+ rcu_read_lock();
mas_set(&mas, 1000);
val = mas_find_rev(&mas, 1000);
MT_BUG_ON(mt, val != xa_mk_value(100));
@@ -712,13 +351,15 @@ static noinline void check_rev_find(struct maple_tree *mt)
MT_BUG_ON(mt, val != xa_mk_value(0));
val = mas_find_rev(&mas, 0);
MT_BUG_ON(mt, val != NULL);
+ rcu_read_unlock();
}
static noinline void check_find(struct maple_tree *mt)
{
unsigned long val = 0;
- unsigned long count = 20;
+ unsigned long count;
unsigned long max;
+ unsigned long top;
unsigned long last = 0, index = 0;
void *entry, *entry2;
@@ -727,6 +368,18 @@ static noinline void check_find(struct maple_tree *mt)
/* Insert 0. */
MT_BUG_ON(mt, mtree_insert_index(mt, val++, GFP_KERNEL));
+#if defined(CONFIG_64BIT)
+ top = 4398046511104UL;
+#else
+ top = ULONG_MAX;
+#endif
+
+ if (MAPLE_32BIT) {
+ count = 15;
+ } else {
+ count = 20;
+ }
+
for (int i = 0; i <= count; i++) {
if (val != 64)
MT_BUG_ON(mt, mtree_insert_index(mt, val, GFP_KERNEL));
@@ -805,12 +458,17 @@ static noinline void check_find(struct maple_tree *mt)
index = 0;
MT_BUG_ON(mt, mtree_insert_index(mt, ULONG_MAX, GFP_KERNEL));
mt_for_each(mt, entry, index, ULONG_MAX) {
- if (val == 4398046511104)
- MT_BUG_ON(mt, entry !=
- xa_mk_value(ULONG_MAX & LONG_MAX));
+ if (val == top)
+ MT_BUG_ON(mt, entry != xa_mk_value(LONG_MAX));
else
MT_BUG_ON(mt, xa_mk_value(val) != entry);
- val <<= 2;
+
+ /* Workaround for 32bit */
+ if ((val << 2) < val)
+ val = ULONG_MAX;
+ else
+ val <<= 2;
+
if (val == 64) /* Skip zero entry. */
val <<= 2;
/* For zero check. */
@@ -842,11 +500,16 @@ static noinline void check_find(struct maple_tree *mt)
mas_for_each(&mas, entry, ULONG_MAX) {
if (val == 64)
MT_BUG_ON(mt, entry != XA_ZERO_ENTRY);
- else if (val == 4398046511104)
- MT_BUG_ON(mt, entry != xa_mk_value(ULONG_MAX & LONG_MAX));
+ else if (val == top)
+ MT_BUG_ON(mt, entry != xa_mk_value(LONG_MAX));
else
MT_BUG_ON(mt, xa_mk_value(val) != entry);
- val <<= 2;
+
+ /* Workaround for 32bit */
+ if ((val << 2) < val)
+ val = ULONG_MAX;
+ else
+ val <<= 2;
/* For zero check. */
if (!val)
@@ -951,33847 +614,8 @@ static noinline void check_find_2(struct maple_tree *mt)
/*MT_BUG_ON(mt, !mtree_empty(mt)); */
}
-#define erase_ptr(i) entry[i%2]
-#define erase_check_load(mt, i) check_load(mt, set[i], entry[i%2])
-#define erase_check_insert(mt, i) check_insert(mt, set[i], entry[i%2])
-#define erase_check_erase(mt, i) check_erase(mt, set[i], entry[i%2])
-
-static noinline void check_erase_testset(struct maple_tree *mt)
-{
- unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
- 1001, 1002, 1003, 1005, 0,
- 6003, 6002, 6008, 6012, 6015,
- 7003, 7002, 7008, 7012, 7015,
- 8003, 8002, 8008, 8012, 8015,
- 9003, 9002, 9008, 9012, 9015,
- 10003, 10002, 10008, 10012, 10015,
- 11003, 11002, 11008, 11012, 11015,
- 12003, 12002, 12008, 12012, 12015,
- 13003, 13002, 13008, 13012, 13015,
- 14003, 14002, 14008, 14012, 14015,
- 15003, 15002, 15008, 15012, 15015,
- };
-
-
- void *ptr = &set;
- void *entry[2] = { ptr, mt };
- void *root_node;
-
-
- rcu_register_thread();
- mt_set_in_rcu(mt);
- for (int i = 0; i < 4; i++)
- erase_check_insert(mt, i);
- for (int i = 0; i < 4; i++)
- erase_check_load(mt, i);
-
- mt_set_non_kernel(2);
- erase_check_erase(mt, 1);
- erase_check_load(mt, 0);
- check_load(mt, set[1], NULL);
- for (int i = 2; i < 4; i++)
- erase_check_load(mt, i);
-
-
- erase_check_erase(mt, 2);
- erase_check_load(mt, 0);
- check_load(mt, set[1], NULL);
- check_load(mt, set[2], NULL);
-
- erase_check_insert(mt, 1);
- erase_check_insert(mt, 2);
-
- for (int i = 0; i < 4; i++)
- erase_check_load(mt, i);
-
- /* Check erase and load without an allocation. */
- erase_check_load(mt, 3);
- erase_check_erase(mt, 1);
- erase_check_load(mt, 0);
- check_load(mt, set[1], NULL);
- for (int i = 2; i < 4; i++)
- erase_check_load(mt, i);
-
- /*
- * Set the newly erased node. This will produce a different allocated
- * node to avoid busy slots.
- */
- root_node = mt->ma_root;
- erase_check_insert(mt, 1);
-
- erase_check_load(mt, 0);
- check_load(mt, 5016, NULL);
- erase_check_load(mt, 1);
- check_load(mt, 5013, NULL);
- erase_check_load(mt, 2);
- check_load(mt, 5018, NULL);
- erase_check_load(mt, 3);
-
- erase_check_erase(mt, 2); /* erase 5017 to check append */
- erase_check_load(mt, 0);
- check_load(mt, 5016, NULL);
- erase_check_load(mt, 1);
- check_load(mt, 5013, NULL);
- check_load(mt, set[2], NULL);
- check_load(mt, 5018, NULL);
-
- erase_check_load(mt, 3);
-
- root_node = mt->ma_root;
- erase_check_insert(mt, 2);
-
- erase_check_load(mt, 0);
- check_load(mt, 5016, NULL);
- erase_check_load(mt, 1);
- check_load(mt, 5013, NULL);
- erase_check_load(mt, 2);
- check_load(mt, 5018, NULL);
- erase_check_load(mt, 3);
-
- mt_set_non_kernel(1);
- erase_check_erase(mt, 2); /* erase 5017 to check append */
- erase_check_load(mt, 0);
- check_load(mt, 5016, NULL);
- check_load(mt, set[2], NULL);
- erase_check_erase(mt, 0); /* erase 5015 to check append */
- check_load(mt, set[0], NULL);
- check_load(mt, 5016, NULL);
- erase_check_insert(mt, 4); /* 1000 < Should not split. */
- check_load(mt, set[0], NULL);
- check_load(mt, 5016, NULL);
- erase_check_load(mt, 1);
- check_load(mt, 5013, NULL);
- check_load(mt, set[2], NULL);
- check_load(mt, 5018, NULL);
- erase_check_load(mt, 4);
- check_load(mt, 999, NULL);
- check_load(mt, 1001, NULL);
- erase_check_load(mt, 4);
- if (mt_in_rcu(mt))
- MT_BUG_ON(mt, root_node == mt->ma_root);
- else
- MT_BUG_ON(mt, root_node != mt->ma_root);
-
- /* Should not have split. */
- MT_BUG_ON(mt, !mte_is_leaf(mt->ma_root));
-
-
- /* Coalesce testing */
- erase_check_insert(mt, 0);
- erase_check_insert(mt, 2);
-
- for (int i = 5; i < 25; i++) {
- erase_check_insert(mt, i);
- for (int j = i; j >= 0; j--)
- erase_check_load(mt, j);
- }
-
- erase_check_erase(mt, 14); /*6015 */
- for (int i = 0; i < 25; i++) {
- if (i == 14)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
- erase_check_erase(mt, 16); /*7002 */
- for (int i = 0; i < 25; i++) {
- if (i == 16 || i == 14)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
-
- mt_set_non_kernel(1);
- erase_check_erase(mt, 13); /*6012 */
- for (int i = 0; i < 25; i++) {
- if (i == 16 || i == 14 || i == 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- erase_check_erase(mt, 15); /*7003 */
- for (int i = 0; i < 25; i++) {
- if (i <= 16 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- mt_set_non_kernel(2);
- erase_check_erase(mt, 17); /*7008 *should* cause coalesce. */
- for (int i = 0; i < 25; i++) {
- if (i <= 17 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- erase_check_erase(mt, 18); /*7012 */
- for (int i = 0; i < 25; i++) {
- if (i <= 18 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- mt_set_non_kernel(2);
- erase_check_erase(mt, 19); /*7015 */
- for (int i = 0; i < 25; i++) {
- if (i <= 19 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- erase_check_erase(mt, 20); /*8003 */
- for (int i = 0; i < 25; i++) {
- if (i <= 20 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- erase_check_erase(mt, 21); /*8002 */
- for (int i = 0; i < 25; i++) {
- if (i <= 21 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- mt_set_non_kernel(2);
- erase_check_erase(mt, 22); /*8008 */
- for (int i = 0; i < 25; i++) {
- if (i <= 22 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
- for (int i = 23; i < 25; i++)
- erase_check_erase(mt, i);
-
- for (int i = 0; i < 25; i++) {
- if (i <= 25 && i >= 13)
- check_load(mt, set[i], NULL);
- else
- erase_check_load(mt, i);
- }
-
- /* Shrinking tree test. */
-
- for (int i = 13; i < ARRAY_SIZE(set); i++)
- erase_check_insert(mt, i);
-
- mt_set_non_kernel(99);
- for (int i = 18; i < ARRAY_SIZE(set); i++) {
- erase_check_erase(mt, i);
- for (int j = 0; j < ARRAY_SIZE(set); j++) {
- if (j < 18 || j > i)
- erase_check_load(mt, j);
- else
- check_load(mt, set[j], NULL);
- }
- }
- mt_set_non_kernel(35);
- for (int i = 0; i < 18; i++) {
- erase_check_erase(mt, i);
- for (int j = 0; j < ARRAY_SIZE(set); j++) {
- if (j < 18 && j > i)
- erase_check_load(mt, j);
- else
- check_load(mt, set[j], NULL);
- }
- }
- erase_check_insert(mt, 8);
- erase_check_insert(mt, 9);
- erase_check_erase(mt, 8);
- rcu_unregister_thread();
-}
-
-#define erase_check_store_range(mt, a, i, ptr) mtree_test_store_range(mt, \
- a[(i)], a[(i + 1)], ptr)
-#define STORE 1
-#define SNULL 2
-#define ERASE 3
-#define ec_type_str(x) \
- (((x) == STORE) ? \
- "STORE" : \
- (((x) == SNULL) ? \
- "SNULL" : "ERASE") \
- )
-#define check_erase2_debug 0
-void *mas_next(struct ma_state *mas, unsigned long max);
-
-/* Calculate the overwritten entries. */
-int mas_ce2_over_count(struct ma_state *mas_start, struct ma_state *mas_end,
- void *s_entry, unsigned long s_min,
- void *e_entry, unsigned long e_max,
- unsigned long *set, int i, bool null_entry)
-{
- int count = 0, span = 0;
- unsigned long retry = 0;
- void *entry;
- struct ma_state tmp;
-
-
- /* count slots */
- memcpy(&tmp, mas_start, sizeof(tmp));
- entry = mas_next(&tmp, mas_end->last);
- while (entry) {
- BUG_ON(retry > 50); /* stop infinite retry on testing. */
- if (xa_is_zero(s_entry)) {
- retry++;
- continue;
- }
- count++;
- span++;
- entry = mas_next(&tmp, mas_end->last);
- }
-
- if (null_entry) {
- /* Check splitting end. */
- if (e_entry && (e_max > mas_end->last))
- count--;
-
- /* check overwrite of entire start */
- if (s_entry && (s_min == mas_start->index))
- count++;
- } else { /* !null_entry (store) */
- bool esplit = e_max > mas_end->last;
- bool ssplit = s_min != mas_start->index;
-
- if (s_entry && e_entry) {
- if (esplit && ssplit)
- count--;
- else if (ssplit)
- count--;
- else if (esplit) {
- if (span)
- count--;
- }
- } else if (s_entry && !e_entry) {
- if (ssplit)
- count--;
- } else if (!s_entry && e_entry) {
- if (esplit)
- count--;
- count--;
- } else {
- count--;
- }
- }
- return count;
-}
-
-/*
- * mas_node_walk() - Walk a maple node to offset of the index.
- * @mas: The maple state
- * @type: The maple node type
- * @*range_min: Pointer to store the minimum range of the offset
- * @*range_max: Pointer to store the maximum range of the offset
- *
- * The offset will be stored in the maple state.
- *
- */
-static inline void mas_node_walk(struct ma_state *mas, struct maple_node *node,
- enum maple_type type, unsigned long *range_min,
- unsigned long *range_max)
-
-{
- unsigned long *pivots;
- unsigned char count;
- unsigned long prev, max;
- unsigned char offset;
- unsigned long index;
-
- if (unlikely(ma_is_dense(type))) {
- (*range_max) = (*range_min) = mas->index;
- if (unlikely(ma_dead_node(node)))
- return;
-
- mas->offset = mas->index = mas->min;
- return;
- }
-
- pivots = ma_pivots(node, type);
- max = pivots[0];
- if (unlikely(ma_dead_node(node)))
- return;
-
- offset = 0;
- prev = mas->min;
- index = mas->index;
- if (unlikely(index <= max))
- goto offset_zero;
-
- count = mt_pivots[type];
- while (++offset < count) {
- prev = max;
- max = pivots[offset];
- if (unlikely(ma_dead_node(node)))
- return;
-
- if (index <= max)
- goto offset_found;
- else if (unlikely(!max))
- goto mas_max;
- }
-
- prev = max;
-mas_max:
- max = mas->max;
-offset_found:
- prev++;
-offset_zero:
- mas->offset = offset;
- if (ma_is_leaf(type)) {
- *range_max = max;
- *range_min = prev;
- } else {
- mas->max = max;
- mas->min = prev;
- }
-}
-
-/*
- * mas_descend_walk(): Locates a value and sets the mas->node and slot
- * accordingly. range_min and range_max are set to the range which the entry is
- * valid.
- * @mas: The maple state
- * @*range_min: A pointer to store the minimum of the range
- * @*range_max: A pointer to store the maximum of the range
- *
- * Check mas->node is still valid on return of any value.
- *
- * Return: true if pointing to a valid node and offset. False otherwise.
- */
-static inline bool mas_descend_walk(struct ma_state *mas,
- unsigned long *range_min, unsigned long *range_max)
-{
- struct maple_enode *next;
- struct maple_node *node;
- enum maple_type type;
-
- next = mas->node;
- while (true) {
- node = mte_to_node(next);
- type = mte_node_type(next);
- mas_node_walk(mas, node, type, range_min, range_max);
- next = mas_slot(mas, ma_slots(node, type), mas->offset);
- if (unlikely(ma_dead_node(node)))
- return false;
-
- if (unlikely(ma_is_leaf(type)))
- return true;
-
- /* Descend. */
- mas->node = next;
- }
- return false;
-}
-
-/*
- * mas_tree_walk() - Walk to @mas->index and set the range values.
- * @mas: The maple state.
- * @*range_min: The minimum range to be set.
- * @*range_max: The maximum range to be set.
- *
- * Ranges are only valid if there is a valid entry at @mas->index.
- *
- * Return: True if a value exists, false otherwise.
- */
-static inline bool mas_tree_walk(struct ma_state *mas, unsigned long *range_min,
- unsigned long *range_max)
-{
- bool ret;
-
-retry:
- ret = false;
- mas_start(mas);
- if (mas_is_none(mas))
- goto not_found;
-
- if (mas_is_ptr(mas)) {
- *range_min = *range_max = 0;
- if (!mas->index)
- return true;
-
- goto not_found;
- }
-
- ret = mas_descend_walk(mas, range_min, range_max);
- if (unlikely(mte_dead_node(mas->node))) {
- mas->node = MAS_START;
- goto retry;
- }
-
- return ret;
-
-not_found:
- mas->offset = MAPLE_NODE_SLOTS;
- return false;
-}
-
-static inline void *mas_range_load(struct ma_state *mas,
- unsigned long *range_min, unsigned long *range_max)
-
-{
- void *entry = NULL;
- unsigned long index = mas->index;
-
- if (mas_is_none(mas) || mas_is_paused(mas))
- mas->node = MAS_START;
-retry:
- if (mas_tree_walk(mas, range_min, range_max))
- if (unlikely(mas->node == MAS_ROOT))
- return mas_root(mas);
-
- if (likely(mas->offset != MAPLE_NODE_SLOTS))
- entry = mas_get_slot(mas, mas->offset);
-
- if (mas_dead_node(mas, index))
- goto retry;
-
- return entry;
-}
-static noinline void check_erase2_testset(struct maple_tree *mt,
- unsigned long *set, unsigned long size)
-{
- int entry_count = 0;
- int check = 0;
- void *foo;
- unsigned long addr = 0;
- void *s_entry = NULL, *e_entry = NULL;
-
- MA_STATE(mas, mt, 0, 0);
-
- for (int i = 0; i < size; i += 3) {
- unsigned long s_min, s_max;
- unsigned long e_min, e_max;
- void *value = NULL;
-
- MA_STATE(mas_start, mt, set[i+1], set[i+1]);
- MA_STATE(mas_end, mt, set[i+2], set[i+2]);
- mt_set_non_kernel(127);
-#if check_erase2_debug
- pr_err("%s: %d %s %lu - %lu\n", __func__, i,
- ec_type_str(set[i]),
- set[i+1], set[i+2]);
-#endif
- s_entry = mas_range_load(&mas_start, &s_min, &s_max);
- e_entry = mas_range_load(&mas_end, &e_min, &e_max);
-
- switch (set[i]) {
- case SNULL:
- if ((s_min == set[i+1]) && (s_max == set[i+2])) {
- if (s_entry)
- entry_count--;
- } else if ((s_min != set[i+1]) && (s_max != set[i+2])) {
- entry_count++;
- } else if ((mas_start.node != mas_end.node) ||
- (mas_start.offset != mas_end.offset)) {
- entry_count -=
- mas_ce2_over_count(&mas_start, &mas_end,
- s_entry, s_min,
- e_entry, e_max, set, i,
- true);
- }
-
-
- erase_check_store_range(mt, set, i + 1, value);
- break;
- case STORE:
- value = xa_mk_value(set[i + 1]);
- if (mas_start.offset > mt_slot_count(mas_start.node)) {
- entry_count++; /* appending an entry. */
- } else if ((s_min == e_min) && (s_max == e_max)) {
- if (!entry_count)
- entry_count++;
-
- else if (s_entry) {
- if (e_max > mas_end.last)
- entry_count++;
-
- if (s_min < mas_start.index)
- entry_count++;
-
- } else {
- entry_count++;
- }
- } else {
- entry_count -=
- mas_ce2_over_count(&mas_start, &mas_end,
- s_entry, s_min,
- e_entry, e_max, set, i,
- false);
- }
-
- erase_check_store_range(mt, set, i + 1, value);
- break;
- case ERASE:
- if (!s_entry)
- break;
- check_erase(mt, set[i+1], xa_mk_value(set[i+1]));
- entry_count--;
- break;
- }
- mt_validate(mt);
- if (entry_count)
- MT_BUG_ON(mt, !mt_height(mt));
-#if check_erase2_debug > 1
- mt_dump(mt);
-#endif
-#if check_erase2_debug
- pr_err("Done\n");
-#endif
-
- check = 0;
- addr = 0;
- mt_for_each(mt, foo, addr, ULONG_MAX) {
- check++;
-#if check_erase2_debug > 2
- pr_err("mt: %lu -> %p (%d)\n", addr+1, foo, check);
-#endif
- if (check > entry_count)
- break;
- }
-
-#if check_erase2_debug > 2
- pr_err("mt_for_each %d and count %d\n", check, entry_count);
-#endif
-
- MT_BUG_ON(mt, check != entry_count);
-
- check = 0;
- addr = 0;
- mas_reset(&mas);
- mas.index = 0;
- rcu_read_lock();
- mas_for_each(&mas, foo, ULONG_MAX) {
- if (xa_is_zero(foo)) {
- if (addr == mas.index) {
- mt_dump(mas.tree);
- pr_err("retry failed %lu - %lu\n",
- mas.index, mas.last);
- MT_BUG_ON(mt, 1);
- }
- addr = mas.index;
- continue;
- }
-#if check_erase2_debug > 2
- pr_err("mas: %lu -> %p\n", mas.index, foo);
-#endif
- check++;
- if (check > entry_count)
- break;
- }
- rcu_read_unlock();
-#if check_erase2_debug > 2
- pr_err("mas_for_each %d and count %d\n", check, entry_count);
- mt_validate(mt);
-#endif
-
- MT_BUG_ON(mt, check != entry_count);
-
- MT_BUG_ON(mt, mtree_load(mas.tree, 0) != NULL);
- }
-}
-
-
-/* These tests were pulled from kvm tests. */
-static noinline void check_erase2_sets(struct maple_tree *mt)
-{
- void *entry;
- unsigned long start = 0;
- unsigned long set[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140721266458624, 140737488351231,
-ERASE, 140721266458624, 140737488351231,
-STORE, 140721266458624, 140721266462719,
-STORE, 94735788949504, 94735789121535,
-ERASE, 94735788949504, 94735789121535,
-STORE, 94735788949504, 94735788965887,
-STORE, 94735788965888, 94735789121535,
-ERASE, 94735788965888, 94735789121535,
-STORE, 94735788965888, 94735789068287,
-STORE, 94735789068288, 94735789109247,
-STORE, 94735789109248, 94735789121535,
-STORE, 140253902692352, 140253902864383,
-ERASE, 140253902692352, 140253902864383,
-STORE, 140253902692352, 140253902696447,
-STORE, 140253902696448, 140253902864383,
- };
- unsigned long set2[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140735933583360, 140737488351231,
-ERASE, 140735933583360, 140737488351231,
-STORE, 140735933583360, 140735933587455,
-STORE, 94811003260928, 94811003432959,
-ERASE, 94811003260928, 94811003432959,
-STORE, 94811003260928, 94811003277311,
-STORE, 94811003277312, 94811003432959,
-ERASE, 94811003277312, 94811003432959,
-STORE, 94811003277312, 94811003379711,
-STORE, 94811003379712, 94811003420671,
-STORE, 94811003420672, 94811003432959,
-STORE, 140277094653952, 140277094825983,
-ERASE, 140277094653952, 140277094825983,
-STORE, 140277094653952, 140277094658047,
-STORE, 140277094658048, 140277094825983,
-ERASE, 140277094658048, 140277094825983,
-STORE, 140277094658048, 140277094780927,
-STORE, 140277094780928, 140277094813695,
-STORE, 140277094813696, 140277094821887,
-STORE, 140277094821888, 140277094825983,
-STORE, 140735933906944, 140735933911039,
- };
- unsigned long set3[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140735790264320, 140737488351231,
-ERASE, 140735790264320, 140737488351231,
-STORE, 140735790264320, 140735790268415,
-STORE, 94016597282816, 94016597454847,
-ERASE, 94016597282816, 94016597454847,
-STORE, 94016597282816, 94016597299199,
-STORE, 94016597299200, 94016597454847,
-ERASE, 94016597299200, 94016597454847,
-STORE, 94016597299200, 94016597401599,
-STORE, 94016597401600, 94016597442559,
-STORE, 94016597442560, 94016597454847,
-STORE, 140496959283200, 140496959455231,
-ERASE, 140496959283200, 140496959455231,
-STORE, 140496959283200, 140496959287295,
-STORE, 140496959287296, 140496959455231,
-ERASE, 140496959287296, 140496959455231,
-STORE, 140496959287296, 140496959410175,
-STORE, 140496959410176, 140496959442943,
-STORE, 140496959442944, 140496959451135,
-STORE, 140496959451136, 140496959455231,
-STORE, 140735791718400, 140735791722495,
-STORE, 140735791706112, 140735791718399,
-STORE, 47135835713536, 47135835721727,
-STORE, 47135835721728, 47135835729919,
-STORE, 47135835729920, 47135835893759,
-ERASE, 47135835729920, 47135835893759,
-STORE, 47135835729920, 47135835742207,
-STORE, 47135835742208, 47135835893759,
-STORE, 47135835840512, 47135835893759,
-STORE, 47135835742208, 47135835840511,
-ERASE, 47135835742208, 47135835840511,
-STORE, 47135835742208, 47135835840511,
-STORE, 47135835885568, 47135835893759,
-STORE, 47135835840512, 47135835885567,
-ERASE, 47135835840512, 47135835885567,
-STORE, 47135835840512, 47135835893759,
-ERASE, 47135835840512, 47135835893759,
-STORE, 47135835840512, 47135835885567,
-STORE, 47135835885568, 47135835893759,
- };
-
- unsigned long set4[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140728251703296, 140737488351231,
-ERASE, 140728251703296, 140737488351231,
-STORE, 140728251703296, 140728251707391,
-STORE, 94668429205504, 94668429377535,
-ERASE, 94668429205504, 94668429377535,
-STORE, 94668429205504, 94668429221887,
-STORE, 94668429221888, 94668429377535,
-ERASE, 94668429221888, 94668429377535,
-STORE, 94668429221888, 94668429324287,
-STORE, 94668429324288, 94668429365247,
-STORE, 94668429365248, 94668429377535,
-STORE, 47646523273216, 47646523445247,
-ERASE, 47646523273216, 47646523445247,
-STORE, 47646523273216, 47646523277311,
-STORE, 47646523277312, 47646523445247,
-ERASE, 47646523277312, 47646523445247,
-STORE, 47646523277312, 47646523400191,
- };
-
- unsigned long set5[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140726874062848, 140737488351231,
-ERASE, 140726874062848, 140737488351231,
-STORE, 140726874062848, 140726874066943,
-STORE, 94248892870656, 94248893042687,
-ERASE, 94248892870656, 94248893042687,
-STORE, 94248892870656, 94248892887039,
-STORE, 94248892887040, 94248893042687,
-ERASE, 94248892887040, 94248893042687,
-STORE, 94248892887040, 94248892989439,
-STORE, 94248892989440, 94248893030399,
-STORE, 94248893030400, 94248893042687,
-STORE, 47884786266112, 47884786438143,
-ERASE, 47884786266112, 47884786438143,
-STORE, 47884786266112, 47884786270207,
-STORE, 47884786270208, 47884786438143,
-ERASE, 47884786270208, 47884786438143,
-STORE, 47884786270208, 47884786393087,
-STORE, 47884786393088, 47884786425855,
-STORE, 47884786425856, 47884786434047,
-STORE, 47884786434048, 47884786438143,
-STORE, 140726874513408, 140726874517503,
-STORE, 140726874501120, 140726874513407,
-STORE, 47884786438144, 47884786446335,
-STORE, 47884786446336, 47884786454527,
-STORE, 47884786454528, 47884786618367,
-ERASE, 47884786454528, 47884786618367,
-STORE, 47884786454528, 47884786466815,
-STORE, 47884786466816, 47884786618367,
-STORE, 47884786565120, 47884786618367,
-STORE, 47884786466816, 47884786565119,
-ERASE, 47884786466816, 47884786565119,
-STORE, 47884786466816, 47884786565119,
-STORE, 47884786610176, 47884786618367,
-STORE, 47884786565120, 47884786610175,
-ERASE, 47884786565120, 47884786610175,
-STORE, 47884786565120, 47884786618367,
-ERASE, 47884786565120, 47884786618367,
-STORE, 47884786565120, 47884786610175,
-STORE, 47884786610176, 47884786618367,
-ERASE, 47884786610176, 47884786618367,
-STORE, 47884786610176, 47884786618367,
-STORE, 47884786618368, 47884789669887,
-STORE, 47884787163136, 47884789669887,
-STORE, 47884786618368, 47884787163135,
-ERASE, 47884787163136, 47884789669887,
-STORE, 47884787163136, 47884789448703,
-STORE, 47884789448704, 47884789669887,
-STORE, 47884788858880, 47884789448703,
-STORE, 47884787163136, 47884788858879,
-ERASE, 47884787163136, 47884788858879,
-STORE, 47884787163136, 47884788858879,
-STORE, 47884789444608, 47884789448703,
-STORE, 47884788858880, 47884789444607,
-ERASE, 47884788858880, 47884789444607,
-STORE, 47884788858880, 47884789444607,
-STORE, 47884789653504, 47884789669887,
-STORE, 47884789448704, 47884789653503,
-ERASE, 47884789448704, 47884789653503,
-STORE, 47884789448704, 47884789653503,
-ERASE, 47884789653504, 47884789669887,
-STORE, 47884789653504, 47884789669887,
-STORE, 47884789669888, 47884791508991,
-STORE, 47884789809152, 47884791508991,
-STORE, 47884789669888, 47884789809151,
-ERASE, 47884789809152, 47884791508991,
-STORE, 47884789809152, 47884791468031,
-STORE, 47884791468032, 47884791508991,
-STORE, 47884791152640, 47884791468031,
-STORE, 47884789809152, 47884791152639,
-ERASE, 47884789809152, 47884791152639,
-STORE, 47884789809152, 47884791152639,
-STORE, 47884791463936, 47884791468031,
-STORE, 47884791152640, 47884791463935,
-ERASE, 47884791152640, 47884791463935,
-STORE, 47884791152640, 47884791463935,
-STORE, 47884791492608, 47884791508991,
-STORE, 47884791468032, 47884791492607,
-ERASE, 47884791468032, 47884791492607,
-STORE, 47884791468032, 47884791492607,
-ERASE, 47884791492608, 47884791508991,
-STORE, 47884791492608, 47884791508991,
-STORE, 47884791508992, 47884791644159,
-ERASE, 47884791508992, 47884791644159,
-STORE, 47884791508992, 47884791533567,
-STORE, 47884791533568, 47884791644159,
-STORE, 47884791595008, 47884791644159,
-STORE, 47884791533568, 47884791595007,
-ERASE, 47884791533568, 47884791595007,
-STORE, 47884791533568, 47884791595007,
-STORE, 47884791619584, 47884791644159,
-STORE, 47884791595008, 47884791619583,
-ERASE, 47884791595008, 47884791619583,
-STORE, 47884791595008, 47884791644159,
-ERASE, 47884791595008, 47884791644159,
-STORE, 47884791595008, 47884791619583,
-STORE, 47884791619584, 47884791644159,
-STORE, 47884791627776, 47884791644159,
-STORE, 47884791619584, 47884791627775,
-ERASE, 47884791619584, 47884791627775,
-STORE, 47884791619584, 47884791627775,
-ERASE, 47884791627776, 47884791644159,
-STORE, 47884791627776, 47884791644159,
-STORE, 47884791644160, 47884791664639,
-ERASE, 47884791644160, 47884791664639,
-STORE, 47884791644160, 47884791648255,
-STORE, 47884791648256, 47884791664639,
-STORE, 47884791652352, 47884791664639,
-STORE, 47884791648256, 47884791652351,
-ERASE, 47884791648256, 47884791652351,
-STORE, 47884791648256, 47884791652351,
-STORE, 47884791656448, 47884791664639,
-STORE, 47884791652352, 47884791656447,
-ERASE, 47884791652352, 47884791656447,
-STORE, 47884791652352, 47884791664639,
-ERASE, 47884791652352, 47884791664639,
-STORE, 47884791652352, 47884791656447,
-STORE, 47884791656448, 47884791664639,
-ERASE, 47884791656448, 47884791664639,
-STORE, 47884791656448, 47884791664639,
-STORE, 47884791664640, 47884791672831,
-ERASE, 47884791468032, 47884791492607,
-STORE, 47884791468032, 47884791484415,
-STORE, 47884791484416, 47884791492607,
-ERASE, 47884791656448, 47884791664639,
-STORE, 47884791656448, 47884791660543,
-STORE, 47884791660544, 47884791664639,
-ERASE, 47884791619584, 47884791627775,
-STORE, 47884791619584, 47884791623679,
-STORE, 47884791623680, 47884791627775,
- };
-
- unsigned long set6[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140722999021568, 140737488351231,
-ERASE, 140722999021568, 140737488351231,
-STORE, 140722999021568, 140722999025663,
-STORE, 94901500268544, 94901500440575,
-ERASE, 94901500268544, 94901500440575,
-STORE, 94901500268544, 94901500284927,
-STORE, 94901500284928, 94901500440575,
-ERASE, 94901500284928, 94901500440575,
-STORE, 94901500284928, 94901500387327,
-STORE, 94901500387328, 94901500428287,
-STORE, 94901500428288, 94901500440575,
-STORE, 47430426660864, 47430426832895,
-ERASE, 47430426660864, 47430426832895,
-STORE, 47430426660864, 47430426664959,
-STORE, 47430426664960, 47430426832895,
-ERASE, 47430426664960, 47430426832895,
-STORE, 47430426664960, 47430426787839,
-STORE, 47430426787840, 47430426820607,
-STORE, 47430426820608, 47430426828799,
-STORE, 47430426828800, 47430426832895,
-STORE, 140722999115776, 140722999119871,
-STORE, 140722999103488, 140722999115775,
-STORE, 47430426832896, 47430426841087,
-STORE, 47430426841088, 47430426849279,
-STORE, 47430426849280, 47430427013119,
-ERASE, 47430426849280, 47430427013119,
-STORE, 47430426849280, 47430426861567,
-STORE, 47430426861568, 47430427013119,
-STORE, 47430426959872, 47430427013119,
-STORE, 47430426861568, 47430426959871,
-ERASE, 47430426861568, 47430426959871,
-STORE, 47430426861568, 47430426959871,
-STORE, 47430427004928, 47430427013119,
-STORE, 47430426959872, 47430427004927,
-ERASE, 47430426959872, 47430427004927,
-STORE, 47430426959872, 47430427013119,
-ERASE, 47430426959872, 47430427013119,
-STORE, 47430426959872, 47430427004927,
-STORE, 47430427004928, 47430427013119,
-ERASE, 47430427004928, 47430427013119,
-STORE, 47430427004928, 47430427013119,
-STORE, 47430427013120, 47430430064639,
-STORE, 47430427557888, 47430430064639,
-STORE, 47430427013120, 47430427557887,
-ERASE, 47430427557888, 47430430064639,
-STORE, 47430427557888, 47430429843455,
-STORE, 47430429843456, 47430430064639,
-STORE, 47430429253632, 47430429843455,
-STORE, 47430427557888, 47430429253631,
-ERASE, 47430427557888, 47430429253631,
-STORE, 47430427557888, 47430429253631,
-STORE, 47430429839360, 47430429843455,
-STORE, 47430429253632, 47430429839359,
-ERASE, 47430429253632, 47430429839359,
-STORE, 47430429253632, 47430429839359,
-STORE, 47430430048256, 47430430064639,
-STORE, 47430429843456, 47430430048255,
-ERASE, 47430429843456, 47430430048255,
-STORE, 47430429843456, 47430430048255,
-ERASE, 47430430048256, 47430430064639,
-STORE, 47430430048256, 47430430064639,
-STORE, 47430430064640, 47430431903743,
-STORE, 47430430203904, 47430431903743,
-STORE, 47430430064640, 47430430203903,
-ERASE, 47430430203904, 47430431903743,
-STORE, 47430430203904, 47430431862783,
-STORE, 47430431862784, 47430431903743,
-STORE, 47430431547392, 47430431862783,
-STORE, 47430430203904, 47430431547391,
-ERASE, 47430430203904, 47430431547391,
-STORE, 47430430203904, 47430431547391,
-STORE, 47430431858688, 47430431862783,
-STORE, 47430431547392, 47430431858687,
-ERASE, 47430431547392, 47430431858687,
-STORE, 47430431547392, 47430431858687,
-STORE, 47430431887360, 47430431903743,
-STORE, 47430431862784, 47430431887359,
-ERASE, 47430431862784, 47430431887359,
-STORE, 47430431862784, 47430431887359,
-ERASE, 47430431887360, 47430431903743,
-STORE, 47430431887360, 47430431903743,
-STORE, 47430431903744, 47430432038911,
-ERASE, 47430431903744, 47430432038911,
-STORE, 47430431903744, 47430431928319,
-STORE, 47430431928320, 47430432038911,
-STORE, 47430431989760, 47430432038911,
-STORE, 47430431928320, 47430431989759,
-ERASE, 47430431928320, 47430431989759,
-STORE, 47430431928320, 47430431989759,
-STORE, 47430432014336, 47430432038911,
-STORE, 47430431989760, 47430432014335,
-ERASE, 47430431989760, 47430432014335,
-STORE, 47430431989760, 47430432038911,
-ERASE, 47430431989760, 47430432038911,
-STORE, 47430431989760, 47430432014335,
-STORE, 47430432014336, 47430432038911,
-STORE, 47430432022528, 47430432038911,
-STORE, 47430432014336, 47430432022527,
-ERASE, 47430432014336, 47430432022527,
-STORE, 47430432014336, 47430432022527,
-ERASE, 47430432022528, 47430432038911,
-STORE, 47430432022528, 47430432038911,
-STORE, 47430432038912, 47430432059391,
-ERASE, 47430432038912, 47430432059391,
-STORE, 47430432038912, 47430432043007,
-STORE, 47430432043008, 47430432059391,
-STORE, 47430432047104, 47430432059391,
-STORE, 47430432043008, 47430432047103,
-ERASE, 47430432043008, 47430432047103,
-STORE, 47430432043008, 47430432047103,
-STORE, 47430432051200, 47430432059391,
-STORE, 47430432047104, 47430432051199,
-ERASE, 47430432047104, 47430432051199,
-STORE, 47430432047104, 47430432059391,
-ERASE, 47430432047104, 47430432059391,
-STORE, 47430432047104, 47430432051199,
-STORE, 47430432051200, 47430432059391,
-ERASE, 47430432051200, 47430432059391,
-STORE, 47430432051200, 47430432059391,
-STORE, 47430432059392, 47430432067583,
-ERASE, 47430431862784, 47430431887359,
-STORE, 47430431862784, 47430431879167,
-STORE, 47430431879168, 47430431887359,
-ERASE, 47430432051200, 47430432059391,
-STORE, 47430432051200, 47430432055295,
-STORE, 47430432055296, 47430432059391,
-ERASE, 47430432014336, 47430432022527,
-STORE, 47430432014336, 47430432018431,
-STORE, 47430432018432, 47430432022527,
- };
- unsigned long set7[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140729808330752, 140737488351231,
-ERASE, 140729808330752, 140737488351231,
-STORE, 140729808330752, 140729808334847,
-STORE, 94629632020480, 94629632192511,
-ERASE, 94629632020480, 94629632192511,
-STORE, 94629632020480, 94629632036863,
-STORE, 94629632036864, 94629632192511,
-ERASE, 94629632036864, 94629632192511,
-STORE, 94629632036864, 94629632139263,
-STORE, 94629632139264, 94629632180223,
-STORE, 94629632180224, 94629632192511,
-STORE, 47439981776896, 47439981948927,
-ERASE, 47439981776896, 47439981948927,
-STORE, 47439981776896, 47439981780991,
-STORE, 47439981780992, 47439981948927,
-ERASE, 47439981780992, 47439981948927,
-STORE, 47439981780992, 47439981903871,
-STORE, 47439981903872, 47439981936639,
-STORE, 47439981936640, 47439981944831,
-STORE, 47439981944832, 47439981948927,
-STORE, 140729808474112, 140729808478207,
-STORE, 140729808461824, 140729808474111,
-STORE, 47439981948928, 47439981957119,
-STORE, 47439981957120, 47439981965311,
-STORE, 47439981965312, 47439982129151,
-ERASE, 47439981965312, 47439982129151,
-STORE, 47439981965312, 47439981977599,
-STORE, 47439981977600, 47439982129151,
-STORE, 47439982075904, 47439982129151,
-STORE, 47439981977600, 47439982075903,
-ERASE, 47439981977600, 47439982075903,
-STORE, 47439981977600, 47439982075903,
-STORE, 47439982120960, 47439982129151,
-STORE, 47439982075904, 47439982120959,
-ERASE, 47439982075904, 47439982120959,
-STORE, 47439982075904, 47439982129151,
-ERASE, 47439982075904, 47439982129151,
-STORE, 47439982075904, 47439982120959,
-STORE, 47439982120960, 47439982129151,
-ERASE, 47439982120960, 47439982129151,
-STORE, 47439982120960, 47439982129151,
-STORE, 47439982129152, 47439985180671,
-STORE, 47439982673920, 47439985180671,
-STORE, 47439982129152, 47439982673919,
-ERASE, 47439982673920, 47439985180671,
-STORE, 47439982673920, 47439984959487,
-STORE, 47439984959488, 47439985180671,
-STORE, 47439984369664, 47439984959487,
-STORE, 47439982673920, 47439984369663,
-ERASE, 47439982673920, 47439984369663,
-STORE, 47439982673920, 47439984369663,
-STORE, 47439984955392, 47439984959487,
-STORE, 47439984369664, 47439984955391,
-ERASE, 47439984369664, 47439984955391,
-STORE, 47439984369664, 47439984955391,
-STORE, 47439985164288, 47439985180671,
-STORE, 47439984959488, 47439985164287,
-ERASE, 47439984959488, 47439985164287,
-STORE, 47439984959488, 47439985164287,
-ERASE, 47439985164288, 47439985180671,
-STORE, 47439985164288, 47439985180671,
-STORE, 47439985180672, 47439987019775,
-STORE, 47439985319936, 47439987019775,
-STORE, 47439985180672, 47439985319935,
-ERASE, 47439985319936, 47439987019775,
-STORE, 47439985319936, 47439986978815,
-STORE, 47439986978816, 47439987019775,
-STORE, 47439986663424, 47439986978815,
-STORE, 47439985319936, 47439986663423,
-ERASE, 47439985319936, 47439986663423,
-STORE, 47439985319936, 47439986663423,
-STORE, 47439986974720, 47439986978815,
-STORE, 47439986663424, 47439986974719,
-ERASE, 47439986663424, 47439986974719,
-STORE, 47439986663424, 47439986974719,
-STORE, 47439987003392, 47439987019775,
-STORE, 47439986978816, 47439987003391,
-ERASE, 47439986978816, 47439987003391,
-STORE, 47439986978816, 47439987003391,
-ERASE, 47439987003392, 47439987019775,
-STORE, 47439987003392, 47439987019775,
-STORE, 47439987019776, 47439987154943,
-ERASE, 47439987019776, 47439987154943,
-STORE, 47439987019776, 47439987044351,
-STORE, 47439987044352, 47439987154943,
-STORE, 47439987105792, 47439987154943,
-STORE, 47439987044352, 47439987105791,
-ERASE, 47439987044352, 47439987105791,
-STORE, 47439987044352, 47439987105791,
-STORE, 47439987130368, 47439987154943,
-STORE, 47439987105792, 47439987130367,
-ERASE, 47439987105792, 47439987130367,
-STORE, 47439987105792, 47439987154943,
-ERASE, 47439987105792, 47439987154943,
-STORE, 47439987105792, 47439987130367,
-STORE, 47439987130368, 47439987154943,
-STORE, 47439987138560, 47439987154943,
-STORE, 47439987130368, 47439987138559,
-ERASE, 47439987130368, 47439987138559,
-STORE, 47439987130368, 47439987138559,
-ERASE, 47439987138560, 47439987154943,
-STORE, 47439987138560, 47439987154943,
-STORE, 47439987154944, 47439987175423,
-ERASE, 47439987154944, 47439987175423,
-STORE, 47439987154944, 47439987159039,
-STORE, 47439987159040, 47439987175423,
-STORE, 47439987163136, 47439987175423,
-STORE, 47439987159040, 47439987163135,
-ERASE, 47439987159040, 47439987163135,
-STORE, 47439987159040, 47439987163135,
-STORE, 47439987167232, 47439987175423,
-STORE, 47439987163136, 47439987167231,
-ERASE, 47439987163136, 47439987167231,
-STORE, 47439987163136, 47439987175423,
-ERASE, 47439987163136, 47439987175423,
-STORE, 47439987163136, 47439987167231,
-STORE, 47439987167232, 47439987175423,
-ERASE, 47439987167232, 47439987175423,
-STORE, 47439987167232, 47439987175423,
-STORE, 47439987175424, 47439987183615,
-ERASE, 47439986978816, 47439987003391,
-STORE, 47439986978816, 47439986995199,
-STORE, 47439986995200, 47439987003391,
-ERASE, 47439987167232, 47439987175423,
-STORE, 47439987167232, 47439987171327,
-STORE, 47439987171328, 47439987175423,
-ERASE, 47439987130368, 47439987138559,
-STORE, 47439987130368, 47439987134463,
-STORE, 47439987134464, 47439987138559,
- };
- unsigned long set8[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140722482974720, 140737488351231,
-ERASE, 140722482974720, 140737488351231,
-STORE, 140722482974720, 140722482978815,
-STORE, 94121505034240, 94121505206271,
-ERASE, 94121505034240, 94121505206271,
-STORE, 94121505034240, 94121505050623,
-STORE, 94121505050624, 94121505206271,
-ERASE, 94121505050624, 94121505206271,
-STORE, 94121505050624, 94121505153023,
-STORE, 94121505153024, 94121505193983,
-STORE, 94121505193984, 94121505206271,
-STORE, 47708483284992, 47708483457023,
-ERASE, 47708483284992, 47708483457023,
-STORE, 47708483284992, 47708483289087,
-STORE, 47708483289088, 47708483457023,
-ERASE, 47708483289088, 47708483457023,
-STORE, 47708483289088, 47708483411967,
-STORE, 47708483411968, 47708483444735,
-STORE, 47708483444736, 47708483452927,
-STORE, 47708483452928, 47708483457023,
-STORE, 140722483142656, 140722483146751,
-STORE, 140722483130368, 140722483142655,
-STORE, 47708483457024, 47708483465215,
-STORE, 47708483465216, 47708483473407,
-STORE, 47708483473408, 47708483637247,
-ERASE, 47708483473408, 47708483637247,
-STORE, 47708483473408, 47708483485695,
-STORE, 47708483485696, 47708483637247,
-STORE, 47708483584000, 47708483637247,
-STORE, 47708483485696, 47708483583999,
-ERASE, 47708483485696, 47708483583999,
-STORE, 47708483485696, 47708483583999,
-STORE, 47708483629056, 47708483637247,
-STORE, 47708483584000, 47708483629055,
-ERASE, 47708483584000, 47708483629055,
-STORE, 47708483584000, 47708483637247,
-ERASE, 47708483584000, 47708483637247,
-STORE, 47708483584000, 47708483629055,
-STORE, 47708483629056, 47708483637247,
-ERASE, 47708483629056, 47708483637247,
-STORE, 47708483629056, 47708483637247,
-STORE, 47708483637248, 47708486688767,
-STORE, 47708484182016, 47708486688767,
-STORE, 47708483637248, 47708484182015,
-ERASE, 47708484182016, 47708486688767,
-STORE, 47708484182016, 47708486467583,
-STORE, 47708486467584, 47708486688767,
-STORE, 47708485877760, 47708486467583,
-STORE, 47708484182016, 47708485877759,
-ERASE, 47708484182016, 47708485877759,
-STORE, 47708484182016, 47708485877759,
-STORE, 47708486463488, 47708486467583,
-STORE, 47708485877760, 47708486463487,
-ERASE, 47708485877760, 47708486463487,
-STORE, 47708485877760, 47708486463487,
-STORE, 47708486672384, 47708486688767,
-STORE, 47708486467584, 47708486672383,
-ERASE, 47708486467584, 47708486672383,
-STORE, 47708486467584, 47708486672383,
-ERASE, 47708486672384, 47708486688767,
-STORE, 47708486672384, 47708486688767,
-STORE, 47708486688768, 47708488527871,
-STORE, 47708486828032, 47708488527871,
-STORE, 47708486688768, 47708486828031,
-ERASE, 47708486828032, 47708488527871,
-STORE, 47708486828032, 47708488486911,
-STORE, 47708488486912, 47708488527871,
-STORE, 47708488171520, 47708488486911,
-STORE, 47708486828032, 47708488171519,
-ERASE, 47708486828032, 47708488171519,
-STORE, 47708486828032, 47708488171519,
-STORE, 47708488482816, 47708488486911,
-STORE, 47708488171520, 47708488482815,
-ERASE, 47708488171520, 47708488482815,
-STORE, 47708488171520, 47708488482815,
-STORE, 47708488511488, 47708488527871,
-STORE, 47708488486912, 47708488511487,
-ERASE, 47708488486912, 47708488511487,
-STORE, 47708488486912, 47708488511487,
-ERASE, 47708488511488, 47708488527871,
-STORE, 47708488511488, 47708488527871,
-STORE, 47708488527872, 47708488663039,
-ERASE, 47708488527872, 47708488663039,
-STORE, 47708488527872, 47708488552447,
-STORE, 47708488552448, 47708488663039,
-STORE, 47708488613888, 47708488663039,
-STORE, 47708488552448, 47708488613887,
-ERASE, 47708488552448, 47708488613887,
-STORE, 47708488552448, 47708488613887,
-STORE, 47708488638464, 47708488663039,
-STORE, 47708488613888, 47708488638463,
-ERASE, 47708488613888, 47708488638463,
-STORE, 47708488613888, 47708488663039,
-ERASE, 47708488613888, 47708488663039,
-STORE, 47708488613888, 47708488638463,
-STORE, 47708488638464, 47708488663039,
-STORE, 47708488646656, 47708488663039,
-STORE, 47708488638464, 47708488646655,
-ERASE, 47708488638464, 47708488646655,
-STORE, 47708488638464, 47708488646655,
-ERASE, 47708488646656, 47708488663039,
-STORE, 47708488646656, 47708488663039,
-STORE, 47708488663040, 47708488683519,
-ERASE, 47708488663040, 47708488683519,
-STORE, 47708488663040, 47708488667135,
-STORE, 47708488667136, 47708488683519,
-STORE, 47708488671232, 47708488683519,
-STORE, 47708488667136, 47708488671231,
-ERASE, 47708488667136, 47708488671231,
-STORE, 47708488667136, 47708488671231,
-STORE, 47708488675328, 47708488683519,
-STORE, 47708488671232, 47708488675327,
-ERASE, 47708488671232, 47708488675327,
-STORE, 47708488671232, 47708488683519,
-ERASE, 47708488671232, 47708488683519,
-STORE, 47708488671232, 47708488675327,
-STORE, 47708488675328, 47708488683519,
-ERASE, 47708488675328, 47708488683519,
-STORE, 47708488675328, 47708488683519,
-STORE, 47708488683520, 47708488691711,
-ERASE, 47708488486912, 47708488511487,
-STORE, 47708488486912, 47708488503295,
-STORE, 47708488503296, 47708488511487,
-ERASE, 47708488675328, 47708488683519,
-STORE, 47708488675328, 47708488679423,
-STORE, 47708488679424, 47708488683519,
-ERASE, 47708488638464, 47708488646655,
-STORE, 47708488638464, 47708488642559,
-STORE, 47708488642560, 47708488646655,
- };
-
- unsigned long set9[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140736427839488, 140737488351231,
-ERASE, 140736427839488, 140736427839488,
-STORE, 140736427839488, 140736427843583,
-STORE, 94071213395968, 94071213567999,
-ERASE, 94071213395968, 94071213395968,
-STORE, 94071213395968, 94071213412351,
-STORE, 94071213412352, 94071213567999,
-ERASE, 94071213412352, 94071213412352,
-STORE, 94071213412352, 94071213514751,
-STORE, 94071213514752, 94071213555711,
-STORE, 94071213555712, 94071213567999,
-STORE, 139968410644480, 139968410816511,
-ERASE, 139968410644480, 139968410644480,
-STORE, 139968410644480, 139968410648575,
-STORE, 139968410648576, 139968410816511,
-ERASE, 139968410648576, 139968410648576,
-STORE, 139968410648576, 139968410771455,
-STORE, 139968410771456, 139968410804223,
-STORE, 139968410804224, 139968410812415,
-STORE, 139968410812416, 139968410816511,
-STORE, 140736429277184, 140736429281279,
-STORE, 140736429264896, 140736429277183,
-STORE, 47664384352256, 47664384360447,
-STORE, 47664384360448, 47664384368639,
-STORE, 47664384368640, 47664384532479,
-ERASE, 47664384368640, 47664384368640,
-STORE, 47664384368640, 47664384380927,
-STORE, 47664384380928, 47664384532479,
-STORE, 47664384479232, 47664384532479,
-STORE, 47664384380928, 47664384479231,
-ERASE, 47664384380928, 47664384380928,
-STORE, 47664384380928, 47664384479231,
-STORE, 47664384524288, 47664384532479,
-STORE, 47664384479232, 47664384524287,
-ERASE, 47664384479232, 47664384479232,
-STORE, 47664384479232, 47664384532479,
-ERASE, 47664384479232, 47664384479232,
-STORE, 47664384479232, 47664384524287,
-STORE, 47664384524288, 47664384532479,
-ERASE, 47664384524288, 47664384524288,
-STORE, 47664384524288, 47664384532479,
-STORE, 47664384532480, 47664387583999,
-STORE, 47664385077248, 47664387583999,
-STORE, 47664384532480, 47664385077247,
-ERASE, 47664385077248, 47664385077248,
-STORE, 47664385077248, 47664387362815,
-STORE, 47664387362816, 47664387583999,
-STORE, 47664386772992, 47664387362815,
-STORE, 47664385077248, 47664386772991,
-ERASE, 47664385077248, 47664385077248,
-STORE, 47664385077248, 47664386772991,
-STORE, 47664387358720, 47664387362815,
-STORE, 47664386772992, 47664387358719,
-ERASE, 47664386772992, 47664386772992,
-STORE, 47664386772992, 47664387358719,
-STORE, 47664387567616, 47664387583999,
-STORE, 47664387362816, 47664387567615,
-ERASE, 47664387362816, 47664387362816,
-STORE, 47664387362816, 47664387567615,
-ERASE, 47664387567616, 47664387567616,
-STORE, 47664387567616, 47664387583999,
-STORE, 47664387584000, 47664389423103,
-STORE, 47664387723264, 47664389423103,
-STORE, 47664387584000, 47664387723263,
-ERASE, 47664387723264, 47664387723264,
-STORE, 47664387723264, 47664389382143,
-STORE, 47664389382144, 47664389423103,
-STORE, 47664389066752, 47664389382143,
-STORE, 47664387723264, 47664389066751,
-ERASE, 47664387723264, 47664387723264,
-STORE, 47664387723264, 47664389066751,
-STORE, 47664389378048, 47664389382143,
-STORE, 47664389066752, 47664389378047,
-ERASE, 47664389066752, 47664389066752,
-STORE, 47664389066752, 47664389378047,
-STORE, 47664389406720, 47664389423103,
-STORE, 47664389382144, 47664389406719,
-ERASE, 47664389382144, 47664389382144,
-STORE, 47664389382144, 47664389406719,
-ERASE, 47664389406720, 47664389406720,
-STORE, 47664389406720, 47664389423103,
-STORE, 47664389423104, 47664389558271,
-ERASE, 47664389423104, 47664389423104,
-STORE, 47664389423104, 47664389447679,
-STORE, 47664389447680, 47664389558271,
-STORE, 47664389509120, 47664389558271,
-STORE, 47664389447680, 47664389509119,
-ERASE, 47664389447680, 47664389447680,
-STORE, 47664389447680, 47664389509119,
-STORE, 47664389533696, 47664389558271,
-STORE, 47664389509120, 47664389533695,
-ERASE, 47664389509120, 47664389509120,
-STORE, 47664389509120, 47664389558271,
-ERASE, 47664389509120, 47664389509120,
-STORE, 47664389509120, 47664389533695,
-STORE, 47664389533696, 47664389558271,
-STORE, 47664389541888, 47664389558271,
-STORE, 47664389533696, 47664389541887,
-ERASE, 47664389533696, 47664389533696,
-STORE, 47664389533696, 47664389541887,
-ERASE, 47664389541888, 47664389541888,
-STORE, 47664389541888, 47664389558271,
-STORE, 47664389558272, 47664389578751,
-ERASE, 47664389558272, 47664389558272,
-STORE, 47664389558272, 47664389562367,
-STORE, 47664389562368, 47664389578751,
-STORE, 47664389566464, 47664389578751,
-STORE, 47664389562368, 47664389566463,
-ERASE, 47664389562368, 47664389562368,
-STORE, 47664389562368, 47664389566463,
-STORE, 47664389570560, 47664389578751,
-STORE, 47664389566464, 47664389570559,
-ERASE, 47664389566464, 47664389566464,
-STORE, 47664389566464, 47664389578751,
-ERASE, 47664389566464, 47664389566464,
-STORE, 47664389566464, 47664389570559,
-STORE, 47664389570560, 47664389578751,
-ERASE, 47664389570560, 47664389570560,
-STORE, 47664389570560, 47664389578751,
-STORE, 47664389578752, 47664389586943,
-ERASE, 47664389382144, 47664389382144,
-STORE, 47664389382144, 47664389398527,
-STORE, 47664389398528, 47664389406719,
-ERASE, 47664389570560, 47664389570560,
-STORE, 47664389570560, 47664389574655,
-STORE, 47664389574656, 47664389578751,
-ERASE, 47664389533696, 47664389533696,
-STORE, 47664389533696, 47664389537791,
-STORE, 47664389537792, 47664389541887,
-ERASE, 47664387362816, 47664387362816,
-STORE, 47664387362816, 47664387559423,
-STORE, 47664387559424, 47664387567615,
-ERASE, 47664384524288, 47664384524288,
-STORE, 47664384524288, 47664384528383,
-STORE, 47664384528384, 47664384532479,
-ERASE, 94071213555712, 94071213555712,
-STORE, 94071213555712, 94071213563903,
-STORE, 94071213563904, 94071213567999,
-ERASE, 139968410804224, 139968410804224,
-STORE, 139968410804224, 139968410808319,
-STORE, 139968410808320, 139968410812415,
-ERASE, 47664384352256, 47664384352256,
-STORE, 94071244402688, 94071244537855,
-STORE, 140737488347136, 140737488351231,
-STORE, 140728271503360, 140737488351231,
-ERASE, 140728271503360, 140728271503360,
-STORE, 140728271503360, 140728271507455,
-STORE, 94410361982976, 94410362155007,
-ERASE, 94410361982976, 94410361982976,
-STORE, 94410361982976, 94410361999359,
-STORE, 94410361999360, 94410362155007,
-ERASE, 94410361999360, 94410361999360,
-STORE, 94410361999360, 94410362101759,
-STORE, 94410362101760, 94410362142719,
-STORE, 94410362142720, 94410362155007,
-STORE, 140351953997824, 140351954169855,
-ERASE, 140351953997824, 140351953997824,
-STORE, 140351953997824, 140351954001919,
-STORE, 140351954001920, 140351954169855,
-ERASE, 140351954001920, 140351954001920,
-STORE, 140351954001920, 140351954124799,
-STORE, 140351954124800, 140351954157567,
-STORE, 140351954157568, 140351954165759,
-STORE, 140351954165760, 140351954169855,
-STORE, 140728272429056, 140728272433151,
-STORE, 140728272416768, 140728272429055,
-STORE, 47280840998912, 47280841007103,
-STORE, 47280841007104, 47280841015295,
-STORE, 47280841015296, 47280841179135,
-ERASE, 47280841015296, 47280841015296,
-STORE, 47280841015296, 47280841027583,
-STORE, 47280841027584, 47280841179135,
-STORE, 47280841125888, 47280841179135,
-STORE, 47280841027584, 47280841125887,
-ERASE, 47280841027584, 47280841027584,
-STORE, 47280841027584, 47280841125887,
-STORE, 47280841170944, 47280841179135,
-STORE, 47280841125888, 47280841170943,
-ERASE, 47280841125888, 47280841125888,
-STORE, 47280841125888, 47280841179135,
-ERASE, 47280841125888, 47280841125888,
-STORE, 47280841125888, 47280841170943,
-STORE, 47280841170944, 47280841179135,
-ERASE, 47280841170944, 47280841170944,
-STORE, 47280841170944, 47280841179135,
-STORE, 47280841179136, 47280844230655,
-STORE, 47280841723904, 47280844230655,
-STORE, 47280841179136, 47280841723903,
-ERASE, 47280841723904, 47280841723904,
-STORE, 47280841723904, 47280844009471,
-STORE, 47280844009472, 47280844230655,
-STORE, 47280843419648, 47280844009471,
-STORE, 47280841723904, 47280843419647,
-ERASE, 47280841723904, 47280841723904,
-STORE, 47280841723904, 47280843419647,
-STORE, 47280844005376, 47280844009471,
-STORE, 47280843419648, 47280844005375,
-ERASE, 47280843419648, 47280843419648,
-STORE, 47280843419648, 47280844005375,
-STORE, 47280844214272, 47280844230655,
-STORE, 47280844009472, 47280844214271,
-ERASE, 47280844009472, 47280844009472,
-STORE, 47280844009472, 47280844214271,
-ERASE, 47280844214272, 47280844214272,
-STORE, 47280844214272, 47280844230655,
-STORE, 47280844230656, 47280846069759,
-STORE, 47280844369920, 47280846069759,
-STORE, 47280844230656, 47280844369919,
-ERASE, 47280844369920, 47280844369920,
-STORE, 47280844369920, 47280846028799,
-STORE, 47280846028800, 47280846069759,
-STORE, 47280845713408, 47280846028799,
-STORE, 47280844369920, 47280845713407,
-ERASE, 47280844369920, 47280844369920,
-STORE, 47280844369920, 47280845713407,
-STORE, 47280846024704, 47280846028799,
-STORE, 47280845713408, 47280846024703,
-ERASE, 47280845713408, 47280845713408,
-STORE, 47280845713408, 47280846024703,
-STORE, 47280846053376, 47280846069759,
-STORE, 47280846028800, 47280846053375,
-ERASE, 47280846028800, 47280846028800,
-STORE, 47280846028800, 47280846053375,
-ERASE, 47280846053376, 47280846053376,
-STORE, 47280846053376, 47280846069759,
-STORE, 47280846069760, 47280846204927,
-ERASE, 47280846069760, 47280846069760,
-STORE, 47280846069760, 47280846094335,
-STORE, 47280846094336, 47280846204927,
-STORE, 47280846155776, 47280846204927,
-STORE, 47280846094336, 47280846155775,
-ERASE, 47280846094336, 47280846094336,
-STORE, 47280846094336, 47280846155775,
-STORE, 47280846180352, 47280846204927,
-STORE, 47280846155776, 47280846180351,
-ERASE, 47280846155776, 47280846155776,
-STORE, 47280846155776, 47280846204927,
-ERASE, 47280846155776, 47280846155776,
-STORE, 47280846155776, 47280846180351,
-STORE, 47280846180352, 47280846204927,
-STORE, 47280846188544, 47280846204927,
-STORE, 47280846180352, 47280846188543,
-ERASE, 47280846180352, 47280846180352,
-STORE, 47280846180352, 47280846188543,
-ERASE, 47280846188544, 47280846188544,
-STORE, 47280846188544, 47280846204927,
-STORE, 47280846204928, 47280846225407,
-ERASE, 47280846204928, 47280846204928,
-STORE, 47280846204928, 47280846209023,
-STORE, 47280846209024, 47280846225407,
-STORE, 47280846213120, 47280846225407,
-STORE, 47280846209024, 47280846213119,
-ERASE, 47280846209024, 47280846209024,
-STORE, 47280846209024, 47280846213119,
-STORE, 47280846217216, 47280846225407,
-STORE, 47280846213120, 47280846217215,
-ERASE, 47280846213120, 47280846213120,
-STORE, 47280846213120, 47280846225407,
-ERASE, 47280846213120, 47280846213120,
-STORE, 47280846213120, 47280846217215,
-STORE, 47280846217216, 47280846225407,
-ERASE, 47280846217216, 47280846217216,
-STORE, 47280846217216, 47280846225407,
-STORE, 47280846225408, 47280846233599,
-ERASE, 47280846028800, 47280846028800,
-STORE, 47280846028800, 47280846045183,
-STORE, 47280846045184, 47280846053375,
-ERASE, 47280846217216, 47280846217216,
-STORE, 47280846217216, 47280846221311,
-STORE, 47280846221312, 47280846225407,
-ERASE, 47280846180352, 47280846180352,
-STORE, 47280846180352, 47280846184447,
-STORE, 47280846184448, 47280846188543,
-ERASE, 47280844009472, 47280844009472,
-STORE, 47280844009472, 47280844206079,
-STORE, 47280844206080, 47280844214271,
-ERASE, 47280841170944, 47280841170944,
-STORE, 47280841170944, 47280841175039,
-STORE, 47280841175040, 47280841179135,
-ERASE, 94410362142720, 94410362142720,
-STORE, 94410362142720, 94410362150911,
-STORE, 94410362150912, 94410362155007,
-ERASE, 140351954157568, 140351954157568,
-STORE, 140351954157568, 140351954161663,
-STORE, 140351954161664, 140351954165759,
-ERASE, 47280840998912, 47280840998912,
-STORE, 94410379456512, 94410379591679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732946362368, 140737488351231,
-ERASE, 140732946362368, 140732946362368,
-STORE, 140732946362368, 140732946366463,
-STORE, 94352937934848, 94352938106879,
-ERASE, 94352937934848, 94352937934848,
-STORE, 94352937934848, 94352937951231,
-STORE, 94352937951232, 94352938106879,
-ERASE, 94352937951232, 94352937951232,
-STORE, 94352937951232, 94352938053631,
-STORE, 94352938053632, 94352938094591,
-STORE, 94352938094592, 94352938106879,
-STORE, 140595518742528, 140595518914559,
-ERASE, 140595518742528, 140595518742528,
-STORE, 140595518742528, 140595518746623,
-STORE, 140595518746624, 140595518914559,
-ERASE, 140595518746624, 140595518746624,
-STORE, 140595518746624, 140595518869503,
-STORE, 140595518869504, 140595518902271,
-STORE, 140595518902272, 140595518910463,
-STORE, 140595518910464, 140595518914559,
-STORE, 140732947468288, 140732947472383,
-STORE, 140732947456000, 140732947468287,
-STORE, 47037276254208, 47037276262399,
-STORE, 47037276262400, 47037276270591,
-STORE, 47037276270592, 47037276434431,
-ERASE, 47037276270592, 47037276270592,
-STORE, 47037276270592, 47037276282879,
-STORE, 47037276282880, 47037276434431,
-STORE, 47037276381184, 47037276434431,
-STORE, 47037276282880, 47037276381183,
-ERASE, 47037276282880, 47037276282880,
-STORE, 47037276282880, 47037276381183,
-STORE, 47037276426240, 47037276434431,
-STORE, 47037276381184, 47037276426239,
-ERASE, 47037276381184, 47037276381184,
-STORE, 47037276381184, 47037276434431,
-ERASE, 47037276381184, 47037276381184,
-STORE, 47037276381184, 47037276426239,
-STORE, 47037276426240, 47037276434431,
-ERASE, 47037276426240, 47037276426240,
-STORE, 47037276426240, 47037276434431,
-STORE, 47037276434432, 47037279485951,
-STORE, 47037276979200, 47037279485951,
-STORE, 47037276434432, 47037276979199,
-ERASE, 47037276979200, 47037276979200,
-STORE, 47037276979200, 47037279264767,
-STORE, 47037279264768, 47037279485951,
-STORE, 47037278674944, 47037279264767,
-STORE, 47037276979200, 47037278674943,
-ERASE, 47037276979200, 47037276979200,
-STORE, 47037276979200, 47037278674943,
-STORE, 47037279260672, 47037279264767,
-STORE, 47037278674944, 47037279260671,
-ERASE, 47037278674944, 47037278674944,
-STORE, 47037278674944, 47037279260671,
-STORE, 47037279469568, 47037279485951,
-STORE, 47037279264768, 47037279469567,
-ERASE, 47037279264768, 47037279264768,
-STORE, 47037279264768, 47037279469567,
-ERASE, 47037279469568, 47037279469568,
-STORE, 47037279469568, 47037279485951,
-STORE, 47037279485952, 47037281325055,
-STORE, 47037279625216, 47037281325055,
-STORE, 47037279485952, 47037279625215,
-ERASE, 47037279625216, 47037279625216,
-STORE, 47037279625216, 47037281284095,
-STORE, 47037281284096, 47037281325055,
-STORE, 47037280968704, 47037281284095,
-STORE, 47037279625216, 47037280968703,
-ERASE, 47037279625216, 47037279625216,
-STORE, 47037279625216, 47037280968703,
-STORE, 47037281280000, 47037281284095,
-STORE, 47037280968704, 47037281279999,
-ERASE, 47037280968704, 47037280968704,
-STORE, 47037280968704, 47037281279999,
-STORE, 47037281308672, 47037281325055,
-STORE, 47037281284096, 47037281308671,
-ERASE, 47037281284096, 47037281284096,
-STORE, 47037281284096, 47037281308671,
-ERASE, 47037281308672, 47037281308672,
-STORE, 47037281308672, 47037281325055,
-STORE, 47037281325056, 47037281460223,
-ERASE, 47037281325056, 47037281325056,
-STORE, 47037281325056, 47037281349631,
-STORE, 47037281349632, 47037281460223,
-STORE, 47037281411072, 47037281460223,
-STORE, 47037281349632, 47037281411071,
-ERASE, 47037281349632, 47037281349632,
-STORE, 47037281349632, 47037281411071,
-STORE, 47037281435648, 47037281460223,
-STORE, 47037281411072, 47037281435647,
-ERASE, 47037281411072, 47037281411072,
-STORE, 47037281411072, 47037281460223,
-ERASE, 47037281411072, 47037281411072,
-STORE, 47037281411072, 47037281435647,
-STORE, 47037281435648, 47037281460223,
-STORE, 47037281443840, 47037281460223,
-STORE, 47037281435648, 47037281443839,
-ERASE, 47037281435648, 47037281435648,
-STORE, 47037281435648, 47037281443839,
-ERASE, 47037281443840, 47037281443840,
-STORE, 47037281443840, 47037281460223,
-STORE, 47037281460224, 47037281480703,
-ERASE, 47037281460224, 47037281460224,
-STORE, 47037281460224, 47037281464319,
-STORE, 47037281464320, 47037281480703,
-STORE, 47037281468416, 47037281480703,
-STORE, 47037281464320, 47037281468415,
-ERASE, 47037281464320, 47037281464320,
-STORE, 47037281464320, 47037281468415,
-STORE, 47037281472512, 47037281480703,
-STORE, 47037281468416, 47037281472511,
-ERASE, 47037281468416, 47037281468416,
-STORE, 47037281468416, 47037281480703,
-ERASE, 47037281468416, 47037281468416,
-STORE, 47037281468416, 47037281472511,
-STORE, 47037281472512, 47037281480703,
-ERASE, 47037281472512, 47037281472512,
-STORE, 47037281472512, 47037281480703,
-STORE, 47037281480704, 47037281488895,
-ERASE, 47037281284096, 47037281284096,
-STORE, 47037281284096, 47037281300479,
-STORE, 47037281300480, 47037281308671,
-ERASE, 47037281472512, 47037281472512,
-STORE, 47037281472512, 47037281476607,
-STORE, 47037281476608, 47037281480703,
-ERASE, 47037281435648, 47037281435648,
-STORE, 47037281435648, 47037281439743,
-STORE, 47037281439744, 47037281443839,
-ERASE, 47037279264768, 47037279264768,
-STORE, 47037279264768, 47037279461375,
-STORE, 47037279461376, 47037279469567,
-ERASE, 47037276426240, 47037276426240,
-STORE, 47037276426240, 47037276430335,
-STORE, 47037276430336, 47037276434431,
-ERASE, 94352938094592, 94352938094592,
-STORE, 94352938094592, 94352938102783,
-STORE, 94352938102784, 94352938106879,
-ERASE, 140595518902272, 140595518902272,
-STORE, 140595518902272, 140595518906367,
-STORE, 140595518906368, 140595518910463,
-ERASE, 47037276254208, 47037276254208,
-STORE, 94352938438656, 94352938573823,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733506027520, 140737488351231,
-ERASE, 140733506027520, 140733506027520,
-STORE, 140733506027520, 140733506031615,
-STORE, 94150123073536, 94150123245567,
-ERASE, 94150123073536, 94150123073536,
-STORE, 94150123073536, 94150123089919,
-STORE, 94150123089920, 94150123245567,
-ERASE, 94150123089920, 94150123089920,
-STORE, 94150123089920, 94150123192319,
-STORE, 94150123192320, 94150123233279,
-STORE, 94150123233280, 94150123245567,
-STORE, 140081290375168, 140081290547199,
-ERASE, 140081290375168, 140081290375168,
-STORE, 140081290375168, 140081290379263,
-STORE, 140081290379264, 140081290547199,
-ERASE, 140081290379264, 140081290379264,
-STORE, 140081290379264, 140081290502143,
-STORE, 140081290502144, 140081290534911,
-STORE, 140081290534912, 140081290543103,
-STORE, 140081290543104, 140081290547199,
-STORE, 140733506707456, 140733506711551,
-STORE, 140733506695168, 140733506707455,
-STORE, 47551504621568, 47551504629759,
-STORE, 47551504629760, 47551504637951,
-STORE, 47551504637952, 47551504801791,
-ERASE, 47551504637952, 47551504637952,
-STORE, 47551504637952, 47551504650239,
-STORE, 47551504650240, 47551504801791,
-STORE, 47551504748544, 47551504801791,
-STORE, 47551504650240, 47551504748543,
-ERASE, 47551504650240, 47551504650240,
-STORE, 47551504650240, 47551504748543,
-STORE, 47551504793600, 47551504801791,
-STORE, 47551504748544, 47551504793599,
-ERASE, 47551504748544, 47551504748544,
-STORE, 47551504748544, 47551504801791,
-ERASE, 47551504748544, 47551504748544,
-STORE, 47551504748544, 47551504793599,
-STORE, 47551504793600, 47551504801791,
-ERASE, 47551504793600, 47551504793600,
-STORE, 47551504793600, 47551504801791,
-STORE, 47551504801792, 47551507853311,
-STORE, 47551505346560, 47551507853311,
-STORE, 47551504801792, 47551505346559,
-ERASE, 47551505346560, 47551505346560,
-STORE, 47551505346560, 47551507632127,
-STORE, 47551507632128, 47551507853311,
-STORE, 47551507042304, 47551507632127,
-STORE, 47551505346560, 47551507042303,
-ERASE, 47551505346560, 47551505346560,
-STORE, 47551505346560, 47551507042303,
-STORE, 47551507628032, 47551507632127,
-STORE, 47551507042304, 47551507628031,
-ERASE, 47551507042304, 47551507042304,
-STORE, 47551507042304, 47551507628031,
-STORE, 47551507836928, 47551507853311,
-STORE, 47551507632128, 47551507836927,
-ERASE, 47551507632128, 47551507632128,
-STORE, 47551507632128, 47551507836927,
-ERASE, 47551507836928, 47551507836928,
-STORE, 47551507836928, 47551507853311,
-STORE, 47551507853312, 47551509692415,
-STORE, 47551507992576, 47551509692415,
-STORE, 47551507853312, 47551507992575,
-ERASE, 47551507992576, 47551507992576,
-STORE, 47551507992576, 47551509651455,
-STORE, 47551509651456, 47551509692415,
-STORE, 47551509336064, 47551509651455,
-STORE, 47551507992576, 47551509336063,
-ERASE, 47551507992576, 47551507992576,
-STORE, 47551507992576, 47551509336063,
-STORE, 47551509647360, 47551509651455,
-STORE, 47551509336064, 47551509647359,
-ERASE, 47551509336064, 47551509336064,
-STORE, 47551509336064, 47551509647359,
-STORE, 47551509676032, 47551509692415,
-STORE, 47551509651456, 47551509676031,
-ERASE, 47551509651456, 47551509651456,
-STORE, 47551509651456, 47551509676031,
-ERASE, 47551509676032, 47551509676032,
-STORE, 47551509676032, 47551509692415,
-STORE, 47551509692416, 47551509827583,
-ERASE, 47551509692416, 47551509692416,
-STORE, 47551509692416, 47551509716991,
-STORE, 47551509716992, 47551509827583,
-STORE, 47551509778432, 47551509827583,
-STORE, 47551509716992, 47551509778431,
-ERASE, 47551509716992, 47551509716992,
-STORE, 47551509716992, 47551509778431,
-STORE, 47551509803008, 47551509827583,
-STORE, 47551509778432, 47551509803007,
-ERASE, 47551509778432, 47551509778432,
-STORE, 47551509778432, 47551509827583,
-ERASE, 47551509778432, 47551509778432,
-STORE, 47551509778432, 47551509803007,
-STORE, 47551509803008, 47551509827583,
-STORE, 47551509811200, 47551509827583,
-STORE, 47551509803008, 47551509811199,
-ERASE, 47551509803008, 47551509803008,
-STORE, 47551509803008, 47551509811199,
-ERASE, 47551509811200, 47551509811200,
-STORE, 47551509811200, 47551509827583,
-STORE, 47551509827584, 47551509848063,
-ERASE, 47551509827584, 47551509827584,
-STORE, 47551509827584, 47551509831679,
-STORE, 47551509831680, 47551509848063,
-STORE, 47551509835776, 47551509848063,
-STORE, 47551509831680, 47551509835775,
-ERASE, 47551509831680, 47551509831680,
-STORE, 47551509831680, 47551509835775,
-STORE, 47551509839872, 47551509848063,
-STORE, 47551509835776, 47551509839871,
-ERASE, 47551509835776, 47551509835776,
-STORE, 47551509835776, 47551509848063,
-ERASE, 47551509835776, 47551509835776,
-STORE, 47551509835776, 47551509839871,
-STORE, 47551509839872, 47551509848063,
-ERASE, 47551509839872, 47551509839872,
-STORE, 47551509839872, 47551509848063,
-STORE, 47551509848064, 47551509856255,
-ERASE, 47551509651456, 47551509651456,
-STORE, 47551509651456, 47551509667839,
-STORE, 47551509667840, 47551509676031,
-ERASE, 47551509839872, 47551509839872,
-STORE, 47551509839872, 47551509843967,
-STORE, 47551509843968, 47551509848063,
-ERASE, 47551509803008, 47551509803008,
-STORE, 47551509803008, 47551509807103,
-STORE, 47551509807104, 47551509811199,
-ERASE, 47551507632128, 47551507632128,
-STORE, 47551507632128, 47551507828735,
-STORE, 47551507828736, 47551507836927,
-ERASE, 47551504793600, 47551504793600,
-STORE, 47551504793600, 47551504797695,
-STORE, 47551504797696, 47551504801791,
-ERASE, 94150123233280, 94150123233280,
-STORE, 94150123233280, 94150123241471,
-STORE, 94150123241472, 94150123245567,
-ERASE, 140081290534912, 140081290534912,
-STORE, 140081290534912, 140081290539007,
-STORE, 140081290539008, 140081290543103,
-ERASE, 47551504621568, 47551504621568,
-STORE, 94150148112384, 94150148247551,
-STORE, 140737488347136, 140737488351231,
-STORE, 140734389334016, 140737488351231,
-ERASE, 140734389334016, 140734389334016,
-STORE, 140734389334016, 140734389338111,
-STORE, 94844636606464, 94844636778495,
-ERASE, 94844636606464, 94844636606464,
-STORE, 94844636606464, 94844636622847,
-STORE, 94844636622848, 94844636778495,
-ERASE, 94844636622848, 94844636622848,
-STORE, 94844636622848, 94844636725247,
-STORE, 94844636725248, 94844636766207,
-STORE, 94844636766208, 94844636778495,
-STORE, 139922765217792, 139922765389823,
-ERASE, 139922765217792, 139922765217792,
-STORE, 139922765217792, 139922765221887,
-STORE, 139922765221888, 139922765389823,
-ERASE, 139922765221888, 139922765221888,
-STORE, 139922765221888, 139922765344767,
-STORE, 139922765344768, 139922765377535,
-STORE, 139922765377536, 139922765385727,
-STORE, 139922765385728, 139922765389823,
-STORE, 140734389678080, 140734389682175,
-STORE, 140734389665792, 140734389678079,
-STORE, 47710029778944, 47710029787135,
-STORE, 47710029787136, 47710029795327,
-STORE, 47710029795328, 47710029959167,
-ERASE, 47710029795328, 47710029795328,
-STORE, 47710029795328, 47710029807615,
-STORE, 47710029807616, 47710029959167,
-STORE, 47710029905920, 47710029959167,
-STORE, 47710029807616, 47710029905919,
-ERASE, 47710029807616, 47710029807616,
-STORE, 47710029807616, 47710029905919,
-STORE, 47710029950976, 47710029959167,
-STORE, 47710029905920, 47710029950975,
-ERASE, 47710029905920, 47710029905920,
-STORE, 47710029905920, 47710029959167,
-ERASE, 47710029905920, 47710029905920,
-STORE, 47710029905920, 47710029950975,
-STORE, 47710029950976, 47710029959167,
-ERASE, 47710029950976, 47710029950976,
-STORE, 47710029950976, 47710029959167,
-STORE, 47710029959168, 47710033010687,
-STORE, 47710030503936, 47710033010687,
-STORE, 47710029959168, 47710030503935,
-ERASE, 47710030503936, 47710030503936,
-STORE, 47710030503936, 47710032789503,
-STORE, 47710032789504, 47710033010687,
-STORE, 47710032199680, 47710032789503,
-STORE, 47710030503936, 47710032199679,
-ERASE, 47710030503936, 47710030503936,
-STORE, 47710030503936, 47710032199679,
-STORE, 47710032785408, 47710032789503,
-STORE, 47710032199680, 47710032785407,
-ERASE, 47710032199680, 47710032199680,
-STORE, 47710032199680, 47710032785407,
-STORE, 47710032994304, 47710033010687,
-STORE, 47710032789504, 47710032994303,
-ERASE, 47710032789504, 47710032789504,
-STORE, 47710032789504, 47710032994303,
-ERASE, 47710032994304, 47710032994304,
-STORE, 47710032994304, 47710033010687,
-STORE, 47710033010688, 47710034849791,
-STORE, 47710033149952, 47710034849791,
-STORE, 47710033010688, 47710033149951,
-ERASE, 47710033149952, 47710033149952,
-STORE, 47710033149952, 47710034808831,
-STORE, 47710034808832, 47710034849791,
-STORE, 47710034493440, 47710034808831,
-STORE, 47710033149952, 47710034493439,
-ERASE, 47710033149952, 47710033149952,
-STORE, 47710033149952, 47710034493439,
-STORE, 47710034804736, 47710034808831,
-STORE, 47710034493440, 47710034804735,
-ERASE, 47710034493440, 47710034493440,
-STORE, 47710034493440, 47710034804735,
-STORE, 47710034833408, 47710034849791,
-STORE, 47710034808832, 47710034833407,
-ERASE, 47710034808832, 47710034808832,
-STORE, 47710034808832, 47710034833407,
-ERASE, 47710034833408, 47710034833408,
-STORE, 47710034833408, 47710034849791,
-STORE, 47710034849792, 47710034984959,
-ERASE, 47710034849792, 47710034849792,
-STORE, 47710034849792, 47710034874367,
-STORE, 47710034874368, 47710034984959,
-STORE, 47710034935808, 47710034984959,
-STORE, 47710034874368, 47710034935807,
-ERASE, 47710034874368, 47710034874368,
-STORE, 47710034874368, 47710034935807,
-STORE, 47710034960384, 47710034984959,
-STORE, 47710034935808, 47710034960383,
-ERASE, 47710034935808, 47710034935808,
-STORE, 47710034935808, 47710034984959,
-ERASE, 47710034935808, 47710034935808,
-STORE, 47710034935808, 47710034960383,
-STORE, 47710034960384, 47710034984959,
-STORE, 47710034968576, 47710034984959,
-STORE, 47710034960384, 47710034968575,
-ERASE, 47710034960384, 47710034960384,
-STORE, 47710034960384, 47710034968575,
-ERASE, 47710034968576, 47710034968576,
-STORE, 47710034968576, 47710034984959,
-STORE, 47710034984960, 47710035005439,
-ERASE, 47710034984960, 47710034984960,
-STORE, 47710034984960, 47710034989055,
-STORE, 47710034989056, 47710035005439,
-STORE, 47710034993152, 47710035005439,
-STORE, 47710034989056, 47710034993151,
-ERASE, 47710034989056, 47710034989056,
-STORE, 47710034989056, 47710034993151,
-STORE, 47710034997248, 47710035005439,
-STORE, 47710034993152, 47710034997247,
-ERASE, 47710034993152, 47710034993152,
-STORE, 47710034993152, 47710035005439,
-ERASE, 47710034993152, 47710034993152,
-STORE, 47710034993152, 47710034997247,
-STORE, 47710034997248, 47710035005439,
-ERASE, 47710034997248, 47710034997248,
-STORE, 47710034997248, 47710035005439,
-STORE, 47710035005440, 47710035013631,
-ERASE, 47710034808832, 47710034808832,
-STORE, 47710034808832, 47710034825215,
-STORE, 47710034825216, 47710034833407,
-ERASE, 47710034997248, 47710034997248,
-STORE, 47710034997248, 47710035001343,
-STORE, 47710035001344, 47710035005439,
-ERASE, 47710034960384, 47710034960384,
-STORE, 47710034960384, 47710034964479,
-STORE, 47710034964480, 47710034968575,
-ERASE, 47710032789504, 47710032789504,
-STORE, 47710032789504, 47710032986111,
-STORE, 47710032986112, 47710032994303,
-ERASE, 47710029950976, 47710029950976,
-STORE, 47710029950976, 47710029955071,
-STORE, 47710029955072, 47710029959167,
-ERASE, 94844636766208, 94844636766208,
-STORE, 94844636766208, 94844636774399,
-STORE, 94844636774400, 94844636778495,
-ERASE, 139922765377536, 139922765377536,
-STORE, 139922765377536, 139922765381631,
-STORE, 139922765381632, 139922765385727,
-ERASE, 47710029778944, 47710029778944,
-STORE, 94844641775616, 94844641910783,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732213886976, 140737488351231,
-ERASE, 140732213886976, 140732213886976,
-STORE, 140732213886976, 140732213891071,
-STORE, 94240508887040, 94240509059071,
-ERASE, 94240508887040, 94240508887040,
-STORE, 94240508887040, 94240508903423,
-STORE, 94240508903424, 94240509059071,
-ERASE, 94240508903424, 94240508903424,
-STORE, 94240508903424, 94240509005823,
-STORE, 94240509005824, 94240509046783,
-STORE, 94240509046784, 94240509059071,
-STORE, 140275106516992, 140275106689023,
-ERASE, 140275106516992, 140275106516992,
-STORE, 140275106516992, 140275106521087,
-STORE, 140275106521088, 140275106689023,
-ERASE, 140275106521088, 140275106521088,
-STORE, 140275106521088, 140275106643967,
-STORE, 140275106643968, 140275106676735,
-STORE, 140275106676736, 140275106684927,
-STORE, 140275106684928, 140275106689023,
-STORE, 140732213977088, 140732213981183,
-STORE, 140732213964800, 140732213977087,
-STORE, 47357688479744, 47357688487935,
-STORE, 47357688487936, 47357688496127,
-STORE, 47357688496128, 47357688659967,
-ERASE, 47357688496128, 47357688496128,
-STORE, 47357688496128, 47357688508415,
-STORE, 47357688508416, 47357688659967,
-STORE, 47357688606720, 47357688659967,
-STORE, 47357688508416, 47357688606719,
-ERASE, 47357688508416, 47357688508416,
-STORE, 47357688508416, 47357688606719,
-STORE, 47357688651776, 47357688659967,
-STORE, 47357688606720, 47357688651775,
-ERASE, 47357688606720, 47357688606720,
-STORE, 47357688606720, 47357688659967,
-ERASE, 47357688606720, 47357688606720,
-STORE, 47357688606720, 47357688651775,
-STORE, 47357688651776, 47357688659967,
-ERASE, 47357688651776, 47357688651776,
-STORE, 47357688651776, 47357688659967,
-STORE, 47357688659968, 47357691711487,
-STORE, 47357689204736, 47357691711487,
-STORE, 47357688659968, 47357689204735,
-ERASE, 47357689204736, 47357689204736,
-STORE, 47357689204736, 47357691490303,
-STORE, 47357691490304, 47357691711487,
-STORE, 47357690900480, 47357691490303,
-STORE, 47357689204736, 47357690900479,
-ERASE, 47357689204736, 47357689204736,
-STORE, 47357689204736, 47357690900479,
-STORE, 47357691486208, 47357691490303,
-STORE, 47357690900480, 47357691486207,
-ERASE, 47357690900480, 47357690900480,
-STORE, 47357690900480, 47357691486207,
-STORE, 47357691695104, 47357691711487,
-STORE, 47357691490304, 47357691695103,
-ERASE, 47357691490304, 47357691490304,
-STORE, 47357691490304, 47357691695103,
-ERASE, 47357691695104, 47357691695104,
-STORE, 47357691695104, 47357691711487,
-STORE, 47357691711488, 47357693550591,
-STORE, 47357691850752, 47357693550591,
-STORE, 47357691711488, 47357691850751,
-ERASE, 47357691850752, 47357691850752,
-STORE, 47357691850752, 47357693509631,
-STORE, 47357693509632, 47357693550591,
-STORE, 47357693194240, 47357693509631,
-STORE, 47357691850752, 47357693194239,
-ERASE, 47357691850752, 47357691850752,
-STORE, 47357691850752, 47357693194239,
-STORE, 47357693505536, 47357693509631,
-STORE, 47357693194240, 47357693505535,
-ERASE, 47357693194240, 47357693194240,
-STORE, 47357693194240, 47357693505535,
-STORE, 47357693534208, 47357693550591,
-STORE, 47357693509632, 47357693534207,
-ERASE, 47357693509632, 47357693509632,
-STORE, 47357693509632, 47357693534207,
-ERASE, 47357693534208, 47357693534208,
-STORE, 47357693534208, 47357693550591,
-STORE, 47357693550592, 47357693685759,
-ERASE, 47357693550592, 47357693550592,
-STORE, 47357693550592, 47357693575167,
-STORE, 47357693575168, 47357693685759,
-STORE, 47357693636608, 47357693685759,
-STORE, 47357693575168, 47357693636607,
-ERASE, 47357693575168, 47357693575168,
-STORE, 47357693575168, 47357693636607,
-STORE, 47357693661184, 47357693685759,
-STORE, 47357693636608, 47357693661183,
-ERASE, 47357693636608, 47357693636608,
-STORE, 47357693636608, 47357693685759,
-ERASE, 47357693636608, 47357693636608,
-STORE, 47357693636608, 47357693661183,
-STORE, 47357693661184, 47357693685759,
-STORE, 47357693669376, 47357693685759,
-STORE, 47357693661184, 47357693669375,
-ERASE, 47357693661184, 47357693661184,
-STORE, 47357693661184, 47357693669375,
-ERASE, 47357693669376, 47357693669376,
-STORE, 47357693669376, 47357693685759,
-STORE, 47357693685760, 47357693706239,
-ERASE, 47357693685760, 47357693685760,
-STORE, 47357693685760, 47357693689855,
-STORE, 47357693689856, 47357693706239,
-STORE, 47357693693952, 47357693706239,
-STORE, 47357693689856, 47357693693951,
-ERASE, 47357693689856, 47357693689856,
-STORE, 47357693689856, 47357693693951,
-STORE, 47357693698048, 47357693706239,
-STORE, 47357693693952, 47357693698047,
-ERASE, 47357693693952, 47357693693952,
-STORE, 47357693693952, 47357693706239,
-ERASE, 47357693693952, 47357693693952,
-STORE, 47357693693952, 47357693698047,
-STORE, 47357693698048, 47357693706239,
-ERASE, 47357693698048, 47357693698048,
-STORE, 47357693698048, 47357693706239,
-STORE, 47357693706240, 47357693714431,
-ERASE, 47357693509632, 47357693509632,
-STORE, 47357693509632, 47357693526015,
-STORE, 47357693526016, 47357693534207,
-ERASE, 47357693698048, 47357693698048,
-STORE, 47357693698048, 47357693702143,
-STORE, 47357693702144, 47357693706239,
-ERASE, 47357693661184, 47357693661184,
-STORE, 47357693661184, 47357693665279,
-STORE, 47357693665280, 47357693669375,
-ERASE, 47357691490304, 47357691490304,
-STORE, 47357691490304, 47357691686911,
-STORE, 47357691686912, 47357691695103,
-ERASE, 47357688651776, 47357688651776,
-STORE, 47357688651776, 47357688655871,
-STORE, 47357688655872, 47357688659967,
-ERASE, 94240509046784, 94240509046784,
-STORE, 94240509046784, 94240509054975,
-STORE, 94240509054976, 94240509059071,
-ERASE, 140275106676736, 140275106676736,
-STORE, 140275106676736, 140275106680831,
-STORE, 140275106680832, 140275106684927,
-ERASE, 47357688479744, 47357688479744,
-STORE, 94240518361088, 94240518496255,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732688277504, 140737488351231,
-ERASE, 140732688277504, 140732688277504,
-STORE, 140732688277504, 140732688281599,
-STORE, 94629171351552, 94629172064255,
-ERASE, 94629171351552, 94629171351552,
-STORE, 94629171351552, 94629171400703,
-STORE, 94629171400704, 94629172064255,
-ERASE, 94629171400704, 94629171400704,
-STORE, 94629171400704, 94629171945471,
-STORE, 94629171945472, 94629172043775,
-STORE, 94629172043776, 94629172064255,
-STORE, 139770707644416, 139770707816447,
-ERASE, 139770707644416, 139770707644416,
-STORE, 139770707644416, 139770707648511,
-STORE, 139770707648512, 139770707816447,
-ERASE, 139770707648512, 139770707648512,
-STORE, 139770707648512, 139770707771391,
-STORE, 139770707771392, 139770707804159,
-STORE, 139770707804160, 139770707812351,
-STORE, 139770707812352, 139770707816447,
-STORE, 140732689121280, 140732689125375,
-STORE, 140732689108992, 140732689121279,
-STORE, 47862087352320, 47862087360511,
-STORE, 47862087360512, 47862087368703,
-STORE, 47862087368704, 47862087475199,
-STORE, 47862087385088, 47862087475199,
-STORE, 47862087368704, 47862087385087,
-ERASE, 47862087385088, 47862087385088,
-STORE, 47862087385088, 47862087458815,
-STORE, 47862087458816, 47862087475199,
-STORE, 47862087438336, 47862087458815,
-STORE, 47862087385088, 47862087438335,
-ERASE, 47862087385088, 47862087385088,
-STORE, 47862087385088, 47862087438335,
-STORE, 47862087454720, 47862087458815,
-STORE, 47862087438336, 47862087454719,
-ERASE, 47862087438336, 47862087438336,
-STORE, 47862087438336, 47862087454719,
-STORE, 47862087467008, 47862087475199,
-STORE, 47862087458816, 47862087467007,
-ERASE, 47862087458816, 47862087458816,
-STORE, 47862087458816, 47862087467007,
-ERASE, 47862087467008, 47862087467008,
-STORE, 47862087467008, 47862087475199,
-STORE, 47862087475200, 47862089314303,
-STORE, 47862087614464, 47862089314303,
-STORE, 47862087475200, 47862087614463,
-ERASE, 47862087614464, 47862087614464,
-STORE, 47862087614464, 47862089273343,
-STORE, 47862089273344, 47862089314303,
-STORE, 47862088957952, 47862089273343,
-STORE, 47862087614464, 47862088957951,
-ERASE, 47862087614464, 47862087614464,
-STORE, 47862087614464, 47862088957951,
-STORE, 47862089269248, 47862089273343,
-STORE, 47862088957952, 47862089269247,
-ERASE, 47862088957952, 47862088957952,
-STORE, 47862088957952, 47862089269247,
-STORE, 47862089297920, 47862089314303,
-STORE, 47862089273344, 47862089297919,
-ERASE, 47862089273344, 47862089273344,
-STORE, 47862089273344, 47862089297919,
-ERASE, 47862089297920, 47862089297920,
-STORE, 47862089297920, 47862089314303,
-STORE, 47862089297920, 47862089326591,
-ERASE, 47862089273344, 47862089273344,
-STORE, 47862089273344, 47862089289727,
-STORE, 47862089289728, 47862089297919,
-ERASE, 47862087458816, 47862087458816,
-STORE, 47862087458816, 47862087462911,
-STORE, 47862087462912, 47862087467007,
-ERASE, 94629172043776, 94629172043776,
-STORE, 94629172043776, 94629172060159,
-STORE, 94629172060160, 94629172064255,
-ERASE, 139770707804160, 139770707804160,
-STORE, 139770707804160, 139770707808255,
-STORE, 139770707808256, 139770707812351,
-ERASE, 47862087352320, 47862087352320,
-STORE, 94629197533184, 94629197668351,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727540711424, 140737488351231,
-ERASE, 140727540711424, 140727540711424,
-STORE, 140727540711424, 140727540715519,
-STORE, 94299865313280, 94299866025983,
-ERASE, 94299865313280, 94299865313280,
-STORE, 94299865313280, 94299865362431,
-STORE, 94299865362432, 94299866025983,
-ERASE, 94299865362432, 94299865362432,
-STORE, 94299865362432, 94299865907199,
-STORE, 94299865907200, 94299866005503,
-STORE, 94299866005504, 94299866025983,
-STORE, 140680268763136, 140680268935167,
-ERASE, 140680268763136, 140680268763136,
-STORE, 140680268763136, 140680268767231,
-STORE, 140680268767232, 140680268935167,
-ERASE, 140680268767232, 140680268767232,
-STORE, 140680268767232, 140680268890111,
-STORE, 140680268890112, 140680268922879,
-STORE, 140680268922880, 140680268931071,
-STORE, 140680268931072, 140680268935167,
-STORE, 140727541424128, 140727541428223,
-STORE, 140727541411840, 140727541424127,
-STORE, 46952526233600, 46952526241791,
-STORE, 46952526241792, 46952526249983,
-STORE, 46952526249984, 46952526356479,
-STORE, 46952526266368, 46952526356479,
-STORE, 46952526249984, 46952526266367,
-ERASE, 46952526266368, 46952526266368,
-STORE, 46952526266368, 46952526340095,
-STORE, 46952526340096, 46952526356479,
-STORE, 46952526319616, 46952526340095,
-STORE, 46952526266368, 46952526319615,
-ERASE, 46952526266368, 46952526266368,
-STORE, 46952526266368, 46952526319615,
-STORE, 46952526336000, 46952526340095,
-STORE, 46952526319616, 46952526335999,
-ERASE, 46952526319616, 46952526319616,
-STORE, 46952526319616, 46952526335999,
-STORE, 46952526348288, 46952526356479,
-STORE, 46952526340096, 46952526348287,
-ERASE, 46952526340096, 46952526340096,
-STORE, 46952526340096, 46952526348287,
-ERASE, 46952526348288, 46952526348288,
-STORE, 46952526348288, 46952526356479,
-STORE, 46952526356480, 46952528195583,
-STORE, 46952526495744, 46952528195583,
-STORE, 46952526356480, 46952526495743,
-ERASE, 46952526495744, 46952526495744,
-STORE, 46952526495744, 46952528154623,
-STORE, 46952528154624, 46952528195583,
-STORE, 46952527839232, 46952528154623,
-STORE, 46952526495744, 46952527839231,
-ERASE, 46952526495744, 46952526495744,
-STORE, 46952526495744, 46952527839231,
-STORE, 46952528150528, 46952528154623,
-STORE, 46952527839232, 46952528150527,
-ERASE, 46952527839232, 46952527839232,
-STORE, 46952527839232, 46952528150527,
-STORE, 46952528179200, 46952528195583,
-STORE, 46952528154624, 46952528179199,
-ERASE, 46952528154624, 46952528154624,
-STORE, 46952528154624, 46952528179199,
-ERASE, 46952528179200, 46952528179200,
-STORE, 46952528179200, 46952528195583,
-STORE, 46952528179200, 46952528207871,
-ERASE, 46952528154624, 46952528154624,
-STORE, 46952528154624, 46952528171007,
-STORE, 46952528171008, 46952528179199,
-ERASE, 46952526340096, 46952526340096,
-STORE, 46952526340096, 46952526344191,
-STORE, 46952526344192, 46952526348287,
-ERASE, 94299866005504, 94299866005504,
-STORE, 94299866005504, 94299866021887,
-STORE, 94299866021888, 94299866025983,
-ERASE, 140680268922880, 140680268922880,
-STORE, 140680268922880, 140680268926975,
-STORE, 140680268926976, 140680268931071,
-ERASE, 46952526233600, 46952526233600,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722874793984, 140737488351231,
-ERASE, 140722874793984, 140722874793984,
-STORE, 140722874793984, 140722874798079,
-STORE, 94448916213760, 94448916926463,
-ERASE, 94448916213760, 94448916213760,
-STORE, 94448916213760, 94448916262911,
-STORE, 94448916262912, 94448916926463,
-ERASE, 94448916262912, 94448916262912,
-STORE, 94448916262912, 94448916807679,
-STORE, 94448916807680, 94448916905983,
-STORE, 94448916905984, 94448916926463,
-STORE, 140389117046784, 140389117218815,
-ERASE, 140389117046784, 140389117046784,
-STORE, 140389117046784, 140389117050879,
-STORE, 140389117050880, 140389117218815,
-ERASE, 140389117050880, 140389117050880,
-STORE, 140389117050880, 140389117173759,
-STORE, 140389117173760, 140389117206527,
-STORE, 140389117206528, 140389117214719,
-STORE, 140389117214720, 140389117218815,
-STORE, 140722875297792, 140722875301887,
-STORE, 140722875285504, 140722875297791,
-STORE, 47243677949952, 47243677958143,
-STORE, 47243677958144, 47243677966335,
-STORE, 47243677966336, 47243678072831,
-STORE, 47243677982720, 47243678072831,
-STORE, 47243677966336, 47243677982719,
-ERASE, 47243677982720, 47243677982720,
-STORE, 47243677982720, 47243678056447,
-STORE, 47243678056448, 47243678072831,
-STORE, 47243678035968, 47243678056447,
-STORE, 47243677982720, 47243678035967,
-ERASE, 47243677982720, 47243677982720,
-STORE, 47243677982720, 47243678035967,
-STORE, 47243678052352, 47243678056447,
-STORE, 47243678035968, 47243678052351,
-ERASE, 47243678035968, 47243678035968,
-STORE, 47243678035968, 47243678052351,
-STORE, 47243678064640, 47243678072831,
-STORE, 47243678056448, 47243678064639,
-ERASE, 47243678056448, 47243678056448,
-STORE, 47243678056448, 47243678064639,
-ERASE, 47243678064640, 47243678064640,
-STORE, 47243678064640, 47243678072831,
-STORE, 47243678072832, 47243679911935,
-STORE, 47243678212096, 47243679911935,
-STORE, 47243678072832, 47243678212095,
-ERASE, 47243678212096, 47243678212096,
-STORE, 47243678212096, 47243679870975,
-STORE, 47243679870976, 47243679911935,
-STORE, 47243679555584, 47243679870975,
-STORE, 47243678212096, 47243679555583,
-ERASE, 47243678212096, 47243678212096,
-STORE, 47243678212096, 47243679555583,
-STORE, 47243679866880, 47243679870975,
-STORE, 47243679555584, 47243679866879,
-ERASE, 47243679555584, 47243679555584,
-STORE, 47243679555584, 47243679866879,
-STORE, 47243679895552, 47243679911935,
-STORE, 47243679870976, 47243679895551,
-ERASE, 47243679870976, 47243679870976,
-STORE, 47243679870976, 47243679895551,
-ERASE, 47243679895552, 47243679895552,
-STORE, 47243679895552, 47243679911935,
-STORE, 47243679895552, 47243679924223,
-ERASE, 47243679870976, 47243679870976,
-STORE, 47243679870976, 47243679887359,
-STORE, 47243679887360, 47243679895551,
-ERASE, 47243678056448, 47243678056448,
-STORE, 47243678056448, 47243678060543,
-STORE, 47243678060544, 47243678064639,
-ERASE, 94448916905984, 94448916905984,
-STORE, 94448916905984, 94448916922367,
-STORE, 94448916922368, 94448916926463,
-ERASE, 140389117206528, 140389117206528,
-STORE, 140389117206528, 140389117210623,
-STORE, 140389117210624, 140389117214719,
-ERASE, 47243677949952, 47243677949952,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733068505088, 140737488351231,
-ERASE, 140733068505088, 140733068505088,
-STORE, 140733068505088, 140733068509183,
-STORE, 94207145750528, 94207146463231,
-ERASE, 94207145750528, 94207145750528,
-STORE, 94207145750528, 94207145799679,
-STORE, 94207145799680, 94207146463231,
-ERASE, 94207145799680, 94207145799680,
-STORE, 94207145799680, 94207146344447,
-STORE, 94207146344448, 94207146442751,
-STORE, 94207146442752, 94207146463231,
-STORE, 140684504911872, 140684505083903,
-ERASE, 140684504911872, 140684504911872,
-STORE, 140684504911872, 140684504915967,
-STORE, 140684504915968, 140684505083903,
-ERASE, 140684504915968, 140684504915968,
-STORE, 140684504915968, 140684505038847,
-STORE, 140684505038848, 140684505071615,
-STORE, 140684505071616, 140684505079807,
-STORE, 140684505079808, 140684505083903,
-STORE, 140733068607488, 140733068611583,
-STORE, 140733068595200, 140733068607487,
-STORE, 46948290084864, 46948290093055,
-STORE, 46948290093056, 46948290101247,
-STORE, 46948290101248, 46948290207743,
-STORE, 46948290117632, 46948290207743,
-STORE, 46948290101248, 46948290117631,
-ERASE, 46948290117632, 46948290117632,
-STORE, 46948290117632, 46948290191359,
-STORE, 46948290191360, 46948290207743,
-STORE, 46948290170880, 46948290191359,
-STORE, 46948290117632, 46948290170879,
-ERASE, 46948290117632, 46948290117632,
-STORE, 46948290117632, 46948290170879,
-STORE, 46948290187264, 46948290191359,
-STORE, 46948290170880, 46948290187263,
-ERASE, 46948290170880, 46948290170880,
-STORE, 46948290170880, 46948290187263,
-STORE, 46948290199552, 46948290207743,
-STORE, 46948290191360, 46948290199551,
-ERASE, 46948290191360, 46948290191360,
-STORE, 46948290191360, 46948290199551,
-ERASE, 46948290199552, 46948290199552,
-STORE, 46948290199552, 46948290207743,
-STORE, 46948290207744, 46948292046847,
-STORE, 46948290347008, 46948292046847,
-STORE, 46948290207744, 46948290347007,
-ERASE, 46948290347008, 46948290347008,
-STORE, 46948290347008, 46948292005887,
-STORE, 46948292005888, 46948292046847,
-STORE, 46948291690496, 46948292005887,
-STORE, 46948290347008, 46948291690495,
-ERASE, 46948290347008, 46948290347008,
-STORE, 46948290347008, 46948291690495,
-STORE, 46948292001792, 46948292005887,
-STORE, 46948291690496, 46948292001791,
-ERASE, 46948291690496, 46948291690496,
-STORE, 46948291690496, 46948292001791,
-STORE, 46948292030464, 46948292046847,
-STORE, 46948292005888, 46948292030463,
-ERASE, 46948292005888, 46948292005888,
-STORE, 46948292005888, 46948292030463,
-ERASE, 46948292030464, 46948292030464,
-STORE, 46948292030464, 46948292046847,
-STORE, 46948292030464, 46948292059135,
-ERASE, 46948292005888, 46948292005888,
-STORE, 46948292005888, 46948292022271,
-STORE, 46948292022272, 46948292030463,
-ERASE, 46948290191360, 46948290191360,
-STORE, 46948290191360, 46948290195455,
-STORE, 46948290195456, 46948290199551,
-ERASE, 94207146442752, 94207146442752,
-STORE, 94207146442752, 94207146459135,
-STORE, 94207146459136, 94207146463231,
-ERASE, 140684505071616, 140684505071616,
-STORE, 140684505071616, 140684505075711,
-STORE, 140684505075712, 140684505079807,
-ERASE, 46948290084864, 46948290084864,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726367158272, 140737488351231,
-ERASE, 140726367158272, 140726367158272,
-STORE, 140726367158272, 140726367162367,
-STORE, 94436124106752, 94436124819455,
-ERASE, 94436124106752, 94436124106752,
-STORE, 94436124106752, 94436124155903,
-STORE, 94436124155904, 94436124819455,
-ERASE, 94436124155904, 94436124155904,
-STORE, 94436124155904, 94436124700671,
-STORE, 94436124700672, 94436124798975,
-STORE, 94436124798976, 94436124819455,
-STORE, 140049025044480, 140049025216511,
-ERASE, 140049025044480, 140049025044480,
-STORE, 140049025044480, 140049025048575,
-STORE, 140049025048576, 140049025216511,
-ERASE, 140049025048576, 140049025048576,
-STORE, 140049025048576, 140049025171455,
-STORE, 140049025171456, 140049025204223,
-STORE, 140049025204224, 140049025212415,
-STORE, 140049025212416, 140049025216511,
-STORE, 140726367256576, 140726367260671,
-STORE, 140726367244288, 140726367256575,
-STORE, 47583769952256, 47583769960447,
-STORE, 47583769960448, 47583769968639,
-STORE, 47583769968640, 47583770075135,
-STORE, 47583769985024, 47583770075135,
-STORE, 47583769968640, 47583769985023,
-ERASE, 47583769985024, 47583769985024,
-STORE, 47583769985024, 47583770058751,
-STORE, 47583770058752, 47583770075135,
-STORE, 47583770038272, 47583770058751,
-STORE, 47583769985024, 47583770038271,
-ERASE, 47583769985024, 47583769985024,
-STORE, 47583769985024, 47583770038271,
-STORE, 47583770054656, 47583770058751,
-STORE, 47583770038272, 47583770054655,
-ERASE, 47583770038272, 47583770038272,
-STORE, 47583770038272, 47583770054655,
-STORE, 47583770066944, 47583770075135,
-STORE, 47583770058752, 47583770066943,
-ERASE, 47583770058752, 47583770058752,
-STORE, 47583770058752, 47583770066943,
-ERASE, 47583770066944, 47583770066944,
-STORE, 47583770066944, 47583770075135,
-STORE, 47583770075136, 47583771914239,
-STORE, 47583770214400, 47583771914239,
-STORE, 47583770075136, 47583770214399,
-ERASE, 47583770214400, 47583770214400,
-STORE, 47583770214400, 47583771873279,
-STORE, 47583771873280, 47583771914239,
-STORE, 47583771557888, 47583771873279,
-STORE, 47583770214400, 47583771557887,
-ERASE, 47583770214400, 47583770214400,
-STORE, 47583770214400, 47583771557887,
-STORE, 47583771869184, 47583771873279,
-STORE, 47583771557888, 47583771869183,
-ERASE, 47583771557888, 47583771557888,
-STORE, 47583771557888, 47583771869183,
-STORE, 47583771897856, 47583771914239,
-STORE, 47583771873280, 47583771897855,
-ERASE, 47583771873280, 47583771873280,
-STORE, 47583771873280, 47583771897855,
-ERASE, 47583771897856, 47583771897856,
-STORE, 47583771897856, 47583771914239,
-STORE, 47583771897856, 47583771926527,
-ERASE, 47583771873280, 47583771873280,
-STORE, 47583771873280, 47583771889663,
-STORE, 47583771889664, 47583771897855,
-ERASE, 47583770058752, 47583770058752,
-STORE, 47583770058752, 47583770062847,
-STORE, 47583770062848, 47583770066943,
-ERASE, 94436124798976, 94436124798976,
-STORE, 94436124798976, 94436124815359,
-STORE, 94436124815360, 94436124819455,
-ERASE, 140049025204224, 140049025204224,
-STORE, 140049025204224, 140049025208319,
-STORE, 140049025208320, 140049025212415,
-ERASE, 47583769952256, 47583769952256,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727116099584, 140737488351231,
-ERASE, 140727116099584, 140727116099584,
-STORE, 140727116099584, 140727116103679,
-STORE, 94166319734784, 94166320447487,
-ERASE, 94166319734784, 94166319734784,
-STORE, 94166319734784, 94166319783935,
-STORE, 94166319783936, 94166320447487,
-ERASE, 94166319783936, 94166319783936,
-STORE, 94166319783936, 94166320328703,
-STORE, 94166320328704, 94166320427007,
-STORE, 94166320427008, 94166320447487,
-STORE, 139976559542272, 139976559714303,
-ERASE, 139976559542272, 139976559542272,
-STORE, 139976559542272, 139976559546367,
-STORE, 139976559546368, 139976559714303,
-ERASE, 139976559546368, 139976559546368,
-STORE, 139976559546368, 139976559669247,
-STORE, 139976559669248, 139976559702015,
-STORE, 139976559702016, 139976559710207,
-STORE, 139976559710208, 139976559714303,
-STORE, 140727116222464, 140727116226559,
-STORE, 140727116210176, 140727116222463,
-STORE, 47656235454464, 47656235462655,
-STORE, 47656235462656, 47656235470847,
-STORE, 47656235470848, 47656235577343,
-STORE, 47656235487232, 47656235577343,
-STORE, 47656235470848, 47656235487231,
-ERASE, 47656235487232, 47656235487232,
-STORE, 47656235487232, 47656235560959,
-STORE, 47656235560960, 47656235577343,
-STORE, 47656235540480, 47656235560959,
-STORE, 47656235487232, 47656235540479,
-ERASE, 47656235487232, 47656235487232,
-STORE, 47656235487232, 47656235540479,
-STORE, 47656235556864, 47656235560959,
-STORE, 47656235540480, 47656235556863,
-ERASE, 47656235540480, 47656235540480,
-STORE, 47656235540480, 47656235556863,
-STORE, 47656235569152, 47656235577343,
-STORE, 47656235560960, 47656235569151,
-ERASE, 47656235560960, 47656235560960,
-STORE, 47656235560960, 47656235569151,
-ERASE, 47656235569152, 47656235569152,
-STORE, 47656235569152, 47656235577343,
-STORE, 47656235577344, 47656237416447,
-STORE, 47656235716608, 47656237416447,
-STORE, 47656235577344, 47656235716607,
-ERASE, 47656235716608, 47656235716608,
-STORE, 47656235716608, 47656237375487,
-STORE, 47656237375488, 47656237416447,
-STORE, 47656237060096, 47656237375487,
-STORE, 47656235716608, 47656237060095,
-ERASE, 47656235716608, 47656235716608,
-STORE, 47656235716608, 47656237060095,
-STORE, 47656237371392, 47656237375487,
-STORE, 47656237060096, 47656237371391,
-ERASE, 47656237060096, 47656237060096,
-STORE, 47656237060096, 47656237371391,
-STORE, 47656237400064, 47656237416447,
-STORE, 47656237375488, 47656237400063,
-ERASE, 47656237375488, 47656237375488,
-STORE, 47656237375488, 47656237400063,
-ERASE, 47656237400064, 47656237400064,
-STORE, 47656237400064, 47656237416447,
-STORE, 47656237400064, 47656237428735,
-ERASE, 47656237375488, 47656237375488,
-STORE, 47656237375488, 47656237391871,
-STORE, 47656237391872, 47656237400063,
-ERASE, 47656235560960, 47656235560960,
-STORE, 47656235560960, 47656235565055,
-STORE, 47656235565056, 47656235569151,
-ERASE, 94166320427008, 94166320427008,
-STORE, 94166320427008, 94166320443391,
-STORE, 94166320443392, 94166320447487,
-ERASE, 139976559702016, 139976559702016,
-STORE, 139976559702016, 139976559706111,
-STORE, 139976559706112, 139976559710207,
-ERASE, 47656235454464, 47656235454464,
-STORE, 94166332153856, 94166332289023,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726412816384, 140737488351231,
-ERASE, 140726412816384, 140726412816384,
-STORE, 140726412816384, 140726412820479,
-STORE, 94094884507648, 94094885220351,
-ERASE, 94094884507648, 94094884507648,
-STORE, 94094884507648, 94094884556799,
-STORE, 94094884556800, 94094885220351,
-ERASE, 94094884556800, 94094884556800,
-STORE, 94094884556800, 94094885101567,
-STORE, 94094885101568, 94094885199871,
-STORE, 94094885199872, 94094885220351,
-STORE, 139773773938688, 139773774110719,
-ERASE, 139773773938688, 139773773938688,
-STORE, 139773773938688, 139773773942783,
-STORE, 139773773942784, 139773774110719,
-ERASE, 139773773942784, 139773773942784,
-STORE, 139773773942784, 139773774065663,
-STORE, 139773774065664, 139773774098431,
-STORE, 139773774098432, 139773774106623,
-STORE, 139773774106624, 139773774110719,
-STORE, 140726412963840, 140726412967935,
-STORE, 140726412951552, 140726412963839,
-STORE, 47859021058048, 47859021066239,
-STORE, 47859021066240, 47859021074431,
-STORE, 47859021074432, 47859021180927,
-STORE, 47859021090816, 47859021180927,
-STORE, 47859021074432, 47859021090815,
-ERASE, 47859021090816, 47859021090816,
-STORE, 47859021090816, 47859021164543,
-STORE, 47859021164544, 47859021180927,
-STORE, 47859021144064, 47859021164543,
-STORE, 47859021090816, 47859021144063,
-ERASE, 47859021090816, 47859021090816,
-STORE, 47859021090816, 47859021144063,
-STORE, 47859021160448, 47859021164543,
-STORE, 47859021144064, 47859021160447,
-ERASE, 47859021144064, 47859021144064,
-STORE, 47859021144064, 47859021160447,
-STORE, 47859021172736, 47859021180927,
-STORE, 47859021164544, 47859021172735,
-ERASE, 47859021164544, 47859021164544,
-STORE, 47859021164544, 47859021172735,
-ERASE, 47859021172736, 47859021172736,
-STORE, 47859021172736, 47859021180927,
-STORE, 47859021180928, 47859023020031,
-STORE, 47859021320192, 47859023020031,
-STORE, 47859021180928, 47859021320191,
-ERASE, 47859021320192, 47859021320192,
-STORE, 47859021320192, 47859022979071,
-STORE, 47859022979072, 47859023020031,
-STORE, 47859022663680, 47859022979071,
-STORE, 47859021320192, 47859022663679,
-ERASE, 47859021320192, 47859021320192,
-STORE, 47859021320192, 47859022663679,
-STORE, 47859022974976, 47859022979071,
-STORE, 47859022663680, 47859022974975,
-ERASE, 47859022663680, 47859022663680,
-STORE, 47859022663680, 47859022974975,
-STORE, 47859023003648, 47859023020031,
-STORE, 47859022979072, 47859023003647,
-ERASE, 47859022979072, 47859022979072,
-STORE, 47859022979072, 47859023003647,
-ERASE, 47859023003648, 47859023003648,
-STORE, 47859023003648, 47859023020031,
-STORE, 47859023003648, 47859023032319,
-ERASE, 47859022979072, 47859022979072,
-STORE, 47859022979072, 47859022995455,
-STORE, 47859022995456, 47859023003647,
-ERASE, 47859021164544, 47859021164544,
-STORE, 47859021164544, 47859021168639,
-STORE, 47859021168640, 47859021172735,
-ERASE, 94094885199872, 94094885199872,
-STORE, 94094885199872, 94094885216255,
-STORE, 94094885216256, 94094885220351,
-ERASE, 139773774098432, 139773774098432,
-STORE, 139773774098432, 139773774102527,
-STORE, 139773774102528, 139773774106623,
-ERASE, 47859021058048, 47859021058048,
-STORE, 94094901108736, 94094901243903,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736567963648, 140737488351231,
-ERASE, 140736567963648, 140736567963648,
-STORE, 140736567963648, 140736567967743,
-STORE, 94924425748480, 94924426461183,
-ERASE, 94924425748480, 94924425748480,
-STORE, 94924425748480, 94924425797631,
-STORE, 94924425797632, 94924426461183,
-ERASE, 94924425797632, 94924425797632,
-STORE, 94924425797632, 94924426342399,
-STORE, 94924426342400, 94924426440703,
-STORE, 94924426440704, 94924426461183,
-STORE, 140042126319616, 140042126491647,
-ERASE, 140042126319616, 140042126319616,
-STORE, 140042126319616, 140042126323711,
-STORE, 140042126323712, 140042126491647,
-ERASE, 140042126323712, 140042126323712,
-STORE, 140042126323712, 140042126446591,
-STORE, 140042126446592, 140042126479359,
-STORE, 140042126479360, 140042126487551,
-STORE, 140042126487552, 140042126491647,
-STORE, 140736568672256, 140736568676351,
-STORE, 140736568659968, 140736568672255,
-STORE, 47590668677120, 47590668685311,
-STORE, 47590668685312, 47590668693503,
-STORE, 47590668693504, 47590668799999,
-STORE, 47590668709888, 47590668799999,
-STORE, 47590668693504, 47590668709887,
-ERASE, 47590668709888, 47590668709888,
-STORE, 47590668709888, 47590668783615,
-STORE, 47590668783616, 47590668799999,
-STORE, 47590668763136, 47590668783615,
-STORE, 47590668709888, 47590668763135,
-ERASE, 47590668709888, 47590668709888,
-STORE, 47590668709888, 47590668763135,
-STORE, 47590668779520, 47590668783615,
-STORE, 47590668763136, 47590668779519,
-ERASE, 47590668763136, 47590668763136,
-STORE, 47590668763136, 47590668779519,
-STORE, 47590668791808, 47590668799999,
-STORE, 47590668783616, 47590668791807,
-ERASE, 47590668783616, 47590668783616,
-STORE, 47590668783616, 47590668791807,
-ERASE, 47590668791808, 47590668791808,
-STORE, 47590668791808, 47590668799999,
-STORE, 47590668800000, 47590670639103,
-STORE, 47590668939264, 47590670639103,
-STORE, 47590668800000, 47590668939263,
-ERASE, 47590668939264, 47590668939264,
-STORE, 47590668939264, 47590670598143,
-STORE, 47590670598144, 47590670639103,
-STORE, 47590670282752, 47590670598143,
-STORE, 47590668939264, 47590670282751,
-ERASE, 47590668939264, 47590668939264,
-STORE, 47590668939264, 47590670282751,
-STORE, 47590670594048, 47590670598143,
-STORE, 47590670282752, 47590670594047,
-ERASE, 47590670282752, 47590670282752,
-STORE, 47590670282752, 47590670594047,
-STORE, 47590670622720, 47590670639103,
-STORE, 47590670598144, 47590670622719,
-ERASE, 47590670598144, 47590670598144,
-STORE, 47590670598144, 47590670622719,
-ERASE, 47590670622720, 47590670622720,
-STORE, 47590670622720, 47590670639103,
-STORE, 47590670622720, 47590670651391,
-ERASE, 47590670598144, 47590670598144,
-STORE, 47590670598144, 47590670614527,
-STORE, 47590670614528, 47590670622719,
-ERASE, 47590668783616, 47590668783616,
-STORE, 47590668783616, 47590668787711,
-STORE, 47590668787712, 47590668791807,
-ERASE, 94924426440704, 94924426440704,
-STORE, 94924426440704, 94924426457087,
-STORE, 94924426457088, 94924426461183,
-ERASE, 140042126479360, 140042126479360,
-STORE, 140042126479360, 140042126483455,
-STORE, 140042126483456, 140042126487551,
-ERASE, 47590668677120, 47590668677120,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733281439744, 140737488351231,
-ERASE, 140733281439744, 140733281439744,
-STORE, 140733281439744, 140733281443839,
-STORE, 94490667069440, 94490667782143,
-ERASE, 94490667069440, 94490667069440,
-STORE, 94490667069440, 94490667118591,
-STORE, 94490667118592, 94490667782143,
-ERASE, 94490667118592, 94490667118592,
-STORE, 94490667118592, 94490667663359,
-STORE, 94490667663360, 94490667761663,
-STORE, 94490667761664, 94490667782143,
-STORE, 139878215118848, 139878215290879,
-ERASE, 139878215118848, 139878215118848,
-STORE, 139878215118848, 139878215122943,
-STORE, 139878215122944, 139878215290879,
-ERASE, 139878215122944, 139878215122944,
-STORE, 139878215122944, 139878215245823,
-STORE, 139878215245824, 139878215278591,
-STORE, 139878215278592, 139878215286783,
-STORE, 139878215286784, 139878215290879,
-STORE, 140733281464320, 140733281468415,
-STORE, 140733281452032, 140733281464319,
-STORE, 47754579877888, 47754579886079,
-STORE, 47754579886080, 47754579894271,
-STORE, 47754579894272, 47754580000767,
-STORE, 47754579910656, 47754580000767,
-STORE, 47754579894272, 47754579910655,
-ERASE, 47754579910656, 47754579910656,
-STORE, 47754579910656, 47754579984383,
-STORE, 47754579984384, 47754580000767,
-STORE, 47754579963904, 47754579984383,
-STORE, 47754579910656, 47754579963903,
-ERASE, 47754579910656, 47754579910656,
-STORE, 47754579910656, 47754579963903,
-STORE, 47754579980288, 47754579984383,
-STORE, 47754579963904, 47754579980287,
-ERASE, 47754579963904, 47754579963904,
-STORE, 47754579963904, 47754579980287,
-STORE, 47754579992576, 47754580000767,
-STORE, 47754579984384, 47754579992575,
-ERASE, 47754579984384, 47754579984384,
-STORE, 47754579984384, 47754579992575,
-ERASE, 47754579992576, 47754579992576,
-STORE, 47754579992576, 47754580000767,
-STORE, 47754580000768, 47754581839871,
-STORE, 47754580140032, 47754581839871,
-STORE, 47754580000768, 47754580140031,
-ERASE, 47754580140032, 47754580140032,
-STORE, 47754580140032, 47754581798911,
-STORE, 47754581798912, 47754581839871,
-STORE, 47754581483520, 47754581798911,
-STORE, 47754580140032, 47754581483519,
-ERASE, 47754580140032, 47754580140032,
-STORE, 47754580140032, 47754581483519,
-STORE, 47754581794816, 47754581798911,
-STORE, 47754581483520, 47754581794815,
-ERASE, 47754581483520, 47754581483520,
-STORE, 47754581483520, 47754581794815,
-STORE, 47754581823488, 47754581839871,
-STORE, 47754581798912, 47754581823487,
-ERASE, 47754581798912, 47754581798912,
-STORE, 47754581798912, 47754581823487,
-ERASE, 47754581823488, 47754581823488,
-STORE, 47754581823488, 47754581839871,
-STORE, 47754581823488, 47754581852159,
-ERASE, 47754581798912, 47754581798912,
-STORE, 47754581798912, 47754581815295,
-STORE, 47754581815296, 47754581823487,
-ERASE, 47754579984384, 47754579984384,
-STORE, 47754579984384, 47754579988479,
-STORE, 47754579988480, 47754579992575,
-ERASE, 94490667761664, 94490667761664,
-STORE, 94490667761664, 94490667778047,
-STORE, 94490667778048, 94490667782143,
-ERASE, 139878215278592, 139878215278592,
-STORE, 139878215278592, 139878215282687,
-STORE, 139878215282688, 139878215286783,
-ERASE, 47754579877888, 47754579877888,
-STORE, 94490669649920, 94490669785087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140735382188032, 140737488351231,
-ERASE, 140735382188032, 140735382188032,
-STORE, 140735382188032, 140735382192127,
-STORE, 94150181302272, 94150182014975,
-ERASE, 94150181302272, 94150181302272,
-STORE, 94150181302272, 94150181351423,
-STORE, 94150181351424, 94150182014975,
-ERASE, 94150181351424, 94150181351424,
-STORE, 94150181351424, 94150181896191,
-STORE, 94150181896192, 94150181994495,
-STORE, 94150181994496, 94150182014975,
-STORE, 139679752458240, 139679752630271,
-ERASE, 139679752458240, 139679752458240,
-STORE, 139679752458240, 139679752462335,
-STORE, 139679752462336, 139679752630271,
-ERASE, 139679752462336, 139679752462336,
-STORE, 139679752462336, 139679752585215,
-STORE, 139679752585216, 139679752617983,
-STORE, 139679752617984, 139679752626175,
-STORE, 139679752626176, 139679752630271,
-STORE, 140735382536192, 140735382540287,
-STORE, 140735382523904, 140735382536191,
-STORE, 47953042538496, 47953042546687,
-STORE, 47953042546688, 47953042554879,
-STORE, 47953042554880, 47953042661375,
-STORE, 47953042571264, 47953042661375,
-STORE, 47953042554880, 47953042571263,
-ERASE, 47953042571264, 47953042571264,
-STORE, 47953042571264, 47953042644991,
-STORE, 47953042644992, 47953042661375,
-STORE, 47953042624512, 47953042644991,
-STORE, 47953042571264, 47953042624511,
-ERASE, 47953042571264, 47953042571264,
-STORE, 47953042571264, 47953042624511,
-STORE, 47953042640896, 47953042644991,
-STORE, 47953042624512, 47953042640895,
-ERASE, 47953042624512, 47953042624512,
-STORE, 47953042624512, 47953042640895,
-STORE, 47953042653184, 47953042661375,
-STORE, 47953042644992, 47953042653183,
-ERASE, 47953042644992, 47953042644992,
-STORE, 47953042644992, 47953042653183,
-ERASE, 47953042653184, 47953042653184,
-STORE, 47953042653184, 47953042661375,
-STORE, 47953042661376, 47953044500479,
-STORE, 47953042800640, 47953044500479,
-STORE, 47953042661376, 47953042800639,
-ERASE, 47953042800640, 47953042800640,
-STORE, 47953042800640, 47953044459519,
-STORE, 47953044459520, 47953044500479,
-STORE, 47953044144128, 47953044459519,
-STORE, 47953042800640, 47953044144127,
-ERASE, 47953042800640, 47953042800640,
-STORE, 47953042800640, 47953044144127,
-STORE, 47953044455424, 47953044459519,
-STORE, 47953044144128, 47953044455423,
-ERASE, 47953044144128, 47953044144128,
-STORE, 47953044144128, 47953044455423,
-STORE, 47953044484096, 47953044500479,
-STORE, 47953044459520, 47953044484095,
-ERASE, 47953044459520, 47953044459520,
-STORE, 47953044459520, 47953044484095,
-ERASE, 47953044484096, 47953044484096,
-STORE, 47953044484096, 47953044500479,
-STORE, 47953044484096, 47953044512767,
-ERASE, 47953044459520, 47953044459520,
-STORE, 47953044459520, 47953044475903,
-STORE, 47953044475904, 47953044484095,
-ERASE, 47953042644992, 47953042644992,
-STORE, 47953042644992, 47953042649087,
-STORE, 47953042649088, 47953042653183,
-ERASE, 94150181994496, 94150181994496,
-STORE, 94150181994496, 94150182010879,
-STORE, 94150182010880, 94150182014975,
-ERASE, 139679752617984, 139679752617984,
-STORE, 139679752617984, 139679752622079,
-STORE, 139679752622080, 139679752626175,
-ERASE, 47953042538496, 47953042538496,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737044123648, 140737488351231,
-ERASE, 140737044123648, 140737044123648,
-STORE, 140737044123648, 140737044127743,
-STORE, 94425324294144, 94425325006847,
-ERASE, 94425324294144, 94425324294144,
-STORE, 94425324294144, 94425324343295,
-STORE, 94425324343296, 94425325006847,
-ERASE, 94425324343296, 94425324343296,
-STORE, 94425324343296, 94425324888063,
-STORE, 94425324888064, 94425324986367,
-STORE, 94425324986368, 94425325006847,
-STORE, 140382015016960, 140382015188991,
-ERASE, 140382015016960, 140382015016960,
-STORE, 140382015016960, 140382015021055,
-STORE, 140382015021056, 140382015188991,
-ERASE, 140382015021056, 140382015021056,
-STORE, 140382015021056, 140382015143935,
-STORE, 140382015143936, 140382015176703,
-STORE, 140382015176704, 140382015184895,
-STORE, 140382015184896, 140382015188991,
-STORE, 140737045585920, 140737045590015,
-STORE, 140737045573632, 140737045585919,
-STORE, 47250779979776, 47250779987967,
-STORE, 47250779987968, 47250779996159,
-STORE, 47250779996160, 47250780102655,
-STORE, 47250780012544, 47250780102655,
-STORE, 47250779996160, 47250780012543,
-ERASE, 47250780012544, 47250780012544,
-STORE, 47250780012544, 47250780086271,
-STORE, 47250780086272, 47250780102655,
-STORE, 47250780065792, 47250780086271,
-STORE, 47250780012544, 47250780065791,
-ERASE, 47250780012544, 47250780012544,
-STORE, 47250780012544, 47250780065791,
-STORE, 47250780082176, 47250780086271,
-STORE, 47250780065792, 47250780082175,
-ERASE, 47250780065792, 47250780065792,
-STORE, 47250780065792, 47250780082175,
-STORE, 47250780094464, 47250780102655,
-STORE, 47250780086272, 47250780094463,
-ERASE, 47250780086272, 47250780086272,
-STORE, 47250780086272, 47250780094463,
-ERASE, 47250780094464, 47250780094464,
-STORE, 47250780094464, 47250780102655,
-STORE, 47250780102656, 47250781941759,
-STORE, 47250780241920, 47250781941759,
-STORE, 47250780102656, 47250780241919,
-ERASE, 47250780241920, 47250780241920,
-STORE, 47250780241920, 47250781900799,
-STORE, 47250781900800, 47250781941759,
-STORE, 47250781585408, 47250781900799,
-STORE, 47250780241920, 47250781585407,
-ERASE, 47250780241920, 47250780241920,
-STORE, 47250780241920, 47250781585407,
-STORE, 47250781896704, 47250781900799,
-STORE, 47250781585408, 47250781896703,
-ERASE, 47250781585408, 47250781585408,
-STORE, 47250781585408, 47250781896703,
-STORE, 47250781925376, 47250781941759,
-STORE, 47250781900800, 47250781925375,
-ERASE, 47250781900800, 47250781900800,
-STORE, 47250781900800, 47250781925375,
-ERASE, 47250781925376, 47250781925376,
-STORE, 47250781925376, 47250781941759,
-STORE, 47250781925376, 47250781954047,
-ERASE, 47250781900800, 47250781900800,
-STORE, 47250781900800, 47250781917183,
-STORE, 47250781917184, 47250781925375,
-ERASE, 47250780086272, 47250780086272,
-STORE, 47250780086272, 47250780090367,
-STORE, 47250780090368, 47250780094463,
-ERASE, 94425324986368, 94425324986368,
-STORE, 94425324986368, 94425325002751,
-STORE, 94425325002752, 94425325006847,
-ERASE, 140382015176704, 140382015176704,
-STORE, 140382015176704, 140382015180799,
-STORE, 140382015180800, 140382015184895,
-ERASE, 47250779979776, 47250779979776,
-STORE, 94425351438336, 94425351573503,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736801144832, 140737488351231,
-ERASE, 140736801144832, 140736801144832,
-STORE, 140736801144832, 140736801148927,
-STORE, 94629429358592, 94629430071295,
-ERASE, 94629429358592, 94629429358592,
-STORE, 94629429358592, 94629429407743,
-STORE, 94629429407744, 94629430071295,
-ERASE, 94629429407744, 94629429407744,
-STORE, 94629429407744, 94629429952511,
-STORE, 94629429952512, 94629430050815,
-STORE, 94629430050816, 94629430071295,
-STORE, 139801685483520, 139801685655551,
-ERASE, 139801685483520, 139801685483520,
-STORE, 139801685483520, 139801685487615,
-STORE, 139801685487616, 139801685655551,
-ERASE, 139801685487616, 139801685487616,
-STORE, 139801685487616, 139801685610495,
-STORE, 139801685610496, 139801685643263,
-STORE, 139801685643264, 139801685651455,
-STORE, 139801685651456, 139801685655551,
-STORE, 140736801198080, 140736801202175,
-STORE, 140736801185792, 140736801198079,
-STORE, 47831109513216, 47831109521407,
-STORE, 47831109521408, 47831109529599,
-STORE, 47831109529600, 47831109636095,
-STORE, 47831109545984, 47831109636095,
-STORE, 47831109529600, 47831109545983,
-ERASE, 47831109545984, 47831109545984,
-STORE, 47831109545984, 47831109619711,
-STORE, 47831109619712, 47831109636095,
-STORE, 47831109599232, 47831109619711,
-STORE, 47831109545984, 47831109599231,
-ERASE, 47831109545984, 47831109545984,
-STORE, 47831109545984, 47831109599231,
-STORE, 47831109615616, 47831109619711,
-STORE, 47831109599232, 47831109615615,
-ERASE, 47831109599232, 47831109599232,
-STORE, 47831109599232, 47831109615615,
-STORE, 47831109627904, 47831109636095,
-STORE, 47831109619712, 47831109627903,
-ERASE, 47831109619712, 47831109619712,
-STORE, 47831109619712, 47831109627903,
-ERASE, 47831109627904, 47831109627904,
-STORE, 47831109627904, 47831109636095,
-STORE, 47831109636096, 47831111475199,
-STORE, 47831109775360, 47831111475199,
-STORE, 47831109636096, 47831109775359,
-ERASE, 47831109775360, 47831109775360,
-STORE, 47831109775360, 47831111434239,
-STORE, 47831111434240, 47831111475199,
-STORE, 47831111118848, 47831111434239,
-STORE, 47831109775360, 47831111118847,
-ERASE, 47831109775360, 47831109775360,
-STORE, 47831109775360, 47831111118847,
-STORE, 47831111430144, 47831111434239,
-STORE, 47831111118848, 47831111430143,
-ERASE, 47831111118848, 47831111118848,
-STORE, 47831111118848, 47831111430143,
-STORE, 47831111458816, 47831111475199,
-STORE, 47831111434240, 47831111458815,
-ERASE, 47831111434240, 47831111434240,
-STORE, 47831111434240, 47831111458815,
-ERASE, 47831111458816, 47831111458816,
-STORE, 47831111458816, 47831111475199,
-STORE, 47831111458816, 47831111487487,
-ERASE, 47831111434240, 47831111434240,
-STORE, 47831111434240, 47831111450623,
-STORE, 47831111450624, 47831111458815,
-ERASE, 47831109619712, 47831109619712,
-STORE, 47831109619712, 47831109623807,
-STORE, 47831109623808, 47831109627903,
-ERASE, 94629430050816, 94629430050816,
-STORE, 94629430050816, 94629430067199,
-STORE, 94629430067200, 94629430071295,
-ERASE, 139801685643264, 139801685643264,
-STORE, 139801685643264, 139801685647359,
-STORE, 139801685647360, 139801685651455,
-ERASE, 47831109513216, 47831109513216,
-STORE, 140737488347136, 140737488351231,
-STORE, 140729419612160, 140737488351231,
-ERASE, 140729419612160, 140729419612160,
-STORE, 140729419612160, 140729419616255,
-STORE, 94443354148864, 94443354861567,
-ERASE, 94443354148864, 94443354148864,
-STORE, 94443354148864, 94443354198015,
-STORE, 94443354198016, 94443354861567,
-ERASE, 94443354198016, 94443354198016,
-STORE, 94443354198016, 94443354742783,
-STORE, 94443354742784, 94443354841087,
-STORE, 94443354841088, 94443354861567,
-STORE, 139741700038656, 139741700210687,
-ERASE, 139741700038656, 139741700038656,
-STORE, 139741700038656, 139741700042751,
-STORE, 139741700042752, 139741700210687,
-ERASE, 139741700042752, 139741700042752,
-STORE, 139741700042752, 139741700165631,
-STORE, 139741700165632, 139741700198399,
-STORE, 139741700198400, 139741700206591,
-STORE, 139741700206592, 139741700210687,
-STORE, 140729420574720, 140729420578815,
-STORE, 140729420562432, 140729420574719,
-STORE, 47891094958080, 47891094966271,
-STORE, 47891094966272, 47891094974463,
-STORE, 47891094974464, 47891095080959,
-STORE, 47891094990848, 47891095080959,
-STORE, 47891094974464, 47891094990847,
-ERASE, 47891094990848, 47891094990848,
-STORE, 47891094990848, 47891095064575,
-STORE, 47891095064576, 47891095080959,
-STORE, 47891095044096, 47891095064575,
-STORE, 47891094990848, 47891095044095,
-ERASE, 47891094990848, 47891094990848,
-STORE, 47891094990848, 47891095044095,
-STORE, 47891095060480, 47891095064575,
-STORE, 47891095044096, 47891095060479,
-ERASE, 47891095044096, 47891095044096,
-STORE, 47891095044096, 47891095060479,
-STORE, 47891095072768, 47891095080959,
-STORE, 47891095064576, 47891095072767,
-ERASE, 47891095064576, 47891095064576,
-STORE, 47891095064576, 47891095072767,
-ERASE, 47891095072768, 47891095072768,
-STORE, 47891095072768, 47891095080959,
-STORE, 47891095080960, 47891096920063,
-STORE, 47891095220224, 47891096920063,
-STORE, 47891095080960, 47891095220223,
-ERASE, 47891095220224, 47891095220224,
-STORE, 47891095220224, 47891096879103,
-STORE, 47891096879104, 47891096920063,
-STORE, 47891096563712, 47891096879103,
-STORE, 47891095220224, 47891096563711,
-ERASE, 47891095220224, 47891095220224,
-STORE, 47891095220224, 47891096563711,
-STORE, 47891096875008, 47891096879103,
-STORE, 47891096563712, 47891096875007,
-ERASE, 47891096563712, 47891096563712,
-STORE, 47891096563712, 47891096875007,
-STORE, 47891096903680, 47891096920063,
-STORE, 47891096879104, 47891096903679,
-ERASE, 47891096879104, 47891096879104,
-STORE, 47891096879104, 47891096903679,
-ERASE, 47891096903680, 47891096903680,
-STORE, 47891096903680, 47891096920063,
-STORE, 47891096903680, 47891096932351,
-ERASE, 47891096879104, 47891096879104,
-STORE, 47891096879104, 47891096895487,
-STORE, 47891096895488, 47891096903679,
-ERASE, 47891095064576, 47891095064576,
-STORE, 47891095064576, 47891095068671,
-STORE, 47891095068672, 47891095072767,
-ERASE, 94443354841088, 94443354841088,
-STORE, 94443354841088, 94443354857471,
-STORE, 94443354857472, 94443354861567,
-ERASE, 139741700198400, 139741700198400,
-STORE, 139741700198400, 139741700202495,
-STORE, 139741700202496, 139741700206591,
-ERASE, 47891094958080, 47891094958080,
-STORE, 94443360825344, 94443360960511,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722961661952, 140737488351231,
-ERASE, 140722961661952, 140722961661952,
-STORE, 140722961661952, 140722961666047,
-STORE, 94878388944896, 94878389657599,
-ERASE, 94878388944896, 94878388944896,
-STORE, 94878388944896, 94878388994047,
-STORE, 94878388994048, 94878389657599,
-ERASE, 94878388994048, 94878388994048,
-STORE, 94878388994048, 94878389538815,
-STORE, 94878389538816, 94878389637119,
-STORE, 94878389637120, 94878389657599,
-STORE, 140210690056192, 140210690228223,
-ERASE, 140210690056192, 140210690056192,
-STORE, 140210690056192, 140210690060287,
-STORE, 140210690060288, 140210690228223,
-ERASE, 140210690060288, 140210690060288,
-STORE, 140210690060288, 140210690183167,
-STORE, 140210690183168, 140210690215935,
-STORE, 140210690215936, 140210690224127,
-STORE, 140210690224128, 140210690228223,
-STORE, 140722963148800, 140722963152895,
-STORE, 140722963136512, 140722963148799,
-STORE, 47422104940544, 47422104948735,
-STORE, 47422104948736, 47422104956927,
-STORE, 47422104956928, 47422105063423,
-STORE, 47422104973312, 47422105063423,
-STORE, 47422104956928, 47422104973311,
-ERASE, 47422104973312, 47422104973312,
-STORE, 47422104973312, 47422105047039,
-STORE, 47422105047040, 47422105063423,
-STORE, 47422105026560, 47422105047039,
-STORE, 47422104973312, 47422105026559,
-ERASE, 47422104973312, 47422104973312,
-STORE, 47422104973312, 47422105026559,
-STORE, 47422105042944, 47422105047039,
-STORE, 47422105026560, 47422105042943,
-ERASE, 47422105026560, 47422105026560,
-STORE, 47422105026560, 47422105042943,
-STORE, 47422105055232, 47422105063423,
-STORE, 47422105047040, 47422105055231,
-ERASE, 47422105047040, 47422105047040,
-STORE, 47422105047040, 47422105055231,
-ERASE, 47422105055232, 47422105055232,
-STORE, 47422105055232, 47422105063423,
-STORE, 47422105063424, 47422106902527,
-STORE, 47422105202688, 47422106902527,
-STORE, 47422105063424, 47422105202687,
-ERASE, 47422105202688, 47422105202688,
-STORE, 47422105202688, 47422106861567,
-STORE, 47422106861568, 47422106902527,
-STORE, 47422106546176, 47422106861567,
-STORE, 47422105202688, 47422106546175,
-ERASE, 47422105202688, 47422105202688,
-STORE, 47422105202688, 47422106546175,
-STORE, 47422106857472, 47422106861567,
-STORE, 47422106546176, 47422106857471,
-ERASE, 47422106546176, 47422106546176,
-STORE, 47422106546176, 47422106857471,
-STORE, 47422106886144, 47422106902527,
-STORE, 47422106861568, 47422106886143,
-ERASE, 47422106861568, 47422106861568,
-STORE, 47422106861568, 47422106886143,
-ERASE, 47422106886144, 47422106886144,
-STORE, 47422106886144, 47422106902527,
-STORE, 47422106886144, 47422106914815,
-ERASE, 47422106861568, 47422106861568,
-STORE, 47422106861568, 47422106877951,
-STORE, 47422106877952, 47422106886143,
-ERASE, 47422105047040, 47422105047040,
-STORE, 47422105047040, 47422105051135,
-STORE, 47422105051136, 47422105055231,
-ERASE, 94878389637120, 94878389637120,
-STORE, 94878389637120, 94878389653503,
-STORE, 94878389653504, 94878389657599,
-ERASE, 140210690215936, 140210690215936,
-STORE, 140210690215936, 140210690220031,
-STORE, 140210690220032, 140210690224127,
-ERASE, 47422104940544, 47422104940544,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727690309632, 140737488351231,
-ERASE, 140727690309632, 140727690309632,
-STORE, 140727690309632, 140727690313727,
-STORE, 94121892208640, 94121892921343,
-ERASE, 94121892208640, 94121892208640,
-STORE, 94121892208640, 94121892257791,
-STORE, 94121892257792, 94121892921343,
-ERASE, 94121892257792, 94121892257792,
-STORE, 94121892257792, 94121892802559,
-STORE, 94121892802560, 94121892900863,
-STORE, 94121892900864, 94121892921343,
-STORE, 140662438326272, 140662438498303,
-ERASE, 140662438326272, 140662438326272,
-STORE, 140662438326272, 140662438330367,
-STORE, 140662438330368, 140662438498303,
-ERASE, 140662438330368, 140662438330368,
-STORE, 140662438330368, 140662438453247,
-STORE, 140662438453248, 140662438486015,
-STORE, 140662438486016, 140662438494207,
-STORE, 140662438494208, 140662438498303,
-STORE, 140727690379264, 140727690383359,
-STORE, 140727690366976, 140727690379263,
-STORE, 46970356670464, 46970356678655,
-STORE, 46970356678656, 46970356686847,
-STORE, 46970356686848, 46970356793343,
-STORE, 46970356703232, 46970356793343,
-STORE, 46970356686848, 46970356703231,
-ERASE, 46970356703232, 46970356703232,
-STORE, 46970356703232, 46970356776959,
-STORE, 46970356776960, 46970356793343,
-STORE, 46970356756480, 46970356776959,
-STORE, 46970356703232, 46970356756479,
-ERASE, 46970356703232, 46970356703232,
-STORE, 46970356703232, 46970356756479,
-STORE, 46970356772864, 46970356776959,
-STORE, 46970356756480, 46970356772863,
-ERASE, 46970356756480, 46970356756480,
-STORE, 46970356756480, 46970356772863,
-STORE, 46970356785152, 46970356793343,
-STORE, 46970356776960, 46970356785151,
-ERASE, 46970356776960, 46970356776960,
-STORE, 46970356776960, 46970356785151,
-ERASE, 46970356785152, 46970356785152,
-STORE, 46970356785152, 46970356793343,
-STORE, 46970356793344, 46970358632447,
-STORE, 46970356932608, 46970358632447,
-STORE, 46970356793344, 46970356932607,
-ERASE, 46970356932608, 46970356932608,
-STORE, 46970356932608, 46970358591487,
-STORE, 46970358591488, 46970358632447,
-STORE, 46970358276096, 46970358591487,
-STORE, 46970356932608, 46970358276095,
-ERASE, 46970356932608, 46970356932608,
-STORE, 46970356932608, 46970358276095,
-STORE, 46970358587392, 46970358591487,
-STORE, 46970358276096, 46970358587391,
-ERASE, 46970358276096, 46970358276096,
-STORE, 46970358276096, 46970358587391,
-STORE, 46970358616064, 46970358632447,
-STORE, 46970358591488, 46970358616063,
-ERASE, 46970358591488, 46970358591488,
-STORE, 46970358591488, 46970358616063,
-ERASE, 46970358616064, 46970358616064,
-STORE, 46970358616064, 46970358632447,
-STORE, 46970358616064, 46970358644735,
-ERASE, 46970358591488, 46970358591488,
-STORE, 46970358591488, 46970358607871,
-STORE, 46970358607872, 46970358616063,
-ERASE, 46970356776960, 46970356776960,
-STORE, 46970356776960, 46970356781055,
-STORE, 46970356781056, 46970356785151,
-ERASE, 94121892900864, 94121892900864,
-STORE, 94121892900864, 94121892917247,
-STORE, 94121892917248, 94121892921343,
-ERASE, 140662438486016, 140662438486016,
-STORE, 140662438486016, 140662438490111,
-STORE, 140662438490112, 140662438494207,
-ERASE, 46970356670464, 46970356670464,
-STORE, 94121898610688, 94121898745855,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737189351424, 140737488351231,
-ERASE, 140737189351424, 140737189351424,
-STORE, 140737189351424, 140737189355519,
-STORE, 93847948832768, 93847949545471,
-ERASE, 93847948832768, 93847948832768,
-STORE, 93847948832768, 93847948881919,
-STORE, 93847948881920, 93847949545471,
-ERASE, 93847948881920, 93847948881920,
-STORE, 93847948881920, 93847949426687,
-STORE, 93847949426688, 93847949524991,
-STORE, 93847949524992, 93847949545471,
-STORE, 139698989985792, 139698990157823,
-ERASE, 139698989985792, 139698989985792,
-STORE, 139698989985792, 139698989989887,
-STORE, 139698989989888, 139698990157823,
-ERASE, 139698989989888, 139698989989888,
-STORE, 139698989989888, 139698990112767,
-STORE, 139698990112768, 139698990145535,
-STORE, 139698990145536, 139698990153727,
-STORE, 139698990153728, 139698990157823,
-STORE, 140737189744640, 140737189748735,
-STORE, 140737189732352, 140737189744639,
-STORE, 47933805010944, 47933805019135,
-STORE, 47933805019136, 47933805027327,
-STORE, 47933805027328, 47933805133823,
-STORE, 47933805043712, 47933805133823,
-STORE, 47933805027328, 47933805043711,
-ERASE, 47933805043712, 47933805043712,
-STORE, 47933805043712, 47933805117439,
-STORE, 47933805117440, 47933805133823,
-STORE, 47933805096960, 47933805117439,
-STORE, 47933805043712, 47933805096959,
-ERASE, 47933805043712, 47933805043712,
-STORE, 47933805043712, 47933805096959,
-STORE, 47933805113344, 47933805117439,
-STORE, 47933805096960, 47933805113343,
-ERASE, 47933805096960, 47933805096960,
-STORE, 47933805096960, 47933805113343,
-STORE, 47933805125632, 47933805133823,
-STORE, 47933805117440, 47933805125631,
-ERASE, 47933805117440, 47933805117440,
-STORE, 47933805117440, 47933805125631,
-ERASE, 47933805125632, 47933805125632,
-STORE, 47933805125632, 47933805133823,
-STORE, 47933805133824, 47933806972927,
-STORE, 47933805273088, 47933806972927,
-STORE, 47933805133824, 47933805273087,
-ERASE, 47933805273088, 47933805273088,
-STORE, 47933805273088, 47933806931967,
-STORE, 47933806931968, 47933806972927,
-STORE, 47933806616576, 47933806931967,
-STORE, 47933805273088, 47933806616575,
-ERASE, 47933805273088, 47933805273088,
-STORE, 47933805273088, 47933806616575,
-STORE, 47933806927872, 47933806931967,
-STORE, 47933806616576, 47933806927871,
-ERASE, 47933806616576, 47933806616576,
-STORE, 47933806616576, 47933806927871,
-STORE, 47933806956544, 47933806972927,
-STORE, 47933806931968, 47933806956543,
-ERASE, 47933806931968, 47933806931968,
-STORE, 47933806931968, 47933806956543,
-ERASE, 47933806956544, 47933806956544,
-STORE, 47933806956544, 47933806972927,
-STORE, 47933806956544, 47933806985215,
-ERASE, 47933806931968, 47933806931968,
-STORE, 47933806931968, 47933806948351,
-STORE, 47933806948352, 47933806956543,
-ERASE, 47933805117440, 47933805117440,
-STORE, 47933805117440, 47933805121535,
-STORE, 47933805121536, 47933805125631,
-ERASE, 93847949524992, 93847949524992,
-STORE, 93847949524992, 93847949541375,
-STORE, 93847949541376, 93847949545471,
-ERASE, 139698990145536, 139698990145536,
-STORE, 139698990145536, 139698990149631,
-STORE, 139698990149632, 139698990153727,
-ERASE, 47933805010944, 47933805010944,
-STORE, 140737488347136, 140737488351231,
-STORE, 140725553991680, 140737488351231,
-ERASE, 140725553991680, 140725553991680,
-STORE, 140725553991680, 140725553995775,
-STORE, 93980056248320, 93980056961023,
-ERASE, 93980056248320, 93980056248320,
-STORE, 93980056248320, 93980056297471,
-STORE, 93980056297472, 93980056961023,
-ERASE, 93980056297472, 93980056297472,
-STORE, 93980056297472, 93980056842239,
-STORE, 93980056842240, 93980056940543,
-STORE, 93980056940544, 93980056961023,
-STORE, 140146588971008, 140146589143039,
-ERASE, 140146588971008, 140146588971008,
-STORE, 140146588971008, 140146588975103,
-STORE, 140146588975104, 140146589143039,
-ERASE, 140146588975104, 140146588975104,
-STORE, 140146588975104, 140146589097983,
-STORE, 140146589097984, 140146589130751,
-STORE, 140146589130752, 140146589138943,
-STORE, 140146589138944, 140146589143039,
-STORE, 140725554860032, 140725554864127,
-STORE, 140725554847744, 140725554860031,
-STORE, 47486206025728, 47486206033919,
-STORE, 47486206033920, 47486206042111,
-STORE, 47486206042112, 47486206148607,
-STORE, 47486206058496, 47486206148607,
-STORE, 47486206042112, 47486206058495,
-ERASE, 47486206058496, 47486206058496,
-STORE, 47486206058496, 47486206132223,
-STORE, 47486206132224, 47486206148607,
-STORE, 47486206111744, 47486206132223,
-STORE, 47486206058496, 47486206111743,
-ERASE, 47486206058496, 47486206058496,
-STORE, 47486206058496, 47486206111743,
-STORE, 47486206128128, 47486206132223,
-STORE, 47486206111744, 47486206128127,
-ERASE, 47486206111744, 47486206111744,
-STORE, 47486206111744, 47486206128127,
-STORE, 47486206140416, 47486206148607,
-STORE, 47486206132224, 47486206140415,
-ERASE, 47486206132224, 47486206132224,
-STORE, 47486206132224, 47486206140415,
-ERASE, 47486206140416, 47486206140416,
-STORE, 47486206140416, 47486206148607,
-STORE, 47486206148608, 47486207987711,
-STORE, 47486206287872, 47486207987711,
-STORE, 47486206148608, 47486206287871,
-ERASE, 47486206287872, 47486206287872,
-STORE, 47486206287872, 47486207946751,
-STORE, 47486207946752, 47486207987711,
-STORE, 47486207631360, 47486207946751,
-STORE, 47486206287872, 47486207631359,
-ERASE, 47486206287872, 47486206287872,
-STORE, 47486206287872, 47486207631359,
-STORE, 47486207942656, 47486207946751,
-STORE, 47486207631360, 47486207942655,
-ERASE, 47486207631360, 47486207631360,
-STORE, 47486207631360, 47486207942655,
-STORE, 47486207971328, 47486207987711,
-STORE, 47486207946752, 47486207971327,
-ERASE, 47486207946752, 47486207946752,
-STORE, 47486207946752, 47486207971327,
-ERASE, 47486207971328, 47486207971328,
-STORE, 47486207971328, 47486207987711,
-STORE, 47486207971328, 47486207999999,
-ERASE, 47486207946752, 47486207946752,
-STORE, 47486207946752, 47486207963135,
-STORE, 47486207963136, 47486207971327,
-ERASE, 47486206132224, 47486206132224,
-STORE, 47486206132224, 47486206136319,
-STORE, 47486206136320, 47486206140415,
-ERASE, 93980056940544, 93980056940544,
-STORE, 93980056940544, 93980056956927,
-STORE, 93980056956928, 93980056961023,
-ERASE, 140146589130752, 140146589130752,
-STORE, 140146589130752, 140146589134847,
-STORE, 140146589134848, 140146589138943,
-ERASE, 47486206025728, 47486206025728,
-STORE, 93980070006784, 93980070141951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727334776832, 140737488351231,
-ERASE, 140727334776832, 140727334776832,
-STORE, 140727334776832, 140727334780927,
-STORE, 94049747247104, 94049747959807,
-ERASE, 94049747247104, 94049747247104,
-STORE, 94049747247104, 94049747296255,
-STORE, 94049747296256, 94049747959807,
-ERASE, 94049747296256, 94049747296256,
-STORE, 94049747296256, 94049747841023,
-STORE, 94049747841024, 94049747939327,
-STORE, 94049747939328, 94049747959807,
-STORE, 140227307216896, 140227307388927,
-ERASE, 140227307216896, 140227307216896,
-STORE, 140227307216896, 140227307220991,
-STORE, 140227307220992, 140227307388927,
-ERASE, 140227307220992, 140227307220992,
-STORE, 140227307220992, 140227307343871,
-STORE, 140227307343872, 140227307376639,
-STORE, 140227307376640, 140227307384831,
-STORE, 140227307384832, 140227307388927,
-STORE, 140727335337984, 140727335342079,
-STORE, 140727335325696, 140727335337983,
-STORE, 47405487779840, 47405487788031,
-STORE, 47405487788032, 47405487796223,
-STORE, 47405487796224, 47405487902719,
-STORE, 47405487812608, 47405487902719,
-STORE, 47405487796224, 47405487812607,
-ERASE, 47405487812608, 47405487812608,
-STORE, 47405487812608, 47405487886335,
-STORE, 47405487886336, 47405487902719,
-STORE, 47405487865856, 47405487886335,
-STORE, 47405487812608, 47405487865855,
-ERASE, 47405487812608, 47405487812608,
-STORE, 47405487812608, 47405487865855,
-STORE, 47405487882240, 47405487886335,
-STORE, 47405487865856, 47405487882239,
-ERASE, 47405487865856, 47405487865856,
-STORE, 47405487865856, 47405487882239,
-STORE, 47405487894528, 47405487902719,
-STORE, 47405487886336, 47405487894527,
-ERASE, 47405487886336, 47405487886336,
-STORE, 47405487886336, 47405487894527,
-ERASE, 47405487894528, 47405487894528,
-STORE, 47405487894528, 47405487902719,
-STORE, 47405487902720, 47405489741823,
-STORE, 47405488041984, 47405489741823,
-STORE, 47405487902720, 47405488041983,
-ERASE, 47405488041984, 47405488041984,
-STORE, 47405488041984, 47405489700863,
-STORE, 47405489700864, 47405489741823,
-STORE, 47405489385472, 47405489700863,
-STORE, 47405488041984, 47405489385471,
-ERASE, 47405488041984, 47405488041984,
-STORE, 47405488041984, 47405489385471,
-STORE, 47405489696768, 47405489700863,
-STORE, 47405489385472, 47405489696767,
-ERASE, 47405489385472, 47405489385472,
-STORE, 47405489385472, 47405489696767,
-STORE, 47405489725440, 47405489741823,
-STORE, 47405489700864, 47405489725439,
-ERASE, 47405489700864, 47405489700864,
-STORE, 47405489700864, 47405489725439,
-ERASE, 47405489725440, 47405489725440,
-STORE, 47405489725440, 47405489741823,
-STORE, 47405489725440, 47405489754111,
-ERASE, 47405489700864, 47405489700864,
-STORE, 47405489700864, 47405489717247,
-STORE, 47405489717248, 47405489725439,
-ERASE, 47405487886336, 47405487886336,
-STORE, 47405487886336, 47405487890431,
-STORE, 47405487890432, 47405487894527,
-ERASE, 94049747939328, 94049747939328,
-STORE, 94049747939328, 94049747955711,
-STORE, 94049747955712, 94049747959807,
-ERASE, 140227307376640, 140227307376640,
-STORE, 140227307376640, 140227307380735,
-STORE, 140227307380736, 140227307384831,
-ERASE, 47405487779840, 47405487779840,
-STORE, 94049758810112, 94049758945279,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727079718912, 140737488351231,
-ERASE, 140727079718912, 140727079718912,
-STORE, 140727079718912, 140727079723007,
-STORE, 94250996527104, 94250997239807,
-ERASE, 94250996527104, 94250996527104,
-STORE, 94250996527104, 94250996576255,
-STORE, 94250996576256, 94250997239807,
-ERASE, 94250996576256, 94250996576256,
-STORE, 94250996576256, 94250997121023,
-STORE, 94250997121024, 94250997219327,
-STORE, 94250997219328, 94250997239807,
-STORE, 140060022587392, 140060022759423,
-ERASE, 140060022587392, 140060022587392,
-STORE, 140060022587392, 140060022591487,
-STORE, 140060022591488, 140060022759423,
-ERASE, 140060022591488, 140060022591488,
-STORE, 140060022591488, 140060022714367,
-STORE, 140060022714368, 140060022747135,
-STORE, 140060022747136, 140060022755327,
-STORE, 140060022755328, 140060022759423,
-STORE, 140727079788544, 140727079792639,
-STORE, 140727079776256, 140727079788543,
-/* this next one caused issues when lowering the efficiency */
-STORE, 47572772409344, 47572772417535,
-STORE, 47572772417536, 47572772425727,
-STORE, 47572772425728, 47572772532223,
-STORE, 47572772442112, 47572772532223,
-STORE, 47572772425728, 47572772442111,
-ERASE, 47572772442112, 47572772442112,
-STORE, 47572772442112, 47572772515839,
-STORE, 47572772515840, 47572772532223,
-STORE, 47572772495360, 47572772515839,
-STORE, 47572772442112, 47572772495359,
-ERASE, 47572772442112, 47572772442112,
-STORE, 47572772442112, 47572772495359,
-STORE, 47572772511744, 47572772515839,
-STORE, 47572772495360, 47572772511743,
-ERASE, 47572772495360, 47572772495360,
-STORE, 47572772495360, 47572772511743,
-STORE, 47572772524032, 47572772532223,
-STORE, 47572772515840, 47572772524031,
-ERASE, 47572772515840, 47572772515840,
-STORE, 47572772515840, 47572772524031,
-ERASE, 47572772524032, 47572772524032,
-STORE, 47572772524032, 47572772532223,
-STORE, 47572772532224, 47572774371327,
-STORE, 47572772671488, 47572774371327,
-STORE, 47572772532224, 47572772671487,
-ERASE, 47572772671488, 47572772671488,
-STORE, 47572772671488, 47572774330367,
-STORE, 47572774330368, 47572774371327,
-STORE, 47572774014976, 47572774330367,
-STORE, 47572772671488, 47572774014975,
-ERASE, 47572772671488, 47572772671488,
-STORE, 47572772671488, 47572774014975,
-STORE, 47572774326272, 47572774330367,
-STORE, 47572774014976, 47572774326271,
-ERASE, 47572774014976, 47572774014976,
-STORE, 47572774014976, 47572774326271,
-STORE, 47572774354944, 47572774371327,
-STORE, 47572774330368, 47572774354943,
-ERASE, 47572774330368, 47572774330368,
-STORE, 47572774330368, 47572774354943,
-ERASE, 47572774354944, 47572774354944,
-STORE, 47572774354944, 47572774371327,
-STORE, 47572774354944, 47572774383615,
-ERASE, 47572774330368, 47572774330368,
-STORE, 47572774330368, 47572774346751,
-STORE, 47572774346752, 47572774354943,
-ERASE, 47572772515840, 47572772515840,
-STORE, 47572772515840, 47572772519935,
-STORE, 47572772519936, 47572772524031,
-ERASE, 94250997219328, 94250997219328,
-STORE, 94250997219328, 94250997235711,
-STORE, 94250997235712, 94250997239807,
-ERASE, 140060022747136, 140060022747136,
-STORE, 140060022747136, 140060022751231,
-STORE, 140060022751232, 140060022755327,
-ERASE, 47572772409344, 47572772409344,
-STORE, 94251018305536, 94251018440703,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730012389376, 140737488351231,
-ERASE, 140730012389376, 140730012389376,
-STORE, 140730012389376, 140730012393471,
-STORE, 94382607675392, 94382607695871,
-ERASE, 94382607675392, 94382607675392,
-STORE, 94382607675392, 94382607679487,
-STORE, 94382607679488, 94382607695871,
-ERASE, 94382607679488, 94382607679488,
-STORE, 94382607679488, 94382607683583,
-STORE, 94382607683584, 94382607687679,
-STORE, 94382607687680, 94382607695871,
-STORE, 140252451454976, 140252451627007,
-ERASE, 140252451454976, 140252451454976,
-STORE, 140252451454976, 140252451459071,
-STORE, 140252451459072, 140252451627007,
-ERASE, 140252451459072, 140252451459072,
-STORE, 140252451459072, 140252451581951,
-STORE, 140252451581952, 140252451614719,
-STORE, 140252451614720, 140252451622911,
-STORE, 140252451622912, 140252451627007,
-STORE, 140730013548544, 140730013552639,
-STORE, 140730013536256, 140730013548543,
-STORE, 47380343541760, 47380343549951,
-STORE, 47380343549952, 47380343558143,
-STORE, 47380343558144, 47380345397247,
-STORE, 47380343697408, 47380345397247,
-STORE, 47380343558144, 47380343697407,
-ERASE, 47380343697408, 47380343697408,
-STORE, 47380343697408, 47380345356287,
-STORE, 47380345356288, 47380345397247,
-STORE, 47380345040896, 47380345356287,
-STORE, 47380343697408, 47380345040895,
-ERASE, 47380343697408, 47380343697408,
-STORE, 47380343697408, 47380345040895,
-STORE, 47380345352192, 47380345356287,
-STORE, 47380345040896, 47380345352191,
-ERASE, 47380345040896, 47380345040896,
-STORE, 47380345040896, 47380345352191,
-STORE, 47380345380864, 47380345397247,
-STORE, 47380345356288, 47380345380863,
-ERASE, 47380345356288, 47380345356288,
-STORE, 47380345356288, 47380345380863,
-ERASE, 47380345380864, 47380345380864,
-STORE, 47380345380864, 47380345397247,
-ERASE, 47380345356288, 47380345356288,
-STORE, 47380345356288, 47380345372671,
-STORE, 47380345372672, 47380345380863,
-ERASE, 94382607687680, 94382607687680,
-STORE, 94382607687680, 94382607691775,
-STORE, 94382607691776, 94382607695871,
-ERASE, 140252451614720, 140252451614720,
-STORE, 140252451614720, 140252451618815,
-STORE, 140252451618816, 140252451622911,
-ERASE, 47380343541760, 47380343541760,
-STORE, 94382626803712, 94382626938879,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730900271104, 140737488351231,
-ERASE, 140730900271104, 140730900271104,
-STORE, 140730900271104, 140730900275199,
-STORE, 93855478120448, 93855478337535,
-ERASE, 93855478120448, 93855478120448,
-STORE, 93855478120448, 93855478198271,
-STORE, 93855478198272, 93855478337535,
-ERASE, 93855478198272, 93855478198272,
-STORE, 93855478198272, 93855478243327,
-STORE, 93855478243328, 93855478288383,
-STORE, 93855478288384, 93855478337535,
-STORE, 140092686573568, 140092686745599,
-ERASE, 140092686573568, 140092686573568,
-STORE, 140092686573568, 140092686577663,
-STORE, 140092686577664, 140092686745599,
-ERASE, 140092686577664, 140092686577664,
-STORE, 140092686577664, 140092686700543,
-STORE, 140092686700544, 140092686733311,
-STORE, 140092686733312, 140092686741503,
-STORE, 140092686741504, 140092686745599,
-STORE, 140730900537344, 140730900541439,
-STORE, 140730900525056, 140730900537343,
-STORE, 47540108423168, 47540108431359,
-STORE, 47540108431360, 47540108439551,
-STORE, 47540108439552, 47540110278655,
-STORE, 47540108578816, 47540110278655,
-STORE, 47540108439552, 47540108578815,
-ERASE, 47540108578816, 47540108578816,
-STORE, 47540108578816, 47540110237695,
-STORE, 47540110237696, 47540110278655,
-STORE, 47540109922304, 47540110237695,
-STORE, 47540108578816, 47540109922303,
-ERASE, 47540108578816, 47540108578816,
-STORE, 47540108578816, 47540109922303,
-STORE, 47540110233600, 47540110237695,
-STORE, 47540109922304, 47540110233599,
-ERASE, 47540109922304, 47540109922304,
-STORE, 47540109922304, 47540110233599,
-STORE, 47540110262272, 47540110278655,
-STORE, 47540110237696, 47540110262271,
-ERASE, 47540110237696, 47540110237696,
-STORE, 47540110237696, 47540110262271,
-ERASE, 47540110262272, 47540110262272,
-STORE, 47540110262272, 47540110278655,
-ERASE, 47540110237696, 47540110237696,
-STORE, 47540110237696, 47540110254079,
-STORE, 47540110254080, 47540110262271,
-ERASE, 93855478288384, 93855478288384,
-STORE, 93855478288384, 93855478333439,
-STORE, 93855478333440, 93855478337535,
-ERASE, 140092686733312, 140092686733312,
-STORE, 140092686733312, 140092686737407,
-STORE, 140092686737408, 140092686741503,
-ERASE, 47540108423168, 47540108423168,
-STORE, 93855492222976, 93855492358143,
-STORE, 93855492222976, 93855492493311,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733498146816, 140737488351231,
-ERASE, 140733498146816, 140733498146816,
-STORE, 140733498146816, 140733498150911,
-STORE, 94170739654656, 94170740367359,
-ERASE, 94170739654656, 94170739654656,
-STORE, 94170739654656, 94170739703807,
-STORE, 94170739703808, 94170740367359,
-ERASE, 94170739703808, 94170739703808,
-STORE, 94170739703808, 94170740248575,
-STORE, 94170740248576, 94170740346879,
-STORE, 94170740346880, 94170740367359,
-STORE, 140024788877312, 140024789049343,
-ERASE, 140024788877312, 140024788877312,
-STORE, 140024788877312, 140024788881407,
-STORE, 140024788881408, 140024789049343,
-ERASE, 140024788881408, 140024788881408,
-STORE, 140024788881408, 140024789004287,
-STORE, 140024789004288, 140024789037055,
-STORE, 140024789037056, 140024789045247,
-STORE, 140024789045248, 140024789049343,
-STORE, 140733499023360, 140733499027455,
-STORE, 140733499011072, 140733499023359,
-STORE, 47608006119424, 47608006127615,
-STORE, 47608006127616, 47608006135807,
-STORE, 47608006135808, 47608006242303,
-STORE, 47608006152192, 47608006242303,
-STORE, 47608006135808, 47608006152191,
-ERASE, 47608006152192, 47608006152192,
-STORE, 47608006152192, 47608006225919,
-STORE, 47608006225920, 47608006242303,
-STORE, 47608006205440, 47608006225919,
-STORE, 47608006152192, 47608006205439,
-ERASE, 47608006152192, 47608006152192,
-STORE, 47608006152192, 47608006205439,
-STORE, 47608006221824, 47608006225919,
-STORE, 47608006205440, 47608006221823,
-ERASE, 47608006205440, 47608006205440,
-STORE, 47608006205440, 47608006221823,
-STORE, 47608006234112, 47608006242303,
-STORE, 47608006225920, 47608006234111,
-ERASE, 47608006225920, 47608006225920,
-STORE, 47608006225920, 47608006234111,
-ERASE, 47608006234112, 47608006234112,
-STORE, 47608006234112, 47608006242303,
-STORE, 47608006242304, 47608008081407,
-STORE, 47608006381568, 47608008081407,
-STORE, 47608006242304, 47608006381567,
-ERASE, 47608006381568, 47608006381568,
-STORE, 47608006381568, 47608008040447,
-STORE, 47608008040448, 47608008081407,
-STORE, 47608007725056, 47608008040447,
-STORE, 47608006381568, 47608007725055,
-ERASE, 47608006381568, 47608006381568,
-STORE, 47608006381568, 47608007725055,
-STORE, 47608008036352, 47608008040447,
-STORE, 47608007725056, 47608008036351,
-ERASE, 47608007725056, 47608007725056,
-STORE, 47608007725056, 47608008036351,
-STORE, 47608008065024, 47608008081407,
-STORE, 47608008040448, 47608008065023,
-ERASE, 47608008040448, 47608008040448,
-STORE, 47608008040448, 47608008065023,
-ERASE, 47608008065024, 47608008065024,
-STORE, 47608008065024, 47608008081407,
-STORE, 47608008065024, 47608008093695,
-ERASE, 47608008040448, 47608008040448,
-STORE, 47608008040448, 47608008056831,
-STORE, 47608008056832, 47608008065023,
-ERASE, 47608006225920, 47608006225920,
-STORE, 47608006225920, 47608006230015,
-STORE, 47608006230016, 47608006234111,
-ERASE, 94170740346880, 94170740346880,
-STORE, 94170740346880, 94170740363263,
-STORE, 94170740363264, 94170740367359,
-ERASE, 140024789037056, 140024789037056,
-STORE, 140024789037056, 140024789041151,
-STORE, 140024789041152, 140024789045247,
-ERASE, 47608006119424, 47608006119424,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730264326144, 140737488351231,
-ERASE, 140730264326144, 140730264326144,
-STORE, 140730264326144, 140730264330239,
-STORE, 94653216407552, 94653217120255,
-ERASE, 94653216407552, 94653216407552,
-STORE, 94653216407552, 94653216456703,
-STORE, 94653216456704, 94653217120255,
-ERASE, 94653216456704, 94653216456704,
-STORE, 94653216456704, 94653217001471,
-STORE, 94653217001472, 94653217099775,
-STORE, 94653217099776, 94653217120255,
-STORE, 140103617011712, 140103617183743,
-ERASE, 140103617011712, 140103617011712,
-STORE, 140103617011712, 140103617015807,
-STORE, 140103617015808, 140103617183743,
-ERASE, 140103617015808, 140103617015808,
-STORE, 140103617015808, 140103617138687,
-STORE, 140103617138688, 140103617171455,
-STORE, 140103617171456, 140103617179647,
-STORE, 140103617179648, 140103617183743,
-STORE, 140730265427968, 140730265432063,
-STORE, 140730265415680, 140730265427967,
-STORE, 47529177985024, 47529177993215,
-STORE, 47529177993216, 47529178001407,
-STORE, 47529178001408, 47529178107903,
-STORE, 47529178017792, 47529178107903,
-STORE, 47529178001408, 47529178017791,
-ERASE, 47529178017792, 47529178017792,
-STORE, 47529178017792, 47529178091519,
-STORE, 47529178091520, 47529178107903,
-STORE, 47529178071040, 47529178091519,
-STORE, 47529178017792, 47529178071039,
-ERASE, 47529178017792, 47529178017792,
-STORE, 47529178017792, 47529178071039,
-STORE, 47529178087424, 47529178091519,
-STORE, 47529178071040, 47529178087423,
-ERASE, 47529178071040, 47529178071040,
-STORE, 47529178071040, 47529178087423,
-STORE, 47529178099712, 47529178107903,
-STORE, 47529178091520, 47529178099711,
-ERASE, 47529178091520, 47529178091520,
-STORE, 47529178091520, 47529178099711,
-ERASE, 47529178099712, 47529178099712,
-STORE, 47529178099712, 47529178107903,
-STORE, 47529178107904, 47529179947007,
-STORE, 47529178247168, 47529179947007,
-STORE, 47529178107904, 47529178247167,
-ERASE, 47529178247168, 47529178247168,
-STORE, 47529178247168, 47529179906047,
-STORE, 47529179906048, 47529179947007,
-STORE, 47529179590656, 47529179906047,
-STORE, 47529178247168, 47529179590655,
-ERASE, 47529178247168, 47529178247168,
-STORE, 47529178247168, 47529179590655,
-STORE, 47529179901952, 47529179906047,
-STORE, 47529179590656, 47529179901951,
-ERASE, 47529179590656, 47529179590656,
-STORE, 47529179590656, 47529179901951,
-STORE, 47529179930624, 47529179947007,
-STORE, 47529179906048, 47529179930623,
-ERASE, 47529179906048, 47529179906048,
-STORE, 47529179906048, 47529179930623,
-ERASE, 47529179930624, 47529179930624,
-STORE, 47529179930624, 47529179947007,
-STORE, 47529179930624, 47529179959295,
-ERASE, 47529179906048, 47529179906048,
-STORE, 47529179906048, 47529179922431,
-STORE, 47529179922432, 47529179930623,
-ERASE, 47529178091520, 47529178091520,
-STORE, 47529178091520, 47529178095615,
-STORE, 47529178095616, 47529178099711,
-ERASE, 94653217099776, 94653217099776,
-STORE, 94653217099776, 94653217116159,
-STORE, 94653217116160, 94653217120255,
-ERASE, 140103617171456, 140103617171456,
-STORE, 140103617171456, 140103617175551,
-STORE, 140103617175552, 140103617179647,
-ERASE, 47529177985024, 47529177985024,
-STORE, 94653241135104, 94653241270271,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736284549120, 140737488351231,
-ERASE, 140736284549120, 140736284549120,
-STORE, 140736284549120, 140736284553215,
-STORE, 93963663822848, 93963664506879,
-ERASE, 93963663822848, 93963663822848,
-STORE, 93963663822848, 93963663884287,
-STORE, 93963663884288, 93963664506879,
-ERASE, 93963663884288, 93963663884288,
-STORE, 93963663884288, 93963664240639,
-STORE, 93963664240640, 93963664379903,
-STORE, 93963664379904, 93963664506879,
-STORE, 140450188439552, 140450188611583,
-ERASE, 140450188439552, 140450188439552,
-STORE, 140450188439552, 140450188443647,
-STORE, 140450188443648, 140450188611583,
-ERASE, 140450188443648, 140450188443648,
-STORE, 140450188443648, 140450188566527,
-STORE, 140450188566528, 140450188599295,
-STORE, 140450188599296, 140450188607487,
-STORE, 140450188607488, 140450188611583,
-STORE, 140736284577792, 140736284581887,
-STORE, 140736284565504, 140736284577791,
-STORE, 47182606557184, 47182606565375,
-STORE, 47182606565376, 47182606573567,
-STORE, 47182606573568, 47182608412671,
-STORE, 47182606712832, 47182608412671,
-STORE, 47182606573568, 47182606712831,
-ERASE, 47182606712832, 47182606712832,
-STORE, 47182606712832, 47182608371711,
-STORE, 47182608371712, 47182608412671,
-STORE, 47182608056320, 47182608371711,
-STORE, 47182606712832, 47182608056319,
-ERASE, 47182606712832, 47182606712832,
-STORE, 47182606712832, 47182608056319,
-STORE, 47182608367616, 47182608371711,
-STORE, 47182608056320, 47182608367615,
-ERASE, 47182608056320, 47182608056320,
-STORE, 47182608056320, 47182608367615,
-STORE, 47182608396288, 47182608412671,
-STORE, 47182608371712, 47182608396287,
-ERASE, 47182608371712, 47182608371712,
-STORE, 47182608371712, 47182608396287,
-ERASE, 47182608396288, 47182608396288,
-STORE, 47182608396288, 47182608412671,
-STORE, 47182608412672, 47182608523263,
-STORE, 47182608429056, 47182608523263,
-STORE, 47182608412672, 47182608429055,
-ERASE, 47182608429056, 47182608429056,
-STORE, 47182608429056, 47182608515071,
-STORE, 47182608515072, 47182608523263,
-STORE, 47182608490496, 47182608515071,
-STORE, 47182608429056, 47182608490495,
-ERASE, 47182608429056, 47182608429056,
-STORE, 47182608429056, 47182608490495,
-STORE, 47182608510976, 47182608515071,
-STORE, 47182608490496, 47182608510975,
-ERASE, 47182608490496, 47182608490496,
-STORE, 47182608490496, 47182608510975,
-ERASE, 47182608515072, 47182608515072,
-STORE, 47182608515072, 47182608523263,
-STORE, 47182608523264, 47182608568319,
-ERASE, 47182608523264, 47182608523264,
-STORE, 47182608523264, 47182608531455,
-STORE, 47182608531456, 47182608568319,
-STORE, 47182608551936, 47182608568319,
-STORE, 47182608531456, 47182608551935,
-ERASE, 47182608531456, 47182608531456,
-STORE, 47182608531456, 47182608551935,
-STORE, 47182608560128, 47182608568319,
-STORE, 47182608551936, 47182608560127,
-ERASE, 47182608551936, 47182608551936,
-STORE, 47182608551936, 47182608568319,
-ERASE, 47182608551936, 47182608551936,
-STORE, 47182608551936, 47182608560127,
-STORE, 47182608560128, 47182608568319,
-ERASE, 47182608560128, 47182608560128,
-STORE, 47182608560128, 47182608568319,
-STORE, 47182608568320, 47182608916479,
-STORE, 47182608609280, 47182608916479,
-STORE, 47182608568320, 47182608609279,
-ERASE, 47182608609280, 47182608609280,
-STORE, 47182608609280, 47182608891903,
-STORE, 47182608891904, 47182608916479,
-STORE, 47182608822272, 47182608891903,
-STORE, 47182608609280, 47182608822271,
-ERASE, 47182608609280, 47182608609280,
-STORE, 47182608609280, 47182608822271,
-STORE, 47182608887808, 47182608891903,
-STORE, 47182608822272, 47182608887807,
-ERASE, 47182608822272, 47182608822272,
-STORE, 47182608822272, 47182608887807,
-ERASE, 47182608891904, 47182608891904,
-STORE, 47182608891904, 47182608916479,
-STORE, 47182608916480, 47182611177471,
-STORE, 47182609068032, 47182611177471,
-STORE, 47182608916480, 47182609068031,
-ERASE, 47182609068032, 47182609068032,
-STORE, 47182609068032, 47182611161087,
-STORE, 47182611161088, 47182611177471,
-STORE, 47182611169280, 47182611177471,
-STORE, 47182611161088, 47182611169279,
-ERASE, 47182611161088, 47182611161088,
-STORE, 47182611161088, 47182611169279,
-ERASE, 47182611169280, 47182611169280,
-STORE, 47182611169280, 47182611177471,
-STORE, 47182611177472, 47182611312639,
-ERASE, 47182611177472, 47182611177472,
-STORE, 47182611177472, 47182611202047,
-STORE, 47182611202048, 47182611312639,
-STORE, 47182611263488, 47182611312639,
-STORE, 47182611202048, 47182611263487,
-ERASE, 47182611202048, 47182611202048,
-STORE, 47182611202048, 47182611263487,
-STORE, 47182611288064, 47182611312639,
-STORE, 47182611263488, 47182611288063,
-ERASE, 47182611263488, 47182611263488,
-STORE, 47182611263488, 47182611312639,
-ERASE, 47182611263488, 47182611263488,
-STORE, 47182611263488, 47182611288063,
-STORE, 47182611288064, 47182611312639,
-STORE, 47182611296256, 47182611312639,
-STORE, 47182611288064, 47182611296255,
-ERASE, 47182611288064, 47182611288064,
-STORE, 47182611288064, 47182611296255,
-ERASE, 47182611296256, 47182611296256,
-STORE, 47182611296256, 47182611312639,
-STORE, 47182611296256, 47182611320831,
-STORE, 47182611320832, 47182611484671,
-ERASE, 47182611320832, 47182611320832,
-STORE, 47182611320832, 47182611333119,
-STORE, 47182611333120, 47182611484671,
-STORE, 47182611431424, 47182611484671,
-STORE, 47182611333120, 47182611431423,
-ERASE, 47182611333120, 47182611333120,
-STORE, 47182611333120, 47182611431423,
-STORE, 47182611476480, 47182611484671,
-STORE, 47182611431424, 47182611476479,
-ERASE, 47182611431424, 47182611431424,
-STORE, 47182611431424, 47182611484671,
-ERASE, 47182611431424, 47182611431424,
-STORE, 47182611431424, 47182611476479,
-STORE, 47182611476480, 47182611484671,
-ERASE, 47182611476480, 47182611476480,
-STORE, 47182611476480, 47182611484671,
-STORE, 47182611484672, 47182612082687,
-STORE, 47182611603456, 47182612082687,
-STORE, 47182611484672, 47182611603455,
-ERASE, 47182611603456, 47182611603456,
-STORE, 47182611603456, 47182612029439,
-STORE, 47182612029440, 47182612082687,
-STORE, 47182611918848, 47182612029439,
-STORE, 47182611603456, 47182611918847,
-ERASE, 47182611603456, 47182611603456,
-STORE, 47182611603456, 47182611918847,
-STORE, 47182612025344, 47182612029439,
-STORE, 47182611918848, 47182612025343,
-ERASE, 47182611918848, 47182611918848,
-STORE, 47182611918848, 47182612025343,
-ERASE, 47182612029440, 47182612029440,
-STORE, 47182612029440, 47182612082687,
-STORE, 47182612082688, 47182615134207,
-STORE, 47182612627456, 47182615134207,
-STORE, 47182612082688, 47182612627455,
-ERASE, 47182612627456, 47182612627456,
-STORE, 47182612627456, 47182614913023,
-STORE, 47182614913024, 47182615134207,
-STORE, 47182614323200, 47182614913023,
-STORE, 47182612627456, 47182614323199,
-ERASE, 47182612627456, 47182612627456,
-STORE, 47182612627456, 47182614323199,
-STORE, 47182614908928, 47182614913023,
-STORE, 47182614323200, 47182614908927,
-ERASE, 47182614323200, 47182614323200,
-STORE, 47182614323200, 47182614908927,
-STORE, 47182615117824, 47182615134207,
-STORE, 47182614913024, 47182615117823,
-ERASE, 47182614913024, 47182614913024,
-STORE, 47182614913024, 47182615117823,
-ERASE, 47182615117824, 47182615117824,
-STORE, 47182615117824, 47182615134207,
-STORE, 47182615134208, 47182615166975,
-ERASE, 47182615134208, 47182615134208,
-STORE, 47182615134208, 47182615142399,
-STORE, 47182615142400, 47182615166975,
-STORE, 47182615154688, 47182615166975,
-STORE, 47182615142400, 47182615154687,
-ERASE, 47182615142400, 47182615142400,
-STORE, 47182615142400, 47182615154687,
-STORE, 47182615158784, 47182615166975,
-STORE, 47182615154688, 47182615158783,
-ERASE, 47182615154688, 47182615154688,
-STORE, 47182615154688, 47182615166975,
-ERASE, 47182615154688, 47182615154688,
-STORE, 47182615154688, 47182615158783,
-STORE, 47182615158784, 47182615166975,
-ERASE, 47182615158784, 47182615158784,
-STORE, 47182615158784, 47182615166975,
-STORE, 47182615166976, 47182615203839,
-ERASE, 47182615166976, 47182615166976,
-STORE, 47182615166976, 47182615175167,
-STORE, 47182615175168, 47182615203839,
-STORE, 47182615191552, 47182615203839,
-STORE, 47182615175168, 47182615191551,
-ERASE, 47182615175168, 47182615175168,
-STORE, 47182615175168, 47182615191551,
-STORE, 47182615195648, 47182615203839,
-STORE, 47182615191552, 47182615195647,
-ERASE, 47182615191552, 47182615191552,
-STORE, 47182615191552, 47182615203839,
-ERASE, 47182615191552, 47182615191552,
-STORE, 47182615191552, 47182615195647,
-STORE, 47182615195648, 47182615203839,
-ERASE, 47182615195648, 47182615195648,
-STORE, 47182615195648, 47182615203839,
-STORE, 47182615203840, 47182615678975,
-ERASE, 47182615203840, 47182615203840,
-STORE, 47182615203840, 47182615212031,
-STORE, 47182615212032, 47182615678975,
-STORE, 47182615547904, 47182615678975,
-STORE, 47182615212032, 47182615547903,
-ERASE, 47182615212032, 47182615212032,
-STORE, 47182615212032, 47182615547903,
-STORE, 47182615670784, 47182615678975,
-STORE, 47182615547904, 47182615670783,
-ERASE, 47182615547904, 47182615547904,
-STORE, 47182615547904, 47182615678975,
-ERASE, 47182615547904, 47182615547904,
-STORE, 47182615547904, 47182615670783,
-STORE, 47182615670784, 47182615678975,
-ERASE, 47182615670784, 47182615670784,
-STORE, 47182615670784, 47182615678975,
-STORE, 47182615678976, 47182615687167,
-STORE, 47182615687168, 47182615707647,
-ERASE, 47182615687168, 47182615687168,
-STORE, 47182615687168, 47182615691263,
-STORE, 47182615691264, 47182615707647,
-STORE, 47182615695360, 47182615707647,
-STORE, 47182615691264, 47182615695359,
-ERASE, 47182615691264, 47182615691264,
-STORE, 47182615691264, 47182615695359,
-STORE, 47182615699456, 47182615707647,
-STORE, 47182615695360, 47182615699455,
-ERASE, 47182615695360, 47182615695360,
-STORE, 47182615695360, 47182615707647,
-ERASE, 47182615695360, 47182615695360,
-STORE, 47182615695360, 47182615699455,
-STORE, 47182615699456, 47182615707647,
-ERASE, 47182615699456, 47182615699456,
-STORE, 47182615699456, 47182615707647,
-STORE, 47182615707648, 47182615715839,
-ERASE, 47182608371712, 47182608371712,
-STORE, 47182608371712, 47182608388095,
-STORE, 47182608388096, 47182608396287,
-ERASE, 47182615699456, 47182615699456,
-STORE, 47182615699456, 47182615703551,
-STORE, 47182615703552, 47182615707647,
-ERASE, 47182611288064, 47182611288064,
-STORE, 47182611288064, 47182611292159,
-STORE, 47182611292160, 47182611296255,
-ERASE, 47182615670784, 47182615670784,
-STORE, 47182615670784, 47182615674879,
-STORE, 47182615674880, 47182615678975,
-ERASE, 47182615195648, 47182615195648,
-STORE, 47182615195648, 47182615199743,
-STORE, 47182615199744, 47182615203839,
-ERASE, 47182615158784, 47182615158784,
-STORE, 47182615158784, 47182615162879,
-STORE, 47182615162880, 47182615166975,
-ERASE, 47182614913024, 47182614913024,
-STORE, 47182614913024, 47182615109631,
-STORE, 47182615109632, 47182615117823,
-ERASE, 47182612029440, 47182612029440,
-STORE, 47182612029440, 47182612066303,
-STORE, 47182612066304, 47182612082687,
-ERASE, 47182611476480, 47182611476480,
-STORE, 47182611476480, 47182611480575,
-STORE, 47182611480576, 47182611484671,
-ERASE, 47182611161088, 47182611161088,
-STORE, 47182611161088, 47182611165183,
-STORE, 47182611165184, 47182611169279,
-ERASE, 47182608891904, 47182608891904,
-STORE, 47182608891904, 47182608912383,
-STORE, 47182608912384, 47182608916479,
-ERASE, 47182608560128, 47182608560128,
-STORE, 47182608560128, 47182608564223,
-STORE, 47182608564224, 47182608568319,
-ERASE, 47182608515072, 47182608515072,
-STORE, 47182608515072, 47182608519167,
-STORE, 47182608519168, 47182608523263,
-ERASE, 93963664379904, 93963664379904,
-STORE, 93963664379904, 93963664502783,
-STORE, 93963664502784, 93963664506879,
-ERASE, 140450188599296, 140450188599296,
-STORE, 140450188599296, 140450188603391,
-STORE, 140450188603392, 140450188607487,
-ERASE, 47182606557184, 47182606557184,
-STORE, 93963694723072, 93963694858239,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730313261056, 140737488351231,
-ERASE, 140730313261056, 140730313261056,
-STORE, 140730313261056, 140730313265151,
-STORE, 94386579017728, 94386579697663,
-ERASE, 94386579017728, 94386579017728,
-STORE, 94386579017728, 94386579083263,
-STORE, 94386579083264, 94386579697663,
-ERASE, 94386579083264, 94386579083264,
-STORE, 94386579083264, 94386579431423,
-STORE, 94386579431424, 94386579570687,
-STORE, 94386579570688, 94386579697663,
-STORE, 140124810838016, 140124811010047,
-ERASE, 140124810838016, 140124810838016,
-STORE, 140124810838016, 140124810842111,
-STORE, 140124810842112, 140124811010047,
-ERASE, 140124810842112, 140124810842112,
-STORE, 140124810842112, 140124810964991,
-STORE, 140124810964992, 140124810997759,
-STORE, 140124810997760, 140124811005951,
-STORE, 140124811005952, 140124811010047,
-STORE, 140730313601024, 140730313605119,
-STORE, 140730313588736, 140730313601023,
-STORE, 47507984158720, 47507984166911,
-STORE, 47507984166912, 47507984175103,
-STORE, 47507984175104, 47507986014207,
-STORE, 47507984314368, 47507986014207,
-STORE, 47507984175104, 47507984314367,
-ERASE, 47507984314368, 47507984314368,
-STORE, 47507984314368, 47507985973247,
-STORE, 47507985973248, 47507986014207,
-STORE, 47507985657856, 47507985973247,
-STORE, 47507984314368, 47507985657855,
-ERASE, 47507984314368, 47507984314368,
-STORE, 47507984314368, 47507985657855,
-STORE, 47507985969152, 47507985973247,
-STORE, 47507985657856, 47507985969151,
-ERASE, 47507985657856, 47507985657856,
-STORE, 47507985657856, 47507985969151,
-STORE, 47507985997824, 47507986014207,
-STORE, 47507985973248, 47507985997823,
-ERASE, 47507985973248, 47507985973248,
-STORE, 47507985973248, 47507985997823,
-ERASE, 47507985997824, 47507985997824,
-STORE, 47507985997824, 47507986014207,
-STORE, 47507986014208, 47507986124799,
-STORE, 47507986030592, 47507986124799,
-STORE, 47507986014208, 47507986030591,
-ERASE, 47507986030592, 47507986030592,
-STORE, 47507986030592, 47507986116607,
-STORE, 47507986116608, 47507986124799,
-STORE, 47507986092032, 47507986116607,
-STORE, 47507986030592, 47507986092031,
-ERASE, 47507986030592, 47507986030592,
-STORE, 47507986030592, 47507986092031,
-STORE, 47507986112512, 47507986116607,
-STORE, 47507986092032, 47507986112511,
-ERASE, 47507986092032, 47507986092032,
-STORE, 47507986092032, 47507986112511,
-ERASE, 47507986116608, 47507986116608,
-STORE, 47507986116608, 47507986124799,
-STORE, 47507986124800, 47507986169855,
-ERASE, 47507986124800, 47507986124800,
-STORE, 47507986124800, 47507986132991,
-STORE, 47507986132992, 47507986169855,
-STORE, 47507986153472, 47507986169855,
-STORE, 47507986132992, 47507986153471,
-ERASE, 47507986132992, 47507986132992,
-STORE, 47507986132992, 47507986153471,
-STORE, 47507986161664, 47507986169855,
-STORE, 47507986153472, 47507986161663,
-ERASE, 47507986153472, 47507986153472,
-STORE, 47507986153472, 47507986169855,
-ERASE, 47507986153472, 47507986153472,
-STORE, 47507986153472, 47507986161663,
-STORE, 47507986161664, 47507986169855,
-ERASE, 47507986161664, 47507986161664,
-STORE, 47507986161664, 47507986169855,
-STORE, 47507986169856, 47507986518015,
-STORE, 47507986210816, 47507986518015,
-STORE, 47507986169856, 47507986210815,
-ERASE, 47507986210816, 47507986210816,
-STORE, 47507986210816, 47507986493439,
-STORE, 47507986493440, 47507986518015,
-STORE, 47507986423808, 47507986493439,
-STORE, 47507986210816, 47507986423807,
-ERASE, 47507986210816, 47507986210816,
-STORE, 47507986210816, 47507986423807,
-STORE, 47507986489344, 47507986493439,
-STORE, 47507986423808, 47507986489343,
-ERASE, 47507986423808, 47507986423808,
-STORE, 47507986423808, 47507986489343,
-ERASE, 47507986493440, 47507986493440,
-STORE, 47507986493440, 47507986518015,
-STORE, 47507986518016, 47507988779007,
-STORE, 47507986669568, 47507988779007,
-STORE, 47507986518016, 47507986669567,
-ERASE, 47507986669568, 47507986669568,
-STORE, 47507986669568, 47507988762623,
-STORE, 47507988762624, 47507988779007,
-STORE, 47507988770816, 47507988779007,
-STORE, 47507988762624, 47507988770815,
-ERASE, 47507988762624, 47507988762624,
-STORE, 47507988762624, 47507988770815,
-ERASE, 47507988770816, 47507988770816,
-STORE, 47507988770816, 47507988779007,
-STORE, 47507988779008, 47507988914175,
-ERASE, 47507988779008, 47507988779008,
-STORE, 47507988779008, 47507988803583,
-STORE, 47507988803584, 47507988914175,
-STORE, 47507988865024, 47507988914175,
-STORE, 47507988803584, 47507988865023,
-ERASE, 47507988803584, 47507988803584,
-STORE, 47507988803584, 47507988865023,
-STORE, 47507988889600, 47507988914175,
-STORE, 47507988865024, 47507988889599,
-ERASE, 47507988865024, 47507988865024,
-STORE, 47507988865024, 47507988914175,
-ERASE, 47507988865024, 47507988865024,
-STORE, 47507988865024, 47507988889599,
-STORE, 47507988889600, 47507988914175,
-STORE, 47507988897792, 47507988914175,
-STORE, 47507988889600, 47507988897791,
-ERASE, 47507988889600, 47507988889600,
-STORE, 47507988889600, 47507988897791,
-ERASE, 47507988897792, 47507988897792,
-STORE, 47507988897792, 47507988914175,
-STORE, 47507988897792, 47507988922367,
-STORE, 47507988922368, 47507989086207,
-ERASE, 47507988922368, 47507988922368,
-STORE, 47507988922368, 47507988934655,
-STORE, 47507988934656, 47507989086207,
-STORE, 47507989032960, 47507989086207,
-STORE, 47507988934656, 47507989032959,
-ERASE, 47507988934656, 47507988934656,
-STORE, 47507988934656, 47507989032959,
-STORE, 47507989078016, 47507989086207,
-STORE, 47507989032960, 47507989078015,
-ERASE, 47507989032960, 47507989032960,
-STORE, 47507989032960, 47507989086207,
-ERASE, 47507989032960, 47507989032960,
-STORE, 47507989032960, 47507989078015,
-STORE, 47507989078016, 47507989086207,
-ERASE, 47507989078016, 47507989078016,
-STORE, 47507989078016, 47507989086207,
-STORE, 47507989086208, 47507989684223,
-STORE, 47507989204992, 47507989684223,
-STORE, 47507989086208, 47507989204991,
-ERASE, 47507989204992, 47507989204992,
-STORE, 47507989204992, 47507989630975,
-STORE, 47507989630976, 47507989684223,
-STORE, 47507989520384, 47507989630975,
-STORE, 47507989204992, 47507989520383,
-ERASE, 47507989204992, 47507989204992,
-STORE, 47507989204992, 47507989520383,
-STORE, 47507989626880, 47507989630975,
-STORE, 47507989520384, 47507989626879,
-ERASE, 47507989520384, 47507989520384,
-STORE, 47507989520384, 47507989626879,
-ERASE, 47507989630976, 47507989630976,
-STORE, 47507989630976, 47507989684223,
-STORE, 47507989684224, 47507992735743,
-STORE, 47507990228992, 47507992735743,
-STORE, 47507989684224, 47507990228991,
-ERASE, 47507990228992, 47507990228992,
-STORE, 47507990228992, 47507992514559,
-STORE, 47507992514560, 47507992735743,
-STORE, 47507991924736, 47507992514559,
-STORE, 47507990228992, 47507991924735,
-ERASE, 47507990228992, 47507990228992,
-STORE, 47507990228992, 47507991924735,
-STORE, 47507992510464, 47507992514559,
-STORE, 47507991924736, 47507992510463,
-ERASE, 47507991924736, 47507991924736,
-STORE, 47507991924736, 47507992510463,
-STORE, 47507992719360, 47507992735743,
-STORE, 47507992514560, 47507992719359,
-ERASE, 47507992514560, 47507992514560,
-STORE, 47507992514560, 47507992719359,
-ERASE, 47507992719360, 47507992719360,
-STORE, 47507992719360, 47507992735743,
-STORE, 47507992735744, 47507992768511,
-ERASE, 47507992735744, 47507992735744,
-STORE, 47507992735744, 47507992743935,
-STORE, 47507992743936, 47507992768511,
-STORE, 47507992756224, 47507992768511,
-STORE, 47507992743936, 47507992756223,
-ERASE, 47507992743936, 47507992743936,
-STORE, 47507992743936, 47507992756223,
-STORE, 47507992760320, 47507992768511,
-STORE, 47507992756224, 47507992760319,
-ERASE, 47507992756224, 47507992756224,
-STORE, 47507992756224, 47507992768511,
-ERASE, 47507992756224, 47507992756224,
-STORE, 47507992756224, 47507992760319,
-STORE, 47507992760320, 47507992768511,
-ERASE, 47507992760320, 47507992760320,
-STORE, 47507992760320, 47507992768511,
-STORE, 47507992768512, 47507992805375,
-ERASE, 47507992768512, 47507992768512,
-STORE, 47507992768512, 47507992776703,
-STORE, 47507992776704, 47507992805375,
-STORE, 47507992793088, 47507992805375,
-STORE, 47507992776704, 47507992793087,
-ERASE, 47507992776704, 47507992776704,
-STORE, 47507992776704, 47507992793087,
-STORE, 47507992797184, 47507992805375,
-STORE, 47507992793088, 47507992797183,
-ERASE, 47507992793088, 47507992793088,
-STORE, 47507992793088, 47507992805375,
-ERASE, 47507992793088, 47507992793088,
-STORE, 47507992793088, 47507992797183,
-STORE, 47507992797184, 47507992805375,
-ERASE, 47507992797184, 47507992797184,
-STORE, 47507992797184, 47507992805375,
-STORE, 47507992805376, 47507993280511,
-ERASE, 47507992805376, 47507992805376,
-STORE, 47507992805376, 47507992813567,
-STORE, 47507992813568, 47507993280511,
-STORE, 47507993149440, 47507993280511,
-STORE, 47507992813568, 47507993149439,
-ERASE, 47507992813568, 47507992813568,
-STORE, 47507992813568, 47507993149439,
-STORE, 47507993272320, 47507993280511,
-STORE, 47507993149440, 47507993272319,
-ERASE, 47507993149440, 47507993149440,
-STORE, 47507993149440, 47507993280511,
-ERASE, 47507993149440, 47507993149440,
-STORE, 47507993149440, 47507993272319,
-STORE, 47507993272320, 47507993280511,
-ERASE, 47507993272320, 47507993272320,
-STORE, 47507993272320, 47507993280511,
-STORE, 47507993280512, 47507993288703,
-STORE, 47507993288704, 47507993309183,
-ERASE, 47507993288704, 47507993288704,
-STORE, 47507993288704, 47507993292799,
-STORE, 47507993292800, 47507993309183,
-STORE, 47507993296896, 47507993309183,
-STORE, 47507993292800, 47507993296895,
-ERASE, 47507993292800, 47507993292800,
-STORE, 47507993292800, 47507993296895,
-STORE, 47507993300992, 47507993309183,
-STORE, 47507993296896, 47507993300991,
-ERASE, 47507993296896, 47507993296896,
-STORE, 47507993296896, 47507993309183,
-ERASE, 47507993296896, 47507993296896,
-STORE, 47507993296896, 47507993300991,
-STORE, 47507993300992, 47507993309183,
-ERASE, 47507993300992, 47507993300992,
-STORE, 47507993300992, 47507993309183,
-STORE, 47507993309184, 47507993317375,
-ERASE, 47507985973248, 47507985973248,
-STORE, 47507985973248, 47507985989631,
-STORE, 47507985989632, 47507985997823,
-ERASE, 47507993300992, 47507993300992,
-STORE, 47507993300992, 47507993305087,
-STORE, 47507993305088, 47507993309183,
-ERASE, 47507988889600, 47507988889600,
-STORE, 47507988889600, 47507988893695,
-STORE, 47507988893696, 47507988897791,
-ERASE, 47507993272320, 47507993272320,
-STORE, 47507993272320, 47507993276415,
-STORE, 47507993276416, 47507993280511,
-ERASE, 47507992797184, 47507992797184,
-STORE, 47507992797184, 47507992801279,
-STORE, 47507992801280, 47507992805375,
-ERASE, 47507992760320, 47507992760320,
-STORE, 47507992760320, 47507992764415,
-STORE, 47507992764416, 47507992768511,
-ERASE, 47507992514560, 47507992514560,
-STORE, 47507992514560, 47507992711167,
-STORE, 47507992711168, 47507992719359,
-ERASE, 47507989630976, 47507989630976,
-STORE, 47507989630976, 47507989667839,
-STORE, 47507989667840, 47507989684223,
-ERASE, 47507989078016, 47507989078016,
-STORE, 47507989078016, 47507989082111,
-STORE, 47507989082112, 47507989086207,
-ERASE, 47507988762624, 47507988762624,
-STORE, 47507988762624, 47507988766719,
-STORE, 47507988766720, 47507988770815,
-ERASE, 47507986493440, 47507986493440,
-STORE, 47507986493440, 47507986513919,
-STORE, 47507986513920, 47507986518015,
-ERASE, 47507986161664, 47507986161664,
-STORE, 47507986161664, 47507986165759,
-STORE, 47507986165760, 47507986169855,
-ERASE, 47507986116608, 47507986116608,
-STORE, 47507986116608, 47507986120703,
-STORE, 47507986120704, 47507986124799,
-ERASE, 94386579570688, 94386579570688,
-STORE, 94386579570688, 94386579693567,
-STORE, 94386579693568, 94386579697663,
-ERASE, 140124810997760, 140124810997760,
-STORE, 140124810997760, 140124811001855,
-STORE, 140124811001856, 140124811005951,
-ERASE, 47507984158720, 47507984158720,
-STORE, 94386583982080, 94386584117247,
-STORE, 94386583982080, 94386584256511,
-ERASE, 94386583982080, 94386583982080,
-STORE, 94386583982080, 94386584223743,
-STORE, 94386584223744, 94386584256511,
-ERASE, 94386584223744, 94386584223744,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733763395584, 140737488351231,
-ERASE, 140733763395584, 140733763395584,
-STORE, 140733763395584, 140733763399679,
-STORE, 94011546472448, 94011547152383,
-ERASE, 94011546472448, 94011546472448,
-STORE, 94011546472448, 94011546537983,
-STORE, 94011546537984, 94011547152383,
-ERASE, 94011546537984, 94011546537984,
-STORE, 94011546537984, 94011546886143,
-STORE, 94011546886144, 94011547025407,
-STORE, 94011547025408, 94011547152383,
-STORE, 139757597949952, 139757598121983,
-ERASE, 139757597949952, 139757597949952,
-STORE, 139757597949952, 139757597954047,
-STORE, 139757597954048, 139757598121983,
-ERASE, 139757597954048, 139757597954048,
-STORE, 139757597954048, 139757598076927,
-STORE, 139757598076928, 139757598109695,
-STORE, 139757598109696, 139757598117887,
-STORE, 139757598117888, 139757598121983,
-STORE, 140733763596288, 140733763600383,
-STORE, 140733763584000, 140733763596287,
-STORE, 47875197046784, 47875197054975,
-STORE, 47875197054976, 47875197063167,
-STORE, 47875197063168, 47875198902271,
-STORE, 47875197202432, 47875198902271,
-STORE, 47875197063168, 47875197202431,
-ERASE, 47875197202432, 47875197202432,
-STORE, 47875197202432, 47875198861311,
-STORE, 47875198861312, 47875198902271,
-STORE, 47875198545920, 47875198861311,
-STORE, 47875197202432, 47875198545919,
-ERASE, 47875197202432, 47875197202432,
-STORE, 47875197202432, 47875198545919,
-STORE, 47875198857216, 47875198861311,
-STORE, 47875198545920, 47875198857215,
-ERASE, 47875198545920, 47875198545920,
-STORE, 47875198545920, 47875198857215,
-STORE, 47875198885888, 47875198902271,
-STORE, 47875198861312, 47875198885887,
-ERASE, 47875198861312, 47875198861312,
-STORE, 47875198861312, 47875198885887,
-ERASE, 47875198885888, 47875198885888,
-STORE, 47875198885888, 47875198902271,
-STORE, 47875198902272, 47875199012863,
-STORE, 47875198918656, 47875199012863,
-STORE, 47875198902272, 47875198918655,
-ERASE, 47875198918656, 47875198918656,
-STORE, 47875198918656, 47875199004671,
-STORE, 47875199004672, 47875199012863,
-STORE, 47875198980096, 47875199004671,
-STORE, 47875198918656, 47875198980095,
-ERASE, 47875198918656, 47875198918656,
-STORE, 47875198918656, 47875198980095,
-STORE, 47875199000576, 47875199004671,
-STORE, 47875198980096, 47875199000575,
-ERASE, 47875198980096, 47875198980096,
-STORE, 47875198980096, 47875199000575,
-ERASE, 47875199004672, 47875199004672,
-STORE, 47875199004672, 47875199012863,
-STORE, 47875199012864, 47875199057919,
-ERASE, 47875199012864, 47875199012864,
-STORE, 47875199012864, 47875199021055,
-STORE, 47875199021056, 47875199057919,
-STORE, 47875199041536, 47875199057919,
-STORE, 47875199021056, 47875199041535,
-ERASE, 47875199021056, 47875199021056,
-STORE, 47875199021056, 47875199041535,
-STORE, 47875199049728, 47875199057919,
-STORE, 47875199041536, 47875199049727,
-ERASE, 47875199041536, 47875199041536,
-STORE, 47875199041536, 47875199057919,
-ERASE, 47875199041536, 47875199041536,
-STORE, 47875199041536, 47875199049727,
-STORE, 47875199049728, 47875199057919,
-ERASE, 47875199049728, 47875199049728,
-STORE, 47875199049728, 47875199057919,
-STORE, 47875199057920, 47875199406079,
-STORE, 47875199098880, 47875199406079,
-STORE, 47875199057920, 47875199098879,
-ERASE, 47875199098880, 47875199098880,
-STORE, 47875199098880, 47875199381503,
-STORE, 47875199381504, 47875199406079,
-STORE, 47875199311872, 47875199381503,
-STORE, 47875199098880, 47875199311871,
-ERASE, 47875199098880, 47875199098880,
-STORE, 47875199098880, 47875199311871,
-STORE, 47875199377408, 47875199381503,
-STORE, 47875199311872, 47875199377407,
-ERASE, 47875199311872, 47875199311872,
-STORE, 47875199311872, 47875199377407,
-ERASE, 47875199381504, 47875199381504,
-STORE, 47875199381504, 47875199406079,
-STORE, 47875199406080, 47875201667071,
-STORE, 47875199557632, 47875201667071,
-STORE, 47875199406080, 47875199557631,
-ERASE, 47875199557632, 47875199557632,
-STORE, 47875199557632, 47875201650687,
-STORE, 47875201650688, 47875201667071,
-STORE, 47875201658880, 47875201667071,
-STORE, 47875201650688, 47875201658879,
-ERASE, 47875201650688, 47875201650688,
-STORE, 47875201650688, 47875201658879,
-ERASE, 47875201658880, 47875201658880,
-STORE, 47875201658880, 47875201667071,
-STORE, 47875201667072, 47875201802239,
-ERASE, 47875201667072, 47875201667072,
-STORE, 47875201667072, 47875201691647,
-STORE, 47875201691648, 47875201802239,
-STORE, 47875201753088, 47875201802239,
-STORE, 47875201691648, 47875201753087,
-ERASE, 47875201691648, 47875201691648,
-STORE, 47875201691648, 47875201753087,
-STORE, 47875201777664, 47875201802239,
-STORE, 47875201753088, 47875201777663,
-ERASE, 47875201753088, 47875201753088,
-STORE, 47875201753088, 47875201802239,
-ERASE, 47875201753088, 47875201753088,
-STORE, 47875201753088, 47875201777663,
-STORE, 47875201777664, 47875201802239,
-STORE, 47875201785856, 47875201802239,
-STORE, 47875201777664, 47875201785855,
-ERASE, 47875201777664, 47875201777664,
-STORE, 47875201777664, 47875201785855,
-ERASE, 47875201785856, 47875201785856,
-STORE, 47875201785856, 47875201802239,
-STORE, 47875201785856, 47875201810431,
-STORE, 47875201810432, 47875201974271,
-ERASE, 47875201810432, 47875201810432,
-STORE, 47875201810432, 47875201822719,
-STORE, 47875201822720, 47875201974271,
-STORE, 47875201921024, 47875201974271,
-STORE, 47875201822720, 47875201921023,
-ERASE, 47875201822720, 47875201822720,
-STORE, 47875201822720, 47875201921023,
-STORE, 47875201966080, 47875201974271,
-STORE, 47875201921024, 47875201966079,
-ERASE, 47875201921024, 47875201921024,
-STORE, 47875201921024, 47875201974271,
-ERASE, 47875201921024, 47875201921024,
-STORE, 47875201921024, 47875201966079,
-STORE, 47875201966080, 47875201974271,
-ERASE, 47875201966080, 47875201966080,
-STORE, 47875201966080, 47875201974271,
-STORE, 47875201974272, 47875202572287,
-STORE, 47875202093056, 47875202572287,
-STORE, 47875201974272, 47875202093055,
-ERASE, 47875202093056, 47875202093056,
-STORE, 47875202093056, 47875202519039,
-STORE, 47875202519040, 47875202572287,
-STORE, 47875202408448, 47875202519039,
-STORE, 47875202093056, 47875202408447,
-ERASE, 47875202093056, 47875202093056,
-STORE, 47875202093056, 47875202408447,
-STORE, 47875202514944, 47875202519039,
-STORE, 47875202408448, 47875202514943,
-ERASE, 47875202408448, 47875202408448,
-STORE, 47875202408448, 47875202514943,
-ERASE, 47875202519040, 47875202519040,
-STORE, 47875202519040, 47875202572287,
-STORE, 47875202572288, 47875205623807,
-STORE, 47875203117056, 47875205623807,
-STORE, 47875202572288, 47875203117055,
-ERASE, 47875203117056, 47875203117056,
-STORE, 47875203117056, 47875205402623,
-STORE, 47875205402624, 47875205623807,
-STORE, 47875204812800, 47875205402623,
-STORE, 47875203117056, 47875204812799,
-ERASE, 47875203117056, 47875203117056,
-STORE, 47875203117056, 47875204812799,
-STORE, 47875205398528, 47875205402623,
-STORE, 47875204812800, 47875205398527,
-ERASE, 47875204812800, 47875204812800,
-STORE, 47875204812800, 47875205398527,
-STORE, 47875205607424, 47875205623807,
-STORE, 47875205402624, 47875205607423,
-ERASE, 47875205402624, 47875205402624,
-STORE, 47875205402624, 47875205607423,
-ERASE, 47875205607424, 47875205607424,
-STORE, 47875205607424, 47875205623807,
-STORE, 47875205623808, 47875205656575,
-ERASE, 47875205623808, 47875205623808,
-STORE, 47875205623808, 47875205631999,
-STORE, 47875205632000, 47875205656575,
-STORE, 47875205644288, 47875205656575,
-STORE, 47875205632000, 47875205644287,
-ERASE, 47875205632000, 47875205632000,
-STORE, 47875205632000, 47875205644287,
-STORE, 47875205648384, 47875205656575,
-STORE, 47875205644288, 47875205648383,
-ERASE, 47875205644288, 47875205644288,
-STORE, 47875205644288, 47875205656575,
-ERASE, 47875205644288, 47875205644288,
-STORE, 47875205644288, 47875205648383,
-STORE, 47875205648384, 47875205656575,
-ERASE, 47875205648384, 47875205648384,
-STORE, 47875205648384, 47875205656575,
-STORE, 47875205656576, 47875205693439,
-ERASE, 47875205656576, 47875205656576,
-STORE, 47875205656576, 47875205664767,
-STORE, 47875205664768, 47875205693439,
-STORE, 47875205681152, 47875205693439,
-STORE, 47875205664768, 47875205681151,
-ERASE, 47875205664768, 47875205664768,
-STORE, 47875205664768, 47875205681151,
-STORE, 47875205685248, 47875205693439,
-STORE, 47875205681152, 47875205685247,
-ERASE, 47875205681152, 47875205681152,
-STORE, 47875205681152, 47875205693439,
-ERASE, 47875205681152, 47875205681152,
-STORE, 47875205681152, 47875205685247,
-STORE, 47875205685248, 47875205693439,
-ERASE, 47875205685248, 47875205685248,
-STORE, 47875205685248, 47875205693439,
-STORE, 47875205693440, 47875206168575,
-ERASE, 47875205693440, 47875205693440,
-STORE, 47875205693440, 47875205701631,
-STORE, 47875205701632, 47875206168575,
-STORE, 47875206037504, 47875206168575,
-STORE, 47875205701632, 47875206037503,
-ERASE, 47875205701632, 47875205701632,
-STORE, 47875205701632, 47875206037503,
-STORE, 47875206160384, 47875206168575,
-STORE, 47875206037504, 47875206160383,
-ERASE, 47875206037504, 47875206037504,
-STORE, 47875206037504, 47875206168575,
-ERASE, 47875206037504, 47875206037504,
-STORE, 47875206037504, 47875206160383,
-STORE, 47875206160384, 47875206168575,
-ERASE, 47875206160384, 47875206160384,
-STORE, 47875206160384, 47875206168575,
-STORE, 47875206168576, 47875206176767,
-STORE, 47875206176768, 47875206197247,
-ERASE, 47875206176768, 47875206176768,
-STORE, 47875206176768, 47875206180863,
-STORE, 47875206180864, 47875206197247,
-STORE, 47875206184960, 47875206197247,
-STORE, 47875206180864, 47875206184959,
-ERASE, 47875206180864, 47875206180864,
-STORE, 47875206180864, 47875206184959,
-STORE, 47875206189056, 47875206197247,
-STORE, 47875206184960, 47875206189055,
-ERASE, 47875206184960, 47875206184960,
-STORE, 47875206184960, 47875206197247,
-ERASE, 47875206184960, 47875206184960,
-STORE, 47875206184960, 47875206189055,
-STORE, 47875206189056, 47875206197247,
-ERASE, 47875206189056, 47875206189056,
-STORE, 47875206189056, 47875206197247,
-STORE, 47875206197248, 47875206205439,
-ERASE, 47875198861312, 47875198861312,
-STORE, 47875198861312, 47875198877695,
-STORE, 47875198877696, 47875198885887,
-ERASE, 47875206189056, 47875206189056,
-STORE, 47875206189056, 47875206193151,
-STORE, 47875206193152, 47875206197247,
-ERASE, 47875201777664, 47875201777664,
-STORE, 47875201777664, 47875201781759,
-STORE, 47875201781760, 47875201785855,
-ERASE, 47875206160384, 47875206160384,
-STORE, 47875206160384, 47875206164479,
-STORE, 47875206164480, 47875206168575,
-ERASE, 47875205685248, 47875205685248,
-STORE, 47875205685248, 47875205689343,
-STORE, 47875205689344, 47875205693439,
-ERASE, 47875205648384, 47875205648384,
-STORE, 47875205648384, 47875205652479,
-STORE, 47875205652480, 47875205656575,
-ERASE, 47875205402624, 47875205402624,
-STORE, 47875205402624, 47875205599231,
-STORE, 47875205599232, 47875205607423,
-ERASE, 47875202519040, 47875202519040,
-STORE, 47875202519040, 47875202555903,
-STORE, 47875202555904, 47875202572287,
-ERASE, 47875201966080, 47875201966080,
-STORE, 47875201966080, 47875201970175,
-STORE, 47875201970176, 47875201974271,
-ERASE, 47875201650688, 47875201650688,
-STORE, 47875201650688, 47875201654783,
-STORE, 47875201654784, 47875201658879,
-ERASE, 47875199381504, 47875199381504,
-STORE, 47875199381504, 47875199401983,
-STORE, 47875199401984, 47875199406079,
-ERASE, 47875199049728, 47875199049728,
-STORE, 47875199049728, 47875199053823,
-STORE, 47875199053824, 47875199057919,
-ERASE, 47875199004672, 47875199004672,
-STORE, 47875199004672, 47875199008767,
-STORE, 47875199008768, 47875199012863,
-ERASE, 94011547025408, 94011547025408,
-STORE, 94011547025408, 94011547148287,
-STORE, 94011547148288, 94011547152383,
-ERASE, 139757598109696, 139757598109696,
-STORE, 139757598109696, 139757598113791,
-STORE, 139757598113792, 139757598117887,
-ERASE, 47875197046784, 47875197046784,
-STORE, 94011557584896, 94011557720063,
-STORE, 94011557584896, 94011557855231,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557851135,
-STORE, 94011557851136, 94011557855231,
-ERASE, 94011557851136, 94011557851136,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557847039,
-STORE, 94011557847040, 94011557851135,
-ERASE, 94011557847040, 94011557847040,
-STORE, 94011557584896, 94011557982207,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557978111,
-STORE, 94011557978112, 94011557982207,
-ERASE, 94011557978112, 94011557978112,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557974015,
-STORE, 94011557974016, 94011557978111,
-ERASE, 94011557974016, 94011557974016,
-STORE, 140737488347136, 140737488351231,
-STORE, 140734130360320, 140737488351231,
-ERASE, 140734130360320, 140734130360320,
-STORE, 140734130360320, 140734130364415,
-STORE, 94641232105472, 94641232785407,
-ERASE, 94641232105472, 94641232105472,
-STORE, 94641232105472, 94641232171007,
-STORE, 94641232171008, 94641232785407,
-ERASE, 94641232171008, 94641232171008,
-STORE, 94641232171008, 94641232519167,
-STORE, 94641232519168, 94641232658431,
-STORE, 94641232658432, 94641232785407,
-STORE, 139726599516160, 139726599688191,
-ERASE, 139726599516160, 139726599516160,
-STORE, 139726599516160, 139726599520255,
-STORE, 139726599520256, 139726599688191,
-ERASE, 139726599520256, 139726599520256,
-STORE, 139726599520256, 139726599643135,
-STORE, 139726599643136, 139726599675903,
-STORE, 139726599675904, 139726599684095,
-STORE, 139726599684096, 139726599688191,
-STORE, 140734130446336, 140734130450431,
-STORE, 140734130434048, 140734130446335,
-STORE, 47906195480576, 47906195488767,
-STORE, 47906195488768, 47906195496959,
-STORE, 47906195496960, 47906197336063,
-STORE, 47906195636224, 47906197336063,
-STORE, 47906195496960, 47906195636223,
-ERASE, 47906195636224, 47906195636224,
-STORE, 47906195636224, 47906197295103,
-STORE, 47906197295104, 47906197336063,
-STORE, 47906196979712, 47906197295103,
-STORE, 47906195636224, 47906196979711,
-ERASE, 47906195636224, 47906195636224,
-STORE, 47906195636224, 47906196979711,
-STORE, 47906197291008, 47906197295103,
-STORE, 47906196979712, 47906197291007,
-ERASE, 47906196979712, 47906196979712,
-STORE, 47906196979712, 47906197291007,
-STORE, 47906197319680, 47906197336063,
-STORE, 47906197295104, 47906197319679,
-ERASE, 47906197295104, 47906197295104,
-STORE, 47906197295104, 47906197319679,
-ERASE, 47906197319680, 47906197319680,
-STORE, 47906197319680, 47906197336063,
-STORE, 47906197336064, 47906197446655,
-STORE, 47906197352448, 47906197446655,
-STORE, 47906197336064, 47906197352447,
-ERASE, 47906197352448, 47906197352448,
-STORE, 47906197352448, 47906197438463,
-STORE, 47906197438464, 47906197446655,
-STORE, 47906197413888, 47906197438463,
-STORE, 47906197352448, 47906197413887,
-ERASE, 47906197352448, 47906197352448,
-STORE, 47906197352448, 47906197413887,
-STORE, 47906197434368, 47906197438463,
-STORE, 47906197413888, 47906197434367,
-ERASE, 47906197413888, 47906197413888,
-STORE, 47906197413888, 47906197434367,
-ERASE, 47906197438464, 47906197438464,
-STORE, 47906197438464, 47906197446655,
-STORE, 47906197446656, 47906197491711,
-ERASE, 47906197446656, 47906197446656,
-STORE, 47906197446656, 47906197454847,
-STORE, 47906197454848, 47906197491711,
-STORE, 47906197475328, 47906197491711,
-STORE, 47906197454848, 47906197475327,
-ERASE, 47906197454848, 47906197454848,
-STORE, 47906197454848, 47906197475327,
-STORE, 47906197483520, 47906197491711,
-STORE, 47906197475328, 47906197483519,
-ERASE, 47906197475328, 47906197475328,
-STORE, 47906197475328, 47906197491711,
-ERASE, 47906197475328, 47906197475328,
-STORE, 47906197475328, 47906197483519,
-STORE, 47906197483520, 47906197491711,
-ERASE, 47906197483520, 47906197483520,
-STORE, 47906197483520, 47906197491711,
-STORE, 47906197491712, 47906197839871,
-STORE, 47906197532672, 47906197839871,
-STORE, 47906197491712, 47906197532671,
-ERASE, 47906197532672, 47906197532672,
-STORE, 47906197532672, 47906197815295,
-STORE, 47906197815296, 47906197839871,
-STORE, 47906197745664, 47906197815295,
-STORE, 47906197532672, 47906197745663,
-ERASE, 47906197532672, 47906197532672,
-STORE, 47906197532672, 47906197745663,
-STORE, 47906197811200, 47906197815295,
-STORE, 47906197745664, 47906197811199,
-ERASE, 47906197745664, 47906197745664,
-STORE, 47906197745664, 47906197811199,
-ERASE, 47906197815296, 47906197815296,
-STORE, 47906197815296, 47906197839871,
-STORE, 47906197839872, 47906200100863,
-STORE, 47906197991424, 47906200100863,
-STORE, 47906197839872, 47906197991423,
-ERASE, 47906197991424, 47906197991424,
-STORE, 47906197991424, 47906200084479,
-STORE, 47906200084480, 47906200100863,
-STORE, 47906200092672, 47906200100863,
-STORE, 47906200084480, 47906200092671,
-ERASE, 47906200084480, 47906200084480,
-STORE, 47906200084480, 47906200092671,
-ERASE, 47906200092672, 47906200092672,
-STORE, 47906200092672, 47906200100863,
-STORE, 47906200100864, 47906200236031,
-ERASE, 47906200100864, 47906200100864,
-STORE, 47906200100864, 47906200125439,
-STORE, 47906200125440, 47906200236031,
-STORE, 47906200186880, 47906200236031,
-STORE, 47906200125440, 47906200186879,
-ERASE, 47906200125440, 47906200125440,
-STORE, 47906200125440, 47906200186879,
-STORE, 47906200211456, 47906200236031,
-STORE, 47906200186880, 47906200211455,
-ERASE, 47906200186880, 47906200186880,
-STORE, 47906200186880, 47906200236031,
-ERASE, 47906200186880, 47906200186880,
-STORE, 47906200186880, 47906200211455,
-STORE, 47906200211456, 47906200236031,
-STORE, 47906200219648, 47906200236031,
-STORE, 47906200211456, 47906200219647,
-ERASE, 47906200211456, 47906200211456,
-STORE, 47906200211456, 47906200219647,
-ERASE, 47906200219648, 47906200219648,
-STORE, 47906200219648, 47906200236031,
-STORE, 47906200219648, 47906200244223,
-STORE, 47906200244224, 47906200408063,
-ERASE, 47906200244224, 47906200244224,
-STORE, 47906200244224, 47906200256511,
-STORE, 47906200256512, 47906200408063,
-STORE, 47906200354816, 47906200408063,
-STORE, 47906200256512, 47906200354815,
-ERASE, 47906200256512, 47906200256512,
-STORE, 47906200256512, 47906200354815,
-STORE, 47906200399872, 47906200408063,
-STORE, 47906200354816, 47906200399871,
-ERASE, 47906200354816, 47906200354816,
-STORE, 47906200354816, 47906200408063,
-ERASE, 47906200354816, 47906200354816,
-STORE, 47906200354816, 47906200399871,
-STORE, 47906200399872, 47906200408063,
-ERASE, 47906200399872, 47906200399872,
-STORE, 47906200399872, 47906200408063,
-STORE, 47906200408064, 47906201006079,
-STORE, 47906200526848, 47906201006079,
-STORE, 47906200408064, 47906200526847,
-ERASE, 47906200526848, 47906200526848,
-STORE, 47906200526848, 47906200952831,
-STORE, 47906200952832, 47906201006079,
-STORE, 47906200842240, 47906200952831,
-STORE, 47906200526848, 47906200842239,
-ERASE, 47906200526848, 47906200526848,
-STORE, 47906200526848, 47906200842239,
-STORE, 47906200948736, 47906200952831,
-STORE, 47906200842240, 47906200948735,
-ERASE, 47906200842240, 47906200842240,
-STORE, 47906200842240, 47906200948735,
-ERASE, 47906200952832, 47906200952832,
-STORE, 47906200952832, 47906201006079,
-STORE, 47906201006080, 47906204057599,
-STORE, 47906201550848, 47906204057599,
-STORE, 47906201006080, 47906201550847,
-ERASE, 47906201550848, 47906201550848,
-STORE, 47906201550848, 47906203836415,
-STORE, 47906203836416, 47906204057599,
-STORE, 47906203246592, 47906203836415,
-STORE, 47906201550848, 47906203246591,
-ERASE, 47906201550848, 47906201550848,
-STORE, 47906201550848, 47906203246591,
-STORE, 47906203832320, 47906203836415,
-STORE, 47906203246592, 47906203832319,
-ERASE, 47906203246592, 47906203246592,
-STORE, 47906203246592, 47906203832319,
-STORE, 47906204041216, 47906204057599,
-STORE, 47906203836416, 47906204041215,
-ERASE, 47906203836416, 47906203836416,
-STORE, 47906203836416, 47906204041215,
-ERASE, 47906204041216, 47906204041216,
-STORE, 47906204041216, 47906204057599,
-STORE, 47906204057600, 47906204090367,
-ERASE, 47906204057600, 47906204057600,
-STORE, 47906204057600, 47906204065791,
-STORE, 47906204065792, 47906204090367,
-STORE, 47906204078080, 47906204090367,
-STORE, 47906204065792, 47906204078079,
-ERASE, 47906204065792, 47906204065792,
-STORE, 47906204065792, 47906204078079,
-STORE, 47906204082176, 47906204090367,
-STORE, 47906204078080, 47906204082175,
-ERASE, 47906204078080, 47906204078080,
-STORE, 47906204078080, 47906204090367,
-ERASE, 47906204078080, 47906204078080,
-STORE, 47906204078080, 47906204082175,
-STORE, 47906204082176, 47906204090367,
-ERASE, 47906204082176, 47906204082176,
-STORE, 47906204082176, 47906204090367,
-STORE, 47906204090368, 47906204127231,
-ERASE, 47906204090368, 47906204090368,
-STORE, 47906204090368, 47906204098559,
-STORE, 47906204098560, 47906204127231,
-STORE, 47906204114944, 47906204127231,
-STORE, 47906204098560, 47906204114943,
-ERASE, 47906204098560, 47906204098560,
-STORE, 47906204098560, 47906204114943,
-STORE, 47906204119040, 47906204127231,
-STORE, 47906204114944, 47906204119039,
-ERASE, 47906204114944, 47906204114944,
-STORE, 47906204114944, 47906204127231,
-ERASE, 47906204114944, 47906204114944,
-STORE, 47906204114944, 47906204119039,
-STORE, 47906204119040, 47906204127231,
-ERASE, 47906204119040, 47906204119040,
-STORE, 47906204119040, 47906204127231,
-STORE, 47906204127232, 47906204602367,
-ERASE, 47906204127232, 47906204127232,
-STORE, 47906204127232, 47906204135423,
-STORE, 47906204135424, 47906204602367,
-STORE, 47906204471296, 47906204602367,
-STORE, 47906204135424, 47906204471295,
-ERASE, 47906204135424, 47906204135424,
-STORE, 47906204135424, 47906204471295,
-STORE, 47906204594176, 47906204602367,
-STORE, 47906204471296, 47906204594175,
-ERASE, 47906204471296, 47906204471296,
-STORE, 47906204471296, 47906204602367,
-ERASE, 47906204471296, 47906204471296,
-STORE, 47906204471296, 47906204594175,
-STORE, 47906204594176, 47906204602367,
-ERASE, 47906204594176, 47906204594176,
-STORE, 47906204594176, 47906204602367,
-STORE, 47906204602368, 47906204610559,
-STORE, 47906204610560, 47906204631039,
-ERASE, 47906204610560, 47906204610560,
-STORE, 47906204610560, 47906204614655,
-STORE, 47906204614656, 47906204631039,
-STORE, 47906204618752, 47906204631039,
-STORE, 47906204614656, 47906204618751,
-ERASE, 47906204614656, 47906204614656,
-STORE, 47906204614656, 47906204618751,
-STORE, 47906204622848, 47906204631039,
-STORE, 47906204618752, 47906204622847,
-ERASE, 47906204618752, 47906204618752,
-STORE, 47906204618752, 47906204631039,
-ERASE, 47906204618752, 47906204618752,
-STORE, 47906204618752, 47906204622847,
-STORE, 47906204622848, 47906204631039,
-ERASE, 47906204622848, 47906204622848,
-STORE, 47906204622848, 47906204631039,
-STORE, 47906204631040, 47906204639231,
-ERASE, 47906197295104, 47906197295104,
-STORE, 47906197295104, 47906197311487,
-STORE, 47906197311488, 47906197319679,
-ERASE, 47906204622848, 47906204622848,
-STORE, 47906204622848, 47906204626943,
-STORE, 47906204626944, 47906204631039,
-ERASE, 47906200211456, 47906200211456,
-STORE, 47906200211456, 47906200215551,
-STORE, 47906200215552, 47906200219647,
-ERASE, 47906204594176, 47906204594176,
-STORE, 47906204594176, 47906204598271,
-STORE, 47906204598272, 47906204602367,
-ERASE, 47906204119040, 47906204119040,
-STORE, 47906204119040, 47906204123135,
-STORE, 47906204123136, 47906204127231,
-ERASE, 47906204082176, 47906204082176,
-STORE, 47906204082176, 47906204086271,
-STORE, 47906204086272, 47906204090367,
-ERASE, 47906203836416, 47906203836416,
-STORE, 47906203836416, 47906204033023,
-STORE, 47906204033024, 47906204041215,
-ERASE, 47906200952832, 47906200952832,
-STORE, 47906200952832, 47906200989695,
-STORE, 47906200989696, 47906201006079,
-ERASE, 47906200399872, 47906200399872,
-STORE, 47906200399872, 47906200403967,
-STORE, 47906200403968, 47906200408063,
-ERASE, 47906200084480, 47906200084480,
-STORE, 47906200084480, 47906200088575,
-STORE, 47906200088576, 47906200092671,
-ERASE, 47906197815296, 47906197815296,
-STORE, 47906197815296, 47906197835775,
-STORE, 47906197835776, 47906197839871,
-ERASE, 47906197483520, 47906197483520,
-STORE, 47906197483520, 47906197487615,
-STORE, 47906197487616, 47906197491711,
-ERASE, 47906197438464, 47906197438464,
-STORE, 47906197438464, 47906197442559,
-STORE, 47906197442560, 47906197446655,
-ERASE, 94641232658432, 94641232658432,
-STORE, 94641232658432, 94641232781311,
-STORE, 94641232781312, 94641232785407,
-ERASE, 139726599675904, 139726599675904,
-STORE, 139726599675904, 139726599679999,
-STORE, 139726599680000, 139726599684095,
-ERASE, 47906195480576, 47906195480576,
-STORE, 94641242615808, 94641242750975,
- };
-
- unsigned long set10[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140736427839488, 140737488351231,
-ERASE, 140736427839488, 140736427839488,
-STORE, 140736427839488, 140736427843583,
-STORE, 94071213395968, 94071213567999,
-ERASE, 94071213395968, 94071213395968,
-STORE, 94071213395968, 94071213412351,
-STORE, 94071213412352, 94071213567999,
-ERASE, 94071213412352, 94071213412352,
-STORE, 94071213412352, 94071213514751,
-STORE, 94071213514752, 94071213555711,
-STORE, 94071213555712, 94071213567999,
-STORE, 139968410644480, 139968410816511,
-ERASE, 139968410644480, 139968410644480,
-STORE, 139968410644480, 139968410648575,
-STORE, 139968410648576, 139968410816511,
-ERASE, 139968410648576, 139968410648576,
-STORE, 139968410648576, 139968410771455,
-STORE, 139968410771456, 139968410804223,
-STORE, 139968410804224, 139968410812415,
-STORE, 139968410812416, 139968410816511,
-STORE, 140736429277184, 140736429281279,
-STORE, 140736429264896, 140736429277183,
-STORE, 47664384352256, 47664384360447,
-STORE, 47664384360448, 47664384368639,
-STORE, 47664384368640, 47664384532479,
-ERASE, 47664384368640, 47664384368640,
-STORE, 47664384368640, 47664384380927,
-STORE, 47664384380928, 47664384532479,
-STORE, 47664384479232, 47664384532479,
-STORE, 47664384380928, 47664384479231,
-ERASE, 47664384380928, 47664384380928,
-STORE, 47664384380928, 47664384479231,
-STORE, 47664384524288, 47664384532479,
-STORE, 47664384479232, 47664384524287,
-ERASE, 47664384479232, 47664384479232,
-STORE, 47664384479232, 47664384532479,
-ERASE, 47664384479232, 47664384479232,
-STORE, 47664384479232, 47664384524287,
-STORE, 47664384524288, 47664384532479,
-ERASE, 47664384524288, 47664384524288,
-STORE, 47664384524288, 47664384532479,
-STORE, 47664384532480, 47664387583999,
-STORE, 47664385077248, 47664387583999,
-STORE, 47664384532480, 47664385077247,
-ERASE, 47664385077248, 47664385077248,
-STORE, 47664385077248, 47664387362815,
-STORE, 47664387362816, 47664387583999,
-STORE, 47664386772992, 47664387362815,
-STORE, 47664385077248, 47664386772991,
-ERASE, 47664385077248, 47664385077248,
-STORE, 47664385077248, 47664386772991,
-STORE, 47664387358720, 47664387362815,
-STORE, 47664386772992, 47664387358719,
-ERASE, 47664386772992, 47664386772992,
-STORE, 47664386772992, 47664387358719,
-STORE, 47664387567616, 47664387583999,
-STORE, 47664387362816, 47664387567615,
-ERASE, 47664387362816, 47664387362816,
-STORE, 47664387362816, 47664387567615,
-ERASE, 47664387567616, 47664387567616,
-STORE, 47664387567616, 47664387583999,
-STORE, 47664387584000, 47664389423103,
-STORE, 47664387723264, 47664389423103,
-STORE, 47664387584000, 47664387723263,
-ERASE, 47664387723264, 47664387723264,
-STORE, 47664387723264, 47664389382143,
-STORE, 47664389382144, 47664389423103,
-STORE, 47664389066752, 47664389382143,
-STORE, 47664387723264, 47664389066751,
-ERASE, 47664387723264, 47664387723264,
-STORE, 47664387723264, 47664389066751,
-STORE, 47664389378048, 47664389382143,
-STORE, 47664389066752, 47664389378047,
-ERASE, 47664389066752, 47664389066752,
-STORE, 47664389066752, 47664389378047,
-STORE, 47664389406720, 47664389423103,
-STORE, 47664389382144, 47664389406719,
-ERASE, 47664389382144, 47664389382144,
-STORE, 47664389382144, 47664389406719,
-ERASE, 47664389406720, 47664389406720,
-STORE, 47664389406720, 47664389423103,
-STORE, 47664389423104, 47664389558271,
-ERASE, 47664389423104, 47664389423104,
-STORE, 47664389423104, 47664389447679,
-STORE, 47664389447680, 47664389558271,
-STORE, 47664389509120, 47664389558271,
-STORE, 47664389447680, 47664389509119,
-ERASE, 47664389447680, 47664389447680,
-STORE, 47664389447680, 47664389509119,
-STORE, 47664389533696, 47664389558271,
-STORE, 47664389509120, 47664389533695,
-ERASE, 47664389509120, 47664389509120,
-STORE, 47664389509120, 47664389558271,
-ERASE, 47664389509120, 47664389509120,
-STORE, 47664389509120, 47664389533695,
-STORE, 47664389533696, 47664389558271,
-STORE, 47664389541888, 47664389558271,
-STORE, 47664389533696, 47664389541887,
-ERASE, 47664389533696, 47664389533696,
-STORE, 47664389533696, 47664389541887,
-ERASE, 47664389541888, 47664389541888,
-STORE, 47664389541888, 47664389558271,
-STORE, 47664389558272, 47664389578751,
-ERASE, 47664389558272, 47664389558272,
-STORE, 47664389558272, 47664389562367,
-STORE, 47664389562368, 47664389578751,
-STORE, 47664389566464, 47664389578751,
-STORE, 47664389562368, 47664389566463,
-ERASE, 47664389562368, 47664389562368,
-STORE, 47664389562368, 47664389566463,
-STORE, 47664389570560, 47664389578751,
-STORE, 47664389566464, 47664389570559,
-ERASE, 47664389566464, 47664389566464,
-STORE, 47664389566464, 47664389578751,
-ERASE, 47664389566464, 47664389566464,
-STORE, 47664389566464, 47664389570559,
-STORE, 47664389570560, 47664389578751,
-ERASE, 47664389570560, 47664389570560,
-STORE, 47664389570560, 47664389578751,
-STORE, 47664389578752, 47664389586943,
-ERASE, 47664389382144, 47664389382144,
-STORE, 47664389382144, 47664389398527,
-STORE, 47664389398528, 47664389406719,
-ERASE, 47664389570560, 47664389570560,
-STORE, 47664389570560, 47664389574655,
-STORE, 47664389574656, 47664389578751,
-ERASE, 47664389533696, 47664389533696,
-STORE, 47664389533696, 47664389537791,
-STORE, 47664389537792, 47664389541887,
-ERASE, 47664387362816, 47664387362816,
-STORE, 47664387362816, 47664387559423,
-STORE, 47664387559424, 47664387567615,
-ERASE, 47664384524288, 47664384524288,
-STORE, 47664384524288, 47664384528383,
-STORE, 47664384528384, 47664384532479,
-ERASE, 94071213555712, 94071213555712,
-STORE, 94071213555712, 94071213563903,
-STORE, 94071213563904, 94071213567999,
-ERASE, 139968410804224, 139968410804224,
-STORE, 139968410804224, 139968410808319,
-STORE, 139968410808320, 139968410812415,
-ERASE, 47664384352256, 47664384352256,
-STORE, 94071244402688, 94071244537855,
-STORE, 140737488347136, 140737488351231,
-STORE, 140728271503360, 140737488351231,
-ERASE, 140728271503360, 140728271503360,
-STORE, 140728271503360, 140728271507455,
-STORE, 94410361982976, 94410362155007,
-ERASE, 94410361982976, 94410361982976,
-STORE, 94410361982976, 94410361999359,
-STORE, 94410361999360, 94410362155007,
-ERASE, 94410361999360, 94410361999360,
-STORE, 94410361999360, 94410362101759,
-STORE, 94410362101760, 94410362142719,
-STORE, 94410362142720, 94410362155007,
-STORE, 140351953997824, 140351954169855,
-ERASE, 140351953997824, 140351953997824,
-STORE, 140351953997824, 140351954001919,
-STORE, 140351954001920, 140351954169855,
-ERASE, 140351954001920, 140351954001920,
-STORE, 140351954001920, 140351954124799,
-STORE, 140351954124800, 140351954157567,
-STORE, 140351954157568, 140351954165759,
-STORE, 140351954165760, 140351954169855,
-STORE, 140728272429056, 140728272433151,
-STORE, 140728272416768, 140728272429055,
-STORE, 47280840998912, 47280841007103,
-STORE, 47280841007104, 47280841015295,
-STORE, 47280841015296, 47280841179135,
-ERASE, 47280841015296, 47280841015296,
-STORE, 47280841015296, 47280841027583,
-STORE, 47280841027584, 47280841179135,
-STORE, 47280841125888, 47280841179135,
-STORE, 47280841027584, 47280841125887,
-ERASE, 47280841027584, 47280841027584,
-STORE, 47280841027584, 47280841125887,
-STORE, 47280841170944, 47280841179135,
-STORE, 47280841125888, 47280841170943,
-ERASE, 47280841125888, 47280841125888,
-STORE, 47280841125888, 47280841179135,
-ERASE, 47280841125888, 47280841125888,
-STORE, 47280841125888, 47280841170943,
-STORE, 47280841170944, 47280841179135,
-ERASE, 47280841170944, 47280841170944,
-STORE, 47280841170944, 47280841179135,
-STORE, 47280841179136, 47280844230655,
-STORE, 47280841723904, 47280844230655,
-STORE, 47280841179136, 47280841723903,
-ERASE, 47280841723904, 47280841723904,
-STORE, 47280841723904, 47280844009471,
-STORE, 47280844009472, 47280844230655,
-STORE, 47280843419648, 47280844009471,
-STORE, 47280841723904, 47280843419647,
-ERASE, 47280841723904, 47280841723904,
-STORE, 47280841723904, 47280843419647,
-STORE, 47280844005376, 47280844009471,
-STORE, 47280843419648, 47280844005375,
-ERASE, 47280843419648, 47280843419648,
-STORE, 47280843419648, 47280844005375,
-STORE, 47280844214272, 47280844230655,
-STORE, 47280844009472, 47280844214271,
-ERASE, 47280844009472, 47280844009472,
-STORE, 47280844009472, 47280844214271,
-ERASE, 47280844214272, 47280844214272,
-STORE, 47280844214272, 47280844230655,
-STORE, 47280844230656, 47280846069759,
-STORE, 47280844369920, 47280846069759,
-STORE, 47280844230656, 47280844369919,
-ERASE, 47280844369920, 47280844369920,
-STORE, 47280844369920, 47280846028799,
-STORE, 47280846028800, 47280846069759,
-STORE, 47280845713408, 47280846028799,
-STORE, 47280844369920, 47280845713407,
-ERASE, 47280844369920, 47280844369920,
-STORE, 47280844369920, 47280845713407,
-STORE, 47280846024704, 47280846028799,
-STORE, 47280845713408, 47280846024703,
-ERASE, 47280845713408, 47280845713408,
-STORE, 47280845713408, 47280846024703,
-STORE, 47280846053376, 47280846069759,
-STORE, 47280846028800, 47280846053375,
-ERASE, 47280846028800, 47280846028800,
-STORE, 47280846028800, 47280846053375,
-ERASE, 47280846053376, 47280846053376,
-STORE, 47280846053376, 47280846069759,
-STORE, 47280846069760, 47280846204927,
-ERASE, 47280846069760, 47280846069760,
-STORE, 47280846069760, 47280846094335,
-STORE, 47280846094336, 47280846204927,
-STORE, 47280846155776, 47280846204927,
-STORE, 47280846094336, 47280846155775,
-ERASE, 47280846094336, 47280846094336,
-STORE, 47280846094336, 47280846155775,
-STORE, 47280846180352, 47280846204927,
-STORE, 47280846155776, 47280846180351,
-ERASE, 47280846155776, 47280846155776,
-STORE, 47280846155776, 47280846204927,
-ERASE, 47280846155776, 47280846155776,
-STORE, 47280846155776, 47280846180351,
-STORE, 47280846180352, 47280846204927,
-STORE, 47280846188544, 47280846204927,
-STORE, 47280846180352, 47280846188543,
-ERASE, 47280846180352, 47280846180352,
-STORE, 47280846180352, 47280846188543,
-ERASE, 47280846188544, 47280846188544,
-STORE, 47280846188544, 47280846204927,
-STORE, 47280846204928, 47280846225407,
-ERASE, 47280846204928, 47280846204928,
-STORE, 47280846204928, 47280846209023,
-STORE, 47280846209024, 47280846225407,
-STORE, 47280846213120, 47280846225407,
-STORE, 47280846209024, 47280846213119,
-ERASE, 47280846209024, 47280846209024,
-STORE, 47280846209024, 47280846213119,
-STORE, 47280846217216, 47280846225407,
-STORE, 47280846213120, 47280846217215,
-ERASE, 47280846213120, 47280846213120,
-STORE, 47280846213120, 47280846225407,
-ERASE, 47280846213120, 47280846213120,
-STORE, 47280846213120, 47280846217215,
-STORE, 47280846217216, 47280846225407,
-ERASE, 47280846217216, 47280846217216,
-STORE, 47280846217216, 47280846225407,
-STORE, 47280846225408, 47280846233599,
-ERASE, 47280846028800, 47280846028800,
-STORE, 47280846028800, 47280846045183,
-STORE, 47280846045184, 47280846053375,
-ERASE, 47280846217216, 47280846217216,
-STORE, 47280846217216, 47280846221311,
-STORE, 47280846221312, 47280846225407,
-ERASE, 47280846180352, 47280846180352,
-STORE, 47280846180352, 47280846184447,
-STORE, 47280846184448, 47280846188543,
-ERASE, 47280844009472, 47280844009472,
-STORE, 47280844009472, 47280844206079,
-STORE, 47280844206080, 47280844214271,
-ERASE, 47280841170944, 47280841170944,
-STORE, 47280841170944, 47280841175039,
-STORE, 47280841175040, 47280841179135,
-ERASE, 94410362142720, 94410362142720,
-STORE, 94410362142720, 94410362150911,
-STORE, 94410362150912, 94410362155007,
-ERASE, 140351954157568, 140351954157568,
-STORE, 140351954157568, 140351954161663,
-STORE, 140351954161664, 140351954165759,
-ERASE, 47280840998912, 47280840998912,
-STORE, 94410379456512, 94410379591679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732946362368, 140737488351231,
-ERASE, 140732946362368, 140732946362368,
-STORE, 140732946362368, 140732946366463,
-STORE, 94352937934848, 94352938106879,
-ERASE, 94352937934848, 94352937934848,
-STORE, 94352937934848, 94352937951231,
-STORE, 94352937951232, 94352938106879,
-ERASE, 94352937951232, 94352937951232,
-STORE, 94352937951232, 94352938053631,
-STORE, 94352938053632, 94352938094591,
-STORE, 94352938094592, 94352938106879,
-STORE, 140595518742528, 140595518914559,
-ERASE, 140595518742528, 140595518742528,
-STORE, 140595518742528, 140595518746623,
-STORE, 140595518746624, 140595518914559,
-ERASE, 140595518746624, 140595518746624,
-STORE, 140595518746624, 140595518869503,
-STORE, 140595518869504, 140595518902271,
-STORE, 140595518902272, 140595518910463,
-STORE, 140595518910464, 140595518914559,
-STORE, 140732947468288, 140732947472383,
-STORE, 140732947456000, 140732947468287,
-STORE, 47037276254208, 47037276262399,
-STORE, 47037276262400, 47037276270591,
-STORE, 47037276270592, 47037276434431,
-ERASE, 47037276270592, 47037276270592,
-STORE, 47037276270592, 47037276282879,
-STORE, 47037276282880, 47037276434431,
-STORE, 47037276381184, 47037276434431,
-STORE, 47037276282880, 47037276381183,
-ERASE, 47037276282880, 47037276282880,
-STORE, 47037276282880, 47037276381183,
-STORE, 47037276426240, 47037276434431,
-STORE, 47037276381184, 47037276426239,
-ERASE, 47037276381184, 47037276381184,
-STORE, 47037276381184, 47037276434431,
-ERASE, 47037276381184, 47037276381184,
-STORE, 47037276381184, 47037276426239,
-STORE, 47037276426240, 47037276434431,
-ERASE, 47037276426240, 47037276426240,
-STORE, 47037276426240, 47037276434431,
-STORE, 47037276434432, 47037279485951,
-STORE, 47037276979200, 47037279485951,
-STORE, 47037276434432, 47037276979199,
-ERASE, 47037276979200, 47037276979200,
-STORE, 47037276979200, 47037279264767,
-STORE, 47037279264768, 47037279485951,
-STORE, 47037278674944, 47037279264767,
-STORE, 47037276979200, 47037278674943,
-ERASE, 47037276979200, 47037276979200,
-STORE, 47037276979200, 47037278674943,
-STORE, 47037279260672, 47037279264767,
-STORE, 47037278674944, 47037279260671,
-ERASE, 47037278674944, 47037278674944,
-STORE, 47037278674944, 47037279260671,
-STORE, 47037279469568, 47037279485951,
-STORE, 47037279264768, 47037279469567,
-ERASE, 47037279264768, 47037279264768,
-STORE, 47037279264768, 47037279469567,
-ERASE, 47037279469568, 47037279469568,
-STORE, 47037279469568, 47037279485951,
-STORE, 47037279485952, 47037281325055,
-STORE, 47037279625216, 47037281325055,
-STORE, 47037279485952, 47037279625215,
-ERASE, 47037279625216, 47037279625216,
-STORE, 47037279625216, 47037281284095,
-STORE, 47037281284096, 47037281325055,
-STORE, 47037280968704, 47037281284095,
-STORE, 47037279625216, 47037280968703,
-ERASE, 47037279625216, 47037279625216,
-STORE, 47037279625216, 47037280968703,
-STORE, 47037281280000, 47037281284095,
-STORE, 47037280968704, 47037281279999,
-ERASE, 47037280968704, 47037280968704,
-STORE, 47037280968704, 47037281279999,
-STORE, 47037281308672, 47037281325055,
-STORE, 47037281284096, 47037281308671,
-ERASE, 47037281284096, 47037281284096,
-STORE, 47037281284096, 47037281308671,
-ERASE, 47037281308672, 47037281308672,
-STORE, 47037281308672, 47037281325055,
-STORE, 47037281325056, 47037281460223,
-ERASE, 47037281325056, 47037281325056,
-STORE, 47037281325056, 47037281349631,
-STORE, 47037281349632, 47037281460223,
-STORE, 47037281411072, 47037281460223,
-STORE, 47037281349632, 47037281411071,
-ERASE, 47037281349632, 47037281349632,
-STORE, 47037281349632, 47037281411071,
-STORE, 47037281435648, 47037281460223,
-STORE, 47037281411072, 47037281435647,
-ERASE, 47037281411072, 47037281411072,
-STORE, 47037281411072, 47037281460223,
-ERASE, 47037281411072, 47037281411072,
-STORE, 47037281411072, 47037281435647,
-STORE, 47037281435648, 47037281460223,
-STORE, 47037281443840, 47037281460223,
-STORE, 47037281435648, 47037281443839,
-ERASE, 47037281435648, 47037281435648,
-STORE, 47037281435648, 47037281443839,
-ERASE, 47037281443840, 47037281443840,
-STORE, 47037281443840, 47037281460223,
-STORE, 47037281460224, 47037281480703,
-ERASE, 47037281460224, 47037281460224,
-STORE, 47037281460224, 47037281464319,
-STORE, 47037281464320, 47037281480703,
-STORE, 47037281468416, 47037281480703,
-STORE, 47037281464320, 47037281468415,
-ERASE, 47037281464320, 47037281464320,
-STORE, 47037281464320, 47037281468415,
-STORE, 47037281472512, 47037281480703,
-STORE, 47037281468416, 47037281472511,
-ERASE, 47037281468416, 47037281468416,
-STORE, 47037281468416, 47037281480703,
-ERASE, 47037281468416, 47037281468416,
-STORE, 47037281468416, 47037281472511,
-STORE, 47037281472512, 47037281480703,
-ERASE, 47037281472512, 47037281472512,
-STORE, 47037281472512, 47037281480703,
-STORE, 47037281480704, 47037281488895,
-ERASE, 47037281284096, 47037281284096,
-STORE, 47037281284096, 47037281300479,
-STORE, 47037281300480, 47037281308671,
-ERASE, 47037281472512, 47037281472512,
-STORE, 47037281472512, 47037281476607,
-STORE, 47037281476608, 47037281480703,
-ERASE, 47037281435648, 47037281435648,
-STORE, 47037281435648, 47037281439743,
-STORE, 47037281439744, 47037281443839,
-ERASE, 47037279264768, 47037279264768,
-STORE, 47037279264768, 47037279461375,
-STORE, 47037279461376, 47037279469567,
-ERASE, 47037276426240, 47037276426240,
-STORE, 47037276426240, 47037276430335,
-STORE, 47037276430336, 47037276434431,
-ERASE, 94352938094592, 94352938094592,
-STORE, 94352938094592, 94352938102783,
-STORE, 94352938102784, 94352938106879,
-ERASE, 140595518902272, 140595518902272,
-STORE, 140595518902272, 140595518906367,
-STORE, 140595518906368, 140595518910463,
-ERASE, 47037276254208, 47037276254208,
-STORE, 94352938438656, 94352938573823,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733506027520, 140737488351231,
-ERASE, 140733506027520, 140733506027520,
-STORE, 140733506027520, 140733506031615,
-STORE, 94150123073536, 94150123245567,
-ERASE, 94150123073536, 94150123073536,
-STORE, 94150123073536, 94150123089919,
-STORE, 94150123089920, 94150123245567,
-ERASE, 94150123089920, 94150123089920,
-STORE, 94150123089920, 94150123192319,
-STORE, 94150123192320, 94150123233279,
-STORE, 94150123233280, 94150123245567,
-STORE, 140081290375168, 140081290547199,
-ERASE, 140081290375168, 140081290375168,
-STORE, 140081290375168, 140081290379263,
-STORE, 140081290379264, 140081290547199,
-ERASE, 140081290379264, 140081290379264,
-STORE, 140081290379264, 140081290502143,
-STORE, 140081290502144, 140081290534911,
-STORE, 140081290534912, 140081290543103,
-STORE, 140081290543104, 140081290547199,
-STORE, 140733506707456, 140733506711551,
-STORE, 140733506695168, 140733506707455,
-STORE, 47551504621568, 47551504629759,
-STORE, 47551504629760, 47551504637951,
-STORE, 47551504637952, 47551504801791,
-ERASE, 47551504637952, 47551504637952,
-STORE, 47551504637952, 47551504650239,
-STORE, 47551504650240, 47551504801791,
-STORE, 47551504748544, 47551504801791,
-STORE, 47551504650240, 47551504748543,
-ERASE, 47551504650240, 47551504650240,
-STORE, 47551504650240, 47551504748543,
-STORE, 47551504793600, 47551504801791,
-STORE, 47551504748544, 47551504793599,
-ERASE, 47551504748544, 47551504748544,
-STORE, 47551504748544, 47551504801791,
-ERASE, 47551504748544, 47551504748544,
-STORE, 47551504748544, 47551504793599,
-STORE, 47551504793600, 47551504801791,
-ERASE, 47551504793600, 47551504793600,
-STORE, 47551504793600, 47551504801791,
-STORE, 47551504801792, 47551507853311,
-STORE, 47551505346560, 47551507853311,
-STORE, 47551504801792, 47551505346559,
-ERASE, 47551505346560, 47551505346560,
-STORE, 47551505346560, 47551507632127,
-STORE, 47551507632128, 47551507853311,
-STORE, 47551507042304, 47551507632127,
-STORE, 47551505346560, 47551507042303,
-ERASE, 47551505346560, 47551505346560,
-STORE, 47551505346560, 47551507042303,
-STORE, 47551507628032, 47551507632127,
-STORE, 47551507042304, 47551507628031,
-ERASE, 47551507042304, 47551507042304,
-STORE, 47551507042304, 47551507628031,
-STORE, 47551507836928, 47551507853311,
-STORE, 47551507632128, 47551507836927,
-ERASE, 47551507632128, 47551507632128,
-STORE, 47551507632128, 47551507836927,
-ERASE, 47551507836928, 47551507836928,
-STORE, 47551507836928, 47551507853311,
-STORE, 47551507853312, 47551509692415,
-STORE, 47551507992576, 47551509692415,
-STORE, 47551507853312, 47551507992575,
-ERASE, 47551507992576, 47551507992576,
-STORE, 47551507992576, 47551509651455,
-STORE, 47551509651456, 47551509692415,
-STORE, 47551509336064, 47551509651455,
-STORE, 47551507992576, 47551509336063,
-ERASE, 47551507992576, 47551507992576,
-STORE, 47551507992576, 47551509336063,
-STORE, 47551509647360, 47551509651455,
-STORE, 47551509336064, 47551509647359,
-ERASE, 47551509336064, 47551509336064,
-STORE, 47551509336064, 47551509647359,
-STORE, 47551509676032, 47551509692415,
-STORE, 47551509651456, 47551509676031,
-ERASE, 47551509651456, 47551509651456,
-STORE, 47551509651456, 47551509676031,
-ERASE, 47551509676032, 47551509676032,
-STORE, 47551509676032, 47551509692415,
-STORE, 47551509692416, 47551509827583,
-ERASE, 47551509692416, 47551509692416,
-STORE, 47551509692416, 47551509716991,
-STORE, 47551509716992, 47551509827583,
-STORE, 47551509778432, 47551509827583,
-STORE, 47551509716992, 47551509778431,
-ERASE, 47551509716992, 47551509716992,
-STORE, 47551509716992, 47551509778431,
-STORE, 47551509803008, 47551509827583,
-STORE, 47551509778432, 47551509803007,
-ERASE, 47551509778432, 47551509778432,
-STORE, 47551509778432, 47551509827583,
-ERASE, 47551509778432, 47551509778432,
-STORE, 47551509778432, 47551509803007,
-STORE, 47551509803008, 47551509827583,
-STORE, 47551509811200, 47551509827583,
-STORE, 47551509803008, 47551509811199,
-ERASE, 47551509803008, 47551509803008,
-STORE, 47551509803008, 47551509811199,
-ERASE, 47551509811200, 47551509811200,
-STORE, 47551509811200, 47551509827583,
-STORE, 47551509827584, 47551509848063,
-ERASE, 47551509827584, 47551509827584,
-STORE, 47551509827584, 47551509831679,
-STORE, 47551509831680, 47551509848063,
-STORE, 47551509835776, 47551509848063,
-STORE, 47551509831680, 47551509835775,
-ERASE, 47551509831680, 47551509831680,
-STORE, 47551509831680, 47551509835775,
-STORE, 47551509839872, 47551509848063,
-STORE, 47551509835776, 47551509839871,
-ERASE, 47551509835776, 47551509835776,
-STORE, 47551509835776, 47551509848063,
-ERASE, 47551509835776, 47551509835776,
-STORE, 47551509835776, 47551509839871,
-STORE, 47551509839872, 47551509848063,
-ERASE, 47551509839872, 47551509839872,
-STORE, 47551509839872, 47551509848063,
-STORE, 47551509848064, 47551509856255,
-ERASE, 47551509651456, 47551509651456,
-STORE, 47551509651456, 47551509667839,
-STORE, 47551509667840, 47551509676031,
-ERASE, 47551509839872, 47551509839872,
-STORE, 47551509839872, 47551509843967,
-STORE, 47551509843968, 47551509848063,
-ERASE, 47551509803008, 47551509803008,
-STORE, 47551509803008, 47551509807103,
-STORE, 47551509807104, 47551509811199,
-ERASE, 47551507632128, 47551507632128,
-STORE, 47551507632128, 47551507828735,
-STORE, 47551507828736, 47551507836927,
-ERASE, 47551504793600, 47551504793600,
-STORE, 47551504793600, 47551504797695,
-STORE, 47551504797696, 47551504801791,
-ERASE, 94150123233280, 94150123233280,
-STORE, 94150123233280, 94150123241471,
-STORE, 94150123241472, 94150123245567,
-ERASE, 140081290534912, 140081290534912,
-STORE, 140081290534912, 140081290539007,
-STORE, 140081290539008, 140081290543103,
-ERASE, 47551504621568, 47551504621568,
-STORE, 94150148112384, 94150148247551,
-STORE, 140737488347136, 140737488351231,
-STORE, 140734389334016, 140737488351231,
-ERASE, 140734389334016, 140734389334016,
-STORE, 140734389334016, 140734389338111,
-STORE, 94844636606464, 94844636778495,
-ERASE, 94844636606464, 94844636606464,
-STORE, 94844636606464, 94844636622847,
-STORE, 94844636622848, 94844636778495,
-ERASE, 94844636622848, 94844636622848,
-STORE, 94844636622848, 94844636725247,
-STORE, 94844636725248, 94844636766207,
-STORE, 94844636766208, 94844636778495,
-STORE, 139922765217792, 139922765389823,
-ERASE, 139922765217792, 139922765217792,
-STORE, 139922765217792, 139922765221887,
-STORE, 139922765221888, 139922765389823,
-ERASE, 139922765221888, 139922765221888,
-STORE, 139922765221888, 139922765344767,
-STORE, 139922765344768, 139922765377535,
-STORE, 139922765377536, 139922765385727,
-STORE, 139922765385728, 139922765389823,
-STORE, 140734389678080, 140734389682175,
-STORE, 140734389665792, 140734389678079,
-STORE, 47710029778944, 47710029787135,
-STORE, 47710029787136, 47710029795327,
-STORE, 47710029795328, 47710029959167,
-ERASE, 47710029795328, 47710029795328,
-STORE, 47710029795328, 47710029807615,
-STORE, 47710029807616, 47710029959167,
-STORE, 47710029905920, 47710029959167,
-STORE, 47710029807616, 47710029905919,
-ERASE, 47710029807616, 47710029807616,
-STORE, 47710029807616, 47710029905919,
-STORE, 47710029950976, 47710029959167,
-STORE, 47710029905920, 47710029950975,
-ERASE, 47710029905920, 47710029905920,
-STORE, 47710029905920, 47710029959167,
-ERASE, 47710029905920, 47710029905920,
-STORE, 47710029905920, 47710029950975,
-STORE, 47710029950976, 47710029959167,
-ERASE, 47710029950976, 47710029950976,
-STORE, 47710029950976, 47710029959167,
-STORE, 47710029959168, 47710033010687,
-STORE, 47710030503936, 47710033010687,
-STORE, 47710029959168, 47710030503935,
-ERASE, 47710030503936, 47710030503936,
-STORE, 47710030503936, 47710032789503,
-STORE, 47710032789504, 47710033010687,
-STORE, 47710032199680, 47710032789503,
-STORE, 47710030503936, 47710032199679,
-ERASE, 47710030503936, 47710030503936,
-STORE, 47710030503936, 47710032199679,
-STORE, 47710032785408, 47710032789503,
-STORE, 47710032199680, 47710032785407,
-ERASE, 47710032199680, 47710032199680,
-STORE, 47710032199680, 47710032785407,
-STORE, 47710032994304, 47710033010687,
-STORE, 47710032789504, 47710032994303,
-ERASE, 47710032789504, 47710032789504,
-STORE, 47710032789504, 47710032994303,
-ERASE, 47710032994304, 47710032994304,
-STORE, 47710032994304, 47710033010687,
-STORE, 47710033010688, 47710034849791,
-STORE, 47710033149952, 47710034849791,
-STORE, 47710033010688, 47710033149951,
-ERASE, 47710033149952, 47710033149952,
-STORE, 47710033149952, 47710034808831,
-STORE, 47710034808832, 47710034849791,
-STORE, 47710034493440, 47710034808831,
-STORE, 47710033149952, 47710034493439,
-ERASE, 47710033149952, 47710033149952,
-STORE, 47710033149952, 47710034493439,
-STORE, 47710034804736, 47710034808831,
-STORE, 47710034493440, 47710034804735,
-ERASE, 47710034493440, 47710034493440,
-STORE, 47710034493440, 47710034804735,
-STORE, 47710034833408, 47710034849791,
-STORE, 47710034808832, 47710034833407,
-ERASE, 47710034808832, 47710034808832,
-STORE, 47710034808832, 47710034833407,
-ERASE, 47710034833408, 47710034833408,
-STORE, 47710034833408, 47710034849791,
-STORE, 47710034849792, 47710034984959,
-ERASE, 47710034849792, 47710034849792,
-STORE, 47710034849792, 47710034874367,
-STORE, 47710034874368, 47710034984959,
-STORE, 47710034935808, 47710034984959,
-STORE, 47710034874368, 47710034935807,
-ERASE, 47710034874368, 47710034874368,
-STORE, 47710034874368, 47710034935807,
-STORE, 47710034960384, 47710034984959,
-STORE, 47710034935808, 47710034960383,
-ERASE, 47710034935808, 47710034935808,
-STORE, 47710034935808, 47710034984959,
-ERASE, 47710034935808, 47710034935808,
-STORE, 47710034935808, 47710034960383,
-STORE, 47710034960384, 47710034984959,
-STORE, 47710034968576, 47710034984959,
-STORE, 47710034960384, 47710034968575,
-ERASE, 47710034960384, 47710034960384,
-STORE, 47710034960384, 47710034968575,
-ERASE, 47710034968576, 47710034968576,
-STORE, 47710034968576, 47710034984959,
-STORE, 47710034984960, 47710035005439,
-ERASE, 47710034984960, 47710034984960,
-STORE, 47710034984960, 47710034989055,
-STORE, 47710034989056, 47710035005439,
-STORE, 47710034993152, 47710035005439,
-STORE, 47710034989056, 47710034993151,
-ERASE, 47710034989056, 47710034989056,
-STORE, 47710034989056, 47710034993151,
-STORE, 47710034997248, 47710035005439,
-STORE, 47710034993152, 47710034997247,
-ERASE, 47710034993152, 47710034993152,
-STORE, 47710034993152, 47710035005439,
-ERASE, 47710034993152, 47710034993152,
-STORE, 47710034993152, 47710034997247,
-STORE, 47710034997248, 47710035005439,
-ERASE, 47710034997248, 47710034997248,
-STORE, 47710034997248, 47710035005439,
-STORE, 47710035005440, 47710035013631,
-ERASE, 47710034808832, 47710034808832,
-STORE, 47710034808832, 47710034825215,
-STORE, 47710034825216, 47710034833407,
-ERASE, 47710034997248, 47710034997248,
-STORE, 47710034997248, 47710035001343,
-STORE, 47710035001344, 47710035005439,
-ERASE, 47710034960384, 47710034960384,
-STORE, 47710034960384, 47710034964479,
-STORE, 47710034964480, 47710034968575,
-ERASE, 47710032789504, 47710032789504,
-STORE, 47710032789504, 47710032986111,
-STORE, 47710032986112, 47710032994303,
-ERASE, 47710029950976, 47710029950976,
-STORE, 47710029950976, 47710029955071,
-STORE, 47710029955072, 47710029959167,
-ERASE, 94844636766208, 94844636766208,
-STORE, 94844636766208, 94844636774399,
-STORE, 94844636774400, 94844636778495,
-ERASE, 139922765377536, 139922765377536,
-STORE, 139922765377536, 139922765381631,
-STORE, 139922765381632, 139922765385727,
-ERASE, 47710029778944, 47710029778944,
-STORE, 94844641775616, 94844641910783,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732213886976, 140737488351231,
-ERASE, 140732213886976, 140732213886976,
-STORE, 140732213886976, 140732213891071,
-STORE, 94240508887040, 94240509059071,
-ERASE, 94240508887040, 94240508887040,
-STORE, 94240508887040, 94240508903423,
-STORE, 94240508903424, 94240509059071,
-ERASE, 94240508903424, 94240508903424,
-STORE, 94240508903424, 94240509005823,
-STORE, 94240509005824, 94240509046783,
-STORE, 94240509046784, 94240509059071,
-STORE, 140275106516992, 140275106689023,
-ERASE, 140275106516992, 140275106516992,
-STORE, 140275106516992, 140275106521087,
-STORE, 140275106521088, 140275106689023,
-ERASE, 140275106521088, 140275106521088,
-STORE, 140275106521088, 140275106643967,
-STORE, 140275106643968, 140275106676735,
-STORE, 140275106676736, 140275106684927,
-STORE, 140275106684928, 140275106689023,
-STORE, 140732213977088, 140732213981183,
-STORE, 140732213964800, 140732213977087,
-STORE, 47357688479744, 47357688487935,
-STORE, 47357688487936, 47357688496127,
-STORE, 47357688496128, 47357688659967,
-ERASE, 47357688496128, 47357688496128,
-STORE, 47357688496128, 47357688508415,
-STORE, 47357688508416, 47357688659967,
-STORE, 47357688606720, 47357688659967,
-STORE, 47357688508416, 47357688606719,
-ERASE, 47357688508416, 47357688508416,
-STORE, 47357688508416, 47357688606719,
-STORE, 47357688651776, 47357688659967,
-STORE, 47357688606720, 47357688651775,
-ERASE, 47357688606720, 47357688606720,
-STORE, 47357688606720, 47357688659967,
-ERASE, 47357688606720, 47357688606720,
-STORE, 47357688606720, 47357688651775,
-STORE, 47357688651776, 47357688659967,
-ERASE, 47357688651776, 47357688651776,
-STORE, 47357688651776, 47357688659967,
-STORE, 47357688659968, 47357691711487,
-STORE, 47357689204736, 47357691711487,
-STORE, 47357688659968, 47357689204735,
-ERASE, 47357689204736, 47357689204736,
-STORE, 47357689204736, 47357691490303,
-STORE, 47357691490304, 47357691711487,
-STORE, 47357690900480, 47357691490303,
-STORE, 47357689204736, 47357690900479,
-ERASE, 47357689204736, 47357689204736,
-STORE, 47357689204736, 47357690900479,
-STORE, 47357691486208, 47357691490303,
-STORE, 47357690900480, 47357691486207,
-ERASE, 47357690900480, 47357690900480,
-STORE, 47357690900480, 47357691486207,
-STORE, 47357691695104, 47357691711487,
-STORE, 47357691490304, 47357691695103,
-ERASE, 47357691490304, 47357691490304,
-STORE, 47357691490304, 47357691695103,
-ERASE, 47357691695104, 47357691695104,
-STORE, 47357691695104, 47357691711487,
-STORE, 47357691711488, 47357693550591,
-STORE, 47357691850752, 47357693550591,
-STORE, 47357691711488, 47357691850751,
-ERASE, 47357691850752, 47357691850752,
-STORE, 47357691850752, 47357693509631,
-STORE, 47357693509632, 47357693550591,
-STORE, 47357693194240, 47357693509631,
-STORE, 47357691850752, 47357693194239,
-ERASE, 47357691850752, 47357691850752,
-STORE, 47357691850752, 47357693194239,
-STORE, 47357693505536, 47357693509631,
-STORE, 47357693194240, 47357693505535,
-ERASE, 47357693194240, 47357693194240,
-STORE, 47357693194240, 47357693505535,
-STORE, 47357693534208, 47357693550591,
-STORE, 47357693509632, 47357693534207,
-ERASE, 47357693509632, 47357693509632,
-STORE, 47357693509632, 47357693534207,
-ERASE, 47357693534208, 47357693534208,
-STORE, 47357693534208, 47357693550591,
-STORE, 47357693550592, 47357693685759,
-ERASE, 47357693550592, 47357693550592,
-STORE, 47357693550592, 47357693575167,
-STORE, 47357693575168, 47357693685759,
-STORE, 47357693636608, 47357693685759,
-STORE, 47357693575168, 47357693636607,
-ERASE, 47357693575168, 47357693575168,
-STORE, 47357693575168, 47357693636607,
-STORE, 47357693661184, 47357693685759,
-STORE, 47357693636608, 47357693661183,
-ERASE, 47357693636608, 47357693636608,
-STORE, 47357693636608, 47357693685759,
-ERASE, 47357693636608, 47357693636608,
-STORE, 47357693636608, 47357693661183,
-STORE, 47357693661184, 47357693685759,
-STORE, 47357693669376, 47357693685759,
-STORE, 47357693661184, 47357693669375,
-ERASE, 47357693661184, 47357693661184,
-STORE, 47357693661184, 47357693669375,
-ERASE, 47357693669376, 47357693669376,
-STORE, 47357693669376, 47357693685759,
-STORE, 47357693685760, 47357693706239,
-ERASE, 47357693685760, 47357693685760,
-STORE, 47357693685760, 47357693689855,
-STORE, 47357693689856, 47357693706239,
-STORE, 47357693693952, 47357693706239,
-STORE, 47357693689856, 47357693693951,
-ERASE, 47357693689856, 47357693689856,
-STORE, 47357693689856, 47357693693951,
-STORE, 47357693698048, 47357693706239,
-STORE, 47357693693952, 47357693698047,
-ERASE, 47357693693952, 47357693693952,
-STORE, 47357693693952, 47357693706239,
-ERASE, 47357693693952, 47357693693952,
-STORE, 47357693693952, 47357693698047,
-STORE, 47357693698048, 47357693706239,
-ERASE, 47357693698048, 47357693698048,
-STORE, 47357693698048, 47357693706239,
-STORE, 47357693706240, 47357693714431,
-ERASE, 47357693509632, 47357693509632,
-STORE, 47357693509632, 47357693526015,
-STORE, 47357693526016, 47357693534207,
-ERASE, 47357693698048, 47357693698048,
-STORE, 47357693698048, 47357693702143,
-STORE, 47357693702144, 47357693706239,
-ERASE, 47357693661184, 47357693661184,
-STORE, 47357693661184, 47357693665279,
-STORE, 47357693665280, 47357693669375,
-ERASE, 47357691490304, 47357691490304,
-STORE, 47357691490304, 47357691686911,
-STORE, 47357691686912, 47357691695103,
-ERASE, 47357688651776, 47357688651776,
-STORE, 47357688651776, 47357688655871,
-STORE, 47357688655872, 47357688659967,
-ERASE, 94240509046784, 94240509046784,
-STORE, 94240509046784, 94240509054975,
-STORE, 94240509054976, 94240509059071,
-ERASE, 140275106676736, 140275106676736,
-STORE, 140275106676736, 140275106680831,
-STORE, 140275106680832, 140275106684927,
-ERASE, 47357688479744, 47357688479744,
-STORE, 94240518361088, 94240518496255,
-STORE, 140737488347136, 140737488351231,
-STORE, 140732688277504, 140737488351231,
-ERASE, 140732688277504, 140732688277504,
-STORE, 140732688277504, 140732688281599,
-STORE, 94629171351552, 94629172064255,
-ERASE, 94629171351552, 94629171351552,
-STORE, 94629171351552, 94629171400703,
-STORE, 94629171400704, 94629172064255,
-ERASE, 94629171400704, 94629171400704,
-STORE, 94629171400704, 94629171945471,
-STORE, 94629171945472, 94629172043775,
-STORE, 94629172043776, 94629172064255,
-STORE, 139770707644416, 139770707816447,
-ERASE, 139770707644416, 139770707644416,
-STORE, 139770707644416, 139770707648511,
-STORE, 139770707648512, 139770707816447,
-ERASE, 139770707648512, 139770707648512,
-STORE, 139770707648512, 139770707771391,
-STORE, 139770707771392, 139770707804159,
-STORE, 139770707804160, 139770707812351,
-STORE, 139770707812352, 139770707816447,
-STORE, 140732689121280, 140732689125375,
-STORE, 140732689108992, 140732689121279,
-STORE, 47862087352320, 47862087360511,
-STORE, 47862087360512, 47862087368703,
-STORE, 47862087368704, 47862087475199,
-STORE, 47862087385088, 47862087475199,
-STORE, 47862087368704, 47862087385087,
-ERASE, 47862087385088, 47862087385088,
-STORE, 47862087385088, 47862087458815,
-STORE, 47862087458816, 47862087475199,
-STORE, 47862087438336, 47862087458815,
-STORE, 47862087385088, 47862087438335,
-ERASE, 47862087385088, 47862087385088,
-STORE, 47862087385088, 47862087438335,
-STORE, 47862087454720, 47862087458815,
-STORE, 47862087438336, 47862087454719,
-ERASE, 47862087438336, 47862087438336,
-STORE, 47862087438336, 47862087454719,
-STORE, 47862087467008, 47862087475199,
-STORE, 47862087458816, 47862087467007,
-ERASE, 47862087458816, 47862087458816,
-STORE, 47862087458816, 47862087467007,
-ERASE, 47862087467008, 47862087467008,
-STORE, 47862087467008, 47862087475199,
-STORE, 47862087475200, 47862089314303,
-STORE, 47862087614464, 47862089314303,
-STORE, 47862087475200, 47862087614463,
-ERASE, 47862087614464, 47862087614464,
-STORE, 47862087614464, 47862089273343,
-STORE, 47862089273344, 47862089314303,
-STORE, 47862088957952, 47862089273343,
-STORE, 47862087614464, 47862088957951,
-ERASE, 47862087614464, 47862087614464,
-STORE, 47862087614464, 47862088957951,
-STORE, 47862089269248, 47862089273343,
-STORE, 47862088957952, 47862089269247,
-ERASE, 47862088957952, 47862088957952,
-STORE, 47862088957952, 47862089269247,
-STORE, 47862089297920, 47862089314303,
-STORE, 47862089273344, 47862089297919,
-ERASE, 47862089273344, 47862089273344,
-STORE, 47862089273344, 47862089297919,
-ERASE, 47862089297920, 47862089297920,
-STORE, 47862089297920, 47862089314303,
-STORE, 47862089297920, 47862089326591,
-ERASE, 47862089273344, 47862089273344,
-STORE, 47862089273344, 47862089289727,
-STORE, 47862089289728, 47862089297919,
-ERASE, 47862087458816, 47862087458816,
-STORE, 47862087458816, 47862087462911,
-STORE, 47862087462912, 47862087467007,
-ERASE, 94629172043776, 94629172043776,
-STORE, 94629172043776, 94629172060159,
-STORE, 94629172060160, 94629172064255,
-ERASE, 139770707804160, 139770707804160,
-STORE, 139770707804160, 139770707808255,
-STORE, 139770707808256, 139770707812351,
-ERASE, 47862087352320, 47862087352320,
-STORE, 94629197533184, 94629197668351,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727540711424, 140737488351231,
-ERASE, 140727540711424, 140727540711424,
-STORE, 140727540711424, 140727540715519,
-STORE, 94299865313280, 94299866025983,
-ERASE, 94299865313280, 94299865313280,
-STORE, 94299865313280, 94299865362431,
-STORE, 94299865362432, 94299866025983,
-ERASE, 94299865362432, 94299865362432,
-STORE, 94299865362432, 94299865907199,
-STORE, 94299865907200, 94299866005503,
-STORE, 94299866005504, 94299866025983,
-STORE, 140680268763136, 140680268935167,
-ERASE, 140680268763136, 140680268763136,
-STORE, 140680268763136, 140680268767231,
-STORE, 140680268767232, 140680268935167,
-ERASE, 140680268767232, 140680268767232,
-STORE, 140680268767232, 140680268890111,
-STORE, 140680268890112, 140680268922879,
-STORE, 140680268922880, 140680268931071,
-STORE, 140680268931072, 140680268935167,
-STORE, 140727541424128, 140727541428223,
-STORE, 140727541411840, 140727541424127,
-STORE, 46952526233600, 46952526241791,
-STORE, 46952526241792, 46952526249983,
-STORE, 46952526249984, 46952526356479,
-STORE, 46952526266368, 46952526356479,
-STORE, 46952526249984, 46952526266367,
-ERASE, 46952526266368, 46952526266368,
-STORE, 46952526266368, 46952526340095,
-STORE, 46952526340096, 46952526356479,
-STORE, 46952526319616, 46952526340095,
-STORE, 46952526266368, 46952526319615,
-ERASE, 46952526266368, 46952526266368,
-STORE, 46952526266368, 46952526319615,
-STORE, 46952526336000, 46952526340095,
-STORE, 46952526319616, 46952526335999,
-ERASE, 46952526319616, 46952526319616,
-STORE, 46952526319616, 46952526335999,
-STORE, 46952526348288, 46952526356479,
-STORE, 46952526340096, 46952526348287,
-ERASE, 46952526340096, 46952526340096,
-STORE, 46952526340096, 46952526348287,
-ERASE, 46952526348288, 46952526348288,
-STORE, 46952526348288, 46952526356479,
-STORE, 46952526356480, 46952528195583,
-STORE, 46952526495744, 46952528195583,
-STORE, 46952526356480, 46952526495743,
-ERASE, 46952526495744, 46952526495744,
-STORE, 46952526495744, 46952528154623,
-STORE, 46952528154624, 46952528195583,
-STORE, 46952527839232, 46952528154623,
-STORE, 46952526495744, 46952527839231,
-ERASE, 46952526495744, 46952526495744,
-STORE, 46952526495744, 46952527839231,
-STORE, 46952528150528, 46952528154623,
-STORE, 46952527839232, 46952528150527,
-ERASE, 46952527839232, 46952527839232,
-STORE, 46952527839232, 46952528150527,
-STORE, 46952528179200, 46952528195583,
-STORE, 46952528154624, 46952528179199,
-ERASE, 46952528154624, 46952528154624,
-STORE, 46952528154624, 46952528179199,
-ERASE, 46952528179200, 46952528179200,
-STORE, 46952528179200, 46952528195583,
-STORE, 46952528179200, 46952528207871,
-ERASE, 46952528154624, 46952528154624,
-STORE, 46952528154624, 46952528171007,
-STORE, 46952528171008, 46952528179199,
-ERASE, 46952526340096, 46952526340096,
-STORE, 46952526340096, 46952526344191,
-STORE, 46952526344192, 46952526348287,
-ERASE, 94299866005504, 94299866005504,
-STORE, 94299866005504, 94299866021887,
-STORE, 94299866021888, 94299866025983,
-ERASE, 140680268922880, 140680268922880,
-STORE, 140680268922880, 140680268926975,
-STORE, 140680268926976, 140680268931071,
-ERASE, 46952526233600, 46952526233600,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722874793984, 140737488351231,
-ERASE, 140722874793984, 140722874793984,
-STORE, 140722874793984, 140722874798079,
-STORE, 94448916213760, 94448916926463,
-ERASE, 94448916213760, 94448916213760,
-STORE, 94448916213760, 94448916262911,
-STORE, 94448916262912, 94448916926463,
-ERASE, 94448916262912, 94448916262912,
-STORE, 94448916262912, 94448916807679,
-STORE, 94448916807680, 94448916905983,
-STORE, 94448916905984, 94448916926463,
-STORE, 140389117046784, 140389117218815,
-ERASE, 140389117046784, 140389117046784,
-STORE, 140389117046784, 140389117050879,
-STORE, 140389117050880, 140389117218815,
-ERASE, 140389117050880, 140389117050880,
-STORE, 140389117050880, 140389117173759,
-STORE, 140389117173760, 140389117206527,
-STORE, 140389117206528, 140389117214719,
-STORE, 140389117214720, 140389117218815,
-STORE, 140722875297792, 140722875301887,
-STORE, 140722875285504, 140722875297791,
-STORE, 47243677949952, 47243677958143,
-STORE, 47243677958144, 47243677966335,
-STORE, 47243677966336, 47243678072831,
-STORE, 47243677982720, 47243678072831,
-STORE, 47243677966336, 47243677982719,
-ERASE, 47243677982720, 47243677982720,
-STORE, 47243677982720, 47243678056447,
-STORE, 47243678056448, 47243678072831,
-STORE, 47243678035968, 47243678056447,
-STORE, 47243677982720, 47243678035967,
-ERASE, 47243677982720, 47243677982720,
-STORE, 47243677982720, 47243678035967,
-STORE, 47243678052352, 47243678056447,
-STORE, 47243678035968, 47243678052351,
-ERASE, 47243678035968, 47243678035968,
-STORE, 47243678035968, 47243678052351,
-STORE, 47243678064640, 47243678072831,
-STORE, 47243678056448, 47243678064639,
-ERASE, 47243678056448, 47243678056448,
-STORE, 47243678056448, 47243678064639,
-ERASE, 47243678064640, 47243678064640,
-STORE, 47243678064640, 47243678072831,
-STORE, 47243678072832, 47243679911935,
-STORE, 47243678212096, 47243679911935,
-STORE, 47243678072832, 47243678212095,
-ERASE, 47243678212096, 47243678212096,
-STORE, 47243678212096, 47243679870975,
-STORE, 47243679870976, 47243679911935,
-STORE, 47243679555584, 47243679870975,
-STORE, 47243678212096, 47243679555583,
-ERASE, 47243678212096, 47243678212096,
-STORE, 47243678212096, 47243679555583,
-STORE, 47243679866880, 47243679870975,
-STORE, 47243679555584, 47243679866879,
-ERASE, 47243679555584, 47243679555584,
-STORE, 47243679555584, 47243679866879,
-STORE, 47243679895552, 47243679911935,
-STORE, 47243679870976, 47243679895551,
-ERASE, 47243679870976, 47243679870976,
-STORE, 47243679870976, 47243679895551,
-ERASE, 47243679895552, 47243679895552,
-STORE, 47243679895552, 47243679911935,
-STORE, 47243679895552, 47243679924223,
-ERASE, 47243679870976, 47243679870976,
-STORE, 47243679870976, 47243679887359,
-STORE, 47243679887360, 47243679895551,
-ERASE, 47243678056448, 47243678056448,
-STORE, 47243678056448, 47243678060543,
-STORE, 47243678060544, 47243678064639,
-ERASE, 94448916905984, 94448916905984,
-STORE, 94448916905984, 94448916922367,
-STORE, 94448916922368, 94448916926463,
-ERASE, 140389117206528, 140389117206528,
-STORE, 140389117206528, 140389117210623,
-STORE, 140389117210624, 140389117214719,
-ERASE, 47243677949952, 47243677949952,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733068505088, 140737488351231,
-ERASE, 140733068505088, 140733068505088,
-STORE, 140733068505088, 140733068509183,
-STORE, 94207145750528, 94207146463231,
-ERASE, 94207145750528, 94207145750528,
-STORE, 94207145750528, 94207145799679,
-STORE, 94207145799680, 94207146463231,
-ERASE, 94207145799680, 94207145799680,
-STORE, 94207145799680, 94207146344447,
-STORE, 94207146344448, 94207146442751,
-STORE, 94207146442752, 94207146463231,
-STORE, 140684504911872, 140684505083903,
-ERASE, 140684504911872, 140684504911872,
-STORE, 140684504911872, 140684504915967,
-STORE, 140684504915968, 140684505083903,
-ERASE, 140684504915968, 140684504915968,
-STORE, 140684504915968, 140684505038847,
-STORE, 140684505038848, 140684505071615,
-STORE, 140684505071616, 140684505079807,
-STORE, 140684505079808, 140684505083903,
-STORE, 140733068607488, 140733068611583,
-STORE, 140733068595200, 140733068607487,
-STORE, 46948290084864, 46948290093055,
-STORE, 46948290093056, 46948290101247,
-STORE, 46948290101248, 46948290207743,
-STORE, 46948290117632, 46948290207743,
-STORE, 46948290101248, 46948290117631,
-ERASE, 46948290117632, 46948290117632,
-STORE, 46948290117632, 46948290191359,
-STORE, 46948290191360, 46948290207743,
-STORE, 46948290170880, 46948290191359,
-STORE, 46948290117632, 46948290170879,
-ERASE, 46948290117632, 46948290117632,
-STORE, 46948290117632, 46948290170879,
-STORE, 46948290187264, 46948290191359,
-STORE, 46948290170880, 46948290187263,
-ERASE, 46948290170880, 46948290170880,
-STORE, 46948290170880, 46948290187263,
-STORE, 46948290199552, 46948290207743,
-STORE, 46948290191360, 46948290199551,
-ERASE, 46948290191360, 46948290191360,
-STORE, 46948290191360, 46948290199551,
-ERASE, 46948290199552, 46948290199552,
-STORE, 46948290199552, 46948290207743,
-STORE, 46948290207744, 46948292046847,
-STORE, 46948290347008, 46948292046847,
-STORE, 46948290207744, 46948290347007,
-ERASE, 46948290347008, 46948290347008,
-STORE, 46948290347008, 46948292005887,
-STORE, 46948292005888, 46948292046847,
-STORE, 46948291690496, 46948292005887,
-STORE, 46948290347008, 46948291690495,
-ERASE, 46948290347008, 46948290347008,
-STORE, 46948290347008, 46948291690495,
-STORE, 46948292001792, 46948292005887,
-STORE, 46948291690496, 46948292001791,
-ERASE, 46948291690496, 46948291690496,
-STORE, 46948291690496, 46948292001791,
-STORE, 46948292030464, 46948292046847,
-STORE, 46948292005888, 46948292030463,
-ERASE, 46948292005888, 46948292005888,
-STORE, 46948292005888, 46948292030463,
-ERASE, 46948292030464, 46948292030464,
-STORE, 46948292030464, 46948292046847,
-STORE, 46948292030464, 46948292059135,
-ERASE, 46948292005888, 46948292005888,
-STORE, 46948292005888, 46948292022271,
-STORE, 46948292022272, 46948292030463,
-ERASE, 46948290191360, 46948290191360,
-STORE, 46948290191360, 46948290195455,
-STORE, 46948290195456, 46948290199551,
-ERASE, 94207146442752, 94207146442752,
-STORE, 94207146442752, 94207146459135,
-STORE, 94207146459136, 94207146463231,
-ERASE, 140684505071616, 140684505071616,
-STORE, 140684505071616, 140684505075711,
-STORE, 140684505075712, 140684505079807,
-ERASE, 46948290084864, 46948290084864,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726367158272, 140737488351231,
-ERASE, 140726367158272, 140726367158272,
-STORE, 140726367158272, 140726367162367,
-STORE, 94436124106752, 94436124819455,
-ERASE, 94436124106752, 94436124106752,
-STORE, 94436124106752, 94436124155903,
-STORE, 94436124155904, 94436124819455,
-ERASE, 94436124155904, 94436124155904,
-STORE, 94436124155904, 94436124700671,
-STORE, 94436124700672, 94436124798975,
-STORE, 94436124798976, 94436124819455,
-STORE, 140049025044480, 140049025216511,
-ERASE, 140049025044480, 140049025044480,
-STORE, 140049025044480, 140049025048575,
-STORE, 140049025048576, 140049025216511,
-ERASE, 140049025048576, 140049025048576,
-STORE, 140049025048576, 140049025171455,
-STORE, 140049025171456, 140049025204223,
-STORE, 140049025204224, 140049025212415,
-STORE, 140049025212416, 140049025216511,
-STORE, 140726367256576, 140726367260671,
-STORE, 140726367244288, 140726367256575,
-STORE, 47583769952256, 47583769960447,
-STORE, 47583769960448, 47583769968639,
-STORE, 47583769968640, 47583770075135,
-STORE, 47583769985024, 47583770075135,
-STORE, 47583769968640, 47583769985023,
-ERASE, 47583769985024, 47583769985024,
-STORE, 47583769985024, 47583770058751,
-STORE, 47583770058752, 47583770075135,
-STORE, 47583770038272, 47583770058751,
-STORE, 47583769985024, 47583770038271,
-ERASE, 47583769985024, 47583769985024,
-STORE, 47583769985024, 47583770038271,
-STORE, 47583770054656, 47583770058751,
-STORE, 47583770038272, 47583770054655,
-ERASE, 47583770038272, 47583770038272,
-STORE, 47583770038272, 47583770054655,
-STORE, 47583770066944, 47583770075135,
-STORE, 47583770058752, 47583770066943,
-ERASE, 47583770058752, 47583770058752,
-STORE, 47583770058752, 47583770066943,
-ERASE, 47583770066944, 47583770066944,
-STORE, 47583770066944, 47583770075135,
-STORE, 47583770075136, 47583771914239,
-STORE, 47583770214400, 47583771914239,
-STORE, 47583770075136, 47583770214399,
-ERASE, 47583770214400, 47583770214400,
-STORE, 47583770214400, 47583771873279,
-STORE, 47583771873280, 47583771914239,
-STORE, 47583771557888, 47583771873279,
-STORE, 47583770214400, 47583771557887,
-ERASE, 47583770214400, 47583770214400,
-STORE, 47583770214400, 47583771557887,
-STORE, 47583771869184, 47583771873279,
-STORE, 47583771557888, 47583771869183,
-ERASE, 47583771557888, 47583771557888,
-STORE, 47583771557888, 47583771869183,
-STORE, 47583771897856, 47583771914239,
-STORE, 47583771873280, 47583771897855,
-ERASE, 47583771873280, 47583771873280,
-STORE, 47583771873280, 47583771897855,
-ERASE, 47583771897856, 47583771897856,
-STORE, 47583771897856, 47583771914239,
-STORE, 47583771897856, 47583771926527,
-ERASE, 47583771873280, 47583771873280,
-STORE, 47583771873280, 47583771889663,
-STORE, 47583771889664, 47583771897855,
-ERASE, 47583770058752, 47583770058752,
-STORE, 47583770058752, 47583770062847,
-STORE, 47583770062848, 47583770066943,
-ERASE, 94436124798976, 94436124798976,
-STORE, 94436124798976, 94436124815359,
-STORE, 94436124815360, 94436124819455,
-ERASE, 140049025204224, 140049025204224,
-STORE, 140049025204224, 140049025208319,
-STORE, 140049025208320, 140049025212415,
-ERASE, 47583769952256, 47583769952256,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727116099584, 140737488351231,
-ERASE, 140727116099584, 140727116099584,
-STORE, 140727116099584, 140727116103679,
-STORE, 94166319734784, 94166320447487,
-ERASE, 94166319734784, 94166319734784,
-STORE, 94166319734784, 94166319783935,
-STORE, 94166319783936, 94166320447487,
-ERASE, 94166319783936, 94166319783936,
-STORE, 94166319783936, 94166320328703,
-STORE, 94166320328704, 94166320427007,
-STORE, 94166320427008, 94166320447487,
-STORE, 139976559542272, 139976559714303,
-ERASE, 139976559542272, 139976559542272,
-STORE, 139976559542272, 139976559546367,
-STORE, 139976559546368, 139976559714303,
-ERASE, 139976559546368, 139976559546368,
-STORE, 139976559546368, 139976559669247,
-STORE, 139976559669248, 139976559702015,
-STORE, 139976559702016, 139976559710207,
-STORE, 139976559710208, 139976559714303,
-STORE, 140727116222464, 140727116226559,
-STORE, 140727116210176, 140727116222463,
-STORE, 47656235454464, 47656235462655,
-STORE, 47656235462656, 47656235470847,
-STORE, 47656235470848, 47656235577343,
-STORE, 47656235487232, 47656235577343,
-STORE, 47656235470848, 47656235487231,
-ERASE, 47656235487232, 47656235487232,
-STORE, 47656235487232, 47656235560959,
-STORE, 47656235560960, 47656235577343,
-STORE, 47656235540480, 47656235560959,
-STORE, 47656235487232, 47656235540479,
-ERASE, 47656235487232, 47656235487232,
-STORE, 47656235487232, 47656235540479,
-STORE, 47656235556864, 47656235560959,
-STORE, 47656235540480, 47656235556863,
-ERASE, 47656235540480, 47656235540480,
-STORE, 47656235540480, 47656235556863,
-STORE, 47656235569152, 47656235577343,
-STORE, 47656235560960, 47656235569151,
-ERASE, 47656235560960, 47656235560960,
-STORE, 47656235560960, 47656235569151,
-ERASE, 47656235569152, 47656235569152,
-STORE, 47656235569152, 47656235577343,
-STORE, 47656235577344, 47656237416447,
-STORE, 47656235716608, 47656237416447,
-STORE, 47656235577344, 47656235716607,
-ERASE, 47656235716608, 47656235716608,
-STORE, 47656235716608, 47656237375487,
-STORE, 47656237375488, 47656237416447,
-STORE, 47656237060096, 47656237375487,
-STORE, 47656235716608, 47656237060095,
-ERASE, 47656235716608, 47656235716608,
-STORE, 47656235716608, 47656237060095,
-STORE, 47656237371392, 47656237375487,
-STORE, 47656237060096, 47656237371391,
-ERASE, 47656237060096, 47656237060096,
-STORE, 47656237060096, 47656237371391,
-STORE, 47656237400064, 47656237416447,
-STORE, 47656237375488, 47656237400063,
-ERASE, 47656237375488, 47656237375488,
-STORE, 47656237375488, 47656237400063,
-ERASE, 47656237400064, 47656237400064,
-STORE, 47656237400064, 47656237416447,
-STORE, 47656237400064, 47656237428735,
-ERASE, 47656237375488, 47656237375488,
-STORE, 47656237375488, 47656237391871,
-STORE, 47656237391872, 47656237400063,
-ERASE, 47656235560960, 47656235560960,
-STORE, 47656235560960, 47656235565055,
-STORE, 47656235565056, 47656235569151,
-ERASE, 94166320427008, 94166320427008,
-STORE, 94166320427008, 94166320443391,
-STORE, 94166320443392, 94166320447487,
-ERASE, 139976559702016, 139976559702016,
-STORE, 139976559702016, 139976559706111,
-STORE, 139976559706112, 139976559710207,
-ERASE, 47656235454464, 47656235454464,
-STORE, 94166332153856, 94166332289023,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726412816384, 140737488351231,
-ERASE, 140726412816384, 140726412816384,
-STORE, 140726412816384, 140726412820479,
-STORE, 94094884507648, 94094885220351,
-ERASE, 94094884507648, 94094884507648,
-STORE, 94094884507648, 94094884556799,
-STORE, 94094884556800, 94094885220351,
-ERASE, 94094884556800, 94094884556800,
-STORE, 94094884556800, 94094885101567,
-STORE, 94094885101568, 94094885199871,
-STORE, 94094885199872, 94094885220351,
-STORE, 139773773938688, 139773774110719,
-ERASE, 139773773938688, 139773773938688,
-STORE, 139773773938688, 139773773942783,
-STORE, 139773773942784, 139773774110719,
-ERASE, 139773773942784, 139773773942784,
-STORE, 139773773942784, 139773774065663,
-STORE, 139773774065664, 139773774098431,
-STORE, 139773774098432, 139773774106623,
-STORE, 139773774106624, 139773774110719,
-STORE, 140726412963840, 140726412967935,
-STORE, 140726412951552, 140726412963839,
-STORE, 47859021058048, 47859021066239,
-STORE, 47859021066240, 47859021074431,
-STORE, 47859021074432, 47859021180927,
-STORE, 47859021090816, 47859021180927,
-STORE, 47859021074432, 47859021090815,
-ERASE, 47859021090816, 47859021090816,
-STORE, 47859021090816, 47859021164543,
-STORE, 47859021164544, 47859021180927,
-STORE, 47859021144064, 47859021164543,
-STORE, 47859021090816, 47859021144063,
-ERASE, 47859021090816, 47859021090816,
-STORE, 47859021090816, 47859021144063,
-STORE, 47859021160448, 47859021164543,
-STORE, 47859021144064, 47859021160447,
-ERASE, 47859021144064, 47859021144064,
-STORE, 47859021144064, 47859021160447,
-STORE, 47859021172736, 47859021180927,
-STORE, 47859021164544, 47859021172735,
-ERASE, 47859021164544, 47859021164544,
-STORE, 47859021164544, 47859021172735,
-ERASE, 47859021172736, 47859021172736,
-STORE, 47859021172736, 47859021180927,
-STORE, 47859021180928, 47859023020031,
-STORE, 47859021320192, 47859023020031,
-STORE, 47859021180928, 47859021320191,
-ERASE, 47859021320192, 47859021320192,
-STORE, 47859021320192, 47859022979071,
-STORE, 47859022979072, 47859023020031,
-STORE, 47859022663680, 47859022979071,
-STORE, 47859021320192, 47859022663679,
-ERASE, 47859021320192, 47859021320192,
-STORE, 47859021320192, 47859022663679,
-STORE, 47859022974976, 47859022979071,
-STORE, 47859022663680, 47859022974975,
-ERASE, 47859022663680, 47859022663680,
-STORE, 47859022663680, 47859022974975,
-STORE, 47859023003648, 47859023020031,
-STORE, 47859022979072, 47859023003647,
-ERASE, 47859022979072, 47859022979072,
-STORE, 47859022979072, 47859023003647,
-ERASE, 47859023003648, 47859023003648,
-STORE, 47859023003648, 47859023020031,
-STORE, 47859023003648, 47859023032319,
-ERASE, 47859022979072, 47859022979072,
-STORE, 47859022979072, 47859022995455,
-STORE, 47859022995456, 47859023003647,
-ERASE, 47859021164544, 47859021164544,
-STORE, 47859021164544, 47859021168639,
-STORE, 47859021168640, 47859021172735,
-ERASE, 94094885199872, 94094885199872,
-STORE, 94094885199872, 94094885216255,
-STORE, 94094885216256, 94094885220351,
-ERASE, 139773774098432, 139773774098432,
-STORE, 139773774098432, 139773774102527,
-STORE, 139773774102528, 139773774106623,
-ERASE, 47859021058048, 47859021058048,
-STORE, 94094901108736, 94094901243903,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736567963648, 140737488351231,
-ERASE, 140736567963648, 140736567963648,
-STORE, 140736567963648, 140736567967743,
-STORE, 94924425748480, 94924426461183,
-ERASE, 94924425748480, 94924425748480,
-STORE, 94924425748480, 94924425797631,
-STORE, 94924425797632, 94924426461183,
-ERASE, 94924425797632, 94924425797632,
-STORE, 94924425797632, 94924426342399,
-STORE, 94924426342400, 94924426440703,
-STORE, 94924426440704, 94924426461183,
-STORE, 140042126319616, 140042126491647,
-ERASE, 140042126319616, 140042126319616,
-STORE, 140042126319616, 140042126323711,
-STORE, 140042126323712, 140042126491647,
-ERASE, 140042126323712, 140042126323712,
-STORE, 140042126323712, 140042126446591,
-STORE, 140042126446592, 140042126479359,
-STORE, 140042126479360, 140042126487551,
-STORE, 140042126487552, 140042126491647,
-STORE, 140736568672256, 140736568676351,
-STORE, 140736568659968, 140736568672255,
-STORE, 47590668677120, 47590668685311,
-STORE, 47590668685312, 47590668693503,
-STORE, 47590668693504, 47590668799999,
-STORE, 47590668709888, 47590668799999,
-STORE, 47590668693504, 47590668709887,
-ERASE, 47590668709888, 47590668709888,
-STORE, 47590668709888, 47590668783615,
-STORE, 47590668783616, 47590668799999,
-STORE, 47590668763136, 47590668783615,
-STORE, 47590668709888, 47590668763135,
-ERASE, 47590668709888, 47590668709888,
-STORE, 47590668709888, 47590668763135,
-STORE, 47590668779520, 47590668783615,
-STORE, 47590668763136, 47590668779519,
-ERASE, 47590668763136, 47590668763136,
-STORE, 47590668763136, 47590668779519,
-STORE, 47590668791808, 47590668799999,
-STORE, 47590668783616, 47590668791807,
-ERASE, 47590668783616, 47590668783616,
-STORE, 47590668783616, 47590668791807,
-ERASE, 47590668791808, 47590668791808,
-STORE, 47590668791808, 47590668799999,
-STORE, 47590668800000, 47590670639103,
-STORE, 47590668939264, 47590670639103,
-STORE, 47590668800000, 47590668939263,
-ERASE, 47590668939264, 47590668939264,
-STORE, 47590668939264, 47590670598143,
-STORE, 47590670598144, 47590670639103,
-STORE, 47590670282752, 47590670598143,
-STORE, 47590668939264, 47590670282751,
-ERASE, 47590668939264, 47590668939264,
-STORE, 47590668939264, 47590670282751,
-STORE, 47590670594048, 47590670598143,
-STORE, 47590670282752, 47590670594047,
-ERASE, 47590670282752, 47590670282752,
-STORE, 47590670282752, 47590670594047,
-STORE, 47590670622720, 47590670639103,
-STORE, 47590670598144, 47590670622719,
-ERASE, 47590670598144, 47590670598144,
-STORE, 47590670598144, 47590670622719,
-ERASE, 47590670622720, 47590670622720,
-STORE, 47590670622720, 47590670639103,
-STORE, 47590670622720, 47590670651391,
-ERASE, 47590670598144, 47590670598144,
-STORE, 47590670598144, 47590670614527,
-STORE, 47590670614528, 47590670622719,
-ERASE, 47590668783616, 47590668783616,
-STORE, 47590668783616, 47590668787711,
-STORE, 47590668787712, 47590668791807,
-ERASE, 94924426440704, 94924426440704,
-STORE, 94924426440704, 94924426457087,
-STORE, 94924426457088, 94924426461183,
-ERASE, 140042126479360, 140042126479360,
-STORE, 140042126479360, 140042126483455,
-STORE, 140042126483456, 140042126487551,
-ERASE, 47590668677120, 47590668677120,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733281439744, 140737488351231,
-ERASE, 140733281439744, 140733281439744,
-STORE, 140733281439744, 140733281443839,
-STORE, 94490667069440, 94490667782143,
-ERASE, 94490667069440, 94490667069440,
-STORE, 94490667069440, 94490667118591,
-STORE, 94490667118592, 94490667782143,
-ERASE, 94490667118592, 94490667118592,
-STORE, 94490667118592, 94490667663359,
-STORE, 94490667663360, 94490667761663,
-STORE, 94490667761664, 94490667782143,
-STORE, 139878215118848, 139878215290879,
-ERASE, 139878215118848, 139878215118848,
-STORE, 139878215118848, 139878215122943,
-STORE, 139878215122944, 139878215290879,
-ERASE, 139878215122944, 139878215122944,
-STORE, 139878215122944, 139878215245823,
-STORE, 139878215245824, 139878215278591,
-STORE, 139878215278592, 139878215286783,
-STORE, 139878215286784, 139878215290879,
-STORE, 140733281464320, 140733281468415,
-STORE, 140733281452032, 140733281464319,
-STORE, 47754579877888, 47754579886079,
-STORE, 47754579886080, 47754579894271,
-STORE, 47754579894272, 47754580000767,
-STORE, 47754579910656, 47754580000767,
-STORE, 47754579894272, 47754579910655,
-ERASE, 47754579910656, 47754579910656,
-STORE, 47754579910656, 47754579984383,
-STORE, 47754579984384, 47754580000767,
-STORE, 47754579963904, 47754579984383,
-STORE, 47754579910656, 47754579963903,
-ERASE, 47754579910656, 47754579910656,
-STORE, 47754579910656, 47754579963903,
-STORE, 47754579980288, 47754579984383,
-STORE, 47754579963904, 47754579980287,
-ERASE, 47754579963904, 47754579963904,
-STORE, 47754579963904, 47754579980287,
-STORE, 47754579992576, 47754580000767,
-STORE, 47754579984384, 47754579992575,
-ERASE, 47754579984384, 47754579984384,
-STORE, 47754579984384, 47754579992575,
-ERASE, 47754579992576, 47754579992576,
-STORE, 47754579992576, 47754580000767,
-STORE, 47754580000768, 47754581839871,
-STORE, 47754580140032, 47754581839871,
-STORE, 47754580000768, 47754580140031,
-ERASE, 47754580140032, 47754580140032,
-STORE, 47754580140032, 47754581798911,
-STORE, 47754581798912, 47754581839871,
-STORE, 47754581483520, 47754581798911,
-STORE, 47754580140032, 47754581483519,
-ERASE, 47754580140032, 47754580140032,
-STORE, 47754580140032, 47754581483519,
-STORE, 47754581794816, 47754581798911,
-STORE, 47754581483520, 47754581794815,
-ERASE, 47754581483520, 47754581483520,
-STORE, 47754581483520, 47754581794815,
-STORE, 47754581823488, 47754581839871,
-STORE, 47754581798912, 47754581823487,
-ERASE, 47754581798912, 47754581798912,
-STORE, 47754581798912, 47754581823487,
-ERASE, 47754581823488, 47754581823488,
-STORE, 47754581823488, 47754581839871,
-STORE, 47754581823488, 47754581852159,
-ERASE, 47754581798912, 47754581798912,
-STORE, 47754581798912, 47754581815295,
-STORE, 47754581815296, 47754581823487,
-ERASE, 47754579984384, 47754579984384,
-STORE, 47754579984384, 47754579988479,
-STORE, 47754579988480, 47754579992575,
-ERASE, 94490667761664, 94490667761664,
-STORE, 94490667761664, 94490667778047,
-STORE, 94490667778048, 94490667782143,
-ERASE, 139878215278592, 139878215278592,
-STORE, 139878215278592, 139878215282687,
-STORE, 139878215282688, 139878215286783,
-ERASE, 47754579877888, 47754579877888,
-STORE, 94490669649920, 94490669785087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140735382188032, 140737488351231,
-ERASE, 140735382188032, 140735382188032,
-STORE, 140735382188032, 140735382192127,
-STORE, 94150181302272, 94150182014975,
-ERASE, 94150181302272, 94150181302272,
-STORE, 94150181302272, 94150181351423,
-STORE, 94150181351424, 94150182014975,
-ERASE, 94150181351424, 94150181351424,
-STORE, 94150181351424, 94150181896191,
-STORE, 94150181896192, 94150181994495,
-STORE, 94150181994496, 94150182014975,
-STORE, 139679752458240, 139679752630271,
-ERASE, 139679752458240, 139679752458240,
-STORE, 139679752458240, 139679752462335,
-STORE, 139679752462336, 139679752630271,
-ERASE, 139679752462336, 139679752462336,
-STORE, 139679752462336, 139679752585215,
-STORE, 139679752585216, 139679752617983,
-STORE, 139679752617984, 139679752626175,
-STORE, 139679752626176, 139679752630271,
-STORE, 140735382536192, 140735382540287,
-STORE, 140735382523904, 140735382536191,
-STORE, 47953042538496, 47953042546687,
-STORE, 47953042546688, 47953042554879,
-STORE, 47953042554880, 47953042661375,
-STORE, 47953042571264, 47953042661375,
-STORE, 47953042554880, 47953042571263,
-ERASE, 47953042571264, 47953042571264,
-STORE, 47953042571264, 47953042644991,
-STORE, 47953042644992, 47953042661375,
-STORE, 47953042624512, 47953042644991,
-STORE, 47953042571264, 47953042624511,
-ERASE, 47953042571264, 47953042571264,
-STORE, 47953042571264, 47953042624511,
-STORE, 47953042640896, 47953042644991,
-STORE, 47953042624512, 47953042640895,
-ERASE, 47953042624512, 47953042624512,
-STORE, 47953042624512, 47953042640895,
-STORE, 47953042653184, 47953042661375,
-STORE, 47953042644992, 47953042653183,
-ERASE, 47953042644992, 47953042644992,
-STORE, 47953042644992, 47953042653183,
-ERASE, 47953042653184, 47953042653184,
-STORE, 47953042653184, 47953042661375,
-STORE, 47953042661376, 47953044500479,
-STORE, 47953042800640, 47953044500479,
-STORE, 47953042661376, 47953042800639,
-ERASE, 47953042800640, 47953042800640,
-STORE, 47953042800640, 47953044459519,
-STORE, 47953044459520, 47953044500479,
-STORE, 47953044144128, 47953044459519,
-STORE, 47953042800640, 47953044144127,
-ERASE, 47953042800640, 47953042800640,
-STORE, 47953042800640, 47953044144127,
-STORE, 47953044455424, 47953044459519,
-STORE, 47953044144128, 47953044455423,
-ERASE, 47953044144128, 47953044144128,
-STORE, 47953044144128, 47953044455423,
-STORE, 47953044484096, 47953044500479,
-STORE, 47953044459520, 47953044484095,
-ERASE, 47953044459520, 47953044459520,
-STORE, 47953044459520, 47953044484095,
-ERASE, 47953044484096, 47953044484096,
-STORE, 47953044484096, 47953044500479,
-STORE, 47953044484096, 47953044512767,
-ERASE, 47953044459520, 47953044459520,
-STORE, 47953044459520, 47953044475903,
-STORE, 47953044475904, 47953044484095,
-ERASE, 47953042644992, 47953042644992,
-STORE, 47953042644992, 47953042649087,
-STORE, 47953042649088, 47953042653183,
-ERASE, 94150181994496, 94150181994496,
-STORE, 94150181994496, 94150182010879,
-STORE, 94150182010880, 94150182014975,
-ERASE, 139679752617984, 139679752617984,
-STORE, 139679752617984, 139679752622079,
-STORE, 139679752622080, 139679752626175,
-ERASE, 47953042538496, 47953042538496,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737044123648, 140737488351231,
-ERASE, 140737044123648, 140737044123648,
-STORE, 140737044123648, 140737044127743,
-STORE, 94425324294144, 94425325006847,
-ERASE, 94425324294144, 94425324294144,
-STORE, 94425324294144, 94425324343295,
-STORE, 94425324343296, 94425325006847,
-ERASE, 94425324343296, 94425324343296,
-STORE, 94425324343296, 94425324888063,
-STORE, 94425324888064, 94425324986367,
-STORE, 94425324986368, 94425325006847,
-STORE, 140382015016960, 140382015188991,
-ERASE, 140382015016960, 140382015016960,
-STORE, 140382015016960, 140382015021055,
-STORE, 140382015021056, 140382015188991,
-ERASE, 140382015021056, 140382015021056,
-STORE, 140382015021056, 140382015143935,
-STORE, 140382015143936, 140382015176703,
-STORE, 140382015176704, 140382015184895,
-STORE, 140382015184896, 140382015188991,
-STORE, 140737045585920, 140737045590015,
-STORE, 140737045573632, 140737045585919,
-STORE, 47250779979776, 47250779987967,
-STORE, 47250779987968, 47250779996159,
-STORE, 47250779996160, 47250780102655,
-STORE, 47250780012544, 47250780102655,
-STORE, 47250779996160, 47250780012543,
-ERASE, 47250780012544, 47250780012544,
-STORE, 47250780012544, 47250780086271,
-STORE, 47250780086272, 47250780102655,
-STORE, 47250780065792, 47250780086271,
-STORE, 47250780012544, 47250780065791,
-ERASE, 47250780012544, 47250780012544,
-STORE, 47250780012544, 47250780065791,
-STORE, 47250780082176, 47250780086271,
-STORE, 47250780065792, 47250780082175,
-ERASE, 47250780065792, 47250780065792,
-STORE, 47250780065792, 47250780082175,
-STORE, 47250780094464, 47250780102655,
-STORE, 47250780086272, 47250780094463,
-ERASE, 47250780086272, 47250780086272,
-STORE, 47250780086272, 47250780094463,
-ERASE, 47250780094464, 47250780094464,
-STORE, 47250780094464, 47250780102655,
-STORE, 47250780102656, 47250781941759,
-STORE, 47250780241920, 47250781941759,
-STORE, 47250780102656, 47250780241919,
-ERASE, 47250780241920, 47250780241920,
-STORE, 47250780241920, 47250781900799,
-STORE, 47250781900800, 47250781941759,
-STORE, 47250781585408, 47250781900799,
-STORE, 47250780241920, 47250781585407,
-ERASE, 47250780241920, 47250780241920,
-STORE, 47250780241920, 47250781585407,
-STORE, 47250781896704, 47250781900799,
-STORE, 47250781585408, 47250781896703,
-ERASE, 47250781585408, 47250781585408,
-STORE, 47250781585408, 47250781896703,
-STORE, 47250781925376, 47250781941759,
-STORE, 47250781900800, 47250781925375,
-ERASE, 47250781900800, 47250781900800,
-STORE, 47250781900800, 47250781925375,
-ERASE, 47250781925376, 47250781925376,
-STORE, 47250781925376, 47250781941759,
-STORE, 47250781925376, 47250781954047,
-ERASE, 47250781900800, 47250781900800,
-STORE, 47250781900800, 47250781917183,
-STORE, 47250781917184, 47250781925375,
-ERASE, 47250780086272, 47250780086272,
-STORE, 47250780086272, 47250780090367,
-STORE, 47250780090368, 47250780094463,
-ERASE, 94425324986368, 94425324986368,
-STORE, 94425324986368, 94425325002751,
-STORE, 94425325002752, 94425325006847,
-ERASE, 140382015176704, 140382015176704,
-STORE, 140382015176704, 140382015180799,
-STORE, 140382015180800, 140382015184895,
-ERASE, 47250779979776, 47250779979776,
-STORE, 94425351438336, 94425351573503,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736801144832, 140737488351231,
-ERASE, 140736801144832, 140736801144832,
-STORE, 140736801144832, 140736801148927,
-STORE, 94629429358592, 94629430071295,
-ERASE, 94629429358592, 94629429358592,
-STORE, 94629429358592, 94629429407743,
-STORE, 94629429407744, 94629430071295,
-ERASE, 94629429407744, 94629429407744,
-STORE, 94629429407744, 94629429952511,
-STORE, 94629429952512, 94629430050815,
-STORE, 94629430050816, 94629430071295,
-STORE, 139801685483520, 139801685655551,
-ERASE, 139801685483520, 139801685483520,
-STORE, 139801685483520, 139801685487615,
-STORE, 139801685487616, 139801685655551,
-ERASE, 139801685487616, 139801685487616,
-STORE, 139801685487616, 139801685610495,
-STORE, 139801685610496, 139801685643263,
-STORE, 139801685643264, 139801685651455,
-STORE, 139801685651456, 139801685655551,
-STORE, 140736801198080, 140736801202175,
-STORE, 140736801185792, 140736801198079,
-STORE, 47831109513216, 47831109521407,
-STORE, 47831109521408, 47831109529599,
-STORE, 47831109529600, 47831109636095,
-STORE, 47831109545984, 47831109636095,
-STORE, 47831109529600, 47831109545983,
-ERASE, 47831109545984, 47831109545984,
-STORE, 47831109545984, 47831109619711,
-STORE, 47831109619712, 47831109636095,
-STORE, 47831109599232, 47831109619711,
-STORE, 47831109545984, 47831109599231,
-ERASE, 47831109545984, 47831109545984,
-STORE, 47831109545984, 47831109599231,
-STORE, 47831109615616, 47831109619711,
-STORE, 47831109599232, 47831109615615,
-ERASE, 47831109599232, 47831109599232,
-STORE, 47831109599232, 47831109615615,
-STORE, 47831109627904, 47831109636095,
-STORE, 47831109619712, 47831109627903,
-ERASE, 47831109619712, 47831109619712,
-STORE, 47831109619712, 47831109627903,
-ERASE, 47831109627904, 47831109627904,
-STORE, 47831109627904, 47831109636095,
-STORE, 47831109636096, 47831111475199,
-STORE, 47831109775360, 47831111475199,
-STORE, 47831109636096, 47831109775359,
-ERASE, 47831109775360, 47831109775360,
-STORE, 47831109775360, 47831111434239,
-STORE, 47831111434240, 47831111475199,
-STORE, 47831111118848, 47831111434239,
-STORE, 47831109775360, 47831111118847,
-ERASE, 47831109775360, 47831109775360,
-STORE, 47831109775360, 47831111118847,
-STORE, 47831111430144, 47831111434239,
-STORE, 47831111118848, 47831111430143,
-ERASE, 47831111118848, 47831111118848,
-STORE, 47831111118848, 47831111430143,
-STORE, 47831111458816, 47831111475199,
-STORE, 47831111434240, 47831111458815,
-ERASE, 47831111434240, 47831111434240,
-STORE, 47831111434240, 47831111458815,
-ERASE, 47831111458816, 47831111458816,
-STORE, 47831111458816, 47831111475199,
-STORE, 47831111458816, 47831111487487,
-ERASE, 47831111434240, 47831111434240,
-STORE, 47831111434240, 47831111450623,
-STORE, 47831111450624, 47831111458815,
-ERASE, 47831109619712, 47831109619712,
-STORE, 47831109619712, 47831109623807,
-STORE, 47831109623808, 47831109627903,
-ERASE, 94629430050816, 94629430050816,
-STORE, 94629430050816, 94629430067199,
-STORE, 94629430067200, 94629430071295,
-ERASE, 139801685643264, 139801685643264,
-STORE, 139801685643264, 139801685647359,
-STORE, 139801685647360, 139801685651455,
-ERASE, 47831109513216, 47831109513216,
-STORE, 140737488347136, 140737488351231,
-STORE, 140729419612160, 140737488351231,
-ERASE, 140729419612160, 140729419612160,
-STORE, 140729419612160, 140729419616255,
-STORE, 94443354148864, 94443354861567,
-ERASE, 94443354148864, 94443354148864,
-STORE, 94443354148864, 94443354198015,
-STORE, 94443354198016, 94443354861567,
-ERASE, 94443354198016, 94443354198016,
-STORE, 94443354198016, 94443354742783,
-STORE, 94443354742784, 94443354841087,
-STORE, 94443354841088, 94443354861567,
-STORE, 139741700038656, 139741700210687,
-ERASE, 139741700038656, 139741700038656,
-STORE, 139741700038656, 139741700042751,
-STORE, 139741700042752, 139741700210687,
-ERASE, 139741700042752, 139741700042752,
-STORE, 139741700042752, 139741700165631,
-STORE, 139741700165632, 139741700198399,
-STORE, 139741700198400, 139741700206591,
-STORE, 139741700206592, 139741700210687,
-STORE, 140729420574720, 140729420578815,
-STORE, 140729420562432, 140729420574719,
-STORE, 47891094958080, 47891094966271,
-STORE, 47891094966272, 47891094974463,
-STORE, 47891094974464, 47891095080959,
-STORE, 47891094990848, 47891095080959,
-STORE, 47891094974464, 47891094990847,
-ERASE, 47891094990848, 47891094990848,
-STORE, 47891094990848, 47891095064575,
-STORE, 47891095064576, 47891095080959,
-STORE, 47891095044096, 47891095064575,
-STORE, 47891094990848, 47891095044095,
-ERASE, 47891094990848, 47891094990848,
-STORE, 47891094990848, 47891095044095,
-STORE, 47891095060480, 47891095064575,
-STORE, 47891095044096, 47891095060479,
-ERASE, 47891095044096, 47891095044096,
-STORE, 47891095044096, 47891095060479,
-STORE, 47891095072768, 47891095080959,
-STORE, 47891095064576, 47891095072767,
-ERASE, 47891095064576, 47891095064576,
-STORE, 47891095064576, 47891095072767,
-ERASE, 47891095072768, 47891095072768,
-STORE, 47891095072768, 47891095080959,
-STORE, 47891095080960, 47891096920063,
-STORE, 47891095220224, 47891096920063,
-STORE, 47891095080960, 47891095220223,
-ERASE, 47891095220224, 47891095220224,
-STORE, 47891095220224, 47891096879103,
-STORE, 47891096879104, 47891096920063,
-STORE, 47891096563712, 47891096879103,
-STORE, 47891095220224, 47891096563711,
-ERASE, 47891095220224, 47891095220224,
-STORE, 47891095220224, 47891096563711,
-STORE, 47891096875008, 47891096879103,
-STORE, 47891096563712, 47891096875007,
-ERASE, 47891096563712, 47891096563712,
-STORE, 47891096563712, 47891096875007,
-STORE, 47891096903680, 47891096920063,
-STORE, 47891096879104, 47891096903679,
-ERASE, 47891096879104, 47891096879104,
-STORE, 47891096879104, 47891096903679,
-ERASE, 47891096903680, 47891096903680,
-STORE, 47891096903680, 47891096920063,
-STORE, 47891096903680, 47891096932351,
-ERASE, 47891096879104, 47891096879104,
-STORE, 47891096879104, 47891096895487,
-STORE, 47891096895488, 47891096903679,
-ERASE, 47891095064576, 47891095064576,
-STORE, 47891095064576, 47891095068671,
-STORE, 47891095068672, 47891095072767,
-ERASE, 94443354841088, 94443354841088,
-STORE, 94443354841088, 94443354857471,
-STORE, 94443354857472, 94443354861567,
-ERASE, 139741700198400, 139741700198400,
-STORE, 139741700198400, 139741700202495,
-STORE, 139741700202496, 139741700206591,
-ERASE, 47891094958080, 47891094958080,
-STORE, 94443360825344, 94443360960511,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722961661952, 140737488351231,
-ERASE, 140722961661952, 140722961661952,
-STORE, 140722961661952, 140722961666047,
-STORE, 94878388944896, 94878389657599,
-ERASE, 94878388944896, 94878388944896,
-STORE, 94878388944896, 94878388994047,
-STORE, 94878388994048, 94878389657599,
-ERASE, 94878388994048, 94878388994048,
-STORE, 94878388994048, 94878389538815,
-STORE, 94878389538816, 94878389637119,
-STORE, 94878389637120, 94878389657599,
-STORE, 140210690056192, 140210690228223,
-ERASE, 140210690056192, 140210690056192,
-STORE, 140210690056192, 140210690060287,
-STORE, 140210690060288, 140210690228223,
-ERASE, 140210690060288, 140210690060288,
-STORE, 140210690060288, 140210690183167,
-STORE, 140210690183168, 140210690215935,
-STORE, 140210690215936, 140210690224127,
-STORE, 140210690224128, 140210690228223,
-STORE, 140722963148800, 140722963152895,
-STORE, 140722963136512, 140722963148799,
-STORE, 47422104940544, 47422104948735,
-STORE, 47422104948736, 47422104956927,
-STORE, 47422104956928, 47422105063423,
-STORE, 47422104973312, 47422105063423,
-STORE, 47422104956928, 47422104973311,
-ERASE, 47422104973312, 47422104973312,
-STORE, 47422104973312, 47422105047039,
-STORE, 47422105047040, 47422105063423,
-STORE, 47422105026560, 47422105047039,
-STORE, 47422104973312, 47422105026559,
-ERASE, 47422104973312, 47422104973312,
-STORE, 47422104973312, 47422105026559,
-STORE, 47422105042944, 47422105047039,
-STORE, 47422105026560, 47422105042943,
-ERASE, 47422105026560, 47422105026560,
-STORE, 47422105026560, 47422105042943,
-STORE, 47422105055232, 47422105063423,
-STORE, 47422105047040, 47422105055231,
-ERASE, 47422105047040, 47422105047040,
-STORE, 47422105047040, 47422105055231,
-ERASE, 47422105055232, 47422105055232,
-STORE, 47422105055232, 47422105063423,
-STORE, 47422105063424, 47422106902527,
-STORE, 47422105202688, 47422106902527,
-STORE, 47422105063424, 47422105202687,
-ERASE, 47422105202688, 47422105202688,
-STORE, 47422105202688, 47422106861567,
-STORE, 47422106861568, 47422106902527,
-STORE, 47422106546176, 47422106861567,
-STORE, 47422105202688, 47422106546175,
-ERASE, 47422105202688, 47422105202688,
-STORE, 47422105202688, 47422106546175,
-STORE, 47422106857472, 47422106861567,
-STORE, 47422106546176, 47422106857471,
-ERASE, 47422106546176, 47422106546176,
-STORE, 47422106546176, 47422106857471,
-STORE, 47422106886144, 47422106902527,
-STORE, 47422106861568, 47422106886143,
-ERASE, 47422106861568, 47422106861568,
-STORE, 47422106861568, 47422106886143,
-ERASE, 47422106886144, 47422106886144,
-STORE, 47422106886144, 47422106902527,
-STORE, 47422106886144, 47422106914815,
-ERASE, 47422106861568, 47422106861568,
-STORE, 47422106861568, 47422106877951,
-STORE, 47422106877952, 47422106886143,
-ERASE, 47422105047040, 47422105047040,
-STORE, 47422105047040, 47422105051135,
-STORE, 47422105051136, 47422105055231,
-ERASE, 94878389637120, 94878389637120,
-STORE, 94878389637120, 94878389653503,
-STORE, 94878389653504, 94878389657599,
-ERASE, 140210690215936, 140210690215936,
-STORE, 140210690215936, 140210690220031,
-STORE, 140210690220032, 140210690224127,
-ERASE, 47422104940544, 47422104940544,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727690309632, 140737488351231,
-ERASE, 140727690309632, 140727690309632,
-STORE, 140727690309632, 140727690313727,
-STORE, 94121892208640, 94121892921343,
-ERASE, 94121892208640, 94121892208640,
-STORE, 94121892208640, 94121892257791,
-STORE, 94121892257792, 94121892921343,
-ERASE, 94121892257792, 94121892257792,
-STORE, 94121892257792, 94121892802559,
-STORE, 94121892802560, 94121892900863,
-STORE, 94121892900864, 94121892921343,
-STORE, 140662438326272, 140662438498303,
-ERASE, 140662438326272, 140662438326272,
-STORE, 140662438326272, 140662438330367,
-STORE, 140662438330368, 140662438498303,
-ERASE, 140662438330368, 140662438330368,
-STORE, 140662438330368, 140662438453247,
-STORE, 140662438453248, 140662438486015,
-STORE, 140662438486016, 140662438494207,
-STORE, 140662438494208, 140662438498303,
-STORE, 140727690379264, 140727690383359,
-STORE, 140727690366976, 140727690379263,
-STORE, 46970356670464, 46970356678655,
-STORE, 46970356678656, 46970356686847,
-STORE, 46970356686848, 46970356793343,
-STORE, 46970356703232, 46970356793343,
-STORE, 46970356686848, 46970356703231,
-ERASE, 46970356703232, 46970356703232,
-STORE, 46970356703232, 46970356776959,
-STORE, 46970356776960, 46970356793343,
-STORE, 46970356756480, 46970356776959,
-STORE, 46970356703232, 46970356756479,
-ERASE, 46970356703232, 46970356703232,
-STORE, 46970356703232, 46970356756479,
-STORE, 46970356772864, 46970356776959,
-STORE, 46970356756480, 46970356772863,
-ERASE, 46970356756480, 46970356756480,
-STORE, 46970356756480, 46970356772863,
-STORE, 46970356785152, 46970356793343,
-STORE, 46970356776960, 46970356785151,
-ERASE, 46970356776960, 46970356776960,
-STORE, 46970356776960, 46970356785151,
-ERASE, 46970356785152, 46970356785152,
-STORE, 46970356785152, 46970356793343,
-STORE, 46970356793344, 46970358632447,
-STORE, 46970356932608, 46970358632447,
-STORE, 46970356793344, 46970356932607,
-ERASE, 46970356932608, 46970356932608,
-STORE, 46970356932608, 46970358591487,
-STORE, 46970358591488, 46970358632447,
-STORE, 46970358276096, 46970358591487,
-STORE, 46970356932608, 46970358276095,
-ERASE, 46970356932608, 46970356932608,
-STORE, 46970356932608, 46970358276095,
-STORE, 46970358587392, 46970358591487,
-STORE, 46970358276096, 46970358587391,
-ERASE, 46970358276096, 46970358276096,
-STORE, 46970358276096, 46970358587391,
-STORE, 46970358616064, 46970358632447,
-STORE, 46970358591488, 46970358616063,
-ERASE, 46970358591488, 46970358591488,
-STORE, 46970358591488, 46970358616063,
-ERASE, 46970358616064, 46970358616064,
-STORE, 46970358616064, 46970358632447,
-STORE, 46970358616064, 46970358644735,
-ERASE, 46970358591488, 46970358591488,
-STORE, 46970358591488, 46970358607871,
-STORE, 46970358607872, 46970358616063,
-ERASE, 46970356776960, 46970356776960,
-STORE, 46970356776960, 46970356781055,
-STORE, 46970356781056, 46970356785151,
-ERASE, 94121892900864, 94121892900864,
-STORE, 94121892900864, 94121892917247,
-STORE, 94121892917248, 94121892921343,
-ERASE, 140662438486016, 140662438486016,
-STORE, 140662438486016, 140662438490111,
-STORE, 140662438490112, 140662438494207,
-ERASE, 46970356670464, 46970356670464,
-STORE, 94121898610688, 94121898745855,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737189351424, 140737488351231,
-ERASE, 140737189351424, 140737189351424,
-STORE, 140737189351424, 140737189355519,
-STORE, 93847948832768, 93847949545471,
-ERASE, 93847948832768, 93847948832768,
-STORE, 93847948832768, 93847948881919,
-STORE, 93847948881920, 93847949545471,
-ERASE, 93847948881920, 93847948881920,
-STORE, 93847948881920, 93847949426687,
-STORE, 93847949426688, 93847949524991,
-STORE, 93847949524992, 93847949545471,
-STORE, 139698989985792, 139698990157823,
-ERASE, 139698989985792, 139698989985792,
-STORE, 139698989985792, 139698989989887,
-STORE, 139698989989888, 139698990157823,
-ERASE, 139698989989888, 139698989989888,
-STORE, 139698989989888, 139698990112767,
-STORE, 139698990112768, 139698990145535,
-STORE, 139698990145536, 139698990153727,
-STORE, 139698990153728, 139698990157823,
-STORE, 140737189744640, 140737189748735,
-STORE, 140737189732352, 140737189744639,
-STORE, 47933805010944, 47933805019135,
-STORE, 47933805019136, 47933805027327,
-STORE, 47933805027328, 47933805133823,
-STORE, 47933805043712, 47933805133823,
-STORE, 47933805027328, 47933805043711,
-ERASE, 47933805043712, 47933805043712,
-STORE, 47933805043712, 47933805117439,
-STORE, 47933805117440, 47933805133823,
-STORE, 47933805096960, 47933805117439,
-STORE, 47933805043712, 47933805096959,
-ERASE, 47933805043712, 47933805043712,
-STORE, 47933805043712, 47933805096959,
-STORE, 47933805113344, 47933805117439,
-STORE, 47933805096960, 47933805113343,
-ERASE, 47933805096960, 47933805096960,
-STORE, 47933805096960, 47933805113343,
-STORE, 47933805125632, 47933805133823,
-STORE, 47933805117440, 47933805125631,
-ERASE, 47933805117440, 47933805117440,
-STORE, 47933805117440, 47933805125631,
-ERASE, 47933805125632, 47933805125632,
-STORE, 47933805125632, 47933805133823,
-STORE, 47933805133824, 47933806972927,
-STORE, 47933805273088, 47933806972927,
-STORE, 47933805133824, 47933805273087,
-ERASE, 47933805273088, 47933805273088,
-STORE, 47933805273088, 47933806931967,
-STORE, 47933806931968, 47933806972927,
-STORE, 47933806616576, 47933806931967,
-STORE, 47933805273088, 47933806616575,
-ERASE, 47933805273088, 47933805273088,
-STORE, 47933805273088, 47933806616575,
-STORE, 47933806927872, 47933806931967,
-STORE, 47933806616576, 47933806927871,
-ERASE, 47933806616576, 47933806616576,
-STORE, 47933806616576, 47933806927871,
-STORE, 47933806956544, 47933806972927,
-STORE, 47933806931968, 47933806956543,
-ERASE, 47933806931968, 47933806931968,
-STORE, 47933806931968, 47933806956543,
-ERASE, 47933806956544, 47933806956544,
-STORE, 47933806956544, 47933806972927,
-STORE, 47933806956544, 47933806985215,
-ERASE, 47933806931968, 47933806931968,
-STORE, 47933806931968, 47933806948351,
-STORE, 47933806948352, 47933806956543,
-ERASE, 47933805117440, 47933805117440,
-STORE, 47933805117440, 47933805121535,
-STORE, 47933805121536, 47933805125631,
-ERASE, 93847949524992, 93847949524992,
-STORE, 93847949524992, 93847949541375,
-STORE, 93847949541376, 93847949545471,
-ERASE, 139698990145536, 139698990145536,
-STORE, 139698990145536, 139698990149631,
-STORE, 139698990149632, 139698990153727,
-ERASE, 47933805010944, 47933805010944,
-STORE, 140737488347136, 140737488351231,
-STORE, 140725553991680, 140737488351231,
-ERASE, 140725553991680, 140725553991680,
-STORE, 140725553991680, 140725553995775,
-STORE, 93980056248320, 93980056961023,
-ERASE, 93980056248320, 93980056248320,
-STORE, 93980056248320, 93980056297471,
-STORE, 93980056297472, 93980056961023,
-ERASE, 93980056297472, 93980056297472,
-STORE, 93980056297472, 93980056842239,
-STORE, 93980056842240, 93980056940543,
-STORE, 93980056940544, 93980056961023,
-STORE, 140146588971008, 140146589143039,
-ERASE, 140146588971008, 140146588971008,
-STORE, 140146588971008, 140146588975103,
-STORE, 140146588975104, 140146589143039,
-ERASE, 140146588975104, 140146588975104,
-STORE, 140146588975104, 140146589097983,
-STORE, 140146589097984, 140146589130751,
-STORE, 140146589130752, 140146589138943,
-STORE, 140146589138944, 140146589143039,
-STORE, 140725554860032, 140725554864127,
-STORE, 140725554847744, 140725554860031,
-STORE, 47486206025728, 47486206033919,
-STORE, 47486206033920, 47486206042111,
-STORE, 47486206042112, 47486206148607,
-STORE, 47486206058496, 47486206148607,
-STORE, 47486206042112, 47486206058495,
-ERASE, 47486206058496, 47486206058496,
-STORE, 47486206058496, 47486206132223,
-STORE, 47486206132224, 47486206148607,
-STORE, 47486206111744, 47486206132223,
-STORE, 47486206058496, 47486206111743,
-ERASE, 47486206058496, 47486206058496,
-STORE, 47486206058496, 47486206111743,
-STORE, 47486206128128, 47486206132223,
-STORE, 47486206111744, 47486206128127,
-ERASE, 47486206111744, 47486206111744,
-STORE, 47486206111744, 47486206128127,
-STORE, 47486206140416, 47486206148607,
-STORE, 47486206132224, 47486206140415,
-ERASE, 47486206132224, 47486206132224,
-STORE, 47486206132224, 47486206140415,
-ERASE, 47486206140416, 47486206140416,
-STORE, 47486206140416, 47486206148607,
-STORE, 47486206148608, 47486207987711,
-STORE, 47486206287872, 47486207987711,
-STORE, 47486206148608, 47486206287871,
-ERASE, 47486206287872, 47486206287872,
-STORE, 47486206287872, 47486207946751,
-STORE, 47486207946752, 47486207987711,
-STORE, 47486207631360, 47486207946751,
-STORE, 47486206287872, 47486207631359,
-ERASE, 47486206287872, 47486206287872,
-STORE, 47486206287872, 47486207631359,
-STORE, 47486207942656, 47486207946751,
-STORE, 47486207631360, 47486207942655,
-ERASE, 47486207631360, 47486207631360,
-STORE, 47486207631360, 47486207942655,
-STORE, 47486207971328, 47486207987711,
-STORE, 47486207946752, 47486207971327,
-ERASE, 47486207946752, 47486207946752,
-STORE, 47486207946752, 47486207971327,
-ERASE, 47486207971328, 47486207971328,
-STORE, 47486207971328, 47486207987711,
-STORE, 47486207971328, 47486207999999,
-ERASE, 47486207946752, 47486207946752,
-STORE, 47486207946752, 47486207963135,
-STORE, 47486207963136, 47486207971327,
-ERASE, 47486206132224, 47486206132224,
-STORE, 47486206132224, 47486206136319,
-STORE, 47486206136320, 47486206140415,
-ERASE, 93980056940544, 93980056940544,
-STORE, 93980056940544, 93980056956927,
-STORE, 93980056956928, 93980056961023,
-ERASE, 140146589130752, 140146589130752,
-STORE, 140146589130752, 140146589134847,
-STORE, 140146589134848, 140146589138943,
-ERASE, 47486206025728, 47486206025728,
-STORE, 93980070006784, 93980070141951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727334776832, 140737488351231,
-ERASE, 140727334776832, 140727334776832,
-STORE, 140727334776832, 140727334780927,
-STORE, 94049747247104, 94049747959807,
-ERASE, 94049747247104, 94049747247104,
-STORE, 94049747247104, 94049747296255,
-STORE, 94049747296256, 94049747959807,
-ERASE, 94049747296256, 94049747296256,
-STORE, 94049747296256, 94049747841023,
-STORE, 94049747841024, 94049747939327,
-STORE, 94049747939328, 94049747959807,
-STORE, 140227307216896, 140227307388927,
-ERASE, 140227307216896, 140227307216896,
-STORE, 140227307216896, 140227307220991,
-STORE, 140227307220992, 140227307388927,
-ERASE, 140227307220992, 140227307220992,
-STORE, 140227307220992, 140227307343871,
-STORE, 140227307343872, 140227307376639,
-STORE, 140227307376640, 140227307384831,
-STORE, 140227307384832, 140227307388927,
-STORE, 140727335337984, 140727335342079,
-STORE, 140727335325696, 140727335337983,
-STORE, 47405487779840, 47405487788031,
-STORE, 47405487788032, 47405487796223,
-STORE, 47405487796224, 47405487902719,
-STORE, 47405487812608, 47405487902719,
-STORE, 47405487796224, 47405487812607,
-ERASE, 47405487812608, 47405487812608,
-STORE, 47405487812608, 47405487886335,
-STORE, 47405487886336, 47405487902719,
-STORE, 47405487865856, 47405487886335,
-STORE, 47405487812608, 47405487865855,
-ERASE, 47405487812608, 47405487812608,
-STORE, 47405487812608, 47405487865855,
-STORE, 47405487882240, 47405487886335,
-STORE, 47405487865856, 47405487882239,
-ERASE, 47405487865856, 47405487865856,
-STORE, 47405487865856, 47405487882239,
-STORE, 47405487894528, 47405487902719,
-STORE, 47405487886336, 47405487894527,
-ERASE, 47405487886336, 47405487886336,
-STORE, 47405487886336, 47405487894527,
-ERASE, 47405487894528, 47405487894528,
-STORE, 47405487894528, 47405487902719,
-STORE, 47405487902720, 47405489741823,
-STORE, 47405488041984, 47405489741823,
-STORE, 47405487902720, 47405488041983,
-ERASE, 47405488041984, 47405488041984,
-STORE, 47405488041984, 47405489700863,
-STORE, 47405489700864, 47405489741823,
-STORE, 47405489385472, 47405489700863,
-STORE, 47405488041984, 47405489385471,
-ERASE, 47405488041984, 47405488041984,
-STORE, 47405488041984, 47405489385471,
-STORE, 47405489696768, 47405489700863,
-STORE, 47405489385472, 47405489696767,
-ERASE, 47405489385472, 47405489385472,
-STORE, 47405489385472, 47405489696767,
-STORE, 47405489725440, 47405489741823,
-STORE, 47405489700864, 47405489725439,
-ERASE, 47405489700864, 47405489700864,
-STORE, 47405489700864, 47405489725439,
-ERASE, 47405489725440, 47405489725440,
-STORE, 47405489725440, 47405489741823,
-STORE, 47405489725440, 47405489754111,
-ERASE, 47405489700864, 47405489700864,
-STORE, 47405489700864, 47405489717247,
-STORE, 47405489717248, 47405489725439,
-ERASE, 47405487886336, 47405487886336,
-STORE, 47405487886336, 47405487890431,
-STORE, 47405487890432, 47405487894527,
-ERASE, 94049747939328, 94049747939328,
-STORE, 94049747939328, 94049747955711,
-STORE, 94049747955712, 94049747959807,
-ERASE, 140227307376640, 140227307376640,
-STORE, 140227307376640, 140227307380735,
-STORE, 140227307380736, 140227307384831,
-ERASE, 47405487779840, 47405487779840,
-STORE, 94049758810112, 94049758945279,
-STORE, 140737488347136, 140737488351231,
-STORE, 140727079718912, 140737488351231,
-ERASE, 140727079718912, 140727079718912,
-STORE, 140727079718912, 140727079723007,
-STORE, 94250996527104, 94250997239807,
-ERASE, 94250996527104, 94250996527104,
-STORE, 94250996527104, 94250996576255,
-STORE, 94250996576256, 94250997239807,
-ERASE, 94250996576256, 94250996576256,
-STORE, 94250996576256, 94250997121023,
-STORE, 94250997121024, 94250997219327,
-STORE, 94250997219328, 94250997239807,
-STORE, 140060022587392, 140060022759423,
-ERASE, 140060022587392, 140060022587392,
-STORE, 140060022587392, 140060022591487,
-STORE, 140060022591488, 140060022759423,
-ERASE, 140060022591488, 140060022591488,
-STORE, 140060022591488, 140060022714367,
-STORE, 140060022714368, 140060022747135,
-STORE, 140060022747136, 140060022755327,
-STORE, 140060022755328, 140060022759423,
-STORE, 140727079788544, 140727079792639,
-STORE, 140727079776256, 140727079788543,
-STORE, 47572772409344, 47572772417535,
-STORE, 47572772417536, 47572772425727,
-STORE, 47572772425728, 47572772532223,
-STORE, 47572772442112, 47572772532223,
-STORE, 47572772425728, 47572772442111,
-ERASE, 47572772442112, 47572772442112,
-STORE, 47572772442112, 47572772515839,
-STORE, 47572772515840, 47572772532223,
-STORE, 47572772495360, 47572772515839,
-STORE, 47572772442112, 47572772495359,
-ERASE, 47572772442112, 47572772442112,
-STORE, 47572772442112, 47572772495359,
-STORE, 47572772511744, 47572772515839,
-STORE, 47572772495360, 47572772511743,
-ERASE, 47572772495360, 47572772495360,
-STORE, 47572772495360, 47572772511743,
-STORE, 47572772524032, 47572772532223,
-STORE, 47572772515840, 47572772524031,
-ERASE, 47572772515840, 47572772515840,
-STORE, 47572772515840, 47572772524031,
-ERASE, 47572772524032, 47572772524032,
-STORE, 47572772524032, 47572772532223,
-STORE, 47572772532224, 47572774371327,
-STORE, 47572772671488, 47572774371327,
-STORE, 47572772532224, 47572772671487,
-ERASE, 47572772671488, 47572772671488,
-STORE, 47572772671488, 47572774330367,
-STORE, 47572774330368, 47572774371327,
-STORE, 47572774014976, 47572774330367,
-STORE, 47572772671488, 47572774014975,
-ERASE, 47572772671488, 47572772671488,
-STORE, 47572772671488, 47572774014975,
-STORE, 47572774326272, 47572774330367,
-STORE, 47572774014976, 47572774326271,
-ERASE, 47572774014976, 47572774014976,
-STORE, 47572774014976, 47572774326271,
-STORE, 47572774354944, 47572774371327,
-STORE, 47572774330368, 47572774354943,
-ERASE, 47572774330368, 47572774330368,
-STORE, 47572774330368, 47572774354943,
-ERASE, 47572774354944, 47572774354944,
-STORE, 47572774354944, 47572774371327,
-STORE, 47572774354944, 47572774383615,
-ERASE, 47572774330368, 47572774330368,
-STORE, 47572774330368, 47572774346751,
-STORE, 47572774346752, 47572774354943,
-ERASE, 47572772515840, 47572772515840,
-STORE, 47572772515840, 47572772519935,
-STORE, 47572772519936, 47572772524031,
-ERASE, 94250997219328, 94250997219328,
-STORE, 94250997219328, 94250997235711,
-STORE, 94250997235712, 94250997239807,
-ERASE, 140060022747136, 140060022747136,
-STORE, 140060022747136, 140060022751231,
-STORE, 140060022751232, 140060022755327,
-ERASE, 47572772409344, 47572772409344,
-STORE, 94251018305536, 94251018440703,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730012389376, 140737488351231,
-ERASE, 140730012389376, 140730012389376,
-STORE, 140730012389376, 140730012393471,
-STORE, 94382607675392, 94382607695871,
-ERASE, 94382607675392, 94382607675392,
-STORE, 94382607675392, 94382607679487,
-STORE, 94382607679488, 94382607695871,
-ERASE, 94382607679488, 94382607679488,
-STORE, 94382607679488, 94382607683583,
-STORE, 94382607683584, 94382607687679,
-STORE, 94382607687680, 94382607695871,
-STORE, 140252451454976, 140252451627007,
-ERASE, 140252451454976, 140252451454976,
-STORE, 140252451454976, 140252451459071,
-STORE, 140252451459072, 140252451627007,
-ERASE, 140252451459072, 140252451459072,
-STORE, 140252451459072, 140252451581951,
-STORE, 140252451581952, 140252451614719,
-STORE, 140252451614720, 140252451622911,
-STORE, 140252451622912, 140252451627007,
-STORE, 140730013548544, 140730013552639,
-STORE, 140730013536256, 140730013548543,
-STORE, 47380343541760, 47380343549951,
-STORE, 47380343549952, 47380343558143,
-STORE, 47380343558144, 47380345397247,
-STORE, 47380343697408, 47380345397247,
-STORE, 47380343558144, 47380343697407,
-ERASE, 47380343697408, 47380343697408,
-STORE, 47380343697408, 47380345356287,
-STORE, 47380345356288, 47380345397247,
-STORE, 47380345040896, 47380345356287,
-STORE, 47380343697408, 47380345040895,
-ERASE, 47380343697408, 47380343697408,
-STORE, 47380343697408, 47380345040895,
-STORE, 47380345352192, 47380345356287,
-STORE, 47380345040896, 47380345352191,
-ERASE, 47380345040896, 47380345040896,
-STORE, 47380345040896, 47380345352191,
-STORE, 47380345380864, 47380345397247,
-STORE, 47380345356288, 47380345380863,
-ERASE, 47380345356288, 47380345356288,
-STORE, 47380345356288, 47380345380863,
-ERASE, 47380345380864, 47380345380864,
-STORE, 47380345380864, 47380345397247,
-ERASE, 47380345356288, 47380345356288,
-STORE, 47380345356288, 47380345372671,
-STORE, 47380345372672, 47380345380863,
-ERASE, 94382607687680, 94382607687680,
-STORE, 94382607687680, 94382607691775,
-STORE, 94382607691776, 94382607695871,
-ERASE, 140252451614720, 140252451614720,
-STORE, 140252451614720, 140252451618815,
-STORE, 140252451618816, 140252451622911,
-ERASE, 47380343541760, 47380343541760,
-STORE, 94382626803712, 94382626938879,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730900271104, 140737488351231,
-ERASE, 140730900271104, 140730900271104,
-STORE, 140730900271104, 140730900275199,
-STORE, 93855478120448, 93855478337535,
-ERASE, 93855478120448, 93855478120448,
-STORE, 93855478120448, 93855478198271,
-STORE, 93855478198272, 93855478337535,
-ERASE, 93855478198272, 93855478198272,
-STORE, 93855478198272, 93855478243327,
-STORE, 93855478243328, 93855478288383,
-STORE, 93855478288384, 93855478337535,
-STORE, 140092686573568, 140092686745599,
-ERASE, 140092686573568, 140092686573568,
-STORE, 140092686573568, 140092686577663,
-STORE, 140092686577664, 140092686745599,
-ERASE, 140092686577664, 140092686577664,
-STORE, 140092686577664, 140092686700543,
-STORE, 140092686700544, 140092686733311,
-STORE, 140092686733312, 140092686741503,
-STORE, 140092686741504, 140092686745599,
-STORE, 140730900537344, 140730900541439,
-STORE, 140730900525056, 140730900537343,
-STORE, 47540108423168, 47540108431359,
-STORE, 47540108431360, 47540108439551,
-STORE, 47540108439552, 47540110278655,
-STORE, 47540108578816, 47540110278655,
-STORE, 47540108439552, 47540108578815,
-ERASE, 47540108578816, 47540108578816,
-STORE, 47540108578816, 47540110237695,
-STORE, 47540110237696, 47540110278655,
-STORE, 47540109922304, 47540110237695,
-STORE, 47540108578816, 47540109922303,
-ERASE, 47540108578816, 47540108578816,
-STORE, 47540108578816, 47540109922303,
-STORE, 47540110233600, 47540110237695,
-STORE, 47540109922304, 47540110233599,
-ERASE, 47540109922304, 47540109922304,
-STORE, 47540109922304, 47540110233599,
-STORE, 47540110262272, 47540110278655,
-STORE, 47540110237696, 47540110262271,
-ERASE, 47540110237696, 47540110237696,
-STORE, 47540110237696, 47540110262271,
-ERASE, 47540110262272, 47540110262272,
-STORE, 47540110262272, 47540110278655,
-ERASE, 47540110237696, 47540110237696,
-STORE, 47540110237696, 47540110254079,
-STORE, 47540110254080, 47540110262271,
-ERASE, 93855478288384, 93855478288384,
-STORE, 93855478288384, 93855478333439,
-STORE, 93855478333440, 93855478337535,
-ERASE, 140092686733312, 140092686733312,
-STORE, 140092686733312, 140092686737407,
-STORE, 140092686737408, 140092686741503,
-ERASE, 47540108423168, 47540108423168,
-STORE, 93855492222976, 93855492358143,
-STORE, 93855492222976, 93855492493311,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733498146816, 140737488351231,
-ERASE, 140733498146816, 140733498146816,
-STORE, 140733498146816, 140733498150911,
-STORE, 94170739654656, 94170740367359,
-ERASE, 94170739654656, 94170739654656,
-STORE, 94170739654656, 94170739703807,
-STORE, 94170739703808, 94170740367359,
-ERASE, 94170739703808, 94170739703808,
-STORE, 94170739703808, 94170740248575,
-STORE, 94170740248576, 94170740346879,
-STORE, 94170740346880, 94170740367359,
-STORE, 140024788877312, 140024789049343,
-ERASE, 140024788877312, 140024788877312,
-STORE, 140024788877312, 140024788881407,
-STORE, 140024788881408, 140024789049343,
-ERASE, 140024788881408, 140024788881408,
-STORE, 140024788881408, 140024789004287,
-STORE, 140024789004288, 140024789037055,
-STORE, 140024789037056, 140024789045247,
-STORE, 140024789045248, 140024789049343,
-STORE, 140733499023360, 140733499027455,
-STORE, 140733499011072, 140733499023359,
-STORE, 47608006119424, 47608006127615,
-STORE, 47608006127616, 47608006135807,
-STORE, 47608006135808, 47608006242303,
-STORE, 47608006152192, 47608006242303,
-STORE, 47608006135808, 47608006152191,
-ERASE, 47608006152192, 47608006152192,
-STORE, 47608006152192, 47608006225919,
-STORE, 47608006225920, 47608006242303,
-STORE, 47608006205440, 47608006225919,
-STORE, 47608006152192, 47608006205439,
-ERASE, 47608006152192, 47608006152192,
-STORE, 47608006152192, 47608006205439,
-STORE, 47608006221824, 47608006225919,
-STORE, 47608006205440, 47608006221823,
-ERASE, 47608006205440, 47608006205440,
-STORE, 47608006205440, 47608006221823,
-STORE, 47608006234112, 47608006242303,
-STORE, 47608006225920, 47608006234111,
-ERASE, 47608006225920, 47608006225920,
-STORE, 47608006225920, 47608006234111,
-ERASE, 47608006234112, 47608006234112,
-STORE, 47608006234112, 47608006242303,
-STORE, 47608006242304, 47608008081407,
-STORE, 47608006381568, 47608008081407,
-STORE, 47608006242304, 47608006381567,
-ERASE, 47608006381568, 47608006381568,
-STORE, 47608006381568, 47608008040447,
-STORE, 47608008040448, 47608008081407,
-STORE, 47608007725056, 47608008040447,
-STORE, 47608006381568, 47608007725055,
-ERASE, 47608006381568, 47608006381568,
-STORE, 47608006381568, 47608007725055,
-STORE, 47608008036352, 47608008040447,
-STORE, 47608007725056, 47608008036351,
-ERASE, 47608007725056, 47608007725056,
-STORE, 47608007725056, 47608008036351,
-STORE, 47608008065024, 47608008081407,
-STORE, 47608008040448, 47608008065023,
-ERASE, 47608008040448, 47608008040448,
-STORE, 47608008040448, 47608008065023,
-ERASE, 47608008065024, 47608008065024,
-STORE, 47608008065024, 47608008081407,
-STORE, 47608008065024, 47608008093695,
-ERASE, 47608008040448, 47608008040448,
-STORE, 47608008040448, 47608008056831,
-STORE, 47608008056832, 47608008065023,
-ERASE, 47608006225920, 47608006225920,
-STORE, 47608006225920, 47608006230015,
-STORE, 47608006230016, 47608006234111,
-ERASE, 94170740346880, 94170740346880,
-STORE, 94170740346880, 94170740363263,
-STORE, 94170740363264, 94170740367359,
-ERASE, 140024789037056, 140024789037056,
-STORE, 140024789037056, 140024789041151,
-STORE, 140024789041152, 140024789045247,
-ERASE, 47608006119424, 47608006119424,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730264326144, 140737488351231,
-ERASE, 140730264326144, 140730264326144,
-STORE, 140730264326144, 140730264330239,
-STORE, 94653216407552, 94653217120255,
-ERASE, 94653216407552, 94653216407552,
-STORE, 94653216407552, 94653216456703,
-STORE, 94653216456704, 94653217120255,
-ERASE, 94653216456704, 94653216456704,
-STORE, 94653216456704, 94653217001471,
-STORE, 94653217001472, 94653217099775,
-STORE, 94653217099776, 94653217120255,
-STORE, 140103617011712, 140103617183743,
-ERASE, 140103617011712, 140103617011712,
-STORE, 140103617011712, 140103617015807,
-STORE, 140103617015808, 140103617183743,
-ERASE, 140103617015808, 140103617015808,
-STORE, 140103617015808, 140103617138687,
-STORE, 140103617138688, 140103617171455,
-STORE, 140103617171456, 140103617179647,
-STORE, 140103617179648, 140103617183743,
-STORE, 140730265427968, 140730265432063,
-STORE, 140730265415680, 140730265427967,
-STORE, 47529177985024, 47529177993215,
-STORE, 47529177993216, 47529178001407,
-STORE, 47529178001408, 47529178107903,
-STORE, 47529178017792, 47529178107903,
-STORE, 47529178001408, 47529178017791,
-ERASE, 47529178017792, 47529178017792,
-STORE, 47529178017792, 47529178091519,
-STORE, 47529178091520, 47529178107903,
-STORE, 47529178071040, 47529178091519,
-STORE, 47529178017792, 47529178071039,
-ERASE, 47529178017792, 47529178017792,
-STORE, 47529178017792, 47529178071039,
-STORE, 47529178087424, 47529178091519,
-STORE, 47529178071040, 47529178087423,
-ERASE, 47529178071040, 47529178071040,
-STORE, 47529178071040, 47529178087423,
-STORE, 47529178099712, 47529178107903,
-STORE, 47529178091520, 47529178099711,
-ERASE, 47529178091520, 47529178091520,
-STORE, 47529178091520, 47529178099711,
-ERASE, 47529178099712, 47529178099712,
-STORE, 47529178099712, 47529178107903,
-STORE, 47529178107904, 47529179947007,
-STORE, 47529178247168, 47529179947007,
-STORE, 47529178107904, 47529178247167,
-ERASE, 47529178247168, 47529178247168,
-STORE, 47529178247168, 47529179906047,
-STORE, 47529179906048, 47529179947007,
-STORE, 47529179590656, 47529179906047,
-STORE, 47529178247168, 47529179590655,
-ERASE, 47529178247168, 47529178247168,
-STORE, 47529178247168, 47529179590655,
-STORE, 47529179901952, 47529179906047,
-STORE, 47529179590656, 47529179901951,
-ERASE, 47529179590656, 47529179590656,
-STORE, 47529179590656, 47529179901951,
-STORE, 47529179930624, 47529179947007,
-STORE, 47529179906048, 47529179930623,
-ERASE, 47529179906048, 47529179906048,
-STORE, 47529179906048, 47529179930623,
-ERASE, 47529179930624, 47529179930624,
-STORE, 47529179930624, 47529179947007,
-STORE, 47529179930624, 47529179959295,
-ERASE, 47529179906048, 47529179906048,
-STORE, 47529179906048, 47529179922431,
-STORE, 47529179922432, 47529179930623,
-ERASE, 47529178091520, 47529178091520,
-STORE, 47529178091520, 47529178095615,
-STORE, 47529178095616, 47529178099711,
-ERASE, 94653217099776, 94653217099776,
-STORE, 94653217099776, 94653217116159,
-STORE, 94653217116160, 94653217120255,
-ERASE, 140103617171456, 140103617171456,
-STORE, 140103617171456, 140103617175551,
-STORE, 140103617175552, 140103617179647,
-ERASE, 47529177985024, 47529177985024,
-STORE, 94653241135104, 94653241270271,
-STORE, 140737488347136, 140737488351231,
-STORE, 140736284549120, 140737488351231,
-ERASE, 140736284549120, 140736284549120,
-STORE, 140736284549120, 140736284553215,
-STORE, 93963663822848, 93963664506879,
-ERASE, 93963663822848, 93963663822848,
-STORE, 93963663822848, 93963663884287,
-STORE, 93963663884288, 93963664506879,
-ERASE, 93963663884288, 93963663884288,
-STORE, 93963663884288, 93963664240639,
-STORE, 93963664240640, 93963664379903,
-STORE, 93963664379904, 93963664506879,
-STORE, 140450188439552, 140450188611583,
-ERASE, 140450188439552, 140450188439552,
-STORE, 140450188439552, 140450188443647,
-STORE, 140450188443648, 140450188611583,
-ERASE, 140450188443648, 140450188443648,
-STORE, 140450188443648, 140450188566527,
-STORE, 140450188566528, 140450188599295,
-STORE, 140450188599296, 140450188607487,
-STORE, 140450188607488, 140450188611583,
-STORE, 140736284577792, 140736284581887,
-STORE, 140736284565504, 140736284577791,
-STORE, 47182606557184, 47182606565375,
-STORE, 47182606565376, 47182606573567,
-STORE, 47182606573568, 47182608412671,
-STORE, 47182606712832, 47182608412671,
-STORE, 47182606573568, 47182606712831,
-ERASE, 47182606712832, 47182606712832,
-STORE, 47182606712832, 47182608371711,
-STORE, 47182608371712, 47182608412671,
-STORE, 47182608056320, 47182608371711,
-STORE, 47182606712832, 47182608056319,
-ERASE, 47182606712832, 47182606712832,
-STORE, 47182606712832, 47182608056319,
-STORE, 47182608367616, 47182608371711,
-STORE, 47182608056320, 47182608367615,
-ERASE, 47182608056320, 47182608056320,
-STORE, 47182608056320, 47182608367615,
-STORE, 47182608396288, 47182608412671,
-STORE, 47182608371712, 47182608396287,
-ERASE, 47182608371712, 47182608371712,
-STORE, 47182608371712, 47182608396287,
-ERASE, 47182608396288, 47182608396288,
-STORE, 47182608396288, 47182608412671,
-STORE, 47182608412672, 47182608523263,
-STORE, 47182608429056, 47182608523263,
-STORE, 47182608412672, 47182608429055,
-ERASE, 47182608429056, 47182608429056,
-STORE, 47182608429056, 47182608515071,
-STORE, 47182608515072, 47182608523263,
-STORE, 47182608490496, 47182608515071,
-STORE, 47182608429056, 47182608490495,
-ERASE, 47182608429056, 47182608429056,
-STORE, 47182608429056, 47182608490495,
-STORE, 47182608510976, 47182608515071,
-STORE, 47182608490496, 47182608510975,
-ERASE, 47182608490496, 47182608490496,
-STORE, 47182608490496, 47182608510975,
-ERASE, 47182608515072, 47182608515072,
-STORE, 47182608515072, 47182608523263,
-STORE, 47182608523264, 47182608568319,
-ERASE, 47182608523264, 47182608523264,
-STORE, 47182608523264, 47182608531455,
-STORE, 47182608531456, 47182608568319,
-STORE, 47182608551936, 47182608568319,
-STORE, 47182608531456, 47182608551935,
-ERASE, 47182608531456, 47182608531456,
-STORE, 47182608531456, 47182608551935,
-STORE, 47182608560128, 47182608568319,
-STORE, 47182608551936, 47182608560127,
-ERASE, 47182608551936, 47182608551936,
-STORE, 47182608551936, 47182608568319,
-ERASE, 47182608551936, 47182608551936,
-STORE, 47182608551936, 47182608560127,
-STORE, 47182608560128, 47182608568319,
-ERASE, 47182608560128, 47182608560128,
-STORE, 47182608560128, 47182608568319,
-STORE, 47182608568320, 47182608916479,
-STORE, 47182608609280, 47182608916479,
-STORE, 47182608568320, 47182608609279,
-ERASE, 47182608609280, 47182608609280,
-STORE, 47182608609280, 47182608891903,
-STORE, 47182608891904, 47182608916479,
-STORE, 47182608822272, 47182608891903,
-STORE, 47182608609280, 47182608822271,
-ERASE, 47182608609280, 47182608609280,
-STORE, 47182608609280, 47182608822271,
-STORE, 47182608887808, 47182608891903,
-STORE, 47182608822272, 47182608887807,
-ERASE, 47182608822272, 47182608822272,
-STORE, 47182608822272, 47182608887807,
-ERASE, 47182608891904, 47182608891904,
-STORE, 47182608891904, 47182608916479,
-STORE, 47182608916480, 47182611177471,
-STORE, 47182609068032, 47182611177471,
-STORE, 47182608916480, 47182609068031,
-ERASE, 47182609068032, 47182609068032,
-STORE, 47182609068032, 47182611161087,
-STORE, 47182611161088, 47182611177471,
-STORE, 47182611169280, 47182611177471,
-STORE, 47182611161088, 47182611169279,
-ERASE, 47182611161088, 47182611161088,
-STORE, 47182611161088, 47182611169279,
-ERASE, 47182611169280, 47182611169280,
-STORE, 47182611169280, 47182611177471,
-STORE, 47182611177472, 47182611312639,
-ERASE, 47182611177472, 47182611177472,
-STORE, 47182611177472, 47182611202047,
-STORE, 47182611202048, 47182611312639,
-STORE, 47182611263488, 47182611312639,
-STORE, 47182611202048, 47182611263487,
-ERASE, 47182611202048, 47182611202048,
-STORE, 47182611202048, 47182611263487,
-STORE, 47182611288064, 47182611312639,
-STORE, 47182611263488, 47182611288063,
-ERASE, 47182611263488, 47182611263488,
-STORE, 47182611263488, 47182611312639,
-ERASE, 47182611263488, 47182611263488,
-STORE, 47182611263488, 47182611288063,
-STORE, 47182611288064, 47182611312639,
-STORE, 47182611296256, 47182611312639,
-STORE, 47182611288064, 47182611296255,
-ERASE, 47182611288064, 47182611288064,
-STORE, 47182611288064, 47182611296255,
-ERASE, 47182611296256, 47182611296256,
-STORE, 47182611296256, 47182611312639,
-STORE, 47182611296256, 47182611320831,
-STORE, 47182611320832, 47182611484671,
-ERASE, 47182611320832, 47182611320832,
-STORE, 47182611320832, 47182611333119,
-STORE, 47182611333120, 47182611484671,
-STORE, 47182611431424, 47182611484671,
-STORE, 47182611333120, 47182611431423,
-ERASE, 47182611333120, 47182611333120,
-STORE, 47182611333120, 47182611431423,
-STORE, 47182611476480, 47182611484671,
-STORE, 47182611431424, 47182611476479,
-ERASE, 47182611431424, 47182611431424,
-STORE, 47182611431424, 47182611484671,
-ERASE, 47182611431424, 47182611431424,
-STORE, 47182611431424, 47182611476479,
-STORE, 47182611476480, 47182611484671,
-ERASE, 47182611476480, 47182611476480,
-STORE, 47182611476480, 47182611484671,
-STORE, 47182611484672, 47182612082687,
-STORE, 47182611603456, 47182612082687,
-STORE, 47182611484672, 47182611603455,
-ERASE, 47182611603456, 47182611603456,
-STORE, 47182611603456, 47182612029439,
-STORE, 47182612029440, 47182612082687,
-STORE, 47182611918848, 47182612029439,
-STORE, 47182611603456, 47182611918847,
-ERASE, 47182611603456, 47182611603456,
-STORE, 47182611603456, 47182611918847,
-STORE, 47182612025344, 47182612029439,
-STORE, 47182611918848, 47182612025343,
-ERASE, 47182611918848, 47182611918848,
-STORE, 47182611918848, 47182612025343,
-ERASE, 47182612029440, 47182612029440,
-STORE, 47182612029440, 47182612082687,
-STORE, 47182612082688, 47182615134207,
-STORE, 47182612627456, 47182615134207,
-STORE, 47182612082688, 47182612627455,
-ERASE, 47182612627456, 47182612627456,
-STORE, 47182612627456, 47182614913023,
-STORE, 47182614913024, 47182615134207,
-STORE, 47182614323200, 47182614913023,
-STORE, 47182612627456, 47182614323199,
-ERASE, 47182612627456, 47182612627456,
-STORE, 47182612627456, 47182614323199,
-STORE, 47182614908928, 47182614913023,
-STORE, 47182614323200, 47182614908927,
-ERASE, 47182614323200, 47182614323200,
-STORE, 47182614323200, 47182614908927,
-STORE, 47182615117824, 47182615134207,
-STORE, 47182614913024, 47182615117823,
-ERASE, 47182614913024, 47182614913024,
-STORE, 47182614913024, 47182615117823,
-ERASE, 47182615117824, 47182615117824,
-STORE, 47182615117824, 47182615134207,
-STORE, 47182615134208, 47182615166975,
-ERASE, 47182615134208, 47182615134208,
-STORE, 47182615134208, 47182615142399,
-STORE, 47182615142400, 47182615166975,
-STORE, 47182615154688, 47182615166975,
-STORE, 47182615142400, 47182615154687,
-ERASE, 47182615142400, 47182615142400,
-STORE, 47182615142400, 47182615154687,
-STORE, 47182615158784, 47182615166975,
-STORE, 47182615154688, 47182615158783,
-ERASE, 47182615154688, 47182615154688,
-STORE, 47182615154688, 47182615166975,
-ERASE, 47182615154688, 47182615154688,
-STORE, 47182615154688, 47182615158783,
-STORE, 47182615158784, 47182615166975,
-ERASE, 47182615158784, 47182615158784,
-STORE, 47182615158784, 47182615166975,
-STORE, 47182615166976, 47182615203839,
-ERASE, 47182615166976, 47182615166976,
-STORE, 47182615166976, 47182615175167,
-STORE, 47182615175168, 47182615203839,
-STORE, 47182615191552, 47182615203839,
-STORE, 47182615175168, 47182615191551,
-ERASE, 47182615175168, 47182615175168,
-STORE, 47182615175168, 47182615191551,
-STORE, 47182615195648, 47182615203839,
-STORE, 47182615191552, 47182615195647,
-ERASE, 47182615191552, 47182615191552,
-STORE, 47182615191552, 47182615203839,
-ERASE, 47182615191552, 47182615191552,
-STORE, 47182615191552, 47182615195647,
-STORE, 47182615195648, 47182615203839,
-ERASE, 47182615195648, 47182615195648,
-STORE, 47182615195648, 47182615203839,
-STORE, 47182615203840, 47182615678975,
-ERASE, 47182615203840, 47182615203840,
-STORE, 47182615203840, 47182615212031,
-STORE, 47182615212032, 47182615678975,
-STORE, 47182615547904, 47182615678975,
-STORE, 47182615212032, 47182615547903,
-ERASE, 47182615212032, 47182615212032,
-STORE, 47182615212032, 47182615547903,
-STORE, 47182615670784, 47182615678975,
-STORE, 47182615547904, 47182615670783,
-ERASE, 47182615547904, 47182615547904,
-STORE, 47182615547904, 47182615678975,
-ERASE, 47182615547904, 47182615547904,
-STORE, 47182615547904, 47182615670783,
-STORE, 47182615670784, 47182615678975,
-ERASE, 47182615670784, 47182615670784,
-STORE, 47182615670784, 47182615678975,
-STORE, 47182615678976, 47182615687167,
-STORE, 47182615687168, 47182615707647,
-ERASE, 47182615687168, 47182615687168,
-STORE, 47182615687168, 47182615691263,
-STORE, 47182615691264, 47182615707647,
-STORE, 47182615695360, 47182615707647,
-STORE, 47182615691264, 47182615695359,
-ERASE, 47182615691264, 47182615691264,
-STORE, 47182615691264, 47182615695359,
-STORE, 47182615699456, 47182615707647,
-STORE, 47182615695360, 47182615699455,
-ERASE, 47182615695360, 47182615695360,
-STORE, 47182615695360, 47182615707647,
-ERASE, 47182615695360, 47182615695360,
-STORE, 47182615695360, 47182615699455,
-STORE, 47182615699456, 47182615707647,
-ERASE, 47182615699456, 47182615699456,
-STORE, 47182615699456, 47182615707647,
-STORE, 47182615707648, 47182615715839,
-ERASE, 47182608371712, 47182608371712,
-STORE, 47182608371712, 47182608388095,
-STORE, 47182608388096, 47182608396287,
-ERASE, 47182615699456, 47182615699456,
-STORE, 47182615699456, 47182615703551,
-STORE, 47182615703552, 47182615707647,
-ERASE, 47182611288064, 47182611288064,
-STORE, 47182611288064, 47182611292159,
-STORE, 47182611292160, 47182611296255,
-ERASE, 47182615670784, 47182615670784,
-STORE, 47182615670784, 47182615674879,
-STORE, 47182615674880, 47182615678975,
-ERASE, 47182615195648, 47182615195648,
-STORE, 47182615195648, 47182615199743,
-STORE, 47182615199744, 47182615203839,
-ERASE, 47182615158784, 47182615158784,
-STORE, 47182615158784, 47182615162879,
-STORE, 47182615162880, 47182615166975,
-ERASE, 47182614913024, 47182614913024,
-STORE, 47182614913024, 47182615109631,
-STORE, 47182615109632, 47182615117823,
-ERASE, 47182612029440, 47182612029440,
-STORE, 47182612029440, 47182612066303,
-STORE, 47182612066304, 47182612082687,
-ERASE, 47182611476480, 47182611476480,
-STORE, 47182611476480, 47182611480575,
-STORE, 47182611480576, 47182611484671,
-ERASE, 47182611161088, 47182611161088,
-STORE, 47182611161088, 47182611165183,
-STORE, 47182611165184, 47182611169279,
-ERASE, 47182608891904, 47182608891904,
-STORE, 47182608891904, 47182608912383,
-STORE, 47182608912384, 47182608916479,
-ERASE, 47182608560128, 47182608560128,
-STORE, 47182608560128, 47182608564223,
-STORE, 47182608564224, 47182608568319,
-ERASE, 47182608515072, 47182608515072,
-STORE, 47182608515072, 47182608519167,
-STORE, 47182608519168, 47182608523263,
-ERASE, 93963664379904, 93963664379904,
-STORE, 93963664379904, 93963664502783,
-STORE, 93963664502784, 93963664506879,
-ERASE, 140450188599296, 140450188599296,
-STORE, 140450188599296, 140450188603391,
-STORE, 140450188603392, 140450188607487,
-ERASE, 47182606557184, 47182606557184,
-STORE, 93963694723072, 93963694858239,
-STORE, 140737488347136, 140737488351231,
-STORE, 140730313261056, 140737488351231,
-ERASE, 140730313261056, 140730313261056,
-STORE, 140730313261056, 140730313265151,
-STORE, 94386579017728, 94386579697663,
-ERASE, 94386579017728, 94386579017728,
-STORE, 94386579017728, 94386579083263,
-STORE, 94386579083264, 94386579697663,
-ERASE, 94386579083264, 94386579083264,
-STORE, 94386579083264, 94386579431423,
-STORE, 94386579431424, 94386579570687,
-STORE, 94386579570688, 94386579697663,
-STORE, 140124810838016, 140124811010047,
-ERASE, 140124810838016, 140124810838016,
-STORE, 140124810838016, 140124810842111,
-STORE, 140124810842112, 140124811010047,
-ERASE, 140124810842112, 140124810842112,
-STORE, 140124810842112, 140124810964991,
-STORE, 140124810964992, 140124810997759,
-STORE, 140124810997760, 140124811005951,
-STORE, 140124811005952, 140124811010047,
-STORE, 140730313601024, 140730313605119,
-STORE, 140730313588736, 140730313601023,
-STORE, 47507984158720, 47507984166911,
-STORE, 47507984166912, 47507984175103,
-STORE, 47507984175104, 47507986014207,
-STORE, 47507984314368, 47507986014207,
-STORE, 47507984175104, 47507984314367,
-ERASE, 47507984314368, 47507984314368,
-STORE, 47507984314368, 47507985973247,
-STORE, 47507985973248, 47507986014207,
-STORE, 47507985657856, 47507985973247,
-STORE, 47507984314368, 47507985657855,
-ERASE, 47507984314368, 47507984314368,
-STORE, 47507984314368, 47507985657855,
-STORE, 47507985969152, 47507985973247,
-STORE, 47507985657856, 47507985969151,
-ERASE, 47507985657856, 47507985657856,
-STORE, 47507985657856, 47507985969151,
-STORE, 47507985997824, 47507986014207,
-STORE, 47507985973248, 47507985997823,
-ERASE, 47507985973248, 47507985973248,
-STORE, 47507985973248, 47507985997823,
-ERASE, 47507985997824, 47507985997824,
-STORE, 47507985997824, 47507986014207,
-STORE, 47507986014208, 47507986124799,
-STORE, 47507986030592, 47507986124799,
-STORE, 47507986014208, 47507986030591,
-ERASE, 47507986030592, 47507986030592,
-STORE, 47507986030592, 47507986116607,
-STORE, 47507986116608, 47507986124799,
-STORE, 47507986092032, 47507986116607,
-STORE, 47507986030592, 47507986092031,
-ERASE, 47507986030592, 47507986030592,
-STORE, 47507986030592, 47507986092031,
-STORE, 47507986112512, 47507986116607,
-STORE, 47507986092032, 47507986112511,
-ERASE, 47507986092032, 47507986092032,
-STORE, 47507986092032, 47507986112511,
-ERASE, 47507986116608, 47507986116608,
-STORE, 47507986116608, 47507986124799,
-STORE, 47507986124800, 47507986169855,
-ERASE, 47507986124800, 47507986124800,
-STORE, 47507986124800, 47507986132991,
-STORE, 47507986132992, 47507986169855,
-STORE, 47507986153472, 47507986169855,
-STORE, 47507986132992, 47507986153471,
-ERASE, 47507986132992, 47507986132992,
-STORE, 47507986132992, 47507986153471,
-STORE, 47507986161664, 47507986169855,
-STORE, 47507986153472, 47507986161663,
-ERASE, 47507986153472, 47507986153472,
-STORE, 47507986153472, 47507986169855,
-ERASE, 47507986153472, 47507986153472,
-STORE, 47507986153472, 47507986161663,
-STORE, 47507986161664, 47507986169855,
-ERASE, 47507986161664, 47507986161664,
-STORE, 47507986161664, 47507986169855,
-STORE, 47507986169856, 47507986518015,
-STORE, 47507986210816, 47507986518015,
-STORE, 47507986169856, 47507986210815,
-ERASE, 47507986210816, 47507986210816,
-STORE, 47507986210816, 47507986493439,
-STORE, 47507986493440, 47507986518015,
-STORE, 47507986423808, 47507986493439,
-STORE, 47507986210816, 47507986423807,
-ERASE, 47507986210816, 47507986210816,
-STORE, 47507986210816, 47507986423807,
-STORE, 47507986489344, 47507986493439,
-STORE, 47507986423808, 47507986489343,
-ERASE, 47507986423808, 47507986423808,
-STORE, 47507986423808, 47507986489343,
-ERASE, 47507986493440, 47507986493440,
-STORE, 47507986493440, 47507986518015,
-STORE, 47507986518016, 47507988779007,
-STORE, 47507986669568, 47507988779007,
-STORE, 47507986518016, 47507986669567,
-ERASE, 47507986669568, 47507986669568,
-STORE, 47507986669568, 47507988762623,
-STORE, 47507988762624, 47507988779007,
-STORE, 47507988770816, 47507988779007,
-STORE, 47507988762624, 47507988770815,
-ERASE, 47507988762624, 47507988762624,
-STORE, 47507988762624, 47507988770815,
-ERASE, 47507988770816, 47507988770816,
-STORE, 47507988770816, 47507988779007,
-STORE, 47507988779008, 47507988914175,
-ERASE, 47507988779008, 47507988779008,
-STORE, 47507988779008, 47507988803583,
-STORE, 47507988803584, 47507988914175,
-STORE, 47507988865024, 47507988914175,
-STORE, 47507988803584, 47507988865023,
-ERASE, 47507988803584, 47507988803584,
-STORE, 47507988803584, 47507988865023,
-STORE, 47507988889600, 47507988914175,
-STORE, 47507988865024, 47507988889599,
-ERASE, 47507988865024, 47507988865024,
-STORE, 47507988865024, 47507988914175,
-ERASE, 47507988865024, 47507988865024,
-STORE, 47507988865024, 47507988889599,
-STORE, 47507988889600, 47507988914175,
-STORE, 47507988897792, 47507988914175,
-STORE, 47507988889600, 47507988897791,
-ERASE, 47507988889600, 47507988889600,
-STORE, 47507988889600, 47507988897791,
-ERASE, 47507988897792, 47507988897792,
-STORE, 47507988897792, 47507988914175,
-STORE, 47507988897792, 47507988922367,
-STORE, 47507988922368, 47507989086207,
-ERASE, 47507988922368, 47507988922368,
-STORE, 47507988922368, 47507988934655,
-STORE, 47507988934656, 47507989086207,
-STORE, 47507989032960, 47507989086207,
-STORE, 47507988934656, 47507989032959,
-ERASE, 47507988934656, 47507988934656,
-STORE, 47507988934656, 47507989032959,
-STORE, 47507989078016, 47507989086207,
-STORE, 47507989032960, 47507989078015,
-ERASE, 47507989032960, 47507989032960,
-STORE, 47507989032960, 47507989086207,
-ERASE, 47507989032960, 47507989032960,
-STORE, 47507989032960, 47507989078015,
-STORE, 47507989078016, 47507989086207,
-ERASE, 47507989078016, 47507989078016,
-STORE, 47507989078016, 47507989086207,
-STORE, 47507989086208, 47507989684223,
-STORE, 47507989204992, 47507989684223,
-STORE, 47507989086208, 47507989204991,
-ERASE, 47507989204992, 47507989204992,
-STORE, 47507989204992, 47507989630975,
-STORE, 47507989630976, 47507989684223,
-STORE, 47507989520384, 47507989630975,
-STORE, 47507989204992, 47507989520383,
-ERASE, 47507989204992, 47507989204992,
-STORE, 47507989204992, 47507989520383,
-STORE, 47507989626880, 47507989630975,
-STORE, 47507989520384, 47507989626879,
-ERASE, 47507989520384, 47507989520384,
-STORE, 47507989520384, 47507989626879,
-ERASE, 47507989630976, 47507989630976,
-STORE, 47507989630976, 47507989684223,
-STORE, 47507989684224, 47507992735743,
-STORE, 47507990228992, 47507992735743,
-STORE, 47507989684224, 47507990228991,
-ERASE, 47507990228992, 47507990228992,
-STORE, 47507990228992, 47507992514559,
-STORE, 47507992514560, 47507992735743,
-STORE, 47507991924736, 47507992514559,
-STORE, 47507990228992, 47507991924735,
-ERASE, 47507990228992, 47507990228992,
-STORE, 47507990228992, 47507991924735,
-STORE, 47507992510464, 47507992514559,
-STORE, 47507991924736, 47507992510463,
-ERASE, 47507991924736, 47507991924736,
-STORE, 47507991924736, 47507992510463,
-STORE, 47507992719360, 47507992735743,
-STORE, 47507992514560, 47507992719359,
-ERASE, 47507992514560, 47507992514560,
-STORE, 47507992514560, 47507992719359,
-ERASE, 47507992719360, 47507992719360,
-STORE, 47507992719360, 47507992735743,
-STORE, 47507992735744, 47507992768511,
-ERASE, 47507992735744, 47507992735744,
-STORE, 47507992735744, 47507992743935,
-STORE, 47507992743936, 47507992768511,
-STORE, 47507992756224, 47507992768511,
-STORE, 47507992743936, 47507992756223,
-ERASE, 47507992743936, 47507992743936,
-STORE, 47507992743936, 47507992756223,
-STORE, 47507992760320, 47507992768511,
-STORE, 47507992756224, 47507992760319,
-ERASE, 47507992756224, 47507992756224,
-STORE, 47507992756224, 47507992768511,
-ERASE, 47507992756224, 47507992756224,
-STORE, 47507992756224, 47507992760319,
-STORE, 47507992760320, 47507992768511,
-ERASE, 47507992760320, 47507992760320,
-STORE, 47507992760320, 47507992768511,
-STORE, 47507992768512, 47507992805375,
-ERASE, 47507992768512, 47507992768512,
-STORE, 47507992768512, 47507992776703,
-STORE, 47507992776704, 47507992805375,
-STORE, 47507992793088, 47507992805375,
-STORE, 47507992776704, 47507992793087,
-ERASE, 47507992776704, 47507992776704,
-STORE, 47507992776704, 47507992793087,
-STORE, 47507992797184, 47507992805375,
-STORE, 47507992793088, 47507992797183,
-ERASE, 47507992793088, 47507992793088,
-STORE, 47507992793088, 47507992805375,
-ERASE, 47507992793088, 47507992793088,
-STORE, 47507992793088, 47507992797183,
-STORE, 47507992797184, 47507992805375,
-ERASE, 47507992797184, 47507992797184,
-STORE, 47507992797184, 47507992805375,
-STORE, 47507992805376, 47507993280511,
-ERASE, 47507992805376, 47507992805376,
-STORE, 47507992805376, 47507992813567,
-STORE, 47507992813568, 47507993280511,
-STORE, 47507993149440, 47507993280511,
-STORE, 47507992813568, 47507993149439,
-ERASE, 47507992813568, 47507992813568,
-STORE, 47507992813568, 47507993149439,
-STORE, 47507993272320, 47507993280511,
-STORE, 47507993149440, 47507993272319,
-ERASE, 47507993149440, 47507993149440,
-STORE, 47507993149440, 47507993280511,
-ERASE, 47507993149440, 47507993149440,
-STORE, 47507993149440, 47507993272319,
-STORE, 47507993272320, 47507993280511,
-ERASE, 47507993272320, 47507993272320,
-STORE, 47507993272320, 47507993280511,
-STORE, 47507993280512, 47507993288703,
-STORE, 47507993288704, 47507993309183,
-ERASE, 47507993288704, 47507993288704,
-STORE, 47507993288704, 47507993292799,
-STORE, 47507993292800, 47507993309183,
-STORE, 47507993296896, 47507993309183,
-STORE, 47507993292800, 47507993296895,
-ERASE, 47507993292800, 47507993292800,
-STORE, 47507993292800, 47507993296895,
-STORE, 47507993300992, 47507993309183,
-STORE, 47507993296896, 47507993300991,
-ERASE, 47507993296896, 47507993296896,
-STORE, 47507993296896, 47507993309183,
-ERASE, 47507993296896, 47507993296896,
-STORE, 47507993296896, 47507993300991,
-STORE, 47507993300992, 47507993309183,
-ERASE, 47507993300992, 47507993300992,
-STORE, 47507993300992, 47507993309183,
-STORE, 47507993309184, 47507993317375,
-ERASE, 47507985973248, 47507985973248,
-STORE, 47507985973248, 47507985989631,
-STORE, 47507985989632, 47507985997823,
-ERASE, 47507993300992, 47507993300992,
-STORE, 47507993300992, 47507993305087,
-STORE, 47507993305088, 47507993309183,
-ERASE, 47507988889600, 47507988889600,
-STORE, 47507988889600, 47507988893695,
-STORE, 47507988893696, 47507988897791,
-ERASE, 47507993272320, 47507993272320,
-STORE, 47507993272320, 47507993276415,
-STORE, 47507993276416, 47507993280511,
-ERASE, 47507992797184, 47507992797184,
-STORE, 47507992797184, 47507992801279,
-STORE, 47507992801280, 47507992805375,
-ERASE, 47507992760320, 47507992760320,
-STORE, 47507992760320, 47507992764415,
-STORE, 47507992764416, 47507992768511,
-ERASE, 47507992514560, 47507992514560,
-STORE, 47507992514560, 47507992711167,
-STORE, 47507992711168, 47507992719359,
-ERASE, 47507989630976, 47507989630976,
-STORE, 47507989630976, 47507989667839,
-STORE, 47507989667840, 47507989684223,
-ERASE, 47507989078016, 47507989078016,
-STORE, 47507989078016, 47507989082111,
-STORE, 47507989082112, 47507989086207,
-ERASE, 47507988762624, 47507988762624,
-STORE, 47507988762624, 47507988766719,
-STORE, 47507988766720, 47507988770815,
-ERASE, 47507986493440, 47507986493440,
-STORE, 47507986493440, 47507986513919,
-STORE, 47507986513920, 47507986518015,
-ERASE, 47507986161664, 47507986161664,
-STORE, 47507986161664, 47507986165759,
-STORE, 47507986165760, 47507986169855,
-ERASE, 47507986116608, 47507986116608,
-STORE, 47507986116608, 47507986120703,
-STORE, 47507986120704, 47507986124799,
-ERASE, 94386579570688, 94386579570688,
-STORE, 94386579570688, 94386579693567,
-STORE, 94386579693568, 94386579697663,
-ERASE, 140124810997760, 140124810997760,
-STORE, 140124810997760, 140124811001855,
-STORE, 140124811001856, 140124811005951,
-ERASE, 47507984158720, 47507984158720,
-STORE, 94386583982080, 94386584117247,
-STORE, 94386583982080, 94386584256511,
-ERASE, 94386583982080, 94386583982080,
-STORE, 94386583982080, 94386584223743,
-STORE, 94386584223744, 94386584256511,
-ERASE, 94386584223744, 94386584223744,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733763395584, 140737488351231,
-ERASE, 140733763395584, 140733763395584,
-STORE, 140733763395584, 140733763399679,
-STORE, 94011546472448, 94011547152383,
-ERASE, 94011546472448, 94011546472448,
-STORE, 94011546472448, 94011546537983,
-STORE, 94011546537984, 94011547152383,
-ERASE, 94011546537984, 94011546537984,
-STORE, 94011546537984, 94011546886143,
-STORE, 94011546886144, 94011547025407,
-STORE, 94011547025408, 94011547152383,
-STORE, 139757597949952, 139757598121983,
-ERASE, 139757597949952, 139757597949952,
-STORE, 139757597949952, 139757597954047,
-STORE, 139757597954048, 139757598121983,
-ERASE, 139757597954048, 139757597954048,
-STORE, 139757597954048, 139757598076927,
-STORE, 139757598076928, 139757598109695,
-STORE, 139757598109696, 139757598117887,
-STORE, 139757598117888, 139757598121983,
-STORE, 140733763596288, 140733763600383,
-STORE, 140733763584000, 140733763596287,
-STORE, 47875197046784, 47875197054975,
-STORE, 47875197054976, 47875197063167,
-STORE, 47875197063168, 47875198902271,
-STORE, 47875197202432, 47875198902271,
-STORE, 47875197063168, 47875197202431,
-ERASE, 47875197202432, 47875197202432,
-STORE, 47875197202432, 47875198861311,
-STORE, 47875198861312, 47875198902271,
-STORE, 47875198545920, 47875198861311,
-STORE, 47875197202432, 47875198545919,
-ERASE, 47875197202432, 47875197202432,
-STORE, 47875197202432, 47875198545919,
-STORE, 47875198857216, 47875198861311,
-STORE, 47875198545920, 47875198857215,
-ERASE, 47875198545920, 47875198545920,
-STORE, 47875198545920, 47875198857215,
-STORE, 47875198885888, 47875198902271,
-STORE, 47875198861312, 47875198885887,
-ERASE, 47875198861312, 47875198861312,
-STORE, 47875198861312, 47875198885887,
-ERASE, 47875198885888, 47875198885888,
-STORE, 47875198885888, 47875198902271,
-STORE, 47875198902272, 47875199012863,
-STORE, 47875198918656, 47875199012863,
-STORE, 47875198902272, 47875198918655,
-ERASE, 47875198918656, 47875198918656,
-STORE, 47875198918656, 47875199004671,
-STORE, 47875199004672, 47875199012863,
-STORE, 47875198980096, 47875199004671,
-STORE, 47875198918656, 47875198980095,
-ERASE, 47875198918656, 47875198918656,
-STORE, 47875198918656, 47875198980095,
-STORE, 47875199000576, 47875199004671,
-STORE, 47875198980096, 47875199000575,
-ERASE, 47875198980096, 47875198980096,
-STORE, 47875198980096, 47875199000575,
-ERASE, 47875199004672, 47875199004672,
-STORE, 47875199004672, 47875199012863,
-STORE, 47875199012864, 47875199057919,
-ERASE, 47875199012864, 47875199012864,
-STORE, 47875199012864, 47875199021055,
-STORE, 47875199021056, 47875199057919,
-STORE, 47875199041536, 47875199057919,
-STORE, 47875199021056, 47875199041535,
-ERASE, 47875199021056, 47875199021056,
-STORE, 47875199021056, 47875199041535,
-STORE, 47875199049728, 47875199057919,
-STORE, 47875199041536, 47875199049727,
-ERASE, 47875199041536, 47875199041536,
-STORE, 47875199041536, 47875199057919,
-ERASE, 47875199041536, 47875199041536,
-STORE, 47875199041536, 47875199049727,
-STORE, 47875199049728, 47875199057919,
-ERASE, 47875199049728, 47875199049728,
-STORE, 47875199049728, 47875199057919,
-STORE, 47875199057920, 47875199406079,
-STORE, 47875199098880, 47875199406079,
-STORE, 47875199057920, 47875199098879,
-ERASE, 47875199098880, 47875199098880,
-STORE, 47875199098880, 47875199381503,
-STORE, 47875199381504, 47875199406079,
-STORE, 47875199311872, 47875199381503,
-STORE, 47875199098880, 47875199311871,
-ERASE, 47875199098880, 47875199098880,
-STORE, 47875199098880, 47875199311871,
-STORE, 47875199377408, 47875199381503,
-STORE, 47875199311872, 47875199377407,
-ERASE, 47875199311872, 47875199311872,
-STORE, 47875199311872, 47875199377407,
-ERASE, 47875199381504, 47875199381504,
-STORE, 47875199381504, 47875199406079,
-STORE, 47875199406080, 47875201667071,
-STORE, 47875199557632, 47875201667071,
-STORE, 47875199406080, 47875199557631,
-ERASE, 47875199557632, 47875199557632,
-STORE, 47875199557632, 47875201650687,
-STORE, 47875201650688, 47875201667071,
-STORE, 47875201658880, 47875201667071,
-STORE, 47875201650688, 47875201658879,
-ERASE, 47875201650688, 47875201650688,
-STORE, 47875201650688, 47875201658879,
-ERASE, 47875201658880, 47875201658880,
-STORE, 47875201658880, 47875201667071,
-STORE, 47875201667072, 47875201802239,
-ERASE, 47875201667072, 47875201667072,
-STORE, 47875201667072, 47875201691647,
-STORE, 47875201691648, 47875201802239,
-STORE, 47875201753088, 47875201802239,
-STORE, 47875201691648, 47875201753087,
-ERASE, 47875201691648, 47875201691648,
-STORE, 47875201691648, 47875201753087,
-STORE, 47875201777664, 47875201802239,
-STORE, 47875201753088, 47875201777663,
-ERASE, 47875201753088, 47875201753088,
-STORE, 47875201753088, 47875201802239,
-ERASE, 47875201753088, 47875201753088,
-STORE, 47875201753088, 47875201777663,
-STORE, 47875201777664, 47875201802239,
-STORE, 47875201785856, 47875201802239,
-STORE, 47875201777664, 47875201785855,
-ERASE, 47875201777664, 47875201777664,
-STORE, 47875201777664, 47875201785855,
-ERASE, 47875201785856, 47875201785856,
-STORE, 47875201785856, 47875201802239,
-STORE, 47875201785856, 47875201810431,
-STORE, 47875201810432, 47875201974271,
-ERASE, 47875201810432, 47875201810432,
-STORE, 47875201810432, 47875201822719,
-STORE, 47875201822720, 47875201974271,
-STORE, 47875201921024, 47875201974271,
-STORE, 47875201822720, 47875201921023,
-ERASE, 47875201822720, 47875201822720,
-STORE, 47875201822720, 47875201921023,
-STORE, 47875201966080, 47875201974271,
-STORE, 47875201921024, 47875201966079,
-ERASE, 47875201921024, 47875201921024,
-STORE, 47875201921024, 47875201974271,
-ERASE, 47875201921024, 47875201921024,
-STORE, 47875201921024, 47875201966079,
-STORE, 47875201966080, 47875201974271,
-ERASE, 47875201966080, 47875201966080,
-STORE, 47875201966080, 47875201974271,
-STORE, 47875201974272, 47875202572287,
-STORE, 47875202093056, 47875202572287,
-STORE, 47875201974272, 47875202093055,
-ERASE, 47875202093056, 47875202093056,
-STORE, 47875202093056, 47875202519039,
-STORE, 47875202519040, 47875202572287,
-STORE, 47875202408448, 47875202519039,
-STORE, 47875202093056, 47875202408447,
-ERASE, 47875202093056, 47875202093056,
-STORE, 47875202093056, 47875202408447,
-STORE, 47875202514944, 47875202519039,
-STORE, 47875202408448, 47875202514943,
-ERASE, 47875202408448, 47875202408448,
-STORE, 47875202408448, 47875202514943,
-ERASE, 47875202519040, 47875202519040,
-STORE, 47875202519040, 47875202572287,
-STORE, 47875202572288, 47875205623807,
-STORE, 47875203117056, 47875205623807,
-STORE, 47875202572288, 47875203117055,
-ERASE, 47875203117056, 47875203117056,
-STORE, 47875203117056, 47875205402623,
-STORE, 47875205402624, 47875205623807,
-STORE, 47875204812800, 47875205402623,
-STORE, 47875203117056, 47875204812799,
-ERASE, 47875203117056, 47875203117056,
-STORE, 47875203117056, 47875204812799,
-STORE, 47875205398528, 47875205402623,
-STORE, 47875204812800, 47875205398527,
-ERASE, 47875204812800, 47875204812800,
-STORE, 47875204812800, 47875205398527,
-STORE, 47875205607424, 47875205623807,
-STORE, 47875205402624, 47875205607423,
-ERASE, 47875205402624, 47875205402624,
-STORE, 47875205402624, 47875205607423,
-ERASE, 47875205607424, 47875205607424,
-STORE, 47875205607424, 47875205623807,
-STORE, 47875205623808, 47875205656575,
-ERASE, 47875205623808, 47875205623808,
-STORE, 47875205623808, 47875205631999,
-STORE, 47875205632000, 47875205656575,
-STORE, 47875205644288, 47875205656575,
-STORE, 47875205632000, 47875205644287,
-ERASE, 47875205632000, 47875205632000,
-STORE, 47875205632000, 47875205644287,
-STORE, 47875205648384, 47875205656575,
-STORE, 47875205644288, 47875205648383,
-ERASE, 47875205644288, 47875205644288,
-STORE, 47875205644288, 47875205656575,
-ERASE, 47875205644288, 47875205644288,
-STORE, 47875205644288, 47875205648383,
-STORE, 47875205648384, 47875205656575,
-ERASE, 47875205648384, 47875205648384,
-STORE, 47875205648384, 47875205656575,
-STORE, 47875205656576, 47875205693439,
-ERASE, 47875205656576, 47875205656576,
-STORE, 47875205656576, 47875205664767,
-STORE, 47875205664768, 47875205693439,
-STORE, 47875205681152, 47875205693439,
-STORE, 47875205664768, 47875205681151,
-ERASE, 47875205664768, 47875205664768,
-STORE, 47875205664768, 47875205681151,
-STORE, 47875205685248, 47875205693439,
-STORE, 47875205681152, 47875205685247,
-ERASE, 47875205681152, 47875205681152,
-STORE, 47875205681152, 47875205693439,
-ERASE, 47875205681152, 47875205681152,
-STORE, 47875205681152, 47875205685247,
-STORE, 47875205685248, 47875205693439,
-ERASE, 47875205685248, 47875205685248,
-STORE, 47875205685248, 47875205693439,
-STORE, 47875205693440, 47875206168575,
-ERASE, 47875205693440, 47875205693440,
-STORE, 47875205693440, 47875205701631,
-STORE, 47875205701632, 47875206168575,
-STORE, 47875206037504, 47875206168575,
-STORE, 47875205701632, 47875206037503,
-ERASE, 47875205701632, 47875205701632,
-STORE, 47875205701632, 47875206037503,
-STORE, 47875206160384, 47875206168575,
-STORE, 47875206037504, 47875206160383,
-ERASE, 47875206037504, 47875206037504,
-STORE, 47875206037504, 47875206168575,
-ERASE, 47875206037504, 47875206037504,
-STORE, 47875206037504, 47875206160383,
-STORE, 47875206160384, 47875206168575,
-ERASE, 47875206160384, 47875206160384,
-STORE, 47875206160384, 47875206168575,
-STORE, 47875206168576, 47875206176767,
-STORE, 47875206176768, 47875206197247,
-ERASE, 47875206176768, 47875206176768,
-STORE, 47875206176768, 47875206180863,
-STORE, 47875206180864, 47875206197247,
-STORE, 47875206184960, 47875206197247,
-STORE, 47875206180864, 47875206184959,
-ERASE, 47875206180864, 47875206180864,
-STORE, 47875206180864, 47875206184959,
-STORE, 47875206189056, 47875206197247,
-STORE, 47875206184960, 47875206189055,
-ERASE, 47875206184960, 47875206184960,
-STORE, 47875206184960, 47875206197247,
-ERASE, 47875206184960, 47875206184960,
-STORE, 47875206184960, 47875206189055,
-STORE, 47875206189056, 47875206197247,
-ERASE, 47875206189056, 47875206189056,
-STORE, 47875206189056, 47875206197247,
-STORE, 47875206197248, 47875206205439,
-ERASE, 47875198861312, 47875198861312,
-STORE, 47875198861312, 47875198877695,
-STORE, 47875198877696, 47875198885887,
-ERASE, 47875206189056, 47875206189056,
-STORE, 47875206189056, 47875206193151,
-STORE, 47875206193152, 47875206197247,
-ERASE, 47875201777664, 47875201777664,
-STORE, 47875201777664, 47875201781759,
-STORE, 47875201781760, 47875201785855,
-ERASE, 47875206160384, 47875206160384,
-STORE, 47875206160384, 47875206164479,
-STORE, 47875206164480, 47875206168575,
-ERASE, 47875205685248, 47875205685248,
-STORE, 47875205685248, 47875205689343,
-STORE, 47875205689344, 47875205693439,
-ERASE, 47875205648384, 47875205648384,
-STORE, 47875205648384, 47875205652479,
-STORE, 47875205652480, 47875205656575,
-ERASE, 47875205402624, 47875205402624,
-STORE, 47875205402624, 47875205599231,
-STORE, 47875205599232, 47875205607423,
-ERASE, 47875202519040, 47875202519040,
-STORE, 47875202519040, 47875202555903,
-STORE, 47875202555904, 47875202572287,
-ERASE, 47875201966080, 47875201966080,
-STORE, 47875201966080, 47875201970175,
-STORE, 47875201970176, 47875201974271,
-ERASE, 47875201650688, 47875201650688,
-STORE, 47875201650688, 47875201654783,
-STORE, 47875201654784, 47875201658879,
-ERASE, 47875199381504, 47875199381504,
-STORE, 47875199381504, 47875199401983,
-STORE, 47875199401984, 47875199406079,
-ERASE, 47875199049728, 47875199049728,
-STORE, 47875199049728, 47875199053823,
-STORE, 47875199053824, 47875199057919,
-ERASE, 47875199004672, 47875199004672,
-STORE, 47875199004672, 47875199008767,
-STORE, 47875199008768, 47875199012863,
-ERASE, 94011547025408, 94011547025408,
-STORE, 94011547025408, 94011547148287,
-STORE, 94011547148288, 94011547152383,
-ERASE, 139757598109696, 139757598109696,
-STORE, 139757598109696, 139757598113791,
-STORE, 139757598113792, 139757598117887,
-ERASE, 47875197046784, 47875197046784,
-STORE, 94011557584896, 94011557720063,
-STORE, 94011557584896, 94011557855231,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557851135,
-STORE, 94011557851136, 94011557855231,
-ERASE, 94011557851136, 94011557851136,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557847039,
-STORE, 94011557847040, 94011557851135,
-ERASE, 94011557847040, 94011557847040,
-STORE, 94011557584896, 94011557982207,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557978111,
-STORE, 94011557978112, 94011557982207,
-ERASE, 94011557978112, 94011557978112,
-ERASE, 94011557584896, 94011557584896,
-STORE, 94011557584896, 94011557974015,
-STORE, 94011557974016, 94011557978111,
-ERASE, 94011557974016, 94011557974016,
-STORE, 140737488347136, 140737488351231,
-STORE, 140734130360320, 140737488351231,
-ERASE, 140734130360320, 140734130360320,
-STORE, 140734130360320, 140734130364415,
-STORE, 94641232105472, 94641232785407,
-ERASE, 94641232105472, 94641232105472,
-STORE, 94641232105472, 94641232171007,
-STORE, 94641232171008, 94641232785407,
-ERASE, 94641232171008, 94641232171008,
-STORE, 94641232171008, 94641232519167,
-STORE, 94641232519168, 94641232658431,
-STORE, 94641232658432, 94641232785407,
-STORE, 139726599516160, 139726599688191,
-ERASE, 139726599516160, 139726599516160,
-STORE, 139726599516160, 139726599520255,
-STORE, 139726599520256, 139726599688191,
-ERASE, 139726599520256, 139726599520256,
-STORE, 139726599520256, 139726599643135,
-STORE, 139726599643136, 139726599675903,
-STORE, 139726599675904, 139726599684095,
-STORE, 139726599684096, 139726599688191,
-STORE, 140734130446336, 140734130450431,
-STORE, 140734130434048, 140734130446335,
-STORE, 47906195480576, 47906195488767,
-STORE, 47906195488768, 47906195496959,
-STORE, 47906195496960, 47906197336063,
-STORE, 47906195636224, 47906197336063,
-STORE, 47906195496960, 47906195636223,
-ERASE, 47906195636224, 47906195636224,
-STORE, 47906195636224, 47906197295103,
-STORE, 47906197295104, 47906197336063,
-STORE, 47906196979712, 47906197295103,
-STORE, 47906195636224, 47906196979711,
-ERASE, 47906195636224, 47906195636224,
-STORE, 47906195636224, 47906196979711,
-STORE, 47906197291008, 47906197295103,
-STORE, 47906196979712, 47906197291007,
-ERASE, 47906196979712, 47906196979712,
-STORE, 47906196979712, 47906197291007,
-STORE, 47906197319680, 47906197336063,
-STORE, 47906197295104, 47906197319679,
-ERASE, 47906197295104, 47906197295104,
-STORE, 47906197295104, 47906197319679,
-ERASE, 47906197319680, 47906197319680,
-STORE, 47906197319680, 47906197336063,
-STORE, 47906197336064, 47906197446655,
-STORE, 47906197352448, 47906197446655,
-STORE, 47906197336064, 47906197352447,
-ERASE, 47906197352448, 47906197352448,
-STORE, 47906197352448, 47906197438463,
-STORE, 47906197438464, 47906197446655,
-STORE, 47906197413888, 47906197438463,
-STORE, 47906197352448, 47906197413887,
-ERASE, 47906197352448, 47906197352448,
-STORE, 47906197352448, 47906197413887,
-STORE, 47906197434368, 47906197438463,
-STORE, 47906197413888, 47906197434367,
-ERASE, 47906197413888, 47906197413888,
-STORE, 47906197413888, 47906197434367,
-ERASE, 47906197438464, 47906197438464,
-STORE, 47906197438464, 47906197446655,
-STORE, 47906197446656, 47906197491711,
-ERASE, 47906197446656, 47906197446656,
-STORE, 47906197446656, 47906197454847,
-STORE, 47906197454848, 47906197491711,
-STORE, 47906197475328, 47906197491711,
-STORE, 47906197454848, 47906197475327,
-ERASE, 47906197454848, 47906197454848,
-STORE, 47906197454848, 47906197475327,
-STORE, 47906197483520, 47906197491711,
-STORE, 47906197475328, 47906197483519,
-ERASE, 47906197475328, 47906197475328,
-STORE, 47906197475328, 47906197491711,
-ERASE, 47906197475328, 47906197475328,
-STORE, 47906197475328, 47906197483519,
-STORE, 47906197483520, 47906197491711,
-ERASE, 47906197483520, 47906197483520,
-STORE, 47906197483520, 47906197491711,
-STORE, 47906197491712, 47906197839871,
-STORE, 47906197532672, 47906197839871,
-STORE, 47906197491712, 47906197532671,
-ERASE, 47906197532672, 47906197532672,
-STORE, 47906197532672, 47906197815295,
-STORE, 47906197815296, 47906197839871,
-STORE, 47906197745664, 47906197815295,
-STORE, 47906197532672, 47906197745663,
-ERASE, 47906197532672, 47906197532672,
-STORE, 47906197532672, 47906197745663,
-STORE, 47906197811200, 47906197815295,
-STORE, 47906197745664, 47906197811199,
-ERASE, 47906197745664, 47906197745664,
-STORE, 47906197745664, 47906197811199,
-ERASE, 47906197815296, 47906197815296,
-STORE, 47906197815296, 47906197839871,
-STORE, 47906197839872, 47906200100863,
-STORE, 47906197991424, 47906200100863,
-STORE, 47906197839872, 47906197991423,
-ERASE, 47906197991424, 47906197991424,
-STORE, 47906197991424, 47906200084479,
-STORE, 47906200084480, 47906200100863,
-STORE, 47906200092672, 47906200100863,
-STORE, 47906200084480, 47906200092671,
-ERASE, 47906200084480, 47906200084480,
-STORE, 47906200084480, 47906200092671,
-ERASE, 47906200092672, 47906200092672,
-STORE, 47906200092672, 47906200100863,
-STORE, 47906200100864, 47906200236031,
-ERASE, 47906200100864, 47906200100864,
-STORE, 47906200100864, 47906200125439,
-STORE, 47906200125440, 47906200236031,
-STORE, 47906200186880, 47906200236031,
-STORE, 47906200125440, 47906200186879,
-ERASE, 47906200125440, 47906200125440,
-STORE, 47906200125440, 47906200186879,
-STORE, 47906200211456, 47906200236031,
-STORE, 47906200186880, 47906200211455,
-ERASE, 47906200186880, 47906200186880,
-STORE, 47906200186880, 47906200236031,
-ERASE, 47906200186880, 47906200186880,
-STORE, 47906200186880, 47906200211455,
-STORE, 47906200211456, 47906200236031,
-STORE, 47906200219648, 47906200236031,
-STORE, 47906200211456, 47906200219647,
-ERASE, 47906200211456, 47906200211456,
-STORE, 47906200211456, 47906200219647,
-ERASE, 47906200219648, 47906200219648,
-STORE, 47906200219648, 47906200236031,
-STORE, 47906200219648, 47906200244223,
-STORE, 47906200244224, 47906200408063,
-ERASE, 47906200244224, 47906200244224,
-STORE, 47906200244224, 47906200256511,
-STORE, 47906200256512, 47906200408063,
-STORE, 47906200354816, 47906200408063,
-STORE, 47906200256512, 47906200354815,
-ERASE, 47906200256512, 47906200256512,
-STORE, 47906200256512, 47906200354815,
-STORE, 47906200399872, 47906200408063,
-STORE, 47906200354816, 47906200399871,
-ERASE, 47906200354816, 47906200354816,
-STORE, 47906200354816, 47906200408063,
-ERASE, 47906200354816, 47906200354816,
-STORE, 47906200354816, 47906200399871,
-STORE, 47906200399872, 47906200408063,
-ERASE, 47906200399872, 47906200399872,
-STORE, 47906200399872, 47906200408063,
-STORE, 47906200408064, 47906201006079,
-STORE, 47906200526848, 47906201006079,
-STORE, 47906200408064, 47906200526847,
-ERASE, 47906200526848, 47906200526848,
-STORE, 47906200526848, 47906200952831,
-STORE, 47906200952832, 47906201006079,
-STORE, 47906200842240, 47906200952831,
-STORE, 47906200526848, 47906200842239,
-ERASE, 47906200526848, 47906200526848,
-STORE, 47906200526848, 47906200842239,
-STORE, 47906200948736, 47906200952831,
-STORE, 47906200842240, 47906200948735,
-ERASE, 47906200842240, 47906200842240,
-STORE, 47906200842240, 47906200948735,
-ERASE, 47906200952832, 47906200952832,
-STORE, 47906200952832, 47906201006079,
-STORE, 47906201006080, 47906204057599,
-STORE, 47906201550848, 47906204057599,
-STORE, 47906201006080, 47906201550847,
-ERASE, 47906201550848, 47906201550848,
-STORE, 47906201550848, 47906203836415,
-STORE, 47906203836416, 47906204057599,
-STORE, 47906203246592, 47906203836415,
-STORE, 47906201550848, 47906203246591,
-ERASE, 47906201550848, 47906201550848,
-STORE, 47906201550848, 47906203246591,
-STORE, 47906203832320, 47906203836415,
-STORE, 47906203246592, 47906203832319,
-ERASE, 47906203246592, 47906203246592,
-STORE, 47906203246592, 47906203832319,
-STORE, 47906204041216, 47906204057599,
-STORE, 47906203836416, 47906204041215,
-ERASE, 47906203836416, 47906203836416,
-STORE, 47906203836416, 47906204041215,
-ERASE, 47906204041216, 47906204041216,
-STORE, 47906204041216, 47906204057599,
-STORE, 47906204057600, 47906204090367,
-ERASE, 47906204057600, 47906204057600,
-STORE, 47906204057600, 47906204065791,
-STORE, 47906204065792, 47906204090367,
-STORE, 47906204078080, 47906204090367,
-STORE, 47906204065792, 47906204078079,
-ERASE, 47906204065792, 47906204065792,
-STORE, 47906204065792, 47906204078079,
-STORE, 47906204082176, 47906204090367,
-STORE, 47906204078080, 47906204082175,
-ERASE, 47906204078080, 47906204078080,
-STORE, 47906204078080, 47906204090367,
-ERASE, 47906204078080, 47906204078080,
-STORE, 47906204078080, 47906204082175,
-STORE, 47906204082176, 47906204090367,
-ERASE, 47906204082176, 47906204082176,
-STORE, 47906204082176, 47906204090367,
-STORE, 47906204090368, 47906204127231,
-ERASE, 47906204090368, 47906204090368,
-STORE, 47906204090368, 47906204098559,
-STORE, 47906204098560, 47906204127231,
-STORE, 47906204114944, 47906204127231,
-STORE, 47906204098560, 47906204114943,
-ERASE, 47906204098560, 47906204098560,
-STORE, 47906204098560, 47906204114943,
-STORE, 47906204119040, 47906204127231,
-STORE, 47906204114944, 47906204119039,
-ERASE, 47906204114944, 47906204114944,
-STORE, 47906204114944, 47906204127231,
-ERASE, 47906204114944, 47906204114944,
-STORE, 47906204114944, 47906204119039,
-STORE, 47906204119040, 47906204127231,
-ERASE, 47906204119040, 47906204119040,
-STORE, 47906204119040, 47906204127231,
-STORE, 47906204127232, 47906204602367,
-ERASE, 47906204127232, 47906204127232,
-STORE, 47906204127232, 47906204135423,
-STORE, 47906204135424, 47906204602367,
-STORE, 47906204471296, 47906204602367,
-STORE, 47906204135424, 47906204471295,
-ERASE, 47906204135424, 47906204135424,
-STORE, 47906204135424, 47906204471295,
-STORE, 47906204594176, 47906204602367,
-STORE, 47906204471296, 47906204594175,
-ERASE, 47906204471296, 47906204471296,
-STORE, 47906204471296, 47906204602367,
-ERASE, 47906204471296, 47906204471296,
-STORE, 47906204471296, 47906204594175,
-STORE, 47906204594176, 47906204602367,
-ERASE, 47906204594176, 47906204594176,
-STORE, 47906204594176, 47906204602367,
-STORE, 47906204602368, 47906204610559,
-STORE, 47906204610560, 47906204631039,
-ERASE, 47906204610560, 47906204610560,
-STORE, 47906204610560, 47906204614655,
-STORE, 47906204614656, 47906204631039,
-STORE, 47906204618752, 47906204631039,
-STORE, 47906204614656, 47906204618751,
-ERASE, 47906204614656, 47906204614656,
-STORE, 47906204614656, 47906204618751,
-STORE, 47906204622848, 47906204631039,
-STORE, 47906204618752, 47906204622847,
-ERASE, 47906204618752, 47906204618752,
-STORE, 47906204618752, 47906204631039,
-ERASE, 47906204618752, 47906204618752,
-STORE, 47906204618752, 47906204622847,
-STORE, 47906204622848, 47906204631039,
-ERASE, 47906204622848, 47906204622848,
-STORE, 47906204622848, 47906204631039,
-STORE, 47906204631040, 47906204639231,
-ERASE, 47906197295104, 47906197295104,
-STORE, 47906197295104, 47906197311487,
-STORE, 47906197311488, 47906197319679,
-ERASE, 47906204622848, 47906204622848,
-STORE, 47906204622848, 47906204626943,
-STORE, 47906204626944, 47906204631039,
-ERASE, 47906200211456, 47906200211456,
-STORE, 47906200211456, 47906200215551,
-STORE, 47906200215552, 47906200219647,
-ERASE, 47906204594176, 47906204594176,
-STORE, 47906204594176, 47906204598271,
-STORE, 47906204598272, 47906204602367,
-ERASE, 47906204119040, 47906204119040,
-STORE, 47906204119040, 47906204123135,
-STORE, 47906204123136, 47906204127231,
-ERASE, 47906204082176, 47906204082176,
-STORE, 47906204082176, 47906204086271,
-STORE, 47906204086272, 47906204090367,
-ERASE, 47906203836416, 47906203836416,
-STORE, 47906203836416, 47906204033023,
-STORE, 47906204033024, 47906204041215,
-ERASE, 47906200952832, 47906200952832,
-STORE, 47906200952832, 47906200989695,
-STORE, 47906200989696, 47906201006079,
-ERASE, 47906200399872, 47906200399872,
-STORE, 47906200399872, 47906200403967,
-STORE, 47906200403968, 47906200408063,
-ERASE, 47906200084480, 47906200084480,
-STORE, 47906200084480, 47906200088575,
-STORE, 47906200088576, 47906200092671,
-ERASE, 47906197815296, 47906197815296,
-STORE, 47906197815296, 47906197835775,
-STORE, 47906197835776, 47906197839871,
-ERASE, 47906197483520, 47906197483520,
-STORE, 47906197483520, 47906197487615,
-STORE, 47906197487616, 47906197491711,
-ERASE, 47906197438464, 47906197438464,
-STORE, 47906197438464, 47906197442559,
-STORE, 47906197442560, 47906197446655,
-ERASE, 94641232658432, 94641232658432,
-STORE, 94641232658432, 94641232781311,
-STORE, 94641232781312, 94641232785407,
-ERASE, 139726599675904, 139726599675904,
-STORE, 139726599675904, 139726599679999,
-STORE, 139726599680000, 139726599684095,
-ERASE, 47906195480576, 47906195480576,
-STORE, 94641242615808, 94641242750975,
- };
- unsigned long set11[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140732658499584, 140737488351231,
-ERASE, 140732658499584, 140732658499584,
-STORE, 140732658499584, 140732658503679,
-STORE, 94029856579584, 94029856751615,
-ERASE, 94029856579584, 94029856579584,
-STORE, 94029856579584, 94029856595967,
-STORE, 94029856595968, 94029856751615,
-ERASE, 94029856595968, 94029856595968,
-STORE, 94029856595968, 94029856698367,
-STORE, 94029856698368, 94029856739327,
-STORE, 94029856739328, 94029856751615,
-STORE, 140014592573440, 140014592745471,
-ERASE, 140014592573440, 140014592573440,
-STORE, 140014592573440, 140014592577535,
-STORE, 140014592577536, 140014592745471,
-ERASE, 140014592577536, 140014592577536,
-STORE, 140014592577536, 140014592700415,
-STORE, 140014592700416, 140014592733183,
-STORE, 140014592733184, 140014592741375,
-STORE, 140014592741376, 140014592745471,
-STORE, 140732658565120, 140732658569215,
-STORE, 140732658552832, 140732658565119,
- };
-
- unsigned long set12[] = { /* contains 12 values. */
-STORE, 140737488347136, 140737488351231,
-STORE, 140732658499584, 140737488351231,
-ERASE, 140732658499584, 140732658499584,
-STORE, 140732658499584, 140732658503679,
-STORE, 94029856579584, 94029856751615,
-ERASE, 94029856579584, 94029856579584,
-STORE, 94029856579584, 94029856595967,
-STORE, 94029856595968, 94029856751615,
-ERASE, 94029856595968, 94029856595968,
-STORE, 94029856595968, 94029856698367,
-STORE, 94029856698368, 94029856739327,
-STORE, 94029856739328, 94029856751615,
-STORE, 140014592573440, 140014592745471,
-ERASE, 140014592573440, 140014592573440,
-STORE, 140014592573440, 140014592577535,
-STORE, 140014592577536, 140014592745471,
-ERASE, 140014592577536, 140014592577536,
-STORE, 140014592577536, 140014592700415,
-STORE, 140014592700416, 140014592733183,
-STORE, 140014592733184, 140014592741375,
-STORE, 140014592741376, 140014592745471,
-STORE, 140732658565120, 140732658569215,
-STORE, 140732658552832, 140732658565119,
-STORE, 140014592741375, 140014592741375, /* contrived */
-STORE, 140014592733184, 140014592741376, /* creates first entry retry. */
- };
- unsigned long set13[] = {
-STORE, 140373516247040, 140373516251135,/*: ffffa2e7b0e10d80 */
-STORE, 140373516251136, 140373516255231,/*: ffffa2e7b1195d80 */
-STORE, 140373516255232, 140373516443647,/*: ffffa2e7b0e109c0 */
-STORE, 140373516443648, 140373516587007,/*: ffffa2e7b05fecc0 */
-STORE, 140373516963840, 140373518647295,/*: ffffa2e7bfbdcc00 */
-STORE, 140373518647296, 140373518663679,/*: ffffa2e7bf5d59c0 */
-STORE, 140373518663680, 140373518684159,/*: deleted (257) */
-STORE, 140373518680064, 140373518684159,/*: ffffa2e7b0e1cb40 */
-STORE, 140373518684160, 140373518688254,/*: ffffa2e7b05fec00 */
-STORE, 140373518688256, 140373518692351,/*: ffffa2e7bfbdcd80 */
-STORE, 140373518692352, 140373518696447,/*: ffffa2e7b0749e40 */
- };
- unsigned long set14[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140731667996672, 140737488351231,
-SNULL, 140731668000767, 140737488351231,
-STORE, 140731667996672, 140731668000767,
-STORE, 140731667865600, 140731668000767,
-STORE, 94077521272832, 94077521313791,
-SNULL, 94077521301503, 94077521313791,
-STORE, 94077521272832, 94077521301503,
-STORE, 94077521301504, 94077521313791,
-ERASE, 94077521301504, 94077521313791,
-STORE, 94077521305600, 94077521313791,
-STORE, 139826134630400, 139826136883199,
-SNULL, 139826134773759, 139826136883199,
-STORE, 139826134630400, 139826134773759,
-STORE, 139826134773760, 139826136883199,
-ERASE, 139826134773760, 139826136883199,
-STORE, 139826136870912, 139826136879103,
-STORE, 139826136879104, 139826136883199,
-STORE, 140731668013056, 140731668017151,
-STORE, 140731668000768, 140731668013055,
-STORE, 139826136862720, 139826136870911,
-STORE, 139826132406272, 139826134630399,
-SNULL, 139826134056959, 139826134630399,
-STORE, 139826132406272, 139826134056959,
-STORE, 139826134056960, 139826134630399,
-SNULL, 139826134056960, 139826134626303,
-STORE, 139826134626304, 139826134630399,
-STORE, 139826134056960, 139826134626303,
-ERASE, 139826134056960, 139826134626303,
-STORE, 139826134056960, 139826134626303,
-ERASE, 139826134626304, 139826134630399,
-STORE, 139826134626304, 139826134630399,
-STORE, 139826136842240, 139826136862719,
-STORE, 139826130022400, 139826132406271,
-SNULL, 139826130022400, 139826130288639,
-STORE, 139826130288640, 139826132406271,
-STORE, 139826130022400, 139826130288639,
-SNULL, 139826132381695, 139826132406271,
-STORE, 139826130288640, 139826132381695,
-STORE, 139826132381696, 139826132406271,
-SNULL, 139826132381696, 139826132402175,
-STORE, 139826132402176, 139826132406271,
-STORE, 139826132381696, 139826132402175,
-ERASE, 139826132381696, 139826132402175,
-STORE, 139826132381696, 139826132402175,
-ERASE, 139826132402176, 139826132406271,
-STORE, 139826132402176, 139826132406271,
-STORE, 139826127806464, 139826130022399,
-SNULL, 139826127806464, 139826127904767,
-STORE, 139826127904768, 139826130022399,
-STORE, 139826127806464, 139826127904767,
-SNULL, 139826129997823, 139826130022399,
-STORE, 139826127904768, 139826129997823,
-STORE, 139826129997824, 139826130022399,
-SNULL, 139826129997824, 139826130006015,
-STORE, 139826130006016, 139826130022399,
-STORE, 139826129997824, 139826130006015,
-ERASE, 139826129997824, 139826130006015,
-STORE, 139826129997824, 139826130006015,
-ERASE, 139826130006016, 139826130022399,
-STORE, 139826130006016, 139826130022399,
-STORE, 139826124009472, 139826127806463,
-SNULL, 139826124009472, 139826125668351,
-STORE, 139826125668352, 139826127806463,
-STORE, 139826124009472, 139826125668351,
-SNULL, 139826127765503, 139826127806463,
-STORE, 139826125668352, 139826127765503,
-STORE, 139826127765504, 139826127806463,
-SNULL, 139826127765504, 139826127790079,
-STORE, 139826127790080, 139826127806463,
-STORE, 139826127765504, 139826127790079,
-ERASE, 139826127765504, 139826127790079,
-STORE, 139826127765504, 139826127790079,
-ERASE, 139826127790080, 139826127806463,
-STORE, 139826127790080, 139826127806463,
-STORE, 139826121748480, 139826124009471,
-SNULL, 139826121748480, 139826121900031,
-STORE, 139826121900032, 139826124009471,
-STORE, 139826121748480, 139826121900031,
-SNULL, 139826123993087, 139826124009471,
-STORE, 139826121900032, 139826123993087,
-STORE, 139826123993088, 139826124009471,
-SNULL, 139826123993088, 139826124001279,
-STORE, 139826124001280, 139826124009471,
-STORE, 139826123993088, 139826124001279,
-ERASE, 139826123993088, 139826124001279,
-STORE, 139826123993088, 139826124001279,
-ERASE, 139826124001280, 139826124009471,
-STORE, 139826124001280, 139826124009471,
-STORE, 139826119626752, 139826121748479,
-SNULL, 139826119626752, 139826119643135,
-STORE, 139826119643136, 139826121748479,
-STORE, 139826119626752, 139826119643135,
-SNULL, 139826121740287, 139826121748479,
-STORE, 139826119643136, 139826121740287,
-STORE, 139826121740288, 139826121748479,
-ERASE, 139826121740288, 139826121748479,
-STORE, 139826121740288, 139826121748479,
-STORE, 139826136834048, 139826136842239,
-STORE, 139826117496832, 139826119626751,
-SNULL, 139826117496832, 139826117525503,
-STORE, 139826117525504, 139826119626751,
-STORE, 139826117496832, 139826117525503,
-SNULL, 139826119618559, 139826119626751,
-STORE, 139826117525504, 139826119618559,
-STORE, 139826119618560, 139826119626751,
-ERASE, 139826119618560, 139826119626751,
-STORE, 139826119618560, 139826119626751,
-STORE, 139826115244032, 139826117496831,
-SNULL, 139826115244032, 139826115395583,
-STORE, 139826115395584, 139826117496831,
-STORE, 139826115244032, 139826115395583,
-SNULL, 139826117488639, 139826117496831,
-STORE, 139826115395584, 139826117488639,
-STORE, 139826117488640, 139826117496831,
-ERASE, 139826117488640, 139826117496831,
-STORE, 139826117488640, 139826117496831,
-STORE, 139826113073152, 139826115244031,
-SNULL, 139826113073152, 139826113142783,
-STORE, 139826113142784, 139826115244031,
-STORE, 139826113073152, 139826113142783,
-SNULL, 139826115235839, 139826115244031,
-STORE, 139826113142784, 139826115235839,
-STORE, 139826115235840, 139826115244031,
-ERASE, 139826115235840, 139826115244031,
-STORE, 139826115235840, 139826115244031,
-STORE, 139826109861888, 139826113073151,
-SNULL, 139826109861888, 139826110939135,
-STORE, 139826110939136, 139826113073151,
-STORE, 139826109861888, 139826110939135,
-SNULL, 139826113036287, 139826113073151,
-STORE, 139826110939136, 139826113036287,
-STORE, 139826113036288, 139826113073151,
-ERASE, 139826113036288, 139826113073151,
-STORE, 139826113036288, 139826113073151,
-STORE, 139826107727872, 139826109861887,
-SNULL, 139826107727872, 139826107756543,
-STORE, 139826107756544, 139826109861887,
-STORE, 139826107727872, 139826107756543,
-SNULL, 139826109853695, 139826109861887,
-STORE, 139826107756544, 139826109853695,
-STORE, 139826109853696, 139826109861887,
-ERASE, 139826109853696, 139826109861887,
-STORE, 139826109853696, 139826109861887,
-STORE, 139826105417728, 139826107727871,
-SNULL, 139826105417728, 139826105622527,
-STORE, 139826105622528, 139826107727871,
-STORE, 139826105417728, 139826105622527,
-SNULL, 139826107719679, 139826107727871,
-STORE, 139826105622528, 139826107719679,
-STORE, 139826107719680, 139826107727871,
-ERASE, 139826107719680, 139826107727871,
-STORE, 139826107719680, 139826107727871,
-STORE, 139826136825856, 139826136842239,
-STORE, 139826103033856, 139826105417727,
-SNULL, 139826103033856, 139826103226367,
-STORE, 139826103226368, 139826105417727,
-STORE, 139826103033856, 139826103226367,
-SNULL, 139826105319423, 139826105417727,
-STORE, 139826103226368, 139826105319423,
-STORE, 139826105319424, 139826105417727,
-ERASE, 139826105319424, 139826105417727,
-STORE, 139826105319424, 139826105417727,
-STORE, 139826100916224, 139826103033855,
-SNULL, 139826100916224, 139826100932607,
-STORE, 139826100932608, 139826103033855,
-STORE, 139826100916224, 139826100932607,
-SNULL, 139826103025663, 139826103033855,
-STORE, 139826100932608, 139826103025663,
-STORE, 139826103025664, 139826103033855,
-ERASE, 139826103025664, 139826103033855,
-STORE, 139826103025664, 139826103033855,
-STORE, 139826098348032, 139826100916223,
-SNULL, 139826098348032, 139826098814975,
-STORE, 139826098814976, 139826100916223,
-STORE, 139826098348032, 139826098814975,
-SNULL, 139826100908031, 139826100916223,
-STORE, 139826098814976, 139826100908031,
-STORE, 139826100908032, 139826100916223,
-ERASE, 139826100908032, 139826100916223,
-STORE, 139826100908032, 139826100916223,
-STORE, 139826096234496, 139826098348031,
-SNULL, 139826096234496, 139826096246783,
-STORE, 139826096246784, 139826098348031,
-STORE, 139826096234496, 139826096246783,
-SNULL, 139826098339839, 139826098348031,
-STORE, 139826096246784, 139826098339839,
-STORE, 139826098339840, 139826098348031,
-ERASE, 139826098339840, 139826098348031,
-STORE, 139826098339840, 139826098348031,
-STORE, 139826094055424, 139826096234495,
-SNULL, 139826094055424, 139826094133247,
-STORE, 139826094133248, 139826096234495,
-STORE, 139826094055424, 139826094133247,
-SNULL, 139826096226303, 139826096234495,
-STORE, 139826094133248, 139826096226303,
-STORE, 139826096226304, 139826096234495,
-ERASE, 139826096226304, 139826096234495,
-STORE, 139826096226304, 139826096234495,
-STORE, 139826136817664, 139826136842239,
-STORE, 139826091937792, 139826094055423,
-SNULL, 139826091937792, 139826091954175,
-STORE, 139826091954176, 139826094055423,
-STORE, 139826091937792, 139826091954175,
-SNULL, 139826094047231, 139826094055423,
-STORE, 139826091954176, 139826094047231,
-STORE, 139826094047232, 139826094055423,
-ERASE, 139826094047232, 139826094055423,
-STORE, 139826094047232, 139826094055423,
-STORE, 139826136809472, 139826136842239,
-SNULL, 139826127781887, 139826127790079,
-STORE, 139826127765504, 139826127781887,
-STORE, 139826127781888, 139826127790079,
-SNULL, 139826094051327, 139826094055423,
-STORE, 139826094047232, 139826094051327,
-STORE, 139826094051328, 139826094055423,
-SNULL, 139826096230399, 139826096234495,
-STORE, 139826096226304, 139826096230399,
-STORE, 139826096230400, 139826096234495,
-SNULL, 139826098343935, 139826098348031,
-STORE, 139826098339840, 139826098343935,
-STORE, 139826098343936, 139826098348031,
-SNULL, 139826130001919, 139826130006015,
-STORE, 139826129997824, 139826130001919,
-STORE, 139826130001920, 139826130006015,
-SNULL, 139826100912127, 139826100916223,
-STORE, 139826100908032, 139826100912127,
-STORE, 139826100912128, 139826100916223,
-SNULL, 139826103029759, 139826103033855,
-STORE, 139826103025664, 139826103029759,
-STORE, 139826103029760, 139826103033855,
-SNULL, 139826105413631, 139826105417727,
-STORE, 139826105319424, 139826105413631,
-STORE, 139826105413632, 139826105417727,
-SNULL, 139826107723775, 139826107727871,
-STORE, 139826107719680, 139826107723775,
-STORE, 139826107723776, 139826107727871,
-SNULL, 139826109857791, 139826109861887,
-STORE, 139826109853696, 139826109857791,
-STORE, 139826109857792, 139826109861887,
-SNULL, 139826113044479, 139826113073151,
-STORE, 139826113036288, 139826113044479,
-STORE, 139826113044480, 139826113073151,
-SNULL, 139826115239935, 139826115244031,
-STORE, 139826115235840, 139826115239935,
-STORE, 139826115239936, 139826115244031,
-SNULL, 139826117492735, 139826117496831,
-STORE, 139826117488640, 139826117492735,
-STORE, 139826117492736, 139826117496831,
-SNULL, 139826119622655, 139826119626751,
-STORE, 139826119618560, 139826119622655,
-STORE, 139826119622656, 139826119626751,
-SNULL, 139826121744383, 139826121748479,
-STORE, 139826121740288, 139826121744383,
-STORE, 139826121744384, 139826121748479,
-SNULL, 139826123997183, 139826124001279,
-STORE, 139826123993088, 139826123997183,
-STORE, 139826123997184, 139826124001279,
-SNULL, 139826132398079, 139826132402175,
-STORE, 139826132381696, 139826132398079,
-STORE, 139826132398080, 139826132402175,
-SNULL, 139826134622207, 139826134626303,
-STORE, 139826134056960, 139826134622207,
-STORE, 139826134622208, 139826134626303,
-SNULL, 94077521309695, 94077521313791,
-STORE, 94077521305600, 94077521309695,
-STORE, 94077521309696, 94077521313791,
-SNULL, 139826136875007, 139826136879103,
-STORE, 139826136870912, 139826136875007,
-STORE, 139826136875008, 139826136879103,
-ERASE, 139826136842240, 139826136862719,
-STORE, 94077554049024, 94077554184191,
-STORE, 139826136543232, 139826136842239,
-STORE, 139826136276992, 139826136842239,
-STORE, 139826136010752, 139826136842239,
-STORE, 139826135744512, 139826136842239,
-SNULL, 139826136543231, 139826136842239,
-STORE, 139826135744512, 139826136543231,
-STORE, 139826136543232, 139826136842239,
-SNULL, 139826136543232, 139826136809471,
-STORE, 139826136809472, 139826136842239,
-STORE, 139826136543232, 139826136809471,
- };
- unsigned long set15[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140722061451264, 140737488351231,
-SNULL, 140722061455359, 140737488351231,
-STORE, 140722061451264, 140722061455359,
-STORE, 140722061320192, 140722061455359,
-STORE, 94728600248320, 94728600289279,
-SNULL, 94728600276991, 94728600289279,
-STORE, 94728600248320, 94728600276991,
-STORE, 94728600276992, 94728600289279,
-ERASE, 94728600276992, 94728600289279,
-STORE, 94728600281088, 94728600289279,
-STORE, 139906806779904, 139906809032703,
-SNULL, 139906806923263, 139906809032703,
-STORE, 139906806779904, 139906806923263,
-STORE, 139906806923264, 139906809032703,
-ERASE, 139906806923264, 139906809032703,
-STORE, 139906809020416, 139906809028607,
-STORE, 139906809028608, 139906809032703,
-STORE, 140722061692928, 140722061697023,
-STORE, 140722061680640, 140722061692927,
-STORE, 139906809012224, 139906809020415,
-STORE, 139906804555776, 139906806779903,
-SNULL, 139906806206463, 139906806779903,
-STORE, 139906804555776, 139906806206463,
-STORE, 139906806206464, 139906806779903,
-SNULL, 139906806206464, 139906806775807,
-STORE, 139906806775808, 139906806779903,
-STORE, 139906806206464, 139906806775807,
-ERASE, 139906806206464, 139906806775807,
-STORE, 139906806206464, 139906806775807,
-ERASE, 139906806775808, 139906806779903,
-STORE, 139906806775808, 139906806779903,
-STORE, 139906808991744, 139906809012223,
-STORE, 139906802171904, 139906804555775,
-SNULL, 139906802171904, 139906802438143,
-STORE, 139906802438144, 139906804555775,
-STORE, 139906802171904, 139906802438143,
-SNULL, 139906804531199, 139906804555775,
-STORE, 139906802438144, 139906804531199,
-STORE, 139906804531200, 139906804555775,
-SNULL, 139906804531200, 139906804551679,
-STORE, 139906804551680, 139906804555775,
-STORE, 139906804531200, 139906804551679,
-ERASE, 139906804531200, 139906804551679,
-STORE, 139906804531200, 139906804551679,
-ERASE, 139906804551680, 139906804555775,
-STORE, 139906804551680, 139906804555775,
-STORE, 139906799955968, 139906802171903,
-SNULL, 139906799955968, 139906800054271,
-STORE, 139906800054272, 139906802171903,
-STORE, 139906799955968, 139906800054271,
-SNULL, 139906802147327, 139906802171903,
-STORE, 139906800054272, 139906802147327,
-STORE, 139906802147328, 139906802171903,
-SNULL, 139906802147328, 139906802155519,
-STORE, 139906802155520, 139906802171903,
-STORE, 139906802147328, 139906802155519,
-ERASE, 139906802147328, 139906802155519,
-STORE, 139906802147328, 139906802155519,
-ERASE, 139906802155520, 139906802171903,
-STORE, 139906802155520, 139906802171903,
-STORE, 139906796158976, 139906799955967,
-SNULL, 139906796158976, 139906797817855,
-STORE, 139906797817856, 139906799955967,
-STORE, 139906796158976, 139906797817855,
-SNULL, 139906799915007, 139906799955967,
-STORE, 139906797817856, 139906799915007,
-STORE, 139906799915008, 139906799955967,
-SNULL, 139906799915008, 139906799939583,
-STORE, 139906799939584, 139906799955967,
-STORE, 139906799915008, 139906799939583,
-ERASE, 139906799915008, 139906799939583,
-STORE, 139906799915008, 139906799939583,
-ERASE, 139906799939584, 139906799955967,
-STORE, 139906799939584, 139906799955967,
-STORE, 139906793897984, 139906796158975,
-SNULL, 139906793897984, 139906794049535,
-STORE, 139906794049536, 139906796158975,
-STORE, 139906793897984, 139906794049535,
-SNULL, 139906796142591, 139906796158975,
-STORE, 139906794049536, 139906796142591,
-STORE, 139906796142592, 139906796158975,
-SNULL, 139906796142592, 139906796150783,
-STORE, 139906796150784, 139906796158975,
-STORE, 139906796142592, 139906796150783,
-ERASE, 139906796142592, 139906796150783,
-STORE, 139906796142592, 139906796150783,
-ERASE, 139906796150784, 139906796158975,
-STORE, 139906796150784, 139906796158975,
-STORE, 139906791776256, 139906793897983,
-SNULL, 139906791776256, 139906791792639,
-STORE, 139906791792640, 139906793897983,
-STORE, 139906791776256, 139906791792639,
-SNULL, 139906793889791, 139906793897983,
-STORE, 139906791792640, 139906793889791,
-STORE, 139906793889792, 139906793897983,
-ERASE, 139906793889792, 139906793897983,
-STORE, 139906793889792, 139906793897983,
-STORE, 139906808983552, 139906808991743,
-STORE, 139906789646336, 139906791776255,
-SNULL, 139906789646336, 139906789675007,
-STORE, 139906789675008, 139906791776255,
-STORE, 139906789646336, 139906789675007,
-SNULL, 139906791768063, 139906791776255,
-STORE, 139906789675008, 139906791768063,
-STORE, 139906791768064, 139906791776255,
-ERASE, 139906791768064, 139906791776255,
-STORE, 139906791768064, 139906791776255,
-STORE, 139906787393536, 139906789646335,
-SNULL, 139906787393536, 139906787545087,
-STORE, 139906787545088, 139906789646335,
-STORE, 139906787393536, 139906787545087,
-SNULL, 139906789638143, 139906789646335,
-STORE, 139906787545088, 139906789638143,
-STORE, 139906789638144, 139906789646335,
-ERASE, 139906789638144, 139906789646335,
-STORE, 139906789638144, 139906789646335,
-STORE, 139906785222656, 139906787393535,
-SNULL, 139906785222656, 139906785292287,
-STORE, 139906785292288, 139906787393535,
-STORE, 139906785222656, 139906785292287,
-SNULL, 139906787385343, 139906787393535,
-STORE, 139906785292288, 139906787385343,
-STORE, 139906787385344, 139906787393535,
-ERASE, 139906787385344, 139906787393535,
-STORE, 139906787385344, 139906787393535,
-STORE, 139906782011392, 139906785222655,
-SNULL, 139906782011392, 139906783088639,
-STORE, 139906783088640, 139906785222655,
-STORE, 139906782011392, 139906783088639,
-SNULL, 139906785185791, 139906785222655,
-STORE, 139906783088640, 139906785185791,
-STORE, 139906785185792, 139906785222655,
-ERASE, 139906785185792, 139906785222655,
-STORE, 139906785185792, 139906785222655,
-STORE, 139906779877376, 139906782011391,
-SNULL, 139906779877376, 139906779906047,
-STORE, 139906779906048, 139906782011391,
-STORE, 139906779877376, 139906779906047,
-SNULL, 139906782003199, 139906782011391,
-STORE, 139906779906048, 139906782003199,
-STORE, 139906782003200, 139906782011391,
-ERASE, 139906782003200, 139906782011391,
-STORE, 139906782003200, 139906782011391,
-STORE, 139906777567232, 139906779877375,
-SNULL, 139906777567232, 139906777772031,
-STORE, 139906777772032, 139906779877375,
-STORE, 139906777567232, 139906777772031,
-SNULL, 139906779869183, 139906779877375,
-STORE, 139906777772032, 139906779869183,
-STORE, 139906779869184, 139906779877375,
-ERASE, 139906779869184, 139906779877375,
-STORE, 139906779869184, 139906779877375,
-STORE, 139906808975360, 139906808991743,
-STORE, 139906775183360, 139906777567231,
-SNULL, 139906775183360, 139906775375871,
-STORE, 139906775375872, 139906777567231,
-STORE, 139906775183360, 139906775375871,
-SNULL, 139906777468927, 139906777567231,
-STORE, 139906775375872, 139906777468927,
-STORE, 139906777468928, 139906777567231,
-ERASE, 139906777468928, 139906777567231,
-STORE, 139906777468928, 139906777567231,
-STORE, 139906773065728, 139906775183359,
-SNULL, 139906773065728, 139906773082111,
-STORE, 139906773082112, 139906775183359,
-STORE, 139906773065728, 139906773082111,
-SNULL, 139906775175167, 139906775183359,
-STORE, 139906773082112, 139906775175167,
-STORE, 139906775175168, 139906775183359,
-ERASE, 139906775175168, 139906775183359,
-STORE, 139906775175168, 139906775183359,
-STORE, 139906770497536, 139906773065727,
-SNULL, 139906770497536, 139906770964479,
-STORE, 139906770964480, 139906773065727,
-STORE, 139906770497536, 139906770964479,
-SNULL, 139906773057535, 139906773065727,
-STORE, 139906770964480, 139906773057535,
-STORE, 139906773057536, 139906773065727,
-ERASE, 139906773057536, 139906773065727,
-STORE, 139906773057536, 139906773065727,
-STORE, 139906768384000, 139906770497535,
-SNULL, 139906768384000, 139906768396287,
-STORE, 139906768396288, 139906770497535,
-STORE, 139906768384000, 139906768396287,
-SNULL, 139906770489343, 139906770497535,
-STORE, 139906768396288, 139906770489343,
-STORE, 139906770489344, 139906770497535,
-ERASE, 139906770489344, 139906770497535,
-STORE, 139906770489344, 139906770497535,
-STORE, 139906766204928, 139906768383999,
-SNULL, 139906766204928, 139906766282751,
-STORE, 139906766282752, 139906768383999,
-STORE, 139906766204928, 139906766282751,
-SNULL, 139906768375807, 139906768383999,
-STORE, 139906766282752, 139906768375807,
-STORE, 139906768375808, 139906768383999,
-ERASE, 139906768375808, 139906768383999,
-STORE, 139906768375808, 139906768383999,
-STORE, 139906808967168, 139906808991743,
-STORE, 139906764087296, 139906766204927,
-SNULL, 139906764087296, 139906764103679,
-STORE, 139906764103680, 139906766204927,
-STORE, 139906764087296, 139906764103679,
-SNULL, 139906766196735, 139906766204927,
-STORE, 139906764103680, 139906766196735,
-STORE, 139906766196736, 139906766204927,
-ERASE, 139906766196736, 139906766204927,
-STORE, 139906766196736, 139906766204927,
-STORE, 139906808958976, 139906808991743,
-SNULL, 139906799931391, 139906799939583,
-STORE, 139906799915008, 139906799931391,
-STORE, 139906799931392, 139906799939583,
-SNULL, 139906766200831, 139906766204927,
-STORE, 139906766196736, 139906766200831,
-STORE, 139906766200832, 139906766204927,
-SNULL, 139906768379903, 139906768383999,
-STORE, 139906768375808, 139906768379903,
-STORE, 139906768379904, 139906768383999,
-SNULL, 139906770493439, 139906770497535,
-STORE, 139906770489344, 139906770493439,
-STORE, 139906770493440, 139906770497535,
-SNULL, 139906802151423, 139906802155519,
-STORE, 139906802147328, 139906802151423,
-STORE, 139906802151424, 139906802155519,
-SNULL, 139906773061631, 139906773065727,
-STORE, 139906773057536, 139906773061631,
-STORE, 139906773061632, 139906773065727,
-SNULL, 139906775179263, 139906775183359,
-STORE, 139906775175168, 139906775179263,
-STORE, 139906775179264, 139906775183359,
-SNULL, 139906777563135, 139906777567231,
-STORE, 139906777468928, 139906777563135,
-STORE, 139906777563136, 139906777567231,
-SNULL, 139906779873279, 139906779877375,
-STORE, 139906779869184, 139906779873279,
-STORE, 139906779873280, 139906779877375,
-SNULL, 139906782007295, 139906782011391,
-STORE, 139906782003200, 139906782007295,
-STORE, 139906782007296, 139906782011391,
-SNULL, 139906785193983, 139906785222655,
-STORE, 139906785185792, 139906785193983,
-STORE, 139906785193984, 139906785222655,
-SNULL, 139906787389439, 139906787393535,
-STORE, 139906787385344, 139906787389439,
-STORE, 139906787389440, 139906787393535,
-SNULL, 139906789642239, 139906789646335,
-STORE, 139906789638144, 139906789642239,
-STORE, 139906789642240, 139906789646335,
-SNULL, 139906791772159, 139906791776255,
-STORE, 139906791768064, 139906791772159,
-STORE, 139906791772160, 139906791776255,
-SNULL, 139906793893887, 139906793897983,
-STORE, 139906793889792, 139906793893887,
-STORE, 139906793893888, 139906793897983,
-SNULL, 139906796146687, 139906796150783,
-STORE, 139906796142592, 139906796146687,
-STORE, 139906796146688, 139906796150783,
-SNULL, 139906804547583, 139906804551679,
-STORE, 139906804531200, 139906804547583,
-STORE, 139906804547584, 139906804551679,
-SNULL, 139906806771711, 139906806775807,
-STORE, 139906806206464, 139906806771711,
-STORE, 139906806771712, 139906806775807,
-SNULL, 94728600285183, 94728600289279,
-STORE, 94728600281088, 94728600285183,
-STORE, 94728600285184, 94728600289279,
-SNULL, 139906809024511, 139906809028607,
-STORE, 139906809020416, 139906809024511,
-STORE, 139906809024512, 139906809028607,
-ERASE, 139906808991744, 139906809012223,
-STORE, 94728620138496, 94728620273663,
-STORE, 139906808692736, 139906808991743,
-STORE, 139906808426496, 139906808991743,
-STORE, 139906808160256, 139906808991743,
-STORE, 139906807894016, 139906808991743,
-SNULL, 139906808692735, 139906808991743,
-STORE, 139906807894016, 139906808692735,
-STORE, 139906808692736, 139906808991743,
-SNULL, 139906808692736, 139906808958975,
-STORE, 139906808958976, 139906808991743,
-STORE, 139906808692736, 139906808958975,
- };
-
- unsigned long set16[] = {
-STORE, 94174808662016, 94174809321471,
-STORE, 94174811414528, 94174811426815,
-STORE, 94174811426816, 94174811430911,
-STORE, 94174811430912, 94174811443199,
-STORE, 94174841700352, 94174841835519,
-STORE, 140173257838592, 140173259497471,
-STORE, 140173259497472, 140173261594623,
-STORE, 140173261594624, 140173261611007,
-STORE, 140173261611008, 140173261619199,
-STORE, 140173261619200, 140173261635583,
-STORE, 140173261635584, 140173261778943,
-STORE, 140173263863808, 140173263871999,
-STORE, 140173263876096, 140173263880191,
-STORE, 140173263880192, 140173263884287,
-STORE, 140173263884288, 140173263888383,
-STORE, 140729801007104, 140729801142271,
-STORE, 140729801617408, 140729801629695,
-STORE, 140729801629696, 140729801633791,
-STORE, 140737488347136, 140737488351231,
-STORE, 140728166858752, 140737488351231,
-SNULL, 140728166862847, 140737488351231,
-STORE, 140728166858752, 140728166862847,
-STORE, 140728166727680, 140728166862847,
-STORE, 93912949866496, 93912950337535,
-SNULL, 93912950288383, 93912950337535,
-STORE, 93912949866496, 93912950288383,
-STORE, 93912950288384, 93912950337535,
-ERASE, 93912950288384, 93912950337535,
-STORE, 93912950292480, 93912950337535,
-STORE, 139921863385088, 139921865637887,
-SNULL, 139921863528447, 139921865637887,
-STORE, 139921863385088, 139921863528447,
-STORE, 139921863528448, 139921865637887,
-ERASE, 139921863528448, 139921865637887,
-STORE, 139921865625600, 139921865633791,
-STORE, 139921865633792, 139921865637887,
-STORE, 140728167899136, 140728167903231,
-STORE, 140728167886848, 140728167899135,
-STORE, 139921865601024, 139921865625599,
-STORE, 139921865592832, 139921865601023,
-STORE, 139921861251072, 139921863385087,
-SNULL, 139921861251072, 139921861279743,
-STORE, 139921861279744, 139921863385087,
-STORE, 139921861251072, 139921861279743,
-SNULL, 139921863376895, 139921863385087,
-STORE, 139921861279744, 139921863376895,
-STORE, 139921863376896, 139921863385087,
-ERASE, 139921863376896, 139921863385087,
-STORE, 139921863376896, 139921863385087,
-STORE, 139921858867200, 139921861251071,
-SNULL, 139921858867200, 139921859133439,
-STORE, 139921859133440, 139921861251071,
-STORE, 139921858867200, 139921859133439,
-SNULL, 139921861226495, 139921861251071,
-STORE, 139921859133440, 139921861226495,
-STORE, 139921861226496, 139921861251071,
-SNULL, 139921861226496, 139921861246975,
-STORE, 139921861246976, 139921861251071,
-STORE, 139921861226496, 139921861246975,
-ERASE, 139921861226496, 139921861246975,
-STORE, 139921861226496, 139921861246975,
-ERASE, 139921861246976, 139921861251071,
-STORE, 139921861246976, 139921861251071,
-STORE, 139921856675840, 139921858867199,
-SNULL, 139921856675840, 139921856765951,
-STORE, 139921856765952, 139921858867199,
-STORE, 139921856675840, 139921856765951,
-SNULL, 139921858859007, 139921858867199,
-STORE, 139921856765952, 139921858859007,
-STORE, 139921858859008, 139921858867199,
-ERASE, 139921858859008, 139921858867199,
-STORE, 139921858859008, 139921858867199,
-STORE, 139921854414848, 139921856675839,
-SNULL, 139921854414848, 139921854566399,
-STORE, 139921854566400, 139921856675839,
-STORE, 139921854414848, 139921854566399,
-SNULL, 139921856659455, 139921856675839,
-STORE, 139921854566400, 139921856659455,
-STORE, 139921856659456, 139921856675839,
-SNULL, 139921856659456, 139921856667647,
-STORE, 139921856667648, 139921856675839,
-STORE, 139921856659456, 139921856667647,
-ERASE, 139921856659456, 139921856667647,
-STORE, 139921856659456, 139921856667647,
-ERASE, 139921856667648, 139921856675839,
-STORE, 139921856667648, 139921856675839,
-STORE, 139921852284928, 139921854414847,
-SNULL, 139921852284928, 139921852313599,
-STORE, 139921852313600, 139921854414847,
-STORE, 139921852284928, 139921852313599,
-SNULL, 139921854406655, 139921854414847,
-STORE, 139921852313600, 139921854406655,
-STORE, 139921854406656, 139921854414847,
-ERASE, 139921854406656, 139921854414847,
-STORE, 139921854406656, 139921854414847,
-STORE, 139921850068992, 139921852284927,
-SNULL, 139921850068992, 139921850167295,
-STORE, 139921850167296, 139921852284927,
-STORE, 139921850068992, 139921850167295,
-SNULL, 139921852260351, 139921852284927,
-STORE, 139921850167296, 139921852260351,
-STORE, 139921852260352, 139921852284927,
-SNULL, 139921852260352, 139921852268543,
-STORE, 139921852268544, 139921852284927,
-STORE, 139921852260352, 139921852268543,
-ERASE, 139921852260352, 139921852268543,
-STORE, 139921852260352, 139921852268543,
-ERASE, 139921852268544, 139921852284927,
-STORE, 139921852268544, 139921852284927,
-STORE, 139921865584640, 139921865601023,
-STORE, 139921846272000, 139921850068991,
-SNULL, 139921846272000, 139921847930879,
-STORE, 139921847930880, 139921850068991,
-STORE, 139921846272000, 139921847930879,
-SNULL, 139921850028031, 139921850068991,
-STORE, 139921847930880, 139921850028031,
-STORE, 139921850028032, 139921850068991,
-SNULL, 139921850028032, 139921850052607,
-STORE, 139921850052608, 139921850068991,
-STORE, 139921850028032, 139921850052607,
-ERASE, 139921850028032, 139921850052607,
-STORE, 139921850028032, 139921850052607,
-ERASE, 139921850052608, 139921850068991,
-STORE, 139921850052608, 139921850068991,
-STORE, 139921844154368, 139921846271999,
-SNULL, 139921844154368, 139921844170751,
-STORE, 139921844170752, 139921846271999,
-STORE, 139921844154368, 139921844170751,
-SNULL, 139921846263807, 139921846271999,
-STORE, 139921844170752, 139921846263807,
-STORE, 139921846263808, 139921846271999,
-ERASE, 139921846263808, 139921846271999,
-STORE, 139921846263808, 139921846271999,
-STORE, 139921842036736, 139921844154367,
-SNULL, 139921842036736, 139921842053119,
-STORE, 139921842053120, 139921844154367,
-STORE, 139921842036736, 139921842053119,
-SNULL, 139921844146175, 139921844154367,
-STORE, 139921842053120, 139921844146175,
-STORE, 139921844146176, 139921844154367,
-ERASE, 139921844146176, 139921844154367,
-STORE, 139921844146176, 139921844154367,
-STORE, 139921839468544, 139921842036735,
-SNULL, 139921839468544, 139921839935487,
-STORE, 139921839935488, 139921842036735,
-STORE, 139921839468544, 139921839935487,
-SNULL, 139921842028543, 139921842036735,
-STORE, 139921839935488, 139921842028543,
-STORE, 139921842028544, 139921842036735,
-ERASE, 139921842028544, 139921842036735,
-STORE, 139921842028544, 139921842036735,
-STORE, 139921837355008, 139921839468543,
-SNULL, 139921837355008, 139921837367295,
-STORE, 139921837367296, 139921839468543,
-STORE, 139921837355008, 139921837367295,
-SNULL, 139921839460351, 139921839468543,
-STORE, 139921837367296, 139921839460351,
-STORE, 139921839460352, 139921839468543,
-ERASE, 139921839460352, 139921839468543,
-STORE, 139921839460352, 139921839468543,
-STORE, 139921865576448, 139921865601023,
-STORE, 139921865564160, 139921865601023,
-SNULL, 139921850044415, 139921850052607,
-STORE, 139921850028032, 139921850044415,
-STORE, 139921850044416, 139921850052607,
-SNULL, 139921839464447, 139921839468543,
-STORE, 139921839460352, 139921839464447,
-STORE, 139921839464448, 139921839468543,
-SNULL, 139921852264447, 139921852268543,
-STORE, 139921852260352, 139921852264447,
-STORE, 139921852264448, 139921852268543,
-SNULL, 139921842032639, 139921842036735,
-STORE, 139921842028544, 139921842032639,
-STORE, 139921842032640, 139921842036735,
-SNULL, 139921844150271, 139921844154367,
-STORE, 139921844146176, 139921844150271,
-STORE, 139921844150272, 139921844154367,
-SNULL, 139921846267903, 139921846271999,
-STORE, 139921846263808, 139921846267903,
-STORE, 139921846267904, 139921846271999,
-SNULL, 139921854410751, 139921854414847,
-STORE, 139921854406656, 139921854410751,
-STORE, 139921854410752, 139921854414847,
-SNULL, 139921856663551, 139921856667647,
-STORE, 139921856659456, 139921856663551,
-STORE, 139921856663552, 139921856667647,
-SNULL, 139921858863103, 139921858867199,
-STORE, 139921858859008, 139921858863103,
-STORE, 139921858863104, 139921858867199,
-SNULL, 139921861242879, 139921861246975,
-STORE, 139921861226496, 139921861242879,
-STORE, 139921861242880, 139921861246975,
-SNULL, 139921863380991, 139921863385087,
-STORE, 139921863376896, 139921863380991,
-STORE, 139921863380992, 139921863385087,
-SNULL, 93912950333439, 93912950337535,
-STORE, 93912950292480, 93912950333439,
-STORE, 93912950333440, 93912950337535,
-SNULL, 139921865629695, 139921865633791,
-STORE, 139921865625600, 139921865629695,
-STORE, 139921865629696, 139921865633791,
-ERASE, 139921865601024, 139921865625599,
-STORE, 93912968110080, 93912968245247,
-STORE, 139921828913152, 139921837355007,
-STORE, 139921865621504, 139921865625599,
-STORE, 139921865617408, 139921865621503,
-STORE, 139921865613312, 139921865617407,
-STORE, 139921865547776, 139921865564159,
- };
-
- unsigned long set17[] = {
-STORE, 94397057224704, 94397057646591,
-STORE, 94397057650688, 94397057691647,
-STORE, 94397057691648, 94397057695743,
-STORE, 94397075271680, 94397075406847,
-STORE, 139953169051648, 139953169063935,
-STORE, 139953169063936, 139953171156991,
-STORE, 139953171156992, 139953171161087,
-STORE, 139953171161088, 139953171165183,
-STORE, 139953171165184, 139953171632127,
-STORE, 139953171632128, 139953173725183,
-STORE, 139953173725184, 139953173729279,
-STORE, 139953173729280, 139953173733375,
-STORE, 139953173733376, 139953173749759,
-STORE, 139953173749760, 139953175842815,
-STORE, 139953175842816, 139953175846911,
-STORE, 139953175846912, 139953175851007,
-STORE, 139953175851008, 139953175867391,
-STORE, 139953175867392, 139953177960447,
-STORE, 139953177960448, 139953177964543,
-STORE, 139953177964544, 139953177968639,
-STORE, 139953177968640, 139953179627519,
-STORE, 139953179627520, 139953181724671,
-STORE, 139953181724672, 139953181741055,
-STORE, 139953181741056, 139953181749247,
-STORE, 139953181749248, 139953181765631,
-STORE, 139953181765632, 139953181863935,
-STORE, 139953181863936, 139953183956991,
-STORE, 139953183956992, 139953183961087,
-STORE, 139953183961088, 139953183965183,
-STORE, 139953183965184, 139953183981567,
-STORE, 139953183981568, 139953184010239,
-STORE, 139953184010240, 139953186103295,
-STORE, 139953186103296, 139953186107391,
-STORE, 139953186107392, 139953186111487,
-STORE, 139953186111488, 139953186263039,
-STORE, 139953186263040, 139953188356095,
-STORE, 139953188356096, 139953188360191,
-STORE, 139953188360192, 139953188364287,
-STORE, 139953188364288, 139953188372479,
-STORE, 139953188372480, 139953188462591,
-STORE, 139953188462592, 139953190555647,
-STORE, 139953190555648, 139953190559743,
-STORE, 139953190559744, 139953190563839,
-STORE, 139953190563840, 139953190830079,
-STORE, 139953190830080, 139953192923135,
-STORE, 139953192923136, 139953192939519,
-STORE, 139953192939520, 139953192943615,
-STORE, 139953192943616, 139953192947711,
-STORE, 139953192947712, 139953192976383,
-STORE, 139953192976384, 139953195073535,
-STORE, 139953195073536, 139953195077631,
-STORE, 139953195077632, 139953195081727,
-STORE, 139953195081728, 139953195225087,
-STORE, 139953197281280, 139953197318143,
-STORE, 139953197322240, 139953197326335,
-STORE, 139953197326336, 139953197330431,
-STORE, 139953197330432, 139953197334527,
-STORE, 140720477511680, 140720477646847,
-STORE, 140720478302208, 140720478314495,
-STORE, 140720478314496, 140720478318591,
- };
- unsigned long set18[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140724953673728, 140737488351231,
-SNULL, 140724953677823, 140737488351231,
-STORE, 140724953673728, 140724953677823,
-STORE, 140724953542656, 140724953677823,
-STORE, 94675199266816, 94675199311871,
-SNULL, 94675199303679, 94675199311871,
-STORE, 94675199266816, 94675199303679,
-STORE, 94675199303680, 94675199311871,
-ERASE, 94675199303680, 94675199311871,
-STORE, 94675199303680, 94675199311871,
-STORE, 140222970605568, 140222972858367,
-SNULL, 140222970748927, 140222972858367,
-STORE, 140222970605568, 140222970748927,
-STORE, 140222970748928, 140222972858367,
-ERASE, 140222970748928, 140222972858367,
-STORE, 140222972846080, 140222972854271,
-STORE, 140222972854272, 140222972858367,
-STORE, 140724954365952, 140724954370047,
-STORE, 140724954353664, 140724954365951,
-STORE, 140222972841984, 140222972846079,
-STORE, 140222972833792, 140222972841983,
-STORE, 140222968475648, 140222970605567,
-SNULL, 140222968475648, 140222968504319,
-STORE, 140222968504320, 140222970605567,
-STORE, 140222968475648, 140222968504319,
-SNULL, 140222970597375, 140222970605567,
-STORE, 140222968504320, 140222970597375,
-STORE, 140222970597376, 140222970605567,
-ERASE, 140222970597376, 140222970605567,
-STORE, 140222970597376, 140222970605567,
- };
- unsigned long set19[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140725182459904, 140737488351231,
-SNULL, 140725182463999, 140737488351231,
-STORE, 140725182459904, 140725182463999,
-STORE, 140725182328832, 140725182463999,
-STORE, 94730166636544, 94730166763519,
-SNULL, 94730166747135, 94730166763519,
-STORE, 94730166636544, 94730166747135,
-STORE, 94730166747136, 94730166763519,
-ERASE, 94730166747136, 94730166763519,
-STORE, 94730166751232, 94730166763519,
-STORE, 140656834555904, 140656836808703,
-SNULL, 140656834699263, 140656836808703,
-STORE, 140656834555904, 140656834699263,
-STORE, 140656834699264, 140656836808703,
-ERASE, 140656834699264, 140656836808703,
-STORE, 140656836796416, 140656836804607,
-STORE, 140656836804608, 140656836808703,
-STORE, 140725183389696, 140725183393791,
-STORE, 140725183377408, 140725183389695,
-STORE, 140656836788224, 140656836796415,
-STORE, 140656832331776, 140656834555903,
-SNULL, 140656833982463, 140656834555903,
-STORE, 140656832331776, 140656833982463,
-STORE, 140656833982464, 140656834555903,
-SNULL, 140656833982464, 140656834551807,
-STORE, 140656834551808, 140656834555903,
-STORE, 140656833982464, 140656834551807,
-ERASE, 140656833982464, 140656834551807,
-STORE, 140656833982464, 140656834551807,
-ERASE, 140656834551808, 140656834555903,
-STORE, 140656834551808, 140656834555903,
-STORE, 140656836763648, 140656836788223,
-STORE, 140656830070784, 140656832331775,
-SNULL, 140656830070784, 140656830222335,
-STORE, 140656830222336, 140656832331775,
-STORE, 140656830070784, 140656830222335,
-SNULL, 140656832315391, 140656832331775,
-STORE, 140656830222336, 140656832315391,
-STORE, 140656832315392, 140656832331775,
-SNULL, 140656832315392, 140656832323583,
-STORE, 140656832323584, 140656832331775,
-STORE, 140656832315392, 140656832323583,
-ERASE, 140656832315392, 140656832323583,
-STORE, 140656832315392, 140656832323583,
-ERASE, 140656832323584, 140656832331775,
-STORE, 140656832323584, 140656832331775,
-STORE, 140656827940864, 140656830070783,
-SNULL, 140656827940864, 140656827969535,
-STORE, 140656827969536, 140656830070783,
-STORE, 140656827940864, 140656827969535,
-SNULL, 140656830062591, 140656830070783,
-STORE, 140656827969536, 140656830062591,
-STORE, 140656830062592, 140656830070783,
-ERASE, 140656830062592, 140656830070783,
-STORE, 140656830062592, 140656830070783,
-STORE, 140656825724928, 140656827940863,
-SNULL, 140656825724928, 140656825823231,
-STORE, 140656825823232, 140656827940863,
-STORE, 140656825724928, 140656825823231,
-SNULL, 140656827916287, 140656827940863,
-STORE, 140656825823232, 140656827916287,
-STORE, 140656827916288, 140656827940863,
-SNULL, 140656827916288, 140656827924479,
-STORE, 140656827924480, 140656827940863,
-STORE, 140656827916288, 140656827924479,
-ERASE, 140656827916288, 140656827924479,
-STORE, 140656827916288, 140656827924479,
-ERASE, 140656827924480, 140656827940863,
-STORE, 140656827924480, 140656827940863,
-STORE, 140656821927936, 140656825724927,
-SNULL, 140656821927936, 140656823586815,
-STORE, 140656823586816, 140656825724927,
-STORE, 140656821927936, 140656823586815,
-SNULL, 140656825683967, 140656825724927,
-STORE, 140656823586816, 140656825683967,
-STORE, 140656825683968, 140656825724927,
-SNULL, 140656825683968, 140656825708543,
-STORE, 140656825708544, 140656825724927,
-STORE, 140656825683968, 140656825708543,
-ERASE, 140656825683968, 140656825708543,
-STORE, 140656825683968, 140656825708543,
-ERASE, 140656825708544, 140656825724927,
-STORE, 140656825708544, 140656825724927,
-STORE, 140656819806208, 140656821927935,
-SNULL, 140656819806208, 140656819822591,
-STORE, 140656819822592, 140656821927935,
-STORE, 140656819806208, 140656819822591,
-SNULL, 140656821919743, 140656821927935,
-STORE, 140656819822592, 140656821919743,
-STORE, 140656821919744, 140656821927935,
-ERASE, 140656821919744, 140656821927935,
-STORE, 140656821919744, 140656821927935,
-STORE, 140656836755456, 140656836763647,
-STORE, 140656817553408, 140656819806207,
-SNULL, 140656817553408, 140656817704959,
-STORE, 140656817704960, 140656819806207,
-STORE, 140656817553408, 140656817704959,
-SNULL, 140656819798015, 140656819806207,
-STORE, 140656817704960, 140656819798015,
-STORE, 140656819798016, 140656819806207,
-ERASE, 140656819798016, 140656819806207,
-STORE, 140656819798016, 140656819806207,
-STORE, 140656815382528, 140656817553407,
-SNULL, 140656815382528, 140656815452159,
-STORE, 140656815452160, 140656817553407,
-STORE, 140656815382528, 140656815452159,
-SNULL, 140656817545215, 140656817553407,
-STORE, 140656815452160, 140656817545215,
-STORE, 140656817545216, 140656817553407,
-ERASE, 140656817545216, 140656817553407,
-STORE, 140656817545216, 140656817553407,
-STORE, 140656812171264, 140656815382527,
-SNULL, 140656812171264, 140656813248511,
-STORE, 140656813248512, 140656815382527,
-STORE, 140656812171264, 140656813248511,
-SNULL, 140656815345663, 140656815382527,
-STORE, 140656813248512, 140656815345663,
-STORE, 140656815345664, 140656815382527,
-ERASE, 140656815345664, 140656815382527,
-STORE, 140656815345664, 140656815382527,
-STORE, 140656810037248, 140656812171263,
-SNULL, 140656810037248, 140656810065919,
-STORE, 140656810065920, 140656812171263,
-STORE, 140656810037248, 140656810065919,
-SNULL, 140656812163071, 140656812171263,
-STORE, 140656810065920, 140656812163071,
-STORE, 140656812163072, 140656812171263,
-ERASE, 140656812163072, 140656812171263,
-STORE, 140656812163072, 140656812171263,
-STORE, 140656807727104, 140656810037247,
-SNULL, 140656807727104, 140656807931903,
-STORE, 140656807931904, 140656810037247,
-STORE, 140656807727104, 140656807931903,
-SNULL, 140656810029055, 140656810037247,
-STORE, 140656807931904, 140656810029055,
-STORE, 140656810029056, 140656810037247,
-ERASE, 140656810029056, 140656810037247,
-STORE, 140656810029056, 140656810037247,
-STORE, 140656805343232, 140656807727103,
-SNULL, 140656805343232, 140656805535743,
-STORE, 140656805535744, 140656807727103,
-STORE, 140656805343232, 140656805535743,
-SNULL, 140656807628799, 140656807727103,
-STORE, 140656805535744, 140656807628799,
-STORE, 140656807628800, 140656807727103,
-ERASE, 140656807628800, 140656807727103,
-STORE, 140656807628800, 140656807727103,
-STORE, 140656836747264, 140656836763647,
-STORE, 140656802775040, 140656805343231,
-SNULL, 140656802775040, 140656803241983,
-STORE, 140656803241984, 140656805343231,
-STORE, 140656802775040, 140656803241983,
-SNULL, 140656805335039, 140656805343231,
-STORE, 140656803241984, 140656805335039,
-STORE, 140656805335040, 140656805343231,
-ERASE, 140656805335040, 140656805343231,
-STORE, 140656805335040, 140656805343231,
-STORE, 140656800661504, 140656802775039,
-SNULL, 140656800661504, 140656800673791,
-STORE, 140656800673792, 140656802775039,
-STORE, 140656800661504, 140656800673791,
-SNULL, 140656802766847, 140656802775039,
-STORE, 140656800673792, 140656802766847,
-STORE, 140656802766848, 140656802775039,
-ERASE, 140656802766848, 140656802775039,
-STORE, 140656802766848, 140656802775039,
-STORE, 140656798482432, 140656800661503,
-SNULL, 140656798482432, 140656798560255,
-STORE, 140656798560256, 140656800661503,
-STORE, 140656798482432, 140656798560255,
-SNULL, 140656800653311, 140656800661503,
-STORE, 140656798560256, 140656800653311,
-STORE, 140656800653312, 140656800661503,
-ERASE, 140656800653312, 140656800661503,
-STORE, 140656800653312, 140656800661503,
-STORE, 140656796364800, 140656798482431,
-SNULL, 140656796364800, 140656796381183,
-STORE, 140656796381184, 140656798482431,
-STORE, 140656796364800, 140656796381183,
-SNULL, 140656798474239, 140656798482431,
-STORE, 140656796381184, 140656798474239,
-STORE, 140656798474240, 140656798482431,
-ERASE, 140656798474240, 140656798482431,
-STORE, 140656798474240, 140656798482431,
-STORE, 140656836739072, 140656836763647,
-STORE, 140656836726784, 140656836763647,
-SNULL, 140656825700351, 140656825708543,
-STORE, 140656825683968, 140656825700351,
-STORE, 140656825700352, 140656825708543,
-SNULL, 140656798478335, 140656798482431,
-STORE, 140656798474240, 140656798478335,
-STORE, 140656798478336, 140656798482431,
-SNULL, 140656800657407, 140656800661503,
-STORE, 140656800653312, 140656800657407,
-STORE, 140656800657408, 140656800661503,
-SNULL, 140656802770943, 140656802775039,
-STORE, 140656802766848, 140656802770943,
-STORE, 140656802770944, 140656802775039,
-SNULL, 140656827920383, 140656827924479,
-STORE, 140656827916288, 140656827920383,
-STORE, 140656827920384, 140656827924479,
-SNULL, 140656805339135, 140656805343231,
-STORE, 140656805335040, 140656805339135,
-STORE, 140656805339136, 140656805343231,
-SNULL, 140656807723007, 140656807727103,
-STORE, 140656807628800, 140656807723007,
-STORE, 140656807723008, 140656807727103,
-SNULL, 140656810033151, 140656810037247,
-STORE, 140656810029056, 140656810033151,
-STORE, 140656810033152, 140656810037247,
-SNULL, 140656812167167, 140656812171263,
-STORE, 140656812163072, 140656812167167,
-STORE, 140656812167168, 140656812171263,
-SNULL, 140656815353855, 140656815382527,
-STORE, 140656815345664, 140656815353855,
-STORE, 140656815353856, 140656815382527,
-SNULL, 140656817549311, 140656817553407,
-STORE, 140656817545216, 140656817549311,
-STORE, 140656817549312, 140656817553407,
-SNULL, 140656819802111, 140656819806207,
-STORE, 140656819798016, 140656819802111,
-STORE, 140656819802112, 140656819806207,
-SNULL, 140656821923839, 140656821927935,
-STORE, 140656821919744, 140656821923839,
-STORE, 140656821923840, 140656821927935,
-SNULL, 140656830066687, 140656830070783,
-STORE, 140656830062592, 140656830066687,
-STORE, 140656830066688, 140656830070783,
-SNULL, 140656832319487, 140656832323583,
-STORE, 140656832315392, 140656832319487,
-STORE, 140656832319488, 140656832323583,
-SNULL, 140656834547711, 140656834551807,
-STORE, 140656833982464, 140656834547711,
-STORE, 140656834547712, 140656834551807,
-SNULL, 94730166759423, 94730166763519,
-STORE, 94730166751232, 94730166759423,
-STORE, 94730166759424, 94730166763519,
-SNULL, 140656836800511, 140656836804607,
-STORE, 140656836796416, 140656836800511,
-STORE, 140656836800512, 140656836804607,
-ERASE, 140656836763648, 140656836788223,
-STORE, 94730171318272, 94730171453439,
-STORE, 140656836784128, 140656836788223,
-STORE, 140656836780032, 140656836784127,
-STORE, 140656791920640, 140656796364799,
-STORE, 140656836775936, 140656836780031,
-STORE, 140656787476480, 140656791920639,
-STORE, 140656779083776, 140656787476479,
-SNULL, 140656779087871, 140656787476479,
-STORE, 140656779083776, 140656779087871,
-STORE, 140656779087872, 140656787476479,
-STORE, 140656836771840, 140656836775935,
-STORE, 140656774639616, 140656779083775,
-STORE, 140656766246912, 140656774639615,
-SNULL, 140656766251007, 140656774639615,
-STORE, 140656766246912, 140656766251007,
-STORE, 140656766251008, 140656774639615,
-ERASE, 140656791920640, 140656796364799,
-ERASE, 140656836780032, 140656836784127,
-ERASE, 140656787476480, 140656791920639,
-ERASE, 140656836775936, 140656836780031,
-STORE, 140656836780032, 140656836784127,
-STORE, 140656791920640, 140656796364799,
-STORE, 140656836775936, 140656836780031,
-STORE, 140656787476480, 140656791920639,
-ERASE, 140656774639616, 140656779083775,
- };
- unsigned long set20[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140735952392192, 140737488351231,
-SNULL, 140735952396287, 140737488351231,
-STORE, 140735952392192, 140735952396287,
-STORE, 140735952261120, 140735952396287,
-STORE, 94849008947200, 94849009414143,
-SNULL, 94849009364991, 94849009414143,
-STORE, 94849008947200, 94849009364991,
-STORE, 94849009364992, 94849009414143,
-ERASE, 94849009364992, 94849009414143,
-STORE, 94849009364992, 94849009414143,
-STORE, 140590397943808, 140590400196607,
-SNULL, 140590398087167, 140590400196607,
-STORE, 140590397943808, 140590398087167,
-STORE, 140590398087168, 140590400196607,
-ERASE, 140590398087168, 140590400196607,
-STORE, 140590400184320, 140590400192511,
-STORE, 140590400192512, 140590400196607,
-STORE, 140735952850944, 140735952855039,
-STORE, 140735952838656, 140735952850943,
-STORE, 140590400180224, 140590400184319,
-STORE, 140590400172032, 140590400180223,
-STORE, 140590395809792, 140590397943807,
-SNULL, 140590395809792, 140590395838463,
-STORE, 140590395838464, 140590397943807,
-STORE, 140590395809792, 140590395838463,
-SNULL, 140590397935615, 140590397943807,
-STORE, 140590395838464, 140590397935615,
-STORE, 140590397935616, 140590397943807,
-ERASE, 140590397935616, 140590397943807,
-STORE, 140590397935616, 140590397943807,
-STORE, 140590393425920, 140590395809791,
-SNULL, 140590393425920, 140590393692159,
-STORE, 140590393692160, 140590395809791,
-STORE, 140590393425920, 140590393692159,
-SNULL, 140590395785215, 140590395809791,
-STORE, 140590393692160, 140590395785215,
-STORE, 140590395785216, 140590395809791,
-SNULL, 140590395785216, 140590395805695,
-STORE, 140590395805696, 140590395809791,
-STORE, 140590395785216, 140590395805695,
-ERASE, 140590395785216, 140590395805695,
-STORE, 140590395785216, 140590395805695,
-ERASE, 140590395805696, 140590395809791,
-STORE, 140590395805696, 140590395809791,
-STORE, 140590391234560, 140590393425919,
-SNULL, 140590391234560, 140590391324671,
-STORE, 140590391324672, 140590393425919,
-STORE, 140590391234560, 140590391324671,
-SNULL, 140590393417727, 140590393425919,
-STORE, 140590391324672, 140590393417727,
-STORE, 140590393417728, 140590393425919,
-ERASE, 140590393417728, 140590393425919,
-STORE, 140590393417728, 140590393425919,
-STORE, 140590388973568, 140590391234559,
-SNULL, 140590388973568, 140590389125119,
-STORE, 140590389125120, 140590391234559,
-STORE, 140590388973568, 140590389125119,
-SNULL, 140590391218175, 140590391234559,
-STORE, 140590389125120, 140590391218175,
-STORE, 140590391218176, 140590391234559,
-SNULL, 140590391218176, 140590391226367,
-STORE, 140590391226368, 140590391234559,
-STORE, 140590391218176, 140590391226367,
-ERASE, 140590391218176, 140590391226367,
-STORE, 140590391218176, 140590391226367,
-ERASE, 140590391226368, 140590391234559,
-STORE, 140590391226368, 140590391234559,
-STORE, 140590386843648, 140590388973567,
-SNULL, 140590386843648, 140590386872319,
-STORE, 140590386872320, 140590388973567,
-STORE, 140590386843648, 140590386872319,
-SNULL, 140590388965375, 140590388973567,
-STORE, 140590386872320, 140590388965375,
-STORE, 140590388965376, 140590388973567,
-ERASE, 140590388965376, 140590388973567,
-STORE, 140590388965376, 140590388973567,
-STORE, 140590384627712, 140590386843647,
-SNULL, 140590384627712, 140590384726015,
-STORE, 140590384726016, 140590386843647,
-STORE, 140590384627712, 140590384726015,
-SNULL, 140590386819071, 140590386843647,
-STORE, 140590384726016, 140590386819071,
-STORE, 140590386819072, 140590386843647,
-SNULL, 140590386819072, 140590386827263,
-STORE, 140590386827264, 140590386843647,
-STORE, 140590386819072, 140590386827263,
-ERASE, 140590386819072, 140590386827263,
-STORE, 140590386819072, 140590386827263,
-ERASE, 140590386827264, 140590386843647,
-STORE, 140590386827264, 140590386843647,
-STORE, 140590400163840, 140590400180223,
-STORE, 140590380830720, 140590384627711,
-SNULL, 140590380830720, 140590382489599,
-STORE, 140590382489600, 140590384627711,
-STORE, 140590380830720, 140590382489599,
-SNULL, 140590384586751, 140590384627711,
-STORE, 140590382489600, 140590384586751,
-STORE, 140590384586752, 140590384627711,
-SNULL, 140590384586752, 140590384611327,
-STORE, 140590384611328, 140590384627711,
-STORE, 140590384586752, 140590384611327,
-ERASE, 140590384586752, 140590384611327,
-STORE, 140590384586752, 140590384611327,
-ERASE, 140590384611328, 140590384627711,
-STORE, 140590384611328, 140590384627711,
-STORE, 140590378713088, 140590380830719,
-SNULL, 140590378713088, 140590378729471,
-STORE, 140590378729472, 140590380830719,
-STORE, 140590378713088, 140590378729471,
-SNULL, 140590380822527, 140590380830719,
-STORE, 140590378729472, 140590380822527,
-STORE, 140590380822528, 140590380830719,
-ERASE, 140590380822528, 140590380830719,
-STORE, 140590380822528, 140590380830719,
-STORE, 140590376595456, 140590378713087,
-SNULL, 140590376595456, 140590376611839,
-STORE, 140590376611840, 140590378713087,
-STORE, 140590376595456, 140590376611839,
-SNULL, 140590378704895, 140590378713087,
-STORE, 140590376611840, 140590378704895,
-STORE, 140590378704896, 140590378713087,
-ERASE, 140590378704896, 140590378713087,
-STORE, 140590378704896, 140590378713087,
-STORE, 140590374027264, 140590376595455,
-SNULL, 140590374027264, 140590374494207,
-STORE, 140590374494208, 140590376595455,
-STORE, 140590374027264, 140590374494207,
-SNULL, 140590376587263, 140590376595455,
-STORE, 140590374494208, 140590376587263,
-STORE, 140590376587264, 140590376595455,
-ERASE, 140590376587264, 140590376595455,
-STORE, 140590376587264, 140590376595455,
-STORE, 140590371913728, 140590374027263,
-SNULL, 140590371913728, 140590371926015,
-STORE, 140590371926016, 140590374027263,
-STORE, 140590371913728, 140590371926015,
-SNULL, 140590374019071, 140590374027263,
-STORE, 140590371926016, 140590374019071,
-STORE, 140590374019072, 140590374027263,
-ERASE, 140590374019072, 140590374027263,
-STORE, 140590374019072, 140590374027263,
-STORE, 140590400155648, 140590400180223,
-STORE, 140590400143360, 140590400180223,
-SNULL, 140590384603135, 140590384611327,
-STORE, 140590384586752, 140590384603135,
-STORE, 140590384603136, 140590384611327,
-SNULL, 140590374023167, 140590374027263,
-STORE, 140590374019072, 140590374023167,
-STORE, 140590374023168, 140590374027263,
-SNULL, 140590386823167, 140590386827263,
-STORE, 140590386819072, 140590386823167,
-STORE, 140590386823168, 140590386827263,
-SNULL, 140590376591359, 140590376595455,
- };
- unsigned long set21[] = {
-STORE, 93874710941696, 93874711363583,
-STORE, 93874711367680, 93874711408639,
-STORE, 93874711408640, 93874711412735,
-STORE, 93874720989184, 93874721124351,
-STORE, 140708365086720, 140708365099007,
-STORE, 140708365099008, 140708367192063,
-STORE, 140708367192064, 140708367196159,
-STORE, 140708367196160, 140708367200255,
-STORE, 140708367200256, 140708367667199,
-STORE, 140708367667200, 140708369760255,
-STORE, 140708369760256, 140708369764351,
-STORE, 140708369764352, 140708369768447,
-STORE, 140708369768448, 140708369784831,
-STORE, 140708369784832, 140708371877887,
-STORE, 140708371877888, 140708371881983,
-STORE, 140708371881984, 140708371886079,
-STORE, 140708371886080, 140708371902463,
-STORE, 140708371902464, 140708373995519,
-STORE, 140708373995520, 140708373999615,
-STORE, 140708373999616, 140708374003711,
-STORE, 140708374003712, 140708375662591,
-STORE, 140708375662592, 140708377759743,
-STORE, 140708377759744, 140708377776127,
-STORE, 140708377776128, 140708377784319,
-STORE, 140708377784320, 140708377800703,
-STORE, 140708377800704, 140708377899007,
-STORE, 140708377899008, 140708379992063,
-STORE, 140708379992064, 140708379996159,
-STORE, 140708379996160, 140708380000255,
-STORE, 140708380000256, 140708380016639,
-STORE, 140708380016640, 140708380045311,
-STORE, 140708380045312, 140708382138367,
-STORE, 140708382138368, 140708382142463,
-STORE, 140708382142464, 140708382146559,
-STORE, 140708382146560, 140708382298111,
-STORE, 140708382298112, 140708384391167,
-STORE, 140708384391168, 140708384395263,
-STORE, 140708384395264, 140708384399359,
-STORE, 140708384399360, 140708384407551,
-STORE, 140708384407552, 140708384497663,
-STORE, 140708384497664, 140708386590719,
-STORE, 140708386590720, 140708386594815,
-STORE, 140708386594816, 140708386598911,
-STORE, 140708386598912, 140708386865151,
-STORE, 140708386865152, 140708388958207,
-STORE, 140708388958208, 140708388974591,
-STORE, 140708388974592, 140708388978687,
-STORE, 140708388978688, 140708388982783,
-STORE, 140708388982784, 140708389011455,
-STORE, 140708389011456, 140708391108607,
-STORE, 140708391108608, 140708391112703,
-STORE, 140708391112704, 140708391116799,
-STORE, 140708391116800, 140708391260159,
-STORE, 140708393291776, 140708393308159,
-STORE, 140708393308160, 140708393312255,
-STORE, 140708393312256, 140708393316351,
-STORE, 140708393316352, 140708393353215,
-STORE, 140708393353216, 140708393357311,
-STORE, 140708393357312, 140708393361407,
-STORE, 140708393361408, 140708393365503,
-STORE, 140708393365504, 140708393369599,
-STORE, 140730557042688, 140730557177855,
-STORE, 140730557235200, 140730557247487,
-STORE, 140730557247488, 140730557251583,
-ERASE, 140708393353216, 140708393357311,
-ERASE, 140708393312256, 140708393316351,
-ERASE, 140708393308160, 140708393312255,
-ERASE, 140708393291776, 140708393308159,
- };
- unsigned long set22[] = {
-STORE, 93951397134336, 93951397183487,
-STORE, 93951397183488, 93951397728255,
-STORE, 93951397728256, 93951397826559,
-STORE, 93951397826560, 93951397842943,
-STORE, 93951397842944, 93951397847039,
-STORE, 93951425974272, 93951426109439,
-STORE, 140685152665600, 140685152677887,
-STORE, 140685152677888, 140685152829439,
-STORE, 140685152829440, 140685154181119,
-STORE, 140685154181120, 140685154484223,
-STORE, 140685154484224, 140685154496511,
-STORE, 140685154496512, 140685154508799,
-STORE, 140685154508800, 140685154525183,
-STORE, 140685154525184, 140685154541567,
-STORE, 140685154541568, 140685154590719,
-STORE, 140685154590720, 140685154603007,
-STORE, 140685154603008, 140685154607103,
-STORE, 140685154607104, 140685154611199,
-STORE, 140685154611200, 140685154615295,
-STORE, 140685154615296, 140685154631679,
-STORE, 140685154639872, 140685154643967,
-STORE, 140685154643968, 140685154766847,
-STORE, 140685154766848, 140685154799615,
-STORE, 140685154803712, 140685154807807,
-STORE, 140685154807808, 140685154811903,
-STORE, 140685154811904, 140685154815999,
-STORE, 140722188902400, 140722189037567,
-STORE, 140722189512704, 140722189524991,
-STORE, 140722189524992, 140722189529087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733429354496, 140737488351231,
-SNULL, 140733429358591, 140737488351231,
-STORE, 140733429354496, 140733429358591,
-STORE, 140733429223424, 140733429358591,
-STORE, 94526683537408, 94526683660287,
-SNULL, 94526683553791, 94526683660287,
-STORE, 94526683537408, 94526683553791,
-STORE, 94526683553792, 94526683660287,
-ERASE, 94526683553792, 94526683660287,
-STORE, 94526683553792, 94526683623423,
-STORE, 94526683623424, 94526683647999,
-STORE, 94526683652096, 94526683660287,
-STORE, 140551363747840, 140551363923967,
-SNULL, 140551363751935, 140551363923967,
-STORE, 140551363747840, 140551363751935,
-STORE, 140551363751936, 140551363923967,
-ERASE, 140551363751936, 140551363923967,
-STORE, 140551363751936, 140551363874815,
-STORE, 140551363874816, 140551363907583,
-STORE, 140551363911680, 140551363919871,
-STORE, 140551363919872, 140551363923967,
-STORE, 140733429690368, 140733429694463,
-STORE, 140733429678080, 140733429690367,
-STORE, 140551363739648, 140551363747839,
-STORE, 140551363731456, 140551363739647,
-STORE, 140551363379200, 140551363731455,
-SNULL, 140551363379200, 140551363420159,
-STORE, 140551363420160, 140551363731455,
-STORE, 140551363379200, 140551363420159,
-SNULL, 140551363706879, 140551363731455,
-STORE, 140551363420160, 140551363706879,
-STORE, 140551363706880, 140551363731455,
-SNULL, 140551363420160, 140551363637247,
-STORE, 140551363637248, 140551363706879,
-STORE, 140551363420160, 140551363637247,
-ERASE, 140551363420160, 140551363637247,
-STORE, 140551363420160, 140551363637247,
-SNULL, 140551363637248, 140551363702783,
-STORE, 140551363702784, 140551363706879,
-STORE, 140551363637248, 140551363702783,
-ERASE, 140551363637248, 140551363702783,
-STORE, 140551363637248, 140551363702783,
-ERASE, 140551363706880, 140551363731455,
-STORE, 140551363706880, 140551363731455,
-STORE, 140551361531904, 140551363379199,
-SNULL, 140551361683455, 140551363379199,
-STORE, 140551361531904, 140551361683455,
-STORE, 140551361683456, 140551363379199,
-SNULL, 140551361683456, 140551363035135,
-STORE, 140551363035136, 140551363379199,
-STORE, 140551361683456, 140551363035135,
-ERASE, 140551361683456, 140551363035135,
-STORE, 140551361683456, 140551363035135,
-SNULL, 140551363035136, 140551363338239,
-STORE, 140551363338240, 140551363379199,
-STORE, 140551363035136, 140551363338239,
-ERASE, 140551363035136, 140551363338239,
-STORE, 140551363035136, 140551363379199,
-SNULL, 140551363338239, 140551363379199,
-STORE, 140551363035136, 140551363338239,
-STORE, 140551363338240, 140551363379199,
-SNULL, 140551363338240, 140551363362815,
-STORE, 140551363362816, 140551363379199,
-STORE, 140551363338240, 140551363362815,
-ERASE, 140551363338240, 140551363362815,
-STORE, 140551363338240, 140551363362815,
-ERASE, 140551363362816, 140551363379199,
-STORE, 140551363362816, 140551363379199,
-STORE, 140551361519616, 140551361531903,
-SNULL, 140551363350527, 140551363362815,
-STORE, 140551363338240, 140551363350527,
-STORE, 140551363350528, 140551363362815,
-SNULL, 140551363727359, 140551363731455,
-STORE, 140551363706880, 140551363727359,
-STORE, 140551363727360, 140551363731455,
-SNULL, 94526683656191, 94526683660287,
-STORE, 94526683652096, 94526683656191,
-STORE, 94526683656192, 94526683660287,
-SNULL, 140551363915775, 140551363919871,
-STORE, 140551363911680, 140551363915775,
-STORE, 140551363915776, 140551363919871,
-ERASE, 140551363739648, 140551363747839,
-STORE, 94526715490304, 94526715625471,
-STORE, 140551361253376, 140551361531903,
-STORE, 140551360987136, 140551361531903,
-STORE, 140551360720896, 140551361531903,
-STORE, 140551360454656, 140551361531903,
-SNULL, 140551361253375, 140551361531903,
-STORE, 140551360454656, 140551361253375,
-STORE, 140551361253376, 140551361531903,
-SNULL, 140551361253376, 140551361519615,
-STORE, 140551361519616, 140551361531903,
-STORE, 140551361253376, 140551361519615,
-ERASE, 140551361253376, 140551361519615,
- };
-
- unsigned long set23[] = {
-STORE, 94014447943680, 94014448156671,
-STORE, 94014450253824, 94014450257919,
-STORE, 94014450257920, 94014450266111,
-STORE, 94014450266112, 94014450278399,
-STORE, 94014464225280, 94014464630783,
-STORE, 139761764306944, 139761765965823,
-STORE, 139761765965824, 139761768062975,
-STORE, 139761768062976, 139761768079359,
-STORE, 139761768079360, 139761768087551,
-STORE, 139761768087552, 139761768103935,
-STORE, 139761768103936, 139761768116223,
-STORE, 139761768116224, 139761770209279,
-STORE, 139761770209280, 139761770213375,
-STORE, 139761770213376, 139761770217471,
-STORE, 139761770217472, 139761770360831,
-STORE, 139761770729472, 139761772412927,
-STORE, 139761772412928, 139761772429311,
-STORE, 139761772457984, 139761772462079,
-STORE, 139761772462080, 139761772466175,
-STORE, 139761772466176, 139761772470271,
-STORE, 140724336517120, 140724336652287,
-STORE, 140724336955392, 140724336967679,
-STORE, 140724336967680, 140724336971775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140721840295936, 140737488351231,
-SNULL, 140721840300031, 140737488351231,
-STORE, 140721840295936, 140721840300031,
-STORE, 140721840164864, 140721840300031,
-STORE, 93937913667584, 93937915830271,
-SNULL, 93937913729023, 93937915830271,
-STORE, 93937913667584, 93937913729023,
-STORE, 93937913729024, 93937915830271,
-ERASE, 93937913729024, 93937915830271,
-STORE, 93937915822080, 93937915830271,
-STORE, 140598835335168, 140598837587967,
-SNULL, 140598835478527, 140598837587967,
-STORE, 140598835335168, 140598835478527,
-STORE, 140598835478528, 140598837587967,
-ERASE, 140598835478528, 140598837587967,
-STORE, 140598837575680, 140598837583871,
-STORE, 140598837583872, 140598837587967,
-STORE, 140721841086464, 140721841090559,
-STORE, 140721841074176, 140721841086463,
-STORE, 140598837547008, 140598837575679,
-STORE, 140598837538816, 140598837547007,
-STORE, 140598831538176, 140598835335167,
-SNULL, 140598831538176, 140598833197055,
-STORE, 140598833197056, 140598835335167,
-STORE, 140598831538176, 140598833197055,
-SNULL, 140598835294207, 140598835335167,
-STORE, 140598833197056, 140598835294207,
-STORE, 140598835294208, 140598835335167,
-SNULL, 140598835294208, 140598835318783,
-STORE, 140598835318784, 140598835335167,
-STORE, 140598835294208, 140598835318783,
-ERASE, 140598835294208, 140598835318783,
-STORE, 140598835294208, 140598835318783,
-ERASE, 140598835318784, 140598835335167,
-STORE, 140598835318784, 140598835335167,
-SNULL, 140598835310591, 140598835318783,
-STORE, 140598835294208, 140598835310591,
-STORE, 140598835310592, 140598835318783,
-SNULL, 93937915826175, 93937915830271,
-STORE, 93937915822080, 93937915826175,
-STORE, 93937915826176, 93937915830271,
-SNULL, 140598837579775, 140598837583871,
-STORE, 140598837575680, 140598837579775,
-STORE, 140598837579776, 140598837583871,
-ERASE, 140598837547008, 140598837575679,
-STORE, 93937929179136, 93937929314303,
-STORE, 140598835855360, 140598837538815,
-STORE, 140737488347136, 140737488351231,
-STORE, 140728187723776, 140737488351231,
-SNULL, 140728187727871, 140737488351231,
-STORE, 140728187723776, 140728187727871,
-STORE, 140728187592704, 140728187727871,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140583951437824, 140583953690623,
-SNULL, 140583951581183, 140583953690623,
-STORE, 140583951437824, 140583951581183,
-STORE, 140583951581184, 140583953690623,
-ERASE, 140583951581184, 140583953690623,
-STORE, 140583953678336, 140583953686527,
-STORE, 140583953686528, 140583953690623,
-STORE, 140728189116416, 140728189120511,
-STORE, 140728189104128, 140728189116415,
-STORE, 140583953649664, 140583953678335,
-STORE, 140583953641472, 140583953649663,
-STORE, 140583948275712, 140583951437823,
-SNULL, 140583948275712, 140583949336575,
-STORE, 140583949336576, 140583951437823,
-STORE, 140583948275712, 140583949336575,
-SNULL, 140583951429631, 140583951437823,
-STORE, 140583949336576, 140583951429631,
-STORE, 140583951429632, 140583951437823,
-ERASE, 140583951429632, 140583951437823,
-STORE, 140583951429632, 140583951437823,
-STORE, 140583944478720, 140583948275711,
-SNULL, 140583944478720, 140583946137599,
-STORE, 140583946137600, 140583948275711,
-STORE, 140583944478720, 140583946137599,
-SNULL, 140583948234751, 140583948275711,
-STORE, 140583946137600, 140583948234751,
-STORE, 140583948234752, 140583948275711,
-SNULL, 140583948234752, 140583948259327,
-STORE, 140583948259328, 140583948275711,
-STORE, 140583948234752, 140583948259327,
-ERASE, 140583948234752, 140583948259327,
-STORE, 140583948234752, 140583948259327,
-ERASE, 140583948259328, 140583948275711,
-STORE, 140583948259328, 140583948275711,
-STORE, 140583953629184, 140583953649663,
-SNULL, 140583948251135, 140583948259327,
-STORE, 140583948234752, 140583948251135,
-STORE, 140583948251136, 140583948259327,
-SNULL, 140583951433727, 140583951437823,
-STORE, 140583951429632, 140583951433727,
-STORE, 140583951433728, 140583951437823,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140583953682431, 140583953686527,
-STORE, 140583953678336, 140583953682431,
-STORE, 140583953682432, 140583953686527,
-ERASE, 140583953649664, 140583953678335,
-STORE, 17821696, 17956863,
-STORE, 17821696, 18104319,
-STORE, 140583951945728, 140583953629183,
-STORE, 94014447943680, 94014448156671,
-STORE, 94014450253824, 94014450257919,
-STORE, 94014450257920, 94014450266111,
-STORE, 94014450266112, 94014450278399,
-STORE, 94014464225280, 94014465196031,
-STORE, 139761764306944, 139761765965823,
-STORE, 139761765965824, 139761768062975,
-STORE, 139761768062976, 139761768079359,
-STORE, 139761768079360, 139761768087551,
-STORE, 139761768087552, 139761768103935,
-STORE, 139761768103936, 139761768116223,
-STORE, 139761768116224, 139761770209279,
-STORE, 139761770209280, 139761770213375,
-STORE, 139761770213376, 139761770217471,
-STORE, 139761770217472, 139761770360831,
-STORE, 139761770729472, 139761772412927,
-STORE, 139761772412928, 139761772429311,
-STORE, 139761772457984, 139761772462079,
-STORE, 139761772462080, 139761772466175,
-STORE, 139761772466176, 139761772470271,
-STORE, 140724336517120, 140724336652287,
-STORE, 140724336955392, 140724336967679,
-STORE, 140724336967680, 140724336971775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726063296512, 140737488351231,
-SNULL, 140726063300607, 140737488351231,
-STORE, 140726063296512, 140726063300607,
-STORE, 140726063165440, 140726063300607,
-STORE, 94016795934720, 94016798158847,
-SNULL, 94016796045311, 94016798158847,
-STORE, 94016795934720, 94016796045311,
-STORE, 94016796045312, 94016798158847,
-ERASE, 94016796045312, 94016798158847,
-STORE, 94016798138368, 94016798150655,
-STORE, 94016798150656, 94016798158847,
-STORE, 139975915966464, 139975918219263,
-SNULL, 139975916109823, 139975918219263,
-STORE, 139975915966464, 139975916109823,
-STORE, 139975916109824, 139975918219263,
-ERASE, 139975916109824, 139975918219263,
-STORE, 139975918206976, 139975918215167,
-STORE, 139975918215168, 139975918219263,
-STORE, 140726064541696, 140726064545791,
-STORE, 140726064529408, 140726064541695,
-STORE, 139975918178304, 139975918206975,
-STORE, 139975918170112, 139975918178303,
-STORE, 139975912169472, 139975915966463,
-SNULL, 139975912169472, 139975913828351,
-STORE, 139975913828352, 139975915966463,
-STORE, 139975912169472, 139975913828351,
-SNULL, 139975915925503, 139975915966463,
-STORE, 139975913828352, 139975915925503,
-STORE, 139975915925504, 139975915966463,
-SNULL, 139975915925504, 139975915950079,
-STORE, 139975915950080, 139975915966463,
-STORE, 139975915925504, 139975915950079,
-ERASE, 139975915925504, 139975915950079,
-STORE, 139975915925504, 139975915950079,
-ERASE, 139975915950080, 139975915966463,
-STORE, 139975915950080, 139975915966463,
-SNULL, 139975915941887, 139975915950079,
-STORE, 139975915925504, 139975915941887,
-STORE, 139975915941888, 139975915950079,
-SNULL, 94016798146559, 94016798150655,
-STORE, 94016798138368, 94016798146559,
-STORE, 94016798146560, 94016798150655,
-SNULL, 139975918211071, 139975918215167,
-STORE, 139975918206976, 139975918211071,
-STORE, 139975918211072, 139975918215167,
-ERASE, 139975918178304, 139975918206975,
-STORE, 94016804925440, 94016805060607,
-STORE, 94596177661952, 94596177772543,
-STORE, 94596179865600, 94596179873791,
-STORE, 94596179873792, 94596179877887,
-STORE, 94596179877888, 94596179886079,
-STORE, 94596211597312, 94596211863551,
-STORE, 140127351840768, 140127353499647,
-STORE, 140127353499648, 140127355596799,
-STORE, 140127355596800, 140127355613183,
-STORE, 140127355613184, 140127355621375,
-STORE, 140127355621376, 140127355637759,
-STORE, 140127355637760, 140127355781119,
-STORE, 140127357841408, 140127357849599,
-STORE, 140127357878272, 140127357882367,
-STORE, 140127357882368, 140127357886463,
-STORE, 140127357886464, 140127357890559,
-STORE, 140726167252992, 140726167392255,
-STORE, 140726167838720, 140726167851007,
-STORE, 140726167851008, 140726167855103,
-STORE, 140737488347136, 140737488351231,
-STORE, 140731874017280, 140737488351231,
-SNULL, 140731874021375, 140737488351231,
-STORE, 140731874017280, 140731874021375,
-STORE, 140731873886208, 140731874021375,
-STORE, 94178682265600, 94178684489727,
-SNULL, 94178682376191, 94178684489727,
-STORE, 94178682265600, 94178682376191,
-STORE, 94178682376192, 94178684489727,
-ERASE, 94178682376192, 94178684489727,
-STORE, 94178684469248, 94178684481535,
-STORE, 94178684481536, 94178684489727,
-STORE, 140460853403648, 140460855656447,
-SNULL, 140460853547007, 140460855656447,
-STORE, 140460853403648, 140460853547007,
-STORE, 140460853547008, 140460855656447,
-ERASE, 140460853547008, 140460855656447,
-STORE, 140460855644160, 140460855652351,
-STORE, 140460855652352, 140460855656447,
-STORE, 140731874103296, 140731874107391,
-STORE, 140731874091008, 140731874103295,
-STORE, 140460855615488, 140460855644159,
-STORE, 140460855607296, 140460855615487,
-STORE, 140460849606656, 140460853403647,
-SNULL, 140460849606656, 140460851265535,
-STORE, 140460851265536, 140460853403647,
-STORE, 140460849606656, 140460851265535,
-SNULL, 140460853362687, 140460853403647,
-STORE, 140460851265536, 140460853362687,
-STORE, 140460853362688, 140460853403647,
-SNULL, 140460853362688, 140460853387263,
-STORE, 140460853387264, 140460853403647,
-STORE, 140460853362688, 140460853387263,
-ERASE, 140460853362688, 140460853387263,
-STORE, 140460853362688, 140460853387263,
-ERASE, 140460853387264, 140460853403647,
-STORE, 140460853387264, 140460853403647,
-SNULL, 140460853379071, 140460853387263,
-STORE, 140460853362688, 140460853379071,
-STORE, 140460853379072, 140460853387263,
-SNULL, 94178684477439, 94178684481535,
-STORE, 94178684469248, 94178684477439,
-STORE, 94178684477440, 94178684481535,
-SNULL, 140460855648255, 140460855652351,
-STORE, 140460855644160, 140460855648255,
-STORE, 140460855648256, 140460855652351,
-ERASE, 140460855615488, 140460855644159,
-STORE, 94178692063232, 94178692198399,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733096603648, 140737488351231,
-SNULL, 140733096611839, 140737488351231,
-STORE, 140733096603648, 140733096611839,
-STORE, 140733096472576, 140733096611839,
-STORE, 94796716122112, 94796718325759,
-SNULL, 94796716224511, 94796718325759,
-STORE, 94796716122112, 94796716224511,
-STORE, 94796716224512, 94796718325759,
-ERASE, 94796716224512, 94796718325759,
-STORE, 94796718317568, 94796718325759,
-STORE, 139667892793344, 139667895046143,
-SNULL, 139667892936703, 139667895046143,
-STORE, 139667892793344, 139667892936703,
-STORE, 139667892936704, 139667895046143,
-ERASE, 139667892936704, 139667895046143,
-STORE, 139667895033856, 139667895042047,
-STORE, 139667895042048, 139667895046143,
-STORE, 140733096857600, 140733096861695,
-STORE, 140733096845312, 140733096857599,
-STORE, 139667895005184, 139667895033855,
-STORE, 139667894996992, 139667895005183,
-STORE, 139667890532352, 139667892793343,
-SNULL, 139667890532352, 139667890683903,
-STORE, 139667890683904, 139667892793343,
-STORE, 139667890532352, 139667890683903,
-SNULL, 139667892776959, 139667892793343,
-STORE, 139667890683904, 139667892776959,
-STORE, 139667892776960, 139667892793343,
-SNULL, 139667892776960, 139667892785151,
-STORE, 139667892785152, 139667892793343,
-STORE, 139667892776960, 139667892785151,
-ERASE, 139667892776960, 139667892785151,
-STORE, 139667892776960, 139667892785151,
-ERASE, 139667892785152, 139667892793343,
-STORE, 139667892785152, 139667892793343,
-STORE, 139667886735360, 139667890532351,
-SNULL, 139667886735360, 139667888394239,
-STORE, 139667888394240, 139667890532351,
-STORE, 139667886735360, 139667888394239,
-SNULL, 139667890491391, 139667890532351,
-STORE, 139667888394240, 139667890491391,
-STORE, 139667890491392, 139667890532351,
-SNULL, 139667890491392, 139667890515967,
-STORE, 139667890515968, 139667890532351,
-STORE, 139667890491392, 139667890515967,
-ERASE, 139667890491392, 139667890515967,
-STORE, 139667890491392, 139667890515967,
-ERASE, 139667890515968, 139667890532351,
-STORE, 139667890515968, 139667890532351,
-STORE, 139667884167168, 139667886735359,
-SNULL, 139667884167168, 139667884634111,
-STORE, 139667884634112, 139667886735359,
-STORE, 139667884167168, 139667884634111,
-SNULL, 139667886727167, 139667886735359,
-STORE, 139667884634112, 139667886727167,
-STORE, 139667886727168, 139667886735359,
-ERASE, 139667886727168, 139667886735359,
-STORE, 139667886727168, 139667886735359,
-STORE, 139667882053632, 139667884167167,
-SNULL, 139667882053632, 139667882065919,
-STORE, 139667882065920, 139667884167167,
-STORE, 139667882053632, 139667882065919,
-SNULL, 139667884158975, 139667884167167,
-STORE, 139667882065920, 139667884158975,
-STORE, 139667884158976, 139667884167167,
-ERASE, 139667884158976, 139667884167167,
-STORE, 139667884158976, 139667884167167,
-STORE, 139667879837696, 139667882053631,
-SNULL, 139667879837696, 139667879935999,
-STORE, 139667879936000, 139667882053631,
-STORE, 139667879837696, 139667879935999,
-SNULL, 139667882029055, 139667882053631,
-STORE, 139667879936000, 139667882029055,
-STORE, 139667882029056, 139667882053631,
-SNULL, 139667882029056, 139667882037247,
-STORE, 139667882037248, 139667882053631,
-STORE, 139667882029056, 139667882037247,
-ERASE, 139667882029056, 139667882037247,
-STORE, 139667882029056, 139667882037247,
-ERASE, 139667882037248, 139667882053631,
-STORE, 139667882037248, 139667882053631,
-STORE, 139667894988800, 139667895005183,
-SNULL, 139667890507775, 139667890515967,
-STORE, 139667890491392, 139667890507775,
-STORE, 139667890507776, 139667890515967,
-SNULL, 139667882033151, 139667882037247,
-STORE, 139667882029056, 139667882033151,
-STORE, 139667882033152, 139667882037247,
-SNULL, 139667884163071, 139667884167167,
-STORE, 139667884158976, 139667884163071,
-STORE, 139667884163072, 139667884167167,
-SNULL, 139667886731263, 139667886735359,
-STORE, 139667886727168, 139667886731263,
-STORE, 139667886731264, 139667886735359,
-SNULL, 139667892781055, 139667892785151,
-STORE, 139667892776960, 139667892781055,
-STORE, 139667892781056, 139667892785151,
-SNULL, 94796718321663, 94796718325759,
-STORE, 94796718317568, 94796718321663,
-STORE, 94796718321664, 94796718325759,
-SNULL, 139667895037951, 139667895042047,
-STORE, 139667895033856, 139667895037951,
-STORE, 139667895037952, 139667895042047,
-ERASE, 139667895005184, 139667895033855,
-STORE, 94796726063104, 94796726198271,
-STORE, 139667893305344, 139667894988799,
-STORE, 139667895005184, 139667895033855,
-STORE, 94796726063104, 94796726333439,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722489507840, 140737488351231,
-SNULL, 140722489516031, 140737488351231,
-STORE, 140722489507840, 140722489516031,
-STORE, 140722489376768, 140722489516031,
-STORE, 93980993265664, 93980995489791,
-SNULL, 93980993376255, 93980995489791,
-STORE, 93980993265664, 93980993376255,
-STORE, 93980993376256, 93980995489791,
-ERASE, 93980993376256, 93980995489791,
-STORE, 93980995469312, 93980995481599,
-STORE, 93980995481600, 93980995489791,
-STORE, 140261313593344, 140261315846143,
-SNULL, 140261313736703, 140261315846143,
-STORE, 140261313593344, 140261313736703,
-STORE, 140261313736704, 140261315846143,
-ERASE, 140261313736704, 140261315846143,
-STORE, 140261315833856, 140261315842047,
-STORE, 140261315842048, 140261315846143,
-STORE, 140722489675776, 140722489679871,
-STORE, 140722489663488, 140722489675775,
-STORE, 140261315805184, 140261315833855,
-STORE, 140261315796992, 140261315805183,
-STORE, 140261309796352, 140261313593343,
-SNULL, 140261309796352, 140261311455231,
-STORE, 140261311455232, 140261313593343,
-STORE, 140261309796352, 140261311455231,
-SNULL, 140261313552383, 140261313593343,
-STORE, 140261311455232, 140261313552383,
-STORE, 140261313552384, 140261313593343,
-SNULL, 140261313552384, 140261313576959,
-STORE, 140261313576960, 140261313593343,
-STORE, 140261313552384, 140261313576959,
-ERASE, 140261313552384, 140261313576959,
-STORE, 140261313552384, 140261313576959,
-ERASE, 140261313576960, 140261313593343,
-STORE, 140261313576960, 140261313593343,
-SNULL, 140261313568767, 140261313576959,
-STORE, 140261313552384, 140261313568767,
-STORE, 140261313568768, 140261313576959,
-SNULL, 93980995477503, 93980995481599,
-STORE, 93980995469312, 93980995477503,
-STORE, 93980995477504, 93980995481599,
-SNULL, 140261315837951, 140261315842047,
-STORE, 140261315833856, 140261315837951,
-STORE, 140261315837952, 140261315842047,
-ERASE, 140261315805184, 140261315833855,
-STORE, 93980997443584, 93980997578751,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140737488338944, 140737488351231,
-STORE, 140734059450368, 140737488351231,
-SNULL, 140734059462655, 140737488351231,
-STORE, 140734059450368, 140734059462655,
-STORE, 140734059319296, 140734059462655,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140307554983936, 140307557236735,
-SNULL, 140307555127295, 140307557236735,
-STORE, 140307554983936, 140307555127295,
-STORE, 140307555127296, 140307557236735,
-ERASE, 140307555127296, 140307557236735,
-STORE, 140307557224448, 140307557232639,
-STORE, 140307557232640, 140307557236735,
-STORE, 140734059483136, 140734059487231,
-STORE, 140734059470848, 140734059483135,
-STORE, 140307557195776, 140307557224447,
-STORE, 140307557187584, 140307557195775,
-STORE, 140307551821824, 140307554983935,
-SNULL, 140307551821824, 140307552882687,
-STORE, 140307552882688, 140307554983935,
-STORE, 140307551821824, 140307552882687,
-SNULL, 140307554975743, 140307554983935,
-STORE, 140307552882688, 140307554975743,
-STORE, 140307554975744, 140307554983935,
-ERASE, 140307554975744, 140307554983935,
-STORE, 140307554975744, 140307554983935,
-STORE, 140307548024832, 140307551821823,
-SNULL, 140307548024832, 140307549683711,
-STORE, 140307549683712, 140307551821823,
-STORE, 140307548024832, 140307549683711,
-SNULL, 140307551780863, 140307551821823,
-STORE, 140307549683712, 140307551780863,
-STORE, 140307551780864, 140307551821823,
-SNULL, 140307551780864, 140307551805439,
-STORE, 140307551805440, 140307551821823,
-STORE, 140307551780864, 140307551805439,
-ERASE, 140307551780864, 140307551805439,
-STORE, 140307551780864, 140307551805439,
-ERASE, 140307551805440, 140307551821823,
-STORE, 140307551805440, 140307551821823,
-STORE, 140307557175296, 140307557195775,
-SNULL, 140307551797247, 140307551805439,
-STORE, 140307551780864, 140307551797247,
-STORE, 140307551797248, 140307551805439,
-SNULL, 140307554979839, 140307554983935,
-STORE, 140307554975744, 140307554979839,
-STORE, 140307554979840, 140307554983935,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140307557228543, 140307557232639,
-STORE, 140307557224448, 140307557228543,
-STORE, 140307557228544, 140307557232639,
-ERASE, 140307557195776, 140307557224447,
-STORE, 39698432, 39833599,
-STORE, 39698432, 39981055,
-STORE, 94306485321728, 94306485432319,
-STORE, 94306487525376, 94306487533567,
-STORE, 94306487533568, 94306487537663,
-STORE, 94306487537664, 94306487545855,
-STORE, 94306488868864, 94306489004031,
-STORE, 140497673998336, 140497675657215,
-STORE, 140497675657216, 140497677754367,
-STORE, 140497677754368, 140497677770751,
-STORE, 140497677770752, 140497677778943,
-STORE, 140497677778944, 140497677795327,
-STORE, 140497677795328, 140497677938687,
-STORE, 140497679998976, 140497680007167,
-STORE, 140497680035840, 140497680039935,
-STORE, 140497680039936, 140497680044031,
-STORE, 140497680044032, 140497680048127,
-STORE, 140732780462080, 140732780601343,
-STORE, 140732782239744, 140732782252031,
-STORE, 140732782252032, 140732782256127,
-STORE, 94236915900416, 94236916011007,
-STORE, 94236918104064, 94236918112255,
-STORE, 94236918112256, 94236918116351,
-STORE, 94236918116352, 94236918124543,
-STORE, 94236939489280, 94236939624447,
-STORE, 140046091743232, 140046093402111,
-STORE, 140046093402112, 140046095499263,
-STORE, 140046095499264, 140046095515647,
-STORE, 140046095515648, 140046095523839,
-STORE, 140046095523840, 140046095540223,
-STORE, 140046095540224, 140046095683583,
-STORE, 140046097743872, 140046097752063,
-STORE, 140046097780736, 140046097784831,
-STORE, 140046097784832, 140046097788927,
-STORE, 140046097788928, 140046097793023,
-STORE, 140726694449152, 140726694588415,
-STORE, 140726695313408, 140726695325695,
-STORE, 140726695325696, 140726695329791,
-STORE, 94894582779904, 94894582992895,
-STORE, 94894585090048, 94894585094143,
-STORE, 94894585094144, 94894585102335,
-STORE, 94894585102336, 94894585114623,
-STORE, 94894592868352, 94894594293759,
-STORE, 139733563842560, 139733565501439,
-STORE, 139733565501440, 139733567598591,
-STORE, 139733567598592, 139733567614975,
-STORE, 139733567614976, 139733567623167,
-STORE, 139733567623168, 139733567639551,
-STORE, 139733567639552, 139733567651839,
-STORE, 139733567651840, 139733569744895,
-STORE, 139733569744896, 139733569748991,
-STORE, 139733569748992, 139733569753087,
-STORE, 139733569753088, 139733569896447,
-STORE, 139733570265088, 139733571948543,
-STORE, 139733571948544, 139733571964927,
-STORE, 139733571993600, 139733571997695,
-STORE, 139733571997696, 139733572001791,
-STORE, 139733572001792, 139733572005887,
-STORE, 140726369255424, 140726369394687,
-STORE, 140726370402304, 140726370414591,
-STORE, 140726370414592, 140726370418687,
-STORE, 94899236483072, 94899236696063,
-STORE, 94899238793216, 94899238797311,
-STORE, 94899238797312, 94899238805503,
-STORE, 94899238805504, 94899238817791,
-STORE, 94899263045632, 94899263979519,
-STORE, 140040959893504, 140040961552383,
-STORE, 140040961552384, 140040963649535,
-STORE, 140040963649536, 140040963665919,
-STORE, 140040963665920, 140040963674111,
-STORE, 140040963674112, 140040963690495,
-STORE, 140040963690496, 140040963702783,
-STORE, 140040963702784, 140040965795839,
-STORE, 140040965795840, 140040965799935,
-STORE, 140040965799936, 140040965804031,
-STORE, 140040965804032, 140040965947391,
-STORE, 140040966316032, 140040967999487,
-STORE, 140040967999488, 140040968015871,
-STORE, 140040968044544, 140040968048639,
-STORE, 140040968048640, 140040968052735,
-STORE, 140040968052736, 140040968056831,
-STORE, 140729921359872, 140729921499135,
-STORE, 140729921613824, 140729921626111,
-STORE, 140729921626112, 140729921630207,
-STORE, 94818265190400, 94818265403391,
-STORE, 94818267500544, 94818267504639,
-STORE, 94818267504640, 94818267512831,
-STORE, 94818267512832, 94818267525119,
-STORE, 94818283372544, 94818285858815,
-STORE, 139818425675776, 139818427334655,
-STORE, 139818427334656, 139818429431807,
-STORE, 139818429431808, 139818429448191,
-STORE, 139818429448192, 139818429456383,
-STORE, 139818429456384, 139818429472767,
-STORE, 139818429472768, 139818429485055,
-STORE, 139818429485056, 139818431578111,
-STORE, 139818431578112, 139818431582207,
-STORE, 139818431582208, 139818431586303,
-STORE, 139818431586304, 139818431729663,
-STORE, 139818432098304, 139818433781759,
-STORE, 139818433781760, 139818433798143,
-STORE, 139818433826816, 139818433830911,
-STORE, 139818433830912, 139818433835007,
-STORE, 139818433835008, 139818433839103,
-STORE, 140726170509312, 140726170648575,
-STORE, 140726171824128, 140726171836415,
-STORE, 140726171836416, 140726171840511,
-STORE, 94611513188352, 94611513401343,
-STORE, 94611515498496, 94611515502591,
-STORE, 94611515502592, 94611515510783,
-STORE, 94611515510784, 94611515523071,
-STORE, 94611516502016, 94611516907519,
-STORE, 140596246388736, 140596248047615,
-STORE, 140596248047616, 140596250144767,
-STORE, 140596250144768, 140596250161151,
-STORE, 140596250161152, 140596250169343,
-STORE, 140596250169344, 140596250185727,
-STORE, 140596250185728, 140596250198015,
-STORE, 140596250198016, 140596252291071,
-STORE, 140596252291072, 140596252295167,
-STORE, 140596252295168, 140596252299263,
-STORE, 140596252299264, 140596252442623,
-STORE, 140596252811264, 140596254494719,
-STORE, 140596254494720, 140596254511103,
-STORE, 140596254539776, 140596254543871,
-STORE, 140596254543872, 140596254547967,
-STORE, 140596254547968, 140596254552063,
-STORE, 140731551338496, 140731551477759,
-STORE, 140731551780864, 140731551793151,
-STORE, 140731551793152, 140731551797247,
-STORE, 94313835851776, 94313836064767,
-STORE, 94313838161920, 94313838166015,
-STORE, 94313838166016, 94313838174207,
-STORE, 94313838174208, 94313838186495,
-STORE, 94313858416640, 94313861906431,
-STORE, 140693503918080, 140693505576959,
-STORE, 140693505576960, 140693507674111,
-STORE, 140693507674112, 140693507690495,
-STORE, 140693507690496, 140693507698687,
-STORE, 140693507698688, 140693507715071,
-STORE, 140693507715072, 140693507727359,
-STORE, 140693507727360, 140693509820415,
-STORE, 140693509820416, 140693509824511,
-STORE, 140693509824512, 140693509828607,
-STORE, 140693509828608, 140693509971967,
-STORE, 140693510340608, 140693512024063,
-STORE, 140693512024064, 140693512040447,
-STORE, 140693512069120, 140693512073215,
-STORE, 140693512073216, 140693512077311,
-STORE, 140693512077312, 140693512081407,
-STORE, 140721116065792, 140721116205055,
-STORE, 140721117831168, 140721117843455,
-STORE, 140721117843456, 140721117847551,
-STORE, 94843650150400, 94843650363391,
-STORE, 94843652460544, 94843652464639,
-STORE, 94843652464640, 94843652472831,
-STORE, 94843652472832, 94843652485119,
-STORE, 94843685388288, 94843686281215,
-STORE, 140484193681408, 140484195340287,
-STORE, 140484195340288, 140484197437439,
-STORE, 140484197437440, 140484197453823,
-STORE, 140484197453824, 140484197462015,
-STORE, 140484197462016, 140484197478399,
-STORE, 140484197478400, 140484197490687,
-STORE, 140484197490688, 140484199583743,
-STORE, 140484199583744, 140484199587839,
-STORE, 140484199587840, 140484199591935,
-STORE, 140484199591936, 140484199735295,
-STORE, 140484200103936, 140484201787391,
-STORE, 140484201787392, 140484201803775,
-STORE, 140484201832448, 140484201836543,
-STORE, 140484201836544, 140484201840639,
-STORE, 140484201840640, 140484201844735,
-STORE, 140726294315008, 140726294454271,
-STORE, 140726295646208, 140726295658495,
-STORE, 140726295658496, 140726295662591,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140720422371328, 140737488351231,
-SNULL, 140720422379519, 140737488351231,
-STORE, 140720422371328, 140720422379519,
-STORE, 140720422240256, 140720422379519,
-STORE, 94417967845376, 94417970180095,
-SNULL, 94417968058367, 94417970180095,
-STORE, 94417967845376, 94417968058367,
-STORE, 94417968058368, 94417970180095,
-ERASE, 94417968058368, 94417970180095,
-STORE, 94417970155520, 94417970167807,
-STORE, 94417970167808, 94417970180095,
-STORE, 140252450045952, 140252452298751,
-SNULL, 140252450189311, 140252452298751,
-STORE, 140252450045952, 140252450189311,
-STORE, 140252450189312, 140252452298751,
-ERASE, 140252450189312, 140252452298751,
-STORE, 140252452286464, 140252452294655,
-STORE, 140252452294656, 140252452298751,
-STORE, 140720422416384, 140720422420479,
-STORE, 140720422404096, 140720422416383,
-STORE, 140252452257792, 140252452286463,
-STORE, 140252452249600, 140252452257791,
-STORE, 140252447932416, 140252450045951,
-SNULL, 140252447932416, 140252447944703,
-STORE, 140252447944704, 140252450045951,
-STORE, 140252447932416, 140252447944703,
-SNULL, 140252450037759, 140252450045951,
-STORE, 140252447944704, 140252450037759,
-STORE, 140252450037760, 140252450045951,
-ERASE, 140252450037760, 140252450045951,
-STORE, 140252450037760, 140252450045951,
-STORE, 140252444135424, 140252447932415,
-SNULL, 140252444135424, 140252445794303,
-STORE, 140252445794304, 140252447932415,
-STORE, 140252444135424, 140252445794303,
-SNULL, 140252447891455, 140252447932415,
-STORE, 140252445794304, 140252447891455,
-STORE, 140252447891456, 140252447932415,
-SNULL, 140252447891456, 140252447916031,
-STORE, 140252447916032, 140252447932415,
-STORE, 140252447891456, 140252447916031,
-ERASE, 140252447891456, 140252447916031,
-STORE, 140252447891456, 140252447916031,
-ERASE, 140252447916032, 140252447932415,
-STORE, 140252447916032, 140252447932415,
-STORE, 140252452241408, 140252452257791,
-SNULL, 140252447907839, 140252447916031,
-STORE, 140252447891456, 140252447907839,
-STORE, 140252447907840, 140252447916031,
-SNULL, 140252450041855, 140252450045951,
-STORE, 140252450037760, 140252450041855,
-STORE, 140252450041856, 140252450045951,
-SNULL, 94417970159615, 94417970167807,
-STORE, 94417970155520, 94417970159615,
-STORE, 94417970159616, 94417970167807,
-SNULL, 140252452290559, 140252452294655,
-STORE, 140252452286464, 140252452290559,
-STORE, 140252452290560, 140252452294655,
-ERASE, 140252452257792, 140252452286463,
-STORE, 94417996333056, 94417996468223,
-STORE, 140252450557952, 140252452241407,
-STORE, 94417996333056, 94417996603391,
-STORE, 94417996333056, 94417996738559,
-STORE, 94417996333056, 94417996910591,
-SNULL, 94417996881919, 94417996910591,
-STORE, 94417996333056, 94417996881919,
-STORE, 94417996881920, 94417996910591,
-ERASE, 94417996881920, 94417996910591,
-STORE, 94417996333056, 94417997017087,
-STORE, 94417996333056, 94417997152255,
-SNULL, 94417997135871, 94417997152255,
-STORE, 94417996333056, 94417997135871,
-STORE, 94417997135872, 94417997152255,
-ERASE, 94417997135872, 94417997152255,
-STORE, 94417996333056, 94417997291519,
-SNULL, 94417997271039, 94417997291519,
-STORE, 94417996333056, 94417997271039,
-STORE, 94417997271040, 94417997291519,
-ERASE, 94417997271040, 94417997291519,
-STORE, 94417996333056, 94417997406207,
-SNULL, 94417997381631, 94417997406207,
-STORE, 94417996333056, 94417997381631,
-STORE, 94417997381632, 94417997406207,
-ERASE, 94417997381632, 94417997406207,
-STORE, 94417996333056, 94417997516799,
-SNULL, 94417997488127, 94417997516799,
-STORE, 94417996333056, 94417997488127,
-STORE, 94417997488128, 94417997516799,
-ERASE, 94417997488128, 94417997516799,
-STORE, 94417996333056, 94417997643775,
-SNULL, 94417997631487, 94417997643775,
-STORE, 94417996333056, 94417997631487,
-STORE, 94417997631488, 94417997643775,
-ERASE, 94417997631488, 94417997643775,
-SNULL, 94417997590527, 94417997631487,
-STORE, 94417996333056, 94417997590527,
-STORE, 94417997590528, 94417997631487,
-ERASE, 94417997590528, 94417997631487,
-STORE, 94417996333056, 94417997733887,
-STORE, 94417996333056, 94417997869055,
-STORE, 94417996333056, 94417998004223,
-SNULL, 94417998000127, 94417998004223,
-STORE, 94417996333056, 94417998000127,
-STORE, 94417998000128, 94417998004223,
-ERASE, 94417998000128, 94417998004223,
-STORE, 94049170993152, 94049171206143,
-STORE, 94049173303296, 94049173307391,
-STORE, 94049173307392, 94049173315583,
-STORE, 94049173315584, 94049173327871,
-STORE, 94049176236032, 94049183645695,
-STORE, 139807795544064, 139807797202943,
-STORE, 139807797202944, 139807799300095,
-STORE, 139807799300096, 139807799316479,
-STORE, 139807799316480, 139807799324671,
-STORE, 139807799324672, 139807799341055,
-STORE, 139807799341056, 139807799353343,
-STORE, 139807799353344, 139807801446399,
-STORE, 139807801446400, 139807801450495,
-STORE, 139807801450496, 139807801454591,
-STORE, 139807801454592, 139807801597951,
-STORE, 139807801966592, 139807803650047,
-STORE, 139807803650048, 139807803666431,
-STORE, 139807803695104, 139807803699199,
-STORE, 139807803699200, 139807803703295,
-STORE, 139807803703296, 139807803707391,
-STORE, 140727555538944, 140727555678207,
-STORE, 140727555940352, 140727555952639,
-STORE, 140727555952640, 140727555956735,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722483441664, 140737488351231,
-SNULL, 140722483449855, 140737488351231,
-STORE, 140722483441664, 140722483449855,
-STORE, 140722483310592, 140722483449855,
-STORE, 94416704921600, 94416707145727,
-SNULL, 94416705032191, 94416707145727,
-STORE, 94416704921600, 94416705032191,
-STORE, 94416705032192, 94416707145727,
-ERASE, 94416705032192, 94416707145727,
-STORE, 94416707125248, 94416707137535,
-STORE, 94416707137536, 94416707145727,
-STORE, 140555439296512, 140555441549311,
-SNULL, 140555439439871, 140555441549311,
-STORE, 140555439296512, 140555439439871,
-STORE, 140555439439872, 140555441549311,
-ERASE, 140555439439872, 140555441549311,
-STORE, 140555441537024, 140555441545215,
-STORE, 140555441545216, 140555441549311,
-STORE, 140722484781056, 140722484785151,
-STORE, 140722484768768, 140722484781055,
-STORE, 140555441508352, 140555441537023,
-STORE, 140555441500160, 140555441508351,
-STORE, 140555435499520, 140555439296511,
-SNULL, 140555435499520, 140555437158399,
-STORE, 140555437158400, 140555439296511,
-STORE, 140555435499520, 140555437158399,
-SNULL, 140555439255551, 140555439296511,
-STORE, 140555437158400, 140555439255551,
-STORE, 140555439255552, 140555439296511,
-SNULL, 140555439255552, 140555439280127,
-STORE, 140555439280128, 140555439296511,
-STORE, 140555439255552, 140555439280127,
-ERASE, 140555439255552, 140555439280127,
-STORE, 140555439255552, 140555439280127,
-ERASE, 140555439280128, 140555439296511,
-STORE, 140555439280128, 140555439296511,
-SNULL, 140555439271935, 140555439280127,
-STORE, 140555439255552, 140555439271935,
-STORE, 140555439271936, 140555439280127,
-SNULL, 94416707133439, 94416707137535,
-STORE, 94416707125248, 94416707133439,
-STORE, 94416707133440, 94416707137535,
-SNULL, 140555441541119, 140555441545215,
-STORE, 140555441537024, 140555441541119,
-STORE, 140555441541120, 140555441545215,
-ERASE, 140555441508352, 140555441537023,
-STORE, 94416724672512, 94416724807679,
-STORE, 94686636953600, 94686637166591,
-STORE, 94686639263744, 94686639267839,
-STORE, 94686639267840, 94686639276031,
-STORE, 94686639276032, 94686639288319,
-STORE, 94686662193152, 94686663163903,
-STORE, 140312944431104, 140312946089983,
-STORE, 140312946089984, 140312948187135,
-STORE, 140312948187136, 140312948203519,
-STORE, 140312948203520, 140312948211711,
-STORE, 140312948211712, 140312948228095,
-STORE, 140312948228096, 140312948240383,
-STORE, 140312948240384, 140312950333439,
-STORE, 140312950333440, 140312950337535,
-STORE, 140312950337536, 140312950341631,
-STORE, 140312950341632, 140312950484991,
-STORE, 140312950853632, 140312952537087,
-STORE, 140312952537088, 140312952553471,
-STORE, 140312952582144, 140312952586239,
-STORE, 140312952586240, 140312952590335,
-STORE, 140312952590336, 140312952594431,
-STORE, 140730598920192, 140730599059455,
-STORE, 140730599108608, 140730599120895,
-STORE, 140730599120896, 140730599124991,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140726234079232, 140737488351231,
-SNULL, 140726234087423, 140737488351231,
-STORE, 140726234079232, 140726234087423,
-STORE, 140726233948160, 140726234087423,
-STORE, 94589467578368, 94589469802495,
-SNULL, 94589467688959, 94589469802495,
-STORE, 94589467578368, 94589467688959,
-STORE, 94589467688960, 94589469802495,
-ERASE, 94589467688960, 94589469802495,
-STORE, 94589469782016, 94589469794303,
-STORE, 94589469794304, 94589469802495,
-STORE, 140587082842112, 140587085094911,
-SNULL, 140587082985471, 140587085094911,
-STORE, 140587082842112, 140587082985471,
-STORE, 140587082985472, 140587085094911,
-ERASE, 140587082985472, 140587085094911,
-STORE, 140587085082624, 140587085090815,
-STORE, 140587085090816, 140587085094911,
-STORE, 140726234103808, 140726234107903,
-STORE, 140726234091520, 140726234103807,
-STORE, 140587085053952, 140587085082623,
-STORE, 140587085045760, 140587085053951,
-STORE, 140587079045120, 140587082842111,
-SNULL, 140587079045120, 140587080703999,
-STORE, 140587080704000, 140587082842111,
-STORE, 140587079045120, 140587080703999,
-SNULL, 140587082801151, 140587082842111,
-STORE, 140587080704000, 140587082801151,
-STORE, 140587082801152, 140587082842111,
-SNULL, 140587082801152, 140587082825727,
-STORE, 140587082825728, 140587082842111,
-STORE, 140587082801152, 140587082825727,
-ERASE, 140587082801152, 140587082825727,
-STORE, 140587082801152, 140587082825727,
-ERASE, 140587082825728, 140587082842111,
-STORE, 140587082825728, 140587082842111,
-SNULL, 140587082817535, 140587082825727,
-STORE, 140587082801152, 140587082817535,
-STORE, 140587082817536, 140587082825727,
-SNULL, 94589469790207, 94589469794303,
-STORE, 94589469782016, 94589469790207,
-STORE, 94589469790208, 94589469794303,
-SNULL, 140587085086719, 140587085090815,
-STORE, 140587085082624, 140587085086719,
-STORE, 140587085086720, 140587085090815,
-ERASE, 140587085053952, 140587085082623,
-STORE, 94589477507072, 94589477642239,
-STORE, 94225448325120, 94225448538111,
-STORE, 94225450635264, 94225450639359,
-STORE, 94225450639360, 94225450647551,
-STORE, 94225450647552, 94225450659839,
-STORE, 94225470246912, 94225473548287,
-STORE, 140199245496320, 140199247155199,
-STORE, 140199247155200, 140199249252351,
-STORE, 140199249252352, 140199249268735,
-STORE, 140199249268736, 140199249276927,
-STORE, 140199249276928, 140199249293311,
-STORE, 140199249293312, 140199249305599,
-STORE, 140199249305600, 140199251398655,
-STORE, 140199251398656, 140199251402751,
-STORE, 140199251402752, 140199251406847,
-STORE, 140199251406848, 140199251550207,
-STORE, 140199251918848, 140199253602303,
-STORE, 140199253602304, 140199253618687,
-STORE, 140199253647360, 140199253651455,
-STORE, 140199253651456, 140199253655551,
-STORE, 140199253655552, 140199253659647,
-STORE, 140726264414208, 140726264553471,
-STORE, 140726265843712, 140726265855999,
-STORE, 140726265856000, 140726265860095,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733508358144, 140737488351231,
-SNULL, 140733508366335, 140737488351231,
-STORE, 140733508358144, 140733508366335,
-STORE, 140733508227072, 140733508366335,
-STORE, 94766263947264, 94766266171391,
-SNULL, 94766264057855, 94766266171391,
-STORE, 94766263947264, 94766264057855,
-STORE, 94766264057856, 94766266171391,
-ERASE, 94766264057856, 94766266171391,
-STORE, 94766266150912, 94766266163199,
-STORE, 94766266163200, 94766266171391,
-STORE, 140693985132544, 140693987385343,
-SNULL, 140693985275903, 140693987385343,
-STORE, 140693985132544, 140693985275903,
-STORE, 140693985275904, 140693987385343,
-ERASE, 140693985275904, 140693987385343,
-STORE, 140693987373056, 140693987381247,
-STORE, 140693987381248, 140693987385343,
-STORE, 140733509939200, 140733509943295,
-STORE, 140733509926912, 140733509939199,
-STORE, 140693987344384, 140693987373055,
-STORE, 140693987336192, 140693987344383,
-STORE, 140693981335552, 140693985132543,
-SNULL, 140693981335552, 140693982994431,
-STORE, 140693982994432, 140693985132543,
-STORE, 140693981335552, 140693982994431,
-SNULL, 140693985091583, 140693985132543,
-STORE, 140693982994432, 140693985091583,
-STORE, 140693985091584, 140693985132543,
-SNULL, 140693985091584, 140693985116159,
-STORE, 140693985116160, 140693985132543,
-STORE, 140693985091584, 140693985116159,
-ERASE, 140693985091584, 140693985116159,
-STORE, 140693985091584, 140693985116159,
-ERASE, 140693985116160, 140693985132543,
-STORE, 140693985116160, 140693985132543,
-SNULL, 140693985107967, 140693985116159,
-STORE, 140693985091584, 140693985107967,
-STORE, 140693985107968, 140693985116159,
-SNULL, 94766266159103, 94766266163199,
-STORE, 94766266150912, 94766266159103,
-STORE, 94766266159104, 94766266163199,
-SNULL, 140693987377151, 140693987381247,
-STORE, 140693987373056, 140693987377151,
-STORE, 140693987377152, 140693987381247,
-ERASE, 140693987344384, 140693987373055,
-STORE, 94766282035200, 94766282170367,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724769353728, 140737488351231,
-SNULL, 140724769361919, 140737488351231,
-STORE, 140724769353728, 140724769361919,
-STORE, 140724769222656, 140724769361919,
-STORE, 94710460526592, 94710462750719,
-SNULL, 94710460637183, 94710462750719,
-STORE, 94710460526592, 94710460637183,
-STORE, 94710460637184, 94710462750719,
-ERASE, 94710460637184, 94710462750719,
-STORE, 94710462730240, 94710462742527,
-STORE, 94710462742528, 94710462750719,
-STORE, 140469764395008, 140469766647807,
-SNULL, 140469764538367, 140469766647807,
-STORE, 140469764395008, 140469764538367,
-STORE, 140469764538368, 140469766647807,
-ERASE, 140469764538368, 140469766647807,
-STORE, 140469766635520, 140469766643711,
-STORE, 140469766643712, 140469766647807,
-STORE, 140724770877440, 140724770881535,
-STORE, 140724770865152, 140724770877439,
-STORE, 140469766606848, 140469766635519,
-STORE, 140469766598656, 140469766606847,
-STORE, 140469760598016, 140469764395007,
-SNULL, 140469760598016, 140469762256895,
-STORE, 140469762256896, 140469764395007,
-STORE, 140469760598016, 140469762256895,
-SNULL, 140469764354047, 140469764395007,
-STORE, 140469762256896, 140469764354047,
-STORE, 140469764354048, 140469764395007,
-SNULL, 140469764354048, 140469764378623,
-STORE, 140469764378624, 140469764395007,
-STORE, 140469764354048, 140469764378623,
-ERASE, 140469764354048, 140469764378623,
-STORE, 140469764354048, 140469764378623,
-ERASE, 140469764378624, 140469764395007,
-STORE, 140469764378624, 140469764395007,
-SNULL, 140469764370431, 140469764378623,
-STORE, 140469764354048, 140469764370431,
-STORE, 140469764370432, 140469764378623,
-SNULL, 94710462738431, 94710462742527,
-STORE, 94710462730240, 94710462738431,
-STORE, 94710462738432, 94710462742527,
-SNULL, 140469766639615, 140469766643711,
-STORE, 140469766635520, 140469766639615,
-STORE, 140469766639616, 140469766643711,
-ERASE, 140469766606848, 140469766635519,
-STORE, 94710485581824, 94710485716991,
-STORE, 94105755795456, 94105756008447,
-STORE, 94105758105600, 94105758109695,
-STORE, 94105758109696, 94105758117887,
-STORE, 94105758117888, 94105758130175,
-STORE, 94105788981248, 94105794871295,
-STORE, 140641190031360, 140641191690239,
-STORE, 140641191690240, 140641193787391,
-STORE, 140641193787392, 140641193803775,
-STORE, 140641193803776, 140641193811967,
-STORE, 140641193811968, 140641193828351,
-STORE, 140641193828352, 140641193840639,
-STORE, 140641193840640, 140641195933695,
-STORE, 140641195933696, 140641195937791,
-STORE, 140641195937792, 140641195941887,
-STORE, 140641195941888, 140641196085247,
-STORE, 140641196453888, 140641198137343,
-STORE, 140641198137344, 140641198153727,
-STORE, 140641198182400, 140641198186495,
-STORE, 140641198186496, 140641198190591,
-STORE, 140641198190592, 140641198194687,
-STORE, 140731980034048, 140731980173311,
-STORE, 140731981078528, 140731981090815,
-STORE, 140731981090816, 140731981094911,
-STORE, 93828086431744, 93828086644735,
-STORE, 93828088741888, 93828088745983,
-STORE, 93828088745984, 93828088754175,
-STORE, 93828088754176, 93828088766463,
-STORE, 93828094193664, 93828096831487,
-STORE, 139844717334528, 139844718993407,
-STORE, 139844718993408, 139844721090559,
-STORE, 139844721090560, 139844721106943,
-STORE, 139844721106944, 139844721115135,
-STORE, 139844721115136, 139844721131519,
-STORE, 139844721131520, 139844721143807,
-STORE, 139844721143808, 139844723236863,
-STORE, 139844723236864, 139844723240959,
-STORE, 139844723240960, 139844723245055,
-STORE, 139844723245056, 139844723388415,
-STORE, 139844723757056, 139844725440511,
-STORE, 139844725440512, 139844725456895,
-STORE, 139844725485568, 139844725489663,
-STORE, 139844725489664, 139844725493759,
-STORE, 139844725493760, 139844725497855,
-STORE, 140729996185600, 140729996324863,
-STORE, 140729996828672, 140729996840959,
-STORE, 140729996840960, 140729996845055,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722494771200, 140737488351231,
-SNULL, 140722494775295, 140737488351231,
-STORE, 140722494771200, 140722494775295,
-STORE, 140722494640128, 140722494775295,
-STORE, 94324011311104, 94324013535231,
-SNULL, 94324011421695, 94324013535231,
-STORE, 94324011311104, 94324011421695,
-STORE, 94324011421696, 94324013535231,
-ERASE, 94324011421696, 94324013535231,
-STORE, 94324013514752, 94324013527039,
-STORE, 94324013527040, 94324013535231,
-STORE, 140151462309888, 140151464562687,
-SNULL, 140151462453247, 140151464562687,
-STORE, 140151462309888, 140151462453247,
-STORE, 140151462453248, 140151464562687,
-ERASE, 140151462453248, 140151464562687,
-STORE, 140151464550400, 140151464558591,
-STORE, 140151464558592, 140151464562687,
-STORE, 140722495467520, 140722495471615,
-STORE, 140722495455232, 140722495467519,
-STORE, 140151464521728, 140151464550399,
-STORE, 140151464513536, 140151464521727,
-STORE, 140151458512896, 140151462309887,
-SNULL, 140151458512896, 140151460171775,
-STORE, 140151460171776, 140151462309887,
-STORE, 140151458512896, 140151460171775,
-SNULL, 140151462268927, 140151462309887,
-STORE, 140151460171776, 140151462268927,
-STORE, 140151462268928, 140151462309887,
-SNULL, 140151462268928, 140151462293503,
-STORE, 140151462293504, 140151462309887,
-STORE, 140151462268928, 140151462293503,
-ERASE, 140151462268928, 140151462293503,
-STORE, 140151462268928, 140151462293503,
-ERASE, 140151462293504, 140151462309887,
-STORE, 140151462293504, 140151462309887,
-SNULL, 140151462285311, 140151462293503,
-STORE, 140151462268928, 140151462285311,
-STORE, 140151462285312, 140151462293503,
-SNULL, 94324013522943, 94324013527039,
-STORE, 94324013514752, 94324013522943,
-STORE, 94324013522944, 94324013527039,
-SNULL, 140151464554495, 140151464558591,
-STORE, 140151464550400, 140151464554495,
-STORE, 140151464554496, 140151464558591,
-ERASE, 140151464521728, 140151464550399,
-STORE, 94324024778752, 94324024913919,
-STORE, 94899262967808, 94899263180799,
-STORE, 94899265277952, 94899265282047,
-STORE, 94899265282048, 94899265290239,
-STORE, 94899265290240, 94899265302527,
-STORE, 94899295469568, 94899298689023,
-STORE, 140434388418560, 140434390077439,
-STORE, 140434390077440, 140434392174591,
-STORE, 140434392174592, 140434392190975,
-STORE, 140434392190976, 140434392199167,
-STORE, 140434392199168, 140434392215551,
-STORE, 140434392215552, 140434392227839,
-STORE, 140434392227840, 140434394320895,
-STORE, 140434394320896, 140434394324991,
-STORE, 140434394324992, 140434394329087,
-STORE, 140434394329088, 140434394472447,
-STORE, 140434394841088, 140434396524543,
-STORE, 140434396524544, 140434396540927,
-STORE, 140434396569600, 140434396573695,
-STORE, 140434396573696, 140434396577791,
-STORE, 140434396577792, 140434396581887,
-STORE, 140720618135552, 140720618274815,
-STORE, 140720618418176, 140720618430463,
-STORE, 140720618430464, 140720618434559,
-STORE, 94425529798656, 94425530011647,
-STORE, 94425532108800, 94425532112895,
-STORE, 94425532112896, 94425532121087,
-STORE, 94425532121088, 94425532133375,
-STORE, 94425557753856, 94425566576639,
-STORE, 140600528470016, 140600530128895,
-STORE, 140600530128896, 140600532226047,
-STORE, 140600532226048, 140600532242431,
-STORE, 140600532242432, 140600532250623,
-STORE, 140600532250624, 140600532267007,
-STORE, 140600532267008, 140600532279295,
-STORE, 140600532279296, 140600534372351,
-STORE, 140600534372352, 140600534376447,
-STORE, 140600534376448, 140600534380543,
-STORE, 140600534380544, 140600534523903,
-STORE, 140600534892544, 140600536575999,
-STORE, 140600536576000, 140600536592383,
-STORE, 140600536621056, 140600536625151,
-STORE, 140600536625152, 140600536629247,
-STORE, 140600536629248, 140600536633343,
-STORE, 140721857785856, 140721857925119,
-STORE, 140721858068480, 140721858080767,
-STORE, 140721858080768, 140721858084863,
-STORE, 94425529798656, 94425530011647,
-STORE, 94425532108800, 94425532112895,
-STORE, 94425532112896, 94425532121087,
-STORE, 94425532121088, 94425532133375,
-STORE, 94425557753856, 94425568772095,
-STORE, 140600528470016, 140600530128895,
-STORE, 140600530128896, 140600532226047,
-STORE, 140600532226048, 140600532242431,
-STORE, 140600532242432, 140600532250623,
-STORE, 140600532250624, 140600532267007,
-STORE, 140600532267008, 140600532279295,
-STORE, 140600532279296, 140600534372351,
-STORE, 140600534372352, 140600534376447,
-STORE, 140600534376448, 140600534380543,
-STORE, 140600534380544, 140600534523903,
-STORE, 140600534892544, 140600536575999,
-STORE, 140600536576000, 140600536592383,
-STORE, 140600536621056, 140600536625151,
-STORE, 140600536625152, 140600536629247,
-STORE, 140600536629248, 140600536633343,
-STORE, 140721857785856, 140721857925119,
-STORE, 140721858068480, 140721858080767,
-STORE, 140721858080768, 140721858084863,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735611645952, 140737488351231,
-SNULL, 140735611654143, 140737488351231,
-STORE, 140735611645952, 140735611654143,
-STORE, 140735611514880, 140735611654143,
-STORE, 94592137641984, 94592139866111,
-SNULL, 94592137752575, 94592139866111,
-STORE, 94592137641984, 94592137752575,
-STORE, 94592137752576, 94592139866111,
-ERASE, 94592137752576, 94592139866111,
-STORE, 94592139845632, 94592139857919,
-STORE, 94592139857920, 94592139866111,
-STORE, 140350425030656, 140350427283455,
-SNULL, 140350425174015, 140350427283455,
-STORE, 140350425030656, 140350425174015,
-STORE, 140350425174016, 140350427283455,
-ERASE, 140350425174016, 140350427283455,
-STORE, 140350427271168, 140350427279359,
-STORE, 140350427279360, 140350427283455,
-STORE, 140735612043264, 140735612047359,
-STORE, 140735612030976, 140735612043263,
-STORE, 140350427242496, 140350427271167,
-STORE, 140350427234304, 140350427242495,
-STORE, 140350421233664, 140350425030655,
-SNULL, 140350421233664, 140350422892543,
-STORE, 140350422892544, 140350425030655,
-STORE, 140350421233664, 140350422892543,
-SNULL, 140350424989695, 140350425030655,
-STORE, 140350422892544, 140350424989695,
-STORE, 140350424989696, 140350425030655,
-SNULL, 140350424989696, 140350425014271,
-STORE, 140350425014272, 140350425030655,
-STORE, 140350424989696, 140350425014271,
-ERASE, 140350424989696, 140350425014271,
-STORE, 140350424989696, 140350425014271,
-ERASE, 140350425014272, 140350425030655,
-STORE, 140350425014272, 140350425030655,
-SNULL, 140350425006079, 140350425014271,
-STORE, 140350424989696, 140350425006079,
-STORE, 140350425006080, 140350425014271,
-SNULL, 94592139853823, 94592139857919,
-STORE, 94592139845632, 94592139853823,
-STORE, 94592139853824, 94592139857919,
-SNULL, 140350427275263, 140350427279359,
-STORE, 140350427271168, 140350427275263,
-STORE, 140350427275264, 140350427279359,
-ERASE, 140350427242496, 140350427271167,
-STORE, 94592164823040, 94592164958207,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723500535808, 140737488351231,
-SNULL, 140723500543999, 140737488351231,
-STORE, 140723500535808, 140723500543999,
-STORE, 140723500404736, 140723500543999,
-STORE, 94458379010048, 94458381234175,
-SNULL, 94458379120639, 94458381234175,
-STORE, 94458379010048, 94458379120639,
-STORE, 94458379120640, 94458381234175,
-ERASE, 94458379120640, 94458381234175,
-STORE, 94458381213696, 94458381225983,
-STORE, 94458381225984, 94458381234175,
-STORE, 139771674230784, 139771676483583,
-SNULL, 139771674374143, 139771676483583,
-STORE, 139771674230784, 139771674374143,
-STORE, 139771674374144, 139771676483583,
-ERASE, 139771674374144, 139771676483583,
-STORE, 139771676471296, 139771676479487,
-STORE, 139771676479488, 139771676483583,
-STORE, 140723500769280, 140723500773375,
-STORE, 140723500756992, 140723500769279,
-STORE, 139771676442624, 139771676471295,
-STORE, 139771676434432, 139771676442623,
-STORE, 139771670433792, 139771674230783,
-SNULL, 139771670433792, 139771672092671,
-STORE, 139771672092672, 139771674230783,
-STORE, 139771670433792, 139771672092671,
-SNULL, 139771674189823, 139771674230783,
-STORE, 139771672092672, 139771674189823,
-STORE, 139771674189824, 139771674230783,
-SNULL, 139771674189824, 139771674214399,
-STORE, 139771674214400, 139771674230783,
-STORE, 139771674189824, 139771674214399,
-ERASE, 139771674189824, 139771674214399,
-STORE, 139771674189824, 139771674214399,
-ERASE, 139771674214400, 139771674230783,
-STORE, 139771674214400, 139771674230783,
-SNULL, 139771674206207, 139771674214399,
-STORE, 139771674189824, 139771674206207,
-STORE, 139771674206208, 139771674214399,
-SNULL, 94458381221887, 94458381225983,
-STORE, 94458381213696, 94458381221887,
-STORE, 94458381221888, 94458381225983,
-SNULL, 139771676475391, 139771676479487,
-STORE, 139771676471296, 139771676475391,
-STORE, 139771676475392, 139771676479487,
-ERASE, 139771676442624, 139771676471295,
-STORE, 94458401873920, 94458402009087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731316264960, 140737488351231,
-SNULL, 140731316273151, 140737488351231,
-STORE, 140731316264960, 140731316273151,
-STORE, 140731316133888, 140731316273151,
-STORE, 94437830881280, 94437833215999,
-SNULL, 94437831094271, 94437833215999,
-STORE, 94437830881280, 94437831094271,
-STORE, 94437831094272, 94437833215999,
-ERASE, 94437831094272, 94437833215999,
-STORE, 94437833191424, 94437833203711,
-STORE, 94437833203712, 94437833215999,
-STORE, 140265986031616, 140265988284415,
-SNULL, 140265986174975, 140265988284415,
-STORE, 140265986031616, 140265986174975,
-STORE, 140265986174976, 140265988284415,
-ERASE, 140265986174976, 140265988284415,
-STORE, 140265988272128, 140265988280319,
-STORE, 140265988280320, 140265988284415,
-STORE, 140731316318208, 140731316322303,
-STORE, 140731316305920, 140731316318207,
-STORE, 140265988243456, 140265988272127,
-STORE, 140265988235264, 140265988243455,
-STORE, 140265983918080, 140265986031615,
-SNULL, 140265983918080, 140265983930367,
-STORE, 140265983930368, 140265986031615,
-STORE, 140265983918080, 140265983930367,
-SNULL, 140265986023423, 140265986031615,
-STORE, 140265983930368, 140265986023423,
-STORE, 140265986023424, 140265986031615,
-ERASE, 140265986023424, 140265986031615,
-STORE, 140265986023424, 140265986031615,
-STORE, 140265980121088, 140265983918079,
-SNULL, 140265980121088, 140265981779967,
-STORE, 140265981779968, 140265983918079,
-STORE, 140265980121088, 140265981779967,
-SNULL, 140265983877119, 140265983918079,
-STORE, 140265981779968, 140265983877119,
-STORE, 140265983877120, 140265983918079,
-SNULL, 140265983877120, 140265983901695,
-STORE, 140265983901696, 140265983918079,
-STORE, 140265983877120, 140265983901695,
-ERASE, 140265983877120, 140265983901695,
-STORE, 140265983877120, 140265983901695,
-ERASE, 140265983901696, 140265983918079,
-STORE, 140265983901696, 140265983918079,
-STORE, 140265988227072, 140265988243455,
-SNULL, 140265983893503, 140265983901695,
-STORE, 140265983877120, 140265983893503,
-STORE, 140265983893504, 140265983901695,
-SNULL, 140265986027519, 140265986031615,
-STORE, 140265986023424, 140265986027519,
-STORE, 140265986027520, 140265986031615,
-SNULL, 94437833195519, 94437833203711,
-STORE, 94437833191424, 94437833195519,
-STORE, 94437833195520, 94437833203711,
-SNULL, 140265988276223, 140265988280319,
-STORE, 140265988272128, 140265988276223,
-STORE, 140265988276224, 140265988280319,
-ERASE, 140265988243456, 140265988272127,
-STORE, 94437847638016, 94437847773183,
-STORE, 140265986543616, 140265988227071,
-STORE, 94437847638016, 94437847908351,
-STORE, 94437847638016, 94437848043519,
-STORE, 94437847638016, 94437848190975,
-SNULL, 94437848178687, 94437848190975,
-STORE, 94437847638016, 94437848178687,
-STORE, 94437848178688, 94437848190975,
-ERASE, 94437848178688, 94437848190975,
-STORE, 94437847638016, 94437848330239,
-STORE, 94437847638016, 94437848465407,
-SNULL, 94437848444927, 94437848465407,
-STORE, 94437847638016, 94437848444927,
-STORE, 94437848444928, 94437848465407,
-ERASE, 94437848444928, 94437848465407,
-STORE, 94437847638016, 94437848584191,
-STORE, 94437847638016, 94437848719359,
-SNULL, 94437848678399, 94437848719359,
-STORE, 94437847638016, 94437848678399,
-STORE, 94437848678400, 94437848719359,
-ERASE, 94437848678400, 94437848719359,
-STORE, 94437847638016, 94437848842239,
-SNULL, 94437848825855, 94437848842239,
-STORE, 94437847638016, 94437848825855,
-STORE, 94437848825856, 94437848842239,
-ERASE, 94437848825856, 94437848842239,
-STORE, 94437847638016, 94437848961023,
-STORE, 94437847638016, 94437849096191,
-STORE, 94661814710272, 94661814923263,
-STORE, 94661817020416, 94661817024511,
-STORE, 94661817024512, 94661817032703,
-STORE, 94661817032704, 94661817044991,
-STORE, 94661840424960, 94661841240063,
-STORE, 140582259814400, 140582261473279,
-STORE, 140582261473280, 140582263570431,
-STORE, 140582263570432, 140582263586815,
-STORE, 140582263586816, 140582263595007,
-STORE, 140582263595008, 140582263611391,
-STORE, 140582263611392, 140582263623679,
-STORE, 140582263623680, 140582265716735,
-STORE, 140582265716736, 140582265720831,
-STORE, 140582265720832, 140582265724927,
-STORE, 140582265724928, 140582265868287,
-STORE, 140582266236928, 140582267920383,
-STORE, 140582267920384, 140582267936767,
-STORE, 140582267965440, 140582267969535,
-STORE, 140582267969536, 140582267973631,
-STORE, 140582267973632, 140582267977727,
-STORE, 140735472508928, 140735472648191,
-STORE, 140735472672768, 140735472685055,
-STORE, 140735472685056, 140735472689151,
-STORE, 94440069140480, 94440069353471,
-STORE, 94440071450624, 94440071454719,
-STORE, 94440071454720, 94440071462911,
-STORE, 94440071462912, 94440071475199,
-STORE, 94440072122368, 94440079048703,
-STORE, 140112218095616, 140112219754495,
-STORE, 140112219754496, 140112221851647,
-STORE, 140112221851648, 140112221868031,
-STORE, 140112221868032, 140112221876223,
-STORE, 140112221876224, 140112221892607,
-STORE, 140112221892608, 140112221904895,
-STORE, 140112221904896, 140112223997951,
-STORE, 140112223997952, 140112224002047,
-STORE, 140112224002048, 140112224006143,
-STORE, 140112224006144, 140112224149503,
-STORE, 140112224518144, 140112226201599,
-STORE, 140112226201600, 140112226217983,
-STORE, 140112226246656, 140112226250751,
-STORE, 140112226250752, 140112226254847,
-STORE, 140112226254848, 140112226258943,
-STORE, 140737460969472, 140737461108735,
-STORE, 140737462083584, 140737462095871,
-STORE, 140737462095872, 140737462099967,
-STORE, 94257654345728, 94257654390783,
-STORE, 94257656483840, 94257656487935,
-STORE, 94257656487936, 94257656492031,
-STORE, 94257656492032, 94257656496127,
-STORE, 94257665859584, 94257665994751,
-STORE, 140507070345216, 140507070386175,
-STORE, 140507070386176, 140507072483327,
-STORE, 140507072483328, 140507072487423,
-STORE, 140507072487424, 140507072491519,
-STORE, 140507072491520, 140507072516095,
-STORE, 140507072516096, 140507072561151,
-STORE, 140507072561152, 140507074654207,
-STORE, 140507074654208, 140507074658303,
-STORE, 140507074658304, 140507074662399,
-STORE, 140507074662400, 140507074744319,
-STORE, 140507074744320, 140507076841471,
-STORE, 140507076841472, 140507076845567,
-STORE, 140507076845568, 140507076849663,
-STORE, 140507076849664, 140507076857855,
-STORE, 140507076857856, 140507076886527,
-STORE, 140507076886528, 140507078979583,
-STORE, 140507078979584, 140507078983679,
-STORE, 140507078983680, 140507078987775,
-STORE, 140507078987776, 140507079086079,
-STORE, 140507079086080, 140507081179135,
-STORE, 140507081179136, 140507081183231,
-STORE, 140507081183232, 140507081187327,
-STORE, 140507081187328, 140507081203711,
-STORE, 140507081203712, 140507081220095,
-STORE, 140507081220096, 140507083317247,
-STORE, 140507083317248, 140507083321343,
-STORE, 140507083321344, 140507083325439,
-STORE, 140507083325440, 140507083792383,
-STORE, 140507083792384, 140507085885439,
-STORE, 140507085885440, 140507085889535,
-STORE, 140507085889536, 140507085893631,
-STORE, 140507085893632, 140507085905919,
-STORE, 140507085905920, 140507087998975,
-STORE, 140507087998976, 140507088003071,
-STORE, 140507088003072, 140507088007167,
-STORE, 140507088007168, 140507088125951,
-STORE, 140507088125952, 140507090219007,
-STORE, 140507090219008, 140507090223103,
-STORE, 140507090223104, 140507090227199,
-STORE, 140507090227200, 140507090268159,
-STORE, 140507090268160, 140507091927039,
-STORE, 140507091927040, 140507094024191,
-STORE, 140507094024192, 140507094040575,
-STORE, 140507094040576, 140507094048767,
-STORE, 140507094048768, 140507094065151,
-STORE, 140507094065152, 140507094216703,
-STORE, 140507094216704, 140507096309759,
-STORE, 140507096309760, 140507096313855,
-STORE, 140507096313856, 140507096317951,
-STORE, 140507096317952, 140507096326143,
-STORE, 140507096326144, 140507096379391,
-STORE, 140507096379392, 140507098472447,
-STORE, 140507098472448, 140507098476543,
-STORE, 140507098476544, 140507098480639,
-STORE, 140507098480640, 140507098623999,
-STORE, 140507098980352, 140507100663807,
-STORE, 140507100663808, 140507100692479,
-STORE, 140507100721152, 140507100725247,
-STORE, 140507100725248, 140507100729343,
-STORE, 140507100729344, 140507100733439,
-STORE, 140728152780800, 140728152915967,
-STORE, 140728153698304, 140728153710591,
-STORE, 140728153710592, 140728153714687,
-STORE, 140507068137472, 140507070345215,
-SNULL, 140507068137472, 140507068190719,
-STORE, 140507068190720, 140507070345215,
-STORE, 140507068137472, 140507068190719,
-SNULL, 140507070287871, 140507070345215,
-STORE, 140507068190720, 140507070287871,
-STORE, 140507070287872, 140507070345215,
-SNULL, 140507070287872, 140507070296063,
-STORE, 140507070296064, 140507070345215,
-STORE, 140507070287872, 140507070296063,
-ERASE, 140507070287872, 140507070296063,
-STORE, 140507070287872, 140507070296063,
-ERASE, 140507070296064, 140507070345215,
-STORE, 140507070296064, 140507070345215,
-STORE, 140507100692480, 140507100721151,
-STORE, 140507065810944, 140507068137471,
-SNULL, 140507065810944, 140507065843711,
-STORE, 140507065843712, 140507068137471,
-STORE, 140507065810944, 140507065843711,
-SNULL, 140507067940863, 140507068137471,
-STORE, 140507065843712, 140507067940863,
-STORE, 140507067940864, 140507068137471,
-SNULL, 140507067940864, 140507067949055,
-STORE, 140507067949056, 140507068137471,
-STORE, 140507067940864, 140507067949055,
-ERASE, 140507067940864, 140507067949055,
-STORE, 140507067940864, 140507067949055,
-ERASE, 140507067949056, 140507068137471,
-STORE, 140507067949056, 140507068137471,
-SNULL, 140507067944959, 140507067949055,
-STORE, 140507067940864, 140507067944959,
-STORE, 140507067944960, 140507067949055,
-SNULL, 140507070291967, 140507070296063,
-STORE, 140507070287872, 140507070291967,
-STORE, 140507070291968, 140507070296063,
-ERASE, 140507100692480, 140507100721151,
-STORE, 140507063705600, 140507065810943,
-SNULL, 140507063705600, 140507063709695,
-STORE, 140507063709696, 140507065810943,
-STORE, 140507063705600, 140507063709695,
-SNULL, 140507065802751, 140507065810943,
-STORE, 140507063709696, 140507065802751,
-STORE, 140507065802752, 140507065810943,
-ERASE, 140507065802752, 140507065810943,
-STORE, 140507065802752, 140507065810943,
-SNULL, 140507065806847, 140507065810943,
-STORE, 140507065802752, 140507065806847,
-STORE, 140507065806848, 140507065810943,
-STORE, 140507061600256, 140507063705599,
-SNULL, 140507061600256, 140507061604351,
-STORE, 140507061604352, 140507063705599,
-STORE, 140507061600256, 140507061604351,
-SNULL, 140507063697407, 140507063705599,
-STORE, 140507061604352, 140507063697407,
-STORE, 140507063697408, 140507063705599,
-ERASE, 140507063697408, 140507063705599,
-STORE, 140507063697408, 140507063705599,
-SNULL, 140507063701503, 140507063705599,
-STORE, 140507063697408, 140507063701503,
-STORE, 140507063701504, 140507063705599,
-STORE, 140507059490816, 140507061600255,
-SNULL, 140507059490816, 140507059499007,
-STORE, 140507059499008, 140507061600255,
-STORE, 140507059490816, 140507059499007,
-SNULL, 140507061592063, 140507061600255,
-STORE, 140507059499008, 140507061592063,
-STORE, 140507061592064, 140507061600255,
-ERASE, 140507061592064, 140507061600255,
-STORE, 140507061592064, 140507061600255,
-SNULL, 140507061596159, 140507061600255,
-STORE, 140507061592064, 140507061596159,
-STORE, 140507061596160, 140507061600255,
-STORE, 140507057377280, 140507059490815,
-SNULL, 140507057377280, 140507057389567,
-STORE, 140507057389568, 140507059490815,
-STORE, 140507057377280, 140507057389567,
-SNULL, 140507059482623, 140507059490815,
-STORE, 140507057389568, 140507059482623,
-STORE, 140507059482624, 140507059490815,
-ERASE, 140507059482624, 140507059490815,
-STORE, 140507059482624, 140507059490815,
-SNULL, 140507059486719, 140507059490815,
-STORE, 140507059482624, 140507059486719,
-STORE, 140507059486720, 140507059490815,
-STORE, 140507055255552, 140507057377279,
-SNULL, 140507055255552, 140507055276031,
-STORE, 140507055276032, 140507057377279,
-STORE, 140507055255552, 140507055276031,
-SNULL, 140507057369087, 140507057377279,
-STORE, 140507055276032, 140507057369087,
-STORE, 140507057369088, 140507057377279,
-ERASE, 140507057369088, 140507057377279,
-STORE, 140507057369088, 140507057377279,
-SNULL, 140507057373183, 140507057377279,
-STORE, 140507057369088, 140507057373183,
-STORE, 140507057373184, 140507057377279,
-STORE, 140507098693632, 140507098980351,
-SNULL, 140507098959871, 140507098980351,
-STORE, 140507098693632, 140507098959871,
-STORE, 140507098959872, 140507098980351,
-SNULL, 140507098959872, 140507098976255,
-STORE, 140507098976256, 140507098980351,
-STORE, 140507098959872, 140507098976255,
-ERASE, 140507098959872, 140507098976255,
-STORE, 140507098959872, 140507098976255,
-ERASE, 140507098976256, 140507098980351,
-STORE, 140507098976256, 140507098980351,
-STORE, 140507100692480, 140507100721151,
-STORE, 140507053125632, 140507055255551,
-SNULL, 140507053125632, 140507053154303,
-STORE, 140507053154304, 140507055255551,
-STORE, 140507053125632, 140507053154303,
-SNULL, 140507055247359, 140507055255551,
-STORE, 140507053154304, 140507055247359,
-STORE, 140507055247360, 140507055255551,
-ERASE, 140507055247360, 140507055255551,
-STORE, 140507055247360, 140507055255551,
-STORE, 140507051012096, 140507053125631,
-SNULL, 140507051012096, 140507051024383,
-STORE, 140507051024384, 140507053125631,
-STORE, 140507051012096, 140507051024383,
-SNULL, 140507053117439, 140507053125631,
-STORE, 140507051024384, 140507053117439,
-STORE, 140507053117440, 140507053125631,
-ERASE, 140507053117440, 140507053125631,
-STORE, 140507053117440, 140507053125631,
-SNULL, 140507053121535, 140507053125631,
-STORE, 140507053117440, 140507053121535,
-STORE, 140507053121536, 140507053125631,
-SNULL, 140507055251455, 140507055255551,
-STORE, 140507055247360, 140507055251455,
-STORE, 140507055251456, 140507055255551,
-SNULL, 140507098972159, 140507098976255,
-STORE, 140507098959872, 140507098972159,
-STORE, 140507098972160, 140507098976255,
-ERASE, 140507100692480, 140507100721151,
-STORE, 140507100717056, 140507100721151,
-ERASE, 140507100717056, 140507100721151,
-STORE, 140507100717056, 140507100721151,
-ERASE, 140507100717056, 140507100721151,
-STORE, 140507100717056, 140507100721151,
-ERASE, 140507100717056, 140507100721151,
-STORE, 140507100717056, 140507100721151,
-ERASE, 140507100717056, 140507100721151,
-STORE, 140507100692480, 140507100721151,
-ERASE, 140507068137472, 140507068190719,
-ERASE, 140507068190720, 140507070287871,
-ERASE, 140507070287872, 140507070291967,
-ERASE, 140507070291968, 140507070296063,
-ERASE, 140507070296064, 140507070345215,
-ERASE, 140507065810944, 140507065843711,
-ERASE, 140507065843712, 140507067940863,
-ERASE, 140507067940864, 140507067944959,
-ERASE, 140507067944960, 140507067949055,
-ERASE, 140507067949056, 140507068137471,
-ERASE, 140507063705600, 140507063709695,
-ERASE, 140507063709696, 140507065802751,
-ERASE, 140507065802752, 140507065806847,
-ERASE, 140507065806848, 140507065810943,
-ERASE, 140507061600256, 140507061604351,
-ERASE, 140507061604352, 140507063697407,
-ERASE, 140507063697408, 140507063701503,
-ERASE, 140507063701504, 140507063705599,
-ERASE, 140507059490816, 140507059499007,
-ERASE, 140507059499008, 140507061592063,
-ERASE, 140507061592064, 140507061596159,
-ERASE, 140507061596160, 140507061600255,
-ERASE, 140507057377280, 140507057389567,
-ERASE, 140507057389568, 140507059482623,
-ERASE, 140507059482624, 140507059486719,
-ERASE, 140507059486720, 140507059490815,
-ERASE, 140507055255552, 140507055276031,
-ERASE, 140507055276032, 140507057369087,
-ERASE, 140507057369088, 140507057373183,
-ERASE, 140507057373184, 140507057377279,
-ERASE, 140507098693632, 140507098959871,
-ERASE, 140507098959872, 140507098972159,
-ERASE, 140507098972160, 140507098976255,
-ERASE, 140507098976256, 140507098980351,
-ERASE, 140507051012096, 140507051024383,
-ERASE, 140507051024384, 140507053117439,
-ERASE, 140507053117440, 140507053121535,
-ERASE, 140507053121536, 140507053125631,
-STORE, 94036448296960, 94036448509951,
-STORE, 94036450607104, 94036450611199,
-STORE, 94036450611200, 94036450619391,
-STORE, 94036450619392, 94036450631679,
-STORE, 94036482445312, 94036502376447,
-STORE, 140469487013888, 140469488672767,
-STORE, 140469488672768, 140469490769919,
-STORE, 140469490769920, 140469490786303,
-STORE, 140469490786304, 140469490794495,
-STORE, 140469490794496, 140469490810879,
-STORE, 140469490810880, 140469490823167,
-STORE, 140469490823168, 140469492916223,
-STORE, 140469492916224, 140469492920319,
-STORE, 140469492920320, 140469492924415,
-STORE, 140469492924416, 140469493067775,
-STORE, 140469493436416, 140469495119871,
-STORE, 140469495119872, 140469495136255,
-STORE, 140469495164928, 140469495169023,
-STORE, 140469495169024, 140469495173119,
-STORE, 140469495173120, 140469495177215,
-STORE, 140732281446400, 140732281585663,
-STORE, 140732282736640, 140732282748927,
-STORE, 140732282748928, 140732282753023,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723411931136, 140737488351231,
-SNULL, 140723411939327, 140737488351231,
-STORE, 140723411931136, 140723411939327,
-STORE, 140723411800064, 140723411939327,
-STORE, 93993768685568, 93993770909695,
-SNULL, 93993768796159, 93993770909695,
-STORE, 93993768685568, 93993768796159,
-STORE, 93993768796160, 93993770909695,
-ERASE, 93993768796160, 93993770909695,
-STORE, 93993770889216, 93993770901503,
-STORE, 93993770901504, 93993770909695,
-STORE, 140508681740288, 140508683993087,
-SNULL, 140508681883647, 140508683993087,
-STORE, 140508681740288, 140508681883647,
-STORE, 140508681883648, 140508683993087,
-ERASE, 140508681883648, 140508683993087,
-STORE, 140508683980800, 140508683988991,
-STORE, 140508683988992, 140508683993087,
-STORE, 140723412070400, 140723412074495,
-STORE, 140723412058112, 140723412070399,
-STORE, 140508683952128, 140508683980799,
-STORE, 140508683943936, 140508683952127,
-STORE, 140508677943296, 140508681740287,
-SNULL, 140508677943296, 140508679602175,
-STORE, 140508679602176, 140508681740287,
-STORE, 140508677943296, 140508679602175,
-SNULL, 140508681699327, 140508681740287,
-STORE, 140508679602176, 140508681699327,
-STORE, 140508681699328, 140508681740287,
-SNULL, 140508681699328, 140508681723903,
-STORE, 140508681723904, 140508681740287,
-STORE, 140508681699328, 140508681723903,
-ERASE, 140508681699328, 140508681723903,
-STORE, 140508681699328, 140508681723903,
-ERASE, 140508681723904, 140508681740287,
-STORE, 140508681723904, 140508681740287,
-SNULL, 140508681715711, 140508681723903,
-STORE, 140508681699328, 140508681715711,
-STORE, 140508681715712, 140508681723903,
-SNULL, 93993770897407, 93993770901503,
-STORE, 93993770889216, 93993770897407,
-STORE, 93993770897408, 93993770901503,
-SNULL, 140508683984895, 140508683988991,
-STORE, 140508683980800, 140508683984895,
-STORE, 140508683984896, 140508683988991,
-ERASE, 140508683952128, 140508683980799,
-STORE, 93993791582208, 93993791717375,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140734685458432, 140737488351231,
-SNULL, 140734685466623, 140737488351231,
-STORE, 140734685458432, 140734685466623,
-STORE, 140734685327360, 140734685466623,
-STORE, 93832321548288, 93832323772415,
-SNULL, 93832321658879, 93832323772415,
-STORE, 93832321548288, 93832321658879,
-STORE, 93832321658880, 93832323772415,
-ERASE, 93832321658880, 93832323772415,
-STORE, 93832323751936, 93832323764223,
-STORE, 93832323764224, 93832323772415,
-STORE, 140650945118208, 140650947371007,
-SNULL, 140650945261567, 140650947371007,
-STORE, 140650945118208, 140650945261567,
-STORE, 140650945261568, 140650947371007,
-ERASE, 140650945261568, 140650947371007,
-STORE, 140650947358720, 140650947366911,
-STORE, 140650947366912, 140650947371007,
-STORE, 140734686081024, 140734686085119,
-STORE, 140734686068736, 140734686081023,
-STORE, 140650947330048, 140650947358719,
-STORE, 140650947321856, 140650947330047,
-STORE, 140650941321216, 140650945118207,
-SNULL, 140650941321216, 140650942980095,
-STORE, 140650942980096, 140650945118207,
-STORE, 140650941321216, 140650942980095,
-SNULL, 140650945077247, 140650945118207,
-STORE, 140650942980096, 140650945077247,
-STORE, 140650945077248, 140650945118207,
-SNULL, 140650945077248, 140650945101823,
-STORE, 140650945101824, 140650945118207,
-STORE, 140650945077248, 140650945101823,
-ERASE, 140650945077248, 140650945101823,
-STORE, 140650945077248, 140650945101823,
-ERASE, 140650945101824, 140650945118207,
-STORE, 140650945101824, 140650945118207,
-SNULL, 140650945093631, 140650945101823,
-STORE, 140650945077248, 140650945093631,
-STORE, 140650945093632, 140650945101823,
-SNULL, 93832323760127, 93832323764223,
-STORE, 93832323751936, 93832323760127,
-STORE, 93832323760128, 93832323764223,
-SNULL, 140650947362815, 140650947366911,
-STORE, 140650947358720, 140650947362815,
-STORE, 140650947362816, 140650947366911,
-ERASE, 140650947330048, 140650947358719,
-STORE, 93832331890688, 93832332025855,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728333520896, 140737488351231,
-SNULL, 140728333529087, 140737488351231,
-STORE, 140728333520896, 140728333529087,
-STORE, 140728333389824, 140728333529087,
-STORE, 94872734732288, 94872736956415,
-SNULL, 94872734842879, 94872736956415,
-STORE, 94872734732288, 94872734842879,
-STORE, 94872734842880, 94872736956415,
-ERASE, 94872734842880, 94872736956415,
-STORE, 94872736935936, 94872736948223,
-STORE, 94872736948224, 94872736956415,
-STORE, 139755193257984, 139755195510783,
-SNULL, 139755193401343, 139755195510783,
-STORE, 139755193257984, 139755193401343,
-STORE, 139755193401344, 139755195510783,
-ERASE, 139755193401344, 139755195510783,
-STORE, 139755195498496, 139755195506687,
-STORE, 139755195506688, 139755195510783,
-STORE, 140728333926400, 140728333930495,
-STORE, 140728333914112, 140728333926399,
-STORE, 139755195469824, 139755195498495,
-STORE, 139755195461632, 139755195469823,
-STORE, 139755189460992, 139755193257983,
-SNULL, 139755189460992, 139755191119871,
-STORE, 139755191119872, 139755193257983,
-STORE, 139755189460992, 139755191119871,
-SNULL, 139755193217023, 139755193257983,
-STORE, 139755191119872, 139755193217023,
-STORE, 139755193217024, 139755193257983,
-SNULL, 139755193217024, 139755193241599,
-STORE, 139755193241600, 139755193257983,
-STORE, 139755193217024, 139755193241599,
-ERASE, 139755193217024, 139755193241599,
-STORE, 139755193217024, 139755193241599,
-ERASE, 139755193241600, 139755193257983,
-STORE, 139755193241600, 139755193257983,
-SNULL, 139755193233407, 139755193241599,
-STORE, 139755193217024, 139755193233407,
-STORE, 139755193233408, 139755193241599,
-SNULL, 94872736944127, 94872736948223,
-STORE, 94872736935936, 94872736944127,
-STORE, 94872736944128, 94872736948223,
-SNULL, 139755195502591, 139755195506687,
-STORE, 139755195498496, 139755195502591,
-STORE, 139755195502592, 139755195506687,
-ERASE, 139755195469824, 139755195498495,
-STORE, 94872749744128, 94872749879295,
-STORE, 94720243642368, 94720243855359,
-STORE, 94720245952512, 94720245956607,
-STORE, 94720245956608, 94720245964799,
-STORE, 94720245964800, 94720245977087,
-STORE, 94720277745664, 94720278151167,
-STORE, 140453174497280, 140453176156159,
-STORE, 140453176156160, 140453178253311,
-STORE, 140453178253312, 140453178269695,
-STORE, 140453178269696, 140453178277887,
-STORE, 140453178277888, 140453178294271,
-STORE, 140453178294272, 140453178306559,
-STORE, 140453178306560, 140453180399615,
-STORE, 140453180399616, 140453180403711,
-STORE, 140453180403712, 140453180407807,
-STORE, 140453180407808, 140453180551167,
-STORE, 140453180919808, 140453182603263,
-STORE, 140453182603264, 140453182619647,
-STORE, 140453182648320, 140453182652415,
-STORE, 140453182652416, 140453182656511,
-STORE, 140453182656512, 140453182660607,
-STORE, 140733223923712, 140733224062975,
-STORE, 140733224808448, 140733224820735,
-STORE, 140733224820736, 140733224824831,
-STORE, 94321091141632, 94321091354623,
-STORE, 94321093451776, 94321093455871,
-STORE, 94321093455872, 94321093464063,
-STORE, 94321093464064, 94321093476351,
-STORE, 94321115873280, 94321117229055,
-STORE, 139695978840064, 139695980498943,
-STORE, 139695980498944, 139695982596095,
-STORE, 139695982596096, 139695982612479,
-STORE, 139695982612480, 139695982620671,
-STORE, 139695982620672, 139695982637055,
-STORE, 139695982637056, 139695982649343,
-STORE, 139695982649344, 139695984742399,
-STORE, 139695984742400, 139695984746495,
-STORE, 139695984746496, 139695984750591,
-STORE, 139695984750592, 139695984893951,
-STORE, 139695985262592, 139695986946047,
-STORE, 139695986946048, 139695986962431,
-STORE, 139695986991104, 139695986995199,
-STORE, 139695986995200, 139695986999295,
-STORE, 139695986999296, 139695987003391,
-STORE, 140734650564608, 140734650703871,
-STORE, 140734650785792, 140734650798079,
-STORE, 140734650798080, 140734650802175,
-STORE, 94523438456832, 94523438669823,
-STORE, 94523440766976, 94523440771071,
-STORE, 94523440771072, 94523440779263,
-STORE, 94523440779264, 94523440791551,
-STORE, 94523464544256, 94523465842687,
-STORE, 140453231493120, 140453233151999,
-STORE, 140453233152000, 140453235249151,
-STORE, 140453235249152, 140453235265535,
-STORE, 140453235265536, 140453235273727,
-STORE, 140453235273728, 140453235290111,
-STORE, 140453235290112, 140453235302399,
-STORE, 140453235302400, 140453237395455,
-STORE, 140453237395456, 140453237399551,
-STORE, 140453237399552, 140453237403647,
-STORE, 140453237403648, 140453237547007,
-STORE, 140453237915648, 140453239599103,
-STORE, 140453239599104, 140453239615487,
-STORE, 140453239644160, 140453239648255,
-STORE, 140453239648256, 140453239652351,
-STORE, 140453239652352, 140453239656447,
-STORE, 140734679445504, 140734679584767,
-STORE, 140734680018944, 140734680031231,
-STORE, 140734680031232, 140734680035327,
-STORE, 94614776987648, 94614777200639,
-STORE, 94614779297792, 94614779301887,
-STORE, 94614779301888, 94614779310079,
-STORE, 94614779310080, 94614779322367,
-STORE, 94614798467072, 94614800699391,
-STORE, 139677037182976, 139677038841855,
-STORE, 139677038841856, 139677040939007,
-STORE, 139677040939008, 139677040955391,
-STORE, 139677040955392, 139677040963583,
-STORE, 139677040963584, 139677040979967,
-STORE, 139677040979968, 139677040992255,
-STORE, 139677040992256, 139677043085311,
-STORE, 139677043085312, 139677043089407,
-STORE, 139677043089408, 139677043093503,
-STORE, 139677043093504, 139677043236863,
-STORE, 139677043605504, 139677045288959,
-STORE, 139677045288960, 139677045305343,
-STORE, 139677045334016, 139677045338111,
-STORE, 139677045338112, 139677045342207,
-STORE, 139677045342208, 139677045346303,
-STORE, 140721604411392, 140721604550655,
-STORE, 140721606135808, 140721606148095,
-STORE, 140721606148096, 140721606152191,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140729280544768, 140737488351231,
-SNULL, 140729280552959, 140737488351231,
-STORE, 140729280544768, 140729280552959,
-STORE, 140729280413696, 140729280552959,
-STORE, 94863939334144, 94863941558271,
-SNULL, 94863939444735, 94863941558271,
-STORE, 94863939334144, 94863939444735,
-STORE, 94863939444736, 94863941558271,
-ERASE, 94863939444736, 94863941558271,
-STORE, 94863941537792, 94863941550079,
-STORE, 94863941550080, 94863941558271,
-STORE, 139691047276544, 139691049529343,
-SNULL, 139691047419903, 139691049529343,
-STORE, 139691047276544, 139691047419903,
-STORE, 139691047419904, 139691049529343,
-ERASE, 139691047419904, 139691049529343,
-STORE, 139691049517056, 139691049525247,
-STORE, 139691049525248, 139691049529343,
-STORE, 140729281679360, 140729281683455,
-STORE, 140729281667072, 140729281679359,
-STORE, 139691049488384, 139691049517055,
-STORE, 139691049480192, 139691049488383,
-STORE, 139691043479552, 139691047276543,
-SNULL, 139691043479552, 139691045138431,
-STORE, 139691045138432, 139691047276543,
-STORE, 139691043479552, 139691045138431,
-SNULL, 139691047235583, 139691047276543,
-STORE, 139691045138432, 139691047235583,
-STORE, 139691047235584, 139691047276543,
-SNULL, 139691047235584, 139691047260159,
-STORE, 139691047260160, 139691047276543,
-STORE, 139691047235584, 139691047260159,
-ERASE, 139691047235584, 139691047260159,
-STORE, 139691047235584, 139691047260159,
-ERASE, 139691047260160, 139691047276543,
-STORE, 139691047260160, 139691047276543,
-SNULL, 139691047251967, 139691047260159,
-STORE, 139691047235584, 139691047251967,
-STORE, 139691047251968, 139691047260159,
-SNULL, 94863941545983, 94863941550079,
-STORE, 94863941537792, 94863941545983,
-STORE, 94863941545984, 94863941550079,
-SNULL, 139691049521151, 139691049525247,
-STORE, 139691049517056, 139691049521151,
-STORE, 139691049521152, 139691049525247,
-ERASE, 139691049488384, 139691049517055,
-STORE, 94863951294464, 94863951429631,
-STORE, 93998209294336, 93998209507327,
-STORE, 93998211604480, 93998211608575,
-STORE, 93998211608576, 93998211616767,
-STORE, 93998211616768, 93998211629055,
-STORE, 93998227210240, 93998227615743,
-STORE, 140243029913600, 140243031572479,
-STORE, 140243031572480, 140243033669631,
-STORE, 140243033669632, 140243033686015,
-STORE, 140243033686016, 140243033694207,
-STORE, 140243033694208, 140243033710591,
-STORE, 140243033710592, 140243033722879,
-STORE, 140243033722880, 140243035815935,
-STORE, 140243035815936, 140243035820031,
-STORE, 140243035820032, 140243035824127,
-STORE, 140243035824128, 140243035967487,
-STORE, 140243036336128, 140243038019583,
-STORE, 140243038019584, 140243038035967,
-STORE, 140243038064640, 140243038068735,
-STORE, 140243038068736, 140243038072831,
-STORE, 140243038072832, 140243038076927,
-STORE, 140734976479232, 140734976618495,
-STORE, 140734977978368, 140734977990655,
-STORE, 140734977990656, 140734977994751,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722742775808, 140737488351231,
-SNULL, 140722742783999, 140737488351231,
-STORE, 140722742775808, 140722742783999,
-STORE, 140722742644736, 140722742783999,
-STORE, 93857673662464, 93857675997183,
-SNULL, 93857673875455, 93857675997183,
-STORE, 93857673662464, 93857673875455,
-STORE, 93857673875456, 93857675997183,
-ERASE, 93857673875456, 93857675997183,
-STORE, 93857675972608, 93857675984895,
-STORE, 93857675984896, 93857675997183,
-STORE, 140629677498368, 140629679751167,
-SNULL, 140629677641727, 140629679751167,
-STORE, 140629677498368, 140629677641727,
-STORE, 140629677641728, 140629679751167,
-ERASE, 140629677641728, 140629679751167,
-STORE, 140629679738880, 140629679747071,
-STORE, 140629679747072, 140629679751167,
-STORE, 140722743222272, 140722743226367,
-STORE, 140722743209984, 140722743222271,
-STORE, 140629679710208, 140629679738879,
-STORE, 140629679702016, 140629679710207,
-STORE, 140629675384832, 140629677498367,
-SNULL, 140629675384832, 140629675397119,
-STORE, 140629675397120, 140629677498367,
-STORE, 140629675384832, 140629675397119,
-SNULL, 140629677490175, 140629677498367,
-STORE, 140629675397120, 140629677490175,
-STORE, 140629677490176, 140629677498367,
-ERASE, 140629677490176, 140629677498367,
-STORE, 140629677490176, 140629677498367,
-STORE, 140629671587840, 140629675384831,
-SNULL, 140629671587840, 140629673246719,
-STORE, 140629673246720, 140629675384831,
-STORE, 140629671587840, 140629673246719,
-SNULL, 140629675343871, 140629675384831,
-STORE, 140629673246720, 140629675343871,
-STORE, 140629675343872, 140629675384831,
-SNULL, 140629675343872, 140629675368447,
-STORE, 140629675368448, 140629675384831,
-STORE, 140629675343872, 140629675368447,
-ERASE, 140629675343872, 140629675368447,
-STORE, 140629675343872, 140629675368447,
-ERASE, 140629675368448, 140629675384831,
-STORE, 140629675368448, 140629675384831,
-STORE, 140629679693824, 140629679710207,
-SNULL, 140629675360255, 140629675368447,
-STORE, 140629675343872, 140629675360255,
-STORE, 140629675360256, 140629675368447,
-SNULL, 140629677494271, 140629677498367,
-STORE, 140629677490176, 140629677494271,
-STORE, 140629677494272, 140629677498367,
-SNULL, 93857675976703, 93857675984895,
-STORE, 93857675972608, 93857675976703,
-STORE, 93857675976704, 93857675984895,
-SNULL, 140629679742975, 140629679747071,
-STORE, 140629679738880, 140629679742975,
-STORE, 140629679742976, 140629679747071,
-ERASE, 140629679710208, 140629679738879,
-STORE, 93857705832448, 93857705967615,
-STORE, 140629678010368, 140629679693823,
-STORE, 93857705832448, 93857706102783,
-STORE, 93857705832448, 93857706237951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735922421760, 140737488351231,
-SNULL, 140735922429951, 140737488351231,
-STORE, 140735922421760, 140735922429951,
-STORE, 140735922290688, 140735922429951,
-STORE, 94651136139264, 94651138363391,
-SNULL, 94651136249855, 94651138363391,
-STORE, 94651136139264, 94651136249855,
-STORE, 94651136249856, 94651138363391,
-ERASE, 94651136249856, 94651138363391,
-STORE, 94651138342912, 94651138355199,
-STORE, 94651138355200, 94651138363391,
-STORE, 140325788266496, 140325790519295,
-SNULL, 140325788409855, 140325790519295,
-STORE, 140325788266496, 140325788409855,
-STORE, 140325788409856, 140325790519295,
-ERASE, 140325788409856, 140325790519295,
-STORE, 140325790507008, 140325790515199,
-STORE, 140325790515200, 140325790519295,
-STORE, 140735923572736, 140735923576831,
-STORE, 140735923560448, 140735923572735,
-STORE, 140325790478336, 140325790507007,
-STORE, 140325790470144, 140325790478335,
-STORE, 140325784469504, 140325788266495,
-SNULL, 140325784469504, 140325786128383,
-STORE, 140325786128384, 140325788266495,
-STORE, 140325784469504, 140325786128383,
-SNULL, 140325788225535, 140325788266495,
-STORE, 140325786128384, 140325788225535,
-STORE, 140325788225536, 140325788266495,
-SNULL, 140325788225536, 140325788250111,
-STORE, 140325788250112, 140325788266495,
-STORE, 140325788225536, 140325788250111,
-ERASE, 140325788225536, 140325788250111,
-STORE, 140325788225536, 140325788250111,
-ERASE, 140325788250112, 140325788266495,
-STORE, 140325788250112, 140325788266495,
-SNULL, 140325788241919, 140325788250111,
-STORE, 140325788225536, 140325788241919,
-STORE, 140325788241920, 140325788250111,
-SNULL, 94651138351103, 94651138355199,
-STORE, 94651138342912, 94651138351103,
-STORE, 94651138351104, 94651138355199,
-SNULL, 140325790511103, 140325790515199,
-STORE, 140325790507008, 140325790511103,
-STORE, 140325790511104, 140325790515199,
-ERASE, 140325790478336, 140325790507007,
-STORE, 94651146297344, 94651146432511,
-STORE, 94212330168320, 94212330381311,
-STORE, 94212332478464, 94212332482559,
-STORE, 94212332482560, 94212332490751,
-STORE, 94212332490752, 94212332503039,
-STORE, 94212348891136, 94212349825023,
-STORE, 140611630604288, 140611632263167,
-STORE, 140611632263168, 140611634360319,
-STORE, 140611634360320, 140611634376703,
-STORE, 140611634376704, 140611634384895,
-STORE, 140611634384896, 140611634401279,
-STORE, 140611634401280, 140611634413567,
-STORE, 140611634413568, 140611636506623,
-STORE, 140611636506624, 140611636510719,
-STORE, 140611636510720, 140611636514815,
-STORE, 140611636514816, 140611636658175,
-STORE, 140611637026816, 140611638710271,
-STORE, 140611638710272, 140611638726655,
-STORE, 140611638755328, 140611638759423,
-STORE, 140611638759424, 140611638763519,
-STORE, 140611638763520, 140611638767615,
-STORE, 140726974533632, 140726974672895,
-STORE, 140726974943232, 140726974955519,
-STORE, 140726974955520, 140726974959615,
-STORE, 94572463521792, 94572463734783,
-STORE, 94572465831936, 94572465836031,
-STORE, 94572465836032, 94572465844223,
-STORE, 94572465844224, 94572465856511,
-STORE, 94572491534336, 94572492865535,
-STORE, 140644351492096, 140644353150975,
-STORE, 140644353150976, 140644355248127,
-STORE, 140644355248128, 140644355264511,
-STORE, 140644355264512, 140644355272703,
-STORE, 140644355272704, 140644355289087,
-STORE, 140644355289088, 140644355301375,
-STORE, 140644355301376, 140644357394431,
-STORE, 140644357394432, 140644357398527,
-STORE, 140644357398528, 140644357402623,
-STORE, 140644357402624, 140644357545983,
-STORE, 140644357914624, 140644359598079,
-STORE, 140644359598080, 140644359614463,
-STORE, 140644359643136, 140644359647231,
-STORE, 140644359647232, 140644359651327,
-STORE, 140644359651328, 140644359655423,
-STORE, 140727841824768, 140727841964031,
-STORE, 140727843188736, 140727843201023,
-STORE, 140727843201024, 140727843205119,
-STORE, 94144315457536, 94144315670527,
-STORE, 94144317767680, 94144317771775,
-STORE, 94144317771776, 94144317779967,
-STORE, 94144317779968, 94144317792255,
-STORE, 94144318369792, 94144320815103,
-STORE, 140316717645824, 140316719304703,
-STORE, 140316719304704, 140316721401855,
-STORE, 140316721401856, 140316721418239,
-STORE, 140316721418240, 140316721426431,
-STORE, 140316721426432, 140316721442815,
-STORE, 140316721442816, 140316721455103,
-STORE, 140316721455104, 140316723548159,
-STORE, 140316723548160, 140316723552255,
-STORE, 140316723552256, 140316723556351,
-STORE, 140316723556352, 140316723699711,
-STORE, 140316724068352, 140316725751807,
-STORE, 140316725751808, 140316725768191,
-STORE, 140316725796864, 140316725800959,
-STORE, 140316725800960, 140316725805055,
-STORE, 140316725805056, 140316725809151,
-STORE, 140725744283648, 140725744422911,
-STORE, 140725745852416, 140725745864703,
-STORE, 140725745864704, 140725745868799,
-STORE, 94646858846208, 94646859059199,
-STORE, 94646861156352, 94646861160447,
-STORE, 94646861160448, 94646861168639,
-STORE, 94646861168640, 94646861180927,
-STORE, 94646879805440, 94646881894399,
-STORE, 140435449745408, 140435451404287,
-STORE, 140435451404288, 140435453501439,
-STORE, 140435453501440, 140435453517823,
-STORE, 140435453517824, 140435453526015,
-STORE, 140435453526016, 140435453542399,
-STORE, 140435453542400, 140435453554687,
-STORE, 140435453554688, 140435455647743,
-STORE, 140435455647744, 140435455651839,
-STORE, 140435455651840, 140435455655935,
-STORE, 140435455655936, 140435455799295,
-STORE, 140435456167936, 140435457851391,
-STORE, 140435457851392, 140435457867775,
-STORE, 140435457896448, 140435457900543,
-STORE, 140435457900544, 140435457904639,
-STORE, 140435457904640, 140435457908735,
-STORE, 140721033818112, 140721033957375,
-STORE, 140721034018816, 140721034031103,
-STORE, 140721034031104, 140721034035199,
-STORE, 94872903438336, 94872903651327,
-STORE, 94872905748480, 94872905752575,
-STORE, 94872905752576, 94872905760767,
-STORE, 94872905760768, 94872905773055,
-STORE, 94872931246080, 94872931651583,
-STORE, 139771607810048, 139771609468927,
-STORE, 139771609468928, 139771611566079,
-STORE, 139771611566080, 139771611582463,
-STORE, 139771611582464, 139771611590655,
-STORE, 139771611590656, 139771611607039,
-STORE, 139771611607040, 139771611619327,
-STORE, 139771611619328, 139771613712383,
-STORE, 139771613712384, 139771613716479,
-STORE, 139771613716480, 139771613720575,
-STORE, 139771613720576, 139771613863935,
-STORE, 139771614232576, 139771615916031,
-STORE, 139771615916032, 139771615932415,
-STORE, 139771615961088, 139771615965183,
-STORE, 139771615965184, 139771615969279,
-STORE, 139771615969280, 139771615973375,
-STORE, 140725402931200, 140725403070463,
-STORE, 140725403852800, 140725403865087,
-STORE, 140725403865088, 140725403869183,
-STORE, 94740737736704, 94740737949695,
-STORE, 94740740046848, 94740740050943,
-STORE, 94740740050944, 94740740059135,
-STORE, 94740740059136, 94740740071423,
-STORE, 94740743249920, 94740744724479,
-STORE, 140640287010816, 140640288669695,
-STORE, 140640288669696, 140640290766847,
-STORE, 140640290766848, 140640290783231,
-STORE, 140640290783232, 140640290791423,
-STORE, 140640290791424, 140640290807807,
-STORE, 140640290807808, 140640290820095,
-STORE, 140640290820096, 140640292913151,
-STORE, 140640292913152, 140640292917247,
-STORE, 140640292917248, 140640292921343,
-STORE, 140640292921344, 140640293064703,
-STORE, 140640293433344, 140640295116799,
-STORE, 140640295116800, 140640295133183,
-STORE, 140640295161856, 140640295165951,
-STORE, 140640295165952, 140640295170047,
-STORE, 140640295170048, 140640295174143,
-STORE, 140725133303808, 140725133443071,
-STORE, 140725133684736, 140725133697023,
-STORE, 140725133697024, 140725133701119,
-STORE, 140737488347136, 140737488351231,
-STORE, 140722826371072, 140737488351231,
-SNULL, 140722826375167, 140737488351231,
-STORE, 140722826371072, 140722826375167,
-STORE, 140722826240000, 140722826375167,
-STORE, 94113818611712, 94113820835839,
-SNULL, 94113818722303, 94113820835839,
-STORE, 94113818611712, 94113818722303,
-STORE, 94113818722304, 94113820835839,
-ERASE, 94113818722304, 94113820835839,
-STORE, 94113820815360, 94113820827647,
-STORE, 94113820827648, 94113820835839,
-STORE, 139628194508800, 139628196761599,
-SNULL, 139628194652159, 139628196761599,
-STORE, 139628194508800, 139628194652159,
-STORE, 139628194652160, 139628196761599,
-ERASE, 139628194652160, 139628196761599,
-STORE, 139628196749312, 139628196757503,
-STORE, 139628196757504, 139628196761599,
-STORE, 140722826727424, 140722826731519,
-STORE, 140722826715136, 140722826727423,
-STORE, 139628196720640, 139628196749311,
-STORE, 139628196712448, 139628196720639,
-STORE, 139628190711808, 139628194508799,
-SNULL, 139628190711808, 139628192370687,
-STORE, 139628192370688, 139628194508799,
-STORE, 139628190711808, 139628192370687,
-SNULL, 139628194467839, 139628194508799,
-STORE, 139628192370688, 139628194467839,
-STORE, 139628194467840, 139628194508799,
-SNULL, 139628194467840, 139628194492415,
-STORE, 139628194492416, 139628194508799,
-STORE, 139628194467840, 139628194492415,
-ERASE, 139628194467840, 139628194492415,
-STORE, 139628194467840, 139628194492415,
-ERASE, 139628194492416, 139628194508799,
-STORE, 139628194492416, 139628194508799,
-SNULL, 139628194484223, 139628194492415,
-STORE, 139628194467840, 139628194484223,
-STORE, 139628194484224, 139628194492415,
-SNULL, 94113820823551, 94113820827647,
-STORE, 94113820815360, 94113820823551,
-STORE, 94113820823552, 94113820827647,
-SNULL, 139628196753407, 139628196757503,
-STORE, 139628196749312, 139628196753407,
-STORE, 139628196753408, 139628196757503,
-ERASE, 139628196720640, 139628196749311,
-STORE, 94113830850560, 94113830985727,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731865833472, 140737488351231,
-SNULL, 140731865841663, 140737488351231,
-STORE, 140731865833472, 140731865841663,
-STORE, 140731865702400, 140731865841663,
-STORE, 94763339386880, 94763341611007,
-SNULL, 94763339497471, 94763341611007,
-STORE, 94763339386880, 94763339497471,
-STORE, 94763339497472, 94763341611007,
-ERASE, 94763339497472, 94763341611007,
-STORE, 94763341590528, 94763341602815,
-STORE, 94763341602816, 94763341611007,
-STORE, 139778398486528, 139778400739327,
-SNULL, 139778398629887, 139778400739327,
-STORE, 139778398486528, 139778398629887,
-STORE, 139778398629888, 139778400739327,
-ERASE, 139778398629888, 139778400739327,
-STORE, 139778400727040, 139778400735231,
-STORE, 139778400735232, 139778400739327,
-STORE, 140731865858048, 140731865862143,
-STORE, 140731865845760, 140731865858047,
-STORE, 139778400698368, 139778400727039,
-STORE, 139778400690176, 139778400698367,
-STORE, 139778394689536, 139778398486527,
-SNULL, 139778394689536, 139778396348415,
-STORE, 139778396348416, 139778398486527,
-STORE, 139778394689536, 139778396348415,
-SNULL, 139778398445567, 139778398486527,
-STORE, 139778396348416, 139778398445567,
-STORE, 139778398445568, 139778398486527,
-SNULL, 139778398445568, 139778398470143,
-STORE, 139778398470144, 139778398486527,
-STORE, 139778398445568, 139778398470143,
-ERASE, 139778398445568, 139778398470143,
-STORE, 139778398445568, 139778398470143,
-ERASE, 139778398470144, 139778398486527,
-STORE, 139778398470144, 139778398486527,
-SNULL, 139778398461951, 139778398470143,
-STORE, 139778398445568, 139778398461951,
-STORE, 139778398461952, 139778398470143,
-SNULL, 94763341598719, 94763341602815,
-STORE, 94763341590528, 94763341598719,
-STORE, 94763341598720, 94763341602815,
-SNULL, 139778400731135, 139778400735231,
-STORE, 139778400727040, 139778400731135,
-STORE, 139778400731136, 139778400735231,
-ERASE, 139778400698368, 139778400727039,
-STORE, 94763362197504, 94763362332671,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140737488338944, 140737488351231,
-STORE, 140732053192704, 140737488351231,
-SNULL, 140732053204991, 140737488351231,
-STORE, 140732053192704, 140732053204991,
-STORE, 140732053061632, 140732053204991,
-STORE, 4194304, 26279935,
-STORE, 28372992, 28454911,
-STORE, 28454912, 29806591,
-STORE, 140176018599936, 140176020852735,
-SNULL, 140176018743295, 140176020852735,
-STORE, 140176018599936, 140176018743295,
-STORE, 140176018743296, 140176020852735,
-ERASE, 140176018743296, 140176020852735,
-STORE, 140176020840448, 140176020848639,
-STORE, 140176020848640, 140176020852735,
-STORE, 140732053381120, 140732053385215,
-STORE, 140732053368832, 140732053381119,
-STORE, 140176020811776, 140176020840447,
-STORE, 140176020803584, 140176020811775,
-STORE, 140176014766080, 140176018599935,
-SNULL, 140176014766080, 140176016474111,
-STORE, 140176016474112, 140176018599935,
-STORE, 140176014766080, 140176016474111,
-SNULL, 140176018567167, 140176018599935,
-STORE, 140176016474112, 140176018567167,
-STORE, 140176018567168, 140176018599935,
-ERASE, 140176018567168, 140176018599935,
-STORE, 140176018567168, 140176018599935,
-STORE, 140176012570624, 140176014766079,
-SNULL, 140176012570624, 140176012664831,
-STORE, 140176012664832, 140176014766079,
-STORE, 140176012570624, 140176012664831,
-SNULL, 140176014757887, 140176014766079,
-STORE, 140176012664832, 140176014757887,
-STORE, 140176014757888, 140176014766079,
-ERASE, 140176014757888, 140176014766079,
-STORE, 140176014757888, 140176014766079,
-STORE, 140176010051584, 140176012570623,
-SNULL, 140176010051584, 140176010465279,
-STORE, 140176010465280, 140176012570623,
-STORE, 140176010051584, 140176010465279,
-SNULL, 140176012558335, 140176012570623,
-STORE, 140176010465280, 140176012558335,
-STORE, 140176012558336, 140176012570623,
-ERASE, 140176012558336, 140176012570623,
-STORE, 140176012558336, 140176012570623,
-STORE, 140176007417856, 140176010051583,
-SNULL, 140176007417856, 140176007946239,
-STORE, 140176007946240, 140176010051583,
-STORE, 140176007417856, 140176007946239,
-SNULL, 140176010043391, 140176010051583,
-STORE, 140176007946240, 140176010043391,
-STORE, 140176010043392, 140176010051583,
-ERASE, 140176010043392, 140176010051583,
-STORE, 140176010043392, 140176010051583,
-STORE, 140176005304320, 140176007417855,
-SNULL, 140176005304320, 140176005316607,
-STORE, 140176005316608, 140176007417855,
-STORE, 140176005304320, 140176005316607,
-SNULL, 140176007409663, 140176007417855,
-STORE, 140176005316608, 140176007409663,
-STORE, 140176007409664, 140176007417855,
-ERASE, 140176007409664, 140176007417855,
-STORE, 140176007409664, 140176007417855,
-STORE, 140176003100672, 140176005304319,
-SNULL, 140176003100672, 140176003203071,
-STORE, 140176003203072, 140176005304319,
-STORE, 140176003100672, 140176003203071,
-SNULL, 140176005296127, 140176005304319,
-STORE, 140176003203072, 140176005296127,
-STORE, 140176005296128, 140176005304319,
-ERASE, 140176005296128, 140176005304319,
-STORE, 140176005296128, 140176005304319,
-STORE, 140176020795392, 140176020811775,
-STORE, 140175999938560, 140176003100671,
-SNULL, 140175999938560, 140176000999423,
-STORE, 140176000999424, 140176003100671,
-STORE, 140175999938560, 140176000999423,
-SNULL, 140176003092479, 140176003100671,
-STORE, 140176000999424, 140176003092479,
-STORE, 140176003092480, 140176003100671,
-ERASE, 140176003092480, 140176003100671,
-STORE, 140176003092480, 140176003100671,
-STORE, 140175996141568, 140175999938559,
-SNULL, 140175996141568, 140175997800447,
-STORE, 140175997800448, 140175999938559,
-STORE, 140175996141568, 140175997800447,
-SNULL, 140175999897599, 140175999938559,
-STORE, 140175997800448, 140175999897599,
-STORE, 140175999897600, 140175999938559,
-SNULL, 140175999897600, 140175999922175,
-STORE, 140175999922176, 140175999938559,
-STORE, 140175999897600, 140175999922175,
-ERASE, 140175999897600, 140175999922175,
-STORE, 140175999897600, 140175999922175,
-ERASE, 140175999922176, 140175999938559,
-STORE, 140175999922176, 140175999938559,
-STORE, 140176020783104, 140176020811775,
-SNULL, 140175999913983, 140175999922175,
-STORE, 140175999897600, 140175999913983,
-STORE, 140175999913984, 140175999922175,
-SNULL, 140176003096575, 140176003100671,
-STORE, 140176003092480, 140176003096575,
-STORE, 140176003096576, 140176003100671,
-SNULL, 140176005300223, 140176005304319,
-STORE, 140176005296128, 140176005300223,
-STORE, 140176005300224, 140176005304319,
-SNULL, 140176007413759, 140176007417855,
-STORE, 140176007409664, 140176007413759,
-STORE, 140176007413760, 140176007417855,
-SNULL, 140176010047487, 140176010051583,
-STORE, 140176010043392, 140176010047487,
-STORE, 140176010047488, 140176010051583,
-SNULL, 140176012566527, 140176012570623,
-STORE, 140176012558336, 140176012566527,
-STORE, 140176012566528, 140176012570623,
-SNULL, 140176014761983, 140176014766079,
-STORE, 140176014757888, 140176014761983,
-STORE, 140176014761984, 140176014766079,
-SNULL, 140176018571263, 140176018599935,
-STORE, 140176018567168, 140176018571263,
-STORE, 140176018571264, 140176018599935,
-SNULL, 28405759, 28454911,
-STORE, 28372992, 28405759,
-STORE, 28405760, 28454911,
-SNULL, 140176020844543, 140176020848639,
-STORE, 140176020840448, 140176020844543,
-STORE, 140176020844544, 140176020848639,
-ERASE, 140176020811776, 140176020840447,
-STORE, 53080064, 53215231,
-STORE, 140176019099648, 140176020783103,
-STORE, 140176020836352, 140176020840447,
-STORE, 140176018964480, 140176019099647,
-STORE, 53080064, 53358591,
-STORE, 140175994044416, 140175996141567,
-STORE, 140176020828160, 140176020840447,
-STORE, 140176020819968, 140176020840447,
-STORE, 140176020783104, 140176020819967,
-STORE, 140176018948096, 140176019099647,
-STORE, 53080064, 53493759,
-STORE, 53080064, 53649407,
-STORE, 140176018939904, 140176019099647,
-STORE, 140176018931712, 140176019099647,
-STORE, 53080064, 53784575,
-STORE, 53080064, 53919743,
-STORE, 140176018915328, 140176019099647,
-STORE, 140176018907136, 140176019099647,
-STORE, 53080064, 54059007,
-STORE, 140175993769984, 140175996141567,
-STORE, 140176018747392, 140176019099647,
-STORE, 53080064, 54198271,
-SNULL, 54190079, 54198271,
-STORE, 53080064, 54190079,
-STORE, 54190080, 54198271,
-ERASE, 54190080, 54198271,
-SNULL, 54181887, 54190079,
-STORE, 53080064, 54181887,
-STORE, 54181888, 54190079,
-ERASE, 54181888, 54190079,
-SNULL, 54173695, 54181887,
-STORE, 53080064, 54173695,
-STORE, 54173696, 54181887,
-ERASE, 54173696, 54181887,
-SNULL, 54165503, 54173695,
-STORE, 53080064, 54165503,
-STORE, 54165504, 54173695,
-ERASE, 54165504, 54173695,
-STORE, 140175993753600, 140175996141567,
-STORE, 140175993688064, 140175996141567,
-STORE, 140175993655296, 140175996141567,
-STORE, 140175991558144, 140175996141567,
-STORE, 140175991492608, 140175996141567,
-STORE, 53080064, 54312959,
-STORE, 140175991361536, 140175996141567,
-STORE, 140175991099392, 140175996141567,
-STORE, 140175991091200, 140175996141567,
-STORE, 140175991074816, 140175996141567,
-STORE, 140175991066624, 140175996141567,
-STORE, 140175991058432, 140175996141567,
-STORE, 53080064, 54448127,
-SNULL, 54439935, 54448127,
-STORE, 53080064, 54439935,
-STORE, 54439936, 54448127,
-ERASE, 54439936, 54448127,
-SNULL, 54431743, 54439935,
-STORE, 53080064, 54431743,
-STORE, 54431744, 54439935,
-ERASE, 54431744, 54439935,
-SNULL, 54419455, 54431743,
-STORE, 53080064, 54419455,
-STORE, 54419456, 54431743,
-ERASE, 54419456, 54431743,
-SNULL, 54403071, 54419455,
-STORE, 53080064, 54403071,
-STORE, 54403072, 54419455,
-ERASE, 54403072, 54419455,
-STORE, 140175991042048, 140175996141567,
-STORE, 53080064, 54538239,
-SNULL, 54534143, 54538239,
-STORE, 53080064, 54534143,
-STORE, 54534144, 54538239,
-ERASE, 54534144, 54538239,
-SNULL, 54530047, 54534143,
-STORE, 53080064, 54530047,
-STORE, 54530048, 54534143,
-ERASE, 54530048, 54534143,
-SNULL, 54525951, 54530047,
-STORE, 53080064, 54525951,
-STORE, 54525952, 54530047,
-ERASE, 54525952, 54530047,
-SNULL, 54521855, 54525951,
-STORE, 53080064, 54521855,
-STORE, 54521856, 54525951,
-ERASE, 54521856, 54525951,
-SNULL, 54517759, 54521855,
-STORE, 53080064, 54517759,
-STORE, 54517760, 54521855,
-ERASE, 54517760, 54521855,
-SNULL, 54513663, 54517759,
-STORE, 53080064, 54513663,
-STORE, 54513664, 54517759,
-ERASE, 54513664, 54517759,
-SNULL, 54509567, 54513663,
-STORE, 53080064, 54509567,
-STORE, 54509568, 54513663,
-ERASE, 54509568, 54513663,
-STORE, 140175991025664, 140175996141567,
-STORE, 140175990992896, 140175996141567,
-STORE, 53080064, 54644735,
-SNULL, 54628351, 54644735,
-STORE, 53080064, 54628351,
-STORE, 54628352, 54644735,
-ERASE, 54628352, 54644735,
-SNULL, 54616063, 54628351,
-STORE, 53080064, 54616063,
-STORE, 54616064, 54628351,
-ERASE, 54616064, 54628351,
-STORE, 140175988895744, 140175996141567,
-STORE, 53080064, 54767615,
-STORE, 140175988879360, 140175996141567,
-STORE, 140175988617216, 140175996141567,
-STORE, 140175988609024, 140175996141567,
-STORE, 140175988600832, 140175996141567,
-STORE, 53080064, 54906879,
-SNULL, 54898687, 54906879,
-STORE, 53080064, 54898687,
-STORE, 54898688, 54906879,
-ERASE, 54898688, 54906879,
-SNULL, 54853631, 54898687,
-STORE, 53080064, 54853631,
-STORE, 54853632, 54898687,
-ERASE, 54853632, 54898687,
-STORE, 140175986503680, 140175996141567,
-STORE, 53080064, 54996991,
-STORE, 140175986495488, 140175996141567,
-STORE, 140175986487296, 140175996141567,
-STORE, 140175985438720, 140175996141567,
-STORE, 53080064, 55136255,
-STORE, 140175985405952, 140175996141567,
-STORE, 140175985139712, 140175996141567,
-SNULL, 140176018964479, 140176019099647,
-STORE, 140176018747392, 140176018964479,
-STORE, 140176018964480, 140176019099647,
-ERASE, 140176018964480, 140176019099647,
-STORE, 140175983042560, 140175996141567,
-STORE, 140175982518272, 140175996141567,
-STORE, 140175980421120, 140175996141567,
-STORE, 53080064, 55287807,
-STORE, 53080064, 55427071,
-STORE, 140176019091456, 140176019099647,
-STORE, 140176019083264, 140176019099647,
-STORE, 140176019075072, 140176019099647,
-STORE, 140176019066880, 140176019099647,
-STORE, 140176019058688, 140176019099647,
-STORE, 140175980158976, 140175996141567,
-STORE, 140176019050496, 140176019099647,
-STORE, 140176019042304, 140176019099647,
-STORE, 140176019034112, 140176019099647,
-STORE, 140176019025920, 140176019099647,
-STORE, 140176019017728, 140176019099647,
-STORE, 140176019009536, 140176019099647,
-STORE, 140176019001344, 140176019099647,
-STORE, 140176018993152, 140176019099647,
-STORE, 140176018984960, 140176019099647,
-STORE, 140176018976768, 140176019099647,
-STORE, 140176018968576, 140176019099647,
-STORE, 140175978061824, 140175996141567,
-STORE, 53080064, 55603199,
-STORE, 140175978029056, 140175996141567,
-STORE, 140175977996288, 140175996141567,
-STORE, 53080064, 55738367,
-STORE, 53080064, 55881727,
-STORE, 140175977963520, 140175996141567,
-STORE, 140175977930752, 140175996141567,
-STORE, 53080064, 56041471,
-STORE, 140175977897984, 140175996141567,
-STORE, 140175977865216, 140175996141567,
-SNULL, 55881727, 56041471,
-STORE, 53080064, 55881727,
-STORE, 55881728, 56041471,
-ERASE, 55881728, 56041471,
-SNULL, 55721983, 55881727,
-STORE, 53080064, 55721983,
-STORE, 55721984, 55881727,
-ERASE, 55721984, 55881727,
-SNULL, 55570431, 55721983,
-STORE, 53080064, 55570431,
-STORE, 55570432, 55721983,
-ERASE, 55570432, 55721983,
-STORE, 140175977857024, 140175996141567,
-STORE, 140175975759872, 140175996141567,
-STORE, 53080064, 55754751,
-STORE, 53080064, 55943167,
-STORE, 140175975751680, 140175996141567,
-STORE, 140175975743488, 140175996141567,
-STORE, 140175975735296, 140175996141567,
-STORE, 140175975727104, 140175996141567,
-STORE, 140175975718912, 140175996141567,
-STORE, 140175975710720, 140175996141567,
-STORE, 140175975702528, 140175996141567,
-STORE, 140175975694336, 140175996141567,
-STORE, 140175975686144, 140175996141567,
-STORE, 140175975677952, 140175996141567,
-STORE, 140175975669760, 140175996141567,
-STORE, 140175974621184, 140175996141567,
-STORE, 140175974612992, 140175996141567,
-STORE, 53080064, 56139775,
-STORE, 140175972515840, 140175996141567,
-STORE, 53080064, 56401919,
-STORE, 140175970418688, 140175996141567,
-STORE, 140175970410496, 140175996141567,
-STORE, 140175970402304, 140175996141567,
-STORE, 140175970394112, 140175996141567,
-STORE, 53080064, 56569855,
-STORE, 140175969865728, 140175996141567,
-SNULL, 140175985139711, 140175996141567,
-STORE, 140175969865728, 140175985139711,
-STORE, 140175985139712, 140175996141567,
-SNULL, 140175985139712, 140175985405951,
-STORE, 140175985405952, 140175996141567,
-STORE, 140175985139712, 140175985405951,
-ERASE, 140175985139712, 140175985405951,
-STORE, 140175965671424, 140175985139711,
-STORE, 140175985397760, 140175996141567,
-STORE, 140175985389568, 140175996141567,
-STORE, 140175985381376, 140175996141567,
-STORE, 140175985373184, 140175996141567,
-STORE, 140175985364992, 140175996141567,
-STORE, 140175985356800, 140175996141567,
-STORE, 140175985348608, 140175996141567,
-STORE, 140175985340416, 140175996141567,
-STORE, 140175985332224, 140175996141567,
-STORE, 140175985324032, 140175996141567,
-STORE, 140175985315840, 140175996141567,
-STORE, 140175985307648, 140175996141567,
-STORE, 140175985299456, 140175996141567,
-STORE, 140175985291264, 140175996141567,
-STORE, 140175985283072, 140175996141567,
-STORE, 140175985274880, 140175996141567,
-STORE, 140175963574272, 140175985139711,
-STORE, 140175985266688, 140175996141567,
-STORE, 140175961477120, 140175985139711,
-STORE, 53080064, 56831999,
-STORE, 140175959379968, 140175985139711,
-STORE, 140175985258496, 140175996141567,
-STORE, 140175957282816, 140175985139711,
-STORE, 140175985250304, 140175996141567,
-STORE, 140175985242112, 140175996141567,
-STORE, 140175985233920, 140175996141567,
-STORE, 140175985225728, 140175996141567,
-STORE, 140175985217536, 140175996141567,
-STORE, 140175957151744, 140175985139711,
-STORE, 140175956627456, 140175985139711,
-SNULL, 140175980158975, 140175985139711,
-STORE, 140175956627456, 140175980158975,
-STORE, 140175980158976, 140175985139711,
-SNULL, 140175980158976, 140175980421119,
-STORE, 140175980421120, 140175985139711,
-STORE, 140175980158976, 140175980421119,
-ERASE, 140175980158976, 140175980421119,
-STORE, 140175954530304, 140175980158975,
-STORE, 140175985209344, 140175996141567,
-STORE, 53080064, 57094143,
-STORE, 140175952433152, 140175980158975,
-STORE, 140175985192960, 140175996141567,
-STORE, 140175985184768, 140175996141567,
-STORE, 140175985176576, 140175996141567,
-STORE, 140175985168384, 140175996141567,
-STORE, 140175985160192, 140175996141567,
-STORE, 140175985152000, 140175996141567,
-STORE, 140175985143808, 140175996141567,
-STORE, 140175980412928, 140175985139711,
-STORE, 140175980404736, 140175985139711,
-STORE, 140175980396544, 140175985139711,
-STORE, 140175980388352, 140175985139711,
-STORE, 140175980380160, 140175985139711,
-STORE, 140175980371968, 140175985139711,
-STORE, 140175980363776, 140175985139711,
-STORE, 140175980355584, 140175985139711,
-STORE, 140175980347392, 140175985139711,
-STORE, 140175980339200, 140175985139711,
-STORE, 53080064, 57356287,
-SNULL, 140176018747392, 140176018907135,
-STORE, 140176018907136, 140176018964479,
-STORE, 140176018747392, 140176018907135,
-ERASE, 140176018747392, 140176018907135,
-STORE, 140175952146432, 140175980158975,
-STORE, 140175950049280, 140175980158975,
-SNULL, 140175952146431, 140175980158975,
-STORE, 140175950049280, 140175952146431,
-STORE, 140175952146432, 140175980158975,
-SNULL, 140175952146432, 140175952433151,
-STORE, 140175952433152, 140175980158975,
-STORE, 140175952146432, 140175952433151,
-ERASE, 140175952146432, 140175952433151,
-STORE, 140176018898944, 140176018964479,
-STORE, 53080064, 57749503,
-STORE, 140175949520896, 140175952146431,
-STORE, 140175947423744, 140175952146431,
-SNULL, 140175993769983, 140175996141567,
-STORE, 140175985143808, 140175993769983,
-STORE, 140175993769984, 140175996141567,
-SNULL, 140175993769984, 140175994044415,
-STORE, 140175994044416, 140175996141567,
-STORE, 140175993769984, 140175994044415,
-ERASE, 140175993769984, 140175994044415,
-STORE, 140176018890752, 140176018964479,
-STORE, 140176018882560, 140176018964479,
-STORE, 140176018874368, 140176018964479,
-STORE, 140176018866176, 140176018964479,
-STORE, 140176018849792, 140176018964479,
-STORE, 140176018841600, 140176018964479,
-STORE, 140176018825216, 140176018964479,
-STORE, 140176018817024, 140176018964479,
-STORE, 140176018800640, 140176018964479,
-STORE, 140176018792448, 140176018964479,
-STORE, 140176018759680, 140176018964479,
-STORE, 140176018751488, 140176018964479,
-STORE, 140175994028032, 140175996141567,
-STORE, 140176018743296, 140176018964479,
-STORE, 140175994011648, 140175996141567,
-STORE, 140175994003456, 140175996141567,
-STORE, 140175993987072, 140175996141567,
-STORE, 140175993978880, 140175996141567,
-STORE, 140175993946112, 140175996141567,
-STORE, 140175993937920, 140175996141567,
-STORE, 140175993921536, 140175996141567,
-STORE, 140175993913344, 140175996141567,
-STORE, 140175993896960, 140175996141567,
-STORE, 140175993888768, 140175996141567,
-STORE, 140175993872384, 140175996141567,
-STORE, 140175993864192, 140175996141567,
-STORE, 140175993831424, 140175996141567,
-STORE, 140175993823232, 140175996141567,
-STORE, 140175993806848, 140175996141567,
-STORE, 140175993798656, 140175996141567,
-STORE, 140175993782272, 140175996141567,
-STORE, 140175993774080, 140175996141567,
-STORE, 140175980322816, 140175985139711,
-STORE, 140175980314624, 140175985139711,
-STORE, 140175980281856, 140175985139711,
-STORE, 140175980273664, 140175985139711,
-STORE, 140175980257280, 140175985139711,
-STORE, 140175945326592, 140175952146431,
-STORE, 140175980249088, 140175985139711,
-STORE, 140175980232704, 140175985139711,
-STORE, 140175980224512, 140175985139711,
-STORE, 140175980208128, 140175985139711,
-STORE, 140175980199936, 140175985139711,
-STORE, 140175980167168, 140175985139711,
-STORE, 140175952433152, 140175985139711,
-STORE, 140175952416768, 140175985139711,
-STORE, 140175952408576, 140175985139711,
-STORE, 140175952392192, 140175985139711,
-STORE, 140175952384000, 140175985139711,
-STORE, 140175952367616, 140175985139711,
-STORE, 140175943229440, 140175952146431,
-STORE, 140175952359424, 140175985139711,
-STORE, 140175952326656, 140175985139711,
-STORE, 140175952318464, 140175985139711,
-STORE, 140175952302080, 140175985139711,
-STORE, 140175952293888, 140175985139711,
-STORE, 140175952277504, 140175985139711,
-STORE, 140175952269312, 140175985139711,
-STORE, 140175952252928, 140175985139711,
-STORE, 140175952244736, 140175985139711,
-STORE, 140175952211968, 140175985139711,
-STORE, 140175952203776, 140175985139711,
-STORE, 140175952187392, 140175985139711,
-STORE, 140175952179200, 140175985139711,
-STORE, 140175952162816, 140175985139711,
-STORE, 140175952154624, 140175985139711,
-STORE, 140175943213056, 140175952146431,
-STORE, 140175943213056, 140175985139711,
-STORE, 140175943180288, 140175985139711,
-STORE, 140175943172096, 140175985139711,
-STORE, 140175943155712, 140175985139711,
-STORE, 140175943147520, 140175985139711,
-STORE, 140175943131136, 140175985139711,
-STORE, 140175943122944, 140175985139711,
-STORE, 140175943106560, 140175985139711,
-STORE, 140175943098368, 140175985139711,
-STORE, 140175943065600, 140175985139711,
-STORE, 140175943057408, 140175985139711,
-STORE, 140175943041024, 140175985139711,
-STORE, 140175943032832, 140175985139711,
-STORE, 140175943016448, 140175985139711,
-STORE, 140175943008256, 140175985139711,
-STORE, 140175942991872, 140175985139711,
-STORE, 140175942983680, 140175985139711,
-STORE, 140175942950912, 140175985139711,
-STORE, 140175942942720, 140175985139711,
-STORE, 140175942926336, 140175985139711,
-STORE, 140175942918144, 140175985139711,
-STORE, 140175942901760, 140175985139711,
-STORE, 140175942893568, 140175985139711,
-STORE, 140175942877184, 140175985139711,
-STORE, 140175942868992, 140175985139711,
-STORE, 140175942836224, 140175985139711,
-STORE, 140175942828032, 140175985139711,
-STORE, 140175942811648, 140175985139711,
-STORE, 140175942803456, 140175985139711,
-STORE, 140175942787072, 140175985139711,
-STORE, 140175942778880, 140175985139711,
-STORE, 140175942762496, 140175985139711,
-STORE, 140175942754304, 140175985139711,
-STORE, 140175942721536, 140175985139711,
-STORE, 140175942713344, 140175985139711,
-STORE, 140175942696960, 140175985139711,
-STORE, 140175942688768, 140175985139711,
-STORE, 140175942672384, 140175985139711,
-STORE, 140175942664192, 140175985139711,
-STORE, 140175942647808, 140175985139711,
-STORE, 140175942639616, 140175985139711,
-STORE, 140175942606848, 140175985139711,
-STORE, 140175942598656, 140175985139711,
-STORE, 140175942582272, 140175985139711,
-STORE, 140175942574080, 140175985139711,
-STORE, 140175942557696, 140175985139711,
-STORE, 140175942549504, 140175985139711,
-STORE, 140175942533120, 140175985139711,
-STORE, 140175942524928, 140175985139711,
-STORE, 140175942492160, 140175985139711,
-STORE, 140175942483968, 140175985139711,
-STORE, 140175942467584, 140175985139711,
-STORE, 140175942459392, 140175985139711,
-STORE, 140175942443008, 140175985139711,
-STORE, 140175942434816, 140175985139711,
-STORE, 140175942418432, 140175985139711,
-STORE, 140175942410240, 140175985139711,
-STORE, 140175942377472, 140175985139711,
-STORE, 140175942369280, 140175985139711,
-STORE, 140175942352896, 140175985139711,
-STORE, 140175942344704, 140175985139711,
-STORE, 140175942328320, 140175985139711,
-STORE, 140175942320128, 140175985139711,
-STORE, 140175942303744, 140175985139711,
-STORE, 140175942295552, 140175985139711,
-STORE, 140175942262784, 140175985139711,
-STORE, 140175942254592, 140175985139711,
-STORE, 140175942238208, 140175985139711,
-STORE, 140175942230016, 140175985139711,
-STORE, 140175942213632, 140175985139711,
-STORE, 140175942205440, 140175985139711,
-STORE, 140175942189056, 140175985139711,
-STORE, 140175942180864, 140175985139711,
-STORE, 140175942148096, 140175985139711,
-STORE, 140175942139904, 140175985139711,
-STORE, 140175942123520, 140175985139711,
-STORE, 140175942115328, 140175985139711,
-STORE, 140175942098944, 140175985139711,
-STORE, 140175942090752, 140175985139711,
-STORE, 140175942074368, 140175985139711,
-STORE, 140175942066176, 140175985139711,
-STORE, 140175942033408, 140175985139711,
-STORE, 140175942025216, 140175985139711,
-STORE, 140175942008832, 140175985139711,
-STORE, 140175942000640, 140175985139711,
-STORE, 140175941984256, 140175985139711,
-STORE, 140175941976064, 140175985139711,
-STORE, 140175941959680, 140175985139711,
-STORE, 140175939862528, 140175985139711,
-STORE, 140175939854336, 140175985139711,
-STORE, 140175939821568, 140175985139711,
-STORE, 140175939813376, 140175985139711,
-STORE, 140175939796992, 140175985139711,
-STORE, 140175939788800, 140175985139711,
-STORE, 140175939772416, 140175985139711,
-STORE, 140175939764224, 140175985139711,
-STORE, 140175939747840, 140175985139711,
-STORE, 140175939739648, 140175985139711,
-STORE, 140175939706880, 140175985139711,
-STORE, 140175939698688, 140175985139711,
-STORE, 140175939682304, 140175985139711,
-STORE, 140175939674112, 140175985139711,
-STORE, 140175939657728, 140175985139711,
-STORE, 140175939649536, 140175985139711,
-STORE, 140175939633152, 140175985139711,
-STORE, 140175939624960, 140175985139711,
-STORE, 140175939592192, 140175985139711,
-STORE, 140175939584000, 140175985139711,
-STORE, 140175939567616, 140175985139711,
-STORE, 140175939559424, 140175985139711,
-STORE, 140175939543040, 140175985139711,
-STORE, 140175939534848, 140175985139711,
-STORE, 140175939518464, 140175985139711,
-STORE, 140175939510272, 140175985139711,
-STORE, 140175939477504, 140175985139711,
-STORE, 140175939469312, 140175985139711,
-STORE, 140175939452928, 140175985139711,
-STORE, 140175939444736, 140175985139711,
-STORE, 140175939428352, 140175985139711,
-STORE, 140175939420160, 140175985139711,
-STORE, 140175939403776, 140175985139711,
-STORE, 140175939395584, 140175985139711,
-STORE, 140175939362816, 140175985139711,
-STORE, 140175939354624, 140175985139711,
-STORE, 140175939338240, 140175985139711,
-STORE, 140175939330048, 140175985139711,
-STORE, 140175939313664, 140175985139711,
-STORE, 140175939305472, 140175985139711,
-STORE, 140175939289088, 140175985139711,
-STORE, 140175939280896, 140175985139711,
-STORE, 140175939248128, 140175985139711,
-STORE, 140175939239936, 140175985139711,
-STORE, 140175939223552, 140175985139711,
-STORE, 140175939215360, 140175985139711,
-STORE, 140175939198976, 140175985139711,
-STORE, 140175939190784, 140175985139711,
-STORE, 140175939174400, 140175985139711,
-STORE, 140175939166208, 140175985139711,
-STORE, 140175939133440, 140175985139711,
-STORE, 140175939125248, 140175985139711,
-STORE, 140175939108864, 140175985139711,
-STORE, 140175939100672, 140175985139711,
-STORE, 140175939084288, 140175985139711,
-STORE, 140175939076096, 140175985139711,
-STORE, 140175939059712, 140175985139711,
-STORE, 140175939051520, 140175985139711,
-STORE, 140175939018752, 140175985139711,
-STORE, 140175939010560, 140175985139711,
-STORE, 140175938994176, 140175985139711,
-STORE, 140175938985984, 140175985139711,
-STORE, 140175938969600, 140175985139711,
-STORE, 140175938961408, 140175985139711,
-STORE, 140175938945024, 140175985139711,
-STORE, 140175938936832, 140175985139711,
-STORE, 140175938904064, 140175985139711,
-STORE, 140175938895872, 140175985139711,
-STORE, 140175938879488, 140175985139711,
-STORE, 140175938871296, 140175985139711,
-STORE, 140175938854912, 140175985139711,
-STORE, 140175938846720, 140175985139711,
-STORE, 140175938830336, 140175985139711,
-STORE, 140175938822144, 140175985139711,
-STORE, 140175938789376, 140175985139711,
-STORE, 140175938781184, 140175985139711,
-STORE, 140175938764800, 140175985139711,
-STORE, 140175938756608, 140175985139711,
-STORE, 140175938740224, 140175985139711,
-STORE, 140175938732032, 140175985139711,
-STORE, 140175938715648, 140175985139711,
-STORE, 140175938707456, 140175985139711,
-STORE, 140175938674688, 140175985139711,
-STORE, 140175938666496, 140175985139711,
-STORE, 140175938650112, 140175985139711,
-STORE, 140175938641920, 140175985139711,
-STORE, 140175938625536, 140175985139711,
-STORE, 140175938617344, 140175985139711,
-STORE, 140175938600960, 140175985139711,
-STORE, 140175938592768, 140175985139711,
-STORE, 140175938560000, 140175985139711,
-STORE, 140175938551808, 140175985139711,
-STORE, 140175938535424, 140175985139711,
-STORE, 140175938527232, 140175985139711,
-STORE, 140175938510848, 140175985139711,
-STORE, 140175938502656, 140175985139711,
-STORE, 140175938486272, 140175985139711,
-STORE, 140175938478080, 140175985139711,
-STORE, 140175938445312, 140175985139711,
-STORE, 140175938437120, 140175985139711,
-STORE, 140175938420736, 140175985139711,
-STORE, 140175938412544, 140175985139711,
-STORE, 140175938396160, 140175985139711,
-STORE, 140175938387968, 140175985139711,
-STORE, 140175938371584, 140175985139711,
-STORE, 140175938363392, 140175985139711,
-STORE, 140175938330624, 140175985139711,
-STORE, 140175938322432, 140175985139711,
-STORE, 140175938306048, 140175985139711,
-STORE, 140175938297856, 140175985139711,
-STORE, 140175938281472, 140175985139711,
-STORE, 140175938273280, 140175985139711,
-STORE, 140175938256896, 140175985139711,
-STORE, 140175938248704, 140175985139711,
-STORE, 140175938215936, 140175985139711,
-STORE, 140175938207744, 140175985139711,
-STORE, 140175938191360, 140175985139711,
-STORE, 140175938183168, 140175985139711,
-STORE, 140175938166784, 140175985139711,
-STORE, 140175938158592, 140175985139711,
-STORE, 140175938142208, 140175985139711,
-STORE, 140175936045056, 140175985139711,
-STORE, 140175936036864, 140175985139711,
-STORE, 140175936004096, 140175985139711,
-STORE, 140175935995904, 140175985139711,
-STORE, 140175935979520, 140175985139711,
-STORE, 140175935971328, 140175985139711,
-STORE, 140175935954944, 140175985139711,
-STORE, 140175935946752, 140175985139711,
-STORE, 140175935930368, 140175985139711,
-STORE, 140175935922176, 140175985139711,
-STORE, 140175935889408, 140175985139711,
-STORE, 140175935881216, 140175985139711,
-STORE, 140175935864832, 140175985139711,
-STORE, 140175935856640, 140175985139711,
-STORE, 140175935840256, 140175985139711,
-STORE, 140175935832064, 140175985139711,
-STORE, 140175935815680, 140175985139711,
-STORE, 140175935807488, 140175985139711,
-STORE, 140175935774720, 140175985139711,
-STORE, 140175935766528, 140175985139711,
-STORE, 140175935750144, 140175985139711,
-STORE, 140175935741952, 140175985139711,
-STORE, 140175935725568, 140175985139711,
-STORE, 140175935717376, 140175985139711,
-STORE, 140175935700992, 140175985139711,
-STORE, 140175935692800, 140175985139711,
-STORE, 140175935660032, 140175985139711,
-STORE, 140175935651840, 140175985139711,
-STORE, 140175935635456, 140175985139711,
-STORE, 140175935627264, 140175985139711,
-STORE, 140175935610880, 140175985139711,
-STORE, 140175935602688, 140175985139711,
-STORE, 140175935586304, 140175985139711,
-STORE, 140175935578112, 140175985139711,
-STORE, 140175935545344, 140175985139711,
-STORE, 140175935537152, 140175985139711,
-STORE, 140175935520768, 140175985139711,
-STORE, 140175935512576, 140175985139711,
-STORE, 140175935496192, 140175985139711,
-STORE, 140175935488000, 140175985139711,
-STORE, 140175935471616, 140175985139711,
-STORE, 140175935463424, 140175985139711,
-STORE, 140175935430656, 140175985139711,
-STORE, 140175935422464, 140175985139711,
-STORE, 140175935406080, 140175985139711,
-STORE, 140175935397888, 140175985139711,
-STORE, 140175935381504, 140175985139711,
-STORE, 140175935373312, 140175985139711,
-STORE, 140175935356928, 140175985139711,
-STORE, 140175935348736, 140175985139711,
-STORE, 140175935315968, 140175985139711,
-STORE, 140175935307776, 140175985139711,
-STORE, 140175935291392, 140175985139711,
-STORE, 140175935283200, 140175985139711,
-STORE, 140175935266816, 140175985139711,
-STORE, 140175935258624, 140175985139711,
-STORE, 140175935242240, 140175985139711,
-STORE, 140175935234048, 140175985139711,
-STORE, 140175935201280, 140175985139711,
-STORE, 140175935193088, 140175985139711,
-STORE, 140175935176704, 140175985139711,
-STORE, 140175935168512, 140175985139711,
-STORE, 140175935152128, 140175985139711,
-STORE, 140175935143936, 140175985139711,
-STORE, 140175935127552, 140175985139711,
-STORE, 140175935119360, 140175985139711,
-STORE, 140175935086592, 140175985139711,
-STORE, 140175935078400, 140175985139711,
-STORE, 140175935062016, 140175985139711,
-STORE, 140175935053824, 140175985139711,
-STORE, 140175935037440, 140175985139711,
-STORE, 140175935029248, 140175985139711,
-STORE, 140175935012864, 140175985139711,
-STORE, 140175935004672, 140175985139711,
-STORE, 140175934971904, 140175985139711,
-STORE, 140175934963712, 140175985139711,
-STORE, 140175934947328, 140175985139711,
-STORE, 140175934939136, 140175985139711,
-STORE, 140175934922752, 140175985139711,
-STORE, 140175934914560, 140175985139711,
-STORE, 140175934898176, 140175985139711,
-STORE, 140175934889984, 140175985139711,
-STORE, 140175934857216, 140175985139711,
-STORE, 140175934849024, 140175985139711,
-STORE, 140175934832640, 140175985139711,
-STORE, 140175934824448, 140175985139711,
-STORE, 140175934808064, 140175985139711,
-STORE, 140175934799872, 140175985139711,
-STORE, 140175934783488, 140175985139711,
-STORE, 140175934775296, 140175985139711,
-STORE, 140175934742528, 140175985139711,
-STORE, 140175934734336, 140175985139711,
-STORE, 140175934717952, 140175985139711,
-STORE, 140175934709760, 140175985139711,
-STORE, 140175934693376, 140175985139711,
-STORE, 140175934685184, 140175985139711,
-STORE, 140175934668800, 140175985139711,
-STORE, 140175934660608, 140175985139711,
-STORE, 140175934627840, 140175985139711,
-STORE, 140175934619648, 140175985139711,
-STORE, 140175934603264, 140175985139711,
-STORE, 140175934595072, 140175985139711,
-STORE, 140175934578688, 140175985139711,
-STORE, 140175934570496, 140175985139711,
-STORE, 140175934554112, 140175985139711,
-STORE, 140175934545920, 140175985139711,
-STORE, 140175934513152, 140175985139711,
-STORE, 140175934504960, 140175985139711,
-STORE, 140175934488576, 140175985139711,
-STORE, 140175934480384, 140175985139711,
-STORE, 140175934464000, 140175985139711,
-STORE, 140175934455808, 140175985139711,
-STORE, 140175934439424, 140175985139711,
-STORE, 140175934431232, 140175985139711,
-STORE, 140175934398464, 140175985139711,
-STORE, 140175934390272, 140175985139711,
-STORE, 140175934373888, 140175985139711,
-STORE, 140175934365696, 140175985139711,
-STORE, 140175934349312, 140175985139711,
-STORE, 140175934341120, 140175985139711,
-STORE, 140175934324736, 140175985139711,
-STORE, 140175932227584, 140175985139711,
-STORE, 140175932219392, 140175985139711,
-STORE, 140175932186624, 140175985139711,
-STORE, 140175932178432, 140175985139711,
-STORE, 140175932162048, 140175985139711,
-STORE, 140175932153856, 140175985139711,
-STORE, 140175932137472, 140175985139711,
-STORE, 53080064, 57884671,
-STORE, 140175932129280, 140175985139711,
-STORE, 140175932112896, 140175985139711,
-STORE, 140175932104704, 140175985139711,
-STORE, 140175932071936, 140175985139711,
-STORE, 140175932063744, 140175985139711,
-STORE, 140175932047360, 140175985139711,
-STORE, 140175932039168, 140175985139711,
-STORE, 140175932022784, 140175985139711,
-STORE, 140175932014592, 140175985139711,
-STORE, 140175931998208, 140175985139711,
-STORE, 140175931990016, 140175985139711,
-STORE, 140175931957248, 140175985139711,
-STORE, 140175931949056, 140175985139711,
-STORE, 140175931932672, 140175985139711,
-STORE, 140175931924480, 140175985139711,
-STORE, 140175931908096, 140175985139711,
-STORE, 140175931899904, 140175985139711,
-STORE, 140175931883520, 140175985139711,
-STORE, 140175931875328, 140175985139711,
-STORE, 140175931842560, 140175985139711,
-STORE, 140175931834368, 140175985139711,
-STORE, 140175931817984, 140175985139711,
-STORE, 140175931809792, 140175985139711,
-STORE, 140175931793408, 140175985139711,
-STORE, 140175931785216, 140175985139711,
-STORE, 140175931768832, 140175985139711,
-STORE, 140175931760640, 140175985139711,
-STORE, 140175931727872, 140175985139711,
-STORE, 140175931719680, 140175985139711,
-STORE, 140175931703296, 140175985139711,
-STORE, 140175931695104, 140175985139711,
-STORE, 140175931678720, 140175985139711,
-STORE, 140175931670528, 140175985139711,
-STORE, 140175931654144, 140175985139711,
-STORE, 140175931645952, 140175985139711,
-STORE, 140175931613184, 140175985139711,
-STORE, 140175931604992, 140175985139711,
-STORE, 140175931588608, 140175985139711,
-STORE, 140175931580416, 140175985139711,
-STORE, 140175931564032, 140175985139711,
-STORE, 140175931555840, 140175985139711,
-STORE, 140175931539456, 140175985139711,
-STORE, 140175931531264, 140175985139711,
-STORE, 140175931498496, 140175985139711,
-STORE, 140175931490304, 140175985139711,
-STORE, 140175931473920, 140175985139711,
-STORE, 140175931465728, 140175985139711,
-STORE, 140175931449344, 140175985139711,
-STORE, 140175931441152, 140175985139711,
-STORE, 140175931424768, 140175985139711,
-STORE, 140175931416576, 140175985139711,
-STORE, 140175931383808, 140175985139711,
-STORE, 140175931375616, 140175985139711,
-STORE, 140175931359232, 140175985139711,
-STORE, 140175931351040, 140175985139711,
-STORE, 140175931334656, 140175985139711,
-STORE, 140175931326464, 140175985139711,
-STORE, 140175931310080, 140175985139711,
-STORE, 140175931301888, 140175985139711,
-STORE, 140175931269120, 140175985139711,
-STORE, 140175931260928, 140175985139711,
-STORE, 140175931244544, 140175985139711,
-STORE, 140175931236352, 140175985139711,
-STORE, 140175931219968, 140175985139711,
-STORE, 140175931211776, 140175985139711,
-STORE, 140175931195392, 140175985139711,
-STORE, 140175931187200, 140175985139711,
-STORE, 140175931154432, 140175985139711,
-STORE, 140175931146240, 140175985139711,
-STORE, 140175931129856, 140175985139711,
-STORE, 140175931121664, 140175985139711,
-STORE, 140175931105280, 140175985139711,
-STORE, 140175931097088, 140175985139711,
-STORE, 140175931080704, 140175985139711,
-STORE, 140175931072512, 140175985139711,
-STORE, 140175931039744, 140175985139711,
-STORE, 140175931031552, 140175985139711,
-STORE, 140175931015168, 140175985139711,
-STORE, 140175931006976, 140175985139711,
-STORE, 140175930990592, 140175985139711,
-STORE, 140175930982400, 140175985139711,
-STORE, 140175930966016, 140175985139711,
-STORE, 140175930957824, 140175985139711,
-STORE, 140175930925056, 140175985139711,
-STORE, 140175930916864, 140175985139711,
-STORE, 140175930900480, 140175985139711,
-STORE, 140175930892288, 140175985139711,
-STORE, 140175930875904, 140175985139711,
-STORE, 140175930867712, 140175985139711,
-STORE, 140175930851328, 140175985139711,
-STORE, 140175930843136, 140175985139711,
-STORE, 140175930810368, 140175985139711,
-STORE, 140175930802176, 140175985139711,
-STORE, 140175930785792, 140175985139711,
-STORE, 140175930777600, 140175985139711,
-STORE, 140175930761216, 140175985139711,
-STORE, 140175930753024, 140175985139711,
-STORE, 140175930736640, 140175985139711,
-STORE, 140175930728448, 140175985139711,
-STORE, 140175930695680, 140175985139711,
-STORE, 140175930687488, 140175985139711,
-STORE, 140175930671104, 140175985139711,
-STORE, 140175930662912, 140175985139711,
-STORE, 140175930646528, 140175985139711,
-STORE, 140175930638336, 140175985139711,
-STORE, 140175930621952, 140175985139711,
-STORE, 140175930613760, 140175985139711,
-STORE, 140175930580992, 140175985139711,
-STORE, 140175930572800, 140175985139711,
-STORE, 140175930556416, 140175985139711,
-STORE, 140175930548224, 140175985139711,
-STORE, 140175930531840, 140175985139711,
-STORE, 140175930523648, 140175985139711,
-STORE, 140175930507264, 140175985139711,
-STORE, 140175928410112, 140175985139711,
-STORE, 140175928401920, 140175985139711,
-STORE, 140175928369152, 140175985139711,
-STORE, 140175928360960, 140175985139711,
-STORE, 140175928344576, 140175985139711,
-STORE, 140175928336384, 140175985139711,
-STORE, 140175928320000, 140175985139711,
-STORE, 140175928311808, 140175985139711,
-STORE, 140175928295424, 140175985139711,
-STORE, 140175927242752, 140175985139711,
-SNULL, 140175956627455, 140175985139711,
-STORE, 140175927242752, 140175956627455,
-STORE, 140175956627456, 140175985139711,
- };
- unsigned long set24[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140735281639424, 140737488351231,
-SNULL, 140735281643519, 140737488351231,
-STORE, 140735281639424, 140735281643519,
-STORE, 140735281508352, 140735281643519,
-STORE, 94717834911744, 94717834928127,
-SNULL, 94717834915839, 94717834928127,
-STORE, 94717834911744, 94717834915839,
-STORE, 94717834915840, 94717834928127,
-ERASE, 94717834915840, 94717834928127,
-STORE, 94717834919936, 94717834928127,
-STORE, 140428246065152, 140428248317951,
-SNULL, 140428246208511, 140428248317951,
-STORE, 140428246065152, 140428246208511,
-STORE, 140428246208512, 140428248317951,
-ERASE, 140428246208512, 140428248317951,
-STORE, 140428248305664, 140428248313855,
-STORE, 140428248313856, 140428248317951,
-STORE, 140735281811456, 140735281815551,
-STORE, 140735281799168, 140735281811455,
-STORE, 140428248297472, 140428248305663,
-STORE, 140428243841024, 140428246065151,
-SNULL, 140428245491711, 140428246065151,
-STORE, 140428243841024, 140428245491711,
-STORE, 140428245491712, 140428246065151,
-SNULL, 140428245491712, 140428246061055,
-STORE, 140428246061056, 140428246065151,
-STORE, 140428245491712, 140428246061055,
-ERASE, 140428245491712, 140428246061055,
-STORE, 140428245491712, 140428246061055,
-ERASE, 140428246061056, 140428246065151,
-STORE, 140428246061056, 140428246065151,
-STORE, 140428248268800, 140428248297471,
-STORE, 140428241625088, 140428243841023,
-SNULL, 140428241625088, 140428241723391,
-STORE, 140428241723392, 140428243841023,
-STORE, 140428241625088, 140428241723391,
-SNULL, 140428243816447, 140428243841023,
-STORE, 140428241723392, 140428243816447,
-STORE, 140428243816448, 140428243841023,
-SNULL, 140428243816448, 140428243824639,
-STORE, 140428243824640, 140428243841023,
-STORE, 140428243816448, 140428243824639,
-ERASE, 140428243816448, 140428243824639,
-STORE, 140428243816448, 140428243824639,
-ERASE, 140428243824640, 140428243841023,
-STORE, 140428243824640, 140428243841023,
-STORE, 140428237828096, 140428241625087,
-SNULL, 140428237828096, 140428239486975,
-STORE, 140428239486976, 140428241625087,
-STORE, 140428237828096, 140428239486975,
-SNULL, 140428241584127, 140428241625087,
-STORE, 140428239486976, 140428241584127,
-STORE, 140428241584128, 140428241625087,
-SNULL, 140428241584128, 140428241608703,
-STORE, 140428241608704, 140428241625087,
-STORE, 140428241584128, 140428241608703,
-ERASE, 140428241584128, 140428241608703,
-STORE, 140428241584128, 140428241608703,
-ERASE, 140428241608704, 140428241625087,
-STORE, 140428241608704, 140428241625087,
-STORE, 140428235567104, 140428237828095,
-SNULL, 140428235567104, 140428235718655,
-STORE, 140428235718656, 140428237828095,
-STORE, 140428235567104, 140428235718655,
-SNULL, 140428237811711, 140428237828095,
-STORE, 140428235718656, 140428237811711,
-STORE, 140428237811712, 140428237828095,
-SNULL, 140428237811712, 140428237819903,
-STORE, 140428237819904, 140428237828095,
-STORE, 140428237811712, 140428237819903,
-ERASE, 140428237811712, 140428237819903,
-STORE, 140428237811712, 140428237819903,
-ERASE, 140428237819904, 140428237828095,
-STORE, 140428237819904, 140428237828095,
-STORE, 140428233445376, 140428235567103,
-SNULL, 140428233445376, 140428233461759,
-STORE, 140428233461760, 140428235567103,
-STORE, 140428233445376, 140428233461759,
-SNULL, 140428235558911, 140428235567103,
-STORE, 140428233461760, 140428235558911,
-STORE, 140428235558912, 140428235567103,
-ERASE, 140428235558912, 140428235567103,
-STORE, 140428235558912, 140428235567103,
-STORE, 140428231315456, 140428233445375,
-SNULL, 140428231315456, 140428231344127,
-STORE, 140428231344128, 140428233445375,
-STORE, 140428231315456, 140428231344127,
-SNULL, 140428233437183, 140428233445375,
-STORE, 140428231344128, 140428233437183,
-STORE, 140428233437184, 140428233445375,
-ERASE, 140428233437184, 140428233445375,
-STORE, 140428233437184, 140428233445375,
-STORE, 140428248260608, 140428248268799,
-STORE, 140428229062656, 140428231315455,
-SNULL, 140428229062656, 140428229214207,
-STORE, 140428229214208, 140428231315455,
-STORE, 140428229062656, 140428229214207,
-SNULL, 140428231307263, 140428231315455,
-STORE, 140428229214208, 140428231307263,
-STORE, 140428231307264, 140428231315455,
-ERASE, 140428231307264, 140428231315455,
-STORE, 140428231307264, 140428231315455,
-STORE, 140428226891776, 140428229062655,
-SNULL, 140428226891776, 140428226961407,
-STORE, 140428226961408, 140428229062655,
-STORE, 140428226891776, 140428226961407,
-SNULL, 140428229054463, 140428229062655,
-STORE, 140428226961408, 140428229054463,
-STORE, 140428229054464, 140428229062655,
-ERASE, 140428229054464, 140428229062655,
-STORE, 140428229054464, 140428229062655,
-STORE, 140428223680512, 140428226891775,
-SNULL, 140428223680512, 140428224757759,
-STORE, 140428224757760, 140428226891775,
-STORE, 140428223680512, 140428224757759,
-SNULL, 140428226854911, 140428226891775,
-STORE, 140428224757760, 140428226854911,
-STORE, 140428226854912, 140428226891775,
-ERASE, 140428226854912, 140428226891775,
-STORE, 140428226854912, 140428226891775,
-STORE, 140428221546496, 140428223680511,
-SNULL, 140428221546496, 140428221575167,
-STORE, 140428221575168, 140428223680511,
-STORE, 140428221546496, 140428221575167,
-SNULL, 140428223672319, 140428223680511,
-STORE, 140428221575168, 140428223672319,
-STORE, 140428223672320, 140428223680511,
-ERASE, 140428223672320, 140428223680511,
-STORE, 140428223672320, 140428223680511,
-STORE, 140428219236352, 140428221546495,
-SNULL, 140428219236352, 140428219441151,
-STORE, 140428219441152, 140428221546495,
-STORE, 140428219236352, 140428219441151,
-SNULL, 140428221538303, 140428221546495,
-STORE, 140428219441152, 140428221538303,
-STORE, 140428221538304, 140428221546495,
-ERASE, 140428221538304, 140428221546495,
-STORE, 140428221538304, 140428221546495,
-STORE, 140428216852480, 140428219236351,
-SNULL, 140428216852480, 140428217044991,
-STORE, 140428217044992, 140428219236351,
-STORE, 140428216852480, 140428217044991,
-SNULL, 140428219138047, 140428219236351,
-STORE, 140428217044992, 140428219138047,
-STORE, 140428219138048, 140428219236351,
-ERASE, 140428219138048, 140428219236351,
-STORE, 140428219138048, 140428219236351,
-STORE, 140428248252416, 140428248268799,
-STORE, 140428214284288, 140428216852479,
-SNULL, 140428214284288, 140428214751231,
-STORE, 140428214751232, 140428216852479,
-STORE, 140428214284288, 140428214751231,
-SNULL, 140428216844287, 140428216852479,
-STORE, 140428214751232, 140428216844287,
-STORE, 140428216844288, 140428216852479,
-ERASE, 140428216844288, 140428216852479,
-STORE, 140428216844288, 140428216852479,
-STORE, 140428212170752, 140428214284287,
-SNULL, 140428212170752, 140428212183039,
-STORE, 140428212183040, 140428214284287,
-STORE, 140428212170752, 140428212183039,
-SNULL, 140428214276095, 140428214284287,
-STORE, 140428212183040, 140428214276095,
-STORE, 140428214276096, 140428214284287,
-ERASE, 140428214276096, 140428214284287,
-STORE, 140428214276096, 140428214284287,
-STORE, 140428209991680, 140428212170751,
-SNULL, 140428209991680, 140428210069503,
-STORE, 140428210069504, 140428212170751,
-STORE, 140428209991680, 140428210069503,
-SNULL, 140428212162559, 140428212170751,
-STORE, 140428210069504, 140428212162559,
-STORE, 140428212162560, 140428212170751,
-ERASE, 140428212162560, 140428212170751,
-STORE, 140428212162560, 140428212170751,
-STORE, 140428207874048, 140428209991679,
-SNULL, 140428207874048, 140428207890431,
-STORE, 140428207890432, 140428209991679,
-STORE, 140428207874048, 140428207890431,
-SNULL, 140428209983487, 140428209991679,
-STORE, 140428207890432, 140428209983487,
-STORE, 140428209983488, 140428209991679,
-ERASE, 140428209983488, 140428209991679,
-STORE, 140428209983488, 140428209991679,
-STORE, 140428248244224, 140428248268799,
-STORE, 140428248231936, 140428248268799,
-SNULL, 140428241600511, 140428241608703,
-STORE, 140428241584128, 140428241600511,
-STORE, 140428241600512, 140428241608703,
-SNULL, 140428209987583, 140428209991679,
-STORE, 140428209983488, 140428209987583,
-STORE, 140428209987584, 140428209991679,
-SNULL, 140428212166655, 140428212170751,
-STORE, 140428212162560, 140428212166655,
-STORE, 140428212166656, 140428212170751,
-SNULL, 140428214280191, 140428214284287,
-STORE, 140428214276096, 140428214280191,
-STORE, 140428214280192, 140428214284287,
-SNULL, 140428243820543, 140428243824639,
-STORE, 140428243816448, 140428243820543,
-STORE, 140428243820544, 140428243824639,
-SNULL, 140428216848383, 140428216852479,
-STORE, 140428216844288, 140428216848383,
-STORE, 140428216848384, 140428216852479,
-SNULL, 140428219232255, 140428219236351,
-STORE, 140428219138048, 140428219232255,
-STORE, 140428219232256, 140428219236351,
-SNULL, 140428221542399, 140428221546495,
-STORE, 140428221538304, 140428221542399,
-STORE, 140428221542400, 140428221546495,
-SNULL, 140428223676415, 140428223680511,
-STORE, 140428223672320, 140428223676415,
-STORE, 140428223676416, 140428223680511,
-SNULL, 140428226863103, 140428226891775,
-STORE, 140428226854912, 140428226863103,
-STORE, 140428226863104, 140428226891775,
-SNULL, 140428229058559, 140428229062655,
-STORE, 140428229054464, 140428229058559,
-STORE, 140428229058560, 140428229062655,
-SNULL, 140428231311359, 140428231315455,
-STORE, 140428231307264, 140428231311359,
-STORE, 140428231311360, 140428231315455,
-SNULL, 140428233441279, 140428233445375,
-STORE, 140428233437184, 140428233441279,
-STORE, 140428233441280, 140428233445375,
-SNULL, 140428235563007, 140428235567103,
-STORE, 140428235558912, 140428235563007,
-STORE, 140428235563008, 140428235567103,
-SNULL, 140428237815807, 140428237819903,
-STORE, 140428237811712, 140428237815807,
-STORE, 140428237815808, 140428237819903,
-SNULL, 140428246056959, 140428246061055,
-STORE, 140428245491712, 140428246056959,
-STORE, 140428246056960, 140428246061055,
-SNULL, 94717834924031, 94717834928127,
-STORE, 94717834919936, 94717834924031,
-STORE, 94717834924032, 94717834928127,
-SNULL, 140428248309759, 140428248313855,
-STORE, 140428248305664, 140428248309759,
-STORE, 140428248309760, 140428248313855,
-ERASE, 140428248268800, 140428248297471,
-STORE, 94717843058688, 94717843193855,
-STORE, 94749677137920, 94749677559807,
-STORE, 94749677563904, 94749677604863,
-STORE, 94749677604864, 94749677608959,
-STORE, 94749710970880, 94749711241215,
-STORE, 140490884894720, 140490884935679,
-STORE, 140490884935680, 140490887032831,
-STORE, 140490887032832, 140490887036927,
-STORE, 140490887036928, 140490887041023,
-STORE, 140490887041024, 140490887065599,
-STORE, 140490887065600, 140490887110655,
-STORE, 140490887110656, 140490889203711,
-STORE, 140490889203712, 140490889207807,
-STORE, 140490889207808, 140490889211903,
-STORE, 140490889211904, 140490889293823,
-STORE, 140490889293824, 140490891390975,
-STORE, 140490891390976, 140490891395071,
-STORE, 140490891395072, 140490891399167,
-STORE, 140490891399168, 140490891407359,
-STORE, 140490891407360, 140490891436031,
-STORE, 140490891436032, 140490893529087,
-STORE, 140490893529088, 140490893533183,
-STORE, 140490893533184, 140490893537279,
-STORE, 140490893537280, 140490901979135,
-STORE, 140490901979136, 140490901991423,
-STORE, 140490901991424, 140490904084479,
-STORE, 140490904084480, 140490904088575,
-STORE, 140490904088576, 140490904092671,
-STORE, 140490904092672, 140490904559615,
-STORE, 140490904559616, 140490906652671,
-STORE, 140490906652672, 140490906656767,
-STORE, 140490906656768, 140490906660863,
-STORE, 140490906660864, 140490906677247,
-STORE, 140490906677248, 140490908770303,
-STORE, 140490908770304, 140490908774399,
-STORE, 140490908774400, 140490908778495,
-STORE, 140490908778496, 140490908794879,
-STORE, 140490908794880, 140490910887935,
-STORE, 140490910887936, 140490910892031,
-STORE, 140490910892032, 140490910896127,
-STORE, 140490910896128, 140490912555007,
-STORE, 140490912555008, 140490914652159,
-STORE, 140490914652160, 140490914668543,
-STORE, 140490914668544, 140490914676735,
-STORE, 140490914676736, 140490914693119,
-STORE, 140490914693120, 140490914791423,
-STORE, 140490914791424, 140490916884479,
-STORE, 140490916884480, 140490916888575,
-STORE, 140490916888576, 140490916892671,
-STORE, 140490916892672, 140490916909055,
-STORE, 140490916909056, 140490916937727,
-STORE, 140490916937728, 140490919030783,
-STORE, 140490919030784, 140490919034879,
-STORE, 140490919034880, 140490919038975,
-STORE, 140490919038976, 140490919190527,
-STORE, 140490919190528, 140490921283583,
-STORE, 140490921283584, 140490921287679,
-STORE, 140490921287680, 140490921291775,
-STORE, 140490921291776, 140490921299967,
-STORE, 140490921299968, 140490921390079,
-STORE, 140490921390080, 140490923483135,
-STORE, 140490923483136, 140490923487231,
-STORE, 140490923487232, 140490923491327,
-STORE, 140490923491328, 140490923757567,
-STORE, 140490923757568, 140490925850623,
-STORE, 140490925850624, 140490925867007,
-STORE, 140490925867008, 140490925871103,
-STORE, 140490925871104, 140490925875199,
-STORE, 140490925875200, 140490925903871,
-STORE, 140490925903872, 140490928001023,
-STORE, 140490928001024, 140490928005119,
-STORE, 140490928005120, 140490928009215,
-STORE, 140490928009216, 140490928152575,
-STORE, 140490930184192, 140490930221055,
-STORE, 140490930221056, 140490930237439,
-STORE, 140490930237440, 140490930241535,
-STORE, 140490930241536, 140490930245631,
-STORE, 140490930245632, 140490930249727,
-STORE, 140490930249728, 140490930253823,
-STORE, 140490930253824, 140490930257919,
-STORE, 140490930257920, 140490930262015,
-STORE, 140724611694592, 140724611829759,
-STORE, 140724612427776, 140724612440063,
-STORE, 140724612440064, 140724612444159,
-STORE, 94103163662336, 94103163772927,
-STORE, 94103165865984, 94103165874175,
-STORE, 94103165874176, 94103165878271,
-STORE, 94103165878272, 94103165886463,
-STORE, 94103182548992, 94103182684159,
-STORE, 140092694708224, 140092696367103,
-STORE, 140092696367104, 140092698464255,
-STORE, 140092698464256, 140092698480639,
-STORE, 140092698480640, 140092698488831,
-STORE, 140092698488832, 140092698505215,
-STORE, 140092698505216, 140092698648575,
-STORE, 140092700708864, 140092700717055,
-STORE, 140092700745728, 140092700749823,
-STORE, 140092700749824, 140092700753919,
-STORE, 140092700753920, 140092700758015,
-STORE, 140736800911360, 140736801046527,
-STORE, 140736802308096, 140736802320383,
-STORE, 140736802320384, 140736802324479,
-STORE, 93948802064384, 93948802174975,
-STORE, 93948804268032, 93948804276223,
-STORE, 93948804276224, 93948804280319,
-STORE, 93948804280320, 93948804288511,
-STORE, 93948806266880, 93948806402047,
-STORE, 140222999113728, 140223000772607,
-STORE, 140223000772608, 140223002869759,
-STORE, 140223002869760, 140223002886143,
-STORE, 140223002886144, 140223002894335,
-STORE, 140223002894336, 140223002910719,
-STORE, 140223002910720, 140223003054079,
-STORE, 140223005114368, 140223005122559,
-STORE, 140223005151232, 140223005155327,
-STORE, 140223005155328, 140223005159423,
-STORE, 140223005159424, 140223005163519,
-STORE, 140720877506560, 140720877641727,
-STORE, 140720878231552, 140720878243839,
-STORE, 140720878243840, 140720878247935,
-STORE, 140737488347136, 140737488351231,
-STORE, 140733232087040, 140737488351231,
-SNULL, 140733232091135, 140737488351231,
-STORE, 140733232087040, 140733232091135,
-STORE, 140733231955968, 140733232091135,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140161681321984, 140161683574783,
-SNULL, 140161681465343, 140161683574783,
-STORE, 140161681321984, 140161681465343,
-STORE, 140161681465344, 140161683574783,
-ERASE, 140161681465344, 140161683574783,
-STORE, 140161683562496, 140161683570687,
-STORE, 140161683570688, 140161683574783,
-STORE, 140733232214016, 140733232218111,
-STORE, 140733232201728, 140733232214015,
-STORE, 140161683533824, 140161683562495,
-STORE, 140161683525632, 140161683533823,
-STORE, 140161678159872, 140161681321983,
-SNULL, 140161678159872, 140161679220735,
-STORE, 140161679220736, 140161681321983,
-STORE, 140161678159872, 140161679220735,
-SNULL, 140161681313791, 140161681321983,
-STORE, 140161679220736, 140161681313791,
-STORE, 140161681313792, 140161681321983,
-ERASE, 140161681313792, 140161681321983,
-STORE, 140161681313792, 140161681321983,
-STORE, 140161674362880, 140161678159871,
-SNULL, 140161674362880, 140161676021759,
-STORE, 140161676021760, 140161678159871,
-STORE, 140161674362880, 140161676021759,
-SNULL, 140161678118911, 140161678159871,
-STORE, 140161676021760, 140161678118911,
-STORE, 140161678118912, 140161678159871,
-SNULL, 140161678118912, 140161678143487,
-STORE, 140161678143488, 140161678159871,
-STORE, 140161678118912, 140161678143487,
-ERASE, 140161678118912, 140161678143487,
-STORE, 140161678118912, 140161678143487,
-ERASE, 140161678143488, 140161678159871,
-STORE, 140161678143488, 140161678159871,
-STORE, 140161683513344, 140161683533823,
-SNULL, 140161678135295, 140161678143487,
-STORE, 140161678118912, 140161678135295,
-STORE, 140161678135296, 140161678143487,
-SNULL, 140161681317887, 140161681321983,
-STORE, 140161681313792, 140161681317887,
-STORE, 140161681317888, 140161681321983,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140161683566591, 140161683570687,
-STORE, 140161683562496, 140161683566591,
-STORE, 140161683566592, 140161683570687,
-ERASE, 140161683533824, 140161683562495,
-STORE, 25477120, 25612287,
-STORE, 25477120, 25759743,
-STORE, 140161681829888, 140161683513343,
-STORE, 25477120, 25915391,
-STORE, 25477120, 26054655,
-SNULL, 25800703, 26054655,
-STORE, 25477120, 25800703,
-STORE, 25800704, 26054655,
-ERASE, 25800704, 26054655,
-STORE, 140737488347136, 140737488351231,
-STORE, 140723218452480, 140737488351231,
-SNULL, 140723218456575, 140737488351231,
-STORE, 140723218452480, 140723218456575,
-STORE, 140723218321408, 140723218456575,
-STORE, 4194304, 26279935,
-STORE, 28372992, 28454911,
-STORE, 28454912, 29806591,
-STORE, 140398872264704, 140398874517503,
-SNULL, 140398872408063, 140398874517503,
-STORE, 140398872264704, 140398872408063,
-STORE, 140398872408064, 140398874517503,
-ERASE, 140398872408064, 140398874517503,
-STORE, 140398874505216, 140398874513407,
-STORE, 140398874513408, 140398874517503,
-STORE, 140723219247104, 140723219251199,
-STORE, 140723219234816, 140723219247103,
-STORE, 140398874476544, 140398874505215,
-STORE, 140398874468352, 140398874476543,
-STORE, 140398868430848, 140398872264703,
-SNULL, 140398868430848, 140398870138879,
-STORE, 140398870138880, 140398872264703,
-STORE, 140398868430848, 140398870138879,
-SNULL, 140398872231935, 140398872264703,
-STORE, 140398870138880, 140398872231935,
-STORE, 140398872231936, 140398872264703,
-ERASE, 140398872231936, 140398872264703,
-STORE, 140398872231936, 140398872264703,
-STORE, 140398866235392, 140398868430847,
-SNULL, 140398866235392, 140398866329599,
-STORE, 140398866329600, 140398868430847,
-STORE, 140398866235392, 140398866329599,
-SNULL, 140398868422655, 140398868430847,
-STORE, 140398866329600, 140398868422655,
-STORE, 140398868422656, 140398868430847,
-ERASE, 140398868422656, 140398868430847,
-STORE, 140398868422656, 140398868430847,
-STORE, 140398863716352, 140398866235391,
-SNULL, 140398863716352, 140398864130047,
-STORE, 140398864130048, 140398866235391,
-STORE, 140398863716352, 140398864130047,
-SNULL, 140398866223103, 140398866235391,
-STORE, 140398864130048, 140398866223103,
-STORE, 140398866223104, 140398866235391,
-ERASE, 140398866223104, 140398866235391,
-STORE, 140398866223104, 140398866235391,
-STORE, 140398861082624, 140398863716351,
-SNULL, 140398861082624, 140398861611007,
-STORE, 140398861611008, 140398863716351,
-STORE, 140398861082624, 140398861611007,
-SNULL, 140398863708159, 140398863716351,
-STORE, 140398861611008, 140398863708159,
-STORE, 140398863708160, 140398863716351,
-ERASE, 140398863708160, 140398863716351,
-STORE, 140398863708160, 140398863716351,
-STORE, 140398858969088, 140398861082623,
-SNULL, 140398858969088, 140398858981375,
-STORE, 140398858981376, 140398861082623,
-STORE, 140398858969088, 140398858981375,
-SNULL, 140398861074431, 140398861082623,
-STORE, 140398858981376, 140398861074431,
-STORE, 140398861074432, 140398861082623,
-ERASE, 140398861074432, 140398861082623,
-STORE, 140398861074432, 140398861082623,
-STORE, 140398856765440, 140398858969087,
-SNULL, 140398856765440, 140398856867839,
-STORE, 140398856867840, 140398858969087,
-STORE, 140398856765440, 140398856867839,
-SNULL, 140398858960895, 140398858969087,
-STORE, 140398856867840, 140398858960895,
-STORE, 140398858960896, 140398858969087,
-ERASE, 140398858960896, 140398858969087,
-STORE, 140398858960896, 140398858969087,
-STORE, 140398874460160, 140398874476543,
-STORE, 140398853603328, 140398856765439,
-SNULL, 140398853603328, 140398854664191,
-STORE, 140398854664192, 140398856765439,
-STORE, 140398853603328, 140398854664191,
-SNULL, 140398856757247, 140398856765439,
-STORE, 140398854664192, 140398856757247,
-STORE, 140398856757248, 140398856765439,
-ERASE, 140398856757248, 140398856765439,
-STORE, 140398856757248, 140398856765439,
-STORE, 140398849806336, 140398853603327,
-SNULL, 140398849806336, 140398851465215,
-STORE, 140398851465216, 140398853603327,
-STORE, 140398849806336, 140398851465215,
-SNULL, 140398853562367, 140398853603327,
-STORE, 140398851465216, 140398853562367,
-STORE, 140398853562368, 140398853603327,
-SNULL, 140398853562368, 140398853586943,
-STORE, 140398853586944, 140398853603327,
-STORE, 140398853562368, 140398853586943,
-ERASE, 140398853562368, 140398853586943,
-STORE, 140398853562368, 140398853586943,
-ERASE, 140398853586944, 140398853603327,
-STORE, 140398853586944, 140398853603327,
-STORE, 140398874447872, 140398874476543,
-SNULL, 140398853578751, 140398853586943,
-STORE, 140398853562368, 140398853578751,
-STORE, 140398853578752, 140398853586943,
-SNULL, 140398856761343, 140398856765439,
-STORE, 140398856757248, 140398856761343,
-STORE, 140398856761344, 140398856765439,
-SNULL, 140398858964991, 140398858969087,
-STORE, 140398858960896, 140398858964991,
-STORE, 140398858964992, 140398858969087,
-SNULL, 140398861078527, 140398861082623,
-STORE, 140398861074432, 140398861078527,
-STORE, 140398861078528, 140398861082623,
-SNULL, 140398863712255, 140398863716351,
-STORE, 140398863708160, 140398863712255,
-STORE, 140398863712256, 140398863716351,
-SNULL, 140398866231295, 140398866235391,
-STORE, 140398866223104, 140398866231295,
-STORE, 140398866231296, 140398866235391,
-SNULL, 140398868426751, 140398868430847,
-STORE, 140398868422656, 140398868426751,
-STORE, 140398868426752, 140398868430847,
-SNULL, 140398872236031, 140398872264703,
-STORE, 140398872231936, 140398872236031,
-STORE, 140398872236032, 140398872264703,
-SNULL, 28405759, 28454911,
-STORE, 28372992, 28405759,
-STORE, 28405760, 28454911,
-SNULL, 140398874509311, 140398874513407,
-STORE, 140398874505216, 140398874509311,
-STORE, 140398874509312, 140398874513407,
-ERASE, 140398874476544, 140398874505215,
-STORE, 43278336, 43413503,
-STORE, 140398872764416, 140398874447871,
-STORE, 140398874501120, 140398874505215,
-STORE, 140398872629248, 140398872764415,
-STORE, 43278336, 43556863,
-STORE, 140398847709184, 140398849806335,
-STORE, 140398874492928, 140398874505215,
-STORE, 140398874484736, 140398874505215,
-STORE, 140398874447872, 140398874484735,
-STORE, 140398872612864, 140398872764415,
-STORE, 43278336, 43692031,
-STORE, 43278336, 43880447,
-STORE, 140398872604672, 140398872764415,
-STORE, 140398872596480, 140398872764415,
-STORE, 43278336, 44044287,
-STORE, 140398872580096, 140398872764415,
-STORE, 140737488347136, 140737488351231,
-STORE, 140734403092480, 140737488351231,
-SNULL, 140734403096575, 140737488351231,
-STORE, 140734403092480, 140734403096575,
-STORE, 140734402961408, 140734403096575,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140240662380544, 140240664633343,
-SNULL, 140240662523903, 140240664633343,
-STORE, 140240662380544, 140240662523903,
-STORE, 140240662523904, 140240664633343,
-ERASE, 140240662523904, 140240664633343,
-STORE, 140240664621056, 140240664629247,
-STORE, 140240664629248, 140240664633343,
-STORE, 140734403145728, 140734403149823,
-STORE, 140734403133440, 140734403145727,
-STORE, 140240664592384, 140240664621055,
-STORE, 140240664584192, 140240664592383,
-STORE, 140240659218432, 140240662380543,
-SNULL, 140240659218432, 140240660279295,
-STORE, 140240660279296, 140240662380543,
-STORE, 140240659218432, 140240660279295,
-SNULL, 140240662372351, 140240662380543,
-STORE, 140240660279296, 140240662372351,
-STORE, 140240662372352, 140240662380543,
-ERASE, 140240662372352, 140240662380543,
-STORE, 140240662372352, 140240662380543,
-STORE, 140240655421440, 140240659218431,
-SNULL, 140240655421440, 140240657080319,
-STORE, 140240657080320, 140240659218431,
-STORE, 140240655421440, 140240657080319,
-SNULL, 140240659177471, 140240659218431,
-STORE, 140240657080320, 140240659177471,
-STORE, 140240659177472, 140240659218431,
-SNULL, 140240659177472, 140240659202047,
-STORE, 140240659202048, 140240659218431,
-STORE, 140240659177472, 140240659202047,
-ERASE, 140240659177472, 140240659202047,
-STORE, 140240659177472, 140240659202047,
-ERASE, 140240659202048, 140240659218431,
-STORE, 140240659202048, 140240659218431,
-STORE, 140240664571904, 140240664592383,
-SNULL, 140240659193855, 140240659202047,
-STORE, 140240659177472, 140240659193855,
-STORE, 140240659193856, 140240659202047,
-SNULL, 140240662376447, 140240662380543,
-STORE, 140240662372352, 140240662376447,
-STORE, 140240662376448, 140240662380543,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140240664625151, 140240664629247,
-STORE, 140240664621056, 140240664625151,
-STORE, 140240664625152, 140240664629247,
-ERASE, 140240664592384, 140240664621055,
-STORE, 30646272, 30781439,
-STORE, 30646272, 30928895,
-STORE, 140240662888448, 140240664571903,
-STORE, 94256659468288, 94256659578879,
-STORE, 94256661671936, 94256661680127,
-STORE, 94256661680128, 94256661684223,
-STORE, 94256661684224, 94256661692415,
-STORE, 94256687980544, 94256688115711,
-STORE, 139801712504832, 139801714163711,
-STORE, 139801714163712, 139801716260863,
-STORE, 139801716260864, 139801716277247,
-STORE, 139801716277248, 139801716285439,
-STORE, 139801716285440, 139801716301823,
-STORE, 139801716301824, 139801716445183,
-STORE, 139801718505472, 139801718513663,
-STORE, 139801718542336, 139801718546431,
-STORE, 139801718546432, 139801718550527,
-STORE, 139801718550528, 139801718554623,
-STORE, 140721575538688, 140721575673855,
-STORE, 140721577013248, 140721577025535,
-STORE, 140721577025536, 140721577029631,
-STORE, 140737488347136, 140737488351231,
-STORE, 140729259393024, 140737488351231,
-SNULL, 140729259397119, 140737488351231,
-STORE, 140729259393024, 140729259397119,
-STORE, 140729259261952, 140729259397119,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 139682376638464, 139682378891263,
-SNULL, 139682376781823, 139682378891263,
-STORE, 139682376638464, 139682376781823,
-STORE, 139682376781824, 139682378891263,
-ERASE, 139682376781824, 139682378891263,
-STORE, 139682378878976, 139682378887167,
-STORE, 139682378887168, 139682378891263,
-STORE, 140729260462080, 140729260466175,
-STORE, 140729260449792, 140729260462079,
-STORE, 139682378850304, 139682378878975,
-STORE, 139682378842112, 139682378850303,
-STORE, 139682373476352, 139682376638463,
-SNULL, 139682373476352, 139682374537215,
-STORE, 139682374537216, 139682376638463,
-STORE, 139682373476352, 139682374537215,
-SNULL, 139682376630271, 139682376638463,
-STORE, 139682374537216, 139682376630271,
-STORE, 139682376630272, 139682376638463,
-ERASE, 139682376630272, 139682376638463,
-STORE, 139682376630272, 139682376638463,
-STORE, 139682369679360, 139682373476351,
-SNULL, 139682369679360, 139682371338239,
-STORE, 139682371338240, 139682373476351,
-STORE, 139682369679360, 139682371338239,
-SNULL, 139682373435391, 139682373476351,
-STORE, 139682371338240, 139682373435391,
-STORE, 139682373435392, 139682373476351,
-SNULL, 139682373435392, 139682373459967,
-STORE, 139682373459968, 139682373476351,
-STORE, 139682373435392, 139682373459967,
-ERASE, 139682373435392, 139682373459967,
-STORE, 139682373435392, 139682373459967,
-ERASE, 139682373459968, 139682373476351,
-STORE, 139682373459968, 139682373476351,
-STORE, 139682378829824, 139682378850303,
-SNULL, 139682373451775, 139682373459967,
-STORE, 139682373435392, 139682373451775,
-STORE, 139682373451776, 139682373459967,
-SNULL, 139682376634367, 139682376638463,
-STORE, 139682376630272, 139682376634367,
-STORE, 139682376634368, 139682376638463,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 139682378883071, 139682378887167,
-STORE, 139682378878976, 139682378883071,
-STORE, 139682378883072, 139682378887167,
-ERASE, 139682378850304, 139682378878975,
-STORE, 10022912, 10158079,
-STORE, 10022912, 10305535,
-STORE, 139682377146368, 139682378829823,
-STORE, 140737488347136, 140737488351231,
-STORE, 140731831926784, 140737488351231,
-SNULL, 140731831930879, 140737488351231,
-STORE, 140731831926784, 140731831930879,
-STORE, 140731831795712, 140731831930879,
-STORE, 94615305261056, 94615307485183,
-SNULL, 94615305371647, 94615307485183,
-STORE, 94615305261056, 94615305371647,
-STORE, 94615305371648, 94615307485183,
-ERASE, 94615305371648, 94615307485183,
-STORE, 94615307464704, 94615307476991,
-STORE, 94615307476992, 94615307485183,
-STORE, 140163912994816, 140163915247615,
-SNULL, 140163913138175, 140163915247615,
-STORE, 140163912994816, 140163913138175,
-STORE, 140163913138176, 140163915247615,
-ERASE, 140163913138176, 140163915247615,
-STORE, 140163915235328, 140163915243519,
-STORE, 140163915243520, 140163915247615,
-STORE, 140731832217600, 140731832221695,
-STORE, 140731832205312, 140731832217599,
-STORE, 140163915206656, 140163915235327,
-STORE, 140163915198464, 140163915206655,
-STORE, 140163909197824, 140163912994815,
-SNULL, 140163909197824, 140163910856703,
-STORE, 140163910856704, 140163912994815,
-STORE, 140163909197824, 140163910856703,
-SNULL, 140163912953855, 140163912994815,
-STORE, 140163910856704, 140163912953855,
-STORE, 140163912953856, 140163912994815,
-SNULL, 140163912953856, 140163912978431,
-STORE, 140163912978432, 140163912994815,
-STORE, 140163912953856, 140163912978431,
-ERASE, 140163912953856, 140163912978431,
-STORE, 140163912953856, 140163912978431,
-ERASE, 140163912978432, 140163912994815,
-STORE, 140163912978432, 140163912994815,
-SNULL, 140163912970239, 140163912978431,
-STORE, 140163912953856, 140163912970239,
-STORE, 140163912970240, 140163912978431,
-SNULL, 94615307472895, 94615307476991,
-STORE, 94615307464704, 94615307472895,
-STORE, 94615307472896, 94615307476991,
-SNULL, 140163915239423, 140163915243519,
-STORE, 140163915235328, 140163915239423,
-STORE, 140163915239424, 140163915243519,
-ERASE, 140163915206656, 140163915235327,
-STORE, 94615330672640, 94615330807807,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725254479872, 140737488351231,
-SNULL, 140725254488063, 140737488351231,
-STORE, 140725254479872, 140725254488063,
-STORE, 140725254348800, 140725254488063,
-STORE, 94572781277184, 94572785741823,
-SNULL, 94572783312895, 94572785741823,
-STORE, 94572781277184, 94572783312895,
-STORE, 94572783312896, 94572785741823,
-ERASE, 94572783312896, 94572785741823,
-STORE, 94572785405952, 94572785455103,
-STORE, 94572785455104, 94572785741823,
-STORE, 139636001341440, 139636003594239,
-SNULL, 139636001484799, 139636003594239,
-STORE, 139636001341440, 139636001484799,
-STORE, 139636001484800, 139636003594239,
-ERASE, 139636001484800, 139636003594239,
-STORE, 139636003581952, 139636003590143,
-STORE, 139636003590144, 139636003594239,
-STORE, 140725255557120, 140725255561215,
-STORE, 140725255544832, 140725255557119,
-STORE, 139636003553280, 139636003581951,
-STORE, 139636003545088, 139636003553279,
-STORE, 139635998773248, 139636001341439,
-SNULL, 139635998773248, 139635999240191,
-STORE, 139635999240192, 139636001341439,
-STORE, 139635998773248, 139635999240191,
-SNULL, 139636001333247, 139636001341439,
-STORE, 139635999240192, 139636001333247,
-STORE, 139636001333248, 139636001341439,
-ERASE, 139636001333248, 139636001341439,
-STORE, 139636001333248, 139636001341439,
-STORE, 139635996569600, 139635998773247,
-SNULL, 139635996569600, 139635996671999,
-STORE, 139635996672000, 139635998773247,
-STORE, 139635996569600, 139635996671999,
-SNULL, 139635998765055, 139635998773247,
-STORE, 139635996672000, 139635998765055,
-STORE, 139635998765056, 139635998773247,
-ERASE, 139635998765056, 139635998773247,
-STORE, 139635998765056, 139635998773247,
-STORE, 139635994353664, 139635996569599,
-SNULL, 139635994353664, 139635994451967,
-STORE, 139635994451968, 139635996569599,
-STORE, 139635994353664, 139635994451967,
-SNULL, 139635996545023, 139635996569599,
-STORE, 139635994451968, 139635996545023,
-STORE, 139635996545024, 139635996569599,
-SNULL, 139635996545024, 139635996553215,
-STORE, 139635996553216, 139635996569599,
-STORE, 139635996545024, 139635996553215,
-ERASE, 139635996545024, 139635996553215,
-STORE, 139635996545024, 139635996553215,
-ERASE, 139635996553216, 139635996569599,
-STORE, 139635996553216, 139635996569599,
-STORE, 139635992223744, 139635994353663,
-SNULL, 139635992223744, 139635992252415,
-STORE, 139635992252416, 139635994353663,
-STORE, 139635992223744, 139635992252415,
-SNULL, 139635994345471, 139635994353663,
-STORE, 139635992252416, 139635994345471,
-STORE, 139635994345472, 139635994353663,
-ERASE, 139635994345472, 139635994353663,
-STORE, 139635994345472, 139635994353663,
-STORE, 139635988426752, 139635992223743,
-SNULL, 139635988426752, 139635990085631,
-STORE, 139635990085632, 139635992223743,
-STORE, 139635988426752, 139635990085631,
-SNULL, 139635992182783, 139635992223743,
-STORE, 139635990085632, 139635992182783,
-STORE, 139635992182784, 139635992223743,
-SNULL, 139635992182784, 139635992207359,
-STORE, 139635992207360, 139635992223743,
-STORE, 139635992182784, 139635992207359,
-ERASE, 139635992182784, 139635992207359,
-STORE, 139635992182784, 139635992207359,
-ERASE, 139635992207360, 139635992223743,
-STORE, 139635992207360, 139635992223743,
-STORE, 139636003536896, 139636003553279,
-SNULL, 139635992199167, 139635992207359,
-STORE, 139635992182784, 139635992199167,
-STORE, 139635992199168, 139635992207359,
-SNULL, 139635996549119, 139635996553215,
-STORE, 139635996545024, 139635996549119,
-STORE, 139635996549120, 139635996553215,
-SNULL, 139635994349567, 139635994353663,
-STORE, 139635994345472, 139635994349567,
-STORE, 139635994349568, 139635994353663,
-SNULL, 139635998769151, 139635998773247,
-STORE, 139635998765056, 139635998769151,
-STORE, 139635998769152, 139635998773247,
-SNULL, 139636001337343, 139636001341439,
-STORE, 139636001333248, 139636001337343,
-STORE, 139636001337344, 139636001341439,
-SNULL, 94572785418239, 94572785455103,
-STORE, 94572785405952, 94572785418239,
-STORE, 94572785418240, 94572785455103,
-SNULL, 139636003586047, 139636003590143,
-STORE, 139636003581952, 139636003586047,
-STORE, 139636003586048, 139636003590143,
-ERASE, 139636003553280, 139636003581951,
-STORE, 94572798435328, 94572798570495,
-STORE, 139636001853440, 139636003536895,
-STORE, 139635981426688, 139635988426751,
-STORE, 139635980615680, 139635981426687,
-STORE, 94572798435328, 94572798705663,
-STORE, 94572798435328, 94572798840831,
-STORE, 94572798435328, 94572798975999,
-STORE, 94572798435328, 94572799111167,
-STORE, 94572798435328, 94572799246335,
-STORE, 94572798435328, 94572799381503,
-STORE, 94572798435328, 94572799516671,
-STORE, 94572798435328, 94572799651839,
-STORE, 94572798435328, 94572799787007,
-STORE, 94572798435328, 94572799922175,
-STORE, 94572798435328, 94572800057343,
-STORE, 94572798435328, 94572800192511,
-STORE, 94572798435328, 94572800327679,
-STORE, 94572798435328, 94572800462847,
-STORE, 94572798435328, 94572800598015,
-STORE, 94572798435328, 94572800733183,
-STORE, 94572798435328, 94572800868351,
-STORE, 94572798435328, 94572801003519,
-STORE, 94572798435328, 94572801138687,
-STORE, 94572798435328, 94572801273855,
-STORE, 94572798435328, 94572801409023,
-STORE, 94572798435328, 94572801544191,
-STORE, 94572798435328, 94572801679359,
-STORE, 94572798435328, 94572801814527,
-STORE, 94572798435328, 94572801949695,
-STORE, 94572798435328, 94572802084863,
-STORE, 94572798435328, 94572802220031,
-STORE, 94572798435328, 94572802355199,
-STORE, 94572798435328, 94572802490367,
-STORE, 94572798435328, 94572802625535,
-STORE, 94572798435328, 94572802760703,
-STORE, 94572798435328, 94572802895871,
-STORE, 94572798435328, 94572803031039,
-STORE, 94572798435328, 94572803166207,
-STORE, 94572798435328, 94572803301375,
-STORE, 94572798435328, 94572803436543,
-STORE, 94572798435328, 94572803571711,
-STORE, 94572798435328, 94572803706879,
-STORE, 94572798435328, 94572803842047,
-STORE, 94572798435328, 94572803977215,
-STORE, 94572798435328, 94572804112383,
-STORE, 94572798435328, 94572804247551,
-STORE, 94572798435328, 94572804382719,
-STORE, 94572798435328, 94572804517887,
-STORE, 94572798435328, 94572804653055,
-STORE, 94572798435328, 94572804788223,
-STORE, 94572798435328, 94572804923391,
-STORE, 94572798435328, 94572805058559,
-STORE, 94572798435328, 94572805193727,
-STORE, 94572798435328, 94572805328895,
-STORE, 94572798435328, 94572805464063,
-STORE, 94572798435328, 94572805599231,
-STORE, 94572798435328, 94572805734399,
-STORE, 94572798435328, 94572805869567,
-STORE, 94572798435328, 94572806004735,
-STORE, 94572798435328, 94572806139903,
-STORE, 94572798435328, 94572806275071,
-STORE, 94572798435328, 94572806410239,
-STORE, 94572798435328, 94572806545407,
-STORE, 94572798435328, 94572806680575,
-STORE, 94572798435328, 94572806815743,
-STORE, 94572798435328, 94572806950911,
-STORE, 94572798435328, 94572807086079,
-STORE, 94572798435328, 94572807221247,
-STORE, 94572798435328, 94572807356415,
-STORE, 94572798435328, 94572807491583,
-STORE, 94572798435328, 94572807626751,
-STORE, 94572798435328, 94572807761919,
-STORE, 94572798435328, 94572807897087,
-STORE, 94572798435328, 94572808032255,
-STORE, 94572798435328, 94572808167423,
-STORE, 94572798435328, 94572808302591,
-STORE, 94572798435328, 94572808437759,
-STORE, 94572798435328, 94572808572927,
-ERASE, 139635981426688, 139635988426751,
-STORE, 139635985088512, 139635988426751,
-STORE, 139635778273280, 139635980615679,
-STORE, 139635567632384, 139635778273279,
-STORE, 94572798435328, 94572808716287,
-STORE, 139635984564224, 139635985088511,
-STORE, 139635559239680, 139635567632383,
-SNULL, 139635559243775, 139635567632383,
-STORE, 139635559239680, 139635559243775,
-STORE, 139635559243776, 139635567632383,
-STORE, 139635550846976, 139635559239679,
-SNULL, 139635550851071, 139635559239679,
-STORE, 139635550846976, 139635550851071,
-STORE, 139635550851072, 139635559239679,
-STORE, 139635542454272, 139635550846975,
-STORE, 139635408236544, 139635542454271,
-SNULL, 139635408236544, 139635426590719,
-STORE, 139635426590720, 139635542454271,
-STORE, 139635408236544, 139635426590719,
-ERASE, 139635408236544, 139635426590719,
-STORE, 139635292372992, 139635542454271,
-SNULL, 139635359481855, 139635542454271,
-STORE, 139635292372992, 139635359481855,
-STORE, 139635359481856, 139635542454271,
-SNULL, 139635359481856, 139635426590719,
-STORE, 139635426590720, 139635542454271,
-STORE, 139635359481856, 139635426590719,
-ERASE, 139635359481856, 139635426590719,
-SNULL, 139635542458367, 139635550846975,
-STORE, 139635542454272, 139635542458367,
-STORE, 139635542458368, 139635550846975,
-STORE, 139635418198016, 139635426590719,
-SNULL, 139635493699583, 139635542454271,
-STORE, 139635426590720, 139635493699583,
-STORE, 139635493699584, 139635542454271,
-ERASE, 139635493699584, 139635542454271,
-SNULL, 139635426725887, 139635493699583,
-STORE, 139635426590720, 139635426725887,
-STORE, 139635426725888, 139635493699583,
-SNULL, 139635292508159, 139635359481855,
-STORE, 139635292372992, 139635292508159,
-STORE, 139635292508160, 139635359481855,
-SNULL, 139635418202111, 139635426590719,
-STORE, 139635418198016, 139635418202111,
-STORE, 139635418202112, 139635426590719,
-STORE, 139635225264128, 139635292372991,
-STORE, 139635534061568, 139635542454271,
-SNULL, 139635534065663, 139635542454271,
-STORE, 139635534061568, 139635534065663,
-STORE, 139635534065664, 139635542454271,
-STORE, 139635525668864, 139635534061567,
-SNULL, 139635525672959, 139635534061567,
-STORE, 139635525668864, 139635525672959,
-STORE, 139635525672960, 139635534061567,
-SNULL, 139635225399295, 139635292372991,
-STORE, 139635225264128, 139635225399295,
-STORE, 139635225399296, 139635292372991,
-STORE, 139635091046400, 139635225264127,
-SNULL, 139635158155263, 139635225264127,
-STORE, 139635091046400, 139635158155263,
-STORE, 139635158155264, 139635225264127,
-ERASE, 139635158155264, 139635225264127,
-STORE, 139634956828672, 139635158155263,
-STORE, 139635517276160, 139635525668863,
-SNULL, 139635517280255, 139635525668863,
-STORE, 139635517276160, 139635517280255,
-STORE, 139635517280256, 139635525668863,
-SNULL, 139634956828672, 139635091046399,
-STORE, 139635091046400, 139635158155263,
-STORE, 139634956828672, 139635091046399,
-SNULL, 139635091181567, 139635158155263,
-STORE, 139635091046400, 139635091181567,
-STORE, 139635091181568, 139635158155263,
-SNULL, 139635023937535, 139635091046399,
-STORE, 139634956828672, 139635023937535,
-STORE, 139635023937536, 139635091046399,
-ERASE, 139635023937536, 139635091046399,
-STORE, 139634956828672, 139635091046399,
-SNULL, 139634956828672, 139635023937535,
-STORE, 139635023937536, 139635091046399,
-STORE, 139634956828672, 139635023937535,
-SNULL, 139635024072703, 139635091046399,
-STORE, 139635023937536, 139635024072703,
-STORE, 139635024072704, 139635091046399,
-STORE, 139635508883456, 139635517276159,
-SNULL, 139635508887551, 139635517276159,
-STORE, 139635508883456, 139635508887551,
-STORE, 139635508887552, 139635517276159,
-STORE, 139634822610944, 139635023937535,
-SNULL, 139634822610944, 139634956828671,
-STORE, 139634956828672, 139635023937535,
-STORE, 139634822610944, 139634956828671,
-SNULL, 139634956963839, 139635023937535,
-STORE, 139634956828672, 139634956963839,
-STORE, 139634956963840, 139635023937535,
-STORE, 139635500490752, 139635508883455,
-SNULL, 139634889719807, 139634956828671,
-STORE, 139634822610944, 139634889719807,
-STORE, 139634889719808, 139634956828671,
-ERASE, 139634889719808, 139634956828671,
-SNULL, 139635500494847, 139635508883455,
-STORE, 139635500490752, 139635500494847,
-STORE, 139635500494848, 139635508883455,
-SNULL, 139634822746111, 139634889719807,
-STORE, 139634822610944, 139634822746111,
-STORE, 139634822746112, 139634889719807,
-STORE, 139635409805312, 139635418198015,
-STORE, 139634822746112, 139634956828671,
-SNULL, 139634822746112, 139634889719807,
-STORE, 139634889719808, 139634956828671,
-STORE, 139634822746112, 139634889719807,
-SNULL, 139634889854975, 139634956828671,
-STORE, 139634889719808, 139634889854975,
-STORE, 139634889854976, 139634956828671,
-SNULL, 139635409809407, 139635418198015,
-STORE, 139635409805312, 139635409809407,
-STORE, 139635409809408, 139635418198015,
-STORE, 139635401412608, 139635409805311,
-STORE, 139634688393216, 139634822610943,
-SNULL, 139634755502079, 139634822610943,
-STORE, 139634688393216, 139634755502079,
-STORE, 139634755502080, 139634822610943,
-ERASE, 139634755502080, 139634822610943,
-SNULL, 139635401416703, 139635409805311,
-STORE, 139635401412608, 139635401416703,
-STORE, 139635401416704, 139635409805311,
-STORE, 139634554175488, 139634755502079,
-SNULL, 139634554175488, 139634688393215,
-STORE, 139634688393216, 139634755502079,
-STORE, 139634554175488, 139634688393215,
-SNULL, 139634688528383, 139634755502079,
-STORE, 139634688393216, 139634688528383,
-STORE, 139634688528384, 139634755502079,
-STORE, 139635393019904, 139635401412607,
-SNULL, 139634621284351, 139634688393215,
-STORE, 139634554175488, 139634621284351,
-STORE, 139634621284352, 139634688393215,
-ERASE, 139634621284352, 139634688393215,
-SNULL, 139634554310655, 139634621284351,
-STORE, 139634554175488, 139634554310655,
-STORE, 139634554310656, 139634621284351,
-STORE, 139634554310656, 139634688393215,
-SNULL, 139635393023999, 139635401412607,
-STORE, 139635393019904, 139635393023999,
-STORE, 139635393024000, 139635401412607,
-SNULL, 139634554310656, 139634621284351,
-STORE, 139634621284352, 139634688393215,
-STORE, 139634554310656, 139634621284351,
-SNULL, 139634621419519, 139634688393215,
-STORE, 139634621284352, 139634621419519,
-STORE, 139634621419520, 139634688393215,
-STORE, 139635384627200, 139635393019903,
-SNULL, 139635384631295, 139635393019903,
-STORE, 139635384627200, 139635384631295,
-STORE, 139635384631296, 139635393019903,
-STORE, 139635376234496, 139635384627199,
-SNULL, 139635376238591, 139635384627199,
-STORE, 139635376234496, 139635376238591,
-STORE, 139635376238592, 139635384627199,
-STORE, 139635367841792, 139635376234495,
-SNULL, 139635367845887, 139635376234495,
-STORE, 139635367841792, 139635367845887,
-STORE, 139635367845888, 139635376234495,
-STORE, 139634419957760, 139634554175487,
-SNULL, 139634487066623, 139634554175487,
-STORE, 139634419957760, 139634487066623,
-STORE, 139634487066624, 139634554175487,
-ERASE, 139634487066624, 139634554175487,
-STORE, 139635216871424, 139635225264127,
-SNULL, 139635216875519, 139635225264127,
-STORE, 139635216871424, 139635216875519,
-STORE, 139635216875520, 139635225264127,
-SNULL, 139634420092927, 139634487066623,
-STORE, 139634419957760, 139634420092927,
-STORE, 139634420092928, 139634487066623,
-STORE, 139635208478720, 139635216871423,
-SNULL, 139635208482815, 139635216871423,
-STORE, 139635208478720, 139635208482815,
-STORE, 139635208482816, 139635216871423,
-STORE, 139635200086016, 139635208478719,
-SNULL, 139635200090111, 139635208478719,
-STORE, 139635200086016, 139635200090111,
-STORE, 139635200090112, 139635208478719,
-STORE, 139635191693312, 139635200086015,
-SNULL, 139635191697407, 139635200086015,
-STORE, 139635191693312, 139635191697407,
-STORE, 139635191697408, 139635200086015,
-STORE, 139635183300608, 139635191693311,
-SNULL, 139635183304703, 139635191693311,
-STORE, 139635183300608, 139635183304703,
-STORE, 139635183304704, 139635191693311,
-STORE, 139634420092928, 139634554175487,
-SNULL, 139634420092928, 139634487066623,
-STORE, 139634487066624, 139634554175487,
-STORE, 139634420092928, 139634487066623,
-SNULL, 139634487201791, 139634554175487,
-STORE, 139634487066624, 139634487201791,
-STORE, 139634487201792, 139634554175487,
-ERASE, 139635559239680, 139635559243775,
-ERASE, 139635559243776, 139635567632383,
-ERASE, 139635550846976, 139635550851071,
-ERASE, 139635550851072, 139635559239679,
-ERASE, 139635542454272, 139635542458367,
-ERASE, 139635542458368, 139635550846975,
-ERASE, 139635418198016, 139635418202111,
-ERASE, 139635418202112, 139635426590719,
-ERASE, 139635534061568, 139635534065663,
-ERASE, 139635534065664, 139635542454271,
-ERASE, 139635525668864, 139635525672959,
-ERASE, 139635525672960, 139635534061567,
-ERASE, 139635517276160, 139635517280255,
-ERASE, 139635517280256, 139635525668863,
-ERASE, 139635508883456, 139635508887551,
-ERASE, 139635508887552, 139635517276159,
-ERASE, 139635500490752, 139635500494847,
-ERASE, 139635500494848, 139635508883455,
-ERASE, 139635409805312, 139635409809407,
-ERASE, 139635409809408, 139635418198015,
-ERASE, 139635401412608, 139635401416703,
-ERASE, 139635401416704, 139635409805311,
-ERASE, 139635393019904, 139635393023999,
-ERASE, 139635393024000, 139635401412607,
-ERASE, 139635384627200, 139635384631295,
-ERASE, 139635384631296, 139635393019903,
- };
- unsigned long set25[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722547441664, 140737488351231,
-SNULL, 140722547449855, 140737488351231,
-STORE, 140722547441664, 140722547449855,
-STORE, 140722547310592, 140722547449855,
-STORE, 94827521732608, 94827523956735,
-SNULL, 94827521843199, 94827523956735,
-STORE, 94827521732608, 94827521843199,
-STORE, 94827521843200, 94827523956735,
-ERASE, 94827521843200, 94827523956735,
-STORE, 94827523936256, 94827523948543,
-STORE, 94827523948544, 94827523956735,
-STORE, 139816136847360, 139816139100159,
-SNULL, 139816136990719, 139816139100159,
-STORE, 139816136847360, 139816136990719,
-STORE, 139816136990720, 139816139100159,
-ERASE, 139816136990720, 139816139100159,
-STORE, 139816139087872, 139816139096063,
-STORE, 139816139096064, 139816139100159,
-STORE, 140722548142080, 140722548146175,
-STORE, 140722548129792, 140722548142079,
-STORE, 139816139059200, 139816139087871,
-STORE, 139816139051008, 139816139059199,
-STORE, 139816133050368, 139816136847359,
-SNULL, 139816133050368, 139816134709247,
-STORE, 139816134709248, 139816136847359,
-STORE, 139816133050368, 139816134709247,
-SNULL, 139816136806399, 139816136847359,
-STORE, 139816134709248, 139816136806399,
-STORE, 139816136806400, 139816136847359,
-SNULL, 139816136806400, 139816136830975,
-STORE, 139816136830976, 139816136847359,
-STORE, 139816136806400, 139816136830975,
-ERASE, 139816136806400, 139816136830975,
-STORE, 139816136806400, 139816136830975,
-ERASE, 139816136830976, 139816136847359,
-STORE, 139816136830976, 139816136847359,
-SNULL, 139816136822783, 139816136830975,
-STORE, 139816136806400, 139816136822783,
-STORE, 139816136822784, 139816136830975,
-SNULL, 94827523944447, 94827523948543,
-STORE, 94827523936256, 94827523944447,
-STORE, 94827523944448, 94827523948543,
-SNULL, 139816139091967, 139816139096063,
-STORE, 139816139087872, 139816139091967,
-STORE, 139816139091968, 139816139096063,
-ERASE, 139816139059200, 139816139087871,
-STORE, 94827534970880, 94827535106047,
-STORE, 94114394132480, 94114394345471,
-STORE, 94114396442624, 94114396446719,
-STORE, 94114396446720, 94114396454911,
-STORE, 94114396454912, 94114396467199,
-STORE, 94114421575680, 94114427715583,
-STORE, 139934313955328, 139934315614207,
-STORE, 139934315614208, 139934317711359,
-STORE, 139934317711360, 139934317727743,
-STORE, 139934317727744, 139934317735935,
-STORE, 139934317735936, 139934317752319,
-STORE, 139934317752320, 139934317764607,
-STORE, 139934317764608, 139934319857663,
-STORE, 139934319857664, 139934319861759,
-STORE, 139934319861760, 139934319865855,
-STORE, 139934319865856, 139934320009215,
-STORE, 139934320377856, 139934322061311,
-STORE, 139934322061312, 139934322077695,
-STORE, 139934322106368, 139934322110463,
-STORE, 139934322110464, 139934322114559,
-STORE, 139934322114560, 139934322118655,
-STORE, 140731200376832, 140731200516095,
-STORE, 140731200929792, 140731200942079,
-STORE, 140731200942080, 140731200946175,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140734133174272, 140737488351231,
-SNULL, 140734133182463, 140737488351231,
-STORE, 140734133174272, 140734133182463,
-STORE, 140734133043200, 140734133182463,
-STORE, 94412675600384, 94412677824511,
-SNULL, 94412675710975, 94412677824511,
-STORE, 94412675600384, 94412675710975,
-STORE, 94412675710976, 94412677824511,
-ERASE, 94412675710976, 94412677824511,
-STORE, 94412677804032, 94412677816319,
-STORE, 94412677816320, 94412677824511,
-STORE, 140320087945216, 140320090198015,
-SNULL, 140320088088575, 140320090198015,
-STORE, 140320087945216, 140320088088575,
-STORE, 140320088088576, 140320090198015,
-ERASE, 140320088088576, 140320090198015,
-STORE, 140320090185728, 140320090193919,
-STORE, 140320090193920, 140320090198015,
-STORE, 140734134591488, 140734134595583,
-STORE, 140734134579200, 140734134591487,
-STORE, 140320090157056, 140320090185727,
-STORE, 140320090148864, 140320090157055,
-STORE, 140320084148224, 140320087945215,
-SNULL, 140320084148224, 140320085807103,
-STORE, 140320085807104, 140320087945215,
-STORE, 140320084148224, 140320085807103,
-SNULL, 140320087904255, 140320087945215,
-STORE, 140320085807104, 140320087904255,
-STORE, 140320087904256, 140320087945215,
-SNULL, 140320087904256, 140320087928831,
-STORE, 140320087928832, 140320087945215,
-STORE, 140320087904256, 140320087928831,
-ERASE, 140320087904256, 140320087928831,
-STORE, 140320087904256, 140320087928831,
-ERASE, 140320087928832, 140320087945215,
-STORE, 140320087928832, 140320087945215,
-SNULL, 140320087920639, 140320087928831,
-STORE, 140320087904256, 140320087920639,
-STORE, 140320087920640, 140320087928831,
-SNULL, 94412677812223, 94412677816319,
-STORE, 94412677804032, 94412677812223,
-STORE, 94412677812224, 94412677816319,
-SNULL, 140320090189823, 140320090193919,
-STORE, 140320090185728, 140320090189823,
-STORE, 140320090189824, 140320090193919,
-ERASE, 140320090157056, 140320090185727,
-STORE, 94412684546048, 94412684681215,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723005485056, 140737488351231,
-SNULL, 140723005493247, 140737488351231,
-STORE, 140723005485056, 140723005493247,
-STORE, 140723005353984, 140723005493247,
-STORE, 94387431936000, 94387434160127,
-SNULL, 94387432046591, 94387434160127,
-STORE, 94387431936000, 94387432046591,
-STORE, 94387432046592, 94387434160127,
-ERASE, 94387432046592, 94387434160127,
-STORE, 94387434139648, 94387434151935,
-STORE, 94387434151936, 94387434160127,
-STORE, 140151675392000, 140151677644799,
-SNULL, 140151675535359, 140151677644799,
-STORE, 140151675392000, 140151675535359,
-STORE, 140151675535360, 140151677644799,
-ERASE, 140151675535360, 140151677644799,
-STORE, 140151677632512, 140151677640703,
-STORE, 140151677640704, 140151677644799,
-STORE, 140723005784064, 140723005788159,
-STORE, 140723005771776, 140723005784063,
-STORE, 140151677603840, 140151677632511,
-STORE, 140151677595648, 140151677603839,
-STORE, 140151671595008, 140151675391999,
-SNULL, 140151671595008, 140151673253887,
-STORE, 140151673253888, 140151675391999,
-STORE, 140151671595008, 140151673253887,
-SNULL, 140151675351039, 140151675391999,
-STORE, 140151673253888, 140151675351039,
-STORE, 140151675351040, 140151675391999,
-SNULL, 140151675351040, 140151675375615,
-STORE, 140151675375616, 140151675391999,
-STORE, 140151675351040, 140151675375615,
-ERASE, 140151675351040, 140151675375615,
-STORE, 140151675351040, 140151675375615,
-ERASE, 140151675375616, 140151675391999,
-STORE, 140151675375616, 140151675391999,
-SNULL, 140151675367423, 140151675375615,
-STORE, 140151675351040, 140151675367423,
-STORE, 140151675367424, 140151675375615,
-SNULL, 94387434147839, 94387434151935,
-STORE, 94387434139648, 94387434147839,
-STORE, 94387434147840, 94387434151935,
-SNULL, 140151677636607, 140151677640703,
-STORE, 140151677632512, 140151677636607,
-STORE, 140151677636608, 140151677640703,
-ERASE, 140151677603840, 140151677632511,
-STORE, 94387458818048, 94387458953215,
-STORE, 94909010997248, 94909011210239,
-STORE, 94909013307392, 94909013311487,
-STORE, 94909013311488, 94909013319679,
-STORE, 94909013319680, 94909013331967,
-STORE, 94909014827008, 94909023371263,
-STORE, 140712411975680, 140712413634559,
-STORE, 140712413634560, 140712415731711,
-STORE, 140712415731712, 140712415748095,
-STORE, 140712415748096, 140712415756287,
-STORE, 140712415756288, 140712415772671,
-STORE, 140712415772672, 140712415784959,
-STORE, 140712415784960, 140712417878015,
-STORE, 140712417878016, 140712417882111,
-STORE, 140712417882112, 140712417886207,
-STORE, 140712417886208, 140712418029567,
-STORE, 140712418398208, 140712420081663,
-STORE, 140712420081664, 140712420098047,
-STORE, 140712420126720, 140712420130815,
-STORE, 140712420130816, 140712420134911,
-STORE, 140712420134912, 140712420139007,
-STORE, 140729293111296, 140729293250559,
-STORE, 140729293307904, 140729293320191,
-STORE, 140729293320192, 140729293324287,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140720541691904, 140737488351231,
-SNULL, 140720541700095, 140737488351231,
-STORE, 140720541691904, 140720541700095,
-STORE, 140720541560832, 140720541700095,
-STORE, 94203603419136, 94203605643263,
-SNULL, 94203603529727, 94203605643263,
-STORE, 94203603419136, 94203603529727,
-STORE, 94203603529728, 94203605643263,
-ERASE, 94203603529728, 94203605643263,
-STORE, 94203605622784, 94203605635071,
-STORE, 94203605635072, 94203605643263,
-STORE, 139847623081984, 139847625334783,
-SNULL, 139847623225343, 139847625334783,
-STORE, 139847623081984, 139847623225343,
-STORE, 139847623225344, 139847625334783,
-ERASE, 139847623225344, 139847625334783,
-STORE, 139847625322496, 139847625330687,
-STORE, 139847625330688, 139847625334783,
-STORE, 140720542547968, 140720542552063,
-STORE, 140720542535680, 140720542547967,
-STORE, 139847625293824, 139847625322495,
-STORE, 139847625285632, 139847625293823,
-STORE, 139847619284992, 139847623081983,
-SNULL, 139847619284992, 139847620943871,
-STORE, 139847620943872, 139847623081983,
-STORE, 139847619284992, 139847620943871,
-SNULL, 139847623041023, 139847623081983,
-STORE, 139847620943872, 139847623041023,
-STORE, 139847623041024, 139847623081983,
-SNULL, 139847623041024, 139847623065599,
-STORE, 139847623065600, 139847623081983,
-STORE, 139847623041024, 139847623065599,
-ERASE, 139847623041024, 139847623065599,
-STORE, 139847623041024, 139847623065599,
-ERASE, 139847623065600, 139847623081983,
-STORE, 139847623065600, 139847623081983,
-SNULL, 139847623057407, 139847623065599,
-STORE, 139847623041024, 139847623057407,
-STORE, 139847623057408, 139847623065599,
-SNULL, 94203605630975, 94203605635071,
-STORE, 94203605622784, 94203605630975,
-STORE, 94203605630976, 94203605635071,
-SNULL, 139847625326591, 139847625330687,
-STORE, 139847625322496, 139847625326591,
-STORE, 139847625326592, 139847625330687,
-ERASE, 139847625293824, 139847625322495,
-STORE, 94203634880512, 94203635015679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721428738048, 140737488351231,
-SNULL, 140721428746239, 140737488351231,
-STORE, 140721428738048, 140721428746239,
-STORE, 140721428606976, 140721428746239,
-STORE, 93968808378368, 93968810602495,
-SNULL, 93968808488959, 93968810602495,
-STORE, 93968808378368, 93968808488959,
-STORE, 93968808488960, 93968810602495,
-ERASE, 93968808488960, 93968810602495,
-STORE, 93968810582016, 93968810594303,
-STORE, 93968810594304, 93968810602495,
-STORE, 140397757026304, 140397759279103,
-SNULL, 140397757169663, 140397759279103,
-STORE, 140397757026304, 140397757169663,
-STORE, 140397757169664, 140397759279103,
-ERASE, 140397757169664, 140397759279103,
-STORE, 140397759266816, 140397759275007,
-STORE, 140397759275008, 140397759279103,
-STORE, 140721430368256, 140721430372351,
-STORE, 140721430355968, 140721430368255,
-STORE, 140397759238144, 140397759266815,
-STORE, 140397759229952, 140397759238143,
-STORE, 140397753229312, 140397757026303,
-SNULL, 140397753229312, 140397754888191,
-STORE, 140397754888192, 140397757026303,
-STORE, 140397753229312, 140397754888191,
-SNULL, 140397756985343, 140397757026303,
-STORE, 140397754888192, 140397756985343,
-STORE, 140397756985344, 140397757026303,
-SNULL, 140397756985344, 140397757009919,
-STORE, 140397757009920, 140397757026303,
-STORE, 140397756985344, 140397757009919,
-ERASE, 140397756985344, 140397757009919,
-STORE, 140397756985344, 140397757009919,
-ERASE, 140397757009920, 140397757026303,
-STORE, 140397757009920, 140397757026303,
-SNULL, 140397757001727, 140397757009919,
-STORE, 140397756985344, 140397757001727,
-STORE, 140397757001728, 140397757009919,
-SNULL, 93968810590207, 93968810594303,
-STORE, 93968810582016, 93968810590207,
-STORE, 93968810590208, 93968810594303,
-SNULL, 140397759270911, 140397759275007,
-STORE, 140397759266816, 140397759270911,
-STORE, 140397759270912, 140397759275007,
-ERASE, 140397759238144, 140397759266815,
-STORE, 93968837025792, 93968837160959,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721751044096, 140737488351231,
-SNULL, 140721751052287, 140737488351231,
-STORE, 140721751044096, 140721751052287,
-STORE, 140721750913024, 140721751052287,
-STORE, 94426051657728, 94426053881855,
-SNULL, 94426051768319, 94426053881855,
-STORE, 94426051657728, 94426051768319,
-STORE, 94426051768320, 94426053881855,
-ERASE, 94426051768320, 94426053881855,
-STORE, 94426053861376, 94426053873663,
-STORE, 94426053873664, 94426053881855,
-STORE, 140228456181760, 140228458434559,
-SNULL, 140228456325119, 140228458434559,
-STORE, 140228456181760, 140228456325119,
-STORE, 140228456325120, 140228458434559,
-ERASE, 140228456325120, 140228458434559,
-STORE, 140228458422272, 140228458430463,
-STORE, 140228458430464, 140228458434559,
-STORE, 140721751117824, 140721751121919,
-STORE, 140721751105536, 140721751117823,
-STORE, 140228458393600, 140228458422271,
-STORE, 140228458385408, 140228458393599,
-STORE, 140228452384768, 140228456181759,
-SNULL, 140228452384768, 140228454043647,
-STORE, 140228454043648, 140228456181759,
-STORE, 140228452384768, 140228454043647,
-SNULL, 140228456140799, 140228456181759,
-STORE, 140228454043648, 140228456140799,
-STORE, 140228456140800, 140228456181759,
-SNULL, 140228456140800, 140228456165375,
-STORE, 140228456165376, 140228456181759,
-STORE, 140228456140800, 140228456165375,
-ERASE, 140228456140800, 140228456165375,
-STORE, 140228456140800, 140228456165375,
-ERASE, 140228456165376, 140228456181759,
-STORE, 140228456165376, 140228456181759,
-SNULL, 140228456157183, 140228456165375,
-STORE, 140228456140800, 140228456157183,
-STORE, 140228456157184, 140228456165375,
-SNULL, 94426053869567, 94426053873663,
-STORE, 94426053861376, 94426053869567,
-STORE, 94426053869568, 94426053873663,
-SNULL, 140228458426367, 140228458430463,
-STORE, 140228458422272, 140228458426367,
-STORE, 140228458426368, 140228458430463,
-ERASE, 140228458393600, 140228458422271,
-STORE, 94426073681920, 94426073817087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732727623680, 140737488351231,
-SNULL, 140732727631871, 140737488351231,
-STORE, 140732727623680, 140732727631871,
-STORE, 140732727492608, 140732727631871,
-STORE, 94537485996032, 94537488220159,
-SNULL, 94537486106623, 94537488220159,
-STORE, 94537485996032, 94537486106623,
-STORE, 94537486106624, 94537488220159,
-ERASE, 94537486106624, 94537488220159,
-STORE, 94537488199680, 94537488211967,
-STORE, 94537488211968, 94537488220159,
-STORE, 140446578036736, 140446580289535,
-SNULL, 140446578180095, 140446580289535,
-STORE, 140446578036736, 140446578180095,
-STORE, 140446578180096, 140446580289535,
-ERASE, 140446578180096, 140446580289535,
-STORE, 140446580277248, 140446580285439,
-STORE, 140446580285440, 140446580289535,
-STORE, 140732727758848, 140732727762943,
-STORE, 140732727746560, 140732727758847,
-STORE, 140446580248576, 140446580277247,
-STORE, 140446580240384, 140446580248575,
-STORE, 140446574239744, 140446578036735,
-SNULL, 140446574239744, 140446575898623,
-STORE, 140446575898624, 140446578036735,
-STORE, 140446574239744, 140446575898623,
-SNULL, 140446577995775, 140446578036735,
-STORE, 140446575898624, 140446577995775,
-STORE, 140446577995776, 140446578036735,
-SNULL, 140446577995776, 140446578020351,
-STORE, 140446578020352, 140446578036735,
-STORE, 140446577995776, 140446578020351,
-ERASE, 140446577995776, 140446578020351,
-STORE, 140446577995776, 140446578020351,
-ERASE, 140446578020352, 140446578036735,
-STORE, 140446578020352, 140446578036735,
-SNULL, 140446578012159, 140446578020351,
-STORE, 140446577995776, 140446578012159,
-STORE, 140446578012160, 140446578020351,
-SNULL, 94537488207871, 94537488211967,
-STORE, 94537488199680, 94537488207871,
-STORE, 94537488207872, 94537488211967,
-SNULL, 140446580281343, 140446580285439,
-STORE, 140446580277248, 140446580281343,
-STORE, 140446580281344, 140446580285439,
-ERASE, 140446580248576, 140446580277247,
-STORE, 94537489014784, 94537489149951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728766808064, 140737488351231,
-SNULL, 140728766816255, 140737488351231,
-STORE, 140728766808064, 140728766816255,
-STORE, 140728766676992, 140728766816255,
-STORE, 94418513866752, 94418516090879,
-SNULL, 94418513977343, 94418516090879,
-STORE, 94418513866752, 94418513977343,
-STORE, 94418513977344, 94418516090879,
-ERASE, 94418513977344, 94418516090879,
-STORE, 94418516070400, 94418516082687,
-STORE, 94418516082688, 94418516090879,
-STORE, 140556479520768, 140556481773567,
-SNULL, 140556479664127, 140556481773567,
-STORE, 140556479520768, 140556479664127,
-STORE, 140556479664128, 140556481773567,
-ERASE, 140556479664128, 140556481773567,
-STORE, 140556481761280, 140556481769471,
-STORE, 140556481769472, 140556481773567,
-STORE, 140728767148032, 140728767152127,
-STORE, 140728767135744, 140728767148031,
-STORE, 140556481732608, 140556481761279,
-STORE, 140556481724416, 140556481732607,
-STORE, 140556475723776, 140556479520767,
-SNULL, 140556475723776, 140556477382655,
-STORE, 140556477382656, 140556479520767,
-STORE, 140556475723776, 140556477382655,
-SNULL, 140556479479807, 140556479520767,
-STORE, 140556477382656, 140556479479807,
-STORE, 140556479479808, 140556479520767,
-SNULL, 140556479479808, 140556479504383,
-STORE, 140556479504384, 140556479520767,
-STORE, 140556479479808, 140556479504383,
-ERASE, 140556479479808, 140556479504383,
-STORE, 140556479479808, 140556479504383,
-ERASE, 140556479504384, 140556479520767,
-STORE, 140556479504384, 140556479520767,
-SNULL, 140556479496191, 140556479504383,
-STORE, 140556479479808, 140556479496191,
-STORE, 140556479496192, 140556479504383,
-SNULL, 94418516078591, 94418516082687,
-STORE, 94418516070400, 94418516078591,
-STORE, 94418516078592, 94418516082687,
-SNULL, 140556481765375, 140556481769471,
-STORE, 140556481761280, 140556481765375,
-STORE, 140556481765376, 140556481769471,
-ERASE, 140556481732608, 140556481761279,
-STORE, 94418541113344, 94418541248511,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723945873408, 140737488351231,
-SNULL, 140723945881599, 140737488351231,
-STORE, 140723945873408, 140723945881599,
-STORE, 140723945742336, 140723945881599,
-STORE, 94543169773568, 94543171997695,
-SNULL, 94543169884159, 94543171997695,
-STORE, 94543169773568, 94543169884159,
-STORE, 94543169884160, 94543171997695,
-ERASE, 94543169884160, 94543171997695,
-STORE, 94543171977216, 94543171989503,
-STORE, 94543171989504, 94543171997695,
-STORE, 139890420883456, 139890423136255,
-SNULL, 139890421026815, 139890423136255,
-STORE, 139890420883456, 139890421026815,
-STORE, 139890421026816, 139890423136255,
-ERASE, 139890421026816, 139890423136255,
-STORE, 139890423123968, 139890423132159,
-STORE, 139890423132160, 139890423136255,
-STORE, 140723946102784, 140723946106879,
-STORE, 140723946090496, 140723946102783,
-STORE, 139890423095296, 139890423123967,
-STORE, 139890423087104, 139890423095295,
-STORE, 139890417086464, 139890420883455,
-SNULL, 139890417086464, 139890418745343,
-STORE, 139890418745344, 139890420883455,
-STORE, 139890417086464, 139890418745343,
-SNULL, 139890420842495, 139890420883455,
-STORE, 139890418745344, 139890420842495,
-STORE, 139890420842496, 139890420883455,
-SNULL, 139890420842496, 139890420867071,
-STORE, 139890420867072, 139890420883455,
-STORE, 139890420842496, 139890420867071,
-ERASE, 139890420842496, 139890420867071,
-STORE, 139890420842496, 139890420867071,
-ERASE, 139890420867072, 139890420883455,
-STORE, 139890420867072, 139890420883455,
-SNULL, 139890420858879, 139890420867071,
-STORE, 139890420842496, 139890420858879,
-STORE, 139890420858880, 139890420867071,
-SNULL, 94543171985407, 94543171989503,
-STORE, 94543171977216, 94543171985407,
-STORE, 94543171985408, 94543171989503,
-SNULL, 139890423128063, 139890423132159,
-STORE, 139890423123968, 139890423128063,
-STORE, 139890423128064, 139890423132159,
-ERASE, 139890423095296, 139890423123967,
-STORE, 94543197097984, 94543197233151,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140736205979648, 140737488351231,
-SNULL, 140736205987839, 140737488351231,
-STORE, 140736205979648, 140736205987839,
-STORE, 140736205848576, 140736205987839,
-STORE, 94913209913344, 94913212137471,
-SNULL, 94913210023935, 94913212137471,
-STORE, 94913209913344, 94913210023935,
-STORE, 94913210023936, 94913212137471,
-ERASE, 94913210023936, 94913212137471,
-STORE, 94913212116992, 94913212129279,
-STORE, 94913212129280, 94913212137471,
-STORE, 140006323052544, 140006325305343,
-SNULL, 140006323195903, 140006325305343,
-STORE, 140006323052544, 140006323195903,
-STORE, 140006323195904, 140006325305343,
-ERASE, 140006323195904, 140006325305343,
-STORE, 140006325293056, 140006325301247,
-STORE, 140006325301248, 140006325305343,
-STORE, 140736206716928, 140736206721023,
-STORE, 140736206704640, 140736206716927,
-STORE, 140006325264384, 140006325293055,
-STORE, 140006325256192, 140006325264383,
-STORE, 140006319255552, 140006323052543,
-SNULL, 140006319255552, 140006320914431,
-STORE, 140006320914432, 140006323052543,
-STORE, 140006319255552, 140006320914431,
-SNULL, 140006323011583, 140006323052543,
-STORE, 140006320914432, 140006323011583,
-STORE, 140006323011584, 140006323052543,
-SNULL, 140006323011584, 140006323036159,
-STORE, 140006323036160, 140006323052543,
-STORE, 140006323011584, 140006323036159,
-ERASE, 140006323011584, 140006323036159,
-STORE, 140006323011584, 140006323036159,
-ERASE, 140006323036160, 140006323052543,
-STORE, 140006323036160, 140006323052543,
-SNULL, 140006323027967, 140006323036159,
-STORE, 140006323011584, 140006323027967,
-STORE, 140006323027968, 140006323036159,
-SNULL, 94913212125183, 94913212129279,
-STORE, 94913212116992, 94913212125183,
-STORE, 94913212125184, 94913212129279,
-SNULL, 140006325297151, 140006325301247,
-STORE, 140006325293056, 140006325297151,
-STORE, 140006325297152, 140006325301247,
-ERASE, 140006325264384, 140006325293055,
-STORE, 94913239932928, 94913240068095,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140726926897152, 140737488351231,
-SNULL, 140726926905343, 140737488351231,
-STORE, 140726926897152, 140726926905343,
-STORE, 140726926766080, 140726926905343,
-STORE, 94213246820352, 94213249044479,
-SNULL, 94213246930943, 94213249044479,
-STORE, 94213246820352, 94213246930943,
-STORE, 94213246930944, 94213249044479,
-ERASE, 94213246930944, 94213249044479,
-STORE, 94213249024000, 94213249036287,
-STORE, 94213249036288, 94213249044479,
-STORE, 140368830242816, 140368832495615,
-SNULL, 140368830386175, 140368832495615,
-STORE, 140368830242816, 140368830386175,
-STORE, 140368830386176, 140368832495615,
-ERASE, 140368830386176, 140368832495615,
-STORE, 140368832483328, 140368832491519,
-STORE, 140368832491520, 140368832495615,
-STORE, 140726926999552, 140726927003647,
-STORE, 140726926987264, 140726926999551,
-STORE, 140368832454656, 140368832483327,
-STORE, 140368832446464, 140368832454655,
-STORE, 140368826445824, 140368830242815,
-SNULL, 140368826445824, 140368828104703,
-STORE, 140368828104704, 140368830242815,
-STORE, 140368826445824, 140368828104703,
-SNULL, 140368830201855, 140368830242815,
-STORE, 140368828104704, 140368830201855,
-STORE, 140368830201856, 140368830242815,
-SNULL, 140368830201856, 140368830226431,
-STORE, 140368830226432, 140368830242815,
-STORE, 140368830201856, 140368830226431,
-ERASE, 140368830201856, 140368830226431,
-STORE, 140368830201856, 140368830226431,
-ERASE, 140368830226432, 140368830242815,
-STORE, 140368830226432, 140368830242815,
-SNULL, 140368830218239, 140368830226431,
-STORE, 140368830201856, 140368830218239,
-STORE, 140368830218240, 140368830226431,
-SNULL, 94213249032191, 94213249036287,
-STORE, 94213249024000, 94213249032191,
-STORE, 94213249032192, 94213249036287,
-SNULL, 140368832487423, 140368832491519,
-STORE, 140368832483328, 140368832487423,
-STORE, 140368832487424, 140368832491519,
-ERASE, 140368832454656, 140368832483327,
-STORE, 94213267435520, 94213267570687,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728954130432, 140737488351231,
-SNULL, 140728954138623, 140737488351231,
-STORE, 140728954130432, 140728954138623,
-STORE, 140728953999360, 140728954138623,
-STORE, 94672570966016, 94672573190143,
-SNULL, 94672571076607, 94672573190143,
-STORE, 94672570966016, 94672571076607,
-STORE, 94672571076608, 94672573190143,
-ERASE, 94672571076608, 94672573190143,
-STORE, 94672573169664, 94672573181951,
-STORE, 94672573181952, 94672573190143,
-STORE, 140201696735232, 140201698988031,
-SNULL, 140201696878591, 140201698988031,
-STORE, 140201696735232, 140201696878591,
-STORE, 140201696878592, 140201698988031,
-ERASE, 140201696878592, 140201698988031,
-STORE, 140201698975744, 140201698983935,
-STORE, 140201698983936, 140201698988031,
-STORE, 140728954163200, 140728954167295,
-STORE, 140728954150912, 140728954163199,
-STORE, 140201698947072, 140201698975743,
-STORE, 140201698938880, 140201698947071,
-STORE, 140201692938240, 140201696735231,
-SNULL, 140201692938240, 140201694597119,
-STORE, 140201694597120, 140201696735231,
-STORE, 140201692938240, 140201694597119,
-SNULL, 140201696694271, 140201696735231,
-STORE, 140201694597120, 140201696694271,
-STORE, 140201696694272, 140201696735231,
-SNULL, 140201696694272, 140201696718847,
-STORE, 140201696718848, 140201696735231,
-STORE, 140201696694272, 140201696718847,
-ERASE, 140201696694272, 140201696718847,
-STORE, 140201696694272, 140201696718847,
-ERASE, 140201696718848, 140201696735231,
-STORE, 140201696718848, 140201696735231,
-SNULL, 140201696710655, 140201696718847,
-STORE, 140201696694272, 140201696710655,
-STORE, 140201696710656, 140201696718847,
-SNULL, 94672573177855, 94672573181951,
-STORE, 94672573169664, 94672573177855,
-STORE, 94672573177856, 94672573181951,
-SNULL, 140201698979839, 140201698983935,
-STORE, 140201698975744, 140201698979839,
-STORE, 140201698979840, 140201698983935,
-ERASE, 140201698947072, 140201698975743,
-STORE, 94672595689472, 94672595824639,
-STORE, 94114394132480, 94114394345471,
-STORE, 94114396442624, 94114396446719,
-STORE, 94114396446720, 94114396454911,
-STORE, 94114396454912, 94114396467199,
-STORE, 94114421575680, 94114428256255,
-STORE, 139934313955328, 139934315614207,
-STORE, 139934315614208, 139934317711359,
-STORE, 139934317711360, 139934317727743,
-STORE, 139934317727744, 139934317735935,
-STORE, 139934317735936, 139934317752319,
-STORE, 139934317752320, 139934317764607,
-STORE, 139934317764608, 139934319857663,
-STORE, 139934319857664, 139934319861759,
-STORE, 139934319861760, 139934319865855,
-STORE, 139934319865856, 139934320009215,
-STORE, 139934320377856, 139934322061311,
-STORE, 139934322061312, 139934322077695,
-STORE, 139934322106368, 139934322110463,
-STORE, 139934322110464, 139934322114559,
-STORE, 139934322114560, 139934322118655,
-STORE, 140731200376832, 140731200516095,
-STORE, 140731200929792, 140731200942079,
-STORE, 140731200942080, 140731200946175,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721532362752, 140737488351231,
-SNULL, 140721532370943, 140737488351231,
-STORE, 140721532362752, 140721532370943,
-STORE, 140721532231680, 140721532370943,
-STORE, 94467222597632, 94467224821759,
-SNULL, 94467222708223, 94467224821759,
-STORE, 94467222597632, 94467222708223,
-STORE, 94467222708224, 94467224821759,
-ERASE, 94467222708224, 94467224821759,
-STORE, 94467224801280, 94467224813567,
-STORE, 94467224813568, 94467224821759,
-STORE, 140191433543680, 140191435796479,
-SNULL, 140191433687039, 140191435796479,
-STORE, 140191433543680, 140191433687039,
-STORE, 140191433687040, 140191435796479,
-ERASE, 140191433687040, 140191435796479,
-STORE, 140191435784192, 140191435792383,
-STORE, 140191435792384, 140191435796479,
-STORE, 140721533034496, 140721533038591,
-STORE, 140721533022208, 140721533034495,
-STORE, 140191435755520, 140191435784191,
-STORE, 140191435747328, 140191435755519,
-STORE, 140191429746688, 140191433543679,
-SNULL, 140191429746688, 140191431405567,
-STORE, 140191431405568, 140191433543679,
-STORE, 140191429746688, 140191431405567,
-SNULL, 140191433502719, 140191433543679,
-STORE, 140191431405568, 140191433502719,
-STORE, 140191433502720, 140191433543679,
-SNULL, 140191433502720, 140191433527295,
-STORE, 140191433527296, 140191433543679,
-STORE, 140191433502720, 140191433527295,
-ERASE, 140191433502720, 140191433527295,
-STORE, 140191433502720, 140191433527295,
-ERASE, 140191433527296, 140191433543679,
-STORE, 140191433527296, 140191433543679,
-SNULL, 140191433519103, 140191433527295,
-STORE, 140191433502720, 140191433519103,
-STORE, 140191433519104, 140191433527295,
-SNULL, 94467224809471, 94467224813567,
-STORE, 94467224801280, 94467224809471,
-STORE, 94467224809472, 94467224813567,
-SNULL, 140191435788287, 140191435792383,
-STORE, 140191435784192, 140191435788287,
-STORE, 140191435788288, 140191435792383,
-ERASE, 140191435755520, 140191435784191,
-STORE, 94467251847168, 94467251982335,
-STORE, 94367895400448, 94367895613439,
-STORE, 94367897710592, 94367897714687,
-STORE, 94367897714688, 94367897722879,
-STORE, 94367897722880, 94367897735167,
-STORE, 94367925264384, 94367926861823,
-STORE, 139801317548032, 139801319206911,
-STORE, 139801319206912, 139801321304063,
-STORE, 139801321304064, 139801321320447,
-STORE, 139801321320448, 139801321328639,
-STORE, 139801321328640, 139801321345023,
-STORE, 139801321345024, 139801321357311,
-STORE, 139801321357312, 139801323450367,
-STORE, 139801323450368, 139801323454463,
-STORE, 139801323454464, 139801323458559,
-STORE, 139801323458560, 139801323601919,
-STORE, 139801323970560, 139801325654015,
-STORE, 139801325654016, 139801325670399,
-STORE, 139801325699072, 139801325703167,
-STORE, 139801325703168, 139801325707263,
-STORE, 139801325707264, 139801325711359,
-STORE, 140724442861568, 140724443000831,
-STORE, 140724443611136, 140724443623423,
-STORE, 140724443623424, 140724443627519,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731353149440, 140737488351231,
-SNULL, 140731353157631, 140737488351231,
-STORE, 140731353149440, 140731353157631,
-STORE, 140731353018368, 140731353157631,
-STORE, 94310379503616, 94310381838335,
-SNULL, 94310379716607, 94310381838335,
-STORE, 94310379503616, 94310379716607,
-STORE, 94310379716608, 94310381838335,
-ERASE, 94310379716608, 94310381838335,
-STORE, 94310381813760, 94310381826047,
-STORE, 94310381826048, 94310381838335,
-STORE, 140515434659840, 140515436912639,
-SNULL, 140515434803199, 140515436912639,
-STORE, 140515434659840, 140515434803199,
-STORE, 140515434803200, 140515436912639,
-ERASE, 140515434803200, 140515436912639,
-STORE, 140515436900352, 140515436908543,
-STORE, 140515436908544, 140515436912639,
-STORE, 140731353886720, 140731353890815,
-STORE, 140731353874432, 140731353886719,
-STORE, 140515436871680, 140515436900351,
-STORE, 140515436863488, 140515436871679,
-STORE, 140515432546304, 140515434659839,
-SNULL, 140515432546304, 140515432558591,
-STORE, 140515432558592, 140515434659839,
-STORE, 140515432546304, 140515432558591,
-SNULL, 140515434651647, 140515434659839,
-STORE, 140515432558592, 140515434651647,
-STORE, 140515434651648, 140515434659839,
-ERASE, 140515434651648, 140515434659839,
-STORE, 140515434651648, 140515434659839,
-STORE, 140515428749312, 140515432546303,
-SNULL, 140515428749312, 140515430408191,
-STORE, 140515430408192, 140515432546303,
-STORE, 140515428749312, 140515430408191,
-SNULL, 140515432505343, 140515432546303,
-STORE, 140515430408192, 140515432505343,
-STORE, 140515432505344, 140515432546303,
-SNULL, 140515432505344, 140515432529919,
-STORE, 140515432529920, 140515432546303,
-STORE, 140515432505344, 140515432529919,
-ERASE, 140515432505344, 140515432529919,
-STORE, 140515432505344, 140515432529919,
-ERASE, 140515432529920, 140515432546303,
-STORE, 140515432529920, 140515432546303,
-STORE, 140515436855296, 140515436871679,
-SNULL, 140515432521727, 140515432529919,
-STORE, 140515432505344, 140515432521727,
-STORE, 140515432521728, 140515432529919,
-SNULL, 140515434655743, 140515434659839,
-STORE, 140515434651648, 140515434655743,
-STORE, 140515434655744, 140515434659839,
-SNULL, 94310381817855, 94310381826047,
-STORE, 94310381813760, 94310381817855,
-STORE, 94310381817856, 94310381826047,
-SNULL, 140515436904447, 140515436908543,
-STORE, 140515436900352, 140515436904447,
-STORE, 140515436904448, 140515436908543,
-ERASE, 140515436871680, 140515436900351,
-STORE, 94310395457536, 94310395592703,
-STORE, 140515435171840, 140515436855295,
-STORE, 94310395457536, 94310395727871,
-STORE, 94310395457536, 94310395863039,
-STORE, 94310395457536, 94310396047359,
-SNULL, 94310396022783, 94310396047359,
-STORE, 94310395457536, 94310396022783,
-STORE, 94310396022784, 94310396047359,
-ERASE, 94310396022784, 94310396047359,
-STORE, 94310395457536, 94310396157951,
-STORE, 94310395457536, 94310396293119,
-SNULL, 94310396276735, 94310396293119,
-STORE, 94310395457536, 94310396276735,
-STORE, 94310396276736, 94310396293119,
-ERASE, 94310396276736, 94310396293119,
-STORE, 94310395457536, 94310396411903,
-SNULL, 94310396383231, 94310396411903,
-STORE, 94310395457536, 94310396383231,
-STORE, 94310396383232, 94310396411903,
-ERASE, 94310396383232, 94310396411903,
-STORE, 94310395457536, 94310396522495,
-STORE, 94310395457536, 94310396674047,
-SNULL, 94310396657663, 94310396674047,
-STORE, 94310395457536, 94310396657663,
-STORE, 94310396657664, 94310396674047,
-ERASE, 94310396657664, 94310396674047,
-SNULL, 94310396624895, 94310396657663,
-STORE, 94310395457536, 94310396624895,
-STORE, 94310396624896, 94310396657663,
-ERASE, 94310396624896, 94310396657663,
-STORE, 94310395457536, 94310396776447,
-SNULL, 94310396764159, 94310396776447,
-STORE, 94310395457536, 94310396764159,
-STORE, 94310396764160, 94310396776447,
-ERASE, 94310396764160, 94310396776447,
-SNULL, 94310396739583, 94310396764159,
-STORE, 94310395457536, 94310396739583,
-STORE, 94310396739584, 94310396764159,
-ERASE, 94310396739584, 94310396764159,
-STORE, 94310395457536, 94310396882943,
-STORE, 94310395457536, 94310397018111,
-STORE, 94310395457536, 94310397161471,
-STORE, 94310395457536, 94310397300735,
-SNULL, 94310397292543, 94310397300735,
-STORE, 94310395457536, 94310397292543,
-STORE, 94310397292544, 94310397300735,
-ERASE, 94310397292544, 94310397300735,
-STORE, 94359222210560, 94359222423551,
-STORE, 94359224520704, 94359224524799,
-STORE, 94359224524800, 94359224532991,
-STORE, 94359224532992, 94359224545279,
-STORE, 94359238348800, 94359239385087,
-STORE, 140675699838976, 140675701497855,
-STORE, 140675701497856, 140675703595007,
-STORE, 140675703595008, 140675703611391,
-STORE, 140675703611392, 140675703619583,
-STORE, 140675703619584, 140675703635967,
-STORE, 140675703635968, 140675703648255,
-STORE, 140675703648256, 140675705741311,
-STORE, 140675705741312, 140675705745407,
-STORE, 140675705745408, 140675705749503,
-STORE, 140675705749504, 140675705892863,
-STORE, 140675706261504, 140675707944959,
-STORE, 140675707944960, 140675707961343,
-STORE, 140675707990016, 140675707994111,
-STORE, 140675707994112, 140675707998207,
-STORE, 140675707998208, 140675708002303,
-STORE, 140721324634112, 140721324773375,
-STORE, 140721324810240, 140721324822527,
-STORE, 140721324822528, 140721324826623,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724099678208, 140737488351231,
-SNULL, 140724099686399, 140737488351231,
-STORE, 140724099678208, 140724099686399,
-STORE, 140724099547136, 140724099686399,
-STORE, 94586638516224, 94586640850943,
-SNULL, 94586638729215, 94586640850943,
-STORE, 94586638516224, 94586638729215,
-STORE, 94586638729216, 94586640850943,
-ERASE, 94586638729216, 94586640850943,
-STORE, 94586640826368, 94586640838655,
-STORE, 94586640838656, 94586640850943,
-STORE, 140371033796608, 140371036049407,
-SNULL, 140371033939967, 140371036049407,
-STORE, 140371033796608, 140371033939967,
-STORE, 140371033939968, 140371036049407,
-ERASE, 140371033939968, 140371036049407,
-STORE, 140371036037120, 140371036045311,
-STORE, 140371036045312, 140371036049407,
-STORE, 140724100001792, 140724100005887,
-STORE, 140724099989504, 140724100001791,
-STORE, 140371036008448, 140371036037119,
-STORE, 140371036000256, 140371036008447,
-STORE, 140371031683072, 140371033796607,
-SNULL, 140371031683072, 140371031695359,
-STORE, 140371031695360, 140371033796607,
-STORE, 140371031683072, 140371031695359,
-SNULL, 140371033788415, 140371033796607,
-STORE, 140371031695360, 140371033788415,
-STORE, 140371033788416, 140371033796607,
-ERASE, 140371033788416, 140371033796607,
-STORE, 140371033788416, 140371033796607,
-STORE, 140371027886080, 140371031683071,
-SNULL, 140371027886080, 140371029544959,
-STORE, 140371029544960, 140371031683071,
-STORE, 140371027886080, 140371029544959,
-SNULL, 140371031642111, 140371031683071,
-STORE, 140371029544960, 140371031642111,
-STORE, 140371031642112, 140371031683071,
-SNULL, 140371031642112, 140371031666687,
-STORE, 140371031666688, 140371031683071,
-STORE, 140371031642112, 140371031666687,
-ERASE, 140371031642112, 140371031666687,
-STORE, 140371031642112, 140371031666687,
-ERASE, 140371031666688, 140371031683071,
-STORE, 140371031666688, 140371031683071,
-STORE, 140371035992064, 140371036008447,
-SNULL, 140371031658495, 140371031666687,
-STORE, 140371031642112, 140371031658495,
-STORE, 140371031658496, 140371031666687,
-SNULL, 140371033792511, 140371033796607,
-STORE, 140371033788416, 140371033792511,
-STORE, 140371033792512, 140371033796607,
-SNULL, 94586640830463, 94586640838655,
-STORE, 94586640826368, 94586640830463,
-STORE, 94586640830464, 94586640838655,
-SNULL, 140371036041215, 140371036045311,
-STORE, 140371036037120, 140371036041215,
-STORE, 140371036041216, 140371036045311,
-ERASE, 140371036008448, 140371036037119,
-STORE, 94586663849984, 94586663985151,
-STORE, 140371034308608, 140371035992063,
-STORE, 94586663849984, 94586664120319,
-STORE, 94586663849984, 94586664255487,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140727532937216, 140737488351231,
-SNULL, 140727532945407, 140737488351231,
-STORE, 140727532937216, 140727532945407,
-STORE, 140727532806144, 140727532945407,
-STORE, 94849780191232, 94849782525951,
-SNULL, 94849780404223, 94849782525951,
-STORE, 94849780191232, 94849780404223,
-STORE, 94849780404224, 94849782525951,
-ERASE, 94849780404224, 94849782525951,
-STORE, 94849782501376, 94849782513663,
-STORE, 94849782513664, 94849782525951,
-STORE, 140382070218752, 140382072471551,
-SNULL, 140382070362111, 140382072471551,
-STORE, 140382070218752, 140382070362111,
-STORE, 140382070362112, 140382072471551,
-ERASE, 140382070362112, 140382072471551,
-STORE, 140382072459264, 140382072467455,
-STORE, 140382072467456, 140382072471551,
-STORE, 140727533092864, 140727533096959,
-STORE, 140727533080576, 140727533092863,
-STORE, 140382072430592, 140382072459263,
-STORE, 140382072422400, 140382072430591,
-STORE, 140382068105216, 140382070218751,
-SNULL, 140382068105216, 140382068117503,
-STORE, 140382068117504, 140382070218751,
-STORE, 140382068105216, 140382068117503,
-SNULL, 140382070210559, 140382070218751,
-STORE, 140382068117504, 140382070210559,
-STORE, 140382070210560, 140382070218751,
-ERASE, 140382070210560, 140382070218751,
-STORE, 140382070210560, 140382070218751,
-STORE, 140382064308224, 140382068105215,
-SNULL, 140382064308224, 140382065967103,
-STORE, 140382065967104, 140382068105215,
-STORE, 140382064308224, 140382065967103,
-SNULL, 140382068064255, 140382068105215,
-STORE, 140382065967104, 140382068064255,
-STORE, 140382068064256, 140382068105215,
-SNULL, 140382068064256, 140382068088831,
-STORE, 140382068088832, 140382068105215,
-STORE, 140382068064256, 140382068088831,
-ERASE, 140382068064256, 140382068088831,
-STORE, 140382068064256, 140382068088831,
-ERASE, 140382068088832, 140382068105215,
-STORE, 140382068088832, 140382068105215,
-STORE, 140382072414208, 140382072430591,
-SNULL, 140382068080639, 140382068088831,
-STORE, 140382068064256, 140382068080639,
-STORE, 140382068080640, 140382068088831,
-SNULL, 140382070214655, 140382070218751,
-STORE, 140382070210560, 140382070214655,
-STORE, 140382070214656, 140382070218751,
-SNULL, 94849782505471, 94849782513663,
-STORE, 94849782501376, 94849782505471,
-STORE, 94849782505472, 94849782513663,
-SNULL, 140382072463359, 140382072467455,
-STORE, 140382072459264, 140382072463359,
-STORE, 140382072463360, 140382072467455,
-ERASE, 140382072430592, 140382072459263,
-STORE, 94849782845440, 94849782980607,
-STORE, 140382070730752, 140382072414207,
-STORE, 94849782845440, 94849783115775,
-STORE, 94849782845440, 94849783250943,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722594377728, 140737488351231,
-SNULL, 140722594385919, 140737488351231,
-STORE, 140722594377728, 140722594385919,
-STORE, 140722594246656, 140722594385919,
-STORE, 94421466353664, 94421468577791,
-SNULL, 94421466464255, 94421468577791,
-STORE, 94421466353664, 94421466464255,
-STORE, 94421466464256, 94421468577791,
-ERASE, 94421466464256, 94421468577791,
-STORE, 94421468557312, 94421468569599,
-STORE, 94421468569600, 94421468577791,
-STORE, 140345458057216, 140345460310015,
-SNULL, 140345458200575, 140345460310015,
-STORE, 140345458057216, 140345458200575,
-STORE, 140345458200576, 140345460310015,
-ERASE, 140345458200576, 140345460310015,
-STORE, 140345460297728, 140345460305919,
-STORE, 140345460305920, 140345460310015,
-STORE, 140722595557376, 140722595561471,
-STORE, 140722595545088, 140722595557375,
-STORE, 140345460269056, 140345460297727,
-STORE, 140345460260864, 140345460269055,
-STORE, 140345454260224, 140345458057215,
-SNULL, 140345454260224, 140345455919103,
-STORE, 140345455919104, 140345458057215,
-STORE, 140345454260224, 140345455919103,
-SNULL, 140345458016255, 140345458057215,
-STORE, 140345455919104, 140345458016255,
-STORE, 140345458016256, 140345458057215,
-SNULL, 140345458016256, 140345458040831,
-STORE, 140345458040832, 140345458057215,
-STORE, 140345458016256, 140345458040831,
-ERASE, 140345458016256, 140345458040831,
-STORE, 140345458016256, 140345458040831,
-ERASE, 140345458040832, 140345458057215,
-STORE, 140345458040832, 140345458057215,
-SNULL, 140345458032639, 140345458040831,
-STORE, 140345458016256, 140345458032639,
-STORE, 140345458032640, 140345458040831,
-SNULL, 94421468565503, 94421468569599,
-STORE, 94421468557312, 94421468565503,
-STORE, 94421468565504, 94421468569599,
-SNULL, 140345460301823, 140345460305919,
-STORE, 140345460297728, 140345460301823,
-STORE, 140345460301824, 140345460305919,
-ERASE, 140345460269056, 140345460297727,
-STORE, 94421496004608, 94421496139775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140726096302080, 140737488351231,
-SNULL, 140726096310271, 140737488351231,
-STORE, 140726096302080, 140726096310271,
-STORE, 140726096171008, 140726096310271,
-STORE, 94101992124416, 94101994459135,
-SNULL, 94101992337407, 94101994459135,
-STORE, 94101992124416, 94101992337407,
-STORE, 94101992337408, 94101994459135,
-ERASE, 94101992337408, 94101994459135,
-STORE, 94101994434560, 94101994446847,
-STORE, 94101994446848, 94101994459135,
-STORE, 140192085594112, 140192087846911,
-SNULL, 140192085737471, 140192087846911,
-STORE, 140192085594112, 140192085737471,
-STORE, 140192085737472, 140192087846911,
-ERASE, 140192085737472, 140192087846911,
-STORE, 140192087834624, 140192087842815,
-STORE, 140192087842816, 140192087846911,
-STORE, 140726096375808, 140726096379903,
-STORE, 140726096363520, 140726096375807,
-STORE, 140192087805952, 140192087834623,
-STORE, 140192087797760, 140192087805951,
-STORE, 140192083480576, 140192085594111,
-SNULL, 140192083480576, 140192083492863,
-STORE, 140192083492864, 140192085594111,
-STORE, 140192083480576, 140192083492863,
-SNULL, 140192085585919, 140192085594111,
-STORE, 140192083492864, 140192085585919,
-STORE, 140192085585920, 140192085594111,
-ERASE, 140192085585920, 140192085594111,
-STORE, 140192085585920, 140192085594111,
-STORE, 140192079683584, 140192083480575,
-SNULL, 140192079683584, 140192081342463,
-STORE, 140192081342464, 140192083480575,
-STORE, 140192079683584, 140192081342463,
-SNULL, 140192083439615, 140192083480575,
-STORE, 140192081342464, 140192083439615,
-STORE, 140192083439616, 140192083480575,
-SNULL, 140192083439616, 140192083464191,
-STORE, 140192083464192, 140192083480575,
-STORE, 140192083439616, 140192083464191,
-ERASE, 140192083439616, 140192083464191,
-STORE, 140192083439616, 140192083464191,
-ERASE, 140192083464192, 140192083480575,
-STORE, 140192083464192, 140192083480575,
-STORE, 140192087789568, 140192087805951,
-SNULL, 140192083455999, 140192083464191,
-STORE, 140192083439616, 140192083455999,
-STORE, 140192083456000, 140192083464191,
-SNULL, 140192085590015, 140192085594111,
-STORE, 140192085585920, 140192085590015,
-STORE, 140192085590016, 140192085594111,
-SNULL, 94101994438655, 94101994446847,
-STORE, 94101994434560, 94101994438655,
-STORE, 94101994438656, 94101994446847,
-SNULL, 140192087838719, 140192087842815,
-STORE, 140192087834624, 140192087838719,
-STORE, 140192087838720, 140192087842815,
-ERASE, 140192087805952, 140192087834623,
-STORE, 94102011887616, 94102012022783,
-STORE, 140192086106112, 140192087789567,
-STORE, 94102011887616, 94102012157951,
-STORE, 94102011887616, 94102012293119,
-STORE, 94102011887616, 94102012440575,
-SNULL, 94102012428287, 94102012440575,
-STORE, 94102011887616, 94102012428287,
-STORE, 94102012428288, 94102012440575,
-ERASE, 94102012428288, 94102012440575,
-STORE, 94102011887616, 94102012579839,
-STORE, 94102011887616, 94102012715007,
-SNULL, 94102012694527, 94102012715007,
-STORE, 94102011887616, 94102012694527,
-STORE, 94102012694528, 94102012715007,
-ERASE, 94102012694528, 94102012715007,
-STORE, 94102011887616, 94102012833791,
-STORE, 94102011887616, 94102012968959,
-SNULL, 94102012927999, 94102012968959,
-STORE, 94102011887616, 94102012927999,
-STORE, 94102012928000, 94102012968959,
-ERASE, 94102012928000, 94102012968959,
-STORE, 94102011887616, 94102013091839,
-SNULL, 94102013075455, 94102013091839,
-STORE, 94102011887616, 94102013075455,
-STORE, 94102013075456, 94102013091839,
-ERASE, 94102013075456, 94102013091839,
-STORE, 94102011887616, 94102013210623,
-STORE, 94102011887616, 94102013345791,
-STORE, 93968727965696, 93968728178687,
-STORE, 93968730275840, 93968730279935,
-STORE, 93968730279936, 93968730288127,
-STORE, 93968730288128, 93968730300415,
-STORE, 93968731140096, 93968732704767,
-STORE, 140588443168768, 140588444827647,
-STORE, 140588444827648, 140588446924799,
-STORE, 140588446924800, 140588446941183,
-STORE, 140588446941184, 140588446949375,
-STORE, 140588446949376, 140588446965759,
-STORE, 140588446965760, 140588446978047,
-STORE, 140588446978048, 140588449071103,
-STORE, 140588449071104, 140588449075199,
-STORE, 140588449075200, 140588449079295,
-STORE, 140588449079296, 140588449222655,
-STORE, 140588449591296, 140588451274751,
-STORE, 140588451274752, 140588451291135,
-STORE, 140588451319808, 140588451323903,
-STORE, 140588451323904, 140588451327999,
-STORE, 140588451328000, 140588451332095,
-STORE, 140733877239808, 140733877379071,
-STORE, 140733878702080, 140733878714367,
-STORE, 140733878714368, 140733878718463,
-STORE, 93968727965696, 93968728178687,
-STORE, 93968730275840, 93968730279935,
-STORE, 93968730279936, 93968730288127,
-STORE, 93968730288128, 93968730300415,
-STORE, 93968731140096, 93968732991487,
-STORE, 140588443168768, 140588444827647,
-STORE, 140588444827648, 140588446924799,
-STORE, 140588446924800, 140588446941183,
-STORE, 140588446941184, 140588446949375,
-STORE, 140588446949376, 140588446965759,
-STORE, 140588446965760, 140588446978047,
-STORE, 140588446978048, 140588449071103,
-STORE, 140588449071104, 140588449075199,
-STORE, 140588449075200, 140588449079295,
-STORE, 140588449079296, 140588449222655,
-STORE, 140588449591296, 140588451274751,
-STORE, 140588451274752, 140588451291135,
-STORE, 140588451319808, 140588451323903,
-STORE, 140588451323904, 140588451327999,
-STORE, 140588451328000, 140588451332095,
-STORE, 140733877239808, 140733877379071,
-STORE, 140733878702080, 140733878714367,
-STORE, 140733878714368, 140733878718463,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733054472192, 140737488351231,
-SNULL, 140733054480383, 140737488351231,
-STORE, 140733054472192, 140733054480383,
-STORE, 140733054341120, 140733054480383,
-STORE, 93992873623552, 93992875847679,
-SNULL, 93992873734143, 93992875847679,
-STORE, 93992873623552, 93992873734143,
-STORE, 93992873734144, 93992875847679,
-ERASE, 93992873734144, 93992875847679,
-STORE, 93992875827200, 93992875839487,
-STORE, 93992875839488, 93992875847679,
-STORE, 139790881488896, 139790883741695,
-SNULL, 139790881632255, 139790883741695,
-STORE, 139790881488896, 139790881632255,
-STORE, 139790881632256, 139790883741695,
-ERASE, 139790881632256, 139790883741695,
-STORE, 139790883729408, 139790883737599,
-STORE, 139790883737600, 139790883741695,
-STORE, 140733054754816, 140733054758911,
-STORE, 140733054742528, 140733054754815,
-STORE, 139790883700736, 139790883729407,
-STORE, 139790883692544, 139790883700735,
-STORE, 139790877691904, 139790881488895,
-SNULL, 139790877691904, 139790879350783,
-STORE, 139790879350784, 139790881488895,
-STORE, 139790877691904, 139790879350783,
-SNULL, 139790881447935, 139790881488895,
-STORE, 139790879350784, 139790881447935,
-STORE, 139790881447936, 139790881488895,
-SNULL, 139790881447936, 139790881472511,
-STORE, 139790881472512, 139790881488895,
-STORE, 139790881447936, 139790881472511,
-ERASE, 139790881447936, 139790881472511,
-STORE, 139790881447936, 139790881472511,
-ERASE, 139790881472512, 139790881488895,
-STORE, 139790881472512, 139790881488895,
-SNULL, 139790881464319, 139790881472511,
-STORE, 139790881447936, 139790881464319,
-STORE, 139790881464320, 139790881472511,
-SNULL, 93992875835391, 93992875839487,
-STORE, 93992875827200, 93992875835391,
-STORE, 93992875835392, 93992875839487,
-SNULL, 139790883733503, 139790883737599,
-STORE, 139790883729408, 139790883733503,
-STORE, 139790883733504, 139790883737599,
-ERASE, 139790883700736, 139790883729407,
-STORE, 93992877031424, 93992877166591,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728550887424, 140737488351231,
-SNULL, 140728550895615, 140737488351231,
-STORE, 140728550887424, 140728550895615,
-STORE, 140728550756352, 140728550895615,
-STORE, 94707634077696, 94707636301823,
-SNULL, 94707634188287, 94707636301823,
-STORE, 94707634077696, 94707634188287,
-STORE, 94707634188288, 94707636301823,
-ERASE, 94707634188288, 94707636301823,
-STORE, 94707636281344, 94707636293631,
-STORE, 94707636293632, 94707636301823,
-STORE, 140553545666560, 140553547919359,
-SNULL, 140553545809919, 140553547919359,
-STORE, 140553545666560, 140553545809919,
-STORE, 140553545809920, 140553547919359,
-ERASE, 140553545809920, 140553547919359,
-STORE, 140553547907072, 140553547915263,
-STORE, 140553547915264, 140553547919359,
-STORE, 140728552374272, 140728552378367,
-STORE, 140728552361984, 140728552374271,
-STORE, 140553547878400, 140553547907071,
-STORE, 140553547870208, 140553547878399,
-STORE, 140553541869568, 140553545666559,
-SNULL, 140553541869568, 140553543528447,
-STORE, 140553543528448, 140553545666559,
-STORE, 140553541869568, 140553543528447,
-SNULL, 140553545625599, 140553545666559,
-STORE, 140553543528448, 140553545625599,
-STORE, 140553545625600, 140553545666559,
-SNULL, 140553545625600, 140553545650175,
-STORE, 140553545650176, 140553545666559,
-STORE, 140553545625600, 140553545650175,
-ERASE, 140553545625600, 140553545650175,
-STORE, 140553545625600, 140553545650175,
-ERASE, 140553545650176, 140553545666559,
-STORE, 140553545650176, 140553545666559,
-SNULL, 140553545641983, 140553545650175,
-STORE, 140553545625600, 140553545641983,
-STORE, 140553545641984, 140553545650175,
-SNULL, 94707636289535, 94707636293631,
-STORE, 94707636281344, 94707636289535,
-STORE, 94707636289536, 94707636293631,
-SNULL, 140553547911167, 140553547915263,
-STORE, 140553547907072, 140553547911167,
-STORE, 140553547911168, 140553547915263,
-ERASE, 140553547878400, 140553547907071,
-STORE, 94707651411968, 94707651547135,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732168695808, 140737488351231,
-SNULL, 140732168703999, 140737488351231,
-STORE, 140732168695808, 140732168703999,
-STORE, 140732168564736, 140732168703999,
-STORE, 94454287859712, 94454290083839,
-SNULL, 94454287970303, 94454290083839,
-STORE, 94454287859712, 94454287970303,
-STORE, 94454287970304, 94454290083839,
-ERASE, 94454287970304, 94454290083839,
-STORE, 94454290063360, 94454290075647,
-STORE, 94454290075648, 94454290083839,
-STORE, 140564947107840, 140564949360639,
-SNULL, 140564947251199, 140564949360639,
-STORE, 140564947107840, 140564947251199,
-STORE, 140564947251200, 140564949360639,
-ERASE, 140564947251200, 140564949360639,
-STORE, 140564949348352, 140564949356543,
-STORE, 140564949356544, 140564949360639,
-STORE, 140732168843264, 140732168847359,
-STORE, 140732168830976, 140732168843263,
-STORE, 140564949319680, 140564949348351,
-STORE, 140564949311488, 140564949319679,
-STORE, 140564943310848, 140564947107839,
-SNULL, 140564943310848, 140564944969727,
-STORE, 140564944969728, 140564947107839,
-STORE, 140564943310848, 140564944969727,
-SNULL, 140564947066879, 140564947107839,
-STORE, 140564944969728, 140564947066879,
-STORE, 140564947066880, 140564947107839,
-SNULL, 140564947066880, 140564947091455,
-STORE, 140564947091456, 140564947107839,
-STORE, 140564947066880, 140564947091455,
-ERASE, 140564947066880, 140564947091455,
-STORE, 140564947066880, 140564947091455,
-ERASE, 140564947091456, 140564947107839,
-STORE, 140564947091456, 140564947107839,
-SNULL, 140564947083263, 140564947091455,
-STORE, 140564947066880, 140564947083263,
-STORE, 140564947083264, 140564947091455,
-SNULL, 94454290071551, 94454290075647,
-STORE, 94454290063360, 94454290071551,
-STORE, 94454290071552, 94454290075647,
-SNULL, 140564949352447, 140564949356543,
-STORE, 140564949348352, 140564949352447,
-STORE, 140564949352448, 140564949356543,
-ERASE, 140564949319680, 140564949348351,
-STORE, 94454316236800, 94454316371967,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735155617792, 140737488351231,
-SNULL, 140735155625983, 140737488351231,
-STORE, 140735155617792, 140735155625983,
-STORE, 140735155486720, 140735155625983,
-STORE, 93915969556480, 93915971780607,
-SNULL, 93915969667071, 93915971780607,
-STORE, 93915969556480, 93915969667071,
-STORE, 93915969667072, 93915971780607,
-ERASE, 93915969667072, 93915971780607,
-STORE, 93915971760128, 93915971772415,
-STORE, 93915971772416, 93915971780607,
-STORE, 140141164605440, 140141166858239,
-SNULL, 140141164748799, 140141166858239,
-STORE, 140141164605440, 140141164748799,
-STORE, 140141164748800, 140141166858239,
-ERASE, 140141164748800, 140141166858239,
-STORE, 140141166845952, 140141166854143,
-STORE, 140141166854144, 140141166858239,
-STORE, 140735155691520, 140735155695615,
-STORE, 140735155679232, 140735155691519,
-STORE, 140141166817280, 140141166845951,
-STORE, 140141166809088, 140141166817279,
-STORE, 140141160808448, 140141164605439,
-SNULL, 140141160808448, 140141162467327,
-STORE, 140141162467328, 140141164605439,
-STORE, 140141160808448, 140141162467327,
-SNULL, 140141164564479, 140141164605439,
-STORE, 140141162467328, 140141164564479,
-STORE, 140141164564480, 140141164605439,
-SNULL, 140141164564480, 140141164589055,
-STORE, 140141164589056, 140141164605439,
-STORE, 140141164564480, 140141164589055,
-ERASE, 140141164564480, 140141164589055,
-STORE, 140141164564480, 140141164589055,
-ERASE, 140141164589056, 140141164605439,
-STORE, 140141164589056, 140141164605439,
-SNULL, 140141164580863, 140141164589055,
-STORE, 140141164564480, 140141164580863,
-STORE, 140141164580864, 140141164589055,
-SNULL, 93915971768319, 93915971772415,
-STORE, 93915971760128, 93915971768319,
-STORE, 93915971768320, 93915971772415,
-SNULL, 140141166850047, 140141166854143,
-STORE, 140141166845952, 140141166850047,
-STORE, 140141166850048, 140141166854143,
-ERASE, 140141166817280, 140141166845951,
-STORE, 93916002775040, 93916002910207,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728988409856, 140737488351231,
-SNULL, 140728988418047, 140737488351231,
-STORE, 140728988409856, 140728988418047,
-STORE, 140728988278784, 140728988418047,
-STORE, 94021634813952, 94021637038079,
-SNULL, 94021634924543, 94021637038079,
-STORE, 94021634813952, 94021634924543,
-STORE, 94021634924544, 94021637038079,
-ERASE, 94021634924544, 94021637038079,
-STORE, 94021637017600, 94021637029887,
-STORE, 94021637029888, 94021637038079,
-STORE, 140638014038016, 140638016290815,
-SNULL, 140638014181375, 140638016290815,
-STORE, 140638014038016, 140638014181375,
-STORE, 140638014181376, 140638016290815,
-ERASE, 140638014181376, 140638016290815,
-STORE, 140638016278528, 140638016286719,
-STORE, 140638016286720, 140638016290815,
-STORE, 140728988536832, 140728988540927,
-STORE, 140728988524544, 140728988536831,
-STORE, 140638016249856, 140638016278527,
-STORE, 140638016241664, 140638016249855,
-STORE, 140638010241024, 140638014038015,
-SNULL, 140638010241024, 140638011899903,
-STORE, 140638011899904, 140638014038015,
-STORE, 140638010241024, 140638011899903,
-SNULL, 140638013997055, 140638014038015,
-STORE, 140638011899904, 140638013997055,
-STORE, 140638013997056, 140638014038015,
-SNULL, 140638013997056, 140638014021631,
-STORE, 140638014021632, 140638014038015,
-STORE, 140638013997056, 140638014021631,
-ERASE, 140638013997056, 140638014021631,
-STORE, 140638013997056, 140638014021631,
-ERASE, 140638014021632, 140638014038015,
-STORE, 140638014021632, 140638014038015,
-SNULL, 140638014013439, 140638014021631,
-STORE, 140638013997056, 140638014013439,
-STORE, 140638014013440, 140638014021631,
-SNULL, 94021637025791, 94021637029887,
-STORE, 94021637017600, 94021637025791,
-STORE, 94021637025792, 94021637029887,
-SNULL, 140638016282623, 140638016286719,
-STORE, 140638016278528, 140638016282623,
-STORE, 140638016282624, 140638016286719,
-ERASE, 140638016249856, 140638016278527,
-STORE, 94021643124736, 94021643259903,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731219275776, 140737488351231,
-SNULL, 140731219283967, 140737488351231,
-STORE, 140731219275776, 140731219283967,
-STORE, 140731219144704, 140731219283967,
-STORE, 93888803647488, 93888805871615,
-SNULL, 93888803758079, 93888805871615,
-STORE, 93888803647488, 93888803758079,
-STORE, 93888803758080, 93888805871615,
-ERASE, 93888803758080, 93888805871615,
-STORE, 93888805851136, 93888805863423,
-STORE, 93888805863424, 93888805871615,
-STORE, 139630576934912, 139630579187711,
-SNULL, 139630577078271, 139630579187711,
-STORE, 139630576934912, 139630577078271,
-STORE, 139630577078272, 139630579187711,
-ERASE, 139630577078272, 139630579187711,
-STORE, 139630579175424, 139630579183615,
-STORE, 139630579183616, 139630579187711,
-STORE, 140731219718144, 140731219722239,
-STORE, 140731219705856, 140731219718143,
-STORE, 139630579146752, 139630579175423,
-STORE, 139630579138560, 139630579146751,
-STORE, 139630573137920, 139630576934911,
-SNULL, 139630573137920, 139630574796799,
-STORE, 139630574796800, 139630576934911,
-STORE, 139630573137920, 139630574796799,
-SNULL, 139630576893951, 139630576934911,
-STORE, 139630574796800, 139630576893951,
-STORE, 139630576893952, 139630576934911,
-SNULL, 139630576893952, 139630576918527,
-STORE, 139630576918528, 139630576934911,
-STORE, 139630576893952, 139630576918527,
-ERASE, 139630576893952, 139630576918527,
-STORE, 139630576893952, 139630576918527,
-ERASE, 139630576918528, 139630576934911,
-STORE, 139630576918528, 139630576934911,
-SNULL, 139630576910335, 139630576918527,
-STORE, 139630576893952, 139630576910335,
-STORE, 139630576910336, 139630576918527,
-SNULL, 93888805859327, 93888805863423,
-STORE, 93888805851136, 93888805859327,
-STORE, 93888805859328, 93888805863423,
-SNULL, 139630579179519, 139630579183615,
-STORE, 139630579175424, 139630579179519,
-STORE, 139630579179520, 139630579183615,
-ERASE, 139630579146752, 139630579175423,
-STORE, 93888822235136, 93888822370303,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733391151104, 140737488351231,
-SNULL, 140733391159295, 140737488351231,
-STORE, 140733391151104, 140733391159295,
-STORE, 140733391020032, 140733391159295,
-STORE, 94393875324928, 94393877549055,
-SNULL, 94393875435519, 94393877549055,
-STORE, 94393875324928, 94393875435519,
-STORE, 94393875435520, 94393877549055,
-ERASE, 94393875435520, 94393877549055,
-STORE, 94393877528576, 94393877540863,
-STORE, 94393877540864, 94393877549055,
-STORE, 140292111740928, 140292113993727,
-SNULL, 140292111884287, 140292113993727,
-STORE, 140292111740928, 140292111884287,
-STORE, 140292111884288, 140292113993727,
-ERASE, 140292111884288, 140292113993727,
-STORE, 140292113981440, 140292113989631,
-STORE, 140292113989632, 140292113993727,
-STORE, 140733391532032, 140733391536127,
-STORE, 140733391519744, 140733391532031,
-STORE, 140292113952768, 140292113981439,
-STORE, 140292113944576, 140292113952767,
-STORE, 140292107943936, 140292111740927,
-SNULL, 140292107943936, 140292109602815,
-STORE, 140292109602816, 140292111740927,
-STORE, 140292107943936, 140292109602815,
-SNULL, 140292111699967, 140292111740927,
-STORE, 140292109602816, 140292111699967,
-STORE, 140292111699968, 140292111740927,
-SNULL, 140292111699968, 140292111724543,
-STORE, 140292111724544, 140292111740927,
-STORE, 140292111699968, 140292111724543,
-ERASE, 140292111699968, 140292111724543,
-STORE, 140292111699968, 140292111724543,
-ERASE, 140292111724544, 140292111740927,
-STORE, 140292111724544, 140292111740927,
-SNULL, 140292111716351, 140292111724543,
-STORE, 140292111699968, 140292111716351,
-STORE, 140292111716352, 140292111724543,
-SNULL, 94393877536767, 94393877540863,
-STORE, 94393877528576, 94393877536767,
-STORE, 94393877536768, 94393877540863,
-SNULL, 140292113985535, 140292113989631,
-STORE, 140292113981440, 140292113985535,
-STORE, 140292113985536, 140292113989631,
-ERASE, 140292113952768, 140292113981439,
-STORE, 94393909342208, 94393909477375,
-STORE, 94458367512576, 94458367725567,
-STORE, 94458369822720, 94458369826815,
-STORE, 94458369826816, 94458369835007,
-STORE, 94458369835008, 94458369847295,
-STORE, 94458393292800, 94458399666175,
-STORE, 140619773841408, 140619775500287,
-STORE, 140619775500288, 140619777597439,
-STORE, 140619777597440, 140619777613823,
-STORE, 140619777613824, 140619777622015,
-STORE, 140619777622016, 140619777638399,
-STORE, 140619777638400, 140619777650687,
-STORE, 140619777650688, 140619779743743,
-STORE, 140619779743744, 140619779747839,
-STORE, 140619779747840, 140619779751935,
-STORE, 140619779751936, 140619779895295,
-STORE, 140619780263936, 140619781947391,
-STORE, 140619781947392, 140619781963775,
-STORE, 140619781992448, 140619781996543,
-STORE, 140619781996544, 140619782000639,
-STORE, 140619782000640, 140619782004735,
-STORE, 140725811675136, 140725811814399,
-STORE, 140725812813824, 140725812826111,
-STORE, 140725812826112, 140725812830207,
-STORE, 94458367512576, 94458367725567,
-STORE, 94458369822720, 94458369826815,
-STORE, 94458369826816, 94458369835007,
-STORE, 94458369835008, 94458369847295,
-STORE, 94458393292800, 94458400366591,
-STORE, 140619773841408, 140619775500287,
-STORE, 140619775500288, 140619777597439,
-STORE, 140619777597440, 140619777613823,
-STORE, 140619777613824, 140619777622015,
-STORE, 140619777622016, 140619777638399,
-STORE, 140619777638400, 140619777650687,
-STORE, 140619777650688, 140619779743743,
-STORE, 140619779743744, 140619779747839,
-STORE, 140619779747840, 140619779751935,
-STORE, 140619779751936, 140619779895295,
-STORE, 140619780263936, 140619781947391,
-STORE, 140619781947392, 140619781963775,
-STORE, 140619781992448, 140619781996543,
-STORE, 140619781996544, 140619782000639,
-STORE, 140619782000640, 140619782004735,
-STORE, 140725811675136, 140725811814399,
-STORE, 140725812813824, 140725812826111,
-STORE, 140725812826112, 140725812830207,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728740679680, 140737488351231,
-SNULL, 140728740687871, 140737488351231,
-STORE, 140728740679680, 140728740687871,
-STORE, 140728740548608, 140728740687871,
-STORE, 94764075249664, 94764077473791,
-SNULL, 94764075360255, 94764077473791,
-STORE, 94764075249664, 94764075360255,
-STORE, 94764075360256, 94764077473791,
-ERASE, 94764075360256, 94764077473791,
-STORE, 94764077453312, 94764077465599,
-STORE, 94764077465600, 94764077473791,
-STORE, 139766406791168, 139766409043967,
-SNULL, 139766406934527, 139766409043967,
-STORE, 139766406791168, 139766406934527,
-STORE, 139766406934528, 139766409043967,
-ERASE, 139766406934528, 139766409043967,
-STORE, 139766409031680, 139766409039871,
-STORE, 139766409039872, 139766409043967,
-STORE, 140728740913152, 140728740917247,
-STORE, 140728740900864, 140728740913151,
-STORE, 139766409003008, 139766409031679,
-STORE, 139766408994816, 139766409003007,
-STORE, 139766402994176, 139766406791167,
-SNULL, 139766402994176, 139766404653055,
-STORE, 139766404653056, 139766406791167,
-STORE, 139766402994176, 139766404653055,
-SNULL, 139766406750207, 139766406791167,
-STORE, 139766404653056, 139766406750207,
-STORE, 139766406750208, 139766406791167,
-SNULL, 139766406750208, 139766406774783,
-STORE, 139766406774784, 139766406791167,
-STORE, 139766406750208, 139766406774783,
-ERASE, 139766406750208, 139766406774783,
-STORE, 139766406750208, 139766406774783,
-ERASE, 139766406774784, 139766406791167,
-STORE, 139766406774784, 139766406791167,
-SNULL, 139766406766591, 139766406774783,
-STORE, 139766406750208, 139766406766591,
-STORE, 139766406766592, 139766406774783,
-SNULL, 94764077461503, 94764077465599,
-STORE, 94764077453312, 94764077461503,
-STORE, 94764077461504, 94764077465599,
-SNULL, 139766409035775, 139766409039871,
-STORE, 139766409031680, 139766409035775,
-STORE, 139766409035776, 139766409039871,
-ERASE, 139766409003008, 139766409031679,
-STORE, 94764090458112, 94764090593279,
-STORE, 94758057480192, 94758057590783,
-STORE, 94758059683840, 94758059692031,
-STORE, 94758059692032, 94758059696127,
-STORE, 94758059696128, 94758059704319,
-STORE, 94758083215360, 94758083350527,
-STORE, 139951456772096, 139951458430975,
-STORE, 139951458430976, 139951460528127,
-STORE, 139951460528128, 139951460544511,
-STORE, 139951460544512, 139951460552703,
-STORE, 139951460552704, 139951460569087,
-STORE, 139951460569088, 139951460712447,
-STORE, 139951462772736, 139951462780927,
-STORE, 139951462809600, 139951462813695,
-STORE, 139951462813696, 139951462817791,
-STORE, 139951462817792, 139951462821887,
-STORE, 140734098313216, 140734098452479,
-STORE, 140734098911232, 140734098923519,
-STORE, 140734098923520, 140734098927615,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724904095744, 140737488351231,
-SNULL, 140724904103935, 140737488351231,
-STORE, 140724904095744, 140724904103935,
-STORE, 140724903964672, 140724904103935,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140408497864704, 140408500117503,
-SNULL, 140408498008063, 140408500117503,
-STORE, 140408497864704, 140408498008063,
-STORE, 140408498008064, 140408500117503,
-ERASE, 140408498008064, 140408500117503,
-STORE, 140408500105216, 140408500113407,
-STORE, 140408500113408, 140408500117503,
-STORE, 140724905369600, 140724905373695,
-STORE, 140724905357312, 140724905369599,
-STORE, 140408500076544, 140408500105215,
-STORE, 140408500068352, 140408500076543,
-STORE, 140408494702592, 140408497864703,
-SNULL, 140408494702592, 140408495763455,
-STORE, 140408495763456, 140408497864703,
-STORE, 140408494702592, 140408495763455,
-SNULL, 140408497856511, 140408497864703,
-STORE, 140408495763456, 140408497856511,
-STORE, 140408497856512, 140408497864703,
-ERASE, 140408497856512, 140408497864703,
-STORE, 140408497856512, 140408497864703,
-STORE, 140408490905600, 140408494702591,
-SNULL, 140408490905600, 140408492564479,
-STORE, 140408492564480, 140408494702591,
-STORE, 140408490905600, 140408492564479,
-SNULL, 140408494661631, 140408494702591,
-STORE, 140408492564480, 140408494661631,
-STORE, 140408494661632, 140408494702591,
-SNULL, 140408494661632, 140408494686207,
-STORE, 140408494686208, 140408494702591,
-STORE, 140408494661632, 140408494686207,
-ERASE, 140408494661632, 140408494686207,
-STORE, 140408494661632, 140408494686207,
-ERASE, 140408494686208, 140408494702591,
-STORE, 140408494686208, 140408494702591,
-STORE, 140408500056064, 140408500076543,
-SNULL, 140408494678015, 140408494686207,
-STORE, 140408494661632, 140408494678015,
-STORE, 140408494678016, 140408494686207,
-SNULL, 140408497860607, 140408497864703,
-STORE, 140408497856512, 140408497860607,
-STORE, 140408497860608, 140408497864703,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140408500109311, 140408500113407,
-STORE, 140408500105216, 140408500109311,
-STORE, 140408500109312, 140408500113407,
-ERASE, 140408500076544, 140408500105215,
-STORE, 25235456, 25370623,
-STORE, 25235456, 25518079,
-STORE, 140408498372608, 140408500056063,
-STORE, 94543937388544, 94543937499135,
-STORE, 94543939592192, 94543939600383,
-STORE, 94543939600384, 94543939604479,
-STORE, 94543939604480, 94543939612671,
-STORE, 94543941447680, 94543941582847,
-STORE, 140282621947904, 140282623606783,
-STORE, 140282623606784, 140282625703935,
-STORE, 140282625703936, 140282625720319,
-STORE, 140282625720320, 140282625728511,
-STORE, 140282625728512, 140282625744895,
-STORE, 140282625744896, 140282625888255,
-STORE, 140282627948544, 140282627956735,
-STORE, 140282627985408, 140282627989503,
-STORE, 140282627989504, 140282627993599,
-STORE, 140282627993600, 140282627997695,
-STORE, 140728295723008, 140728295862271,
-STORE, 140728296476672, 140728296488959,
-STORE, 140728296488960, 140728296493055,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431510691839,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431510691839,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140737488338944, 140737488351231,
-STORE, 140736944451584, 140737488351231,
-SNULL, 140736944463871, 140737488351231,
-STORE, 140736944451584, 140736944463871,
-STORE, 140736944320512, 140736944463871,
-STORE, 4194304, 26279935,
-STORE, 28372992, 28454911,
-STORE, 28454912, 29806591,
-STORE, 139693609893888, 139693612146687,
-SNULL, 139693610037247, 139693612146687,
-STORE, 139693609893888, 139693610037247,
-STORE, 139693610037248, 139693612146687,
-ERASE, 139693610037248, 139693612146687,
-STORE, 139693612134400, 139693612142591,
-STORE, 139693612142592, 139693612146687,
-STORE, 140736945152000, 140736945156095,
-STORE, 140736945139712, 140736945151999,
-STORE, 139693612105728, 139693612134399,
-STORE, 139693612097536, 139693612105727,
-STORE, 139693606060032, 139693609893887,
-SNULL, 139693606060032, 139693607768063,
-STORE, 139693607768064, 139693609893887,
-STORE, 139693606060032, 139693607768063,
-SNULL, 139693609861119, 139693609893887,
-STORE, 139693607768064, 139693609861119,
-STORE, 139693609861120, 139693609893887,
-ERASE, 139693609861120, 139693609893887,
-STORE, 139693609861120, 139693609893887,
-STORE, 139693603864576, 139693606060031,
-SNULL, 139693603864576, 139693603958783,
-STORE, 139693603958784, 139693606060031,
-STORE, 139693603864576, 139693603958783,
-SNULL, 139693606051839, 139693606060031,
-STORE, 139693603958784, 139693606051839,
-STORE, 139693606051840, 139693606060031,
-ERASE, 139693606051840, 139693606060031,
-STORE, 139693606051840, 139693606060031,
-STORE, 139693601345536, 139693603864575,
-SNULL, 139693601345536, 139693601759231,
-STORE, 139693601759232, 139693603864575,
-STORE, 139693601345536, 139693601759231,
-SNULL, 139693603852287, 139693603864575,
-STORE, 139693601759232, 139693603852287,
-STORE, 139693603852288, 139693603864575,
-ERASE, 139693603852288, 139693603864575,
-STORE, 139693603852288, 139693603864575,
-STORE, 139693598711808, 139693601345535,
-SNULL, 139693598711808, 139693599240191,
-STORE, 139693599240192, 139693601345535,
-STORE, 139693598711808, 139693599240191,
-SNULL, 139693601337343, 139693601345535,
-STORE, 139693599240192, 139693601337343,
-STORE, 139693601337344, 139693601345535,
-ERASE, 139693601337344, 139693601345535,
-STORE, 139693601337344, 139693601345535,
-STORE, 139693596598272, 139693598711807,
-SNULL, 139693596598272, 139693596610559,
-STORE, 139693596610560, 139693598711807,
-STORE, 139693596598272, 139693596610559,
-SNULL, 139693598703615, 139693598711807,
-STORE, 139693596610560, 139693598703615,
-STORE, 139693598703616, 139693598711807,
-ERASE, 139693598703616, 139693598711807,
-STORE, 139693598703616, 139693598711807,
-STORE, 139693594394624, 139693596598271,
-SNULL, 139693594394624, 139693594497023,
-STORE, 139693594497024, 139693596598271,
-STORE, 139693594394624, 139693594497023,
-SNULL, 139693596590079, 139693596598271,
-STORE, 139693594497024, 139693596590079,
-STORE, 139693596590080, 139693596598271,
-ERASE, 139693596590080, 139693596598271,
-STORE, 139693596590080, 139693596598271,
-STORE, 139693612089344, 139693612105727,
-STORE, 139693591232512, 139693594394623,
-SNULL, 139693591232512, 139693592293375,
-STORE, 139693592293376, 139693594394623,
-STORE, 139693591232512, 139693592293375,
-SNULL, 139693594386431, 139693594394623,
-STORE, 139693592293376, 139693594386431,
-STORE, 139693594386432, 139693594394623,
-ERASE, 139693594386432, 139693594394623,
-STORE, 139693594386432, 139693594394623,
-STORE, 139693587435520, 139693591232511,
-SNULL, 139693587435520, 139693589094399,
-STORE, 139693589094400, 139693591232511,
-STORE, 139693587435520, 139693589094399,
-SNULL, 139693591191551, 139693591232511,
-STORE, 139693589094400, 139693591191551,
-STORE, 139693591191552, 139693591232511,
-SNULL, 139693591191552, 139693591216127,
-STORE, 139693591216128, 139693591232511,
-STORE, 139693591191552, 139693591216127,
-ERASE, 139693591191552, 139693591216127,
-STORE, 139693591191552, 139693591216127,
-ERASE, 139693591216128, 139693591232511,
-STORE, 139693591216128, 139693591232511,
-STORE, 139693612077056, 139693612105727,
-SNULL, 139693591207935, 139693591216127,
-STORE, 139693591191552, 139693591207935,
-STORE, 139693591207936, 139693591216127,
-SNULL, 139693594390527, 139693594394623,
-STORE, 139693594386432, 139693594390527,
-STORE, 139693594390528, 139693594394623,
-SNULL, 139693596594175, 139693596598271,
-STORE, 139693596590080, 139693596594175,
-STORE, 139693596594176, 139693596598271,
-SNULL, 139693598707711, 139693598711807,
-STORE, 139693598703616, 139693598707711,
-STORE, 139693598707712, 139693598711807,
-SNULL, 139693601341439, 139693601345535,
-STORE, 139693601337344, 139693601341439,
-STORE, 139693601341440, 139693601345535,
-SNULL, 139693603860479, 139693603864575,
-STORE, 139693603852288, 139693603860479,
-STORE, 139693603860480, 139693603864575,
-SNULL, 139693606055935, 139693606060031,
-STORE, 139693606051840, 139693606055935,
-STORE, 139693606055936, 139693606060031,
-SNULL, 139693609865215, 139693609893887,
-STORE, 139693609861120, 139693609865215,
-STORE, 139693609865216, 139693609893887,
-SNULL, 28405759, 28454911,
-STORE, 28372992, 28405759,
-STORE, 28405760, 28454911,
-SNULL, 139693612138495, 139693612142591,
-STORE, 139693612134400, 139693612138495,
-STORE, 139693612138496, 139693612142591,
-ERASE, 139693612105728, 139693612134399,
-STORE, 39976960, 40112127,
-STORE, 139693610393600, 139693612077055,
-STORE, 139693612130304, 139693612134399,
-STORE, 139693610258432, 139693610393599,
-STORE, 39976960, 40255487,
-STORE, 139693585338368, 139693587435519,
-STORE, 139693612122112, 139693612134399,
-STORE, 139693612113920, 139693612134399,
-STORE, 139693612077056, 139693612113919,
-STORE, 139693610242048, 139693610393599,
-STORE, 39976960, 40390655,
-STORE, 39976960, 40546303,
-STORE, 139693610233856, 139693610393599,
-STORE, 139693610225664, 139693610393599,
-STORE, 39976960, 40714239,
-STORE, 139693610209280, 139693610393599,
-STORE, 39976960, 40861695,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431528759295,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140729993904128, 140737488351231,
-SNULL, 140729993912319, 140737488351231,
-STORE, 140729993904128, 140729993912319,
-STORE, 140729993773056, 140729993912319,
-STORE, 93926271991808, 93926274215935,
-SNULL, 93926272102399, 93926274215935,
-STORE, 93926271991808, 93926272102399,
-STORE, 93926272102400, 93926274215935,
-ERASE, 93926272102400, 93926274215935,
-STORE, 93926274195456, 93926274207743,
-STORE, 93926274207744, 93926274215935,
-STORE, 139962167296000, 139962169548799,
-SNULL, 139962167439359, 139962169548799,
-STORE, 139962167296000, 139962167439359,
-STORE, 139962167439360, 139962169548799,
-ERASE, 139962167439360, 139962169548799,
-STORE, 139962169536512, 139962169544703,
-STORE, 139962169544704, 139962169548799,
-STORE, 140729995096064, 140729995100159,
-STORE, 140729995083776, 140729995096063,
-STORE, 139962169507840, 139962169536511,
-STORE, 139962169499648, 139962169507839,
-STORE, 139962163499008, 139962167295999,
-SNULL, 139962163499008, 139962165157887,
-STORE, 139962165157888, 139962167295999,
-STORE, 139962163499008, 139962165157887,
-SNULL, 139962167255039, 139962167295999,
-STORE, 139962165157888, 139962167255039,
-STORE, 139962167255040, 139962167295999,
-SNULL, 139962167255040, 139962167279615,
-STORE, 139962167279616, 139962167295999,
-STORE, 139962167255040, 139962167279615,
-ERASE, 139962167255040, 139962167279615,
-STORE, 139962167255040, 139962167279615,
-ERASE, 139962167279616, 139962167295999,
-STORE, 139962167279616, 139962167295999,
-SNULL, 139962167271423, 139962167279615,
-STORE, 139962167255040, 139962167271423,
-STORE, 139962167271424, 139962167279615,
-SNULL, 93926274203647, 93926274207743,
-STORE, 93926274195456, 93926274203647,
-STORE, 93926274203648, 93926274207743,
-SNULL, 139962169540607, 139962169544703,
-STORE, 139962169536512, 139962169540607,
-STORE, 139962169540608, 139962169544703,
-ERASE, 139962169507840, 139962169536511,
-STORE, 93926291120128, 93926291255295,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724960579584, 140737488351231,
-SNULL, 140724960587775, 140737488351231,
-STORE, 140724960579584, 140724960587775,
-STORE, 140724960448512, 140724960587775,
-STORE, 94246489489408, 94246491713535,
-SNULL, 94246489599999, 94246491713535,
-STORE, 94246489489408, 94246489599999,
-STORE, 94246489600000, 94246491713535,
-ERASE, 94246489600000, 94246491713535,
-STORE, 94246491693056, 94246491705343,
-STORE, 94246491705344, 94246491713535,
-STORE, 140098174926848, 140098177179647,
-SNULL, 140098175070207, 140098177179647,
-STORE, 140098174926848, 140098175070207,
-STORE, 140098175070208, 140098177179647,
-ERASE, 140098175070208, 140098177179647,
-STORE, 140098177167360, 140098177175551,
-STORE, 140098177175552, 140098177179647,
-STORE, 140724961439744, 140724961443839,
-STORE, 140724961427456, 140724961439743,
-STORE, 140098177138688, 140098177167359,
-STORE, 140098177130496, 140098177138687,
-STORE, 140098171129856, 140098174926847,
-SNULL, 140098171129856, 140098172788735,
-STORE, 140098172788736, 140098174926847,
-STORE, 140098171129856, 140098172788735,
-SNULL, 140098174885887, 140098174926847,
-STORE, 140098172788736, 140098174885887,
-STORE, 140098174885888, 140098174926847,
-SNULL, 140098174885888, 140098174910463,
-STORE, 140098174910464, 140098174926847,
-STORE, 140098174885888, 140098174910463,
-ERASE, 140098174885888, 140098174910463,
-STORE, 140098174885888, 140098174910463,
-ERASE, 140098174910464, 140098174926847,
-STORE, 140098174910464, 140098174926847,
-SNULL, 140098174902271, 140098174910463,
-STORE, 140098174885888, 140098174902271,
-STORE, 140098174902272, 140098174910463,
-SNULL, 94246491701247, 94246491705343,
-STORE, 94246491693056, 94246491701247,
-STORE, 94246491701248, 94246491705343,
-SNULL, 140098177171455, 140098177175551,
-STORE, 140098177167360, 140098177171455,
-STORE, 140098177171456, 140098177175551,
-ERASE, 140098177138688, 140098177167359,
-STORE, 94246516998144, 94246517133311,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140730522918912, 140737488351231,
-SNULL, 140730522927103, 140737488351231,
-STORE, 140730522918912, 140730522927103,
-STORE, 140730522787840, 140730522927103,
-STORE, 94196043120640, 94196045344767,
-SNULL, 94196043231231, 94196045344767,
-STORE, 94196043120640, 94196043231231,
-STORE, 94196043231232, 94196045344767,
-ERASE, 94196043231232, 94196045344767,
-STORE, 94196045324288, 94196045336575,
-STORE, 94196045336576, 94196045344767,
-STORE, 139815918940160, 139815921192959,
-SNULL, 139815919083519, 139815921192959,
-STORE, 139815918940160, 139815919083519,
-STORE, 139815919083520, 139815921192959,
-ERASE, 139815919083520, 139815921192959,
-STORE, 139815921180672, 139815921188863,
-STORE, 139815921188864, 139815921192959,
-STORE, 140730523344896, 140730523348991,
-STORE, 140730523332608, 140730523344895,
-STORE, 139815921152000, 139815921180671,
-STORE, 139815921143808, 139815921151999,
-STORE, 139815915143168, 139815918940159,
-SNULL, 139815915143168, 139815916802047,
-STORE, 139815916802048, 139815918940159,
-STORE, 139815915143168, 139815916802047,
-SNULL, 139815918899199, 139815918940159,
-STORE, 139815916802048, 139815918899199,
-STORE, 139815918899200, 139815918940159,
-SNULL, 139815918899200, 139815918923775,
-STORE, 139815918923776, 139815918940159,
-STORE, 139815918899200, 139815918923775,
-ERASE, 139815918899200, 139815918923775,
-STORE, 139815918899200, 139815918923775,
-ERASE, 139815918923776, 139815918940159,
-STORE, 139815918923776, 139815918940159,
-SNULL, 139815918915583, 139815918923775,
-STORE, 139815918899200, 139815918915583,
-STORE, 139815918915584, 139815918923775,
-SNULL, 94196045332479, 94196045336575,
-STORE, 94196045324288, 94196045332479,
-STORE, 94196045332480, 94196045336575,
-SNULL, 139815921184767, 139815921188863,
-STORE, 139815921180672, 139815921184767,
-STORE, 139815921184768, 139815921188863,
-ERASE, 139815921152000, 139815921180671,
-STORE, 94196076183552, 94196076318719,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722460393472, 140737488351231,
-SNULL, 140722460401663, 140737488351231,
-STORE, 140722460393472, 140722460401663,
-STORE, 140722460262400, 140722460401663,
-STORE, 94569810399232, 94569812623359,
-SNULL, 94569810509823, 94569812623359,
-STORE, 94569810399232, 94569810509823,
-STORE, 94569810509824, 94569812623359,
-ERASE, 94569810509824, 94569812623359,
-STORE, 94569812602880, 94569812615167,
-STORE, 94569812615168, 94569812623359,
-STORE, 139681565450240, 139681567703039,
-SNULL, 139681565593599, 139681567703039,
-STORE, 139681565450240, 139681565593599,
-STORE, 139681565593600, 139681567703039,
-ERASE, 139681565593600, 139681567703039,
-STORE, 139681567690752, 139681567698943,
-STORE, 139681567698944, 139681567703039,
-STORE, 140722460569600, 140722460573695,
-STORE, 140722460557312, 140722460569599,
-STORE, 139681567662080, 139681567690751,
-STORE, 139681567653888, 139681567662079,
-STORE, 139681561653248, 139681565450239,
-SNULL, 139681561653248, 139681563312127,
-STORE, 139681563312128, 139681565450239,
-STORE, 139681561653248, 139681563312127,
-SNULL, 139681565409279, 139681565450239,
-STORE, 139681563312128, 139681565409279,
-STORE, 139681565409280, 139681565450239,
-SNULL, 139681565409280, 139681565433855,
-STORE, 139681565433856, 139681565450239,
-STORE, 139681565409280, 139681565433855,
-ERASE, 139681565409280, 139681565433855,
-STORE, 139681565409280, 139681565433855,
-ERASE, 139681565433856, 139681565450239,
-STORE, 139681565433856, 139681565450239,
-SNULL, 139681565425663, 139681565433855,
-STORE, 139681565409280, 139681565425663,
-STORE, 139681565425664, 139681565433855,
-SNULL, 94569812611071, 94569812615167,
-STORE, 94569812602880, 94569812611071,
-STORE, 94569812611072, 94569812615167,
-SNULL, 139681567694847, 139681567698943,
-STORE, 139681567690752, 139681567694847,
-STORE, 139681567694848, 139681567698943,
-ERASE, 139681567662080, 139681567690751,
-STORE, 94569818066944, 94569818202111,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431534280703,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725452365824, 140737488351231,
-SNULL, 140725452374015, 140737488351231,
-STORE, 140725452365824, 140725452374015,
-STORE, 140725452234752, 140725452374015,
-STORE, 94395067465728, 94395069689855,
-SNULL, 94395067576319, 94395069689855,
-STORE, 94395067465728, 94395067576319,
-STORE, 94395067576320, 94395069689855,
-ERASE, 94395067576320, 94395069689855,
-STORE, 94395069669376, 94395069681663,
-STORE, 94395069681664, 94395069689855,
-STORE, 140269941211136, 140269943463935,
-SNULL, 140269941354495, 140269943463935,
-STORE, 140269941211136, 140269941354495,
-STORE, 140269941354496, 140269943463935,
-ERASE, 140269941354496, 140269943463935,
-STORE, 140269943451648, 140269943459839,
-STORE, 140269943459840, 140269943463935,
-STORE, 140725452558336, 140725452562431,
-STORE, 140725452546048, 140725452558335,
-STORE, 140269943422976, 140269943451647,
-STORE, 140269943414784, 140269943422975,
-STORE, 140269937414144, 140269941211135,
-SNULL, 140269937414144, 140269939073023,
-STORE, 140269939073024, 140269941211135,
-STORE, 140269937414144, 140269939073023,
-SNULL, 140269941170175, 140269941211135,
-STORE, 140269939073024, 140269941170175,
-STORE, 140269941170176, 140269941211135,
-SNULL, 140269941170176, 140269941194751,
-STORE, 140269941194752, 140269941211135,
-STORE, 140269941170176, 140269941194751,
-ERASE, 140269941170176, 140269941194751,
-STORE, 140269941170176, 140269941194751,
-ERASE, 140269941194752, 140269941211135,
-STORE, 140269941194752, 140269941211135,
-SNULL, 140269941186559, 140269941194751,
-STORE, 140269941170176, 140269941186559,
-STORE, 140269941186560, 140269941194751,
-SNULL, 94395069677567, 94395069681663,
-STORE, 94395069669376, 94395069677567,
-STORE, 94395069677568, 94395069681663,
-SNULL, 140269943455743, 140269943459839,
-STORE, 140269943451648, 140269943455743,
-STORE, 140269943455744, 140269943459839,
-ERASE, 140269943422976, 140269943451647,
-STORE, 94395101691904, 94395101827071,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733860118528, 140737488351231,
-SNULL, 140733860126719, 140737488351231,
-STORE, 140733860118528, 140733860126719,
-STORE, 140733859987456, 140733860126719,
-STORE, 94484752990208, 94484755214335,
-SNULL, 94484753100799, 94484755214335,
-STORE, 94484752990208, 94484753100799,
-STORE, 94484753100800, 94484755214335,
-ERASE, 94484753100800, 94484755214335,
-STORE, 94484755193856, 94484755206143,
-STORE, 94484755206144, 94484755214335,
-STORE, 139958922309632, 139958924562431,
-SNULL, 139958922452991, 139958924562431,
-STORE, 139958922309632, 139958922452991,
-STORE, 139958922452992, 139958924562431,
-ERASE, 139958922452992, 139958924562431,
-STORE, 139958924550144, 139958924558335,
-STORE, 139958924558336, 139958924562431,
-STORE, 140733860253696, 140733860257791,
-STORE, 140733860241408, 140733860253695,
-STORE, 139958924521472, 139958924550143,
-STORE, 139958924513280, 139958924521471,
-STORE, 139958918512640, 139958922309631,
-SNULL, 139958918512640, 139958920171519,
-STORE, 139958920171520, 139958922309631,
-STORE, 139958918512640, 139958920171519,
-SNULL, 139958922268671, 139958922309631,
-STORE, 139958920171520, 139958922268671,
-STORE, 139958922268672, 139958922309631,
-SNULL, 139958922268672, 139958922293247,
-STORE, 139958922293248, 139958922309631,
-STORE, 139958922268672, 139958922293247,
-ERASE, 139958922268672, 139958922293247,
-STORE, 139958922268672, 139958922293247,
-ERASE, 139958922293248, 139958922309631,
-STORE, 139958922293248, 139958922309631,
-SNULL, 139958922285055, 139958922293247,
-STORE, 139958922268672, 139958922285055,
-STORE, 139958922285056, 139958922293247,
-SNULL, 94484755202047, 94484755206143,
-STORE, 94484755193856, 94484755202047,
-STORE, 94484755202048, 94484755206143,
-SNULL, 139958924554239, 139958924558335,
-STORE, 139958924550144, 139958924554239,
-STORE, 139958924554240, 139958924558335,
-ERASE, 139958924521472, 139958924550143,
-STORE, 94484777615360, 94484777750527,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731051036672, 140737488351231,
-SNULL, 140731051044863, 140737488351231,
-STORE, 140731051036672, 140731051044863,
-STORE, 140731050905600, 140731051044863,
-STORE, 93945822998528, 93945825222655,
-SNULL, 93945823109119, 93945825222655,
-STORE, 93945822998528, 93945823109119,
-STORE, 93945823109120, 93945825222655,
-ERASE, 93945823109120, 93945825222655,
-STORE, 93945825202176, 93945825214463,
-STORE, 93945825214464, 93945825222655,
-STORE, 140153503997952, 140153506250751,
-SNULL, 140153504141311, 140153506250751,
-STORE, 140153503997952, 140153504141311,
-STORE, 140153504141312, 140153506250751,
-ERASE, 140153504141312, 140153506250751,
-STORE, 140153506238464, 140153506246655,
-STORE, 140153506246656, 140153506250751,
-STORE, 140731051331584, 140731051335679,
-STORE, 140731051319296, 140731051331583,
-STORE, 140153506209792, 140153506238463,
-STORE, 140153506201600, 140153506209791,
-STORE, 140153500200960, 140153503997951,
-SNULL, 140153500200960, 140153501859839,
-STORE, 140153501859840, 140153503997951,
-STORE, 140153500200960, 140153501859839,
-SNULL, 140153503956991, 140153503997951,
-STORE, 140153501859840, 140153503956991,
-STORE, 140153503956992, 140153503997951,
-SNULL, 140153503956992, 140153503981567,
-STORE, 140153503981568, 140153503997951,
-STORE, 140153503956992, 140153503981567,
-ERASE, 140153503956992, 140153503981567,
-STORE, 140153503956992, 140153503981567,
-ERASE, 140153503981568, 140153503997951,
-STORE, 140153503981568, 140153503997951,
-SNULL, 140153503973375, 140153503981567,
-STORE, 140153503956992, 140153503973375,
-STORE, 140153503973376, 140153503981567,
-SNULL, 93945825210367, 93945825214463,
-STORE, 93945825202176, 93945825210367,
-STORE, 93945825210368, 93945825214463,
-SNULL, 140153506242559, 140153506246655,
-STORE, 140153506238464, 140153506242559,
-STORE, 140153506242560, 140153506246655,
-ERASE, 140153506209792, 140153506238463,
-STORE, 93945854537728, 93945854672895,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431537885183,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140736025325568, 140737488351231,
-SNULL, 140736025333759, 140737488351231,
-STORE, 140736025325568, 140736025333759,
-STORE, 140736025194496, 140736025333759,
-STORE, 94809095172096, 94809097396223,
-SNULL, 94809095282687, 94809097396223,
-STORE, 94809095172096, 94809095282687,
-STORE, 94809095282688, 94809097396223,
-ERASE, 94809095282688, 94809097396223,
-STORE, 94809097375744, 94809097388031,
-STORE, 94809097388032, 94809097396223,
-STORE, 140194992517120, 140194994769919,
-SNULL, 140194992660479, 140194994769919,
-STORE, 140194992517120, 140194992660479,
-STORE, 140194992660480, 140194994769919,
-ERASE, 140194992660480, 140194994769919,
-STORE, 140194994757632, 140194994765823,
-STORE, 140194994765824, 140194994769919,
-STORE, 140736026173440, 140736026177535,
-STORE, 140736026161152, 140736026173439,
-STORE, 140194994728960, 140194994757631,
-STORE, 140194994720768, 140194994728959,
-STORE, 140194988720128, 140194992517119,
-SNULL, 140194988720128, 140194990379007,
-STORE, 140194990379008, 140194992517119,
-STORE, 140194988720128, 140194990379007,
-SNULL, 140194992476159, 140194992517119,
-STORE, 140194990379008, 140194992476159,
-STORE, 140194992476160, 140194992517119,
-SNULL, 140194992476160, 140194992500735,
-STORE, 140194992500736, 140194992517119,
-STORE, 140194992476160, 140194992500735,
-ERASE, 140194992476160, 140194992500735,
-STORE, 140194992476160, 140194992500735,
-ERASE, 140194992500736, 140194992517119,
-STORE, 140194992500736, 140194992517119,
-SNULL, 140194992492543, 140194992500735,
-STORE, 140194992476160, 140194992492543,
-STORE, 140194992492544, 140194992500735,
-SNULL, 94809097383935, 94809097388031,
-STORE, 94809097375744, 94809097383935,
-STORE, 94809097383936, 94809097388031,
-SNULL, 140194994761727, 140194994765823,
-STORE, 140194994757632, 140194994761727,
-STORE, 140194994761728, 140194994765823,
-ERASE, 140194994728960, 140194994757631,
-STORE, 94809124286464, 94809124421631,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140726342660096, 140737488351231,
-SNULL, 140726342668287, 140737488351231,
-STORE, 140726342660096, 140726342668287,
-STORE, 140726342529024, 140726342668287,
-STORE, 94140331462656, 94140333686783,
-SNULL, 94140331573247, 94140333686783,
-STORE, 94140331462656, 94140331573247,
-STORE, 94140331573248, 94140333686783,
-ERASE, 94140331573248, 94140333686783,
-STORE, 94140333666304, 94140333678591,
-STORE, 94140333678592, 94140333686783,
-STORE, 140714077208576, 140714079461375,
-SNULL, 140714077351935, 140714079461375,
-STORE, 140714077208576, 140714077351935,
-STORE, 140714077351936, 140714079461375,
-ERASE, 140714077351936, 140714079461375,
-STORE, 140714079449088, 140714079457279,
-STORE, 140714079457280, 140714079461375,
-STORE, 140726343933952, 140726343938047,
-STORE, 140726343921664, 140726343933951,
-STORE, 140714079420416, 140714079449087,
-STORE, 140714079412224, 140714079420415,
-STORE, 140714073411584, 140714077208575,
-SNULL, 140714073411584, 140714075070463,
-STORE, 140714075070464, 140714077208575,
-STORE, 140714073411584, 140714075070463,
-SNULL, 140714077167615, 140714077208575,
-STORE, 140714075070464, 140714077167615,
-STORE, 140714077167616, 140714077208575,
-SNULL, 140714077167616, 140714077192191,
-STORE, 140714077192192, 140714077208575,
-STORE, 140714077167616, 140714077192191,
-ERASE, 140714077167616, 140714077192191,
-STORE, 140714077167616, 140714077192191,
-ERASE, 140714077192192, 140714077208575,
-STORE, 140714077192192, 140714077208575,
-SNULL, 140714077183999, 140714077192191,
-STORE, 140714077167616, 140714077183999,
-STORE, 140714077184000, 140714077192191,
-SNULL, 94140333674495, 94140333678591,
-STORE, 94140333666304, 94140333674495,
-STORE, 94140333674496, 94140333678591,
-SNULL, 140714079453183, 140714079457279,
-STORE, 140714079449088, 140714079453183,
-STORE, 140714079453184, 140714079457279,
-ERASE, 140714079420416, 140714079449087,
-STORE, 94140341432320, 94140341567487,
-STORE, 94431504838656, 94431505051647,
-STORE, 94431507148800, 94431507152895,
-STORE, 94431507152896, 94431507161087,
-STORE, 94431507161088, 94431507173375,
-STORE, 94431510286336, 94431539601407,
-STORE, 139818797948928, 139818799607807,
-STORE, 139818799607808, 139818801704959,
-STORE, 139818801704960, 139818801721343,
-STORE, 139818801721344, 139818801729535,
-STORE, 139818801729536, 139818801745919,
-STORE, 139818801745920, 139818801758207,
-STORE, 139818801758208, 139818803851263,
-STORE, 139818803851264, 139818803855359,
-STORE, 139818803855360, 139818803859455,
-STORE, 139818803859456, 139818804002815,
-STORE, 139818804371456, 139818806054911,
-STORE, 139818806054912, 139818806071295,
-STORE, 139818806099968, 139818806104063,
-STORE, 139818806104064, 139818806108159,
-STORE, 139818806108160, 139818806112255,
-STORE, 140731430457344, 140731430596607,
-STORE, 140731431227392, 140731431239679,
-STORE, 140731431239680, 140731431243775,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725843607552, 140737488351231,
-SNULL, 140725843615743, 140737488351231,
-STORE, 140725843607552, 140725843615743,
-STORE, 140725843476480, 140725843615743,
-STORE, 94889043505152, 94889045839871,
-SNULL, 94889043718143, 94889045839871,
-STORE, 94889043505152, 94889043718143,
-STORE, 94889043718144, 94889045839871,
-ERASE, 94889043718144, 94889045839871,
-STORE, 94889045815296, 94889045827583,
-STORE, 94889045827584, 94889045839871,
-STORE, 140250965946368, 140250968199167,
-SNULL, 140250966089727, 140250968199167,
-STORE, 140250965946368, 140250966089727,
-STORE, 140250966089728, 140250968199167,
-ERASE, 140250966089728, 140250968199167,
-STORE, 140250968186880, 140250968195071,
-STORE, 140250968195072, 140250968199167,
-STORE, 140725844500480, 140725844504575,
-STORE, 140725844488192, 140725844500479,
-STORE, 140250968158208, 140250968186879,
-STORE, 140250968150016, 140250968158207,
-STORE, 140250963832832, 140250965946367,
-SNULL, 140250963832832, 140250963845119,
-STORE, 140250963845120, 140250965946367,
-STORE, 140250963832832, 140250963845119,
-SNULL, 140250965938175, 140250965946367,
-STORE, 140250963845120, 140250965938175,
-STORE, 140250965938176, 140250965946367,
-ERASE, 140250965938176, 140250965946367,
-STORE, 140250965938176, 140250965946367,
-STORE, 140250960035840, 140250963832831,
-SNULL, 140250960035840, 140250961694719,
-STORE, 140250961694720, 140250963832831,
-STORE, 140250960035840, 140250961694719,
-SNULL, 140250963791871, 140250963832831,
-STORE, 140250961694720, 140250963791871,
-STORE, 140250963791872, 140250963832831,
-SNULL, 140250963791872, 140250963816447,
-STORE, 140250963816448, 140250963832831,
-STORE, 140250963791872, 140250963816447,
-ERASE, 140250963791872, 140250963816447,
-STORE, 140250963791872, 140250963816447,
-ERASE, 140250963816448, 140250963832831,
-STORE, 140250963816448, 140250963832831,
-STORE, 140250968141824, 140250968158207,
-SNULL, 140250963808255, 140250963816447,
-STORE, 140250963791872, 140250963808255,
-STORE, 140250963808256, 140250963816447,
-SNULL, 140250965942271, 140250965946367,
-STORE, 140250965938176, 140250965942271,
-STORE, 140250965942272, 140250965946367,
-SNULL, 94889045819391, 94889045827583,
-STORE, 94889045815296, 94889045819391,
-STORE, 94889045819392, 94889045827583,
-SNULL, 140250968190975, 140250968195071,
-STORE, 140250968186880, 140250968190975,
-STORE, 140250968190976, 140250968195071,
-ERASE, 140250968158208, 140250968186879,
-STORE, 94889052213248, 94889052348415,
-STORE, 140250966458368, 140250968141823,
-STORE, 94889052213248, 94889052483583,
-STORE, 94889052213248, 94889052618751,
-STORE, 94170851819520, 94170852032511,
-STORE, 94170854129664, 94170854133759,
-STORE, 94170854133760, 94170854141951,
-STORE, 94170854141952, 94170854154239,
-STORE, 94170866515968, 94170867740671,
-STORE, 140062030422016, 140062032080895,
-STORE, 140062032080896, 140062034178047,
-STORE, 140062034178048, 140062034194431,
-STORE, 140062034194432, 140062034202623,
-STORE, 140062034202624, 140062034219007,
-STORE, 140062034219008, 140062034231295,
-STORE, 140062034231296, 140062036324351,
-STORE, 140062036324352, 140062036328447,
-STORE, 140062036328448, 140062036332543,
-STORE, 140062036332544, 140062036475903,
-STORE, 140062036844544, 140062038527999,
-STORE, 140062038528000, 140062038544383,
-STORE, 140062038573056, 140062038577151,
-STORE, 140062038577152, 140062038581247,
-STORE, 140062038581248, 140062038585343,
-STORE, 140736210550784, 140736210690047,
-STORE, 140736210759680, 140736210771967,
-STORE, 140736210771968, 140736210776063,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724272365568, 140737488351231,
-SNULL, 140724272373759, 140737488351231,
-STORE, 140724272365568, 140724272373759,
-STORE, 140724272234496, 140724272373759,
-STORE, 94607711965184, 94607714189311,
-SNULL, 94607712075775, 94607714189311,
-STORE, 94607711965184, 94607712075775,
-STORE, 94607712075776, 94607714189311,
-ERASE, 94607712075776, 94607714189311,
-STORE, 94607714168832, 94607714181119,
-STORE, 94607714181120, 94607714189311,
-STORE, 140054949253120, 140054951505919,
-SNULL, 140054949396479, 140054951505919,
-STORE, 140054949253120, 140054949396479,
-STORE, 140054949396480, 140054951505919,
-ERASE, 140054949396480, 140054951505919,
-STORE, 140054951493632, 140054951501823,
-STORE, 140054951501824, 140054951505919,
-STORE, 140724272992256, 140724272996351,
-STORE, 140724272979968, 140724272992255,
-STORE, 140054951464960, 140054951493631,
-STORE, 140054951456768, 140054951464959,
-STORE, 140054945456128, 140054949253119,
-SNULL, 140054945456128, 140054947115007,
-STORE, 140054947115008, 140054949253119,
-STORE, 140054945456128, 140054947115007,
-SNULL, 140054949212159, 140054949253119,
-STORE, 140054947115008, 140054949212159,
-STORE, 140054949212160, 140054949253119,
-SNULL, 140054949212160, 140054949236735,
-STORE, 140054949236736, 140054949253119,
-STORE, 140054949212160, 140054949236735,
-ERASE, 140054949212160, 140054949236735,
-STORE, 140054949212160, 140054949236735,
-ERASE, 140054949236736, 140054949253119,
-STORE, 140054949236736, 140054949253119,
-SNULL, 140054949228543, 140054949236735,
-STORE, 140054949212160, 140054949228543,
-STORE, 140054949228544, 140054949236735,
-SNULL, 94607714177023, 94607714181119,
-STORE, 94607714168832, 94607714177023,
-STORE, 94607714177024, 94607714181119,
-SNULL, 140054951497727, 140054951501823,
-STORE, 140054951493632, 140054951497727,
-STORE, 140054951497728, 140054951501823,
-ERASE, 140054951464960, 140054951493631,
-STORE, 94607733374976, 94607733510143,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733586923520, 140737488351231,
-SNULL, 140733586931711, 140737488351231,
-STORE, 140733586923520, 140733586931711,
-STORE, 140733586792448, 140733586931711,
-STORE, 93901634904064, 93901637128191,
-SNULL, 93901635014655, 93901637128191,
-STORE, 93901634904064, 93901635014655,
-STORE, 93901635014656, 93901637128191,
-ERASE, 93901635014656, 93901637128191,
-STORE, 93901637107712, 93901637119999,
-STORE, 93901637120000, 93901637128191,
-STORE, 140086104784896, 140086107037695,
-SNULL, 140086104928255, 140086107037695,
-STORE, 140086104784896, 140086104928255,
-STORE, 140086104928256, 140086107037695,
-ERASE, 140086104928256, 140086107037695,
-STORE, 140086107025408, 140086107033599,
-STORE, 140086107033600, 140086107037695,
-STORE, 140733587263488, 140733587267583,
-STORE, 140733587251200, 140733587263487,
-STORE, 140086106996736, 140086107025407,
-STORE, 140086106988544, 140086106996735,
-STORE, 140086100987904, 140086104784895,
-SNULL, 140086100987904, 140086102646783,
-STORE, 140086102646784, 140086104784895,
-STORE, 140086100987904, 140086102646783,
-SNULL, 140086104743935, 140086104784895,
-STORE, 140086102646784, 140086104743935,
-STORE, 140086104743936, 140086104784895,
-SNULL, 140086104743936, 140086104768511,
-STORE, 140086104768512, 140086104784895,
-STORE, 140086104743936, 140086104768511,
-ERASE, 140086104743936, 140086104768511,
-STORE, 140086104743936, 140086104768511,
-ERASE, 140086104768512, 140086104784895,
-STORE, 140086104768512, 140086104784895,
-SNULL, 140086104760319, 140086104768511,
-STORE, 140086104743936, 140086104760319,
-STORE, 140086104760320, 140086104768511,
-SNULL, 93901637115903, 93901637119999,
-STORE, 93901637107712, 93901637115903,
-STORE, 93901637115904, 93901637119999,
-SNULL, 140086107029503, 140086107033599,
-STORE, 140086107025408, 140086107029503,
-STORE, 140086107029504, 140086107033599,
-ERASE, 140086106996736, 140086107025407,
-STORE, 93901662715904, 93901662851071,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723365613568, 140737488351231,
-SNULL, 140723365621759, 140737488351231,
-STORE, 140723365613568, 140723365621759,
-STORE, 140723365482496, 140723365621759,
-STORE, 94759193546752, 94759195770879,
-SNULL, 94759193657343, 94759195770879,
-STORE, 94759193546752, 94759193657343,
-STORE, 94759193657344, 94759195770879,
-ERASE, 94759193657344, 94759195770879,
-STORE, 94759195750400, 94759195762687,
-STORE, 94759195762688, 94759195770879,
-STORE, 140607636246528, 140607638499327,
-SNULL, 140607636389887, 140607638499327,
-STORE, 140607636246528, 140607636389887,
-STORE, 140607636389888, 140607638499327,
-ERASE, 140607636389888, 140607638499327,
-STORE, 140607638487040, 140607638495231,
-STORE, 140607638495232, 140607638499327,
-STORE, 140723365900288, 140723365904383,
-STORE, 140723365888000, 140723365900287,
-STORE, 140607638458368, 140607638487039,
-STORE, 140607638450176, 140607638458367,
-STORE, 140607632449536, 140607636246527,
-SNULL, 140607632449536, 140607634108415,
-STORE, 140607634108416, 140607636246527,
-STORE, 140607632449536, 140607634108415,
-SNULL, 140607636205567, 140607636246527,
-STORE, 140607634108416, 140607636205567,
-STORE, 140607636205568, 140607636246527,
-SNULL, 140607636205568, 140607636230143,
-STORE, 140607636230144, 140607636246527,
-STORE, 140607636205568, 140607636230143,
-ERASE, 140607636205568, 140607636230143,
-STORE, 140607636205568, 140607636230143,
-ERASE, 140607636230144, 140607636246527,
-STORE, 140607636230144, 140607636246527,
-SNULL, 140607636221951, 140607636230143,
-STORE, 140607636205568, 140607636221951,
-STORE, 140607636221952, 140607636230143,
-SNULL, 94759195758591, 94759195762687,
-STORE, 94759195750400, 94759195758591,
-STORE, 94759195758592, 94759195762687,
-SNULL, 140607638491135, 140607638495231,
-STORE, 140607638487040, 140607638491135,
-STORE, 140607638491136, 140607638495231,
-ERASE, 140607638458368, 140607638487039,
-STORE, 94759204995072, 94759205130239,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732503789568, 140737488351231,
-SNULL, 140732503797759, 140737488351231,
-STORE, 140732503789568, 140732503797759,
-STORE, 140732503658496, 140732503797759,
-STORE, 94077792956416, 94077795180543,
-SNULL, 94077793067007, 94077795180543,
-STORE, 94077792956416, 94077793067007,
-STORE, 94077793067008, 94077795180543,
-ERASE, 94077793067008, 94077795180543,
-STORE, 94077795160064, 94077795172351,
-STORE, 94077795172352, 94077795180543,
-STORE, 140359874252800, 140359876505599,
-SNULL, 140359874396159, 140359876505599,
-STORE, 140359874252800, 140359874396159,
-STORE, 140359874396160, 140359876505599,
-ERASE, 140359874396160, 140359876505599,
-STORE, 140359876493312, 140359876501503,
-STORE, 140359876501504, 140359876505599,
-STORE, 140732504465408, 140732504469503,
-STORE, 140732504453120, 140732504465407,
-STORE, 140359876464640, 140359876493311,
-STORE, 140359876456448, 140359876464639,
-STORE, 140359870455808, 140359874252799,
-SNULL, 140359870455808, 140359872114687,
-STORE, 140359872114688, 140359874252799,
-STORE, 140359870455808, 140359872114687,
-SNULL, 140359874211839, 140359874252799,
-STORE, 140359872114688, 140359874211839,
-STORE, 140359874211840, 140359874252799,
-SNULL, 140359874211840, 140359874236415,
-STORE, 140359874236416, 140359874252799,
-STORE, 140359874211840, 140359874236415,
-ERASE, 140359874211840, 140359874236415,
-STORE, 140359874211840, 140359874236415,
-ERASE, 140359874236416, 140359874252799,
-STORE, 140359874236416, 140359874252799,
-SNULL, 140359874228223, 140359874236415,
-STORE, 140359874211840, 140359874228223,
-STORE, 140359874228224, 140359874236415,
-SNULL, 94077795168255, 94077795172351,
-STORE, 94077795160064, 94077795168255,
-STORE, 94077795168256, 94077795172351,
-SNULL, 140359876497407, 140359876501503,
-STORE, 140359876493312, 140359876497407,
-STORE, 140359876497408, 140359876501503,
-ERASE, 140359876464640, 140359876493311,
-STORE, 94077808717824, 94077808852991,
-STORE, 94549486252032, 94549486465023,
-STORE, 94549488562176, 94549488566271,
-STORE, 94549488566272, 94549488574463,
-STORE, 94549488574464, 94549488586751,
-STORE, 94549503492096, 94549506121727,
-STORE, 140085800894464, 140085802553343,
-STORE, 140085802553344, 140085804650495,
-STORE, 140085804650496, 140085804666879,
-STORE, 140085804666880, 140085804675071,
-STORE, 140085804675072, 140085804691455,
-STORE, 140085804691456, 140085804703743,
-STORE, 140085804703744, 140085806796799,
-STORE, 140085806796800, 140085806800895,
-STORE, 140085806800896, 140085806804991,
-STORE, 140085806804992, 140085806948351,
-STORE, 140085807316992, 140085809000447,
-STORE, 140085809000448, 140085809016831,
-STORE, 140085809045504, 140085809049599,
-STORE, 140085809049600, 140085809053695,
-STORE, 140085809053696, 140085809057791,
-STORE, 140731810545664, 140731810684927,
-STORE, 140731810967552, 140731810979839,
-STORE, 140731810979840, 140731810983935,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724752330752, 140737488351231,
-SNULL, 140724752338943, 140737488351231,
-STORE, 140724752330752, 140724752338943,
-STORE, 140724752199680, 140724752338943,
-STORE, 94656357539840, 94656359874559,
-SNULL, 94656357752831, 94656359874559,
-STORE, 94656357539840, 94656357752831,
-STORE, 94656357752832, 94656359874559,
-ERASE, 94656357752832, 94656359874559,
-STORE, 94656359849984, 94656359862271,
-STORE, 94656359862272, 94656359874559,
-STORE, 139632585203712, 139632587456511,
-SNULL, 139632585347071, 139632587456511,
-STORE, 139632585203712, 139632585347071,
-STORE, 139632585347072, 139632587456511,
-ERASE, 139632585347072, 139632587456511,
-STORE, 139632587444224, 139632587452415,
-STORE, 139632587452416, 139632587456511,
-STORE, 139632587440128, 139632587444223,
-STORE, 139632587427840, 139632587440127,
-STORE, 139632587399168, 139632587427839,
-STORE, 139632587390976, 139632587399167,
-STORE, 139632583090176, 139632585203711,
-SNULL, 139632583090176, 139632583102463,
-STORE, 139632583102464, 139632585203711,
-STORE, 139632583090176, 139632583102463,
-SNULL, 139632585195519, 139632585203711,
-STORE, 139632583102464, 139632585195519,
-STORE, 139632585195520, 139632585203711,
-ERASE, 139632585195520, 139632585203711,
-STORE, 139632585195520, 139632585203711,
-STORE, 139632579293184, 139632583090175,
-SNULL, 139632579293184, 139632580952063,
-STORE, 139632580952064, 139632583090175,
-STORE, 139632579293184, 139632580952063,
-SNULL, 139632583049215, 139632583090175,
-STORE, 139632580952064, 139632583049215,
-STORE, 139632583049216, 139632583090175,
-SNULL, 139632583049216, 139632583073791,
-STORE, 139632583073792, 139632583090175,
-STORE, 139632583049216, 139632583073791,
-ERASE, 139632583049216, 139632583073791,
-STORE, 139632583049216, 139632583073791,
-ERASE, 139632583073792, 139632583090175,
-STORE, 139632583073792, 139632583090175,
-STORE, 139632587382784, 139632587399167,
-SNULL, 139632583065599, 139632583073791,
-STORE, 139632583049216, 139632583065599,
-STORE, 139632583065600, 139632583073791,
-SNULL, 139632585199615, 139632585203711,
-STORE, 139632585195520, 139632585199615,
-STORE, 139632585199616, 139632585203711,
-SNULL, 94656359854079, 94656359862271,
-STORE, 94656359849984, 94656359854079,
-STORE, 94656359854080, 94656359862271,
-SNULL, 139632587448319, 139632587452415,
-STORE, 139632587444224, 139632587448319,
-STORE, 139632587448320, 139632587452415,
-ERASE, 139632587399168, 139632587427839,
-STORE, 94656378912768, 94656379047935,
-STORE, 139632585699328, 139632587382783,
-STORE, 94656378912768, 94656379183103,
-STORE, 94656378912768, 94656379318271,
-STORE, 94656378912768, 94656379494399,
-SNULL, 94656379469823, 94656379494399,
-STORE, 94656378912768, 94656379469823,
-STORE, 94656379469824, 94656379494399,
-ERASE, 94656379469824, 94656379494399,
-STORE, 94656378912768, 94656379621375,
-STORE, 94656378912768, 94656379756543,
-STORE, 94656378912768, 94656379912191,
-STORE, 94656378912768, 94656380055551,
-STORE, 94656378912768, 94656380190719,
-STORE, 94656378912768, 94656380338175,
-SNULL, 94656380313599, 94656380338175,
-STORE, 94656378912768, 94656380313599,
-STORE, 94656380313600, 94656380338175,
-ERASE, 94656380313600, 94656380338175,
-STORE, 94656378912768, 94656380448767,
-SNULL, 94656380432383, 94656380448767,
-STORE, 94656378912768, 94656380432383,
-STORE, 94656380432384, 94656380448767,
-ERASE, 94656380432384, 94656380448767,
-STORE, 94656378912768, 94656380567551,
-STORE, 94656378912768, 94656380719103,
-STORE, 94656378912768, 94656380858367,
-STORE, 94656378912768, 94656380997631,
-STORE, 94656378912768, 94656381132799,
-SNULL, 94656381124607, 94656381132799,
-STORE, 94656378912768, 94656381124607,
-STORE, 94656381124608, 94656381132799,
-ERASE, 94656381124608, 94656381132799,
-STORE, 94656378912768, 94656381276159,
-STORE, 94656378912768, 94656381427711,
-STORE, 94604087611392, 94604087824383,
-STORE, 94604089921536, 94604089925631,
-STORE, 94604089925632, 94604089933823,
-STORE, 94604089933824, 94604089946111,
-STORE, 94604105125888, 94604106424319,
-STORE, 140454937694208, 140454939353087,
-STORE, 140454939353088, 140454941450239,
-STORE, 140454941450240, 140454941466623,
-STORE, 140454941466624, 140454941474815,
-STORE, 140454941474816, 140454941491199,
-STORE, 140454941491200, 140454941503487,
-STORE, 140454941503488, 140454943596543,
-STORE, 140454943596544, 140454943600639,
-STORE, 140454943600640, 140454943604735,
-STORE, 140454943604736, 140454943748095,
-STORE, 140454944116736, 140454945800191,
-STORE, 140454945800192, 140454945816575,
-STORE, 140454945845248, 140454945849343,
-STORE, 140454945849344, 140454945853439,
-STORE, 140454945853440, 140454945857535,
-STORE, 140728438214656, 140728438353919,
-STORE, 140728439095296, 140728439107583,
-STORE, 140728439107584, 140728439111679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140727821099008, 140737488351231,
-SNULL, 140727821107199, 140737488351231,
-STORE, 140727821099008, 140727821107199,
-STORE, 140727820967936, 140727821107199,
-STORE, 94088457240576, 94088459575295,
-SNULL, 94088457453567, 94088459575295,
-STORE, 94088457240576, 94088457453567,
-STORE, 94088457453568, 94088459575295,
-ERASE, 94088457453568, 94088459575295,
-STORE, 94088459550720, 94088459563007,
-STORE, 94088459563008, 94088459575295,
-STORE, 140234378989568, 140234381242367,
-SNULL, 140234379132927, 140234381242367,
-STORE, 140234378989568, 140234379132927,
-STORE, 140234379132928, 140234381242367,
-ERASE, 140234379132928, 140234381242367,
-STORE, 140234381230080, 140234381238271,
-STORE, 140234381238272, 140234381242367,
-STORE, 140727822077952, 140727822082047,
-STORE, 140727822065664, 140727822077951,
-STORE, 140234381201408, 140234381230079,
-STORE, 140234381193216, 140234381201407,
-STORE, 140234376876032, 140234378989567,
-SNULL, 140234376876032, 140234376888319,
-STORE, 140234376888320, 140234378989567,
-STORE, 140234376876032, 140234376888319,
-SNULL, 140234378981375, 140234378989567,
-STORE, 140234376888320, 140234378981375,
-STORE, 140234378981376, 140234378989567,
-ERASE, 140234378981376, 140234378989567,
-STORE, 140234378981376, 140234378989567,
-STORE, 140234373079040, 140234376876031,
-SNULL, 140234373079040, 140234374737919,
-STORE, 140234374737920, 140234376876031,
-STORE, 140234373079040, 140234374737919,
-SNULL, 140234376835071, 140234376876031,
-STORE, 140234374737920, 140234376835071,
-STORE, 140234376835072, 140234376876031,
-SNULL, 140234376835072, 140234376859647,
-STORE, 140234376859648, 140234376876031,
-STORE, 140234376835072, 140234376859647,
-ERASE, 140234376835072, 140234376859647,
-STORE, 140234376835072, 140234376859647,
-ERASE, 140234376859648, 140234376876031,
-STORE, 140234376859648, 140234376876031,
-STORE, 140234381185024, 140234381201407,
-SNULL, 140234376851455, 140234376859647,
-STORE, 140234376835072, 140234376851455,
-STORE, 140234376851456, 140234376859647,
-SNULL, 140234378985471, 140234378989567,
-STORE, 140234378981376, 140234378985471,
-STORE, 140234378985472, 140234378989567,
-SNULL, 94088459554815, 94088459563007,
-STORE, 94088459550720, 94088459554815,
-STORE, 94088459554816, 94088459563007,
-SNULL, 140234381234175, 140234381238271,
-STORE, 140234381230080, 140234381234175,
-STORE, 140234381234176, 140234381238271,
-ERASE, 140234381201408, 140234381230079,
-STORE, 94088468852736, 94088468987903,
-STORE, 140234379501568, 140234381185023,
-STORE, 94088468852736, 94088469123071,
-STORE, 94088468852736, 94088469258239,
-STORE, 94110050402304, 94110050615295,
-STORE, 94110052712448, 94110052716543,
-STORE, 94110052716544, 94110052724735,
-STORE, 94110052724736, 94110052737023,
-STORE, 94110061875200, 94110062415871,
-STORE, 140139439357952, 140139441016831,
-STORE, 140139441016832, 140139443113983,
-STORE, 140139443113984, 140139443130367,
-STORE, 140139443130368, 140139443138559,
-STORE, 140139443138560, 140139443154943,
-STORE, 140139443154944, 140139443167231,
-STORE, 140139443167232, 140139445260287,
-STORE, 140139445260288, 140139445264383,
-STORE, 140139445264384, 140139445268479,
-STORE, 140139445268480, 140139445411839,
-STORE, 140139445780480, 140139447463935,
-STORE, 140139447463936, 140139447480319,
-STORE, 140139447508992, 140139447513087,
-STORE, 140139447513088, 140139447517183,
-STORE, 140139447517184, 140139447521279,
-STORE, 140731901427712, 140731901566975,
-STORE, 140731902259200, 140731902271487,
-STORE, 140731902271488, 140731902275583,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140727282622464, 140737488351231,
-SNULL, 140727282630655, 140737488351231,
-STORE, 140727282622464, 140727282630655,
-STORE, 140727282491392, 140727282630655,
-STORE, 94266649866240, 94266652200959,
-SNULL, 94266650079231, 94266652200959,
-STORE, 94266649866240, 94266650079231,
-STORE, 94266650079232, 94266652200959,
-ERASE, 94266650079232, 94266652200959,
-STORE, 94266652176384, 94266652188671,
-STORE, 94266652188672, 94266652200959,
-STORE, 139888497991680, 139888500244479,
-SNULL, 139888498135039, 139888500244479,
-STORE, 139888497991680, 139888498135039,
-STORE, 139888498135040, 139888500244479,
-ERASE, 139888498135040, 139888500244479,
-STORE, 139888500232192, 139888500240383,
-STORE, 139888500240384, 139888500244479,
-STORE, 140727283113984, 140727283118079,
-STORE, 140727283101696, 140727283113983,
-STORE, 139888500203520, 139888500232191,
-STORE, 139888500195328, 139888500203519,
-STORE, 139888495878144, 139888497991679,
-SNULL, 139888495878144, 139888495890431,
-STORE, 139888495890432, 139888497991679,
-STORE, 139888495878144, 139888495890431,
-SNULL, 139888497983487, 139888497991679,
-STORE, 139888495890432, 139888497983487,
-STORE, 139888497983488, 139888497991679,
-ERASE, 139888497983488, 139888497991679,
-STORE, 139888497983488, 139888497991679,
-STORE, 139888492081152, 139888495878143,
-SNULL, 139888492081152, 139888493740031,
-STORE, 139888493740032, 139888495878143,
-STORE, 139888492081152, 139888493740031,
-SNULL, 139888495837183, 139888495878143,
-STORE, 139888493740032, 139888495837183,
-STORE, 139888495837184, 139888495878143,
-SNULL, 139888495837184, 139888495861759,
-STORE, 139888495861760, 139888495878143,
-STORE, 139888495837184, 139888495861759,
-ERASE, 139888495837184, 139888495861759,
-STORE, 139888495837184, 139888495861759,
-ERASE, 139888495861760, 139888495878143,
-STORE, 139888495861760, 139888495878143,
-STORE, 139888500187136, 139888500203519,
-SNULL, 139888495853567, 139888495861759,
-STORE, 139888495837184, 139888495853567,
-STORE, 139888495853568, 139888495861759,
-SNULL, 139888497987583, 139888497991679,
-STORE, 139888497983488, 139888497987583,
-STORE, 139888497987584, 139888497991679,
-SNULL, 94266652180479, 94266652188671,
-STORE, 94266652176384, 94266652180479,
-STORE, 94266652180480, 94266652188671,
-SNULL, 139888500236287, 139888500240383,
-STORE, 139888500232192, 139888500236287,
-STORE, 139888500236288, 139888500240383,
-ERASE, 139888500203520, 139888500232191,
-STORE, 94266678542336, 94266678677503,
-STORE, 139888498503680, 139888500187135,
-STORE, 94266678542336, 94266678812671,
-STORE, 94266678542336, 94266678947839,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722507702272, 140737488351231,
-SNULL, 140722507710463, 140737488351231,
-STORE, 140722507702272, 140722507710463,
-STORE, 140722507571200, 140722507710463,
-STORE, 94313981394944, 94313983729663,
-SNULL, 94313981607935, 94313983729663,
-STORE, 94313981394944, 94313981607935,
-STORE, 94313981607936, 94313983729663,
-ERASE, 94313981607936, 94313983729663,
-STORE, 94313983705088, 94313983717375,
-STORE, 94313983717376, 94313983729663,
-STORE, 140456286076928, 140456288329727,
-SNULL, 140456286220287, 140456288329727,
-STORE, 140456286076928, 140456286220287,
-STORE, 140456286220288, 140456288329727,
-ERASE, 140456286220288, 140456288329727,
-STORE, 140456288317440, 140456288325631,
-STORE, 140456288325632, 140456288329727,
-STORE, 140722507997184, 140722508001279,
-STORE, 140722507984896, 140722507997183,
-STORE, 140456288288768, 140456288317439,
-STORE, 140456288280576, 140456288288767,
-STORE, 140456283963392, 140456286076927,
-SNULL, 140456283963392, 140456283975679,
-STORE, 140456283975680, 140456286076927,
-STORE, 140456283963392, 140456283975679,
-SNULL, 140456286068735, 140456286076927,
-STORE, 140456283975680, 140456286068735,
-STORE, 140456286068736, 140456286076927,
-ERASE, 140456286068736, 140456286076927,
-STORE, 140456286068736, 140456286076927,
-STORE, 140456280166400, 140456283963391,
-SNULL, 140456280166400, 140456281825279,
-STORE, 140456281825280, 140456283963391,
-STORE, 140456280166400, 140456281825279,
-SNULL, 140456283922431, 140456283963391,
-STORE, 140456281825280, 140456283922431,
-STORE, 140456283922432, 140456283963391,
-SNULL, 140456283922432, 140456283947007,
-STORE, 140456283947008, 140456283963391,
-STORE, 140456283922432, 140456283947007,
-ERASE, 140456283922432, 140456283947007,
-STORE, 140456283922432, 140456283947007,
-ERASE, 140456283947008, 140456283963391,
-STORE, 140456283947008, 140456283963391,
-STORE, 140456288272384, 140456288288767,
-SNULL, 140456283938815, 140456283947007,
-STORE, 140456283922432, 140456283938815,
-STORE, 140456283938816, 140456283947007,
-SNULL, 140456286072831, 140456286076927,
-STORE, 140456286068736, 140456286072831,
-STORE, 140456286072832, 140456286076927,
-SNULL, 94313983709183, 94313983717375,
-STORE, 94313983705088, 94313983709183,
-STORE, 94313983709184, 94313983717375,
-SNULL, 140456288321535, 140456288325631,
-STORE, 140456288317440, 140456288321535,
-STORE, 140456288321536, 140456288325631,
-ERASE, 140456288288768, 140456288317439,
-STORE, 94314006716416, 94314006851583,
-STORE, 140456286588928, 140456288272383,
-STORE, 94314006716416, 94314006986751,
-STORE, 94314006716416, 94314007121919,
-STORE, 93948644454400, 93948644667391,
-STORE, 93948646764544, 93948646768639,
-STORE, 93948646768640, 93948646776831,
-STORE, 93948646776832, 93948646789119,
-STORE, 93948664999936, 93948667142143,
-STORE, 140187350659072, 140187352317951,
-STORE, 140187352317952, 140187354415103,
-STORE, 140187354415104, 140187354431487,
-STORE, 140187354431488, 140187354439679,
-STORE, 140187354439680, 140187354456063,
-STORE, 140187354456064, 140187354468351,
-STORE, 140187354468352, 140187356561407,
-STORE, 140187356561408, 140187356565503,
-STORE, 140187356565504, 140187356569599,
-STORE, 140187356569600, 140187356712959,
-STORE, 140187357081600, 140187358765055,
-STORE, 140187358765056, 140187358781439,
-STORE, 140187358810112, 140187358814207,
-STORE, 140187358814208, 140187358818303,
-STORE, 140187358818304, 140187358822399,
-STORE, 140730484518912, 140730484658175,
-STORE, 140730485690368, 140730485702655,
-STORE, 140730485702656, 140730485706751,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721211551744, 140737488351231,
-SNULL, 140721211559935, 140737488351231,
-STORE, 140721211551744, 140721211559935,
-STORE, 140721211420672, 140721211559935,
-STORE, 94105221423104, 94105223757823,
-SNULL, 94105221636095, 94105223757823,
-STORE, 94105221423104, 94105221636095,
-STORE, 94105221636096, 94105223757823,
-ERASE, 94105221636096, 94105223757823,
-STORE, 94105223733248, 94105223745535,
-STORE, 94105223745536, 94105223757823,
-STORE, 140474453676032, 140474455928831,
-SNULL, 140474453819391, 140474455928831,
-STORE, 140474453676032, 140474453819391,
-STORE, 140474453819392, 140474455928831,
-ERASE, 140474453819392, 140474455928831,
-STORE, 140474455916544, 140474455924735,
-STORE, 140474455924736, 140474455928831,
-STORE, 140721211703296, 140721211707391,
-STORE, 140721211691008, 140721211703295,
-STORE, 140474455887872, 140474455916543,
-STORE, 140474455879680, 140474455887871,
-STORE, 140474451562496, 140474453676031,
-SNULL, 140474451562496, 140474451574783,
-STORE, 140474451574784, 140474453676031,
-STORE, 140474451562496, 140474451574783,
-SNULL, 140474453667839, 140474453676031,
-STORE, 140474451574784, 140474453667839,
-STORE, 140474453667840, 140474453676031,
-ERASE, 140474453667840, 140474453676031,
-STORE, 140474453667840, 140474453676031,
-STORE, 140474447765504, 140474451562495,
-SNULL, 140474447765504, 140474449424383,
-STORE, 140474449424384, 140474451562495,
-STORE, 140474447765504, 140474449424383,
-SNULL, 140474451521535, 140474451562495,
-STORE, 140474449424384, 140474451521535,
-STORE, 140474451521536, 140474451562495,
-SNULL, 140474451521536, 140474451546111,
-STORE, 140474451546112, 140474451562495,
-STORE, 140474451521536, 140474451546111,
-ERASE, 140474451521536, 140474451546111,
-STORE, 140474451521536, 140474451546111,
-ERASE, 140474451546112, 140474451562495,
-STORE, 140474451546112, 140474451562495,
-STORE, 140474455871488, 140474455887871,
-SNULL, 140474451537919, 140474451546111,
-STORE, 140474451521536, 140474451537919,
-STORE, 140474451537920, 140474451546111,
-SNULL, 140474453671935, 140474453676031,
-STORE, 140474453667840, 140474453671935,
-STORE, 140474453671936, 140474453676031,
-SNULL, 94105223737343, 94105223745535,
-STORE, 94105223733248, 94105223737343,
-STORE, 94105223737344, 94105223745535,
-SNULL, 140474455920639, 140474455924735,
-STORE, 140474455916544, 140474455920639,
-STORE, 140474455920640, 140474455924735,
-ERASE, 140474455887872, 140474455916543,
-STORE, 94105238712320, 94105238847487,
-STORE, 140474454188032, 140474455871487,
-STORE, 94105238712320, 94105238982655,
-STORE, 94105238712320, 94105239117823,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732356354048, 140737488351231,
-SNULL, 140732356362239, 140737488351231,
-STORE, 140732356354048, 140732356362239,
-STORE, 140732356222976, 140732356362239,
-STORE, 94461165989888, 94461168324607,
-SNULL, 94461166202879, 94461168324607,
-STORE, 94461165989888, 94461166202879,
-STORE, 94461166202880, 94461168324607,
-ERASE, 94461166202880, 94461168324607,
-STORE, 94461168300032, 94461168312319,
-STORE, 94461168312320, 94461168324607,
-STORE, 140317255110656, 140317257363455,
-SNULL, 140317255254015, 140317257363455,
-STORE, 140317255110656, 140317255254015,
-STORE, 140317255254016, 140317257363455,
-ERASE, 140317255254016, 140317257363455,
-STORE, 140317257351168, 140317257359359,
-STORE, 140317257359360, 140317257363455,
-STORE, 140732356583424, 140732356587519,
-STORE, 140732356571136, 140732356583423,
-STORE, 140317257322496, 140317257351167,
-STORE, 140317257314304, 140317257322495,
-STORE, 140317252997120, 140317255110655,
-SNULL, 140317252997120, 140317253009407,
-STORE, 140317253009408, 140317255110655,
-STORE, 140317252997120, 140317253009407,
-SNULL, 140317255102463, 140317255110655,
-STORE, 140317253009408, 140317255102463,
-STORE, 140317255102464, 140317255110655,
-ERASE, 140317255102464, 140317255110655,
-STORE, 140317255102464, 140317255110655,
-STORE, 140317249200128, 140317252997119,
-SNULL, 140317249200128, 140317250859007,
-STORE, 140317250859008, 140317252997119,
-STORE, 140317249200128, 140317250859007,
-SNULL, 140317252956159, 140317252997119,
-STORE, 140317250859008, 140317252956159,
-STORE, 140317252956160, 140317252997119,
-SNULL, 140317252956160, 140317252980735,
-STORE, 140317252980736, 140317252997119,
-STORE, 140317252956160, 140317252980735,
-ERASE, 140317252956160, 140317252980735,
-STORE, 140317252956160, 140317252980735,
-ERASE, 140317252980736, 140317252997119,
-STORE, 140317252980736, 140317252997119,
-STORE, 140317257306112, 140317257322495,
-SNULL, 140317252972543, 140317252980735,
-STORE, 140317252956160, 140317252972543,
-STORE, 140317252972544, 140317252980735,
-SNULL, 140317255106559, 140317255110655,
-STORE, 140317255102464, 140317255106559,
-STORE, 140317255106560, 140317255110655,
-SNULL, 94461168304127, 94461168312319,
-STORE, 94461168300032, 94461168304127,
-STORE, 94461168304128, 94461168312319,
-SNULL, 140317257355263, 140317257359359,
-STORE, 140317257351168, 140317257355263,
-STORE, 140317257355264, 140317257359359,
-ERASE, 140317257322496, 140317257351167,
-STORE, 94461195268096, 94461195403263,
-STORE, 140317255622656, 140317257306111,
-STORE, 94461195268096, 94461195538431,
-STORE, 94461195268096, 94461195673599,
-STORE, 94110050402304, 94110050615295,
-STORE, 94110052712448, 94110052716543,
-STORE, 94110052716544, 94110052724735,
-STORE, 94110052724736, 94110052737023,
-STORE, 94110061875200, 94110062415871,
-STORE, 140139439357952, 140139441016831,
-STORE, 140139441016832, 140139443113983,
-STORE, 140139443113984, 140139443130367,
-STORE, 140139443130368, 140139443138559,
-STORE, 140139443138560, 140139443154943,
-STORE, 140139443154944, 140139443167231,
-STORE, 140139443167232, 140139445260287,
-STORE, 140139445260288, 140139445264383,
-STORE, 140139445264384, 140139445268479,
-STORE, 140139445268480, 140139445411839,
-STORE, 140139445780480, 140139447463935,
-STORE, 140139447463936, 140139447480319,
-STORE, 140139447508992, 140139447513087,
-STORE, 140139447513088, 140139447517183,
-STORE, 140139447517184, 140139447521279,
-STORE, 140731901427712, 140731901566975,
-STORE, 140731902259200, 140731902271487,
-STORE, 140731902271488, 140731902275583,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140720941613056, 140737488351231,
-SNULL, 140720941621247, 140737488351231,
-STORE, 140720941613056, 140720941621247,
-STORE, 140720941481984, 140720941621247,
-STORE, 93902377721856, 93902379945983,
-SNULL, 93902377832447, 93902379945983,
-STORE, 93902377721856, 93902377832447,
-STORE, 93902377832448, 93902379945983,
-ERASE, 93902377832448, 93902379945983,
-STORE, 93902379925504, 93902379937791,
-STORE, 93902379937792, 93902379945983,
-STORE, 139836543635456, 139836545888255,
-SNULL, 139836543778815, 139836545888255,
-STORE, 139836543635456, 139836543778815,
-STORE, 139836543778816, 139836545888255,
-ERASE, 139836543778816, 139836545888255,
-STORE, 139836545875968, 139836545884159,
-STORE, 139836545884160, 139836545888255,
-STORE, 140720941711360, 140720941715455,
-STORE, 140720941699072, 140720941711359,
-STORE, 139836545847296, 139836545875967,
-STORE, 139836545839104, 139836545847295,
-STORE, 139836539838464, 139836543635455,
-SNULL, 139836539838464, 139836541497343,
-STORE, 139836541497344, 139836543635455,
-STORE, 139836539838464, 139836541497343,
-SNULL, 139836543594495, 139836543635455,
-STORE, 139836541497344, 139836543594495,
-STORE, 139836543594496, 139836543635455,
-SNULL, 139836543594496, 139836543619071,
-STORE, 139836543619072, 139836543635455,
-STORE, 139836543594496, 139836543619071,
-ERASE, 139836543594496, 139836543619071,
-STORE, 139836543594496, 139836543619071,
-ERASE, 139836543619072, 139836543635455,
-STORE, 139836543619072, 139836543635455,
-SNULL, 139836543610879, 139836543619071,
-STORE, 139836543594496, 139836543610879,
-STORE, 139836543610880, 139836543619071,
-SNULL, 93902379933695, 93902379937791,
-STORE, 93902379925504, 93902379933695,
-STORE, 93902379933696, 93902379937791,
-SNULL, 139836545880063, 139836545884159,
-STORE, 139836545875968, 139836545880063,
-STORE, 139836545880064, 139836545884159,
-ERASE, 139836545847296, 139836545875967,
-STORE, 93902396891136, 93902397026303,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140736538206208, 140737488351231,
-SNULL, 140736538214399, 140737488351231,
-STORE, 140736538206208, 140736538214399,
-STORE, 140736538075136, 140736538214399,
-STORE, 94173471399936, 94173473734655,
-SNULL, 94173471612927, 94173473734655,
-STORE, 94173471399936, 94173471612927,
-STORE, 94173471612928, 94173473734655,
-ERASE, 94173471612928, 94173473734655,
-STORE, 94173473710080, 94173473722367,
-STORE, 94173473722368, 94173473734655,
-STORE, 140035513556992, 140035515809791,
-SNULL, 140035513700351, 140035515809791,
-STORE, 140035513556992, 140035513700351,
-STORE, 140035513700352, 140035515809791,
-ERASE, 140035513700352, 140035515809791,
-STORE, 140035515797504, 140035515805695,
-STORE, 140035515805696, 140035515809791,
-STORE, 140736538329088, 140736538333183,
-STORE, 140736538316800, 140736538329087,
-STORE, 140035515768832, 140035515797503,
-STORE, 140035515760640, 140035515768831,
-STORE, 140035511443456, 140035513556991,
-SNULL, 140035511443456, 140035511455743,
-STORE, 140035511455744, 140035513556991,
-STORE, 140035511443456, 140035511455743,
-SNULL, 140035513548799, 140035513556991,
-STORE, 140035511455744, 140035513548799,
-STORE, 140035513548800, 140035513556991,
-ERASE, 140035513548800, 140035513556991,
-STORE, 140035513548800, 140035513556991,
-STORE, 140035507646464, 140035511443455,
-SNULL, 140035507646464, 140035509305343,
-STORE, 140035509305344, 140035511443455,
-STORE, 140035507646464, 140035509305343,
-SNULL, 140035511402495, 140035511443455,
-STORE, 140035509305344, 140035511402495,
-STORE, 140035511402496, 140035511443455,
-SNULL, 140035511402496, 140035511427071,
-STORE, 140035511427072, 140035511443455,
-STORE, 140035511402496, 140035511427071,
-ERASE, 140035511402496, 140035511427071,
-STORE, 140035511402496, 140035511427071,
-ERASE, 140035511427072, 140035511443455,
-STORE, 140035511427072, 140035511443455,
-STORE, 140035515752448, 140035515768831,
-SNULL, 140035511418879, 140035511427071,
-STORE, 140035511402496, 140035511418879,
-STORE, 140035511418880, 140035511427071,
-SNULL, 140035513552895, 140035513556991,
-STORE, 140035513548800, 140035513552895,
-STORE, 140035513552896, 140035513556991,
-SNULL, 94173473714175, 94173473722367,
-STORE, 94173473710080, 94173473714175,
-STORE, 94173473714176, 94173473722367,
-SNULL, 140035515801599, 140035515805695,
-STORE, 140035515797504, 140035515801599,
-STORE, 140035515801600, 140035515805695,
-ERASE, 140035515768832, 140035515797503,
-STORE, 94173478645760, 94173478780927,
-STORE, 140035514068992, 140035515752447,
-STORE, 94173478645760, 94173478916095,
-STORE, 94173478645760, 94173479051263,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140724216176640, 140737488351231,
-SNULL, 140724216184831, 140737488351231,
-STORE, 140724216176640, 140724216184831,
-STORE, 140724216045568, 140724216184831,
-STORE, 94870930628608, 94870932963327,
-SNULL, 94870930841599, 94870932963327,
-STORE, 94870930628608, 94870930841599,
-STORE, 94870930841600, 94870932963327,
-ERASE, 94870930841600, 94870932963327,
-STORE, 94870932938752, 94870932951039,
-STORE, 94870932951040, 94870932963327,
-STORE, 140453683736576, 140453685989375,
-SNULL, 140453683879935, 140453685989375,
-STORE, 140453683736576, 140453683879935,
-STORE, 140453683879936, 140453685989375,
-ERASE, 140453683879936, 140453685989375,
-STORE, 140453685977088, 140453685985279,
-STORE, 140453685985280, 140453685989375,
-STORE, 140724216832000, 140724216836095,
-STORE, 140724216819712, 140724216831999,
-STORE, 140453685948416, 140453685977087,
-STORE, 140453685940224, 140453685948415,
-STORE, 140453681623040, 140453683736575,
-SNULL, 140453681623040, 140453681635327,
-STORE, 140453681635328, 140453683736575,
-STORE, 140453681623040, 140453681635327,
-SNULL, 140453683728383, 140453683736575,
-STORE, 140453681635328, 140453683728383,
-STORE, 140453683728384, 140453683736575,
-ERASE, 140453683728384, 140453683736575,
-STORE, 140453683728384, 140453683736575,
-STORE, 140453677826048, 140453681623039,
-SNULL, 140453677826048, 140453679484927,
-STORE, 140453679484928, 140453681623039,
-STORE, 140453677826048, 140453679484927,
-SNULL, 140453681582079, 140453681623039,
-STORE, 140453679484928, 140453681582079,
-STORE, 140453681582080, 140453681623039,
-SNULL, 140453681582080, 140453681606655,
-STORE, 140453681606656, 140453681623039,
-STORE, 140453681582080, 140453681606655,
-ERASE, 140453681582080, 140453681606655,
-STORE, 140453681582080, 140453681606655,
-ERASE, 140453681606656, 140453681623039,
-STORE, 140453681606656, 140453681623039,
-STORE, 140453685932032, 140453685948415,
-SNULL, 140453681598463, 140453681606655,
-STORE, 140453681582080, 140453681598463,
-STORE, 140453681598464, 140453681606655,
-SNULL, 140453683732479, 140453683736575,
-STORE, 140453683728384, 140453683732479,
-STORE, 140453683732480, 140453683736575,
-SNULL, 94870932942847, 94870932951039,
-STORE, 94870932938752, 94870932942847,
-STORE, 94870932942848, 94870932951039,
-SNULL, 140453685981183, 140453685985279,
-STORE, 140453685977088, 140453685981183,
-STORE, 140453685981184, 140453685985279,
-ERASE, 140453685948416, 140453685977087,
-STORE, 94870940565504, 94870940700671,
-STORE, 140453684248576, 140453685932031,
-STORE, 94870940565504, 94870940835839,
-STORE, 94870940565504, 94870940971007,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731275661312, 140737488351231,
-SNULL, 140731275669503, 140737488351231,
-STORE, 140731275661312, 140731275669503,
-STORE, 140731275530240, 140731275669503,
-STORE, 94642788548608, 94642790883327,
-SNULL, 94642788761599, 94642790883327,
-STORE, 94642788548608, 94642788761599,
-STORE, 94642788761600, 94642790883327,
-ERASE, 94642788761600, 94642790883327,
-STORE, 94642790858752, 94642790871039,
-STORE, 94642790871040, 94642790883327,
-STORE, 140228458749952, 140228461002751,
-SNULL, 140228458893311, 140228461002751,
-STORE, 140228458749952, 140228458893311,
-STORE, 140228458893312, 140228461002751,
-ERASE, 140228458893312, 140228461002751,
-STORE, 140228460990464, 140228460998655,
-STORE, 140228460998656, 140228461002751,
-STORE, 140731276349440, 140731276353535,
-STORE, 140731276337152, 140731276349439,
-STORE, 140228460961792, 140228460990463,
-STORE, 140228460953600, 140228460961791,
-STORE, 140228456636416, 140228458749951,
-SNULL, 140228456636416, 140228456648703,
-STORE, 140228456648704, 140228458749951,
-STORE, 140228456636416, 140228456648703,
-SNULL, 140228458741759, 140228458749951,
-STORE, 140228456648704, 140228458741759,
-STORE, 140228458741760, 140228458749951,
-ERASE, 140228458741760, 140228458749951,
-STORE, 140228458741760, 140228458749951,
-STORE, 140228452839424, 140228456636415,
-SNULL, 140228452839424, 140228454498303,
-STORE, 140228454498304, 140228456636415,
-STORE, 140228452839424, 140228454498303,
-SNULL, 140228456595455, 140228456636415,
-STORE, 140228454498304, 140228456595455,
-STORE, 140228456595456, 140228456636415,
-SNULL, 140228456595456, 140228456620031,
-STORE, 140228456620032, 140228456636415,
-STORE, 140228456595456, 140228456620031,
-ERASE, 140228456595456, 140228456620031,
-STORE, 140228456595456, 140228456620031,
-ERASE, 140228456620032, 140228456636415,
-STORE, 140228456620032, 140228456636415,
-STORE, 140228460945408, 140228460961791,
-SNULL, 140228456611839, 140228456620031,
-STORE, 140228456595456, 140228456611839,
-STORE, 140228456611840, 140228456620031,
-SNULL, 140228458745855, 140228458749951,
-STORE, 140228458741760, 140228458745855,
-STORE, 140228458745856, 140228458749951,
-SNULL, 94642790862847, 94642790871039,
-STORE, 94642790858752, 94642790862847,
-STORE, 94642790862848, 94642790871039,
-SNULL, 140228460994559, 140228460998655,
-STORE, 140228460990464, 140228460994559,
-STORE, 140228460994560, 140228460998655,
-ERASE, 140228460961792, 140228460990463,
-STORE, 94642801549312, 94642801684479,
-STORE, 140228459261952, 140228460945407,
-STORE, 94642801549312, 94642801819647,
-STORE, 94642801549312, 94642801954815,
-STORE, 94604087611392, 94604087824383,
-STORE, 94604089921536, 94604089925631,
-STORE, 94604089925632, 94604089933823,
-STORE, 94604089933824, 94604089946111,
-STORE, 94604105125888, 94604106424319,
-STORE, 140454937694208, 140454939353087,
-STORE, 140454939353088, 140454941450239,
-STORE, 140454941450240, 140454941466623,
-STORE, 140454941466624, 140454941474815,
-STORE, 140454941474816, 140454941491199,
-STORE, 140454941491200, 140454941503487,
-STORE, 140454941503488, 140454943596543,
-STORE, 140454943596544, 140454943600639,
-STORE, 140454943600640, 140454943604735,
-STORE, 140454943604736, 140454943748095,
-STORE, 140454944116736, 140454945800191,
-STORE, 140454945800192, 140454945816575,
-STORE, 140454945845248, 140454945849343,
-STORE, 140454945849344, 140454945853439,
-STORE, 140454945853440, 140454945857535,
-STORE, 140728438214656, 140728438353919,
-STORE, 140728439095296, 140728439107583,
-STORE, 140728439107584, 140728439111679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721843453952, 140737488351231,
-SNULL, 140721843462143, 140737488351231,
-STORE, 140721843453952, 140721843462143,
-STORE, 140721843322880, 140721843462143,
-STORE, 94465962455040, 94465964789759,
-SNULL, 94465962668031, 94465964789759,
-STORE, 94465962455040, 94465962668031,
-STORE, 94465962668032, 94465964789759,
-ERASE, 94465962668032, 94465964789759,
-STORE, 94465964765184, 94465964777471,
-STORE, 94465964777472, 94465964789759,
-STORE, 139913488314368, 139913490567167,
-SNULL, 139913488457727, 139913490567167,
-STORE, 139913488314368, 139913488457727,
-STORE, 139913488457728, 139913490567167,
-ERASE, 139913488457728, 139913490567167,
-STORE, 139913490554880, 139913490563071,
-STORE, 139913490563072, 139913490567167,
-STORE, 140721843503104, 140721843507199,
-STORE, 140721843490816, 140721843503103,
-STORE, 139913490526208, 139913490554879,
-STORE, 139913490518016, 139913490526207,
-STORE, 139913486200832, 139913488314367,
-SNULL, 139913486200832, 139913486213119,
-STORE, 139913486213120, 139913488314367,
-STORE, 139913486200832, 139913486213119,
-SNULL, 139913488306175, 139913488314367,
-STORE, 139913486213120, 139913488306175,
-STORE, 139913488306176, 139913488314367,
-ERASE, 139913488306176, 139913488314367,
-STORE, 139913488306176, 139913488314367,
-STORE, 139913482403840, 139913486200831,
-SNULL, 139913482403840, 139913484062719,
-STORE, 139913484062720, 139913486200831,
-STORE, 139913482403840, 139913484062719,
-SNULL, 139913486159871, 139913486200831,
-STORE, 139913484062720, 139913486159871,
-STORE, 139913486159872, 139913486200831,
-SNULL, 139913486159872, 139913486184447,
-STORE, 139913486184448, 139913486200831,
-STORE, 139913486159872, 139913486184447,
-ERASE, 139913486159872, 139913486184447,
-STORE, 139913486159872, 139913486184447,
-ERASE, 139913486184448, 139913486200831,
-STORE, 139913486184448, 139913486200831,
-STORE, 139913490509824, 139913490526207,
-SNULL, 139913486176255, 139913486184447,
-STORE, 139913486159872, 139913486176255,
-STORE, 139913486176256, 139913486184447,
-SNULL, 139913488310271, 139913488314367,
-STORE, 139913488306176, 139913488310271,
-STORE, 139913488310272, 139913488314367,
-SNULL, 94465964769279, 94465964777471,
-STORE, 94465964765184, 94465964769279,
-STORE, 94465964769280, 94465964777471,
-SNULL, 139913490558975, 139913490563071,
-STORE, 139913490554880, 139913490558975,
-STORE, 139913490558976, 139913490563071,
-ERASE, 139913490526208, 139913490554879,
-STORE, 94465970024448, 94465970159615,
-STORE, 139913488826368, 139913490509823,
-STORE, 94465970024448, 94465970294783,
-STORE, 94465970024448, 94465970429951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140720583307264, 140737488351231,
-SNULL, 140720583315455, 140737488351231,
-STORE, 140720583307264, 140720583315455,
-STORE, 140720583176192, 140720583315455,
-STORE, 94212322082816, 94212324417535,
-SNULL, 94212322295807, 94212324417535,
-STORE, 94212322082816, 94212322295807,
-STORE, 94212322295808, 94212324417535,
-ERASE, 94212322295808, 94212324417535,
-STORE, 94212324392960, 94212324405247,
-STORE, 94212324405248, 94212324417535,
-STORE, 139659688538112, 139659690790911,
-SNULL, 139659688681471, 139659690790911,
-STORE, 139659688538112, 139659688681471,
-STORE, 139659688681472, 139659690790911,
-ERASE, 139659688681472, 139659690790911,
-STORE, 139659690778624, 139659690786815,
-STORE, 139659690786816, 139659690790911,
-STORE, 140720584781824, 140720584785919,
-STORE, 140720584769536, 140720584781823,
-STORE, 139659690749952, 139659690778623,
-STORE, 139659690741760, 139659690749951,
-STORE, 139659686424576, 139659688538111,
-SNULL, 139659686424576, 139659686436863,
-STORE, 139659686436864, 139659688538111,
-STORE, 139659686424576, 139659686436863,
-SNULL, 139659688529919, 139659688538111,
-STORE, 139659686436864, 139659688529919,
-STORE, 139659688529920, 139659688538111,
-ERASE, 139659688529920, 139659688538111,
-STORE, 139659688529920, 139659688538111,
-STORE, 139659682627584, 139659686424575,
-SNULL, 139659682627584, 139659684286463,
-STORE, 139659684286464, 139659686424575,
-STORE, 139659682627584, 139659684286463,
-SNULL, 139659686383615, 139659686424575,
-STORE, 139659684286464, 139659686383615,
-STORE, 139659686383616, 139659686424575,
-SNULL, 139659686383616, 139659686408191,
-STORE, 139659686408192, 139659686424575,
-STORE, 139659686383616, 139659686408191,
-ERASE, 139659686383616, 139659686408191,
-STORE, 139659686383616, 139659686408191,
-ERASE, 139659686408192, 139659686424575,
-STORE, 139659686408192, 139659686424575,
-STORE, 139659690733568, 139659690749951,
-SNULL, 139659686399999, 139659686408191,
-STORE, 139659686383616, 139659686399999,
-STORE, 139659686400000, 139659686408191,
-SNULL, 139659688534015, 139659688538111,
-STORE, 139659688529920, 139659688534015,
-STORE, 139659688534016, 139659688538111,
-SNULL, 94212324397055, 94212324405247,
-STORE, 94212324392960, 94212324397055,
-STORE, 94212324397056, 94212324405247,
-SNULL, 139659690782719, 139659690786815,
-STORE, 139659690778624, 139659690782719,
-STORE, 139659690782720, 139659690786815,
-ERASE, 139659690749952, 139659690778623,
-STORE, 94212355014656, 94212355149823,
-STORE, 139659689050112, 139659690733567,
-STORE, 94212355014656, 94212355284991,
-STORE, 94212355014656, 94212355420159,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140727689830400, 140737488351231,
-SNULL, 140727689838591, 140737488351231,
-STORE, 140727689830400, 140727689838591,
-STORE, 140727689699328, 140727689838591,
-STORE, 94572390281216, 94572392615935,
-SNULL, 94572390494207, 94572392615935,
-STORE, 94572390281216, 94572390494207,
-STORE, 94572390494208, 94572392615935,
-ERASE, 94572390494208, 94572392615935,
-STORE, 94572392591360, 94572392603647,
-STORE, 94572392603648, 94572392615935,
-STORE, 140575923769344, 140575926022143,
-SNULL, 140575923912703, 140575926022143,
-STORE, 140575923769344, 140575923912703,
-STORE, 140575923912704, 140575926022143,
-ERASE, 140575923912704, 140575926022143,
-STORE, 140575926009856, 140575926018047,
-STORE, 140575926018048, 140575926022143,
-STORE, 140727689871360, 140727689875455,
-STORE, 140727689859072, 140727689871359,
-STORE, 140575925981184, 140575926009855,
-STORE, 140575925972992, 140575925981183,
-STORE, 140575921655808, 140575923769343,
-SNULL, 140575921655808, 140575921668095,
-STORE, 140575921668096, 140575923769343,
-STORE, 140575921655808, 140575921668095,
-SNULL, 140575923761151, 140575923769343,
-STORE, 140575921668096, 140575923761151,
-STORE, 140575923761152, 140575923769343,
-ERASE, 140575923761152, 140575923769343,
-STORE, 140575923761152, 140575923769343,
-STORE, 140575917858816, 140575921655807,
-SNULL, 140575917858816, 140575919517695,
-STORE, 140575919517696, 140575921655807,
-STORE, 140575917858816, 140575919517695,
-SNULL, 140575921614847, 140575921655807,
-STORE, 140575919517696, 140575921614847,
-STORE, 140575921614848, 140575921655807,
-SNULL, 140575921614848, 140575921639423,
-STORE, 140575921639424, 140575921655807,
-STORE, 140575921614848, 140575921639423,
-ERASE, 140575921614848, 140575921639423,
-STORE, 140575921614848, 140575921639423,
-ERASE, 140575921639424, 140575921655807,
-STORE, 140575921639424, 140575921655807,
-STORE, 140575925964800, 140575925981183,
-SNULL, 140575921631231, 140575921639423,
-STORE, 140575921614848, 140575921631231,
-STORE, 140575921631232, 140575921639423,
-SNULL, 140575923765247, 140575923769343,
-STORE, 140575923761152, 140575923765247,
-STORE, 140575923765248, 140575923769343,
-SNULL, 94572392595455, 94572392603647,
-STORE, 94572392591360, 94572392595455,
-STORE, 94572392595456, 94572392603647,
-SNULL, 140575926013951, 140575926018047,
-STORE, 140575926009856, 140575926013951,
-STORE, 140575926013952, 140575926018047,
-ERASE, 140575925981184, 140575926009855,
-STORE, 94572402278400, 94572402413567,
-STORE, 140575924281344, 140575925964799,
-STORE, 94572402278400, 94572402548735,
-STORE, 94572402278400, 94572402683903,
-STORE, 94572402278400, 94572402851839,
-SNULL, 94572402827263, 94572402851839,
-STORE, 94572402278400, 94572402827263,
-STORE, 94572402827264, 94572402851839,
-ERASE, 94572402827264, 94572402851839,
-STORE, 94572402278400, 94572402966527,
-STORE, 94572402278400, 94572403109887,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725520506880, 140737488351231,
-SNULL, 140725520515071, 140737488351231,
-STORE, 140725520506880, 140725520515071,
-STORE, 140725520375808, 140725520515071,
-STORE, 93829948788736, 93829951012863,
-SNULL, 93829948899327, 93829951012863,
-STORE, 93829948788736, 93829948899327,
-STORE, 93829948899328, 93829951012863,
-ERASE, 93829948899328, 93829951012863,
-STORE, 93829950992384, 93829951004671,
-STORE, 93829951004672, 93829951012863,
-STORE, 140133696794624, 140133699047423,
-SNULL, 140133696937983, 140133699047423,
-STORE, 140133696794624, 140133696937983,
-STORE, 140133696937984, 140133699047423,
-ERASE, 140133696937984, 140133699047423,
-STORE, 140133699035136, 140133699043327,
-STORE, 140133699043328, 140133699047423,
-STORE, 140725520875520, 140725520879615,
-STORE, 140725520863232, 140725520875519,
-STORE, 140133699006464, 140133699035135,
-STORE, 140133698998272, 140133699006463,
-STORE, 140133692997632, 140133696794623,
-SNULL, 140133692997632, 140133694656511,
-STORE, 140133694656512, 140133696794623,
-STORE, 140133692997632, 140133694656511,
-SNULL, 140133696753663, 140133696794623,
-STORE, 140133694656512, 140133696753663,
-STORE, 140133696753664, 140133696794623,
-SNULL, 140133696753664, 140133696778239,
-STORE, 140133696778240, 140133696794623,
-STORE, 140133696753664, 140133696778239,
-ERASE, 140133696753664, 140133696778239,
-STORE, 140133696753664, 140133696778239,
-ERASE, 140133696778240, 140133696794623,
-STORE, 140133696778240, 140133696794623,
-SNULL, 140133696770047, 140133696778239,
-STORE, 140133696753664, 140133696770047,
-STORE, 140133696770048, 140133696778239,
-SNULL, 93829951000575, 93829951004671,
-STORE, 93829950992384, 93829951000575,
-STORE, 93829951000576, 93829951004671,
-SNULL, 140133699039231, 140133699043327,
-STORE, 140133699035136, 140133699039231,
-STORE, 140133699039232, 140133699043327,
-ERASE, 140133699006464, 140133699035135,
-STORE, 93829978693632, 93829978828799,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140736118022144, 140737488351231,
-SNULL, 140736118030335, 140737488351231,
-STORE, 140736118022144, 140736118030335,
-STORE, 140736117891072, 140736118030335,
-STORE, 94467663982592, 94467666206719,
-SNULL, 94467664093183, 94467666206719,
-STORE, 94467663982592, 94467664093183,
-STORE, 94467664093184, 94467666206719,
-ERASE, 94467664093184, 94467666206719,
-STORE, 94467666186240, 94467666198527,
-STORE, 94467666198528, 94467666206719,
-STORE, 140525377327104, 140525379579903,
-SNULL, 140525377470463, 140525379579903,
-STORE, 140525377327104, 140525377470463,
-STORE, 140525377470464, 140525379579903,
-ERASE, 140525377470464, 140525379579903,
-STORE, 140525379567616, 140525379575807,
-STORE, 140525379575808, 140525379579903,
-STORE, 140736118771712, 140736118775807,
-STORE, 140736118759424, 140736118771711,
-STORE, 140525379538944, 140525379567615,
-STORE, 140525379530752, 140525379538943,
-STORE, 140525373530112, 140525377327103,
-SNULL, 140525373530112, 140525375188991,
-STORE, 140525375188992, 140525377327103,
-STORE, 140525373530112, 140525375188991,
-SNULL, 140525377286143, 140525377327103,
-STORE, 140525375188992, 140525377286143,
-STORE, 140525377286144, 140525377327103,
-SNULL, 140525377286144, 140525377310719,
-STORE, 140525377310720, 140525377327103,
-STORE, 140525377286144, 140525377310719,
-ERASE, 140525377286144, 140525377310719,
-STORE, 140525377286144, 140525377310719,
-ERASE, 140525377310720, 140525377327103,
-STORE, 140525377310720, 140525377327103,
-SNULL, 140525377302527, 140525377310719,
-STORE, 140525377286144, 140525377302527,
-STORE, 140525377302528, 140525377310719,
-SNULL, 94467666194431, 94467666198527,
-STORE, 94467666186240, 94467666194431,
-STORE, 94467666194432, 94467666198527,
-SNULL, 140525379571711, 140525379575807,
-STORE, 140525379567616, 140525379571711,
-STORE, 140525379571712, 140525379575807,
-ERASE, 140525379538944, 140525379567615,
-STORE, 94467693379584, 94467693514751,
-STORE, 94200172744704, 94200172957695,
-STORE, 94200175054848, 94200175058943,
-STORE, 94200175058944, 94200175067135,
-STORE, 94200175067136, 94200175079423,
-STORE, 94200196673536, 94200198905855,
-STORE, 140053867720704, 140053869379583,
-STORE, 140053869379584, 140053871476735,
-STORE, 140053871476736, 140053871493119,
-STORE, 140053871493120, 140053871501311,
-STORE, 140053871501312, 140053871517695,
-STORE, 140053871517696, 140053871529983,
-STORE, 140053871529984, 140053873623039,
-STORE, 140053873623040, 140053873627135,
-STORE, 140053873627136, 140053873631231,
-STORE, 140053873631232, 140053873774591,
-STORE, 140053874143232, 140053875826687,
-STORE, 140053875826688, 140053875843071,
-STORE, 140053875871744, 140053875875839,
-STORE, 140053875875840, 140053875879935,
-STORE, 140053875879936, 140053875884031,
-STORE, 140728538484736, 140728538623999,
-STORE, 140728538652672, 140728538664959,
-STORE, 140728538664960, 140728538669055,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732307775488, 140737488351231,
-SNULL, 140732307783679, 140737488351231,
-STORE, 140732307775488, 140732307783679,
-STORE, 140732307644416, 140732307783679,
-STORE, 93831417630720, 93831419965439,
-SNULL, 93831417843711, 93831419965439,
-STORE, 93831417630720, 93831417843711,
-STORE, 93831417843712, 93831419965439,
-ERASE, 93831417843712, 93831419965439,
-STORE, 93831419940864, 93831419953151,
-STORE, 93831419953152, 93831419965439,
-STORE, 140241062088704, 140241064341503,
-SNULL, 140241062232063, 140241064341503,
-STORE, 140241062088704, 140241062232063,
-STORE, 140241062232064, 140241064341503,
-ERASE, 140241062232064, 140241064341503,
-STORE, 140241064329216, 140241064337407,
-STORE, 140241064337408, 140241064341503,
-STORE, 140732308140032, 140732308144127,
-STORE, 140732308127744, 140732308140031,
-STORE, 140241064300544, 140241064329215,
-STORE, 140241064292352, 140241064300543,
-STORE, 140241059975168, 140241062088703,
-SNULL, 140241059975168, 140241059987455,
-STORE, 140241059987456, 140241062088703,
-STORE, 140241059975168, 140241059987455,
-SNULL, 140241062080511, 140241062088703,
-STORE, 140241059987456, 140241062080511,
-STORE, 140241062080512, 140241062088703,
-ERASE, 140241062080512, 140241062088703,
-STORE, 140241062080512, 140241062088703,
-STORE, 140241056178176, 140241059975167,
-SNULL, 140241056178176, 140241057837055,
-STORE, 140241057837056, 140241059975167,
-STORE, 140241056178176, 140241057837055,
-SNULL, 140241059934207, 140241059975167,
-STORE, 140241057837056, 140241059934207,
-STORE, 140241059934208, 140241059975167,
-SNULL, 140241059934208, 140241059958783,
-STORE, 140241059958784, 140241059975167,
-STORE, 140241059934208, 140241059958783,
-ERASE, 140241059934208, 140241059958783,
-STORE, 140241059934208, 140241059958783,
-ERASE, 140241059958784, 140241059975167,
-STORE, 140241059958784, 140241059975167,
-STORE, 140241064284160, 140241064300543,
-SNULL, 140241059950591, 140241059958783,
-STORE, 140241059934208, 140241059950591,
-STORE, 140241059950592, 140241059958783,
-SNULL, 140241062084607, 140241062088703,
-STORE, 140241062080512, 140241062084607,
-STORE, 140241062084608, 140241062088703,
-SNULL, 93831419944959, 93831419953151,
-STORE, 93831419940864, 93831419944959,
-STORE, 93831419944960, 93831419953151,
-SNULL, 140241064333311, 140241064337407,
-STORE, 140241064329216, 140241064333311,
-STORE, 140241064333312, 140241064337407,
-ERASE, 140241064300544, 140241064329215,
-STORE, 93831435284480, 93831435419647,
-STORE, 140241062600704, 140241064284159,
-STORE, 93831435284480, 93831435554815,
-STORE, 93831435284480, 93831435689983,
-STORE, 93831435284480, 93831435862015,
-SNULL, 93831435837439, 93831435862015,
-STORE, 93831435284480, 93831435837439,
-STORE, 93831435837440, 93831435862015,
-ERASE, 93831435837440, 93831435862015,
-STORE, 93831435284480, 93831435972607,
-STORE, 93831435284480, 93831436107775,
-SNULL, 93831436091391, 93831436107775,
-STORE, 93831435284480, 93831436091391,
-STORE, 93831436091392, 93831436107775,
-ERASE, 93831436091392, 93831436107775,
-STORE, 93831435284480, 93831436226559,
-STORE, 93831435284480, 93831436361727,
-STORE, 93831435284480, 93831436505087,
-STORE, 93831435284480, 93831436652543,
-STORE, 93831435284480, 93831436787711,
-STORE, 93831435284480, 93831436926975,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140728546775040, 140737488351231,
-SNULL, 140728546783231, 140737488351231,
-STORE, 140728546775040, 140728546783231,
-STORE, 140728546643968, 140728546783231,
-STORE, 94456178786304, 94456181010431,
-SNULL, 94456178896895, 94456181010431,
-STORE, 94456178786304, 94456178896895,
-STORE, 94456178896896, 94456181010431,
-ERASE, 94456178896896, 94456181010431,
-STORE, 94456180989952, 94456181002239,
-STORE, 94456181002240, 94456181010431,
-STORE, 140221893091328, 140221895344127,
-SNULL, 140221893234687, 140221895344127,
-STORE, 140221893091328, 140221893234687,
-STORE, 140221893234688, 140221895344127,
-ERASE, 140221893234688, 140221895344127,
-STORE, 140221895331840, 140221895340031,
-STORE, 140221895340032, 140221895344127,
-STORE, 140728547803136, 140728547807231,
-STORE, 140728547790848, 140728547803135,
-STORE, 140221895303168, 140221895331839,
-STORE, 140221895294976, 140221895303167,
-STORE, 140221889294336, 140221893091327,
-SNULL, 140221889294336, 140221890953215,
-STORE, 140221890953216, 140221893091327,
-STORE, 140221889294336, 140221890953215,
-SNULL, 140221893050367, 140221893091327,
-STORE, 140221890953216, 140221893050367,
-STORE, 140221893050368, 140221893091327,
-SNULL, 140221893050368, 140221893074943,
-STORE, 140221893074944, 140221893091327,
-STORE, 140221893050368, 140221893074943,
-ERASE, 140221893050368, 140221893074943,
-STORE, 140221893050368, 140221893074943,
-ERASE, 140221893074944, 140221893091327,
-STORE, 140221893074944, 140221893091327,
-SNULL, 140221893066751, 140221893074943,
-STORE, 140221893050368, 140221893066751,
-STORE, 140221893066752, 140221893074943,
-SNULL, 94456180998143, 94456181002239,
-STORE, 94456180989952, 94456180998143,
-STORE, 94456180998144, 94456181002239,
-SNULL, 140221895335935, 140221895340031,
-STORE, 140221895331840, 140221895335935,
-STORE, 140221895335936, 140221895340031,
-ERASE, 140221895303168, 140221895331839,
-STORE, 94456203730944, 94456203866111,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140734438637568, 140737488351231,
-SNULL, 140734438645759, 140737488351231,
-STORE, 140734438637568, 140734438645759,
-STORE, 140734438506496, 140734438645759,
-STORE, 94652233351168, 94652235575295,
-SNULL, 94652233461759, 94652235575295,
-STORE, 94652233351168, 94652233461759,
-STORE, 94652233461760, 94652235575295,
-ERASE, 94652233461760, 94652235575295,
-STORE, 94652235554816, 94652235567103,
-STORE, 94652235567104, 94652235575295,
-STORE, 140536493195264, 140536495448063,
-SNULL, 140536493338623, 140536495448063,
-STORE, 140536493195264, 140536493338623,
-STORE, 140536493338624, 140536495448063,
-ERASE, 140536493338624, 140536495448063,
-STORE, 140536495435776, 140536495443967,
-STORE, 140536495443968, 140536495448063,
-STORE, 140734439002112, 140734439006207,
-STORE, 140734438989824, 140734439002111,
-STORE, 140536495407104, 140536495435775,
-STORE, 140536495398912, 140536495407103,
-STORE, 140536489398272, 140536493195263,
-SNULL, 140536489398272, 140536491057151,
-STORE, 140536491057152, 140536493195263,
-STORE, 140536489398272, 140536491057151,
-SNULL, 140536493154303, 140536493195263,
-STORE, 140536491057152, 140536493154303,
-STORE, 140536493154304, 140536493195263,
-SNULL, 140536493154304, 140536493178879,
-STORE, 140536493178880, 140536493195263,
-STORE, 140536493154304, 140536493178879,
-ERASE, 140536493154304, 140536493178879,
-STORE, 140536493154304, 140536493178879,
-ERASE, 140536493178880, 140536493195263,
-STORE, 140536493178880, 140536493195263,
-SNULL, 140536493170687, 140536493178879,
-STORE, 140536493154304, 140536493170687,
-STORE, 140536493170688, 140536493178879,
-SNULL, 94652235563007, 94652235567103,
-STORE, 94652235554816, 94652235563007,
-STORE, 94652235563008, 94652235567103,
-SNULL, 140536495439871, 140536495443967,
-STORE, 140536495435776, 140536495439871,
-STORE, 140536495439872, 140536495443967,
-ERASE, 140536495407104, 140536495435775,
-STORE, 94652265619456, 94652265754623,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140721814200320, 140737488351231,
-SNULL, 140721814208511, 140737488351231,
-STORE, 140721814200320, 140721814208511,
-STORE, 140721814069248, 140721814208511,
-STORE, 94062800691200, 94062802915327,
-SNULL, 94062800801791, 94062802915327,
-STORE, 94062800691200, 94062800801791,
-STORE, 94062800801792, 94062802915327,
-ERASE, 94062800801792, 94062802915327,
-STORE, 94062802894848, 94062802907135,
-STORE, 94062802907136, 94062802915327,
-STORE, 139717739700224, 139717741953023,
-SNULL, 139717739843583, 139717741953023,
-STORE, 139717739700224, 139717739843583,
-STORE, 139717739843584, 139717741953023,
-ERASE, 139717739843584, 139717741953023,
-STORE, 139717741940736, 139717741948927,
-STORE, 139717741948928, 139717741953023,
-STORE, 140721814224896, 140721814228991,
-STORE, 140721814212608, 140721814224895,
-STORE, 139717741912064, 139717741940735,
-STORE, 139717741903872, 139717741912063,
-STORE, 139717735903232, 139717739700223,
-SNULL, 139717735903232, 139717737562111,
-STORE, 139717737562112, 139717739700223,
-STORE, 139717735903232, 139717737562111,
-SNULL, 139717739659263, 139717739700223,
-STORE, 139717737562112, 139717739659263,
-STORE, 139717739659264, 139717739700223,
-SNULL, 139717739659264, 139717739683839,
-STORE, 139717739683840, 139717739700223,
-STORE, 139717739659264, 139717739683839,
-ERASE, 139717739659264, 139717739683839,
-STORE, 139717739659264, 139717739683839,
-ERASE, 139717739683840, 139717739700223,
-STORE, 139717739683840, 139717739700223,
-SNULL, 139717739675647, 139717739683839,
-STORE, 139717739659264, 139717739675647,
-STORE, 139717739675648, 139717739683839,
-SNULL, 94062802903039, 94062802907135,
-STORE, 94062802894848, 94062802903039,
-STORE, 94062802903040, 94062802907135,
-SNULL, 139717741944831, 139717741948927,
-STORE, 139717741940736, 139717741944831,
-STORE, 139717741944832, 139717741948927,
-ERASE, 139717741912064, 139717741940735,
-STORE, 94062814060544, 94062814195711,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723945754624, 140737488351231,
-SNULL, 140723945762815, 140737488351231,
-STORE, 140723945754624, 140723945762815,
-STORE, 140723945623552, 140723945762815,
-STORE, 94886119305216, 94886121639935,
-SNULL, 94886119518207, 94886121639935,
-STORE, 94886119305216, 94886119518207,
-STORE, 94886119518208, 94886121639935,
-ERASE, 94886119518208, 94886121639935,
-STORE, 94886121615360, 94886121627647,
-STORE, 94886121627648, 94886121639935,
-STORE, 140152532131840, 140152534384639,
-SNULL, 140152532275199, 140152534384639,
-STORE, 140152532131840, 140152532275199,
-STORE, 140152532275200, 140152534384639,
-ERASE, 140152532275200, 140152534384639,
-STORE, 140152534372352, 140152534380543,
-STORE, 140152534380544, 140152534384639,
-STORE, 140723946213376, 140723946217471,
-STORE, 140723946201088, 140723946213375,
-STORE, 140152534343680, 140152534372351,
-STORE, 140152534335488, 140152534343679,
-STORE, 140152530018304, 140152532131839,
-SNULL, 140152530018304, 140152530030591,
-STORE, 140152530030592, 140152532131839,
-STORE, 140152530018304, 140152530030591,
-SNULL, 140152532123647, 140152532131839,
-STORE, 140152530030592, 140152532123647,
-STORE, 140152532123648, 140152532131839,
-ERASE, 140152532123648, 140152532131839,
-STORE, 140152532123648, 140152532131839,
-STORE, 140152526221312, 140152530018303,
-SNULL, 140152526221312, 140152527880191,
-STORE, 140152527880192, 140152530018303,
-STORE, 140152526221312, 140152527880191,
-SNULL, 140152529977343, 140152530018303,
-STORE, 140152527880192, 140152529977343,
-STORE, 140152529977344, 140152530018303,
-SNULL, 140152529977344, 140152530001919,
-STORE, 140152530001920, 140152530018303,
-STORE, 140152529977344, 140152530001919,
-ERASE, 140152529977344, 140152530001919,
-STORE, 140152529977344, 140152530001919,
-ERASE, 140152530001920, 140152530018303,
-STORE, 140152530001920, 140152530018303,
-STORE, 140152534327296, 140152534343679,
-SNULL, 140152529993727, 140152530001919,
-STORE, 140152529977344, 140152529993727,
-STORE, 140152529993728, 140152530001919,
-SNULL, 140152532127743, 140152532131839,
-STORE, 140152532123648, 140152532127743,
-STORE, 140152532127744, 140152532131839,
-SNULL, 94886121619455, 94886121627647,
-STORE, 94886121615360, 94886121619455,
-STORE, 94886121619456, 94886121627647,
-SNULL, 140152534376447, 140152534380543,
-STORE, 140152534372352, 140152534376447,
-STORE, 140152534376448, 140152534380543,
-ERASE, 140152534343680, 140152534372351,
-STORE, 94886129770496, 94886129905663,
-STORE, 140152532643840, 140152534327295,
-STORE, 94886129770496, 94886130040831,
-STORE, 94886129770496, 94886130175999,
-STORE, 94886129770496, 94886130348031,
-SNULL, 94886130323455, 94886130348031,
-STORE, 94886129770496, 94886130323455,
-STORE, 94886130323456, 94886130348031,
-ERASE, 94886130323456, 94886130348031,
-STORE, 94886129770496, 94886130458623,
-STORE, 94886129770496, 94886130606079,
-SNULL, 94886130573311, 94886130606079,
-STORE, 94886129770496, 94886130573311,
-STORE, 94886130573312, 94886130606079,
-ERASE, 94886130573312, 94886130606079,
-STORE, 94886129770496, 94886130724863,
-STORE, 94886129770496, 94886130876415,
-STORE, 94886129770496, 94886131023871,
-STORE, 94886129770496, 94886131175423,
-STORE, 94886129770496, 94886131318783,
-STORE, 94886129770496, 94886131453951,
-SNULL, 94886131449855, 94886131453951,
-STORE, 94886129770496, 94886131449855,
-STORE, 94886131449856, 94886131453951,
-ERASE, 94886131449856, 94886131453951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735450779648, 140737488351231,
-SNULL, 140735450787839, 140737488351231,
-STORE, 140735450779648, 140735450787839,
-STORE, 140735450648576, 140735450787839,
-STORE, 93947794079744, 93947796414463,
-SNULL, 93947794292735, 93947796414463,
-STORE, 93947794079744, 93947794292735,
-STORE, 93947794292736, 93947796414463,
-ERASE, 93947794292736, 93947796414463,
-STORE, 93947796389888, 93947796402175,
-STORE, 93947796402176, 93947796414463,
-STORE, 139841993433088, 139841995685887,
-SNULL, 139841993576447, 139841995685887,
-STORE, 139841993433088, 139841993576447,
-STORE, 139841993576448, 139841995685887,
-ERASE, 139841993576448, 139841995685887,
-STORE, 139841995673600, 139841995681791,
-STORE, 139841995681792, 139841995685887,
-STORE, 140735451308032, 140735451312127,
-STORE, 140735451295744, 140735451308031,
-STORE, 139841995644928, 139841995673599,
-STORE, 139841995636736, 139841995644927,
-STORE, 139841991319552, 139841993433087,
-SNULL, 139841991319552, 139841991331839,
-STORE, 139841991331840, 139841993433087,
-STORE, 139841991319552, 139841991331839,
-SNULL, 139841993424895, 139841993433087,
-STORE, 139841991331840, 139841993424895,
-STORE, 139841993424896, 139841993433087,
-ERASE, 139841993424896, 139841993433087,
-STORE, 139841993424896, 139841993433087,
-STORE, 139841987522560, 139841991319551,
-SNULL, 139841987522560, 139841989181439,
-STORE, 139841989181440, 139841991319551,
-STORE, 139841987522560, 139841989181439,
-SNULL, 139841991278591, 139841991319551,
-STORE, 139841989181440, 139841991278591,
-STORE, 139841991278592, 139841991319551,
-SNULL, 139841991278592, 139841991303167,
-STORE, 139841991303168, 139841991319551,
-STORE, 139841991278592, 139841991303167,
-ERASE, 139841991278592, 139841991303167,
-STORE, 139841991278592, 139841991303167,
-ERASE, 139841991303168, 139841991319551,
-STORE, 139841991303168, 139841991319551,
-STORE, 139841995628544, 139841995644927,
-SNULL, 139841991294975, 139841991303167,
-STORE, 139841991278592, 139841991294975,
-STORE, 139841991294976, 139841991303167,
-SNULL, 139841993428991, 139841993433087,
-STORE, 139841993424896, 139841993428991,
-STORE, 139841993428992, 139841993433087,
-SNULL, 93947796393983, 93947796402175,
-STORE, 93947796389888, 93947796393983,
-STORE, 93947796393984, 93947796402175,
-SNULL, 139841995677695, 139841995681791,
-STORE, 139841995673600, 139841995677695,
-STORE, 139841995677696, 139841995681791,
-ERASE, 139841995644928, 139841995673599,
-STORE, 93947829739520, 93947829874687,
-STORE, 139841993945088, 139841995628543,
-STORE, 93947829739520, 93947830009855,
-STORE, 93947829739520, 93947830145023,
-STORE, 94659351814144, 94659352027135,
-STORE, 94659354124288, 94659354128383,
-STORE, 94659354128384, 94659354136575,
-STORE, 94659354136576, 94659354148863,
-STORE, 94659383476224, 94659385057279,
-STORE, 139959054557184, 139959056216063,
-STORE, 139959056216064, 139959058313215,
-STORE, 139959058313216, 139959058329599,
-STORE, 139959058329600, 139959058337791,
-STORE, 139959058337792, 139959058354175,
-STORE, 139959058354176, 139959058366463,
-STORE, 139959058366464, 139959060459519,
-STORE, 139959060459520, 139959060463615,
-STORE, 139959060463616, 139959060467711,
-STORE, 139959060467712, 139959060611071,
-STORE, 139959060979712, 139959062663167,
-STORE, 139959062663168, 139959062679551,
-STORE, 139959062708224, 139959062712319,
-STORE, 139959062712320, 139959062716415,
-STORE, 139959062716416, 139959062720511,
-STORE, 140735532539904, 140735532679167,
-STORE, 140735532830720, 140735532843007,
-STORE, 140735532843008, 140735532847103,
-STORE, 93894361829376, 93894362042367,
-STORE, 93894364139520, 93894364143615,
-STORE, 93894364143616, 93894364151807,
-STORE, 93894364151808, 93894364164095,
-STORE, 93894396944384, 93894397624319,
-STORE, 140075612573696, 140075614232575,
-STORE, 140075614232576, 140075616329727,
-STORE, 140075616329728, 140075616346111,
-STORE, 140075616346112, 140075616354303,
-STORE, 140075616354304, 140075616370687,
-STORE, 140075616370688, 140075616382975,
-STORE, 140075616382976, 140075618476031,
-STORE, 140075618476032, 140075618480127,
-STORE, 140075618480128, 140075618484223,
-STORE, 140075618484224, 140075618627583,
-STORE, 140075618996224, 140075620679679,
-STORE, 140075620679680, 140075620696063,
-STORE, 140075620724736, 140075620728831,
-STORE, 140075620728832, 140075620732927,
-STORE, 140075620732928, 140075620737023,
-STORE, 140720830312448, 140720830451711,
-STORE, 140720830631936, 140720830644223,
-STORE, 140720830644224, 140720830648319,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735116226560, 140737488351231,
-SNULL, 140735116234751, 140737488351231,
-STORE, 140735116226560, 140735116234751,
-STORE, 140735116095488, 140735116234751,
-STORE, 94873398054912, 94873400279039,
-SNULL, 94873398165503, 94873400279039,
-STORE, 94873398054912, 94873398165503,
-STORE, 94873398165504, 94873400279039,
-ERASE, 94873398165504, 94873400279039,
-STORE, 94873400258560, 94873400270847,
-STORE, 94873400270848, 94873400279039,
-STORE, 140303828606976, 140303830859775,
-SNULL, 140303828750335, 140303830859775,
-STORE, 140303828606976, 140303828750335,
-STORE, 140303828750336, 140303830859775,
-ERASE, 140303828750336, 140303830859775,
-STORE, 140303830847488, 140303830855679,
-STORE, 140303830855680, 140303830859775,
-STORE, 140735116251136, 140735116255231,
-STORE, 140735116238848, 140735116251135,
-STORE, 140303830818816, 140303830847487,
-STORE, 140303830810624, 140303830818815,
-STORE, 140303824809984, 140303828606975,
-SNULL, 140303824809984, 140303826468863,
-STORE, 140303826468864, 140303828606975,
-STORE, 140303824809984, 140303826468863,
-SNULL, 140303828566015, 140303828606975,
-STORE, 140303826468864, 140303828566015,
-STORE, 140303828566016, 140303828606975,
-SNULL, 140303828566016, 140303828590591,
-STORE, 140303828590592, 140303828606975,
-STORE, 140303828566016, 140303828590591,
-ERASE, 140303828566016, 140303828590591,
-STORE, 140303828566016, 140303828590591,
-ERASE, 140303828590592, 140303828606975,
-STORE, 140303828590592, 140303828606975,
-SNULL, 140303828582399, 140303828590591,
-STORE, 140303828566016, 140303828582399,
-STORE, 140303828582400, 140303828590591,
-SNULL, 94873400266751, 94873400270847,
-STORE, 94873400258560, 94873400266751,
-STORE, 94873400266752, 94873400270847,
-SNULL, 140303830851583, 140303830855679,
-STORE, 140303830847488, 140303830851583,
-STORE, 140303830851584, 140303830855679,
-ERASE, 140303830818816, 140303830847487,
-STORE, 94873413713920, 94873413849087,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140732349956096, 140737488351231,
-SNULL, 140732349964287, 140737488351231,
-STORE, 140732349956096, 140732349964287,
-STORE, 140732349825024, 140732349964287,
-STORE, 94009652736000, 94009655070719,
-SNULL, 94009652948991, 94009655070719,
-STORE, 94009652736000, 94009652948991,
-STORE, 94009652948992, 94009655070719,
-ERASE, 94009652948992, 94009655070719,
-STORE, 94009655046144, 94009655058431,
-STORE, 94009655058432, 94009655070719,
-STORE, 140295688531968, 140295690784767,
-SNULL, 140295688675327, 140295690784767,
-STORE, 140295688531968, 140295688675327,
-STORE, 140295688675328, 140295690784767,
-ERASE, 140295688675328, 140295690784767,
-STORE, 140295690772480, 140295690780671,
-STORE, 140295690780672, 140295690784767,
-STORE, 140732350005248, 140732350009343,
-STORE, 140732349992960, 140732350005247,
-STORE, 140295690743808, 140295690772479,
-STORE, 140295690735616, 140295690743807,
-STORE, 140295686418432, 140295688531967,
-SNULL, 140295686418432, 140295686430719,
-STORE, 140295686430720, 140295688531967,
-STORE, 140295686418432, 140295686430719,
-SNULL, 140295688523775, 140295688531967,
-STORE, 140295686430720, 140295688523775,
-STORE, 140295688523776, 140295688531967,
-ERASE, 140295688523776, 140295688531967,
-STORE, 140295688523776, 140295688531967,
-STORE, 140295682621440, 140295686418431,
-SNULL, 140295682621440, 140295684280319,
-STORE, 140295684280320, 140295686418431,
-STORE, 140295682621440, 140295684280319,
-SNULL, 140295686377471, 140295686418431,
-STORE, 140295684280320, 140295686377471,
-STORE, 140295686377472, 140295686418431,
-SNULL, 140295686377472, 140295686402047,
-STORE, 140295686402048, 140295686418431,
-STORE, 140295686377472, 140295686402047,
-ERASE, 140295686377472, 140295686402047,
-STORE, 140295686377472, 140295686402047,
-ERASE, 140295686402048, 140295686418431,
-STORE, 140295686402048, 140295686418431,
-STORE, 140295690727424, 140295690743807,
-SNULL, 140295686393855, 140295686402047,
-STORE, 140295686377472, 140295686393855,
-STORE, 140295686393856, 140295686402047,
-SNULL, 140295688527871, 140295688531967,
-STORE, 140295688523776, 140295688527871,
-STORE, 140295688527872, 140295688531967,
-SNULL, 94009655050239, 94009655058431,
-STORE, 94009655046144, 94009655050239,
-STORE, 94009655050240, 94009655058431,
-SNULL, 140295690776575, 140295690780671,
-STORE, 140295690772480, 140295690776575,
-STORE, 140295690776576, 140295690780671,
-ERASE, 140295690743808, 140295690772479,
-STORE, 94009672114176, 94009672249343,
-STORE, 140295689043968, 140295690727423,
-STORE, 94009672114176, 94009672384511,
-STORE, 94009672114176, 94009672519679,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722376515584, 140737488351231,
-SNULL, 140722376523775, 140737488351231,
-STORE, 140722376515584, 140722376523775,
-STORE, 140722376384512, 140722376523775,
-STORE, 94089815773184, 94089818107903,
-SNULL, 94089815986175, 94089818107903,
-STORE, 94089815773184, 94089815986175,
-STORE, 94089815986176, 94089818107903,
-ERASE, 94089815986176, 94089818107903,
-STORE, 94089818083328, 94089818095615,
-STORE, 94089818095616, 94089818107903,
-STORE, 140265595711488, 140265597964287,
-SNULL, 140265595854847, 140265597964287,
-STORE, 140265595711488, 140265595854847,
-STORE, 140265595854848, 140265597964287,
-ERASE, 140265595854848, 140265597964287,
-STORE, 140265597952000, 140265597960191,
-STORE, 140265597960192, 140265597964287,
-STORE, 140722378297344, 140722378301439,
-STORE, 140722378285056, 140722378297343,
-STORE, 140265597923328, 140265597951999,
-STORE, 140265597915136, 140265597923327,
-STORE, 140265593597952, 140265595711487,
-SNULL, 140265593597952, 140265593610239,
-STORE, 140265593610240, 140265595711487,
-STORE, 140265593597952, 140265593610239,
-SNULL, 140265595703295, 140265595711487,
-STORE, 140265593610240, 140265595703295,
-STORE, 140265595703296, 140265595711487,
-ERASE, 140265595703296, 140265595711487,
-STORE, 140265595703296, 140265595711487,
-STORE, 140265589800960, 140265593597951,
-SNULL, 140265589800960, 140265591459839,
-STORE, 140265591459840, 140265593597951,
-STORE, 140265589800960, 140265591459839,
-SNULL, 140265593556991, 140265593597951,
-STORE, 140265591459840, 140265593556991,
-STORE, 140265593556992, 140265593597951,
-SNULL, 140265593556992, 140265593581567,
-STORE, 140265593581568, 140265593597951,
-STORE, 140265593556992, 140265593581567,
-ERASE, 140265593556992, 140265593581567,
-STORE, 140265593556992, 140265593581567,
-ERASE, 140265593581568, 140265593597951,
-STORE, 140265593581568, 140265593597951,
-STORE, 140265597906944, 140265597923327,
-SNULL, 140265593573375, 140265593581567,
-STORE, 140265593556992, 140265593573375,
-STORE, 140265593573376, 140265593581567,
-SNULL, 140265595707391, 140265595711487,
-STORE, 140265595703296, 140265595707391,
-STORE, 140265595707392, 140265595711487,
-SNULL, 94089818087423, 94089818095615,
-STORE, 94089818083328, 94089818087423,
-STORE, 94089818087424, 94089818095615,
-SNULL, 140265597956095, 140265597960191,
-STORE, 140265597952000, 140265597956095,
-STORE, 140265597956096, 140265597960191,
-ERASE, 140265597923328, 140265597951999,
-STORE, 94089837146112, 94089837281279,
-STORE, 140265596223488, 140265597906943,
-STORE, 94089837146112, 94089837416447,
-STORE, 94089837146112, 94089837551615,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735265218560, 140737488351231,
-SNULL, 140735265226751, 140737488351231,
-STORE, 140735265218560, 140735265226751,
-STORE, 140735265087488, 140735265226751,
-STORE, 94250422370304, 94250424705023,
-SNULL, 94250422583295, 94250424705023,
-STORE, 94250422370304, 94250422583295,
-STORE, 94250422583296, 94250424705023,
-ERASE, 94250422583296, 94250424705023,
-STORE, 94250424680448, 94250424692735,
-STORE, 94250424692736, 94250424705023,
-STORE, 140344442474496, 140344444727295,
-SNULL, 140344442617855, 140344444727295,
-STORE, 140344442474496, 140344442617855,
-STORE, 140344442617856, 140344444727295,
-ERASE, 140344442617856, 140344444727295,
-STORE, 140344444715008, 140344444723199,
-STORE, 140344444723200, 140344444727295,
-STORE, 140735265341440, 140735265345535,
-STORE, 140735265329152, 140735265341439,
-STORE, 140344444686336, 140344444715007,
-STORE, 140344444678144, 140344444686335,
-STORE, 140344440360960, 140344442474495,
-SNULL, 140344440360960, 140344440373247,
-STORE, 140344440373248, 140344442474495,
-STORE, 140344440360960, 140344440373247,
-SNULL, 140344442466303, 140344442474495,
-STORE, 140344440373248, 140344442466303,
-STORE, 140344442466304, 140344442474495,
-ERASE, 140344442466304, 140344442474495,
-STORE, 140344442466304, 140344442474495,
-STORE, 140344436563968, 140344440360959,
-SNULL, 140344436563968, 140344438222847,
-STORE, 140344438222848, 140344440360959,
-STORE, 140344436563968, 140344438222847,
-SNULL, 140344440319999, 140344440360959,
-STORE, 140344438222848, 140344440319999,
-STORE, 140344440320000, 140344440360959,
-SNULL, 140344440320000, 140344440344575,
-STORE, 140344440344576, 140344440360959,
-STORE, 140344440320000, 140344440344575,
-ERASE, 140344440320000, 140344440344575,
-STORE, 140344440320000, 140344440344575,
-ERASE, 140344440344576, 140344440360959,
-STORE, 140344440344576, 140344440360959,
-STORE, 140344444669952, 140344444686335,
-SNULL, 140344440336383, 140344440344575,
-STORE, 140344440320000, 140344440336383,
-STORE, 140344440336384, 140344440344575,
-SNULL, 140344442470399, 140344442474495,
-STORE, 140344442466304, 140344442470399,
-STORE, 140344442470400, 140344442474495,
-SNULL, 94250424684543, 94250424692735,
-STORE, 94250424680448, 94250424684543,
-STORE, 94250424684544, 94250424692735,
-SNULL, 140344444719103, 140344444723199,
-STORE, 140344444715008, 140344444719103,
-STORE, 140344444719104, 140344444723199,
-ERASE, 140344444686336, 140344444715007,
-STORE, 94250445512704, 94250445647871,
-STORE, 140344442986496, 140344444669951,
-STORE, 94250445512704, 94250445783039,
-STORE, 94250445512704, 94250445918207,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725762719744, 140737488351231,
-SNULL, 140725762727935, 140737488351231,
-STORE, 140725762719744, 140725762727935,
-STORE, 140725762588672, 140725762727935,
-STORE, 94819009097728, 94819011432447,
-SNULL, 94819009310719, 94819011432447,
-STORE, 94819009097728, 94819009310719,
-STORE, 94819009310720, 94819011432447,
-ERASE, 94819009310720, 94819011432447,
-STORE, 94819011407872, 94819011420159,
-STORE, 94819011420160, 94819011432447,
-STORE, 139987985596416, 139987987849215,
-SNULL, 139987985739775, 139987987849215,
-STORE, 139987985596416, 139987985739775,
-STORE, 139987985739776, 139987987849215,
-ERASE, 139987985739776, 139987987849215,
-STORE, 139987987836928, 139987987845119,
-STORE, 139987987845120, 139987987849215,
-STORE, 140725763072000, 140725763076095,
-STORE, 140725763059712, 140725763071999,
-STORE, 139987987808256, 139987987836927,
-STORE, 139987987800064, 139987987808255,
-STORE, 139987983482880, 139987985596415,
-SNULL, 139987983482880, 139987983495167,
-STORE, 139987983495168, 139987985596415,
-STORE, 139987983482880, 139987983495167,
-SNULL, 139987985588223, 139987985596415,
-STORE, 139987983495168, 139987985588223,
-STORE, 139987985588224, 139987985596415,
-ERASE, 139987985588224, 139987985596415,
-STORE, 139987985588224, 139987985596415,
-STORE, 139987979685888, 139987983482879,
-SNULL, 139987979685888, 139987981344767,
-STORE, 139987981344768, 139987983482879,
-STORE, 139987979685888, 139987981344767,
-SNULL, 139987983441919, 139987983482879,
-STORE, 139987981344768, 139987983441919,
-STORE, 139987983441920, 139987983482879,
-SNULL, 139987983441920, 139987983466495,
-STORE, 139987983466496, 139987983482879,
-STORE, 139987983441920, 139987983466495,
-ERASE, 139987983441920, 139987983466495,
-STORE, 139987983441920, 139987983466495,
-ERASE, 139987983466496, 139987983482879,
-STORE, 139987983466496, 139987983482879,
-STORE, 139987987791872, 139987987808255,
-SNULL, 139987983458303, 139987983466495,
-STORE, 139987983441920, 139987983458303,
-STORE, 139987983458304, 139987983466495,
-SNULL, 139987985592319, 139987985596415,
-STORE, 139987985588224, 139987985592319,
-STORE, 139987985592320, 139987985596415,
-SNULL, 94819011411967, 94819011420159,
-STORE, 94819011407872, 94819011411967,
-STORE, 94819011411968, 94819011420159,
-SNULL, 139987987841023, 139987987845119,
-STORE, 139987987836928, 139987987841023,
-STORE, 139987987841024, 139987987845119,
-ERASE, 139987987808256, 139987987836927,
-STORE, 94819028176896, 94819028312063,
-STORE, 139987986108416, 139987987791871,
-STORE, 94819028176896, 94819028447231,
-STORE, 94819028176896, 94819028582399,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722475413504, 140737488351231,
-SNULL, 140722475421695, 140737488351231,
-STORE, 140722475413504, 140722475421695,
-STORE, 140722475282432, 140722475421695,
-STORE, 94620599119872, 94620601343999,
-SNULL, 94620599230463, 94620601343999,
-STORE, 94620599119872, 94620599230463,
-STORE, 94620599230464, 94620601343999,
-ERASE, 94620599230464, 94620601343999,
-STORE, 94620601323520, 94620601335807,
-STORE, 94620601335808, 94620601343999,
-STORE, 139891763060736, 139891765313535,
-SNULL, 139891763204095, 139891765313535,
-STORE, 139891763060736, 139891763204095,
-STORE, 139891763204096, 139891765313535,
-ERASE, 139891763204096, 139891765313535,
-STORE, 139891765301248, 139891765309439,
-STORE, 139891765309440, 139891765313535,
-STORE, 140722475700224, 140722475704319,
-STORE, 140722475687936, 140722475700223,
-STORE, 139891765272576, 139891765301247,
-STORE, 139891765264384, 139891765272575,
-STORE, 139891759263744, 139891763060735,
-SNULL, 139891759263744, 139891760922623,
-STORE, 139891760922624, 139891763060735,
-STORE, 139891759263744, 139891760922623,
-SNULL, 139891763019775, 139891763060735,
-STORE, 139891760922624, 139891763019775,
-STORE, 139891763019776, 139891763060735,
-SNULL, 139891763019776, 139891763044351,
-STORE, 139891763044352, 139891763060735,
-STORE, 139891763019776, 139891763044351,
-ERASE, 139891763019776, 139891763044351,
-STORE, 139891763019776, 139891763044351,
-ERASE, 139891763044352, 139891763060735,
-STORE, 139891763044352, 139891763060735,
-SNULL, 139891763036159, 139891763044351,
-STORE, 139891763019776, 139891763036159,
-STORE, 139891763036160, 139891763044351,
-SNULL, 94620601331711, 94620601335807,
-STORE, 94620601323520, 94620601331711,
-STORE, 94620601331712, 94620601335807,
-SNULL, 139891765305343, 139891765309439,
-STORE, 139891765301248, 139891765305343,
-STORE, 139891765305344, 139891765309439,
-ERASE, 139891765272576, 139891765301247,
-STORE, 94620610027520, 94620610162687,
-STORE, 94031976210432, 94031976423423,
-STORE, 94031978520576, 94031978524671,
-STORE, 94031978524672, 94031978532863,
-STORE, 94031978532864, 94031978545151,
-STORE, 94031990398976, 94031992565759,
-STORE, 140336240640000, 140336242298879,
-STORE, 140336242298880, 140336244396031,
-STORE, 140336244396032, 140336244412415,
-STORE, 140336244412416, 140336244420607,
-STORE, 140336244420608, 140336244436991,
-STORE, 140336244436992, 140336244449279,
-STORE, 140336244449280, 140336246542335,
-STORE, 140336246542336, 140336246546431,
-STORE, 140336246546432, 140336246550527,
-STORE, 140336246550528, 140336246693887,
-STORE, 140336247062528, 140336248745983,
-STORE, 140336248745984, 140336248762367,
-STORE, 140336248791040, 140336248795135,
-STORE, 140336248795136, 140336248799231,
-STORE, 140336248799232, 140336248803327,
-STORE, 140728500064256, 140728500203519,
-STORE, 140728501501952, 140728501514239,
-STORE, 140728501514240, 140728501518335,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140730503987200, 140737488351231,
-SNULL, 140730503995391, 140737488351231,
-STORE, 140730503987200, 140730503995391,
-STORE, 140730503856128, 140730503995391,
-STORE, 93866544205824, 93866546429951,
-SNULL, 93866544316415, 93866546429951,
-STORE, 93866544205824, 93866544316415,
-STORE, 93866544316416, 93866546429951,
-ERASE, 93866544316416, 93866546429951,
-STORE, 93866546409472, 93866546421759,
-STORE, 93866546421760, 93866546429951,
-STORE, 140216311959552, 140216314212351,
-SNULL, 140216312102911, 140216314212351,
-STORE, 140216311959552, 140216312102911,
-STORE, 140216312102912, 140216314212351,
-ERASE, 140216312102912, 140216314212351,
-STORE, 140216314200064, 140216314208255,
-STORE, 140216314208256, 140216314212351,
-STORE, 140730504626176, 140730504630271,
-STORE, 140730504613888, 140730504626175,
-STORE, 140216314171392, 140216314200063,
-STORE, 140216314163200, 140216314171391,
-STORE, 140216308162560, 140216311959551,
-SNULL, 140216308162560, 140216309821439,
-STORE, 140216309821440, 140216311959551,
-STORE, 140216308162560, 140216309821439,
-SNULL, 140216311918591, 140216311959551,
-STORE, 140216309821440, 140216311918591,
-STORE, 140216311918592, 140216311959551,
-SNULL, 140216311918592, 140216311943167,
-STORE, 140216311943168, 140216311959551,
-STORE, 140216311918592, 140216311943167,
-ERASE, 140216311918592, 140216311943167,
-STORE, 140216311918592, 140216311943167,
-ERASE, 140216311943168, 140216311959551,
-STORE, 140216311943168, 140216311959551,
-SNULL, 140216311934975, 140216311943167,
-STORE, 140216311918592, 140216311934975,
-STORE, 140216311934976, 140216311943167,
-SNULL, 93866546417663, 93866546421759,
-STORE, 93866546409472, 93866546417663,
-STORE, 93866546417664, 93866546421759,
-SNULL, 140216314204159, 140216314208255,
-STORE, 140216314200064, 140216314204159,
-STORE, 140216314204160, 140216314208255,
-ERASE, 140216314171392, 140216314200063,
-STORE, 93866550386688, 93866550521855,
-STORE, 94074292674560, 94074292887551,
-STORE, 94074294984704, 94074294988799,
-STORE, 94074294988800, 94074294996991,
-STORE, 94074294996992, 94074295009279,
-STORE, 94074300219392, 94074301378559,
-STORE, 139781563256832, 139781564915711,
-STORE, 139781564915712, 139781567012863,
-STORE, 139781567012864, 139781567029247,
-STORE, 139781567029248, 139781567037439,
-STORE, 139781567037440, 139781567053823,
-STORE, 139781567053824, 139781567066111,
-STORE, 139781567066112, 139781569159167,
-STORE, 139781569159168, 139781569163263,
-STORE, 139781569163264, 139781569167359,
-STORE, 139781569167360, 139781569310719,
-STORE, 139781569679360, 139781571362815,
-STORE, 139781571362816, 139781571379199,
-STORE, 139781571407872, 139781571411967,
-STORE, 139781571411968, 139781571416063,
-STORE, 139781571416064, 139781571420159,
-STORE, 140723688488960, 140723688628223,
-STORE, 140723689005056, 140723689017343,
-STORE, 140723689017344, 140723689021439,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735189745664, 140737488351231,
-SNULL, 140735189753855, 140737488351231,
-STORE, 140735189745664, 140735189753855,
-STORE, 140735189614592, 140735189753855,
-STORE, 94172072177664, 94172074512383,
-SNULL, 94172072390655, 94172074512383,
-STORE, 94172072177664, 94172072390655,
-STORE, 94172072390656, 94172074512383,
-ERASE, 94172072390656, 94172074512383,
-STORE, 94172074487808, 94172074500095,
-STORE, 94172074500096, 94172074512383,
-STORE, 140687827263488, 140687829516287,
-SNULL, 140687827406847, 140687829516287,
-STORE, 140687827263488, 140687827406847,
-STORE, 140687827406848, 140687829516287,
-ERASE, 140687827406848, 140687829516287,
-STORE, 140687829504000, 140687829512191,
-STORE, 140687829512192, 140687829516287,
-STORE, 140735189766144, 140735189770239,
-STORE, 140735189753856, 140735189766143,
-STORE, 140687829475328, 140687829503999,
-STORE, 140687829467136, 140687829475327,
-STORE, 140687825149952, 140687827263487,
-SNULL, 140687825149952, 140687825162239,
-STORE, 140687825162240, 140687827263487,
-STORE, 140687825149952, 140687825162239,
-SNULL, 140687827255295, 140687827263487,
-STORE, 140687825162240, 140687827255295,
-STORE, 140687827255296, 140687827263487,
-ERASE, 140687827255296, 140687827263487,
-STORE, 140687827255296, 140687827263487,
-STORE, 140687821352960, 140687825149951,
-SNULL, 140687821352960, 140687823011839,
-STORE, 140687823011840, 140687825149951,
-STORE, 140687821352960, 140687823011839,
-SNULL, 140687825108991, 140687825149951,
-STORE, 140687823011840, 140687825108991,
-STORE, 140687825108992, 140687825149951,
-SNULL, 140687825108992, 140687825133567,
-STORE, 140687825133568, 140687825149951,
-STORE, 140687825108992, 140687825133567,
-ERASE, 140687825108992, 140687825133567,
-STORE, 140687825108992, 140687825133567,
-ERASE, 140687825133568, 140687825149951,
-STORE, 140687825133568, 140687825149951,
-STORE, 140687829458944, 140687829475327,
-SNULL, 140687825125375, 140687825133567,
-STORE, 140687825108992, 140687825125375,
-STORE, 140687825125376, 140687825133567,
-SNULL, 140687827259391, 140687827263487,
-STORE, 140687827255296, 140687827259391,
-STORE, 140687827259392, 140687827263487,
-SNULL, 94172074491903, 94172074500095,
-STORE, 94172074487808, 94172074491903,
-STORE, 94172074491904, 94172074500095,
-SNULL, 140687829508095, 140687829512191,
-STORE, 140687829504000, 140687829508095,
-STORE, 140687829508096, 140687829512191,
-ERASE, 140687829475328, 140687829503999,
-STORE, 94172092432384, 94172092567551,
-STORE, 140687827775488, 140687829458943,
-STORE, 94172092432384, 94172092702719,
-STORE, 94172092432384, 94172092837887,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140737229504512, 140737488351231,
-SNULL, 140737229512703, 140737488351231,
-STORE, 140737229504512, 140737229512703,
-STORE, 140737229373440, 140737229512703,
-STORE, 94155246866432, 94155249090559,
-SNULL, 94155246977023, 94155249090559,
-STORE, 94155246866432, 94155246977023,
-STORE, 94155246977024, 94155249090559,
-ERASE, 94155246977024, 94155249090559,
-STORE, 94155249070080, 94155249082367,
-STORE, 94155249082368, 94155249090559,
-STORE, 140640993693696, 140640995946495,
-SNULL, 140640993837055, 140640995946495,
-STORE, 140640993693696, 140640993837055,
-STORE, 140640993837056, 140640995946495,
-ERASE, 140640993837056, 140640995946495,
-STORE, 140640995934208, 140640995942399,
-STORE, 140640995942400, 140640995946495,
-STORE, 140737230004224, 140737230008319,
-STORE, 140737229991936, 140737230004223,
-STORE, 140640995905536, 140640995934207,
-STORE, 140640995897344, 140640995905535,
-STORE, 140640989896704, 140640993693695,
-SNULL, 140640989896704, 140640991555583,
-STORE, 140640991555584, 140640993693695,
-STORE, 140640989896704, 140640991555583,
-SNULL, 140640993652735, 140640993693695,
-STORE, 140640991555584, 140640993652735,
-STORE, 140640993652736, 140640993693695,
-SNULL, 140640993652736, 140640993677311,
-STORE, 140640993677312, 140640993693695,
-STORE, 140640993652736, 140640993677311,
-ERASE, 140640993652736, 140640993677311,
-STORE, 140640993652736, 140640993677311,
-ERASE, 140640993677312, 140640993693695,
-STORE, 140640993677312, 140640993693695,
-SNULL, 140640993669119, 140640993677311,
-STORE, 140640993652736, 140640993669119,
-STORE, 140640993669120, 140640993677311,
-SNULL, 94155249078271, 94155249082367,
-STORE, 94155249070080, 94155249078271,
-STORE, 94155249078272, 94155249082367,
-SNULL, 140640995938303, 140640995942399,
-STORE, 140640995934208, 140640995938303,
-STORE, 140640995938304, 140640995942399,
-ERASE, 140640995905536, 140640995934207,
-STORE, 94155281035264, 94155281170431,
-STORE, 94088066453504, 94088066564095,
-STORE, 94088068657152, 94088068665343,
-STORE, 94088068665344, 94088068669439,
-STORE, 94088068669440, 94088068677631,
-STORE, 94088090214400, 94088090349567,
-STORE, 140503024627712, 140503026286591,
-STORE, 140503026286592, 140503028383743,
-STORE, 140503028383744, 140503028400127,
-STORE, 140503028400128, 140503028408319,
-STORE, 140503028408320, 140503028424703,
-STORE, 140503028424704, 140503028568063,
-STORE, 140503030628352, 140503030636543,
-STORE, 140503030665216, 140503030669311,
-STORE, 140503030669312, 140503030673407,
-STORE, 140503030673408, 140503030677503,
-STORE, 140730894725120, 140730894864383,
-STORE, 140730894880768, 140730894893055,
-STORE, 140730894893056, 140730894897151,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140730434342912, 140737488351231,
-SNULL, 140730434351103, 140737488351231,
-STORE, 140730434342912, 140730434351103,
-STORE, 140730434211840, 140730434351103,
-STORE, 4194304, 5128191,
-STORE, 7221248, 7241727,
-STORE, 7241728, 7249919,
-STORE, 140109041938432, 140109044191231,
-SNULL, 140109042081791, 140109044191231,
-STORE, 140109041938432, 140109042081791,
-STORE, 140109042081792, 140109044191231,
-ERASE, 140109042081792, 140109044191231,
-STORE, 140109044178944, 140109044187135,
-STORE, 140109044187136, 140109044191231,
-STORE, 140730434850816, 140730434854911,
-STORE, 140730434838528, 140730434850815,
-STORE, 140109044150272, 140109044178943,
-STORE, 140109044142080, 140109044150271,
-STORE, 140109038776320, 140109041938431,
-SNULL, 140109038776320, 140109039837183,
-STORE, 140109039837184, 140109041938431,
-STORE, 140109038776320, 140109039837183,
-SNULL, 140109041930239, 140109041938431,
-STORE, 140109039837184, 140109041930239,
-STORE, 140109041930240, 140109041938431,
-ERASE, 140109041930240, 140109041938431,
-STORE, 140109041930240, 140109041938431,
-STORE, 140109034979328, 140109038776319,
-SNULL, 140109034979328, 140109036638207,
-STORE, 140109036638208, 140109038776319,
-STORE, 140109034979328, 140109036638207,
-SNULL, 140109038735359, 140109038776319,
-STORE, 140109036638208, 140109038735359,
-STORE, 140109038735360, 140109038776319,
-SNULL, 140109038735360, 140109038759935,
-STORE, 140109038759936, 140109038776319,
-STORE, 140109038735360, 140109038759935,
-ERASE, 140109038735360, 140109038759935,
-STORE, 140109038735360, 140109038759935,
-ERASE, 140109038759936, 140109038776319,
-STORE, 140109038759936, 140109038776319,
-STORE, 140109044129792, 140109044150271,
-SNULL, 140109038751743, 140109038759935,
-STORE, 140109038735360, 140109038751743,
-STORE, 140109038751744, 140109038759935,
-SNULL, 140109041934335, 140109041938431,
-STORE, 140109041930240, 140109041934335,
-STORE, 140109041934336, 140109041938431,
-SNULL, 7233535, 7241727,
-STORE, 7221248, 7233535,
-STORE, 7233536, 7241727,
-SNULL, 140109044183039, 140109044187135,
-STORE, 140109044178944, 140109044183039,
-STORE, 140109044183040, 140109044187135,
-ERASE, 140109044150272, 140109044178943,
-STORE, 20000768, 20135935,
-STORE, 20000768, 20283391,
-STORE, 140109042446336, 140109044129791,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140730853408768, 140737488351231,
-SNULL, 140730853416959, 140737488351231,
-STORE, 140730853408768, 140730853416959,
-STORE, 140730853277696, 140730853416959,
-STORE, 94865902977024, 94865905311743,
-SNULL, 94865903190015, 94865905311743,
-STORE, 94865902977024, 94865903190015,
-STORE, 94865903190016, 94865905311743,
-ERASE, 94865903190016, 94865905311743,
-STORE, 94865905287168, 94865905299455,
-STORE, 94865905299456, 94865905311743,
-STORE, 139768865738752, 139768867991551,
-SNULL, 139768865882111, 139768867991551,
-STORE, 139768865738752, 139768865882111,
-STORE, 139768865882112, 139768867991551,
-ERASE, 139768865882112, 139768867991551,
-STORE, 139768867979264, 139768867987455,
-STORE, 139768867987456, 139768867991551,
-STORE, 140730853957632, 140730853961727,
-STORE, 140730853945344, 140730853957631,
-STORE, 139768867950592, 139768867979263,
-STORE, 139768867942400, 139768867950591,
-STORE, 139768863625216, 139768865738751,
-SNULL, 139768863625216, 139768863637503,
-STORE, 139768863637504, 139768865738751,
-STORE, 139768863625216, 139768863637503,
-SNULL, 139768865730559, 139768865738751,
-STORE, 139768863637504, 139768865730559,
-STORE, 139768865730560, 139768865738751,
-ERASE, 139768865730560, 139768865738751,
-STORE, 139768865730560, 139768865738751,
-STORE, 139768859828224, 139768863625215,
-SNULL, 139768859828224, 139768861487103,
-STORE, 139768861487104, 139768863625215,
-STORE, 139768859828224, 139768861487103,
-SNULL, 139768863584255, 139768863625215,
-STORE, 139768861487104, 139768863584255,
-STORE, 139768863584256, 139768863625215,
-SNULL, 139768863584256, 139768863608831,
-STORE, 139768863608832, 139768863625215,
-STORE, 139768863584256, 139768863608831,
-ERASE, 139768863584256, 139768863608831,
-STORE, 139768863584256, 139768863608831,
-ERASE, 139768863608832, 139768863625215,
-STORE, 139768863608832, 139768863625215,
-STORE, 139768867934208, 139768867950591,
-SNULL, 139768863600639, 139768863608831,
-STORE, 139768863584256, 139768863600639,
-STORE, 139768863600640, 139768863608831,
-SNULL, 139768865734655, 139768865738751,
-STORE, 139768865730560, 139768865734655,
-STORE, 139768865734656, 139768865738751,
-SNULL, 94865905291263, 94865905299455,
-STORE, 94865905287168, 94865905291263,
-STORE, 94865905291264, 94865905299455,
-SNULL, 139768867983359, 139768867987455,
-STORE, 139768867979264, 139768867983359,
-STORE, 139768867983360, 139768867987455,
-ERASE, 139768867950592, 139768867979263,
-STORE, 94865923670016, 94865923805183,
-STORE, 139768866250752, 139768867934207,
-STORE, 94865923670016, 94865923940351,
-STORE, 94865923670016, 94865924075519,
-STORE, 94865923670016, 94865924222975,
-SNULL, 94865924210687, 94865924222975,
-STORE, 94865923670016, 94865924210687,
-STORE, 94865924210688, 94865924222975,
-ERASE, 94865924210688, 94865924222975,
-STORE, 94865923670016, 94865924349951,
-STORE, 94865923670016, 94865924493311,
-STORE, 94865923670016, 94865924640767,
-SNULL, 94865924603903, 94865924640767,
-STORE, 94865923670016, 94865924603903,
-STORE, 94865924603904, 94865924640767,
-ERASE, 94865924603904, 94865924640767,
-STORE, 94865923670016, 94865924747263,
-STORE, 94865923670016, 94865924898815,
-SNULL, 94865924874239, 94865924898815,
-STORE, 94865923670016, 94865924874239,
-STORE, 94865924874240, 94865924898815,
-ERASE, 94865924874240, 94865924898815,
-STORE, 94865923670016, 94865925025791,
-SNULL, 94865925013503, 94865925025791,
-STORE, 94865923670016, 94865925013503,
-STORE, 94865925013504, 94865925025791,
-ERASE, 94865925013504, 94865925025791,
-SNULL, 94865924988927, 94865925013503,
-STORE, 94865923670016, 94865924988927,
-STORE, 94865924988928, 94865925013503,
-ERASE, 94865924988928, 94865925013503,
-STORE, 94865923670016, 94865925152767,
-SNULL, 94865925136383, 94865925152767,
-STORE, 94865923670016, 94865925136383,
-STORE, 94865925136384, 94865925152767,
-ERASE, 94865925136384, 94865925152767,
-STORE, 94865923670016, 94865925292031,
-SNULL, 94865925279743, 94865925292031,
-STORE, 94865923670016, 94865925279743,
-STORE, 94865925279744, 94865925292031,
-ERASE, 94865925279744, 94865925292031,
-SNULL, 94865925255167, 94865925279743,
-STORE, 94865923670016, 94865925255167,
-STORE, 94865925255168, 94865925279743,
-ERASE, 94865925255168, 94865925279743,
-STORE, 94865923670016, 94865925406719,
-SNULL, 94865925394431, 94865925406719,
-STORE, 94865923670016, 94865925394431,
-STORE, 94865925394432, 94865925406719,
-ERASE, 94865925394432, 94865925406719,
-STORE, 94865923670016, 94865925545983,
-SNULL, 94865925533695, 94865925545983,
-STORE, 94865923670016, 94865925533695,
-STORE, 94865925533696, 94865925545983,
-ERASE, 94865925533696, 94865925545983,
-SNULL, 94865925492735, 94865925533695,
-STORE, 94865923670016, 94865925492735,
-STORE, 94865925492736, 94865925533695,
-ERASE, 94865925492736, 94865925533695,
-STORE, 94865923670016, 94865925627903,
-SNULL, 94865925599231, 94865925627903,
-STORE, 94865923670016, 94865925599231,
-STORE, 94865925599232, 94865925627903,
-ERASE, 94865925599232, 94865925627903,
-STORE, 94865923670016, 94865925738495,
-SNULL, 94865925726207, 94865925738495,
-STORE, 94865923670016, 94865925726207,
-STORE, 94865925726208, 94865925738495,
-ERASE, 94865925726208, 94865925738495,
-STORE, 94865923670016, 94865925877759,
-SNULL, 94865925865471, 94865925877759,
-STORE, 94865923670016, 94865925865471,
-STORE, 94865925865472, 94865925877759,
-ERASE, 94865925865472, 94865925877759,
-STORE, 94865923670016, 94865926021119,
-SNULL, 94865926008831, 94865926021119,
-STORE, 94865923670016, 94865926008831,
-STORE, 94865926008832, 94865926021119,
-ERASE, 94865926008832, 94865926021119,
-SNULL, 94865925971967, 94865926008831,
-STORE, 94865923670016, 94865925971967,
-STORE, 94865925971968, 94865926008831,
-ERASE, 94865925971968, 94865926008831,
-STORE, 94865923670016, 94865926115327,
-STORE, 94865923670016, 94865926254591,
-SNULL, 94865926246399, 94865926254591,
-STORE, 94865923670016, 94865926246399,
-STORE, 94865926246400, 94865926254591,
-ERASE, 94865926246400, 94865926254591,
-STORE, 94865923670016, 94865926385663,
-STORE, 94865923670016, 94865926537215,
-STORE, 94865923670016, 94865926672383,
-STORE, 94865923670016, 94865926815743,
-STORE, 94865923670016, 94865926955007,
-STORE, 94865923670016, 94865927094271,
-STORE, 94865923670016, 94865927233535,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140731148435456, 140737488351231,
-SNULL, 140731148443647, 140737488351231,
-STORE, 140731148435456, 140731148443647,
-STORE, 140731148304384, 140731148443647,
-STORE, 94090775400448, 94090777735167,
-SNULL, 94090775613439, 94090777735167,
-STORE, 94090775400448, 94090775613439,
-STORE, 94090775613440, 94090777735167,
-ERASE, 94090775613440, 94090777735167,
-STORE, 94090777710592, 94090777722879,
-STORE, 94090777722880, 94090777735167,
-STORE, 140301090283520, 140301092536319,
-SNULL, 140301090426879, 140301092536319,
-STORE, 140301090283520, 140301090426879,
-STORE, 140301090426880, 140301092536319,
-ERASE, 140301090426880, 140301092536319,
-STORE, 140301092524032, 140301092532223,
-STORE, 140301092532224, 140301092536319,
-STORE, 140731148570624, 140731148574719,
-STORE, 140731148558336, 140731148570623,
-STORE, 140301092495360, 140301092524031,
-STORE, 140301092487168, 140301092495359,
-STORE, 140301088169984, 140301090283519,
-SNULL, 140301088169984, 140301088182271,
-STORE, 140301088182272, 140301090283519,
-STORE, 140301088169984, 140301088182271,
-SNULL, 140301090275327, 140301090283519,
-STORE, 140301088182272, 140301090275327,
-STORE, 140301090275328, 140301090283519,
-ERASE, 140301090275328, 140301090283519,
-STORE, 140301090275328, 140301090283519,
-STORE, 140301084372992, 140301088169983,
-SNULL, 140301084372992, 140301086031871,
-STORE, 140301086031872, 140301088169983,
-STORE, 140301084372992, 140301086031871,
-SNULL, 140301088129023, 140301088169983,
-STORE, 140301086031872, 140301088129023,
-STORE, 140301088129024, 140301088169983,
-SNULL, 140301088129024, 140301088153599,
-STORE, 140301088153600, 140301088169983,
-STORE, 140301088129024, 140301088153599,
-ERASE, 140301088129024, 140301088153599,
-STORE, 140301088129024, 140301088153599,
-ERASE, 140301088153600, 140301088169983,
-STORE, 140301088153600, 140301088169983,
-STORE, 140301092478976, 140301092495359,
-SNULL, 140301088145407, 140301088153599,
-STORE, 140301088129024, 140301088145407,
-STORE, 140301088145408, 140301088153599,
-SNULL, 140301090279423, 140301090283519,
-STORE, 140301090275328, 140301090279423,
-STORE, 140301090279424, 140301090283519,
-SNULL, 94090777714687, 94090777722879,
-STORE, 94090777710592, 94090777714687,
-STORE, 94090777714688, 94090777722879,
-SNULL, 140301092528127, 140301092532223,
-STORE, 140301092524032, 140301092528127,
-STORE, 140301092528128, 140301092532223,
-ERASE, 140301092495360, 140301092524031,
-STORE, 94090794590208, 94090794725375,
-STORE, 140301090795520, 140301092478975,
-STORE, 94090794590208, 94090794860543,
-STORE, 94090794590208, 94090794995711,
-STORE, 94090794590208, 94090795163647,
-SNULL, 94090795139071, 94090795163647,
-STORE, 94090794590208, 94090795139071,
-STORE, 94090795139072, 94090795163647,
-ERASE, 94090795139072, 94090795163647,
-STORE, 94090794590208, 94090795278335,
-STORE, 94090794590208, 94090795425791,
-SNULL, 94090795388927, 94090795425791,
-STORE, 94090794590208, 94090795388927,
-STORE, 94090795388928, 94090795425791,
-ERASE, 94090795388928, 94090795425791,
-STORE, 94090794590208, 94090795528191,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733084430336, 140737488351231,
-SNULL, 140733084438527, 140737488351231,
-STORE, 140733084430336, 140733084438527,
-STORE, 140733084299264, 140733084438527,
-STORE, 94116169183232, 94116171517951,
-SNULL, 94116169396223, 94116171517951,
-STORE, 94116169183232, 94116169396223,
-STORE, 94116169396224, 94116171517951,
-ERASE, 94116169396224, 94116171517951,
-STORE, 94116171493376, 94116171505663,
-STORE, 94116171505664, 94116171517951,
-STORE, 139772214128640, 139772216381439,
-SNULL, 139772214271999, 139772216381439,
-STORE, 139772214128640, 139772214271999,
-STORE, 139772214272000, 139772216381439,
-ERASE, 139772214272000, 139772216381439,
-STORE, 139772216369152, 139772216377343,
-STORE, 139772216377344, 139772216381439,
-STORE, 140733085270016, 140733085274111,
-STORE, 140733085257728, 140733085270015,
-STORE, 139772216340480, 139772216369151,
-STORE, 139772216332288, 139772216340479,
-STORE, 139772212015104, 139772214128639,
-SNULL, 139772212015104, 139772212027391,
-STORE, 139772212027392, 139772214128639,
-STORE, 139772212015104, 139772212027391,
-SNULL, 139772214120447, 139772214128639,
-STORE, 139772212027392, 139772214120447,
-STORE, 139772214120448, 139772214128639,
-ERASE, 139772214120448, 139772214128639,
-STORE, 139772214120448, 139772214128639,
-STORE, 139772208218112, 139772212015103,
-SNULL, 139772208218112, 139772209876991,
-STORE, 139772209876992, 139772212015103,
-STORE, 139772208218112, 139772209876991,
-SNULL, 139772211974143, 139772212015103,
-STORE, 139772209876992, 139772211974143,
-STORE, 139772211974144, 139772212015103,
-SNULL, 139772211974144, 139772211998719,
-STORE, 139772211998720, 139772212015103,
-STORE, 139772211974144, 139772211998719,
-ERASE, 139772211974144, 139772211998719,
-STORE, 139772211974144, 139772211998719,
-ERASE, 139772211998720, 139772212015103,
-STORE, 139772211998720, 139772212015103,
-STORE, 139772216324096, 139772216340479,
-SNULL, 139772211990527, 139772211998719,
-STORE, 139772211974144, 139772211990527,
-STORE, 139772211990528, 139772211998719,
-SNULL, 139772214124543, 139772214128639,
-STORE, 139772214120448, 139772214124543,
-STORE, 139772214124544, 139772214128639,
-SNULL, 94116171497471, 94116171505663,
-STORE, 94116171493376, 94116171497471,
-STORE, 94116171497472, 94116171505663,
-SNULL, 139772216373247, 139772216377343,
-STORE, 139772216369152, 139772216373247,
-STORE, 139772216373248, 139772216377343,
-ERASE, 139772216340480, 139772216369151,
-STORE, 94116199383040, 94116199518207,
-STORE, 139772214640640, 139772216324095,
-STORE, 94116199383040, 94116199653375,
-STORE, 94116199383040, 94116199788543,
-STORE, 140737488347136, 140737488351231,
-STORE, 140726067826688, 140737488351231,
-SNULL, 140726067830783, 140737488351231,
-STORE, 140726067826688, 140726067830783,
-STORE, 140726067695616, 140726067830783,
-STORE, 94535150673920, 94535152898047,
-SNULL, 94535150784511, 94535152898047,
-STORE, 94535150673920, 94535150784511,
-STORE, 94535150784512, 94535152898047,
-ERASE, 94535150784512, 94535152898047,
-STORE, 94535152877568, 94535152889855,
-STORE, 94535152889856, 94535152898047,
-STORE, 140381257314304, 140381259567103,
-SNULL, 140381257457663, 140381259567103,
-STORE, 140381257314304, 140381257457663,
-STORE, 140381257457664, 140381259567103,
-ERASE, 140381257457664, 140381259567103,
-STORE, 140381259554816, 140381259563007,
-STORE, 140381259563008, 140381259567103,
-STORE, 140726068060160, 140726068064255,
-STORE, 140726068047872, 140726068060159,
-STORE, 140381259526144, 140381259554815,
-STORE, 140381259517952, 140381259526143,
-STORE, 140381253517312, 140381257314303,
-SNULL, 140381253517312, 140381255176191,
-STORE, 140381255176192, 140381257314303,
-STORE, 140381253517312, 140381255176191,
-SNULL, 140381257273343, 140381257314303,
-STORE, 140381255176192, 140381257273343,
-STORE, 140381257273344, 140381257314303,
-SNULL, 140381257273344, 140381257297919,
-STORE, 140381257297920, 140381257314303,
-STORE, 140381257273344, 140381257297919,
-ERASE, 140381257273344, 140381257297919,
-STORE, 140381257273344, 140381257297919,
-ERASE, 140381257297920, 140381257314303,
-STORE, 140381257297920, 140381257314303,
-SNULL, 140381257289727, 140381257297919,
-STORE, 140381257273344, 140381257289727,
-STORE, 140381257289728, 140381257297919,
-SNULL, 94535152885759, 94535152889855,
-STORE, 94535152877568, 94535152885759,
-STORE, 94535152885760, 94535152889855,
-SNULL, 140381259558911, 140381259563007,
-STORE, 140381259554816, 140381259558911,
-STORE, 140381259558912, 140381259563007,
-ERASE, 140381259526144, 140381259554815,
-STORE, 94535186296832, 94535186431999,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140729189425152, 140737488351231,
-SNULL, 140729189433343, 140737488351231,
-STORE, 140729189425152, 140729189433343,
-STORE, 140729189294080, 140729189433343,
-STORE, 94428200128512, 94428202352639,
-SNULL, 94428200239103, 94428202352639,
-STORE, 94428200128512, 94428200239103,
-STORE, 94428200239104, 94428202352639,
-ERASE, 94428200239104, 94428202352639,
-STORE, 94428202332160, 94428202344447,
-STORE, 94428202344448, 94428202352639,
-STORE, 139707216986112, 139707219238911,
-SNULL, 139707217129471, 139707219238911,
-STORE, 139707216986112, 139707217129471,
-STORE, 139707217129472, 139707219238911,
-ERASE, 139707217129472, 139707219238911,
-STORE, 139707219226624, 139707219234815,
-STORE, 139707219234816, 139707219238911,
-STORE, 140729189785600, 140729189789695,
-STORE, 140729189773312, 140729189785599,
-STORE, 139707219197952, 139707219226623,
-STORE, 139707219189760, 139707219197951,
-STORE, 139707213189120, 139707216986111,
-SNULL, 139707213189120, 139707214847999,
-STORE, 139707214848000, 139707216986111,
-STORE, 139707213189120, 139707214847999,
-SNULL, 139707216945151, 139707216986111,
-STORE, 139707214848000, 139707216945151,
-STORE, 139707216945152, 139707216986111,
-SNULL, 139707216945152, 139707216969727,
-STORE, 139707216969728, 139707216986111,
-STORE, 139707216945152, 139707216969727,
-ERASE, 139707216945152, 139707216969727,
-STORE, 139707216945152, 139707216969727,
-ERASE, 139707216969728, 139707216986111,
-STORE, 139707216969728, 139707216986111,
-SNULL, 139707216961535, 139707216969727,
-STORE, 139707216945152, 139707216961535,
-STORE, 139707216961536, 139707216969727,
-SNULL, 94428202340351, 94428202344447,
-STORE, 94428202332160, 94428202340351,
-STORE, 94428202340352, 94428202344447,
-SNULL, 139707219230719, 139707219234815,
-STORE, 139707219226624, 139707219230719,
-STORE, 139707219230720, 139707219234815,
-ERASE, 139707219197952, 139707219226623,
-STORE, 94428208599040, 94428208734207,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722000953344, 140737488351231,
-SNULL, 140722000961535, 140737488351231,
-STORE, 140722000953344, 140722000961535,
-STORE, 140722000822272, 140722000961535,
-STORE, 94636494757888, 94636496982015,
-SNULL, 94636494868479, 94636496982015,
-STORE, 94636494757888, 94636494868479,
-STORE, 94636494868480, 94636496982015,
-ERASE, 94636494868480, 94636496982015,
-STORE, 94636496961536, 94636496973823,
-STORE, 94636496973824, 94636496982015,
-STORE, 140142275100672, 140142277353471,
-SNULL, 140142275244031, 140142277353471,
-STORE, 140142275100672, 140142275244031,
-STORE, 140142275244032, 140142277353471,
-ERASE, 140142275244032, 140142277353471,
-STORE, 140142277341184, 140142277349375,
-STORE, 140142277349376, 140142277353471,
-STORE, 140722002747392, 140722002751487,
-STORE, 140722002735104, 140722002747391,
-STORE, 140142277312512, 140142277341183,
-STORE, 140142277304320, 140142277312511,
-STORE, 140142271303680, 140142275100671,
-SNULL, 140142271303680, 140142272962559,
-STORE, 140142272962560, 140142275100671,
-STORE, 140142271303680, 140142272962559,
-SNULL, 140142275059711, 140142275100671,
-STORE, 140142272962560, 140142275059711,
-STORE, 140142275059712, 140142275100671,
-SNULL, 140142275059712, 140142275084287,
-STORE, 140142275084288, 140142275100671,
-STORE, 140142275059712, 140142275084287,
-ERASE, 140142275059712, 140142275084287,
-STORE, 140142275059712, 140142275084287,
-ERASE, 140142275084288, 140142275100671,
-STORE, 140142275084288, 140142275100671,
-SNULL, 140142275076095, 140142275084287,
-STORE, 140142275059712, 140142275076095,
-STORE, 140142275076096, 140142275084287,
-SNULL, 94636496969727, 94636496973823,
-STORE, 94636496961536, 94636496969727,
-STORE, 94636496969728, 94636496973823,
-SNULL, 140142277345279, 140142277349375,
-STORE, 140142277341184, 140142277345279,
-STORE, 140142277345280, 140142277349375,
-ERASE, 140142277312512, 140142277341183,
-STORE, 94636516286464, 94636516421631,
-STORE, 94071103692800, 94071103905791,
-STORE, 94071106002944, 94071106007039,
-STORE, 94071106007040, 94071106015231,
-STORE, 94071106015232, 94071106027519,
-STORE, 94071138521088, 94071140368383,
-STORE, 140145668190208, 140145669849087,
-STORE, 140145669849088, 140145671946239,
-STORE, 140145671946240, 140145671962623,
-STORE, 140145671962624, 140145671970815,
-STORE, 140145671970816, 140145671987199,
-STORE, 140145671987200, 140145671999487,
-STORE, 140145671999488, 140145674092543,
-STORE, 140145674092544, 140145674096639,
-STORE, 140145674096640, 140145674100735,
-STORE, 140145674100736, 140145674244095,
-STORE, 140145674612736, 140145676296191,
-STORE, 140145676296192, 140145676312575,
-STORE, 140145676341248, 140145676345343,
-STORE, 140145676345344, 140145676349439,
-STORE, 140145676349440, 140145676353535,
-STORE, 140734927740928, 140734927880191,
-STORE, 140734928842752, 140734928855039,
-STORE, 140734928855040, 140734928859135,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722342535168, 140737488351231,
-SNULL, 140722342543359, 140737488351231,
-STORE, 140722342535168, 140722342543359,
-STORE, 140722342404096, 140722342543359,
-STORE, 94399699714048, 94399702048767,
-SNULL, 94399699927039, 94399702048767,
-STORE, 94399699714048, 94399699927039,
-STORE, 94399699927040, 94399702048767,
-ERASE, 94399699927040, 94399702048767,
-STORE, 94399702024192, 94399702036479,
-STORE, 94399702036480, 94399702048767,
-STORE, 139811024748544, 139811027001343,
-SNULL, 139811024891903, 139811027001343,
-STORE, 139811024748544, 139811024891903,
-STORE, 139811024891904, 139811027001343,
-ERASE, 139811024891904, 139811027001343,
-STORE, 139811026989056, 139811026997247,
-STORE, 139811026997248, 139811027001343,
-STORE, 140722342707200, 140722342711295,
-STORE, 140722342694912, 140722342707199,
-STORE, 139811026960384, 139811026989055,
-STORE, 139811026952192, 139811026960383,
-STORE, 139811022635008, 139811024748543,
-SNULL, 139811022635008, 139811022647295,
-STORE, 139811022647296, 139811024748543,
-STORE, 139811022635008, 139811022647295,
-SNULL, 139811024740351, 139811024748543,
-STORE, 139811022647296, 139811024740351,
-STORE, 139811024740352, 139811024748543,
-ERASE, 139811024740352, 139811024748543,
-STORE, 139811024740352, 139811024748543,
-STORE, 139811018838016, 139811022635007,
-SNULL, 139811018838016, 139811020496895,
-STORE, 139811020496896, 139811022635007,
-STORE, 139811018838016, 139811020496895,
-SNULL, 139811022594047, 139811022635007,
-STORE, 139811020496896, 139811022594047,
-STORE, 139811022594048, 139811022635007,
-SNULL, 139811022594048, 139811022618623,
-STORE, 139811022618624, 139811022635007,
-STORE, 139811022594048, 139811022618623,
-ERASE, 139811022594048, 139811022618623,
-STORE, 139811022594048, 139811022618623,
-ERASE, 139811022618624, 139811022635007,
-STORE, 139811022618624, 139811022635007,
-STORE, 139811026944000, 139811026960383,
-SNULL, 139811022610431, 139811022618623,
-STORE, 139811022594048, 139811022610431,
-STORE, 139811022610432, 139811022618623,
-SNULL, 139811024744447, 139811024748543,
-STORE, 139811024740352, 139811024744447,
-STORE, 139811024744448, 139811024748543,
-SNULL, 94399702028287, 94399702036479,
-STORE, 94399702024192, 94399702028287,
-STORE, 94399702028288, 94399702036479,
-SNULL, 139811026993151, 139811026997247,
-STORE, 139811026989056, 139811026993151,
-STORE, 139811026993152, 139811026997247,
-ERASE, 139811026960384, 139811026989055,
-STORE, 94399723880448, 94399724015615,
-STORE, 139811025260544, 139811026943999,
-STORE, 94399723880448, 94399724150783,
-STORE, 94399723880448, 94399724285951,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140735364939776, 140737488351231,
-SNULL, 140735364947967, 140737488351231,
-STORE, 140735364939776, 140735364947967,
-STORE, 140735364808704, 140735364947967,
-STORE, 94421528674304, 94421531009023,
-SNULL, 94421528887295, 94421531009023,
-STORE, 94421528674304, 94421528887295,
-STORE, 94421528887296, 94421531009023,
-ERASE, 94421528887296, 94421531009023,
-STORE, 94421530984448, 94421530996735,
-STORE, 94421530996736, 94421531009023,
-STORE, 140162004742144, 140162006994943,
-SNULL, 140162004885503, 140162006994943,
-STORE, 140162004742144, 140162004885503,
-STORE, 140162004885504, 140162006994943,
-ERASE, 140162004885504, 140162006994943,
-STORE, 140162006982656, 140162006990847,
-STORE, 140162006990848, 140162006994943,
-STORE, 140735365402624, 140735365406719,
-STORE, 140735365390336, 140735365402623,
-STORE, 140162006953984, 140162006982655,
-STORE, 140162006945792, 140162006953983,
-STORE, 140162002628608, 140162004742143,
-SNULL, 140162002628608, 140162002640895,
-STORE, 140162002640896, 140162004742143,
-STORE, 140162002628608, 140162002640895,
-SNULL, 140162004733951, 140162004742143,
-STORE, 140162002640896, 140162004733951,
-STORE, 140162004733952, 140162004742143,
-ERASE, 140162004733952, 140162004742143,
-STORE, 140162004733952, 140162004742143,
-STORE, 140161998831616, 140162002628607,
-SNULL, 140161998831616, 140162000490495,
-STORE, 140162000490496, 140162002628607,
-STORE, 140161998831616, 140162000490495,
-SNULL, 140162002587647, 140162002628607,
-STORE, 140162000490496, 140162002587647,
-STORE, 140162002587648, 140162002628607,
-SNULL, 140162002587648, 140162002612223,
-STORE, 140162002612224, 140162002628607,
-STORE, 140162002587648, 140162002612223,
-ERASE, 140162002587648, 140162002612223,
-STORE, 140162002587648, 140162002612223,
-ERASE, 140162002612224, 140162002628607,
-STORE, 140162002612224, 140162002628607,
-STORE, 140162006937600, 140162006953983,
-SNULL, 140162002604031, 140162002612223,
-STORE, 140162002587648, 140162002604031,
-STORE, 140162002604032, 140162002612223,
-SNULL, 140162004738047, 140162004742143,
-STORE, 140162004733952, 140162004738047,
-STORE, 140162004738048, 140162004742143,
-SNULL, 94421530988543, 94421530996735,
-STORE, 94421530984448, 94421530988543,
-STORE, 94421530988544, 94421530996735,
-SNULL, 140162006986751, 140162006990847,
-STORE, 140162006982656, 140162006986751,
-STORE, 140162006986752, 140162006990847,
-ERASE, 140162006953984, 140162006982655,
-STORE, 94421551697920, 94421551833087,
-STORE, 140162005254144, 140162006937599,
-STORE, 94421551697920, 94421551968255,
-STORE, 94421551697920, 94421552103423,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140733498486784, 140737488351231,
-SNULL, 140733498494975, 140737488351231,
-STORE, 140733498486784, 140733498494975,
-STORE, 140733498355712, 140733498494975,
-STORE, 94567985836032, 94567988170751,
-SNULL, 94567986049023, 94567988170751,
-STORE, 94567985836032, 94567986049023,
-STORE, 94567986049024, 94567988170751,
-ERASE, 94567986049024, 94567988170751,
-STORE, 94567988146176, 94567988158463,
-STORE, 94567988158464, 94567988170751,
-STORE, 139634278572032, 139634280824831,
-SNULL, 139634278715391, 139634280824831,
-STORE, 139634278572032, 139634278715391,
-STORE, 139634278715392, 139634280824831,
-ERASE, 139634278715392, 139634280824831,
-STORE, 139634280812544, 139634280820735,
-STORE, 139634280820736, 139634280824831,
-STORE, 140733498544128, 140733498548223,
-STORE, 140733498531840, 140733498544127,
-STORE, 139634280783872, 139634280812543,
-STORE, 139634280775680, 139634280783871,
-STORE, 139634276458496, 139634278572031,
-SNULL, 139634276458496, 139634276470783,
-STORE, 139634276470784, 139634278572031,
-STORE, 139634276458496, 139634276470783,
-SNULL, 139634278563839, 139634278572031,
-STORE, 139634276470784, 139634278563839,
-STORE, 139634278563840, 139634278572031,
-ERASE, 139634278563840, 139634278572031,
-STORE, 139634278563840, 139634278572031,
-STORE, 139634272661504, 139634276458495,
-SNULL, 139634272661504, 139634274320383,
-STORE, 139634274320384, 139634276458495,
-STORE, 139634272661504, 139634274320383,
-SNULL, 139634276417535, 139634276458495,
-STORE, 139634274320384, 139634276417535,
-STORE, 139634276417536, 139634276458495,
-SNULL, 139634276417536, 139634276442111,
-STORE, 139634276442112, 139634276458495,
-STORE, 139634276417536, 139634276442111,
-ERASE, 139634276417536, 139634276442111,
-STORE, 139634276417536, 139634276442111,
-ERASE, 139634276442112, 139634276458495,
-STORE, 139634276442112, 139634276458495,
-STORE, 139634280767488, 139634280783871,
-SNULL, 139634276433919, 139634276442111,
-STORE, 139634276417536, 139634276433919,
-STORE, 139634276433920, 139634276442111,
-SNULL, 139634278567935, 139634278572031,
-STORE, 139634278563840, 139634278567935,
-STORE, 139634278567936, 139634278572031,
-SNULL, 94567988150271, 94567988158463,
-STORE, 94567988146176, 94567988150271,
-STORE, 94567988150272, 94567988158463,
-SNULL, 139634280816639, 139634280820735,
-STORE, 139634280812544, 139634280816639,
-STORE, 139634280816640, 139634280820735,
-ERASE, 139634280783872, 139634280812543,
-STORE, 94567996379136, 94567996514303,
-STORE, 139634279084032, 139634280767487,
-STORE, 94567996379136, 94567996649471,
-STORE, 94567996379136, 94567996784639,
-STORE, 94567996379136, 94567996960767,
-SNULL, 94567996932095, 94567996960767,
-STORE, 94567996379136, 94567996932095,
-STORE, 94567996932096, 94567996960767,
-ERASE, 94567996932096, 94567996960767,
-STORE, 94567996379136, 94567997071359,
-STORE, 94567996379136, 94567997206527,
-SNULL, 94567997186047, 94567997206527,
-STORE, 94567996379136, 94567997186047,
-STORE, 94567997186048, 94567997206527,
-ERASE, 94567997186048, 94567997206527,
-STORE, 94567996379136, 94567997358079,
-STORE, 94567996379136, 94567997493247,
-SNULL, 94567997476863, 94567997493247,
-STORE, 94567996379136, 94567997476863,
-STORE, 94567997476864, 94567997493247,
-ERASE, 94567997476864, 94567997493247,
-STORE, 94567996379136, 94567997612031,
-STORE, 94567996379136, 94567997767679,
-SNULL, 94567997739007, 94567997767679,
-STORE, 94567996379136, 94567997739007,
-STORE, 94567997739008, 94567997767679,
-ERASE, 94567997739008, 94567997767679,
-SNULL, 94567997698047, 94567997739007,
-STORE, 94567996379136, 94567997698047,
-STORE, 94567997698048, 94567997739007,
-ERASE, 94567997698048, 94567997739007,
-STORE, 94567996379136, 94567997853695,
-STORE, 94567996379136, 94567997988863,
-STORE, 94567996379136, 94567998132223,
-STORE, 94567996379136, 94567998275583,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140723667759104, 140737488351231,
-SNULL, 140723667767295, 140737488351231,
-STORE, 140723667759104, 140723667767295,
-STORE, 140723667628032, 140723667767295,
-STORE, 94231598800896, 94231601135615,
-SNULL, 94231599013887, 94231601135615,
-STORE, 94231598800896, 94231599013887,
-STORE, 94231599013888, 94231601135615,
-ERASE, 94231599013888, 94231601135615,
-STORE, 94231601111040, 94231601123327,
-STORE, 94231601123328, 94231601135615,
-STORE, 140269472649216, 140269474902015,
-SNULL, 140269472792575, 140269474902015,
-STORE, 140269472649216, 140269472792575,
-STORE, 140269472792576, 140269474902015,
-ERASE, 140269472792576, 140269474902015,
-STORE, 140269474889728, 140269474897919,
-STORE, 140269474897920, 140269474902015,
-STORE, 140723667836928, 140723667841023,
-STORE, 140723667824640, 140723667836927,
-STORE, 140269474861056, 140269474889727,
-STORE, 140269474852864, 140269474861055,
-STORE, 140269470535680, 140269472649215,
-SNULL, 140269470535680, 140269470547967,
-STORE, 140269470547968, 140269472649215,
-STORE, 140269470535680, 140269470547967,
-SNULL, 140269472641023, 140269472649215,
-STORE, 140269470547968, 140269472641023,
-STORE, 140269472641024, 140269472649215,
-ERASE, 140269472641024, 140269472649215,
-STORE, 140269472641024, 140269472649215,
-STORE, 140269466738688, 140269470535679,
-SNULL, 140269466738688, 140269468397567,
-STORE, 140269468397568, 140269470535679,
-STORE, 140269466738688, 140269468397567,
-SNULL, 140269470494719, 140269470535679,
-STORE, 140269468397568, 140269470494719,
-STORE, 140269470494720, 140269470535679,
-SNULL, 140269470494720, 140269470519295,
-STORE, 140269470519296, 140269470535679,
-STORE, 140269470494720, 140269470519295,
-ERASE, 140269470494720, 140269470519295,
-STORE, 140269470494720, 140269470519295,
-ERASE, 140269470519296, 140269470535679,
-STORE, 140269470519296, 140269470535679,
-STORE, 140269474844672, 140269474861055,
-SNULL, 140269470511103, 140269470519295,
-STORE, 140269470494720, 140269470511103,
-STORE, 140269470511104, 140269470519295,
-SNULL, 140269472645119, 140269472649215,
-STORE, 140269472641024, 140269472645119,
-STORE, 140269472645120, 140269472649215,
-SNULL, 94231601115135, 94231601123327,
-STORE, 94231601111040, 94231601115135,
-STORE, 94231601115136, 94231601123327,
-SNULL, 140269474893823, 140269474897919,
-STORE, 140269474889728, 140269474893823,
-STORE, 140269474893824, 140269474897919,
-ERASE, 140269474861056, 140269474889727,
-STORE, 94231626592256, 94231626727423,
-STORE, 140269473161216, 140269474844671,
-STORE, 94231626592256, 94231626862591,
-STORE, 94231626592256, 94231626997759,
-STORE, 94327178862592, 94327179075583,
-STORE, 94327181172736, 94327181176831,
-STORE, 94327181176832, 94327181185023,
-STORE, 94327181185024, 94327181197311,
-STORE, 94327185715200, 94327186685951,
-STORE, 140172071755776, 140172073414655,
-STORE, 140172073414656, 140172075511807,
-STORE, 140172075511808, 140172075528191,
-STORE, 140172075528192, 140172075536383,
-STORE, 140172075536384, 140172075552767,
-STORE, 140172075552768, 140172075565055,
-STORE, 140172075565056, 140172077658111,
-STORE, 140172077658112, 140172077662207,
-STORE, 140172077662208, 140172077666303,
-STORE, 140172077666304, 140172077809663,
-STORE, 140172078178304, 140172079861759,
-STORE, 140172079861760, 140172079878143,
-STORE, 140172079878144, 140172079906815,
-STORE, 140172079906816, 140172079910911,
-STORE, 140172079910912, 140172079915007,
-STORE, 140172079915008, 140172079919103,
-STORE, 140720358359040, 140720358494207,
-STORE, 140720358498304, 140720358510591,
-STORE, 140720358510592, 140720358514687,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140722548621312, 140737488351231,
-SNULL, 140722548629503, 140737488351231,
-STORE, 140722548621312, 140722548629503,
-STORE, 140722548490240, 140722548629503,
-STORE, 93949289504768, 93949291728895,
-SNULL, 93949289615359, 93949291728895,
-STORE, 93949289504768, 93949289615359,
-STORE, 93949289615360, 93949291728895,
-ERASE, 93949289615360, 93949291728895,
-STORE, 93949291708416, 93949291720703,
-STORE, 93949291720704, 93949291728895,
-STORE, 140305861902336, 140305864155135,
-SNULL, 140305862045695, 140305864155135,
-STORE, 140305861902336, 140305862045695,
-STORE, 140305862045696, 140305864155135,
-ERASE, 140305862045696, 140305864155135,
-STORE, 140305864142848, 140305864151039,
-STORE, 140305864151040, 140305864155135,
-STORE, 140722549821440, 140722549825535,
-STORE, 140722549809152, 140722549821439,
-STORE, 140305864114176, 140305864142847,
-STORE, 140305864105984, 140305864114175,
-STORE, 140305858105344, 140305861902335,
-SNULL, 140305858105344, 140305859764223,
-STORE, 140305859764224, 140305861902335,
-STORE, 140305858105344, 140305859764223,
-SNULL, 140305861861375, 140305861902335,
-STORE, 140305859764224, 140305861861375,
-STORE, 140305861861376, 140305861902335,
-SNULL, 140305861861376, 140305861885951,
-STORE, 140305861885952, 140305861902335,
-STORE, 140305861861376, 140305861885951,
-ERASE, 140305861861376, 140305861885951,
-STORE, 140305861861376, 140305861885951,
-ERASE, 140305861885952, 140305861902335,
-STORE, 140305861885952, 140305861902335,
-SNULL, 140305861877759, 140305861885951,
-STORE, 140305861861376, 140305861877759,
-STORE, 140305861877760, 140305861885951,
-SNULL, 93949291716607, 93949291720703,
-STORE, 93949291708416, 93949291716607,
-STORE, 93949291716608, 93949291720703,
-SNULL, 140305864146943, 140305864151039,
-STORE, 140305864142848, 140305864146943,
-STORE, 140305864146944, 140305864151039,
-ERASE, 140305864114176, 140305864142847,
-STORE, 93949324136448, 93949324271615,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140725754908672, 140737488351231,
-SNULL, 140725754916863, 140737488351231,
-STORE, 140725754908672, 140725754916863,
-STORE, 140725754777600, 140725754916863,
-STORE, 94831184375808, 94831186599935,
-SNULL, 94831184486399, 94831186599935,
-STORE, 94831184375808, 94831184486399,
-STORE, 94831184486400, 94831186599935,
-ERASE, 94831184486400, 94831186599935,
-STORE, 94831186579456, 94831186591743,
-STORE, 94831186591744, 94831186599935,
-STORE, 140605482479616, 140605484732415,
-SNULL, 140605482622975, 140605484732415,
-STORE, 140605482479616, 140605482622975,
-STORE, 140605482622976, 140605484732415,
-ERASE, 140605482622976, 140605484732415,
-STORE, 140605484720128, 140605484728319,
-STORE, 140605484728320, 140605484732415,
-STORE, 140725755670528, 140725755674623,
-STORE, 140725755658240, 140725755670527,
-STORE, 140605484691456, 140605484720127,
-STORE, 140605484683264, 140605484691455,
-STORE, 140605478682624, 140605482479615,
-SNULL, 140605478682624, 140605480341503,
-STORE, 140605480341504, 140605482479615,
-STORE, 140605478682624, 140605480341503,
-SNULL, 140605482438655, 140605482479615,
-STORE, 140605480341504, 140605482438655,
-STORE, 140605482438656, 140605482479615,
-SNULL, 140605482438656, 140605482463231,
-STORE, 140605482463232, 140605482479615,
-STORE, 140605482438656, 140605482463231,
-ERASE, 140605482438656, 140605482463231,
-STORE, 140605482438656, 140605482463231,
-ERASE, 140605482463232, 140605482479615,
-STORE, 140605482463232, 140605482479615,
-SNULL, 140605482455039, 140605482463231,
-STORE, 140605482438656, 140605482455039,
-STORE, 140605482455040, 140605482463231,
-SNULL, 94831186587647, 94831186591743,
-STORE, 94831186579456, 94831186587647,
-STORE, 94831186587648, 94831186591743,
-SNULL, 140605484724223, 140605484728319,
-STORE, 140605484720128, 140605484724223,
-STORE, 140605484724224, 140605484728319,
-ERASE, 140605484691456, 140605484720127,
-STORE, 94831217156096, 94831217291263,
-STORE, 94327178862592, 94327179075583,
-STORE, 94327181172736, 94327181176831,
-STORE, 94327181176832, 94327181185023,
-STORE, 94327181185024, 94327181197311,
-STORE, 94327185715200, 94327186685951,
-STORE, 140172071755776, 140172073414655,
-STORE, 140172073414656, 140172075511807,
-STORE, 140172075511808, 140172075528191,
-STORE, 140172075528192, 140172075536383,
-STORE, 140172075536384, 140172075552767,
-STORE, 140172075552768, 140172075565055,
-STORE, 140172075565056, 140172077658111,
-STORE, 140172077658112, 140172077662207,
-STORE, 140172077662208, 140172077666303,
-STORE, 140172077666304, 140172077809663,
-STORE, 140172078178304, 140172079861759,
-STORE, 140172079861760, 140172079878143,
-STORE, 140172079878144, 140172079906815,
-STORE, 140172079906816, 140172079910911,
-STORE, 140172079910912, 140172079915007,
-STORE, 140172079915008, 140172079919103,
-STORE, 140720358359040, 140720358494207,
-STORE, 140720358498304, 140720358510591,
-STORE, 140720358510592, 140720358514687,
-STORE, 140737488347136, 140737488351231,
-STORE, 140737488343040, 140737488351231,
-STORE, 140737488338944, 140737488351231,
-STORE, 140734529933312, 140737488351231,
-SNULL, 140734529945599, 140737488351231,
-STORE, 140734529933312, 140734529945599,
-STORE, 140734529802240, 140734529945599,
-STORE, 4194304, 26279935,
-STORE, 28372992, 28454911,
-STORE, 28454912, 29806591,
-STORE, 140249744060416, 140249746313215,
-SNULL, 140249744203775, 140249746313215,
-STORE, 140249744060416, 140249744203775,
-STORE, 140249744203776, 140249746313215,
-ERASE, 140249744203776, 140249746313215,
-STORE, 140249746300928, 140249746309119,
-STORE, 140249746309120, 140249746313215,
-STORE, 140734530174976, 140734530179071,
-STORE, 140734530162688, 140734530174975,
-STORE, 140249746272256, 140249746300927,
-STORE, 140249746264064, 140249746272255,
-STORE, 140249740226560, 140249744060415,
-SNULL, 140249740226560, 140249741934591,
-STORE, 140249741934592, 140249744060415,
-STORE, 140249740226560, 140249741934591,
-SNULL, 140249744027647, 140249744060415,
-STORE, 140249741934592, 140249744027647,
-STORE, 140249744027648, 140249744060415,
-ERASE, 140249744027648, 140249744060415,
-STORE, 140249744027648, 140249744060415,
-STORE, 140249738031104, 140249740226559,
-SNULL, 140249738031104, 140249738125311,
-STORE, 140249738125312, 140249740226559,
-STORE, 140249738031104, 140249738125311,
-SNULL, 140249740218367, 140249740226559,
-STORE, 140249738125312, 140249740218367,
-STORE, 140249740218368, 140249740226559,
-ERASE, 140249740218368, 140249740226559,
-STORE, 140249740218368, 140249740226559,
-STORE, 140249735512064, 140249738031103,
-SNULL, 140249735512064, 140249735925759,
-STORE, 140249735925760, 140249738031103,
-STORE, 140249735512064, 140249735925759,
-SNULL, 140249738018815, 140249738031103,
-STORE, 140249735925760, 140249738018815,
-STORE, 140249738018816, 140249738031103,
-ERASE, 140249738018816, 140249738031103,
-STORE, 140249738018816, 140249738031103,
-STORE, 140249732878336, 140249735512063,
-SNULL, 140249732878336, 140249733406719,
-STORE, 140249733406720, 140249735512063,
-STORE, 140249732878336, 140249733406719,
-SNULL, 140249735503871, 140249735512063,
-STORE, 140249733406720, 140249735503871,
-STORE, 140249735503872, 140249735512063,
-ERASE, 140249735503872, 140249735512063,
-STORE, 140249735503872, 140249735512063,
-STORE, 140249730764800, 140249732878335,
-SNULL, 140249730764800, 140249730777087,
-STORE, 140249730777088, 140249732878335,
-STORE, 140249730764800, 140249730777087,
-SNULL, 140249732870143, 140249732878335,
-STORE, 140249730777088, 140249732870143,
-STORE, 140249732870144, 140249732878335,
-ERASE, 140249732870144, 140249732878335,
-STORE, 140249732870144, 140249732878335,
-STORE, 140249728561152, 140249730764799,
-SNULL, 140249728561152, 140249728663551,
-STORE, 140249728663552, 140249730764799,
-STORE, 140249728561152, 140249728663551,
-SNULL, 140249730756607, 140249730764799,
-STORE, 140249728663552, 140249730756607,
-STORE, 140249730756608, 140249730764799,
-ERASE, 140249730756608, 140249730764799,
-STORE, 140249730756608, 140249730764799,
-STORE, 140249746255872, 140249746272255,
-STORE, 140249725399040, 140249728561151,
-SNULL, 140249725399040, 140249726459903,
-STORE, 140249726459904, 140249728561151,
-STORE, 140249725399040, 140249726459903,
-SNULL, 140249728552959, 140249728561151,
-STORE, 140249726459904, 140249728552959,
-STORE, 140249728552960, 140249728561151,
-ERASE, 140249728552960, 140249728561151,
-STORE, 140249728552960, 140249728561151,
-STORE, 140249721602048, 140249725399039,
-SNULL, 140249721602048, 140249723260927,
-STORE, 140249723260928, 140249725399039,
-STORE, 140249721602048, 140249723260927,
-SNULL, 140249725358079, 140249725399039,
-STORE, 140249723260928, 140249725358079,
-STORE, 140249725358080, 140249725399039,
-SNULL, 140249725358080, 140249725382655,
-STORE, 140249725382656, 140249725399039,
-STORE, 140249725358080, 140249725382655,
-ERASE, 140249725358080, 140249725382655,
-STORE, 140249725358080, 140249725382655,
-ERASE, 140249725382656, 140249725399039,
-STORE, 140249725382656, 140249725399039,
-STORE, 140249746243584, 140249746272255,
-SNULL, 140249725374463, 140249725382655,
-STORE, 140249725358080, 140249725374463,
-STORE, 140249725374464, 140249725382655,
-SNULL, 140249728557055, 140249728561151,
-STORE, 140249728552960, 140249728557055,
-STORE, 140249728557056, 140249728561151,
-SNULL, 140249730760703, 140249730764799,
-STORE, 140249730756608, 140249730760703,
-STORE, 140249730760704, 140249730764799,
-SNULL, 140249732874239, 140249732878335,
-STORE, 140249732870144, 140249732874239,
-STORE, 140249732874240, 140249732878335,
-SNULL, 140249735507967, 140249735512063,
-STORE, 140249735503872, 140249735507967,
-STORE, 140249735507968, 140249735512063,
-SNULL, 140249738027007, 140249738031103,
-STORE, 140249738018816, 140249738027007,
-STORE, 140249738027008, 140249738031103,
-SNULL, 140249740222463, 140249740226559,
-STORE, 140249740218368, 140249740222463,
-STORE, 140249740222464, 140249740226559,
-SNULL, 140249744031743, 140249744060415,
-STORE, 140249744027648, 140249744031743,
-STORE, 140249744031744, 140249744060415,
-SNULL, 28405759, 28454911,
-STORE, 28372992, 28405759,
-STORE, 28405760, 28454911,
-SNULL, 140249746305023, 140249746309119,
-STORE, 140249746300928, 140249746305023,
-STORE, 140249746305024, 140249746309119,
-ERASE, 140249746272256, 140249746300927,
-STORE, 33853440, 33988607,
-STORE, 140249744560128, 140249746243583,
-STORE, 140249746296832, 140249746300927,
-STORE, 140249744424960, 140249744560127,
-STORE, 33853440, 34131967,
-STORE, 140249719504896, 140249721602047,
-STORE, 140249746288640, 140249746300927,
-STORE, 140249746280448, 140249746300927,
-STORE, 140249746243584, 140249746280447,
-STORE, 140249744408576, 140249744560127,
-STORE, 33853440, 34267135,
-STORE, 33853440, 34422783,
-STORE, 140249744400384, 140249744560127,
-STORE, 140249744392192, 140249744560127,
-STORE, 33853440, 34557951,
-STORE, 33853440, 34693119,
-STORE, 140249744375808, 140249744560127,
-STORE, 140249744367616, 140249744560127,
-STORE, 33853440, 34832383,
-STORE, 140249719230464, 140249721602047,
-STORE, 140249744207872, 140249744560127,
-STORE, 33853440, 34971647,
-SNULL, 34963455, 34971647,
-STORE, 33853440, 34963455,
-STORE, 34963456, 34971647,
-ERASE, 34963456, 34971647,
-SNULL, 34955263, 34963455,
-STORE, 33853440, 34955263,
-STORE, 34955264, 34963455,
-ERASE, 34955264, 34963455,
-SNULL, 34947071, 34955263,
-STORE, 33853440, 34947071,
-STORE, 34947072, 34955263,
-ERASE, 34947072, 34955263,
-SNULL, 34938879, 34947071,
-STORE, 33853440, 34938879,
-STORE, 34938880, 34947071,
-ERASE, 34938880, 34947071,
-STORE, 140249719214080, 140249721602047,
-STORE, 140249719148544, 140249721602047,
-STORE, 140249719115776, 140249721602047,
-STORE, 140249717018624, 140249721602047,
-STORE, 140249716953088, 140249721602047,
-STORE, 33853440, 35086335,
-STORE, 140249716822016, 140249721602047,
-STORE, 140249716559872, 140249721602047,
-STORE, 140249716551680, 140249721602047,
-STORE, 140249716535296, 140249721602047,
-STORE, 140249716527104, 140249721602047,
-STORE, 140249716518912, 140249721602047,
-STORE, 33853440, 35221503,
-SNULL, 35213311, 35221503,
-STORE, 33853440, 35213311,
-STORE, 35213312, 35221503,
-ERASE, 35213312, 35221503,
-SNULL, 35205119, 35213311,
-STORE, 33853440, 35205119,
-STORE, 35205120, 35213311,
-ERASE, 35205120, 35213311,
-SNULL, 35192831, 35205119,
-STORE, 33853440, 35192831,
-STORE, 35192832, 35205119,
-ERASE, 35192832, 35205119,
-SNULL, 35176447, 35192831,
-STORE, 33853440, 35176447,
-STORE, 35176448, 35192831,
-ERASE, 35176448, 35192831,
-STORE, 140249716502528, 140249721602047,
-STORE, 33853440, 35311615,
-SNULL, 35307519, 35311615,
-STORE, 33853440, 35307519,
-STORE, 35307520, 35311615,
-ERASE, 35307520, 35311615,
-SNULL, 35303423, 35307519,
-STORE, 33853440, 35303423,
-STORE, 35303424, 35307519,
-ERASE, 35303424, 35307519,
-SNULL, 35299327, 35303423,
-STORE, 33853440, 35299327,
-STORE, 35299328, 35303423,
-ERASE, 35299328, 35303423,
-SNULL, 35295231, 35299327,
-STORE, 33853440, 35295231,
-STORE, 35295232, 35299327,
-ERASE, 35295232, 35299327,
-SNULL, 35291135, 35295231,
-STORE, 33853440, 35291135,
-STORE, 35291136, 35295231,
-ERASE, 35291136, 35295231,
-SNULL, 35287039, 35291135,
-STORE, 33853440, 35287039,
-STORE, 35287040, 35291135,
-ERASE, 35287040, 35291135,
-SNULL, 35282943, 35287039,
-STORE, 33853440, 35282943,
-STORE, 35282944, 35287039,
-ERASE, 35282944, 35287039,
-STORE, 140249716486144, 140249721602047,
-STORE, 140249716453376, 140249721602047,
-STORE, 33853440, 35418111,
-SNULL, 35401727, 35418111,
-STORE, 33853440, 35401727,
-STORE, 35401728, 35418111,
-ERASE, 35401728, 35418111,
-SNULL, 35389439, 35401727,
-STORE, 33853440, 35389439,
-STORE, 35389440, 35401727,
-ERASE, 35389440, 35401727,
-STORE, 140249714356224, 140249721602047,
-STORE, 33853440, 35540991,
-STORE, 140249714339840, 140249721602047,
-STORE, 140249714077696, 140249721602047,
-STORE, 140249714069504, 140249721602047,
-STORE, 140249714061312, 140249721602047,
-STORE, 33853440, 35680255,
-SNULL, 35672063, 35680255,
-STORE, 33853440, 35672063,
-STORE, 35672064, 35680255,
-ERASE, 35672064, 35680255,
-SNULL, 35627007, 35672063,
-STORE, 33853440, 35627007,
-STORE, 35627008, 35672063,
-ERASE, 35627008, 35672063,
-STORE, 140249711964160, 140249721602047,
-STORE, 33853440, 35762175,
-SNULL, 35753983, 35762175,
-STORE, 33853440, 35753983,
-STORE, 35753984, 35762175,
-ERASE, 35753984, 35762175,
-SNULL, 35745791, 35753983,
-STORE, 33853440, 35745791,
-STORE, 35745792, 35753983,
-ERASE, 35745792, 35753983,
-STORE, 140249711955968, 140249721602047,
-STORE, 140249711947776, 140249721602047,
-STORE, 140249710899200, 140249721602047,
-STORE, 140249710866432, 140249721602047,
-STORE, 140249710600192, 140249721602047,
-SNULL, 140249744424959, 140249744560127,
-STORE, 140249744207872, 140249744424959,
-STORE, 140249744424960, 140249744560127,
-ERASE, 140249744424960, 140249744560127,
-STORE, 140249708503040, 140249721602047,
-STORE, 33853440, 35885055,
-STORE, 140249707978752, 140249721602047,
-STORE, 140249705881600, 140249721602047,
-STORE, 33853440, 36036607,
-STORE, 33853440, 36175871,
-STORE, 140249744551936, 140249744560127,
-STORE, 140249744543744, 140249744560127,
-STORE, 140249744535552, 140249744560127,
-STORE, 140249744527360, 140249744560127,
-STORE, 140249744519168, 140249744560127,
-STORE, 140249705619456, 140249721602047,
-STORE, 140249744510976, 140249744560127,
-STORE, 140249744502784, 140249744560127,
-STORE, 140249744494592, 140249744560127,
-STORE, 140249744486400, 140249744560127,
-STORE, 140249744478208, 140249744560127,
-STORE, 140249744470016, 140249744560127,
-STORE, 140249744461824, 140249744560127,
-STORE, 140249744453632, 140249744560127,
-STORE, 140249744445440, 140249744560127,
-STORE, 140249744437248, 140249744560127,
-STORE, 140249744429056, 140249744560127,
-STORE, 140249703522304, 140249721602047,
-STORE, 33853440, 36311039,
-STORE, 140249703489536, 140249721602047,
-STORE, 33853440, 36474879,
-STORE, 140249703456768, 140249721602047,
-STORE, 33853440, 36622335,
-STORE, 140249703424000, 140249721602047,
-STORE, 140249703391232, 140249721602047,
-STORE, 33853440, 36810751,
-STORE, 140249703358464, 140249721602047,
-STORE, 140249703325696, 140249721602047,
-SNULL, 36655103, 36810751,
-STORE, 33853440, 36655103,
-STORE, 36655104, 36810751,
-ERASE, 36655104, 36810751,
-SNULL, 36438015, 36655103,
-STORE, 33853440, 36438015,
-STORE, 36438016, 36655103,
-ERASE, 36438016, 36655103,
-STORE, 140249703317504, 140249721602047,
-STORE, 140249701220352, 140249721602047,
-STORE, 33853440, 36585471,
-STORE, 33853440, 36782079,
-STORE, 140249701212160, 140249721602047,
-STORE, 140249701203968, 140249721602047,
-STORE, 140249701195776, 140249721602047,
-STORE, 140249701187584, 140249721602047,
-STORE, 140249701179392, 140249721602047,
-STORE, 140249701171200, 140249721602047,
-STORE, 140249701163008, 140249721602047,
-STORE, 140249701154816, 140249721602047,
-STORE, 140249701146624, 140249721602047,
-STORE, 140249701138432, 140249721602047,
-STORE, 140249701130240, 140249721602047,
-STORE, 140249700081664, 140249721602047,
-STORE, 140249700073472, 140249721602047,
-STORE, 33853440, 36978687,
-STORE, 140249697976320, 140249721602047,
-STORE, 33853440, 37240831,
-STORE, 140249695879168, 140249721602047,
-STORE, 140249695870976, 140249721602047,
-STORE, 140249695862784, 140249721602047,
-STORE, 140249695854592, 140249721602047,
-STORE, 140249695326208, 140249721602047,
-SNULL, 140249710600191, 140249721602047,
-STORE, 140249695326208, 140249710600191,
-STORE, 140249710600192, 140249721602047,
-SNULL, 140249710600192, 140249710866431,
-STORE, 140249710866432, 140249721602047,
-STORE, 140249710600192, 140249710866431,
-ERASE, 140249710600192, 140249710866431,
-STORE, 140249691131904, 140249710600191,
-STORE, 33853440, 37474303,
-STORE, 140249710858240, 140249721602047,
-STORE, 140249710850048, 140249721602047,
-STORE, 140249710841856, 140249721602047,
-STORE, 140249710833664, 140249721602047,
-STORE, 140249710825472, 140249721602047,
-STORE, 140249710817280, 140249721602047,
-STORE, 140249710809088, 140249721602047,
-STORE, 140249710800896, 140249721602047,
-STORE, 140249710792704, 140249721602047,
-STORE, 140249710784512, 140249721602047,
-STORE, 140249710776320, 140249721602047,
-STORE, 140249710768128, 140249721602047,
-STORE, 140249710759936, 140249721602047,
-STORE, 140249710751744, 140249721602047,
-STORE, 140249710743552, 140249721602047,
-STORE, 140249710735360, 140249721602047,
-STORE, 140249689034752, 140249710600191,
-STORE, 140249710727168, 140249721602047,
-STORE, 140249686937600, 140249710600191,
-STORE, 33853440, 37867519,
-STORE, 140249684840448, 140249710600191,
-STORE, 140249710718976, 140249721602047,
-STORE, 140249682743296, 140249710600191,
-STORE, 140249710710784, 140249721602047,
-STORE, 140249710702592, 140249721602047,
-STORE, 140249710694400, 140249721602047,
-STORE, 140249710686208, 140249721602047,
-STORE, 140249710678016, 140249721602047,
-STORE, 140249682612224, 140249710600191,
-STORE, 140249682087936, 140249710600191,
-SNULL, 140249705619455, 140249710600191,
-STORE, 140249682087936, 140249705619455,
-STORE, 140249705619456, 140249710600191,
-SNULL, 140249705619456, 140249705881599,
-STORE, 140249705881600, 140249710600191,
-STORE, 140249705619456, 140249705881599,
-ERASE, 140249705619456, 140249705881599,
-STORE, 140249679990784, 140249705619455,
-STORE, 140249710669824, 140249721602047,
-STORE, 140249677893632, 140249705619455,
-STORE, 140249710653440, 140249721602047,
-STORE, 140249710645248, 140249721602047,
-STORE, 140249710637056, 140249721602047,
-STORE, 140249710628864, 140249721602047,
-STORE, 140249710620672, 140249721602047,
-STORE, 140249710612480, 140249721602047,
-STORE, 140249710604288, 140249721602047,
-STORE, 140249705873408, 140249710600191,
-STORE, 140249705865216, 140249710600191,
-STORE, 140249705857024, 140249710600191,
-STORE, 140249705848832, 140249710600191,
-STORE, 140249705840640, 140249710600191,
-STORE, 140249705832448, 140249710600191,
-STORE, 140249705824256, 140249710600191,
-STORE, 140249705816064, 140249710600191,
-STORE, 140249705807872, 140249710600191,
-STORE, 140249705799680, 140249710600191,
-STORE, 33853440, 38129663,
-SNULL, 140249744207872, 140249744367615,
-STORE, 140249744367616, 140249744424959,
-STORE, 140249744207872, 140249744367615,
-ERASE, 140249744207872, 140249744367615,
-STORE, 140249677606912, 140249705619455,
-STORE, 140249675509760, 140249705619455,
-SNULL, 140249677606911, 140249705619455,
-STORE, 140249675509760, 140249677606911,
-STORE, 140249677606912, 140249705619455,
-SNULL, 140249677606912, 140249677893631,
-STORE, 140249677893632, 140249705619455,
-STORE, 140249677606912, 140249677893631,
-ERASE, 140249677606912, 140249677893631,
-STORE, 140249744359424, 140249744424959,
-STORE, 33853440, 38391807,
-STORE, 140249674981376, 140249677606911,
-STORE, 140249672884224, 140249677606911,
-SNULL, 140249719230463, 140249721602047,
-STORE, 140249710604288, 140249719230463,
-STORE, 140249719230464, 140249721602047,
-SNULL, 140249719230464, 140249719504895,
-STORE, 140249719504896, 140249721602047,
-STORE, 140249719230464, 140249719504895,
-ERASE, 140249719230464, 140249719504895,
-STORE, 140249744351232, 140249744424959,
-STORE, 140249744343040, 140249744424959,
-STORE, 140249744334848, 140249744424959,
-STORE, 140249744326656, 140249744424959,
-STORE, 140249744310272, 140249744424959,
-STORE, 140249744302080, 140249744424959,
-STORE, 140249744285696, 140249744424959,
-STORE, 140249744277504, 140249744424959,
-STORE, 140249744261120, 140249744424959,
-STORE, 140249744252928, 140249744424959,
-STORE, 140249744220160, 140249744424959,
-STORE, 140249744211968, 140249744424959,
-STORE, 140249719488512, 140249721602047,
-STORE, 140249744203776, 140249744424959,
-STORE, 140249719472128, 140249721602047,
-STORE, 140249719463936, 140249721602047,
-STORE, 140249719447552, 140249721602047,
-STORE, 140249719439360, 140249721602047,
-STORE, 140249719406592, 140249721602047,
-STORE, 140249719398400, 140249721602047,
-STORE, 140249719382016, 140249721602047,
-STORE, 140249719373824, 140249721602047,
-STORE, 140249719357440, 140249721602047,
-STORE, 140249719349248, 140249721602047,
-STORE, 140249719332864, 140249721602047,
-STORE, 140249719324672, 140249721602047,
-STORE, 140249719291904, 140249721602047,
-STORE, 140249719283712, 140249721602047,
-STORE, 140249719267328, 140249721602047,
-STORE, 140249719259136, 140249721602047,
-STORE, 140249719242752, 140249721602047,
-STORE, 140249719234560, 140249721602047,
-STORE, 140249705783296, 140249710600191,
-STORE, 140249705775104, 140249710600191,
-STORE, 140249705742336, 140249710600191,
-STORE, 140249705734144, 140249710600191,
-STORE, 140249705717760, 140249710600191,
-STORE, 140249670787072, 140249677606911,
-STORE, 140249705709568, 140249710600191,
-STORE, 140249705693184, 140249710600191,
-STORE, 140249705684992, 140249710600191,
-STORE, 140249705668608, 140249710600191,
-STORE, 140249705660416, 140249710600191,
-STORE, 140249705627648, 140249710600191,
-STORE, 140249677893632, 140249710600191,
-STORE, 140249677877248, 140249710600191,
-STORE, 140249677869056, 140249710600191,
-STORE, 140249677852672, 140249710600191,
-STORE, 140249677844480, 140249710600191,
-STORE, 140249677828096, 140249710600191,
-STORE, 140249668689920, 140249677606911,
-STORE, 140249677819904, 140249710600191,
-STORE, 140249677787136, 140249710600191,
-STORE, 140249677778944, 140249710600191,
-STORE, 140249677762560, 140249710600191,
-STORE, 140249677754368, 140249710600191,
-STORE, 140249677737984, 140249710600191,
-STORE, 140249677729792, 140249710600191,
-STORE, 140249677713408, 140249710600191,
-STORE, 140249677705216, 140249710600191,
-STORE, 140249677672448, 140249710600191,
-STORE, 140249677664256, 140249710600191,
-STORE, 140249677647872, 140249710600191,
-STORE, 140249677639680, 140249710600191,
-STORE, 140249677623296, 140249710600191,
-STORE, 140249677615104, 140249710600191,
-STORE, 140249668673536, 140249677606911,
-STORE, 140249668673536, 140249710600191,
-STORE, 140249668640768, 140249710600191,
-STORE, 140249668632576, 140249710600191,
-STORE, 140249668616192, 140249710600191,
-STORE, 140249668608000, 140249710600191,
-STORE, 140249668591616, 140249710600191,
-STORE, 140249668583424, 140249710600191,
-STORE, 140249668567040, 140249710600191,
-STORE, 140249668558848, 140249710600191,
-STORE, 140249668526080, 140249710600191,
-STORE, 140249668517888, 140249710600191,
-STORE, 140249668501504, 140249710600191,
-STORE, 140249668493312, 140249710600191,
-STORE, 140249668476928, 140249710600191,
-STORE, 140249668468736, 140249710600191,
-STORE, 140249668452352, 140249710600191,
-STORE, 140249668444160, 140249710600191,
-STORE, 140249668411392, 140249710600191,
-STORE, 140249668403200, 140249710600191,
-STORE, 140249668386816, 140249710600191,
-STORE, 140249668378624, 140249710600191,
-STORE, 140249668362240, 140249710600191,
-STORE, 140249668354048, 140249710600191,
-STORE, 140249668337664, 140249710600191,
-STORE, 140249668329472, 140249710600191,
-STORE, 140249668296704, 140249710600191,
-STORE, 140249668288512, 140249710600191,
-STORE, 140249668272128, 140249710600191,
-STORE, 140249668263936, 140249710600191,
-STORE, 140249668247552, 140249710600191,
-STORE, 140249668239360, 140249710600191,
-STORE, 140249668222976, 140249710600191,
-STORE, 140249668214784, 140249710600191,
-STORE, 140249668182016, 140249710600191,
-STORE, 140249668173824, 140249710600191,
-STORE, 140249668157440, 140249710600191,
-STORE, 140249668149248, 140249710600191,
-STORE, 140249668132864, 140249710600191,
-STORE, 140249668124672, 140249710600191,
-STORE, 140249668108288, 140249710600191,
-STORE, 140249668100096, 140249710600191,
-STORE, 140249668067328, 140249710600191,
-STORE, 140249668059136, 140249710600191,
-STORE, 140249668042752, 140249710600191,
-STORE, 140249668034560, 140249710600191,
-STORE, 140249668018176, 140249710600191,
-STORE, 140249668009984, 140249710600191,
-STORE, 140249667993600, 140249710600191,
-STORE, 140249667985408, 140249710600191,
-STORE, 140249667952640, 140249710600191,
-STORE, 140249667944448, 140249710600191,
-STORE, 140249667928064, 140249710600191,
-STORE, 140249667919872, 140249710600191,
-STORE, 140249667903488, 140249710600191,
-STORE, 140249667895296, 140249710600191,
-STORE, 140249667878912, 140249710600191,
-STORE, 140249667870720, 140249710600191,
-STORE, 140249667837952, 140249710600191,
-STORE, 140249667829760, 140249710600191,
-STORE, 140249667813376, 140249710600191,
-STORE, 140249667805184, 140249710600191,
-STORE, 140249667788800, 140249710600191,
-STORE, 140249667780608, 140249710600191,
-STORE, 140249667764224, 140249710600191,
-STORE, 140249667756032, 140249710600191,
-STORE, 140249667723264, 140249710600191,
-STORE, 140249667715072, 140249710600191,
-STORE, 140249667698688, 140249710600191,
-STORE, 140249667690496, 140249710600191,
-STORE, 140249667674112, 140249710600191,
-STORE, 140249667665920, 140249710600191,
-STORE, 140249667649536, 140249710600191,
-STORE, 140249667641344, 140249710600191,
-STORE, 140249667608576, 140249710600191,
-STORE, 140249667600384, 140249710600191,
-STORE, 140249667584000, 140249710600191,
-STORE, 140249667575808, 140249710600191,
-STORE, 140249667559424, 140249710600191,
-STORE, 140249667551232, 140249710600191,
-STORE, 140249667534848, 140249710600191,
-STORE, 140249667526656, 140249710600191,
-STORE, 140249667493888, 140249710600191,
-STORE, 140249667485696, 140249710600191,
-STORE, 140249667469312, 140249710600191,
-STORE, 140249667461120, 140249710600191,
-STORE, 140249667444736, 140249710600191,
-STORE, 140249667436544, 140249710600191,
-STORE, 140249667420160, 140249710600191,
-STORE, 140249665323008, 140249710600191,
-STORE, 140249665314816, 140249710600191,
-STORE, 140249665282048, 140249710600191,
-STORE, 140249665273856, 140249710600191,
-STORE, 140249665257472, 140249710600191,
-STORE, 140249665249280, 140249710600191,
-STORE, 140249665232896, 140249710600191,
-STORE, 140249665224704, 140249710600191,
-STORE, 140249665208320, 140249710600191,
-STORE, 140249665200128, 140249710600191,
-STORE, 140249665167360, 140249710600191,
-STORE, 140249665159168, 140249710600191,
-STORE, 140249665142784, 140249710600191,
-STORE, 140249665134592, 140249710600191,
-STORE, 140249665118208, 140249710600191,
-STORE, 140249665110016, 140249710600191,
-STORE, 140249665093632, 140249710600191,
-STORE, 140249665085440, 140249710600191,
-STORE, 140249665052672, 140249710600191,
-STORE, 140249665044480, 140249710600191,
-STORE, 140249665028096, 140249710600191,
-STORE, 140249665019904, 140249710600191,
-STORE, 140249665003520, 140249710600191,
-STORE, 140249664995328, 140249710600191,
-STORE, 140249664978944, 140249710600191,
-STORE, 140249664970752, 140249710600191,
-STORE, 140249664937984, 140249710600191,
-STORE, 140249664929792, 140249710600191,
-STORE, 140249664913408, 140249710600191,
-STORE, 140249664905216, 140249710600191,
-STORE, 140249664888832, 140249710600191,
-STORE, 140249664880640, 140249710600191,
-STORE, 140249664864256, 140249710600191,
-STORE, 140249664856064, 140249710600191,
-STORE, 140249664823296, 140249710600191,
-STORE, 140249664815104, 140249710600191,
-STORE, 140249664798720, 140249710600191,
-STORE, 140249664790528, 140249710600191,
-STORE, 140249664774144, 140249710600191,
-STORE, 140249664765952, 140249710600191,
-STORE, 140249664749568, 140249710600191,
-STORE, 140249664741376, 140249710600191,
-STORE, 140249664708608, 140249710600191,
-STORE, 140249664700416, 140249710600191,
-STORE, 140249664684032, 140249710600191,
-STORE, 140249664675840, 140249710600191,
-STORE, 140249664659456, 140249710600191,
-STORE, 140249664651264, 140249710600191,
-STORE, 140249664634880, 140249710600191,
-STORE, 140249664626688, 140249710600191,
-STORE, 140249664593920, 140249710600191,
-STORE, 140249664585728, 140249710600191,
-STORE, 140249664569344, 140249710600191,
-STORE, 140249664561152, 140249710600191,
-STORE, 140249664544768, 140249710600191,
-STORE, 140249664536576, 140249710600191,
-STORE, 140249664520192, 140249710600191,
-STORE, 140249664512000, 140249710600191,
-STORE, 140249664479232, 140249710600191,
-STORE, 140249664471040, 140249710600191,
-STORE, 140249664454656, 140249710600191,
-STORE, 140249664446464, 140249710600191,
-STORE, 140249664430080, 140249710600191,
-STORE, 140249664421888, 140249710600191,
-STORE, 140249664405504, 140249710600191,
-STORE, 140249664397312, 140249710600191,
-STORE, 140249664364544, 140249710600191,
-STORE, 140249664356352, 140249710600191,
-STORE, 140249664339968, 140249710600191,
-STORE, 140249664331776, 140249710600191,
-STORE, 140249664315392, 140249710600191,
-STORE, 140249664307200, 140249710600191,
-STORE, 140249664290816, 140249710600191,
-STORE, 140249664282624, 140249710600191,
-STORE, 140249664249856, 140249710600191,
-STORE, 140249664241664, 140249710600191,
-STORE, 140249664225280, 140249710600191,
-STORE, 140249664217088, 140249710600191,
-STORE, 140249664200704, 140249710600191,
-STORE, 140249664192512, 140249710600191,
-STORE, 140249664176128, 140249710600191,
-STORE, 140249664167936, 140249710600191,
-STORE, 140249664135168, 140249710600191,
-STORE, 140249664126976, 140249710600191,
-STORE, 140249664110592, 140249710600191,
-STORE, 140249664102400, 140249710600191,
-STORE, 140249664086016, 140249710600191,
-STORE, 140249664077824, 140249710600191,
-STORE, 140249664061440, 140249710600191,
-STORE, 140249664053248, 140249710600191,
-STORE, 140249664020480, 140249710600191,
-STORE, 140249664012288, 140249710600191,
-STORE, 140249663995904, 140249710600191,
-STORE, 140249663987712, 140249710600191,
-STORE, 140249663971328, 140249710600191,
-STORE, 140249663963136, 140249710600191,
-STORE, 140249663946752, 140249710600191,
-STORE, 140249663938560, 140249710600191,
-STORE, 140249663905792, 140249710600191,
-STORE, 140249663897600, 140249710600191,
-STORE, 140249663881216, 140249710600191,
-STORE, 140249663873024, 140249710600191,
-STORE, 140249663856640, 140249710600191,
-STORE, 140249663848448, 140249710600191,
-STORE, 140249663832064, 140249710600191,
-STORE, 140249663823872, 140249710600191,
-STORE, 140249663791104, 140249710600191,
-STORE, 140249663782912, 140249710600191,
-STORE, 140249663766528, 140249710600191,
-STORE, 140249663758336, 140249710600191,
-STORE, 140249663741952, 140249710600191,
-STORE, 140249663733760, 140249710600191,
-STORE, 140249663717376, 140249710600191,
-STORE, 140249663709184, 140249710600191,
-STORE, 140249663676416, 140249710600191,
-STORE, 140249663668224, 140249710600191,
-STORE, 140249663651840, 140249710600191,
-STORE, 140249663643648, 140249710600191,
-STORE, 140249663627264, 140249710600191,
-STORE, 33853440, 38526975,
-STORE, 140249663619072, 140249710600191,
-STORE, 140249663602688, 140249710600191,
-STORE, 140249661505536, 140249710600191,
-STORE, 140249661497344, 140249710600191,
-STORE, 140249661464576, 140249710600191,
-STORE, 140249661456384, 140249710600191,
-STORE, 140249661440000, 140249710600191,
-STORE, 140249661431808, 140249710600191,
-STORE, 140249661415424, 140249710600191,
-STORE, 140249661407232, 140249710600191,
-STORE, 140249661390848, 140249710600191,
-STORE, 140249661382656, 140249710600191,
-STORE, 140249661349888, 140249710600191,
-STORE, 140249661341696, 140249710600191,
-STORE, 140249661325312, 140249710600191,
-STORE, 140249661317120, 140249710600191,
-STORE, 140249661300736, 140249710600191,
-STORE, 140249661292544, 140249710600191,
-STORE, 140249661276160, 140249710600191,
-STORE, 140249661267968, 140249710600191,
-STORE, 140249661235200, 140249710600191,
-STORE, 140249661227008, 140249710600191,
-STORE, 140249661210624, 140249710600191,
-STORE, 140249661202432, 140249710600191,
-STORE, 140249661186048, 140249710600191,
-STORE, 140249661177856, 140249710600191,
-STORE, 140249661161472, 140249710600191,
-STORE, 140249661153280, 140249710600191,
-STORE, 140249661120512, 140249710600191,
-STORE, 140249661112320, 140249710600191,
-STORE, 140249661095936, 140249710600191,
-STORE, 140249661087744, 140249710600191,
-STORE, 140249661071360, 140249710600191,
-STORE, 140249661063168, 140249710600191,
-STORE, 140249661046784, 140249710600191,
-STORE, 140249661038592, 140249710600191,
-STORE, 140249661005824, 140249710600191,
-STORE, 140249660997632, 140249710600191,
-STORE, 140249660981248, 140249710600191,
-STORE, 140249660973056, 140249710600191,
-STORE, 140249660956672, 140249710600191,
-STORE, 140249660948480, 140249710600191,
-STORE, 140249660932096, 140249710600191,
-STORE, 140249660923904, 140249710600191,
-STORE, 140249660891136, 140249710600191,
-STORE, 140249660882944, 140249710600191,
-STORE, 140249660866560, 140249710600191,
-STORE, 140249660858368, 140249710600191,
-STORE, 140249660841984, 140249710600191,
-STORE, 140249660833792, 140249710600191,
-STORE, 140249660817408, 140249710600191,
-STORE, 140249660809216, 140249710600191,
-STORE, 140249660776448, 140249710600191,
-STORE, 140249660768256, 140249710600191,
-STORE, 140249660751872, 140249710600191,
-STORE, 140249660743680, 140249710600191,
-STORE, 140249660727296, 140249710600191,
-STORE, 140249660719104, 140249710600191,
-STORE, 140249660702720, 140249710600191,
-STORE, 140249660694528, 140249710600191,
-STORE, 140249660661760, 140249710600191,
-STORE, 140249660653568, 140249710600191,
-STORE, 140249660637184, 140249710600191,
-STORE, 140249660628992, 140249710600191,
-STORE, 140249660612608, 140249710600191,
-STORE, 140249660604416, 140249710600191,
-STORE, 140249660588032, 140249710600191,
-STORE, 140249660579840, 140249710600191,
-STORE, 140249660547072, 140249710600191,
-STORE, 140249660538880, 140249710600191,
-STORE, 140249660522496, 140249710600191,
-STORE, 140249660514304, 140249710600191,
-STORE, 140249660497920, 140249710600191,
-STORE, 140249660489728, 140249710600191,
-STORE, 140249660473344, 140249710600191,
-STORE, 140249660465152, 140249710600191,
-STORE, 140249660432384, 140249710600191,
-STORE, 140249660424192, 140249710600191,
-STORE, 140249660407808, 140249710600191,
-STORE, 140249660399616, 140249710600191,
-STORE, 140249660383232, 140249710600191,
-STORE, 140249660375040, 140249710600191,
-STORE, 140249660358656, 140249710600191,
-STORE, 140249660350464, 140249710600191,
-STORE, 140249660317696, 140249710600191,
-STORE, 140249660309504, 140249710600191,
-STORE, 140249660293120, 140249710600191,
-STORE, 140249660284928, 140249710600191,
-STORE, 140249660268544, 140249710600191,
-STORE, 140249660260352, 140249710600191,
-STORE, 140249660243968, 140249710600191,
-STORE, 140249660235776, 140249710600191,
-STORE, 140249660203008, 140249710600191,
-STORE, 140249660194816, 140249710600191,
-STORE, 140249660178432, 140249710600191,
-STORE, 140249660170240, 140249710600191,
-STORE, 140249660153856, 140249710600191,
-STORE, 140249660145664, 140249710600191,
-STORE, 140249660129280, 140249710600191,
-STORE, 140249660121088, 140249710600191,
-STORE, 140249660088320, 140249710600191,
-STORE, 140249660080128, 140249710600191,
-STORE, 140249660063744, 140249710600191,
-STORE, 140249660055552, 140249710600191,
-STORE, 140249660039168, 140249710600191,
-STORE, 140249660030976, 140249710600191,
-STORE, 140249660014592, 140249710600191,
-STORE, 140249660006400, 140249710600191,
-STORE, 140249659973632, 140249710600191,
-STORE, 140249659965440, 140249710600191,
-STORE, 140249659949056, 140249710600191,
-STORE, 140249659940864, 140249710600191,
-STORE, 140249659924480, 140249710600191,
-STORE, 140249659916288, 140249710600191,
-STORE, 140249659899904, 140249710600191,
-STORE, 140249659891712, 140249710600191,
-STORE, 140249659858944, 140249710600191,
-STORE, 140249659850752, 140249710600191,
-STORE, 140249659834368, 140249710600191,
-STORE, 140249659826176, 140249710600191,
-STORE, 140249659809792, 140249710600191,
-STORE, 140249659801600, 140249710600191,
-STORE, 140249659785216, 140249710600191,
-STORE, 140249657688064, 140249710600191,
-STORE, 140249657679872, 140249710600191,
-STORE, 140249657647104, 140249710600191,
-STORE, 140249657638912, 140249710600191,
-STORE, 140249657622528, 140249710600191,
-STORE, 140249657614336, 140249710600191,
-STORE, 140249657597952, 140249710600191,
-STORE, 140249657589760, 140249710600191,
-STORE, 140249657573376, 140249710600191,
-STORE, 140249657565184, 140249710600191,
-STORE, 140249657532416, 140249710600191,
-STORE, 140249657524224, 140249710600191,
-STORE, 140249657507840, 140249710600191,
-STORE, 140249657499648, 140249710600191,
-STORE, 140249657483264, 140249710600191,
-STORE, 140249657475072, 140249710600191,
-STORE, 140249657458688, 140249710600191,
-STORE, 140249657450496, 140249710600191,
-STORE, 140249657417728, 140249710600191,
-STORE, 140249657409536, 140249710600191,
-STORE, 140249657393152, 140249710600191,
-STORE, 140249657384960, 140249710600191,
-STORE, 140249657368576, 140249710600191,
-STORE, 140249657360384, 140249710600191,
-STORE, 140249657344000, 140249710600191,
-STORE, 140249657335808, 140249710600191,
-STORE, 140249657303040, 140249710600191,
-STORE, 140249657294848, 140249710600191,
-STORE, 140249657278464, 140249710600191,
-STORE, 140249657270272, 140249710600191,
-STORE, 140249657253888, 140249710600191,
-STORE, 140249657245696, 140249710600191,
-STORE, 140249657229312, 140249710600191,
-STORE, 140249657221120, 140249710600191,
-STORE, 140249657188352, 140249710600191,
-STORE, 140249657180160, 140249710600191,
-STORE, 140249657163776, 140249710600191,
-STORE, 140249657155584, 140249710600191,
-STORE, 140249657139200, 140249710600191,
-STORE, 140249657131008, 140249710600191,
-STORE, 140249657114624, 140249710600191,
-STORE, 140249657106432, 140249710600191,
-STORE, 140249657073664, 140249710600191,
-STORE, 140249657065472, 140249710600191,
-STORE, 140249657049088, 140249710600191,
-STORE, 140249657040896, 140249710600191,
-STORE, 140249657024512, 140249710600191,
-STORE, 140249657016320, 140249710600191,
-STORE, 140249656999936, 140249710600191,
-STORE, 140249656991744, 140249710600191,
-STORE, 140249656958976, 140249710600191,
-STORE, 140249656950784, 140249710600191,
-STORE, 140249656934400, 140249710600191,
-STORE, 140249656926208, 140249710600191,
-STORE, 140249656909824, 140249710600191,
-STORE, 140249656901632, 140249710600191,
-STORE, 140249656885248, 140249710600191,
-STORE, 140249656877056, 140249710600191,
-STORE, 140249656844288, 140249710600191,
-STORE, 140249656836096, 140249710600191,
-STORE, 140249656819712, 140249710600191,
-STORE, 140249656811520, 140249710600191,
-STORE, 140249656795136, 140249710600191,
-STORE, 33853440, 38662143,
-STORE, 140249656786944, 140249710600191,
-STORE, 140249656770560, 140249710600191,
-STORE, 140249656762368, 140249710600191,
-STORE, 140249656729600, 140249710600191,
-STORE, 140249656721408, 140249710600191,
-STORE, 140249656705024, 140249710600191,
-STORE, 140249656696832, 140249710600191,
-STORE, 140249656680448, 140249710600191,
-STORE, 140249656672256, 140249710600191,
-STORE, 140249656655872, 140249710600191,
-STORE, 140249656647680, 140249710600191,
-STORE, 140249656614912, 140249710600191,
-STORE, 140249656606720, 140249710600191,
-STORE, 140249656590336, 140249710600191,
-STORE, 140249656582144, 140249710600191,
-STORE, 140249656565760, 140249710600191,
-STORE, 140249656557568, 140249710600191,
-STORE, 140249656541184, 140249710600191,
-STORE, 140249656532992, 140249710600191,
-STORE, 140249656500224, 140249710600191,
-STORE, 140249656492032, 140249710600191,
-STORE, 140249656475648, 140249710600191,
-STORE, 140249656467456, 140249710600191,
-STORE, 140249656451072, 140249710600191,
-STORE, 140249656442880, 140249710600191,
-STORE, 140249656426496, 140249710600191,
-STORE, 140249656418304, 140249710600191,
-STORE, 140249656385536, 140249710600191,
-STORE, 140249656377344, 140249710600191,
-STORE, 140249656360960, 140249710600191,
-STORE, 140249656352768, 140249710600191,
-STORE, 140249656336384, 140249710600191,
-STORE, 140249656328192, 140249710600191,
-STORE, 140249656311808, 140249710600191,
-STORE, 140249656303616, 140249710600191,
-STORE, 140249656270848, 140249710600191,
-STORE, 140249656262656, 140249710600191,
-STORE, 140249656246272, 140249710600191,
-STORE, 140249656238080, 140249710600191,
-STORE, 140249656221696, 140249710600191,
-STORE, 140249656213504, 140249710600191,
-STORE, 140249656197120, 140249710600191,
-STORE, 140249656188928, 140249710600191,
-STORE, 140249656156160, 140249710600191,
-STORE, 140249656147968, 140249710600191,
-STORE, 140249656131584, 140249710600191,
-STORE, 140249656123392, 140249710600191,
-STORE, 140249656107008, 140249710600191,
-STORE, 140249656098816, 140249710600191,
-STORE, 140249656082432, 140249710600191,
-STORE, 140249656074240, 140249710600191,
-STORE, 140249656041472, 140249710600191,
-STORE, 140249656033280, 140249710600191,
-STORE, 140249656016896, 140249710600191,
-STORE, 140249656008704, 140249710600191,
-STORE, 140249655992320, 140249710600191,
-STORE, 140249655984128, 140249710600191,
-STORE, 140249655967744, 140249710600191,
-STORE, 140249653870592, 140249710600191,
-STORE, 140249653862400, 140249710600191,
-STORE, 140249653829632, 140249710600191,
-STORE, 140249653821440, 140249710600191,
-STORE, 140249653805056, 140249710600191,
-STORE, 140249653796864, 140249710600191,
-STORE, 140249653780480, 140249710600191,
-STORE, 140249653772288, 140249710600191,
-STORE, 140249653755904, 140249710600191,
-STORE, 140249652703232, 140249710600191,
-SNULL, 140249682087935, 140249710600191,
-STORE, 140249652703232, 140249682087935,
-STORE, 140249682087936, 140249710600191,
- };
-
- unsigned long set26[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140729464770560, 140737488351231,
-SNULL, 140729464774655, 140737488351231,
-STORE, 140729464770560, 140729464774655,
-STORE, 140729464639488, 140729464774655,
-STORE, 4194304, 5066751,
-STORE, 7159808, 7172095,
-STORE, 7172096, 7180287,
-STORE, 140729465114624, 140729465118719,
-STORE, 140729465102336, 140729465114623,
-STORE, 30867456, 30875647,
-STORE, 30867456, 31010815,
-STORE, 140109040988160, 140109042671615,
-STORE, 140109040959488, 140109040988159,
-STORE, 140109040943104, 140109040959487,
-ERASE, 140109040943104, 140109040959487,
-STORE, 140109040840704, 140109040959487,
-ERASE, 140109040840704, 140109040959487,
-STORE, 140109040951296, 140109040959487,
-ERASE, 140109040951296, 140109040959487,
-STORE, 140109040955392, 140109040959487,
-ERASE, 140109040955392, 140109040959487,
- };
- unsigned long set27[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140726128070656, 140737488351231,
-SNULL, 140726128074751, 140737488351231,
-STORE, 140726128070656, 140726128074751,
-STORE, 140726127939584, 140726128074751,
-STORE, 94478497189888, 94478499303423,
-SNULL, 94478497202175, 94478499303423,
-STORE, 94478497189888, 94478497202175,
-STORE, 94478497202176, 94478499303423,
-ERASE, 94478497202176, 94478499303423,
-STORE, 94478499295232, 94478499303423,
-STORE, 140415605723136, 140415607975935,
-SNULL, 140415605866495, 140415607975935,
-STORE, 140415605723136, 140415605866495,
-STORE, 140415605866496, 140415607975935,
-ERASE, 140415605866496, 140415607975935,
-STORE, 140415607963648, 140415607971839,
-STORE, 140415607971840, 140415607975935,
-STORE, 140726130024448, 140726130028543,
-STORE, 140726130012160, 140726130024447,
-STORE, 140415607934976, 140415607963647,
-STORE, 140415607926784, 140415607934975,
-STORE, 140415603245056, 140415605723135,
-SNULL, 140415603245056, 140415603613695,
-STORE, 140415603613696, 140415605723135,
-STORE, 140415603245056, 140415603613695,
-SNULL, 140415605710847, 140415605723135,
-STORE, 140415603613696, 140415605710847,
-STORE, 140415605710848, 140415605723135,
-ERASE, 140415605710848, 140415605723135,
-STORE, 140415605710848, 140415605723135,
-STORE, 140415599370240, 140415603245055,
-SNULL, 140415599370240, 140415601111039,
-STORE, 140415601111040, 140415603245055,
-STORE, 140415599370240, 140415601111039,
-SNULL, 140415603208191, 140415603245055,
-STORE, 140415601111040, 140415603208191,
-STORE, 140415603208192, 140415603245055,
-ERASE, 140415603208192, 140415603245055,
-STORE, 140415603208192, 140415603245055,
-STORE, 140415595692032, 140415599370239,
-SNULL, 140415595692032, 140415597207551,
-STORE, 140415597207552, 140415599370239,
-STORE, 140415595692032, 140415597207551,
-SNULL, 140415599304703, 140415599370239,
-STORE, 140415597207552, 140415599304703,
-STORE, 140415599304704, 140415599370239,
-SNULL, 140415599304704, 140415599353855,
-STORE, 140415599353856, 140415599370239,
-STORE, 140415599304704, 140415599353855,
-ERASE, 140415599304704, 140415599353855,
-STORE, 140415599304704, 140415599353855,
-ERASE, 140415599353856, 140415599370239,
-STORE, 140415599353856, 140415599370239,
-STORE, 140415593500672, 140415595692031,
-SNULL, 140415593500672, 140415593590783,
-STORE, 140415593590784, 140415595692031,
-STORE, 140415593500672, 140415593590783,
-SNULL, 140415595683839, 140415595692031,
-STORE, 140415593590784, 140415595683839,
-STORE, 140415595683840, 140415595692031,
-ERASE, 140415595683840, 140415595692031,
-STORE, 140415595683840, 140415595692031,
-STORE, 140415589703680, 140415593500671,
-SNULL, 140415589703680, 140415591362559,
-STORE, 140415591362560, 140415593500671,
-STORE, 140415589703680, 140415591362559,
-SNULL, 140415593459711, 140415593500671,
-STORE, 140415591362560, 140415593459711,
-STORE, 140415593459712, 140415593500671,
-SNULL, 140415593459712, 140415593484287,
-STORE, 140415593484288, 140415593500671,
-STORE, 140415593459712, 140415593484287,
-ERASE, 140415593459712, 140415593484287,
-STORE, 140415593459712, 140415593484287,
-ERASE, 140415593484288, 140415593500671,
-STORE, 140415593484288, 140415593500671,
-STORE, 140415587590144, 140415589703679,
-SNULL, 140415587590144, 140415587602431,
-STORE, 140415587602432, 140415589703679,
-STORE, 140415587590144, 140415587602431,
-SNULL, 140415589695487, 140415589703679,
-STORE, 140415587602432, 140415589695487,
-STORE, 140415589695488, 140415589703679,
-ERASE, 140415589695488, 140415589703679,
-STORE, 140415589695488, 140415589703679,
-STORE, 140415607918592, 140415607934975,
-STORE, 140415585398784, 140415587590143,
-SNULL, 140415585398784, 140415585480703,
-STORE, 140415585480704, 140415587590143,
-STORE, 140415585398784, 140415585480703,
-SNULL, 140415587573759, 140415587590143,
-STORE, 140415585480704, 140415587573759,
-STORE, 140415587573760, 140415587590143,
-SNULL, 140415587573760, 140415587581951,
-STORE, 140415587581952, 140415587590143,
-STORE, 140415587573760, 140415587581951,
-ERASE, 140415587573760, 140415587581951,
-STORE, 140415587573760, 140415587581951,
-ERASE, 140415587581952, 140415587590143,
-STORE, 140415587581952, 140415587590143,
-STORE, 140415583182848, 140415585398783,
-SNULL, 140415583182848, 140415583281151,
-STORE, 140415583281152, 140415585398783,
-STORE, 140415583182848, 140415583281151,
-SNULL, 140415585374207, 140415585398783,
-STORE, 140415583281152, 140415585374207,
-STORE, 140415585374208, 140415585398783,
-SNULL, 140415585374208, 140415585382399,
-STORE, 140415585382400, 140415585398783,
-STORE, 140415585374208, 140415585382399,
-ERASE, 140415585374208, 140415585382399,
-STORE, 140415585374208, 140415585382399,
-ERASE, 140415585382400, 140415585398783,
-STORE, 140415585382400, 140415585398783,
-STORE, 140415580979200, 140415583182847,
-SNULL, 140415580979200, 140415581081599,
-STORE, 140415581081600, 140415583182847,
-STORE, 140415580979200, 140415581081599,
-SNULL, 140415583174655, 140415583182847,
-STORE, 140415581081600, 140415583174655,
-STORE, 140415583174656, 140415583182847,
-ERASE, 140415583174656, 140415583182847,
-STORE, 140415583174656, 140415583182847,
-STORE, 140415578816512, 140415580979199,
-SNULL, 140415578816512, 140415578877951,
-STORE, 140415578877952, 140415580979199,
-STORE, 140415578816512, 140415578877951,
-SNULL, 140415580971007, 140415580979199,
-STORE, 140415578877952, 140415580971007,
-STORE, 140415580971008, 140415580979199,
-ERASE, 140415580971008, 140415580979199,
-STORE, 140415580971008, 140415580979199,
-STORE, 140415576563712, 140415578816511,
-SNULL, 140415576563712, 140415576715263,
-STORE, 140415576715264, 140415578816511,
-STORE, 140415576563712, 140415576715263,
-SNULL, 140415578808319, 140415578816511,
-STORE, 140415576715264, 140415578808319,
-STORE, 140415578808320, 140415578816511,
-ERASE, 140415578808320, 140415578816511,
-STORE, 140415578808320, 140415578816511,
-STORE, 140415574392832, 140415576563711,
-SNULL, 140415574392832, 140415574462463,
-STORE, 140415574462464, 140415576563711,
-STORE, 140415574392832, 140415574462463,
-SNULL, 140415576555519, 140415576563711,
-STORE, 140415574462464, 140415576555519,
-STORE, 140415576555520, 140415576563711,
-ERASE, 140415576555520, 140415576563711,
-STORE, 140415576555520, 140415576563711,
-STORE, 140415607910400, 140415607934975,
-STORE, 140415571230720, 140415574392831,
-SNULL, 140415571230720, 140415572291583,
-STORE, 140415572291584, 140415574392831,
-STORE, 140415571230720, 140415572291583,
-SNULL, 140415574384639, 140415574392831,
-STORE, 140415572291584, 140415574384639,
-STORE, 140415574384640, 140415574392831,
-ERASE, 140415574384640, 140415574392831,
-STORE, 140415574384640, 140415574392831,
-STORE, 140415607902208, 140415607934975,
-SNULL, 140415593476095, 140415593484287,
-STORE, 140415593459712, 140415593476095,
-STORE, 140415593476096, 140415593484287,
-SNULL, 140415574388735, 140415574392831,
-STORE, 140415574384640, 140415574388735,
-STORE, 140415574388736, 140415574392831,
-SNULL, 140415576559615, 140415576563711,
-STORE, 140415576555520, 140415576559615,
-STORE, 140415576559616, 140415576563711,
-SNULL, 140415589699583, 140415589703679,
-STORE, 140415589695488, 140415589699583,
-STORE, 140415589699584, 140415589703679,
-SNULL, 140415585378303, 140415585382399,
-STORE, 140415585374208, 140415585378303,
-STORE, 140415585378304, 140415585382399,
-SNULL, 140415578812415, 140415578816511,
-STORE, 140415578808320, 140415578812415,
-STORE, 140415578812416, 140415578816511,
-SNULL, 140415580975103, 140415580979199,
-STORE, 140415580971008, 140415580975103,
-STORE, 140415580975104, 140415580979199,
-SNULL, 140415583178751, 140415583182847,
-STORE, 140415583174656, 140415583178751,
-STORE, 140415583178752, 140415583182847,
-SNULL, 140415587577855, 140415587581951,
-STORE, 140415587573760, 140415587577855,
-STORE, 140415587577856, 140415587581951,
-SNULL, 140415595687935, 140415595692031,
-STORE, 140415595683840, 140415595687935,
-STORE, 140415595687936, 140415595692031,
-STORE, 140415607894016, 140415607934975,
-SNULL, 140415599345663, 140415599353855,
-STORE, 140415599304704, 140415599345663,
-STORE, 140415599345664, 140415599353855,
-SNULL, 140415603240959, 140415603245055,
-STORE, 140415603208192, 140415603240959,
-STORE, 140415603240960, 140415603245055,
-SNULL, 140415605719039, 140415605723135,
-STORE, 140415605710848, 140415605719039,
-STORE, 140415605719040, 140415605723135,
-SNULL, 94478499299327, 94478499303423,
-STORE, 94478499295232, 94478499299327,
-STORE, 94478499299328, 94478499303423,
-SNULL, 140415607967743, 140415607971839,
-STORE, 140415607963648, 140415607967743,
-STORE, 140415607967744, 140415607971839,
-ERASE, 140415607934976, 140415607963647,
-STORE, 94478511173632, 94478511378431,
-STORE, 140415606210560, 140415607894015,
-STORE, 140415607934976, 140415607963647,
-STORE, 94478511173632, 94478511513599,
-STORE, 94478511173632, 94478511648767,
-SNULL, 94478511615999, 94478511648767,
-STORE, 94478511173632, 94478511615999,
-STORE, 94478511616000, 94478511648767,
-ERASE, 94478511616000, 94478511648767,
-STORE, 94478511173632, 94478511751167,
-SNULL, 94478511747071, 94478511751167,
-STORE, 94478511173632, 94478511747071,
-STORE, 94478511747072, 94478511751167,
-ERASE, 94478511747072, 94478511751167,
-STORE, 94478511173632, 94478511882239,
-SNULL, 94478511878143, 94478511882239,
-STORE, 94478511173632, 94478511878143,
-STORE, 94478511878144, 94478511882239,
-ERASE, 94478511878144, 94478511882239,
-STORE, 94478511173632, 94478512013311,
-SNULL, 94478512009215, 94478512013311,
-STORE, 94478511173632, 94478512009215,
-STORE, 94478512009216, 94478512013311,
-ERASE, 94478512009216, 94478512013311,
-STORE, 94478511173632, 94478512144383,
-STORE, 94478511173632, 94478512279551,
-STORE, 140415606181888, 140415606210559,
-STORE, 140415569100800, 140415571230719,
-SNULL, 140415569100800, 140415569129471,
-STORE, 140415569129472, 140415571230719,
-STORE, 140415569100800, 140415569129471,
-SNULL, 140415571222527, 140415571230719,
-STORE, 140415569129472, 140415571222527,
-STORE, 140415571222528, 140415571230719,
-ERASE, 140415571222528, 140415571230719,
-STORE, 140415571222528, 140415571230719,
-STORE, 140415566905344, 140415569100799,
-SNULL, 140415566905344, 140415566987263,
-STORE, 140415566987264, 140415569100799,
-STORE, 140415566905344, 140415566987263,
-SNULL, 140415569084415, 140415569100799,
-STORE, 140415566987264, 140415569084415,
-STORE, 140415569084416, 140415569100799,
-SNULL, 140415569084416, 140415569092607,
-STORE, 140415569092608, 140415569100799,
-STORE, 140415569084416, 140415569092607,
-ERASE, 140415569084416, 140415569092607,
-STORE, 140415569084416, 140415569092607,
-ERASE, 140415569092608, 140415569100799,
-STORE, 140415569092608, 140415569100799,
-SNULL, 140415569088511, 140415569092607,
-STORE, 140415569084416, 140415569088511,
-STORE, 140415569088512, 140415569092607,
-SNULL, 140415571226623, 140415571230719,
-STORE, 140415571222528, 140415571226623,
-STORE, 140415571226624, 140415571230719,
-ERASE, 140415606181888, 140415606210559,
-STORE, 140415606181888, 140415606210559,
-STORE, 140415564759040, 140415566905343,
-SNULL, 140415564759040, 140415564804095,
-STORE, 140415564804096, 140415566905343,
-STORE, 140415564759040, 140415564804095,
-SNULL, 140415566897151, 140415566905343,
-STORE, 140415564804096, 140415566897151,
-STORE, 140415566897152, 140415566905343,
-ERASE, 140415566897152, 140415566905343,
-STORE, 140415566897152, 140415566905343,
-STORE, 140415562588160, 140415564759039,
-SNULL, 140415562588160, 140415562629119,
-STORE, 140415562629120, 140415564759039,
-STORE, 140415562588160, 140415562629119,
-SNULL, 140415564726271, 140415564759039,
-STORE, 140415562629120, 140415564726271,
-STORE, 140415564726272, 140415564759039,
-SNULL, 140415564726272, 140415564734463,
-STORE, 140415564734464, 140415564759039,
-STORE, 140415564726272, 140415564734463,
-ERASE, 140415564726272, 140415564734463,
-STORE, 140415564726272, 140415564734463,
-ERASE, 140415564734464, 140415564759039,
-STORE, 140415564734464, 140415564759039,
-SNULL, 140415564730367, 140415564734463,
-STORE, 140415564726272, 140415564730367,
-STORE, 140415564730368, 140415564734463,
-SNULL, 140415566901247, 140415566905343,
-STORE, 140415566897152, 140415566901247,
-STORE, 140415566901248, 140415566905343,
-ERASE, 140415606181888, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415605944320, 140415606210559,
-ERASE, 140415605944320, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 94478511173632, 94478512414719,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 140415606206464, 140415606210559,
-ERASE, 140415606206464, 140415606210559,
-STORE, 94478511173632, 94478512652287,
-STORE, 94478511173632, 94478512787455,
-STORE, 94478511173632, 94478512922623,
-STORE, 94478511173632, 94478513057791,
-STORE, 140415537422336, 140415562588159,
-STORE, 94478511173632, 94478513192959,
-STORE, 94478511173632, 94478513356799,
-STORE, 94478511173632, 94478513491967,
-STORE, 94478511173632, 94478513627135,
-STORE, 94478511173632, 94478513790975,
-STORE, 94478511173632, 94478513926143,
-STORE, 94478511173632, 94478514061311,
-STORE, 94478511173632, 94478514196479,
-STORE, 94478511173632, 94478514331647,
-STORE, 94478511173632, 94478514606079,
-STORE, 94478511173632, 94478514741247,
-STORE, 94478511173632, 94478514876415,
-STORE, 94478511173632, 94478515011583,
-STORE, 94478511173632, 94478515146751,
-STORE, 94478511173632, 94478515281919,
-STORE, 94478511173632, 94478515474431,
-STORE, 94478511173632, 94478515609599,
-STORE, 94478511173632, 94478515744767,
-STORE, 140415536922624, 140415562588159,
-STORE, 94478511173632, 94478515879935,
-STORE, 94478511173632, 94478516015103,
-STORE, 94478511173632, 94478516150271,
-STORE, 94478511173632, 94478516285439,
-STORE, 94478511173632, 94478516420607,
-STORE, 94478511173632, 94478516555775,
-STORE, 94478511173632, 94478516690943,
-STORE, 94478511173632, 94478516826111,
-STORE, 94478511173632, 94478516961279,
-STORE, 94478511173632, 94478517231615,
-STORE, 94478511173632, 94478517366783,
-STORE, 94478511173632, 94478517501951,
-STORE, 94478511173632, 94478517637119,
-STORE, 94478511173632, 94478517772287,
-STORE, 94478511173632, 94478517907455,
-STORE, 94478511173632, 94478518042623,
-STORE, 94478511173632, 94478518177791,
-STORE, 94478511173632, 94478518312959,
-STORE, 94478511173632, 94478518448127,
-STORE, 140415535910912, 140415562588159,
-SNULL, 140415536922623, 140415562588159,
-STORE, 140415535910912, 140415536922623,
-STORE, 140415536922624, 140415562588159,
-SNULL, 140415536922624, 140415537422335,
-STORE, 140415537422336, 140415562588159,
-STORE, 140415536922624, 140415537422335,
-ERASE, 140415536922624, 140415537422335,
-STORE, 94478511173632, 94478518583295,
-STORE, 94478511173632, 94478518718463,
-STORE, 94478511173632, 94478518853631,
-STORE, 94478511173632, 94478518988799,
-STORE, 94478511173632, 94478519123967,
-STORE, 94478511173632, 94478519259135,
-STORE, 140415509696512, 140415535910911,
-ERASE, 140415537422336, 140415562588159,
-STORE, 140415482433536, 140415509696511,
- };
- unsigned long set28[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140722475622400, 140737488351231,
-SNULL, 140722475626495, 140737488351231,
-STORE, 140722475622400, 140722475626495,
-STORE, 140722475491328, 140722475626495,
-STORE, 93865834291200, 93865836548095,
-SNULL, 93865834422271, 93865836548095,
-STORE, 93865834291200, 93865834422271,
-STORE, 93865834422272, 93865836548095,
-ERASE, 93865834422272, 93865836548095,
-STORE, 93865836519424, 93865836527615,
-STORE, 93865836527616, 93865836548095,
-STORE, 139918411104256, 139918413357055,
-SNULL, 139918411247615, 139918413357055,
-STORE, 139918411104256, 139918411247615,
-STORE, 139918411247616, 139918413357055,
-ERASE, 139918411247616, 139918413357055,
-STORE, 139918413344768, 139918413352959,
-STORE, 139918413352960, 139918413357055,
-STORE, 140722476642304, 140722476646399,
-STORE, 140722476630016, 140722476642303,
-STORE, 139918413316096, 139918413344767,
-STORE, 139918413307904, 139918413316095,
-STORE, 139918408888320, 139918411104255,
-SNULL, 139918408888320, 139918408986623,
-STORE, 139918408986624, 139918411104255,
-STORE, 139918408888320, 139918408986623,
-SNULL, 139918411079679, 139918411104255,
-STORE, 139918408986624, 139918411079679,
-STORE, 139918411079680, 139918411104255,
-SNULL, 139918411079680, 139918411087871,
-STORE, 139918411087872, 139918411104255,
-STORE, 139918411079680, 139918411087871,
-ERASE, 139918411079680, 139918411087871,
-STORE, 139918411079680, 139918411087871,
-ERASE, 139918411087872, 139918411104255,
-STORE, 139918411087872, 139918411104255,
-STORE, 139918405091328, 139918408888319,
-SNULL, 139918405091328, 139918406750207,
-STORE, 139918406750208, 139918408888319,
-STORE, 139918405091328, 139918406750207,
-SNULL, 139918408847359, 139918408888319,
-STORE, 139918406750208, 139918408847359,
-STORE, 139918408847360, 139918408888319,
-SNULL, 139918408847360, 139918408871935,
-STORE, 139918408871936, 139918408888319,
-STORE, 139918408847360, 139918408871935,
-ERASE, 139918408847360, 139918408871935,
-STORE, 139918408847360, 139918408871935,
-ERASE, 139918408871936, 139918408888319,
-STORE, 139918408871936, 139918408888319,
-STORE, 139918413299712, 139918413316095,
-SNULL, 139918408863743, 139918408871935,
-STORE, 139918408847360, 139918408863743,
-STORE, 139918408863744, 139918408871935,
-SNULL, 139918411083775, 139918411087871,
-STORE, 139918411079680, 139918411083775,
-STORE, 139918411083776, 139918411087871,
-SNULL, 93865836523519, 93865836527615,
-STORE, 93865836519424, 93865836523519,
-STORE, 93865836523520, 93865836527615,
-SNULL, 139918413348863, 139918413352959,
-STORE, 139918413344768, 139918413348863,
-STORE, 139918413348864, 139918413352959,
-ERASE, 139918413316096, 139918413344767,
-STORE, 93865848528896, 93865848664063,
- };
- unsigned long set29[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140734467944448, 140737488351231,
-SNULL, 140734467948543, 140737488351231,
-STORE, 140734467944448, 140734467948543,
-STORE, 140734467813376, 140734467948543,
-STORE, 94880407924736, 94880410177535,
-SNULL, 94880408055807, 94880410177535,
-STORE, 94880407924736, 94880408055807,
-STORE, 94880408055808, 94880410177535,
-ERASE, 94880408055808, 94880410177535,
-STORE, 94880410148864, 94880410157055,
-STORE, 94880410157056, 94880410177535,
-STORE, 140143367815168, 140143370067967,
-SNULL, 140143367958527, 140143370067967,
-STORE, 140143367815168, 140143367958527,
-STORE, 140143367958528, 140143370067967,
-ERASE, 140143367958528, 140143370067967,
-STORE, 140143370055680, 140143370063871,
-STORE, 140143370063872, 140143370067967,
-STORE, 140734468329472, 140734468333567,
-STORE, 140734468317184, 140734468329471,
-STORE, 140143370027008, 140143370055679,
-STORE, 140143370018816, 140143370027007,
-STORE, 140143365599232, 140143367815167,
-SNULL, 140143365599232, 140143365697535,
-STORE, 140143365697536, 140143367815167,
-STORE, 140143365599232, 140143365697535,
-SNULL, 140143367790591, 140143367815167,
-STORE, 140143365697536, 140143367790591,
-STORE, 140143367790592, 140143367815167,
-SNULL, 140143367790592, 140143367798783,
-STORE, 140143367798784, 140143367815167,
-STORE, 140143367790592, 140143367798783,
-ERASE, 140143367790592, 140143367798783,
-STORE, 140143367790592, 140143367798783,
-ERASE, 140143367798784, 140143367815167,
-STORE, 140143367798784, 140143367815167,
-STORE, 140143361802240, 140143365599231,
-SNULL, 140143361802240, 140143363461119,
-STORE, 140143363461120, 140143365599231,
-STORE, 140143361802240, 140143363461119,
-SNULL, 140143365558271, 140143365599231,
-STORE, 140143363461120, 140143365558271,
-STORE, 140143365558272, 140143365599231,
-SNULL, 140143365558272, 140143365582847,
-STORE, 140143365582848, 140143365599231,
-STORE, 140143365558272, 140143365582847,
-ERASE, 140143365558272, 140143365582847,
-STORE, 140143365558272, 140143365582847,
-ERASE, 140143365582848, 140143365599231,
-STORE, 140143365582848, 140143365599231,
-STORE, 140143370010624, 140143370027007,
-SNULL, 140143365574655, 140143365582847,
-STORE, 140143365558272, 140143365574655,
-STORE, 140143365574656, 140143365582847,
-SNULL, 140143367794687, 140143367798783,
-STORE, 140143367790592, 140143367794687,
-STORE, 140143367794688, 140143367798783,
-SNULL, 94880410152959, 94880410157055,
-STORE, 94880410148864, 94880410152959,
-STORE, 94880410152960, 94880410157055,
-SNULL, 140143370059775, 140143370063871,
-STORE, 140143370055680, 140143370059775,
-STORE, 140143370059776, 140143370063871,
-ERASE, 140143370027008, 140143370055679,
-STORE, 94880442400768, 94880442535935,
-STORE, 140143353409536, 140143361802239,
-SNULL, 140143353413631, 140143361802239,
-STORE, 140143353409536, 140143353413631,
-STORE, 140143353413632, 140143361802239,
-STORE, 140143345016832, 140143353409535,
-STORE, 140143210799104, 140143345016831,
-SNULL, 140143210799104, 140143239364607,
-STORE, 140143239364608, 140143345016831,
-STORE, 140143210799104, 140143239364607,
-ERASE, 140143210799104, 140143239364607,
-SNULL, 140143306473471, 140143345016831,
-STORE, 140143239364608, 140143306473471,
-STORE, 140143306473472, 140143345016831,
-ERASE, 140143306473472, 140143345016831,
-SNULL, 140143239499775, 140143306473471,
-STORE, 140143239364608, 140143239499775,
-STORE, 140143239499776, 140143306473471,
-SNULL, 140143345020927, 140143353409535,
-STORE, 140143345016832, 140143345020927,
-STORE, 140143345020928, 140143353409535,
-STORE, 140143336624128, 140143345016831,
-SNULL, 140143336628223, 140143345016831,
-STORE, 140143336624128, 140143336628223,
-STORE, 140143336628224, 140143345016831,
-STORE, 140143328231424, 140143336624127,
-SNULL, 140143328235519, 140143336624127,
-STORE, 140143328231424, 140143328235519,
-STORE, 140143328235520, 140143336624127,
-STORE, 140143319838720, 140143328231423,
-SNULL, 140143319842815, 140143328231423,
-STORE, 140143319838720, 140143319842815,
-STORE, 140143319842816, 140143328231423,
-STORE, 140143311446016, 140143319838719,
-STORE, 140143105146880, 140143239364607,
-STORE, 140143096754176, 140143105146879,
-STORE, 140143029645312, 140143096754175,
-ERASE, 140143029645312, 140143096754175,
-STORE, 140142962536448, 140143096754175,
-SNULL, 140142962536448, 140142970929151,
-STORE, 140142970929152, 140143096754175,
-STORE, 140142962536448, 140142970929151,
-ERASE, 140142962536448, 140142970929151,
-STORE, 140142962536448, 140142970929151,
-STORE, 140142828318720, 140142962536447,
-STORE, 140142819926016, 140142828318719,
-SNULL, 140142828318720, 140142836711423,
-STORE, 140142836711424, 140142962536447,
-STORE, 140142828318720, 140142836711423,
-ERASE, 140142828318720, 140142836711423,
-SNULL, 140143172255743, 140143239364607,
-STORE, 140143105146880, 140143172255743,
-STORE, 140143172255744, 140143239364607,
-ERASE, 140143172255744, 140143239364607,
-SNULL, 140143105282047, 140143172255743,
-STORE, 140143105146880, 140143105282047,
-STORE, 140143105282048, 140143172255743,
-SNULL, 140143038038015, 140143096754175,
-STORE, 140142970929152, 140143038038015,
-STORE, 140143038038016, 140143096754175,
-ERASE, 140143038038016, 140143096754175,
-SNULL, 140142971064319, 140143038038015,
-STORE, 140142970929152, 140142971064319,
-STORE, 140142971064320, 140143038038015,
-SNULL, 140142903820287, 140142962536447,
-STORE, 140142836711424, 140142903820287,
-STORE, 140142903820288, 140142962536447,
-ERASE, 140142903820288, 140142962536447,
-SNULL, 140142836846591, 140142903820287,
-STORE, 140142836711424, 140142836846591,
-STORE, 140142836846592, 140142903820287,
-STORE, 140142685708288, 140142819926015,
-SNULL, 140143311450111, 140143319838719,
-STORE, 140143311446016, 140143311450111,
-STORE, 140143311450112, 140143319838719,
-SNULL, 140142962540543, 140142970929151,
-STORE, 140142962536448, 140142962540543,
-STORE, 140142962540544, 140142970929151,
-SNULL, 140142685708288, 140142702493695,
-STORE, 140142702493696, 140142819926015,
-STORE, 140142685708288, 140142702493695,
-ERASE, 140142685708288, 140142702493695,
-SNULL, 140142769602559, 140142819926015,
-STORE, 140142702493696, 140142769602559,
-STORE, 140142769602560, 140142819926015,
-ERASE, 140142769602560, 140142819926015,
-SNULL, 140142702628863, 140142769602559,
-STORE, 140142702493696, 140142702628863,
-STORE, 140142702628864, 140142769602559,
-STORE, 140143230971904, 140143239364607,
-SNULL, 140143230975999, 140143239364607,
-STORE, 140143230971904, 140143230975999,
-STORE, 140143230976000, 140143239364607,
-SNULL, 140143096758271, 140143105146879,
-STORE, 140143096754176, 140143096758271,
-STORE, 140143096758272, 140143105146879,
-STORE, 140143222579200, 140143230971903,
-SNULL, 140143222583295, 140143230971903,
-STORE, 140143222579200, 140143222583295,
-STORE, 140143222583296, 140143230971903,
-STORE, 140143214186496, 140143222579199,
-SNULL, 140142819930111, 140142828318719,
-STORE, 140142819926016, 140142819930111,
-STORE, 140142819930112, 140142828318719,
-STORE, 140143205793792, 140143222579199,
-SNULL, 140143205793792, 140143214186495,
-STORE, 140143214186496, 140143222579199,
-STORE, 140143205793792, 140143214186495,
-SNULL, 140143214190591, 140143222579199,
-STORE, 140143214186496, 140143214190591,
-STORE, 140143214190592, 140143222579199,
-SNULL, 140143205797887, 140143214186495,
-STORE, 140143205793792, 140143205797887,
-STORE, 140143205797888, 140143214186495,
-STORE, 140143197401088, 140143205793791,
-SNULL, 140143197405183, 140143205793791,
-STORE, 140143197401088, 140143197405183,
-STORE, 140143197405184, 140143205793791,
-STORE, 140143189008384, 140143197401087,
-STORE, 140143180615680, 140143197401087,
-STORE, 140143088361472, 140143096754175,
-SNULL, 140143180619775, 140143197401087,
-STORE, 140143180615680, 140143180619775,
-STORE, 140143180619776, 140143197401087,
-SNULL, 140143180619776, 140143189008383,
-STORE, 140143189008384, 140143197401087,
-STORE, 140143180619776, 140143189008383,
-SNULL, 140143189012479, 140143197401087,
-STORE, 140143189008384, 140143189012479,
-STORE, 140143189012480, 140143197401087,
-SNULL, 140143088365567, 140143096754175,
-STORE, 140143088361472, 140143088365567,
-STORE, 140143088365568, 140143096754175,
-STORE, 140143079968768, 140143088361471,
-SNULL, 140143079972863, 140143088361471,
-STORE, 140143079968768, 140143079972863,
-STORE, 140143079972864, 140143088361471,
-STORE, 140143071576064, 140143079968767,
-SNULL, 140143071580159, 140143079968767,
-STORE, 140143071576064, 140143071580159,
-STORE, 140143071580160, 140143079968767,
-STORE, 140143063183360, 140143071576063,
-STORE, 140143054790656, 140143071576063,
-SNULL, 140143054794751, 140143071576063,
-STORE, 140143054790656, 140143054794751,
-STORE, 140143054794752, 140143071576063,
-SNULL, 140143054794752, 140143063183359,
-STORE, 140143063183360, 140143071576063,
-STORE, 140143054794752, 140143063183359,
-SNULL, 140143063187455, 140143071576063,
-STORE, 140143063183360, 140143063187455,
-STORE, 140143063187456, 140143071576063,
-STORE, 140143046397952, 140143054790655,
-STORE, 140142954143744, 140142962536447,
-STORE, 140142945751040, 140142962536447,
-STORE, 140142937358336, 140142962536447,
-STORE, 140142928965632, 140142962536447,
-STORE, 140142568275968, 140142702493695,
-SNULL, 140142635384831, 140142702493695,
-STORE, 140142568275968, 140142635384831,
-STORE, 140142635384832, 140142702493695,
-ERASE, 140142635384832, 140142702493695,
-STORE, 140142920572928, 140142962536447,
-STORE, 140142912180224, 140142962536447,
-STORE, 140142568275968, 140142702493695,
-SNULL, 140142568275968, 140142635384831,
-STORE, 140142635384832, 140142702493695,
-STORE, 140142568275968, 140142635384831,
-SNULL, 140142635519999, 140142702493695,
-STORE, 140142635384832, 140142635519999,
-STORE, 140142635520000, 140142702493695,
-STORE, 140142819930112, 140142836711423,
-STORE, 140142811533312, 140142819926015,
-STORE, 140142434058240, 140142635384831,
-SNULL, 140142501167103, 140142635384831,
-STORE, 140142434058240, 140142501167103,
-STORE, 140142501167104, 140142635384831,
-SNULL, 140142501167104, 140142568275967,
-STORE, 140142568275968, 140142635384831,
-STORE, 140142501167104, 140142568275967,
-ERASE, 140142501167104, 140142568275967,
-STORE, 140142299840512, 140142501167103,
-STORE, 140142803140608, 140142819926015,
-SNULL, 140142366949375, 140142501167103,
-STORE, 140142299840512, 140142366949375,
-STORE, 140142366949376, 140142501167103,
-SNULL, 140142366949376, 140142434058239,
-STORE, 140142434058240, 140142501167103,
-STORE, 140142366949376, 140142434058239,
-ERASE, 140142366949376, 140142434058239,
-STORE, 140142794747904, 140142819926015,
-STORE, 140142786355200, 140142819926015,
-STORE, 140142299840512, 140142501167103,
-STORE, 140142777962496, 140142819926015,
-STORE, 140142559883264, 140142568275967,
-STORE, 140142232731648, 140142501167103,
-STORE, 140142551490560, 140142568275967,
-SNULL, 140142777962496, 140142803140607,
-STORE, 140142803140608, 140142819926015,
-STORE, 140142777962496, 140142803140607,
-SNULL, 140142803144703, 140142819926015,
-STORE, 140142803140608, 140142803144703,
-STORE, 140142803144704, 140142819926015,
-STORE, 140142543097856, 140142568275967,
-STORE, 140142098513920, 140142501167103,
-SNULL, 140142165622783, 140142501167103,
-STORE, 140142098513920, 140142165622783,
-STORE, 140142165622784, 140142501167103,
-SNULL, 140142165622784, 140142232731647,
-STORE, 140142232731648, 140142501167103,
-STORE, 140142165622784, 140142232731647,
-ERASE, 140142165622784, 140142232731647,
-SNULL, 140142568411135, 140142635384831,
-STORE, 140142568275968, 140142568411135,
-STORE, 140142568411136, 140142635384831,
-STORE, 140141964296192, 140142165622783,
-SNULL, 140142912180224, 140142928965631,
-STORE, 140142928965632, 140142962536447,
-STORE, 140142912180224, 140142928965631,
-SNULL, 140142928969727, 140142962536447,
-STORE, 140142928965632, 140142928969727,
-STORE, 140142928969728, 140142962536447,
-STORE, 140141830078464, 140142165622783,
-SNULL, 140142912184319, 140142928965631,
-STORE, 140142912180224, 140142912184319,
-STORE, 140142912184320, 140142928965631,
-SNULL, 140142232731648, 140142434058239,
-STORE, 140142434058240, 140142501167103,
-STORE, 140142232731648, 140142434058239,
-SNULL, 140142434193407, 140142501167103,
-STORE, 140142434058240, 140142434193407,
-STORE, 140142434193408, 140142501167103,
-SNULL, 140142232731648, 140142299840511,
-STORE, 140142299840512, 140142434058239,
-STORE, 140142232731648, 140142299840511,
-SNULL, 140142299975679, 140142434058239,
-STORE, 140142299840512, 140142299975679,
-STORE, 140142299975680, 140142434058239,
-SNULL, 140142928969728, 140142954143743,
-STORE, 140142954143744, 140142962536447,
-STORE, 140142928969728, 140142954143743,
-SNULL, 140142954147839, 140142962536447,
-STORE, 140142954143744, 140142954147839,
-STORE, 140142954147840, 140142962536447,
-STORE, 140141830078464, 140142299840511,
-SNULL, 140142543097856, 140142559883263,
-STORE, 140142559883264, 140142568275967,
-STORE, 140142543097856, 140142559883263,
-SNULL, 140142559887359, 140142568275967,
-STORE, 140142559883264, 140142559887359,
-STORE, 140142559887360, 140142568275967,
-STORE, 140142534705152, 140142559883263,
-SNULL, 140142928969728, 140142945751039,
-STORE, 140142945751040, 140142954143743,
-STORE, 140142928969728, 140142945751039,
-SNULL, 140142945755135, 140142954143743,
-STORE, 140142945751040, 140142945755135,
-STORE, 140142945755136, 140142954143743,
-SNULL, 140142299975680, 140142366949375,
-STORE, 140142366949376, 140142434058239,
-STORE, 140142299975680, 140142366949375,
-SNULL, 140142367084543, 140142434058239,
-STORE, 140142366949376, 140142367084543,
-STORE, 140142367084544, 140142434058239,
-SNULL, 140142928969728, 140142937358335,
-STORE, 140142937358336, 140142945751039,
-STORE, 140142928969728, 140142937358335,
-SNULL, 140142937362431, 140142945751039,
-STORE, 140142937358336, 140142937362431,
-STORE, 140142937362432, 140142945751039,
-SNULL, 140141830078464, 140142232731647,
-STORE, 140142232731648, 140142299840511,
-STORE, 140141830078464, 140142232731647,
-SNULL, 140142232866815, 140142299840511,
-STORE, 140142232731648, 140142232866815,
-STORE, 140142232866816, 140142299840511,
-SNULL, 140142534705152, 140142543097855,
-STORE, 140142543097856, 140142559883263,
-STORE, 140142534705152, 140142543097855,
-SNULL, 140142543101951, 140142559883263,
-STORE, 140142543097856, 140142543101951,
-STORE, 140142543101952, 140142559883263,
-STORE, 140142526312448, 140142543097855,
-STORE, 140142517919744, 140142543097855,
-SNULL, 140141830078464, 140142098513919,
-STORE, 140142098513920, 140142232731647,
-STORE, 140141830078464, 140142098513919,
-SNULL, 140142098649087, 140142232731647,
-STORE, 140142098513920, 140142098649087,
-STORE, 140142098649088, 140142232731647,
-SNULL, 140142031405055, 140142098513919,
-STORE, 140141830078464, 140142031405055,
-STORE, 140142031405056, 140142098513919,
-ERASE, 140142031405056, 140142098513919,
-SNULL, 140141830078464, 140141964296191,
-STORE, 140141964296192, 140142031405055,
-STORE, 140141830078464, 140141964296191,
-SNULL, 140141964431359, 140142031405055,
-STORE, 140141964296192, 140141964431359,
-STORE, 140141964431360, 140142031405055,
-STORE, 140142509527040, 140142543097855,
-SNULL, 140141897187327, 140141964296191,
-STORE, 140141830078464, 140141897187327,
-STORE, 140141897187328, 140141964296191,
-ERASE, 140141897187328, 140141964296191,
-SNULL, 140141830213631, 140141897187327,
-STORE, 140141830078464, 140141830213631,
-STORE, 140141830213632, 140141897187327,
-SNULL, 140142803144704, 140142811533311,
-STORE, 140142811533312, 140142819926015,
-STORE, 140142803144704, 140142811533311,
-SNULL, 140142811537407, 140142819926015,
-STORE, 140142811533312, 140142811537407,
-STORE, 140142811537408, 140142819926015,
-SNULL, 140142098649088, 140142165622783,
-STORE, 140142165622784, 140142232731647,
-STORE, 140142098649088, 140142165622783,
-SNULL, 140142165757951, 140142232731647,
-STORE, 140142165622784, 140142165757951,
-STORE, 140142165757952, 140142232731647,
-STORE, 140142090121216, 140142098513919,
-SNULL, 140142777962496, 140142786355199,
-STORE, 140142786355200, 140142803140607,
-STORE, 140142777962496, 140142786355199,
-SNULL, 140142786359295, 140142803140607,
-STORE, 140142786355200, 140142786359295,
-STORE, 140142786359296, 140142803140607,
-SNULL, 140142509527040, 140142534705151,
-STORE, 140142534705152, 140142543097855,
-STORE, 140142509527040, 140142534705151,
-SNULL, 140142534709247, 140142543097855,
-STORE, 140142534705152, 140142534709247,
-STORE, 140142534709248, 140142543097855,
-STORE, 140142081728512, 140142098513919,
-SNULL, 140142786359296, 140142794747903,
-STORE, 140142794747904, 140142803140607,
-STORE, 140142786359296, 140142794747903,
-SNULL, 140142794751999, 140142803140607,
-STORE, 140142794747904, 140142794751999,
-STORE, 140142794752000, 140142803140607,
-STORE, 140142073335808, 140142098513919,
-SNULL, 140142073339903, 140142098513919,
-STORE, 140142073335808, 140142073339903,
-STORE, 140142073339904, 140142098513919,
-SNULL, 140142543101952, 140142551490559,
-STORE, 140142551490560, 140142559883263,
-STORE, 140142543101952, 140142551490559,
-SNULL, 140142551494655, 140142559883263,
-STORE, 140142551490560, 140142551494655,
-STORE, 140142551494656, 140142559883263,
-SNULL, 140142509527040, 140142517919743,
-STORE, 140142517919744, 140142534705151,
-STORE, 140142509527040, 140142517919743,
-SNULL, 140142517923839, 140142534705151,
-STORE, 140142517919744, 140142517923839,
-STORE, 140142517923840, 140142534705151,
-STORE, 140142064943104, 140142073335807,
-SNULL, 140142073339904, 140142090121215,
-STORE, 140142090121216, 140142098513919,
-STORE, 140142073339904, 140142090121215,
-SNULL, 140142090125311, 140142098513919,
-STORE, 140142090121216, 140142090125311,
-STORE, 140142090125312, 140142098513919,
-STORE, 140142056550400, 140142073335807,
-SNULL, 140142056554495, 140142073335807,
-STORE, 140142056550400, 140142056554495,
-STORE, 140142056554496, 140142073335807,
-STORE, 140142048157696, 140142056550399,
-SNULL, 140142509531135, 140142517919743,
-STORE, 140142509527040, 140142509531135,
-STORE, 140142509531136, 140142517919743,
-SNULL, 140142777966591, 140142786355199,
-STORE, 140142777962496, 140142777966591,
-STORE, 140142777966592, 140142786355199,
-SNULL, 140143046402047, 140143054790655,
-STORE, 140143046397952, 140143046402047,
-STORE, 140143046402048, 140143054790655,
-SNULL, 140142912184320, 140142920572927,
-STORE, 140142920572928, 140142928965631,
-STORE, 140142912184320, 140142920572927,
-SNULL, 140142920577023, 140142928965631,
-STORE, 140142920572928, 140142920577023,
-STORE, 140142920577024, 140142928965631,
-STORE, 140142039764992, 140142056550399,
-STORE, 140141955903488, 140141964296191,
-SNULL, 140142819930112, 140142828318719,
-STORE, 140142828318720, 140142836711423,
-STORE, 140142819930112, 140142828318719,
-SNULL, 140142828322815, 140142836711423,
-STORE, 140142828318720, 140142828322815,
-STORE, 140142828322816, 140142836711423,
-SNULL, 140142517923840, 140142526312447,
-STORE, 140142526312448, 140142534705151,
-STORE, 140142517923840, 140142526312447,
-SNULL, 140142526316543, 140142534705151,
-STORE, 140142526312448, 140142526316543,
-STORE, 140142526316544, 140142534705151,
-STORE, 140141947510784, 140141964296191,
-SNULL, 140142056554496, 140142064943103,
-STORE, 140142064943104, 140142073335807,
-STORE, 140142056554496, 140142064943103,
-SNULL, 140142064947199, 140142073335807,
-STORE, 140142064943104, 140142064947199,
-STORE, 140142064947200, 140142073335807,
-SNULL, 140142073339904, 140142081728511,
-STORE, 140142081728512, 140142090121215,
-STORE, 140142073339904, 140142081728511,
-SNULL, 140142081732607, 140142090121215,
-STORE, 140142081728512, 140142081732607,
-STORE, 140142081732608, 140142090121215,
-STORE, 140141939118080, 140141964296191,
-STORE, 140141930725376, 140141964296191,
-STORE, 140141922332672, 140141964296191,
-STORE, 140141913939968, 140141964296191,
-SNULL, 140141913939968, 140141922332671,
-STORE, 140141922332672, 140141964296191,
-STORE, 140141913939968, 140141922332671,
-SNULL, 140141922336767, 140141964296191,
-STORE, 140141922332672, 140141922336767,
-STORE, 140141922336768, 140141964296191,
-STORE, 140141905547264, 140141922332671,
-SNULL, 140141905551359, 140141922332671,
-STORE, 140141905547264, 140141905551359,
-STORE, 140141905551360, 140141922332671,
-STORE, 140141821685760, 140141830078463,
-STORE, 140141813293056, 140141830078463,
-STORE, 140141804900352, 140141830078463,
-STORE, 140141796507648, 140141830078463,
-SNULL, 140141796511743, 140141830078463,
-STORE, 140141796507648, 140141796511743,
-STORE, 140141796511744, 140141830078463,
-SNULL, 140141922336768, 140141955903487,
-STORE, 140141955903488, 140141964296191,
-STORE, 140141922336768, 140141955903487,
-SNULL, 140141955907583, 140141964296191,
-STORE, 140141955903488, 140141955907583,
-STORE, 140141955907584, 140141964296191,
-STORE, 140141788114944, 140141796507647,
-STORE, 140141779722240, 140141796507647,
-SNULL, 140141779722240, 140141788114943,
-STORE, 140141788114944, 140141796507647,
-STORE, 140141779722240, 140141788114943,
-SNULL, 140141788119039, 140141796507647,
-STORE, 140141788114944, 140141788119039,
-STORE, 140141788119040, 140141796507647,
-SNULL, 140141922336768, 140141947510783,
-STORE, 140141947510784, 140141955903487,
-STORE, 140141922336768, 140141947510783,
-SNULL, 140141947514879, 140141955903487,
-STORE, 140141947510784, 140141947514879,
-STORE, 140141947514880, 140141955903487,
-SNULL, 140142039764992, 140142048157695,
-STORE, 140142048157696, 140142056550399,
-STORE, 140142039764992, 140142048157695,
-SNULL, 140142048161791, 140142056550399,
-STORE, 140142048157696, 140142048161791,
-STORE, 140142048161792, 140142056550399,
-SNULL, 140142039769087, 140142048157695,
-STORE, 140142039764992, 140142039769087,
-STORE, 140142039769088, 140142048157695,
-SNULL, 140141796511744, 140141804900351,
-STORE, 140141804900352, 140141830078463,
-STORE, 140141796511744, 140141804900351,
-SNULL, 140141804904447, 140141830078463,
-STORE, 140141804900352, 140141804904447,
-STORE, 140141804904448, 140141830078463,
-STORE, 140141771329536, 140141788114943,
-STORE, 140141762936832, 140141788114943,
-STORE, 140141754544128, 140141788114943,
-SNULL, 140141804904448, 140141821685759,
-STORE, 140141821685760, 140141830078463,
-STORE, 140141804904448, 140141821685759,
-SNULL, 140141821689855, 140141830078463,
-STORE, 140141821685760, 140141821689855,
-STORE, 140141821689856, 140141830078463,
-SNULL, 140141922336768, 140141939118079,
-STORE, 140141939118080, 140141947510783,
-STORE, 140141922336768, 140141939118079,
-SNULL, 140141939122175, 140141947510783,
-STORE, 140141939118080, 140141939122175,
-STORE, 140141939122176, 140141947510783,
-SNULL, 140141905551360, 140141913939967,
-STORE, 140141913939968, 140141922332671,
-STORE, 140141905551360, 140141913939967,
-SNULL, 140141913944063, 140141922332671,
-STORE, 140141913939968, 140141913944063,
-STORE, 140141913944064, 140141922332671,
-STORE, 140141746151424, 140141788114943,
-STORE, 140141737758720, 140141788114943,
-SNULL, 140141804904448, 140141813293055,
-STORE, 140141813293056, 140141821685759,
-STORE, 140141804904448, 140141813293055,
-SNULL, 140141813297151, 140141821685759,
-STORE, 140141813293056, 140141813297151,
-STORE, 140141813297152, 140141821685759,
-STORE, 140141729366016, 140141788114943,
-STORE, 140141720973312, 140141788114943,
-STORE, 140141712580608, 140141788114943,
-SNULL, 140141712584703, 140141788114943,
-STORE, 140141712580608, 140141712584703,
-STORE, 140141712584704, 140141788114943,
-SNULL, 140141922336768, 140141930725375,
-STORE, 140141930725376, 140141939118079,
-STORE, 140141922336768, 140141930725375,
-SNULL, 140141930729471, 140141939118079,
-STORE, 140141930725376, 140141930729471,
-STORE, 140141930729472, 140141939118079,
-STORE, 140141704187904, 140141712580607,
-SNULL, 140141704191999, 140141712580607,
-STORE, 140141704187904, 140141704191999,
-STORE, 140141704192000, 140141712580607,
-STORE, 140141695795200, 140141704187903,
-STORE, 140141687402496, 140141704187903,
-SNULL, 140141712584704, 140141771329535,
-STORE, 140141771329536, 140141788114943,
-STORE, 140141712584704, 140141771329535,
-SNULL, 140141771333631, 140141788114943,
-STORE, 140141771329536, 140141771333631,
-STORE, 140141771333632, 140141788114943,
-SNULL, 140141771333632, 140141779722239,
-STORE, 140141779722240, 140141788114943,
-STORE, 140141771333632, 140141779722239,
-SNULL, 140141779726335, 140141788114943,
-STORE, 140141779722240, 140141779726335,
-STORE, 140141779726336, 140141788114943,
-STORE, 140141679009792, 140141704187903,
-SNULL, 140141679013887, 140141704187903,
-STORE, 140141679009792, 140141679013887,
-STORE, 140141679013888, 140141704187903,
-STORE, 140141670617088, 140141679009791,
-SNULL, 140141670621183, 140141679009791,
-STORE, 140141670617088, 140141670621183,
-STORE, 140141670621184, 140141679009791,
-STORE, 140141662224384, 140141670617087,
-SNULL, 140141712584704, 140141737758719,
-STORE, 140141737758720, 140141771329535,
-STORE, 140141712584704, 140141737758719,
-SNULL, 140141737762815, 140141771329535,
-STORE, 140141737758720, 140141737762815,
-STORE, 140141737762816, 140141771329535,
-SNULL, 140141712584704, 140141729366015,
-STORE, 140141729366016, 140141737758719,
-STORE, 140141712584704, 140141729366015,
-SNULL, 140141729370111, 140141737758719,
-STORE, 140141729366016, 140141729370111,
-STORE, 140141729370112, 140141737758719,
-SNULL, 140141737762816, 140141746151423,
-STORE, 140141746151424, 140141771329535,
-STORE, 140141737762816, 140141746151423,
-SNULL, 140141746155519, 140141771329535,
-STORE, 140141746151424, 140141746155519,
-STORE, 140141746155520, 140141771329535,
-STORE, 140141653831680, 140141670617087,
-SNULL, 140141746155520, 140141762936831,
-STORE, 140141762936832, 140141771329535,
-STORE, 140141746155520, 140141762936831,
-SNULL, 140141762940927, 140141771329535,
-STORE, 140141762936832, 140141762940927,
-STORE, 140141762940928, 140141771329535,
-STORE, 140141645438976, 140141670617087,
-SNULL, 140141645443071, 140141670617087,
-STORE, 140141645438976, 140141645443071,
-STORE, 140141645443072, 140141670617087,
-SNULL, 140141712584704, 140141720973311,
-STORE, 140141720973312, 140141729366015,
-STORE, 140141712584704, 140141720973311,
-SNULL, 140141720977407, 140141729366015,
-STORE, 140141720973312, 140141720977407,
-STORE, 140141720977408, 140141729366015,
-STORE, 140141637046272, 140141645438975,
-SNULL, 140141637050367, 140141645438975,
-STORE, 140141637046272, 140141637050367,
-STORE, 140141637050368, 140141645438975,
-STORE, 140141628653568, 140141637046271,
-SNULL, 140141628657663, 140141637046271,
-STORE, 140141628653568, 140141628657663,
-STORE, 140141628657664, 140141637046271,
-STORE, 140141620260864, 140141628653567,
-SNULL, 140141679013888, 140141687402495,
-STORE, 140141687402496, 140141704187903,
-STORE, 140141679013888, 140141687402495,
-SNULL, 140141687406591, 140141704187903,
-STORE, 140141687402496, 140141687406591,
-STORE, 140141687406592, 140141704187903,
-SNULL, 140141746155520, 140141754544127,
-STORE, 140141754544128, 140141762936831,
-STORE, 140141746155520, 140141754544127,
-SNULL, 140141754548223, 140141762936831,
-STORE, 140141754544128, 140141754548223,
-STORE, 140141754548224, 140141762936831,
-SNULL, 140141687406592, 140141695795199,
-STORE, 140141695795200, 140141704187903,
-STORE, 140141687406592, 140141695795199,
-SNULL, 140141695799295, 140141704187903,
-STORE, 140141695795200, 140141695799295,
-STORE, 140141695799296, 140141704187903,
-STORE, 140141611868160, 140141628653567,
-SNULL, 140141611872255, 140141628653567,
-STORE, 140141611868160, 140141611872255,
-STORE, 140141611872256, 140141628653567,
-SNULL, 140141645443072, 140141662224383,
-STORE, 140141662224384, 140141670617087,
-STORE, 140141645443072, 140141662224383,
-SNULL, 140141662228479, 140141670617087,
-STORE, 140141662224384, 140141662228479,
-STORE, 140141662228480, 140141670617087,
-STORE, 140141603475456, 140141611868159,
-SNULL, 140141603479551, 140141611868159,
-STORE, 140141603475456, 140141603479551,
-STORE, 140141603479552, 140141611868159,
-STORE, 140141595082752, 140141603475455,
-SNULL, 140141645443072, 140141653831679,
-STORE, 140141653831680, 140141662224383,
-STORE, 140141645443072, 140141653831679,
-SNULL, 140141653835775, 140141662224383,
-STORE, 140141653831680, 140141653835775,
-STORE, 140141653835776, 140141662224383,
-STORE, 140141586690048, 140141603475455,
-SNULL, 140141611872256, 140141620260863,
-STORE, 140141620260864, 140141628653567,
-STORE, 140141611872256, 140141620260863,
-SNULL, 140141620264959, 140141628653567,
-STORE, 140141620260864, 140141620264959,
-STORE, 140141620264960, 140141628653567,
-SNULL, 140141586690048, 140141595082751,
-STORE, 140141595082752, 140141603475455,
-STORE, 140141586690048, 140141595082751,
-SNULL, 140141595086847, 140141603475455,
-STORE, 140141595082752, 140141595086847,
-STORE, 140141595086848, 140141603475455,
-STORE, 140141578297344, 140141595082751,
-SNULL, 140141578301439, 140141595082751,
-STORE, 140141578297344, 140141578301439,
-STORE, 140141578301440, 140141595082751,
-SNULL, 140141578301440, 140141586690047,
-STORE, 140141586690048, 140141595082751,
-STORE, 140141578301440, 140141586690047,
-SNULL, 140141586694143, 140141595082751,
-STORE, 140141586690048, 140141586694143,
-STORE, 140141586694144, 140141595082751,
-STORE, 140143370027008, 140143370055679,
-STORE, 140143309254656, 140143311446015,
-SNULL, 140143309254656, 140143309344767,
-STORE, 140143309344768, 140143311446015,
-STORE, 140143309254656, 140143309344767,
-SNULL, 140143311437823, 140143311446015,
-STORE, 140143309344768, 140143311437823,
-STORE, 140143311437824, 140143311446015,
-ERASE, 140143311437824, 140143311446015,
-STORE, 140143311437824, 140143311446015,
-SNULL, 140143311441919, 140143311446015,
-STORE, 140143311437824, 140143311441919,
-STORE, 140143311441920, 140143311446015,
-ERASE, 140143370027008, 140143370055679,
-ERASE, 140142912180224, 140142912184319,
-ERASE, 140142912184320, 140142920572927,
-ERASE, 140142945751040, 140142945755135,
-ERASE, 140142945755136, 140142954143743,
-ERASE, 140142090121216, 140142090125311,
-ERASE, 140142090125312, 140142098513919,
-ERASE, 140142794747904, 140142794751999,
-ERASE, 140142794752000, 140142803140607,
-ERASE, 140141913939968, 140141913944063,
-ERASE, 140141913944064, 140141922332671,
-ERASE, 140141746151424, 140141746155519,
-ERASE, 140141746155520, 140141754544127,
-ERASE, 140142954143744, 140142954147839,
-ERASE, 140142954147840, 140142962536447,
-ERASE, 140142081728512, 140142081732607,
-ERASE, 140142081732608, 140142090121215,
-ERASE, 140141905547264, 140141905551359,
-ERASE, 140141905551360, 140141913939967,
-ERASE, 140141729366016, 140141729370111,
-ERASE, 140141729370112, 140141737758719,
-ERASE, 140142920572928, 140142920577023,
-ERASE, 140142920577024, 140142928965631,
-ERASE, 140142039764992, 140142039769087,
-ERASE, 140142039769088, 140142048157695,
-ERASE, 140141679009792, 140141679013887,
-ERASE, 140141679013888, 140141687402495,
-ERASE, 140142551490560, 140142551494655,
-ERASE, 140142551494656, 140142559883263,
-ERASE, 140141947510784, 140141947514879,
-ERASE, 140141947514880, 140141955903487,
-ERASE, 140141771329536, 140141771333631,
-ERASE, 140141771333632, 140141779722239,
-ERASE, 140142928965632, 140142928969727,
-ERASE, 140142928969728, 140142937358335,
-ERASE, 140142073335808, 140142073339903,
-ERASE, 140142073339904, 140142081728511,
-ERASE, 140142543097856, 140142543101951,
-ERASE, 140142543101952, 140142551490559,
-ERASE, 140141955903488, 140141955907583,
-ERASE, 140141955907584, 140141964296191,
-ERASE, 140141704187904, 140141704191999,
-ERASE, 140141704192000, 140141712580607,
-ERASE, 140142786355200, 140142786359295,
-ERASE, 140142786359296, 140142794747903,
-ERASE, 140142056550400, 140142056554495,
-ERASE, 140142056554496, 140142064943103,
-ERASE, 140142828318720, 140142828322815,
-ERASE, 140142828322816, 140142836711423,
-ERASE, 140141788114944, 140141788119039,
-ERASE, 140141788119040, 140141796507647,
-ERASE, 140141695795200, 140141695799295,
-ERASE, 140141695799296, 140141704187903,
-ERASE, 140141578297344, 140141578301439,
-ERASE, 140141578301440, 140141586690047,
-ERASE, 140141611868160, 140141611872255,
-ERASE, 140141611872256, 140141620260863,
-ERASE, 140142811533312, 140142811537407,
-ERASE, 140142811537408, 140142819926015,
-ERASE, 140142064943104, 140142064947199,
-ERASE, 140142064947200, 140142073335807,
-ERASE, 140141628653568, 140141628657663,
-ERASE, 140141628657664, 140141637046271,
-ERASE, 140143046397952, 140143046402047,
-ERASE, 140143046402048, 140143054790655,
-ERASE, 140141796507648, 140141796511743,
-ERASE, 140141796511744, 140141804900351,
-ERASE, 140142803140608, 140142803144703,
-ERASE, 140142803144704, 140142811533311,
-ERASE, 140142509527040, 140142509531135,
-ERASE, 140142509531136, 140142517919743,
-ERASE, 140141821685760, 140141821689855,
-ERASE, 140141821689856, 140141830078463,
-ERASE, 140142777962496, 140142777966591,
-ERASE, 140142777966592, 140142786355199,
-ERASE, 140141804900352, 140141804904447,
-ERASE, 140141804904448, 140141813293055,
-ERASE, 140141930725376, 140141930729471,
-ERASE, 140141930729472, 140141939118079,
-ERASE, 140142937358336, 140142937362431,
-ERASE, 140142937362432, 140142945751039,
-ERASE, 140142559883264, 140142559887359,
-ERASE, 140142559887360, 140142568275967,
-ERASE, 140142534705152, 140142534709247,
-ERASE, 140142534709248, 140142543097855,
-ERASE, 140142048157696, 140142048161791,
-ERASE, 140142048161792, 140142056550399,
-ERASE, 140141754544128, 140141754548223,
-ERASE, 140141754548224, 140141762936831,
-ERASE, 140141939118080, 140141939122175,
-ERASE, 140141939122176, 140141947510783,
-ERASE, 140141653831680, 140141653835775,
-ERASE, 140141653835776, 140141662224383,
-ERASE, 140141712580608, 140141712584703,
-ERASE, 140141712584704, 140141720973311,
-ERASE, 140141645438976, 140141645443071,
-ERASE, 140141645443072, 140141653831679,
-ERASE, 140141687402496, 140141687406591,
-ERASE, 140141687406592, 140141695795199,
-ERASE, 140141662224384, 140141662228479,
-ERASE, 140141662228480, 140141670617087,
-ERASE, 140141922332672, 140141922336767,
-ERASE, 140141922336768, 140141930725375,
-ERASE, 140141737758720, 140141737762815,
-ERASE, 140141737762816, 140141746151423,
-ERASE, 140141637046272, 140141637050367,
-ERASE, 140141637050368, 140141645438975,
-ERASE, 140142517919744, 140142517923839,
-ERASE, 140142517923840, 140142526312447,
-ERASE, 140143096754176, 140143096758271,
-ERASE, 140143096758272, 140143105146879,
-ERASE, 140141595082752, 140141595086847,
-ERASE, 140141595086848, 140141603475455,
-ERASE, 140141762936832, 140141762940927,
-ERASE, 140141762940928, 140141771329535,
-ERASE, 140143311446016, 140143311450111,
-ERASE, 140143311450112, 140143319838719,
-ERASE, 140142526312448, 140142526316543,
-ERASE, 140142526316544, 140142534705151,
-ERASE, 140142819926016, 140142819930111,
-ERASE, 140142819930112, 140142828318719,
-ERASE, 140143180615680, 140143180619775,
-ERASE, 140143180619776, 140143189008383,
-ERASE, 140142962536448, 140142962540543,
-ERASE, 140142962540544, 140142970929151,
-ERASE, 140143214186496, 140143214190591,
-ERASE, 140143214190592, 140143222579199,
-ERASE, 140143088361472, 140143088365567,
-ERASE, 140143088365568, 140143096754175,
-ERASE, 140141586690048, 140141586694143,
-ERASE, 140141586694144, 140141595082751,
-ERASE, 140143230971904, 140143230975999,
-ERASE, 140143230976000, 140143239364607,
-ERASE, 140141779722240, 140141779726335,
-ERASE, 140141779726336, 140141788114943,
-ERASE, 140141670617088, 140141670621183,
-ERASE, 140141670621184, 140141679009791,
-ERASE, 140141813293056, 140141813297151,
-ERASE, 140141813297152, 140141821685759,
-ERASE, 140143222579200, 140143222583295,
-ERASE, 140143222583296, 140143230971903,
-ERASE, 140143189008384, 140143189012479,
-ERASE, 140143189012480, 140143197401087,
-ERASE, 140143071576064, 140143071580159,
-ERASE, 140143071580160, 140143079968767,
-ERASE, 140141620260864, 140141620264959,
-ERASE, 140141620264960, 140141628653567,
-ERASE, 140141603475456, 140141603479551,
-ERASE, 140141603479552, 140141611868159,
-ERASE, 140141720973312, 140141720977407,
-ERASE, 140141720977408, 140141729366015,
-ERASE, 140143079968768, 140143079972863,
-ERASE, 140143079972864, 140143088361471,
-ERASE, 140143205793792, 140143205797887,
-ERASE, 140143205797888, 140143214186495,
- };
- unsigned long set30[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140733436743680, 140737488351231,
-SNULL, 140733436747775, 140737488351231,
-STORE, 140733436743680, 140733436747775,
-STORE, 140733436612608, 140733436747775,
-STORE, 94630728904704, 94630731157503,
-SNULL, 94630729035775, 94630731157503,
-STORE, 94630728904704, 94630729035775,
-STORE, 94630729035776, 94630731157503,
-ERASE, 94630729035776, 94630731157503,
-STORE, 94630731128832, 94630731137023,
-STORE, 94630731137024, 94630731157503,
-STORE, 140165750841344, 140165753094143,
-SNULL, 140165750984703, 140165753094143,
-STORE, 140165750841344, 140165750984703,
-STORE, 140165750984704, 140165753094143,
-ERASE, 140165750984704, 140165753094143,
-STORE, 140165753081856, 140165753090047,
-STORE, 140165753090048, 140165753094143,
-STORE, 140733436887040, 140733436891135,
-STORE, 140733436874752, 140733436887039,
-STORE, 140165753053184, 140165753081855,
-STORE, 140165753044992, 140165753053183,
-STORE, 140165748625408, 140165750841343,
-SNULL, 140165748625408, 140165748723711,
-STORE, 140165748723712, 140165750841343,
-STORE, 140165748625408, 140165748723711,
-SNULL, 140165750816767, 140165750841343,
-STORE, 140165748723712, 140165750816767,
-STORE, 140165750816768, 140165750841343,
-SNULL, 140165750816768, 140165750824959,
-STORE, 140165750824960, 140165750841343,
-STORE, 140165750816768, 140165750824959,
-ERASE, 140165750816768, 140165750824959,
-STORE, 140165750816768, 140165750824959,
-ERASE, 140165750824960, 140165750841343,
-STORE, 140165750824960, 140165750841343,
-STORE, 140165744828416, 140165748625407,
-SNULL, 140165744828416, 140165746487295,
-STORE, 140165746487296, 140165748625407,
-STORE, 140165744828416, 140165746487295,
-SNULL, 140165748584447, 140165748625407,
-STORE, 140165746487296, 140165748584447,
-STORE, 140165748584448, 140165748625407,
-SNULL, 140165748584448, 140165748609023,
-STORE, 140165748609024, 140165748625407,
-STORE, 140165748584448, 140165748609023,
-ERASE, 140165748584448, 140165748609023,
-STORE, 140165748584448, 140165748609023,
-ERASE, 140165748609024, 140165748625407,
-STORE, 140165748609024, 140165748625407,
-STORE, 140165753036800, 140165753053183,
-SNULL, 140165748600831, 140165748609023,
-STORE, 140165748584448, 140165748600831,
-STORE, 140165748600832, 140165748609023,
-SNULL, 140165750820863, 140165750824959,
-STORE, 140165750816768, 140165750820863,
-STORE, 140165750820864, 140165750824959,
-SNULL, 94630731132927, 94630731137023,
-STORE, 94630731128832, 94630731132927,
-STORE, 94630731132928, 94630731137023,
-SNULL, 140165753085951, 140165753090047,
-STORE, 140165753081856, 140165753085951,
-STORE, 140165753085952, 140165753090047,
-ERASE, 140165753053184, 140165753081855,
-STORE, 94630743547904, 94630743683071,
-STORE, 140165736435712, 140165744828415,
-SNULL, 140165736439807, 140165744828415,
-STORE, 140165736435712, 140165736439807,
-STORE, 140165736439808, 140165744828415,
-STORE, 140165728043008, 140165736435711,
-STORE, 140165593825280, 140165728043007,
-SNULL, 140165593825280, 140165653725183,
-STORE, 140165653725184, 140165728043007,
-STORE, 140165593825280, 140165653725183,
-ERASE, 140165593825280, 140165653725183,
-SNULL, 140165720834047, 140165728043007,
-STORE, 140165653725184, 140165720834047,
-STORE, 140165720834048, 140165728043007,
-ERASE, 140165720834048, 140165728043007,
-SNULL, 140165653860351, 140165720834047,
-STORE, 140165653725184, 140165653860351,
-STORE, 140165653860352, 140165720834047,
-SNULL, 140165728047103, 140165736435711,
-STORE, 140165728043008, 140165728047103,
-STORE, 140165728047104, 140165736435711,
-STORE, 140165645332480, 140165653725183,
-SNULL, 140165645336575, 140165653725183,
-STORE, 140165645332480, 140165645336575,
-STORE, 140165645336576, 140165653725183,
-STORE, 140165636939776, 140165645332479,
-SNULL, 140165636943871, 140165645332479,
-STORE, 140165636939776, 140165636943871,
-STORE, 140165636943872, 140165645332479,
-STORE, 140165628547072, 140165636939775,
-SNULL, 140165628551167, 140165636939775,
-STORE, 140165628547072, 140165628551167,
-STORE, 140165628551168, 140165636939775,
-STORE, 140165620154368, 140165628547071,
-STORE, 140165611761664, 140165628547071,
-STORE, 140165603368960, 140165628547071,
-STORE, 140165469151232, 140165603368959,
-SNULL, 140165469151232, 140165519507455,
-STORE, 140165519507456, 140165603368959,
-STORE, 140165469151232, 140165519507455,
-ERASE, 140165469151232, 140165519507455,
-SNULL, 140165586616319, 140165603368959,
-STORE, 140165519507456, 140165586616319,
-STORE, 140165586616320, 140165603368959,
-ERASE, 140165586616320, 140165603368959,
-STORE, 140165594976256, 140165628547071,
-STORE, 140165385289728, 140165586616319,
-SNULL, 140165452398591, 140165586616319,
-STORE, 140165385289728, 140165452398591,
-STORE, 140165452398592, 140165586616319,
-SNULL, 140165452398592, 140165519507455,
-STORE, 140165519507456, 140165586616319,
-STORE, 140165452398592, 140165519507455,
-ERASE, 140165452398592, 140165519507455,
-STORE, 140165251072000, 140165452398591,
-SNULL, 140165318180863, 140165452398591,
-STORE, 140165251072000, 140165318180863,
-STORE, 140165318180864, 140165452398591,
-SNULL, 140165318180864, 140165385289727,
-STORE, 140165385289728, 140165452398591,
-STORE, 140165318180864, 140165385289727,
-ERASE, 140165318180864, 140165385289727,
-SNULL, 140165519642623, 140165586616319,
-STORE, 140165519507456, 140165519642623,
-STORE, 140165519642624, 140165586616319,
-SNULL, 140165594976256, 140165611761663,
-STORE, 140165611761664, 140165628547071,
-STORE, 140165594976256, 140165611761663,
-SNULL, 140165611765759, 140165628547071,
-STORE, 140165611761664, 140165611765759,
-STORE, 140165611765760, 140165628547071,
-STORE, 140165385289728, 140165519507455,
-SNULL, 140165385424895, 140165519507455,
-STORE, 140165385289728, 140165385424895,
-STORE, 140165385424896, 140165519507455,
-SNULL, 140165594976256, 140165603368959,
-STORE, 140165603368960, 140165611761663,
-STORE, 140165594976256, 140165603368959,
-SNULL, 140165603373055, 140165611761663,
-STORE, 140165603368960, 140165603373055,
-STORE, 140165603373056, 140165611761663,
-SNULL, 140165251207167, 140165318180863,
-STORE, 140165251072000, 140165251207167,
-STORE, 140165251207168, 140165318180863,
-STORE, 140165376897024, 140165385289727,
-SNULL, 140165376901119, 140165385289727,
-STORE, 140165376897024, 140165376901119,
-STORE, 140165376901120, 140165385289727,
-SNULL, 140165385424896, 140165452398591,
-STORE, 140165452398592, 140165519507455,
-STORE, 140165385424896, 140165452398591,
-SNULL, 140165452533759, 140165519507455,
-STORE, 140165452398592, 140165452533759,
-STORE, 140165452533760, 140165519507455,
-STORE, 140165368504320, 140165376897023,
-SNULL, 140165594980351, 140165603368959,
-STORE, 140165594976256, 140165594980351,
-STORE, 140165594980352, 140165603368959,
-SNULL, 140165368508415, 140165376897023,
-STORE, 140165368504320, 140165368508415,
-STORE, 140165368508416, 140165376897023,
-SNULL, 140165611765760, 140165620154367,
-STORE, 140165620154368, 140165628547071,
-STORE, 140165611765760, 140165620154367,
-SNULL, 140165620158463, 140165628547071,
-STORE, 140165620154368, 140165620158463,
-STORE, 140165620158464, 140165628547071,
-STORE, 140165360111616, 140165368504319,
-STORE, 140165351718912, 140165368504319,
-STORE, 140165343326208, 140165368504319,
-SNULL, 140165343326208, 140165351718911,
-STORE, 140165351718912, 140165368504319,
-STORE, 140165343326208, 140165351718911,
-SNULL, 140165351723007, 140165368504319,
-STORE, 140165351718912, 140165351723007,
-STORE, 140165351723008, 140165368504319,
-SNULL, 140165343330303, 140165351718911,
-STORE, 140165343326208, 140165343330303,
-STORE, 140165343330304, 140165351718911,
-SNULL, 140165351723008, 140165360111615,
-STORE, 140165360111616, 140165368504319,
-STORE, 140165351723008, 140165360111615,
-SNULL, 140165360115711, 140165368504319,
-STORE, 140165360111616, 140165360115711,
-STORE, 140165360115712, 140165368504319,
-STORE, 140165334933504, 140165343326207,
-SNULL, 140165334937599, 140165343326207,
-STORE, 140165334933504, 140165334937599,
-STORE, 140165334937600, 140165343326207,
-STORE, 140165326540800, 140165334933503,
-STORE, 140165242679296, 140165251071999,
-SNULL, 140165242683391, 140165251071999,
-STORE, 140165242679296, 140165242683391,
-STORE, 140165242683392, 140165251071999,
-STORE, 140165234286592, 140165242679295,
-STORE, 140165225893888, 140165242679295,
-SNULL, 140165225897983, 140165242679295,
-STORE, 140165225893888, 140165225897983,
-STORE, 140165225897984, 140165242679295,
-SNULL, 140165225897984, 140165234286591,
-STORE, 140165234286592, 140165242679295,
-STORE, 140165225897984, 140165234286591,
-SNULL, 140165234290687, 140165242679295,
-STORE, 140165234286592, 140165234290687,
-STORE, 140165234290688, 140165242679295,
-SNULL, 140165326544895, 140165334933503,
-STORE, 140165326540800, 140165326544895,
-STORE, 140165326544896, 140165334933503,
-STORE, 140165217501184, 140165225893887,
-STORE, 140165209108480, 140165225893887,
-SNULL, 140165209108480, 140165217501183,
-STORE, 140165217501184, 140165225893887,
-STORE, 140165209108480, 140165217501183,
-SNULL, 140165217505279, 140165225893887,
-STORE, 140165217501184, 140165217505279,
-STORE, 140165217505280, 140165225893887,
-SNULL, 140165209112575, 140165217501183,
-STORE, 140165209108480, 140165209112575,
-STORE, 140165209112576, 140165217501183,
-STORE, 140165200715776, 140165209108479,
-STORE, 140165066498048, 140165200715775,
-SNULL, 140165066498048, 140165116854271,
-STORE, 140165116854272, 140165200715775,
-STORE, 140165066498048, 140165116854271,
-ERASE, 140165066498048, 140165116854271,
-SNULL, 140165183963135, 140165200715775,
-STORE, 140165116854272, 140165183963135,
-STORE, 140165183963136, 140165200715775,
-ERASE, 140165183963136, 140165200715775,
-SNULL, 140165116989439, 140165183963135,
-STORE, 140165116854272, 140165116989439,
-STORE, 140165116989440, 140165183963135,
-STORE, 140165192323072, 140165209108479,
-STORE, 140165108461568, 140165116854271,
-STORE, 140164974243840, 140165108461567,
-STORE, 140164965851136, 140164974243839,
-SNULL, 140164974243840, 140164982636543,
-STORE, 140164982636544, 140165108461567,
-STORE, 140164974243840, 140164982636543,
-ERASE, 140164974243840, 140164982636543,
-STORE, 140164965851136, 140164982636543,
-STORE, 140164957458432, 140164982636543,
-STORE, 140164949065728, 140164982636543,
-STORE, 140164940673024, 140164982636543,
-STORE, 140164806455296, 140164940673023,
-STORE, 140164798062592, 140164806455295,
-STORE, 140164789669888, 140164806455295,
-STORE, 140164655452160, 140164789669887,
-STORE, 140164647059456, 140164655452159,
-STORE, 140164638666752, 140164655452159,
-SNULL, 140164655452160, 140164714201087,
-STORE, 140164714201088, 140164789669887,
-STORE, 140164655452160, 140164714201087,
-ERASE, 140164655452160, 140164714201087,
-STORE, 140164705808384, 140164714201087,
-STORE, 140164697415680, 140164714201087,
-STORE, 140164504449024, 140164638666751,
-SNULL, 140164504449024, 140164512874495,
-STORE, 140164512874496, 140164638666751,
-STORE, 140164504449024, 140164512874495,
-ERASE, 140164504449024, 140164512874495,
-STORE, 140164689022976, 140164714201087,
-STORE, 140164680630272, 140164714201087,
-SNULL, 140164680634367, 140164714201087,
-STORE, 140164680630272, 140164680634367,
-STORE, 140164680634368, 140164714201087,
-STORE, 140164378656768, 140164638666751,
-SNULL, 140165192323072, 140165200715775,
-STORE, 140165200715776, 140165209108479,
-STORE, 140165192323072, 140165200715775,
-SNULL, 140165200719871, 140165209108479,
-STORE, 140165200715776, 140165200719871,
-STORE, 140165200719872, 140165209108479,
-SNULL, 140165049745407, 140165108461567,
-STORE, 140164982636544, 140165049745407,
-STORE, 140165049745408, 140165108461567,
-ERASE, 140165049745408, 140165108461567,
-SNULL, 140164982771711, 140165049745407,
-STORE, 140164982636544, 140164982771711,
-STORE, 140164982771712, 140165049745407,
-STORE, 140164244439040, 140164638666751,
-SNULL, 140164311547903, 140164638666751,
-STORE, 140164244439040, 140164311547903,
-STORE, 140164311547904, 140164638666751,
-SNULL, 140164311547904, 140164378656767,
-STORE, 140164378656768, 140164638666751,
-STORE, 140164311547904, 140164378656767,
-ERASE, 140164311547904, 140164378656767,
-SNULL, 140164806455296, 140164848418815,
-STORE, 140164848418816, 140164940673023,
-STORE, 140164806455296, 140164848418815,
-ERASE, 140164806455296, 140164848418815,
-SNULL, 140164915527679, 140164940673023,
-STORE, 140164848418816, 140164915527679,
-STORE, 140164915527680, 140164940673023,
-ERASE, 140164915527680, 140164940673023,
-STORE, 140164110221312, 140164311547903,
-SNULL, 140164177330175, 140164311547903,
-STORE, 140164110221312, 140164177330175,
-STORE, 140164177330176, 140164311547903,
-SNULL, 140164177330176, 140164244439039,
-STORE, 140164244439040, 140164311547903,
-STORE, 140164177330176, 140164244439039,
-ERASE, 140164177330176, 140164244439039,
-SNULL, 140164781309951, 140164789669887,
-STORE, 140164714201088, 140164781309951,
-STORE, 140164781309952, 140164789669887,
-ERASE, 140164781309952, 140164789669887,
-STORE, 140163976003584, 140164177330175,
-SNULL, 140164043112447, 140164177330175,
-STORE, 140163976003584, 140164043112447,
-STORE, 140164043112448, 140164177330175,
-SNULL, 140164043112448, 140164110221311,
-STORE, 140164110221312, 140164177330175,
-STORE, 140164043112448, 140164110221311,
-ERASE, 140164043112448, 140164110221311,
-SNULL, 140164579983359, 140164638666751,
-STORE, 140164378656768, 140164579983359,
-STORE, 140164579983360, 140164638666751,
-ERASE, 140164579983360, 140164638666751,
-STORE, 140163841785856, 140164043112447,
-SNULL, 140163908894719, 140164043112447,
-STORE, 140163841785856, 140163908894719,
-STORE, 140163908894720, 140164043112447,
-SNULL, 140163908894720, 140163976003583,
-STORE, 140163976003584, 140164043112447,
-STORE, 140163908894720, 140163976003583,
-ERASE, 140163908894720, 140163976003583,
-SNULL, 140164940673024, 140164965851135,
-STORE, 140164965851136, 140164982636543,
-STORE, 140164940673024, 140164965851135,
-SNULL, 140164965855231, 140164982636543,
-STORE, 140164965851136, 140164965855231,
-STORE, 140164965855232, 140164982636543,
-SNULL, 140164965855232, 140164974243839,
-STORE, 140164974243840, 140164982636543,
-STORE, 140164965855232, 140164974243839,
-SNULL, 140164974247935, 140164982636543,
-STORE, 140164974243840, 140164974247935,
-STORE, 140164974247936, 140164982636543,
-SNULL, 140164445765631, 140164579983359,
-STORE, 140164378656768, 140164445765631,
-STORE, 140164445765632, 140164579983359,
-SNULL, 140164445765632, 140164512874495,
-STORE, 140164512874496, 140164579983359,
-STORE, 140164445765632, 140164512874495,
-ERASE, 140164445765632, 140164512874495,
-SNULL, 140164378791935, 140164445765631,
-STORE, 140164378656768, 140164378791935,
-STORE, 140164378791936, 140164445765631,
-SNULL, 140164789673983, 140164806455295,
-STORE, 140164789669888, 140164789673983,
-STORE, 140164789673984, 140164806455295,
-SNULL, 140164789673984, 140164798062591,
-STORE, 140164798062592, 140164806455295,
-STORE, 140164789673984, 140164798062591,
-SNULL, 140164798066687, 140164806455295,
-STORE, 140164798062592, 140164798066687,
-STORE, 140164798066688, 140164806455295,
-SNULL, 140164638670847, 140164655452159,
-STORE, 140164638666752, 140164638670847,
-STORE, 140164638670848, 140164655452159,
-STORE, 140165100068864, 140165116854271,
-STORE, 140165091676160, 140165116854271,
-STORE, 140165083283456, 140165116854271,
-SNULL, 140164244574207, 140164311547903,
-STORE, 140164244439040, 140164244574207,
-STORE, 140164244574208, 140164311547903,
-SNULL, 140164848553983, 140164915527679,
-STORE, 140164848418816, 140164848553983,
-STORE, 140164848553984, 140164915527679,
-SNULL, 140164110356479, 140164177330175,
-STORE, 140164110221312, 140164110356479,
-STORE, 140164110356480, 140164177330175,
-SNULL, 140164714336255, 140164781309951,
-STORE, 140164714201088, 140164714336255,
-STORE, 140164714336256, 140164781309951,
-SNULL, 140163976138751, 140164043112447,
-STORE, 140163976003584, 140163976138751,
-STORE, 140163976138752, 140164043112447,
-SNULL, 140164513009663, 140164579983359,
-STORE, 140164512874496, 140164513009663,
-STORE, 140164513009664, 140164579983359,
-SNULL, 140163841921023, 140163908894719,
-STORE, 140163841785856, 140163841921023,
-STORE, 140163841921024, 140163908894719,
-SNULL, 140165083283456, 140165100068863,
-STORE, 140165100068864, 140165116854271,
-STORE, 140165083283456, 140165100068863,
-SNULL, 140165100072959, 140165116854271,
-STORE, 140165100068864, 140165100072959,
-STORE, 140165100072960, 140165116854271,
-SNULL, 140165100072960, 140165108461567,
-STORE, 140165108461568, 140165116854271,
-STORE, 140165100072960, 140165108461567,
-SNULL, 140165108465663, 140165116854271,
-STORE, 140165108461568, 140165108465663,
-STORE, 140165108465664, 140165116854271,
-STORE, 140165074890752, 140165100068863,
-SNULL, 140165074894847, 140165100068863,
-STORE, 140165074890752, 140165074894847,
-STORE, 140165074894848, 140165100068863,
-STORE, 140165066498048, 140165074890751,
-STORE, 140165058105344, 140165074890751,
-STORE, 140164932280320, 140164965851135,
-SNULL, 140165192327167, 140165200715775,
-STORE, 140165192323072, 140165192327167,
-STORE, 140165192327168, 140165200715775,
-STORE, 140164923887616, 140164965851135,
-SNULL, 140164923891711, 140164965851135,
-STORE, 140164923887616, 140164923891711,
-STORE, 140164923891712, 140164965851135,
-SNULL, 140164680634368, 140164705808383,
-STORE, 140164705808384, 140164714201087,
-STORE, 140164680634368, 140164705808383,
-SNULL, 140164705812479, 140164714201087,
-STORE, 140164705808384, 140164705812479,
-STORE, 140164705812480, 140164714201087,
-SNULL, 140164680634368, 140164697415679,
-STORE, 140164697415680, 140164705808383,
-STORE, 140164680634368, 140164697415679,
-SNULL, 140164697419775, 140164705808383,
-STORE, 140164697415680, 140164697419775,
-STORE, 140164697419776, 140164705808383,
-STORE, 140164840026112, 140164848418815,
-STORE, 140164831633408, 140164848418815,
-STORE, 140164823240704, 140164848418815,
-SNULL, 140165074894848, 140165083283455,
-STORE, 140165083283456, 140165100068863,
-STORE, 140165074894848, 140165083283455,
-SNULL, 140165083287551, 140165100068863,
-STORE, 140165083283456, 140165083287551,
-STORE, 140165083287552, 140165100068863,
-SNULL, 140165083287552, 140165091676159,
-STORE, 140165091676160, 140165100068863,
-STORE, 140165083287552, 140165091676159,
-SNULL, 140165091680255, 140165100068863,
-STORE, 140165091676160, 140165091680255,
-STORE, 140165091680256, 140165100068863,
-SNULL, 140164638670848, 140164647059455,
-STORE, 140164647059456, 140164655452159,
-STORE, 140164638670848, 140164647059455,
-SNULL, 140164647063551, 140164655452159,
-STORE, 140164647059456, 140164647063551,
-STORE, 140164647063552, 140164655452159,
-SNULL, 140164923891712, 140164940673023,
-STORE, 140164940673024, 140164965851135,
-STORE, 140164923891712, 140164940673023,
-SNULL, 140164940677119, 140164965851135,
-STORE, 140164940673024, 140164940677119,
-STORE, 140164940677120, 140164965851135,
-SNULL, 140164940677120, 140164949065727,
-STORE, 140164949065728, 140164965851135,
-STORE, 140164940677120, 140164949065727,
-SNULL, 140164949069823, 140164965851135,
-STORE, 140164949065728, 140164949069823,
-STORE, 140164949069824, 140164965851135,
-SNULL, 140164949069824, 140164957458431,
-STORE, 140164957458432, 140164965851135,
-STORE, 140164949069824, 140164957458431,
-SNULL, 140164957462527, 140164965851135,
-STORE, 140164957458432, 140164957462527,
-STORE, 140164957462528, 140164965851135,
-SNULL, 140164680634368, 140164689022975,
-STORE, 140164689022976, 140164697415679,
-STORE, 140164680634368, 140164689022975,
-SNULL, 140164689027071, 140164697415679,
-STORE, 140164689022976, 140164689027071,
-STORE, 140164689027072, 140164697415679,
-STORE, 140164814848000, 140164848418815,
-SNULL, 140165058105344, 140165066498047,
-STORE, 140165066498048, 140165074890751,
-STORE, 140165058105344, 140165066498047,
-SNULL, 140165066502143, 140165074890751,
-STORE, 140165066498048, 140165066502143,
-STORE, 140165066502144, 140165074890751,
-SNULL, 140165058109439, 140165066498047,
-STORE, 140165058105344, 140165058109439,
-STORE, 140165058109440, 140165066498047,
-STORE, 140164798066688, 140164814847999,
-SNULL, 140164798066688, 140164806455295,
-STORE, 140164806455296, 140164814847999,
-STORE, 140164798066688, 140164806455295,
-SNULL, 140164806459391, 140164814847999,
-STORE, 140164806455296, 140164806459391,
-STORE, 140164806459392, 140164814847999,
-SNULL, 140164923891712, 140164932280319,
-STORE, 140164932280320, 140164940673023,
-STORE, 140164923891712, 140164932280319,
-SNULL, 140164932284415, 140164940673023,
-STORE, 140164932280320, 140164932284415,
-STORE, 140164932284416, 140164940673023,
-STORE, 140164672237568, 140164680630271,
-STORE, 140164663844864, 140164680630271,
-STORE, 140164647063552, 140164680630271,
-SNULL, 140164647063552, 140164655452159,
-STORE, 140164655452160, 140164680630271,
-STORE, 140164647063552, 140164655452159,
-SNULL, 140164655456255, 140164680630271,
-STORE, 140164655452160, 140164655456255,
-STORE, 140164655456256, 140164680630271,
-STORE, 140164630274048, 140164638666751,
-SNULL, 140164814852095, 140164848418815,
-STORE, 140164814848000, 140164814852095,
-STORE, 140164814852096, 140164848418815,
-SNULL, 140164814852096, 140164831633407,
-STORE, 140164831633408, 140164848418815,
-STORE, 140164814852096, 140164831633407,
-SNULL, 140164831637503, 140164848418815,
-STORE, 140164831633408, 140164831637503,
-STORE, 140164831637504, 140164848418815,
-STORE, 140164621881344, 140164638666751,
-SNULL, 140164831637504, 140164840026111,
-STORE, 140164840026112, 140164848418815,
-STORE, 140164831637504, 140164840026111,
-SNULL, 140164840030207, 140164848418815,
-STORE, 140164840026112, 140164840030207,
-STORE, 140164840030208, 140164848418815,
-STORE, 140164613488640, 140164638666751,
-SNULL, 140164613492735, 140164638666751,
-STORE, 140164613488640, 140164613492735,
-STORE, 140164613492736, 140164638666751,
-STORE, 140164605095936, 140164613488639,
-SNULL, 140164605100031, 140164613488639,
-STORE, 140164605095936, 140164605100031,
-STORE, 140164605100032, 140164613488639,
-STORE, 140164596703232, 140164605095935,
-STORE, 140164588310528, 140164605095935,
-SNULL, 140164588314623, 140164605095935,
-STORE, 140164588310528, 140164588314623,
-STORE, 140164588314624, 140164605095935,
-STORE, 140164504481792, 140164512874495,
-STORE, 140164496089088, 140164512874495,
-SNULL, 140164496089088, 140164504481791,
-STORE, 140164504481792, 140164512874495,
-STORE, 140164496089088, 140164504481791,
-SNULL, 140164504485887, 140164512874495,
-STORE, 140164504481792, 140164504485887,
-STORE, 140164504485888, 140164512874495,
-SNULL, 140164613492736, 140164630274047,
-STORE, 140164630274048, 140164638666751,
-STORE, 140164613492736, 140164630274047,
-SNULL, 140164630278143, 140164638666751,
-STORE, 140164630274048, 140164630278143,
-STORE, 140164630278144, 140164638666751,
-STORE, 140164487696384, 140164504481791,
-STORE, 140164479303680, 140164504481791,
-SNULL, 140164814852096, 140164823240703,
-STORE, 140164823240704, 140164831633407,
-STORE, 140164814852096, 140164823240703,
-SNULL, 140164823244799, 140164831633407,
-STORE, 140164823240704, 140164823244799,
-STORE, 140164823244800, 140164831633407,
-STORE, 140164470910976, 140164504481791,
-SNULL, 140164470910976, 140164496089087,
-STORE, 140164496089088, 140164504481791,
-STORE, 140164470910976, 140164496089087,
-SNULL, 140164496093183, 140164504481791,
-STORE, 140164496089088, 140164496093183,
-STORE, 140164496093184, 140164504481791,
-SNULL, 140164655456256, 140164672237567,
-STORE, 140164672237568, 140164680630271,
-STORE, 140164655456256, 140164672237567,
-SNULL, 140164672241663, 140164680630271,
-STORE, 140164672237568, 140164672241663,
-STORE, 140164672241664, 140164680630271,
-STORE, 140164462518272, 140164496089087,
-STORE, 140164454125568, 140164496089087,
-SNULL, 140164655456256, 140164663844863,
-STORE, 140164663844864, 140164672237567,
-STORE, 140164655456256, 140164663844863,
-SNULL, 140164663848959, 140164672237567,
-STORE, 140164663844864, 140164663848959,
-STORE, 140164663848960, 140164672237567,
-STORE, 140164370264064, 140164378656767,
-STORE, 140164361871360, 140164378656767,
-STORE, 140164353478656, 140164378656767,
-STORE, 140164345085952, 140164378656767,
-SNULL, 140164345085952, 140164353478655,
-STORE, 140164353478656, 140164378656767,
-STORE, 140164345085952, 140164353478655,
-SNULL, 140164353482751, 140164378656767,
-STORE, 140164353478656, 140164353482751,
-STORE, 140164353482752, 140164378656767,
-SNULL, 140164454125568, 140164487696383,
-STORE, 140164487696384, 140164496089087,
-STORE, 140164454125568, 140164487696383,
-SNULL, 140164487700479, 140164496089087,
-STORE, 140164487696384, 140164487700479,
-STORE, 140164487700480, 140164496089087,
-STORE, 140164336693248, 140164353478655,
-SNULL, 140164336697343, 140164353478655,
-STORE, 140164336693248, 140164336697343,
-STORE, 140164336697344, 140164353478655,
-STORE, 140164328300544, 140164336693247,
-SNULL, 140164454125568, 140164479303679,
-STORE, 140164479303680, 140164487696383,
-STORE, 140164454125568, 140164479303679,
-SNULL, 140164479307775, 140164487696383,
-STORE, 140164479303680, 140164479307775,
-STORE, 140164479307776, 140164487696383,
-STORE, 140164319907840, 140164336693247,
-STORE, 140164236046336, 140164244439039,
-SNULL, 140164588314624, 140164596703231,
-STORE, 140164596703232, 140164605095935,
-STORE, 140164588314624, 140164596703231,
-SNULL, 140164596707327, 140164605095935,
-STORE, 140164596703232, 140164596707327,
-STORE, 140164596707328, 140164605095935,
-SNULL, 140164454125568, 140164462518271,
-STORE, 140164462518272, 140164479303679,
-STORE, 140164454125568, 140164462518271,
-SNULL, 140164462522367, 140164479303679,
-STORE, 140164462518272, 140164462522367,
-STORE, 140164462522368, 140164479303679,
-STORE, 140164227653632, 140164244439039,
-SNULL, 140164227657727, 140164244439039,
-STORE, 140164227653632, 140164227657727,
-STORE, 140164227657728, 140164244439039,
-SNULL, 140164462522368, 140164470910975,
-STORE, 140164470910976, 140164479303679,
-STORE, 140164462522368, 140164470910975,
-SNULL, 140164470915071, 140164479303679,
-STORE, 140164470910976, 140164470915071,
-STORE, 140164470915072, 140164479303679,
-SNULL, 140164613492736, 140164621881343,
-STORE, 140164621881344, 140164630274047,
-STORE, 140164613492736, 140164621881343,
-SNULL, 140164621885439, 140164630274047,
-STORE, 140164621881344, 140164621885439,
-STORE, 140164621885440, 140164630274047,
-SNULL, 140164353482752, 140164370264063,
-STORE, 140164370264064, 140164378656767,
-STORE, 140164353482752, 140164370264063,
-SNULL, 140164370268159, 140164378656767,
-STORE, 140164370264064, 140164370268159,
-STORE, 140164370268160, 140164378656767,
-STORE, 140164219260928, 140164227653631,
-SNULL, 140164319911935, 140164336693247,
-STORE, 140164319907840, 140164319911935,
-STORE, 140164319911936, 140164336693247,
-SNULL, 140164336697344, 140164345085951,
-STORE, 140164345085952, 140164353478655,
-STORE, 140164336697344, 140164345085951,
-SNULL, 140164345090047, 140164353478655,
-STORE, 140164345085952, 140164345090047,
-STORE, 140164345090048, 140164353478655,
-SNULL, 140164319911936, 140164328300543,
-STORE, 140164328300544, 140164336693247,
-STORE, 140164319911936, 140164328300543,
-SNULL, 140164328304639, 140164336693247,
-STORE, 140164328300544, 140164328304639,
-STORE, 140164328304640, 140164336693247,
-SNULL, 140164454129663, 140164462518271,
-STORE, 140164454125568, 140164454129663,
-STORE, 140164454129664, 140164462518271,
-STORE, 140164210868224, 140164227653631,
-STORE, 140164202475520, 140164227653631,
-STORE, 140164194082816, 140164227653631,
-SNULL, 140164194086911, 140164227653631,
-STORE, 140164194082816, 140164194086911,
-STORE, 140164194086912, 140164227653631,
-SNULL, 140164353482752, 140164361871359,
-STORE, 140164361871360, 140164370264063,
-STORE, 140164353482752, 140164361871359,
-SNULL, 140164361875455, 140164370264063,
-STORE, 140164361871360, 140164361875455,
-STORE, 140164361875456, 140164370264063,
-SNULL, 140164227657728, 140164236046335,
-STORE, 140164236046336, 140164244439039,
-STORE, 140164227657728, 140164236046335,
-SNULL, 140164236050431, 140164244439039,
-STORE, 140164236046336, 140164236050431,
-STORE, 140164236050432, 140164244439039,
-STORE, 140164185690112, 140164194082815,
-SNULL, 140164194086912, 140164219260927,
-STORE, 140164219260928, 140164227653631,
-STORE, 140164194086912, 140164219260927,
-SNULL, 140164219265023, 140164227653631,
-STORE, 140164219260928, 140164219265023,
-STORE, 140164219265024, 140164227653631,
-STORE, 140164101828608, 140164110221311,
-STORE, 140164093435904, 140164110221311,
-STORE, 140164085043200, 140164110221311,
-SNULL, 140164085047295, 140164110221311,
-STORE, 140164085043200, 140164085047295,
-STORE, 140164085047296, 140164110221311,
-STORE, 140164076650496, 140164085043199,
-SNULL, 140164185694207, 140164194082815,
-STORE, 140164185690112, 140164185694207,
-STORE, 140164185694208, 140164194082815,
-SNULL, 140164085047296, 140164101828607,
-STORE, 140164101828608, 140164110221311,
-STORE, 140164085047296, 140164101828607,
-SNULL, 140164101832703, 140164110221311,
-STORE, 140164101828608, 140164101832703,
-STORE, 140164101832704, 140164110221311,
-SNULL, 140164085047296, 140164093435903,
-STORE, 140164093435904, 140164101828607,
-STORE, 140164085047296, 140164093435903,
-SNULL, 140164093439999, 140164101828607,
-STORE, 140164093435904, 140164093439999,
-STORE, 140164093440000, 140164101828607,
-SNULL, 140164194086912, 140164202475519,
-STORE, 140164202475520, 140164219260927,
-STORE, 140164194086912, 140164202475519,
-SNULL, 140164202479615, 140164219260927,
-STORE, 140164202475520, 140164202479615,
-STORE, 140164202479616, 140164219260927,
-SNULL, 140164202479616, 140164210868223,
-STORE, 140164210868224, 140164219260927,
-STORE, 140164202479616, 140164210868223,
-SNULL, 140164210872319, 140164219260927,
-STORE, 140164210868224, 140164210872319,
-STORE, 140164210872320, 140164219260927,
-SNULL, 140164076654591, 140164085043199,
-STORE, 140164076650496, 140164076654591,
-STORE, 140164076654592, 140164085043199,
-STORE, 140164068257792, 140164076650495,
-SNULL, 140164068261887, 140164076650495,
-STORE, 140164068257792, 140164068261887,
-STORE, 140164068261888, 140164076650495,
-STORE, 140165753053184, 140165753081855,
-STORE, 140165725851648, 140165728043007,
-SNULL, 140165725851648, 140165725941759,
-STORE, 140165725941760, 140165728043007,
-STORE, 140165725851648, 140165725941759,
-SNULL, 140165728034815, 140165728043007,
-STORE, 140165725941760, 140165728034815,
-STORE, 140165728034816, 140165728043007,
-ERASE, 140165728034816, 140165728043007,
-STORE, 140165728034816, 140165728043007,
-SNULL, 140165728038911, 140165728043007,
-STORE, 140165728034816, 140165728038911,
-STORE, 140165728038912, 140165728043007,
-ERASE, 140165753053184, 140165753081855,
-ERASE, 140164638666752, 140164638670847,
-ERASE, 140164638670848, 140164647059455,
-ERASE, 140165091676160, 140165091680255,
-ERASE, 140165091680256, 140165100068863,
-ERASE, 140164613488640, 140164613492735,
-ERASE, 140164613492736, 140164621881343,
-ERASE, 140164319907840, 140164319911935,
-ERASE, 140164319911936, 140164328300543,
-ERASE, 140165620154368, 140165620158463,
-ERASE, 140165620158464, 140165628547071,
-ERASE, 140164798062592, 140164798066687,
-ERASE, 140164798066688, 140164806455295,
-ERASE, 140164789669888, 140164789673983,
-ERASE, 140164789673984, 140164798062591,
-ERASE, 140164965851136, 140164965855231,
-ERASE, 140164965855232, 140164974243839,
-ERASE, 140165074890752, 140165074894847,
-ERASE, 140165074894848, 140165083283455,
-ERASE, 140164672237568, 140164672241663,
-ERASE, 140164672241664, 140164680630271,
-ERASE, 140164454125568, 140164454129663,
-ERASE, 140164454129664, 140164462518271,
-ERASE, 140165200715776, 140165200719871,
-ERASE, 140165200719872, 140165209108479,
-ERASE, 140164932280320, 140164932284415,
-ERASE, 140164932284416, 140164940673023,
-ERASE, 140164663844864, 140164663848959,
-ERASE, 140164663848960, 140164672237567,
-ERASE, 140164697415680, 140164697419775,
-ERASE, 140164697419776, 140164705808383,
-ERASE, 140164831633408, 140164831637503,
-ERASE, 140164831637504, 140164840026111,
-ERASE, 140165192323072, 140165192327167,
-ERASE, 140165192327168, 140165200715775,
-ERASE, 140165108461568, 140165108465663,
-ERASE, 140165108465664, 140165116854271,
-ERASE, 140164840026112, 140164840030207,
-ERASE, 140164840030208, 140164848418815,
-ERASE, 140164647059456, 140164647063551,
-ERASE, 140164647063552, 140164655452159,
-ERASE, 140165083283456, 140165083287551,
-ERASE, 140165083287552, 140165091676159,
-ERASE, 140164923887616, 140164923891711,
-ERASE, 140164923891712, 140164932280319,
-ERASE, 140164823240704, 140164823244799,
-ERASE, 140164823244800, 140164831633407,
-ERASE, 140164227653632, 140164227657727,
-ERASE, 140164227657728, 140164236046335,
-ERASE, 140164957458432, 140164957462527,
-ERASE, 140164957462528, 140164965851135,
-ERASE, 140164680630272, 140164680634367,
-ERASE, 140164680634368, 140164689022975,
-ERASE, 140164974243840, 140164974247935,
-ERASE, 140164974247936, 140164982636543,
-ERASE, 140165066498048, 140165066502143,
-ERASE, 140165066502144, 140165074890751,
-ERASE, 140164621881344, 140164621885439,
-ERASE, 140164621885440, 140164630274047,
-ERASE, 140164949065728, 140164949069823,
-ERASE, 140164949069824, 140164957458431,
-ERASE, 140164588310528, 140164588314623,
-ERASE, 140164588314624, 140164596703231,
-ERASE, 140164806455296, 140164806459391,
-ERASE, 140164806459392, 140164814847999,
-ERASE, 140164940673024, 140164940677119,
-ERASE, 140164940677120, 140164949065727,
-ERASE, 140164596703232, 140164596707327,
-ERASE, 140164596707328, 140164605095935,
-ERASE, 140164605095936, 140164605100031,
-ERASE, 140164605100032, 140164613488639,
-ERASE, 140164655452160, 140164655456255,
-ERASE, 140164655456256, 140164663844863,
-ERASE, 140164705808384, 140164705812479,
-ERASE, 140164705812480, 140164714201087,
-ERASE, 140164689022976, 140164689027071,
-ERASE, 140164689027072, 140164697415679,
-ERASE, 140164630274048, 140164630278143,
-ERASE, 140164630278144, 140164638666751,
-ERASE, 140164479303680, 140164479307775,
-ERASE, 140164479307776, 140164487696383,
-ERASE, 140164236046336, 140164236050431,
-ERASE, 140164236050432, 140164244439039,
-ERASE, 140164085043200, 140164085047295,
-ERASE, 140164085047296, 140164093435903,
-ERASE, 140164345085952, 140164345090047,
-ERASE, 140164345090048, 140164353478655,
-ERASE, 140164101828608, 140164101832703,
-ERASE, 140164101832704, 140164110221311,
-ERASE, 140164370264064, 140164370268159,
-ERASE, 140164370268160, 140164378656767,
-ERASE, 140164336693248, 140164336697343,
-ERASE, 140164336697344, 140164345085951,
-ERASE, 140164194082816, 140164194086911,
-ERASE, 140164194086912, 140164202475519,
-ERASE, 140164353478656, 140164353482751,
-ERASE, 140164353482752, 140164361871359,
-ERASE, 140164210868224, 140164210872319,
-ERASE, 140164210872320, 140164219260927,
-ERASE, 140164814848000, 140164814852095,
-ERASE, 140164814852096, 140164823240703,
-ERASE, 140164504481792, 140164504485887,
-ERASE, 140164504485888, 140164512874495,
-ERASE, 140165100068864, 140165100072959,
-ERASE, 140165100072960, 140165108461567,
-ERASE, 140164361871360, 140164361875455,
-ERASE, 140164361875456, 140164370264063,
-ERASE, 140164470910976, 140164470915071,
-ERASE, 140164470915072, 140164479303679,
-ERASE, 140164076650496, 140164076654591,
-ERASE, 140164076654592, 140164085043199,
-ERASE, 140164202475520, 140164202479615,
-ERASE, 140164202479616, 140164210868223,
-ERASE, 140164462518272, 140164462522367,
-ERASE, 140164462522368, 140164470910975,
-ERASE, 140165351718912, 140165351723007,
-ERASE, 140165351723008, 140165360111615,
-ERASE, 140164328300544, 140164328304639,
-ERASE, 140164328304640, 140164336693247,
-ERASE, 140164093435904, 140164093439999,
-ERASE, 140164093440000, 140164101828607,
-ERASE, 140165603368960, 140165603373055,
-ERASE, 140165603373056, 140165611761663,
-ERASE, 140165368504320, 140165368508415,
-ERASE, 140165368508416, 140165376897023,
-ERASE, 140165334933504, 140165334937599,
-ERASE, 140165334937600, 140165343326207,
-ERASE, 140165594976256, 140165594980351,
-ERASE, 140165594980352, 140165603368959,
-ERASE, 140164487696384, 140164487700479,
-ERASE, 140164487700480, 140164496089087,
-ERASE, 140164219260928, 140164219265023,
-ERASE, 140164219265024, 140164227653631,
-ERASE, 140164185690112, 140164185694207,
-ERASE, 140164185694208, 140164194082815,
-ERASE, 140164068257792, 140164068261887,
-ERASE, 140164068261888, 140164076650495,
-ERASE, 140165225893888, 140165225897983,
-ERASE, 140165225897984, 140165234286591,
-ERASE, 140165058105344, 140165058109439,
- };
- unsigned long set31[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140730890784768, 140737488351231,
-SNULL, 140730890788863, 140737488351231,
-STORE, 140730890784768, 140730890788863,
-STORE, 140730890653696, 140730890788863,
-STORE, 94577123659776, 94577125912575,
-SNULL, 94577123790847, 94577125912575,
-STORE, 94577123659776, 94577123790847,
-STORE, 94577123790848, 94577125912575,
-ERASE, 94577123790848, 94577125912575,
-STORE, 94577125883904, 94577125892095,
-STORE, 94577125892096, 94577125912575,
-STORE, 140624060407808, 140624062660607,
-SNULL, 140624060551167, 140624062660607,
-STORE, 140624060407808, 140624060551167,
-STORE, 140624060551168, 140624062660607,
-ERASE, 140624060551168, 140624062660607,
-STORE, 140624062648320, 140624062656511,
-STORE, 140624062656512, 140624062660607,
-STORE, 140730892140544, 140730892144639,
-STORE, 140730892128256, 140730892140543,
-STORE, 140624062619648, 140624062648319,
-STORE, 140624062611456, 140624062619647,
-STORE, 140624058191872, 140624060407807,
-SNULL, 140624058191872, 140624058290175,
-STORE, 140624058290176, 140624060407807,
-STORE, 140624058191872, 140624058290175,
-SNULL, 140624060383231, 140624060407807,
-STORE, 140624058290176, 140624060383231,
-STORE, 140624060383232, 140624060407807,
-SNULL, 140624060383232, 140624060391423,
-STORE, 140624060391424, 140624060407807,
-STORE, 140624060383232, 140624060391423,
-ERASE, 140624060383232, 140624060391423,
-STORE, 140624060383232, 140624060391423,
-ERASE, 140624060391424, 140624060407807,
-STORE, 140624060391424, 140624060407807,
-STORE, 140624054394880, 140624058191871,
-SNULL, 140624054394880, 140624056053759,
-STORE, 140624056053760, 140624058191871,
-STORE, 140624054394880, 140624056053759,
-SNULL, 140624058150911, 140624058191871,
-STORE, 140624056053760, 140624058150911,
-STORE, 140624058150912, 140624058191871,
-SNULL, 140624058150912, 140624058175487,
-STORE, 140624058175488, 140624058191871,
-STORE, 140624058150912, 140624058175487,
-ERASE, 140624058150912, 140624058175487,
-STORE, 140624058150912, 140624058175487,
-ERASE, 140624058175488, 140624058191871,
-STORE, 140624058175488, 140624058191871,
-STORE, 140624062603264, 140624062619647,
-SNULL, 140624058167295, 140624058175487,
-STORE, 140624058150912, 140624058167295,
-STORE, 140624058167296, 140624058175487,
-SNULL, 140624060387327, 140624060391423,
-STORE, 140624060383232, 140624060387327,
-STORE, 140624060387328, 140624060391423,
-SNULL, 94577125887999, 94577125892095,
-STORE, 94577125883904, 94577125887999,
-STORE, 94577125888000, 94577125892095,
-SNULL, 140624062652415, 140624062656511,
-STORE, 140624062648320, 140624062652415,
-STORE, 140624062652416, 140624062656511,
-ERASE, 140624062619648, 140624062648319,
-STORE, 94577157709824, 94577157844991,
-STORE, 140624046002176, 140624054394879,
-SNULL, 140624046006271, 140624054394879,
-STORE, 140624046002176, 140624046006271,
-STORE, 140624046006272, 140624054394879,
-STORE, 140624037609472, 140624046002175,
-STORE, 140623903391744, 140624037609471,
-SNULL, 140623903391744, 140623940157439,
-STORE, 140623940157440, 140624037609471,
-STORE, 140623903391744, 140623940157439,
-ERASE, 140623903391744, 140623940157439,
-SNULL, 140624007266303, 140624037609471,
-STORE, 140623940157440, 140624007266303,
-STORE, 140624007266304, 140624037609471,
-ERASE, 140624007266304, 140624037609471,
-SNULL, 140623940292607, 140624007266303,
-STORE, 140623940157440, 140623940292607,
-STORE, 140623940292608, 140624007266303,
-SNULL, 140624037613567, 140624046002175,
-STORE, 140624037609472, 140624037613567,
-STORE, 140624037613568, 140624046002175,
-STORE, 140624029216768, 140624037609471,
-SNULL, 140624029220863, 140624037609471,
-STORE, 140624029216768, 140624029220863,
-STORE, 140624029220864, 140624037609471,
-STORE, 140624020824064, 140624029216767,
-SNULL, 140624020828159, 140624029216767,
-STORE, 140624020824064, 140624020828159,
-STORE, 140624020828160, 140624029216767,
-STORE, 140624012431360, 140624020824063,
-SNULL, 140624012435455, 140624020824063,
-STORE, 140624012431360, 140624012435455,
-STORE, 140624012435456, 140624020824063,
-STORE, 140623931764736, 140623940157439,
-STORE, 140623797547008, 140623931764735,
-SNULL, 140623797547008, 140623805939711,
-STORE, 140623805939712, 140623931764735,
-STORE, 140623797547008, 140623805939711,
-ERASE, 140623797547008, 140623805939711,
-SNULL, 140623873048575, 140623931764735,
-STORE, 140623805939712, 140623873048575,
-STORE, 140623873048576, 140623931764735,
-ERASE, 140623873048576, 140623931764735,
-STORE, 140623923372032, 140623940157439,
-STORE, 140623914979328, 140623940157439,
-STORE, 140623906586624, 140623940157439,
-STORE, 140623671721984, 140623873048575,
-SNULL, 140623738830847, 140623873048575,
-STORE, 140623671721984, 140623738830847,
-STORE, 140623738830848, 140623873048575,
-SNULL, 140623738830848, 140623805939711,
-STORE, 140623805939712, 140623873048575,
-STORE, 140623738830848, 140623805939711,
-ERASE, 140623738830848, 140623805939711,
-SNULL, 140623806074879, 140623873048575,
-STORE, 140623805939712, 140623806074879,
-STORE, 140623806074880, 140623873048575,
-SNULL, 140623906586624, 140623931764735,
-STORE, 140623931764736, 140623940157439,
-STORE, 140623906586624, 140623931764735,
-SNULL, 140623931768831, 140623940157439,
-STORE, 140623931764736, 140623931768831,
-STORE, 140623931768832, 140623940157439,
-STORE, 140623537504256, 140623738830847,
-SNULL, 140623537504256, 140623671721983,
-STORE, 140623671721984, 140623738830847,
-STORE, 140623537504256, 140623671721983,
-SNULL, 140623671857151, 140623738830847,
-STORE, 140623671721984, 140623671857151,
-STORE, 140623671857152, 140623738830847,
-SNULL, 140623604613119, 140623671721983,
-STORE, 140623537504256, 140623604613119,
-STORE, 140623604613120, 140623671721983,
-ERASE, 140623604613120, 140623671721983,
-SNULL, 140623537639423, 140623604613119,
-STORE, 140623537504256, 140623537639423,
-STORE, 140623537639424, 140623604613119,
-STORE, 140623537639424, 140623671721983,
-SNULL, 140623537639424, 140623604613119,
-STORE, 140623604613120, 140623671721983,
-STORE, 140623537639424, 140623604613119,
-SNULL, 140623604748287, 140623671721983,
-STORE, 140623604613120, 140623604748287,
-STORE, 140623604748288, 140623671721983,
-STORE, 140623898193920, 140623931764735,
-SNULL, 140623898193920, 140623923372031,
-STORE, 140623923372032, 140623931764735,
-STORE, 140623898193920, 140623923372031,
-SNULL, 140623923376127, 140623931764735,
-STORE, 140623923372032, 140623923376127,
-STORE, 140623923376128, 140623931764735,
-STORE, 140623889801216, 140623923372031,
-SNULL, 140623889801216, 140623898193919,
-STORE, 140623898193920, 140623923372031,
-STORE, 140623889801216, 140623898193919,
-SNULL, 140623898198015, 140623923372031,
-STORE, 140623898193920, 140623898198015,
-STORE, 140623898198016, 140623923372031,
-SNULL, 140623889805311, 140623898193919,
-STORE, 140623889801216, 140623889805311,
-STORE, 140623889805312, 140623898193919,
-SNULL, 140623898198016, 140623906586623,
-STORE, 140623906586624, 140623923372031,
-STORE, 140623898198016, 140623906586623,
-SNULL, 140623906590719, 140623923372031,
-STORE, 140623906586624, 140623906590719,
-STORE, 140623906590720, 140623923372031,
-STORE, 140623881408512, 140623889801215,
-SNULL, 140623906590720, 140623914979327,
-STORE, 140623914979328, 140623923372031,
-STORE, 140623906590720, 140623914979327,
-SNULL, 140623914983423, 140623923372031,
-STORE, 140623914979328, 140623914983423,
-STORE, 140623914983424, 140623923372031,
-SNULL, 140623881412607, 140623889801215,
-STORE, 140623881408512, 140623881412607,
-STORE, 140623881412608, 140623889801215,
-STORE, 140623797547008, 140623805939711,
-STORE, 140623789154304, 140623805939711,
-STORE, 140623780761600, 140623805939711,
-SNULL, 140623780761600, 140623789154303,
-STORE, 140623789154304, 140623805939711,
-STORE, 140623780761600, 140623789154303,
-SNULL, 140623789158399, 140623805939711,
-STORE, 140623789154304, 140623789158399,
-STORE, 140623789158400, 140623805939711,
-STORE, 140623772368896, 140623789154303,
-STORE, 140623763976192, 140623789154303,
-SNULL, 140623763976192, 140623780761599,
-STORE, 140623780761600, 140623789154303,
-STORE, 140623763976192, 140623780761599,
-SNULL, 140623780765695, 140623789154303,
-STORE, 140623780761600, 140623780765695,
-STORE, 140623780765696, 140623789154303,
-SNULL, 140623789158400, 140623797547007,
-STORE, 140623797547008, 140623805939711,
-STORE, 140623789158400, 140623797547007,
-SNULL, 140623797551103, 140623805939711,
-STORE, 140623797547008, 140623797551103,
-STORE, 140623797551104, 140623805939711,
-SNULL, 140623763976192, 140623772368895,
-STORE, 140623772368896, 140623780761599,
-STORE, 140623763976192, 140623772368895,
-SNULL, 140623772372991, 140623780761599,
-STORE, 140623772368896, 140623772372991,
-STORE, 140623772372992, 140623780761599,
-SNULL, 140623763980287, 140623772368895,
-STORE, 140623763976192, 140623763980287,
-STORE, 140623763980288, 140623772368895,
-STORE, 140623755583488, 140623763976191,
-STORE, 140623747190784, 140623763976191,
-SNULL, 140623747190784, 140623755583487,
-STORE, 140623755583488, 140623763976191,
-STORE, 140623747190784, 140623755583487,
-SNULL, 140623755587583, 140623763976191,
-STORE, 140623755583488, 140623755587583,
-STORE, 140623755587584, 140623763976191,
-STORE, 140623529111552, 140623537504255,
-SNULL, 140623747194879, 140623755583487,
-STORE, 140623747190784, 140623747194879,
-STORE, 140623747194880, 140623755583487,
-SNULL, 140623529115647, 140623537504255,
-STORE, 140623529111552, 140623529115647,
-STORE, 140623529115648, 140623537504255,
-STORE, 140623520718848, 140623529111551,
-SNULL, 140623520722943, 140623529111551,
-STORE, 140623520718848, 140623520722943,
-STORE, 140623520722944, 140623529111551,
-STORE, 140623512326144, 140623520718847,
-STORE, 140623503933440, 140623520718847,
-STORE, 140623495540736, 140623520718847,
-STORE, 140623361323008, 140623495540735,
-STORE, 140623227105280, 140623495540735,
-STORE, 140623218712576, 140623227105279,
-STORE, 140623084494848, 140623218712575,
-STORE, 140623076102144, 140623084494847,
-STORE, 140622941884416, 140623076102143,
-SNULL, 140622941884416, 140623000633343,
-STORE, 140623000633344, 140623076102143,
-STORE, 140622941884416, 140623000633343,
-ERASE, 140622941884416, 140623000633343,
-STORE, 140622992240640, 140623000633343,
-STORE, 140622983847936, 140623000633343,
-STORE, 140622849630208, 140622983847935,
-STORE, 140622841237504, 140622849630207,
-SNULL, 140622849630208, 140622866415615,
-STORE, 140622866415616, 140622983847935,
-STORE, 140622849630208, 140622866415615,
-ERASE, 140622849630208, 140622866415615,
-STORE, 140622858022912, 140622866415615,
-SNULL, 140622933524479, 140622983847935,
-STORE, 140622866415616, 140622933524479,
-STORE, 140622933524480, 140622983847935,
-ERASE, 140622933524480, 140622983847935,
-STORE, 140622975455232, 140623000633343,
-STORE, 140622707019776, 140622841237503,
-STORE, 140622967062528, 140623000633343,
-STORE, 140622572802048, 140622841237503,
-STORE, 140622958669824, 140623000633343,
-STORE, 140622438584320, 140622841237503,
-STORE, 140622950277120, 140623000633343,
-SNULL, 140622858027007, 140622866415615,
-STORE, 140622858022912, 140622858027007,
-STORE, 140622858027008, 140622866415615,
-STORE, 140622941884416, 140623000633343,
-STORE, 140622841237504, 140622858022911,
-SNULL, 140622841237504, 140622849630207,
-STORE, 140622849630208, 140622858022911,
-STORE, 140622841237504, 140622849630207,
-SNULL, 140622849634303, 140622858022911,
-STORE, 140622849630208, 140622849634303,
-STORE, 140622849634304, 140622858022911,
-STORE, 140622430191616, 140622438584319,
-SNULL, 140622430195711, 140622438584319,
-STORE, 140622430191616, 140622430195711,
-STORE, 140622430195712, 140622438584319,
-SNULL, 140623361323007, 140623495540735,
-STORE, 140623227105280, 140623361323007,
-STORE, 140623361323008, 140623495540735,
-SNULL, 140623361323008, 140623403286527,
-STORE, 140623403286528, 140623495540735,
-STORE, 140623361323008, 140623403286527,
-ERASE, 140623361323008, 140623403286527,
-SNULL, 140623470395391, 140623495540735,
-STORE, 140623403286528, 140623470395391,
-STORE, 140623470395392, 140623495540735,
-ERASE, 140623470395392, 140623495540735,
-SNULL, 140623227105280, 140623269068799,
-STORE, 140623269068800, 140623361323007,
-STORE, 140623227105280, 140623269068799,
-ERASE, 140623227105280, 140623269068799,
-SNULL, 140623084494848, 140623134851071,
-STORE, 140623134851072, 140623218712575,
-STORE, 140623084494848, 140623134851071,
-ERASE, 140623084494848, 140623134851071,
-SNULL, 140623201959935, 140623218712575,
-STORE, 140623134851072, 140623201959935,
-STORE, 140623201959936, 140623218712575,
-ERASE, 140623201959936, 140623218712575,
-SNULL, 140623067742207, 140623076102143,
-STORE, 140623000633344, 140623067742207,
-STORE, 140623067742208, 140623076102143,
-ERASE, 140623067742208, 140623076102143,
-STORE, 140622295973888, 140622430191615,
-SNULL, 140622295973888, 140622329544703,
-STORE, 140622329544704, 140622430191615,
-STORE, 140622295973888, 140622329544703,
-ERASE, 140622295973888, 140622329544703,
-SNULL, 140622866550783, 140622933524479,
-STORE, 140622866415616, 140622866550783,
-STORE, 140622866550784, 140622933524479,
-SNULL, 140622707019775, 140622841237503,
-STORE, 140622438584320, 140622707019775,
-STORE, 140622707019776, 140622841237503,
-SNULL, 140622707019776, 140622732197887,
-STORE, 140622732197888, 140622841237503,
-STORE, 140622707019776, 140622732197887,
-ERASE, 140622707019776, 140622732197887,
-SNULL, 140622799306751, 140622841237503,
-STORE, 140622732197888, 140622799306751,
-STORE, 140622799306752, 140622841237503,
-ERASE, 140622799306752, 140622841237503,
-SNULL, 140622572802047, 140622707019775,
-STORE, 140622438584320, 140622572802047,
-STORE, 140622572802048, 140622707019775,
-SNULL, 140622572802048, 140622597980159,
-STORE, 140622597980160, 140622707019775,
-STORE, 140622572802048, 140622597980159,
-ERASE, 140622572802048, 140622597980159,
-SNULL, 140622438584320, 140622463762431,
-STORE, 140622463762432, 140622572802047,
-STORE, 140622438584320, 140622463762431,
-ERASE, 140622438584320, 140622463762431,
-SNULL, 140622530871295, 140622572802047,
-STORE, 140622463762432, 140622530871295,
-STORE, 140622530871296, 140622572802047,
-ERASE, 140622530871296, 140622572802047,
-STORE, 140622195326976, 140622430191615,
-SNULL, 140622262435839, 140622430191615,
-STORE, 140622195326976, 140622262435839,
-STORE, 140622262435840, 140622430191615,
-SNULL, 140622262435840, 140622329544703,
-STORE, 140622329544704, 140622430191615,
-STORE, 140622262435840, 140622329544703,
-ERASE, 140622262435840, 140622329544703,
-SNULL, 140622841241599, 140622849630207,
-STORE, 140622841237504, 140622841241599,
-STORE, 140622841241600, 140622849630207,
-STORE, 140623487148032, 140623520718847,
-STORE, 140623478755328, 140623520718847,
-SNULL, 140622941884416, 140622983847935,
-STORE, 140622983847936, 140623000633343,
-STORE, 140622941884416, 140622983847935,
-SNULL, 140622983852031, 140623000633343,
-STORE, 140622983847936, 140622983852031,
-STORE, 140622983852032, 140623000633343,
-STORE, 140623394893824, 140623403286527,
-SNULL, 140623394897919, 140623403286527,
-STORE, 140623394893824, 140623394897919,
-STORE, 140623394897920, 140623403286527,
-SNULL, 140623403421695, 140623470395391,
-STORE, 140623403286528, 140623403421695,
-STORE, 140623403421696, 140623470395391,
-SNULL, 140623478755328, 140623503933439,
-STORE, 140623503933440, 140623520718847,
-STORE, 140623478755328, 140623503933439,
-SNULL, 140623503937535, 140623520718847,
-STORE, 140623503933440, 140623503937535,
-STORE, 140623503937536, 140623520718847,
-SNULL, 140623336177663, 140623361323007,
-STORE, 140623269068800, 140623336177663,
-STORE, 140623336177664, 140623361323007,
-ERASE, 140623336177664, 140623361323007,
-SNULL, 140623269203967, 140623336177663,
-STORE, 140623269068800, 140623269203967,
-STORE, 140623269203968, 140623336177663,
-SNULL, 140623134986239, 140623201959935,
-STORE, 140623134851072, 140623134986239,
-STORE, 140623134986240, 140623201959935,
-SNULL, 140623000768511, 140623067742207,
-STORE, 140623000633344, 140623000768511,
-STORE, 140623000768512, 140623067742207,
-SNULL, 140622396653567, 140622430191615,
-STORE, 140622329544704, 140622396653567,
-STORE, 140622396653568, 140622430191615,
-ERASE, 140622396653568, 140622430191615,
-SNULL, 140622732333055, 140622799306751,
-STORE, 140622732197888, 140622732333055,
-STORE, 140622732333056, 140622799306751,
-SNULL, 140622941884416, 140622975455231,
-STORE, 140622975455232, 140622983847935,
-STORE, 140622941884416, 140622975455231,
-SNULL, 140622975459327, 140622983847935,
-STORE, 140622975455232, 140622975459327,
-STORE, 140622975459328, 140622983847935,
-SNULL, 140622665089023, 140622707019775,
-STORE, 140622597980160, 140622665089023,
-STORE, 140622665089024, 140622707019775,
-ERASE, 140622665089024, 140622707019775,
-SNULL, 140622598115327, 140622665089023,
-STORE, 140622597980160, 140622598115327,
-STORE, 140622598115328, 140622665089023,
-SNULL, 140622463897599, 140622530871295,
-STORE, 140622463762432, 140622463897599,
-STORE, 140622463897600, 140622530871295,
-SNULL, 140622195462143, 140622262435839,
-STORE, 140622195326976, 140622195462143,
-STORE, 140622195462144, 140622262435839,
-STORE, 140623386501120, 140623394893823,
-SNULL, 140622941884416, 140622950277119,
-STORE, 140622950277120, 140622975455231,
-STORE, 140622941884416, 140622950277119,
-SNULL, 140622950281215, 140622975455231,
-STORE, 140622950277120, 140622950281215,
-STORE, 140622950281216, 140622975455231,
-SNULL, 140622941888511, 140622950277119,
-STORE, 140622941884416, 140622941888511,
-STORE, 140622941888512, 140622950277119,
-STORE, 140623378108416, 140623394893823,
-SNULL, 140623478755328, 140623495540735,
-STORE, 140623495540736, 140623503933439,
-STORE, 140623478755328, 140623495540735,
-SNULL, 140623495544831, 140623503933439,
-STORE, 140623495540736, 140623495544831,
-STORE, 140623495544832, 140623503933439,
-SNULL, 140623478755328, 140623487148031,
-STORE, 140623487148032, 140623495540735,
-STORE, 140623478755328, 140623487148031,
-SNULL, 140623487152127, 140623495540735,
-STORE, 140623487148032, 140623487152127,
-STORE, 140623487152128, 140623495540735,
-SNULL, 140623218716671, 140623227105279,
-STORE, 140623218712576, 140623218716671,
-STORE, 140623218716672, 140623227105279,
-SNULL, 140623076106239, 140623084494847,
-STORE, 140623076102144, 140623076106239,
-STORE, 140623076106240, 140623084494847,
-SNULL, 140622329679871, 140622396653567,
-STORE, 140622329544704, 140622329679871,
-STORE, 140622329679872, 140622396653567,
-SNULL, 140622950281216, 140622958669823,
-STORE, 140622958669824, 140622975455231,
-STORE, 140622950281216, 140622958669823,
-SNULL, 140622958673919, 140622975455231,
-STORE, 140622958669824, 140622958673919,
-STORE, 140622958673920, 140622975455231,
-SNULL, 140623503937536, 140623512326143,
-STORE, 140623512326144, 140623520718847,
-STORE, 140623503937536, 140623512326143,
-SNULL, 140623512330239, 140623520718847,
-STORE, 140623512326144, 140623512330239,
-STORE, 140623512330240, 140623520718847,
-SNULL, 140623378108416, 140623386501119,
-STORE, 140623386501120, 140623394893823,
-STORE, 140623378108416, 140623386501119,
-SNULL, 140623386505215, 140623394893823,
-STORE, 140623386501120, 140623386505215,
-STORE, 140623386505216, 140623394893823,
-STORE, 140623369715712, 140623386501119,
-STORE, 140623361323008, 140623386501119,
-STORE, 140623352930304, 140623386501119,
-SNULL, 140623352930304, 140623361323007,
-STORE, 140623361323008, 140623386501119,
-STORE, 140623352930304, 140623361323007,
-SNULL, 140623361327103, 140623386501119,
-STORE, 140623361323008, 140623361327103,
-STORE, 140623361327104, 140623386501119,
-SNULL, 140623478759423, 140623487148031,
-STORE, 140623478755328, 140623478759423,
-STORE, 140623478759424, 140623487148031,
-STORE, 140623344537600, 140623361323007,
-STORE, 140623260676096, 140623269068799,
-SNULL, 140622958673920, 140622967062527,
-STORE, 140622967062528, 140622975455231,
-STORE, 140622958673920, 140622967062527,
-SNULL, 140622967066623, 140622975455231,
-STORE, 140622967062528, 140622967066623,
-STORE, 140622967066624, 140622975455231,
-STORE, 140623252283392, 140623269068799,
-STORE, 140623243890688, 140623269068799,
-SNULL, 140622983852032, 140622992240639,
-STORE, 140622992240640, 140623000633343,
-STORE, 140622983852032, 140622992240639,
-SNULL, 140622992244735, 140623000633343,
-STORE, 140622992240640, 140622992244735,
-STORE, 140622992244736, 140623000633343,
-STORE, 140623235497984, 140623269068799,
-STORE, 140623218716672, 140623235497983,
-STORE, 140623210319872, 140623218712575,
-STORE, 140623126458368, 140623134851071,
-SNULL, 140623210323967, 140623218712575,
-STORE, 140623210319872, 140623210323967,
-STORE, 140623210323968, 140623218712575,
-SNULL, 140623218716672, 140623227105279,
-STORE, 140623227105280, 140623235497983,
-STORE, 140623218716672, 140623227105279,
-SNULL, 140623227109375, 140623235497983,
-STORE, 140623227105280, 140623227109375,
-STORE, 140623227109376, 140623235497983,
-STORE, 140623118065664, 140623134851071,
-STORE, 140623109672960, 140623134851071,
-SNULL, 140623109677055, 140623134851071,
-STORE, 140623109672960, 140623109677055,
-STORE, 140623109677056, 140623134851071,
-STORE, 140623101280256, 140623109672959,
-STORE, 140623092887552, 140623109672959,
-SNULL, 140623092887552, 140623101280255,
-STORE, 140623101280256, 140623109672959,
-STORE, 140623092887552, 140623101280255,
-SNULL, 140623101284351, 140623109672959,
-STORE, 140623101280256, 140623101284351,
-STORE, 140623101284352, 140623109672959,
-SNULL, 140623361327104, 140623378108415,
-STORE, 140623378108416, 140623386501119,
-STORE, 140623361327104, 140623378108415,
-SNULL, 140623378112511, 140623386501119,
-STORE, 140623378108416, 140623378112511,
-STORE, 140623378112512, 140623386501119,
-SNULL, 140623235497984, 140623243890687,
-STORE, 140623243890688, 140623269068799,
-STORE, 140623235497984, 140623243890687,
-SNULL, 140623243894783, 140623269068799,
-STORE, 140623243890688, 140623243894783,
-STORE, 140623243894784, 140623269068799,
-SNULL, 140623361327104, 140623369715711,
-STORE, 140623369715712, 140623378108415,
-STORE, 140623361327104, 140623369715711,
-SNULL, 140623369719807, 140623378108415,
-STORE, 140623369715712, 140623369719807,
-STORE, 140623369719808, 140623378108415,
-SNULL, 140623243894784, 140623252283391,
-STORE, 140623252283392, 140623269068799,
-STORE, 140623243894784, 140623252283391,
-SNULL, 140623252287487, 140623269068799,
-STORE, 140623252283392, 140623252287487,
-STORE, 140623252287488, 140623269068799,
-SNULL, 140623235502079, 140623243890687,
-STORE, 140623235497984, 140623235502079,
-STORE, 140623235502080, 140623243890687,
-SNULL, 140623344541695, 140623361323007,
-STORE, 140623344537600, 140623344541695,
-STORE, 140623344541696, 140623361323007,
-STORE, 140623076106240, 140623092887551,
-SNULL, 140623076106240, 140623084494847,
-STORE, 140623084494848, 140623092887551,
-STORE, 140623076106240, 140623084494847,
-SNULL, 140623084498943, 140623092887551,
-STORE, 140623084494848, 140623084498943,
-STORE, 140623084498944, 140623092887551,
-SNULL, 140623344541696, 140623352930303,
-STORE, 140623352930304, 140623361323007,
-STORE, 140623344541696, 140623352930303,
-SNULL, 140623352934399, 140623361323007,
-STORE, 140623352930304, 140623352934399,
-STORE, 140623352934400, 140623361323007,
-SNULL, 140623109677056, 140623118065663,
-STORE, 140623118065664, 140623134851071,
-STORE, 140623109677056, 140623118065663,
-SNULL, 140623118069759, 140623134851071,
-STORE, 140623118065664, 140623118069759,
-STORE, 140623118069760, 140623134851071,
-STORE, 140622832844800, 140622841237503,
-STORE, 140622824452096, 140622841237503,
-SNULL, 140622824452096, 140622832844799,
-STORE, 140622832844800, 140622841237503,
-STORE, 140622824452096, 140622832844799,
-SNULL, 140622832848895, 140622841237503,
-STORE, 140622832844800, 140622832848895,
-STORE, 140622832848896, 140622841237503,
-STORE, 140622816059392, 140622832844799,
-SNULL, 140623092891647, 140623101280255,
-STORE, 140623092887552, 140623092891647,
-STORE, 140623092891648, 140623101280255,
-SNULL, 140623118069760, 140623126458367,
-STORE, 140623126458368, 140623134851071,
-STORE, 140623118069760, 140623126458367,
-SNULL, 140623126462463, 140623134851071,
-STORE, 140623126458368, 140623126462463,
-STORE, 140623126462464, 140623134851071,
-SNULL, 140623252287488, 140623260676095,
-STORE, 140623260676096, 140623269068799,
-STORE, 140623252287488, 140623260676095,
-SNULL, 140623260680191, 140623269068799,
-STORE, 140623260676096, 140623260680191,
-STORE, 140623260680192, 140623269068799,
-STORE, 140622807666688, 140622832844799,
-STORE, 140622723805184, 140622732197887,
-STORE, 140622715412480, 140622732197887,
-STORE, 140622707019776, 140622732197887,
-SNULL, 140622707023871, 140622732197887,
-STORE, 140622707019776, 140622707023871,
-STORE, 140622707023872, 140622732197887,
-STORE, 140622698627072, 140622707019775,
-STORE, 140622690234368, 140622707019775,
-SNULL, 140622690238463, 140622707019775,
-STORE, 140622690234368, 140622690238463,
-STORE, 140622690238464, 140622707019775,
-SNULL, 140622807666688, 140622816059391,
-STORE, 140622816059392, 140622832844799,
-STORE, 140622807666688, 140622816059391,
-SNULL, 140622816063487, 140622832844799,
-STORE, 140622816059392, 140622816063487,
-STORE, 140622816063488, 140622832844799,
-STORE, 140622681841664, 140622690234367,
-STORE, 140622673448960, 140622690234367,
-SNULL, 140622673453055, 140622690234367,
-STORE, 140622673448960, 140622673453055,
-STORE, 140622673453056, 140622690234367,
-STORE, 140622589587456, 140622597980159,
-SNULL, 140622807670783, 140622816059391,
-STORE, 140622807666688, 140622807670783,
-STORE, 140622807670784, 140622816059391,
-STORE, 140622581194752, 140622597980159,
-SNULL, 140622581198847, 140622597980159,
-STORE, 140622581194752, 140622581198847,
-STORE, 140622581198848, 140622597980159,
-SNULL, 140622816063488, 140622824452095,
-STORE, 140622824452096, 140622832844799,
-STORE, 140622816063488, 140622824452095,
-SNULL, 140622824456191, 140622832844799,
-STORE, 140622824452096, 140622824456191,
-STORE, 140622824456192, 140622832844799,
-STORE, 140622572802048, 140622581194751,
-SNULL, 140622572806143, 140622581194751,
-STORE, 140622572802048, 140622572806143,
-STORE, 140622572806144, 140622581194751,
-STORE, 140622564409344, 140622572802047,
-STORE, 140622556016640, 140622572802047,
-SNULL, 140622556016640, 140622564409343,
-STORE, 140622564409344, 140622572802047,
-STORE, 140622556016640, 140622564409343,
-SNULL, 140622564413439, 140622572802047,
-STORE, 140622564409344, 140622564413439,
-STORE, 140622564413440, 140622572802047,
-SNULL, 140622690238464, 140622698627071,
-STORE, 140622698627072, 140622707019775,
-STORE, 140622690238464, 140622698627071,
-SNULL, 140622698631167, 140622707019775,
-STORE, 140622698627072, 140622698631167,
-STORE, 140622698631168, 140622707019775,
-SNULL, 140622707023872, 140622723805183,
-STORE, 140622723805184, 140622732197887,
-STORE, 140622707023872, 140622723805183,
-SNULL, 140622723809279, 140622732197887,
-STORE, 140622723805184, 140622723809279,
-STORE, 140622723809280, 140622732197887,
-SNULL, 140622707023872, 140622715412479,
-STORE, 140622715412480, 140622723805183,
-STORE, 140622707023872, 140622715412479,
-SNULL, 140622715416575, 140622723805183,
-STORE, 140622715412480, 140622715416575,
-STORE, 140622715416576, 140622723805183,
-STORE, 140622547623936, 140622564409343,
-SNULL, 140622547628031, 140622564409343,
-STORE, 140622547623936, 140622547628031,
-STORE, 140622547628032, 140622564409343,
-STORE, 140622539231232, 140622547623935,
-SNULL, 140622539235327, 140622547623935,
-STORE, 140622539231232, 140622539235327,
-STORE, 140622539235328, 140622547623935,
-SNULL, 140622581198848, 140622589587455,
-STORE, 140622589587456, 140622597980159,
-STORE, 140622581198848, 140622589587455,
-SNULL, 140622589591551, 140622597980159,
-STORE, 140622589587456, 140622589591551,
-STORE, 140622589591552, 140622597980159,
-STORE, 140622455369728, 140622463762431,
-SNULL, 140622455373823, 140622463762431,
-STORE, 140622455369728, 140622455373823,
-STORE, 140622455373824, 140622463762431,
-STORE, 140622446977024, 140622455369727,
-SNULL, 140622446981119, 140622455369727,
-STORE, 140622446977024, 140622446981119,
-STORE, 140622446981120, 140622455369727,
-SNULL, 140622547628032, 140622556016639,
-STORE, 140622556016640, 140622564409343,
-STORE, 140622547628032, 140622556016639,
-SNULL, 140622556020735, 140622564409343,
-STORE, 140622556016640, 140622556020735,
-STORE, 140622556020736, 140622564409343,
-STORE, 140622430195712, 140622446977023,
-STORE, 140622421798912, 140622430191615,
-SNULL, 140622430195712, 140622438584319,
-STORE, 140622438584320, 140622446977023,
-STORE, 140622430195712, 140622438584319,
-SNULL, 140622438588415, 140622446977023,
-STORE, 140622438584320, 140622438588415,
-STORE, 140622438588416, 140622446977023,
-STORE, 140622413406208, 140622430191615,
-STORE, 140622405013504, 140622430191615,
-SNULL, 140622405013504, 140622413406207,
-STORE, 140622413406208, 140622430191615,
-STORE, 140622405013504, 140622413406207,
-SNULL, 140622413410303, 140622430191615,
-STORE, 140622413406208, 140622413410303,
-STORE, 140622413410304, 140622430191615,
-SNULL, 140622673453056, 140622681841663,
-STORE, 140622681841664, 140622690234367,
-STORE, 140622673453056, 140622681841663,
-SNULL, 140622681845759, 140622690234367,
-STORE, 140622681841664, 140622681845759,
-STORE, 140622681845760, 140622690234367,
-STORE, 140622321152000, 140622329544703,
-SNULL, 140622413410304, 140622421798911,
-STORE, 140622421798912, 140622430191615,
-STORE, 140622413410304, 140622421798911,
-SNULL, 140622421803007, 140622430191615,
-STORE, 140622421798912, 140622421803007,
-STORE, 140622421803008, 140622430191615,
-STORE, 140622312759296, 140622329544703,
-SNULL, 140622312763391, 140622329544703,
-STORE, 140622312759296, 140622312763391,
-STORE, 140622312763392, 140622329544703,
-SNULL, 140622405017599, 140622413406207,
-STORE, 140622405013504, 140622405017599,
-STORE, 140622405017600, 140622413406207,
-STORE, 140622304366592, 140622312759295,
-SNULL, 140622304370687, 140622312759295,
-STORE, 140622304366592, 140622304370687,
-STORE, 140622304370688, 140622312759295,
-SNULL, 140622312763392, 140622321151999,
-STORE, 140622321152000, 140622329544703,
-STORE, 140622312763392, 140622321151999,
-SNULL, 140622321156095, 140622329544703,
-STORE, 140622321152000, 140622321156095,
-STORE, 140622321156096, 140622329544703,
-STORE, 140624062619648, 140624062648319,
-STORE, 140624010240000, 140624012431359,
-SNULL, 140624010240000, 140624010330111,
-STORE, 140624010330112, 140624012431359,
-STORE, 140624010240000, 140624010330111,
-SNULL, 140624012423167, 140624012431359,
-STORE, 140624010330112, 140624012423167,
-STORE, 140624012423168, 140624012431359,
-ERASE, 140624012423168, 140624012431359,
-STORE, 140624012423168, 140624012431359,
-SNULL, 140624012427263, 140624012431359,
-STORE, 140624012423168, 140624012427263,
-STORE, 140624012427264, 140624012431359,
-ERASE, 140624062619648, 140624062648319,
-ERASE, 140622849630208, 140622849634303,
-ERASE, 140622849634304, 140622858022911,
-ERASE, 140623394893824, 140623394897919,
-ERASE, 140623394897920, 140623403286527,
-ERASE, 140623361323008, 140623361327103,
-ERASE, 140623361327104, 140623369715711,
-ERASE, 140623084494848, 140623084498943,
-ERASE, 140623084498944, 140623092887551,
-ERASE, 140623931764736, 140623931768831,
-ERASE, 140623931768832, 140623940157439,
-ERASE, 140622841237504, 140622841241599,
-ERASE, 140622841241600, 140622849630207,
-ERASE, 140623487148032, 140623487152127,
-ERASE, 140623487152128, 140623495540735,
-ERASE, 140623109672960, 140623109677055,
-ERASE, 140623109677056, 140623118065663,
-ERASE, 140622983847936, 140622983852031,
-ERASE, 140622983852032, 140622992240639,
-ERASE, 140623352930304, 140623352934399,
-ERASE, 140623352934400, 140623361323007,
-ERASE, 140622564409344, 140622564413439,
-ERASE, 140622564413440, 140622572802047,
-ERASE, 140622430191616, 140622430195711,
-ERASE, 140622430195712, 140622438584319,
-ERASE, 140622958669824, 140622958673919,
-ERASE, 140622958673920, 140622967062527,
-ERASE, 140622992240640, 140622992244735,
-ERASE, 140622992244736, 140623000633343,
-ERASE, 140623227105280, 140623227109375,
-ERASE, 140623227109376, 140623235497983,
-ERASE, 140622321152000, 140622321156095,
-ERASE, 140622321156096, 140622329544703,
-ERASE, 140622858022912, 140622858027007,
-ERASE, 140622858027008, 140622866415615,
-ERASE, 140622975455232, 140622975459327,
-ERASE, 140622975459328, 140622983847935,
-ERASE, 140623378108416, 140623378112511,
-ERASE, 140623378112512, 140623386501119,
-ERASE, 140623495540736, 140623495544831,
-ERASE, 140623495544832, 140623503933439,
-ERASE, 140623118065664, 140623118069759,
-ERASE, 140623118069760, 140623126458367,
-ERASE, 140622572802048, 140622572806143,
-ERASE, 140622572806144, 140622581194751,
-ERASE, 140622421798912, 140622421803007,
-ERASE, 140622421803008, 140622430191615,
-ERASE, 140622967062528, 140622967066623,
-ERASE, 140622967066624, 140622975455231,
-ERASE, 140623252283392, 140623252287487,
-ERASE, 140623252287488, 140623260676095,
-ERASE, 140622673448960, 140622673453055,
-ERASE, 140622673453056, 140622681841663,
-ERASE, 140623076102144, 140623076106239,
-ERASE, 140623076106240, 140623084494847,
-ERASE, 140623101280256, 140623101284351,
-ERASE, 140623101284352, 140623109672959,
-ERASE, 140622715412480, 140622715416575,
-ERASE, 140622715416576, 140622723805183,
-ERASE, 140622405013504, 140622405017599,
-ERASE, 140622405017600, 140622413406207,
-ERASE, 140623478755328, 140623478759423,
-ERASE, 140623478759424, 140623487148031,
-ERASE, 140623906586624, 140623906590719,
-ERASE, 140623906590720, 140623914979327,
-ERASE, 140622950277120, 140622950281215,
-ERASE, 140622950281216, 140622958669823,
- };
- unsigned long set32[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140731244212224, 140737488351231,
-SNULL, 140731244216319, 140737488351231,
-STORE, 140731244212224, 140731244216319,
-STORE, 140731244081152, 140731244216319,
-STORE, 94427773984768, 94427776237567,
-SNULL, 94427774115839, 94427776237567,
-STORE, 94427773984768, 94427774115839,
-STORE, 94427774115840, 94427776237567,
-ERASE, 94427774115840, 94427776237567,
-STORE, 94427776208896, 94427776217087,
-STORE, 94427776217088, 94427776237567,
-STORE, 140401464893440, 140401467146239,
-SNULL, 140401465036799, 140401467146239,
-STORE, 140401464893440, 140401465036799,
-STORE, 140401465036800, 140401467146239,
-ERASE, 140401465036800, 140401467146239,
-STORE, 140401467133952, 140401467142143,
-STORE, 140401467142144, 140401467146239,
-STORE, 140731244507136, 140731244511231,
-STORE, 140731244494848, 140731244507135,
-STORE, 140401467105280, 140401467133951,
-STORE, 140401467097088, 140401467105279,
-STORE, 140401462677504, 140401464893439,
-SNULL, 140401462677504, 140401462775807,
-STORE, 140401462775808, 140401464893439,
-STORE, 140401462677504, 140401462775807,
-SNULL, 140401464868863, 140401464893439,
-STORE, 140401462775808, 140401464868863,
-STORE, 140401464868864, 140401464893439,
-SNULL, 140401464868864, 140401464877055,
-STORE, 140401464877056, 140401464893439,
-STORE, 140401464868864, 140401464877055,
-ERASE, 140401464868864, 140401464877055,
-STORE, 140401464868864, 140401464877055,
-ERASE, 140401464877056, 140401464893439,
-STORE, 140401464877056, 140401464893439,
-STORE, 140401458880512, 140401462677503,
-SNULL, 140401458880512, 140401460539391,
-STORE, 140401460539392, 140401462677503,
-STORE, 140401458880512, 140401460539391,
-SNULL, 140401462636543, 140401462677503,
-STORE, 140401460539392, 140401462636543,
-STORE, 140401462636544, 140401462677503,
-SNULL, 140401462636544, 140401462661119,
-STORE, 140401462661120, 140401462677503,
-STORE, 140401462636544, 140401462661119,
-ERASE, 140401462636544, 140401462661119,
-STORE, 140401462636544, 140401462661119,
-ERASE, 140401462661120, 140401462677503,
-STORE, 140401462661120, 140401462677503,
-STORE, 140401467088896, 140401467105279,
-SNULL, 140401462652927, 140401462661119,
-STORE, 140401462636544, 140401462652927,
-STORE, 140401462652928, 140401462661119,
-SNULL, 140401464872959, 140401464877055,
-STORE, 140401464868864, 140401464872959,
-STORE, 140401464872960, 140401464877055,
-SNULL, 94427776212991, 94427776217087,
-STORE, 94427776208896, 94427776212991,
-STORE, 94427776212992, 94427776217087,
-SNULL, 140401467138047, 140401467142143,
-STORE, 140401467133952, 140401467138047,
-STORE, 140401467138048, 140401467142143,
-ERASE, 140401467105280, 140401467133951,
-STORE, 94427784683520, 94427784818687,
-STORE, 140401450487808, 140401458880511,
-SNULL, 140401450491903, 140401458880511,
-STORE, 140401450487808, 140401450491903,
-STORE, 140401450491904, 140401458880511,
-STORE, 140401442095104, 140401450487807,
-STORE, 140401307877376, 140401442095103,
-SNULL, 140401307877376, 140401340055551,
-STORE, 140401340055552, 140401442095103,
-STORE, 140401307877376, 140401340055551,
-ERASE, 140401307877376, 140401340055551,
-SNULL, 140401407164415, 140401442095103,
-STORE, 140401340055552, 140401407164415,
-STORE, 140401407164416, 140401442095103,
-ERASE, 140401407164416, 140401442095103,
-SNULL, 140401340190719, 140401407164415,
-STORE, 140401340055552, 140401340190719,
-STORE, 140401340190720, 140401407164415,
-SNULL, 140401442099199, 140401450487807,
-STORE, 140401442095104, 140401442099199,
-STORE, 140401442099200, 140401450487807,
-STORE, 140401433702400, 140401442095103,
-SNULL, 140401433706495, 140401442095103,
-STORE, 140401433702400, 140401433706495,
-STORE, 140401433706496, 140401442095103,
-STORE, 140401425309696, 140401433702399,
-SNULL, 140401425313791, 140401433702399,
-STORE, 140401425309696, 140401425313791,
-STORE, 140401425313792, 140401433702399,
-STORE, 140401416916992, 140401425309695,
-SNULL, 140401416921087, 140401425309695,
-STORE, 140401416916992, 140401416921087,
-STORE, 140401416921088, 140401425309695,
-STORE, 140401408524288, 140401416916991,
-STORE, 140401205837824, 140401340055551,
-SNULL, 140401272946687, 140401340055551,
-STORE, 140401205837824, 140401272946687,
-STORE, 140401272946688, 140401340055551,
-ERASE, 140401272946688, 140401340055551,
-SNULL, 140401205972991, 140401272946687,
-STORE, 140401205837824, 140401205972991,
-STORE, 140401205972992, 140401272946687,
-STORE, 140401331662848, 140401340055551,
-STORE, 140401323270144, 140401340055551,
-STORE, 140401138728960, 140401205837823,
-STORE, 140401314877440, 140401340055551,
-SNULL, 140401408528383, 140401416916991,
-STORE, 140401408524288, 140401408528383,
-STORE, 140401408528384, 140401416916991,
-SNULL, 140401138864127, 140401205837823,
-STORE, 140401138728960, 140401138864127,
-STORE, 140401138864128, 140401205837823,
-STORE, 140401004511232, 140401138728959,
-SNULL, 140401071620095, 140401138728959,
-STORE, 140401004511232, 140401071620095,
-STORE, 140401071620096, 140401138728959,
-ERASE, 140401071620096, 140401138728959,
-STORE, 140400870293504, 140401071620095,
-SNULL, 140400937402367, 140401071620095,
-STORE, 140400870293504, 140400937402367,
-STORE, 140400937402368, 140401071620095,
-SNULL, 140400937402368, 140401004511231,
-STORE, 140401004511232, 140401071620095,
-STORE, 140400937402368, 140401004511231,
-ERASE, 140400937402368, 140401004511231,
-STORE, 140401306484736, 140401340055551,
-SNULL, 140401306484736, 140401323270143,
-STORE, 140401323270144, 140401340055551,
-STORE, 140401306484736, 140401323270143,
-SNULL, 140401323274239, 140401340055551,
-STORE, 140401323270144, 140401323274239,
-STORE, 140401323274240, 140401340055551,
-SNULL, 140401004646399, 140401071620095,
-STORE, 140401004511232, 140401004646399,
-STORE, 140401004646400, 140401071620095,
-SNULL, 140400870428671, 140400937402367,
-STORE, 140400870293504, 140400870428671,
-STORE, 140400870428672, 140400937402367,
-SNULL, 140401306488831, 140401323270143,
-STORE, 140401306484736, 140401306488831,
-STORE, 140401306488832, 140401323270143,
-STORE, 140401298092032, 140401306484735,
-SNULL, 140401306488832, 140401314877439,
-STORE, 140401314877440, 140401323270143,
-STORE, 140401306488832, 140401314877439,
-SNULL, 140401314881535, 140401323270143,
-STORE, 140401314877440, 140401314881535,
-STORE, 140401314881536, 140401323270143,
-SNULL, 140401323274240, 140401331662847,
-STORE, 140401331662848, 140401340055551,
-STORE, 140401323274240, 140401331662847,
-SNULL, 140401331666943, 140401340055551,
-STORE, 140401331662848, 140401331666943,
-STORE, 140401331666944, 140401340055551,
-SNULL, 140401298096127, 140401306484735,
-STORE, 140401298092032, 140401298096127,
-STORE, 140401298096128, 140401306484735,
-STORE, 140401289699328, 140401298092031,
-STORE, 140401281306624, 140401298092031,
-STORE, 140401130336256, 140401138728959,
-SNULL, 140401281306624, 140401289699327,
-STORE, 140401289699328, 140401298092031,
-STORE, 140401281306624, 140401289699327,
-SNULL, 140401289703423, 140401298092031,
-STORE, 140401289699328, 140401289703423,
-STORE, 140401289703424, 140401298092031,
-STORE, 140401121943552, 140401138728959,
-STORE, 140401113550848, 140401138728959,
-SNULL, 140401281310719, 140401289699327,
-STORE, 140401281306624, 140401281310719,
-STORE, 140401281310720, 140401289699327,
-SNULL, 140401113550848, 140401121943551,
-STORE, 140401121943552, 140401138728959,
-STORE, 140401113550848, 140401121943551,
-SNULL, 140401121947647, 140401138728959,
-STORE, 140401121943552, 140401121947647,
-STORE, 140401121947648, 140401138728959,
-STORE, 140401105158144, 140401121943551,
-SNULL, 140401121947648, 140401130336255,
-STORE, 140401130336256, 140401138728959,
-STORE, 140401121947648, 140401130336255,
-SNULL, 140401130340351, 140401138728959,
-STORE, 140401130336256, 140401130340351,
-STORE, 140401130340352, 140401138728959,
-STORE, 140401096765440, 140401121943551,
-SNULL, 140401096765440, 140401113550847,
-STORE, 140401113550848, 140401121943551,
-STORE, 140401096765440, 140401113550847,
-SNULL, 140401113554943, 140401121943551,
-STORE, 140401113550848, 140401113554943,
-STORE, 140401113554944, 140401121943551,
-STORE, 140401088372736, 140401113550847,
-SNULL, 140401088372736, 140401096765439,
-STORE, 140401096765440, 140401113550847,
-STORE, 140401088372736, 140401096765439,
-SNULL, 140401096769535, 140401113550847,
-STORE, 140401096765440, 140401096769535,
-STORE, 140401096769536, 140401113550847,
-SNULL, 140401096769536, 140401105158143,
-STORE, 140401105158144, 140401113550847,
-STORE, 140401096769536, 140401105158143,
-SNULL, 140401105162239, 140401113550847,
-STORE, 140401105158144, 140401105162239,
-STORE, 140401105162240, 140401113550847,
-SNULL, 140401088376831, 140401096765439,
-STORE, 140401088372736, 140401088376831,
-STORE, 140401088376832, 140401096765439,
-STORE, 140401079980032, 140401088372735,
-STORE, 140400996118528, 140401004511231,
-SNULL, 140401079984127, 140401088372735,
-STORE, 140401079980032, 140401079984127,
-STORE, 140401079984128, 140401088372735,
-SNULL, 140400996122623, 140401004511231,
-STORE, 140400996118528, 140400996122623,
-STORE, 140400996122624, 140401004511231,
-STORE, 140400987725824, 140400996118527,
-STORE, 140400979333120, 140400996118527,
-STORE, 140400803184640, 140400870293503,
-SNULL, 140400803319807, 140400870293503,
-STORE, 140400803184640, 140400803319807,
-STORE, 140400803319808, 140400870293503,
-SNULL, 140400979333120, 140400987725823,
-STORE, 140400987725824, 140400996118527,
-STORE, 140400979333120, 140400987725823,
-SNULL, 140400987729919, 140400996118527,
-STORE, 140400987725824, 140400987729919,
-STORE, 140400987729920, 140400996118527,
-STORE, 140400970940416, 140400987725823,
-STORE, 140400962547712, 140400987725823,
-STORE, 140400668966912, 140400803184639,
-STORE, 140400954155008, 140400987725823,
-STORE, 140400945762304, 140400987725823,
-STORE, 140400660574208, 140400668966911,
-STORE, 140400593465344, 140400660574207,
-STORE, 140400585072640, 140400593465343,
-STORE, 140400450854912, 140400585072639,
-STORE, 140400442462208, 140400450854911,
-STORE, 140400434069504, 140400450854911,
-STORE, 140400299851776, 140400434069503,
-STORE, 140400291459072, 140400299851775,
-SNULL, 140400299851776, 140400333422591,
-STORE, 140400333422592, 140400434069503,
-STORE, 140400299851776, 140400333422591,
-ERASE, 140400299851776, 140400333422591,
-STORE, 140400325029888, 140400333422591,
-STORE, 140400157241344, 140400291459071,
-STORE, 140400316637184, 140400333422591,
-STORE, 140400308244480, 140400333422591,
-STORE, 140400023023616, 140400291459071,
-STORE, 140400291459072, 140400333422591,
-SNULL, 140400023023616, 140400064987135,
-STORE, 140400064987136, 140400291459071,
-STORE, 140400023023616, 140400064987135,
-ERASE, 140400023023616, 140400064987135,
-STORE, 140400056594432, 140400064987135,
-SNULL, 140400056598527, 140400064987135,
-STORE, 140400056594432, 140400056598527,
-STORE, 140400056598528, 140400064987135,
-STORE, 140399989485568, 140400056594431,
-SNULL, 140400291459072, 140400316637183,
-STORE, 140400316637184, 140400333422591,
-STORE, 140400291459072, 140400316637183,
-SNULL, 140400316641279, 140400333422591,
-STORE, 140400316637184, 140400316641279,
-STORE, 140400316641280, 140400333422591,
-STORE, 140399855267840, 140400056594431,
-SNULL, 140399855267840, 140399863660543,
-STORE, 140399863660544, 140400056594431,
-STORE, 140399855267840, 140399863660543,
-ERASE, 140399855267840, 140399863660543,
-SNULL, 140400736075775, 140400803184639,
-STORE, 140400668966912, 140400736075775,
-STORE, 140400736075776, 140400803184639,
-ERASE, 140400736075776, 140400803184639,
-SNULL, 140400669102079, 140400736075775,
-STORE, 140400668966912, 140400669102079,
-STORE, 140400669102080, 140400736075775,
-STORE, 140400669102080, 140400803184639,
-SNULL, 140400669102080, 140400736075775,
-STORE, 140400736075776, 140400803184639,
-STORE, 140400669102080, 140400736075775,
-SNULL, 140400736210943, 140400803184639,
-STORE, 140400736075776, 140400736210943,
-STORE, 140400736210944, 140400803184639,
-ERASE, 140400593465344, 140400660574207,
-SNULL, 140400450854912, 140400467640319,
-STORE, 140400467640320, 140400585072639,
-STORE, 140400450854912, 140400467640319,
-ERASE, 140400450854912, 140400467640319,
-STORE, 140399729442816, 140400056594431,
-SNULL, 140400400531455, 140400434069503,
-STORE, 140400333422592, 140400400531455,
-STORE, 140400400531456, 140400434069503,
-ERASE, 140400400531456, 140400434069503,
-SNULL, 140400333557759, 140400400531455,
-STORE, 140400333422592, 140400333557759,
-STORE, 140400333557760, 140400400531455,
-SNULL, 140400157241343, 140400291459071,
-STORE, 140400064987136, 140400157241343,
-STORE, 140400157241344, 140400291459071,
-SNULL, 140400157241344, 140400199204863,
-STORE, 140400199204864, 140400291459071,
-STORE, 140400157241344, 140400199204863,
-ERASE, 140400157241344, 140400199204863,
-SNULL, 140400266313727, 140400291459071,
-STORE, 140400199204864, 140400266313727,
-STORE, 140400266313728, 140400291459071,
-ERASE, 140400266313728, 140400291459071,
-SNULL, 140400132095999, 140400157241343,
-STORE, 140400064987136, 140400132095999,
-STORE, 140400132096000, 140400157241343,
-ERASE, 140400132096000, 140400157241343,
-SNULL, 140400065122303, 140400132095999,
-STORE, 140400064987136, 140400065122303,
-STORE, 140400065122304, 140400132095999,
-SNULL, 140400945762304, 140400954155007,
-STORE, 140400954155008, 140400987725823,
-STORE, 140400945762304, 140400954155007,
-SNULL, 140400954159103, 140400987725823,
-STORE, 140400954155008, 140400954159103,
-STORE, 140400954159104, 140400987725823,
-SNULL, 140400434069504, 140400442462207,
-STORE, 140400442462208, 140400450854911,
-STORE, 140400434069504, 140400442462207,
-SNULL, 140400442466303, 140400450854911,
-STORE, 140400442462208, 140400442466303,
-STORE, 140400442466304, 140400450854911,
-SNULL, 140400291463167, 140400316637183,
-STORE, 140400291459072, 140400291463167,
-STORE, 140400291463168, 140400316637183,
-STORE, 140400652181504, 140400668966911,
-STORE, 140400643788800, 140400668966911,
-SNULL, 140400291463168, 140400299851775,
-STORE, 140400299851776, 140400316637183,
-STORE, 140400291463168, 140400299851775,
-SNULL, 140400299855871, 140400316637183,
-STORE, 140400299851776, 140400299855871,
-STORE, 140400299855872, 140400316637183,
-STORE, 140400635396096, 140400668966911,
-SNULL, 140400635396096, 140400643788799,
-STORE, 140400643788800, 140400668966911,
-STORE, 140400635396096, 140400643788799,
-SNULL, 140400643792895, 140400668966911,
-STORE, 140400643788800, 140400643792895,
-STORE, 140400643792896, 140400668966911,
-SNULL, 140399989485567, 140400056594431,
-STORE, 140399729442816, 140399989485567,
-STORE, 140399989485568, 140400056594431,
-ERASE, 140399989485568, 140400056594431,
-SNULL, 140399930769407, 140399989485567,
-STORE, 140399729442816, 140399930769407,
-STORE, 140399930769408, 140399989485567,
-ERASE, 140399930769408, 140399989485567,
-SNULL, 140400945766399, 140400954155007,
-STORE, 140400945762304, 140400945766399,
-STORE, 140400945766400, 140400954155007,
-SNULL, 140400534749183, 140400585072639,
-STORE, 140400467640320, 140400534749183,
-STORE, 140400534749184, 140400585072639,
-ERASE, 140400534749184, 140400585072639,
-SNULL, 140399796551679, 140399930769407,
-STORE, 140399729442816, 140399796551679,
-STORE, 140399796551680, 140399930769407,
-SNULL, 140399796551680, 140399863660543,
-STORE, 140399863660544, 140399930769407,
-STORE, 140399796551680, 140399863660543,
-ERASE, 140399796551680, 140399863660543,
-SNULL, 140400199340031, 140400266313727,
-STORE, 140400199204864, 140400199340031,
-STORE, 140400199340032, 140400266313727,
-STORE, 140400627003392, 140400643788799,
-SNULL, 140400316641280, 140400325029887,
-STORE, 140400325029888, 140400333422591,
-STORE, 140400316641280, 140400325029887,
-SNULL, 140400325033983, 140400333422591,
-STORE, 140400325029888, 140400325033983,
-STORE, 140400325033984, 140400333422591,
-SNULL, 140400627003392, 140400635396095,
-STORE, 140400635396096, 140400643788799,
-STORE, 140400627003392, 140400635396095,
-SNULL, 140400635400191, 140400643788799,
-STORE, 140400635396096, 140400635400191,
-STORE, 140400635400192, 140400643788799,
-SNULL, 140400434073599, 140400442462207,
-STORE, 140400434069504, 140400434073599,
-STORE, 140400434073600, 140400442462207,
-STORE, 140400618610688, 140400635396095,
-STORE, 140400610217984, 140400635396095,
-SNULL, 140400954159104, 140400962547711,
-STORE, 140400962547712, 140400987725823,
-STORE, 140400954159104, 140400962547711,
-SNULL, 140400962551807, 140400987725823,
-STORE, 140400962547712, 140400962551807,
-STORE, 140400962551808, 140400987725823,
-SNULL, 140400299855872, 140400308244479,
-STORE, 140400308244480, 140400316637183,
-STORE, 140400299855872, 140400308244479,
-SNULL, 140400308248575, 140400316637183,
-STORE, 140400308244480, 140400308248575,
-STORE, 140400308248576, 140400316637183,
-STORE, 140400601825280, 140400635396095,
-SNULL, 140400601829375, 140400635396095,
-STORE, 140400601825280, 140400601829375,
-STORE, 140400601829376, 140400635396095,
-STORE, 140400576679936, 140400593465343,
-SNULL, 140400576684031, 140400593465343,
-STORE, 140400576679936, 140400576684031,
-STORE, 140400576684032, 140400593465343,
-SNULL, 140400643792896, 140400652181503,
-STORE, 140400652181504, 140400668966911,
-STORE, 140400643792896, 140400652181503,
-SNULL, 140400652185599, 140400668966911,
-STORE, 140400652181504, 140400652185599,
-STORE, 140400652185600, 140400668966911,
-STORE, 140399595225088, 140399796551679,
-SNULL, 140399662333951, 140399796551679,
-STORE, 140399595225088, 140399662333951,
-STORE, 140399662333952, 140399796551679,
-SNULL, 140399662333952, 140399729442815,
-STORE, 140399729442816, 140399796551679,
-STORE, 140399662333952, 140399729442815,
-ERASE, 140399662333952, 140399729442815,
-SNULL, 140399863795711, 140399930769407,
-STORE, 140399863660544, 140399863795711,
-STORE, 140399863795712, 140399930769407,
-STORE, 140400568287232, 140400576679935,
-SNULL, 140400568291327, 140400576679935,
-STORE, 140400568287232, 140400568291327,
-STORE, 140400568291328, 140400576679935,
-SNULL, 140400467775487, 140400534749183,
-STORE, 140400467640320, 140400467775487,
-STORE, 140400467775488, 140400534749183,
-SNULL, 140399729577983, 140399796551679,
-STORE, 140399729442816, 140399729577983,
-STORE, 140399729577984, 140399796551679,
-SNULL, 140400601829376, 140400627003391,
-STORE, 140400627003392, 140400635396095,
-STORE, 140400601829376, 140400627003391,
-SNULL, 140400627007487, 140400635396095,
-STORE, 140400627003392, 140400627007487,
-STORE, 140400627007488, 140400635396095,
-STORE, 140400559894528, 140400568287231,
-STORE, 140400551501824, 140400568287231,
-STORE, 140400543109120, 140400568287231,
-STORE, 140400459247616, 140400467640319,
-STORE, 140400442466304, 140400467640319,
-SNULL, 140399595360255, 140399662333951,
-STORE, 140399595225088, 140399595360255,
-STORE, 140399595360256, 140399662333951,
-SNULL, 140400962551808, 140400970940415,
-STORE, 140400970940416, 140400987725823,
-STORE, 140400962551808, 140400970940415,
-SNULL, 140400970944511, 140400987725823,
-STORE, 140400970940416, 140400970944511,
-STORE, 140400970944512, 140400987725823,
-SNULL, 140400652185600, 140400660574207,
-STORE, 140400660574208, 140400668966911,
-STORE, 140400652185600, 140400660574207,
-SNULL, 140400660578303, 140400668966911,
-STORE, 140400660574208, 140400660578303,
-STORE, 140400660578304, 140400668966911,
-SNULL, 140400576684032, 140400585072639,
-STORE, 140400585072640, 140400593465343,
-STORE, 140400576684032, 140400585072639,
-SNULL, 140400585076735, 140400593465343,
-STORE, 140400585072640, 140400585076735,
-STORE, 140400585076736, 140400593465343,
-STORE, 140400425676800, 140400434069503,
-STORE, 140400417284096, 140400434069503,
-STORE, 140400408891392, 140400434069503,
-SNULL, 140400408891392, 140400417284095,
-STORE, 140400417284096, 140400434069503,
-STORE, 140400408891392, 140400417284095,
-SNULL, 140400417288191, 140400434069503,
-STORE, 140400417284096, 140400417288191,
-STORE, 140400417288192, 140400434069503,
-STORE, 140400283066368, 140400291459071,
-SNULL, 140400601829376, 140400618610687,
-STORE, 140400618610688, 140400627003391,
-STORE, 140400601829376, 140400618610687,
-SNULL, 140400618614783, 140400627003391,
-STORE, 140400618610688, 140400618614783,
-STORE, 140400618614784, 140400627003391,
-SNULL, 140400601829376, 140400610217983,
-STORE, 140400610217984, 140400618610687,
-STORE, 140400601829376, 140400610217983,
-SNULL, 140400610222079, 140400618610687,
-STORE, 140400610217984, 140400610222079,
-STORE, 140400610222080, 140400618610687,
-STORE, 140400274673664, 140400291459071,
-STORE, 140400190812160, 140400199204863,
-STORE, 140400182419456, 140400199204863,
-SNULL, 140400442466304, 140400450854911,
-STORE, 140400450854912, 140400467640319,
-STORE, 140400442466304, 140400450854911,
-SNULL, 140400450859007, 140400467640319,
-STORE, 140400450854912, 140400450859007,
-STORE, 140400450859008, 140400467640319,
-SNULL, 140400543109120, 140400559894527,
-STORE, 140400559894528, 140400568287231,
-STORE, 140400543109120, 140400559894527,
-SNULL, 140400559898623, 140400568287231,
-STORE, 140400559894528, 140400559898623,
-STORE, 140400559898624, 140400568287231,
-SNULL, 140400450859008, 140400459247615,
-STORE, 140400459247616, 140400467640319,
-STORE, 140400450859008, 140400459247615,
-SNULL, 140400459251711, 140400467640319,
-STORE, 140400459247616, 140400459251711,
-STORE, 140400459251712, 140400467640319,
-SNULL, 140400543113215, 140400559894527,
-STORE, 140400543109120, 140400543113215,
-STORE, 140400543113216, 140400559894527,
-SNULL, 140400970944512, 140400979333119,
-STORE, 140400979333120, 140400987725823,
-STORE, 140400970944512, 140400979333119,
-SNULL, 140400979337215, 140400987725823,
-STORE, 140400979333120, 140400979337215,
-STORE, 140400979337216, 140400987725823,
-STORE, 140400174026752, 140400199204863,
-SNULL, 140400174030847, 140400199204863,
-STORE, 140400174026752, 140400174030847,
-STORE, 140400174030848, 140400199204863,
-SNULL, 140400274673664, 140400283066367,
-STORE, 140400283066368, 140400291459071,
-STORE, 140400274673664, 140400283066367,
-SNULL, 140400283070463, 140400291459071,
-STORE, 140400283066368, 140400283070463,
-STORE, 140400283070464, 140400291459071,
-STORE, 140400165634048, 140400174026751,
-SNULL, 140400165638143, 140400174026751,
-STORE, 140400165634048, 140400165638143,
-STORE, 140400165638144, 140400174026751,
-SNULL, 140400174030848, 140400182419455,
-STORE, 140400182419456, 140400199204863,
-STORE, 140400174030848, 140400182419455,
-SNULL, 140400182423551, 140400199204863,
-STORE, 140400182419456, 140400182423551,
-STORE, 140400182423552, 140400199204863,
-SNULL, 140400182423552, 140400190812159,
-STORE, 140400190812160, 140400199204863,
-STORE, 140400182423552, 140400190812159,
-SNULL, 140400190816255, 140400199204863,
-STORE, 140400190812160, 140400190816255,
-STORE, 140400190816256, 140400199204863,
-STORE, 140400157241344, 140400165634047,
-SNULL, 140400157245439, 140400165634047,
-STORE, 140400157241344, 140400157245439,
-STORE, 140400157245440, 140400165634047,
-SNULL, 140400408895487, 140400417284095,
-STORE, 140400408891392, 140400408895487,
-STORE, 140400408895488, 140400417284095,
-SNULL, 140400417288192, 140400425676799,
-STORE, 140400425676800, 140400434069503,
-STORE, 140400417288192, 140400425676799,
-SNULL, 140400425680895, 140400434069503,
-STORE, 140400425676800, 140400425680895,
-STORE, 140400425680896, 140400434069503,
-STORE, 140400148848640, 140400157241343,
-SNULL, 140400148852735, 140400157241343,
-STORE, 140400148848640, 140400148852735,
-STORE, 140400148852736, 140400157241343,
-SNULL, 140400543113216, 140400551501823,
-STORE, 140400551501824, 140400559894527,
-STORE, 140400543113216, 140400551501823,
-SNULL, 140400551505919, 140400559894527,
-STORE, 140400551501824, 140400551505919,
-STORE, 140400551505920, 140400559894527,
-STORE, 140400140455936, 140400148848639,
-STORE, 140400048201728, 140400056594431,
-SNULL, 140400140460031, 140400148848639,
-STORE, 140400140455936, 140400140460031,
-STORE, 140400140460032, 140400148848639,
-STORE, 140400039809024, 140400056594431,
-SNULL, 140400039813119, 140400056594431,
-STORE, 140400039809024, 140400039813119,
-STORE, 140400039813120, 140400056594431,
-STORE, 140400031416320, 140400039809023,
-STORE, 140400023023616, 140400039809023,
-SNULL, 140400274677759, 140400283066367,
-STORE, 140400274673664, 140400274677759,
-STORE, 140400274677760, 140400283066367,
-STORE, 140400014630912, 140400039809023,
-STORE, 140400006238208, 140400039809023,
-STORE, 140399997845504, 140400039809023,
-SNULL, 140399997849599, 140400039809023,
-STORE, 140399997845504, 140399997849599,
-STORE, 140399997849600, 140400039809023,
-STORE, 140399989452800, 140399997845503,
-SNULL, 140399989456895, 140399997845503,
-STORE, 140399989452800, 140399989456895,
-STORE, 140399989456896, 140399997845503,
-STORE, 140399981060096, 140399989452799,
-SNULL, 140399981064191, 140399989452799,
-STORE, 140399981060096, 140399981064191,
-STORE, 140399981064192, 140399989452799,
-STORE, 140399972667392, 140399981060095,
-STORE, 140399964274688, 140399981060095,
-SNULL, 140399964278783, 140399981060095,
-STORE, 140399964274688, 140399964278783,
-STORE, 140399964278784, 140399981060095,
-SNULL, 140400039813120, 140400048201727,
-STORE, 140400048201728, 140400056594431,
-STORE, 140400039813120, 140400048201727,
-SNULL, 140400048205823, 140400056594431,
-STORE, 140400048201728, 140400048205823,
-STORE, 140400048205824, 140400056594431,
-SNULL, 140399997849600, 140400031416319,
-STORE, 140400031416320, 140400039809023,
-STORE, 140399997849600, 140400031416319,
-SNULL, 140400031420415, 140400039809023,
-STORE, 140400031416320, 140400031420415,
-STORE, 140400031420416, 140400039809023,
-STORE, 140399955881984, 140399964274687,
-SNULL, 140399955886079, 140399964274687,
-STORE, 140399955881984, 140399955886079,
-STORE, 140399955886080, 140399964274687,
-STORE, 140399947489280, 140399955881983,
-STORE, 140399939096576, 140399955881983,
-STORE, 140399855267840, 140399863660543,
-SNULL, 140399939100671, 140399955881983,
-STORE, 140399939096576, 140399939100671,
-STORE, 140399939100672, 140399955881983,
-SNULL, 140399997849600, 140400014630911,
-STORE, 140400014630912, 140400031416319,
-STORE, 140399997849600, 140400014630911,
-SNULL, 140400014635007, 140400031416319,
-STORE, 140400014630912, 140400014635007,
-STORE, 140400014635008, 140400031416319,
-SNULL, 140400014635008, 140400023023615,
-STORE, 140400023023616, 140400031416319,
-STORE, 140400014635008, 140400023023615,
-SNULL, 140400023027711, 140400031416319,
-STORE, 140400023023616, 140400023027711,
-STORE, 140400023027712, 140400031416319,
-SNULL, 140399997849600, 140400006238207,
-STORE, 140400006238208, 140400014630911,
-STORE, 140399997849600, 140400006238207,
-SNULL, 140400006242303, 140400014630911,
-STORE, 140400006238208, 140400006242303,
-STORE, 140400006242304, 140400014630911,
-STORE, 140399846875136, 140399863660543,
-STORE, 140399838482432, 140399863660543,
-SNULL, 140399838486527, 140399863660543,
-STORE, 140399838482432, 140399838486527,
-STORE, 140399838486528, 140399863660543,
-SNULL, 140399939100672, 140399947489279,
-STORE, 140399947489280, 140399955881983,
-STORE, 140399939100672, 140399947489279,
-SNULL, 140399947493375, 140399955881983,
-STORE, 140399947489280, 140399947493375,
-STORE, 140399947493376, 140399955881983,
-SNULL, 140399964278784, 140399972667391,
-STORE, 140399972667392, 140399981060095,
-STORE, 140399964278784, 140399972667391,
-SNULL, 140399972671487, 140399981060095,
-STORE, 140399972667392, 140399972671487,
-STORE, 140399972671488, 140399981060095,
-SNULL, 140399838486528, 140399855267839,
-STORE, 140399855267840, 140399863660543,
-STORE, 140399838486528, 140399855267839,
-SNULL, 140399855271935, 140399863660543,
-STORE, 140399855267840, 140399855271935,
-STORE, 140399855271936, 140399863660543,
-STORE, 140399830089728, 140399838482431,
-SNULL, 140399830093823, 140399838482431,
-STORE, 140399830089728, 140399830093823,
-STORE, 140399830093824, 140399838482431,
-STORE, 140399821697024, 140399830089727,
-SNULL, 140399821701119, 140399830089727,
-STORE, 140399821697024, 140399821701119,
-STORE, 140399821701120, 140399830089727,
-SNULL, 140399838486528, 140399846875135,
-STORE, 140399846875136, 140399855267839,
-STORE, 140399838486528, 140399846875135,
-SNULL, 140399846879231, 140399855267839,
-STORE, 140399846875136, 140399846879231,
-STORE, 140399846879232, 140399855267839,
-STORE, 140399813304320, 140399821697023,
-STORE, 140399804911616, 140399821697023,
-SNULL, 140399804915711, 140399821697023,
-STORE, 140399804911616, 140399804915711,
-STORE, 140399804915712, 140399821697023,
-STORE, 140399721050112, 140399729442815,
-SNULL, 140399804915712, 140399813304319,
-STORE, 140399813304320, 140399821697023,
-STORE, 140399804915712, 140399813304319,
-SNULL, 140399813308415, 140399821697023,
-STORE, 140399813304320, 140399813308415,
-STORE, 140399813308416, 140399821697023,
-SNULL, 140399721054207, 140399729442815,
-STORE, 140399721050112, 140399721054207,
-STORE, 140399721054208, 140399729442815,
-STORE, 140401467105280, 140401467133951,
-STORE, 140401279115264, 140401281306623,
-SNULL, 140401279115264, 140401279205375,
-STORE, 140401279205376, 140401281306623,
-STORE, 140401279115264, 140401279205375,
-SNULL, 140401281298431, 140401281306623,
-STORE, 140401279205376, 140401281298431,
-STORE, 140401281298432, 140401281306623,
-ERASE, 140401281298432, 140401281306623,
-STORE, 140401281298432, 140401281306623,
-SNULL, 140401281302527, 140401281306623,
-STORE, 140401281298432, 140401281302527,
-STORE, 140401281302528, 140401281306623,
-ERASE, 140401467105280, 140401467133951,
-ERASE, 140400056594432, 140400056598527,
-ERASE, 140400056598528, 140400064987135,
-ERASE, 140400635396096, 140400635400191,
-ERASE, 140400635400192, 140400643788799,
-ERASE, 140400408891392, 140400408895487,
-ERASE, 140400408895488, 140400417284095,
-ERASE, 140400299851776, 140400299855871,
-ERASE, 140400299855872, 140400308244479,
-ERASE, 140400627003392, 140400627007487,
-ERASE, 140400627007488, 140400635396095,
-ERASE, 140400954155008, 140400954159103,
-ERASE, 140400954159104, 140400962547711,
-ERASE, 140400291459072, 140400291463167,
-ERASE, 140400291463168, 140400299851775,
-ERASE, 140400643788800, 140400643792895,
-ERASE, 140400643792896, 140400652181503,
-ERASE, 140400325029888, 140400325033983,
-ERASE, 140400325033984, 140400333422591,
-ERASE, 140400610217984, 140400610222079,
-ERASE, 140400610222080, 140400618610687,
-ERASE, 140400190812160, 140400190816255,
-ERASE, 140400190816256, 140400199204863,
-ERASE, 140399964274688, 140399964278783,
-ERASE, 140399964278784, 140399972667391,
-ERASE, 140400945762304, 140400945766399,
-ERASE, 140400945766400, 140400954155007,
-ERASE, 140400568287232, 140400568291327,
-ERASE, 140400568291328, 140400576679935,
-ERASE, 140399972667392, 140399972671487,
-ERASE, 140399972671488, 140399981060095,
-ERASE, 140400962547712, 140400962551807,
-ERASE, 140400962551808, 140400970940415,
-ERASE, 140400987725824, 140400987729919,
-ERASE, 140400987729920, 140400996118527,
-ERASE, 140400652181504, 140400652185599,
-ERASE, 140400652185600, 140400660574207,
-ERASE, 140400450854912, 140400450859007,
-ERASE, 140400450859008, 140400459247615,
-ERASE, 140400031416320, 140400031420415,
-ERASE, 140400031420416, 140400039809023,
-ERASE, 140400308244480, 140400308248575,
-ERASE, 140400308248576, 140400316637183,
-ERASE, 140400434069504, 140400434073599,
-ERASE, 140400434073600, 140400442462207,
-ERASE, 140400543109120, 140400543113215,
-ERASE, 140400543113216, 140400551501823,
-ERASE, 140400023023616, 140400023027711,
-ERASE, 140400023027712, 140400031416319,
-ERASE, 140399813304320, 140399813308415,
-ERASE, 140399813308416, 140399821697023,
-ERASE, 140400316637184, 140400316641279,
-ERASE, 140400316641280, 140400325029887,
-ERASE, 140400585072640, 140400585076735,
-ERASE, 140400585076736, 140400593465343,
-ERASE, 140400148848640, 140400148852735,
-ERASE, 140400148852736, 140400157241343,
-ERASE, 140399955881984, 140399955886079,
-ERASE, 140399955886080, 140399964274687,
-ERASE, 140399821697024, 140399821701119,
-ERASE, 140399821701120, 140399830089727,
-ERASE, 140400601825280, 140400601829375,
-ERASE, 140400601829376, 140400610217983,
-ERASE, 140400979333120, 140400979337215,
-ERASE, 140400979337216, 140400987725823,
-ERASE, 140399997845504, 140399997849599,
-ERASE, 140399997849600, 140400006238207,
-ERASE, 140400459247616, 140400459251711,
-ERASE, 140400459251712, 140400467640319,
-ERASE, 140400551501824, 140400551505919,
-ERASE, 140400551505920, 140400559894527,
-ERASE, 140399939096576, 140399939100671,
-ERASE, 140399939100672, 140399947489279,
-ERASE, 140400442462208, 140400442466303,
-ERASE, 140400442466304, 140400450854911,
-ERASE, 140400576679936, 140400576684031,
-ERASE, 140400576684032, 140400585072639,
-ERASE, 140400559894528, 140400559898623,
-ERASE, 140400559898624, 140400568287231,
-ERASE, 140400417284096, 140400417288191,
-ERASE, 140400417288192, 140400425676799,
-ERASE, 140400283066368, 140400283070463,
-ERASE, 140400283070464, 140400291459071,
- };
- unsigned long set33[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140734562918400, 140737488351231,
-SNULL, 140734562922495, 140737488351231,
-STORE, 140734562918400, 140734562922495,
-STORE, 140734562787328, 140734562922495,
-STORE, 94133878984704, 94133881237503,
-SNULL, 94133879115775, 94133881237503,
-STORE, 94133878984704, 94133879115775,
-STORE, 94133879115776, 94133881237503,
-ERASE, 94133879115776, 94133881237503,
-STORE, 94133881208832, 94133881217023,
-STORE, 94133881217024, 94133881237503,
-STORE, 140583654043648, 140583656296447,
-SNULL, 140583654187007, 140583656296447,
-STORE, 140583654043648, 140583654187007,
-STORE, 140583654187008, 140583656296447,
-ERASE, 140583654187008, 140583656296447,
-STORE, 140583656284160, 140583656292351,
-STORE, 140583656292352, 140583656296447,
-STORE, 140734564319232, 140734564323327,
-STORE, 140734564306944, 140734564319231,
-STORE, 140583656255488, 140583656284159,
-STORE, 140583656247296, 140583656255487,
-STORE, 140583651827712, 140583654043647,
-SNULL, 140583651827712, 140583651926015,
-STORE, 140583651926016, 140583654043647,
-STORE, 140583651827712, 140583651926015,
-SNULL, 140583654019071, 140583654043647,
-STORE, 140583651926016, 140583654019071,
-STORE, 140583654019072, 140583654043647,
-SNULL, 140583654019072, 140583654027263,
-STORE, 140583654027264, 140583654043647,
-STORE, 140583654019072, 140583654027263,
-ERASE, 140583654019072, 140583654027263,
-STORE, 140583654019072, 140583654027263,
-ERASE, 140583654027264, 140583654043647,
-STORE, 140583654027264, 140583654043647,
-STORE, 140583648030720, 140583651827711,
-SNULL, 140583648030720, 140583649689599,
-STORE, 140583649689600, 140583651827711,
-STORE, 140583648030720, 140583649689599,
-SNULL, 140583651786751, 140583651827711,
-STORE, 140583649689600, 140583651786751,
-STORE, 140583651786752, 140583651827711,
-SNULL, 140583651786752, 140583651811327,
-STORE, 140583651811328, 140583651827711,
-STORE, 140583651786752, 140583651811327,
-ERASE, 140583651786752, 140583651811327,
-STORE, 140583651786752, 140583651811327,
-ERASE, 140583651811328, 140583651827711,
-STORE, 140583651811328, 140583651827711,
-STORE, 140583656239104, 140583656255487,
-SNULL, 140583651803135, 140583651811327,
-STORE, 140583651786752, 140583651803135,
-STORE, 140583651803136, 140583651811327,
-SNULL, 140583654023167, 140583654027263,
-STORE, 140583654019072, 140583654023167,
-STORE, 140583654023168, 140583654027263,
-SNULL, 94133881212927, 94133881217023,
-STORE, 94133881208832, 94133881212927,
-STORE, 94133881212928, 94133881217023,
-SNULL, 140583656288255, 140583656292351,
-STORE, 140583656284160, 140583656288255,
-STORE, 140583656288256, 140583656292351,
-ERASE, 140583656255488, 140583656284159,
-STORE, 94133881733120, 94133881868287,
-STORE, 140583639638016, 140583648030719,
-SNULL, 140583639642111, 140583648030719,
-STORE, 140583639638016, 140583639642111,
-STORE, 140583639642112, 140583648030719,
-STORE, 140583631245312, 140583639638015,
-STORE, 140583497027584, 140583631245311,
-SNULL, 140583497027584, 140583540621311,
-STORE, 140583540621312, 140583631245311,
-STORE, 140583497027584, 140583540621311,
-ERASE, 140583497027584, 140583540621311,
-SNULL, 140583607730175, 140583631245311,
-STORE, 140583540621312, 140583607730175,
-STORE, 140583607730176, 140583631245311,
-ERASE, 140583607730176, 140583631245311,
-SNULL, 140583540756479, 140583607730175,
-STORE, 140583540621312, 140583540756479,
-STORE, 140583540756480, 140583607730175,
-SNULL, 140583631249407, 140583639638015,
-STORE, 140583631245312, 140583631249407,
-STORE, 140583631249408, 140583639638015,
-STORE, 140583622852608, 140583631245311,
-SNULL, 140583622856703, 140583631245311,
-STORE, 140583622852608, 140583622856703,
-STORE, 140583622856704, 140583631245311,
-STORE, 140583614459904, 140583622852607,
-SNULL, 140583614463999, 140583622852607,
-STORE, 140583614459904, 140583614463999,
-STORE, 140583614464000, 140583622852607,
-STORE, 140583532228608, 140583540621311,
-SNULL, 140583532232703, 140583540621311,
-STORE, 140583532228608, 140583532232703,
-STORE, 140583532232704, 140583540621311,
-STORE, 140583523835904, 140583532228607,
-STORE, 140583515443200, 140583532228607,
-STORE, 140583507050496, 140583532228607,
-STORE, 140583372832768, 140583507050495,
-STORE, 140583364440064, 140583372832767,
-STORE, 140583230222336, 140583364440063,
-STORE, 140583096004608, 140583364440063,
-SNULL, 140583230222335, 140583364440063,
-STORE, 140583096004608, 140583230222335,
-STORE, 140583230222336, 140583364440063,
-SNULL, 140583230222336, 140583272185855,
-STORE, 140583272185856, 140583364440063,
-STORE, 140583230222336, 140583272185855,
-ERASE, 140583230222336, 140583272185855,
-STORE, 140582961786880, 140583230222335,
-SNULL, 140583372832768, 140583406403583,
-STORE, 140583406403584, 140583507050495,
-STORE, 140583372832768, 140583406403583,
-ERASE, 140583372832768, 140583406403583,
-SNULL, 140583473512447, 140583507050495,
-STORE, 140583406403584, 140583473512447,
-STORE, 140583473512448, 140583507050495,
-ERASE, 140583473512448, 140583507050495,
-SNULL, 140583096004607, 140583230222335,
-STORE, 140582961786880, 140583096004607,
-STORE, 140583096004608, 140583230222335,
-SNULL, 140583096004608, 140583137968127,
-STORE, 140583137968128, 140583230222335,
-STORE, 140583096004608, 140583137968127,
-ERASE, 140583096004608, 140583137968127,
-SNULL, 140583339294719, 140583364440063,
-STORE, 140583272185856, 140583339294719,
-STORE, 140583339294720, 140583364440063,
-ERASE, 140583339294720, 140583364440063,
-SNULL, 140583272321023, 140583339294719,
-STORE, 140583272185856, 140583272321023,
-STORE, 140583272321024, 140583339294719,
-SNULL, 140582961786880, 140583003750399,
-STORE, 140583003750400, 140583096004607,
-STORE, 140582961786880, 140583003750399,
-ERASE, 140582961786880, 140583003750399,
- };
-
- unsigned long set34[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140731327180800, 140737488351231,
-SNULL, 140731327184895, 140737488351231,
-STORE, 140731327180800, 140731327184895,
-STORE, 140731327049728, 140731327184895,
-STORE, 94632924487680, 94632926740479,
-SNULL, 94632924618751, 94632926740479,
-STORE, 94632924487680, 94632924618751,
-STORE, 94632924618752, 94632926740479,
-ERASE, 94632924618752, 94632926740479,
-STORE, 94632926711808, 94632926719999,
-STORE, 94632926720000, 94632926740479,
-STORE, 140012544888832, 140012547141631,
-SNULL, 140012545032191, 140012547141631,
-STORE, 140012544888832, 140012545032191,
-STORE, 140012545032192, 140012547141631,
-ERASE, 140012545032192, 140012547141631,
-STORE, 140012547129344, 140012547137535,
-STORE, 140012547137536, 140012547141631,
-STORE, 140731327725568, 140731327729663,
-STORE, 140731327713280, 140731327725567,
-STORE, 140012547100672, 140012547129343,
-STORE, 140012547092480, 140012547100671,
-STORE, 140012542672896, 140012544888831,
-SNULL, 140012542672896, 140012542771199,
-STORE, 140012542771200, 140012544888831,
-STORE, 140012542672896, 140012542771199,
-SNULL, 140012544864255, 140012544888831,
-STORE, 140012542771200, 140012544864255,
-STORE, 140012544864256, 140012544888831,
-SNULL, 140012544864256, 140012544872447,
-STORE, 140012544872448, 140012544888831,
-STORE, 140012544864256, 140012544872447,
-ERASE, 140012544864256, 140012544872447,
-STORE, 140012544864256, 140012544872447,
-ERASE, 140012544872448, 140012544888831,
-STORE, 140012544872448, 140012544888831,
-STORE, 140012538875904, 140012542672895,
-SNULL, 140012538875904, 140012540534783,
-STORE, 140012540534784, 140012542672895,
-STORE, 140012538875904, 140012540534783,
-SNULL, 140012542631935, 140012542672895,
-STORE, 140012540534784, 140012542631935,
-STORE, 140012542631936, 140012542672895,
-SNULL, 140012542631936, 140012542656511,
-STORE, 140012542656512, 140012542672895,
-STORE, 140012542631936, 140012542656511,
-ERASE, 140012542631936, 140012542656511,
-STORE, 140012542631936, 140012542656511,
-ERASE, 140012542656512, 140012542672895,
-STORE, 140012542656512, 140012542672895,
-STORE, 140012547084288, 140012547100671,
-SNULL, 140012542648319, 140012542656511,
-STORE, 140012542631936, 140012542648319,
-STORE, 140012542648320, 140012542656511,
-SNULL, 140012544868351, 140012544872447,
-STORE, 140012544864256, 140012544868351,
-STORE, 140012544868352, 140012544872447,
-SNULL, 94632926715903, 94632926719999,
-STORE, 94632926711808, 94632926715903,
-STORE, 94632926715904, 94632926719999,
-SNULL, 140012547133439, 140012547137535,
-STORE, 140012547129344, 140012547133439,
-STORE, 140012547133440, 140012547137535,
-ERASE, 140012547100672, 140012547129343,
-STORE, 94632939606016, 94632939741183,
-STORE, 140012530483200, 140012538875903,
-SNULL, 140012530487295, 140012538875903,
-STORE, 140012530483200, 140012530487295,
-STORE, 140012530487296, 140012538875903,
-STORE, 140012522090496, 140012530483199,
-STORE, 140012387872768, 140012522090495,
-SNULL, 140012387872768, 140012444188671,
-STORE, 140012444188672, 140012522090495,
-STORE, 140012387872768, 140012444188671,
-ERASE, 140012387872768, 140012444188671,
-SNULL, 140012511297535, 140012522090495,
-STORE, 140012444188672, 140012511297535,
-STORE, 140012511297536, 140012522090495,
-ERASE, 140012511297536, 140012522090495,
-SNULL, 140012444323839, 140012511297535,
-STORE, 140012444188672, 140012444323839,
-STORE, 140012444323840, 140012511297535,
-SNULL, 140012522094591, 140012530483199,
-STORE, 140012522090496, 140012522094591,
-STORE, 140012522094592, 140012530483199,
-STORE, 140012513697792, 140012522090495,
-SNULL, 140012513701887, 140012522090495,
-STORE, 140012513697792, 140012513701887,
-STORE, 140012513701888, 140012522090495,
-STORE, 140012435795968, 140012444188671,
-SNULL, 140012435800063, 140012444188671,
-STORE, 140012435795968, 140012435800063,
-STORE, 140012435800064, 140012444188671,
-STORE, 140012427403264, 140012435795967,
-SNULL, 140012427407359, 140012435795967,
-STORE, 140012427403264, 140012427407359,
-STORE, 140012427407360, 140012435795967,
-STORE, 140012419010560, 140012427403263,
-STORE, 140012410617856, 140012427403263,
-STORE, 140012276400128, 140012410617855,
-STORE, 140012268007424, 140012276400127,
-STORE, 140012133789696, 140012268007423,
-SNULL, 140012133789696, 140012175753215,
-STORE, 140012175753216, 140012268007423,
-STORE, 140012133789696, 140012175753215,
-ERASE, 140012133789696, 140012175753215,
-STORE, 140012041535488, 140012268007423,
-SNULL, 140012108644351, 140012268007423,
-STORE, 140012041535488, 140012108644351,
-STORE, 140012108644352, 140012268007423,
-SNULL, 140012108644352, 140012175753215,
-STORE, 140012175753216, 140012268007423,
-STORE, 140012108644352, 140012175753215,
-ERASE, 140012108644352, 140012175753215,
-SNULL, 140012276400128, 140012309970943,
-STORE, 140012309970944, 140012410617855,
-STORE, 140012276400128, 140012309970943,
-ERASE, 140012276400128, 140012309970943,
-STORE, 140012301578240, 140012309970943,
-STORE, 140012041535488, 140012268007423,
-SNULL, 140012242862079, 140012268007423,
-STORE, 140012041535488, 140012242862079,
-STORE, 140012242862080, 140012268007423,
-ERASE, 140012242862080, 140012268007423,
-SNULL, 140012041670655, 140012242862079,
-STORE, 140012041535488, 140012041670655,
-STORE, 140012041670656, 140012242862079,
-SNULL, 140012041670656, 140012108644351,
-STORE, 140012108644352, 140012242862079,
-STORE, 140012041670656, 140012108644351,
-SNULL, 140012108779519, 140012242862079,
-STORE, 140012108644352, 140012108779519,
-STORE, 140012108779520, 140012242862079,
-SNULL, 140012377079807, 140012410617855,
-STORE, 140012309970944, 140012377079807,
-STORE, 140012377079808, 140012410617855,
-ERASE, 140012377079808, 140012410617855,
-SNULL, 140012310106111, 140012377079807,
-STORE, 140012309970944, 140012310106111,
-STORE, 140012310106112, 140012377079807,
-SNULL, 140012410621951, 140012427403263,
-STORE, 140012410617856, 140012410621951,
-STORE, 140012410621952, 140012427403263,
-SNULL, 140012108779520, 140012175753215,
-STORE, 140012175753216, 140012242862079,
-STORE, 140012108779520, 140012175753215,
-SNULL, 140012175888383, 140012242862079,
-STORE, 140012175753216, 140012175888383,
-STORE, 140012175888384, 140012242862079,
-SNULL, 140012301582335, 140012309970943,
-STORE, 140012301578240, 140012301582335,
-STORE, 140012301582336, 140012309970943,
-SNULL, 140012410621952, 140012419010559,
-STORE, 140012419010560, 140012427403263,
-STORE, 140012410621952, 140012419010559,
-SNULL, 140012419014655, 140012427403263,
-STORE, 140012419010560, 140012419014655,
-STORE, 140012419014656, 140012427403263,
-SNULL, 140012268011519, 140012276400127,
-STORE, 140012268007424, 140012268011519,
-STORE, 140012268011520, 140012276400127,
-STORE, 140012402225152, 140012410617855,
-STORE, 140012393832448, 140012410617855,
-SNULL, 140012393832448, 140012402225151,
-STORE, 140012402225152, 140012410617855,
-STORE, 140012393832448, 140012402225151,
-SNULL, 140012402229247, 140012410617855,
-STORE, 140012402225152, 140012402229247,
-STORE, 140012402229248, 140012410617855,
-STORE, 140012385439744, 140012402225151,
-SNULL, 140012385439744, 140012393832447,
-STORE, 140012393832448, 140012402225151,
-STORE, 140012385439744, 140012393832447,
-SNULL, 140012393836543, 140012402225151,
-STORE, 140012393832448, 140012393836543,
-STORE, 140012393836544, 140012402225151,
-STORE, 140012293185536, 140012301578239,
-STORE, 140012284792832, 140012301578239,
-SNULL, 140012284792832, 140012293185535,
-STORE, 140012293185536, 140012301578239,
-STORE, 140012284792832, 140012293185535,
-SNULL, 140012293189631, 140012301578239,
-STORE, 140012293185536, 140012293189631,
-STORE, 140012293189632, 140012301578239,
-STORE, 140012268011520, 140012284792831,
-SNULL, 140012385443839, 140012393832447,
-STORE, 140012385439744, 140012385443839,
-STORE, 140012385443840, 140012393832447,
-STORE, 140012259614720, 140012268007423,
-SNULL, 140012259618815, 140012268007423,
-STORE, 140012259614720, 140012259618815,
-STORE, 140012259618816, 140012268007423,
-STORE, 140012251222016, 140012259614719,
-SNULL, 140012251226111, 140012259614719,
-STORE, 140012251222016, 140012251226111,
-STORE, 140012251226112, 140012259614719,
-SNULL, 140012284796927, 140012293185535,
-STORE, 140012284792832, 140012284796927,
-STORE, 140012284796928, 140012293185535,
-SNULL, 140012268011520, 140012276400127,
-STORE, 140012276400128, 140012284792831,
-STORE, 140012268011520, 140012276400127,
-SNULL, 140012276404223, 140012284792831,
-STORE, 140012276400128, 140012276404223,
-STORE, 140012276404224, 140012284792831,
-STORE, 140012033142784, 140012041535487,
-SNULL, 140012033146879, 140012041535487,
-STORE, 140012033142784, 140012033146879,
-STORE, 140012033146880, 140012041535487,
-STORE, 140012024750080, 140012033142783,
-STORE, 140012016357376, 140012033142783,
-SNULL, 140012016357376, 140012024750079,
-STORE, 140012024750080, 140012033142783,
-STORE, 140012016357376, 140012024750079,
-SNULL, 140012024754175, 140012033142783,
-STORE, 140012024750080, 140012024754175,
-STORE, 140012024754176, 140012033142783,
-SNULL, 140012016361471, 140012024750079,
-STORE, 140012016357376, 140012016361471,
-STORE, 140012016361472, 140012024750079,
-STORE, 140012007964672, 140012016357375,
-SNULL, 140012007968767, 140012016357375,
-STORE, 140012007964672, 140012007968767,
-STORE, 140012007968768, 140012016357375,
-STORE, 140011999571968, 140012007964671,
-STORE, 140011991179264, 140012007964671,
-STORE, 140011856961536, 140011991179263,
-STORE, 140011848568832, 140011856961535,
-STORE, 140011714351104, 140011848568831,
-SNULL, 140011714351104, 140011773100031,
-STORE, 140011773100032, 140011848568831,
-STORE, 140011714351104, 140011773100031,
-ERASE, 140011714351104, 140011773100031,
-STORE, 140011764707328, 140011773100031,
-STORE, 140011756314624, 140011773100031,
-STORE, 140011622096896, 140011756314623,
-STORE, 140011613704192, 140011622096895,
-STORE, 140011479486464, 140011613704191,
-STORE, 140011471093760, 140011479486463,
-SNULL, 140011479486464, 140011504664575,
-STORE, 140011504664576, 140011613704191,
-STORE, 140011479486464, 140011504664575,
-ERASE, 140011479486464, 140011504664575,
-STORE, 140011496271872, 140011504664575,
-STORE, 140011487879168, 140011504664575,
-STORE, 140011336876032, 140011471093759,
-SNULL, 140011336876032, 140011370446847,
-STORE, 140011370446848, 140011471093759,
-STORE, 140011336876032, 140011370446847,
-ERASE, 140011336876032, 140011370446847,
-STORE, 140011471093760, 140011487879167,
-STORE, 140011362054144, 140011370446847,
-SNULL, 140011362058239, 140011370446847,
-STORE, 140011362054144, 140011362058239,
-STORE, 140011362058240, 140011370446847,
-STORE, 140011353661440, 140011362054143,
-STORE, 140011345268736, 140011362054143,
-SNULL, 140011345272831, 140011362054143,
-STORE, 140011345268736, 140011345272831,
-STORE, 140011345272832, 140011362054143,
-STORE, 140011336876032, 140011345268735,
-STORE, 140011328483328, 140011345268735,
-SNULL, 140011328487423, 140011345268735,
-STORE, 140011328483328, 140011328487423,
-STORE, 140011328487424, 140011345268735,
-STORE, 140011320090624, 140011328483327,
-STORE, 140011185872896, 140011320090623,
-SNULL, 140011185872896, 140011236229119,
-STORE, 140011236229120, 140011320090623,
-STORE, 140011185872896, 140011236229119,
-ERASE, 140011185872896, 140011236229119,
-SNULL, 140011856961536, 140011907317759,
-STORE, 140011907317760, 140011991179263,
-STORE, 140011856961536, 140011907317759,
-ERASE, 140011856961536, 140011907317759,
-SNULL, 140011974426623, 140011991179263,
-STORE, 140011907317760, 140011974426623,
-STORE, 140011974426624, 140011991179263,
-ERASE, 140011974426624, 140011991179263,
-SNULL, 140011840208895, 140011848568831,
-STORE, 140011773100032, 140011840208895,
-STORE, 140011840208896, 140011848568831,
-ERASE, 140011840208896, 140011848568831,
-SNULL, 140011773235199, 140011840208895,
-STORE, 140011773100032, 140011773235199,
-STORE, 140011773235200, 140011840208895,
-STORE, 140011102011392, 140011320090623,
-SNULL, 140011169120255, 140011320090623,
-STORE, 140011102011392, 140011169120255,
-STORE, 140011169120256, 140011320090623,
-SNULL, 140011169120256, 140011236229119,
-STORE, 140011236229120, 140011320090623,
-STORE, 140011169120256, 140011236229119,
-ERASE, 140011169120256, 140011236229119,
-SNULL, 140011622096896, 140011638882303,
-STORE, 140011638882304, 140011756314623,
-STORE, 140011622096896, 140011638882303,
-ERASE, 140011622096896, 140011638882303,
-SNULL, 140011705991167, 140011756314623,
-STORE, 140011638882304, 140011705991167,
-STORE, 140011705991168, 140011756314623,
-ERASE, 140011705991168, 140011756314623,
-SNULL, 140011571773439, 140011613704191,
-STORE, 140011504664576, 140011571773439,
-STORE, 140011571773440, 140011613704191,
-ERASE, 140011571773440, 140011613704191,
-STORE, 140010967793664, 140011169120255,
-SNULL, 140011034902527, 140011169120255,
-STORE, 140010967793664, 140011034902527,
-STORE, 140011034902528, 140011169120255,
-SNULL, 140011034902528, 140011102011391,
-STORE, 140011102011392, 140011169120255,
-STORE, 140011034902528, 140011102011391,
-ERASE, 140011034902528, 140011102011391,
-STORE, 140010833575936, 140011034902527,
-SNULL, 140011437555711, 140011471093759,
-STORE, 140011370446848, 140011437555711,
-STORE, 140011437555712, 140011471093759,
-ERASE, 140011437555712, 140011471093759,
-SNULL, 140011370582015, 140011437555711,
-STORE, 140011370446848, 140011370582015,
-STORE, 140011370582016, 140011437555711,
-STORE, 140010699358208, 140011034902527,
-SNULL, 140011487883263, 140011504664575,
-STORE, 140011487879168, 140011487883263,
-STORE, 140011487883264, 140011504664575,
-SNULL, 140011345272832, 140011353661439,
-STORE, 140011353661440, 140011362054143,
-STORE, 140011345272832, 140011353661439,
-SNULL, 140011353665535, 140011362054143,
-STORE, 140011353661440, 140011353665535,
-STORE, 140011353665536, 140011362054143,
-SNULL, 140011328487424, 140011336876031,
-STORE, 140011336876032, 140011345268735,
-STORE, 140011328487424, 140011336876031,
-SNULL, 140011336880127, 140011345268735,
-STORE, 140011336876032, 140011336880127,
-STORE, 140011336880128, 140011345268735,
-SNULL, 140011303337983, 140011320090623,
-STORE, 140011236229120, 140011303337983,
-STORE, 140011303337984, 140011320090623,
-ERASE, 140011303337984, 140011320090623,
-SNULL, 140011907452927, 140011974426623,
-STORE, 140011907317760, 140011907452927,
-STORE, 140011907452928, 140011974426623,
-SNULL, 140011102146559, 140011169120255,
-STORE, 140011102011392, 140011102146559,
-STORE, 140011102146560, 140011169120255,
-SNULL, 140011639017471, 140011705991167,
-STORE, 140011638882304, 140011639017471,
-STORE, 140011639017472, 140011705991167,
-SNULL, 140011504799743, 140011571773439,
-STORE, 140011504664576, 140011504799743,
-STORE, 140011504799744, 140011571773439,
-SNULL, 140011613708287, 140011622096895,
-STORE, 140011613704192, 140011613708287,
-STORE, 140011613708288, 140011622096895,
-SNULL, 140010699358208, 140010967793663,
-STORE, 140010967793664, 140011034902527,
-STORE, 140010699358208, 140010967793663,
-SNULL, 140010967928831, 140011034902527,
-STORE, 140010967793664, 140010967928831,
-STORE, 140010967928832, 140011034902527,
-SNULL, 140010900684799, 140010967793663,
-STORE, 140010699358208, 140010900684799,
-STORE, 140010900684800, 140010967793663,
-ERASE, 140010900684800, 140010967793663,
-SNULL, 140010766467071, 140010900684799,
-STORE, 140010699358208, 140010766467071,
-STORE, 140010766467072, 140010900684799,
-SNULL, 140010766467072, 140010833575935,
-STORE, 140010833575936, 140010900684799,
-STORE, 140010766467072, 140010833575935,
-ERASE, 140010766467072, 140010833575935,
-SNULL, 140010699493375, 140010766467071,
-STORE, 140010699358208, 140010699493375,
-STORE, 140010699493376, 140010766467071,
-SNULL, 140011848572927, 140011856961535,
-STORE, 140011848568832, 140011848572927,
-STORE, 140011848572928, 140011856961535,
-STORE, 140011982786560, 140012007964671,
-STORE, 140011898925056, 140011907317759,
-SNULL, 140011898929151, 140011907317759,
-STORE, 140011898925056, 140011898929151,
-STORE, 140011898929152, 140011907317759,
-SNULL, 140011320094719, 140011328483327,
-STORE, 140011320090624, 140011320094719,
-STORE, 140011320094720, 140011328483327,
-STORE, 140011890532352, 140011898925055,
-STORE, 140011882139648, 140011898925055,
-SNULL, 140011882143743, 140011898925055,
-STORE, 140011882139648, 140011882143743,
-STORE, 140011882143744, 140011898925055,
-STORE, 140011873746944, 140011882139647,
-SNULL, 140011873751039, 140011882139647,
-STORE, 140011873746944, 140011873751039,
-STORE, 140011873751040, 140011882139647,
-SNULL, 140011236364287, 140011303337983,
-STORE, 140011236229120, 140011236364287,
-STORE, 140011236364288, 140011303337983,
-SNULL, 140011756318719, 140011773100031,
-STORE, 140011756314624, 140011756318719,
-STORE, 140011756318720, 140011773100031,
-SNULL, 140011756318720, 140011764707327,
-STORE, 140011764707328, 140011773100031,
-STORE, 140011756318720, 140011764707327,
-SNULL, 140011764711423, 140011773100031,
-STORE, 140011764707328, 140011764711423,
-STORE, 140011764711424, 140011773100031,
-SNULL, 140011471097855, 140011487879167,
-STORE, 140011471093760, 140011471097855,
-STORE, 140011471097856, 140011487879167,
-SNULL, 140010833711103, 140010900684799,
-STORE, 140010833575936, 140010833711103,
-STORE, 140010833711104, 140010900684799,
-SNULL, 140011982790655, 140012007964671,
-STORE, 140011982786560, 140011982790655,
-STORE, 140011982790656, 140012007964671,
-STORE, 140011865354240, 140011873746943,
-STORE, 140011848572928, 140011865354239,
-SNULL, 140011848572928, 140011856961535,
-STORE, 140011856961536, 140011865354239,
-STORE, 140011848572928, 140011856961535,
-SNULL, 140011856965631, 140011865354239,
-STORE, 140011856961536, 140011856965631,
-STORE, 140011856965632, 140011865354239,
-STORE, 140011747921920, 140011756314623,
-STORE, 140011739529216, 140011756314623,
-SNULL, 140011471097856, 140011479486463,
-STORE, 140011479486464, 140011487879167,
-STORE, 140011471097856, 140011479486463,
-SNULL, 140011479490559, 140011487879167,
-STORE, 140011479486464, 140011479490559,
-STORE, 140011479490560, 140011487879167,
-STORE, 140011731136512, 140011756314623,
-STORE, 140011722743808, 140011756314623,
-SNULL, 140011982790656, 140011999571967,
-STORE, 140011999571968, 140012007964671,
-STORE, 140011982790656, 140011999571967,
-SNULL, 140011999576063, 140012007964671,
-STORE, 140011999571968, 140011999576063,
-STORE, 140011999576064, 140012007964671,
-STORE, 140011714351104, 140011756314623,
-SNULL, 140011882143744, 140011890532351,
-STORE, 140011890532352, 140011898925055,
-STORE, 140011882143744, 140011890532351,
-SNULL, 140011890536447, 140011898925055,
-STORE, 140011890532352, 140011890536447,
-STORE, 140011890536448, 140011898925055,
-STORE, 140011630489600, 140011638882303,
-STORE, 140011613708288, 140011638882303,
-STORE, 140011605311488, 140011613704191,
-STORE, 140011596918784, 140011613704191,
-STORE, 140011588526080, 140011613704191,
-SNULL, 140011487883264, 140011496271871,
-STORE, 140011496271872, 140011504664575,
-STORE, 140011487883264, 140011496271871,
-SNULL, 140011496275967, 140011504664575,
-STORE, 140011496271872, 140011496275967,
-STORE, 140011496275968, 140011504664575,
-STORE, 140011580133376, 140011613704191,
-SNULL, 140011580137471, 140011613704191,
-STORE, 140011580133376, 140011580137471,
-STORE, 140011580137472, 140011613704191,
-SNULL, 140011982790656, 140011991179263,
-STORE, 140011991179264, 140011999571967,
-STORE, 140011982790656, 140011991179263,
-SNULL, 140011991183359, 140011999571967,
-STORE, 140011991179264, 140011991183359,
-STORE, 140011991183360, 140011999571967,
-SNULL, 140011865358335, 140011873746943,
-STORE, 140011865354240, 140011865358335,
-STORE, 140011865358336, 140011873746943,
-STORE, 140011462701056, 140011471093759,
-SNULL, 140011714351104, 140011739529215,
-STORE, 140011739529216, 140011756314623,
-STORE, 140011714351104, 140011739529215,
-SNULL, 140011739533311, 140011756314623,
-STORE, 140011739529216, 140011739533311,
-STORE, 140011739533312, 140011756314623,
-SNULL, 140011739533312, 140011747921919,
-STORE, 140011747921920, 140011756314623,
-STORE, 140011739533312, 140011747921919,
-SNULL, 140011747926015, 140011756314623,
-STORE, 140011747921920, 140011747926015,
-STORE, 140011747926016, 140011756314623,
-SNULL, 140011613708288, 140011630489599,
-STORE, 140011630489600, 140011638882303,
-STORE, 140011613708288, 140011630489599,
-SNULL, 140011630493695, 140011638882303,
-STORE, 140011630489600, 140011630493695,
-STORE, 140011630493696, 140011638882303,
-SNULL, 140011714351104, 140011722743807,
-STORE, 140011722743808, 140011739529215,
-STORE, 140011714351104, 140011722743807,
-SNULL, 140011722747903, 140011739529215,
-STORE, 140011722743808, 140011722747903,
-STORE, 140011722747904, 140011739529215,
-SNULL, 140011714355199, 140011722743807,
-STORE, 140011714351104, 140011714355199,
-STORE, 140011714355200, 140011722743807,
-SNULL, 140011722747904, 140011731136511,
-STORE, 140011731136512, 140011739529215,
-STORE, 140011722747904, 140011731136511,
-SNULL, 140011731140607, 140011739529215,
-STORE, 140011731136512, 140011731140607,
-STORE, 140011731140608, 140011739529215,
-STORE, 140011454308352, 140011471093759,
-STORE, 140011445915648, 140011471093759,
-SNULL, 140011580137472, 140011588526079,
-STORE, 140011588526080, 140011613704191,
-STORE, 140011580137472, 140011588526079,
-SNULL, 140011588530175, 140011613704191,
-STORE, 140011588526080, 140011588530175,
-STORE, 140011588530176, 140011613704191,
-SNULL, 140011445915648, 140011462701055,
-STORE, 140011462701056, 140011471093759,
-STORE, 140011445915648, 140011462701055,
-SNULL, 140011462705151, 140011471093759,
-STORE, 140011462701056, 140011462705151,
-STORE, 140011462705152, 140011471093759,
-SNULL, 140011588530176, 140011596918783,
-STORE, 140011596918784, 140011613704191,
-STORE, 140011588530176, 140011596918783,
-SNULL, 140011596922879, 140011613704191,
-STORE, 140011596918784, 140011596922879,
-STORE, 140011596922880, 140011613704191,
-SNULL, 140011596922880, 140011605311487,
-STORE, 140011605311488, 140011613704191,
-STORE, 140011596922880, 140011605311487,
-SNULL, 140011605315583, 140011613704191,
-STORE, 140011605311488, 140011605315583,
-STORE, 140011605315584, 140011613704191,
-SNULL, 140011613708288, 140011622096895,
-STORE, 140011622096896, 140011630489599,
-STORE, 140011613708288, 140011622096895,
-SNULL, 140011622100991, 140011630489599,
-STORE, 140011622096896, 140011622100991,
-STORE, 140011622100992, 140011630489599,
-STORE, 140011311697920, 140011320090623,
-STORE, 140011227836416, 140011236229119,
-STORE, 140011219443712, 140011236229119,
-SNULL, 140011219447807, 140011236229119,
-STORE, 140011219443712, 140011219447807,
-STORE, 140011219447808, 140011236229119,
-STORE, 140011211051008, 140011219443711,
-STORE, 140011202658304, 140011219443711,
-SNULL, 140011202662399, 140011219443711,
-STORE, 140011202658304, 140011202662399,
-STORE, 140011202662400, 140011219443711,
-STORE, 140011194265600, 140011202658303,
-STORE, 140011185872896, 140011202658303,
-STORE, 140011177480192, 140011202658303,
-STORE, 140011093618688, 140011102011391,
-SNULL, 140011445915648, 140011454308351,
-STORE, 140011454308352, 140011462701055,
-STORE, 140011445915648, 140011454308351,
-SNULL, 140011454312447, 140011462701055,
-STORE, 140011454308352, 140011454312447,
-STORE, 140011454312448, 140011462701055,
-STORE, 140011085225984, 140011102011391,
-SNULL, 140011085230079, 140011102011391,
-STORE, 140011085225984, 140011085230079,
-STORE, 140011085230080, 140011102011391,
-SNULL, 140011177484287, 140011202658303,
-STORE, 140011177480192, 140011177484287,
-STORE, 140011177484288, 140011202658303,
-SNULL, 140011445919743, 140011454308351,
-STORE, 140011445915648, 140011445919743,
-STORE, 140011445919744, 140011454308351,
-SNULL, 140011177484288, 140011185872895,
-STORE, 140011185872896, 140011202658303,
-STORE, 140011177484288, 140011185872895,
-SNULL, 140011185876991, 140011202658303,
-STORE, 140011185872896, 140011185876991,
-STORE, 140011185876992, 140011202658303,
-STORE, 140011076833280, 140011085225983,
-SNULL, 140011202662400, 140011211051007,
-STORE, 140011211051008, 140011219443711,
-STORE, 140011202662400, 140011211051007,
-SNULL, 140011211055103, 140011219443711,
-STORE, 140011211051008, 140011211055103,
-STORE, 140011211055104, 140011219443711,
-SNULL, 140011185876992, 140011194265599,
-STORE, 140011194265600, 140011202658303,
-STORE, 140011185876992, 140011194265599,
-SNULL, 140011194269695, 140011202658303,
-STORE, 140011194265600, 140011194269695,
-STORE, 140011194269696, 140011202658303,
-STORE, 140011068440576, 140011085225983,
-SNULL, 140011311702015, 140011320090623,
-STORE, 140011311697920, 140011311702015,
-STORE, 140011311702016, 140011320090623,
-STORE, 140011060047872, 140011085225983,
-SNULL, 140011060051967, 140011085225983,
-STORE, 140011060047872, 140011060051967,
-STORE, 140011060051968, 140011085225983,
-STORE, 140011051655168, 140011060047871,
-STORE, 140011043262464, 140011060047871,
-SNULL, 140011043266559, 140011060047871,
-STORE, 140011043262464, 140011043266559,
-STORE, 140011043266560, 140011060047871,
-SNULL, 140011219447808, 140011227836415,
-STORE, 140011227836416, 140011236229119,
-STORE, 140011219447808, 140011227836415,
-SNULL, 140011227840511, 140011236229119,
-STORE, 140011227836416, 140011227840511,
-STORE, 140011227840512, 140011236229119,
-SNULL, 140011085230080, 140011093618687,
-STORE, 140011093618688, 140011102011391,
-STORE, 140011085230080, 140011093618687,
-SNULL, 140011093622783, 140011102011391,
-STORE, 140011093618688, 140011093622783,
-STORE, 140011093622784, 140011102011391,
-STORE, 140010959400960, 140010967793663,
-STORE, 140010951008256, 140010967793663,
-SNULL, 140010951008256, 140010959400959,
-STORE, 140010959400960, 140010967793663,
-STORE, 140010951008256, 140010959400959,
-SNULL, 140010959405055, 140010967793663,
-STORE, 140010959400960, 140010959405055,
-STORE, 140010959405056, 140010967793663,
-STORE, 140010942615552, 140010959400959,
-STORE, 140010934222848, 140010959400959,
-SNULL, 140011060051968, 140011076833279,
-STORE, 140011076833280, 140011085225983,
-STORE, 140011060051968, 140011076833279,
-SNULL, 140011076837375, 140011085225983,
-STORE, 140011076833280, 140011076837375,
-STORE, 140011076837376, 140011085225983,
-SNULL, 140011043266560, 140011051655167,
-STORE, 140011051655168, 140011060047871,
-STORE, 140011043266560, 140011051655167,
-SNULL, 140011051659263, 140011060047871,
-STORE, 140011051655168, 140011051659263,
-STORE, 140011051659264, 140011060047871,
-STORE, 140010925830144, 140010959400959,
-SNULL, 140011060051968, 140011068440575,
-STORE, 140011068440576, 140011076833279,
-STORE, 140011060051968, 140011068440575,
-SNULL, 140011068444671, 140011076833279,
-STORE, 140011068440576, 140011068444671,
-STORE, 140011068444672, 140011076833279,
-STORE, 140010917437440, 140010959400959,
-STORE, 140010909044736, 140010959400959,
-STORE, 140010825183232, 140010833575935,
-SNULL, 140010909044736, 140010942615551,
-STORE, 140010942615552, 140010959400959,
-STORE, 140010909044736, 140010942615551,
-SNULL, 140010942619647, 140010959400959,
-STORE, 140010942615552, 140010942619647,
-STORE, 140010942619648, 140010959400959,
-SNULL, 140010909044736, 140010934222847,
-STORE, 140010934222848, 140010942615551,
-STORE, 140010909044736, 140010934222847,
-SNULL, 140010934226943, 140010942615551,
-STORE, 140010934222848, 140010934226943,
-STORE, 140010934226944, 140010942615551,
-SNULL, 140010909048831, 140010934222847,
-STORE, 140010909044736, 140010909048831,
-STORE, 140010909048832, 140010934222847,
-STORE, 140010816790528, 140010833575935,
-SNULL, 140010816794623, 140010833575935,
-STORE, 140010816790528, 140010816794623,
-STORE, 140010816794624, 140010833575935,
-STORE, 140010808397824, 140010816790527,
-SNULL, 140010942619648, 140010951008255,
-STORE, 140010951008256, 140010959400959,
-STORE, 140010942619648, 140010951008255,
-SNULL, 140010951012351, 140010959400959,
-STORE, 140010951008256, 140010951012351,
-STORE, 140010951012352, 140010959400959,
-STORE, 140010800005120, 140010816790527,
-SNULL, 140010800009215, 140010816790527,
-STORE, 140010800005120, 140010800009215,
-STORE, 140010800009216, 140010816790527,
-SNULL, 140010909048832, 140010925830143,
-STORE, 140010925830144, 140010934222847,
-STORE, 140010909048832, 140010925830143,
-SNULL, 140010925834239, 140010934222847,
-STORE, 140010925830144, 140010925834239,
-STORE, 140010925834240, 140010934222847,
-SNULL, 140010816794624, 140010825183231,
-STORE, 140010825183232, 140010833575935,
-STORE, 140010816794624, 140010825183231,
-SNULL, 140010825187327, 140010833575935,
-STORE, 140010825183232, 140010825187327,
-STORE, 140010825187328, 140010833575935,
-SNULL, 140010909048832, 140010917437439,
-STORE, 140010917437440, 140010925830143,
-STORE, 140010909048832, 140010917437439,
-SNULL, 140010917441535, 140010925830143,
-STORE, 140010917437440, 140010917441535,
-STORE, 140010917441536, 140010925830143,
-SNULL, 140010800009216, 140010808397823,
-STORE, 140010808397824, 140010816790527,
-STORE, 140010800009216, 140010808397823,
-SNULL, 140010808401919, 140010816790527,
-STORE, 140010808397824, 140010808401919,
-STORE, 140010808401920, 140010816790527,
-STORE, 140010791612416, 140010800005119,
-SNULL, 140010791616511, 140010800005119,
-STORE, 140010791612416, 140010791616511,
-STORE, 140010791616512, 140010800005119,
-STORE, 140012547100672, 140012547129343,
-STORE, 140012511506432, 140012513697791,
-SNULL, 140012511506432, 140012511596543,
-STORE, 140012511596544, 140012513697791,
-STORE, 140012511506432, 140012511596543,
-SNULL, 140012513689599, 140012513697791,
-STORE, 140012511596544, 140012513689599,
-STORE, 140012513689600, 140012513697791,
-ERASE, 140012513689600, 140012513697791,
-STORE, 140012513689600, 140012513697791,
-SNULL, 140012513693695, 140012513697791,
-STORE, 140012513689600, 140012513693695,
-STORE, 140012513693696, 140012513697791,
-ERASE, 140012547100672, 140012547129343,
-ERASE, 140011362054144, 140011362058239,
-ERASE, 140011362058240, 140011370446847,
-ERASE, 140011882139648, 140011882143743,
-ERASE, 140011882143744, 140011890532351,
-ERASE, 140011873746944, 140011873751039,
-ERASE, 140011873751040, 140011882139647,
-ERASE, 140011588526080, 140011588530175,
-ERASE, 140011588530176, 140011596918783,
-ERASE, 140011328483328, 140011328487423,
-ERASE, 140011328487424, 140011336876031,
-ERASE, 140011898925056, 140011898929151,
-ERASE, 140011898929152, 140011907317759,
-ERASE, 140011353661440, 140011353665535,
-ERASE, 140011353665536, 140011362054143,
-ERASE, 140011336876032, 140011336880127,
-ERASE, 140011336880128, 140011345268735,
-ERASE, 140011731136512, 140011731140607,
-ERASE, 140011731140608, 140011739529215,
-ERASE, 140011479486464, 140011479490559,
-ERASE, 140011479490560, 140011487879167,
-ERASE, 140011756314624, 140011756318719,
-ERASE, 140011756318720, 140011764707327,
-ERASE, 140011580133376, 140011580137471,
-ERASE, 140011580137472, 140011588526079,
-ERASE, 140011219443712, 140011219447807,
-ERASE, 140011219447808, 140011227836415,
-ERASE, 140011051655168, 140011051659263,
-ERASE, 140011051659264, 140011060047871,
-ERASE, 140011999571968, 140011999576063,
-ERASE, 140011999576064, 140012007964671,
-ERASE, 140011714351104, 140011714355199,
-ERASE, 140011714355200, 140011722743807,
-ERASE, 140011739529216, 140011739533311,
-ERASE, 140011739533312, 140011747921919,
-ERASE, 140011320090624, 140011320094719,
-ERASE, 140011320094720, 140011328483327,
-ERASE, 140011630489600, 140011630493695,
-ERASE, 140011630493696, 140011638882303,
-ERASE, 140011345268736, 140011345272831,
-ERASE, 140011345272832, 140011353661439,
-ERASE, 140011496271872, 140011496275967,
-ERASE, 140011496275968, 140011504664575,
-ERASE, 140011194265600, 140011194269695,
-ERASE, 140011194269696, 140011202658303,
-ERASE, 140011068440576, 140011068444671,
-ERASE, 140011068444672, 140011076833279,
-ERASE, 140010909044736, 140010909048831,
-ERASE, 140010909048832, 140010917437439,
-ERASE, 140011764707328, 140011764711423,
-ERASE, 140011764711424, 140011773100031,
-ERASE, 140011462701056, 140011462705151,
-ERASE, 140011462705152, 140011471093759,
-ERASE, 140011076833280, 140011076837375,
-ERASE, 140011076837376, 140011085225983,
-ERASE, 140011991179264, 140011991183359,
-ERASE, 140011991183360, 140011999571967,
-ERASE, 140011211051008, 140011211055103,
-ERASE, 140011211055104, 140011219443711,
-ERASE, 140010917437440, 140010917441535,
-ERASE, 140010917441536, 140010925830143,
-ERASE, 140011085225984, 140011085230079,
-ERASE, 140011085230080, 140011093618687,
-ERASE, 140011487879168, 140011487883263,
-ERASE, 140011487883264, 140011496271871,
-ERASE, 140011856961536, 140011856965631,
-ERASE, 140011856965632, 140011865354239,
-ERASE, 140011982786560, 140011982790655,
-ERASE, 140011982790656, 140011991179263,
-ERASE, 140011722743808, 140011722747903,
-ERASE, 140011722747904, 140011731136511,
-ERASE, 140011177480192, 140011177484287,
-ERASE, 140011177484288, 140011185872895,
-ERASE, 140011848568832, 140011848572927,
-ERASE, 140011848572928, 140011856961535,
-ERASE, 140011890532352, 140011890536447,
-ERASE, 140011890536448, 140011898925055,
-ERASE, 140011622096896, 140011622100991,
-ERASE, 140011622100992, 140011630489599,
-ERASE, 140011311697920, 140011311702015,
-ERASE, 140011311702016, 140011320090623,
-ERASE, 140011471093760, 140011471097855,
-ERASE, 140011471097856, 140011479486463,
-ERASE, 140011605311488, 140011605315583,
-ERASE, 140011605315584, 140011613704191,
-ERASE, 140010791612416, 140010791616511,
-ERASE, 140010791616512, 140010800005119,
-ERASE, 140010959400960, 140010959405055,
-ERASE, 140010959405056, 140010967793663,
-ERASE, 140011185872896, 140011185876991,
-ERASE, 140011185876992, 140011194265599,
-ERASE, 140011454308352, 140011454312447,
-ERASE, 140011454312448, 140011462701055,
-ERASE, 140011596918784, 140011596922879,
-ERASE, 140011596922880, 140011605311487,
-ERASE, 140011060047872, 140011060051967,
-ERASE, 140011060051968, 140011068440575,
-ERASE, 140010925830144, 140010925834239,
-ERASE, 140010925834240, 140010934222847,
-ERASE, 140011747921920, 140011747926015,
-ERASE, 140011747926016, 140011756314623,
-ERASE, 140011202658304, 140011202662399,
-ERASE, 140011202662400, 140011211051007,
-ERASE, 140010800005120, 140010800009215,
-ERASE, 140010800009216, 140010808397823,
-ERASE, 140011093618688, 140011093622783,
-ERASE, 140011093622784, 140011102011391,
-ERASE, 140010808397824, 140010808401919,
-ERASE, 140010808401920, 140010816790527,
-ERASE, 140012419010560, 140012419014655,
-ERASE, 140012419014656, 140012427403263,
-ERASE, 140010934222848, 140010934226943,
-ERASE, 140010934226944, 140010942615551,
-ERASE, 140010942615552, 140010942619647,
-ERASE, 140010942619648, 140010951008255,
-ERASE, 140011613704192, 140011613708287,
-ERASE, 140011613708288, 140011622096895,
-ERASE, 140011865354240, 140011865358335,
-ERASE, 140011865358336, 140011873746943,
-ERASE, 140012301578240, 140012301582335,
-ERASE, 140012301582336, 140012309970943,
-ERASE, 140012393832448, 140012393836543,
-ERASE, 140012393836544, 140012402225151,
-ERASE, 140012410617856, 140012410621951,
-ERASE, 140012410621952, 140012419010559,
-ERASE, 140012402225152, 140012402229247,
-ERASE, 140012402229248, 140012410617855,
-ERASE, 140012259614720, 140012259618815,
-ERASE, 140012259618816, 140012268007423,
-ERASE, 140012251222016, 140012251226111,
-ERASE, 140012251226112, 140012259614719,
-ERASE, 140012284792832, 140012284796927,
-ERASE, 140012284796928, 140012293185535,
-ERASE, 140011445915648, 140011445919743,
-ERASE, 140011445919744, 140011454308351,
-ERASE, 140010951008256, 140010951012351,
-ERASE, 140010951012352, 140010959400959,
-ERASE, 140011043262464, 140011043266559,
-ERASE, 140011043266560, 140011051655167,
-ERASE, 140010825183232, 140010825187327,
-ERASE, 140010825187328, 140010833575935,
-ERASE, 140012293185536, 140012293189631,
-ERASE, 140012293189632, 140012301578239,
-ERASE, 140012276400128, 140012276404223,
-ERASE, 140012276404224, 140012284792831,
-ERASE, 140012016357376, 140012016361471,
-ERASE, 140012016361472, 140012024750079,
-ERASE, 140012024750080, 140012024754175,
-ERASE, 140012024754176, 140012033142783,
-ERASE, 140011227836416, 140011227840511,
-ERASE, 140011227840512, 140011236229119,
-ERASE, 140010816790528, 140010816794623,
-ERASE, 140010816794624, 140010825183231,
-ERASE, 140012268007424, 140012268011519,
-ERASE, 140012268011520, 140012276400127,
-ERASE, 140012385439744, 140012385443839,
-ERASE, 140012385443840, 140012393832447,
-ERASE, 140012522090496, 140012522094591,
-ERASE, 140012522094592, 140012530483199,
-ERASE, 140012033142784, 140012033146879,
-ERASE, 140012033146880, 140012041535487,
- };
- unsigned long set35[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140730536939520, 140737488351231,
-SNULL, 140730536943615, 140737488351231,
-STORE, 140730536939520, 140730536943615,
-STORE, 140730536808448, 140730536943615,
-STORE, 94245239877632, 94245242130431,
-SNULL, 94245240008703, 94245242130431,
-STORE, 94245239877632, 94245240008703,
-STORE, 94245240008704, 94245242130431,
-ERASE, 94245240008704, 94245242130431,
-STORE, 94245242101760, 94245242109951,
-STORE, 94245242109952, 94245242130431,
-STORE, 140475575263232, 140475577516031,
-SNULL, 140475575406591, 140475577516031,
-STORE, 140475575263232, 140475575406591,
-STORE, 140475575406592, 140475577516031,
-ERASE, 140475575406592, 140475577516031,
-STORE, 140475577503744, 140475577511935,
-STORE, 140475577511936, 140475577516031,
-STORE, 140730538164224, 140730538168319,
-STORE, 140730538151936, 140730538164223,
-STORE, 140475577475072, 140475577503743,
-STORE, 140475577466880, 140475577475071,
-STORE, 140475573047296, 140475575263231,
-SNULL, 140475573047296, 140475573145599,
-STORE, 140475573145600, 140475575263231,
-STORE, 140475573047296, 140475573145599,
-SNULL, 140475575238655, 140475575263231,
-STORE, 140475573145600, 140475575238655,
-STORE, 140475575238656, 140475575263231,
-SNULL, 140475575238656, 140475575246847,
-STORE, 140475575246848, 140475575263231,
-STORE, 140475575238656, 140475575246847,
-ERASE, 140475575238656, 140475575246847,
-STORE, 140475575238656, 140475575246847,
-ERASE, 140475575246848, 140475575263231,
-STORE, 140475575246848, 140475575263231,
-STORE, 140475569250304, 140475573047295,
-SNULL, 140475569250304, 140475570909183,
-STORE, 140475570909184, 140475573047295,
-STORE, 140475569250304, 140475570909183,
-SNULL, 140475573006335, 140475573047295,
-STORE, 140475570909184, 140475573006335,
-STORE, 140475573006336, 140475573047295,
-SNULL, 140475573006336, 140475573030911,
-STORE, 140475573030912, 140475573047295,
-STORE, 140475573006336, 140475573030911,
-ERASE, 140475573006336, 140475573030911,
-STORE, 140475573006336, 140475573030911,
-ERASE, 140475573030912, 140475573047295,
-STORE, 140475573030912, 140475573047295,
-STORE, 140475577458688, 140475577475071,
-SNULL, 140475573022719, 140475573030911,
-STORE, 140475573006336, 140475573022719,
-STORE, 140475573022720, 140475573030911,
-SNULL, 140475575242751, 140475575246847,
-STORE, 140475575238656, 140475575242751,
-STORE, 140475575242752, 140475575246847,
-SNULL, 94245242105855, 94245242109951,
-STORE, 94245242101760, 94245242105855,
-STORE, 94245242105856, 94245242109951,
-SNULL, 140475577507839, 140475577511935,
-STORE, 140475577503744, 140475577507839,
-STORE, 140475577507840, 140475577511935,
-ERASE, 140475577475072, 140475577503743,
-STORE, 94245271216128, 94245271351295,
-STORE, 140475560857600, 140475569250303,
-SNULL, 140475560861695, 140475569250303,
-STORE, 140475560857600, 140475560861695,
-STORE, 140475560861696, 140475569250303,
-STORE, 140475552464896, 140475560857599,
-STORE, 140475418247168, 140475552464895,
-SNULL, 140475418247168, 140475428241407,
-STORE, 140475428241408, 140475552464895,
-STORE, 140475418247168, 140475428241407,
-ERASE, 140475418247168, 140475428241407,
-SNULL, 140475495350271, 140475552464895,
-STORE, 140475428241408, 140475495350271,
-STORE, 140475495350272, 140475552464895,
-ERASE, 140475495350272, 140475552464895,
-SNULL, 140475428376575, 140475495350271,
-STORE, 140475428241408, 140475428376575,
-STORE, 140475428376576, 140475495350271,
-SNULL, 140475552468991, 140475560857599,
-STORE, 140475552464896, 140475552468991,
-STORE, 140475552468992, 140475560857599,
-STORE, 140475544072192, 140475552464895,
-SNULL, 140475544076287, 140475552464895,
-STORE, 140475544072192, 140475544076287,
-STORE, 140475544076288, 140475552464895,
-STORE, 140475535679488, 140475544072191,
-SNULL, 140475535683583, 140475544072191,
-STORE, 140475535679488, 140475535683583,
-STORE, 140475535683584, 140475544072191,
-STORE, 140475527286784, 140475535679487,
-SNULL, 140475527290879, 140475535679487,
-STORE, 140475527286784, 140475527290879,
-STORE, 140475527290880, 140475535679487,
-STORE, 140475518894080, 140475527286783,
-STORE, 140475510501376, 140475527286783,
-STORE, 140475502108672, 140475527286783,
-STORE, 140475419848704, 140475428241407,
-STORE, 140475285630976, 140475419848703,
-SNULL, 140475285630976, 140475294023679,
-STORE, 140475294023680, 140475419848703,
-STORE, 140475285630976, 140475294023679,
-ERASE, 140475285630976, 140475294023679,
-STORE, 140475159805952, 140475419848703,
-STORE, 140475025588224, 140475419848703,
-SNULL, 140475092697087, 140475419848703,
-STORE, 140475025588224, 140475092697087,
-STORE, 140475092697088, 140475419848703,
-SNULL, 140475092697088, 140475159805951,
-STORE, 140475159805952, 140475419848703,
-STORE, 140475092697088, 140475159805951,
-ERASE, 140475092697088, 140475159805951,
-STORE, 140474891370496, 140475092697087,
-SNULL, 140474958479359, 140475092697087,
-STORE, 140474891370496, 140474958479359,
-STORE, 140474958479360, 140475092697087,
-SNULL, 140474958479360, 140475025588223,
-STORE, 140475025588224, 140475092697087,
-STORE, 140474958479360, 140475025588223,
-ERASE, 140474958479360, 140475025588223,
-SNULL, 140475361132543, 140475419848703,
-STORE, 140475159805952, 140475361132543,
-STORE, 140475361132544, 140475419848703,
-ERASE, 140475361132544, 140475419848703,
-SNULL, 140475159805952, 140475294023679,
-STORE, 140475294023680, 140475361132543,
-STORE, 140475159805952, 140475294023679,
-SNULL, 140475294158847, 140475361132543,
-STORE, 140475294023680, 140475294158847,
-STORE, 140475294158848, 140475361132543,
-SNULL, 140475226914815, 140475294023679,
-STORE, 140475159805952, 140475226914815,
-STORE, 140475226914816, 140475294023679,
-ERASE, 140475226914816, 140475294023679,
-SNULL, 140475025723391, 140475092697087,
-STORE, 140475025588224, 140475025723391,
-STORE, 140475025723392, 140475092697087,
-SNULL, 140475159941119, 140475226914815,
-STORE, 140475159805952, 140475159941119,
-STORE, 140475159941120, 140475226914815,
-SNULL, 140474891505663, 140474958479359,
-STORE, 140474891370496, 140474891505663,
-STORE, 140474891505664, 140474958479359,
-SNULL, 140475502108672, 140475518894079,
-STORE, 140475518894080, 140475527286783,
-STORE, 140475502108672, 140475518894079,
-SNULL, 140475518898175, 140475527286783,
-STORE, 140475518894080, 140475518898175,
-STORE, 140475518898176, 140475527286783,
-STORE, 140475411456000, 140475428241407,
-SNULL, 140475502112767, 140475518894079,
-STORE, 140475502108672, 140475502112767,
-STORE, 140475502112768, 140475518894079,
-SNULL, 140475411460095, 140475428241407,
-STORE, 140475411456000, 140475411460095,
-STORE, 140475411460096, 140475428241407,
-SNULL, 140475411460096, 140475419848703,
-STORE, 140475419848704, 140475428241407,
-STORE, 140475411460096, 140475419848703,
-SNULL, 140475419852799, 140475428241407,
-STORE, 140475419848704, 140475419852799,
-STORE, 140475419852800, 140475428241407,
-STORE, 140475403063296, 140475411455999,
-SNULL, 140475502112768, 140475510501375,
-STORE, 140475510501376, 140475518894079,
-STORE, 140475502112768, 140475510501375,
-SNULL, 140475510505471, 140475518894079,
-STORE, 140475510501376, 140475510505471,
-STORE, 140475510505472, 140475518894079,
-SNULL, 140475403067391, 140475411455999,
-STORE, 140475403063296, 140475403067391,
-STORE, 140475403067392, 140475411455999,
-STORE, 140475394670592, 140475403063295,
-SNULL, 140475394674687, 140475403063295,
-STORE, 140475394670592, 140475394674687,
-STORE, 140475394674688, 140475403063295,
-STORE, 140475386277888, 140475394670591,
-STORE, 140475377885184, 140475394670591,
-STORE, 140475369492480, 140475394670591,
-SNULL, 140475369496575, 140475394670591,
-STORE, 140475369492480, 140475369496575,
-STORE, 140475369496576, 140475394670591,
-SNULL, 140475369496576, 140475377885183,
-STORE, 140475377885184, 140475394670591,
-STORE, 140475369496576, 140475377885183,
-SNULL, 140475377889279, 140475394670591,
-STORE, 140475377885184, 140475377889279,
-STORE, 140475377889280, 140475394670591,
-STORE, 140475285630976, 140475294023679,
-SNULL, 140475377889280, 140475386277887,
-STORE, 140475386277888, 140475394670591,
-STORE, 140475377889280, 140475386277887,
-SNULL, 140475386281983, 140475394670591,
-STORE, 140475386277888, 140475386281983,
-STORE, 140475386281984, 140475394670591,
-SNULL, 140475285635071, 140475294023679,
-STORE, 140475285630976, 140475285635071,
-STORE, 140475285635072, 140475294023679,
-STORE, 140475277238272, 140475285630975,
-STORE, 140475268845568, 140475285630975,
-SNULL, 140475268845568, 140475277238271,
-STORE, 140475277238272, 140475285630975,
-STORE, 140475268845568, 140475277238271,
-SNULL, 140475277242367, 140475285630975,
-STORE, 140475277238272, 140475277242367,
-STORE, 140475277242368, 140475285630975,
-STORE, 140475260452864, 140475277238271,
-SNULL, 140475260452864, 140475268845567,
-STORE, 140475268845568, 140475277238271,
-STORE, 140475260452864, 140475268845567,
-SNULL, 140475268849663, 140475277238271,
-STORE, 140475268845568, 140475268849663,
-STORE, 140475268849664, 140475277238271,
-SNULL, 140475260456959, 140475268845567,
-STORE, 140475260452864, 140475260456959,
-STORE, 140475260456960, 140475268845567,
-STORE, 140475252060160, 140475260452863,
-SNULL, 140475252064255, 140475260452863,
-STORE, 140475252060160, 140475252064255,
-STORE, 140475252064256, 140475260452863,
-STORE, 140475243667456, 140475252060159,
-SNULL, 140475243671551, 140475252060159,
-STORE, 140475243667456, 140475243671551,
-STORE, 140475243671552, 140475252060159,
-STORE, 140475235274752, 140475243667455,
-STORE, 140475151413248, 140475159805951,
-STORE, 140474891505664, 140475025588223,
-STORE, 140475143020544, 140475159805951,
-SNULL, 140474891505664, 140474958479359,
-STORE, 140474958479360, 140475025588223,
-STORE, 140474891505664, 140474958479359,
-SNULL, 140474958614527, 140475025588223,
-STORE, 140474958479360, 140474958614527,
-STORE, 140474958614528, 140475025588223,
-STORE, 140474824261632, 140474891370495,
-SNULL, 140474824396799, 140474891370495,
-STORE, 140474824261632, 140474824396799,
-STORE, 140474824396800, 140474891370495,
-STORE, 140475134627840, 140475159805951,
-STORE, 140474690043904, 140474824261631,
-STORE, 140475126235136, 140475159805951,
-STORE, 140475117842432, 140475159805951,
-STORE, 140474622935040, 140474824261631,
-STORE, 140475109449728, 140475159805951,
-STORE, 140474488717312, 140474824261631,
-STORE, 140475101057024, 140475159805951,
-STORE, 140474480324608, 140474488717311,
-STORE, 140474413215744, 140474480324607,
-STORE, 140474404823040, 140474413215743,
-ERASE, 140474413215744, 140474480324607,
-STORE, 140474471931904, 140474488717311,
-STORE, 140474270605312, 140474404823039,
-SNULL, 140475101057024, 140475126235135,
-STORE, 140475126235136, 140475159805951,
-STORE, 140475101057024, 140475126235135,
-SNULL, 140475126239231, 140475159805951,
-STORE, 140475126235136, 140475126239231,
-STORE, 140475126239232, 140475159805951,
-STORE, 140474463539200, 140474488717311,
-STORE, 140474455146496, 140474488717311,
-SNULL, 140474455150591, 140474488717311,
-STORE, 140474455146496, 140474455150591,
-STORE, 140474455150592, 140474488717311,
-STORE, 140474446753792, 140474455146495,
-SNULL, 140474446757887, 140474455146495,
-STORE, 140474446753792, 140474446757887,
-STORE, 140474446757888, 140474455146495,
-STORE, 140474438361088, 140474446753791,
-STORE, 140474429968384, 140474446753791,
-SNULL, 140474429972479, 140474446753791,
-STORE, 140474429968384, 140474429972479,
-STORE, 140474429972480, 140474446753791,
-SNULL, 140475235278847, 140475243667455,
-STORE, 140475235274752, 140475235278847,
-STORE, 140475235278848, 140475243667455,
-SNULL, 140474757152767, 140474824261631,
-STORE, 140474488717312, 140474757152767,
-STORE, 140474757152768, 140474824261631,
-ERASE, 140474757152768, 140474824261631,
-SNULL, 140474488717312, 140474690043903,
-STORE, 140474690043904, 140474757152767,
-STORE, 140474488717312, 140474690043903,
-SNULL, 140474690179071, 140474757152767,
-STORE, 140474690043904, 140474690179071,
-STORE, 140474690179072, 140474757152767,
-SNULL, 140474488717312, 140474622935039,
-STORE, 140474622935040, 140474690043903,
-STORE, 140474488717312, 140474622935039,
-SNULL, 140474623070207, 140474690043903,
-STORE, 140474622935040, 140474623070207,
-STORE, 140474623070208, 140474690043903,
-SNULL, 140475101057024, 140475117842431,
-STORE, 140475117842432, 140475126235135,
-STORE, 140475101057024, 140475117842431,
-SNULL, 140475117846527, 140475126235135,
-STORE, 140475117842432, 140475117846527,
-STORE, 140475117846528, 140475126235135,
-SNULL, 140474555826175, 140474622935039,
-STORE, 140474488717312, 140474555826175,
-STORE, 140474555826176, 140474622935039,
-ERASE, 140474555826176, 140474622935039,
-STORE, 140474136387584, 140474404823039,
-SNULL, 140474136387584, 140474153172991,
-STORE, 140474153172992, 140474404823039,
-STORE, 140474136387584, 140474153172991,
-ERASE, 140474136387584, 140474153172991,
-STORE, 140474018955264, 140474404823039,
-STORE, 140473884737536, 140474404823039,
-SNULL, 140474086064127, 140474404823039,
-STORE, 140473884737536, 140474086064127,
-STORE, 140474086064128, 140474404823039,
-SNULL, 140474086064128, 140474153172991,
-STORE, 140474153172992, 140474404823039,
-STORE, 140474086064128, 140474153172991,
-ERASE, 140474086064128, 140474153172991,
-STORE, 140473750519808, 140474086064127,
-SNULL, 140473817628671, 140474086064127,
-STORE, 140473750519808, 140473817628671,
-STORE, 140473817628672, 140474086064127,
-SNULL, 140473817628672, 140473884737535,
-STORE, 140473884737536, 140474086064127,
-STORE, 140473817628672, 140473884737535,
-ERASE, 140473817628672, 140473884737535,
-SNULL, 140475126239232, 140475151413247,
-STORE, 140475151413248, 140475159805951,
-STORE, 140475126239232, 140475151413247,
-SNULL, 140475151417343, 140475159805951,
-STORE, 140475151413248, 140475151417343,
-STORE, 140475151417344, 140475159805951,
-SNULL, 140474270605311, 140474404823039,
-STORE, 140474153172992, 140474270605311,
-STORE, 140474270605312, 140474404823039,
-SNULL, 140474270605312, 140474287390719,
-STORE, 140474287390720, 140474404823039,
-STORE, 140474270605312, 140474287390719,
-ERASE, 140474270605312, 140474287390719,
-SNULL, 140474429972480, 140474438361087,
-STORE, 140474438361088, 140474446753791,
-STORE, 140474429972480, 140474438361087,
-SNULL, 140474438365183, 140474446753791,
-STORE, 140474438361088, 140474438365183,
-STORE, 140474438365184, 140474446753791,
-STORE, 140474815868928, 140474824261631,
-SNULL, 140474815873023, 140474824261631,
-STORE, 140474815868928, 140474815873023,
-STORE, 140474815873024, 140474824261631,
-SNULL, 140474220281855, 140474270605311,
-STORE, 140474153172992, 140474220281855,
-STORE, 140474220281856, 140474270605311,
-ERASE, 140474220281856, 140474270605311,
-SNULL, 140474488852479, 140474555826175,
-STORE, 140474488717312, 140474488852479,
-STORE, 140474488852480, 140474555826175,
-SNULL, 140475101057024, 140475109449727,
-STORE, 140475109449728, 140475117842431,
-STORE, 140475101057024, 140475109449727,
-SNULL, 140475109453823, 140475117842431,
-STORE, 140475109449728, 140475109453823,
-STORE, 140475109453824, 140475117842431,
-SNULL, 140473951846399, 140474086064127,
-STORE, 140473884737536, 140473951846399,
-STORE, 140473951846400, 140474086064127,
-SNULL, 140473951846400, 140474018955263,
-STORE, 140474018955264, 140474086064127,
-STORE, 140473951846400, 140474018955263,
-ERASE, 140473951846400, 140474018955263,
-SNULL, 140473884872703, 140473951846399,
-STORE, 140473884737536, 140473884872703,
-STORE, 140473884872704, 140473951846399,
-SNULL, 140474019090431, 140474086064127,
-STORE, 140474018955264, 140474019090431,
-STORE, 140474019090432, 140474086064127,
-SNULL, 140473750654975, 140473817628671,
-STORE, 140473750519808, 140473750654975,
-STORE, 140473750654976, 140473817628671,
-SNULL, 140474455150592, 140474463539199,
-STORE, 140474463539200, 140474488717311,
-STORE, 140474455150592, 140474463539199,
-SNULL, 140474463543295, 140474488717311,
-STORE, 140474463539200, 140474463543295,
-STORE, 140474463543296, 140474488717311,
-STORE, 140474807476224, 140474815868927,
-SNULL, 140474463543296, 140474471931903,
-STORE, 140474471931904, 140474488717311,
-STORE, 140474463543296, 140474471931903,
-SNULL, 140474471935999, 140474488717311,
-STORE, 140474471931904, 140474471935999,
-STORE, 140474471936000, 140474488717311,
-STORE, 140474799083520, 140474815868927,
-STORE, 140474790690816, 140474815868927,
-SNULL, 140474790690816, 140474799083519,
-STORE, 140474799083520, 140474815868927,
-STORE, 140474790690816, 140474799083519,
-SNULL, 140474799087615, 140474815868927,
-STORE, 140474799083520, 140474799087615,
-STORE, 140474799087616, 140474815868927,
-SNULL, 140474354499583, 140474404823039,
-STORE, 140474287390720, 140474354499583,
-STORE, 140474354499584, 140474404823039,
-ERASE, 140474354499584, 140474404823039,
-SNULL, 140474287525887, 140474354499583,
-STORE, 140474287390720, 140474287525887,
-STORE, 140474287525888, 140474354499583,
-STORE, 140474782298112, 140474799083519,
-STORE, 140474773905408, 140474799083519,
-SNULL, 140474773909503, 140474799083519,
-STORE, 140474773905408, 140474773909503,
-STORE, 140474773909504, 140474799083519,
-SNULL, 140475126239232, 140475134627839,
-STORE, 140475134627840, 140475151413247,
-STORE, 140475126239232, 140475134627839,
-SNULL, 140475134631935, 140475151413247,
-STORE, 140475134627840, 140475134631935,
-STORE, 140475134631936, 140475151413247,
-STORE, 140474765512704, 140474773905407,
-STORE, 140474614542336, 140474622935039,
-SNULL, 140474153308159, 140474220281855,
-STORE, 140474153172992, 140474153308159,
-STORE, 140474153308160, 140474220281855,
-SNULL, 140474404827135, 140474413215743,
-STORE, 140474404823040, 140474404827135,
-STORE, 140474404827136, 140474413215743,
-STORE, 140474606149632, 140474622935039,
-SNULL, 140474606153727, 140474622935039,
-STORE, 140474606149632, 140474606153727,
-STORE, 140474606153728, 140474622935039,
-STORE, 140474597756928, 140474606149631,
-SNULL, 140474597761023, 140474606149631,
-STORE, 140474597756928, 140474597761023,
-STORE, 140474597761024, 140474606149631,
-SNULL, 140475134631936, 140475143020543,
-STORE, 140475143020544, 140475151413247,
-STORE, 140475134631936, 140475143020543,
-SNULL, 140475143024639, 140475151413247,
-STORE, 140475143020544, 140475143024639,
-STORE, 140475143024640, 140475151413247,
-STORE, 140474589364224, 140474597756927,
-SNULL, 140474606153728, 140474614542335,
-STORE, 140474614542336, 140474622935039,
-STORE, 140474606153728, 140474614542335,
-SNULL, 140474614546431, 140474622935039,
-STORE, 140474614542336, 140474614546431,
-STORE, 140474614546432, 140474622935039,
-SNULL, 140474765516799, 140474773905407,
-STORE, 140474765512704, 140474765516799,
-STORE, 140474765516800, 140474773905407,
-STORE, 140474580971520, 140474597756927,
-SNULL, 140474773909504, 140474782298111,
-STORE, 140474782298112, 140474799083519,
-STORE, 140474773909504, 140474782298111,
-SNULL, 140474782302207, 140474799083519,
-STORE, 140474782298112, 140474782302207,
-STORE, 140474782302208, 140474799083519,
-SNULL, 140474471936000, 140474480324607,
-STORE, 140474480324608, 140474488717311,
-STORE, 140474471936000, 140474480324607,
-SNULL, 140474480328703, 140474488717311,
-STORE, 140474480324608, 140474480328703,
-STORE, 140474480328704, 140474488717311,
-STORE, 140474572578816, 140474597756927,
-SNULL, 140474572582911, 140474597756927,
-STORE, 140474572578816, 140474572582911,
-STORE, 140474572582912, 140474597756927,
-SNULL, 140474782302208, 140474790690815,
-STORE, 140474790690816, 140474799083519,
-STORE, 140474782302208, 140474790690815,
-SNULL, 140474790694911, 140474799083519,
-STORE, 140474790690816, 140474790694911,
-STORE, 140474790694912, 140474799083519,
-STORE, 140474564186112, 140474572578815,
-STORE, 140474421575680, 140474429968383,
-STORE, 140474396430336, 140474404823039,
-SNULL, 140474396434431, 140474404823039,
-STORE, 140474396430336, 140474396434431,
-STORE, 140474396434432, 140474404823039,
-STORE, 140474388037632, 140474396430335,
-SNULL, 140474799087616, 140474807476223,
-STORE, 140474807476224, 140474815868927,
-STORE, 140474799087616, 140474807476223,
-SNULL, 140474807480319, 140474815868927,
-STORE, 140474807476224, 140474807480319,
-STORE, 140474807480320, 140474815868927,
-SNULL, 140475101061119, 140475109449727,
-STORE, 140475101057024, 140475101061119,
-STORE, 140475101061120, 140475109449727,
-STORE, 140474379644928, 140474396430335,
-SNULL, 140474572582912, 140474589364223,
-STORE, 140474589364224, 140474597756927,
-STORE, 140474572582912, 140474589364223,
-SNULL, 140474589368319, 140474597756927,
-STORE, 140474589364224, 140474589368319,
-STORE, 140474589368320, 140474597756927,
-STORE, 140474371252224, 140474396430335,
-STORE, 140474362859520, 140474396430335,
-STORE, 140474278998016, 140474287390719,
-STORE, 140474270605312, 140474287390719,
-STORE, 140474262212608, 140474287390719,
-SNULL, 140474262216703, 140474287390719,
-STORE, 140474262212608, 140474262216703,
-STORE, 140474262216704, 140474287390719,
-STORE, 140474253819904, 140474262212607,
-SNULL, 140474253823999, 140474262212607,
-STORE, 140474253819904, 140474253823999,
-STORE, 140474253824000, 140474262212607,
-SNULL, 140474362859520, 140474388037631,
-STORE, 140474388037632, 140474396430335,
-STORE, 140474362859520, 140474388037631,
-SNULL, 140474388041727, 140474396430335,
-STORE, 140474388037632, 140474388041727,
-STORE, 140474388041728, 140474396430335,
-SNULL, 140474362859520, 140474379644927,
-STORE, 140474379644928, 140474388037631,
-STORE, 140474362859520, 140474379644927,
-SNULL, 140474379649023, 140474388037631,
-STORE, 140474379644928, 140474379649023,
-STORE, 140474379649024, 140474388037631,
-STORE, 140474245427200, 140474253819903,
-STORE, 140474237034496, 140474253819903,
-STORE, 140474228641792, 140474253819903,
-STORE, 140474144780288, 140474153172991,
-SNULL, 140474228645887, 140474253819903,
-STORE, 140474228641792, 140474228645887,
-STORE, 140474228645888, 140474253819903,
-SNULL, 140474564190207, 140474572578815,
-STORE, 140474564186112, 140474564190207,
-STORE, 140474564190208, 140474572578815,
-STORE, 140474136387584, 140474153172991,
-SNULL, 140474362859520, 140474371252223,
-STORE, 140474371252224, 140474379644927,
-STORE, 140474362859520, 140474371252223,
-SNULL, 140474371256319, 140474379644927,
-STORE, 140474371252224, 140474371256319,
-STORE, 140474371256320, 140474379644927,
-STORE, 140474127994880, 140474153172991,
-STORE, 140474119602176, 140474153172991,
-SNULL, 140474421579775, 140474429968383,
-STORE, 140474421575680, 140474421579775,
-STORE, 140474421579776, 140474429968383,
-STORE, 140474111209472, 140474153172991,
-SNULL, 140474111213567, 140474153172991,
-STORE, 140474111209472, 140474111213567,
-STORE, 140474111213568, 140474153172991,
-SNULL, 140474262216704, 140474270605311,
-STORE, 140474270605312, 140474287390719,
-STORE, 140474262216704, 140474270605311,
-SNULL, 140474270609407, 140474287390719,
-STORE, 140474270605312, 140474270609407,
-STORE, 140474270609408, 140474287390719,
-STORE, 140474102816768, 140474111209471,
-SNULL, 140474102820863, 140474111209471,
-STORE, 140474102816768, 140474102820863,
-STORE, 140474102820864, 140474111209471,
-SNULL, 140474270609408, 140474278998015,
-STORE, 140474278998016, 140474287390719,
-STORE, 140474270609408, 140474278998015,
-SNULL, 140474279002111, 140474287390719,
-STORE, 140474278998016, 140474279002111,
-STORE, 140474279002112, 140474287390719,
-STORE, 140474094424064, 140474102816767,
-SNULL, 140474572582912, 140474580971519,
-STORE, 140474580971520, 140474589364223,
-STORE, 140474572582912, 140474580971519,
-SNULL, 140474580975615, 140474589364223,
-STORE, 140474580971520, 140474580975615,
-STORE, 140474580975616, 140474589364223,
-SNULL, 140474362863615, 140474371252223,
-STORE, 140474362859520, 140474362863615,
-STORE, 140474362863616, 140474371252223,
-STORE, 140474010562560, 140474018955263,
-SNULL, 140474228645888, 140474245427199,
-STORE, 140474245427200, 140474253819903,
-STORE, 140474228645888, 140474245427199,
-SNULL, 140474245431295, 140474253819903,
-STORE, 140474245427200, 140474245431295,
-STORE, 140474245431296, 140474253819903,
-SNULL, 140474111213568, 140474136387583,
-STORE, 140474136387584, 140474153172991,
-STORE, 140474111213568, 140474136387583,
-SNULL, 140474136391679, 140474153172991,
-STORE, 140474136387584, 140474136391679,
-STORE, 140474136391680, 140474153172991,
-STORE, 140474002169856, 140474018955263,
-STORE, 140473993777152, 140474018955263,
-SNULL, 140474111213568, 140474127994879,
-STORE, 140474127994880, 140474136387583,
-STORE, 140474111213568, 140474127994879,
-SNULL, 140474127998975, 140474136387583,
-STORE, 140474127994880, 140474127998975,
-STORE, 140474127998976, 140474136387583,
-SNULL, 140474228645888, 140474237034495,
-STORE, 140474237034496, 140474245427199,
-STORE, 140474228645888, 140474237034495,
-SNULL, 140474237038591, 140474245427199,
-STORE, 140474237034496, 140474237038591,
-STORE, 140474237038592, 140474245427199,
-SNULL, 140474136391680, 140474144780287,
-STORE, 140474144780288, 140474153172991,
-STORE, 140474136391680, 140474144780287,
-SNULL, 140474144784383, 140474153172991,
-STORE, 140474144780288, 140474144784383,
-STORE, 140474144784384, 140474153172991,
-STORE, 140473985384448, 140474018955263,
-STORE, 140473976991744, 140474018955263,
-STORE, 140473968599040, 140474018955263,
-SNULL, 140473968603135, 140474018955263,
-STORE, 140473968599040, 140473968603135,
-STORE, 140473968603136, 140474018955263,
-SNULL, 140474111213568, 140474119602175,
-STORE, 140474119602176, 140474127994879,
-STORE, 140474111213568, 140474119602175,
-SNULL, 140474119606271, 140474127994879,
-STORE, 140474119602176, 140474119606271,
-STORE, 140474119606272, 140474127994879,
-STORE, 140473960206336, 140473968599039,
-SNULL, 140474094428159, 140474102816767,
-STORE, 140474094424064, 140474094428159,
-STORE, 140474094428160, 140474102816767,
-STORE, 140473876344832, 140473884737535,
-STORE, 140473867952128, 140473884737535,
-STORE, 140473859559424, 140473884737535,
-SNULL, 140473859563519, 140473884737535,
-STORE, 140473859559424, 140473859563519,
-STORE, 140473859563520, 140473884737535,
-SNULL, 140473968603136, 140473993777151,
-STORE, 140473993777152, 140474018955263,
-STORE, 140473968603136, 140473993777151,
-SNULL, 140473993781247, 140474018955263,
-STORE, 140473993777152, 140473993781247,
-STORE, 140473993781248, 140474018955263,
-SNULL, 140473960210431, 140473968599039,
-STORE, 140473960206336, 140473960210431,
-STORE, 140473960210432, 140473968599039,
-SNULL, 140473993781248, 140474010562559,
-STORE, 140474010562560, 140474018955263,
-STORE, 140473993781248, 140474010562559,
-SNULL, 140474010566655, 140474018955263,
-STORE, 140474010562560, 140474010566655,
-STORE, 140474010566656, 140474018955263,
-SNULL, 140473968603136, 140473985384447,
-STORE, 140473985384448, 140473993777151,
-STORE, 140473968603136, 140473985384447,
-SNULL, 140473985388543, 140473993777151,
-STORE, 140473985384448, 140473985388543,
-STORE, 140473985388544, 140473993777151,
-SNULL, 140473993781248, 140474002169855,
-STORE, 140474002169856, 140474010562559,
-STORE, 140473993781248, 140474002169855,
-SNULL, 140474002173951, 140474010562559,
-STORE, 140474002169856, 140474002173951,
-STORE, 140474002173952, 140474010562559,
-STORE, 140473851166720, 140473859559423,
-SNULL, 140473851170815, 140473859559423,
-STORE, 140473851166720, 140473851170815,
-STORE, 140473851170816, 140473859559423,
-SNULL, 140473968603136, 140473976991743,
-STORE, 140473976991744, 140473985384447,
-STORE, 140473968603136, 140473976991743,
-SNULL, 140473976995839, 140473985384447,
-STORE, 140473976991744, 140473976995839,
-STORE, 140473976995840, 140473985384447,
-STORE, 140473842774016, 140473851166719,
-SNULL, 140473859563520, 140473867952127,
-STORE, 140473867952128, 140473884737535,
-STORE, 140473859563520, 140473867952127,
-SNULL, 140473867956223, 140473884737535,
-STORE, 140473867952128, 140473867956223,
-STORE, 140473867956224, 140473884737535,
-SNULL, 140473867956224, 140473876344831,
-STORE, 140473876344832, 140473884737535,
-STORE, 140473867956224, 140473876344831,
-SNULL, 140473876348927, 140473884737535,
-STORE, 140473876344832, 140473876348927,
-STORE, 140473876348928, 140473884737535,
-STORE, 140473834381312, 140473851166719,
-SNULL, 140473834385407, 140473851166719,
-STORE, 140473834381312, 140473834385407,
-STORE, 140473834385408, 140473851166719,
-SNULL, 140473834385408, 140473842774015,
-STORE, 140473842774016, 140473851166719,
-STORE, 140473834385408, 140473842774015,
-SNULL, 140473842778111, 140473851166719,
-STORE, 140473842774016, 140473842778111,
-STORE, 140473842778112, 140473851166719,
-STORE, 140473825988608, 140473834381311,
-SNULL, 140473825992703, 140473834381311,
-STORE, 140473825988608, 140473825992703,
-STORE, 140473825992704, 140473834381311,
-STORE, 140475577475072, 140475577503743,
-STORE, 140475499917312, 140475502108671,
-SNULL, 140475499917312, 140475500007423,
-STORE, 140475500007424, 140475502108671,
-STORE, 140475499917312, 140475500007423,
-SNULL, 140475502100479, 140475502108671,
-STORE, 140475500007424, 140475502100479,
-STORE, 140475502100480, 140475502108671,
-ERASE, 140475502100480, 140475502108671,
-STORE, 140475502100480, 140475502108671,
-SNULL, 140475502104575, 140475502108671,
-STORE, 140475502100480, 140475502104575,
-STORE, 140475502104576, 140475502108671,
-ERASE, 140475577475072, 140475577503743,
-ERASE, 140475235274752, 140475235278847,
-ERASE, 140475235278848, 140475243667455,
-ERASE, 140474815868928, 140474815873023,
-ERASE, 140474815873024, 140474824261631,
-ERASE, 140474606149632, 140474606153727,
-ERASE, 140474606153728, 140474614542335,
-ERASE, 140474270605312, 140474270609407,
-ERASE, 140474270609408, 140474278998015,
-ERASE, 140474438361088, 140474438365183,
-ERASE, 140474438365184, 140474446753791,
-ERASE, 140474597756928, 140474597761023,
-ERASE, 140474597761024, 140474606149631,
-ERASE, 140475126235136, 140475126239231,
-ERASE, 140475126239232, 140475134627839,
-ERASE, 140474463539200, 140474463543295,
-ERASE, 140474463543296, 140474471931903,
-ERASE, 140474388037632, 140474388041727,
-ERASE, 140474388041728, 140474396430335,
-ERASE, 140474404823040, 140474404827135,
-ERASE, 140474404827136, 140474413215743,
-ERASE, 140474278998016, 140474279002111,
-ERASE, 140474279002112, 140474287390719,
-ERASE, 140474094424064, 140474094428159,
-ERASE, 140474094428160, 140474102816767,
-ERASE, 140473867952128, 140473867956223,
-ERASE, 140473867956224, 140473876344831,
-ERASE, 140475151413248, 140475151417343,
-ERASE, 140475151417344, 140475159805951,
-ERASE, 140474455146496, 140474455150591,
-ERASE, 140474455150592, 140474463539199,
-ERASE, 140474807476224, 140474807480319,
-ERASE, 140474807480320, 140474815868927,
-ERASE, 140475117842432, 140475117846527,
-ERASE, 140475117846528, 140475126235135,
-ERASE, 140474446753792, 140474446757887,
-ERASE, 140474446757888, 140474455146495,
-ERASE, 140474429968384, 140474429972479,
-ERASE, 140474429972480, 140474438361087,
-ERASE, 140474782298112, 140474782302207,
-ERASE, 140474782302208, 140474790690815,
-ERASE, 140474136387584, 140474136391679,
-ERASE, 140474136391680, 140474144780287,
-ERASE, 140474002169856, 140474002173951,
-ERASE, 140474002173952, 140474010562559,
-ERASE, 140475134627840, 140475134631935,
-ERASE, 140475134631936, 140475143020543,
-ERASE, 140474471931904, 140474471935999,
-ERASE, 140474471936000, 140474480324607,
-ERASE, 140474396430336, 140474396434431,
-ERASE, 140474396434432, 140474404823039,
- };
- unsigned long set36[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140723893125120, 140737488351231,
-SNULL, 140723893129215, 140737488351231,
-STORE, 140723893125120, 140723893129215,
-STORE, 140723892994048, 140723893129215,
-STORE, 94076829786112, 94076832038911,
-SNULL, 94076829917183, 94076832038911,
-STORE, 94076829786112, 94076829917183,
-STORE, 94076829917184, 94076832038911,
-ERASE, 94076829917184, 94076832038911,
-STORE, 94076832010240, 94076832018431,
-STORE, 94076832018432, 94076832038911,
-STORE, 140122444345344, 140122446598143,
-SNULL, 140122444488703, 140122446598143,
-STORE, 140122444345344, 140122444488703,
-STORE, 140122444488704, 140122446598143,
-ERASE, 140122444488704, 140122446598143,
-STORE, 140122446585856, 140122446594047,
-STORE, 140122446594048, 140122446598143,
-STORE, 140723893538816, 140723893542911,
-STORE, 140723893526528, 140723893538815,
-STORE, 140122446557184, 140122446585855,
-STORE, 140122446548992, 140122446557183,
-STORE, 140122442129408, 140122444345343,
-SNULL, 140122442129408, 140122442227711,
-STORE, 140122442227712, 140122444345343,
-STORE, 140122442129408, 140122442227711,
-SNULL, 140122444320767, 140122444345343,
-STORE, 140122442227712, 140122444320767,
-STORE, 140122444320768, 140122444345343,
-SNULL, 140122444320768, 140122444328959,
-STORE, 140122444328960, 140122444345343,
-STORE, 140122444320768, 140122444328959,
-ERASE, 140122444320768, 140122444328959,
-STORE, 140122444320768, 140122444328959,
-ERASE, 140122444328960, 140122444345343,
-STORE, 140122444328960, 140122444345343,
-STORE, 140122438332416, 140122442129407,
-SNULL, 140122438332416, 140122439991295,
-STORE, 140122439991296, 140122442129407,
-STORE, 140122438332416, 140122439991295,
-SNULL, 140122442088447, 140122442129407,
-STORE, 140122439991296, 140122442088447,
-STORE, 140122442088448, 140122442129407,
-SNULL, 140122442088448, 140122442113023,
-STORE, 140122442113024, 140122442129407,
-STORE, 140122442088448, 140122442113023,
-ERASE, 140122442088448, 140122442113023,
-STORE, 140122442088448, 140122442113023,
-ERASE, 140122442113024, 140122442129407,
-STORE, 140122442113024, 140122442129407,
-STORE, 140122446540800, 140122446557183,
-SNULL, 140122442104831, 140122442113023,
-STORE, 140122442088448, 140122442104831,
-STORE, 140122442104832, 140122442113023,
-SNULL, 140122444324863, 140122444328959,
-STORE, 140122444320768, 140122444324863,
-STORE, 140122444324864, 140122444328959,
-SNULL, 94076832014335, 94076832018431,
-STORE, 94076832010240, 94076832014335,
-STORE, 94076832014336, 94076832018431,
-SNULL, 140122446589951, 140122446594047,
-STORE, 140122446585856, 140122446589951,
-STORE, 140122446589952, 140122446594047,
-ERASE, 140122446557184, 140122446585855,
-STORE, 94076845723648, 94076845858815,
-STORE, 140122429939712, 140122438332415,
-SNULL, 140122429943807, 140122438332415,
-STORE, 140122429939712, 140122429943807,
-STORE, 140122429943808, 140122438332415,
-STORE, 140122421547008, 140122429939711,
-STORE, 140122287329280, 140122421547007,
-SNULL, 140122287329280, 140122301399039,
-STORE, 140122301399040, 140122421547007,
-STORE, 140122287329280, 140122301399039,
-ERASE, 140122287329280, 140122301399039,
-SNULL, 140122368507903, 140122421547007,
-STORE, 140122301399040, 140122368507903,
-STORE, 140122368507904, 140122421547007,
-ERASE, 140122368507904, 140122421547007,
-SNULL, 140122301534207, 140122368507903,
-STORE, 140122301399040, 140122301534207,
-STORE, 140122301534208, 140122368507903,
-SNULL, 140122421551103, 140122429939711,
-STORE, 140122421547008, 140122421551103,
-STORE, 140122421551104, 140122429939711,
-STORE, 140122413154304, 140122421547007,
-SNULL, 140122413158399, 140122421547007,
-STORE, 140122413154304, 140122413158399,
-STORE, 140122413158400, 140122421547007,
-STORE, 140122404761600, 140122413154303,
-SNULL, 140122404765695, 140122413154303,
-STORE, 140122404761600, 140122404765695,
-STORE, 140122404765696, 140122413154303,
-STORE, 140122396368896, 140122404761599,
-SNULL, 140122396372991, 140122404761599,
-STORE, 140122396368896, 140122396372991,
-STORE, 140122396372992, 140122404761599,
-STORE, 140122387976192, 140122396368895,
-STORE, 140122167181312, 140122301399039,
-SNULL, 140122234290175, 140122301399039,
-STORE, 140122167181312, 140122234290175,
-STORE, 140122234290176, 140122301399039,
-ERASE, 140122234290176, 140122301399039,
-SNULL, 140122167316479, 140122234290175,
-STORE, 140122167181312, 140122167316479,
-STORE, 140122167316480, 140122234290175,
-STORE, 140122379583488, 140122396368895,
-STORE, 140122371190784, 140122396368895,
-STORE, 140122167316480, 140122301399039,
-STORE, 140122158788608, 140122167181311,
-SNULL, 140122371190784, 140122387976191,
-STORE, 140122387976192, 140122396368895,
-STORE, 140122371190784, 140122387976191,
-SNULL, 140122387980287, 140122396368895,
-STORE, 140122387976192, 140122387980287,
-STORE, 140122387980288, 140122396368895,
-SNULL, 140122167316480, 140122234290175,
-STORE, 140122234290176, 140122301399039,
-STORE, 140122167316480, 140122234290175,
-SNULL, 140122234425343, 140122301399039,
-STORE, 140122234290176, 140122234425343,
-STORE, 140122234425344, 140122301399039,
-STORE, 140122024570880, 140122158788607,
-SNULL, 140122024570880, 140122032963583,
-STORE, 140122032963584, 140122158788607,
-STORE, 140122024570880, 140122032963583,
-ERASE, 140122024570880, 140122032963583,
-STORE, 140121898745856, 140122158788607,
-STORE, 140121890353152, 140121898745855,
-SNULL, 140122100072447, 140122158788607,
-STORE, 140121898745856, 140122100072447,
-STORE, 140122100072448, 140122158788607,
-ERASE, 140122100072448, 140122158788607,
-SNULL, 140121965854719, 140122100072447,
-STORE, 140121898745856, 140121965854719,
-STORE, 140121965854720, 140122100072447,
-SNULL, 140121965854720, 140122032963583,
-STORE, 140122032963584, 140122100072447,
-STORE, 140121965854720, 140122032963583,
-ERASE, 140121965854720, 140122032963583,
-SNULL, 140121898881023, 140121965854719,
-STORE, 140121898745856, 140121898881023,
-STORE, 140121898881024, 140121965854719,
-SNULL, 140121890357247, 140121898745855,
-STORE, 140121890353152, 140121890357247,
-STORE, 140121890357248, 140121898745855,
-SNULL, 140122371190784, 140122379583487,
-STORE, 140122379583488, 140122387976191,
-STORE, 140122371190784, 140122379583487,
-SNULL, 140122379587583, 140122387976191,
-STORE, 140122379583488, 140122379587583,
-STORE, 140122379587584, 140122387976191,
-SNULL, 140122033098751, 140122100072447,
-STORE, 140122032963584, 140122033098751,
-STORE, 140122033098752, 140122100072447,
-SNULL, 140122158792703, 140122167181311,
-STORE, 140122158788608, 140122158792703,
-STORE, 140122158792704, 140122167181311,
-STORE, 140122150395904, 140122158788607,
-STORE, 140122142003200, 140122158788607,
-SNULL, 140122142007295, 140122158788607,
-STORE, 140122142003200, 140122142007295,
-STORE, 140122142007296, 140122158788607,
-SNULL, 140122371194879, 140122379583487,
-STORE, 140122371190784, 140122371194879,
-STORE, 140122371194880, 140122379583487,
-SNULL, 140122142007296, 140122150395903,
-STORE, 140122150395904, 140122158788607,
-STORE, 140122142007296, 140122150395903,
-SNULL, 140122150399999, 140122158788607,
-STORE, 140122150395904, 140122150399999,
-STORE, 140122150400000, 140122158788607,
-STORE, 140122133610496, 140122142003199,
-STORE, 140122125217792, 140122142003199,
-STORE, 140122116825088, 140122142003199,
-SNULL, 140122116829183, 140122142003199,
-STORE, 140122116825088, 140122116829183,
-STORE, 140122116829184, 140122142003199,
-SNULL, 140122116829184, 140122133610495,
-STORE, 140122133610496, 140122142003199,
-STORE, 140122116829184, 140122133610495,
-SNULL, 140122133614591, 140122142003199,
-STORE, 140122133610496, 140122133614591,
-STORE, 140122133614592, 140122142003199,
-SNULL, 140122116829184, 140122125217791,
-STORE, 140122125217792, 140122133610495,
-STORE, 140122116829184, 140122125217791,
-SNULL, 140122125221887, 140122133610495,
-STORE, 140122125217792, 140122125221887,
-STORE, 140122125221888, 140122133610495,
-STORE, 140122108432384, 140122116825087,
-SNULL, 140122108436479, 140122116825087,
-STORE, 140122108432384, 140122108436479,
-STORE, 140122108436480, 140122116825087,
-STORE, 140122024570880, 140122032963583,
-STORE, 140122016178176, 140122032963583,
-SNULL, 140122016182271, 140122032963583,
-STORE, 140122016178176, 140122016182271,
-STORE, 140122016182272, 140122032963583,
-SNULL, 140122016182272, 140122024570879,
-STORE, 140122024570880, 140122032963583,
-STORE, 140122016182272, 140122024570879,
-SNULL, 140122024574975, 140122032963583,
-STORE, 140122024570880, 140122024574975,
-STORE, 140122024574976, 140122032963583,
-STORE, 140122007785472, 140122016178175,
-SNULL, 140122007789567, 140122016178175,
-STORE, 140122007785472, 140122007789567,
-STORE, 140122007789568, 140122016178175,
-STORE, 140121999392768, 140122007785471,
-STORE, 140121991000064, 140122007785471,
-SNULL, 140121991004159, 140122007785471,
-STORE, 140121991000064, 140121991004159,
-STORE, 140121991004160, 140122007785471,
-SNULL, 140121991004160, 140121999392767,
-STORE, 140121999392768, 140122007785471,
-STORE, 140121991004160, 140121999392767,
-SNULL, 140121999396863, 140122007785471,
-STORE, 140121999392768, 140121999396863,
-STORE, 140121999396864, 140122007785471,
-STORE, 140121982607360, 140121991000063,
-STORE, 140121823244288, 140121890353151,
-ERASE, 140121823244288, 140121890353151,
-STORE, 140121756135424, 140121890353151,
-SNULL, 140121756135424, 140121764528127,
-STORE, 140121764528128, 140121890353151,
-STORE, 140121756135424, 140121764528127,
-ERASE, 140121756135424, 140121764528127,
-SNULL, 140121831636991, 140121890353151,
-STORE, 140121764528128, 140121831636991,
-STORE, 140121831636992, 140121890353151,
-ERASE, 140121831636992, 140121890353151,
-STORE, 140121974214656, 140121991000063,
-STORE, 140121630310400, 140121831636991,
-SNULL, 140121697419263, 140121831636991,
-STORE, 140121630310400, 140121697419263,
-STORE, 140121697419264, 140121831636991,
-SNULL, 140121697419264, 140121764528127,
-STORE, 140121764528128, 140121831636991,
-STORE, 140121697419264, 140121764528127,
-ERASE, 140121697419264, 140121764528127,
-STORE, 140121881960448, 140121890353151,
-STORE, 140121630310400, 140121831636991,
-STORE, 140121873567744, 140121890353151,
-SNULL, 140121630310400, 140121697419263,
-STORE, 140121697419264, 140121831636991,
-STORE, 140121630310400, 140121697419263,
-SNULL, 140121697554431, 140121831636991,
-STORE, 140121697419264, 140121697554431,
-STORE, 140121697554432, 140121831636991,
-STORE, 140121865175040, 140121890353151,
-STORE, 140121856782336, 140121890353151,
-STORE, 140121848389632, 140121890353151,
-STORE, 140121839996928, 140121890353151,
-STORE, 140121496092672, 140121697419263,
-STORE, 140121487699968, 140121496092671,
-STORE, 140121420591104, 140121487699967,
-STORE, 140121412198400, 140121420591103,
-ERASE, 140121420591104, 140121487699967,
-STORE, 140121479307264, 140121496092671,
-STORE, 140121277980672, 140121412198399,
-SNULL, 140121277980672, 140121294766079,
-STORE, 140121294766080, 140121412198399,
-STORE, 140121277980672, 140121294766079,
-ERASE, 140121277980672, 140121294766079,
-STORE, 140121470914560, 140121496092671,
-STORE, 140121462521856, 140121496092671,
-STORE, 140121160548352, 140121412198399,
-STORE, 140121454129152, 140121496092671,
-SNULL, 140121227657215, 140121412198399,
-STORE, 140121160548352, 140121227657215,
-STORE, 140121227657216, 140121412198399,
-SNULL, 140121227657216, 140121294766079,
-STORE, 140121294766080, 140121412198399,
-STORE, 140121227657216, 140121294766079,
-ERASE, 140121227657216, 140121294766079,
-STORE, 140121445736448, 140121496092671,
-STORE, 140121437343744, 140121496092671,
-SNULL, 140121437343744, 140121445736447,
-STORE, 140121445736448, 140121496092671,
-STORE, 140121437343744, 140121445736447,
-SNULL, 140121445740543, 140121496092671,
-STORE, 140121445736448, 140121445740543,
-STORE, 140121445740544, 140121496092671,
-SNULL, 140121697554432, 140121764528127,
-STORE, 140121764528128, 140121831636991,
-STORE, 140121697554432, 140121764528127,
-SNULL, 140121764663295, 140121831636991,
-STORE, 140121764528128, 140121764663295,
-STORE, 140121764663296, 140121831636991,
-SNULL, 140121496092672, 140121630310399,
-STORE, 140121630310400, 140121697419263,
-STORE, 140121496092672, 140121630310399,
-SNULL, 140121630445567, 140121697419263,
-STORE, 140121630310400, 140121630445567,
-STORE, 140121630445568, 140121697419263,
-SNULL, 140121445740544, 140121454129151,
-STORE, 140121454129152, 140121496092671,
-STORE, 140121445740544, 140121454129151,
-SNULL, 140121454133247, 140121496092671,
-STORE, 140121454129152, 140121454133247,
-STORE, 140121454133248, 140121496092671,
-STORE, 140121026330624, 140121227657215,
-SNULL, 140121093439487, 140121227657215,
-STORE, 140121026330624, 140121093439487,
-STORE, 140121093439488, 140121227657215,
-SNULL, 140121093439488, 140121160548351,
-STORE, 140121160548352, 140121227657215,
-STORE, 140121093439488, 140121160548351,
-ERASE, 140121093439488, 140121160548351,
-SNULL, 140121563201535, 140121630310399,
-STORE, 140121496092672, 140121563201535,
-STORE, 140121563201536, 140121630310399,
-ERASE, 140121563201536, 140121630310399,
-STORE, 140120892112896, 140121093439487,
-SNULL, 140120959221759, 140121093439487,
-STORE, 140120892112896, 140120959221759,
-STORE, 140120959221760, 140121093439487,
-SNULL, 140120959221760, 140121026330623,
-STORE, 140121026330624, 140121093439487,
-STORE, 140120959221760, 140121026330623,
-ERASE, 140120959221760, 140121026330623,
-STORE, 140120757895168, 140120959221759,
-SNULL, 140121361874943, 140121412198399,
-STORE, 140121294766080, 140121361874943,
-STORE, 140121361874944, 140121412198399,
-ERASE, 140121361874944, 140121412198399,
-SNULL, 140121294901247, 140121361874943,
-STORE, 140121294766080, 140121294901247,
-STORE, 140121294901248, 140121361874943,
-STORE, 140120623677440, 140120959221759,
-SNULL, 140120690786303, 140120959221759,
-STORE, 140120623677440, 140120690786303,
-STORE, 140120690786304, 140120959221759,
-SNULL, 140120690786304, 140120757895167,
-STORE, 140120757895168, 140120959221759,
-STORE, 140120690786304, 140120757895167,
-ERASE, 140120690786304, 140120757895167,
-SNULL, 140121160683519, 140121227657215,
-STORE, 140121160548352, 140121160683519,
-STORE, 140121160683520, 140121227657215,
-SNULL, 140121974214656, 140121982607359,
-STORE, 140121982607360, 140121991000063,
-STORE, 140121974214656, 140121982607359,
-SNULL, 140121982611455, 140121991000063,
-STORE, 140121982607360, 140121982611455,
-STORE, 140121982611456, 140121991000063,
-SNULL, 140121839996928, 140121873567743,
-STORE, 140121873567744, 140121890353151,
-STORE, 140121839996928, 140121873567743,
-SNULL, 140121873571839, 140121890353151,
-STORE, 140121873567744, 140121873571839,
-STORE, 140121873571840, 140121890353151,
-SNULL, 140121873571840, 140121881960447,
-STORE, 140121881960448, 140121890353151,
-STORE, 140121873571840, 140121881960447,
-SNULL, 140121881964543, 140121890353151,
-STORE, 140121881960448, 140121881964543,
-STORE, 140121881964544, 140121890353151,
-SNULL, 140121840001023, 140121873567743,
-STORE, 140121839996928, 140121840001023,
-STORE, 140121840001024, 140121873567743,
-SNULL, 140121840001024, 140121865175039,
-STORE, 140121865175040, 140121873567743,
-STORE, 140121840001024, 140121865175039,
-SNULL, 140121865179135, 140121873567743,
-STORE, 140121865175040, 140121865179135,
-STORE, 140121865179136, 140121873567743,
-SNULL, 140121437347839, 140121445736447,
-STORE, 140121437343744, 140121437347839,
-STORE, 140121437347840, 140121445736447,
-STORE, 140121621917696, 140121630310399,
-STORE, 140121613524992, 140121630310399,
-SNULL, 140121026465791, 140121093439487,
-STORE, 140121026330624, 140121026465791,
-STORE, 140121026465792, 140121093439487,
-SNULL, 140121496227839, 140121563201535,
-STORE, 140121496092672, 140121496227839,
-STORE, 140121496227840, 140121563201535,
-SNULL, 140120757895168, 140120892112895,
-STORE, 140120892112896, 140120959221759,
-STORE, 140120757895168, 140120892112895,
-SNULL, 140120892248063, 140120959221759,
-STORE, 140120892112896, 140120892248063,
-STORE, 140120892248064, 140120959221759,
-SNULL, 140120825004031, 140120892112895,
-STORE, 140120757895168, 140120825004031,
-STORE, 140120825004032, 140120892112895,
-ERASE, 140120825004032, 140120892112895,
-SNULL, 140120623812607, 140120690786303,
-STORE, 140120623677440, 140120623812607,
-STORE, 140120623812608, 140120690786303,
-SNULL, 140120758030335, 140120825004031,
-STORE, 140120757895168, 140120758030335,
-STORE, 140120758030336, 140120825004031,
-SNULL, 140121454133248, 140121462521855,
-STORE, 140121462521856, 140121496092671,
-STORE, 140121454133248, 140121462521855,
-SNULL, 140121462525951, 140121496092671,
-STORE, 140121462521856, 140121462525951,
-STORE, 140121462525952, 140121496092671,
-STORE, 140121605132288, 140121630310399,
-SNULL, 140121605136383, 140121630310399,
-STORE, 140121605132288, 140121605136383,
-STORE, 140121605136384, 140121630310399,
-STORE, 140121596739584, 140121605132287,
-SNULL, 140121605136384, 140121621917695,
-STORE, 140121621917696, 140121630310399,
-STORE, 140121605136384, 140121621917695,
-SNULL, 140121621921791, 140121630310399,
-STORE, 140121621917696, 140121621921791,
-STORE, 140121621921792, 140121630310399,
-STORE, 140121588346880, 140121605132287,
-STORE, 140121579954176, 140121605132287,
-SNULL, 140121412202495, 140121420591103,
-STORE, 140121412198400, 140121412202495,
-STORE, 140121412202496, 140121420591103,
-SNULL, 140121974218751, 140121982607359,
-STORE, 140121974214656, 140121974218751,
-STORE, 140121974218752, 140121982607359,
-SNULL, 140121462525952, 140121479307263,
-STORE, 140121479307264, 140121496092671,
-STORE, 140121462525952, 140121479307263,
-SNULL, 140121479311359, 140121496092671,
-STORE, 140121479307264, 140121479311359,
-STORE, 140121479311360, 140121496092671,
-STORE, 140121571561472, 140121605132287,
-SNULL, 140121571565567, 140121605132287,
-STORE, 140121571561472, 140121571565567,
-STORE, 140121571565568, 140121605132287,
-STORE, 140121428951040, 140121437343743,
-SNULL, 140121428955135, 140121437343743,
-STORE, 140121428951040, 140121428955135,
-STORE, 140121428955136, 140121437343743,
-SNULL, 140121840001024, 140121856782335,
-STORE, 140121856782336, 140121865175039,
-STORE, 140121840001024, 140121856782335,
-SNULL, 140121856786431, 140121865175039,
-STORE, 140121856782336, 140121856786431,
-STORE, 140121856786432, 140121865175039,
-STORE, 140121403805696, 140121412198399,
-SNULL, 140121840001024, 140121848389631,
-STORE, 140121848389632, 140121856782335,
-STORE, 140121840001024, 140121848389631,
-SNULL, 140121848393727, 140121856782335,
-STORE, 140121848389632, 140121848393727,
-STORE, 140121848393728, 140121856782335,
-SNULL, 140121479311360, 140121487699967,
-STORE, 140121487699968, 140121496092671,
-STORE, 140121479311360, 140121487699967,
-SNULL, 140121487704063, 140121496092671,
-STORE, 140121487699968, 140121487704063,
-STORE, 140121487704064, 140121496092671,
-STORE, 140121395412992, 140121412198399,
-STORE, 140121387020288, 140121412198399,
-SNULL, 140121387024383, 140121412198399,
-STORE, 140121387020288, 140121387024383,
-STORE, 140121387024384, 140121412198399,
-SNULL, 140121605136384, 140121613524991,
-STORE, 140121613524992, 140121621917695,
-STORE, 140121605136384, 140121613524991,
-SNULL, 140121613529087, 140121621917695,
-STORE, 140121613524992, 140121613529087,
-STORE, 140121613529088, 140121621917695,
-SNULL, 140121462525952, 140121470914559,
-STORE, 140121470914560, 140121479307263,
-STORE, 140121462525952, 140121470914559,
-SNULL, 140121470918655, 140121479307263,
-STORE, 140121470914560, 140121470918655,
-STORE, 140121470918656, 140121479307263,
-STORE, 140121378627584, 140121387020287,
-SNULL, 140121378631679, 140121387020287,
-STORE, 140121378627584, 140121378631679,
-STORE, 140121378631680, 140121387020287,
-SNULL, 140121571565568, 140121596739583,
-STORE, 140121596739584, 140121605132287,
-STORE, 140121571565568, 140121596739583,
-SNULL, 140121596743679, 140121605132287,
-STORE, 140121596739584, 140121596743679,
-STORE, 140121596743680, 140121605132287,
-SNULL, 140121387024384, 140121403805695,
-STORE, 140121403805696, 140121412198399,
-STORE, 140121387024384, 140121403805695,
-SNULL, 140121403809791, 140121412198399,
-STORE, 140121403805696, 140121403809791,
-STORE, 140121403809792, 140121412198399,
-STORE, 140121370234880, 140121378627583,
-SNULL, 140121387024384, 140121395412991,
-STORE, 140121395412992, 140121403805695,
-STORE, 140121387024384, 140121395412991,
-SNULL, 140121395417087, 140121403805695,
-STORE, 140121395412992, 140121395417087,
-STORE, 140121395417088, 140121403805695,
-SNULL, 140121571565568, 140121588346879,
-STORE, 140121588346880, 140121596739583,
-STORE, 140121571565568, 140121588346879,
-SNULL, 140121588350975, 140121596739583,
-STORE, 140121588346880, 140121588350975,
-STORE, 140121588350976, 140121596739583,
-SNULL, 140121571565568, 140121579954175,
-STORE, 140121579954176, 140121588346879,
-STORE, 140121571565568, 140121579954175,
-SNULL, 140121579958271, 140121588346879,
-STORE, 140121579954176, 140121579958271,
-STORE, 140121579958272, 140121588346879,
-STORE, 140121286373376, 140121294766079,
-STORE, 140121277980672, 140121294766079,
-SNULL, 140121277980672, 140121286373375,
-STORE, 140121286373376, 140121294766079,
-STORE, 140121277980672, 140121286373375,
-SNULL, 140121286377471, 140121294766079,
-STORE, 140121286373376, 140121286377471,
-STORE, 140121286377472, 140121294766079,
-STORE, 140121269587968, 140121286373375,
-STORE, 140121261195264, 140121286373375,
-SNULL, 140121261195264, 140121269587967,
-STORE, 140121269587968, 140121286373375,
-STORE, 140121261195264, 140121269587967,
-SNULL, 140121269592063, 140121286373375,
-STORE, 140121269587968, 140121269592063,
-STORE, 140121269592064, 140121286373375,
-STORE, 140121252802560, 140121269587967,
-SNULL, 140121252806655, 140121269587967,
-STORE, 140121252802560, 140121252806655,
-STORE, 140121252806656, 140121269587967,
-STORE, 140121244409856, 140121252802559,
-STORE, 140121236017152, 140121252802559,
-SNULL, 140121236017152, 140121244409855,
-STORE, 140121244409856, 140121252802559,
-STORE, 140121236017152, 140121244409855,
-SNULL, 140121244413951, 140121252802559,
-STORE, 140121244409856, 140121244413951,
-STORE, 140121244413952, 140121252802559,
-SNULL, 140121370238975, 140121378627583,
-STORE, 140121370234880, 140121370238975,
-STORE, 140121370238976, 140121378627583,
-STORE, 140121152155648, 140121160548351,
-STORE, 140121143762944, 140121160548351,
-STORE, 140121135370240, 140121160548351,
-SNULL, 140121135374335, 140121160548351,
-STORE, 140121135370240, 140121135374335,
-STORE, 140121135374336, 140121160548351,
-STORE, 140121126977536, 140121135370239,
-STORE, 140121118584832, 140121135370239,
-STORE, 140121110192128, 140121135370239,
-SNULL, 140121110192128, 140121118584831,
-STORE, 140121118584832, 140121135370239,
-STORE, 140121110192128, 140121118584831,
-SNULL, 140121118588927, 140121135370239,
-STORE, 140121118584832, 140121118588927,
-STORE, 140121118588928, 140121135370239,
-STORE, 140121101799424, 140121118584831,
-STORE, 140121017937920, 140121026330623,
-STORE, 140121009545216, 140121026330623,
-SNULL, 140121009545216, 140121017937919,
-STORE, 140121017937920, 140121026330623,
-STORE, 140121009545216, 140121017937919,
-SNULL, 140121017942015, 140121026330623,
-STORE, 140121017937920, 140121017942015,
-STORE, 140121017942016, 140121026330623,
-SNULL, 140121269592064, 140121277980671,
-STORE, 140121277980672, 140121286373375,
-STORE, 140121269592064, 140121277980671,
-SNULL, 140121277984767, 140121286373375,
-STORE, 140121277980672, 140121277984767,
-STORE, 140121277984768, 140121286373375,
-STORE, 140121001152512, 140121017937919,
-SNULL, 140121252806656, 140121261195263,
-STORE, 140121261195264, 140121269587967,
-STORE, 140121252806656, 140121261195263,
-SNULL, 140121261199359, 140121269587967,
-STORE, 140121261195264, 140121261199359,
-STORE, 140121261199360, 140121269587967,
-SNULL, 140121135374336, 140121152155647,
-STORE, 140121152155648, 140121160548351,
-STORE, 140121135374336, 140121152155647,
-SNULL, 140121152159743, 140121160548351,
-STORE, 140121152155648, 140121152159743,
-STORE, 140121152159744, 140121160548351,
-STORE, 140120992759808, 140121017937919,
-STORE, 140120984367104, 140121017937919,
-STORE, 140120975974400, 140121017937919,
-SNULL, 140121101799424, 140121110192127,
-STORE, 140121110192128, 140121118584831,
-STORE, 140121101799424, 140121110192127,
-SNULL, 140121110196223, 140121118584831,
-STORE, 140121110192128, 140121110196223,
-STORE, 140121110196224, 140121118584831,
-SNULL, 140121118588928, 140121126977535,
-STORE, 140121126977536, 140121135370239,
-STORE, 140121118588928, 140121126977535,
-SNULL, 140121126981631, 140121135370239,
-STORE, 140121126977536, 140121126981631,
-STORE, 140121126981632, 140121135370239,
-STORE, 140120967581696, 140121017937919,
-STORE, 140120883720192, 140120892112895,
-SNULL, 140120883724287, 140120892112895,
-STORE, 140120883720192, 140120883724287,
-STORE, 140120883724288, 140120892112895,
-STORE, 140120875327488, 140120883720191,
-SNULL, 140121101803519, 140121110192127,
-STORE, 140121101799424, 140121101803519,
-STORE, 140121101803520, 140121110192127,
-SNULL, 140121135374336, 140121143762943,
-STORE, 140121143762944, 140121152155647,
-STORE, 140121135374336, 140121143762943,
-SNULL, 140121143767039, 140121152155647,
-STORE, 140121143762944, 140121143767039,
-STORE, 140121143767040, 140121152155647,
-STORE, 140120866934784, 140120883720191,
-SNULL, 140120967581696, 140120984367103,
-STORE, 140120984367104, 140121017937919,
-STORE, 140120967581696, 140120984367103,
-SNULL, 140120984371199, 140121017937919,
-STORE, 140120984367104, 140120984371199,
-STORE, 140120984371200, 140121017937919,
-STORE, 140120858542080, 140120883720191,
-SNULL, 140121236021247, 140121244409855,
-STORE, 140121236017152, 140121236021247,
-STORE, 140121236021248, 140121244409855,
-SNULL, 140120984371200, 140121009545215,
-STORE, 140121009545216, 140121017937919,
-STORE, 140120984371200, 140121009545215,
-SNULL, 140121009549311, 140121017937919,
-STORE, 140121009545216, 140121009549311,
-STORE, 140121009549312, 140121017937919,
-SNULL, 140120984371200, 140120992759807,
-STORE, 140120992759808, 140121009545215,
-STORE, 140120984371200, 140120992759807,
-SNULL, 140120992763903, 140121009545215,
-STORE, 140120992759808, 140120992763903,
-STORE, 140120992763904, 140121009545215,
-SNULL, 140120992763904, 140121001152511,
-STORE, 140121001152512, 140121009545215,
-STORE, 140120992763904, 140121001152511,
-SNULL, 140121001156607, 140121009545215,
-STORE, 140121001152512, 140121001156607,
-STORE, 140121001156608, 140121009545215,
-STORE, 140120850149376, 140120883720191,
-SNULL, 140120850153471, 140120883720191,
-STORE, 140120850149376, 140120850153471,
-STORE, 140120850153472, 140120883720191,
-SNULL, 140120967585791, 140120984367103,
-STORE, 140120967581696, 140120967585791,
-STORE, 140120967585792, 140120984367103,
-SNULL, 140120850153472, 140120866934783,
-STORE, 140120866934784, 140120883720191,
-STORE, 140120850153472, 140120866934783,
-SNULL, 140120866938879, 140120883720191,
-STORE, 140120866934784, 140120866938879,
-STORE, 140120866938880, 140120883720191,
-STORE, 140120841756672, 140120850149375,
-SNULL, 140120967585792, 140120975974399,
-STORE, 140120975974400, 140120984367103,
-STORE, 140120967585792, 140120975974399,
-SNULL, 140120975978495, 140120984367103,
-STORE, 140120975974400, 140120975978495,
-STORE, 140120975978496, 140120984367103,
-SNULL, 140120866938880, 140120875327487,
-STORE, 140120875327488, 140120883720191,
-STORE, 140120866938880, 140120875327487,
-SNULL, 140120875331583, 140120883720191,
-STORE, 140120875327488, 140120875331583,
-STORE, 140120875331584, 140120883720191,
-STORE, 140120833363968, 140120850149375,
-STORE, 140120749502464, 140120757895167,
-STORE, 140120741109760, 140120757895167,
-STORE, 140120732717056, 140120757895167,
-STORE, 140120724324352, 140120757895167,
-SNULL, 140120724324352, 140120732717055,
-STORE, 140120732717056, 140120757895167,
-STORE, 140120724324352, 140120732717055,
-SNULL, 140120732721151, 140120757895167,
-STORE, 140120732717056, 140120732721151,
-STORE, 140120732721152, 140120757895167,
-STORE, 140120715931648, 140120732717055,
-SNULL, 140120715935743, 140120732717055,
-STORE, 140120715931648, 140120715935743,
-STORE, 140120715935744, 140120732717055,
-SNULL, 140120850153472, 140120858542079,
-STORE, 140120858542080, 140120866934783,
-STORE, 140120850153472, 140120858542079,
-SNULL, 140120858546175, 140120866934783,
-STORE, 140120858542080, 140120858546175,
-STORE, 140120858546176, 140120866934783,
-STORE, 140120707538944, 140120715931647,
-SNULL, 140120707543039, 140120715931647,
-STORE, 140120707538944, 140120707543039,
-STORE, 140120707543040, 140120715931647,
-SNULL, 140120833368063, 140120850149375,
-STORE, 140120833363968, 140120833368063,
-STORE, 140120833368064, 140120850149375,
-SNULL, 140120833368064, 140120841756671,
-STORE, 140120841756672, 140120850149375,
-STORE, 140120833368064, 140120841756671,
-SNULL, 140120841760767, 140120850149375,
-STORE, 140120841756672, 140120841760767,
-STORE, 140120841760768, 140120850149375,
-STORE, 140120699146240, 140120707538943,
-SNULL, 140120715935744, 140120724324351,
-STORE, 140120724324352, 140120732717055,
-STORE, 140120715935744, 140120724324351,
-SNULL, 140120724328447, 140120732717055,
-STORE, 140120724324352, 140120724328447,
-STORE, 140120724328448, 140120732717055,
-SNULL, 140120732721152, 140120741109759,
-STORE, 140120741109760, 140120757895167,
-STORE, 140120732721152, 140120741109759,
-SNULL, 140120741113855, 140120757895167,
-STORE, 140120741109760, 140120741113855,
-STORE, 140120741113856, 140120757895167,
-SNULL, 140120741113856, 140120749502463,
-STORE, 140120749502464, 140120757895167,
-STORE, 140120741113856, 140120749502463,
-SNULL, 140120749506559, 140120757895167,
-STORE, 140120749502464, 140120749506559,
-STORE, 140120749506560, 140120757895167,
-SNULL, 140120699150335, 140120707538943,
-STORE, 140120699146240, 140120699150335,
-STORE, 140120699150336, 140120707538943,
-STORE, 140122446557184, 140122446585855,
-STORE, 140122368999424, 140122371190783,
-SNULL, 140122368999424, 140122369089535,
-STORE, 140122369089536, 140122371190783,
-STORE, 140122368999424, 140122369089535,
-SNULL, 140122371182591, 140122371190783,
-STORE, 140122369089536, 140122371182591,
-STORE, 140122371182592, 140122371190783,
-ERASE, 140122371182592, 140122371190783,
-STORE, 140122371182592, 140122371190783,
-SNULL, 140122371186687, 140122371190783,
-STORE, 140122371182592, 140122371186687,
-STORE, 140122371186688, 140122371190783,
-ERASE, 140122446557184, 140122446585855,
-ERASE, 140121445736448, 140121445740543,
-ERASE, 140121445740544, 140121454129151,
-ERASE, 140121621917696, 140121621921791,
-ERASE, 140121621921792, 140121630310399,
-ERASE, 140121579954176, 140121579958271,
-ERASE, 140121579958272, 140121588346879,
-ERASE, 140121261195264, 140121261199359,
-ERASE, 140121261199360, 140121269587967,
-ERASE, 140121454129152, 140121454133247,
-ERASE, 140121454133248, 140121462521855,
-ERASE, 140121588346880, 140121588350975,
-ERASE, 140121588350976, 140121596739583,
-ERASE, 140121135370240, 140121135374335,
-ERASE, 140121135374336, 140121143762943,
-ERASE, 140121881960448, 140121881964543,
-ERASE, 140121881964544, 140121890353151,
-ERASE, 140121428951040, 140121428955135,
-ERASE, 140121428955136, 140121437343743,
-ERASE, 140121387020288, 140121387024383,
-ERASE, 140121387024384, 140121395412991,
-ERASE, 140121487699968, 140121487704063,
-ERASE, 140121487704064, 140121496092671,
-ERASE, 140121437343744, 140121437347839,
-ERASE, 140121437347840, 140121445736447,
-ERASE, 140121613524992, 140121613529087,
-ERASE, 140121613529088, 140121621917695,
-ERASE, 140121856782336, 140121856786431,
-ERASE, 140121856786432, 140121865175039,
-ERASE, 140121252802560, 140121252806655,
-ERASE, 140121252806656, 140121261195263,
-ERASE, 140121839996928, 140121840001023,
-ERASE, 140121840001024, 140121848389631,
-ERASE, 140121596739584, 140121596743679,
-ERASE, 140121596743680, 140121605132287,
-ERASE, 140121009545216, 140121009549311,
-ERASE, 140121009549312, 140121017937919,
-ERASE, 140120724324352, 140120724328447,
-ERASE, 140120724328448, 140120732717055,
-ERASE, 140120883720192, 140120883724287,
-ERASE, 140120883724288, 140120892112895,
-ERASE, 140121982607360, 140121982611455,
-ERASE, 140121982611456, 140121991000063,
-ERASE, 140121571561472, 140121571565567,
-ERASE, 140121571565568, 140121579954175,
-ERASE, 140121286373376, 140121286377471,
-ERASE, 140121286377472, 140121294766079,
-ERASE, 140120875327488, 140120875331583,
-ERASE, 140120875331584, 140120883720191,
-ERASE, 140121848389632, 140121848393727,
-ERASE, 140121848393728, 140121856782335,
-ERASE, 140121370234880, 140121370238975,
-ERASE, 140121370238976, 140121378627583,
-ERASE, 140121143762944, 140121143767039,
-ERASE, 140121143767040, 140121152155647,
-ERASE, 140121118584832, 140121118588927,
-ERASE, 140121118588928, 140121126977535,
-ERASE, 140120866934784, 140120866938879,
-ERASE, 140120866938880, 140120875327487,
-ERASE, 140120741109760, 140120741113855,
-ERASE, 140120741113856, 140120749502463,
-ERASE, 140121865175040, 140121865179135,
-ERASE, 140121865179136, 140121873567743,
-ERASE, 140121403805696, 140121403809791,
-ERASE, 140121403809792, 140121412198399,
-ERASE, 140121236017152, 140121236021247,
-ERASE, 140121236021248, 140121244409855,
-ERASE, 140120732717056, 140120732721151,
-ERASE, 140120732721152, 140120741109759,
-ERASE, 140121017937920, 140121017942015,
-ERASE, 140121017942016, 140121026330623,
-ERASE, 140121873567744, 140121873571839,
-ERASE, 140121873571840, 140121881960447,
-ERASE, 140121470914560, 140121470918655,
-ERASE, 140121470918656, 140121479307263,
-ERASE, 140121126977536, 140121126981631,
-ERASE, 140121126981632, 140121135370239,
-ERASE, 140120850149376, 140120850153471,
-ERASE, 140120850153472, 140120858542079,
-ERASE, 140120707538944, 140120707543039,
-ERASE, 140120707543040, 140120715931647,
-ERASE, 140121479307264, 140121479311359,
-ERASE, 140121479311360, 140121487699967,
-ERASE, 140120967581696, 140120967585791,
-ERASE, 140120967585792, 140120975974399,
-ERASE, 140120841756672, 140120841760767,
-ERASE, 140120841760768, 140120850149375,
-ERASE, 140121412198400, 140121412202495,
-ERASE, 140121412202496, 140121420591103,
-ERASE, 140122158788608, 140122158792703,
-ERASE, 140122158792704, 140122167181311,
-ERASE, 140122142003200, 140122142007295,
-ERASE, 140122142007296, 140122150395903,
-ERASE, 140121101799424, 140121101803519,
-ERASE, 140121101803520, 140121110192127,
-ERASE, 140120858542080, 140120858546175,
-ERASE, 140120858546176, 140120866934783,
-ERASE, 140120833363968, 140120833368063,
-ERASE, 140120833368064, 140120841756671,
-ERASE, 140121277980672, 140121277984767,
-ERASE, 140121277984768, 140121286373375,
-ERASE, 140121001152512, 140121001156607,
-ERASE, 140121001156608, 140121009545215,
-ERASE, 140120749502464, 140120749506559,
-ERASE, 140120749506560, 140120757895167,
-ERASE, 140121605132288, 140121605136383,
-ERASE, 140121605136384, 140121613524991,
-ERASE, 140121378627584, 140121378631679,
-ERASE, 140121378631680, 140121387020287,
-ERASE, 140121110192128, 140121110196223,
-ERASE, 140121110196224, 140121118584831,
-ERASE, 140121462521856, 140121462525951,
-ERASE, 140121462525952, 140121470914559,
-ERASE, 140121395412992, 140121395417087,
-ERASE, 140121395417088, 140121403805695,
-ERASE, 140121152155648, 140121152159743,
-ERASE, 140121152159744, 140121160548351,
-ERASE, 140120992759808, 140120992763903,
-ERASE, 140120992763904, 140121001152511,
-ERASE, 140122387976192, 140122387980287,
-ERASE, 140122387980288, 140122396368895,
-ERASE, 140121890353152, 140121890357247,
-ERASE, 140121890357248, 140121898745855,
-ERASE, 140121269587968, 140121269592063,
-ERASE, 140121269592064, 140121277980671,
- };
- unsigned long set37[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140722404016128, 140737488351231,
-SNULL, 140722404020223, 140737488351231,
-STORE, 140722404016128, 140722404020223,
-STORE, 140722403885056, 140722404020223,
-STORE, 94637010001920, 94637012254719,
-SNULL, 94637010132991, 94637012254719,
-STORE, 94637010001920, 94637010132991,
-STORE, 94637010132992, 94637012254719,
-ERASE, 94637010132992, 94637012254719,
-STORE, 94637012226048, 94637012234239,
-STORE, 94637012234240, 94637012254719,
-STORE, 139760240594944, 139760242847743,
-SNULL, 139760240738303, 139760242847743,
-STORE, 139760240594944, 139760240738303,
-STORE, 139760240738304, 139760242847743,
-ERASE, 139760240738304, 139760242847743,
-STORE, 139760242835456, 139760242843647,
-STORE, 139760242843648, 139760242847743,
-STORE, 140722405232640, 140722405236735,
-STORE, 140722405220352, 140722405232639,
-STORE, 139760242806784, 139760242835455,
-STORE, 139760242798592, 139760242806783,
-STORE, 139760238379008, 139760240594943,
-SNULL, 139760238379008, 139760238477311,
-STORE, 139760238477312, 139760240594943,
-STORE, 139760238379008, 139760238477311,
-SNULL, 139760240570367, 139760240594943,
-STORE, 139760238477312, 139760240570367,
-STORE, 139760240570368, 139760240594943,
-SNULL, 139760240570368, 139760240578559,
-STORE, 139760240578560, 139760240594943,
-STORE, 139760240570368, 139760240578559,
-ERASE, 139760240570368, 139760240578559,
-STORE, 139760240570368, 139760240578559,
-ERASE, 139760240578560, 139760240594943,
-STORE, 139760240578560, 139760240594943,
-STORE, 139760234582016, 139760238379007,
-SNULL, 139760234582016, 139760236240895,
-STORE, 139760236240896, 139760238379007,
-STORE, 139760234582016, 139760236240895,
-SNULL, 139760238338047, 139760238379007,
-STORE, 139760236240896, 139760238338047,
-STORE, 139760238338048, 139760238379007,
-SNULL, 139760238338048, 139760238362623,
-STORE, 139760238362624, 139760238379007,
-STORE, 139760238338048, 139760238362623,
-ERASE, 139760238338048, 139760238362623,
-STORE, 139760238338048, 139760238362623,
-ERASE, 139760238362624, 139760238379007,
-STORE, 139760238362624, 139760238379007,
-STORE, 139760242790400, 139760242806783,
-SNULL, 139760238354431, 139760238362623,
-STORE, 139760238338048, 139760238354431,
-STORE, 139760238354432, 139760238362623,
-SNULL, 139760240574463, 139760240578559,
-STORE, 139760240570368, 139760240574463,
-STORE, 139760240574464, 139760240578559,
-SNULL, 94637012230143, 94637012234239,
-STORE, 94637012226048, 94637012230143,
-STORE, 94637012230144, 94637012234239,
-SNULL, 139760242839551, 139760242843647,
-STORE, 139760242835456, 139760242839551,
-STORE, 139760242839552, 139760242843647,
-ERASE, 139760242806784, 139760242835455,
-STORE, 94637033324544, 94637033459711,
-STORE, 139760226189312, 139760234582015,
-SNULL, 139760226193407, 139760234582015,
-STORE, 139760226189312, 139760226193407,
-STORE, 139760226193408, 139760234582015,
-STORE, 139760217796608, 139760226189311,
-STORE, 139760083578880, 139760217796607,
-SNULL, 139760083578880, 139760114860031,
-STORE, 139760114860032, 139760217796607,
-STORE, 139760083578880, 139760114860031,
-ERASE, 139760083578880, 139760114860031,
-SNULL, 139760181968895, 139760217796607,
-STORE, 139760114860032, 139760181968895,
-STORE, 139760181968896, 139760217796607,
-ERASE, 139760181968896, 139760217796607,
-SNULL, 139760114995199, 139760181968895,
-STORE, 139760114860032, 139760114995199,
-STORE, 139760114995200, 139760181968895,
-SNULL, 139760217800703, 139760226189311,
-STORE, 139760217796608, 139760217800703,
-STORE, 139760217800704, 139760226189311,
-STORE, 139760209403904, 139760217796607,
-SNULL, 139760209407999, 139760217796607,
-STORE, 139760209403904, 139760209407999,
-STORE, 139760209408000, 139760217796607,
-STORE, 139760201011200, 139760209403903,
-SNULL, 139760201015295, 139760209403903,
-STORE, 139760201011200, 139760201015295,
-STORE, 139760201015296, 139760209403903,
-STORE, 139760192618496, 139760201011199,
-SNULL, 139760192622591, 139760201011199,
-STORE, 139760192618496, 139760192622591,
-STORE, 139760192622592, 139760201011199,
-STORE, 139760184225792, 139760192618495,
-STORE, 139759980642304, 139760114860031,
-STORE, 139759972249600, 139759980642303,
-STORE, 139759963856896, 139759980642303,
-STORE, 139759955464192, 139759980642303,
-STORE, 139759888355328, 139759955464191,
-SNULL, 139760047751167, 139760114860031,
-STORE, 139759980642304, 139760047751167,
-STORE, 139760047751168, 139760114860031,
-ERASE, 139760047751168, 139760114860031,
-SNULL, 139759980777471, 139760047751167,
-STORE, 139759980642304, 139759980777471,
-STORE, 139759980777472, 139760047751167,
-STORE, 139759980777472, 139760114860031,
-SNULL, 139759980777472, 139760047751167,
-STORE, 139760047751168, 139760114860031,
-STORE, 139759980777472, 139760047751167,
-SNULL, 139760047886335, 139760114860031,
-STORE, 139760047751168, 139760047886335,
-STORE, 139760047886336, 139760114860031,
-STORE, 139759821246464, 139759955464191,
-SNULL, 139759821246464, 139759888355327,
-STORE, 139759888355328, 139759955464191,
-STORE, 139759821246464, 139759888355327,
-ERASE, 139759821246464, 139759888355327,
-ERASE, 139759888355328, 139759955464191,
- };
- unsigned long set38[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140730666221568, 140737488351231,
-SNULL, 140730666225663, 140737488351231,
-STORE, 140730666221568, 140730666225663,
-STORE, 140730666090496, 140730666225663,
-STORE, 94177584803840, 94177587056639,
-SNULL, 94177584934911, 94177587056639,
-STORE, 94177584803840, 94177584934911,
-STORE, 94177584934912, 94177587056639,
-ERASE, 94177584934912, 94177587056639,
-STORE, 94177587027968, 94177587036159,
-STORE, 94177587036160, 94177587056639,
-STORE, 140614382714880, 140614384967679,
-SNULL, 140614382858239, 140614384967679,
-STORE, 140614382714880, 140614382858239,
-STORE, 140614382858240, 140614384967679,
-ERASE, 140614382858240, 140614384967679,
-STORE, 140614384955392, 140614384963583,
-STORE, 140614384963584, 140614384967679,
-STORE, 140730666315776, 140730666319871,
-STORE, 140730666303488, 140730666315775,
-STORE, 140614384926720, 140614384955391,
-STORE, 140614384918528, 140614384926719,
-STORE, 140614380498944, 140614382714879,
-SNULL, 140614380498944, 140614380597247,
-STORE, 140614380597248, 140614382714879,
-STORE, 140614380498944, 140614380597247,
-SNULL, 140614382690303, 140614382714879,
-STORE, 140614380597248, 140614382690303,
-STORE, 140614382690304, 140614382714879,
-SNULL, 140614382690304, 140614382698495,
-STORE, 140614382698496, 140614382714879,
-STORE, 140614382690304, 140614382698495,
-ERASE, 140614382690304, 140614382698495,
-STORE, 140614382690304, 140614382698495,
-ERASE, 140614382698496, 140614382714879,
-STORE, 140614382698496, 140614382714879,
-STORE, 140614376701952, 140614380498943,
-SNULL, 140614376701952, 140614378360831,
-STORE, 140614378360832, 140614380498943,
-STORE, 140614376701952, 140614378360831,
-SNULL, 140614380457983, 140614380498943,
-STORE, 140614378360832, 140614380457983,
-STORE, 140614380457984, 140614380498943,
-SNULL, 140614380457984, 140614380482559,
-STORE, 140614380482560, 140614380498943,
-STORE, 140614380457984, 140614380482559,
-ERASE, 140614380457984, 140614380482559,
-STORE, 140614380457984, 140614380482559,
-ERASE, 140614380482560, 140614380498943,
-STORE, 140614380482560, 140614380498943,
-STORE, 140614384910336, 140614384926719,
-SNULL, 140614380474367, 140614380482559,
-STORE, 140614380457984, 140614380474367,
-STORE, 140614380474368, 140614380482559,
-SNULL, 140614382694399, 140614382698495,
-STORE, 140614382690304, 140614382694399,
-STORE, 140614382694400, 140614382698495,
-SNULL, 94177587032063, 94177587036159,
-STORE, 94177587027968, 94177587032063,
-STORE, 94177587032064, 94177587036159,
-SNULL, 140614384959487, 140614384963583,
-STORE, 140614384955392, 140614384959487,
-STORE, 140614384959488, 140614384963583,
-ERASE, 140614384926720, 140614384955391,
-STORE, 94177619791872, 94177619927039,
-STORE, 140614368309248, 140614376701951,
-SNULL, 140614368313343, 140614376701951,
-STORE, 140614368309248, 140614368313343,
-STORE, 140614368313344, 140614376701951,
-STORE, 140614359916544, 140614368309247,
-STORE, 140614225698816, 140614359916543,
-SNULL, 140614225698816, 140614276481023,
-STORE, 140614276481024, 140614359916543,
-STORE, 140614225698816, 140614276481023,
-ERASE, 140614225698816, 140614276481023,
-SNULL, 140614343589887, 140614359916543,
-STORE, 140614276481024, 140614343589887,
-STORE, 140614343589888, 140614359916543,
-ERASE, 140614343589888, 140614359916543,
-SNULL, 140614276616191, 140614343589887,
-STORE, 140614276481024, 140614276616191,
-STORE, 140614276616192, 140614343589887,
-SNULL, 140614359920639, 140614368309247,
-STORE, 140614359916544, 140614359920639,
-STORE, 140614359920640, 140614368309247,
-STORE, 140614351523840, 140614359916543,
-SNULL, 140614351527935, 140614359916543,
-STORE, 140614351523840, 140614351527935,
-STORE, 140614351527936, 140614359916543,
-STORE, 140614268088320, 140614276481023,
-SNULL, 140614268092415, 140614276481023,
-STORE, 140614268088320, 140614268092415,
-STORE, 140614268092416, 140614276481023,
-STORE, 140614259695616, 140614268088319,
-SNULL, 140614259699711, 140614268088319,
-STORE, 140614259695616, 140614259699711,
-STORE, 140614259699712, 140614268088319,
-STORE, 140614251302912, 140614259695615,
-STORE, 140614242910208, 140614259695615,
-STORE, 140614108692480, 140614242910207,
-SNULL, 140614108692480, 140614142263295,
-STORE, 140614142263296, 140614242910207,
-STORE, 140614108692480, 140614142263295,
-ERASE, 140614108692480, 140614142263295,
-STORE, 140614133870592, 140614142263295,
-STORE, 140613999652864, 140614133870591,
-SNULL, 140613999652864, 140614008045567,
-STORE, 140614008045568, 140614133870591,
-STORE, 140613999652864, 140614008045567,
-ERASE, 140613999652864, 140614008045567,
-STORE, 140613999652864, 140614008045567,
-STORE, 140613865435136, 140613999652863,
-SNULL, 140613865435136, 140613873827839,
-STORE, 140613873827840, 140613999652863,
-STORE, 140613865435136, 140613873827839,
-ERASE, 140613865435136, 140613873827839,
-SNULL, 140614209372159, 140614242910207,
-STORE, 140614142263296, 140614209372159,
-STORE, 140614209372160, 140614242910207,
-ERASE, 140614209372160, 140614242910207,
-SNULL, 140614142398463, 140614209372159,
-STORE, 140614142263296, 140614142398463,
-STORE, 140614142398464, 140614209372159,
-SNULL, 140614075154431, 140614133870591,
-STORE, 140614008045568, 140614075154431,
-STORE, 140614075154432, 140614133870591,
-ERASE, 140614075154432, 140614133870591,
-SNULL, 140614008180735, 140614075154431,
-STORE, 140614008045568, 140614008180735,
-STORE, 140614008180736, 140614075154431,
-SNULL, 140613940936703, 140613999652863,
-STORE, 140613873827840, 140613940936703,
-STORE, 140613940936704, 140613999652863,
-ERASE, 140613940936704, 140613999652863,
-SNULL, 140614242914303, 140614259695615,
-STORE, 140614242910208, 140614242914303,
-STORE, 140614242914304, 140614259695615,
-STORE, 140613739610112, 140613940936703,
-STORE, 140614234517504, 140614242910207,
-SNULL, 140614242914304, 140614251302911,
-STORE, 140614251302912, 140614259695615,
-STORE, 140614242914304, 140614251302911,
-SNULL, 140614251307007, 140614259695615,
-STORE, 140614251302912, 140614251307007,
-STORE, 140614251307008, 140614259695615,
-SNULL, 140613739610112, 140613873827839,
-STORE, 140613873827840, 140613940936703,
-STORE, 140613739610112, 140613873827839,
-SNULL, 140613873963007, 140613940936703,
-STORE, 140613873827840, 140613873963007,
-STORE, 140613873963008, 140613940936703,
-SNULL, 140614133874687, 140614142263295,
-STORE, 140614133870592, 140614133874687,
-STORE, 140614133874688, 140614142263295,
-SNULL, 140613806718975, 140613873827839,
-STORE, 140613739610112, 140613806718975,
-STORE, 140613806718976, 140613873827839,
-ERASE, 140613806718976, 140613873827839,
-STORE, 140614226124800, 140614242910207,
-SNULL, 140613739745279, 140613806718975,
-STORE, 140613739610112, 140613739745279,
-STORE, 140613739745280, 140613806718975,
-SNULL, 140613999656959, 140614008045567,
-STORE, 140613999652864, 140613999656959,
-STORE, 140613999656960, 140614008045567,
-SNULL, 140614226124800, 140614234517503,
-STORE, 140614234517504, 140614242910207,
-STORE, 140614226124800, 140614234517503,
-SNULL, 140614234521599, 140614242910207,
-STORE, 140614234517504, 140614234521599,
-STORE, 140614234521600, 140614242910207,
-STORE, 140614217732096, 140614234517503,
-STORE, 140614125477888, 140614133870591,
-SNULL, 140614125481983, 140614133870591,
-STORE, 140614125477888, 140614125481983,
-STORE, 140614125481984, 140614133870591,
-STORE, 140614117085184, 140614125477887,
-SNULL, 140614217736191, 140614234517503,
-STORE, 140614217732096, 140614217736191,
-STORE, 140614217736192, 140614234517503,
-SNULL, 140614117089279, 140614125477887,
-STORE, 140614117085184, 140614117089279,
-STORE, 140614117089280, 140614125477887,
-SNULL, 140614217736192, 140614226124799,
-STORE, 140614226124800, 140614234517503,
-STORE, 140614217736192, 140614226124799,
-SNULL, 140614226128895, 140614234517503,
-STORE, 140614226124800, 140614226128895,
-STORE, 140614226128896, 140614234517503,
-STORE, 140614108692480, 140614117085183,
-STORE, 140614100299776, 140614117085183,
-STORE, 140614091907072, 140614117085183,
-SNULL, 140614091907072, 140614108692479,
-STORE, 140614108692480, 140614117085183,
-STORE, 140614091907072, 140614108692479,
-SNULL, 140614108696575, 140614117085183,
-STORE, 140614108692480, 140614108696575,
-STORE, 140614108696576, 140614117085183,
-SNULL, 140614091907072, 140614100299775,
-STORE, 140614100299776, 140614108692479,
-STORE, 140614091907072, 140614100299775,
-SNULL, 140614100303871, 140614108692479,
-STORE, 140614100299776, 140614100303871,
-STORE, 140614100303872, 140614108692479,
-STORE, 140614083514368, 140614100299775,
-SNULL, 140614083518463, 140614100299775,
-STORE, 140614083514368, 140614083518463,
-STORE, 140614083518464, 140614100299775,
-STORE, 140613991260160, 140613999652863,
-SNULL, 140614083518464, 140614091907071,
-STORE, 140614091907072, 140614100299775,
-STORE, 140614083518464, 140614091907071,
-SNULL, 140614091911167, 140614100299775,
-STORE, 140614091907072, 140614091911167,
-STORE, 140614091911168, 140614100299775,
-SNULL, 140613991264255, 140613999652863,
-STORE, 140613991260160, 140613991264255,
-STORE, 140613991264256, 140613999652863,
-STORE, 140613982867456, 140613991260159,
-SNULL, 140613982871551, 140613991260159,
-STORE, 140613982867456, 140613982871551,
-STORE, 140613982871552, 140613991260159,
-STORE, 140613974474752, 140613982867455,
-SNULL, 140613974478847, 140613982867455,
-STORE, 140613974474752, 140613974478847,
-STORE, 140613974478848, 140613982867455,
-STORE, 140613966082048, 140613974474751,
-STORE, 140613739745280, 140613873827839,
-SNULL, 140613739745280, 140613806718975,
-STORE, 140613806718976, 140613873827839,
-STORE, 140613739745280, 140613806718975,
-SNULL, 140613806854143, 140613873827839,
-STORE, 140613806718976, 140613806854143,
-STORE, 140613806854144, 140613873827839,
-SNULL, 140613966086143, 140613974474751,
-STORE, 140613966082048, 140613966086143,
-STORE, 140613966086144, 140613974474751,
-STORE, 140613957689344, 140613966082047,
-STORE, 140613605392384, 140613739610111,
-STORE, 140613949296640, 140613966082047,
-STORE, 140613596999680, 140613605392383,
-STORE, 140613529890816, 140613596999679,
-STORE, 140613521498112, 140613529890815,
-STORE, 140613513105408, 140613529890815,
-STORE, 140613378887680, 140613513105407,
-SNULL, 140613378887680, 140613404065791,
-STORE, 140613404065792, 140613513105407,
-STORE, 140613378887680, 140613404065791,
-ERASE, 140613378887680, 140613404065791,
-STORE, 140613395673088, 140613404065791,
-STORE, 140613261455360, 140613395673087,
-SNULL, 140613261455360, 140613269848063,
-STORE, 140613269848064, 140613395673087,
-STORE, 140613261455360, 140613269848063,
-ERASE, 140613261455360, 140613269848063,
-STORE, 140613261455360, 140613269848063,
-STORE, 140613253062656, 140613269848063,
-STORE, 140613118844928, 140613253062655,
-STORE, 140613110452224, 140613118844927,
-SNULL, 140613118844928, 140613135630335,
-STORE, 140613135630336, 140613253062655,
-STORE, 140613118844928, 140613135630335,
-ERASE, 140613118844928, 140613135630335,
-STORE, 140613127237632, 140613135630335,
-STORE, 140613110452224, 140613135630335,
-STORE, 140612976234496, 140613110452223,
-STORE, 140612967841792, 140612976234495,
-STORE, 140612833624064, 140612967841791,
-STORE, 140612825231360, 140612833624063,
-STORE, 140612816838656, 140612833624063,
-STORE, 140612682620928, 140612816838655,
-STORE, 140612674228224, 140612682620927,
-SNULL, 140612682620928, 140612732977151,
-STORE, 140612732977152, 140612816838655,
-STORE, 140612682620928, 140612732977151,
-ERASE, 140612682620928, 140612732977151,
-SNULL, 140613672501247, 140613739610111,
-STORE, 140613605392384, 140613672501247,
-STORE, 140613672501248, 140613739610111,
-ERASE, 140613672501248, 140613739610111,
-SNULL, 140613605527551, 140613672501247,
-STORE, 140613605392384, 140613605527551,
-STORE, 140613605527552, 140613672501247,
-ERASE, 140613529890816, 140613596999679,
-STORE, 140612540010496, 140612674228223,
-SNULL, 140612540010496, 140612598759423,
-STORE, 140612598759424, 140612674228223,
-STORE, 140612540010496, 140612598759423,
-ERASE, 140612540010496, 140612598759423,
-SNULL, 140613471174655, 140613513105407,
-STORE, 140613404065792, 140613471174655,
-STORE, 140613471174656, 140613513105407,
-ERASE, 140613471174656, 140613513105407,
-SNULL, 140613404200959, 140613471174655,
-STORE, 140613404065792, 140613404200959,
-STORE, 140613404200960, 140613471174655,
-SNULL, 140613336956927, 140613395673087,
-STORE, 140613269848064, 140613336956927,
-STORE, 140613336956928, 140613395673087,
-ERASE, 140613336956928, 140613395673087,
-SNULL, 140612833624064, 140612867194879,
-STORE, 140612867194880, 140612967841791,
-STORE, 140612833624064, 140612867194879,
-ERASE, 140612833624064, 140612867194879,
-SNULL, 140612976234496, 140613001412607,
-STORE, 140613001412608, 140613110452223,
-STORE, 140612976234496, 140613001412607,
-ERASE, 140612976234496, 140613001412607,
-SNULL, 140613202739199, 140613253062655,
-STORE, 140613135630336, 140613202739199,
-STORE, 140613202739200, 140613253062655,
-ERASE, 140613202739200, 140613253062655,
-SNULL, 140613135765503, 140613202739199,
-STORE, 140613135630336, 140613135765503,
-STORE, 140613135765504, 140613202739199,
-SNULL, 140612816842751, 140612833624063,
-STORE, 140612816838656, 140612816842751,
-STORE, 140612816842752, 140612833624063,
-SNULL, 140613110456319, 140613135630335,
-STORE, 140613110452224, 140613110456319,
-STORE, 140613110456320, 140613135630335,
-SNULL, 140613949300735, 140613966082047,
-STORE, 140613949296640, 140613949300735,
-STORE, 140613949300736, 140613966082047,
-SNULL, 140613110456320, 140613118844927,
-STORE, 140613118844928, 140613135630335,
-STORE, 140613110456320, 140613118844927,
-SNULL, 140613118849023, 140613135630335,
-STORE, 140613118844928, 140613118849023,
-STORE, 140613118849024, 140613135630335,
-SNULL, 140612800086015, 140612816838655,
-STORE, 140612732977152, 140612800086015,
-STORE, 140612800086016, 140612816838655,
-ERASE, 140612800086016, 140612816838655,
-SNULL, 140613253062656, 140613261455359,
-STORE, 140613261455360, 140613269848063,
-STORE, 140613253062656, 140613261455359,
-SNULL, 140613261459455, 140613269848063,
-STORE, 140613261455360, 140613261459455,
-STORE, 140613261459456, 140613269848063,
-SNULL, 140612674232319, 140612682620927,
-STORE, 140612674228224, 140612674232319,
-STORE, 140612674232320, 140612682620927,
-STORE, 140613731217408, 140613739610111,
-STORE, 140613722824704, 140613739610111,
-SNULL, 140613949300736, 140613957689343,
-STORE, 140613957689344, 140613966082047,
-STORE, 140613949300736, 140613957689343,
-SNULL, 140613957693439, 140613966082047,
-STORE, 140613957689344, 140613957693439,
-STORE, 140613957693440, 140613966082047,
-STORE, 140612464541696, 140612674228223,
-SNULL, 140612531650559, 140612674228223,
-STORE, 140612464541696, 140612531650559,
-STORE, 140612531650560, 140612674228223,
-SNULL, 140612531650560, 140612598759423,
-STORE, 140612598759424, 140612674228223,
-STORE, 140612531650560, 140612598759423,
-ERASE, 140612531650560, 140612598759423,
-SNULL, 140612665868287, 140612674228223,
-STORE, 140612598759424, 140612665868287,
-STORE, 140612665868288, 140612674228223,
-ERASE, 140612665868288, 140612674228223,
-SNULL, 140613269983231, 140613336956927,
-STORE, 140613269848064, 140613269983231,
-STORE, 140613269983232, 140613336956927,
-SNULL, 140612934303743, 140612967841791,
-STORE, 140612867194880, 140612934303743,
-STORE, 140612934303744, 140612967841791,
-ERASE, 140612934303744, 140612967841791,
-SNULL, 140613068521471, 140613110452223,
-STORE, 140613001412608, 140613068521471,
-STORE, 140613068521472, 140613110452223,
-ERASE, 140613068521472, 140613110452223,
-STORE, 140613714432000, 140613739610111,
-SNULL, 140613001547775, 140613068521471,
-STORE, 140613001412608, 140613001547775,
-STORE, 140613001547776, 140613068521471,
-SNULL, 140612733112319, 140612800086015,
-STORE, 140612732977152, 140612733112319,
-STORE, 140612733112320, 140612800086015,
-SNULL, 140613513109503, 140613529890815,
-STORE, 140613513105408, 140613513109503,
-STORE, 140613513109504, 140613529890815,
-STORE, 140613706039296, 140613739610111,
-STORE, 140613697646592, 140613739610111,
-STORE, 140613689253888, 140613739610111,
-SNULL, 140613689257983, 140613739610111,
-STORE, 140613689253888, 140613689257983,
-STORE, 140613689257984, 140613739610111,
-SNULL, 140613253066751, 140613261455359,
-STORE, 140613253062656, 140613253066751,
-STORE, 140613253066752, 140613261455359,
-STORE, 140613680861184, 140613689253887,
-STORE, 140613588606976, 140613605392383,
-SNULL, 140613689257984, 140613731217407,
-STORE, 140613731217408, 140613739610111,
-STORE, 140613689257984, 140613731217407,
-SNULL, 140613731221503, 140613739610111,
-STORE, 140613731217408, 140613731221503,
-STORE, 140613731221504, 140613739610111,
-STORE, 140613580214272, 140613605392383,
-SNULL, 140612464676863, 140612531650559,
-STORE, 140612464541696, 140612464676863,
-STORE, 140612464676864, 140612531650559,
-SNULL, 140612598894591, 140612665868287,
-STORE, 140612598759424, 140612598894591,
-STORE, 140612598894592, 140612665868287,
-SNULL, 140612867330047, 140612934303743,
-STORE, 140612867194880, 140612867330047,
-STORE, 140612867330048, 140612934303743,
-STORE, 140613571821568, 140613605392383,
-SNULL, 140613571825663, 140613605392383,
-STORE, 140613571821568, 140613571825663,
-STORE, 140613571825664, 140613605392383,
-SNULL, 140613689257984, 140613722824703,
-STORE, 140613722824704, 140613731217407,
-STORE, 140613689257984, 140613722824703,
-SNULL, 140613722828799, 140613731217407,
-STORE, 140613722824704, 140613722828799,
-STORE, 140613722828800, 140613731217407,
-SNULL, 140613689257984, 140613714431999,
-STORE, 140613714432000, 140613722824703,
-STORE, 140613689257984, 140613714431999,
-SNULL, 140613714436095, 140613722824703,
-STORE, 140613714432000, 140613714436095,
-STORE, 140613714436096, 140613722824703,
-SNULL, 140612816842752, 140612825231359,
-STORE, 140612825231360, 140612833624063,
-STORE, 140612816842752, 140612825231359,
-SNULL, 140612825235455, 140612833624063,
-STORE, 140612825231360, 140612825235455,
-STORE, 140612825235456, 140612833624063,
-SNULL, 140613395677183, 140613404065791,
-STORE, 140613395673088, 140613395677183,
-STORE, 140613395677184, 140613404065791,
-SNULL, 140613689257984, 140613706039295,
-STORE, 140613706039296, 140613714431999,
-STORE, 140613689257984, 140613706039295,
-SNULL, 140613706043391, 140613714431999,
-STORE, 140613706039296, 140613706043391,
-STORE, 140613706043392, 140613714431999,
-SNULL, 140613118849024, 140613127237631,
-STORE, 140613127237632, 140613135630335,
-STORE, 140613118849024, 140613127237631,
-SNULL, 140613127241727, 140613135630335,
-STORE, 140613127237632, 140613127241727,
-STORE, 140613127241728, 140613135630335,
-SNULL, 140613571825664, 140613580214271,
-STORE, 140613580214272, 140613605392383,
-STORE, 140613571825664, 140613580214271,
-SNULL, 140613580218367, 140613605392383,
-STORE, 140613580214272, 140613580218367,
-STORE, 140613580218368, 140613605392383,
-SNULL, 140613689257984, 140613697646591,
-STORE, 140613697646592, 140613706039295,
-STORE, 140613689257984, 140613697646591,
-SNULL, 140613697650687, 140613706039295,
-STORE, 140613697646592, 140613697650687,
-STORE, 140613697650688, 140613706039295,
-SNULL, 140613680865279, 140613689253887,
-STORE, 140613680861184, 140613680865279,
-STORE, 140613680865280, 140613689253887,
-STORE, 140613563428864, 140613571821567,
-SNULL, 140613563432959, 140613571821567,
-STORE, 140613563428864, 140613563432959,
-STORE, 140613563432960, 140613571821567,
-SNULL, 140613580218368, 140613588606975,
-STORE, 140613588606976, 140613605392383,
-STORE, 140613580218368, 140613588606975,
-SNULL, 140613588611071, 140613605392383,
-STORE, 140613588606976, 140613588611071,
-STORE, 140613588611072, 140613605392383,
-SNULL, 140613513109504, 140613521498111,
-STORE, 140613521498112, 140613529890815,
-STORE, 140613513109504, 140613521498111,
-SNULL, 140613521502207, 140613529890815,
-STORE, 140613521498112, 140613521502207,
-STORE, 140613521502208, 140613529890815,
-SNULL, 140613588611072, 140613596999679,
-STORE, 140613596999680, 140613605392383,
-STORE, 140613588611072, 140613596999679,
-SNULL, 140613597003775, 140613605392383,
-STORE, 140613596999680, 140613597003775,
-STORE, 140613597003776, 140613605392383,
-STORE, 140613555036160, 140613563428863,
-SNULL, 140613555040255, 140613563428863,
-STORE, 140613555036160, 140613555040255,
-STORE, 140613555040256, 140613563428863,
-STORE, 140613546643456, 140613555036159,
-STORE, 140613538250752, 140613555036159,
-SNULL, 140613538250752, 140613546643455,
-STORE, 140613546643456, 140613555036159,
-STORE, 140613538250752, 140613546643455,
-SNULL, 140613546647551, 140613555036159,
-STORE, 140613546643456, 140613546647551,
-STORE, 140613546647552, 140613555036159,
-STORE, 140613504712704, 140613513105407,
-STORE, 140613496320000, 140613513105407,
-SNULL, 140613496324095, 140613513105407,
-STORE, 140613496320000, 140613496324095,
-STORE, 140613496324096, 140613513105407,
-STORE, 140613487927296, 140613496319999,
-SNULL, 140613487931391, 140613496319999,
-STORE, 140613487927296, 140613487931391,
-STORE, 140613487931392, 140613496319999,
-STORE, 140613479534592, 140613487927295,
-SNULL, 140612967845887, 140612976234495,
-STORE, 140612967841792, 140612967845887,
-STORE, 140612967845888, 140612976234495,
-STORE, 140613387280384, 140613395673087,
-STORE, 140613378887680, 140613395673087,
-SNULL, 140613378887680, 140613387280383,
-STORE, 140613387280384, 140613395673087,
-STORE, 140613378887680, 140613387280383,
-SNULL, 140613387284479, 140613395673087,
-STORE, 140613387280384, 140613387284479,
-STORE, 140613387284480, 140613395673087,
-STORE, 140613370494976, 140613387280383,
-STORE, 140613362102272, 140613387280383,
-SNULL, 140613479538687, 140613487927295,
-STORE, 140613479534592, 140613479538687,
-STORE, 140613479538688, 140613487927295,
-STORE, 140613353709568, 140613387280383,
-STORE, 140613345316864, 140613387280383,
-STORE, 140613244669952, 140613253062655,
-SNULL, 140613345320959, 140613387280383,
-STORE, 140613345316864, 140613345320959,
-STORE, 140613345320960, 140613387280383,
-SNULL, 140613538254847, 140613546643455,
-STORE, 140613538250752, 140613538254847,
-STORE, 140613538254848, 140613546643455,
-STORE, 140613236277248, 140613253062655,
-STORE, 140613227884544, 140613253062655,
-STORE, 140613219491840, 140613253062655,
-STORE, 140613211099136, 140613253062655,
-SNULL, 140613211103231, 140613253062655,
-STORE, 140613211099136, 140613211103231,
-STORE, 140613211103232, 140613253062655,
-STORE, 140613102059520, 140613110452223,
-STORE, 140613093666816, 140613110452223,
-SNULL, 140613093670911, 140613110452223,
-STORE, 140613093666816, 140613093670911,
-STORE, 140613093670912, 140613110452223,
-STORE, 140613085274112, 140613093666815,
-SNULL, 140613496324096, 140613504712703,
-STORE, 140613504712704, 140613513105407,
-STORE, 140613496324096, 140613504712703,
-SNULL, 140613504716799, 140613513105407,
-STORE, 140613504712704, 140613504716799,
-STORE, 140613504716800, 140613513105407,
-SNULL, 140613345320960, 140613378887679,
-STORE, 140613378887680, 140613387280383,
-STORE, 140613345320960, 140613378887679,
-SNULL, 140613378891775, 140613387280383,
-STORE, 140613378887680, 140613378891775,
-STORE, 140613378891776, 140613387280383,
-SNULL, 140613345320960, 140613362102271,
-STORE, 140613362102272, 140613378887679,
-STORE, 140613345320960, 140613362102271,
-SNULL, 140613362106367, 140613378887679,
-STORE, 140613362102272, 140613362106367,
-STORE, 140613362106368, 140613378887679,
-SNULL, 140613362106368, 140613370494975,
-STORE, 140613370494976, 140613378887679,
-STORE, 140613362106368, 140613370494975,
-SNULL, 140613370499071, 140613378887679,
-STORE, 140613370494976, 140613370499071,
-STORE, 140613370499072, 140613378887679,
-STORE, 140613076881408, 140613093666815,
-STORE, 140612993019904, 140613001412607,
-SNULL, 140613076885503, 140613093666815,
-STORE, 140613076881408, 140613076885503,
-STORE, 140613076885504, 140613093666815,
-SNULL, 140613093670912, 140613102059519,
-STORE, 140613102059520, 140613110452223,
-STORE, 140613093670912, 140613102059519,
-SNULL, 140613102063615, 140613110452223,
-STORE, 140613102059520, 140613102063615,
-STORE, 140613102063616, 140613110452223,
-SNULL, 140613076885504, 140613085274111,
-STORE, 140613085274112, 140613093666815,
-STORE, 140613076885504, 140613085274111,
-SNULL, 140613085278207, 140613093666815,
-STORE, 140613085274112, 140613085278207,
-STORE, 140613085278208, 140613093666815,
-STORE, 140612984627200, 140613001412607,
-STORE, 140612967845888, 140612984627199,
-SNULL, 140613211103232, 140613219491839,
-STORE, 140613219491840, 140613253062655,
-STORE, 140613211103232, 140613219491839,
-SNULL, 140613219495935, 140613253062655,
-STORE, 140613219491840, 140613219495935,
-STORE, 140613219495936, 140613253062655,
-STORE, 140612959449088, 140612967841791,
-STORE, 140612951056384, 140612967841791,
-SNULL, 140612951060479, 140612967841791,
-STORE, 140612951056384, 140612951060479,
-STORE, 140612951060480, 140612967841791,
-SNULL, 140613345320960, 140613353709567,
-STORE, 140613353709568, 140613362102271,
-STORE, 140613345320960, 140613353709567,
-SNULL, 140613353713663, 140613362102271,
-STORE, 140613353709568, 140613353713663,
-STORE, 140613353713664, 140613362102271,
-SNULL, 140613219495936, 140613244669951,
-STORE, 140613244669952, 140613253062655,
-STORE, 140613219495936, 140613244669951,
-SNULL, 140613244674047, 140613253062655,
-STORE, 140613244669952, 140613244674047,
-STORE, 140613244674048, 140613253062655,
-STORE, 140612942663680, 140612951056383,
-SNULL, 140613219495936, 140613236277247,
-STORE, 140613236277248, 140613244669951,
-STORE, 140613219495936, 140613236277247,
-SNULL, 140613236281343, 140613244669951,
-STORE, 140613236277248, 140613236281343,
-STORE, 140613236281344, 140613244669951,
-SNULL, 140613219495936, 140613227884543,
-STORE, 140613227884544, 140613236277247,
-STORE, 140613219495936, 140613227884543,
-SNULL, 140613227888639, 140613236277247,
-STORE, 140613227884544, 140613227888639,
-STORE, 140613227888640, 140613236277247,
-SNULL, 140612984627200, 140612993019903,
-STORE, 140612993019904, 140613001412607,
-STORE, 140612984627200, 140612993019903,
-SNULL, 140612993023999, 140613001412607,
-STORE, 140612993019904, 140612993023999,
-STORE, 140612993024000, 140613001412607,
-STORE, 140612858802176, 140612867194879,
-STORE, 140612850409472, 140612867194879,
-SNULL, 140612951060480, 140612959449087,
-STORE, 140612959449088, 140612967841791,
-STORE, 140612951060480, 140612959449087,
-SNULL, 140612959453183, 140612967841791,
-STORE, 140612959449088, 140612959453183,
-STORE, 140612959453184, 140612967841791,
-SNULL, 140612967845888, 140612976234495,
-STORE, 140612976234496, 140612984627199,
-STORE, 140612967845888, 140612976234495,
-SNULL, 140612976238591, 140612984627199,
-STORE, 140612976234496, 140612976238591,
-STORE, 140612976238592, 140612984627199,
-STORE, 140612842016768, 140612867194879,
-SNULL, 140612842020863, 140612867194879,
-STORE, 140612842016768, 140612842020863,
-STORE, 140612842020864, 140612867194879,
-SNULL, 140612984631295, 140612993019903,
-STORE, 140612984627200, 140612984631295,
-STORE, 140612984631296, 140612993019903,
-STORE, 140612825235456, 140612842016767,
-STORE, 140612808445952, 140612816838655,
-SNULL, 140612942667775, 140612951056383,
-STORE, 140612942663680, 140612942667775,
-STORE, 140612942667776, 140612951056383,
-STORE, 140612724584448, 140612732977151,
-SNULL, 140612724588543, 140612732977151,
-STORE, 140612724584448, 140612724588543,
-STORE, 140612724588544, 140612732977151,
-STORE, 140612716191744, 140612724584447,
-SNULL, 140612842020864, 140612850409471,
-STORE, 140612850409472, 140612867194879,
-STORE, 140612842020864, 140612850409471,
-SNULL, 140612850413567, 140612867194879,
-STORE, 140612850409472, 140612850413567,
-STORE, 140612850413568, 140612867194879,
-SNULL, 140612850413568, 140612858802175,
-STORE, 140612858802176, 140612867194879,
-STORE, 140612850413568, 140612858802175,
-SNULL, 140612858806271, 140612867194879,
-STORE, 140612858802176, 140612858806271,
-STORE, 140612858806272, 140612867194879,
-STORE, 140612707799040, 140612724584447,
-SNULL, 140612707803135, 140612724584447,
-STORE, 140612707799040, 140612707803135,
-STORE, 140612707803136, 140612724584447,
-SNULL, 140612707803136, 140612716191743,
-STORE, 140612716191744, 140612724584447,
-STORE, 140612707803136, 140612716191743,
-SNULL, 140612716195839, 140612724584447,
-STORE, 140612716191744, 140612716195839,
-STORE, 140612716195840, 140612724584447,
-SNULL, 140612808450047, 140612816838655,
-STORE, 140612808445952, 140612808450047,
-STORE, 140612808450048, 140612816838655,
-SNULL, 140612825235456, 140612833624063,
-STORE, 140612833624064, 140612842016767,
-STORE, 140612825235456, 140612833624063,
-SNULL, 140612833628159, 140612842016767,
-STORE, 140612833624064, 140612833628159,
-STORE, 140612833628160, 140612842016767,
-STORE, 140612699406336, 140612707799039,
-SNULL, 140612699410431, 140612707799039,
-STORE, 140612699406336, 140612699410431,
-STORE, 140612699410432, 140612707799039,
-STORE, 140614384926720, 140614384955391,
-STORE, 140614349332480, 140614351523839,
-SNULL, 140614349332480, 140614349422591,
-STORE, 140614349422592, 140614351523839,
-STORE, 140614349332480, 140614349422591,
-SNULL, 140614351515647, 140614351523839,
-STORE, 140614349422592, 140614351515647,
-STORE, 140614351515648, 140614351523839,
-ERASE, 140614351515648, 140614351523839,
-STORE, 140614351515648, 140614351523839,
-SNULL, 140614351519743, 140614351523839,
-STORE, 140614351515648, 140614351519743,
-STORE, 140614351519744, 140614351523839,
-ERASE, 140614384926720, 140614384955391,
-ERASE, 140613949296640, 140613949300735,
-ERASE, 140613949300736, 140613957689343,
-ERASE, 140613689253888, 140613689257983,
-ERASE, 140613689257984, 140613697646591,
-ERASE, 140613563428864, 140613563432959,
-ERASE, 140613563432960, 140613571821567,
-ERASE, 140613211099136, 140613211103231,
-ERASE, 140613211103232, 140613219491839,
-ERASE, 140614133870592, 140614133874687,
-ERASE, 140614133874688, 140614142263295,
-ERASE, 140612967841792, 140612967845887,
-ERASE, 140612967845888, 140612976234495,
-ERASE, 140613076881408, 140613076885503,
-ERASE, 140613076885504, 140613085274111,
-ERASE, 140612850409472, 140612850413567,
-ERASE, 140612850413568, 140612858802175,
-ERASE, 140613110452224, 140613110456319,
-ERASE, 140613110456320, 140613118844927,
-ERASE, 140613706039296, 140613706043391,
-ERASE, 140613706043392, 140613714431999,
-ERASE, 140613521498112, 140613521502207,
-ERASE, 140613521502208, 140613529890815,
-ERASE, 140613362102272, 140613362106367,
-ERASE, 140613362106368, 140613370494975,
-ERASE, 140613253062656, 140613253066751,
-ERASE, 140613253066752, 140613261455359,
-ERASE, 140612816838656, 140612816842751,
-ERASE, 140612816842752, 140612825231359,
-ERASE, 140613261455360, 140613261459455,
-ERASE, 140613261459456, 140613269848063,
-ERASE, 140613118844928, 140613118849023,
-ERASE, 140613118849024, 140613127237631,
-ERASE, 140613714432000, 140613714436095,
-ERASE, 140613714436096, 140613722824703,
-ERASE, 140613496320000, 140613496324095,
-ERASE, 140613496324096, 140613504712703,
-ERASE, 140613513105408, 140613513109503,
-ERASE, 140613513109504, 140613521498111,
-ERASE, 140613697646592, 140613697650687,
-ERASE, 140613697650688, 140613706039295,
-ERASE, 140613093666816, 140613093670911,
-ERASE, 140613093670912, 140613102059519,
-ERASE, 140612993019904, 140612993023999,
-ERASE, 140612993024000, 140613001412607,
-ERASE, 140613127237632, 140613127241727,
-ERASE, 140613127241728, 140613135630335,
-ERASE, 140613957689344, 140613957693439,
-ERASE, 140613957693440, 140613966082047,
-ERASE, 140613571821568, 140613571825663,
-ERASE, 140613571825664, 140613580214271,
-ERASE, 140613479534592, 140613479538687,
-ERASE, 140613479538688, 140613487927295,
-ERASE, 140612984627200, 140612984631295,
-ERASE, 140612984631296, 140612993019903,
-ERASE, 140613588606976, 140613588611071,
-ERASE, 140613588611072, 140613596999679,
-ERASE, 140613680861184, 140613680865279,
-ERASE, 140613680865280, 140613689253887,
-ERASE, 140613345316864, 140613345320959,
-ERASE, 140613345320960, 140613353709567,
-ERASE, 140613596999680, 140613597003775,
-ERASE, 140613597003776, 140613605392383,
-ERASE, 140613966082048, 140613966086143,
-ERASE, 140613966086144, 140613974474751,
-ERASE, 140613731217408, 140613731221503,
-ERASE, 140613731221504, 140613739610111,
-ERASE, 140613395673088, 140613395677183,
-ERASE, 140613395677184, 140613404065791,
-ERASE, 140612825231360, 140612825235455,
-ERASE, 140612825235456, 140612833624063,
-ERASE, 140612674228224, 140612674232319,
-ERASE, 140612674232320, 140612682620927,
-ERASE, 140613722824704, 140613722828799,
-ERASE, 140613722828800, 140613731217407,
-ERASE, 140613487927296, 140613487931391,
-ERASE, 140613487931392, 140613496319999,
-ERASE, 140613102059520, 140613102063615,
-ERASE, 140613102063616, 140613110452223,
-ERASE, 140614242910208, 140614242914303,
-ERASE, 140614242914304, 140614251302911,
-ERASE, 140612808445952, 140612808450047,
-ERASE, 140612808450048, 140612816838655,
-ERASE, 140613236277248, 140613236281343,
-ERASE, 140613236281344, 140613244669951,
-ERASE, 140613580214272, 140613580218367,
-ERASE, 140613580218368, 140613588606975,
-ERASE, 140613370494976, 140613370499071,
-ERASE, 140613370499072, 140613378887679,
-ERASE, 140613244669952, 140613244674047,
-ERASE, 140613244674048, 140613253062655,
-ERASE, 140612724584448, 140612724588543,
-ERASE, 140612724588544, 140612732977151,
-ERASE, 140612707799040, 140612707803135,
-ERASE, 140612707803136, 140612716191743,
-ERASE, 140613504712704, 140613504716799,
-ERASE, 140613504716800, 140613513105407,
- };
-
- unsigned long set39[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140736271417344, 140737488351231,
-SNULL, 140736271421439, 140737488351231,
-STORE, 140736271417344, 140736271421439,
-STORE, 140736271286272, 140736271421439,
-STORE, 94412930822144, 94412933074943,
-SNULL, 94412930953215, 94412933074943,
-STORE, 94412930822144, 94412930953215,
-STORE, 94412930953216, 94412933074943,
-ERASE, 94412930953216, 94412933074943,
-STORE, 94412933046272, 94412933054463,
-STORE, 94412933054464, 94412933074943,
-STORE, 140326136901632, 140326139154431,
-SNULL, 140326137044991, 140326139154431,
-STORE, 140326136901632, 140326137044991,
-STORE, 140326137044992, 140326139154431,
-ERASE, 140326137044992, 140326139154431,
-STORE, 140326139142144, 140326139150335,
-STORE, 140326139150336, 140326139154431,
-STORE, 140736271585280, 140736271589375,
-STORE, 140736271572992, 140736271585279,
-STORE, 140326139113472, 140326139142143,
-STORE, 140326139105280, 140326139113471,
-STORE, 140326134685696, 140326136901631,
-SNULL, 140326134685696, 140326134783999,
-STORE, 140326134784000, 140326136901631,
-STORE, 140326134685696, 140326134783999,
-SNULL, 140326136877055, 140326136901631,
-STORE, 140326134784000, 140326136877055,
-STORE, 140326136877056, 140326136901631,
-SNULL, 140326136877056, 140326136885247,
-STORE, 140326136885248, 140326136901631,
-STORE, 140326136877056, 140326136885247,
-ERASE, 140326136877056, 140326136885247,
-STORE, 140326136877056, 140326136885247,
-ERASE, 140326136885248, 140326136901631,
-STORE, 140326136885248, 140326136901631,
-STORE, 140326130888704, 140326134685695,
-SNULL, 140326130888704, 140326132547583,
-STORE, 140326132547584, 140326134685695,
-STORE, 140326130888704, 140326132547583,
-SNULL, 140326134644735, 140326134685695,
-STORE, 140326132547584, 140326134644735,
-STORE, 140326134644736, 140326134685695,
-SNULL, 140326134644736, 140326134669311,
-STORE, 140326134669312, 140326134685695,
-STORE, 140326134644736, 140326134669311,
-ERASE, 140326134644736, 140326134669311,
-STORE, 140326134644736, 140326134669311,
-ERASE, 140326134669312, 140326134685695,
-STORE, 140326134669312, 140326134685695,
-STORE, 140326139097088, 140326139113471,
-SNULL, 140326134661119, 140326134669311,
-STORE, 140326134644736, 140326134661119,
-STORE, 140326134661120, 140326134669311,
-SNULL, 140326136881151, 140326136885247,
-STORE, 140326136877056, 140326136881151,
-STORE, 140326136881152, 140326136885247,
-SNULL, 94412933050367, 94412933054463,
-STORE, 94412933046272, 94412933050367,
-STORE, 94412933050368, 94412933054463,
-SNULL, 140326139146239, 140326139150335,
-STORE, 140326139142144, 140326139146239,
-STORE, 140326139146240, 140326139150335,
-ERASE, 140326139113472, 140326139142143,
-STORE, 94412939493376, 94412939628543,
-STORE, 140326122496000, 140326130888703,
-SNULL, 140326122500095, 140326130888703,
-STORE, 140326122496000, 140326122500095,
-STORE, 140326122500096, 140326130888703,
-STORE, 140326114103296, 140326122495999,
-STORE, 140325979885568, 140326114103295,
-SNULL, 140325979885568, 140326043910143,
-STORE, 140326043910144, 140326114103295,
-STORE, 140325979885568, 140326043910143,
-ERASE, 140325979885568, 140326043910143,
-SNULL, 140326111019007, 140326114103295,
-STORE, 140326043910144, 140326111019007,
-STORE, 140326111019008, 140326114103295,
-ERASE, 140326111019008, 140326114103295,
-SNULL, 140326044045311, 140326111019007,
-STORE, 140326043910144, 140326044045311,
-STORE, 140326044045312, 140326111019007,
-SNULL, 140326114107391, 140326122495999,
-STORE, 140326114103296, 140326114107391,
-STORE, 140326114107392, 140326122495999,
-STORE, 140326035517440, 140326043910143,
-SNULL, 140326035521535, 140326043910143,
-STORE, 140326035517440, 140326035521535,
-STORE, 140326035521536, 140326043910143,
-STORE, 140326027124736, 140326035517439,
-SNULL, 140326027128831, 140326035517439,
-STORE, 140326027124736, 140326027128831,
-STORE, 140326027128832, 140326035517439,
-STORE, 140326018732032, 140326027124735,
-SNULL, 140326018736127, 140326027124735,
-STORE, 140326018732032, 140326018736127,
-STORE, 140326018736128, 140326027124735,
-STORE, 140326010339328, 140326018732031,
-STORE, 140326001946624, 140326018732031,
-STORE, 140325993553920, 140326018732031,
-STORE, 140325859336192, 140325993553919,
-SNULL, 140325859336192, 140325909692415,
-STORE, 140325909692416, 140325993553919,
-STORE, 140325859336192, 140325909692415,
-ERASE, 140325859336192, 140325909692415,
-SNULL, 140325976801279, 140325993553919,
-STORE, 140325909692416, 140325976801279,
-STORE, 140325976801280, 140325993553919,
-ERASE, 140325976801280, 140325993553919,
-STORE, 140325985161216, 140326018732031,
-STORE, 140325775474688, 140325976801279,
-STORE, 140325708365824, 140325976801279,
-SNULL, 140325708500991, 140325976801279,
-STORE, 140325708365824, 140325708500991,
-STORE, 140325708500992, 140325976801279,
-SNULL, 140325708500992, 140325909692415,
-STORE, 140325909692416, 140325976801279,
-STORE, 140325708500992, 140325909692415,
-SNULL, 140325909827583, 140325976801279,
-STORE, 140325909692416, 140325909827583,
-STORE, 140325909827584, 140325976801279,
-SNULL, 140325842583551, 140325909692415,
-STORE, 140325708500992, 140325842583551,
-STORE, 140325842583552, 140325909692415,
-ERASE, 140325842583552, 140325909692415,
-SNULL, 140325708500992, 140325775474687,
-STORE, 140325775474688, 140325842583551,
-STORE, 140325708500992, 140325775474687,
-SNULL, 140325775609855, 140325842583551,
-STORE, 140325775474688, 140325775609855,
-STORE, 140325775609856, 140325842583551,
-STORE, 140325775609856, 140325909692415,
-SNULL, 140325775609856, 140325842583551,
-STORE, 140325842583552, 140325909692415,
-STORE, 140325775609856, 140325842583551,
-SNULL, 140325842718719, 140325909692415,
-STORE, 140325842583552, 140325842718719,
-STORE, 140325842718720, 140325909692415,
-SNULL, 140325985161216, 140325993553919,
-STORE, 140325993553920, 140326018732031,
-STORE, 140325985161216, 140325993553919,
-SNULL, 140325993558015, 140326018732031,
-STORE, 140325993553920, 140325993558015,
-STORE, 140325993558016, 140326018732031,
-SNULL, 140325985165311, 140325993553919,
-STORE, 140325985161216, 140325985165311,
-STORE, 140325985165312, 140325993553919,
-SNULL, 140325993558016, 140326001946623,
-STORE, 140326001946624, 140326018732031,
-STORE, 140325993558016, 140326001946623,
-SNULL, 140326001950719, 140326018732031,
-STORE, 140326001946624, 140326001950719,
-STORE, 140326001950720, 140326018732031,
-SNULL, 140326001950720, 140326010339327,
-STORE, 140326010339328, 140326018732031,
-STORE, 140326001950720, 140326010339327,
-SNULL, 140326010343423, 140326018732031,
-STORE, 140326010339328, 140326010343423,
-STORE, 140326010343424, 140326018732031,
-STORE, 140325699973120, 140325708365823,
-STORE, 140325691580416, 140325708365823,
-STORE, 140325683187712, 140325708365823,
-SNULL, 140325683191807, 140325708365823,
-STORE, 140325683187712, 140325683191807,
-STORE, 140325683191808, 140325708365823,
-SNULL, 140325683191808, 140325699973119,
-STORE, 140325699973120, 140325708365823,
-STORE, 140325683191808, 140325699973119,
-SNULL, 140325699977215, 140325708365823,
-STORE, 140325699973120, 140325699977215,
-STORE, 140325699977216, 140325708365823,
-STORE, 140325674795008, 140325683187711,
-STORE, 140325666402304, 140325683187711,
-STORE, 140325658009600, 140325683187711,
-SNULL, 140325658009600, 140325666402303,
-STORE, 140325666402304, 140325683187711,
-STORE, 140325658009600, 140325666402303,
-SNULL, 140325666406399, 140325683187711,
-STORE, 140325666402304, 140325666406399,
-STORE, 140325666406400, 140325683187711,
-SNULL, 140325683191808, 140325691580415,
-STORE, 140325691580416, 140325699973119,
-STORE, 140325683191808, 140325691580415,
-SNULL, 140325691584511, 140325699973119,
-STORE, 140325691580416, 140325691584511,
-STORE, 140325691584512, 140325699973119,
-SNULL, 140325666406400, 140325674795007,
-STORE, 140325674795008, 140325683187711,
-STORE, 140325666406400, 140325674795007,
-SNULL, 140325674799103, 140325683187711,
-STORE, 140325674795008, 140325674799103,
-STORE, 140325674799104, 140325683187711,
-STORE, 140325649616896, 140325666402303,
-SNULL, 140325649616896, 140325658009599,
-STORE, 140325658009600, 140325666402303,
-STORE, 140325649616896, 140325658009599,
-SNULL, 140325658013695, 140325666402303,
-STORE, 140325658009600, 140325658013695,
-STORE, 140325658013696, 140325666402303,
-SNULL, 140325649620991, 140325658009599,
-STORE, 140325649616896, 140325649620991,
-STORE, 140325649620992, 140325658009599,
-STORE, 140325641224192, 140325649616895,
-STORE, 140325632831488, 140325649616895,
-SNULL, 140325632835583, 140325649616895,
-STORE, 140325632831488, 140325632835583,
-STORE, 140325632835584, 140325649616895,
-STORE, 140325624438784, 140325632831487,
-SNULL, 140325624442879, 140325632831487,
-STORE, 140325624438784, 140325624442879,
-STORE, 140325624442880, 140325632831487,
-SNULL, 140325632835584, 140325641224191,
-STORE, 140325641224192, 140325649616895,
-STORE, 140325632835584, 140325641224191,
-SNULL, 140325641228287, 140325649616895,
-STORE, 140325641224192, 140325641228287,
-STORE, 140325641228288, 140325649616895,
-STORE, 140325616046080, 140325624438783,
-SNULL, 140325616050175, 140325624438783,
-STORE, 140325616046080, 140325616050175,
-STORE, 140325616050176, 140325624438783,
-STORE, 140325607653376, 140325616046079,
-SNULL, 140325607657471, 140325616046079,
-STORE, 140325607653376, 140325607657471,
-STORE, 140325607657472, 140325616046079,
-STORE, 140325599260672, 140325607653375,
-STORE, 140325590867968, 140325607653375,
-STORE, 140325456650240, 140325590867967,
-SNULL, 140325456650240, 140325507039231,
-STORE, 140325507039232, 140325590867967,
-STORE, 140325456650240, 140325507039231,
-ERASE, 140325456650240, 140325507039231,
-STORE, 140325498646528, 140325507039231,
-STORE, 140325364428800, 140325498646527,
-SNULL, 140325364428800, 140325372821503,
-STORE, 140325372821504, 140325498646527,
-STORE, 140325364428800, 140325372821503,
-ERASE, 140325364428800, 140325372821503,
-STORE, 140325364428800, 140325372821503,
-STORE, 140325356036096, 140325372821503,
-STORE, 140325221818368, 140325356036095,
-SNULL, 140325221818368, 140325238603775,
-STORE, 140325238603776, 140325356036095,
-STORE, 140325221818368, 140325238603775,
-ERASE, 140325221818368, 140325238603775,
-STORE, 140325230211072, 140325238603775,
-STORE, 140325221818368, 140325238603775,
-STORE, 140325087600640, 140325221818367,
-STORE, 140325079207936, 140325087600639,
-SNULL, 140325087600640, 140325104386047,
-STORE, 140325104386048, 140325221818367,
-STORE, 140325087600640, 140325104386047,
-ERASE, 140325087600640, 140325104386047,
-STORE, 140325095993344, 140325104386047,
-STORE, 140325079207936, 140325104386047,
-STORE, 140324944990208, 140325079207935,
-SNULL, 140324944990208, 140324970168319,
-STORE, 140324970168320, 140325079207935,
-STORE, 140324944990208, 140324970168319,
-ERASE, 140324944990208, 140324970168319,
-STORE, 140324961775616, 140324970168319,
-STORE, 140324953382912, 140324970168319,
-STORE, 140324819165184, 140324953382911,
-STORE, 140324684947456, 140324953382911,
-STORE, 140324676554752, 140324684947455,
-STORE, 140324668162048, 140324684947455,
-STORE, 140324533944320, 140324668162047,
-STORE, 140324525551616, 140324533944319,
-SNULL, 140324533944320, 140324567515135,
-STORE, 140324567515136, 140324668162047,
-STORE, 140324533944320, 140324567515135,
-ERASE, 140324533944320, 140324567515135,
-STORE, 140324559122432, 140324567515135,
-STORE, 140324391333888, 140324525551615,
-SNULL, 140325574148095, 140325590867967,
-STORE, 140325507039232, 140325574148095,
-STORE, 140325574148096, 140325590867967,
-ERASE, 140325574148096, 140325590867967,
-SNULL, 140325439930367, 140325498646527,
-STORE, 140325372821504, 140325439930367,
-STORE, 140325439930368, 140325498646527,
-ERASE, 140325439930368, 140325498646527,
-SNULL, 140325305712639, 140325356036095,
-STORE, 140325238603776, 140325305712639,
-STORE, 140325305712640, 140325356036095,
-ERASE, 140325305712640, 140325356036095,
-SNULL, 140325171494911, 140325221818367,
-STORE, 140325104386048, 140325171494911,
-STORE, 140325171494912, 140325221818367,
-ERASE, 140325171494912, 140325221818367,
-SNULL, 140325104521215, 140325171494911,
-STORE, 140325104386048, 140325104521215,
-STORE, 140325104521216, 140325171494911,
-STORE, 140324257116160, 140324525551615,
-SNULL, 140324257116160, 140324299079679,
-STORE, 140324299079680, 140324525551615,
-STORE, 140324257116160, 140324299079679,
-ERASE, 140324257116160, 140324299079679,
-SNULL, 140325037277183, 140325079207935,
-STORE, 140324970168320, 140325037277183,
-STORE, 140325037277184, 140325079207935,
-ERASE, 140325037277184, 140325079207935,
-SNULL, 140324819165183, 140324953382911,
-STORE, 140324684947456, 140324819165183,
-STORE, 140324819165184, 140324953382911,
-SNULL, 140324819165184, 140324835950591,
-STORE, 140324835950592, 140324953382911,
-STORE, 140324819165184, 140324835950591,
-ERASE, 140324819165184, 140324835950591,
-SNULL, 140324903059455, 140324953382911,
-STORE, 140324835950592, 140324903059455,
-STORE, 140324903059456, 140324953382911,
-ERASE, 140324903059456, 140324953382911,
-SNULL, 140324684947456, 140324701732863,
-STORE, 140324701732864, 140324819165183,
-STORE, 140324684947456, 140324701732863,
-ERASE, 140324684947456, 140324701732863,
-SNULL, 140324768841727, 140324819165183,
-STORE, 140324701732864, 140324768841727,
-STORE, 140324768841728, 140324819165183,
-ERASE, 140324768841728, 140324819165183,
-SNULL, 140324634623999, 140324668162047,
-STORE, 140324567515136, 140324634623999,
-STORE, 140324634624000, 140324668162047,
-ERASE, 140324634624000, 140324668162047,
-SNULL, 140324391333887, 140324525551615,
-STORE, 140324299079680, 140324391333887,
-STORE, 140324391333888, 140324525551615,
-SNULL, 140324391333888, 140324433297407,
-STORE, 140324433297408, 140324525551615,
-STORE, 140324391333888, 140324433297407,
-ERASE, 140324391333888, 140324433297407,
-SNULL, 140325507174399, 140325574148095,
-STORE, 140325507039232, 140325507174399,
-STORE, 140325507174400, 140325574148095,
-SNULL, 140325590867968, 140325599260671,
-STORE, 140325599260672, 140325607653375,
-STORE, 140325590867968, 140325599260671,
-SNULL, 140325599264767, 140325607653375,
-STORE, 140325599260672, 140325599264767,
-STORE, 140325599264768, 140325607653375,
-SNULL, 140325372956671, 140325439930367,
-STORE, 140325372821504, 140325372956671,
-STORE, 140325372956672, 140325439930367,
-SNULL, 140324668166143, 140324684947455,
-STORE, 140324668162048, 140324668166143,
-STORE, 140324668166144, 140324684947455,
-SNULL, 140324525555711, 140324533944319,
-STORE, 140324525551616, 140324525555711,
-STORE, 140324525555712, 140324533944319,
-SNULL, 140324953382912, 140324961775615,
-STORE, 140324961775616, 140324970168319,
-STORE, 140324953382912, 140324961775615,
-SNULL, 140324961779711, 140324970168319,
-STORE, 140324961775616, 140324961779711,
-STORE, 140324961779712, 140324970168319,
-SNULL, 140325079212031, 140325104386047,
-STORE, 140325079207936, 140325079212031,
-STORE, 140325079212032, 140325104386047,
-SNULL, 140325221818368, 140325230211071,
-STORE, 140325230211072, 140325238603775,
-STORE, 140325221818368, 140325230211071,
-SNULL, 140325230215167, 140325238603775,
-STORE, 140325230211072, 140325230215167,
-STORE, 140325230215168, 140325238603775,
-SNULL, 140325356036096, 140325364428799,
-STORE, 140325364428800, 140325372821503,
-STORE, 140325356036096, 140325364428799,
-SNULL, 140325364432895, 140325372821503,
- };
- unsigned long set40[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140734309167104, 140737488351231,
-SNULL, 140734309171199, 140737488351231,
-STORE, 140734309167104, 140734309171199,
-STORE, 140734309036032, 140734309171199,
-STORE, 94270500081664, 94270502334463,
-SNULL, 94270500212735, 94270502334463,
-STORE, 94270500081664, 94270500212735,
-STORE, 94270500212736, 94270502334463,
-ERASE, 94270500212736, 94270502334463,
-STORE, 94270502305792, 94270502313983,
-STORE, 94270502313984, 94270502334463,
-STORE, 140321935110144, 140321937362943,
-SNULL, 140321935253503, 140321937362943,
-STORE, 140321935110144, 140321935253503,
-STORE, 140321935253504, 140321937362943,
-ERASE, 140321935253504, 140321937362943,
-STORE, 140321937350656, 140321937358847,
-STORE, 140321937358848, 140321937362943,
-STORE, 140734309625856, 140734309629951,
-STORE, 140734309613568, 140734309625855,
-STORE, 140321937321984, 140321937350655,
-STORE, 140321937313792, 140321937321983,
-STORE, 140321932894208, 140321935110143,
-SNULL, 140321932894208, 140321932992511,
-STORE, 140321932992512, 140321935110143,
-STORE, 140321932894208, 140321932992511,
-SNULL, 140321935085567, 140321935110143,
-STORE, 140321932992512, 140321935085567,
-STORE, 140321935085568, 140321935110143,
-SNULL, 140321935085568, 140321935093759,
-STORE, 140321935093760, 140321935110143,
-STORE, 140321935085568, 140321935093759,
-ERASE, 140321935085568, 140321935093759,
-STORE, 140321935085568, 140321935093759,
-ERASE, 140321935093760, 140321935110143,
-STORE, 140321935093760, 140321935110143,
-STORE, 140321929097216, 140321932894207,
-SNULL, 140321929097216, 140321930756095,
-STORE, 140321930756096, 140321932894207,
-STORE, 140321929097216, 140321930756095,
-SNULL, 140321932853247, 140321932894207,
-STORE, 140321930756096, 140321932853247,
-STORE, 140321932853248, 140321932894207,
-SNULL, 140321932853248, 140321932877823,
-STORE, 140321932877824, 140321932894207,
-STORE, 140321932853248, 140321932877823,
-ERASE, 140321932853248, 140321932877823,
-STORE, 140321932853248, 140321932877823,
-ERASE, 140321932877824, 140321932894207,
-STORE, 140321932877824, 140321932894207,
-STORE, 140321937305600, 140321937321983,
-SNULL, 140321932869631, 140321932877823,
-STORE, 140321932853248, 140321932869631,
-STORE, 140321932869632, 140321932877823,
-SNULL, 140321935089663, 140321935093759,
-STORE, 140321935085568, 140321935089663,
-STORE, 140321935089664, 140321935093759,
-SNULL, 94270502309887, 94270502313983,
-STORE, 94270502305792, 94270502309887,
-STORE, 94270502309888, 94270502313983,
-SNULL, 140321937354751, 140321937358847,
-STORE, 140321937350656, 140321937354751,
-STORE, 140321937354752, 140321937358847,
-ERASE, 140321937321984, 140321937350655,
-STORE, 94270507364352, 94270507499519,
-STORE, 140321920704512, 140321929097215,
-SNULL, 140321920708607, 140321929097215,
-STORE, 140321920704512, 140321920708607,
-STORE, 140321920708608, 140321929097215,
-STORE, 140321912311808, 140321920704511,
-STORE, 140321778094080, 140321912311807,
-SNULL, 140321778094080, 140321816051711,
-STORE, 140321816051712, 140321912311807,
-STORE, 140321778094080, 140321816051711,
-ERASE, 140321778094080, 140321816051711,
-SNULL, 140321883160575, 140321912311807,
-STORE, 140321816051712, 140321883160575,
-STORE, 140321883160576, 140321912311807,
-ERASE, 140321883160576, 140321912311807,
-SNULL, 140321816186879, 140321883160575,
-STORE, 140321816051712, 140321816186879,
-STORE, 140321816186880, 140321883160575,
-SNULL, 140321912315903, 140321920704511,
-STORE, 140321912311808, 140321912315903,
-STORE, 140321912315904, 140321920704511,
-STORE, 140321903919104, 140321912311807,
-SNULL, 140321903923199, 140321912311807,
-STORE, 140321903919104, 140321903923199,
-STORE, 140321903923200, 140321912311807,
-STORE, 140321895526400, 140321903919103,
-SNULL, 140321895530495, 140321903919103,
-STORE, 140321895526400, 140321895530495,
-STORE, 140321895530496, 140321903919103,
-STORE, 140321887133696, 140321895526399,
-SNULL, 140321887137791, 140321895526399,
-STORE, 140321887133696, 140321887137791,
-STORE, 140321887137792, 140321895526399,
-STORE, 140321807659008, 140321816051711,
-STORE, 140321673441280, 140321807659007,
-SNULL, 140321673441280, 140321681833983,
-STORE, 140321681833984, 140321807659007,
-STORE, 140321673441280, 140321681833983,
-ERASE, 140321673441280, 140321681833983,
-SNULL, 140321748942847, 140321807659007,
-STORE, 140321681833984, 140321748942847,
-STORE, 140321748942848, 140321807659007,
-ERASE, 140321748942848, 140321807659007,
-STORE, 140321799266304, 140321816051711,
-STORE, 140321790873600, 140321816051711,
-STORE, 140321782480896, 140321816051711,
-STORE, 140321547616256, 140321748942847,
-SNULL, 140321614725119, 140321748942847,
-STORE, 140321547616256, 140321614725119,
-STORE, 140321614725120, 140321748942847,
-SNULL, 140321614725120, 140321681833983,
-STORE, 140321681833984, 140321748942847,
-STORE, 140321614725120, 140321681833983,
-ERASE, 140321614725120, 140321681833983,
-SNULL, 140321681969151, 140321748942847,
-STORE, 140321681833984, 140321681969151,
-STORE, 140321681969152, 140321748942847,
-STORE, 140321547616256, 140321681833983,
-SNULL, 140321547616256, 140321614725119,
-STORE, 140321614725120, 140321681833983,
-STORE, 140321547616256, 140321614725119,
-SNULL, 140321614860287, 140321681833983,
-STORE, 140321614725120, 140321614860287,
-STORE, 140321614860288, 140321681833983,
-SNULL, 140321547751423, 140321614725119,
-STORE, 140321547616256, 140321547751423,
-STORE, 140321547751424, 140321614725119,
-STORE, 140321480507392, 140321547616255,
-SNULL, 140321782480896, 140321799266303,
-STORE, 140321799266304, 140321816051711,
-STORE, 140321782480896, 140321799266303,
-SNULL, 140321799270399, 140321816051711,
-STORE, 140321799266304, 140321799270399,
-STORE, 140321799270400, 140321816051711,
-STORE, 140321774088192, 140321799266303,
-SNULL, 140321774088192, 140321790873599,
-STORE, 140321790873600, 140321799266303,
-STORE, 140321774088192, 140321790873599,
-SNULL, 140321790877695, 140321799266303,
-STORE, 140321790873600, 140321790877695,
-STORE, 140321790877696, 140321799266303,
-SNULL, 140321480642559, 140321547616255,
-STORE, 140321480507392, 140321480642559,
-STORE, 140321480642560, 140321547616255,
-SNULL, 140321774088192, 140321782480895,
-STORE, 140321782480896, 140321790873599,
-STORE, 140321774088192, 140321782480895,
-SNULL, 140321782484991, 140321790873599,
-STORE, 140321782480896, 140321782484991,
-STORE, 140321782484992, 140321790873599,
-SNULL, 140321799270400, 140321807659007,
-STORE, 140321807659008, 140321816051711,
-STORE, 140321799270400, 140321807659007,
-SNULL, 140321807663103, 140321816051711,
-STORE, 140321807659008, 140321807663103,
-STORE, 140321807663104, 140321816051711,
-STORE, 140321765695488, 140321782480895,
-STORE, 140321757302784, 140321782480895,
-SNULL, 140321757306879, 140321782480895,
-STORE, 140321757302784, 140321757306879,
-STORE, 140321757306880, 140321782480895,
-STORE, 140321472114688, 140321480507391,
-STORE, 140321463721984, 140321480507391,
-SNULL, 140321463726079, 140321480507391,
-STORE, 140321463721984, 140321463726079,
-STORE, 140321463726080, 140321480507391,
-SNULL, 140321757306880, 140321774088191,
-STORE, 140321774088192, 140321782480895,
-STORE, 140321757306880, 140321774088191,
-SNULL, 140321774092287, 140321782480895,
-STORE, 140321774088192, 140321774092287,
-STORE, 140321774092288, 140321782480895,
-SNULL, 140321463726080, 140321472114687,
-STORE, 140321472114688, 140321480507391,
-STORE, 140321463726080, 140321472114687,
-SNULL, 140321472118783, 140321480507391,
-STORE, 140321472114688, 140321472118783,
-STORE, 140321472118784, 140321480507391,
-SNULL, 140321757306880, 140321765695487,
-STORE, 140321765695488, 140321774088191,
-STORE, 140321757306880, 140321765695487,
-SNULL, 140321765699583, 140321774088191,
-STORE, 140321765695488, 140321765699583,
-STORE, 140321765699584, 140321774088191,
-STORE, 140321455329280, 140321463721983,
-SNULL, 140321455333375, 140321463721983,
-STORE, 140321455329280, 140321455333375,
-STORE, 140321455333376, 140321463721983,
-STORE, 140321446936576, 140321455329279,
-STORE, 140321438543872, 140321455329279,
-STORE, 140321430151168, 140321455329279,
-SNULL, 140321430155263, 140321455329279,
-STORE, 140321430151168, 140321430155263,
-STORE, 140321430155264, 140321455329279,
-SNULL, 140321430155264, 140321446936575,
-STORE, 140321446936576, 140321455329279,
-STORE, 140321430155264, 140321446936575,
-SNULL, 140321446940671, 140321455329279,
-STORE, 140321446936576, 140321446940671,
-STORE, 140321446940672, 140321455329279,
-SNULL, 140321430155264, 140321438543871,
-STORE, 140321438543872, 140321446936575,
-STORE, 140321430155264, 140321438543871,
-SNULL, 140321438547967, 140321446936575,
-STORE, 140321438543872, 140321438547967,
-STORE, 140321438547968, 140321446936575,
-STORE, 140321421758464, 140321430151167,
-SNULL, 140321421762559, 140321430151167,
-STORE, 140321421758464, 140321421762559,
-STORE, 140321421762560, 140321430151167,
-STORE, 140321413365760, 140321421758463,
-SNULL, 140321413369855, 140321421758463,
-STORE, 140321413365760, 140321413369855,
-STORE, 140321413369856, 140321421758463,
-STORE, 140321404973056, 140321413365759,
-SNULL, 140321404977151, 140321413365759,
-STORE, 140321404973056, 140321404977151,
-STORE, 140321404977152, 140321413365759,
-STORE, 140321396580352, 140321404973055,
-STORE, 140321388187648, 140321404973055,
-STORE, 140321253969920, 140321388187647,
-SNULL, 140321253969920, 140321279180799,
-STORE, 140321279180800, 140321388187647,
-STORE, 140321253969920, 140321279180799,
-ERASE, 140321253969920, 140321279180799,
-SNULL, 140321346289663, 140321388187647,
-STORE, 140321279180800, 140321346289663,
-STORE, 140321346289664, 140321388187647,
-ERASE, 140321346289664, 140321388187647,
-STORE, 140321144963072, 140321346289663,
-STORE, 140321379794944, 140321404973055,
-STORE, 140321371402240, 140321404973055,
-STORE, 140321010745344, 140321346289663,
-STORE, 140321363009536, 140321404973055,
-SNULL, 140321077854207, 140321346289663,
-STORE, 140321010745344, 140321077854207,
-STORE, 140321077854208, 140321346289663,
-SNULL, 140321077854208, 140321144963071,
-STORE, 140321144963072, 140321346289663,
-STORE, 140321077854208, 140321144963071,
-ERASE, 140321077854208, 140321144963071,
-STORE, 140321354616832, 140321404973055,
-STORE, 140321136570368, 140321144963071,
-STORE, 140320943636480, 140321077854207,
-STORE, 140320876527616, 140321077854207,
-STORE, 140321128177664, 140321144963071,
-SNULL, 140320876662783, 140321077854207,
-STORE, 140320876527616, 140320876662783,
-STORE, 140320876662784, 140321077854207,
-STORE, 140321119784960, 140321144963071,
-STORE, 140321111392256, 140321144963071,
-STORE, 140320742309888, 140320876527615,
-STORE, 140321102999552, 140321144963071,
-STORE, 140320608092160, 140320876527615,
-SNULL, 140320675201023, 140320876527615,
-STORE, 140320608092160, 140320675201023,
-STORE, 140320675201024, 140320876527615,
-SNULL, 140320675201024, 140320742309887,
-STORE, 140320742309888, 140320876527615,
-STORE, 140320675201024, 140320742309887,
-ERASE, 140320675201024, 140320742309887,
-STORE, 140321094606848, 140321144963071,
-STORE, 140321086214144, 140321144963071,
-STORE, 140320608092160, 140320876527615,
-SNULL, 140320608092160, 140320675201023,
-STORE, 140320675201024, 140320876527615,
-STORE, 140320608092160, 140320675201023,
-SNULL, 140320675336191, 140320876527615,
-STORE, 140320675201024, 140320675336191,
-STORE, 140320675336192, 140320876527615,
-STORE, 140320599699456, 140320608092159,
-STORE, 140320591306752, 140320608092159,
-STORE, 140320457089024, 140320591306751,
-STORE, 140320448696320, 140320457089023,
-STORE, 140320314478592, 140320448696319,
-SNULL, 140321144963072, 140321279180799,
-STORE, 140321279180800, 140321346289663,
-STORE, 140321144963072, 140321279180799,
-SNULL, 140321279315967, 140321346289663,
-STORE, 140321279180800, 140321279315967,
-STORE, 140321279315968, 140321346289663,
-SNULL, 140321086214144, 140321136570367,
-STORE, 140321136570368, 140321144963071,
-STORE, 140321086214144, 140321136570367,
-SNULL, 140321136574463, 140321144963071,
-STORE, 140321136570368, 140321136574463,
-STORE, 140321136574464, 140321144963071,
-SNULL, 140321212071935, 140321279180799,
-STORE, 140321144963072, 140321212071935,
-STORE, 140321212071936, 140321279180799,
-ERASE, 140321212071936, 140321279180799,
-SNULL, 140321145098239, 140321212071935,
-STORE, 140321144963072, 140321145098239,
-STORE, 140321145098240, 140321212071935,
-SNULL, 140320876662784, 140321010745343,
-STORE, 140321010745344, 140321077854207,
-STORE, 140320876662784, 140321010745343,
-SNULL, 140321010880511, 140321077854207,
-STORE, 140321010745344, 140321010880511,
-STORE, 140321010880512, 140321077854207,
-SNULL, 140321354616832, 140321379794943,
-STORE, 140321379794944, 140321404973055,
-STORE, 140321354616832, 140321379794943,
-SNULL, 140321379799039, 140321404973055,
-STORE, 140321379794944, 140321379799039,
-STORE, 140321379799040, 140321404973055,
-SNULL, 140320876662784, 140320943636479,
-STORE, 140320943636480, 140321010745343,
-STORE, 140320876662784, 140320943636479,
-SNULL, 140320943771647, 140321010745343,
-STORE, 140320943636480, 140320943771647,
-STORE, 140320943771648, 140321010745343,
-SNULL, 140320809418751, 140320876527615,
-STORE, 140320675336192, 140320809418751,
-STORE, 140320809418752, 140320876527615,
-ERASE, 140320809418752, 140320876527615,
-SNULL, 140320675336192, 140320742309887,
-STORE, 140320742309888, 140320809418751,
-STORE, 140320675336192, 140320742309887,
-SNULL, 140320742445055, 140320809418751,
-STORE, 140320742309888, 140320742445055,
-STORE, 140320742445056, 140320809418751,
-SNULL, 140320608227327, 140320675201023,
-STORE, 140320608092160, 140320608227327,
-STORE, 140320608227328, 140320675201023,
-SNULL, 140320457089024, 140320473874431,
-STORE, 140320473874432, 140320591306751,
-STORE, 140320457089024, 140320473874431,
-ERASE, 140320457089024, 140320473874431,
-SNULL, 140320540983295, 140320591306751,
-STORE, 140320473874432, 140320540983295,
-STORE, 140320540983296, 140320591306751,
-ERASE, 140320540983296, 140320591306751,
-SNULL, 140320314478592, 140320339656703,
-STORE, 140320339656704, 140320448696319,
-STORE, 140320314478592, 140320339656703,
-ERASE, 140320314478592, 140320339656703,
-SNULL, 140321086214144, 140321128177663,
-STORE, 140321128177664, 140321136570367,
-STORE, 140321086214144, 140321128177663,
-SNULL, 140321128181759, 140321136570367,
-STORE, 140321128177664, 140321128181759,
-STORE, 140321128181760, 140321136570367,
-SNULL, 140321354616832, 140321371402239,
-STORE, 140321371402240, 140321379794943,
-STORE, 140321354616832, 140321371402239,
-SNULL, 140321371406335, 140321379794943,
-STORE, 140321371402240, 140321371406335,
-STORE, 140321371406336, 140321379794943,
-SNULL, 140320591310847, 140320608092159,
-STORE, 140320591306752, 140320591310847,
-STORE, 140320591310848, 140320608092159,
-SNULL, 140321354616832, 140321363009535,
-STORE, 140321363009536, 140321371402239,
-STORE, 140321354616832, 140321363009535,
-SNULL, 140321363013631, 140321371402239,
-STORE, 140321363009536, 140321363013631,
-STORE, 140321363013632, 140321371402239,
-SNULL, 140321086214144, 140321119784959,
-STORE, 140321119784960, 140321128177663,
-STORE, 140321086214144, 140321119784959,
-SNULL, 140321119789055, 140321128177663,
-STORE, 140321119784960, 140321119789055,
-STORE, 140321119789056, 140321128177663,
-SNULL, 140321086218239, 140321119784959,
-STORE, 140321086214144, 140321086218239,
-STORE, 140321086218240, 140321119784959,
-SNULL, 140321086218240, 140321094606847,
-STORE, 140321094606848, 140321119784959,
-STORE, 140321086218240, 140321094606847,
-SNULL, 140321094610943, 140321119784959,
-STORE, 140321094606848, 140321094610943,
-STORE, 140321094610944, 140321119784959,
-SNULL, 140320474009599, 140320540983295,
-STORE, 140320473874432, 140320474009599,
-STORE, 140320474009600, 140320540983295,
-SNULL, 140320406765567, 140320448696319,
-STORE, 140320339656704, 140320406765567,
-STORE, 140320406765568, 140320448696319,
-ERASE, 140320406765568, 140320448696319,
-SNULL, 140320339791871, 140320406765567,
-STORE, 140320339656704, 140320339791871,
-STORE, 140320339791872, 140320406765567,
-STORE, 140321270788096, 140321279180799,
-STORE, 140321262395392, 140321279180799,
-STORE, 140321254002688, 140321279180799,
-SNULL, 140321254002688, 140321262395391,
-STORE, 140321262395392, 140321279180799,
-STORE, 140321254002688, 140321262395391,
-SNULL, 140321262399487, 140321279180799,
-STORE, 140321262395392, 140321262399487,
-STORE, 140321262399488, 140321279180799,
-STORE, 140321245609984, 140321262395391,
-STORE, 140321237217280, 140321262395391,
-SNULL, 140321237217280, 140321245609983,
-STORE, 140321245609984, 140321262395391,
-STORE, 140321237217280, 140321245609983,
-SNULL, 140321245614079, 140321262395391,
-STORE, 140321245609984, 140321245614079,
-STORE, 140321245614080, 140321262395391,
-SNULL, 140321379799040, 140321388187647,
-STORE, 140321388187648, 140321404973055,
-STORE, 140321379799040, 140321388187647,
-SNULL, 140321388191743, 140321404973055,
-STORE, 140321388187648, 140321388191743,
-STORE, 140321388191744, 140321404973055,
-SNULL, 140321354620927, 140321363009535,
-STORE, 140321354616832, 140321354620927,
-STORE, 140321354620928, 140321363009535,
-SNULL, 140321388191744, 140321396580351,
-STORE, 140321396580352, 140321404973055,
-STORE, 140321388191744, 140321396580351,
-SNULL, 140321396584447, 140321404973055,
-STORE, 140321396580352, 140321396584447,
-STORE, 140321396584448, 140321404973055,
-SNULL, 140321094610944, 140321111392255,
-STORE, 140321111392256, 140321119784959,
-STORE, 140321094610944, 140321111392255,
-SNULL, 140321111396351, 140321119784959,
-STORE, 140321111392256, 140321111396351,
-STORE, 140321111396352, 140321119784959,
-STORE, 140321228824576, 140321245609983,
-SNULL, 140321094610944, 140321102999551,
-STORE, 140321102999552, 140321111392255,
-STORE, 140321094610944, 140321102999551,
-SNULL, 140321103003647, 140321111392255,
-STORE, 140321102999552, 140321103003647,
-STORE, 140321103003648, 140321111392255,
-STORE, 140321220431872, 140321245609983,
-SNULL, 140321220435967, 140321245609983,
-STORE, 140321220431872, 140321220435967,
-STORE, 140321220435968, 140321245609983,
-STORE, 140320868134912, 140320876527615,
-SNULL, 140320868139007, 140320876527615,
-STORE, 140320868134912, 140320868139007,
-STORE, 140320868139008, 140320876527615,
-SNULL, 140320591310848, 140320599699455,
-STORE, 140320599699456, 140320608092159,
-STORE, 140320591310848, 140320599699455,
-SNULL, 140320599703551, 140320608092159,
-STORE, 140320599699456, 140320599703551,
-STORE, 140320599703552, 140320608092159,
-STORE, 140320859742208, 140320868134911,
-SNULL, 140321262399488, 140321270788095,
-STORE, 140321270788096, 140321279180799,
-STORE, 140321262399488, 140321270788095,
-SNULL, 140321270792191, 140321279180799,
-STORE, 140321270788096, 140321270792191,
-STORE, 140321270792192, 140321279180799,
-STORE, 140320851349504, 140320868134911,
-STORE, 140320842956800, 140320868134911,
-STORE, 140320834564096, 140320868134911,
-STORE, 140320826171392, 140320868134911,
-SNULL, 140320826171392, 140320834564095,
-STORE, 140320834564096, 140320868134911,
-STORE, 140320826171392, 140320834564095,
-SNULL, 140320834568191, 140320868134911,
-STORE, 140320834564096, 140320834568191,
-STORE, 140320834568192, 140320868134911,
-SNULL, 140321220435968, 140321228824575,
-STORE, 140321228824576, 140321245609983,
-STORE, 140321220435968, 140321228824575,
-SNULL, 140321228828671, 140321245609983,
-STORE, 140321228824576, 140321228828671,
-STORE, 140321228828672, 140321245609983,
-STORE, 140320817778688, 140320834564095,
-SNULL, 140320817782783, 140320834564095,
-STORE, 140320817778688, 140320817782783,
-STORE, 140320817782784, 140320834564095,
-STORE, 140320582914048, 140320591306751,
-SNULL, 140321228828672, 140321237217279,
-STORE, 140321237217280, 140321245609983,
-STORE, 140321228828672, 140321237217279,
-SNULL, 140321237221375, 140321245609983,
-STORE, 140321237217280, 140321237221375,
-STORE, 140321237221376, 140321245609983,
-SNULL, 140320448700415, 140320457089023,
-STORE, 140320448696320, 140320448700415,
-STORE, 140320448700416, 140320457089023,
-SNULL, 140321245614080, 140321254002687,
-STORE, 140321254002688, 140321262395391,
-STORE, 140321245614080, 140321254002687,
-SNULL, 140321254006783, 140321262395391,
-STORE, 140321254002688, 140321254006783,
-STORE, 140321254006784, 140321262395391,
-STORE, 140320574521344, 140320591306751,
-SNULL, 140320574525439, 140320591306751,
-STORE, 140320574521344, 140320574525439,
-STORE, 140320574525440, 140320591306751,
-STORE, 140320566128640, 140320574521343,
-SNULL, 140320566132735, 140320574521343,
-STORE, 140320566128640, 140320566132735,
-STORE, 140320566132736, 140320574521343,
-SNULL, 140320574525440, 140320582914047,
-STORE, 140320582914048, 140320591306751,
-STORE, 140320574525440, 140320582914047,
-SNULL, 140320582918143, 140320591306751,
-STORE, 140320582914048, 140320582918143,
-STORE, 140320582918144, 140320591306751,
-STORE, 140320557735936, 140320566128639,
-SNULL, 140320557740031, 140320566128639,
-STORE, 140320557735936, 140320557740031,
-STORE, 140320557740032, 140320566128639,
-STORE, 140320549343232, 140320557735935,
-STORE, 140320465481728, 140320473874431,
-STORE, 140320448700416, 140320473874431,
-SNULL, 140320834568192, 140320859742207,
-STORE, 140320859742208, 140320868134911,
-STORE, 140320834568192, 140320859742207,
-SNULL, 140320859746303, 140320868134911,
-STORE, 140320859742208, 140320859746303,
-STORE, 140320859746304, 140320868134911,
-STORE, 140320440303616, 140320448696319,
-STORE, 140320431910912, 140320448696319,
-SNULL, 140320834568192, 140320851349503,
-STORE, 140320851349504, 140320859742207,
-STORE, 140320834568192, 140320851349503,
-SNULL, 140320851353599, 140320859742207,
-STORE, 140320851349504, 140320851353599,
-STORE, 140320851353600, 140320859742207,
-SNULL, 140320817782784, 140320826171391,
-STORE, 140320826171392, 140320834564095,
-STORE, 140320817782784, 140320826171391,
-SNULL, 140320826175487, 140320834564095,
-STORE, 140320826171392, 140320826175487,
-STORE, 140320826175488, 140320834564095,
-SNULL, 140320834568192, 140320842956799,
-STORE, 140320842956800, 140320851349503,
-STORE, 140320834568192, 140320842956799,
-SNULL, 140320842960895, 140320851349503,
-STORE, 140320842956800, 140320842960895,
-STORE, 140320842960896, 140320851349503,
-STORE, 140320423518208, 140320448696319,
-SNULL, 140320423522303, 140320448696319,
-STORE, 140320423518208, 140320423522303,
-STORE, 140320423522304, 140320448696319,
-STORE, 140320415125504, 140320423518207,
-STORE, 140320331264000, 140320339656703,
-STORE, 140320322871296, 140320339656703,
-STORE, 140320314478592, 140320339656703,
-SNULL, 140320314482687, 140320339656703,
-STORE, 140320314478592, 140320314482687,
-STORE, 140320314482688, 140320339656703,
-STORE, 140320306085888, 140320314478591,
-SNULL, 140320306089983, 140320314478591,
-STORE, 140320306085888, 140320306089983,
-STORE, 140320306089984, 140320314478591,
-STORE, 140320297693184, 140320306085887,
-SNULL, 140320297697279, 140320306085887,
-STORE, 140320297693184, 140320297697279,
-STORE, 140320297697280, 140320306085887,
-STORE, 140320289300480, 140320297693183,
-STORE, 140320280907776, 140320297693183,
-SNULL, 140320280911871, 140320297693183,
-STORE, 140320280907776, 140320280911871,
-STORE, 140320280911872, 140320297693183,
-SNULL, 140320423522304, 140320431910911,
-STORE, 140320431910912, 140320448696319,
-STORE, 140320423522304, 140320431910911,
-SNULL, 140320431915007, 140320448696319,
-STORE, 140320431910912, 140320431915007,
-STORE, 140320431915008, 140320448696319,
-SNULL, 140320549347327, 140320557735935,
-STORE, 140320549343232, 140320549347327,
-STORE, 140320549347328, 140320557735935,
-STORE, 140320272515072, 140320280907775,
-SNULL, 140320448700416, 140320457089023,
-STORE, 140320457089024, 140320473874431,
-STORE, 140320448700416, 140320457089023,
-SNULL, 140320457093119, 140320473874431,
-STORE, 140320457089024, 140320457093119,
-STORE, 140320457093120, 140320473874431,
-STORE, 140320264122368, 140320280907775,
-SNULL, 140320457093120, 140320465481727,
-STORE, 140320465481728, 140320473874431,
-STORE, 140320457093120, 140320465481727,
-SNULL, 140320465485823, 140320473874431,
-STORE, 140320465481728, 140320465485823,
-STORE, 140320465485824, 140320473874431,
-SNULL, 140320431915008, 140320440303615,
-STORE, 140320440303616, 140320448696319,
-STORE, 140320431915008, 140320440303615,
-SNULL, 140320440307711, 140320448696319,
-STORE, 140320440303616, 140320440307711,
-STORE, 140320440307712, 140320448696319,
-STORE, 140320255729664, 140320280907775,
-STORE, 140320247336960, 140320280907775,
-SNULL, 140320247341055, 140320280907775,
-STORE, 140320247336960, 140320247341055,
-STORE, 140320247341056, 140320280907775,
-STORE, 140320238944256, 140320247336959,
-STORE, 140320230551552, 140320247336959,
-SNULL, 140320230551552, 140320238944255,
-STORE, 140320238944256, 140320247336959,
-STORE, 140320230551552, 140320238944255,
-SNULL, 140320238948351, 140320247336959,
-STORE, 140320238944256, 140320238948351,
-STORE, 140320238948352, 140320247336959,
-SNULL, 140320314482688, 140320331263999,
-STORE, 140320331264000, 140320339656703,
-STORE, 140320314482688, 140320331263999,
-SNULL, 140320331268095, 140320339656703,
-STORE, 140320331264000, 140320331268095,
-STORE, 140320331268096, 140320339656703,
-SNULL, 140320280911872, 140320289300479,
-STORE, 140320289300480, 140320297693183,
-STORE, 140320280911872, 140320289300479,
-SNULL, 140320289304575, 140320297693183,
-STORE, 140320289300480, 140320289304575,
-STORE, 140320289304576, 140320297693183,
-SNULL, 140320415129599, 140320423518207,
-STORE, 140320415125504, 140320415129599,
-STORE, 140320415129600, 140320423518207,
-STORE, 140320222158848, 140320238944255,
-STORE, 140320213766144, 140320238944255,
-STORE, 140320205373440, 140320238944255,
-SNULL, 140320205377535, 140320238944255,
-STORE, 140320205373440, 140320205377535,
-STORE, 140320205377536, 140320238944255,
-SNULL, 140320314482688, 140320322871295,
-STORE, 140320322871296, 140320331263999,
-STORE, 140320314482688, 140320322871295,
-SNULL, 140320322875391, 140320331263999,
-STORE, 140320322871296, 140320322875391,
-STORE, 140320322875392, 140320331263999,
-SNULL, 140320247341056, 140320272515071,
-STORE, 140320272515072, 140320280907775,
-STORE, 140320247341056, 140320272515071,
-SNULL, 140320272519167, 140320280907775,
-STORE, 140320272515072, 140320272519167,
-STORE, 140320272519168, 140320280907775,
-SNULL, 140320247341056, 140320264122367,
-STORE, 140320264122368, 140320272515071,
-STORE, 140320247341056, 140320264122367,
-SNULL, 140320264126463, 140320272515071,
-STORE, 140320264122368, 140320264126463,
-STORE, 140320264126464, 140320272515071,
-SNULL, 140320205377536, 140320230551551,
-STORE, 140320230551552, 140320238944255,
-STORE, 140320205377536, 140320230551551,
-SNULL, 140320230555647, 140320238944255,
-STORE, 140320230551552, 140320230555647,
-STORE, 140320230555648, 140320238944255,
-STORE, 140320196980736, 140320205373439,
-SNULL, 140320196984831, 140320205373439,
-STORE, 140320196980736, 140320196984831,
-STORE, 140320196984832, 140320205373439,
-STORE, 140320188588032, 140320196980735,
-SNULL, 140320247341056, 140320255729663,
-STORE, 140320255729664, 140320264122367,
-STORE, 140320247341056, 140320255729663,
-SNULL, 140320255733759, 140320264122367,
-STORE, 140320255729664, 140320255733759,
-STORE, 140320255733760, 140320264122367,
-STORE, 140320180195328, 140320196980735,
-SNULL, 140320180199423, 140320196980735,
-STORE, 140320180195328, 140320180199423,
-STORE, 140320180199424, 140320196980735,
-STORE, 140320171802624, 140320180195327,
-STORE, 140320163409920, 140320180195327,
-SNULL, 140320163414015, 140320180195327,
-STORE, 140320163409920, 140320163414015,
-STORE, 140320163414016, 140320180195327,
-SNULL, 140320205377536, 140320222158847,
-STORE, 140320222158848, 140320230551551,
-STORE, 140320205377536, 140320222158847,
-SNULL, 140320222162943, 140320230551551,
-STORE, 140320222158848, 140320222162943,
-STORE, 140320222162944, 140320230551551,
-SNULL, 140320205377536, 140320213766143,
-STORE, 140320213766144, 140320222158847,
-STORE, 140320205377536, 140320213766143,
-SNULL, 140320213770239, 140320222158847,
-STORE, 140320213766144, 140320213770239,
-STORE, 140320213770240, 140320222158847,
-STORE, 140320155017216, 140320163409919,
-SNULL, 140320180199424, 140320188588031,
-STORE, 140320188588032, 140320196980735,
-STORE, 140320180199424, 140320188588031,
-SNULL, 140320188592127, 140320196980735,
-STORE, 140320188588032, 140320188592127,
-STORE, 140320188592128, 140320196980735,
-SNULL, 140320155021311, 140320163409919,
-STORE, 140320155017216, 140320155021311,
-STORE, 140320155021312, 140320163409919,
-SNULL, 140320163414016, 140320171802623,
-STORE, 140320171802624, 140320180195327,
-STORE, 140320163414016, 140320171802623,
-SNULL, 140320171806719, 140320180195327,
-STORE, 140320171802624, 140320171806719,
-STORE, 140320171806720, 140320180195327,
-STORE, 140320146624512, 140320155017215,
-SNULL, 140320146628607, 140320155017215,
-STORE, 140320146624512, 140320146628607,
-STORE, 140320146628608, 140320155017215,
-STORE, 140321937321984, 140321937350655,
-STORE, 140321884942336, 140321887133695,
-SNULL, 140321884942336, 140321885032447,
-STORE, 140321885032448, 140321887133695,
-STORE, 140321884942336, 140321885032447,
-SNULL, 140321887125503, 140321887133695,
-STORE, 140321885032448, 140321887125503,
-STORE, 140321887125504, 140321887133695,
-ERASE, 140321887125504, 140321887133695,
-STORE, 140321887125504, 140321887133695,
-SNULL, 140321887129599, 140321887133695,
-STORE, 140321887125504, 140321887129599,
-STORE, 140321887129600, 140321887133695,
-ERASE, 140321937321984, 140321937350655,
-ERASE, 140321086214144, 140321086218239,
-ERASE, 140321086218240, 140321094606847,
-ERASE, 140321119784960, 140321119789055,
-ERASE, 140321119789056, 140321128177663,
-ERASE, 140321245609984, 140321245614079,
-ERASE, 140321245614080, 140321254002687,
-ERASE, 140320574521344, 140320574525439,
-ERASE, 140320574525440, 140320582914047,
-ERASE, 140320297693184, 140320297697279,
-ERASE, 140320297697280, 140320306085887,
-ERASE, 140321354616832, 140321354620927,
-ERASE, 140321354620928, 140321363009535,
-ERASE, 140320834564096, 140320834568191,
-ERASE, 140320834568192, 140320842956799,
-ERASE, 140320591306752, 140320591310847,
-ERASE, 140320591310848, 140320599699455,
-ERASE, 140321136570368, 140321136574463,
-ERASE, 140321136574464, 140321144963071,
-ERASE, 140321237217280, 140321237221375,
-ERASE, 140321237221376, 140321245609983,
-ERASE, 140321363009536, 140321363013631,
-ERASE, 140321363013632, 140321371402239,
-ERASE, 140320599699456, 140320599703551,
-ERASE, 140320599703552, 140320608092159,
-ERASE, 140321396580352, 140321396584447,
-ERASE, 140321396584448, 140321404973055,
-ERASE, 140320566128640, 140320566132735,
-ERASE, 140320566132736, 140320574521343,
-ERASE, 140321094606848, 140321094610943,
-ERASE, 140321094610944, 140321102999551,
-ERASE, 140320582914048, 140320582918143,
-ERASE, 140320582918144, 140320591306751,
-ERASE, 140320289300480, 140320289304575,
-ERASE, 140320289304576, 140320297693183,
-ERASE, 140320163409920, 140320163414015,
- };
- unsigned long set41[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140728157171712, 140737488351231,
-SNULL, 140728157175807, 140737488351231,
-STORE, 140728157171712, 140728157175807,
-STORE, 140728157040640, 140728157175807,
-STORE, 94376106364928, 94376108613631,
-SNULL, 94376106487807, 94376108613631,
-STORE, 94376106364928, 94376106487807,
-STORE, 94376106487808, 94376108613631,
-SNULL, 94376106487808, 94376108613631,
-STORE, 94376108584960, 94376108593151,
-STORE, 94376108593152, 94376108613631,
-STORE, 140113496432640, 140113498685439,
-SNULL, 140113496575999, 140113498685439,
-STORE, 140113496432640, 140113496575999,
-STORE, 140113496576000, 140113498685439,
-SNULL, 140113496576000, 140113498685439,
-STORE, 140113498673152, 140113498681343,
-STORE, 140113498681344, 140113498685439,
-STORE, 140728157609984, 140728157618175,
-STORE, 140728157593600, 140728157609983,
-STORE, 140113498636288, 140113498673151,
-STORE, 140113498628096, 140113498636287,
-STORE, 140113492635648, 140113496432639,
-SNULL, 140113492635648, 140113494294527,
-STORE, 140113494294528, 140113496432639,
-STORE, 140113492635648, 140113494294527,
-SNULL, 140113496391679, 140113496432639,
-STORE, 140113494294528, 140113496391679,
-STORE, 140113496391680, 140113496432639,
-SNULL, 140113496391680, 140113496416255,
-STORE, 140113496416256, 140113496432639,
-STORE, 140113496391680, 140113496416255,
-SNULL, 140113496391680, 140113496416255,
-STORE, 140113496391680, 140113496416255,
-SNULL, 140113496416256, 140113496432639,
-STORE, 140113496416256, 140113496432639,
-SNULL, 140113496408063, 140113496416255,
-STORE, 140113496391680, 140113496408063,
-STORE, 140113496408064, 140113496416255,
-SNULL, 94376108589055, 94376108593151,
-STORE, 94376108584960, 94376108589055,
-STORE, 94376108589056, 94376108593151,
-SNULL, 140113498677247, 140113498681343,
-STORE, 140113498673152, 140113498677247,
-STORE, 140113498677248, 140113498681343,
-SNULL, 140113498636288, 140113498673151,
-STORE, 94376135090176, 94376135094271,
-STORE, 94376135090176, 94376135098367,
-STORE, 94376139288576, 94376139292671,
-STORE, 94376143482880, 94376143486975,
-STORE, 94376147677184, 94376147681279,
-STORE, 94376151871488, 94376151875583,
-STORE, 94376156065792, 94376156069887,
-STORE, 94376160260096, 94376160264191,
-STORE, 94376164454400, 94376164458495,
-STORE, 94376168648704, 94376168652799,
-STORE, 94376172843008, 94376172847103,
-STORE, 94376177037312, 94376177041407,
-STORE, 94376181231616, 94376181235711,
-STORE, 94376185425920, 94376185430015,
-STORE, 94376189620224, 94376189624319,
-STORE, 94376193814528, 94376193818623,
-STORE, 94376198008832, 94376198012927,
-STORE, 94376202203136, 94376202207231,
-STORE, 94376206397440, 94376206401535,
-STORE, 94376210591744, 94376210595839,
-STORE, 94376214786048, 94376214790143,
-STORE, 94376218980352, 94376218984447,
-STORE, 94376223174656, 94376223178751,
-STORE, 94376227368960, 94376227373055,
-STORE, 94376231563264, 94376231567359,
-STORE, 94376235757568, 94376235761663,
-STORE, 94376239951872, 94376239955967,
-STORE, 94376244146176, 94376244150271,
-STORE, 94376248340480, 94376248344575,
-STORE, 94376252534784, 94376252538879,
-STORE, 94376256729088, 94376256733183,
-STORE, 94376260923392, 94376260927487,
-STORE, 94376265117696, 94376265121791,
-STORE, 94376269312000, 94376269316095,
-STORE, 94376273506304, 94376273510399,
-STORE, 94376277700608, 94376277704703,
-STORE, 94376281894912, 94376281899007,
-STORE, 94376286089216, 94376286093311,
-STORE, 94376290283520, 94376290287615,
-STORE, 94376294477824, 94376294481919,
-STORE, 94376298672128, 94376298676223,
-STORE, 94376302866432, 94376302870527,
-STORE, 94376307060736, 94376307064831,
-STORE, 94376311255040, 94376311259135,
-STORE, 94376315449344, 94376315453439,
-STORE, 94376319643648, 94376319647743,
-STORE, 94376323837952, 94376323842047,
-STORE, 94376328032256, 94376328036351,
-STORE, 94376332226560, 94376332230655,
-STORE, 94376336420864, 94376336424959,
-STORE, 94376340615168, 94376340619263,
-STORE, 94376344809472, 94376344813567,
-STORE, 94376349003776, 94376349007871,
-STORE, 94376353198080, 94376353202175,
-STORE, 94376357392384, 94376357396479,
-STORE, 94376361586688, 94376361590783,
-STORE, 94376365780992, 94376365785087,
-STORE, 94376369975296, 94376369979391,
-STORE, 94376374169600, 94376374173695,
-STORE, 94376378363904, 94376378367999,
-STORE, 94376382558208, 94376382562303,
-STORE, 94376386752512, 94376386756607,
-STORE, 94376390946816, 94376390950911,
-STORE, 94376395141120, 94376395145215,
-STORE, 94376399335424, 94376399339519,
-STORE, 94376403529728, 94376403533823,
-STORE, 94376407724032, 94376407728127,
-STORE, 94376411918336, 94376411922431,
-STORE, 94376416112640, 94376416116735,
-STORE, 94376420306944, 94376420311039,
-STORE, 94376424501248, 94376424505343,
-STORE, 94376428695552, 94376428699647,
-STORE, 94376432889856, 94376432893951,
-STORE, 94376437084160, 94376437088255,
-STORE, 94376441278464, 94376441282559,
-STORE, 94376445472768, 94376445476863,
-STORE, 94376449667072, 94376449671167,
-STORE, 94376453861376, 94376453865471,
-STORE, 94376458055680, 94376458059775,
-STORE, 94376462249984, 94376462254079,
-STORE, 94376466444288, 94376466448383,
-STORE, 94376470638592, 94376470642687,
-STORE, 94376474832896, 94376474836991,
-STORE, 94376479027200, 94376479031295,
-STORE, 94376483221504, 94376483225599,
-STORE, 94376487415808, 94376487419903,
-STORE, 94376491610112, 94376491614207,
-STORE, 94376495804416, 94376495808511,
-STORE, 94376499998720, 94376500002815,
-STORE, 94376504193024, 94376504197119,
-STORE, 94376508387328, 94376508391423,
-STORE, 94376512581632, 94376512585727,
-STORE, 94376516775936, 94376516780031,
-STORE, 94376520970240, 94376520974335,
-STORE, 94376525164544, 94376525168639,
-STORE, 94376529358848, 94376529362943,
-STORE, 94376533553152, 94376533557247,
-STORE, 94376537747456, 94376537751551,
-STORE, 94376541941760, 94376541945855,
-STORE, 94376546136064, 94376546140159,
-STORE, 94376550330368, 94376550334463,
-STORE, 94376554524672, 94376554528767,
-STORE, 94376558718976, 94376558723071,
-STORE, 94376562913280, 94376562917375,
-STORE, 94376567107584, 94376567111679,
-STORE, 94376571301888, 94376571305983,
-STORE, 94376575496192, 94376575500287,
-STORE, 94376579690496, 94376579694591,
-STORE, 94376583884800, 94376583888895,
-STORE, 94376588079104, 94376588083199,
-STORE, 94376592273408, 94376592277503,
-STORE, 94376596467712, 94376596471807,
-STORE, 94376600662016, 94376600666111,
-STORE, 94376604856320, 94376604860415,
-STORE, 94376609050624, 94376609054719,
-STORE, 94376613244928, 94376613249023,
-STORE, 94376617439232, 94376617443327,
-STORE, 94376621633536, 94376621637631,
-STORE, 94376625827840, 94376625831935,
-STORE, 94376630022144, 94376630026239,
-STORE, 94376634216448, 94376634220543,
-STORE, 94376638410752, 94376638414847,
-STORE, 94376642605056, 94376642609151,
-STORE, 94376646799360, 94376646803455,
-STORE, 94376650993664, 94376650997759,
-STORE, 94376655187968, 94376655192063,
-STORE, 94376659382272, 94376659386367,
-STORE, 94376663576576, 94376663580671,
-STORE, 94376667770880, 94376667774975,
-STORE, 94376671965184, 94376671969279,
-STORE, 94376676159488, 94376676163583,
-STORE, 94376680353792, 94376680357887,
-STORE, 94376684548096, 94376684552191,
-STORE, 94376688742400, 94376688746495,
-STORE, 94376692936704, 94376692940799,
-STORE, 94376697131008, 94376697135103,
-STORE, 94376701325312, 94376701329407,
-STORE, 94376705519616, 94376705523711,
-STORE, 94376709713920, 94376709718015,
-STORE, 94376713908224, 94376713912319,
-STORE, 94376718102528, 94376718106623,
-STORE, 94376722296832, 94376722300927,
-STORE, 94376726491136, 94376726495231,
-STORE, 94376730685440, 94376730689535,
-STORE, 94376734879744, 94376734883839,
-STORE, 94376739074048, 94376739078143,
-STORE, 94376743268352, 94376743272447,
-STORE, 94376747462656, 94376747466751,
-STORE, 94376751656960, 94376751661055,
-STORE, 94376755851264, 94376755855359,
-STORE, 94376760045568, 94376760049663,
-STORE, 94376764239872, 94376764243967,
-STORE, 94376768434176, 94376768438271,
-STORE, 94376772628480, 94376772632575,
-STORE, 94376776822784, 94376776826879,
-STORE, 94376781017088, 94376781021183,
-STORE, 94376785211392, 94376785215487,
-STORE, 94376789405696, 94376789409791,
-STORE, 94376793600000, 94376793604095,
-STORE, 94376797794304, 94376797798399,
-STORE, 94376801988608, 94376801992703,
-STORE, 94376806182912, 94376806187007,
-STORE, 94376810377216, 94376810381311,
-STORE, 94376814571520, 94376814575615,
-STORE, 94376818765824, 94376818769919,
-STORE, 94376822960128, 94376822964223,
-STORE, 94376827154432, 94376827158527,
-STORE, 94376831348736, 94376831352831,
-STORE, 94376835543040, 94376835547135,
-STORE, 94376839737344, 94376839741439,
-STORE, 94376843931648, 94376843935743,
-STORE, 94376848125952, 94376848130047,
-STORE, 94376852320256, 94376852324351,
-STORE, 94376856514560, 94376856518655,
-STORE, 94376860708864, 94376860712959,
-STORE, 94376864903168, 94376864907263,
-STORE, 94376869097472, 94376869101567,
-STORE, 94376873291776, 94376873295871,
-STORE, 94376877486080, 94376877490175,
-STORE, 94376881680384, 94376881684479,
-STORE, 94376885874688, 94376885878783,
-STORE, 94376890068992, 94376890073087,
-STORE, 94376894263296, 94376894267391,
-STORE, 94376898457600, 94376898461695,
-STORE, 94376902651904, 94376902655999,
-STORE, 94376906846208, 94376906850303,
-STORE, 94376911040512, 94376911044607,
-STORE, 94376915234816, 94376915238911,
-STORE, 94376919429120, 94376919433215,
-STORE, 94376923623424, 94376923627519,
-STORE, 94376927817728, 94376927821823,
-STORE, 94376932012032, 94376932016127,
-STORE, 94376936206336, 94376936210431,
-STORE, 94376940400640, 94376940404735,
-STORE, 94376944594944, 94376944599039,
-STORE, 94376948789248, 94376948793343,
-STORE, 94376952983552, 94376952987647,
-STORE, 94376957177856, 94376957181951,
-STORE, 94376961372160, 94376961376255,
-STORE, 94376965566464, 94376965570559,
-STORE, 94376969760768, 94376969764863,
-STORE, 94376973955072, 94376973959167,
-STORE, 94376978149376, 94376978153471,
-STORE, 94376982343680, 94376982347775,
-STORE, 94376986537984, 94376986542079,
-STORE, 94376990732288, 94376990736383,
-STORE, 94376994926592, 94376994930687,
-STORE, 94376999120896, 94376999124991,
-STORE, 94377003315200, 94377003319295,
-STORE, 94377007509504, 94377007513599,
-STORE, 94377011703808, 94377011707903,
-STORE, 94377015898112, 94377015902207,
-STORE, 94377020092416, 94377020096511,
-STORE, 94377024286720, 94377024290815,
-STORE, 94377028481024, 94377028485119,
-STORE, 94377032675328, 94377032679423,
-STORE, 94377036869632, 94377036873727,
-STORE, 94377041063936, 94377041068031,
-STORE, 94377045258240, 94377045262335,
-STORE, 94377049452544, 94377049456639,
-STORE, 94377053646848, 94377053650943,
-STORE, 94377057841152, 94377057845247,
-STORE, 94377062035456, 94377062039551,
-STORE, 94377066229760, 94377066233855,
-STORE, 94377070424064, 94377070428159,
-STORE, 94377074618368, 94377074622463,
-STORE, 94377078812672, 94377078816767,
-STORE, 94377083006976, 94377083011071,
-STORE, 94377087201280, 94377087205375,
-STORE, 94377091395584, 94377091399679,
-STORE, 94377095589888, 94377095593983,
-STORE, 94377099784192, 94377099788287,
-STORE, 94377103978496, 94377103982591,
-STORE, 94377108172800, 94377108176895,
-STORE, 94377112367104, 94377112371199,
-STORE, 94377116561408, 94377116565503,
-STORE, 94377120755712, 94377120759807,
-STORE, 94377124950016, 94377124954111,
-STORE, 94377129144320, 94377129148415,
-STORE, 94377133338624, 94377133342719,
-STORE, 94377137532928, 94377137537023,
-STORE, 94377141727232, 94377141731327,
-STORE, 94377145921536, 94377145925631,
-STORE, 94377150115840, 94377150119935,
-STORE, 94377154310144, 94377154314239,
-STORE, 94377158504448, 94377158508543,
-STORE, 94377162698752, 94377162702847,
-STORE, 94377166893056, 94377166897151,
-STORE, 94377171087360, 94377171091455,
-STORE, 94377175281664, 94377175285759,
-STORE, 94377179475968, 94377179480063,
-STORE, 94377183670272, 94377183674367,
-STORE, 94377187864576, 94377187868671,
-STORE, 94377192058880, 94377192062975,
-STORE, 94377196253184, 94377196257279,
-STORE, 94377200447488, 94377200451583,
-STORE, 94377204641792, 94377204645887,
-SNULL, 94376135094271, 94376135098367,
-STORE, 94376135090176, 94376135094271,
-STORE, 94376135094272, 94376135098367,
-SNULL, 94376135094272, 94377208836095,
- };
- unsigned long set42[] = {
-STORE, 314572800, 1388314623,
-STORE, 1462157312, 1462169599,
-STORE, 1462169600, 1462185983,
-STORE, 1462185984, 1462190079,
-STORE, 1462190080, 1462194175,
-STORE, 1462194176, 1462198271,
-STORE, 1879986176, 1881800703,
-STORE, 1881800704, 1882034175,
-STORE, 1882034176, 1882193919,
-STORE, 1882193920, 1882406911,
-STORE, 1882406912, 1882451967,
-STORE, 1882451968, 1882996735,
-STORE, 1882996736, 1885892607,
-STORE, 1885892608, 1885896703,
-STORE, 1885896704, 1885904895,
-STORE, 1885904896, 1885908991,
-STORE, 1885908992, 1885913087,
-STORE, 1885913088, 1885966335,
-STORE, 1885966336, 1886232575,
-STORE, 1886232576, 1886236671,
-STORE, 1886236672, 1886240767,
-STORE, 1886240768, 1886244863,
-STORE, 1886244864, 1886248959,
-STORE, 1886248960, 1886294015,
-STORE, 1886294016, 1886494719,
-STORE, 1886494720, 1886498815,
-STORE, 1886498816, 1886502911,
-STORE, 1886502912, 1886507007,
-STORE, 1886507008, 1886511103,
-STORE, 1886511104, 1886556159,
-STORE, 1886556160, 1886629887,
-STORE, 1886629888, 1886633983,
-STORE, 1886633984, 1886638079,
-STORE, 1886638080, 1886642175,
-STORE, 1886642176, 1886646271,
-STORE, 1886646272, 1886666751,
-STORE, 1886666752, 1886670847,
-STORE, 1886670848, 1886674943,
-STORE, 1886674944, 1886679039,
-STORE, 1886679040, 1895419903,
-STORE, 1895419904, 1895550975,
-STORE, 1895550976, 1896148991,
-STORE, 1896148992, 1897189375,
-STORE, 1897189376, 1897701375,
-STORE, 1897701376, 1897803775,
-STORE, 1897803776, 1897816063,
-STORE, 1897816064, 1899913215,
-STORE, 1899913216, 1909379071,
-STORE, 1909379072, 1909387263,
-STORE, 1909387264, 1909391359,
-STORE, 1909391360, 1909432319,
-STORE, 1909432320, 1909436415,
-STORE, 1909436416, 1909440511,
-STORE, 1909440512, 1909460991,
-STORE, 1909460992, 1909547007,
-STORE, 1909547008, 1909551103,
-STORE, 1909551104, 1909555199,
-STORE, 1909555200, 1909559295,
-STORE, 1909559296, 1909563391,
-STORE, 1909563392, 1909739519,
-STORE, 1909739520, 1910566911,
-STORE, 1910566912, 1910571007,
-STORE, 1910571008, 1910575103,
-STORE, 1910575104, 1910579199,
-STORE, 1910579200, 1910583295,
-STORE, 1910583296, 1910587391,
-STORE, 1910587392, 1910620159,
-STORE, 1910620160, 1910624255,
-STORE, 1910624256, 1910628351,
-STORE, 1910628352, 1910632447,
-STORE, 1910632448, 1910652927,
-STORE, 1910652928, 1910657023,
-STORE, 1910657024, 1910661119,
-STORE, 1910661120, 1910665215,
-STORE, 1910665216, 1910669311,
-STORE, 1910669312, 1910677503,
-STORE, 1910677504, 1910681599,
-STORE, 1910681600, 1910685695,
-STORE, 1910685696, 1910689791,
-STORE, 1910689792, 1910697983,
-STORE, 1910697984, 1910702079,
-STORE, 1910702080, 1910706175,
-STORE, 1910706176, 1910710271,
-STORE, 1910710272, 1914093567,
-STORE, 1914093568, 1914097663,
-STORE, 1914097664, 1969434623,
-STORE, 1969434624, 1977819135,
-STORE, 3290435584, 3426750463,
-STORE, 3426750464, 3426754559,
-STORE, 3426754560, 3426762751,
-STORE, 3426762752, 3426766847,
-STORE, 3426766848, 3426770943,
-STORE, 3427037184, 3427061759,
-STORE, 3427061760, 3427135487,
-STORE, 3427135488, 3427143679,
-STORE, 3427143680, 3427147775,
-STORE, 3427147776, 3427209215,
-STORE, 3427319808, 3432116223,
-STORE, 3432116224, 3450130431,
-STORE, 3450130432, 3451027455,
-STORE, 3451027456, 3451031551,
-STORE, 3451031552, 3451461631,
-STORE, 3451736064, 3456688127,
-STORE, 3456688128, 3475222527,
-STORE, 3475222528, 3476119551,
-STORE, 3476119552, 3476127743,
-STORE, 3476127744, 3476553727,
-STORE, 3476631552, 3477315583,
-STORE, 3477315584, 3479949311,
-STORE, 3479949312, 3480002559,
-STORE, 3480002560, 3480006655,
-STORE, 3480006656, 3480432639,
-STORE, 3480539136, 3480543231,
-STORE, 3480543232, 3480547327,
-STORE, 3480547328, 3480555519,
-STORE, 3480854528, 3480903679,
-STORE, 3480903680, 3480969215,
-STORE, 3480969216, 3480977407,
-STORE, 3480977408, 3480981503,
-STORE, 3481030656, 3481092095,
-STORE, 3481092096, 3481235455,
-STORE, 3481235456, 3481243647,
-STORE, 3481243648, 3481247743,
-STORE, 3481436160, 3481444351,
-STORE, 3481444352, 3481456639,
-STORE, 3481456640, 3481460735,
-STORE, 3481460736, 3481464831,
-STORE, 3481587712, 3481645055,
-STORE, 3481645056, 3481772031,
-STORE, 3481772032, 3481776127,
-STORE, 3481776128, 3481780223,
-STORE, 3481874432, 3481935871,
-STORE, 3481935872, 3482030079,
-STORE, 3482030080, 3482038271,
-STORE, 3482038272, 3482042367,
-STORE, 3482198016, 3482230783,
-STORE, 3482230784, 3482271743,
-STORE, 3482271744, 3482279935,
-STORE, 3482279936, 3482284031,
-STORE, 3482562560, 3482566655,
-STORE, 3482566656, 3482570751,
-STORE, 3482570752, 3482574847,
-STORE, 3482636288, 3482689535,
-STORE, 3482689536, 3482746879,
-STORE, 3482746880, 3482755071,
-STORE, 3482755072, 3482759167,
-STORE, 3482972160, 3483062271,
-STORE, 3483062272, 3483242495,
-STORE, 3483242496, 3483246591,
-STORE, 3483246592, 3483250687,
-STORE, 3483398144, 3483688959,
-STORE, 3483688960, 3484114943,
-STORE, 3484114944, 3484131327,
-STORE, 3484131328, 3484135423,
-STORE, 3484135424, 3484143615,
-STORE, 3484184576, 3484475391,
-STORE, 3484475392, 3485028351,
-STORE, 3485028352, 3485057023,
-STORE, 3485057024, 3485061119,
-STORE, 3485360128, 3485364223,
-STORE, 3485364224, 3485368319,
-STORE, 3485368320, 3485372415,
-STORE, 3485589504, 3485593599,
-STORE, 3485593600, 3485597695,
-STORE, 3485597696, 3485601791,
-STORE, 3485913088, 3485937663,
-STORE, 3485937664, 3485974527,
-STORE, 3485974528, 3485982719,
-STORE, 3485982720, 3485986815,
-STORE, 3486052352, 3486056447,
-STORE, 3486056448, 3486064639,
-STORE, 3486064640, 3486068735,
-STORE, 3486068736, 3486072831,
-STORE, 3486294016, 3486302207,
-STORE, 3486302208, 3486306303,
-STORE, 3486306304, 3486310399,
-STORE, 3486310400, 3486314495,
-STORE, 3486670848, 3486679039,
-STORE, 3486679040, 3486683135,
-STORE, 3486683136, 3486687231,
-STORE, 3486687232, 3486691327,
-STORE, 3486863360, 3486871551,
-STORE, 3486871552, 3486875647,
-STORE, 3486875648, 3486879743,
-STORE, 3486879744, 3486883839,
-STORE, 3487584256, 3522543615,
-STORE, 3522543616, 3523321855,
-STORE, 3523321856, 3523342335,
-STORE, 3523342336, 3523387391,
-STORE, 3523387392, 3523391487,
-STORE, 3523391488, 3523395583,
-STORE, 3523477504, 3523686399,
-STORE, 3523686400, 3523981311,
-STORE, 3523981312, 3523997695,
-STORE, 3523997696, 3524001791,
-STORE, 3524177920, 3525013503,
-STORE, 3525013504, 3526582271,
-STORE, 3526582272, 3526606847,
-STORE, 3526606848, 3526610943,
-STORE, 3526610944, 3526615039,
-STORE, 3526672384, 3526746111,
-STORE, 3526746112, 3526860799,
-STORE, 3526860800, 3526868991,
-STORE, 3526868992, 3526873087,
-STORE, 3527000064, 3527475199,
-STORE, 3527475200, 3527479295,
-STORE, 3527479296, 3527573503,
-STORE, 3527573504, 3527581695,
-STORE, 3527581696, 3527585791,
-STORE, 3527585792, 3527606271,
-STORE, 3527909376, 3527913471,
-STORE, 3527913472, 3527917567,
-STORE, 3527917568, 3527921663,
-STORE, 3527950336, 3528011775,
-STORE, 3528011776, 3528093695,
-STORE, 3528093696, 3528101887,
-STORE, 3528101888, 3528105983,
-STORE, 3528228864, 3528241151,
-STORE, 3528241152, 3528261631,
-STORE, 3528261632, 3528265727,
-STORE, 3528273920, 3528593407,
-STORE, 3528593408, 3528609791,
-STORE, 3528609792, 3528638463,
-STORE, 3528638464, 3528642559,
-STORE, 3528642560, 3528646655,
-STORE, 3528880128, 3528912895,
-STORE, 3528912896, 3528962047,
-STORE, 3528962048, 3528966143,
-STORE, 3528966144, 3528970239,
-STORE, 3528982528, 3530293247,
-STORE, 3530366976, 3530825727,
-STORE, 3530825728, 3531317247,
-STORE, 3531317248, 3541041151,
-STORE, 3541041152, 3541303295,
-STORE, 3541430272, 3566206975,
-STORE, 3566206976, 3566993407,
-STORE, 3567239168, 3587571711,
-STORE, 3587571712, 3588284415,
-STORE, 3588284416, 3588661247,
-STORE, 3588661248, 3589066751,
-STORE, 3589066752, 3589574655,
-STORE, 3589574656, 3590078463,
-STORE, 3590078464, 3590373375,
-STORE, 3590373376, 3590668287,
-STORE, 3590668288, 3590963199,
-STORE, 3590963200, 3591294975,
-STORE, 3591294976, 3591602175,
-STORE, 3591602176, 3591933951,
-STORE, 3591933952, 3592241151,
-STORE, 3592241152, 3592572927,
-STORE, 3592572928, 3592876031,
-STORE, 3592876032, 3593211903,
-STORE, 3593211904, 3593547775,
-STORE, 3593547776, 3593650175,
-STORE, 3593650176, 3593928703,
-STORE, 3593928704, 3593936895,
-STORE, 3593936896, 3593940991,
-STORE, 3594006528, 3594301439,
-STORE, 3594301440, 3594739711,
-STORE, 3594739712, 3594756095,
-STORE, 3594756096, 3594760191,
-STORE, 3594760192, 3594768383,
-STORE, 3594952704, 3595051007,
-STORE, 3595051008, 3595223039,
-STORE, 3595223040, 3595227135,
-STORE, 3595227136, 3595235327,
-STORE, 3595431936, 3595775999,
-STORE, 3595776000, 3596701695,
-STORE, 3596701696, 3596742655,
-STORE, 3596742656, 3596746751,
-STORE, 3596746752, 3596750847,
-STORE, 3596767232, 3597070335,
-STORE, 3597070336, 3597402111,
-STORE, 3597402112, 3598188543,
-STORE, 3598262272, 3623428095,
-STORE, 3623428096, 3623432191,
-STORE, 3623432192, 3623436287,
-STORE, 3623436288, 3623440383,
-STORE, 3623616512, 3623878655,
-STORE, 3624169472, 3624300543,
-STORE, 3627524096, 3628523519,
-STORE, 3628523520, 3629522943,
-STORE, 3696631808, 3730186239,
-STORE, 3730186240, 3763740671,
-STORE, 3763740672, 3764027391,
-STORE, 3764027392, 3765133311,
-STORE, 3765133312, 3765145599,
-STORE, 3765145600, 3765149695,
-STORE, 3765178368, 3766022143,
-STORE, 3766022144, 3768791039,
-STORE, 3768791040, 3768840191,
-STORE, 3768840192, 3768844287,
-STORE, 3768897536, 3768913919,
-STORE, 3768913920, 3768934399,
-STORE, 3768934400, 3768938495,
-STORE, 3769016320, 3769147391,
-STORE, 3769147392, 3769233407,
-STORE, 3769233408, 3769356287,
-STORE, 3769356288, 3769360383,
-STORE, 3769360384, 3769368575,
-STORE, 3769376768, 3794542591,
-STORE, 3794542592, 3794599935,
-STORE, 3794599936, 3794731007,
-STORE, 3794731008, 3794735103,
-STORE, 3794735104, 3794743295,
-STORE, 3794849792, 3794980863,
-STORE, 3794980864, 3794984959,
-STORE, 3794984960, 3794989055,
-STORE, 3794989056, 3794993151,
-STORE, 3794993152, 3794997247,
-STORE, 3795103744, 3795128319,
-STORE, 3795128320, 3795165183,
-STORE, 3795165184, 3795169279,
-STORE, 3795169280, 3795173375,
-STORE, 3795210240, 3795357695,
-STORE, 3795357696, 3795365887,
-STORE, 3795365888, 3795374079,
-STORE, 3795374080, 3795378175,
-STORE, 3795378176, 3795382271,
-STORE, 3795406848, 3795738623,
-STORE, 3795738624, 3795742719,
-STORE, 3795742720, 3795755007,
-STORE, 3795755008, 3795759103,
-STORE, 3795763200, 3795894271,
-STORE, 3795894272, 3796041727,
-STORE, 3796041728, 3796054015,
-STORE, 3796054016, 3796066303,
-STORE, 3796066304, 3796070399,
-STORE, 3796176896, 3796205567,
-STORE, 3796205568, 3796250623,
-STORE, 3796250624, 3796254719,
-STORE, 3796254720, 3796258815,
-STORE, 3796262912, 3796393983,
-STORE, 3796393984, 3796516863,
-STORE, 3796516864, 3796873215,
-STORE, 3796873216, 3796885503,
-STORE, 3796885504, 3796889599,
-STORE, 3796963328, 3796967423,
-STORE, 3796967424, 3796975615,
-STORE, 3796975616, 3796979711,
-STORE, 3797000192, 3797307391,
-STORE, 3797307392, 3797311487,
-STORE, 3797311488, 3797315583,
-STORE, 3797315584, 3797323775,
-STORE, 3797327872, 3797450751,
-STORE, 3797450752, 3797458943,
-STORE, 3797458944, 3797471231,
-STORE, 3797471232, 3797475327,
-STORE, 3797577728, 3797700607,
-STORE, 3797700608, 3797721087,
-STORE, 3797721088, 3797733375,
-STORE, 3797733376, 3797741567,
-STORE, 3797741568, 3797864447,
-STORE, 3797864448, 3797995519,
-STORE, 3797995520, 3798048767,
-STORE, 3798048768, 3798179839,
-STORE, 3798179840, 3798188031,
-STORE, 3798188032, 3798192127,
-STORE, 3798290432, 3798302719,
-STORE, 3798302720, 3798323199,
-STORE, 3798323200, 3798327295,
-STORE, 3798327296, 3798331391,
-STORE, 3798429696, 3798433791,
-STORE, 3798433792, 3798552575,
-STORE, 3798552576, 3798556671,
-STORE, 3798556672, 3798568959,
-STORE, 3798568960, 3798573055,
-STORE, 3798573056, 3798581247,
-STORE, 3798618112, 3798749183,
-STORE, 3798749184, 3798855679,
-STORE, 3798855680, 3798966271,
-STORE, 3798966272, 3798982655,
-STORE, 3798982656, 3798986751,
-STORE, 3799101440, 3799171071,
-STORE, 3799171072, 3799240703,
-STORE, 3799240704, 3799248895,
-STORE, 3799248896, 3799252991,
-STORE, 3799326720, 3799650303,
-STORE, 3799650304, 3800629247,
-STORE, 3800629248, 3800641535,
-STORE, 3800641536, 3800645631,
-STORE, 3800645632, 3800649727,
-STORE, 3800649728, 3800903679,
-STORE, 3800903680, 3800936447,
-STORE, 3800936448, 3800969215,
-STORE, 3800969216, 3800981503,
-STORE, 3800981504, 3800985599,
-STORE, 3801001984, 3801133055,
-STORE, 3801133056, 3801202687,
-STORE, 3801202688, 3801591807,
-STORE, 3801591808, 3801599999,
-STORE, 3801600000, 3801604095,
-STORE, 3801604096, 3801608191,
-STORE, 3801608192, 3801739263,
-STORE, 3801739264, 3801755647,
-STORE, 3801755648, 3801796607,
-STORE, 3801796608, 3801804799,
-STORE, 3801804800, 3801808895,
-STORE, 3801878528, 3801944063,
-STORE, 3801944064, 3802116095,
-STORE, 3802116096, 3802124287,
-STORE, 3802124288, 3802128383,
-STORE, 3802136576, 3803447295,
-STORE, 3803492352, 3803553791,
-STORE, 3803553792, 3804233727,
-STORE, 3804233728, 3806068735,
-STORE, 3806121984, 3806253055,
-STORE, 3806253056, 3806674943,
-STORE, 3806674944, 3807117311,
-STORE, 3807117312, 3807379455,
-STORE, 3807379456, 3807432703,
-STORE, 3807432704, 3807563775,
-STORE, 3807563776, 3809202175,
-STORE, 3809202176, 3810250751,
-STORE, 3810250752, 3827027967,
-STORE, 3827027968, 3829125119,
-STORE, 3829125120, 3837513727,
-STORE, 3837513728, 3839610879,
-STORE, 3839610880, 3847999487,
-STORE, 3847999488, 3856392191,
-STORE, 3856392192, 3864784895,
-STORE, 3864784896, 3868983295,
-STORE, 3868983296, 3885760511,
-STORE, 3885760512, 3886809087,
-STORE, 3886809088, 3887857663,
-STORE, 3887857664, 3888119807,
-STORE, 3888144384, 3888148479,
-STORE, 3888148480, 3888218111,
-STORE, 3888218112, 3888222207,
-STORE, 3888222208, 3888353279,
-STORE, 3888353280, 3889172479,
-STORE, 3889172480, 3892314111,
-STORE, 3892314112, 3892576255,
-STORE, 3892588544, 3892637695,
-STORE, 3892637696, 3892686847,
-STORE, 3892686848, 3892744191,
-STORE, 3892748288, 3892785151,
-STORE, 3892785152, 3895459839,
-STORE, 3895459840, 3895721983,
-STORE, 3895738368, 3895885823,
-STORE, 3895885824, 3897081855,
-STORE, 3897081856, 3906482175,
-STORE, 3906482176, 3916144639,
-STORE, 3916144640, 3925766143,
-STORE, 3925766144, 3926974463,
-STORE, 3926974464, 3928367103,
-STORE, 3928367104, 3928911871,
-STORE, 3928911872, 3933995007,
-STORE, 3933995008, 3935830015,
-STORE, 3935830016, 3935846399,
-STORE, 3935879168, 3936010239,
-STORE, 3936010240, 3936026623,
-STORE, 3936026624, 3936034815,
-STORE, 3936034816, 3936051199,
-STORE, 3936051200, 3936055295,
-STORE, 3936071680, 3936137215,
-STORE, 3936137216, 3936202751,
-STORE, 3936202752, 3936219135,
-STORE, 3936235520, 3936251903,
-STORE, 3936268288, 3936276479,
-STORE, 3936276480, 3936284671,
-STORE, 3936284672, 3936288767,
-STORE, 3936288768, 3936292863,
-STORE, 3936296960, 3936354303,
-STORE, 3936354304, 3936616447,
-STORE, 3936628736, 3936669695,
-STORE, 3936669696, 3936747519,
-STORE, 3936747520, 3936870399,
-STORE, 3936870400, 3936874495,
-STORE, 3936874496, 3936878591,
-STORE, 3936882688, 3936903167,
-STORE, 3936911360, 3936948223,
-STORE, 3936948224, 3936964607,
-STORE, 3936964608, 3937103871,
-STORE, 3937103872, 3937107967,
-STORE, 3937132544, 3937161215,
-STORE, 3937189888, 3937255423,
-STORE, 3937255424, 3938512895,
-STORE, 3938512896, 3945435135,
-STORE, 3945435136, 3945476095,
-STORE, 3945476096, 3945484287,
-STORE, 3945484288, 3945496575,
-STORE, 3945500672, 3945541631,
-STORE, 3945558016, 3945566207,
-STORE, 3945566208, 3945594879,
-STORE, 3945594880, 3945598975,
-STORE, 3945598976, 3945603071,
-STORE, 3945611264, 3945742335,
-STORE, 3945742336, 3945844735,
-STORE, 3945844736, 3945848831,
-STORE, 3945848832, 3945861119,
-STORE, 3945861120, 3945865215,
-STORE, 3945869312, 3945897983,
-STORE, 3945897984, 3946303487,
-STORE, 3946303488, 3946397695,
-STORE, 3946397696, 3946569727,
-STORE, 3946569728, 3946573823,
-STORE, 3946573824, 3946594303,
-STORE, 3946594304, 3946663935,
-STORE, 3946663936, 3946708991,
-STORE, 3946708992, 3946823679,
-STORE, 3946823680, 3946827775,
-STORE, 3946827776, 3946831871,
-STORE, 3946831872, 3946860543,
-STORE, 3946893312, 3946897407,
-STORE, 3946897408, 3946905599,
-STORE, 3946905600, 3946909695,
-STORE, 3946909696, 3946913791,
-STORE, 3946913792, 3946930175,
-STORE, 3946930176, 3946967039,
-STORE, 3946967040, 3947102207,
-STORE, 3947102208, 3948412927,
-STORE, 3948441600, 3948556287,
-STORE, 3948556288, 3948576767,
-STORE, 3948576768, 3948597247,
-STORE, 3948597248, 3948605439,
-STORE, 3948605440, 3948609535,
-STORE, 3948609536, 3948654591,
-STORE, 3948654592, 3948781567,
-STORE, 3948781568, 3948822527,
-STORE, 3948822528, 3948904447,
-STORE, 3948904448, 3948908543,
-STORE, 3948908544, 3948912639,
-STORE, 3948945408, 3949043711,
-STORE, 3949043712, 3949174783,
-STORE, 3949174784, 3949191167,
-STORE, 3949191168, 3949195263,
-STORE, 3949207552, 3949252607,
-STORE, 3949252608, 3949256703,
-STORE, 3949256704, 3949363199,
-STORE, 3949363200, 3949367295,
-STORE, 3949367296, 3949379583,
-STORE, 3949379584, 3949383679,
-STORE, 3949383680, 3949400063,
-STORE, 3949400064, 3949404159,
-STORE, 3949416448, 3949481983,
-STORE, 3949481984, 3949486079,
-STORE, 3949486080, 3949592575,
-STORE, 3949592576, 3949596671,
-STORE, 3949596672, 3949621247,
-STORE, 3949621248, 3949662207,
-STORE, 3949662208, 3949666303,
-STORE, 3949694976, 3949727743,
-STORE, 3949727744, 3949731839,
-STORE, 3949731840, 3949838335,
-STORE, 3949838336, 3949842431,
-STORE, 3949842432, 3949846527,
-STORE, 3949846528, 3949854719,
-STORE, 3949854720, 3949858815,
-STORE, 3949858816, 3949862911,
-STORE, 3949867008, 3949891583,
-STORE, 3949891584, 3949928447,
-STORE, 3949928448, 3949993983,
-STORE, 3949993984, 3950043135,
-STORE, 3950043136, 3950059519,
-STORE, 3950059520, 3950096383,
-STORE, 3950096384, 3950100479,
-STORE, 3950100480, 3950104575,
-STORE, 3950104576, 3950157823,
-STORE, 3950157824, 3950292991,
-STORE, 3950292992, 3950346239,
-STORE, 3950346240, 3950477311,
-STORE, 3950477312, 3950485503,
-STORE, 3950485504, 3950489599,
-STORE, 3950493696, 3950510079,
-STORE, 3950510080, 3950661631,
-STORE, 3950661632, 3951005695,
-STORE, 3951005696, 3951026175,
-STORE, 3951026176, 3951030271,
-STORE, 3951030272, 3951054847,
-STORE, 3951054848, 3951116287,
-STORE, 3951116288, 3951144959,
-STORE, 3951144960, 3951149055,
-STORE, 3951149056, 3951194111,
-STORE, 3951194112, 3951202303,
-STORE, 3951202304, 3951206399,
-STORE, 3951210496, 3951226879,
-STORE, 3951226880, 3951329279,
-STORE, 3951329280, 3951366143,
-STORE, 3951366144, 3951411199,
-STORE, 3951411200, 3951415295,
-STORE, 3951415296, 3951419391,
-STORE, 3951419392, 3951452159,
-STORE, 3951452160, 3951566847,
-STORE, 3951566848, 3951812607,
-STORE, 3951812608, 3952173055,
-STORE, 3952173056, 3952214015,
-STORE, 3952214016, 3952218111,
-STORE, 3952222208, 3952250879,
-STORE, 3952250880, 3952369663,
-STORE, 3952369664, 3952488447,
-STORE, 3952488448, 3952627711,
-STORE, 3952627712, 3952635903,
-STORE, 3952635904, 3952639999,
-STORE, 3952652288, 3952668671,
-STORE, 3952668672, 3953000447,
-STORE, 3953000448, 3953004543,
-STORE, 3953004544, 3953008639,
-STORE, 3953008640, 3953012735,
-STORE, 3953012736, 3953037311,
-STORE, 3953037312, 3953151999,
-STORE, 3953152000, 3953291263,
-STORE, 3953291264, 3953324031,
-STORE, 3953324032, 3953364991,
-STORE, 3953364992, 3953373183,
-STORE, 3953373184, 3953377279,
-STORE, 3953381376, 3953410047,
-STORE, 3953410048, 3953491967,
-STORE, 3953491968, 3953643519,
-STORE, 3953643520, 3953651711,
-STORE, 3953651712, 3953655807,
-STORE, 3953659904, 3953766399,
-STORE, 3953766400, 3953774591,
-STORE, 3953774592, 3953786879,
-STORE, 3953786880, 3953790975,
-STORE, 3953790976, 3953823743,
-STORE, 3953823744, 3953963007,
-STORE, 3953963008, 3954024447,
-STORE, 3954024448, 3954118655,
-STORE, 3954118656, 3954122751,
-STORE, 3954122752, 3954126847,
-STORE, 3954130944, 3954184191,
-STORE, 3954184192, 3954294783,
-STORE, 3954294784, 3954323455,
-STORE, 3954323456, 3954393087,
-STORE, 3954393088, 3954397183,
-STORE, 3954397184, 3954401279,
-STORE, 3954401280, 3954405375,
-STORE, 3954409472, 3954528255,
-STORE, 3954528256, 3954737151,
-STORE, 3954737152, 3955052543,
-STORE, 3955052544, 3955060735,
-STORE, 3955060736, 3955064831,
-STORE, 3955068928, 3955105791,
-STORE, 3955105792, 3955167231,
-STORE, 3955167232, 3955277823,
-STORE, 3955277824, 3955310591,
-STORE, 3955310592, 3955351551,
-STORE, 3955351552, 3955359743,
-STORE, 3955359744, 3955363839,
-STORE, 3955363840, 3955392511,
-STORE, 3955392512, 3955453951,
-STORE, 3955453952, 3955601407,
-STORE, 3955601408, 3955777535,
-STORE, 3955777536, 3955982335,
-STORE, 3955982336, 3956011007,
-STORE, 3956011008, 3956015103,
-STORE, 3956023296, 3956039679,
-STORE, 3956039680, 3956125695,
-STORE, 3956125696, 3956129791,
-STORE, 3956129792, 3956133887,
-STORE, 3956133888, 3956137983,
-STORE, 3956142080, 3956449279,
-STORE, 3956449280, 3956543487,
-STORE, 3956543488, 3956719615,
-STORE, 3956719616, 3956731903,
-STORE, 3956731904, 3956735999,
-STORE, 3956744192, 3956793343,
-STORE, 3956793344, 3956887551,
-STORE, 3956887552, 3956953087,
-STORE, 3956953088, 3957035007,
-STORE, 3957035008, 3957039103,
-STORE, 3957039104, 3957047295,
-STORE, 3957047296, 3957071871,
-STORE, 3957071872, 3957231615,
-STORE, 3957231616, 3957563391,
-STORE, 3957563392, 3957579775,
-STORE, 3957579776, 3957583871,
-STORE, 3957592064, 3957608447,
-STORE, 3957608448, 3957878783,
-STORE, 3957878784, 3958591487,
-STORE, 3958591488, 3958599679,
-STORE, 3958599680, 3958607871,
-STORE, 3958607872, 3958620159,
-STORE, 3958620160, 3958624255,
-STORE, 3958624256, 3963199487,
-STORE, 3963199488, 3963285503,
-STORE, 3963285504, 3963371519,
-STORE, 3963371520, 3963428863,
-STORE, 3963428864, 3963555839,
-STORE, 3963555840, 3963559935,
-STORE, 3963559936, 3963564031,
-STORE, 3963568128, 3963596799,
-STORE, 3963596800, 3963682815,
-STORE, 3963682816, 3963695103,
-STORE, 3963695104, 3963711487,
-STORE, 3963711488, 3963715583,
-STORE, 3963719680, 3963752447,
-STORE, 3963752448, 3963846655,
-STORE, 3963846656, 3963932671,
-STORE, 3963932672, 3964444671,
-STORE, 3964444672, 3964448767,
-STORE, 3964448768, 3965808639,
-STORE, 3965808640, 3965845503,
-STORE, 3965845504, 3965849599,
-STORE, 3965853696, 3965935615,
-STORE, 3965935616, 3966017535,
-STORE, 3966017536, 3966103551,
-STORE, 3966103552, 3966685183,
-STORE, 3966685184, 3967705087,
-STORE, 3967705088, 3967758335,
-STORE, 3967758336, 3967762431,
-STORE, 3967762432, 3967770623,
-STORE, 3967770624, 3967799295,
-STORE, 3967799296, 3967848447,
-STORE, 3967848448, 3967868927,
-STORE, 3967868928, 3967901695,
-STORE, 3967901696, 3967905791,
-STORE, 3967905792, 3967909887,
-STORE, 3967909888, 3967995903,
-STORE, 3967995904, 3968077823,
-STORE, 3968077824, 3968159743,
-STORE, 3968159744, 3968167935,
-STORE, 3968167936, 3968172031,
-STORE, 3968172032, 3968192511,
-STORE, 3968192512, 3968196607,
-STORE, 3968196608, 3968200703,
-STORE, 3968208896, 3968516095,
-STORE, 3968516096, 3968528383,
-STORE, 3968528384, 3968552959,
-STORE, 3968552960, 3968557055,
-STORE, 3968561152, 3968593919,
-STORE, 3968593920, 3968626687,
-STORE, 3968626688, 3971153919,
-STORE, 3971153920, 3973754879,
-STORE, 3973754880, 3973804031,
-STORE, 3973804032, 3973820415,
-STORE, 3973820416, 3973832703,
-STORE, 3973840896, 3973873663,
-STORE, 3973873664, 3973967871,
-STORE, 3973967872, 3973976063,
-STORE, 3973976064, 3973984255,
-STORE, 3973984256, 3973988351,
-STORE, 3973988352, 3973992447,
-STORE, 3973996544, 3974008831,
-STORE, 3974008832, 3974045695,
-STORE, 3974045696, 3974139903,
-STORE, 3974139904, 3974254591,
-STORE, 3974254592, 3974275071,
-STORE, 3974275072, 3974291455,
-STORE, 3974291456, 3974295551,
-STORE, 3974295552, 3974373375,
-STORE, 3974373376, 3974524927,
-STORE, 3974524928, 3974529023,
-STORE, 3974529024, 3974537215,
-STORE, 3974537216, 3974541311,
-STORE, 3974541312, 3974545407,
-STORE, 3974545408, 3974627327,
-STORE, 3974627328, 3974680575,
-STORE, 3974680576, 3974811647,
-STORE, 3974811648, 3974819839,
-STORE, 3974819840, 3974823935,
-STORE, 3974832128, 3974918143,
-STORE, 3974918144, 3974963199,
-STORE, 3974963200, 3975077887,
-STORE, 3975077888, 3975090175,
-STORE, 3975090176, 3975094271,
-STORE, 3975094272, 3975102463,
-STORE, 3975102464, 3975114751,
-STORE, 3975114752, 3975266303,
-STORE, 3975266304, 3975274495,
-STORE, 3975274496, 3975286783,
-STORE, 3975286784, 3975290879,
-STORE, 3975290880, 3975299071,
-STORE, 3975299072, 3975315455,
-STORE, 3975315456, 3975430143,
-STORE, 3975430144, 3975536639,
-STORE, 3975536640, 3975651327,
-STORE, 3975651328, 3975655423,
-STORE, 3975655424, 3975659519,
-STORE, 3975659520, 3975770111,
-STORE, 3975770112, 3975778303,
-STORE, 3975778304, 3975790591,
-STORE, 3975790592, 3975794687,
-STORE, 3975794688, 3975798783,
-STORE, 3975798784, 3975831551,
-STORE, 3975831552, 3975872511,
-STORE, 3975872512, 3975987199,
-STORE, 3975987200, 3976134655,
-STORE, 3976134656, 3977175039,
-STORE, 3977175040, 3977183231,
-STORE, 3977183232, 3977191423,
-STORE, 3977191424, 3977195519,
-STORE, 3977199616, 3977248767,
-STORE, 3977248768, 3977539583,
-STORE, 3977539584, 3977965567,
-STORE, 3977965568, 3977981951,
-STORE, 3977981952, 3977986047,
-STORE, 3977986048, 3977994239,
-STORE, 3977994240, 3978002431,
-STORE, 3978002432, 3978084351,
-STORE, 3978084352, 3978125311,
-STORE, 3978125312, 3978174463,
-STORE, 3978174464, 3978178559,
-STORE, 3978178560, 3978182655,
-STORE, 3978182656, 3978207231,
-STORE, 3978207232, 3978297343,
-STORE, 3978297344, 3978301439,
-STORE, 3978301440, 3978305535,
-STORE, 3978305536, 3978309631,
-STORE, 3978309632, 3978317823,
-STORE, 3978317824, 3978625023,
-STORE, 3978625024, 3978657791,
-STORE, 3978657792, 3978727423,
-STORE, 3978727424, 3978735615,
-STORE, 3978735616, 3978739711,
-STORE, 3978739712, 3978760191,
-STORE, 3978760192, 3978842111,
-STORE, 3978842112, 3978850303,
-STORE, 3978850304, 3978858495,
-STORE, 3978858496, 3978862591,
-STORE, 3978862592, 3978895359,
-STORE, 3978895360, 3979014143,
-STORE, 3979014144, 3979132927,
-STORE, 3979132928, 3979288575,
-STORE, 3979288576, 3979481087,
-STORE, 3979481088, 3979489279,
-STORE, 3979489280, 3979493375,
-STORE, 3979497472, 3979583487,
-STORE, 3979583488, 3979673599,
-STORE, 3979673600, 3979718655,
-STORE, 3979718656, 3979829247,
-STORE, 3979829248, 3979841535,
-STORE, 3979841536, 3979882495,
-STORE, 3979882496, 3979964415,
-STORE, 3979964416, 3980013567,
-STORE, 3980013568, 3980148735,
-STORE, 3980148736, 3980152831,
-STORE, 3980152832, 3980320767,
-STORE, 3980320768, 3980337151,
-STORE, 3980337152, 3980341247,
-STORE, 3980345344, 3980365823,
-STORE, 3980365824, 3980423167,
-STORE, 3980423168, 3980460031,
-STORE, 3980460032, 3980500991,
-STORE, 3980500992, 3980509183,
-STORE, 3980509184, 3980513279,
-STORE, 3980513280, 3980546047,
-STORE, 3980546048, 3980660735,
-STORE, 3980660736, 3980951551,
-STORE, 3980951552, 3981500415,
-STORE, 3981500416, 3981529087,
-STORE, 3981529088, 3981533183,
-STORE, 3981537280, 3981549567,
-STORE, 3981549568, 3981598719,
-STORE, 3981598720, 3981717503,
-STORE, 3981717504, 3982127103,
-STORE, 3982127104, 3982675967,
-STORE, 3982675968, 3982733311,
-STORE, 3982733312, 3982737407,
-STORE, 3982741504, 3982860287,
-STORE, 3982860288, 3982905343,
-STORE, 3982905344, 3982966783,
-STORE, 3982966784, 3982974975,
-STORE, 3982974976, 3982979071,
-STORE, 3982979072, 3983032319,
-STORE, 3983032320, 3983085567,
-STORE, 3983085568, 3983208447,
-STORE, 3983208448, 3983212543,
-STORE, 3983212544, 3983220735,
-STORE, 3983220736, 3983224831,
-STORE, 3983224832, 3983237119,
-STORE, 3983237120, 3983351807,
-STORE, 3983351808, 3983376383,
-STORE, 3983376384, 3983392767,
-STORE, 3983392768, 3983396863,
-STORE, 3983396864, 3983400959,
-STORE, 3983400960, 3983417343,
-STORE, 3983417344, 3983753215,
-STORE, 3983753216, 3983757311,
-STORE, 3983757312, 3983761407,
-STORE, 3983761408, 3983765503,
-STORE, 3983765504, 3983769599,
-STORE, 3983769600, 3983880191,
-STORE, 3983880192, 3983892479,
-STORE, 3983892480, 3983900671,
-STORE, 3983900672, 3983904767,
-STORE, 3983904768, 3983908863,
-STORE, 3983908864, 3983941631,
-STORE, 3983941632, 3983990783,
-STORE, 3983990784, 3984097279,
-STORE, 3984097280, 3984105471,
-STORE, 3984105472, 3984117759,
-STORE, 3984117760, 3984121855,
-STORE, 3984121856, 3984125951,
-STORE, 3984125952, 3984134143,
-STORE, 3984134144, 3984150527,
-STORE, 3984150528, 3984416767,
-STORE, 3984416768, 3984470015,
-STORE, 3984470016, 3984564223,
-STORE, 3984564224, 3984568319,
-STORE, 3984572416, 3984629759,
-STORE, 3984629760, 3984805887,
-STORE, 3984805888, 3985096703,
-STORE, 3985096704, 3985104895,
-STORE, 3985104896, 3985108991,
-STORE, 3985113088, 3986862079,
-STORE, 3986862080, 3993640959,
-STORE, 3993640960, 3993739263,
-STORE, 3993739264, 3993743359,
-STORE, 3993743360, 3993759743,
-STORE, 3993759744, 3993780223,
-STORE, 3993780224, 3993784319,
-STORE, 3993784320, 3993792511,
-STORE, 3993792512, 3993796607,
-STORE, 3993796608, 3993800703,
-STORE, 3993804800, 3994214399,
-STORE, 3994214400, 3994218495,
-STORE, 3994218496, 3994222591,
-STORE, 3994222592, 3994226687,
-STORE, 3994230784, 3994243071,
-STORE, 3994243072, 3994255359,
-STORE, 3994255360, 3994304511,
-STORE, 3994304512, 3994386431,
-STORE, 3994386432, 3994509311,
-STORE, 3994509312, 3994521599,
-STORE, 3994521600, 3994525695,
-STORE, 3994529792, 3994542079,
-STORE, 3994542080, 3994660863,
-STORE, 3994660864, 3994705919,
-STORE, 3994705920, 3994796031,
-STORE, 3994796032, 3994800127,
-STORE, 3994800128, 3994804223,
-STORE, 3994804224, 3994812415,
-STORE, 3994812416, 3994845183,
-STORE, 3994845184, 3994898431,
-STORE, 3994898432, 3994902527,
-STORE, 3994902528, 3994906623,
-STORE, 3994910720, 3994931199,
-STORE, 3994931200, 3995181055,
-STORE, 3995181056, 3995222015,
-STORE, 3995222016, 3995275263,
-STORE, 3995275264, 3995279359,
-STORE, 3995279360, 3995283455,
-STORE, 3995283456, 3995291647,
-STORE, 3995291648, 3995324415,
-STORE, 3995324416, 3995451391,
-STORE, 3995451392, 3995697151,
-STORE, 3995697152, 3996078079,
-STORE, 3996078080, 3996086271,
-STORE, 3996086272, 3996090367,
-STORE, 3996094464, 3996119039,
-STORE, 3996119040, 3996200959,
-STORE, 3996200960, 3996229631,
-STORE, 3996229632, 3996233727,
-STORE, 3996233728, 3996282879,
-STORE, 3996282880, 3996291071,
-STORE, 3996291072, 3996295167,
-STORE, 3996299264, 3996311551,
-STORE, 3996311552, 3996430335,
-STORE, 3996430336, 3996467199,
-STORE, 3996467200, 3996504063,
-STORE, 3996504064, 3996512255,
-STORE, 3996512256, 3996516351,
-STORE, 3996516352, 3996540927,
-STORE, 3996540928, 3996671999,
-STORE, 3996672000, 3996676095,
-STORE, 3996676096, 3996684287,
-STORE, 3996684288, 3996688383,
-STORE, 3996688384, 3996692479,
-STORE, 3996692480, 3996717055,
-STORE, 3996717056, 3997048831,
-STORE, 3997048832, 3997057023,
-STORE, 3997057024, 3997073407,
-STORE, 3997073408, 3997077503,
-STORE, 3997077504, 3997081599,
-STORE, 3997081600, 3997097983,
-STORE, 3997097984, 3997179903,
-STORE, 3997179904, 3997356031,
-STORE, 3997356032, 3997650943,
-STORE, 3997650944, 3997675519,
-STORE, 3997675520, 3997679615,
-STORE, 3997683712, 3997700095,
-STORE, 3997700096, 3997745151,
-STORE, 3997745152, 3997802495,
-STORE, 3997802496, 3997810687,
-STORE, 3997810688, 3997814783,
-STORE, 3997814784, 3998064639,
-STORE, 3998064640, 3998081023,
-STORE, 3998081024, 3998085119,
-STORE, 3998085120, 3998130175,
-STORE, 3998130176, 3998134271,
-STORE, 3998134272, 3998142463,
-STORE, 3998142464, 3998179327,
-STORE, 3998179328, 3998212095,
-STORE, 3998212096, 3998326783,
-STORE, 3998326784, 3998351359,
-STORE, 3998351360, 3998392319,
-STORE, 3998392320, 3998396415,
-STORE, 3998396416, 3998400511,
-STORE, 3998400512, 3998433279,
-STORE, 3998433280, 3998466047,
-STORE, 3998466048, 3998613503,
-STORE, 3998613504, 3998666751,
-STORE, 3998666752, 3998724095,
-STORE, 3998724096, 3998732287,
-STORE, 3998732288, 3998736383,
-STORE, 3998736384, 3998760959,
-STORE, 3998760960, 3998777343,
-STORE, 3998777344, 3998822399,
-STORE, 3998822400, 3998826495,
-STORE, 3998826496, 3998830591,
-STORE, 3998830592, 3998863359,
-STORE, 3998863360, 3998900223,
-STORE, 3998900224, 3999043583,
-STORE, 3999043584, 3999121407,
-STORE, 3999121408, 3999215615,
-STORE, 3999215616, 3999223807,
-STORE, 3999223808, 3999227903,
-STORE, 3999227904, 3999236095,
-STORE, 3999236096, 3999268863,
-STORE, 3999268864, 3999301631,
-STORE, 3999301632, 3999354879,
-STORE, 3999354880, 3999428607,
-STORE, 3999428608, 3999436799,
-STORE, 3999436800, 3999440895,
-STORE, 3999444992, 3999461375,
-STORE, 3999461376, 3999584255,
-STORE, 3999584256, 3999760383,
-STORE, 3999760384, 4000219135,
-STORE, 4000219136, 4000235519,
-STORE, 4000235520, 4000251903,
-STORE, 4000251904, 4000501759,
-STORE, 4000501760, 4000505855,
-STORE, 4000505856, 4000509951,
-STORE, 4000509952, 4000518143,
-STORE, 4000518144, 4000522239,
-STORE, 4000522240, 4000587775,
-STORE, 4000587776, 4000645119,
-STORE, 4000645120, 4000813055,
-STORE, 4000813056, 4000817151,
-STORE, 4000821248, 4000837631,
-STORE, 4000837632, 4000870399,
-STORE, 4000870400, 4000874495,
-STORE, 4000874496, 4000878591,
-STORE, 4000878592, 4000882687,
-STORE, 4000882688, 4000886783,
-STORE, 4000886784, 4000890879,
-STORE, 4000890880, 4000907263,
-STORE, 4000907264, 4001214463,
-STORE, 4001214464, 4001558527,
-STORE, 4001558528, 4002484223,
-STORE, 4002484224, 4002525183,
-STORE, 4002525184, 4002529279,
-STORE, 4002529280, 4002533375,
-STORE, 4002533376, 4002537471,
-STORE, 4002537472, 4002660351,
-STORE, 4002660352, 4002779135,
-STORE, 4002779136, 4002791423,
-STORE, 4002791424, 4002799615,
-STORE, 4002799616, 4002807807,
-STORE, 4002807808, 4002811903,
-STORE, 4002811904, 4002828287,
-STORE, 4002828288, 4002910207,
-STORE, 4002910208, 4003028991,
-STORE, 4003028992, 4003037183,
-STORE, 4003037184, 4003045375,
-STORE, 4003045376, 4003049471,
-STORE, 4003049472, 4003053567,
-STORE, 4003053568, 4003057663,
-STORE, 4003057664, 4003065855,
-STORE, 4003065856, 4003135487,
-STORE, 4003135488, 4003446783,
-STORE, 4003446784, 4003450879,
-STORE, 4003450880, 4003454975,
-STORE, 4003454976, 4003459071,
-STORE, 4003459072, 4003463167,
-STORE, 4003463168, 4003495935,
-STORE, 4003495936, 4003569663,
-STORE, 4003569664, 4003573759,
-STORE, 4003573760, 4003704831,
-STORE, 4003704832, 4003708927,
-STORE, 4003708928, 4003713023,
-STORE, 4003713024, 4003737599,
-STORE, 4003737600, 4003770367,
-STORE, 4003770368, 4003876863,
-STORE, 4003876864, 4003880959,
-STORE, 4003880960, 4003885055,
-STORE, 4003885056, 4003889151,
-STORE, 4003889152, 4003893247,
-STORE, 4003893248, 4003897343,
-STORE, 4003897344, 4003962879,
-STORE, 4003962880, 4004069375,
-STORE, 4004069376, 4004093951,
-STORE, 4004093952, 4004118527,
-STORE, 4004118528, 4004122623,
-STORE, 4004122624, 4004126719,
-STORE, 4004126720, 4004155391,
-STORE, 4004155392, 4004286463,
-STORE, 4004286464, 4004384767,
-STORE, 4004384768, 4004388863,
-STORE, 4004388864, 4004646911,
-STORE, 4004646912, 4004655103,
-STORE, 4004655104, 4004659199,
-STORE, 4004659200, 4004667391,
-STORE, 4004667392, 4004683775,
-STORE, 4004683776, 4004814847,
-STORE, 4004814848, 4004818943,
-STORE, 4004818944, 4004823039,
-STORE, 4004823040, 4004827135,
-STORE, 4004827136, 4004835327,
-STORE, 4004835328, 4004954111,
-STORE, 4004954112, 4005085183,
-STORE, 4005085184, 4005306367,
-STORE, 4005306368, 4005765119,
-STORE, 4005765120, 4005789695,
-STORE, 4005789696, 4005793791,
-STORE, 4005793792, 4005801983,
-STORE, 4005801984, 4005920767,
-STORE, 4005920768, 4005945343,
-STORE, 4005945344, 4005949439,
-STORE, 4005949440, 4005986303,
-STORE, 4005986304, 4005990399,
-STORE, 4005990400, 4005994495,
-STORE, 4005994496, 4006002687,
-STORE, 4006002688, 4006109183,
-STORE, 4006109184, 4006117375,
-STORE, 4006117376, 4006121471,
-STORE, 4006121472, 4006133759,
-STORE, 4006133760, 4006137855,
-STORE, 4006137856, 4006141951,
-STORE, 4006141952, 4006150143,
-STORE, 4006150144, 4006391807,
-STORE, 4006391808, 4006445055,
-STORE, 4006445056, 4006563839,
-STORE, 4006563840, 4006572031,
-STORE, 4006572032, 4006576127,
-STORE, 4006576128, 4006584319,
-STORE, 4006584320, 4006694911,
-STORE, 4006694912, 4006739967,
-STORE, 4006739968, 4006776831,
-STORE, 4006776832, 4006785023,
-STORE, 4006785024, 4006789119,
-STORE, 4006789120, 4006797311,
-STORE, 4006797312, 4006813695,
-STORE, 4006813696, 4006846463,
-STORE, 4006846464, 4006977535,
-STORE, 4006977536, 4007006207,
-STORE, 4007006208, 4007010303,
-STORE, 4007010304, 4007067647,
-STORE, 4007067648, 4007075839,
-STORE, 4007075840, 4007084031,
-STORE, 4007084032, 4007100415,
-STORE, 4007100416, 4007116799,
-STORE, 4007116800, 4007133183,
-STORE, 4007133184, 4007153663,
-STORE, 4007153664, 4007178239,
-STORE, 4007178240, 4007202815,
-STORE, 4007202816, 4007206911,
-STORE, 4007206912, 4007272447,
-STORE, 4007272448, 4007276543,
-STORE, 4007276544, 4007280639,
-STORE, 4007280640, 4007284735,
-STORE, 4007284736, 4007292927,
-STORE, 4007292928, 4007423999,
-STORE, 4007424000, 4007448575,
-STORE, 4007448576, 4007452671,
-STORE, 4007452672, 4007505919,
-STORE, 4007505920, 4007510015,
-STORE, 4007510016, 4007514111,
-STORE, 4007514112, 4007645183,
-STORE, 4007645184, 4007776255,
-STORE, 4007776256, 4007780351,
-STORE, 4007780352, 4007784447,
-STORE, 4007784448, 4007788543,
-STORE, 4007788544, 4007809023,
-STORE, 4007809024, 4007829503,
-STORE, 4007829504, 4007960575,
-STORE, 4007960576, 4008091647,
-STORE, 4008091648, 4008296447,
-STORE, 4008296448, 4008890367,
-STORE, 4008890368, 4008898559,
-STORE, 4008898560, 4008902655,
-STORE, 4008902656, 4008996863,
-STORE, 4008996864, 4009041919,
-STORE, 4009041920, 4009082879,
-STORE, 4009082880, 4009091071,
-STORE, 4009091072, 4009107455,
-STORE, 4009107456, 4009349119,
-STORE, 4009349120, 4009373695,
-STORE, 4009373696, 4009414655,
-STORE, 4009414656, 4009422847,
-STORE, 4009422848, 4009426943,
-STORE, 4009426944, 4009447423,
-STORE, 4009447424, 4009471999,
-STORE, 4009472000, 4009512959,
-STORE, 4009512960, 4009594879,
-STORE, 4009594880, 4009598975,
-STORE, 4009598976, 4009697279,
-STORE, 4009697280, 4009713663,
-STORE, 4009713664, 4009717759,
-STORE, 4009717760, 4009721855,
-STORE, 4009721856, 4009730047,
-STORE, 4009730048, 4009861119,
-STORE, 4009861120, 4009951231,
-STORE, 4009951232, 4010131455,
-STORE, 4010131456, 4010135551,
-STORE, 4010135552, 4010139647,
-STORE, 4010139648, 4010143743,
-STORE, 4010143744, 4010164223,
-STORE, 4010164224, 4010295295,
-STORE, 4010295296, 4010299391,
-STORE, 4010299392, 4010491903,
-STORE, 4010491904, 4010495999,
-STORE, 4010496000, 4010668031,
-STORE, 4010668032, 4011028479,
-STORE, 4011028480, 4011053055,
-STORE, 4011053056, 4011057151,
-STORE, 4011057152, 4011118591,
-STORE, 4011118592, 4011126783,
-STORE, 4011126784, 4011130879,
-STORE, 4011130880, 4011143167,
-STORE, 4011143168, 4011147263,
-STORE, 4011147264, 4011167743,
-STORE, 4011167744, 4011171839,
-STORE, 4011171840, 4011360255,
-STORE, 4011360256, 4011364351,
-STORE, 4011364352, 4011626495,
-STORE, 4011626496, 4012216319,
-STORE, 4012216320, 4012228607,
-STORE, 4012228608, 4012232703,
-STORE, 4012232704, 4012236799,
-STORE, 4012236800, 4012240895,
-STORE, 4012240896, 4012261375,
-STORE, 4012261376, 4012392447,
-STORE, 4012392448, 4012466175,
-STORE, 4012466176, 4012597247,
-STORE, 4012597248, 4012601343,
-STORE, 4012601344, 4012605439,
-STORE, 4012605440, 4012609535,
-STORE, 4012609536, 4012679167,
-STORE, 4012679168, 4013563903,
-STORE, 4013563904, 4015366143,
-STORE, 4015366144, 4015411199,
-STORE, 4015411200, 4015415295,
-STORE, 4015415296, 4015419391,
-STORE, 4015419392, 4015542271,
-STORE, 4015542272, 4015550463,
-STORE, 4015550464, 4015558655,
-STORE, 4015558656, 4015562751,
-STORE, 4015562752, 4015583231,
-STORE, 4015583232, 4015587327,
-STORE, 4015587328, 4015603711,
-STORE, 4015665152, 4015669247,
-STORE, 4015669248, 4015812607,
-STORE, 4015812608, 4015816703,
-STORE, 4015816704, 4016111615,
-STORE, 4016111616, 4016467967,
-STORE, 4016467968, 4016508927,
-STORE, 4016508928, 4016517119,
-STORE, 4016517120, 4016525311,
-STORE, 4016525312, 4016586751,
-STORE, 4016586752, 4016664575,
-STORE, 4016664576, 4016697343,
-STORE, 4016697344, 4016742399,
-STORE, 4016742400, 4016746495,
-STORE, 4016746496, 4016750591,
-STORE, 4016750592, 4016758783,
-STORE, 4016799744, 4016844799,
-STORE, 4016844800, 4016902143,
-STORE, 4016902144, 4016992255,
-STORE, 4016992256, 4017000447,
-STORE, 4017000448, 4017004543,
-STORE, 4017004544, 4017008639,
-STORE, 4017008640, 4017016831,
-STORE, 4017016832, 4017020927,
-STORE, 4017020928, 4017127423,
-STORE, 4017127424, 4017131519,
-STORE, 4017131520, 4017229823,
-STORE, 4017229824, 4017422335,
-STORE, 4017422336, 4017438719,
-STORE, 4017438720, 4017442815,
-STORE, 4017442816, 4017446911,
-STORE, 4017446912, 4017455103,
-STORE, 4017455104, 4017766399,
-STORE, 4017766400, 4017909759,
-STORE, 4017909760, 4018081791,
-STORE, 4018081792, 4018089983,
-STORE, 4018089984, 4018094079,
-STORE, 4018094080, 4018098175,
-STORE, 4018098176, 4018327551,
-STORE, 4018327552, 4018331647,
-STORE, 4018331648, 4018339839,
-STORE, 4018339840, 4018348031,
-STORE, 4018348032, 4018610175,
-STORE, 4018610176, 4018626559,
-STORE, 4018626560, 4018647039,
-STORE, 4018647040, 4018651135,
-STORE, 4018651136, 4018749439,
-STORE, 4018749440, 4018761727,
-STORE, 4018761728, 4018802687,
-STORE, 4018802688, 4018806783,
-STORE, 4018806784, 4018810879,
-STORE, 4018810880, 4018814975,
-STORE, 4018814976, 4018823167,
-STORE, 4018823168, 4018954239,
-STORE, 4018954240, 4019007487,
-STORE, 4019007488, 4019068927,
-STORE, 4019068928, 4019077119,
-STORE, 4019077120, 4019081215,
-STORE, 4019081216, 4019093503,
-STORE, 4019093504, 4019208191,
-STORE, 4019208192, 4019232767,
-STORE, 4019232768, 4019265535,
-STORE, 4019265536, 4019269631,
-STORE, 4019269632, 4019277823,
-STORE, 4019277824, 4019458047,
-STORE, 4019458048, 4019519487,
-STORE, 4019519488, 4019613695,
-STORE, 4019613696, 4019621887,
-STORE, 4019621888, 4019625983,
-STORE, 4019625984, 4019630079,
-STORE, 4019630080, 4019744767,
-STORE, 4019744768, 4019822591,
-STORE, 4019822592, 4019929087,
-STORE, 4019929088, 4019941375,
-STORE, 4019941376, 4019945471,
-STORE, 4019945472, 4019961855,
-STORE, 4019961856, 4019994623,
-STORE, 4019994624, 4019998719,
-STORE, 4019998720, 4020002815,
-STORE, 4020002816, 4020006911,
-STORE, 4020006912, 4020011007,
-STORE, 4020011008, 4020256767,
-STORE, 4020256768, 4020326399,
-STORE, 4020326400, 4020457471,
-STORE, 4020457472, 4020469759,
-STORE, 4020469760, 4020473855,
-STORE, 4020473856, 4020482047,
-STORE, 4020482048, 4020711423,
-STORE, 4020711424, 4020715519,
-STORE, 4020715520, 4020719615,
-STORE, 4020719616, 4020723711,
-STORE, 4020723712, 4020805631,
-STORE, 4020805632, 4021051391,
-STORE, 4021051392, 4021460991,
-STORE, 4021460992, 4021469183,
-STORE, 4021469184, 4021473279,
-STORE, 4021473280, 4021571583,
-STORE, 4021571584, 4021633023,
-STORE, 4021633024, 4021727231,
-STORE, 4021727232, 4021735423,
-STORE, 4021735424, 4021739519,
-STORE, 4021739520, 4021747711,
-STORE, 4021747712, 4021829631,
-STORE, 4021829632, 4021866495,
-STORE, 4021866496, 4021919743,
-STORE, 4021919744, 4021927935,
-STORE, 4021927936, 4021932031,
-STORE, 4021932032, 4021944319,
-STORE, 4021944320, 4022157311,
-STORE, 4022157312, 4022161407,
-STORE, 4022161408, 4022173695,
-STORE, 4022173696, 4022177791,
-STORE, 4022177792, 4022472703,
-STORE, 4022472704, 4022509567,
-STORE, 4022509568, 4022583295,
-STORE, 4022583296, 4022587391,
-STORE, 4022587392, 4022591487,
-STORE, 4022591488, 4022607871,
-STORE, 4022607872, 4022657023,
-STORE, 4022657024, 4022722559,
-STORE, 4022722560, 4022730751,
-STORE, 4022730752, 4022734847,
-STORE, 4022734848, 4022865919,
-STORE, 4022865920, 4022943743,
-STORE, 4022943744, 4023062527,
-STORE, 4023062528, 4023074815,
-STORE, 4023074816, 4023078911,
-STORE, 4023078912, 4023128063,
-STORE, 4023128064, 4023218175,
-STORE, 4023218176, 4023361535,
-STORE, 4023361536, 4023373823,
-STORE, 4023373824, 4023377919,
-STORE, 4023377920, 4023558143,
-STORE, 4023558144, 4023631871,
-STORE, 4023631872, 4023816191,
-STORE, 4023816192, 4023820287,
-STORE, 4023820288, 4023824383,
-STORE, 4023824384, 4023832575,
-STORE, 4023832576, 4024078335,
-STORE, 4024078336, 4024197119,
-STORE, 4024197120, 4024389631,
-STORE, 4024389632, 4024406015,
-STORE, 4024406016, 4024410111,
-STORE, 4024410112, 4024422399,
-STORE, 4024422400, 4024619007,
-STORE, 4024619008, 4024639487,
-STORE, 4024639488, 4024655871,
-STORE, 4024655872, 4024664063,
-STORE, 4024664064, 4024668159,
-STORE, 4024668160, 4024676351,
-STORE, 4024676352, 4024905727,
-STORE, 4024905728, 4024909823,
-STORE, 4024909824, 4024918015,
-STORE, 4024918016, 4024922111,
-STORE, 4024922112, 4024930303,
-STORE, 4024930304, 4025110527,
-STORE, 4025110528, 4025176063,
-STORE, 4025176064, 4025208831,
-STORE, 4025208832, 4025212927,
-STORE, 4025212928, 4025217023,
-STORE, 4025217024, 4025348095,
-STORE, 4025348096, 4025372671,
-STORE, 4025372672, 4025458687,
-STORE, 4025458688, 4025466879,
-STORE, 4025466880, 4025565183,
-STORE, 4025565184, 4025757695,
-STORE, 4025757696, 4026249215,
-STORE, 4026249216, 4026261503,
-STORE, 4026261504, 4026265599,
-STORE, 4026265600, 4026269695,
-STORE, 4026269696, 4026302463,
-STORE, 4026302464, 4026306559,
-STORE, 4026306560, 4026314751,
-STORE, 4026314752, 4026318847,
-STORE, 4026318848, 4026322943,
-STORE, 4026322944, 4026327039,
-STORE, 4026327040, 4026654719,
-STORE, 4026654720, 4026671103,
-STORE, 4026671104, 4026720255,
-STORE, 4026720256, 4026724351,
-STORE, 4026724352, 4026728447,
-STORE, 4026728448, 4026732543,
-STORE, 4026732544, 4026863615,
-STORE, 4026863616, 4027027455,
-STORE, 4027027456, 4027031551,
-STORE, 4027031552, 4027514879,
-STORE, 4027514880, 4027531263,
-STORE, 4027531264, 4027535359,
-STORE, 4027535360, 4027539455,
-STORE, 4027539456, 4027785215,
-STORE, 4027785216, 4027789311,
-STORE, 4027789312, 4027793407,
-STORE, 4027793408, 4027797503,
-STORE, 4027797504, 4027863039,
-STORE, 4027863040, 4027899903,
-STORE, 4027899904, 4027949055,
-STORE, 4027949056, 4027957247,
-STORE, 4027957248, 4027961343,
-STORE, 4027961344, 4027965439,
-STORE, 4027965440, 4028194815,
-STORE, 4028194816, 4028252159,
-STORE, 4028252160, 4028338175,
-STORE, 4028338176, 4028350463,
-STORE, 4028350464, 4028354559,
-STORE, 4028354560, 4028452863,
-STORE, 4028452864, 4028489727,
-STORE, 4028489728, 4028530687,
-STORE, 4028530688, 4028538879,
-STORE, 4028538880, 4028542975,
-STORE, 4028542976, 4028551167,
-STORE, 4028551168, 4028665855,
-STORE, 4028665856, 4029349887,
-STORE, 4029349888, 4030468095,
-STORE, 4030468096, 4030513151,
-STORE, 4030513152, 4030517247,
-STORE, 4030517248, 4030525439,
-STORE, 4030525440, 4030529535,
-STORE, 4030529536, 4030758911,
-STORE, 4030758912, 4030828543,
-STORE, 4030828544, 4030943231,
-STORE, 4030943232, 4030951423,
-STORE, 4030951424, 4030955519,
-STORE, 4030955520, 4030967807,
-STORE, 4030967808, 4031131647,
-STORE, 4031131648, 4031135743,
-STORE, 4031135744, 4031139839,
-STORE, 4031139840, 4031148031,
-STORE, 4031148032, 4031152127,
-STORE, 4031152128, 4031160319,
-STORE, 4031160320, 4031504383,
-STORE, 4031504384, 4031598591,
-STORE, 4031598592, 4031754239,
-STORE, 4031754240, 4031766527,
-STORE, 4031766528, 4031770623,
-STORE, 4031770624, 4031774719,
-STORE, 4031774720, 4031782911,
-STORE, 4031782912, 4031799295,
-STORE, 4031799296, 4031856639,
-STORE, 4031856640, 4031983615,
-STORE, 4031983616, 4031987711,
-STORE, 4031987712, 4031991807,
-STORE, 4031991808, 4032270335,
-STORE, 4032270336, 4032274431,
-STORE, 4032274432, 4032282623,
-STORE, 4032282624, 4032286719,
-STORE, 4032286720, 4032290815,
-STORE, 4032290816, 4032389119,
-STORE, 4032389120, 4032397311,
-STORE, 4032397312, 4032405503,
-STORE, 4032405504, 4032413695,
-STORE, 4032413696, 4032417791,
-STORE, 4032417792, 4032565247,
-STORE, 4032565248, 4032593919,
-STORE, 4032593920, 4032737279,
-STORE, 4032737280, 4032741375,
-STORE, 4032741376, 4032745471,
-STORE, 4032745472, 4032770047,
-STORE, 4032770048, 4032933887,
-STORE, 4032933888, 4032999423,
-STORE, 4032999424, 4033032191,
-STORE, 4033032192, 4033036287,
-STORE, 4033036288, 4033040383,
-STORE, 4033040384, 4033105919,
-STORE, 4033105920, 4033396735,
-STORE, 4033396736, 4033822719,
-STORE, 4033822720, 4033839103,
-STORE, 4033839104, 4033843199,
-STORE, 4033843200, 4033851391,
-STORE, 4033851392, 4033863679,
-STORE, 4033863680, 4033880063,
-STORE, 4033880064, 4033933311,
-STORE, 4033933312, 4034023423,
-STORE, 4034023424, 4034031615,
-STORE, 4034031616, 4034035711,
-STORE, 4034035712, 4034043903,
-STORE, 4034043904, 4034142207,
-STORE, 4034142208, 4034191359,
-STORE, 4034191360, 4034260991,
-STORE, 4034260992, 4034269183,
-STORE, 4034269184, 4034273279,
-STORE, 4034273280, 4034281471,
-STORE, 4034281472, 4034412543,
-STORE, 4034412544, 4034445311,
-STORE, 4034445312, 4034490367,
-STORE, 4034490368, 4034494463,
-STORE, 4034494464, 4034498559,
-STORE, 4034498560, 4034662399,
-STORE, 4034662400, 4034666495,
-STORE, 4034666496, 4034670591,
-STORE, 4034670592, 4034674687,
-STORE, 4034674688, 4034678783,
-STORE, 4034678784, 4034682879,
-STORE, 4034682880, 4034781183,
-STORE, 4034781184, 4035043327,
-STORE, 4035043328, 4035047423,
-STORE, 4035047424, 4035055615,
-STORE, 4035055616, 4035059711,
-STORE, 4035059712, 4035063807,
-STORE, 4035063808, 4035067903,
-STORE, 4035067904, 4035100671,
-STORE, 4035100672, 4035375103,
-STORE, 4035375104, 4035383295,
-STORE, 4035383296, 4035395583,
-STORE, 4035395584, 4035399679,
-STORE, 4035399680, 4035403775,
-STORE, 4035403776, 4035407871,
-STORE, 4035407872, 4035411967,
-STORE, 4035411968, 4035477503,
-STORE, 4035477504, 4035608575,
-STORE, 4035608576, 4035641343,
-STORE, 4035641344, 4035682303,
-STORE, 4035682304, 4035686399,
-STORE, 4035686400, 4035690495,
-STORE, 4035690496, 4035694591,
-STORE, 4035694592, 4035743743,
-STORE, 4035743744, 4035784703,
-STORE, 4035784704, 4035829759,
-STORE, 4035829760, 4035837951,
-STORE, 4035837952, 4035842047,
-STORE, 4035842048, 4035846143,
-STORE, 4035846144, 4035850239,
-STORE, 4035850240, 4036001791,
-STORE, 4036001792, 4036005887,
-STORE, 4036005888, 4036214783,
-STORE, 4036214784, 4036218879,
-STORE, 4036218880, 4036603903,
-STORE, 4036603904, 4036648959,
-STORE, 4036648960, 4036653055,
-STORE, 4036653056, 4036657151,
-STORE, 4036657152, 4036665343,
-STORE, 4036665344, 4036780031,
-STORE, 4036780032, 4036829183,
-STORE, 4036829184, 4036984831,
-STORE, 4036984832, 4036993023,
-STORE, 4036993024, 4036997119,
-STORE, 4036997120, 4037001215,
-STORE, 4037001216, 4037009407,
-STORE, 4037009408, 4037025791,
-STORE, 4037025792, 4037095423,
-STORE, 4037095424, 4037181439,
-STORE, 4037181440, 4037193727,
-STORE, 4037193728, 4037197823,
-STORE, 4037197824, 4037206015,
-STORE, 4037206016, 4037320703,
-STORE, 4037320704, 4037337087,
-STORE, 4037337088, 4037349375,
-STORE, 4037349376, 4037357567,
-STORE, 4037357568, 4037361663,
-STORE, 4037369856, 4037386239,
-STORE, 4037386240, 4037672959,
-STORE, 4037672960, 4037689343,
-STORE, 4037689344, 4037730303,
-STORE, 4037730304, 4037734399,
-STORE, 4037734400, 4037738495,
-STORE, 4037738496, 4037742591,
-STORE, 4037742592, 4037758975,
-STORE, 4037758976, 4037890047,
-STORE, 4037890048, 4037931007,
-STORE, 4037931008, 4037976063,
-STORE, 4037976064, 4037984255,
-STORE, 4037984256, 4037988351,
-STORE, 4037988352, 4038053887,
-STORE, 4038053888, 4038184959,
-STORE, 4038184960, 4038189055,
-STORE, 4038189056, 4038197247,
-STORE, 4038197248, 4038201343,
-STORE, 4038201344, 4038205439,
-STORE, 4038205440, 4038209535,
-STORE, 4038217728, 4038250495,
-STORE, 4038250496, 4038512639,
-STORE, 4038512640, 4038516735,
-STORE, 4038516736, 4038520831,
-STORE, 4038520832, 4038524927,
-STORE, 4038524928, 4038529023,
-STORE, 4038529024, 4038533119,
-STORE, 4038541312, 4038623231,
-STORE, 4038623232, 4038754303,
-STORE, 4038754304, 4038885375,
-STORE, 4038885376, 4038889471,
-STORE, 4038897664, 4038963199,
-STORE, 4038963200, 4038967295,
-STORE, 4038967296, 4038983679,
-STORE, 4038983680, 4039114751,
-STORE, 4039114752, 4039245823,
-STORE, 4039245824, 4039376895,
-STORE, 4039376896, 4040687615,
-STORE, 4040687616, 4040691711,
-STORE, 4040691712, 4040806399,
-STORE, 4040806400, 4040937471,
-STORE, 4040937472, 4040941567,
-STORE, 4040945664, 4040949759,
-STORE, 4040949760, 4041080831,
-STORE, 4041080832, 4041211903,
-STORE, 4041211904, 4043046911,
-STORE, 4043046912, 4043051007,
-STORE, 4043051008, 4043055103,
-STORE, 4043055104, 4043137023,
-STORE, 4043137024, 4043141119,
-STORE, 4043141120, 4043145215,
-STORE, 4043145216, 4043153407,
-STORE, 4043153408, 4043186175,
-STORE, 4043186176, 4043317247,
-STORE, 4043317248, 4043448319,
-STORE, 4043448320, 4043579391,
-STORE, 4043579392, 4043583487,
-STORE, 4043583488, 4043599871,
-STORE, 4043599872, 4043661311,
-STORE, 4043661312, 4043792383,
-STORE, 4043792384, 4043796479,
-STORE, 4043796480, 4043800575,
-STORE, 4043800576, 4043816959,
-STORE, 4043816960, 4043821055,
-STORE, 4043821056, 4043825151,
-STORE, 4043825152, 4043829247,
-STORE, 4043829248, 4043833343,
-STORE, 4043833344, 4047241215,
-STORE, 4047241216, 4047249407,
-STORE, 4047249408, 4047253503,
-STORE, 4047253504, 4047323135,
-STORE, 4047323136, 4047327231,
-STORE, 4047327232, 4047458303,
-STORE, 4047458304, 4047589375,
-STORE, 4047589376, 4047720447,
-STORE, 4047720448, 4047773695,
-STORE, 4047773696, 4047790079,
-STORE, 4047790080, 4047921151,
-STORE, 4047921152, 4048052223,
-STORE, 4048052224, 4048183295,
-STORE, 4048183296, 4049002495,
-STORE, 4049002496, 4049133567,
-STORE, 4049133568, 4049154047,
-STORE, 4049154048, 4049158143,
-STORE, 4049158144, 4049162239,
-STORE, 4049162240, 4049166335,
-STORE, 4049166336, 4049174527,
-STORE, 4049174528, 4049182719,
-STORE, 4049182720, 4049186815,
-STORE, 4049186816, 4049190911,
-STORE, 4049190912, 4049195007,
-STORE, 4049195008, 4049203199,
-STORE, 4049203200, 4049207295,
-STORE, 4049207296, 4049211391,
-STORE, 4049211392, 4049215487,
-STORE, 4049215488, 4049219583,
-STORE, 4049219584, 4049227775,
-STORE, 4049227776, 4049231871,
-STORE, 4049231872, 4049235967,
-STORE, 4049235968, 4049244159,
-STORE, 4049244160, 4049248255,
-STORE, 4049248256, 4049252351,
-STORE, 4049252352, 4049256447,
-STORE, 4049256448, 4049268735,
-STORE, 4049268736, 4049272831,
-STORE, 4049272832, 4049313791,
-STORE, 4049313792, 4049723391,
-STORE, 4049723392, 4049727487,
-STORE, 4049727488, 4049858559,
-STORE, 4049858560, 4049989631,
-STORE, 4049989632, 4049993727,
-STORE, 4049993728, 4050026495,
-STORE, 4050026496, 4050030591,
-STORE, 4050030592, 4050161663,
-STORE, 4050161664, 4050169855,
-STORE, 4050169856, 4050223103,
-STORE, 4050223104, 4050632703,
-STORE, 4050632704, 4050636799,
-STORE, 4050636800, 4050640895,
-STORE, 4050640896, 4050644991,
-STORE, 4050644992, 4050661375,
-STORE, 4050661376, 4050665471,
-STORE, 4050665472, 4050673663,
-STORE, 4050673664, 4050677759,
-STORE, 4050677760, 4050694143,
-STORE, 4050694144, 4050702335,
-STORE, 4050702336, 4050956287,
-STORE, 4050956288, 4051963903,
-STORE, 4051963904, 4051980287,
-STORE, 4051980288, 4051988479,
-STORE, 4051988480, 4052000767,
-STORE, 4052000768, 4052004863,
-STORE, 4052004864, 4052029439,
-STORE, 4284014592, 4284018687,
-STORE, 4284018688, 4292403199,
-SNULL, 4041080832, 4041211903,
-SNULL, 3795763200, 3795894271,
-STORE, 3629522944, 3696631807,
-SNULL, 3663077375, 3696631807,
-STORE, 3629522944, 3663077375,
-STORE, 3663077376, 3696631807,
-SNULL, 3663077376, 3696631807,
-STORE, 3663077376, 3696631807,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3626471424, 3627524095,
-SNULL, 3626471424, 3626475519,
-STORE, 3626475520, 3627524095,
-STORE, 3626471424, 3626475519,
-SNULL, 3627519999, 3627524095,
-STORE, 3626475520, 3627519999,
-STORE, 3627520000, 3627524095,
-STORE, 3625418752, 3626475519,
-SNULL, 3625418752, 3625422847,
-STORE, 3625422848, 3626475519,
-STORE, 3625418752, 3625422847,
-SNULL, 3626467327, 3626475519,
-STORE, 3625422848, 3626467327,
-STORE, 3626467328, 3626475519,
-STORE, 3624366080, 3625422847,
-SNULL, 3624366080, 3624370175,
-STORE, 3624370176, 3625422847,
-STORE, 3624366080, 3624370175,
-SNULL, 3625414655, 3625422847,
-STORE, 3624370176, 3625414655,
-STORE, 3625414656, 3625422847,
-STORE, 4041191424, 4041211903,
-SNULL, 4041195519, 4041211903,
-STORE, 4041191424, 4041195519,
-STORE, 4041195520, 4041211903,
-STORE, 4041170944, 4041191423,
-SNULL, 4041175039, 4041191423,
-STORE, 4041170944, 4041175039,
-STORE, 4041175040, 4041191423,
-SNULL, 3625426943, 3626467327,
-STORE, 3625422848, 3625426943,
-STORE, 3625426944, 3626467327,
-STORE, 4041162752, 4041170943,
-SNULL, 3626479615, 3627519999,
-STORE, 3626475520, 3626479615,
-STORE, 3626479616, 3627519999,
-STORE, 4041154560, 4041162751,
-STORE, 4041154560, 4041170943,
-STORE, 4041134080, 4041154559,
-SNULL, 4041138175, 4041154559,
-STORE, 4041134080, 4041138175,
-STORE, 4041138176, 4041154559,
-SNULL, 3624374271, 3625414655,
-STORE, 3624370176, 3624374271,
-STORE, 3624374272, 3625414655,
-STORE, 4041125888, 4041134079,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-STORE, 3487174656, 3487584255,
-STORE, 4041121792, 4041125887,
-SNULL, 4041121792, 4041125887,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 3487174656, 3487584255,
-STORE, 3222274048, 3223326719,
-SNULL, 3222274048, 3222278143,
-STORE, 3222278144, 3223326719,
-STORE, 3222274048, 3222278143,
-SNULL, 3223322623, 3223326719,
-STORE, 3222278144, 3223322623,
-STORE, 3223322624, 3223326719,
-STORE, 3221221376, 3222278143,
-SNULL, 3221221376, 3221225471,
-STORE, 3221225472, 3222278143,
-STORE, 3221221376, 3221225471,
-SNULL, 3222269951, 3222278143,
-STORE, 3221225472, 3222269951,
-STORE, 3222269952, 3222278143,
-STORE, 3220168704, 3221225471,
-SNULL, 3220168704, 3220172799,
-STORE, 3220172800, 3221225471,
-STORE, 3220168704, 3220172799,
-SNULL, 3221217279, 3221225471,
-STORE, 3220172800, 3221217279,
-STORE, 3221217280, 3221225471,
-STORE, 4041117696, 4041125887,
-STORE, 4041117696, 4041134079,
-STORE, 3219083264, 3220172799,
-SNULL, 3219083264, 3219087359,
-STORE, 3219087360, 3220172799,
-STORE, 3219083264, 3219087359,
-SNULL, 3220164607, 3220172799,
-STORE, 3219087360, 3220164607,
-STORE, 3220164608, 3220172799,
-STORE, 4041109504, 4041117695,
-STORE, 4041109504, 4041134079,
-STORE, 3217997824, 3219087359,
-SNULL, 3217997824, 3218001919,
-STORE, 3218001920, 3219087359,
-STORE, 3217997824, 3218001919,
-SNULL, 3219079167, 3219087359,
-STORE, 3218001920, 3219079167,
-STORE, 3219079168, 3219087359,
-STORE, 4041101312, 4041109503,
-STORE, 4041101312, 4041134079,
-STORE, 3216912384, 3218001919,
-SNULL, 3216912384, 3216916479,
-STORE, 3216916480, 3218001919,
-STORE, 3216912384, 3216916479,
-SNULL, 3217993727, 3218001919,
-STORE, 3216916480, 3217993727,
-STORE, 3217993728, 3218001919,
-STORE, 4041093120, 4041101311,
-STORE, 4041093120, 4041134079,
-STORE, 3215826944, 3216916479,
-SNULL, 3215826944, 3215831039,
-STORE, 3215831040, 3216916479,
-STORE, 3215826944, 3215831039,
-SNULL, 3216908287, 3216916479,
-STORE, 3215831040, 3216908287,
-STORE, 3216908288, 3216916479,
-STORE, 4016779264, 4016799743,
-SNULL, 4016783359, 4016799743,
-STORE, 4016779264, 4016783359,
-STORE, 4016783360, 4016799743,
-STORE, 4016758784, 4016779263,
-SNULL, 4016762879, 4016779263,
-STORE, 4016758784, 4016762879,
-STORE, 4016762880, 4016779263,
-SNULL, 3222282239, 3223322623,
-STORE, 3222278144, 3222282239,
-STORE, 3222282240, 3223322623,
-STORE, 4041084928, 4041093119,
-STORE, 4041084928, 4041134079,
-SNULL, 3221229567, 3222269951,
-STORE, 3221225472, 3221229567,
-STORE, 3221229568, 3222269951,
-STORE, 4015644672, 4015665151,
-STORE, 4038889472, 4038897663,
-SNULL, 4015648767, 4015665151,
-STORE, 4015644672, 4015648767,
-STORE, 4015648768, 4015665151,
-STORE, 4015624192, 4015644671,
-SNULL, 4015628287, 4015644671,
-STORE, 4015624192, 4015628287,
-STORE, 4015628288, 4015644671,
-SNULL, 3219091455, 3220164607,
-STORE, 3219087360, 3219091455,
-STORE, 3219091456, 3220164607,
-STORE, 4015603712, 4015624191,
-SNULL, 4015607807, 4015624191,
-STORE, 4015603712, 4015607807,
-STORE, 4015607808, 4015624191,
-SNULL, 3218006015, 3219079167,
-STORE, 3218001920, 3218006015,
-STORE, 3218006016, 3219079167,
-STORE, 3949674496, 3949694975,
-SNULL, 3949678591, 3949694975,
-STORE, 3949674496, 3949678591,
-STORE, 3949678592, 3949694975,
-SNULL, 3216920575, 3217993727,
-STORE, 3216916480, 3216920575,
-STORE, 3216920576, 3217993727,
-STORE, 3948924928, 3948945407,
-SNULL, 3948929023, 3948945407,
-STORE, 3948924928, 3948929023,
-STORE, 3948929024, 3948945407,
-SNULL, 3215835135, 3216908287,
-STORE, 3215831040, 3215835135,
-STORE, 3215835136, 3216908287,
-SNULL, 3220176895, 3221217279,
-STORE, 3220172800, 3220176895,
-STORE, 3220176896, 3221217279,
-STORE, 3214786560, 3215826943,
-STORE, 3213733888, 3214786559,
-SNULL, 3213733888, 3213737983,
-STORE, 3213737984, 3214786559,
-STORE, 3213733888, 3213737983,
-SNULL, 3214782463, 3214786559,
-STORE, 3213737984, 3214782463,
-STORE, 3214782464, 3214786559,
-STORE, 4038533120, 4038541311,
-STORE, 3948421120, 3948441599,
-SNULL, 3948425215, 3948441599,
-STORE, 3948421120, 3948425215,
-STORE, 3948425216, 3948441599,
-SNULL, 3213742079, 3214782463,
-STORE, 3213737984, 3213742079,
-STORE, 3213742080, 3214782463,
-STORE, 4038209536, 4038217727,
-STORE, 3212681216, 3213737983,
-SNULL, 3212681216, 3212685311,
-STORE, 3212685312, 3213737983,
-STORE, 3212681216, 3212685311,
-SNULL, 3213729791, 3213737983,
-STORE, 3212685312, 3213729791,
-STORE, 3213729792, 3213737983,
-STORE, 3795763200, 3795894271,
-STORE, 3946872832, 3946893311,
-SNULL, 3946876927, 3946893311,
-STORE, 3946872832, 3946876927,
-STORE, 3946876928, 3946893311,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-STORE, 3487174656, 3487584255,
-SNULL, 3212689407, 3213729791,
-STORE, 3212685312, 3212689407,
-STORE, 3212689408, 3213729791,
-STORE, 4041080832, 4041084927,
-STORE, 4040941568, 4040945663,
-STORE, 4037361664, 4037369855,
-STORE, 4000817152, 4000821247,
-STORE, 3999440896, 3999444991,
-STORE, 3212161024, 3212681215,
-SNULL, 3212161024, 3212439551,
-STORE, 3212439552, 3212681215,
-STORE, 3212161024, 3212439551,
-SNULL, 3212161024, 3212439551,
-SNULL, 3212464127, 3212681215,
-STORE, 3212439552, 3212464127,
-STORE, 3212464128, 3212681215,
-SNULL, 3212464128, 3212681215,
-SNULL, 3212439552, 3212451839,
-STORE, 3212451840, 3212464127,
-STORE, 3212439552, 3212451839,
-SNULL, 3212439552, 3212451839,
-STORE, 3212439552, 3212451839,
-SNULL, 3212451840, 3212455935,
-STORE, 3212455936, 3212464127,
-STORE, 3212451840, 3212455935,
-SNULL, 3212451840, 3212455935,
-STORE, 3212451840, 3212455935,
-SNULL, 3212455936, 3212460031,
-STORE, 3212460032, 3212464127,
-STORE, 3212455936, 3212460031,
-SNULL, 3212455936, 3212460031,
-STORE, 3212455936, 3212460031,
-SNULL, 3212460032, 3212464127,
-STORE, 3212460032, 3212464127,
-STORE, 3997679616, 3997683711,
-SNULL, 4049235968, 4049240063,
-STORE, 4049240064, 4049244159,
-STORE, 4049235968, 4049240063,
-SNULL, 4049240064, 4049244159,
-STORE, 4049240064, 4049244159,
-SNULL, 3997679616, 3997683711,
-SNULL, 3999440896, 3999444991,
-SNULL, 4000817152, 4000821247,
-SNULL, 4040941568, 4040945663,
-SNULL, 4041080832, 4041084927,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 3487174656, 3487584255,
-SNULL, 3212451840, 3212455935,
-STORE, 3212451840, 3212455935,
-STORE, 4041080832, 4041084927,
-STORE, 3623890944, 3624169471,
-SNULL, 4041080832, 4041084927,
-STORE, 4041080832, 4041084927,
-SNULL, 4041080832, 4041084927,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-STORE, 4041080832, 4041084927,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-STORE, 3211386880, 3212439551,
-SNULL, 3211386880, 3211390975,
-STORE, 3211390976, 3212439551,
-STORE, 3211386880, 3211390975,
-SNULL, 3212435455, 3212439551,
-STORE, 3211390976, 3212435455,
-STORE, 3212435456, 3212439551,
-STORE, 4040941568, 4040945663,
-STORE, 3937169408, 3937189887,
-STORE, 3623485440, 3623616511,
-SNULL, 717225983, 1388314623,
-STORE, 314572800, 717225983,
-STORE, 717225984, 1388314623,
-SNULL, 717225984, 1388314623,
-STORE, 3937112064, 3937132543,
-SNULL, 3937116159, 3937132543,
-STORE, 3937112064, 3937116159,
-STORE, 3937116160, 3937132543,
-SNULL, 3211395071, 3212435455,
-STORE, 3211390976, 3211395071,
-STORE, 3211395072, 3212435455,
-STORE, 4000817152, 4000821247,
-STORE, 3974823936, 3974832127,
-STORE, 3595284480, 3595431935,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-STORE, 3487174656, 3487584255,
-STORE, 3999440896, 3999444991,
-STORE, 3997679616, 3997683711,
-STORE, 3996295168, 3996299263,
-STORE, 3996090368, 3996094463,
-STORE, 3210866688, 3211386879,
-SNULL, 3210866688, 3211001855,
-STORE, 3211001856, 3211386879,
-STORE, 3210866688, 3211001855,
-SNULL, 3210866688, 3211001855,
-SNULL, 3211038719, 3211386879,
-STORE, 3211001856, 3211038719,
-STORE, 3211038720, 3211386879,
-SNULL, 3211038720, 3211386879,
-SNULL, 3211001856, 3211022335,
-STORE, 3211022336, 3211038719,
-STORE, 3211001856, 3211022335,
-SNULL, 3211001856, 3211022335,
-STORE, 3211001856, 3211022335,
-SNULL, 3211022336, 3211030527,
-STORE, 3211030528, 3211038719,
-STORE, 3211022336, 3211030527,
-SNULL, 3211022336, 3211030527,
-STORE, 3211022336, 3211030527,
-SNULL, 3211030528, 3211034623,
-STORE, 3211034624, 3211038719,
-STORE, 3211030528, 3211034623,
-SNULL, 3211030528, 3211034623,
-STORE, 3211030528, 3211034623,
-SNULL, 3211034624, 3211038719,
-STORE, 3211034624, 3211038719,
-STORE, 3994906624, 3994910719,
-SNULL, 4049240064, 4049244159,
-STORE, 4049240064, 4049244159,
-SNULL, 3994906624, 3994910719,
-SNULL, 3996090368, 3996094463,
-SNULL, 3996295168, 3996299263,
-SNULL, 3997679616, 3997683711,
-SNULL, 3999440896, 3999444991,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 3487174656, 3487584255,
-SNULL, 3211022336, 3211030527,
-STORE, 3211022336, 3211030527,
-STORE, 3999440896, 3999444991,
-STORE, 3210199040, 3211001855,
-SNULL, 3999440896, 3999444991,
-STORE, 3999440896, 3999444991,
-SNULL, 3999440896, 3999444991,
-STORE, 3594821632, 3594952703,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 4048183296, 4048592895,
-STORE, 4048592896, 4049002495,
-STORE, 4048183296, 4048592895,
-STORE, 4048183296, 4049002495,
-SNULL, 1914101759, 1969434623,
-STORE, 1914097664, 1914101759,
-STORE, 1914101760, 1969434623,
-STORE, 3567108096, 3567239167,
-STORE, 3973832704, 3973840895,
-STORE, 3209113600, 3210199039,
-SNULL, 3209113600, 3209117695,
-STORE, 3209117696, 3210199039,
-STORE, 3209113600, 3209117695,
-SNULL, 3210194943, 3210199039,
-STORE, 3209117696, 3210194943,
-STORE, 3210194944, 3210199039,
-STORE, 3935858688, 3935879167,
-SNULL, 3935862783, 3935879167,
-STORE, 3935858688, 3935862783,
-STORE, 3935862784, 3935879167,
-SNULL, 3209121791, 3210194943,
-STORE, 3209117696, 3209121791,
-STORE, 3209121792, 3210194943,
-STORE, 3528749056, 3528880127,
-STORE, 3968200704, 3968208895,
-STORE, 3208028160, 3209117695,
-SNULL, 3208028160, 3208032255,
-STORE, 3208032256, 3209117695,
-STORE, 3208028160, 3208032255,
-SNULL, 3209109503, 3209117695,
-STORE, 3208032256, 3209109503,
-STORE, 3209109504, 3209117695,
-STORE, 3888123904, 3888144383,
-SNULL, 3888127999, 3888144383,
-STORE, 3888123904, 3888127999,
-STORE, 3888128000, 3888144383,
-SNULL, 3208036351, 3209109503,
-STORE, 3208032256, 3208036351,
-STORE, 3208036352, 3209109503,
-SNULL, 3968200704, 3968208895,
-SNULL, 3888123904, 3888144383,
-SNULL, 3209109504, 3209113599,
-STORE, 3209113600, 3209117695,
-STORE, 3209109504, 3209113599,
-SNULL, 3208028160, 3209113599,
-STORE, 3208060928, 3209117695,
-SNULL, 3208060928, 3208065023,
-STORE, 3208065024, 3209117695,
-STORE, 3208060928, 3208065023,
-SNULL, 3209109503, 3209117695,
-STORE, 3208065024, 3209109503,
-STORE, 3209109504, 3209117695,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3888123904, 3888144383,
-SNULL, 3888127999, 3888144383,
-STORE, 3888123904, 3888127999,
-STORE, 3888128000, 3888144383,
-SNULL, 3208069119, 3209109503,
-STORE, 3208065024, 3208069119,
-STORE, 3208069120, 3209109503,
-STORE, 3968200704, 3968208895,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3527778304, 3527909375,
-STORE, 3999440896, 3999444991,
-STORE, 3997679616, 3997683711,
-STORE, 1914097664, 1914105855,
-STORE, 1914105856, 1969434623,
-STORE, 3957583872, 3957592063,
-STORE, 3206975488, 3208065023,
-SNULL, 3206975488, 3206979583,
-STORE, 3206979584, 3208065023,
-STORE, 3206975488, 3206979583,
-SNULL, 3208056831, 3208065023,
-STORE, 3206979584, 3208056831,
-STORE, 3208056832, 3208065023,
-STORE, 3956736000, 3956744191,
-STORE, 3205890048, 3206979583,
-SNULL, 3205890048, 3205894143,
-STORE, 3205894144, 3206979583,
-STORE, 3205890048, 3205894143,
-SNULL, 3206971391, 3206979583,
-STORE, 3205894144, 3206971391,
-STORE, 3206971392, 3206979583,
-STORE, 3806101504, 3806121983,
-SNULL, 3806105599, 3806121983,
-STORE, 3806101504, 3806105599,
-STORE, 3806105600, 3806121983,
-SNULL, 3206983679, 3208056831,
-STORE, 3206979584, 3206983679,
-STORE, 3206983680, 3208056831,
-STORE, 3806081024, 3806101503,
-SNULL, 3806085119, 3806101503,
-STORE, 3806081024, 3806085119,
-STORE, 3806085120, 3806101503,
-SNULL, 3205898239, 3206971391,
-STORE, 3205894144, 3205898239,
-STORE, 3205898240, 3206971391,
-STORE, 3956015104, 3956023295,
-STORE, 3204804608, 3205894143,
-SNULL, 3204804608, 3204808703,
-STORE, 3204808704, 3205894143,
-STORE, 3204804608, 3204808703,
-SNULL, 3205885951, 3205894143,
-STORE, 3204808704, 3205885951,
-STORE, 3205885952, 3205894143,
-STORE, 3803471872, 3803492351,
-STORE, 3803451392, 3803471871,
-STORE, 3803451392, 3803492351,
-SNULL, 3957583872, 3957592063,
-SNULL, 3806101504, 3806121983,
-SNULL, 3206975487, 3206979583,
-STORE, 3206971392, 3206975487,
-STORE, 3206975488, 3206979583,
-SNULL, 3208056832, 3208060927,
-STORE, 3208060928, 3208065023,
-STORE, 3208056832, 3208060927,
-SNULL, 3206975488, 3208060927,
-STORE, 3801845760, 3801878527,
-STORE, 3806101504, 3806121983,
-SNULL, 3806105599, 3806121983,
-STORE, 3806101504, 3806105599,
-STORE, 3806105600, 3806121983,
-SNULL, 3204812799, 3205885951,
-STORE, 3204808704, 3204812799,
-STORE, 3204812800, 3205885951,
-STORE, 1914097664, 1914109951,
-STORE, 1914109952, 1969434623,
-STORE, 3957583872, 3957592063,
-STORE, 3206971392, 3208065023,
-SNULL, 3206971392, 3206979583,
-STORE, 3206979584, 3208065023,
-STORE, 3206971392, 3206979583,
-SNULL, 3208056831, 3208065023,
-STORE, 3206979584, 3208056831,
-STORE, 3208056832, 3208065023,
-STORE, 3801825280, 3801845759,
-SNULL, 3801829375, 3801845759,
-STORE, 3801825280, 3801829375,
-STORE, 3801829376, 3801845759,
-SNULL, 3206983679, 3208056831,
-STORE, 3206979584, 3206983679,
-STORE, 3206983680, 3208056831,
-STORE, 3202707456, 3204804607,
-SNULL, 3202707456, 3204804607,
-STORE, 3202707456, 3204804607,
-STORE, 3200610304, 3202707455,
-SNULL, 3202707456, 3204804607,
-SNULL, 3200610304, 3202707455,
-STORE, 3202707456, 3204804607,
-SNULL, 3202707456, 3204804607,
-STORE, 3202707456, 3204804607,
-SNULL, 3202707456, 3204804607,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3527647232, 3527778303,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-STORE, 3487059968, 3487584255,
-SNULL, 3487059968, 3487301631,
-STORE, 3487301632, 3487584255,
-STORE, 3487059968, 3487301631,
-SNULL, 3487059968, 3487301631,
-SNULL, 3487563775, 3487584255,
-STORE, 3487301632, 3487563775,
-STORE, 3487563776, 3487584255,
-SNULL, 3487563776, 3487584255,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3524046848, 3524177919,
-STORE, 3487170560, 3487301631,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3487039488, 3487170559,
-STORE, 3487039488, 3487301631,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3204280320, 3204804607,
-SNULL, 3204280320, 3204448255,
-STORE, 3204448256, 3204804607,
-STORE, 3204280320, 3204448255,
-SNULL, 3204280320, 3204448255,
-SNULL, 3204710399, 3204804607,
-STORE, 3204448256, 3204710399,
-STORE, 3204710400, 3204804607,
-SNULL, 3204710400, 3204804607,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3996295168, 3996299263,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-SNULL, 3996295168, 3996299263,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3486908416, 3487039487,
-STORE, 3486908416, 3487301631,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3223326720, 3290435583,
-SNULL, 3223326720, 3256881151,
-STORE, 3256881152, 3290435583,
-STORE, 3223326720, 3256881151,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-STORE, 3201826816, 3202351103,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-STORE, 3202351104, 3204448255,
-SNULL, 3202351104, 3204448255,
-SNULL, 3803471871, 3803492351,
-STORE, 3803451392, 3803471871,
-STORE, 3803471872, 3803492351,
-SNULL, 3803471872, 3803492351,
-SNULL, 3803451392, 3803471871,
-STORE, 3798999040, 3799101439,
-SNULL, 3798999040, 3799101439,
-STORE, 3952644096, 3952652287,
-STORE, 3203362816, 3204448255,
-SNULL, 3203362816, 3203366911,
-STORE, 3203366912, 3204448255,
-STORE, 3203362816, 3203366911,
-SNULL, 3204444159, 3204448255,
-STORE, 3203366912, 3204444159,
-STORE, 3204444160, 3204448255,
-STORE, 3803471872, 3803492351,
-SNULL, 3803475967, 3803492351,
-STORE, 3803471872, 3803475967,
-STORE, 3803475968, 3803492351,
-SNULL, 3203371007, 3204444159,
-STORE, 3203366912, 3203371007,
-STORE, 3203371008, 3204444159,
-STORE, 3199729664, 3201826815,
-SNULL, 3199729664, 3201826815,
-STORE, 3199729664, 3201826815,
-SNULL, 3199729664, 3201826815,
-STORE, 3199729664, 3201826815,
-SNULL, 3199729664, 3201826815,
-STORE, 3199729664, 3201826815,
-SNULL, 3199729664, 3201826815,
-STORE, 3199729664, 3201826815,
-SNULL, 3199729664, 3201826815,
-STORE, 3200774144, 3201826815,
-SNULL, 3200774144, 3200778239,
-STORE, 3200778240, 3201826815,
-STORE, 3200774144, 3200778239,
-SNULL, 3201822719, 3201826815,
-STORE, 3200778240, 3201822719,
-STORE, 3201822720, 3201826815,
-STORE, 3803451392, 3803471871,
-SNULL, 3803455487, 3803471871,
-STORE, 3803451392, 3803455487,
-STORE, 3803455488, 3803471871,
-SNULL, 3200782335, 3201822719,
-STORE, 3200778240, 3200782335,
-STORE, 3200782336, 3201822719,
-STORE, 3949666304, 3949674495,
-STORE, 3949408256, 3949416447,
-STORE, 3199688704, 3200778239,
-SNULL, 3199688704, 3199692799,
-STORE, 3199692800, 3200778239,
-STORE, 3199688704, 3199692799,
-SNULL, 3200770047, 3200778239,
-STORE, 3199692800, 3200770047,
-STORE, 3200770048, 3200778239,
-STORE, 3799306240, 3799326719,
-SNULL, 3799310335, 3799326719,
-STORE, 3799306240, 3799310335,
-STORE, 3799310336, 3799326719,
-SNULL, 3199696895, 3200770047,
-STORE, 3199692800, 3199696895,
-STORE, 3199696896, 3200770047,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-STORE, 3799277568, 3799306239,
-SNULL, 3799277568, 3799306239,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-SNULL, 4041162751, 4041170943,
-STORE, 4041154560, 4041162751,
-STORE, 4041162752, 4041170943,
-SNULL, 4041162752, 4041170943,
-SNULL, 4041154560, 4041162751,
-SNULL, 4041191424, 4041211903,
-SNULL, 4041170944, 4041191423,
-SNULL, 3626471423, 3626475519,
-STORE, 3626467328, 3626471423,
-STORE, 3626471424, 3626475519,
-SNULL, 3626471424, 3627524095,
-SNULL, 3625418751, 3625422847,
-STORE, 3625414656, 3625418751,
-STORE, 3625418752, 3625422847,
-SNULL, 3625418752, 3626471423,
-STORE, 3627393024, 3627524095,
-STORE, 3627261952, 3627393023,
-STORE, 3627261952, 3627524095,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-STORE, 3195494400, 3197591551,
-SNULL, 3197591552, 3199688703,
-SNULL, 3195494400, 3197591551,
-STORE, 3197591552, 3199688703,
-SNULL, 3197591552, 3199688703,
-STORE, 3197591552, 3199688703,
-STORE, 3195494400, 3197591551,
-SNULL, 3197591552, 3199688703,
-SNULL, 3195494400, 3197591551,
-STORE, 3798999040, 3799101439,
-SNULL, 3798999040, 3799101439,
-/*
- * mmap: unmapped_area_topdown: ffff9a9f14ddaa80
- * Gap was found: mt 4041162752 gap_end 4041183232
- * mmap: window was 4052029440 - 4096 size 28672
- * mmap: mas.min 4041154560 max 4041191423 mas.last 4041191423
- * mmap: mas.index 4041162752 align mask 0 offset 0
- * mmap: rb_find_vma find on 4041162752 => ffff9a9f03d19678 (ffff9a9f03d19678)
- */
- };
-
- unsigned long set43[] = {
-STORE, 140737488347136, 140737488351231,
-STORE, 140734187720704, 140737488351231,
-SNULL, 140734187724800, 140737488351231,
-STORE, 140734187589632, 140734187724799,
-STORE, 4194304, 6443007,
-STORE, 4337664, 6443007,
-STORE, 4194304, 4337663,
-SNULL, 4337664, 6443007,
-STORE, 6430720, 6443007,
-STORE, 206158430208, 206160674815,
-STORE, 206158569472, 206160674815,
-STORE, 206158430208, 206158569471,
-SNULL, 206158569472, 206160674815,
-STORE, 206160662528, 206160670719,
-STORE, 206160670720, 206160674815,
-STORE, 140734188756992, 140734188765183,
-STORE, 140734188740608, 140734188756991,
-STORE, 140501948112896, 140501948116991,
- };
-
- int count = 0;
- void *ptr = NULL;
-
- MA_STATE(mas, mt, 0, 0);
-
- mt_set_non_kernel(3);
- check_erase2_testset(mt, set, ARRAY_SIZE(set));
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set2, ARRAY_SIZE(set2));
- start = 140735933894656;
- MT_BUG_ON(mt, !!mt_find(mt, &start, 140735933906943UL));
- mtree_destroy(mt);
-
- mt_set_non_kernel(2);
- mt_init_flags(mt, 0);
- check_erase2_testset(mt, set3, ARRAY_SIZE(set3));
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_init_flags(mt, 0);
- check_erase2_testset(mt, set4, ARRAY_SIZE(set4));
- rcu_read_lock();
- mas_for_each(&mas, entry, ULONG_MAX) {
- if (xa_is_zero(entry))
- continue;
- }
- rcu_read_unlock();
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- mt_set_non_kernel(100);
- check_erase2_testset(mt, set5, ARRAY_SIZE(set5));
- rcu_barrier();
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set6, ARRAY_SIZE(set6));
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set7, ARRAY_SIZE(set7));
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set8, ARRAY_SIZE(set8));
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set9, ARRAY_SIZE(set9));
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set10, ARRAY_SIZE(set10));
- rcu_barrier();
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set11, ARRAY_SIZE(set11));
- rcu_barrier();
- mas_empty_area_rev(&mas, 12288, 140014592737280, 0x2000);
- MT_BUG_ON(mt, mas.last != 140014592573439);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mas.tree = mt;
- count = 0;
- mas.index = 0;
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set12, ARRAY_SIZE(set12));
- rcu_barrier();
- mas_for_each(&mas, entry, ULONG_MAX) {
- if (xa_is_zero(entry))
- continue;
- BUG_ON(count > 12);
- count++;
- }
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set13, ARRAY_SIZE(set13));
- mtree_erase(mt, 140373516443648);
- rcu_read_lock();
- mas_empty_area_rev(&mas, 0, 140373518663680, 4096);
- rcu_read_unlock();
- mtree_destroy(mt);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set14, ARRAY_SIZE(set14));
- rcu_barrier();
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set15, ARRAY_SIZE(set15));
- rcu_barrier();
- mtree_destroy(mt);
-
- /* set16 was to find a bug on limit updating at slot 0. */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set16, ARRAY_SIZE(set16));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 139921865637888, 0x6000);
- MT_BUG_ON(mt, mas.last != 139921865547775);
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- /*
- * set17 found a bug in walking backwards and not counting nulls at
- * the end. This could cause a gap to be missed if the null had any
- * size.
- */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set17, ARRAY_SIZE(set17));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 139953197334528, 0x1000);
- MT_BUG_ON(mt, mas.last != 139953197322239);
-/* MT_BUG_ON(mt, mas.index != 139953197318144); */
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- /*
- * set18 found a bug in walking backwards and not setting the max from
- * the node, but using the parent node. This was only an issue if the
- * next slot in the parent had what we needed.
- */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set18, ARRAY_SIZE(set18));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 140222972858368, 2215936);
- MT_BUG_ON(mt, mas.last != 140222968475647);
- /*MT_BUG_ON(mt, mas.index != 140222966259712); */
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- /*
- * set19 found 2 bugs in prev.
- * 1. If we hit root without finding anything, then there was an
- * infinite loop.
- * 2. The first ascending wasn't using the correct slot which may have
- * caused missed entries.
- */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set19, ARRAY_SIZE(set19));
- rcu_barrier();
- mas.index = 140656779083776;
- entry = mas_find(&mas, ULONG_MAX);
- MT_BUG_ON(mt, entry != xa_mk_value(140656779083776));
- entry = mas_prev(&mas, 0);
- MT_BUG_ON(mt, entry != xa_mk_value(140656766251008));
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- /*
- * set20 found a bug in mas_may_move_gap due to the slot being
- * overwritten during the __mas_add operation and setting it to zero.
- */
- mt_set_non_kernel(99);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set20, ARRAY_SIZE(set20));
- rcu_barrier();
- check_load(mt, 94849009414144, NULL);
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set21, ARRAY_SIZE(set21));
- rcu_barrier();
- mt_validate(mt);
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_set_non_kernel(999);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set22, ARRAY_SIZE(set22));
- rcu_barrier();
- mt_validate(mt);
- ptr = mtree_load(mt, 140551363362816);
- MT_BUG_ON(mt, ptr == mtree_load(mt, 140551363420159));
- mt_set_non_kernel(0);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set23, ARRAY_SIZE(set23));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
-
- mt_set_non_kernel(99);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set24, ARRAY_SIZE(set24));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set25, ARRAY_SIZE(set25));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* Split on NULL followed by delete - causes gap issues. */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set26, ARRAY_SIZE(set26));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 140109042671616, 409600);
- MT_BUG_ON(mt, mas.last != 140109040959487);
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* Split on NULL followed by delete - causes gap issues. */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set27, ARRAY_SIZE(set27));
- rcu_barrier();
- MT_BUG_ON(mt, 0 != mtree_load(mt, 140415537422336));
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set28, ARRAY_SIZE(set28));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 139918413357056, 2097152);
- /* Search for the size of gap then align it (offset 0) */
- mas.index = (mas.last + 1 - 2097152 - 0) & (~2093056);
- MT_BUG_ON(mt, mas.index != 139918401601536);
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* This test found issues with retry moving rebalanced nodes so the
- * incorrect parent pivot was updated.
- */
- mt_set_non_kernel(999);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set29, ARRAY_SIZE(set29));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* This test found issues with deleting all entries in a node when
- * surrounded by entries in the next nodes, then deleting the entries
- * surrounding the node filled with deleted entries.
- */
- mt_set_non_kernel(999);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set30, ARRAY_SIZE(set30));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* This test found an issue with deleting all entries in a node that was
- * the end node and mas_gap incorrectly set next = curr, and curr = prev
- * then moved next to the left, losing data.
- */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set31, ARRAY_SIZE(set31));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set32, ARRAY_SIZE(set32));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
-/*
- * mmap: empty_area_topdown: ffff88821c9cb600 Gap was found:
- * mt 140582827569152 gap_end 140582869532672
- * mmap: window was 140583656296448 - 4096 size 134217728
- * mmap: mas.min 94133881868288 max 140582961786879 mas.last 140582961786879
- * mmap: mas.index 140582827569152 align mask 0 offset 0
- * mmap: rb_find_vma find on
- * 140582827569152 => ffff88821c5bad00 (ffff88821c5bad00)
- */
-
- /* move gap failed due to an entirely empty node */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set33, ARRAY_SIZE(set33));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 140583656296448, 134217728);
- MT_BUG_ON(mt, mas.last != 140583003750399);
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /*
- * Incorrect gap in tree caused by mas_prev not setting the limits
- * correctly while walking down.
- */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set34, ARRAY_SIZE(set34));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* Empty leaf at the end of a parent caused incorrect gap. */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set35, ARRAY_SIZE(set35));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- mt_set_non_kernel(99);
- /* Empty leaf at the end of a parent caused incorrect gap. */
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set36, ARRAY_SIZE(set36));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set37, ARRAY_SIZE(set37));
- rcu_barrier();
- MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712));
- mt_validate(mt);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set38, ARRAY_SIZE(set38));
- rcu_barrier();
- MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712));
- mt_validate(mt);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set39, ARRAY_SIZE(set39));
- rcu_barrier();
- mt_validate(mt);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set40, ARRAY_SIZE(set40));
- rcu_barrier();
- mt_validate(mt);
- mtree_destroy(mt);
-
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set41, ARRAY_SIZE(set41));
- rcu_barrier();
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* move gap failed due to an entirely empty node. */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set42, ARRAY_SIZE(set42));
- rcu_barrier();
- mas_empty_area_rev(&mas, 4096, 4052029440, 28672);
- MT_BUG_ON(mt, mas.last != 4041211903);
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* gap calc off by one */
- mt_set_non_kernel(99);
- mas_reset(&mas);
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- check_erase2_testset(mt, set43, ARRAY_SIZE(set43));
- rcu_barrier();
- mt_set_non_kernel(0);
- mt_validate(mt);
- mtree_destroy(mt);
-}
+#if defined(CONFIG_64BIT)
static noinline void check_alloc_rev_range(struct maple_tree *mt)
{
/*
@@ -34911,6 +735,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
}
+ mas_lock(&mas);
for (i = 0; i < ARRAY_SIZE(holes); i += 3) {
#if DEBUG_REV_RANGE
pr_debug("Search from %lu-%lu for gap %lu should be at %lu\n",
@@ -34931,6 +756,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
mas_reset(&mas);
}
+ mas_unlock(&mas);
for (i = 0; i < req_range_count; i += 5) {
#if DEBUG_REV_RANGE
pr_debug("\tReverse request between %lu-%lu size %lu, should get %lu\n",
@@ -35058,6 +884,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
int i, range_count = ARRAY_SIZE(range);
int req_range_count = ARRAY_SIZE(req_range);
unsigned long min = 0x565234af2000;
+ MA_STATE(mas, mt, 0, 0);
mtree_store_range(mt, MTREE_ALLOC_MAX, ULONG_MAX, XA_ZERO_ENTRY,
GFP_KERNEL);
@@ -35074,8 +901,8 @@ static noinline void check_alloc_range(struct maple_tree *mt)
}
- MA_STATE(mas, mt, 0, 0);
+ mas_lock(&mas);
for (i = 0; i < ARRAY_SIZE(holes); i += 3) {
#if DEBUG_ALLOC_RANGE
@@ -35090,6 +917,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
min = holes[i+1];
mas_reset(&mas);
}
+ mas_unlock(&mas);
for (i = 0; i < req_range_count; i += 5) {
#if DEBUG_ALLOC_RANGE
pr_debug("\tTest %d: %lu-%lu size %lu expected %lu (%lu-%lu)\n",
@@ -35112,6 +940,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
mtree_destroy(mt);
}
+#endif
static noinline void check_ranges(struct maple_tree *mt)
{
@@ -35355,7 +1184,8 @@ static noinline void check_ranges(struct maple_tree *mt)
MT_BUG_ON(mt, mt_height(mt) >= 4);
for (i = 5; i < 45; i += 10)
check_store_range(mt, 11700 + i, 11700 + i + 1, NULL, 0);
- MT_BUG_ON(mt, mt_height(mt) < 4);
+ if (!MAPLE_32BIT)
+ MT_BUG_ON(mt, mt_height(mt) < 4);
mtree_destroy(mt);
@@ -35376,16 +1206,17 @@ static noinline void check_ranges(struct maple_tree *mt)
MT_BUG_ON(mt, mt_height(mt) >= 4);
/* triple split across multiple levels. */
check_store_range(mt, 8184, 8184, xa_mk_value(8184), 0);
- MT_BUG_ON(mt, mt_height(mt) != 4);
+ if (!MAPLE_32BIT)
+ MT_BUG_ON(mt, mt_height(mt) != 4);
}
static noinline void check_next_entry(struct maple_tree *mt)
{
void *entry = NULL;
unsigned long limit = 30, i = 0;
+ MA_STATE(mas, mt, i, i);
MT_BUG_ON(mt, !mtree_empty(mt));
- MA_STATE(mas, mt, i, i);
check_seq(mt, limit, false);
rcu_read_lock();
@@ -35536,353 +1367,13 @@ static noinline void check_root_expand(struct maple_tree *mt)
mas_unlock(&mas);
}
-static noinline void check_prealloc(struct maple_tree *mt)
-{
- unsigned long i, max = 100;
- unsigned long allocated;
- unsigned char height;
- struct maple_node *mn;
- void *ptr = check_prealloc;
- MA_STATE(mas, mt, 10, 20);
-
- mt_set_non_kernel(1000);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_destroy(&mas);
- allocated = mas_allocated(&mas);
- MT_BUG_ON(mt, allocated != 0);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- mas_destroy(&mas);
- allocated = mas_allocated(&mas);
- MT_BUG_ON(mt, allocated != 0);
-
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
- ma_free_rcu(mn);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- mas_destroy(&mas);
- allocated = mas_allocated(&mas);
- MT_BUG_ON(mt, allocated != 0);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- mas_destroy(&mas);
- allocated = mas_allocated(&mas);
- MT_BUG_ON(mt, allocated != 0);
- ma_free_rcu(mn);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mn = mas_pop_node(&mas);
- MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
- mas_push_node(&mas, mn);
- MT_BUG_ON(mt, mas_allocated(&mas) != allocated);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- mas_destroy(&mas);
- allocated = mas_allocated(&mas);
- MT_BUG_ON(mt, allocated != 0);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_store_prealloc(&mas, ptr);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_store_prealloc(&mas, ptr);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_store_prealloc(&mas, ptr);
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_store_prealloc(&mas, ptr);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- mt_set_non_kernel(1);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL & GFP_NOWAIT) == 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated != 0);
- mas_destroy(&mas);
-
-
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated == 0);
- MT_BUG_ON(mt, allocated != 1 + height * 3);
- mas_store_prealloc(&mas, ptr);
- MT_BUG_ON(mt, mas_allocated(&mas) != 0);
- mt_set_non_kernel(1);
- MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL & GFP_NOWAIT) == 0);
- allocated = mas_allocated(&mas);
- height = mas_mt_height(&mas);
- MT_BUG_ON(mt, allocated != 0);
-}
-
-static noinline void check_spanning_write(struct maple_tree *mt)
-{
- unsigned long i, max = 5000;
- MA_STATE(mas, mt, 1200, 2380);
-
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 1205);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- for (i = 1; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mtree_lock(mt);
- mas_set_range(&mas, 9, 50006); /* Will expand to 0 - ULONG_MAX */
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 1205);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mt_validate(mt);
- mtree_destroy(mt);
-
- /* Test spanning store that requires a right cousin rebalance */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 0, 12900); /* Spans more than 2 levels */
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 1205);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test non-alloc tree spanning store */
- mt_init_flags(mt, 0);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 0, 300);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 15);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test spanning store that requires a right sibling rebalance */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 0, 12865);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 15);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test spanning store that requires a left sibling rebalance */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 90, 13665);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 95);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test spanning store that requires a left cousin rebalance */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 46805, 49995);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 46815);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /*
- * Test spanning store that requires a left cousin rebalance all the way
- * to root
- */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mas_set_range(&mas, 32395, 49995);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 46815);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /*
- * Test spanning store that requires a right cousin rebalance all the
- * way to root
- */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
- mas_set_range(&mas, 38875, 43190);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 38900);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test spanning store ending at full node (depth 2)*/
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
- mtree_lock(mt);
- mas_set(&mas, 47606);
- mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
- mas_set(&mas, 47607);
- mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
- mas_set(&mas, 47608);
- mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
- mas_set(&mas, 47609);
- mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
- /* Ensure the parent node is full */
- mas_ascend(&mas);
- MT_BUG_ON(mt, (mas_data_end(&mas)) != mt_slot_count(mas.node) - 1);
- mas_set_range(&mas, 11516, 48940);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- /* Test spanning write with many levels of no siblings */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
- mas_set_range(&mas, 43200, 49999);
- mtree_lock(mt);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mas_set(&mas, 43200);
- MT_BUG_ON(mt, mas_walk(&mas) != NULL);
- mtree_unlock(mt);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= 100; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
-
- mtree_lock(mt);
- mas_set_range(&mas, 76, 875);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- mtree_unlock(mt);
-}
-
-static noinline void check_null_expand(struct maple_tree *mt)
-{
- unsigned long i, max = 100;
- unsigned char data_end;
- MA_STATE(mas, mt, 959, 959);
-
- for (i = 0; i <= max; i++)
- mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
- /* Test expanding null at start. */
- mas_walk(&mas);
- data_end = mas_data_end(&mas);
- mas_set_range(&mas, 959, 963);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- MT_BUG_ON(mt, mtree_load(mt, 963) != NULL);
- MT_BUG_ON(mt, data_end != mas_data_end(&mas));
-
- /* Test expanding null at end. */
- mas_set(&mas, 880);
- mas_walk(&mas);
- data_end = mas_data_end(&mas);
- mas_set_range(&mas, 884, 887);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- MT_BUG_ON(mt, mtree_load(mt, 884) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 889) != NULL);
- MT_BUG_ON(mt, data_end != mas_data_end(&mas));
-
- /* Test expanding null at start and end. */
- mas_set(&mas, 890);
- mas_walk(&mas);
- data_end = mas_data_end(&mas);
- mas_set_range(&mas, 900, 905);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- MT_BUG_ON(mt, mtree_load(mt, 899) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 900) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 905) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 906) != NULL);
- MT_BUG_ON(mt, data_end - 2 != mas_data_end(&mas));
-
- /* Test expanding null across multiple slots. */
- mas_set(&mas, 800);
- mas_walk(&mas);
- data_end = mas_data_end(&mas);
- mas_set_range(&mas, 810, 825);
- mas_store_gfp(&mas, NULL, GFP_KERNEL);
- MT_BUG_ON(mt, mtree_load(mt, 809) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 810) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 825) != NULL);
- MT_BUG_ON(mt, mtree_load(mt, 826) != NULL);
- MT_BUG_ON(mt, data_end - 4 != mas_data_end(&mas));
-}
-
static noinline void check_gap_combining(struct maple_tree *mt)
{
struct maple_enode *mn1, *mn2;
void *entry;
-
- unsigned long seq100[] = {
+ unsigned long singletons = 100;
+ unsigned long *seq100;
+ unsigned long seq100_64[] = {
/* 0-5 */
74, 75, 76,
50, 100, 2,
@@ -35895,6 +1386,21 @@ static noinline void check_gap_combining(struct maple_tree *mt)
80, 81, 82,
76, 2, 79, 85, 4,
};
+
+ unsigned long seq100_32[] = {
+ /* 0-5 */
+ 61, 62, 63,
+ 50, 100, 2,
+
+ /* 6-12 */
+ 31, 32, 33, 30,
+ 20, 50, 3,
+
+ /* 13-20*/
+ 80, 81, 82,
+ 76, 2, 79, 85, 4,
+ };
+
unsigned long seq2000[] = {
1152, 1151,
1100, 1200, 2,
@@ -35905,12 +1411,19 @@ static noinline void check_gap_combining(struct maple_tree *mt)
286, 310,
};
- unsigned long index = seq100[0];
+ unsigned long index;
- MA_STATE(mas, mt, index, index);
+ MA_STATE(mas, mt, 0, 0);
+
+ if (MAPLE_32BIT)
+ seq100 = seq100_32;
+ else
+ seq100 = seq100_64;
+ index = seq100[0];
+ mas_set(&mas, index);
MT_BUG_ON(mt, !mtree_empty(mt));
- check_seq(mt, 100, false); /* create 100 singletons. */
+ check_seq(mt, singletons, false); /* create 100 singletons. */
mt_set_non_kernel(1);
mtree_test_erase(mt, seq100[2]);
@@ -36063,108 +1576,6 @@ static noinline void check_node_overwrite(struct maple_tree *mt)
mt_validate(mt);
}
-static void mas_dfs_preorder(struct ma_state *mas)
-{
-
- struct maple_enode *prev;
- unsigned char end, slot = 0;
-
- if (mas_is_start(mas)) {
- mas_start(mas);
- return;
- }
-
- if (mte_is_leaf(mas->node) && mte_is_root(mas->node))
- goto done;
-
-walk_up:
- end = mas_data_end(mas);
- if (mte_is_leaf(mas->node) ||
- (slot > end)) {
- if (mte_is_root(mas->node))
- goto done;
-
- slot = mte_parent_slot(mas->node) + 1;
- mas_ascend(mas);
- goto walk_up;
- }
-
- prev = mas->node;
- mas->node = mas_get_slot(mas, slot);
- if (!mas->node || slot > end) {
- if (mte_is_root(prev))
- goto done;
-
- mas->node = prev;
- slot = mte_parent_slot(mas->node) + 1;
- mas_ascend(mas);
- goto walk_up;
- }
-
- return;
-done:
- mas->node = MAS_NONE;
-}
-
-
-static void check_dfs_preorder(struct maple_tree *mt)
-{
- unsigned long count = 0, max = 1000;
-
- MA_STATE(mas, mt, 0, 0);
-
- check_seq(mt, max, false);
- do {
- count++;
- mas_dfs_preorder(&mas);
- } while (!mas_is_none(&mas));
- MT_BUG_ON(mt, count != 74);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- mas_reset(&mas);
- count = 0;
- check_seq(mt, max, false);
- do {
- count++;
- mas_dfs_preorder(&mas);
- } while (!mas_is_none(&mas));
- /*printk("count %lu\n", count); */
- MT_BUG_ON(mt, count != 77);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- mas_reset(&mas);
- count = 0;
- check_rev_seq(mt, max, false);
- do {
- count++;
- mas_dfs_preorder(&mas);
- } while (!mas_is_none(&mas));
- /*printk("count %lu\n", count); */
- MT_BUG_ON(mt, count != 77);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- mas_reset(&mas);
- mt_zero_nr_tallocated();
- mt_set_non_kernel(200);
- mas_expected_entries(&mas, max);
- for (count = 0; count <= max; count++) {
- mas.index = mas.last = count;
- mas_store(&mas, xa_mk_value(count));
- MT_BUG_ON(mt, mas_is_err(&mas));
- }
- mas_destroy(&mas);
- rcu_barrier();
- /*
- * pr_info(" ->seq test of 0-%lu %luK in %d active (%d total)\n",
- * max, mt_get_alloc_size()/1024, mt_nr_allocated(),
- * mt_nr_tallocated());
- */
-
-}
-
#if defined(BENCH_SLOT_STORE)
static noinline void bench_slot_store(struct maple_tree *mt)
{
@@ -36258,6 +1669,7 @@ static noinline void bench_mt_for_each(struct maple_tree *mt)
}
#endif
+/* check_forking - simulate the kernel forking sequence with the tree. */
static noinline void check_forking(struct maple_tree *mt)
{
@@ -36276,18 +1688,22 @@ static noinline void check_forking(struct maple_tree *mt)
newmas.tree = &newmt;
mas_reset(&newmas);
mas_reset(&mas);
+ mas_lock(&newmas);
mas.index = 0;
mas.last = 0;
if (mas_expected_entries(&newmas, nr_entries)) {
pr_err("OOM!");
BUG_ON(1);
}
+ rcu_read_lock();
mas_for_each(&mas, val, ULONG_MAX) {
newmas.index = mas.index;
newmas.last = mas.last;
mas_store(&newmas, val);
}
+ rcu_read_unlock();
mas_destroy(&newmas);
+ mas_unlock(&newmas);
mt_validate(&newmt);
mt_set_non_kernel(0);
mtree_destroy(&newmt);
@@ -36309,6 +1725,8 @@ static noinline void check_mas_store_gfp(struct maple_tree *mt)
mt_set_non_kernel(99999);
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
newmas.tree = &newmt;
+ rcu_read_lock();
+ mas_lock(&newmas);
mas_reset(&newmas);
mas_set(&mas, 0);
mas_for_each(&mas, val, ULONG_MAX) {
@@ -36316,7 +1734,8 @@ static noinline void check_mas_store_gfp(struct maple_tree *mt)
newmas.last = mas.last;
mas_store_gfp(&newmas, val, GFP_KERNEL);
}
-
+ mas_unlock(&newmas);
+ rcu_read_unlock();
mt_validate(&newmt);
mt_set_non_kernel(0);
mtree_destroy(&newmt);
@@ -36344,6 +1763,8 @@ static noinline void bench_forking(struct maple_tree *mt)
mas_reset(&mas);
mas.index = 0;
mas.last = 0;
+ rcu_read_lock();
+ mas_lock(&newmas);
if (mas_expected_entries(&newmas, nr_entries)) {
printk("OOM!");
BUG_ON(1);
@@ -36354,6 +1775,8 @@ static noinline void bench_forking(struct maple_tree *mt)
mas_store(&newmas, val);
}
mas_destroy(&newmas);
+ mas_unlock(&newmas);
+ rcu_read_unlock();
mt_validate(&newmt);
mt_set_non_kernel(0);
mtree_destroy(&newmt);
@@ -36363,15 +1786,27 @@ static noinline void bench_forking(struct maple_tree *mt)
static noinline void next_prev_test(struct maple_tree *mt)
{
- int i, nr_entries = 200;
+ int i, nr_entries;
void *val;
MA_STATE(mas, mt, 0, 0);
struct maple_enode *mn;
+ unsigned long *level2;
+ unsigned long level2_64[] = {707, 1000, 710, 715, 720, 725};
+ unsigned long level2_32[] = {1747, 2000, 1750, 1755, 1760, 1765};
+
+ if (MAPLE_32BIT) {
+ nr_entries = 500;
+ level2 = level2_32;
+ } else {
+ nr_entries = 200;
+ level2 = level2_64;
+ }
for (i = 0; i <= nr_entries; i++)
mtree_store_range(mt, i*10, i*10 + 5,
xa_mk_value(i), GFP_KERNEL);
+ mas_lock(&mas);
for (i = 0; i <= nr_entries / 2; i++) {
mas_next(&mas, 1000);
if (mas_is_none(&mas))
@@ -36442,33 +1877,32 @@ static noinline void next_prev_test(struct maple_tree *mt)
/* Check across two levels of the tree */
mas_reset(&mas);
- mas_set(&mas, 707);
+ mas_set(&mas, level2[0]);
val = mas_walk(&mas);
MT_BUG_ON(mt, val != NULL);
- val = mas_next(&mas, 1000);
- MT_BUG_ON(mt, val != xa_mk_value(710 / 10));
- MT_BUG_ON(mt, mas.index != 710);
- MT_BUG_ON(mt, mas.last != 715);
+ val = mas_next(&mas, level2[1]);
+ MT_BUG_ON(mt, val != xa_mk_value(level2[2] / 10));
+ MT_BUG_ON(mt, mas.index != level2[2]);
+ MT_BUG_ON(mt, mas.last != level2[3]);
mn = mas.node;
- val = mas_next(&mas, 1000);
- MT_BUG_ON(mt, val != xa_mk_value(720 / 10));
- MT_BUG_ON(mt, mas.index != 720);
- MT_BUG_ON(mt, mas.last != 725);
+ val = mas_next(&mas, level2[1]);
+ MT_BUG_ON(mt, val != xa_mk_value(level2[4] / 10));
+ MT_BUG_ON(mt, mas.index != level2[4]);
+ MT_BUG_ON(mt, mas.last != level2[5]);
MT_BUG_ON(mt, mn == mas.node);
val = mas_prev(&mas, 0);
- MT_BUG_ON(mt, val != xa_mk_value(710 / 10));
- MT_BUG_ON(mt, mas.index != 710);
- MT_BUG_ON(mt, mas.last != 715);
+ MT_BUG_ON(mt, val != xa_mk_value(level2[2] / 10));
+ MT_BUG_ON(mt, mas.index != level2[2]);
+ MT_BUG_ON(mt, mas.last != level2[3]);
/* Check running off the end and back on */
- mas_reset(&mas);
- mas_set(&mas, 2000);
+ mas_set(&mas, nr_entries * 10);
val = mas_walk(&mas);
- MT_BUG_ON(mt, val != xa_mk_value(2000 / 10));
- MT_BUG_ON(mt, mas.index != 2000);
- MT_BUG_ON(mt, mas.last != 2005);
+ MT_BUG_ON(mt, val != xa_mk_value(nr_entries));
+ MT_BUG_ON(mt, mas.index != (nr_entries * 10));
+ MT_BUG_ON(mt, mas.last != (nr_entries * 10 + 5));
val = mas_next(&mas, ULONG_MAX);
MT_BUG_ON(mt, val != NULL);
@@ -36476,9 +1910,9 @@ static noinline void next_prev_test(struct maple_tree *mt)
MT_BUG_ON(mt, mas.last != ULONG_MAX);
val = mas_prev(&mas, 0);
- MT_BUG_ON(mt, val != xa_mk_value(2000 / 10));
- MT_BUG_ON(mt, mas.index != 2000);
- MT_BUG_ON(mt, mas.last != 2005);
+ MT_BUG_ON(mt, val != xa_mk_value(nr_entries));
+ MT_BUG_ON(mt, mas.index != (nr_entries * 10));
+ MT_BUG_ON(mt, mas.last != (nr_entries * 10 + 5));
/* Check running off the start and back on */
mas_reset(&mas);
@@ -36509,990 +1943,21 @@ static noinline void next_prev_test(struct maple_tree *mt)
MT_BUG_ON(mt, val != NULL);
MT_BUG_ON(mt, mas.index != 0);
MT_BUG_ON(mt, mas.last != 0);
+ mas_unlock(&mas);
mtree_destroy(mt);
mt_init(mt);
mtree_store_range(mt, 0, 0, xa_mk_value(0), GFP_KERNEL);
mtree_store_range(mt, 5, 5, xa_mk_value(5), GFP_KERNEL);
+ rcu_read_lock();
mas_set(&mas, 5);
val = mas_prev(&mas, 4);
MT_BUG_ON(mt, val != NULL);
-}
-
-#define RCU_RANGE_COUNT 1000
-#define RCU_MT_BUG_ON(test, y) {if (y) { test->stop = true;} MT_BUG_ON(test->mt, y);}
-struct rcu_test_struct2 {
- struct maple_tree *mt;
-
- bool start;
- bool stop;
- unsigned int thread_count;
-
- unsigned int seen_toggle;
- unsigned int seen_added;
- unsigned int seen_modified;
- unsigned int seen_deleted;
- int pause;
-
- unsigned long index[RCU_RANGE_COUNT];
- unsigned long last[RCU_RANGE_COUNT];
-};
-
-struct rcu_reader_struct {
- unsigned int id;
- int mod;
- int del;
- int flip;
- int add;
- int next;
- struct rcu_test_struct2 *test;
-};
-
-/* RCU reader helper function */
-static void rcu_reader_register(struct rcu_test_struct2 *test)
-{
- rcu_register_thread();
- uatomic_inc(&test->thread_count);
-
- while (!test->start)
- usleep(test->pause * 100);
-}
-
-static void rcu_reader_setup(struct rcu_reader_struct *reader,
- unsigned int id, struct rcu_test_struct2 *test)
-{
- reader->id = id;
- reader->test = test;
- reader->mod = reader->id % 10;
- reader->del = (reader->mod + 1) % 10;
- reader->flip = (reader->mod + 2) % 10;
- reader->add = (reader->mod + 3) % 10;
- reader->next = (reader->mod + 4) % 10;
-}
-
-/* RCU reader in increasing index */
-static void *rcu_reader_fwd(void *ptr)
-{
- struct rcu_reader_struct *reader = (struct rcu_reader_struct *)ptr;
- struct rcu_test_struct2 *test = reader->test;
- unsigned long index = reader->id;
- bool toggled, modified, deleted, added;
- int i;
- void *entry, *prev = NULL;
- MA_STATE(mas, test->mt, 0, 0);
-
- rcu_reader_register(test);
- toggled = modified = deleted = added = false;
-
- while (!test->stop) {
- i = 0;
- /* mas_for_each ?*/
- rcu_read_lock();
- mas_set(&mas, test->index[index]);
- mas_for_each(&mas, entry, test->last[index + 9]) {
- unsigned long r_start, r_end, alt_start;
- void *expected, *alt;
-
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
-
- if (i == reader->del) {
- if (!deleted) {
- alt_start = test->index[index + reader->flip];
- /* delete occurred. */
- if (mas.index == alt_start) {
- uatomic_inc(&test->seen_deleted);
- deleted = true;
- }
- }
- if (deleted) {
- i = reader->flip;
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
- }
- }
-
- if (!added && (i == reader->add)) {
- alt_start = test->index[index + reader->next];
- if (mas.index == r_start) {
- uatomic_inc(&test->seen_added);
- added = true;
- } else if (mas.index == alt_start) {
- i = reader->next;
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
- }
- }
-
- RCU_MT_BUG_ON(test, mas.index != r_start);
- RCU_MT_BUG_ON(test, mas.last != r_end);
-
- if (i == reader->flip) {
- alt = xa_mk_value(index + i + RCU_RANGE_COUNT);
- if (prev) {
- if (toggled && entry == expected)
- uatomic_inc(&test->seen_toggle);
- else if (!toggled && entry == alt)
- uatomic_inc(&test->seen_toggle);
- }
-
- if (entry == expected)
- toggled = false;
- else if (entry == alt)
- toggled = true;
- else {
- printk("!!%lu-%lu -> %p not %p or %p\n", mas.index, mas.last, entry, expected, alt);
- RCU_MT_BUG_ON(test, 1);
- }
-
- prev = entry;
- } else if (i == reader->mod) {
- alt = xa_mk_value(index + i * 2 + 1 +
- RCU_RANGE_COUNT);
- if (entry != expected) {
- if (!modified)
- uatomic_inc(&test->seen_modified);
- modified = true;
- } else {
- if (modified)
- uatomic_inc(&test->seen_modified);
- modified = false;
- }
-
- if (modified)
- RCU_MT_BUG_ON(test, entry != alt);
-
- } else {
- if (entry != expected)
- printk("!!%lu-%lu -> %p not %p\n", mas.index, mas.last, entry, expected);
- RCU_MT_BUG_ON(test, entry != expected);
- }
-
- i++;
- }
- rcu_read_unlock();
- usleep(test->pause);
- }
-
- rcu_unregister_thread();
- return NULL;
-}
-
-/* RCU reader in decreasing index */
-static void *rcu_reader_rev(void *ptr)
-{
- struct rcu_reader_struct *reader = (struct rcu_reader_struct *)ptr;
- struct rcu_test_struct2 *test = reader->test;
- unsigned long index = reader->id;
- bool toggled, modified, deleted, added;
- int i;
- void *prev = NULL;
- MA_STATE(mas, test->mt, 0, 0);
-
- rcu_reader_register(test);
- toggled = modified = deleted = added = false;
-
-
- while (!test->stop) {
- void *entry;
-
- i = 9;
- mas_set(&mas, test->index[index + i]);
-
- rcu_read_lock();
- while (i--) {
- unsigned long r_start, r_end, alt_start;
- void *expected, *alt;
- int line = __LINE__;
-
- entry = mas_prev(&mas, test->index[index]);
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
-
- if (i == reader->del) {
- alt_start = test->index[index + reader->mod];
- if (mas.index == alt_start) {
- line = __LINE__;
- if (!deleted)
- uatomic_inc(&test->seen_deleted);
- deleted = true;
- }
- if (deleted) {
- line = __LINE__;
- i = reader->mod;
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
- }
- }
- if (!added && (i == reader->add)) {
- alt_start = test->index[index + reader->flip];
- if (mas.index == r_start) {
- line = __LINE__;
- uatomic_inc(&test->seen_added);
- added = true;
- } else if (mas.index == alt_start) {
- line = __LINE__;
- i = reader->flip;
- r_start = test->index[index + i];
- r_end = test->last[index + i];
- expected = xa_mk_value(r_start);
- }
- }
-
- if (i == reader->mod)
- line = __LINE__;
- else if (i == reader->flip)
- line = __LINE__;
-
- if (mas.index != r_start) {
- alt = xa_mk_value(index + i * 2 + 1 +
- RCU_RANGE_COUNT);
- mt_dump(test->mt);
- printk("Error: %lu-%lu %p != %lu-%lu %p %p line %d i %d\n",
- mas.index, mas.last, entry,
- r_start, r_end, expected, alt,
- line, i);
- }
- RCU_MT_BUG_ON(test, mas.index != r_start);
- RCU_MT_BUG_ON(test, mas.last != r_end);
-
- if (i == reader->mod) {
- alt = xa_mk_value(index + i * 2 + 1 +
- RCU_RANGE_COUNT);
-
- if (entry != expected) {
- if (!modified)
- uatomic_inc(&test->seen_modified);
- modified = true;
- } else {
- if (modified)
- uatomic_inc(&test->seen_modified);
- modified = false;
- }
- if (modified)
- RCU_MT_BUG_ON(test, entry != alt);
-
-
- } else if (i == reader->flip) {
- alt = xa_mk_value(index + i +
- RCU_RANGE_COUNT);
- if (prev) {
- if (toggled && entry == expected)
- uatomic_inc(&test->seen_toggle);
- else if (!toggled && entry == alt)
- uatomic_inc(&test->seen_toggle);
- }
-
- if (entry == expected)
- toggled = false;
- else if (entry == alt)
- toggled = true;
- else {
- printk("%lu-%lu %p != %p or %p\n",
- mas.index, mas.last, entry,
- expected, alt);
- RCU_MT_BUG_ON(test, 1);
- }
-
- prev = entry;
- } else {
- if (entry != expected)
- printk("%lu-%lu %p != %p\n", mas.index,
- mas.last, entry, expected);
- RCU_MT_BUG_ON(test, entry != expected);
- }
- }
- rcu_read_unlock();
- usleep(test->pause);
- }
-
- rcu_unregister_thread();
- return NULL;
-}
-
-static void rcu_stress_rev(struct maple_tree *mt, struct rcu_test_struct2 *test,
- int count, struct rcu_reader_struct *test_reader)
-{
- int i, j = 10000;
- bool toggle = true;
-
- test->start = true; /* Release the hounds! */
- usleep(5);
-
- while (j--) {
- toggle = !toggle;
- i = count;
- while (i--) {
- unsigned long start, end;
- struct rcu_reader_struct *this = &test_reader[i];
-
- /* Mod offset */
- if (j == 600) {
- start = test->index[this->id + this->mod];
- end = test->last[this->id + this->mod];
- mtree_store_range(mt, start, end,
- xa_mk_value(this->id + this->mod * 2 +
- 1 + RCU_RANGE_COUNT),
- GFP_KERNEL);
- }
-
- /* Toggle */
- if (!(j % 5)) {
- start = test->index[this->id + this->flip];
- end = test->last[this->id + this->flip];
- mtree_store_range(mt, start, end,
- xa_mk_value((toggle ? start :
- this->id + this->flip +
- RCU_RANGE_COUNT)),
- GFP_KERNEL);
- }
-
- /* delete */
- if (j == 400) {
- start = test->index[this->id + this->del];
- end = test->last[this->id + this->del];
- mtree_store_range(mt, start, end, NULL, GFP_KERNEL);
- }
-
- /* add */
- if (j == 500) {
- start = test->index[this->id + this->add];
- end = test->last[this->id + this->add];
- mtree_store_range(mt, start, end,
- xa_mk_value(start), GFP_KERNEL);
- }
- }
- usleep(test->pause);
- /* If a test fails, don't flood the console */
- if (test->stop)
- break;
- }
-}
-
-static void rcu_stress_fwd(struct maple_tree *mt, struct rcu_test_struct2 *test,
- int count, struct rcu_reader_struct *test_reader)
-{
- int j, i;
- bool toggle = true;
-
- test->start = true; /* Release the hounds! */
- usleep(5);
- for (j = 0; j < 10000; j++) {
- toggle = !toggle;
- for (i = 0; i < count; i++) {
- unsigned long start, end;
- struct rcu_reader_struct *this = &test_reader[i];
-
- /* Mod offset */
- if (j == 600) {
- start = test->index[this->id + this->mod];
- end = test->last[this->id + this->mod];
- mtree_store_range(mt, start, end,
- xa_mk_value(this->id + this->mod * 2 +
- 1 + RCU_RANGE_COUNT),
- GFP_KERNEL);
- }
-
- /* Toggle */
- if (!(j % 5)) {
- start = test->index[this->id + this->flip];
- end = test->last[this->id + this->flip];
- mtree_store_range(mt, start, end,
- xa_mk_value((toggle ? start :
- this->id + this->flip +
- RCU_RANGE_COUNT)),
- GFP_KERNEL);
- }
-
- /* delete */
- if (j == 400) {
- start = test->index[this->id + this->del];
- end = test->last[this->id + this->del];
- mtree_store_range(mt, start, end, NULL, GFP_KERNEL);
- }
-
- /* add */
- if (j == 500) {
- start = test->index[this->id + this->add];
- end = test->last[this->id + this->add];
- mtree_store_range(mt, start, end,
- xa_mk_value(start), GFP_KERNEL);
- }
- }
- usleep(test->pause);
- /* If a test fails, don't flood the console */
- if (test->stop)
- break;
- }
-}
-
-/*
- * This is to check:
- * 1. Range that is not ever present
- * 2. Range that is always present
- * 3. Things being added but not removed.
- * 4. Things being removed but not added.
- * 5. Things are being added and removed, searches my succeed or fail
- *
- * This sets up two readers for every 10 entries; one forward and one reverse
- * reading.
- */
-static void rcu_stress(struct maple_tree *mt, bool forward)
-{
- unsigned int count, i;
- unsigned long r, seed;
- pthread_t readers[RCU_RANGE_COUNT / 5];
- struct rcu_test_struct2 test;
- struct rcu_reader_struct test_reader[RCU_RANGE_COUNT / 5];
- void *(*function)(void *);
-
- /* Test setup */
- test.mt = mt;
- test.pause = 5;
- test.seen_toggle = 0;
- test.seen_deleted = 0;
- test.seen_added = 0;
- test.seen_modified = 0;
- test.thread_count = 0;
- test.start = test.stop = false;
- seed = time(NULL);
- srand(seed);
- for (i = 0; i < RCU_RANGE_COUNT; i++) {
- r = seed + rand();
- mtree_store_range(mt, seed, r,
- xa_mk_value(seed), GFP_KERNEL);
-
- /* Record start and end of entry */
- test.index[i] = seed;
- test.last[i] = r;
- seed = 1 + r + rand() % 10;
- }
-
- i = count = ARRAY_SIZE(readers);
- while (i--) {
- unsigned long id;
-
- id = i / 2 * 10;
- if (i % 2)
- function = rcu_reader_fwd;
- else
- function = rcu_reader_rev;
-
- rcu_reader_setup(&test_reader[i], id, &test);
- if (pthread_create(&readers[i], NULL, *function,
- &test_reader[i])) {
- perror("creating reader thread");
- exit(1);
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(readers); i++) {
- struct rcu_reader_struct *this = &test_reader[i];
- int add = this->id + this->add;
-
- /* Remove add entries from the tree for later addition */
- mtree_store_range(mt, test.index[add], test.last[add],
- NULL, GFP_KERNEL);
- }
-
- mt_set_in_rcu(mt);
- do {
- usleep(5);
- } while (test.thread_count > ARRAY_SIZE(readers));
-
- if (forward)
- rcu_stress_fwd(mt, &test, count, test_reader);
- else
- rcu_stress_rev(mt, &test, count, test_reader);
-
- test.stop = true;
- while (count--)
- pthread_join(readers[count], NULL);
-
- mt_validate(mt);
-}
-
-
-struct rcu_test_struct {
- struct maple_tree *mt; /* the maple tree */
- int count; /* Number of times to check value(s) */
- unsigned long index; /* The first index to check */
- void *entry1; /* The first entry value */
- void *entry2; /* The second entry value */
- void *entry3; /* The third entry value */
-
- bool update_2;
- bool update_3;
- unsigned long range_start;
- unsigned long range_end;
- unsigned int loop_sleep;
- unsigned int val_sleep;
-
- unsigned int failed; /* failed detection for other threads */
- unsigned int seen_entry2; /* Number of threads that have seen the new value */
- unsigned int seen_entry3; /* Number of threads that have seen the new value */
- unsigned int seen_both; /* Number of threads that have seen both new values */
- unsigned int seen_toggle;
- unsigned int seen_added;
- unsigned int seen_removed;
- unsigned long last; /* The end of the range to write. */
-
- unsigned long removed; /* The index of the removed entry */
- unsigned long added; /* The index of the removed entry */
- unsigned long toggle; /* The index of the removed entry */
-};
-
-static inline
-int eval_rcu_entry(struct rcu_test_struct *test, void *entry, bool *update_2,
- bool *update_3)
-{
- if (entry == test->entry1)
- return 0;
-
- if (entry == test->entry2) {
- if (!(*update_2)) {
- uatomic_inc(&test->seen_entry2);
- *update_2 = true;
- if (update_3)
- uatomic_inc(&test->seen_both);
- }
- return 0;
- }
-
- if (entry == test->entry3) {
- if (!(*update_3)) {
- uatomic_inc(&test->seen_entry3);
- *update_3 = true;
- if (update_2)
- uatomic_inc(&test->seen_both);
- }
- return 0;
- }
-
- return 1;
-}
-
-/*
- * rcu_val() - Read a given value in the tree test->count times using the
- * regular API
- *
- * @ptr: The pointer to the rcu_test_struct
- */
-static void *rcu_val(void *ptr)
-{
- struct rcu_test_struct *test = (struct rcu_test_struct *)ptr;
- unsigned long count = test->count;
- bool update_2 = false;
- bool update_3 = false;
- void *entry;
-
- rcu_register_thread();
- while (count--) {
- usleep(test->val_sleep);
- /*
- * No locking required, regular API locking is handled in the
- * maple tree code
- */
- entry = mtree_load(test->mt, test->index);
- MT_BUG_ON(test->mt, eval_rcu_entry(test, entry, &update_2,
- &update_3));
- }
- rcu_unregister_thread();
- return NULL;
-}
-
-/*
- * rcu_loop() - Loop over a section of the maple tree, checking for an expected
- * value using the advanced API
- *
- * @ptr - The pointer to the rcu_test_struct
- */
-static void *rcu_loop(void *ptr)
-{
- struct rcu_test_struct *test = (struct rcu_test_struct *)ptr;
- unsigned long count = test->count;
- void *entry, *expected;
- bool update_2 = false;
- bool update_3 = false;
- MA_STATE(mas, test->mt, test->range_start, test->range_start);
-
- rcu_register_thread();
-
- /*
- * Loop through the test->range_start - test->range_end test->count
- * times
- */
- while (count--) {
- usleep(test->loop_sleep);
- rcu_read_lock();
- mas_for_each(&mas, entry, test->range_end) {
- /* The expected value is based on the start range. */
- expected = xa_mk_value(mas.index ? mas.index / 10 : 0);
-
- /* Out of the interesting range */
- if (mas.index < test->index || mas.index > test->last) {
- if (entry != expected) {
- printk("%lx - %lx = %p not %p\n",
- mas.index, mas.last, entry, expected);
- }
- MT_BUG_ON(test->mt, entry != expected);
- continue;
- }
-
- if (entry == expected)
- continue; /* Not seen. */
-
- /* In the interesting range */
- MT_BUG_ON(test->mt, eval_rcu_entry(test, entry,
- &update_2,
- &update_3));
- }
- rcu_read_unlock();
- mas_set(&mas, test->range_start);
- }
-
- rcu_unregister_thread();
- return NULL;
-}
-
-static noinline
-void run_check_rcu(struct maple_tree *mt, struct rcu_test_struct *vals)
-{
-
- int i;
- void *(*function)(void *);
- pthread_t readers[20];
-
- mt_set_in_rcu(mt);
- MT_BUG_ON(mt, !mt_in_rcu(mt));
-
- for (i = 0; i < ARRAY_SIZE(readers); i++) {
- if (i % 2)
- function = rcu_loop;
- else
- function = rcu_val;
-
- if (pthread_create(&readers[i], NULL, *function, vals)) {
- perror("creating reader thread");
- exit(1);
- }
- }
-
- usleep(5); /* small yield to ensure all threads are at least started. */
- mtree_store_range(mt, vals->index, vals->last, vals->entry2,
- GFP_KERNEL);
- while (i--)
- pthread_join(readers[i], NULL);
-
- /* Make sure the test caught at least one update. */
- MT_BUG_ON(mt, !vals->seen_entry2);
-}
-
-static noinline
-void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals)
-{
-
- int i;
- void *(*function)(void *);
- pthread_t readers[20];
- unsigned int index = vals->index;
-
- mt_set_in_rcu(mt);
- MT_BUG_ON(mt, !mt_in_rcu(mt));
-
- for (i = 0; i < ARRAY_SIZE(readers); i++) {
- if (i % 2)
- function = rcu_loop;
- else
- function = rcu_val;
-
- if (pthread_create(&readers[i], NULL, *function, vals)) {
- perror("creating reader thread");
- exit(1);
- }
- }
-
- usleep(5); /* small yield to ensure all threads are at least started. */
-
- while (index <= vals->last) {
- mtree_store(mt, index,
- (index % 2 ? vals->entry2 : vals->entry3),
- GFP_KERNEL);
- index++;
- usleep(5);
- }
-
- while (i--)
- pthread_join(readers[i], NULL);
-
- /* Make sure the test caught at least one update. */
- MT_BUG_ON(mt, !vals->seen_entry2);
- MT_BUG_ON(mt, !vals->seen_entry3);
- MT_BUG_ON(mt, !vals->seen_both);
-}
-static noinline void check_rcu_simulated(struct maple_tree *mt)
-{
- unsigned long i, nr_entries = 1000;
- unsigned long target = 4320;
- unsigned long val = 0xDEAD;
-
- MA_STATE(mas_writer, mt, 0, 0);
- MA_STATE(mas_reader, mt, target, target);
-
- rcu_register_thread();
-
- mt_set_in_rcu(mt);
- mas_lock(&mas_writer);
- for (i = 0; i <= nr_entries; i++) {
- mas_writer.index = i * 10;
- mas_writer.last = i * 10 + 5;
- mas_store_gfp(&mas_writer, xa_mk_value(i), GFP_KERNEL);
- }
- mas_unlock(&mas_writer);
-
- /* Overwrite one entry with a new value. */
- mas_set_range(&mas_writer, target, target + 5);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
- rcu_read_unlock();
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
- mas_reset(&mas_reader);
-
-
- /* Overwrite 1/2 the entry */
- mas_set_range(&mas_writer, target, target + 2);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
- rcu_read_unlock();
-
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
- mas_reset(&mas_reader);
-
- /* Overwrite last 1/2 the entry */
- mas_set_range(&mas_writer, target + 2, target + 5);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- rcu_read_unlock();
-
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
- mas_reset(&mas_reader);
-
- /* Overwrite more than the entry */
- mas_set_range(&mas_writer, target - 5, target + 15);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
- rcu_read_unlock();
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
- mas_reset(&mas_reader);
-
- /* Overwrite more than the node. */
- mas_set_range(&mas_writer, target - 400, target + 400);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
- rcu_read_unlock();
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
- mas_reset(&mas_reader);
-
- /* Overwrite the tree */
- mas_set_range(&mas_writer, 0, ULONG_MAX);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
- rcu_read_unlock();
-
- /* Clear out tree & recreate it */
- mas_lock(&mas_writer);
- mas_set_range(&mas_writer, 0, ULONG_MAX);
- mas_store_gfp(&mas_writer, NULL, GFP_KERNEL);
- mas_set_range(&mas_writer, 0, 0);
- for (i = 0; i <= nr_entries; i++) {
- mas_writer.index = i * 10;
- mas_writer.last = i * 10 + 5;
- mas_store_gfp(&mas_writer, xa_mk_value(i), GFP_KERNEL);
- }
- mas_unlock(&mas_writer);
-
- /* next check */
- /* Overwrite one entry with a new value. */
- mas_reset(&mas_reader);
- mas_set_range(&mas_writer, target, target + 5);
- mas_set_range(&mas_reader, target, target);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_prev(&mas_reader, 0);
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_next(&mas_reader, ULONG_MAX) != xa_mk_value(val));
rcu_read_unlock();
-
- /* Restore value. */
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
- mas_unlock(&mas_writer);
-
- /* prev check */
- /* Overwrite one entry with a new value. */
- mas_reset(&mas_reader);
- mas_set_range(&mas_writer, target, target + 5);
- mas_set_range(&mas_reader, target, target);
- rcu_read_lock();
- MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
- mas_next(&mas_reader, ULONG_MAX);
- mas_lock(&mas_writer);
- mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
- mas_unlock(&mas_writer);
- MT_BUG_ON(mt, mas_prev(&mas_reader, 0) != xa_mk_value(val));
- rcu_read_unlock();
-
- rcu_unregister_thread();
}
-static noinline void check_rcu_threaded(struct maple_tree *mt)
-{
- unsigned long i, nr_entries = 1000;
- struct rcu_test_struct vals;
-
- vals.val_sleep = 200;
- vals.loop_sleep = 110;
-
- rcu_register_thread();
- for (i = 0; i <= nr_entries; i++)
- mtree_store_range(mt, i*10, i*10 + 5,
- xa_mk_value(i), GFP_KERNEL);
- /* Store across several slots. */
- vals.count = 1000;
- vals.mt = mt;
- vals.index = 8650;
- vals.last = 8666;
- vals.entry1 = xa_mk_value(865);
- vals.entry2 = xa_mk_value(8650);
- vals.entry3 = xa_mk_value(8650);
- vals.range_start = 0;
- vals.range_end = ULONG_MAX;
- vals.seen_entry2 = 0;
- vals.seen_entry3 = 0;
-
- run_check_rcu(mt, &vals);
- mtree_destroy(mt);
-
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= nr_entries; i++)
- mtree_store_range(mt, i*10, i*10 + 5,
- xa_mk_value(i), GFP_KERNEL);
-
- /* 4390-4395: value 439 (0x1b7) [0x36f] */
- /* Store across several slots. */
- /* Spanning store. */
- vals.count = 10000;
- vals.mt = mt;
- vals.index = 4390;
- vals.last = 4398;
- vals.entry1 = xa_mk_value(4390);
- vals.entry2 = xa_mk_value(439);
- vals.entry3 = xa_mk_value(439);
- vals.seen_entry2 = 0;
- vals.range_start = 4316;
- vals.range_end = 5035;
- run_check_rcu(mt, &vals);
- mtree_destroy(mt);
-
-
- /* Forward writer for rcu stress */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- rcu_stress(mt, true);
- mtree_destroy(mt);
-
- /* Reverse writer for rcu stress */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- rcu_stress(mt, false);
- mtree_destroy(mt);
- /* Slow reader test with spanning store. */
- mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
- for (i = 0; i <= nr_entries; i++)
- mtree_store_range(mt, i*10, i*10 + 5,
- xa_mk_value(i), GFP_KERNEL);
-
- /* 4390-4395: value 439 (0x1b7) [0x36f] */
- /* Store across several slots. */
- /* Spanning store. */
- vals.count = 15000;
- vals.mt = mt;
- vals.index = 4390;
- vals.last = 4398;
- vals.entry1 = xa_mk_value(4390);
- vals.entry2 = xa_mk_value(439);
- vals.entry3 = xa_mk_value(4391);
- vals.seen_toggle = 0;
- vals.seen_added = 0;
- vals.seen_removed = 0;
- vals.range_start = 4316;
- vals.range_end = 5035;
- vals.removed = 4360;
- vals.added = 4396;
- vals.toggle = 4347;
- vals.val_sleep = 400;
- vals.loop_sleep = 200;
- vals.seen_entry2 = 0;
- vals.seen_entry3 = 0;
- vals.seen_both = 0;
- vals.entry3 = xa_mk_value(438);
-
- run_check_rcu_slowread(mt, &vals);
- rcu_unregister_thread();
-}
-
-extern void test_kmem_cache_bulk(void);
/* Test spanning writes that require balancing right sibling or right cousin */
static noinline void check_spanning_relatives(struct maple_tree *mt)
@@ -37556,7 +2021,7 @@ static noinline void check_fuzzer(struct maple_tree *mt)
* Also discovered issue with metadata setting.
*/
mt_init_flags(mt, 0);
- mtree_test_store_range(mt, 0, 18446744073709551615UL, (void *)0x1);
+ mtree_test_store_range(mt, 0, ULONG_MAX, (void *)0x1);
mtree_test_store(mt, 4, (void *)0x9);
mtree_test_erase(mt, 5);
mtree_test_erase(mt, 0);
@@ -37612,9 +2077,9 @@ static noinline void check_fuzzer(struct maple_tree *mt)
mtree_test_insert(mt, 8, (void *)0x11);
mtree_test_insert(mt, 4, (void *)0x9);
mtree_test_insert(mt, 2480, (void *)0x1361);
- mtree_test_insert(mt, 18446744073709551615UL,
+ mtree_test_insert(mt, ULONG_MAX,
(void *)0xffffffffffffffff);
- mtree_test_erase(mt, 18446744073709551615UL);
+ mtree_test_erase(mt, ULONG_MAX);
mtree_destroy(mt);
/*
@@ -37883,8 +2348,8 @@ static noinline void check_fuzzer(struct maple_tree *mt)
mtree_test_insert(mt, 8, (void *)0x11);
mtree_test_insert(mt, 21, (void *)0x2b);
mtree_test_insert(mt, 2, (void *)0x5);
- mtree_test_insert(mt, 18446744073709551605UL, (void *)0xffffffffffffffeb);
- mtree_test_erase(mt, 18446744073709551605UL);
+ mtree_test_insert(mt, ULONG_MAX - 10, (void *)0xffffffffffffffeb);
+ mtree_test_erase(mt, ULONG_MAX - 10);
mtree_test_store_range(mt, 0, 281, (void *)0x1);
mtree_test_erase(mt, 2);
mtree_test_insert(mt, 1211, (void *)0x977);
@@ -37900,9 +2365,11 @@ static noinline void check_fuzzer(struct maple_tree *mt)
mtree_test_insert(mt, 8, (void *)0x11);
mtree_test_insert(mt, 21, (void *)0x2b);
mtree_test_insert(mt, 2, (void *)0x5);
- mtree_test_insert(mt, 18446744073709551605UL, (void *)0xffffffffffffffeb);
- mtree_test_erase(mt, 18446744073709551605UL);
+ mtree_test_insert(mt, ULONG_MAX - 10, (void *)0xffffffffffffffeb);
+ mtree_test_erase(mt, ULONG_MAX - 10);
}
+
+/* duplicate the tree with a specific gap */
static noinline void check_dup_gaps(struct maple_tree *mt,
unsigned long nr_entries, bool zero_start,
unsigned long gap)
@@ -37914,7 +2381,6 @@ static noinline void check_dup_gaps(struct maple_tree *mt,
MA_STATE(mas, mt, 0, 0);
MA_STATE(newmas, &newmt, 0, 0);
-
if (!zero_start)
i = 1;
@@ -37925,58 +2391,78 @@ static noinline void check_dup_gaps(struct maple_tree *mt,
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
mt_set_non_kernel(99999);
+ mas_lock(&newmas);
ret = mas_expected_entries(&newmas, nr_entries);
mt_set_non_kernel(0);
MT_BUG_ON(mt, ret != 0);
+ rcu_read_lock();
mas_for_each(&mas, tmp, ULONG_MAX) {
newmas.index = mas.index;
newmas.last = mas.last;
mas_store(&newmas, tmp);
}
-
- mas_destroy(&mas);
+ rcu_read_unlock();
mas_destroy(&newmas);
+ mas_unlock(&newmas);
+
mtree_destroy(&newmt);
}
+/* Duplicate many sizes of trees. Mainly to test expected entry values */
static noinline void check_dup(struct maple_tree *mt)
{
int i;
+ int big_start = 100010;
/* Check with a value at zero */
for (i = 10; i < 1000; i++) {
mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
check_dup_gaps(mt, i, true, 5);
mtree_destroy(mt);
+ rcu_barrier();
}
+ cond_resched();
+ mt_cache_shrink();
/* Check with a value at zero, no gap */
for (i = 1000; i < 2000; i++) {
mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
check_dup_gaps(mt, i, true, 0);
mtree_destroy(mt);
+ rcu_barrier();
}
+ cond_resched();
+ mt_cache_shrink();
/* Check with a value at zero and unreasonably large */
- for (i = 100010; i < 100020; i++) {
+ for (i = big_start; i < big_start + 10; i++) {
mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
check_dup_gaps(mt, i, true, 5);
mtree_destroy(mt);
+ rcu_barrier();
}
+ cond_resched();
+ mt_cache_shrink();
/* Small to medium size not starting at zero*/
for (i = 200; i < 1000; i++) {
mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
check_dup_gaps(mt, i, false, 5);
mtree_destroy(mt);
+ rcu_barrier();
}
+ cond_resched();
+ mt_cache_shrink();
/* Unreasonably large not starting at zero*/
- for (i = 100010; i < 100020; i++) {
+ for (i = big_start; i < big_start + 10; i++) {
mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
check_dup_gaps(mt, i, false, 5);
mtree_destroy(mt);
+ rcu_barrier();
+ cond_resched();
+ mt_cache_shrink();
}
/* Check non-allocation tree not starting at zero */
@@ -37984,22 +2470,32 @@ static noinline void check_dup(struct maple_tree *mt)
mt_init_flags(mt, 0);
check_dup_gaps(mt, i, false, 5);
mtree_destroy(mt);
+ rcu_barrier();
+ cond_resched();
+ if (i % 2 == 0)
+ mt_cache_shrink();
}
+ mt_cache_shrink();
/* Check non-allocation tree starting at zero */
for (i = 200; i < 1000; i++) {
mt_init_flags(mt, 0);
check_dup_gaps(mt, i, true, 5);
mtree_destroy(mt);
+ rcu_barrier();
+ cond_resched();
}
+ mt_cache_shrink();
/* Unreasonably large */
- for (i = 100015; i < 100020; i++) {
+ for (i = big_start + 5; i < big_start + 10; i++) {
mt_init_flags(mt, 0);
check_dup_gaps(mt, i, true, 5);
mtree_destroy(mt);
+ rcu_barrier();
+ mt_cache_shrink();
+ cond_resched();
}
-
}
static DEFINE_MTREE(tree);
@@ -38059,28 +2555,6 @@ static int maple_tree_seed(void)
goto skip;
#endif
- test_kmem_cache_bulk();
-
- mt_init_flags(&tree, 0);
- check_new_node(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
- check_prealloc(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
- check_spanning_write(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
- check_null_expand(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, 0);
- check_dfs_preorder(&tree);
- mtree_destroy(&tree);
-
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
check_forking(&tree);
mtree_destroy(&tree);
@@ -38094,6 +2568,8 @@ static int maple_tree_seed(void)
check_ranges(&tree);
mtree_destroy(&tree);
+#if defined(CONFIG_64BIT)
+ /* These tests have ranges outside of 4GB */
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
check_alloc_range(&tree);
mtree_destroy(&tree);
@@ -38101,6 +2577,7 @@ static int maple_tree_seed(void)
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
check_alloc_rev_range(&tree);
mtree_destroy(&tree);
+#endif
mt_init_flags(&tree, 0);
@@ -38160,10 +2637,6 @@ static int maple_tree_seed(void)
mtree_destroy(&tree);
mt_init_flags(&tree, 0);
- check_erase_testset(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, 0);
/*
* set[] = {5015, 5014, 5017, 25, 1000,
* 1001, 1002, 1003, 1005, 0,
@@ -38215,7 +2688,6 @@ static int maple_tree_seed(void)
check_load(&tree, set[9], &tree);
mtree_destroy(&tree);
- check_nomem(&tree);
mt_init_flags(&tree, 0);
check_seq(&tree, 16, false);
mtree_destroy(&tree);
@@ -38242,10 +2714,6 @@ static int maple_tree_seed(void)
check_prev_entry(&tree);
mtree_destroy(&tree);
- mt_init_flags(&tree, 0);
- check_erase2_sets(&tree);
- mtree_destroy(&tree);
-
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
check_gap_combining(&tree);
mtree_destroy(&tree);
@@ -38259,14 +2727,6 @@ static int maple_tree_seed(void)
mtree_destroy(&tree);
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
- check_rcu_simulated(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
- check_rcu_threaded(&tree);
- mtree_destroy(&tree);
-
- mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
check_spanning_relatives(&tree);
mtree_destroy(&tree);
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 4bd15a593fbd..d34dc636b81c 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -126,7 +126,7 @@ __test(const char *expect, int elen, const char *fmt, ...)
* be able to print it as expected.
*/
failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap);
- rand = 1 + prandom_u32_max(elen+1);
+ rand = get_random_u32_inclusive(1, elen + 1);
/* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */
failed_tests += do_test(rand, expect, elen, fmt, ap);
failed_tests += do_test(0, expect, elen, fmt, ap);
@@ -179,18 +179,6 @@ test_number(void)
* behaviour.
*/
test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0);
-#ifndef __CHAR_UNSIGNED__
- {
- /*
- * Passing a 'char' to a %02x specifier doesn't do
- * what was presumably the intention when char is
- * signed and the value is negative. One must either &
- * with 0xff or cast to u8.
- */
- char val = -16;
- test("0xfffffff0|0xf0|0xf0", "%#02x|%#02x|%#02x", val, val & 0xff, (u8)val);
- }
-#endif
}
static void __init
@@ -704,31 +692,29 @@ flags(void)
static void __init fwnode_pointer(void)
{
- const struct software_node softnodes[] = {
- { .name = "first", },
- { .name = "second", .parent = &softnodes[0], },
- { .name = "third", .parent = &softnodes[1], },
- { NULL /* Guardian */ }
- };
- const char * const full_name = "first/second/third";
+ const struct software_node first = { .name = "first" };
+ const struct software_node second = { .name = "second", .parent = &first };
+ const struct software_node third = { .name = "third", .parent = &second };
+ const struct software_node *group[] = { &first, &second, &third, NULL };
const char * const full_name_second = "first/second";
+ const char * const full_name_third = "first/second/third";
const char * const second_name = "second";
const char * const third_name = "third";
int rval;
- rval = software_node_register_nodes(softnodes);
+ rval = software_node_register_node_group(group);
if (rval) {
pr_warn("cannot register softnodes; rval %d\n", rval);
return;
}
- test(full_name_second, "%pfw", software_node_fwnode(&softnodes[1]));
- test(full_name, "%pfw", software_node_fwnode(&softnodes[2]));
- test(full_name, "%pfwf", software_node_fwnode(&softnodes[2]));
- test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
- test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
+ test(full_name_second, "%pfw", software_node_fwnode(&second));
+ test(full_name_third, "%pfw", software_node_fwnode(&third));
+ test(full_name_third, "%pfwf", software_node_fwnode(&third));
+ test(second_name, "%pfwP", software_node_fwnode(&second));
+ test(third_name, "%pfwP", software_node_fwnode(&third));
- software_node_unregister_nodes(softnodes);
+ software_node_unregister_node_group(group);
}
static void __init fourcc_pointer(void)
diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c
index f2ba5787055a..6a8e445c8b55 100644
--- a/lib/test_rhashtable.c
+++ b/lib/test_rhashtable.c
@@ -368,8 +368,8 @@ static int __init test_rhltable(unsigned int entries)
pr_info("test %d random rhlist add/delete operations\n", entries);
for (j = 0; j < entries; j++) {
- u32 i = prandom_u32_max(entries);
- u32 prand = prandom_u32_max(4);
+ u32 i = get_random_u32_below(entries);
+ u32 prand = get_random_u32_below(4);
cond_resched();
@@ -396,7 +396,7 @@ static int __init test_rhltable(unsigned int entries)
}
if (prand & 2) {
- i = prandom_u32_max(entries);
+ i = get_random_u32_below(entries);
if (test_bit(i, obj_in_table)) {
err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
WARN(err, "cannot remove element at slot %d", i);
diff --git a/lib/test_vmalloc.c b/lib/test_vmalloc.c
index cf7780572f5b..f90d2c27675b 100644
--- a/lib/test_vmalloc.c
+++ b/lib/test_vmalloc.c
@@ -151,7 +151,7 @@ static int random_size_alloc_test(void)
int i;
for (i = 0; i < test_loop_count; i++) {
- n = prandom_u32_max(100) + 1;
+ n = get_random_u32_inclusive(1, 100);
p = vmalloc(n * PAGE_SIZE);
if (!p)
@@ -291,12 +291,12 @@ pcpu_alloc_test(void)
return -1;
for (i = 0; i < 35000; i++) {
- size = prandom_u32_max(PAGE_SIZE / 4) + 1;
+ size = get_random_u32_inclusive(1, PAGE_SIZE / 4);
/*
* Maximum PAGE_SIZE
*/
- align = 1 << (prandom_u32_max(11) + 1);
+ align = 1 << get_random_u32_inclusive(1, 11);
pcpu[i] = __alloc_percpu(size, align);
if (!pcpu[i])
@@ -391,7 +391,7 @@ static void shuffle_array(int *arr, int n)
for (i = n - 1; i > 0; i--) {
/* Cut the range. */
- j = prandom_u32_max(i);
+ j = get_random_u32_below(i);
/* Swap indexes. */
swap(arr[i], arr[j]);
diff --git a/lib/vdso/Makefile b/lib/vdso/Makefile
index c415a685d61b..e814061d6aa0 100644
--- a/lib/vdso/Makefile
+++ b/lib/vdso/Makefile
@@ -17,6 +17,6 @@ $(error ARCH_REL_TYPE_ABS is not set)
endif
quiet_cmd_vdso_check = VDSOCHK $@
- cmd_vdso_check = if $(OBJDUMP) -R $@ | egrep -h "$(ARCH_REL_TYPE_ABS)"; \
+ cmd_vdso_check = if $(OBJDUMP) -R $@ | grep -E -h "$(ARCH_REL_TYPE_ABS)"; \
then (echo >&2 "$@: dynamic relocations are not supported"; \
rm -f $@; /bin/false); fi
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 24f37bab8bc1..be71a03c936a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -41,6 +41,7 @@
#include <linux/siphash.h>
#include <linux/compiler.h>
#include <linux/property.h>
+#include <linux/notifier.h>
#ifdef CONFIG_BLOCK
#include <linux/blkdev.h>
#endif
@@ -752,26 +753,21 @@ early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable);
static bool filled_random_ptr_key __read_mostly;
static siphash_key_t ptr_key __read_mostly;
-static void fill_ptr_key_workfn(struct work_struct *work);
-static DECLARE_DELAYED_WORK(fill_ptr_key_work, fill_ptr_key_workfn);
-static void fill_ptr_key_workfn(struct work_struct *work)
+static int fill_ptr_key(struct notifier_block *nb, unsigned long action, void *data)
{
- if (!rng_is_initialized()) {
- queue_delayed_work(system_unbound_wq, &fill_ptr_key_work, HZ * 2);
- return;
- }
-
get_random_bytes(&ptr_key, sizeof(ptr_key));
/* Pairs with smp_rmb() before reading ptr_key. */
smp_wmb();
WRITE_ONCE(filled_random_ptr_key, true);
+ return NOTIFY_DONE;
}
static int __init vsprintf_init_hashval(void)
{
- fill_ptr_key_workfn(NULL);
+ static struct notifier_block fill_ptr_key_nb = { .notifier_call = fill_ptr_key };
+ execute_with_initialized_rng(&fill_ptr_key_nb);
return 0;
}
subsys_initcall(vsprintf_init_hashval)
@@ -866,7 +862,7 @@ char *restricted_pointer(char *buf, char *end, const void *ptr,
* kptr_restrict==1 cannot be used in IRQ context
* because its test for CAP_SYSLOG would be meaningless.
*/
- if (in_irq() || in_serving_softirq() || in_nmi()) {
+ if (in_hardirq() || in_serving_softirq() || in_nmi()) {
if (spec.field_width == -1)
spec.field_width = 2 * sizeof(ptr);
return error_string(buf, end, "pK-error", spec);
diff --git a/mm/Kconfig b/mm/Kconfig
index 57e1d8c5b505..623d95659ff9 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -219,17 +219,43 @@ config SLUB
and has enhanced diagnostics. SLUB is the default choice for
a slab allocator.
-config SLOB
+config SLOB_DEPRECATED
depends on EXPERT
- bool "SLOB (Simple Allocator)"
+ bool "SLOB (Simple Allocator - DEPRECATED)"
depends on !PREEMPT_RT
help
+ Deprecated and scheduled for removal in a few cycles. SLUB
+ recommended as replacement. CONFIG_SLUB_TINY can be considered
+ on systems with 16MB or less RAM.
+
+ If you need SLOB to stay, please contact linux-mm@kvack.org and
+ people listed in the SLAB ALLOCATOR section of MAINTAINERS file,
+ with your use case.
+
SLOB replaces the stock allocator with a drastically simpler
allocator. SLOB is generally more space efficient but
does not perform as well on large systems.
endchoice
+config SLOB
+ bool
+ default y
+ depends on SLOB_DEPRECATED
+
+config SLUB_TINY
+ bool "Configure SLUB for minimal memory footprint"
+ depends on SLUB && EXPERT
+ select SLAB_MERGE_DEFAULT
+ help
+ Configures the SLUB allocator in a way to achieve minimal memory
+ footprint, sacrificing scalability, debugging and other features.
+ This is intended only for the smallest system that had used the
+ SLOB allocator and is not recommended for systems with more than
+ 16MB RAM.
+
+ If unsure, say N.
+
config SLAB_MERGE_DEFAULT
bool "Allow slab caches to be merged"
default y
@@ -247,7 +273,7 @@ config SLAB_MERGE_DEFAULT
config SLAB_FREELIST_RANDOM
bool "Randomize slab freelist"
- depends on SLAB || SLUB
+ depends on SLAB || (SLUB && !SLUB_TINY)
help
Randomizes the freelist order used on creating new pages. This
security feature reduces the predictability of the kernel slab
@@ -255,7 +281,7 @@ config SLAB_FREELIST_RANDOM
config SLAB_FREELIST_HARDENED
bool "Harden slab freelist metadata"
- depends on SLAB || SLUB
+ depends on SLAB || (SLUB && !SLUB_TINY)
help
Many kernel heap attacks try to target slab cache metadata and
other infrastructure. This options makes minor performance
@@ -267,7 +293,7 @@ config SLAB_FREELIST_HARDENED
config SLUB_STATS
default n
bool "Enable SLUB performance statistics"
- depends on SLUB && SYSFS
+ depends on SLUB && SYSFS && !SLUB_TINY
help
SLUB statistics are useful to debug SLUBs allocation behavior in
order find ways to optimize the allocator. This should never be
@@ -279,7 +305,7 @@ config SLUB_STATS
config SLUB_CPU_PARTIAL
default y
- depends on SLUB && SMP
+ depends on SLUB && SMP && !SLUB_TINY
bool "SLUB per cpu partial cache"
help
Per cpu partial caches accelerate objects allocation and freeing
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index ce8dded36de9..fca699ad1fb0 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -56,7 +56,7 @@ config DEBUG_SLAB
config SLUB_DEBUG
default y
bool "Enable SLUB debugging support" if EXPERT
- depends on SLUB && SYSFS
+ depends on SLUB && SYSFS && !SLUB_TINY
select STACKDEPOT if STACKTRACE_SUPPORT
help
SLUB has extensive debug support features. Disabling these can
diff --git a/mm/compaction.c b/mm/compaction.c
index c51f7f545afe..1f6da31dd9a5 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -985,28 +985,28 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
}
/*
+ * Be careful not to clear PageLRU until after we're
+ * sure the page is not being freed elsewhere -- the
+ * page release code relies on it.
+ */
+ if (unlikely(!get_page_unless_zero(page)))
+ goto isolate_fail;
+
+ /*
* Migration will fail if an anonymous page is pinned in memory,
* so avoid taking lru_lock and isolating it unnecessarily in an
* admittedly racy check.
*/
mapping = page_mapping(page);
- if (!mapping && page_count(page) > page_mapcount(page))
- goto isolate_fail;
+ if (!mapping && (page_count(page) - 1) > total_mapcount(page))
+ goto isolate_fail_put;
/*
* Only allow to migrate anonymous pages in GFP_NOFS context
* because those do not depend on fs locks.
*/
if (!(cc->gfp_mask & __GFP_FS) && mapping)
- goto isolate_fail;
-
- /*
- * Be careful not to clear PageLRU until after we're
- * sure the page is not being freed elsewhere -- the
- * page release code relies on it.
- */
- if (unlikely(!get_page_unless_zero(page)))
- goto isolate_fail;
+ goto isolate_fail_put;
/* Only take pages on LRU: a check now makes later tests safe */
if (!PageLRU(page))
diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c
index 6f0ae7d3ae39..b3f454a5c682 100644
--- a/mm/damon/dbgfs.c
+++ b/mm/damon/dbgfs.c
@@ -890,6 +890,7 @@ out:
static int dbgfs_rm_context(char *name)
{
struct dentry *root, *dir, **new_dirs;
+ struct inode *inode;
struct damon_ctx **new_ctxs;
int i, j;
int ret = 0;
@@ -905,6 +906,12 @@ static int dbgfs_rm_context(char *name)
if (!dir)
return -ENOENT;
+ inode = d_inode(dir);
+ if (!S_ISDIR(inode->i_mode)) {
+ ret = -EINVAL;
+ goto out_dput;
+ }
+
new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs),
GFP_KERNEL);
if (!new_dirs) {
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 9f1219a67e3f..07e5f1bdf025 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -2283,12 +2283,54 @@ static struct damos *damon_sysfs_mk_scheme(
&wmarks);
}
+static void damon_sysfs_update_scheme(struct damos *scheme,
+ struct damon_sysfs_scheme *sysfs_scheme)
+{
+ struct damon_sysfs_access_pattern *access_pattern =
+ sysfs_scheme->access_pattern;
+ struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
+ struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
+ struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
+
+ scheme->pattern.min_sz_region = access_pattern->sz->min;
+ scheme->pattern.max_sz_region = access_pattern->sz->max;
+ scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min;
+ scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max;
+ scheme->pattern.min_age_region = access_pattern->age->min;
+ scheme->pattern.max_age_region = access_pattern->age->max;
+
+ scheme->action = sysfs_scheme->action;
+
+ scheme->quota.ms = sysfs_quotas->ms;
+ scheme->quota.sz = sysfs_quotas->sz;
+ scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms;
+ scheme->quota.weight_sz = sysfs_weights->sz;
+ scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
+ scheme->quota.weight_age = sysfs_weights->age;
+
+ scheme->wmarks.metric = sysfs_wmarks->metric;
+ scheme->wmarks.interval = sysfs_wmarks->interval_us;
+ scheme->wmarks.high = sysfs_wmarks->high;
+ scheme->wmarks.mid = sysfs_wmarks->mid;
+ scheme->wmarks.low = sysfs_wmarks->low;
+}
+
static int damon_sysfs_set_schemes(struct damon_ctx *ctx,
struct damon_sysfs_schemes *sysfs_schemes)
{
- int i;
+ struct damos *scheme, *next;
+ int i = 0;
- for (i = 0; i < sysfs_schemes->nr; i++) {
+ damon_for_each_scheme_safe(scheme, next, ctx) {
+ if (i < sysfs_schemes->nr)
+ damon_sysfs_update_scheme(scheme,
+ sysfs_schemes->schemes_arr[i]);
+ else
+ damon_destroy_scheme(scheme);
+ i++;
+ }
+
+ for (; i < sysfs_schemes->nr; i++) {
struct damos *scheme, *next;
scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
@@ -2339,6 +2381,10 @@ static int damon_sysfs_upd_schemes_stats(struct damon_sysfs_kdamond *kdamond)
damon_for_each_scheme(scheme, ctx) {
struct damon_sysfs_stats *sysfs_stats;
+ /* user could have removed the scheme sysfs dir */
+ if (schemes_idx >= sysfs_schemes->nr)
+ break;
+
sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
sysfs_stats->nr_tried = scheme->stat.nr_tried;
sysfs_stats->sz_tried = scheme->stat.sz_tried;
diff --git a/mm/failslab.c b/mm/failslab.c
index 58df9789f1d2..ffc420c0e767 100644
--- a/mm/failslab.c
+++ b/mm/failslab.c
@@ -16,6 +16,8 @@ static struct {
bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
{
+ int flags = 0;
+
/* No fault-injection for bootstrap cache */
if (unlikely(s == kmem_cache))
return false;
@@ -30,10 +32,16 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
return false;
+ /*
+ * In some cases, it expects to specify __GFP_NOWARN
+ * to avoid printing any information(not just a warning),
+ * thus avoiding deadlocks. See commit 6b9dbedbe349 for
+ * details.
+ */
if (gfpflags & __GFP_NOWARN)
- failslab.attr.no_warn = true;
+ flags |= FAULT_NOWARN;
- return should_fail(&failslab.attr, s->object_size);
+ return should_fail_ex(&failslab.attr, s->object_size, flags);
}
static int __init setup_failslab(char *str)
diff --git a/mm/gup.c b/mm/gup.c
index fe195d47de74..98aac6201e1b 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -123,6 +123,9 @@ retry:
*/
struct folio *try_grab_folio(struct page *page, int refs, unsigned int flags)
{
+ if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)))
+ return NULL;
+
if (flags & FOLL_GET)
return try_get_folio(page, refs);
else if (flags & FOLL_PIN) {
@@ -202,17 +205,22 @@ static void gup_put_folio(struct folio *folio, int refs, unsigned int flags)
* time. Cases: please see the try_grab_folio() documentation, with
* "refs=1".
*
- * Return: true for success, or if no action was required (if neither FOLL_PIN
- * nor FOLL_GET was set, nothing is done). False for failure: FOLL_GET or
- * FOLL_PIN was set, but the page could not be grabbed.
+ * Return: 0 for success, or if no action was required (if neither FOLL_PIN
+ * nor FOLL_GET was set, nothing is done). A negative error code for failure:
+ *
+ * -ENOMEM FOLL_GET or FOLL_PIN was set, but the page could not
+ * be grabbed.
*/
-bool __must_check try_grab_page(struct page *page, unsigned int flags)
+int __must_check try_grab_page(struct page *page, unsigned int flags)
{
struct folio *folio = page_folio(page);
WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN));
if (WARN_ON_ONCE(folio_ref_count(folio) <= 0))
- return false;
+ return -ENOMEM;
+
+ if (unlikely(!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)))
+ return -EREMOTEIO;
if (flags & FOLL_GET)
folio_ref_inc(folio);
@@ -232,7 +240,7 @@ bool __must_check try_grab_page(struct page *page, unsigned int flags)
node_stat_mod_folio(folio, NR_FOLL_PIN_ACQUIRED, 1);
}
- return true;
+ return 0;
}
/**
@@ -624,10 +632,12 @@ retry:
!PageAnonExclusive(page), page);
/* try_grab_page() does nothing unless FOLL_GET or FOLL_PIN is set. */
- if (unlikely(!try_grab_page(page, flags))) {
- page = ERR_PTR(-ENOMEM);
+ ret = try_grab_page(page, flags);
+ if (unlikely(ret)) {
+ page = ERR_PTR(ret);
goto out;
}
+
/*
* We need to make the page accessible if and only if we are going
* to access its content (the FOLL_PIN case). Please see
@@ -960,10 +970,9 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address,
goto unmap;
*page = pte_page(*pte);
}
- if (unlikely(!try_grab_page(*page, gup_flags))) {
- ret = -ENOMEM;
+ ret = try_grab_page(*page, gup_flags);
+ if (unlikely(ret))
goto unmap;
- }
out:
ret = 0;
unmap:
@@ -1058,6 +1067,9 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
if ((gup_flags & FOLL_LONGTERM) && vma_is_fsdax(vma))
return -EOPNOTSUPP;
+ if ((gup_flags & FOLL_LONGTERM) && (gup_flags & FOLL_PCI_P2PDMA))
+ return -EOPNOTSUPP;
+
if (vma_is_secretmem(vma))
return -EFAULT;
@@ -2534,9 +2546,15 @@ static int __gup_device_huge(unsigned long pfn, unsigned long addr,
undo_dev_pagemap(nr, nr_start, flags, pages);
break;
}
+
+ if (!(flags & FOLL_PCI_P2PDMA) && is_pci_p2pdma_page(page)) {
+ undo_dev_pagemap(nr, nr_start, flags, pages);
+ break;
+ }
+
SetPageReferenced(page);
pages[*nr] = page;
- if (unlikely(!try_grab_page(page, flags))) {
+ if (unlikely(try_grab_page(page, flags))) {
undo_dev_pagemap(nr, nr_start, flags, pages);
break;
}
@@ -2852,7 +2870,7 @@ static int gup_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, unsigned lo
next = pud_addr_end(addr, end);
if (unlikely(!pud_present(pud)))
return 0;
- if (unlikely(pud_huge(pud))) {
+ if (unlikely(pud_huge(pud) || pud_devmap(pud))) {
if (!gup_huge_pud(pud, pudp, addr, next, flags,
pages, nr))
return 0;
@@ -3018,7 +3036,8 @@ static int internal_get_user_pages_fast(unsigned long start,
if (WARN_ON_ONCE(gup_flags & ~(FOLL_WRITE | FOLL_LONGTERM |
FOLL_FORCE | FOLL_PIN | FOLL_GET |
- FOLL_FAST_ONLY | FOLL_NOFAULT)))
+ FOLL_FAST_ONLY | FOLL_NOFAULT |
+ FOLL_PCI_P2PDMA)))
return -EINVAL;
if (gup_flags & FOLL_PIN)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 561a42567477..ffbea56a8711 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1035,6 +1035,7 @@ struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn = pmd_pfn(*pmd);
struct mm_struct *mm = vma->vm_mm;
struct page *page;
+ int ret;
assert_spin_locked(pmd_lockptr(mm, pmd));
@@ -1066,8 +1067,9 @@ struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
if (!*pgmap)
return ERR_PTR(-EFAULT);
page = pfn_to_page(pfn);
- if (!try_grab_page(page, flags))
- page = ERR_PTR(-ENOMEM);
+ ret = try_grab_page(page, flags);
+ if (ret)
+ page = ERR_PTR(ret);
return page;
}
@@ -1193,6 +1195,7 @@ struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn = pud_pfn(*pud);
struct mm_struct *mm = vma->vm_mm;
struct page *page;
+ int ret;
assert_spin_locked(pud_lockptr(mm, pud));
@@ -1226,8 +1229,10 @@ struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr,
if (!*pgmap)
return ERR_PTR(-EFAULT);
page = pfn_to_page(pfn);
- if (!try_grab_page(page, flags))
- page = ERR_PTR(-ENOMEM);
+
+ ret = try_grab_page(page, flags);
+ if (ret)
+ page = ERR_PTR(ret);
return page;
}
@@ -1435,6 +1440,7 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
{
struct mm_struct *mm = vma->vm_mm;
struct page *page;
+ int ret;
assert_spin_locked(pmd_lockptr(mm, pmd));
@@ -1459,8 +1465,9 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) &&
!PageAnonExclusive(page), page);
- if (!try_grab_page(page, flags))
- return ERR_PTR(-ENOMEM);
+ ret = try_grab_page(page, flags);
+ if (ret)
+ return ERR_PTR(ret);
if (flags & FOLL_TOUCH)
touch_pmd(vma, addr, pmd, flags & FOLL_WRITE);
@@ -2206,9 +2213,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
entry = pte_wrprotect(entry);
if (!young)
entry = pte_mkold(entry);
- /* NOTE: this may set soft-dirty too on some archs */
- if (dirty)
- entry = pte_mkdirty(entry);
+ /*
+ * NOTE: we don't do pte_mkdirty when dirty==true
+ * because it breaks sparc64 which can sigsegv
+ * random process. Need to revisit when we figure
+ * out what is special with sparc64.
+ */
if (soft_dirty)
entry = pte_mksoft_dirty(entry);
if (uffd_wp)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 546df97c31e4..3d9f4abec17c 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1800,6 +1800,7 @@ static bool __prep_compound_gigantic_page(struct page *page, unsigned int order,
/* we rely on prep_new_huge_page to set the destructor */
set_compound_order(page, order);
+ __ClearPageReserved(page);
__SetPageHead(page);
for (i = 0; i < nr_pages; i++) {
p = nth_page(page, i);
@@ -1816,7 +1817,8 @@ static bool __prep_compound_gigantic_page(struct page *page, unsigned int order,
* on the head page when they need know if put_page() is needed
* after get_user_pages().
*/
- __ClearPageReserved(p);
+ if (i != 0) /* head page cleared above */
+ __ClearPageReserved(p);
/*
* Subtle and very unlikely
*
@@ -5204,17 +5206,22 @@ void __unmap_hugepage_range_final(struct mmu_gather *tlb,
__unmap_hugepage_range(tlb, vma, start, end, ref_page, zap_flags);
- /*
- * Unlock and free the vma lock before releasing i_mmap_rwsem. When
- * the vma_lock is freed, this makes the vma ineligible for pmd
- * sharing. And, i_mmap_rwsem is required to set up pmd sharing.
- * This is important as page tables for this unmapped range will
- * be asynchrously deleted. If the page tables are shared, there
- * will be issues when accessed by someone else.
- */
- __hugetlb_vma_unlock_write_free(vma);
-
- i_mmap_unlock_write(vma->vm_file->f_mapping);
+ if (zap_flags & ZAP_FLAG_UNMAP) { /* final unmap */
+ /*
+ * Unlock and free the vma lock before releasing i_mmap_rwsem.
+ * When the vma_lock is freed, this makes the vma ineligible
+ * for pmd sharing. And, i_mmap_rwsem is required to set up
+ * pmd sharing. This is important as page tables for this
+ * unmapped range will be asynchrously deleted. If the page
+ * tables are shared, there will be issues when accessed by
+ * someone else.
+ */
+ __hugetlb_vma_unlock_write_free(vma);
+ i_mmap_unlock_write(vma->vm_file->f_mapping);
+ } else {
+ i_mmap_unlock_write(vma->vm_file->f_mapping);
+ hugetlb_vma_unlock_write(vma);
+ }
}
void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
@@ -6111,6 +6118,10 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
ptl = huge_pte_lock(h, dst_mm, dst_pte);
+ ret = -EIO;
+ if (PageHWPoison(page))
+ goto out_release_unlock;
+
/*
* We allow to overwrite a pte marker: consider when both MISSING|WP
* registered, we firstly wr-protect a none pte which has no page cache
@@ -6361,8 +6372,10 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
* tables. If the huge page is present, then the tail
* pages must also be present. The ptl prevents the
* head page and tail pages from being rearranged in
- * any way. So this page must be available at this
- * point, unless the page refcount overflowed:
+ * any way. As this is hugetlb, the pages will never
+ * be p2pdma or not longterm pinable. So this page
+ * must be available at this point, unless the page
+ * refcount overflowed:
*/
if (WARN_ON_ONCE(!try_grab_folio(pages[i], refs,
flags))) {
@@ -7243,14 +7256,15 @@ retry:
page = pte_page(pte) +
((address & ~huge_page_mask(h)) >> PAGE_SHIFT);
/*
- * try_grab_page() should always succeed here, because: a) we
- * hold the pmd (ptl) lock, and b) we've just checked that the
- * huge pmd (head) page is present in the page tables. The ptl
- * prevents the head page and tail pages from being rearranged
- * in any way. So this page must be available at this point,
- * unless the page refcount overflowed:
+ * try_grab_page() should always be able to get the page here,
+ * because: a) we hold the pmd (ptl) lock, and b) we've just
+ * checked that the huge pmd (head) page is present in the
+ * page tables. The ptl prevents the head page and tail pages
+ * from being rearranged in any way. So this page must be
+ * available at this point, unless the page refcount
+ * overflowed:
*/
- if (WARN_ON_ONCE(!try_grab_page(page, flags))) {
+ if (try_grab_page(page, flags)) {
page = NULL;
goto out;
}
@@ -7288,7 +7302,7 @@ retry:
pte = huge_ptep_get((pte_t *)pud);
if (pte_present(pte)) {
page = pud_page(*pud) + ((address & ~PUD_MASK) >> PAGE_SHIFT);
- if (WARN_ON_ONCE(!try_grab_page(page, flags))) {
+ if (try_grab_page(page, flags)) {
page = NULL;
goto out;
}
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index ba2a2596fb4e..4962dd1ba4a6 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) "HugeTLB: " fmt
#include <linux/pgtable.h>
+#include <linux/moduleparam.h>
#include <linux/bootmem_info.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index d8b5590f9484..b076f597a378 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -450,15 +450,22 @@ void kasan_init_object_meta(struct kmem_cache *cache, const void *object)
__memset(alloc_meta, 0, sizeof(*alloc_meta));
}
-size_t kasan_metadata_size(struct kmem_cache *cache)
+size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
{
+ struct kasan_cache *info = &cache->kasan_info;
+
if (!kasan_requires_meta())
return 0;
- return (cache->kasan_info.alloc_meta_offset ?
- sizeof(struct kasan_alloc_meta) : 0) +
- ((cache->kasan_info.free_meta_offset &&
- cache->kasan_info.free_meta_offset != KASAN_NO_FREE_META) ?
- sizeof(struct kasan_free_meta) : 0);
+
+ if (in_object)
+ return (info->free_meta_offset ?
+ 0 : sizeof(struct kasan_free_meta));
+ else
+ return (info->alloc_meta_offset ?
+ sizeof(struct kasan_alloc_meta) : 0) +
+ ((info->free_meta_offset &&
+ info->free_meta_offset != KASAN_NO_FREE_META) ?
+ sizeof(struct kasan_free_meta) : 0);
}
static void __kasan_record_aux_stack(void *addr, bool can_alloc)
diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
index 0d59098f0876..54181eba3e24 100644
--- a/mm/kasan/kasan_test.c
+++ b/mm/kasan/kasan_test.c
@@ -1299,7 +1299,7 @@ static void match_all_not_assigned(struct kunit *test)
KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
for (i = 0; i < 256; i++) {
- size = prandom_u32_max(1024) + 1;
+ size = get_random_u32_inclusive(1, 1024);
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
@@ -1308,7 +1308,7 @@ static void match_all_not_assigned(struct kunit *test)
}
for (i = 0; i < 256; i++) {
- order = prandom_u32_max(4) + 1;
+ order = get_random_u32_inclusive(1, 4);
pages = alloc_pages(GFP_KERNEL, order);
ptr = page_address(pages);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -1321,7 +1321,7 @@ static void match_all_not_assigned(struct kunit *test)
return;
for (i = 0; i < 256; i++) {
- size = prandom_u32_max(1024) + 1;
+ size = get_random_u32_inclusive(1, 1024);
ptr = vmalloc(size);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
diff --git a/mm/kfence/core.c b/mm/kfence/core.c
index 141788858b70..6cbd93f2007b 100644
--- a/mm/kfence/core.c
+++ b/mm/kfence/core.c
@@ -360,9 +360,9 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
unsigned long flags;
struct slab *slab;
void *addr;
- const bool random_right_allocate = prandom_u32_max(2);
+ const bool random_right_allocate = get_random_u32_below(2);
const bool random_fault = CONFIG_KFENCE_STRESS_TEST_FAULTS &&
- !prandom_u32_max(CONFIG_KFENCE_STRESS_TEST_FAULTS);
+ !get_random_u32_below(CONFIG_KFENCE_STRESS_TEST_FAULTS);
/* Try to obtain a free object. */
raw_spin_lock_irqsave(&kfence_freelist_lock, flags);
diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c
index a97bffe0cc3e..b5d66a69200d 100644
--- a/mm/kfence/kfence_test.c
+++ b/mm/kfence/kfence_test.c
@@ -532,8 +532,8 @@ static void test_free_bulk(struct kunit *test)
int iter;
for (iter = 0; iter < 5; iter++) {
- const size_t size = setup_test_cache(test, 8 + prandom_u32_max(300), 0,
- (iter & 1) ? ctor_set_x : NULL);
+ const size_t size = setup_test_cache(test, get_random_u32_inclusive(8, 307),
+ 0, (iter & 1) ? ctor_set_x : NULL);
void *objects[] = {
test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT),
test_alloc(test, size, GFP_KERNEL, ALLOCATE_NONE),
diff --git a/mm/kfence/report.c b/mm/kfence/report.c
index 7e496856c2eb..46ecea18c4ca 100644
--- a/mm/kfence/report.c
+++ b/mm/kfence/report.c
@@ -75,18 +75,23 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") ||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") ||
+ str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
!strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) {
/*
- * In case of tail calls from any of the below
- * to any of the above.
+ * In case of tail calls from any of the below to any of
+ * the above, optimized by the compiler such that the
+ * stack trace would omit the initial entry point below.
*/
fallback = skipnr + 1;
}
- /* Also the *_bulk() variants by only checking prefixes. */
+ /*
+ * The below list should only include the initial entry points
+ * into the slab allocators. Includes the *_bulk() variants by
+ * checking prefixes.
+ */
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") ||
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") ||
- str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") ||
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc"))
goto found;
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 4734315f7940..3703a56571c1 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -97,8 +97,8 @@ struct collapse_control {
/* Num pages scanned per node */
u32 node_load[MAX_NUMNODES];
- /* Last target selected in hpage_collapse_find_target_node() */
- int last_target_node;
+ /* nodemask for allocation fallback */
+ nodemask_t alloc_nmask;
};
/**
@@ -734,7 +734,6 @@ static void khugepaged_alloc_sleep(void)
struct collapse_control khugepaged_collapse_control = {
.is_khugepaged = true,
- .last_target_node = NUMA_NO_NODE,
};
static bool hpage_collapse_scan_abort(int nid, struct collapse_control *cc)
@@ -783,16 +782,11 @@ static int hpage_collapse_find_target_node(struct collapse_control *cc)
target_node = nid;
}
- /* do some balance if several nodes have the same hit record */
- if (target_node <= cc->last_target_node)
- for (nid = cc->last_target_node + 1; nid < MAX_NUMNODES;
- nid++)
- if (max_value == cc->node_load[nid]) {
- target_node = nid;
- break;
- }
+ for_each_online_node(nid) {
+ if (max_value == cc->node_load[nid])
+ node_set(nid, cc->alloc_nmask);
+ }
- cc->last_target_node = target_node;
return target_node;
}
#else
@@ -802,9 +796,10 @@ static int hpage_collapse_find_target_node(struct collapse_control *cc)
}
#endif
-static bool hpage_collapse_alloc_page(struct page **hpage, gfp_t gfp, int node)
+static bool hpage_collapse_alloc_page(struct page **hpage, gfp_t gfp, int node,
+ nodemask_t *nmask)
{
- *hpage = __alloc_pages_node(node, gfp, HPAGE_PMD_ORDER);
+ *hpage = __alloc_pages(gfp, HPAGE_PMD_ORDER, node, nmask);
if (unlikely(!*hpage)) {
count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
return false;
@@ -955,12 +950,11 @@ static int __collapse_huge_page_swapin(struct mm_struct *mm,
static int alloc_charge_hpage(struct page **hpage, struct mm_struct *mm,
struct collapse_control *cc)
{
- /* Only allocate from the target node */
gfp_t gfp = (cc->is_khugepaged ? alloc_hugepage_khugepaged_gfpmask() :
- GFP_TRANSHUGE) | __GFP_THISNODE;
+ GFP_TRANSHUGE);
int node = hpage_collapse_find_target_node(cc);
- if (!hpage_collapse_alloc_page(hpage, gfp, node))
+ if (!hpage_collapse_alloc_page(hpage, gfp, node, &cc->alloc_nmask))
return SCAN_ALLOC_HUGE_PAGE_FAIL;
if (unlikely(mem_cgroup_charge(page_folio(*hpage), mm, gfp)))
return SCAN_CGROUP_CHARGE_FAIL;
@@ -1057,6 +1051,7 @@ static int collapse_huge_page(struct mm_struct *mm, unsigned long address,
_pmd = pmdp_collapse_flush(vma, address, pmd);
spin_unlock(pmd_ptl);
mmu_notifier_invalidate_range_end(&range);
+ tlb_remove_table_sync_one();
spin_lock(pte_ptl);
result = __collapse_huge_page_isolate(vma, address, pte, cc,
@@ -1144,6 +1139,7 @@ static int hpage_collapse_scan_pmd(struct mm_struct *mm,
goto out;
memset(cc->node_load, 0, sizeof(cc->node_load));
+ nodes_clear(cc->alloc_nmask);
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
for (_address = address, _pte = pte; _pte < pte + HPAGE_PMD_NR;
_pte++, _address += PAGE_SIZE) {
@@ -1384,16 +1380,43 @@ static int set_huge_pmd(struct vm_area_struct *vma, unsigned long addr,
return SCAN_SUCCEED;
}
+/*
+ * A note about locking:
+ * Trying to take the page table spinlocks would be useless here because those
+ * are only used to synchronize:
+ *
+ * - modifying terminal entries (ones that point to a data page, not to another
+ * page table)
+ * - installing *new* non-terminal entries
+ *
+ * Instead, we need roughly the same kind of protection as free_pgtables() or
+ * mm_take_all_locks() (but only for a single VMA):
+ * The mmap lock together with this VMA's rmap locks covers all paths towards
+ * the page table entries we're messing with here, except for hardware page
+ * table walks and lockless_pages_from_mm().
+ */
static void collapse_and_free_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, pmd_t *pmdp)
{
- spinlock_t *ptl;
pmd_t pmd;
+ struct mmu_notifier_range range;
mmap_assert_write_locked(mm);
- ptl = pmd_lock(vma->vm_mm, pmdp);
+ if (vma->vm_file)
+ lockdep_assert_held_write(&vma->vm_file->f_mapping->i_mmap_rwsem);
+ /*
+ * All anon_vmas attached to the VMA have the same root and are
+ * therefore locked by the same lock.
+ */
+ if (vma->anon_vma)
+ lockdep_assert_held_write(&vma->anon_vma->root->rwsem);
+
+ mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, NULL, mm, addr,
+ addr + HPAGE_PMD_SIZE);
+ mmu_notifier_invalidate_range_start(&range);
pmd = pmdp_collapse_flush(vma, addr, pmdp);
- spin_unlock(ptl);
+ tlb_remove_table_sync_one();
+ mmu_notifier_invalidate_range_end(&range);
mm_dec_nr_ptes(mm);
page_table_check_pte_clear_range(mm, addr, pmd);
pte_free(mm, pmd_pgtable(pmd));
@@ -1444,6 +1467,14 @@ int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
if (!hugepage_vma_check(vma, vma->vm_flags, false, false, false))
return SCAN_VMA_CHECK;
+ /*
+ * Symmetry with retract_page_tables(): Exclude MAP_PRIVATE mappings
+ * that got written to. Without this, we'd have to also lock the
+ * anon_vma if one exists.
+ */
+ if (vma->anon_vma)
+ return SCAN_VMA_CHECK;
+
/* Keep pmd pgtable for uffd-wp; see comment in retract_page_tables() */
if (userfaultfd_wp(vma))
return SCAN_PTE_UFFD_WP;
@@ -1477,6 +1508,20 @@ int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
goto drop_hpage;
}
+ /*
+ * We need to lock the mapping so that from here on, only GUP-fast and
+ * hardware page walks can access the parts of the page tables that
+ * we're operating on.
+ * See collapse_and_free_pmd().
+ */
+ i_mmap_lock_write(vma->vm_file->f_mapping);
+
+ /*
+ * This spinlock should be unnecessary: Nobody else should be accessing
+ * the page tables under spinlock protection here, only
+ * lockless_pages_from_mm() and the hardware page walker can access page
+ * tables while all the high-level locks are held in write mode.
+ */
start_pte = pte_offset_map_lock(mm, pmd, haddr, &ptl);
result = SCAN_FAIL;
@@ -1531,6 +1576,8 @@ int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
/* step 4: remove pte entries */
collapse_and_free_pmd(mm, vma, haddr, pmd);
+ i_mmap_unlock_write(vma->vm_file->f_mapping);
+
maybe_install_pmd:
/* step 5: install pmd entry */
result = install_pmd
@@ -1544,6 +1591,7 @@ drop_hpage:
abort:
pte_unmap_unlock(start_pte, ptl);
+ i_mmap_unlock_write(vma->vm_file->f_mapping);
goto drop_hpage;
}
@@ -1600,7 +1648,8 @@ static int retract_page_tables(struct address_space *mapping, pgoff_t pgoff,
* An alternative would be drop the check, but check that page
* table is clear before calling pmdp_collapse_flush() under
* ptl. It has higher chance to recover THP for the VMA, but
- * has higher cost too.
+ * has higher cost too. It would also probably require locking
+ * the anon_vma.
*/
if (vma->anon_vma) {
result = SCAN_PAGE_ANON;
@@ -2077,6 +2126,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr,
present = 0;
swap = 0;
memset(cc->node_load, 0, sizeof(cc->node_load));
+ nodes_clear(cc->alloc_nmask);
rcu_read_lock();
xas_for_each(&xas, page, start + HPAGE_PMD_NR - 1) {
if (xas_retry(&xas, page))
@@ -2157,8 +2207,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr,
}
}
- trace_mm_khugepaged_scan_file(mm, page, file->f_path.dentry->d_iname,
- present, swap, result);
+ trace_mm_khugepaged_scan_file(mm, page, file, present, swap, result);
return result;
}
#else
@@ -2576,7 +2625,6 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev,
if (!cc)
return -ENOMEM;
cc->is_khugepaged = false;
- cc->last_target_node = NUMA_NO_NODE;
mmgrab(mm);
lru_add_drain_all();
@@ -2602,6 +2650,7 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev,
}
mmap_assert_locked(mm);
memset(cc->node_load, 0, sizeof(cc->node_load));
+ nodes_clear(cc->alloc_nmask);
if (IS_ENABLED(CONFIG_SHMEM) && vma->vm_file) {
struct file *file = get_file(vma->vm_file);
pgoff_t pgoff = linear_page_index(vma, addr);
diff --git a/mm/kmsan/kmsan.h b/mm/kmsan/kmsan.h
index 7019c46d33a7..a14744205435 100644
--- a/mm/kmsan/kmsan.h
+++ b/mm/kmsan/kmsan.h
@@ -124,6 +124,8 @@ static __always_inline bool kmsan_in_runtime(void)
{
if ((hardirq_count() >> HARDIRQ_SHIFT) > 1)
return true;
+ if (in_nmi())
+ return true;
return kmsan_get_context()->kmsan_in_runtime;
}
diff --git a/mm/maccess.c b/mm/maccess.c
index 5f4d240f67ec..074f6b086671 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -97,7 +97,7 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
return src - unsafe_addr;
Efault:
pagefault_enable();
- dst[-1] = '\0';
+ dst[0] = '\0';
return -EFAULT;
}
diff --git a/mm/madvise.c b/mm/madvise.c
index c7105ec6d08c..d03e149ffe6e 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -772,8 +772,8 @@ static int madvise_free_single_vma(struct vm_area_struct *vma,
* Application no longer needs these pages. If the pages are dirty,
* it's OK to just throw them away. The app will be more careful about
* data it wants to keep. Be sure to free swap resources too. The
- * zap_page_range call sets things up for shrink_active_list to actually free
- * these pages later if no one else has touched them in the meantime,
+ * zap_page_range_single call sets things up for shrink_active_list to actually
+ * free these pages later if no one else has touched them in the meantime,
* although we could add these pages to a global reuse list for
* shrink_active_list to pick up before reclaiming other pages.
*
@@ -790,7 +790,7 @@ static int madvise_free_single_vma(struct vm_area_struct *vma,
static long madvise_dontneed_single_vma(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- zap_page_range(vma, start, end - start);
+ zap_page_range_single(vma, start, end - start, NULL);
return 0;
}
@@ -1459,7 +1459,7 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
goto out;
}
- ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+ ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
if (ret < 0)
goto out;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2d8549ae1b30..266a1ab05434 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3026,7 +3026,7 @@ struct obj_cgroup *get_obj_cgroup_from_page(struct page *page)
{
struct obj_cgroup *objcg;
- if (!memcg_kmem_enabled() || memcg_kmem_bypass())
+ if (!memcg_kmem_enabled())
return NULL;
if (PageMemcgKmem(page)) {
@@ -4832,6 +4832,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
unsigned int efd, cfd;
struct fd efile;
struct fd cfile;
+ struct dentry *cdentry;
const char *name;
char *endp;
int ret;
@@ -4886,6 +4887,16 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
goto out_put_cfile;
/*
+ * The control file must be a regular cgroup1 file. As a regular cgroup
+ * file can't be renamed, it's safe to access its name afterwards.
+ */
+ cdentry = cfile.file->f_path.dentry;
+ if (cdentry->d_sb->s_type != &cgroup_fs_type || !d_is_reg(cdentry)) {
+ ret = -EINVAL;
+ goto out_put_cfile;
+ }
+
+ /*
* Determine the event callbacks and set them in @event. This used
* to be done via struct cftype but cgroup core no longer knows
* about these events. The following is crude but the whole thing
@@ -4893,7 +4904,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
*
* DO NOT ADD NEW FILES.
*/
- name = cfile.file->f_path.dentry->d_name.name;
+ name = cdentry->d_name.name;
if (!strcmp(name, "memory.usage_in_bytes")) {
event->register_event = mem_cgroup_usage_register_event;
@@ -4917,7 +4928,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
* automatically removed on cgroup destruction but the removal is
* asynchronous, so take an extra ref on @css.
*/
- cfile_css = css_tryget_online_from_dir(cfile.file->f_path.dentry->d_parent,
+ cfile_css = css_tryget_online_from_dir(cdentry->d_parent,
&memory_cgrp_subsys);
ret = -EINVAL;
if (IS_ERR(cfile_css))
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 145bb561ddb3..bead6bccc7f2 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1080,6 +1080,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
int res;
struct page *hpage = compound_head(p);
struct address_space *mapping;
+ bool extra_pins = false;
if (!PageHuge(hpage))
return MF_DELAYED;
@@ -1087,6 +1088,8 @@ static int me_huge_page(struct page_state *ps, struct page *p)
mapping = page_mapping(hpage);
if (mapping) {
res = truncate_error_page(hpage, page_to_pfn(p), mapping);
+ /* The page is kept in page cache. */
+ extra_pins = true;
unlock_page(hpage);
} else {
unlock_page(hpage);
@@ -1104,7 +1107,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
}
}
- if (has_extra_refcount(ps, p, false))
+ if (has_extra_refcount(ps, p, extra_pins))
res = MF_FAILED;
return res;
diff --git a/mm/memory.c b/mm/memory.c
index f88c351aecd4..8c8420934d60 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1341,15 +1341,6 @@ copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
return ret;
}
-/*
- * Parameter block passed down to zap_pte_range in exceptional cases.
- */
-struct zap_details {
- struct folio *single_folio; /* Locked folio to be unmapped */
- bool even_cows; /* Zap COWed private pages too? */
- zap_flags_t zap_flags; /* Extra flags for zapping */
-};
-
/* Whether we should zap all COWed (private) pages too */
static inline bool should_zap_cows(struct zap_details *details)
{
@@ -1720,7 +1711,7 @@ void unmap_vmas(struct mmu_gather *tlb, struct maple_tree *mt,
{
struct mmu_notifier_range range;
struct zap_details details = {
- .zap_flags = ZAP_FLAG_DROP_MARKER,
+ .zap_flags = ZAP_FLAG_DROP_MARKER | ZAP_FLAG_UNMAP,
/* Careful - we need to zap private pages too! */
.even_cows = true,
};
@@ -1774,19 +1765,27 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long start,
*
* The range must fit into one VMA.
*/
-static void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
+void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
unsigned long size, struct zap_details *details)
{
+ const unsigned long end = address + size;
struct mmu_notifier_range range;
struct mmu_gather tlb;
lru_add_drain();
mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
- address, address + size);
+ address, end);
+ if (is_vm_hugetlb_page(vma))
+ adjust_range_if_pmd_sharing_possible(vma, &range.start,
+ &range.end);
tlb_gather_mmu(&tlb, vma->vm_mm);
update_hiwater_rss(vma->vm_mm);
mmu_notifier_invalidate_range_start(&range);
- unmap_single_vma(&tlb, vma, address, range.end, details);
+ /*
+ * unmap 'address-end' not 'range.start-range.end' as range
+ * could have been expanded for hugetlb pmd sharing.
+ */
+ unmap_single_vma(&tlb, vma, address, end, details);
mmu_notifier_invalidate_range_end(&range);
tlb_finish_mmu(&tlb);
}
@@ -3763,7 +3762,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
*/
get_page(vmf->page);
pte_unmap_unlock(vmf->pte, vmf->ptl);
- vmf->page->pgmap->ops->migrate_to_ram(vmf);
+ ret = vmf->page->pgmap->ops->migrate_to_ram(vmf);
put_page(vmf->page);
} else if (is_hwpoison_entry(entry)) {
ret = VM_FAULT_HWPOISON;
diff --git a/mm/memremap.c b/mm/memremap.c
index 421bec3a29ee..08cbf54fe037 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -335,6 +335,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
WARN(1, "File system DAX not supported\n");
return ERR_PTR(-EINVAL);
}
+ params.pgprot = pgprot_decrypted(params.pgprot);
break;
case MEMORY_DEVICE_GENERIC:
break;
diff --git a/mm/migrate.c b/mm/migrate.c
index dff333593a8a..19ba91ba3d05 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -74,13 +74,22 @@ int isolate_movable_page(struct page *page, isolate_mode_t mode)
if (unlikely(!get_page_unless_zero(page)))
goto out;
+ if (unlikely(PageSlab(page)))
+ goto out_putpage;
+ /* Pairs with smp_wmb() in slab freeing, e.g. SLUB's __free_slab() */
+ smp_rmb();
/*
- * Check PageMovable before holding a PG_lock because page's owner
- * assumes anybody doesn't touch PG_lock of newly allocated page
- * so unconditionally grabbing the lock ruins page's owner side.
+ * Check movable flag before taking the page lock because
+ * we use non-atomic bitops on newly allocated page flags so
+ * unconditionally grabbing the lock ruins page's owner side.
*/
if (unlikely(!__PageMovable(page)))
goto out_putpage;
+ /* Pairs with smp_wmb() in slab allocation, e.g. SLUB's alloc_slab_page() */
+ smp_rmb();
+ if (unlikely(PageSlab(page)))
+ goto out_putpage;
+
/*
* As movable pages are not isolated from LRU lists, concurrent
* compaction threads can race against page migration functions
@@ -820,6 +829,7 @@ int buffer_migrate_folio_norefs(struct address_space *mapping,
{
return __buffer_migrate_folio(mapping, dst, src, mode, true);
}
+EXPORT_SYMBOL_GPL(buffer_migrate_folio_norefs);
#endif
int filemap_migrate_folio(struct address_space *mapping,
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 6fa682eef7a0..721b2365dbca 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -357,7 +357,8 @@ static bool migrate_vma_check_page(struct page *page, struct page *fault_page)
}
/*
- * Unmaps pages for migration. Returns number of unmapped pages.
+ * Unmaps pages for migration. Returns number of source pfns marked as
+ * migrating.
*/
static unsigned long migrate_device_unmap(unsigned long *src_pfns,
unsigned long npages,
@@ -373,8 +374,11 @@ static unsigned long migrate_device_unmap(unsigned long *src_pfns,
struct page *page = migrate_pfn_to_page(src_pfns[i]);
struct folio *folio;
- if (!page)
+ if (!page) {
+ if (src_pfns[i] & MIGRATE_PFN_MIGRATE)
+ unmapped++;
continue;
+ }
/* ZONE_DEVICE pages are not on LRU */
if (!is_zone_device_page(page)) {
diff --git a/mm/mmap.c b/mm/mmap.c
index 2def55555e05..54abd46e6007 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -226,8 +226,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
/* Search one past newbrk */
mas_set(&mas, newbrk);
brkvma = mas_find(&mas, oldbrk);
- BUG_ON(brkvma == NULL);
- if (brkvma->vm_start >= oldbrk)
+ if (!brkvma || brkvma->vm_start >= oldbrk)
goto out; /* mapping intersects with an existing non-brk vma. */
/*
* mm->brk must be protected by write mmap_lock.
@@ -456,7 +455,7 @@ void vma_mas_remove(struct vm_area_struct *vma, struct ma_state *mas)
* vma_mas_szero() - Set a given range to zero. Used when modifying a
* vm_area_struct start or end.
*
- * @mm: The struct_mm
+ * @mas: The maple tree ma_state
* @start: The start address to zero
* @end: The end address to zero.
*/
@@ -1779,9 +1778,6 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
*/
pgoff = 0;
get_area = shmem_get_unmapped_area;
- } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
- /* Ensures that larger anonymous mappings are THP aligned. */
- get_area = thp_get_unmapped_area;
}
addr = get_area(file, addr, len, pgoff, flags);
@@ -2674,6 +2670,8 @@ cannot_expand:
error = -EINVAL;
if (file)
goto close_and_free_vma;
+ else if (vma->vm_file)
+ goto unmap_and_free_vma;
else
goto free_vma;
}
@@ -2682,6 +2680,8 @@ cannot_expand:
error = -ENOMEM;
if (file)
goto close_and_free_vma;
+ else if (vma->vm_file)
+ goto unmap_and_free_vma;
else
goto free_vma;
}
@@ -2751,7 +2751,7 @@ unmap_and_free_vma:
/* Undo any partial mapping done by a device driver. */
unmap_region(mm, mas.tree, vma, prev, next, vma->vm_start, vma->vm_end);
- if (vm_flags & VM_SHARED)
+ if (file && (vm_flags & VM_SHARED))
mapping_unmap_writable(file->f_mapping);
free_vma:
vm_area_free(vma);
@@ -2945,9 +2945,9 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct *vma,
* Expand the existing vma if possible; Note that singular lists do not
* occur after forking, so the expand will only happen on new VMAs.
*/
- if (vma &&
- (!vma->anon_vma || list_is_singular(&vma->anon_vma_chain)) &&
- ((vma->vm_flags & ~VM_SOFTDIRTY) == flags)) {
+ if (vma && vma->vm_end == addr && !vma_policy(vma) &&
+ can_vma_merge_after(vma, flags, NULL, NULL,
+ addr >> PAGE_SHIFT, NULL_VM_UFFD_CTX, NULL)) {
mas_set_range(mas, vma->vm_start, addr + len - 1);
if (mas_preallocate(mas, vma, GFP_KERNEL))
return -ENOMEM;
@@ -3034,11 +3034,6 @@ int vm_brk_flags(unsigned long addr, unsigned long request, unsigned long flags)
goto munmap_failed;
vma = mas_prev(&mas, 0);
- if (!vma || vma->vm_end != addr || vma_policy(vma) ||
- !can_vma_merge_after(vma, flags, NULL, NULL,
- addr >> PAGE_SHIFT, NULL_VM_UFFD_CTX, NULL))
- vma = NULL;
-
ret = do_brk_flags(&mas, vma, addr, len, flags);
populate = ((mm->def_flags & VM_LOCKED) != 0);
mmap_write_unlock(mm);
diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c
index add4244e5790..3a2c3f8cad2f 100644
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -153,7 +153,7 @@ static void tlb_remove_table_smp_sync(void *arg)
/* Simply deliver the interrupt */
}
-static void tlb_remove_table_sync_one(void)
+void tlb_remove_table_sync_one(void)
{
/*
* This isn't an RCU grace period and hence the page-tables cannot be
@@ -177,8 +177,6 @@ static void tlb_remove_table_free(struct mmu_table_batch *batch)
#else /* !CONFIG_MMU_GATHER_RCU_TABLE_FREE */
-static void tlb_remove_table_sync_one(void) { }
-
static void tlb_remove_table_free(struct mmu_table_batch *batch)
{
__tlb_remove_table_free(batch);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 218b28ee49ed..6e60657875d3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3887,6 +3887,8 @@ __setup("fail_page_alloc=", setup_fail_page_alloc);
static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
+ int flags = 0;
+
if (order < fail_page_alloc.min_order)
return false;
if (gfp_mask & __GFP_NOFAIL)
@@ -3897,10 +3899,11 @@ static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
(gfp_mask & __GFP_DIRECT_RECLAIM))
return false;
+ /* See comment in __should_failslab() */
if (gfp_mask & __GFP_NOWARN)
- fail_page_alloc.attr.no_warn = true;
+ flags |= FAULT_NOWARN;
- return should_fail(&fail_page_alloc.attr, 1 << order);
+ return should_fail_ex(&fail_page_alloc.attr, 1 << order, flags);
}
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
diff --git a/mm/page_ext.c b/mm/page_ext.c
index affe80243b6d..ddf1968560f0 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -166,7 +166,7 @@ struct page_ext *page_ext_get(struct page *page)
/**
* page_ext_put() - Working with page extended information is done.
- * @page_ext - Page extended information received from page_ext_get().
+ * @page_ext: Page extended information received from page_ext_get().
*
* The page extended information of the page may not be valid after this
* function is called.
diff --git a/mm/page_io.c b/mm/page_io.c
index 2af34dd8fa4d..3a5f921b932e 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -376,7 +376,7 @@ void swap_write_unplug(struct swap_iocb *sio)
struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
int ret;
- iov_iter_bvec(&from, WRITE, sio->bvec, sio->pages, sio->len);
+ iov_iter_bvec(&from, ITER_SOURCE, sio->bvec, sio->pages, sio->len);
ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
if (ret != -EIOCBQUEUED)
sio_write_complete(&sio->iocb, ret);
@@ -530,7 +530,7 @@ void __swap_read_unplug(struct swap_iocb *sio)
struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
int ret;
- iov_iter_bvec(&from, READ, sio->bvec, sio->pages, sio->len);
+ iov_iter_bvec(&from, ITER_DEST, sio->bvec, sio->pages, sio->len);
ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
if (ret != -EIOCBQUEUED)
sio_read_complete(&sio->iocb, ret);
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index 382958eef8a9..79a8554f024c 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -11,10 +11,42 @@
#include "page_reporting.h"
#include "internal.h"
-unsigned int page_reporting_order = MAX_ORDER;
-module_param(page_reporting_order, uint, 0644);
+/* Initialize to an unsupported value */
+unsigned int page_reporting_order = -1;
+
+static int page_order_update_notify(const char *val, const struct kernel_param *kp)
+{
+ /*
+ * If param is set beyond this limit, order is set to default
+ * pageblock_order value
+ */
+ return param_set_uint_minmax(val, kp, 0, MAX_ORDER-1);
+}
+
+static const struct kernel_param_ops page_reporting_param_ops = {
+ .set = &page_order_update_notify,
+ /*
+ * For the get op, use param_get_int instead of param_get_uint.
+ * This is to make sure that when unset the initialized value of
+ * -1 is shown correctly
+ */
+ .get = &param_get_int,
+};
+
+module_param_cb(page_reporting_order, &page_reporting_param_ops,
+ &page_reporting_order, 0644);
MODULE_PARM_DESC(page_reporting_order, "Set page reporting order");
+/*
+ * This symbol is also a kernel parameter. Export the page_reporting_order
+ * symbol so that other drivers can access it to control order values without
+ * having to introduce another configurable parameter. Only one driver can
+ * register with the page_reporting driver for the service, so we have just
+ * one control parameter for the use case(which can be accessed in both
+ * drivers)
+ */
+EXPORT_SYMBOL_GPL(page_reporting_order);
+
#define PAGE_REPORTING_DELAY (2 * HZ)
static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
@@ -330,10 +362,18 @@ int page_reporting_register(struct page_reporting_dev_info *prdev)
}
/*
- * Update the page reporting order if it's specified by driver.
- * Otherwise, it falls back to @pageblock_order.
+ * If the page_reporting_order value is not set, we check if
+ * an order is provided from the driver that is performing the
+ * registration. If that is not provided either, we default to
+ * pageblock_order.
*/
- page_reporting_order = prdev->order ? : pageblock_order;
+
+ if (page_reporting_order == -1) {
+ if (prdev->order > 0 && prdev->order <= MAX_ORDER)
+ page_reporting_order = prdev->order;
+ else
+ page_reporting_order = pageblock_order;
+ }
/* initialize state and work structures */
atomic_set(&prdev->state, PAGE_REPORTING_IDLE);
diff --git a/mm/percpu.c b/mm/percpu.c
index 27697b2429c2..acd78da0493b 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -72,7 +72,6 @@
#include <linux/cpumask.h>
#include <linux/memblock.h>
#include <linux/err.h>
-#include <linux/lcm.h>
#include <linux/list.h>
#include <linux/log2.h>
#include <linux/mm.h>
@@ -174,9 +173,6 @@ static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop, map ext
struct list_head *pcpu_chunk_lists __ro_after_init; /* chunk list slots */
-/* chunks which need their map areas extended, protected by pcpu_lock */
-static LIST_HEAD(pcpu_map_extend_chunks);
-
/*
* The number of empty populated pages, protected by pcpu_lock.
* The reserved chunk doesn't contribute to the count.
@@ -834,13 +830,15 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
/*
* Update s_block.
- * block->first_free must be updated if the allocation takes its place.
- * If the allocation breaks the contig_hint, a scan is required to
- * restore this hint.
*/
if (s_block->contig_hint == PCPU_BITMAP_BLOCK_BITS)
nr_empty_pages++;
+ /*
+ * block->first_free must be updated if the allocation takes its place.
+ * If the allocation breaks the contig_hint, a scan is required to
+ * restore this hint.
+ */
if (s_off == s_block->first_free)
s_block->first_free = find_next_zero_bit(
pcpu_index_alloc_map(chunk, s_index),
@@ -915,6 +913,12 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
}
}
+ /*
+ * If the allocation is not atomic, some blocks may not be
+ * populated with pages, while we account it here. The number
+ * of pages will be added back with pcpu_chunk_populated()
+ * when populating pages.
+ */
if (nr_empty_pages)
pcpu_update_empty_pages(chunk, -nr_empty_pages);
@@ -1342,7 +1346,7 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
int map_size)
{
struct pcpu_chunk *chunk;
- unsigned long aligned_addr, lcm_align;
+ unsigned long aligned_addr;
int start_offset, offset_bits, region_size, region_bits;
size_t alloc_size;
@@ -1350,14 +1354,7 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
aligned_addr = tmp_addr & PAGE_MASK;
start_offset = tmp_addr - aligned_addr;
-
- /*
- * Align the end of the region with the LCM of PAGE_SIZE and
- * PCPU_BITMAP_BLOCK_SIZE. One of these constants is a multiple of
- * the other.
- */
- lcm_align = lcm(PAGE_SIZE, PCPU_BITMAP_BLOCK_SIZE);
- region_size = ALIGN(start_offset + map_size, lcm_align);
+ region_size = ALIGN(start_offset + map_size, PAGE_SIZE);
/* allocate chunk */
alloc_size = struct_size(chunk, populated,
@@ -1820,16 +1817,12 @@ restart:
spin_unlock_irqrestore(&pcpu_lock, flags);
- /*
- * No space left. Create a new chunk. We don't want multiple
- * tasks to create chunks simultaneously. Serialize and create iff
- * there's still no empty chunk after grabbing the mutex.
- */
if (is_atomic) {
err = "atomic alloc failed, no space left";
goto fail;
}
+ /* No space left. Create a new chunk. */
if (list_empty(&pcpu_chunk_lists[pcpu_free_slot])) {
chunk = pcpu_create_chunk(pcpu_gfp);
if (!chunk) {
@@ -2146,9 +2139,9 @@ static void pcpu_reclaim_populated(void)
* other accessor is the free path which only returns area back to the
* allocator not touching the populated bitmap.
*/
- while (!list_empty(&pcpu_chunk_lists[pcpu_to_depopulate_slot])) {
- chunk = list_first_entry(&pcpu_chunk_lists[pcpu_to_depopulate_slot],
- struct pcpu_chunk, list);
+ while ((chunk = list_first_entry_or_null(
+ &pcpu_chunk_lists[pcpu_to_depopulate_slot],
+ struct pcpu_chunk, list))) {
WARN_ON(chunk->immutable);
/*
@@ -2166,7 +2159,7 @@ static void pcpu_reclaim_populated(void)
/* reintegrate chunk to prevent atomic alloc failures */
if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_HIGH) {
reintegrate = true;
- goto end_chunk;
+ break;
}
/*
@@ -2202,7 +2195,6 @@ static void pcpu_reclaim_populated(void)
end = -1;
}
-end_chunk:
/* batch tlb flush per chunk to amortize cost */
if (freed_page_start < freed_page_end) {
spin_unlock_irq(&pcpu_lock);
diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c
index 4bcc11958089..78dfaf9e8990 100644
--- a/mm/process_vm_access.c
+++ b/mm/process_vm_access.c
@@ -263,7 +263,7 @@ static ssize_t process_vm_rw(pid_t pid,
struct iovec *iov_r;
struct iov_iter iter;
ssize_t rc;
- int dir = vm_write ? WRITE : READ;
+ int dir = vm_write ? ITER_SOURCE : ITER_DEST;
if (flags != 0)
return -EINVAL;
diff --git a/mm/shmem.c b/mm/shmem.c
index c1d8b8a1aa3b..202ec3156d04 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -948,6 +948,15 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
index++;
}
+ /*
+ * When undoing a failed fallocate, we want none of the partial folio
+ * zeroing and splitting below, but shall want to truncate the whole
+ * folio when !uptodate indicates that it was added by this fallocate,
+ * even when [lstart, lend] covers only a part of the folio.
+ */
+ if (unfalloc)
+ goto whole_folios;
+
same_folio = (lstart >> PAGE_SHIFT) == (lend >> PAGE_SHIFT);
folio = shmem_get_partial_folio(inode, lstart >> PAGE_SHIFT);
if (folio) {
@@ -973,6 +982,8 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
folio_put(folio);
}
+whole_folios:
+
index = start;
while (index < end) {
cond_resched();
@@ -1121,7 +1132,7 @@ static int shmem_setattr(struct user_namespace *mnt_userns,
setattr_copy(&init_user_ns, inode, attr);
if (attr->ia_valid & ATTR_MODE)
- error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
+ error = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
if (!error && update_ctime) {
inode->i_ctime = current_time(inode);
if (update_mtime)
@@ -3272,7 +3283,7 @@ static int shmem_initxattrs(struct inode *inode,
memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
xattr->name, len);
- simple_xattr_list_add(&info->xattrs, new_xattr);
+ simple_xattr_add(&info->xattrs, new_xattr);
}
return 0;
diff --git a/mm/slab.c b/mm/slab.c
index 59c8e28f7b6a..7a269db050ee 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -234,7 +234,7 @@ static void kmem_cache_node_init(struct kmem_cache_node *parent)
parent->shared = NULL;
parent->alien = NULL;
parent->colour_next = 0;
- spin_lock_init(&parent->list_lock);
+ raw_spin_lock_init(&parent->list_lock);
parent->free_objects = 0;
parent->free_touched = 0;
}
@@ -559,9 +559,9 @@ static noinline void cache_free_pfmemalloc(struct kmem_cache *cachep,
slab_node = slab_nid(slab);
n = get_node(cachep, slab_node);
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
free_block(cachep, &objp, 1, slab_node, &list);
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
slabs_destroy(cachep, &list);
}
@@ -684,7 +684,7 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
struct kmem_cache_node *n = get_node(cachep, node);
if (ac->avail) {
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
/*
* Stuff objects into the remote nodes shared array first.
* That way we could avoid the overhead of putting the objects
@@ -695,7 +695,7 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
free_block(cachep, ac->entry, ac->avail, node, list);
ac->avail = 0;
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
}
}
@@ -768,9 +768,9 @@ static int __cache_free_alien(struct kmem_cache *cachep, void *objp,
slabs_destroy(cachep, &list);
} else {
n = get_node(cachep, slab_node);
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
free_block(cachep, &objp, 1, slab_node, &list);
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
slabs_destroy(cachep, &list);
}
return 1;
@@ -811,10 +811,10 @@ static int init_cache_node(struct kmem_cache *cachep, int node, gfp_t gfp)
*/
n = get_node(cachep, node);
if (n) {
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
n->free_limit = (1 + nr_cpus_node(node)) * cachep->batchcount +
cachep->num;
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
return 0;
}
@@ -893,7 +893,7 @@ static int setup_kmem_cache_node(struct kmem_cache *cachep,
goto fail;
n = get_node(cachep, node);
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
if (n->shared && force_change) {
free_block(cachep, n->shared->entry,
n->shared->avail, node, &list);
@@ -911,7 +911,7 @@ static int setup_kmem_cache_node(struct kmem_cache *cachep,
new_alien = NULL;
}
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
slabs_destroy(cachep, &list);
/*
@@ -950,7 +950,7 @@ static void cpuup_canceled(long cpu)
if (!n)
continue;
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
/* Free limit for this kmem_cache_node */
n->free_limit -= cachep->batchcount;
@@ -961,7 +961,7 @@ static void cpuup_canceled(long cpu)
nc->avail = 0;
if (!cpumask_empty(mask)) {
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
goto free_slab;
}
@@ -975,7 +975,7 @@ static void cpuup_canceled(long cpu)
alien = n->alien;
n->alien = NULL;
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
kfree(shared);
if (alien) {
@@ -1159,7 +1159,7 @@ static void __init init_list(struct kmem_cache *cachep, struct kmem_cache_node *
/*
* Do not assume that spinlocks can be initialized via memcpy:
*/
- spin_lock_init(&ptr->list_lock);
+ raw_spin_lock_init(&ptr->list_lock);
MAKE_ALL_LISTS(cachep, ptr, nodeid);
cachep->node[nodeid] = ptr;
@@ -1330,11 +1330,11 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
for_each_kmem_cache_node(cachep, node, n) {
unsigned long total_slabs, free_slabs, free_objs;
- spin_lock_irqsave(&n->list_lock, flags);
+ raw_spin_lock_irqsave(&n->list_lock, flags);
total_slabs = n->total_slabs;
free_slabs = n->free_slabs;
free_objs = n->free_objects;
- spin_unlock_irqrestore(&n->list_lock, flags);
+ raw_spin_unlock_irqrestore(&n->list_lock, flags);
pr_warn(" node %d: slabs: %ld/%ld, objs: %ld/%ld\n",
node, total_slabs - free_slabs, total_slabs,
@@ -1370,6 +1370,8 @@ static struct slab *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
account_slab(slab, cachep->gfporder, cachep, flags);
__folio_set_slab(folio);
+ /* Make the flag visible before any changes to folio->mapping */
+ smp_wmb();
/* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */
if (sk_memalloc_socks() && page_is_pfmemalloc(folio_page(folio, 0)))
slab_set_pfmemalloc(slab);
@@ -1387,9 +1389,11 @@ static void kmem_freepages(struct kmem_cache *cachep, struct slab *slab)
BUG_ON(!folio_test_slab(folio));
__slab_clear_pfmemalloc(slab);
- __folio_clear_slab(folio);
page_mapcount_reset(folio_page(folio, 0));
folio->mapping = NULL;
+ /* Make the mapping reset visible before clearing the flag */
+ smp_wmb();
+ __folio_clear_slab(folio);
if (current->reclaim_state)
current->reclaim_state->reclaimed_slab += 1 << order;
@@ -2096,7 +2100,7 @@ static void check_spinlock_acquired(struct kmem_cache *cachep)
{
#ifdef CONFIG_SMP
check_irq_off();
- assert_spin_locked(&get_node(cachep, numa_mem_id())->list_lock);
+ assert_raw_spin_locked(&get_node(cachep, numa_mem_id())->list_lock);
#endif
}
@@ -2104,7 +2108,7 @@ static void check_spinlock_acquired_node(struct kmem_cache *cachep, int node)
{
#ifdef CONFIG_SMP
check_irq_off();
- assert_spin_locked(&get_node(cachep, node)->list_lock);
+ assert_raw_spin_locked(&get_node(cachep, node)->list_lock);
#endif
}
@@ -2144,9 +2148,9 @@ static void do_drain(void *arg)
check_irq_off();
ac = cpu_cache_get(cachep);
n = get_node(cachep, node);
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
free_block(cachep, ac->entry, ac->avail, node, &list);
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
ac->avail = 0;
slabs_destroy(cachep, &list);
}
@@ -2164,9 +2168,9 @@ static void drain_cpu_caches(struct kmem_cache *cachep)
drain_alien_cache(cachep, n->alien);
for_each_kmem_cache_node(cachep, node, n) {
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
drain_array_locked(cachep, n->shared, node, true, &list);
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
slabs_destroy(cachep, &list);
}
@@ -2188,10 +2192,10 @@ static int drain_freelist(struct kmem_cache *cache,
nr_freed = 0;
while (nr_freed < tofree && !list_empty(&n->slabs_free)) {
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
p = n->slabs_free.prev;
if (p == &n->slabs_free) {
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
goto out;
}
@@ -2204,7 +2208,7 @@ static int drain_freelist(struct kmem_cache *cache,
* to the cache.
*/
n->free_objects -= cache->num;
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
slab_destroy(cache, slab);
nr_freed++;
}
@@ -2629,7 +2633,7 @@ static void cache_grow_end(struct kmem_cache *cachep, struct slab *slab)
INIT_LIST_HEAD(&slab->slab_list);
n = get_node(cachep, slab_nid(slab));
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
n->total_slabs++;
if (!slab->active) {
list_add_tail(&slab->slab_list, &n->slabs_free);
@@ -2639,7 +2643,7 @@ static void cache_grow_end(struct kmem_cache *cachep, struct slab *slab)
STATS_INC_GROWN(cachep);
n->free_objects += cachep->num - slab->active;
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
fixup_objfreelist_debug(cachep, &list);
}
@@ -2805,7 +2809,7 @@ static struct slab *get_first_slab(struct kmem_cache_node *n, bool pfmemalloc)
{
struct slab *slab;
- assert_spin_locked(&n->list_lock);
+ assert_raw_spin_locked(&n->list_lock);
slab = list_first_entry_or_null(&n->slabs_partial, struct slab,
slab_list);
if (!slab) {
@@ -2832,10 +2836,10 @@ static noinline void *cache_alloc_pfmemalloc(struct kmem_cache *cachep,
if (!gfp_pfmemalloc_allowed(flags))
return NULL;
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
slab = get_first_slab(n, true);
if (!slab) {
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
return NULL;
}
@@ -2844,7 +2848,7 @@ static noinline void *cache_alloc_pfmemalloc(struct kmem_cache *cachep,
fixup_slab_list(cachep, n, slab, &list);
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
fixup_objfreelist_debug(cachep, &list);
return obj;
@@ -2903,7 +2907,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
if (!n->free_objects && (!shared || !shared->avail))
goto direct_grow;
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
shared = READ_ONCE(n->shared);
/* See if we can refill from the shared array */
@@ -2927,7 +2931,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
must_grow:
n->free_objects -= ac->avail;
alloc_done:
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
fixup_objfreelist_debug(cachep, &list);
direct_grow:
@@ -3147,7 +3151,7 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
BUG_ON(!n);
check_irq_off();
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
slab = get_first_slab(n, false);
if (!slab)
goto must_grow;
@@ -3165,12 +3169,12 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
fixup_slab_list(cachep, n, slab, &list);
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
fixup_objfreelist_debug(cachep, &list);
return obj;
must_grow:
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
slab = cache_grow_begin(cachep, gfp_exact_node(flags), nodeid);
if (slab) {
/* This slab isn't counted yet so don't update free_objects */
@@ -3254,7 +3258,8 @@ slab_alloc_node(struct kmem_cache *cachep, struct list_lru *lru, gfp_t flags,
init = slab_want_init_on_alloc(flags, cachep);
out:
- slab_post_alloc_hook(cachep, objcg, flags, 1, &objp, init);
+ slab_post_alloc_hook(cachep, objcg, flags, 1, &objp, init,
+ cachep->object_size);
return objp;
}
@@ -3325,7 +3330,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
check_irq_off();
n = get_node(cachep, node);
- spin_lock(&n->list_lock);
+ raw_spin_lock(&n->list_lock);
if (n->shared) {
struct array_cache *shared_array = n->shared;
int max = shared_array->limit - shared_array->avail;
@@ -3354,7 +3359,7 @@ free_done:
STATS_SET_FREEABLE(cachep, i);
}
#endif
- spin_unlock(&n->list_lock);
+ raw_spin_unlock(&n->list_lock);
ac->avail -= batchcount;
memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);
slabs_destroy(cachep, &list);
@@ -3446,16 +3451,6 @@ void *__kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *lru,
return ret;
}
-/**
- * kmem_cache_alloc - Allocate an object
- * @cachep: The cache to allocate from.
- * @flags: See kmalloc().
- *
- * Allocate an object from this cache. The flags are only relevant
- * if the cache has no available objects.
- *
- * Return: pointer to the new object or %NULL in case of error
- */
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
return __kmem_cache_alloc_lru(cachep, NULL, flags);
@@ -3507,13 +3502,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
* Done outside of the IRQ disabled section.
*/
slab_post_alloc_hook(s, objcg, flags, size, p,
- slab_want_init_on_alloc(flags, s));
+ slab_want_init_on_alloc(flags, s), s->object_size);
/* FIXME: Trace call missing. Christoph would like a bulk variant */
return size;
error:
local_irq_enable();
cache_alloc_debugcheck_after_bulk(s, flags, i, p, _RET_IP_);
- slab_post_alloc_hook(s, objcg, flags, i, p, false);
+ slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
kmem_cache_free_bulk(s, i, p);
return 0;
}
@@ -3721,9 +3716,9 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
node = cpu_to_mem(cpu);
n = get_node(cachep, node);
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
free_block(cachep, ac->entry, ac->avail, node, &list);
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
slabs_destroy(cachep, &list);
}
free_percpu(prev);
@@ -3815,9 +3810,9 @@ static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n,
return;
}
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
drain_array_locked(cachep, ac, node, false, &list);
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
slabs_destroy(cachep, &list);
}
@@ -3901,7 +3896,7 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
for_each_kmem_cache_node(cachep, node, n) {
check_irq_on();
- spin_lock_irq(&n->list_lock);
+ raw_spin_lock_irq(&n->list_lock);
total_slabs += n->total_slabs;
free_slabs += n->free_slabs;
@@ -3910,7 +3905,7 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
if (n->shared)
shared_avail += n->shared->avail;
- spin_unlock_irq(&n->list_lock);
+ raw_spin_unlock_irq(&n->list_lock);
}
num_objs = total_slabs * cachep->num;
active_slabs = total_slabs - free_slabs;
diff --git a/mm/slab.h b/mm/slab.h
index 0202a8c2f0d2..7cc432969945 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -11,37 +11,43 @@ struct slab {
#if defined(CONFIG_SLAB)
+ struct kmem_cache *slab_cache;
union {
- struct list_head slab_list;
+ struct {
+ struct list_head slab_list;
+ void *freelist; /* array of free object indexes */
+ void *s_mem; /* first object */
+ };
struct rcu_head rcu_head;
};
- struct kmem_cache *slab_cache;
- void *freelist; /* array of free object indexes */
- void *s_mem; /* first object */
unsigned int active;
#elif defined(CONFIG_SLUB)
- union {
- struct list_head slab_list;
- struct rcu_head rcu_head;
-#ifdef CONFIG_SLUB_CPU_PARTIAL
- struct {
- struct slab *next;
- int slabs; /* Nr of slabs left */
- };
-#endif
- };
struct kmem_cache *slab_cache;
- /* Double-word boundary */
- void *freelist; /* first free object */
union {
- unsigned long counters;
struct {
- unsigned inuse:16;
- unsigned objects:15;
- unsigned frozen:1;
+ union {
+ struct list_head slab_list;
+#ifdef CONFIG_SLUB_CPU_PARTIAL
+ struct {
+ struct slab *next;
+ int slabs; /* Nr of slabs left */
+ };
+#endif
+ };
+ /* Double-word boundary */
+ void *freelist; /* first free object */
+ union {
+ unsigned long counters;
+ struct {
+ unsigned inuse:16;
+ unsigned objects:15;
+ unsigned frozen:1;
+ };
+ };
};
+ struct rcu_head rcu_head;
};
unsigned int __unused;
@@ -66,9 +72,10 @@ struct slab {
#define SLAB_MATCH(pg, sl) \
static_assert(offsetof(struct page, pg) == offsetof(struct slab, sl))
SLAB_MATCH(flags, __page_flags);
-SLAB_MATCH(compound_head, slab_list); /* Ensure bit 0 is clear */
#ifndef CONFIG_SLOB
-SLAB_MATCH(rcu_head, rcu_head);
+SLAB_MATCH(compound_head, slab_cache); /* Ensure bit 0 is clear */
+#else
+SLAB_MATCH(compound_head, slab_list); /* Ensure bit 0 is clear */
#endif
SLAB_MATCH(_refcount, __page_refcount);
#ifdef CONFIG_MEMCG
@@ -76,6 +83,9 @@ SLAB_MATCH(memcg_data, memcg_data);
#endif
#undef SLAB_MATCH
static_assert(sizeof(struct slab) <= sizeof(struct page));
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && defined(CONFIG_SLUB)
+static_assert(IS_ALIGNED(offsetof(struct slab, freelist), 2*sizeof(void *)));
+#endif
/**
* folio_slab - Converts from folio to slab.
@@ -207,8 +217,6 @@ struct kmem_cache {
unsigned int size; /* The aligned/padded/added on size */
unsigned int align; /* Alignment as calculated */
slab_flags_t flags; /* Active flags on the slab */
- unsigned int useroffset;/* Usercopy region offset */
- unsigned int usersize; /* Usercopy region size */
const char *name; /* Slab name for sysfs */
int refcount; /* Use counter */
void (*ctor)(void *); /* Called on object slot creation */
@@ -336,7 +344,8 @@ static inline slab_flags_t kmem_cache_flags(unsigned int object_size,
SLAB_ACCOUNT)
#elif defined(CONFIG_SLUB)
#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \
- SLAB_TEMPORARY | SLAB_ACCOUNT | SLAB_NO_USER_FLAGS)
+ SLAB_TEMPORARY | SLAB_ACCOUNT | \
+ SLAB_NO_USER_FLAGS | SLAB_KMALLOC)
#else
#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE)
#endif
@@ -356,6 +365,7 @@ static inline slab_flags_t kmem_cache_flags(unsigned int object_size,
SLAB_RECLAIM_ACCOUNT | \
SLAB_TEMPORARY | \
SLAB_ACCOUNT | \
+ SLAB_KMALLOC | \
SLAB_NO_USER_FLAGS)
bool __kmem_cache_empty(struct kmem_cache *);
@@ -720,13 +730,27 @@ static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
static inline void slab_post_alloc_hook(struct kmem_cache *s,
struct obj_cgroup *objcg, gfp_t flags,
- size_t size, void **p, bool init)
+ size_t size, void **p, bool init,
+ unsigned int orig_size)
{
+ unsigned int zero_size = s->object_size;
size_t i;
flags &= gfp_allowed_mask;
/*
+ * For kmalloc object, the allocated memory size(object_size) is likely
+ * larger than the requested size(orig_size). If redzone check is
+ * enabled for the extra space, don't zero it, as it will be redzoned
+ * soon. The redzone operation for this extra space could be seen as a
+ * replacement of current poisoning under certain debug option, and
+ * won't break other sanity checks.
+ */
+ if (kmem_cache_debug_flags(s, SLAB_STORE_USER | SLAB_RED_ZONE) &&
+ (s->flags & SLAB_KMALLOC))
+ zero_size = orig_size;
+
+ /*
* As memory initialization might be integrated into KASAN,
* kasan_slab_alloc and initialization memset must be
* kept together to avoid discrepancies in behavior.
@@ -736,7 +760,7 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s,
for (i = 0; i < size; i++) {
p[i] = kasan_slab_alloc(s, p[i], flags, init);
if (p[i] && init && !kasan_has_integrated_init())
- memset(p[i], 0, s->object_size);
+ memset(p[i], 0, zero_size);
kmemleak_alloc_recursive(p[i], s->object_size, 1,
s->flags, flags);
kmsan_slab_alloc(s, p[i], flags);
@@ -750,9 +774,8 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s,
* The slab lists for all objects.
*/
struct kmem_cache_node {
- spinlock_t list_lock;
-
#ifdef CONFIG_SLAB
+ raw_spinlock_t list_lock;
struct list_head slabs_partial; /* partial list first, better asm code */
struct list_head slabs_full;
struct list_head slabs_free;
@@ -768,6 +791,7 @@ struct kmem_cache_node {
#endif
#ifdef CONFIG_SLUB
+ spinlock_t list_lock;
unsigned long nr_partial;
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
@@ -871,4 +895,8 @@ void __check_heap_object(const void *ptr, unsigned long n,
}
#endif
+#ifdef CONFIG_SLUB_DEBUG
+void skip_orig_size_check(struct kmem_cache *s, const void *object);
+#endif
+
#endif /* MM_SLAB_H */
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 33b1886b06eb..3e49bb830060 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -143,8 +143,10 @@ int slab_unmergeable(struct kmem_cache *s)
if (s->ctor)
return 1;
+#ifdef CONFIG_HARDENED_USERCOPY
if (s->usersize)
return 1;
+#endif
/*
* We may have set a slab to be unmergeable during bootstrap.
@@ -223,8 +225,10 @@ static struct kmem_cache *create_cache(const char *name,
s->size = s->object_size = object_size;
s->align = align;
s->ctor = ctor;
+#ifdef CONFIG_HARDENED_USERCOPY
s->useroffset = useroffset;
s->usersize = usersize;
+#endif
err = __kmem_cache_create(s, flags);
if (err)
@@ -317,7 +321,8 @@ kmem_cache_create_usercopy(const char *name,
flags &= CACHE_CREATE_MASK;
/* Fail closed on bad usersize of useroffset values. */
- if (WARN_ON(!usersize && useroffset) ||
+ if (!IS_ENABLED(CONFIG_HARDENED_USERCOPY) ||
+ WARN_ON(!usersize && useroffset) ||
WARN_ON(size < usersize || size - usersize < useroffset))
usersize = useroffset = 0;
@@ -595,8 +600,8 @@ void kmem_dump_obj(void *object)
ptroffset = ((char *)object - (char *)kp.kp_objp) - kp.kp_data_offset;
pr_cont(" pointer offset %lu", ptroffset);
}
- if (kp.kp_slab_cache && kp.kp_slab_cache->usersize)
- pr_cont(" size %u", kp.kp_slab_cache->usersize);
+ if (kp.kp_slab_cache && kp.kp_slab_cache->object_size)
+ pr_cont(" size %u", kp.kp_slab_cache->object_size);
if (kp.kp_ret)
pr_cont(" allocated at %pS\n", kp.kp_ret);
else
@@ -640,8 +645,10 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name,
align = max(align, size);
s->align = calculate_alignment(flags, align, size);
+#ifdef CONFIG_HARDENED_USERCOPY
s->useroffset = useroffset;
s->usersize = usersize;
+#endif
err = __kmem_cache_create(s, flags);
@@ -766,10 +773,16 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
#define KMALLOC_CGROUP_NAME(sz)
#endif
+#ifndef CONFIG_SLUB_TINY
+#define KMALLOC_RCL_NAME(sz) .name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #sz,
+#else
+#define KMALLOC_RCL_NAME(sz)
+#endif
+
#define INIT_KMALLOC_INFO(__size, __short_size) \
{ \
.name[KMALLOC_NORMAL] = "kmalloc-" #__short_size, \
- .name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #__short_size, \
+ KMALLOC_RCL_NAME(__short_size) \
KMALLOC_CGROUP_NAME(__short_size) \
KMALLOC_DMA_NAME(__short_size) \
.size = __size, \
@@ -855,7 +868,7 @@ void __init setup_kmalloc_cache_index_table(void)
static void __init
new_kmalloc_cache(int idx, enum kmalloc_cache_type type, slab_flags_t flags)
{
- if (type == KMALLOC_RECLAIM) {
+ if ((KMALLOC_RECLAIM != KMALLOC_NORMAL) && (type == KMALLOC_RECLAIM)) {
flags |= SLAB_RECLAIM_ACCOUNT;
} else if (IS_ENABLED(CONFIG_MEMCG_KMEM) && (type == KMALLOC_CGROUP)) {
if (mem_cgroup_kmem_disabled()) {
@@ -941,7 +954,7 @@ void *__do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
ret = __kmalloc_large_node(size, flags, node);
- trace_kmalloc(_RET_IP_, ret, size,
+ trace_kmalloc(caller, ret, size,
PAGE_SIZE << get_order(size), flags, node);
return ret;
}
@@ -953,7 +966,7 @@ void *__do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller
ret = __kmem_cache_alloc_node(s, flags, node, size, caller);
ret = kasan_kmalloc(s, ret, size, flags);
- trace_kmalloc(_RET_IP_, ret, size, s->size, flags, node);
+ trace_kmalloc(caller, ret, size, s->size, flags, node);
return ret;
}
@@ -1010,7 +1023,7 @@ EXPORT_SYMBOL(kfree);
/**
* __ksize -- Report full size of underlying allocation
- * @objp: pointer to the object
+ * @object: pointer to the object
*
* This should only be used internally to query the true size of allocations.
* It is not meant to be a way to discover the usable size of an allocation
@@ -1018,7 +1031,7 @@ EXPORT_SYMBOL(kfree);
* the originally requested allocation size may trigger KASAN, UBSAN_BOUNDS,
* and/or FORTIFY_SOURCE.
*
- * Return: size of the actual memory used by @objp in bytes
+ * Return: size of the actual memory used by @object in bytes
*/
size_t __ksize(const void *object)
{
@@ -1037,10 +1050,13 @@ size_t __ksize(const void *object)
return folio_size(folio);
}
+#ifdef CONFIG_SLUB_DEBUG
+ skip_orig_size_check(folio_slab(folio)->slab_cache, object);
+#endif
+
return slab_ksize(folio_slab(folio)->slab_cache);
}
-#ifdef CONFIG_TRACING
void *kmalloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
{
void *ret = __kmem_cache_alloc_node(s, gfpflags, NUMA_NO_NODE,
@@ -1064,7 +1080,6 @@ void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
return ret;
}
EXPORT_SYMBOL(kmalloc_node_trace);
-#endif /* !CONFIG_TRACING */
#endif /* !CONFIG_SLOB */
gfp_t kmalloc_fix_flags(gfp_t flags)
@@ -1411,20 +1426,6 @@ void kfree_sensitive(const void *p)
}
EXPORT_SYMBOL(kfree_sensitive);
-/**
- * ksize - get the actual amount of memory allocated for a given object
- * @objp: Pointer to the object
- *
- * kmalloc may internally round up allocations and return more memory
- * than requested. ksize() can be used to determine the actual amount of
- * memory allocated. The caller may use this additional memory, even though
- * a smaller amount of memory was initially specified with the kmalloc call.
- * The caller must guarantee that objp points to a valid object previously
- * allocated with either kmalloc() or kmem_cache_alloc(). The object
- * must not be freed during the duration of the call.
- *
- * Return: size of the actual memory used by @objp in bytes
- */
size_t ksize(const void *objp)
{
size_t size;
diff --git a/mm/slub.c b/mm/slub.c
index 157527d7101b..2248f85e8167 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -39,6 +39,7 @@
#include <linux/memcontrol.h>
#include <linux/random.h>
#include <kunit/test.h>
+#include <kunit/test-bug.h>
#include <linux/sort.h>
#include <linux/debugfs.h>
@@ -187,6 +188,12 @@ do { \
#define USE_LOCKLESS_FAST_PATH() (false)
#endif
+#ifndef CONFIG_SLUB_TINY
+#define __fastpath_inline __always_inline
+#else
+#define __fastpath_inline
+#endif
+
#ifdef CONFIG_SLUB_DEBUG
#ifdef CONFIG_SLUB_DEBUG_ON
DEFINE_STATIC_KEY_TRUE(slub_debug_enabled);
@@ -241,6 +248,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
/* Enable to log cmpxchg failures */
#undef SLUB_DEBUG_CMPXCHG
+#ifndef CONFIG_SLUB_TINY
/*
* Minimum number of partial slabs. These will be left on the partial
* lists even if they are empty. kmem_cache_shrink may reclaim them.
@@ -253,6 +261,10 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
* sort the partial list by the number of objects in use.
*/
#define MAX_PARTIAL 10
+#else
+#define MIN_PARTIAL 0
+#define MAX_PARTIAL 0
+#endif
#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \
SLAB_POISON | SLAB_STORE_USER)
@@ -298,7 +310,7 @@ struct track {
enum track_item { TRACK_ALLOC, TRACK_FREE };
-#ifdef CONFIG_SYSFS
+#ifdef SLAB_SUPPORTS_SYSFS
static int sysfs_slab_add(struct kmem_cache *);
static int sysfs_slab_alias(struct kmem_cache *, const char *);
#else
@@ -332,10 +344,12 @@ static inline void stat(const struct kmem_cache *s, enum stat_item si)
*/
static nodemask_t slab_nodes;
+#ifndef CONFIG_SLUB_TINY
/*
* Workqueue used for flush_cpu_slab().
*/
static struct workqueue_struct *flushwq;
+#endif
/********************************************************************
* Core slab cache functions
@@ -381,10 +395,12 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object)
return freelist_dereference(s, object + s->offset);
}
+#ifndef CONFIG_SLUB_TINY
static void prefetch_freepointer(const struct kmem_cache *s, void *object)
{
prefetchw(object + s->offset);
}
+#endif
/*
* When running under KMSAN, get_freepointer_safe() may return an uninitialized
@@ -603,7 +619,7 @@ static bool slab_add_kunit_errors(void)
{
struct kunit_resource *resource;
- if (likely(!current->kunit_test))
+ if (!kunit_get_current_test())
return false;
resource = kunit_find_named_resource(current->kunit_test, "slab_errors");
@@ -829,6 +845,17 @@ static inline void set_orig_size(struct kmem_cache *s,
if (!slub_debug_orig_size(s))
return;
+#ifdef CONFIG_KASAN_GENERIC
+ /*
+ * KASAN could save its free meta data in object's data area at
+ * offset 0, if the size is larger than 'orig_size', it will
+ * overlap the data redzone in [orig_size+1, object_size], and
+ * the check should be skipped.
+ */
+ if (kasan_metadata_size(s, true) > orig_size)
+ orig_size = s->object_size;
+#endif
+
p += get_info_end(s);
p += sizeof(struct track) * 2;
@@ -848,6 +875,11 @@ static inline unsigned int get_orig_size(struct kmem_cache *s, void *object)
return *(unsigned int *)p;
}
+void skip_orig_size_check(struct kmem_cache *s, const void *object)
+{
+ set_orig_size(s, (void *)object, s->object_size);
+}
+
static void slab_bug(struct kmem_cache *s, char *fmt, ...)
{
struct va_format vaf;
@@ -910,7 +942,7 @@ static void print_trailer(struct kmem_cache *s, struct slab *slab, u8 *p)
if (slub_debug_orig_size(s))
off += sizeof(unsigned int);
- off += kasan_metadata_size(s);
+ off += kasan_metadata_size(s, false);
if (off != size_from_object(s))
/* Beginning of the filler is the free pointer */
@@ -966,17 +998,28 @@ static __printf(3, 4) void slab_err(struct kmem_cache *s, struct slab *slab,
static void init_object(struct kmem_cache *s, void *object, u8 val)
{
u8 *p = kasan_reset_tag(object);
+ unsigned int poison_size = s->object_size;
- if (s->flags & SLAB_RED_ZONE)
+ if (s->flags & SLAB_RED_ZONE) {
memset(p - s->red_left_pad, val, s->red_left_pad);
+ if (slub_debug_orig_size(s) && val == SLUB_RED_ACTIVE) {
+ /*
+ * Redzone the extra allocated space by kmalloc than
+ * requested, and the poison size will be limited to
+ * the original request size accordingly.
+ */
+ poison_size = get_orig_size(s, object);
+ }
+ }
+
if (s->flags & __OBJECT_POISON) {
- memset(p, POISON_FREE, s->object_size - 1);
- p[s->object_size - 1] = POISON_END;
+ memset(p, POISON_FREE, poison_size - 1);
+ p[poison_size - 1] = POISON_END;
}
if (s->flags & SLAB_RED_ZONE)
- memset(p + s->object_size, val, s->inuse - s->object_size);
+ memset(p + poison_size, val, s->inuse - poison_size);
}
static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
@@ -1070,7 +1113,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct slab *slab, u8 *p)
off += sizeof(unsigned int);
}
- off += kasan_metadata_size(s);
+ off += kasan_metadata_size(s, false);
if (size_from_object(s) == off)
return 1;
@@ -1120,6 +1163,7 @@ static int check_object(struct kmem_cache *s, struct slab *slab,
{
u8 *p = object;
u8 *endobject = object + s->object_size;
+ unsigned int orig_size;
if (s->flags & SLAB_RED_ZONE) {
if (!check_bytes_and_report(s, slab, object, "Left Redzone",
@@ -1129,6 +1173,17 @@ static int check_object(struct kmem_cache *s, struct slab *slab,
if (!check_bytes_and_report(s, slab, object, "Right Redzone",
endobject, val, s->inuse - s->object_size))
return 0;
+
+ if (slub_debug_orig_size(s) && val == SLUB_RED_ACTIVE) {
+ orig_size = get_orig_size(s, object);
+
+ if (s->object_size > orig_size &&
+ !check_bytes_and_report(s, slab, object,
+ "kmalloc Redzone", p + orig_size,
+ val, s->object_size - orig_size)) {
+ return 0;
+ }
+ }
} else {
if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
check_bytes_and_report(s, slab, p, "Alignment padding",
@@ -1363,7 +1418,7 @@ static inline int alloc_consistency_checks(struct kmem_cache *s,
return 1;
}
-static noinline int alloc_debug_processing(struct kmem_cache *s,
+static noinline bool alloc_debug_processing(struct kmem_cache *s,
struct slab *slab, void *object, int orig_size)
{
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
@@ -1375,7 +1430,7 @@ static noinline int alloc_debug_processing(struct kmem_cache *s,
trace(s, slab, object, 1);
set_orig_size(s, object, orig_size);
init_object(s, object, SLUB_RED_ACTIVE);
- return 1;
+ return true;
bad:
if (folio_test_slab(slab_folio(slab))) {
@@ -1388,7 +1443,7 @@ bad:
slab->inuse = slab->objects;
slab->freelist = NULL;
}
- return 0;
+ return false;
}
static inline int free_consistency_checks(struct kmem_cache *s,
@@ -1641,17 +1696,17 @@ static inline void setup_object_debug(struct kmem_cache *s, void *object) {}
static inline
void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr) {}
-static inline int alloc_debug_processing(struct kmem_cache *s,
- struct slab *slab, void *object, int orig_size) { return 0; }
+static inline bool alloc_debug_processing(struct kmem_cache *s,
+ struct slab *slab, void *object, int orig_size) { return true; }
-static inline void free_debug_processing(
- struct kmem_cache *s, struct slab *slab,
- void *head, void *tail, int bulk_cnt,
- unsigned long addr) {}
+static inline bool free_debug_processing(struct kmem_cache *s,
+ struct slab *slab, void *head, void *tail, int *bulk_cnt,
+ unsigned long addr, depot_stack_handle_t handle) { return true; }
static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
static inline int check_object(struct kmem_cache *s, struct slab *slab,
void *object, u8 val) { return 1; }
+static inline depot_stack_handle_t set_track_prepare(void) { return 0; }
static inline void set_track(struct kmem_cache *s, void *object,
enum track_item alloc, unsigned long addr) {}
static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
@@ -1676,11 +1731,13 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
static inline void dec_slabs_node(struct kmem_cache *s, int node,
int objects) {}
+#ifndef CONFIG_SLUB_TINY
static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
void **freelist, void *nextfree)
{
return false;
}
+#endif
#endif /* CONFIG_SLUB_DEBUG */
/*
@@ -1800,6 +1857,8 @@ static inline struct slab *alloc_slab_page(gfp_t flags, int node,
slab = folio_slab(folio);
__folio_set_slab(folio);
+ /* Make the flag visible before any changes to folio->mapping */
+ smp_wmb();
if (page_is_pfmemalloc(folio_page(folio, 0)))
slab_set_pfmemalloc(slab);
@@ -1881,7 +1940,7 @@ static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
return false;
freelist_count = oo_objects(s->oo);
- pos = prandom_u32_max(freelist_count);
+ pos = get_random_u32_below(freelist_count);
page_limit = slab->objects * s->size;
start = fixup_red_left(s, slab_address(slab));
@@ -1999,17 +2058,11 @@ static void __free_slab(struct kmem_cache *s, struct slab *slab)
int order = folio_order(folio);
int pages = 1 << order;
- if (kmem_cache_debug_flags(s, SLAB_CONSISTENCY_CHECKS)) {
- void *p;
-
- slab_pad_check(s, slab);
- for_each_object(p, s, slab_address(slab), slab->objects)
- check_object(s, slab, p, SLUB_RED_INACTIVE);
- }
-
__slab_clear_pfmemalloc(slab);
- __folio_clear_slab(folio);
folio->mapping = NULL;
+ /* Make the mapping reset visible before clearing the flag */
+ smp_wmb();
+ __folio_clear_slab(folio);
if (current->reclaim_state)
current->reclaim_state->reclaimed_slab += pages;
unaccount_slab(slab, order, s);
@@ -2025,9 +2078,17 @@ static void rcu_free_slab(struct rcu_head *h)
static void free_slab(struct kmem_cache *s, struct slab *slab)
{
- if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU)) {
+ if (kmem_cache_debug_flags(s, SLAB_CONSISTENCY_CHECKS)) {
+ void *p;
+
+ slab_pad_check(s, slab);
+ for_each_object(p, s, slab_address(slab), slab->objects)
+ check_object(s, slab, p, SLUB_RED_INACTIVE);
+ }
+
+ if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU))
call_rcu(&slab->rcu_head, rcu_free_slab);
- } else
+ else
__free_slab(s, slab);
}
@@ -2214,7 +2275,7 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
if (!pfmemalloc_match(slab, pc->flags))
continue;
- if (kmem_cache_debug(s)) {
+ if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
object = alloc_single_from_partial(s, n, slab,
pc->orig_size);
if (object)
@@ -2329,6 +2390,8 @@ static void *get_partial(struct kmem_cache *s, int node, struct partial_context
return get_any_partial(s, pc);
}
+#ifndef CONFIG_SLUB_TINY
+
#ifdef CONFIG_PREEMPTION
/*
* Calculate the next globally unique transaction for disambiguation
@@ -2342,7 +2405,7 @@ static void *get_partial(struct kmem_cache *s, int node, struct partial_context
* different cpus.
*/
#define TID_STEP 1
-#endif
+#endif /* CONFIG_PREEMPTION */
static inline unsigned long next_tid(unsigned long tid)
{
@@ -2411,7 +2474,7 @@ static void init_kmem_cache_cpus(struct kmem_cache *s)
static void deactivate_slab(struct kmem_cache *s, struct slab *slab,
void *freelist)
{
- enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE, M_FULL_NOLIST };
+ enum slab_modes { M_NONE, M_PARTIAL, M_FREE, M_FULL_NOLIST };
struct kmem_cache_node *n = get_node(s, slab_nid(slab));
int free_delta = 0;
enum slab_modes mode = M_NONE;
@@ -2487,14 +2550,6 @@ redo:
* acquire_slab() will see a slab that is frozen
*/
spin_lock_irqsave(&n->list_lock, flags);
- } else if (kmem_cache_debug_flags(s, SLAB_STORE_USER)) {
- mode = M_FULL;
- /*
- * This also ensures that the scanning of full
- * slabs from diagnostic functions will not see
- * any frozen slabs.
- */
- spin_lock_irqsave(&n->list_lock, flags);
} else {
mode = M_FULL_NOLIST;
}
@@ -2504,7 +2559,7 @@ redo:
old.freelist, old.counters,
new.freelist, new.counters,
"unfreezing slab")) {
- if (mode == M_PARTIAL || mode == M_FULL)
+ if (mode == M_PARTIAL)
spin_unlock_irqrestore(&n->list_lock, flags);
goto redo;
}
@@ -2518,10 +2573,6 @@ redo:
stat(s, DEACTIVATE_EMPTY);
discard_slab(s, slab);
stat(s, FREE_SLAB);
- } else if (mode == M_FULL) {
- add_full(s, n, slab);
- spin_unlock_irqrestore(&n->list_lock, flags);
- stat(s, DEACTIVATE_FULL);
} else if (mode == M_FULL_NOLIST) {
stat(s, DEACTIVATE_FULL);
}
@@ -2803,6 +2854,13 @@ static int slub_cpu_dead(unsigned int cpu)
return 0;
}
+#else /* CONFIG_SLUB_TINY */
+static inline void flush_all_cpus_locked(struct kmem_cache *s) { }
+static inline void flush_all(struct kmem_cache *s) { }
+static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) { }
+static inline int slub_cpu_dead(unsigned int cpu) { return 0; }
+#endif /* CONFIG_SLUB_TINY */
+
/*
* Check if the objects in a per cpu structure fit numa
* locality expectations.
@@ -2828,38 +2886,28 @@ static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
}
/* Supports checking bulk free of a constructed freelist */
-static noinline void free_debug_processing(
- struct kmem_cache *s, struct slab *slab,
- void *head, void *tail, int bulk_cnt,
- unsigned long addr)
+static inline bool free_debug_processing(struct kmem_cache *s,
+ struct slab *slab, void *head, void *tail, int *bulk_cnt,
+ unsigned long addr, depot_stack_handle_t handle)
{
- struct kmem_cache_node *n = get_node(s, slab_nid(slab));
- struct slab *slab_free = NULL;
+ bool checks_ok = false;
void *object = head;
int cnt = 0;
- unsigned long flags;
- bool checks_ok = false;
- depot_stack_handle_t handle = 0;
-
- if (s->flags & SLAB_STORE_USER)
- handle = set_track_prepare();
-
- spin_lock_irqsave(&n->list_lock, flags);
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
if (!check_slab(s, slab))
goto out;
}
- if (slab->inuse < bulk_cnt) {
+ if (slab->inuse < *bulk_cnt) {
slab_err(s, slab, "Slab has %d allocated objects but %d are to be freed\n",
- slab->inuse, bulk_cnt);
+ slab->inuse, *bulk_cnt);
goto out;
}
next_object:
- if (++cnt > bulk_cnt)
+ if (++cnt > *bulk_cnt)
goto out_cnt;
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
@@ -2881,61 +2929,22 @@ next_object:
checks_ok = true;
out_cnt:
- if (cnt != bulk_cnt)
+ if (cnt != *bulk_cnt) {
slab_err(s, slab, "Bulk free expected %d objects but found %d\n",
- bulk_cnt, cnt);
-
-out:
- if (checks_ok) {
- void *prior = slab->freelist;
-
- /* Perform the actual freeing while we still hold the locks */
- slab->inuse -= cnt;
- set_freepointer(s, tail, prior);
- slab->freelist = head;
-
- /*
- * If the slab is empty, and node's partial list is full,
- * it should be discarded anyway no matter it's on full or
- * partial list.
- */
- if (slab->inuse == 0 && n->nr_partial >= s->min_partial)
- slab_free = slab;
-
- if (!prior) {
- /* was on full list */
- remove_full(s, n, slab);
- if (!slab_free) {
- add_partial(n, slab, DEACTIVATE_TO_TAIL);
- stat(s, FREE_ADD_PARTIAL);
- }
- } else if (slab_free) {
- remove_partial(n, slab);
- stat(s, FREE_REMOVE_PARTIAL);
- }
+ *bulk_cnt, cnt);
+ *bulk_cnt = cnt;
}
- if (slab_free) {
- /*
- * Update the counters while still holding n->list_lock to
- * prevent spurious validation warnings
- */
- dec_slabs_node(s, slab_nid(slab_free), slab_free->objects);
- }
-
- spin_unlock_irqrestore(&n->list_lock, flags);
+out:
if (!checks_ok)
slab_fix(s, "Object at 0x%p not freed", object);
- if (slab_free) {
- stat(s, FREE_SLAB);
- free_slab(s, slab_free);
- }
+ return checks_ok;
}
#endif /* CONFIG_SLUB_DEBUG */
-#if defined(CONFIG_SLUB_DEBUG) || defined(CONFIG_SYSFS)
+#if defined(CONFIG_SLUB_DEBUG) || defined(SLAB_SUPPORTS_SYSFS)
static unsigned long count_partial(struct kmem_cache_node *n,
int (*get_count)(struct slab *))
{
@@ -2949,12 +2958,12 @@ static unsigned long count_partial(struct kmem_cache_node *n,
spin_unlock_irqrestore(&n->list_lock, flags);
return x;
}
-#endif /* CONFIG_SLUB_DEBUG || CONFIG_SYSFS */
+#endif /* CONFIG_SLUB_DEBUG || SLAB_SUPPORTS_SYSFS */
+#ifdef CONFIG_SLUB_DEBUG
static noinline void
slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
{
-#ifdef CONFIG_SLUB_DEBUG
static DEFINE_RATELIMIT_STATE(slub_oom_rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
int node;
@@ -2985,8 +2994,11 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
pr_warn(" node %d: slabs: %ld, objs: %ld, free: %ld\n",
node, nr_slabs, nr_objs, nr_free);
}
-#endif
}
+#else /* CONFIG_SLUB_DEBUG */
+static inline void
+slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) { }
+#endif
static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
{
@@ -2996,6 +3008,7 @@ static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
return true;
}
+#ifndef CONFIG_SLUB_TINY
/*
* Check the slab->freelist and either transfer the freelist to the
* per cpu freelist or deactivate the slab.
@@ -3283,45 +3296,13 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
return p;
}
-/*
- * If the object has been wiped upon free, make sure it's fully initialized by
- * zeroing out freelist pointer.
- */
-static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
- void *obj)
-{
- if (unlikely(slab_want_init_on_free(s)) && obj)
- memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
- 0, sizeof(void *));
-}
-
-/*
- * 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.
- *
- * The fastpath works by first checking if the lockless freelist can be used.
- * If not then __slab_alloc is called for slow processing.
- *
- * Otherwise we can simply pick the next object from the lockless free list.
- */
-static __always_inline void *slab_alloc_node(struct kmem_cache *s, struct list_lru *lru,
+static __always_inline void *__slab_alloc_node(struct kmem_cache *s,
gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
{
- void *object;
struct kmem_cache_cpu *c;
struct slab *slab;
unsigned long tid;
- struct obj_cgroup *objcg = NULL;
- bool init = false;
-
- s = slab_pre_alloc_hook(s, lru, &objcg, 1, gfpflags);
- if (!s)
- return NULL;
-
- object = kfence_alloc(s, orig_size, gfpflags);
- if (unlikely(object))
- goto out;
+ void *object;
redo:
/*
@@ -3391,22 +3372,95 @@ redo:
stat(s, ALLOC_FASTPATH);
}
+ return object;
+}
+#else /* CONFIG_SLUB_TINY */
+static void *__slab_alloc_node(struct kmem_cache *s,
+ gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
+{
+ struct partial_context pc;
+ struct slab *slab;
+ void *object;
+
+ pc.flags = gfpflags;
+ pc.slab = &slab;
+ pc.orig_size = orig_size;
+ object = get_partial(s, node, &pc);
+
+ if (object)
+ return object;
+
+ slab = new_slab(s, gfpflags, node);
+ if (unlikely(!slab)) {
+ slab_out_of_memory(s, gfpflags, node);
+ return NULL;
+ }
+
+ object = alloc_single_from_new_slab(s, slab, orig_size);
+
+ return object;
+}
+#endif /* CONFIG_SLUB_TINY */
+
+/*
+ * If the object has been wiped upon free, make sure it's fully initialized by
+ * zeroing out freelist pointer.
+ */
+static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
+ void *obj)
+{
+ if (unlikely(slab_want_init_on_free(s)) && obj)
+ memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
+ 0, sizeof(void *));
+}
+
+/*
+ * 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.
+ *
+ * The fastpath works by first checking if the lockless freelist can be used.
+ * If not then __slab_alloc is called for slow processing.
+ *
+ * Otherwise we can simply pick the next object from the lockless free list.
+ */
+static __fastpath_inline void *slab_alloc_node(struct kmem_cache *s, struct list_lru *lru,
+ gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
+{
+ void *object;
+ struct obj_cgroup *objcg = NULL;
+ bool init = false;
+
+ s = slab_pre_alloc_hook(s, lru, &objcg, 1, gfpflags);
+ if (!s)
+ return NULL;
+
+ object = kfence_alloc(s, orig_size, gfpflags);
+ if (unlikely(object))
+ goto out;
+
+ object = __slab_alloc_node(s, gfpflags, node, addr, orig_size);
+
maybe_wipe_obj_freeptr(s, object);
init = slab_want_init_on_alloc(gfpflags, s);
out:
- slab_post_alloc_hook(s, objcg, gfpflags, 1, &object, init);
+ /*
+ * When init equals 'true', like for kzalloc() family, only
+ * @orig_size bytes might be zeroed instead of s->object_size
+ */
+ slab_post_alloc_hook(s, objcg, gfpflags, 1, &object, init, orig_size);
return object;
}
-static __always_inline void *slab_alloc(struct kmem_cache *s, struct list_lru *lru,
+static __fastpath_inline void *slab_alloc(struct kmem_cache *s, struct list_lru *lru,
gfp_t gfpflags, unsigned long addr, size_t orig_size)
{
return slab_alloc_node(s, lru, gfpflags, NUMA_NO_NODE, addr, orig_size);
}
-static __always_inline
+static __fastpath_inline
void *__kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
gfp_t gfpflags)
{
@@ -3448,6 +3502,67 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
}
EXPORT_SYMBOL(kmem_cache_alloc_node);
+static noinline void free_to_partial_list(
+ struct kmem_cache *s, struct slab *slab,
+ void *head, void *tail, int bulk_cnt,
+ unsigned long addr)
+{
+ struct kmem_cache_node *n = get_node(s, slab_nid(slab));
+ struct slab *slab_free = NULL;
+ int cnt = bulk_cnt;
+ unsigned long flags;
+ depot_stack_handle_t handle = 0;
+
+ if (s->flags & SLAB_STORE_USER)
+ handle = set_track_prepare();
+
+ spin_lock_irqsave(&n->list_lock, flags);
+
+ if (free_debug_processing(s, slab, head, tail, &cnt, addr, handle)) {
+ void *prior = slab->freelist;
+
+ /* Perform the actual freeing while we still hold the locks */
+ slab->inuse -= cnt;
+ set_freepointer(s, tail, prior);
+ slab->freelist = head;
+
+ /*
+ * If the slab is empty, and node's partial list is full,
+ * it should be discarded anyway no matter it's on full or
+ * partial list.
+ */
+ if (slab->inuse == 0 && n->nr_partial >= s->min_partial)
+ slab_free = slab;
+
+ if (!prior) {
+ /* was on full list */
+ remove_full(s, n, slab);
+ if (!slab_free) {
+ add_partial(n, slab, DEACTIVATE_TO_TAIL);
+ stat(s, FREE_ADD_PARTIAL);
+ }
+ } else if (slab_free) {
+ remove_partial(n, slab);
+ stat(s, FREE_REMOVE_PARTIAL);
+ }
+ }
+
+ if (slab_free) {
+ /*
+ * Update the counters while still holding n->list_lock to
+ * prevent spurious validation warnings
+ */
+ dec_slabs_node(s, slab_nid(slab_free), slab_free->objects);
+ }
+
+ spin_unlock_irqrestore(&n->list_lock, flags);
+
+ if (slab_free) {
+ stat(s, FREE_SLAB);
+ free_slab(s, slab_free);
+ }
+}
+
/*
* Slow path handling. This may still be called frequently since objects
* have a longer lifetime than the cpu slabs in most processing loads.
@@ -3473,8 +3588,8 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
if (kfence_free(head))
return;
- if (kmem_cache_debug(s)) {
- free_debug_processing(s, slab, head, tail, cnt, addr);
+ if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
+ free_to_partial_list(s, slab, head, tail, cnt, addr);
return;
}
@@ -3574,6 +3689,7 @@ slab_empty:
discard_slab(s, slab);
}
+#ifndef CONFIG_SLUB_TINY
/*
* Fastpath with forced inlining to produce a kfree and kmem_cache_free that
* can perform fastpath freeing without additional function calls.
@@ -3648,8 +3764,18 @@ redo:
}
stat(s, FREE_FASTPATH);
}
+#else /* CONFIG_SLUB_TINY */
+static void do_slab_free(struct kmem_cache *s,
+ struct slab *slab, void *head, void *tail,
+ int cnt, unsigned long addr)
+{
+ void *tail_obj = tail ? : head;
+
+ __slab_free(s, slab, head, tail_obj, cnt, addr);
+}
+#endif /* CONFIG_SLUB_TINY */
-static __always_inline void slab_free(struct kmem_cache *s, struct slab *slab,
+static __fastpath_inline void slab_free(struct kmem_cache *s, struct slab *slab,
void *head, void *tail, void **p, int cnt,
unsigned long addr)
{
@@ -3782,18 +3908,13 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
}
EXPORT_SYMBOL(kmem_cache_free_bulk);
-/* Note that interrupts must be enabled when calling this function. */
-int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
- void **p)
+#ifndef CONFIG_SLUB_TINY
+static inline int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags,
+ size_t size, void **p, struct obj_cgroup *objcg)
{
struct kmem_cache_cpu *c;
int i;
- struct obj_cgroup *objcg = NULL;
- /* memcg and kmem_cache debug support */
- s = slab_pre_alloc_hook(s, NULL, &objcg, size, flags);
- if (unlikely(!s))
- return false;
/*
* Drain objects in the per cpu slab, while disabling local
* IRQs, which protects against PREEMPT and interrupts
@@ -3847,19 +3968,72 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
local_unlock_irq(&s->cpu_slab->lock);
slub_put_cpu_ptr(s->cpu_slab);
- /*
- * memcg and kmem_cache debug support and memory initialization.
- * Done outside of the IRQ disabled fastpath loop.
- */
- slab_post_alloc_hook(s, objcg, flags, size, p,
- slab_want_init_on_alloc(flags, s));
return i;
+
error:
slub_put_cpu_ptr(s->cpu_slab);
- slab_post_alloc_hook(s, objcg, flags, i, p, false);
+ slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
+ kmem_cache_free_bulk(s, i, p);
+ return 0;
+
+}
+#else /* CONFIG_SLUB_TINY */
+static int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags,
+ size_t size, void **p, struct obj_cgroup *objcg)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ void *object = kfence_alloc(s, s->object_size, flags);
+
+ if (unlikely(object)) {
+ p[i] = object;
+ continue;
+ }
+
+ p[i] = __slab_alloc_node(s, flags, NUMA_NO_NODE,
+ _RET_IP_, s->object_size);
+ if (unlikely(!p[i]))
+ goto error;
+
+ maybe_wipe_obj_freeptr(s, p[i]);
+ }
+
+ return i;
+
+error:
+ slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
kmem_cache_free_bulk(s, i, p);
return 0;
}
+#endif /* CONFIG_SLUB_TINY */
+
+/* Note that interrupts must be enabled when calling this function. */
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+ void **p)
+{
+ int i;
+ struct obj_cgroup *objcg = NULL;
+
+ if (!size)
+ return 0;
+
+ /* memcg and kmem_cache debug support */
+ s = slab_pre_alloc_hook(s, NULL, &objcg, size, flags);
+ if (unlikely(!s))
+ return 0;
+
+ i = __kmem_cache_alloc_bulk(s, flags, size, p, objcg);
+
+ /*
+ * memcg and kmem_cache debug support and memory initialization.
+ * Done outside of the IRQ disabled fastpath loop.
+ */
+ if (i != 0)
+ slab_post_alloc_hook(s, objcg, flags, size, p,
+ slab_want_init_on_alloc(flags, s), s->object_size);
+ return i;
+}
EXPORT_SYMBOL(kmem_cache_alloc_bulk);
@@ -3883,7 +4057,8 @@ EXPORT_SYMBOL(kmem_cache_alloc_bulk);
* take the list_lock.
*/
static unsigned int slub_min_order;
-static unsigned int slub_max_order = PAGE_ALLOC_COSTLY_ORDER;
+static unsigned int slub_max_order =
+ IS_ENABLED(CONFIG_SLUB_TINY) ? 1 : PAGE_ALLOC_COSTLY_ORDER;
static unsigned int slub_min_objects;
/*
@@ -4014,10 +4189,12 @@ init_kmem_cache_node(struct kmem_cache_node *n)
#endif
}
+#ifndef CONFIG_SLUB_TINY
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
- KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
+ NR_KMALLOC_TYPES * KMALLOC_SHIFT_HIGH *
+ sizeof(struct kmem_cache_cpu));
/*
* Must align to double word boundary for the double cmpxchg
@@ -4033,6 +4210,12 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
return 1;
}
+#else
+static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
+{
+ return 1;
+}
+#endif /* CONFIG_SLUB_TINY */
static struct kmem_cache *kmem_cache_node;
@@ -4095,7 +4278,9 @@ static void free_kmem_cache_nodes(struct kmem_cache *s)
void __kmem_cache_release(struct kmem_cache *s)
{
cache_random_seq_destroy(s);
+#ifndef CONFIG_SLUB_TINY
free_percpu(s->cpu_slab);
+#endif
free_kmem_cache_nodes(s);
}
@@ -4202,7 +4387,8 @@ static int calculate_sizes(struct kmem_cache *s)
*/
s->inuse = size;
- if ((flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) ||
+ if (slub_debug_orig_size(s) ||
+ (flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) ||
((flags & SLAB_RED_ZONE) && s->object_size < sizeof(void *)) ||
s->ctor) {
/*
@@ -4872,8 +5058,10 @@ void __init kmem_cache_init(void)
void __init kmem_cache_init_late(void)
{
+#ifndef CONFIG_SLUB_TINY
flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM, 0);
WARN_ON(!flushwq);
+#endif
}
struct kmem_cache *
@@ -4924,7 +5112,7 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags)
return 0;
}
-#ifdef CONFIG_SYSFS
+#ifdef SLAB_SUPPORTS_SYSFS
static int count_inuse(struct slab *slab)
{
return slab->inuse;
@@ -5182,7 +5370,7 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
#endif /* CONFIG_DEBUG_FS */
#endif /* CONFIG_SLUB_DEBUG */
-#ifdef CONFIG_SYSFS
+#ifdef SLAB_SUPPORTS_SYSFS
enum slab_stat_type {
SL_ALL, /* All slabs */
SL_PARTIAL, /* Only partially allocated slabs */
@@ -5502,11 +5690,13 @@ static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
SLAB_ATTR_RO(cache_dma);
#endif
+#ifdef CONFIG_HARDENED_USERCOPY
static ssize_t usersize_show(struct kmem_cache *s, char *buf)
{
return sysfs_emit(buf, "%u\n", s->usersize);
}
SLAB_ATTR_RO(usersize);
+#endif
static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
{
@@ -5586,7 +5776,21 @@ static ssize_t failslab_show(struct kmem_cache *s, char *buf)
{
return sysfs_emit(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB));
}
-SLAB_ATTR_RO(failslab);
+
+static ssize_t failslab_store(struct kmem_cache *s, const char *buf,
+ size_t length)
+{
+ if (s->refcount > 1)
+ return -EINVAL;
+
+ if (buf[0] == '1')
+ WRITE_ONCE(s->flags, s->flags | SLAB_FAILSLAB);
+ else
+ WRITE_ONCE(s->flags, s->flags & ~SLAB_FAILSLAB);
+
+ return length;
+}
+SLAB_ATTR(failslab);
#endif
static ssize_t shrink_show(struct kmem_cache *s, char *buf)
@@ -5803,7 +6007,9 @@ static struct attribute *slab_attrs[] = {
#ifdef CONFIG_FAILSLAB
&failslab_attr.attr,
#endif
+#ifdef CONFIG_HARDENED_USERCOPY
&usersize_attr.attr,
+#endif
#ifdef CONFIG_KFENCE
&skip_kfence_attr.attr,
#endif
@@ -5920,11 +6126,6 @@ static int sysfs_slab_add(struct kmem_cache *s)
struct kset *kset = cache_kset(s);
int unmergeable = slab_unmergeable(s);
- if (!kset) {
- kobject_init(&s->kobj, &slab_ktype);
- return 0;
- }
-
if (!unmergeable && disable_higher_order_debug &&
(slub_debug & DEBUG_METADATA_FLAGS))
unmergeable = 1;
@@ -6054,9 +6255,8 @@ static int __init slab_sysfs_init(void)
mutex_unlock(&slab_mutex);
return 0;
}
-
-__initcall(slab_sysfs_init);
-#endif /* CONFIG_SYSFS */
+late_initcall(slab_sysfs_init);
+#endif /* SLAB_SUPPORTS_SYSFS */
#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
static int slab_debugfs_show(struct seq_file *seq, void *v)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 5fc1237a9f21..3eedf7ae957f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -772,8 +772,7 @@ static void set_cluster_next(struct swap_info_struct *si, unsigned long next)
/* No free swap slots available */
if (si->highest_bit <= si->lowest_bit)
return;
- next = si->lowest_bit +
- prandom_u32_max(si->highest_bit - si->lowest_bit + 1);
+ next = get_random_u32_inclusive(si->lowest_bit, si->highest_bit);
next = ALIGN_DOWN(next, SWAP_ADDRESS_SPACE_PAGES);
next = max_t(unsigned int, next, si->lowest_bit);
}
@@ -973,23 +972,23 @@ done:
scan:
spin_unlock(&si->lock);
while (++offset <= READ_ONCE(si->highest_bit)) {
- if (swap_offset_available_and_locked(si, offset))
- goto checks;
if (unlikely(--latency_ration < 0)) {
cond_resched();
latency_ration = LATENCY_LIMIT;
scanned_many = true;
}
+ if (swap_offset_available_and_locked(si, offset))
+ goto checks;
}
offset = si->lowest_bit;
while (offset < scan_base) {
- if (swap_offset_available_and_locked(si, offset))
- goto checks;
if (unlikely(--latency_ration < 0)) {
cond_resched();
latency_ration = LATENCY_LIMIT;
scanned_many = true;
}
+ if (swap_offset_available_and_locked(si, offset))
+ goto checks;
offset++;
}
spin_lock(&si->lock);
@@ -3089,7 +3088,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
*/
for_each_possible_cpu(cpu) {
per_cpu(*p->cluster_next_cpu, cpu) =
- 1 + prandom_u32_max(p->highest_bit);
+ get_random_u32_inclusive(1, p->highest_bit);
}
nr_cluster = DIV_ROUND_UP(maxpages, SWAPFILE_CLUSTER);
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 3d0fef3980b3..650ab6cfd5f4 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -64,7 +64,7 @@ int mfill_atomic_install_pte(struct mm_struct *dst_mm, pmd_t *dst_pmd,
pte_t _dst_pte, *dst_pte;
bool writable = dst_vma->vm_flags & VM_WRITE;
bool vm_shared = dst_vma->vm_flags & VM_SHARED;
- bool page_in_cache = page->mapping;
+ bool page_in_cache = page_mapping(page);
spinlock_t *ptl;
struct inode *inode;
pgoff_t offset, max_off;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 04d8b88e5216..8fcc5fa768c0 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2514,8 +2514,20 @@ static unsigned long shrink_inactive_list(unsigned long nr_to_scan,
* the flushers simply cannot keep up with the allocation
* rate. Nudge the flusher threads in case they are asleep.
*/
- if (stat.nr_unqueued_dirty == nr_taken)
+ if (stat.nr_unqueued_dirty == nr_taken) {
wakeup_flusher_threads(WB_REASON_VMSCAN);
+ /*
+ * For cgroupv1 dirty throttling is achieved by waking up
+ * the kernel flusher here and later waiting on folios
+ * which are in writeback to finish (see shrink_folio_list()).
+ *
+ * Flusher may not be able to issue writeback quickly
+ * enough for cgroupv1 writeback throttling to work
+ * on a large system.
+ */
+ if (!writeback_throttling_sane(sc))
+ reclaim_throttle(pgdat, VMSCAN_THROTTLE_WRITEBACK);
+ }
sc->nr.dirty += stat.nr_dirty;
sc->nr.congested += stat.nr_congested;
@@ -3975,7 +3987,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area
goto next;
if (!pmd_trans_huge(pmd[i])) {
- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) &&
+ if (arch_has_hw_nonleaf_pmd_young() &&
get_cap(LRU_GEN_NONLEAF_YOUNG))
pmdp_test_and_clear_young(vma, addr, pmd + i);
goto next;
@@ -4073,14 +4085,14 @@ restart:
#endif
walk->mm_stats[MM_NONLEAF_TOTAL]++;
-#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG
- if (get_cap(LRU_GEN_NONLEAF_YOUNG)) {
+ if (arch_has_hw_nonleaf_pmd_young() &&
+ get_cap(LRU_GEN_NONLEAF_YOUNG)) {
if (!pmd_young(val))
continue;
walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos);
}
-#endif
+
if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i))
continue;
@@ -4971,10 +4983,13 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap
int scanned;
int reclaimed;
LIST_HEAD(list);
+ LIST_HEAD(clean);
struct folio *folio;
+ struct folio *next;
enum vm_event_item item;
struct reclaim_stat stat;
struct lru_gen_mm_walk *walk;
+ bool skip_retry = false;
struct mem_cgroup *memcg = lruvec_memcg(lruvec);
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
@@ -4991,20 +5006,37 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap
if (list_empty(&list))
return scanned;
-
+retry:
reclaimed = shrink_folio_list(&list, pgdat, sc, &stat, false);
+ sc->nr_reclaimed += reclaimed;
- list_for_each_entry(folio, &list, lru) {
- /* restore LRU_REFS_FLAGS cleared by isolate_folio() */
- if (folio_test_workingset(folio))
- folio_set_referenced(folio);
+ list_for_each_entry_safe_reverse(folio, next, &list, lru) {
+ if (!folio_evictable(folio)) {
+ list_del(&folio->lru);
+ folio_putback_lru(folio);
+ continue;
+ }
- /* don't add rejected pages to the oldest generation */
if (folio_test_reclaim(folio) &&
- (folio_test_dirty(folio) || folio_test_writeback(folio)))
- folio_clear_active(folio);
- else
- folio_set_active(folio);
+ (folio_test_dirty(folio) || folio_test_writeback(folio))) {
+ /* restore LRU_REFS_FLAGS cleared by isolate_folio() */
+ if (folio_test_workingset(folio))
+ folio_set_referenced(folio);
+ continue;
+ }
+
+ if (skip_retry || folio_test_active(folio) || folio_test_referenced(folio) ||
+ folio_mapped(folio) || folio_test_locked(folio) ||
+ folio_test_dirty(folio) || folio_test_writeback(folio)) {
+ /* don't add rejected folios to the oldest generation */
+ set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS,
+ BIT(PG_active));
+ continue;
+ }
+
+ /* retry folios that may have missed folio_rotate_reclaimable() */
+ list_move(&folio->lru, &clean);
+ sc->nr_scanned -= folio_nr_pages(folio);
}
spin_lock_irq(&lruvec->lru_lock);
@@ -5026,7 +5058,13 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap
mem_cgroup_uncharge_list(&list);
free_unref_page_list(&list);
- sc->nr_reclaimed += reclaimed;
+ INIT_LIST_HEAD(&list);
+ list_splice_init(&clean, &list);
+
+ if (!list_empty(&list)) {
+ skip_retry = true;
+ goto retry;
+ }
if (need_swapping && type == LRU_GEN_ANON)
*need_swapping = true;
@@ -5354,7 +5392,7 @@ static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, c
if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))
caps |= BIT(LRU_GEN_MM_WALK);
- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG))
+ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG))
caps |= BIT(LRU_GEN_NONLEAF_YOUNG);
return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps);
@@ -5844,8 +5882,8 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
enum lru_list lru;
unsigned long nr_reclaimed = 0;
unsigned long nr_to_reclaim = sc->nr_to_reclaim;
+ bool proportional_reclaim;
struct blk_plug plug;
- bool scan_adjusted;
if (lru_gen_enabled()) {
lru_gen_shrink_lruvec(lruvec, sc);
@@ -5868,8 +5906,8 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
* abort proportional reclaim if either the file or anon lru has already
* dropped to zero at the first pass.
*/
- scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() &&
- sc->priority == DEF_PRIORITY);
+ proportional_reclaim = (!cgroup_reclaim(sc) && !current_is_kswapd() &&
+ sc->priority == DEF_PRIORITY);
blk_start_plug(&plug);
while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
@@ -5889,7 +5927,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
cond_resched();
- if (nr_reclaimed < nr_to_reclaim || scan_adjusted)
+ if (nr_reclaimed < nr_to_reclaim || proportional_reclaim)
continue;
/*
@@ -5940,8 +5978,6 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
nr_scanned = targets[lru] - nr[lru];
nr[lru] = targets[lru] * (100 - percentage) / 100;
nr[lru] -= min(nr[lru], nr_scanned);
-
- scan_adjusted = true;
}
blk_finish_plug(&plug);
sc->nr_reclaimed += nr_reclaimed;
diff --git a/net/802/garp.c b/net/802/garp.c
index fc9eb02a912f..77aac2763835 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -407,7 +407,7 @@ static void garp_join_timer_arm(struct garp_applicant *app)
{
unsigned long delay;
- delay = prandom_u32_max(msecs_to_jiffies(garp_join_time));
+ delay = get_random_u32_below(msecs_to_jiffies(garp_join_time));
mod_timer(&app->join_timer, jiffies + delay);
}
diff --git a/net/802/mrp.c b/net/802/mrp.c
index 155f74d8b14f..8c6f0381023b 100644
--- a/net/802/mrp.c
+++ b/net/802/mrp.c
@@ -592,7 +592,7 @@ static void mrp_join_timer_arm(struct mrp_applicant *app)
{
unsigned long delay;
- delay = prandom_u32_max(msecs_to_jiffies(mrp_join_time));
+ delay = get_random_u32_below(msecs_to_jiffies(mrp_join_time));
mod_timer(&app->join_timer, jiffies + delay);
}
diff --git a/net/9p/client.c b/net/9p/client.c
index aaa37b07e30a..0638b12055ba 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -2043,7 +2043,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
struct kvec kv = {.iov_base = data, .iov_len = count};
struct iov_iter to;
- iov_iter_kvec(&to, READ, &kv, 1, count);
+ iov_iter_kvec(&to, ITER_DEST, &kv, 1, count);
p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
fid->fid, offset, count);
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 56a186768750..07db2f436d44 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -120,7 +120,7 @@ struct p9_conn {
struct list_head unsent_req_list;
struct p9_req_t *rreq;
struct p9_req_t *wreq;
- char tmp_buf[7];
+ char tmp_buf[P9_HDRSZ];
struct p9_fcall rc;
int wpos;
int wsize;
@@ -202,9 +202,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
list_move(&req->req_list, &cancel_list);
+ req->status = REQ_STATUS_ERROR;
}
list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
list_move(&req->req_list, &cancel_list);
+ req->status = REQ_STATUS_ERROR;
}
spin_unlock(&m->req_lock);
@@ -291,7 +293,7 @@ static void p9_read_work(struct work_struct *work)
if (!m->rc.sdata) {
m->rc.sdata = m->tmp_buf;
m->rc.offset = 0;
- m->rc.capacity = 7; /* start by reading header */
+ m->rc.capacity = P9_HDRSZ; /* start by reading header */
}
clear_bit(Rpending, &m->wsched);
@@ -314,7 +316,7 @@ static void p9_read_work(struct work_struct *work)
p9_debug(P9_DEBUG_TRANS, "got new header\n");
/* Header size */
- m->rc.size = 7;
+ m->rc.size = P9_HDRSZ;
err = p9_parse_header(&m->rc, &m->rc.size, NULL, NULL, 0);
if (err) {
p9_debug(P9_DEBUG_ERROR,
@@ -322,14 +324,6 @@ static void p9_read_work(struct work_struct *work)
goto error;
}
- if (m->rc.size >= m->client->msize) {
- p9_debug(P9_DEBUG_ERROR,
- "requested packet size too big: %d\n",
- m->rc.size);
- err = -EIO;
- goto error;
- }
-
p9_debug(P9_DEBUG_TRANS,
"mux %p pkt: size: %d bytes tag: %d\n",
m, m->rc.size, m->rc.tag);
@@ -342,6 +336,14 @@ static void p9_read_work(struct work_struct *work)
goto error;
}
+ if (m->rc.size > m->rreq->rc.capacity) {
+ p9_debug(P9_DEBUG_ERROR,
+ "requested packet size too big: %d for tag %d with capacity %zd\n",
+ m->rc.size, m->rc.tag, m->rreq->rc.capacity);
+ err = -EIO;
+ goto error;
+ }
+
if (!m->rreq->rc.sdata) {
p9_debug(P9_DEBUG_ERROR,
"No recv fcall for tag %d (req %p), disconnecting!\n",
@@ -860,8 +862,10 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket)
struct file *file;
p = kzalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
- if (!p)
+ if (!p) {
+ sock_release(csocket);
return -ENOMEM;
+ }
csocket->sk->sk_allocation = GFP_NOIO;
file = sock_alloc_file(csocket, 0, NULL);
diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
index b15c64128c3e..aaa5fd364691 100644
--- a/net/9p/trans_xen.c
+++ b/net/9p/trans_xen.c
@@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
continue;
}
+ if (h.size > req->rc.capacity) {
+ dev_warn(&priv->dev->dev,
+ "requested packet size too big: %d for tag %d with capacity %zd\n",
+ h.size, h.tag, req->rc.capacity);
+ req->status = REQ_STATUS_ERROR;
+ goto recv_error;
+ }
+
memcpy(&req->rc, &h, sizeof(h));
req->rc.offset = 0;
@@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work)
masked_prod, &masked_cons,
XEN_9PFS_RING_SIZE(ring));
+recv_error:
virt_mb();
cons += h.size;
ring->intf->in_cons = cons;
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 7f6a7c96ac92..114ee5da261f 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -280,7 +280,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
unsigned int msecs;
msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
- msecs += prandom_u32_max(2 * BATADV_JITTER);
+ msecs += get_random_u32_below(2 * BATADV_JITTER);
return jiffies + msecs_to_jiffies(msecs);
}
@@ -288,7 +288,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
/* when do we schedule a ogm packet to be sent */
static unsigned long batadv_iv_ogm_fwd_send_time(void)
{
- return jiffies + msecs_to_jiffies(prandom_u32_max(BATADV_JITTER / 2));
+ return jiffies + msecs_to_jiffies(get_random_u32_below(BATADV_JITTER / 2));
}
/* apply hop penalty for a normal link */
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index f1741fbfb617..f9a58fb5442e 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -51,7 +51,7 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
unsigned int msecs;
msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
- msecs += prandom_u32_max(2 * BATADV_JITTER);
+ msecs += get_random_u32_below(2 * BATADV_JITTER);
queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
msecs_to_jiffies(msecs));
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 033639df96d8..addfd8c4fe95 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -90,7 +90,7 @@ static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
/* msecs * [0.9, 1.1] */
- msecs += prandom_u32_max(msecs / 5) - (msecs / 10);
+ msecs += get_random_u32_below(msecs / 5) - (msecs / 10);
queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.aggr_wq,
msecs_to_jiffies(msecs / 1000));
}
@@ -109,7 +109,7 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
return;
msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
- msecs += prandom_u32_max(2 * BATADV_JITTER);
+ msecs += get_random_u32_below(2 * BATADV_JITTER);
queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
msecs_to_jiffies(msecs));
}
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 5f4aeeb60dc4..bf29fba4dde5 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -1009,7 +1009,7 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,
static u8 batadv_nc_random_weight_tq(u8 tq)
{
/* randomize the estimated packet loss (max TQ - estimated TQ) */
- u8 rand_tq = prandom_u32_max(BATADV_TQ_MAX_VALUE + 1 - tq);
+ u8 rand_tq = get_random_u32_below(BATADV_TQ_MAX_VALUE + 1 - tq);
/* convert to (randomized) estimated tq again */
return BATADV_TQ_MAX_VALUE - rand_tq;
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 215af9b3b589..4eb1b3ced0d2 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -441,7 +441,7 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
iv.iov_len = skb->len;
memset(&msg, 0, sizeof(msg));
- iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, skb->len);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, skb->len);
err = l2cap_chan_send(chan, &msg, skb->len);
if (err > 0) {
@@ -972,6 +972,7 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type);
hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
if (!hcon)
return -ENOENT;
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 1fcc482397c3..e7adb8a98cf9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -56,7 +56,7 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *dat
memset(&msg, 0, sizeof(msg));
- iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, total_len);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, total_len);
l2cap_chan_send(chan, &msg, total_len);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index dc65974f5adb..1c3c7ff5c3c6 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -737,7 +737,7 @@ static int __init bt_init(void)
err = bt_sysfs_init();
if (err < 0)
- return err;
+ goto cleanup_led;
err = sock_register(&bt_sock_family_ops);
if (err)
@@ -773,6 +773,8 @@ unregister_socket:
sock_unregister(PF_BLUETOOTH);
cleanup_sysfs:
bt_sysfs_cleanup();
+cleanup_led:
+ bt_leds_cleanup();
return err;
}
diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 38201532f58e..3cc135bb1d30 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -72,9 +72,8 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
continue;
}
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
- sizeof(*cmd), cmd,
- HCI_CMD_TIMEOUT);
+ skb = __hci_cmd_sync_sk(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
+ sizeof(*cmd), cmd, 0, HCI_CMD_TIMEOUT, NULL);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
PTR_ERR(skb));
@@ -127,8 +126,8 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
struct hci_op_read_local_codec_caps caps;
__u8 i;
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
- HCI_CMD_TIMEOUT);
+ skb = __hci_cmd_sync_sk(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
+ 0, HCI_CMD_TIMEOUT, NULL);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
@@ -158,7 +157,8 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
for (i = 0; i < std_codecs->num; i++) {
caps.id = std_codecs->codec[i];
caps.direction = 0x00;
- hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
+ hci_read_codec_capabilities(hdev,
+ LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
@@ -178,7 +178,8 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
caps.cid = vnd_codecs->codec[i].cid;
caps.vid = vnd_codecs->codec[i].vid;
caps.direction = 0x00;
- hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
+ hci_read_codec_capabilities(hdev,
+ LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
}
error:
@@ -194,8 +195,8 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
struct hci_op_read_local_codec_caps caps;
__u8 i;
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS_V2, 0, NULL,
- HCI_CMD_TIMEOUT);
+ skb = __hci_cmd_sync_sk(hdev, HCI_OP_READ_LOCAL_CODECS_V2, 0, NULL,
+ 0, HCI_CMD_TIMEOUT, NULL);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0540555b3704..d97fac4f7130 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2764,7 +2764,8 @@ int hci_register_suspend_notifier(struct hci_dev *hdev)
{
int ret = 0;
- if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
+ if (!hdev->suspend_notifier.notifier_call &&
+ !test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
hdev->suspend_notifier.notifier_call = hci_suspend_notifier;
ret = register_pm_notifier(&hdev->suspend_notifier);
}
@@ -2776,8 +2777,11 @@ int hci_unregister_suspend_notifier(struct hci_dev *hdev)
{
int ret = 0;
- if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
+ if (hdev->suspend_notifier.notifier_call) {
ret = unregister_pm_notifier(&hdev->suspend_notifier);
+ if (!ret)
+ hdev->suspend_notifier.notifier_call = NULL;
+ }
return ret;
}
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 5a0296a4352e..f7e006a36382 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -269,7 +269,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
const void *param)
{
- bt_dev_err(req->hdev, "HCI_REQ-0x%4.4x", opcode);
+ bt_dev_dbg(req->hdev, "HCI_REQ-0x%4.4x", opcode);
hci_req_add_ev(req, opcode, plen, param, 0);
}
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 76c3107c9f91..1fc693122a47 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -12,6 +12,7 @@
#include <net/bluetooth/mgmt.h>
#include "hci_request.h"
+#include "hci_codec.h"
#include "hci_debugfs.h"
#include "smp.h"
#include "eir.h"
@@ -3780,7 +3781,8 @@ static int hci_read_page_scan_activity_sync(struct hci_dev *hdev)
static int hci_read_def_err_data_reporting_sync(struct hci_dev *hdev)
{
if (!(hdev->commands[18] & 0x04) ||
- !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING))
+ !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING) ||
+ test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_READ_DEF_ERR_DATA_REPORTING,
@@ -4238,11 +4240,12 @@ static int hci_set_event_mask_page_2_sync(struct hci_dev *hdev)
/* Read local codec list if the HCI command is supported */
static int hci_read_local_codecs_sync(struct hci_dev *hdev)
{
- if (!(hdev->commands[29] & 0x20))
- return 0;
+ if (hdev->commands[45] & 0x04)
+ hci_read_supported_codecs_v2(hdev);
+ else if (hdev->commands[29] & 0x20)
+ hci_read_supported_codecs(hdev);
- return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
- HCI_CMD_TIMEOUT);
+ return 0;
}
/* Read local pairing options if the HCI command is supported */
@@ -4298,7 +4301,8 @@ static int hci_set_err_data_report_sync(struct hci_dev *hdev)
bool enabled = hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED);
if (!(hdev->commands[18] & 0x08) ||
- !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING))
+ !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING) ||
+ test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks))
return 0;
if (enabled == hdev->err_data_reporting)
@@ -4457,6 +4461,9 @@ static const struct {
HCI_QUIRK_BROKEN(STORED_LINK_KEY,
"HCI Delete Stored Link Key command is advertised, "
"but not supported."),
+ HCI_QUIRK_BROKEN(ERR_DATA_REPORTING,
+ "HCI Read Default Erroneous Data Reporting command is "
+ "advertised, but not supported."),
HCI_QUIRK_BROKEN(READ_TRANSMIT_POWER,
"HCI Read Transmit Power Level command is advertised, "
"but not supported."),
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index f825857db6d0..26db929b97c4 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -879,6 +879,7 @@ static int iso_listen_bis(struct sock *sk)
iso_pi(sk)->bc_sid);
hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
return err;
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9c24947aa41e..9fdede5fe71c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4453,7 +4453,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
chan->ident = cmd->ident;
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
- chan->num_conf_rsp++;
+ if (chan->num_conf_rsp < L2CAP_CONF_MAX_CONF_RSP)
+ chan->num_conf_rsp++;
/* Reset config buffer. */
chan->conf_len = 0;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a92e7e485feb..81ce668b0b77 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7373,9 +7373,8 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
/* To avoid client trying to guess when to poll again for information we
* calculate conn info age as random value between min/max set in hdev.
*/
- conn_info_age = hdev->conn_info_min_age +
- prandom_u32_max(hdev->conn_info_max_age -
- hdev->conn_info_min_age);
+ conn_info_age = get_random_u32_inclusive(hdev->conn_info_min_age,
+ hdev->conn_info_max_age - 1);
/* Query controller to refresh cached values if they are too old or were
* never read.
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 11f853d0500f..70663229b3cc 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -605,7 +605,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
memset(&msg, 0, sizeof(msg));
- iov_iter_kvec(&msg.msg_iter, WRITE, iv, 2, 1 + len);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iv, 2, 1 + len);
l2cap_chan_send(chan, &msg, 1 + len);
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 13d578ce2a09..fcb3e6c5e03c 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -774,6 +774,7 @@ static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
if (user_size > size)
return ERR_PTR(-EMSGSIZE);
+ size = SKB_DATA_ALIGN(size);
data = kzalloc(size + headroom + tailroom, GFP_USER);
if (!data)
return ERR_PTR(-ENOMEM);
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 6e53dc991409..9ffd40b8270c 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -959,6 +959,8 @@ int __br_vlan_set_proto(struct net_bridge *br, __be16 proto,
list_for_each_entry(p, &br->port_list, list) {
vg = nbp_vlan_group(p);
list_for_each_entry(vlan, &vg->vlan_list, vlist) {
+ if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
+ continue;
err = vlan_vid_add(p->dev, proto, vlan->vid);
if (err)
goto err_filt;
@@ -973,8 +975,11 @@ int __br_vlan_set_proto(struct net_bridge *br, __be16 proto,
/* Delete VLANs for the old proto from the device filter. */
list_for_each_entry(p, &br->port_list, list) {
vg = nbp_vlan_group(p);
- list_for_each_entry(vlan, &vg->vlan_list, vlist)
+ list_for_each_entry(vlan, &vg->vlan_list, vlist) {
+ if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
+ continue;
vlan_vid_del(p->dev, oldproto, vlan->vid);
+ }
}
return 0;
@@ -983,13 +988,19 @@ err_filt:
attr.u.vlan_protocol = ntohs(oldproto);
switchdev_port_attr_set(br->dev, &attr, NULL);
- list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist)
+ list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) {
+ if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
+ continue;
vlan_vid_del(p->dev, proto, vlan->vid);
+ }
list_for_each_entry_continue_reverse(p, &br->port_list, list) {
vg = nbp_vlan_group(p);
- list_for_each_entry(vlan, &vg->vlan_list, vlist)
+ list_for_each_entry(vlan, &vg->vlan_list, vlist) {
+ if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
+ continue;
vlan_vid_del(p->dev, proto, vlan->vid);
+ }
}
return err;
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 4d63ef13a1fd..f35fc87c453a 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -310,9 +310,6 @@ static int chnl_net_open(struct net_device *dev)
if (result == 0) {
pr_debug("connect timeout\n");
- caif_disconnect_client(dev_net(dev), &priv->chnl);
- priv->state = CAIF_DISCONNECTED;
- pr_debug("state disconnected\n");
result = -ETIMEDOUT;
goto error;
}
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 9503ab10f9b8..c69168f11e44 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -450,7 +450,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
/* insert new receiver (dev,canid,mask) -> (func,data) */
- if (dev && dev->type != ARPHRD_CAN)
+ if (dev && (dev->type != ARPHRD_CAN || !can_get_ml_priv(dev)))
return -ENODEV;
if (dev && !net_eq(net, dev_net(dev)))
@@ -677,7 +677,7 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- if (unlikely(dev->type != ARPHRD_CAN || (!can_is_can_skb(skb)))) {
+ if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_can_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@@ -692,7 +692,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canfd_skb(skb)))) {
+ if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canfd_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@@ -707,7 +707,7 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canxl_skb(skb)))) {
+ if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canxl_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@@ -902,6 +902,7 @@ out_pernet:
static __exit void can_exit(void)
{
/* protocol unregister */
+ dev_remove_pack(&canxl_packet);
dev_remove_pack(&canfd_packet);
dev_remove_pack(&can_packet);
sock_unregister(PF_CAN);
diff --git a/net/can/isotp.c b/net/can/isotp.c
index a9d1357f8489..608f8c24ae46 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -111,6 +111,9 @@ MODULE_ALIAS("can-proto-6");
#define ISOTP_FC_WT 1 /* wait */
#define ISOTP_FC_OVFLW 2 /* overflow */
+#define ISOTP_FC_TIMEOUT 1 /* 1 sec */
+#define ISOTP_ECHO_TIMEOUT 2 /* 2 secs */
+
enum {
ISOTP_IDLE = 0,
ISOTP_WAIT_FIRST_FC,
@@ -258,7 +261,8 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus)
so->lastrxcf_tstamp = ktime_set(0, 0);
/* start rx timeout watchdog */
- hrtimer_start(&so->rxtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
+ hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
+ HRTIMER_MODE_REL_SOFT);
return 0;
}
@@ -344,6 +348,8 @@ static int check_pad(struct isotp_sock *so, struct canfd_frame *cf,
return 0;
}
+static void isotp_send_cframe(struct isotp_sock *so);
+
static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
{
struct sock *sk = &so->sk;
@@ -398,14 +404,15 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
case ISOTP_FC_CTS:
so->tx.bs = 0;
so->tx.state = ISOTP_SENDING;
- /* start cyclic timer for sending CF frame */
- hrtimer_start(&so->txtimer, so->tx_gap,
+ /* send CF frame and enable echo timeout handling */
+ hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
+ isotp_send_cframe(so);
break;
case ISOTP_FC_WT:
/* start timer to wait for next FC frame */
- hrtimer_start(&so->txtimer, ktime_set(1, 0),
+ hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
break;
@@ -600,7 +607,7 @@ static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
/* perform blocksize handling, if enabled */
if (!so->rxfc.bs || ++so->rx.bs < so->rxfc.bs) {
/* start rx timeout watchdog */
- hrtimer_start(&so->rxtimer, ktime_set(1, 0),
+ hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
return 0;
}
@@ -829,7 +836,7 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
struct isotp_sock *so = isotp_sk(sk);
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
- /* only handle my own local echo skb's */
+ /* only handle my own local echo CF/SF skb's (no FF!) */
if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
return;
@@ -849,13 +856,16 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
if (so->txfc.bs && so->tx.bs >= so->txfc.bs) {
/* stop and wait for FC with timeout */
so->tx.state = ISOTP_WAIT_FC;
- hrtimer_start(&so->txtimer, ktime_set(1, 0),
+ hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
return;
}
/* no gap between data frames needed => use burst mode */
if (!so->tx_gap) {
+ /* enable echo timeout handling */
+ hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
+ HRTIMER_MODE_REL_SOFT);
isotp_send_cframe(so);
return;
}
@@ -879,7 +889,7 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
/* start timeout for unlikely lost echo skb */
hrtimer_set_expires(&so->txtimer,
ktime_add(ktime_get(),
- ktime_set(2, 0)));
+ ktime_set(ISOTP_ECHO_TIMEOUT, 0)));
restart = HRTIMER_RESTART;
/* push out the next consecutive frame */
@@ -907,7 +917,8 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "can-isotp: tx timer state %08X cfecho %08X\n",
+ so->tx.state, so->cfecho);
}
return restart;
@@ -923,7 +934,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
struct canfd_frame *cf;
int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0;
- s64 hrtimer_sec = 0;
+ s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT;
int off;
int err;
@@ -942,6 +953,8 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
if (err)
goto err_out;
+
+ so->tx.state = ISOTP_SENDING;
}
if (!size || size > MAX_MSG_LENGTH) {
@@ -986,6 +999,10 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
cf = (struct canfd_frame *)skb->data;
skb_put_zero(skb, so->ll.mtu);
+ /* cfecho should have been zero'ed by init / former isotp_rcv_echo() */
+ if (so->cfecho)
+ pr_notice_once("can-isotp: uninit cfecho %08X\n", so->cfecho);
+
/* check for single frame transmission depending on TX_DL */
if (size <= so->tx.ll_dl - SF_PCI_SZ4 - ae - off) {
/* The message size generally fits into a SingleFrame - good.
@@ -1011,11 +1028,8 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
else
cf->data[ae] |= size;
- so->tx.state = ISOTP_IDLE;
- wake_up_interruptible(&so->wait);
-
- /* don't enable wait queue for a single frame transmission */
- wait_tx_done = 0;
+ /* set CF echo tag for isotp_rcv_echo() (SF-mode) */
+ so->cfecho = *(u32 *)cf->data;
} else {
/* send first frame */
@@ -1031,31 +1045,23 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
/* disable wait for FCs due to activated block size */
so->txfc.bs = 0;
- /* cfecho should have been zero'ed by init */
- if (so->cfecho)
- pr_notice_once("can-isotp: no fc cfecho %08X\n",
- so->cfecho);
-
- /* set consecutive frame echo tag */
+ /* set CF echo tag for isotp_rcv_echo() (CF-mode) */
so->cfecho = *(u32 *)cf->data;
-
- /* switch directly to ISOTP_SENDING state */
- so->tx.state = ISOTP_SENDING;
-
- /* start timeout for unlikely lost echo skb */
- hrtimer_sec = 2;
} else {
/* standard flow control check */
so->tx.state = ISOTP_WAIT_FIRST_FC;
/* start timeout for FC */
- hrtimer_sec = 1;
- }
+ hrtimer_sec = ISOTP_FC_TIMEOUT;
- hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
- HRTIMER_MODE_REL_SOFT);
+ /* no CF echo tag for isotp_rcv_echo() (FF-mode) */
+ so->cfecho = 0;
+ }
}
+ hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
+ HRTIMER_MODE_REL_SOFT);
+
/* send the first or only CAN frame */
cf->flags = so->ll.tx_flags;
@@ -1068,8 +1074,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
__func__, ERR_PTR(err));
/* no transmission -> no timeout monitoring */
- if (hrtimer_sec)
- hrtimer_cancel(&so->txtimer);
+ hrtimer_cancel(&so->txtimer);
/* reset consecutive frame echo tag */
so->cfecho = 0;
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
index 144c86b0e3ff..821d4ff303b3 100644
--- a/net/can/j1939/main.c
+++ b/net/can/j1939/main.c
@@ -336,6 +336,9 @@ int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb)
/* re-claim the CAN_HDR from the SKB */
cf = skb_push(skb, J1939_CAN_HDR);
+ /* initialize header structure */
+ memset(cf, 0, J1939_CAN_HDR);
+
/* make it a full can frame again */
skb_put(skb, J1939_CAN_FTR + (8 - dlc));
diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
index b670ba03a675..7e90f9e61d9b 100644
--- a/net/can/j1939/socket.c
+++ b/net/can/j1939/socket.c
@@ -189,7 +189,7 @@ activate_next:
int time_ms = 0;
if (err)
- time_ms = 10 + prandom_u32_max(16);
+ time_ms = 10 + get_random_u32_below(16);
j1939_tp_schedule_txtimer(first, time_ms);
}
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 55f29c9f9e08..67d36776aff4 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -1168,7 +1168,7 @@ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
if (session->tx_retry < J1939_XTP_TX_RETRY_LIMIT) {
session->tx_retry++;
j1939_tp_schedule_txtimer(session,
- 10 + prandom_u32_max(16));
+ 10 + get_random_u32_below(16));
} else {
netdev_alert(priv->ndev, "%s: 0x%p: tx retry count reached\n",
__func__, session);
diff --git a/net/ceph/messenger_v1.c b/net/ceph/messenger_v1.c
index 3ddbde87e4d6..d1787d7d33ef 100644
--- a/net/ceph/messenger_v1.c
+++ b/net/ceph/messenger_v1.c
@@ -30,7 +30,7 @@ static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
if (!buf)
msg.msg_flags |= MSG_TRUNC;
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, len);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len);
r = sock_recvmsg(sock, &msg, msg.msg_flags);
if (r == -EAGAIN)
r = 0;
@@ -49,7 +49,7 @@ static int ceph_tcp_recvpage(struct socket *sock, struct page *page,
int r;
BUG_ON(page_offset + length > PAGE_SIZE);
- iov_iter_bvec(&msg.msg_iter, READ, &bvec, 1, length);
+ iov_iter_bvec(&msg.msg_iter, ITER_DEST, &bvec, 1, length);
r = sock_recvmsg(sock, &msg, msg.msg_flags);
if (r == -EAGAIN)
r = 0;
diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c
index cc8ff81a50b7..3009028c4fa2 100644
--- a/net/ceph/messenger_v2.c
+++ b/net/ceph/messenger_v2.c
@@ -168,7 +168,7 @@ static int do_try_sendpage(struct socket *sock, struct iov_iter *it)
bv.bv_offset, bv.bv_len,
CEPH_MSG_FLAGS);
} else {
- iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, bv.bv_len);
+ iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, bv.bv_len);
ret = sock_sendmsg(sock, &msg);
}
if (ret <= 0) {
@@ -225,7 +225,7 @@ static void reset_in_kvecs(struct ceph_connection *con)
WARN_ON(iov_iter_count(&con->v2.in_iter));
con->v2.in_kvec_cnt = 0;
- iov_iter_kvec(&con->v2.in_iter, READ, con->v2.in_kvecs, 0, 0);
+ iov_iter_kvec(&con->v2.in_iter, ITER_DEST, con->v2.in_kvecs, 0, 0);
}
static void set_in_bvec(struct ceph_connection *con, const struct bio_vec *bv)
@@ -233,7 +233,7 @@ static void set_in_bvec(struct ceph_connection *con, const struct bio_vec *bv)
WARN_ON(iov_iter_count(&con->v2.in_iter));
con->v2.in_bvec = *bv;
- iov_iter_bvec(&con->v2.in_iter, READ, &con->v2.in_bvec, 1, bv->bv_len);
+ iov_iter_bvec(&con->v2.in_iter, ITER_DEST, &con->v2.in_bvec, 1, bv->bv_len);
}
static void set_in_skip(struct ceph_connection *con, int len)
@@ -241,7 +241,7 @@ static void set_in_skip(struct ceph_connection *con, int len)
WARN_ON(iov_iter_count(&con->v2.in_iter));
dout("%s con %p len %d\n", __func__, con, len);
- iov_iter_discard(&con->v2.in_iter, READ, len);
+ iov_iter_discard(&con->v2.in_iter, ITER_DEST, len);
}
static void add_out_kvec(struct ceph_connection *con, void *buf, int len)
@@ -265,7 +265,7 @@ static void reset_out_kvecs(struct ceph_connection *con)
con->v2.out_kvec_cnt = 0;
- iov_iter_kvec(&con->v2.out_iter, WRITE, con->v2.out_kvecs, 0, 0);
+ iov_iter_kvec(&con->v2.out_iter, ITER_SOURCE, con->v2.out_kvecs, 0, 0);
con->v2.out_iter_sendpage = false;
}
@@ -277,7 +277,7 @@ static void set_out_bvec(struct ceph_connection *con, const struct bio_vec *bv,
con->v2.out_bvec = *bv;
con->v2.out_iter_sendpage = zerocopy;
- iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1,
+ iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
con->v2.out_bvec.bv_len);
}
@@ -290,7 +290,7 @@ static void set_out_bvec_zero(struct ceph_connection *con)
con->v2.out_bvec.bv_offset = 0;
con->v2.out_bvec.bv_len = min(con->v2.out_zero, (int)PAGE_SIZE);
con->v2.out_iter_sendpage = true;
- iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1,
+ iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
con->v2.out_bvec.bv_len);
}
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index db60217f911b..faabad6603db 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -222,7 +222,7 @@ static void pick_new_mon(struct ceph_mon_client *monc)
max--;
}
- n = prandom_u32_max(max);
+ n = get_random_u32_below(max);
if (o >= 0 && n >= o)
n++;
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 4e4f1e4bc265..11c04e7d928e 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -1479,7 +1479,7 @@ static bool target_should_be_paused(struct ceph_osd_client *osdc,
static int pick_random_replica(const struct ceph_osds *acting)
{
- int i = prandom_u32_max(acting->size);
+ int i = get_random_u32_below(acting->size);
dout("%s picked osd%d, primary osd%d\n", __func__,
acting->osds[i], acting->primary);
diff --git a/net/compat.c b/net/compat.c
index 385f04a6be2f..161b7bea1f62 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -95,7 +95,8 @@ int get_compat_msghdr(struct msghdr *kmsg,
if (err)
return err;
- err = import_iovec(save_addr ? READ : WRITE, compat_ptr(msg.msg_iov), msg.msg_iovlen,
+ err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE,
+ compat_ptr(msg.msg_iov), msg.msg_iovlen,
UIO_FASTIOV, iov, &kmsg->msg_iter);
return err < 0 ? err : 0;
}
diff --git a/net/core/dev_addr_lists_test.c b/net/core/dev_addr_lists_test.c
index 049cfbc58aa9..90e7e3811ae7 100644
--- a/net/core/dev_addr_lists_test.c
+++ b/net/core/dev_addr_lists_test.c
@@ -71,11 +71,11 @@ static void dev_addr_test_basic(struct kunit *test)
memset(addr, 2, sizeof(addr));
eth_hw_addr_set(netdev, addr);
- KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
+ KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
memset(addr, 3, sizeof(addr));
dev_addr_set(netdev, addr);
- KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
+ KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
}
static void dev_addr_test_sync_one(struct kunit *test)
diff --git a/net/core/dst.c b/net/core/dst.c
index bc9c9be4e080..a4e738d321ba 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -174,7 +174,7 @@ void dst_release(struct dst_entry *dst)
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
__func__, dst, newrefcnt);
if (!newrefcnt)
- call_rcu(&dst->rcu_head, dst_destroy_rcu);
+ call_rcu_hurry(&dst->rcu_head, dst_destroy_rcu);
}
}
EXPORT_SYMBOL(dst_release);
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 25cd35f5922e..007730412947 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -296,7 +296,7 @@ skb_flow_dissect_ct(const struct sk_buff *skb,
key->ct_zone = ct->zone.id;
#endif
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
- key->ct_mark = ct->mark;
+ key->ct_mark = READ_ONCE(ct->mark);
#endif
cl = nf_ct_labels_find(ct);
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index 6fac2f0ef074..711cd3b4347a 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -48,9 +48,11 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
return "RPL";
case LWTUNNEL_ENCAP_IOAM6:
return "IOAM6";
+ case LWTUNNEL_ENCAP_XFRM:
+ /* module autoload not supported for encap type */
+ return NULL;
case LWTUNNEL_ENCAP_IP6:
case LWTUNNEL_ENCAP_IP:
- case LWTUNNEL_ENCAP_XFRM:
case LWTUNNEL_ENCAP_NONE:
case __LWTUNNEL_ENCAP_MAX:
/* should not have got here */
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index a77a85e357e0..f00a79fc301b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -111,7 +111,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh)
unsigned long neigh_rand_reach_time(unsigned long base)
{
- return base ? prandom_u32_max(base) + (base >> 1) : 0;
+ return base ? get_random_u32_below(base) + (base >> 1) : 0;
}
EXPORT_SYMBOL(neigh_rand_reach_time);
@@ -307,7 +307,31 @@ static int neigh_del_timer(struct neighbour *n)
return 0;
}
-static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
+static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
+ int family)
+{
+ switch (family) {
+ case AF_INET:
+ return __in_dev_arp_parms_get_rcu(dev);
+ case AF_INET6:
+ return __in6_dev_nd_parms_get_rcu(dev);
+ }
+ return NULL;
+}
+
+static void neigh_parms_qlen_dec(struct net_device *dev, int family)
+{
+ struct neigh_parms *p;
+
+ rcu_read_lock();
+ p = neigh_get_dev_parms_rcu(dev, family);
+ if (p)
+ p->qlen--;
+ rcu_read_unlock();
+}
+
+static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
+ int family)
{
struct sk_buff_head tmp;
unsigned long flags;
@@ -321,13 +345,7 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
struct net_device *dev = skb->dev;
if (net == NULL || net_eq(dev_net(dev), net)) {
- struct in_device *in_dev;
-
- rcu_read_lock();
- in_dev = __in_dev_get_rcu(dev);
- if (in_dev)
- in_dev->arp_parms->qlen--;
- rcu_read_unlock();
+ neigh_parms_qlen_dec(dev, family);
__skb_unlink(skb, list);
__skb_queue_tail(&tmp, skb);
}
@@ -409,7 +427,8 @@ static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
write_lock_bh(&tbl->lock);
neigh_flush_dev(tbl, dev, skip_perm);
pneigh_ifdown_and_unlock(tbl, dev);
- pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL);
+ pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
+ tbl->family);
if (skb_queue_empty_lockless(&tbl->proxy_queue))
del_timer_sync(&tbl->proxy_timer);
return 0;
@@ -1621,13 +1640,8 @@ static void neigh_proxy_process(struct timer_list *t)
if (tdif <= 0) {
struct net_device *dev = skb->dev;
- struct in_device *in_dev;
- rcu_read_lock();
- in_dev = __in_dev_get_rcu(dev);
- if (in_dev)
- in_dev->arp_parms->qlen--;
- rcu_read_unlock();
+ neigh_parms_qlen_dec(dev, tbl->family);
__skb_unlink(skb, &tbl->proxy_queue);
if (tbl->proxy_redo && netif_running(dev)) {
@@ -1652,7 +1666,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
struct sk_buff *skb)
{
unsigned long sched_next = jiffies +
- prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
+ get_random_u32_below(NEIGH_VAR(p, PROXY_DELAY));
if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
kfree_skb(skb);
@@ -1821,7 +1835,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl)
cancel_delayed_work_sync(&tbl->managed_work);
cancel_delayed_work_sync(&tbl->gc_work);
del_timer_sync(&tbl->proxy_timer);
- pneigh_queue_purge(&tbl->proxy_queue, NULL);
+ pneigh_queue_purge(&tbl->proxy_queue, NULL, tbl->family);
neigh_ifdown(tbl, NULL);
if (atomic_read(&tbl->entries))
pr_crit("neighbour leakage\n");
@@ -3539,18 +3553,6 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write,
return ret;
}
-static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
- int family)
-{
- switch (family) {
- case AF_INET:
- return __in_dev_arp_parms_get_rcu(dev);
- case AF_INET6:
- return __in6_dev_nd_parms_get_rcu(dev);
- }
- return NULL;
-}
-
static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
int index)
{
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index c3763056c554..760238196db1 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2324,7 +2324,7 @@ static inline int f_pick(struct pktgen_dev *pkt_dev)
pkt_dev->curfl = 0; /*reset */
}
} else {
- flow = prandom_u32_max(pkt_dev->cflows);
+ flow = get_random_u32_below(pkt_dev->cflows);
pkt_dev->curfl = flow;
if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
@@ -2380,9 +2380,8 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
__u16 t;
if (pkt_dev->flags & F_QUEUE_MAP_RND) {
- t = prandom_u32_max(pkt_dev->queue_map_max -
- pkt_dev->queue_map_min + 1) +
- pkt_dev->queue_map_min;
+ t = get_random_u32_inclusive(pkt_dev->queue_map_min,
+ pkt_dev->queue_map_max);
} else {
t = pkt_dev->cur_queue_map + 1;
if (t > pkt_dev->queue_map_max)
@@ -2411,7 +2410,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__u32 tmp;
if (pkt_dev->flags & F_MACSRC_RND)
- mc = prandom_u32_max(pkt_dev->src_mac_count);
+ mc = get_random_u32_below(pkt_dev->src_mac_count);
else {
mc = pkt_dev->cur_src_mac_offset++;
if (pkt_dev->cur_src_mac_offset >=
@@ -2437,7 +2436,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__u32 tmp;
if (pkt_dev->flags & F_MACDST_RND)
- mc = prandom_u32_max(pkt_dev->dst_mac_count);
+ mc = get_random_u32_below(pkt_dev->dst_mac_count);
else {
mc = pkt_dev->cur_dst_mac_offset++;
@@ -2469,18 +2468,17 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
}
if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
- pkt_dev->vlan_id = prandom_u32_max(4096);
+ pkt_dev->vlan_id = get_random_u32_below(4096);
}
if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
- pkt_dev->svlan_id = prandom_u32_max(4096);
+ pkt_dev->svlan_id = get_random_u32_below(4096);
}
if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
if (pkt_dev->flags & F_UDPSRC_RND)
- pkt_dev->cur_udp_src = prandom_u32_max(
- pkt_dev->udp_src_max - pkt_dev->udp_src_min) +
- pkt_dev->udp_src_min;
+ pkt_dev->cur_udp_src = get_random_u32_inclusive(pkt_dev->udp_src_min,
+ pkt_dev->udp_src_max - 1);
else {
pkt_dev->cur_udp_src++;
@@ -2491,9 +2489,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
if (pkt_dev->flags & F_UDPDST_RND) {
- pkt_dev->cur_udp_dst = prandom_u32_max(
- pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) +
- pkt_dev->udp_dst_min;
+ pkt_dev->cur_udp_dst = get_random_u32_inclusive(pkt_dev->udp_dst_min,
+ pkt_dev->udp_dst_max - 1);
} else {
pkt_dev->cur_udp_dst++;
if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
@@ -2508,7 +2505,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (imn < imx) {
__u32 t;
if (pkt_dev->flags & F_IPSRC_RND)
- t = prandom_u32_max(imx - imn) + imn;
+ t = get_random_u32_inclusive(imn, imx - 1);
else {
t = ntohl(pkt_dev->cur_saddr);
t++;
@@ -2530,8 +2527,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (pkt_dev->flags & F_IPDST_RND) {
do {
- t = prandom_u32_max(imx - imn) +
- imn;
+ t = get_random_u32_inclusive(imn, imx - 1);
s = htonl(t);
} while (ipv4_is_loopback(s) ||
ipv4_is_multicast(s) ||
@@ -2578,9 +2574,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
__u32 t;
if (pkt_dev->flags & F_TXSIZE_RND) {
- t = prandom_u32_max(pkt_dev->max_pkt_size -
- pkt_dev->min_pkt_size) +
- pkt_dev->min_pkt_size;
+ t = get_random_u32_inclusive(pkt_dev->min_pkt_size,
+ pkt_dev->max_pkt_size - 1);
} else {
t = pkt_dev->cur_pkt_size + 1;
if (t > pkt_dev->max_pkt_size)
@@ -2589,7 +2584,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->cur_pkt_size = t;
} else if (pkt_dev->n_imix_entries > 0) {
struct imix_pkt *entry;
- __u32 t = prandom_u32_max(IMIX_PRECISION);
+ __u32 t = get_random_u32_below(IMIX_PRECISION);
__u8 entry_index = pkt_dev->imix_distribution[t];
entry = &pkt_dev->imix_entries[entry_index];
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d1a3fa6f3f12..88fa40571d0c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4134,23 +4134,25 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
int i = 0;
int pos;
- if (list_skb && !list_skb->head_frag && skb_headlen(list_skb) &&
- (skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY)) {
- /* gso_size is untrusted, and we have a frag_list with a linear
- * non head_frag head.
- *
- * (we assume checking the first list_skb member suffices;
- * i.e if either of the list_skb members have non head_frag
- * head, then the first one has too).
- *
- * If head_skb's headlen does not fit requested gso_size, it
- * means that the frag_list members do NOT terminate on exact
- * gso_size boundaries. Hence we cannot perform skb_frag_t page
- * sharing. Therefore we must fallback to copying the frag_list
- * skbs; we do so by disabling SG.
- */
- if (mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb))
- features &= ~NETIF_F_SG;
+ if ((skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY) &&
+ mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) {
+ struct sk_buff *check_skb;
+
+ for (check_skb = list_skb; check_skb; check_skb = check_skb->next) {
+ if (skb_headlen(check_skb) && !check_skb->head_frag) {
+ /* gso_size is untrusted, and we have a frag_list with
+ * a linear non head_frag item.
+ *
+ * If head_skb's headlen does not fit requested gso_size,
+ * it means that the frag_list members do NOT terminate
+ * on exact gso_size boundaries. Hence we cannot perform
+ * skb_frag_t page sharing. Therefore we must fallback to
+ * copying the frag_list skbs; we do so by disabling SG.
+ */
+ features &= ~NETIF_F_SG;
+ break;
+ }
+ }
}
__skb_push(head_skb, doffset);
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
index 1efdc47a999b..e6b9ced3eda8 100644
--- a/net/core/skmsg.c
+++ b/net/core/skmsg.c
@@ -803,16 +803,13 @@ static void sk_psock_link_destroy(struct sk_psock *psock)
}
}
-void sk_psock_stop(struct sk_psock *psock, bool wait)
+void sk_psock_stop(struct sk_psock *psock)
{
spin_lock_bh(&psock->ingress_lock);
sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
sk_psock_cork_free(psock);
__sk_psock_zap_ingress(psock);
spin_unlock_bh(&psock->ingress_lock);
-
- if (wait)
- cancel_work_sync(&psock->work);
}
static void sk_psock_done_strp(struct sk_psock *psock);
@@ -850,7 +847,7 @@ void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
sk_psock_stop_verdict(sk, psock);
write_unlock_bh(&sk->sk_callback_lock);
- sk_psock_stop(psock, false);
+ sk_psock_stop(psock);
INIT_RCU_WORK(&psock->rwork, sk_psock_destroy);
queue_rcu_work(system_wq, &psock->rwork);
diff --git a/net/core/sock.c b/net/core/sock.c
index a3ba0358c77c..c9c6af85d9c0 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1793,7 +1793,8 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
break;
case SO_PEERSEC:
- return security_socket_getpeersec_stream(sock, optval.user, optlen.user, len);
+ return security_socket_getpeersec_stream(sock,
+ optval, optlen, len);
case SO_MARK:
v.val = sk->sk_mark;
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index a660baedd9e7..81beb16ab1eb 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1596,7 +1596,7 @@ void sock_map_destroy(struct sock *sk)
saved_destroy = psock->saved_destroy;
sock_map_remove_links(sk, psock);
rcu_read_unlock();
- sk_psock_stop(psock, false);
+ sk_psock_stop(psock);
sk_psock_put(sk, psock);
saved_destroy(sk);
}
@@ -1619,9 +1619,10 @@ void sock_map_close(struct sock *sk, long timeout)
saved_close = psock->saved_close;
sock_map_remove_links(sk, psock);
rcu_read_unlock();
- sk_psock_stop(psock, true);
- sk_psock_put(sk, psock);
+ sk_psock_stop(psock);
release_sock(sk);
+ cancel_work_sync(&psock->work);
+ sk_psock_put(sk, psock);
saved_close(sk, timeout);
}
EXPORT_SYMBOL_GPL(sock_map_close);
diff --git a/net/core/stream.c b/net/core/stream.c
index 75fded8495f5..5b1fe2b82eac 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -123,7 +123,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
DEFINE_WAIT_FUNC(wait, woken_wake_function);
if (sk_stream_memory_free(sk))
- current_timeo = vm_wait = prandom_u32_max(HZ / 5) + 2;
+ current_timeo = vm_wait = get_random_u32_below(HZ / 5) + 2;
add_wait_queue(sk_sleep(sk), &wait);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 713b7b8dad7e..b780827f5e0a 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -45,11 +45,10 @@ static unsigned int dccp_v4_pernet_id __read_mostly;
int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
- struct inet_bind_hashbucket *prev_addr_hashbucket = NULL;
- __be32 daddr, nexthop, prev_sk_rcv_saddr;
struct inet_sock *inet = inet_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
__be16 orig_sport, orig_dport;
+ __be32 daddr, nexthop;
struct flowi4 *fl4;
struct rtable *rt;
int err;
@@ -91,26 +90,13 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
daddr = fl4->daddr;
if (inet->inet_saddr == 0) {
- if (inet_csk(sk)->icsk_bind2_hash) {
- prev_addr_hashbucket =
- inet_bhashfn_portaddr(&dccp_hashinfo, sk,
- sock_net(sk),
- inet->inet_num);
- prev_sk_rcv_saddr = sk->sk_rcv_saddr;
- }
- inet->inet_saddr = fl4->saddr;
- }
-
- sk_rcv_saddr_set(sk, inet->inet_saddr);
-
- if (prev_addr_hashbucket) {
- err = inet_bhash2_update_saddr(prev_addr_hashbucket, sk);
+ err = inet_bhash2_update_saddr(sk, &fl4->saddr, AF_INET);
if (err) {
- inet->inet_saddr = 0;
- sk_rcv_saddr_set(sk, prev_sk_rcv_saddr);
ip_rt_put(rt);
return err;
}
+ } else {
+ sk_rcv_saddr_set(sk, inet->inet_saddr);
}
inet->inet_dport = usin->sin_port;
@@ -157,6 +143,7 @@ failure:
* This unhashes the socket and releases the local port, if necessary.
*/
dccp_set_state(sk, DCCP_CLOSED);
+ inet_bhash2_reset_saddr(sk);
ip_rt_put(rt);
sk->sk_route_caps = 0;
inet->inet_dport = 0;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index e57b43006074..602f3432d80b 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -934,26 +934,11 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
}
if (saddr == NULL) {
- struct inet_bind_hashbucket *prev_addr_hashbucket = NULL;
- struct in6_addr prev_v6_rcv_saddr;
-
- if (icsk->icsk_bind2_hash) {
- prev_addr_hashbucket = inet_bhashfn_portaddr(&dccp_hashinfo,
- sk, sock_net(sk),
- inet->inet_num);
- prev_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
- }
-
saddr = &fl6.saddr;
- sk->sk_v6_rcv_saddr = *saddr;
-
- if (prev_addr_hashbucket) {
- err = inet_bhash2_update_saddr(prev_addr_hashbucket, sk);
- if (err) {
- sk->sk_v6_rcv_saddr = prev_v6_rcv_saddr;
- goto failure;
- }
- }
+
+ err = inet_bhash2_update_saddr(sk, saddr, AF_INET6);
+ if (err)
+ goto failure;
}
/* set the source address */
@@ -985,6 +970,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
late_failure:
dccp_set_state(sk, DCCP_CLOSED);
+ inet_bhash2_reset_saddr(sk);
__sk_dst_reset(sk);
failure:
inet->inet_dport = 0;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index c548ca3e9b0e..85e35c5e8890 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -279,8 +279,7 @@ int dccp_disconnect(struct sock *sk, int flags)
inet->inet_dport = 0;
- if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
- inet_reset_saddr(sk);
+ inet_bhash2_reset_saddr(sk);
sk->sk_shutdown = 0;
sock_reset_flag(sk, SOCK_DONE);
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index e504a18fc125..5417f7b1187c 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -864,6 +864,14 @@ disconnect:
return err;
}
+static void dsa_switch_teardown_tag_protocol(struct dsa_switch *ds)
+{
+ const struct dsa_device_ops *tag_ops = ds->dst->tag_ops;
+
+ if (tag_ops->disconnect)
+ tag_ops->disconnect(ds);
+}
+
static int dsa_switch_setup(struct dsa_switch *ds)
{
struct dsa_devlink_priv *dl_priv;
@@ -953,6 +961,8 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
ds->slave_mii_bus = NULL;
}
+ dsa_switch_teardown_tag_protocol(ds);
+
if (ds->ops->teardown)
ds->ops->teardown(ds);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 6e65c7ffd6f3..71e9707d11d4 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -210,6 +210,7 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
extern struct rtnl_link_ops dsa_link_ops __read_mostly;
/* port.c */
+bool dsa_port_supports_hwtstamp(struct dsa_port *dp, struct ifreq *ifr);
void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
const struct dsa_device_ops *tag_ops);
int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age);
diff --git a/net/dsa/master.c b/net/dsa/master.c
index 40367ab41cf8..421de166515f 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -204,8 +204,7 @@ static int dsa_master_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
* switch in the tree that is PTP capable.
*/
list_for_each_entry(dp, &dst->ports, list)
- if (dp->ds->ops->port_hwtstamp_get ||
- dp->ds->ops->port_hwtstamp_set)
+ if (dsa_port_supports_hwtstamp(dp, ifr))
return -EBUSY;
break;
}
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 208168276995..750fe68d9b2a 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -110,6 +110,22 @@ static bool dsa_port_can_configure_learning(struct dsa_port *dp)
return !err;
}
+bool dsa_port_supports_hwtstamp(struct dsa_port *dp, struct ifreq *ifr)
+{
+ struct dsa_switch *ds = dp->ds;
+ int err;
+
+ if (!ds->ops->port_hwtstamp_get || !ds->ops->port_hwtstamp_set)
+ return false;
+
+ /* "See through" shim implementations of the "get" method.
+ * This will clobber the ifreq structure, but we will either return an
+ * error, or the master will overwrite it with proper values.
+ */
+ err = ds->ops->port_hwtstamp_get(ds, dp->index, ifr);
+ return err != -EOPNOTSUPP;
+}
+
int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
{
struct dsa_switch *ds = dp->ds;
diff --git a/net/dsa/tag_hellcreek.c b/net/dsa/tag_hellcreek.c
index 846588c0070a..53a206d11685 100644
--- a/net/dsa/tag_hellcreek.c
+++ b/net/dsa/tag_hellcreek.c
@@ -49,7 +49,8 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb,
return NULL;
}
- pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN);
+ if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN))
+ return NULL;
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index 38fa19c1e2d5..429250298ac4 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -21,7 +21,8 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
if (!skb->dev)
return NULL;
- pskb_trim_rcsum(skb, skb->len - len);
+ if (pskb_trim_rcsum(skb, skb->len - len))
+ return NULL;
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index 83e4136516b0..1a85125bda6d 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -665,7 +665,8 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
* padding and trailer we need to account for the fact that
* skb->data points to skb_mac_header(skb) + ETH_HLEN.
*/
- pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN);
+ if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN))
+ return NULL;
/* Trap-to-host frame, no timestamp trailer */
} else {
*source_port = SJA1110_RX_HEADER_SRC_PORT(rx_header);
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index a50429a62f74..56bb27d67a2e 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -351,17 +351,18 @@ static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev,
struct hsr_node *node_src)
{
bool was_multicast_frame;
- int res;
+ int res, recv_len;
was_multicast_frame = (skb->pkt_type == PACKET_MULTICAST);
hsr_addr_subst_source(node_src, skb);
skb_pull(skb, ETH_HLEN);
+ recv_len = skb->len;
res = netif_rx(skb);
if (res == NET_RX_DROP) {
dev->stats.rx_dropped++;
} else {
dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += recv_len;
if (was_multicast_frame)
dev->stats.multicast++;
}
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index e983bb0c5012..2dfb12230f08 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -402,6 +402,16 @@ config INET_IPCOMP
If unsure, say Y.
+config INET_TABLE_PERTURB_ORDER
+ int "INET: Source port perturbation table size (as power of 2)" if EXPERT
+ default 16
+ help
+ Source port perturbation table size (as power of 2) for
+ RFC 6056 3.3.4. Algorithm 4: Double-Hash Port Selection Algorithm.
+
+ The default is almost always what you want.
+ Only change this if you know what you are doing.
+
config INET_XFRM_TUNNEL
tristate
select INET_TUNNEL
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 4728087c42a5..0da679411330 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1230,7 +1230,6 @@ EXPORT_SYMBOL(inet_unregister_protosw);
static int inet_sk_reselect_saddr(struct sock *sk)
{
- struct inet_bind_hashbucket *prev_addr_hashbucket;
struct inet_sock *inet = inet_sk(sk);
__be32 old_saddr = inet->inet_saddr;
__be32 daddr = inet->inet_daddr;
@@ -1260,16 +1259,8 @@ static int inet_sk_reselect_saddr(struct sock *sk)
return 0;
}
- prev_addr_hashbucket =
- inet_bhashfn_portaddr(tcp_or_dccp_get_hashinfo(sk), sk,
- sock_net(sk), inet->inet_num);
-
- inet->inet_saddr = inet->inet_rcv_saddr = new_saddr;
-
- err = inet_bhash2_update_saddr(prev_addr_hashbucket, sk);
+ err = inet_bhash2_update_saddr(sk, &new_saddr, AF_INET);
if (err) {
- inet->inet_saddr = old_saddr;
- inet->inet_rcv_saddr = old_saddr;
ip_rt_put(rt);
return err;
}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index e8b9a9202fec..b0acf6e19aed 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -234,13 +234,20 @@ static void inet_free_ifa(struct in_ifaddr *ifa)
call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
}
+static void in_dev_free_rcu(struct rcu_head *head)
+{
+ struct in_device *idev = container_of(head, struct in_device, rcu_head);
+
+ kfree(rcu_dereference_protected(idev->mc_hash, 1));
+ kfree(idev);
+}
+
void in_dev_finish_destroy(struct in_device *idev)
{
struct net_device *dev = idev->dev;
WARN_ON(idev->ifa_list);
WARN_ON(idev->mc_list);
- kfree(rcu_dereference_protected(idev->mc_hash, 1));
#ifdef NET_REFCNT_DEBUG
pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
#endif
@@ -248,7 +255,7 @@ void in_dev_finish_destroy(struct in_device *idev)
if (!idev->dead)
pr_err("Freeing alive in_device %p\n", idev);
else
- kfree(idev);
+ call_rcu(&idev->rcu_head, in_dev_free_rcu);
}
EXPORT_SYMBOL(in_dev_finish_destroy);
@@ -298,12 +305,6 @@ out_kfree:
goto out;
}
-static void in_dev_rcu_put(struct rcu_head *head)
-{
- struct in_device *idev = container_of(head, struct in_device, rcu_head);
- in_dev_put(idev);
-}
-
static void inetdev_destroy(struct in_device *in_dev)
{
struct net_device *dev;
@@ -328,7 +329,7 @@ static void inetdev_destroy(struct in_device *in_dev)
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
arp_ifdown(dev);
- call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
+ in_dev_put(in_dev);
}
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c
index 170152772d33..3969fa805679 100644
--- a/net/ipv4/esp4_offload.c
+++ b/net/ipv4/esp4_offload.c
@@ -314,6 +314,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
xo->seq.low += skb_shinfo(skb)->gso_segs;
}
+ if (xo->seq.low < seq)
+ xo->seq.hi++;
+
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
ip_hdr(skb)->tot_len = htons(skb->len);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index f361d3d56be2..b5736ef16ed2 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -841,6 +841,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
return -EINVAL;
}
+ if (!cfg->fc_table)
+ cfg->fc_table = RT_TABLE_MAIN;
+
return 0;
errout:
return err;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index f721c308248b..ce9ff3c62e84 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -423,6 +423,7 @@ static struct fib_info *fib_find_info(struct fib_info *nfi)
nfi->fib_prefsrc == fi->fib_prefsrc &&
nfi->fib_priority == fi->fib_priority &&
nfi->fib_type == fi->fib_type &&
+ nfi->fib_tb_id == fi->fib_tb_id &&
memcmp(nfi->fib_metrics, fi->fib_metrics,
sizeof(u32) * RTAX_MAX) == 0 &&
!((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) &&
@@ -888,9 +889,11 @@ int fib_nh_match(struct net *net, struct fib_config *cfg, struct fib_info *fi,
return 1;
}
- /* cannot match on nexthop object attributes */
- if (fi->nh)
- return 1;
+ if (fi->nh) {
+ if (cfg->fc_oif || cfg->fc_gw_family || cfg->fc_mp)
+ return 1;
+ return 0;
+ }
if (cfg->fc_oif || cfg->fc_gw_family) {
struct fib_nh *nh;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 452ff177e4da..74d403dbd2b4 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -126,7 +126,7 @@ struct key_vector {
/* This list pointer if valid if (pos | bits) == 0 (LEAF) */
struct hlist_head leaf;
/* This array is valid if (pos | bits) > 0 (TNODE) */
- struct key_vector __rcu *tnode[0];
+ DECLARE_FLEX_ARRAY(struct key_vector __rcu *, tnode);
};
};
@@ -1381,8 +1381,10 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
/* The alias was already inserted, so the node must exist. */
l = l ? l : fib_find_node(t, &tp, key);
- if (WARN_ON_ONCE(!l))
+ if (WARN_ON_ONCE(!l)) {
+ err = -ENOENT;
goto out_free_new_fa;
+ }
if (fib_find_alias(&l->leaf, new_fa->fa_slen, 0, 0, tb->tb_id, true) ==
new_fa) {
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index d5d745c3e345..46aa2d65e40a 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -263,7 +263,7 @@ bool icmp_global_allow(void)
/* We want to use a credit of one in average, but need to randomize
* it for security reasons.
*/
- credit = max_t(int, credit - prandom_u32_max(3), 0);
+ credit = max_t(int, credit - get_random_u32_below(3), 0);
rc = true;
}
WRITE_ONCE(icmp_global.credit, credit);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 81be3e0f0e70..c920aa9a62a9 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -213,7 +213,7 @@ static void igmp_stop_timer(struct ip_mc_list *im)
/* It must be called with locked im->lock */
static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
{
- int tv = prandom_u32_max(max_delay);
+ int tv = get_random_u32_below(max_delay);
im->tm_running = 1;
if (!mod_timer(&im->timer, jiffies+tv+2))
@@ -222,7 +222,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
static void igmp_gq_start_timer(struct in_device *in_dev)
{
- int tv = prandom_u32_max(in_dev->mr_maxdelay);
+ int tv = get_random_u32_below(in_dev->mr_maxdelay);
unsigned long exp = jiffies + tv + 2;
if (in_dev->mr_gq_running &&
@@ -236,7 +236,7 @@ static void igmp_gq_start_timer(struct in_device *in_dev)
static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
{
- int tv = prandom_u32_max(delay);
+ int tv = get_random_u32_below(delay);
if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2))
in_dev_hold(in_dev);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 4e84ed21d16f..f22051219b50 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -314,7 +314,7 @@ other_half_scan:
if (likely(remaining > 1))
remaining &= ~1U;
- offset = prandom_u32_max(remaining);
+ offset = get_random_u32_below(remaining);
/* __inet_hash_connect() favors ports having @low parity
* We do the opposite to not pollute connect() users.
*/
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index d3dc28156622..d039b4e732a3 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -858,34 +858,80 @@ inet_bhash2_addr_any_hashbucket(const struct sock *sk, const struct net *net, in
return &hinfo->bhash2[hash & (hinfo->bhash_size - 1)];
}
-int inet_bhash2_update_saddr(struct inet_bind_hashbucket *prev_saddr, struct sock *sk)
+static void inet_update_saddr(struct sock *sk, void *saddr, int family)
+{
+ if (family == AF_INET) {
+ inet_sk(sk)->inet_saddr = *(__be32 *)saddr;
+ sk_rcv_saddr_set(sk, inet_sk(sk)->inet_saddr);
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ else {
+ sk->sk_v6_rcv_saddr = *(struct in6_addr *)saddr;
+ }
+#endif
+}
+
+static int __inet_bhash2_update_saddr(struct sock *sk, void *saddr, int family, bool reset)
{
struct inet_hashinfo *hinfo = tcp_or_dccp_get_hashinfo(sk);
+ struct inet_bind_hashbucket *head, *head2;
struct inet_bind2_bucket *tb2, *new_tb2;
int l3mdev = inet_sk_bound_l3mdev(sk);
- struct inet_bind_hashbucket *head2;
int port = inet_sk(sk)->inet_num;
struct net *net = sock_net(sk);
+ int bhash;
+
+ if (!inet_csk(sk)->icsk_bind2_hash) {
+ /* Not bind()ed before. */
+ if (reset)
+ inet_reset_saddr(sk);
+ else
+ inet_update_saddr(sk, saddr, family);
+
+ return 0;
+ }
/* Allocate a bind2 bucket ahead of time to avoid permanently putting
* the bhash2 table in an inconsistent state if a new tb2 bucket
* allocation fails.
*/
new_tb2 = kmem_cache_alloc(hinfo->bind2_bucket_cachep, GFP_ATOMIC);
- if (!new_tb2)
+ if (!new_tb2) {
+ if (reset) {
+ /* The (INADDR_ANY, port) bucket might have already
+ * been freed, then we cannot fixup icsk_bind2_hash,
+ * so we give up and unlink sk from bhash/bhash2 not
+ * to leave inconsistency in bhash2.
+ */
+ inet_put_port(sk);
+ inet_reset_saddr(sk);
+ }
+
return -ENOMEM;
+ }
+ bhash = inet_bhashfn(net, port, hinfo->bhash_size);
+ head = &hinfo->bhash[bhash];
head2 = inet_bhashfn_portaddr(hinfo, sk, net, port);
- if (prev_saddr) {
- spin_lock_bh(&prev_saddr->lock);
- __sk_del_bind2_node(sk);
- inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep,
- inet_csk(sk)->icsk_bind2_hash);
- spin_unlock_bh(&prev_saddr->lock);
- }
+ /* If we change saddr locklessly, another thread
+ * iterating over bhash might see corrupted address.
+ */
+ spin_lock_bh(&head->lock);
- spin_lock_bh(&head2->lock);
+ spin_lock(&head2->lock);
+ __sk_del_bind2_node(sk);
+ inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep, inet_csk(sk)->icsk_bind2_hash);
+ spin_unlock(&head2->lock);
+
+ if (reset)
+ inet_reset_saddr(sk);
+ else
+ inet_update_saddr(sk, saddr, family);
+
+ head2 = inet_bhashfn_portaddr(hinfo, sk, net, port);
+
+ spin_lock(&head2->lock);
tb2 = inet_bind2_bucket_find(head2, net, port, l3mdev, sk);
if (!tb2) {
tb2 = new_tb2;
@@ -893,26 +939,40 @@ int inet_bhash2_update_saddr(struct inet_bind_hashbucket *prev_saddr, struct soc
}
sk_add_bind2_node(sk, &tb2->owners);
inet_csk(sk)->icsk_bind2_hash = tb2;
- spin_unlock_bh(&head2->lock);
+ spin_unlock(&head2->lock);
+
+ spin_unlock_bh(&head->lock);
if (tb2 != new_tb2)
kmem_cache_free(hinfo->bind2_bucket_cachep, new_tb2);
return 0;
}
+
+int inet_bhash2_update_saddr(struct sock *sk, void *saddr, int family)
+{
+ return __inet_bhash2_update_saddr(sk, saddr, family, false);
+}
EXPORT_SYMBOL_GPL(inet_bhash2_update_saddr);
+void inet_bhash2_reset_saddr(struct sock *sk)
+{
+ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
+ __inet_bhash2_update_saddr(sk, NULL, 0, true);
+}
+EXPORT_SYMBOL_GPL(inet_bhash2_reset_saddr);
+
/* RFC 6056 3.3.4. Algorithm 4: Double-Hash Port Selection Algorithm
* Note that we use 32bit integers (vs RFC 'short integers')
* because 2^16 is not a multiple of num_ephemeral and this
* property might be used by clever attacker.
+ *
* RFC claims using TABLE_LENGTH=10 buckets gives an improvement, though
- * attacks were since demonstrated, thus we use 65536 instead to really
- * give more isolation and privacy, at the expense of 256kB of kernel
- * memory.
+ * attacks were since demonstrated, thus we use 65536 by default instead
+ * to really give more isolation and privacy, at the expense of 256kB
+ * of kernel memory.
*/
-#define INET_TABLE_PERTURB_SHIFT 16
-#define INET_TABLE_PERTURB_SIZE (1 << INET_TABLE_PERTURB_SHIFT)
+#define INET_TABLE_PERTURB_SIZE (1 << CONFIG_INET_TABLE_PERTURB_ORDER)
static u32 *table_perturb;
int __inet_hash_connect(struct inet_timewait_death_row *death_row,
@@ -1037,7 +1097,7 @@ ok:
* on low contention the randomness is maximal and on high contention
* it may be inexistent.
*/
- i = max_t(int, i, prandom_u32_max(8) * 2);
+ i = max_t(int, i, get_random_u32_below(8) * 2);
WRITE_ONCE(table_perturb[index], READ_ONCE(table_perturb[index]) + i + 2);
/* Head lock still held and bh's disabled */
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f866d6282b2b..cae9f1a4e059 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1492,24 +1492,6 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct ip_tunnel_parm *p = &t->parms;
__be16 o_flags = p->o_flags;
- if (t->erspan_ver <= 2) {
- if (t->erspan_ver != 0 && !t->collect_md)
- o_flags |= TUNNEL_KEY;
-
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
- goto nla_put_failure;
-
- if (t->erspan_ver == 1) {
- if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
- goto nla_put_failure;
- } else if (t->erspan_ver == 2) {
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
- goto nla_put_failure;
- if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
- goto nla_put_failure;
- }
- }
-
if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
nla_put_be16(skb, IFLA_GRE_IFLAGS,
gre_tnl_flags_to_gre_flags(p->i_flags)) ||
@@ -1550,6 +1532,34 @@ nla_put_failure:
return -EMSGSIZE;
}
+static int erspan_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+
+ if (t->erspan_ver <= 2) {
+ if (t->erspan_ver != 0 && !t->collect_md)
+ t->parms.o_flags |= TUNNEL_KEY;
+
+ if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
+ goto nla_put_failure;
+
+ if (t->erspan_ver == 1) {
+ if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
+ goto nla_put_failure;
+ } else if (t->erspan_ver == 2) {
+ if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
+ goto nla_put_failure;
+ if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
+ goto nla_put_failure;
+ }
+ }
+
+ return ipgre_fill_info(skb, dev);
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
static void erspan_setup(struct net_device *dev)
{
struct ip_tunnel *t = netdev_priv(dev);
@@ -1628,7 +1638,7 @@ static struct rtnl_link_ops erspan_link_ops __read_mostly = {
.changelink = erspan_changelink,
.dellink = ip_tunnel_dellink,
.get_size = ipgre_get_size,
- .fill_info = ipgre_fill_info,
+ .fill_info = erspan_fill_info,
.get_link_net = ip_tunnel_get_link_net,
};
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 1b512390b3cf..e880ce77322a 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -366,6 +366,11 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
iph->tos, dev);
if (unlikely(err))
goto drop_error;
+ } else {
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
+
+ if (in_dev && IN_DEV_ORCONF(in_dev, NOPOLICY))
+ IPCB(skb)->flags |= IPSKB_NOPOLICY;
}
#ifdef CONFIG_IP_ROUTE_CLASSID
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index f8e176c77d1c..b3cc416ed292 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -435,7 +435,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
switch (ctinfo) {
case IP_CT_NEW:
- ct->mark = hash;
+ WRITE_ONCE(ct->mark, hash);
break;
case IP_CT_RELATED:
case IP_CT_RELATED_REPLY:
@@ -452,7 +452,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
#ifdef DEBUG
nf_ct_dump_tuple_ip(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
#endif
- pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
+ pr_debug("hash=%u ct_hash=%u ", hash, READ_ONCE(ct->mark));
if (!clusterip_responsible(cipinfo->config, hash)) {
pr_debug("not responsible\n");
return NF_DROP;
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index bde333b24837..04b4ec07bb06 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -49,6 +49,11 @@
#include <net/transp_v6.h>
#endif
+#define ping_portaddr_for_each_entry(__sk, node, list) \
+ hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node)
+#define ping_portaddr_for_each_entry_rcu(__sk, node, list) \
+ hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node)
+
struct ping_table {
struct hlist_nulls_head hash[PING_HTABLE_SIZE];
spinlock_t lock;
@@ -192,7 +197,7 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
return NULL;
}
- ping_portaddr_for_each_entry(sk, hnode, hslot) {
+ ping_portaddr_for_each_entry_rcu(sk, hnode, hslot) {
isk = inet_sk(sk);
pr_debug("iterate\n");
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index cd1fa9f70f1a..de6e3515ab4f 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -471,7 +471,7 @@ static u32 ip_idents_reserve(u32 hash, int segs)
old = READ_ONCE(*p_tstamp);
if (old != now && cmpxchg(p_tstamp, old, now) == old)
- delta = prandom_u32_max(now - old);
+ delta = get_random_u32_below(now - old);
/* If UBSAN reports an error there, please make sure your compiler
* supports -fno-strict-overflow before reporting it that was a bug
@@ -689,7 +689,7 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
} else {
/* Randomize max depth to avoid some side channels attacks. */
int max_depth = FNHE_RECLAIM_DEPTH +
- prandom_u32_max(FNHE_RECLAIM_DEPTH);
+ get_random_u32_below(FNHE_RECLAIM_DEPTH);
while (depth > max_depth) {
fnhe_remove_oldest(hash);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ef14efa1fb70..3f570b25c53d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2000,7 +2000,7 @@ static int receive_fallback_to_copy(struct sock *sk,
if (copy_address != zc->copybuf_address)
return -EINVAL;
- err = import_single_range(READ, (void __user *)copy_address,
+ err = import_single_range(ITER_DEST, (void __user *)copy_address,
inq, &iov, &msg.msg_iter);
if (err)
return err;
@@ -2034,7 +2034,7 @@ static int tcp_copy_straggler_data(struct tcp_zerocopy_receive *zc,
if (copy_address != zc->copybuf_address)
return -EINVAL;
- err = import_single_range(READ, (void __user *)copy_address,
+ err = import_single_range(ITER_DEST, (void __user *)copy_address,
copylen, &iov, &msg.msg_iter);
if (err)
return err;
@@ -3114,8 +3114,7 @@ int tcp_disconnect(struct sock *sk, int flags)
inet->inet_dport = 0;
- if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
- inet_reset_saddr(sk);
+ inet_bhash2_reset_saddr(sk);
sk->sk_shutdown = 0;
sock_reset_flag(sk, SOCK_DONE);
@@ -3647,7 +3646,7 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
case TCP_REPAIR_OPTIONS:
if (!tp->repair)
err = -EINVAL;
- else if (sk->sk_state == TCP_ESTABLISHED)
+ else if (sk->sk_state == TCP_ESTABLISHED && !tp->bytes_sent)
err = tcp_repair_options_est(sk, optval, optlen);
else
err = -EPERM;
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 54eec33c6e1c..d2c470524e58 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -618,7 +618,7 @@ static void bbr_reset_probe_bw_mode(struct sock *sk)
struct bbr *bbr = inet_csk_ca(sk);
bbr->mode = BBR_PROBE_BW;
- bbr->cycle_idx = CYCLE_LEN - 1 - prandom_u32_max(bbr_cycle_rand);
+ bbr->cycle_idx = CYCLE_LEN - 1 - get_random_u32_below(bbr_cycle_rand);
bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */
}
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index c501c329b1db..cf9c3e8f7ccb 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -278,7 +278,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
{
bool cork = false, enospc = sk_msg_full(msg);
struct sock *sk_redir;
- u32 tosend, delta = 0;
+ u32 tosend, origsize, sent, delta = 0;
u32 eval = __SK_NONE;
int ret;
@@ -333,10 +333,12 @@ more_data:
cork = true;
psock->cork = NULL;
}
- sk_msg_return(sk, msg, msg->sg.size);
+ sk_msg_return(sk, msg, tosend);
release_sock(sk);
+ origsize = msg->sg.size;
ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags);
+ sent = origsize - msg->sg.size;
if (eval == __SK_REDIRECT)
sock_put(sk_redir);
@@ -375,7 +377,7 @@ more_data:
msg->sg.data[msg->sg.start].page_link &&
msg->sg.data[msg->sg.start].length) {
if (eval == __SK_REDIRECT)
- sk_mem_charge(sk, msg->sg.size);
+ sk_mem_charge(sk, tosend - sent);
goto more_data;
}
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 0640453fce54..23cf418efe4f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3646,7 +3646,8 @@ static void tcp_send_challenge_ack(struct sock *sk)
u32 half = (ack_limit + 1) >> 1;
WRITE_ONCE(net->ipv4.tcp_challenge_timestamp, now);
- WRITE_ONCE(net->ipv4.tcp_challenge_count, half + prandom_u32_max(ack_limit));
+ WRITE_ONCE(net->ipv4.tcp_challenge_count,
+ get_random_u32_inclusive(half, ack_limit + half - 1));
}
count = READ_ONCE(net->ipv4.tcp_challenge_count);
if (count > 0) {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 87d440f47a70..da46357f501b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -199,15 +199,14 @@ static int tcp_v4_pre_connect(struct sock *sk, struct sockaddr *uaddr,
/* This will initiate an outgoing connection. */
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
- struct inet_bind_hashbucket *prev_addr_hashbucket = NULL;
struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct inet_timewait_death_row *tcp_death_row;
- __be32 daddr, nexthop, prev_sk_rcv_saddr;
struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct ip_options_rcu *inet_opt;
struct net *net = sock_net(sk);
__be16 orig_sport, orig_dport;
+ __be32 daddr, nexthop;
struct flowi4 *fl4;
struct rtable *rt;
int err;
@@ -251,24 +250,13 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
if (!inet->inet_saddr) {
- if (inet_csk(sk)->icsk_bind2_hash) {
- prev_addr_hashbucket = inet_bhashfn_portaddr(tcp_death_row->hashinfo,
- sk, net, inet->inet_num);
- prev_sk_rcv_saddr = sk->sk_rcv_saddr;
- }
- inet->inet_saddr = fl4->saddr;
- }
-
- sk_rcv_saddr_set(sk, inet->inet_saddr);
-
- if (prev_addr_hashbucket) {
- err = inet_bhash2_update_saddr(prev_addr_hashbucket, sk);
+ err = inet_bhash2_update_saddr(sk, &fl4->saddr, AF_INET);
if (err) {
- inet->inet_saddr = 0;
- sk_rcv_saddr_set(sk, prev_sk_rcv_saddr);
ip_rt_put(rt);
return err;
}
+ } else {
+ sk_rcv_saddr_set(sk, inet->inet_saddr);
}
if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
@@ -343,6 +331,7 @@ failure:
* if necessary.
*/
tcp_set_state(sk, TCP_CLOSE);
+ inet_bhash2_reset_saddr(sk);
ip_rt_put(rt);
sk->sk_route_caps = 0;
inet->inet_dport = 0;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 9c3f5202a97b..d720f6f5de3f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -104,7 +104,7 @@ static inline u32 cstamp_delta(unsigned long cstamp)
static inline s32 rfc3315_s14_backoff_init(s32 irt)
{
/* multiply 'initial retransmission time' by 0.9 .. 1.1 */
- u64 tmp = (900000 + prandom_u32_max(200001)) * (u64)irt;
+ u64 tmp = get_random_u32_inclusive(900000, 1100000) * (u64)irt;
do_div(tmp, 1000000);
return (s32)tmp;
}
@@ -112,11 +112,11 @@ static inline s32 rfc3315_s14_backoff_init(s32 irt)
static inline s32 rfc3315_s14_backoff_update(s32 rt, s32 mrt)
{
/* multiply 'retransmission timeout' by 1.9 .. 2.1 */
- u64 tmp = (1900000 + prandom_u32_max(200001)) * (u64)rt;
+ u64 tmp = get_random_u32_inclusive(1900000, 2100000) * (u64)rt;
do_div(tmp, 1000000);
if ((s32)tmp > mrt) {
/* multiply 'maximum retransmission time' by 0.9 .. 1.1 */
- tmp = (900000 + prandom_u32_max(200001)) * (u64)mrt;
+ tmp = get_random_u32_inclusive(900000, 1100000) * (u64)mrt;
do_div(tmp, 1000000);
}
return (s32)tmp;
@@ -3967,7 +3967,7 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
if (ifp->flags & IFA_F_OPTIMISTIC)
rand_num = 0;
else
- rand_num = prandom_u32_max(idev->cnf.rtr_solicit_delay ?: 1);
+ rand_num = get_random_u32_below(idev->cnf.rtr_solicit_delay ? : 1);
nonce = 0;
if (idev->cnf.enhanced_dad ||
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 8a22486cf270..17ac45aa7194 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -437,6 +437,7 @@ static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
{
struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
ifal->ifal_family = AF_INET6;
+ ifal->__ifal_reserved = 0;
ifal->ifal_prefixlen = prefixlen;
ifal->ifal_flags = 0;
ifal->ifal_index = ifindex;
diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c
index 79d43548279c..242f4295940e 100644
--- a/net/ipv6/esp6_offload.c
+++ b/net/ipv6/esp6_offload.c
@@ -346,6 +346,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
xo->seq.low += skb_shinfo(skb)->gso_segs;
}
+ if (xo->seq.low < seq)
+ xo->seq.hi++;
+
esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
len = skb->len - sizeof(struct ipv6hdr);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e19507614f64..60fd91bb5171 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -920,6 +920,9 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
if (err < 0)
goto fail;
+ /* We prevent @rt from being freed. */
+ rcu_read_lock();
+
for (;;) {
/* Prepare header of the next frame,
* before previous one went down. */
@@ -943,6 +946,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
if (err == 0) {
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGOKS);
+ rcu_read_unlock();
return 0;
}
@@ -950,6 +954,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGFAILS);
+ rcu_read_unlock();
return err;
slow_path_clean:
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 7860383295d8..1c02160cf7a4 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1050,7 +1050,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
/* called with mc_lock */
static void mld_gq_start_work(struct inet6_dev *idev)
{
- unsigned long tv = prandom_u32_max(idev->mc_maxdelay);
+ unsigned long tv = get_random_u32_below(idev->mc_maxdelay);
idev->mc_gq_running = 1;
if (!mod_delayed_work(mld_wq, &idev->mc_gq_work, tv + 2))
@@ -1068,7 +1068,7 @@ static void mld_gq_stop_work(struct inet6_dev *idev)
/* called with mc_lock */
static void mld_ifc_start_work(struct inet6_dev *idev, unsigned long delay)
{
- unsigned long tv = prandom_u32_max(delay);
+ unsigned long tv = get_random_u32_below(delay);
if (!mod_delayed_work(mld_wq, &idev->mc_ifc_work, tv + 2))
in6_dev_hold(idev);
@@ -1085,7 +1085,7 @@ static void mld_ifc_stop_work(struct inet6_dev *idev)
/* called with mc_lock */
static void mld_dad_start_work(struct inet6_dev *idev, unsigned long delay)
{
- unsigned long tv = prandom_u32_max(delay);
+ unsigned long tv = get_random_u32_below(delay);
if (!mod_delayed_work(mld_wq, &idev->mc_dad_work, tv + 2))
in6_dev_hold(idev);
@@ -1130,7 +1130,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
}
if (delay >= resptime)
- delay = prandom_u32_max(resptime);
+ delay = get_random_u32_below(resptime);
if (!mod_delayed_work(mld_wq, &ma->mca_work, delay))
refcount_inc(&ma->mca_refcnt);
@@ -2574,7 +2574,7 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
- delay = prandom_u32_max(unsolicited_report_interval(ma->idev));
+ delay = get_random_u32_below(unsolicited_report_interval(ma->idev));
if (cancel_delayed_work(&ma->mca_work)) {
refcount_dec(&ma->mca_refcnt);
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 2685c3f15e9d..b5205311f372 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -15,13 +15,7 @@ static u32 __ipv6_select_ident(struct net *net,
const struct in6_addr *dst,
const struct in6_addr *src)
{
- u32 id;
-
- do {
- id = get_random_u32();
- } while (!id);
-
- return id;
+ return get_random_u32_above(0);
}
/* This function exists only for tap drivers that must support broken
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 2f355f0ec32a..e74e0361fd92 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1713,7 +1713,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
net->ipv6.rt6_stats->fib_rt_cache++;
/* Randomize max depth to avoid some side channels attacks. */
- max_depth = FIB6_MAX_DEPTH + prandom_u32_max(FIB6_MAX_DEPTH);
+ max_depth = FIB6_MAX_DEPTH + get_random_u32_below(FIB6_MAX_DEPTH);
while (bucket->depth > max_depth)
rt6_exception_remove_oldest(bucket);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2a3f9296df1e..f0548dbcabd2 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -292,24 +292,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
if (!saddr) {
- struct inet_bind_hashbucket *prev_addr_hashbucket = NULL;
- struct in6_addr prev_v6_rcv_saddr;
-
- if (icsk->icsk_bind2_hash) {
- prev_addr_hashbucket = inet_bhashfn_portaddr(tcp_death_row->hashinfo,
- sk, net, inet->inet_num);
- prev_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
- }
saddr = &fl6.saddr;
- sk->sk_v6_rcv_saddr = *saddr;
- if (prev_addr_hashbucket) {
- err = inet_bhash2_update_saddr(prev_addr_hashbucket, sk);
- if (err) {
- sk->sk_v6_rcv_saddr = prev_v6_rcv_saddr;
- goto failure;
- }
- }
+ err = inet_bhash2_update_saddr(sk, saddr, AF_INET6);
+ if (err)
+ goto failure;
}
/* set the source address */
@@ -359,6 +346,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
late_failure:
tcp_set_state(sk, TCP_CLOSE);
+ inet_bhash2_reset_saddr(sk);
failure:
inet->inet_dport = 0;
sk->sk_route_caps = 0;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 4a4b0e49ec92..ea435eba3053 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -287,9 +287,13 @@ int __init xfrm6_init(void)
if (ret)
goto out_state;
- register_pernet_subsys(&xfrm6_net_ops);
+ ret = register_pernet_subsys(&xfrm6_net_ops);
+ if (ret)
+ goto out_protocol;
out:
return ret;
+out_protocol:
+ xfrm6_protocol_fini();
out_state:
xfrm6_state_fini();
out_policy:
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index a5004228111d..890a2423f559 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -222,7 +222,7 @@ static void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)
struct sk_buff *skb;
struct kcm_sock *kcm;
- while ((skb = __skb_dequeue(head))) {
+ while ((skb = skb_dequeue(head))) {
/* Reset destructor to avoid calling kcm_rcv_ready */
skb->destructor = sock_rfree;
skb_orphan(skb);
@@ -1085,53 +1085,17 @@ out_error:
return err;
}
-static struct sk_buff *kcm_wait_data(struct sock *sk, int flags,
- long timeo, int *err)
-{
- struct sk_buff *skb;
-
- while (!(skb = skb_peek(&sk->sk_receive_queue))) {
- if (sk->sk_err) {
- *err = sock_error(sk);
- return NULL;
- }
-
- if (sock_flag(sk, SOCK_DONE))
- return NULL;
-
- if ((flags & MSG_DONTWAIT) || !timeo) {
- *err = -EAGAIN;
- return NULL;
- }
-
- sk_wait_data(sk, &timeo, NULL);
-
- /* Handle signals */
- if (signal_pending(current)) {
- *err = sock_intr_errno(timeo);
- return NULL;
- }
- }
-
- return skb;
-}
-
static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
size_t len, int flags)
{
struct sock *sk = sock->sk;
struct kcm_sock *kcm = kcm_sk(sk);
int err = 0;
- long timeo;
struct strp_msg *stm;
int copied = 0;
struct sk_buff *skb;
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- lock_sock(sk);
-
- skb = kcm_wait_data(sk, flags, timeo, &err);
+ skb = skb_recv_datagram(sk, flags, &err);
if (!skb)
goto out;
@@ -1162,14 +1126,11 @@ msg_finished:
/* Finished with message */
msg->msg_flags |= MSG_EOR;
KCM_STATS_INCR(kcm->stats.rx_msgs);
- skb_unlink(skb, &sk->sk_receive_queue);
- kfree_skb(skb);
}
}
out:
- release_sock(sk);
-
+ skb_free_datagram(sk, skb);
return copied ? : err;
}
@@ -1179,7 +1140,6 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
{
struct sock *sk = sock->sk;
struct kcm_sock *kcm = kcm_sk(sk);
- long timeo;
struct strp_msg *stm;
int err = 0;
ssize_t copied;
@@ -1187,11 +1147,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
/* Only support splice for SOCKSEQPACKET */
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- lock_sock(sk);
-
- skb = kcm_wait_data(sk, flags, timeo, &err);
+ skb = skb_recv_datagram(sk, flags, &err);
if (!skb)
goto err_out;
@@ -1219,13 +1175,11 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
* finish reading the message.
*/
- release_sock(sk);
-
+ skb_free_datagram(sk, skb);
return copied;
err_out:
- release_sock(sk);
-
+ skb_free_datagram(sk, skb);
return err;
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index c85df5b958d2..95edcbedf6ef 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2905,7 +2905,7 @@ static int count_ah_combs(const struct xfrm_tmpl *t)
break;
if (!aalg->pfkey_supported)
continue;
- if (aalg_tmpl_set(t, aalg) && aalg->available)
+ if (aalg_tmpl_set(t, aalg))
sz += sizeof(struct sadb_comb);
}
return sz + sizeof(struct sadb_prop);
@@ -2923,7 +2923,7 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
if (!ealg->pfkey_supported)
continue;
- if (!(ealg_tmpl_set(t, ealg) && ealg->available))
+ if (!(ealg_tmpl_set(t, ealg)))
continue;
for (k = 1; ; k++) {
@@ -2934,16 +2934,17 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
if (!aalg->pfkey_supported)
continue;
- if (aalg_tmpl_set(t, aalg) && aalg->available)
+ if (aalg_tmpl_set(t, aalg))
sz += sizeof(struct sadb_comb);
}
}
return sz + sizeof(struct sadb_prop);
}
-static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
+static int dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
{
struct sadb_prop *p;
+ int sz = 0;
int i;
p = skb_put(skb, sizeof(struct sadb_prop));
@@ -2971,13 +2972,17 @@ static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
c->sadb_comb_soft_addtime = 20*60*60;
c->sadb_comb_hard_usetime = 8*60*60;
c->sadb_comb_soft_usetime = 7*60*60;
+ sz += sizeof(*c);
}
}
+
+ return sz + sizeof(*p);
}
-static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
+static int dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
{
struct sadb_prop *p;
+ int sz = 0;
int i, k;
p = skb_put(skb, sizeof(struct sadb_prop));
@@ -3019,8 +3024,11 @@ static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
c->sadb_comb_soft_addtime = 20*60*60;
c->sadb_comb_hard_usetime = 8*60*60;
c->sadb_comb_soft_usetime = 7*60*60;
+ sz += sizeof(*c);
}
}
+
+ return sz + sizeof(*p);
}
static int key_notify_policy_expire(struct xfrm_policy *xp, const struct km_event *c)
@@ -3150,6 +3158,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
int ctx_size = 0;
+ int alg_size = 0;
sockaddr_size = pfkey_sockaddr_size(x->props.family);
if (!sockaddr_size)
@@ -3161,16 +3170,16 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
sizeof(struct sadb_x_policy);
if (x->id.proto == IPPROTO_AH)
- size += count_ah_combs(t);
+ alg_size = count_ah_combs(t);
else if (x->id.proto == IPPROTO_ESP)
- size += count_esp_combs(t);
+ alg_size = count_esp_combs(t);
if ((xfrm_ctx = x->security)) {
ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
size += sizeof(struct sadb_x_sec_ctx) + ctx_size;
}
- skb = alloc_skb(size + 16, GFP_ATOMIC);
+ skb = alloc_skb(size + alg_size + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -3224,10 +3233,13 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
pol->sadb_x_policy_priority = xp->priority;
/* Set sadb_comb's. */
+ alg_size = 0;
if (x->id.proto == IPPROTO_AH)
- dump_ah_combs(skb, t);
+ alg_size = dump_ah_combs(skb, t);
else if (x->id.proto == IPPROTO_ESP)
- dump_esp_combs(skb, t);
+ alg_size = dump_esp_combs(skb, t);
+
+ hdr->sadb_msg_len += alg_size / 8;
/* security context */
if (xfrm_ctx) {
@@ -3382,7 +3394,7 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
hdr->sadb_msg_len = size / sizeof(uint64_t);
hdr->sadb_msg_errno = 0;
hdr->sadb_msg_reserved = 0;
- hdr->sadb_msg_seq = x->km.seq = get_acqseq();
+ hdr->sadb_msg_seq = x->km.seq;
hdr->sadb_msg_pid = 0;
/* SA */
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 7499c51b1850..9a1415fe3fa7 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1150,8 +1150,10 @@ static void l2tp_tunnel_destruct(struct sock *sk)
}
/* Remove hooks into tunnel socket */
+ write_lock_bh(&sk->sk_callback_lock);
sk->sk_destruct = tunnel->old_sk_destruct;
sk->sk_user_data = NULL;
+ write_unlock_bh(&sk->sk_callback_lock);
/* Call the original destructor */
if (sk->sk_destruct)
@@ -1469,16 +1471,19 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
sock = sockfd_lookup(tunnel->fd, &ret);
if (!sock)
goto err;
-
- ret = l2tp_validate_socket(sock->sk, net, tunnel->encap);
- if (ret < 0)
- goto err_sock;
}
+ sk = sock->sk;
+ write_lock_bh(&sk->sk_callback_lock);
+ ret = l2tp_validate_socket(sk, net, tunnel->encap);
+ if (ret < 0)
+ goto err_inval_sock;
+ rcu_assign_sk_user_data(sk, tunnel);
+ write_unlock_bh(&sk->sk_callback_lock);
+
tunnel->l2tp_net = net;
pn = l2tp_pernet(net);
- sk = sock->sk;
sock_hold(sk);
tunnel->sock = sk;
@@ -1503,8 +1508,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
};
setup_udp_tunnel_sock(net, sock, &udp_cfg);
- } else {
- sk->sk_user_data = tunnel;
}
tunnel->old_sk_destruct = sk->sk_destruct;
@@ -1521,6 +1524,11 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
return 0;
err_sock:
+ write_lock_bh(&sk->sk_callback_lock);
+ rcu_assign_sk_user_data(sk, NULL);
+err_inval_sock:
+ write_unlock_bh(&sk->sk_callback_lock);
+
if (tunnel->fd < 0)
sock_release(sock);
else
diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c
index 2e66598fac79..e8ebd343e2bf 100644
--- a/net/mac80211/airtime.c
+++ b/net/mac80211/airtime.c
@@ -452,6 +452,9 @@ static u32 ieee80211_get_rate_duration(struct ieee80211_hw *hw,
(status->encoding == RX_ENC_HE && streams > 8)))
return 0;
+ if (idx >= MCS_GROUP_RATES)
+ return 0;
+
duration = airtime_mcs_groups[group].duration[idx];
duration <<= airtime_mcs_groups[group].shift;
*overhead = 36 + (streams << 2);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 46f3eddc2388..02b5abc7326b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1439,8 +1439,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_led_exit(local);
destroy_workqueue(local->workqueue);
fail_workqueue:
- if (local->wiphy_ciphers_allocated)
+ if (local->wiphy_ciphers_allocated) {
kfree(local->hw.wiphy->cipher_suites);
+ local->wiphy_ciphers_allocated = false;
+ }
kfree(local->int_scan_req);
return result;
}
@@ -1508,8 +1510,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
mutex_destroy(&local->iflist_mtx);
mutex_destroy(&local->mtx);
- if (local->wiphy_ciphers_allocated)
+ if (local->wiphy_ciphers_allocated) {
kfree(local->hw.wiphy->cipher_suites);
+ local->wiphy_ciphers_allocated = false;
+ }
idr_for_each(&local->ack_status_frames,
ieee80211_free_ack_frame, NULL);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index acc1c299f1ae..69d5e1ec6ede 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -710,7 +710,7 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
- kfree_skb(skb);
+ ieee80211_free_txskb(&sdata->local->hw, skb);
sdata->u.mesh.mshstats.dropped_frames_no_route++;
}
diff --git a/net/mac80211/s1g.c b/net/mac80211/s1g.c
index 8ca7d45d6daa..c1f964e9991c 100644
--- a/net/mac80211/s1g.c
+++ b/net/mac80211/s1g.c
@@ -112,6 +112,9 @@ ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
goto out;
}
+ /* TWT Information not supported yet */
+ twt->control |= IEEE80211_TWT_CONTROL_RX_DISABLED;
+
drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt);
out:
ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a364148149f9..874f2a4d831d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4418,6 +4418,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (likely(!is_multicast_ether_addr(eth->h_dest)))
goto normal;
+ if (unlikely(!ieee80211_sdata_running(sdata))) {
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) {
struct sk_buff_head queue;
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
index 500ed1b81250..7e2065e72915 100644
--- a/net/mac802154/iface.c
+++ b/net/mac802154/iface.c
@@ -662,6 +662,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
sdata->dev = ndev;
sdata->wpan_dev.wpan_phy = local->hw.phy;
sdata->local = local;
+ INIT_LIST_HEAD(&sdata->wpan_dev.list);
/* setup type-dependent data */
ret = ieee802154_setup_sdata(sdata, type);
diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c
index b6b5e496fa40..fc9e728b6333 100644
--- a/net/mctp/af_mctp.c
+++ b/net/mctp/af_mctp.c
@@ -665,12 +665,14 @@ static __init int mctp_init(void)
rc = mctp_neigh_init();
if (rc)
- goto err_unreg_proto;
+ goto err_unreg_routes;
mctp_device_init();
return 0;
+err_unreg_routes:
+ mctp_routes_exit();
err_unreg_proto:
proto_unregister(&mctp_proto);
err_unreg_sock:
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 2155f15a074c..f9a80b82dc51 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -1400,7 +1400,7 @@ int __init mctp_routes_init(void)
return register_pernet_subsys(&mctp_net_ops);
}
-void __exit mctp_routes_exit(void)
+void mctp_routes_exit(void)
{
unregister_pernet_subsys(&mctp_net_ops);
rtnl_unregister(PF_MCTP, RTM_DELROUTE);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index b6dc6e260334..1dbc62537259 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -2354,12 +2354,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
goto out;
}
- /* if we are invoked by the msk cleanup code, the subflow is
- * already orphaned
- */
- if (ssk->sk_socket)
- sock_orphan(ssk);
-
+ sock_orphan(ssk);
subflow->disposable = 1;
/* if ssk hit tcp_done(), tcp_cleanup_ulp() cleared the related ops
@@ -2940,7 +2935,11 @@ cleanup:
if (ssk == msk->first)
subflow->fail_tout = 0;
- sock_orphan(ssk);
+ /* detach from the parent socket, but allow data_ready to
+ * push incoming data into the mptcp stack, to properly ack it
+ */
+ ssk->sk_socket = NULL;
+ ssk->sk_wq = NULL;
unlock_sock_fast(ssk, slow);
}
sock_orphan(sk);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 02a54d59697b..2159b5f9988f 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1745,16 +1745,16 @@ void mptcp_subflow_queue_clean(struct sock *listener_ssk)
for (msk = head; msk; msk = next) {
struct sock *sk = (struct sock *)msk;
- bool slow, do_cancel_work;
+ bool do_cancel_work;
sock_hold(sk);
- slow = lock_sock_fast_nested(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
next = msk->dl_next;
msk->first = NULL;
msk->dl_next = NULL;
do_cancel_work = __mptcp_close(sk, 0);
- unlock_sock_fast(sk, slow);
+ release_sock(sk);
if (do_cancel_work)
mptcp_cancel_work(sk);
sock_put(sk);
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 3adc291d9ce1..7499192af586 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -916,7 +916,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
#ifdef IP_SET_HASH_WITH_MULTI
if (h->bucketsize >= AHASH_MAX_TUNED)
goto set_full;
- else if (h->bucketsize < multi)
+ else if (h->bucketsize <= multi)
h->bucketsize += AHASH_INIT_SIZE;
#endif
if (n->size >= AHASH_MAX(h)) {
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index dd30c03d5a23..75d556d71652 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -151,18 +151,16 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE)
return -ERANGE;
- if (retried) {
+ if (retried)
ip = ntohl(h->next.ip);
- e.ip = htonl(ip);
- }
for (; ip <= ip_to;) {
+ e.ip = htonl(ip);
ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
ip += hosts;
- e.ip = htonl(ip);
- if (e.ip == 0)
+ if (ip == 0)
return 0;
ret = 0;
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index a56fd0b5a430..4963fec815da 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -1617,7 +1617,7 @@ ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
EnterFunction(7);
/* Receive a packet */
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, buflen);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, buflen);
len = sock_recvmsg(sock, &msg, MSG_DONTWAIT);
if (len < 0)
return len;
diff --git a/net/netfilter/ipvs/ip_vs_twos.c b/net/netfilter/ipvs/ip_vs_twos.c
index f2579fc9c75b..3308e4cc740a 100644
--- a/net/netfilter/ipvs/ip_vs_twos.c
+++ b/net/netfilter/ipvs/ip_vs_twos.c
@@ -71,8 +71,8 @@ static struct ip_vs_dest *ip_vs_twos_schedule(struct ip_vs_service *svc,
* from 0 to total_weight
*/
total_weight += 1;
- rweight1 = prandom_u32_max(total_weight);
- rweight2 = prandom_u32_max(total_weight);
+ rweight1 = get_random_u32_below(total_weight);
+ rweight2 = get_random_u32_below(total_weight);
/* Pick two weighted servers */
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f97bda06d2a9..8006ca862551 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -891,7 +891,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
zone = nf_ct_zone(ct);
if (!nf_ct_ext_valid_pre(ct->ext)) {
- NF_CT_STAT_INC(net, insert_failed);
+ NF_CT_STAT_INC_ATOMIC(net, insert_failed);
return -ETIMEDOUT;
}
@@ -906,7 +906,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
nf_ct_zone_id(nf_ct_zone(ct), IP_CT_DIR_REPLY));
} while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
- max_chainlen = MIN_CHAINLEN + prandom_u32_max(MAX_CHAINLEN);
+ max_chainlen = MIN_CHAINLEN + get_random_u32_below(MAX_CHAINLEN);
/* See if there's one in the list already, including reverse */
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[hash], hnnode) {
@@ -938,7 +938,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
if (!nf_ct_ext_valid_post(ct->ext)) {
nf_ct_kill(ct);
- NF_CT_STAT_INC(net, drop);
+ NF_CT_STAT_INC_ATOMIC(net, drop);
return -ETIMEDOUT;
}
@@ -1227,7 +1227,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
goto dying;
}
- max_chainlen = MIN_CHAINLEN + prandom_u32_max(MAX_CHAINLEN);
+ max_chainlen = MIN_CHAINLEN + get_random_u32_below(MAX_CHAINLEN);
/* See if there's one in the list already, including reverse:
NAT could have grabbed it without realizing, since we're
not in the hash. If there is, we lost race. */
@@ -1275,7 +1275,7 @@ chaintoolong:
*/
if (!nf_ct_ext_valid_post(ct->ext)) {
nf_ct_kill(ct);
- NF_CT_STAT_INC(net, drop);
+ NF_CT_STAT_INC_ATOMIC(net, drop);
return NF_DROP;
}
@@ -1781,7 +1781,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
}
#ifdef CONFIG_NF_CONNTRACK_MARK
- ct->mark = exp->master->mark;
+ ct->mark = READ_ONCE(exp->master->mark);
#endif
#ifdef CONFIG_NF_CONNTRACK_SECMARK
ct->secmark = exp->master->secmark;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 7562b215b932..1286ae7d4609 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -330,7 +330,12 @@ nla_put_failure:
#ifdef CONFIG_NF_CONNTRACK_MARK
static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
{
- if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark)))
+ u32 mark = READ_ONCE(ct->mark);
+
+ if (!mark)
+ return 0;
+
+ if (nla_put_be32(skb, CTA_MARK, htonl(mark)))
goto nla_put_failure;
return 0;
@@ -826,8 +831,8 @@ ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
}
#ifdef CONFIG_NF_CONNTRACK_MARK
- if ((events & (1 << IPCT_MARK) || ct->mark)
- && ctnetlink_dump_mark(skb, ct) < 0)
+ if (events & (1 << IPCT_MARK) &&
+ ctnetlink_dump_mark(skb, ct) < 0)
goto nla_put_failure;
#endif
nlmsg_end(skb, nlh);
@@ -1154,7 +1159,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
}
#ifdef CONFIG_NF_CONNTRACK_MARK
- if ((ct->mark & filter->mark.mask) != filter->mark.val)
+ if ((READ_ONCE(ct->mark) & filter->mark.mask) != filter->mark.val)
goto ignore_entry;
#endif
status = (u32)READ_ONCE(ct->status);
@@ -2002,9 +2007,9 @@ static void ctnetlink_change_mark(struct nf_conn *ct,
mask = ~ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
mark = ntohl(nla_get_be32(cda[CTA_MARK]));
- newmark = (ct->mark & mask) ^ mark;
- if (newmark != ct->mark)
- ct->mark = newmark;
+ newmark = (READ_ONCE(ct->mark) & mask) ^ mark;
+ if (newmark != READ_ONCE(ct->mark))
+ WRITE_ONCE(ct->mark, newmark);
}
#endif
@@ -2730,7 +2735,7 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
goto nla_put_failure;
#ifdef CONFIG_NF_CONNTRACK_MARK
- if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
+ if (ctnetlink_dump_mark(skb, ct) < 0)
goto nla_put_failure;
#endif
if (ctnetlink_dump_labels(skb, ct) < 0)
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 4ffe84c5a82c..bca839ab1ae8 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -366,7 +366,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
goto release;
#if defined(CONFIG_NF_CONNTRACK_MARK)
- seq_printf(s, "mark=%u ", ct->mark);
+ seq_printf(s, "mark=%u ", READ_ONCE(ct->mark));
#endif
ct_show_secctx(s, ct);
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index b04645ced89b..0fdcdb2c9ae4 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -997,13 +997,13 @@ static void flow_offload_queue_work(struct flow_offload_work *offload)
struct net *net = read_pnet(&offload->flowtable->net);
if (offload->cmd == FLOW_CLS_REPLACE) {
- NF_FLOW_TABLE_STAT_INC(net, count_wq_add);
+ NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count_wq_add);
queue_work(nf_flow_offload_add_wq, &offload->work);
} else if (offload->cmd == FLOW_CLS_DESTROY) {
- NF_FLOW_TABLE_STAT_INC(net, count_wq_del);
+ NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count_wq_del);
queue_work(nf_flow_offload_del_wq, &offload->work);
} else {
- NF_FLOW_TABLE_STAT_INC(net, count_wq_stats);
+ NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count_wq_stats);
queue_work(nf_flow_offload_stats_wq, &offload->work);
}
}
@@ -1098,6 +1098,7 @@ static int nf_flow_table_block_setup(struct nf_flowtable *flowtable,
struct flow_block_cb *block_cb, *next;
int err = 0;
+ down_write(&flowtable->flow_block_lock);
switch (cmd) {
case FLOW_BLOCK_BIND:
list_splice(&bo->cb_list, &flowtable->flow_block.cb_list);
@@ -1112,6 +1113,7 @@ static int nf_flow_table_block_setup(struct nf_flowtable *flowtable,
WARN_ON_ONCE(1);
err = -EOPNOTSUPP;
}
+ up_write(&flowtable->flow_block_lock);
return err;
}
@@ -1168,7 +1170,9 @@ static int nf_flow_table_offload_cmd(struct flow_block_offload *bo,
nf_flow_table_block_offload_init(bo, dev_net(dev), cmd, flowtable,
extack);
+ down_write(&flowtable->flow_block_lock);
err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_FT, bo);
+ up_write(&flowtable->flow_block_lock);
if (err < 0)
return err;
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index a95a25196943..bf591e6af005 100644
--- a/net/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -223,7 +223,7 @@ u16 nf_nat_exp_find_port(struct nf_conntrack_expect *exp, u16 port)
if (res != -EBUSY || (--attempts_left < 0))
break;
- port = min + prandom_u32_max(range);
+ port = min + get_random_u32_below(range);
}
return 0;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 76bd4d03dbda..7a09421f19e1 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5958,7 +5958,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
&timeout);
if (err)
return err;
- } else if (set->flags & NFT_SET_TIMEOUT) {
+ } else if (set->flags & NFT_SET_TIMEOUT &&
+ !(flags & NFT_SET_ELEM_INTERVAL_END)) {
timeout = set->timeout;
}
@@ -6024,7 +6025,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
err = -EOPNOTSUPP;
goto err_set_elem_expr;
}
- } else if (set->num_exprs > 0) {
+ } else if (set->num_exprs > 0 &&
+ !(flags & NFT_SET_ELEM_INTERVAL_END)) {
err = nft_set_elem_expr_clone(ctx, set, expr_array);
if (err < 0)
goto err_set_elem_expr_clone;
@@ -10090,7 +10092,8 @@ static void __net_exit nf_tables_exit_net(struct net *net)
struct nftables_pernet *nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
- if (!list_empty(&nft_net->commit_list))
+ if (!list_empty(&nft_net->commit_list) ||
+ !list_empty(&nft_net->module_list))
__nf_tables_abort(net, NFNL_ABORT_NONE);
__nft_release_tables(net);
mutex_unlock(&nft_net->commit_mutex);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 9c44518cb70f..6d18fb346868 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -294,6 +294,7 @@ replay:
nfnl_lock(subsys_id);
if (nfnl_dereference_protected(subsys_id) != ss ||
nfnetlink_find_client(type, ss) != nc) {
+ nfnl_unlock(subsys_id);
err = -EAGAIN;
break;
}
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index a3f01f209a53..641dc21f92b4 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -98,7 +98,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
return;
#ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK:
- *dest = ct->mark;
+ *dest = READ_ONCE(ct->mark);
return;
#endif
#ifdef CONFIG_NF_CONNTRACK_SECMARK
@@ -297,8 +297,8 @@ static void nft_ct_set_eval(const struct nft_expr *expr,
switch (priv->key) {
#ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK:
- if (ct->mark != value) {
- ct->mark = value;
+ if (READ_ONCE(ct->mark) != value) {
+ WRITE_ONCE(ct->mark, value);
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 4f9299b9dcdd..06d46d182634 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1162,6 +1162,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
struct nft_pipapo_match *m = priv->clone;
u8 genmask = nft_genmask_next(net);
struct nft_pipapo_field *f;
+ const u8 *start_p, *end_p;
int i, bsize_max, err = 0;
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
@@ -1202,9 +1203,9 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
}
/* Validate */
+ start_p = start;
+ end_p = end;
nft_pipapo_for_each_field(f, i, m) {
- const u8 *start_p = start, *end_p = end;
-
if (f->rules >= (unsigned long)NFT_PIPAPO_RULE0_MAX)
return -ENOSPC;
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index e5ebc0810675..ad3c033db64e 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -30,6 +30,7 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
u_int32_t new_targetmark;
struct nf_conn *ct;
u_int32_t newmark;
+ u_int32_t oldmark;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
@@ -37,14 +38,15 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
switch (info->mode) {
case XT_CONNMARK_SET:
- newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
+ oldmark = READ_ONCE(ct->mark);
+ newmark = (oldmark & ~info->ctmask) ^ info->ctmark;
if (info->shift_dir == D_SHIFT_RIGHT)
newmark >>= info->shift_bits;
else
newmark <<= info->shift_bits;
- if (ct->mark != newmark) {
- ct->mark = newmark;
+ if (READ_ONCE(ct->mark) != newmark) {
+ WRITE_ONCE(ct->mark, newmark);
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
@@ -55,15 +57,15 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
else
new_targetmark <<= info->shift_bits;
- newmark = (ct->mark & ~info->ctmask) ^
+ newmark = (READ_ONCE(ct->mark) & ~info->ctmask) ^
new_targetmark;
- if (ct->mark != newmark) {
- ct->mark = newmark;
+ if (READ_ONCE(ct->mark) != newmark) {
+ WRITE_ONCE(ct->mark, newmark);
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
case XT_CONNMARK_RESTORE:
- new_targetmark = (ct->mark & info->ctmask);
+ new_targetmark = (READ_ONCE(ct->mark) & info->ctmask);
if (info->shift_dir == D_SHIFT_RIGHT)
new_targetmark >>= info->shift_bits;
else
@@ -126,7 +128,7 @@ connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (ct == NULL)
return false;
- return ((ct->mark & info->mask) == info->mark) ^ info->invert;
+ return ((READ_ONCE(ct->mark) & info->mask) == info->mark) ^ info->invert;
}
static int connmark_mt_check(const struct xt_mtchk_param *par)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a662e8a5ff84..7a401d94463a 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -835,7 +835,7 @@ retry:
/* Bind collision, search negative portid values. */
if (rover == -4096)
/* rover will be in range [S32_MIN, -4097] */
- rover = S32_MIN + prandom_u32_max(-4096 - S32_MIN);
+ rover = S32_MIN + get_random_u32_below(-4096 - S32_MIN);
else if (rover >= -4096)
rover = -4097;
portid = rover--;
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 6a193cce2a75..4ffdf2f45c44 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -542,7 +542,7 @@ static int nci_open_device(struct nci_dev *ndev)
skb_queue_purge(&ndev->tx_q);
ndev->ops->close(ndev);
- ndev->flags = 0;
+ ndev->flags &= BIT(NCI_UNREG);
}
done:
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index aa5e712adf07..3d36ea5701f0 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -279,8 +279,10 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
nci_plen(skb->data));
conn_info = nci_get_conn_info_by_conn_id(ndev, nci_conn_id(skb->data));
- if (!conn_info)
+ if (!conn_info) {
+ kfree_skb(skb);
return;
+ }
/* strip the nci data header */
skb_pull(skb, NCI_DATA_HDR_SIZE);
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 282c51051dcc..994a0a1efb58 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -240,6 +240,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
target->sens_res = nfca_poll->sens_res;
target->sel_res = nfca_poll->sel_res;
target->nfcid1_len = nfca_poll->nfcid1_len;
+ if (target->nfcid1_len > ARRAY_SIZE(target->nfcid1))
+ return -EPROTO;
if (target->nfcid1_len > 0) {
memcpy(target->nfcid1, nfca_poll->nfcid1,
target->nfcid1_len);
@@ -248,6 +250,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params;
target->sensb_res_len = nfcb_poll->sensb_res_len;
+ if (target->sensb_res_len > ARRAY_SIZE(target->sensb_res))
+ return -EPROTO;
if (target->sensb_res_len > 0) {
memcpy(target->sensb_res, nfcb_poll->sensb_res,
target->sensb_res_len);
@@ -256,6 +260,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params;
target->sensf_res_len = nfcf_poll->sensf_res_len;
+ if (target->sensf_res_len > ARRAY_SIZE(target->sensf_res))
+ return -EPROTO;
if (target->sensf_res_len > 0) {
memcpy(target->sensf_res, nfcf_poll->sensf_res,
target->sensf_res_len);
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index c7b10234cf7c..c8eaf4234b2e 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -152,7 +152,7 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
static u32 ovs_ct_get_mark(const struct nf_conn *ct)
{
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
- return ct ? ct->mark : 0;
+ return ct ? READ_ONCE(ct->mark) : 0;
#else
return 0;
#endif
@@ -340,9 +340,9 @@ static int ovs_ct_set_mark(struct nf_conn *ct, struct sw_flow_key *key,
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
u32 new_mark;
- new_mark = ct_mark | (ct->mark & ~(mask));
- if (ct->mark != new_mark) {
- ct->mark = new_mark;
+ new_mark = ct_mark | (READ_ONCE(ct->mark) & ~(mask));
+ if (READ_ONCE(ct->mark) != new_mark) {
+ WRITE_ONCE(ct->mark, new_mark);
if (nf_ct_is_confirmed(ct))
nf_conntrack_event_cache(IPCT_MARK, ct);
key->ct.mark = new_mark;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6ce8dd19f33c..96fea8afc004 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1350,7 +1350,7 @@ static bool fanout_flow_is_huge(struct packet_sock *po, struct sk_buff *skb)
if (READ_ONCE(history[i]) == rxhash)
count++;
- victim = prandom_u32_max(ROLLOVER_HLEN);
+ victim = get_random_u32_below(ROLLOVER_HLEN);
/* Avoid dirtying the cache line if possible */
if (READ_ONCE(history[victim]) != rxhash)
@@ -1386,7 +1386,7 @@ static unsigned int fanout_demux_rnd(struct packet_fanout *f,
struct sk_buff *skb,
unsigned int num)
{
- return prandom_u32_max(num);
+ return get_random_u32_below(num);
}
static unsigned int fanout_demux_rollover(struct packet_fanout *f,
@@ -2293,8 +2293,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb->ip_summed == CHECKSUM_PARTIAL)
status |= TP_STATUS_CSUMNOTREADY;
else if (skb->pkt_type != PACKET_OUTGOING &&
- (skb->ip_summed == CHECKSUM_COMPLETE ||
- skb_csum_unnecessary(skb)))
+ skb_csum_unnecessary(skb))
status |= TP_STATUS_CSUM_VALID;
if (snaplen > res)
@@ -3520,8 +3519,7 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (skb->ip_summed == CHECKSUM_PARTIAL)
aux.tp_status |= TP_STATUS_CSUMNOTREADY;
else if (skb->pkt_type != PACKET_OUTGOING &&
- (skb->ip_summed == CHECKSUM_COMPLETE ||
- skb_csum_unnecessary(skb)))
+ skb_csum_unnecessary(skb))
aux.tp_status |= TP_STATUS_CSUM_VALID;
aux.tp_len = origlen;
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 1ad0ec5afb50..8499ceb7719c 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -399,6 +399,7 @@ enum rxrpc_conn_proto_state {
struct rxrpc_bundle {
struct rxrpc_conn_parameters params;
refcount_t ref;
+ atomic_t active; /* Number of active users */
unsigned int debug_id;
bool try_upgrade; /* True if the bundle is attempting upgrade */
bool alloc_conn; /* True if someone's getting a conn */
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 3c9eeb5b750c..bdb335cb2d05 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -40,6 +40,8 @@ __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ;
DEFINE_IDR(rxrpc_client_conn_ids);
static DEFINE_SPINLOCK(rxrpc_conn_id_lock);
+static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
+
/*
* Get a connection ID and epoch for a client connection from the global pool.
* The connection struct pointer is then recorded in the idr radix tree. The
@@ -123,6 +125,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp,
bundle->params = *cp;
rxrpc_get_peer(bundle->params.peer);
refcount_set(&bundle->ref, 1);
+ atomic_set(&bundle->active, 1);
spin_lock_init(&bundle->channel_lock);
INIT_LIST_HEAD(&bundle->waiting_calls);
}
@@ -149,7 +152,7 @@ void rxrpc_put_bundle(struct rxrpc_bundle *bundle)
dead = __refcount_dec_and_test(&bundle->ref, &r);
- _debug("PUT B=%x %d", d, r);
+ _debug("PUT B=%x %d", d, r - 1);
if (dead)
rxrpc_free_bundle(bundle);
}
@@ -338,6 +341,7 @@ found_bundle_free:
rxrpc_free_bundle(candidate);
found_bundle:
rxrpc_get_bundle(bundle);
+ atomic_inc(&bundle->active);
spin_unlock(&local->client_bundles_lock);
_leave(" = %u [found]", bundle->debug_id);
return bundle;
@@ -435,6 +439,7 @@ static void rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle, gfp_t gfp)
if (old)
trace_rxrpc_client(old, -1, rxrpc_client_replace);
candidate->bundle_shift = shift;
+ atomic_inc(&bundle->active);
bundle->conns[i] = candidate;
for (j = 0; j < RXRPC_MAXCALLS; j++)
set_bit(shift + j, &bundle->avail_chans);
@@ -725,6 +730,7 @@ granted_channel:
smp_rmb();
out_put_bundle:
+ rxrpc_deactivate_bundle(bundle);
rxrpc_put_bundle(bundle);
out:
_leave(" = %d", ret);
@@ -900,9 +906,8 @@ out:
static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
{
struct rxrpc_bundle *bundle = conn->bundle;
- struct rxrpc_local *local = bundle->params.local;
unsigned int bindex;
- bool need_drop = false, need_put = false;
+ bool need_drop = false;
int i;
_enter("C=%x", conn->debug_id);
@@ -921,15 +926,22 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
}
spin_unlock(&bundle->channel_lock);
- /* If there are no more connections, remove the bundle */
- if (!bundle->avail_chans) {
- _debug("maybe unbundle");
- spin_lock(&local->client_bundles_lock);
+ if (need_drop) {
+ rxrpc_deactivate_bundle(bundle);
+ rxrpc_put_connection(conn);
+ }
+}
- for (i = 0; i < ARRAY_SIZE(bundle->conns); i++)
- if (bundle->conns[i])
- break;
- if (i == ARRAY_SIZE(bundle->conns) && !bundle->params.exclusive) {
+/*
+ * Drop the active count on a bundle.
+ */
+static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle)
+{
+ struct rxrpc_local *local = bundle->params.local;
+ bool need_put = false;
+
+ if (atomic_dec_and_lock(&bundle->active, &local->client_bundles_lock)) {
+ if (!bundle->params.exclusive) {
_debug("erase bundle");
rb_erase(&bundle->local_node, &local->client_bundles);
need_put = true;
@@ -939,10 +951,6 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
if (need_put)
rxrpc_put_bundle(bundle);
}
-
- if (need_drop)
- rxrpc_put_connection(conn);
- _leave("");
}
/*
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 1e8ab4749c6c..4662a6ce8a7e 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -976,7 +976,7 @@ config NET_ACT_TUNNEL_KEY
config NET_ACT_CT
tristate "connection tracking tc action"
- depends on NET_CLS_ACT && NF_CONNTRACK && NF_NAT && NF_FLOW_TABLE
+ depends on NET_CLS_ACT && NF_CONNTRACK && (!NF_NAT || NF_NAT) && NF_FLOW_TABLE
help
Say Y here to allow sending the packets to conntrack module.
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 66b143bb04ac..d41002e4613f 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -61,7 +61,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a,
c = nf_ct_get(skb, &ctinfo);
if (c) {
- skb->mark = c->mark;
+ skb->mark = READ_ONCE(c->mark);
/* using overlimits stats to count how many packets marked */
ca->tcf_qstats.overlimits++;
goto out;
@@ -81,7 +81,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a,
c = nf_ct_tuplehash_to_ctrack(thash);
/* using overlimits stats to count how many packets marked */
ca->tcf_qstats.overlimits++;
- skb->mark = c->mark;
+ skb->mark = READ_ONCE(c->mark);
nf_ct_put(c);
out:
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index b38d91d6b249..4c7f7861ea96 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -178,7 +178,7 @@ static void tcf_ct_flow_table_add_action_meta(struct nf_conn *ct,
entry = tcf_ct_flow_table_flow_action_get_next(action);
entry->id = FLOW_ACTION_CT_METADATA;
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
- entry->ct_metadata.mark = ct->mark;
+ entry->ct_metadata.mark = READ_ONCE(ct->mark);
#endif
ctinfo = dir == IP_CT_DIR_ORIGINAL ? IP_CT_ESTABLISHED :
IP_CT_ESTABLISHED_REPLY;
@@ -936,9 +936,9 @@ static void tcf_ct_act_set_mark(struct nf_conn *ct, u32 mark, u32 mask)
if (!mask)
return;
- new_mark = mark | (ct->mark & ~(mask));
- if (ct->mark != new_mark) {
- ct->mark = new_mark;
+ new_mark = mark | (READ_ONCE(ct->mark) & ~(mask));
+ if (READ_ONCE(ct->mark) != new_mark) {
+ WRITE_ONCE(ct->mark, new_mark);
if (nf_ct_is_confirmed(ct))
nf_conntrack_event_cache(IPCT_MARK, ct);
}
diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c
index d4102f0a9abd..eaa02f098d1c 100644
--- a/net/sched/act_ctinfo.c
+++ b/net/sched/act_ctinfo.c
@@ -32,7 +32,7 @@ static void tcf_ctinfo_dscp_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
{
u8 dscp, newdscp;
- newdscp = (((ct->mark & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
+ newdscp = (((READ_ONCE(ct->mark) & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
~INET_ECN_MASK;
switch (proto) {
@@ -72,7 +72,7 @@ static void tcf_ctinfo_cpmark_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
struct sk_buff *skb)
{
ca->stats_cpmark_set++;
- skb->mark = ct->mark & cp->cpmarkmask;
+ skb->mark = READ_ONCE(ct->mark) & cp->cpmarkmask;
}
static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
@@ -130,7 +130,7 @@ static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
}
if (cp->mode & CTINFO_MODE_DSCP)
- if (!cp->dscpstatemask || (ct->mark & cp->dscpstatemask))
+ if (!cp->dscpstatemask || (READ_ONCE(ct->mark) & cp->dscpstatemask))
tcf_ctinfo_dscp_set(ct, ca, cp, skb, wlen, proto);
if (cp->mode & CTINFO_MODE_CPMARK)
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index 62d682b96b88..be267ffaaba7 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -25,7 +25,7 @@ static struct tc_action_ops act_gact_ops;
static int gact_net_rand(struct tcf_gact *gact)
{
smp_rmb(); /* coupled with smp_wmb() in tcf_gact_init() */
- if (prandom_u32_max(gact->tcfg_pval))
+ if (get_random_u32_below(gact->tcfg_pval))
return gact->tcf_action;
return gact->tcfg_paction;
}
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 7a25477f5d99..4194480746b0 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -168,7 +168,7 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a,
psample_group = rcu_dereference_bh(s->psample_group);
/* randomly sample packets according to rate */
- if (psample_group && (prandom_u32_max(s->rate) == 0)) {
+ if (psample_group && (get_random_u32_below(s->rate) == 0)) {
if (!skb_at_tc_ingress(skb)) {
md.in_ifindex = skb->skb_iif;
md.out_ifindex = skb->dev->ifindex;
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index 3ac3e5c80b6f..19c851125901 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -183,7 +183,7 @@ static struct sk_buff *choke_peek_random(const struct choke_sched_data *q,
int retrys = 3;
do {
- *pidx = (q->head + prandom_u32_max(choke_len(q))) & q->tab_mask;
+ *pidx = (q->head + get_random_u32_below(choke_len(q))) & q->tab_mask;
skb = q->tab[*pidx];
if (skb)
return skb;
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index fb00ac40ecb7..6ef3021e1169 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -513,8 +513,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
goto finish_segs;
}
- skb->data[prandom_u32_max(skb_headlen(skb))] ^=
- 1<<prandom_u32_max(8);
+ skb->data[get_random_u32_below(skb_headlen(skb))] ^=
+ 1<<get_random_u32_below(8);
}
if (unlikely(sch->q.qlen >= sch->limit)) {
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index e213aaf45d67..20831079fb09 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -384,6 +384,7 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
{
struct sctp_outq *q = &asoc->outqueue;
struct sctp_chunk *chk, *temp;
+ struct sctp_stream_out *sout;
q->sched->unsched_all(&asoc->stream);
@@ -398,12 +399,14 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
sctp_sched_dequeue_common(q, chk);
asoc->sent_cnt_removable--;
asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
- if (chk->sinfo.sinfo_stream < asoc->stream.outcnt) {
- struct sctp_stream_out *streamout =
- SCTP_SO(&asoc->stream, chk->sinfo.sinfo_stream);
- streamout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
- }
+ sout = SCTP_SO(&asoc->stream, chk->sinfo.sinfo_stream);
+ sout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
+
+ /* clear out_curr if all frag chunks are pruned */
+ if (asoc->stream.out_curr == sout &&
+ list_is_last(&chk->frag_list, &chk->msg->chunks))
+ asoc->stream.out_curr = NULL;
msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk);
sctp_chunk_free(chk);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 83628c347744..cfe72085fdc4 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -8319,7 +8319,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1;
- rover = prandom_u32_max(remaining) + low;
+ rover = get_random_u32_below(remaining) + low;
do {
rover++;
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index ef9fceadef8d..ee6514af830f 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -52,6 +52,19 @@ static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
}
}
+static void sctp_stream_free_ext(struct sctp_stream *stream, __u16 sid)
+{
+ struct sctp_sched_ops *sched;
+
+ if (!SCTP_SO(stream, sid)->ext)
+ return;
+
+ sched = sctp_sched_ops_from_stream(stream);
+ sched->free_sid(stream, sid);
+ kfree(SCTP_SO(stream, sid)->ext);
+ SCTP_SO(stream, sid)->ext = NULL;
+}
+
/* Migrates chunks from stream queues to new stream queues if needed,
* but not across associations. Also, removes those chunks to streams
* higher than the new max.
@@ -70,16 +83,14 @@ static void sctp_stream_outq_migrate(struct sctp_stream *stream,
* sctp_stream_update will swap ->out pointers.
*/
for (i = 0; i < outcnt; i++) {
- kfree(SCTP_SO(new, i)->ext);
+ sctp_stream_free_ext(new, i);
SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
SCTP_SO(stream, i)->ext = NULL;
}
}
- for (i = outcnt; i < stream->outcnt; i++) {
- kfree(SCTP_SO(stream, i)->ext);
- SCTP_SO(stream, i)->ext = NULL;
- }
+ for (i = outcnt; i < stream->outcnt; i++)
+ sctp_stream_free_ext(stream, i);
}
static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
@@ -174,9 +185,9 @@ void sctp_stream_free(struct sctp_stream *stream)
struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
int i;
- sched->free(stream);
+ sched->unsched_all(stream);
for (i = 0; i < stream->outcnt; i++)
- kfree(SCTP_SO(stream, i)->ext);
+ sctp_stream_free_ext(stream, i);
genradix_free(&stream->out);
genradix_free(&stream->in);
}
diff --git a/net/sctp/stream_sched.c b/net/sctp/stream_sched.c
index 1ad565ed5627..7c8f9d89e16a 100644
--- a/net/sctp/stream_sched.c
+++ b/net/sctp/stream_sched.c
@@ -46,6 +46,10 @@ static int sctp_sched_fcfs_init_sid(struct sctp_stream *stream, __u16 sid,
return 0;
}
+static void sctp_sched_fcfs_free_sid(struct sctp_stream *stream, __u16 sid)
+{
+}
+
static void sctp_sched_fcfs_free(struct sctp_stream *stream)
{
}
@@ -96,6 +100,7 @@ static struct sctp_sched_ops sctp_sched_fcfs = {
.get = sctp_sched_fcfs_get,
.init = sctp_sched_fcfs_init,
.init_sid = sctp_sched_fcfs_init_sid,
+ .free_sid = sctp_sched_fcfs_free_sid,
.free = sctp_sched_fcfs_free,
.enqueue = sctp_sched_fcfs_enqueue,
.dequeue = sctp_sched_fcfs_dequeue,
diff --git a/net/sctp/stream_sched_prio.c b/net/sctp/stream_sched_prio.c
index 80b5a2c4cbc7..4fc9f2923ed1 100644
--- a/net/sctp/stream_sched_prio.c
+++ b/net/sctp/stream_sched_prio.c
@@ -204,6 +204,24 @@ static int sctp_sched_prio_init_sid(struct sctp_stream *stream, __u16 sid,
return sctp_sched_prio_set(stream, sid, 0, gfp);
}
+static void sctp_sched_prio_free_sid(struct sctp_stream *stream, __u16 sid)
+{
+ struct sctp_stream_priorities *prio = SCTP_SO(stream, sid)->ext->prio_head;
+ int i;
+
+ if (!prio)
+ return;
+
+ SCTP_SO(stream, sid)->ext->prio_head = NULL;
+ for (i = 0; i < stream->outcnt; i++) {
+ if (SCTP_SO(stream, i)->ext &&
+ SCTP_SO(stream, i)->ext->prio_head == prio)
+ return;
+ }
+
+ kfree(prio);
+}
+
static void sctp_sched_prio_free(struct sctp_stream *stream)
{
struct sctp_stream_priorities *prio, *n;
@@ -323,6 +341,7 @@ static struct sctp_sched_ops sctp_sched_prio = {
.get = sctp_sched_prio_get,
.init = sctp_sched_prio_init,
.init_sid = sctp_sched_prio_init_sid,
+ .free_sid = sctp_sched_prio_free_sid,
.free = sctp_sched_prio_free,
.enqueue = sctp_sched_prio_enqueue,
.dequeue = sctp_sched_prio_dequeue,
diff --git a/net/sctp/stream_sched_rr.c b/net/sctp/stream_sched_rr.c
index ff425aed62c7..cc444fe0d67c 100644
--- a/net/sctp/stream_sched_rr.c
+++ b/net/sctp/stream_sched_rr.c
@@ -90,6 +90,10 @@ static int sctp_sched_rr_init_sid(struct sctp_stream *stream, __u16 sid,
return 0;
}
+static void sctp_sched_rr_free_sid(struct sctp_stream *stream, __u16 sid)
+{
+}
+
static void sctp_sched_rr_free(struct sctp_stream *stream)
{
sctp_sched_rr_unsched_all(stream);
@@ -177,6 +181,7 @@ static struct sctp_sched_ops sctp_sched_rr = {
.get = sctp_sched_rr_get,
.init = sctp_sched_rr_init,
.init_sid = sctp_sched_rr_init_sid,
+ .free_sid = sctp_sched_rr_free_sid,
.free = sctp_sched_rr_free,
.enqueue = sctp_sched_rr_enqueue,
.dequeue = sctp_sched_rr_dequeue,
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index f8fd98784977..ca1eba95c293 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -199,7 +199,7 @@ void sctp_transport_reset_hb_timer(struct sctp_transport *transport)
if ((time_before(transport->hb_timer.expires, expires) ||
!timer_pending(&transport->hb_timer)) &&
!mod_timer(&transport->hb_timer,
- expires + prandom_u32_max(transport->rto)))
+ expires + get_random_u32_below(transport->rto)))
sctp_transport_hold(transport);
}
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index 1472f31480d8..dfb9797f7bc6 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -673,7 +673,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
*/
krflags = MSG_PEEK | MSG_WAITALL;
clc_sk->sk_rcvtimeo = timeout;
- iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1,
sizeof(struct smc_clc_msg_hdr));
len = sock_recvmsg(smc->clcsock, &msg, krflags);
if (signal_pending(current)) {
@@ -720,7 +720,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
} else {
recvlen = datlen;
}
- iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
krflags = MSG_WAITALL;
len = sock_recvmsg(smc->clcsock, &msg, krflags);
if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
@@ -737,7 +737,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
/* receive remaining proposal message */
recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
SMC_CLC_RECV_BUF_LEN : datlen;
- iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
len = sock_recvmsg(smc->clcsock, &msg, krflags);
datlen -= len;
}
diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c
index 64dedffe9d26..f4b6a71ac488 100644
--- a/net/smc/smc_tx.c
+++ b/net/smc/smc_tx.c
@@ -308,7 +308,7 @@ int smc_tx_sendpage(struct smc_sock *smc, struct page *page, int offset,
iov.iov_base = kaddr + offset;
iov.iov_len = size;
- iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size);
rc = smc_tx_sendmsg(smc, &msg, size);
kunmap(page);
return rc;
diff --git a/net/socket.c b/net/socket.c
index 00da9ce3dba0..73463c7c3702 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -750,7 +750,7 @@ EXPORT_SYMBOL(sock_sendmsg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size)
{
- iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
+ iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
return sock_sendmsg(sock, msg);
}
EXPORT_SYMBOL(kernel_sendmsg);
@@ -776,7 +776,7 @@ int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
if (!sock->ops->sendmsg_locked)
return sock_no_sendmsg_locked(sk, msg, size);
- iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
+ iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
}
@@ -1034,7 +1034,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size, int flags)
{
msg->msg_control_is_user = false;
- iov_iter_kvec(&msg->msg_iter, READ, vec, num, size);
+ iov_iter_kvec(&msg->msg_iter, ITER_DEST, vec, num, size);
return sock_recvmsg(sock, msg, flags);
}
EXPORT_SYMBOL(kernel_recvmsg);
@@ -2092,7 +2092,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
struct iovec iov;
int fput_needed;
- err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter);
+ err = import_single_range(ITER_SOURCE, buff, len, &iov, &msg.msg_iter);
if (unlikely(err))
return err;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
@@ -2157,7 +2157,7 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
int err, err2;
int fput_needed;
- err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter);
+ err = import_single_range(ITER_DEST, ubuf, size, &iov, &msg.msg_iter);
if (unlikely(err))
return err;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
@@ -2417,7 +2417,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
if (err)
return err;
- err = import_iovec(save_addr ? READ : WRITE,
+ err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE,
msg.msg_iov, msg.msg_iovlen,
UIO_FASTIOV, iov, &kmsg->msg_iter);
return err < 0 ? err : 0;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index bcd74dddbe2d..148bb0a7fa5b 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -49,11 +49,36 @@
#include <linux/sunrpc/svcauth.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/cache.h>
+#include <linux/sunrpc/gss_krb5.h>
#include <trace/events/rpcgss.h>
#include "gss_rpc_upcall.h"
+/*
+ * Unfortunately there isn't a maximum checksum size exported via the
+ * GSS API. Manufacture one based on GSS mechanisms supported by this
+ * implementation.
+ */
+#define GSS_MAX_CKSUMSIZE (GSS_KRB5_TOK_HDR_LEN + GSS_KRB5_MAX_CKSUM_LEN)
+
+/*
+ * This value may be increased in the future to accommodate other
+ * usage of the scratch buffer.
+ */
+#define GSS_SCRATCH_SIZE GSS_MAX_CKSUMSIZE
+
+struct gss_svc_data {
+ /* decoded gss client cred: */
+ struct rpc_gss_wire_cred clcred;
+ /* save a pointer to the beginning of the encoded verifier,
+ * for use in encryption/checksumming in svcauth_gss_release: */
+ __be32 *verf_start;
+ struct rsc *rsci;
+
+ /* for temporary results */
+ u8 gsd_scratch[GSS_SCRATCH_SIZE];
+};
/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
* into replies.
@@ -887,13 +912,11 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
static int
unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
{
+ struct gss_svc_data *gsd = rqstp->rq_auth_data;
u32 integ_len, rseqno, maj_stat;
- int stat = -EINVAL;
struct xdr_netobj mic;
struct xdr_buf integ_buf;
- mic.data = NULL;
-
/* NFS READ normally uses splice to send data in-place. However
* the data in cache can change after the reply's MIC is computed
* but before the RPC reply is sent. To prevent the client from
@@ -917,11 +940,9 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
/* copy out mic... */
if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
goto unwrap_failed;
- if (mic.len > RPC_MAX_AUTH_SIZE)
- goto unwrap_failed;
- mic.data = kmalloc(mic.len, GFP_KERNEL);
- if (!mic.data)
+ if (mic.len > sizeof(gsd->gsd_scratch))
goto unwrap_failed;
+ mic.data = gsd->gsd_scratch;
if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
goto unwrap_failed;
maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
@@ -932,20 +953,17 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
goto bad_seqno;
/* trim off the mic and padding at the end before returning */
xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4);
- stat = 0;
-out:
- kfree(mic.data);
- return stat;
+ return 0;
unwrap_failed:
trace_rpcgss_svc_unwrap_failed(rqstp);
- goto out;
+ return -EINVAL;
bad_seqno:
trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno);
- goto out;
+ return -EINVAL;
bad_mic:
trace_rpcgss_svc_mic(rqstp, maj_stat);
- goto out;
+ return -EINVAL;
}
static inline int
@@ -1023,15 +1041,6 @@ bad_unwrap:
return -EINVAL;
}
-struct gss_svc_data {
- /* decoded gss client cred: */
- struct rpc_gss_wire_cred clcred;
- /* save a pointer to the beginning of the encoded verifier,
- * for use in encryption/checksumming in svcauth_gss_release: */
- __be32 *verf_start;
- struct rsc *rsci;
-};
-
static int
svcauth_gss_set_client(struct svc_rqst *rqstp)
{
@@ -1162,18 +1171,23 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
return res;
inlen = svc_getnl(argv);
- if (inlen > (argv->iov_len + rqstp->rq_arg.page_len))
+ if (inlen > (argv->iov_len + rqstp->rq_arg.page_len)) {
+ kfree(in_handle->data);
return SVC_DENIED;
+ }
pages = DIV_ROUND_UP(inlen, PAGE_SIZE);
in_token->pages = kcalloc(pages, sizeof(struct page *), GFP_KERNEL);
- if (!in_token->pages)
+ if (!in_token->pages) {
+ kfree(in_handle->data);
return SVC_DENIED;
+ }
in_token->page_base = 0;
in_token->page_len = inlen;
for (i = 0; i < pages; i++) {
in_token->pages[i] = alloc_page(GFP_KERNEL);
if (!in_token->pages[i]) {
+ kfree(in_handle->data);
gss_free_in_token_pages(in_token);
return SVC_DENIED;
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index f075a9fb5ccc..95ff74706104 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -677,7 +677,7 @@ static void cache_limit_defers(void)
/* Consider removing either the first or the last */
if (cache_defer_cnt > DFR_MAX) {
- if (prandom_u32_max(2))
+ if (get_random_u32_below(2))
discard = list_entry(cache_defer_list.next,
struct cache_deferred_req, recent);
else
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 993acf38af87..0b0b9f1eed46 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1442,7 +1442,7 @@ static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
break;
default:
err = -EAFNOSUPPORT;
- goto out;
+ goto out_release;
}
if (err < 0) {
dprintk("RPC: can't bind UDP socket (%d)\n", err);
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index 71ba4cf513bc..1b2b84feeec6 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -214,14 +214,14 @@ static inline int xprt_sendmsg(struct socket *sock, struct msghdr *msg,
static int xprt_send_kvec(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t seek)
{
- iov_iter_kvec(&msg->msg_iter, WRITE, vec, 1, vec->iov_len);
+ iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, 1, vec->iov_len);
return xprt_sendmsg(sock, msg, seek);
}
static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg,
struct xdr_buf *xdr, size_t base)
{
- iov_iter_bvec(&msg->msg_iter, WRITE, xdr->bvec, xdr_buf_pagecount(xdr),
+ iov_iter_bvec(&msg->msg_iter, ITER_SOURCE, xdr->bvec, xdr_buf_pagecount(xdr),
xdr->page_len + xdr->page_base);
return xprt_sendmsg(sock, msg, base + xdr->page_base);
}
@@ -244,7 +244,7 @@ static int xprt_send_rm_and_kvec(struct socket *sock, struct msghdr *msg,
};
size_t len = iov[0].iov_len + iov[1].iov_len;
- iov_iter_kvec(&msg->msg_iter, WRITE, iov, 2, len);
+ iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, iov, 2, len);
return xprt_sendmsg(sock, msg, base);
}
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 149171774bc6..8f1b596db33f 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -638,7 +638,6 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
return rqstp;
__set_bit(RQ_BUSY, &rqstp->rq_flags);
- spin_lock_init(&rqstp->rq_lock);
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
@@ -1281,8 +1280,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
/* Also give the program a chance to reject this call: */
if (auth_res == SVC_OK && progp)
auth_res = progp->pg_authenticate(rqstp);
- if (auth_res != SVC_OK)
- trace_svc_authenticate(rqstp, auth_res);
+ trace_svc_authenticate(rqstp, auth_res);
switch (auth_res) {
case SVC_OK:
break;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 2fc98fea59b4..015714398007 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -260,7 +260,7 @@ static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen,
rqstp->rq_respages = &rqstp->rq_pages[i];
rqstp->rq_next_page = rqstp->rq_respages + 1;
- iov_iter_bvec(&msg.msg_iter, READ, bvec, i, buflen);
+ iov_iter_bvec(&msg.msg_iter, ITER_DEST, bvec, i, buflen);
if (seek) {
iov_iter_advance(&msg.msg_iter, seek);
buflen -= seek;
@@ -874,7 +874,7 @@ static ssize_t svc_tcp_read_marker(struct svc_sock *svsk,
want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
iov.iov_len = want;
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, want);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);
len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
if (len < 0)
return len;
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 336a7c7833e4..f7767bf22406 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -1224,30 +1224,34 @@ EXPORT_SYMBOL(xdr_restrict_buflen);
/**
* xdr_write_pages - Insert a list of pages into an XDR buffer for sending
* @xdr: pointer to xdr_stream
- * @pages: list of pages
- * @base: offset of first byte
- * @len: length of data in bytes
+ * @pages: array of pages to insert
+ * @base: starting offset of first data byte in @pages
+ * @len: number of data bytes in @pages to insert
*
+ * After the @pages are added, the tail iovec is instantiated pointing to
+ * end of the head buffer, and the stream is set up to encode subsequent
+ * items into the tail.
*/
void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
unsigned int len)
{
struct xdr_buf *buf = xdr->buf;
- struct kvec *iov = buf->tail;
+ struct kvec *tail = buf->tail;
+
buf->pages = pages;
buf->page_base = base;
buf->page_len = len;
- iov->iov_base = (char *)xdr->p;
- iov->iov_len = 0;
- xdr->iov = iov;
+ tail->iov_base = xdr->p;
+ tail->iov_len = 0;
+ xdr->iov = tail;
if (len & 3) {
unsigned int pad = 4 - (len & 3);
BUG_ON(xdr->p >= xdr->end);
- iov->iov_base = (char *)xdr->p + (len & 3);
- iov->iov_len += pad;
+ tail->iov_base = (char *)xdr->p + (len & 3);
+ tail->iov_len += pad;
len += pad;
*xdr->p++ = 0;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 656cec208371..ab453ede54f0 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1164,7 +1164,7 @@ xprt_request_enqueue_receive(struct rpc_task *task)
spin_unlock(&xprt->queue_lock);
/* Turn off autodisconnect */
- del_singleshot_timer_sync(&xprt->timer);
+ del_timer_sync(&xprt->timer);
return 0;
}
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 44b87e4274b4..b098fde373ab 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -831,7 +831,7 @@ struct rpcrdma_req *rpcrdma_req_create(struct rpcrdma_xprt *r_xprt,
return req;
out3:
- kfree(req->rl_sendbuf);
+ rpcrdma_regbuf_free(req->rl_sendbuf);
out2:
kfree(req);
out1:
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 915b9902f673..c0506d0d7478 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -364,7 +364,7 @@ static ssize_t
xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags,
struct kvec *kvec, size_t count, size_t seek)
{
- iov_iter_kvec(&msg->msg_iter, READ, kvec, 1, count);
+ iov_iter_kvec(&msg->msg_iter, ITER_DEST, kvec, 1, count);
return xs_sock_recvmsg(sock, msg, flags, seek);
}
@@ -373,7 +373,7 @@ xs_read_bvec(struct socket *sock, struct msghdr *msg, int flags,
struct bio_vec *bvec, unsigned long nr, size_t count,
size_t seek)
{
- iov_iter_bvec(&msg->msg_iter, READ, bvec, nr, count);
+ iov_iter_bvec(&msg->msg_iter, ITER_DEST, bvec, nr, count);
return xs_sock_recvmsg(sock, msg, flags, seek);
}
@@ -381,7 +381,7 @@ static ssize_t
xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
size_t count)
{
- iov_iter_discard(&msg->msg_iter, READ, count);
+ iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
return sock_recvmsg(sock, msg, flags);
}
@@ -1619,7 +1619,7 @@ static int xs_get_random_port(void)
if (max < min)
return -EADDRINUSE;
range = max - min + 1;
- rand = prandom_u32_max(range);
+ rand = get_random_u32_below(range);
return rand + min;
}
diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
index f09316a9035f..d67440de011e 100644
--- a/net/tipc/crypto.c
+++ b/net/tipc/crypto.c
@@ -1971,6 +1971,9 @@ rcv:
/* Ok, everything's fine, try to synch own keys according to peers' */
tipc_crypto_key_synch(rx, *skb);
+ /* Re-fetch skb cb as skb might be changed in tipc_msg_validate */
+ skb_cb = TIPC_SKB_CB(*skb);
+
/* Mark skb decrypted */
skb_cb->decrypted = 1;
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index e8630707901e..e8dcdf267c0c 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -211,7 +211,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
u32 self;
int err;
- skb_linearize(skb);
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
+ return;
+ }
hdr = buf_msg(skb);
if (caps & TIPC_NODE_ID128)
diff --git a/net/tipc/link.c b/net/tipc/link.c
index e260c0d557f5..b3ce24823f50 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2224,7 +2224,9 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
if (tipc_own_addr(l->net) > msg_prevnode(hdr))
l->net_plane = msg_net_plane(hdr);
- skb_linearize(skb);
+ if (skb_linearize(skb))
+ goto exit;
+
hdr = buf_msg(skb);
data = msg_data(hdr);
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index fc68733673ba..dfea27a906f2 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -880,7 +880,7 @@ static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg)
};
ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
- if (TLV_GET_DATA_LEN(msg->req) < sizeof(struct tipc_name_table_query))
+ if (TLV_GET_DATA_LEN(msg->req) < (int)sizeof(struct tipc_name_table_query))
return -EINVAL;
depth = ntohl(ntq->depth);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index b48d97cbbe29..49ddc484c4fe 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1689,6 +1689,7 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
struct tipc_node *n;
struct sk_buff_head xmitq;
bool node_up = false;
+ struct net *peer_net;
int bearer_id;
int rc;
@@ -1705,18 +1706,23 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
return -EHOSTUNREACH;
}
+ rcu_read_lock();
tipc_node_read_lock(n);
node_up = node_is_up(n);
- if (node_up && n->peer_net && check_net(n->peer_net)) {
+ peer_net = n->peer_net;
+ tipc_node_read_unlock(n);
+ if (node_up && peer_net && check_net(peer_net)) {
/* xmit inner linux container */
- tipc_lxc_xmit(n->peer_net, list);
+ tipc_lxc_xmit(peer_net, list);
if (likely(skb_queue_empty(list))) {
- tipc_node_read_unlock(n);
+ rcu_read_unlock();
tipc_node_put(n);
return 0;
}
}
+ rcu_read_unlock();
+ tipc_node_read_lock(n);
bearer_id = n->active_links[selector & 1];
if (unlikely(bearer_id == INVALID_BEARER_ID)) {
tipc_node_read_unlock(n);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index e902b01ea3cb..b35c8701876a 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -3010,7 +3010,7 @@ static int tipc_sk_insert(struct tipc_sock *tsk)
struct net *net = sock_net(sk);
struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 remaining = (TIPC_MAX_PORT - TIPC_MIN_PORT) + 1;
- u32 portid = prandom_u32_max(remaining) + TIPC_MIN_PORT;
+ u32 portid = get_random_u32_below(remaining) + TIPC_MIN_PORT;
while (remaining--) {
portid++;
diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c
index d92ec92f0b71..69c88cc03887 100644
--- a/net/tipc/topsrv.c
+++ b/net/tipc/topsrv.c
@@ -176,7 +176,7 @@ static void tipc_conn_close(struct tipc_conn *con)
conn_put(con);
}
-static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s)
+static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s, struct socket *sock)
{
struct tipc_conn *con;
int ret;
@@ -202,10 +202,12 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s)
}
con->conid = ret;
s->idr_in_use++;
- spin_unlock_bh(&s->idr_lock);
set_bit(CF_CONNECTED, &con->flags);
con->server = s;
+ con->sock = sock;
+ conn_get(con);
+ spin_unlock_bh(&s->idr_lock);
return con;
}
@@ -394,7 +396,7 @@ static int tipc_conn_rcv_from_sock(struct tipc_conn *con)
iov.iov_base = &s;
iov.iov_len = sizeof(s);
msg.msg_name = NULL;
- iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, iov.iov_len);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, iov.iov_len);
ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
if (ret == -EWOULDBLOCK)
return -EWOULDBLOCK;
@@ -467,7 +469,7 @@ static void tipc_topsrv_accept(struct work_struct *work)
ret = kernel_accept(lsock, &newsock, O_NONBLOCK);
if (ret < 0)
return;
- con = tipc_conn_alloc(srv);
+ con = tipc_conn_alloc(srv, newsock);
if (IS_ERR(con)) {
ret = PTR_ERR(con);
sock_release(newsock);
@@ -479,11 +481,11 @@ static void tipc_topsrv_accept(struct work_struct *work)
newsk->sk_data_ready = tipc_conn_data_ready;
newsk->sk_write_space = tipc_conn_write_space;
newsk->sk_user_data = con;
- con->sock = newsock;
write_unlock_bh(&newsk->sk_callback_lock);
/* Wake up receive process in case of 'SYN+' message */
newsk->sk_data_ready(newsk);
+ conn_put(con);
}
}
@@ -577,17 +579,17 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
sub.filter = filter;
*(u64 *)&sub.usr_handle = (u64)port;
- con = tipc_conn_alloc(tipc_topsrv(net));
+ con = tipc_conn_alloc(tipc_topsrv(net), NULL);
if (IS_ERR(con))
return false;
*conid = con->conid;
- con->sock = NULL;
rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub);
- if (rc >= 0)
- return true;
+ if (rc)
+ conn_put(con);
+
conn_put(con);
- return false;
+ return !rc;
}
void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index a03d66046ca3..6c593788dc25 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -620,7 +620,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page,
kaddr = kmap(page);
iov.iov_base = kaddr + offset;
iov.iov_len = size;
- iov_iter_kvec(&msg_iter, WRITE, &iov, 1, size);
+ iov_iter_kvec(&msg_iter, ITER_SOURCE, &iov, 1, size);
iter_offset.msg_iter = &msg_iter;
rc = tls_push_data(sk, iter_offset, size, flags, TLS_RECORD_TYPE_DATA,
NULL);
@@ -697,7 +697,7 @@ static int tls_device_push_pending_record(struct sock *sk, int flags)
union tls_iter_offset iter;
struct iov_iter msg_iter;
- iov_iter_kvec(&msg_iter, WRITE, NULL, 0, 0);
+ iov_iter_kvec(&msg_iter, ITER_SOURCE, NULL, 0, 0);
iter.msg_iter = &msg_iter;
return tls_push_data(sk, iter, 0, flags, TLS_RECORD_TYPE_DATA, NULL);
}
diff --git a/net/tls/tls_device_fallback.c b/net/tls/tls_device_fallback.c
index cdb391a8754b..7fbb1d0b69b3 100644
--- a/net/tls/tls_device_fallback.c
+++ b/net/tls/tls_device_fallback.c
@@ -346,7 +346,7 @@ static struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx,
salt = tls_ctx->crypto_send.aes_gcm_256.salt;
break;
default:
- return NULL;
+ goto free_req;
}
cipher_sz = &tls_cipher_size_desc[tls_ctx->crypto_send.info.cipher_type];
buf_len = cipher_sz->salt + cipher_sz->iv + TLS_AAD_SPACE_SIZE +
@@ -492,7 +492,8 @@ int tls_sw_fallback_init(struct sock *sk,
key = ((struct tls12_crypto_info_aes_gcm_256 *)crypto_info)->key;
break;
default:
- return -EINVAL;
+ rc = -EINVAL;
+ goto free_aead;
}
cipher_sz = &tls_cipher_size_desc[crypto_info->cipher_type];
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 105f522a89fe..616b55c5b890 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -114,14 +114,16 @@ static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
return nla_put(nlskb, UNIX_DIAG_RQLEN, sizeof(rql), &rql);
}
-static int sk_diag_dump_uid(struct sock *sk, struct sk_buff *nlskb)
+static int sk_diag_dump_uid(struct sock *sk, struct sk_buff *nlskb,
+ struct user_namespace *user_ns)
{
- uid_t uid = from_kuid_munged(sk_user_ns(nlskb->sk), sock_i_uid(sk));
+ uid_t uid = from_kuid_munged(user_ns, sock_i_uid(sk));
return nla_put(nlskb, UNIX_DIAG_UID, sizeof(uid_t), &uid);
}
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
- u32 portid, u32 seq, u32 flags, int sk_ino)
+ struct user_namespace *user_ns,
+ u32 portid, u32 seq, u32 flags, int sk_ino)
{
struct nlmsghdr *nlh;
struct unix_diag_msg *rep;
@@ -167,7 +169,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
goto out_nlmsg_trim;
if ((req->udiag_show & UDIAG_SHOW_UID) &&
- sk_diag_dump_uid(sk, skb))
+ sk_diag_dump_uid(sk, skb, user_ns))
goto out_nlmsg_trim;
nlmsg_end(skb, nlh);
@@ -179,7 +181,8 @@ out_nlmsg_trim:
}
static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
- u32 portid, u32 seq, u32 flags)
+ struct user_namespace *user_ns,
+ u32 portid, u32 seq, u32 flags)
{
int sk_ino;
@@ -190,7 +193,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
if (!sk_ino)
return 0;
- return sk_diag_fill(sk, skb, req, portid, seq, flags, sk_ino);
+ return sk_diag_fill(sk, skb, req, user_ns, portid, seq, flags, sk_ino);
}
static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@ -214,7 +217,7 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
goto next;
if (!(req->udiag_states & (1 << sk->sk_state)))
goto next;
- if (sk_diag_dump(sk, skb, req,
+ if (sk_diag_dump(sk, skb, req, sk_user_ns(skb->sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI) < 0) {
@@ -282,7 +285,8 @@ again:
if (!rep)
goto out;
- err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).portid,
+ err = sk_diag_fill(sk, rep, req, sk_user_ns(NETLINK_CB(in_skb).sk),
+ NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, req->udiag_ino);
if (err < 0) {
nlmsg_free(rep);
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 884eca7f6743..d593d5b6d4b1 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -626,8 +626,7 @@ static int __vsock_bind_connectible(struct vsock_sock *vsk,
struct sockaddr_vm new_addr;
if (!port)
- port = LAST_RESERVED_PORT + 1 +
- prandom_u32_max(U32_MAX - LAST_RESERVED_PORT);
+ port = get_random_u32_above(LAST_RESERVED_PORT);
vsock_addr_init(&new_addr, addr->svm_cid, addr->svm_port);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index d5c7a5aa6853..c3d950d29432 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1084,6 +1084,8 @@ MODULE_FIRMWARE("regulatory.db");
static int query_regdb_file(const char *alpha2)
{
+ int err;
+
ASSERT_RTNL();
if (regdb)
@@ -1093,9 +1095,13 @@ static int query_regdb_file(const char *alpha2)
if (!alpha2)
return -ENOMEM;
- return request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
- &reg_pdev->dev, GFP_KERNEL,
- (void *)alpha2, regdb_fw_cb);
+ err = request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
+ &reg_pdev->dev, GFP_KERNEL,
+ (void *)alpha2, regdb_fw_cb);
+ if (err)
+ kfree(alpha2);
+
+ return err;
}
int reg_reload_regdb(void)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 806a5f1330ff..3d86482e83f5 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -330,7 +330,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
* determine if they are the same ie.
*/
if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
- if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
+ if (tmp_old[1] >= 5 && tmp[1] >= 5 &&
+ !memcmp(tmp_old + 2, tmp + 2, 5)) {
/* same vendor ie, copy from
* subelement
*/
@@ -1674,7 +1675,9 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
if (old == rcu_access_pointer(known->pub.ies))
rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
- cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
+ cfg80211_update_hidden_bsses(known,
+ rcu_access_pointer(new->pub.beacon_ies),
+ old);
if (old)
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
@@ -2524,10 +2527,15 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
const struct cfg80211_bss_ies *ies1, *ies2;
size_t ielen = len - offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
- struct cfg80211_non_tx_bss non_tx_data;
+ struct cfg80211_non_tx_bss non_tx_data = {};
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
len, gfp);
+
+ /* don't do any further MBSSID handling for S1G */
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control))
+ return res;
+
if (!res || !wiphy->support_mbssid ||
!cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
return res;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 1f285b515028..39680e7bad45 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1557,10 +1557,12 @@ static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate)
tmp = result;
tmp *= SCALE;
do_div(tmp, mcs_divisors[rate->mcs]);
- result = tmp;
/* and take NSS */
- result = (result * rate->nss) / 8;
+ tmp *= rate->nss;
+ do_div(tmp, 8);
+
+ result = tmp;
return result / 10000;
}
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 5259ef8f5242..748d8630ab58 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -117,7 +117,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
if (!pskb_may_pull(skb, 1)) {
x25_neigh_put(nb);
- return 0;
+ goto drop;
}
switch (skb->data[0]) {
diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c
index 29a540dcb5a7..d6fece1ed982 100644
--- a/net/xfrm/espintcp.c
+++ b/net/xfrm/espintcp.c
@@ -354,7 +354,7 @@ static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
*((__be16 *)buf) = cpu_to_be16(msglen);
pfx_iov.iov_base = buf;
pfx_iov.iov_len = sizeof(buf);
- iov_iter_kvec(&pfx_iter, WRITE, &pfx_iov, 1, pfx_iov.iov_len);
+ iov_iter_kvec(&pfx_iter, ITER_SOURCE, &pfx_iov, 1, pfx_iov.iov_len);
err = sk_msg_memcopy_from_iter(sk, &pfx_iter, &emsg->skmsg,
pfx_iov.iov_len);
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 5f5aafd418af..21269e8f2db4 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -97,6 +97,18 @@ static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb)
}
}
+static inline bool xmit_xfrm_check_overflow(struct sk_buff *skb)
+{
+ struct xfrm_offload *xo = xfrm_offload(skb);
+ __u32 seq = xo->seq.low;
+
+ seq += skb_shinfo(skb)->gso_segs;
+ if (unlikely(seq < xo->seq.low))
+ return true;
+
+ return false;
+}
+
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
{
int err;
@@ -134,7 +146,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
return skb;
}
- if (skb_is_gso(skb) && unlikely(x->xso.dev != dev)) {
+ if (skb_is_gso(skb) && (unlikely(x->xso.dev != dev) ||
+ unlikely(xmit_xfrm_check_overflow(skb)))) {
struct sk_buff *segs;
/* Packet got rerouted, fixup features and segment it. */
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index 9f4d42eb090f..ce56d659c55a 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -714,7 +714,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff
oseq += skb_shinfo(skb)->gso_segs;
}
- if (unlikely(oseq < replay_esn->oseq)) {
+ if (unlikely(xo->seq.low < replay_esn->oseq)) {
XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
xo->seq.hi = oseq_hi;
replay_esn->oseq_hi = oseq_hi;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 3d2fe7712ac5..d63a3644ee1a 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2072,7 +2072,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
} else {
u32 spi = 0;
for (h = 0; h < high-low+1; h++) {
- spi = low + prandom_u32_max(high - low + 1);
+ spi = get_random_u32_inclusive(low, high);
x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
if (x0 == NULL) {
newspi = htonl(spi);
diff --git a/rust/Makefile b/rust/Makefile
index 7700d3853404..ff70c4c916f8 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -19,6 +19,12 @@ obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
exports_kernel_generated.h
+ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
+obj-$(CONFIG_RUST) += build_error.o
+else
+always-$(CONFIG_RUST) += build_error.o
+endif
+
obj-$(CONFIG_RUST) += exports.o
# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
@@ -108,7 +114,7 @@ rustdoc-alloc: $(src)/alloc/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE
$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern alloc \
- --extern macros=$(objtree)/$(obj)/libmacros.so \
+ --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
--extern bindings
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
@@ -126,6 +132,9 @@ quiet_cmd_rustc_test_library = RUSTC TL $<
-L$(objtree)/$(obj)/test \
--crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<
+rusttestlib-build_error: $(src)/build_error.rs rusttest-prepare FORCE
+ $(call if_changed,rustc_test_library)
+
rusttestlib-macros: private rustc_target_flags = --extern proc_macro
rusttestlib-macros: private rustc_test_library_proc = yes
rusttestlib-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
@@ -216,9 +225,9 @@ rusttest-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
$(call if_changed,rustdoc_test)
rusttest-kernel: private rustc_target_flags = --extern alloc \
- --extern macros --extern bindings
+ --extern build_error --extern macros --extern bindings
rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \
- rusttestlib-macros rusttestlib-bindings FORCE
+ rusttestlib-build_error rusttestlib-macros rusttestlib-bindings FORCE
$(call if_changed,rustc_test)
$(call if_changed,rustc_test_library)
@@ -366,6 +375,9 @@ $(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs)
$(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE
$(call if_changed_dep,rustc_library)
+$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
+ $(call if_changed_dep,rustc_library)
+
$(obj)/bindings.o: $(src)/bindings/lib.rs \
$(obj)/compiler_builtins.o \
$(obj)/bindings/bindings_generated.rs \
@@ -373,8 +385,8 @@ $(obj)/bindings.o: $(src)/bindings/lib.rs \
$(call if_changed_dep,rustc_library)
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
- --extern macros --extern bindings
-$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o \
+ --extern build_error --extern macros --extern bindings
+$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
$(obj)/libmacros.so $(obj)/bindings.o FORCE
$(call if_changed_dep,rustc_library)
diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
index daf5f2da7168..eb77db5def55 100644
--- a/rust/alloc/raw_vec.rs
+++ b/rust/alloc/raw_vec.rs
@@ -20,11 +20,11 @@ use crate::collections::TryReserveErrorKind::*;
#[cfg(test)]
mod tests;
-#[cfg(not(no_global_oom_handling))]
enum AllocInit {
/// The contents of the new memory are uninitialized.
Uninitialized,
/// The new memory is guaranteed to be zeroed.
+ #[allow(dead_code)]
Zeroed,
}
@@ -133,6 +133,13 @@ impl<T, A: Allocator> RawVec<T, A> {
Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
}
+ /// Like `try_with_capacity`, but parameterized over the choice of
+ /// allocator for the returned `RawVec`.
+ #[inline]
+ pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+ Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
+ }
+
/// Like `with_capacity_zeroed`, but parameterized over the choice
/// of allocator for the returned `RawVec`.
#[cfg(not(no_global_oom_handling))]
@@ -203,6 +210,30 @@ impl<T, A: Allocator> RawVec<T, A> {
}
}
+ fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
+ // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
+ if mem::size_of::<T>() == 0 || capacity == 0 {
+ return Ok(Self::new_in(alloc));
+ }
+
+ let layout = Layout::array::<T>(capacity).map_err(|_| CapacityOverflow)?;
+ alloc_guard(layout.size())?;
+ let result = match init {
+ AllocInit::Uninitialized => alloc.allocate(layout),
+ AllocInit::Zeroed => alloc.allocate_zeroed(layout),
+ };
+ let ptr = result.map_err(|_| AllocError { layout, non_exhaustive: () })?;
+
+ // Allocators currently return a `NonNull<[u8]>` whose length
+ // matches the size requested. If that ever changes, the capacity
+ // here should change to `ptr.len() / mem::size_of::<T>()`.
+ Ok(Self {
+ ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
+ cap: capacity,
+ alloc,
+ })
+ }
+
/// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
///
/// # Safety
diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
index 540787804cc2..8ac6c1e3b2a8 100644
--- a/rust/alloc/vec/mod.rs
+++ b/rust/alloc/vec/mod.rs
@@ -472,6 +472,48 @@ impl<T> Vec<T> {
Self::with_capacity_in(capacity, Global)
}
+ /// Tries to construct a new, empty `Vec<T>` with the specified capacity.
+ ///
+ /// The vector will be able to hold exactly `capacity` elements without
+ /// reallocating. If `capacity` is 0, the vector will not allocate.
+ ///
+ /// It is important to note that although the returned vector has the
+ /// *capacity* specified, the vector will have a zero *length*. For an
+ /// explanation of the difference between length and capacity, see
+ /// *[Capacity and reallocation]*.
+ ///
+ /// [Capacity and reallocation]: #capacity-and-reallocation
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = Vec::try_with_capacity(10).unwrap();
+ ///
+ /// // The vector contains no items, even though it has capacity for more
+ /// assert_eq!(vec.len(), 0);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // These are all done without reallocating...
+ /// for i in 0..10 {
+ /// vec.push(i);
+ /// }
+ /// assert_eq!(vec.len(), 10);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // ...but this may make the vector reallocate
+ /// vec.push(11);
+ /// assert_eq!(vec.len(), 11);
+ /// assert!(vec.capacity() >= 11);
+ ///
+ /// let mut result = Vec::try_with_capacity(usize::MAX);
+ /// assert!(result.is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "kernel", since = "1.0.0")]
+ pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
+ Self::try_with_capacity_in(capacity, Global)
+ }
+
/// Creates a `Vec<T>` directly from the raw components of another vector.
///
/// # Safety
@@ -617,6 +659,53 @@ impl<T, A: Allocator> Vec<T, A> {
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
}
+ /// Tries to construct a new, empty `Vec<T, A>` with the specified capacity
+ /// with the provided allocator.
+ ///
+ /// The vector will be able to hold exactly `capacity` elements without
+ /// reallocating. If `capacity` is 0, the vector will not allocate.
+ ///
+ /// It is important to note that although the returned vector has the
+ /// *capacity* specified, the vector will have a zero *length*. For an
+ /// explanation of the difference between length and capacity, see
+ /// *[Capacity and reallocation]*.
+ ///
+ /// [Capacity and reallocation]: #capacity-and-reallocation
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap();
+ ///
+ /// // The vector contains no items, even though it has capacity for more
+ /// assert_eq!(vec.len(), 0);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // These are all done without reallocating...
+ /// for i in 0..10 {
+ /// vec.push(i);
+ /// }
+ /// assert_eq!(vec.len(), 10);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // ...but this may make the vector reallocate
+ /// vec.push(11);
+ /// assert_eq!(vec.len(), 11);
+ /// assert!(vec.capacity() >= 11);
+ ///
+ /// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
+ /// assert!(result.is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "kernel", since = "1.0.0")]
+ pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+ Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
+ }
+
/// Creates a `Vec<T, A>` directly from the raw components of another vector.
///
/// # Safety
diff --git a/rust/build_error.rs b/rust/build_error.rs
new file mode 100644
index 000000000000..fa24eeef9929
--- /dev/null
+++ b/rust/build_error.rs
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time error.
+//!
+//! This crate provides a [const function][const-functions] `build_error`, which will panic in
+//! compile-time if executed in [const context][const-context], and will cause a build error
+//! if not executed at compile time and the optimizer does not optimise away the call.
+//!
+//! It is used by `build_assert!` in the kernel crate, allowing checking of
+//! conditions that could be checked statically, but could not be enforced in
+//! Rust yet (e.g. perform some checks in [const functions][const-functions], but those
+//! functions could still be called in the runtime).
+//!
+//! For details on constant evaluation in Rust, please see the [Reference][const-eval].
+//!
+//! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html
+//! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions
+//! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+
+#![no_std]
+
+/// Panics if executed in [const context][const-context], or triggers a build error if not.
+///
+/// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+#[inline(never)]
+#[cold]
+#[export_name = "rust_build_error"]
+#[track_caller]
+pub const fn build_error(msg: &'static str) -> ! {
+ panic!("{}", msg);
+}
diff --git a/rust/exports.c b/rust/exports.c
index bb7cc64cecd0..83e2a7070cae 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -19,3 +19,8 @@
#include "exports_alloc_generated.h"
#include "exports_bindings_generated.h"
#include "exports_kernel_generated.h"
+
+// For modules using `rust/build_error.rs`.
+#ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
+EXPORT_SYMBOL_RUST_GPL(rust_build_error);
+#endif
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..659542393c09
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+///
+/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
+/// // foo(usize::MAX); // Fails to compile.
+/// ```
+#[macro_export]
+macro_rules! build_error {
+ () => {{
+ $crate::build_error("")
+ }};
+ ($msg:expr) => {{
+ $crate::build_error($msg)
+ }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```ignore
+/// fn foo() {
+/// static_assert!(1 > 1); // Compile-time error
+/// build_assert!(1 > 1); // Build-time error
+/// assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+/// // `static_assert!(N > 1);` is not allowed
+/// build_assert!(N > 1); // Build-time check
+/// assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+/// // `static_assert!(n > 1);` is not allowed
+/// build_assert!(n > 1); // Build-time check
+/// assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+ ($cond:expr $(,)?) => {{
+ if !$cond {
+ $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+ }
+ }};
+ ($cond:expr, $msg:expr) => {{
+ if !$cond {
+ $crate::build_error($msg);
+ }
+ }};
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 466b2a8fe569..5b9751d7ff1d 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -4,12 +4,60 @@
//!
//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
-use alloc::collections::TryReserveError;
+use alloc::{
+ alloc::{AllocError, LayoutError},
+ collections::TryReserveError,
+};
+
+use core::convert::From;
+use core::num::TryFromIntError;
+use core::str::Utf8Error;
/// Contains the C-compatible error codes.
pub mod code {
- /// Out of memory.
- pub const ENOMEM: super::Error = super::Error(-(crate::bindings::ENOMEM as i32));
+ macro_rules! declare_err {
+ ($err:tt $(,)? $($doc:expr),+) => {
+ $(
+ #[doc = $doc]
+ )*
+ pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+ };
+ }
+
+ declare_err!(EPERM, "Operation not permitted.");
+ declare_err!(ENOENT, "No such file or directory.");
+ declare_err!(ESRCH, "No such process.");
+ declare_err!(EINTR, "Interrupted system call.");
+ declare_err!(EIO, "I/O error.");
+ declare_err!(ENXIO, "No such device or address.");
+ declare_err!(E2BIG, "Argument list too long.");
+ declare_err!(ENOEXEC, "Exec format error.");
+ declare_err!(EBADF, "Bad file number.");
+ declare_err!(ECHILD, "Exec format error.");
+ declare_err!(EAGAIN, "Try again.");
+ declare_err!(ENOMEM, "Out of memory.");
+ declare_err!(EACCES, "Permission denied.");
+ declare_err!(EFAULT, "Bad address.");
+ declare_err!(ENOTBLK, "Block device required.");
+ declare_err!(EBUSY, "Device or resource busy.");
+ declare_err!(EEXIST, "File exists.");
+ declare_err!(EXDEV, "Cross-device link.");
+ declare_err!(ENODEV, "No such device.");
+ declare_err!(ENOTDIR, "Not a directory.");
+ declare_err!(EISDIR, "Is a directory.");
+ declare_err!(EINVAL, "Invalid argument.");
+ declare_err!(ENFILE, "File table overflow.");
+ declare_err!(EMFILE, "Too many open files.");
+ declare_err!(ENOTTY, "Not a typewriter.");
+ declare_err!(ETXTBSY, "Text file busy.");
+ declare_err!(EFBIG, "File too large.");
+ declare_err!(ENOSPC, "No space left on device.");
+ declare_err!(ESPIPE, "Illegal seek.");
+ declare_err!(EROFS, "Read-only file system.");
+ declare_err!(EMLINK, "Too many links.");
+ declare_err!(EPIPE, "Broken pipe.");
+ declare_err!(EDOM, "Math argument out of domain of func.");
+ declare_err!(ERANGE, "Math result not representable.");
}
/// Generic integer kernel error.
@@ -30,12 +78,48 @@ impl Error {
}
}
+impl From<AllocError> for Error {
+ fn from(_: AllocError) -> Error {
+ code::ENOMEM
+ }
+}
+
+impl From<TryFromIntError> for Error {
+ fn from(_: TryFromIntError) -> Error {
+ code::EINVAL
+ }
+}
+
+impl From<Utf8Error> for Error {
+ fn from(_: Utf8Error) -> Error {
+ code::EINVAL
+ }
+}
+
impl From<TryReserveError> for Error {
fn from(_: TryReserveError) -> Error {
code::ENOMEM
}
}
+impl From<LayoutError> for Error {
+ fn from(_: LayoutError) -> Error {
+ code::ENOMEM
+ }
+}
+
+impl From<core::fmt::Error> for Error {
+ fn from(_: core::fmt::Error) -> Error {
+ code::EINVAL
+ }
+}
+
+impl From<core::convert::Infallible> for Error {
+ fn from(e: core::convert::Infallible) -> Error {
+ match e {}
+ }
+}
+
/// A [`Result`] with an [`Error`] error type.
///
/// To be used as the return type for functions that may fail.
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index abd46261d385..53040fa9e897 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -12,6 +12,7 @@
//! do so first instead of bypassing this crate.
#![no_std]
+#![feature(allocator_api)]
#![feature(core_ffi_c)]
// Ensure conditional compilation based on the kernel configuration works;
@@ -22,15 +23,23 @@ compile_error!("Missing kernel configuration for conditional compilation");
#[cfg(not(test))]
#[cfg(not(testlib))]
mod allocator;
+mod build_assert;
pub mod error;
pub mod prelude;
pub mod print;
+mod static_assert;
+#[doc(hidden)]
+pub mod std_vendor;
pub mod str;
+pub mod types;
#[doc(hidden)]
pub use bindings;
pub use macros;
+#[doc(hidden)]
+pub use build_error::build_error;
+
/// Prefix to appear before log messages printed from within the `kernel` crate.
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 495e22250726..7a90249ee9b9 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -11,10 +11,18 @@
//! use kernel::prelude::*;
//! ```
-pub use super::{
- error::{Error, Result},
- pr_emerg, pr_info, ThisModule,
-};
-pub use alloc::{boxed::Box, vec::Vec};
pub use core::pin::Pin;
-pub use macros::module;
+
+pub use alloc::{boxed::Box, vec::Vec};
+
+pub use macros::{module, vtable};
+
+pub use super::build_assert;
+
+pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
+
+pub use super::static_assert;
+
+pub use super::error::{code::*, Error, Result};
+
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 55db5a1ba752..29bf9c2e8aee 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -74,7 +74,14 @@ pub mod format_strings {
// Furthermore, `static` instead of `const` is used to share the strings
// for all the kernel.
pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+ pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+ pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+ pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+ pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+ pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+ pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+ pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
}
/// Prints a message via the kernel's [`_printk`].
@@ -105,6 +112,26 @@ pub unsafe fn call_printk(
}
}
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+ // `_printk` does not seem to fail in any path.
+ //
+ // SAFETY: The format string is fixed.
+ #[cfg(CONFIG_PRINTK)]
+ unsafe {
+ bindings::_printk(
+ format_strings::CONT.as_ptr() as _,
+ &args as *const _ as *const c_void,
+ );
+ }
+}
+
/// Performs formatting and forwards the string to [`call_printk`].
///
/// Public but hidden since it should only be used from public macros.
@@ -114,7 +141,7 @@ pub unsafe fn call_printk(
#[allow(clippy::crate_in_macro_def)]
macro_rules! print_macro (
// The non-continuation cases (most of them, e.g. `INFO`).
- ($format_string:path, $($arg:tt)+) => (
+ ($format_string:path, false, $($arg:tt)+) => (
// SAFETY: This hidden macro should only be called by the documented
// printing macros which ensure the format string is one of the fixed
// ones. All `__LOG_PREFIX`s are null-terminated as they are generated
@@ -128,6 +155,13 @@ macro_rules! print_macro (
);
}
);
+
+ // The `CONT` case.
+ ($format_string:path, true, $($arg:tt)+) => (
+ $crate::print::call_printk_cont(
+ format_args!($($arg)+),
+ );
+ );
);
/// Stub for doctests
@@ -168,7 +202,127 @@ macro_rules! print_macro (
#[macro_export]
macro_rules! pr_emerg (
($($arg:tt)*) => (
- $crate::print_macro!($crate::print::format_strings::EMERG, $($arg)*)
+ $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
+ )
+);
+
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
+ )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
+ )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
+ )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
+ )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
)
);
@@ -193,6 +347,60 @@ macro_rules! pr_emerg (
#[doc(alias = "print")]
macro_rules! pr_info (
($($arg:tt)*) => (
- $crate::print_macro!($crate::print::format_strings::INFO, $($arg)*)
+ $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
+ )
+);
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+ ($($arg:tt)*) => (
+ if cfg!(debug_assertions) {
+ $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+ }
+ )
+);
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+ ($($arg:tt)*) => (
+ $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
)
);
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..3115ee0ba8e9
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+/// x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+ ($condition:expr) => {
+ const _: () = core::assert!($condition);
+ };
+}
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..b3e68b24a8c6
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in
+//! the <https://github.com/rust-lang/rust> repository, licensed under
+//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
+//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// # #[allow(clippy::dbg_macro)]
+/// let b = dbg!(a * 2) + 1;
+/// // ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a temporary debugging tool to be
+/// used during development. Therefore, avoid committing `dbg!` macro
+/// invocations into the kernel tree.
+///
+/// For debug output that is intended to be kept in the kernel tree,
+/// use [`pr_debug`] and similar facilities instead.
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// fn foo(n: usize) {
+/// if dbg!(n.checked_sub(4)).is_some() {
+/// // ...
+/// }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// fn factorial(n: u32) -> u32 {
+/// if dbg!(n <= 1) {
+/// dbg!(1)
+/// } else {
+/// dbg!(n * factorial(n - 1))
+/// }
+/// }
+///
+/// dbg!(factorial(4));
+/// # }
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```ignore
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// # }
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+ // NOTE: We cannot use `concat!` to make a static string as a format argument
+ // of `pr_info!` because `file!` could contain a `{` or
+ // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+ // will be malformed.
+ () => {
+ $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+ };
+ ($val:expr $(,)?) => {
+ // Use of `match` here is intentional because it affects the lifetimes
+ // of temporaries - https://stackoverflow.com/a/48732525/1063961
+ match $val {
+ tmp => {
+ $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+ ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+ tmp
+ }
+ }
+ };
+ ($($val:expr),+ $(,)?) => {
+ ($($crate::dbg!($val)),+,)
+ };
+}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index e45ff220ae50..b771310fa4a4 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -2,7 +2,377 @@
//! String representations.
-use core::fmt;
+use alloc::vec::Vec;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
+
+use crate::{
+ bindings,
+ error::{code::*, Error},
+};
+
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+ ($str:literal) => {{
+ const S: &'static str = $str;
+ const C: &'static $crate::str::BStr = S.as_bytes();
+ C
+ }};
+}
+
+/// Possible errors when using conversion functions in [`CStr`].
+#[derive(Debug, Clone, Copy)]
+pub enum CStrConvertError {
+ /// Supplied bytes contain an interior `NUL`.
+ InteriorNul,
+
+ /// Supplied bytes are not terminated by `NUL`.
+ NotNulTerminated,
+}
+
+impl From<CStrConvertError> for Error {
+ #[inline]
+ fn from(_: CStrConvertError) -> Error {
+ EINVAL
+ }
+}
+
+/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
+/// end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+#[repr(transparent)]
+pub struct CStr([u8]);
+
+impl CStr {
+ /// Returns the length of this string excluding `NUL`.
+ #[inline]
+ pub const fn len(&self) -> usize {
+ self.len_with_nul() - 1
+ }
+
+ /// Returns the length of this string with `NUL`.
+ #[inline]
+ pub const fn len_with_nul(&self) -> usize {
+ // SAFETY: This is one of the invariant of `CStr`.
+ // We add a `unreachable_unchecked` here to hint the optimizer that
+ // the value returned from this function is non-zero.
+ if self.0.is_empty() {
+ unsafe { core::hint::unreachable_unchecked() };
+ }
+ self.0.len()
+ }
+
+ /// Returns `true` if the string only includes `NUL`.
+ #[inline]
+ pub const fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Wraps a raw C string pointer.
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
+ /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
+ /// must not be mutated.
+ #[inline]
+ pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self {
+ // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
+ // to a `NUL`-terminated C string.
+ let len = unsafe { bindings::strlen(ptr) } + 1;
+ // SAFETY: Lifetime guaranteed by the safety precondition.
+ let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
+ // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
+ // As we have added 1 to `len`, the last byte is known to be `NUL`.
+ unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
+ }
+
+ /// Creates a [`CStr`] from a `[u8]`.
+ ///
+ /// The provided slice must be `NUL`-terminated, does not contain any
+ /// interior `NUL` bytes.
+ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
+ if bytes.is_empty() {
+ return Err(CStrConvertError::NotNulTerminated);
+ }
+ if bytes[bytes.len() - 1] != 0 {
+ return Err(CStrConvertError::NotNulTerminated);
+ }
+ let mut i = 0;
+ // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
+ // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
+ while i + 1 < bytes.len() {
+ if bytes[i] == 0 {
+ return Err(CStrConvertError::InteriorNul);
+ }
+ i += 1;
+ }
+ // SAFETY: We just checked that all properties hold.
+ Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+ }
+
+ /// Creates a [`CStr`] from a `[u8]` without performing any additional
+ /// checks.
+ ///
+ /// # Safety
+ ///
+ /// `bytes` *must* end with a `NUL` byte, and should only have a single
+ /// `NUL` byte (or the string will be truncated).
+ #[inline]
+ pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
+ unsafe { core::mem::transmute(bytes) }
+ }
+
+ /// Returns a C pointer to the string.
+ #[inline]
+ pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
+ self.0.as_ptr() as _
+ }
+
+ /// Convert the string to a byte slice without the trailing 0 byte.
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.0[..self.len()]
+ }
+
+ /// Convert the string to a byte slice containing the trailing 0 byte.
+ #[inline]
+ pub const fn as_bytes_with_nul(&self) -> &[u8] {
+ &self.0
+ }
+
+ /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
+ ///
+ /// If the contents of the [`CStr`] are valid UTF-8 data, this
+ /// function will return the corresponding [`&str`] slice. Otherwise,
+ /// it will return an error with details of where UTF-8 validation failed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::str::CStr;
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+ /// assert_eq!(cstr.to_str(), Ok("foo"));
+ /// ```
+ #[inline]
+ pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
+ core::str::from_utf8(self.as_bytes())
+ }
+
+ /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
+ /// valid UTF-8.
+ ///
+ /// # Safety
+ ///
+ /// The contents must be valid UTF-8.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::c_str;
+ /// # use kernel::str::CStr;
+ /// // SAFETY: String literals are guaranteed to be valid UTF-8
+ /// // by the Rust compiler.
+ /// let bar = c_str!("ツ");
+ /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+ /// ```
+ #[inline]
+ pub unsafe fn as_str_unchecked(&self) -> &str {
+ unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+ }
+}
+
+impl fmt::Display for CStr {
+ /// Formats printable ASCII characters, escaping the rest.
+ ///
+ /// ```
+ /// # use kernel::c_str;
+ /// # use kernel::str::CStr;
+ /// # use kernel::str::CString;
+ /// let penguin = c_str!("🐧");
+ /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
+ /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+ ///
+ /// let ascii = c_str!("so \"cool\"");
+ /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+ /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+ /// ```
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for &c in self.as_bytes() {
+ if (0x20..0x7f).contains(&c) {
+ // Printable character.
+ f.write_char(c as char)?;
+ } else {
+ write!(f, "\\x{:02x}", c)?;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl fmt::Debug for CStr {
+ /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
+ ///
+ /// ```
+ /// # use kernel::c_str;
+ /// # use kernel::str::CStr;
+ /// # use kernel::str::CString;
+ /// let penguin = c_str!("🐧");
+ /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
+ /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
+ ///
+ /// // Embedded double quotes are escaped.
+ /// let ascii = c_str!("so \"cool\"");
+ /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
+ /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
+ /// ```
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("\"")?;
+ for &c in self.as_bytes() {
+ match c {
+ // Printable characters.
+ b'\"' => f.write_str("\\\"")?,
+ 0x20..=0x7e => f.write_char(c as char)?,
+ _ => write!(f, "\\x{:02x}", c)?,
+ }
+ }
+ f.write_str("\"")
+ }
+}
+
+impl AsRef<BStr> for CStr {
+ #[inline]
+ fn as_ref(&self) -> &BStr {
+ self.as_bytes()
+ }
+}
+
+impl Deref for CStr {
+ type Target = BStr;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ self.as_bytes()
+ }
+}
+
+impl Index<ops::RangeFrom<usize>> for CStr {
+ type Output = CStr;
+
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
+ // Delegate bounds checking to slice.
+ // Assign to _ to mute clippy's unnecessary operation warning.
+ let _ = &self.as_bytes()[index.start..];
+ // SAFETY: We just checked the bounds.
+ unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+ }
+}
+
+impl Index<ops::RangeFull> for CStr {
+ type Output = CStr;
+
+ #[inline]
+ fn index(&self, _index: ops::RangeFull) -> &Self::Output {
+ self
+ }
+}
+
+mod private {
+ use core::ops;
+
+ // Marker trait for index types that can be forward to `BStr`.
+ pub trait CStrIndex {}
+
+ impl CStrIndex for usize {}
+ impl CStrIndex for ops::Range<usize> {}
+ impl CStrIndex for ops::RangeInclusive<usize> {}
+ impl CStrIndex for ops::RangeToInclusive<usize> {}
+}
+
+impl<Idx> Index<Idx> for CStr
+where
+ Idx: private::CStrIndex,
+ BStr: Index<Idx>,
+{
+ type Output = <BStr as Index<Idx>>::Output;
+
+ #[inline]
+ fn index(&self, index: Idx) -> &Self::Output {
+ &self.as_bytes()[index]
+ }
+}
+
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+ ($str:expr) => {{
+ const S: &str = concat!($str, "\0");
+ const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
+ Ok(v) => v,
+ Err(_) => panic!("string contains interior NUL"),
+ };
+ C
+ }};
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_cstr_to_str() {
+ let good_bytes = b"\xf0\x9f\xa6\x80\0";
+ let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+ let checked_str = checked_cstr.to_str().unwrap();
+ assert_eq!(checked_str, "🦀");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_cstr_to_str_panic() {
+ let bad_bytes = b"\xc3\x28\0";
+ let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+ checked_cstr.to_str().unwrap();
+ }
+
+ #[test]
+ fn test_cstr_as_str_unchecked() {
+ let good_bytes = b"\xf0\x9f\x90\xA7\0";
+ let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+ let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+ assert_eq!(unchecked_str, "🐧");
+ }
+}
/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
///
@@ -15,13 +385,22 @@ use core::fmt;
/// is less than `end`.
pub(crate) struct RawFormatter {
// Use `usize` to use `saturating_*` functions.
- #[allow(dead_code)]
beg: usize,
pos: usize,
end: usize,
}
impl RawFormatter {
+ /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+ fn new() -> Self {
+ // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+ Self {
+ beg: 0,
+ pos: 0,
+ end: 0,
+ }
+ }
+
/// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
///
/// # Safety
@@ -37,12 +416,34 @@ impl RawFormatter {
}
}
+ /// Creates a new instance of [`RawFormatter`] with the given buffer.
+ ///
+ /// # Safety
+ ///
+ /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+ /// for the lifetime of the returned [`RawFormatter`].
+ pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+ let pos = buf as usize;
+ // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+ // guarantees that the memory region is valid for writes.
+ Self {
+ pos,
+ beg: pos,
+ end: pos.saturating_add(len),
+ }
+ }
+
/// Returns the current insert position.
///
/// N.B. It may point to invalid memory.
pub(crate) fn pos(&self) -> *mut u8 {
self.pos as _
}
+
+ /// Return the number of bytes written to the formatter.
+ pub(crate) fn bytes_written(&self) -> usize {
+ self.pos - self.beg
+ }
}
impl fmt::Write for RawFormatter {
@@ -70,3 +471,121 @@ impl fmt::Write for RawFormatter {
Ok(())
}
}
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+ /// Creates a new instance of [`Formatter`] with the given buffer.
+ ///
+ /// # Safety
+ ///
+ /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+ /// for the lifetime of the returned [`Formatter`].
+ pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+ // SAFETY: The safety requirements of this function satisfy those of the callee.
+ Self(unsafe { RawFormatter::from_buffer(buf, len) })
+ }
+}
+
+impl Deref for Formatter {
+ type Target = RawFormatter;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl fmt::Write for Formatter {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.0.write_str(s)?;
+
+ // Fail the request if we go past the end of the buffer.
+ if self.0.pos > self.0.end {
+ Err(fmt::Error)
+ } else {
+ Ok(())
+ }
+ }
+}
+
+/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
+///
+/// Used for interoperability with kernel APIs that take C strings.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+ buf: Vec<u8>,
+}
+
+impl CString {
+ /// Creates an instance of [`CString`] from the given formatted arguments.
+ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+ // Calculate the size needed (formatted string plus `NUL` terminator).
+ let mut f = RawFormatter::new();
+ f.write_fmt(args)?;
+ f.write_str("\0")?;
+ let size = f.bytes_written();
+
+ // Allocate a vector with the required number of bytes, and write to it.
+ let mut buf = Vec::try_with_capacity(size)?;
+ // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+ let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+ f.write_fmt(args)?;
+ f.write_str("\0")?;
+
+ // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+ // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+ unsafe { buf.set_len(f.bytes_written()) };
+
+ // Check that there are no `NUL` bytes before the end.
+ // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+ // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+ // so `f.bytes_written() - 1` doesn't underflow.
+ let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+ if !ptr.is_null() {
+ return Err(EINVAL);
+ }
+
+ // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+ // exist in the buffer.
+ Ok(Self { buf })
+ }
+}
+
+impl Deref for CString {
+ type Target = CStr;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+ // other `NUL` bytes exist.
+ unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+ }
+}
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+ ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..e84e51ec9716
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+
+use core::{cell::UnsafeCell, mem::MaybeUninit};
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+#[repr(transparent)]
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+ /// Creates a new opaque value.
+ pub const fn new(value: T) -> Self {
+ Self(MaybeUninit::new(UnsafeCell::new(value)))
+ }
+
+ /// Creates an uninitialised value.
+ pub const fn uninit() -> Self {
+ Self(MaybeUninit::uninit())
+ }
+
+ /// Returns a raw pointer to the opaque data.
+ pub fn get(&self) -> *mut T {
+ UnsafeCell::raw_get(self.0.as_ptr())
+ }
+}
+
+/// A sum type that always holds either a value of type `L` or `R`.
+pub enum Either<L, R> {
+ /// Constructs an instance of [`Either`] containing a value of type `L`.
+ Left(L),
+
+ /// Constructs an instance of [`Either`] containing a value of type `R`.
+ Right(R),
+}
diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
new file mode 100644
index 000000000000..7e4b450f3a50
--- /dev/null
+++ b/rust/macros/concat_idents.rs
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use proc_macro::{token_stream, Ident, TokenStream, TokenTree};
+
+use crate::helpers::expect_punct;
+
+fn expect_ident(it: &mut token_stream::IntoIter) -> Ident {
+ if let Some(TokenTree::Ident(ident)) = it.next() {
+ ident
+ } else {
+ panic!("Expected Ident")
+ }
+}
+
+pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
+ let mut it = ts.into_iter();
+ let a = expect_ident(&mut it);
+ assert_eq!(expect_punct(&mut it), ',');
+ let b = expect_ident(&mut it);
+ assert!(it.next().is_none(), "only two idents can be concatenated");
+ let res = Ident::new(&format!("{a}{b}"), b.span());
+ TokenStream::from_iter([TokenTree::Ident(res)])
+}
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index cdc7dc6135d2..cf7ad950dc1e 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -18,10 +18,16 @@ pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
}
}
-pub(crate) fn try_byte_string(it: &mut token_stream::IntoIter) -> Option<String> {
- try_literal(it).and_then(|byte_string| {
- if byte_string.starts_with("b\"") && byte_string.ends_with('\"') {
- Some(byte_string[2..byte_string.len() - 1].to_string())
+pub(crate) fn try_string(it: &mut token_stream::IntoIter) -> Option<String> {
+ try_literal(it).and_then(|string| {
+ if string.starts_with('\"') && string.ends_with('\"') {
+ let content = &string[1..string.len() - 1];
+ if content.contains('\\') {
+ panic!("Escape sequences in string literals not yet handled");
+ }
+ Some(content.to_string())
+ } else if string.starts_with("r\"") {
+ panic!("Raw string literals are not yet handled");
} else {
None
}
@@ -40,8 +46,14 @@ pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char {
}
}
-pub(crate) fn expect_byte_string(it: &mut token_stream::IntoIter) -> String {
- try_byte_string(it).expect("Expected byte string")
+pub(crate) fn expect_string(it: &mut token_stream::IntoIter) -> String {
+ try_string(it).expect("Expected string")
+}
+
+pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String {
+ let string = try_string(it).expect("Expected string");
+ assert!(string.is_ascii(), "Expected ASCII string");
+ string
}
pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 91764bfb1f89..c1d385e345b9 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -2,8 +2,10 @@
//! Crate for all kernel procedural macros.
+mod concat_idents;
mod helpers;
mod module;
+mod vtable;
use proc_macro::TokenStream;
@@ -23,20 +25,20 @@ use proc_macro::TokenStream;
///
/// module!{
/// type: MyModule,
-/// name: b"my_kernel_module",
-/// author: b"Rust for Linux Contributors",
-/// description: b"My very own kernel module!",
-/// license: b"GPL",
+/// name: "my_kernel_module",
+/// author: "Rust for Linux Contributors",
+/// description: "My very own kernel module!",
+/// license: "GPL",
/// params: {
/// my_i32: i32 {
/// default: 42,
/// permissions: 0o000,
-/// description: b"Example of i32",
+/// description: "Example of i32",
/// },
/// writeable_i32: i32 {
/// default: 42,
/// permissions: 0o644,
-/// description: b"Example of i32",
+/// description: "Example of i32",
/// },
/// },
/// }
@@ -70,3 +72,97 @@ use proc_macro::TokenStream;
pub fn module(ts: TokenStream) -> TokenStream {
module::module(ts)
}
+
+/// Declares or implements a vtable trait.
+///
+/// Linux's use of pure vtables is very close to Rust traits, but they differ
+/// in how unimplemented functions are represented. In Rust, traits can provide
+/// default implementation for all non-required methods (and the default
+/// implementation could just return `Error::EINVAL`); Linux typically use C
+/// `NULL` pointers to represent these functions.
+///
+/// This attribute is intended to close the gap. Traits can be declared and
+/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
+/// will be generated for each method in the trait, indicating if the implementor
+/// has overridden a method.
+///
+/// This attribute is not needed if all methods are required.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// // Declares a `#[vtable]` trait
+/// #[vtable]
+/// pub trait Operations: Send + Sync + Sized {
+/// fn foo(&self) -> Result<()> {
+/// Err(EINVAL)
+/// }
+///
+/// fn bar(&self) -> Result<()> {
+/// Err(EINVAL)
+/// }
+/// }
+///
+/// struct Foo;
+///
+/// // Implements the `#[vtable]` trait
+/// #[vtable]
+/// impl Operations for Foo {
+/// fn foo(&self) -> Result<()> {
+/// # Err(EINVAL)
+/// // ...
+/// }
+/// }
+///
+/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
+/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
+/// ```
+#[proc_macro_attribute]
+pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
+ vtable::vtable(attr, ts)
+}
+
+/// Concatenate two identifiers.
+///
+/// This is useful in macros that need to declare or reference items with names
+/// starting with a fixed prefix and ending in a user specified name. The resulting
+/// identifier has the span of the second argument.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::macro::concat_idents;
+///
+/// macro_rules! pub_no_prefix {
+/// ($prefix:ident, $($newname:ident),+) => {
+/// $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+
+/// };
+/// }
+///
+/// pub_no_prefix!(
+/// binder_driver_return_protocol_,
+/// BR_OK,
+/// BR_ERROR,
+/// BR_TRANSACTION,
+/// BR_REPLY,
+/// BR_DEAD_REPLY,
+/// BR_TRANSACTION_COMPLETE,
+/// BR_INCREFS,
+/// BR_ACQUIRE,
+/// BR_RELEASE,
+/// BR_DECREFS,
+/// BR_NOOP,
+/// BR_SPAWN_LOOPER,
+/// BR_DEAD_BINDER,
+/// BR_CLEAR_DEATH_NOTIFICATION_DONE,
+/// BR_FAILED_REPLY
+/// );
+///
+/// assert_eq!(BR_OK, binder_driver_return_protocol_BR_OK);
+/// ```
+#[proc_macro]
+pub fn concat_idents(ts: TokenStream) -> TokenStream {
+ concat_idents::concat_idents(ts)
+}
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 186a5b8be23c..a7e363c2b044 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -108,11 +108,11 @@ impl ModuleInfo {
match key.as_str() {
"type" => info.type_ = expect_ident(it),
- "name" => info.name = expect_byte_string(it),
- "author" => info.author = Some(expect_byte_string(it)),
- "description" => info.description = Some(expect_byte_string(it)),
- "license" => info.license = expect_byte_string(it),
- "alias" => info.alias = Some(expect_byte_string(it)),
+ "name" => info.name = expect_string_ascii(it),
+ "author" => info.author = Some(expect_string(it)),
+ "description" => info.description = Some(expect_string(it)),
+ "license" => info.license = expect_string_ascii(it),
+ "alias" => info.alias = Some(expect_string_ascii(it)),
_ => panic!(
"Unknown key \"{}\". Valid keys are: {:?}.",
key, EXPECTED_KEYS
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
new file mode 100644
index 000000000000..34d5e7fb5768
--- /dev/null
+++ b/rust/macros/vtable.rs
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
+use std::collections::HashSet;
+use std::fmt::Write;
+
+pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
+ let mut tokens: Vec<_> = ts.into_iter().collect();
+
+ // Scan for the `trait` or `impl` keyword.
+ let is_trait = tokens
+ .iter()
+ .find_map(|token| match token {
+ TokenTree::Ident(ident) => match ident.to_string().as_str() {
+ "trait" => Some(true),
+ "impl" => Some(false),
+ _ => None,
+ },
+ _ => None,
+ })
+ .expect("#[vtable] attribute should only be applied to trait or impl block");
+
+ // Retrieve the main body. The main body should be the last token tree.
+ let body = match tokens.pop() {
+ Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => group,
+ _ => panic!("cannot locate main body of trait or impl block"),
+ };
+
+ let mut body_it = body.stream().into_iter();
+ let mut functions = Vec::new();
+ let mut consts = HashSet::new();
+ while let Some(token) = body_it.next() {
+ match token {
+ TokenTree::Ident(ident) if ident.to_string() == "fn" => {
+ let fn_name = match body_it.next() {
+ Some(TokenTree::Ident(ident)) => ident.to_string(),
+ // Possibly we've encountered a fn pointer type instead.
+ _ => continue,
+ };
+ functions.push(fn_name);
+ }
+ TokenTree::Ident(ident) if ident.to_string() == "const" => {
+ let const_name = match body_it.next() {
+ Some(TokenTree::Ident(ident)) => ident.to_string(),
+ // Possibly we've encountered an inline const block instead.
+ _ => continue,
+ };
+ consts.insert(const_name);
+ }
+ _ => (),
+ }
+ }
+
+ let mut const_items;
+ if is_trait {
+ const_items = "
+ /// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable)
+ /// attribute when implementing this trait.
+ const USE_VTABLE_ATTR: ();
+ "
+ .to_owned();
+
+ for f in functions {
+ let gen_const_name = format!("HAS_{}", f.to_uppercase());
+ // Skip if it's declared already -- this allows user override.
+ if consts.contains(&gen_const_name) {
+ continue;
+ }
+ // We don't know on the implementation-site whether a method is required or provided
+ // so we have to generate a const for all methods.
+ write!(
+ const_items,
+ "/// Indicates if the `{f}` method is overridden by the implementor.
+ const {gen_const_name}: bool = false;",
+ )
+ .unwrap();
+ }
+ } else {
+ const_items = "const USE_VTABLE_ATTR: () = ();".to_owned();
+
+ for f in functions {
+ let gen_const_name = format!("HAS_{}", f.to_uppercase());
+ if consts.contains(&gen_const_name) {
+ continue;
+ }
+ write!(const_items, "const {gen_const_name}: bool = true;").unwrap();
+ }
+ }
+
+ let new_body = vec![const_items.parse().unwrap(), body.stream()]
+ .into_iter()
+ .collect();
+ tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body)));
+ tokens.into_iter().collect()
+}
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index f29bb3c72230..e2056c8b902c 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -76,7 +76,8 @@ static int parse_path(char *env_path, const char ***const path_list)
#define ACCESS_FILE ( \
LANDLOCK_ACCESS_FS_EXECUTE | \
LANDLOCK_ACCESS_FS_WRITE_FILE | \
- LANDLOCK_ACCESS_FS_READ_FILE)
+ LANDLOCK_ACCESS_FS_READ_FILE | \
+ LANDLOCK_ACCESS_FS_TRUNCATE)
/* clang-format on */
@@ -160,11 +161,12 @@ out_free_name:
LANDLOCK_ACCESS_FS_MAKE_FIFO | \
LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
LANDLOCK_ACCESS_FS_MAKE_SYM | \
- LANDLOCK_ACCESS_FS_REFER)
+ LANDLOCK_ACCESS_FS_REFER | \
+ LANDLOCK_ACCESS_FS_TRUNCATE)
/* clang-format on */
-#define LANDLOCK_ABI_LAST 2
+#define LANDLOCK_ABI_LAST 3
int main(const int argc, char *const argv[], char *const *const envp)
{
@@ -232,8 +234,27 @@ int main(const int argc, char *const argv[], char *const *const envp)
/* Best-effort security. */
switch (abi) {
case 1:
- /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
+ /*
+ * Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2
+ *
+ * Note: The "refer" operations (file renaming and linking
+ * across different directories) are always forbidden when using
+ * Landlock with ABI 1.
+ *
+ * If only ABI 1 is available, this sandboxer knowingly forbids
+ * refer operations.
+ *
+ * If a program *needs* to do refer operations after enabling
+ * Landlock, it can not use Landlock at ABI level 1. To be
+ * compatible with different kernel versions, such programs
+ * should then fall back to not restrict themselves at all if
+ * the running kernel only supports ABI 1.
+ */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
+ __attribute__((fallthrough));
+ case 2:
+ /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
+ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
fprintf(stderr,
"Hint: You should update the running kernel "
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index 841e0906e943..b0f74a81c8f9 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -20,6 +20,16 @@ config SAMPLE_RUST_MINIMAL
If unsure, say N.
+config SAMPLE_RUST_PRINT
+ tristate "Printing macros"
+ help
+ This option builds the Rust printing macros sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_print.
+
+ If unsure, say N.
+
config SAMPLE_RUST_HOSTPROGS
bool "Host programs"
help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 1daba5f8658a..03086dabbea4 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
index 54ad17685742..dc05f4bbe27e 100644
--- a/samples/rust/rust_minimal.rs
+++ b/samples/rust/rust_minimal.rs
@@ -6,10 +6,10 @@ use kernel::prelude::*;
module! {
type: RustMinimal,
- name: b"rust_minimal",
- author: b"Rust for Linux Contributors",
- description: b"Rust minimal sample",
- license: b"GPL",
+ name: "rust_minimal",
+ author: "Rust for Linux Contributors",
+ description: "Rust minimal sample",
+ license: "GPL",
}
struct RustMinimal {
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..8b39d9cef6d1
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::pr_cont;
+use kernel::prelude::*;
+
+module! {
+ type: RustPrint,
+ name: "rust_print",
+ author: "Rust for Linux Contributors",
+ description: "Rust printing macros sample",
+ license: "GPL",
+}
+
+struct RustPrint;
+
+impl kernel::Module for RustPrint {
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ pr_info!("Rust printing macros sample (init)\n");
+
+ pr_emerg!("Emergency message (level 0) without args\n");
+ pr_alert!("Alert message (level 1) without args\n");
+ pr_crit!("Critical message (level 2) without args\n");
+ pr_err!("Error message (level 3) without args\n");
+ pr_warn!("Warning message (level 4) without args\n");
+ pr_notice!("Notice message (level 5) without args\n");
+ pr_info!("Info message (level 6) without args\n");
+
+ pr_info!("A line that");
+ pr_cont!(" is continued");
+ pr_cont!(" without args\n");
+
+ pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+ pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+ pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+ pr_err!("{} message (level {}) with args\n", "Error", 3);
+ pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+ pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+ pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+ pr_info!("A {} that", "line");
+ pr_cont!(" is {}", "continued");
+ pr_cont!(" with {}\n", "args");
+
+ Ok(RustPrint)
+ }
+}
+
+impl Drop for RustPrint {
+ fn drop(&mut self) {
+ pr_info!("Rust printing macros sample (exit)\n");
+ }
+}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 41f3602fc8de..3ceab076127b 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -468,10 +468,12 @@ intermediate_targets = $(foreach sfx, $(2), \
$(filter %$(strip $(1)), $(targets))))
# %.asn1.o <- %.asn1.[ch] <- %.asn1
# %.dtb.o <- %.dtb.S <- %.dtb <- %.dts
+# %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso
# %.lex.o <- %.lex.c <- %.l
# %.tab.o <- %.tab.[ch] <- %.y
targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \
$(call intermediate_targets, .dtb.o, .dtb.S .dtb) \
+ $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) \
$(call intermediate_targets, .lex.o, .lex.c) \
$(call intermediate_targets, .tab.o, .tab.c .tab.h)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 3aa384cec76b..250b9fd73f6d 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -358,7 +358,7 @@ DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@)
# Generate an assembly file to wrap the output of the device tree compiler
-quiet_cmd_dt_S_dtb= DTB $@
+quiet_cmd_dt_S_dtb= DTBS $@
cmd_dt_S_dtb= \
{ \
echo '\#include <asm-generic/vmlinux.lds.h>'; \
@@ -375,6 +375,24 @@ cmd_dt_S_dtb= \
$(obj)/%.dtb.S: $(obj)/%.dtb FORCE
$(call if_changed,dt_S_dtb)
+# Generate an assembly file to wrap the output of the device tree compiler
+quiet_cmd_dt_S_dtbo= DTBOS $@
+cmd_dt_S_dtbo= \
+{ \
+ echo '\#include <asm-generic/vmlinux.lds.h>'; \
+ echo '.section .dtb.init.rodata,"a"'; \
+ echo '.balign STRUCT_ALIGNMENT'; \
+ echo '.global __dtbo_$(subst -,_,$(*F))_begin'; \
+ echo '__dtbo_$(subst -,_,$(*F))_begin:'; \
+ echo '.incbin "$<" '; \
+ echo '__dtbo_$(subst -,_,$(*F))_end:'; \
+ echo '.global __dtbo_$(subst -,_,$(*F))_end'; \
+ echo '.balign STRUCT_ALIGNMENT'; \
+} > $@
+
+$(obj)/%.dtbo.S: $(obj)/%.dtbo FORCE
+ $(call if_changed,dt_S_dtbo)
+
quiet_cmd_dtc = DTC $@
cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
$(DTC) -o $@ -b 0 \
@@ -408,6 +426,9 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
$(obj)/%.dtbo: $(src)/%.dts $(DTC) FORCE
$(call if_changed_dep,dtc)
+$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE
+ $(call if_changed_dep,dtc)
+
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
# Bzip2
diff --git a/scripts/Makefile.package b/scripts/Makefile.package
index 8bbcced67c22..2a90139ecbe1 100644
--- a/scripts/Makefile.package
+++ b/scripts/Makefile.package
@@ -30,8 +30,8 @@ KBUILD_PKG_ROOTCMD ?="fakeroot -u"
export KDEB_SOURCENAME
# Include only those top-level files that are needed by make, plus the GPL copy
TAR_CONTENT := Documentation LICENSES arch block certs crypto drivers fs \
- include init io_uring ipc kernel lib mm net samples scripts \
- security sound tools usr virt \
+ include init io_uring ipc kernel lib mm net rust \
+ samples scripts security sound tools usr virt \
.config .scmversion Makefile \
Kbuild Kconfig COPYING $(wildcard localversion*)
MKSPEC := $(srctree)/scripts/package/mkspec
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 1e5e66ae5a52..78cc595b98ce 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -702,6 +702,17 @@ sub find_standard_signature {
return "";
}
+our $obsolete_archives = qr{(?xi:
+ \Qfreedesktop.org/archives/dri-devel\E |
+ \Qlists.infradead.org\E |
+ \Qlkml.org\E |
+ \Qmail-archive.com\E |
+ \Qmailman.alsa-project.org/pipermail\E |
+ \Qmarc.info\E |
+ \Qozlabs.org/pipermail\E |
+ \Qspinics.net\E
+)};
+
our @typeListMisordered = (
qr{char\s+(?:un)?signed},
qr{int\s+(?:(?:un)?signed\s+)?short\s},
@@ -3324,6 +3335,12 @@ sub process {
$last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i);
}
+# Check for mailing list archives other than lore.kernel.org
+ if ($rawline =~ m{http.*\b$obsolete_archives}) {
+ WARN("PREFER_LORE_ARCHIVE",
+ "Use lore.kernel.org archive links when possible - see https://lore.kernel.org/lists.html\n" . $herecurr);
+ }
+
# Check for added, moved or deleted files
if (!$reported_maintainer_file && !$in_commit_log &&
($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ ||
@@ -5901,6 +5918,7 @@ sub process {
$dstat !~ /$exceptions/ &&
$dstat !~ /^\.$Ident\s*=/ && # .foo =
$dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
+ $dstat !~ /^case\b/ && # case ...
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
$dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...}
$dstat !~ /^for\s*$Constant$/ && # for (...)
@@ -7128,7 +7146,7 @@ sub process {
}
# check for alloc argument mismatch
- if ($line =~ /\b((?:devm_)?(?:kcalloc|kmalloc_array))\s*\(\s*sizeof\b/) {
+ if ($line =~ /\b((?:devm_)?((?:k|kv)?(calloc|malloc_array)(?:_node)?))\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
"$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
}
diff --git a/scripts/faddr2line b/scripts/faddr2line
index 5514c23f45c2..0e73aca4f908 100755
--- a/scripts/faddr2line
+++ b/scripts/faddr2line
@@ -74,7 +74,8 @@ command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed"
find_dir_prefix() {
local objfile=$1
- local start_kernel_addr=$(${READELF} --symbols --wide $objfile | ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}')
+ local start_kernel_addr=$(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' |
+ ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}')
[[ -z $start_kernel_addr ]] && return
local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr)
@@ -178,7 +179,7 @@ __faddr2line() {
found=2
break
fi
- done < <(${READELF} --symbols --wide $objfile | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2)
+ done < <(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2)
if [[ $found = 0 ]]; then
warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size"
@@ -259,7 +260,7 @@ __faddr2line() {
DONE=1
- done < <(${READELF} --symbols --wide $objfile | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn')
+ done < <(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn')
}
[[ $# -lt 2 ]] && usage
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index 75bb611bd751..ecc7ea9a4dcf 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -68,6 +68,12 @@ def generate_crates(srctree, objtree, sysroot_src):
crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so"
append_crate(
+ "build_error",
+ srctree / "rust" / "build_error.rs",
+ ["core", "compiler_builtins"],
+ )
+
+ append_crate(
"bindings",
srctree / "rust"/ "bindings" / "lib.rs",
["core"],
@@ -78,7 +84,7 @@ def generate_crates(srctree, objtree, sysroot_src):
append_crate(
"kernel",
srctree / "rust" / "kernel" / "lib.rs",
- ["core", "alloc", "macros", "bindings"],
+ ["core", "alloc", "macros", "build_error", "bindings"],
cfg=cfg,
)
crates[-1]["source"] = {
diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt
index b16326a92c45..f226e45e3b7b 100644
--- a/scripts/head-object-list.txt
+++ b/scripts/head-object-list.txt
@@ -15,7 +15,6 @@ arch/alpha/kernel/head.o
arch/arc/kernel/head.o
arch/arm/kernel/head-nommu.o
arch/arm/kernel/head.o
-arch/arm64/kernel/head.o
arch/csky/kernel/head.o
arch/hexagon/kernel/head.o
arch/ia64/kernel/head.o
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index aea04365bc69..11bafc8e85ab 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -866,48 +866,53 @@ sub output_function_rst(%) {
print "\n";
}
- print "**Parameters**\n\n";
+ #
+ # Put our descriptive text into a container (thus an HTML <div>) to help
+ # set the function prototypes apart.
+ #
+ print ".. container:: kernelindent\n\n";
$lineprefix = " ";
+ print $lineprefix . "**Parameters**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
$type = $args{'parametertypes'}{$parameter};
if ($type ne "") {
- print "``$type``\n";
+ print $lineprefix . "``$type``\n";
} else {
- print "``$parameter``\n";
+ print $lineprefix . "``$parameter``\n";
}
print_lineno($parameterdesc_start_lines{$parameter_name});
+ $lineprefix = " ";
if (defined($args{'parameterdescs'}{$parameter_name}) &&
$args{'parameterdescs'}{$parameter_name} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
} else {
- print " *undescribed*\n";
+ print $lineprefix . "*undescribed*\n";
}
+ $lineprefix = " ";
print "\n";
}
- $lineprefix = $oldprefix;
output_section_rst(@_);
+ $lineprefix = $oldprefix;
}
sub output_section_rst(%) {
my %args = %{$_[0]};
my $section;
my $oldprefix = $lineprefix;
- $lineprefix = "";
foreach $section (@{$args{'sectionlist'}}) {
- print "**$section**\n\n";
+ print $lineprefix . "**$section**\n\n";
print_lineno($section_start_lines{$section});
output_highlight_rst($args{'sections'}{$section});
print "\n";
}
print "\n";
- $lineprefix = $oldprefix;
}
sub output_enum_rst(%) {
@@ -915,6 +920,7 @@ sub output_enum_rst(%) {
my ($parameter);
my $oldprefix = $lineprefix;
my $count;
+ my $outer;
if ($sphinx_major < 3) {
my $name = "enum " . $args{'enum'};
@@ -924,22 +930,25 @@ sub output_enum_rst(%) {
print "\n\n.. c:enum:: " . $name . "\n\n";
}
print_lineno($declaration_start_line);
- $lineprefix = " ";
+ $lineprefix = " ";
output_highlight_rst($args{'purpose'});
print "\n";
- print "**Constants**\n\n";
- $lineprefix = " ";
+ print ".. container:: kernelindent\n\n";
+ $outer = $lineprefix . " ";
+ $lineprefix = $outer . " ";
+ print $outer . "**Constants**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
- print "``$parameter``\n";
+ print $outer . "``$parameter``\n";
+
if ($args{'parameterdescs'}{$parameter} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter});
} else {
- print " *undescribed*\n";
+ print $lineprefix . "*undescribed*\n";
}
print "\n";
}
-
+ print "\n";
$lineprefix = $oldprefix;
output_section_rst(@_);
}
@@ -982,18 +991,19 @@ sub output_struct_rst(%) {
}
}
print_lineno($declaration_start_line);
- $lineprefix = " ";
+ $lineprefix = " ";
output_highlight_rst($args{'purpose'});
print "\n";
- print "**Definition**\n\n";
- print "::\n\n";
+ print ".. container:: kernelindent\n\n";
+ print $lineprefix . "**Definition**::\n\n";
my $declaration = $args{'definition'};
- $declaration =~ s/\t/ /g;
- print " " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration };\n\n";
+ $lineprefix = $lineprefix . " ";
+ $declaration =~ s/\t/$lineprefix/g;
+ print $lineprefix . $args{'type'} . " " . $args{'struct'} . " {\n$declaration" . $lineprefix . "};\n\n";
- print "**Members**\n\n";
$lineprefix = " ";
+ print $lineprefix . "**Members**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
($parameter =~ /^#/) && next;
@@ -1003,8 +1013,10 @@ sub output_struct_rst(%) {
($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
print_lineno($parameterdesc_start_lines{$parameter_name});
- print "``" . $parameter . "``\n";
+ print $lineprefix . "``" . $parameter . "``\n";
+ $lineprefix = " ";
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
+ $lineprefix = " ";
print "\n";
}
print "\n";
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
index b6593eac5003..201bccfbc678 100755
--- a/scripts/min-tool-version.sh
+++ b/scripts/min-tool-version.sh
@@ -25,7 +25,7 @@ icc)
;;
llvm)
if [ "$SRCARCH" = s390 ]; then
- echo 14.0.0
+ echo 15.0.0
else
echo 11.0.0
fi
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index da4bddd26171..bf5bcf2836d8 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -3,6 +3,12 @@
* Archs are free to supply their own linker scripts. ld will
* combine them automatically.
*/
+#ifdef CONFIG_UNWIND_TABLES
+#define DISCARD_EH_FRAME
+#else
+#define DISCARD_EH_FRAME *(.eh_frame)
+#endif
+
SECTIONS {
/DISCARD/ : {
*(.discard)
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
index 60a2a63a5e90..a3ac5a716e9f 100755
--- a/scripts/package/mkdebian
+++ b/scripts/package/mkdebian
@@ -90,7 +90,7 @@ if [ -n "$KDEB_PKGVERSION" ]; then
packageversion=$KDEB_PKGVERSION
revision=${packageversion##*-}
else
- revision=$(cat .version 2>/dev/null||echo 1)
+ revision=$($srctree/init/build-version)
packageversion=$version-$revision
fi
sourcename=$KDEB_SOURCENAME
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index 8435b99452b6..ded8bcfc0247 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -23,6 +23,7 @@ absoulte||absolute
acccess||access
acceess||access
accelaration||acceleration
+accelearion||acceleration
acceleratoin||acceleration
accelleration||acceleration
accesing||accessing
@@ -58,6 +59,7 @@ acording||according
activete||activate
actived||activated
actualy||actually
+actvie||active
acumulating||accumulating
acumulative||accumulative
acumulator||accumulator
@@ -253,6 +255,7 @@ brigde||bridge
broadcase||broadcast
broadcat||broadcast
bufer||buffer
+bufferred||buffered
bufufer||buffer
cacluated||calculated
caculate||calculate
@@ -273,6 +276,7 @@ cant||can't
cant'||can't
canot||cannot
cann't||can't
+cannnot||cannot
capabilites||capabilities
capabilties||capabilities
capabilty||capability
@@ -309,6 +313,7 @@ chiled||child
chked||checked
chnage||change
chnages||changes
+chnange||change
chnnel||channel
choosen||chosen
chouse||chose
@@ -439,6 +444,7 @@ defferred||deferred
definate||definite
definately||definitely
definiation||definition
+definiton||definition
defintion||definition
defintions||definitions
defualt||default
@@ -452,6 +458,7 @@ delare||declare
delares||declares
delaring||declaring
delemiter||delimiter
+delibrately||deliberately
delievered||delivered
demodualtor||demodulator
demension||dimension
@@ -481,6 +488,7 @@ destroied||destroyed
detabase||database
deteced||detected
detectt||detect
+detroyed||destroyed
develope||develop
developement||development
developped||developed
@@ -507,6 +515,7 @@ dimention||dimension
dimesions||dimensions
diconnected||disconnected
disabed||disabled
+disasembler||disassembler
disble||disable
disgest||digest
disired||desired
@@ -666,6 +675,7 @@ finanize||finalize
findn||find
finilizes||finalizes
finsih||finish
+fliter||filter
flusing||flushing
folloing||following
followign||following
@@ -725,6 +735,7 @@ hanled||handled
happend||happened
hardare||hardware
harware||hardware
+hardward||hardware
havind||having
heirarchically||hierarchically
heirarchy||hierarchy
@@ -740,6 +751,7 @@ howver||however
hsould||should
hypervior||hypervisor
hypter||hyper
+idel||idle
identidier||identifier
iligal||illegal
illigal||illegal
@@ -931,9 +943,11 @@ matchs||matches
mathimatical||mathematical
mathimatic||mathematic
mathimatics||mathematics
+maxmium||maximum
maximium||maximum
maxium||maximum
mechamism||mechanism
+mechanim||mechanism
meetign||meeting
memeory||memory
memmber||member
@@ -942,6 +956,7 @@ memroy||memory
ment||meant
mergable||mergeable
mesage||message
+mesages||messages
messags||messages
messgaes||messages
messsage||message
@@ -983,8 +998,9 @@ monochromo||monochrome
monocrome||monochrome
mopdule||module
mroe||more
-multipler||multiplier
mulitplied||multiplied
+muliple||multiple
+multipler||multiplier
multidimensionnal||multidimensional
multipe||multiple
multple||multiple
@@ -1109,6 +1125,7 @@ peroid||period
persistance||persistence
persistant||persistent
phoneticly||phonetically
+plaform||platform
plalform||platform
platfoem||platform
platfrom||platform
@@ -1236,6 +1253,7 @@ refering||referring
refernces||references
refernnce||reference
refrence||reference
+regiser||register
registed||registered
registerd||registered
registeration||registration
@@ -1276,6 +1294,7 @@ reseting||resetting
reseved||reserved
reseverd||reserved
resizeable||resizable
+resotre||restore
resouce||resource
resouces||resources
resoures||resources
@@ -1314,6 +1333,7 @@ runtine||runtime
sacrifying||sacrificing
safly||safely
safty||safety
+satify||satisfy
savable||saveable
scaleing||scaling
scaned||scanned
@@ -1365,10 +1385,12 @@ similiar||similar
simlar||similar
simliar||similar
simpified||simplified
+simultaneusly||simultaneously
simultanous||simultaneous
singaled||signaled
singal||signal
singed||signed
+slect||select
sleeped||slept
sliped||slipped
softwade||software
@@ -1438,6 +1460,7 @@ suported||supported
suport||support
supportet||supported
suppored||supported
+supporing||supporting
supportin||supporting
suppoted||supported
suppported||supported
@@ -1475,15 +1498,18 @@ sytem||system
sythesis||synthesis
taht||that
tained||tainted
+tarffic||traffic
tansmit||transmit
targetted||targeted
targetting||targeting
taskelt||tasklet
teh||the
+temeprature||temperature
temorary||temporary
temproarily||temporarily
temperture||temperature
thead||thread
+theads||threads
therfore||therefore
thier||their
threds||threads
@@ -1533,12 +1559,14 @@ ture||true
tyep||type
udpate||update
uesd||used
+unknwon||unknown
uknown||unknown
usccess||success
uncommited||uncommitted
uncompatible||incompatible
unconditionaly||unconditionally
undeflow||underflow
+undelying||underlying
underun||underrun
unecessary||unnecessary
unexecpted||unexpected
@@ -1569,11 +1597,14 @@ unneedingly||unnecessarily
unnsupported||unsupported
unmached||unmatched
unprecise||imprecise
+unpriviledged||unprivileged
+unpriviliged||unprivileged
unregester||unregister
unresgister||unregister
unrgesiter||unregister
unsinged||unsigned
unstabel||unstable
+unsolicted||unsolicited
unsolicitied||unsolicited
unsuccessfull||unsuccessful
unsuported||unsupported
diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install
index ec84fc62774e..1fb88fdceec3 100755
--- a/scripts/sphinx-pre-install
+++ b/scripts/sphinx-pre-install
@@ -362,7 +362,6 @@ sub give_debian_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx-rtd-theme",
"ensurepip" => "python3-venv",
"virtualenv" => "virtualenv",
"dot" => "graphviz",
@@ -397,7 +396,6 @@ sub give_redhat_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -475,7 +473,6 @@ sub give_opensuse_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -523,7 +520,6 @@ sub give_mageia_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -567,7 +563,6 @@ sub give_mageia_hints()
sub give_arch_linux_hints()
{
my %map = (
- "sphinx_rtd_theme" => "python-sphinx_rtd_theme",
"virtualenv" => "python-virtualenv",
"dot" => "graphviz",
"convert" => "imagemagick",
@@ -598,7 +593,6 @@ sub give_arch_linux_hints()
sub give_gentoo_hints()
{
my %map = (
- "sphinx_rtd_theme" => "dev-python/sphinx_rtd_theme",
"virtualenv" => "dev-python/virtualenv",
"dot" => "media-gfx/graphviz",
"convert" => "media-gfx/imagemagick",
@@ -895,7 +889,6 @@ sub recommend_sphinx_version($)
$verbose_warn_install = 0;
add_package("python-sphinx", 0);
- check_python_module("sphinx_rtd_theme", 1);
check_distros();
@@ -968,7 +961,6 @@ sub check_needs()
check_perl_module("Pod::Usage", 0);
check_program("make", 0);
check_program("gcc", 0);
- check_python_module("sphinx_rtd_theme", 1) if (!$virtualenv);
check_program("dot", 1);
check_program("convert", 1);
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index cb3496e00d8a..f334e7cccf2d 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -106,8 +106,8 @@ config SECURITY_APPARMOR_PARANOID_LOAD
Disabling the check will speed up policy loads.
config SECURITY_APPARMOR_KUNIT_TEST
- bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
- depends on KUNIT=y && SECURITY_APPARMOR
+ tristate "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
+ depends on KUNIT && SECURITY_APPARMOR
default KUNIT_ALL_TESTS
help
This builds the AppArmor KUnit tests.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index ff23fcfefe19..065f4e346553 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -8,6 +8,9 @@ apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \
resource.o secid.o file.o policy_ns.o label.o mount.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
+obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o
+apparmor_policy_unpack_test-objs += policy_unpack_test.o
+
clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of address family names
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 91689d34d281..00dc0ec066de 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -311,10 +311,9 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
struct aa_profile *profile, unsigned int state)
{
int i;
- ssize_t size;
struct dentry *d;
char *value = NULL;
- int value_size = 0, ret = profile->xattr_count;
+ int size, value_size = 0, ret = profile->xattr_count;
if (!bprm || !profile->xattr_count)
return 0;
@@ -859,10 +858,10 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
const char *info = NULL;
int error = 0;
bool unsafe = false;
- kuid_t i_uid = i_uid_into_mnt(file_mnt_user_ns(bprm->file),
- file_inode(bprm->file));
+ vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(bprm->file),
+ file_inode(bprm->file));
struct path_cond cond = {
- i_uid,
+ vfsuid_into_kuid(vfsuid),
file_inode(bprm->file)->i_mode
};
@@ -970,7 +969,7 @@ audit:
error = fn_for_each(label, profile,
aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC,
bprm->filename, NULL, new,
- i_uid, info, error));
+ vfsuid_into_kuid(vfsuid), info, error));
aa_put_label(new);
goto done;
}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index e1b7e93602e4..d43679894d23 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -510,8 +510,10 @@ static int __file_path_perm(const char *op, struct aa_label *label,
{
struct aa_profile *profile;
struct aa_perms perms = {};
+ vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(file),
+ file_inode(file));
struct path_cond cond = {
- .uid = i_uid_into_mnt(file_mnt_user_ns(file), file_inode(file)),
+ .uid = vfsuid_into_kuid(vfsuid),
.mode = file_inode(file)->i_mode
};
char *buffer;
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index eb5f7d7f132b..e89b701447bc 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -49,6 +49,43 @@ enum {
};
/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data. The interface has the notion of a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data. Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatibility.
+ */
+
+enum aa_code {
+ AA_U8,
+ AA_U16,
+ AA_U32,
+ AA_U64,
+ AA_NAME, /* same as string except it is items name */
+ AA_STRING,
+ AA_BLOB,
+ AA_STRUCT,
+ AA_STRUCTEND,
+ AA_LIST,
+ AA_LISTEND,
+ AA_ARRAY,
+ AA_ARRAYEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile. The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+ void *start;
+ void *end;
+ void *pos; /* pointer to current position in the buffer */
+ u32 version;
+};
+
+/*
* struct aa_loaddata - buffer of policy raw_data set
*
* there is no loaddata ref for being on ns list, nor a ref from
@@ -126,4 +163,17 @@ static inline void aa_put_loaddata(struct aa_loaddata *data)
kref_put(&data->count, aa_loaddata_kref);
}
+#if IS_ENABLED(CONFIG_KUNIT)
+bool aa_inbounds(struct aa_ext *e, size_t size);
+size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk);
+bool aa_unpack_X(struct aa_ext *e, enum aa_code code);
+bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name);
+bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name);
+bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name);
+size_t aa_unpack_array(struct aa_ext *e, const char *name);
+size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name);
+int aa_unpack_str(struct aa_ext *e, const char **string, const char *name);
+int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name);
+#endif
+
#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index f56070270c69..ff14fe0ffca2 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -225,8 +225,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
static int common_perm_cond(const char *op, const struct path *path, u32 mask)
{
struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
+ vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns,
+ d_backing_inode(path->dentry));
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)),
+ vfsuid_into_kuid(vfsuid),
d_backing_inode(path->dentry)->i_mode
};
@@ -270,11 +272,13 @@ static int common_perm_rm(const char *op, const struct path *dir,
struct inode *inode = d_backing_inode(dentry);
struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
struct path_cond cond = { };
+ vfsuid_t vfsuid;
if (!inode || !path_mediated_fs(dentry))
return 0;
- cond.uid = i_uid_into_mnt(mnt_userns, inode);
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ cond.uid = vfsuid_into_kuid(vfsuid);
cond.mode = inode->i_mode;
return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
@@ -329,6 +333,11 @@ static int apparmor_path_truncate(const struct path *path)
return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR);
}
+static int apparmor_file_truncate(struct file *file)
+{
+ return apparmor_path_truncate(&file->f_path);
+}
+
static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
const char *old_name)
{
@@ -368,20 +377,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
label = begin_current_label_crit_section();
if (!unconfined(label)) {
struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
+ vfsuid_t vfsuid;
struct path old_path = { .mnt = old_dir->mnt,
.dentry = old_dentry };
struct path new_path = { .mnt = new_dir->mnt,
.dentry = new_dentry };
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)),
- d_backing_inode(old_dentry)->i_mode
+ .mode = d_backing_inode(old_dentry)->i_mode
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+ cond.uid = vfsuid_into_kuid(vfsuid);
if (flags & RENAME_EXCHANGE) {
struct path_cond cond_exchange = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)),
- d_backing_inode(new_dentry)->i_mode
+ .mode = d_backing_inode(new_dentry)->i_mode,
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+ cond_exchange.uid = vfsuid_into_kuid(vfsuid);
error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
@@ -447,10 +459,12 @@ static int apparmor_file_open(struct file *file)
if (!unconfined(label)) {
struct user_namespace *mnt_userns = file_mnt_user_ns(file);
struct inode *inode = file_inode(file);
+ vfsuid_t vfsuid;
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, inode),
- inode->i_mode
+ .mode = inode->i_mode,
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ cond.uid = vfsuid_into_kuid(vfsuid);
error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
@@ -1103,11 +1117,10 @@ static struct aa_label *sk_peer_label(struct sock *sk)
* Note: for tcp only valid if using ipsec or cipso on lan
*/
static int apparmor_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen,
+ sockptr_t optval, sockptr_t optlen,
unsigned int len)
{
- char *name;
+ char *name = NULL;
int slen, error = 0;
struct aa_label *label;
struct aa_label *peer;
@@ -1124,23 +1137,21 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
/* don't include terminating \0 in slen, it breaks some apps */
if (slen < 0) {
error = -ENOMEM;
- } else {
- if (slen > len) {
- error = -ERANGE;
- } else if (copy_to_user(optval, name, slen)) {
- error = -EFAULT;
- goto out;
- }
- if (put_user(slen, optlen))
- error = -EFAULT;
-out:
- kfree(name);
-
+ goto done;
+ }
+ if (slen > len) {
+ error = -ERANGE;
+ goto done_len;
}
+ if (copy_to_sockptr(optval, name, slen))
+ error = -EFAULT;
+done_len:
+ if (copy_to_sockptr(optlen, &slen, sizeof(slen)))
+ error = -EFAULT;
done:
end_current_label_crit_section(label);
-
+ kfree(name);
return error;
}
@@ -1232,6 +1243,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
LSM_HOOK_INIT(file_lock, apparmor_file_lock),
+ LSM_HOOK_INIT(file_truncate, apparmor_file_truncate),
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 55d31bac4f35..12e535fdfa8b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -14,6 +14,7 @@
*/
#include <asm/unaligned.h>
+#include <kunit/visibility.h>
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/zlib.h>
@@ -37,43 +38,6 @@
#define v7 7
#define v8 8 /* full network masking */
-/*
- * The AppArmor interface treats data as a type byte followed by the
- * actual data. The interface has the notion of a named entry
- * which has a name (AA_NAME typecode followed by name string) followed by
- * the entries typecode and data. Named types allow for optional
- * elements and extensions to be added and tested for without breaking
- * backwards compatibility.
- */
-
-enum aa_code {
- AA_U8,
- AA_U16,
- AA_U32,
- AA_U64,
- AA_NAME, /* same as string except it is items name */
- AA_STRING,
- AA_BLOB,
- AA_STRUCT,
- AA_STRUCTEND,
- AA_LIST,
- AA_LISTEND,
- AA_ARRAY,
- AA_ARRAYEND,
-};
-
-/*
- * aa_ext is the read of the buffer containing the serialized profile. The
- * data is copied into a kernel buffer in apparmorfs and then handed off to
- * the unpack routines.
- */
-struct aa_ext {
- void *start;
- void *end;
- void *pos; /* pointer to current position in the buffer */
- u32 version;
-};
-
/* audit callback for unpack fields */
static void audit_cb(struct audit_buffer *ab, void *va)
{
@@ -199,10 +163,11 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size)
}
/* test if read will be in packed data bounds */
-static bool inbounds(struct aa_ext *e, size_t size)
+VISIBLE_IF_KUNIT bool aa_inbounds(struct aa_ext *e, size_t size)
{
return (size <= e->end - e->pos);
}
+EXPORT_SYMBOL_IF_KUNIT(aa_inbounds);
static void *kvmemdup(const void *src, size_t len)
{
@@ -214,22 +179,22 @@ static void *kvmemdup(const void *src, size_t len)
}
/**
- * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
+ * aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL)
* @chunk: start address for chunk of data (NOT NULL)
*
* Returns: the size of chunk found with the read head at the end of the chunk.
*/
-static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
+VISIBLE_IF_KUNIT size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk)
{
size_t size = 0;
void *pos = e->pos;
- if (!inbounds(e, sizeof(u16)))
+ if (!aa_inbounds(e, sizeof(u16)))
goto fail;
size = le16_to_cpu(get_unaligned((__le16 *) e->pos));
e->pos += sizeof(__le16);
- if (!inbounds(e, size))
+ if (!aa_inbounds(e, size))
goto fail;
*chunk = e->pos;
e->pos += size;
@@ -239,20 +204,22 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u16_chunk);
/* unpack control byte */
-static bool unpack_X(struct aa_ext *e, enum aa_code code)
+VISIBLE_IF_KUNIT bool aa_unpack_X(struct aa_ext *e, enum aa_code code)
{
- if (!inbounds(e, 1))
+ if (!aa_inbounds(e, 1))
return false;
if (*(u8 *) e->pos != code)
return false;
e->pos++;
return true;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_X);
/**
- * unpack_nameX - check is the next element is of type X with a name of @name
+ * aa_unpack_nameX - check is the next element is of type X with a name of @name
* @e: serialized data extent information (NOT NULL)
* @code: type code
* @name: name to match to the serialized element. (MAYBE NULL)
@@ -267,7 +234,7 @@ static bool unpack_X(struct aa_ext *e, enum aa_code code)
*
* Returns: false if either match fails, the read head does not move
*/
-static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
{
/*
* May need to reset pos if name or type doesn't match
@@ -277,9 +244,9 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
* Check for presence of a tagname, and if present name size
* AA_NAME tag value is a u16.
*/
- if (unpack_X(e, AA_NAME)) {
+ if (aa_unpack_X(e, AA_NAME)) {
char *tag = NULL;
- size_t size = unpack_u16_chunk(e, &tag);
+ size_t size = aa_unpack_u16_chunk(e, &tag);
/* if a name is specified it must match. otherwise skip tag */
if (name && (!size || tag[size-1] != '\0' || strcmp(name, tag)))
goto fail;
@@ -289,20 +256,21 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
}
/* now check if type code matches */
- if (unpack_X(e, code))
+ if (aa_unpack_X(e, code))
return true;
fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_nameX);
static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U8, name)) {
- if (!inbounds(e, sizeof(u8)))
+ if (aa_unpack_nameX(e, AA_U8, name)) {
+ if (!aa_inbounds(e, sizeof(u8)))
goto fail;
if (data)
*data = *((u8 *)e->pos);
@@ -315,12 +283,12 @@ fail:
return false;
}
-static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U32, name)) {
- if (!inbounds(e, sizeof(u32)))
+ if (aa_unpack_nameX(e, AA_U32, name)) {
+ if (!aa_inbounds(e, sizeof(u32)))
goto fail;
if (data)
*data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
@@ -332,13 +300,14 @@ fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u32);
-static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U64, name)) {
- if (!inbounds(e, sizeof(u64)))
+ if (aa_unpack_nameX(e, AA_U64, name)) {
+ if (!aa_inbounds(e, sizeof(u64)))
goto fail;
if (data)
*data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
@@ -350,14 +319,15 @@ fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u64);
-static size_t unpack_array(struct aa_ext *e, const char *name)
+VISIBLE_IF_KUNIT size_t aa_unpack_array(struct aa_ext *e, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_ARRAY, name)) {
+ if (aa_unpack_nameX(e, AA_ARRAY, name)) {
int size;
- if (!inbounds(e, sizeof(u16)))
+ if (!aa_inbounds(e, sizeof(u16)))
goto fail;
size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos));
e->pos += sizeof(u16);
@@ -368,18 +338,19 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_array);
-static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
+VISIBLE_IF_KUNIT size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_BLOB, name)) {
+ if (aa_unpack_nameX(e, AA_BLOB, name)) {
u32 size;
- if (!inbounds(e, sizeof(u32)))
+ if (!aa_inbounds(e, sizeof(u32)))
goto fail;
size = le32_to_cpu(get_unaligned((__le32 *) e->pos));
e->pos += sizeof(u32);
- if (inbounds(e, (size_t) size)) {
+ if (aa_inbounds(e, (size_t) size)) {
*blob = e->pos;
e->pos += size;
return size;
@@ -390,15 +361,16 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_blob);
-static int unpack_str(struct aa_ext *e, const char **string, const char *name)
+VISIBLE_IF_KUNIT int aa_unpack_str(struct aa_ext *e, const char **string, const char *name)
{
char *src_str;
size_t size = 0;
void *pos = e->pos;
*string = NULL;
- if (unpack_nameX(e, AA_STRING, name)) {
- size = unpack_u16_chunk(e, &src_str);
+ if (aa_unpack_nameX(e, AA_STRING, name)) {
+ size = aa_unpack_u16_chunk(e, &src_str);
if (size) {
/* strings are null terminated, length is size - 1 */
if (src_str[size - 1] != 0)
@@ -413,12 +385,13 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_str);
-static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
+VISIBLE_IF_KUNIT int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name)
{
const char *tmp;
void *pos = e->pos;
- int res = unpack_str(e, &tmp, name);
+ int res = aa_unpack_str(e, &tmp, name);
*string = NULL;
if (!res)
@@ -432,6 +405,7 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
return res;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_strdup);
/**
@@ -446,7 +420,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
size_t size;
struct aa_dfa *dfa = NULL;
- size = unpack_blob(e, &blob, "aadfa");
+ size = aa_unpack_blob(e, &blob, "aadfa");
if (size) {
/*
* The dfa is aligned with in the blob to 8 bytes
@@ -482,10 +456,10 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
void *saved_pos = e->pos;
/* exec table is optional */
- if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) {
int i, size;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
/* currently 4 exec bits and entries 0-3 are reserved iupcx */
if (size > 16 - 4)
goto fail;
@@ -497,8 +471,8 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
profile->file.trans.size = size;
for (i = 0; i < size; i++) {
char *str;
- int c, j, pos, size2 = unpack_strdup(e, &str, NULL);
- /* unpack_strdup verifies that the last character is
+ int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL);
+ /* aa_unpack_strdup verifies that the last character is
* null termination byte.
*/
if (!size2)
@@ -521,7 +495,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
goto fail;
/* beginning with : requires an embedded \0,
* verify that exactly 1 internal \0 exists
- * trailing \0 already verified by unpack_strdup
+ * trailing \0 already verified by aa_unpack_strdup
*
* convert \0 back to : for label_parse
*/
@@ -533,9 +507,9 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
/* fail - all other cases with embedded \0 */
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
return true;
@@ -550,21 +524,21 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_STRUCT, "xattrs")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "xattrs")) {
int i, size;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
profile->xattr_count = size;
profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
if (!profile->xattrs)
goto fail;
for (i = 0; i < size; i++) {
- if (!unpack_strdup(e, &profile->xattrs[i], NULL))
+ if (!aa_unpack_strdup(e, &profile->xattrs[i], NULL))
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -580,8 +554,8 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
void *pos = e->pos;
int i, size;
- if (unpack_nameX(e, AA_STRUCT, "secmark")) {
- size = unpack_array(e, NULL);
+ if (aa_unpack_nameX(e, AA_STRUCT, "secmark")) {
+ size = aa_unpack_array(e, NULL);
profile->secmark = kcalloc(size, sizeof(struct aa_secmark),
GFP_KERNEL);
@@ -595,12 +569,12 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
goto fail;
if (!unpack_u8(e, &profile->secmark[i].deny, NULL))
goto fail;
- if (!unpack_strdup(e, &profile->secmark[i].label, NULL))
+ if (!aa_unpack_strdup(e, &profile->secmark[i].label, NULL))
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -624,26 +598,26 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
void *pos = e->pos;
/* rlimits are optional */
- if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "rlimits")) {
int i, size;
u32 tmp = 0;
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
profile->rlimits.mask = tmp;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
if (size > RLIM_NLIMITS)
goto fail;
for (i = 0; i < size; i++) {
u64 tmp2 = 0;
int a = aa_map_resource(i);
- if (!unpack_u64(e, &tmp2, NULL))
+ if (!aa_unpack_u64(e, &tmp2, NULL))
goto fail;
profile->rlimits.limits[a].rlim_max = tmp2;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
return true;
@@ -691,9 +665,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
*ns_name = NULL;
/* check that we have the right struct being passed */
- if (!unpack_nameX(e, AA_STRUCT, "profile"))
+ if (!aa_unpack_nameX(e, AA_STRUCT, "profile"))
goto fail;
- if (!unpack_str(e, &name, NULL))
+ if (!aa_unpack_str(e, &name, NULL))
goto fail;
if (*name == '\0')
goto fail;
@@ -713,10 +687,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
return ERR_PTR(-ENOMEM);
/* profile renaming is optional */
- (void) unpack_str(e, &profile->rename, "rename");
+ (void) aa_unpack_str(e, &profile->rename, "rename");
/* attachment string is optional */
- (void) unpack_str(e, &profile->attach, "attach");
+ (void) aa_unpack_str(e, &profile->attach, "attach");
/* xmatch is optional and may be NULL */
profile->xmatch = unpack_dfa(e);
@@ -728,7 +702,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* xmatch_len is not optional if xmatch is set */
if (profile->xmatch) {
- if (!unpack_u32(e, &tmp, NULL)) {
+ if (!aa_unpack_u32(e, &tmp, NULL)) {
info = "missing xmatch len";
goto fail;
}
@@ -736,15 +710,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* disconnected attachment string is optional */
- (void) unpack_str(e, &profile->disconnected, "disconnected");
+ (void) aa_unpack_str(e, &profile->disconnected, "disconnected");
/* per profile debug flags (complain, audit) */
- if (!unpack_nameX(e, AA_STRUCT, "flags")) {
+ if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) {
info = "profile missing flags";
goto fail;
}
info = "failed to unpack profile flags";
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp & PACKED_FLAG_HAT)
profile->label.flags |= FLAG_HAT;
@@ -752,7 +726,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->label.flags |= FLAG_DEBUG1;
if (tmp & PACKED_FLAG_DEBUG2)
profile->label.flags |= FLAG_DEBUG2;
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
profile->mode = APPARMOR_COMPLAIN;
@@ -766,16 +740,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
} else {
goto fail;
}
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp)
profile->audit = AUDIT_ALL;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
/* path_flags is optional */
- if (unpack_u32(e, &profile->path_flags, "path_flags"))
+ if (aa_unpack_u32(e, &profile->path_flags, "path_flags"))
profile->path_flags |= profile->label.flags &
PATH_MEDIATE_DELETED;
else
@@ -783,38 +757,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->path_flags = PATH_MEDIATE_DELETED;
info = "failed to unpack profile capabilities";
- if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+ if (!aa_unpack_u32(e, &tmpcap.cap[0], NULL))
goto fail;
info = "failed to unpack upper profile capabilities";
- if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "caps64")) {
/* optional upper half of 64 bit caps */
- if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(tmpcap.cap[1]), NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
info = "failed to unpack extended profile capabilities";
- if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "capsx")) {
/* optional extended caps mediation mask */
- if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -833,7 +807,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- if (unpack_nameX(e, AA_STRUCT, "policydb")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
info = "failed to unpack policydb";
profile->policy.dfa = unpack_dfa(e);
@@ -845,7 +819,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
error = -EPROTO;
goto fail;
}
- if (!unpack_u32(e, &profile->policy.start[0], "start"))
+ if (!aa_unpack_u32(e, &profile->policy.start[0], "start"))
/* default start state */
profile->policy.start[0] = DFA_START;
/* setup class index */
@@ -855,7 +829,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->policy.start[0],
i);
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
} else
profile->policy.dfa = aa_get_dfa(nulldfa);
@@ -868,7 +842,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
info = "failed to unpack profile file rules";
goto fail;
} else if (profile->file.dfa) {
- if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+ if (!aa_unpack_u32(e, &profile->file.start, "dfa_start"))
/* default start state */
profile->file.start = DFA_START;
} else if (profile->policy.dfa &&
@@ -883,7 +857,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- if (unpack_nameX(e, AA_STRUCT, "data")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
info = "out of memory";
profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
if (!profile->data)
@@ -901,7 +875,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- while (unpack_strdup(e, &key, NULL)) {
+ while (aa_unpack_strdup(e, &key, NULL)) {
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
kfree_sensitive(key);
@@ -909,7 +883,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
data->key = key;
- data->size = unpack_blob(e, &data->data, NULL);
+ data->size = aa_unpack_blob(e, &data->data, NULL);
data->data = kvmemdup(data->data, data->size);
if (data->size && !data->data) {
kfree_sensitive(data->key);
@@ -921,13 +895,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->data->p);
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) {
info = "failed to unpack end of key, value data table";
goto fail;
}
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) {
info = "failed to unpack end of profile";
goto fail;
}
@@ -960,7 +934,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
*ns = NULL;
/* get the interface version */
- if (!unpack_u32(e, &e->version, "version")) {
+ if (!aa_unpack_u32(e, &e->version, "version")) {
if (required) {
audit_iface(NULL, NULL, NULL, "invalid profile format",
e, error);
@@ -979,7 +953,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
}
/* read the namespace if present */
- if (unpack_str(e, &name, "namespace")) {
+ if (aa_unpack_str(e, &name, "namespace")) {
if (*name == '\0') {
audit_iface(NULL, NULL, NULL, "invalid namespace name",
e, error);
@@ -1251,7 +1225,3 @@ fail:
return error;
}
-
-#ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST
-#include "policy_unpack_test.c"
-#endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */
diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c
index 0a969b2e03db..f25cf2a023d5 100644
--- a/security/apparmor/policy_unpack_test.c
+++ b/security/apparmor/policy_unpack_test.c
@@ -4,6 +4,7 @@
*/
#include <kunit/test.h>
+#include <kunit/visibility.h>
#include "include/policy.h"
#include "include/policy_unpack.h"
@@ -43,6 +44,8 @@
#define TEST_ARRAY_BUF_OFFSET \
(TEST_NAMED_ARRAY_BUF_OFFSET + 3 + strlen(TEST_ARRAY_NAME) + 1)
+MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
+
struct policy_unpack_fixture {
struct aa_ext *e;
size_t e_size;
@@ -125,16 +128,16 @@ static void policy_unpack_test_inbounds_when_inbounds(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, 0));
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size / 2));
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, 0));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size / 2));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size));
}
static void policy_unpack_test_inbounds_when_out_of_bounds(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- KUNIT_EXPECT_FALSE(test, inbounds(puf->e, puf->e_size + 1));
+ KUNIT_EXPECT_FALSE(test, aa_inbounds(puf->e, puf->e_size + 1));
}
static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test)
@@ -144,7 +147,7 @@ static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test)
puf->e->pos += TEST_ARRAY_BUF_OFFSET;
- array_size = unpack_array(puf->e, NULL);
+ array_size = aa_unpack_array(puf->e, NULL);
KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -159,7 +162,7 @@ static void policy_unpack_test_unpack_array_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;
- array_size = unpack_array(puf->e, name);
+ array_size = aa_unpack_array(puf->e, name);
KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -175,7 +178,7 @@ static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16);
- array_size = unpack_array(puf->e, name);
+ array_size = aa_unpack_array(puf->e, name);
KUNIT_EXPECT_EQ(test, array_size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -189,7 +192,7 @@ static void policy_unpack_test_unpack_blob_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_BLOB_BUF_OFFSET;
- size = unpack_blob(puf->e, &blob, NULL);
+ size = aa_unpack_blob(puf->e, &blob, NULL);
KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
KUNIT_EXPECT_TRUE(test,
@@ -203,7 +206,7 @@ static void policy_unpack_test_unpack_blob_with_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET;
- size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
+ size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
KUNIT_EXPECT_TRUE(test,
@@ -222,7 +225,7 @@ static void policy_unpack_test_unpack_blob_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->start + TEST_BLOB_BUF_OFFSET
+ TEST_BLOB_DATA_SIZE - 1;
- size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
+ size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
@@ -235,7 +238,7 @@ static void policy_unpack_test_unpack_str_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_STRING_BUF_OFFSET;
- size = unpack_str(puf->e, &string, NULL);
+ size = aa_unpack_str(puf->e, &string, NULL);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
@@ -247,7 +250,7 @@ static void policy_unpack_test_unpack_str_with_name(struct kunit *test)
const char *string = NULL;
size_t size;
- size = unpack_str(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
@@ -263,7 +266,7 @@ static void policy_unpack_test_unpack_str_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
+ strlen(TEST_STRING_DATA) - 1;
- size = unpack_str(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
@@ -276,7 +279,7 @@ static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_STRING_BUF_OFFSET;
- size = unpack_strdup(puf->e, &string, NULL);
+ size = aa_unpack_strdup(puf->e, &string, NULL);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_FALSE(test,
@@ -291,7 +294,7 @@ static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test)
char *string = NULL;
size_t size;
- size = unpack_strdup(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_FALSE(test,
@@ -310,7 +313,7 @@ static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
+ strlen(TEST_STRING_DATA) - 1;
- size = unpack_strdup(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, string);
@@ -324,7 +327,7 @@ static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, NULL);
+ success = aa_unpack_nameX(puf->e, AA_U32, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -338,7 +341,7 @@ static void policy_unpack_test_unpack_nameX_with_wrong_code(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_BLOB, NULL);
+ success = aa_unpack_nameX(puf->e, AA_BLOB, NULL);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -353,7 +356,7 @@ static void policy_unpack_test_unpack_nameX_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, name);
+ success = aa_unpack_nameX(puf->e, AA_U32, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -368,7 +371,7 @@ static void policy_unpack_test_unpack_nameX_with_wrong_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, name);
+ success = aa_unpack_nameX(puf->e, AA_U32, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -389,7 +392,7 @@ static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test)
*/
puf->e->end += TEST_U16_DATA;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_PTR_EQ(test, chunk,
puf->e->start + TEST_U16_OFFSET + 2);
@@ -406,7 +409,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1(
puf->e->pos = puf->e->end - 1;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, chunk);
@@ -428,7 +431,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2(
*/
puf->e->end = puf->e->pos + TEST_U16_DATA - 1;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, chunk);
@@ -443,7 +446,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_u32(puf->e, &data, NULL);
+ success = aa_unpack_u32(puf->e, &data, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
@@ -460,7 +463,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_u32(puf->e, &data, name);
+ success = aa_unpack_u32(puf->e, &data, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
@@ -478,7 +481,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);
- success = unpack_u32(puf->e, &data, name);
+ success = aa_unpack_u32(puf->e, &data, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -493,7 +496,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test)
puf->e->pos += TEST_U64_BUF_OFFSET;
- success = unpack_u64(puf->e, &data, NULL);
+ success = aa_unpack_u64(puf->e, &data, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
@@ -510,7 +513,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
- success = unpack_u64(puf->e, &data, name);
+ success = aa_unpack_u64(puf->e, &data, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
@@ -528,7 +531,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);
- success = unpack_u64(puf->e, &data, name);
+ success = aa_unpack_u64(puf->e, &data, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -538,7 +541,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
static void policy_unpack_test_unpack_X_code_match(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- bool success = unpack_X(puf->e, AA_NAME);
+ bool success = aa_unpack_X(puf->e, AA_NAME);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start + 1);
@@ -547,7 +550,7 @@ static void policy_unpack_test_unpack_X_code_match(struct kunit *test)
static void policy_unpack_test_unpack_X_code_mismatch(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- bool success = unpack_X(puf->e, AA_STRING);
+ bool success = aa_unpack_X(puf->e, AA_STRING);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start);
@@ -559,7 +562,7 @@ static void policy_unpack_test_unpack_X_out_of_bounds(struct kunit *test)
bool success;
puf->e->pos = puf->e->end;
- success = unpack_X(puf->e, AA_NAME);
+ success = aa_unpack_X(puf->e, AA_NAME);
KUNIT_EXPECT_FALSE(test, success);
}
@@ -605,3 +608,5 @@ static struct kunit_suite apparmor_policy_unpack_test_module = {
};
kunit_test_suite(apparmor_policy_unpack_test_module);
+
+MODULE_LICENSE("GPL");
diff --git a/security/commoncap.c b/security/commoncap.c
index bc751fa5adad..1164278b97fd 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -328,14 +328,16 @@ int cap_inode_killpriv(struct user_namespace *mnt_userns, struct dentry *dentry)
return error;
}
-static bool rootid_owns_currentns(kuid_t kroot)
+static bool rootid_owns_currentns(vfsuid_t rootvfsuid)
{
struct user_namespace *ns;
+ kuid_t kroot;
- if (!uid_valid(kroot))
+ if (!vfsuid_valid(rootvfsuid))
return false;
- for (ns = current_user_ns(); ; ns = ns->parent) {
+ kroot = vfsuid_into_kuid(rootvfsuid);
+ for (ns = current_user_ns();; ns = ns->parent) {
if (from_kuid(ns, kroot) == 0)
return true;
if (ns == &init_user_ns)
@@ -350,14 +352,14 @@ static __u32 sansflags(__u32 m)
return m & ~VFS_CAP_FLAGS_EFFECTIVE;
}
-static bool is_v2header(size_t size, const struct vfs_cap_data *cap)
+static bool is_v2header(int size, const struct vfs_cap_data *cap)
{
if (size != XATTR_CAPS_SZ_2)
return false;
return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;
}
-static bool is_v3header(size_t size, const struct vfs_cap_data *cap)
+static bool is_v3header(int size, const struct vfs_cap_data *cap)
{
if (size != XATTR_CAPS_SZ_3)
return false;
@@ -379,8 +381,9 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
struct inode *inode, const char *name, void **buffer,
bool alloc)
{
- int size, ret;
+ int size;
kuid_t kroot;
+ vfsuid_t vfsroot;
u32 nsmagic, magic;
uid_t root, mappedroot;
char *tmpbuf = NULL;
@@ -395,22 +398,18 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
dentry = d_find_any_alias(inode);
if (!dentry)
return -EINVAL;
-
- size = sizeof(struct vfs_ns_cap_data);
- ret = (int)vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS,
- &tmpbuf, size, GFP_NOFS);
+ size = vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS, &tmpbuf,
+ sizeof(struct vfs_ns_cap_data), GFP_NOFS);
dput(dentry);
-
- if (ret < 0 || !tmpbuf) {
- size = ret;
+ /* gcc11 complains if we don't check for !tmpbuf */
+ if (size < 0 || !tmpbuf)
goto out_free;
- }
fs_ns = inode->i_sb->s_user_ns;
cap = (struct vfs_cap_data *) tmpbuf;
- if (is_v2header((size_t) ret, cap)) {
+ if (is_v2header(size, cap)) {
root = 0;
- } else if (is_v3header((size_t) ret, cap)) {
+ } else if (is_v3header(size, cap)) {
nscap = (struct vfs_ns_cap_data *) tmpbuf;
root = le32_to_cpu(nscap->rootid);
} else {
@@ -421,11 +420,11 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
kroot = make_kuid(fs_ns, root);
/* If this is an idmapped mount shift the kuid. */
- kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot);
+ vfsroot = make_vfsuid(mnt_userns, fs_ns, kroot);
/* If the root kuid maps to a valid uid in current ns, then return
* this as a nscap. */
- mappedroot = from_kuid(current_user_ns(), kroot);
+ mappedroot = from_kuid(current_user_ns(), vfsuid_into_kuid(vfsroot));
if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
size = sizeof(struct vfs_ns_cap_data);
if (alloc) {
@@ -452,7 +451,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
goto out_free;
}
- if (!rootid_owns_currentns(kroot)) {
+ if (!rootid_owns_currentns(vfsroot)) {
size = -EOVERFLOW;
goto out_free;
}
@@ -490,29 +489,17 @@ out_free:
* @value: vfs caps value which may be modified by this function
* @size: size of @ivalue
* @task_ns: user namespace of the caller
- * @mnt_userns: user namespace of the mount the inode was found from
- * @fs_userns: user namespace of the filesystem
- *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then
- * take care to map the inode according to @mnt_userns before checking
- * permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs init_user_ns.
*/
-static kuid_t rootid_from_xattr(const void *value, size_t size,
- struct user_namespace *task_ns,
- struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns)
+static vfsuid_t rootid_from_xattr(const void *value, size_t size,
+ struct user_namespace *task_ns)
{
const struct vfs_ns_cap_data *nscap = value;
- kuid_t rootkid;
uid_t rootid = 0;
if (size == XATTR_CAPS_SZ_3)
rootid = le32_to_cpu(nscap->rootid);
- rootkid = make_kuid(task_ns, rootid);
- return mapped_kuid_user(mnt_userns, fs_userns, rootkid);
+ return VFSUIDT_INIT(make_kuid(task_ns, rootid));
}
static bool validheader(size_t size, const struct vfs_cap_data *cap)
@@ -550,6 +537,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
struct user_namespace *task_ns = current_user_ns(),
*fs_ns = inode->i_sb->s_user_ns;
kuid_t rootid;
+ vfsuid_t vfsrootid;
size_t newsize;
if (!*ivalue)
@@ -563,7 +551,11 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
/* user is privileged, just write the v2 */
return size;
- rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns);
+ vfsrootid = rootid_from_xattr(*ivalue, size, task_ns);
+ if (!vfsuid_valid(vfsrootid))
+ return -EINVAL;
+
+ rootid = from_vfsuid(mnt_userns, fs_ns, vfsrootid);
if (!uid_valid(rootid))
return -EINVAL;
@@ -657,6 +649,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
struct vfs_ns_cap_data data, *nscaps = &data;
struct vfs_cap_data *caps = (struct vfs_cap_data *) &data;
kuid_t rootkuid;
+ vfsuid_t rootvfsuid;
struct user_namespace *fs_ns;
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
@@ -701,11 +694,15 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
default:
return -EINVAL;
}
+
+ rootvfsuid = make_vfsuid(mnt_userns, fs_ns, rootkuid);
+ if (!vfsuid_valid(rootvfsuid))
+ return -ENODATA;
+
/* Limit the caps to the mounter of the filesystem
* or the more limited uid specified in the xattr.
*/
- rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid);
- if (!rootid_owns_currentns(rootkuid))
+ if (!rootid_owns_currentns(rootvfsuid))
return -ENODATA;
CAP_FOR_EACH_U32(i) {
@@ -718,7 +715,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
- cpu_caps->rootid = rootkuid;
+ cpu_caps->rootid = vfsuid_into_kuid(rootvfsuid);
return 0;
}
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index a9f8c63a96d1..bef2b9285fb3 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -82,6 +82,17 @@ free_and_exit:
return -ENOMEM;
}
+static void dev_exceptions_move(struct list_head *dest, struct list_head *orig)
+{
+ struct dev_exception_item *ex, *tmp;
+
+ lockdep_assert_held(&devcgroup_mutex);
+
+ list_for_each_entry_safe(ex, tmp, orig, list) {
+ list_move_tail(&ex->list, dest);
+ }
+}
+
/*
* called under devcgroup_mutex
*/
@@ -604,11 +615,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
int count, rc = 0;
struct dev_exception_item ex;
struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
+ struct dev_cgroup tmp_devcgrp;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
memset(&ex, 0, sizeof(ex));
+ memset(&tmp_devcgrp, 0, sizeof(tmp_devcgrp));
b = buffer;
switch (*b) {
@@ -620,15 +633,27 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
if (!may_allow_all(parent))
return -EPERM;
- dev_exception_clean(devcgroup);
- devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
- if (!parent)
+ if (!parent) {
+ devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
+ dev_exception_clean(devcgroup);
break;
+ }
+ INIT_LIST_HEAD(&tmp_devcgrp.exceptions);
+ rc = dev_exceptions_copy(&tmp_devcgrp.exceptions,
+ &devcgroup->exceptions);
+ if (rc)
+ return rc;
+ dev_exception_clean(devcgroup);
rc = dev_exceptions_copy(&devcgroup->exceptions,
&parent->exceptions);
- if (rc)
+ if (rc) {
+ dev_exceptions_move(&devcgroup->exceptions,
+ &tmp_devcgrp.exceptions);
return rc;
+ }
+ devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
+ dev_exception_clean(&tmp_devcgrp);
break;
case DEVCG_DENY:
if (css_has_online_children(&devcgroup->css))
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 708de9656bbd..fa5ff13fa8c9 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -335,14 +335,15 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
(char **)&xattr_data, 0, GFP_NOFS);
if (rc <= 0) {
if (rc == -ENODATA)
- return 0;
- return rc;
+ rc = 0;
+ goto out;
}
if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG)
rc = 1;
else
rc = 0;
+out:
kfree(xattr_data);
return rc;
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 23d484e05e6f..f02e609460e2 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -8,7 +8,7 @@
*
* File: evm_main.c
* implements evm_inode_setxattr, evm_inode_post_setxattr,
- * evm_inode_removexattr, and evm_verifyxattr
+ * evm_inode_removexattr, evm_verifyxattr, and evm_inode_set_acl.
*/
#define pr_fmt(fmt) "EVM: "fmt
@@ -435,66 +435,6 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
}
/*
- * evm_xattr_acl_change - check if passed ACL changes the inode mode
- * @mnt_userns: user namespace of the idmapped mount
- * @dentry: pointer to the affected dentry
- * @xattr_name: requested xattr
- * @xattr_value: requested xattr value
- * @xattr_value_len: requested xattr value length
- *
- * Check if passed ACL changes the inode mode, which is protected by EVM.
- *
- * Returns 1 if passed ACL causes inode mode change, 0 otherwise.
- */
-static int evm_xattr_acl_change(struct user_namespace *mnt_userns,
- struct dentry *dentry, const char *xattr_name,
- const void *xattr_value, size_t xattr_value_len)
-{
-#ifdef CONFIG_FS_POSIX_ACL
- umode_t mode;
- struct posix_acl *acl = NULL, *acl_res;
- struct inode *inode = d_backing_inode(dentry);
- int rc;
-
- /*
- * An earlier comment here mentioned that the idmappings for
- * ACL_{GROUP,USER} don't matter since EVM is only interested in the
- * mode stored as part of POSIX ACLs. Nonetheless, if it must translate
- * from the uapi POSIX ACL representation to the VFS internal POSIX ACL
- * representation it should do so correctly. There's no guarantee that
- * we won't change POSIX ACLs in a way that ACL_{GROUP,USER} matters
- * for the mode at some point and it's difficult to keep track of all
- * the LSM and integrity modules and what they do to POSIX ACLs.
- *
- * Frankly, EVM shouldn't try to interpret the uapi struct for POSIX
- * ACLs it received. It requires knowledge that only the VFS is
- * guaranteed to have.
- */
- acl = vfs_set_acl_prepare(mnt_userns, i_user_ns(inode),
- xattr_value, xattr_value_len);
- if (IS_ERR_OR_NULL(acl))
- return 1;
-
- acl_res = acl;
- /*
- * Passing mnt_userns is necessary to correctly determine the GID in
- * an idmapped mount, as the GID is used to clear the setgid bit in
- * the inode mode.
- */
- rc = posix_acl_update_mode(mnt_userns, inode, &mode, &acl_res);
-
- posix_acl_release(acl);
-
- if (rc)
- return 1;
-
- if (inode->i_mode != mode)
- return 1;
-#endif
- return 0;
-}
-
-/*
* evm_xattr_change - check if passed xattr value differs from current value
* @mnt_userns: user namespace of the idmapped mount
* @dentry: pointer to the affected dentry
@@ -513,20 +453,19 @@ static int evm_xattr_change(struct user_namespace *mnt_userns,
char *xattr_data = NULL;
int rc = 0;
- if (posix_xattr_acl(xattr_name))
- return evm_xattr_acl_change(mnt_userns, dentry, xattr_name,
- xattr_value, xattr_value_len);
-
rc = vfs_getxattr_alloc(&init_user_ns, dentry, xattr_name, &xattr_data,
0, GFP_NOFS);
- if (rc < 0)
- return 1;
+ if (rc < 0) {
+ rc = 1;
+ goto out;
+ }
if (rc == xattr_value_len)
rc = !!memcmp(xattr_value, xattr_data, rc);
else
rc = 1;
+out:
kfree(xattr_data);
return rc;
}
@@ -670,6 +609,86 @@ int evm_inode_removexattr(struct user_namespace *mnt_userns,
return evm_protect_xattr(mnt_userns, dentry, xattr_name, NULL, 0);
}
+#ifdef CONFIG_FS_POSIX_ACL
+static int evm_inode_set_acl_change(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *name,
+ struct posix_acl *kacl)
+{
+ int rc;
+
+ umode_t mode;
+ struct inode *inode = d_backing_inode(dentry);
+
+ if (!kacl)
+ return 1;
+
+ rc = posix_acl_update_mode(mnt_userns, inode, &mode, &kacl);
+ if (rc || (inode->i_mode != mode))
+ return 1;
+
+ return 0;
+}
+#else
+static inline int evm_inode_set_acl_change(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *name,
+ struct posix_acl *kacl)
+{
+ return 0;
+}
+#endif
+
+/**
+ * evm_inode_set_acl - protect the EVM extended attribute from posix acls
+ * @mnt_userns: user namespace of the idmapped mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ * @kacl: pointer to the posix acls
+ *
+ * Prevent modifying posix acls causing the EVM HMAC to be re-calculated
+ * and 'security.evm' xattr updated, unless the existing 'security.evm' is
+ * valid.
+ */
+int evm_inode_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
+{
+ enum integrity_status evm_status;
+
+ /* Policy permits modification of the protected xattrs even though
+ * there's no HMAC key loaded
+ */
+ if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
+ return 0;
+
+ evm_status = evm_verify_current_integrity(dentry);
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS))
+ return 0;
+
+ /* Exception if the HMAC is not going to be calculated. */
+ if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
+ evm_status == INTEGRITY_UNKNOWN))
+ return 0;
+
+ /*
+ * Writing other xattrs is safe for portable signatures, as portable
+ * signatures are immutable and can never be updated.
+ */
+ if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
+ return 0;
+
+ if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+ !evm_inode_set_acl_change(mnt_userns, dentry, acl_name, kacl))
+ return 0;
+
+ if (evm_status != INTEGRITY_PASS_IMMUTABLE)
+ integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
+ dentry->d_name.name, "appraise_metadata",
+ integrity_status_msg[evm_status],
+ -EPERM, 0);
+ return -EPERM;
+}
+
static void evm_reset_status(struct inode *inode)
{
struct integrity_iint_cache *iint;
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index be965a8715e4..03b440921e61 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -326,7 +326,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value);
+ struct evm_ima_xattr_data **xattr_value, int xattr_len);
#else
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
@@ -372,7 +372,8 @@ ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len)
}
static inline int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value)
+ struct evm_ima_xattr_data **xattr_value,
+ int xattr_len)
{
return 0;
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 3e0fbbd99534..ee6f7e237f2e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -221,12 +221,12 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
}
int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value)
+ struct evm_ima_xattr_data **xattr_value, int xattr_len)
{
- ssize_t ret;
+ int ret;
ret = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_IMA,
- (char **)xattr_value, 0, GFP_NOFS);
+ (char **)xattr_value, xattr_len, GFP_NOFS);
if (ret == -EOPNOTSUPP)
ret = 0;
return ret;
@@ -774,6 +774,15 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
return result;
}
+int ima_inode_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
+{
+ if (evm_revalidate_status(acl_name))
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+
+ return 0;
+}
+
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 040b03ddc1c7..0226899947d6 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -293,7 +293,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
/* HASH sets the digital signature and update flags, nothing else */
if ((action & IMA_HASH) &&
!(test_bit(IMA_DIGSIG, &iint->atomic_flags))) {
- xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
+ xattr_len = ima_read_xattr(file_dentry(file),
+ &xattr_value, xattr_len);
if ((xattr_value && xattr_len > 2) &&
(xattr_value->type == EVM_IMA_XATTR_DIGSIG))
set_bit(IMA_DIGSIG, &iint->atomic_flags);
@@ -316,7 +317,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) {
/* read 'security.ima' */
- xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
+ xattr_len = ima_read_xattr(file_dentry(file),
+ &xattr_value, xattr_len);
/*
* Read the appended modsig if allowed by the policy, and allow
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index a8802b8da946..54c475f98ce1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -85,8 +85,8 @@ struct ima_rule_entry {
kgid_t fgroup;
bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */
bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid);
- bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */
- bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
+ bool (*fowner_op)(vfsuid_t vfsuid, kuid_t rule_uid); /* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid() */
+ bool (*fgroup_op)(vfsgid_t vfsgid, kgid_t rule_gid); /* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid() */
int pcr;
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
struct {
@@ -186,11 +186,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
#endif
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
- {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
+ {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
.flags = IMA_FOWNER},
#else
/* force signature */
- {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
+ {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
.flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
#endif
};
@@ -601,10 +601,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return false;
}
if ((rule->flags & IMA_FOWNER) &&
- !rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner))
+ !rule->fowner_op(i_uid_into_vfsuid(mnt_userns, inode),
+ rule->fowner))
return false;
if ((rule->flags & IMA_FGROUP) &&
- !rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup))
+ !rule->fgroup_op(i_gid_into_vfsgid(mnt_userns, inode),
+ rule->fgroup))
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
int rc = 0;
@@ -1371,8 +1373,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->fgroup = INVALID_GID;
entry->uid_op = &uid_eq;
entry->gid_op = &gid_eq;
- entry->fowner_op = &uid_eq;
- entry->fgroup_op = &gid_eq;
+ entry->fowner_op = &vfsuid_eq_kuid;
+ entry->fgroup_op = &vfsgid_eq_kgid;
entry->action = UNKNOWN;
while ((p = strsep(&rule, " \t")) != NULL) {
substring_t args[MAX_OPT_ARGS];
@@ -1650,11 +1652,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break;
case Opt_fowner_gt:
- entry->fowner_op = &uid_gt;
+ entry->fowner_op = &vfsuid_gt_kuid;
fallthrough;
case Opt_fowner_lt:
if (token == Opt_fowner_lt)
- entry->fowner_op = &uid_lt;
+ entry->fowner_op = &vfsuid_lt_kuid;
fallthrough;
case Opt_fowner_eq:
ima_log_string_op(ab, "fowner", args[0].from, token);
@@ -1676,11 +1678,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break;
case Opt_fgroup_gt:
- entry->fgroup_op = &gid_gt;
+ entry->fgroup_op = &vfsgid_gt_kgid;
fallthrough;
case Opt_fgroup_lt:
if (token == Opt_fgroup_lt)
- entry->fgroup_op = &gid_lt;
+ entry->fgroup_op = &vfsgid_lt_kgid;
fallthrough;
case Opt_fgroup_eq:
ima_log_string_op(ab, "fgroup", args[0].from, token);
@@ -2151,9 +2153,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->flags & IMA_FOWNER) {
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
- if (entry->fowner_op == &uid_gt)
+ if (entry->fowner_op == &vfsuid_gt_kuid)
seq_printf(m, pt(Opt_fowner_gt), tbuf);
- else if (entry->fowner_op == &uid_lt)
+ else if (entry->fowner_op == &vfsuid_lt_kuid)
seq_printf(m, pt(Opt_fowner_lt), tbuf);
else
seq_printf(m, pt(Opt_fowner_eq), tbuf);
@@ -2162,9 +2164,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->flags & IMA_FGROUP) {
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup));
- if (entry->fgroup_op == &gid_gt)
+ if (entry->fgroup_op == &vfsgid_gt_kgid)
seq_printf(m, pt(Opt_fgroup_gt), tbuf);
- else if (entry->fgroup_op == &gid_lt)
+ else if (entry->fgroup_op == &vfsgid_lt_kgid)
seq_printf(m, pt(Opt_fgroup_lt), tbuf);
else
seq_printf(m, pt(Opt_fgroup_eq), tbuf);
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 7bf9b1507220..4564faae7d67 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -601,16 +601,15 @@ int ima_eventevmsig_init(struct ima_event_data *event_data,
rc = vfs_getxattr_alloc(&init_user_ns, file_dentry(event_data->file),
XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
- if (rc <= 0)
- return 0;
-
- if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
- kfree(xattr_data);
- return 0;
+ if (rc <= 0 || xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
+ rc = 0;
+ goto out;
}
rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
field_data);
+
+out:
kfree(xattr_data);
return rc;
}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 96a92a645216..d54f73c558f7 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1251,7 +1251,7 @@ long keyctl_instantiate_key(key_serial_t id,
struct iov_iter from;
int ret;
- ret = import_single_range(WRITE, (void __user *)_payload, plen,
+ ret = import_single_range(ITER_SOURCE, (void __user *)_payload, plen,
&iov, &from);
if (unlikely(ret))
return ret;
@@ -1283,7 +1283,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
if (!_payload_iov)
ioc = 0;
- ret = import_iovec(WRITE, _payload_iov, ioc,
+ ret = import_iovec(ITER_SOURCE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), &iov, &from);
if (ret < 0)
return ret;
diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c
index c8626686ee1b..ac3e270ade69 100644
--- a/security/keys/trusted-keys/trusted_tee.c
+++ b/security/keys/trusted-keys/trusted_tee.c
@@ -219,7 +219,8 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
{
- if (ver->impl_id == TEE_IMPL_ID_OPTEE)
+ if (ver->impl_id == TEE_IMPL_ID_OPTEE &&
+ ver->gen_caps & TEE_GEN_CAP_REG_MEM)
return 1;
else
return 0;
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 64ed7665455f..adcea0fe7e68 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -146,7 +146,8 @@ retry:
#define ACCESS_FILE ( \
LANDLOCK_ACCESS_FS_EXECUTE | \
LANDLOCK_ACCESS_FS_WRITE_FILE | \
- LANDLOCK_ACCESS_FS_READ_FILE)
+ LANDLOCK_ACCESS_FS_READ_FILE | \
+ LANDLOCK_ACCESS_FS_TRUNCATE)
/* clang-format on */
/*
@@ -297,6 +298,19 @@ get_handled_accesses(const struct landlock_ruleset *const domain)
return access_dom & LANDLOCK_MASK_ACCESS_FS;
}
+/**
+ * init_layer_masks - Initialize layer masks from an access request
+ *
+ * Populates @layer_masks such that for each access right in @access_request,
+ * the bits for all the layers are set where this access right is handled.
+ *
+ * @domain: The domain that defines the current restrictions.
+ * @access_request: The requested access rights to check.
+ * @layer_masks: The layer masks to populate.
+ *
+ * Returns: An access mask where each access right bit is set which is handled
+ * in any of the active layers in @domain.
+ */
static inline access_mask_t
init_layer_masks(const struct landlock_ruleset *const domain,
const access_mask_t access_request,
@@ -430,7 +444,7 @@ is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS],
}
/**
- * check_access_path_dual - Check accesses for requests with a common path
+ * is_access_to_paths_allowed - Check accesses for requests with a common path
*
* @domain: Domain to check against.
* @path: File hierarchy to walk through.
@@ -465,14 +479,10 @@ is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS],
* allow the request.
*
* Returns:
- * - 0 if the access request is granted;
- * - -EACCES if it is denied because of access right other than
- * LANDLOCK_ACCESS_FS_REFER;
- * - -EXDEV if the renaming or linking would be a privileged escalation
- * (according to each layered policies), or if LANDLOCK_ACCESS_FS_REFER is
- * not allowed by the source or the destination.
+ * - true if the access request is granted;
+ * - false otherwise.
*/
-static int check_access_path_dual(
+static bool is_access_to_paths_allowed(
const struct landlock_ruleset *const domain,
const struct path *const path,
const access_mask_t access_request_parent1,
@@ -492,17 +502,17 @@ static int check_access_path_dual(
(*layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS] = NULL;
if (!access_request_parent1 && !access_request_parent2)
- return 0;
+ return true;
if (WARN_ON_ONCE(!domain || !path))
- return 0;
+ return true;
if (is_nouser_or_private(path->dentry))
- return 0;
+ return true;
if (WARN_ON_ONCE(domain->num_layers < 1 || !layer_masks_parent1))
- return -EACCES;
+ return false;
if (unlikely(layer_masks_parent2)) {
if (WARN_ON_ONCE(!dentry_child1))
- return -EACCES;
+ return false;
/*
* For a double request, first check for potential privilege
* escalation by looking at domain handled accesses (which are
@@ -513,7 +523,7 @@ static int check_access_path_dual(
is_dom_check = true;
} else {
if (WARN_ON_ONCE(dentry_child1 || dentry_child2))
- return -EACCES;
+ return false;
/* For a simple request, only check for requested accesses. */
access_masked_parent1 = access_request_parent1;
access_masked_parent2 = access_request_parent2;
@@ -622,24 +632,7 @@ jump_up:
}
path_put(&walker_path);
- if (allowed_parent1 && allowed_parent2)
- return 0;
-
- /*
- * This prioritizes EACCES over EXDEV for all actions, including
- * renames with RENAME_EXCHANGE.
- */
- if (likely(is_eacces(layer_masks_parent1, access_request_parent1) ||
- is_eacces(layer_masks_parent2, access_request_parent2)))
- return -EACCES;
-
- /*
- * Gracefully forbids reparenting if the destination directory
- * hierarchy is not a superset of restrictions of the source directory
- * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the
- * source or the destination.
- */
- return -EXDEV;
+ return allowed_parent1 && allowed_parent2;
}
static inline int check_access_path(const struct landlock_ruleset *const domain,
@@ -649,8 +642,10 @@ static inline int check_access_path(const struct landlock_ruleset *const domain,
layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
access_request = init_layer_masks(domain, access_request, &layer_masks);
- return check_access_path_dual(domain, path, access_request,
- &layer_masks, NULL, 0, NULL, NULL);
+ if (is_access_to_paths_allowed(domain, path, access_request,
+ &layer_masks, NULL, 0, NULL, NULL))
+ return 0;
+ return -EACCES;
}
static inline int current_check_access_path(const struct path *const path,
@@ -711,8 +706,9 @@ static inline access_mask_t maybe_remove(const struct dentry *const dentry)
* file. While walking from @dir to @mnt_root, we record all the domain's
* allowed accesses in @layer_masks_dom.
*
- * This is similar to check_access_path_dual() but much simpler because it only
- * handles walking on the same mount point and only checks one set of accesses.
+ * This is similar to is_access_to_paths_allowed() but much simpler because it
+ * only handles walking on the same mount point and only checks one set of
+ * accesses.
*
* Returns:
* - true if all the domain access rights are allowed for @dir;
@@ -857,10 +853,11 @@ static int current_check_refer_path(struct dentry *const old_dentry,
access_request_parent1 = init_layer_masks(
dom, access_request_parent1 | access_request_parent2,
&layer_masks_parent1);
- return check_access_path_dual(dom, new_dir,
- access_request_parent1,
- &layer_masks_parent1, NULL, 0,
- NULL, NULL);
+ if (is_access_to_paths_allowed(
+ dom, new_dir, access_request_parent1,
+ &layer_masks_parent1, NULL, 0, NULL, NULL))
+ return 0;
+ return -EACCES;
}
access_request_parent1 |= LANDLOCK_ACCESS_FS_REFER;
@@ -886,11 +883,27 @@ static int current_check_refer_path(struct dentry *const old_dentry,
* parent access rights. This will be useful to compare with the
* destination parent access rights.
*/
- return check_access_path_dual(dom, &mnt_dir, access_request_parent1,
- &layer_masks_parent1, old_dentry,
- access_request_parent2,
- &layer_masks_parent2,
- exchange ? new_dentry : NULL);
+ if (is_access_to_paths_allowed(
+ dom, &mnt_dir, access_request_parent1, &layer_masks_parent1,
+ old_dentry, access_request_parent2, &layer_masks_parent2,
+ exchange ? new_dentry : NULL))
+ return 0;
+
+ /*
+ * This prioritizes EACCES over EXDEV for all actions, including
+ * renames with RENAME_EXCHANGE.
+ */
+ if (likely(is_eacces(&layer_masks_parent1, access_request_parent1) ||
+ is_eacces(&layer_masks_parent2, access_request_parent2)))
+ return -EACCES;
+
+ /*
+ * Gracefully forbids reparenting if the destination directory
+ * hierarchy is not a superset of restrictions of the source directory
+ * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the
+ * source or the destination.
+ */
+ return -EXDEV;
}
/* Inode hooks */
@@ -1142,9 +1155,23 @@ static int hook_path_rmdir(const struct path *const dir,
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR);
}
+static int hook_path_truncate(const struct path *const path)
+{
+ return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
+}
+
/* File hooks */
-static inline access_mask_t get_file_access(const struct file *const file)
+/**
+ * get_required_file_open_access - Get access needed to open a file
+ *
+ * @file: File being opened.
+ *
+ * Returns the access rights that are required for opening the given file,
+ * depending on the file type and open mode.
+ */
+static inline access_mask_t
+get_required_file_open_access(const struct file *const file)
{
access_mask_t access = 0;
@@ -1162,19 +1189,95 @@ static inline access_mask_t get_file_access(const struct file *const file)
return access;
}
+static int hook_file_alloc_security(struct file *const file)
+{
+ /*
+ * Grants all access rights, even if most of them are not checked later
+ * on. It is more consistent.
+ *
+ * Notably, file descriptors for regular files can also be acquired
+ * without going through the file_open hook, for example when using
+ * memfd_create(2).
+ */
+ landlock_file(file)->allowed_access = LANDLOCK_MASK_ACCESS_FS;
+ return 0;
+}
+
static int hook_file_open(struct file *const file)
{
+ layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
+ access_mask_t open_access_request, full_access_request, allowed_access;
+ const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE;
const struct landlock_ruleset *const dom =
landlock_get_current_domain();
if (!dom)
return 0;
+
/*
- * Because a file may be opened with O_PATH, get_file_access() may
- * return 0. This case will be handled with a future Landlock
+ * Because a file may be opened with O_PATH, get_required_file_open_access()
+ * may return 0. This case will be handled with a future Landlock
* evolution.
*/
- return check_access_path(dom, &file->f_path, get_file_access(file));
+ open_access_request = get_required_file_open_access(file);
+
+ /*
+ * We look up more access than what we immediately need for open(), so
+ * that we can later authorize operations on opened files.
+ */
+ full_access_request = open_access_request | optional_access;
+
+ if (is_access_to_paths_allowed(
+ dom, &file->f_path,
+ init_layer_masks(dom, full_access_request, &layer_masks),
+ &layer_masks, NULL, 0, NULL, NULL)) {
+ allowed_access = full_access_request;
+ } else {
+ unsigned long access_bit;
+ const unsigned long access_req = full_access_request;
+
+ /*
+ * Calculate the actual allowed access rights from layer_masks.
+ * Add each access right to allowed_access which has not been
+ * vetoed by any layer.
+ */
+ allowed_access = 0;
+ for_each_set_bit(access_bit, &access_req,
+ ARRAY_SIZE(layer_masks)) {
+ if (!layer_masks[access_bit])
+ allowed_access |= BIT_ULL(access_bit);
+ }
+ }
+
+ /*
+ * For operations on already opened files (i.e. ftruncate()), it is the
+ * access rights at the time of open() which decide whether the
+ * operation is permitted. Therefore, we record the relevant subset of
+ * file access rights in the opened struct file.
+ */
+ landlock_file(file)->allowed_access = allowed_access;
+
+ if ((open_access_request & allowed_access) == open_access_request)
+ return 0;
+
+ return -EACCES;
+}
+
+static int hook_file_truncate(struct file *const file)
+{
+ /*
+ * Allows truncation if the truncate right was available at the time of
+ * opening the file, to get a consistent access check as for read, write
+ * and execute operations.
+ *
+ * Note: For checks done based on the file's Landlock allowed access, we
+ * enforce them independently of whether the current thread is in a
+ * Landlock domain, so that open files passed between independent
+ * processes retain their behaviour.
+ */
+ if (landlock_file(file)->allowed_access & LANDLOCK_ACCESS_FS_TRUNCATE)
+ return 0;
+ return -EACCES;
}
static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
@@ -1194,8 +1297,11 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(path_symlink, hook_path_symlink),
LSM_HOOK_INIT(path_unlink, hook_path_unlink),
LSM_HOOK_INIT(path_rmdir, hook_path_rmdir),
+ LSM_HOOK_INIT(path_truncate, hook_path_truncate),
+ LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security),
LSM_HOOK_INIT(file_open, hook_file_open),
+ LSM_HOOK_INIT(file_truncate, hook_file_truncate),
};
__init void landlock_add_fs_hooks(void)
diff --git a/security/landlock/fs.h b/security/landlock/fs.h
index 8db7acf9109b..488e4813680a 100644
--- a/security/landlock/fs.h
+++ b/security/landlock/fs.h
@@ -37,6 +37,24 @@ struct landlock_inode_security {
};
/**
+ * struct landlock_file_security - File security blob
+ *
+ * This information is populated when opening a file in hook_file_open, and
+ * tracks the relevant Landlock access rights that were available at the time
+ * of opening the file. Other LSM hooks use these rights in order to authorize
+ * operations on already opened files.
+ */
+struct landlock_file_security {
+ /**
+ * @allowed_access: Access rights that were available at the time of
+ * opening the file. This is not necessarily the full set of access
+ * rights available at that time, but it's the necessary subset as
+ * needed to authorize later operations on the open file.
+ */
+ access_mask_t allowed_access;
+};
+
+/**
* struct landlock_superblock_security - Superblock security blob
*
* Enable hook_sb_delete() to wait for concurrent calls to release_inode().
@@ -50,6 +68,12 @@ struct landlock_superblock_security {
atomic_long_t inode_refs;
};
+static inline struct landlock_file_security *
+landlock_file(const struct file *const file)
+{
+ return file->f_security + landlock_blob_sizes.lbs_file;
+}
+
static inline struct landlock_inode_security *
landlock_inode(const struct inode *const inode)
{
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index b54184ab9439..82288f0e9e5e 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -18,7 +18,7 @@
#define LANDLOCK_MAX_NUM_LAYERS 16
#define LANDLOCK_MAX_NUM_RULES U32_MAX
-#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_REFER
+#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_TRUNCATE
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index f8e8e980454c..3f196d2ce4f9 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -19,6 +19,7 @@ bool landlock_initialized __lsm_ro_after_init = false;
struct lsm_blob_sizes landlock_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct landlock_cred_security),
+ .lbs_file = sizeof(struct landlock_file_security),
.lbs_inode = sizeof(struct landlock_inode_security),
.lbs_superblock = sizeof(struct landlock_superblock_security),
};
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 2ca0ccbd905a..245cc650a4dc 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -129,7 +129,7 @@ static const struct file_operations ruleset_fops = {
.write = fop_dummy_write,
};
-#define LANDLOCK_ABI_VERSION 2
+#define LANDLOCK_ABI_VERSION 3
/**
* sys_landlock_create_ruleset - Create a new ruleset
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 75cc3f8d2a42..a7355b4b9bb8 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -190,6 +190,7 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
/**
* dump_common_audit_data - helper to dump common audit data
+ * @ab : the audit buffer
* @a : common audit data
*
*/
diff --git a/security/security.c b/security/security.c
index 79d82cb6e469..d1571900a8c7 100644
--- a/security/security.c
+++ b/security/security.c
@@ -161,8 +161,8 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
lsm->enabled = &lsm_enabled_true;
ordered_lsms[last_lsm++] = lsm;
- init_debug("%s ordering: %s (%sabled)\n", from, lsm->name,
- is_enabled(lsm) ? "en" : "dis");
+ init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+ is_enabled(lsm) ? "enabled" : "disabled");
}
/* Is an LSM allowed to be initialized? */
@@ -185,11 +185,12 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
{
int offset;
- if (*need > 0) {
- offset = *lbs;
- *lbs += *need;
- *need = offset;
- }
+ if (*need <= 0)
+ return;
+
+ offset = ALIGN(*lbs, sizeof(void *));
+ *lbs = offset + *need;
+ *need = offset;
}
static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
@@ -224,7 +225,7 @@ static void __init prepare_lsm(struct lsm_info *lsm)
if (enabled) {
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
exclusive = lsm;
- init_debug("exclusive chosen: %s\n", lsm->name);
+ init_debug("exclusive chosen: %s\n", lsm->name);
}
lsm_set_blob_sizes(lsm->blobs);
@@ -252,7 +253,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* LSM_ORDER_FIRST is always first. */
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (lsm->order == LSM_ORDER_FIRST)
- append_ordered_lsm(lsm, "first");
+ append_ordered_lsm(lsm, " first");
}
/* Process "security=", if given. */
@@ -270,7 +271,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
- init_debug("security=%s disabled: %s\n",
+ init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
chosen_major_lsm, major->name);
}
}
@@ -291,7 +292,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
if (!found)
- init_debug("%s ignored: %s\n", origin, name);
+ init_debug("%s ignored: %s (not built into kernel)\n",
+ origin, name);
}
/* Process "security=", if given. */
@@ -309,7 +311,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
if (exists_ordered_lsm(lsm))
continue;
set_enabled(lsm, false);
- init_debug("%s disabled: %s\n", origin, lsm->name);
+ init_debug("%s skipped: %s (not in requested order)\n",
+ origin, lsm->name);
}
kfree(sep);
@@ -320,6 +323,24 @@ static void __init lsm_early_task(struct task_struct *task);
static int lsm_append(const char *new, char **result);
+static void __init report_lsm_order(void)
+{
+ struct lsm_info **lsm, *early;
+ int first = 0;
+
+ pr_info("initializing lsm=");
+
+ /* Report each enabled LSM name, comma separated. */
+ for (early = __start_early_lsm_info; early < __end_early_lsm_info; early++)
+ if (is_enabled(early))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ if (is_enabled(*lsm))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+
+ pr_cont("\n");
+}
+
static void __init ordered_lsm_init(void)
{
struct lsm_info **lsm;
@@ -329,7 +350,8 @@ static void __init ordered_lsm_init(void)
if (chosen_lsm_order) {
if (chosen_major_lsm) {
- pr_info("security= is ignored because it is superseded by lsm=\n");
+ pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
+ chosen_major_lsm, chosen_lsm_order);
chosen_major_lsm = NULL;
}
ordered_lsm_parse(chosen_lsm_order, "cmdline");
@@ -339,6 +361,8 @@ static void __init ordered_lsm_init(void)
for (lsm = ordered_lsms; *lsm; lsm++)
prepare_lsm(*lsm);
+ report_lsm_order();
+
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
@@ -395,13 +419,17 @@ int __init security_init(void)
{
struct lsm_info *lsm;
- pr_info("Security Framework initializing\n");
+ init_debug("legacy security=%s\n", chosen_major_lsm ?: " *unspecified*");
+ init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
+ init_debug("boot arg lsm=%s\n", chosen_lsm_order ?: " *unspecified*");
/*
* Append the names of the early LSM modules now that kmalloc() is
* available
*/
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ init_debug(" early started: %s (%s)\n", lsm->name,
+ is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
lsm_append(lsm->name, &lsm_names);
}
@@ -1372,6 +1400,48 @@ int security_inode_setxattr(struct user_namespace *mnt_userns,
return evm_inode_setxattr(mnt_userns, dentry, name, value, size);
}
+int security_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ int ret;
+
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ ret = call_int_hook(inode_set_acl, 0, mnt_userns, dentry, acl_name,
+ kacl);
+ if (ret)
+ return ret;
+ ret = ima_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
+ if (ret)
+ return ret;
+ return evm_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
+}
+
+int security_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ return call_int_hook(inode_get_acl, 0, mnt_userns, dentry, acl_name);
+}
+
+int security_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ int ret;
+
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ ret = call_int_hook(inode_remove_acl, 0, mnt_userns, dentry, acl_name);
+ if (ret)
+ return ret;
+ ret = ima_inode_remove_acl(mnt_userns, dentry, acl_name);
+ if (ret)
+ return ret;
+ return evm_inode_remove_acl(mnt_userns, dentry, acl_name);
+}
+
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
@@ -1652,6 +1722,11 @@ int security_file_open(struct file *file)
return fsnotify_perm(file, MAY_OPEN);
}
+int security_file_truncate(struct file *file)
+{
+ return call_int_hook(file_truncate, 0, file);
+}
+
int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{
int rc = lsm_task_alloc(task);
@@ -2267,11 +2342,11 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(security_sock_rcv_skb);
-int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
+ sockptr_t optlen, unsigned int len)
{
return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
- optval, optlen, len);
+ optval, optlen, len);
}
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f553c370397e..3c5be76a9199 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3240,6 +3240,25 @@ static int selinux_inode_setxattr(struct user_namespace *mnt_userns,
&ad);
}
+static int selinux_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
+static int selinux_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
+}
+
+static int selinux_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size,
int flags)
@@ -5119,11 +5138,12 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock,
+ sockptr_t optval, sockptr_t optlen,
+ unsigned int len)
{
int err = 0;
- char *scontext;
+ char *scontext = NULL;
u32 scontext_len;
struct sk_security_struct *sksec = sock->sk->sk_security;
u32 peer_sid = SECSID_NULL;
@@ -5139,17 +5159,15 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
&scontext_len);
if (err)
return err;
-
if (scontext_len > len) {
err = -ERANGE;
goto out_len;
}
- if (copy_to_user(optval, scontext, scontext_len))
+ if (copy_to_sockptr(optval, scontext, scontext_len))
err = -EFAULT;
-
out_len:
- if (put_user(scontext_len, optlen))
+ if (copy_to_sockptr(optlen, &scontext_len, sizeof(scontext_len)))
err = -EFAULT;
kfree(scontext);
return err;
@@ -7088,6 +7106,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
+ LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl),
+ LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl),
+ LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl),
LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index a00d19139436..0a6894cdc54d 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -294,7 +294,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
*/
pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n");
- ssleep(5);
+ ssleep(15);
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -763,7 +763,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
checkreqprot_set(fsi->state, (new_value ? 1 : 0));
if (new_value)
- ssleep(5);
+ ssleep(15);
length = count;
selinux_ima_measure_state(fsi->state);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 64a6a37dc36d..0092b29022f5 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -68,12 +68,6 @@
#include "policycap_names.h"
#include "ima.h"
-struct convert_context_args {
- struct selinux_state *state;
- struct policydb *oldp;
- struct policydb *newp;
-};
-
struct selinux_policy_convert_data {
struct convert_context_args args;
struct sidtab_convert_params sidtab_params;
@@ -2014,18 +2008,22 @@ static inline int convert_context_handle_invalid_context(
return 0;
}
-/*
- * Convert the values in the security context
- * structure `oldc' from the values specified
- * in the policy `p->oldp' to the values specified
- * in the policy `p->newp', storing the new context
- * in `newc'. Verify that the context is valid
- * under the new policy.
+/**
+ * services_convert_context - Convert a security context across policies.
+ * @args: populated convert_context_args struct
+ * @oldc: original context
+ * @newc: converted context
+ * @gfp_flags: allocation flags
+ *
+ * Convert the values in the security context structure @oldc from the values
+ * specified in the policy @args->oldp to the values specified in the policy
+ * @args->newp, storing the new context in @newc, and verifying that the
+ * context is valid under the new policy.
*/
-static int convert_context(struct context *oldc, struct context *newc, void *p,
- gfp_t gfp_flags)
+int services_convert_context(struct convert_context_args *args,
+ struct context *oldc, struct context *newc,
+ gfp_t gfp_flags)
{
- struct convert_context_args *args;
struct ocontext *oc;
struct role_datum *role;
struct type_datum *typdatum;
@@ -2034,15 +2032,12 @@ static int convert_context(struct context *oldc, struct context *newc, void *p,
u32 len;
int rc;
- args = p;
-
if (oldc->str) {
s = kstrdup(oldc->str, gfp_flags);
if (!s)
return -ENOMEM;
- rc = string_to_context_struct(args->newp, NULL, s,
- newc, SECSID_NULL);
+ rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
if (rc == -EINVAL) {
/*
* Retain string representation for later mapping.
@@ -2073,8 +2068,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p,
/* Convert the user. */
usrdatum = symtab_search(&args->newp->p_users,
- sym_name(args->oldp,
- SYM_USERS, oldc->user - 1));
+ sym_name(args->oldp, SYM_USERS, oldc->user - 1));
if (!usrdatum)
goto bad;
newc->user = usrdatum->value;
@@ -2088,8 +2082,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p,
/* Convert the type. */
typdatum = symtab_search(&args->newp->p_types,
- sym_name(args->oldp,
- SYM_TYPES, oldc->type - 1));
+ sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
if (!typdatum)
goto bad;
newc->type = typdatum->value;
@@ -2123,8 +2116,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p,
/* Check the validity of the new context. */
if (!policydb_context_isvalid(args->newp, newc)) {
rc = convert_context_handle_invalid_context(args->state,
- args->oldp,
- oldc);
+ args->oldp, oldc);
if (rc)
goto bad;
}
@@ -2333,21 +2325,21 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
goto err_free_isids;
}
+ /*
+ * Convert the internal representations of contexts
+ * in the new SID table.
+ */
+
convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
if (!convert_data) {
rc = -ENOMEM;
goto err_free_isids;
}
- /*
- * Convert the internal representations of contexts
- * in the new SID table.
- */
convert_data->args.state = state;
convert_data->args.oldp = &oldpolicy->policydb;
convert_data->args.newp = &newpolicy->policydb;
- convert_data->sidtab_params.func = convert_context;
convert_data->sidtab_params.args = &convert_data->args;
convert_data->sidtab_params.target = newpolicy->sidtab;
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index 9555ad074303..c4301626487f 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -29,10 +29,19 @@ struct selinux_policy {
u32 latest_granting;
} __randomize_layout;
-void services_compute_xperms_drivers(struct extended_perms *xperms,
- struct avtab_node *node);
+struct convert_context_args {
+ struct selinux_state *state;
+ struct policydb *oldp;
+ struct policydb *newp;
+};
+void services_compute_xperms_drivers(struct extended_perms *xperms,
+ struct avtab_node *node);
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
- struct avtab_node *node);
+ struct avtab_node *node);
+
+int services_convert_context(struct convert_context_args *args,
+ struct context *oldc, struct context *newc,
+ gfp_t gfp_flags);
#endif /* _SS_SERVICES_H_ */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index db5cce385bf8..38d25173aebd 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -18,6 +18,7 @@
#include "flask.h"
#include "security.h"
#include "sidtab.h"
+#include "services.h"
struct sidtab_str_cache {
struct rcu_head rcu_member;
@@ -292,7 +293,6 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
}
count = s->count;
- convert = s->convert;
/* bail out if we already reached max entries */
rc = -EOVERFLOW;
@@ -316,25 +316,29 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
* if we are building a new sidtab, we need to convert the context
* and insert it there as well
*/
+ convert = s->convert;
if (convert) {
+ struct sidtab *target = convert->target;
+
rc = -ENOMEM;
- dst_convert = sidtab_do_lookup(convert->target, count, 1);
+ dst_convert = sidtab_do_lookup(target, count, 1);
if (!dst_convert) {
context_destroy(&dst->context);
goto out_unlock;
}
- rc = convert->func(context, &dst_convert->context,
- convert->args, GFP_ATOMIC);
+ rc = services_convert_context(convert->args,
+ context, &dst_convert->context,
+ GFP_ATOMIC);
if (rc) {
context_destroy(&dst->context);
goto out_unlock;
}
dst_convert->sid = index_to_sid(count);
dst_convert->hash = context_compute_hash(&dst_convert->context);
- convert->target->count = count + 1;
+ target->count = count + 1;
- hash_add_rcu(convert->target->context_to_sid,
+ hash_add_rcu(target->context_to_sid,
&dst_convert->list, dst_convert->hash);
}
@@ -402,9 +406,10 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst,
}
i = 0;
while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
- rc = convert->func(&esrc->ptr_leaf->entries[i].context,
- &edst->ptr_leaf->entries[i].context,
- convert->args, GFP_KERNEL);
+ rc = services_convert_context(convert->args,
+ &esrc->ptr_leaf->entries[i].context,
+ &edst->ptr_leaf->entries[i].context,
+ GFP_KERNEL);
if (rc)
return rc;
(*pos)++;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 9fce0d553fe2..72810a080e77 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -65,8 +65,7 @@ struct sidtab_isid_entry {
};
struct sidtab_convert_params {
- int (*func)(struct context *oldc, struct context *newc, void *args, gfp_t gfp_flags);
- void *args;
+ struct convert_context_args *args;
struct sidtab *target;
};
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b6306d71c908..9a82a15685d1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1393,6 +1393,74 @@ static int smack_inode_removexattr(struct user_namespace *mnt_userns,
}
/**
+ * smack_inode_set_acl - Smack check for setting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ * @kacl: the posix acls
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
+ return rc;
+}
+
+/**
+ * smack_inode_get_acl - Smack check for getting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc);
+ return rc;
+}
+
+/**
+ * smack_inode_remove_acl - Smack check for getting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
+ return rc;
+}
+
+/**
* smack_inode_getsecurity - get smack xattrs
* @mnt_userns: active user namespace
* @inode: the object
@@ -4006,12 +4074,12 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* returns zero on success, an error code otherwise
*/
static int smack_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned len)
+ sockptr_t optval, sockptr_t optlen,
+ unsigned int len)
{
struct socket_smack *ssp;
char *rcp = "";
- int slen = 1;
+ u32 slen = 1;
int rc = 0;
ssp = sock->sk->sk_security;
@@ -4019,15 +4087,16 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
rcp = ssp->smk_packet->smk_known;
slen = strlen(rcp) + 1;
}
-
- if (slen > len)
+ if (slen > len) {
rc = -ERANGE;
- else if (copy_to_user(optval, rcp, slen) != 0)
- rc = -EFAULT;
+ goto out_len;
+ }
- if (put_user(slen, optlen) != 0)
+ if (copy_to_sockptr(optval, rcp, slen))
+ rc = -EFAULT;
+out_len:
+ if (copy_to_sockptr(optlen, &slen, sizeof(slen)))
rc = -EFAULT;
-
return rc;
}
@@ -4816,6 +4885,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr),
LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr),
+ LSM_HOOK_INIT(inode_set_acl, smack_inode_set_acl),
+ LSM_HOOK_INIT(inode_get_acl, smack_inode_get_acl),
+ LSM_HOOK_INIT(inode_remove_acl, smack_inode_remove_acl),
LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity),
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 71e82d855ebf..af04a7b7eb28 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -135,6 +135,18 @@ static int tomoyo_path_truncate(const struct path *path)
}
/**
+ * tomoyo_file_truncate - Target for security_file_truncate().
+ *
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_file_truncate(struct file *file)
+{
+ return tomoyo_path_truncate(&file->f_path);
+}
+
+/**
* tomoyo_path_unlink - Target for security_path_unlink().
*
* @parent: Pointer to "struct path".
@@ -545,6 +557,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security),
LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl),
LSM_HOOK_INIT(file_open, tomoyo_file_open),
+ LSM_HOOK_INIT(file_truncate, tomoyo_file_truncate),
LSM_HOOK_INIT(path_truncate, tomoyo_path_truncate),
LSM_HOOK_INIT(path_unlink, tomoyo_path_unlink),
LSM_HOOK_INIT(path_mkdir, tomoyo_path_mkdir),
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 2d0f904aba00..4c75381f5ab8 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -990,8 +990,7 @@ static void onyx_exit_codec(struct aoa_codec *codec)
onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
}
-static int onyx_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int onyx_i2c_probe(struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
struct onyx *onyx;
@@ -1049,7 +1048,7 @@ static struct i2c_driver onyx_driver = {
.driver = {
.name = "aoa_codec_onyx",
},
- .probe = onyx_i2c_probe,
+ .probe_new = onyx_i2c_probe,
.remove = onyx_i2c_remove,
.id_table = onyx_i2c_id,
};
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index ab89475b7715..f906e9aaddcf 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -875,8 +875,7 @@ static void tas_exit_codec(struct aoa_codec *codec)
}
-static int tas_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tas_i2c_probe(struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
struct tas *tas;
@@ -937,7 +936,7 @@ static struct i2c_driver tas_driver = {
.driver = {
.name = "aoa_codec_tas",
},
- .probe = tas_i2c_probe,
+ .probe_new = tas_i2c_probe,
.remove = tas_i2c_remove,
.id_table = tas_i2c_id,
};
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index e55c0421718b..2ca33fd5a575 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -402,8 +402,10 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
goto err_clk2;
irq = platform_get_irq(dev, 0);
- if (!irq)
+ if (irq < 0) {
+ ret = irq;
goto err_irq;
+ }
ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL);
if (ret < 0)
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 03cffe771366..3cf5a87d69ea 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-map-ops.h>
#include <linux/genalloc.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
@@ -20,7 +21,6 @@
#define DEFAULT_GFP \
(GFP_KERNEL | \
- __GFP_COMP | /* compound page lets parts be mapped */ \
__GFP_RETRY_MAYFAIL | /* don't trigger OOM-killer */ \
__GFP_NOWARN) /* no stack trace print - this call is non-critical */
@@ -542,18 +542,18 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
void *p;
sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir,
- DEFAULT_GFP, 0);
- if (!sgt) {
+ DEFAULT_GFP | __GFP_COMP, 0);
#ifdef CONFIG_SND_DMA_SGBUF
+ if (!sgt && !get_dma_ops(dmab->dev.dev)) {
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
else
dmab->dev.type = SNDRV_DMA_TYPE_DEV_SG_FALLBACK;
return snd_dma_sg_fallback_alloc(dmab, size);
-#else
- return NULL;
-#endif
}
+#endif
+ if (!sgt)
+ return NULL;
dmab->dev.need_sync = dma_need_sync(dmab->dev.dev,
sg_dma_address(sgt->sgl));
@@ -719,7 +719,6 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
struct snd_dma_sg_fallback {
size_t count;
struct page **pages;
- dma_addr_t *addrs;
};
static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab,
@@ -731,38 +730,49 @@ static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab,
for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++)
do_free_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc);
kvfree(sgbuf->pages);
- kvfree(sgbuf->addrs);
kfree(sgbuf);
}
static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct snd_dma_sg_fallback *sgbuf;
- struct page **pages;
- size_t i, count;
+ struct page **pagep, *curp;
+ size_t chunk, npages;
+ dma_addr_t addr;
void *p;
bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (!sgbuf)
return NULL;
- count = PAGE_ALIGN(size) >> PAGE_SHIFT;
- pages = kvcalloc(count, sizeof(*pages), GFP_KERNEL);
- if (!pages)
- goto error;
- sgbuf->pages = pages;
- sgbuf->addrs = kvcalloc(count, sizeof(*sgbuf->addrs), GFP_KERNEL);
- if (!sgbuf->addrs)
+ size = PAGE_ALIGN(size);
+ sgbuf->count = size >> PAGE_SHIFT;
+ sgbuf->pages = kvcalloc(sgbuf->count, sizeof(*sgbuf->pages), GFP_KERNEL);
+ if (!sgbuf->pages)
goto error;
- for (i = 0; i < count; sgbuf->count++, i++) {
- p = do_alloc_pages(dmab->dev.dev, PAGE_SIZE, &sgbuf->addrs[i], wc);
- if (!p)
- goto error;
- sgbuf->pages[i] = virt_to_page(p);
+ pagep = sgbuf->pages;
+ chunk = size;
+ while (size > 0) {
+ chunk = min(size, chunk);
+ p = do_alloc_pages(dmab->dev.dev, chunk, &addr, wc);
+ if (!p) {
+ if (chunk <= PAGE_SIZE)
+ goto error;
+ chunk >>= 1;
+ chunk = PAGE_SIZE << get_order(chunk);
+ continue;
+ }
+
+ size -= chunk;
+ /* fill pages */
+ npages = chunk >> PAGE_SHIFT;
+ curp = virt_to_page(p);
+ while (npages--)
+ *pagep++ = curp++;
}
- p = vmap(pages, count, VM_MAP, PAGE_KERNEL);
+ p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL);
if (!p)
goto error;
dmab->private_data = sgbuf;
@@ -810,7 +820,7 @@ static void *snd_dma_noncoherent_alloc(struct snd_dma_buffer *dmab, size_t size)
void *p;
p = dma_alloc_noncoherent(dmab->dev.dev, size, &dmab->addr,
- dmab->dev.dir, DEFAULT_GFP);
+ dmab->dev.dir, DEFAULT_GFP | __GFP_COMP);
if (p)
dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->addr);
return p;
@@ -857,7 +867,7 @@ static const struct snd_malloc_ops snd_dma_noncoherent_ops = {
/*
* Entry points
*/
-static const struct snd_malloc_ops *dma_ops[] = {
+static const struct snd_malloc_ops *snd_dma_ops[] = {
[SNDRV_DMA_TYPE_CONTINUOUS] = &snd_dma_continuous_ops,
[SNDRV_DMA_TYPE_VMALLOC] = &snd_dma_vmalloc_ops,
#ifdef CONFIG_HAS_DMA
@@ -883,7 +893,7 @@ static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab)
if (WARN_ON_ONCE(!dmab))
return NULL;
if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN ||
- dmab->dev.type >= ARRAY_SIZE(dma_ops)))
+ dmab->dev.type >= ARRAY_SIZE(snd_dma_ops)))
return NULL;
- return dma_ops[dmab->dev.type];
+ return snd_dma_ops[dmab->dev.type];
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 33769ca78cc8..9c122e757efe 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -288,7 +288,7 @@ static int constrain_mask_params(struct snd_pcm_substream *substream,
&substream->runtime->hw_constraints;
struct snd_mask *m;
unsigned int k;
- struct snd_mask old_mask;
+ struct snd_mask old_mask __maybe_unused;
int changed;
for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
@@ -324,7 +324,7 @@ static int constrain_interval_params(struct snd_pcm_substream *substream,
&substream->runtime->hw_constraints;
struct snd_interval *i;
unsigned int k;
- struct snd_interval old_interval;
+ struct snd_interval old_interval __maybe_unused;
int changed;
for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
@@ -364,8 +364,8 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
unsigned int stamp;
struct snd_pcm_hw_rule *r;
unsigned int d;
- struct snd_mask old_mask;
- struct snd_interval old_interval;
+ struct snd_mask old_mask __maybe_unused;
+ struct snd_interval old_interval __maybe_unused;
bool again;
int changed, err = 0;
@@ -648,8 +648,8 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
-1
};
const int *v;
- struct snd_mask old_mask;
- struct snd_interval old_interval;
+ struct snd_mask old_mask __maybe_unused;
+ struct snd_interval old_interval __maybe_unused;
int changed;
for (v = vars; *v != -1; v++) {
@@ -1424,16 +1424,24 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream,
static int snd_pcm_do_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
+ int err;
+
if (substream->runtime->trigger_master != substream)
return 0;
- return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ err = substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ /* XRUN happened during the start */
+ if (err == -EPIPE)
+ __snd_pcm_set_state(substream->runtime, SNDRV_PCM_STATE_XRUN);
+ return err;
}
static void snd_pcm_undo_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- if (substream->runtime->trigger_master == substream)
+ if (substream->runtime->trigger_master == substream) {
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ substream->runtime->stop_operating = true;
+ }
}
static void snd_pcm_post_start(struct snd_pcm_substream *substream,
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
index f18da2050772..350b40b906ca 100644
--- a/sound/core/pcm_trace.h
+++ b/sound/core/pcm_trace.h
@@ -88,19 +88,19 @@ TRACE_EVENT(hw_ptr_error,
__field( unsigned int, device )
__field( unsigned int, number )
__field( unsigned int, stream )
- __field( const char *, reason )
+ __string( reason, why )
),
TP_fast_assign(
__entry->card = (substream)->pcm->card->number;
__entry->device = (substream)->pcm->device;
__entry->number = (substream)->number;
__entry->stream = (substream)->stream;
- __entry->reason = (why);
+ __assign_str(reason, why);
),
TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s",
__entry->card, __entry->device,
__entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
- __entry->number, __entry->reason)
+ __entry->number, __get_str(reason))
);
TRACE_EVENT(applptr,
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index d8edb6055072..7147fda66d93 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1050,7 +1050,6 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_runtime *runtime = substream->runtime;
struct snd_rawmidi_framing_tstamp *dest_ptr;
struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec };
- int dest_frames = 0;
int orig_count = src_count;
int frame_size = sizeof(struct snd_rawmidi_framing_tstamp);
@@ -1077,7 +1076,6 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
runtime->avail += frame_size;
runtime->hw_ptr += frame_size;
runtime->hw_ptr %= runtime->buffer_size;
- dest_frames++;
}
return orig_count - src_count;
}
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index b7aee23fc387..47ef6bc30c0e 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -113,15 +113,19 @@ EXPORT_SYMBOL(snd_seq_dump_var_event);
* expand the variable length event to linear buffer space.
*/
-static int seq_copy_in_kernel(char **bufptr, const void *src, int size)
+static int seq_copy_in_kernel(void *ptr, void *src, int size)
{
+ char **bufptr = ptr;
+
memcpy(*bufptr, src, size);
*bufptr += size;
return 0;
}
-static int seq_copy_in_user(char __user **bufptr, const void *src, int size)
+static int seq_copy_in_user(void *ptr, void *src, int size)
{
+ char __user **bufptr = ptr;
+
if (copy_to_user(*bufptr, src, size))
return -EFAULT;
*bufptr += size;
@@ -151,8 +155,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
return newlen;
}
err = snd_seq_dump_var_event(event,
- in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel :
- (snd_seq_dump_func_t)seq_copy_in_user,
+ in_kernel ? seq_copy_in_kernel : seq_copy_in_user,
&buf);
return err < 0 ? err : newlen;
}
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index d3bc9e8c407d..f0d34cf70c3e 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -815,6 +815,9 @@ static void snd_mts64_interrupt(void *private)
u8 status, data;
struct snd_rawmidi_substream *substream;
+ if (!mts)
+ return;
+
spin_lock(&mts->lock);
ret = mts64_read(mts->pardev->port);
data = ret & 0x00ff;
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
index 9bf7b960a720..a5f3fbf28b8c 100644
--- a/sound/firewire/dice/Makefile
+++ b/sound/firewire/dice/Makefile
@@ -2,5 +2,5 @@
snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o \
- dice-harman.o
+ dice-harman.o dice-focusrite.o
obj-$(CONFIG_SND_DICE) += snd-dice.o
diff --git a/sound/firewire/dice/dice-focusrite.c b/sound/firewire/dice/dice-focusrite.c
new file mode 100644
index 000000000000..ea27cfb01cc0
--- /dev/null
+++ b/sound/firewire/dice/dice-focusrite.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-focusrite.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2022 Takashi Sakamoto
+
+#include "dice.h"
+
+int snd_dice_detect_focusrite_pro40_tcd3070_formats(struct snd_dice *dice)
+{
+ // Focusrite shipped several variants of Saffire Pro 40. One of them is based on TCD3070-CH
+ // apart from the others with TCD2220. It doesn't support TCAT protocol extension.
+ dice->tx_pcm_chs[0][0] = 20;
+ dice->tx_midi_ports[0] = 1;
+ dice->rx_pcm_chs[0][0] = 20;
+ dice->rx_midi_ports[0] = 1;
+
+ dice->tx_pcm_chs[0][1] = 16;
+ dice->tx_midi_ports[1] = 1;
+ dice->rx_pcm_chs[0][1] = 16;
+ dice->rx_midi_ports[1] = 1;
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index f99e00083141..4c677c8546c7 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -59,7 +59,7 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
static int select_clock(struct snd_dice *dice, unsigned int rate)
{
- __be32 reg;
+ __be32 reg, new;
u32 data;
int i;
int err;
@@ -83,15 +83,17 @@ static int select_clock(struct snd_dice *dice, unsigned int rate)
if (completion_done(&dice->clock_accepted))
reinit_completion(&dice->clock_accepted);
- reg = cpu_to_be32(data);
+ new = cpu_to_be32(data);
err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
- &reg, sizeof(reg));
+ &new, sizeof(new));
if (err < 0)
return err;
if (wait_for_completion_timeout(&dice->clock_accepted,
- msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
- return -ETIMEDOUT;
+ msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
+ if (reg != new)
+ return -ETIMEDOUT;
+ }
return 0;
}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index f75902bc8e74..6036a5edbcb8 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -382,6 +382,16 @@ static const struct ieee1394_device_id dice_id_table[] = {
.model_id = 0x000001,
.driver_data = (kernel_ulong_t)snd_dice_detect_harman_formats,
},
+ // Focusrite Saffire Pro 40 with TCD3070-CH.
+ // The model has quirk in its GUID, in which model field is 0x000013 and different from
+ // model ID (0x0000de) in its root/unit directory.
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_FOCUSRITE,
+ .model_id = 0x0000de,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_focusrite_pro40_tcd3070_formats,
+ },
{
.match_flags = IEEE1394_MATCH_VERSION,
.version = DICE_INTERFACE,
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index fd440cc625f9..674f7d552c2e 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -231,5 +231,6 @@ int snd_dice_detect_extension_formats(struct snd_dice *dice);
int snd_dice_detect_mytek_formats(struct snd_dice *dice);
int snd_dice_detect_presonus_formats(struct snd_dice *dice);
int snd_dice_detect_harman_formats(struct snd_dice *dice);
+int snd_dice_detect_focusrite_pro40_tcd3070_formats(struct snd_dice *dice);
#endif
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 80876b9a87f4..6199bb60ccf0 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -108,50 +108,48 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
/**
- * snd_hdac_link_free_all- free hdac extended link objects
+ * snd_hdac_ext_link_free_all- free hdac extended link objects
*
* @bus: the pointer to HDAC bus object
*/
-void snd_hdac_link_free_all(struct hdac_bus *bus)
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus)
{
- struct hdac_ext_link *l;
+ struct hdac_ext_link *hlink;
while (!list_empty(&bus->hlink_list)) {
- l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
- list_del(&l->list);
- kfree(l);
+ hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
+ list_del(&hlink->list);
+ kfree(hlink);
}
}
-EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all);
/**
- * snd_hdac_ext_bus_link_at - get link at specified address
- * @bus: link's parent bus device
+ * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address
+ * @bus: hlink's parent bus device
* @addr: codec device address
*
- * Returns link object or NULL if matching link is not found.
+ * Returns hlink object or NULL if matching hlink is not found.
*/
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr)
{
struct hdac_ext_link *hlink;
- int i;
list_for_each_entry(hlink, &bus->hlink_list, list)
- for (i = 0; i < HDA_MAX_CODECS; i++)
- if (hlink->lsdiid & (0x1 << addr))
- return hlink;
+ if (hlink->lsdiid & (0x1 << addr))
+ return hlink;
return NULL;
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_addr);
/**
- * snd_hdac_ext_bus_get_link - get link based on codec name
+ * snd_hdac_ext_bus_get_hlink_by_name - get hlink based on codec name
* @bus: the pointer to HDAC bus object
* @codec_name: codec name
*/
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
- const char *codec_name)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+ const char *codec_name)
{
int bus_idx, addr;
@@ -162,11 +160,11 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
if (addr < 0 || addr > 31)
return NULL;
- return snd_hdac_ext_bus_link_at(bus, addr);
+ return snd_hdac_ext_bus_get_hlink_by_addr(bus, addr);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_name);
-static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
+static int check_hdac_link_power_active(struct hdac_ext_link *hlink, bool enable)
{
int timeout;
u32 val;
@@ -176,7 +174,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
timeout = 150;
do {
- val = readl(link->ml_addr + AZX_REG_ML_LCTL);
+ val = readl(hlink->ml_addr + AZX_REG_ML_LCTL);
if (enable) {
if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT))
return 0;
@@ -192,26 +190,26 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
/**
* snd_hdac_ext_bus_link_power_up -power up hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
*/
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink)
{
- snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
- return check_hdac_link_power_active(link, true);
+ return check_hdac_link_power_active(hlink, true);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up);
/**
* snd_hdac_ext_bus_link_power_down -power down hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
*/
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink)
{
- snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
- return check_hdac_link_power_active(link, false);
+ return check_hdac_link_power_active(hlink, false);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
@@ -225,9 +223,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
int ret;
list_for_each_entry(hlink, &bus->hlink_list, list) {
- snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
- ret = check_hdac_link_power_active(hlink, true);
+ ret = snd_hdac_ext_bus_link_power_up(hlink);
if (ret < 0)
return ret;
}
@@ -246,9 +242,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
int ret;
list_for_each_entry(hlink, &bus->hlink_list, list) {
- snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_ML_LCTL_SPA, 0);
- ret = check_hdac_link_power_active(hlink, false);
+ ret = snd_hdac_ext_bus_link_power_down(hlink);
if (ret < 0)
return ret;
}
@@ -257,8 +251,32 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
+/**
+ * snd_hdac_ext_bus_link_set_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *link,
+ int stream)
+{
+ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_set_stream_id);
+
+/**
+ * snd_hdac_ext_bus_link_clear_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *link,
+ int stream)
+{
+ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_clear_stream_id);
+
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
- struct hdac_ext_link *link)
+ struct hdac_ext_link *hlink)
{
unsigned long codec_mask;
int ret = 0;
@@ -269,18 +287,18 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
* if we move from 0 to 1, count will be 1 so power up this link
* as well, also check the dma status and trigger that
*/
- if (++link->ref_count == 1) {
+ if (++hlink->ref_count == 1) {
if (!bus->cmd_dma_state) {
snd_hdac_bus_init_cmd_io(bus);
bus->cmd_dma_state = true;
}
- ret = snd_hdac_ext_bus_link_power_up(link);
+ ret = snd_hdac_ext_bus_link_power_up(hlink);
/*
* clear the register to invalidate all the output streams
*/
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV,
+ snd_hdac_updatew(hlink->ml_addr, AZX_REG_ML_LOSIDV,
AZX_ML_LOSIDV_STREAM_MASK, 0);
/*
* wait for 521usec for codec to report status
@@ -300,10 +318,10 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
- struct hdac_ext_link *link)
+ struct hdac_ext_link *hlink)
{
int ret = 0;
- struct hdac_ext_link *hlink;
+ struct hdac_ext_link *hlink_tmp;
bool link_up = false;
mutex_lock(&bus->lock);
@@ -312,15 +330,15 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
* if we move from 1 to 0, count will be 0
* so power down this link as well
*/
- if (--link->ref_count == 0) {
- ret = snd_hdac_ext_bus_link_power_down(link);
+ if (--hlink->ref_count == 0) {
+ ret = snd_hdac_ext_bus_link_power_down(hlink);
/*
* now check if all links are off, if so turn off
* cmd dma as well
*/
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (hlink->ref_count) {
+ list_for_each_entry(hlink_tmp, &bus->hlink_list, list) {
+ if (hlink_tmp->ref_count) {
link_up = true;
break;
}
@@ -341,7 +359,7 @@ static void hdac_ext_codec_link_up(struct hdac_device *codec)
{
const char *devname = dev_name(&codec->dev);
struct hdac_ext_link *hlink =
- snd_hdac_ext_bus_get_link(codec->bus, devname);
+ snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
if (hlink)
snd_hdac_ext_bus_link_get(codec->bus, hlink);
@@ -351,7 +369,7 @@ static void hdac_ext_codec_link_down(struct hdac_device *codec)
{
const char *devname = dev_name(&codec->dev);
struct hdac_ext_link *hlink =
- snd_hdac_ext_bus_get_link(codec->bus, devname);
+ snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
if (hlink)
snd_hdac_ext_bus_link_put(codec->bus, hlink);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 70f3ad71aaf0..2a071a09224d 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -39,20 +39,6 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
AZX_PPLC_INTERVAL * idx;
}
- if (bus->spbcap) {
- hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
- AZX_SPB_INTERVAL * idx +
- AZX_SPB_SPIB;
-
- hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
- AZX_SPB_INTERVAL * idx +
- AZX_SPB_MAXFIFO;
- }
-
- if (bus->drsmcap)
- hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
- AZX_DRSM_INTERVAL * idx;
-
hext_stream->decoupled = false;
snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag);
}
@@ -140,36 +126,36 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
/**
- * snd_hdac_ext_link_stream_start - start a stream
+ * snd_hdac_ext_stream_start - start a stream
* @hext_stream: HD-audio ext core stream to start
*/
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream)
{
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_start);
/**
- * snd_hdac_ext_link_stream_clear - stop a stream DMA
+ * snd_hdac_ext_stream_clear - stop a stream DMA
* @hext_stream: HD-audio ext core stream to stop
*/
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream)
{
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_clear);
/**
- * snd_hdac_ext_link_stream_reset - reset a stream
+ * snd_hdac_ext_stream_reset - reset a stream
* @hext_stream: HD-audio ext core stream to reset
*/
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream)
{
unsigned char val;
int timeout;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST);
@@ -196,20 +182,20 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
} while (--timeout);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_reset);
/**
- * snd_hdac_ext_link_stream_setup - set up the SD for streaming
+ * snd_hdac_ext_stream_setup - set up the SD for streaming
* @hext_stream: HD-audio ext core stream to set up
* @fmt: stream format
*/
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
{
struct hdac_stream *hstream = &hext_stream->hstream;
unsigned int val;
/* make sure the run bit is zero for SD */
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
/* program the stream_tag */
val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL);
val = (val & ~AZX_PPLCCTL_STRM_MASK) |
@@ -221,35 +207,11 @@ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
return 0;
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
-
-/**
- * snd_hdac_ext_link_set_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
- int stream)
-{
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
-
-/**
- * snd_hdac_ext_link_clear_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
- int stream)
-{
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_setup);
static struct hdac_ext_stream *
-hdac_ext_link_stream_assign(struct hdac_bus *bus,
- struct snd_pcm_substream *substream)
+hdac_ext_link_dma_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
@@ -284,8 +246,8 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
}
static struct hdac_ext_stream *
-hdac_ext_host_stream_assign(struct hdac_bus *bus,
- struct snd_pcm_substream *substream)
+hdac_ext_host_dma_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
@@ -353,10 +315,10 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
return hext_stream;
case HDAC_EXT_STREAM_TYPE_HOST:
- return hdac_ext_host_stream_assign(bus, substream);
+ return hdac_ext_host_dma_stream_assign(bus, substream);
case HDAC_EXT_STREAM_TYPE_LINK:
- return hdac_ext_link_stream_assign(bus, substream);
+ return hdac_ext_link_dma_stream_assign(bus, substream);
default:
return NULL;
@@ -405,128 +367,3 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
-
-/**
- * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable SPIB
- * @index: stream index for which SPIB need to be enabled
- */
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
- bool enable, int index)
-{
- u32 mask = 0;
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return;
- }
-
- mask |= (1 << index);
-
- if (enable)
- snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
- else
- snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
-
-/**
- * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: spib value to set
- */
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value)
-{
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return -EINVAL;
- }
-
- writel(value, hext_stream->spib_addr);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
-
-/**
- * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- *
- * Return maxfifo for the stream
- */
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream)
-{
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return -EINVAL;
- }
-
- return readl(hext_stream->fifo_addr);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
-
-/**
- * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable DRSM
- * @index: stream index for which DRSM need to be enabled
- */
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
- bool enable, int index)
-{
- u32 mask = 0;
-
- if (!bus->drsmcap) {
- dev_err(bus->dev, "Address of DRSM capability is NULL\n");
- return;
- }
-
- mask |= (1 << index);
-
- if (enable)
- snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
- else
- snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
-
-/**
- * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: dpib value to set
- */
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value)
-{
-
- if (!bus->drsmcap) {
- dev_err(bus->dev, "Address of DRSM capability is NULL\n");
- return -EINVAL;
- }
-
- writel(value, hext_stream->dpibr_addr);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
-
-/**
- * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
- * @hext_stream: hdac_ext_stream
- * @value: lpib value to set
- */
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value)
-{
- snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 1b8be39c38a9..3b250ee7f6a7 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -103,6 +103,20 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
azx_dev->stream_tag = tag;
snd_hdac_dsp_lock_init(azx_dev);
list_add_tail(&azx_dev->list, &bus->stream_list);
+
+ if (bus->spbcap) {
+ azx_dev->spib_addr = bus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_SPIB;
+
+ azx_dev->fifo_addr = bus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_MAXFIFO;
+ }
+
+ if (bus->drsmcap)
+ azx_dev->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
+ AZX_DRSM_INTERVAL * idx;
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_init);
@@ -718,6 +732,150 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_sync);
+/**
+ * snd_hdac_stream_spbcap_enable - enable SPIB for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable SPIB
+ * @index: stream index for which SPIB need to be enabled
+ */
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus,
+ bool enable, int index)
+{
+ u32 mask = 0;
+
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return;
+ }
+
+ mask |= (1 << index);
+
+ if (enable)
+ snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
+ else
+ snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable);
+
+/**
+ * snd_hdac_stream_set_spib - sets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: spib value to set
+ */
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value)
+{
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return -EINVAL;
+ }
+
+ writel(value, azx_dev->spib_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib);
+
+/**
+ * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ *
+ * Return maxfifo for the stream
+ */
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev)
+{
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return -EINVAL;
+ }
+
+ return readl(azx_dev->fifo_addr);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo);
+
+/**
+ * snd_hdac_stream_drsm_enable - enable DMA resume for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+ bool enable, int index)
+{
+ u32 mask = 0;
+
+ if (!bus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+ return;
+ }
+
+ mask |= (1 << index);
+
+ if (enable)
+ snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
+ else
+ snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable);
+
+/*
+ * snd_hdac_stream_wait_drsm - wait for HW to clear RSM for a stream
+ * @azx_dev: HD-audio core stream to await RSM for
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev)
+{
+ struct hdac_bus *bus = azx_dev->bus;
+ u32 mask, reg;
+ int ret;
+
+ mask = 1 << azx_dev->index;
+
+ ret = read_poll_timeout(snd_hdac_reg_readl, reg, !(reg & mask), 250, 2000, false, bus,
+ bus->drsmcap + AZX_REG_DRSM_CTL);
+ if (ret)
+ dev_dbg(bus->dev, "polling RSM 0x%08x failed: %d\n", mask, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_wait_drsm);
+
+/**
+ * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value)
+{
+ if (!bus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+ return -EINVAL;
+ }
+
+ writel(value, azx_dev->dpibr_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr);
+
+/**
+ * snd_hdac_stream_set_lpib - sets the lpib value of a stream
+ * @azx_dev: hdac_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value)
+{
+ snd_hdac_stream_writel(azx_dev, SD_LPIB, value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib);
+
#ifdef CONFIG_SND_HDA_DSP_LOADER
/**
* snd_hdac_dsp_prepare - prepare for DSP loading
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
index e47de49a32e3..62a9615dcf52 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/hdac_sysfs.c
@@ -346,8 +346,10 @@ static int add_widget_node(struct kobject *parent, hda_nid_t nid,
return -ENOMEM;
kobject_init(kobj, &widget_ktype);
err = kobject_add(kobj, parent, "%02x", nid);
- if (err < 0)
+ if (err < 0) {
+ kobject_put(kobj);
return err;
+ }
err = sysfs_create_group(kobj, group);
if (err < 0) {
kobject_put(kobj);
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index b9eb3208f288..ae31bb127594 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -321,6 +321,11 @@ static const struct config_entry config_table[] = {
}
},
{
+ .flags = FLAG_SOF,
+ .device = 0x34c8,
+ .codec_hid = &essx_83x6,
+ },
+ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = 0x34c8,
},
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 8de43aaa10aa..001786e2aba1 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -725,7 +725,6 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
unsigned int remdata, xfercount, next_jiffies;
int first = 1;
- int loops = 0;
u16 state;
u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
char name[16];
@@ -806,7 +805,6 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
(unsigned long)frames_to_bytes(runtime,
runtime->control->appl_ptr)
);
- loops++;
}
pcm_buf_dma_ofs = min_buf_pos;
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index bb31b7fe867d..477a5b4b50bc 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -361,7 +361,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
pci_dev->device, pci_dev->subsystem_vendor,
pci_dev->subsystem_device, pci_dev->devfn);
- if (pci_enable_device(pci_dev) < 0) {
+ if (pcim_enable_device(pci_dev) < 0) {
dev_err(&pci_dev->dev,
"pci_enable_device failed, disabling device\n");
return -EIO;
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 0db24cc4d916..9c88e99e3750 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -110,7 +110,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
unsigned int period_bytes)
{
unsigned int i;
- u32 addr, desc_addr, jmpprd_addr;
+ u32 addr, jmpprd_addr;
struct cs5535audio_dma_desc *lastdesc;
if (periods > CS5535AUDIO_MAX_DESCRIPTORS)
@@ -131,14 +131,12 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
/* the u32 cast is okay because in snd*create we successfully told
pci alloc that we're only 32 bit capable so the upper will be 0 */
addr = (u32) substream->runtime->dma_addr;
- desc_addr = (u32) dma->desc_buf.addr;
for (i = 0; i < periods; i++) {
struct cs5535audio_dma_desc *desc =
&((struct cs5535audio_dma_desc *) dma->desc_buf.area)[i];
desc->addr = cpu_to_le32(addr);
desc->size = cpu_to_le16(period_bytes);
desc->ctlreserved = cpu_to_le16(PRD_EOP);
- desc_addr += sizeof(struct cs5535audio_dma_desc);
addr += period_bytes;
}
/* we reserved one dummy descriptor at the end to do the PRD jump */
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index a8e8cf98befa..06d304db4183 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -98,7 +98,7 @@ config SND_HDA_SCODEC_CS35L41
config SND_HDA_CS_DSP_CONTROLS
tristate
- select CS_DSP
+ select FW_CS_DSP
config SND_HDA_SCODEC_CS35L41_I2C
tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index e5f0549bf06d..91842c0c8c74 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -1545,3 +1545,4 @@ MODULE_DESCRIPTION("CS35L41 HDA Driver");
MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c
index 5a6252d9b9e1..7826b1a12d7d 100644
--- a/sound/pci/hda/cs35l41_hda_i2c.c
+++ b/sound/pci/hda/cs35l41_hda_i2c.c
@@ -12,7 +12,7 @@
#include "cs35l41_hda.h"
-static int cs35l41_hda_i2c_probe(struct i2c_client *clt, const struct i2c_device_id *id)
+static int cs35l41_hda_i2c_probe(struct i2c_client *clt)
{
const char *device_name;
@@ -58,7 +58,7 @@ static struct i2c_driver cs35l41_i2c_driver = {
.pm = &cs35l41_hda_pm_ops,
},
.id_table = cs35l41_hda_i2c_id,
- .probe = cs35l41_hda_i2c_probe,
+ .probe_new = cs35l41_hda_i2c_probe,
.remove = cs35l41_hda_i2c_remove,
};
module_i2c_driver(cs35l41_i2c_driver);
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c
index 1622a22f96f6..5433f6227ac9 100644
--- a/sound/pci/hda/hda_cs_dsp_ctl.c
+++ b/sound/pci/hda/hda_cs_dsp_ctl.c
@@ -249,3 +249,4 @@ EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS);
MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library");
MODULE_AUTHOR("Stefan Binding, <sbinding@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 6ff19dd0d10c..87002670c0c9 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -485,8 +485,8 @@ static int intel_ml_lctl_set_power(struct azx *chip, int state)
int timeout;
/*
- * the codecs are sharing the first link setting by default
- * If other links are enabled for stream, they need similar fix
+ * Changes to LCTL.SCF are only needed for the first multi-link dealing
+ * with external codecs
*/
val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
val &= ~AZX_ML_LCTL_SPA;
@@ -513,7 +513,7 @@ static void intel_init_lctl(struct azx *chip)
/* 0. check lctl register value is correct or not */
val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
- /* if SCF is already set, let's use it */
+ /* only perform additional configurations if the SCF is initially based on 6MHz */
if ((val & AZX_ML_LCTL_SCF) != 0)
return;
@@ -531,7 +531,7 @@ static void intel_init_lctl(struct azx *chip)
if (ret)
goto set_spa;
- /* 2. update SCF to select a properly audio clock*/
+ /* 2. update SCF to select an audio clock different from 6MHz */
val &= ~AZX_ML_LCTL_SCF;
val |= intel_get_lctl_scf(chip);
writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
@@ -2711,6 +2711,9 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xab28),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
+ { PCI_DEVICE(0x1002, 0xab30),
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab38),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 9580fe00cbd9..0a292bf271f2 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1306,6 +1306,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI),
SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
index 754aa8ddd2e4..0ba1fbcbb21e 100644
--- a/sound/pci/hda/patch_cs8409.c
+++ b/sound/pci/hda/patch_cs8409.c
@@ -888,7 +888,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
/* Initialize CS42L42 companion codec */
cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
- usleep_range(20000, 25000);
+ usleep_range(30000, 35000);
/* Clear interrupts, by reading interrupt status registers */
cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 701a72ec5629..5f51f8fc7fdc 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6903,6 +6903,34 @@ static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
}
}
+static void alc295_fixup_dell_inspiron_top_speakers(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x14, 0x90170151 },
+ { 0x17, 0x90170150 },
+ { }
+ };
+ static const hda_nid_t conn[] = { 0x02, 0x03 };
+ static const hda_nid_t preferred_pairs[] = {
+ 0x14, 0x02,
+ 0x17, 0x03,
+ 0x21, 0x02,
+ 0
+ };
+ struct alc_spec *spec = codec->spec;
+
+ alc_fixup_no_shutup(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ spec->gen.preferred_dacs = preferred_pairs;
+ break;
+ }
+}
+
enum {
ALC269_FIXUP_GPIO2,
ALC269_FIXUP_SONY_VAIO,
@@ -7146,6 +7174,7 @@ enum {
ALC287_FIXUP_LEGION_16ITHG6,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+ ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9095,6 +9124,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
},
+ [ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc295_fixup_dell_inspiron_top_speakers,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9195,6 +9230,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+ SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
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),
@@ -9354,6 +9391,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9404,6 +9443,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
@@ -9435,6 +9475,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
+ SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
+ SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -9608,6 +9650,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
+ SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 80e5108157ef..0c4f43963c75 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -16,8 +16,7 @@
static struct pmac_keywest *keywest_ctx;
static bool keywest_probed;
-static int keywest_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int keywest_probe(struct i2c_client *client)
{
keywest_probed = true;
/* If instantiated via i2c-powermac, we still need to set the client */
@@ -91,7 +90,7 @@ static struct i2c_driver keywest_driver = {
.driver = {
.name = "PMac Keywest Audio",
},
- .probe = keywest_probe,
+ .probe_new = keywest_probe,
.remove = keywest_remove,
.id_table = keywest_i2c_id,
};
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 150786279257..c88ebd84bdd5 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -129,10 +129,10 @@ config SND_SOC_AMD_RPL_ACP6x
If unsure select "N".
config SND_SOC_AMD_PS
- tristate "AMD Audio Coprocessor-v6.2 Pink Sardine support"
+ tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
depends on X86 && PCI && ACPI
help
- This option enables Audio Coprocessor i.e ACP v6.2 support on
+ This option enables Audio Coprocessor i.e ACP v6.3 support on
AMD Pink sardine platform. By enabling this flag build will be
triggered for ACP PCI driver, ACP PDM DMA driver.
Say m if you have such a device.
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index ef1b4cefc273..375417bd7d6e 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -21,7 +21,6 @@
#include "acp.h"
#include "../codecs/da7219.h"
-#include "../codecs/da7219-aad.h"
#include "../codecs/rt5682.h"
#define CZ_PLAT_CLK 48000000
@@ -82,7 +81,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &cz_jack);
+ snd_soc_component_set_jack(component, &cz_jack, NULL);
return 0;
}
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index ac416572db0d..09b6511c0a26 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -51,7 +51,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
struct acp_stream *stream;
- int slot_len;
+ int slot_len, no_of_slots;
switch (slot_width) {
case SLOT_WIDTH_8:
@@ -71,6 +71,20 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
return -EINVAL;
}
+ switch (slots) {
+ case 1 ... 7:
+ no_of_slots = slots;
+ break;
+ case 8:
+ no_of_slots = 0;
+ break;
+ default:
+ dev_err(dev, "Unsupported slots %d\n", slots);
+ return -EINVAL;
+ }
+
+ slots = no_of_slots;
+
spin_lock_irq(&adata->acp_lock);
list_for_each_entry(stream, &adata->stream_list, list) {
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 4c69cb6e3400..a78cf29387a7 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -167,11 +167,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- if (!drvdata->soc_mclk) {
- ret = acp_clk_enable(drvdata);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
- return ret;
+
+ if (strcmp(codec_dai->name, "rt5682s-aif1") && strcmp(codec_dai->name, "rt5682s-aif2")) {
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ return ret;
+ }
}
}
@@ -280,7 +283,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
static const struct snd_soc_ops acp_card_rt5682s_ops = {
.startup = acp_card_hs_startup,
- .shutdown = acp_card_shutdown,
};
static const unsigned int dmic_channels[] = {
@@ -570,6 +572,52 @@ SND_SOC_DAILINK_DEF(sof_dmic,
SND_SOC_DAILINK_DEF(pdm_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic")));
+static int acp_rtk_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_component *component = dapm->component;
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret = 0;
+
+ if (!component)
+ return 0;
+
+ if (strncmp(component->name, "i2c-RTL5682", 11) &&
+ strncmp(component->name, "i2c-10EC1019", 12))
+ return 0;
+
+ /*
+ * For Realtek's codec and amplifier components,
+ * the lrck and bclk must be enabled brfore their all dapms be powered on,
+ * and must be disabled after their all dapms be powered down
+ * to avoid any pop.
+ */
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
+ clk_set_rate(drvdata->wclk, 48000);
+ clk_set_rate(drvdata->bclk, 48000 * 64);
+
+ /* Increase bclk's enable_count */
+ ret = clk_prepare_enable(drvdata->bclk);
+ if (ret < 0)
+ dev_err(component->dev, "Failed to enable bclk %d\n", ret);
+ } else {
+ /*
+ * Decrease bclk's enable_count.
+ * While the enable_count is 0, the bclk would be closed.
+ */
+ clk_disable_unprepare(drvdata->bclk);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
{
struct snd_soc_dai_link *links;
@@ -730,6 +778,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
card->dai_link = links;
card->num_links = num_links;
+ card->set_bias_level = acp_rtk_set_bias_level;
return 0;
}
@@ -907,6 +956,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
card->dai_link = links;
card->num_links = num_links;
+ card->set_bias_level = acp_rtk_set_bias_level;
return 0;
}
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index 85a81add4ef9..447612a7a762 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -184,10 +184,6 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
stream->substream = substream;
- spin_lock_irq(&adata->acp_lock);
- list_add_tail(&stream->list, &adata->stream_list);
- spin_unlock_irq(&adata->acp_lock);
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = acp_pcm_hardware_playback;
else
@@ -203,6 +199,10 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
writel(1, ACP_EXTERNAL_INTR_ENB(adata));
+ spin_lock_irq(&adata->acp_lock);
+ list_add_tail(&stream->list, &adata->stream_list);
+ spin_unlock_irq(&adata->acp_lock);
+
return ret;
}
diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp63.h
index 8b30aefa4cd0..5e7f9c1c1b0e 100644
--- a/sound/soc/amd/ps/acp62.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -5,13 +5,13 @@
* Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.
*/
-#include <sound/acp62_chip_offset_byte.h>
+#include <sound/acp63_chip_offset_byte.h>
#define ACP_DEVICE_ID 0x15E2
-#define ACP6x_REG_START 0x1240000
-#define ACP6x_REG_END 0x1250200
-#define ACP6x_DEVS 3
-#define ACP6x_PDM_MODE 1
+#define ACP63_REG_START 0x1240000
+#define ACP63_REG_END 0x1250200
+#define ACP63_DEVS 3
+#define ACP63_PDM_MODE 1
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
@@ -78,21 +78,28 @@ struct pdm_stream_instance {
u16 channels;
dma_addr_t dma_addr;
u64 bytescount;
- void __iomem *acp62_base;
+ void __iomem *acp63_base;
};
struct pdm_dev_data {
u32 pdm_irq;
- void __iomem *acp62_base;
+ void __iomem *acp63_base;
struct snd_pcm_substream *capture_stream;
};
-static inline u32 acp62_readl(void __iomem *base_addr)
+static inline u32 acp63_readl(void __iomem *base_addr)
{
return readl(base_addr);
}
-static inline void acp62_writel(u32 val, void __iomem *base_addr)
+static inline void acp63_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr);
}
+
+struct acp63_dev_data {
+ void __iomem *acp63_base;
+ struct resource *res;
+ bool acp63_audio_mode;
+ struct platform_device *pdev[ACP63_DEVS];
+};
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index dff2e2376bbf..489f01a20699 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -15,30 +15,23 @@
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
-#include "acp62.h"
+#include "acp63.h"
-struct acp62_dev_data {
- void __iomem *acp62_base;
- struct resource *res;
- bool acp62_audio_mode;
- struct platform_device *pdev[ACP6x_DEVS];
-};
-
-static int acp62_power_on(void __iomem *acp_base)
+static int acp63_power_on(void __iomem *acp_base)
{
u32 val;
int timeout;
- val = acp62_readl(acp_base + ACP_PGFSM_STATUS);
+ val = acp63_readl(acp_base + ACP_PGFSM_STATUS);
if (!val)
return val;
if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
- acp62_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+ acp63_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
timeout = 0;
while (++timeout < 500) {
- val = acp62_readl(acp_base + ACP_PGFSM_STATUS);
+ val = acp63_readl(acp_base + ACP_PGFSM_STATUS);
if (!val)
return 0;
udelay(1);
@@ -46,23 +39,23 @@ static int acp62_power_on(void __iomem *acp_base)
return -ETIMEDOUT;
}
-static int acp62_reset(void __iomem *acp_base)
+static int acp63_reset(void __iomem *acp_base)
{
u32 val;
int timeout;
- acp62_writel(1, acp_base + ACP_SOFT_RESET);
+ acp63_writel(1, acp_base + ACP_SOFT_RESET);
timeout = 0;
while (++timeout < 500) {
- val = acp62_readl(acp_base + ACP_SOFT_RESET);
+ val = acp63_readl(acp_base + ACP_SOFT_RESET);
if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
break;
cpu_relax();
}
- acp62_writel(0, acp_base + ACP_SOFT_RESET);
+ acp63_writel(0, acp_base + ACP_SOFT_RESET);
timeout = 0;
while (++timeout < 500) {
- val = acp62_readl(acp_base + ACP_SOFT_RESET);
+ val = acp63_readl(acp_base + ACP_SOFT_RESET);
if (!val)
return 0;
cpu_relax();
@@ -70,57 +63,57 @@ static int acp62_reset(void __iomem *acp_base)
return -ETIMEDOUT;
}
-static void acp62_enable_interrupts(void __iomem *acp_base)
+static void acp63_enable_interrupts(void __iomem *acp_base)
{
- acp62_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
+ acp63_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
}
-static void acp62_disable_interrupts(void __iomem *acp_base)
+static void acp63_disable_interrupts(void __iomem *acp_base)
{
- acp62_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
+ acp63_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
ACP_EXTERNAL_INTR_STAT);
- acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
- acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
+ acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
}
-static int acp62_init(void __iomem *acp_base, struct device *dev)
+static int acp63_init(void __iomem *acp_base, struct device *dev)
{
int ret;
- ret = acp62_power_on(acp_base);
+ ret = acp63_power_on(acp_base);
if (ret) {
dev_err(dev, "ACP power on failed\n");
return ret;
}
- acp62_writel(0x01, acp_base + ACP_CONTROL);
- ret = acp62_reset(acp_base);
+ acp63_writel(0x01, acp_base + ACP_CONTROL);
+ ret = acp63_reset(acp_base);
if (ret) {
dev_err(dev, "ACP reset failed\n");
return ret;
}
- acp62_writel(0x03, acp_base + ACP_CLKMUX_SEL);
- acp62_enable_interrupts(acp_base);
+ acp63_writel(0x03, acp_base + ACP_CLKMUX_SEL);
+ acp63_enable_interrupts(acp_base);
return 0;
}
-static int acp62_deinit(void __iomem *acp_base, struct device *dev)
+static int acp63_deinit(void __iomem *acp_base, struct device *dev)
{
int ret;
- acp62_disable_interrupts(acp_base);
- ret = acp62_reset(acp_base);
+ acp63_disable_interrupts(acp_base);
+ ret = acp63_reset(acp_base);
if (ret) {
dev_err(dev, "ACP reset failed\n");
return ret;
}
- acp62_writel(0, acp_base + ACP_CLKMUX_SEL);
- acp62_writel(0, acp_base + ACP_CONTROL);
+ acp63_writel(0, acp_base + ACP_CLKMUX_SEL);
+ acp63_writel(0, acp_base + ACP_CONTROL);
return 0;
}
-static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
+static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
{
- struct acp62_dev_data *adata;
+ struct acp63_dev_data *adata;
struct pdm_dev_data *ps_pdm_data;
u32 val;
@@ -128,10 +121,10 @@ static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
if (!adata)
return IRQ_NONE;
- val = acp62_readl(adata->acp62_base + ACP_EXTERNAL_INTR_STAT);
+ val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (val & BIT(PDM_DMA_STAT)) {
ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev);
- acp62_writel(BIT(PDM_DMA_STAT), adata->acp62_base + ACP_EXTERNAL_INTR_STAT);
+ acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (ps_pdm_data->capture_stream)
snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
return IRQ_HANDLED;
@@ -139,11 +132,11 @@ static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
-static int snd_acp62_probe(struct pci_dev *pci,
+static int snd_acp63_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
- struct acp62_dev_data *adata;
- struct platform_device_info pdevinfo[ACP6x_DEVS];
+ struct acp63_dev_data *adata;
+ struct platform_device_info pdevinfo[ACP63_DEVS];
int index, ret;
int val = 0x00;
struct acpi_device *adev;
@@ -157,7 +150,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
case 0x63:
break;
default:
- dev_dbg(&pci->dev, "acp62 pci device not found\n");
+ dev_dbg(&pci->dev, "acp63 pci device not found\n");
return -ENODEV;
}
if (pci_enable_device(pci)) {
@@ -170,7 +163,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
dev_err(&pci->dev, "pci_request_regions failed\n");
goto disable_pci;
}
- adata = devm_kzalloc(&pci->dev, sizeof(struct acp62_dev_data),
+ adata = devm_kzalloc(&pci->dev, sizeof(struct acp63_dev_data),
GFP_KERNEL);
if (!adata) {
ret = -ENOMEM;
@@ -178,18 +171,18 @@ static int snd_acp62_probe(struct pci_dev *pci,
}
addr = pci_resource_start(pci, 0);
- adata->acp62_base = devm_ioremap(&pci->dev, addr,
+ adata->acp63_base = devm_ioremap(&pci->dev, addr,
pci_resource_len(pci, 0));
- if (!adata->acp62_base) {
+ if (!adata->acp63_base) {
ret = -ENOMEM;
goto release_regions;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
- ret = acp62_init(adata->acp62_base, &pci->dev);
+ ret = acp63_init(adata->acp63_base, &pci->dev);
if (ret)
goto release_regions;
- val = acp62_readl(adata->acp62_base + ACP_PIN_CONFIG);
+ val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG);
switch (val) {
case ACP_CONFIG_0:
case ACP_CONFIG_1:
@@ -219,8 +212,8 @@ static int snd_acp62_probe(struct pci_dev *pci,
adata->res->name = "acp_iomem";
adata->res->flags = IORESOURCE_MEM;
adata->res->start = addr;
- adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START);
- adata->acp62_audio_mode = ACP6x_PDM_MODE;
+ adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START);
+ adata->acp63_audio_mode = ACP63_PDM_MODE;
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo[0].name = "acp_ps_pdm_dma";
@@ -237,7 +230,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
pdevinfo[2].id = 0;
pdevinfo[2].parent = &pci->dev;
- for (index = 0; index < ACP6x_DEVS; index++) {
+ for (index = 0; index < ACP63_DEVS; index++) {
adata->pdev[index] =
platform_device_register_full(&pdevinfo[index]);
@@ -248,7 +241,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
ret = PTR_ERR(adata->pdev[index]);
goto unregister_devs;
}
- ret = devm_request_irq(&pci->dev, pci->irq, acp62_irq_handler,
+ ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler,
irqflags, "ACP_PCI_IRQ", adata);
if (ret) {
dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
@@ -267,7 +260,7 @@ unregister_devs:
for (--index; index >= 0; index--)
platform_device_unregister(adata->pdev[index]);
de_init:
- if (acp62_deinit(adata->acp62_base, &pci->dev))
+ if (acp63_deinit(adata->acp63_base, &pci->dev))
dev_err(&pci->dev, "ACP de-init failed\n");
release_regions:
pci_release_regions(pci);
@@ -277,46 +270,46 @@ disable_pci:
return ret;
}
-static int __maybe_unused snd_acp62_suspend(struct device *dev)
+static int __maybe_unused snd_acp63_suspend(struct device *dev)
{
- struct acp62_dev_data *adata;
+ struct acp63_dev_data *adata;
int ret;
adata = dev_get_drvdata(dev);
- ret = acp62_deinit(adata->acp62_base, dev);
+ ret = acp63_deinit(adata->acp63_base, dev);
if (ret)
dev_err(dev, "ACP de-init failed\n");
return ret;
}
-static int __maybe_unused snd_acp62_resume(struct device *dev)
+static int __maybe_unused snd_acp63_resume(struct device *dev)
{
- struct acp62_dev_data *adata;
+ struct acp63_dev_data *adata;
int ret;
adata = dev_get_drvdata(dev);
- ret = acp62_init(adata->acp62_base, dev);
+ ret = acp63_init(adata->acp63_base, dev);
if (ret)
dev_err(dev, "ACP init failed\n");
return ret;
}
-static const struct dev_pm_ops acp62_pm_ops = {
- SET_RUNTIME_PM_OPS(snd_acp62_suspend, snd_acp62_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_acp62_suspend, snd_acp62_resume)
+static const struct dev_pm_ops acp63_pm_ops = {
+ SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume)
};
-static void snd_acp62_remove(struct pci_dev *pci)
+static void snd_acp63_remove(struct pci_dev *pci)
{
- struct acp62_dev_data *adata;
+ struct acp63_dev_data *adata;
int ret, index;
adata = pci_get_drvdata(pci);
- if (adata->acp62_audio_mode == ACP6x_PDM_MODE) {
- for (index = 0; index < ACP6x_DEVS; index++)
+ if (adata->acp63_audio_mode == ACP63_PDM_MODE) {
+ for (index = 0; index < ACP63_DEVS; index++)
platform_device_unregister(adata->pdev[index]);
}
- ret = acp62_deinit(adata->acp62_base, &pci->dev);
+ ret = acp63_deinit(adata->acp63_base, &pci->dev);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
pm_runtime_forbid(&pci->dev);
@@ -325,25 +318,25 @@ static void snd_acp62_remove(struct pci_dev *pci)
pci_disable_device(pci);
}
-static const struct pci_device_id snd_acp62_ids[] = {
+static const struct pci_device_id snd_acp63_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
.class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
.class_mask = 0xffffff },
{ 0, },
};
-MODULE_DEVICE_TABLE(pci, snd_acp62_ids);
+MODULE_DEVICE_TABLE(pci, snd_acp63_ids);
-static struct pci_driver ps_acp62_driver = {
+static struct pci_driver ps_acp63_driver = {
.name = KBUILD_MODNAME,
- .id_table = snd_acp62_ids,
- .probe = snd_acp62_probe,
- .remove = snd_acp62_remove,
+ .id_table = snd_acp63_ids,
+ .probe = snd_acp63_probe,
+ .remove = snd_acp63_remove,
.driver = {
- .pm = &acp62_pm_ops,
+ .pm = &acp63_pm_ops,
}
};
-module_pci_driver(ps_acp62_driver);
+module_pci_driver(ps_acp63_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c
index b3e97093481d..3ffbe4fdafdf 100644
--- a/sound/soc/amd/ps/ps-mach.c
+++ b/sound/soc/amd/ps/ps-mach.c
@@ -13,11 +13,11 @@
#include <linux/io.h>
#include <linux/dmi.h>
-#include "acp62.h"
+#include "acp63.h"
#define DRV_NAME "acp_ps_mach"
-SND_SOC_DAILINK_DEF(acp62_pdm,
+SND_SOC_DAILINK_DEF(acp63_pdm,
DAILINK_COMP_ARRAY(COMP_CPU("acp_ps_pdm_dma.0")));
SND_SOC_DAILINK_DEF(dmic_codec,
@@ -27,31 +27,31 @@ SND_SOC_DAILINK_DEF(dmic_codec,
SND_SOC_DAILINK_DEF(pdm_platform,
DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_ps_pdm_dma.0")));
-static struct snd_soc_dai_link acp62_dai_pdm[] = {
+static struct snd_soc_dai_link acp63_dai_pdm[] = {
{
- .name = "acp62-dmic-capture",
+ .name = "acp63-dmic-capture",
.stream_name = "DMIC capture",
.capture_only = 1,
- SND_SOC_DAILINK_REG(acp62_pdm, dmic_codec, pdm_platform),
+ SND_SOC_DAILINK_REG(acp63_pdm, dmic_codec, pdm_platform),
},
};
-static struct snd_soc_card acp62_card = {
- .name = "acp62",
+static struct snd_soc_card acp63_card = {
+ .name = "acp63",
.owner = THIS_MODULE,
- .dai_link = acp62_dai_pdm,
+ .dai_link = acp63_dai_pdm,
.num_links = 1,
};
-static int acp62_probe(struct platform_device *pdev)
+static int acp63_probe(struct platform_device *pdev)
{
- struct acp62_pdm *machine = NULL;
+ struct acp63_pdm *machine = NULL;
struct snd_soc_card *card;
int ret;
- platform_set_drvdata(pdev, &acp62_card);
+ platform_set_drvdata(pdev, &acp63_card);
card = platform_get_drvdata(pdev);
- acp62_card.dev = &pdev->dev;
+ acp63_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(card, machine);
ret = devm_snd_soc_register_card(&pdev->dev, card);
@@ -64,15 +64,15 @@ static int acp62_probe(struct platform_device *pdev)
return 0;
}
-static struct platform_driver acp62_mach_driver = {
+static struct platform_driver acp63_mach_driver = {
.driver = {
.name = "acp_ps_mach",
.pm = &snd_soc_pm_ops,
},
- .probe = acp62_probe,
+ .probe = acp63_probe,
};
-module_platform_driver(acp62_mach_driver);
+module_platform_driver(acp63_mach_driver);
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index b207b726cd82..eea71a9d2ef1 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -14,11 +14,11 @@
#include <sound/soc-dai.h>
#include <linux/pm_runtime.h>
-#include "acp62.h"
+#include "acp63.h"
#define DRV_NAME "acp_ps_pdm_dma"
-static const struct snd_pcm_hardware acp62_pdm_hardware_capture = {
+static const struct snd_pcm_hardware acp63_pdm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -37,61 +37,61 @@ static const struct snd_pcm_hardware acp62_pdm_hardware_capture = {
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
-static void acp62_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size,
+static void acp63_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size,
u32 watermark_size, void __iomem *acp_base)
{
- acp62_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR);
- acp62_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE);
- acp62_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
- acp62_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL);
+ acp63_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR);
+ acp63_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE);
+ acp63_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+ acp63_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL);
}
-static void acp62_enable_pdm_clock(void __iomem *acp_base)
+static void acp63_enable_pdm_clock(void __iomem *acp_base)
{
u32 pdm_clk_enable, pdm_ctrl;
pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK;
pdm_ctrl = 0x00;
- acp62_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
- pdm_ctrl = acp62_readl(acp_base + ACP_WOV_MISC_CTRL);
+ acp63_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
+ pdm_ctrl = acp63_readl(acp_base + ACP_WOV_MISC_CTRL);
pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
- acp62_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
+ acp63_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
}
-static void acp62_enable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_enable_pdm_interrupts(void __iomem *acp_base)
{
u32 ext_int_ctrl;
- ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl |= PDM_DMA_INTR_MASK;
- acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
}
-static void acp62_disable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_disable_pdm_interrupts(void __iomem *acp_base)
{
u32 ext_int_ctrl;
- ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
- acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
}
-static bool acp62_check_pdm_dma_status(void __iomem *acp_base)
+static bool acp63_check_pdm_dma_status(void __iomem *acp_base)
{
bool pdm_dma_status;
u32 pdm_enable, pdm_dma_enable;
pdm_dma_status = false;
- pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE);
- pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE);
+ pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & ACP_PDM_DMA_EN_STATUS))
pdm_dma_status = true;
return pdm_dma_status;
}
-static int acp62_start_pdm_dma(void __iomem *acp_base)
+static int acp63_start_pdm_dma(void __iomem *acp_base)
{
u32 pdm_enable;
u32 pdm_dma_enable;
@@ -100,12 +100,12 @@ static int acp62_start_pdm_dma(void __iomem *acp_base)
pdm_enable = 0x01;
pdm_dma_enable = 0x01;
- acp62_enable_pdm_clock(acp_base);
- acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ acp63_enable_pdm_clock(acp_base);
+ acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
+ acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
timeout = 0;
while (++timeout < ACP_COUNTER) {
- pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS)
return 0;
udelay(DELAY_US);
@@ -113,7 +113,7 @@ static int acp62_start_pdm_dma(void __iomem *acp_base)
return -ETIMEDOUT;
}
-static int acp62_stop_pdm_dma(void __iomem *acp_base)
+static int acp63_stop_pdm_dma(void __iomem *acp_base)
{
u32 pdm_enable, pdm_dma_enable;
int timeout;
@@ -121,14 +121,14 @@ static int acp62_stop_pdm_dma(void __iomem *acp_base)
pdm_enable = 0x00;
pdm_dma_enable = 0x00;
- pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE);
- pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE);
+ pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
if (pdm_dma_enable & 0x01) {
pdm_dma_enable = 0x02;
- acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
timeout = 0;
while (++timeout < ACP_COUNTER) {
- pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) == 0x00)
break;
udelay(DELAY_US);
@@ -138,13 +138,13 @@ static int acp62_stop_pdm_dma(void __iomem *acp_base)
}
if (pdm_enable == ACP_PDM_ENABLE) {
pdm_enable = ACP_PDM_DISABLE;
- acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
+ acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
}
- acp62_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
+ acp63_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
return 0;
}
-static void acp62_config_dma(struct pdm_stream_instance *rtd, int direction)
+static void acp63_config_dma(struct pdm_stream_instance *rtd, int direction)
{
u16 page_idx;
u32 low, high, val;
@@ -154,24 +154,24 @@ static void acp62_config_dma(struct pdm_stream_instance *rtd, int direction)
val = PDM_PTE_OFFSET;
/* Group Enable */
- acp62_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp62_base +
+ acp63_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp63_base +
ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
- acp62_writel(PAGE_SIZE_4K_ENABLE, rtd->acp62_base +
+ acp63_writel(PAGE_SIZE_4K_ENABLE, rtd->acp63_base +
ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
/* Load the low address of page int ACP SRAM through SRBM */
low = lower_32_bits(addr);
high = upper_32_bits(addr);
- acp62_writel(low, rtd->acp62_base + ACP_SCRATCH_REG_0 + val);
+ acp63_writel(low, rtd->acp63_base + ACP_SCRATCH_REG_0 + val);
high |= BIT(31);
- acp62_writel(high, rtd->acp62_base + ACP_SCRATCH_REG_0 + val + 4);
+ acp63_writel(high, rtd->acp63_base + ACP_SCRATCH_REG_0 + val + 4);
val += 8;
addr += PAGE_SIZE;
}
}
-static int acp62_pdm_dma_open(struct snd_soc_component *component,
+static int acp63_pdm_dma_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
@@ -186,7 +186,7 @@ static int acp62_pdm_dma_open(struct snd_soc_component *component,
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- runtime->hw = acp62_pdm_hardware_capture;
+ runtime->hw = acp63_pdm_hardware_capture;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -196,17 +196,17 @@ static int acp62_pdm_dma_open(struct snd_soc_component *component,
return ret;
}
- acp62_enable_pdm_interrupts(adata->acp62_base);
+ acp63_enable_pdm_interrupts(adata->acp63_base);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
adata->capture_stream = substream;
- pdm_data->acp62_base = adata->acp62_base;
+ pdm_data->acp63_base = adata->acp63_base;
runtime->private_data = pdm_data;
return ret;
}
-static int acp62_pdm_dma_hw_params(struct snd_soc_component *component,
+static int acp63_pdm_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -220,26 +220,26 @@ static int acp62_pdm_dma_hw_params(struct snd_soc_component *component,
period_bytes = params_period_bytes(params);
rtd->dma_addr = substream->runtime->dma_addr;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
- acp62_config_dma(rtd, substream->stream);
- acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size,
- period_bytes, rtd->acp62_base);
+ acp63_config_dma(rtd, substream->stream);
+ acp63_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size,
+ period_bytes, rtd->acp63_base);
return 0;
}
-static u64 acp62_pdm_get_byte_count(struct pdm_stream_instance *rtd,
+static u64 acp63_pdm_get_byte_count(struct pdm_stream_instance *rtd,
int direction)
{
u32 high, low;
u64 byte_count;
- high = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
+ high = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
byte_count = high;
- low = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
+ low = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
byte_count = (byte_count << 32) | low;
return byte_count;
}
-static snd_pcm_uframes_t acp62_pdm_dma_pointer(struct snd_soc_component *comp,
+static snd_pcm_uframes_t acp63_pdm_dma_pointer(struct snd_soc_component *comp,
struct snd_pcm_substream *stream)
{
struct pdm_stream_instance *rtd;
@@ -249,14 +249,14 @@ static snd_pcm_uframes_t acp62_pdm_dma_pointer(struct snd_soc_component *comp,
rtd = stream->runtime->private_data;
buffersize = frames_to_bytes(stream->runtime,
stream->runtime->buffer_size);
- bytescount = acp62_pdm_get_byte_count(rtd, stream->stream);
+ bytescount = acp63_pdm_get_byte_count(rtd, stream->stream);
if (bytescount > rtd->bytescount)
bytescount -= rtd->bytescount;
pos = do_div(bytescount, buffersize);
return bytes_to_frames(stream->runtime, pos);
}
-static int acp62_pdm_dma_new(struct snd_soc_component *component,
+static int acp63_pdm_dma_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct device *parent = component->dev->parent;
@@ -266,19 +266,19 @@ static int acp62_pdm_dma_new(struct snd_soc_component *component,
return 0;
}
-static int acp62_pdm_dma_close(struct snd_soc_component *component,
+static int acp63_pdm_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
- acp62_disable_pdm_interrupts(adata->acp62_base);
+ acp63_disable_pdm_interrupts(adata->acp63_base);
adata->capture_stream = NULL;
kfree(runtime->private_data);
return 0;
}
-static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
+static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct pdm_stream_instance *rtd;
@@ -299,20 +299,20 @@ static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- acp62_writel(ch_mask, rtd->acp62_base + ACP_WOV_PDM_NO_OF_CHANNELS);
- acp62_writel(PDM_DECIMATION_FACTOR, rtd->acp62_base +
+ acp63_writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ acp63_writel(PDM_DECIMATION_FACTOR, rtd->acp63_base +
ACP_WOV_PDM_DECIMATION_FACTOR);
- rtd->bytescount = acp62_pdm_get_byte_count(rtd, substream->stream);
- pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base);
+ rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+ pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
if (!pdm_status)
- ret = acp62_start_pdm_dma(rtd->acp62_base);
+ ret = acp63_start_pdm_dma(rtd->acp63_base);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base);
+ pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
if (pdm_status)
- ret = acp62_stop_pdm_dma(rtd->acp62_base);
+ ret = acp63_stop_pdm_dma(rtd->acp63_base);
break;
default:
ret = -EINVAL;
@@ -321,11 +321,11 @@ static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
return ret;
}
-static const struct snd_soc_dai_ops acp62_pdm_dai_ops = {
- .trigger = acp62_pdm_dai_trigger,
+static const struct snd_soc_dai_ops acp63_pdm_dai_ops = {
+ .trigger = acp63_pdm_dai_trigger,
};
-static struct snd_soc_dai_driver acp62_pdm_dai_driver = {
+static struct snd_soc_dai_driver acp63_pdm_dai_driver = {
.name = "acp_ps_pdm_dma.0",
.capture = {
.rates = SNDRV_PCM_RATE_48000,
@@ -335,19 +335,19 @@ static struct snd_soc_dai_driver acp62_pdm_dai_driver = {
.rate_min = 48000,
.rate_max = 48000,
},
- .ops = &acp62_pdm_dai_ops,
+ .ops = &acp63_pdm_dai_ops,
};
-static const struct snd_soc_component_driver acp62_pdm_component = {
+static const struct snd_soc_component_driver acp63_pdm_component = {
.name = DRV_NAME,
- .open = acp62_pdm_dma_open,
- .close = acp62_pdm_dma_close,
- .hw_params = acp62_pdm_dma_hw_params,
- .pointer = acp62_pdm_dma_pointer,
- .pcm_construct = acp62_pdm_dma_new,
+ .open = acp63_pdm_dma_open,
+ .close = acp63_pdm_dma_close,
+ .hw_params = acp63_pdm_dma_hw_params,
+ .pointer = acp63_pdm_dma_pointer,
+ .pcm_construct = acp63_pdm_dma_new,
};
-static int acp62_pdm_audio_probe(struct platform_device *pdev)
+static int acp63_pdm_audio_probe(struct platform_device *pdev)
{
struct resource *res;
struct pdm_dev_data *adata;
@@ -363,16 +363,16 @@ static int acp62_pdm_audio_probe(struct platform_device *pdev)
if (!adata)
return -ENOMEM;
- adata->acp62_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp62_base)
+ adata->acp63_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!adata->acp63_base)
return -ENOMEM;
adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
- &acp62_pdm_component,
- &acp62_pdm_dai_driver, 1);
+ &acp63_pdm_component,
+ &acp63_pdm_dai_driver, 1);
if (status) {
dev_err(&pdev->dev, "Fail to register acp pdm dai\n");
@@ -385,13 +385,13 @@ static int acp62_pdm_audio_probe(struct platform_device *pdev)
return 0;
}
-static int acp62_pdm_audio_remove(struct platform_device *pdev)
+static int acp63_pdm_audio_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
-static int __maybe_unused acp62_pdm_resume(struct device *dev)
+static int __maybe_unused acp63_pdm_resume(struct device *dev)
{
struct pdm_dev_data *adata;
struct snd_pcm_runtime *runtime;
@@ -404,47 +404,47 @@ static int __maybe_unused acp62_pdm_resume(struct device *dev)
rtd = runtime->private_data;
period_bytes = frames_to_bytes(runtime, runtime->period_size);
buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
- acp62_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
- acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
- period_bytes, adata->acp62_base);
+ acp63_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+ acp63_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
+ period_bytes, adata->acp63_base);
}
- acp62_enable_pdm_interrupts(adata->acp62_base);
+ acp63_enable_pdm_interrupts(adata->acp63_base);
return 0;
}
-static int __maybe_unused acp62_pdm_suspend(struct device *dev)
+static int __maybe_unused acp63_pdm_suspend(struct device *dev)
{
struct pdm_dev_data *adata;
adata = dev_get_drvdata(dev);
- acp62_disable_pdm_interrupts(adata->acp62_base);
+ acp63_disable_pdm_interrupts(adata->acp63_base);
return 0;
}
-static int __maybe_unused acp62_pdm_runtime_resume(struct device *dev)
+static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev)
{
struct pdm_dev_data *adata;
adata = dev_get_drvdata(dev);
- acp62_enable_pdm_interrupts(adata->acp62_base);
+ acp63_enable_pdm_interrupts(adata->acp63_base);
return 0;
}
-static const struct dev_pm_ops acp62_pdm_pm_ops = {
- SET_RUNTIME_PM_OPS(acp62_pdm_suspend, acp62_pdm_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(acp62_pdm_suspend, acp62_pdm_resume)
+static const struct dev_pm_ops acp63_pdm_pm_ops = {
+ SET_RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume)
};
-static struct platform_driver acp62_pdm_dma_driver = {
- .probe = acp62_pdm_audio_probe,
- .remove = acp62_pdm_audio_remove,
+static struct platform_driver acp63_pdm_dma_driver = {
+ .probe = acp63_pdm_audio_probe,
+ .remove = acp63_pdm_audio_remove,
.driver = {
.name = "acp_ps_pdm_dma",
- .pm = &acp62_pdm_pm_ops,
+ .pm = &acp63_pdm_pm_ops,
},
};
-module_platform_driver(acp62_pdm_dma_driver);
+module_platform_driver(acp63_pdm_dma_driver);
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
MODULE_DESCRIPTION("AMD PINK SARDINE PDM Driver");
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 6c0f1de10429..1f0b5527c594 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -206,6 +206,20 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"),
+ }
+ },
{}
};
diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c
index ab2d7a791f39..dc96a6fbf514 100644
--- a/sound/soc/atmel/mchp-spdiftx.c
+++ b/sound/soc/atmel/mchp-spdiftx.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <sound/asoundef.h>
@@ -175,6 +176,7 @@ static const struct regmap_config mchp_spdiftx_regmap_config = {
.readable_reg = mchp_spdiftx_readable_reg,
.writeable_reg = mchp_spdiftx_writeable_reg,
.precious_reg = mchp_spdiftx_precious_reg,
+ .cache_type = REGCACHE_FLAT,
};
#define SPDIFTX_GCLK_RATIO 128
@@ -196,7 +198,7 @@ struct mchp_spdiftx_dev {
struct clk *pclk;
struct clk *gclk;
unsigned int fmt;
- unsigned int gclk_enabled:1;
+ unsigned int suspend_irq;
};
static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev)
@@ -317,16 +319,25 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd,
running = !!(mr & SPDIFTX_MR_TXEN_ENABLE);
switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_START:
+ regmap_write(dev->regmap, SPDIFTX_IER, dev->suspend_irq |
+ SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
+ dev->suspend_irq = 0;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!running) {
mr &= ~SPDIFTX_MR_TXEN_MASK;
mr |= SPDIFTX_MR_TXEN_ENABLE;
}
break;
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
+ regmap_read(dev->regmap, SPDIFTX_IMR, &dev->suspend_irq);
+ fallthrough;
+ case SNDRV_PCM_TRIGGER_STOP:
+ regmap_write(dev->regmap, SPDIFTX_IDR, dev->suspend_irq |
+ SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (running) {
mr &= ~SPDIFTX_MR_TXEN_MASK;
@@ -355,6 +366,7 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
struct mchp_spdiftx_mixer_control *ctrl = &dev->control;
u32 mr;
unsigned int bps = params_physical_width(params) / 8;
+ unsigned char aes3;
int ret;
dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
@@ -440,55 +452,54 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
mr |= SPDIFTX_MR_BPS(bps);
- spin_lock_irqsave(&ctrl->lock, flags);
- ctrl->ch_stat[3] &= ~IEC958_AES3_CON_FS;
switch (params_rate(params)) {
case 22050:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_22050;
+ aes3 = IEC958_AES3_CON_FS_22050;
break;
case 24000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_24000;
+ aes3 = IEC958_AES3_CON_FS_24000;
break;
case 32000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_32000;
+ aes3 = IEC958_AES3_CON_FS_32000;
break;
case 44100:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_44100;
+ aes3 = IEC958_AES3_CON_FS_44100;
break;
case 48000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_48000;
+ aes3 = IEC958_AES3_CON_FS_48000;
break;
case 88200:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_88200;
+ aes3 = IEC958_AES3_CON_FS_88200;
break;
case 96000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_96000;
+ aes3 = IEC958_AES3_CON_FS_96000;
break;
case 176400:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_176400;
+ aes3 = IEC958_AES3_CON_FS_176400;
break;
case 192000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_192000;
+ aes3 = IEC958_AES3_CON_FS_192000;
break;
case 8000:
case 11025:
case 16000:
case 64000:
- ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_NOTID;
+ aes3 = IEC958_AES3_CON_FS_NOTID;
break;
default:
dev_err(dev->dev, "unsupported sample frequency: %u\n",
params_rate(params));
- spin_unlock_irqrestore(&ctrl->lock, flags);
return -EINVAL;
}
+ spin_lock_irqsave(&ctrl->lock, flags);
+ ctrl->ch_stat[3] &= ~IEC958_AES3_CON_FS;
+ ctrl->ch_stat[3] |= aes3;
mchp_spdiftx_channel_status_write(dev);
spin_unlock_irqrestore(&ctrl->lock, flags);
- if (dev->gclk_enabled) {
- clk_disable_unprepare(dev->gclk);
- dev->gclk_enabled = 0;
- }
+ /* GCLK is enabled by runtime PM. */
+ clk_disable_unprepare(dev->gclk);
+
ret = clk_set_rate(dev->gclk, params_rate(params) *
SPDIFTX_GCLK_RATIO);
if (ret) {
@@ -502,14 +513,10 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
dev_err(dev->dev, "unable to enable gclk: %d\n", ret);
return ret;
}
- dev->gclk_enabled = 1;
+
dev_dbg(dev->dev, "%s(): GCLK set to %d\n", __func__,
params_rate(params) * SPDIFTX_GCLK_RATIO);
- /* Enable interrupts */
- regmap_write(dev->regmap, SPDIFTX_IER,
- SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
-
regmap_write(dev->regmap, SPDIFTX_MR, mr);
return 0;
@@ -520,13 +527,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream,
{
struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
- regmap_write(dev->regmap, SPDIFTX_IDR,
- SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
- if (dev->gclk_enabled) {
- clk_disable_unprepare(dev->gclk);
- dev->gclk_enabled = 0;
- }
-
return regmap_write(dev->regmap, SPDIFTX_CR,
SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR);
}
@@ -708,17 +708,9 @@ static struct snd_kcontrol_new mchp_spdiftx_ctrls[] = {
static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
{
struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
- int ret;
snd_soc_dai_init_dma_data(dai, &dev->playback, NULL);
- ret = clk_prepare_enable(dev->pclk);
- if (ret) {
- dev_err(dev->dev,
- "failed to enable the peripheral clock: %d\n", ret);
- return ret;
- }
-
/* Add controls */
snd_soc_add_dai_controls(dai, mchp_spdiftx_ctrls,
ARRAY_SIZE(mchp_spdiftx_ctrls));
@@ -726,19 +718,9 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static int mchp_spdiftx_dai_remove(struct snd_soc_dai *dai)
-{
- struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
-
- clk_disable_unprepare(dev->pclk);
-
- return 0;
-}
-
static struct snd_soc_dai_driver mchp_spdiftx_dai = {
.name = "mchp-spdiftx",
.probe = mchp_spdiftx_dai_probe,
- .remove = mchp_spdiftx_dai_remove,
.playback = {
.stream_name = "S/PDIF Playback",
.channels_min = 1,
@@ -762,6 +744,55 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids);
+static int mchp_spdiftx_runtime_suspend(struct device *dev)
+{
+ struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev);
+
+ regcache_cache_only(spdiftx->regmap, true);
+
+ clk_disable_unprepare(spdiftx->gclk);
+ clk_disable_unprepare(spdiftx->pclk);
+
+ return 0;
+}
+
+static int mchp_spdiftx_runtime_resume(struct device *dev)
+{
+ struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(spdiftx->pclk);
+ if (ret) {
+ dev_err(spdiftx->dev,
+ "failed to enable the peripheral clock: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(spdiftx->gclk);
+ if (ret) {
+ dev_err(spdiftx->dev,
+ "failed to enable generic clock: %d\n", ret);
+ goto disable_pclk;
+ }
+
+ regcache_cache_only(spdiftx->regmap, false);
+ regcache_mark_dirty(spdiftx->regmap);
+ ret = regcache_sync(spdiftx->regmap);
+ if (ret) {
+ regcache_cache_only(spdiftx->regmap, true);
+ clk_disable_unprepare(spdiftx->gclk);
+disable_pclk:
+ clk_disable_unprepare(spdiftx->pclk);
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops mchp_spdiftx_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(mchp_spdiftx_runtime_suspend, mchp_spdiftx_runtime_resume,
+ NULL)
+};
+
static int mchp_spdiftx_probe(struct platform_device *pdev)
{
struct mchp_spdiftx_dev *dev;
@@ -826,29 +857,59 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
+ pm_runtime_enable(dev->dev);
+ if (!pm_runtime_enabled(dev->dev)) {
+ err = mchp_spdiftx_runtime_resume(dev->dev);
+ if (err)
+ return err;
+ }
+
dev->playback.addr = (dma_addr_t)mem->start + SPDIFTX_CDR;
dev->playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (err) {
dev_err(&pdev->dev, "failed to register PMC: %d\n", err);
- return err;
+ goto pm_runtime_suspend;
}
err = devm_snd_soc_register_component(&pdev->dev,
&mchp_spdiftx_component,
&mchp_spdiftx_dai, 1);
- if (err)
+ if (err) {
dev_err(&pdev->dev, "failed to register component: %d\n", err);
+ goto pm_runtime_suspend;
+ }
+
+ return 0;
+
+pm_runtime_suspend:
+ if (!pm_runtime_status_suspended(dev->dev))
+ mchp_spdiftx_runtime_suspend(dev->dev);
+ pm_runtime_disable(dev->dev);
return err;
}
+static int mchp_spdiftx_remove(struct platform_device *pdev)
+{
+ struct mchp_spdiftx_dev *dev = platform_get_drvdata(pdev);
+
+ if (!pm_runtime_status_suspended(dev->dev))
+ mchp_spdiftx_runtime_suspend(dev->dev);
+
+ pm_runtime_disable(dev->dev);
+
+ return 0;
+}
+
static struct platform_driver mchp_spdiftx_driver = {
.probe = mchp_spdiftx_probe,
+ .remove = mchp_spdiftx_remove,
.driver = {
.name = "mchp_spdiftx",
.of_match_table = of_match_ptr(mchp_spdiftx_dt_ids),
+ .pm = pm_ptr(&mchp_spdiftx_pm_ops)
},
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7022e6286e6c..0f9d71490075 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -199,6 +199,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
+ imply SND_SOC_RT1318_SDW
imply SND_SOC_RT9120
imply SND_SOC_SDW_MOCKUP
imply SND_SOC_SGTL5000
@@ -348,7 +349,7 @@ config SND_SOC_WM_HUBS
config SND_SOC_WM_ADSP
tristate
- select CS_DSP
+ select FW_CS_DSP
select SND_SOC_COMPRESS
default y if SND_SOC_MADERA=y
default y if SND_SOC_CS47L24=y
@@ -1311,6 +1312,11 @@ config SND_SOC_RT1316_SDW
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1318_SDW
+ tristate "Realtek RT1318 Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
config SND_SOC_RT5514
tristate
depends on I2C
@@ -1930,7 +1936,7 @@ config SND_SOC_WM8960
depends on I2C
config SND_SOC_WM8961
- tristate
+ tristate "Wolfson Microelectronics WM8961 CODEC"
depends on I2C
config SND_SOC_WM8962
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 9170ee1447dd..71d3ce5867e4 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -196,6 +196,7 @@ snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
snd-soc-rt1308-sdw-objs := rt1308-sdw.o
snd-soc-rt1316-sdw-objs := rt1316-sdw.o
+snd-soc-rt1318-sdw-objs := rt1318-sdw.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
@@ -551,6 +552,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index a9f89e8565ec..d9bde7eb043a 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -8,7 +8,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gcd.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -25,7 +24,6 @@
#include "adau-utils.h"
struct adau1372 {
- struct clk *clk;
struct regmap *regmap;
void (*switch_mode)(struct device *dev);
bool use_pll;
@@ -207,10 +205,10 @@ static const struct snd_kcontrol_new adau1372_controls[] = {
2, 1, 0, adau1372_pga_boost_tlv),
SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
3, 1, 0, adau1372_pga_boost_tlv),
- SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1),
- SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1),
- SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1),
- SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1),
+ SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 0),
+ SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 0),
+ SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 0),
+ SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 0),
SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0),
0, 0xff, 1, adau1372_digital_tlv),
@@ -370,10 +368,10 @@ static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0),
- SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0),
- SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0),
- SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0),
- SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 1, NULL, 0),
SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0),
SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0),
SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0),
@@ -663,6 +661,7 @@ static int adau1372_hw_params(struct snd_pcm_substream *substream,
case 16:
sai1 = ADAU1372_SAI1_BCLKRATE;
break;
+ case 24:
case 32:
sai1 = 0;
break;
@@ -700,6 +699,7 @@ static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
case 16:
sai1 = ADAU1372_SAI1_BCLK_TDMC;
break;
+ case 24:
case 32:
sai1 = 0;
break;
@@ -870,7 +870,9 @@ static const struct snd_soc_dai_ops adau1372_dai_ops = {
.startup = adau1372_startup,
};
-#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver adau1372_dai_driver = {
.name = "adau1372",
@@ -925,9 +927,9 @@ int adau1372_probe(struct device *dev, struct regmap *regmap,
if (!adau1372)
return -ENOMEM;
- adau1372->clk = devm_clk_get(dev, "mclk");
- if (IS_ERR(adau1372->clk))
- return PTR_ERR(adau1372->clk);
+ adau1372->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(adau1372->mclk))
+ return PTR_ERR(adau1372->mclk);
adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
if (IS_ERR(adau1372->pd_gpio))
@@ -947,7 +949,7 @@ int adau1372_probe(struct device *dev, struct regmap *regmap,
* 12.288MHz. Automatically choose a valid configuration from the
* external clock.
*/
- rate = clk_get_rate(adau1372->clk);
+ rate = clk_get_rate(adau1372->mclk);
switch (rate) {
case 12288000:
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 7f832d00ab17..37e178e8a1d0 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -12,7 +12,6 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/gcd.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index c0f44ecef606..634d4dbca5ec 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -16,7 +16,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <linux/gcd.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 1db73552c746..8c69c8cf9b67 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -13,6 +13,7 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
@@ -46,6 +47,7 @@ struct ak4458_priv {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpiod;
+ struct reset_control *reset;
struct gpio_desc *mute_gpiod;
int digfil; /* SSLOW, SD, SLOW bits */
int fs; /* sampling rate */
@@ -633,6 +635,12 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
if (ak4458->reset_gpiod) {
gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
usleep_range(1000, 2000);
+ } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+ if (active)
+ reset_control_assert(ak4458->reset);
+ else
+ reset_control_deassert(ak4458->reset);
+ usleep_range(1000, 2000);
}
}
@@ -668,7 +676,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
- ak4458_reset(ak4458, true);
ak4458_reset(ak4458, false);
regcache_cache_only(ak4458->regmap, false);
@@ -748,6 +755,10 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
ak4458->drvdata = of_device_get_match_data(&i2c->dev);
+ ak4458->reset = devm_reset_control_get_optional_shared(ak4458->dev, NULL);
+ if (IS_ERR(ak4458->reset))
+ return PTR_ERR(ak4458->reset);
+
ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(ak4458->reset_gpiod))
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 31ae752e242f..a078dd422ea1 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -918,8 +918,8 @@ static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
fs1 = CS35L36_FS1_DEFAULT_VAL;
fs2 = CS35L36_FS2_DEFAULT_VAL;
} else {
- fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
- fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
+ fs1 = 3 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
+ fs2 = 5 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
}
regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 51721edd8f53..e88d9ff95cdf 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -143,7 +143,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
0, 0xA0, 96, adc_att_tlv),
SOC_DOUBLE_R_SX_TLV("PGA Volume",
CS42L51_ALC_PGA_CTL, CS42L51_ALC_PGB_CTL,
- 0, 0x19, 30, pga_tlv),
+ 0, 0x1A, 30, pga_tlv),
SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index f90d43996a51..37629ebd90e0 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -145,7 +145,7 @@ static const struct reg_default cs42l83_reg_defaults[] = {
* This is all the same as for CS42L42 but we
* replace the on-reset register defaults.
*/
-const struct regmap_config cs42l83_regmap = {
+static const struct regmap_config cs42l83_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index bd80e9fc907f..052ffb7dcfc6 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -12,15 +12,30 @@
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "cs42xx8.h"
+static const struct of_device_id cs42xx8_of_match[];
+
static int cs42xx8_i2c_probe(struct i2c_client *i2c)
{
- int ret = cs42xx8_probe(&i2c->dev,
- devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+ int ret;
+ struct cs42xx8_driver_data *drvdata;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(cs42xx8_of_match, &i2c->dev);
+ if (!of_id) {
+ dev_err(&i2c->dev, "failed to find driver data\n");
+ return -EINVAL;
+ }
+
+ drvdata = (struct cs42xx8_driver_data *)of_id->data;
+
+ ret = cs42xx8_probe(&i2c->dev,
+ devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config), drvdata);
if (ret)
return ret;
@@ -35,7 +50,14 @@ static void cs42xx8_i2c_remove(struct i2c_client *i2c)
pm_runtime_disable(&i2c->dev);
}
-static struct i2c_device_id cs42xx8_i2c_id[] = {
+static const struct of_device_id cs42xx8_of_match[] = {
+ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+
+static const struct i2c_device_id cs42xx8_i2c_id[] = {
{"cs42448", (kernel_ulong_t)&cs42448_data},
{"cs42888", (kernel_ulong_t)&cs42888_data},
{}
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index d14eb2f6e1dd..4558ec38a7ac 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -13,7 +13,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -511,17 +510,8 @@ const struct cs42xx8_driver_data cs42888_data = {
};
EXPORT_SYMBOL_GPL(cs42888_data);
-const struct of_device_id cs42xx8_of_match[] = {
- { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
- { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
-EXPORT_SYMBOL_GPL(cs42xx8_of_match);
-
-int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)
{
- const struct of_device_id *of_id;
struct cs42xx8_priv *cs42xx8;
int ret, val, i;
@@ -535,17 +525,11 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
if (cs42xx8 == NULL)
return -ENOMEM;
- cs42xx8->regmap = regmap;
dev_set_drvdata(dev, cs42xx8);
- of_id = of_match_device(cs42xx8_of_match, dev);
- if (of_id)
- cs42xx8->drvdata = of_id->data;
+ cs42xx8->regmap = regmap;
- if (!cs42xx8->drvdata) {
- dev_err(dev, "failed to find driver data\n");
- return -EINVAL;
- }
+ cs42xx8->drvdata = drvdata;
cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
index d36c61b6df74..342389e8b1a8 100644
--- a/sound/soc/codecs/cs42xx8.h
+++ b/sound/soc/codecs/cs42xx8.h
@@ -22,8 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm;
extern const struct cs42xx8_driver_data cs42448_data;
extern const struct cs42xx8_driver_data cs42888_data;
extern const struct regmap_config cs42xx8_regmap_config;
-extern const struct of_device_id cs42xx8_of_match[];
-int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata);
/* CS42888 register map */
#define CS42XX8_CHIPID 0x01 /* Chip ID */
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index bba73c44c219..c55b033d89da 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -43,7 +43,6 @@ void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jac
DA7219_ACCDET_EN_MASK,
(jack ? DA7219_ACCDET_EN_MASK : 0));
}
-EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
/*
* Button/HPTest work
@@ -352,9 +351,14 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
u8 events[DA7219_AAD_IRQ_REG_MAX];
- u8 statusa;
+ u8 statusa, srm_st;
int i, report = 0, mask = 0;
+ srm_st = snd_soc_component_read(component, DA7219_PLL_SRM_STS) & DA7219_PLL_SRM_STS_MCLK;
+ msleep(da7219_aad->gnd_switch_delay * ((srm_st == 0x0) ? 2 : 1) - 4);
+ /* Enable ground switch */
+ snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
+
/* Read current IRQ events */
regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
events, DA7219_AAD_IRQ_REG_MAX);
@@ -454,8 +458,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
snd_soc_dapm_disable_pin(dapm, "Mic Bias");
snd_soc_dapm_sync(dapm);
- /* Enable ground switch */
- snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
+ /* Disable ground switch */
+ snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
}
}
@@ -831,6 +835,32 @@ static void da7219_aad_handle_pdata(struct snd_soc_component *component)
}
}
+static void da7219_aad_handle_gnd_switch_time(struct snd_soc_component *component)
+{
+ struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+ struct da7219_aad_priv *da7219_aad = da7219->aad;
+ u8 jack_det;
+
+ jack_det = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_2)
+ & DA7219_JACK_DETECT_RATE_MASK;
+ switch (jack_det) {
+ case 0x00:
+ da7219_aad->gnd_switch_delay = 32;
+ break;
+ case 0x10:
+ da7219_aad->gnd_switch_delay = 64;
+ break;
+ case 0x20:
+ da7219_aad->gnd_switch_delay = 128;
+ break;
+ case 0x30:
+ da7219_aad->gnd_switch_delay = 256;
+ break;
+ default:
+ da7219_aad->gnd_switch_delay = 32;
+ break;
+ }
+}
/*
* Suspend/Resume
@@ -908,9 +938,6 @@ int da7219_aad_init(struct snd_soc_component *component)
snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
DA7219_BUTTON_CONFIG_MASK, 0);
- /* Enable ground switch */
- snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
-
INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
@@ -928,9 +955,10 @@ int da7219_aad_init(struct snd_soc_component *component)
regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
&mask, DA7219_AAD_IRQ_REG_MAX);
+ da7219_aad_handle_gnd_switch_time(component);
+
return 0;
}
-EXPORT_SYMBOL_GPL(da7219_aad_init);
void da7219_aad_exit(struct snd_soc_component *component)
{
@@ -948,7 +976,6 @@ void da7219_aad_exit(struct snd_soc_component *component)
cancel_work_sync(&da7219_aad->btn_det_work);
cancel_work_sync(&da7219_aad->hptest_work);
}
-EXPORT_SYMBOL_GPL(da7219_aad_exit);
/*
* AAD related I2C probe handling
@@ -972,7 +999,6 @@ int da7219_aad_probe(struct i2c_client *i2c)
return 0;
}
-EXPORT_SYMBOL_GPL(da7219_aad_probe);
MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
index f48a12012ef3..21fdf53095cc 100644
--- a/sound/soc/codecs/da7219-aad.h
+++ b/sound/soc/codecs/da7219-aad.h
@@ -187,6 +187,7 @@ enum da7219_aad_event_regs {
struct da7219_aad_priv {
struct snd_soc_component *component;
int irq;
+ int gnd_switch_delay;
u8 micbias_pulse_lvl;
u32 micbias_pulse_time;
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 4746c8700451..7468ee4af2ea 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2633,11 +2633,20 @@ static int da7219_resume(struct snd_soc_component *component)
#define da7219_resume NULL
#endif
+static int da7219_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack,
+ void *data)
+{
+ da7219_aad_jack_det(component, jack);
+
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_component_dev_da7219 = {
.probe = da7219_probe,
.remove = da7219_remove,
.suspend = da7219_suspend,
.resume = da7219_resume,
+ .set_jack = da7219_set_jack,
.set_bias_level = da7219_set_bias_level,
.controls = da7219_snd_controls,
.num_controls = ARRAY_SIZE(da7219_snd_controls),
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 87c1cc16592b..9ddf6a35e91c 100755
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -814,8 +814,7 @@ static const struct snd_soc_component_driver soc_component_dev_es8326 = {
.endianness = 1,
};
-static int es8326_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int es8326_i2c_probe(struct i2c_client *i2c)
{
struct es8326_priv *es8326;
int ret;
@@ -895,7 +894,7 @@ static struct i2c_driver es8326_i2c_driver = {
.acpi_match_table = ACPI_PTR(es8326_acpi_match),
.of_match_table = of_match_ptr(es8326_of_match),
},
- .probe = es8326_i2c_probe,
+ .probe_new = es8326_i2c_probe,
.id_table = es8326_i2c_id,
};
module_i2c_driver(es8326_i2c_driver);
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index 61e8e9be6b8d..4b8ec6f77337 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -130,10 +130,8 @@ static void hda_codec_unregister_dais(struct hda_codec *codec,
if (strcmp(dai->driver->name, pcm->name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
break;
}
@@ -181,7 +179,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
!pm_runtime_status_suspended(&hdev->dev));
#endif
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -213,7 +211,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
patch = (hda_codec_patch_t)codec->preset->driver_data;
if (!patch) {
- dev_err(&hdev->dev, "no patch specified?\n");
+ dev_err(&hdev->dev, "no patch specified\n");
ret = -EINVAL;
goto err;
}
@@ -289,7 +287,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
if (hda_codec_is_display(codec))
snd_hdac_display_power(bus, hdev->addr, false);
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (hlink)
snd_hdac_ext_bus_link_put(bus, hlink);
/*
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 8af434e14bfb..be66853afbe2 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -400,7 +400,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
hda_codec_patch_t patch;
int ret;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -516,7 +516,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
struct hda_codec *codec = hda_pvt->codec;
struct hdac_ext_link *hlink = NULL;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return;
@@ -584,7 +584,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
int ret;
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h
index fc19c34ca00e..b65560981abb 100644
--- a/sound/soc/codecs/hdac_hda.h
+++ b/sound/soc/codecs/hdac_hda.h
@@ -14,7 +14,7 @@ enum {
HDAC_HDMI_1_DAI_ID,
HDAC_HDMI_2_DAI_ID,
HDAC_HDMI_3_DAI_ID,
- HDAC_LAST_DAI_ID = HDAC_HDMI_3_DAI_ID,
+ HDAC_DAI_ID_NUM
};
struct hdac_hda_pcm {
@@ -24,7 +24,7 @@ struct hdac_hda_pcm {
struct hdac_hda_priv {
struct hda_codec *codec;
- struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID];
+ struct hdac_hda_pcm pcm[HDAC_DAI_ID_NUM];
bool need_display_power;
};
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index cb23650ad522..ed4f7cdda04f 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1967,7 +1967,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
* hold the ref while we probe, also no need to drop the ref on
* exit, we call pm_runtime_suspend() so that will do for us
*/
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2144,7 +2144,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2244,7 +2244,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D3);
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
@@ -2270,7 +2270,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
if (!bus)
return 0;
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 0b1cdb2d6049..74cbbe16f9ae 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -816,12 +816,19 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
.source = "RX",
},
};
- int ret;
+ int ret, i;
dapm = snd_soc_component_get_dapm(dai->component);
- ret = snd_soc_dapm_add_routes(dapm, route, 2);
- if (ret)
- return ret;
+
+ /* One of the directions might be omitted for unidirectional DAIs */
+ for (i = 0; i < ARRAY_SIZE(route); i++) {
+ if (!route[i].source || !route[i].sink)
+ continue;
+
+ ret = snd_soc_dapm_add_routes(dapm, &route[i], 1);
+ if (ret)
+ return ret;
+ }
daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL);
if (!daifmt)
@@ -1009,11 +1016,24 @@ static int hdmi_codec_probe(struct platform_device *pdev)
if (hcd->i2s) {
daidrv[i] = hdmi_i2s_dai;
daidrv[i].playback.channels_max = hcd->max_i2s_channels;
+ if (hcd->no_i2s_playback)
+ memset(&daidrv[i].playback, 0,
+ sizeof(daidrv[i].playback));
+ if (hcd->no_i2s_capture)
+ memset(&daidrv[i].capture, 0,
+ sizeof(daidrv[i].capture));
i++;
}
- if (hcd->spdif)
+ if (hcd->spdif) {
daidrv[i] = hdmi_spdif_dai;
+ if (hcd->no_spdif_playback)
+ memset(&daidrv[i].playback, 0,
+ sizeof(daidrv[i].playback));
+ if (hcd->no_spdif_capture)
+ memset(&daidrv[i].capture, 0,
+ sizeof(daidrv[i].capture));
+ }
dev_set_drvdata(dev, hcp);
diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c
index 71ea576f7e67..39cebaa167be 100644
--- a/sound/soc/codecs/jz4725b.c
+++ b/sound/soc/codecs/jz4725b.c
@@ -136,6 +136,24 @@ enum {
#define REG_CGR3_GO1L_OFFSET 0
#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET)
+#define REG_CGR4_GO2R_OFFSET 0
+#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET)
+
+#define REG_CGR5_GO2L_OFFSET 0
+#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET)
+
+#define REG_CGR6_GO3R_OFFSET 0
+#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET)
+
+#define REG_CGR7_GO3L_OFFSET 0
+#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET)
+
+#define REG_CGR8_GOR_OFFSET 0
+#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET)
+
+#define REG_CGR9_GOL_OFFSET 0
+#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET)
+
#define REG_CGR10_GIL_OFFSET 0
#define REG_CGR10_GIR_OFFSET 4
@@ -147,9 +165,28 @@ struct jz_icdc {
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0),
+ 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0),
+ 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0),
+ 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
+
+static const char * const jz4725b_mic_mode_texts[] = {
+ "Single Ended", "Differential",
+};
+
+static const struct soc_enum jz4725b_mic_mode_enum =
+ SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET,
+ 2, jz4725b_mic_mode_texts);
static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
- SOC_DOUBLE_TLV("Master Playback Volume",
+ SOC_DOUBLE_TLV("DAC Playback Volume",
JZ4725B_CODEC_REG_CGR1,
REG_CGR1_GODL_OFFSET,
REG_CGR1_GODR_OFFSET,
@@ -159,8 +196,29 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
REG_CGR10_GIL_OFFSET,
REG_CGR10_GIR_OFFSET,
0xf, 0, jz4725b_adc_tlv),
-
- SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
+ SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR3,
+ JZ4725B_CODEC_REG_CGR2,
+ REG_CGR2_GO1R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR5,
+ JZ4725B_CODEC_REG_CGR4,
+ REG_CGR4_GO2R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR7,
+ JZ4725B_CODEC_REG_CGR6,
+ REG_CGR6_GO3R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+
+ SOC_DOUBLE_R_TLV("Master Playback Volume",
+ JZ4725B_CODEC_REG_CGR9,
+ JZ4725B_CODEC_REG_CGR8,
+ REG_CGR8_GOR_OFFSET,
+ 0x1f, 1, jz4725b_out_tlv),
+
+ SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_DAC_MUTE_OFFSET, 1, 1),
SOC_SINGLE("Deemphasize Filter Playback Switch",
@@ -170,6 +228,13 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
SOC_SINGLE("High-Pass Filter Capture Switch",
JZ4725B_CODEC_REG_CR2,
REG_CR2_ADC_HPF_OFFSET, 1, 0),
+
+ SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum),
+
+ SOC_SINGLE_TLV("Mic1 Boost Capture Volume",
+ JZ4725B_CODEC_REG_PMR2,
+ REG_PMR2_GIM_OFFSET,
+ 1, 0, jz4725b_mic_boost_tlv),
};
static const char * const jz4725b_codec_adc_src_texts[] = {
@@ -186,8 +251,12 @@ static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
+ SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_BYPASS_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE1_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE2_OFFSET, 1, 0),
};
static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
@@ -282,7 +351,9 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
{"Line In", NULL, "LLINEIN"},
{"Line In", NULL, "RLINEIN"},
- {"Mixer", "Line In Bypass", "Line In"},
+ {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"},
+ {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"},
+ {"Mixer", "Line In Bypass Playback Switch", "Line In"},
{"DAC to Mixer", NULL, "DAC"},
{"Mixer", NULL, "DAC to Mixer"},
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index ee15cf6b98bb..2ef62d6edc30 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -46,6 +46,7 @@
#define CDC_TX_TOP_CSR_SWR_AMIC1_CTL (0x00D4)
#define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n) (0x0100 + 0x8 * n)
#define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0)
+#define CDC_TX_MACRO_DMIC_MUX_SEL_MASK GENMASK(7, 4)
#define CDC_TX_INP_MUX_ADC_MUX0_CFG0 (0x0100)
#define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n) (0x0104 + 0x8 * n)
#define CDC_TX_INP_MUX_ADC_MUX0_CFG1 (0x0104)
@@ -774,7 +775,10 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
}
if (val != 0) {
- if (val < 5) {
+ if (widget->shift) { /* MSM DMIC */
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+ } else if (val < 5) {
snd_soc_component_write_field(component, mic_sel_reg,
CDC_TXn_ADC_DMIC_SEL_MASK, 0);
} else {
@@ -1272,6 +1276,52 @@ static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6"
static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const char * const dmic_mux_text[] = {
+ "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+ "DMIC4", "DMIC5", "DMIC6", "DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+ 4, dmic_mux_text);
+
+static const struct snd_kcontrol_new tx_dmic0_mux = SOC_DAPM_ENUM_EXT("tx_dmic0", tx_dmic0_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic1_mux = SOC_DAPM_ENUM_EXT("tx_dmic1", tx_dmic1_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic2_mux = SOC_DAPM_ENUM_EXT("tx_dmic2", tx_dmic2_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic3_mux = SOC_DAPM_ENUM_EXT("tx_dmic3", tx_dmic3_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic4_mux = SOC_DAPM_ENUM_EXT("tx_dmic4", tx_dmic4_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic5_mux = SOC_DAPM_ENUM_EXT("tx_dmic5", tx_dmic5_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic6_mux = SOC_DAPM_ENUM_EXT("tx_dmic6", tx_dmic6_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic7_mux = SOC_DAPM_ENUM_EXT("tx_dmic7", tx_dmic7_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
static const char * const dec_mode_mux_text[] = {
"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
};
@@ -1380,6 +1430,15 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX0", SND_SOC_NOPM, 4, 0, &tx_dmic0_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX1", SND_SOC_NOPM, 4, 0, &tx_dmic1_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX2", SND_SOC_NOPM, 4, 0, &tx_dmic2_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX3", SND_SOC_NOPM, 4, 0, &tx_dmic3_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX4", SND_SOC_NOPM, 4, 0, &tx_dmic4_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX5", SND_SOC_NOPM, 4, 0, &tx_dmic5_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX6", SND_SOC_NOPM, 4, 0, &tx_dmic6_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX7", SND_SOC_NOPM, 4, 0, &tx_dmic7_mux),
+
SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
@@ -1392,6 +1451,14 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+ SND_SOC_DAPM_INPUT("TX DMIC0"),
+ SND_SOC_DAPM_INPUT("TX DMIC1"),
+ SND_SOC_DAPM_INPUT("TX DMIC2"),
+ SND_SOC_DAPM_INPUT("TX DMIC3"),
+ SND_SOC_DAPM_INPUT("TX DMIC4"),
+ SND_SOC_DAPM_INPUT("TX DMIC5"),
+ SND_SOC_DAPM_INPUT("TX DMIC6"),
+ SND_SOC_DAPM_INPUT("TX DMIC7"),
SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
TX_MACRO_DEC0, 0,
@@ -1495,6 +1562,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX DEC6 MUX", NULL, "TX_MCLK"},
{"TX DEC7 MUX", NULL, "TX_MCLK"},
+ {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"},
+ {"TX DMIC MUX0", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX0", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX0", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX0", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX0", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX0", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX0", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
+
{"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
{"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
@@ -1510,6 +1587,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
+ {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
+
{"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
{"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
@@ -1525,6 +1612,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
+ {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
+
{"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
{"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
@@ -1540,6 +1637,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
+ {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
+
{"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
{"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
@@ -1555,6 +1662,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
+ {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
+
{"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
{"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
@@ -1570,6 +1687,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
+ {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
+
{"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
{"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
@@ -1585,6 +1712,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
+ {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
+
{"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
{"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
@@ -1600,6 +1737,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
+ {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
+
{"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
{"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 5e0abefe7cce..5cfe96f6e430 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_clk.h>
@@ -2350,14 +2351,15 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
{
struct device *dev = wsa->dev;
const char *parent_clk_name;
- const char *clk_name = "mclk";
struct clk_hw *hw;
struct clk_init_data init;
int ret;
parent_clk_name = __clk_get_name(wsa->npl);
- init.name = clk_name;
+ init.name = "mclk";
+ of_property_read_string(dev_of_node(dev), "clock-output-names",
+ &init.name);
init.ops = &swclk_gate_ops;
init.flags = 0;
init.parent_names = &parent_clk_name;
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 3e04c7f0cce4..ec0905df65d1 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -549,6 +549,10 @@ static int max98373_i2c_probe(struct i2c_client *i2c)
max98373->cache = devm_kcalloc(&i2c->dev, max98373->cache_num,
sizeof(*max98373->cache),
GFP_KERNEL);
+ if (!max98373->cache) {
+ ret = -ENOMEM;
+ return ret;
+ }
for (i = 0; i < max98373->cache_num; i++)
max98373->cache[i].reg = max98373_i2c_cache_reg[i];
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 899965b19d12..3cd1be743d9e 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <linux/of.h>
@@ -533,10 +534,8 @@ static int max98373_sdw_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct max98373_priv *max98373 =
snd_soc_component_get_drvdata(component);
-
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
int ret, chan_sz, sampling_rate;
@@ -548,28 +547,20 @@ static int max98373_sdw_dai_hw_params(struct snd_pcm_substream *substream,
if (!max98373->slave)
return -EINVAL;
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
port_config.num = 1;
+
+ if (max98373->slot) {
+ stream_config.ch_count = max98373->slot;
+ port_config.ch_mask = max98373->rx_mask;
+ }
} else {
- direction = SDW_DATA_DIR_TX;
port_config.num = 3;
- }
- stream_config.frame_rate = params_rate(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- if (max98373->slot && direction == SDW_DATA_DIR_RX) {
- stream_config.ch_count = max98373->slot;
- port_config.ch_mask = max98373->rx_mask;
- } else {
/* only IV are supported by capture */
- if (direction == SDW_DATA_DIR_TX)
- stream_config.ch_count = 2;
- else
- stream_config.ch_count = params_channels(params);
-
+ stream_config.ch_count = 2;
port_config.ch_mask = GENMASK((int)stream_config.ch_count - 1, 0);
}
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index a7b6a23f2cd8..db3de41f10e0 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1731,9 +1731,9 @@ static void max98396_supply_disable(void *r)
regulator_disable((struct regulator *) r);
}
-static int max98396_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int max98396_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct max98396_priv *max98396 = NULL;
int i, ret, reg;
@@ -1907,7 +1907,7 @@ static struct i2c_driver max98396_i2c_driver = {
.acpi_match_table = ACPI_PTR(max98396_acpi_match),
.pm = &max98396_pm,
},
- .probe = max98396_i2c_probe,
+ .probe_new = max98396_i2c_probe,
.id_table = max98396_i2c_id,
};
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 6d2941a9dbd6..e161ab037bf7 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -323,7 +323,7 @@ static int max9867_startup(struct snd_pcm_substream *substream,
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- int value;
+ int value, freq = 0;
unsigned long int rate, ratio;
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
@@ -373,6 +373,35 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
MAX9867_IFC1B_BCLK_MASK, value);
+
+ /* Exact integer mode available for 8kHz and 16kHz sample rates
+ * and certain PCLK (prescaled MCLK) values.
+ */
+ if (params_rate(params) == 8000 ||
+ params_rate(params) == 16000) {
+ switch (max9867->pclk) {
+ case 12000000:
+ freq = 0x08;
+ break;
+ case 13000000:
+ freq = 0x0A;
+ break;
+ case 16000000:
+ freq = 0x0C;
+ break;
+ case 19200000:
+ freq = 0x0E;
+ break;
+ }
+ }
+ if (freq && params_rate(params) == 16000)
+ freq++;
+
+ /* If exact integer mode not available, the freq value
+ * remains zero, i.e. normal mode is used.
+ */
+ regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
+ MAX9867_FREQ_MASK, freq);
} else {
/*
* digital pll locks on to any externally supplied LRCLK signal
@@ -428,8 +457,6 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
freq);
max9867->sysclk = freq;
value = value << MAX9867_PSCLK_SHIFT;
- /* exact integer mode is not supported */
- value &= ~MAX9867_FREQ_MASK;
regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
MAX9867_PSCLK_MASK, value);
return 0;
diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c
index ad4dce9e5080..125742601f88 100644
--- a/sound/soc/codecs/nau8315.c
+++ b/sound/soc/codecs/nau8315.c
@@ -137,6 +137,7 @@ static int nau8315_platform_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id nau8315_device_id[] = {
{ .compatible = "nuvoton,nau8315" },
+ { .compatible = "nuvoton,nau8318" },
{}
};
MODULE_DEVICE_TABLE(of, nau8315_device_id);
@@ -145,6 +146,7 @@ MODULE_DEVICE_TABLE(of, nau8315_device_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id nau8315_acpi_match[] = {
{ "NVTN2010", 0 },
+ { "NVTN2012", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 3eac7c92df88..4bffa9c20f2b 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1686,6 +1686,9 @@ static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
/* Enable internal VCO needed for interruptions */
nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+ /* Raise up the internal clock for jack detection */
+ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+ NAU8825_CLK_MCLK_SRC_MASK, 0);
/* Enable ADC needed for interruptions */
regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
@@ -1733,6 +1736,121 @@ static int nau8825_button_decode(int value)
return buttons;
}
+static int nau8825_high_imped_detection(struct nau8825 *nau8825)
+{
+ struct regmap *regmap = nau8825->regmap;
+ struct snd_soc_dapm_context *dapm = nau8825->dapm;
+ unsigned int adc_mg1, adc_mg2;
+
+ /* Initial phase */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2);
+ regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+ NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+ regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0x6);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_LOWNOISE_MASK | NAU8825_MICBIAS_VOLTAGE_MASK,
+ NAU8825_MICBIAS_LOWNOISE_EN);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK | NAU8825_SAR_TRACKING_GAIN_MASK |
+ NAU8825_SAR_HV_SEL_MASK | NAU8825_SAR_RES_SEL_MASK |
+ NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+ NAU8825_SAR_HV_SEL_VDDMIC | NAU8825_SAR_RES_SEL_70K);
+
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin(dapm, "SAR");
+ snd_soc_dapm_sync(dapm);
+
+ /* Configure settings for first reading of SARADC */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND2);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKR2);
+ regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg1);
+
+ /* Configure settings for second reading of SARADC */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+ NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKSLV);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK, NAU8825_SAR_INPUT_JKSLV);
+ regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg2);
+
+ /* Disable phase */
+ snd_soc_dapm_disable_pin(dapm, "SAR");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
+
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_LOWNOISE_MASK |
+ NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+ NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+ regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+ NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+ regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_TRACKING_GAIN_MASK | NAU8825_SAR_HV_SEL_MASK,
+ nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+ (nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT) |
+ (nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT));
+ dev_dbg(nau8825->dev, "adc_mg1:%x, adc_mg2:%x\n", adc_mg1, adc_mg2);
+
+ /* Confirmation phase */
+ if (adc_mg1 > adc_mg2) {
+ dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n");
+
+ /* Unground MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+ NAU8825_SPKR_ENGND2);
+ /* Attach 2kOhm Resistor from MICBIAS to MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKR2);
+ /* Attach SARADC to MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK,
+ NAU8825_SAR_INPUT_JKR2);
+ } else if (adc_mg1 < adc_mg2) {
+ dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
+
+ /* Unground MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+ NAU8825_SPKR_ENGND1);
+ /* Attach 2kOhm Resistor from MICBIAS to MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKSLV);
+ /* Attach SARADC to MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK,
+ NAU8825_SAR_INPUT_JKSLV);
+ } else {
+ dev_err(nau8825->dev, "Jack broken.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nau8825_jack_insert(struct nau8825 *nau8825)
{
struct regmap *regmap = nau8825->regmap;
@@ -1794,12 +1912,23 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
snd_soc_dapm_sync(dapm);
break;
case 3:
- /* detect error case */
- dev_err(nau8825->dev, "detection error; disable mic function\n");
- type = SND_JACK_HEADPHONE;
+ /* Detection failure case */
+ dev_warn(nau8825->dev,
+ "Detection failure. Try the manually mechanism for jack type checking.\n");
+ if (!nau8825_high_imped_detection(nau8825)) {
+ type = SND_JACK_HEADSET;
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin(dapm, "SAR");
+ snd_soc_dapm_sync(dapm);
+ } else
+ type = SND_JACK_HEADPHONE;
break;
}
+ /* Update to the default divider of internal clock for power saving */
+ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+ NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+
/* Leaving HPOL/R grounded after jack insert by default. They will be
* ungrounded as part of the widget power up sequence at the beginning
* of playback to reduce pop.
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index d84191a7beb2..0c3a446e0e1a 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -155,6 +155,8 @@
/* HSD_CTRL (0xc) */
#define NAU8825_HSD_AUTO_MODE (1 << 6)
/* 0 - open, 1 - short to GND */
+#define NAU8825_SPKR_ENGND1 (1 << 3)
+#define NAU8825_SPKR_ENGND2 (1 << 2)
#define NAU8825_SPKR_DWN1R (1 << 1)
#define NAU8825_SPKR_DWN1L (1 << 0)
@@ -207,6 +209,17 @@
#define NAU8825_SAR_INPUT_JKR2 (0 << 11)
#define NAU8825_SAR_TRACKING_GAIN_SFT 8
#define NAU8825_SAR_TRACKING_GAIN_MASK (0x7 << NAU8825_SAR_TRACKING_GAIN_SFT)
+#define NAU8825_SAR_HV_SEL_SFT 7
+#define NAU8825_SAR_HV_SEL_MASK (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_MICBIAS (0 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_VDDMIC (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SFT 4
+#define NAU8825_SAR_RES_SEL_MASK (0x7 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_35K (0 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_70K (1 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_170K (2 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_360K (3 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SHORTED (4 << NAU8825_SAR_RES_SEL_SFT)
#define NAU8825_SAR_COMPARE_TIME_SFT 2
#define NAU8825_SAR_COMPARE_TIME_MASK (3 << 2)
#define NAU8825_SAR_SAMPLING_TIME_SFT 0
@@ -385,6 +398,13 @@
#define NAU8825_BIAS_VMID_SEL_SFT 4
#define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT)
+/* ANALOG_CONTROL_1 (0x69) */
+#define NAU8825_TESTDACIN_SFT 14
+#define NAU8825_TESTDACIN_MASK (0x3 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_HIGH (1 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_LOW (2 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_GND (3 << NAU8825_TESTDACIN_SFT)
+
/* ANALOG_CONTROL_2 (0x6a) */
#define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12)
#define NAU8825_DAC_CAPACITOR_MSB (1 << 1)
@@ -412,6 +432,9 @@
/* MIC_BIAS (0x74) */
#define NAU8825_MICBIAS_JKSLV (1 << 14)
#define NAU8825_MICBIAS_JKR2 (1 << 12)
+#define NAU8825_MICBIAS_LOWNOISE_SFT 10
+#define NAU8825_MICBIAS_LOWNOISE_MASK (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
+#define NAU8825_MICBIAS_LOWNOISE_EN (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
#define NAU8825_MICBIAS_POWERUP_SFT 8
#define NAU8825_MICBIAS_VOLTAGE_SFT 0
#define NAU8825_MICBIAS_VOLTAGE_MASK 0x7
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 767463e82665..89059a673cf0 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1634,7 +1634,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (val > 6) {
dev_err(dev, "Invalid pll-in\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
pcm512x->pll_in = val;
}
@@ -1643,7 +1643,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (val > 6) {
dev_err(dev, "Invalid pll-out\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
pcm512x->pll_out = val;
}
@@ -1652,12 +1652,12 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
dev_err(dev,
"Error: both pll-in and pll-out, or none\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
dev_err(dev, "Error: pll-in == pll-out\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
}
#endif
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index f99aed353f10..ca2790d63b71 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -17,6 +17,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -197,6 +198,17 @@ static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308)
efuse_c_btl_l, efuse_c_btl_r);
}
+static void rt1308_apply_bq_params(struct rt1308_sdw_priv *rt1308)
+{
+ unsigned int i, reg, data;
+
+ for (i = 0; i < rt1308->bq_params_cnt; i += 3) {
+ reg = rt1308->bq_params[i] | (rt1308->bq_params[i + 1] << 8);
+ data = rt1308->bq_params[i + 2];
+ regmap_write(rt1308->regmap, reg, data);
+ }
+}
+
static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
@@ -542,11 +554,10 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1308_sdw_priv *rt1308 =
snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels, ch_mask;
+ int retval;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
stream = snd_soc_dai_get_dma_data(dai, substream);
@@ -558,30 +569,19 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
/* port 1 for playback */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 1;
- } else {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
return -EINVAL;
- }
if (rt1308->slots) {
- num_channels = rt1308->slots;
- ch_mask = rt1308->rx_mask;
- } else {
- num_channels = params_channels(params);
- ch_mask = (1 << num_channels) - 1;
+ stream_config.ch_count = rt1308->slots;
+ port_config.ch_mask = rt1308->rx_mask;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = num_channels;
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- port_config.ch_mask = ch_mask;
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt1308->sdw_slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
@@ -619,14 +619,42 @@ static const struct sdw_slave_ops rt1308_slave_ops = {
.bus_config = rt1308_bus_config,
};
+static int rt1308_sdw_parse_dt(struct rt1308_sdw_priv *rt1308, struct device *dev)
+{
+ int ret = 0;
+
+ device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1308->bq_params_cnt);
+ if (rt1308->bq_params_cnt) {
+ rt1308->bq_params = devm_kzalloc(dev, rt1308->bq_params_cnt, GFP_KERNEL);
+ if (!rt1308->bq_params) {
+ dev_err(dev, "Could not allocate bq_params memory\n");
+ ret = -ENOMEM;
+ } else {
+ ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1308->bq_params, rt1308->bq_params_cnt);
+ if (ret < 0)
+ dev_err(dev, "Could not read list of realtek,bq-params\n");
+ }
+ }
+
+ dev_dbg(dev, "bq_params_cnt=%d\n", rt1308->bq_params_cnt);
+ return ret;
+}
+
static int rt1308_sdw_component_probe(struct snd_soc_component *component)
{
+ struct rt1308_sdw_priv *rt1308 = snd_soc_component_get_drvdata(component);
int ret;
+ rt1308->component = component;
+ rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
+ /* apply BQ params */
+ rt1308_apply_bq_params(rt1308);
+
return 0;
}
diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h
index 62ce27799307..1eaaef9f351b 100644
--- a/sound/soc/codecs/rt1308-sdw.h
+++ b/sound/soc/codecs/rt1308-sdw.h
@@ -166,6 +166,8 @@ struct rt1308_sdw_priv {
int rx_mask;
int slots;
int hw_ver;
+ unsigned char *bq_params;
+ unsigned int bq_params_cnt;
};
struct sdw_stream_data {
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ed0a11436362..e6294cc7a995 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -14,6 +14,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "rt1316-sdw.h"
@@ -254,6 +255,17 @@ static int rt1316_read_prop(struct sdw_slave *slave)
return 0;
}
+static void rt1316_apply_bq_params(struct rt1316_sdw_priv *rt1316)
+{
+ unsigned int i, reg, data;
+
+ for (i = 0; i < rt1316->bq_params_cnt; i += 3) {
+ reg = rt1316->bq_params[i] | (rt1316->bq_params[i + 1] << 8);
+ data = rt1316->bq_params[i + 2];
+ regmap_write(rt1316->regmap, reg, data);
+ }
+}
+
static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
@@ -519,11 +531,10 @@ static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1316_sdw_priv *rt1316 =
snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels, ch_mask;
+ int retval;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
stream = snd_soc_dai_get_dma_data(dai, substream);
@@ -535,25 +546,13 @@ static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
- /* port 1 for playback */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 1;
- } else {
- direction = SDW_DATA_DIR_TX;
- port = 2;
- }
-
- num_channels = params_channels(params);
- ch_mask = (1 << num_channels) - 1;
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = num_channels;
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- port_config.ch_mask = ch_mask;
- port_config.num = port;
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
+ port_config.num = 2;
retval = sdw_stream_add_slave(rt1316->sdw_slave, &stream_config,
&port_config, 1, stream->sdw_stream);
@@ -590,14 +589,42 @@ static struct sdw_slave_ops rt1316_slave_ops = {
.update_status = rt1316_update_status,
};
+static int rt1316_sdw_parse_dt(struct rt1316_sdw_priv *rt1316, struct device *dev)
+{
+ int ret = 0;
+
+ device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1316->bq_params_cnt);
+ if (rt1316->bq_params_cnt) {
+ rt1316->bq_params = devm_kzalloc(dev, rt1316->bq_params_cnt, GFP_KERNEL);
+ if (!rt1316->bq_params) {
+ dev_err(dev, "Could not allocate bq_params memory\n");
+ ret = -ENOMEM;
+ } else {
+ ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1316->bq_params, rt1316->bq_params_cnt);
+ if (ret < 0)
+ dev_err(dev, "Could not read list of realtek,bq-params\n");
+ }
+ }
+
+ dev_dbg(dev, "bq_params_cnt=%d\n", rt1316->bq_params_cnt);
+ return ret;
+}
+
static int rt1316_sdw_component_probe(struct snd_soc_component *component)
{
+ struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component);
int ret;
+ rt1316->component = component;
+ rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
+ /* apply BQ params */
+ rt1316_apply_bq_params(rt1316);
+
return 0;
}
diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h
index cbcdaa8f8cfa..57dbd49993b0 100644
--- a/sound/soc/codecs/rt1316-sdw.h
+++ b/sound/soc/codecs/rt1316-sdw.h
@@ -46,6 +46,8 @@ struct rt1316_sdw_priv {
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
+ unsigned char *bq_params;
+ unsigned int bq_params_cnt;
};
struct sdw_stream_data {
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
new file mode 100644
index 000000000000..f85f5ab2c6d0
--- /dev/null
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -0,0 +1,884 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318-sdw.c -- rt1318 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2022 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include "rt1318-sdw.h"
+
+static const struct reg_sequence rt1318_blind_write[] = {
+ { 0xc001, 0x43 },
+ { 0xc003, 0xa2 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc320, 0x20 },
+ { 0xf203, 0x18 },
+ { 0xf211, 0x00 },
+ { 0xf212, 0x26 },
+ { 0xf20d, 0x17 },
+ { 0xf214, 0x06 },
+ { 0xf20e, 0x00 },
+ { 0xf223, 0x7f },
+ { 0xf224, 0xdb },
+ { 0xf225, 0xee },
+ { 0xf226, 0x3f },
+ { 0xf227, 0x0f },
+ { 0xf21a, 0x78 },
+ { 0xf242, 0x3c },
+ { 0xc321, 0x0b },
+ { 0xc200, 0xd8 },
+ { 0xc201, 0x27 },
+ { 0xc202, 0x0f },
+ { 0xf800, 0x20 },
+ { 0xdf00, 0x10 },
+ { 0xdf5f, 0x01 },
+ { 0xdf60, 0xa7 },
+ { 0xc400, 0x0e },
+ { 0xc401, 0x43 },
+ { 0xc402, 0xe0 },
+ { 0xc403, 0x00 },
+ { 0xc404, 0x4c },
+ { 0xc407, 0x02 },
+ { 0xc408, 0x3f },
+ { 0xc300, 0x01 },
+ { 0xc206, 0x78 },
+ { 0xc203, 0x84 },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x03 },
+ { 0xe000, 0x88 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x01 },
+ { 0xe706, 0x0f },
+ { 0xe707, 0x30 },
+ { 0xe806, 0x0f },
+ { 0xe807, 0x30 },
+ { 0xed00, 0xb0 },
+ { 0xce04, 0x02 },
+ { 0xce05, 0x63 },
+ { 0xce06, 0x68 },
+ { 0xce07, 0x07 },
+ { 0xcf04, 0x02 },
+ { 0xcf05, 0x63 },
+ { 0xcf06, 0x68 },
+ { 0xcf07, 0x07 },
+ { 0xce60, 0xe3 },
+ { 0xc130, 0x51 },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x06 },
+ { 0xf109, 0x9b },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x0b },
+ { 0xf109, 0x03 },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x0c },
+ { 0xf109, 0x7f },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+
+ { 0xe604, 0x00 },
+ { 0xdb00, 0x0c },
+ { 0xdd00, 0x0c },
+ { 0xdc19, 0x00 },
+ { 0xdc1a, 0xff },
+ { 0xdc1b, 0xff },
+ { 0xdc1c, 0xff },
+ { 0xdc1d, 0x00 },
+ { 0xdc1e, 0x00 },
+ { 0xdc1f, 0x00 },
+ { 0xdc20, 0xff },
+ { 0xde19, 0x00 },
+ { 0xde1a, 0xff },
+ { 0xde1b, 0xff },
+ { 0xde1c, 0xff },
+ { 0xde1d, 0x00 },
+ { 0xde1e, 0x00 },
+ { 0xde1f, 0x00 },
+ { 0xde20, 0xff },
+ { 0xdb32, 0x00 },
+ { 0xdd32, 0x00 },
+ { 0xdb33, 0x0a },
+ { 0xdd33, 0x0a },
+ { 0xdb34, 0x1a },
+ { 0xdd34, 0x1a },
+ { 0xdb17, 0xef },
+ { 0xdd17, 0xef },
+ { 0xdba7, 0x00 },
+ { 0xdba8, 0x64 },
+ { 0xdda7, 0x00 },
+ { 0xdda8, 0x64 },
+ { 0xdb19, 0x40 },
+ { 0xdd19, 0x40 },
+ { 0xdb00, 0x4c },
+ { 0xdb01, 0x79 },
+ { 0xdd01, 0x79 },
+ { 0xdb04, 0x05 },
+ { 0xdb05, 0x03 },
+ { 0xdd04, 0x05 },
+ { 0xdd05, 0x03 },
+ { 0xdbbb, 0x09 },
+ { 0xdbbc, 0x30 },
+ { 0xdbbd, 0xf0 },
+ { 0xdbbe, 0xf1 },
+ { 0xddbb, 0x09 },
+ { 0xddbc, 0x30 },
+ { 0xddbd, 0xf0 },
+ { 0xddbe, 0xf1 },
+ { 0xdb01, 0x79 },
+ { 0xdd01, 0x79 },
+ { 0xdc52, 0xef },
+ { 0xde52, 0xef },
+ { 0x2f55, 0x22 },
+};
+
+static const struct reg_default rt1318_reg_defaults[] = {
+ { 0x3000, 0x00 },
+ { 0x3004, 0x01 },
+ { 0x3005, 0x23 },
+ { 0x3202, 0x00 },
+ { 0x3203, 0x01 },
+ { 0x3206, 0x00 },
+ { 0xc000, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc003, 0x22 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc008, 0x05 },
+ { 0xc00a, 0xfc },
+ { 0xc00b, 0x0f },
+ { 0xc00c, 0x0e },
+ { 0xc00d, 0xef },
+ { 0xc00e, 0xe5 },
+ { 0xc00f, 0xff },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x00 },
+ { 0xc122, 0x00 },
+ { 0xc123, 0x14 },
+ { 0xc125, 0x00 },
+ { 0xc200, 0x00 },
+ { 0xc201, 0x00 },
+ { 0xc202, 0x00 },
+ { 0xc203, 0x04 },
+ { 0xc204, 0x00 },
+ { 0xc205, 0x00 },
+ { 0xc206, 0x68 },
+ { 0xc207, 0x70 },
+ { 0xc208, 0x00 },
+ { 0xc20a, 0x00 },
+ { 0xc20b, 0x01 },
+ { 0xc20c, 0x7f },
+ { 0xc20d, 0x01 },
+ { 0xc20e, 0x7f },
+ { 0xc300, 0x00 },
+ { 0xc301, 0x00 },
+ { 0xc303, 0x80 },
+ { 0xc320, 0x00 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x02 },
+ { 0xc410, 0x04 },
+ { 0xc430, 0x00 },
+ { 0xc431, 0x00 },
+ { 0xca00, 0x10 },
+ { 0xca01, 0x00 },
+ { 0xca02, 0x0b },
+ { 0xca10, 0x10 },
+ { 0xca11, 0x00 },
+ { 0xca12, 0x0b },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
+ { 0xe300, 0xa0 },
+ { 0xed00, 0x80 },
+ { 0xed01, 0x0f },
+ { 0xed02, 0xff },
+ { 0xed03, 0x00 },
+ { 0xed04, 0x00 },
+ { 0xed05, 0x0f },
+ { 0xed06, 0xff },
+ { 0xf010, 0x10 },
+ { 0xf011, 0xec },
+ { 0xf012, 0x68 },
+ { 0xf013, 0x21 },
+ { 0xf800, 0x00 },
+ { 0xf801, 0x12 },
+ { 0xf802, 0xe0 },
+ { 0xf803, 0x2f },
+ { 0xf804, 0x00 },
+ { 0xf805, 0x00 },
+ { 0xf806, 0x07 },
+ { 0xf807, 0xff },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+};
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3000:
+ case 0x3004 ... 0x3005:
+ case 0x3202 ... 0x3203:
+ case 0x3206:
+ case 0xc000 ... 0xc00f:
+ case 0xc120 ... 0xc125:
+ case 0xc200 ... 0xc20e:
+ case 0xc300 ... 0xc303:
+ case 0xc320 ... 0xc322:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xca00 ... 0xca02:
+ case 0xca10 ... 0xca12:
+ case 0xcb00 ... 0xcb0b:
+ case 0xcc00 ... 0xcce5:
+ case 0xcd00 ... 0xcde5:
+ case 0xce00 ... 0xce6a:
+ case 0xcf00 ... 0xcf53:
+ case 0xd000 ... 0xd0cc:
+ case 0xd100 ... 0xd1b9:
+ case 0xdb00 ... 0xdc53:
+ case 0xdd00 ... 0xde53:
+ case 0xdf00 ... 0xdf6b:
+ case 0xe300:
+ case 0xeb00 ... 0xebcc:
+ case 0xec00 ... 0xecb9:
+ case 0xed00 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case 0xf800 ... 0xf807:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3000 ... 0x3001:
+ case 0xc000:
+ case 0xc301:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xdb06:
+ case 0xdb12:
+ case 0xdb1d ... 0xdb1f:
+ case 0xdb35:
+ case 0xdb37:
+ case 0xdb8a ... 0xdb92:
+ case 0xdbc5 ... 0xdbc8:
+ case 0xdc2b ... 0xdc49:
+ case 0xdd0b:
+ case 0xdd12:
+ case 0xdd1d ... 0xdd1f:
+ case 0xdd35:
+ case 0xdd8a ... 0xdd92:
+ case 0xddc5 ... 0xddc8:
+ case 0xde2b ... 0xde44:
+ case 0xdf4a ... 0xdf55:
+ case 0xe224 ... 0xe23b:
+ case 0xea01:
+ case 0xebc5:
+ case 0xebc8:
+ case 0xebcb ... 0xebcc:
+ case 0xed03 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt1318_sdw_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1318_readable_register,
+ .volatile_reg = rt1318_volatile_register,
+ .max_register = 0x41081488,
+ .reg_defaults = rt1318_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1318_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ prop->is_sdca = true;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = BIT(2);
+ prop->sink_ports = BIT(1);
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 20;
+
+ return 0;
+}
+
+static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+ if (rt1318->hw_init)
+ return 0;
+
+ if (rt1318->first_hw_init) {
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_cache_bypass(rt1318->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ /* blind write */
+ regmap_multi_reg_write(rt1318->regmap, rt1318_blind_write,
+ ARRAY_SIZE(rt1318_blind_write));
+
+ if (rt1318->first_hw_init) {
+ regcache_cache_bypass(rt1318->regmap, false);
+ regcache_mark_dirty(rt1318->regmap);
+ }
+
+ /* Mark Slave initialization complete */
+ rt1318->first_hw_init = true;
+ rt1318->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+static int rt1318_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt1318->status = status;
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1318->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1318_io_init(&slave->dev, slave);
+}
+
+static int rt1318_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const char * const rt1318_rx_data_ch_select[] = {
+ "L,R",
+ "L,L",
+ "L,R",
+ "L,L+R",
+ "R,L",
+ "R,R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1318_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
+ rt1318_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+
+ /* UDMPU Cluster Selection */
+ SOC_ENUM("RX Channel Select", rt1318_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1318_sto_dac =
+ SOC_DAPM_DOUBLE_R("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R),
+ 0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1318_sto_dac),
+
+ /* Output */
+ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1318_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ /* Input */
+ SND_SOC_DAPM_PGA("FB Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("FB Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+ { "DAC", "Switch", "DP1RX" },
+ { "CLASS D", NULL, "DAC" },
+ { "SPOL", NULL, "CLASS D" },
+ { "SPOR", NULL, "CLASS D" },
+
+ { "FB Data", NULL, "FB Gen" },
+ { "DP2TX", NULL, "FB Data" },
+};
+
+static int rt1318_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ struct sdw_stream_data *stream;
+
+ if (!sdw_stream)
+ return 0;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ stream->sdw_stream = sdw_stream;
+
+ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->playback_dma_data = stream;
+ else
+ dai->capture_dma_data = stream;
+
+ return 0;
+}
+
+static void rt1318_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_stream_data *stream;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(stream);
+}
+
+static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_sdw_priv *rt1318 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_data *stream;
+ int retval, port, num_channels, ch_mask;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!stream)
+ return -EINVAL;
+
+ if (!rt1318->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 1;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ port = 2;
+ }
+
+ num_channels = params_channels(params);
+ ch_mask = (1 << num_channels) - 1;
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = num_channels;
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ port_config.ch_mask = ch_mask;
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
+ &port_config, 1, stream->sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 16000:
+ sampling_rate = RT1318_SDCA_RATE_16000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT1318_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT1318_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1318_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1318_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1318_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_sdw_priv *rt1318 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_data *stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1318->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1318->sdw_slave, stream->sdw_stream);
+ return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static struct sdw_slave_ops rt1318_slave_ops = {
+ .read_prop = rt1318_read_prop,
+ .update_status = rt1318_update_status,
+};
+
+static int rt1318_sdw_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1318 = {
+ .probe = rt1318_sdw_component_probe,
+ .controls = rt1318_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1318_snd_controls),
+ .dapm_widgets = rt1318_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+ .dapm_routes = rt1318_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+ .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+ .hw_params = rt1318_sdw_hw_params,
+ .hw_free = rt1318_sdw_pcm_hw_free,
+ .set_stream = rt1318_set_sdw_stream,
+ .shutdown = rt1318_sdw_shutdown,
+};
+
+#define RT1318_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1318_sdw_dai[] = {
+ {
+ .name = "rt1318-aif",
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .ops = &rt1318_aif_dai_ops,
+ },
+};
+
+static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
+ struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318;
+ int ret;
+
+ rt1318 = devm_kzalloc(dev, sizeof(*rt1318), GFP_KERNEL);
+ if (!rt1318)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1318);
+ rt1318->sdw_slave = slave;
+ rt1318->regmap = regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1318->hw_init = false;
+ rt1318->first_hw_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_sdw_rt1318,
+ rt1318_sdw_dai,
+ ARRAY_SIZE(rt1318_sdw_dai));
+
+ dev_dbg(&slave->dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static int rt1318_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw(slave, &rt1318_sdw_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1318_sdw_init(&slave->dev, regmap, slave);
+}
+
+static int rt1318_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+ if (rt1318->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt1318_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1318, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1318_id);
+
+static int __maybe_unused rt1318_dev_suspend(struct device *dev)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+ if (!rt1318->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1318->regmap, true);
+ return 0;
+}
+
+#define RT1318_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1318_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt1318->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1318_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_sync(rt1318->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt1318_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
+ SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1318_sdw_driver = {
+ .driver = {
+ .name = "rt1318-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt1318_pm,
+ },
+ .probe = rt1318_sdw_probe,
+ .remove = rt1318_sdw_remove,
+ .ops = &rt1318_slave_ops,
+ .id_table = rt1318_id,
+};
+module_sdw_driver(rt1318_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h
new file mode 100644
index 000000000000..4d7ac9c4bd8d
--- /dev/null
+++ b/sound/soc/codecs/rt1318-sdw.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318-sdw.h -- RT1318 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2022 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1318_SDW_H__
+#define __RT1318_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* imp-defined registers */
+#define RT1318_SAPU_SM 0x3203
+
+#define R1318_TCON 0xc203
+#define R1318_TCON_RELATED_1 0xc206
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_0 0xdb00
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_4 0xdb08
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_4 0xdd08
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_6 0xdb12
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_6 0xdd12
+
+#define RT1318_INIT_RECIPROCAL_REG_L_24 0xdbb5
+#define RT1318_INIT_RECIPROCAL_REG_L_23_16 0xdbb6
+#define RT1318_INIT_RECIPROCAL_REG_L_15_8 0xdbb7
+#define RT1318_INIT_RECIPROCAL_REG_L_7_0 0xdbb8
+#define RT1318_INIT_RECIPROCAL_REG_R_24 0xddb5
+#define RT1318_INIT_RECIPROCAL_REG_R_23_16 0xddb6
+#define RT1318_INIT_RECIPROCAL_REG_R_15_8 0xddb7
+#define RT1318_INIT_RECIPROCAL_REG_R_7_0 0xddb8
+
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_24 0xdbc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_23_16 0xdbc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_15_8 0xdbc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_7_0 0xdbc8
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_24 0xddc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_23_16 0xddc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_15_8 0xddc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_7_0 0xddc8
+
+#define RT1318_R0_COMPARE_FLAG_L 0xdb35
+#define RT1318_R0_COMPARE_FLAG_R 0xdd35
+
+#define RT1318_STP_INITIAL_RS_TEMP_H 0xdd93
+#define RT1318_STP_INITIAL_RS_TEMP_L 0xdd94
+
+/* RT1318 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1318 SDCA entity */
+#define RT1318_SDCA_ENT_PDE23 0x31
+#define RT1318_SDCA_ENT_XU24 0x24
+#define RT1318_SDCA_ENT_FU21 0x03
+#define RT1318_SDCA_ENT_UDMPU21 0x02
+#define RT1318_SDCA_ENT_CS21 0x21
+#define RT1318_SDCA_ENT_SAPU 0x29
+
+/* RT1318 SDCA control */
+#define RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1318_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1318_SDCA_CTL_FU_MUTE 0x01
+#define RT1318_SDCA_CTL_FU_VOLUME 0x02
+#define RT1318_SDCA_CTL_UDMPU_CLUSTER 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+
+/* RT1318 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+
+/* sample frequency index */
+#define RT1318_SDCA_RATE_16000HZ 0x04
+#define RT1318_SDCA_RATE_32000HZ 0x07
+#define RT1318_SDCA_RATE_44100HZ 0x08
+#define RT1318_SDCA_RATE_48000HZ 0x09
+#define RT1318_SDCA_RATE_96000HZ 0x0b
+#define RT1318_SDCA_RATE_192000HZ 0x0d
+
+
+struct rt1318_sdw_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct sdw_slave *sdw_slave;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+};
+
+struct sdw_stream_data {
+ struct sdw_stream_runtime *sdw_stream;
+};
+
+#endif /* __RT1318_SDW_H__ */
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index a2ce52dafea8..cea26f3a02b6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
}
},
+ {
+ .ident = "Intel Kabylake R RVP",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 1a25a3787935..362663abcb89 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -298,13 +298,14 @@ static int rt5514_spi_pcm_new(struct snd_soc_component *component,
}
static const struct snd_soc_component_driver rt5514_spi_component = {
- .name = DRV_NAME,
- .probe = rt5514_spi_pcm_probe,
- .open = rt5514_spi_pcm_open,
- .hw_params = rt5514_spi_hw_params,
- .hw_free = rt5514_spi_hw_free,
- .pointer = rt5514_spi_pcm_pointer,
- .pcm_construct = rt5514_spi_pcm_new,
+ .name = DRV_NAME,
+ .probe = rt5514_spi_pcm_probe,
+ .open = rt5514_spi_pcm_open,
+ .hw_params = rt5514_spi_hw_params,
+ .hw_free = rt5514_spi_hw_free,
+ .pointer = rt5514_spi_pcm_pointer,
+ .pcm_construct = rt5514_spi_pcm_new,
+ .legacy_dai_naming = 1,
};
/**
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 0f8e6dd214b0..708e55b7431a 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2792,6 +2792,11 @@ static int rt5640_suspend(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+ if (rt5640->irq) {
+ /* disable jack interrupts during system suspend */
+ disable_irq(rt5640->irq);
+ }
+
rt5640_cancel_work(rt5640);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
rt5640_reset(component);
@@ -2815,6 +2820,9 @@ static int rt5640_resume(struct snd_soc_component *component)
regcache_cache_only(rt5640->regmap, false);
regcache_sync(rt5640->regmap);
+ if (rt5640->irq)
+ enable_irq(rt5640->irq);
+
if (rt5640->jack) {
if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
snd_soc_component_update_bits(component,
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 8f3993a4c1cc..d25703dd7499 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -396,15 +396,16 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component)
}
static const struct snd_soc_component_driver rt5677_spi_dai_component = {
- .name = DRV_NAME,
- .probe = rt5677_spi_pcm_probe,
- .open = rt5677_spi_pcm_open,
- .close = rt5677_spi_pcm_close,
- .hw_params = rt5677_spi_hw_params,
- .hw_free = rt5677_spi_hw_free,
- .prepare = rt5677_spi_prepare,
- .pointer = rt5677_spi_pcm_pointer,
- .pcm_construct = rt5677_spi_pcm_new,
+ .name = DRV_NAME,
+ .probe = rt5677_spi_pcm_probe,
+ .open = rt5677_spi_pcm_open,
+ .close = rt5677_spi_pcm_close,
+ .hw_params = rt5677_spi_hw_params,
+ .hw_free = rt5677_spi_hw_free,
+ .prepare = rt5677_spi_prepare,
+ .pointer = rt5677_spi_pcm_pointer,
+ .pcm_construct = rt5677_spi_pcm_new,
+ .legacy_dai_naming = 1,
};
/* Select a suitable transfer command for the next transfer to ensure
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index c1a94229dc7e..d8a573dcb771 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -24,6 +24,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/jack.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -130,11 +131,10 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -147,22 +147,12 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 1;
- } else {
- direction = SDW_DATA_DIR_TX;
- port = 2;
- }
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = (1 << (num_channels)) - 1;
- port_config.num = port;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
+ port_config.num = 2;
retval = sdw_stream_add_slave(rt5682->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 2df95e792900..7e3eb65afe16 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -35,6 +35,8 @@ const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
"AVDD",
"MICVDD",
"VBAT",
+ "DBVDD",
+ "LDO1-IN",
};
EXPORT_SYMBOL_GPL(rt5682_supply_names);
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 52ff0d9c36c5..d568c6993c33 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1424,7 +1424,7 @@ enum {
RT5682_CLK_SEL_I2S2_ASRC,
};
-#define RT5682_NUM_SUPPLIES 3
+#define RT5682_NUM_SUPPLIES 5
struct rt5682_priv {
struct snd_soc_component *component;
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 80c673aa14db..f5e5dbc3b0f0 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -44,6 +44,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = {
static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = {
[RT5682S_SUPPLY_AVDD] = "AVDD",
[RT5682S_SUPPLY_MICVDD] = "MICVDD",
+ [RT5682S_SUPPLY_DBVDD] = "DBVDD",
+ [RT5682S_SUPPLY_LDO1_IN] = "LDO1-IN",
};
static const struct reg_sequence patch_list[] = {
@@ -3089,6 +3091,14 @@ static void rt5682s_i2c_disable_regulators(void *data)
if (ret)
dev_err(dev, "Failed to disable supply AVDD: %d\n", ret);
+ ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+ if (ret)
+ dev_err(dev, "Failed to disable supply DBVDD: %d\n", ret);
+
+ ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+ if (ret)
+ dev_err(dev, "Failed to disable supply LDO1-IN: %d\n", ret);
+
usleep_range(1000, 1500);
ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer);
@@ -3150,6 +3160,18 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supply DBVDD: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supply LDO1-IN: %d\n", ret);
+ return ret;
+ }
+
if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
GPIOF_OUT_INIT_HIGH, "rt5682s"))
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index 45464a041765..67f86a38a1cc 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -1438,6 +1438,8 @@ struct pll_calc_map {
enum {
RT5682S_SUPPLY_AVDD,
RT5682S_SUPPLY_MICVDD,
+ RT5682S_SUPPLY_DBVDD,
+ RT5682S_SUPPLY_LDO1_IN,
RT5682S_NUM_SUPPLIES,
};
diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
index 055c3ae974d8..6534c9b51442 100644
--- a/sound/soc/codecs/rt700.c
+++ b/sound/soc/codecs/rt700.c
@@ -19,6 +19,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -910,11 +911,10 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int val = 0;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -927,35 +927,25 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
/* This code assumes port 1 for playback and port 2 for capture */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 1;
- } else {
- direction = SDW_DATA_DIR_TX;
- port = 2;
- }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
+ port_config.num = 2;
switch (dai->id) {
case RT700_AIF1:
break;
case RT700_AIF2:
- port += 2;
+ port_config.num += 2;
break;
default:
dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = (1 << (num_channels)) - 1;
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt700->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index 4120842fe699..88a8392a58ed 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -230,7 +230,7 @@ static int rt711_sdca_read_prop(struct sdw_slave *slave)
}
/* set the timeout values */
- prop->clk_stop_timeout = 20;
+ prop->clk_stop_timeout = 700;
/* wake-up event */
prop->wake_capable = 1;
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 925268121901..b78dd5994edb 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -18,6 +18,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -1257,11 +1258,10 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1274,28 +1274,19 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 3;
+ port_config.num = 3;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT711_AIF1)
- port = 2;
+ port_config.num = 2;
else if (dai->id == RT711_AIF2)
- port = 4;
+ port_config.num = 4;
else
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = GENMASK(num_channels - 1, 0);
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt711->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 1bf618089194..78e1da9b0738 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -19,6 +19,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -999,11 +1000,10 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int val = 0;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1016,28 +1016,19 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 3;
+ port_config.num = 3;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT711_AIF1)
- port = 4;
+ port_config.num = 4;
else if (dai->id == RT711_AIF2)
- port = 2;
+ port_config.num = 2;
else
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = (1 << (num_channels)) - 1;
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt711->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
index ce8bbc76199a..1fca7a3f46ea 100644
--- a/sound/soc/codecs/rt715-sdca.c
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -20,6 +20,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -820,11 +821,10 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct rt715_sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int val;
stream = snd_soc_dai_get_dma_data(dai, substream);
@@ -835,16 +835,16 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
if (!rt715->slave)
return -EINVAL;
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
switch (dai->id) {
case RT715_AIF1:
- direction = SDW_DATA_DIR_TX;
- port = 6;
+ port_config.num = 6;
rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
0xa500);
break;
case RT715_AIF2:
- direction = SDW_DATA_DIR_TX;
- port = 4;
+ port_config.num = 4;
rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
0xaf00);
break;
@@ -853,15 +853,6 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = GENMASK(num_channels - 1, 0);
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt715->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c
index e93240521c74..1a2036ccfbac 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -28,6 +28,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -203,12 +204,12 @@ static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
- unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC2_H};
- unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
- RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
- RT715_SET_GAIN_MIX_ADC2_L};
+ static const unsigned int capture_reg_H[] = {
+ RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
+ RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
+ static const unsigned int capture_reg_L[] = {
+ RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
+ RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0;
unsigned int read_ll, read_rl, i, j, loop_cnt = 4;
@@ -283,12 +284,12 @@ static int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
- unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC2_H};
- unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
- RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
- RT715_SET_GAIN_MIX_ADC2_L};
+ static const unsigned int capture_reg_H[] = {
+ RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
+ RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
+ static const unsigned int capture_reg_L[] = {
+ RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
+ RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
unsigned int read_ll, read_rl;
@@ -311,12 +312,12 @@ static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
- unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC2_H};
- unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
- RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
- RT715_SET_GAIN_MIX_ADC2_L};
+ static const unsigned int capture_reg_H[] = {
+ RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
+ RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
+ static const unsigned int capture_reg_L[] = {
+ RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
+ RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L};
unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0;
unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f;
@@ -392,12 +393,12 @@ static int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
- unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC2_H};
- unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
- RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
- RT715_SET_GAIN_MIX_ADC2_L};
+ static const unsigned int capture_reg_H[] = {
+ RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
+ RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
+ static const unsigned int capture_reg_L[] = {
+ RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
+ RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
unsigned int read_ll, read_rl;
@@ -801,11 +802,10 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int retval, port, num_channels;
+ int retval;
unsigned int val = 0;
stream = snd_soc_dai_get_dma_data(dai, substream);
@@ -816,15 +816,15 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
if (!rt715->slave)
return -EINVAL;
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
switch (dai->id) {
case RT715_AIF1:
- direction = SDW_DATA_DIR_TX;
- port = 6;
+ port_config.num = 6;
rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa500);
break;
case RT715_AIF2:
- direction = SDW_DATA_DIR_TX;
- port = 4;
+ port_config.num = 4;
rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa000);
break;
default:
@@ -832,15 +832,6 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = (1 << (num_channels)) - 1;
- port_config.num = port;
-
retval = sdw_stream_add_slave(rt715->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
if (retval) {
diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c
index 288b55368d2a..af52f2728854 100644
--- a/sound/soc/codecs/sdw-mockup.c
+++ b/sound/soc/codecs/sdw-mockup.c
@@ -16,6 +16,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/soc.h>
struct sdw_mockup_priv {
@@ -80,12 +81,9 @@ static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct sdw_mockup_priv *sdw_mockup = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
- struct sdw_port_config port_config;
- enum sdw_data_direction direction;
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
struct sdw_stream_data *stream;
- int num_channels;
- int port;
int ret;
stream = snd_soc_dai_get_dma_data(dai, substream);
@@ -96,22 +94,12 @@ static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
/* SoundWire specific configuration */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
- port = 1;
- } else {
- direction = SDW_DATA_DIR_TX;
- port = 8;
- }
-
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
- num_channels = params_channels(params);
- port_config.ch_mask = (1 << num_channels) - 1;
- port_config.num = port;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
+ port_config.num = 8;
ret = sdw_stream_add_slave(sdw_mockup->slave, &stream_config,
&port_config, 1, stream->sdw_stream);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 4b2135eba74d..a916f4619ea3 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1794,6 +1794,7 @@ static void sgtl5000_i2c_remove(struct i2c_client *client)
{
struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
+ regmap_write(sgtl5000->regmap, SGTL5000_CHIP_CLK_CTRL, SGTL5000_CHIP_CLK_CTRL_DEFAULT);
regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT);
regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT);
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index d30c0d24d90a..bf67de12d20b 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -55,6 +55,14 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
e, NULL);
}
+static unsigned int simple_mux_read(struct snd_soc_component *component,
+ unsigned int reg)
+{
+ struct simple_mux *priv = snd_soc_component_get_drvdata(component);
+
+ return priv->mux;
+}
+
static const struct snd_kcontrol_new simple_mux_mux =
SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
@@ -76,6 +84,7 @@ static const struct snd_soc_component_driver simple_mux_component_driver = {
.num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets),
.dapm_routes = simple_mux_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes),
+ .read = simple_mux_read,
};
static int simple_mux_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c
index 43daa9dc8ab5..27026030704a 100644
--- a/sound/soc/codecs/src4xxx-i2c.c
+++ b/sound/soc/codecs/src4xxx-i2c.c
@@ -12,8 +12,7 @@
#include "src4xxx.h"
-static int src4xxx_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int src4xxx_i2c_probe(struct i2c_client *i2c)
{
return src4xxx_probe(&i2c->dev,
devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL);
@@ -37,7 +36,7 @@ static struct i2c_driver src4xxx_i2c_driver = {
.name = "src4xxx",
.of_match_table = of_match_ptr(src4xxx_of_match),
},
- .probe = src4xxx_i2c_probe,
+ .probe_new = src4xxx_i2c_probe,
.id_table = src4xxx_i2c_ids,
};
module_i2c_driver(src4xxx_i2c_driver);
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 51b87a936179..2e0ed3e68fa5 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -438,20 +438,13 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (tx_mask == 0 || rx_mask != 0)
return -EINVAL;
- if (slots == 1) {
- if (tx_mask != 1)
- return -EINVAL;
- left_slot = 0;
- right_slot = 0;
+ left_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << left_slot);
+ if (tx_mask == 0) {
+ right_slot = left_slot;
} else {
- left_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << left_slot);
- if (tx_mask == 0) {
- right_slot = left_slot;
- } else {
- right_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << right_slot);
- }
+ right_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << right_slot);
}
if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index b6765235a4b3..8557759acb1f 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -395,21 +395,13 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (tx_mask == 0 || rx_mask != 0)
return -EINVAL;
- if (slots == 1) {
- if (tx_mask != 1)
- return -EINVAL;
-
- left_slot = 0;
- right_slot = 0;
+ left_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << left_slot);
+ if (tx_mask == 0) {
+ right_slot = left_slot;
} else {
- left_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << left_slot);
- if (tx_mask == 0) {
- right_slot = left_slot;
- } else {
- right_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << right_slot);
- }
+ right_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << right_slot);
}
if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index a6db6f0e5431..09e7ada1bca4 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -380,20 +380,13 @@ static int tas2780_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (tx_mask == 0 || rx_mask != 0)
return -EINVAL;
- if (slots == 1) {
- if (tx_mask != 1)
- return -EINVAL;
- left_slot = 0;
- right_slot = 0;
+ left_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << left_slot);
+ if (tx_mask == 0) {
+ right_slot = left_slot;
} else {
- left_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << left_slot);
- if (tx_mask == 0) {
- right_slot = left_slot;
- } else {
- right_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << right_slot);
- }
+ right_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << right_slot);
}
if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
@@ -598,8 +591,7 @@ static int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780)
return 0;
}
-static int tas2780_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tas2780_i2c_probe(struct i2c_client *client)
{
struct tas2780_priv *tas2780;
int result;
@@ -653,7 +645,7 @@ static struct i2c_driver tas2780_i2c_driver = {
.name = "tas2780",
.of_match_table = of_match_ptr(tas2780_of_match),
},
- .probe = tas2780_i2c_probe,
+ .probe_new = tas2780_i2c_probe,
.id_table = tas2780_i2c_id,
};
module_i2c_driver(tas2780_i2c_driver);
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index a969547708d4..52bb55724724 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -14,6 +14,7 @@
#include <dt-bindings/sound/tlv320adc3xxx.h>
#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/io.h>
@@ -1025,7 +1026,9 @@ static const struct gpio_chip adc3xxx_gpio_chip = {
static void adc3xxx_free_gpio(struct adc3xxx *adc3xxx)
{
+#ifdef CONFIG_GPIOLIB
gpiochip_remove(&adc3xxx->gpio_chip);
+#endif
}
static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 08938801daec..56e795a00e22 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -32,12 +32,12 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -45,7 +45,6 @@
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/tlv320aic3x.h>
#include "tlv320aic3x.h"
@@ -57,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
-static LIST_HEAD(reset_list);
-
struct aic3x_priv;
struct aic3x_disable_nb {
@@ -66,6 +63,10 @@ struct aic3x_disable_nb {
struct aic3x_priv *aic3x;
};
+struct aic3x_setup_data {
+ unsigned int gpio_func[2];
+};
+
/* codec private data */
struct aic3x_priv {
struct snd_soc_component *component;
@@ -77,9 +78,9 @@ struct aic3x_priv {
unsigned int dai_fmt;
unsigned int tdm_delay;
unsigned int slot_width;
- struct list_head list;
int master;
- int gpio_reset;
+ struct gpio_desc *gpio_reset;
+ bool shared_reset;
int power;
u16 model;
@@ -1366,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb,
* Put codec to reset and require cache sync as at least one
* of the supplies was disabled
*/
- if (gpio_is_valid(aic3x->gpio_reset))
- gpio_set_value(aic3x->gpio_reset, 0);
+ if (aic3x->gpio_reset)
+ gpiod_set_value(aic3x->gpio_reset, 1);
regcache_mark_dirty(aic3x->regmap);
}
@@ -1387,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
goto out;
aic3x->power = 1;
- if (gpio_is_valid(aic3x->gpio_reset)) {
+ if (aic3x->gpio_reset) {
udelay(1);
- gpio_set_value(aic3x->gpio_reset, 1);
+ gpiod_set_value(aic3x->gpio_reset, 0);
}
/* Sync reg_cache with the hardware */
@@ -1595,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component)
return 0;
}
-static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
-{
- struct aic3x_priv *a;
-
- list_for_each_entry(a, &reset_list, list) {
- if (gpio_is_valid(aic3x->gpio_reset) &&
- aic3x->gpio_reset == a->gpio_reset)
- return true;
- }
-
- return false;
-}
-
static int aic3x_component_probe(struct snd_soc_component *component)
{
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
@@ -1748,7 +1736,6 @@ static const struct reg_sequence aic3007_class_d[] = {
int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
{
- struct aic3x_pdata *pdata = dev->platform_data;
struct aic3x_priv *aic3x;
struct aic3x_setup_data *ai3x_setup;
struct device_node *np = dev->of_node;
@@ -1768,28 +1755,11 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
regcache_cache_only(aic3x->regmap, true);
dev_set_drvdata(dev, aic3x);
- if (pdata) {
- aic3x->gpio_reset = pdata->gpio_reset;
- aic3x->setup = pdata->setup;
- aic3x->micbias_vg = pdata->micbias_vg;
- } else if (np) {
+ if (np) {
ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL);
if (!ai3x_setup)
return -ENOMEM;
- ret = of_get_named_gpio(np, "reset-gpios", 0);
- if (ret >= 0) {
- aic3x->gpio_reset = ret;
- } else {
- ret = of_get_named_gpio(np, "gpio-reset", 0);
- if (ret > 0) {
- dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
- aic3x->gpio_reset = ret;
- } else {
- aic3x->gpio_reset = -1;
- }
- }
-
if (of_property_read_u32_array(np, "ai3x-gpio-func",
ai3x_setup->gpio_func, 2) >= 0) {
aic3x->setup = ai3x_setup;
@@ -1814,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
} else {
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
}
-
- } else {
- aic3x->gpio_reset = -1;
}
aic3x->model = driver_data;
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
- if (ret != 0)
- goto err;
- gpio_direction_output(aic3x->gpio_reset, 0);
+ aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+ if (ret) {
+ if (ret != -EBUSY)
+ return ret;
+
+ /*
+ * Apparently there are setups where the codec is sharing
+ * its reset line. Try to get it non-exclusively, although
+ * the utility of this is unclear: how do we make sure that
+ * resetting one chip will not disturb the others that share
+ * the same line?
+ */
+ aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
+ GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+ if (ret)
+ return ret;
+
+ aic3x->shared_reset = true;
}
+ gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
+
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
aic3x->supplies[i].supply = aic3x_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
- if (ret != 0) {
+ if (ret) {
dev_err(dev, "Failed to request supplies: %d\n", ret);
- goto err_gpio;
+ return ret;
}
aic3x_configure_ocmv(dev, aic3x);
@@ -1845,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
ARRAY_SIZE(aic3007_class_d));
if (ret != 0)
- dev_err(dev, "Failed to init class D: %d\n",
- ret);
+ dev_err(dev, "Failed to init class D: %d\n", ret);
}
ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
-
- if (ret != 0)
- goto err_gpio;
-
- INIT_LIST_HEAD(&aic3x->list);
- list_add(&aic3x->list, &reset_list);
+ if (ret)
+ return ret;
return 0;
-
-err_gpio:
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x))
- gpio_free(aic3x->gpio_reset);
-err:
- return ret;
}
EXPORT_SYMBOL(aic3x_probe);
@@ -1872,13 +1844,9 @@ void aic3x_remove(struct device *dev)
{
struct aic3x_priv *aic3x = dev_get_drvdata(dev);
- list_del(&aic3x->list);
-
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- gpio_set_value(aic3x->gpio_reset, 0);
- gpio_free(aic3x->gpio_reset);
- }
+ /* Leave the codec in reset state */
+ if (aic3x->gpio_reset && !aic3x->shared_reset)
+ gpiod_set_value(aic3x->gpio_reset, 1);
}
EXPORT_SYMBOL(aic3x_remove);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 14298f9e6d9b..066e5a6322b8 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -298,4 +298,47 @@ enum {
#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0
#define AIC3X_BUTTON_DEBOUNCE_MASK 3
+/* GPIO API */
+enum {
+ AIC3X_GPIO1_FUNC_DISABLED = 0,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
+ AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
+ AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
+ AIC3X_GPIO1_FUNC_INPUT = 8,
+ AIC3X_GPIO1_FUNC_OUTPUT = 9,
+ AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
+ AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
+ AIC3X_GPIO1_FUNC_ALL_IRQ = 16
+};
+
+enum {
+ AIC3X_GPIO2_FUNC_DISABLED = 0,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
+ AIC3X_GPIO2_FUNC_INPUT = 3,
+ AIC3X_GPIO2_FUNC_OUTPUT = 4,
+ AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
+ AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+ AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+ AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
+ AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
+ AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
+};
+
+enum aic3x_micbias_voltage {
+ AIC3X_MICBIAS_OFF = 0,
+ AIC3X_MICBIAS_2_0V = 1,
+ AIC3X_MICBIAS_2_5V = 2,
+ AIC3X_MICBIAS_AVDDV = 3,
+};
+
#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index e48768233e20..9c50ac356c89 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -700,8 +700,10 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_board_params *board_params = twl4030->board_params;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
- unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
- 8388608, 16777216, 33554432, 67108864};
+ static const unsigned int ramp_base[] = {
+ 524288, 1048576, 2097152, 4194304,
+ 8388608, 16777216, 33554432, 67108864
+ };
unsigned int delay;
hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index aca06a4026f3..fcac763b04d1 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -3128,8 +3128,8 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x,
s16 c1;
s32 x1, d1;
int32_t denom;
- int minCode_param[] = {
- 3277, 1639, 820, 410, 205, 103, 52, 26
+ static const int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
};
regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x20);
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 7dc6aaf65576..a4857024711d 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -971,9 +971,16 @@ static const struct i2c_device_id wm8961_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
+static const struct of_device_id wm8961_of_match[] __maybe_unused = {
+ { .compatible = "wlf,wm8961", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8961_of_match);
+
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
.name = "wm8961",
+ .of_match_table = of_match_ptr(wm8961_of_match),
},
.probe_new = wm8961_i2c_probe,
.id_table = wm8961_i2c_id,
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index b4b4355c6728..b901e4c65e8a 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2503,6 +2503,14 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
+ /* DSPCLK_DIV field in WM8962_CLOCKING1 register is used to generate
+ * correct frequency of LRCLK and BCLK. Sometimes the read-only value
+ * can't be updated timely after enabling SYSCLK. This results in wrong
+ * calculation values. Delay is introduced here to wait for newest
+ * value from register. The time of the delay should be at least
+ * 500~1000us according to test.
+ */
+ usleep_range(500, 1000);
dspclk = snd_soc_component_read(component, WM8962_CLOCKING1);
if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index a682f8020eb6..aa2f55401a88 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -498,7 +498,7 @@ static int wm8978_configure_pll(struct snd_soc_component *component)
if (4 * f_opclk < 3 * f_mclk)
/* Have to use OPCLKDIV */
- opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+ opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk);
else
opclk_div = 1;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 8a2e9771bb50..ea0dbc634ecf 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -19,6 +19,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <sound/core.h>
@@ -419,16 +420,21 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+ void *scratch;
int ret = 0;
- mutex_lock(&cs_ctl->dsp->pwr_lock);
+ scratch = vmalloc(size);
+ if (!scratch)
+ return -ENOMEM;
- if (copy_from_user(cs_ctl->cache, bytes, size))
+ if (copy_from_user(scratch, bytes, size)) {
ret = -EFAULT;
- else
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size);
-
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
+ } else {
+ mutex_lock(&cs_ctl->dsp->pwr_lock);
+ ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, scratch, size);
+ mutex_unlock(&cs_ctl->dsp->pwr_lock);
+ }
+ vfree(scratch);
return ret;
}
@@ -455,7 +461,10 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
mutex_unlock(&cs_ctl->dsp->pwr_lock);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ return 1;
}
static int wm_coeff_get(struct snd_kcontrol *kctl,
@@ -682,10 +691,10 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
int ret;
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
- if (ret)
+ if (ret < 0)
return ret;
- if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
+ if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS))
return 0;
ctl = cs_ctl->priv;
@@ -1035,6 +1044,16 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(wm_adsp_early_event);
+static int wm_adsp_pre_run(struct cs_dsp *cs_dsp)
+{
+ struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
+
+ if (!dsp->pre_run)
+ return 0;
+
+ return (*dsp->pre_run)(dsp);
+}
+
static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
{
struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
@@ -2043,9 +2062,11 @@ static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
.control_add = wm_adsp_control_add,
.control_remove = wm_adsp_control_remove,
+ .pre_run = wm_adsp_pre_run,
.post_run = wm_adsp_event_post_run,
.post_stop = wm_adsp_event_post_stop,
.watchdog_expired = wm_adsp_fatal_error,
};
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 375009a65828..dc2f7a096e26 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -36,6 +36,7 @@ struct wm_adsp {
int fw;
struct work_struct boot_work;
+ int (*pre_run)(struct wm_adsp *dsp);
bool preloaded;
bool fatal_error;
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index c7b10bbfba7e..966ba4909204 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -7,7 +7,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -1380,22 +1380,19 @@ static int wsa883x_probe(struct sdw_slave *pdev,
return -ENOMEM;
wsa883x->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(wsa883x->vdd)) {
- dev_err(dev, "No vdd regulator found\n");
- return PTR_ERR(wsa883x->vdd);
- }
+ if (IS_ERR(wsa883x->vdd))
+ return dev_err_probe(dev, PTR_ERR(wsa883x->vdd),
+ "No vdd regulator found\n");
ret = regulator_enable(wsa883x->vdd);
- if (ret) {
- dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n");
wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
- GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH);
if (IS_ERR(wsa883x->sd_n)) {
- dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
- ret = PTR_ERR(wsa883x->sd_n);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->sd_n),
+ "Shutdown Control GPIO not found\n");
goto err;
}
@@ -1411,12 +1408,13 @@ static int wsa883x_probe(struct sdw_slave *pdev,
pdev->prop.simple_clk_stop_capable = true;
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
- gpiod_direction_output(wsa883x->sd_n, 1);
+ gpiod_direction_output(wsa883x->sd_n, 0);
wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
if (IS_ERR(wsa883x->regmap)) {
- dev_err(&pdev->dev, "regmap_init failed\n");
- ret = PTR_ERR(wsa883x->regmap);
+ gpiod_direction_output(wsa883x->sd_n, 1);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->regmap),
+ "regmap_init failed\n");
goto err;
}
pm_runtime_set_autosuspend_delay(dev, 3000);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 936aef5d2767..e16e7b3fa96c 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1232,7 +1232,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
ret = pm_runtime_put_sync(&pdev->dev);
- if (ret < 0)
+ if (ret < 0 && ret != -ENOSYS)
goto err_pm_get_sync;
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 5c21fc490fce..17fefd27ec90 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -1069,7 +1069,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0);
ret = pm_runtime_put_sync(&pdev->dev);
- if (ret < 0)
+ if (ret < 0 && ret != -ENOSYS)
goto err_pm_get_sync;
/*
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 79ef4e269bc9..7b17f152bbf3 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -47,11 +47,15 @@ struct fsl_micfil {
struct clk *pll11k_clk;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct sdma_peripheral_config sdmacfg;
+ struct snd_soc_card *card;
unsigned int dataline;
char name[32];
int irq[MICFIL_IRQ_LINES];
enum quality quality;
int dc_remover;
+ int vad_init_mode;
+ int vad_enabled;
+ int vad_detected;
};
struct fsl_micfil_soc_data {
@@ -59,6 +63,7 @@ struct fsl_micfil_soc_data {
unsigned int fifo_depth;
unsigned int dataline;
bool imx;
+ bool use_edma;
u64 formats;
};
@@ -78,9 +83,19 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
};
+static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
+ .imx = true,
+ .fifos = 8,
+ .fifo_depth = 32,
+ .dataline = 0xf,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .use_edma = true,
+};
+
static const struct of_device_id fsl_micfil_dt_ids[] = {
{ .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm },
{ .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp },
+ { .compatible = "fsl,imx93-micfil", .data = &fsl_micfil_imx93 },
{}
};
MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids);
@@ -152,6 +167,152 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol,
return micfil_set_quality(micfil);
}
+static const char * const micfil_hwvad_enable[] = {
+ "Disable (Record only)",
+ "Enable (Record with Vad)",
+};
+
+static const char * const micfil_hwvad_init_mode[] = {
+ "Envelope mode", "Energy mode",
+};
+
+static const char * const micfil_hwvad_hpf_texts[] = {
+ "Filter bypass",
+ "Cut-off @1750Hz",
+ "Cut-off @215Hz",
+ "Cut-off @102Hz",
+};
+
+/*
+ * DC Remover Control
+ * Filter Bypassed 1 1
+ * Cut-off @21Hz 0 0
+ * Cut-off @83Hz 0 1
+ * Cut-off @152HZ 1 0
+ */
+static const char * const micfil_dc_remover_texts[] = {
+ "Cut-off @21Hz", "Cut-off @83Hz",
+ "Cut-off @152Hz", "Bypass",
+};
+
+static const struct soc_enum hwvad_enable_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_enable),
+ micfil_hwvad_enable);
+static const struct soc_enum hwvad_init_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_init_mode),
+ micfil_hwvad_init_mode);
+static const struct soc_enum hwvad_hpf_enum =
+ SOC_ENUM_SINGLE(REG_MICFIL_VAD0_CTRL2, 0,
+ ARRAY_SIZE(micfil_hwvad_hpf_texts),
+ micfil_hwvad_hpf_texts);
+static const struct soc_enum fsl_micfil_dc_remover_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_dc_remover_texts),
+ micfil_dc_remover_texts);
+
+static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+ int i = 0, ret = 0;
+ u32 reg_val = 0;
+
+ if (val < 0 || val > 3)
+ return -EINVAL;
+
+ micfil->dc_remover = val;
+
+ /* Calculate total value for all channels */
+ for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
+ reg_val |= val << MICFIL_DC_CHX_SHIFT(i);
+
+ /* Update DC Remover mode for all channels */
+ ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL,
+ MICFIL_DC_CTRL_CONFIG, reg_val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->dc_remover;
+
+ return 0;
+}
+
+static int hwvad_put_enable(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+
+ micfil->vad_enabled = val;
+
+ return 0;
+}
+
+static int hwvad_get_enable(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_enabled;
+
+ return 0;
+}
+
+static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+
+ /* 0 - Envelope-based Mode
+ * 1 - Energy-based Mode
+ */
+ micfil->vad_init_mode = val;
+
+ return 0;
+}
+
+static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_init_mode;
+
+ return 0;
+}
+
+static int hwvad_detected(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_detected;
+
+ return 0;
+}
+
static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
@@ -172,6 +333,27 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum,
micfil_quality_get, micfil_quality_set),
+ SOC_ENUM_EXT("HWVAD Enablement Switch", hwvad_enable_enum,
+ hwvad_get_enable, hwvad_put_enable),
+ SOC_ENUM_EXT("HWVAD Initialization Mode", hwvad_init_mode_enum,
+ hwvad_get_init_mode, hwvad_put_init_mode),
+ SOC_ENUM("HWVAD High-Pass Filter", hwvad_hpf_enum),
+ SOC_SINGLE("HWVAD ZCD Switch", REG_MICFIL_VAD0_ZCD, 0, 1, 0),
+ SOC_SINGLE("HWVAD ZCD Auto Threshold Switch",
+ REG_MICFIL_VAD0_ZCD, 2, 1, 0),
+ SOC_ENUM_EXT("MICFIL DC Remover Control", fsl_micfil_dc_remover_enum,
+ micfil_get_dc_remover_state, micfil_put_dc_remover_state),
+ SOC_SINGLE("HWVAD Input Gain", REG_MICFIL_VAD0_CTRL2, 8, 15, 0),
+ SOC_SINGLE("HWVAD Sound Gain", REG_MICFIL_VAD0_SCONFIG, 0, 15, 0),
+ SOC_SINGLE("HWVAD Noise Gain", REG_MICFIL_VAD0_NCONFIG, 0, 15, 0),
+ SOC_SINGLE_RANGE("HWVAD Detector Frame Time", REG_MICFIL_VAD0_CTRL2, 16, 0, 63, 0),
+ SOC_SINGLE("HWVAD Detector Initialization Time", REG_MICFIL_VAD0_CTRL1, 8, 31, 0),
+ SOC_SINGLE("HWVAD Noise Filter Adjustment", REG_MICFIL_VAD0_NCONFIG, 8, 31, 0),
+ SOC_SINGLE("HWVAD ZCD Threshold", REG_MICFIL_VAD0_ZCD, 16, 1023, 0),
+ SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0),
+ SOC_SINGLE("HWVAD ZCD And Behavior Switch",
+ REG_MICFIL_VAD0_ZCD, 4, 1, 0),
+ SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
};
/* The SRES is a self-negated bit which provides the CPU with the
@@ -194,6 +376,25 @@ static int fsl_micfil_reset(struct device *dev)
if (ret)
return ret;
+ /*
+ * SRES is self-cleared bit, but REG_MICFIL_CTRL1 is defined
+ * as non-volatile register, so SRES still remain in regmap
+ * cache after set, that every update of REG_MICFIL_CTRL1,
+ * software reset happens. so clear it explicitly.
+ */
+ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1,
+ MICFIL_CTRL1_SRES);
+ if (ret)
+ return ret;
+
+ /*
+ * Set SRES should clear CHnF flags, But even add delay here
+ * the CHnF may not be cleared sometimes, so clear CHnF explicitly.
+ */
+ ret = regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, 0xFF, 0xFF);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -210,6 +411,167 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
return 0;
}
+/* Enable/disable hwvad interrupts */
+static int fsl_micfil_configure_hwvad_interrupts(struct fsl_micfil *micfil, int enable)
+{
+ u32 vadie_reg = enable ? MICFIL_VAD0_CTRL1_IE : 0;
+ u32 vaderie_reg = enable ? MICFIL_VAD0_CTRL1_ERIE : 0;
+
+ /* Voice Activity Detector Error Interruption */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ERIE, vaderie_reg);
+
+ /* Voice Activity Detector Interruption */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_IE, vadie_reg);
+
+ return 0;
+}
+
+/* Configuration done only in energy-based initialization mode */
+static int fsl_micfil_init_hwvad_energy_mode(struct fsl_micfil *micfil)
+{
+ /* Keep the VADFRENDIS bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_FRENDIS);
+
+ /* Keep the VADPREFEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_PREFEN);
+
+ /* Keep the VADSFILEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SFILEN);
+
+ /* Keep the VADSMAXEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SMAXEN);
+
+ /* Keep the VADNFILAUTO bitfield asserted. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NFILAUT);
+
+ /* Keep the VADNMINEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NMINEN);
+
+ /* Keep the VADNDECEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NDECEN);
+
+ /* Keep the VADNOREN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NOREN);
+
+ return 0;
+}
+
+/* Configuration done only in envelope-based initialization mode */
+static int fsl_micfil_init_hwvad_envelope_mode(struct fsl_micfil *micfil)
+{
+ /* Assert the VADFRENDIS bitfield */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_FRENDIS);
+
+ /* Assert the VADPREFEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_PREFEN);
+
+ /* Assert the VADSFILEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SFILEN);
+
+ /* Assert the VADSMAXEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SMAXEN);
+
+ /* Clear the VADNFILAUTO bitfield */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NFILAUT);
+
+ /* Assert the VADNMINEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NMINEN);
+
+ /* Assert the VADNDECEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NDECEN);
+
+ /* Assert VADNOREN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NOREN);
+
+ return 0;
+}
+
+/*
+ * Hardware Voice Active Detection: The HWVAD takes data from the input
+ * of a selected PDM microphone to detect if there is any
+ * voice activity. When a voice activity is detected, an interrupt could
+ * be delivered to the system. Initialization in section 8.4:
+ * Can work in two modes:
+ * -> Eneveope-based mode (section 8.4.1)
+ * -> Energy-based mode (section 8.4.2)
+ *
+ * It is important to remark that the HWVAD detector could be enabled
+ * or reset only when the MICFIL isn't running i.e. when the BSY_FIL
+ * bit in STAT register is cleared
+ */
+static int fsl_micfil_hwvad_enable(struct fsl_micfil *micfil)
+{
+ int ret;
+
+ micfil->vad_detected = 0;
+
+ /* envelope-based specific initialization */
+ if (micfil->vad_init_mode == MICFIL_HWVAD_ENVELOPE_MODE)
+ ret = fsl_micfil_init_hwvad_envelope_mode(micfil);
+ else
+ ret = fsl_micfil_init_hwvad_energy_mode(micfil);
+ if (ret)
+ return ret;
+
+ /* Voice Activity Detector Internal Filters Initialization*/
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ST10);
+
+ /* Voice Activity Detector Internal Filter */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ST10);
+
+ /* Enable Interrupts */
+ ret = fsl_micfil_configure_hwvad_interrupts(micfil, 1);
+ if (ret)
+ return ret;
+
+ /* Voice Activity Detector Reset */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_RST);
+
+ /* Voice Activity Detector Enabled */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_EN);
+
+ return 0;
+}
+
+static int fsl_micfil_hwvad_disable(struct fsl_micfil *micfil)
+{
+ struct device *dev = &micfil->pdev->dev;
+ int ret = 0;
+
+ /* Disable HWVAD */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_EN);
+
+ /* Disable hwvad interrupts */
+ ret = fsl_micfil_configure_hwvad_interrupts(micfil, 0);
+ if (ret)
+ dev_err(dev, "Failed to disable interrupts\n");
+
+ return ret;
+}
+
static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -245,10 +607,16 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret)
return ret;
+ if (micfil->vad_enabled)
+ fsl_micfil_hwvad_enable(micfil);
+
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (micfil->vad_enabled)
+ fsl_micfil_hwvad_disable(micfil);
+
/* Disable the module */
ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1,
MICFIL_CTRL1_PDMIEN);
@@ -328,11 +696,23 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr));
+ /* Configure CIC OSR in VADCICOSR */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_CICOSR,
+ FIELD_PREP(MICFIL_VAD0_CTRL1_CICOSR, 16 - osr));
+
+ /* Configure source channel in VADCHSEL */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_CHSEL,
+ FIELD_PREP(MICFIL_VAD0_CTRL1_CHSEL, (channels - 1)));
+
micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg;
micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg);
micfil->sdmacfg.n_fifos_src = channels;
micfil->sdmacfg.sw_done = true;
micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX;
+ if (micfil->soc->use_edma)
+ micfil->dma_params_rx.maxburst = channels;
return 0;
}
@@ -351,6 +731,7 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
int ret, i;
micfil->quality = QUALITY_VLOW0;
+ micfil->card = cpu_dai->component->card;
/* set default gain to 2 */
regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
@@ -585,6 +966,71 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
return IRQ_HANDLED;
}
+static irqreturn_t voice_detected_fn(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct snd_kcontrol *kctl;
+
+ if (!micfil->card)
+ return IRQ_HANDLED;
+
+ kctl = snd_soc_card_get_kcontrol(micfil->card, "VAD Detected");
+ if (!kctl)
+ return IRQ_HANDLED;
+
+ if (micfil->vad_detected)
+ snd_ctl_notify(micfil->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &kctl->id);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t hwvad_isr(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct device *dev = &micfil->pdev->dev;
+ u32 vad0_reg;
+ int ret;
+
+ regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+ /*
+ * The only difference between MICFIL_VAD0_STAT_EF and
+ * MICFIL_VAD0_STAT_IF is that the former requires Write
+ * 1 to Clear. Since both flags are set, it is enough
+ * to only read one of them
+ */
+ if (vad0_reg & MICFIL_VAD0_STAT_IF) {
+ /* Write 1 to clear */
+ regmap_write_bits(micfil->regmap, REG_MICFIL_VAD0_STAT,
+ MICFIL_VAD0_STAT_IF,
+ MICFIL_VAD0_STAT_IF);
+
+ micfil->vad_detected = 1;
+ }
+
+ ret = fsl_micfil_hwvad_disable(micfil);
+ if (ret)
+ dev_err(dev, "Failed to disable hwvad\n");
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t hwvad_err_isr(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct device *dev = &micfil->pdev->dev;
+ u32 vad0_reg;
+
+ regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+ if (vad0_reg & MICFIL_VAD0_STAT_INSATF)
+ dev_dbg(dev, "voice activity input overflow/underflow detected\n");
+
+ return IRQ_HANDLED;
+}
+
static int fsl_micfil_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -677,6 +1123,26 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return ret;
}
+ /* Digital Microphone interface voice activity detector event */
+ ret = devm_request_threaded_irq(&pdev->dev, micfil->irq[2],
+ hwvad_isr, voice_detected_fn,
+ IRQF_SHARED, micfil->name, micfil);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim hwvad event irq %u\n",
+ micfil->irq[0]);
+ return ret;
+ }
+
+ /* Digital Microphone interface voice activity detector error */
+ ret = devm_request_irq(&pdev->dev, micfil->irq[3],
+ hwvad_err_isr, IRQF_SHARED,
+ micfil->name, micfil);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim hwvad error irq %u\n",
+ micfil->irq[1]);
+ return ret;
+ }
+
micfil->dma_params_rx.chan_name = "rx";
micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0;
micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h
index d60285dd07bc..9237a1c4cb8f 100644
--- a/sound/soc/fsl/fsl_micfil.h
+++ b/sound/soc/fsl/fsl_micfil.h
@@ -136,10 +136,14 @@
#define FIFO_PTRWID 3
#define FIFO_LEN BIT(FIFO_PTRWID)
-#define MICFIL_IRQ_LINES 2
+#define MICFIL_IRQ_LINES 4
#define MICFIL_MAX_RETRY 25
#define MICFIL_SLEEP_MIN 90000 /* in us */
#define MICFIL_SLEEP_MAX 100000 /* in us */
#define MICFIL_DMA_MAXBURST_RX 6
+/* HWVAD Constants */
+#define MICFIL_HWVAD_ENVELOPE_MODE 0
+#define MICFIL_HWVAD_ENERGY_MODE 1
+
#endif /* _FSL_MICFIL_H */
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
index bf94838bdbef..46c7868a2653 100644
--- a/sound/soc/fsl/fsl_rpmsg.c
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -117,14 +117,14 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_RPMSG_FORMATS,
},
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_RPMSG_FORMATS,
},
@@ -235,7 +235,7 @@ static int fsl_rpmsg_probe(struct platform_device *pdev)
rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
"imx-audio-rpmsg",
- PLATFORM_DEVID_NONE,
+ PLATFORM_DEVID_AUTO,
NULL,
0);
if (IS_ERR(rpmsg->card_pdev)) {
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 81f89f6767a2..1c9be8a5dcb1 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -872,10 +872,10 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
- sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
+ sai->soc_data->fifo_depth - sai->dma_params_tx.maxburst);
regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs),
FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
- FSL_SAI_MAXBURST_RX - 1);
+ sai->dma_params_rx.maxburst - 1);
snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
&sai->dma_params_rx);
@@ -1416,8 +1416,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0;
sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0;
- sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
- sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+ sai->dma_params_rx.maxburst =
+ sai->soc_data->max_burst[RX] ? sai->soc_data->max_burst[RX] : FSL_SAI_MAXBURST_RX;
+ sai->dma_params_tx.maxburst =
+ sai->soc_data->max_burst[TX] ? sai->soc_data->max_burst[TX] : FSL_SAI_MAXBURST_TX;
sai->pinctrl = devm_pinctrl_get(&pdev->dev);
@@ -1446,7 +1448,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
}
ret = pm_runtime_put_sync(dev);
- if (ret < 0)
+ if (ret < 0 && ret != -ENOSYS)
goto err_pm_get_sync;
/*
@@ -1579,6 +1581,18 @@ static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = {
.max_register = FSL_SAI_RTCAP,
};
+static const struct fsl_sai_soc_data fsl_sai_imx93_data = {
+ .use_imx_pcm = true,
+ .use_edma = true,
+ .fifo_depth = 128,
+ .reg_offset = 8,
+ .mclk0_is_mclk1 = false,
+ .pins = 4,
+ .flags = 0,
+ .max_register = FSL_SAI_MCTL,
+ .max_burst = {8, 8},
+};
+
static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
{ .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
@@ -1590,6 +1604,7 @@ static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data },
{ .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data },
{ .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data },
+ { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_sai_ids);
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 697f6690068c..197748a888d5 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -235,6 +235,7 @@ struct fsl_sai_soc_data {
unsigned int reg_offset;
unsigned int flags;
unsigned int max_register;
+ unsigned int max_burst[2];
};
/**
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index c043efe4548d..2a6802fb2a8b 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -934,6 +934,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = {
{ FSL_XCVR_RX_DPTH_CTRL_SET, 0x00002C89 },
{ FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00002C89 },
{ FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00002C89 },
+ { FSL_XCVR_RX_DPTH_CNTR_CTRL, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_CNTR_CTRL_SET, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_TSCR, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_BCR, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_BCTR, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_BCRR, 0x00000000 },
{ FSL_XCVR_TX_DPTH_CTRL, 0x00000000 },
{ FSL_XCVR_TX_DPTH_CTRL_SET, 0x00000000 },
{ FSL_XCVR_TX_DPTH_CTRL_CLR, 0x00000000 },
@@ -944,6 +952,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = {
{ FSL_XCVR_TX_CS_DATA_3, 0x00000000 },
{ FSL_XCVR_TX_CS_DATA_4, 0x00000000 },
{ FSL_XCVR_TX_CS_DATA_5, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CNTR_CTRL, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CNTR_CTRL_SET, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_TSCR, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_BCR, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_BCTR, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_BCRR, 0x00000000 },
{ FSL_XCVR_DEBUG_REG_0, 0x00000000 },
{ FSL_XCVR_DEBUG_REG_1, 0x00000000 },
};
@@ -975,6 +991,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
case FSL_XCVR_RX_DPTH_CTRL_SET:
case FSL_XCVR_RX_DPTH_CTRL_CLR:
case FSL_XCVR_RX_DPTH_CTRL_TOG:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
+ case FSL_XCVR_RX_DPTH_TSCR:
+ case FSL_XCVR_RX_DPTH_BCR:
+ case FSL_XCVR_RX_DPTH_BCTR:
+ case FSL_XCVR_RX_DPTH_BCRR:
case FSL_XCVR_TX_DPTH_CTRL:
case FSL_XCVR_TX_DPTH_CTRL_SET:
case FSL_XCVR_TX_DPTH_CTRL_CLR:
@@ -985,6 +1009,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
case FSL_XCVR_TX_CS_DATA_3:
case FSL_XCVR_TX_CS_DATA_4:
case FSL_XCVR_TX_CS_DATA_5:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG:
+ case FSL_XCVR_TX_DPTH_TSCR:
+ case FSL_XCVR_TX_DPTH_BCR:
+ case FSL_XCVR_TX_DPTH_BCTR:
+ case FSL_XCVR_TX_DPTH_BCRR:
case FSL_XCVR_DEBUG_REG_0:
case FSL_XCVR_DEBUG_REG_1:
return true;
@@ -1017,6 +1049,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
case FSL_XCVR_RX_DPTH_CTRL_SET:
case FSL_XCVR_RX_DPTH_CTRL_CLR:
case FSL_XCVR_RX_DPTH_CTRL_TOG:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
case FSL_XCVR_TX_DPTH_CTRL_SET:
case FSL_XCVR_TX_DPTH_CTRL_CLR:
case FSL_XCVR_TX_DPTH_CTRL_TOG:
@@ -1026,6 +1062,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
case FSL_XCVR_TX_CS_DATA_3:
case FSL_XCVR_TX_CS_DATA_4:
case FSL_XCVR_TX_CS_DATA_5:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG:
return true;
default:
return false;
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
index 7f2853c60085..4769b0fca21d 100644
--- a/sound/soc/fsl/fsl_xcvr.h
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -49,6 +49,16 @@
#define FSL_XCVR_RX_DPTH_CTRL_CLR 0x188
#define FSL_XCVR_RX_DPTH_CTRL_TOG 0x18c
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL 0x1C0
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_SET 0x1C4
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR 0x1C8
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG 0x1CC
+
+#define FSL_XCVR_RX_DPTH_TSCR 0x1D0
+#define FSL_XCVR_RX_DPTH_BCR 0x1D4
+#define FSL_XCVR_RX_DPTH_BCTR 0x1D8
+#define FSL_XCVR_RX_DPTH_BCRR 0x1DC
+
#define FSL_XCVR_TX_DPTH_CTRL 0x220 /* TX datapath ctrl reg */
#define FSL_XCVR_TX_DPTH_CTRL_SET 0x224
#define FSL_XCVR_TX_DPTH_CTRL_CLR 0x228
@@ -59,6 +69,17 @@
#define FSL_XCVR_TX_CS_DATA_3 0x23C
#define FSL_XCVR_TX_CS_DATA_4 0x240
#define FSL_XCVR_TX_CS_DATA_5 0x244
+
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL 0x260
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_SET 0x264
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR 0x268
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG 0x26C
+
+#define FSL_XCVR_TX_DPTH_TSCR 0x270
+#define FSL_XCVR_TX_DPTH_BCR 0x274
+#define FSL_XCVR_TX_DPTH_BCTR 0x278
+#define FSL_XCVR_TX_DPTH_BCRR 0x27C
+
#define FSL_XCVR_DEBUG_REG_0 0x2E0
#define FSL_XCVR_DEBUG_REG_1 0x2F0
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 905c3a071300..d5234ac4b09b 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -88,7 +88,7 @@ static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
/* Register platform driver for rpmsg routine */
data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
IMX_PCM_DRV_NAME,
- PLATFORM_DEVID_NONE,
+ PLATFORM_DEVID_AUTO,
NULL, 0);
if (IS_ERR(data->rpmsg_pdev)) {
dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
@@ -110,6 +110,7 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
{ .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
{ },
};
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 35049043e532..2f310994f7ee 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -178,7 +178,7 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
msg->s_msg.param.channels = RPMSG_CH_STEREO;
break;
default:
- ret = -EINVAL;
+ msg->s_msg.param.channels = params_channels(params);
break;
}
@@ -684,7 +684,7 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
info->dev = &pdev->dev;
/* Setup work queue */
- info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
+ info->rpmsg_wq = alloc_ordered_workqueue(info->rpdev->id.name,
WQ_HIGHPRI |
WQ_UNBOUND |
WQ_FREEZABLE);
@@ -723,11 +723,15 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
if (ret)
goto fail;
- component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
+ component = snd_soc_lookup_component(&pdev->dev, NULL);
if (!component) {
ret = -EINVAL;
goto fail;
}
+
+ /* platform component name is used by machine driver to link with */
+ component->name = info->rpdev->id.name;
+
#ifdef CONFIG_DEBUG_FS
component->debugfs_prefix = "rpmsg";
#endif
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 4d99f4858a14..89178106fe2c 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -58,6 +58,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
struct platform_device *rpmsg_pdev = to_platform_device(dev);
struct device_node *np = rpmsg_pdev->dev.of_node;
struct of_phandle_args args;
+ const char *platform_name;
struct imx_rpmsg *data;
int ret = 0;
@@ -109,7 +110,10 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
}
data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
- data->dai.platforms->name = IMX_PCM_DRV_NAME;
+ if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name))
+ data->dai.platforms->name = platform_name;
+ else
+ data->dai.platforms->name = "rpmsg-audio-channel";
data->dai.playback_only = true;
data->dai.capture_only = true;
data->card.num_links = 1;
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
index fe547c18771f..994db61a26b3 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
@@ -49,10 +49,13 @@
* +-+ +-+
*
* [DPCM]
+ *
+ * CPU3/CPU4 are converting rate to 44100
+ *
* FE BE
* ****
* cpu3 <-@--* *--@-> codec3
- * cpu4 <-@--* *
+ * cpu4 <-@--* * (44.1kHz)
* ****
*
* [DPCM-Multi]
@@ -286,7 +289,10 @@
port@2 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
/* [DPCM]::BE */
- port@3 { codec3_ep: endpoint { remote-endpoint = <&be00_ep>; }; };
+ port@3 {
+ convert-rate = <44100>;
+ codec3_ep: endpoint { remote-endpoint = <&be00_ep>; };
+ };
/* [DPCM-Multi]::BE */
port@4 { codec4_ep: endpoint { remote-endpoint = <&mbe1_ep>; }; };
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 8ac6df645ee6..06609a526b78 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -849,7 +849,8 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
goto err;
}
- graph_parse_convert(rep, dai_props);
+ graph_parse_convert(ep, dai_props); /* at node of <dpcm> */
+ graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
snd_soc_dai_link_set_capabilities(dai_link);
@@ -1271,9 +1272,6 @@ err:
if (ret < 0)
dev_err_probe(dev, ret, "parse error\n");
- if (ret == 0)
- dev_warn(dev, "Audio Graph Card2 is still under Experimental stage\n");
-
return ret;
}
EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index be69bbc47f81..e35becce9635 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -41,27 +41,6 @@ static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
}
}
-void asoc_simple_convert_fixup(struct asoc_simple_data *data,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- if (data->convert_rate)
- rate->min =
- rate->max = data->convert_rate;
-
- if (data->convert_channels)
- channels->min =
- channels->max = data->convert_channels;
-
- if (data->convert_sample_format)
- asoc_simple_fixup_sample_fmt(data, params);
-}
-EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
-
void asoc_simple_parse_convert(struct device_node *np,
char *prefix,
struct asoc_simple_data *data)
@@ -522,8 +501,20 @@ int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+ struct asoc_simple_data *data = &dai_props->adata;
+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (data->convert_rate)
+ rate->min =
+ rate->max = data->convert_rate;
- asoc_simple_convert_fixup(&dai_props->adata, params);
+ if (data->convert_channels)
+ channels->min =
+ channels->max = data->convert_channels;
+
+ if (data->convert_sample_format)
+ asoc_simple_fixup_sample_fmt(data, params);
return 0;
}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index d2ca710ac3fa..ac799de4f7fd 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -177,7 +177,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
- select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
+ select SND_SOC_HDAC_HDA
select SND_SOC_ACPI_INTEL_MATCH
select SND_INTEL_DSP_CONFIG
help
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b8e2b23c9f64..7c8ce98eda9d 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -133,12 +133,14 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
buf = apl_log_payload_addr(addr);
memcpy_fromio(&layout, addr, sizeof(layout));
if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+ union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+
/*
* DSP awaits the remaining logs to be
* gathered before dumping stack
*/
- msg->log.core = msg->ext.coredump.core_id;
- avs_dsp_op(adev, log_buffer_status, msg);
+ lbs_msg.log.core = msg->ext.coredump.core_id;
+ avs_dsp_op(adev, log_buffer_status, &lbs_msg);
}
pos = dump + AVS_FW_REGS_SIZE;
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 92e37722d280..8d05b27608fe 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -24,6 +24,13 @@ struct avs_tplg_library;
struct avs_soc_component;
struct avs_ipc_msg;
+#ifdef CONFIG_ACPI
+#define AVS_S0IX_SUPPORTED \
+ (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
+#else
+#define AVS_S0IX_SUPPORTED false
+#endif
+
/*
* struct avs_dsp_ops - Platform-specific DSP operations
*
@@ -127,6 +134,7 @@ struct avs_dev {
struct list_head fw_list;
int *core_refs; /* reference count per core */
char **lib_names;
+ int num_lp_paths;
struct completion fw_ready;
struct work_struct probe_work;
@@ -220,8 +228,10 @@ static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
/*
* If IPC channel is blocked e.g.: due to ongoing recovery,
* -EPERM error code is expected and thus it's not an actual error.
+ *
+ * Unsupported IPCs are of no harm either.
*/
- if (error == -EPERM)
+ if (error == -EPERM || error == AVS_IPC_NOT_SUPPORTED)
dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
tx->glb.primary, tx->glb.ext.val, error);
else
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 87f9c18be238..02cc1ce8f5f5 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -29,6 +29,12 @@ static const struct dmi_system_id kbl_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
+ },
+ },
{}
};
@@ -122,6 +128,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "rt298-tplg.bin",
},
{
+ .id = "MX98927",
+ .drv_name = "avs_max98927",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "max98927-tplg.bin",
+ },
+ {
.id = "MX98373",
.drv_name = "avs_max98373",
.mach_params = {
@@ -130,6 +144,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "max98373-tplg.bin",
},
{
+ .id = "MX98357A",
+ .drv_name = "avs_max98357a",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "max98357a-tplg.bin",
+ },
+ {
.id = "DLGS7219",
.drv_name = "avs_da7219",
.mach_params = {
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 4d68e3ef992b..9bd40fdd9028 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -36,6 +36,16 @@ config SND_SOC_INTEL_AVS_MACH_I2S_TEST
This adds support for I2S test-board which can be used to verify
transfer over I2S interface with SSP loopback scenarios.
+config SND_SOC_INTEL_AVS_MACH_MAX98927
+ tristate "max98927 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98927
+ help
+ This adds support for AVS with MAX98927 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_MAX98357A
tristate "max98357A I2S board"
depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index bc75376d58c2..4d70b8d09ce5 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -4,6 +4,7 @@ snd-soc-avs-da7219-objs := da7219.o
snd-soc-avs-dmic-objs := dmic.o
snd-soc-avs-hdaudio-objs := hdaudio.o
snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98927-objs := max98927.o
snd-soc-avs-max98357a-objs := max98357a.o
snd-soc-avs-max98373-objs := max98373.o
snd-soc-avs-nau8825-objs := nau8825.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 02ae542ad779..acd43b6108e9 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -6,6 +6,7 @@
//
#include <linux/module.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -15,7 +16,6 @@
#include <sound/soc-dapm.h>
#include <uapi/linux/input-event-codes.h>
#include "../../../codecs/da7219.h"
-#include "../../../codecs/da7219-aad.h"
#define DA7219_DAI_NAME "da7219-hifi"
@@ -72,15 +72,18 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
struct snd_soc_card *card = runtime->card;
struct snd_soc_jack *jack;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
int clk_freq;
int ret;
jack = snd_soc_card_get_drvdata(card);
- clk_freq = 19200000;
+ if (soc_intel_is_apl())
+ clk_freq = 19200000;
+ else /* kbl */
+ clk_freq = 24576000;
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
if (ret) {
@@ -106,9 +109,12 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, jack);
+ return snd_soc_component_set_jack(component, jack, NULL);
+}
- return 0;
+static void avs_da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
@@ -143,6 +149,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->id = 0;
dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_da7219_codec_init;
+ dl->exit = avs_da7219_codec_exit;
dl->nonatomic = 1;
dl->no_pcm = 1;
dl->dpcm_capture = 1;
@@ -185,30 +192,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_da7219_probe(struct platform_device *pdev)
@@ -246,7 +242,6 @@ static int avs_da7219_probe(struct platform_device *pdev)
card->name = "avs_da7219";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 073663ba140d..e68c4c7aa2ba 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/hda_codec.h>
#include <sound/hda_i915.h>
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 0fa8f5606385..8e221ecd34b0 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -53,7 +53,7 @@ avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_par
channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
new file mode 100644
index 000000000000..7cccce99f92e
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98927_DEV0_NAME "i2c-MX98927:00"
+#define MAX98927_DEV1_NAME "i2c-MX98927:01"
+#define MAX98927_CODEC_NAME "max98927-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98927_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 16 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int avs_max98927_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+ int i;
+
+ for_each_rtd_codec_dais(runtime, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ else if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+
+ if (ret < 0) {
+ dev_err(runtime->dev, "hw_params for %s failed: %d\n",
+ codec_dai->component->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_max98927_ops = {
+ .hw_params = avs_max98927_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV0_NAME);
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV1_NAME);
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->be_hw_params_fixup = avs_max98927_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+ dl->ops = &avs_max98927_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98927_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98927";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98927_driver = {
+ .probe = avs_max98927_probe,
+ .driver = {
+ .name = "avs_max98927",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98927_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98927");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index f76909e9f990..6731d8a49076 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -79,11 +79,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_card *card = runtime->card;
struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
- struct snd_soc_card *card = runtime->card;
int num_pins, ret;
jack = snd_soc_card_get_drvdata(card);
@@ -108,11 +106,12 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- //snd_soc_component_set_jack(component, jack, NULL);
- // TODO: Fix nau8825 codec to use .set_jack, like everyone else
- nau8825_enable_jack_detect(component, jack);
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int
@@ -203,6 +202,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->id = 0;
dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_nau8825_codec_init;
+ dl->exit = avs_nau8825_codec_exit;
dl->be_hw_params_fixup = avs_nau8825_be_fixup;
dl->ops = &avs_nau8825_ops;
dl->nonatomic = 1;
@@ -247,23 +247,11 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
@@ -280,7 +268,7 @@ static int avs_card_resume_post(struct snd_soc_card *card)
codec_dai->playback_widget->active)
snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_nau8825_probe(struct platform_device *pdev)
@@ -318,7 +306,6 @@ static int avs_nau8825_probe(struct platform_device *pdev)
card->name = "avs_nau8825";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index afef5a3ca60b..6a1e121f082f 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -119,6 +119,11 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
return 0;
}
+static void avs_rt274_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+}
+
static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
{
struct snd_interval *rate, *channels;
@@ -160,7 +165,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
- dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT274_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -171,6 +176,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->id = 0;
dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_rt274_codec_init;
+ dl->exit = avs_rt274_codec_exit;
dl->be_hw_params_fixup = avs_rt274_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
@@ -214,30 +220,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt274_probe(struct platform_device *pdev)
@@ -275,7 +270,6 @@ static int avs_rt274_probe(struct platform_device *pdev)
card->name = "avs_rt274";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index e51d4e181274..8447b37a2a41 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -14,6 +14,8 @@
#include <sound/soc-acpi.h>
#include "../../../codecs/rt286.h"
+#define RT286_CODEC_DAI "rt286-aif1"
+
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -48,10 +50,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
- struct snd_soc_card *card = runtime->card;
int num_pins, ret;
jack = snd_soc_card_get_drvdata(card);
@@ -66,9 +67,12 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
- snd_soc_component_set_jack(component, jack, NULL);
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_rt286_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -130,7 +134,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
- dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT286_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -141,6 +145,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->id = 0;
dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_rt286_codec_init;
+ dl->exit = avs_rt286_codec_exit;
dl->be_hw_params_fixup = avs_rt286_be_fixup;
dl->ops = &avs_rt286_ops;
dl->nonatomic = 1;
@@ -185,30 +190,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT286_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT286_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt286_probe(struct platform_device *pdev)
@@ -246,7 +240,6 @@ static int avs_rt286_probe(struct platform_device *pdev)
card->name = "avs_rt286";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index b28d36872dcb..bd25f0fde35e 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/dmi.h>
#include <linux/module.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -14,6 +15,18 @@
#include <sound/soc-acpi.h>
#include "../../../codecs/rt298.h"
+#define RT298_CODEC_DAI "rt298-aif1"
+
+static const struct dmi_system_id kblr_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
+ },
+ },
+ {}
+};
+
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -48,10 +61,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
- struct snd_soc_card *card = runtime->card;
int num_pins, ret;
jack = snd_soc_card_get_drvdata(card);
@@ -66,9 +78,12 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
- snd_soc_component_set_jack(component, jack, NULL);
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_rt298_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -96,9 +111,15 @@ avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_param
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ unsigned int clk_freq;
int ret;
- ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+ if (dmi_first_match(kblr_dmi_table))
+ clk_freq = 24000000;
+ else
+ clk_freq = 19200000;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, clk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
@@ -130,7 +151,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
- dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT298_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -139,8 +160,12 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ if (dmi_first_match(kblr_dmi_table))
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ else
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_rt298_codec_init;
+ dl->exit = avs_rt298_codec_exit;
dl->be_hw_params_fixup = avs_rt298_be_fixup;
dl->ops = &avs_rt298_ops;
dl->nonatomic = 1;
@@ -185,30 +210,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT298_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT298_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt298_probe(struct platform_device *pdev)
@@ -246,7 +260,6 @@ static int avs_rt298_probe(struct platform_device *pdev)
card->name = "avs_rt298";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 01f9b9f0c12b..473e9fe5d0bf 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -26,6 +26,7 @@
#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
#define AVS_RT5682_MCLK_EN BIT(3)
#define AVS_RT5682_MCLK_24MHZ BIT(4)
+#define AVS_RT5682_CODEC_DAI_NAME "rt5682-aif1"
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
@@ -119,6 +120,11 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
return 0;
};
+static void avs_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+}
+
static int
avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
@@ -184,7 +190,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
- dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, AVS_RT5682_CODEC_DAI_NAME);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -194,6 +200,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->num_platforms = 1;
dl->id = 0;
dl->init = avs_rt5682_codec_init;
+ dl->exit = avs_rt5682_codec_exit;
dl->ops = &avs_rt5682_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
@@ -237,30 +244,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
return 0;
}
-static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component)
- snd_soc_component_set_jack(component, jack, NULL);
- return 0;
-}
-
-static int avs_card_remove(struct snd_soc_card *card)
-{
- return avs_card_set_jack(card, NULL);
-}
-
static int avs_card_suspend_pre(struct snd_soc_card *card)
{
- return avs_card_set_jack(card, NULL);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, AVS_RT5682_CODEC_DAI_NAME);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, AVS_RT5682_CODEC_DAI_NAME);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt5682_probe(struct platform_device *pdev)
@@ -304,7 +300,6 @@ static int avs_rt5682_probe(struct platform_device *pdev)
card->name = "avs_rt5682";
card->dev = dev;
card->owner = THIS_MODULE;
- card->remove = avs_card_remove;
card->suspend_pre = avs_card_suspend_pre;
card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index 9f84c8ab3447..c5db69612762 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -103,7 +103,7 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para
channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index bb0719c58ca4..f7bc06404dbc 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -27,6 +27,14 @@
#include "avs.h"
#include "cldma.h"
+static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
+module_param(pgctl_mask, uint, 0444);
+MODULE_PARM_DESC(pgctl_mask, "PCI PGCTL policy override");
+
+static u32 cgctl_mask = AZX_CGCTL_MISCBDCGE_MASK;
+module_param(cgctl_mask, uint, 0444);
+MODULE_PARM_DESC(cgctl_mask, "PCI CGCTL policy override");
+
static void
avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
{
@@ -41,19 +49,16 @@ avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
{
- u32 value;
+ u32 value = enable ? 0 : pgctl_mask;
- value = enable ? 0 : AZX_PGCTL_LSRMD_MASK;
- avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL,
- AZX_PGCTL_LSRMD_MASK, value);
+ avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value);
}
static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable)
{
- u32 value;
+ u32 value = enable ? cgctl_mask : 0;
- value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
- avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, value);
+ avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value);
}
void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
@@ -63,9 +68,8 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
{
- u32 value;
+ u32 value = enable ? AZX_VS_EM2_L1SEN : 0;
- value = enable ? AZX_VS_EM2_L1SEN : 0;
snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
}
@@ -440,7 +444,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
- if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
dma_set_max_seg_size(dev, UINT_MAX);
@@ -504,7 +508,7 @@ static void avs_pci_remove(struct pci_dev *pci)
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
/* reverse ml_capabilities */
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
snd_hdac_ext_bus_exit(bus);
avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
@@ -534,12 +538,30 @@ static void avs_pci_remove(struct pci_dev *pci)
pm_runtime_get_noresume(&pci->dev);
}
-static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
+static int avs_suspend_standby(struct avs_dev *adev)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct pci_dev *pci = adev->base.pci;
+
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_stop_cmd_io(bus);
+
+ snd_hdac_ext_bus_link_power_down_all(bus);
+
+ enable_irq_wake(pci->irq);
+ pci_save_state(pci);
+
+ return 0;
+}
+
+static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
flush_work(&adev->probe_work);
+ if (low_power && adev->num_lp_paths)
+ return avs_suspend_standby(adev);
snd_hdac_ext_bus_link_power_down_all(bus);
@@ -577,12 +599,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
+static int avs_resume_standby(struct avs_dev *adev)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct pci_dev *pci = adev->base.pci;
+
+ pci_restore_state(pci);
+ disable_irq_wake(pci->irq);
+
+ snd_hdac_ext_bus_link_power_up_all(bus);
+
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_init_cmd_io(bus);
+
+ return 0;
+}
+
+static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
{
struct hdac_bus *bus = &adev->base.core;
- struct hdac_ext_link *hlink;
int ret;
+ if (low_power && adev->num_lp_paths)
+ return avs_resume_standby(adev);
+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
avs_hdac_bus_init_chip(bus, true);
@@ -595,41 +635,55 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
return ret;
}
- /* turn off the links that were off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- /* check dma status and clean up CORB/RIRB buffers */
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
-
return 0;
}
static int __maybe_unused avs_suspend(struct device *dev)
{
- return avs_suspend_common(to_avs_dev(dev));
+ return avs_suspend_common(to_avs_dev(dev), true);
}
static int __maybe_unused avs_resume(struct device *dev)
{
- return avs_resume_common(to_avs_dev(dev), true);
+ return avs_resume_common(to_avs_dev(dev), true, true);
}
static int __maybe_unused avs_runtime_suspend(struct device *dev)
{
- return avs_suspend_common(to_avs_dev(dev));
+ return avs_suspend_common(to_avs_dev(dev), true);
}
static int __maybe_unused avs_runtime_resume(struct device *dev)
{
- return avs_resume_common(to_avs_dev(dev), true);
+ return avs_resume_common(to_avs_dev(dev), true, false);
+}
+
+static int __maybe_unused avs_freeze(struct device *dev)
+{
+ return avs_suspend_common(to_avs_dev(dev), false);
+}
+static int __maybe_unused avs_thaw(struct device *dev)
+{
+ return avs_resume_common(to_avs_dev(dev), false, true);
+}
+
+static int __maybe_unused avs_poweroff(struct device *dev)
+{
+ return avs_suspend_common(to_avs_dev(dev), false);
+}
+
+static int __maybe_unused avs_restore(struct device *dev)
+{
+ return avs_resume_common(to_avs_dev(dev), false, true);
}
static const struct dev_pm_ops avs_dev_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume)
+ .suspend = avs_suspend,
+ .resume = avs_resume,
+ .freeze = avs_freeze,
+ .thaw = avs_thaw,
+ .poweroff = avs_poweroff,
+ .restore = avs_restore,
SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
};
@@ -667,7 +721,11 @@ static const struct avs_spec apl_desc = {
static const struct pci_device_id avs_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
+ { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
+ { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
+ { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
+ { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
{ PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
{ PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
{ 0 }
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 020d85c7520d..af8a260093f4 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -74,7 +74,7 @@ int avs_dsp_disable_d0ix(struct avs_dev *adev)
struct avs_ipc *ipc = adev->ipc;
/* Prevent PG only on the first disable. */
- if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) {
+ if (atomic_inc_return(&ipc->d0ix_disable_depth) == 1) {
cancel_delayed_work_sync(&ipc->d0ix_work);
return avs_dsp_set_d0ix(adev, false);
}
@@ -123,7 +123,10 @@ static void avs_dsp_recovery(struct avs_dev *adev)
if (!substream || !substream->runtime)
continue;
+ /* No need for _irq() as we are in nonatomic context. */
+ snd_pcm_stream_lock(substream);
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock(substream);
}
}
}
@@ -192,7 +195,8 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
/* update size in case of LARGE_CONFIG_GET */
if (msg.msg_target == AVS_MOD_MSG &&
msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
- ipc->rx.size = msg.ext.large_config.data_off_size;
+ ipc->rx.size = min_t(u32, AVS_MAILBOX_SIZE,
+ msg.ext.large_config.data_off_size);
memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size);
trace_avs_msg_payload(ipc->rx.data, ipc->rx.size);
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 9e3f8ff33a87..56bb0a59249d 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -43,7 +43,7 @@
/* Occasionally, engineering (release candidate) firmware is provided for testing. */
static bool debug_ignore_fw_version;
module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);
-MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes (default), 1=no");
+MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes");
#define AVS_LIB_NAME_SIZE 8
@@ -224,11 +224,19 @@ static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *
if (ret < 0)
return ret;
+ avs_hda_power_gating_enable(adev, false);
+ avs_hda_clock_gating_enable(adev, false);
+ avs_hda_l1sen_enable(adev, false);
+
hda_cldma_set_data(cl, (void *)mod->data, mod->size);
hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));
ret = avs_ipc_load_modules(adev, &mentry->module_id, 1);
hda_cldma_stop(cl);
+ avs_hda_l1sen_enable(adev, true);
+ avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
+
if (ret) {
dev_err(adev->dev, "load module %d failed: %d\n", mentry->module_id, ret);
avs_release_last_firmware(adev);
@@ -369,8 +377,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
- ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
+ snd_hdac_stream_spbcap_enable(bus, true, hstream->index);
+ ret = snd_hdac_stream_set_spib(bus, hstream, fw->size);
if (ret)
goto cleanup_resources;
@@ -400,8 +408,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
cleanup_resources:
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, hstream->index);
+ snd_hdac_stream_set_spib(bus, hstream, 0);
snd_hdac_dsp_cleanup(hstream, &dmab);
release_stream:
@@ -436,8 +444,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
+ snd_hdac_stream_spbcap_enable(bus, true, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, lib->size);
memcpy(dmab.area, lib->data, lib->size);
@@ -451,8 +459,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
}
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, 0);
snd_hdac_dsp_cleanup(stream, &dmab);
release_stream:
@@ -605,6 +613,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
+ avs_hda_power_gating_enable(adev, false);
avs_hda_clock_gating_enable(adev, false);
avs_hda_l1sen_enable(adev, false);
@@ -625,6 +634,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
reenable_gating:
avs_hda_l1sen_enable(adev, true);
avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index d4bcee1aabcf..6b0fecbf07c3 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -687,20 +687,13 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
{
- int ret;
-
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_ENABLE_LOGS, log_info, size);
- if (ret)
- dev_err(adev->dev, "enable logs failed: %d\n", ret);
-
- return ret;
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_ENABLE_LOGS, log_info, size);
}
int avs_ipc_set_system_time(struct avs_dev *adev)
{
struct avs_sys_time sys_time;
- int ret;
u64 us;
/* firmware expects UTC time in micro seconds */
@@ -708,12 +701,8 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
sys_time.val_l = us & UINT_MAX;
sys_time.val_u = us >> 32;
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
- if (ret)
- dev_err(adev->dev, "set system time failed: %d\n", ret);
-
- return ret;
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
}
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index c0f90dba9af8..02b3b7a74783 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -150,6 +150,8 @@ union avs_module_msg {
};
} __packed;
+#define AVS_IPC_NOT_SUPPORTED 15
+
union avs_reply_msg {
u64 val;
struct {
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 8fe5917b1e26..70d687fa9923 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -28,6 +28,8 @@ struct avs_dma_data {
* host stream assigned
*/
struct hdac_ext_stream *host_stream;
+
+ struct snd_pcm_substream *substream;
};
static struct avs_tplg_path_template *
@@ -55,8 +57,11 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
return dw->priv;
}
-static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe)
+static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe,
+ const struct snd_soc_dai_ops *ops)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_tplg_path_template *template;
struct avs_dma_data *data;
@@ -71,9 +76,13 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
if (!data)
return -ENOMEM;
+ data->substream = substream;
data->template = template;
snd_soc_dai_set_dma_data(dai, substream, data);
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths++;
+
return 0;
}
@@ -151,15 +160,22 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
return ret;
}
+static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops;
+
static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_startup(substream, dai, false);
+ return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops);
}
static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_dma_data *data;
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths--;
+
data = snd_soc_dai_get_dma_data(dai, substream);
snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -202,30 +218,43 @@ static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct
static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct avs_dma_data *data;
int ret = 0;
data = snd_soc_dai_get_dma_data(dai, substream);
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+ break;
+ }
+
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run BE path failed: %d\n", ret);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset BE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset BE path failed: %d\n", ret);
break;
default:
@@ -245,9 +274,11 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
.trigger = avs_dai_nonhda_be_trigger,
};
+static const struct snd_soc_dai_ops avs_dai_hda_be_ops;
+
static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_startup(substream, dai, false);
+ return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops);
}
static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -292,12 +323,12 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn
/* clear link <-> stream mapping */
codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
return 0;
}
@@ -322,15 +353,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
runtime->sample_bits, 0);
snd_hdac_ext_stream_decouple(bus, link_stream, true);
- snd_hdac_ext_link_stream_reset(link_stream);
- snd_hdac_ext_link_stream_setup(link_stream, format_val);
+ snd_hdac_ext_stream_reset(link_stream);
+ snd_hdac_ext_stream_setup(link_stream, format_val);
- link = snd_hdac_ext_bus_link_at(bus, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
if (ret)
@@ -343,6 +374,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct hdac_ext_stream *link_stream;
struct avs_dma_data *data;
int ret = 0;
@@ -353,28 +385,40 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
link_stream = substream->runtime->private_data;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_stream);
+ snd_hdac_ext_stream_start(link_stream);
+
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+ break;
+ }
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run BE path failed: %d\n", ret);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- snd_hdac_ext_link_stream_clear(link_stream);
+ snd_hdac_ext_stream_clear(link_stream);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset BE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset BE path failed: %d\n", ret);
break;
default:
@@ -407,6 +451,8 @@ static const struct snd_pcm_hw_constraint_list hw_rates = {
.mask = 0,
};
+const struct snd_soc_dai_ops avs_dai_fe_ops;
+
static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -416,7 +462,7 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
struct hdac_ext_stream *host_stream;
int ret;
- ret = avs_dai_startup(substream, dai, true);
+ ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops);
if (ret)
return ret;
@@ -443,8 +489,13 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_dma_data *data;
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths--;
+
data = snd_soc_dai_get_dma_data(dai, substream);
snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -499,7 +550,7 @@ create_err:
return ret;
}
-static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+static int __avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
@@ -523,9 +574,15 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so
snd_hdac_stream_cleanup(hdac_stream(host_stream));
hdac_stream(host_stream)->prepared = false;
- ret = snd_pcm_lib_free_pages(substream);
- if (ret < 0)
- dev_dbg(dai->dev, "Failed to free pages!\n");
+ return ret;
+}
+
+static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = __avs_dai_fe_hw_free(substream, dai);
+ snd_pcm_lib_free_pages(substream);
return ret;
}
@@ -571,6 +628,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
struct hdac_bus *bus;
@@ -582,17 +640,36 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
bus = hdac_stream(host_stream)->bus;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
spin_lock_irqsave(&bus->reg_lock, flags);
snd_hdac_stream_start(hdac_stream(host_stream), true);
spin_unlock_irqrestore(&bus->reg_lock, flags);
+ /* Timeout on DRSM poll shall not stop the resume so ignore the result. */
+ if (cmd == SNDRV_PCM_TRIGGER_RESUME)
+ snd_hdac_stream_wait_drsm(hdac_stream(host_stream));
+
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause FE path failed: %d\n", ret);
+ break;
+ }
+
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run FE path failed: %d\n", ret);
+
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
@@ -603,11 +680,9 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
snd_hdac_stream_stop(hdac_stream(host_stream));
spin_unlock_irqrestore(&bus->reg_lock, flags);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset FE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset FE path failed: %d\n", ret);
break;
default:
@@ -662,6 +737,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
if (ret < 0)
return ret;
+ avs_hda_power_gating_enable(adev, false);
avs_hda_clock_gating_enable(adev, false);
avs_hda_l1sen_enable(adev, false);
@@ -669,6 +745,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
avs_hda_l1sen_enable(adev, true);
avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
if (!ret)
ret = avs_module_info_init(adev, false);
@@ -752,33 +829,232 @@ static void avs_component_remove(struct snd_soc_component *component)
}
}
+static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret;
+
+ substream = data->substream;
+ rtd = snd_pcm_substream_chip(substream);
+
+ ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai);
+ if (ret)
+ dev_err(dai->dev, "hw_params on resume failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_resume_fe_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct hdac_ext_stream *host_stream;
+ struct hdac_stream *hstream;
+ struct hdac_bus *bus;
+ int ret;
+
+ host_stream = data->host_stream;
+ hstream = hdac_stream(host_stream);
+ bus = hdac_stream(host_stream)->bus;
+
+ /* Set DRSM before programming stream and position registers. */
+ snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+
+ ret = dai->driver->ops->prepare(data->substream, dai);
+ if (ret) {
+ dev_err(dai->dev, "prepare FE on resume failed: %d\n", ret);
+ return ret;
+ }
+
+ writel(host_stream->pphcllpl, host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+ writel(host_stream->pphcllpu, host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+ writel(host_stream->pphcldpl, host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ writel(host_stream->pphcldpu, host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ /* As per HW spec recommendation, program LPIB and DPIB to the same value. */
+ snd_hdac_stream_set_lpib(hstream, hstream->lpib);
+ snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+
+ return 0;
+}
+
+static int avs_dai_resume_be_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ int ret;
+
+ ret = dai->driver->ops->prepare(data->substream, dai);
+ if (ret)
+ dev_err(dai->dev, "prepare BE on resume failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_suspend_fe_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct hdac_ext_stream *host_stream;
+ int ret;
+
+ host_stream = data->host_stream;
+
+ /* Store position addresses so we can resume from them later on. */
+ hdac_stream(host_stream)->lpib = snd_hdac_stream_get_pos_lpib(hdac_stream(host_stream));
+ host_stream->pphcllpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+ host_stream->pphcllpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+ host_stream->pphcldpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ host_stream->pphcldpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ ret = __avs_dai_fe_hw_free(data->substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev, "hw_free FE on suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_suspend_be_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ int ret;
+
+ ret = dai->driver->ops->hw_free(data->substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev, "hw_free BE on suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_component_pm_op(struct snd_soc_component *component, bool be,
+ int (*op)(struct snd_soc_dai *, struct avs_dma_data *))
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct avs_dma_data *data;
+ struct snd_soc_dai *dai;
+ int ret;
+
+ for_each_component_dais(component, dai) {
+ data = dai->playback_dma_data;
+ if (data) {
+ rtd = snd_pcm_substream_chip(data->substream);
+ if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+ ret = op(dai, data);
+ if (ret < 0) {
+ __snd_pcm_set_state(data->substream->runtime,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ return ret;
+ }
+ }
+ }
+
+ data = dai->capture_dma_data;
+ if (data) {
+ rtd = snd_pcm_substream_chip(data->substream);
+ if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+ ret = op(dai, data);
+ if (ret < 0) {
+ __snd_pcm_set_state(data->substream->runtime,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int avs_component_resume_hw_params(struct snd_soc_component *component, bool be)
+{
+ return avs_component_pm_op(component, be, &avs_dai_resume_hw_params);
+}
+
+static int avs_component_resume_prepare(struct snd_soc_component *component, bool be)
+{
+ int (*prepare_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+ if (be)
+ prepare_cb = &avs_dai_resume_be_prepare;
+ else
+ prepare_cb = &avs_dai_resume_fe_prepare;
+
+ return avs_component_pm_op(component, be, prepare_cb);
+}
+
+static int avs_component_suspend_hw_free(struct snd_soc_component *component, bool be)
+{
+ int (*hw_free_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+ if (be)
+ hw_free_cb = &avs_dai_suspend_be_hw_free;
+ else
+ hw_free_cb = &avs_dai_suspend_fe_hw_free;
+
+ return avs_component_pm_op(component, be, hw_free_cb);
+}
+
+static int avs_component_suspend(struct snd_soc_component *component)
+{
+ int ret;
+
+ /*
+ * When freeing paths, FEs need to be first as they perform
+ * path unbinding.
+ */
+ ret = avs_component_suspend_hw_free(component, false);
+ if (ret)
+ return ret;
+
+ return avs_component_suspend_hw_free(component, true);
+}
+
+static int avs_component_resume(struct snd_soc_component *component)
+{
+ int ret;
+
+ /*
+ * When creating paths, FEs need to be last as they perform
+ * path binding.
+ */
+ ret = avs_component_resume_hw_params(component, true);
+ if (ret)
+ return ret;
+
+ ret = avs_component_resume_hw_params(component, false);
+ if (ret)
+ return ret;
+
+ /* It is expected that the LINK stream is prepared first. */
+ ret = avs_component_resume_prepare(component, true);
+ if (ret)
+ return ret;
+
+ return avs_component_resume_prepare(component, false);
+}
+
+static const struct snd_pcm_hardware avs_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .buffer_bytes_max = AZX_MAX_BUF_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
+ .periods_min = 2,
+ .periods_max = AZX_MAX_FRAG,
+ .fifo_size = 0,
+};
+
static int avs_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_pcm_hardware hwparams;
/* only FE DAI links are handled here */
if (rtd->dai_link->no_pcm)
return 0;
- hwparams.info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
-
- hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE;
- hwparams.period_bytes_min = 128;
- hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
- hwparams.periods_min = 2;
- hwparams.periods_max = AZX_MAX_FRAG;
- hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
- hwparams.fifo_size = 0;
-
- return snd_soc_set_runtime_hwparams(substream, &hwparams);
+ return snd_soc_set_runtime_hwparams(substream, &avs_pcm_hardware);
}
static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
@@ -840,6 +1116,8 @@ static const struct snd_soc_component_driver avs_component_driver = {
.name = "avs-pcm",
.probe = avs_component_probe,
.remove = avs_component_remove,
+ .suspend = avs_component_suspend,
+ .resume = avs_component_resume,
.open = avs_component_open,
.pointer = avs_component_pointer,
.mmap = avs_component_mmap,
@@ -1016,10 +1294,8 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen
if (!strstr(dai->driver->name, name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
}
}
@@ -1122,9 +1398,35 @@ static int avs_component_hda_open(struct snd_soc_component *component,
struct hdac_ext_stream *link_stream;
struct hda_codec *codec;
- /* only BE DAI links are handled here */
- if (!rtd->dai_link->no_pcm)
- return avs_component_open(component, substream);
+ if (!rtd->dai_link->no_pcm) {
+ struct snd_pcm_hardware hwparams = avs_pcm_hardware;
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_dpcm *dpcm;
+ int dir = substream->stream;
+
+ /*
+ * Support the DPCM reparenting while still fulfilling expectations of HDAudio
+ * common code - a valid stream pointer at substream->runtime->private_data -
+ * by having all FEs point to the same private data.
+ */
+ for_each_dpcm_be(rtd, dir, dpcm) {
+ struct snd_pcm_substream *be_substream;
+
+ be = dpcm->be;
+ if (be->dpcm[dir].users == 1)
+ break;
+
+ be_substream = snd_soc_dpcm_get_substream(be, dir);
+ substream->runtime->private_data = be_substream->runtime->private_data;
+ break;
+ }
+
+ /* RESUME unsupported for de-coupled HD-Audio capture. */
+ if (dir == SNDRV_PCM_STREAM_CAPTURE)
+ hwparams.info &= ~SNDRV_PCM_INFO_RESUME;
+
+ return snd_soc_set_runtime_hwparams(substream, &hwparams);
+ }
codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,
@@ -1157,6 +1459,8 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
.name = "avs-hda-pcm",
.probe = avs_component_hda_probe,
.remove = avs_component_hda_remove,
+ .suspend = avs_component_suspend,
+ .resume = avs_component_resume,
.open = avs_component_hda_open,
.close = avs_component_hda_close,
.pointer = avs_component_pointer,
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
index bda5ec7510fe..dc98b5cf900f 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -28,12 +28,12 @@ static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
info->core_mask = resource_mask;
if (enable)
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0)) {
+ for_each_set_bit(i, &resource_mask, num_cores) {
info->logs_core[i].enable = enable;
info->logs_core[i].min_priority = *priorities++;
}
else
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0))
+ for_each_set_bit(i, &resource_mask, num_cores)
info->logs_core[i].enable = enable;
ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 8a9f9fc48938..e845eaf0a1e7 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
if (!le32_to_cpu(dw->priv.size))
return 0;
+ if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+ dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+ w->ignore_suspend = false;
+ }
+
tplg = acomp->tplg;
mach = dev_get_platdata(comp->card->dev);
@@ -1442,6 +1447,11 @@ static int avs_dai_load(struct snd_soc_component *comp, int index,
static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg)
{
+ if (link->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+ dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+ link->ignore_suspend = false;
+ }
+
if (!link->no_pcm) {
/* Stream control handled by IPCs. */
link->nonatomic = true;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index aa12d7e3dd2f..a472de1909f4 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -668,6 +668,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_RT1308_SDW
select SND_SOC_RT1308
select SND_SOC_RT1316_SDW
+ select SND_SOC_RT1318_SDW
select SND_SOC_RT715_SDW
select SND_SOC_RT715_SDCA_SDW
select SND_SOC_RT5682_SDW
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 53458e748191..7e1a4ff77ac3 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -37,8 +37,8 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
snd-soc-ehl-rt5660-objs := ehl_rt5660.o
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
snd-soc-sof-sdw-objs += sof_sdw.o \
- sof_sdw_max98373.o \
- sof_sdw_rt1308.o sof_sdw_rt1316.o \
+ sof_sdw_max98373.o sof_sdw_rt1308.o \
+ sof_sdw_rt1316.o sof_sdw_rt1318.o \
sof_sdw_rt5682.o sof_sdw_rt700.o \
sof_sdw_rt711.o sof_sdw_rt711_sdca.o \
sof_sdw_rt715.o sof_sdw_rt715_sdca.o \
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index 67c3f49b924c..d0682bc543c9 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -88,7 +88,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *chan = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The ADSP will covert the FE rate to 48k, max 4-channels */
+ /* The ADSP will convert the FE rate to 48k, max 4-channels */
rate->min = rate->max = 48000;
chan->min = 2;
chan->max = 4;
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 31488702768e..f3e08d258ac1 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -141,7 +141,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *chan = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
index 6b76df0e7c9b..b7687a93a923 100644
--- a/sound/soc/intel/boards/bdw_rt286.c
+++ b/sound/soc/intel/boards/bdw_rt286.c
@@ -73,6 +73,13 @@ static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
return snd_soc_component_set_jack(codec, &card_headset, NULL);
}
+static void codec_link_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(codec, NULL, NULL);
+}
+
static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -165,6 +172,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.no_pcm = 1,
.init = codec_link_init,
+ .exit = codec_link_exit,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = codec_link_hw_params_fixup,
@@ -175,43 +183,24 @@ static struct snd_soc_dai_link card_dai_links[] = {
},
};
-static void bdw_rt286_disable_jack(struct snd_soc_card *card)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component) {
- if (!strcmp(component->name, "i2c-INT343A:00")) {
- dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
- snd_soc_component_set_jack(component, NULL, NULL);
- break;
- }
- }
-}
-
-static int bdw_rt286_suspend(struct snd_soc_card *card)
+static int card_suspend_pre(struct snd_soc_card *card)
{
- bdw_rt286_disable_jack(card);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
- return 0;
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
-static int bdw_rt286_resume(struct snd_soc_card *card)
+static int card_resume_post(struct snd_soc_card *card)
{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component) {
- if (!strcmp(component->name, "i2c-INT343A:00")) {
- dev_dbg(component->dev, "enabling jack detect for resume.\n");
- snd_soc_component_set_jack(component, &card_headset, NULL);
- break;
- }
- }
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
- return 0;
+ return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
}
static struct snd_soc_card bdw_rt286_card = {
.owner = THIS_MODULE,
+ .suspend_pre = card_suspend_pre,
+ .resume_post = card_resume_post,
.dai_link = card_dai_links,
.num_links = ARRAY_SIZE(card_dai_links),
.controls = card_controls,
@@ -221,8 +210,6 @@ static struct snd_soc_card bdw_rt286_card = {
.dapm_routes = card_routes,
.num_dapm_routes = ARRAY_SIZE(card_routes),
.fully_routed = true,
- .suspend_pre = bdw_rt286_suspend,
- .resume_post = bdw_rt286_resume,
};
/* Use space before codec name to simplify card ID, and simplify driver name. */
@@ -254,18 +241,8 @@ static int bdw_rt286_probe(struct platform_device *pdev)
return devm_snd_soc_register_card(dev, &bdw_rt286_card);
}
-static int bdw_rt286_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- bdw_rt286_disable_jack(card);
-
- return 0;
-}
-
static struct platform_driver bdw_rt286_driver = {
.probe = bdw_rt286_probe,
- .remove = bdw_rt286_remove,
.driver = {
.name = "bdw_rt286",
.pm = &snd_soc_pm_ops
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 7c6c95e99ade..c593995facaa 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -19,7 +19,6 @@
#include <sound/soc-acpi.h>
#include "../../codecs/hdac_hdmi.h"
#include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
#include "../common/soc-intel-quirks.h"
#include "hda_dsp_common.h"
@@ -259,7 +258,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3,
KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &broxton_headset);
+ snd_soc_component_set_jack(component, &broxton_headset, NULL);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 4bd93c3ba377..bf89fe80423d 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -210,7 +210,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index ae899866863e..41cec67157b6 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -111,7 +111,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 6432b83f616f..09d1f0f6d686 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -243,7 +243,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
@@ -443,6 +443,13 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
| BYT_CHT_ES8316_INTMIC_IN2_MAP
| BYT_CHT_ES8316_JD_INVERTED),
},
+ { /* Nanote UMPC-01 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"),
+ },
+ .driver_data = (void *)BYT_CHT_ES8316_INTMIC_IN1_MAP,
+ },
{ /* Teclast X98 Plus II */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index fb9d9e271845..6db07b2417ca 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -1390,7 +1390,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 2beb686768f2..81ac6eeda2e6 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -683,7 +683,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 45a6805787f5..1669eb3bd80f 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -248,7 +248,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = 48000;
rate->max = 48000;
channels->min = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 64eb73525ee3..2c086e901aae 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -272,7 +272,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index 4c1d83b317c7..af2d9a78465d 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -136,7 +136,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 96501aed8bee..25a054bd4073 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -344,7 +344,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index ca47f6476b07..49d3da8f7316 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -270,7 +270,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 329457e3e3a2..18365ce6bcba 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include "../../codecs/da7219.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
#define KBL_MAXIM_CODEC_DAI "HiFi"
@@ -207,7 +206,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &ctx->kabylake_headset);
+ snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
if (ret)
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 362579f25835..ad4223fee0c5 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include "../../codecs/da7219.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
#define MAX98927_CODEC_DAI "max98927-aif1"
@@ -382,7 +381,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &ctx->kabylake_headset);
+ snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
return 0;
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 8dceb0b02581..e13a5a4d8f7e 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -154,7 +154,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 62c0d46d0086..575604dc8936 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -333,7 +333,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c
index 6e39eda77385..851c516c8f5b 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.c
+++ b/sound/soc/intel/boards/sof_cirrus_common.c
@@ -155,7 +155,7 @@ static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" };
*/
static int cs35l41_compute_codec_conf(void)
{
- const char * const uid_strings[] = { "0", "1", "2", "3" };
+ static const char * const uid_strings[] = { "0", "1", "2", "3" };
unsigned int uid, sz = 0;
struct acpi_device *adev;
struct device *physdev;
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
index e048e789e633..740aa11cb019 100644
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -7,13 +7,13 @@
#include <linux/input.h>
#include <linux/module.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/platform_device.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
#include "hda_dsp_common.h"
#define DIALOG_CODEC_DAI "da7219-hifi"
@@ -184,7 +184,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, jack);
+ snd_soc_component_set_jack(component, jack, NULL);
return ret;
}
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index fbb42e54947a..70713e4b07dc 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -63,6 +63,7 @@ struct sof_es8336_private {
struct snd_soc_jack jack;
struct list_head hdmi_pcm_list;
bool speaker_en;
+ struct delayed_work pcm_pop_work;
};
struct sof_hdmi_pcm {
@@ -111,6 +112,46 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk headset at mic1 port enabled\n");
}
+static void pcm_pop_work_events(struct work_struct *work)
+{
+ struct sof_es8336_private *priv =
+ container_of(work, struct sof_es8336_private, pcm_pop_work.work);
+
+ gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
+
+ if (quirk & SOF_ES8336_HEADPHONE_GPIO)
+ gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en);
+
+}
+
+static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (priv->speaker_en == false)
+ if (substream->stream == 0) {
+ cancel_delayed_work(&priv->pcm_pop_work);
+ gpiod_set_value_cansleep(priv->gpio_speakers, true);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -122,19 +163,7 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
- if (SND_SOC_DAPM_EVENT_ON(event))
- msleep(70);
-
- gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
-
- if (!(quirk & SOF_ES8336_HEADPHONE_GPIO))
- return 0;
-
- if (SND_SOC_DAPM_EVENT_ON(event))
- msleep(70);
-
- gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en);
-
+ queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70));
return 0;
}
@@ -344,6 +373,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream,
/* machine stream operations */
static struct snd_soc_ops sof_es8336_ops = {
.hw_params = sof_es8336_hw_params,
+ .trigger = sof_8336_trigger,
};
static struct snd_soc_dai_link_component platform_component[] = {
@@ -723,7 +753,8 @@ static int sof_es8336_probe(struct platform_device *pdev)
}
INIT_LIST_HEAD(&priv->hdmi_pcm_list);
-
+ INIT_DELAYED_WORK(&priv->pcm_pop_work,
+ pcm_pop_work_events);
snd_soc_card_set_drvdata(card, priv);
if (mach->mach_params.dmic_num > 0) {
@@ -752,6 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
+ cancel_delayed_work(&priv->pcm_pop_work);
gpiod_put(priv->gpio_speakers);
device_remove_software_node(priv->codec_dev);
put_device(priv->codec_dev);
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 5585c217f78d..27880224359d 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -47,6 +47,7 @@
#define SOF_RT1019P_SPEAKER_AMP_PRESENT BIT(14)
#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15)
#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16)
+#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17)
static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
@@ -483,6 +484,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
} else if (sof_nau8825_quirk &
SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
max_98360a_dai_link(&links[id]);
+ } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
+ sof_rt1015p_dai_link(&links[id]);
} else {
goto devm_err;
}
@@ -576,6 +579,8 @@ static int sof_audio_probe(struct platform_device *pdev)
if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
max_98373_set_codec_conf(&sof_audio_card_nau8825);
+ else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
+ sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
sof_audio_card_nau8825.num_links++;
@@ -642,6 +647,16 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ {
+ .name = "adl_rt1015p_nau8825",
+ .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_RT1015P_SPEAKER_AMP_PRESENT |
+ SOF_NAU8825_SSP_AMP(1) |
+ SOF_NAU8825_NUM_HDMIDEV(4) |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
@@ -663,3 +678,4 @@ MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 2358be208c1f..4a2f91249b10 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -867,10 +867,6 @@ static int sof_audio_probe(struct platform_device *pdev)
if (acpi_dev_present("RTL5682", NULL, -1))
sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
- /* Detect the headset codec variant to support machines in DMI quirk */
- if (acpi_dev_present("RTL5682", NULL, -1))
- sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
-
if (soc_intel_is_byt() || soc_intel_is_cht()) {
is_legacy_cpu = 1;
dmic_be_num = 0;
@@ -1092,10 +1088,9 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_rt1019_rt5682s",
+ .name = "adl_rt1019_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682S_HEADPHONE_CODEC_PRESENT |
SOF_SPEAKER_AMP_PRESENT |
SOF_RT1019_SPEAKER_AMP_PRESENT |
SOF_RT5682_SSP_AMP(1) |
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index ee9857dc3135..b58c7b35599d 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -355,6 +355,47 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD2),
},
+ /* RaptorLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
+ },
+ /* No Jack */
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
/* MeteorLake devices */
{
.callback = sof_sdw_quirk_cb,
@@ -510,6 +551,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "rt1308-aif",
.ops = &sof_sdw_rt1308_i2s_ops,
.init = sof_sdw_rt1308_init,
+ .exit = sof_sdw_rt1308_exit,
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
},
{
@@ -517,6 +559,14 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.direction = {true, true},
.dai_name = "rt1316-aif",
.init = sof_sdw_rt1316_init,
+ .exit = sof_sdw_rt1316_exit,
+ .codec_type = SOF_SDW_CODEC_TYPE_AMP,
+ },
+ {
+ .part_id = 0x1318,
+ .direction = {true, true},
+ .dai_name = "rt1318-aif",
+ .init = sof_sdw_rt1318_init,
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
},
{
diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
new file mode 100644
index 000000000000..4a3e6fdbd623
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
@@ -0,0 +1,300 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ */
+
+/*
+ * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters
+ */
+
+#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H
+#define SND_SOC_SOF_SDW_AMP_COEFF_H
+
+#define RT1308_MAX_BQ_REG 480
+#define RT1316_MAX_BQ_REG 580
+
+static const u8 __maybe_unused dell_0a5d_bq_params[] = {
+ 0xb0, 0xc5, 0x00, /* address: 0xc5b0; data: 0x00 */
+ 0xb1, 0xc5, 0x32,
+ 0xb2, 0xc5, 0x44,
+ 0xb3, 0xc5, 0x19,
+ 0xc0, 0xc5, 0x04,
+ 0xc1, 0xc5, 0x00,
+ 0xc2, 0xc5, 0x00,
+ 0xc3, 0xc5, 0x00,
+ 0xd0, 0xc5, 0x02,
+ 0xd1, 0xc5, 0x00,
+ 0xd2, 0xc5, 0x00,
+ 0xd3, 0xc5, 0x00,
+ 0xe0, 0xc5, 0x01,
+ 0xe1, 0xc5, 0xe8,
+ 0xe2, 0xc5, 0x5f,
+ 0xe3, 0xc5, 0x8a,
+ 0xf0, 0xc5, 0x1f,
+ 0xf1, 0xc5, 0x4e,
+ 0xf2, 0xc5, 0x90,
+ 0xf3, 0xc5, 0x11,
+ 0x50, 0xc6, 0x01,
+ 0x51, 0xc6, 0xff,
+ 0x52, 0xc6, 0x45,
+ 0x53, 0xc6, 0x41,
+ 0x60, 0xc6, 0x1c,
+ 0x61, 0xc6, 0x00,
+ 0x62, 0xc6, 0x00,
+ 0x63, 0xc6, 0x00,
+ 0x70, 0xc6, 0x02,
+ 0x71, 0xc6, 0x00,
+ 0x72, 0xc6, 0x00,
+ 0x73, 0xc6, 0x00,
+ 0x80, 0xc6, 0x03,
+ 0x81, 0xc6, 0xfe,
+ 0x82, 0xc6, 0x89,
+ 0x83, 0xc6, 0xfa,
+ 0x90, 0xc6, 0x1e,
+ 0x91, 0xc6, 0x01,
+ 0x92, 0xc6, 0x74,
+ 0x93, 0xc6, 0xf6,
+ 0x00, 0xc6, 0x01,
+ 0x01, 0xc6, 0xd9,
+ 0x02, 0xc6, 0xfb,
+ 0x03, 0xc6, 0xc4,
+ 0x10, 0xc6, 0x1c,
+ 0x11, 0xc6, 0x00,
+ 0x12, 0xc6, 0x00,
+ 0x13, 0xc6, 0x00,
+ 0x20, 0xc6, 0x02,
+ 0x21, 0xc6, 0x00,
+ 0x22, 0xc6, 0x00,
+ 0x23, 0xc6, 0x00,
+ 0x30, 0xc6, 0x03,
+ 0x31, 0xc6, 0xaf,
+ 0x32, 0xc6, 0x23,
+ 0x33, 0xc6, 0xcb,
+ 0x40, 0xc6, 0x1e,
+ 0x41, 0xc6, 0x47,
+ 0x42, 0xc6, 0x34,
+ 0x43, 0xc6, 0xba,
+ 0xa0, 0xc6, 0x01,
+ 0xa1, 0xc6, 0xff,
+ 0xa2, 0xc6, 0x45,
+ 0xa3, 0xc6, 0x41,
+ 0xb0, 0xc6, 0x1c,
+ 0xb1, 0xc6, 0x00,
+ 0xb2, 0xc6, 0x00,
+ 0xb3, 0xc6, 0x00,
+ 0xc0, 0xc6, 0x02,
+ 0xc1, 0xc6, 0x00,
+ 0xc2, 0xc6, 0x00,
+ 0xc3, 0xc6, 0x00,
+ 0xd0, 0xc6, 0x03,
+ 0xd1, 0xc6, 0xfe,
+ 0xd2, 0xc6, 0x89,
+ 0xd3, 0xc6, 0xfa,
+ 0xe0, 0xc6, 0x1e,
+ 0xe1, 0xc6, 0x01,
+ 0xe2, 0xc6, 0x74,
+ 0xe3, 0xc6, 0xf6,
+ 0x40, 0xc5, 0x0d,
+ 0x30, 0xc7, 0x15,
+ 0x31, 0xc7, 0x7c,
+ 0x32, 0xc7, 0x0f,
+ 0x33, 0xc7, 0xa0,
+ 0x40, 0xc7, 0x00,
+ 0x41, 0xc7, 0x00,
+ 0x42, 0xc7, 0xf8,
+ 0x43, 0xc7, 0xf8,
+ 0x50, 0xc7, 0x00,
+ 0x51, 0xc7, 0x00,
+ 0x52, 0xc7, 0x00,
+ 0x53, 0xc7, 0x01,
+ 0x90, 0xc7, 0x00,
+ 0x91, 0xc7, 0x14,
+ 0x92, 0xc7, 0x00,
+ 0x93, 0xc7, 0x14,
+ 0xa0, 0xc7, 0x00,
+ 0xa1, 0xc7, 0x00,
+ 0xa2, 0xc7, 0xf8,
+ 0xa3, 0xc7, 0xf8,
+ 0xb0, 0xc7, 0x00,
+ 0xb1, 0xc7, 0x00,
+ 0xb2, 0xc7, 0x00,
+ 0xb3, 0xc7, 0x00,
+ 0x60, 0xc7, 0x03,
+ 0x61, 0xc7, 0xe8,
+ 0x62, 0xc7, 0x03,
+ 0x63, 0xc7, 0xb6,
+ 0x70, 0xc7, 0x00,
+ 0x71, 0xc7, 0x00,
+ 0x72, 0xc7, 0xf8,
+ 0x73, 0xc7, 0xf8,
+ 0x80, 0xc7, 0x00,
+ 0x81, 0xc7, 0x00,
+ 0x82, 0xc7, 0x00,
+ 0x83, 0xc7, 0x00,
+ 0xc0, 0xc7, 0x00,
+ 0xc1, 0xc7, 0x14,
+ 0xc2, 0xc7, 0x00,
+ 0xc3, 0xc7, 0x14,
+ 0xd0, 0xc7, 0x00,
+ 0xd1, 0xc7, 0x00,
+ 0xd2, 0xc7, 0xf8,
+ 0xd3, 0xc7, 0xf8,
+ 0xe0, 0xc7, 0x00,
+ 0xe1, 0xc7, 0x00,
+ 0xe2, 0xc7, 0x00,
+ 0xe3, 0xc7, 0x00,
+ 0x60, 0xc5, 0x02,
+ 0x61, 0xc5, 0x00,
+ 0x62, 0xc5, 0x00,
+ 0x63, 0xc5, 0x00,
+ 0x70, 0xc5, 0x02,
+ 0x71, 0xc5, 0x00,
+ 0x72, 0xc5, 0x00,
+ 0x73, 0xc5, 0x00,
+ 0x80, 0xc5, 0x02,
+ 0x81, 0xc5, 0x00,
+ 0x82, 0xc5, 0x00,
+ 0x83, 0xc5, 0x00,
+ 0x90, 0xc5, 0x02,
+ 0x91, 0xc5, 0x00,
+ 0x92, 0xc5, 0x00,
+ 0x93, 0xc5, 0x00,
+ 0x50, 0xc5, 0x01,
+};
+
+static const u8 __maybe_unused dell_0b00_bq_params[] = {
+ 0x03, 0xc2, 0x00,
+ 0x04, 0xc2, 0xb2,
+ 0x05, 0xc2, 0xe0,
+ 0x06, 0xc2, 0x3a,
+ 0x07, 0xc2, 0x01,
+ 0x08, 0xc2, 0x65,
+ 0x09, 0xc2, 0xc0,
+ 0x0a, 0xc2, 0x75,
+ 0x0b, 0xc2, 0x00,
+ 0x0c, 0xc2, 0xb2,
+ 0x0d, 0xc2, 0xe0,
+ 0x0e, 0xc2, 0x3a,
+ 0x0f, 0xc2, 0xf7,
+ 0x10, 0xc2, 0x4d,
+ 0x11, 0xc2, 0x5b,
+ 0x12, 0xc2, 0xe9,
+ 0x13, 0xc2, 0x03,
+ 0x14, 0xc2, 0x7e,
+ 0x15, 0xc2, 0x25,
+ 0x16, 0xc2, 0x01,
+ 0x17, 0xc2, 0x07,
+ 0x18, 0xc2, 0xfd,
+ 0x19, 0xc2, 0x15,
+ 0x1a, 0xc2, 0x04,
+ 0x1b, 0xc2, 0xf0,
+ 0x1c, 0xc2, 0x05,
+ 0x1d, 0xc2, 0xd5,
+ 0x1e, 0xc2, 0xf7,
+ 0x1f, 0xc2, 0x07,
+ 0x20, 0xc2, 0xfd,
+ 0x21, 0xc2, 0x15,
+ 0x22, 0xc2, 0x04,
+ 0x23, 0xc2, 0xf0,
+ 0x24, 0xc2, 0x05,
+ 0x25, 0xc2, 0xd8,
+ 0x26, 0xc2, 0x17,
+ 0x27, 0xc2, 0x07,
+ 0x28, 0xc2, 0xfa,
+ 0x29, 0xc2, 0x2c,
+ 0x2a, 0xc2, 0x29,
+ 0x2b, 0xc2, 0x07,
+ 0x2c, 0xc2, 0x74,
+ 0x2d, 0xc2, 0xe0,
+ 0x2e, 0xc2, 0x33,
+ 0x2f, 0xc2, 0xf1,
+ 0x30, 0xc2, 0x16,
+ 0x31, 0xc2, 0x3f,
+ 0x32, 0xc2, 0x9b,
+ 0x33, 0xc2, 0x07,
+ 0x34, 0xc2, 0x74,
+ 0x35, 0xc2, 0xe0,
+ 0x36, 0xc2, 0x33,
+ 0x37, 0xc2, 0xf1,
+ 0x38, 0xc2, 0x29,
+ 0x39, 0xc2, 0xb0,
+ 0x3a, 0xc2, 0x4d,
+ 0x3b, 0xc2, 0x06,
+ 0x3c, 0xc2, 0xfd,
+ 0x3d, 0xc2, 0x31,
+ 0x3e, 0xc2, 0x18,
+ 0x3f, 0xc2, 0x07,
+ 0x40, 0xc2, 0xfd,
+ 0x41, 0xc2, 0x15,
+ 0x42, 0xc2, 0x04,
+ 0x43, 0xc2, 0xf0,
+ 0x44, 0xc2, 0x05,
+ 0x45, 0xc2, 0xd5,
+ 0x46, 0xc2, 0xf7,
+ 0x47, 0xc2, 0x07,
+ 0x48, 0xc2, 0xfd,
+ 0x49, 0xc2, 0x15,
+ 0x4a, 0xc2, 0x04,
+ 0x4b, 0xc2, 0xf0,
+ 0x4c, 0xc2, 0x05,
+ 0x4d, 0xc2, 0xd8,
+ 0x4e, 0xc2, 0x17,
+ 0x4f, 0xc2, 0x07,
+ 0x50, 0xc2, 0xfa,
+ 0x51, 0xc2, 0x2c,
+ 0x52, 0xc2, 0x29,
+ 0x0b, 0xc0, 0x30,
+ 0x80, 0xc3, 0x13,
+ 0x81, 0xc3, 0x88,
+ 0x82, 0xc3, 0x17,
+ 0x83, 0xc3, 0x70,
+ 0x84, 0xc3, 0x00,
+ 0x85, 0xc3, 0x00,
+ 0x86, 0xc3, 0xff,
+ 0x87, 0xc3, 0xee,
+ 0x88, 0xc3, 0x02,
+ 0x92, 0xc3, 0x00,
+ 0x93, 0xc3, 0x14,
+ 0x94, 0xc3, 0x00,
+ 0x95, 0xc3, 0x14,
+ 0x96, 0xc3, 0x00,
+ 0x97, 0xc3, 0x00,
+ 0x98, 0xc3, 0x00,
+ 0x99, 0xc3, 0x00,
+ 0x9a, 0xc3, 0x01,
+ 0x89, 0xc3, 0x03,
+ 0x8a, 0xc3, 0xe8,
+ 0x8b, 0xc3, 0x03,
+ 0x8c, 0xc3, 0xb6,
+ 0x8d, 0xc3, 0x00,
+ 0x8e, 0xc3, 0x00,
+ 0x8f, 0xc3, 0xff,
+ 0x90, 0xc3, 0xee,
+ 0x91, 0xc3, 0x01,
+ 0x9b, 0xc3, 0x00,
+ 0x9c, 0xc3, 0x14,
+ 0x9d, 0xc3, 0x00,
+ 0x9e, 0xc3, 0x14,
+ 0x9f, 0xc3, 0x00,
+ 0xa0, 0xc3, 0x00,
+ 0xa1, 0xc3, 0x00,
+ 0xa2, 0xc3, 0x00,
+ 0xa3, 0xc3, 0x01,
+ 0x61, 0xc2, 0x08,
+ 0x62, 0xc2, 0x00,
+ 0x63, 0xc2, 0x00,
+ 0x64, 0xc2, 0x00,
+ 0x65, 0xc2, 0x08,
+ 0x66, 0xc2, 0x00,
+ 0x67, 0xc2, 0x00,
+ 0x68, 0xc2, 0x00,
+ 0x69, 0xc2, 0x08,
+ 0x6a, 0xc2, 0x00,
+ 0x6b, 0xc2, 0x00,
+ 0x6c, 0xc2, 0x00,
+ 0x6d, 0xc2, 0x08,
+ 0x6e, 0xc2, 0x00,
+ 0x6f, 0xc2, 0x00,
+ 0x70, 0xc2, 0x00,
+ 0x00, 0xc2, 0xc0,
+};
+
+#endif
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index e2457738a332..54a50f7da4da 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -83,6 +83,7 @@ struct mc_private {
bool idisp_codec;
struct snd_soc_jack sdw_headset;
struct device *headset_codec_dev; /* only one headset per card */
+ struct device *amp_dev1, *amp_dev2;
};
extern unsigned long sof_sdw_quirk;
@@ -132,6 +133,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
+int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT1316 support */
int sof_sdw_rt1316_init(struct snd_soc_card *card,
@@ -139,6 +141,14 @@ int sof_sdw_rt1316_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
+int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
+
+/* RT1318 support */
+int sof_sdw_rt1318_init(struct snd_soc_card *card,
+ const struct snd_soc_acpi_link_adr *link,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback);
/* RT715 support */
int sof_sdw_rt715_init(struct snd_soc_card *card,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c
index f078fb1aad02..a19b055b9c6f 100644
--- a/sound/soc/intel/boards/sof_sdw_rt1308.c
+++ b/sound/soc/intel/boards/sof_sdw_rt1308.c
@@ -11,9 +11,86 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/dmi.h>
#include "sof_sdw_common.h"
+#include "sof_sdw_amp_coeff_tables.h"
#include "../../codecs/rt1308.h"
+struct rt1308_platform_data {
+ const unsigned char *bq_params;
+ const unsigned int bq_params_cnt;
+};
+
+static const struct rt1308_platform_data dell_0a5d_platform_data = {
+ .bq_params = dell_0a5d_bq_params,
+ .bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params),
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+ /* CometLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ /* TigerLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+};
+
+static int rt1308_add_device_props(struct device *sdw_dev)
+{
+ struct property_entry props[3] = {};
+ struct fwnode_handle *fwnode;
+ const struct dmi_system_id *dmi_data;
+ const struct rt1308_platform_data *pdata;
+ unsigned char params[RT1308_MAX_BQ_REG];
+ int ret;
+
+ dmi_data = dmi_first_match(dmi_platform_data);
+ if (!dmi_data)
+ return 0;
+
+ pdata = dmi_data->driver_data;
+ memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
+
+ props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
+ props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
+
+ fwnode = fwnode_create_software_node(props, NULL);
+ if (IS_ERR(fwnode))
+ return PTR_ERR(fwnode);
+
+ ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
+
static const struct snd_soc_dapm_widget rt1308_widgets[] = {
SND_SOC_DAPM_SPK("Speaker", NULL),
};
@@ -127,12 +204,33 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
.hw_params = rt1308_i2s_hw_params,
};
+int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->amp_dev1) {
+ device_remove_software_node(ctx->amp_dev1);
+ put_device(ctx->amp_dev1);
+ }
+
+ if (ctx->amp_dev2) {
+ device_remove_software_node(ctx->amp_dev2);
+ put_device(ctx->amp_dev2);
+ }
+
+ return 0;
+}
+
int sof_sdw_rt1308_init(struct snd_soc_card *card,
const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct device *sdw_dev1, *sdw_dev2;
+ int ret;
+
/* Count amp number and do init on playback link only. */
if (!playback)
return 0;
@@ -142,6 +240,28 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
dai_links->init = first_spk_init;
if (info->amp_num == 2) {
+ sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+ if (!sdw_dev1)
+ return -EPROBE_DEFER;
+
+ ret = rt1308_add_device_props(sdw_dev1);
+ if (ret < 0) {
+ put_device(sdw_dev1);
+ return ret;
+ }
+ ctx->amp_dev1 = sdw_dev1;
+
+ sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+ if (!sdw_dev2)
+ return -EPROBE_DEFER;
+
+ ret = rt1308_add_device_props(sdw_dev2);
+ if (ret < 0) {
+ put_device(sdw_dev2);
+ return ret;
+ }
+ ctx->amp_dev2 = sdw_dev2;
+
/*
* if two 1308s are in one dai link, the init function
* in this dai link will be first set for the first speaker,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1316.c b/sound/soc/intel/boards/sof_sdw_rt1316.c
index 58194b380232..f6bbea0d3810 100644
--- a/sound/soc/intel/boards/sof_sdw_rt1316.c
+++ b/sound/soc/intel/boards/sof_sdw_rt1316.c
@@ -11,7 +11,83 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/dmi.h>
#include "sof_sdw_common.h"
+#include "sof_sdw_amp_coeff_tables.h"
+
+struct rt1316_platform_data {
+ const unsigned char *bq_params;
+ const unsigned int bq_params_cnt;
+};
+
+static const struct rt1316_platform_data dell_0b00_platform_data = {
+ .bq_params = dell_0b00_bq_params,
+ .bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+ /* AlderLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+};
+
+static int rt1316_add_device_props(struct device *sdw_dev)
+{
+ struct property_entry props[3] = {};
+ struct fwnode_handle *fwnode;
+ const struct dmi_system_id *dmi_data;
+ const struct rt1316_platform_data *pdata;
+ unsigned char params[RT1316_MAX_BQ_REG];
+ int ret;
+
+ dmi_data = dmi_first_match(dmi_platform_data);
+ if (!dmi_data)
+ return 0;
+
+ pdata = dmi_data->driver_data;
+ memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
+
+ props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
+ props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
+
+ fwnode = fwnode_create_software_node(props, NULL);
+ if (IS_ERR(fwnode))
+ return PTR_ERR(fwnode);
+
+ ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
static const struct snd_soc_dapm_widget rt1316_widgets[] = {
SND_SOC_DAPM_SPK("Speaker", NULL),
@@ -89,12 +165,33 @@ static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
return second_spk_init(rtd);
}
+int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->amp_dev1) {
+ device_remove_software_node(ctx->amp_dev1);
+ put_device(ctx->amp_dev1);
+ }
+
+ if (ctx->amp_dev2) {
+ device_remove_software_node(ctx->amp_dev2);
+ put_device(ctx->amp_dev2);
+ }
+
+ return 0;
+}
+
int sof_sdw_rt1316_init(struct snd_soc_card *card,
const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct device *sdw_dev1, *sdw_dev2;
+ int ret;
+
/* Count amp number and do init on playback link only. */
if (!playback)
return 0;
@@ -104,6 +201,28 @@ int sof_sdw_rt1316_init(struct snd_soc_card *card,
dai_links->init = first_spk_init;
if (info->amp_num == 2) {
+ sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+ if (!sdw_dev1)
+ return -EPROBE_DEFER;
+
+ ret = rt1316_add_device_props(sdw_dev1);
+ if (ret < 0) {
+ put_device(sdw_dev1);
+ return ret;
+ }
+ ctx->amp_dev1 = sdw_dev1;
+
+ sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+ if (!sdw_dev2)
+ return -EPROBE_DEFER;
+
+ ret = rt1316_add_device_props(sdw_dev2);
+ if (ret < 0) {
+ put_device(sdw_dev2);
+ return ret;
+ }
+ ctx->amp_dev2 = sdw_dev2;
+
/*
* if two 1316s are in one dai link, the init function
* in this dai link will be first set for the first speaker,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1318.c b/sound/soc/intel/boards/sof_sdw_rt1318.c
new file mode 100644
index 000000000000..dbee4bf5c814
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_rt1318.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2022 Intel Corporation
+
+/*
+ * sof_sdw_rt1318 - Helpers to handle RT1318 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include "sof_sdw_common.h"
+
+static const struct snd_soc_dapm_widget rt1318_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/*
+ * dapm routes for rt1318 will be registered dynamically according
+ * to the number of rt1318 used. The first two entries will be registered
+ * for one codec case, and the last two entries are also registered
+ * if two 1318s are used.
+ */
+static const struct snd_soc_dapm_route rt1318_map[] = {
+ { "Speaker", NULL, "rt1318-1 SPOL" },
+ { "Speaker", NULL, "rt1318-1 SPOR" },
+ { "Speaker", NULL, "rt1318-2 SPOL" },
+ { "Speaker", NULL, "rt1318-2 SPOR" },
+};
+
+static const struct snd_kcontrol_new rt1318_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:rt1318",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_add_card_controls(card, rt1318_controls,
+ ARRAY_SIZE(rt1318_controls));
+ if (ret) {
+ dev_err(card->dev, "rt1318 controls addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, rt1318_widgets,
+ ARRAY_SIZE(rt1318_widgets));
+ if (ret) {
+ dev_err(card->dev, "rt1318 widgets addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map, 2);
+ if (ret)
+ dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
+
+ return ret;
+}
+
+static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret;
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map + 2, 2);
+ if (ret)
+ dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
+
+ return ret;
+}
+
+static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ ret = first_spk_init(rtd);
+ if (ret)
+ return ret;
+
+ return second_spk_init(rtd);
+}
+
+int sof_sdw_rt1318_init(struct snd_soc_card *card,
+ const struct snd_soc_acpi_link_adr *link,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback)
+{
+ /* Count amp number and do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+ if (info->amp_num == 1)
+ dai_links->init = first_spk_init;
+
+ if (info->amp_num == 2) {
+ /*
+ * if two 1318s are in one dai link, the init function
+ * in this dai link will be first set for the first speaker,
+ * and it should be reset to initialize all speakers when
+ * the second speaker is found.
+ */
+ if (dai_links->init)
+ dai_links->init = all_spk_init;
+ else
+ dai_links->init = second_spk_init;
+ }
+
+ return 0;
+}
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index 9990d5502d26..60aee56f94bd 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -430,6 +430,11 @@ static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
.codecs = {"10EC5682", "RTL5682"},
};
+static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
+ .num_codecs = 1,
+ .codecs = {"RTL1015"}
+};
+
static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
.num_codecs = 1,
.codecs = {"RTL1019"}
@@ -489,14 +494,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
},
{
- .id = "RTL5682",
- .drv_name = "adl_rt1019_rt5682s",
+ .comp_ids = &adl_rt5682_rt5682s_hp,
+ .drv_name = "adl_rt1019_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_rt1019p_amp,
.sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg",
},
{
.id = "10508825",
+ .drv_name = "adl_rt1015p_nau8825",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &adl_rt1015p_amp,
+ .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
+ },
+ {
+ .id = "10508825",
.drv_name = "sof_nau8825",
.sof_tplg_filename = "sof-adl-nau8825.tplg",
},
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
index b032bc07de8b..d0062f2cd256 100644
--- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -10,6 +10,11 @@
#include <sound/soc-acpi-intel-match.h>
#include "../skylake/skl.h"
+static const struct snd_soc_acpi_codecs essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
static struct skl_machine_pdata icl_pdata = {
.use_tplg_pcm = true,
};
@@ -27,6 +32,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
.drv_name = "sof_rt5682",
.sof_tplg_filename = "sof-icl-rt5682.tplg",
},
+ {
+ .comp_ids = &essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-icl-es8336", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 36c361fb28a4..b1a66a0f6818 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -39,6 +39,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = {
.group_id = 0,
};
+static const struct snd_soc_acpi_endpoint spk_l_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+};
+
static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -48,6 +62,45 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device mx8373_0_adr[] = {
+ {
+ .adr = 0x000023019F837300ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "Left"
+ },
+ {
+ .adr = 0x000027019F837300ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "Right"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = {
+ {
+ .adr = 0x000221025D568200ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt5682"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = {
+ /* Expected order: jack -> amp */
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt5682_2_adr),
+ .adr_d = rt5682_2_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(mx8373_0_adr),
+ .adr_d = mx8373_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
{
.mask = BIT(0),
@@ -84,6 +137,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711.tplg",
},
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = rt5682_link2_max98373_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 9ccf7370157b..3c5229f41bb0 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -56,6 +56,15 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt711_sdca_2_adr[] = {
+ {
+ .adr = 0x000230025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
{
.adr = 0x000131025D131601ull, /* unique ID is set for some reason */
@@ -65,6 +74,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
{
.adr = 0x000330025D131601ull,
@@ -74,6 +92,51 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_0_group2_adr[] = {
+ {
+ .adr = 0x000030025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
+ {
+ .adr = 0x000131025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000131025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+ {
+ .adr = 0x000030025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
{
.adr = 0x000230025D071401ull,
@@ -83,6 +146,15 @@ static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt714_3_adr[] = {
+ {
+ .adr = 0x000330025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
{
.mask = BIT(0),
@@ -107,6 +179,73 @@ static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
{}
};
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt714_link3[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
+ .adr_d = rt711_sdca_2_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+ .adr_d = rt1316_0_group2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+ .adr_d = rt1316_1_group2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt714_3_adr),
+ .adr_d = rt714_3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt714_3_adr),
+ .adr_d = rt714_3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group1_adr),
+ .adr_d = rt1316_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+ .adr_d = rt1316_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{},
};
@@ -121,6 +260,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1316-l13-rt714-l2.tplg",
},
{
+ .link_mask = 0xF, /* 4 active links required */
+ .links = rpl_sdw_rt711_link2_rt1316_link01_rt714_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01-rt714-l3.tplg",
+ },
+ {
+ .link_mask = 0xF, /* 4 active links required */
+ .links = rpl_sdw_rt711_link0_rt1318_link12_rt714_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
+ },
+ {
+ .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
+ .links = rpl_sdw_rt1316_link12_rt714_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
+ },
+ {
.link_mask = 0x1, /* link0 required */
.links = rpl_rvp,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index eaad180af42e..5ab0917a2b3d 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -53,17 +53,15 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream = snd_hdac_get_stream(bus,
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
- struct hdac_ext_stream *estream;
if (!stream)
return -EINVAL;
- estream = stream_to_hdac_ext_stream(stream);
/* enable/disable SPIB for this hdac stream */
- snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
+ snd_hdac_stream_spbcap_enable(bus, enable, stream->index);
/* set the spib value */
- snd_hdac_ext_stream_set_spib(bus, estream, size);
+ snd_hdac_stream_set_spib(bus, stream, size);
return 0;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 1015716f9336..dc627d18518d 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -190,16 +190,16 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format);
- snd_hdac_ext_link_stream_reset(stream);
+ snd_hdac_ext_stream_reset(stream);
- snd_hdac_ext_link_stream_setup(stream, format_val);
+ snd_hdac_ext_stream_setup(stream, format_val);
stream_tag = hstream->stream_tag;
if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
list_for_each_entry(link, &bus->hlink_list, list) {
if (link->index == params->link_index)
- snd_hdac_ext_link_set_stream_id(link,
- stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link,
+ stream_tag);
}
}
@@ -467,6 +467,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig;
struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstream = hdac_stream(stream);
struct snd_soc_dapm_widget *w;
int ret;
@@ -484,11 +485,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
* dpib & lpib position to resume before starting the
* DMA
*/
- snd_hdac_ext_stream_drsm_enable(bus, true,
- hdac_stream(stream)->index);
- snd_hdac_ext_stream_set_dpibr(bus, stream,
- stream->lpib);
- snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+ snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+ snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+ snd_hdac_stream_set_lpib(hstream, hstream->lpib);
}
fallthrough;
@@ -520,13 +519,13 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
ret = skl_decoupled_trigger(substream, cmd);
if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
/* save the dpib and lpib positions */
- stream->dpib = readl(bus->remap_addr +
+ hstream->dpib = readl(bus->remap_addr +
AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
- hdac_stream(stream)->index));
+ hstream->index));
+
+ hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream);
- stream->lpib = snd_hdac_stream_get_pos_lpib(
- hdac_stream(stream));
snd_hdac_ext_stream_decouple(bus, stream, false);
}
break;
@@ -558,7 +557,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -612,13 +611,13 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_dev);
+ snd_hdac_ext_stream_start(link_dev);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- snd_hdac_ext_link_stream_clear(link_dev);
+ snd_hdac_ext_stream_clear(link_dev);
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
snd_hdac_ext_stream_decouple(bus, stream, false);
break;
@@ -643,13 +642,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0;
- link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag);
}
snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 3312b57e3c0c..9bd9f9866898 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -387,15 +387,6 @@ static int skl_resume(struct device *dev)
snd_hdac_bus_init_cmd_io(bus);
} else {
ret = _skl_resume(bus);
-
- /* turn off the links which are off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
}
return ret;
@@ -445,7 +436,7 @@ static int skl_free(struct hdac_bus *bus)
free_irq(bus->irq, (void *)bus);
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
if (bus->remap_addr)
iounmap(bus->remap_addr);
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
index e72f826062e9..dd3b4507fbe6 100644
--- a/sound/soc/jz4740/Kconfig
+++ b/sound/soc/jz4740/Kconfig
@@ -3,6 +3,7 @@ config SND_JZ4740_SOC_I2S
tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
depends on HAS_IOMEM
+ select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index c4c1e89b47c1..6d9cfe0a5041 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -3,19 +3,19 @@
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
*/
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-
-#include <linux/dma-mapping.h>
-
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -23,8 +23,6 @@
#include <sound/initval.h>
#include <sound/dmaengine_pcm.h>
-#include "jz4740-i2s.h"
-
#define JZ_REG_AIC_CONF 0x00
#define JZ_REG_AIC_CTRL 0x04
#define JZ_REG_AIC_I2S_FMT 0x10
@@ -33,67 +31,56 @@
#define JZ_REG_AIC_CLK_DIV 0x30
#define JZ_REG_AIC_FIFO 0x34
-#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
-#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8)
-#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
-#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
-#define JZ_AIC_CONF_I2S BIT(4)
-#define JZ_AIC_CONF_RESET BIT(3)
-#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
-#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
-#define JZ_AIC_CONF_ENABLE BIT(0)
-
-#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
-#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
-#define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
-#define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
-
-#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
-#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
-#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
-#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
-#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
-#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
-#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
-#define JZ_AIC_CTRL_FLUSH BIT(8)
-#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
-#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
-#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
-#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
-#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
-#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
-#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
-
-#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
-#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16
-
-#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
-#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
-#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
-#define JZ_AIC_I2S_FMT_MSB BIT(0)
-
-#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
-
-#define JZ_AIC_CLK_DIV_MASK 0xf
-#define I2SDIV_DV_SHIFT 0
-#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
-#define I2SDIV_IDV_SHIFT 8
-#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
-
-enum jz47xx_i2s_version {
- JZ_I2S_JZ4740,
- JZ_I2S_JZ4760,
- JZ_I2S_JZ4770,
- JZ_I2S_JZ4780,
-};
+#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
+#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
+#define JZ_AIC_CONF_I2S BIT(4)
+#define JZ_AIC_CONF_RESET BIT(3)
+#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
+#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
+#define JZ_AIC_CONF_ENABLE BIT(0)
+
+#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE GENMASK(21, 19)
+#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE GENMASK(18, 16)
+#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
+#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
+#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
+#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
+#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
+#define JZ_AIC_CTRL_TFLUSH BIT(8)
+#define JZ_AIC_CTRL_RFLUSH BIT(7)
+#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
+#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
+#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
+#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
+#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
+#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
+#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
+
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
+#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
+#define JZ_AIC_I2S_FMT_MSB BIT(0)
+
+#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
struct i2s_soc_info {
- enum jz47xx_i2s_version version;
struct snd_soc_dai_driver *dai;
+
+ struct reg_field field_rx_fifo_thresh;
+ struct reg_field field_tx_fifo_thresh;
+ struct reg_field field_i2sdiv_capture;
+ struct reg_field field_i2sdiv_playback;
+
+ bool shared_fifo_flush;
};
struct jz4740_i2s {
- void __iomem *base;
+ struct regmap *regmap;
+
+ struct regmap_field *field_rx_fifo_thresh;
+ struct regmap_field *field_tx_fifo_thresh;
+ struct regmap_field *field_i2sdiv_capture;
+ struct regmap_field *field_i2sdiv_playback;
struct clk *clk_aic;
struct clk *clk_i2s;
@@ -104,40 +91,41 @@ struct jz4740_i2s {
const struct i2s_soc_info *soc_info;
};
-static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
- unsigned int reg)
-{
- return readl(i2s->base + reg);
-}
-
-static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
- unsigned int reg, uint32_t value)
-{
- writel(value, i2s->base + reg);
-}
-
static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- uint32_t conf, ctrl;
int ret;
+ /*
+ * When we can flush FIFOs independently, only flush the FIFO
+ * that is starting up. We can do this when the DAI is active
+ * because it does not disturb other active substreams.
+ */
+ if (!i2s->soc_info->shared_fifo_flush) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
+ else
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH);
+ }
+
if (snd_soc_dai_active(dai))
return 0;
- ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
- ctrl |= JZ_AIC_CTRL_FLUSH;
- jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+ /*
+ * When there is a shared flush bit for both FIFOs, the TFLUSH
+ * bit flushes both FIFOs. Flushing while the DAI is active would
+ * cause FIFO underruns in other active substreams so we have to
+ * guard this behind the snd_soc_dai_active() check.
+ */
+ if (i2s->soc_info->shared_fifo_flush)
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
ret = clk_prepare_enable(i2s->clk_i2s);
if (ret)
return ret;
- conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
- conf |= JZ_AIC_CONF_ENABLE;
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
return 0;
}
@@ -145,14 +133,11 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- uint32_t conf;
if (snd_soc_dai_active(dai))
return;
- conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
- conf &= ~JZ_AIC_CONF_ENABLE;
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+ regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
clk_disable_unprepare(i2s->clk_i2s);
}
@@ -161,8 +146,6 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- uint32_t ctrl;
uint32_t mask;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -170,38 +153,30 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
else
mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
- ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ctrl |= mask;
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, mask);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ctrl &= ~mask;
+ regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CTRL, mask);
break;
default:
return -EINVAL;
}
- jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
-
return 0;
}
static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- uint32_t format = 0;
- uint32_t conf;
-
- conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-
- conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
+ const unsigned int conf_mask = JZ_AIC_CONF_BIT_CLK_MASTER |
+ JZ_AIC_CONF_SYNC_CLK_MASTER;
+ unsigned int conf = 0, format = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BP_FP:
@@ -237,8 +212,8 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
- jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
+ regmap_update_bits(i2s->regmap, JZ_REG_AIC_CONF, conf_mask, conf);
+ regmap_write(i2s->regmap, JZ_REG_AIC_I2S_FMT, format);
return 0;
}
@@ -247,123 +222,51 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ struct regmap_field *div_field;
unsigned int sample_size;
- uint32_t ctrl, div_reg;
+ uint32_t ctrl;
int div;
- ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
+ regmap_read(i2s->regmap, JZ_REG_AIC_CTRL, &ctrl);
- div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
sample_size = 0;
break;
- case SNDRV_PCM_FORMAT_S16:
+ case SNDRV_PCM_FORMAT_S16_LE:
sample_size = 1;
break;
+ case SNDRV_PCM_FORMAT_S20_LE:
+ sample_size = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ sample_size = 4;
+ break;
default:
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
- ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
+ ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE;
+ ctrl |= FIELD_PREP(JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE, sample_size);
+
if (params_channels(params) == 1)
ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
else
ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
- div_reg &= ~I2SDIV_DV_MASK;
- div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
+ div_field = i2s->field_i2sdiv_playback;
} else {
- ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
- ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
-
- if (i2s->soc_info->version >= JZ_I2S_JZ4770) {
- div_reg &= ~I2SDIV_IDV_MASK;
- div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
- } else {
- div_reg &= ~I2SDIV_DV_MASK;
- div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
- }
- }
-
- jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
- jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
-
- return 0;
-}
+ ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE;
+ ctrl |= FIELD_PREP(JZ_AIC_CTRL_INPUT_SAMPLE_SIZE, sample_size);
-static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
- unsigned int freq, int dir)
-{
- struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- struct clk *parent;
- int ret = 0;
-
- switch (clk_id) {
- case JZ4740_I2S_CLKSRC_EXT:
- parent = clk_get(NULL, "ext");
- if (IS_ERR(parent))
- return PTR_ERR(parent);
- clk_set_parent(i2s->clk_i2s, parent);
- break;
- case JZ4740_I2S_CLKSRC_PLL:
- parent = clk_get(NULL, "pll half");
- if (IS_ERR(parent))
- return PTR_ERR(parent);
- clk_set_parent(i2s->clk_i2s, parent);
- ret = clk_set_rate(i2s->clk_i2s, freq);
- break;
- default:
- return -EINVAL;
- }
- clk_put(parent);
-
- return ret;
-}
-
-static int jz4740_i2s_suspend(struct snd_soc_component *component)
-{
- struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
- uint32_t conf;
-
- if (snd_soc_component_active(component)) {
- conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
- conf &= ~JZ_AIC_CONF_ENABLE;
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
- clk_disable_unprepare(i2s->clk_i2s);
+ div_field = i2s->field_i2sdiv_capture;
}
- clk_disable_unprepare(i2s->clk_aic);
-
- return 0;
-}
-
-static int jz4740_i2s_resume(struct snd_soc_component *component)
-{
- struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
- uint32_t conf;
- int ret;
-
- ret = clk_prepare_enable(i2s->clk_aic);
- if (ret)
- return ret;
-
- if (snd_soc_component_active(component)) {
- ret = clk_prepare_enable(i2s->clk_i2s);
- if (ret) {
- clk_disable_unprepare(i2s->clk_aic);
- return ret;
- }
-
- conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
- conf |= JZ_AIC_CONF_ENABLE;
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
- }
+ regmap_write(i2s->regmap, JZ_REG_AIC_CTRL, ctrl);
+ regmap_field_write(div_field, div - 1);
return 0;
}
@@ -371,41 +274,10 @@ static int jz4740_i2s_resume(struct snd_soc_component *component)
static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- uint32_t conf;
- int ret;
-
- ret = clk_prepare_enable(i2s->clk_aic);
- if (ret)
- return ret;
snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
&i2s->capture_dma_data);
- if (i2s->soc_info->version >= JZ_I2S_JZ4760) {
- conf = (7 << JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
- (8 << JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
- JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
- JZ_AIC_CONF_I2S |
- JZ_AIC_CONF_INTERNAL_CODEC;
- } else {
- conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
- (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
- JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
- JZ_AIC_CONF_I2S |
- JZ_AIC_CONF_INTERNAL_CODEC;
- }
-
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
- jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
- return 0;
-}
-
-static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
-{
- struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- clk_disable_unprepare(i2s->clk_aic);
return 0;
}
@@ -415,25 +287,25 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
.trigger = jz4740_i2s_trigger,
.hw_params = jz4740_i2s_hw_params,
.set_fmt = jz4740_i2s_set_fmt,
- .set_sysclk = jz4740_i2s_set_sysclk,
};
#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE)
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver jz4740_i2s_dai = {
.probe = jz4740_i2s_dai_probe,
- .remove = jz4740_i2s_dai_remove,
.playback = {
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = JZ4740_I2S_FMTS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = JZ4740_I2S_FMTS,
},
.symmetric_rate = 1,
@@ -441,45 +313,123 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
};
static const struct i2s_soc_info jz4740_i2s_soc_info = {
- .version = JZ_I2S_JZ4740,
- .dai = &jz4740_i2s_dai,
+ .dai = &jz4740_i2s_dai,
+ .field_rx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 12, 15),
+ .field_tx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 8, 11),
+ .field_i2sdiv_capture = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+ .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+ .shared_fifo_flush = true,
};
static const struct i2s_soc_info jz4760_i2s_soc_info = {
- .version = JZ_I2S_JZ4760,
- .dai = &jz4740_i2s_dai,
+ .dai = &jz4740_i2s_dai,
+ .field_rx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+ .field_tx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+ .field_i2sdiv_capture = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+ .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
};
static struct snd_soc_dai_driver jz4770_i2s_dai = {
.probe = jz4740_i2s_dai_probe,
- .remove = jz4740_i2s_dai_remove,
.playback = {
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = JZ4740_I2S_FMTS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = JZ4740_I2S_FMTS,
},
.ops = &jz4740_i2s_dai_ops,
};
static const struct i2s_soc_info jz4770_i2s_soc_info = {
- .version = JZ_I2S_JZ4770,
- .dai = &jz4770_i2s_dai,
+ .dai = &jz4770_i2s_dai,
+ .field_rx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+ .field_tx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+ .field_i2sdiv_capture = REG_FIELD(JZ_REG_AIC_CLK_DIV, 8, 11),
+ .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
};
static const struct i2s_soc_info jz4780_i2s_soc_info = {
- .version = JZ_I2S_JZ4780,
- .dai = &jz4770_i2s_dai,
+ .dai = &jz4770_i2s_dai,
+ .field_rx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+ .field_tx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+ .field_i2sdiv_capture = REG_FIELD(JZ_REG_AIC_CLK_DIV, 8, 11),
+ .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
};
+static int jz4740_i2s_suspend(struct snd_soc_component *component)
+{
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+
+ if (snd_soc_component_active(component)) {
+ regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
+ clk_disable_unprepare(i2s->clk_i2s);
+ }
+
+ clk_disable_unprepare(i2s->clk_aic);
+
+ return 0;
+}
+
+static int jz4740_i2s_resume(struct snd_soc_component *component)
+{
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = clk_prepare_enable(i2s->clk_aic);
+ if (ret)
+ return ret;
+
+ if (snd_soc_component_active(component)) {
+ ret = clk_prepare_enable(i2s->clk_i2s);
+ if (ret) {
+ clk_disable_unprepare(i2s->clk_aic);
+ return ret;
+ }
+
+ regmap_set_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
+ }
+
+ return 0;
+}
+
+static int jz4740_i2s_probe(struct snd_soc_component *component)
+{
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = clk_prepare_enable(i2s->clk_aic);
+ if (ret)
+ return ret;
+
+ regmap_write(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
+
+ regmap_write(i2s->regmap, JZ_REG_AIC_CONF,
+ JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+ JZ_AIC_CONF_I2S | JZ_AIC_CONF_INTERNAL_CODEC);
+
+ regmap_field_write(i2s->field_rx_fifo_thresh, 7);
+ regmap_field_write(i2s->field_tx_fifo_thresh, 8);
+
+ return 0;
+}
+
+static void jz4740_i2s_remove(struct snd_soc_component *component)
+{
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+
+ clk_disable_unprepare(i2s->clk_aic);
+}
+
static const struct snd_soc_component_driver jz4740_i2s_component = {
.name = "jz4740-i2s",
+ .probe = jz4740_i2s_probe,
+ .remove = jz4740_i2s_remove,
.suspend = jz4740_i2s_suspend,
.resume = jz4740_i2s_resume,
.legacy_dai_naming = 1,
@@ -494,11 +444,49 @@ static const struct of_device_id jz4740_of_matches[] = {
};
MODULE_DEVICE_TABLE(of, jz4740_of_matches);
+static int jz4740_i2s_init_regmap_fields(struct device *dev,
+ struct jz4740_i2s *i2s)
+{
+ i2s->field_rx_fifo_thresh =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->soc_info->field_rx_fifo_thresh);
+ if (IS_ERR(i2s->field_rx_fifo_thresh))
+ return PTR_ERR(i2s->field_rx_fifo_thresh);
+
+ i2s->field_tx_fifo_thresh =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->soc_info->field_tx_fifo_thresh);
+ if (IS_ERR(i2s->field_tx_fifo_thresh))
+ return PTR_ERR(i2s->field_tx_fifo_thresh);
+
+ i2s->field_i2sdiv_capture =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->soc_info->field_i2sdiv_capture);
+ if (IS_ERR(i2s->field_i2sdiv_capture))
+ return PTR_ERR(i2s->field_i2sdiv_capture);
+
+ i2s->field_i2sdiv_playback =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->soc_info->field_i2sdiv_playback);
+ if (IS_ERR(i2s->field_i2sdiv_playback))
+ return PTR_ERR(i2s->field_i2sdiv_playback);
+
+ return 0;
+}
+
+static const struct regmap_config jz4740_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = JZ_REG_AIC_FIFO,
+};
+
static int jz4740_i2s_dev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct jz4740_i2s *i2s;
struct resource *mem;
+ void __iomem *regs;
int ret;
i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
@@ -507,9 +495,9 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
i2s->soc_info = device_get_match_data(dev);
- i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
- if (IS_ERR(i2s->base))
- return PTR_ERR(i2s->base);
+ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
i2s->playback_dma_data.maxburst = 16;
i2s->playback_dma_data.addr = mem->start + JZ_REG_AIC_FIFO;
@@ -525,6 +513,15 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
if (IS_ERR(i2s->clk_i2s))
return PTR_ERR(i2s->clk_i2s);
+ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &jz4740_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap))
+ return PTR_ERR(i2s->regmap);
+
+ ret = jz4740_i2s_init_regmap_fields(dev, i2s);
+ if (ret)
+ return ret;
+
platform_set_drvdata(pdev, i2s);
ret = devm_snd_soc_register_component(dev, &jz4740_i2s_component,
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
deleted file mode 100644
index 4da14eac1145..000000000000
--- a/sound/soc/jz4740/jz4740-i2s.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef _JZ4740_I2S_H
-#define _JZ4740_I2S_H
-
-/* I2S clock source */
-#define JZ4740_I2S_CLKSRC_EXT 0
-#define JZ4740_I2S_CLKSRC_PLL 1
-
-#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 2a4ffe945177..afdf7d61e4c5 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -31,6 +31,122 @@
(SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
+/* These registers are relative to the second register region -
+ * audio pll configuration.
+ */
+#define A38X_PLL_CONF_REG0 0x0
+#define A38X_PLL_FB_CLK_DIV_OFFSET 10
+#define A38X_PLL_FB_CLK_DIV_MASK 0x7fc00
+#define A38X_PLL_CONF_REG1 0x4
+#define A38X_PLL_FREQ_OFFSET_MASK 0xffff
+#define A38X_PLL_FREQ_OFFSET_VALID BIT(16)
+#define A38X_PLL_SW_RESET BIT(31)
+#define A38X_PLL_CONF_REG2 0x8
+#define A38X_PLL_AUDIO_POSTDIV_MASK 0x7f
+
+/* Bit below belongs to SoC control register corresponding to the third
+ * register region.
+ */
+#define A38X_SPDIF_MODE_ENABLE BIT(27)
+
+static int armada_38x_i2s_init_quirk(struct platform_device *pdev,
+ struct kirkwood_dma_data *priv,
+ struct snd_soc_dai_driver *dai_drv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 reg_val;
+ int i;
+
+ priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
+ if (IS_ERR(priv->pll_config))
+ return -ENOMEM;
+
+ priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
+ if (IS_ERR(priv->soc_control))
+ return -ENOMEM;
+
+ /* Select one of exceptive modes: I2S or S/PDIF */
+ reg_val = readl(priv->soc_control);
+ if (of_property_read_bool(np, "spdif-mode")) {
+ reg_val |= A38X_SPDIF_MODE_ENABLE;
+ dev_info(&pdev->dev, "using S/PDIF mode\n");
+ } else {
+ reg_val &= ~A38X_SPDIF_MODE_ENABLE;
+ dev_info(&pdev->dev, "using I2S mode\n");
+ }
+ writel(reg_val, priv->soc_control);
+
+ /* Update available rates of mclk's fs */
+ for (i = 0; i < 2; i++) {
+ dai_drv[i].playback.rates |= SNDRV_PCM_RATE_192000;
+ dai_drv[i].capture.rates |= SNDRV_PCM_RATE_192000;
+ }
+
+ return 0;
+}
+
+static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
+{
+ u32 reg_val;
+ u16 freq_offset = 0x22b0;
+ u8 audio_postdiv, fb_clk_div = 0x1d;
+
+ /* Set frequency offset value to not valid and enable PLL reset */
+ reg_val = readl(base + A38X_PLL_CONF_REG1);
+ reg_val &= ~A38X_PLL_FREQ_OFFSET_VALID;
+ reg_val &= ~A38X_PLL_SW_RESET;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ udelay(1);
+
+ /* Update PLL parameters */
+ switch (rate) {
+ default:
+ case 44100:
+ freq_offset = 0x735;
+ fb_clk_div = 0x1b;
+ audio_postdiv = 0xc;
+ break;
+ case 48000:
+ audio_postdiv = 0xc;
+ break;
+ case 96000:
+ audio_postdiv = 0x6;
+ break;
+ case 192000:
+ audio_postdiv = 0x3;
+ break;
+ }
+
+ reg_val = readl(base + A38X_PLL_CONF_REG0);
+ reg_val &= ~A38X_PLL_FB_CLK_DIV_MASK;
+ reg_val |= (fb_clk_div << A38X_PLL_FB_CLK_DIV_OFFSET);
+ writel(reg_val, base + A38X_PLL_CONF_REG0);
+
+ reg_val = readl(base + A38X_PLL_CONF_REG2);
+ reg_val &= ~A38X_PLL_AUDIO_POSTDIV_MASK;
+ reg_val |= audio_postdiv;
+ writel(reg_val, base + A38X_PLL_CONF_REG2);
+
+ reg_val = readl(base + A38X_PLL_CONF_REG1);
+ reg_val &= ~A38X_PLL_FREQ_OFFSET_MASK;
+ reg_val |= freq_offset;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ udelay(1);
+
+ /* Disable reset */
+ reg_val |= A38X_PLL_SW_RESET;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ /* Wait 50us for PLL to lock */
+ udelay(50);
+
+ /* Restore frequency offset value validity */
+ reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+}
+
static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
@@ -106,7 +222,10 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
* defined in kirkwood_i2s_dai */
dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
__func__, rate);
- kirkwood_set_dco(priv->io, rate);
+ if (priv->pll_config)
+ armada_38x_set_pll(priv->pll_config, rate);
+ else
+ kirkwood_set_dco(priv->io, rate);
clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
} else {
@@ -532,7 +651,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, priv);
- priv->io = devm_platform_ioremap_resource(pdev, 0);
+ if (of_device_is_compatible(np, "marvell,armada-380-audio"))
+ priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
+ else
+ priv->io = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
@@ -540,6 +662,14 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
if (priv->irq < 0)
return priv->irq;
+ if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
+ err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
+ if (err < 0)
+ return err;
+ /* Set initial pll frequency */
+ armada_38x_set_pll(priv->pll_config, 44100);
+ }
+
if (np) {
priv->burst = 128; /* might be 32 or 128 */
} else if (data) {
@@ -623,6 +753,7 @@ static const struct of_device_id mvebu_audio_of_match[] = {
{ .compatible = "marvell,kirkwood-audio" },
{ .compatible = "marvell,dove-audio" },
{ .compatible = "marvell,armada370-audio" },
+ { .compatible = "marvell,armada-380-audio" },
{ }
};
MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index a1733a6aace5..79bb9aa7f086 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -131,6 +131,8 @@
struct kirkwood_dma_data {
void __iomem *io;
+ void __iomem *pll_config;
+ void __iomem *soc_control;
struct clk *clk;
struct clk *extclk;
uint32_t ctl_play;
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index d884bb7c0fc7..1c28b41e4311 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -1038,11 +1038,9 @@ static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component,
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- mtk_btcvsd_snd_write(bt, buf, count);
+ return mtk_btcvsd_snd_write(bt, buf, count);
else
- mtk_btcvsd_snd_read(bt, buf, count);
-
- return 0;
+ return mtk_btcvsd_snd_read(bt, buf, count);
}
/* kcontrol */
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
index d9fd6eb786aa..08ef109744c7 100644
--- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -418,6 +418,7 @@ static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
{.compatible = "mediatek,mt2701-cs42448-machine",},
{}
};
+MODULE_DEVICE_TABLE(of, mt2701_cs42448_machine_dt_match);
#endif
static struct platform_driver mt2701_cs42448_machine = {
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
index 0cdf2ae36243..a184032c15b6 100644
--- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -161,6 +161,7 @@ static const struct of_device_id mt2701_wm8960_machine_dt_match[] = {
{.compatible = "mediatek,mt2701-wm8960-machine",},
{}
};
+MODULE_DEVICE_TABLE(of, mt2701_wm8960_machine_dt_match);
#endif
static struct platform_driver mt2701_wm8960_machine = {
diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
index d2f6213a6bfc..784c201b8fd4 100644
--- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c
+++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
@@ -242,6 +242,7 @@ static const struct of_device_id mt6797_mt6351_dt_match[] = {
{.compatible = "mediatek,mt6797-mt6351-sound",},
{}
};
+MODULE_DEVICE_TABLE(of, mt6797_mt6351_dt_match);
#endif
static struct platform_driver mt6797_mt6351_driver = {
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index dcaeeeb8aac7..bc155dd937e0 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1070,16 +1070,6 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
afe->dev = &pdev->dev;
- irq_id = platform_get_irq(pdev, 0);
- if (irq_id <= 0)
- return irq_id < 0 ? irq_id : -ENXIO;
- ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
- 0, "Afe_ISR_Handle", (void *)afe);
- if (ret) {
- dev_err(afe->dev, "could not request_irq\n");
- return ret;
- }
-
afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(afe->base_addr))
return PTR_ERR(afe->base_addr);
@@ -1185,6 +1175,16 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
goto err_cleanup_components;
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id <= 0)
+ return irq_id < 0 ? irq_id : -ENXIO;
+ ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
+ 0, "Afe_ISR_Handle", (void *)afe);
+ if (ret) {
+ dev_err(afe->dev, "could not request_irq\n");
+ goto err_pm_disable;
+ }
+
dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n");
return 0;
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 9f22d3939818..87bb04846991 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -14,7 +14,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include "../../codecs/da7219-aad.h"
#include "../../codecs/da7219.h"
#include "../../codecs/rt1015.h"
#include "../common/mtk-afe-platform-driver.h"
@@ -592,7 +591,7 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
snd_jack_set_key(
priv->headset_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &priv->headset_jack);
+ snd_soc_component_set_jack(component, &priv->headset_jack, NULL);
return 0;
}
@@ -842,6 +841,7 @@ static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, mt8183_da7219_max98357_dt_match);
#endif
static struct platform_driver mt8183_da7219_max98357_driver = {
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index a86085223677..8fb473543cf9 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -835,6 +835,7 @@ static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, mt8183_mt6358_ts3a227_max98357_dt_match);
#endif
static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
index cfca6bdee834..970b980a81e6 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
@@ -11,10 +11,10 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include "../../codecs/da7219-aad.h"
#include "../../codecs/da7219.h"
#include "../../codecs/mt6358.h"
#include "../common/mtk-afe-platform-driver.h"
@@ -100,7 +100,7 @@ static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(cmpnt_codec, &priv->headset_jack);
+ snd_soc_component_set_jack(cmpnt_codec, &priv->headset_jack, NULL);
return 0;
}
@@ -192,7 +192,7 @@ static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *r
struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv;
int ret;
- ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2");
+ ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
if (ret) {
dev_err(rtd->dev, "Failed to set up shared clocks\n");
return ret;
@@ -1161,6 +1161,7 @@ static const struct of_device_id mt8186_mt6366_da7219_max98357_dt_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, mt8186_mt6366_da7219_max98357_dt_match);
#endif
static struct platform_driver mt8186_mt6366_da7219_max98357_driver = {
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
index 2414c5b77233..8f77a0bc1dc8 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
@@ -7,6 +7,8 @@
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
//
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -39,6 +41,8 @@
struct mt8186_mt6366_rt1019_rt5682s_priv {
struct snd_soc_jack headset_jack, hdmi_jack;
+ struct gpio_desc *dmic_sel;
+ int dmic_switch;
};
/* Headset jack detection DAPM pins */
@@ -68,6 +72,94 @@ static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = {
},
};
+static int dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct mtk_soc_card_data *soc_card_data =
+ snd_soc_card_get_drvdata(dapm->card);
+ struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+
+ ucontrol->value.integer.value[0] = priv->dmic_switch;
+ return 0;
+}
+
+static int dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct mtk_soc_card_data *soc_card_data =
+ snd_soc_card_get_drvdata(dapm->card);
+ struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+
+ priv->dmic_switch = ucontrol->value.integer.value[0];
+ if (priv->dmic_sel) {
+ gpiod_set_value(priv->dmic_sel, priv->dmic_switch);
+ dev_info(dapm->card->dev, "dmic_set_value %d\n",
+ priv->dmic_switch);
+ }
+ return 0;
+}
+
+static const char * const dmic_mux_text[] = {
+ "Front Mic",
+ "Rear Mic",
+};
+
+static SOC_ENUM_SINGLE_DECL(mt8186_dmic_enum,
+ SND_SOC_NOPM, 0, dmic_mux_text);
+
+static const struct snd_kcontrol_new mt8186_dmic_mux_control =
+ SOC_DAPM_ENUM_EXT("DMIC Select Mux", mt8186_dmic_enum,
+ dmic_get, dmic_set);
+
+static const struct snd_soc_dapm_widget dmic_widgets[] = {
+ SND_SOC_DAPM_MIC("DMIC", NULL),
+ SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &mt8186_dmic_mux_control),
+};
+
+static const struct snd_soc_dapm_route dmic_map[] = {
+ /* digital mics */
+ {"Dmic Mux", "Front Mic", "DMIC"},
+ {"Dmic Mux", "Rear Mic", "DMIC"},
+};
+
+static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+ int ret;
+
+ ret = mt8186_mt6366_init(rtd);
+
+ if (ret) {
+ dev_err(card->dev, "mt8186_mt6366_init failed: %d\n", ret);
+ return ret;
+ }
+
+ if (!priv->dmic_sel) {
+ dev_info(card->dev, "dmic_sel is null\n");
+ return ret;
+ }
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+ ARRAY_SIZE(dmic_widgets));
+ if (ret) {
+ dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
+ /* Don't need to add routes if widget addition failed */
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+ ARRAY_SIZE(dmic_map));
+
+ if (ret)
+ dev_err(card->dev, "DMic map addition failed: %d\n", ret);
+
+ return ret;
+}
+
static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_afe =
@@ -168,7 +260,7 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt
struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
int ret;
- ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2");
+ ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
if (ret) {
dev_err(rtd->dev, "Failed to set up shared clocks\n");
return ret;
@@ -775,7 +867,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
- .init = mt8186_mt6366_init,
+ .init = primary_codec_init,
SND_SOC_DAILINK_REG(adda),
},
{
@@ -1015,6 +1107,14 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
soc_card_data->mach_priv = mach_priv;
+ mach_priv->dmic_sel = devm_gpiod_get_optional(&pdev->dev,
+ "dmic", GPIOD_OUT_LOW);
+ if (IS_ERR(mach_priv->dmic_sel)) {
+ dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n",
+ PTR_ERR(mach_priv->dmic_sel));
+ return PTR_ERR(mach_priv->dmic_sel);
+ }
+
adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
if (adsp_node) {
struct mtk_sof_priv *sof_priv;
@@ -1137,6 +1237,7 @@ static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
#endif
static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = {
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index b93c3237ef2d..16660eda577e 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -1261,6 +1261,7 @@ static const struct of_device_id mt8192_mt6359_dt_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, mt8192_mt6359_dt_match);
#endif
static const struct dev_pm_ops mt8192_mt6359_pm_ops = {
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
index 480ed3e08d5b..61be66f47723 100644
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -1544,6 +1544,7 @@ static const struct of_device_id mt8195_mt6359_dt_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, mt8195_mt6359_dt_match);
static struct platform_driver mt8195_mt6359_driver = {
.driver = {
diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c
index 88ac58272f95..ad43cb2a1e3f 100644
--- a/sound/soc/meson/axg-pdm.c
+++ b/sound/soc/meson/axg-pdm.c
@@ -169,7 +169,7 @@ static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os,
/*
* Set the default system clock rate unless it is too fast for
- * for the requested sample rate. In this case, the sample pointer
+ * the requested sample rate. In this case, the sample pointer
* counter could overflow so set a lower system clock rate
*/
if (sys_rate < priv->cfg->sys_rate)
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 5d520e18e512..99b245e3079a 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -98,7 +98,7 @@ static bool filter(struct dma_chan *chan, void *param)
devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
dma_data->ssp_id);
- if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+ if (devname && (strcmp(dev_name(chan->device->dev), devname) == 0) &&
(chan->chan_id == dma_data->dma_res->start)) {
found = true;
}
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 8c7398bc1ca8..96a6d4731e6f 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -2,6 +2,7 @@
menuconfig SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
depends on ARCH_QCOM || COMPILE_TEST
+ imply SND_SOC_QCOM_COMMON
help
Say Y or M if you want to add support to use audio devices
in Qualcomm Technologies SOC-based platforms.
@@ -59,13 +60,14 @@ config SND_SOC_STORM
config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms"
select SND_SOC_LPASS_APQ8016
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
help
Support for Qualcomm Technologies LPASS audio block in
APQ8016 SOC-based systems.
Say Y if you want to use audio devices on MI2S.
config SND_SOC_QCOM_COMMON
+ depends on SOUNDWIRE
tristate
config SND_SOC_QDSP6_COMMON
@@ -142,7 +144,7 @@ config SND_SOC_MSM8996
depends on QCOM_APR
depends on COMMON_CLK
select SND_SOC_QDSP6
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
help
Support for Qualcomm Technologies LPASS audio block in
APQ8096 SoC-based systems.
@@ -153,7 +155,7 @@ config SND_SOC_SDM845
depends on QCOM_APR && I2C && SOUNDWIRE
depends on COMMON_CLK
select SND_SOC_QDSP6
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
select SND_SOC_RT5663
select SND_SOC_MAX98927
imply SND_SOC_CROS_EC_CODEC
@@ -167,7 +169,7 @@ config SND_SOC_SM8250
depends on QCOM_APR && SOUNDWIRE
depends on COMMON_CLK
select SND_SOC_QDSP6
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
help
To add support for audio on Qualcomm Technologies Inc.
SM8250 SoC-based systems.
@@ -178,7 +180,7 @@ config SND_SOC_SC8280XP
depends on QCOM_APR && SOUNDWIRE
depends on COMMON_CLK
select SND_SOC_QDSP6
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
help
To add support for audio on Qualcomm Technologies Inc.
SC8280XP SoC-based systems.
@@ -188,7 +190,7 @@ config SND_SOC_SC7180
tristate "SoC Machine driver for SC7180 boards"
depends on I2C && GPIOLIB
depends on SOUNDWIRE || SOUNDWIRE=n
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
select SND_SOC_LPASS_SC7180
select SND_SOC_MAX98357A
select SND_SOC_RT5682_I2C
@@ -202,7 +204,7 @@ config SND_SOC_SC7180
config SND_SOC_SC7280
tristate "SoC Machine driver for SC7280 boards"
depends on I2C && SOUNDWIRE
- select SND_SOC_QCOM_COMMON
+ depends on SND_SOC_QCOM_COMMON
select SND_SOC_LPASS_SC7280
select SND_SOC_MAX98357A
select SND_SOC_WCD938X_SDW
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 69dd3b504e20..49c74c1662a3 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -180,7 +180,6 @@ err_put_np:
}
EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
-#if IS_ENABLED(CONFIG_SOUNDWIRE)
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared)
@@ -294,7 +293,6 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
-#endif
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup)
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index c5472a642de0..3ef5bb6d12df 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -11,7 +11,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup);
-#if IS_ENABLED(CONFIG_SOUNDWIRE)
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *runtime,
bool *stream_prepared);
@@ -21,26 +20,4 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared);
-#else
-static inline int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *runtime,
- bool *stream_prepared)
-{
- return -ENOTSUPP;
-}
-
-static inline int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct sdw_stream_runtime **psruntime)
-{
- return -ENOTSUPP;
-}
-
-static inline int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *sruntime,
- bool *stream_prepared)
-{
- return -ENOTSUPP;
-}
-#endif
#endif
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index 77a556b27cf0..41db6617e2ed 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <dt-bindings/sound/sc7180-lpass.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -131,6 +132,9 @@ static int sc7180_lpass_init(struct platform_device *pdev)
drvdata->clks = devm_kcalloc(dev, variant->num_clks,
sizeof(*drvdata->clks), GFP_KERNEL);
+ if (!drvdata->clks)
+ return -ENOMEM;
+
drvdata->num_clks = variant->num_clks;
for (i = 0; i < drvdata->num_clks; i++)
@@ -156,10 +160,28 @@ static int sc7180_lpass_exit(struct platform_device *pdev)
struct lpass_data *drvdata = platform_get_drvdata(pdev);
clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
+ return 0;
+}
+
+static int __maybe_unused sc7180_lpass_dev_resume(struct device *dev)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+
+ return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
+}
+
+static int __maybe_unused sc7180_lpass_dev_suspend(struct device *dev)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
return 0;
}
+static const struct dev_pm_ops sc7180_lpass_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume)
+};
+
static struct lpass_variant sc7180_data = {
.i2sctrl_reg_base = 0x1000,
.i2sctrl_reg_stride = 0x1000,
@@ -293,6 +315,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = {
.driver = {
.name = "sc7180-lpass-cpu",
.of_match_table = of_match_ptr(sc7180_lpass_cpu_device_id),
+ .pm = &sc7180_lpass_pm_ops,
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
.remove = asoc_qcom_lpass_cpu_platform_remove,
diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
index 70c4df87d957..d43f480cbae3 100644
--- a/sound/soc/qcom/lpass-sc7280.c
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -232,10 +232,28 @@ static int sc7280_lpass_exit(struct platform_device *pdev)
struct lpass_data *drvdata = platform_get_drvdata(pdev);
clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
+ return 0;
+}
+
+static int __maybe_unused sc7280_lpass_dev_resume(struct device *dev)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+
+ return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
+}
+static int __maybe_unused sc7280_lpass_dev_suspend(struct device *dev)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
return 0;
}
+static const struct dev_pm_ops sc7280_lpass_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume)
+};
+
static struct lpass_variant sc7280_data = {
.i2sctrl_reg_base = 0x1000,
.i2sctrl_reg_stride = 0x1000,
@@ -426,6 +444,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = {
.driver = {
.name = "sc7280-lpass-cpu",
.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
+ .pm = &sc7280_lpass_pm_ops,
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
.remove = asoc_qcom_lpass_cpu_platform_remove,
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 01dac32c50fd..1e0c918eb576 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -159,6 +159,8 @@ struct apm_module_hw_ep_mf_cfg {
#define APM_HW_EP_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_mf_cfg), 8)
+#define APM_MFC_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4)
+
struct apm_module_frame_size_factor_cfg {
struct apm_module_param_data param_data;
uint32_t frame_size_factor;
@@ -311,15 +313,6 @@ static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg,
cfg->sid.scenario_id = sg->scenario_id;
}
-static void apm_populate_connection_obj(struct apm_module_conn_obj *obj,
- struct audioreach_module *module)
-{
- obj->src_mod_inst_id = module->src_mod_inst_id;
- obj->src_mod_op_port_id = module->src_mod_op_port_id;
- obj->dst_mod_inst_id = module->instance_id;
- obj->dst_mod_ip_port_id = module->in_port;
-}
-
static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
struct audioreach_module *module)
{
@@ -332,63 +325,6 @@ static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
obj->prop_id_port.max_op_port = module->max_op_port;
}
-struct audioreach_module *audioreach_get_container_last_module(
- struct audioreach_container *container)
-{
- struct audioreach_module *module;
-
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->dst_mod_inst_id == 0)
- return module;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_last_module);
-
-static bool is_module_in_container(struct audioreach_container *container, int module_iid)
-{
- struct audioreach_module *module;
-
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->instance_id == module_iid)
- return true;
- }
-
- return false;
-}
-
-struct audioreach_module *audioreach_get_container_first_module(
- struct audioreach_container *container)
-{
- struct audioreach_module *module;
-
- /* get the first module from both connected or un-connected containers */
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->src_mod_inst_id == 0 ||
- !is_module_in_container(container, module->src_mod_inst_id))
- return module;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_first_module);
-
-struct audioreach_module *audioreach_get_container_next_module(
- struct audioreach_container *container,
- struct audioreach_module *module)
-{
- int nmodule_iid = module->dst_mod_inst_id;
- struct audioreach_module *nmodule;
-
- list_for_each_entry(nmodule, &container->modules_list, node) {
- if (nmodule->instance_id == nmodule_iid)
- return nmodule;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_next_module);
-
static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
struct audioreach_container *container,
int sub_graph_id)
@@ -400,14 +336,15 @@ static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
obj->container_id = container->container_id;
obj->num_modules = container->num_modules;
i = 0;
- list_for_each_container_module(module, container) {
+ list_for_each_entry(module, &container->modules_list, node) {
obj->mod_cfg[i].module_id = module->module_id;
obj->mod_cfg[i].instance_id = module->instance_id;
i++;
}
}
-static void audioreach_populate_graph(struct apm_graph_open_params *open,
+static void audioreach_populate_graph(struct q6apm *apm, struct audioreach_graph_info *info,
+ struct apm_graph_open_params *open,
struct list_head *sg_list,
int num_sub_graphs)
{
@@ -428,6 +365,16 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
mlobj = &ml_data->mod_list_obj[0];
+
+ if (info->dst_mod_inst_id && info->src_mod_inst_id) {
+ conn_obj = &mc_data->conn_obj[nconn];
+ conn_obj->src_mod_inst_id = info->src_mod_inst_id;
+ conn_obj->src_mod_op_port_id = info->src_mod_op_port_id;
+ conn_obj->dst_mod_inst_id = info->dst_mod_inst_id;
+ conn_obj->dst_mod_ip_port_id = info->dst_mod_ip_port_id;
+ nconn++;
+ }
+
list_for_each_entry(sg, sg_list, node) {
struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++];
@@ -439,30 +386,38 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
apm_populate_container_config(cobj, container);
apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id);
- list_for_each_container_module(module, container) {
- uint32_t src_mod_inst_id;
-
- src_mod_inst_id = module->src_mod_inst_id;
+ list_for_each_entry(module, &container->modules_list, node) {
+ int pn;
- module_prop_obj = &mp_data->mod_prop_obj[nmodule];
+ module_prop_obj = &mp_data->mod_prop_obj[nmodule++];
apm_populate_module_prop_obj(module_prop_obj, module);
- if (src_mod_inst_id) {
- conn_obj = &mc_data->conn_obj[nconn];
- apm_populate_connection_obj(conn_obj, module);
- nconn++;
+ if (!module->max_op_port)
+ continue;
+
+ for (pn = 0; pn < module->max_op_port; pn++) {
+ if (module->dst_mod_inst_id[pn]) {
+ conn_obj = &mc_data->conn_obj[nconn];
+ conn_obj->src_mod_inst_id = module->instance_id;
+ conn_obj->src_mod_op_port_id =
+ module->src_mod_op_port_id[pn];
+ conn_obj->dst_mod_inst_id =
+ module->dst_mod_inst_id[pn];
+ conn_obj->dst_mod_ip_port_id =
+ module->dst_mod_ip_port_id[pn];
+ nconn++;
+ }
}
-
- nmodule++;
}
- mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+ mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj,
+ container->num_modules);
ncontainer++;
}
}
}
-void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id)
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info *info)
{
int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz;
struct apm_module_param_data *param_data;
@@ -475,7 +430,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
struct audioreach_module *module;
struct audioreach_sub_graph *sgs;
struct apm_mod_list_obj *mlobj;
- int num_modules_per_list;
+ struct list_head *sg_list;
int num_connections = 0;
int num_containers = 0;
int num_sub_graphs = 0;
@@ -484,24 +439,33 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
struct gpr_pkt *pkt;
void *p;
+ sg_list = &info->sg_list;
+ ml_sz = 0;
+
+ /* add FE-BE connections */
+ if (info->dst_mod_inst_id && info->src_mod_inst_id)
+ num_connections++;
+
list_for_each_entry(sgs, sg_list, node) {
num_sub_graphs++;
list_for_each_entry(container, &sgs->container_list, node) {
num_containers++;
num_modules += container->num_modules;
- list_for_each_container_module(module, container) {
- if (module->src_mod_inst_id)
- num_connections++;
+ ml_sz = ml_sz + sizeof(struct apm_module_list_params) +
+ APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+
+ list_for_each_entry(module, &container->modules_list, node) {
+ num_connections += module->num_connections;
}
}
}
num_modules_list = num_containers;
- num_modules_per_list = num_modules/num_containers;
sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs);
cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers);
- ml_sz = ALIGN(sizeof(struct apm_module_list_params) +
- num_modules_list * APM_MOD_LIST_OBJ_PSIZE(mlobj, num_modules_per_list), 8);
+
+ ml_sz = ALIGN(ml_sz, 8);
+
mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules);
mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections);
@@ -536,7 +500,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_MODULE_LIST;
param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE;
- params.mod_list_data->num_modules_list = num_sub_graphs;
+ params.mod_list_data->num_modules_list = num_modules_list;
p += ml_sz;
/* Module Properties */
@@ -557,7 +521,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
params.mod_conn_list_data->num_connections = num_connections;
p += mc_sz;
- audioreach_populate_graph(&params, sg_list, num_sub_graphs);
+ audioreach_populate_graph(apm, info, &params, sg_list, num_sub_graphs);
return pkt;
}
@@ -696,6 +660,160 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
return rc;
}
+static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
+ struct audioreach_module *module, bool enable)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_sal_limiter_enable *limiter_enable;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*limiter_enable) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_SAL_LIMITER_ENABLE;
+ param_data->param_size = sizeof(*limiter_enable);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ limiter_enable = p;
+
+ limiter_enable->enable_lim = enable;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_sal_set_media_format(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_sal_output_config *media_format;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*media_format) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_SAL_OUTPUT_CFG;
+ param_data->param_size = sizeof(*media_format);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ media_format = p;
+
+ media_format->bits_per_sample = cfg->bit_width;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_module_enable(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ bool enable)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_module_enable *param;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*param) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_MODULE_ENABLE;
+ param_data->param_size = sizeof(*param);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ param = p;
+
+ param->enable = enable;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_mfc_media_format *media_format;
+ uint32_t num_channels = cfg->num_channels;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
+ APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+ param_data->param_size = APM_MFC_CFG_PSIZE(media_format, num_channels);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ media_format = p;
+
+ media_format->sample_rate = cfg->sample_rate;
+ media_format->bit_width = cfg->bit_width;
+ media_format->num_channels = cfg->num_channels;
+
+ if (num_channels == 1) {
+ media_format->channel_mapping[0] = PCM_CHANNEL_L;
+ } else if (num_channels == 2) {
+ media_format->channel_mapping[0] = PCM_CHANNEL_L;
+ media_format->channel_mapping[1] = PCM_CHANNEL_R;
+ }
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
struct audioreach_module *module,
struct audioreach_module_config *cfg)
@@ -995,7 +1113,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
switch (module->module_id) {
case MODULE_ID_DATA_LOGGING:
- rc = audioreach_logging_set_media_format(graph, module);
+ rc = audioreach_module_enable(graph, module, true);
+ if (!rc)
+ rc = audioreach_logging_set_media_format(graph, module);
break;
case MODULE_ID_PCM_DEC:
case MODULE_ID_PCM_ENC:
@@ -1016,6 +1136,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
case MODULE_ID_CODEC_DMA_SOURCE:
rc = audioreach_codec_dma_set_media_format(graph, module, cfg);
break;
+ case MODULE_ID_SAL:
+ rc = audioreach_sal_set_media_format(graph, module, cfg);
+ if (!rc)
+ rc = audioreach_sal_limiter_enable(graph, module, true);
+ break;
+ case MODULE_ID_MFC:
+ rc = audioreach_mfc_set_media_format(graph, module, cfg);
+ break;
default:
rc = 0;
}
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 3ee8bfcd0121..1d1d47d47d40 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -15,6 +15,8 @@ struct q6apm_graph;
#define MODULE_ID_PCM_CNV 0x07001003
#define MODULE_ID_PCM_ENC 0x07001004
#define MODULE_ID_PCM_DEC 0x07001005
+#define MODULE_ID_SAL 0x07001010
+#define MODULE_ID_MFC 0x07001015
#define MODULE_ID_CODEC_DMA_SINK 0x07001023
#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024
#define MODULE_ID_I2S_SINK 0x0700100A
@@ -499,6 +501,16 @@ struct data_logging_config {
uint32_t mode;
} __packed;
+#define PARAM_ID_SAL_OUTPUT_CFG 0x08001016
+struct param_id_sal_output_config {
+ uint32_t bits_per_sample;
+} __packed;
+
+#define PARAM_ID_SAL_LIMITER_ENABLE 0x0800101E
+struct param_id_sal_limiter_enable {
+ uint32_t enable_lim;
+} __packed;
+
#define PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x08001024
struct param_id_mfc_media_format {
@@ -525,6 +537,11 @@ struct payload_media_fmt_pcm {
uint8_t channel_mapping[];
} __packed;
+#define PARAM_ID_MODULE_ENABLE 0x08001026
+struct param_id_module_enable {
+ uint32_t enable;
+} __packed;
+
#define PARAM_ID_CODEC_DMA_INTF_CFG 0x08001063
struct param_id_codec_dma_intf_cfg {
@@ -595,7 +612,11 @@ struct audioreach_graph_info {
int id;
uint32_t num_sub_graphs;
struct list_head sg_list;
- struct list_head connection_list;
+ /* DPCM connection from FE Graph to BE graph */
+ uint32_t src_mod_inst_id;
+ uint32_t src_mod_op_port_id;
+ uint32_t dst_mod_inst_id;
+ uint32_t dst_mod_ip_port_id;
};
struct audioreach_sub_graph {
@@ -623,6 +644,8 @@ struct audioreach_container {
struct audioreach_sub_graph *sub_graph;
};
+#define AR_MAX_MOD_LINKS 8
+
struct audioreach_module {
uint32_t module_id;
uint32_t instance_id;
@@ -633,11 +656,12 @@ struct audioreach_module {
uint32_t in_port;
uint32_t out_port;
+ uint32_t num_connections;
/* Connections */
uint32_t src_mod_inst_id;
- uint32_t src_mod_op_port_id;
- uint32_t dst_mod_inst_id;
- uint32_t dst_mod_ip_port_id;
+ uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS];
+ uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS];
+ uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS];
/* Format specifics */
uint32_t ch_fmt;
@@ -694,9 +718,8 @@ void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token,
void *audioreach_alloc_pkt(int payload_size, uint32_t opcode,
uint32_t token, uint32_t src_port,
uint32_t dest_port);
-void *audioreach_alloc_graph_pkt(struct q6apm *apm,
- struct list_head *sg_list,
- int graph_id);
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info
+ *info);
/* Topology specific */
int audioreach_tplg_init(struct snd_soc_component *component);
@@ -717,14 +740,4 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph);
int audioreach_gain_set_vol_ctrl(struct q6apm *apm,
struct audioreach_module *module, int vol);
-struct audioreach_module *audioreach_get_container_last_module(
- struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_first_module(
- struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_next_module(
- struct audioreach_container *container,
- struct audioreach_module *module);
-#define list_for_each_container_module(mod, cont) \
- for (mod = audioreach_get_container_first_module(cont); mod != NULL; \
- mod = audioreach_get_container_next_module(cont, mod))
#endif /* __AUDIOREACH_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 794019286c70..5beb898f28f5 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -63,7 +63,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
graph->info = info;
graph->id = graph_id;
- graph->graph = audioreach_alloc_graph_pkt(apm, &info->sg_list, graph_id);
+ graph->graph = audioreach_alloc_graph_pkt(apm, info);
if (IS_ERR(graph->graph)) {
void *err = graph->graph;
@@ -178,87 +178,6 @@ static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
return NULL;
}
-static struct audioreach_module *q6apm_graph_get_last_module(struct q6apm *apm, u32 sgid)
-{
- struct audioreach_container *container;
- struct audioreach_module *module;
- struct audioreach_sub_graph *sg;
-
- mutex_lock(&apm->lock);
- sg = idr_find(&apm->sub_graphs_idr, sgid);
- mutex_unlock(&apm->lock);
- if (!sg)
- return NULL;
-
- container = list_last_entry(&sg->container_list, struct audioreach_container, node);
- module = audioreach_get_container_last_module(container);
-
- return module;
-}
-
-static struct audioreach_module *q6apm_graph_get_first_module(struct q6apm *apm, u32 sgid)
-{
- struct audioreach_container *container;
- struct audioreach_module *module;
- struct audioreach_sub_graph *sg;
-
- mutex_lock(&apm->lock);
- sg = idr_find(&apm->sub_graphs_idr, sgid);
- mutex_unlock(&apm->lock);
- if (!sg)
- return NULL;
-
- container = list_first_entry(&sg->container_list, struct audioreach_container, node);
- module = audioreach_get_container_first_module(container);
-
- return module;
-}
-
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, u32 dst_sgid)
-{
- struct audioreach_module *module;
- u32 iid;
-
- module = q6apm_graph_get_last_module(apm, src_sgid);
- if (!module)
- return false;
-
- iid = module->instance_id;
- module = q6apm_graph_get_first_module(apm, dst_sgid);
- if (!module)
- return false;
-
- if (module->src_mod_inst_id == iid)
- return true;
-
- return false;
-}
-
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, bool connect)
-{
- struct audioreach_module *module;
- u32 iid;
-
- if (connect) {
- module = q6apm_graph_get_last_module(apm, src_sgid);
- if (!module)
- return -ENODEV;
-
- iid = module->instance_id;
- } else {
- iid = 0;
- }
-
- module = q6apm_graph_get_first_module(apm, dst_sgid);
- if (!module)
- return -ENODEV;
-
- /* set src module in dst subgraph first module */
- module->src_mod_inst_id = iid;
-
- return 0;
-}
-
int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
struct audioreach_module_config *cfg)
{
@@ -731,6 +650,7 @@ static int apm_probe(gpr_device_t *gdev)
apm->gdev = gdev;
init_waitqueue_head(&apm->wait);
+ INIT_LIST_HEAD(&apm->widget_list);
idr_init(&apm->graph_idr);
idr_init(&apm->graph_info_idr);
idr_init(&apm->sub_graphs_idr);
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 54eadadf712c..273f97812741 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -58,6 +58,7 @@ struct q6apm {
struct mutex lock;
uint32_t state;
+ struct list_head widget_list;
struct idr graph_idr;
struct idr graph_info_idr;
struct idr sub_graphs_idr;
@@ -141,12 +142,7 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
/* Callback for graph specific */
struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
uint32_t mid);
-
void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid,
- bool connect);
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid,
- u32 dst_sgid);
int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
#endif /* __APM_GRAPH_ */
diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c
index cda33ded29be..8aa1a213bfb7 100644
--- a/sound/soc/qcom/qdsp6/q6prm.c
+++ b/sound/soc/qcom/qdsp6/q6prm.c
@@ -247,5 +247,5 @@ static gpr_driver_t prm_driver = {
};
module_gpr_driver(prm_driver);
-MODULE_DESCRIPTION("Audio Process Manager");
+MODULE_DESCRIPTION("Q6 Proxy Resource Manager");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index bd649c232a06..cccc59b570b9 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -16,7 +16,11 @@
#include "audioreach.h"
struct snd_ar_control {
+ u32 graph_id; /* Graph ID */
u32 sgid; /* Sub Graph ID */
+ u32 module_instance_id; /* Connected Module Instance ID */
+ struct snd_soc_dapm_widget *w;
+ struct list_head node;
struct snd_soc_component *scomp;
};
@@ -44,7 +48,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
INIT_LIST_HEAD(&info->sg_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -53,7 +57,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
return ERR_PTR(ret);
}
- info->id = ret;
+ info->id = graph_id;
return info;
}
@@ -94,7 +98,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
INIT_LIST_HEAD(&sg->container_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -103,7 +107,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
return ERR_PTR(ret);
}
- sg->sub_graph_id = ret;
+ sg->sub_graph_id = sub_graph_id;
return sg;
}
@@ -136,7 +140,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
INIT_LIST_HEAD(&cont->modules_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -145,7 +149,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
return ERR_PTR(ret);
}
- cont->container_id = ret;
+ cont->container_id = container_id;
cont->sub_graph = sg;
/* add to container list */
list_add_tail(&cont->node, &sg->container_list);
@@ -181,7 +185,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
AR_MODULE_DYNAMIC_INSTANCE_ID_START,
AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
} else {
- ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL);
}
mutex_unlock(&apm->lock);
@@ -191,7 +195,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
return ERR_PTR(ret);
}
- mod->instance_id = ret;
+ mod->instance_id = module_id;
/* add to module list */
list_add_tail(&mod->node, &cont->modules_list);
mod->container = cont;
@@ -408,19 +412,25 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
struct snd_soc_dapm_widget *w)
{
uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
- uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0;
- uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0;
+ uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t src_mod_inst_id = 0;
+
int module_id = 0, instance_id = 0, tkn_count = 0;
struct snd_soc_tplg_vendor_value_elem *mod_elem;
struct snd_soc_tplg_vendor_array *mod_array;
struct audioreach_module *mod = NULL;
+ uint32_t token;
bool found;
+ int max_tokens;
mod_array = audioreach_get_module_array(private);
mod_elem = mod_array->value;
-
- while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
- switch (le32_to_cpu(mod_elem->token)) {
+ max_tokens = le32_to_cpu(mod_array->num_elems);
+ while (tkn_count <= (max_tokens - 1)) {
+ token = le32_to_cpu(mod_elem->token);
+ switch (token) {
/* common module info */
case AR_TKN_U32_MODULE_ID:
module_id = le32_to_cpu(mod_elem->value);
@@ -450,17 +460,80 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
case AR_TKN_U32_MODULE_OUT_PORTS:
out_port = le32_to_cpu(mod_elem->value);
break;
- case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
- src_mod_op_port_id = le32_to_cpu(mod_elem->value);
- break;
case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
src_mod_inst_id = le32_to_cpu(mod_elem->value);
break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
+ src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
+ src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
+ src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
+ src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
+ src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
+ src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
+ src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
+ src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
+ break;
case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
- dst_mod_inst_id = le32_to_cpu(mod_elem->value);
+ dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
+ dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
+ dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
+ dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
+ dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
+ dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
+ dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
+ dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
break;
case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
- dst_mod_ip_port_id = le32_to_cpu(mod_elem->value);
+ dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
+ dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
+ dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
+ dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
+ dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
+ dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
+ dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
+ dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
break;
default:
break;
@@ -471,15 +544,23 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
}
if (mod) {
+ int pn, id = 0;
mod->module_id = module_id;
mod->max_ip_port = max_ip_port;
mod->max_op_port = max_op_port;
mod->in_port = in_port;
mod->out_port = out_port;
mod->src_mod_inst_id = src_mod_inst_id;
- mod->src_mod_op_port_id = src_mod_op_port_id;
- mod->dst_mod_inst_id = dst_mod_inst_id;
- mod->dst_mod_ip_port_id = dst_mod_ip_port_id;
+ for (pn = 0; pn < mod->max_op_port; pn++) {
+ if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
+ dst_mod_ip_port_id[pn]) {
+ mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
+ mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
+ mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
+ id++;
+ mod->num_connections = id;
+ }
+ }
}
return mod;
@@ -692,6 +773,7 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
struct snd_soc_tplg_vendor_value_elem *w_elem;
struct snd_soc_tplg_vendor_array *w_array;
struct snd_ar_control *scontrol;
+ struct q6apm *data = dev_get_drvdata(component->dev);
struct snd_soc_dobj *dobj;
int tkn_count = 0;
@@ -711,6 +793,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
scontrol->sgid = le32_to_cpu(w_elem->value);
break;
+ case AR_TKN_DAI_INDEX:
+ scontrol->graph_id = le32_to_cpu(w_elem->value);
+ break;
default: /* ignore other tokens */
break;
}
@@ -718,6 +803,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
w_elem++;
}
+ scontrol->w = w;
+ list_add_tail(&scontrol->node, &data->widget_list);
+
return 0;
}
@@ -819,7 +907,10 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
if (w->id == snd_soc_dapm_mixer) {
/* virtual widget */
- kfree(dobj->private);
+ struct snd_ar_control *scontrol = dobj->private;
+
+ list_del(&scontrol->node);
+ kfree(scontrol);
return 0;
}
@@ -858,7 +949,21 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
return 0;
}
-static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp,
+static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
+ const char *name)
+{
+ struct q6apm *apm = dev_get_drvdata(comp->dev);
+ struct snd_ar_control *control;
+
+ list_for_each_entry(control, &apm->widget_list, node) {
+ if (control->w && !strcmp(name, control->w->name))
+ return control;
+ }
+
+ return NULL;
+}
+
+static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
const char *name)
{
struct q6apm *apm = dev_get_drvdata(comp->dev);
@@ -876,14 +981,41 @@ static struct audioreach_module *audioreach_find_widget(struct snd_soc_component
static int audioreach_route_load(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_route *route)
{
- struct audioreach_module *src, *sink;
-
- src = audioreach_find_widget(scomp, route->source);
- sink = audioreach_find_widget(scomp, route->sink);
+ struct audioreach_module *src_module, *sink_module;
+ struct snd_ar_control *control;
+ struct snd_soc_dapm_widget *w;
+ int i;
+
+ /* check if these are actual modules */
+ src_module = audioreach_find_module(scomp, route->source);
+ sink_module = audioreach_find_module(scomp, route->sink);
+
+ if (sink_module && !src_module) {
+ control = audioreach_find_widget(scomp, route->source);
+ if (control)
+ control->module_instance_id = sink_module->instance_id;
+
+ } else if (!sink_module && src_module && route->control) {
+ /* check if this is a virtual mixer */
+ control = audioreach_find_widget(scomp, route->sink);
+ if (!control || !control->w)
+ return 0;
+
+ w = control->w;
+
+ for (i = 0; i < w->num_kcontrols; i++) {
+ if (!strcmp(route->control, w->kcontrol_news[i].name)) {
+ struct soc_mixer_control *sm;
+ struct snd_soc_dobj *dobj;
+ struct snd_ar_control *scontrol;
+
+ sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
+ dobj = &sm->dobj;
+ scontrol = dobj->private;
+ scontrol->module_instance_id = src_module->instance_id;
+ }
+ }
- if (src && sink) {
- src->dst_mod_inst_id = sink->instance_id;
- sink->src_mod_inst_id = src->instance_id;
}
return 0;
@@ -914,6 +1046,48 @@ static int audioreach_link_load(struct snd_soc_component *component, int index,
return 0;
}
+static void audioreach_connect_sub_graphs(struct q6apm *apm,
+ struct snd_ar_control *m1,
+ struct snd_ar_control *m2,
+ bool connect)
+{
+ struct audioreach_graph_info *info;
+
+ mutex_lock(&apm->lock);
+ info = idr_find(&apm->graph_info_idr, m2->graph_id);
+ mutex_unlock(&apm->lock);
+
+ if (connect) {
+ info->src_mod_inst_id = m1->module_instance_id;
+ info->src_mod_op_port_id = 1;
+ info->dst_mod_inst_id = m2->module_instance_id;
+ info->dst_mod_ip_port_id = 2;
+
+ } else {
+ info->src_mod_inst_id = 0;
+ info->src_mod_op_port_id = 0;
+ info->dst_mod_inst_id = 0;
+ info->dst_mod_ip_port_id = 0;
+ }
+}
+
+static bool audioreach_is_vmixer_connected(struct q6apm *apm,
+ struct snd_ar_control *m1,
+ struct snd_ar_control *m2)
+{
+ struct audioreach_graph_info *info;
+
+ mutex_lock(&apm->lock);
+ info = idr_find(&apm->graph_info_idr, m2->graph_id);
+ mutex_unlock(&apm->lock);
+
+ if (info->dst_mod_inst_id == m2->module_instance_id &&
+ info->src_mod_inst_id == m1->module_instance_id)
+ return true;
+
+ return false;
+}
+
static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -926,7 +1100,7 @@ static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
struct q6apm *data = dev_get_drvdata(c->dev);
bool connected;
- connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid);
+ connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
if (connected)
ucontrol->value.integer.value[0] = 1;
else
@@ -947,10 +1121,10 @@ static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
struct q6apm *data = dev_get_drvdata(c->dev);
if (ucontrol->value.integer.value[0]) {
- q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true);
+ audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
} else {
- q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false);
+ audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
}
return 0;
@@ -998,6 +1172,9 @@ static int audioreach_control_load_mix(struct snd_soc_component *scomp,
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
scontrol->sgid = le32_to_cpu(c_elem->value);
break;
+ case AR_TKN_DAI_INDEX:
+ scontrol->graph_id = le32_to_cpu(c_elem->value);
+ break;
default:
/* Ignore other tokens */
break;
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 2540b9ba37c8..5e52e9d60d44 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -21,7 +21,6 @@
#include <sound/soc.h>
#include "rockchip_i2s.h"
#include "../codecs/da7219.h"
-#include "../codecs/da7219-aad.h"
#include "../codecs/rt5514.h"
#define DRV_NAME "rk3399-gru-sound"
@@ -226,7 +225,7 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(
rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- da7219_aad_jack_det(component, &rockchip_sound_jack);
+ snd_soc_component_set_jack(component, &rockchip_sound_jack, NULL);
return 0;
}
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index 2550bd2a5e78..08b90ec5cc80 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -756,6 +756,12 @@ static int rockchip_i2s_io_multiplex(struct snd_pcm_substream *substream,
if (!i2s_tdm->io_multiplex)
return 0;
+ if (IS_ERR_OR_NULL(i2s_tdm->grf)) {
+ dev_err(i2s_tdm->dev,
+ "io multiplex not supported for this device\n");
+ return -EINVAL;
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
struct snd_pcm_str *playback_str =
&substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -1222,6 +1228,12 @@ static int common_soc_init(struct device *dev, u32 addr)
if (trcm == TRCM_TXRX)
return 0;
+ if (IS_ERR_OR_NULL(i2s_tdm->grf)) {
+ dev_err(i2s_tdm->dev,
+ "no grf present but non-txrx TRCM specified\n");
+ return -EINVAL;
+ }
+
for (i = 0; i < i2s_tdm->soc_data->config_count; i++) {
if (addr != configs[i].addr)
continue;
@@ -1306,6 +1318,7 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
{ .compatible = "rockchip,rk1808-i2s-tdm", .data = &rk1808_i2s_soc_data },
{ .compatible = "rockchip,rk3308-i2s-tdm", .data = &rk3308_i2s_soc_data },
{ .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data },
+ { .compatible = "rockchip,rk3588-i2s-tdm" },
{ .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data },
{},
};
@@ -1544,7 +1557,7 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
i2s_tdm->dev = &pdev->dev;
of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
- if (!of_id || !of_id->data)
+ if (!of_id)
return -EINVAL;
spin_lock_init(&i2s_tdm->lock);
@@ -1568,10 +1581,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
return ret;
i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
- if (IS_ERR(i2s_tdm->grf))
- return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->grf),
- "Error in rockchip,grf\n");
-
i2s_tdm->tx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"tx-m");
if (IS_ERR(i2s_tdm->tx_reset)) {
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 97916e3ca9dd..7bddfd5e38d6 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -39,7 +39,7 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on COMMON_CLK
- depends on OF || COMPILE_TEST
+ depends on OF
select SND_SIMPLE_CARD_UTILS
select REGMAP_MMIO
help
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 5f1e72edfee0..ca1e1281cefa 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -648,8 +648,8 @@ void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
int i;
for_each_rsnd_clk(clk, adg, i)
- dbg_msg(dev, m, "%s : %pa : %ld\n",
- clk_name[i], clk, clk_get_rate(clk));
+ dbg_msg(dev, m, "%-18s : %pa : %ld\n",
+ __clk_get_name(clk), clk, clk_get_rate(clk));
dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
adg->ckr, adg->rbga, adg->rbgb);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 7e380d71b0f8..2d269ac8c137 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1518,7 +1518,8 @@ static int rsnd_hw_params(struct snd_soc_component *component,
int stream = substream->stream;
for_each_dpcm_be(fe, stream, dpcm) {
- struct snd_pcm_hw_params *be_params = &dpcm->hw_params;
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params;
if (params_channels(hw_params) != params_channels(be_params))
io->converted_chan = params_channels(be_params);
@@ -1581,9 +1582,9 @@ static int rsnd_hw_params(struct snd_soc_component *component,
hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
} else if (params_rate(hw_params) * k_up < io->converted_rate) {
hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
- (io->converted_rate + k_up - 1) / k_up;
+ DIV_ROUND_UP(io->converted_rate, k_up);
hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
- (io->converted_rate + k_up - 1) / k_up;
+ DIV_ROUND_UP(io->converted_rate, k_up);
hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 12a82f5a3ff6..e613698824fd 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -447,7 +447,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
*/
rtd = devm_kzalloc(dev,
sizeof(*rtd) +
- sizeof(*component) * (dai_link->num_cpus +
+ sizeof(component) * (dai_link->num_cpus +
dai_link->num_codecs +
dai_link->num_platforms),
GFP_KERNEL);
@@ -939,9 +939,6 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
{
lockdep_assert_held(&client_mutex);
- /* release machine specific resources */
- snd_soc_link_exit(rtd);
-
/*
* Notify the machine driver for extra destruction
*/
@@ -1890,6 +1887,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
snd_soc_dapm_shutdown(card);
+ /* release machine specific resources */
+ for_each_card_rtds(card, rtd)
+ snd_soc_link_exit(rtd);
/* remove and free each DAI */
soc_remove_link_dais(card);
soc_remove_link_components(card);
@@ -3477,10 +3477,23 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_cpus);
static int __init snd_soc_init(void)
{
+ int ret;
+
snd_soc_debugfs_init();
- snd_soc_util_init();
+ ret = snd_soc_util_init();
+ if (ret)
+ goto err_util_init;
- return platform_driver_register(&soc_driver);
+ ret = platform_driver_register(&soc_driver);
+ if (ret)
+ goto err_register;
+ return 0;
+
+err_register:
+ snd_soc_util_exit();
+err_util_init:
+ snd_soc_debugfs_exit();
+ return ret;
}
module_init(snd_soc_init);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 49752af0e205..29a75fdf90e0 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -386,23 +386,16 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int ret = 0;
if (dai->driver->ops &&
- dai->driver->ops->hw_params) {
- /* perform any topology hw_params fixups before DAI */
- ret = snd_soc_link_be_hw_params_fixup(rtd, params);
- if (ret < 0)
- goto end;
-
+ dai->driver->ops->hw_params)
ret = dai->driver->ops->hw_params(substream, params, dai);
- }
/* mark substream if succeeded */
if (ret == 0)
soc_dai_mark_push(dai, substream, hw_params);
-end:
+
return soc_dai_ret(dai, ret);
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d515e7a78ea8..f61c8633e7eb 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -71,9 +71,9 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_pinctrl] = 2,
[snd_soc_dapm_clock_supply] = 2,
[snd_soc_dapm_supply] = 3,
+ [snd_soc_dapm_dai_link] = 3,
[snd_soc_dapm_micbias] = 4,
[snd_soc_dapm_vmid] = 4,
- [snd_soc_dapm_dai_link] = 3,
[snd_soc_dapm_dai_in] = 5,
[snd_soc_dapm_dai_out] = 5,
[snd_soc_dapm_aif_in] = 5,
@@ -652,10 +652,8 @@ static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
}
static struct snd_soc_dapm_widget *
-dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
+dapm_wcache_lookup(struct snd_soc_dapm_widget *w, const char *name)
{
- struct snd_soc_dapm_widget *w = wcache->widget;
-
if (w) {
struct list_head *wlist = &w->dapm->card->widgets;
const int depth = 2;
@@ -673,12 +671,6 @@ dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
return NULL;
}
-static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
- struct snd_soc_dapm_widget *w)
-{
- wcache->widget = w;
-}
-
/**
* snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
* @dapm: The DAPM context for which to set the level
@@ -1881,58 +1873,52 @@ static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
dapm_mark_dirty(peer, "peer state change");
}
-static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
+static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
struct list_head *up_list,
struct list_head *down_list)
{
struct snd_soc_dapm_path *path;
+ int power;
+
+ switch (w->id) {
+ case snd_soc_dapm_pre:
+ power = 0;
+ goto end;
+ case snd_soc_dapm_post:
+ power = 1;
+ goto end;
+ default:
+ break;
+ }
+
+ power = dapm_widget_power_check(w);
if (w->power == power)
return;
trace_snd_soc_dapm_widget_power(w, power);
- /* If we changed our power state perhaps our neigbours changed
- * also.
+ /*
+ * If we changed our power state perhaps our neigbours
+ * changed also.
*/
snd_soc_dapm_widget_for_each_source_path(w, path)
dapm_widget_set_peer_power(path->source, power, path->connect);
- /* Supplies can't affect their outputs, only their inputs */
- if (!w->is_supply) {
+ /*
+ * Supplies can't affect their outputs, only their inputs
+ */
+ if (!w->is_supply)
snd_soc_dapm_widget_for_each_sink_path(w, path)
- dapm_widget_set_peer_power(path->sink, power,
- path->connect);
- }
+ dapm_widget_set_peer_power(path->sink, power, path->connect);
+end:
if (power)
dapm_seq_insert(w, up_list, true);
else
dapm_seq_insert(w, down_list, false);
}
-static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
- struct list_head *up_list,
- struct list_head *down_list)
-{
- int power;
-
- switch (w->id) {
- case snd_soc_dapm_pre:
- dapm_seq_insert(w, down_list, false);
- break;
- case snd_soc_dapm_post:
- dapm_seq_insert(w, up_list, true);
- break;
-
- default:
- power = dapm_widget_power_check(w);
-
- dapm_widget_set_power(w, power, up_list, down_list);
- break;
- }
-}
-
static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
{
if (dapm->idle_bias_off)
@@ -2497,6 +2483,9 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
struct snd_soc_dapm_path *p, *next_p;
enum snd_soc_dapm_direction dir;
+ if (!w)
+ return;
+
list_del(&w->list);
list_del(&w->dirty);
/*
@@ -2516,12 +2505,6 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free_widget);
-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)
{
@@ -2532,7 +2515,9 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
continue;
snd_soc_dapm_free_widget(w);
}
- snd_soc_dapm_reset_cache(dapm);
+
+ dapm->wcache_sink = NULL;
+ dapm->wcache_source = NULL;
}
static struct snd_soc_dapm_widget *dapm_find_widget(
@@ -2838,7 +2823,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink))
{
- struct snd_soc_dapm_widget *widgets[2];
enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *path;
int ret;
@@ -2874,8 +2858,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
path->node[SND_SOC_DAPM_DIR_IN] = wsource;
path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
- widgets[SND_SOC_DAPM_DIR_IN] = wsource;
- widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
path->connected = connected;
INIT_LIST_HEAD(&path->list);
@@ -2917,12 +2899,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
}
list_add(&path->list, &dapm->card->paths);
+
snd_soc_dapm_for_each_direction(dir)
- list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
+ list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
snd_soc_dapm_for_each_direction(dir) {
- dapm_update_widget_flags(widgets[dir]);
- dapm_mark_dirty(widgets[dir], "Route added");
+ dapm_update_widget_flags(path->node[dir]);
+ dapm_mark_dirty(path->node[dir], "Route added");
}
if (dapm->card->instantiated && path->connect)
@@ -2961,8 +2944,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
source = route->source;
}
- wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
- wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
+ wsource = dapm_wcache_lookup(dapm->wcache_source, source);
+ wsink = dapm_wcache_lookup(dapm->wcache_sink, sink);
if (wsink && wsource)
goto skip_search;
@@ -3006,30 +2989,27 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
if (!wsource)
wsource = wtsource;
- if (wsource == NULL) {
- dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
- route->source);
- return -ENODEV;
- }
- if (wsink == NULL) {
- dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
- route->sink);
- return -ENODEV;
- }
+ ret = -ENODEV;
+ if (!wsource)
+ goto err;
+ if (!wsink)
+ goto err;
skip_search:
- dapm_wcache_update(&dapm->path_sink_cache, wsink);
- dapm_wcache_update(&dapm->path_source_cache, wsource);
+ /* update cache */
+ dapm->wcache_sink = wsink;
+ dapm->wcache_source = wsource;
ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
route->connected);
- if (ret)
- goto err;
-
- return 0;
err:
- dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
- source, route->control, sink);
+ if (ret)
+ dev_err(dapm->dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
+ source, !wsource ? "(*)" : "",
+ !route->control ? "" : "> [",
+ !route->control ? "" : route->control,
+ !route->control ? "" : "] -",
+ sink, !wsink ? "(*)" : "");
return ret;
}
@@ -3115,13 +3095,8 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
for (i = 0; i < num; i++) {
int r = snd_soc_dapm_add_route(dapm, route);
- if (r < 0) {
- dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
- route->source,
- route->control ? route->control : "direct",
- route->sink);
+ if (r < 0)
ret = r;
- }
route++;
}
mutex_unlock(&dapm->card->dapm_mutex);
@@ -3645,7 +3620,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
switch (w->id) {
case snd_soc_dapm_regulator_supply:
- w->regulator = devm_regulator_get(dapm->dev, w->name);
+ w->regulator = devm_regulator_get(dapm->dev, widget->name);
if (IS_ERR(w->regulator)) {
ret = PTR_ERR(w->regulator);
goto request_failed;
@@ -4157,56 +4132,53 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
+ const struct snd_kcontrol_new *kcontrol_news;
+ int num_kcontrols;
const char **w_param_text;
unsigned long private_value = 0;
char *link_name;
- int ret;
+ int ret = -ENOMEM;
link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
rtd->dai_link->name, id);
if (!link_name)
- return ERR_PTR(-ENOMEM);
-
- memset(&template, 0, sizeof(template));
- template.reg = SND_SOC_NOPM;
- template.id = snd_soc_dapm_dai_link;
- template.name = link_name;
- template.event = snd_soc_dai_link_event;
- template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
- template.kcontrol_news = NULL;
+ goto name_fail;
/* allocate memory for control, only in case of multiple configs */
+ w_param_text = NULL;
+ kcontrol_news = NULL;
+ num_kcontrols = 0;
if (rtd->dai_link->num_params > 1) {
w_param_text = devm_kcalloc(card->dev,
rtd->dai_link->num_params,
sizeof(char *), GFP_KERNEL);
- if (!w_param_text) {
- ret = -ENOMEM;
+ if (!w_param_text)
goto param_fail;
- }
- template.num_kcontrols = 1;
- template.kcontrol_news =
- snd_soc_dapm_alloc_kcontrol(card,
- link_name,
- rtd->dai_link->params,
- rtd->dai_link->num_params,
- w_param_text, &private_value);
- if (!template.kcontrol_news) {
- ret = -ENOMEM;
+ num_kcontrols = 1;
+ kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, link_name,
+ rtd->dai_link->params,
+ rtd->dai_link->num_params,
+ w_param_text, &private_value);
+ if (!kcontrol_news)
goto param_fail;
- }
- } else {
- w_param_text = NULL;
}
+
+ memset(&template, 0, sizeof(template));
+ template.reg = SND_SOC_NOPM;
+ template.id = snd_soc_dapm_dai_link;
+ template.name = link_name;
+ template.event = snd_soc_dai_link_event;
+ template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
+ template.kcontrol_news = kcontrol_news;
+ template.num_kcontrols = num_kcontrols;
+
dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n",
- link_name, ret);
goto outfree_kcontrol_news;
}
@@ -4220,6 +4192,9 @@ outfree_kcontrol_news:
rtd->dai_link->num_params, w_param_text);
param_fail:
devm_kfree(card->dev, link_name);
+name_fail:
+ dev_err(rtd->dev, "ASoC: Failed to create %s-%s widget: %d\n",
+ rtd->dai_link->name, id, ret);
return ERR_PTR(ret);
}
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index bd88de056358..55b009d3c681 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -452,7 +452,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
val = ucontrol->value.integer.value[0];
if (mc->platform_max && val > mc->platform_max)
return -EINVAL;
- if (val > max - min)
+ if (val > max)
return -EINVAL;
val_mask = mask << shift;
val = (val + min) & mask;
@@ -464,10 +464,15 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
ret = err;
if (snd_soc_volsw_is_stereo(mc)) {
- unsigned int val2;
+ unsigned int val2 = ucontrol->value.integer.value[1];
+
+ if (mc->platform_max && val2 > mc->platform_max)
+ return -EINVAL;
+ if (val2 > max)
+ return -EINVAL;
val_mask = mask << rshift;
- val2 = (ucontrol->value.integer.value[1] + min) & mask;
+ val2 = (val2 + min) & mask;
val2 = val2 << rshift;
err = snd_soc_component_update_bits(component, reg2, val_mask,
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index fb87d6d23408..a7810c78ffa1 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -155,7 +155,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
for_each_dpcm_be(fe, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
- params = &dpcm->hw_params;
+ params = &be->dpcm[stream].hw_params;
offset += scnprintf(buf + offset, size - offset,
"- %s\n", be->dai_link->name);
@@ -822,11 +822,6 @@ static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_startup(dai, substream);
if (ret < 0)
goto err;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dai->tx_mask = 0;
- else
- dai->rx_mask = 0;
}
/* Dynamic PCM DAI links compat checks use dynamic capabilities */
@@ -1252,6 +1247,8 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
return;
be_substream = snd_soc_dpcm_get_substream(be, stream);
+ if (!be_substream)
+ return;
for_each_dpcm_fe(be, stream, dpcm) {
if (dpcm->fe == fe)
@@ -1980,6 +1977,8 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
int ret;
for_each_dpcm_be(fe, stream, dpcm) {
+ struct snd_pcm_hw_params hw_params;
+
be = dpcm->be;
be_substream = snd_soc_dpcm_get_substream(be, stream);
@@ -1988,16 +1987,16 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
continue;
/* copy params for each dpcm */
- memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+ memcpy(&hw_params, &fe->dpcm[stream].hw_params,
sizeof(struct snd_pcm_hw_params));
/* perform any hw_params fixups */
- ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
+ ret = snd_soc_link_be_hw_params_fixup(be, &hw_params);
if (ret < 0)
goto unwind;
/* copy the fixed-up hw params for BE dai */
- memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
+ memcpy(&be->dpcm[stream].hw_params, &hw_params,
sizeof(struct snd_pcm_hw_params));
/* only allow hw_params() if no connected FEs are running */
@@ -2012,7 +2011,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
be->dai_link->name);
- ret = __soc_pcm_hw_params(be, be_substream, &dpcm->hw_params);
+ ret = __soc_pcm_hw_params(be, be_substream, &hw_params);
if (ret < 0)
goto unwind;
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index a3b6df2378b4..a4dba0b751e7 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -264,7 +264,7 @@ int __init snd_soc_util_init(void)
return ret;
}
-void __exit snd_soc_util_exit(void)
+void snd_soc_util_exit(void)
{
platform_driver_unregister(&soc_dummy_driver);
platform_device_unregister(soc_dummy_dev);
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 37f7df5fde17..a2725188f4ce 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -39,7 +39,7 @@ config SND_SOC_SOF_ACPI_DEV
config SND_SOC_SOF_OF
tristate "SOF OF enumeration support"
- depends on OF || COMPILE_TEST
+ depends on OF
help
This adds support for Device Tree enumeration. This option is
required to enable i.MX8 or Mediatek devices.
@@ -97,13 +97,13 @@ config SND_SOC_SOF_NOCODEC
tristate
config SND_SOC_SOF_NOCODEC_SUPPORT
- bool "SOF nocodec mode support"
+ bool "SOF nocodec static mode support"
help
This adds support for a dummy/nocodec machine driver fallback
option if no known codec is detected. This is typically only
enabled for developers or devices where the sound card is
controlled externally.
- This option is mutually exclusive with the Intel HDAudio support.
+ This option is mutually exclusive at build time with the Intel HDAudio support.
Selecting it may have negative impacts and prevent e.g. microphone
functionality from being enabled on Intel CoffeeLake and later
platforms.
@@ -136,6 +136,19 @@ config SND_SOC_SOF_DEBUG
if SND_SOC_SOF_DEBUG
+config SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
+ bool "SOF nocodec debug mode support"
+ depends on !SND_SOC_SOF_NOCODEC_SUPPORT
+ help
+ This adds support for a dummy/nocodec machine driver fallback
+ option.
+ Unlike the SND_SOC_SOF_NOCODEC_SUPPORT, this option is NOT
+ mutually exclusive at build with the Intel HDAudio support. The
+ selection will be done depending on command line or modprobe.d settings
+ Distributions should not select this option!
+ Say Y if you need this nocodec debug fallback option.
+ If unsure select "N".
+
config SND_SOC_SOF_FORCE_NOCODEC_MODE
bool "SOF force nocodec Mode"
depends on SND_SOC_SOF_NOCODEC_SUPPORT
@@ -239,6 +252,7 @@ config SND_SOC_SOF
tristate
select SND_SOC_TOPOLOGY
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
+ select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level.
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index eab7cc53f71a..308d87639916 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -27,6 +27,12 @@ snd-sof-of-objs := sof-of-dev.o
snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
snd-sof-probes-objs := sof-client-probes.o
+ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
+snd-sof-probes-objs += sof-client-probes-ipc3.o
+endif
+ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
+snd-sof-probes-objs += sof-client-probes-ipc4.o
+endif
snd-sof-nocodec-objs := nocodec.o
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index a305ea6efea9..1cb92d6030e3 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -20,6 +20,7 @@ config SND_SOC_SOF_AMD_COMMON
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_PCI_DEV
select SND_AMD_ACP_CONFIG
+ select SND_SOC_SOF_XTENSA
select SND_SOC_ACPI if ACPI
help
This option is not user-selectable but automatically handled by
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index 27b95187356e..bd6c1b198736 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -16,6 +16,7 @@
#include "../sof-audio.h"
#include "acp.h"
#include "acp-dsp-offset.h"
+#include <sound/sof/xtensa.h>
int acp_dai_probe(struct snd_soc_dai *dai)
{
@@ -33,6 +34,107 @@ int acp_dai_probe(struct snd_soc_dai *dai)
}
EXPORT_SYMBOL_NS(acp_dai_probe, SND_SOC_SOF_AMD_COMMON);
+/**
+ * amd_sof_ipc_dump() - This function is called when IPC tx times out.
+ * @sdev: SOF device.
+ */
+void amd_sof_ipc_dump(struct snd_sof_dev *sdev)
+{
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ u32 base = desc->dsp_intr_base;
+ u32 dsp_msg_write = sdev->debug_box.offset +
+ offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
+ u32 dsp_ack_write = sdev->debug_box.offset +
+ offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
+ u32 host_msg_write = sdev->debug_box.offset +
+ offsetof(struct scratch_ipc_conf, sof_host_msg_write);
+ u32 host_ack_write = sdev->debug_box.offset +
+ offsetof(struct scratch_ipc_conf, sof_host_ack_write);
+ u32 dsp_msg, dsp_ack, host_msg, host_ack, irq_stat;
+
+ dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write);
+ dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
+ host_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg_write);
+ host_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_ack_write);
+ irq_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
+
+ dev_err(sdev->dev,
+ "dsp_msg = %#x dsp_ack = %#x host_msg = %#x host_ack = %#x irq_stat = %#x\n",
+ dsp_msg, dsp_ack, host_msg, host_ack, irq_stat);
+}
+
+/**
+ * amd_get_registers() - This function is called in case of DSP oops
+ * in order to gather information about the registers, filename and
+ * linenumber and stack.
+ * @sdev: SOF device.
+ * @xoops: Stores information about registers.
+ * @panic_info: Stores information about filename and line number.
+ * @stack: Stores the stack dump.
+ * @stack_words: Size of the stack dump.
+ */
+static void amd_get_registers(struct snd_sof_dev *sdev,
+ struct sof_ipc_dsp_oops_xtensa *xoops,
+ struct sof_ipc_panic_info *panic_info,
+ u32 *stack, size_t stack_words)
+{
+ u32 offset = sdev->dsp_oops_offset;
+
+ /* first read registers */
+ acp_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
+
+ /* then get panic info */
+ if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
+ dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
+ xoops->arch_hdr.totalsize);
+ return;
+ }
+
+ offset += xoops->arch_hdr.totalsize;
+ acp_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
+
+ /* then get the stack */
+ offset += sizeof(*panic_info);
+ acp_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));
+}
+
+/**
+ * amd_sof_dump() - This function is called when a panic message is
+ * received from the firmware.
+ * @sdev: SOF device.
+ * @flags: parameter not used but required by ops prototype
+ */
+void amd_sof_dump(struct snd_sof_dev *sdev, u32 flags)
+{
+ struct sof_ipc_dsp_oops_xtensa xoops;
+ struct sof_ipc_panic_info panic_info;
+ u32 stack[AMD_STACK_DUMP_SIZE];
+ u32 status;
+
+ /* Get information about the panic status from the debug box area.
+ * Compute the trace point based on the status.
+ */
+ if (sdev->dsp_oops_offset > sdev->debug_box.offset) {
+ acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32));
+ } else {
+ /* Read DSP Panic status from dsp_box.
+ * As window information for exception box offset and size is not available
+ * before FW_READY
+ */
+ acp_mailbox_read(sdev, sdev->dsp_box.offset, &status, sizeof(u32));
+ sdev->dsp_oops_offset = sdev->dsp_box.offset + sizeof(status);
+ }
+
+ /* Get information about the registers, the filename and line
+ * number and the stack.
+ */
+ amd_get_registers(sdev, &xoops, &panic_info, stack, AMD_STACK_DUMP_SIZE);
+
+ /* Print the information to the console */
+ sof_print_oops_and_stack(sdev, KERN_ERR, status, status, &xoops,
+ &panic_info, stack, AMD_STACK_DUMP_SIZE);
+}
+
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *sof_pdata = sdev->pdata;
@@ -76,6 +178,7 @@ struct snd_sof_dsp_ops sof_acp_common_ops = {
/*IPC */
.send_msg = acp_sof_ipc_send_msg,
.ipc_msg_data = acp_sof_ipc_msg_data,
+ .set_stream_data_offset = acp_set_stream_data_offset,
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
.get_window_offset = acp_sof_ipc_get_window_offset,
.irq_thread = acp_sof_ipc_irq_thread,
@@ -103,9 +206,15 @@ struct snd_sof_dsp_ops sof_acp_common_ops = {
/* PM */
.suspend = amd_sof_acp_suspend,
.resume = amd_sof_acp_resume,
+
+ .ipc_dump = amd_sof_ipc_dump,
+ .dbg_dump = amd_sof_dump,
+ .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+ .dsp_arch_ops = &sof_xtensa_arch_ops,
};
EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
MODULE_DESCRIPTION("ACP SOF COMMON Driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index dd030566e372..5a02753c4610 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -154,8 +154,15 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
bool ipc_irq = false;
int dsp_msg, dsp_ack;
+ unsigned int status;
if (sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE) {
+ acp_mailbox_read(sdev, sdev->dsp_box.offset, &status, sizeof(status));
+ if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+ snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status),
+ true);
+ return IRQ_HANDLED;
+ }
snd_sof_ipc_msgs_rx(sdev);
acp_dsp_ipc_host_done(sdev);
return IRQ_HANDLED;
@@ -180,6 +187,12 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
ipc_irq = true;
}
+ acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32));
+ if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+ snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true);
+ return IRQ_HANDLED;
+ }
+
if (!ipc_irq)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
@@ -192,13 +205,41 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *sub
{
unsigned int offset = sdev->dsp_box.offset;
- if (!substream || !sdev->stream_box.size)
+ if (!substream || !sdev->stream_box.size) {
acp_mailbox_read(sdev, offset, p, sz);
+ } else {
+ struct acp_dsp_stream *stream = substream->runtime->private_data;
+
+ if (!stream)
+ return -ESTRPIPE;
+
+ acp_mailbox_read(sdev, stream->posn_offset, p, sz);
+ }
return 0;
}
EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON);
+int acp_set_stream_data_offset(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ size_t posn_offset)
+{
+ struct acp_dsp_stream *stream = substream->runtime->private_data;
+
+ /* check for unaligned offset or overflow */
+ if (posn_offset > sdev->stream_box.size ||
+ posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
+ return -EINVAL;
+
+ stream->posn_offset = sdev->stream_box.offset + posn_offset;
+
+ dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
+ substream->stream, stream->posn_offset);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(acp_set_stream_data_offset, SND_SOC_SOF_AMD_COMMON);
+
int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index d1e74baf5d8b..090c8b18c83c 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -48,7 +48,6 @@ EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON);
int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
u32 offset, void *src, size_t size)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct pci_dev *pci = to_pci_dev(sdev->dev);
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *adata;
@@ -61,7 +60,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
switch (blk_type) {
case SOF_FW_BLK_TYPE_IRAM:
if (!adata->bin_buf) {
- size_fw = plat_data->fw->size;
+ size_fw = sdev->basefw.fw->size;
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
dma_size = page_count * ACP_PAGE_SIZE;
adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
@@ -152,7 +151,6 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev
int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata;
unsigned int src_addr, size_fw;
u32 page_count, dma_size;
@@ -186,7 +184,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
/* Free memory once DMA is complete */
- dma_size = (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
+ dma_size = (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr);
adata->bin_buf = NULL;
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 36966643e36a..6bd2888fbb66 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -255,10 +255,12 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
if (ret)
return ret;
- fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER);
- if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) {
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER,
+ fw_qualifier, fw_qualifier & DSP_FW_RUN_ENABLE,
+ ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US);
+ if (ret < 0) {
dev_err(sdev->dev, "PSP validation failed\n");
- return -EINVAL;
+ return ret;
}
return 0;
@@ -390,6 +392,7 @@ static int acp_power_on(struct snd_sof_dev *sdev)
static int acp_reset(struct snd_sof_dev *sdev)
{
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int val;
int ret;
@@ -410,6 +413,7 @@ static int acp_reset(struct snd_sof_dev *sdev)
if (ret < 0)
dev_err(sdev->dev, "timeout in releasing reset\n");
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
return ret;
}
@@ -456,7 +460,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev)
return ret;
}
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, 0x03);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
ret = acp_memory_init(sdev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index dd3c072d0172..09e16ef8afa0 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -69,6 +69,17 @@
#define BOX_SIZE_512 0x200
#define BOX_SIZE_1024 0x400
+#define EXCEPT_MAX_HDR_SIZE 0x400
+#define AMD_STACK_DUMP_SIZE 32
+
+enum clock_source {
+ ACP_CLOCK_96M = 0,
+ ACP_CLOCK_48M,
+ ACP_CLOCK_24M,
+ ACP_CLOCK_ACLK,
+ ACP_CLOCK_MCLK,
+};
+
struct acp_atu_grp_pte {
u32 low;
u32 high;
@@ -138,6 +149,7 @@ struct acp_dsp_stream {
int stream_tag;
int active;
unsigned int reg_offset;
+ size_t posn_offset;
};
struct sof_amd_acp_desc {
@@ -199,6 +211,9 @@ int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_ty
irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context);
int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
void *p, size_t sz);
+int acp_set_stream_data_offset(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ size_t posn_offset);
int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev,
struct snd_sof_ipc_msg *msg);
int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
@@ -242,6 +257,9 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev);
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state);
int amd_sof_acp_resume(struct snd_sof_dev *sdev);
+void amd_sof_ipc_dump(struct snd_sof_dev *sdev);
+void amd_sof_dump(struct snd_sof_dev *sdev, u32 flags);
+
static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata *pdata)
{
const struct sof_dev_desc *desc = pdata->desc;
diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c
index dcb64a23e121..5288ab882fc9 100644
--- a/sound/soc/sof/amd/rembrandt.c
+++ b/sound/soc/sof/amd/rembrandt.c
@@ -23,6 +23,7 @@
#define I2S_BT_INSTANCE 1
#define I2S_SP_INSTANCE 2
#define PDM_DMIC_INSTANCE 3
+#define I2S_HS_VIRTUAL_INSTANCE 4
static struct snd_soc_dai_driver rembrandt_sof_dai[] = {
[I2S_HS_INSTANCE] = {
@@ -112,6 +113,21 @@ static struct snd_soc_dai_driver rembrandt_sof_dai[] = {
.rate_max = 48000,
},
},
+
+ [I2S_HS_VIRTUAL_INSTANCE] = {
+ .id = I2S_HS_VIRTUAL_INSTANCE,
+ .name = "acp-sof-hs-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .probe = &acp_dai_probe,
+ },
};
/* Rembrandt ops */
diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c
index 6ea8727f977e..adade2e3d3be 100644
--- a/sound/soc/sof/amd/renoir.c
+++ b/sound/soc/sof/amd/renoir.c
@@ -22,6 +22,7 @@
#define I2S_BT_INSTANCE 0
#define I2S_SP_INSTANCE 1
#define PDM_DMIC_INSTANCE 2
+#define I2S_SP_VIRTUAL_INSTANCE 3
static struct snd_soc_dai_driver renoir_sof_dai[] = {
[I2S_BT_INSTANCE] = {
@@ -86,6 +87,21 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = {
.rate_max = 48000,
},
},
+
+ [I2S_SP_VIRTUAL_INSTANCE] = {
+ .id = I2S_SP_VIRTUAL_INSTANCE,
+ .name = "acp-sof-sp-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .probe = &acp_dai_probe,
+ },
};
/* Renoir ops */
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index 7af495fb6125..36a0e2bf30ff 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -277,7 +277,7 @@ if SND_SOC_SOF_HDA_COMMON
config SND_SOC_SOF_HDA_LINK
bool "SOF support for HDA Links(HDA/HDMI)"
- depends on SND_SOC_SOF_NOCODEC=n
+ depends on SND_SOC_SOF_NOCODEC_SUPPORT=n
select SND_SOC_SOF_PROBE_WORK_QUEUE
help
This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index 8b8ea0361785..8201cbdd654c 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -5,7 +5,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o
snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
- hda-dai.o hda-bus.o \
+ hda-dai.o hda-bus.o hda-mlink.o \
skl.o hda-loader-skl.o \
apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 1549ca7587a4..0e7a7e4ad976 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -62,6 +62,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_apl_ops.irq_thread = hda_dsp_ipc4_irq_thread;
@@ -106,6 +109,7 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.rom_init_timeout = 150,
.ssp_count = APL_SSP_COUNT,
.ssp_base_offset = APL_SSP_BASE_OFFSET,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
.quirks = SOF_INTEL_PROCEN_FMT_QUIRK,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index a446154f2803..812a49b1d3f4 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -575,11 +575,7 @@ static struct snd_sof_dsp_ops sof_bdw_ops = {
.run = bdw_run,
.reset = bdw_reset,
- /* Register IO */
- .write = sof_io_write,
- .read = sof_io_read,
- .write64 = sof_io_write64,
- .read64 = sof_io_read64,
+ /* Register IO uses direct mmio */
/* Block IO */
.block_read = sof_block_read,
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index e6dc4ff531c3..faf223b38360 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -225,11 +225,7 @@ static struct snd_sof_dsp_ops sof_byt_ops = {
.run = atom_run,
.reset = atom_reset,
- /* Register IO */
- .write = sof_io_write,
- .read = sof_io_read,
- .write64 = sof_io_write64,
- .read64 = sof_io_read64,
+ /* Register IO uses direct mmio */
/* Block IO */
.block_read = sof_block_read,
@@ -304,11 +300,7 @@ static struct snd_sof_dsp_ops sof_cht_ops = {
.run = atom_run,
.reset = atom_reset,
- /* Register IO */
- .write = sof_io_write,
- .read = sof_io_read,
- .write64 = sof_io_write64,
- .read64 = sof_io_read64,
+ /* Register IO uses direct mmio */
/* Block IO */
.block_read = sof_block_read,
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 19d0b1909bfd..6b075bbe5bfb 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -37,10 +37,12 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcida, hipctdr;
hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
+ hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
@@ -49,9 +51,9 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -70,6 +72,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ cnl_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -86,10 +89,10 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- /* Let DSP know that we have finished processing the message */
- cnl_ipc_host_done(sdev);
+ /* Let DSP know that we have finished processing the message */
+ cnl_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -98,6 +101,13 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
@@ -251,8 +261,16 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -389,6 +407,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_cnl_ops.irq_thread = cnl_ipc4_irq_thread;
@@ -435,6 +456,9 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
@@ -467,6 +491,9 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index 0862ff8b6627..acb4b85868d0 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -18,11 +18,7 @@
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#include "../../codecs/hdac_hda.h"
#define sof_hda_ext_ops snd_soc_hdac_hda_get_ops()
-#else
-#define sof_hda_ext_ops NULL
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power)
{
unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN);
@@ -70,11 +66,13 @@ static const struct hdac_bus_ops bus_core_ops = {
/*
* This can be used for both with/without hda link support.
*/
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
+void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
-#else /* CONFIG_SND_SOC_SOF_HDA */
+#else /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
memset(bus, 0, sizeof(*bus));
bus->dev = dev;
@@ -89,5 +87,14 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
bus->idx = 0;
spin_lock_init(&bus->reg_lock);
-#endif /* CONFIG_SND_SOC_SOF_HDA */
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
+}
+
+void sof_hda_bus_exit(struct snd_sof_dev *sdev)
+{
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ snd_hdac_ext_bus_exit(bus);
+#endif
}
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index f2ec2a6c2e0f..8a5e99a898ec 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -1,7 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// This file is provided under a dual BSD/GPLv2 license. When using or
-// redistributing this file, you may do so under either license.
+// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
@@ -16,15 +13,18 @@
#include <sound/sof.h>
#include "../ops.h"
#include "hda.h"
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#include "../../codecs/hdac_hda.h"
-#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
#define CODEC_PROBE_RETRIES 3
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#define IDISP_VID_INTEL 0x80860000
+static int hda_codec_mask = -1;
+module_param_named(codec_mask, hda_codec_mask, int, 0444);
+MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
+
/* load the legacy HDA codec driver */
static int request_codec_module(struct hda_codec *codec)
{
@@ -72,6 +72,10 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
struct hda_codec *codec;
unsigned int mask = 0;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
if (enable) {
list_for_each_codec(codec, hbus)
if (codec->jacktbl.used)
@@ -80,6 +84,7 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
}
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
/* check jack status after resuming from suspend mode */
void hda_codec_jack_check(struct snd_sof_dev *sdev)
@@ -87,6 +92,10 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
struct hda_bus *hbus = sof_to_hbus(sdev);
struct hda_codec *codec;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
list_for_each_codec(codec, hbus)
/*
* Wake up all jack-detecting codecs regardless whether an event
@@ -95,12 +104,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
if (codec->jacktbl.used)
pm_request_resume(&codec->core.dev);
}
-#else
-void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) {}
-void hda_codec_jack_check(struct snd_sof_dev *sdev) {}
-#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
-EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
-EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
#define is_generic_config(bus) \
@@ -133,13 +137,9 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i
}
/* probe individual codec */
-static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
- bool hda_codec_use_common_hdmi)
+static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
struct hdac_hda_priv *hda_priv;
- int type = HDA_DEV_LEGACY;
-#endif
struct hda_bus *hbus = sof_to_hbus(sdev);
struct hda_codec *codec;
u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
@@ -159,16 +159,11 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
address, resp);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL);
if (!hda_priv)
return -ENOMEM;
- /* only probe ASoC codec drivers for HDAC-HDMI */
- if (!hda_codec_use_common_hdmi && (resp & 0xFFFF0000) == IDISP_VID_INTEL)
- type = HDA_DEV_ASOC;
-
- codec = hda_codec_device_init(&hbus->core, address, type);
+ codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_LEGACY);
ret = PTR_ERR_OR_ZERO(codec);
if (ret < 0)
return ret;
@@ -191,43 +186,40 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
else
codec->probe_id = 0;
- if (type == HDA_DEV_LEGACY) {
- ret = hda_codec_load_module(codec);
- /*
- * handle ret==0 (no driver bound) as an error, but pass
- * other return codes without modification
- */
- if (ret == 0)
- ret = -ENOENT;
- }
+ ret = hda_codec_load_module(codec);
+ /*
+ * handle ret==0 (no driver bound) as an error, but pass
+ * other return codes without modification
+ */
+ if (ret == 0)
+ ret = -ENOENT;
out:
if (ret < 0) {
snd_hdac_device_unregister(&codec->core);
put_device(&codec->core.dev);
}
-#else
- codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_ASOC);
- ret = PTR_ERR_OR_ZERO(codec);
-#endif
return ret;
}
/* Codec initialization */
-void hda_codec_probe_bus(struct snd_sof_dev *sdev,
- bool hda_codec_use_common_hdmi)
+void hda_codec_probe_bus(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
int i, ret;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
/* probe codecs in avail slots */
for (i = 0; i < HDA_MAX_CODECS; i++) {
if (!(bus->codec_mask & (1 << i)))
continue;
- ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi);
+ ret = hda_codec_probe(sdev, i);
if (ret < 0) {
dev_warn(bus->dev, "codec #%d probe error, ret: %d\n",
i, ret);
@@ -235,27 +227,193 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev,
}
}
}
-EXPORT_SYMBOL_NS(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ unsigned int codec_mask;
+
+ codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+ if (codec_mask) {
+ hda_codec_jack_check(sdev);
+ snd_hdac_chip_writew(bus, STATESTS, codec_mask);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_detect_mask(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* Accept unsolicited responses */
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+
+ /* detect codecs */
+ if (!bus->codec_mask) {
+ bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+ dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+ }
+
+ if (hda_codec_mask != -1) {
+ bus->codec_mask &= hda_codec_mask;
+ dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
+ bus->codec_mask);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* initialize the codec command I/O */
+ snd_hdac_bus_init_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* set up CORB/RIRB buffers if was on before suspend */
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_init_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* initialize the codec command I/O */
+ snd_hdac_bus_stop_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* stop the CORB/RIRB DMA if it is On */
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_stop_cmd_io(bus);
+
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* clear rirb status */
+ snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ snd_hdac_set_codec_wakeup(bus, status);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ bool active = false;
+ u32 rirb_status;
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return false;
+
+ rirb_status = snd_hdac_chip_readb(bus, RIRBSTS);
+ if (rirb_status & RIRB_INT_MASK) {
+ /*
+ * Clearing the interrupt status here ensures
+ * that no interrupt gets masked after the RIRB
+ * wp is read in snd_hdac_bus_update_rirb.
+ */
+ snd_hdac_chip_writeb(bus, RIRBSTS,
+ RIRB_INT_MASK);
+ active = true;
+ if (rirb_status & RIRB_INT_RESPONSE)
+ snd_hdac_bus_update_rirb(bus);
+ }
+ return active;
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_device_remove(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
+ /* codec removal, invoke bus_device_remove */
+ snd_hdac_ext_bus_device_remove(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
-#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \
- IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return;
+
if (HDA_IDISP_CODEC(bus->codec_mask)) {
dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable);
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
}
}
-EXPORT_SYMBOL_NS(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
int hda_codec_i915_init(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
int ret;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return 0;
+
/* i915 exposes a HDA codec for HDMI audio */
ret = snd_hdac_i915_init(bus);
if (ret < 0)
@@ -266,12 +424,16 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ return 0;
+
if (!bus->audio_component)
return 0;
@@ -280,7 +442,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
return snd_hdac_i915_exit(bus);
}
-EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
#endif
diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c
index b2326396c870..397303b3ac9d 100644
--- a/sound/soc/sof/intel/hda-common-ops.c
+++ b/sound/soc/sof/intel/hda-common-ops.c
@@ -19,11 +19,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
- /* Register IO */
- .write = sof_io_write,
- .read = sof_io_read,
- .write64 = sof_io_write64,
- .read64 = sof_io_read64,
+ /* Register IO uses direct mmio */
/* Block IO */
.block_read = sof_block_read,
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 0c29bb196e59..3aea36c077c9 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -22,12 +22,6 @@
#include "../ops.h"
#include "hda.h"
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-static int hda_codec_mask = -1;
-module_param_named(codec_mask, hda_codec_mask, int, 0444);
-MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
-#endif
-
/*
* HDA Operations.
*/
@@ -182,72 +176,40 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
return 0;
}
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_ext_link *hlink;
-#endif
struct hdac_stream *stream;
int sd_offset, ret = 0;
if (bus->chip_init)
return 0;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- snd_hdac_set_codec_wakeup(bus, true);
-#endif
- hda_dsp_ctrl_misc_clock_gating(sdev, false);
+ hda_codec_set_codec_wakeup(sdev, true);
- if (full_reset) {
- /* reset HDA controller */
- ret = hda_dsp_ctrl_link_reset(sdev, true);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to reset HDA controller\n");
- goto err;
- }
-
- usleep_range(500, 1000);
-
- /* exit HDA controller reset */
- ret = hda_dsp_ctrl_link_reset(sdev, false);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
- goto err;
- }
-
- usleep_range(1000, 1200);
- }
+ hda_dsp_ctrl_misc_clock_gating(sdev, false);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* check to see if controller is ready */
- if (!snd_hdac_chip_readb(bus, GCTL)) {
- dev_dbg(bus->dev, "controller not ready!\n");
- ret = -EBUSY;
+ /* reset HDA controller */
+ ret = hda_dsp_ctrl_link_reset(sdev, true);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed to reset HDA controller\n");
goto err;
}
- /* Accept unsolicited responses */
- snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
- /* detect codecs */
- if (!bus->codec_mask) {
- bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
- dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+ /* exit HDA controller reset */
+ ret = hda_dsp_ctrl_link_reset(sdev, false);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
+ goto err;
}
- if (hda_codec_mask != -1) {
- bus->codec_mask &= hda_codec_mask;
- dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
- bus->codec_mask);
- }
-#endif
+ hda_codec_detect_mask(sdev);
/* clear stream status */
list_for_each_entry(stream, &bus->stream_list, list) {
sd_offset = SOF_STREAM_SD_OFFSET(stream);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK);
}
@@ -255,19 +217,13 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* clear rirb status */
- snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
-#endif
+ hda_codec_rirb_status_clear(sdev);
/* clear interrupt status register */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* initialize the codec command I/O */
- snd_hdac_bus_init_cmd_io(bus);
-#endif
+ hda_codec_init_cmd_io(sdev);
/* enable CIE and GIE interrupts */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
@@ -282,19 +238,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
upper_32_bits(bus->posbuf.addr));
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* Reset stream-to-link mapping */
- list_for_each_entry(hlink, &bus->hlink_list, list)
- writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
-#endif
+ hda_bus_ml_reset_losidv(bus);
bus->chip_init = true;
err:
hda_dsp_ctrl_misc_clock_gating(sdev, true);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- snd_hdac_set_codec_wakeup(bus, false);
-#endif
+
+ hda_codec_set_codec_wakeup(sdev, false);
return ret;
}
@@ -313,7 +264,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
sd_offset = SOF_STREAM_SD_OFFSET(stream);
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset +
- SOF_HDA_ADSP_REG_CL_SD_CTL,
+ SOF_HDA_ADSP_REG_SD_CTL,
SOF_HDA_CL_DMA_SD_INT_MASK,
0);
}
@@ -331,7 +282,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
list_for_each_entry(stream, &bus->stream_list, list) {
sd_offset = SOF_STREAM_SD_OFFSET(stream);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK);
}
@@ -339,19 +290,14 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* clear rirb status */
- snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
-#endif
+ hda_codec_rirb_status_clear(sdev);
/* clear interrupt status register */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* disable CORB/RIRB */
- snd_hdac_bus_stop_cmd_io(bus);
-#endif
+ hda_codec_stop_cmd_io(sdev);
+
/* disable position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 556e883a32ed..1c3d4887aa30 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -27,16 +27,13 @@ static bool hda_use_tplg_nhlt;
module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
struct hda_pipe_params {
u32 ch;
u32 s_freq;
- u32 s_fmt;
- u8 linktype;
snd_pcm_format_t format;
int link_index;
- int stream;
unsigned int link_bps;
};
@@ -138,27 +135,27 @@ hda_link_stream_assign(struct hdac_bus *bus,
}
static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
- struct hdac_stream *hstream,
+ struct hdac_ext_stream *hext_stream,
struct snd_soc_dai *cpu_dai,
struct snd_soc_dai *codec_dai,
bool trigger_suspend_stop)
{
- struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ struct hdac_stream *hstream = &hext_stream->hstream;
struct hdac_bus *bus = hstream->bus;
struct sof_intel_hda_stream *hda_stream;
- struct hdac_ext_link *link;
+ struct hdac_ext_link *hlink;
int stream_tag;
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
- if (!link)
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+ if (!hlink)
return -EINVAL;
if (trigger_suspend_stop)
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
}
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
@@ -177,10 +174,10 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
struct hdac_stream *hstream = &hext_stream->hstream;
unsigned char stream_tag = hstream->stream_tag;
struct hdac_bus *bus = hstream->bus;
- struct hdac_ext_link *link;
+ struct hdac_ext_link *hlink;
unsigned int format_val;
- snd_hdac_ext_link_stream_reset(hext_stream);
+ snd_hdac_ext_stream_reset(hext_stream);
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
params->format,
@@ -189,13 +186,13 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format);
- snd_hdac_ext_link_stream_setup(hext_stream, format_val);
+ snd_hdac_ext_stream_setup(hext_stream, format_val);
if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
- list_for_each_entry(link, &bus->hlink_list, list) {
- if (link->index == params->link_index)
- snd_hdac_ext_link_set_stream_id(link,
- stream_tag);
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
+ if (hlink->index == params->link_index)
+ snd_hdac_ext_bus_link_set_stream_id(hlink,
+ stream_tag);
}
}
@@ -207,14 +204,17 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hda_pipe_params p_params = {0};
- struct hdac_bus *bus = hstream->bus;
- struct hdac_ext_link *link;
+ struct hdac_ext_stream *hext_stream;
+ struct hdac_ext_link *hlink;
+ struct snd_sof_dev *sdev;
+ struct hdac_bus *bus;
+
+ sdev = snd_soc_component_get_drvdata(cpu_dai->component);
+ bus = sof_to_bus(sdev);
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
@@ -225,18 +225,16 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
}
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
- if (!link)
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+ if (!hlink)
return -EINVAL;
/* set the hdac_stream in the codec dai */
snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);
- p_params.s_fmt = snd_pcm_format_width(params_format(params));
p_params.ch = params_channels(params);
p_params.s_freq = params_rate(params);
- p_params.stream = substream->stream;
- p_params.link_index = link->index;
+ p_params.link_index = hlink->index;
p_params.format = params_format(params);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -257,7 +255,6 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct hdac_stream *hstream = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -270,17 +267,17 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(hext_stream);
+ snd_hdac_ext_stream_start(hext_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, true);
+ ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, true);
if (ret < 0)
return ret;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
break;
default:
@@ -291,7 +288,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
{
- struct hdac_stream *hstream = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -301,7 +297,7 @@ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
if (!hext_stream)
return 0;
- return hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+ return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
}
static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
@@ -458,14 +454,12 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w;
struct snd_soc_dai *codec_dai;
- struct hdac_stream *hstream;
struct snd_soc_dai *cpu_dai;
int ret;
dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
dai->name, substream->stream);
- hstream = substream->runtime->private_data;
rtd = asoc_substream_to_rtd(substream);
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -476,7 +470,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(hext_stream);
+ snd_hdac_ext_stream_start(hext_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
@@ -484,23 +478,23 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_RESET);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_RESET;
- ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+ ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret;
@@ -512,14 +506,14 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
break;
}
default:
@@ -575,7 +569,8 @@ static int hda_dai_suspend(struct hdac_bus *bus)
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
codec_dai = asoc_rtd_to_codec(rtd, 0);
- ret = hda_link_dma_cleanup(hext_stream->link_substream, s,
+ ret = hda_link_dma_cleanup(hext_stream->link_substream,
+ hext_stream,
cpu_dai, codec_dai, false);
if (ret < 0)
return ret;
@@ -726,20 +721,20 @@ static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stre
switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_RESET);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_RESET;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
@@ -777,7 +772,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
ops->drv[i].ops = &ipc3_ssp_dai_ops;
continue;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
if (strstr(ops->drv[i].name, "iDisp") ||
strstr(ops->drv[i].name, "Analog") ||
strstr(ops->drv[i].name, "Digital"))
@@ -798,7 +793,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
ops->drv[i].ops = &ipc4_ssp_dai_ops;
continue;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
if (strstr(ops->drv[i].name, "iDisp") ||
strstr(ops->drv[i].name, "Analog") ||
strstr(ops->drv[i].name, "Digital"))
@@ -916,7 +911,7 @@ struct snd_soc_dai_driver skl_dai[] = {
.channels_max = 4,
},
},
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
{
.name = "iDisp1 Pin",
.playback = {
@@ -989,7 +984,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
* Since the component suspend is called last, we can trap this corner case
* and force the DAIs to release their resources.
*/
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
int ret;
ret = hda_dai_suspend(sof_to_bus(sdev));
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 3c76f843454b..5fa29df54b42 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -347,10 +347,13 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
int retry = HDA_DSP_REG_POLL_RETRY_COUNT;
+ struct snd_sof_pdata *pdata = sdev->pdata;
+ const struct sof_intel_dsp_desc *chip;
- while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) {
+ chip = get_chip_info(pdata);
+ while (snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset) &
+ SOF_HDA_VS_D0I3C_CIP) {
if (!retry--)
return -ETIMEDOUT;
usleep_range(10, 15);
@@ -378,27 +381,33 @@ static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags)
static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
+ struct snd_sof_pdata *pdata = sdev->pdata;
+ const struct sof_intel_dsp_desc *chip;
int ret;
+ u8 reg;
+
+ chip = get_chip_info(pdata);
/* Write to D0I3C after Command-In-Progress bit is cleared */
ret = hda_dsp_wait_d0i3c_done(sdev);
if (ret < 0) {
- dev_err(bus->dev, "CIP timeout before D0I3C update!\n");
+ dev_err(sdev->dev, "CIP timeout before D0I3C update!\n");
return ret;
}
/* Update D0I3C register */
- snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value);
+ snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset,
+ SOF_HDA_VS_D0I3C_I3, value);
/* Wait for cmd in progress to be cleared before exiting the function */
ret = hda_dsp_wait_d0i3c_done(sdev);
if (ret < 0) {
- dev_err(bus->dev, "CIP timeout after D0I3C update!\n");
+ dev_err(sdev->dev, "CIP timeout after D0I3C update!\n");
return ret;
}
- trace_sof_intel_D0I3C_updated(sdev, snd_hdac_chip_readb(bus, VS_D0I3C));
+ reg = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset);
+ trace_sof_intel_D0I3C_updated(sdev, reg);
return 0;
}
@@ -612,9 +621,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_bus *bus = sof_to_bus(sdev);
-#endif
int ret, j;
/*
@@ -633,12 +640,10 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
if (ret < 0)
return ret;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
hda_codec_jack_wake_enable(sdev, runtime_suspend);
- /* power down all hda link */
- snd_hdac_ext_bus_link_power_down_all(bus);
-#endif
+ /* power down all hda links */
+ hda_bus_ml_suspend(bus);
ret = chip->power_down_dsp(sdev);
if (ret < 0) {
@@ -677,10 +682,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct hdac_ext_link *hlink = NULL;
-#endif
int ret;
/* display codec must be powered before link reset */
@@ -693,14 +694,13 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
/* reset and start hda controller */
- ret = hda_dsp_ctrl_init_chip(sdev, true);
+ ret = hda_dsp_ctrl_init_chip(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to start controller after resume\n");
goto cleanup;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* check jack status */
if (runtime_resume) {
hda_codec_jack_wake_enable(sdev, false);
@@ -708,17 +708,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
hda_codec_jack_check(sdev);
}
- /* turn off the links that were off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- /* check dma status and clean up CORB/RIRB buffers */
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
-#endif
-
/* enable ppcap interrupt */
hda_dsp_ctrl_ppcap_enable(sdev, true);
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
@@ -733,37 +722,26 @@ cleanup:
int hda_dsp_resume(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ struct hdac_bus *bus = sof_to_bus(sdev);
struct pci_dev *pci = to_pci_dev(sdev->dev);
const struct sof_dsp_power_state target_state = {
.state = SOF_DSP_PM_D0,
.substate = SOF_HDA_DSP_PM_D0I0,
};
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct hdac_ext_link *hlink = NULL;
-#endif
int ret;
/* resume from D0I3 */
if (sdev->dsp_power_state.state == SOF_DSP_PM_D0) {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* power up links that were active before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (hlink->ref_count) {
- ret = snd_hdac_ext_bus_link_power_up(hlink);
- if (ret < 0) {
- dev_err(sdev->dev,
- "error %d in %s: failed to power up links",
- ret, __func__);
- return ret;
- }
- }
+ ret = hda_bus_ml_resume(bus);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error %d in %s: failed to power up links",
+ ret, __func__);
+ return ret;
}
/* set up CORB/RIRB buffers if was on before suspend */
- if (bus->cmd_dma_state)
- snd_hdac_bus_init_cmd_io(bus);
-#endif
+ hda_codec_resume_cmd_io(sdev);
/* Set DSP power state */
ret = snd_sof_dsp_set_power_state(sdev, &target_state);
@@ -872,20 +850,17 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
HDA_VS_INTEL_EM2_L1SEN,
HDA_VS_INTEL_EM2_L1SEN);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* stop the CORB/RIRB DMA if it is On */
- if (bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
+ hda_codec_suspend_cmd_io(sdev);
/* no link can be powered in s0ix state */
- ret = snd_hdac_ext_bus_link_power_down_all(bus);
+ ret = hda_bus_ml_suspend(bus);
if (ret < 0) {
dev_err(sdev->dev,
"error %d in %s: failed to power down links",
ret, __func__);
return ret;
}
-#endif
/* enable the system waking up via IPC IRQ */
enable_irq_wake(pci->irq);
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 9b3667c705e4..a7c454e03952 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -69,8 +69,16 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -122,10 +130,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcie, hipct;
hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+ hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+
if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
@@ -133,9 +144,9 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
hda_dsp_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -158,6 +169,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ hda_dsp_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -174,10 +186,10 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- /* Let DSP know that we have finished processing the message */
- hda_dsp_ipc_host_done(sdev);
+ /* Let DSP know that we have finished processing the message */
+ hda_dsp_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -186,6 +198,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c
index 0193fb3964a0..69fdef8f89ae 100644
--- a/sound/soc/sof/intel/hda-loader-skl.c
+++ b/sound/soc/sof/intel/hda-loader-skl.c
@@ -141,7 +141,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable)
u32 run = enable ? 0x1 : 0;
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run));
retries = 300;
@@ -150,7 +150,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable)
/* waiting for hardware to report the stream Run bit set */
val = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL);
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL);
val &= HDA_CL_SD_CTL_RUN(1);
if (enable && val)
break;
@@ -174,23 +174,23 @@ static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev)
* Descriptor Error Interrupt and set the cldma stream number to 0.
*/
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0));
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0));
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, HDA_CL_SD_BDLPLBA(0));
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(0));
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
/* Set the Cyclic Buffer Length to 0. */
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0);
+ sd_offset + SOF_HDA_ADSP_REG_SD_CBL, 0);
/* Set the Last Valid Index. */
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0);
+ sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0);
}
static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev,
@@ -240,27 +240,27 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev,
/* setting the stream register */
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
HDA_CL_SD_BDLPLBA(dmab_bdl->addr));
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
HDA_CL_SD_BDLPUBA(dmab_bdl->addr));
/* Set the Cyclic Buffer Length. */
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size);
+ sd_offset + SOF_HDA_ADSP_REG_SD_CBL, max_size);
/* Set the Last Valid Index. */
snd_sof_dsp_write(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1);
+ sd_offset + SOF_HDA_ADSP_REG_SD_LVI, count - 1);
/* Set the Interrupt On Completion, FIFO Error Interrupt,
* Descriptor Error Interrupt and the cldma stream number.
*/
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1));
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
HDA_CL_SD_CTL_STRM(0xf),
HDA_CL_SD_CTL_STRM(1));
}
@@ -439,7 +439,7 @@ static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev,
/* now check DMA interrupt status */
cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS);
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS);
if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) {
dev_err(sdev->dev, "cldma copy failed\n");
@@ -494,14 +494,13 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
struct firmware stripped_firmware;
unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;
int ret;
- stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+ stripped_firmware.data = fw->data + sdev->basefw.payload_offset;
+ stripped_firmware.size = fw->size - sdev->basefw.payload_offset;
dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize);
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 98812d51b31c..d680562edb35 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -19,7 +19,9 @@
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
+#include <sound/sof/ipc4/header.h>
#include "ext_manifest.h"
+#include "../ipc4-priv.h"
#include "../ops.h"
#include "../sof-priv.h"
#include "hda.h"
@@ -263,9 +265,9 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
/* reset BDL address */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0);
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
snd_dma_free_pages(dmab);
@@ -318,10 +320,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct hdac_ext_stream *iccmax_stream;
struct hdac_bus *bus = sof_to_bus(sdev);
- struct firmware stripped_firmware;
struct snd_dma_buffer dmab_bdl;
int ret, ret1;
u8 original_gb;
@@ -329,15 +329,11 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
/* save the original LTRP guardband value */
original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK;
- if (plat_data->fw->size <= plat_data->fw_offset) {
- dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
- return -EINVAL;
- }
-
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
-
- /* prepare capture stream for ICCMAX */
- iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
+ /*
+ * Prepare capture stream for ICCMAX. We do not need to store
+ * the data, so use a buffer of PAGE_SIZE for receiving.
+ */
+ iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
&dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
@@ -397,21 +393,25 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
hda->boot_iteration = 0;
ret = hda_dsp_boot_imr(sdev);
- if (!ret)
+ if (!ret) {
+ hda->booted_from_imr = true;
return 0;
+ }
dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
}
+ hda->booted_from_imr = false;
+
chip_info = desc->chip_info;
- if (plat_data->fw->size <= plat_data->fw_offset) {
+ if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) {
dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
return -EINVAL;
}
- stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+ stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
+ stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
@@ -515,6 +515,70 @@ cleanup:
return ret;
}
+int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib, bool reload)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ struct hdac_ext_stream *hext_stream;
+ struct firmware stripped_firmware;
+ struct sof_ipc4_msg msg = {};
+ struct snd_dma_buffer dmab;
+ int ret, ret1;
+
+ /* IMR booting will restore the libraries as well, skip the loading */
+ if (reload && hda->booted_from_imr)
+ return 0;
+
+ /* the fw_lib has been verified during loading, we can trust the validity here */
+ stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
+ stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;
+
+ /* prepare DMA for code loader stream */
+ hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
+ stripped_firmware.size,
+ &dmab, SNDRV_PCM_STREAM_PLAYBACK);
+ if (IS_ERR(hext_stream)) {
+ dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
+ return PTR_ERR(hext_stream);
+ }
+
+ memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size);
+
+ msg.primary = hext_stream->hstream.stream_tag - 1;
+ msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+ msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);
+
+ ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
+ goto cleanup;
+ }
+
+ ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+
+ ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
+ if (ret1 < 0) {
+ dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
+ if (!ret)
+ ret = ret1;
+ }
+
+cleanup:
+ /* clean up even in case of error and return the first error */
+ ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
+ if (ret1 < 0) {
+ dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
+
+ /* set return value to indicate cleanup failure */
+ if (!ret)
+ ret = ret1;
+ }
+
+ return ret;
+}
+
/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
new file mode 100644
index 000000000000..76ab9a2e7bb3
--- /dev/null
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+
+/*
+ * Management of HDaudio multi-link (capabilities, power, coupling)
+ */
+
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_register.h>
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/intel-dsp-config.h>
+#include <sound/intel-nhlt.h>
+#include <sound/sof.h>
+#include <sound/sof/xtensa.h>
+#include "../sof-audio.h"
+#include "../sof-pci-dev.h"
+#include "../ops.h"
+#include "hda.h"
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+
+void hda_bus_ml_get_capabilities(struct hdac_bus *bus)
+{
+ if (bus->mlcap)
+ snd_hdac_ext_bus_get_ml_capabilities(bus);
+}
+
+void hda_bus_ml_free(struct hdac_bus *bus)
+{
+ struct hdac_ext_link *hlink;
+
+ if (!bus->mlcap)
+ return;
+
+ while (!list_empty(&bus->hlink_list)) {
+ hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
+ list_del(&hlink->list);
+ kfree(hlink);
+ }
+}
+
+void hda_bus_ml_put_all(struct hdac_bus *bus)
+{
+ struct hdac_ext_link *hlink;
+
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ snd_hdac_ext_bus_link_put(bus, hlink);
+}
+
+void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
+{
+ struct hdac_ext_link *hlink;
+
+ /* Reset stream-to-link mapping */
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+}
+
+int hda_bus_ml_resume(struct hdac_bus *bus)
+{
+ struct hdac_ext_link *hlink;
+ int ret;
+
+ /* power up links that were active before suspend */
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
+ if (hlink->ref_count) {
+ ret = snd_hdac_ext_bus_link_power_up(hlink);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int hda_bus_ml_suspend(struct hdac_bus *bus)
+{
+ return snd_hdac_ext_bus_link_power_down_all(bus);
+}
+
+#endif
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 0a9c80216a8c..dc0b359ed9b6 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -142,7 +142,6 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
struct snd_pcm_runtime *runtime = substream->runtime;
ssize_t appl_pos, buf_size;
u32 spib;
@@ -156,7 +155,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea
if (!spib)
spib = buf_size;
- sof_io_write(sdev, hext_stream->spib_addr, spib);
+ sof_io_write(sdev, hstream->spib_addr, spib);
return 0;
}
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index be60e7785da9..7f0fd05a96e6 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -173,7 +173,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
enable << hstream->index);
/* set the SPIB value */
- sof_io_write(sdev, hext_stream->spib_addr, size);
+ sof_io_write(sdev, hstream->spib_addr, size);
return 0;
}
@@ -367,7 +367,7 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
if (ret >= 0) {
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK);
hstream->running = false;
@@ -398,7 +398,6 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
struct snd_dma_buffer *dmab,
struct snd_pcm_hw_params *params)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret;
@@ -419,10 +418,10 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
/* reset BDL address */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
0x0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
0x0);
hstream->frags = 0;
@@ -435,20 +434,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
/* program BDL address */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
(u32)hstream->bdl.addr);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
upper_32_bits(hstream->bdl.addr));
/* program cyclic buffer length */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CBL,
hstream->bufsize);
/* program last valid index */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI,
+ sd_offset + SOF_HDA_ADSP_REG_SD_LVI,
0xffff, (hstream->frags - 1));
/* decouple host and link DMA, enable DSP features */
@@ -456,7 +455,8 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
mask, mask);
/* Follow HW recommendation to set the guardband value to 95us during FW boot */
- snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US);
+ snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_LTRP,
+ HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US);
/* start DMA */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
@@ -520,7 +520,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
}
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
SOF_HDA_CL_DMA_SD_INT_MASK);
@@ -534,10 +534,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
/* reset BDL address */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
0x0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
0x0);
/* clear stream status */
@@ -562,7 +562,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
}
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+ sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
SOF_HDA_CL_DMA_SD_INT_MASK);
@@ -582,7 +582,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
/* program cyclic buffer length */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_CBL,
hstream->bufsize);
/*
@@ -606,7 +606,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
/* program stream format */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset +
- SOF_HDA_ADSP_REG_CL_SD_FORMAT,
+ SOF_HDA_ADSP_REG_SD_FORMAT,
0xffff, hstream->format_val);
if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) {
@@ -617,15 +617,15 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
/* program last valid index */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI,
+ sd_offset + SOF_HDA_ADSP_REG_SD_LVI,
0xffff, (hstream->frags - 1));
/* program BDL address */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
(u32)hstream->bdl.addr);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
- sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+ sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
upper_32_bits(hstream->bdl.addr));
/* enable position buffer, if needed */
@@ -649,7 +649,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
hstream->fifo_size =
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
sd_offset +
- SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE);
+ SOF_HDA_ADSP_REG_SD_FIFOSIZE);
hstream->fifo_size &= 0xffff;
hstream->fifo_size += 1;
} else {
@@ -697,7 +697,8 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
/* The function can be called at irq thread, so use spin_lock_irq */
spin_lock_irq(&bus->reg_lock);
- status = snd_hdac_chip_readl(bus, INTSTS);
+ status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
+
trace_sof_intel_hda_dsp_check_stream_irq(sdev, status);
/* if Register inaccessible, ignore it.*/
@@ -735,11 +736,11 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
list_for_each_entry(s, &bus->stream_list, list) {
if (status & BIT(s->index) && s->opened) {
- sd_status = snd_hdac_stream_readb(s, SD_STS);
+ sd_status = readb(s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
trace_sof_intel_hda_dsp_stream_status(bus->dev, s, sd_status);
- snd_hdac_stream_writeb(s, SD_STS, sd_status);
+ writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
active = true;
if ((!s->substream && !s->cstream) ||
@@ -764,9 +765,6 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
struct hdac_bus *bus = sof_to_bus(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- u32 rirb_status;
-#endif
bool active;
u32 status;
int i;
@@ -778,29 +776,15 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
for (i = 0, active = true; i < 10 && active; i++) {
spin_lock_irq(&bus->reg_lock);
- status = snd_hdac_chip_readl(bus, INTSTS);
+ status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
/* check streams */
active = hda_dsp_stream_check(bus, status);
/* check and clear RIRB interrupt */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
if (status & AZX_INT_CTRL_EN) {
- rirb_status = snd_hdac_chip_readb(bus, RIRBSTS);
- if (rirb_status & RIRB_INT_MASK) {
- /*
- * Clearing the interrupt status here ensures
- * that no interrupt gets masked after the RIRB
- * wp is read in snd_hdac_bus_update_rirb.
- */
- snd_hdac_chip_writeb(bus, RIRBSTS,
- RIRB_INT_MASK);
- active = true;
- if (rirb_status & RIRB_INT_RESPONSE)
- snd_hdac_bus_update_rirb(bus);
- }
+ active |= hda_codec_check_rirb_status(sdev);
}
-#endif
spin_unlock_irq(&bus->reg_lock);
}
@@ -853,15 +837,16 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* mem alloc for the CORB/RIRB ringbuffers */
+ /*
+ * mem alloc for the CORB/RIRB ringbuffers - this will be used only for
+ * HDAudio codecs
+ */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
PAGE_SIZE, &bus->rb);
if (ret < 0) {
dev_err(sdev->dev, "error: RB alloc failed\n");
return -ENOMEM;
}
-#endif
/* create capture streams */
for (i = 0; i < num_capture; i++) {
@@ -883,18 +868,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i;
+ hstream = &hext_stream->hstream;
+
/* do we support SPIB */
if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_SPIB;
- hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_MAXFIFO;
}
- hstream = &hext_stream->hstream;
hstream->bus = bus;
hstream->sd_int_sta_mask = 1 << i;
hstream->index = i;
@@ -939,18 +925,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i;
+ hstream = &hext_stream->hstream;
+
/* do we support SPIB */
if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_SPIB;
- hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_MAXFIFO;
}
- hstream = &hext_stream->hstream;
hstream->bus = bus;
hstream->sd_int_sta_mask = 1 << i;
hstream->index = i;
@@ -992,11 +979,9 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
if (bus->posbuf.area)
snd_dma_free_pages(&bus->posbuf);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* free position buffer */
+ /* free CORB/RIRB buffer - only used for HDaudio codecs */
if (bus->rb.area)
snd_dma_free_pages(&bus->rb);
-#endif
list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
/* TODO: decouple */
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 1188ec51816b..14a2f8701350 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -155,9 +155,27 @@ struct sdw_intel_ops sdw_callback = {
.free_stream = sdw_free_stream,
};
+void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+ struct sof_intel_hda_dev *hdev;
+
+ hdev = sdev->pdata->hw_pdata;
+
+ if (!hdev->sdw)
+ return;
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
+ HDA_DSP_REG_ADSPIC2_SNDW,
+ enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
+}
+
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
- sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable);
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->enable_sdw_irq)
+ chip->enable_sdw_irq(sdev, enable);
}
static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
@@ -220,10 +238,45 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
return 0;
}
+int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hdev;
+ struct sdw_intel_ctx *ctx;
+ u32 caps;
+
+ hdev = sdev->pdata->hw_pdata;
+ ctx = hdev->sdw;
+
+ caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
+ caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
+
+ /* Check HW supported vs property value */
+ if (caps < ctx->count) {
+ dev_err(sdev->dev,
+ "BIOS master count %d is larger than hardware capabilities %d\n",
+ ctx->count, caps);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->read_sdw_lcount)
+ return chip->read_sdw_lcount(sdev);
+
+ return 0;
+}
+
int hda_sdw_startup(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev;
struct snd_sof_pdata *pdata = sdev->pdata;
+ int ret;
hdev = sdev->pdata->hw_pdata;
@@ -233,6 +286,10 @@ int hda_sdw_startup(struct snd_sof_dev *sdev)
if (pdata->machine && !pdata->machine->mach_params.link_mask)
return 0;
+ ret = hda_sdw_check_lcount(sdev);
+ if (ret < 0)
+ return ret;
+
return sdw_intel_startup(hdev->sdw);
}
@@ -383,12 +440,6 @@ static int mclk_id_override = -1;
module_param_named(mclk_id, mclk_id_override, int, 0444);
MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
-module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
-MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
-#endif
-
static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
{HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
{HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
@@ -625,7 +676,6 @@ static bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
u32 adspis;
u32 intsts;
u32 intctl;
@@ -637,7 +687,7 @@ void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL);
ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS);
- rirbsts = snd_hdac_chip_readb(bus, RIRBSTS);
+ rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS);
dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n",
intsts, intctl, rirbsts);
@@ -681,6 +731,17 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev)
hipci, hipcie, hipct, hipcte, hipcctl);
}
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ u32 val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
+
+ return !!(val & chip->ipc_req_mask);
+}
+
static int hda_init(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus;
@@ -692,7 +753,7 @@ static int hda_init(struct snd_sof_dev *sdev)
bus = sof_to_bus(sdev);
/* HDA bus init */
- sof_hda_bus_init(bus, &pci->dev);
+ sof_hda_bus_init(sdev, &pci->dev);
if (sof_hda_position_quirk == SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS)
bus->use_posbuf = 0;
@@ -787,7 +848,7 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *sof_tplg_filename,
@@ -867,9 +928,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_sof_pdata *pdata = sdev->pdata;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_ext_link *hlink;
-#endif
struct sof_intel_hda_dev *hdev = pdata->hw_pdata;
u32 link_mask;
int ret = 0;
@@ -879,13 +937,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
/* Init HDA controller after i915 init */
- ret = hda_dsp_ctrl_init_chip(sdev, true);
+ ret = hda_dsp_ctrl_init_chip(sdev);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
ret);
return ret;
}
+ hda_bus_ml_get_capabilities(bus);
+
/* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) {
@@ -914,37 +974,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
skip_soundwire:
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- if (bus->mlcap)
- snd_hdac_ext_bus_get_ml_capabilities(bus);
-
/* create codec instances */
- hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi);
+ hda_codec_probe_bus(sdev);
if (!HDA_IDISP_CODEC(bus->codec_mask))
hda_codec_i915_display_power(sdev, false);
- /*
- * we are done probing so decrement link counts
- */
- list_for_each_entry(hlink, &bus->hlink_list, list)
- snd_hdac_ext_bus_link_put(bus, hlink);
-#endif
- return 0;
-}
+ hda_bus_ml_put_all(bus);
-static void hda_check_for_state_change(struct snd_sof_dev *sdev)
-{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_bus *bus = sof_to_bus(sdev);
- unsigned int codec_mask;
-
- codec_mask = snd_hdac_chip_readw(bus, STATESTS);
- if (codec_mask) {
- hda_codec_jack_check(sdev);
- snd_hdac_chip_writew(bus, STATESTS, codec_mask);
- }
-#endif
+ return 0;
}
static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
@@ -996,7 +1034,7 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
hda_sdw_process_wakeen(sdev);
}
- hda_check_for_state_change(sdev);
+ hda_codec_check_for_state_change(sdev);
/* enable GIE interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
@@ -1192,10 +1230,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- /* codec removal, invoke bus_device_remove */
- snd_hdac_ext_bus_device_remove(bus);
-#endif
+ hda_codec_device_remove(sdev);
hda_sdw_exit(sdev);
@@ -1223,16 +1258,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
pci_free_irq_vectors(pci);
hda_dsp_stream_free(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- snd_hdac_link_free_all(bus);
-#endif
+
+ hda_bus_ml_free(sof_to_bus(sdev));
iounmap(sdev->bar[HDA_DSP_BAR]);
iounmap(bus->remap_addr);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- snd_hdac_ext_bus_exit(bus);
-#endif
+ sof_hda_bus_exit(sdev);
+
hda_codec_i915_exit(sdev);
return 0;
@@ -1246,7 +1279,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev)
return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
static void hda_generic_machine_select(struct snd_sof_dev *sdev,
struct snd_soc_acpi_mach **mach)
{
@@ -1325,7 +1358,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
if (*mach) {
mach_params = &(*mach)->mach_params;
mach_params->codec_mask = bus->codec_mask;
- mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
+ mach_params->common_hdmi_codec_drv = true;
}
}
#else
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 2ab3c3840b92..022ce80968dd 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -122,17 +122,17 @@
#define SOF_HDA_ADSP_DPLBASE_ENABLE 0x01
/* Stream Registers */
-#define SOF_HDA_ADSP_REG_CL_SD_CTL 0x00
-#define SOF_HDA_ADSP_REG_CL_SD_STS 0x03
-#define SOF_HDA_ADSP_REG_CL_SD_LPIB 0x04
-#define SOF_HDA_ADSP_REG_CL_SD_CBL 0x08
-#define SOF_HDA_ADSP_REG_CL_SD_LVI 0x0C
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOW 0x0E
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE 0x10
-#define SOF_HDA_ADSP_REG_CL_SD_FORMAT 0x12
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14
-#define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18
-#define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C
+#define SOF_HDA_ADSP_REG_SD_CTL 0x00
+#define SOF_HDA_ADSP_REG_SD_STS 0x03
+#define SOF_HDA_ADSP_REG_SD_LPIB 0x04
+#define SOF_HDA_ADSP_REG_SD_CBL 0x08
+#define SOF_HDA_ADSP_REG_SD_LVI 0x0C
+#define SOF_HDA_ADSP_REG_SD_FIFOW 0x0E
+#define SOF_HDA_ADSP_REG_SD_FIFOSIZE 0x10
+#define SOF_HDA_ADSP_REG_SD_FORMAT 0x12
+#define SOF_HDA_ADSP_REG_SD_FIFOL 0x14
+#define SOF_HDA_ADSP_REG_SD_BDLPL 0x18
+#define SOF_HDA_ADSP_REG_SD_BDLPU 0x1C
#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20
/* CL: Software Position Based FIFO Capability Registers */
@@ -294,6 +294,7 @@
#define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10)
#define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14)
+#define HDA_DSP_REG_ADSPIC2_SNDW BIT(5)
#define HDA_DSP_REG_ADSPIS2_SNDW BIT(5)
/* Intel HD Audio Inter-Processor Communication Registers */
@@ -307,6 +308,7 @@
/* Intel Vendor Specific Registers */
#define HDA_VS_INTEL_EM2 0x1030
#define HDA_VS_INTEL_EM2_L1SEN BIT(13)
+#define HDA_VS_INTEL_LTRP 0x1048
#define HDA_VS_INTEL_LTRP_GB_MASK 0x3F
/* HIPCI */
@@ -481,6 +483,7 @@ enum sof_hda_D0_substate {
struct sof_intel_hda_dev {
bool imrboot_supported;
bool skip_imr_boot;
+ bool booted_from_imr;
int boot_iteration;
@@ -521,6 +524,14 @@ struct sof_intel_hda_dev {
/* Intel NHLT information */
struct nhlt_acpi_table *nhlt;
+
+ /*
+ * Pointing to the IPC message if immediate sending was not possible
+ * because the downlink communication channel was BUSY at the time.
+ * The message will be re-tried when the channel becomes free (the ACK
+ * is received from the DSP for the previous message)
+ */
+ struct snd_sof_ipc_msg *delayed_ipc_tx_msg;
};
static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -693,27 +704,51 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset);
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev);
void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
/*
* HDA bus operations.
*/
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev);
+void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev);
+void sof_hda_bus_exit(struct snd_sof_dev *sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
/*
* HDA Codec operations.
*/
-void hda_codec_probe_bus(struct snd_sof_dev *sdev,
- bool hda_codec_use_common_hdmi);
+void hda_codec_probe_bus(struct snd_sof_dev *sdev);
void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable);
void hda_codec_jack_check(struct snd_sof_dev *sdev);
+void hda_codec_check_for_state_change(struct snd_sof_dev *sdev);
+void hda_codec_init_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_detect_mask(struct snd_sof_dev *sdev);
+void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev);
+bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev);
+void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status);
+void hda_codec_device_remove(struct snd_sof_dev *sdev);
-#endif /* CONFIG_SND_SOC_SOF_HDA */
+#else
+
+static inline void hda_codec_probe_bus(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) { }
+static inline void hda_codec_jack_check(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_detect_mask(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) { }
+static inline bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) { return false; }
+static inline void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) { }
+static inline void hda_codec_device_remove(struct snd_sof_dev *sdev) { }
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && \
- (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \
- IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable);
int hda_codec_i915_init(struct snd_sof_dev *sdev);
@@ -721,13 +756,32 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev);
#else
-static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev,
- bool enable) { }
+static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) { }
static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; }
static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; }
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+
+void hda_bus_ml_get_capabilities(struct hdac_bus *bus);
+void hda_bus_ml_free(struct hdac_bus *bus);
+void hda_bus_ml_put_all(struct hdac_bus *bus);
+void hda_bus_ml_reset_losidv(struct hdac_bus *bus);
+int hda_bus_ml_resume(struct hdac_bus *bus);
+int hda_bus_ml_suspend(struct hdac_bus *bus);
+
+#else
+
+static inline void hda_bus_ml_get_capabilities(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_free(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { }
+static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; }
+static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; }
+
+#endif /* CONFIG_SND_SOC_SOF_HDA */
+
/*
* Trace Control.
*/
@@ -741,18 +795,29 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
*/
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev);
int hda_sdw_startup(struct snd_sof_dev *sdev);
+void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
#else
+static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+
static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
{
return 0;
}
+static inline void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+}
+
static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
}
@@ -852,8 +917,12 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask);
irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev);
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void hda_ipc4_dump(struct snd_sof_dev *sdev);
extern struct sdw_intel_ops sdw_callback;
+struct sof_ipc4_fw_library;
+int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib, bool reload);
#endif
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 6d5877108a3d..435941a1692f 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -130,6 +130,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_icl_ops.irq_thread = cnl_ipc4_irq_thread;
@@ -177,6 +180,9 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 10298532816f..904ae42534e1 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -90,8 +90,16 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -126,111 +134,79 @@ static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
}
-static int mtl_enable_interrupts(struct snd_sof_dev *sdev)
+static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
- u32 hfintipptr;
- u32 irqinten;
- u32 host_ipc;
u32 hipcie;
+ u32 mask;
+ u32 val;
int ret;
- /* read Interrupt IP Pointer */
- hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+ /* Enable/Disable SoundWire interrupt */
+ mask = MTL_DSP_REG_HfSNDWIE_IE_MASK;
+ if (enable)
+ val = mask;
+ else
+ val = 0;
- /* Enable Host IPC and SOUNDWIRE */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
- MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK,
- MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK);
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val);
/* check if operation was successful */
- host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
- ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
- (irqinten & host_ipc) == host_ipc,
- HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n");
- return ret;
- }
-
- /* Set Host IPC interrupt enable */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
- MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK);
-
- /* check if operation was successful */
- host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
- ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
- (hipcie & host_ipc) == host_ipc,
- HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n");
- return ret;
- }
-
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
- MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK);
- host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
- (hipcie & host_ipc) == host_ipc,
+ (hipcie & mask) == val,
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0)
- dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n");
-
- return ret;
+ dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",
+ enable ? "enable" : "disable");
}
-static int mtl_disable_interrupts(struct snd_sof_dev *sdev)
+static int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
{
u32 hfintipptr;
u32 irqinten;
- u32 host_ipc;
u32 hipcie;
- int ret1;
+ u32 mask;
+ u32 val;
int ret;
/* read Interrupt IP Pointer */
hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
- /* Disable Host IPC and SOUNDWIRE */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
- MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0);
+ /* Enable/Disable Host IPC and SOUNDWIRE */
+ mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
+ if (enable)
+ val = mask;
+ else
+ val = 0;
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val);
/* check if operation was successful */
- host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
- (irqinten & host_ipc) == 0,
+ (irqinten & mask) == val,
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
- /* Continue to disable other interrupts when error happens */
- if (ret < 0)
- dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n");
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",
+ enable ? "enable" : "disable");
+ return ret;
+ }
- /* Set Host IPC interrupt disable */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
- MTL_DSP_REG_HfHIPCIE_IE_MASK, 0);
+ /* Enable/Disable Host IPC interrupt*/
+ mask = MTL_DSP_REG_HfHIPCIE_IE_MASK;
+ if (enable)
+ val = mask;
+ else
+ val = 0;
- /* check if operation was successful */
- host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
- ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
- (hipcie & host_ipc) == 0,
- HDA_DSP_REG_POLL_INTERVAL_US,
- HDA_DSP_RESET_TIMEOUT_US);
- if (ret1 < 0) {
- dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n");
- if (!ret)
- ret = ret1;
- }
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val);
- /* Set SoundWire IPC interrupt disable */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
- MTL_DSP_REG_HfSNDWIE_IE_MASK, 0);
- host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
- ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
- (hipcie & host_ipc) == 0,
- HDA_DSP_REG_POLL_INTERVAL_US,
- HDA_DSP_RESET_TIMEOUT_US);
- if (ret1 < 0) {
- dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n");
- if (!ret)
- ret = ret1;
+ /* check if operation was successful */
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
+ (hipcie & mask) == val,
+ HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",
+ enable ? "enable" : "disable");
+ return ret;
}
return ret;
@@ -385,7 +361,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);
- /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+ /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
usleep_range(1000, 1010);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
@@ -414,7 +390,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
MTL_HFDSSCS_SPA_MASK, 0);
- /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+ /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
@@ -465,7 +441,7 @@ static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_bo
chip->ipc_ack_mask);
/* step 4: enable interrupts */
- ret = mtl_enable_interrupts(sdev);
+ ret = mtl_enable_interrupts(sdev, true);
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__);
@@ -492,11 +468,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcida;
u32 hipctdr;
hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
+ hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
/* reply message from DSP */
if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {
@@ -507,9 +485,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
mtl_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
/* Message from DSP (reply or notification) */
u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
@@ -530,6 +508,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ mtl_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -546,9 +525,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- mtl_ipc_host_done(sdev);
+ mtl_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -558,6 +537,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
}
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
@@ -590,8 +576,9 @@ static void mtl_ipc_dump(struct snd_sof_dev *sdev)
static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
+ mtl_enable_sdw_irq(sdev, false);
mtl_disable_ipc_interrupts(sdev);
- return mtl_disable_interrupts(sdev);
+ return mtl_enable_interrupts(sdev, false);
}
/* Meteorlake ops */
@@ -641,6 +628,9 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* set DAI ops */
hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
@@ -663,6 +653,9 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE_ACE,
.sdw_alh_base = SDW_ALH_BASE_ACE,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = mtl_enable_sdw_irq,
.check_sdw_irq = mtl_dsp_check_sdw_irq,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.cl_init = mtl_dsp_cl_init,
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 788bf0e3ea87..0fd4e6fe09b8 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -21,6 +21,8 @@
#define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6)
#define MTL_HFINTIPPTR_PTR_MASK GENMASK(20, 0)
+#define MTL_HDA_VS_D0I3C 0x1D4A
+
#define MTL_DSP2CXCAP_PRIMARY_CORE 0x178D00
#define MTL_DSP2CXCTL_PRIMARY_CORE 0x178D04
#define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0)
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 998e219011f0..69279dcc92dc 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -33,6 +33,9 @@ static const struct sof_dev_desc bxt_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/apl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/apl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -61,6 +64,9 @@ static const struct sof_dev_desc glk_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/glk",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/glk",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index c797356f7028..8db3f8d15b55 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc cnl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc cfl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -91,6 +97,9 @@ static const struct sof_dev_desc cml_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 48f24f8ace26..d6cf75e357db 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc icl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/icl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/icl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc jsl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/jsl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/jsl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
index 9f39da984e9f..6e4e6d4ef5a5 100644
--- a/sound/soc/sof/intel/pci-mtl.c
+++ b/sound/soc/sof/intel/pci-mtl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc mtl_desc = {
.default_fw_path = {
[SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/sof-ipc4-lib/mtl",
+ },
.default_tplg_path = {
[SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
},
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index 4cfe4f242fc5..e80c4dfef85a 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc tgl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/tgl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc tglh_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl-h",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/tgl-h",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -90,6 +96,9 @@ static const struct sof_dev_desc ehl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/ehl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/ehl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -118,6 +127,9 @@ static const struct sof_dev_desc adls_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-s",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl-s",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -146,6 +158,9 @@ static const struct sof_dev_desc adl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -174,6 +189,9 @@ static const struct sof_dev_desc adl_n_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-n",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl-n",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -202,6 +220,9 @@ static const struct sof_dev_desc rpls_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl-s",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/rpl-s",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -230,6 +251,9 @@ static const struct sof_dev_desc rpl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/rpl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c
index f0f6d9ba8803..5b2b409752c5 100644
--- a/sound/soc/sof/intel/pci-tng.c
+++ b/sound/soc/sof/intel/pci-tng.c
@@ -144,11 +144,7 @@ struct snd_sof_dsp_ops sof_tng_ops = {
.run = atom_run,
.reset = atom_reset,
- /* Register IO */
- .write = sof_io_write,
- .read = sof_io_read,
- .write64 = sof_io_write64,
- .read64 = sof_io_read64,
+ /* Register IO uses direct mmio */
/* Block IO */
.block_read = sof_block_read,
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index 3ceba5c39317..48428ccbcfe0 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -182,8 +182,11 @@ struct sof_intel_dsp_desc {
int ssp_base_offset; /* base address of the SSPs */
u32 sdw_shim_base;
u32 sdw_alh_base;
+ u32 d0i3_offset;
u32 quirks;
enum sof_intel_hw_ip_version hw_ip_version;
+ int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
+ void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
int (*power_down_dsp)(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 9ae2890e9dac..30f2f49ee149 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -85,6 +85,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread;
@@ -132,6 +135,9 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
@@ -157,6 +163,9 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
@@ -182,6 +191,9 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
@@ -207,6 +219,9 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
+ .d0i3_offset = SOF_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index 6ed3f9b6a0c4..b53abc923026 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -84,6 +84,14 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes
}
EXPORT_SYMBOL(sof_ipc_tx_message);
+/* IPC set or get data from host to DSP */
+int sof_ipc_set_get_data(struct snd_sof_ipc *ipc, void *msg_data,
+ size_t msg_bytes, bool set)
+{
+ return ipc->ops->set_get_data(ipc->sdev, msg_data, msg_bytes, set);
+}
+EXPORT_SYMBOL(sof_ipc_set_get_data);
+
/*
* send IPC message from host to DSP without modifying the DSP state.
* This will be used for IPC's that can be handled by the DSP
@@ -200,6 +208,9 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
return NULL;
}
+ if (ops->init && ops->init(sdev))
+ return NULL;
+
ipc->ops = ops;
return ipc;
@@ -217,5 +228,8 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev)
mutex_lock(&ipc->tx_mutex);
ipc->disable_ipc_tx = true;
mutex_unlock(&ipc->tx_mutex);
+
+ if (ipc->ops->exit)
+ ipc->ops->exit(sdev);
}
EXPORT_SYMBOL(snd_sof_ipc_free);
diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c
index bf423ca4e97b..28218766d211 100644
--- a/sound/soc/sof/ipc3-loader.c
+++ b/sound/soc/sof/ipc3-loader.c
@@ -138,8 +138,7 @@ static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmw
static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
const struct sof_ext_man_elem_header *elem_hdr;
const struct sof_ext_man_header *head;
ssize_t ext_man_size;
@@ -310,18 +309,18 @@ static int sof_ipc3_parse_module_memcpy(struct snd_sof_dev *sdev,
static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ u32 payload_offset = sdev->basefw.payload_offset;
+ const struct firmware *fw = sdev->basefw.fw;
struct snd_sof_fw_header *header;
struct snd_sof_mod_hdr *module;
int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr);
size_t remaining;
int ret, count;
- if (!plat_data->fw)
+ if (!fw)
return -EINVAL;
- header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+ header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
load_module = sof_ops(sdev)->load_module;
if (!load_module) {
dev_dbg(sdev->dev, "Using generic module loading\n");
@@ -331,9 +330,8 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
}
/* parse each module */
- module = (struct snd_sof_mod_hdr *)(fw->data + plat_data->fw_offset +
- sizeof(*header));
- remaining = fw->size - sizeof(*header) - plat_data->fw_offset;
+ module = (struct snd_sof_mod_hdr *)(fw->data + payload_offset + sizeof(*header));
+ remaining = fw->size - sizeof(*header) - payload_offset;
/* check for wrap */
if (remaining > fw->size) {
dev_err(sdev->dev, "%s: fw size smaller than header size\n", __func__);
@@ -374,19 +372,19 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
static int sof_ipc3_validate_firmware(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ u32 payload_offset = sdev->basefw.payload_offset;
+ const struct firmware *fw = sdev->basefw.fw;
struct snd_sof_fw_header *header;
- size_t fw_size = fw->size - plat_data->fw_offset;
+ size_t fw_size = fw->size - payload_offset;
- if (fw->size <= plat_data->fw_offset) {
+ if (fw->size <= payload_offset) {
dev_err(sdev->dev,
"firmware size must be greater than firmware offset\n");
return -EINVAL;
}
/* Read the header information from the data pointer */
- header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+ header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
/* verify FW sig */
if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index dad57bef38f6..f10bfc9bd5cb 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -336,6 +336,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min, channels->max);
break;
case SOF_DAI_AMD_SP:
+ case SOF_DAI_AMD_SP_VIRTUAL:
rate->min = private->dai_config->acpsp.fsync_rate;
rate->max = private->dai_config->acpsp.fsync_rate;
channels->min = private->dai_config->acpsp.tdm_slots;
@@ -347,6 +348,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min, channels->max);
break;
case SOF_DAI_AMD_HS:
+ case SOF_DAI_AMD_HS_VIRTUAL:
rate->min = private->dai_config->acphs.fsync_rate;
rate->max = private->dai_config->acphs.fsync_rate;
channels->min = private->dai_config->acphs.tdm_slots;
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index c148715aa0f9..b94cc40485ed 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -276,6 +276,16 @@ static const struct sof_topology_token acpdmic_tokens[] = {
offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
};
+/* ACPI2S */
+static const struct sof_topology_token acpi2s_tokens[] = {
+ {SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
+ {SOF_TKN_AMD_ACPI2S_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
+ {SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
+};
+
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -311,6 +321,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
+ [SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
};
/**
@@ -1193,6 +1204,7 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
+ int ret;
/* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config);
@@ -1201,12 +1213,15 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_
memset(&config->acpsp, 0, sizeof(config->acpsp));
config->hdr.size = size;
- config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
- config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ ret = sof_update_ipc_object(scomp, &config->acpsp, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
- dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n",
+ dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n",
config->dai_index, config->acpsp.tdm_slots,
- config->acpsp.fsync_rate);
+ config->acpsp.fsync_rate, config->acpsp.tdm_mode);
dai->number_configs = 1;
dai->current_config = 0;
@@ -1223,6 +1238,7 @@ static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
+ int ret;
/* Configures the DAI hardware format and inverted clocks */
sof_dai_set_format(hw_config, config);
@@ -1231,12 +1247,14 @@ static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_
memset(&config->acphs, 0, sizeof(config->acphs));
config->hdr.size = size;
- config->acphs.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
- config->acphs.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ ret = sof_update_ipc_object(scomp, &config->acphs, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
- dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d\n",
+ dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n",
config->dai_index, config->acphs.tdm_slots,
- config->acphs.fsync_rate);
+ config->acphs.fsync_rate, config->acphs.tdm_mode);
dai->number_configs = 1;
dai->current_config = 0;
@@ -1545,9 +1563,11 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
ret = sof_link_acp_bt_load(scomp, slink, config, dai);
break;
case SOF_DAI_AMD_SP:
+ case SOF_DAI_AMD_SP_VIRTUAL:
ret = sof_link_acp_sp_load(scomp, slink, config, dai);
break;
case SOF_DAI_AMD_HS:
+ case SOF_DAI_AMD_HS_VIRTUAL:
ret = sof_link_acp_hs_load(scomp, slink, config, dai);
break;
case SOF_DAI_AMD_DMIC:
@@ -2275,6 +2295,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
+ bool dyn_widgets = false;
int ret;
/*
@@ -2284,12 +2305,14 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
* topology loading the sound card unavailable to open PCMs.
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
- if (swidget->dynamic_pipeline_widget)
+ if (swidget->dynamic_pipeline_widget) {
+ dyn_widgets = true;
continue;
+ }
- /* Do not free widgets for static pipelines with FW ABI older than 3.19 */
+ /* Do not free widgets for static pipelines with FW older than SOF2.2 */
if (!verify && !swidget->dynamic_pipeline_widget &&
- v->abi_version < SOF_ABI_VER(3, 19, 0)) {
+ SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
swidget->use_count = 0;
swidget->complete = 0;
continue;
@@ -2303,9 +2326,11 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
/*
* Tear down all pipelines associated with PCMs that did not get suspended
* and unset the prepare flag so that they can be set up again during resume.
- * Skip this step for older firmware.
+ * Skip this step for older firmware unless topology has any
+ * dynamic pipeline (in which case the step is mandatory).
*/
- if (!verify && v->abi_version >= SOF_ABI_VER(3, 19, 0)) {
+ if (!verify && (dyn_widgets || SOF_FW_VER(v->major, v->minor, v->micro) >=
+ SOF_FW_VER(2, 2, 0))) {
ret = sof_tear_down_left_over_pipelines(sdev);
if (ret < 0) {
dev_err(sdev->dev, "failed to tear down paused pipelines\n");
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index b28af3a48b70..1fef4dcc0936 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -329,6 +329,8 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
struct snd_sof_dev *sdev = ipc->sdev;
int ret;
+ ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
+
ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
if (ret) {
@@ -338,8 +340,6 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
return ret;
}
- ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
-
/* now wait for completion */
return ipc3_wait_tx_done(ipc, reply_data);
}
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index e635ae515fa9..1321acc402fd 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -14,12 +14,15 @@
#include "sof-priv.h"
#include "ops.h"
-static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
+/* The module ID includes the id of the library it is part of at offset 12 */
+#define SOF_IPC4_MOD_LIB_ID_SHIFT 12
+
+static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct snd_sof_pdata *plat_data = sdev->pdata;
+ const struct firmware *fw = fw_lib->sof_fw.fw;
struct sof_man4_fw_binary_header *fw_header;
- const struct firmware *fw = plat_data->fw;
struct sof_ext_manifest4_hdr *ext_man_hdr;
struct sof_man4_module_config *fm_config;
struct sof_ipc4_fw_module *fw_module;
@@ -71,20 +74,20 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
return -EINVAL;
}
- dev_info(sdev->dev, "Loaded firmware version: %u.%u.%u.%u\n",
- fw_header->major_version, fw_header->minor_version,
+ dev_info(sdev->dev, "Loaded firmware library: %s, version: %u.%u.%u.%u\n",
+ fw_header->name, fw_header->major_version, fw_header->minor_version,
fw_header->hotfix_version, fw_header->build_version);
- dev_dbg(sdev->dev, "Firmware name: %s, header length: %u, module count: %u\n",
- fw_header->name, fw_header->len, fw_header->num_module_entries);
+ dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
+ fw_header->len, fw_header->num_module_entries);
- ipc4_data->fw_modules = devm_kmalloc_array(sdev->dev,
- fw_header->num_module_entries,
- sizeof(*fw_module), GFP_KERNEL);
- if (!ipc4_data->fw_modules)
+ fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
+ sizeof(*fw_module), GFP_KERNEL);
+ if (!fw_lib->modules)
return -ENOMEM;
- ipc4_data->num_fw_modules = fw_header->num_module_entries;
- fw_module = ipc4_data->fw_modules;
+ fw_lib->name = fw_header->name;
+ fw_lib->num_modules = fw_header->num_module_entries;
+ fw_module = fw_lib->modules;
fm_entry = (struct sof_man4_module *)((u8 *)fw_header + fw_header->len);
remaining -= fw_header->len;
@@ -134,13 +137,182 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
return ext_man_hdr->len;
}
+static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ ssize_t payload_offset;
+ int ret;
+
+ fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+ if (!fw_lib)
+ return -ENOMEM;
+
+ fw_lib->sof_fw.fw = sdev->basefw.fw;
+
+ payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+ if (payload_offset > 0) {
+ fw_lib->sof_fw.payload_offset = payload_offset;
+
+ /* basefw ID is 0 */
+ fw_lib->id = 0;
+ ret = xa_insert(&ipc4_data->fw_lib_xa, 0, fw_lib, GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ return payload_offset;
+}
+
+static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
+ unsigned long lib_id, const guid_t *uuid)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ const char *fw_filename;
+ ssize_t payload_offset;
+ int ret, i, err;
+
+ if (!sdev->pdata->fw_lib_prefix) {
+ dev_err(sdev->dev,
+ "Library loading is not supported due to not set library path\n");
+ return -EINVAL;
+ }
+
+ if (!ipc4_data->load_library) {
+ dev_err(sdev->dev, "Library loading is not supported on this platform\n");
+ return -EOPNOTSUPP;
+ }
+
+ fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+ if (!fw_lib)
+ return -ENOMEM;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
+ sdev->pdata->fw_lib_prefix, uuid);
+ if (!fw_filename) {
+ ret = -ENOMEM;
+ goto free_fw_lib;
+ }
+
+ ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename);
+ goto free_filename;
+ } else {
+ dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
+ }
+
+ payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+ if (payload_offset <= 0) {
+ if (!payload_offset)
+ ret = -EINVAL;
+ else
+ ret = payload_offset;
+
+ goto release;
+ }
+
+ fw_lib->sof_fw.payload_offset = payload_offset;
+ fw_lib->id = lib_id;
+
+ /* Fix up the module ID numbers within the library */
+ for (i = 0; i < fw_lib->num_modules; i++)
+ fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
+
+ /*
+ * Make sure that the DSP is booted and stays up while attempting the
+ * loading the library for the first time
+ */
+ ret = pm_runtime_resume_and_get(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
+ __func__, ret);
+ goto release;
+ }
+
+ ret = ipc4_data->load_library(sdev, fw_lib, false);
+
+ pm_runtime_mark_last_busy(sdev->dev);
+ err = pm_runtime_put_autosuspend(sdev->dev);
+ if (err < 0)
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
+ __func__, err);
+
+ if (ret)
+ goto release;
+
+ ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL);
+ if (unlikely(ret))
+ goto release;
+
+ kfree(fw_filename);
+
+ return 0;
+
+release:
+ release_firmware(fw_lib->sof_fw.fw);
+ /* Allocated within sof_ipc4_fw_parse_ext_man() */
+ devm_kfree(sdev->dev, fw_lib->modules);
+free_filename:
+ kfree(fw_filename);
+free_fw_lib:
+ devm_kfree(sdev->dev, fw_lib);
+
+ return ret;
+}
+
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+ const guid_t *uuid)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+ int i, ret;
+
+ if (guid_is_null(uuid))
+ return NULL;
+
+ xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+ for (i = 0; i < fw_lib->num_modules; i++) {
+ if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+ return &fw_lib->modules[i];
+ }
+ }
+
+ /*
+ * Do not attempt to load external library in case the maximum number of
+ * firmware libraries have been already loaded
+ */
+ if ((lib_id + 1) == ipc4_data->max_libs_count) {
+ dev_err(sdev->dev,
+ "%s: Maximum allowed number of libraries reached (%u)\n",
+ __func__, ipc4_data->max_libs_count);
+ return NULL;
+ }
+
+ /* The module cannot be found, try to load it as a library */
+ ret = sof_ipc4_load_library_by_uuid(sdev, lib_id + 1, uuid);
+ if (ret)
+ return NULL;
+
+ /* Look for the module in the newly loaded library, it should be available now */
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, lib_id) {
+ for (i = 0; i < fw_lib->num_modules; i++) {
+ if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+ return &fw_lib->modules[i];
+ }
+ }
+
+ return NULL;
+}
+
static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
u32 fw_hdr_offset = ipc4_data->manifest_fw_hdr_offset;
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct sof_man4_fw_binary_header *fw_header;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
struct sof_ext_manifest4_hdr *ext_man_hdr;
ext_man_hdr = (struct sof_ext_manifest4_hdr *)fw->data;
@@ -156,7 +328,7 @@ static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
return 0;
}
-static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
const struct sof_ipc_ops *iops = sdev->ipc->ops;
@@ -204,6 +376,24 @@ static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
trace_sof_ipc4_fw_config(sdev, "Trace log size", *tuple->value);
ipc4_data->mtrace_log_bytes = *tuple->value;
break;
+ case SOF_IPC4_FW_CFG_MAX_LIBS_COUNT:
+ trace_sof_ipc4_fw_config(sdev, "maximum number of libraries",
+ *tuple->value);
+ ipc4_data->max_libs_count = *tuple->value;
+ if (!ipc4_data->max_libs_count)
+ ipc4_data->max_libs_count = 1;
+ break;
+ case SOF_IPC4_FW_CFG_MAX_PPL_COUNT:
+ ipc4_data->max_num_pipelines = *tuple->value;
+ trace_sof_ipc4_fw_config(sdev, "Max PPL count %d",
+ ipc4_data->max_num_pipelines);
+ if (ipc4_data->max_num_pipelines <= 0) {
+ dev_err(sdev->dev, "Invalid max_num_pipelines %d",
+ ipc4_data->max_num_pipelines);
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
default:
break;
}
@@ -217,8 +407,26 @@ out:
return ret;
}
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+ int ret = 0;
+
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, 1) {
+ ret = ipc4_data->load_library(sdev, fw_lib, true);
+ if (ret) {
+ dev_err(sdev->dev, "%s: Failed to reload library: %s, %d\n",
+ __func__, fw_lib->name, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
.validate = sof_ipc4_validate_firmware,
- .parse_ext_manifest = sof_ipc4_fw_parse_ext_man,
- .query_fw_configuration = sof_ipc4_query_fw_configuration,
+ .parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
};
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 732872395980..96941bebc1f1 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -81,7 +81,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
/* first set the pipeline to PAUSED state */
if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0) {
dev_err(sdev->dev, "failed to pause pipeline %d\n",
@@ -96,7 +96,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
continue;
/* then set the final state */
- ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state);
+ ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id, state);
if (ret < 0) {
dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
state, swidget->pipeline_id);
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index e3b8484a2f1f..fc9efdce67e0 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -25,35 +25,63 @@ enum sof_ipc4_mtrace_type {
};
/**
+ * struct sof_ipc4_fw_module - IPC4 module info
+ * @sof_man4_module: Module info
+ * @m_ida: Module instance identifier
+ * @bss_size: Module object size
+ * @private: Module private data
+ */
+struct sof_ipc4_fw_module {
+ struct sof_man4_module man4_module_entry;
+ struct ida m_ida;
+ u32 bss_size;
+ void *private;
+};
+
+/**
+ * struct sof_ipc4_fw_library - IPC4 library information
+ * @sof_fw: SOF Firmware of the library
+ * @id: Library ID. 0 is reserved for basefw, external libraries must have unique
+ * ID number between 1 and (sof_ipc4_fw_data.max_libs_count - 1)
+ * Note: sof_ipc4_fw_data.max_libs_count == 1 implies that external libraries
+ * are not supported
+ * @num_modules : Number of FW modules in the library
+ * @modules: Array of FW modules
+ */
+struct sof_ipc4_fw_library {
+ struct sof_firmware sof_fw;
+ const char *name;
+ u32 id;
+ int num_modules;
+ struct sof_ipc4_fw_module *modules;
+};
+
+/**
* struct sof_ipc4_fw_data - IPC4-specific data
* @manifest_fw_hdr_offset: FW header offset in the manifest
- * @num_fw_modules : Number of modules in base FW
- * @fw_modules: Array of base FW modules
+ * @fw_lib_xa: XArray for firmware libraries, including basefw (ID = 0)
+ * Used to store the FW libraries and to manage the unique IDs of the
+ * libraries.
* @nhlt: NHLT table either from the BIOS or the topology manifest
* @mtrace_type: mtrace type supported on the booted platform
* @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
+ * @max_num_pipelines: max number of pipelines
+ * @max_libs_count: Maximum number of libraries support by the FW including the
+ * base firmware
+ *
+ * @load_library: Callback function for platform dependent library loading
*/
struct sof_ipc4_fw_data {
u32 manifest_fw_hdr_offset;
- int num_fw_modules;
- void *fw_modules;
+ struct xarray fw_lib_xa;
void *nhlt;
enum sof_ipc4_mtrace_type mtrace_type;
u32 mtrace_log_bytes;
-};
+ int max_num_pipelines;
+ u32 max_libs_count;
-/**
- * struct sof_ipc4_fw_module - IPC4 module info
- * @sof_man4_module : Module info
- * @m_ida: Module instance identifier
- * @bss_size: Module object size
- * @private: Module private data
- */
-struct sof_ipc4_fw_module {
- struct sof_man4_module man4_module_entry;
- struct ida m_ida;
- u32 bss_size;
- void *private;
+ int (*load_library)(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib, bool reload);
};
extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
@@ -64,4 +92,9 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
+
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+ const guid_t *uuid);
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index a81af5f73a4b..59f4d42f9011 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -20,6 +20,7 @@
#define SOF_IPC4_TPLG_ABI_SIZE 6
static DEFINE_IDA(alh_group_ida);
+static DEFINE_IDA(pipeline_ida);
static const struct sof_topology_token ipc4_sched_tokens[] = {
{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -280,7 +281,7 @@ static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *avai
available_fmt->out_audio_fmt = NULL;
}
-static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
+static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
{
kfree(swidget->private);
}
@@ -289,22 +290,11 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
- int i;
- if (!fw_modules) {
- dev_err(sdev->dev, "no fw_module information\n");
- return -EINVAL;
- }
+ swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
- /* set module info */
- for (i = 0; i < ipc4_data->num_fw_modules; i++) {
- if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
- swidget->module_info = &fw_modules[i];
- return 0;
- }
- }
+ if (swidget->module_info)
+ return 0;
dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
swidget->widget->name, &swidget->uuid);
@@ -328,8 +318,7 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_
msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
- msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
+ msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
@@ -636,7 +625,6 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
swidget->private = pipeline;
pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
- pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -1447,6 +1435,8 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
+ struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_ipc4_pipeline *pipeline;
struct sof_ipc4_msg *msg;
void *ipc_data = NULL;
@@ -1462,6 +1452,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg = &pipeline->msg;
msg->primary |= pipeline->mem_usage;
+
+ swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
+ GFP_KERNEL);
+ if (swidget->instance_id < 0) {
+ dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
+ swidget->widget->name, swidget->instance_id);
+ return swidget->instance_id;
+ }
+ msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
+ msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
break;
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
@@ -1535,6 +1535,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
msg->extension |= ipc_size >> 2;
+
+ msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
+ msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
}
dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
@@ -1550,6 +1553,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
ida_free(&fw_module->m_ida, swidget->instance_id);
+ } else {
+ ida_free(&pipeline_ida, swidget->instance_id);
}
}
@@ -1567,7 +1572,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
struct sof_ipc4_msg msg = {{ 0 }};
u32 header;
- header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+ header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -1581,6 +1586,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+ ida_free(&pipeline_ida, swidget->instance_id);
} else {
ida_free(&fw_module->m_ida, swidget->instance_id);
}
@@ -1588,6 +1594,88 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
return ret;
}
+static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
+ struct snd_sof_widget *sink_widget, bool pin_type)
+{
+ struct snd_sof_widget *current_swidget;
+ struct snd_soc_component *scomp;
+ struct ida *queue_ida;
+ const char *buddy_name;
+ char **pin_binding;
+ u32 num_pins;
+ int i;
+
+ if (pin_type == SOF_PIN_TYPE_SOURCE) {
+ current_swidget = src_widget;
+ pin_binding = src_widget->src_pin_binding;
+ queue_ida = &src_widget->src_queue_ida;
+ num_pins = src_widget->num_source_pins;
+ buddy_name = sink_widget->widget->name;
+ } else {
+ current_swidget = sink_widget;
+ pin_binding = sink_widget->sink_pin_binding;
+ queue_ida = &sink_widget->sink_queue_ida;
+ num_pins = sink_widget->num_sink_pins;
+ buddy_name = src_widget->widget->name;
+ }
+
+ scomp = current_swidget->scomp;
+
+ if (num_pins < 1) {
+ dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
+ (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
+ num_pins, current_swidget->widget->name);
+ return -EINVAL;
+ }
+
+ /* If there is only one sink/source pin, queue id must be 0 */
+ if (num_pins == 1)
+ return 0;
+
+ /* Allocate queue ID from pin binding array if it is defined in topology. */
+ if (pin_binding) {
+ for (i = 0; i < num_pins; i++) {
+ if (!strcmp(pin_binding[i], buddy_name))
+ return i;
+ }
+ /*
+ * Fail if no queue ID found from pin binding array, so that we don't
+ * mixed use pin binding array and ida for queue ID allocation.
+ */
+ dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
+ (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
+ current_swidget->widget->name);
+ return -EINVAL;
+ }
+
+ /* If no pin binding array specified in topology, use ida to allocate one */
+ return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
+}
+
+static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
+ bool pin_type)
+{
+ struct ida *queue_ida;
+ char **pin_binding;
+ int num_pins;
+
+ if (pin_type == SOF_PIN_TYPE_SOURCE) {
+ pin_binding = swidget->src_pin_binding;
+ queue_ida = &swidget->src_queue_ida;
+ num_pins = swidget->num_source_pins;
+ } else {
+ pin_binding = swidget->sink_pin_binding;
+ queue_ida = &swidget->sink_queue_ida;
+ num_pins = swidget->num_sink_pins;
+ }
+
+ /* Nothing to free if queue ID is not allocated with ida. */
+ if (num_pins == 1 || pin_binding)
+ return;
+
+ ida_free(queue_ida, queue_id);
+}
+
static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
{
struct snd_sof_widget *src_widget = sroute->src_widget;
@@ -1596,12 +1684,29 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
struct sof_ipc4_msg msg = {{ 0 }};
u32 header, extension;
- int src_queue = 0;
- int dst_queue = 0;
int ret;
- dev_dbg(sdev->dev, "bind %s -> %s\n",
- src_widget->widget->name, sink_widget->widget->name);
+ sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
+ SOF_PIN_TYPE_SOURCE);
+ if (sroute->src_queue_id < 0) {
+ dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
+ src_widget->widget->name);
+ return sroute->src_queue_id;
+ }
+
+ sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
+ SOF_PIN_TYPE_SINK);
+ if (sroute->dst_queue_id < 0) {
+ dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
+ sink_widget->widget->name);
+ sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
+ SOF_PIN_TYPE_SOURCE);
+ return sroute->dst_queue_id;
+ }
+
+ dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
+ src_widget->widget->name, sroute->src_queue_id,
+ sink_widget->widget->name, sroute->dst_queue_id);
header = src_fw_module->man4_module_entry.id;
header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
@@ -1611,17 +1716,23 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
extension = sink_fw_module->man4_module_entry.id;
extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
- extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
+ extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
msg.primary = header;
msg.extension = extension;
ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
- if (ret < 0)
+ if (ret < 0) {
dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
__func__, src_widget->widget->name, sink_widget->widget->name);
+ sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
+ SOF_PIN_TYPE_SOURCE);
+ sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id,
+ SOF_PIN_TYPE_SINK);
+ }
+
return ret;
}
@@ -1633,12 +1744,11 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
struct sof_ipc4_msg msg = {{ 0 }};
u32 header, extension;
- int src_queue = 0;
- int dst_queue = 0;
int ret;
- dev_dbg(sdev->dev, "unbind modules %s -> %s\n",
- src_widget->widget->name, sink_widget->widget->name);
+ dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
+ src_widget->widget->name, sroute->src_queue_id,
+ sink_widget->widget->name, sroute->dst_queue_id);
header = src_fw_module->man4_module_entry.id;
header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
@@ -1648,8 +1758,8 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
extension = sink_fw_module->man4_module_entry.id;
extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
- extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
+ extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
msg.primary = header;
msg.extension = extension;
@@ -1659,6 +1769,9 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
src_widget->widget->name, sink_widget->widget->name);
+ sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
+ sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
+
return ret;
}
@@ -1824,6 +1937,39 @@ static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
return -EINVAL;
}
+static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+{
+ struct snd_sof_pcm *spcm;
+ int dir, ret;
+
+ /*
+ * This function is called during system suspend, we need to make sure
+ * that all streams have been freed up.
+ * Freeing might have been skipped when xrun happened just at the start
+ * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
+ * stream. This will call sof_pcm_stream_free() with
+ * free_widget_list = false which will leave the kernel and firmware out
+ * of sync during suspend/resume.
+ *
+ * This will also make sure that paused streams handled correctly.
+ */
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ for_each_pcm_streams(dir) {
+ struct snd_pcm_substream *substream = spcm->stream[dir].substream;
+
+ if (!substream || !substream->runtime)
+ continue;
+
+ if (spcm->stream[dir].list) {
+ ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
static enum sof_tokens host_token_list[] = {
SOF_COMP_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1895,7 +2041,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
sof_ipc4_prepare_copier_module,
sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
+ [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
+ sof_ipc4_widget_free_comp_pipeline,
pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
NULL, NULL},
[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
@@ -1924,4 +2071,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
.dai_config = sof_ipc4_dai_config,
.parse_manifest = sof_ipc4_parse_manifest,
.dai_get_clk = sof_ipc4_dai_get_clk,
+ .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
};
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 6eaa18e27e5a..74cd7e956019 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -8,6 +8,7 @@
// Authors: Rander Wang <rander.wang@linux.intel.com>
// Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
//
+#include <linux/firmware.h>
#include <sound/sof/header.h>
#include <sound/sof/ipc4/header.h>
#include "sof-priv.h"
@@ -342,6 +343,8 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size)
return -EINVAL;
+ sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);
+
ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
if (ret) {
dev_err_ratelimited(sdev->dev,
@@ -350,8 +353,6 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
return ret;
}
- sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);
-
/* now wait for completion */
return ipc4_wait_tx_done(ipc, reply_data);
}
@@ -657,7 +658,47 @@ static const struct sof_ipc_pm_ops ipc4_pm_ops = {
.set_core_state = sof_ipc4_set_core_state,
};
+static int sof_ipc4_init(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ xa_init_flags(&ipc4_data->fw_lib_xa, XA_FLAGS_ALLOC);
+
+ return 0;
+}
+
+static void sof_ipc4_exit(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+
+ xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+ /*
+ * The basefw (ID == 0) is handled by generic code, it is not
+ * loaded by IPC4 code.
+ */
+ if (lib_id != 0)
+ release_firmware(fw_lib->sof_fw.fw);
+
+ fw_lib->sof_fw.fw = NULL;
+ }
+
+ xa_destroy(&ipc4_data->fw_lib_xa);
+}
+
+static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
+{
+ if (sdev->first_boot)
+ return sof_ipc4_query_fw_configuration(sdev);
+
+ return sof_ipc4_reload_fw_libraries(sdev);
+}
+
const struct sof_ipc_ops ipc4_ops = {
+ .init = sof_ipc4_init,
+ .exit = sof_ipc4_exit,
+ .post_fw_boot = sof_ipc4_post_boot,
.tx_msg = sof_ipc4_tx_msg,
.rx_msg = sof_ipc4_rx_msg,
.set_get_data = sof_ipc4_set_get_data,
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index 5f51d936b306..81d202e5ce53 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -22,7 +22,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
int ret;
/* Don't request firmware again if firmware is already requested */
- if (plat_data->fw)
+ if (sdev->basefw.fw)
return 0;
fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
@@ -31,7 +31,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
if (!fw_filename)
return -ENOMEM;
- ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
+ ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
@@ -48,7 +48,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
if (ext_man_size > 0) {
/* when no error occurred, drop extended manifest */
- plat_data->fw_offset = ext_man_size;
+ sdev->basefw.payload_offset = ext_man_size;
} else if (!ext_man_size) {
/* No extended manifest, so nothing to skip during FW load */
dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
@@ -67,7 +67,6 @@ EXPORT_SYMBOL(snd_sof_load_firmware_raw);
int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
int ret;
ret = snd_sof_load_firmware_raw(sdev);
@@ -100,8 +99,8 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
return 0;
error:
- release_firmware(plat_data->fw);
- plat_data->fw = NULL;
+ release_firmware(sdev->basefw.fw);
+ sdev->basefw.fw = NULL;
return ret;
}
@@ -165,6 +164,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
return -EIO; /* FW boots but fw_ready op failed */
+ dev_dbg(sdev->dev, "firmware boot complete\n");
+ sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
+
/* perform post fw run operations */
ret = snd_sof_dsp_post_fw_run(sdev);
if (ret < 0) {
@@ -172,11 +174,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
return ret;
}
- dev_dbg(sdev->dev, "firmware boot complete\n");
- sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
-
- if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
- return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
+ if (sdev->ipc->ops->post_fw_boot)
+ return sdev->ipc->ops->post_fw_boot(sdev);
return 0;
}
@@ -185,7 +184,7 @@ EXPORT_SYMBOL(snd_sof_run_firmware);
void snd_sof_fw_unload(struct snd_sof_dev *sdev)
{
/* TODO: support module unloading at runtime */
- release_firmware(sdev->pdata->fw);
- sdev->pdata->fw = NULL;
+ release_firmware(sdev->basefw.fw);
+ sdev->basefw.fw = NULL;
}
EXPORT_SYMBOL(snd_sof_fw_unload);
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index 181189e00e02..79da25725987 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -430,6 +430,11 @@ static int mt8186_dsp_remove(struct snd_sof_dev *sdev)
return 0;
}
+static int mt8186_dsp_shutdown(struct snd_sof_dev *sdev)
+{
+ return snd_sof_suspend(sdev->dev);
+}
+
static int mt8186_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
mt8186_sof_hifixdsp_shutdown(sdev);
@@ -538,6 +543,7 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = {
/* probe and remove */
.probe = mt8186_dsp_probe,
.remove = mt8186_dsp_remove,
+ .shutdown = mt8186_dsp_shutdown,
/* DSP core boot */
.run = mt8186_run,
@@ -629,6 +635,7 @@ MODULE_DEVICE_TABLE(of, sof_of_mt8186_ids);
static struct platform_driver snd_sof_of_mt8186_driver = {
.probe = sof_of_probe,
.remove = sof_of_remove,
+ .shutdown = sof_of_shutdown,
.driver = {
.name = "sof-audio-of-mt8186",
.pm = &sof_of_pm,
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index 55d43adb6a29..c52752250565 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -302,26 +302,40 @@ static inline int snd_sof_debugfs_add_region_item(struct snd_sof_dev *sdev,
}
/* register IO */
+static inline void snd_sof_dsp_write8(struct snd_sof_dev *sdev, u32 bar,
+ u32 offset, u8 value)
+{
+ if (sof_ops(sdev)->write8)
+ sof_ops(sdev)->write8(sdev, sdev->bar[bar] + offset, value);
+ else
+ writeb(value, sdev->bar[bar] + offset);
+}
+
static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar,
u32 offset, u32 value)
{
- if (sof_ops(sdev)->write) {
+ if (sof_ops(sdev)->write)
sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value);
- return;
- }
-
- dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
+ else
+ writel(value, sdev->bar[bar] + offset);
}
static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar,
u32 offset, u64 value)
{
- if (sof_ops(sdev)->write64) {
+ if (sof_ops(sdev)->write64)
sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value);
- return;
- }
+ else
+ writeq(value, sdev->bar[bar] + offset);
+}
- dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
+static inline u8 snd_sof_dsp_read8(struct snd_sof_dev *sdev, u32 bar,
+ u32 offset)
+{
+ if (sof_ops(sdev)->read8)
+ return sof_ops(sdev)->read8(sdev, sdev->bar[bar] + offset);
+ else
+ return readb(sdev->bar[bar] + offset);
}
static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
@@ -329,9 +343,8 @@ static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
{
if (sof_ops(sdev)->read)
return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset);
-
- dev_err(sdev->dev, "error: %s not defined\n", __func__);
- return -ENOTSUPP;
+ else
+ return readl(sdev->bar[bar] + offset);
}
static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
@@ -339,9 +352,19 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
{
if (sof_ops(sdev)->read64)
return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset);
+ else
+ return readq(sdev->bar[bar] + offset);
+}
- dev_err(sdev->dev, "error: %s not defined\n", __func__);
- return -ENOTSUPP;
+static inline void snd_sof_dsp_update8(struct snd_sof_dev *sdev, u32 bar,
+ u32 offset, u8 value, u8 mask)
+{
+ u8 reg;
+
+ reg = snd_sof_dsp_read8(sdev, bar, offset);
+ reg &= ~mask;
+ reg |= value;
+ snd_sof_dsp_write8(sdev, bar, offset, reg);
}
/* block IO */
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 62092e2d609c..7306a2649857 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -826,6 +826,10 @@ int sof_machine_check(struct snd_sof_dev *sdev)
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
const struct snd_sof_of_mach *of_mach;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto nocodec;
+
/* find machine */
mach = snd_sof_machine_select(sdev);
if (mach) {
@@ -848,6 +852,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
dev_warn(sdev->dev, "Force to use nocodec mode\n");
}
+nocodec:
/* select nocodec mode */
dev_warn(sdev->dev, "Using nocodec machine driver\n");
mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 4284ea2f3a1f..29cf951e3526 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -23,6 +23,17 @@
#define SOF_AUDIO_PCM_DRV_NAME "sof-audio-component"
+/*
+ * The ipc4 firmware only supports up to 8 sink or source pins
+ * per widget, because only 3 bits are used for queue(pin) ID
+ * in ipc4 protocol.
+ */
+#define SOF_WIDGET_MAX_NUM_PINS 8
+
+/* The type of a widget pin is either sink or source */
+#define SOF_PIN_TYPE_SINK 0
+#define SOF_PIN_TYPE_SOURCE 1
+
/* max number of FE PCMs before BEs */
#define SOF_BE_PCM_BASE 16
@@ -237,6 +248,7 @@ enum sof_tokens {
SOF_COPIER_FORMAT_TOKENS,
SOF_GAIN_TOKENS,
SOF_ACPDMIC_TOKENS,
+ SOF_ACPI2S_TOKENS,
/* this should be the last */
SOF_TOKEN_COUNT,
@@ -387,6 +399,33 @@ struct snd_sof_widget {
int num_tuples;
struct snd_sof_tuple *tuples;
+ /*
+ * The allowed range for num_sink/source_pins is [0, SOF_WIDGET_MAX_NUM_PINS].
+ * Widgets may have zero sink or source pins, for example the tone widget has
+ * zero sink pins.
+ */
+ u32 num_sink_pins;
+ u32 num_source_pins;
+
+ /*
+ * The sink/source pin binding array, it takes the form of
+ * [widget_name_connected_to_pin0, widget_name_connected_to_pin1, ...],
+ * with the index as the queue ID.
+ *
+ * The array is used for special pin binding. Note that even if there
+ * is only one sink/source pin requires special pin binding, pin binding
+ * should be defined for all sink/source pins in topology, for pin(s) that
+ * are not used, give the value "NotConnected".
+ *
+ * If pin binding is not defined in topology, nothing to parse in the kernel,
+ * sink_pin_binding and src_pin_binding shall be NULL.
+ */
+ char **sink_pin_binding;
+ char **src_pin_binding;
+
+ struct ida src_queue_ida;
+ struct ida sink_queue_ida;
+
void *private; /* core does not touch this */
};
@@ -400,6 +439,9 @@ struct snd_sof_route {
struct snd_sof_widget *sink_widget;
bool setup;
+ int src_queue_id;
+ int dst_queue_id;
+
void *private;
};
@@ -531,6 +573,7 @@ int get_token_u16(void *elem, void *object, u32 offset);
int get_token_comp_format(void *elem, void *object, u32 offset);
int get_token_dai_type(void *elem, void *object, u32 offset);
int get_token_uuid(void *elem, void *object, u32 offset);
+int get_token_string(void *elem, void *object, u32 offset);
int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id,
struct snd_sof_tuple *tuples, int num_tuples,
size_t object_size, int token_instance_num);
diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c
new file mode 100644
index 000000000000..ef768db5f04d
--- /dev/null
+++ b/sound/soc/sof/sof-client-probes-ipc3.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2019-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+// Code moved to this file by:
+// Jyri Sarha <jyri.sarha@intel.com>
+//
+
+#include <linux/stddef.h>
+#include <sound/soc.h>
+#include <sound/sof/header.h>
+#include "sof-client.h"
+#include "sof-client-probes.h"
+
+struct sof_probe_dma {
+ unsigned int stream_tag;
+ unsigned int dma_buffer_size;
+} __packed;
+
+struct sof_ipc_probe_dma_add_params {
+ struct sof_ipc_cmd_hdr hdr;
+ unsigned int num_elems;
+ struct sof_probe_dma dma[];
+} __packed;
+
+struct sof_ipc_probe_info_params {
+ struct sof_ipc_reply rhdr;
+ unsigned int num_elems;
+ union {
+ DECLARE_FLEX_ARRAY(struct sof_probe_dma, dma);
+ DECLARE_FLEX_ARRAY(struct sof_probe_point_desc, desc);
+ };
+} __packed;
+
+struct sof_ipc_probe_point_add_params {
+ struct sof_ipc_cmd_hdr hdr;
+ unsigned int num_elems;
+ struct sof_probe_point_desc desc[];
+} __packed;
+
+struct sof_ipc_probe_point_remove_params {
+ struct sof_ipc_cmd_hdr hdr;
+ unsigned int num_elems;
+ unsigned int buffer_id[];
+} __packed;
+
+/**
+ * ipc3_probes_init - initialize data probing
+ * @cdev: SOF client device
+ * @stream_tag: Extractor stream tag
+ * @buffer_size: DMA buffer size to set for extractor
+ *
+ * Host chooses whether extraction is supported or not by providing
+ * valid stream tag to DSP. Once specified, stream described by that
+ * tag will be tied to DSP for extraction for the entire lifetime of
+ * probe.
+ *
+ * Probing is initialized only once and each INIT request must be
+ * matched by DEINIT call.
+ */
+static int ipc3_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
+ size_t buffer_size)
+{
+ struct sof_ipc_probe_dma_add_params *msg;
+ size_t size = struct_size(msg, dma, 1);
+ struct sof_ipc_reply reply;
+ int ret;
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ msg->hdr.size = size;
+ msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
+ msg->num_elems = 1;
+ msg->dma[0].stream_tag = stream_tag;
+ msg->dma[0].dma_buffer_size = buffer_size;
+
+ ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+ kfree(msg);
+ return ret;
+}
+
+/**
+ * ipc3_probes_deinit - cleanup after data probing
+ * @cdev: SOF client device
+ *
+ * Host sends DEINIT request to free previously initialized probe
+ * on DSP side once it is no longer needed. DEINIT only when there
+ * are no probes connected and with all injectors detached.
+ */
+static int ipc3_probes_deinit(struct sof_client_dev *cdev)
+{
+ struct sof_ipc_cmd_hdr msg;
+ struct sof_ipc_reply reply;
+
+ msg.size = sizeof(msg);
+ msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
+
+ return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
+}
+
+static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
+ void **params, size_t *num_params)
+{
+ size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
+ struct sof_ipc_probe_info_params msg = {{{0}}};
+ struct sof_ipc_probe_info_params *reply;
+ size_t bytes;
+ int ret;
+
+ *params = NULL;
+ *num_params = 0;
+
+ reply = kzalloc(max_msg_size, GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+ msg.rhdr.hdr.size = sizeof(msg);
+ msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
+
+ ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
+ if (ret < 0 || reply->rhdr.error < 0)
+ goto exit;
+
+ if (!reply->num_elems)
+ goto exit;
+
+ if (cmd == SOF_IPC_PROBE_DMA_INFO)
+ bytes = sizeof(reply->dma[0]);
+ else
+ bytes = sizeof(reply->desc[0]);
+ bytes *= reply->num_elems;
+ *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
+ if (!*params) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ *num_params = reply->num_elems;
+
+exit:
+ kfree(reply);
+ return ret;
+}
+
+/**
+ * ipc3_probes_points_info - retrieve list of active probe points
+ * @cdev: SOF client device
+ * @desc: Returned list of active probes
+ * @num_desc: Returned count of active probes
+ *
+ * Host sends PROBE_POINT_INFO request to obtain list of active probe
+ * points, valid for disconnection when given probe is no longer
+ * required.
+ */
+static int ipc3_probes_points_info(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc **desc,
+ size_t *num_desc)
+{
+ return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
+ (void **)desc, num_desc);
+}
+
+/**
+ * ipc3_probes_points_add - connect specified probes
+ * @cdev: SOF client device
+ * @desc: List of probe points to connect
+ * @num_desc: Number of elements in @desc
+ *
+ * Dynamically connects to provided set of endpoints. Immediately
+ * after connection is established, host must be prepared to
+ * transfer data from or to target stream given the probing purpose.
+ *
+ * Each probe point should be removed using PROBE_POINT_REMOVE
+ * request when no longer needed.
+ */
+static int ipc3_probes_points_add(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc *desc,
+ size_t num_desc)
+{
+ struct sof_ipc_probe_point_add_params *msg;
+ size_t size = struct_size(msg, desc, num_desc);
+ struct sof_ipc_reply reply;
+ int ret;
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ msg->hdr.size = size;
+ msg->num_elems = num_desc;
+ msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
+ memcpy(&msg->desc[0], desc, size - sizeof(*msg));
+
+ ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+ kfree(msg);
+ return ret;
+}
+
+/**
+ * ipc3_probes_points_remove - disconnect specified probes
+ * @cdev: SOF client device
+ * @buffer_id: List of probe points to disconnect
+ * @num_buffer_id: Number of elements in @desc
+ *
+ * Removes previously connected probes from list of active probe
+ * points and frees all resources on DSP side.
+ */
+static int ipc3_probes_points_remove(struct sof_client_dev *cdev,
+ unsigned int *buffer_id,
+ size_t num_buffer_id)
+{
+ struct sof_ipc_probe_point_remove_params *msg;
+ size_t size = struct_size(msg, buffer_id, num_buffer_id);
+ struct sof_ipc_reply reply;
+ int ret;
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ msg->hdr.size = size;
+ msg->num_elems = num_buffer_id;
+ msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
+ memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
+
+ ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+ kfree(msg);
+ return ret;
+}
+
+const struct sof_probes_ipc_ops ipc3_probe_ops = {
+ .init = ipc3_probes_init,
+ .deinit = ipc3_probes_deinit,
+ .points_info = ipc3_probes_points_info,
+ .points_add = ipc3_probes_points_add,
+ .points_remove = ipc3_probes_points_remove,
+};
diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c
new file mode 100644
index 000000000000..66fa7c2f390a
--- /dev/null
+++ b/sound/soc/sof/sof-client-probes-ipc4.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2019-2022 Intel Corporation. All rights reserved.
+//
+// Author: Jyri Sarha <jyri.sarha@intel.com>
+//
+
+#include <sound/soc.h>
+#include <sound/sof/ipc4/header.h>
+#include <uapi/sound/sof/header.h>
+#include "sof-priv.h"
+#include "ipc4-priv.h"
+#include "sof-client.h"
+#include "sof-client-probes.h"
+
+enum sof_ipc4_dma_type {
+ SOF_IPC4_DMA_HDA_HOST_OUTPUT = 0,
+ SOF_IPC4_DMA_HDA_HOST_INPUT = 1,
+ SOF_IPC4_DMA_HDA_LINK_OUTPUT = 8,
+ SOF_IPC4_DMA_HDA_LINK_INPUT = 9,
+ SOF_IPC4_DMA_DMIC_LINK_INPUT = 11,
+ SOF_IPC4_DMA_I2S_LINK_OUTPUT = 12,
+ SOF_IPC4_DMA_I2S_LINK_INPUT = 13,
+};
+
+enum sof_ipc4_probe_runtime_param {
+ SOF_IPC4_PROBE_INJECTION_DMA = 1,
+ SOF_IPC4_PROBE_INJECTION_DMA_DETACH,
+ SOF_IPC4_PROBE_POINTS,
+ SOF_IPC4_PROBE_POINTS_DISCONNECT,
+};
+
+struct sof_ipc4_probe_gtw_cfg {
+ u32 node_id;
+ u32 dma_buffer_size;
+} __packed __aligned(4);
+
+#define SOF_IPC4_PROBE_NODE_ID_INDEX(x) ((x) & GENMASK(7, 0))
+#define SOF_IPC4_PROBE_NODE_ID_TYPE(x) (((x) << 8) & GENMASK(12, 8))
+
+struct sof_ipc4_probe_cfg {
+ struct sof_ipc4_base_module_cfg base;
+ struct sof_ipc4_probe_gtw_cfg gtw_cfg;
+} __packed __aligned(4);
+
+enum sof_ipc4_probe_type {
+ SOF_IPC4_PROBE_TYPE_INPUT = 0,
+ SOF_IPC4_PROBE_TYPE_OUTPUT,
+ SOF_IPC4_PROBE_TYPE_INTERNAL
+};
+
+struct sof_ipc4_probe_point {
+ u32 point_id;
+ u32 purpose;
+ u32 stream_tag;
+} __packed __aligned(4);
+
+#define INVALID_PIPELINE_ID 0xFF
+
+/**
+ * sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module
+ * @cdev: SOF client device
+ * @return: Pointer to IPC4 probe module info
+ *
+ * Look up the IPC4 probe module info based on the hard coded uuid and
+ * store the value for the future calls.
+ */
+static struct sof_man4_module *sof_ipc4_probe_get_module_info(struct sof_client_dev *cdev)
+{
+ struct sof_probes_priv *priv = cdev->data;
+ struct device *dev = &cdev->auxdev.dev;
+ static const guid_t probe_uuid =
+ GUID_INIT(0x7CAD0808, 0xAB10, 0xCD23,
+ 0xEF, 0x45, 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF);
+
+ if (!priv->ipc_priv) {
+ struct sof_ipc4_fw_module *fw_module =
+ sof_client_ipc4_find_module(cdev, &probe_uuid);
+
+ if (!fw_module) {
+ dev_err(dev, "%s: no matching uuid found", __func__);
+ return NULL;
+ }
+
+ priv->ipc_priv = &fw_module->man4_module_entry;
+ }
+
+ return (struct sof_man4_module *)priv->ipc_priv;
+}
+
+/**
+ * ipc4_probes_init - initialize data probing
+ * @cdev: SOF client device
+ * @stream_tag: Extractor stream tag
+ * @buffer_size: DMA buffer size to set for extractor
+ * @return: 0 on success, negative error code on error
+ *
+ * Host chooses whether extraction is supported or not by providing
+ * valid stream tag to DSP. Once specified, stream described by that
+ * tag will be tied to DSP for extraction for the entire lifetime of
+ * probe.
+ *
+ * Probing is initialized only once and each INIT request must be
+ * matched by DEINIT call.
+ */
+static int ipc4_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
+ size_t buffer_size)
+{
+ struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+ struct sof_ipc4_msg msg;
+ struct sof_ipc4_probe_cfg cfg;
+
+ if (!mentry)
+ return -ENODEV;
+
+ memset(&cfg, '\0', sizeof(cfg));
+ cfg.gtw_cfg.node_id = SOF_IPC4_PROBE_NODE_ID_INDEX(stream_tag - 1) |
+ SOF_IPC4_PROBE_NODE_ID_TYPE(SOF_IPC4_DMA_HDA_HOST_INPUT);
+
+ cfg.gtw_cfg.dma_buffer_size = buffer_size;
+
+ msg.primary = mentry->id;
+ msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
+ msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
+
+ msg.data_size = sizeof(cfg);
+ msg.data_ptr = &cfg;
+
+ return sof_client_ipc_tx_message(cdev, &msg, NULL, 0);
+}
+
+/**
+ * ipc4_probes_deinit - cleanup after data probing
+ * @cdev: SOF client device
+ * @return: 0 on success, negative error code on error
+ *
+ * Host sends DEINIT request to free previously initialized probe
+ * on DSP side once it is no longer needed. DEINIT only when there
+ * are no probes connected and with all injectors detached.
+ */
+static int ipc4_probes_deinit(struct sof_client_dev *cdev)
+{
+ struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+ struct sof_ipc4_msg msg;
+
+ msg.primary = mentry->id;
+ msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
+ msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
+
+ msg.data_size = 0;
+ msg.data_ptr = NULL;
+
+ return sof_client_ipc_tx_message(cdev, &msg, NULL, 0);
+}
+
+/**
+ * ipc4_probes_points_info - retrieve list of active probe points
+ * @cdev: SOF client device
+ * @desc: Returned list of active probes
+ * @num_desc: Returned count of active probes
+ * @return: 0 on success, negative error code on error
+ *
+ * Dummy implementation returning empty list of probes.
+ */
+static int ipc4_probes_points_info(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc **desc,
+ size_t *num_desc)
+{
+ /* TODO: Firmware side implementation needed first */
+ *desc = NULL;
+ *num_desc = 0;
+ return 0;
+}
+
+/**
+ * ipc4_probes_points_add - connect specified probes
+ * @cdev: SOF client device
+ * @desc: List of probe points to connect
+ * @num_desc: Number of elements in @desc
+ * @return: 0 on success, negative error code on error
+ *
+ * Translates the generic probe point presentation to an IPC4
+ * message to dynamically connect the provided set of endpoints.
+ */
+static int ipc4_probes_points_add(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc *desc,
+ size_t num_desc)
+{
+ struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+ struct sof_ipc4_probe_point *points;
+ struct sof_ipc4_msg msg;
+ int i, ret;
+
+ /* The sof_probe_point_desc and sof_ipc4_probe_point structs
+ * are of same size and even the integers are the same in the
+ * same order, and similar meaning, but since there is no
+ * performance issue I wrote the conversion explicitly open for
+ * future development.
+ */
+ points = kcalloc(num_desc, sizeof(*points), GFP_KERNEL);
+ if (!points)
+ return -ENOMEM;
+
+ for (i = 0; i < num_desc; i++) {
+ points[i].point_id = desc[i].buffer_id;
+ points[i].purpose = desc[i].purpose;
+ points[i].stream_tag = desc[i].stream_tag;
+ }
+
+ msg.primary = mentry->id;
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS);
+
+ msg.data_size = sizeof(*points) * num_desc;
+ msg.data_ptr = points;
+
+ ret = sof_client_ipc_set_get_data(cdev, &msg, true);
+
+ kfree(points);
+
+ return ret;
+}
+
+/**
+ * ipc4_probes_points_remove - disconnect specified probes
+ * @cdev: SOF client device
+ * @buffer_id: List of probe points to disconnect
+ * @num_buffer_id: Number of elements in @desc
+ * @return: 0 on success, negative error code on error
+ *
+ * Converts the generic buffer_id to IPC4 probe_point_id and remove
+ * the probe points with an IPC4 for message.
+ */
+static int ipc4_probes_points_remove(struct sof_client_dev *cdev,
+ unsigned int *buffer_id, size_t num_buffer_id)
+{
+ struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+ struct sof_ipc4_msg msg;
+ u32 *probe_point_ids;
+ int i, ret;
+
+ probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids),
+ GFP_KERNEL);
+ if (!probe_point_ids)
+ return -ENOMEM;
+
+ for (i = 0; i < num_buffer_id; i++)
+ probe_point_ids[i] = buffer_id[i];
+
+ msg.primary = mentry->id;
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg.extension =
+ SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS_DISCONNECT);
+
+ msg.data_size = num_buffer_id * sizeof(*probe_point_ids);
+ msg.data_ptr = probe_point_ids;
+
+ ret = sof_client_ipc_set_get_data(cdev, &msg, true);
+
+ kfree(probe_point_ids);
+
+ return ret;
+}
+
+const struct sof_probes_ipc_ops ipc4_probe_ops = {
+ .init = ipc4_probes_init,
+ .deinit = ipc4_probes_deinit,
+ .points_info = ipc4_probes_points_info,
+ .points_add = ipc4_probes_points_add,
+ .points_remove = ipc4_probes_points_remove,
+};
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index ddeabbb5580e..fff126808bc0 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/string_helpers.h>
+#include <linux/stddef.h>
#include <sound/soc.h>
#include <sound/sof/header.h>
@@ -29,233 +30,6 @@ static bool __read_mostly sof_probes_enabled;
module_param_named(enable, sof_probes_enabled, bool, 0444);
MODULE_PARM_DESC(enable, "Enable SOF probes support");
-struct sof_probes_priv {
- struct dentry *dfs_points;
- struct dentry *dfs_points_remove;
- u32 extractor_stream_tag;
- struct snd_soc_card card;
-
- const struct sof_probes_host_ops *host_ops;
-};
-
-struct sof_probe_point_desc {
- unsigned int buffer_id;
- unsigned int purpose;
- unsigned int stream_tag;
-} __packed;
-
-struct sof_probe_dma {
- unsigned int stream_tag;
- unsigned int dma_buffer_size;
-} __packed;
-
-struct sof_ipc_probe_dma_add_params {
- struct sof_ipc_cmd_hdr hdr;
- unsigned int num_elems;
- struct sof_probe_dma dma[];
-} __packed;
-
-struct sof_ipc_probe_info_params {
- struct sof_ipc_reply rhdr;
- unsigned int num_elems;
- union {
- struct sof_probe_dma dma[0];
- struct sof_probe_point_desc desc[0];
- };
-} __packed;
-
-struct sof_ipc_probe_point_add_params {
- struct sof_ipc_cmd_hdr hdr;
- unsigned int num_elems;
- struct sof_probe_point_desc desc[];
-} __packed;
-
-struct sof_ipc_probe_point_remove_params {
- struct sof_ipc_cmd_hdr hdr;
- unsigned int num_elems;
- unsigned int buffer_id[];
-} __packed;
-
-/**
- * sof_probes_init - initialize data probing
- * @cdev: SOF client device
- * @stream_tag: Extractor stream tag
- * @buffer_size: DMA buffer size to set for extractor
- *
- * Host chooses whether extraction is supported or not by providing
- * valid stream tag to DSP. Once specified, stream described by that
- * tag will be tied to DSP for extraction for the entire lifetime of
- * probe.
- *
- * Probing is initialized only once and each INIT request must be
- * matched by DEINIT call.
- */
-static int sof_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
- size_t buffer_size)
-{
- struct sof_ipc_probe_dma_add_params *msg;
- size_t size = struct_size(msg, dma, 1);
- struct sof_ipc_reply reply;
- int ret;
-
- msg = kmalloc(size, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
- msg->hdr.size = size;
- msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
- msg->num_elems = 1;
- msg->dma[0].stream_tag = stream_tag;
- msg->dma[0].dma_buffer_size = buffer_size;
-
- ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
- kfree(msg);
- return ret;
-}
-
-/**
- * sof_probes_deinit - cleanup after data probing
- * @cdev: SOF client device
- *
- * Host sends DEINIT request to free previously initialized probe
- * on DSP side once it is no longer needed. DEINIT only when there
- * are no probes connected and with all injectors detached.
- */
-static int sof_probes_deinit(struct sof_client_dev *cdev)
-{
- struct sof_ipc_cmd_hdr msg;
- struct sof_ipc_reply reply;
-
- msg.size = sizeof(msg);
- msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
-
- return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
-}
-
-static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
- void **params, size_t *num_params)
-{
- size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
- struct sof_ipc_probe_info_params msg = {{{0}}};
- struct sof_ipc_probe_info_params *reply;
- size_t bytes;
- int ret;
-
- *params = NULL;
- *num_params = 0;
-
- reply = kzalloc(max_msg_size, GFP_KERNEL);
- if (!reply)
- return -ENOMEM;
- msg.rhdr.hdr.size = sizeof(msg);
- msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
-
- ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
- if (ret < 0 || reply->rhdr.error < 0)
- goto exit;
-
- if (!reply->num_elems)
- goto exit;
-
- if (cmd == SOF_IPC_PROBE_DMA_INFO)
- bytes = sizeof(reply->dma[0]);
- else
- bytes = sizeof(reply->desc[0]);
- bytes *= reply->num_elems;
- *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
- if (!*params) {
- ret = -ENOMEM;
- goto exit;
- }
- *num_params = reply->num_elems;
-
-exit:
- kfree(reply);
- return ret;
-}
-
-/**
- * sof_probes_points_info - retrieve list of active probe points
- * @cdev: SOF client device
- * @desc: Returned list of active probes
- * @num_desc: Returned count of active probes
- *
- * Host sends PROBE_POINT_INFO request to obtain list of active probe
- * points, valid for disconnection when given probe is no longer
- * required.
- */
-static int sof_probes_points_info(struct sof_client_dev *cdev,
- struct sof_probe_point_desc **desc,
- size_t *num_desc)
-{
- return sof_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
- (void **)desc, num_desc);
-}
-
-/**
- * sof_probes_points_add - connect specified probes
- * @cdev: SOF client device
- * @desc: List of probe points to connect
- * @num_desc: Number of elements in @desc
- *
- * Dynamically connects to provided set of endpoints. Immediately
- * after connection is established, host must be prepared to
- * transfer data from or to target stream given the probing purpose.
- *
- * Each probe point should be removed using PROBE_POINT_REMOVE
- * request when no longer needed.
- */
-static int sof_probes_points_add(struct sof_client_dev *cdev,
- struct sof_probe_point_desc *desc,
- size_t num_desc)
-{
- struct sof_ipc_probe_point_add_params *msg;
- size_t size = struct_size(msg, desc, num_desc);
- struct sof_ipc_reply reply;
- int ret;
-
- msg = kmalloc(size, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
- msg->hdr.size = size;
- msg->num_elems = num_desc;
- msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
- memcpy(&msg->desc[0], desc, size - sizeof(*msg));
-
- ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
- kfree(msg);
- return ret;
-}
-
-/**
- * sof_probes_points_remove - disconnect specified probes
- * @cdev: SOF client device
- * @buffer_id: List of probe points to disconnect
- * @num_buffer_id: Number of elements in @desc
- *
- * Removes previously connected probes from list of active probe
- * points and frees all resources on DSP side.
- */
-static int sof_probes_points_remove(struct sof_client_dev *cdev,
- unsigned int *buffer_id, size_t num_buffer_id)
-{
- struct sof_ipc_probe_point_remove_params *msg;
- size_t size = struct_size(msg, buffer_id, num_buffer_id);
- struct sof_ipc_reply reply;
- int ret;
-
- msg = kmalloc(size, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
- msg->hdr.size = size;
- msg->num_elems = num_buffer_id;
- msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
- memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
-
- ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
- kfree(msg);
- return ret;
-}
-
static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
struct snd_soc_dai *dai)
{
@@ -289,23 +63,24 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
struct sof_probes_priv *priv = cdev->data;
const struct sof_probes_host_ops *ops = priv->host_ops;
+ const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
struct sof_probe_point_desc *desc;
size_t num_desc;
int i, ret;
/* disconnect all probe points */
- ret = sof_probes_points_info(cdev, &desc, &num_desc);
+ ret = ipc->points_info(cdev, &desc, &num_desc);
if (ret < 0) {
dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
goto exit;
}
for (i = 0; i < num_desc; i++)
- sof_probes_points_remove(cdev, &desc[i].buffer_id, 1);
+ ipc->points_remove(cdev, &desc[i].buffer_id, 1);
kfree(desc);
exit:
- ret = sof_probes_deinit(cdev);
+ ret = ipc->deinit(cdev);
if (ret < 0)
dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
@@ -328,6 +103,7 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
struct snd_compr_runtime *rtd = cstream->runtime;
struct sof_probes_priv *priv = cdev->data;
const struct sof_probes_host_ops *ops = priv->host_ops;
+ const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
int ret;
cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
@@ -340,7 +116,7 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
if (ret)
return ret;
- ret = sof_probes_init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
+ ret = ipc->init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
if (ret < 0) {
dev_err(dai->dev, "Failed to init probe: %d\n", ret);
return ret;
@@ -419,6 +195,7 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
struct sof_probes_priv *priv = cdev->data;
struct device *dev = &cdev->auxdev.dev;
struct sof_probe_point_desc *desc;
+ const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
int remaining, offset;
size_t num_desc;
char *buf;
@@ -439,7 +216,7 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
goto exit;
}
- ret = sof_probes_points_info(cdev, &desc, &num_desc);
+ ret = ipc->points_info(cdev, &desc, &num_desc);
if (ret < 0)
goto exit;
@@ -475,6 +252,7 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
{
struct sof_client_dev *cdev = file->private_data;
struct sof_probes_priv *priv = cdev->data;
+ const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
struct device *dev = &cdev->auxdev.dev;
struct sof_probe_point_desc *desc;
u32 num_elems, *array;
@@ -505,7 +283,7 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
goto exit;
}
- ret = sof_probes_points_add(cdev, desc, bytes / sizeof(*desc));
+ ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
if (!ret)
ret = count;
@@ -533,6 +311,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
{
struct sof_client_dev *cdev = file->private_data;
struct sof_probes_priv *priv = cdev->data;
+ const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
struct device *dev = &cdev->auxdev.dev;
int ret, err;
u32 *array;
@@ -552,7 +331,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
goto exit;
}
- ret = sof_probes_points_remove(cdev, &array[1], array[0]);
+ ret = ipc->points_remove(cdev, &array[1], array[0]);
if (!ret)
ret = count;
@@ -620,28 +399,39 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
if (!sof_probes_enabled)
return -ENXIO;
- /* only ipc3 is supported */
- if (sof_client_get_ipc_type(cdev) != SOF_IPC)
- return -ENXIO;
-
- if (!dev->platform_data) {
+ ops = dev_get_platdata(dev);
+ if (!ops) {
dev_err(dev, "missing platform data\n");
return -ENODEV;
}
+ if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
+ !ops->pointer) {
+ dev_err(dev, "missing platform callback(s)\n");
+ return -ENODEV;
+ }
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- ops = dev->platform_data;
+ priv->host_ops = ops;
- if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
- !ops->pointer) {
- dev_err(dev, "missing platform callback(s)\n");
+ switch (sof_client_get_ipc_type(cdev)) {
+#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4
+ case SOF_INTEL_IPC4:
+ priv->ipc_ops = &ipc4_probe_ops;
+ break;
+#endif
+#ifdef CONFIG_SND_SOC_SOF_IPC3
+ case SOF_IPC:
+ priv->ipc_ops = &ipc3_probe_ops;
+ break;
+#endif
+ default:
+ dev_err(dev, "Matching IPC ops not found.");
return -ENODEV;
}
- priv->host_ops = ops;
cdev->data = priv;
/* register probes component driver and dai */
diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h
index 9e43f3c444f8..da04d65b8d99 100644
--- a/sound/soc/sof/sof-client-probes.h
+++ b/sound/soc/sof/sof-client-probes.h
@@ -28,4 +28,38 @@ struct sof_probes_host_ops {
struct snd_soc_dai *dai);
};
+struct sof_probe_point_desc {
+ unsigned int buffer_id;
+ unsigned int purpose;
+ unsigned int stream_tag;
+} __packed;
+
+struct sof_probes_ipc_ops {
+ int (*init)(struct sof_client_dev *cdev, u32 stream_tag,
+ size_t buffer_size);
+ int (*deinit)(struct sof_client_dev *cdev);
+ int (*points_info)(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc **desc,
+ size_t *num_desc);
+ int (*points_add)(struct sof_client_dev *cdev,
+ struct sof_probe_point_desc *desc,
+ size_t num_desc);
+ int (*points_remove)(struct sof_client_dev *cdev,
+ unsigned int *buffer_id, size_t num_buffer_id);
+};
+
+extern const struct sof_probes_ipc_ops ipc3_probe_ops;
+extern const struct sof_probes_ipc_ops ipc4_probe_ops;
+
+struct sof_probes_priv {
+ struct dentry *dfs_points;
+ struct dentry *dfs_points_remove;
+ u32 extractor_stream_tag;
+ struct snd_soc_card card;
+ void *ipc_priv;
+
+ const struct sof_probes_host_ops *host_ops;
+ const struct sof_probes_ipc_ops *ipc_ops;
+};
+
#endif
diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c
index 125aa2137195..9017f0864cdd 100644
--- a/sound/soc/sof/sof-client.c
+++ b/sound/soc/sof/sof-client.c
@@ -16,6 +16,7 @@
#include "ops.h"
#include "sof-client.h"
#include "sof-priv.h"
+#include "ipc4-priv.h"
/**
* struct sof_ipc_event_entry - IPC client event description
@@ -265,6 +266,39 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
}
EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT);
+int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
+ bool set)
+{
+ if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
+ struct sof_ipc_cmd_hdr *hdr = ipc_msg;
+
+ return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size,
+ set);
+ } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ struct sof_ipc4_msg *msg = ipc_msg;
+
+ return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg,
+ msg->data_size, set);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT);
+
+#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4
+struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid)
+{
+ struct snd_sof_dev *sdev = c->sdev;
+
+ if (sdev->pdata->ipc_type == SOF_INTEL_IPC4)
+ return sof_ipc4_find_module_by_uuid(sdev, uuid);
+ dev_err(sdev->dev, "Only supported with IPC4\n");
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT);
+#endif
+
int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
{
struct auxiliary_driver *adrv;
diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h
index 46b215d9200f..2589714eaa91 100644
--- a/sound/soc/sof/sof-client.h
+++ b/sound/soc/sof/sof-client.h
@@ -13,6 +13,8 @@ struct sof_ipc_cmd_hdr;
struct snd_sof_dev;
struct dentry;
+struct sof_ipc4_fw_module;
+
/**
* struct sof_client_dev - SOF client device
* @auxdev: auxiliary device
@@ -37,6 +39,10 @@ struct sof_client_dev {
int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
void *reply_data, size_t reply_bytes);
+int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
+ bool set);
+
+struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *u);
struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev);
struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 643fd1036d60..f5ece43d0ec2 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -28,6 +28,10 @@ static char *fw_filename;
module_param(fw_filename, charp, 0444);
MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware.");
+static char *lib_path;
+module_param(lib_path, charp, 0444);
+MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries.");
+
static char *tplg_path;
module_param(tplg_path, charp, 0444);
MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
@@ -272,6 +276,28 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
sof_pdata->desc->default_fw_path[sof_pdata->ipc_type];
}
+ if (lib_path) {
+ sof_pdata->fw_lib_prefix = lib_path;
+
+ dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
+ sof_pdata->fw_lib_prefix);
+
+ } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) {
+ if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
+ sof_pdata->fw_lib_prefix =
+ devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+ sof_pdata->desc->default_lib_path[sof_pdata->ipc_type],
+ "community");
+
+ dev_dbg(dev,
+ "Platform uses community key, changed fw_lib path to %s\n",
+ sof_pdata->fw_lib_prefix);
+ } else {
+ sof_pdata->fw_lib_prefix =
+ sof_pdata->desc->default_lib_path[sof_pdata->ipc_type];
+ }
+ }
+
if (tplg_path)
sof_pdata->tplg_filename_prefix = tplg_path;
else
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index de08825915b3..6760fd895950 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -43,6 +43,9 @@
#define SOF_DBG_PRINT_IPC_SUCCESS_LOGS BIT(9) /* print IPC success
* in dmesg logs
*/
+#define SOF_DBG_FORCE_NOCODEC BIT(10) /* ignore all codec-related
+ * configurations
+ */
/* Flag definitions used for controlling the DSP dump behavior */
#define SOF_DBG_DUMP_REGS BIT(0)
@@ -136,6 +139,17 @@ struct snd_sof_platform_stream_params {
bool cont_update_posn;
};
+/**
+ * struct sof_firmware - Container struct for SOF firmware
+ * @fw: Pointer to the firmware
+ * @payload_offset: Offset of the data within the loaded firmware image to be
+ * loaded to the DSP (skipping for example ext_manifest section)
+ */
+struct sof_firmware {
+ const struct firmware *fw;
+ u32 payload_offset;
+};
+
/*
* SOF DSP HW abstraction operations.
* Used to abstract DSP HW architecture and any IO busses between host CPU
@@ -160,6 +174,10 @@ struct snd_sof_dsp_ops {
* TODO: consider removing these operations and calling respective
* implementations directly
*/
+ void (*write8)(struct snd_sof_dev *sof_dev, void __iomem *addr,
+ u8 value); /* optional */
+ u8 (*read8)(struct snd_sof_dev *sof_dev,
+ void __iomem *addr); /* optional */
void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr,
u32 value); /* optional */
u32 (*read)(struct snd_sof_dev *sof_dev,
@@ -410,15 +428,11 @@ struct sof_ipc_pm_ops {
* DSP.
* The function implements generic, hardware independent way
* of loading the initial firmware and its modules (if any).
- * @query_fw_configuration: Optional function pointer to query information and
- * configuration from the booted firmware.
- * Executed after the first successful firmware boot.
*/
struct sof_ipc_fw_loader_ops {
int (*validate)(struct snd_sof_dev *sdev);
size_t (*parse_ext_manifest)(struct snd_sof_dev *sdev);
int (*load_fw_to_dsp)(struct snd_sof_dev *sdev);
- int (*query_fw_configuration)(struct snd_sof_dev *sdev);
};
struct sof_ipc_tplg_ops;
@@ -432,6 +446,11 @@ struct sof_ipc_pcm_ops;
* @fw_loader: Pointer to Firmware Loader ops
* @fw_tracing: Pointer to Firmware tracing ops
*
+ * @init: Optional pointer for IPC related initialization
+ * @exit: Optional pointer for IPC related cleanup
+ * @post_fw_boot: Optional pointer to execute IPC related tasks after firmware
+ * boot.
+ *
* @tx_msg: Function pointer for sending a 'short' IPC message
* @set_get_data: Function pointer for set/get data ('large' IPC message). This
* function may split up the 'large' message and use the @tx_msg
@@ -453,6 +472,10 @@ struct sof_ipc_ops {
const struct sof_ipc_fw_loader_ops *fw_loader;
const struct sof_ipc_fw_tracing_ops *fw_tracing;
+ int (*init)(struct snd_sof_dev *sdev);
+ void (*exit)(struct snd_sof_dev *sdev);
+ int (*post_fw_boot)(struct snd_sof_dev *sdev);
+
int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes, bool no_pm);
int (*set_get_data)(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
@@ -487,6 +510,9 @@ struct snd_sof_dev {
spinlock_t ipc_lock; /* lock for IPC users */
spinlock_t hw_lock; /* lock for HW IO access */
+ /* Main, Base firmware image */
+ struct sof_firmware basefw;
+
/*
* ASoC components. plat_drv fields are set dynamically so
* can't use const
@@ -654,6 +680,8 @@ static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
}
int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes);
+int sof_ipc_set_get_data(struct snd_sof_ipc *ipc, void *msg_data,
+ size_t msg_bytes, bool set);
int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes);
int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 38855dd60617..c668bd9d21ec 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -289,6 +289,9 @@ static const struct sof_dai_types sof_dais[] = {
{"ACPDMIC", SOF_DAI_AMD_DMIC},
{"ACPHS", SOF_DAI_AMD_HS},
{"AFE", SOF_DAI_MEDIATEK_AFE},
+ {"ACPSP_VIRTUAL", SOF_DAI_AMD_SP_VIRTUAL},
+ {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL},
+
};
static enum sof_ipc_dai_type find_dai(const char *name)
@@ -360,6 +363,21 @@ int get_token_uuid(void *elem, void *object, u32 offset)
return 0;
}
+/*
+ * The string gets from topology will be stored in heap, the owner only
+ * holds a char* member point to the heap.
+ */
+int get_token_string(void *elem, void *object, u32 offset)
+{
+ /* "dst" here points to the char* member of the owner */
+ char **dst = (char **)((u8 *)object + offset);
+
+ *dst = kstrdup(elem, GFP_KERNEL);
+ if (!*dst)
+ return -ENOMEM;
+ return 0;
+};
+
int get_token_comp_format(void *elem, void *object, u32 offset)
{
u32 *val = (u32 *)((u8 *)object + offset);
@@ -392,6 +410,23 @@ static const struct sof_topology_token led_tokens[] = {
offsetof(struct snd_sof_led_control, direction)},
};
+static const struct sof_topology_token comp_pin_tokens[] = {
+ {SOF_TKN_COMP_NUM_SINK_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct snd_sof_widget, num_sink_pins)},
+ {SOF_TKN_COMP_NUM_SOURCE_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct snd_sof_widget, num_source_pins)},
+};
+
+static const struct sof_topology_token comp_sink_pin_binding_tokens[] = {
+ {SOF_TKN_COMP_SINK_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ get_token_string, 0},
+};
+
+static const struct sof_topology_token comp_src_pin_binding_tokens[] = {
+ {SOF_TKN_COMP_SRC_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ get_token_string, 0},
+};
+
/**
* sof_parse_uuid_tokens - Parse multiple sets of UUID tokens
* @scomp: pointer to soc component
@@ -572,7 +607,7 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
{
struct snd_soc_tplg_vendor_string_elem *elem;
int found = 0;
- int i, j;
+ int i, j, ret;
/* parse element by element */
for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
@@ -589,7 +624,9 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
continue;
/* matched - now load token */
- tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+ ret = tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+ if (ret < 0)
+ return ret;
found++;
}
@@ -669,6 +706,7 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
int found = 0;
int total = 0;
int asize;
+ int ret;
while (array_size > 0 && total < count * token_instance_num) {
asize = le32_to_cpu(array->size);
@@ -695,8 +733,15 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
array);
break;
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
- found += sof_parse_string_tokens(scomp, object, offset, tokens, count,
- array);
+
+ ret = sof_parse_string_tokens(scomp, object, offset, tokens, count,
+ array);
+ if (ret < 0) {
+ dev_err(scomp->dev, "error: no memory to copy string token\n");
+ return ret;
+ }
+
+ found += ret;
break;
case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
@@ -1251,6 +1296,79 @@ err:
return ret;
}
+static void sof_free_pin_binding(struct snd_sof_widget *swidget,
+ bool pin_type)
+{
+ char **pin_binding;
+ u32 num_pins;
+ int i;
+
+ if (pin_type == SOF_PIN_TYPE_SINK) {
+ pin_binding = swidget->sink_pin_binding;
+ num_pins = swidget->num_sink_pins;
+ } else {
+ pin_binding = swidget->src_pin_binding;
+ num_pins = swidget->num_source_pins;
+ }
+
+ if (pin_binding) {
+ for (i = 0; i < num_pins; i++)
+ kfree(pin_binding[i]);
+ }
+
+ kfree(pin_binding);
+}
+
+static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
+ struct snd_soc_tplg_private *priv, bool pin_type)
+{
+ const struct sof_topology_token *pin_binding_token;
+ char *pin_binding[SOF_WIDGET_MAX_NUM_PINS];
+ int token_count;
+ u32 num_pins;
+ char **pb;
+ int ret;
+ int i;
+
+ if (pin_type == SOF_PIN_TYPE_SINK) {
+ num_pins = swidget->num_sink_pins;
+ pin_binding_token = comp_sink_pin_binding_tokens;
+ token_count = ARRAY_SIZE(comp_sink_pin_binding_tokens);
+ } else {
+ num_pins = swidget->num_source_pins;
+ pin_binding_token = comp_src_pin_binding_tokens;
+ token_count = ARRAY_SIZE(comp_src_pin_binding_tokens);
+ }
+
+ memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *));
+ ret = sof_parse_token_sets(swidget->scomp, pin_binding, pin_binding_token,
+ token_count, priv->array, le32_to_cpu(priv->size),
+ num_pins, sizeof(char *));
+ if (ret < 0)
+ goto err;
+
+ /* copy pin binding array to swidget only if it is defined in topology */
+ if (pin_binding[0]) {
+ pb = kmemdup(pin_binding, num_pins * sizeof(char *), GFP_KERNEL);
+ if (!pb) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (pin_type == SOF_PIN_TYPE_SINK)
+ swidget->sink_pin_binding = pb;
+ else
+ swidget->src_pin_binding = pb;
+ }
+
+ return 0;
+
+err:
+ for (i = 0; i < num_pins; i++)
+ kfree(pin_binding[i]);
+
+ return ret;
+}
+
/* external widget init - used for any driver specific init */
static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_widget *w,
@@ -1259,6 +1377,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
+ struct snd_soc_tplg_private *priv = &tw->priv;
struct snd_sof_widget *swidget;
struct snd_sof_dai *dai;
enum sof_tokens *token_list;
@@ -1276,11 +1395,50 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
swidget->id = w->id;
swidget->pipeline_id = index;
swidget->private = NULL;
+ ida_init(&swidget->src_queue_ida);
+ ida_init(&swidget->sink_queue_ida);
+
+ ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
+ ARRAY_SIZE(comp_pin_tokens), priv->array,
+ le32_to_cpu(priv->size));
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse component pin tokens for %s\n",
+ w->name);
+ return ret;
+ }
+
+ if (swidget->num_sink_pins > SOF_WIDGET_MAX_NUM_PINS ||
+ swidget->num_source_pins > SOF_WIDGET_MAX_NUM_PINS) {
+ dev_err(scomp->dev, "invalid pins for %s: [sink: %d, src: %d]\n",
+ swidget->widget->name, swidget->num_sink_pins, swidget->num_source_pins);
+ return -EINVAL;
+ }
+
+ if (swidget->num_sink_pins > 1) {
+ ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK);
+ /* on parsing error, pin binding is not allocated, nothing to free. */
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse sink pin binding for %s\n",
+ w->name);
+ return ret;
+ }
+ }
+
+ if (swidget->num_source_pins > 1) {
+ ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE);
+ /* on parsing error, pin binding is not allocated, nothing to free. */
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse source pin binding for %s\n",
+ w->name);
+ return ret;
+ }
+ }
- dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
- swidget->comp_id, index, swidget->id, tw->name,
- strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
- ? tw->sname : "none");
+ dev_dbg(scomp->dev,
+ "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n",
+ swidget->comp_id, w->name, swidget->id, index,
+ swidget->num_sink_pins, swidget->num_source_pins,
+ strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none");
token_list = widget_ops[w->id].token_list;
token_list_size = widget_ops[w->id].token_list_size;
@@ -1344,16 +1502,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
break;
}
- if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) {
- swidget->core = SOF_DSP_PRIMARY_CORE;
- } else {
- int core = sof_get_token_value(SOF_TKN_COMP_CORE_ID, swidget->tuples,
- swidget->num_tuples);
-
- if (core >= 0)
- swidget->core = core;
- }
-
/* check token parsing reply */
if (ret < 0) {
dev_err(scomp->dev,
@@ -1365,6 +1513,16 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
return ret;
}
+ if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) {
+ swidget->core = SOF_DSP_PRIMARY_CORE;
+ } else {
+ int core = sof_get_token_value(SOF_TKN_COMP_CORE_ID, swidget->tuples,
+ swidget->num_tuples);
+
+ if (core >= 0)
+ swidget->core = core;
+ }
+
/* bind widget to external event */
if (tw->event_type) {
if (widget_ops[w->id].bind_event) {
@@ -1471,6 +1629,12 @@ out:
if (widget_ops[swidget->id].ipc_free)
widget_ops[swidget->id].ipc_free(swidget);
+ ida_destroy(&swidget->src_queue_ida);
+ ida_destroy(&swidget->sink_queue_ida);
+
+ sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK);
+ sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE);
+
kfree(swidget->tuples);
/* remove and free swidget object */
@@ -1734,6 +1898,13 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
token_id = SOF_ACPDMIC_TOKENS;
num_tuples += token_list[SOF_ACPDMIC_TOKENS].count;
break;
+ case SOF_DAI_AMD_SP:
+ case SOF_DAI_AMD_HS:
+ case SOF_DAI_AMD_SP_VIRTUAL:
+ case SOF_DAI_AMD_HS_VIRTUAL:
+ token_id = SOF_ACPI2S_TOKENS;
+ num_tuples += token_list[SOF_ACPI2S_TOKENS].count;
+ break;
default:
break;
}
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 643fc8a17018..837c1848d9bf 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -304,6 +304,11 @@ static int stm32_adfsdm_dummy_cb(const void *data, void *private)
return 0;
}
+static void stm32_adfsdm_cleanup(void *data)
+{
+ iio_channel_release_all_cb(data);
+}
+
static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
.open = stm32_adfsdm_pcm_open,
.close = stm32_adfsdm_pcm_close,
@@ -350,6 +355,12 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
if (IS_ERR(priv->iio_cb))
return PTR_ERR(priv->iio_cb);
+ ret = devm_add_action_or_reset(&pdev->dev, stm32_adfsdm_cleanup, priv->iio_cb);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to add action\n");
+ return ret;
+ }
+
component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index ce7f6942308f..f3dd9f8e621c 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -1077,7 +1077,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
if (irq < 0)
return irq;
- ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT,
+ ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, 0,
dev_name(&pdev->dev), i2s);
if (ret) {
dev_err(&pdev->dev, "irq request returned %d\n", ret);
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
index 86cff5a5b1bd..069c993acb31 100644
--- a/sound/soc/sunxi/sun50i-dmic.c
+++ b/sound/soc/sunxi/sun50i-dmic.c
@@ -317,8 +317,7 @@ static int sun50i_dmic_probe(struct platform_device *pdev)
return -ENOMEM;
/* Get the addresses */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
return dev_err_probe(&pdev->dev, PTR_ERR(base),
"get resource failed.\n");
@@ -391,7 +390,7 @@ static const struct dev_pm_ops sun50i_dmic_pm = {
static struct platform_driver sun50i_dmic_driver = {
.driver = {
.name = "sun50i-dmic",
- .of_match_table = of_match_ptr(sun50i_dmic_of_match),
+ .of_match_table = sun50i_dmic_of_match,
.pm = &sun50i_dmic_pm,
},
.probe = sun50i_dmic_probe,
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
index d786daa6aba6..eeacb1220268 100644
--- a/sound/soc/tegra/tegra210_mbdrc.c
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -54,7 +54,7 @@ static const struct tegra210_mbdrc_config mbdrc_init_config = {
.mode = 0, /* Bypass */
.rms_off = 48,
.peak_rms_mode = 1, /* PEAK */
- .fliter_structure = 0, /* All-pass tree */
+ .filter_structure = 0, /* All-pass tree */
.shift_ctrl = 30,
.frame_size = 32,
.channel_mask = 0x3,
@@ -819,7 +819,7 @@ int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
- conf->fliter_structure <<
+ conf->filter_structure <<
TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
index 4c48da0e1dea..76e443a7934e 100644
--- a/sound/soc/tegra/tegra210_mbdrc.h
+++ b/sound/soc/tegra/tegra210_mbdrc.h
@@ -199,7 +199,7 @@ struct tegra210_mbdrc_config {
unsigned int mode;
unsigned int rms_off;
unsigned int peak_rms_mode;
- unsigned int fliter_structure;
+ unsigned int filter_structure;
unsigned int shift_ctrl;
unsigned int frame_size;
unsigned int channel_mask;
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index ca5d1bb6ac59..f5ac2ab77f5b 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -869,7 +869,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
max_active_serializers = 1;
else
- max_active_serializers = (channels + slots - 1) / slots;
+ max_active_serializers = DIV_ROUND_UP(channels, slots);
/* Default configuration */
if (mcasp->version < MCASP_VERSION_3)
@@ -1002,8 +1002,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
*/
if (mcasp->tdm_mask[stream]) {
active_slots = hweight32(mcasp->tdm_mask[stream]);
- active_serializers = (channels + active_slots - 1) /
- active_slots;
+ active_serializers = DIV_ROUND_UP(channels, active_slots);
if (active_serializers == 1)
active_slots = channels;
for (i = 0; i < total_slots; i++) {
@@ -1014,7 +1013,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
}
}
} else {
- active_serializers = (channels + total_slots - 1) / total_slots;
+ active_serializers = DIV_ROUND_UP(channels, total_slots);
if (active_serializers == 1)
active_slots = channels;
else
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
index b8195778953e..0eba60758134 100644
--- a/sound/soc/uniphier/aio-core.c
+++ b/sound/soc/uniphier/aio-core.c
@@ -277,17 +277,18 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
static int aio_port_set_ch(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
- u32 slotsel_2ch[] = {
+ static const u32 slotsel_2ch[] = {
0, 0, 0, 0, 0,
};
- u32 slotsel_multi[] = {
+ static const u32 slotsel_multi[] = {
OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
};
- u32 mode, *slotsel;
+ u32 mode;
+ const u32 *slotsel;
int i;
switch (params_channels(&sub->params)) {
@@ -515,13 +516,13 @@ static int aio_port_set_clk(struct uniphier_aio_sub *sub)
struct uniphier_aio_chip *chip = sub->aio->chip;
struct device *dev = &sub->aio->chip->pdev->dev;
struct regmap *r = sub->aio->chip->regmap;
- u32 v_pll[] = {
+ static const u32 v_pll[] = {
OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
OPORTMXCTR2_ACLKSEL_A2PLL,
OPORTMXCTR2_ACLKSEL_RX1,
};
- u32 v_div[] = {
+ static const u32 v_div[] = {
OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
};
diff --git a/sound/usb/card.c b/sound/usb/card.c
index a5ed11ea1145..26268ffb8274 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -742,6 +742,18 @@ get_alias_quirk(struct usb_device *dev, unsigned int id)
return NULL;
}
+/* register card if we reach to the last interface or to the specified
+ * one given via option
+ */
+static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
+{
+ if (check_delayed_register_option(chip) == ifnum ||
+ chip->last_iface == ifnum ||
+ usb_interface_claimed(usb_ifnum_to_if(chip->dev, chip->last_iface)))
+ return snd_card_register(chip->card);
+ return 0;
+}
+
/*
* probe the active usb device
*
@@ -880,15 +892,9 @@ static int usb_audio_probe(struct usb_interface *intf,
chip->need_delayed_register = false; /* clear again */
}
- /* register card if we reach to the last interface or to the specified
- * one given via option
- */
- if (check_delayed_register_option(chip) == ifnum ||
- usb_interface_claimed(usb_ifnum_to_if(dev, chip->last_iface))) {
- err = snd_card_register(chip->card);
- if (err < 0)
- goto __error;
- }
+ err = try_to_register_card(chip, ifnum);
+ if (err < 0)
+ goto __error_no_register;
if (chip->quirk_flags & QUIRK_FLAG_SHARE_MEDIA_DEVICE) {
/* don't want to fail when snd_media_device_create() fails */
@@ -907,6 +913,11 @@ static int usb_audio_probe(struct usb_interface *intf,
return 0;
__error:
+ /* in the case of error in secondary interface, still try to register */
+ if (chip)
+ try_to_register_card(chip, ifnum);
+
+ __error_no_register:
if (chip) {
/* chip->active is inside the chip->card object,
* decrement before memory is possibly returned.
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index d0b8d61d1d22..4aaf0784940b 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -931,7 +931,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n",
ep->ep_num, ep->opened);
- if (!--ep->iface_ref->opened)
+ if (!--ep->iface_ref->opened &&
+ !(chip->quirk_flags & QUIRK_FLAG_IFACE_SKIP_CLOSE))
endpoint_set_interface(chip, ep, false);
if (!--ep->opened) {
@@ -1672,6 +1673,13 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending)
stop_urbs(ep, false, keep_pending);
if (ep->clock_ref)
atomic_dec(&ep->clock_ref->locked);
+
+ if (ep->chip->quirk_flags & QUIRK_FLAG_FORCE_IFACE_RESET &&
+ usb_pipeout(ep->pipe)) {
+ ep->need_prepare = true;
+ if (ep->iface_ref)
+ ep->iface_ref->need_setup = true;
+ }
}
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index bbff0923d264..2839f6b6f09b 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1133,10 +1133,8 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
port = &umidi->endpoints[i].out->ports[j];
break;
}
- if (!port) {
- snd_BUG();
+ if (!port)
return -ENXIO;
- }
substream->runtime->private_data = port;
port->state = STATE_UNKNOWN;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 8ed165f036a0..9557bd4d1bbc 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -604,6 +604,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_usb_substream *subs = runtime->private_data;
struct snd_usb_audio *chip = subs->stream->chip;
+ int retry = 0;
int ret;
ret = snd_usb_lock_shutdown(chip);
@@ -614,6 +615,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
goto unlock;
}
+ again:
if (subs->sync_endpoint) {
ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint);
if (ret < 0)
@@ -638,9 +640,16 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- !subs->lowlatency_playback)
+ !subs->lowlatency_playback) {
ret = start_endpoints(subs);
-
+ /* if XRUN happens at starting streams (possibly with implicit
+ * fb case), restart again, but only try once.
+ */
+ if (ret == -EPIPE && !retry++) {
+ sync_pending_stops(subs);
+ goto again;
+ }
+ }
unlock:
snd_usb_unlock_shutdown(chip);
return ret;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 06dfdd45cff8..874fcf245747 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2050,6 +2050,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ /* M-Audio Micro */
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x201a),
+},
+{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030),
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
/* .vendor_name = "M-Audio", */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index eadac586bcc8..58b37bfc885c 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -376,7 +376,8 @@ static int create_auto_midi_quirk(struct snd_usb_audio *chip,
static int create_autodetect_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
- struct usb_driver *driver)
+ struct usb_driver *driver,
+ const struct snd_usb_audio_quirk *quirk)
{
int err;
@@ -386,45 +387,6 @@ static int create_autodetect_quirk(struct snd_usb_audio *chip,
return err;
}
-static int create_autodetect_quirks(struct snd_usb_audio *chip,
- struct usb_interface *iface,
- struct usb_driver *driver,
- const struct snd_usb_audio_quirk *quirk)
-{
- int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
- int ifcount, ifnum, err;
-
- err = create_autodetect_quirk(chip, iface, driver);
- if (err < 0)
- return err;
-
- /*
- * ALSA PCM playback/capture devices cannot be registered in two steps,
- * so we have to claim the other corresponding interface here.
- */
- ifcount = chip->dev->actconfig->desc.bNumInterfaces;
- for (ifnum = 0; ifnum < ifcount; ifnum++) {
- if (ifnum == probed_ifnum || quirk->ifnum >= 0)
- continue;
- iface = usb_ifnum_to_if(chip->dev, ifnum);
- if (!iface ||
- usb_interface_claimed(iface) ||
- get_iface_desc(iface->altsetting)->bInterfaceClass !=
- USB_CLASS_VENDOR_SPEC)
- continue;
-
- err = create_autodetect_quirk(chip, iface, driver);
- if (err >= 0) {
- err = usb_driver_claim_interface(driver, iface,
- USB_AUDIO_IFACE_UNUSED);
- if (err < 0)
- return err;
- }
- }
-
- return 0;
-}
-
/*
* Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
* The only way to detect the sample rate is by looking at wMaxPacketSize.
@@ -554,7 +516,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
static const quirk_func_t quirk_funcs[] = {
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
[QUIRK_COMPOSITE] = create_composite_quirk,
- [QUIRK_AUTODETECT] = create_autodetect_quirks,
+ [QUIRK_AUTODETECT] = create_autodetect_quirk,
[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
@@ -1913,6 +1875,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
/* XMOS based USB DACs */
switch (chip->usb_id) {
case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */
+ case USB_ID(0x21ed, 0xd75a): /* Accuphase DAC-60 option card */
case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */
case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */
if (fp->altsetting == 2)
@@ -2081,6 +2044,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
DEVICE_FLG(0x0644, 0x804a, /* TEAC UD-301 */
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
QUIRK_FLAG_IFACE_DELAY),
+ DEVICE_FLG(0x0644, 0x805f, /* TEAC Model 12 */
+ QUIRK_FLAG_FORCE_IFACE_RESET),
DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */
@@ -2185,6 +2150,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
+ QUIRK_FLAG_IFACE_SKIP_CLOSE),
/* Vendor matches */
VENDOR_FLG(0x045e, /* MS Lifecam */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 2c6575029b1c..2aba508a4831 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -170,6 +170,11 @@ extern bool snd_usb_skip_validation;
* Apply the generic implicit feedback sync mode (same as implicit_fb=1 option)
* QUIRK_FLAG_SKIP_IMPLICIT_FB
* Don't apply implicit feedback sync mode
+ * QUIRK_FLAG_IFACE_SKIP_CLOSE
+ * Don't closed interface during setting sample rate
+ * QUIRK_FLAG_FORCE_IFACE_RESET
+ * Force an interface reset whenever stopping & restarting a stream
+ * (e.g. after xrun)
*/
#define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0)
@@ -191,5 +196,7 @@ extern bool snd_usb_skip_validation;
#define QUIRK_FLAG_SET_IFACE_FIRST (1U << 16)
#define QUIRK_FLAG_GENERIC_IMPLICIT_FB (1U << 17)
#define QUIRK_FLAG_SKIP_IMPLICIT_FB (1U << 18)
+#define QUIRK_FLAG_IFACE_SKIP_CLOSE (1U << 19)
+#define QUIRK_FLAG_FORCE_IFACE_RESET (1U << 20)
#endif /* __USBAUDIO_H */
diff --git a/tools/accounting/procacct.c b/tools/accounting/procacct.c
index 8353d3237e50..90c4a37f53d9 100644
--- a/tools/accounting/procacct.c
+++ b/tools/accounting/procacct.c
@@ -261,25 +261,20 @@ void handle_aggr(int mother, struct nlattr *na, int fd)
int main(int argc, char *argv[])
{
- int c, rc, rep_len, aggr_len, len2;
- int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
+ int c, rc, rep_len;
__u16 id;
__u32 mypid;
struct nlattr *na;
int nl_sd = -1;
int len = 0;
- pid_t tid = 0;
int fd = 0;
int write_file = 0;
int maskset = 0;
char *logfile = NULL;
- int containerset = 0;
- char *containerpath = NULL;
int cfd = 0;
int forking = 0;
- sigset_t sigset;
struct msgtemplate msg;
diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h
index 10ac52705892..f17ade084720 100644
--- a/tools/arch/x86/include/asm/msr-index.h
+++ b/tools/arch/x86/include/asm/msr-index.h
@@ -535,6 +535,11 @@
#define MSR_AMD64_CPUID_FN_1 0xc0011004
#define MSR_AMD64_LS_CFG 0xc0011020
#define MSR_AMD64_DC_CFG 0xc0011022
+
+#define MSR_AMD64_DE_CFG 0xc0011029
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
+
#define MSR_AMD64_BU_CFG2 0xc001102a
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
@@ -640,9 +645,6 @@
#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL
#define FAM10H_MMIO_CONF_BASE_SHIFT 20
#define MSR_FAM10H_NODE_ID 0xc001100c
-#define MSR_F10H_DECFG 0xc0011029
-#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1
-#define MSR_F10H_DECFG_LFENCE_SERIALIZE BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT)
/* K8 MSRs */
#define MSR_K8_TOP_MEM1 0xc001001a
diff --git a/tools/arch/x86/intel_sdsi/intel_sdsi.c b/tools/arch/x86/intel_sdsi/intel_sdsi.c
index c0e2f2349db4..2cd92761f171 100644
--- a/tools/arch/x86/intel_sdsi/intel_sdsi.c
+++ b/tools/arch/x86/intel_sdsi/intel_sdsi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * sdsi: Intel Software Defined Silicon tool for provisioning certificates
- * and activation payloads on supported cpus.
+ * sdsi: Intel On Demand (formerly Software Defined Silicon) tool for
+ * provisioning certificates and activation payloads on supported cpus.
*
* See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
* for register descriptions.
@@ -22,19 +22,54 @@
#include <sys/types.h>
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
#define SDSI_DEV "intel_vsec.sdsi"
#define AUX_DEV_PATH "/sys/bus/auxiliary/devices/"
#define SDSI_PATH (AUX_DEV_DIR SDSI_DEV)
-#define GUID 0x6dd191
-#define REGISTERS_MIN_SIZE 72
+#define GUID_V1 0x6dd191
+#define REGS_SIZE_GUID_V1 72
+#define GUID_V2 0xF210D9EF
+#define REGS_SIZE_GUID_V2 80
+#define STATE_CERT_MAX_SIZE 4096
+#define METER_CERT_MAX_SIZE 4096
+#define STATE_MAX_NUM_LICENSES 16
+#define STATE_MAX_NUM_IN_BUNDLE (uint32_t)8
+#define METER_MAX_NUM_BUNDLES 8
#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
+struct nvram_content_auth_err_sts {
+ uint64_t reserved:3;
+ uint64_t sdsi_content_auth_err:1;
+ uint64_t reserved1:1;
+ uint64_t sdsi_metering_auth_err:1;
+ uint64_t reserved2:58;
+};
+
struct enabled_features {
uint64_t reserved:3;
uint64_t sdsi:1;
- uint64_t reserved1:60;
+ uint64_t reserved1:8;
+ uint64_t attestation:1;
+ uint64_t reserved2:13;
+ uint64_t metering:1;
+ uint64_t reserved3:37;
+};
+
+struct key_provision_status {
+ uint64_t reserved:1;
+ uint64_t license_key_provisioned:1;
+ uint64_t reserved2:62;
};
struct auth_fail_count {
@@ -49,31 +84,102 @@ struct availability {
uint64_t reserved:48;
uint64_t available:3;
uint64_t threshold:3;
+ uint64_t reserved2:10;
+};
+
+struct nvram_update_limit {
+ uint64_t reserved:12;
+ uint64_t sdsi_50_pct:1;
+ uint64_t sdsi_75_pct:1;
+ uint64_t sdsi_90_pct:1;
+ uint64_t reserved2:49;
};
struct sdsi_regs {
uint64_t ppin;
- uint64_t reserved;
+ struct nvram_content_auth_err_sts auth_err_sts;
struct enabled_features en_features;
- uint64_t reserved1;
+ struct key_provision_status key_prov_sts;
struct auth_fail_count auth_fail_count;
struct availability prov_avail;
- uint64_t reserved2;
- uint64_t reserved3;
- uint64_t socket_id;
+ struct nvram_update_limit limits;
+ uint64_t pcu_cr3_capid_cfg;
+ union {
+ struct {
+ uint64_t socket_id;
+ } v1;
+ struct {
+ uint64_t reserved;
+ uint64_t socket_id;
+ uint64_t reserved2;
+ } v2;
+ } extra;
+};
+#define CONTENT_TYPE_LK_ENC 0xD
+#define CONTENT_TYPE_LK_BLOB_ENC 0xE
+
+struct state_certificate {
+ uint32_t content_type;
+ uint32_t region_rev_id;
+ uint32_t header_size;
+ uint32_t total_size;
+ uint32_t key_size;
+ uint32_t num_licenses;
+};
+
+struct license_key_info {
+ uint32_t key_rev_id;
+ uint64_t key_image_content[6];
+} __packed;
+
+#define LICENSE_BLOB_SIZE(l) (((l) & 0x7fffffff) * 4)
+#define LICENSE_VALID(l) (!!((l) & 0x80000000))
+
+// License Group Types
+#define LBT_ONE_TIME_UPGRADE 1
+#define LBT_METERED_UPGRADE 2
+
+struct license_blob_content {
+ uint32_t type;
+ uint64_t id;
+ uint64_t ppin;
+ uint64_t previous_ppin;
+ uint32_t rev_id;
+ uint32_t num_bundles;
+} __packed;
+
+struct bundle_encoding {
+ uint32_t encoding;
+ uint32_t encoding_rsvd[7];
+};
+
+struct meter_certificate {
+ uint32_t block_signature;
+ uint32_t counter_unit;
+ uint64_t ppin;
+ uint32_t bundle_length;
+ uint32_t reserved;
+ uint32_t mmrc_encoding;
+ uint32_t mmrc_counter;
+};
+
+struct bundle_encoding_counter {
+ uint32_t encoding;
+ uint32_t counter;
};
struct sdsi_dev {
struct sdsi_regs regs;
+ struct state_certificate sc;
char *dev_name;
char *dev_path;
- int guid;
+ uint32_t guid;
};
enum command {
- CMD_NONE,
CMD_SOCKET_INFO,
- CMD_DUMP_CERT,
+ CMD_METER_CERT,
+ CMD_STATE_CERT,
CMD_PROV_AKC,
CMD_PROV_CAP,
};
@@ -98,7 +204,7 @@ static void sdsi_list_devices(void)
}
if (!found)
- fprintf(stderr, "No sdsi devices found.\n");
+ fprintf(stderr, "No On Demand devices found.\n");
}
static int sdsi_update_registers(struct sdsi_dev *s)
@@ -121,7 +227,7 @@ static int sdsi_update_registers(struct sdsi_dev *s)
return -1;
}
- if (s->guid != GUID) {
+ if (s->guid != GUID_V1 && s->guid != GUID_V2) {
fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);
fclose(regs_ptr);
return -1;
@@ -129,7 +235,8 @@ static int sdsi_update_registers(struct sdsi_dev *s)
/* Update register info for this guid */
ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);
- if (ret != sizeof(s->regs)) {
+ if ((s->guid == GUID_V1 && ret != REGS_SIZE_GUID_V1) ||
+ (s->guid == GUID_V2 && ret != REGS_SIZE_GUID_V2)) {
fprintf(stderr, "Could not read 'registers' file\n");
fclose(regs_ptr);
return -1;
@@ -153,8 +260,18 @@ static int sdsi_read_reg(struct sdsi_dev *s)
printf("Socket information for device %s\n", s->dev_name);
printf("\n");
printf("PPIN: 0x%lx\n", s->regs.ppin);
+ printf("NVRAM Content Authorization Error Status\n");
+ printf(" SDSi Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_content_auth_err ? "Error" : "Okay");
+
+ if (!!s->regs.en_features.metering)
+ printf(" Metering Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_metering_auth_err ? "Error" : "Okay");
+
printf("Enabled Features\n");
- printf(" SDSi: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
+ printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
+ printf(" Attestation: %s\n", !!s->regs.en_features.attestation ? "Enabled" : "Disabled");
+ printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
+ printf(" Metering: %s\n", !!s->regs.en_features.metering ? "Enabled" : "Disabled");
+ printf("License Key (AKC) Provisioned: %s\n", !!s->regs.key_prov_sts.license_key_provisioned ? "Yes" : "No");
printf("Authorization Failure Count\n");
printf(" AKC Failure Count: %d\n", s->regs.auth_fail_count.key_failure_count);
printf(" AKC Failure Threshold: %d\n", s->regs.auth_fail_count.key_failure_threshold);
@@ -163,25 +280,148 @@ static int sdsi_read_reg(struct sdsi_dev *s)
printf("Provisioning Availability\n");
printf(" Updates Available: %d\n", s->regs.prov_avail.available);
printf(" Updates Threshold: %d\n", s->regs.prov_avail.threshold);
- printf("Socket ID: %ld\n", s->regs.socket_id & 0xF);
+ printf("NVRAM Udate Limit\n");
+ printf(" 50%% Limit Reached: %s\n", !!s->regs.limits.sdsi_50_pct ? "Yes" : "No");
+ printf(" 75%% Limit Reached: %s\n", !!s->regs.limits.sdsi_75_pct ? "Yes" : "No");
+ printf(" 90%% Limit Reached: %s\n", !!s->regs.limits.sdsi_90_pct ? "Yes" : "No");
+ if (s->guid == GUID_V1)
+ printf("Socket ID: %ld\n", s->regs.extra.v1.socket_id & 0xF);
+ else
+ printf("Socket ID: %ld\n", s->regs.extra.v2.socket_id & 0xF);
return 0;
}
-static int sdsi_certificate_dump(struct sdsi_dev *s)
+static char *license_blob_type(uint32_t type)
+{
+ switch (type) {
+ case LBT_ONE_TIME_UPGRADE:
+ return "One time upgrade";
+ case LBT_METERED_UPGRADE:
+ return "Metered upgrade";
+ default:
+ return "Unknown license blob type";
+ }
+}
+
+static char *content_type(uint32_t type)
+{
+ switch (type) {
+ case CONTENT_TYPE_LK_ENC:
+ return "Licencse key encoding";
+ case CONTENT_TYPE_LK_BLOB_ENC:
+ return "License key + Blob encoding";
+ default:
+ return "Unknown content type";
+ }
+}
+
+static void get_feature(uint32_t encoding, char *feature)
+{
+ char *name = (char *)&encoding;
+
+ feature[3] = name[0];
+ feature[2] = name[1];
+ feature[1] = name[2];
+ feature[0] = name[3];
+}
+
+static int sdsi_meter_cert_show(struct sdsi_dev *s)
{
- uint64_t state_certificate[512] = {0};
- bool first_instance;
- uint64_t previous;
+ char buf[METER_CERT_MAX_SIZE] = {0};
+ struct bundle_encoding_counter *bec;
+ struct meter_certificate *mc;
+ uint32_t count = 0;
FILE *cert_ptr;
- int i, ret, size;
+ int ret, size;
ret = sdsi_update_registers(s);
if (ret)
return ret;
if (!s->regs.en_features.sdsi) {
- fprintf(stderr, "SDSi feature is present but not enabled.");
+ fprintf(stderr, "SDSi feature is present but not enabled.\n");
+ fprintf(stderr, " Unable to read meter certificate\n");
+ return -1;
+ }
+
+ if (!s->regs.en_features.metering) {
+ fprintf(stderr, "Metering not supporting on this socket.\n");
+ return -1;
+ }
+
+ ret = chdir(s->dev_path);
+ if (ret == -1) {
+ perror("chdir");
+ return ret;
+ }
+
+ cert_ptr = fopen("meter_certificate", "r");
+ if (!cert_ptr) {
+ perror("Could not open 'meter_certificate' file");
+ return -1;
+ }
+
+ size = fread(buf, 1, sizeof(buf), cert_ptr);
+ if (!size) {
+ fprintf(stderr, "Could not read 'meter_certificate' file\n");
+ fclose(cert_ptr);
+ return -1;
+ }
+ fclose(cert_ptr);
+
+ mc = (struct meter_certificate *)buf;
+
+ printf("\n");
+ printf("Meter certificate for device %s\n", s->dev_name);
+ printf("\n");
+ printf("Block Signature: 0x%x\n", mc->block_signature);
+ printf("Count Unit: %dms\n", mc->counter_unit);
+ printf("PPIN: 0x%lx\n", mc->ppin);
+ printf("Feature Bundle Length: %d\n", mc->bundle_length);
+ printf("MMRC encoding: %d\n", mc->mmrc_encoding);
+ printf("MMRC counter: %d\n", mc->mmrc_counter);
+ if (mc->bundle_length % 8) {
+ fprintf(stderr, "Invalid bundle length\n");
+ return -1;
+ }
+
+ if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8) {
+ fprintf(stderr, "More than %d bundles: %d\n",
+ METER_MAX_NUM_BUNDLES, mc->bundle_length / 8);
+ return -1;
+ }
+
+ bec = (void *)(mc) + sizeof(mc);
+
+ printf("Number of Feature Counters: %d\n", mc->bundle_length / 8);
+ while (count++ < mc->bundle_length / 8) {
+ char feature[5];
+
+ feature[4] = '\0';
+ get_feature(bec[count].encoding, feature);
+ printf(" %s: %d\n", feature, bec[count].counter);
+ }
+
+ return 0;
+}
+
+static int sdsi_state_cert_show(struct sdsi_dev *s)
+{
+ char buf[STATE_CERT_MAX_SIZE] = {0};
+ struct state_certificate *sc;
+ struct license_key_info *lki;
+ uint32_t offset = 0;
+ uint32_t count = 0;
+ FILE *cert_ptr;
+ int ret, size;
+
+ ret = sdsi_update_registers(s);
+ if (ret)
+ return ret;
+
+ if (!s->regs.en_features.sdsi) {
+ fprintf(stderr, "On Demand feature is present but not enabled.");
fprintf(stderr, " Unable to read state certificate");
return -1;
}
@@ -198,32 +438,74 @@ static int sdsi_certificate_dump(struct sdsi_dev *s)
return -1;
}
- size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr);
+ size = fread(buf, 1, sizeof(buf), cert_ptr);
if (!size) {
fprintf(stderr, "Could not read 'state_certificate' file\n");
fclose(cert_ptr);
return -1;
}
+ fclose(cert_ptr);
- printf("%3d: 0x%lx\n", 0, state_certificate[0]);
- previous = state_certificate[0];
- first_instance = true;
+ sc = (struct state_certificate *)buf;
- for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) {
- if (state_certificate[i] == previous) {
- if (first_instance) {
- puts("*");
- first_instance = false;
- }
- continue;
+ /* Print register info for this guid */
+ printf("\n");
+ printf("State certificate for device %s\n", s->dev_name);
+ printf("\n");
+ printf("Content Type: %s\n", content_type(sc->content_type));
+ printf("Region Revision ID: %d\n", sc->region_rev_id);
+ printf("Header Size: %d\n", sc->header_size * 4);
+ printf("Total Size: %d\n", sc->total_size);
+ printf("OEM Key Size: %d\n", sc->key_size * 4);
+ printf("Number of Licenses: %d\n", sc->num_licenses);
+
+ /* Skip over the license sizes 4 bytes per license) to get the license key info */
+ lki = (void *)sc + sizeof(*sc) + (4 * sc->num_licenses);
+
+ printf("License blob Info:\n");
+ printf(" License Key Revision ID: 0x%x\n", lki->key_rev_id);
+ printf(" License Key Image Content: 0x%lx%lx%lx%lx%lx%lx\n",
+ lki->key_image_content[5], lki->key_image_content[4],
+ lki->key_image_content[3], lki->key_image_content[2],
+ lki->key_image_content[1], lki->key_image_content[0]);
+
+ while (count++ < sc->num_licenses) {
+ uint32_t blob_size_field = *(uint32_t *)(buf + 0x14 + count * 4);
+ uint32_t blob_size = LICENSE_BLOB_SIZE(blob_size_field);
+ bool license_valid = LICENSE_VALID(blob_size_field);
+ struct license_blob_content *lbc =
+ (void *)(sc) + // start of the state certificate
+ sizeof(*sc) + // size of the state certificate
+ (4 * sc->num_licenses) + // total size of the blob size blocks
+ sizeof(*lki) + // size of the license key info
+ offset; // offset to this blob content
+ struct bundle_encoding *bundle = (void *)(lbc) + sizeof(*lbc);
+ char feature[5];
+ uint32_t i;
+
+ printf(" Blob %d:\n", count - 1);
+ printf(" License blob size: %u\n", blob_size);
+ printf(" License is valid: %s\n", license_valid ? "Yes" : "No");
+ printf(" License blob type: %s\n", license_blob_type(lbc->type));
+ printf(" License blob ID: 0x%lx\n", lbc->id);
+ printf(" PPIN: 0x%lx\n", lbc->ppin);
+ printf(" Previous PPIN: 0x%lx\n", lbc->previous_ppin);
+ printf(" Blob revision ID: %u\n", lbc->rev_id);
+ printf(" Number of Features: %u\n", lbc->num_bundles);
+
+ feature[4] = '\0';
+
+ for (i = 0; i < min(lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); i++) {
+ get_feature(bundle[i].encoding, feature);
+ printf(" Feature %d: %s\n", i, feature);
}
- printf("%3d: 0x%lx\n", i, state_certificate[i]);
- previous = state_certificate[i];
- first_instance = true;
- }
- printf("%3d\n", i);
- fclose(cert_ptr);
+ if (lbc->num_bundles > STATE_MAX_NUM_IN_BUNDLE)
+ fprintf(stderr, " Warning: %d > %d licenses in bundle reported.\n",
+ lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE);
+
+ offset += blob_size;
+ };
return 0;
}
@@ -231,7 +513,7 @@ static int sdsi_certificate_dump(struct sdsi_dev *s)
static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)
{
int bin_fd, prov_fd, size, ret;
- char buf[4096] = { 0 };
+ char buf[STATE_CERT_MAX_SIZE] = { 0 };
char cap[] = "provision_cap";
char akc[] = "provision_akc";
char *prov_file;
@@ -266,7 +548,7 @@ static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command comma
}
/* Read the binary file into the buffer */
- size = read(bin_fd, buf, 4096);
+ size = read(bin_fd, buf, STATE_CERT_MAX_SIZE);
if (size == -1) {
close(bin_fd);
close(prov_fd);
@@ -298,7 +580,7 @@ static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)
return ret;
if (!s->regs.en_features.sdsi) {
- fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
+ fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");
return -1;
}
@@ -328,7 +610,7 @@ static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)
return ret;
if (!s->regs.en_features.sdsi) {
- fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
+ fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");
return -1;
}
@@ -443,25 +725,27 @@ static void sdsi_free_dev(struct sdsi_dev *s)
static void usage(char *prog)
{
- printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog);
+ printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m] [-a FILE] [-c FILE]]\n", prog);
}
static void show_help(void)
{
printf("Commands:\n");
- printf(" %-18s\t%s\n", "-l, --list", "list available sdsi devices");
- printf(" %-18s\t%s\n", "-d, --devno DEVNO", "sdsi device number");
- printf(" %-18s\t%s\n", "-i --info", "show socket information");
- printf(" %-18s\t%s\n", "-D --dump", "dump state certificate data");
- printf(" %-18s\t%s\n", "-a --akc FILE", "provision socket with AKC FILE");
- printf(" %-18s\t%s\n", "-c --cap FILE>", "provision socket with CAP FILE");
+ printf(" %-18s\t%s\n", "-l, --list", "list available On Demand devices");
+ printf(" %-18s\t%s\n", "-d, --devno DEVNO", "On Demand device number");
+ printf(" %-18s\t%s\n", "-i, --info", "show socket information");
+ printf(" %-18s\t%s\n", "-s, --state", "show state certificate");
+ printf(" %-18s\t%s\n", "-m, --meter", "show meter certificate");
+ printf(" %-18s\t%s\n", "-a, --akc FILE", "provision socket with AKC FILE");
+ printf(" %-18s\t%s\n", "-c, --cap FILE>", "provision socket with CAP FILE");
}
int main(int argc, char *argv[])
{
char bin_file[PATH_MAX], *dev_no = NULL;
+ bool device_selected = false;
char *progname;
- enum command command = CMD_NONE;
+ enum command command = -1;
struct sdsi_dev *s;
int ret = 0, opt;
int option_index = 0;
@@ -470,21 +754,23 @@ int main(int argc, char *argv[])
{"akc", required_argument, 0, 'a'},
{"cap", required_argument, 0, 'c'},
{"devno", required_argument, 0, 'd'},
- {"dump", no_argument, 0, 'D'},
{"help", no_argument, 0, 'h'},
{"info", no_argument, 0, 'i'},
{"list", no_argument, 0, 'l'},
+ {"meter", no_argument, 0, 'm'},
+ {"state", no_argument, 0, 's'},
{0, 0, 0, 0 }
};
progname = argv[0];
- while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options,
+ while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilms", long_options,
&option_index)) != -1) {
switch (opt) {
case 'd':
dev_no = optarg;
+ device_selected = true;
break;
case 'l':
sdsi_list_devices();
@@ -492,8 +778,11 @@ int main(int argc, char *argv[])
case 'i':
command = CMD_SOCKET_INFO;
break;
- case 'D':
- command = CMD_DUMP_CERT;
+ case 'm':
+ command = CMD_METER_CERT;
+ break;
+ case 's':
+ command = CMD_STATE_CERT;
break;
case 'a':
case 'c':
@@ -520,39 +809,38 @@ int main(int argc, char *argv[])
}
}
- if (!dev_no) {
- if (command != CMD_NONE)
- fprintf(stderr, "Missing device number, DEVNO, for this command\n");
- usage(progname);
- return -1;
- }
+ if (device_selected) {
+ s = sdsi_create_dev(dev_no);
+ if (!s)
+ return -1;
- s = sdsi_create_dev(dev_no);
- if (!s)
- return -1;
+ switch (command) {
+ case CMD_SOCKET_INFO:
+ ret = sdsi_read_reg(s);
+ break;
+ case CMD_METER_CERT:
+ ret = sdsi_meter_cert_show(s);
+ break;
+ case CMD_STATE_CERT:
+ ret = sdsi_state_cert_show(s);
+ break;
+ case CMD_PROV_AKC:
+ ret = sdsi_provision_akc(s, bin_file);
+ break;
+ case CMD_PROV_CAP:
+ ret = sdsi_provision_cap(s, bin_file);
+ break;
+ default:
+ fprintf(stderr, "No command specified\n");
+ return -1;
+ }
- /* Run the command */
- switch (command) {
- case CMD_NONE:
- fprintf(stderr, "Missing command for device %s\n", dev_no);
- usage(progname);
- break;
- case CMD_SOCKET_INFO:
- ret = sdsi_read_reg(s);
- break;
- case CMD_DUMP_CERT:
- ret = sdsi_certificate_dump(s);
- break;
- case CMD_PROV_AKC:
- ret = sdsi_provision_akc(s, bin_file);
- break;
- case CMD_PROV_CAP:
- ret = sdsi_provision_cap(s, bin_file);
- break;
- }
-
-
- sdsi_free_dev(s);
+ sdsi_free_dev(s);
+
+ } else {
+ fprintf(stderr, "No device specified\n");
+ return -1;
+ }
return ret;
}
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 8727765add88..0cdb4f711510 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -300,6 +300,9 @@ int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
int err;
int fd;
+ if (!REQ_ARGS(3))
+ return -EINVAL;
+
fd = get_fd(&argc, &argv);
if (fd < 0)
return fd;
diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c
index 2491c54a5e4f..f8deae4e26a1 100644
--- a/tools/iio/iio_generic_buffer.c
+++ b/tools/iio/iio_generic_buffer.c
@@ -715,12 +715,12 @@ int main(int argc, char **argv)
continue;
}
- toread = buf_len;
} else {
usleep(timedelay);
- toread = 64;
}
+ toread = buf_len;
+
read_size = read(buf_fd, data, toread * scan_size);
if (read_size < 0) {
if (errno == EAGAIN) {
diff --git a/tools/include/uapi/linux/in.h b/tools/include/uapi/linux/in.h
index f243ce665f74..07a4cb149305 100644
--- a/tools/include/uapi/linux/in.h
+++ b/tools/include/uapi/linux/in.h
@@ -20,6 +20,7 @@
#define _UAPI_LINUX_IN_H
#include <linux/types.h>
+#include <linux/stddef.h>
#include <linux/libc-compat.h>
#include <linux/socket.h>
diff --git a/tools/include/uapi/linux/stddef.h b/tools/include/uapi/linux/stddef.h
new file mode 100644
index 000000000000..bb6ea517efb5
--- /dev/null
+++ b/tools/include/uapi/linux/stddef.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+
+
+#ifndef __always_inline
+#define __always_inline __inline__
+#endif
+
+/**
+ * __struct_group() - Create a mirrored named and anonyomous struct
+ *
+ * @TAG: The tag name for the named sub-struct (usually empty)
+ * @NAME: The identifier name of the mirrored sub-struct
+ * @ATTRS: Any struct attributes (usually empty)
+ * @MEMBERS: The member declarations for the mirrored structs
+ *
+ * Used to create an anonymous union of two structs with identical layout
+ * and size: one anonymous and one named. The former's members can be used
+ * normally without sub-struct naming, and the latter can be used to
+ * reason about the start, end, and size of the group of struct members.
+ * The named struct can also be explicitly tagged for layer reuse, as well
+ * as both having struct attributes appended.
+ */
+#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
+ union { \
+ struct { MEMBERS } ATTRS; \
+ struct TAG { MEMBERS } ATTRS NAME; \
+ }
+
+/**
+ * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
+ *
+ * @TYPE: The type of each flexible array element
+ * @NAME: The name of the flexible array member
+ *
+ * In order to have a flexible array member in a union or alone in a
+ * struct, it needs to be wrapped in an anonymous struct with at least 1
+ * named member, but that member can be empty.
+ */
+#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
+ struct { \
+ struct { } __empty_ ## NAME; \
+ TYPE NAME[]; \
+ }
+#endif
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat
index 9c366b3a676d..6f28180ffeea 100755
--- a/tools/kvm/kvm_stat/kvm_stat
+++ b/tools/kvm/kvm_stat/kvm_stat
@@ -41,11 +41,14 @@ VMX_EXIT_REASONS = {
'EXCEPTION_NMI': 0,
'EXTERNAL_INTERRUPT': 1,
'TRIPLE_FAULT': 2,
- 'PENDING_INTERRUPT': 7,
+ 'INIT_SIGNAL': 3,
+ 'SIPI_SIGNAL': 4,
+ 'INTERRUPT_WINDOW': 7,
'NMI_WINDOW': 8,
'TASK_SWITCH': 9,
'CPUID': 10,
'HLT': 12,
+ 'INVD': 13,
'INVLPG': 14,
'RDPMC': 15,
'RDTSC': 16,
@@ -65,26 +68,48 @@ VMX_EXIT_REASONS = {
'MSR_READ': 31,
'MSR_WRITE': 32,
'INVALID_STATE': 33,
+ 'MSR_LOAD_FAIL': 34,
'MWAIT_INSTRUCTION': 36,
+ 'MONITOR_TRAP_FLAG': 37,
'MONITOR_INSTRUCTION': 39,
'PAUSE_INSTRUCTION': 40,
'MCE_DURING_VMENTRY': 41,
'TPR_BELOW_THRESHOLD': 43,
'APIC_ACCESS': 44,
+ 'EOI_INDUCED': 45,
+ 'GDTR_IDTR': 46,
+ 'LDTR_TR': 47,
'EPT_VIOLATION': 48,
'EPT_MISCONFIG': 49,
+ 'INVEPT': 50,
+ 'RDTSCP': 51,
+ 'PREEMPTION_TIMER': 52,
+ 'INVVPID': 53,
'WBINVD': 54,
'XSETBV': 55,
'APIC_WRITE': 56,
+ 'RDRAND': 57,
'INVPCID': 58,
+ 'VMFUNC': 59,
+ 'ENCLS': 60,
+ 'RDSEED': 61,
+ 'PML_FULL': 62,
+ 'XSAVES': 63,
+ 'XRSTORS': 64,
+ 'UMWAIT': 67,
+ 'TPAUSE': 68,
+ 'BUS_LOCK': 74,
+ 'NOTIFY': 75,
}
SVM_EXIT_REASONS = {
'READ_CR0': 0x000,
+ 'READ_CR2': 0x002,
'READ_CR3': 0x003,
'READ_CR4': 0x004,
'READ_CR8': 0x008,
'WRITE_CR0': 0x010,
+ 'WRITE_CR2': 0x012,
'WRITE_CR3': 0x013,
'WRITE_CR4': 0x014,
'WRITE_CR8': 0x018,
@@ -105,6 +130,7 @@ SVM_EXIT_REASONS = {
'WRITE_DR6': 0x036,
'WRITE_DR7': 0x037,
'EXCP_BASE': 0x040,
+ 'LAST_EXCP': 0x05f,
'INTR': 0x060,
'NMI': 0x061,
'SMI': 0x062,
@@ -151,21 +177,45 @@ SVM_EXIT_REASONS = {
'MWAIT': 0x08b,
'MWAIT_COND': 0x08c,
'XSETBV': 0x08d,
+ 'RDPRU': 0x08e,
+ 'EFER_WRITE_TRAP': 0x08f,
+ 'CR0_WRITE_TRAP': 0x090,
+ 'CR1_WRITE_TRAP': 0x091,
+ 'CR2_WRITE_TRAP': 0x092,
+ 'CR3_WRITE_TRAP': 0x093,
+ 'CR4_WRITE_TRAP': 0x094,
+ 'CR5_WRITE_TRAP': 0x095,
+ 'CR6_WRITE_TRAP': 0x096,
+ 'CR7_WRITE_TRAP': 0x097,
+ 'CR8_WRITE_TRAP': 0x098,
+ 'CR9_WRITE_TRAP': 0x099,
+ 'CR10_WRITE_TRAP': 0x09a,
+ 'CR11_WRITE_TRAP': 0x09b,
+ 'CR12_WRITE_TRAP': 0x09c,
+ 'CR13_WRITE_TRAP': 0x09d,
+ 'CR14_WRITE_TRAP': 0x09e,
+ 'CR15_WRITE_TRAP': 0x09f,
+ 'INVPCID': 0x0a2,
'NPF': 0x400,
+ 'AVIC_INCOMPLETE_IPI': 0x401,
+ 'AVIC_UNACCELERATED_ACCESS': 0x402,
+ 'VMGEXIT': 0x403,
}
-# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h)
+# EC definition of HSR (from arch/arm64/include/asm/esr.h)
AARCH64_EXIT_REASONS = {
'UNKNOWN': 0x00,
- 'WFI': 0x01,
+ 'WFx': 0x01,
'CP15_32': 0x03,
'CP15_64': 0x04,
'CP14_MR': 0x05,
'CP14_LS': 0x06,
'FP_ASIMD': 0x07,
'CP10_ID': 0x08,
+ 'PAC': 0x09,
'CP14_64': 0x0C,
- 'ILL_ISS': 0x0E,
+ 'BTI': 0x0D,
+ 'ILL': 0x0E,
'SVC32': 0x11,
'HVC32': 0x12,
'SMC32': 0x13,
@@ -173,21 +223,26 @@ AARCH64_EXIT_REASONS = {
'HVC64': 0x16,
'SMC64': 0x17,
'SYS64': 0x18,
- 'IABT': 0x20,
- 'IABT_HYP': 0x21,
+ 'SVE': 0x19,
+ 'ERET': 0x1A,
+ 'FPAC': 0x1C,
+ 'SME': 0x1D,
+ 'IMP_DEF': 0x1F,
+ 'IABT_LOW': 0x20,
+ 'IABT_CUR': 0x21,
'PC_ALIGN': 0x22,
- 'DABT': 0x24,
- 'DABT_HYP': 0x25,
+ 'DABT_LOW': 0x24,
+ 'DABT_CUR': 0x25,
'SP_ALIGN': 0x26,
'FP_EXC32': 0x28,
'FP_EXC64': 0x2C,
'SERROR': 0x2F,
- 'BREAKPT': 0x30,
- 'BREAKPT_HYP': 0x31,
- 'SOFTSTP': 0x32,
- 'SOFTSTP_HYP': 0x33,
- 'WATCHPT': 0x34,
- 'WATCHPT_HYP': 0x35,
+ 'BREAKPT_LOW': 0x30,
+ 'BREAKPT_CUR': 0x31,
+ 'SOFTSTP_LOW': 0x32,
+ 'SOFTSTP_CUR': 0x33,
+ 'WATCHPT_LOW': 0x34,
+ 'WATCHPT_CUR': 0x35,
'BKPT32': 0x38,
'VECTOR32': 0x3A,
'BRK64': 0x3C,
@@ -220,6 +275,19 @@ USERSPACE_EXIT_REASONS = {
'S390_TSCH': 22,
'EPR': 23,
'SYSTEM_EVENT': 24,
+ 'S390_STSI': 25,
+ 'IOAPIC_EOI': 26,
+ 'HYPERV': 27,
+ 'ARM_NISV': 28,
+ 'X86_RDMSR': 29,
+ 'X86_WRMSR': 30,
+ 'DIRTY_RING_FULL': 31,
+ 'AP_RESET_HOLD': 32,
+ 'X86_BUS_LOCK': 33,
+ 'XEN': 34,
+ 'RISCV_SBI': 35,
+ 'RISCV_CSR': 36,
+ 'NOTIFY': 37,
}
IOCTL_NUMBERS = {
@@ -1756,7 +1824,7 @@ def assign_globals():
debugfs = ''
for line in open('/proc/mounts'):
- if line.split(' ')[0] == 'debugfs':
+ if line.split(' ')[2] == 'debugfs':
debugfs = line.split(' ')[1]
break
if debugfs == '':
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 184ce1684dcd..91b7106a4a73 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -11169,7 +11169,7 @@ static int attach_raw_tp(const struct bpf_program *prog, long cookie, struct bpf
}
*link = bpf_program__attach_raw_tracepoint(prog, tp_name);
- return libbpf_get_error(link);
+ return libbpf_get_error(*link);
}
/* Common logic for all BPF program types that attach to a btf_id */
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index f3a8e8e74eb8..d504d96adc83 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -234,7 +234,7 @@ static int probe_map_create(enum bpf_map_type map_type)
case BPF_MAP_TYPE_USER_RINGBUF:
key_size = 0;
value_size = 0;
- max_entries = 4096;
+ max_entries = sysconf(_SC_PAGE_SIZE);
break;
case BPF_MAP_TYPE_STRUCT_OPS:
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
diff --git a/tools/lib/bpf/ringbuf.c b/tools/lib/bpf/ringbuf.c
index d285171d4b69..6af142953a94 100644
--- a/tools/lib/bpf/ringbuf.c
+++ b/tools/lib/bpf/ringbuf.c
@@ -77,6 +77,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
__u32 len = sizeof(info);
struct epoll_event *e;
struct ring *r;
+ __u64 mmap_sz;
void *tmp;
int err;
@@ -115,8 +116,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
r->mask = info.max_entries - 1;
/* Map writable consumer page */
- tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
- map_fd, 0);
+ tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
if (tmp == MAP_FAILED) {
err = -errno;
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
@@ -129,8 +129,12 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
* data size to allow simple reading of samples that wrap around the
* end of a ring buffer. See kernel implementation for details.
* */
- tmp = mmap(NULL, rb->page_size + 2 * info.max_entries, PROT_READ,
- MAP_SHARED, map_fd, rb->page_size);
+ mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;
+ if (mmap_sz != (__u64)(size_t)mmap_sz) {
+ pr_warn("ringbuf: ring buffer size (%u) is too big\n", info.max_entries);
+ return libbpf_err(-E2BIG);
+ }
+ tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ, MAP_SHARED, map_fd, rb->page_size);
if (tmp == MAP_FAILED) {
err = -errno;
ringbuf_unmap_ring(rb, r);
@@ -348,6 +352,7 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
{
struct bpf_map_info info;
__u32 len = sizeof(info);
+ __u64 mmap_sz;
void *tmp;
struct epoll_event *rb_epoll;
int err;
@@ -384,8 +389,13 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
* simple reading and writing of samples that wrap around the end of
* the buffer. See the kernel implementation for details.
*/
- tmp = mmap(NULL, rb->page_size + 2 * info.max_entries,
- PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, rb->page_size);
+ mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;
+ if (mmap_sz != (__u64)(size_t)mmap_sz) {
+ pr_warn("user ringbuf: ring buf size (%u) is too big\n", info.max_entries);
+ return -E2BIG;
+ }
+ tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED,
+ map_fd, rb->page_size);
if (tmp == MAP_FAILED) {
err = -errno;
pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %d\n",
@@ -476,6 +486,10 @@ void *user_ring_buffer__reserve(struct user_ring_buffer *rb, __u32 size)
__u64 cons_pos, prod_pos;
struct ringbuf_hdr *hdr;
+ /* The top two bits are used as special flags */
+ if (size & (BPF_RINGBUF_BUSY_BIT | BPF_RINGBUF_DISCARD_BIT))
+ return errno = E2BIG, NULL;
+
/* Synchronizes with smp_store_release() in __bpf_user_ringbuf_peek() in
* the kernel.
*/
diff --git a/tools/memory-model/Documentation/explanation.txt b/tools/memory-model/Documentation/explanation.txt
index ee819a402b69..11a1d2d4f681 100644
--- a/tools/memory-model/Documentation/explanation.txt
+++ b/tools/memory-model/Documentation/explanation.txt
@@ -464,9 +464,10 @@ to address dependencies, since the address of a location accessed
through a pointer will depend on the value read earlier from that
pointer.
-Finally, a read event and another memory access event are linked by a
-control dependency if the value obtained by the read affects whether
-the second event is executed at all. Simple example:
+Finally, a read event X and a write event Y are linked by a control
+dependency if Y syntactically lies within an arm of an if statement and
+X affects the evaluation of the if condition via a data or address
+dependency (or similarly for a switch statement). Simple example:
int x, y;
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 43ec14c29a60..a7f1e6c8bb0a 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -999,6 +999,16 @@ static const char *uaccess_safe_builtin[] = {
"__tsan_read_write4",
"__tsan_read_write8",
"__tsan_read_write16",
+ "__tsan_volatile_read1",
+ "__tsan_volatile_read2",
+ "__tsan_volatile_read4",
+ "__tsan_volatile_read8",
+ "__tsan_volatile_read16",
+ "__tsan_volatile_write1",
+ "__tsan_volatile_write2",
+ "__tsan_volatile_write4",
+ "__tsan_volatile_write8",
+ "__tsan_volatile_write16",
"__tsan_atomic8_load",
"__tsan_atomic16_load",
"__tsan_atomic32_load",
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index a653311d9693..fd7a6ff9e7aa 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -4,6 +4,7 @@ PERF-GUI-VARS
PERF-VERSION-FILE
FEATURE-DUMP
perf
+!include/perf/
perf-read-vdso32
perf-read-vdsox32
perf-help
diff --git a/tools/perf/tests/shell/test_brstack.sh b/tools/perf/tests/shell/test_brstack.sh
index ec801cffae6b..d7ff5c4b4da4 100755
--- a/tools/perf/tests/shell/test_brstack.sh
+++ b/tools/perf/tests/shell/test_brstack.sh
@@ -13,7 +13,10 @@ fi
# skip the test if the hardware doesn't support branch stack sampling
# and if the architecture doesn't support filter types: any,save_type,u
-perf record -b -o- -B --branch-filter any,save_type,u true > /dev/null 2>&1 || exit 2
+if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev/null 2>&1 ; then
+ echo "skip: system doesn't support filter types: any,save_type,u"
+ exit 2
+fi
TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX)
diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c
index 00588b9db474..31faf2bb49ff 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -102,8 +102,10 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
/*
* cannot set it twice, -b + --branch-filter for instance
*/
- if (*mode)
+ if (*mode) {
+ pr_err("Error: Can't use --branch-any (-b) with --branch-filter (-j).\n");
return -1;
+ }
return parse_branch_str(str, mode);
}
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index 5c47ee9963a7..ba66bb7fc1ca 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -273,7 +273,7 @@ static void new_line_csv(struct perf_stat_config *config, void *ctx)
fputc('\n', os->fh);
if (os->prefix)
- fprintf(os->fh, "%s%s", os->prefix, config->csv_sep);
+ fprintf(os->fh, "%s", os->prefix);
aggr_printout(config, os->evsel, os->id, os->nr);
for (i = 0; i < os->nfields; i++)
fputs(config->csv_sep, os->fh);
@@ -559,7 +559,7 @@ static void printout(struct perf_stat_config *config, struct aggr_cpu_id id, int
[AGGR_CORE] = 2,
[AGGR_THREAD] = 1,
[AGGR_UNSET] = 0,
- [AGGR_NODE] = 0,
+ [AGGR_NODE] = 1,
};
pm = config->metric_only ? print_metric_only_csv : print_metric_csv;
@@ -1124,6 +1124,7 @@ static int aggr_header_lens[] = {
[AGGR_SOCKET] = 12,
[AGGR_NONE] = 6,
[AGGR_THREAD] = 24,
+ [AGGR_NODE] = 6,
[AGGR_GLOBAL] = 0,
};
@@ -1133,6 +1134,7 @@ static const char *aggr_header_csv[] = {
[AGGR_SOCKET] = "socket,cpus",
[AGGR_NONE] = "cpu,",
[AGGR_THREAD] = "comm-pid,",
+ [AGGR_NODE] = "node,",
[AGGR_GLOBAL] = ""
};
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile
index 1208a105a871..886bba6c58cd 100644
--- a/tools/power/acpi/tools/acpidump/Makefile
+++ b/tools/power/acpi/tools/acpidump/Makefile
@@ -28,6 +28,7 @@ TOOL_OBJS = \
tbxfroot.o\
utascii.o\
utbuffer.o\
+ utcksum.o\
utdebug.o\
utexcep.o\
utglobal.o\
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
index d54dde02b87d..ea44b0ed5dcb 100644
--- a/tools/power/acpi/tools/acpidump/apdump.c
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -78,7 +78,9 @@ u8 ap_is_valid_checksum(struct acpi_table_header *table)
rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
status = acpi_tb_validate_rsdp(rsdp);
} else {
- status = acpi_tb_verify_checksum(table, table->length);
+ /* We don't have to check for a CDAT here, since CDAT is not in the RSDT/XSDT */
+
+ status = acpi_ut_verify_checksum(table, table->length);
}
if (ACPI_FAILURE(status)) {
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index e9b6de314654..59bfa05dec5d 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -131,9 +131,10 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \
utils/idle_monitor/hsw_ext_idle.o \
utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
+ utils/idle_monitor/rapl_monitor.o \
utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \
- utils/cpuidle-set.o
+ utils/cpuidle-set.o utils/powercap-info.o
UTIL_SRC := $(UTIL_OBJS:.o=.c)
@@ -143,9 +144,12 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
utils/helpers/bitmask.h \
utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
-LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
-LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
-LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
+LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h \
+ lib/powercap.h
+LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c \
+ lib/powercap.c
+LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o \
+ lib/powercap.o
LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
override CFLAGS += -pipe
@@ -276,6 +280,7 @@ install-lib: libcpupower
$(INSTALL) -d $(DESTDIR)${includedir}
$(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
$(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h
+ $(INSTALL_DATA) lib/powercap.h $(DESTDIR)${includedir}/powercap.h
install-tools: $(OUTPUT)cpupower
$(INSTALL) -d $(DESTDIR)${bindir}
@@ -292,6 +297,7 @@ install-man:
$(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1
$(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1
$(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1
+ $(INSTALL_DATA) -D man/cpupower-powercap-info.1 $(DESTDIR)${mandir}/man1/cpupower-powercap-info.1
install-gmo: create-gmo
$(INSTALL) -d $(DESTDIR)${localedir}
@@ -321,6 +327,7 @@ uninstall:
- rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1
- rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1
- rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1
+ - rm -f $(DESTDIR)${mandir}/man1/cpupower-powercap-info.1
- for HLANG in $(LANGUAGES); do \
rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
done;
diff --git a/tools/power/cpupower/lib/powercap.c b/tools/power/cpupower/lib/powercap.c
new file mode 100644
index 000000000000..0ce29ee4c2e4
--- /dev/null
+++ b/tools/power/cpupower/lib/powercap.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * (C) 2016 SUSE Software Solutions GmbH
+ * Thomas Renninger <trenn@suse.de>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <dirent.h>
+
+#include "powercap.h"
+
+static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
+{
+ int fd;
+ ssize_t numread;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return 0;
+
+ numread = read(fd, buf, buflen - 1);
+ if (numread < 1) {
+ close(fd);
+ return 0;
+ }
+
+ buf[numread] = '\0';
+ close(fd);
+
+ return (unsigned int) numread;
+}
+
+static int sysfs_get_enabled(char *path, int *mode)
+{
+ int fd;
+ char yes_no;
+
+ *mode = 0;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ if (read(fd, &yes_no, 1) != 1) {
+ close(fd);
+ return -1;
+ }
+
+ if (yes_no == '1') {
+ *mode = 1;
+ return 0;
+ } else if (yes_no == '0') {
+ return 0;
+ }
+ return -1;
+}
+
+int powercap_get_enabled(int *mode)
+{
+ char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/intel-rapl/enabled";
+
+ return sysfs_get_enabled(path, mode);
+}
+
+/*
+ * Hardcoded, because rapl is the only powercap implementation
+- * this needs to get more generic if more powercap implementations
+ * should show up
+ */
+int powercap_get_driver(char *driver, int buflen)
+{
+ char file[SYSFS_PATH_MAX] = PATH_TO_RAPL;
+
+ struct stat statbuf;
+
+ if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+ driver = "";
+ return -1;
+ } else if (buflen > 10) {
+ strcpy(driver, "intel-rapl");
+ return 0;
+ } else
+ return -1;
+}
+
+enum powercap_get64 {
+ GET_ENERGY_UJ,
+ GET_MAX_ENERGY_RANGE_UJ,
+ GET_POWER_UW,
+ GET_MAX_POWER_RANGE_UW,
+ MAX_GET_64_FILES
+};
+
+static const char *powercap_get64_files[MAX_GET_64_FILES] = {
+ [GET_POWER_UW] = "power_uw",
+ [GET_MAX_POWER_RANGE_UW] = "max_power_range_uw",
+ [GET_ENERGY_UJ] = "energy_uj",
+ [GET_MAX_ENERGY_RANGE_UJ] = "max_energy_range_uj",
+};
+
+static int sysfs_powercap_get64_val(struct powercap_zone *zone,
+ enum powercap_get64 which,
+ uint64_t *val)
+{
+ char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/";
+ int ret;
+ char buf[MAX_LINE_LEN];
+
+ strcat(file, zone->sys_name);
+ strcat(file, "/");
+ strcat(file, powercap_get64_files[which]);
+
+ ret = sysfs_read_file(file, buf, MAX_LINE_LEN);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -1;
+
+ *val = strtoll(buf, NULL, 10);
+ return 0;
+}
+
+int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val)
+{
+ return sysfs_powercap_get64_val(zone, GET_MAX_ENERGY_RANGE_UJ, val);
+}
+
+int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val)
+{
+ return sysfs_powercap_get64_val(zone, GET_ENERGY_UJ, val);
+}
+
+int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val)
+{
+ return sysfs_powercap_get64_val(zone, GET_MAX_POWER_RANGE_UW, val);
+}
+
+int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val)
+{
+ return sysfs_powercap_get64_val(zone, GET_POWER_UW, val);
+}
+
+int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode)
+{
+ char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
+
+ if ((strlen(PATH_TO_POWERCAP) + strlen(zone->sys_name)) +
+ strlen("/enabled") + 1 >= SYSFS_PATH_MAX)
+ return -1;
+
+ strcat(path, "/");
+ strcat(path, zone->sys_name);
+ strcat(path, "/enabled");
+
+ return sysfs_get_enabled(path, mode);
+}
+
+int powercap_zone_set_enabled(struct powercap_zone *zone, int mode)
+{
+ /* To be done if needed */
+ return 0;
+}
+
+
+int powercap_read_zone(struct powercap_zone *zone)
+{
+ struct dirent *dent;
+ DIR *zone_dir;
+ char sysfs_dir[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
+ struct powercap_zone *child_zone;
+ char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
+ int i, ret = 0;
+ uint64_t val = 0;
+
+ strcat(sysfs_dir, "/");
+ strcat(sysfs_dir, zone->sys_name);
+
+ zone_dir = opendir(sysfs_dir);
+ if (zone_dir == NULL)
+ return -1;
+
+ strcat(file, "/");
+ strcat(file, zone->sys_name);
+ strcat(file, "/name");
+ sysfs_read_file(file, zone->name, MAX_LINE_LEN);
+ if (zone->parent)
+ zone->tree_depth = zone->parent->tree_depth + 1;
+ ret = powercap_get_energy_uj(zone, &val);
+ if (ret == 0)
+ zone->has_energy_uj = 1;
+ ret = powercap_get_power_uw(zone, &val);
+ if (ret == 0)
+ zone->has_power_uw = 1;
+
+ while ((dent = readdir(zone_dir)) != NULL) {
+ struct stat st;
+
+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ if (stat(dent->d_name, &st) != 0 || !S_ISDIR(st.st_mode))
+ if (fstatat(dirfd(zone_dir), dent->d_name, &st, 0) < 0)
+ continue;
+
+ if (strncmp(dent->d_name, "intel-rapl:", 11) != 0)
+ continue;
+
+ child_zone = calloc(1, sizeof(struct powercap_zone));
+ if (child_zone == NULL)
+ return -1;
+ for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
+ if (zone->children[i] == NULL) {
+ zone->children[i] = child_zone;
+ break;
+ }
+ if (i == POWERCAP_MAX_CHILD_ZONES - 1) {
+ free(child_zone);
+ fprintf(stderr, "Reached POWERCAP_MAX_CHILD_ZONES %d\n",
+ POWERCAP_MAX_CHILD_ZONES);
+ return -1;
+ }
+ }
+ strcpy(child_zone->sys_name, zone->sys_name);
+ strcat(child_zone->sys_name, "/");
+ strcat(child_zone->sys_name, dent->d_name);
+ child_zone->parent = zone;
+ if (zone->tree_depth >= POWERCAP_MAX_TREE_DEPTH) {
+ fprintf(stderr, "Maximum zone hierarchy depth[%d] reached\n",
+ POWERCAP_MAX_TREE_DEPTH);
+ ret = -1;
+ break;
+ }
+ powercap_read_zone(child_zone);
+ }
+ closedir(zone_dir);
+ return ret;
+}
+
+struct powercap_zone *powercap_init_zones(void)
+{
+ int enabled;
+ struct powercap_zone *root_zone;
+ int ret;
+ char file[SYSFS_PATH_MAX] = PATH_TO_RAPL "/enabled";
+
+ ret = sysfs_get_enabled(file, &enabled);
+
+ if (ret)
+ return NULL;
+
+ if (!enabled)
+ return NULL;
+
+ root_zone = calloc(1, sizeof(struct powercap_zone));
+ if (!root_zone)
+ return NULL;
+
+ strcpy(root_zone->sys_name, "intel-rapl/intel-rapl:0");
+
+ powercap_read_zone(root_zone);
+
+ return root_zone;
+}
+
+/* Call function *f on the passed zone and all its children */
+
+int powercap_walk_zones(struct powercap_zone *zone,
+ int (*f)(struct powercap_zone *zone))
+{
+ int i, ret;
+
+ if (!zone)
+ return -1;
+
+ ret = f(zone);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
+ if (zone->children[i] != NULL)
+ powercap_walk_zones(zone->children[i], f);
+ }
+ return 0;
+}
diff --git a/tools/power/cpupower/lib/powercap.h b/tools/power/cpupower/lib/powercap.h
new file mode 100644
index 000000000000..c049c109f22f
--- /dev/null
+++ b/tools/power/cpupower/lib/powercap.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * (C) 2016 SUSE Software Solutions GmbH
+ * Thomas Renninger <trenn@suse.de>
+ */
+
+#ifndef __CPUPOWER_RAPL_H__
+#define __CPUPOWER_RAPL_H__
+
+#define PATH_TO_POWERCAP "/sys/devices/virtual/powercap"
+#define PATH_TO_RAPL "/sys/devices/virtual/powercap/intel-rapl"
+#define PATH_TO_RAPL_CLASS "/sys/devices/virtual/powercap/intel-rapl"
+
+#define POWERCAP_MAX_CHILD_ZONES 10
+#define POWERCAP_MAX_TREE_DEPTH 10
+
+#define MAX_LINE_LEN 4096
+#define SYSFS_PATH_MAX 255
+
+#include <stdint.h>
+
+struct powercap_zone {
+ char name[MAX_LINE_LEN];
+ /*
+ * sys_name relative to PATH_TO_POWERCAP,
+ * do not forget the / in between
+ */
+ char sys_name[SYSFS_PATH_MAX];
+ int tree_depth;
+ struct powercap_zone *parent;
+ struct powercap_zone *children[POWERCAP_MAX_CHILD_ZONES];
+ /* More possible caps or attributes to be added? */
+ uint32_t has_power_uw:1,
+ has_energy_uj:1;
+
+};
+
+int powercap_walk_zones(struct powercap_zone *zone,
+ int (*f)(struct powercap_zone *zone));
+
+struct powercap_zone *powercap_init_zones(void);
+int powercap_get_enabled(int *mode);
+int powercap_set_enabled(int mode);
+int powercap_get_driver(char *driver, int buflen);
+
+int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val);
+int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val);
+int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val);
+int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val);
+int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode);
+int powercap_zone_set_enabled(struct powercap_zone *zone, int mode);
+
+
+#endif /* __CPUPOWER_RAPL_H__ */
diff --git a/tools/power/cpupower/man/cpupower-powercap-info.1 b/tools/power/cpupower/man/cpupower-powercap-info.1
new file mode 100644
index 000000000000..df3087000efb
--- /dev/null
+++ b/tools/power/cpupower/man/cpupower-powercap-info.1
@@ -0,0 +1,25 @@
+.TH CPUPOWER\-POWERCAP\-INFO "1" "05/08/2016" "" "cpupower Manual"
+.SH NAME
+cpupower\-powercap\-info \- Shows powercapping related kernel and hardware configurations
+.SH SYNOPSIS
+.ft B
+.B cpupower powercap-info
+
+.SH DESCRIPTION
+\fBcpupower powercap-info \fP shows kernel powercapping subsystem information.
+This needs hardware support and a loaded powercapping driver (at this time only
+intel_rapl driver exits) exporting hardware values userspace via sysfs.
+
+Some options are platform wide, some affect single cores. By default values
+of core zero are displayed only. cpupower --cpu all cpuinfo will show the
+settings of all cores, see cpupower(1) how to choose specific cores.
+
+.SH "DOCUMENTATION"
+
+kernel sources:
+Documentation/power/powercap/powercap.txt
+
+
+.SH "SEE ALSO"
+
+cpupower(1)
diff --git a/tools/power/cpupower/po/ka.po b/tools/power/cpupower/po/ka.po
new file mode 100644
index 000000000000..ef71dbac5a13
--- /dev/null
+++ b/tools/power/cpupower/po/ka.po
@@ -0,0 +1,983 @@
+# Georgian translation for cpufrequtils package
+# Georgian messages for cpufrequtils.
+# Copyright (C) 2004-2022 Dominik Brodowski <linux@dominikbrodowski.net>
+# This file is distributed under the same license as the cpufrequtils package.
+# Ekaterine Papava <katopapava@gmail.com>, 2022.
+
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 006\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2022-09-18 22:12+0200\n"
+"Last-Translator: Ekaterine Papava <katopapava@gmail.com>\n"
+"Language-Team: NONE\n"
+"Language: ka\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.1.1\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr "პროცესორის ბირთვი C3"
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr "პროცესორის ბირთვი C6"
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr "პროცესორის პაკეტი C3"
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr "პროცესორის პაკეტი C6"
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr "პროცესორის Core C7"
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr "პროცესორის პაკეტი C2"
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr "პროცესორის პაკეტი C7"
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr "პაკეტი ძილის მდგომარეობაში (PC1 ან ღრმა)"
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr "პროცესორის პაკეტი C1"
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr "ჩრდილო ხიდის P1 ლოგიკური მთვლელი (აბრუნებს 0 ან 1-ს)"
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr "პროცესორის ბირთვი უქმი არაა"
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr "პროცესორის ბირთვი უქმ მდგომარეობაში არაა"
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr "საშუალო სიხშირე (პიკურის ჩათვლით) მეგაჰერცებში"
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"ინტერვალი_წმ | -c ბრძანება ...]\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"ინტერვალი_წმ | -c ბრძანება ...]\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr "\t -v: დამატებითი ინფორმაციის გამოტანა\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr "\t -h: ამ დახმარების გამოტანა\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
+msgstr ""
+"\t -i: გასაზომი დროის ინტერვალი, წამებში (ნაგულისხმები მნიშვნელობაა 1)\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr "\t -t: CPU -ის ტოპოლოგიის/იერარქიის ჩვენება\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+"\t -l: CPU-ის ძილის მონიტორების სიის გამოტანა (განკუთვნილია -m -სთან ერთად "
+"გამოსაყენებლად)\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+"\t -m: მხოლოდ მითითებული CPU-ის ძილის მონიტორების ჩვენება (იგივე "
+"მიმდევრობით)\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+"დასაშვებია მხოლოდ ერთ-ერთის: -t, -l ან -m მითითება\n"
+"თუ მითითებული არც ერთი არაა,"
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr " ნაჩვენები იქნება ყველა მხარდაჭერილი მონიტორი\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+"მონიტორი %s, მთვლელი %s. დათვლის ფუნქცია არ გააჩნია. განხორციელების შეცდომა\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr " *გათიშულია\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr "%s: მონიტორის სახელის მაქსიმალური სიგრძე (%d) გადაჭარბებულია\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr "%s-ში აღწერილი მონიტორი ვერ ვიპოვე. სცადეთ -l პარამეტრი\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr "მონიტორი \"%s\" (%d მდგომარეობა) - გადაივსება %u წამის შემდეგ\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr "%s-ს %.5f წამი დასჭირდა და მუშაობა სტატუსით %d დაასრულა\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr "ხელმისაწვდომი პროცესორების რიცხვის წაკითხვა შეუძლებელია\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr "ხელმისაწვდომ მონიტორს (%s) root-ის წვდომს სჭირდება\n"
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr "აპარატურული C-მდგომარეობის მონიტორები ვერ ვიპოვე\n"
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr "cpupower [ -c cpu-ებისსია ] ქვებრძანება [არგუმენტები]\n"
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr "cpupower --version\n"
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr "ხელმისაწვდომი ქვებრძანებებია:\n"
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+"\n"
+"ზოგიერთ ქვებრძანებას შეუძლია -c cpu-ებისსია პარამეტრი გამოიყენოს.\n"
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+"გამოყენების ინსტრუქციისთვის cpupower-ის სახელმძღვანელოში (manpage) ჩაიხედეთ\n"
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+"და წაიკითხეთ ქვებრძანების სახელმძღვანელო (manpage), თუ ის მხარდაჭერილია.\n"
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+"\n"
+"ზემოთ მოყვანილი ქვებრძანებების შესახებ ინფორმაციის მისაღებად გამოიყენეთ "
+"cpupower help ქვებრძანების_სახელი.\n"
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "გთხოვთ, შეცდომების შესახებ გვაცნობეთ აქ; %s.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr "CPU-ების სიის დამუშავების შეცდომა\n"
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr "ქვებრძანებას %s root-ის პრივილეგიები სჭირდება\n"
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr ""
+"CPU-ების (%s: %s) რაოდენობის მიღების შეცდომა. ჩაითვლება, რომ უდრის 1-ს\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+" minimum CPU frequency - maximum CPU frequency - governor\n"
+msgstr ""
+" CPU-ის მინიმალური სიხშირე - CPU-ის მაქსიმალური სიხშირე - "
+"მმართველი\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+"შეცდომა %d-ე CPU-ის პიკური დატვირთვის მართვის შესაძლებლობების შეფასებისას -- "
+"გაქვთ თუ არა root პრივილეგიები?\n"
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid " boost state support: \n"
+msgstr " პიკის მდგომარეობის მხარდაჭერა: \n"
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid " Supported: %s\n"
+msgstr " მხარდაჭერილია: %s\n"
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr "დიახ"
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr "არა"
+
+#: utils/cpufreq-info.c:164
+#, c-format
+msgid " Active: %s\n"
+msgstr " აქტიური: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid " Boost States: %d\n"
+msgstr " პიკის მდგომარეობები: %d\n"
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid " Total States: %d\n"
+msgstr " სულ მდგომარეობები: %d\n"
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid " Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr " Pstate-Pb%d: %luმჰც (პიკში)\n"
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid " Pstate-P%d: %luMHz\n"
+msgstr " Pstate-P%d: %luმჰც\n"
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid " no or unknown cpufreq driver is active on this CPU\n"
+msgstr " ამ CPU-ზე cpufreq-ის დრაივერი უცნობია, ან არ არსებობს\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid " driver: %s\n"
+msgstr " დრაივერი: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid " CPUs which run at the same hardware frequency: "
+msgstr " CPU-ები, რომლებიც ერთი და იგივე აპარატურულ სიხშირეზე მუშაობენ: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid " CPUs which need to have their frequency coordinated by software: "
+msgstr " CPU-ები, რომლებსაც მათი სიხშირის პროგრამული კოორდინაცია სჭირდებათ: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid " maximum transition latency: "
+msgstr " მაქსიმალური გარდამავალი დაყოვნება: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid " hardware limits: "
+msgstr " აპარატურული ლიმიტები: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid " available frequency steps: "
+msgstr " ხელმისაწვდომი სიხშირის ბიჯები: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid " available cpufreq governors: "
+msgstr " cpufreq -ის ხელმისაწვდომი მმართველები: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid " current policy: frequency should be within "
+msgstr " მიმდინარე პოლიტიკა: სიხშირის დიაპაზონია "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " და "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+" within this range.\n"
+msgstr ""
+"მმართველს \"%s\" შეუძლია გადაწყვიტოს, რომელი სიჩქარე გამოიყენოს\n"
+" ამ დიაპაზონიდან.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid " current CPU frequency is "
+msgstr " CPU-ის მიმდინარე სიხშირეა "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (დამტკიცებულია აპარატურული გადამოწმებით)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid " cpufreq stats: "
+msgstr " cpufreq -ის სტატისტიკა: "
+
+#: utils/cpufreq-info.c:472
+#, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "გამოყენება: cpupower freqinfo [პარამეტრები]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "პარამეტრები:\n"
+
+#: utils/cpufreq-info.c:474
+#, c-format
+msgid " -e, --debug Prints out debug information [default]\n"
+msgstr " -e, --debug გამართვის ინფორმაციის ჩვენება [ნაგულისხმები]\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+" -f, --freq Get frequency the CPU currently runs at, according\n"
+" to the cpufreq core *\n"
+msgstr ""
+" -f, --freq სიხშირის მიღება, რომლითაც CPU ამჟამად მუშაობს, \n"
+" cpufreq ბირთვის შესაბამისად *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
+" it from hardware (only available to root) *\n"
+msgstr ""
+" -w, --hwfreq სიხშირის მიღება, რომლითაც CPU ახლა მუშაობს, "
+"მნიშვნელობის\n"
+" პირდაპირ აპარატურიდან წაკითხვით (საჭიროა root-ის "
+"პრივილეგიები) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+" -l, --hwlimits Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+" -l, --hwlimits CPU-ის მინიმალური და მაქსიმალური დასაშვები სიხშირის "
+"განსაზღვრა *\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid " -d, --driver Determines the used cpufreq kernel driver *\n"
+msgstr ""
+" -d, --driver ბირთვის მიერ გამოყენებული cpufreq -ის დრაივერი *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid " -p, --policy Gets the currently used cpufreq policy *\n"
+msgstr ""
+" -p, --policy cpufreq -ის ამჟამად გამოყენებული პოლიტიკის მიღება*\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid " -g, --governors Determines available cpufreq governors *\n"
+msgstr ""
+" -g, --governors cpufreq-ის ხელმისაწვდომი მმართველების დადგენა *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+" -r, --related-cpus Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+" -r, --related-cpus განსაზღვრავს, რომელი CPU-ები მუშაობს ერთი და იგივე "
+"აპარატურულ სიხშირეზე *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
+" coordinated by software *\n"
+msgstr ""
+" -a, --affected-cpus განსაზღვრავს, რომელი CPU-ებს სჭირდებათ მათი სიხშირის\n"
+" პროგრამული კოორდინაცია *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid " -s, --stats Shows cpufreq statistics if available\n"
+msgstr ""
+" -s, --stats cpufreq -ის სტატისტიკის ჩვენება, თუ ის "
+"ხელმისაწვდომია\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+" -y, --latency Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+" -y, --latency CPU -ის სიხშირის ცვლილების მაქსიმალური დაყოვნების "
+"დადგენა *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid " -b, --boost Checks for turbo or boost modes *\n"
+msgstr " -b, --boost ტურბო და პიკური რეჟიმების შემოწმება *\n"
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+" -o, --proc Prints out information like provided by the /proc/"
+"cpufreq\n"
+" interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+" -o, --proc გამოიტანს ინფორმაციას, რომელიც /proc/cpufreq-ის "
+"მიერაა მოწოდებული.\n"
+" ეს ინტერფეისი 2.4. და ადრეულ 2.6. ბირთვებში იყო "
+"ხელმისაწვდომი\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+" -m, --human human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+" -m, --human -f, -w, -s და -y პარამეტრების გამოტანის "
+"ადამიანისთვის გასაგებ ფორმატში ჩვენება\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid " -h, --help Prints out this screen\n"
+msgstr " -h, --help ამ ეკრანის გამოტანა\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"თუ არგუმენტები საერთოდ არ გადაცემულა ან გადაცემულია -c ან --cpu, მოხდება "
+"cpufreq-ის\n"
+"დრაივერის დამატებითი შეტყობინებების გამოტანა, რომელიც გამართვისთვისაა "
+"საჭირო.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"არგუმენტებისთვის, რომლებიც *-ით არიან მონიშნულები, -c/--cpu \n"
+"არგუმენტის გამოტოვება მის ნულოვან მნიშვნელობაზე დაყენებას უდრის\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr ""
+"ამ პროგრამისთვის გადაცემული არგუმენტის --cpu არგუმენტთან გადაცემა ერთად არ "
+"შეიძლება\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"ერთ --cpu პარამეტრზე ან/და ერთ გამოტანის-შესატყვისი \n"
+"არგუმენტზე მეტის მითითება აკრძალულია\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "არასწორი ან უცნობი არგუმენტი\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "%d-ე CPU-ის ანალიზი შეუძლებელია. ის არ არსებობს\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "%d-ე CPU -ის ანალიზი:\n"
+
+#: utils/cpufreq-set.c:25
+#, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "გამოყენება: cpupower frequency-set [პარამეტრები]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+" -d FREQ, --min FREQ new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+" -d FREQ, --min FREQ CPU-ის ახალი მინიმალური სიხშირე, რომელიც "
+"მმართველს შეუძლია, აირჩიოს\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+" -u FREQ, --max FREQ new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+" -u FREQ, --max FREQ CPU-ის ახალი მაქსიმალური სიხშირე, რომელიც "
+"მმართველს შეუძლია, აირჩიოს\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid " -g GOV, --governor GOV new cpufreq governor\n"
+msgstr " -g GOV, --governor GOV cpufreq-ის ახალი მმართველი\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
+" governor to be available and loaded\n"
+msgstr ""
+" -f FREQ, --freq FREQ მითითებული სიხშირის დაყენება. საჭიროა, "
+"მომხმარებლის სივრცეში გაშვებული\n"
+" მმართველი ხელმისაწვდომი და ჩატვირთული იყოს\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid " -r, --related Switches all hardware-related CPUs\n"
+msgstr ""
+" -r, --related ყველა აპარატურულად-დაავშირებული CPU-ის გადართვა\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid " -h, --help Prints out this screen\n"
+msgstr " -h, --help ამ ეკრანის გამოტანა\n"
+
+#: utils/cpufreq-set.c:35
+#, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"შენიშვნა:\n"
+"1. -c/--cpu პარამეტრის გამოტოვება იგივეა, რაც \"all\" (ყველას) მითითება\n"
+
+#: utils/cpufreq-set.c:37
+#, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+" except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+" by postfixing the value with the wanted unit name, without any space\n"
+" (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"2. The -f FREQ, --freq FREQ პარამეტრის შეთავსება შეუძლებელია სხვა "
+"პარამეტრებთან,\n"
+" -c CPU, --cpu CPU -ის გარდა\n"
+"3. სიხშირეების გადაცემა შეიძლება ჰერცებში (hz), კილოჰერცებში, (KHz) "
+"(ნაგულისხმები), მეგაჰერცებში (MHz), GHz და THz.\n"
+" რიცხვის შემდეგ შესაბამისი ერთეულის, გამოტოვების გარეშე, მიწერით\n"
+" (სიხშირე in kHz(კილოჰერცი) =^ Hz(ჰერცი) * 0.001 =^ MHz(მეგაჰერცი) * 1000 "
+"=^ GHz(გიგაჰერცი) * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+" for example because of hardware which cannot be set to a specific "
+"frequency\n"
+" or because the userspace governor isn't loaded?\n"
+msgstr ""
+"ახალი მნიშვნელოების დაყენება შეუძლებელია. ხშირად დაშვებული შეცდომებია:\n"
+"- გაქვთ თუ არა ადმინისტრატორის უფლებები? (მომხმარებელი root)\n"
+"- არის თუ არა მოთხოვნილი მმართველი ხელმისაწვდომი და შესაბამისი მოდული "
+"modprobe-ით ჩატვირთული?\n"
+"- ცდილობთ დააყენოთ არასწორი პოლიტიკა?\n"
+"- ცდილობთ დააყენოთ განსაზღვრული სიხშირე მაშინ, როცა მომხმარებლის სივრცის "
+"მმართველი ხელმიუწვდომელია.\n"
+" მაგალითად აპარატურის გამო, რომელსაც მითითებული სიხშირის დაყენება არ "
+"შეუძლია,\n"
+" ან იქნებ მომხმარებლის სივრცის მმართველი ჩატვირთული არაა?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "არასწორი, უცნობი ან არასასურველი CPU?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"პარამეტრი -f/--freq არ შეიძლება-d/--min, -u/--max და\n"
+"-g/--governor პარამეტრებთან ერთად იყოს მითითებული\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"საჭიროა -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor პარამეტრებიდან ერთის გადაცემა მაინც\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr "CPU-ის დაყენება: %d\n"
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr "გამოყენება: cpupower set [ -b მნიშვნ ] [ -m მნიშვნ ] [ -s მნიშვნ ]\n"
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
+" Intel models [0-15], see manpage for details\n"
+msgstr ""
+" -b, --perf-bias [VAL] Intel-ის ზოგიერთ მოდელზე [0-15] CPU-ის კვებასა და "
+"წარმადობას შორის დამოკიდებულების დაყენება\n"
+" მეტი დეტალისთვის იხილეთ სახელმძღვანელო (manpage)\n"
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+" -m, --sched-mc [VAL] ბირთვის მრავალბირთვიანობის მგეგმავის პოლიტიკის "
+"დაყენება.\n"
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+" -s, --sched-smt [VAL] ბირთვის ნაკადის დის მგეგმავის პოლიტიკის "
+"დაყენება.\n"
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr "--perf-bias პარამეტრი დიაპაზონიდან [0-%d]\n"
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr "--sched-mc პარამეტრი დიაპაზონიდან [0-%d]\n"
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr "--sched-smt პარამეტრი დიაპაზონიდან [0-%d]\n"
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr "შეცდომა sched-mc -ის დაყენებისას: %s\n"
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr "შეცდომა sched-smt-ის დაყენებისას: %s\n"
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr "%d-ე CPU-ზე perf-bias -ის მნიშვნელობის დაყენების შეცდომა\n"
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr "გამოყენება: cpupower info [ -b ] [ -m ] [ -s ]\n"
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
+" Intel models [0-15], see manpage for details\n"
+msgstr ""
+" -b, --perf-bias [VAL] Intel-ის ზოგიერთ მოდელზე [0-15] CPU-ის კვებასა და "
+"წარმადობას შორის დამოკიდებულების მიღება\n"
+" მეტი დეტალისთვის იხილეთ სახელმძღვანელო (manpage)\n"
+
+#: utils/cpupower-info.c:25
+#, c-format
+msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"
+msgstr ""
+" -m, --sched-mc ბირთვის მრავალბირთვიანობის მგეგმავის პოლიტიკის მიღება.\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"
+msgstr " -s, --sched-smt ბირთვის ნაკადის დის მგეგმავის პოლიტიკის მიღება.\n"
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+"\n"
+"მნიშვნელობის არ-გადაცემის შემთხვევაში ნაჩვენები იქნება სრული ინფორმაცია. "
+"ნაგულისხმევად მხოლოდ ნულოვან ბირთვზე\n"
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr "სისტემის მრავალბირთვიანობის მმართველის პარამეტრი: "
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr "მხარდაუჭერელია\n"
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr "სისტემის ნაკადის დის მართვის პარამეტრი: "
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr "Intel-ის წარმადობის bias-ის დაყენებას root-ის პრივილეგიები სჭირდება\n"
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+"სისტემას intel-ის performance bias-ის დაყენების მხარდაჭერა არ გააჩნია\n"
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr "შეცდომა perf-bias -ის მნიშვნელობის წაკითხვისას\n"
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr "perf-bias: %d\n"
+
+#: utils/cpuidle-info.c:28
+#, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "%d-ე CPU -ის ანალიზი:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr "CPU %u: უქმი მდგომარეობების გარეშე\n"
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr "CPU %u: უქმი მდგომარეობის ინფორმაციის წაკითხვა შეუძლებელია\n"
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr "მაქსიმალური უქმე მდგომარეობის %u დადგენის შეცდომა\n"
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr "უქმე მდგომარეობების რაოდენობა: %d\n"
+
+#: utils/cpuidle-info.c:48
+#, c-format
+msgid "Available idle states:"
+msgstr "ხელმისაწვდომი უქმე მდგომარეობები:"
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr "ალმები/აღწერა: %s\n"
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr "დაყოვება: %lu\n"
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr "გამოყენება: %lu\n"
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr "ხანგრძლივობა: %llu\n"
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr "CPUidle-ის დრაივერის დადგენის შეცდომა\n"
+
+#: utils/cpuidle-info.c:94
+#, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "CPUidle -ის დრაივერი: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr "CPUidle-ის მმართველის დადგენის შეცდომა\n"
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr "CPUidle მმართველი: %s\n"
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr "CPU %u: C-state -ის ინფორმაციის წაკითხვის შეცდომა\n"
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state: C0\n"
+msgstr "აქტიური მდგომარეობა: C0\n"
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate: C%u\n"
+msgstr "max_cstate: C%u\n"
+
+#: utils/cpuidle-info.c:129
+#, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "მაქსიმალური დასაშვები დაყოვნება: %lu usec\n"
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr "მდგომარეობები:\t\n"
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid " C%d: type[C%d] "
+msgstr " C%d: ტიპი[C%d] "
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr "promotion[--] demotion[--] "
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr "დაყოვნება[%03lu] "
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr "გამოყენება[%08lu] "
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr "ხანგრძლივობა[%020Lu] \n"
+
+#: utils/cpuidle-info.c:147
+#, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "გამოყენება: cpupower idleinfo [პარამეტრები]\n"
+
+#: utils/cpuidle-info.c:149
+#, c-format
+msgid " -s, --silent Only show general C-state information\n"
+msgstr " -s, --silent მხოლოდ ზოგადი C-state -ის ინფორმაციის ჩვენება\n"
+
+#: utils/cpuidle-info.c:150
+#, c-format
+msgid ""
+" -o, --proc Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+" interface in older kernels\n"
+msgstr ""
+" -o, --proc გამოაქვს ინფორმაცია, როგორც ის /proc/acpi/processor/*/"
+"power ფაილშია აღწერილი.\n"
+" ინტერფეისი ძველ ბირთვებში იყო ხელმისაწვდომი\n"
+
+#: utils/cpuidle-info.c:209
+#, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr "ერთზე მეტი გამოტანის-შესატყვისი არგუმენტის მითითება აკრძალულია\n"
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index f7065ae60a14..e1caefd467cd 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -8,6 +8,8 @@ extern int cmd_freq_set(int argc, const char **argv);
extern int cmd_freq_info(int argc, const char **argv);
extern int cmd_idle_set(int argc, const char **argv);
extern int cmd_idle_info(int argc, const char **argv);
+extern int cmd_cap_info(int argc, const char **argv);
+extern int cmd_cap_set(int argc, const char **argv);
extern int cmd_monitor(int argc, const char **argv);
#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 0646f615fe2d..c96b77365c63 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -572,9 +572,9 @@ int cmd_freq_info(int argc, char **argv)
ret = 0;
- /* Default is: show output of CPU 0 only */
+ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen))
- bitmask_setbit(cpus_chosen, 0);
+ bitmask_setbit(cpus_chosen, base_cpu);
switch (output_param) {
case -1:
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index f2b202c5552a..44126a87fa7a 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -176,9 +176,9 @@ int cmd_idle_info(int argc, char **argv)
cpuidle_exit(EXIT_FAILURE);
}
- /* Default is: show output of CPU 0 only */
+ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen))
- bitmask_setbit(cpus_chosen, 0);
+ bitmask_setbit(cpus_chosen, base_cpu);
if (output_param == 0)
cpuidle_general_output();
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 06345b543786..18fd7751f509 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -67,9 +67,9 @@ int cmd_info(int argc, char **argv)
if (!params.params)
params.params = 0x7;
- /* Default is: show output of CPU 0 only */
+ /* Default is: show output of base_cpu only */
if (bitmask_isallclear(cpus_chosen))
- bitmask_setbit(cpus_chosen, 0);
+ bitmask_setbit(cpus_chosen, base_cpu);
/* Add more per cpu options here */
if (!params.perf_bias)
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 8ac3304a9957..9ec973165af1 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -54,6 +54,7 @@ static struct cmd_struct commands[] = {
{ "frequency-set", cmd_freq_set, 1 },
{ "idle-info", cmd_idle_info, 0 },
{ "idle-set", cmd_idle_set, 1 },
+ { "powercap-info", cmd_cap_info, 0 },
{ "set", cmd_set, 1 },
{ "info", cmd_info, 0 },
{ "monitor", cmd_monitor, 0 },
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index 7c77045fef52..075e766ff1f3 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -459,9 +459,10 @@ int cmd_monitor(int argc, char **argv)
print_results(1, cpu);
}
- for (num = 0; num < avail_monitors; num++)
- monitors[num]->unregister();
-
+ for (num = 0; num < avail_monitors; num++) {
+ if (monitors[num]->unregister)
+ monitors[num]->unregister();
+ }
cpu_topology_release(cpu_top);
return 0;
}
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
index 0d6ba4dbb9c7..7c926e90c87e 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -4,5 +4,6 @@ DEF(intel_nhm)
DEF(intel_snb)
DEF(intel_hsw_ext)
DEF(mperf)
+DEF(rapl)
#endif
DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/rapl_monitor.c b/tools/power/cpupower/utils/idle_monitor/rapl_monitor.c
new file mode 100644
index 000000000000..46153f1291c3
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/rapl_monitor.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * (C) 2016 SUSE Software Solutions GmbH
+ * Thomas Renninger <trenn@suse.de>
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+
+#include <pci/pci.h>
+
+#include "idle_monitor/cpupower-monitor.h"
+#include "helpers/helpers.h"
+#include "powercap.h"
+
+#define MAX_RAPL_ZONES 10
+
+int rapl_zone_count;
+cstate_t rapl_zones[MAX_RAPL_ZONES];
+struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 };
+
+unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES];
+unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES];
+unsigned long long rapl_max_count;
+
+static int rapl_get_count_uj(unsigned int id, unsigned long long *count,
+ unsigned int cpu)
+{
+ if (rapl_zones_pt[id] == NULL)
+ /* error */
+ return -1;
+
+ *count = rapl_zone_current_count[id] - rapl_zone_previous_count[id];
+
+ return 0;
+}
+
+static int powercap_count_zones(struct powercap_zone *zone)
+{
+ uint64_t val;
+ int uj;
+
+ if (rapl_zone_count >= MAX_RAPL_ZONES)
+ return -1;
+
+ if (!zone->has_energy_uj)
+ return 0;
+
+ printf("%s\n", zone->sys_name);
+ uj = powercap_get_energy_uj(zone, &val);
+ printf("%d\n", uj);
+
+ strncpy(rapl_zones[rapl_zone_count].name, zone->name, CSTATE_NAME_LEN - 1);
+ strcpy(rapl_zones[rapl_zone_count].desc, "");
+ rapl_zones[rapl_zone_count].id = rapl_zone_count;
+ rapl_zones[rapl_zone_count].range = RANGE_MACHINE;
+ rapl_zones[rapl_zone_count].get_count = rapl_get_count_uj;
+ rapl_zones_pt[rapl_zone_count] = zone;
+ rapl_zone_count++;
+
+ return 0;
+}
+
+static int rapl_start(void)
+{
+ int i, ret;
+ uint64_t uj_val;
+
+ for (i = 0; i < rapl_zone_count; i++) {
+ ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);
+ if (ret)
+ return ret;
+ rapl_zone_previous_count[i] = uj_val;
+ }
+
+ return 0;
+}
+
+static int rapl_stop(void)
+{
+ int i;
+ uint64_t uj_val;
+
+ for (i = 0; i < rapl_zone_count; i++) {
+ int ret;
+
+ ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);
+ if (ret)
+ return ret;
+ rapl_zone_current_count[i] = uj_val;
+ if (rapl_max_count < uj_val)
+ rapl_max_count = uj_val - rapl_zone_previous_count[i];
+ }
+ return 0;
+}
+
+struct cpuidle_monitor *rapl_register(void)
+{
+ struct powercap_zone *root_zone;
+ char line[MAX_LINE_LEN] = "";
+ int ret, val;
+
+ ret = powercap_get_driver(line, MAX_LINE_LEN);
+ if (ret < 0) {
+ dprint("No powercapping driver loaded\n");
+ return NULL;
+ }
+
+ dprint("Driver: %s\n", line);
+ ret = powercap_get_enabled(&val);
+ if (ret < 0)
+ return NULL;
+ if (!val) {
+ dprint("Powercapping is disabled\n");
+ return NULL;
+ }
+
+ dprint("Powercap domain hierarchy:\n\n");
+ root_zone = powercap_init_zones();
+
+ if (root_zone == NULL) {
+ dprint("No powercap info found\n");
+ return NULL;
+ }
+
+ powercap_walk_zones(root_zone, powercap_count_zones);
+ rapl_monitor.hw_states_num = rapl_zone_count;
+
+ return &rapl_monitor;
+}
+
+struct cpuidle_monitor rapl_monitor = {
+ .name = "RAPL",
+ .hw_states = rapl_zones,
+ .hw_states_num = 0,
+ .start = rapl_start,
+ .stop = rapl_stop,
+ .do_register = rapl_register,
+ .flags.needs_root = 0,
+ .overflow_s = 60 * 60 * 24 * 100, /* To be implemented */
+};
+
+#endif
diff --git a/tools/power/cpupower/utils/powercap-info.c b/tools/power/cpupower/utils/powercap-info.c
new file mode 100644
index 000000000000..3ea4486f1a0e
--- /dev/null
+++ b/tools/power/cpupower/utils/powercap-info.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * (C) 2016 SUSE Software Solutions GmbH
+ * Thomas Renninger <trenn@suse.de>
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "powercap.h"
+#include "helpers/helpers.h"
+
+int powercap_show_all;
+
+static struct option info_opts[] = {
+ { "all", no_argument, NULL, 'a'},
+ { },
+};
+
+static int powercap_print_one_zone(struct powercap_zone *zone)
+{
+ int mode, i, ret = 0;
+ char pr_prefix[1024] = "";
+
+ for (i = 0; i < zone->tree_depth && i < POWERCAP_MAX_TREE_DEPTH; i++)
+ strcat(pr_prefix, "\t");
+
+ printf("%sZone: %s", pr_prefix, zone->name);
+ ret = powercap_zone_get_enabled(zone, &mode);
+ if (ret < 0)
+ return ret;
+ printf(" (%s)\n", mode ? "enabled" : "disabled");
+
+ if (zone->has_power_uw)
+ printf(_("%sPower can be monitored in micro Jules\n"),
+ pr_prefix);
+
+ if (zone->has_energy_uj)
+ printf(_("%sPower can be monitored in micro Watts\n"),
+ pr_prefix);
+
+ printf("\n");
+
+ if (ret != 0)
+ return ret;
+ return ret;
+}
+
+static int powercap_show(void)
+{
+ struct powercap_zone *root_zone;
+ char line[MAX_LINE_LEN] = "";
+ int ret, val;
+
+ ret = powercap_get_driver(line, MAX_LINE_LEN);
+ if (ret < 0) {
+ printf(_("No powercapping driver loaded\n"));
+ return ret;
+ }
+
+ printf("Driver: %s\n", line);
+ ret = powercap_get_enabled(&val);
+ if (ret < 0)
+ return ret;
+ if (!val) {
+ printf(_("Powercapping is disabled\n"));
+ return -1;
+ }
+
+ printf(_("Powercap domain hierarchy:\n\n"));
+ root_zone = powercap_init_zones();
+
+ if (root_zone == NULL) {
+ printf(_("No powercap info found\n"));
+ return 1;
+ }
+
+ powercap_walk_zones(root_zone, powercap_print_one_zone);
+
+ return 0;
+}
+
+int cmd_cap_set(int argc, char **argv)
+{
+ return 0;
+};
+int cmd_cap_info(int argc, char **argv)
+{
+ int ret = 0, cont = 1;
+
+ do {
+ ret = getopt_long(argc, argv, "a", info_opts, NULL);
+ switch (ret) {
+ case '?':
+ cont = 0;
+ break;
+ case -1:
+ cont = 0;
+ break;
+ case 'a':
+ powercap_show_all = 1;
+ break;
+ default:
+ fprintf(stderr, _("invalid or unknown argument\n"));
+ return EXIT_FAILURE;
+ }
+ } while (cont);
+
+ powercap_show();
+ return 0;
+}
diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py
index cfe343306e08..c60c90f35d18 100755
--- a/tools/power/pm-graph/sleepgraph.py
+++ b/tools/power/pm-graph/sleepgraph.py
@@ -1462,7 +1462,7 @@ class Data:
'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
'ABORT' : r'(?i).*\bABORT\b.*',
'IRQ' : r'.*\bgenirq: .*',
- 'TASKFAIL': r'.*Freezing of tasks *.*',
+ 'TASKFAIL': r'.*Freezing .*after *.*',
'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
'DISKFULL': r'.*\bNo space left on device.*',
'USBERR' : r'.*usb .*device .*, error [0-9-]*',
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild
index 500be85729cc..0805f08af8b3 100644
--- a/tools/testing/cxl/Kbuild
+++ b/tools/testing/cxl/Kbuild
@@ -10,6 +10,7 @@ ldflags-y += --wrap=devm_cxl_add_passthrough_decoder
ldflags-y += --wrap=devm_cxl_enumerate_decoders
ldflags-y += --wrap=cxl_await_media_ready
ldflags-y += --wrap=cxl_hdm_decode_init
+ldflags-y += --wrap=cxl_rcrb_to_component
DRIVERS := ../../../drivers
CXL_SRC := $(DRIVERS)/cxl
@@ -26,6 +27,7 @@ cxl_acpi-y += config_check.o
obj-m += cxl_pmem.o
cxl_pmem-y := $(CXL_SRC)/pmem.o
+cxl_pmem-y += $(CXL_SRC)/security.o
cxl_pmem-y += config_check.o
obj-m += cxl_port.o
diff --git a/tools/testing/cxl/config_check.c b/tools/testing/cxl/config_check.c
index de5e5b3652fd..c4c457e59841 100644
--- a/tools/testing/cxl/config_check.c
+++ b/tools/testing/cxl/config_check.c
@@ -10,4 +10,6 @@ void check(void)
BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_BUS));
BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_ACPI));
BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_PMEM));
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST));
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST));
}
diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
index 7edce12fd2ce..30ee680d38ff 100644
--- a/tools/testing/cxl/test/cxl.c
+++ b/tools/testing/cxl/test/cxl.c
@@ -11,11 +11,15 @@
#include <cxlmem.h>
#include "mock.h"
+static int interleave_arithmetic;
+
#define NR_CXL_HOST_BRIDGES 2
#define NR_CXL_SINGLE_HOST 1
+#define NR_CXL_RCH 1
#define NR_CXL_ROOT_PORTS 2
#define NR_CXL_SWITCH_PORTS 2
#define NR_CXL_PORT_DECODERS 8
+#define NR_BRIDGES (NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + NR_CXL_RCH)
static struct platform_device *cxl_acpi;
static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
@@ -35,6 +39,8 @@ static struct platform_device *cxl_swd_single[NR_MEM_SINGLE];
struct platform_device *cxl_mem[NR_MEM_MULTI];
struct platform_device *cxl_mem_single[NR_MEM_SINGLE];
+static struct platform_device *cxl_rch[NR_CXL_RCH];
+static struct platform_device *cxl_rcd[NR_CXL_RCH];
static inline bool is_multi_bridge(struct device *dev)
{
@@ -57,7 +63,7 @@ static inline bool is_single_bridge(struct device *dev)
}
static struct acpi_device acpi0017_mock;
-static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST] = {
+static struct acpi_device host_bridge[NR_BRIDGES] = {
[0] = {
.handle = &host_bridge[0],
},
@@ -67,7 +73,9 @@ static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST]
[2] = {
.handle = &host_bridge[2],
},
-
+ [3] = {
+ .handle = &host_bridge[3],
+ },
};
static bool is_mock_dev(struct device *dev)
@@ -80,6 +88,9 @@ static bool is_mock_dev(struct device *dev)
for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++)
if (dev == &cxl_mem_single[i]->dev)
return true;
+ for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++)
+ if (dev == &cxl_rcd[i]->dev)
+ return true;
if (dev == &cxl_acpi->dev)
return true;
return false;
@@ -101,7 +112,7 @@ static bool is_mock_adev(struct acpi_device *adev)
static struct {
struct acpi_table_cedt cedt;
- struct acpi_cedt_chbs chbs[NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST];
+ struct acpi_cedt_chbs chbs[NR_BRIDGES];
struct {
struct acpi_cedt_cfmws cfmws;
u32 target[1];
@@ -122,6 +133,26 @@ static struct {
struct acpi_cedt_cfmws cfmws;
u32 target[1];
} cfmws4;
+ struct {
+ struct acpi_cedt_cfmws cfmws;
+ u32 target[1];
+ } cfmws5;
+ struct {
+ struct acpi_cedt_cfmws cfmws;
+ u32 target[1];
+ } cfmws6;
+ struct {
+ struct acpi_cedt_cfmws cfmws;
+ u32 target[2];
+ } cfmws7;
+ struct {
+ struct acpi_cedt_cfmws cfmws;
+ u32 target[4];
+ } cfmws8;
+ struct {
+ struct acpi_cedt_cxims cxims;
+ u64 xormap_list[2];
+ } cxims0;
} __packed mock_cedt = {
.cedt = {
.header = {
@@ -154,6 +185,14 @@ static struct {
.uid = 2,
.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
},
+ .chbs[3] = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CHBS,
+ .length = sizeof(mock_cedt.chbs[0]),
+ },
+ .uid = 3,
+ .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL11,
+ },
.cfmws0 = {
.cfmws = {
.header = {
@@ -229,6 +268,81 @@ static struct {
},
.target = { 2 },
},
+ .cfmws5 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
+ .length = sizeof(mock_cedt.cfmws5),
+ },
+ .interleave_ways = 0,
+ .granularity = 4,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
+ .qtg_id = 5,
+ .window_size = SZ_256M,
+ },
+ .target = { 3 },
+ },
+ /* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */
+ .cfmws6 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
+ .length = sizeof(mock_cedt.cfmws6),
+ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 0,
+ .granularity = 4,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 0,
+ .window_size = SZ_256M * 8UL,
+ },
+ .target = { 0, },
+ },
+ .cfmws7 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
+ .length = sizeof(mock_cedt.cfmws7),
+ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 1,
+ .granularity = 0,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 1,
+ .window_size = SZ_256M * 8UL,
+ },
+ .target = { 0, 1, },
+ },
+ .cfmws8 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
+ .length = sizeof(mock_cedt.cfmws8),
+ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 2,
+ .granularity = 0,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 0,
+ .window_size = SZ_256M * 16UL,
+ },
+ .target = { 0, 1, 0, 1, },
+ },
+ .cxims0 = {
+ .cxims = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CXIMS,
+ .length = sizeof(mock_cedt.cxims0),
+ },
+ .hbig = 0,
+ .nr_xormaps = 2,
+ },
+ .xormap_list = { 0x404100, 0x808200, },
+ },
};
struct acpi_cedt_cfmws *mock_cfmws[] = {
@@ -237,6 +351,22 @@ struct acpi_cedt_cfmws *mock_cfmws[] = {
[2] = &mock_cedt.cfmws2.cfmws,
[3] = &mock_cedt.cfmws3.cfmws,
[4] = &mock_cedt.cfmws4.cfmws,
+ [5] = &mock_cedt.cfmws5.cfmws,
+ /* Modulo Math above, XOR Math below */
+ [6] = &mock_cedt.cfmws6.cfmws,
+ [7] = &mock_cedt.cfmws7.cfmws,
+ [8] = &mock_cedt.cfmws8.cfmws,
+};
+
+static int cfmws_start;
+static int cfmws_end;
+#define CFMWS_MOD_ARRAY_START 0
+#define CFMWS_MOD_ARRAY_END 5
+#define CFMWS_XOR_ARRAY_START 6
+#define CFMWS_XOR_ARRAY_END 8
+
+struct acpi_cedt_cxims *mock_cxims[1] = {
+ [0] = &mock_cedt.cxims0.cxims,
};
struct cxl_mock_res {
@@ -262,11 +392,11 @@ static void depopulate_all_mock_resources(void)
mutex_unlock(&mock_res_lock);
}
-static struct cxl_mock_res *alloc_mock_res(resource_size_t size)
+static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
{
struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
struct genpool_data_align data = {
- .align = SZ_256M,
+ .align = align,
};
unsigned long phys;
@@ -301,17 +431,17 @@ static int populate_cedt(void)
else
size = ACPI_CEDT_CHBS_LENGTH_CXL11;
- res = alloc_mock_res(size);
+ res = alloc_mock_res(size, size);
if (!res)
return -ENOMEM;
chbs->base = res->range.start;
chbs->length = size;
}
- for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
+ for (i = cfmws_start; i <= cfmws_end; i++) {
struct acpi_cedt_cfmws *window = mock_cfmws[i];
- res = alloc_mock_res(window->window_size);
+ res = alloc_mock_res(window->window_size, SZ_256M);
if (!res)
return -ENOMEM;
window->base_hpa = res->range.start;
@@ -320,10 +450,12 @@ static int populate_cedt(void)
return 0;
}
+static bool is_mock_port(struct device *dev);
+
/*
- * WARNING, this hack assumes the format of 'struct
- * cxl_cfmws_context' and 'struct cxl_chbs_context' share the property that
- * the first struct member is the device being probed by the cxl_acpi
+ * WARNING, this hack assumes the format of 'struct cxl_cfmws_context'
+ * and 'struct cxl_chbs_context' share the property that the first
+ * struct member is a cxl_test device being probed by the cxl_acpi
* driver.
*/
struct cxl_cedt_context {
@@ -340,7 +472,7 @@ static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
unsigned long end;
int i;
- if (dev != &cxl_acpi->dev)
+ if (!is_mock_port(dev) && !is_mock_dev(dev))
return acpi_table_parse_cedt(id, handler_arg, arg);
if (id == ACPI_CEDT_TYPE_CHBS)
@@ -351,12 +483,19 @@ static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
}
if (id == ACPI_CEDT_TYPE_CFMWS)
- for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
+ for (i = cfmws_start; i <= cfmws_end; i++) {
h = (union acpi_subtable_headers *) mock_cfmws[i];
end = (unsigned long) h + mock_cfmws[i]->header.length;
handler_arg(h, arg, end);
}
+ if (id == ACPI_CEDT_TYPE_CXIMS)
+ for (i = 0; i < ARRAY_SIZE(mock_cxims); i++) {
+ h = (union acpi_subtable_headers *)mock_cxims[i];
+ end = (unsigned long)h + mock_cxims[i]->header.length;
+ handler_arg(h, arg, end);
+ }
+
return 0;
}
@@ -370,6 +509,10 @@ static bool is_mock_bridge(struct device *dev)
for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
if (dev == &cxl_hb_single[i]->dev)
return true;
+ for (i = 0; i < ARRAY_SIZE(cxl_rch); i++)
+ if (dev == &cxl_rch[i]->dev)
+ return true;
+
return false;
}
@@ -439,14 +582,21 @@ mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,
return AE_OK;
}
-static struct pci_bus mock_pci_bus[NR_CXL_HOST_BRIDGES];
-static struct acpi_pci_root mock_pci_root[NR_CXL_HOST_BRIDGES] = {
+static struct pci_bus mock_pci_bus[NR_BRIDGES];
+static struct acpi_pci_root mock_pci_root[ARRAY_SIZE(mock_pci_bus)] = {
[0] = {
.bus = &mock_pci_bus[0],
},
[1] = {
.bus = &mock_pci_bus[1],
},
+ [2] = {
+ .bus = &mock_pci_bus[2],
+ },
+ [3] = {
+ .bus = &mock_pci_bus[3],
+ },
+
};
static bool is_mock_bus(struct pci_bus *bus)
@@ -634,7 +784,6 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
{
- struct device *dev = &port->dev;
struct platform_device **array;
int i, array_size;
@@ -684,19 +833,22 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,
CXL_RESOURCE_NONE);
- if (IS_ERR(dport)) {
- dev_err(dev, "failed to add dport: %s (%ld)\n",
- dev_name(&pdev->dev), PTR_ERR(dport));
+ if (IS_ERR(dport))
return PTR_ERR(dport);
- }
-
- dev_dbg(dev, "add dport%d: %s\n", pdev->id,
- dev_name(&pdev->dev));
}
return 0;
}
+resource_size_t mock_cxl_rcrb_to_component(struct device *dev,
+ resource_size_t rcrb,
+ enum cxl_rcrb which)
+{
+ dev_dbg(dev, "rcrb: %pa which: %d\n", &rcrb, which);
+
+ return (resource_size_t) which + 1;
+}
+
static struct cxl_mock_ops cxl_mock_ops = {
.is_mock_adev = is_mock_adev,
.is_mock_bridge = is_mock_bridge,
@@ -705,6 +857,7 @@ static struct cxl_mock_ops cxl_mock_ops = {
.is_mock_dev = is_mock_dev,
.acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
.acpi_evaluate_integer = mock_acpi_evaluate_integer,
+ .cxl_rcrb_to_component = mock_cxl_rcrb_to_component,
.acpi_pci_find_root = mock_acpi_pci_find_root,
.devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
.devm_cxl_setup_hdm = mock_cxl_setup_hdm,
@@ -729,6 +882,87 @@ static void mock_companion(struct acpi_device *adev, struct device *dev)
#define SZ_512G (SZ_64G * 8)
#endif
+static __init int cxl_rch_init(void)
+{
+ int rc, i;
+
+ for (i = 0; i < ARRAY_SIZE(cxl_rch); i++) {
+ int idx = NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + i;
+ struct acpi_device *adev = &host_bridge[idx];
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("cxl_host_bridge", idx);
+ if (!pdev)
+ goto err_bridge;
+
+ mock_companion(adev, &pdev->dev);
+ rc = platform_device_add(pdev);
+ if (rc) {
+ platform_device_put(pdev);
+ goto err_bridge;
+ }
+
+ cxl_rch[i] = pdev;
+ mock_pci_bus[idx].bridge = &pdev->dev;
+ rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
+ "firmware_node");
+ if (rc)
+ goto err_bridge;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
+ int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
+ struct platform_device *rch = cxl_rch[i];
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("cxl_rcd", idx);
+ if (!pdev)
+ goto err_mem;
+ pdev->dev.parent = &rch->dev;
+ set_dev_node(&pdev->dev, i % 2);
+
+ rc = platform_device_add(pdev);
+ if (rc) {
+ platform_device_put(pdev);
+ goto err_mem;
+ }
+ cxl_rcd[i] = pdev;
+ }
+
+ return 0;
+
+err_mem:
+ for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_rcd[i]);
+err_bridge:
+ for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
+ struct platform_device *pdev = cxl_rch[i];
+
+ if (!pdev)
+ continue;
+ sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
+ platform_device_unregister(cxl_rch[i]);
+ }
+
+ return rc;
+}
+
+static void cxl_rch_exit(void)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_rcd[i]);
+ for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
+ struct platform_device *pdev = cxl_rch[i];
+
+ if (!pdev)
+ continue;
+ sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
+ platform_device_unregister(cxl_rch[i]);
+ }
+}
+
static __init int cxl_single_init(void)
{
int i, rc;
@@ -751,6 +985,7 @@ static __init int cxl_single_init(void)
}
cxl_hb_single[i] = pdev;
+ mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev;
rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
"physical_node");
if (rc)
@@ -897,6 +1132,16 @@ static __init int cxl_test_init(void)
if (rc)
goto err_gen_pool_add;
+ if (interleave_arithmetic == 1) {
+ cfmws_start = CFMWS_XOR_ARRAY_START;
+ cfmws_end = CFMWS_XOR_ARRAY_END;
+ dev_dbg(NULL, "cxl_test loading xor math option\n");
+ } else {
+ cfmws_start = CFMWS_MOD_ARRAY_START;
+ cfmws_end = CFMWS_MOD_ARRAY_END;
+ dev_dbg(NULL, "cxl_test loading modulo math option\n");
+ }
+
rc = populate_cedt();
if (rc)
goto err_populate;
@@ -917,6 +1162,7 @@ static __init int cxl_test_init(void)
}
cxl_host_bridge[i] = pdev;
+ mock_pci_bus[i].bridge = &pdev->dev;
rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
"physical_node");
if (rc)
@@ -999,9 +1245,13 @@ static __init int cxl_test_init(void)
if (rc)
goto err_mem;
+ rc = cxl_rch_init();
+ if (rc)
+ goto err_single;
+
cxl_acpi = platform_device_alloc("cxl_acpi", 0);
if (!cxl_acpi)
- goto err_single;
+ goto err_rch;
mock_companion(&acpi0017_mock, &cxl_acpi->dev);
acpi0017_mock.dev.bus = &platform_bus_type;
@@ -1014,6 +1264,8 @@ static __init int cxl_test_init(void)
err_add:
platform_device_put(cxl_acpi);
+err_rch:
+ cxl_rch_exit();
err_single:
cxl_single_exit();
err_mem:
@@ -1051,6 +1303,7 @@ static __exit void cxl_test_exit(void)
int i;
platform_device_unregister(cxl_acpi);
+ cxl_rch_exit();
cxl_single_exit();
for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
platform_device_unregister(cxl_mem[i]);
@@ -1073,6 +1326,8 @@ static __exit void cxl_test_exit(void)
unregister_cxl_mock_ops(&cxl_mock_ops);
}
+module_param(interleave_arithmetic, int, 0000);
+MODULE_PARM_DESC(interleave_arithmetic, "Modulo:0, XOR:1");
module_init(cxl_test_init);
module_exit(cxl_test_exit);
MODULE_LICENSE("GPL v2");
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index aa2df3a15051..5e4ecd93f1d2 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -65,6 +65,18 @@ static struct {
},
};
+#define PASS_TRY_LIMIT 3
+
+struct cxl_mockmem_data {
+ void *lsa;
+ u32 security_state;
+ u8 user_pass[NVDIMM_PASSPHRASE_LEN];
+ u8 master_pass[NVDIMM_PASSPHRASE_LEN];
+ int user_limit;
+ int master_limit;
+
+};
+
static int mock_gsl(struct cxl_mbox_cmd *cmd)
{
if (cmd->size_out < sizeof(mock_gsl_payload))
@@ -100,6 +112,24 @@ static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
return 0;
}
+static int mock_rcd_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mbox_identify id = {
+ .fw_revision = { "mock fw v1 " },
+ .total_capacity =
+ cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
+ .volatile_capacity =
+ cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
+ };
+
+ if (cmd->size_out < sizeof(id))
+ return -EINVAL;
+
+ memcpy(cmd->payload_out, &id, sizeof(id));
+
+ return 0;
+}
+
static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{
struct cxl_mbox_identify id = {
@@ -137,10 +167,334 @@ static int mock_partition_info(struct cxl_dev_state *cxlds,
return 0;
}
+static int mock_get_security_state(struct cxl_dev_state *cxlds,
+ struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+
+ if (cmd->size_in)
+ return -EINVAL;
+
+ if (cmd->size_out != sizeof(u32))
+ return -EINVAL;
+
+ memcpy(cmd->payload_out, &mdata->security_state, sizeof(u32));
+
+ return 0;
+}
+
+static void master_plimit_check(struct cxl_mockmem_data *mdata)
+{
+ if (mdata->master_limit == PASS_TRY_LIMIT)
+ return;
+ mdata->master_limit++;
+ if (mdata->master_limit == PASS_TRY_LIMIT)
+ mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
+}
+
+static void user_plimit_check(struct cxl_mockmem_data *mdata)
+{
+ if (mdata->user_limit == PASS_TRY_LIMIT)
+ return;
+ mdata->user_limit++;
+ if (mdata->user_limit == PASS_TRY_LIMIT)
+ mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
+}
+
+static int mock_set_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+ struct cxl_set_pass *set_pass;
+
+ if (cmd->size_in != sizeof(*set_pass))
+ return -EINVAL;
+
+ if (cmd->size_out != 0)
+ return -EINVAL;
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ set_pass = cmd->payload_in;
+ switch (set_pass->type) {
+ case CXL_PMEM_SEC_PASS_MASTER:
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+ /*
+ * CXL spec rev3.0 8.2.9.8.6.2, The master pasphrase shall only be set in
+ * the security disabled state when the user passphrase is not set.
+ */
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+ if (memcmp(mdata->master_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
+ master_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+ memcpy(mdata->master_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
+ mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PASS_SET;
+ return 0;
+
+ case CXL_PMEM_SEC_PASS_USER:
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+ if (memcmp(mdata->user_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
+ user_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+ memcpy(mdata->user_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
+ mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PASS_SET;
+ return 0;
+
+ default:
+ cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
+ }
+ return -EINVAL;
+}
+
+static int mock_disable_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+ struct cxl_disable_pass *dis_pass;
+
+ if (cmd->size_in != sizeof(*dis_pass))
+ return -EINVAL;
+
+ if (cmd->size_out != 0)
+ return -EINVAL;
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ dis_pass = cmd->payload_in;
+ switch (dis_pass->type) {
+ case CXL_PMEM_SEC_PASS_MASTER:
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (memcmp(dis_pass->pass, mdata->master_pass, NVDIMM_PASSPHRASE_LEN)) {
+ master_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+
+ mdata->master_limit = 0;
+ memset(mdata->master_pass, 0, NVDIMM_PASSPHRASE_LEN);
+ mdata->security_state &= ~CXL_PMEM_SEC_STATE_MASTER_PASS_SET;
+ return 0;
+
+ case CXL_PMEM_SEC_PASS_USER:
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (memcmp(dis_pass->pass, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
+ user_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+
+ mdata->user_limit = 0;
+ memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
+ mdata->security_state &= ~(CXL_PMEM_SEC_STATE_USER_PASS_SET |
+ CXL_PMEM_SEC_STATE_LOCKED);
+ return 0;
+
+ default:
+ cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mock_freeze_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+
+ if (cmd->size_in != 0)
+ return -EINVAL;
+
+ if (cmd->size_out != 0)
+ return -EINVAL;
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN)
+ return 0;
+
+ mdata->security_state |= CXL_PMEM_SEC_STATE_FROZEN;
+ return 0;
+}
+
+static int mock_unlock_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+
+ if (cmd->size_in != NVDIMM_PASSPHRASE_LEN)
+ return -EINVAL;
+
+ if (cmd->size_out != 0)
+ return -EINVAL;
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (memcmp(cmd->payload_in, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
+ if (++mdata->user_limit == PASS_TRY_LIMIT)
+ mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+
+ mdata->user_limit = 0;
+ mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
+ return 0;
+}
+
+static int mock_passphrase_secure_erase(struct cxl_dev_state *cxlds,
+ struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+ struct cxl_pass_erase *erase;
+
+ if (cmd->size_in != sizeof(*erase))
+ return -EINVAL;
+
+ if (cmd->size_out != 0)
+ return -EINVAL;
+
+ erase = cmd->payload_in;
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT &&
+ erase->type == CXL_PMEM_SEC_PASS_USER) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT &&
+ erase->type == CXL_PMEM_SEC_PASS_MASTER) {
+ cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+ return -ENXIO;
+ }
+
+ switch (erase->type) {
+ case CXL_PMEM_SEC_PASS_MASTER:
+ /*
+ * The spec does not clearly define the behavior of the scenario
+ * where a master passphrase is passed in while the master
+ * passphrase is not set and user passphrase is not set. The
+ * code will take the assumption that it will behave the same
+ * as a CXL secure erase command without passphrase (0x4401).
+ */
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) {
+ if (memcmp(mdata->master_pass, erase->pass,
+ NVDIMM_PASSPHRASE_LEN)) {
+ master_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+ mdata->master_limit = 0;
+ mdata->user_limit = 0;
+ mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
+ memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
+ mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
+ } else {
+ /*
+ * CXL rev3 8.2.9.8.6.3 Disable Passphrase
+ * When master passphrase is disabled, the device shall
+ * return Invalid Input for the Passphrase Secure Erase
+ * command with master passphrase.
+ */
+ return -EINVAL;
+ }
+ /* Scramble encryption keys so that data is effectively erased */
+ break;
+ case CXL_PMEM_SEC_PASS_USER:
+ /*
+ * The spec does not clearly define the behavior of the scenario
+ * where a user passphrase is passed in while the user
+ * passphrase is not set. The code will take the assumption that
+ * it will behave the same as a CXL secure erase command without
+ * passphrase (0x4401).
+ */
+ if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
+ if (memcmp(mdata->user_pass, erase->pass,
+ NVDIMM_PASSPHRASE_LEN)) {
+ user_plimit_check(mdata);
+ cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
+ return -ENXIO;
+ }
+ mdata->user_limit = 0;
+ mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
+ memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
+ }
+
+ /*
+ * CXL rev3 Table 8-118
+ * If user passphrase is not set or supported by device, current
+ * passphrase value is ignored. Will make the assumption that
+ * the operation will proceed as secure erase w/o passphrase
+ * since spec is not explicit.
+ */
+
+ /* Scramble encryption keys so that data is effectively erased */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{
struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in;
- void *lsa = dev_get_drvdata(cxlds->dev);
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+ void *lsa = mdata->lsa;
u32 offset, length;
if (sizeof(*get_lsa) > cmd->size_in)
@@ -159,7 +513,8 @@ static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{
struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in;
- void *lsa = dev_get_drvdata(cxlds->dev);
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+ void *lsa = mdata->lsa;
u32 offset, length;
if (sizeof(*set_lsa) > cmd->size_in)
@@ -216,7 +571,10 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
rc = mock_get_log(cxlds, cmd);
break;
case CXL_MBOX_OP_IDENTIFY:
- rc = mock_id(cxlds, cmd);
+ if (cxlds->rcd)
+ rc = mock_rcd_id(cxlds, cmd);
+ else
+ rc = mock_id(cxlds, cmd);
break;
case CXL_MBOX_OP_GET_LSA:
rc = mock_get_lsa(cxlds, cmd);
@@ -230,6 +588,24 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
case CXL_MBOX_OP_GET_HEALTH_INFO:
rc = mock_health_info(cxlds, cmd);
break;
+ case CXL_MBOX_OP_GET_SECURITY_STATE:
+ rc = mock_get_security_state(cxlds, cmd);
+ break;
+ case CXL_MBOX_OP_SET_PASSPHRASE:
+ rc = mock_set_passphrase(cxlds, cmd);
+ break;
+ case CXL_MBOX_OP_DISABLE_PASSPHRASE:
+ rc = mock_disable_passphrase(cxlds, cmd);
+ break;
+ case CXL_MBOX_OP_FREEZE_SECURITY:
+ rc = mock_freeze_security(cxlds, cmd);
+ break;
+ case CXL_MBOX_OP_UNLOCK:
+ rc = mock_unlock_security(cxlds, cmd);
+ break;
+ case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE:
+ rc = mock_passphrase_secure_erase(cxlds, cmd);
+ break;
default:
break;
}
@@ -245,21 +621,32 @@ static void label_area_release(void *lsa)
vfree(lsa);
}
+static bool is_rcd(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+
+ return !!id->driver_data;
+}
+
static int cxl_mock_mem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cxl_memdev *cxlmd;
struct cxl_dev_state *cxlds;
- void *lsa;
+ struct cxl_mockmem_data *mdata;
int rc;
- lsa = vmalloc(LSA_SIZE);
- if (!lsa)
+ mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL);
+ if (!mdata)
return -ENOMEM;
- rc = devm_add_action_or_reset(dev, label_area_release, lsa);
+ dev_set_drvdata(dev, mdata);
+
+ mdata->lsa = vmalloc(LSA_SIZE);
+ if (!mdata->lsa)
+ return -ENOMEM;
+ rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa);
if (rc)
return rc;
- dev_set_drvdata(dev, lsa);
cxlds = cxl_dev_state_create(dev);
if (IS_ERR(cxlds))
@@ -268,6 +655,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
cxlds->serial = pdev->id;
cxlds->mbox_send = cxl_mock_mbox_send;
cxlds->payload_size = SZ_4K;
+ if (is_rcd(pdev)) {
+ cxlds->rcd = true;
+ cxlds->component_reg_phys = CXL_RESOURCE_NONE;
+ }
rc = cxl_enumerate_cmds(cxlds);
if (rc)
@@ -285,14 +676,51 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
- if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
- rc = devm_cxl_add_nvdimm(dev, cxlmd);
-
return 0;
}
+static ssize_t security_lock_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n",
+ !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED));
+}
+
+static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
+ u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT |
+ CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
+ int val;
+
+ if (kstrtoint(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val == 1) {
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
+ return -ENXIO;
+ mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED;
+ mdata->security_state &= ~mask;
+ } else {
+ return -EINVAL;
+ }
+ return count;
+}
+
+static DEVICE_ATTR_RW(security_lock);
+
+static struct attribute *cxl_mock_mem_attrs[] = {
+ &dev_attr_security_lock.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(cxl_mock_mem);
+
static const struct platform_device_id cxl_mock_mem_ids[] = {
- { .name = "cxl_mem", },
+ { .name = "cxl_mem", 0 },
+ { .name = "cxl_rcd", 1 },
{ },
};
MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids);
@@ -302,6 +730,7 @@ static struct platform_driver cxl_mock_mem_driver = {
.id_table = cxl_mock_mem_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .dev_groups = cxl_mock_mem_groups,
},
};
diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c
index bce6a21df0d5..5dface08e0de 100644
--- a/tools/testing/cxl/test/mock.c
+++ b/tools/testing/cxl/test/mock.c
@@ -224,6 +224,25 @@ int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
}
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, CXL);
+resource_size_t __wrap_cxl_rcrb_to_component(struct device *dev,
+ resource_size_t rcrb,
+ enum cxl_rcrb which)
+{
+ int index;
+ resource_size_t component_reg_phys;
+ struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+
+ if (ops && ops->is_mock_port(dev))
+ component_reg_phys =
+ ops->cxl_rcrb_to_component(dev, rcrb, which);
+ else
+ component_reg_phys = cxl_rcrb_to_component(dev, rcrb, which);
+ put_cxl_mock_ops(index);
+
+ return component_reg_phys;
+}
+EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcrb_to_component, CXL);
+
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(ACPI);
MODULE_IMPORT_NS(CXL);
diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h
index 738f24e3988a..ef33f159375e 100644
--- a/tools/testing/cxl/test/mock.h
+++ b/tools/testing/cxl/test/mock.h
@@ -15,6 +15,9 @@ struct cxl_mock_ops {
acpi_string pathname,
struct acpi_object_list *arguments,
unsigned long long *data);
+ resource_size_t (*cxl_rcrb_to_component)(struct device *dev,
+ resource_size_t rcrb,
+ enum cxl_rcrb which);
struct acpi_pci_root *(*acpi_pci_find_root)(acpi_handle handle);
bool (*is_mock_bus)(struct pci_bus *bus);
bool (*is_mock_port)(struct device *dev);
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 09d1578f9d66..ac59999ed3de 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -802,7 +802,14 @@ sub process_variables {
my $end = $3;
# append beginning of value to retval
$retval = "$retval$begin";
- if (defined($variable{$var})) {
+ if ($var =~ s/^shell\s+//) {
+ $retval = `$var`;
+ if ($?) {
+ doprint "WARNING: $var returned an error\n";
+ } else {
+ chomp $retval;
+ }
+ } elsif (defined($variable{$var})) {
$retval = "$retval$variable{$var}";
} elsif (defined($remove_undef) && $remove_undef) {
# for if statements, any variable that is not defined,
@@ -1963,7 +1970,7 @@ sub run_scp_mod {
sub _get_grub_index {
- my ($command, $target, $skip) = @_;
+ my ($command, $target, $skip, $submenu) = @_;
return if (defined($grub_number) && defined($last_grub_menu) &&
$last_grub_menu eq $grub_menu && defined($last_machine) &&
@@ -1980,11 +1987,16 @@ sub _get_grub_index {
my $found = 0;
+ my $submenu_number = 0;
+
while (<IN>) {
if (/$target/) {
$grub_number++;
$found = 1;
last;
+ } elsif (defined($submenu) && /$submenu/) {
+ $submenu_number++;
+ $grub_number = -1;
} elsif (/$skip/) {
$grub_number++;
}
@@ -1993,6 +2005,9 @@ sub _get_grub_index {
dodie "Could not find '$grub_menu' through $command on $machine"
if (!$found);
+ if ($submenu_number > 0) {
+ $grub_number = "$submenu_number>$grub_number";
+ }
doprint "$grub_number\n";
$last_grub_menu = $grub_menu;
$last_machine = $machine;
@@ -2003,6 +2018,7 @@ sub get_grub_index {
my $command;
my $target;
my $skip;
+ my $submenu;
my $grub_menu_qt;
if ($reboot_type !~ /^grub/) {
@@ -2017,8 +2033,9 @@ sub get_grub_index {
$skip = '^\s*title\s';
} elsif ($reboot_type eq "grub2") {
$command = "cat $grub_file";
- $target = '^menuentry.*' . $grub_menu_qt;
- $skip = '^menuentry\s|^submenu\s';
+ $target = '^\s*menuentry.*' . $grub_menu_qt;
+ $skip = '^\s*menuentry';
+ $submenu = '^\s*submenu\s';
} elsif ($reboot_type eq "grub2bls") {
$command = $grub_bls_get;
$target = '^title=.*' . $grub_menu_qt;
@@ -2027,7 +2044,7 @@ sub get_grub_index {
return;
}
- _get_grub_index($command, $target, $skip);
+ _get_grub_index($command, $target, $skip, $submenu);
}
sub wait_for_input {
@@ -2090,7 +2107,7 @@ sub reboot_to {
if ($reboot_type eq "grub") {
run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
} elsif (($reboot_type eq "grub2") or ($reboot_type eq "grub2bls")) {
- run_ssh "$grub_reboot $grub_number";
+ run_ssh "$grub_reboot \"'$grub_number'\"";
} elsif ($reboot_type eq "syslinux") {
run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path";
} elsif (defined $reboot_script) {
@@ -3768,9 +3785,10 @@ sub test_this_config {
# .config to make sure it is missing the config that
# we had before
my %configs = %min_configs;
- delete $configs{$config};
+ $configs{$config} = "# $config is not set";
make_new_config ((values %configs), (values %keep_configs));
make_oldconfig;
+ delete $configs{$config};
undef %configs;
assign_configs \%configs, $output_config;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 5e7d1d729752..2d0fe15a096d 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -259,6 +259,14 @@
# If PATH is not a config variable, then the ${PATH} in
# the MAKE_CMD option will be evaluated by the shell when
# the MAKE_CMD option is passed into shell processing.
+#
+# Shell commands can also be inserted with the ${shell <command>}
+# expression. Note, this is case sensitive, thus ${SHELL <command>}
+# will not work.
+#
+# HOSTNAME := ${shell hostname}
+# DEFAULTS IF "${HOSTNAME}" == "frodo"
+#
#### Using options in other options ####
#
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index 4d4663fb578b..43fbe96318fe 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -192,28 +192,30 @@ def _map_to_overall_status(test_status: kunit_parser.TestStatus) -> KunitStatus:
def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input_data: Iterable[str]) -> Tuple[KunitResult, kunit_parser.Test]:
parse_start = time.time()
- test_result = kunit_parser.Test()
-
if request.raw_output:
# Treat unparsed results as one passing test.
- test_result.status = kunit_parser.TestStatus.SUCCESS
- test_result.counts.passed = 1
+ fake_test = kunit_parser.Test()
+ fake_test.status = kunit_parser.TestStatus.SUCCESS
+ fake_test.counts.passed = 1
output: Iterable[str] = input_data
if request.raw_output == 'all':
pass
elif request.raw_output == 'kunit':
- output = kunit_parser.extract_tap_lines(output, lstrip=False)
+ output = kunit_parser.extract_tap_lines(output)
for line in output:
print(line.rstrip())
+ parse_time = time.time() - parse_start
+ return KunitResult(KunitStatus.SUCCESS, parse_time), fake_test
- else:
- test_result = kunit_parser.parse_run_tests(input_data)
- parse_end = time.time()
+
+ # Actually parse the test results.
+ test = kunit_parser.parse_run_tests(input_data)
+ parse_time = time.time() - parse_start
if request.json:
json_str = kunit_json.get_json_result(
- test=test_result,
+ test=test,
metadata=metadata)
if request.json == 'stdout':
print(json_str)
@@ -223,10 +225,10 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
stdout.print_with_timestamp("Test results stored in %s" %
os.path.abspath(request.json))
- if test_result.status != kunit_parser.TestStatus.SUCCESS:
- return KunitResult(KunitStatus.TEST_FAILURE, parse_end - parse_start), test_result
+ if test.status != kunit_parser.TestStatus.SUCCESS:
+ return KunitResult(KunitStatus.TEST_FAILURE, parse_time), test
- return KunitResult(KunitStatus.SUCCESS, parse_end - parse_start), test_result
+ return KunitResult(KunitStatus.SUCCESS, parse_time), test
def run_tests(linux: kunit_kernel.LinuxSourceTree,
request: KunitRequest) -> KunitResult:
@@ -359,14 +361,14 @@ def add_exec_opts(parser) -> None:
choices=['suite', 'test'])
def add_parse_opts(parser) -> None:
- parser.add_argument('--raw_output', help='If set don\'t format output from kernel. '
- 'If set to --raw_output=kunit, filters to just KUnit output.',
+ parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
+ 'By default, filters to just KUnit output. Use '
+ '--raw_output=all to show everything',
type=str, nargs='?', const='all', default=None, choices=['all', 'kunit'])
parser.add_argument('--json',
nargs='?',
- help='Stores test results in a JSON, and either '
- 'prints to stdout or saves to file if a '
- 'filename is specified',
+ help='Prints parsed test results as JSON to stdout or a file if '
+ 'a filename is specified. Does nothing if --raw_output is set.',
type=str, const='stdout', default=None, metavar='FILE')
diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 1ae873e3e341..a225799f6b1b 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -10,8 +10,10 @@
# Author: Rae Moar <rmoar@google.com>
from __future__ import annotations
+from dataclasses import dataclass
import re
import sys
+import textwrap
from enum import Enum, auto
from typing import Iterable, Iterator, List, Optional, Tuple
@@ -58,6 +60,10 @@ class Test:
self.counts.errors += 1
stdout.print_with_timestamp(stdout.red('[ERROR]') + f' Test: {self.name}: {error_message}')
+ def ok_status(self) -> bool:
+ """Returns true if the status was ok, i.e. passed or skipped."""
+ return self.status in (TestStatus.SUCCESS, TestStatus.SKIPPED)
+
class TestStatus(Enum):
"""An enumeration class to represent the status of a test."""
SUCCESS = auto()
@@ -67,27 +73,17 @@ class TestStatus(Enum):
NO_TESTS = auto()
FAILURE_TO_PARSE_TESTS = auto()
+@dataclass
class TestCounts:
"""
Tracks the counts of statuses of all test cases and any errors within
a Test.
-
- Attributes:
- passed : int - the number of tests that have passed
- failed : int - the number of tests that have failed
- crashed : int - the number of tests that have crashed
- skipped : int - the number of tests that have skipped
- errors : int - the number of errors in the test and subtests
- """
- def __init__(self):
- """Creates TestCounts object with counts of all test
- statuses and test errors set to 0.
- """
- self.passed = 0
- self.failed = 0
- self.crashed = 0
- self.skipped = 0
- self.errors = 0
+ """
+ passed: int = 0
+ failed: int = 0
+ crashed: int = 0
+ skipped: int = 0
+ errors: int = 0
def __str__(self) -> str:
"""Returns the string representation of a TestCounts object."""
@@ -213,12 +209,12 @@ class LineStream:
# Parsing helper methods:
-KTAP_START = re.compile(r'KTAP version ([0-9]+)$')
-TAP_START = re.compile(r'TAP version ([0-9]+)$')
-KTAP_END = re.compile('(List of all partitions:|'
+KTAP_START = re.compile(r'\s*KTAP version ([0-9]+)$')
+TAP_START = re.compile(r'\s*TAP version ([0-9]+)$')
+KTAP_END = re.compile(r'\s*(List of all partitions:|'
'Kernel panic - not syncing: VFS:|reboot: System halted)')
-def extract_tap_lines(kernel_output: Iterable[str], lstrip=True) -> LineStream:
+def extract_tap_lines(kernel_output: Iterable[str]) -> LineStream:
"""Extracts KTAP lines from the kernel output."""
def isolate_ktap_output(kernel_output: Iterable[str]) \
-> Iterator[Tuple[int, str]]:
@@ -244,11 +240,8 @@ def extract_tap_lines(kernel_output: Iterable[str], lstrip=True) -> LineStream:
# stop extracting KTAP lines
break
elif started:
- # remove the prefix and optionally any leading
- # whitespace. Our parsing logic relies on this.
+ # remove the prefix, if any.
line = line[prefix_len:]
- if lstrip:
- line = line.lstrip()
yield line_num, line
return LineStream(lines=isolate_ktap_output(kernel_output))
@@ -300,10 +293,10 @@ def parse_ktap_header(lines: LineStream, test: Test) -> bool:
check_version(version_num, TAP_VERSIONS, 'TAP', test)
else:
return False
- test.log.append(lines.pop())
+ lines.pop()
return True
-TEST_HEADER = re.compile(r'^# Subtest: (.*)$')
+TEST_HEADER = re.compile(r'^\s*# Subtest: (.*)$')
def parse_test_header(lines: LineStream, test: Test) -> bool:
"""
@@ -323,11 +316,11 @@ def parse_test_header(lines: LineStream, test: Test) -> bool:
match = TEST_HEADER.match(lines.peek())
if not match:
return False
- test.log.append(lines.pop())
test.name = match.group(1)
+ lines.pop()
return True
-TEST_PLAN = re.compile(r'1\.\.([0-9]+)')
+TEST_PLAN = re.compile(r'^\s*1\.\.([0-9]+)')
def parse_test_plan(lines: LineStream, test: Test) -> bool:
"""
@@ -350,14 +343,14 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
if not match:
test.expected_count = None
return False
- test.log.append(lines.pop())
expected_count = int(match.group(1))
test.expected_count = expected_count
+ lines.pop()
return True
-TEST_RESULT = re.compile(r'^(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
+TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
-TEST_RESULT_SKIP = re.compile(r'^(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
+TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
def peek_test_name_match(lines: LineStream, test: Test) -> bool:
"""
@@ -414,7 +407,7 @@ def parse_test_result(lines: LineStream, test: Test,
# Check if line matches test result line format
if not match:
return False
- test.log.append(lines.pop())
+ lines.pop()
# Set name of test object
if skip_match:
@@ -446,6 +439,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
- '# Subtest: [test name]'
- '[ok|not ok] [test number] [-] [test name] [optional skip
directive]'
+ - 'KTAP version [version number]'
Parameters:
lines - LineStream of KTAP output to parse
@@ -454,8 +448,9 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
Log of diagnostic lines
"""
log = [] # type: List[str]
- while lines and not TEST_RESULT.match(lines.peek()) and not \
- TEST_HEADER.match(lines.peek()):
+ non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START]
+ while lines and not any(re.match(lines.peek())
+ for re in non_diagnostic_lines):
log.append(lines.pop())
return log
@@ -501,17 +496,22 @@ def print_test_header(test: Test) -> None:
test - Test object representing current test being printed
"""
message = test.name
+ if message != "":
+ # Add a leading space before the subtest counts only if a test name
+ # is provided using a "# Subtest" header line.
+ message += " "
if test.expected_count:
if test.expected_count == 1:
- message += ' (1 subtest)'
+ message += '(1 subtest)'
else:
- message += f' ({test.expected_count} subtests)'
+ message += f'({test.expected_count} subtests)'
stdout.print_with_timestamp(format_test_divider(message, len(message)))
def print_log(log: Iterable[str]) -> None:
"""Prints all strings in saved log for test in yellow."""
- for m in log:
- stdout.print_with_timestamp(stdout.yellow(m))
+ formatted = textwrap.dedent('\n'.join(log))
+ for line in formatted.splitlines():
+ stdout.print_with_timestamp(stdout.yellow(line))
def format_test_result(test: Test) -> str:
"""
@@ -565,6 +565,40 @@ def print_test_footer(test: Test) -> None:
stdout.print_with_timestamp(format_test_divider(message,
len(message) - stdout.color_len()))
+
+
+def _summarize_failed_tests(test: Test) -> str:
+ """Tries to summarize all the failing subtests in `test`."""
+
+ def failed_names(test: Test, parent_name: str) -> List[str]:
+ # Note: we use 'main' internally for the top-level test.
+ if not parent_name or parent_name == 'main':
+ full_name = test.name
+ else:
+ full_name = parent_name + '.' + test.name
+
+ if not test.subtests: # this is a leaf node
+ return [full_name]
+
+ # If all the children failed, just say this subtest failed.
+ # Don't summarize it down "the top-level test failed", though.
+ failed_subtests = [sub for sub in test.subtests if not sub.ok_status()]
+ if parent_name and len(failed_subtests) == len(test.subtests):
+ return [full_name]
+
+ all_failures = [] # type: List[str]
+ for t in failed_subtests:
+ all_failures.extend(failed_names(t, full_name))
+ return all_failures
+
+ failures = failed_names(test, '')
+ # If there are too many failures, printing them out will just be noisy.
+ if len(failures) > 10: # this is an arbitrary limit
+ return ''
+
+ return 'Failures: ' + ', '.join(failures)
+
+
def print_summary_line(test: Test) -> None:
"""
Prints summary line of test object. Color of line is dependent on
@@ -587,6 +621,15 @@ def print_summary_line(test: Test) -> None:
color = stdout.red
stdout.print_with_timestamp(color(f'Testing complete. {test.counts}'))
+ # Summarize failures that might have gone off-screen since we had a lot
+ # of tests (arbitrarily defined as >=100 for now).
+ if test.ok_status() or test.counts.total() < 100:
+ return
+ summarized = _summarize_failed_tests(test)
+ if not summarized:
+ return
+ stdout.print_with_timestamp(color(summarized))
+
# Other methods:
def bubble_up_test_results(test: Test) -> None:
@@ -609,7 +652,7 @@ def bubble_up_test_results(test: Test) -> None:
elif test.counts.get_status() == TestStatus.TEST_CRASHED:
test.status = TestStatus.TEST_CRASHED
-def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
+def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool) -> Test:
"""
Finds next test to parse in LineStream, creates new Test object,
parses any subtests of the test, populates Test object with all
@@ -627,15 +670,32 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
1..4
[subtests]
- - Subtest header line
+ - Subtest header (must include either the KTAP version line or
+ "# Subtest" header line)
- Example:
+ Example (preferred format with both KTAP version line and
+ "# Subtest" line):
+ KTAP version 1
# Subtest: name
1..3
[subtests]
ok 1 name
+ Example (only "# Subtest" line):
+
+ # Subtest: name
+ 1..3
+ [subtests]
+ ok 1 name
+
+ Example (only KTAP version line, compliant with KTAP v1 spec):
+
+ KTAP version 1
+ 1..3
+ [subtests]
+ ok 1 name
+
- Test result line
Example:
@@ -647,28 +707,29 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
expected_num - expected test number for test to be parsed
log - list of strings containing any preceding diagnostic lines
corresponding to the current test
+ is_subtest - boolean indicating whether test is a subtest
Return:
Test object populated with characteristics and any subtests
"""
test = Test()
test.log.extend(log)
- parent_test = False
- main = parse_ktap_header(lines, test)
- if main:
- # If KTAP/TAP header is found, attempt to parse
+ if not is_subtest:
+ # If parsing the main/top-level test, parse KTAP version line and
# test plan
test.name = "main"
+ ktap_line = parse_ktap_header(lines, test)
parse_test_plan(lines, test)
parent_test = True
else:
- # If KTAP/TAP header is not found, test must be subtest
- # header or test result line so parse attempt to parser
- # subtest header
- parent_test = parse_test_header(lines, test)
+ # If not the main test, attempt to parse a test header containing
+ # the KTAP version line and/or subtest header line
+ ktap_line = parse_ktap_header(lines, test)
+ subtest_line = parse_test_header(lines, test)
+ parent_test = (ktap_line or subtest_line)
if parent_test:
- # If subtest header is found, attempt to parse
- # test plan and print header
+ # If KTAP version line and/or subtest header is found, attempt
+ # to parse test plan and print test header
parse_test_plan(lines, test)
print_test_header(test)
expected_count = test.expected_count
@@ -683,7 +744,7 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
sub_log = parse_diagnostic(lines)
sub_test = Test()
if not lines or (peek_test_name_match(lines, test) and
- not main):
+ is_subtest):
if expected_count and test_num <= expected_count:
# If parser reaches end of test before
# parsing expected number of subtests, print
@@ -697,20 +758,19 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
test.log.extend(sub_log)
break
else:
- sub_test = parse_test(lines, test_num, sub_log)
+ sub_test = parse_test(lines, test_num, sub_log, True)
subtests.append(sub_test)
test_num += 1
test.subtests = subtests
- if not main:
+ if is_subtest:
# If not main test, look for test result line
test.log.extend(parse_diagnostic(lines))
- if (parent_test and peek_test_name_match(lines, test)) or \
- not parent_test:
- parse_test_result(lines, test, expected_num)
- else:
+ if test.name != "" and not peek_test_name_match(lines, test):
test.add_error('missing subtest result line!')
+ else:
+ parse_test_result(lines, test, expected_num)
- # Check for there being no tests
+ # Check for there being no subtests within parent test
if parent_test and len(subtests) == 0:
# Don't override a bad status if this test had one reported.
# Assumption: no subtests means CRASHED is from Test.__init__()
@@ -720,11 +780,11 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str]) -> Test:
# Add statuses to TestCounts attribute in Test object
bubble_up_test_results(test)
- if parent_test and not main:
+ if parent_test and is_subtest:
# If test has subtests and is not the main test object, print
# footer.
print_test_footer(test)
- elif not main:
+ elif is_subtest:
print_test_result(test)
return test
@@ -744,10 +804,10 @@ def parse_run_tests(kernel_output: Iterable[str]) -> Test:
test = Test()
if not lines:
test.name = '<missing>'
- test.add_error('could not find any KTAP output!')
+ test.add_error('Could not find any KTAP output. Did any KUnit tests run?')
test.status = TestStatus.FAILURE_TO_PARSE_TESTS
else:
- test = parse_test(lines, 0, [])
+ test = parse_test(lines, 0, [], False)
if test.status != TestStatus.NO_TESTS:
test.status = test.counts.get_status()
stdout.print_with_timestamp(DIVIDER)
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index e2cd2cc2e98f..0c2190514103 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -80,6 +80,13 @@ class KconfigTest(unittest.TestCase):
self.assertEqual(actual_kconfig, expected_kconfig)
class KUnitParserTest(unittest.TestCase):
+ def setUp(self):
+ self.print_mock = mock.patch('kunit_printer.Printer.print').start()
+ self.addCleanup(mock.patch.stopall)
+
+ def noPrintCallContains(self, substr: str):
+ for call in self.print_mock.mock_calls:
+ self.assertNotIn(substr, call.args[0])
def assertContains(self, needle: str, haystack: kunit_parser.LineStream):
# Clone the iterator so we can print the contents on failure.
@@ -133,33 +140,29 @@ class KUnitParserTest(unittest.TestCase):
all_passed_log = test_data_path('test_is_test_passed-all_passed.log')
with open(all_passed_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual(result.counts.errors, 0)
def test_parse_successful_nested_tests_log(self):
all_passed_log = test_data_path('test_is_test_passed-all_passed_nested.log')
with open(all_passed_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual(result.counts.errors, 0)
def test_kselftest_nested(self):
kselftest_log = test_data_path('test_is_test_passed-kselftest.log')
with open(kselftest_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual(result.counts.errors, 0)
def test_parse_failed_test_log(self):
failed_log = test_data_path('test_is_test_passed-failure.log')
with open(failed_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.FAILURE,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+ self.assertEqual(result.counts.errors, 0)
def test_no_header(self):
empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
@@ -167,9 +170,8 @@ class KUnitParserTest(unittest.TestCase):
result = kunit_parser.parse_run_tests(
kunit_parser.extract_tap_lines(file.readlines()))
self.assertEqual(0, len(result.subtests))
- self.assertEqual(
- kunit_parser.TestStatus.FAILURE_TO_PARSE_TESTS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.FAILURE_TO_PARSE_TESTS, result.status)
+ self.assertEqual(result.counts.errors, 1)
def test_missing_test_plan(self):
missing_plan_log = test_data_path('test_is_test_passed-'
@@ -179,12 +181,8 @@ class KUnitParserTest(unittest.TestCase):
kunit_parser.extract_tap_lines(
file.readlines()))
# A missing test plan is not an error.
- self.assertEqual(0, result.counts.errors)
- # All tests should be accounted for.
- self.assertEqual(10, result.counts.total())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(result.counts, kunit_parser.TestCounts(passed=10, errors=0))
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
def test_no_tests(self):
header_log = test_data_path('test_is_test_passed-no_tests_run_with_header.log')
@@ -192,9 +190,8 @@ class KUnitParserTest(unittest.TestCase):
result = kunit_parser.parse_run_tests(
kunit_parser.extract_tap_lines(file.readlines()))
self.assertEqual(0, len(result.subtests))
- self.assertEqual(
- kunit_parser.TestStatus.NO_TESTS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.NO_TESTS, result.status)
+ self.assertEqual(result.counts.errors, 1)
def test_no_tests_no_plan(self):
no_plan_log = test_data_path('test_is_test_passed-no_tests_no_plan.log')
@@ -205,7 +202,7 @@ class KUnitParserTest(unittest.TestCase):
self.assertEqual(
kunit_parser.TestStatus.NO_TESTS,
result.subtests[0].subtests[0].status)
- self.assertEqual(1, result.counts.errors)
+ self.assertEqual(result.counts, kunit_parser.TestCounts(passed=1, errors=1))
def test_no_kunit_output(self):
@@ -214,9 +211,10 @@ class KUnitParserTest(unittest.TestCase):
with open(crash_log) as file:
result = kunit_parser.parse_run_tests(
kunit_parser.extract_tap_lines(file.readlines()))
- print_mock.assert_any_call(StrContains('could not find any KTAP output!'))
+ print_mock.assert_any_call(StrContains('Could not find any KTAP output.'))
print_mock.stop()
self.assertEqual(0, len(result.subtests))
+ self.assertEqual(result.counts.errors, 1)
def test_skipped_test(self):
skipped_log = test_data_path('test_skip_tests.log')
@@ -224,18 +222,16 @@ class KUnitParserTest(unittest.TestCase):
result = kunit_parser.parse_run_tests(file.readlines())
# A skipped test does not fail the whole suite.
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual(result.counts, kunit_parser.TestCounts(passed=4, skipped=1))
def test_skipped_all_tests(self):
skipped_log = test_data_path('test_skip_all_tests.log')
with open(skipped_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SKIPPED,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SKIPPED, result.status)
+ self.assertEqual(result.counts, kunit_parser.TestCounts(skipped=5))
def test_ignores_hyphen(self):
hyphen_log = test_data_path('test_strip_hyphen.log')
@@ -243,71 +239,112 @@ class KUnitParserTest(unittest.TestCase):
result = kunit_parser.parse_run_tests(file.readlines())
# A skipped test does not fail the whole suite.
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
self.assertEqual(
"sysctl_test",
result.subtests[0].name)
self.assertEqual(
"example",
result.subtests[1].name)
- file.close()
-
def test_ignores_prefix_printk_time(self):
prefix_log = test_data_path('test_config_printk_time.log')
with open(prefix_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(result.counts.errors, 0)
def test_ignores_multiple_prefixes(self):
prefix_log = test_data_path('test_multiple_prefixes.log')
with open(prefix_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(result.counts.errors, 0)
def test_prefix_mixed_kernel_output(self):
mixed_prefix_log = test_data_path('test_interrupted_tap_output.log')
with open(mixed_prefix_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(result.counts.errors, 0)
def test_prefix_poundsign(self):
pound_log = test_data_path('test_pound_sign.log')
with open(pound_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(result.counts.errors, 0)
def test_kernel_panic_end(self):
panic_log = test_data_path('test_kernel_panic_interrupt.log')
with open(panic_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.TEST_CRASHED,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.TEST_CRASHED, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertGreaterEqual(result.counts.errors, 1)
def test_pound_no_prefix(self):
pound_log = test_data_path('test_pound_no_prefix.log')
with open(pound_log) as file:
result = kunit_parser.parse_run_tests(file.readlines())
- self.assertEqual(
- kunit_parser.TestStatus.SUCCESS,
- result.status)
- self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+ self.assertEqual('kunit-resource-test', result.subtests[0].name)
+ self.assertEqual(result.counts.errors, 0)
+
+ def test_summarize_failures(self):
+ output = """
+ KTAP version 1
+ 1..2
+ # Subtest: all_failed_suite
+ 1..2
+ not ok 1 - test1
+ not ok 2 - test2
+ not ok 1 - all_failed_suite
+ # Subtest: some_failed_suite
+ 1..2
+ ok 1 - test1
+ not ok 2 - test2
+ not ok 1 - some_failed_suite
+ """
+ result = kunit_parser.parse_run_tests(output.splitlines())
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+
+ self.assertEqual(kunit_parser._summarize_failed_tests(result),
+ 'Failures: all_failed_suite, some_failed_suite.test2')
+
+ def test_ktap_format(self):
+ ktap_log = test_data_path('test_parse_ktap_output.log')
+ with open(ktap_log) as file:
+ result = kunit_parser.parse_run_tests(file.readlines())
+ self.assertEqual(result.counts, kunit_parser.TestCounts(passed=3))
+ self.assertEqual('suite', result.subtests[0].name)
+ self.assertEqual('case_1', result.subtests[0].subtests[0].name)
+ self.assertEqual('case_2', result.subtests[0].subtests[1].name)
+
+ def test_parse_subtest_header(self):
+ ktap_log = test_data_path('test_parse_subtest_header.log')
+ with open(ktap_log) as file:
+ result = kunit_parser.parse_run_tests(file.readlines())
+ self.print_mock.assert_any_call(StrContains('suite (1 subtest)'))
+
+ def test_show_test_output_on_failure(self):
+ output = """
+ KTAP version 1
+ 1..1
+ Test output.
+ Indented more.
+ not ok 1 test1
+ """
+ result = kunit_parser.parse_run_tests(output.splitlines())
+ self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status)
+
+ self.print_mock.assert_any_call(StrContains('Test output.'))
+ self.print_mock.assert_any_call(StrContains(' Indented more.'))
+ self.noPrintCallContains('not ok 1 test1')
def line_stream_from_strs(strs: Iterable[str]) -> kunit_parser.LineStream:
return kunit_parser.LineStream(enumerate(strs, start=1))
@@ -485,6 +522,9 @@ class LinuxSourceTreeTest(unittest.TestCase):
class KUnitJsonTest(unittest.TestCase):
+ def setUp(self):
+ self.print_mock = mock.patch('kunit_printer.Printer.print').start()
+ self.addCleanup(mock.patch.stopall)
def _json_for(self, log_file):
with open(test_data_path(log_file)) as file:
@@ -581,7 +621,7 @@ class KUnitMainTest(unittest.TestCase):
self.assertEqual(e.exception.code, 1)
self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
- self.print_mock.assert_any_call(StrContains('could not find any KTAP output!'))
+ self.print_mock.assert_any_call(StrContains('Could not find any KTAP output.'))
def test_exec_no_tests(self):
self.linux_source_mock.run_kernel = mock.Mock(return_value=['TAP version 14', '1..0'])
diff --git a/tools/testing/kunit/test_data/test_parse_ktap_output.log b/tools/testing/kunit/test_data/test_parse_ktap_output.log
new file mode 100644
index 000000000000..ccdf244e5303
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_parse_ktap_output.log
@@ -0,0 +1,8 @@
+KTAP version 1
+1..1
+ KTAP version 1
+ 1..3
+ ok 1 case_1
+ ok 2 case_2
+ ok 3 case_3
+ok 1 suite
diff --git a/tools/testing/kunit/test_data/test_parse_subtest_header.log b/tools/testing/kunit/test_data/test_parse_subtest_header.log
new file mode 100644
index 000000000000..216631092e7b
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_parse_subtest_header.log
@@ -0,0 +1,7 @@
+KTAP version 1
+1..1
+ KTAP version 1
+ # Subtest: suite
+ 1..1
+ ok 1 test
+ok 1 suite \ No newline at end of file
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 5eb5c23b062f..8153251ea389 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -79,7 +79,6 @@ libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o
libnvdimm-$(CONFIG_NVDIMM_DAX) += $(NVDIMM_SRC)/dax_devs.o
libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o
-libnvdimm-y += dimm_devs.o
libnvdimm-y += libnvdimm_test.o
libnvdimm-y += config_check.o
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c
deleted file mode 100644
index 57bd27dedf1f..000000000000
--- a/tools/testing/nvdimm/dimm_devs.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright Intel Corp. 2018 */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/nd.h>
-#include "pmem.h"
-#include "pfn.h"
-#include "nd.h"
-#include "nd-core.h"
-
-ssize_t security_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct nvdimm *nvdimm = to_nvdimm(dev);
-
- /*
- * For the test version we need to poll the "hardware" in order
- * to get the updated status for unlock testing.
- */
- nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
-
- if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
- return sprintf(buf, "disabled\n");
- if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
- return sprintf(buf, "unlocked\n");
- if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
- return sprintf(buf, "locked\n");
- return -ENOTTY;
-}
diff --git a/tools/testing/radix-tree/.gitignore b/tools/testing/radix-tree/.gitignore
index c901d96dd013..49bccb90c35b 100644
--- a/tools/testing/radix-tree/.gitignore
+++ b/tools/testing/radix-tree/.gitignore
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
+generated/bit-length.h
generated/map-shift.h
idr.c
idr-test
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index 89d613e0505b..caf32a9b9608 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -18,9 +18,14 @@ endif
ifeq ($(BUILD), 32)
CFLAGS += -m32
LDFLAGS += -m32
+LONG_BIT := 32
endif
-targets: generated/map-shift.h $(TARGETS)
+ifndef LONG_BIT
+LONG_BIT := $(shell getconf LONG_BIT)
+endif
+
+targets: generated/map-shift.h generated/bit-length.h $(TARGETS)
main: $(OFILES)
@@ -34,11 +39,11 @@ maple: $(CORE_OFILES)
multiorder: multiorder.o $(CORE_OFILES)
clean:
- $(RM) $(TARGETS) *.o radix-tree.c idr.c generated/map-shift.h
+ $(RM) $(TARGETS) *.o radix-tree.c idr.c generated/map-shift.h generated/bit-length.h
vpath %.c ../../lib
-$(OFILES): Makefile *.h */*.h generated/map-shift.h \
+$(OFILES): Makefile *.h */*.h generated/map-shift.h generated/bit-length.h \
../../include/linux/*.h \
../../include/asm/*.h \
../../../include/linux/xarray.h \
@@ -61,3 +66,11 @@ generated/map-shift.h:
echo "#define XA_CHUNK_SHIFT $(SHIFT)" > \
generated/map-shift.h; \
fi
+
+generated/bit-length.h: FORCE
+ @if ! grep -qws CONFIG_$(LONG_BIT)BIT generated/bit-length.h; then \
+ echo "Generating $@"; \
+ echo "#define CONFIG_$(LONG_BIT)BIT 1" > $@; \
+ fi
+
+FORCE: ;
diff --git a/tools/testing/radix-tree/generated/autoconf.h b/tools/testing/radix-tree/generated/autoconf.h
index e7da80350236..92dc474c349b 100644
--- a/tools/testing/radix-tree/generated/autoconf.h
+++ b/tools/testing/radix-tree/generated/autoconf.h
@@ -1,2 +1,2 @@
+#include "bit-length.h"
#define CONFIG_XARRAY_MULTI 1
-#define CONFIG_64BIT 1
diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c
index 2048d12c31df..d587a558997f 100644
--- a/tools/testing/radix-tree/linux.c
+++ b/tools/testing/radix-tree/linux.c
@@ -129,6 +129,10 @@ void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list)
pthread_mutex_unlock(&cachep->lock);
}
+void kmem_cache_shrink(struct kmem_cache *cachep)
+{
+}
+
int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
void **p)
{
diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c
index 35082671928a..2e91973fbaa6 100644
--- a/tools/testing/radix-tree/maple.c
+++ b/tools/testing/radix-tree/maple.c
@@ -2,11 +2,17 @@
/*
* maple_tree.c: Userspace shim for maple tree test-suite
* Copyright (c) 2018 Liam R. Howlett <Liam.Howlett@Oracle.com>
+ *
+ * Any tests that require internal knowledge of the tree or threads and other
+ * difficult to handle in kernel tests.
*/
#define CONFIG_DEBUG_MAPLE_TREE
#define CONFIG_MAPLE_SEARCH
+#define MAPLE_32BIT (MAPLE_NODE_SLOTS > 31)
#include "test.h"
+#include <stdlib.h>
+#include <time.h>
#define module_init(x)
#define module_exit(x)
@@ -18,6 +24,35717 @@
#undef CONFIG_DEBUG_MAPLE_TREE
#include "../../../lib/test_maple_tree.c"
+#define RCU_RANGE_COUNT 1000
+#define RCU_MT_BUG_ON(test, y) {if (y) { test->stop = true; } MT_BUG_ON(test->mt, y); }
+
+struct rcu_test_struct2 {
+ struct maple_tree *mt;
+
+ bool start;
+ bool stop;
+ unsigned int thread_count;
+
+ unsigned int seen_toggle;
+ unsigned int seen_added;
+ unsigned int seen_modified;
+ unsigned int seen_deleted;
+ int pause;
+
+ unsigned long index[RCU_RANGE_COUNT];
+ unsigned long last[RCU_RANGE_COUNT];
+};
+
+struct rcu_reader_struct {
+ unsigned int id;
+ int mod;
+ int del;
+ int flip;
+ int add;
+ int next;
+ struct rcu_test_struct2 *test;
+};
+
+/*
+ * check_new_node() - Check the creation of new nodes and error path
+ * verification.
+ */
+static noinline void check_new_node(struct maple_tree *mt)
+{
+
+ struct maple_node *mn, *mn2, *mn3;
+ struct maple_alloc *smn;
+ struct maple_node *nodes[100];
+ int i, j, total;
+
+ MA_STATE(mas, mt, 0, 0);
+
+ /* Try allocating 3 nodes */
+ mtree_lock(mt);
+ mt_set_non_kernel(0);
+ /* request 3 nodes to be allocated. */
+ mas_node_count(&mas, 3);
+ /* Allocation request of 3. */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 3);
+ /* Allocate failed. */
+ MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+
+ MT_BUG_ON(mt, mas_allocated(&mas) != 3);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, mas.alloc == NULL);
+ MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
+ mas_push_node(&mas, mn);
+ mas_nomem(&mas, GFP_KERNEL); /* free */
+ mtree_unlock(mt);
+
+
+ /* Try allocating 1 node, then 2 more */
+ mtree_lock(mt);
+ /* Set allocation request to 1. */
+ mas_set_alloc_req(&mas, 1);
+ /* Check Allocation request of 1. */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
+ mas_set_err(&mas, -ENOMEM);
+ /* Validate allocation request. */
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ /* Eat the requested node. */
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, mn->slot[0] != NULL);
+ MT_BUG_ON(mt, mn->slot[1] != NULL);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+
+ ma_free_rcu(mn);
+ mas.node = MAS_START;
+ mas_nomem(&mas, GFP_KERNEL);
+ /* Allocate 3 nodes, will fail. */
+ mas_node_count(&mas, 3);
+ /* Drop the lock and allocate 3 nodes. */
+ mas_nomem(&mas, GFP_KERNEL);
+ /* Ensure 3 are allocated. */
+ MT_BUG_ON(mt, mas_allocated(&mas) != 3);
+ /* Allocation request of 0. */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 0);
+
+ MT_BUG_ON(mt, mas.alloc == NULL);
+ MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
+ MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
+ /* Ensure we counted 3. */
+ MT_BUG_ON(mt, mas_allocated(&mas) != 3);
+ /* Free. */
+ mas_nomem(&mas, GFP_KERNEL);
+
+ /* Set allocation request to 1. */
+ mas_set_alloc_req(&mas, 1);
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
+ mas_set_err(&mas, -ENOMEM);
+ /* Validate allocation request. */
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ MT_BUG_ON(mt, mas_allocated(&mas) != 1);
+ /* Check the node is only one node. */
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, mn->slot[0] != NULL);
+ MT_BUG_ON(mt, mn->slot[1] != NULL);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ mas_push_node(&mas, mn);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 1);
+ MT_BUG_ON(mt, mas.alloc->node_count);
+
+ mas_set_alloc_req(&mas, 2); /* request 2 more. */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 2);
+ mas_set_err(&mas, -ENOMEM);
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ MT_BUG_ON(mt, mas_allocated(&mas) != 3);
+ MT_BUG_ON(mt, mas.alloc == NULL);
+ MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
+ MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
+ for (i = 2; i >= 0; i--) {
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != i);
+ MT_BUG_ON(mt, !mn);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ }
+
+ total = 64;
+ mas_set_alloc_req(&mas, total); /* request 2 more. */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != total);
+ mas_set_err(&mas, -ENOMEM);
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ for (i = total; i > 0; i--) {
+ unsigned int e = 0; /* expected node_count */
+
+ if (!MAPLE_32BIT) {
+ if (i >= 35)
+ e = i - 35;
+ else if (i >= 5)
+ e = i - 5;
+ else if (i >= 2)
+ e = i - 2;
+ } else {
+ if (i >= 4)
+ e = i - 4;
+ else if (i == 3)
+ e = i - 2;
+ else
+ e = 0;
+ }
+
+ MT_BUG_ON(mt, mas.alloc->node_count != e);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - 1);
+ MT_BUG_ON(mt, !mn);
+ ma_free_rcu(mn);
+ }
+
+ total = 100;
+ for (i = 1; i < total; i++) {
+ mas_set_alloc_req(&mas, i);
+ mas_set_err(&mas, -ENOMEM);
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ for (j = i; j > 0; j--) {
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
+ MT_BUG_ON(mt, !mn);
+ MT_BUG_ON(mt, not_empty(mn));
+ mas_push_node(&mas, mn);
+ MT_BUG_ON(mt, mas_allocated(&mas) != j);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
+ ma_free_rcu(mn);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+
+ mas_set_alloc_req(&mas, i);
+ mas_set_err(&mas, -ENOMEM);
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ for (j = 0; j <= i/2; j++) {
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
+ nodes[j] = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
+ }
+
+ while (j) {
+ j--;
+ mas_push_node(&mas, nodes[j]);
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != i);
+ for (j = 0; j <= i/2; j++) {
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
+ }
+ MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL));
+
+ }
+
+ /* Set allocation request. */
+ total = 500;
+ mas_node_count(&mas, total);
+ /* Drop the lock and allocate the nodes. */
+ mas_nomem(&mas, GFP_KERNEL);
+ MT_BUG_ON(mt, !mas.alloc);
+ i = 1;
+ smn = mas.alloc;
+ while (i < total) {
+ for (j = 0; j < MAPLE_ALLOC_SLOTS; j++) {
+ i++;
+ MT_BUG_ON(mt, !smn->slot[j]);
+ if (i == total)
+ break;
+ }
+ smn = smn->slot[0]; /* next. */
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != total);
+ mas_nomem(&mas, GFP_KERNEL); /* Free. */
+
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ for (i = 1; i < 128; i++) {
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
+ for (j = i; j > 0; j--) { /*Free the requests */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ }
+
+ for (i = 1; i < MAPLE_NODE_MASK + 1; i++) {
+ MA_STATE(mas2, mt, 0, 0);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
+ for (j = 1; j <= i; j++) { /* Move the allocations to mas2 */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, not_empty(mn));
+ mas_push_node(&mas2, mn);
+ MT_BUG_ON(mt, mas_allocated(&mas2) != j);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ MT_BUG_ON(mt, mas_allocated(&mas2) != i);
+
+ for (j = i; j > 0; j--) { /*Free the requests */
+ MT_BUG_ON(mt, mas_allocated(&mas2) != j);
+ mn = mas_pop_node(&mas2); /* get the next node. */
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas2) != 0);
+ }
+
+
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 1); /* Request */
+ MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
+ MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
+
+ mn = mas_pop_node(&mas); /* get the next node. */
+ MT_BUG_ON(mt, mn == NULL);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS);
+ MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 2);
+
+ mas_push_node(&mas, mn);
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
+ MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
+
+ /* Check the limit of pop/push/pop */
+ mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 2); /* Request */
+ MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
+ MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
+ MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
+ MT_BUG_ON(mt, mas_alloc_req(&mas));
+ MT_BUG_ON(mt, mas.alloc->node_count);
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
+ MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
+ mas_push_node(&mas, mn);
+ MT_BUG_ON(mt, mas.alloc->node_count);
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ for (i = 1; i <= MAPLE_ALLOC_SLOTS + 1; i++) {
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, not_empty(mn));
+ ma_free_rcu(mn);
+ }
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+
+
+ for (i = 3; i < MAPLE_NODE_MASK * 3; i++) {
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ mas_push_node(&mas, mn); /* put it back */
+ mas_destroy(&mas);
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ mn2 = mas_pop_node(&mas); /* get the next node. */
+ mas_push_node(&mas, mn); /* put them back */
+ mas_push_node(&mas, mn2);
+ mas_destroy(&mas);
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ mn2 = mas_pop_node(&mas); /* get the next node. */
+ mn3 = mas_pop_node(&mas); /* get the next node. */
+ mas_push_node(&mas, mn); /* put them back */
+ mas_push_node(&mas, mn2);
+ mas_push_node(&mas, mn3);
+ mas_destroy(&mas);
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ ma_free_rcu(mn);
+ mas_destroy(&mas);
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, i); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mn = mas_pop_node(&mas); /* get the next node. */
+ ma_free_rcu(mn);
+ mn = mas_pop_node(&mas); /* get the next node. */
+ ma_free_rcu(mn);
+ mn = mas_pop_node(&mas); /* get the next node. */
+ ma_free_rcu(mn);
+ mas_destroy(&mas);
+ }
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, 5); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ MT_BUG_ON(mt, mas_allocated(&mas) != 5);
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, 10); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mas.node = MAS_START;
+ MT_BUG_ON(mt, mas_allocated(&mas) != 10);
+ mas_destroy(&mas);
+
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, MAPLE_ALLOC_SLOTS - 1); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS - 1);
+ mas.node = MA_ERROR(-ENOMEM);
+ mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */
+ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
+ mas.node = MAS_START;
+ MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1);
+ mas_destroy(&mas);
+
+ mtree_unlock(mt);
+}
+
+/*
+ * Check erasing including RCU.
+ */
+static noinline void check_erase(struct maple_tree *mt, unsigned long index,
+ void *ptr)
+{
+ MT_BUG_ON(mt, mtree_test_erase(mt, index) != ptr);
+}
+
+#define erase_check_load(mt, i) check_load(mt, set[i], entry[i%2])
+#define erase_check_insert(mt, i) check_insert(mt, set[i], entry[i%2])
+#define erase_check_erase(mt, i) check_erase(mt, set[i], entry[i%2])
+
+static noinline void check_erase_testset(struct maple_tree *mt)
+{
+ unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
+ 1001, 1002, 1003, 1005, 0,
+ 6003, 6002, 6008, 6012, 6015,
+ 7003, 7002, 7008, 7012, 7015,
+ 8003, 8002, 8008, 8012, 8015,
+ 9003, 9002, 9008, 9012, 9015,
+ 10003, 10002, 10008, 10012, 10015,
+ 11003, 11002, 11008, 11012, 11015,
+ 12003, 12002, 12008, 12012, 12015,
+ 13003, 13002, 13008, 13012, 13015,
+ 14003, 14002, 14008, 14012, 14015,
+ 15003, 15002, 15008, 15012, 15015,
+ };
+
+
+ void *ptr = &set;
+ void *entry[2] = { ptr, mt };
+ void *root_node;
+
+
+ rcu_register_thread();
+ mt_set_in_rcu(mt);
+ for (int i = 0; i < 4; i++)
+ erase_check_insert(mt, i);
+ for (int i = 0; i < 4; i++)
+ erase_check_load(mt, i);
+
+ mt_set_non_kernel(2);
+ erase_check_erase(mt, 1);
+ erase_check_load(mt, 0);
+ check_load(mt, set[1], NULL);
+ for (int i = 2; i < 4; i++)
+ erase_check_load(mt, i);
+
+
+ erase_check_erase(mt, 2);
+ erase_check_load(mt, 0);
+ check_load(mt, set[1], NULL);
+ check_load(mt, set[2], NULL);
+
+ erase_check_insert(mt, 1);
+ erase_check_insert(mt, 2);
+
+ for (int i = 0; i < 4; i++)
+ erase_check_load(mt, i);
+
+ /* Check erase and load without an allocation. */
+ erase_check_load(mt, 3);
+ erase_check_erase(mt, 1);
+ erase_check_load(mt, 0);
+ check_load(mt, set[1], NULL);
+ for (int i = 2; i < 4; i++)
+ erase_check_load(mt, i);
+
+ /*
+ * Set the newly erased node. This will produce a different allocated
+ * node to avoid busy slots.
+ */
+ root_node = mt->ma_root;
+ erase_check_insert(mt, 1);
+
+ erase_check_load(mt, 0);
+ check_load(mt, 5016, NULL);
+ erase_check_load(mt, 1);
+ check_load(mt, 5013, NULL);
+ erase_check_load(mt, 2);
+ check_load(mt, 5018, NULL);
+ erase_check_load(mt, 3);
+
+ erase_check_erase(mt, 2); /* erase 5017 to check append */
+ erase_check_load(mt, 0);
+ check_load(mt, 5016, NULL);
+ erase_check_load(mt, 1);
+ check_load(mt, 5013, NULL);
+ check_load(mt, set[2], NULL);
+ check_load(mt, 5018, NULL);
+
+ erase_check_load(mt, 3);
+
+ root_node = mt->ma_root;
+ erase_check_insert(mt, 2);
+
+ erase_check_load(mt, 0);
+ check_load(mt, 5016, NULL);
+ erase_check_load(mt, 1);
+ check_load(mt, 5013, NULL);
+ erase_check_load(mt, 2);
+ check_load(mt, 5018, NULL);
+ erase_check_load(mt, 3);
+
+ mt_set_non_kernel(1);
+ erase_check_erase(mt, 2); /* erase 5017 to check append */
+ erase_check_load(mt, 0);
+ check_load(mt, 5016, NULL);
+ check_load(mt, set[2], NULL);
+ erase_check_erase(mt, 0); /* erase 5015 to check append */
+ check_load(mt, set[0], NULL);
+ check_load(mt, 5016, NULL);
+ erase_check_insert(mt, 4); /* 1000 < Should not split. */
+ check_load(mt, set[0], NULL);
+ check_load(mt, 5016, NULL);
+ erase_check_load(mt, 1);
+ check_load(mt, 5013, NULL);
+ check_load(mt, set[2], NULL);
+ check_load(mt, 5018, NULL);
+ erase_check_load(mt, 4);
+ check_load(mt, 999, NULL);
+ check_load(mt, 1001, NULL);
+ erase_check_load(mt, 4);
+ if (mt_in_rcu(mt))
+ MT_BUG_ON(mt, root_node == mt->ma_root);
+ else
+ MT_BUG_ON(mt, root_node != mt->ma_root);
+
+ /* Should not have split. */
+ MT_BUG_ON(mt, !mte_is_leaf(mt->ma_root));
+
+
+ /* Coalesce testing */
+ erase_check_insert(mt, 0);
+ erase_check_insert(mt, 2);
+
+ for (int i = 5; i < 25; i++) {
+ erase_check_insert(mt, i);
+ for (int j = i; j >= 0; j--)
+ erase_check_load(mt, j);
+ }
+
+ erase_check_erase(mt, 14); /*6015 */
+ for (int i = 0; i < 25; i++) {
+ if (i == 14)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+ erase_check_erase(mt, 16); /*7002 */
+ for (int i = 0; i < 25; i++) {
+ if (i == 16 || i == 14)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+
+ mt_set_non_kernel(1);
+ erase_check_erase(mt, 13); /*6012 */
+ for (int i = 0; i < 25; i++) {
+ if (i == 16 || i == 14 || i == 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ erase_check_erase(mt, 15); /*7003 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 16 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ mt_set_non_kernel(2);
+ erase_check_erase(mt, 17); /*7008 *should* cause coalesce. */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 17 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ erase_check_erase(mt, 18); /*7012 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 18 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ mt_set_non_kernel(2);
+ erase_check_erase(mt, 19); /*7015 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 19 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ erase_check_erase(mt, 20); /*8003 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 20 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ erase_check_erase(mt, 21); /*8002 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 21 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ mt_set_non_kernel(2);
+ erase_check_erase(mt, 22); /*8008 */
+ for (int i = 0; i < 25; i++) {
+ if (i <= 22 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+ for (int i = 23; i < 25; i++)
+ erase_check_erase(mt, i);
+
+ for (int i = 0; i < 25; i++) {
+ if (i <= 25 && i >= 13)
+ check_load(mt, set[i], NULL);
+ else
+ erase_check_load(mt, i);
+ }
+
+ /* Shrinking tree test. */
+
+ for (int i = 13; i < ARRAY_SIZE(set); i++)
+ erase_check_insert(mt, i);
+
+ mt_set_non_kernel(99);
+ for (int i = 18; i < ARRAY_SIZE(set); i++) {
+ erase_check_erase(mt, i);
+ for (int j = 0; j < ARRAY_SIZE(set); j++) {
+ if (j < 18 || j > i)
+ erase_check_load(mt, j);
+ else
+ check_load(mt, set[j], NULL);
+ }
+ }
+ mt_set_non_kernel(35);
+ for (int i = 0; i < 18; i++) {
+ erase_check_erase(mt, i);
+ for (int j = 0; j < ARRAY_SIZE(set); j++) {
+ if (j < 18 && j > i)
+ erase_check_load(mt, j);
+ else
+ check_load(mt, set[j], NULL);
+ }
+ }
+ erase_check_insert(mt, 8);
+ erase_check_insert(mt, 9);
+ erase_check_erase(mt, 8);
+ rcu_unregister_thread();
+}
+
+/* End of erase testing */
+
+/* VM Generated Crashes - uses its own tree walk for verification */
+#define erase_check_store_range(mt, a, i, ptr) mtree_test_store_range(mt, \
+ a[(i)], a[(i + 1)], ptr)
+#define STORE 1
+#define SNULL 2
+#define ERASE 3
+#define ec_type_str(x) \
+ (((x) == STORE) ? \
+ "STORE" : \
+ (((x) == SNULL) ? \
+ "SNULL" : "ERASE") \
+ )
+#define check_erase2_debug 0
+
+/* Calculate the overwritten entries. */
+int mas_ce2_over_count(struct ma_state *mas_start, struct ma_state *mas_end,
+ void *s_entry, unsigned long s_min,
+ void *e_entry, unsigned long e_max,
+ unsigned long *set, int i, bool null_entry)
+{
+ int count = 0, span = 0;
+ unsigned long retry = 0;
+ void *entry;
+ struct ma_state tmp;
+
+
+ /* count slots */
+ memcpy(&tmp, mas_start, sizeof(tmp));
+ entry = mas_next(&tmp, mas_end->last);
+ while (entry) {
+ BUG_ON(retry > 50); /* stop infinite retry on testing. */
+ if (xa_is_zero(s_entry)) {
+ retry++;
+ continue;
+ }
+ count++;
+ span++;
+ entry = mas_next(&tmp, mas_end->last);
+ }
+
+ if (null_entry) {
+ /* Check splitting end. */
+ if (e_entry && (e_max > mas_end->last))
+ count--;
+
+ /* check overwrite of entire start */
+ if (s_entry && (s_min == mas_start->index))
+ count++;
+ } else { /* !null_entry (store) */
+ bool esplit = e_max > mas_end->last;
+ bool ssplit = s_min != mas_start->index;
+
+ if (s_entry && e_entry) {
+ if (esplit && ssplit)
+ count--;
+ else if (ssplit)
+ count--;
+ else if (esplit) {
+ if (span)
+ count--;
+ }
+ } else if (s_entry && !e_entry) {
+ if (ssplit)
+ count--;
+ } else if (!s_entry && e_entry) {
+ if (esplit)
+ count--;
+ count--;
+ } else {
+ count--;
+ }
+ }
+ return count;
+}
+
+/*
+ * mas_node_walk() - Walk a maple node to offset of the index.
+ * @mas: The maple state
+ * @type: The maple node type
+ * @*range_min: Pointer to store the minimum range of the offset
+ * @*range_max: Pointer to store the maximum range of the offset
+ *
+ * The offset will be stored in the maple state.
+ *
+ */
+static inline void mas_node_walk(struct ma_state *mas, struct maple_node *node,
+ enum maple_type type, unsigned long *range_min,
+ unsigned long *range_max)
+
+{
+ unsigned long *pivots;
+ unsigned char count;
+ unsigned long prev, max;
+ unsigned char offset;
+ unsigned long index;
+
+ if (unlikely(ma_is_dense(type))) {
+ (*range_max) = (*range_min) = mas->index;
+ if (unlikely(ma_dead_node(node)))
+ return;
+
+ mas->offset = mas->index = mas->min;
+ return;
+ }
+
+ pivots = ma_pivots(node, type);
+ max = pivots[0];
+ if (unlikely(ma_dead_node(node)))
+ return;
+
+ offset = 0;
+ prev = mas->min;
+ index = mas->index;
+ if (unlikely(index <= max))
+ goto offset_zero;
+
+ count = mt_pivots[type];
+ while (++offset < count) {
+ prev = max;
+ max = pivots[offset];
+ if (unlikely(ma_dead_node(node)))
+ return;
+
+ if (index <= max)
+ goto offset_found;
+ else if (unlikely(!max))
+ goto mas_max;
+ }
+
+ prev = max;
+mas_max:
+ max = mas->max;
+offset_found:
+ prev++;
+offset_zero:
+ mas->offset = offset;
+ if (ma_is_leaf(type)) {
+ *range_max = max;
+ *range_min = prev;
+ } else {
+ mas->max = max;
+ mas->min = prev;
+ }
+}
+
+/*
+ * mas_descend_walk(): Locates a value and sets the mas->node and slot
+ * accordingly. range_min and range_max are set to the range which the entry is
+ * valid.
+ * @mas: The maple state
+ * @*range_min: A pointer to store the minimum of the range
+ * @*range_max: A pointer to store the maximum of the range
+ *
+ * Check mas->node is still valid on return of any value.
+ *
+ * Return: true if pointing to a valid node and offset. False otherwise.
+ */
+static inline bool mas_descend_walk(struct ma_state *mas,
+ unsigned long *range_min, unsigned long *range_max)
+{
+ struct maple_enode *next;
+ struct maple_node *node;
+ enum maple_type type;
+
+ next = mas->node;
+ while (true) {
+ node = mte_to_node(next);
+ type = mte_node_type(next);
+ mas_node_walk(mas, node, type, range_min, range_max);
+ next = mas_slot(mas, ma_slots(node, type), mas->offset);
+ if (unlikely(ma_dead_node(node)))
+ return false;
+
+ if (unlikely(ma_is_leaf(type)))
+ return true;
+
+ /* Descend. */
+ mas->node = next;
+ }
+ return false;
+}
+
+/*
+ * mas_tree_walk() - Walk to @mas->index and set the range values.
+ * @mas: The maple state.
+ * @*range_min: The minimum range to be set.
+ * @*range_max: The maximum range to be set.
+ *
+ * Ranges are only valid if there is a valid entry at @mas->index.
+ *
+ * Return: True if a value exists, false otherwise.
+ */
+static inline bool mas_tree_walk(struct ma_state *mas, unsigned long *range_min,
+ unsigned long *range_max)
+{
+ bool ret;
+
+retry:
+ ret = false;
+ mas_start(mas);
+ if (mas_is_none(mas))
+ goto not_found;
+
+ if (mas_is_ptr(mas)) {
+ *range_min = *range_max = 0;
+ if (!mas->index)
+ return true;
+
+ goto not_found;
+ }
+
+ ret = mas_descend_walk(mas, range_min, range_max);
+ if (unlikely(mte_dead_node(mas->node))) {
+ mas->node = MAS_START;
+ goto retry;
+ }
+
+ return ret;
+
+not_found:
+ mas->offset = MAPLE_NODE_SLOTS;
+ return false;
+}
+
+static inline void *mas_range_load(struct ma_state *mas,
+ unsigned long *range_min, unsigned long *range_max)
+
+{
+ void *entry = NULL;
+ unsigned long index = mas->index;
+
+ if (mas_is_none(mas) || mas_is_paused(mas))
+ mas->node = MAS_START;
+retry:
+ if (mas_tree_walk(mas, range_min, range_max))
+ if (unlikely(mas->node == MAS_ROOT))
+ return mas_root(mas);
+
+ if (likely(mas->offset != MAPLE_NODE_SLOTS))
+ entry = mas_get_slot(mas, mas->offset);
+
+ if (mas_dead_node(mas, index))
+ goto retry;
+
+ return entry;
+}
+
+#if defined(CONFIG_64BIT)
+static noinline void check_erase2_testset(struct maple_tree *mt,
+ unsigned long *set, unsigned long size)
+{
+ int entry_count = 0;
+ int check = 0;
+ void *foo;
+ unsigned long addr = 0;
+ void *s_entry = NULL, *e_entry = NULL;
+
+ MA_STATE(mas, mt, 0, 0);
+
+ for (int i = 0; i < size; i += 3) {
+ unsigned long s_min, s_max;
+ unsigned long e_min, e_max;
+ void *value = NULL;
+
+ MA_STATE(mas_start, mt, set[i+1], set[i+1]);
+ MA_STATE(mas_end, mt, set[i+2], set[i+2]);
+ mt_set_non_kernel(127);
+#if check_erase2_debug
+ pr_err("%s: %d %s %lu - %lu\n", __func__, i,
+ ec_type_str(set[i]),
+ set[i+1], set[i+2]);
+#endif
+ s_entry = mas_range_load(&mas_start, &s_min, &s_max);
+ e_entry = mas_range_load(&mas_end, &e_min, &e_max);
+
+ switch (set[i]) {
+ case SNULL:
+ if ((s_min == set[i+1]) && (s_max == set[i+2])) {
+ if (s_entry)
+ entry_count--;
+ } else if ((s_min != set[i+1]) && (s_max != set[i+2])) {
+ entry_count++;
+ } else if ((mas_start.node != mas_end.node) ||
+ (mas_start.offset != mas_end.offset)) {
+ entry_count -=
+ mas_ce2_over_count(&mas_start, &mas_end,
+ s_entry, s_min,
+ e_entry, e_max, set, i,
+ true);
+ }
+
+
+ erase_check_store_range(mt, set, i + 1, value);
+ break;
+ case STORE:
+ value = xa_mk_value(set[i + 1]);
+ if (mas_start.offset > mt_slot_count(mas_start.node)) {
+ entry_count++; /* appending an entry. */
+ } else if ((s_min == e_min) && (s_max == e_max)) {
+ if (!entry_count)
+ entry_count++;
+
+ else if (s_entry) {
+ if (e_max > mas_end.last)
+ entry_count++;
+
+ if (s_min < mas_start.index)
+ entry_count++;
+
+ } else {
+ entry_count++;
+ }
+ } else {
+ entry_count -=
+ mas_ce2_over_count(&mas_start, &mas_end,
+ s_entry, s_min,
+ e_entry, e_max, set, i,
+ false);
+ }
+
+ erase_check_store_range(mt, set, i + 1, value);
+ break;
+ case ERASE:
+ if (!s_entry)
+ break;
+ check_erase(mt, set[i+1], xa_mk_value(set[i+1]));
+ entry_count--;
+ break;
+ }
+ mt_validate(mt);
+ if (entry_count)
+ MT_BUG_ON(mt, !mt_height(mt));
+#if check_erase2_debug > 1
+ mt_dump(mt);
+#endif
+#if check_erase2_debug
+ pr_err("Done\n");
+#endif
+
+ check = 0;
+ addr = 0;
+ mt_for_each(mt, foo, addr, ULONG_MAX) {
+ check++;
+#if check_erase2_debug > 2
+ pr_err("mt: %lu -> %p (%d)\n", addr+1, foo, check);
+#endif
+ if (check > entry_count)
+ break;
+ }
+
+#if check_erase2_debug > 2
+ pr_err("mt_for_each %d and count %d\n", check, entry_count);
+#endif
+
+ MT_BUG_ON(mt, check != entry_count);
+
+ check = 0;
+ addr = 0;
+ mas_reset(&mas);
+ mas.index = 0;
+ rcu_read_lock();
+ mas_for_each(&mas, foo, ULONG_MAX) {
+ if (xa_is_zero(foo)) {
+ if (addr == mas.index) {
+ mt_dump(mas.tree);
+ pr_err("retry failed %lu - %lu\n",
+ mas.index, mas.last);
+ MT_BUG_ON(mt, 1);
+ }
+ addr = mas.index;
+ continue;
+ }
+#if check_erase2_debug > 2
+ pr_err("mas: %lu -> %p\n", mas.index, foo);
+#endif
+ check++;
+ if (check > entry_count)
+ break;
+ }
+ rcu_read_unlock();
+#if check_erase2_debug > 2
+ pr_err("mas_for_each %d and count %d\n", check, entry_count);
+ mt_validate(mt);
+#endif
+
+ MT_BUG_ON(mt, check != entry_count);
+
+ MT_BUG_ON(mt, mtree_load(mas.tree, 0) != NULL);
+ }
+}
+
+
+/* These tests were pulled from KVM tree modifications which failed. */
+static noinline void check_erase2_sets(struct maple_tree *mt)
+{
+ void *entry;
+ unsigned long start = 0;
+ unsigned long set[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140721266458624, 140737488351231,
+ERASE, 140721266458624, 140737488351231,
+STORE, 140721266458624, 140721266462719,
+STORE, 94735788949504, 94735789121535,
+ERASE, 94735788949504, 94735789121535,
+STORE, 94735788949504, 94735788965887,
+STORE, 94735788965888, 94735789121535,
+ERASE, 94735788965888, 94735789121535,
+STORE, 94735788965888, 94735789068287,
+STORE, 94735789068288, 94735789109247,
+STORE, 94735789109248, 94735789121535,
+STORE, 140253902692352, 140253902864383,
+ERASE, 140253902692352, 140253902864383,
+STORE, 140253902692352, 140253902696447,
+STORE, 140253902696448, 140253902864383,
+ };
+ unsigned long set2[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140735933583360, 140737488351231,
+ERASE, 140735933583360, 140737488351231,
+STORE, 140735933583360, 140735933587455,
+STORE, 94811003260928, 94811003432959,
+ERASE, 94811003260928, 94811003432959,
+STORE, 94811003260928, 94811003277311,
+STORE, 94811003277312, 94811003432959,
+ERASE, 94811003277312, 94811003432959,
+STORE, 94811003277312, 94811003379711,
+STORE, 94811003379712, 94811003420671,
+STORE, 94811003420672, 94811003432959,
+STORE, 140277094653952, 140277094825983,
+ERASE, 140277094653952, 140277094825983,
+STORE, 140277094653952, 140277094658047,
+STORE, 140277094658048, 140277094825983,
+ERASE, 140277094658048, 140277094825983,
+STORE, 140277094658048, 140277094780927,
+STORE, 140277094780928, 140277094813695,
+STORE, 140277094813696, 140277094821887,
+STORE, 140277094821888, 140277094825983,
+STORE, 140735933906944, 140735933911039,
+ };
+ unsigned long set3[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140735790264320, 140737488351231,
+ERASE, 140735790264320, 140737488351231,
+STORE, 140735790264320, 140735790268415,
+STORE, 94016597282816, 94016597454847,
+ERASE, 94016597282816, 94016597454847,
+STORE, 94016597282816, 94016597299199,
+STORE, 94016597299200, 94016597454847,
+ERASE, 94016597299200, 94016597454847,
+STORE, 94016597299200, 94016597401599,
+STORE, 94016597401600, 94016597442559,
+STORE, 94016597442560, 94016597454847,
+STORE, 140496959283200, 140496959455231,
+ERASE, 140496959283200, 140496959455231,
+STORE, 140496959283200, 140496959287295,
+STORE, 140496959287296, 140496959455231,
+ERASE, 140496959287296, 140496959455231,
+STORE, 140496959287296, 140496959410175,
+STORE, 140496959410176, 140496959442943,
+STORE, 140496959442944, 140496959451135,
+STORE, 140496959451136, 140496959455231,
+STORE, 140735791718400, 140735791722495,
+STORE, 140735791706112, 140735791718399,
+STORE, 47135835713536, 47135835721727,
+STORE, 47135835721728, 47135835729919,
+STORE, 47135835729920, 47135835893759,
+ERASE, 47135835729920, 47135835893759,
+STORE, 47135835729920, 47135835742207,
+STORE, 47135835742208, 47135835893759,
+STORE, 47135835840512, 47135835893759,
+STORE, 47135835742208, 47135835840511,
+ERASE, 47135835742208, 47135835840511,
+STORE, 47135835742208, 47135835840511,
+STORE, 47135835885568, 47135835893759,
+STORE, 47135835840512, 47135835885567,
+ERASE, 47135835840512, 47135835885567,
+STORE, 47135835840512, 47135835893759,
+ERASE, 47135835840512, 47135835893759,
+STORE, 47135835840512, 47135835885567,
+STORE, 47135835885568, 47135835893759,
+ };
+
+ unsigned long set4[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140728251703296, 140737488351231,
+ERASE, 140728251703296, 140737488351231,
+STORE, 140728251703296, 140728251707391,
+STORE, 94668429205504, 94668429377535,
+ERASE, 94668429205504, 94668429377535,
+STORE, 94668429205504, 94668429221887,
+STORE, 94668429221888, 94668429377535,
+ERASE, 94668429221888, 94668429377535,
+STORE, 94668429221888, 94668429324287,
+STORE, 94668429324288, 94668429365247,
+STORE, 94668429365248, 94668429377535,
+STORE, 47646523273216, 47646523445247,
+ERASE, 47646523273216, 47646523445247,
+STORE, 47646523273216, 47646523277311,
+STORE, 47646523277312, 47646523445247,
+ERASE, 47646523277312, 47646523445247,
+STORE, 47646523277312, 47646523400191,
+ };
+
+ unsigned long set5[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140726874062848, 140737488351231,
+ERASE, 140726874062848, 140737488351231,
+STORE, 140726874062848, 140726874066943,
+STORE, 94248892870656, 94248893042687,
+ERASE, 94248892870656, 94248893042687,
+STORE, 94248892870656, 94248892887039,
+STORE, 94248892887040, 94248893042687,
+ERASE, 94248892887040, 94248893042687,
+STORE, 94248892887040, 94248892989439,
+STORE, 94248892989440, 94248893030399,
+STORE, 94248893030400, 94248893042687,
+STORE, 47884786266112, 47884786438143,
+ERASE, 47884786266112, 47884786438143,
+STORE, 47884786266112, 47884786270207,
+STORE, 47884786270208, 47884786438143,
+ERASE, 47884786270208, 47884786438143,
+STORE, 47884786270208, 47884786393087,
+STORE, 47884786393088, 47884786425855,
+STORE, 47884786425856, 47884786434047,
+STORE, 47884786434048, 47884786438143,
+STORE, 140726874513408, 140726874517503,
+STORE, 140726874501120, 140726874513407,
+STORE, 47884786438144, 47884786446335,
+STORE, 47884786446336, 47884786454527,
+STORE, 47884786454528, 47884786618367,
+ERASE, 47884786454528, 47884786618367,
+STORE, 47884786454528, 47884786466815,
+STORE, 47884786466816, 47884786618367,
+STORE, 47884786565120, 47884786618367,
+STORE, 47884786466816, 47884786565119,
+ERASE, 47884786466816, 47884786565119,
+STORE, 47884786466816, 47884786565119,
+STORE, 47884786610176, 47884786618367,
+STORE, 47884786565120, 47884786610175,
+ERASE, 47884786565120, 47884786610175,
+STORE, 47884786565120, 47884786618367,
+ERASE, 47884786565120, 47884786618367,
+STORE, 47884786565120, 47884786610175,
+STORE, 47884786610176, 47884786618367,
+ERASE, 47884786610176, 47884786618367,
+STORE, 47884786610176, 47884786618367,
+STORE, 47884786618368, 47884789669887,
+STORE, 47884787163136, 47884789669887,
+STORE, 47884786618368, 47884787163135,
+ERASE, 47884787163136, 47884789669887,
+STORE, 47884787163136, 47884789448703,
+STORE, 47884789448704, 47884789669887,
+STORE, 47884788858880, 47884789448703,
+STORE, 47884787163136, 47884788858879,
+ERASE, 47884787163136, 47884788858879,
+STORE, 47884787163136, 47884788858879,
+STORE, 47884789444608, 47884789448703,
+STORE, 47884788858880, 47884789444607,
+ERASE, 47884788858880, 47884789444607,
+STORE, 47884788858880, 47884789444607,
+STORE, 47884789653504, 47884789669887,
+STORE, 47884789448704, 47884789653503,
+ERASE, 47884789448704, 47884789653503,
+STORE, 47884789448704, 47884789653503,
+ERASE, 47884789653504, 47884789669887,
+STORE, 47884789653504, 47884789669887,
+STORE, 47884789669888, 47884791508991,
+STORE, 47884789809152, 47884791508991,
+STORE, 47884789669888, 47884789809151,
+ERASE, 47884789809152, 47884791508991,
+STORE, 47884789809152, 47884791468031,
+STORE, 47884791468032, 47884791508991,
+STORE, 47884791152640, 47884791468031,
+STORE, 47884789809152, 47884791152639,
+ERASE, 47884789809152, 47884791152639,
+STORE, 47884789809152, 47884791152639,
+STORE, 47884791463936, 47884791468031,
+STORE, 47884791152640, 47884791463935,
+ERASE, 47884791152640, 47884791463935,
+STORE, 47884791152640, 47884791463935,
+STORE, 47884791492608, 47884791508991,
+STORE, 47884791468032, 47884791492607,
+ERASE, 47884791468032, 47884791492607,
+STORE, 47884791468032, 47884791492607,
+ERASE, 47884791492608, 47884791508991,
+STORE, 47884791492608, 47884791508991,
+STORE, 47884791508992, 47884791644159,
+ERASE, 47884791508992, 47884791644159,
+STORE, 47884791508992, 47884791533567,
+STORE, 47884791533568, 47884791644159,
+STORE, 47884791595008, 47884791644159,
+STORE, 47884791533568, 47884791595007,
+ERASE, 47884791533568, 47884791595007,
+STORE, 47884791533568, 47884791595007,
+STORE, 47884791619584, 47884791644159,
+STORE, 47884791595008, 47884791619583,
+ERASE, 47884791595008, 47884791619583,
+STORE, 47884791595008, 47884791644159,
+ERASE, 47884791595008, 47884791644159,
+STORE, 47884791595008, 47884791619583,
+STORE, 47884791619584, 47884791644159,
+STORE, 47884791627776, 47884791644159,
+STORE, 47884791619584, 47884791627775,
+ERASE, 47884791619584, 47884791627775,
+STORE, 47884791619584, 47884791627775,
+ERASE, 47884791627776, 47884791644159,
+STORE, 47884791627776, 47884791644159,
+STORE, 47884791644160, 47884791664639,
+ERASE, 47884791644160, 47884791664639,
+STORE, 47884791644160, 47884791648255,
+STORE, 47884791648256, 47884791664639,
+STORE, 47884791652352, 47884791664639,
+STORE, 47884791648256, 47884791652351,
+ERASE, 47884791648256, 47884791652351,
+STORE, 47884791648256, 47884791652351,
+STORE, 47884791656448, 47884791664639,
+STORE, 47884791652352, 47884791656447,
+ERASE, 47884791652352, 47884791656447,
+STORE, 47884791652352, 47884791664639,
+ERASE, 47884791652352, 47884791664639,
+STORE, 47884791652352, 47884791656447,
+STORE, 47884791656448, 47884791664639,
+ERASE, 47884791656448, 47884791664639,
+STORE, 47884791656448, 47884791664639,
+STORE, 47884791664640, 47884791672831,
+ERASE, 47884791468032, 47884791492607,
+STORE, 47884791468032, 47884791484415,
+STORE, 47884791484416, 47884791492607,
+ERASE, 47884791656448, 47884791664639,
+STORE, 47884791656448, 47884791660543,
+STORE, 47884791660544, 47884791664639,
+ERASE, 47884791619584, 47884791627775,
+STORE, 47884791619584, 47884791623679,
+STORE, 47884791623680, 47884791627775,
+ };
+
+ unsigned long set6[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140722999021568, 140737488351231,
+ERASE, 140722999021568, 140737488351231,
+STORE, 140722999021568, 140722999025663,
+STORE, 94901500268544, 94901500440575,
+ERASE, 94901500268544, 94901500440575,
+STORE, 94901500268544, 94901500284927,
+STORE, 94901500284928, 94901500440575,
+ERASE, 94901500284928, 94901500440575,
+STORE, 94901500284928, 94901500387327,
+STORE, 94901500387328, 94901500428287,
+STORE, 94901500428288, 94901500440575,
+STORE, 47430426660864, 47430426832895,
+ERASE, 47430426660864, 47430426832895,
+STORE, 47430426660864, 47430426664959,
+STORE, 47430426664960, 47430426832895,
+ERASE, 47430426664960, 47430426832895,
+STORE, 47430426664960, 47430426787839,
+STORE, 47430426787840, 47430426820607,
+STORE, 47430426820608, 47430426828799,
+STORE, 47430426828800, 47430426832895,
+STORE, 140722999115776, 140722999119871,
+STORE, 140722999103488, 140722999115775,
+STORE, 47430426832896, 47430426841087,
+STORE, 47430426841088, 47430426849279,
+STORE, 47430426849280, 47430427013119,
+ERASE, 47430426849280, 47430427013119,
+STORE, 47430426849280, 47430426861567,
+STORE, 47430426861568, 47430427013119,
+STORE, 47430426959872, 47430427013119,
+STORE, 47430426861568, 47430426959871,
+ERASE, 47430426861568, 47430426959871,
+STORE, 47430426861568, 47430426959871,
+STORE, 47430427004928, 47430427013119,
+STORE, 47430426959872, 47430427004927,
+ERASE, 47430426959872, 47430427004927,
+STORE, 47430426959872, 47430427013119,
+ERASE, 47430426959872, 47430427013119,
+STORE, 47430426959872, 47430427004927,
+STORE, 47430427004928, 47430427013119,
+ERASE, 47430427004928, 47430427013119,
+STORE, 47430427004928, 47430427013119,
+STORE, 47430427013120, 47430430064639,
+STORE, 47430427557888, 47430430064639,
+STORE, 47430427013120, 47430427557887,
+ERASE, 47430427557888, 47430430064639,
+STORE, 47430427557888, 47430429843455,
+STORE, 47430429843456, 47430430064639,
+STORE, 47430429253632, 47430429843455,
+STORE, 47430427557888, 47430429253631,
+ERASE, 47430427557888, 47430429253631,
+STORE, 47430427557888, 47430429253631,
+STORE, 47430429839360, 47430429843455,
+STORE, 47430429253632, 47430429839359,
+ERASE, 47430429253632, 47430429839359,
+STORE, 47430429253632, 47430429839359,
+STORE, 47430430048256, 47430430064639,
+STORE, 47430429843456, 47430430048255,
+ERASE, 47430429843456, 47430430048255,
+STORE, 47430429843456, 47430430048255,
+ERASE, 47430430048256, 47430430064639,
+STORE, 47430430048256, 47430430064639,
+STORE, 47430430064640, 47430431903743,
+STORE, 47430430203904, 47430431903743,
+STORE, 47430430064640, 47430430203903,
+ERASE, 47430430203904, 47430431903743,
+STORE, 47430430203904, 47430431862783,
+STORE, 47430431862784, 47430431903743,
+STORE, 47430431547392, 47430431862783,
+STORE, 47430430203904, 47430431547391,
+ERASE, 47430430203904, 47430431547391,
+STORE, 47430430203904, 47430431547391,
+STORE, 47430431858688, 47430431862783,
+STORE, 47430431547392, 47430431858687,
+ERASE, 47430431547392, 47430431858687,
+STORE, 47430431547392, 47430431858687,
+STORE, 47430431887360, 47430431903743,
+STORE, 47430431862784, 47430431887359,
+ERASE, 47430431862784, 47430431887359,
+STORE, 47430431862784, 47430431887359,
+ERASE, 47430431887360, 47430431903743,
+STORE, 47430431887360, 47430431903743,
+STORE, 47430431903744, 47430432038911,
+ERASE, 47430431903744, 47430432038911,
+STORE, 47430431903744, 47430431928319,
+STORE, 47430431928320, 47430432038911,
+STORE, 47430431989760, 47430432038911,
+STORE, 47430431928320, 47430431989759,
+ERASE, 47430431928320, 47430431989759,
+STORE, 47430431928320, 47430431989759,
+STORE, 47430432014336, 47430432038911,
+STORE, 47430431989760, 47430432014335,
+ERASE, 47430431989760, 47430432014335,
+STORE, 47430431989760, 47430432038911,
+ERASE, 47430431989760, 47430432038911,
+STORE, 47430431989760, 47430432014335,
+STORE, 47430432014336, 47430432038911,
+STORE, 47430432022528, 47430432038911,
+STORE, 47430432014336, 47430432022527,
+ERASE, 47430432014336, 47430432022527,
+STORE, 47430432014336, 47430432022527,
+ERASE, 47430432022528, 47430432038911,
+STORE, 47430432022528, 47430432038911,
+STORE, 47430432038912, 47430432059391,
+ERASE, 47430432038912, 47430432059391,
+STORE, 47430432038912, 47430432043007,
+STORE, 47430432043008, 47430432059391,
+STORE, 47430432047104, 47430432059391,
+STORE, 47430432043008, 47430432047103,
+ERASE, 47430432043008, 47430432047103,
+STORE, 47430432043008, 47430432047103,
+STORE, 47430432051200, 47430432059391,
+STORE, 47430432047104, 47430432051199,
+ERASE, 47430432047104, 47430432051199,
+STORE, 47430432047104, 47430432059391,
+ERASE, 47430432047104, 47430432059391,
+STORE, 47430432047104, 47430432051199,
+STORE, 47430432051200, 47430432059391,
+ERASE, 47430432051200, 47430432059391,
+STORE, 47430432051200, 47430432059391,
+STORE, 47430432059392, 47430432067583,
+ERASE, 47430431862784, 47430431887359,
+STORE, 47430431862784, 47430431879167,
+STORE, 47430431879168, 47430431887359,
+ERASE, 47430432051200, 47430432059391,
+STORE, 47430432051200, 47430432055295,
+STORE, 47430432055296, 47430432059391,
+ERASE, 47430432014336, 47430432022527,
+STORE, 47430432014336, 47430432018431,
+STORE, 47430432018432, 47430432022527,
+ };
+ unsigned long set7[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140729808330752, 140737488351231,
+ERASE, 140729808330752, 140737488351231,
+STORE, 140729808330752, 140729808334847,
+STORE, 94629632020480, 94629632192511,
+ERASE, 94629632020480, 94629632192511,
+STORE, 94629632020480, 94629632036863,
+STORE, 94629632036864, 94629632192511,
+ERASE, 94629632036864, 94629632192511,
+STORE, 94629632036864, 94629632139263,
+STORE, 94629632139264, 94629632180223,
+STORE, 94629632180224, 94629632192511,
+STORE, 47439981776896, 47439981948927,
+ERASE, 47439981776896, 47439981948927,
+STORE, 47439981776896, 47439981780991,
+STORE, 47439981780992, 47439981948927,
+ERASE, 47439981780992, 47439981948927,
+STORE, 47439981780992, 47439981903871,
+STORE, 47439981903872, 47439981936639,
+STORE, 47439981936640, 47439981944831,
+STORE, 47439981944832, 47439981948927,
+STORE, 140729808474112, 140729808478207,
+STORE, 140729808461824, 140729808474111,
+STORE, 47439981948928, 47439981957119,
+STORE, 47439981957120, 47439981965311,
+STORE, 47439981965312, 47439982129151,
+ERASE, 47439981965312, 47439982129151,
+STORE, 47439981965312, 47439981977599,
+STORE, 47439981977600, 47439982129151,
+STORE, 47439982075904, 47439982129151,
+STORE, 47439981977600, 47439982075903,
+ERASE, 47439981977600, 47439982075903,
+STORE, 47439981977600, 47439982075903,
+STORE, 47439982120960, 47439982129151,
+STORE, 47439982075904, 47439982120959,
+ERASE, 47439982075904, 47439982120959,
+STORE, 47439982075904, 47439982129151,
+ERASE, 47439982075904, 47439982129151,
+STORE, 47439982075904, 47439982120959,
+STORE, 47439982120960, 47439982129151,
+ERASE, 47439982120960, 47439982129151,
+STORE, 47439982120960, 47439982129151,
+STORE, 47439982129152, 47439985180671,
+STORE, 47439982673920, 47439985180671,
+STORE, 47439982129152, 47439982673919,
+ERASE, 47439982673920, 47439985180671,
+STORE, 47439982673920, 47439984959487,
+STORE, 47439984959488, 47439985180671,
+STORE, 47439984369664, 47439984959487,
+STORE, 47439982673920, 47439984369663,
+ERASE, 47439982673920, 47439984369663,
+STORE, 47439982673920, 47439984369663,
+STORE, 47439984955392, 47439984959487,
+STORE, 47439984369664, 47439984955391,
+ERASE, 47439984369664, 47439984955391,
+STORE, 47439984369664, 47439984955391,
+STORE, 47439985164288, 47439985180671,
+STORE, 47439984959488, 47439985164287,
+ERASE, 47439984959488, 47439985164287,
+STORE, 47439984959488, 47439985164287,
+ERASE, 47439985164288, 47439985180671,
+STORE, 47439985164288, 47439985180671,
+STORE, 47439985180672, 47439987019775,
+STORE, 47439985319936, 47439987019775,
+STORE, 47439985180672, 47439985319935,
+ERASE, 47439985319936, 47439987019775,
+STORE, 47439985319936, 47439986978815,
+STORE, 47439986978816, 47439987019775,
+STORE, 47439986663424, 47439986978815,
+STORE, 47439985319936, 47439986663423,
+ERASE, 47439985319936, 47439986663423,
+STORE, 47439985319936, 47439986663423,
+STORE, 47439986974720, 47439986978815,
+STORE, 47439986663424, 47439986974719,
+ERASE, 47439986663424, 47439986974719,
+STORE, 47439986663424, 47439986974719,
+STORE, 47439987003392, 47439987019775,
+STORE, 47439986978816, 47439987003391,
+ERASE, 47439986978816, 47439987003391,
+STORE, 47439986978816, 47439987003391,
+ERASE, 47439987003392, 47439987019775,
+STORE, 47439987003392, 47439987019775,
+STORE, 47439987019776, 47439987154943,
+ERASE, 47439987019776, 47439987154943,
+STORE, 47439987019776, 47439987044351,
+STORE, 47439987044352, 47439987154943,
+STORE, 47439987105792, 47439987154943,
+STORE, 47439987044352, 47439987105791,
+ERASE, 47439987044352, 47439987105791,
+STORE, 47439987044352, 47439987105791,
+STORE, 47439987130368, 47439987154943,
+STORE, 47439987105792, 47439987130367,
+ERASE, 47439987105792, 47439987130367,
+STORE, 47439987105792, 47439987154943,
+ERASE, 47439987105792, 47439987154943,
+STORE, 47439987105792, 47439987130367,
+STORE, 47439987130368, 47439987154943,
+STORE, 47439987138560, 47439987154943,
+STORE, 47439987130368, 47439987138559,
+ERASE, 47439987130368, 47439987138559,
+STORE, 47439987130368, 47439987138559,
+ERASE, 47439987138560, 47439987154943,
+STORE, 47439987138560, 47439987154943,
+STORE, 47439987154944, 47439987175423,
+ERASE, 47439987154944, 47439987175423,
+STORE, 47439987154944, 47439987159039,
+STORE, 47439987159040, 47439987175423,
+STORE, 47439987163136, 47439987175423,
+STORE, 47439987159040, 47439987163135,
+ERASE, 47439987159040, 47439987163135,
+STORE, 47439987159040, 47439987163135,
+STORE, 47439987167232, 47439987175423,
+STORE, 47439987163136, 47439987167231,
+ERASE, 47439987163136, 47439987167231,
+STORE, 47439987163136, 47439987175423,
+ERASE, 47439987163136, 47439987175423,
+STORE, 47439987163136, 47439987167231,
+STORE, 47439987167232, 47439987175423,
+ERASE, 47439987167232, 47439987175423,
+STORE, 47439987167232, 47439987175423,
+STORE, 47439987175424, 47439987183615,
+ERASE, 47439986978816, 47439987003391,
+STORE, 47439986978816, 47439986995199,
+STORE, 47439986995200, 47439987003391,
+ERASE, 47439987167232, 47439987175423,
+STORE, 47439987167232, 47439987171327,
+STORE, 47439987171328, 47439987175423,
+ERASE, 47439987130368, 47439987138559,
+STORE, 47439987130368, 47439987134463,
+STORE, 47439987134464, 47439987138559,
+ };
+ unsigned long set8[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140722482974720, 140737488351231,
+ERASE, 140722482974720, 140737488351231,
+STORE, 140722482974720, 140722482978815,
+STORE, 94121505034240, 94121505206271,
+ERASE, 94121505034240, 94121505206271,
+STORE, 94121505034240, 94121505050623,
+STORE, 94121505050624, 94121505206271,
+ERASE, 94121505050624, 94121505206271,
+STORE, 94121505050624, 94121505153023,
+STORE, 94121505153024, 94121505193983,
+STORE, 94121505193984, 94121505206271,
+STORE, 47708483284992, 47708483457023,
+ERASE, 47708483284992, 47708483457023,
+STORE, 47708483284992, 47708483289087,
+STORE, 47708483289088, 47708483457023,
+ERASE, 47708483289088, 47708483457023,
+STORE, 47708483289088, 47708483411967,
+STORE, 47708483411968, 47708483444735,
+STORE, 47708483444736, 47708483452927,
+STORE, 47708483452928, 47708483457023,
+STORE, 140722483142656, 140722483146751,
+STORE, 140722483130368, 140722483142655,
+STORE, 47708483457024, 47708483465215,
+STORE, 47708483465216, 47708483473407,
+STORE, 47708483473408, 47708483637247,
+ERASE, 47708483473408, 47708483637247,
+STORE, 47708483473408, 47708483485695,
+STORE, 47708483485696, 47708483637247,
+STORE, 47708483584000, 47708483637247,
+STORE, 47708483485696, 47708483583999,
+ERASE, 47708483485696, 47708483583999,
+STORE, 47708483485696, 47708483583999,
+STORE, 47708483629056, 47708483637247,
+STORE, 47708483584000, 47708483629055,
+ERASE, 47708483584000, 47708483629055,
+STORE, 47708483584000, 47708483637247,
+ERASE, 47708483584000, 47708483637247,
+STORE, 47708483584000, 47708483629055,
+STORE, 47708483629056, 47708483637247,
+ERASE, 47708483629056, 47708483637247,
+STORE, 47708483629056, 47708483637247,
+STORE, 47708483637248, 47708486688767,
+STORE, 47708484182016, 47708486688767,
+STORE, 47708483637248, 47708484182015,
+ERASE, 47708484182016, 47708486688767,
+STORE, 47708484182016, 47708486467583,
+STORE, 47708486467584, 47708486688767,
+STORE, 47708485877760, 47708486467583,
+STORE, 47708484182016, 47708485877759,
+ERASE, 47708484182016, 47708485877759,
+STORE, 47708484182016, 47708485877759,
+STORE, 47708486463488, 47708486467583,
+STORE, 47708485877760, 47708486463487,
+ERASE, 47708485877760, 47708486463487,
+STORE, 47708485877760, 47708486463487,
+STORE, 47708486672384, 47708486688767,
+STORE, 47708486467584, 47708486672383,
+ERASE, 47708486467584, 47708486672383,
+STORE, 47708486467584, 47708486672383,
+ERASE, 47708486672384, 47708486688767,
+STORE, 47708486672384, 47708486688767,
+STORE, 47708486688768, 47708488527871,
+STORE, 47708486828032, 47708488527871,
+STORE, 47708486688768, 47708486828031,
+ERASE, 47708486828032, 47708488527871,
+STORE, 47708486828032, 47708488486911,
+STORE, 47708488486912, 47708488527871,
+STORE, 47708488171520, 47708488486911,
+STORE, 47708486828032, 47708488171519,
+ERASE, 47708486828032, 47708488171519,
+STORE, 47708486828032, 47708488171519,
+STORE, 47708488482816, 47708488486911,
+STORE, 47708488171520, 47708488482815,
+ERASE, 47708488171520, 47708488482815,
+STORE, 47708488171520, 47708488482815,
+STORE, 47708488511488, 47708488527871,
+STORE, 47708488486912, 47708488511487,
+ERASE, 47708488486912, 47708488511487,
+STORE, 47708488486912, 47708488511487,
+ERASE, 47708488511488, 47708488527871,
+STORE, 47708488511488, 47708488527871,
+STORE, 47708488527872, 47708488663039,
+ERASE, 47708488527872, 47708488663039,
+STORE, 47708488527872, 47708488552447,
+STORE, 47708488552448, 47708488663039,
+STORE, 47708488613888, 47708488663039,
+STORE, 47708488552448, 47708488613887,
+ERASE, 47708488552448, 47708488613887,
+STORE, 47708488552448, 47708488613887,
+STORE, 47708488638464, 47708488663039,
+STORE, 47708488613888, 47708488638463,
+ERASE, 47708488613888, 47708488638463,
+STORE, 47708488613888, 47708488663039,
+ERASE, 47708488613888, 47708488663039,
+STORE, 47708488613888, 47708488638463,
+STORE, 47708488638464, 47708488663039,
+STORE, 47708488646656, 47708488663039,
+STORE, 47708488638464, 47708488646655,
+ERASE, 47708488638464, 47708488646655,
+STORE, 47708488638464, 47708488646655,
+ERASE, 47708488646656, 47708488663039,
+STORE, 47708488646656, 47708488663039,
+STORE, 47708488663040, 47708488683519,
+ERASE, 47708488663040, 47708488683519,
+STORE, 47708488663040, 47708488667135,
+STORE, 47708488667136, 47708488683519,
+STORE, 47708488671232, 47708488683519,
+STORE, 47708488667136, 47708488671231,
+ERASE, 47708488667136, 47708488671231,
+STORE, 47708488667136, 47708488671231,
+STORE, 47708488675328, 47708488683519,
+STORE, 47708488671232, 47708488675327,
+ERASE, 47708488671232, 47708488675327,
+STORE, 47708488671232, 47708488683519,
+ERASE, 47708488671232, 47708488683519,
+STORE, 47708488671232, 47708488675327,
+STORE, 47708488675328, 47708488683519,
+ERASE, 47708488675328, 47708488683519,
+STORE, 47708488675328, 47708488683519,
+STORE, 47708488683520, 47708488691711,
+ERASE, 47708488486912, 47708488511487,
+STORE, 47708488486912, 47708488503295,
+STORE, 47708488503296, 47708488511487,
+ERASE, 47708488675328, 47708488683519,
+STORE, 47708488675328, 47708488679423,
+STORE, 47708488679424, 47708488683519,
+ERASE, 47708488638464, 47708488646655,
+STORE, 47708488638464, 47708488642559,
+STORE, 47708488642560, 47708488646655,
+ };
+
+ unsigned long set9[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140736427839488, 140737488351231,
+ERASE, 140736427839488, 140736427839488,
+STORE, 140736427839488, 140736427843583,
+STORE, 94071213395968, 94071213567999,
+ERASE, 94071213395968, 94071213395968,
+STORE, 94071213395968, 94071213412351,
+STORE, 94071213412352, 94071213567999,
+ERASE, 94071213412352, 94071213412352,
+STORE, 94071213412352, 94071213514751,
+STORE, 94071213514752, 94071213555711,
+STORE, 94071213555712, 94071213567999,
+STORE, 139968410644480, 139968410816511,
+ERASE, 139968410644480, 139968410644480,
+STORE, 139968410644480, 139968410648575,
+STORE, 139968410648576, 139968410816511,
+ERASE, 139968410648576, 139968410648576,
+STORE, 139968410648576, 139968410771455,
+STORE, 139968410771456, 139968410804223,
+STORE, 139968410804224, 139968410812415,
+STORE, 139968410812416, 139968410816511,
+STORE, 140736429277184, 140736429281279,
+STORE, 140736429264896, 140736429277183,
+STORE, 47664384352256, 47664384360447,
+STORE, 47664384360448, 47664384368639,
+STORE, 47664384368640, 47664384532479,
+ERASE, 47664384368640, 47664384368640,
+STORE, 47664384368640, 47664384380927,
+STORE, 47664384380928, 47664384532479,
+STORE, 47664384479232, 47664384532479,
+STORE, 47664384380928, 47664384479231,
+ERASE, 47664384380928, 47664384380928,
+STORE, 47664384380928, 47664384479231,
+STORE, 47664384524288, 47664384532479,
+STORE, 47664384479232, 47664384524287,
+ERASE, 47664384479232, 47664384479232,
+STORE, 47664384479232, 47664384532479,
+ERASE, 47664384479232, 47664384479232,
+STORE, 47664384479232, 47664384524287,
+STORE, 47664384524288, 47664384532479,
+ERASE, 47664384524288, 47664384524288,
+STORE, 47664384524288, 47664384532479,
+STORE, 47664384532480, 47664387583999,
+STORE, 47664385077248, 47664387583999,
+STORE, 47664384532480, 47664385077247,
+ERASE, 47664385077248, 47664385077248,
+STORE, 47664385077248, 47664387362815,
+STORE, 47664387362816, 47664387583999,
+STORE, 47664386772992, 47664387362815,
+STORE, 47664385077248, 47664386772991,
+ERASE, 47664385077248, 47664385077248,
+STORE, 47664385077248, 47664386772991,
+STORE, 47664387358720, 47664387362815,
+STORE, 47664386772992, 47664387358719,
+ERASE, 47664386772992, 47664386772992,
+STORE, 47664386772992, 47664387358719,
+STORE, 47664387567616, 47664387583999,
+STORE, 47664387362816, 47664387567615,
+ERASE, 47664387362816, 47664387362816,
+STORE, 47664387362816, 47664387567615,
+ERASE, 47664387567616, 47664387567616,
+STORE, 47664387567616, 47664387583999,
+STORE, 47664387584000, 47664389423103,
+STORE, 47664387723264, 47664389423103,
+STORE, 47664387584000, 47664387723263,
+ERASE, 47664387723264, 47664387723264,
+STORE, 47664387723264, 47664389382143,
+STORE, 47664389382144, 47664389423103,
+STORE, 47664389066752, 47664389382143,
+STORE, 47664387723264, 47664389066751,
+ERASE, 47664387723264, 47664387723264,
+STORE, 47664387723264, 47664389066751,
+STORE, 47664389378048, 47664389382143,
+STORE, 47664389066752, 47664389378047,
+ERASE, 47664389066752, 47664389066752,
+STORE, 47664389066752, 47664389378047,
+STORE, 47664389406720, 47664389423103,
+STORE, 47664389382144, 47664389406719,
+ERASE, 47664389382144, 47664389382144,
+STORE, 47664389382144, 47664389406719,
+ERASE, 47664389406720, 47664389406720,
+STORE, 47664389406720, 47664389423103,
+STORE, 47664389423104, 47664389558271,
+ERASE, 47664389423104, 47664389423104,
+STORE, 47664389423104, 47664389447679,
+STORE, 47664389447680, 47664389558271,
+STORE, 47664389509120, 47664389558271,
+STORE, 47664389447680, 47664389509119,
+ERASE, 47664389447680, 47664389447680,
+STORE, 47664389447680, 47664389509119,
+STORE, 47664389533696, 47664389558271,
+STORE, 47664389509120, 47664389533695,
+ERASE, 47664389509120, 47664389509120,
+STORE, 47664389509120, 47664389558271,
+ERASE, 47664389509120, 47664389509120,
+STORE, 47664389509120, 47664389533695,
+STORE, 47664389533696, 47664389558271,
+STORE, 47664389541888, 47664389558271,
+STORE, 47664389533696, 47664389541887,
+ERASE, 47664389533696, 47664389533696,
+STORE, 47664389533696, 47664389541887,
+ERASE, 47664389541888, 47664389541888,
+STORE, 47664389541888, 47664389558271,
+STORE, 47664389558272, 47664389578751,
+ERASE, 47664389558272, 47664389558272,
+STORE, 47664389558272, 47664389562367,
+STORE, 47664389562368, 47664389578751,
+STORE, 47664389566464, 47664389578751,
+STORE, 47664389562368, 47664389566463,
+ERASE, 47664389562368, 47664389562368,
+STORE, 47664389562368, 47664389566463,
+STORE, 47664389570560, 47664389578751,
+STORE, 47664389566464, 47664389570559,
+ERASE, 47664389566464, 47664389566464,
+STORE, 47664389566464, 47664389578751,
+ERASE, 47664389566464, 47664389566464,
+STORE, 47664389566464, 47664389570559,
+STORE, 47664389570560, 47664389578751,
+ERASE, 47664389570560, 47664389570560,
+STORE, 47664389570560, 47664389578751,
+STORE, 47664389578752, 47664389586943,
+ERASE, 47664389382144, 47664389382144,
+STORE, 47664389382144, 47664389398527,
+STORE, 47664389398528, 47664389406719,
+ERASE, 47664389570560, 47664389570560,
+STORE, 47664389570560, 47664389574655,
+STORE, 47664389574656, 47664389578751,
+ERASE, 47664389533696, 47664389533696,
+STORE, 47664389533696, 47664389537791,
+STORE, 47664389537792, 47664389541887,
+ERASE, 47664387362816, 47664387362816,
+STORE, 47664387362816, 47664387559423,
+STORE, 47664387559424, 47664387567615,
+ERASE, 47664384524288, 47664384524288,
+STORE, 47664384524288, 47664384528383,
+STORE, 47664384528384, 47664384532479,
+ERASE, 94071213555712, 94071213555712,
+STORE, 94071213555712, 94071213563903,
+STORE, 94071213563904, 94071213567999,
+ERASE, 139968410804224, 139968410804224,
+STORE, 139968410804224, 139968410808319,
+STORE, 139968410808320, 139968410812415,
+ERASE, 47664384352256, 47664384352256,
+STORE, 94071244402688, 94071244537855,
+STORE, 140737488347136, 140737488351231,
+STORE, 140728271503360, 140737488351231,
+ERASE, 140728271503360, 140728271503360,
+STORE, 140728271503360, 140728271507455,
+STORE, 94410361982976, 94410362155007,
+ERASE, 94410361982976, 94410361982976,
+STORE, 94410361982976, 94410361999359,
+STORE, 94410361999360, 94410362155007,
+ERASE, 94410361999360, 94410361999360,
+STORE, 94410361999360, 94410362101759,
+STORE, 94410362101760, 94410362142719,
+STORE, 94410362142720, 94410362155007,
+STORE, 140351953997824, 140351954169855,
+ERASE, 140351953997824, 140351953997824,
+STORE, 140351953997824, 140351954001919,
+STORE, 140351954001920, 140351954169855,
+ERASE, 140351954001920, 140351954001920,
+STORE, 140351954001920, 140351954124799,
+STORE, 140351954124800, 140351954157567,
+STORE, 140351954157568, 140351954165759,
+STORE, 140351954165760, 140351954169855,
+STORE, 140728272429056, 140728272433151,
+STORE, 140728272416768, 140728272429055,
+STORE, 47280840998912, 47280841007103,
+STORE, 47280841007104, 47280841015295,
+STORE, 47280841015296, 47280841179135,
+ERASE, 47280841015296, 47280841015296,
+STORE, 47280841015296, 47280841027583,
+STORE, 47280841027584, 47280841179135,
+STORE, 47280841125888, 47280841179135,
+STORE, 47280841027584, 47280841125887,
+ERASE, 47280841027584, 47280841027584,
+STORE, 47280841027584, 47280841125887,
+STORE, 47280841170944, 47280841179135,
+STORE, 47280841125888, 47280841170943,
+ERASE, 47280841125888, 47280841125888,
+STORE, 47280841125888, 47280841179135,
+ERASE, 47280841125888, 47280841125888,
+STORE, 47280841125888, 47280841170943,
+STORE, 47280841170944, 47280841179135,
+ERASE, 47280841170944, 47280841170944,
+STORE, 47280841170944, 47280841179135,
+STORE, 47280841179136, 47280844230655,
+STORE, 47280841723904, 47280844230655,
+STORE, 47280841179136, 47280841723903,
+ERASE, 47280841723904, 47280841723904,
+STORE, 47280841723904, 47280844009471,
+STORE, 47280844009472, 47280844230655,
+STORE, 47280843419648, 47280844009471,
+STORE, 47280841723904, 47280843419647,
+ERASE, 47280841723904, 47280841723904,
+STORE, 47280841723904, 47280843419647,
+STORE, 47280844005376, 47280844009471,
+STORE, 47280843419648, 47280844005375,
+ERASE, 47280843419648, 47280843419648,
+STORE, 47280843419648, 47280844005375,
+STORE, 47280844214272, 47280844230655,
+STORE, 47280844009472, 47280844214271,
+ERASE, 47280844009472, 47280844009472,
+STORE, 47280844009472, 47280844214271,
+ERASE, 47280844214272, 47280844214272,
+STORE, 47280844214272, 47280844230655,
+STORE, 47280844230656, 47280846069759,
+STORE, 47280844369920, 47280846069759,
+STORE, 47280844230656, 47280844369919,
+ERASE, 47280844369920, 47280844369920,
+STORE, 47280844369920, 47280846028799,
+STORE, 47280846028800, 47280846069759,
+STORE, 47280845713408, 47280846028799,
+STORE, 47280844369920, 47280845713407,
+ERASE, 47280844369920, 47280844369920,
+STORE, 47280844369920, 47280845713407,
+STORE, 47280846024704, 47280846028799,
+STORE, 47280845713408, 47280846024703,
+ERASE, 47280845713408, 47280845713408,
+STORE, 47280845713408, 47280846024703,
+STORE, 47280846053376, 47280846069759,
+STORE, 47280846028800, 47280846053375,
+ERASE, 47280846028800, 47280846028800,
+STORE, 47280846028800, 47280846053375,
+ERASE, 47280846053376, 47280846053376,
+STORE, 47280846053376, 47280846069759,
+STORE, 47280846069760, 47280846204927,
+ERASE, 47280846069760, 47280846069760,
+STORE, 47280846069760, 47280846094335,
+STORE, 47280846094336, 47280846204927,
+STORE, 47280846155776, 47280846204927,
+STORE, 47280846094336, 47280846155775,
+ERASE, 47280846094336, 47280846094336,
+STORE, 47280846094336, 47280846155775,
+STORE, 47280846180352, 47280846204927,
+STORE, 47280846155776, 47280846180351,
+ERASE, 47280846155776, 47280846155776,
+STORE, 47280846155776, 47280846204927,
+ERASE, 47280846155776, 47280846155776,
+STORE, 47280846155776, 47280846180351,
+STORE, 47280846180352, 47280846204927,
+STORE, 47280846188544, 47280846204927,
+STORE, 47280846180352, 47280846188543,
+ERASE, 47280846180352, 47280846180352,
+STORE, 47280846180352, 47280846188543,
+ERASE, 47280846188544, 47280846188544,
+STORE, 47280846188544, 47280846204927,
+STORE, 47280846204928, 47280846225407,
+ERASE, 47280846204928, 47280846204928,
+STORE, 47280846204928, 47280846209023,
+STORE, 47280846209024, 47280846225407,
+STORE, 47280846213120, 47280846225407,
+STORE, 47280846209024, 47280846213119,
+ERASE, 47280846209024, 47280846209024,
+STORE, 47280846209024, 47280846213119,
+STORE, 47280846217216, 47280846225407,
+STORE, 47280846213120, 47280846217215,
+ERASE, 47280846213120, 47280846213120,
+STORE, 47280846213120, 47280846225407,
+ERASE, 47280846213120, 47280846213120,
+STORE, 47280846213120, 47280846217215,
+STORE, 47280846217216, 47280846225407,
+ERASE, 47280846217216, 47280846217216,
+STORE, 47280846217216, 47280846225407,
+STORE, 47280846225408, 47280846233599,
+ERASE, 47280846028800, 47280846028800,
+STORE, 47280846028800, 47280846045183,
+STORE, 47280846045184, 47280846053375,
+ERASE, 47280846217216, 47280846217216,
+STORE, 47280846217216, 47280846221311,
+STORE, 47280846221312, 47280846225407,
+ERASE, 47280846180352, 47280846180352,
+STORE, 47280846180352, 47280846184447,
+STORE, 47280846184448, 47280846188543,
+ERASE, 47280844009472, 47280844009472,
+STORE, 47280844009472, 47280844206079,
+STORE, 47280844206080, 47280844214271,
+ERASE, 47280841170944, 47280841170944,
+STORE, 47280841170944, 47280841175039,
+STORE, 47280841175040, 47280841179135,
+ERASE, 94410362142720, 94410362142720,
+STORE, 94410362142720, 94410362150911,
+STORE, 94410362150912, 94410362155007,
+ERASE, 140351954157568, 140351954157568,
+STORE, 140351954157568, 140351954161663,
+STORE, 140351954161664, 140351954165759,
+ERASE, 47280840998912, 47280840998912,
+STORE, 94410379456512, 94410379591679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732946362368, 140737488351231,
+ERASE, 140732946362368, 140732946362368,
+STORE, 140732946362368, 140732946366463,
+STORE, 94352937934848, 94352938106879,
+ERASE, 94352937934848, 94352937934848,
+STORE, 94352937934848, 94352937951231,
+STORE, 94352937951232, 94352938106879,
+ERASE, 94352937951232, 94352937951232,
+STORE, 94352937951232, 94352938053631,
+STORE, 94352938053632, 94352938094591,
+STORE, 94352938094592, 94352938106879,
+STORE, 140595518742528, 140595518914559,
+ERASE, 140595518742528, 140595518742528,
+STORE, 140595518742528, 140595518746623,
+STORE, 140595518746624, 140595518914559,
+ERASE, 140595518746624, 140595518746624,
+STORE, 140595518746624, 140595518869503,
+STORE, 140595518869504, 140595518902271,
+STORE, 140595518902272, 140595518910463,
+STORE, 140595518910464, 140595518914559,
+STORE, 140732947468288, 140732947472383,
+STORE, 140732947456000, 140732947468287,
+STORE, 47037276254208, 47037276262399,
+STORE, 47037276262400, 47037276270591,
+STORE, 47037276270592, 47037276434431,
+ERASE, 47037276270592, 47037276270592,
+STORE, 47037276270592, 47037276282879,
+STORE, 47037276282880, 47037276434431,
+STORE, 47037276381184, 47037276434431,
+STORE, 47037276282880, 47037276381183,
+ERASE, 47037276282880, 47037276282880,
+STORE, 47037276282880, 47037276381183,
+STORE, 47037276426240, 47037276434431,
+STORE, 47037276381184, 47037276426239,
+ERASE, 47037276381184, 47037276381184,
+STORE, 47037276381184, 47037276434431,
+ERASE, 47037276381184, 47037276381184,
+STORE, 47037276381184, 47037276426239,
+STORE, 47037276426240, 47037276434431,
+ERASE, 47037276426240, 47037276426240,
+STORE, 47037276426240, 47037276434431,
+STORE, 47037276434432, 47037279485951,
+STORE, 47037276979200, 47037279485951,
+STORE, 47037276434432, 47037276979199,
+ERASE, 47037276979200, 47037276979200,
+STORE, 47037276979200, 47037279264767,
+STORE, 47037279264768, 47037279485951,
+STORE, 47037278674944, 47037279264767,
+STORE, 47037276979200, 47037278674943,
+ERASE, 47037276979200, 47037276979200,
+STORE, 47037276979200, 47037278674943,
+STORE, 47037279260672, 47037279264767,
+STORE, 47037278674944, 47037279260671,
+ERASE, 47037278674944, 47037278674944,
+STORE, 47037278674944, 47037279260671,
+STORE, 47037279469568, 47037279485951,
+STORE, 47037279264768, 47037279469567,
+ERASE, 47037279264768, 47037279264768,
+STORE, 47037279264768, 47037279469567,
+ERASE, 47037279469568, 47037279469568,
+STORE, 47037279469568, 47037279485951,
+STORE, 47037279485952, 47037281325055,
+STORE, 47037279625216, 47037281325055,
+STORE, 47037279485952, 47037279625215,
+ERASE, 47037279625216, 47037279625216,
+STORE, 47037279625216, 47037281284095,
+STORE, 47037281284096, 47037281325055,
+STORE, 47037280968704, 47037281284095,
+STORE, 47037279625216, 47037280968703,
+ERASE, 47037279625216, 47037279625216,
+STORE, 47037279625216, 47037280968703,
+STORE, 47037281280000, 47037281284095,
+STORE, 47037280968704, 47037281279999,
+ERASE, 47037280968704, 47037280968704,
+STORE, 47037280968704, 47037281279999,
+STORE, 47037281308672, 47037281325055,
+STORE, 47037281284096, 47037281308671,
+ERASE, 47037281284096, 47037281284096,
+STORE, 47037281284096, 47037281308671,
+ERASE, 47037281308672, 47037281308672,
+STORE, 47037281308672, 47037281325055,
+STORE, 47037281325056, 47037281460223,
+ERASE, 47037281325056, 47037281325056,
+STORE, 47037281325056, 47037281349631,
+STORE, 47037281349632, 47037281460223,
+STORE, 47037281411072, 47037281460223,
+STORE, 47037281349632, 47037281411071,
+ERASE, 47037281349632, 47037281349632,
+STORE, 47037281349632, 47037281411071,
+STORE, 47037281435648, 47037281460223,
+STORE, 47037281411072, 47037281435647,
+ERASE, 47037281411072, 47037281411072,
+STORE, 47037281411072, 47037281460223,
+ERASE, 47037281411072, 47037281411072,
+STORE, 47037281411072, 47037281435647,
+STORE, 47037281435648, 47037281460223,
+STORE, 47037281443840, 47037281460223,
+STORE, 47037281435648, 47037281443839,
+ERASE, 47037281435648, 47037281435648,
+STORE, 47037281435648, 47037281443839,
+ERASE, 47037281443840, 47037281443840,
+STORE, 47037281443840, 47037281460223,
+STORE, 47037281460224, 47037281480703,
+ERASE, 47037281460224, 47037281460224,
+STORE, 47037281460224, 47037281464319,
+STORE, 47037281464320, 47037281480703,
+STORE, 47037281468416, 47037281480703,
+STORE, 47037281464320, 47037281468415,
+ERASE, 47037281464320, 47037281464320,
+STORE, 47037281464320, 47037281468415,
+STORE, 47037281472512, 47037281480703,
+STORE, 47037281468416, 47037281472511,
+ERASE, 47037281468416, 47037281468416,
+STORE, 47037281468416, 47037281480703,
+ERASE, 47037281468416, 47037281468416,
+STORE, 47037281468416, 47037281472511,
+STORE, 47037281472512, 47037281480703,
+ERASE, 47037281472512, 47037281472512,
+STORE, 47037281472512, 47037281480703,
+STORE, 47037281480704, 47037281488895,
+ERASE, 47037281284096, 47037281284096,
+STORE, 47037281284096, 47037281300479,
+STORE, 47037281300480, 47037281308671,
+ERASE, 47037281472512, 47037281472512,
+STORE, 47037281472512, 47037281476607,
+STORE, 47037281476608, 47037281480703,
+ERASE, 47037281435648, 47037281435648,
+STORE, 47037281435648, 47037281439743,
+STORE, 47037281439744, 47037281443839,
+ERASE, 47037279264768, 47037279264768,
+STORE, 47037279264768, 47037279461375,
+STORE, 47037279461376, 47037279469567,
+ERASE, 47037276426240, 47037276426240,
+STORE, 47037276426240, 47037276430335,
+STORE, 47037276430336, 47037276434431,
+ERASE, 94352938094592, 94352938094592,
+STORE, 94352938094592, 94352938102783,
+STORE, 94352938102784, 94352938106879,
+ERASE, 140595518902272, 140595518902272,
+STORE, 140595518902272, 140595518906367,
+STORE, 140595518906368, 140595518910463,
+ERASE, 47037276254208, 47037276254208,
+STORE, 94352938438656, 94352938573823,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733506027520, 140737488351231,
+ERASE, 140733506027520, 140733506027520,
+STORE, 140733506027520, 140733506031615,
+STORE, 94150123073536, 94150123245567,
+ERASE, 94150123073536, 94150123073536,
+STORE, 94150123073536, 94150123089919,
+STORE, 94150123089920, 94150123245567,
+ERASE, 94150123089920, 94150123089920,
+STORE, 94150123089920, 94150123192319,
+STORE, 94150123192320, 94150123233279,
+STORE, 94150123233280, 94150123245567,
+STORE, 140081290375168, 140081290547199,
+ERASE, 140081290375168, 140081290375168,
+STORE, 140081290375168, 140081290379263,
+STORE, 140081290379264, 140081290547199,
+ERASE, 140081290379264, 140081290379264,
+STORE, 140081290379264, 140081290502143,
+STORE, 140081290502144, 140081290534911,
+STORE, 140081290534912, 140081290543103,
+STORE, 140081290543104, 140081290547199,
+STORE, 140733506707456, 140733506711551,
+STORE, 140733506695168, 140733506707455,
+STORE, 47551504621568, 47551504629759,
+STORE, 47551504629760, 47551504637951,
+STORE, 47551504637952, 47551504801791,
+ERASE, 47551504637952, 47551504637952,
+STORE, 47551504637952, 47551504650239,
+STORE, 47551504650240, 47551504801791,
+STORE, 47551504748544, 47551504801791,
+STORE, 47551504650240, 47551504748543,
+ERASE, 47551504650240, 47551504650240,
+STORE, 47551504650240, 47551504748543,
+STORE, 47551504793600, 47551504801791,
+STORE, 47551504748544, 47551504793599,
+ERASE, 47551504748544, 47551504748544,
+STORE, 47551504748544, 47551504801791,
+ERASE, 47551504748544, 47551504748544,
+STORE, 47551504748544, 47551504793599,
+STORE, 47551504793600, 47551504801791,
+ERASE, 47551504793600, 47551504793600,
+STORE, 47551504793600, 47551504801791,
+STORE, 47551504801792, 47551507853311,
+STORE, 47551505346560, 47551507853311,
+STORE, 47551504801792, 47551505346559,
+ERASE, 47551505346560, 47551505346560,
+STORE, 47551505346560, 47551507632127,
+STORE, 47551507632128, 47551507853311,
+STORE, 47551507042304, 47551507632127,
+STORE, 47551505346560, 47551507042303,
+ERASE, 47551505346560, 47551505346560,
+STORE, 47551505346560, 47551507042303,
+STORE, 47551507628032, 47551507632127,
+STORE, 47551507042304, 47551507628031,
+ERASE, 47551507042304, 47551507042304,
+STORE, 47551507042304, 47551507628031,
+STORE, 47551507836928, 47551507853311,
+STORE, 47551507632128, 47551507836927,
+ERASE, 47551507632128, 47551507632128,
+STORE, 47551507632128, 47551507836927,
+ERASE, 47551507836928, 47551507836928,
+STORE, 47551507836928, 47551507853311,
+STORE, 47551507853312, 47551509692415,
+STORE, 47551507992576, 47551509692415,
+STORE, 47551507853312, 47551507992575,
+ERASE, 47551507992576, 47551507992576,
+STORE, 47551507992576, 47551509651455,
+STORE, 47551509651456, 47551509692415,
+STORE, 47551509336064, 47551509651455,
+STORE, 47551507992576, 47551509336063,
+ERASE, 47551507992576, 47551507992576,
+STORE, 47551507992576, 47551509336063,
+STORE, 47551509647360, 47551509651455,
+STORE, 47551509336064, 47551509647359,
+ERASE, 47551509336064, 47551509336064,
+STORE, 47551509336064, 47551509647359,
+STORE, 47551509676032, 47551509692415,
+STORE, 47551509651456, 47551509676031,
+ERASE, 47551509651456, 47551509651456,
+STORE, 47551509651456, 47551509676031,
+ERASE, 47551509676032, 47551509676032,
+STORE, 47551509676032, 47551509692415,
+STORE, 47551509692416, 47551509827583,
+ERASE, 47551509692416, 47551509692416,
+STORE, 47551509692416, 47551509716991,
+STORE, 47551509716992, 47551509827583,
+STORE, 47551509778432, 47551509827583,
+STORE, 47551509716992, 47551509778431,
+ERASE, 47551509716992, 47551509716992,
+STORE, 47551509716992, 47551509778431,
+STORE, 47551509803008, 47551509827583,
+STORE, 47551509778432, 47551509803007,
+ERASE, 47551509778432, 47551509778432,
+STORE, 47551509778432, 47551509827583,
+ERASE, 47551509778432, 47551509778432,
+STORE, 47551509778432, 47551509803007,
+STORE, 47551509803008, 47551509827583,
+STORE, 47551509811200, 47551509827583,
+STORE, 47551509803008, 47551509811199,
+ERASE, 47551509803008, 47551509803008,
+STORE, 47551509803008, 47551509811199,
+ERASE, 47551509811200, 47551509811200,
+STORE, 47551509811200, 47551509827583,
+STORE, 47551509827584, 47551509848063,
+ERASE, 47551509827584, 47551509827584,
+STORE, 47551509827584, 47551509831679,
+STORE, 47551509831680, 47551509848063,
+STORE, 47551509835776, 47551509848063,
+STORE, 47551509831680, 47551509835775,
+ERASE, 47551509831680, 47551509831680,
+STORE, 47551509831680, 47551509835775,
+STORE, 47551509839872, 47551509848063,
+STORE, 47551509835776, 47551509839871,
+ERASE, 47551509835776, 47551509835776,
+STORE, 47551509835776, 47551509848063,
+ERASE, 47551509835776, 47551509835776,
+STORE, 47551509835776, 47551509839871,
+STORE, 47551509839872, 47551509848063,
+ERASE, 47551509839872, 47551509839872,
+STORE, 47551509839872, 47551509848063,
+STORE, 47551509848064, 47551509856255,
+ERASE, 47551509651456, 47551509651456,
+STORE, 47551509651456, 47551509667839,
+STORE, 47551509667840, 47551509676031,
+ERASE, 47551509839872, 47551509839872,
+STORE, 47551509839872, 47551509843967,
+STORE, 47551509843968, 47551509848063,
+ERASE, 47551509803008, 47551509803008,
+STORE, 47551509803008, 47551509807103,
+STORE, 47551509807104, 47551509811199,
+ERASE, 47551507632128, 47551507632128,
+STORE, 47551507632128, 47551507828735,
+STORE, 47551507828736, 47551507836927,
+ERASE, 47551504793600, 47551504793600,
+STORE, 47551504793600, 47551504797695,
+STORE, 47551504797696, 47551504801791,
+ERASE, 94150123233280, 94150123233280,
+STORE, 94150123233280, 94150123241471,
+STORE, 94150123241472, 94150123245567,
+ERASE, 140081290534912, 140081290534912,
+STORE, 140081290534912, 140081290539007,
+STORE, 140081290539008, 140081290543103,
+ERASE, 47551504621568, 47551504621568,
+STORE, 94150148112384, 94150148247551,
+STORE, 140737488347136, 140737488351231,
+STORE, 140734389334016, 140737488351231,
+ERASE, 140734389334016, 140734389334016,
+STORE, 140734389334016, 140734389338111,
+STORE, 94844636606464, 94844636778495,
+ERASE, 94844636606464, 94844636606464,
+STORE, 94844636606464, 94844636622847,
+STORE, 94844636622848, 94844636778495,
+ERASE, 94844636622848, 94844636622848,
+STORE, 94844636622848, 94844636725247,
+STORE, 94844636725248, 94844636766207,
+STORE, 94844636766208, 94844636778495,
+STORE, 139922765217792, 139922765389823,
+ERASE, 139922765217792, 139922765217792,
+STORE, 139922765217792, 139922765221887,
+STORE, 139922765221888, 139922765389823,
+ERASE, 139922765221888, 139922765221888,
+STORE, 139922765221888, 139922765344767,
+STORE, 139922765344768, 139922765377535,
+STORE, 139922765377536, 139922765385727,
+STORE, 139922765385728, 139922765389823,
+STORE, 140734389678080, 140734389682175,
+STORE, 140734389665792, 140734389678079,
+STORE, 47710029778944, 47710029787135,
+STORE, 47710029787136, 47710029795327,
+STORE, 47710029795328, 47710029959167,
+ERASE, 47710029795328, 47710029795328,
+STORE, 47710029795328, 47710029807615,
+STORE, 47710029807616, 47710029959167,
+STORE, 47710029905920, 47710029959167,
+STORE, 47710029807616, 47710029905919,
+ERASE, 47710029807616, 47710029807616,
+STORE, 47710029807616, 47710029905919,
+STORE, 47710029950976, 47710029959167,
+STORE, 47710029905920, 47710029950975,
+ERASE, 47710029905920, 47710029905920,
+STORE, 47710029905920, 47710029959167,
+ERASE, 47710029905920, 47710029905920,
+STORE, 47710029905920, 47710029950975,
+STORE, 47710029950976, 47710029959167,
+ERASE, 47710029950976, 47710029950976,
+STORE, 47710029950976, 47710029959167,
+STORE, 47710029959168, 47710033010687,
+STORE, 47710030503936, 47710033010687,
+STORE, 47710029959168, 47710030503935,
+ERASE, 47710030503936, 47710030503936,
+STORE, 47710030503936, 47710032789503,
+STORE, 47710032789504, 47710033010687,
+STORE, 47710032199680, 47710032789503,
+STORE, 47710030503936, 47710032199679,
+ERASE, 47710030503936, 47710030503936,
+STORE, 47710030503936, 47710032199679,
+STORE, 47710032785408, 47710032789503,
+STORE, 47710032199680, 47710032785407,
+ERASE, 47710032199680, 47710032199680,
+STORE, 47710032199680, 47710032785407,
+STORE, 47710032994304, 47710033010687,
+STORE, 47710032789504, 47710032994303,
+ERASE, 47710032789504, 47710032789504,
+STORE, 47710032789504, 47710032994303,
+ERASE, 47710032994304, 47710032994304,
+STORE, 47710032994304, 47710033010687,
+STORE, 47710033010688, 47710034849791,
+STORE, 47710033149952, 47710034849791,
+STORE, 47710033010688, 47710033149951,
+ERASE, 47710033149952, 47710033149952,
+STORE, 47710033149952, 47710034808831,
+STORE, 47710034808832, 47710034849791,
+STORE, 47710034493440, 47710034808831,
+STORE, 47710033149952, 47710034493439,
+ERASE, 47710033149952, 47710033149952,
+STORE, 47710033149952, 47710034493439,
+STORE, 47710034804736, 47710034808831,
+STORE, 47710034493440, 47710034804735,
+ERASE, 47710034493440, 47710034493440,
+STORE, 47710034493440, 47710034804735,
+STORE, 47710034833408, 47710034849791,
+STORE, 47710034808832, 47710034833407,
+ERASE, 47710034808832, 47710034808832,
+STORE, 47710034808832, 47710034833407,
+ERASE, 47710034833408, 47710034833408,
+STORE, 47710034833408, 47710034849791,
+STORE, 47710034849792, 47710034984959,
+ERASE, 47710034849792, 47710034849792,
+STORE, 47710034849792, 47710034874367,
+STORE, 47710034874368, 47710034984959,
+STORE, 47710034935808, 47710034984959,
+STORE, 47710034874368, 47710034935807,
+ERASE, 47710034874368, 47710034874368,
+STORE, 47710034874368, 47710034935807,
+STORE, 47710034960384, 47710034984959,
+STORE, 47710034935808, 47710034960383,
+ERASE, 47710034935808, 47710034935808,
+STORE, 47710034935808, 47710034984959,
+ERASE, 47710034935808, 47710034935808,
+STORE, 47710034935808, 47710034960383,
+STORE, 47710034960384, 47710034984959,
+STORE, 47710034968576, 47710034984959,
+STORE, 47710034960384, 47710034968575,
+ERASE, 47710034960384, 47710034960384,
+STORE, 47710034960384, 47710034968575,
+ERASE, 47710034968576, 47710034968576,
+STORE, 47710034968576, 47710034984959,
+STORE, 47710034984960, 47710035005439,
+ERASE, 47710034984960, 47710034984960,
+STORE, 47710034984960, 47710034989055,
+STORE, 47710034989056, 47710035005439,
+STORE, 47710034993152, 47710035005439,
+STORE, 47710034989056, 47710034993151,
+ERASE, 47710034989056, 47710034989056,
+STORE, 47710034989056, 47710034993151,
+STORE, 47710034997248, 47710035005439,
+STORE, 47710034993152, 47710034997247,
+ERASE, 47710034993152, 47710034993152,
+STORE, 47710034993152, 47710035005439,
+ERASE, 47710034993152, 47710034993152,
+STORE, 47710034993152, 47710034997247,
+STORE, 47710034997248, 47710035005439,
+ERASE, 47710034997248, 47710034997248,
+STORE, 47710034997248, 47710035005439,
+STORE, 47710035005440, 47710035013631,
+ERASE, 47710034808832, 47710034808832,
+STORE, 47710034808832, 47710034825215,
+STORE, 47710034825216, 47710034833407,
+ERASE, 47710034997248, 47710034997248,
+STORE, 47710034997248, 47710035001343,
+STORE, 47710035001344, 47710035005439,
+ERASE, 47710034960384, 47710034960384,
+STORE, 47710034960384, 47710034964479,
+STORE, 47710034964480, 47710034968575,
+ERASE, 47710032789504, 47710032789504,
+STORE, 47710032789504, 47710032986111,
+STORE, 47710032986112, 47710032994303,
+ERASE, 47710029950976, 47710029950976,
+STORE, 47710029950976, 47710029955071,
+STORE, 47710029955072, 47710029959167,
+ERASE, 94844636766208, 94844636766208,
+STORE, 94844636766208, 94844636774399,
+STORE, 94844636774400, 94844636778495,
+ERASE, 139922765377536, 139922765377536,
+STORE, 139922765377536, 139922765381631,
+STORE, 139922765381632, 139922765385727,
+ERASE, 47710029778944, 47710029778944,
+STORE, 94844641775616, 94844641910783,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732213886976, 140737488351231,
+ERASE, 140732213886976, 140732213886976,
+STORE, 140732213886976, 140732213891071,
+STORE, 94240508887040, 94240509059071,
+ERASE, 94240508887040, 94240508887040,
+STORE, 94240508887040, 94240508903423,
+STORE, 94240508903424, 94240509059071,
+ERASE, 94240508903424, 94240508903424,
+STORE, 94240508903424, 94240509005823,
+STORE, 94240509005824, 94240509046783,
+STORE, 94240509046784, 94240509059071,
+STORE, 140275106516992, 140275106689023,
+ERASE, 140275106516992, 140275106516992,
+STORE, 140275106516992, 140275106521087,
+STORE, 140275106521088, 140275106689023,
+ERASE, 140275106521088, 140275106521088,
+STORE, 140275106521088, 140275106643967,
+STORE, 140275106643968, 140275106676735,
+STORE, 140275106676736, 140275106684927,
+STORE, 140275106684928, 140275106689023,
+STORE, 140732213977088, 140732213981183,
+STORE, 140732213964800, 140732213977087,
+STORE, 47357688479744, 47357688487935,
+STORE, 47357688487936, 47357688496127,
+STORE, 47357688496128, 47357688659967,
+ERASE, 47357688496128, 47357688496128,
+STORE, 47357688496128, 47357688508415,
+STORE, 47357688508416, 47357688659967,
+STORE, 47357688606720, 47357688659967,
+STORE, 47357688508416, 47357688606719,
+ERASE, 47357688508416, 47357688508416,
+STORE, 47357688508416, 47357688606719,
+STORE, 47357688651776, 47357688659967,
+STORE, 47357688606720, 47357688651775,
+ERASE, 47357688606720, 47357688606720,
+STORE, 47357688606720, 47357688659967,
+ERASE, 47357688606720, 47357688606720,
+STORE, 47357688606720, 47357688651775,
+STORE, 47357688651776, 47357688659967,
+ERASE, 47357688651776, 47357688651776,
+STORE, 47357688651776, 47357688659967,
+STORE, 47357688659968, 47357691711487,
+STORE, 47357689204736, 47357691711487,
+STORE, 47357688659968, 47357689204735,
+ERASE, 47357689204736, 47357689204736,
+STORE, 47357689204736, 47357691490303,
+STORE, 47357691490304, 47357691711487,
+STORE, 47357690900480, 47357691490303,
+STORE, 47357689204736, 47357690900479,
+ERASE, 47357689204736, 47357689204736,
+STORE, 47357689204736, 47357690900479,
+STORE, 47357691486208, 47357691490303,
+STORE, 47357690900480, 47357691486207,
+ERASE, 47357690900480, 47357690900480,
+STORE, 47357690900480, 47357691486207,
+STORE, 47357691695104, 47357691711487,
+STORE, 47357691490304, 47357691695103,
+ERASE, 47357691490304, 47357691490304,
+STORE, 47357691490304, 47357691695103,
+ERASE, 47357691695104, 47357691695104,
+STORE, 47357691695104, 47357691711487,
+STORE, 47357691711488, 47357693550591,
+STORE, 47357691850752, 47357693550591,
+STORE, 47357691711488, 47357691850751,
+ERASE, 47357691850752, 47357691850752,
+STORE, 47357691850752, 47357693509631,
+STORE, 47357693509632, 47357693550591,
+STORE, 47357693194240, 47357693509631,
+STORE, 47357691850752, 47357693194239,
+ERASE, 47357691850752, 47357691850752,
+STORE, 47357691850752, 47357693194239,
+STORE, 47357693505536, 47357693509631,
+STORE, 47357693194240, 47357693505535,
+ERASE, 47357693194240, 47357693194240,
+STORE, 47357693194240, 47357693505535,
+STORE, 47357693534208, 47357693550591,
+STORE, 47357693509632, 47357693534207,
+ERASE, 47357693509632, 47357693509632,
+STORE, 47357693509632, 47357693534207,
+ERASE, 47357693534208, 47357693534208,
+STORE, 47357693534208, 47357693550591,
+STORE, 47357693550592, 47357693685759,
+ERASE, 47357693550592, 47357693550592,
+STORE, 47357693550592, 47357693575167,
+STORE, 47357693575168, 47357693685759,
+STORE, 47357693636608, 47357693685759,
+STORE, 47357693575168, 47357693636607,
+ERASE, 47357693575168, 47357693575168,
+STORE, 47357693575168, 47357693636607,
+STORE, 47357693661184, 47357693685759,
+STORE, 47357693636608, 47357693661183,
+ERASE, 47357693636608, 47357693636608,
+STORE, 47357693636608, 47357693685759,
+ERASE, 47357693636608, 47357693636608,
+STORE, 47357693636608, 47357693661183,
+STORE, 47357693661184, 47357693685759,
+STORE, 47357693669376, 47357693685759,
+STORE, 47357693661184, 47357693669375,
+ERASE, 47357693661184, 47357693661184,
+STORE, 47357693661184, 47357693669375,
+ERASE, 47357693669376, 47357693669376,
+STORE, 47357693669376, 47357693685759,
+STORE, 47357693685760, 47357693706239,
+ERASE, 47357693685760, 47357693685760,
+STORE, 47357693685760, 47357693689855,
+STORE, 47357693689856, 47357693706239,
+STORE, 47357693693952, 47357693706239,
+STORE, 47357693689856, 47357693693951,
+ERASE, 47357693689856, 47357693689856,
+STORE, 47357693689856, 47357693693951,
+STORE, 47357693698048, 47357693706239,
+STORE, 47357693693952, 47357693698047,
+ERASE, 47357693693952, 47357693693952,
+STORE, 47357693693952, 47357693706239,
+ERASE, 47357693693952, 47357693693952,
+STORE, 47357693693952, 47357693698047,
+STORE, 47357693698048, 47357693706239,
+ERASE, 47357693698048, 47357693698048,
+STORE, 47357693698048, 47357693706239,
+STORE, 47357693706240, 47357693714431,
+ERASE, 47357693509632, 47357693509632,
+STORE, 47357693509632, 47357693526015,
+STORE, 47357693526016, 47357693534207,
+ERASE, 47357693698048, 47357693698048,
+STORE, 47357693698048, 47357693702143,
+STORE, 47357693702144, 47357693706239,
+ERASE, 47357693661184, 47357693661184,
+STORE, 47357693661184, 47357693665279,
+STORE, 47357693665280, 47357693669375,
+ERASE, 47357691490304, 47357691490304,
+STORE, 47357691490304, 47357691686911,
+STORE, 47357691686912, 47357691695103,
+ERASE, 47357688651776, 47357688651776,
+STORE, 47357688651776, 47357688655871,
+STORE, 47357688655872, 47357688659967,
+ERASE, 94240509046784, 94240509046784,
+STORE, 94240509046784, 94240509054975,
+STORE, 94240509054976, 94240509059071,
+ERASE, 140275106676736, 140275106676736,
+STORE, 140275106676736, 140275106680831,
+STORE, 140275106680832, 140275106684927,
+ERASE, 47357688479744, 47357688479744,
+STORE, 94240518361088, 94240518496255,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732688277504, 140737488351231,
+ERASE, 140732688277504, 140732688277504,
+STORE, 140732688277504, 140732688281599,
+STORE, 94629171351552, 94629172064255,
+ERASE, 94629171351552, 94629171351552,
+STORE, 94629171351552, 94629171400703,
+STORE, 94629171400704, 94629172064255,
+ERASE, 94629171400704, 94629171400704,
+STORE, 94629171400704, 94629171945471,
+STORE, 94629171945472, 94629172043775,
+STORE, 94629172043776, 94629172064255,
+STORE, 139770707644416, 139770707816447,
+ERASE, 139770707644416, 139770707644416,
+STORE, 139770707644416, 139770707648511,
+STORE, 139770707648512, 139770707816447,
+ERASE, 139770707648512, 139770707648512,
+STORE, 139770707648512, 139770707771391,
+STORE, 139770707771392, 139770707804159,
+STORE, 139770707804160, 139770707812351,
+STORE, 139770707812352, 139770707816447,
+STORE, 140732689121280, 140732689125375,
+STORE, 140732689108992, 140732689121279,
+STORE, 47862087352320, 47862087360511,
+STORE, 47862087360512, 47862087368703,
+STORE, 47862087368704, 47862087475199,
+STORE, 47862087385088, 47862087475199,
+STORE, 47862087368704, 47862087385087,
+ERASE, 47862087385088, 47862087385088,
+STORE, 47862087385088, 47862087458815,
+STORE, 47862087458816, 47862087475199,
+STORE, 47862087438336, 47862087458815,
+STORE, 47862087385088, 47862087438335,
+ERASE, 47862087385088, 47862087385088,
+STORE, 47862087385088, 47862087438335,
+STORE, 47862087454720, 47862087458815,
+STORE, 47862087438336, 47862087454719,
+ERASE, 47862087438336, 47862087438336,
+STORE, 47862087438336, 47862087454719,
+STORE, 47862087467008, 47862087475199,
+STORE, 47862087458816, 47862087467007,
+ERASE, 47862087458816, 47862087458816,
+STORE, 47862087458816, 47862087467007,
+ERASE, 47862087467008, 47862087467008,
+STORE, 47862087467008, 47862087475199,
+STORE, 47862087475200, 47862089314303,
+STORE, 47862087614464, 47862089314303,
+STORE, 47862087475200, 47862087614463,
+ERASE, 47862087614464, 47862087614464,
+STORE, 47862087614464, 47862089273343,
+STORE, 47862089273344, 47862089314303,
+STORE, 47862088957952, 47862089273343,
+STORE, 47862087614464, 47862088957951,
+ERASE, 47862087614464, 47862087614464,
+STORE, 47862087614464, 47862088957951,
+STORE, 47862089269248, 47862089273343,
+STORE, 47862088957952, 47862089269247,
+ERASE, 47862088957952, 47862088957952,
+STORE, 47862088957952, 47862089269247,
+STORE, 47862089297920, 47862089314303,
+STORE, 47862089273344, 47862089297919,
+ERASE, 47862089273344, 47862089273344,
+STORE, 47862089273344, 47862089297919,
+ERASE, 47862089297920, 47862089297920,
+STORE, 47862089297920, 47862089314303,
+STORE, 47862089297920, 47862089326591,
+ERASE, 47862089273344, 47862089273344,
+STORE, 47862089273344, 47862089289727,
+STORE, 47862089289728, 47862089297919,
+ERASE, 47862087458816, 47862087458816,
+STORE, 47862087458816, 47862087462911,
+STORE, 47862087462912, 47862087467007,
+ERASE, 94629172043776, 94629172043776,
+STORE, 94629172043776, 94629172060159,
+STORE, 94629172060160, 94629172064255,
+ERASE, 139770707804160, 139770707804160,
+STORE, 139770707804160, 139770707808255,
+STORE, 139770707808256, 139770707812351,
+ERASE, 47862087352320, 47862087352320,
+STORE, 94629197533184, 94629197668351,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727540711424, 140737488351231,
+ERASE, 140727540711424, 140727540711424,
+STORE, 140727540711424, 140727540715519,
+STORE, 94299865313280, 94299866025983,
+ERASE, 94299865313280, 94299865313280,
+STORE, 94299865313280, 94299865362431,
+STORE, 94299865362432, 94299866025983,
+ERASE, 94299865362432, 94299865362432,
+STORE, 94299865362432, 94299865907199,
+STORE, 94299865907200, 94299866005503,
+STORE, 94299866005504, 94299866025983,
+STORE, 140680268763136, 140680268935167,
+ERASE, 140680268763136, 140680268763136,
+STORE, 140680268763136, 140680268767231,
+STORE, 140680268767232, 140680268935167,
+ERASE, 140680268767232, 140680268767232,
+STORE, 140680268767232, 140680268890111,
+STORE, 140680268890112, 140680268922879,
+STORE, 140680268922880, 140680268931071,
+STORE, 140680268931072, 140680268935167,
+STORE, 140727541424128, 140727541428223,
+STORE, 140727541411840, 140727541424127,
+STORE, 46952526233600, 46952526241791,
+STORE, 46952526241792, 46952526249983,
+STORE, 46952526249984, 46952526356479,
+STORE, 46952526266368, 46952526356479,
+STORE, 46952526249984, 46952526266367,
+ERASE, 46952526266368, 46952526266368,
+STORE, 46952526266368, 46952526340095,
+STORE, 46952526340096, 46952526356479,
+STORE, 46952526319616, 46952526340095,
+STORE, 46952526266368, 46952526319615,
+ERASE, 46952526266368, 46952526266368,
+STORE, 46952526266368, 46952526319615,
+STORE, 46952526336000, 46952526340095,
+STORE, 46952526319616, 46952526335999,
+ERASE, 46952526319616, 46952526319616,
+STORE, 46952526319616, 46952526335999,
+STORE, 46952526348288, 46952526356479,
+STORE, 46952526340096, 46952526348287,
+ERASE, 46952526340096, 46952526340096,
+STORE, 46952526340096, 46952526348287,
+ERASE, 46952526348288, 46952526348288,
+STORE, 46952526348288, 46952526356479,
+STORE, 46952526356480, 46952528195583,
+STORE, 46952526495744, 46952528195583,
+STORE, 46952526356480, 46952526495743,
+ERASE, 46952526495744, 46952526495744,
+STORE, 46952526495744, 46952528154623,
+STORE, 46952528154624, 46952528195583,
+STORE, 46952527839232, 46952528154623,
+STORE, 46952526495744, 46952527839231,
+ERASE, 46952526495744, 46952526495744,
+STORE, 46952526495744, 46952527839231,
+STORE, 46952528150528, 46952528154623,
+STORE, 46952527839232, 46952528150527,
+ERASE, 46952527839232, 46952527839232,
+STORE, 46952527839232, 46952528150527,
+STORE, 46952528179200, 46952528195583,
+STORE, 46952528154624, 46952528179199,
+ERASE, 46952528154624, 46952528154624,
+STORE, 46952528154624, 46952528179199,
+ERASE, 46952528179200, 46952528179200,
+STORE, 46952528179200, 46952528195583,
+STORE, 46952528179200, 46952528207871,
+ERASE, 46952528154624, 46952528154624,
+STORE, 46952528154624, 46952528171007,
+STORE, 46952528171008, 46952528179199,
+ERASE, 46952526340096, 46952526340096,
+STORE, 46952526340096, 46952526344191,
+STORE, 46952526344192, 46952526348287,
+ERASE, 94299866005504, 94299866005504,
+STORE, 94299866005504, 94299866021887,
+STORE, 94299866021888, 94299866025983,
+ERASE, 140680268922880, 140680268922880,
+STORE, 140680268922880, 140680268926975,
+STORE, 140680268926976, 140680268931071,
+ERASE, 46952526233600, 46952526233600,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722874793984, 140737488351231,
+ERASE, 140722874793984, 140722874793984,
+STORE, 140722874793984, 140722874798079,
+STORE, 94448916213760, 94448916926463,
+ERASE, 94448916213760, 94448916213760,
+STORE, 94448916213760, 94448916262911,
+STORE, 94448916262912, 94448916926463,
+ERASE, 94448916262912, 94448916262912,
+STORE, 94448916262912, 94448916807679,
+STORE, 94448916807680, 94448916905983,
+STORE, 94448916905984, 94448916926463,
+STORE, 140389117046784, 140389117218815,
+ERASE, 140389117046784, 140389117046784,
+STORE, 140389117046784, 140389117050879,
+STORE, 140389117050880, 140389117218815,
+ERASE, 140389117050880, 140389117050880,
+STORE, 140389117050880, 140389117173759,
+STORE, 140389117173760, 140389117206527,
+STORE, 140389117206528, 140389117214719,
+STORE, 140389117214720, 140389117218815,
+STORE, 140722875297792, 140722875301887,
+STORE, 140722875285504, 140722875297791,
+STORE, 47243677949952, 47243677958143,
+STORE, 47243677958144, 47243677966335,
+STORE, 47243677966336, 47243678072831,
+STORE, 47243677982720, 47243678072831,
+STORE, 47243677966336, 47243677982719,
+ERASE, 47243677982720, 47243677982720,
+STORE, 47243677982720, 47243678056447,
+STORE, 47243678056448, 47243678072831,
+STORE, 47243678035968, 47243678056447,
+STORE, 47243677982720, 47243678035967,
+ERASE, 47243677982720, 47243677982720,
+STORE, 47243677982720, 47243678035967,
+STORE, 47243678052352, 47243678056447,
+STORE, 47243678035968, 47243678052351,
+ERASE, 47243678035968, 47243678035968,
+STORE, 47243678035968, 47243678052351,
+STORE, 47243678064640, 47243678072831,
+STORE, 47243678056448, 47243678064639,
+ERASE, 47243678056448, 47243678056448,
+STORE, 47243678056448, 47243678064639,
+ERASE, 47243678064640, 47243678064640,
+STORE, 47243678064640, 47243678072831,
+STORE, 47243678072832, 47243679911935,
+STORE, 47243678212096, 47243679911935,
+STORE, 47243678072832, 47243678212095,
+ERASE, 47243678212096, 47243678212096,
+STORE, 47243678212096, 47243679870975,
+STORE, 47243679870976, 47243679911935,
+STORE, 47243679555584, 47243679870975,
+STORE, 47243678212096, 47243679555583,
+ERASE, 47243678212096, 47243678212096,
+STORE, 47243678212096, 47243679555583,
+STORE, 47243679866880, 47243679870975,
+STORE, 47243679555584, 47243679866879,
+ERASE, 47243679555584, 47243679555584,
+STORE, 47243679555584, 47243679866879,
+STORE, 47243679895552, 47243679911935,
+STORE, 47243679870976, 47243679895551,
+ERASE, 47243679870976, 47243679870976,
+STORE, 47243679870976, 47243679895551,
+ERASE, 47243679895552, 47243679895552,
+STORE, 47243679895552, 47243679911935,
+STORE, 47243679895552, 47243679924223,
+ERASE, 47243679870976, 47243679870976,
+STORE, 47243679870976, 47243679887359,
+STORE, 47243679887360, 47243679895551,
+ERASE, 47243678056448, 47243678056448,
+STORE, 47243678056448, 47243678060543,
+STORE, 47243678060544, 47243678064639,
+ERASE, 94448916905984, 94448916905984,
+STORE, 94448916905984, 94448916922367,
+STORE, 94448916922368, 94448916926463,
+ERASE, 140389117206528, 140389117206528,
+STORE, 140389117206528, 140389117210623,
+STORE, 140389117210624, 140389117214719,
+ERASE, 47243677949952, 47243677949952,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733068505088, 140737488351231,
+ERASE, 140733068505088, 140733068505088,
+STORE, 140733068505088, 140733068509183,
+STORE, 94207145750528, 94207146463231,
+ERASE, 94207145750528, 94207145750528,
+STORE, 94207145750528, 94207145799679,
+STORE, 94207145799680, 94207146463231,
+ERASE, 94207145799680, 94207145799680,
+STORE, 94207145799680, 94207146344447,
+STORE, 94207146344448, 94207146442751,
+STORE, 94207146442752, 94207146463231,
+STORE, 140684504911872, 140684505083903,
+ERASE, 140684504911872, 140684504911872,
+STORE, 140684504911872, 140684504915967,
+STORE, 140684504915968, 140684505083903,
+ERASE, 140684504915968, 140684504915968,
+STORE, 140684504915968, 140684505038847,
+STORE, 140684505038848, 140684505071615,
+STORE, 140684505071616, 140684505079807,
+STORE, 140684505079808, 140684505083903,
+STORE, 140733068607488, 140733068611583,
+STORE, 140733068595200, 140733068607487,
+STORE, 46948290084864, 46948290093055,
+STORE, 46948290093056, 46948290101247,
+STORE, 46948290101248, 46948290207743,
+STORE, 46948290117632, 46948290207743,
+STORE, 46948290101248, 46948290117631,
+ERASE, 46948290117632, 46948290117632,
+STORE, 46948290117632, 46948290191359,
+STORE, 46948290191360, 46948290207743,
+STORE, 46948290170880, 46948290191359,
+STORE, 46948290117632, 46948290170879,
+ERASE, 46948290117632, 46948290117632,
+STORE, 46948290117632, 46948290170879,
+STORE, 46948290187264, 46948290191359,
+STORE, 46948290170880, 46948290187263,
+ERASE, 46948290170880, 46948290170880,
+STORE, 46948290170880, 46948290187263,
+STORE, 46948290199552, 46948290207743,
+STORE, 46948290191360, 46948290199551,
+ERASE, 46948290191360, 46948290191360,
+STORE, 46948290191360, 46948290199551,
+ERASE, 46948290199552, 46948290199552,
+STORE, 46948290199552, 46948290207743,
+STORE, 46948290207744, 46948292046847,
+STORE, 46948290347008, 46948292046847,
+STORE, 46948290207744, 46948290347007,
+ERASE, 46948290347008, 46948290347008,
+STORE, 46948290347008, 46948292005887,
+STORE, 46948292005888, 46948292046847,
+STORE, 46948291690496, 46948292005887,
+STORE, 46948290347008, 46948291690495,
+ERASE, 46948290347008, 46948290347008,
+STORE, 46948290347008, 46948291690495,
+STORE, 46948292001792, 46948292005887,
+STORE, 46948291690496, 46948292001791,
+ERASE, 46948291690496, 46948291690496,
+STORE, 46948291690496, 46948292001791,
+STORE, 46948292030464, 46948292046847,
+STORE, 46948292005888, 46948292030463,
+ERASE, 46948292005888, 46948292005888,
+STORE, 46948292005888, 46948292030463,
+ERASE, 46948292030464, 46948292030464,
+STORE, 46948292030464, 46948292046847,
+STORE, 46948292030464, 46948292059135,
+ERASE, 46948292005888, 46948292005888,
+STORE, 46948292005888, 46948292022271,
+STORE, 46948292022272, 46948292030463,
+ERASE, 46948290191360, 46948290191360,
+STORE, 46948290191360, 46948290195455,
+STORE, 46948290195456, 46948290199551,
+ERASE, 94207146442752, 94207146442752,
+STORE, 94207146442752, 94207146459135,
+STORE, 94207146459136, 94207146463231,
+ERASE, 140684505071616, 140684505071616,
+STORE, 140684505071616, 140684505075711,
+STORE, 140684505075712, 140684505079807,
+ERASE, 46948290084864, 46948290084864,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726367158272, 140737488351231,
+ERASE, 140726367158272, 140726367158272,
+STORE, 140726367158272, 140726367162367,
+STORE, 94436124106752, 94436124819455,
+ERASE, 94436124106752, 94436124106752,
+STORE, 94436124106752, 94436124155903,
+STORE, 94436124155904, 94436124819455,
+ERASE, 94436124155904, 94436124155904,
+STORE, 94436124155904, 94436124700671,
+STORE, 94436124700672, 94436124798975,
+STORE, 94436124798976, 94436124819455,
+STORE, 140049025044480, 140049025216511,
+ERASE, 140049025044480, 140049025044480,
+STORE, 140049025044480, 140049025048575,
+STORE, 140049025048576, 140049025216511,
+ERASE, 140049025048576, 140049025048576,
+STORE, 140049025048576, 140049025171455,
+STORE, 140049025171456, 140049025204223,
+STORE, 140049025204224, 140049025212415,
+STORE, 140049025212416, 140049025216511,
+STORE, 140726367256576, 140726367260671,
+STORE, 140726367244288, 140726367256575,
+STORE, 47583769952256, 47583769960447,
+STORE, 47583769960448, 47583769968639,
+STORE, 47583769968640, 47583770075135,
+STORE, 47583769985024, 47583770075135,
+STORE, 47583769968640, 47583769985023,
+ERASE, 47583769985024, 47583769985024,
+STORE, 47583769985024, 47583770058751,
+STORE, 47583770058752, 47583770075135,
+STORE, 47583770038272, 47583770058751,
+STORE, 47583769985024, 47583770038271,
+ERASE, 47583769985024, 47583769985024,
+STORE, 47583769985024, 47583770038271,
+STORE, 47583770054656, 47583770058751,
+STORE, 47583770038272, 47583770054655,
+ERASE, 47583770038272, 47583770038272,
+STORE, 47583770038272, 47583770054655,
+STORE, 47583770066944, 47583770075135,
+STORE, 47583770058752, 47583770066943,
+ERASE, 47583770058752, 47583770058752,
+STORE, 47583770058752, 47583770066943,
+ERASE, 47583770066944, 47583770066944,
+STORE, 47583770066944, 47583770075135,
+STORE, 47583770075136, 47583771914239,
+STORE, 47583770214400, 47583771914239,
+STORE, 47583770075136, 47583770214399,
+ERASE, 47583770214400, 47583770214400,
+STORE, 47583770214400, 47583771873279,
+STORE, 47583771873280, 47583771914239,
+STORE, 47583771557888, 47583771873279,
+STORE, 47583770214400, 47583771557887,
+ERASE, 47583770214400, 47583770214400,
+STORE, 47583770214400, 47583771557887,
+STORE, 47583771869184, 47583771873279,
+STORE, 47583771557888, 47583771869183,
+ERASE, 47583771557888, 47583771557888,
+STORE, 47583771557888, 47583771869183,
+STORE, 47583771897856, 47583771914239,
+STORE, 47583771873280, 47583771897855,
+ERASE, 47583771873280, 47583771873280,
+STORE, 47583771873280, 47583771897855,
+ERASE, 47583771897856, 47583771897856,
+STORE, 47583771897856, 47583771914239,
+STORE, 47583771897856, 47583771926527,
+ERASE, 47583771873280, 47583771873280,
+STORE, 47583771873280, 47583771889663,
+STORE, 47583771889664, 47583771897855,
+ERASE, 47583770058752, 47583770058752,
+STORE, 47583770058752, 47583770062847,
+STORE, 47583770062848, 47583770066943,
+ERASE, 94436124798976, 94436124798976,
+STORE, 94436124798976, 94436124815359,
+STORE, 94436124815360, 94436124819455,
+ERASE, 140049025204224, 140049025204224,
+STORE, 140049025204224, 140049025208319,
+STORE, 140049025208320, 140049025212415,
+ERASE, 47583769952256, 47583769952256,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727116099584, 140737488351231,
+ERASE, 140727116099584, 140727116099584,
+STORE, 140727116099584, 140727116103679,
+STORE, 94166319734784, 94166320447487,
+ERASE, 94166319734784, 94166319734784,
+STORE, 94166319734784, 94166319783935,
+STORE, 94166319783936, 94166320447487,
+ERASE, 94166319783936, 94166319783936,
+STORE, 94166319783936, 94166320328703,
+STORE, 94166320328704, 94166320427007,
+STORE, 94166320427008, 94166320447487,
+STORE, 139976559542272, 139976559714303,
+ERASE, 139976559542272, 139976559542272,
+STORE, 139976559542272, 139976559546367,
+STORE, 139976559546368, 139976559714303,
+ERASE, 139976559546368, 139976559546368,
+STORE, 139976559546368, 139976559669247,
+STORE, 139976559669248, 139976559702015,
+STORE, 139976559702016, 139976559710207,
+STORE, 139976559710208, 139976559714303,
+STORE, 140727116222464, 140727116226559,
+STORE, 140727116210176, 140727116222463,
+STORE, 47656235454464, 47656235462655,
+STORE, 47656235462656, 47656235470847,
+STORE, 47656235470848, 47656235577343,
+STORE, 47656235487232, 47656235577343,
+STORE, 47656235470848, 47656235487231,
+ERASE, 47656235487232, 47656235487232,
+STORE, 47656235487232, 47656235560959,
+STORE, 47656235560960, 47656235577343,
+STORE, 47656235540480, 47656235560959,
+STORE, 47656235487232, 47656235540479,
+ERASE, 47656235487232, 47656235487232,
+STORE, 47656235487232, 47656235540479,
+STORE, 47656235556864, 47656235560959,
+STORE, 47656235540480, 47656235556863,
+ERASE, 47656235540480, 47656235540480,
+STORE, 47656235540480, 47656235556863,
+STORE, 47656235569152, 47656235577343,
+STORE, 47656235560960, 47656235569151,
+ERASE, 47656235560960, 47656235560960,
+STORE, 47656235560960, 47656235569151,
+ERASE, 47656235569152, 47656235569152,
+STORE, 47656235569152, 47656235577343,
+STORE, 47656235577344, 47656237416447,
+STORE, 47656235716608, 47656237416447,
+STORE, 47656235577344, 47656235716607,
+ERASE, 47656235716608, 47656235716608,
+STORE, 47656235716608, 47656237375487,
+STORE, 47656237375488, 47656237416447,
+STORE, 47656237060096, 47656237375487,
+STORE, 47656235716608, 47656237060095,
+ERASE, 47656235716608, 47656235716608,
+STORE, 47656235716608, 47656237060095,
+STORE, 47656237371392, 47656237375487,
+STORE, 47656237060096, 47656237371391,
+ERASE, 47656237060096, 47656237060096,
+STORE, 47656237060096, 47656237371391,
+STORE, 47656237400064, 47656237416447,
+STORE, 47656237375488, 47656237400063,
+ERASE, 47656237375488, 47656237375488,
+STORE, 47656237375488, 47656237400063,
+ERASE, 47656237400064, 47656237400064,
+STORE, 47656237400064, 47656237416447,
+STORE, 47656237400064, 47656237428735,
+ERASE, 47656237375488, 47656237375488,
+STORE, 47656237375488, 47656237391871,
+STORE, 47656237391872, 47656237400063,
+ERASE, 47656235560960, 47656235560960,
+STORE, 47656235560960, 47656235565055,
+STORE, 47656235565056, 47656235569151,
+ERASE, 94166320427008, 94166320427008,
+STORE, 94166320427008, 94166320443391,
+STORE, 94166320443392, 94166320447487,
+ERASE, 139976559702016, 139976559702016,
+STORE, 139976559702016, 139976559706111,
+STORE, 139976559706112, 139976559710207,
+ERASE, 47656235454464, 47656235454464,
+STORE, 94166332153856, 94166332289023,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726412816384, 140737488351231,
+ERASE, 140726412816384, 140726412816384,
+STORE, 140726412816384, 140726412820479,
+STORE, 94094884507648, 94094885220351,
+ERASE, 94094884507648, 94094884507648,
+STORE, 94094884507648, 94094884556799,
+STORE, 94094884556800, 94094885220351,
+ERASE, 94094884556800, 94094884556800,
+STORE, 94094884556800, 94094885101567,
+STORE, 94094885101568, 94094885199871,
+STORE, 94094885199872, 94094885220351,
+STORE, 139773773938688, 139773774110719,
+ERASE, 139773773938688, 139773773938688,
+STORE, 139773773938688, 139773773942783,
+STORE, 139773773942784, 139773774110719,
+ERASE, 139773773942784, 139773773942784,
+STORE, 139773773942784, 139773774065663,
+STORE, 139773774065664, 139773774098431,
+STORE, 139773774098432, 139773774106623,
+STORE, 139773774106624, 139773774110719,
+STORE, 140726412963840, 140726412967935,
+STORE, 140726412951552, 140726412963839,
+STORE, 47859021058048, 47859021066239,
+STORE, 47859021066240, 47859021074431,
+STORE, 47859021074432, 47859021180927,
+STORE, 47859021090816, 47859021180927,
+STORE, 47859021074432, 47859021090815,
+ERASE, 47859021090816, 47859021090816,
+STORE, 47859021090816, 47859021164543,
+STORE, 47859021164544, 47859021180927,
+STORE, 47859021144064, 47859021164543,
+STORE, 47859021090816, 47859021144063,
+ERASE, 47859021090816, 47859021090816,
+STORE, 47859021090816, 47859021144063,
+STORE, 47859021160448, 47859021164543,
+STORE, 47859021144064, 47859021160447,
+ERASE, 47859021144064, 47859021144064,
+STORE, 47859021144064, 47859021160447,
+STORE, 47859021172736, 47859021180927,
+STORE, 47859021164544, 47859021172735,
+ERASE, 47859021164544, 47859021164544,
+STORE, 47859021164544, 47859021172735,
+ERASE, 47859021172736, 47859021172736,
+STORE, 47859021172736, 47859021180927,
+STORE, 47859021180928, 47859023020031,
+STORE, 47859021320192, 47859023020031,
+STORE, 47859021180928, 47859021320191,
+ERASE, 47859021320192, 47859021320192,
+STORE, 47859021320192, 47859022979071,
+STORE, 47859022979072, 47859023020031,
+STORE, 47859022663680, 47859022979071,
+STORE, 47859021320192, 47859022663679,
+ERASE, 47859021320192, 47859021320192,
+STORE, 47859021320192, 47859022663679,
+STORE, 47859022974976, 47859022979071,
+STORE, 47859022663680, 47859022974975,
+ERASE, 47859022663680, 47859022663680,
+STORE, 47859022663680, 47859022974975,
+STORE, 47859023003648, 47859023020031,
+STORE, 47859022979072, 47859023003647,
+ERASE, 47859022979072, 47859022979072,
+STORE, 47859022979072, 47859023003647,
+ERASE, 47859023003648, 47859023003648,
+STORE, 47859023003648, 47859023020031,
+STORE, 47859023003648, 47859023032319,
+ERASE, 47859022979072, 47859022979072,
+STORE, 47859022979072, 47859022995455,
+STORE, 47859022995456, 47859023003647,
+ERASE, 47859021164544, 47859021164544,
+STORE, 47859021164544, 47859021168639,
+STORE, 47859021168640, 47859021172735,
+ERASE, 94094885199872, 94094885199872,
+STORE, 94094885199872, 94094885216255,
+STORE, 94094885216256, 94094885220351,
+ERASE, 139773774098432, 139773774098432,
+STORE, 139773774098432, 139773774102527,
+STORE, 139773774102528, 139773774106623,
+ERASE, 47859021058048, 47859021058048,
+STORE, 94094901108736, 94094901243903,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736567963648, 140737488351231,
+ERASE, 140736567963648, 140736567963648,
+STORE, 140736567963648, 140736567967743,
+STORE, 94924425748480, 94924426461183,
+ERASE, 94924425748480, 94924425748480,
+STORE, 94924425748480, 94924425797631,
+STORE, 94924425797632, 94924426461183,
+ERASE, 94924425797632, 94924425797632,
+STORE, 94924425797632, 94924426342399,
+STORE, 94924426342400, 94924426440703,
+STORE, 94924426440704, 94924426461183,
+STORE, 140042126319616, 140042126491647,
+ERASE, 140042126319616, 140042126319616,
+STORE, 140042126319616, 140042126323711,
+STORE, 140042126323712, 140042126491647,
+ERASE, 140042126323712, 140042126323712,
+STORE, 140042126323712, 140042126446591,
+STORE, 140042126446592, 140042126479359,
+STORE, 140042126479360, 140042126487551,
+STORE, 140042126487552, 140042126491647,
+STORE, 140736568672256, 140736568676351,
+STORE, 140736568659968, 140736568672255,
+STORE, 47590668677120, 47590668685311,
+STORE, 47590668685312, 47590668693503,
+STORE, 47590668693504, 47590668799999,
+STORE, 47590668709888, 47590668799999,
+STORE, 47590668693504, 47590668709887,
+ERASE, 47590668709888, 47590668709888,
+STORE, 47590668709888, 47590668783615,
+STORE, 47590668783616, 47590668799999,
+STORE, 47590668763136, 47590668783615,
+STORE, 47590668709888, 47590668763135,
+ERASE, 47590668709888, 47590668709888,
+STORE, 47590668709888, 47590668763135,
+STORE, 47590668779520, 47590668783615,
+STORE, 47590668763136, 47590668779519,
+ERASE, 47590668763136, 47590668763136,
+STORE, 47590668763136, 47590668779519,
+STORE, 47590668791808, 47590668799999,
+STORE, 47590668783616, 47590668791807,
+ERASE, 47590668783616, 47590668783616,
+STORE, 47590668783616, 47590668791807,
+ERASE, 47590668791808, 47590668791808,
+STORE, 47590668791808, 47590668799999,
+STORE, 47590668800000, 47590670639103,
+STORE, 47590668939264, 47590670639103,
+STORE, 47590668800000, 47590668939263,
+ERASE, 47590668939264, 47590668939264,
+STORE, 47590668939264, 47590670598143,
+STORE, 47590670598144, 47590670639103,
+STORE, 47590670282752, 47590670598143,
+STORE, 47590668939264, 47590670282751,
+ERASE, 47590668939264, 47590668939264,
+STORE, 47590668939264, 47590670282751,
+STORE, 47590670594048, 47590670598143,
+STORE, 47590670282752, 47590670594047,
+ERASE, 47590670282752, 47590670282752,
+STORE, 47590670282752, 47590670594047,
+STORE, 47590670622720, 47590670639103,
+STORE, 47590670598144, 47590670622719,
+ERASE, 47590670598144, 47590670598144,
+STORE, 47590670598144, 47590670622719,
+ERASE, 47590670622720, 47590670622720,
+STORE, 47590670622720, 47590670639103,
+STORE, 47590670622720, 47590670651391,
+ERASE, 47590670598144, 47590670598144,
+STORE, 47590670598144, 47590670614527,
+STORE, 47590670614528, 47590670622719,
+ERASE, 47590668783616, 47590668783616,
+STORE, 47590668783616, 47590668787711,
+STORE, 47590668787712, 47590668791807,
+ERASE, 94924426440704, 94924426440704,
+STORE, 94924426440704, 94924426457087,
+STORE, 94924426457088, 94924426461183,
+ERASE, 140042126479360, 140042126479360,
+STORE, 140042126479360, 140042126483455,
+STORE, 140042126483456, 140042126487551,
+ERASE, 47590668677120, 47590668677120,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733281439744, 140737488351231,
+ERASE, 140733281439744, 140733281439744,
+STORE, 140733281439744, 140733281443839,
+STORE, 94490667069440, 94490667782143,
+ERASE, 94490667069440, 94490667069440,
+STORE, 94490667069440, 94490667118591,
+STORE, 94490667118592, 94490667782143,
+ERASE, 94490667118592, 94490667118592,
+STORE, 94490667118592, 94490667663359,
+STORE, 94490667663360, 94490667761663,
+STORE, 94490667761664, 94490667782143,
+STORE, 139878215118848, 139878215290879,
+ERASE, 139878215118848, 139878215118848,
+STORE, 139878215118848, 139878215122943,
+STORE, 139878215122944, 139878215290879,
+ERASE, 139878215122944, 139878215122944,
+STORE, 139878215122944, 139878215245823,
+STORE, 139878215245824, 139878215278591,
+STORE, 139878215278592, 139878215286783,
+STORE, 139878215286784, 139878215290879,
+STORE, 140733281464320, 140733281468415,
+STORE, 140733281452032, 140733281464319,
+STORE, 47754579877888, 47754579886079,
+STORE, 47754579886080, 47754579894271,
+STORE, 47754579894272, 47754580000767,
+STORE, 47754579910656, 47754580000767,
+STORE, 47754579894272, 47754579910655,
+ERASE, 47754579910656, 47754579910656,
+STORE, 47754579910656, 47754579984383,
+STORE, 47754579984384, 47754580000767,
+STORE, 47754579963904, 47754579984383,
+STORE, 47754579910656, 47754579963903,
+ERASE, 47754579910656, 47754579910656,
+STORE, 47754579910656, 47754579963903,
+STORE, 47754579980288, 47754579984383,
+STORE, 47754579963904, 47754579980287,
+ERASE, 47754579963904, 47754579963904,
+STORE, 47754579963904, 47754579980287,
+STORE, 47754579992576, 47754580000767,
+STORE, 47754579984384, 47754579992575,
+ERASE, 47754579984384, 47754579984384,
+STORE, 47754579984384, 47754579992575,
+ERASE, 47754579992576, 47754579992576,
+STORE, 47754579992576, 47754580000767,
+STORE, 47754580000768, 47754581839871,
+STORE, 47754580140032, 47754581839871,
+STORE, 47754580000768, 47754580140031,
+ERASE, 47754580140032, 47754580140032,
+STORE, 47754580140032, 47754581798911,
+STORE, 47754581798912, 47754581839871,
+STORE, 47754581483520, 47754581798911,
+STORE, 47754580140032, 47754581483519,
+ERASE, 47754580140032, 47754580140032,
+STORE, 47754580140032, 47754581483519,
+STORE, 47754581794816, 47754581798911,
+STORE, 47754581483520, 47754581794815,
+ERASE, 47754581483520, 47754581483520,
+STORE, 47754581483520, 47754581794815,
+STORE, 47754581823488, 47754581839871,
+STORE, 47754581798912, 47754581823487,
+ERASE, 47754581798912, 47754581798912,
+STORE, 47754581798912, 47754581823487,
+ERASE, 47754581823488, 47754581823488,
+STORE, 47754581823488, 47754581839871,
+STORE, 47754581823488, 47754581852159,
+ERASE, 47754581798912, 47754581798912,
+STORE, 47754581798912, 47754581815295,
+STORE, 47754581815296, 47754581823487,
+ERASE, 47754579984384, 47754579984384,
+STORE, 47754579984384, 47754579988479,
+STORE, 47754579988480, 47754579992575,
+ERASE, 94490667761664, 94490667761664,
+STORE, 94490667761664, 94490667778047,
+STORE, 94490667778048, 94490667782143,
+ERASE, 139878215278592, 139878215278592,
+STORE, 139878215278592, 139878215282687,
+STORE, 139878215282688, 139878215286783,
+ERASE, 47754579877888, 47754579877888,
+STORE, 94490669649920, 94490669785087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140735382188032, 140737488351231,
+ERASE, 140735382188032, 140735382188032,
+STORE, 140735382188032, 140735382192127,
+STORE, 94150181302272, 94150182014975,
+ERASE, 94150181302272, 94150181302272,
+STORE, 94150181302272, 94150181351423,
+STORE, 94150181351424, 94150182014975,
+ERASE, 94150181351424, 94150181351424,
+STORE, 94150181351424, 94150181896191,
+STORE, 94150181896192, 94150181994495,
+STORE, 94150181994496, 94150182014975,
+STORE, 139679752458240, 139679752630271,
+ERASE, 139679752458240, 139679752458240,
+STORE, 139679752458240, 139679752462335,
+STORE, 139679752462336, 139679752630271,
+ERASE, 139679752462336, 139679752462336,
+STORE, 139679752462336, 139679752585215,
+STORE, 139679752585216, 139679752617983,
+STORE, 139679752617984, 139679752626175,
+STORE, 139679752626176, 139679752630271,
+STORE, 140735382536192, 140735382540287,
+STORE, 140735382523904, 140735382536191,
+STORE, 47953042538496, 47953042546687,
+STORE, 47953042546688, 47953042554879,
+STORE, 47953042554880, 47953042661375,
+STORE, 47953042571264, 47953042661375,
+STORE, 47953042554880, 47953042571263,
+ERASE, 47953042571264, 47953042571264,
+STORE, 47953042571264, 47953042644991,
+STORE, 47953042644992, 47953042661375,
+STORE, 47953042624512, 47953042644991,
+STORE, 47953042571264, 47953042624511,
+ERASE, 47953042571264, 47953042571264,
+STORE, 47953042571264, 47953042624511,
+STORE, 47953042640896, 47953042644991,
+STORE, 47953042624512, 47953042640895,
+ERASE, 47953042624512, 47953042624512,
+STORE, 47953042624512, 47953042640895,
+STORE, 47953042653184, 47953042661375,
+STORE, 47953042644992, 47953042653183,
+ERASE, 47953042644992, 47953042644992,
+STORE, 47953042644992, 47953042653183,
+ERASE, 47953042653184, 47953042653184,
+STORE, 47953042653184, 47953042661375,
+STORE, 47953042661376, 47953044500479,
+STORE, 47953042800640, 47953044500479,
+STORE, 47953042661376, 47953042800639,
+ERASE, 47953042800640, 47953042800640,
+STORE, 47953042800640, 47953044459519,
+STORE, 47953044459520, 47953044500479,
+STORE, 47953044144128, 47953044459519,
+STORE, 47953042800640, 47953044144127,
+ERASE, 47953042800640, 47953042800640,
+STORE, 47953042800640, 47953044144127,
+STORE, 47953044455424, 47953044459519,
+STORE, 47953044144128, 47953044455423,
+ERASE, 47953044144128, 47953044144128,
+STORE, 47953044144128, 47953044455423,
+STORE, 47953044484096, 47953044500479,
+STORE, 47953044459520, 47953044484095,
+ERASE, 47953044459520, 47953044459520,
+STORE, 47953044459520, 47953044484095,
+ERASE, 47953044484096, 47953044484096,
+STORE, 47953044484096, 47953044500479,
+STORE, 47953044484096, 47953044512767,
+ERASE, 47953044459520, 47953044459520,
+STORE, 47953044459520, 47953044475903,
+STORE, 47953044475904, 47953044484095,
+ERASE, 47953042644992, 47953042644992,
+STORE, 47953042644992, 47953042649087,
+STORE, 47953042649088, 47953042653183,
+ERASE, 94150181994496, 94150181994496,
+STORE, 94150181994496, 94150182010879,
+STORE, 94150182010880, 94150182014975,
+ERASE, 139679752617984, 139679752617984,
+STORE, 139679752617984, 139679752622079,
+STORE, 139679752622080, 139679752626175,
+ERASE, 47953042538496, 47953042538496,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737044123648, 140737488351231,
+ERASE, 140737044123648, 140737044123648,
+STORE, 140737044123648, 140737044127743,
+STORE, 94425324294144, 94425325006847,
+ERASE, 94425324294144, 94425324294144,
+STORE, 94425324294144, 94425324343295,
+STORE, 94425324343296, 94425325006847,
+ERASE, 94425324343296, 94425324343296,
+STORE, 94425324343296, 94425324888063,
+STORE, 94425324888064, 94425324986367,
+STORE, 94425324986368, 94425325006847,
+STORE, 140382015016960, 140382015188991,
+ERASE, 140382015016960, 140382015016960,
+STORE, 140382015016960, 140382015021055,
+STORE, 140382015021056, 140382015188991,
+ERASE, 140382015021056, 140382015021056,
+STORE, 140382015021056, 140382015143935,
+STORE, 140382015143936, 140382015176703,
+STORE, 140382015176704, 140382015184895,
+STORE, 140382015184896, 140382015188991,
+STORE, 140737045585920, 140737045590015,
+STORE, 140737045573632, 140737045585919,
+STORE, 47250779979776, 47250779987967,
+STORE, 47250779987968, 47250779996159,
+STORE, 47250779996160, 47250780102655,
+STORE, 47250780012544, 47250780102655,
+STORE, 47250779996160, 47250780012543,
+ERASE, 47250780012544, 47250780012544,
+STORE, 47250780012544, 47250780086271,
+STORE, 47250780086272, 47250780102655,
+STORE, 47250780065792, 47250780086271,
+STORE, 47250780012544, 47250780065791,
+ERASE, 47250780012544, 47250780012544,
+STORE, 47250780012544, 47250780065791,
+STORE, 47250780082176, 47250780086271,
+STORE, 47250780065792, 47250780082175,
+ERASE, 47250780065792, 47250780065792,
+STORE, 47250780065792, 47250780082175,
+STORE, 47250780094464, 47250780102655,
+STORE, 47250780086272, 47250780094463,
+ERASE, 47250780086272, 47250780086272,
+STORE, 47250780086272, 47250780094463,
+ERASE, 47250780094464, 47250780094464,
+STORE, 47250780094464, 47250780102655,
+STORE, 47250780102656, 47250781941759,
+STORE, 47250780241920, 47250781941759,
+STORE, 47250780102656, 47250780241919,
+ERASE, 47250780241920, 47250780241920,
+STORE, 47250780241920, 47250781900799,
+STORE, 47250781900800, 47250781941759,
+STORE, 47250781585408, 47250781900799,
+STORE, 47250780241920, 47250781585407,
+ERASE, 47250780241920, 47250780241920,
+STORE, 47250780241920, 47250781585407,
+STORE, 47250781896704, 47250781900799,
+STORE, 47250781585408, 47250781896703,
+ERASE, 47250781585408, 47250781585408,
+STORE, 47250781585408, 47250781896703,
+STORE, 47250781925376, 47250781941759,
+STORE, 47250781900800, 47250781925375,
+ERASE, 47250781900800, 47250781900800,
+STORE, 47250781900800, 47250781925375,
+ERASE, 47250781925376, 47250781925376,
+STORE, 47250781925376, 47250781941759,
+STORE, 47250781925376, 47250781954047,
+ERASE, 47250781900800, 47250781900800,
+STORE, 47250781900800, 47250781917183,
+STORE, 47250781917184, 47250781925375,
+ERASE, 47250780086272, 47250780086272,
+STORE, 47250780086272, 47250780090367,
+STORE, 47250780090368, 47250780094463,
+ERASE, 94425324986368, 94425324986368,
+STORE, 94425324986368, 94425325002751,
+STORE, 94425325002752, 94425325006847,
+ERASE, 140382015176704, 140382015176704,
+STORE, 140382015176704, 140382015180799,
+STORE, 140382015180800, 140382015184895,
+ERASE, 47250779979776, 47250779979776,
+STORE, 94425351438336, 94425351573503,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736801144832, 140737488351231,
+ERASE, 140736801144832, 140736801144832,
+STORE, 140736801144832, 140736801148927,
+STORE, 94629429358592, 94629430071295,
+ERASE, 94629429358592, 94629429358592,
+STORE, 94629429358592, 94629429407743,
+STORE, 94629429407744, 94629430071295,
+ERASE, 94629429407744, 94629429407744,
+STORE, 94629429407744, 94629429952511,
+STORE, 94629429952512, 94629430050815,
+STORE, 94629430050816, 94629430071295,
+STORE, 139801685483520, 139801685655551,
+ERASE, 139801685483520, 139801685483520,
+STORE, 139801685483520, 139801685487615,
+STORE, 139801685487616, 139801685655551,
+ERASE, 139801685487616, 139801685487616,
+STORE, 139801685487616, 139801685610495,
+STORE, 139801685610496, 139801685643263,
+STORE, 139801685643264, 139801685651455,
+STORE, 139801685651456, 139801685655551,
+STORE, 140736801198080, 140736801202175,
+STORE, 140736801185792, 140736801198079,
+STORE, 47831109513216, 47831109521407,
+STORE, 47831109521408, 47831109529599,
+STORE, 47831109529600, 47831109636095,
+STORE, 47831109545984, 47831109636095,
+STORE, 47831109529600, 47831109545983,
+ERASE, 47831109545984, 47831109545984,
+STORE, 47831109545984, 47831109619711,
+STORE, 47831109619712, 47831109636095,
+STORE, 47831109599232, 47831109619711,
+STORE, 47831109545984, 47831109599231,
+ERASE, 47831109545984, 47831109545984,
+STORE, 47831109545984, 47831109599231,
+STORE, 47831109615616, 47831109619711,
+STORE, 47831109599232, 47831109615615,
+ERASE, 47831109599232, 47831109599232,
+STORE, 47831109599232, 47831109615615,
+STORE, 47831109627904, 47831109636095,
+STORE, 47831109619712, 47831109627903,
+ERASE, 47831109619712, 47831109619712,
+STORE, 47831109619712, 47831109627903,
+ERASE, 47831109627904, 47831109627904,
+STORE, 47831109627904, 47831109636095,
+STORE, 47831109636096, 47831111475199,
+STORE, 47831109775360, 47831111475199,
+STORE, 47831109636096, 47831109775359,
+ERASE, 47831109775360, 47831109775360,
+STORE, 47831109775360, 47831111434239,
+STORE, 47831111434240, 47831111475199,
+STORE, 47831111118848, 47831111434239,
+STORE, 47831109775360, 47831111118847,
+ERASE, 47831109775360, 47831109775360,
+STORE, 47831109775360, 47831111118847,
+STORE, 47831111430144, 47831111434239,
+STORE, 47831111118848, 47831111430143,
+ERASE, 47831111118848, 47831111118848,
+STORE, 47831111118848, 47831111430143,
+STORE, 47831111458816, 47831111475199,
+STORE, 47831111434240, 47831111458815,
+ERASE, 47831111434240, 47831111434240,
+STORE, 47831111434240, 47831111458815,
+ERASE, 47831111458816, 47831111458816,
+STORE, 47831111458816, 47831111475199,
+STORE, 47831111458816, 47831111487487,
+ERASE, 47831111434240, 47831111434240,
+STORE, 47831111434240, 47831111450623,
+STORE, 47831111450624, 47831111458815,
+ERASE, 47831109619712, 47831109619712,
+STORE, 47831109619712, 47831109623807,
+STORE, 47831109623808, 47831109627903,
+ERASE, 94629430050816, 94629430050816,
+STORE, 94629430050816, 94629430067199,
+STORE, 94629430067200, 94629430071295,
+ERASE, 139801685643264, 139801685643264,
+STORE, 139801685643264, 139801685647359,
+STORE, 139801685647360, 139801685651455,
+ERASE, 47831109513216, 47831109513216,
+STORE, 140737488347136, 140737488351231,
+STORE, 140729419612160, 140737488351231,
+ERASE, 140729419612160, 140729419612160,
+STORE, 140729419612160, 140729419616255,
+STORE, 94443354148864, 94443354861567,
+ERASE, 94443354148864, 94443354148864,
+STORE, 94443354148864, 94443354198015,
+STORE, 94443354198016, 94443354861567,
+ERASE, 94443354198016, 94443354198016,
+STORE, 94443354198016, 94443354742783,
+STORE, 94443354742784, 94443354841087,
+STORE, 94443354841088, 94443354861567,
+STORE, 139741700038656, 139741700210687,
+ERASE, 139741700038656, 139741700038656,
+STORE, 139741700038656, 139741700042751,
+STORE, 139741700042752, 139741700210687,
+ERASE, 139741700042752, 139741700042752,
+STORE, 139741700042752, 139741700165631,
+STORE, 139741700165632, 139741700198399,
+STORE, 139741700198400, 139741700206591,
+STORE, 139741700206592, 139741700210687,
+STORE, 140729420574720, 140729420578815,
+STORE, 140729420562432, 140729420574719,
+STORE, 47891094958080, 47891094966271,
+STORE, 47891094966272, 47891094974463,
+STORE, 47891094974464, 47891095080959,
+STORE, 47891094990848, 47891095080959,
+STORE, 47891094974464, 47891094990847,
+ERASE, 47891094990848, 47891094990848,
+STORE, 47891094990848, 47891095064575,
+STORE, 47891095064576, 47891095080959,
+STORE, 47891095044096, 47891095064575,
+STORE, 47891094990848, 47891095044095,
+ERASE, 47891094990848, 47891094990848,
+STORE, 47891094990848, 47891095044095,
+STORE, 47891095060480, 47891095064575,
+STORE, 47891095044096, 47891095060479,
+ERASE, 47891095044096, 47891095044096,
+STORE, 47891095044096, 47891095060479,
+STORE, 47891095072768, 47891095080959,
+STORE, 47891095064576, 47891095072767,
+ERASE, 47891095064576, 47891095064576,
+STORE, 47891095064576, 47891095072767,
+ERASE, 47891095072768, 47891095072768,
+STORE, 47891095072768, 47891095080959,
+STORE, 47891095080960, 47891096920063,
+STORE, 47891095220224, 47891096920063,
+STORE, 47891095080960, 47891095220223,
+ERASE, 47891095220224, 47891095220224,
+STORE, 47891095220224, 47891096879103,
+STORE, 47891096879104, 47891096920063,
+STORE, 47891096563712, 47891096879103,
+STORE, 47891095220224, 47891096563711,
+ERASE, 47891095220224, 47891095220224,
+STORE, 47891095220224, 47891096563711,
+STORE, 47891096875008, 47891096879103,
+STORE, 47891096563712, 47891096875007,
+ERASE, 47891096563712, 47891096563712,
+STORE, 47891096563712, 47891096875007,
+STORE, 47891096903680, 47891096920063,
+STORE, 47891096879104, 47891096903679,
+ERASE, 47891096879104, 47891096879104,
+STORE, 47891096879104, 47891096903679,
+ERASE, 47891096903680, 47891096903680,
+STORE, 47891096903680, 47891096920063,
+STORE, 47891096903680, 47891096932351,
+ERASE, 47891096879104, 47891096879104,
+STORE, 47891096879104, 47891096895487,
+STORE, 47891096895488, 47891096903679,
+ERASE, 47891095064576, 47891095064576,
+STORE, 47891095064576, 47891095068671,
+STORE, 47891095068672, 47891095072767,
+ERASE, 94443354841088, 94443354841088,
+STORE, 94443354841088, 94443354857471,
+STORE, 94443354857472, 94443354861567,
+ERASE, 139741700198400, 139741700198400,
+STORE, 139741700198400, 139741700202495,
+STORE, 139741700202496, 139741700206591,
+ERASE, 47891094958080, 47891094958080,
+STORE, 94443360825344, 94443360960511,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722961661952, 140737488351231,
+ERASE, 140722961661952, 140722961661952,
+STORE, 140722961661952, 140722961666047,
+STORE, 94878388944896, 94878389657599,
+ERASE, 94878388944896, 94878388944896,
+STORE, 94878388944896, 94878388994047,
+STORE, 94878388994048, 94878389657599,
+ERASE, 94878388994048, 94878388994048,
+STORE, 94878388994048, 94878389538815,
+STORE, 94878389538816, 94878389637119,
+STORE, 94878389637120, 94878389657599,
+STORE, 140210690056192, 140210690228223,
+ERASE, 140210690056192, 140210690056192,
+STORE, 140210690056192, 140210690060287,
+STORE, 140210690060288, 140210690228223,
+ERASE, 140210690060288, 140210690060288,
+STORE, 140210690060288, 140210690183167,
+STORE, 140210690183168, 140210690215935,
+STORE, 140210690215936, 140210690224127,
+STORE, 140210690224128, 140210690228223,
+STORE, 140722963148800, 140722963152895,
+STORE, 140722963136512, 140722963148799,
+STORE, 47422104940544, 47422104948735,
+STORE, 47422104948736, 47422104956927,
+STORE, 47422104956928, 47422105063423,
+STORE, 47422104973312, 47422105063423,
+STORE, 47422104956928, 47422104973311,
+ERASE, 47422104973312, 47422104973312,
+STORE, 47422104973312, 47422105047039,
+STORE, 47422105047040, 47422105063423,
+STORE, 47422105026560, 47422105047039,
+STORE, 47422104973312, 47422105026559,
+ERASE, 47422104973312, 47422104973312,
+STORE, 47422104973312, 47422105026559,
+STORE, 47422105042944, 47422105047039,
+STORE, 47422105026560, 47422105042943,
+ERASE, 47422105026560, 47422105026560,
+STORE, 47422105026560, 47422105042943,
+STORE, 47422105055232, 47422105063423,
+STORE, 47422105047040, 47422105055231,
+ERASE, 47422105047040, 47422105047040,
+STORE, 47422105047040, 47422105055231,
+ERASE, 47422105055232, 47422105055232,
+STORE, 47422105055232, 47422105063423,
+STORE, 47422105063424, 47422106902527,
+STORE, 47422105202688, 47422106902527,
+STORE, 47422105063424, 47422105202687,
+ERASE, 47422105202688, 47422105202688,
+STORE, 47422105202688, 47422106861567,
+STORE, 47422106861568, 47422106902527,
+STORE, 47422106546176, 47422106861567,
+STORE, 47422105202688, 47422106546175,
+ERASE, 47422105202688, 47422105202688,
+STORE, 47422105202688, 47422106546175,
+STORE, 47422106857472, 47422106861567,
+STORE, 47422106546176, 47422106857471,
+ERASE, 47422106546176, 47422106546176,
+STORE, 47422106546176, 47422106857471,
+STORE, 47422106886144, 47422106902527,
+STORE, 47422106861568, 47422106886143,
+ERASE, 47422106861568, 47422106861568,
+STORE, 47422106861568, 47422106886143,
+ERASE, 47422106886144, 47422106886144,
+STORE, 47422106886144, 47422106902527,
+STORE, 47422106886144, 47422106914815,
+ERASE, 47422106861568, 47422106861568,
+STORE, 47422106861568, 47422106877951,
+STORE, 47422106877952, 47422106886143,
+ERASE, 47422105047040, 47422105047040,
+STORE, 47422105047040, 47422105051135,
+STORE, 47422105051136, 47422105055231,
+ERASE, 94878389637120, 94878389637120,
+STORE, 94878389637120, 94878389653503,
+STORE, 94878389653504, 94878389657599,
+ERASE, 140210690215936, 140210690215936,
+STORE, 140210690215936, 140210690220031,
+STORE, 140210690220032, 140210690224127,
+ERASE, 47422104940544, 47422104940544,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727690309632, 140737488351231,
+ERASE, 140727690309632, 140727690309632,
+STORE, 140727690309632, 140727690313727,
+STORE, 94121892208640, 94121892921343,
+ERASE, 94121892208640, 94121892208640,
+STORE, 94121892208640, 94121892257791,
+STORE, 94121892257792, 94121892921343,
+ERASE, 94121892257792, 94121892257792,
+STORE, 94121892257792, 94121892802559,
+STORE, 94121892802560, 94121892900863,
+STORE, 94121892900864, 94121892921343,
+STORE, 140662438326272, 140662438498303,
+ERASE, 140662438326272, 140662438326272,
+STORE, 140662438326272, 140662438330367,
+STORE, 140662438330368, 140662438498303,
+ERASE, 140662438330368, 140662438330368,
+STORE, 140662438330368, 140662438453247,
+STORE, 140662438453248, 140662438486015,
+STORE, 140662438486016, 140662438494207,
+STORE, 140662438494208, 140662438498303,
+STORE, 140727690379264, 140727690383359,
+STORE, 140727690366976, 140727690379263,
+STORE, 46970356670464, 46970356678655,
+STORE, 46970356678656, 46970356686847,
+STORE, 46970356686848, 46970356793343,
+STORE, 46970356703232, 46970356793343,
+STORE, 46970356686848, 46970356703231,
+ERASE, 46970356703232, 46970356703232,
+STORE, 46970356703232, 46970356776959,
+STORE, 46970356776960, 46970356793343,
+STORE, 46970356756480, 46970356776959,
+STORE, 46970356703232, 46970356756479,
+ERASE, 46970356703232, 46970356703232,
+STORE, 46970356703232, 46970356756479,
+STORE, 46970356772864, 46970356776959,
+STORE, 46970356756480, 46970356772863,
+ERASE, 46970356756480, 46970356756480,
+STORE, 46970356756480, 46970356772863,
+STORE, 46970356785152, 46970356793343,
+STORE, 46970356776960, 46970356785151,
+ERASE, 46970356776960, 46970356776960,
+STORE, 46970356776960, 46970356785151,
+ERASE, 46970356785152, 46970356785152,
+STORE, 46970356785152, 46970356793343,
+STORE, 46970356793344, 46970358632447,
+STORE, 46970356932608, 46970358632447,
+STORE, 46970356793344, 46970356932607,
+ERASE, 46970356932608, 46970356932608,
+STORE, 46970356932608, 46970358591487,
+STORE, 46970358591488, 46970358632447,
+STORE, 46970358276096, 46970358591487,
+STORE, 46970356932608, 46970358276095,
+ERASE, 46970356932608, 46970356932608,
+STORE, 46970356932608, 46970358276095,
+STORE, 46970358587392, 46970358591487,
+STORE, 46970358276096, 46970358587391,
+ERASE, 46970358276096, 46970358276096,
+STORE, 46970358276096, 46970358587391,
+STORE, 46970358616064, 46970358632447,
+STORE, 46970358591488, 46970358616063,
+ERASE, 46970358591488, 46970358591488,
+STORE, 46970358591488, 46970358616063,
+ERASE, 46970358616064, 46970358616064,
+STORE, 46970358616064, 46970358632447,
+STORE, 46970358616064, 46970358644735,
+ERASE, 46970358591488, 46970358591488,
+STORE, 46970358591488, 46970358607871,
+STORE, 46970358607872, 46970358616063,
+ERASE, 46970356776960, 46970356776960,
+STORE, 46970356776960, 46970356781055,
+STORE, 46970356781056, 46970356785151,
+ERASE, 94121892900864, 94121892900864,
+STORE, 94121892900864, 94121892917247,
+STORE, 94121892917248, 94121892921343,
+ERASE, 140662438486016, 140662438486016,
+STORE, 140662438486016, 140662438490111,
+STORE, 140662438490112, 140662438494207,
+ERASE, 46970356670464, 46970356670464,
+STORE, 94121898610688, 94121898745855,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737189351424, 140737488351231,
+ERASE, 140737189351424, 140737189351424,
+STORE, 140737189351424, 140737189355519,
+STORE, 93847948832768, 93847949545471,
+ERASE, 93847948832768, 93847948832768,
+STORE, 93847948832768, 93847948881919,
+STORE, 93847948881920, 93847949545471,
+ERASE, 93847948881920, 93847948881920,
+STORE, 93847948881920, 93847949426687,
+STORE, 93847949426688, 93847949524991,
+STORE, 93847949524992, 93847949545471,
+STORE, 139698989985792, 139698990157823,
+ERASE, 139698989985792, 139698989985792,
+STORE, 139698989985792, 139698989989887,
+STORE, 139698989989888, 139698990157823,
+ERASE, 139698989989888, 139698989989888,
+STORE, 139698989989888, 139698990112767,
+STORE, 139698990112768, 139698990145535,
+STORE, 139698990145536, 139698990153727,
+STORE, 139698990153728, 139698990157823,
+STORE, 140737189744640, 140737189748735,
+STORE, 140737189732352, 140737189744639,
+STORE, 47933805010944, 47933805019135,
+STORE, 47933805019136, 47933805027327,
+STORE, 47933805027328, 47933805133823,
+STORE, 47933805043712, 47933805133823,
+STORE, 47933805027328, 47933805043711,
+ERASE, 47933805043712, 47933805043712,
+STORE, 47933805043712, 47933805117439,
+STORE, 47933805117440, 47933805133823,
+STORE, 47933805096960, 47933805117439,
+STORE, 47933805043712, 47933805096959,
+ERASE, 47933805043712, 47933805043712,
+STORE, 47933805043712, 47933805096959,
+STORE, 47933805113344, 47933805117439,
+STORE, 47933805096960, 47933805113343,
+ERASE, 47933805096960, 47933805096960,
+STORE, 47933805096960, 47933805113343,
+STORE, 47933805125632, 47933805133823,
+STORE, 47933805117440, 47933805125631,
+ERASE, 47933805117440, 47933805117440,
+STORE, 47933805117440, 47933805125631,
+ERASE, 47933805125632, 47933805125632,
+STORE, 47933805125632, 47933805133823,
+STORE, 47933805133824, 47933806972927,
+STORE, 47933805273088, 47933806972927,
+STORE, 47933805133824, 47933805273087,
+ERASE, 47933805273088, 47933805273088,
+STORE, 47933805273088, 47933806931967,
+STORE, 47933806931968, 47933806972927,
+STORE, 47933806616576, 47933806931967,
+STORE, 47933805273088, 47933806616575,
+ERASE, 47933805273088, 47933805273088,
+STORE, 47933805273088, 47933806616575,
+STORE, 47933806927872, 47933806931967,
+STORE, 47933806616576, 47933806927871,
+ERASE, 47933806616576, 47933806616576,
+STORE, 47933806616576, 47933806927871,
+STORE, 47933806956544, 47933806972927,
+STORE, 47933806931968, 47933806956543,
+ERASE, 47933806931968, 47933806931968,
+STORE, 47933806931968, 47933806956543,
+ERASE, 47933806956544, 47933806956544,
+STORE, 47933806956544, 47933806972927,
+STORE, 47933806956544, 47933806985215,
+ERASE, 47933806931968, 47933806931968,
+STORE, 47933806931968, 47933806948351,
+STORE, 47933806948352, 47933806956543,
+ERASE, 47933805117440, 47933805117440,
+STORE, 47933805117440, 47933805121535,
+STORE, 47933805121536, 47933805125631,
+ERASE, 93847949524992, 93847949524992,
+STORE, 93847949524992, 93847949541375,
+STORE, 93847949541376, 93847949545471,
+ERASE, 139698990145536, 139698990145536,
+STORE, 139698990145536, 139698990149631,
+STORE, 139698990149632, 139698990153727,
+ERASE, 47933805010944, 47933805010944,
+STORE, 140737488347136, 140737488351231,
+STORE, 140725553991680, 140737488351231,
+ERASE, 140725553991680, 140725553991680,
+STORE, 140725553991680, 140725553995775,
+STORE, 93980056248320, 93980056961023,
+ERASE, 93980056248320, 93980056248320,
+STORE, 93980056248320, 93980056297471,
+STORE, 93980056297472, 93980056961023,
+ERASE, 93980056297472, 93980056297472,
+STORE, 93980056297472, 93980056842239,
+STORE, 93980056842240, 93980056940543,
+STORE, 93980056940544, 93980056961023,
+STORE, 140146588971008, 140146589143039,
+ERASE, 140146588971008, 140146588971008,
+STORE, 140146588971008, 140146588975103,
+STORE, 140146588975104, 140146589143039,
+ERASE, 140146588975104, 140146588975104,
+STORE, 140146588975104, 140146589097983,
+STORE, 140146589097984, 140146589130751,
+STORE, 140146589130752, 140146589138943,
+STORE, 140146589138944, 140146589143039,
+STORE, 140725554860032, 140725554864127,
+STORE, 140725554847744, 140725554860031,
+STORE, 47486206025728, 47486206033919,
+STORE, 47486206033920, 47486206042111,
+STORE, 47486206042112, 47486206148607,
+STORE, 47486206058496, 47486206148607,
+STORE, 47486206042112, 47486206058495,
+ERASE, 47486206058496, 47486206058496,
+STORE, 47486206058496, 47486206132223,
+STORE, 47486206132224, 47486206148607,
+STORE, 47486206111744, 47486206132223,
+STORE, 47486206058496, 47486206111743,
+ERASE, 47486206058496, 47486206058496,
+STORE, 47486206058496, 47486206111743,
+STORE, 47486206128128, 47486206132223,
+STORE, 47486206111744, 47486206128127,
+ERASE, 47486206111744, 47486206111744,
+STORE, 47486206111744, 47486206128127,
+STORE, 47486206140416, 47486206148607,
+STORE, 47486206132224, 47486206140415,
+ERASE, 47486206132224, 47486206132224,
+STORE, 47486206132224, 47486206140415,
+ERASE, 47486206140416, 47486206140416,
+STORE, 47486206140416, 47486206148607,
+STORE, 47486206148608, 47486207987711,
+STORE, 47486206287872, 47486207987711,
+STORE, 47486206148608, 47486206287871,
+ERASE, 47486206287872, 47486206287872,
+STORE, 47486206287872, 47486207946751,
+STORE, 47486207946752, 47486207987711,
+STORE, 47486207631360, 47486207946751,
+STORE, 47486206287872, 47486207631359,
+ERASE, 47486206287872, 47486206287872,
+STORE, 47486206287872, 47486207631359,
+STORE, 47486207942656, 47486207946751,
+STORE, 47486207631360, 47486207942655,
+ERASE, 47486207631360, 47486207631360,
+STORE, 47486207631360, 47486207942655,
+STORE, 47486207971328, 47486207987711,
+STORE, 47486207946752, 47486207971327,
+ERASE, 47486207946752, 47486207946752,
+STORE, 47486207946752, 47486207971327,
+ERASE, 47486207971328, 47486207971328,
+STORE, 47486207971328, 47486207987711,
+STORE, 47486207971328, 47486207999999,
+ERASE, 47486207946752, 47486207946752,
+STORE, 47486207946752, 47486207963135,
+STORE, 47486207963136, 47486207971327,
+ERASE, 47486206132224, 47486206132224,
+STORE, 47486206132224, 47486206136319,
+STORE, 47486206136320, 47486206140415,
+ERASE, 93980056940544, 93980056940544,
+STORE, 93980056940544, 93980056956927,
+STORE, 93980056956928, 93980056961023,
+ERASE, 140146589130752, 140146589130752,
+STORE, 140146589130752, 140146589134847,
+STORE, 140146589134848, 140146589138943,
+ERASE, 47486206025728, 47486206025728,
+STORE, 93980070006784, 93980070141951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727334776832, 140737488351231,
+ERASE, 140727334776832, 140727334776832,
+STORE, 140727334776832, 140727334780927,
+STORE, 94049747247104, 94049747959807,
+ERASE, 94049747247104, 94049747247104,
+STORE, 94049747247104, 94049747296255,
+STORE, 94049747296256, 94049747959807,
+ERASE, 94049747296256, 94049747296256,
+STORE, 94049747296256, 94049747841023,
+STORE, 94049747841024, 94049747939327,
+STORE, 94049747939328, 94049747959807,
+STORE, 140227307216896, 140227307388927,
+ERASE, 140227307216896, 140227307216896,
+STORE, 140227307216896, 140227307220991,
+STORE, 140227307220992, 140227307388927,
+ERASE, 140227307220992, 140227307220992,
+STORE, 140227307220992, 140227307343871,
+STORE, 140227307343872, 140227307376639,
+STORE, 140227307376640, 140227307384831,
+STORE, 140227307384832, 140227307388927,
+STORE, 140727335337984, 140727335342079,
+STORE, 140727335325696, 140727335337983,
+STORE, 47405487779840, 47405487788031,
+STORE, 47405487788032, 47405487796223,
+STORE, 47405487796224, 47405487902719,
+STORE, 47405487812608, 47405487902719,
+STORE, 47405487796224, 47405487812607,
+ERASE, 47405487812608, 47405487812608,
+STORE, 47405487812608, 47405487886335,
+STORE, 47405487886336, 47405487902719,
+STORE, 47405487865856, 47405487886335,
+STORE, 47405487812608, 47405487865855,
+ERASE, 47405487812608, 47405487812608,
+STORE, 47405487812608, 47405487865855,
+STORE, 47405487882240, 47405487886335,
+STORE, 47405487865856, 47405487882239,
+ERASE, 47405487865856, 47405487865856,
+STORE, 47405487865856, 47405487882239,
+STORE, 47405487894528, 47405487902719,
+STORE, 47405487886336, 47405487894527,
+ERASE, 47405487886336, 47405487886336,
+STORE, 47405487886336, 47405487894527,
+ERASE, 47405487894528, 47405487894528,
+STORE, 47405487894528, 47405487902719,
+STORE, 47405487902720, 47405489741823,
+STORE, 47405488041984, 47405489741823,
+STORE, 47405487902720, 47405488041983,
+ERASE, 47405488041984, 47405488041984,
+STORE, 47405488041984, 47405489700863,
+STORE, 47405489700864, 47405489741823,
+STORE, 47405489385472, 47405489700863,
+STORE, 47405488041984, 47405489385471,
+ERASE, 47405488041984, 47405488041984,
+STORE, 47405488041984, 47405489385471,
+STORE, 47405489696768, 47405489700863,
+STORE, 47405489385472, 47405489696767,
+ERASE, 47405489385472, 47405489385472,
+STORE, 47405489385472, 47405489696767,
+STORE, 47405489725440, 47405489741823,
+STORE, 47405489700864, 47405489725439,
+ERASE, 47405489700864, 47405489700864,
+STORE, 47405489700864, 47405489725439,
+ERASE, 47405489725440, 47405489725440,
+STORE, 47405489725440, 47405489741823,
+STORE, 47405489725440, 47405489754111,
+ERASE, 47405489700864, 47405489700864,
+STORE, 47405489700864, 47405489717247,
+STORE, 47405489717248, 47405489725439,
+ERASE, 47405487886336, 47405487886336,
+STORE, 47405487886336, 47405487890431,
+STORE, 47405487890432, 47405487894527,
+ERASE, 94049747939328, 94049747939328,
+STORE, 94049747939328, 94049747955711,
+STORE, 94049747955712, 94049747959807,
+ERASE, 140227307376640, 140227307376640,
+STORE, 140227307376640, 140227307380735,
+STORE, 140227307380736, 140227307384831,
+ERASE, 47405487779840, 47405487779840,
+STORE, 94049758810112, 94049758945279,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727079718912, 140737488351231,
+ERASE, 140727079718912, 140727079718912,
+STORE, 140727079718912, 140727079723007,
+STORE, 94250996527104, 94250997239807,
+ERASE, 94250996527104, 94250996527104,
+STORE, 94250996527104, 94250996576255,
+STORE, 94250996576256, 94250997239807,
+ERASE, 94250996576256, 94250996576256,
+STORE, 94250996576256, 94250997121023,
+STORE, 94250997121024, 94250997219327,
+STORE, 94250997219328, 94250997239807,
+STORE, 140060022587392, 140060022759423,
+ERASE, 140060022587392, 140060022587392,
+STORE, 140060022587392, 140060022591487,
+STORE, 140060022591488, 140060022759423,
+ERASE, 140060022591488, 140060022591488,
+STORE, 140060022591488, 140060022714367,
+STORE, 140060022714368, 140060022747135,
+STORE, 140060022747136, 140060022755327,
+STORE, 140060022755328, 140060022759423,
+STORE, 140727079788544, 140727079792639,
+STORE, 140727079776256, 140727079788543,
+/* this next one caused issues when lowering the efficiency */
+STORE, 47572772409344, 47572772417535,
+STORE, 47572772417536, 47572772425727,
+STORE, 47572772425728, 47572772532223,
+STORE, 47572772442112, 47572772532223,
+STORE, 47572772425728, 47572772442111,
+ERASE, 47572772442112, 47572772442112,
+STORE, 47572772442112, 47572772515839,
+STORE, 47572772515840, 47572772532223,
+STORE, 47572772495360, 47572772515839,
+STORE, 47572772442112, 47572772495359,
+ERASE, 47572772442112, 47572772442112,
+STORE, 47572772442112, 47572772495359,
+STORE, 47572772511744, 47572772515839,
+STORE, 47572772495360, 47572772511743,
+ERASE, 47572772495360, 47572772495360,
+STORE, 47572772495360, 47572772511743,
+STORE, 47572772524032, 47572772532223,
+STORE, 47572772515840, 47572772524031,
+ERASE, 47572772515840, 47572772515840,
+STORE, 47572772515840, 47572772524031,
+ERASE, 47572772524032, 47572772524032,
+STORE, 47572772524032, 47572772532223,
+STORE, 47572772532224, 47572774371327,
+STORE, 47572772671488, 47572774371327,
+STORE, 47572772532224, 47572772671487,
+ERASE, 47572772671488, 47572772671488,
+STORE, 47572772671488, 47572774330367,
+STORE, 47572774330368, 47572774371327,
+STORE, 47572774014976, 47572774330367,
+STORE, 47572772671488, 47572774014975,
+ERASE, 47572772671488, 47572772671488,
+STORE, 47572772671488, 47572774014975,
+STORE, 47572774326272, 47572774330367,
+STORE, 47572774014976, 47572774326271,
+ERASE, 47572774014976, 47572774014976,
+STORE, 47572774014976, 47572774326271,
+STORE, 47572774354944, 47572774371327,
+STORE, 47572774330368, 47572774354943,
+ERASE, 47572774330368, 47572774330368,
+STORE, 47572774330368, 47572774354943,
+ERASE, 47572774354944, 47572774354944,
+STORE, 47572774354944, 47572774371327,
+STORE, 47572774354944, 47572774383615,
+ERASE, 47572774330368, 47572774330368,
+STORE, 47572774330368, 47572774346751,
+STORE, 47572774346752, 47572774354943,
+ERASE, 47572772515840, 47572772515840,
+STORE, 47572772515840, 47572772519935,
+STORE, 47572772519936, 47572772524031,
+ERASE, 94250997219328, 94250997219328,
+STORE, 94250997219328, 94250997235711,
+STORE, 94250997235712, 94250997239807,
+ERASE, 140060022747136, 140060022747136,
+STORE, 140060022747136, 140060022751231,
+STORE, 140060022751232, 140060022755327,
+ERASE, 47572772409344, 47572772409344,
+STORE, 94251018305536, 94251018440703,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730012389376, 140737488351231,
+ERASE, 140730012389376, 140730012389376,
+STORE, 140730012389376, 140730012393471,
+STORE, 94382607675392, 94382607695871,
+ERASE, 94382607675392, 94382607675392,
+STORE, 94382607675392, 94382607679487,
+STORE, 94382607679488, 94382607695871,
+ERASE, 94382607679488, 94382607679488,
+STORE, 94382607679488, 94382607683583,
+STORE, 94382607683584, 94382607687679,
+STORE, 94382607687680, 94382607695871,
+STORE, 140252451454976, 140252451627007,
+ERASE, 140252451454976, 140252451454976,
+STORE, 140252451454976, 140252451459071,
+STORE, 140252451459072, 140252451627007,
+ERASE, 140252451459072, 140252451459072,
+STORE, 140252451459072, 140252451581951,
+STORE, 140252451581952, 140252451614719,
+STORE, 140252451614720, 140252451622911,
+STORE, 140252451622912, 140252451627007,
+STORE, 140730013548544, 140730013552639,
+STORE, 140730013536256, 140730013548543,
+STORE, 47380343541760, 47380343549951,
+STORE, 47380343549952, 47380343558143,
+STORE, 47380343558144, 47380345397247,
+STORE, 47380343697408, 47380345397247,
+STORE, 47380343558144, 47380343697407,
+ERASE, 47380343697408, 47380343697408,
+STORE, 47380343697408, 47380345356287,
+STORE, 47380345356288, 47380345397247,
+STORE, 47380345040896, 47380345356287,
+STORE, 47380343697408, 47380345040895,
+ERASE, 47380343697408, 47380343697408,
+STORE, 47380343697408, 47380345040895,
+STORE, 47380345352192, 47380345356287,
+STORE, 47380345040896, 47380345352191,
+ERASE, 47380345040896, 47380345040896,
+STORE, 47380345040896, 47380345352191,
+STORE, 47380345380864, 47380345397247,
+STORE, 47380345356288, 47380345380863,
+ERASE, 47380345356288, 47380345356288,
+STORE, 47380345356288, 47380345380863,
+ERASE, 47380345380864, 47380345380864,
+STORE, 47380345380864, 47380345397247,
+ERASE, 47380345356288, 47380345356288,
+STORE, 47380345356288, 47380345372671,
+STORE, 47380345372672, 47380345380863,
+ERASE, 94382607687680, 94382607687680,
+STORE, 94382607687680, 94382607691775,
+STORE, 94382607691776, 94382607695871,
+ERASE, 140252451614720, 140252451614720,
+STORE, 140252451614720, 140252451618815,
+STORE, 140252451618816, 140252451622911,
+ERASE, 47380343541760, 47380343541760,
+STORE, 94382626803712, 94382626938879,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730900271104, 140737488351231,
+ERASE, 140730900271104, 140730900271104,
+STORE, 140730900271104, 140730900275199,
+STORE, 93855478120448, 93855478337535,
+ERASE, 93855478120448, 93855478120448,
+STORE, 93855478120448, 93855478198271,
+STORE, 93855478198272, 93855478337535,
+ERASE, 93855478198272, 93855478198272,
+STORE, 93855478198272, 93855478243327,
+STORE, 93855478243328, 93855478288383,
+STORE, 93855478288384, 93855478337535,
+STORE, 140092686573568, 140092686745599,
+ERASE, 140092686573568, 140092686573568,
+STORE, 140092686573568, 140092686577663,
+STORE, 140092686577664, 140092686745599,
+ERASE, 140092686577664, 140092686577664,
+STORE, 140092686577664, 140092686700543,
+STORE, 140092686700544, 140092686733311,
+STORE, 140092686733312, 140092686741503,
+STORE, 140092686741504, 140092686745599,
+STORE, 140730900537344, 140730900541439,
+STORE, 140730900525056, 140730900537343,
+STORE, 47540108423168, 47540108431359,
+STORE, 47540108431360, 47540108439551,
+STORE, 47540108439552, 47540110278655,
+STORE, 47540108578816, 47540110278655,
+STORE, 47540108439552, 47540108578815,
+ERASE, 47540108578816, 47540108578816,
+STORE, 47540108578816, 47540110237695,
+STORE, 47540110237696, 47540110278655,
+STORE, 47540109922304, 47540110237695,
+STORE, 47540108578816, 47540109922303,
+ERASE, 47540108578816, 47540108578816,
+STORE, 47540108578816, 47540109922303,
+STORE, 47540110233600, 47540110237695,
+STORE, 47540109922304, 47540110233599,
+ERASE, 47540109922304, 47540109922304,
+STORE, 47540109922304, 47540110233599,
+STORE, 47540110262272, 47540110278655,
+STORE, 47540110237696, 47540110262271,
+ERASE, 47540110237696, 47540110237696,
+STORE, 47540110237696, 47540110262271,
+ERASE, 47540110262272, 47540110262272,
+STORE, 47540110262272, 47540110278655,
+ERASE, 47540110237696, 47540110237696,
+STORE, 47540110237696, 47540110254079,
+STORE, 47540110254080, 47540110262271,
+ERASE, 93855478288384, 93855478288384,
+STORE, 93855478288384, 93855478333439,
+STORE, 93855478333440, 93855478337535,
+ERASE, 140092686733312, 140092686733312,
+STORE, 140092686733312, 140092686737407,
+STORE, 140092686737408, 140092686741503,
+ERASE, 47540108423168, 47540108423168,
+STORE, 93855492222976, 93855492358143,
+STORE, 93855492222976, 93855492493311,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733498146816, 140737488351231,
+ERASE, 140733498146816, 140733498146816,
+STORE, 140733498146816, 140733498150911,
+STORE, 94170739654656, 94170740367359,
+ERASE, 94170739654656, 94170739654656,
+STORE, 94170739654656, 94170739703807,
+STORE, 94170739703808, 94170740367359,
+ERASE, 94170739703808, 94170739703808,
+STORE, 94170739703808, 94170740248575,
+STORE, 94170740248576, 94170740346879,
+STORE, 94170740346880, 94170740367359,
+STORE, 140024788877312, 140024789049343,
+ERASE, 140024788877312, 140024788877312,
+STORE, 140024788877312, 140024788881407,
+STORE, 140024788881408, 140024789049343,
+ERASE, 140024788881408, 140024788881408,
+STORE, 140024788881408, 140024789004287,
+STORE, 140024789004288, 140024789037055,
+STORE, 140024789037056, 140024789045247,
+STORE, 140024789045248, 140024789049343,
+STORE, 140733499023360, 140733499027455,
+STORE, 140733499011072, 140733499023359,
+STORE, 47608006119424, 47608006127615,
+STORE, 47608006127616, 47608006135807,
+STORE, 47608006135808, 47608006242303,
+STORE, 47608006152192, 47608006242303,
+STORE, 47608006135808, 47608006152191,
+ERASE, 47608006152192, 47608006152192,
+STORE, 47608006152192, 47608006225919,
+STORE, 47608006225920, 47608006242303,
+STORE, 47608006205440, 47608006225919,
+STORE, 47608006152192, 47608006205439,
+ERASE, 47608006152192, 47608006152192,
+STORE, 47608006152192, 47608006205439,
+STORE, 47608006221824, 47608006225919,
+STORE, 47608006205440, 47608006221823,
+ERASE, 47608006205440, 47608006205440,
+STORE, 47608006205440, 47608006221823,
+STORE, 47608006234112, 47608006242303,
+STORE, 47608006225920, 47608006234111,
+ERASE, 47608006225920, 47608006225920,
+STORE, 47608006225920, 47608006234111,
+ERASE, 47608006234112, 47608006234112,
+STORE, 47608006234112, 47608006242303,
+STORE, 47608006242304, 47608008081407,
+STORE, 47608006381568, 47608008081407,
+STORE, 47608006242304, 47608006381567,
+ERASE, 47608006381568, 47608006381568,
+STORE, 47608006381568, 47608008040447,
+STORE, 47608008040448, 47608008081407,
+STORE, 47608007725056, 47608008040447,
+STORE, 47608006381568, 47608007725055,
+ERASE, 47608006381568, 47608006381568,
+STORE, 47608006381568, 47608007725055,
+STORE, 47608008036352, 47608008040447,
+STORE, 47608007725056, 47608008036351,
+ERASE, 47608007725056, 47608007725056,
+STORE, 47608007725056, 47608008036351,
+STORE, 47608008065024, 47608008081407,
+STORE, 47608008040448, 47608008065023,
+ERASE, 47608008040448, 47608008040448,
+STORE, 47608008040448, 47608008065023,
+ERASE, 47608008065024, 47608008065024,
+STORE, 47608008065024, 47608008081407,
+STORE, 47608008065024, 47608008093695,
+ERASE, 47608008040448, 47608008040448,
+STORE, 47608008040448, 47608008056831,
+STORE, 47608008056832, 47608008065023,
+ERASE, 47608006225920, 47608006225920,
+STORE, 47608006225920, 47608006230015,
+STORE, 47608006230016, 47608006234111,
+ERASE, 94170740346880, 94170740346880,
+STORE, 94170740346880, 94170740363263,
+STORE, 94170740363264, 94170740367359,
+ERASE, 140024789037056, 140024789037056,
+STORE, 140024789037056, 140024789041151,
+STORE, 140024789041152, 140024789045247,
+ERASE, 47608006119424, 47608006119424,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730264326144, 140737488351231,
+ERASE, 140730264326144, 140730264326144,
+STORE, 140730264326144, 140730264330239,
+STORE, 94653216407552, 94653217120255,
+ERASE, 94653216407552, 94653216407552,
+STORE, 94653216407552, 94653216456703,
+STORE, 94653216456704, 94653217120255,
+ERASE, 94653216456704, 94653216456704,
+STORE, 94653216456704, 94653217001471,
+STORE, 94653217001472, 94653217099775,
+STORE, 94653217099776, 94653217120255,
+STORE, 140103617011712, 140103617183743,
+ERASE, 140103617011712, 140103617011712,
+STORE, 140103617011712, 140103617015807,
+STORE, 140103617015808, 140103617183743,
+ERASE, 140103617015808, 140103617015808,
+STORE, 140103617015808, 140103617138687,
+STORE, 140103617138688, 140103617171455,
+STORE, 140103617171456, 140103617179647,
+STORE, 140103617179648, 140103617183743,
+STORE, 140730265427968, 140730265432063,
+STORE, 140730265415680, 140730265427967,
+STORE, 47529177985024, 47529177993215,
+STORE, 47529177993216, 47529178001407,
+STORE, 47529178001408, 47529178107903,
+STORE, 47529178017792, 47529178107903,
+STORE, 47529178001408, 47529178017791,
+ERASE, 47529178017792, 47529178017792,
+STORE, 47529178017792, 47529178091519,
+STORE, 47529178091520, 47529178107903,
+STORE, 47529178071040, 47529178091519,
+STORE, 47529178017792, 47529178071039,
+ERASE, 47529178017792, 47529178017792,
+STORE, 47529178017792, 47529178071039,
+STORE, 47529178087424, 47529178091519,
+STORE, 47529178071040, 47529178087423,
+ERASE, 47529178071040, 47529178071040,
+STORE, 47529178071040, 47529178087423,
+STORE, 47529178099712, 47529178107903,
+STORE, 47529178091520, 47529178099711,
+ERASE, 47529178091520, 47529178091520,
+STORE, 47529178091520, 47529178099711,
+ERASE, 47529178099712, 47529178099712,
+STORE, 47529178099712, 47529178107903,
+STORE, 47529178107904, 47529179947007,
+STORE, 47529178247168, 47529179947007,
+STORE, 47529178107904, 47529178247167,
+ERASE, 47529178247168, 47529178247168,
+STORE, 47529178247168, 47529179906047,
+STORE, 47529179906048, 47529179947007,
+STORE, 47529179590656, 47529179906047,
+STORE, 47529178247168, 47529179590655,
+ERASE, 47529178247168, 47529178247168,
+STORE, 47529178247168, 47529179590655,
+STORE, 47529179901952, 47529179906047,
+STORE, 47529179590656, 47529179901951,
+ERASE, 47529179590656, 47529179590656,
+STORE, 47529179590656, 47529179901951,
+STORE, 47529179930624, 47529179947007,
+STORE, 47529179906048, 47529179930623,
+ERASE, 47529179906048, 47529179906048,
+STORE, 47529179906048, 47529179930623,
+ERASE, 47529179930624, 47529179930624,
+STORE, 47529179930624, 47529179947007,
+STORE, 47529179930624, 47529179959295,
+ERASE, 47529179906048, 47529179906048,
+STORE, 47529179906048, 47529179922431,
+STORE, 47529179922432, 47529179930623,
+ERASE, 47529178091520, 47529178091520,
+STORE, 47529178091520, 47529178095615,
+STORE, 47529178095616, 47529178099711,
+ERASE, 94653217099776, 94653217099776,
+STORE, 94653217099776, 94653217116159,
+STORE, 94653217116160, 94653217120255,
+ERASE, 140103617171456, 140103617171456,
+STORE, 140103617171456, 140103617175551,
+STORE, 140103617175552, 140103617179647,
+ERASE, 47529177985024, 47529177985024,
+STORE, 94653241135104, 94653241270271,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736284549120, 140737488351231,
+ERASE, 140736284549120, 140736284549120,
+STORE, 140736284549120, 140736284553215,
+STORE, 93963663822848, 93963664506879,
+ERASE, 93963663822848, 93963663822848,
+STORE, 93963663822848, 93963663884287,
+STORE, 93963663884288, 93963664506879,
+ERASE, 93963663884288, 93963663884288,
+STORE, 93963663884288, 93963664240639,
+STORE, 93963664240640, 93963664379903,
+STORE, 93963664379904, 93963664506879,
+STORE, 140450188439552, 140450188611583,
+ERASE, 140450188439552, 140450188439552,
+STORE, 140450188439552, 140450188443647,
+STORE, 140450188443648, 140450188611583,
+ERASE, 140450188443648, 140450188443648,
+STORE, 140450188443648, 140450188566527,
+STORE, 140450188566528, 140450188599295,
+STORE, 140450188599296, 140450188607487,
+STORE, 140450188607488, 140450188611583,
+STORE, 140736284577792, 140736284581887,
+STORE, 140736284565504, 140736284577791,
+STORE, 47182606557184, 47182606565375,
+STORE, 47182606565376, 47182606573567,
+STORE, 47182606573568, 47182608412671,
+STORE, 47182606712832, 47182608412671,
+STORE, 47182606573568, 47182606712831,
+ERASE, 47182606712832, 47182606712832,
+STORE, 47182606712832, 47182608371711,
+STORE, 47182608371712, 47182608412671,
+STORE, 47182608056320, 47182608371711,
+STORE, 47182606712832, 47182608056319,
+ERASE, 47182606712832, 47182606712832,
+STORE, 47182606712832, 47182608056319,
+STORE, 47182608367616, 47182608371711,
+STORE, 47182608056320, 47182608367615,
+ERASE, 47182608056320, 47182608056320,
+STORE, 47182608056320, 47182608367615,
+STORE, 47182608396288, 47182608412671,
+STORE, 47182608371712, 47182608396287,
+ERASE, 47182608371712, 47182608371712,
+STORE, 47182608371712, 47182608396287,
+ERASE, 47182608396288, 47182608396288,
+STORE, 47182608396288, 47182608412671,
+STORE, 47182608412672, 47182608523263,
+STORE, 47182608429056, 47182608523263,
+STORE, 47182608412672, 47182608429055,
+ERASE, 47182608429056, 47182608429056,
+STORE, 47182608429056, 47182608515071,
+STORE, 47182608515072, 47182608523263,
+STORE, 47182608490496, 47182608515071,
+STORE, 47182608429056, 47182608490495,
+ERASE, 47182608429056, 47182608429056,
+STORE, 47182608429056, 47182608490495,
+STORE, 47182608510976, 47182608515071,
+STORE, 47182608490496, 47182608510975,
+ERASE, 47182608490496, 47182608490496,
+STORE, 47182608490496, 47182608510975,
+ERASE, 47182608515072, 47182608515072,
+STORE, 47182608515072, 47182608523263,
+STORE, 47182608523264, 47182608568319,
+ERASE, 47182608523264, 47182608523264,
+STORE, 47182608523264, 47182608531455,
+STORE, 47182608531456, 47182608568319,
+STORE, 47182608551936, 47182608568319,
+STORE, 47182608531456, 47182608551935,
+ERASE, 47182608531456, 47182608531456,
+STORE, 47182608531456, 47182608551935,
+STORE, 47182608560128, 47182608568319,
+STORE, 47182608551936, 47182608560127,
+ERASE, 47182608551936, 47182608551936,
+STORE, 47182608551936, 47182608568319,
+ERASE, 47182608551936, 47182608551936,
+STORE, 47182608551936, 47182608560127,
+STORE, 47182608560128, 47182608568319,
+ERASE, 47182608560128, 47182608560128,
+STORE, 47182608560128, 47182608568319,
+STORE, 47182608568320, 47182608916479,
+STORE, 47182608609280, 47182608916479,
+STORE, 47182608568320, 47182608609279,
+ERASE, 47182608609280, 47182608609280,
+STORE, 47182608609280, 47182608891903,
+STORE, 47182608891904, 47182608916479,
+STORE, 47182608822272, 47182608891903,
+STORE, 47182608609280, 47182608822271,
+ERASE, 47182608609280, 47182608609280,
+STORE, 47182608609280, 47182608822271,
+STORE, 47182608887808, 47182608891903,
+STORE, 47182608822272, 47182608887807,
+ERASE, 47182608822272, 47182608822272,
+STORE, 47182608822272, 47182608887807,
+ERASE, 47182608891904, 47182608891904,
+STORE, 47182608891904, 47182608916479,
+STORE, 47182608916480, 47182611177471,
+STORE, 47182609068032, 47182611177471,
+STORE, 47182608916480, 47182609068031,
+ERASE, 47182609068032, 47182609068032,
+STORE, 47182609068032, 47182611161087,
+STORE, 47182611161088, 47182611177471,
+STORE, 47182611169280, 47182611177471,
+STORE, 47182611161088, 47182611169279,
+ERASE, 47182611161088, 47182611161088,
+STORE, 47182611161088, 47182611169279,
+ERASE, 47182611169280, 47182611169280,
+STORE, 47182611169280, 47182611177471,
+STORE, 47182611177472, 47182611312639,
+ERASE, 47182611177472, 47182611177472,
+STORE, 47182611177472, 47182611202047,
+STORE, 47182611202048, 47182611312639,
+STORE, 47182611263488, 47182611312639,
+STORE, 47182611202048, 47182611263487,
+ERASE, 47182611202048, 47182611202048,
+STORE, 47182611202048, 47182611263487,
+STORE, 47182611288064, 47182611312639,
+STORE, 47182611263488, 47182611288063,
+ERASE, 47182611263488, 47182611263488,
+STORE, 47182611263488, 47182611312639,
+ERASE, 47182611263488, 47182611263488,
+STORE, 47182611263488, 47182611288063,
+STORE, 47182611288064, 47182611312639,
+STORE, 47182611296256, 47182611312639,
+STORE, 47182611288064, 47182611296255,
+ERASE, 47182611288064, 47182611288064,
+STORE, 47182611288064, 47182611296255,
+ERASE, 47182611296256, 47182611296256,
+STORE, 47182611296256, 47182611312639,
+STORE, 47182611296256, 47182611320831,
+STORE, 47182611320832, 47182611484671,
+ERASE, 47182611320832, 47182611320832,
+STORE, 47182611320832, 47182611333119,
+STORE, 47182611333120, 47182611484671,
+STORE, 47182611431424, 47182611484671,
+STORE, 47182611333120, 47182611431423,
+ERASE, 47182611333120, 47182611333120,
+STORE, 47182611333120, 47182611431423,
+STORE, 47182611476480, 47182611484671,
+STORE, 47182611431424, 47182611476479,
+ERASE, 47182611431424, 47182611431424,
+STORE, 47182611431424, 47182611484671,
+ERASE, 47182611431424, 47182611431424,
+STORE, 47182611431424, 47182611476479,
+STORE, 47182611476480, 47182611484671,
+ERASE, 47182611476480, 47182611476480,
+STORE, 47182611476480, 47182611484671,
+STORE, 47182611484672, 47182612082687,
+STORE, 47182611603456, 47182612082687,
+STORE, 47182611484672, 47182611603455,
+ERASE, 47182611603456, 47182611603456,
+STORE, 47182611603456, 47182612029439,
+STORE, 47182612029440, 47182612082687,
+STORE, 47182611918848, 47182612029439,
+STORE, 47182611603456, 47182611918847,
+ERASE, 47182611603456, 47182611603456,
+STORE, 47182611603456, 47182611918847,
+STORE, 47182612025344, 47182612029439,
+STORE, 47182611918848, 47182612025343,
+ERASE, 47182611918848, 47182611918848,
+STORE, 47182611918848, 47182612025343,
+ERASE, 47182612029440, 47182612029440,
+STORE, 47182612029440, 47182612082687,
+STORE, 47182612082688, 47182615134207,
+STORE, 47182612627456, 47182615134207,
+STORE, 47182612082688, 47182612627455,
+ERASE, 47182612627456, 47182612627456,
+STORE, 47182612627456, 47182614913023,
+STORE, 47182614913024, 47182615134207,
+STORE, 47182614323200, 47182614913023,
+STORE, 47182612627456, 47182614323199,
+ERASE, 47182612627456, 47182612627456,
+STORE, 47182612627456, 47182614323199,
+STORE, 47182614908928, 47182614913023,
+STORE, 47182614323200, 47182614908927,
+ERASE, 47182614323200, 47182614323200,
+STORE, 47182614323200, 47182614908927,
+STORE, 47182615117824, 47182615134207,
+STORE, 47182614913024, 47182615117823,
+ERASE, 47182614913024, 47182614913024,
+STORE, 47182614913024, 47182615117823,
+ERASE, 47182615117824, 47182615117824,
+STORE, 47182615117824, 47182615134207,
+STORE, 47182615134208, 47182615166975,
+ERASE, 47182615134208, 47182615134208,
+STORE, 47182615134208, 47182615142399,
+STORE, 47182615142400, 47182615166975,
+STORE, 47182615154688, 47182615166975,
+STORE, 47182615142400, 47182615154687,
+ERASE, 47182615142400, 47182615142400,
+STORE, 47182615142400, 47182615154687,
+STORE, 47182615158784, 47182615166975,
+STORE, 47182615154688, 47182615158783,
+ERASE, 47182615154688, 47182615154688,
+STORE, 47182615154688, 47182615166975,
+ERASE, 47182615154688, 47182615154688,
+STORE, 47182615154688, 47182615158783,
+STORE, 47182615158784, 47182615166975,
+ERASE, 47182615158784, 47182615158784,
+STORE, 47182615158784, 47182615166975,
+STORE, 47182615166976, 47182615203839,
+ERASE, 47182615166976, 47182615166976,
+STORE, 47182615166976, 47182615175167,
+STORE, 47182615175168, 47182615203839,
+STORE, 47182615191552, 47182615203839,
+STORE, 47182615175168, 47182615191551,
+ERASE, 47182615175168, 47182615175168,
+STORE, 47182615175168, 47182615191551,
+STORE, 47182615195648, 47182615203839,
+STORE, 47182615191552, 47182615195647,
+ERASE, 47182615191552, 47182615191552,
+STORE, 47182615191552, 47182615203839,
+ERASE, 47182615191552, 47182615191552,
+STORE, 47182615191552, 47182615195647,
+STORE, 47182615195648, 47182615203839,
+ERASE, 47182615195648, 47182615195648,
+STORE, 47182615195648, 47182615203839,
+STORE, 47182615203840, 47182615678975,
+ERASE, 47182615203840, 47182615203840,
+STORE, 47182615203840, 47182615212031,
+STORE, 47182615212032, 47182615678975,
+STORE, 47182615547904, 47182615678975,
+STORE, 47182615212032, 47182615547903,
+ERASE, 47182615212032, 47182615212032,
+STORE, 47182615212032, 47182615547903,
+STORE, 47182615670784, 47182615678975,
+STORE, 47182615547904, 47182615670783,
+ERASE, 47182615547904, 47182615547904,
+STORE, 47182615547904, 47182615678975,
+ERASE, 47182615547904, 47182615547904,
+STORE, 47182615547904, 47182615670783,
+STORE, 47182615670784, 47182615678975,
+ERASE, 47182615670784, 47182615670784,
+STORE, 47182615670784, 47182615678975,
+STORE, 47182615678976, 47182615687167,
+STORE, 47182615687168, 47182615707647,
+ERASE, 47182615687168, 47182615687168,
+STORE, 47182615687168, 47182615691263,
+STORE, 47182615691264, 47182615707647,
+STORE, 47182615695360, 47182615707647,
+STORE, 47182615691264, 47182615695359,
+ERASE, 47182615691264, 47182615691264,
+STORE, 47182615691264, 47182615695359,
+STORE, 47182615699456, 47182615707647,
+STORE, 47182615695360, 47182615699455,
+ERASE, 47182615695360, 47182615695360,
+STORE, 47182615695360, 47182615707647,
+ERASE, 47182615695360, 47182615695360,
+STORE, 47182615695360, 47182615699455,
+STORE, 47182615699456, 47182615707647,
+ERASE, 47182615699456, 47182615699456,
+STORE, 47182615699456, 47182615707647,
+STORE, 47182615707648, 47182615715839,
+ERASE, 47182608371712, 47182608371712,
+STORE, 47182608371712, 47182608388095,
+STORE, 47182608388096, 47182608396287,
+ERASE, 47182615699456, 47182615699456,
+STORE, 47182615699456, 47182615703551,
+STORE, 47182615703552, 47182615707647,
+ERASE, 47182611288064, 47182611288064,
+STORE, 47182611288064, 47182611292159,
+STORE, 47182611292160, 47182611296255,
+ERASE, 47182615670784, 47182615670784,
+STORE, 47182615670784, 47182615674879,
+STORE, 47182615674880, 47182615678975,
+ERASE, 47182615195648, 47182615195648,
+STORE, 47182615195648, 47182615199743,
+STORE, 47182615199744, 47182615203839,
+ERASE, 47182615158784, 47182615158784,
+STORE, 47182615158784, 47182615162879,
+STORE, 47182615162880, 47182615166975,
+ERASE, 47182614913024, 47182614913024,
+STORE, 47182614913024, 47182615109631,
+STORE, 47182615109632, 47182615117823,
+ERASE, 47182612029440, 47182612029440,
+STORE, 47182612029440, 47182612066303,
+STORE, 47182612066304, 47182612082687,
+ERASE, 47182611476480, 47182611476480,
+STORE, 47182611476480, 47182611480575,
+STORE, 47182611480576, 47182611484671,
+ERASE, 47182611161088, 47182611161088,
+STORE, 47182611161088, 47182611165183,
+STORE, 47182611165184, 47182611169279,
+ERASE, 47182608891904, 47182608891904,
+STORE, 47182608891904, 47182608912383,
+STORE, 47182608912384, 47182608916479,
+ERASE, 47182608560128, 47182608560128,
+STORE, 47182608560128, 47182608564223,
+STORE, 47182608564224, 47182608568319,
+ERASE, 47182608515072, 47182608515072,
+STORE, 47182608515072, 47182608519167,
+STORE, 47182608519168, 47182608523263,
+ERASE, 93963664379904, 93963664379904,
+STORE, 93963664379904, 93963664502783,
+STORE, 93963664502784, 93963664506879,
+ERASE, 140450188599296, 140450188599296,
+STORE, 140450188599296, 140450188603391,
+STORE, 140450188603392, 140450188607487,
+ERASE, 47182606557184, 47182606557184,
+STORE, 93963694723072, 93963694858239,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730313261056, 140737488351231,
+ERASE, 140730313261056, 140730313261056,
+STORE, 140730313261056, 140730313265151,
+STORE, 94386579017728, 94386579697663,
+ERASE, 94386579017728, 94386579017728,
+STORE, 94386579017728, 94386579083263,
+STORE, 94386579083264, 94386579697663,
+ERASE, 94386579083264, 94386579083264,
+STORE, 94386579083264, 94386579431423,
+STORE, 94386579431424, 94386579570687,
+STORE, 94386579570688, 94386579697663,
+STORE, 140124810838016, 140124811010047,
+ERASE, 140124810838016, 140124810838016,
+STORE, 140124810838016, 140124810842111,
+STORE, 140124810842112, 140124811010047,
+ERASE, 140124810842112, 140124810842112,
+STORE, 140124810842112, 140124810964991,
+STORE, 140124810964992, 140124810997759,
+STORE, 140124810997760, 140124811005951,
+STORE, 140124811005952, 140124811010047,
+STORE, 140730313601024, 140730313605119,
+STORE, 140730313588736, 140730313601023,
+STORE, 47507984158720, 47507984166911,
+STORE, 47507984166912, 47507984175103,
+STORE, 47507984175104, 47507986014207,
+STORE, 47507984314368, 47507986014207,
+STORE, 47507984175104, 47507984314367,
+ERASE, 47507984314368, 47507984314368,
+STORE, 47507984314368, 47507985973247,
+STORE, 47507985973248, 47507986014207,
+STORE, 47507985657856, 47507985973247,
+STORE, 47507984314368, 47507985657855,
+ERASE, 47507984314368, 47507984314368,
+STORE, 47507984314368, 47507985657855,
+STORE, 47507985969152, 47507985973247,
+STORE, 47507985657856, 47507985969151,
+ERASE, 47507985657856, 47507985657856,
+STORE, 47507985657856, 47507985969151,
+STORE, 47507985997824, 47507986014207,
+STORE, 47507985973248, 47507985997823,
+ERASE, 47507985973248, 47507985973248,
+STORE, 47507985973248, 47507985997823,
+ERASE, 47507985997824, 47507985997824,
+STORE, 47507985997824, 47507986014207,
+STORE, 47507986014208, 47507986124799,
+STORE, 47507986030592, 47507986124799,
+STORE, 47507986014208, 47507986030591,
+ERASE, 47507986030592, 47507986030592,
+STORE, 47507986030592, 47507986116607,
+STORE, 47507986116608, 47507986124799,
+STORE, 47507986092032, 47507986116607,
+STORE, 47507986030592, 47507986092031,
+ERASE, 47507986030592, 47507986030592,
+STORE, 47507986030592, 47507986092031,
+STORE, 47507986112512, 47507986116607,
+STORE, 47507986092032, 47507986112511,
+ERASE, 47507986092032, 47507986092032,
+STORE, 47507986092032, 47507986112511,
+ERASE, 47507986116608, 47507986116608,
+STORE, 47507986116608, 47507986124799,
+STORE, 47507986124800, 47507986169855,
+ERASE, 47507986124800, 47507986124800,
+STORE, 47507986124800, 47507986132991,
+STORE, 47507986132992, 47507986169855,
+STORE, 47507986153472, 47507986169855,
+STORE, 47507986132992, 47507986153471,
+ERASE, 47507986132992, 47507986132992,
+STORE, 47507986132992, 47507986153471,
+STORE, 47507986161664, 47507986169855,
+STORE, 47507986153472, 47507986161663,
+ERASE, 47507986153472, 47507986153472,
+STORE, 47507986153472, 47507986169855,
+ERASE, 47507986153472, 47507986153472,
+STORE, 47507986153472, 47507986161663,
+STORE, 47507986161664, 47507986169855,
+ERASE, 47507986161664, 47507986161664,
+STORE, 47507986161664, 47507986169855,
+STORE, 47507986169856, 47507986518015,
+STORE, 47507986210816, 47507986518015,
+STORE, 47507986169856, 47507986210815,
+ERASE, 47507986210816, 47507986210816,
+STORE, 47507986210816, 47507986493439,
+STORE, 47507986493440, 47507986518015,
+STORE, 47507986423808, 47507986493439,
+STORE, 47507986210816, 47507986423807,
+ERASE, 47507986210816, 47507986210816,
+STORE, 47507986210816, 47507986423807,
+STORE, 47507986489344, 47507986493439,
+STORE, 47507986423808, 47507986489343,
+ERASE, 47507986423808, 47507986423808,
+STORE, 47507986423808, 47507986489343,
+ERASE, 47507986493440, 47507986493440,
+STORE, 47507986493440, 47507986518015,
+STORE, 47507986518016, 47507988779007,
+STORE, 47507986669568, 47507988779007,
+STORE, 47507986518016, 47507986669567,
+ERASE, 47507986669568, 47507986669568,
+STORE, 47507986669568, 47507988762623,
+STORE, 47507988762624, 47507988779007,
+STORE, 47507988770816, 47507988779007,
+STORE, 47507988762624, 47507988770815,
+ERASE, 47507988762624, 47507988762624,
+STORE, 47507988762624, 47507988770815,
+ERASE, 47507988770816, 47507988770816,
+STORE, 47507988770816, 47507988779007,
+STORE, 47507988779008, 47507988914175,
+ERASE, 47507988779008, 47507988779008,
+STORE, 47507988779008, 47507988803583,
+STORE, 47507988803584, 47507988914175,
+STORE, 47507988865024, 47507988914175,
+STORE, 47507988803584, 47507988865023,
+ERASE, 47507988803584, 47507988803584,
+STORE, 47507988803584, 47507988865023,
+STORE, 47507988889600, 47507988914175,
+STORE, 47507988865024, 47507988889599,
+ERASE, 47507988865024, 47507988865024,
+STORE, 47507988865024, 47507988914175,
+ERASE, 47507988865024, 47507988865024,
+STORE, 47507988865024, 47507988889599,
+STORE, 47507988889600, 47507988914175,
+STORE, 47507988897792, 47507988914175,
+STORE, 47507988889600, 47507988897791,
+ERASE, 47507988889600, 47507988889600,
+STORE, 47507988889600, 47507988897791,
+ERASE, 47507988897792, 47507988897792,
+STORE, 47507988897792, 47507988914175,
+STORE, 47507988897792, 47507988922367,
+STORE, 47507988922368, 47507989086207,
+ERASE, 47507988922368, 47507988922368,
+STORE, 47507988922368, 47507988934655,
+STORE, 47507988934656, 47507989086207,
+STORE, 47507989032960, 47507989086207,
+STORE, 47507988934656, 47507989032959,
+ERASE, 47507988934656, 47507988934656,
+STORE, 47507988934656, 47507989032959,
+STORE, 47507989078016, 47507989086207,
+STORE, 47507989032960, 47507989078015,
+ERASE, 47507989032960, 47507989032960,
+STORE, 47507989032960, 47507989086207,
+ERASE, 47507989032960, 47507989032960,
+STORE, 47507989032960, 47507989078015,
+STORE, 47507989078016, 47507989086207,
+ERASE, 47507989078016, 47507989078016,
+STORE, 47507989078016, 47507989086207,
+STORE, 47507989086208, 47507989684223,
+STORE, 47507989204992, 47507989684223,
+STORE, 47507989086208, 47507989204991,
+ERASE, 47507989204992, 47507989204992,
+STORE, 47507989204992, 47507989630975,
+STORE, 47507989630976, 47507989684223,
+STORE, 47507989520384, 47507989630975,
+STORE, 47507989204992, 47507989520383,
+ERASE, 47507989204992, 47507989204992,
+STORE, 47507989204992, 47507989520383,
+STORE, 47507989626880, 47507989630975,
+STORE, 47507989520384, 47507989626879,
+ERASE, 47507989520384, 47507989520384,
+STORE, 47507989520384, 47507989626879,
+ERASE, 47507989630976, 47507989630976,
+STORE, 47507989630976, 47507989684223,
+STORE, 47507989684224, 47507992735743,
+STORE, 47507990228992, 47507992735743,
+STORE, 47507989684224, 47507990228991,
+ERASE, 47507990228992, 47507990228992,
+STORE, 47507990228992, 47507992514559,
+STORE, 47507992514560, 47507992735743,
+STORE, 47507991924736, 47507992514559,
+STORE, 47507990228992, 47507991924735,
+ERASE, 47507990228992, 47507990228992,
+STORE, 47507990228992, 47507991924735,
+STORE, 47507992510464, 47507992514559,
+STORE, 47507991924736, 47507992510463,
+ERASE, 47507991924736, 47507991924736,
+STORE, 47507991924736, 47507992510463,
+STORE, 47507992719360, 47507992735743,
+STORE, 47507992514560, 47507992719359,
+ERASE, 47507992514560, 47507992514560,
+STORE, 47507992514560, 47507992719359,
+ERASE, 47507992719360, 47507992719360,
+STORE, 47507992719360, 47507992735743,
+STORE, 47507992735744, 47507992768511,
+ERASE, 47507992735744, 47507992735744,
+STORE, 47507992735744, 47507992743935,
+STORE, 47507992743936, 47507992768511,
+STORE, 47507992756224, 47507992768511,
+STORE, 47507992743936, 47507992756223,
+ERASE, 47507992743936, 47507992743936,
+STORE, 47507992743936, 47507992756223,
+STORE, 47507992760320, 47507992768511,
+STORE, 47507992756224, 47507992760319,
+ERASE, 47507992756224, 47507992756224,
+STORE, 47507992756224, 47507992768511,
+ERASE, 47507992756224, 47507992756224,
+STORE, 47507992756224, 47507992760319,
+STORE, 47507992760320, 47507992768511,
+ERASE, 47507992760320, 47507992760320,
+STORE, 47507992760320, 47507992768511,
+STORE, 47507992768512, 47507992805375,
+ERASE, 47507992768512, 47507992768512,
+STORE, 47507992768512, 47507992776703,
+STORE, 47507992776704, 47507992805375,
+STORE, 47507992793088, 47507992805375,
+STORE, 47507992776704, 47507992793087,
+ERASE, 47507992776704, 47507992776704,
+STORE, 47507992776704, 47507992793087,
+STORE, 47507992797184, 47507992805375,
+STORE, 47507992793088, 47507992797183,
+ERASE, 47507992793088, 47507992793088,
+STORE, 47507992793088, 47507992805375,
+ERASE, 47507992793088, 47507992793088,
+STORE, 47507992793088, 47507992797183,
+STORE, 47507992797184, 47507992805375,
+ERASE, 47507992797184, 47507992797184,
+STORE, 47507992797184, 47507992805375,
+STORE, 47507992805376, 47507993280511,
+ERASE, 47507992805376, 47507992805376,
+STORE, 47507992805376, 47507992813567,
+STORE, 47507992813568, 47507993280511,
+STORE, 47507993149440, 47507993280511,
+STORE, 47507992813568, 47507993149439,
+ERASE, 47507992813568, 47507992813568,
+STORE, 47507992813568, 47507993149439,
+STORE, 47507993272320, 47507993280511,
+STORE, 47507993149440, 47507993272319,
+ERASE, 47507993149440, 47507993149440,
+STORE, 47507993149440, 47507993280511,
+ERASE, 47507993149440, 47507993149440,
+STORE, 47507993149440, 47507993272319,
+STORE, 47507993272320, 47507993280511,
+ERASE, 47507993272320, 47507993272320,
+STORE, 47507993272320, 47507993280511,
+STORE, 47507993280512, 47507993288703,
+STORE, 47507993288704, 47507993309183,
+ERASE, 47507993288704, 47507993288704,
+STORE, 47507993288704, 47507993292799,
+STORE, 47507993292800, 47507993309183,
+STORE, 47507993296896, 47507993309183,
+STORE, 47507993292800, 47507993296895,
+ERASE, 47507993292800, 47507993292800,
+STORE, 47507993292800, 47507993296895,
+STORE, 47507993300992, 47507993309183,
+STORE, 47507993296896, 47507993300991,
+ERASE, 47507993296896, 47507993296896,
+STORE, 47507993296896, 47507993309183,
+ERASE, 47507993296896, 47507993296896,
+STORE, 47507993296896, 47507993300991,
+STORE, 47507993300992, 47507993309183,
+ERASE, 47507993300992, 47507993300992,
+STORE, 47507993300992, 47507993309183,
+STORE, 47507993309184, 47507993317375,
+ERASE, 47507985973248, 47507985973248,
+STORE, 47507985973248, 47507985989631,
+STORE, 47507985989632, 47507985997823,
+ERASE, 47507993300992, 47507993300992,
+STORE, 47507993300992, 47507993305087,
+STORE, 47507993305088, 47507993309183,
+ERASE, 47507988889600, 47507988889600,
+STORE, 47507988889600, 47507988893695,
+STORE, 47507988893696, 47507988897791,
+ERASE, 47507993272320, 47507993272320,
+STORE, 47507993272320, 47507993276415,
+STORE, 47507993276416, 47507993280511,
+ERASE, 47507992797184, 47507992797184,
+STORE, 47507992797184, 47507992801279,
+STORE, 47507992801280, 47507992805375,
+ERASE, 47507992760320, 47507992760320,
+STORE, 47507992760320, 47507992764415,
+STORE, 47507992764416, 47507992768511,
+ERASE, 47507992514560, 47507992514560,
+STORE, 47507992514560, 47507992711167,
+STORE, 47507992711168, 47507992719359,
+ERASE, 47507989630976, 47507989630976,
+STORE, 47507989630976, 47507989667839,
+STORE, 47507989667840, 47507989684223,
+ERASE, 47507989078016, 47507989078016,
+STORE, 47507989078016, 47507989082111,
+STORE, 47507989082112, 47507989086207,
+ERASE, 47507988762624, 47507988762624,
+STORE, 47507988762624, 47507988766719,
+STORE, 47507988766720, 47507988770815,
+ERASE, 47507986493440, 47507986493440,
+STORE, 47507986493440, 47507986513919,
+STORE, 47507986513920, 47507986518015,
+ERASE, 47507986161664, 47507986161664,
+STORE, 47507986161664, 47507986165759,
+STORE, 47507986165760, 47507986169855,
+ERASE, 47507986116608, 47507986116608,
+STORE, 47507986116608, 47507986120703,
+STORE, 47507986120704, 47507986124799,
+ERASE, 94386579570688, 94386579570688,
+STORE, 94386579570688, 94386579693567,
+STORE, 94386579693568, 94386579697663,
+ERASE, 140124810997760, 140124810997760,
+STORE, 140124810997760, 140124811001855,
+STORE, 140124811001856, 140124811005951,
+ERASE, 47507984158720, 47507984158720,
+STORE, 94386583982080, 94386584117247,
+STORE, 94386583982080, 94386584256511,
+ERASE, 94386583982080, 94386583982080,
+STORE, 94386583982080, 94386584223743,
+STORE, 94386584223744, 94386584256511,
+ERASE, 94386584223744, 94386584223744,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733763395584, 140737488351231,
+ERASE, 140733763395584, 140733763395584,
+STORE, 140733763395584, 140733763399679,
+STORE, 94011546472448, 94011547152383,
+ERASE, 94011546472448, 94011546472448,
+STORE, 94011546472448, 94011546537983,
+STORE, 94011546537984, 94011547152383,
+ERASE, 94011546537984, 94011546537984,
+STORE, 94011546537984, 94011546886143,
+STORE, 94011546886144, 94011547025407,
+STORE, 94011547025408, 94011547152383,
+STORE, 139757597949952, 139757598121983,
+ERASE, 139757597949952, 139757597949952,
+STORE, 139757597949952, 139757597954047,
+STORE, 139757597954048, 139757598121983,
+ERASE, 139757597954048, 139757597954048,
+STORE, 139757597954048, 139757598076927,
+STORE, 139757598076928, 139757598109695,
+STORE, 139757598109696, 139757598117887,
+STORE, 139757598117888, 139757598121983,
+STORE, 140733763596288, 140733763600383,
+STORE, 140733763584000, 140733763596287,
+STORE, 47875197046784, 47875197054975,
+STORE, 47875197054976, 47875197063167,
+STORE, 47875197063168, 47875198902271,
+STORE, 47875197202432, 47875198902271,
+STORE, 47875197063168, 47875197202431,
+ERASE, 47875197202432, 47875197202432,
+STORE, 47875197202432, 47875198861311,
+STORE, 47875198861312, 47875198902271,
+STORE, 47875198545920, 47875198861311,
+STORE, 47875197202432, 47875198545919,
+ERASE, 47875197202432, 47875197202432,
+STORE, 47875197202432, 47875198545919,
+STORE, 47875198857216, 47875198861311,
+STORE, 47875198545920, 47875198857215,
+ERASE, 47875198545920, 47875198545920,
+STORE, 47875198545920, 47875198857215,
+STORE, 47875198885888, 47875198902271,
+STORE, 47875198861312, 47875198885887,
+ERASE, 47875198861312, 47875198861312,
+STORE, 47875198861312, 47875198885887,
+ERASE, 47875198885888, 47875198885888,
+STORE, 47875198885888, 47875198902271,
+STORE, 47875198902272, 47875199012863,
+STORE, 47875198918656, 47875199012863,
+STORE, 47875198902272, 47875198918655,
+ERASE, 47875198918656, 47875198918656,
+STORE, 47875198918656, 47875199004671,
+STORE, 47875199004672, 47875199012863,
+STORE, 47875198980096, 47875199004671,
+STORE, 47875198918656, 47875198980095,
+ERASE, 47875198918656, 47875198918656,
+STORE, 47875198918656, 47875198980095,
+STORE, 47875199000576, 47875199004671,
+STORE, 47875198980096, 47875199000575,
+ERASE, 47875198980096, 47875198980096,
+STORE, 47875198980096, 47875199000575,
+ERASE, 47875199004672, 47875199004672,
+STORE, 47875199004672, 47875199012863,
+STORE, 47875199012864, 47875199057919,
+ERASE, 47875199012864, 47875199012864,
+STORE, 47875199012864, 47875199021055,
+STORE, 47875199021056, 47875199057919,
+STORE, 47875199041536, 47875199057919,
+STORE, 47875199021056, 47875199041535,
+ERASE, 47875199021056, 47875199021056,
+STORE, 47875199021056, 47875199041535,
+STORE, 47875199049728, 47875199057919,
+STORE, 47875199041536, 47875199049727,
+ERASE, 47875199041536, 47875199041536,
+STORE, 47875199041536, 47875199057919,
+ERASE, 47875199041536, 47875199041536,
+STORE, 47875199041536, 47875199049727,
+STORE, 47875199049728, 47875199057919,
+ERASE, 47875199049728, 47875199049728,
+STORE, 47875199049728, 47875199057919,
+STORE, 47875199057920, 47875199406079,
+STORE, 47875199098880, 47875199406079,
+STORE, 47875199057920, 47875199098879,
+ERASE, 47875199098880, 47875199098880,
+STORE, 47875199098880, 47875199381503,
+STORE, 47875199381504, 47875199406079,
+STORE, 47875199311872, 47875199381503,
+STORE, 47875199098880, 47875199311871,
+ERASE, 47875199098880, 47875199098880,
+STORE, 47875199098880, 47875199311871,
+STORE, 47875199377408, 47875199381503,
+STORE, 47875199311872, 47875199377407,
+ERASE, 47875199311872, 47875199311872,
+STORE, 47875199311872, 47875199377407,
+ERASE, 47875199381504, 47875199381504,
+STORE, 47875199381504, 47875199406079,
+STORE, 47875199406080, 47875201667071,
+STORE, 47875199557632, 47875201667071,
+STORE, 47875199406080, 47875199557631,
+ERASE, 47875199557632, 47875199557632,
+STORE, 47875199557632, 47875201650687,
+STORE, 47875201650688, 47875201667071,
+STORE, 47875201658880, 47875201667071,
+STORE, 47875201650688, 47875201658879,
+ERASE, 47875201650688, 47875201650688,
+STORE, 47875201650688, 47875201658879,
+ERASE, 47875201658880, 47875201658880,
+STORE, 47875201658880, 47875201667071,
+STORE, 47875201667072, 47875201802239,
+ERASE, 47875201667072, 47875201667072,
+STORE, 47875201667072, 47875201691647,
+STORE, 47875201691648, 47875201802239,
+STORE, 47875201753088, 47875201802239,
+STORE, 47875201691648, 47875201753087,
+ERASE, 47875201691648, 47875201691648,
+STORE, 47875201691648, 47875201753087,
+STORE, 47875201777664, 47875201802239,
+STORE, 47875201753088, 47875201777663,
+ERASE, 47875201753088, 47875201753088,
+STORE, 47875201753088, 47875201802239,
+ERASE, 47875201753088, 47875201753088,
+STORE, 47875201753088, 47875201777663,
+STORE, 47875201777664, 47875201802239,
+STORE, 47875201785856, 47875201802239,
+STORE, 47875201777664, 47875201785855,
+ERASE, 47875201777664, 47875201777664,
+STORE, 47875201777664, 47875201785855,
+ERASE, 47875201785856, 47875201785856,
+STORE, 47875201785856, 47875201802239,
+STORE, 47875201785856, 47875201810431,
+STORE, 47875201810432, 47875201974271,
+ERASE, 47875201810432, 47875201810432,
+STORE, 47875201810432, 47875201822719,
+STORE, 47875201822720, 47875201974271,
+STORE, 47875201921024, 47875201974271,
+STORE, 47875201822720, 47875201921023,
+ERASE, 47875201822720, 47875201822720,
+STORE, 47875201822720, 47875201921023,
+STORE, 47875201966080, 47875201974271,
+STORE, 47875201921024, 47875201966079,
+ERASE, 47875201921024, 47875201921024,
+STORE, 47875201921024, 47875201974271,
+ERASE, 47875201921024, 47875201921024,
+STORE, 47875201921024, 47875201966079,
+STORE, 47875201966080, 47875201974271,
+ERASE, 47875201966080, 47875201966080,
+STORE, 47875201966080, 47875201974271,
+STORE, 47875201974272, 47875202572287,
+STORE, 47875202093056, 47875202572287,
+STORE, 47875201974272, 47875202093055,
+ERASE, 47875202093056, 47875202093056,
+STORE, 47875202093056, 47875202519039,
+STORE, 47875202519040, 47875202572287,
+STORE, 47875202408448, 47875202519039,
+STORE, 47875202093056, 47875202408447,
+ERASE, 47875202093056, 47875202093056,
+STORE, 47875202093056, 47875202408447,
+STORE, 47875202514944, 47875202519039,
+STORE, 47875202408448, 47875202514943,
+ERASE, 47875202408448, 47875202408448,
+STORE, 47875202408448, 47875202514943,
+ERASE, 47875202519040, 47875202519040,
+STORE, 47875202519040, 47875202572287,
+STORE, 47875202572288, 47875205623807,
+STORE, 47875203117056, 47875205623807,
+STORE, 47875202572288, 47875203117055,
+ERASE, 47875203117056, 47875203117056,
+STORE, 47875203117056, 47875205402623,
+STORE, 47875205402624, 47875205623807,
+STORE, 47875204812800, 47875205402623,
+STORE, 47875203117056, 47875204812799,
+ERASE, 47875203117056, 47875203117056,
+STORE, 47875203117056, 47875204812799,
+STORE, 47875205398528, 47875205402623,
+STORE, 47875204812800, 47875205398527,
+ERASE, 47875204812800, 47875204812800,
+STORE, 47875204812800, 47875205398527,
+STORE, 47875205607424, 47875205623807,
+STORE, 47875205402624, 47875205607423,
+ERASE, 47875205402624, 47875205402624,
+STORE, 47875205402624, 47875205607423,
+ERASE, 47875205607424, 47875205607424,
+STORE, 47875205607424, 47875205623807,
+STORE, 47875205623808, 47875205656575,
+ERASE, 47875205623808, 47875205623808,
+STORE, 47875205623808, 47875205631999,
+STORE, 47875205632000, 47875205656575,
+STORE, 47875205644288, 47875205656575,
+STORE, 47875205632000, 47875205644287,
+ERASE, 47875205632000, 47875205632000,
+STORE, 47875205632000, 47875205644287,
+STORE, 47875205648384, 47875205656575,
+STORE, 47875205644288, 47875205648383,
+ERASE, 47875205644288, 47875205644288,
+STORE, 47875205644288, 47875205656575,
+ERASE, 47875205644288, 47875205644288,
+STORE, 47875205644288, 47875205648383,
+STORE, 47875205648384, 47875205656575,
+ERASE, 47875205648384, 47875205648384,
+STORE, 47875205648384, 47875205656575,
+STORE, 47875205656576, 47875205693439,
+ERASE, 47875205656576, 47875205656576,
+STORE, 47875205656576, 47875205664767,
+STORE, 47875205664768, 47875205693439,
+STORE, 47875205681152, 47875205693439,
+STORE, 47875205664768, 47875205681151,
+ERASE, 47875205664768, 47875205664768,
+STORE, 47875205664768, 47875205681151,
+STORE, 47875205685248, 47875205693439,
+STORE, 47875205681152, 47875205685247,
+ERASE, 47875205681152, 47875205681152,
+STORE, 47875205681152, 47875205693439,
+ERASE, 47875205681152, 47875205681152,
+STORE, 47875205681152, 47875205685247,
+STORE, 47875205685248, 47875205693439,
+ERASE, 47875205685248, 47875205685248,
+STORE, 47875205685248, 47875205693439,
+STORE, 47875205693440, 47875206168575,
+ERASE, 47875205693440, 47875205693440,
+STORE, 47875205693440, 47875205701631,
+STORE, 47875205701632, 47875206168575,
+STORE, 47875206037504, 47875206168575,
+STORE, 47875205701632, 47875206037503,
+ERASE, 47875205701632, 47875205701632,
+STORE, 47875205701632, 47875206037503,
+STORE, 47875206160384, 47875206168575,
+STORE, 47875206037504, 47875206160383,
+ERASE, 47875206037504, 47875206037504,
+STORE, 47875206037504, 47875206168575,
+ERASE, 47875206037504, 47875206037504,
+STORE, 47875206037504, 47875206160383,
+STORE, 47875206160384, 47875206168575,
+ERASE, 47875206160384, 47875206160384,
+STORE, 47875206160384, 47875206168575,
+STORE, 47875206168576, 47875206176767,
+STORE, 47875206176768, 47875206197247,
+ERASE, 47875206176768, 47875206176768,
+STORE, 47875206176768, 47875206180863,
+STORE, 47875206180864, 47875206197247,
+STORE, 47875206184960, 47875206197247,
+STORE, 47875206180864, 47875206184959,
+ERASE, 47875206180864, 47875206180864,
+STORE, 47875206180864, 47875206184959,
+STORE, 47875206189056, 47875206197247,
+STORE, 47875206184960, 47875206189055,
+ERASE, 47875206184960, 47875206184960,
+STORE, 47875206184960, 47875206197247,
+ERASE, 47875206184960, 47875206184960,
+STORE, 47875206184960, 47875206189055,
+STORE, 47875206189056, 47875206197247,
+ERASE, 47875206189056, 47875206189056,
+STORE, 47875206189056, 47875206197247,
+STORE, 47875206197248, 47875206205439,
+ERASE, 47875198861312, 47875198861312,
+STORE, 47875198861312, 47875198877695,
+STORE, 47875198877696, 47875198885887,
+ERASE, 47875206189056, 47875206189056,
+STORE, 47875206189056, 47875206193151,
+STORE, 47875206193152, 47875206197247,
+ERASE, 47875201777664, 47875201777664,
+STORE, 47875201777664, 47875201781759,
+STORE, 47875201781760, 47875201785855,
+ERASE, 47875206160384, 47875206160384,
+STORE, 47875206160384, 47875206164479,
+STORE, 47875206164480, 47875206168575,
+ERASE, 47875205685248, 47875205685248,
+STORE, 47875205685248, 47875205689343,
+STORE, 47875205689344, 47875205693439,
+ERASE, 47875205648384, 47875205648384,
+STORE, 47875205648384, 47875205652479,
+STORE, 47875205652480, 47875205656575,
+ERASE, 47875205402624, 47875205402624,
+STORE, 47875205402624, 47875205599231,
+STORE, 47875205599232, 47875205607423,
+ERASE, 47875202519040, 47875202519040,
+STORE, 47875202519040, 47875202555903,
+STORE, 47875202555904, 47875202572287,
+ERASE, 47875201966080, 47875201966080,
+STORE, 47875201966080, 47875201970175,
+STORE, 47875201970176, 47875201974271,
+ERASE, 47875201650688, 47875201650688,
+STORE, 47875201650688, 47875201654783,
+STORE, 47875201654784, 47875201658879,
+ERASE, 47875199381504, 47875199381504,
+STORE, 47875199381504, 47875199401983,
+STORE, 47875199401984, 47875199406079,
+ERASE, 47875199049728, 47875199049728,
+STORE, 47875199049728, 47875199053823,
+STORE, 47875199053824, 47875199057919,
+ERASE, 47875199004672, 47875199004672,
+STORE, 47875199004672, 47875199008767,
+STORE, 47875199008768, 47875199012863,
+ERASE, 94011547025408, 94011547025408,
+STORE, 94011547025408, 94011547148287,
+STORE, 94011547148288, 94011547152383,
+ERASE, 139757598109696, 139757598109696,
+STORE, 139757598109696, 139757598113791,
+STORE, 139757598113792, 139757598117887,
+ERASE, 47875197046784, 47875197046784,
+STORE, 94011557584896, 94011557720063,
+STORE, 94011557584896, 94011557855231,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557851135,
+STORE, 94011557851136, 94011557855231,
+ERASE, 94011557851136, 94011557851136,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557847039,
+STORE, 94011557847040, 94011557851135,
+ERASE, 94011557847040, 94011557847040,
+STORE, 94011557584896, 94011557982207,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557978111,
+STORE, 94011557978112, 94011557982207,
+ERASE, 94011557978112, 94011557978112,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557974015,
+STORE, 94011557974016, 94011557978111,
+ERASE, 94011557974016, 94011557974016,
+STORE, 140737488347136, 140737488351231,
+STORE, 140734130360320, 140737488351231,
+ERASE, 140734130360320, 140734130360320,
+STORE, 140734130360320, 140734130364415,
+STORE, 94641232105472, 94641232785407,
+ERASE, 94641232105472, 94641232105472,
+STORE, 94641232105472, 94641232171007,
+STORE, 94641232171008, 94641232785407,
+ERASE, 94641232171008, 94641232171008,
+STORE, 94641232171008, 94641232519167,
+STORE, 94641232519168, 94641232658431,
+STORE, 94641232658432, 94641232785407,
+STORE, 139726599516160, 139726599688191,
+ERASE, 139726599516160, 139726599516160,
+STORE, 139726599516160, 139726599520255,
+STORE, 139726599520256, 139726599688191,
+ERASE, 139726599520256, 139726599520256,
+STORE, 139726599520256, 139726599643135,
+STORE, 139726599643136, 139726599675903,
+STORE, 139726599675904, 139726599684095,
+STORE, 139726599684096, 139726599688191,
+STORE, 140734130446336, 140734130450431,
+STORE, 140734130434048, 140734130446335,
+STORE, 47906195480576, 47906195488767,
+STORE, 47906195488768, 47906195496959,
+STORE, 47906195496960, 47906197336063,
+STORE, 47906195636224, 47906197336063,
+STORE, 47906195496960, 47906195636223,
+ERASE, 47906195636224, 47906195636224,
+STORE, 47906195636224, 47906197295103,
+STORE, 47906197295104, 47906197336063,
+STORE, 47906196979712, 47906197295103,
+STORE, 47906195636224, 47906196979711,
+ERASE, 47906195636224, 47906195636224,
+STORE, 47906195636224, 47906196979711,
+STORE, 47906197291008, 47906197295103,
+STORE, 47906196979712, 47906197291007,
+ERASE, 47906196979712, 47906196979712,
+STORE, 47906196979712, 47906197291007,
+STORE, 47906197319680, 47906197336063,
+STORE, 47906197295104, 47906197319679,
+ERASE, 47906197295104, 47906197295104,
+STORE, 47906197295104, 47906197319679,
+ERASE, 47906197319680, 47906197319680,
+STORE, 47906197319680, 47906197336063,
+STORE, 47906197336064, 47906197446655,
+STORE, 47906197352448, 47906197446655,
+STORE, 47906197336064, 47906197352447,
+ERASE, 47906197352448, 47906197352448,
+STORE, 47906197352448, 47906197438463,
+STORE, 47906197438464, 47906197446655,
+STORE, 47906197413888, 47906197438463,
+STORE, 47906197352448, 47906197413887,
+ERASE, 47906197352448, 47906197352448,
+STORE, 47906197352448, 47906197413887,
+STORE, 47906197434368, 47906197438463,
+STORE, 47906197413888, 47906197434367,
+ERASE, 47906197413888, 47906197413888,
+STORE, 47906197413888, 47906197434367,
+ERASE, 47906197438464, 47906197438464,
+STORE, 47906197438464, 47906197446655,
+STORE, 47906197446656, 47906197491711,
+ERASE, 47906197446656, 47906197446656,
+STORE, 47906197446656, 47906197454847,
+STORE, 47906197454848, 47906197491711,
+STORE, 47906197475328, 47906197491711,
+STORE, 47906197454848, 47906197475327,
+ERASE, 47906197454848, 47906197454848,
+STORE, 47906197454848, 47906197475327,
+STORE, 47906197483520, 47906197491711,
+STORE, 47906197475328, 47906197483519,
+ERASE, 47906197475328, 47906197475328,
+STORE, 47906197475328, 47906197491711,
+ERASE, 47906197475328, 47906197475328,
+STORE, 47906197475328, 47906197483519,
+STORE, 47906197483520, 47906197491711,
+ERASE, 47906197483520, 47906197483520,
+STORE, 47906197483520, 47906197491711,
+STORE, 47906197491712, 47906197839871,
+STORE, 47906197532672, 47906197839871,
+STORE, 47906197491712, 47906197532671,
+ERASE, 47906197532672, 47906197532672,
+STORE, 47906197532672, 47906197815295,
+STORE, 47906197815296, 47906197839871,
+STORE, 47906197745664, 47906197815295,
+STORE, 47906197532672, 47906197745663,
+ERASE, 47906197532672, 47906197532672,
+STORE, 47906197532672, 47906197745663,
+STORE, 47906197811200, 47906197815295,
+STORE, 47906197745664, 47906197811199,
+ERASE, 47906197745664, 47906197745664,
+STORE, 47906197745664, 47906197811199,
+ERASE, 47906197815296, 47906197815296,
+STORE, 47906197815296, 47906197839871,
+STORE, 47906197839872, 47906200100863,
+STORE, 47906197991424, 47906200100863,
+STORE, 47906197839872, 47906197991423,
+ERASE, 47906197991424, 47906197991424,
+STORE, 47906197991424, 47906200084479,
+STORE, 47906200084480, 47906200100863,
+STORE, 47906200092672, 47906200100863,
+STORE, 47906200084480, 47906200092671,
+ERASE, 47906200084480, 47906200084480,
+STORE, 47906200084480, 47906200092671,
+ERASE, 47906200092672, 47906200092672,
+STORE, 47906200092672, 47906200100863,
+STORE, 47906200100864, 47906200236031,
+ERASE, 47906200100864, 47906200100864,
+STORE, 47906200100864, 47906200125439,
+STORE, 47906200125440, 47906200236031,
+STORE, 47906200186880, 47906200236031,
+STORE, 47906200125440, 47906200186879,
+ERASE, 47906200125440, 47906200125440,
+STORE, 47906200125440, 47906200186879,
+STORE, 47906200211456, 47906200236031,
+STORE, 47906200186880, 47906200211455,
+ERASE, 47906200186880, 47906200186880,
+STORE, 47906200186880, 47906200236031,
+ERASE, 47906200186880, 47906200186880,
+STORE, 47906200186880, 47906200211455,
+STORE, 47906200211456, 47906200236031,
+STORE, 47906200219648, 47906200236031,
+STORE, 47906200211456, 47906200219647,
+ERASE, 47906200211456, 47906200211456,
+STORE, 47906200211456, 47906200219647,
+ERASE, 47906200219648, 47906200219648,
+STORE, 47906200219648, 47906200236031,
+STORE, 47906200219648, 47906200244223,
+STORE, 47906200244224, 47906200408063,
+ERASE, 47906200244224, 47906200244224,
+STORE, 47906200244224, 47906200256511,
+STORE, 47906200256512, 47906200408063,
+STORE, 47906200354816, 47906200408063,
+STORE, 47906200256512, 47906200354815,
+ERASE, 47906200256512, 47906200256512,
+STORE, 47906200256512, 47906200354815,
+STORE, 47906200399872, 47906200408063,
+STORE, 47906200354816, 47906200399871,
+ERASE, 47906200354816, 47906200354816,
+STORE, 47906200354816, 47906200408063,
+ERASE, 47906200354816, 47906200354816,
+STORE, 47906200354816, 47906200399871,
+STORE, 47906200399872, 47906200408063,
+ERASE, 47906200399872, 47906200399872,
+STORE, 47906200399872, 47906200408063,
+STORE, 47906200408064, 47906201006079,
+STORE, 47906200526848, 47906201006079,
+STORE, 47906200408064, 47906200526847,
+ERASE, 47906200526848, 47906200526848,
+STORE, 47906200526848, 47906200952831,
+STORE, 47906200952832, 47906201006079,
+STORE, 47906200842240, 47906200952831,
+STORE, 47906200526848, 47906200842239,
+ERASE, 47906200526848, 47906200526848,
+STORE, 47906200526848, 47906200842239,
+STORE, 47906200948736, 47906200952831,
+STORE, 47906200842240, 47906200948735,
+ERASE, 47906200842240, 47906200842240,
+STORE, 47906200842240, 47906200948735,
+ERASE, 47906200952832, 47906200952832,
+STORE, 47906200952832, 47906201006079,
+STORE, 47906201006080, 47906204057599,
+STORE, 47906201550848, 47906204057599,
+STORE, 47906201006080, 47906201550847,
+ERASE, 47906201550848, 47906201550848,
+STORE, 47906201550848, 47906203836415,
+STORE, 47906203836416, 47906204057599,
+STORE, 47906203246592, 47906203836415,
+STORE, 47906201550848, 47906203246591,
+ERASE, 47906201550848, 47906201550848,
+STORE, 47906201550848, 47906203246591,
+STORE, 47906203832320, 47906203836415,
+STORE, 47906203246592, 47906203832319,
+ERASE, 47906203246592, 47906203246592,
+STORE, 47906203246592, 47906203832319,
+STORE, 47906204041216, 47906204057599,
+STORE, 47906203836416, 47906204041215,
+ERASE, 47906203836416, 47906203836416,
+STORE, 47906203836416, 47906204041215,
+ERASE, 47906204041216, 47906204041216,
+STORE, 47906204041216, 47906204057599,
+STORE, 47906204057600, 47906204090367,
+ERASE, 47906204057600, 47906204057600,
+STORE, 47906204057600, 47906204065791,
+STORE, 47906204065792, 47906204090367,
+STORE, 47906204078080, 47906204090367,
+STORE, 47906204065792, 47906204078079,
+ERASE, 47906204065792, 47906204065792,
+STORE, 47906204065792, 47906204078079,
+STORE, 47906204082176, 47906204090367,
+STORE, 47906204078080, 47906204082175,
+ERASE, 47906204078080, 47906204078080,
+STORE, 47906204078080, 47906204090367,
+ERASE, 47906204078080, 47906204078080,
+STORE, 47906204078080, 47906204082175,
+STORE, 47906204082176, 47906204090367,
+ERASE, 47906204082176, 47906204082176,
+STORE, 47906204082176, 47906204090367,
+STORE, 47906204090368, 47906204127231,
+ERASE, 47906204090368, 47906204090368,
+STORE, 47906204090368, 47906204098559,
+STORE, 47906204098560, 47906204127231,
+STORE, 47906204114944, 47906204127231,
+STORE, 47906204098560, 47906204114943,
+ERASE, 47906204098560, 47906204098560,
+STORE, 47906204098560, 47906204114943,
+STORE, 47906204119040, 47906204127231,
+STORE, 47906204114944, 47906204119039,
+ERASE, 47906204114944, 47906204114944,
+STORE, 47906204114944, 47906204127231,
+ERASE, 47906204114944, 47906204114944,
+STORE, 47906204114944, 47906204119039,
+STORE, 47906204119040, 47906204127231,
+ERASE, 47906204119040, 47906204119040,
+STORE, 47906204119040, 47906204127231,
+STORE, 47906204127232, 47906204602367,
+ERASE, 47906204127232, 47906204127232,
+STORE, 47906204127232, 47906204135423,
+STORE, 47906204135424, 47906204602367,
+STORE, 47906204471296, 47906204602367,
+STORE, 47906204135424, 47906204471295,
+ERASE, 47906204135424, 47906204135424,
+STORE, 47906204135424, 47906204471295,
+STORE, 47906204594176, 47906204602367,
+STORE, 47906204471296, 47906204594175,
+ERASE, 47906204471296, 47906204471296,
+STORE, 47906204471296, 47906204602367,
+ERASE, 47906204471296, 47906204471296,
+STORE, 47906204471296, 47906204594175,
+STORE, 47906204594176, 47906204602367,
+ERASE, 47906204594176, 47906204594176,
+STORE, 47906204594176, 47906204602367,
+STORE, 47906204602368, 47906204610559,
+STORE, 47906204610560, 47906204631039,
+ERASE, 47906204610560, 47906204610560,
+STORE, 47906204610560, 47906204614655,
+STORE, 47906204614656, 47906204631039,
+STORE, 47906204618752, 47906204631039,
+STORE, 47906204614656, 47906204618751,
+ERASE, 47906204614656, 47906204614656,
+STORE, 47906204614656, 47906204618751,
+STORE, 47906204622848, 47906204631039,
+STORE, 47906204618752, 47906204622847,
+ERASE, 47906204618752, 47906204618752,
+STORE, 47906204618752, 47906204631039,
+ERASE, 47906204618752, 47906204618752,
+STORE, 47906204618752, 47906204622847,
+STORE, 47906204622848, 47906204631039,
+ERASE, 47906204622848, 47906204622848,
+STORE, 47906204622848, 47906204631039,
+STORE, 47906204631040, 47906204639231,
+ERASE, 47906197295104, 47906197295104,
+STORE, 47906197295104, 47906197311487,
+STORE, 47906197311488, 47906197319679,
+ERASE, 47906204622848, 47906204622848,
+STORE, 47906204622848, 47906204626943,
+STORE, 47906204626944, 47906204631039,
+ERASE, 47906200211456, 47906200211456,
+STORE, 47906200211456, 47906200215551,
+STORE, 47906200215552, 47906200219647,
+ERASE, 47906204594176, 47906204594176,
+STORE, 47906204594176, 47906204598271,
+STORE, 47906204598272, 47906204602367,
+ERASE, 47906204119040, 47906204119040,
+STORE, 47906204119040, 47906204123135,
+STORE, 47906204123136, 47906204127231,
+ERASE, 47906204082176, 47906204082176,
+STORE, 47906204082176, 47906204086271,
+STORE, 47906204086272, 47906204090367,
+ERASE, 47906203836416, 47906203836416,
+STORE, 47906203836416, 47906204033023,
+STORE, 47906204033024, 47906204041215,
+ERASE, 47906200952832, 47906200952832,
+STORE, 47906200952832, 47906200989695,
+STORE, 47906200989696, 47906201006079,
+ERASE, 47906200399872, 47906200399872,
+STORE, 47906200399872, 47906200403967,
+STORE, 47906200403968, 47906200408063,
+ERASE, 47906200084480, 47906200084480,
+STORE, 47906200084480, 47906200088575,
+STORE, 47906200088576, 47906200092671,
+ERASE, 47906197815296, 47906197815296,
+STORE, 47906197815296, 47906197835775,
+STORE, 47906197835776, 47906197839871,
+ERASE, 47906197483520, 47906197483520,
+STORE, 47906197483520, 47906197487615,
+STORE, 47906197487616, 47906197491711,
+ERASE, 47906197438464, 47906197438464,
+STORE, 47906197438464, 47906197442559,
+STORE, 47906197442560, 47906197446655,
+ERASE, 94641232658432, 94641232658432,
+STORE, 94641232658432, 94641232781311,
+STORE, 94641232781312, 94641232785407,
+ERASE, 139726599675904, 139726599675904,
+STORE, 139726599675904, 139726599679999,
+STORE, 139726599680000, 139726599684095,
+ERASE, 47906195480576, 47906195480576,
+STORE, 94641242615808, 94641242750975,
+ };
+
+ unsigned long set10[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140736427839488, 140737488351231,
+ERASE, 140736427839488, 140736427839488,
+STORE, 140736427839488, 140736427843583,
+STORE, 94071213395968, 94071213567999,
+ERASE, 94071213395968, 94071213395968,
+STORE, 94071213395968, 94071213412351,
+STORE, 94071213412352, 94071213567999,
+ERASE, 94071213412352, 94071213412352,
+STORE, 94071213412352, 94071213514751,
+STORE, 94071213514752, 94071213555711,
+STORE, 94071213555712, 94071213567999,
+STORE, 139968410644480, 139968410816511,
+ERASE, 139968410644480, 139968410644480,
+STORE, 139968410644480, 139968410648575,
+STORE, 139968410648576, 139968410816511,
+ERASE, 139968410648576, 139968410648576,
+STORE, 139968410648576, 139968410771455,
+STORE, 139968410771456, 139968410804223,
+STORE, 139968410804224, 139968410812415,
+STORE, 139968410812416, 139968410816511,
+STORE, 140736429277184, 140736429281279,
+STORE, 140736429264896, 140736429277183,
+STORE, 47664384352256, 47664384360447,
+STORE, 47664384360448, 47664384368639,
+STORE, 47664384368640, 47664384532479,
+ERASE, 47664384368640, 47664384368640,
+STORE, 47664384368640, 47664384380927,
+STORE, 47664384380928, 47664384532479,
+STORE, 47664384479232, 47664384532479,
+STORE, 47664384380928, 47664384479231,
+ERASE, 47664384380928, 47664384380928,
+STORE, 47664384380928, 47664384479231,
+STORE, 47664384524288, 47664384532479,
+STORE, 47664384479232, 47664384524287,
+ERASE, 47664384479232, 47664384479232,
+STORE, 47664384479232, 47664384532479,
+ERASE, 47664384479232, 47664384479232,
+STORE, 47664384479232, 47664384524287,
+STORE, 47664384524288, 47664384532479,
+ERASE, 47664384524288, 47664384524288,
+STORE, 47664384524288, 47664384532479,
+STORE, 47664384532480, 47664387583999,
+STORE, 47664385077248, 47664387583999,
+STORE, 47664384532480, 47664385077247,
+ERASE, 47664385077248, 47664385077248,
+STORE, 47664385077248, 47664387362815,
+STORE, 47664387362816, 47664387583999,
+STORE, 47664386772992, 47664387362815,
+STORE, 47664385077248, 47664386772991,
+ERASE, 47664385077248, 47664385077248,
+STORE, 47664385077248, 47664386772991,
+STORE, 47664387358720, 47664387362815,
+STORE, 47664386772992, 47664387358719,
+ERASE, 47664386772992, 47664386772992,
+STORE, 47664386772992, 47664387358719,
+STORE, 47664387567616, 47664387583999,
+STORE, 47664387362816, 47664387567615,
+ERASE, 47664387362816, 47664387362816,
+STORE, 47664387362816, 47664387567615,
+ERASE, 47664387567616, 47664387567616,
+STORE, 47664387567616, 47664387583999,
+STORE, 47664387584000, 47664389423103,
+STORE, 47664387723264, 47664389423103,
+STORE, 47664387584000, 47664387723263,
+ERASE, 47664387723264, 47664387723264,
+STORE, 47664387723264, 47664389382143,
+STORE, 47664389382144, 47664389423103,
+STORE, 47664389066752, 47664389382143,
+STORE, 47664387723264, 47664389066751,
+ERASE, 47664387723264, 47664387723264,
+STORE, 47664387723264, 47664389066751,
+STORE, 47664389378048, 47664389382143,
+STORE, 47664389066752, 47664389378047,
+ERASE, 47664389066752, 47664389066752,
+STORE, 47664389066752, 47664389378047,
+STORE, 47664389406720, 47664389423103,
+STORE, 47664389382144, 47664389406719,
+ERASE, 47664389382144, 47664389382144,
+STORE, 47664389382144, 47664389406719,
+ERASE, 47664389406720, 47664389406720,
+STORE, 47664389406720, 47664389423103,
+STORE, 47664389423104, 47664389558271,
+ERASE, 47664389423104, 47664389423104,
+STORE, 47664389423104, 47664389447679,
+STORE, 47664389447680, 47664389558271,
+STORE, 47664389509120, 47664389558271,
+STORE, 47664389447680, 47664389509119,
+ERASE, 47664389447680, 47664389447680,
+STORE, 47664389447680, 47664389509119,
+STORE, 47664389533696, 47664389558271,
+STORE, 47664389509120, 47664389533695,
+ERASE, 47664389509120, 47664389509120,
+STORE, 47664389509120, 47664389558271,
+ERASE, 47664389509120, 47664389509120,
+STORE, 47664389509120, 47664389533695,
+STORE, 47664389533696, 47664389558271,
+STORE, 47664389541888, 47664389558271,
+STORE, 47664389533696, 47664389541887,
+ERASE, 47664389533696, 47664389533696,
+STORE, 47664389533696, 47664389541887,
+ERASE, 47664389541888, 47664389541888,
+STORE, 47664389541888, 47664389558271,
+STORE, 47664389558272, 47664389578751,
+ERASE, 47664389558272, 47664389558272,
+STORE, 47664389558272, 47664389562367,
+STORE, 47664389562368, 47664389578751,
+STORE, 47664389566464, 47664389578751,
+STORE, 47664389562368, 47664389566463,
+ERASE, 47664389562368, 47664389562368,
+STORE, 47664389562368, 47664389566463,
+STORE, 47664389570560, 47664389578751,
+STORE, 47664389566464, 47664389570559,
+ERASE, 47664389566464, 47664389566464,
+STORE, 47664389566464, 47664389578751,
+ERASE, 47664389566464, 47664389566464,
+STORE, 47664389566464, 47664389570559,
+STORE, 47664389570560, 47664389578751,
+ERASE, 47664389570560, 47664389570560,
+STORE, 47664389570560, 47664389578751,
+STORE, 47664389578752, 47664389586943,
+ERASE, 47664389382144, 47664389382144,
+STORE, 47664389382144, 47664389398527,
+STORE, 47664389398528, 47664389406719,
+ERASE, 47664389570560, 47664389570560,
+STORE, 47664389570560, 47664389574655,
+STORE, 47664389574656, 47664389578751,
+ERASE, 47664389533696, 47664389533696,
+STORE, 47664389533696, 47664389537791,
+STORE, 47664389537792, 47664389541887,
+ERASE, 47664387362816, 47664387362816,
+STORE, 47664387362816, 47664387559423,
+STORE, 47664387559424, 47664387567615,
+ERASE, 47664384524288, 47664384524288,
+STORE, 47664384524288, 47664384528383,
+STORE, 47664384528384, 47664384532479,
+ERASE, 94071213555712, 94071213555712,
+STORE, 94071213555712, 94071213563903,
+STORE, 94071213563904, 94071213567999,
+ERASE, 139968410804224, 139968410804224,
+STORE, 139968410804224, 139968410808319,
+STORE, 139968410808320, 139968410812415,
+ERASE, 47664384352256, 47664384352256,
+STORE, 94071244402688, 94071244537855,
+STORE, 140737488347136, 140737488351231,
+STORE, 140728271503360, 140737488351231,
+ERASE, 140728271503360, 140728271503360,
+STORE, 140728271503360, 140728271507455,
+STORE, 94410361982976, 94410362155007,
+ERASE, 94410361982976, 94410361982976,
+STORE, 94410361982976, 94410361999359,
+STORE, 94410361999360, 94410362155007,
+ERASE, 94410361999360, 94410361999360,
+STORE, 94410361999360, 94410362101759,
+STORE, 94410362101760, 94410362142719,
+STORE, 94410362142720, 94410362155007,
+STORE, 140351953997824, 140351954169855,
+ERASE, 140351953997824, 140351953997824,
+STORE, 140351953997824, 140351954001919,
+STORE, 140351954001920, 140351954169855,
+ERASE, 140351954001920, 140351954001920,
+STORE, 140351954001920, 140351954124799,
+STORE, 140351954124800, 140351954157567,
+STORE, 140351954157568, 140351954165759,
+STORE, 140351954165760, 140351954169855,
+STORE, 140728272429056, 140728272433151,
+STORE, 140728272416768, 140728272429055,
+STORE, 47280840998912, 47280841007103,
+STORE, 47280841007104, 47280841015295,
+STORE, 47280841015296, 47280841179135,
+ERASE, 47280841015296, 47280841015296,
+STORE, 47280841015296, 47280841027583,
+STORE, 47280841027584, 47280841179135,
+STORE, 47280841125888, 47280841179135,
+STORE, 47280841027584, 47280841125887,
+ERASE, 47280841027584, 47280841027584,
+STORE, 47280841027584, 47280841125887,
+STORE, 47280841170944, 47280841179135,
+STORE, 47280841125888, 47280841170943,
+ERASE, 47280841125888, 47280841125888,
+STORE, 47280841125888, 47280841179135,
+ERASE, 47280841125888, 47280841125888,
+STORE, 47280841125888, 47280841170943,
+STORE, 47280841170944, 47280841179135,
+ERASE, 47280841170944, 47280841170944,
+STORE, 47280841170944, 47280841179135,
+STORE, 47280841179136, 47280844230655,
+STORE, 47280841723904, 47280844230655,
+STORE, 47280841179136, 47280841723903,
+ERASE, 47280841723904, 47280841723904,
+STORE, 47280841723904, 47280844009471,
+STORE, 47280844009472, 47280844230655,
+STORE, 47280843419648, 47280844009471,
+STORE, 47280841723904, 47280843419647,
+ERASE, 47280841723904, 47280841723904,
+STORE, 47280841723904, 47280843419647,
+STORE, 47280844005376, 47280844009471,
+STORE, 47280843419648, 47280844005375,
+ERASE, 47280843419648, 47280843419648,
+STORE, 47280843419648, 47280844005375,
+STORE, 47280844214272, 47280844230655,
+STORE, 47280844009472, 47280844214271,
+ERASE, 47280844009472, 47280844009472,
+STORE, 47280844009472, 47280844214271,
+ERASE, 47280844214272, 47280844214272,
+STORE, 47280844214272, 47280844230655,
+STORE, 47280844230656, 47280846069759,
+STORE, 47280844369920, 47280846069759,
+STORE, 47280844230656, 47280844369919,
+ERASE, 47280844369920, 47280844369920,
+STORE, 47280844369920, 47280846028799,
+STORE, 47280846028800, 47280846069759,
+STORE, 47280845713408, 47280846028799,
+STORE, 47280844369920, 47280845713407,
+ERASE, 47280844369920, 47280844369920,
+STORE, 47280844369920, 47280845713407,
+STORE, 47280846024704, 47280846028799,
+STORE, 47280845713408, 47280846024703,
+ERASE, 47280845713408, 47280845713408,
+STORE, 47280845713408, 47280846024703,
+STORE, 47280846053376, 47280846069759,
+STORE, 47280846028800, 47280846053375,
+ERASE, 47280846028800, 47280846028800,
+STORE, 47280846028800, 47280846053375,
+ERASE, 47280846053376, 47280846053376,
+STORE, 47280846053376, 47280846069759,
+STORE, 47280846069760, 47280846204927,
+ERASE, 47280846069760, 47280846069760,
+STORE, 47280846069760, 47280846094335,
+STORE, 47280846094336, 47280846204927,
+STORE, 47280846155776, 47280846204927,
+STORE, 47280846094336, 47280846155775,
+ERASE, 47280846094336, 47280846094336,
+STORE, 47280846094336, 47280846155775,
+STORE, 47280846180352, 47280846204927,
+STORE, 47280846155776, 47280846180351,
+ERASE, 47280846155776, 47280846155776,
+STORE, 47280846155776, 47280846204927,
+ERASE, 47280846155776, 47280846155776,
+STORE, 47280846155776, 47280846180351,
+STORE, 47280846180352, 47280846204927,
+STORE, 47280846188544, 47280846204927,
+STORE, 47280846180352, 47280846188543,
+ERASE, 47280846180352, 47280846180352,
+STORE, 47280846180352, 47280846188543,
+ERASE, 47280846188544, 47280846188544,
+STORE, 47280846188544, 47280846204927,
+STORE, 47280846204928, 47280846225407,
+ERASE, 47280846204928, 47280846204928,
+STORE, 47280846204928, 47280846209023,
+STORE, 47280846209024, 47280846225407,
+STORE, 47280846213120, 47280846225407,
+STORE, 47280846209024, 47280846213119,
+ERASE, 47280846209024, 47280846209024,
+STORE, 47280846209024, 47280846213119,
+STORE, 47280846217216, 47280846225407,
+STORE, 47280846213120, 47280846217215,
+ERASE, 47280846213120, 47280846213120,
+STORE, 47280846213120, 47280846225407,
+ERASE, 47280846213120, 47280846213120,
+STORE, 47280846213120, 47280846217215,
+STORE, 47280846217216, 47280846225407,
+ERASE, 47280846217216, 47280846217216,
+STORE, 47280846217216, 47280846225407,
+STORE, 47280846225408, 47280846233599,
+ERASE, 47280846028800, 47280846028800,
+STORE, 47280846028800, 47280846045183,
+STORE, 47280846045184, 47280846053375,
+ERASE, 47280846217216, 47280846217216,
+STORE, 47280846217216, 47280846221311,
+STORE, 47280846221312, 47280846225407,
+ERASE, 47280846180352, 47280846180352,
+STORE, 47280846180352, 47280846184447,
+STORE, 47280846184448, 47280846188543,
+ERASE, 47280844009472, 47280844009472,
+STORE, 47280844009472, 47280844206079,
+STORE, 47280844206080, 47280844214271,
+ERASE, 47280841170944, 47280841170944,
+STORE, 47280841170944, 47280841175039,
+STORE, 47280841175040, 47280841179135,
+ERASE, 94410362142720, 94410362142720,
+STORE, 94410362142720, 94410362150911,
+STORE, 94410362150912, 94410362155007,
+ERASE, 140351954157568, 140351954157568,
+STORE, 140351954157568, 140351954161663,
+STORE, 140351954161664, 140351954165759,
+ERASE, 47280840998912, 47280840998912,
+STORE, 94410379456512, 94410379591679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732946362368, 140737488351231,
+ERASE, 140732946362368, 140732946362368,
+STORE, 140732946362368, 140732946366463,
+STORE, 94352937934848, 94352938106879,
+ERASE, 94352937934848, 94352937934848,
+STORE, 94352937934848, 94352937951231,
+STORE, 94352937951232, 94352938106879,
+ERASE, 94352937951232, 94352937951232,
+STORE, 94352937951232, 94352938053631,
+STORE, 94352938053632, 94352938094591,
+STORE, 94352938094592, 94352938106879,
+STORE, 140595518742528, 140595518914559,
+ERASE, 140595518742528, 140595518742528,
+STORE, 140595518742528, 140595518746623,
+STORE, 140595518746624, 140595518914559,
+ERASE, 140595518746624, 140595518746624,
+STORE, 140595518746624, 140595518869503,
+STORE, 140595518869504, 140595518902271,
+STORE, 140595518902272, 140595518910463,
+STORE, 140595518910464, 140595518914559,
+STORE, 140732947468288, 140732947472383,
+STORE, 140732947456000, 140732947468287,
+STORE, 47037276254208, 47037276262399,
+STORE, 47037276262400, 47037276270591,
+STORE, 47037276270592, 47037276434431,
+ERASE, 47037276270592, 47037276270592,
+STORE, 47037276270592, 47037276282879,
+STORE, 47037276282880, 47037276434431,
+STORE, 47037276381184, 47037276434431,
+STORE, 47037276282880, 47037276381183,
+ERASE, 47037276282880, 47037276282880,
+STORE, 47037276282880, 47037276381183,
+STORE, 47037276426240, 47037276434431,
+STORE, 47037276381184, 47037276426239,
+ERASE, 47037276381184, 47037276381184,
+STORE, 47037276381184, 47037276434431,
+ERASE, 47037276381184, 47037276381184,
+STORE, 47037276381184, 47037276426239,
+STORE, 47037276426240, 47037276434431,
+ERASE, 47037276426240, 47037276426240,
+STORE, 47037276426240, 47037276434431,
+STORE, 47037276434432, 47037279485951,
+STORE, 47037276979200, 47037279485951,
+STORE, 47037276434432, 47037276979199,
+ERASE, 47037276979200, 47037276979200,
+STORE, 47037276979200, 47037279264767,
+STORE, 47037279264768, 47037279485951,
+STORE, 47037278674944, 47037279264767,
+STORE, 47037276979200, 47037278674943,
+ERASE, 47037276979200, 47037276979200,
+STORE, 47037276979200, 47037278674943,
+STORE, 47037279260672, 47037279264767,
+STORE, 47037278674944, 47037279260671,
+ERASE, 47037278674944, 47037278674944,
+STORE, 47037278674944, 47037279260671,
+STORE, 47037279469568, 47037279485951,
+STORE, 47037279264768, 47037279469567,
+ERASE, 47037279264768, 47037279264768,
+STORE, 47037279264768, 47037279469567,
+ERASE, 47037279469568, 47037279469568,
+STORE, 47037279469568, 47037279485951,
+STORE, 47037279485952, 47037281325055,
+STORE, 47037279625216, 47037281325055,
+STORE, 47037279485952, 47037279625215,
+ERASE, 47037279625216, 47037279625216,
+STORE, 47037279625216, 47037281284095,
+STORE, 47037281284096, 47037281325055,
+STORE, 47037280968704, 47037281284095,
+STORE, 47037279625216, 47037280968703,
+ERASE, 47037279625216, 47037279625216,
+STORE, 47037279625216, 47037280968703,
+STORE, 47037281280000, 47037281284095,
+STORE, 47037280968704, 47037281279999,
+ERASE, 47037280968704, 47037280968704,
+STORE, 47037280968704, 47037281279999,
+STORE, 47037281308672, 47037281325055,
+STORE, 47037281284096, 47037281308671,
+ERASE, 47037281284096, 47037281284096,
+STORE, 47037281284096, 47037281308671,
+ERASE, 47037281308672, 47037281308672,
+STORE, 47037281308672, 47037281325055,
+STORE, 47037281325056, 47037281460223,
+ERASE, 47037281325056, 47037281325056,
+STORE, 47037281325056, 47037281349631,
+STORE, 47037281349632, 47037281460223,
+STORE, 47037281411072, 47037281460223,
+STORE, 47037281349632, 47037281411071,
+ERASE, 47037281349632, 47037281349632,
+STORE, 47037281349632, 47037281411071,
+STORE, 47037281435648, 47037281460223,
+STORE, 47037281411072, 47037281435647,
+ERASE, 47037281411072, 47037281411072,
+STORE, 47037281411072, 47037281460223,
+ERASE, 47037281411072, 47037281411072,
+STORE, 47037281411072, 47037281435647,
+STORE, 47037281435648, 47037281460223,
+STORE, 47037281443840, 47037281460223,
+STORE, 47037281435648, 47037281443839,
+ERASE, 47037281435648, 47037281435648,
+STORE, 47037281435648, 47037281443839,
+ERASE, 47037281443840, 47037281443840,
+STORE, 47037281443840, 47037281460223,
+STORE, 47037281460224, 47037281480703,
+ERASE, 47037281460224, 47037281460224,
+STORE, 47037281460224, 47037281464319,
+STORE, 47037281464320, 47037281480703,
+STORE, 47037281468416, 47037281480703,
+STORE, 47037281464320, 47037281468415,
+ERASE, 47037281464320, 47037281464320,
+STORE, 47037281464320, 47037281468415,
+STORE, 47037281472512, 47037281480703,
+STORE, 47037281468416, 47037281472511,
+ERASE, 47037281468416, 47037281468416,
+STORE, 47037281468416, 47037281480703,
+ERASE, 47037281468416, 47037281468416,
+STORE, 47037281468416, 47037281472511,
+STORE, 47037281472512, 47037281480703,
+ERASE, 47037281472512, 47037281472512,
+STORE, 47037281472512, 47037281480703,
+STORE, 47037281480704, 47037281488895,
+ERASE, 47037281284096, 47037281284096,
+STORE, 47037281284096, 47037281300479,
+STORE, 47037281300480, 47037281308671,
+ERASE, 47037281472512, 47037281472512,
+STORE, 47037281472512, 47037281476607,
+STORE, 47037281476608, 47037281480703,
+ERASE, 47037281435648, 47037281435648,
+STORE, 47037281435648, 47037281439743,
+STORE, 47037281439744, 47037281443839,
+ERASE, 47037279264768, 47037279264768,
+STORE, 47037279264768, 47037279461375,
+STORE, 47037279461376, 47037279469567,
+ERASE, 47037276426240, 47037276426240,
+STORE, 47037276426240, 47037276430335,
+STORE, 47037276430336, 47037276434431,
+ERASE, 94352938094592, 94352938094592,
+STORE, 94352938094592, 94352938102783,
+STORE, 94352938102784, 94352938106879,
+ERASE, 140595518902272, 140595518902272,
+STORE, 140595518902272, 140595518906367,
+STORE, 140595518906368, 140595518910463,
+ERASE, 47037276254208, 47037276254208,
+STORE, 94352938438656, 94352938573823,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733506027520, 140737488351231,
+ERASE, 140733506027520, 140733506027520,
+STORE, 140733506027520, 140733506031615,
+STORE, 94150123073536, 94150123245567,
+ERASE, 94150123073536, 94150123073536,
+STORE, 94150123073536, 94150123089919,
+STORE, 94150123089920, 94150123245567,
+ERASE, 94150123089920, 94150123089920,
+STORE, 94150123089920, 94150123192319,
+STORE, 94150123192320, 94150123233279,
+STORE, 94150123233280, 94150123245567,
+STORE, 140081290375168, 140081290547199,
+ERASE, 140081290375168, 140081290375168,
+STORE, 140081290375168, 140081290379263,
+STORE, 140081290379264, 140081290547199,
+ERASE, 140081290379264, 140081290379264,
+STORE, 140081290379264, 140081290502143,
+STORE, 140081290502144, 140081290534911,
+STORE, 140081290534912, 140081290543103,
+STORE, 140081290543104, 140081290547199,
+STORE, 140733506707456, 140733506711551,
+STORE, 140733506695168, 140733506707455,
+STORE, 47551504621568, 47551504629759,
+STORE, 47551504629760, 47551504637951,
+STORE, 47551504637952, 47551504801791,
+ERASE, 47551504637952, 47551504637952,
+STORE, 47551504637952, 47551504650239,
+STORE, 47551504650240, 47551504801791,
+STORE, 47551504748544, 47551504801791,
+STORE, 47551504650240, 47551504748543,
+ERASE, 47551504650240, 47551504650240,
+STORE, 47551504650240, 47551504748543,
+STORE, 47551504793600, 47551504801791,
+STORE, 47551504748544, 47551504793599,
+ERASE, 47551504748544, 47551504748544,
+STORE, 47551504748544, 47551504801791,
+ERASE, 47551504748544, 47551504748544,
+STORE, 47551504748544, 47551504793599,
+STORE, 47551504793600, 47551504801791,
+ERASE, 47551504793600, 47551504793600,
+STORE, 47551504793600, 47551504801791,
+STORE, 47551504801792, 47551507853311,
+STORE, 47551505346560, 47551507853311,
+STORE, 47551504801792, 47551505346559,
+ERASE, 47551505346560, 47551505346560,
+STORE, 47551505346560, 47551507632127,
+STORE, 47551507632128, 47551507853311,
+STORE, 47551507042304, 47551507632127,
+STORE, 47551505346560, 47551507042303,
+ERASE, 47551505346560, 47551505346560,
+STORE, 47551505346560, 47551507042303,
+STORE, 47551507628032, 47551507632127,
+STORE, 47551507042304, 47551507628031,
+ERASE, 47551507042304, 47551507042304,
+STORE, 47551507042304, 47551507628031,
+STORE, 47551507836928, 47551507853311,
+STORE, 47551507632128, 47551507836927,
+ERASE, 47551507632128, 47551507632128,
+STORE, 47551507632128, 47551507836927,
+ERASE, 47551507836928, 47551507836928,
+STORE, 47551507836928, 47551507853311,
+STORE, 47551507853312, 47551509692415,
+STORE, 47551507992576, 47551509692415,
+STORE, 47551507853312, 47551507992575,
+ERASE, 47551507992576, 47551507992576,
+STORE, 47551507992576, 47551509651455,
+STORE, 47551509651456, 47551509692415,
+STORE, 47551509336064, 47551509651455,
+STORE, 47551507992576, 47551509336063,
+ERASE, 47551507992576, 47551507992576,
+STORE, 47551507992576, 47551509336063,
+STORE, 47551509647360, 47551509651455,
+STORE, 47551509336064, 47551509647359,
+ERASE, 47551509336064, 47551509336064,
+STORE, 47551509336064, 47551509647359,
+STORE, 47551509676032, 47551509692415,
+STORE, 47551509651456, 47551509676031,
+ERASE, 47551509651456, 47551509651456,
+STORE, 47551509651456, 47551509676031,
+ERASE, 47551509676032, 47551509676032,
+STORE, 47551509676032, 47551509692415,
+STORE, 47551509692416, 47551509827583,
+ERASE, 47551509692416, 47551509692416,
+STORE, 47551509692416, 47551509716991,
+STORE, 47551509716992, 47551509827583,
+STORE, 47551509778432, 47551509827583,
+STORE, 47551509716992, 47551509778431,
+ERASE, 47551509716992, 47551509716992,
+STORE, 47551509716992, 47551509778431,
+STORE, 47551509803008, 47551509827583,
+STORE, 47551509778432, 47551509803007,
+ERASE, 47551509778432, 47551509778432,
+STORE, 47551509778432, 47551509827583,
+ERASE, 47551509778432, 47551509778432,
+STORE, 47551509778432, 47551509803007,
+STORE, 47551509803008, 47551509827583,
+STORE, 47551509811200, 47551509827583,
+STORE, 47551509803008, 47551509811199,
+ERASE, 47551509803008, 47551509803008,
+STORE, 47551509803008, 47551509811199,
+ERASE, 47551509811200, 47551509811200,
+STORE, 47551509811200, 47551509827583,
+STORE, 47551509827584, 47551509848063,
+ERASE, 47551509827584, 47551509827584,
+STORE, 47551509827584, 47551509831679,
+STORE, 47551509831680, 47551509848063,
+STORE, 47551509835776, 47551509848063,
+STORE, 47551509831680, 47551509835775,
+ERASE, 47551509831680, 47551509831680,
+STORE, 47551509831680, 47551509835775,
+STORE, 47551509839872, 47551509848063,
+STORE, 47551509835776, 47551509839871,
+ERASE, 47551509835776, 47551509835776,
+STORE, 47551509835776, 47551509848063,
+ERASE, 47551509835776, 47551509835776,
+STORE, 47551509835776, 47551509839871,
+STORE, 47551509839872, 47551509848063,
+ERASE, 47551509839872, 47551509839872,
+STORE, 47551509839872, 47551509848063,
+STORE, 47551509848064, 47551509856255,
+ERASE, 47551509651456, 47551509651456,
+STORE, 47551509651456, 47551509667839,
+STORE, 47551509667840, 47551509676031,
+ERASE, 47551509839872, 47551509839872,
+STORE, 47551509839872, 47551509843967,
+STORE, 47551509843968, 47551509848063,
+ERASE, 47551509803008, 47551509803008,
+STORE, 47551509803008, 47551509807103,
+STORE, 47551509807104, 47551509811199,
+ERASE, 47551507632128, 47551507632128,
+STORE, 47551507632128, 47551507828735,
+STORE, 47551507828736, 47551507836927,
+ERASE, 47551504793600, 47551504793600,
+STORE, 47551504793600, 47551504797695,
+STORE, 47551504797696, 47551504801791,
+ERASE, 94150123233280, 94150123233280,
+STORE, 94150123233280, 94150123241471,
+STORE, 94150123241472, 94150123245567,
+ERASE, 140081290534912, 140081290534912,
+STORE, 140081290534912, 140081290539007,
+STORE, 140081290539008, 140081290543103,
+ERASE, 47551504621568, 47551504621568,
+STORE, 94150148112384, 94150148247551,
+STORE, 140737488347136, 140737488351231,
+STORE, 140734389334016, 140737488351231,
+ERASE, 140734389334016, 140734389334016,
+STORE, 140734389334016, 140734389338111,
+STORE, 94844636606464, 94844636778495,
+ERASE, 94844636606464, 94844636606464,
+STORE, 94844636606464, 94844636622847,
+STORE, 94844636622848, 94844636778495,
+ERASE, 94844636622848, 94844636622848,
+STORE, 94844636622848, 94844636725247,
+STORE, 94844636725248, 94844636766207,
+STORE, 94844636766208, 94844636778495,
+STORE, 139922765217792, 139922765389823,
+ERASE, 139922765217792, 139922765217792,
+STORE, 139922765217792, 139922765221887,
+STORE, 139922765221888, 139922765389823,
+ERASE, 139922765221888, 139922765221888,
+STORE, 139922765221888, 139922765344767,
+STORE, 139922765344768, 139922765377535,
+STORE, 139922765377536, 139922765385727,
+STORE, 139922765385728, 139922765389823,
+STORE, 140734389678080, 140734389682175,
+STORE, 140734389665792, 140734389678079,
+STORE, 47710029778944, 47710029787135,
+STORE, 47710029787136, 47710029795327,
+STORE, 47710029795328, 47710029959167,
+ERASE, 47710029795328, 47710029795328,
+STORE, 47710029795328, 47710029807615,
+STORE, 47710029807616, 47710029959167,
+STORE, 47710029905920, 47710029959167,
+STORE, 47710029807616, 47710029905919,
+ERASE, 47710029807616, 47710029807616,
+STORE, 47710029807616, 47710029905919,
+STORE, 47710029950976, 47710029959167,
+STORE, 47710029905920, 47710029950975,
+ERASE, 47710029905920, 47710029905920,
+STORE, 47710029905920, 47710029959167,
+ERASE, 47710029905920, 47710029905920,
+STORE, 47710029905920, 47710029950975,
+STORE, 47710029950976, 47710029959167,
+ERASE, 47710029950976, 47710029950976,
+STORE, 47710029950976, 47710029959167,
+STORE, 47710029959168, 47710033010687,
+STORE, 47710030503936, 47710033010687,
+STORE, 47710029959168, 47710030503935,
+ERASE, 47710030503936, 47710030503936,
+STORE, 47710030503936, 47710032789503,
+STORE, 47710032789504, 47710033010687,
+STORE, 47710032199680, 47710032789503,
+STORE, 47710030503936, 47710032199679,
+ERASE, 47710030503936, 47710030503936,
+STORE, 47710030503936, 47710032199679,
+STORE, 47710032785408, 47710032789503,
+STORE, 47710032199680, 47710032785407,
+ERASE, 47710032199680, 47710032199680,
+STORE, 47710032199680, 47710032785407,
+STORE, 47710032994304, 47710033010687,
+STORE, 47710032789504, 47710032994303,
+ERASE, 47710032789504, 47710032789504,
+STORE, 47710032789504, 47710032994303,
+ERASE, 47710032994304, 47710032994304,
+STORE, 47710032994304, 47710033010687,
+STORE, 47710033010688, 47710034849791,
+STORE, 47710033149952, 47710034849791,
+STORE, 47710033010688, 47710033149951,
+ERASE, 47710033149952, 47710033149952,
+STORE, 47710033149952, 47710034808831,
+STORE, 47710034808832, 47710034849791,
+STORE, 47710034493440, 47710034808831,
+STORE, 47710033149952, 47710034493439,
+ERASE, 47710033149952, 47710033149952,
+STORE, 47710033149952, 47710034493439,
+STORE, 47710034804736, 47710034808831,
+STORE, 47710034493440, 47710034804735,
+ERASE, 47710034493440, 47710034493440,
+STORE, 47710034493440, 47710034804735,
+STORE, 47710034833408, 47710034849791,
+STORE, 47710034808832, 47710034833407,
+ERASE, 47710034808832, 47710034808832,
+STORE, 47710034808832, 47710034833407,
+ERASE, 47710034833408, 47710034833408,
+STORE, 47710034833408, 47710034849791,
+STORE, 47710034849792, 47710034984959,
+ERASE, 47710034849792, 47710034849792,
+STORE, 47710034849792, 47710034874367,
+STORE, 47710034874368, 47710034984959,
+STORE, 47710034935808, 47710034984959,
+STORE, 47710034874368, 47710034935807,
+ERASE, 47710034874368, 47710034874368,
+STORE, 47710034874368, 47710034935807,
+STORE, 47710034960384, 47710034984959,
+STORE, 47710034935808, 47710034960383,
+ERASE, 47710034935808, 47710034935808,
+STORE, 47710034935808, 47710034984959,
+ERASE, 47710034935808, 47710034935808,
+STORE, 47710034935808, 47710034960383,
+STORE, 47710034960384, 47710034984959,
+STORE, 47710034968576, 47710034984959,
+STORE, 47710034960384, 47710034968575,
+ERASE, 47710034960384, 47710034960384,
+STORE, 47710034960384, 47710034968575,
+ERASE, 47710034968576, 47710034968576,
+STORE, 47710034968576, 47710034984959,
+STORE, 47710034984960, 47710035005439,
+ERASE, 47710034984960, 47710034984960,
+STORE, 47710034984960, 47710034989055,
+STORE, 47710034989056, 47710035005439,
+STORE, 47710034993152, 47710035005439,
+STORE, 47710034989056, 47710034993151,
+ERASE, 47710034989056, 47710034989056,
+STORE, 47710034989056, 47710034993151,
+STORE, 47710034997248, 47710035005439,
+STORE, 47710034993152, 47710034997247,
+ERASE, 47710034993152, 47710034993152,
+STORE, 47710034993152, 47710035005439,
+ERASE, 47710034993152, 47710034993152,
+STORE, 47710034993152, 47710034997247,
+STORE, 47710034997248, 47710035005439,
+ERASE, 47710034997248, 47710034997248,
+STORE, 47710034997248, 47710035005439,
+STORE, 47710035005440, 47710035013631,
+ERASE, 47710034808832, 47710034808832,
+STORE, 47710034808832, 47710034825215,
+STORE, 47710034825216, 47710034833407,
+ERASE, 47710034997248, 47710034997248,
+STORE, 47710034997248, 47710035001343,
+STORE, 47710035001344, 47710035005439,
+ERASE, 47710034960384, 47710034960384,
+STORE, 47710034960384, 47710034964479,
+STORE, 47710034964480, 47710034968575,
+ERASE, 47710032789504, 47710032789504,
+STORE, 47710032789504, 47710032986111,
+STORE, 47710032986112, 47710032994303,
+ERASE, 47710029950976, 47710029950976,
+STORE, 47710029950976, 47710029955071,
+STORE, 47710029955072, 47710029959167,
+ERASE, 94844636766208, 94844636766208,
+STORE, 94844636766208, 94844636774399,
+STORE, 94844636774400, 94844636778495,
+ERASE, 139922765377536, 139922765377536,
+STORE, 139922765377536, 139922765381631,
+STORE, 139922765381632, 139922765385727,
+ERASE, 47710029778944, 47710029778944,
+STORE, 94844641775616, 94844641910783,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732213886976, 140737488351231,
+ERASE, 140732213886976, 140732213886976,
+STORE, 140732213886976, 140732213891071,
+STORE, 94240508887040, 94240509059071,
+ERASE, 94240508887040, 94240508887040,
+STORE, 94240508887040, 94240508903423,
+STORE, 94240508903424, 94240509059071,
+ERASE, 94240508903424, 94240508903424,
+STORE, 94240508903424, 94240509005823,
+STORE, 94240509005824, 94240509046783,
+STORE, 94240509046784, 94240509059071,
+STORE, 140275106516992, 140275106689023,
+ERASE, 140275106516992, 140275106516992,
+STORE, 140275106516992, 140275106521087,
+STORE, 140275106521088, 140275106689023,
+ERASE, 140275106521088, 140275106521088,
+STORE, 140275106521088, 140275106643967,
+STORE, 140275106643968, 140275106676735,
+STORE, 140275106676736, 140275106684927,
+STORE, 140275106684928, 140275106689023,
+STORE, 140732213977088, 140732213981183,
+STORE, 140732213964800, 140732213977087,
+STORE, 47357688479744, 47357688487935,
+STORE, 47357688487936, 47357688496127,
+STORE, 47357688496128, 47357688659967,
+ERASE, 47357688496128, 47357688496128,
+STORE, 47357688496128, 47357688508415,
+STORE, 47357688508416, 47357688659967,
+STORE, 47357688606720, 47357688659967,
+STORE, 47357688508416, 47357688606719,
+ERASE, 47357688508416, 47357688508416,
+STORE, 47357688508416, 47357688606719,
+STORE, 47357688651776, 47357688659967,
+STORE, 47357688606720, 47357688651775,
+ERASE, 47357688606720, 47357688606720,
+STORE, 47357688606720, 47357688659967,
+ERASE, 47357688606720, 47357688606720,
+STORE, 47357688606720, 47357688651775,
+STORE, 47357688651776, 47357688659967,
+ERASE, 47357688651776, 47357688651776,
+STORE, 47357688651776, 47357688659967,
+STORE, 47357688659968, 47357691711487,
+STORE, 47357689204736, 47357691711487,
+STORE, 47357688659968, 47357689204735,
+ERASE, 47357689204736, 47357689204736,
+STORE, 47357689204736, 47357691490303,
+STORE, 47357691490304, 47357691711487,
+STORE, 47357690900480, 47357691490303,
+STORE, 47357689204736, 47357690900479,
+ERASE, 47357689204736, 47357689204736,
+STORE, 47357689204736, 47357690900479,
+STORE, 47357691486208, 47357691490303,
+STORE, 47357690900480, 47357691486207,
+ERASE, 47357690900480, 47357690900480,
+STORE, 47357690900480, 47357691486207,
+STORE, 47357691695104, 47357691711487,
+STORE, 47357691490304, 47357691695103,
+ERASE, 47357691490304, 47357691490304,
+STORE, 47357691490304, 47357691695103,
+ERASE, 47357691695104, 47357691695104,
+STORE, 47357691695104, 47357691711487,
+STORE, 47357691711488, 47357693550591,
+STORE, 47357691850752, 47357693550591,
+STORE, 47357691711488, 47357691850751,
+ERASE, 47357691850752, 47357691850752,
+STORE, 47357691850752, 47357693509631,
+STORE, 47357693509632, 47357693550591,
+STORE, 47357693194240, 47357693509631,
+STORE, 47357691850752, 47357693194239,
+ERASE, 47357691850752, 47357691850752,
+STORE, 47357691850752, 47357693194239,
+STORE, 47357693505536, 47357693509631,
+STORE, 47357693194240, 47357693505535,
+ERASE, 47357693194240, 47357693194240,
+STORE, 47357693194240, 47357693505535,
+STORE, 47357693534208, 47357693550591,
+STORE, 47357693509632, 47357693534207,
+ERASE, 47357693509632, 47357693509632,
+STORE, 47357693509632, 47357693534207,
+ERASE, 47357693534208, 47357693534208,
+STORE, 47357693534208, 47357693550591,
+STORE, 47357693550592, 47357693685759,
+ERASE, 47357693550592, 47357693550592,
+STORE, 47357693550592, 47357693575167,
+STORE, 47357693575168, 47357693685759,
+STORE, 47357693636608, 47357693685759,
+STORE, 47357693575168, 47357693636607,
+ERASE, 47357693575168, 47357693575168,
+STORE, 47357693575168, 47357693636607,
+STORE, 47357693661184, 47357693685759,
+STORE, 47357693636608, 47357693661183,
+ERASE, 47357693636608, 47357693636608,
+STORE, 47357693636608, 47357693685759,
+ERASE, 47357693636608, 47357693636608,
+STORE, 47357693636608, 47357693661183,
+STORE, 47357693661184, 47357693685759,
+STORE, 47357693669376, 47357693685759,
+STORE, 47357693661184, 47357693669375,
+ERASE, 47357693661184, 47357693661184,
+STORE, 47357693661184, 47357693669375,
+ERASE, 47357693669376, 47357693669376,
+STORE, 47357693669376, 47357693685759,
+STORE, 47357693685760, 47357693706239,
+ERASE, 47357693685760, 47357693685760,
+STORE, 47357693685760, 47357693689855,
+STORE, 47357693689856, 47357693706239,
+STORE, 47357693693952, 47357693706239,
+STORE, 47357693689856, 47357693693951,
+ERASE, 47357693689856, 47357693689856,
+STORE, 47357693689856, 47357693693951,
+STORE, 47357693698048, 47357693706239,
+STORE, 47357693693952, 47357693698047,
+ERASE, 47357693693952, 47357693693952,
+STORE, 47357693693952, 47357693706239,
+ERASE, 47357693693952, 47357693693952,
+STORE, 47357693693952, 47357693698047,
+STORE, 47357693698048, 47357693706239,
+ERASE, 47357693698048, 47357693698048,
+STORE, 47357693698048, 47357693706239,
+STORE, 47357693706240, 47357693714431,
+ERASE, 47357693509632, 47357693509632,
+STORE, 47357693509632, 47357693526015,
+STORE, 47357693526016, 47357693534207,
+ERASE, 47357693698048, 47357693698048,
+STORE, 47357693698048, 47357693702143,
+STORE, 47357693702144, 47357693706239,
+ERASE, 47357693661184, 47357693661184,
+STORE, 47357693661184, 47357693665279,
+STORE, 47357693665280, 47357693669375,
+ERASE, 47357691490304, 47357691490304,
+STORE, 47357691490304, 47357691686911,
+STORE, 47357691686912, 47357691695103,
+ERASE, 47357688651776, 47357688651776,
+STORE, 47357688651776, 47357688655871,
+STORE, 47357688655872, 47357688659967,
+ERASE, 94240509046784, 94240509046784,
+STORE, 94240509046784, 94240509054975,
+STORE, 94240509054976, 94240509059071,
+ERASE, 140275106676736, 140275106676736,
+STORE, 140275106676736, 140275106680831,
+STORE, 140275106680832, 140275106684927,
+ERASE, 47357688479744, 47357688479744,
+STORE, 94240518361088, 94240518496255,
+STORE, 140737488347136, 140737488351231,
+STORE, 140732688277504, 140737488351231,
+ERASE, 140732688277504, 140732688277504,
+STORE, 140732688277504, 140732688281599,
+STORE, 94629171351552, 94629172064255,
+ERASE, 94629171351552, 94629171351552,
+STORE, 94629171351552, 94629171400703,
+STORE, 94629171400704, 94629172064255,
+ERASE, 94629171400704, 94629171400704,
+STORE, 94629171400704, 94629171945471,
+STORE, 94629171945472, 94629172043775,
+STORE, 94629172043776, 94629172064255,
+STORE, 139770707644416, 139770707816447,
+ERASE, 139770707644416, 139770707644416,
+STORE, 139770707644416, 139770707648511,
+STORE, 139770707648512, 139770707816447,
+ERASE, 139770707648512, 139770707648512,
+STORE, 139770707648512, 139770707771391,
+STORE, 139770707771392, 139770707804159,
+STORE, 139770707804160, 139770707812351,
+STORE, 139770707812352, 139770707816447,
+STORE, 140732689121280, 140732689125375,
+STORE, 140732689108992, 140732689121279,
+STORE, 47862087352320, 47862087360511,
+STORE, 47862087360512, 47862087368703,
+STORE, 47862087368704, 47862087475199,
+STORE, 47862087385088, 47862087475199,
+STORE, 47862087368704, 47862087385087,
+ERASE, 47862087385088, 47862087385088,
+STORE, 47862087385088, 47862087458815,
+STORE, 47862087458816, 47862087475199,
+STORE, 47862087438336, 47862087458815,
+STORE, 47862087385088, 47862087438335,
+ERASE, 47862087385088, 47862087385088,
+STORE, 47862087385088, 47862087438335,
+STORE, 47862087454720, 47862087458815,
+STORE, 47862087438336, 47862087454719,
+ERASE, 47862087438336, 47862087438336,
+STORE, 47862087438336, 47862087454719,
+STORE, 47862087467008, 47862087475199,
+STORE, 47862087458816, 47862087467007,
+ERASE, 47862087458816, 47862087458816,
+STORE, 47862087458816, 47862087467007,
+ERASE, 47862087467008, 47862087467008,
+STORE, 47862087467008, 47862087475199,
+STORE, 47862087475200, 47862089314303,
+STORE, 47862087614464, 47862089314303,
+STORE, 47862087475200, 47862087614463,
+ERASE, 47862087614464, 47862087614464,
+STORE, 47862087614464, 47862089273343,
+STORE, 47862089273344, 47862089314303,
+STORE, 47862088957952, 47862089273343,
+STORE, 47862087614464, 47862088957951,
+ERASE, 47862087614464, 47862087614464,
+STORE, 47862087614464, 47862088957951,
+STORE, 47862089269248, 47862089273343,
+STORE, 47862088957952, 47862089269247,
+ERASE, 47862088957952, 47862088957952,
+STORE, 47862088957952, 47862089269247,
+STORE, 47862089297920, 47862089314303,
+STORE, 47862089273344, 47862089297919,
+ERASE, 47862089273344, 47862089273344,
+STORE, 47862089273344, 47862089297919,
+ERASE, 47862089297920, 47862089297920,
+STORE, 47862089297920, 47862089314303,
+STORE, 47862089297920, 47862089326591,
+ERASE, 47862089273344, 47862089273344,
+STORE, 47862089273344, 47862089289727,
+STORE, 47862089289728, 47862089297919,
+ERASE, 47862087458816, 47862087458816,
+STORE, 47862087458816, 47862087462911,
+STORE, 47862087462912, 47862087467007,
+ERASE, 94629172043776, 94629172043776,
+STORE, 94629172043776, 94629172060159,
+STORE, 94629172060160, 94629172064255,
+ERASE, 139770707804160, 139770707804160,
+STORE, 139770707804160, 139770707808255,
+STORE, 139770707808256, 139770707812351,
+ERASE, 47862087352320, 47862087352320,
+STORE, 94629197533184, 94629197668351,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727540711424, 140737488351231,
+ERASE, 140727540711424, 140727540711424,
+STORE, 140727540711424, 140727540715519,
+STORE, 94299865313280, 94299866025983,
+ERASE, 94299865313280, 94299865313280,
+STORE, 94299865313280, 94299865362431,
+STORE, 94299865362432, 94299866025983,
+ERASE, 94299865362432, 94299865362432,
+STORE, 94299865362432, 94299865907199,
+STORE, 94299865907200, 94299866005503,
+STORE, 94299866005504, 94299866025983,
+STORE, 140680268763136, 140680268935167,
+ERASE, 140680268763136, 140680268763136,
+STORE, 140680268763136, 140680268767231,
+STORE, 140680268767232, 140680268935167,
+ERASE, 140680268767232, 140680268767232,
+STORE, 140680268767232, 140680268890111,
+STORE, 140680268890112, 140680268922879,
+STORE, 140680268922880, 140680268931071,
+STORE, 140680268931072, 140680268935167,
+STORE, 140727541424128, 140727541428223,
+STORE, 140727541411840, 140727541424127,
+STORE, 46952526233600, 46952526241791,
+STORE, 46952526241792, 46952526249983,
+STORE, 46952526249984, 46952526356479,
+STORE, 46952526266368, 46952526356479,
+STORE, 46952526249984, 46952526266367,
+ERASE, 46952526266368, 46952526266368,
+STORE, 46952526266368, 46952526340095,
+STORE, 46952526340096, 46952526356479,
+STORE, 46952526319616, 46952526340095,
+STORE, 46952526266368, 46952526319615,
+ERASE, 46952526266368, 46952526266368,
+STORE, 46952526266368, 46952526319615,
+STORE, 46952526336000, 46952526340095,
+STORE, 46952526319616, 46952526335999,
+ERASE, 46952526319616, 46952526319616,
+STORE, 46952526319616, 46952526335999,
+STORE, 46952526348288, 46952526356479,
+STORE, 46952526340096, 46952526348287,
+ERASE, 46952526340096, 46952526340096,
+STORE, 46952526340096, 46952526348287,
+ERASE, 46952526348288, 46952526348288,
+STORE, 46952526348288, 46952526356479,
+STORE, 46952526356480, 46952528195583,
+STORE, 46952526495744, 46952528195583,
+STORE, 46952526356480, 46952526495743,
+ERASE, 46952526495744, 46952526495744,
+STORE, 46952526495744, 46952528154623,
+STORE, 46952528154624, 46952528195583,
+STORE, 46952527839232, 46952528154623,
+STORE, 46952526495744, 46952527839231,
+ERASE, 46952526495744, 46952526495744,
+STORE, 46952526495744, 46952527839231,
+STORE, 46952528150528, 46952528154623,
+STORE, 46952527839232, 46952528150527,
+ERASE, 46952527839232, 46952527839232,
+STORE, 46952527839232, 46952528150527,
+STORE, 46952528179200, 46952528195583,
+STORE, 46952528154624, 46952528179199,
+ERASE, 46952528154624, 46952528154624,
+STORE, 46952528154624, 46952528179199,
+ERASE, 46952528179200, 46952528179200,
+STORE, 46952528179200, 46952528195583,
+STORE, 46952528179200, 46952528207871,
+ERASE, 46952528154624, 46952528154624,
+STORE, 46952528154624, 46952528171007,
+STORE, 46952528171008, 46952528179199,
+ERASE, 46952526340096, 46952526340096,
+STORE, 46952526340096, 46952526344191,
+STORE, 46952526344192, 46952526348287,
+ERASE, 94299866005504, 94299866005504,
+STORE, 94299866005504, 94299866021887,
+STORE, 94299866021888, 94299866025983,
+ERASE, 140680268922880, 140680268922880,
+STORE, 140680268922880, 140680268926975,
+STORE, 140680268926976, 140680268931071,
+ERASE, 46952526233600, 46952526233600,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722874793984, 140737488351231,
+ERASE, 140722874793984, 140722874793984,
+STORE, 140722874793984, 140722874798079,
+STORE, 94448916213760, 94448916926463,
+ERASE, 94448916213760, 94448916213760,
+STORE, 94448916213760, 94448916262911,
+STORE, 94448916262912, 94448916926463,
+ERASE, 94448916262912, 94448916262912,
+STORE, 94448916262912, 94448916807679,
+STORE, 94448916807680, 94448916905983,
+STORE, 94448916905984, 94448916926463,
+STORE, 140389117046784, 140389117218815,
+ERASE, 140389117046784, 140389117046784,
+STORE, 140389117046784, 140389117050879,
+STORE, 140389117050880, 140389117218815,
+ERASE, 140389117050880, 140389117050880,
+STORE, 140389117050880, 140389117173759,
+STORE, 140389117173760, 140389117206527,
+STORE, 140389117206528, 140389117214719,
+STORE, 140389117214720, 140389117218815,
+STORE, 140722875297792, 140722875301887,
+STORE, 140722875285504, 140722875297791,
+STORE, 47243677949952, 47243677958143,
+STORE, 47243677958144, 47243677966335,
+STORE, 47243677966336, 47243678072831,
+STORE, 47243677982720, 47243678072831,
+STORE, 47243677966336, 47243677982719,
+ERASE, 47243677982720, 47243677982720,
+STORE, 47243677982720, 47243678056447,
+STORE, 47243678056448, 47243678072831,
+STORE, 47243678035968, 47243678056447,
+STORE, 47243677982720, 47243678035967,
+ERASE, 47243677982720, 47243677982720,
+STORE, 47243677982720, 47243678035967,
+STORE, 47243678052352, 47243678056447,
+STORE, 47243678035968, 47243678052351,
+ERASE, 47243678035968, 47243678035968,
+STORE, 47243678035968, 47243678052351,
+STORE, 47243678064640, 47243678072831,
+STORE, 47243678056448, 47243678064639,
+ERASE, 47243678056448, 47243678056448,
+STORE, 47243678056448, 47243678064639,
+ERASE, 47243678064640, 47243678064640,
+STORE, 47243678064640, 47243678072831,
+STORE, 47243678072832, 47243679911935,
+STORE, 47243678212096, 47243679911935,
+STORE, 47243678072832, 47243678212095,
+ERASE, 47243678212096, 47243678212096,
+STORE, 47243678212096, 47243679870975,
+STORE, 47243679870976, 47243679911935,
+STORE, 47243679555584, 47243679870975,
+STORE, 47243678212096, 47243679555583,
+ERASE, 47243678212096, 47243678212096,
+STORE, 47243678212096, 47243679555583,
+STORE, 47243679866880, 47243679870975,
+STORE, 47243679555584, 47243679866879,
+ERASE, 47243679555584, 47243679555584,
+STORE, 47243679555584, 47243679866879,
+STORE, 47243679895552, 47243679911935,
+STORE, 47243679870976, 47243679895551,
+ERASE, 47243679870976, 47243679870976,
+STORE, 47243679870976, 47243679895551,
+ERASE, 47243679895552, 47243679895552,
+STORE, 47243679895552, 47243679911935,
+STORE, 47243679895552, 47243679924223,
+ERASE, 47243679870976, 47243679870976,
+STORE, 47243679870976, 47243679887359,
+STORE, 47243679887360, 47243679895551,
+ERASE, 47243678056448, 47243678056448,
+STORE, 47243678056448, 47243678060543,
+STORE, 47243678060544, 47243678064639,
+ERASE, 94448916905984, 94448916905984,
+STORE, 94448916905984, 94448916922367,
+STORE, 94448916922368, 94448916926463,
+ERASE, 140389117206528, 140389117206528,
+STORE, 140389117206528, 140389117210623,
+STORE, 140389117210624, 140389117214719,
+ERASE, 47243677949952, 47243677949952,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733068505088, 140737488351231,
+ERASE, 140733068505088, 140733068505088,
+STORE, 140733068505088, 140733068509183,
+STORE, 94207145750528, 94207146463231,
+ERASE, 94207145750528, 94207145750528,
+STORE, 94207145750528, 94207145799679,
+STORE, 94207145799680, 94207146463231,
+ERASE, 94207145799680, 94207145799680,
+STORE, 94207145799680, 94207146344447,
+STORE, 94207146344448, 94207146442751,
+STORE, 94207146442752, 94207146463231,
+STORE, 140684504911872, 140684505083903,
+ERASE, 140684504911872, 140684504911872,
+STORE, 140684504911872, 140684504915967,
+STORE, 140684504915968, 140684505083903,
+ERASE, 140684504915968, 140684504915968,
+STORE, 140684504915968, 140684505038847,
+STORE, 140684505038848, 140684505071615,
+STORE, 140684505071616, 140684505079807,
+STORE, 140684505079808, 140684505083903,
+STORE, 140733068607488, 140733068611583,
+STORE, 140733068595200, 140733068607487,
+STORE, 46948290084864, 46948290093055,
+STORE, 46948290093056, 46948290101247,
+STORE, 46948290101248, 46948290207743,
+STORE, 46948290117632, 46948290207743,
+STORE, 46948290101248, 46948290117631,
+ERASE, 46948290117632, 46948290117632,
+STORE, 46948290117632, 46948290191359,
+STORE, 46948290191360, 46948290207743,
+STORE, 46948290170880, 46948290191359,
+STORE, 46948290117632, 46948290170879,
+ERASE, 46948290117632, 46948290117632,
+STORE, 46948290117632, 46948290170879,
+STORE, 46948290187264, 46948290191359,
+STORE, 46948290170880, 46948290187263,
+ERASE, 46948290170880, 46948290170880,
+STORE, 46948290170880, 46948290187263,
+STORE, 46948290199552, 46948290207743,
+STORE, 46948290191360, 46948290199551,
+ERASE, 46948290191360, 46948290191360,
+STORE, 46948290191360, 46948290199551,
+ERASE, 46948290199552, 46948290199552,
+STORE, 46948290199552, 46948290207743,
+STORE, 46948290207744, 46948292046847,
+STORE, 46948290347008, 46948292046847,
+STORE, 46948290207744, 46948290347007,
+ERASE, 46948290347008, 46948290347008,
+STORE, 46948290347008, 46948292005887,
+STORE, 46948292005888, 46948292046847,
+STORE, 46948291690496, 46948292005887,
+STORE, 46948290347008, 46948291690495,
+ERASE, 46948290347008, 46948290347008,
+STORE, 46948290347008, 46948291690495,
+STORE, 46948292001792, 46948292005887,
+STORE, 46948291690496, 46948292001791,
+ERASE, 46948291690496, 46948291690496,
+STORE, 46948291690496, 46948292001791,
+STORE, 46948292030464, 46948292046847,
+STORE, 46948292005888, 46948292030463,
+ERASE, 46948292005888, 46948292005888,
+STORE, 46948292005888, 46948292030463,
+ERASE, 46948292030464, 46948292030464,
+STORE, 46948292030464, 46948292046847,
+STORE, 46948292030464, 46948292059135,
+ERASE, 46948292005888, 46948292005888,
+STORE, 46948292005888, 46948292022271,
+STORE, 46948292022272, 46948292030463,
+ERASE, 46948290191360, 46948290191360,
+STORE, 46948290191360, 46948290195455,
+STORE, 46948290195456, 46948290199551,
+ERASE, 94207146442752, 94207146442752,
+STORE, 94207146442752, 94207146459135,
+STORE, 94207146459136, 94207146463231,
+ERASE, 140684505071616, 140684505071616,
+STORE, 140684505071616, 140684505075711,
+STORE, 140684505075712, 140684505079807,
+ERASE, 46948290084864, 46948290084864,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726367158272, 140737488351231,
+ERASE, 140726367158272, 140726367158272,
+STORE, 140726367158272, 140726367162367,
+STORE, 94436124106752, 94436124819455,
+ERASE, 94436124106752, 94436124106752,
+STORE, 94436124106752, 94436124155903,
+STORE, 94436124155904, 94436124819455,
+ERASE, 94436124155904, 94436124155904,
+STORE, 94436124155904, 94436124700671,
+STORE, 94436124700672, 94436124798975,
+STORE, 94436124798976, 94436124819455,
+STORE, 140049025044480, 140049025216511,
+ERASE, 140049025044480, 140049025044480,
+STORE, 140049025044480, 140049025048575,
+STORE, 140049025048576, 140049025216511,
+ERASE, 140049025048576, 140049025048576,
+STORE, 140049025048576, 140049025171455,
+STORE, 140049025171456, 140049025204223,
+STORE, 140049025204224, 140049025212415,
+STORE, 140049025212416, 140049025216511,
+STORE, 140726367256576, 140726367260671,
+STORE, 140726367244288, 140726367256575,
+STORE, 47583769952256, 47583769960447,
+STORE, 47583769960448, 47583769968639,
+STORE, 47583769968640, 47583770075135,
+STORE, 47583769985024, 47583770075135,
+STORE, 47583769968640, 47583769985023,
+ERASE, 47583769985024, 47583769985024,
+STORE, 47583769985024, 47583770058751,
+STORE, 47583770058752, 47583770075135,
+STORE, 47583770038272, 47583770058751,
+STORE, 47583769985024, 47583770038271,
+ERASE, 47583769985024, 47583769985024,
+STORE, 47583769985024, 47583770038271,
+STORE, 47583770054656, 47583770058751,
+STORE, 47583770038272, 47583770054655,
+ERASE, 47583770038272, 47583770038272,
+STORE, 47583770038272, 47583770054655,
+STORE, 47583770066944, 47583770075135,
+STORE, 47583770058752, 47583770066943,
+ERASE, 47583770058752, 47583770058752,
+STORE, 47583770058752, 47583770066943,
+ERASE, 47583770066944, 47583770066944,
+STORE, 47583770066944, 47583770075135,
+STORE, 47583770075136, 47583771914239,
+STORE, 47583770214400, 47583771914239,
+STORE, 47583770075136, 47583770214399,
+ERASE, 47583770214400, 47583770214400,
+STORE, 47583770214400, 47583771873279,
+STORE, 47583771873280, 47583771914239,
+STORE, 47583771557888, 47583771873279,
+STORE, 47583770214400, 47583771557887,
+ERASE, 47583770214400, 47583770214400,
+STORE, 47583770214400, 47583771557887,
+STORE, 47583771869184, 47583771873279,
+STORE, 47583771557888, 47583771869183,
+ERASE, 47583771557888, 47583771557888,
+STORE, 47583771557888, 47583771869183,
+STORE, 47583771897856, 47583771914239,
+STORE, 47583771873280, 47583771897855,
+ERASE, 47583771873280, 47583771873280,
+STORE, 47583771873280, 47583771897855,
+ERASE, 47583771897856, 47583771897856,
+STORE, 47583771897856, 47583771914239,
+STORE, 47583771897856, 47583771926527,
+ERASE, 47583771873280, 47583771873280,
+STORE, 47583771873280, 47583771889663,
+STORE, 47583771889664, 47583771897855,
+ERASE, 47583770058752, 47583770058752,
+STORE, 47583770058752, 47583770062847,
+STORE, 47583770062848, 47583770066943,
+ERASE, 94436124798976, 94436124798976,
+STORE, 94436124798976, 94436124815359,
+STORE, 94436124815360, 94436124819455,
+ERASE, 140049025204224, 140049025204224,
+STORE, 140049025204224, 140049025208319,
+STORE, 140049025208320, 140049025212415,
+ERASE, 47583769952256, 47583769952256,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727116099584, 140737488351231,
+ERASE, 140727116099584, 140727116099584,
+STORE, 140727116099584, 140727116103679,
+STORE, 94166319734784, 94166320447487,
+ERASE, 94166319734784, 94166319734784,
+STORE, 94166319734784, 94166319783935,
+STORE, 94166319783936, 94166320447487,
+ERASE, 94166319783936, 94166319783936,
+STORE, 94166319783936, 94166320328703,
+STORE, 94166320328704, 94166320427007,
+STORE, 94166320427008, 94166320447487,
+STORE, 139976559542272, 139976559714303,
+ERASE, 139976559542272, 139976559542272,
+STORE, 139976559542272, 139976559546367,
+STORE, 139976559546368, 139976559714303,
+ERASE, 139976559546368, 139976559546368,
+STORE, 139976559546368, 139976559669247,
+STORE, 139976559669248, 139976559702015,
+STORE, 139976559702016, 139976559710207,
+STORE, 139976559710208, 139976559714303,
+STORE, 140727116222464, 140727116226559,
+STORE, 140727116210176, 140727116222463,
+STORE, 47656235454464, 47656235462655,
+STORE, 47656235462656, 47656235470847,
+STORE, 47656235470848, 47656235577343,
+STORE, 47656235487232, 47656235577343,
+STORE, 47656235470848, 47656235487231,
+ERASE, 47656235487232, 47656235487232,
+STORE, 47656235487232, 47656235560959,
+STORE, 47656235560960, 47656235577343,
+STORE, 47656235540480, 47656235560959,
+STORE, 47656235487232, 47656235540479,
+ERASE, 47656235487232, 47656235487232,
+STORE, 47656235487232, 47656235540479,
+STORE, 47656235556864, 47656235560959,
+STORE, 47656235540480, 47656235556863,
+ERASE, 47656235540480, 47656235540480,
+STORE, 47656235540480, 47656235556863,
+STORE, 47656235569152, 47656235577343,
+STORE, 47656235560960, 47656235569151,
+ERASE, 47656235560960, 47656235560960,
+STORE, 47656235560960, 47656235569151,
+ERASE, 47656235569152, 47656235569152,
+STORE, 47656235569152, 47656235577343,
+STORE, 47656235577344, 47656237416447,
+STORE, 47656235716608, 47656237416447,
+STORE, 47656235577344, 47656235716607,
+ERASE, 47656235716608, 47656235716608,
+STORE, 47656235716608, 47656237375487,
+STORE, 47656237375488, 47656237416447,
+STORE, 47656237060096, 47656237375487,
+STORE, 47656235716608, 47656237060095,
+ERASE, 47656235716608, 47656235716608,
+STORE, 47656235716608, 47656237060095,
+STORE, 47656237371392, 47656237375487,
+STORE, 47656237060096, 47656237371391,
+ERASE, 47656237060096, 47656237060096,
+STORE, 47656237060096, 47656237371391,
+STORE, 47656237400064, 47656237416447,
+STORE, 47656237375488, 47656237400063,
+ERASE, 47656237375488, 47656237375488,
+STORE, 47656237375488, 47656237400063,
+ERASE, 47656237400064, 47656237400064,
+STORE, 47656237400064, 47656237416447,
+STORE, 47656237400064, 47656237428735,
+ERASE, 47656237375488, 47656237375488,
+STORE, 47656237375488, 47656237391871,
+STORE, 47656237391872, 47656237400063,
+ERASE, 47656235560960, 47656235560960,
+STORE, 47656235560960, 47656235565055,
+STORE, 47656235565056, 47656235569151,
+ERASE, 94166320427008, 94166320427008,
+STORE, 94166320427008, 94166320443391,
+STORE, 94166320443392, 94166320447487,
+ERASE, 139976559702016, 139976559702016,
+STORE, 139976559702016, 139976559706111,
+STORE, 139976559706112, 139976559710207,
+ERASE, 47656235454464, 47656235454464,
+STORE, 94166332153856, 94166332289023,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726412816384, 140737488351231,
+ERASE, 140726412816384, 140726412816384,
+STORE, 140726412816384, 140726412820479,
+STORE, 94094884507648, 94094885220351,
+ERASE, 94094884507648, 94094884507648,
+STORE, 94094884507648, 94094884556799,
+STORE, 94094884556800, 94094885220351,
+ERASE, 94094884556800, 94094884556800,
+STORE, 94094884556800, 94094885101567,
+STORE, 94094885101568, 94094885199871,
+STORE, 94094885199872, 94094885220351,
+STORE, 139773773938688, 139773774110719,
+ERASE, 139773773938688, 139773773938688,
+STORE, 139773773938688, 139773773942783,
+STORE, 139773773942784, 139773774110719,
+ERASE, 139773773942784, 139773773942784,
+STORE, 139773773942784, 139773774065663,
+STORE, 139773774065664, 139773774098431,
+STORE, 139773774098432, 139773774106623,
+STORE, 139773774106624, 139773774110719,
+STORE, 140726412963840, 140726412967935,
+STORE, 140726412951552, 140726412963839,
+STORE, 47859021058048, 47859021066239,
+STORE, 47859021066240, 47859021074431,
+STORE, 47859021074432, 47859021180927,
+STORE, 47859021090816, 47859021180927,
+STORE, 47859021074432, 47859021090815,
+ERASE, 47859021090816, 47859021090816,
+STORE, 47859021090816, 47859021164543,
+STORE, 47859021164544, 47859021180927,
+STORE, 47859021144064, 47859021164543,
+STORE, 47859021090816, 47859021144063,
+ERASE, 47859021090816, 47859021090816,
+STORE, 47859021090816, 47859021144063,
+STORE, 47859021160448, 47859021164543,
+STORE, 47859021144064, 47859021160447,
+ERASE, 47859021144064, 47859021144064,
+STORE, 47859021144064, 47859021160447,
+STORE, 47859021172736, 47859021180927,
+STORE, 47859021164544, 47859021172735,
+ERASE, 47859021164544, 47859021164544,
+STORE, 47859021164544, 47859021172735,
+ERASE, 47859021172736, 47859021172736,
+STORE, 47859021172736, 47859021180927,
+STORE, 47859021180928, 47859023020031,
+STORE, 47859021320192, 47859023020031,
+STORE, 47859021180928, 47859021320191,
+ERASE, 47859021320192, 47859021320192,
+STORE, 47859021320192, 47859022979071,
+STORE, 47859022979072, 47859023020031,
+STORE, 47859022663680, 47859022979071,
+STORE, 47859021320192, 47859022663679,
+ERASE, 47859021320192, 47859021320192,
+STORE, 47859021320192, 47859022663679,
+STORE, 47859022974976, 47859022979071,
+STORE, 47859022663680, 47859022974975,
+ERASE, 47859022663680, 47859022663680,
+STORE, 47859022663680, 47859022974975,
+STORE, 47859023003648, 47859023020031,
+STORE, 47859022979072, 47859023003647,
+ERASE, 47859022979072, 47859022979072,
+STORE, 47859022979072, 47859023003647,
+ERASE, 47859023003648, 47859023003648,
+STORE, 47859023003648, 47859023020031,
+STORE, 47859023003648, 47859023032319,
+ERASE, 47859022979072, 47859022979072,
+STORE, 47859022979072, 47859022995455,
+STORE, 47859022995456, 47859023003647,
+ERASE, 47859021164544, 47859021164544,
+STORE, 47859021164544, 47859021168639,
+STORE, 47859021168640, 47859021172735,
+ERASE, 94094885199872, 94094885199872,
+STORE, 94094885199872, 94094885216255,
+STORE, 94094885216256, 94094885220351,
+ERASE, 139773774098432, 139773774098432,
+STORE, 139773774098432, 139773774102527,
+STORE, 139773774102528, 139773774106623,
+ERASE, 47859021058048, 47859021058048,
+STORE, 94094901108736, 94094901243903,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736567963648, 140737488351231,
+ERASE, 140736567963648, 140736567963648,
+STORE, 140736567963648, 140736567967743,
+STORE, 94924425748480, 94924426461183,
+ERASE, 94924425748480, 94924425748480,
+STORE, 94924425748480, 94924425797631,
+STORE, 94924425797632, 94924426461183,
+ERASE, 94924425797632, 94924425797632,
+STORE, 94924425797632, 94924426342399,
+STORE, 94924426342400, 94924426440703,
+STORE, 94924426440704, 94924426461183,
+STORE, 140042126319616, 140042126491647,
+ERASE, 140042126319616, 140042126319616,
+STORE, 140042126319616, 140042126323711,
+STORE, 140042126323712, 140042126491647,
+ERASE, 140042126323712, 140042126323712,
+STORE, 140042126323712, 140042126446591,
+STORE, 140042126446592, 140042126479359,
+STORE, 140042126479360, 140042126487551,
+STORE, 140042126487552, 140042126491647,
+STORE, 140736568672256, 140736568676351,
+STORE, 140736568659968, 140736568672255,
+STORE, 47590668677120, 47590668685311,
+STORE, 47590668685312, 47590668693503,
+STORE, 47590668693504, 47590668799999,
+STORE, 47590668709888, 47590668799999,
+STORE, 47590668693504, 47590668709887,
+ERASE, 47590668709888, 47590668709888,
+STORE, 47590668709888, 47590668783615,
+STORE, 47590668783616, 47590668799999,
+STORE, 47590668763136, 47590668783615,
+STORE, 47590668709888, 47590668763135,
+ERASE, 47590668709888, 47590668709888,
+STORE, 47590668709888, 47590668763135,
+STORE, 47590668779520, 47590668783615,
+STORE, 47590668763136, 47590668779519,
+ERASE, 47590668763136, 47590668763136,
+STORE, 47590668763136, 47590668779519,
+STORE, 47590668791808, 47590668799999,
+STORE, 47590668783616, 47590668791807,
+ERASE, 47590668783616, 47590668783616,
+STORE, 47590668783616, 47590668791807,
+ERASE, 47590668791808, 47590668791808,
+STORE, 47590668791808, 47590668799999,
+STORE, 47590668800000, 47590670639103,
+STORE, 47590668939264, 47590670639103,
+STORE, 47590668800000, 47590668939263,
+ERASE, 47590668939264, 47590668939264,
+STORE, 47590668939264, 47590670598143,
+STORE, 47590670598144, 47590670639103,
+STORE, 47590670282752, 47590670598143,
+STORE, 47590668939264, 47590670282751,
+ERASE, 47590668939264, 47590668939264,
+STORE, 47590668939264, 47590670282751,
+STORE, 47590670594048, 47590670598143,
+STORE, 47590670282752, 47590670594047,
+ERASE, 47590670282752, 47590670282752,
+STORE, 47590670282752, 47590670594047,
+STORE, 47590670622720, 47590670639103,
+STORE, 47590670598144, 47590670622719,
+ERASE, 47590670598144, 47590670598144,
+STORE, 47590670598144, 47590670622719,
+ERASE, 47590670622720, 47590670622720,
+STORE, 47590670622720, 47590670639103,
+STORE, 47590670622720, 47590670651391,
+ERASE, 47590670598144, 47590670598144,
+STORE, 47590670598144, 47590670614527,
+STORE, 47590670614528, 47590670622719,
+ERASE, 47590668783616, 47590668783616,
+STORE, 47590668783616, 47590668787711,
+STORE, 47590668787712, 47590668791807,
+ERASE, 94924426440704, 94924426440704,
+STORE, 94924426440704, 94924426457087,
+STORE, 94924426457088, 94924426461183,
+ERASE, 140042126479360, 140042126479360,
+STORE, 140042126479360, 140042126483455,
+STORE, 140042126483456, 140042126487551,
+ERASE, 47590668677120, 47590668677120,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733281439744, 140737488351231,
+ERASE, 140733281439744, 140733281439744,
+STORE, 140733281439744, 140733281443839,
+STORE, 94490667069440, 94490667782143,
+ERASE, 94490667069440, 94490667069440,
+STORE, 94490667069440, 94490667118591,
+STORE, 94490667118592, 94490667782143,
+ERASE, 94490667118592, 94490667118592,
+STORE, 94490667118592, 94490667663359,
+STORE, 94490667663360, 94490667761663,
+STORE, 94490667761664, 94490667782143,
+STORE, 139878215118848, 139878215290879,
+ERASE, 139878215118848, 139878215118848,
+STORE, 139878215118848, 139878215122943,
+STORE, 139878215122944, 139878215290879,
+ERASE, 139878215122944, 139878215122944,
+STORE, 139878215122944, 139878215245823,
+STORE, 139878215245824, 139878215278591,
+STORE, 139878215278592, 139878215286783,
+STORE, 139878215286784, 139878215290879,
+STORE, 140733281464320, 140733281468415,
+STORE, 140733281452032, 140733281464319,
+STORE, 47754579877888, 47754579886079,
+STORE, 47754579886080, 47754579894271,
+STORE, 47754579894272, 47754580000767,
+STORE, 47754579910656, 47754580000767,
+STORE, 47754579894272, 47754579910655,
+ERASE, 47754579910656, 47754579910656,
+STORE, 47754579910656, 47754579984383,
+STORE, 47754579984384, 47754580000767,
+STORE, 47754579963904, 47754579984383,
+STORE, 47754579910656, 47754579963903,
+ERASE, 47754579910656, 47754579910656,
+STORE, 47754579910656, 47754579963903,
+STORE, 47754579980288, 47754579984383,
+STORE, 47754579963904, 47754579980287,
+ERASE, 47754579963904, 47754579963904,
+STORE, 47754579963904, 47754579980287,
+STORE, 47754579992576, 47754580000767,
+STORE, 47754579984384, 47754579992575,
+ERASE, 47754579984384, 47754579984384,
+STORE, 47754579984384, 47754579992575,
+ERASE, 47754579992576, 47754579992576,
+STORE, 47754579992576, 47754580000767,
+STORE, 47754580000768, 47754581839871,
+STORE, 47754580140032, 47754581839871,
+STORE, 47754580000768, 47754580140031,
+ERASE, 47754580140032, 47754580140032,
+STORE, 47754580140032, 47754581798911,
+STORE, 47754581798912, 47754581839871,
+STORE, 47754581483520, 47754581798911,
+STORE, 47754580140032, 47754581483519,
+ERASE, 47754580140032, 47754580140032,
+STORE, 47754580140032, 47754581483519,
+STORE, 47754581794816, 47754581798911,
+STORE, 47754581483520, 47754581794815,
+ERASE, 47754581483520, 47754581483520,
+STORE, 47754581483520, 47754581794815,
+STORE, 47754581823488, 47754581839871,
+STORE, 47754581798912, 47754581823487,
+ERASE, 47754581798912, 47754581798912,
+STORE, 47754581798912, 47754581823487,
+ERASE, 47754581823488, 47754581823488,
+STORE, 47754581823488, 47754581839871,
+STORE, 47754581823488, 47754581852159,
+ERASE, 47754581798912, 47754581798912,
+STORE, 47754581798912, 47754581815295,
+STORE, 47754581815296, 47754581823487,
+ERASE, 47754579984384, 47754579984384,
+STORE, 47754579984384, 47754579988479,
+STORE, 47754579988480, 47754579992575,
+ERASE, 94490667761664, 94490667761664,
+STORE, 94490667761664, 94490667778047,
+STORE, 94490667778048, 94490667782143,
+ERASE, 139878215278592, 139878215278592,
+STORE, 139878215278592, 139878215282687,
+STORE, 139878215282688, 139878215286783,
+ERASE, 47754579877888, 47754579877888,
+STORE, 94490669649920, 94490669785087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140735382188032, 140737488351231,
+ERASE, 140735382188032, 140735382188032,
+STORE, 140735382188032, 140735382192127,
+STORE, 94150181302272, 94150182014975,
+ERASE, 94150181302272, 94150181302272,
+STORE, 94150181302272, 94150181351423,
+STORE, 94150181351424, 94150182014975,
+ERASE, 94150181351424, 94150181351424,
+STORE, 94150181351424, 94150181896191,
+STORE, 94150181896192, 94150181994495,
+STORE, 94150181994496, 94150182014975,
+STORE, 139679752458240, 139679752630271,
+ERASE, 139679752458240, 139679752458240,
+STORE, 139679752458240, 139679752462335,
+STORE, 139679752462336, 139679752630271,
+ERASE, 139679752462336, 139679752462336,
+STORE, 139679752462336, 139679752585215,
+STORE, 139679752585216, 139679752617983,
+STORE, 139679752617984, 139679752626175,
+STORE, 139679752626176, 139679752630271,
+STORE, 140735382536192, 140735382540287,
+STORE, 140735382523904, 140735382536191,
+STORE, 47953042538496, 47953042546687,
+STORE, 47953042546688, 47953042554879,
+STORE, 47953042554880, 47953042661375,
+STORE, 47953042571264, 47953042661375,
+STORE, 47953042554880, 47953042571263,
+ERASE, 47953042571264, 47953042571264,
+STORE, 47953042571264, 47953042644991,
+STORE, 47953042644992, 47953042661375,
+STORE, 47953042624512, 47953042644991,
+STORE, 47953042571264, 47953042624511,
+ERASE, 47953042571264, 47953042571264,
+STORE, 47953042571264, 47953042624511,
+STORE, 47953042640896, 47953042644991,
+STORE, 47953042624512, 47953042640895,
+ERASE, 47953042624512, 47953042624512,
+STORE, 47953042624512, 47953042640895,
+STORE, 47953042653184, 47953042661375,
+STORE, 47953042644992, 47953042653183,
+ERASE, 47953042644992, 47953042644992,
+STORE, 47953042644992, 47953042653183,
+ERASE, 47953042653184, 47953042653184,
+STORE, 47953042653184, 47953042661375,
+STORE, 47953042661376, 47953044500479,
+STORE, 47953042800640, 47953044500479,
+STORE, 47953042661376, 47953042800639,
+ERASE, 47953042800640, 47953042800640,
+STORE, 47953042800640, 47953044459519,
+STORE, 47953044459520, 47953044500479,
+STORE, 47953044144128, 47953044459519,
+STORE, 47953042800640, 47953044144127,
+ERASE, 47953042800640, 47953042800640,
+STORE, 47953042800640, 47953044144127,
+STORE, 47953044455424, 47953044459519,
+STORE, 47953044144128, 47953044455423,
+ERASE, 47953044144128, 47953044144128,
+STORE, 47953044144128, 47953044455423,
+STORE, 47953044484096, 47953044500479,
+STORE, 47953044459520, 47953044484095,
+ERASE, 47953044459520, 47953044459520,
+STORE, 47953044459520, 47953044484095,
+ERASE, 47953044484096, 47953044484096,
+STORE, 47953044484096, 47953044500479,
+STORE, 47953044484096, 47953044512767,
+ERASE, 47953044459520, 47953044459520,
+STORE, 47953044459520, 47953044475903,
+STORE, 47953044475904, 47953044484095,
+ERASE, 47953042644992, 47953042644992,
+STORE, 47953042644992, 47953042649087,
+STORE, 47953042649088, 47953042653183,
+ERASE, 94150181994496, 94150181994496,
+STORE, 94150181994496, 94150182010879,
+STORE, 94150182010880, 94150182014975,
+ERASE, 139679752617984, 139679752617984,
+STORE, 139679752617984, 139679752622079,
+STORE, 139679752622080, 139679752626175,
+ERASE, 47953042538496, 47953042538496,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737044123648, 140737488351231,
+ERASE, 140737044123648, 140737044123648,
+STORE, 140737044123648, 140737044127743,
+STORE, 94425324294144, 94425325006847,
+ERASE, 94425324294144, 94425324294144,
+STORE, 94425324294144, 94425324343295,
+STORE, 94425324343296, 94425325006847,
+ERASE, 94425324343296, 94425324343296,
+STORE, 94425324343296, 94425324888063,
+STORE, 94425324888064, 94425324986367,
+STORE, 94425324986368, 94425325006847,
+STORE, 140382015016960, 140382015188991,
+ERASE, 140382015016960, 140382015016960,
+STORE, 140382015016960, 140382015021055,
+STORE, 140382015021056, 140382015188991,
+ERASE, 140382015021056, 140382015021056,
+STORE, 140382015021056, 140382015143935,
+STORE, 140382015143936, 140382015176703,
+STORE, 140382015176704, 140382015184895,
+STORE, 140382015184896, 140382015188991,
+STORE, 140737045585920, 140737045590015,
+STORE, 140737045573632, 140737045585919,
+STORE, 47250779979776, 47250779987967,
+STORE, 47250779987968, 47250779996159,
+STORE, 47250779996160, 47250780102655,
+STORE, 47250780012544, 47250780102655,
+STORE, 47250779996160, 47250780012543,
+ERASE, 47250780012544, 47250780012544,
+STORE, 47250780012544, 47250780086271,
+STORE, 47250780086272, 47250780102655,
+STORE, 47250780065792, 47250780086271,
+STORE, 47250780012544, 47250780065791,
+ERASE, 47250780012544, 47250780012544,
+STORE, 47250780012544, 47250780065791,
+STORE, 47250780082176, 47250780086271,
+STORE, 47250780065792, 47250780082175,
+ERASE, 47250780065792, 47250780065792,
+STORE, 47250780065792, 47250780082175,
+STORE, 47250780094464, 47250780102655,
+STORE, 47250780086272, 47250780094463,
+ERASE, 47250780086272, 47250780086272,
+STORE, 47250780086272, 47250780094463,
+ERASE, 47250780094464, 47250780094464,
+STORE, 47250780094464, 47250780102655,
+STORE, 47250780102656, 47250781941759,
+STORE, 47250780241920, 47250781941759,
+STORE, 47250780102656, 47250780241919,
+ERASE, 47250780241920, 47250780241920,
+STORE, 47250780241920, 47250781900799,
+STORE, 47250781900800, 47250781941759,
+STORE, 47250781585408, 47250781900799,
+STORE, 47250780241920, 47250781585407,
+ERASE, 47250780241920, 47250780241920,
+STORE, 47250780241920, 47250781585407,
+STORE, 47250781896704, 47250781900799,
+STORE, 47250781585408, 47250781896703,
+ERASE, 47250781585408, 47250781585408,
+STORE, 47250781585408, 47250781896703,
+STORE, 47250781925376, 47250781941759,
+STORE, 47250781900800, 47250781925375,
+ERASE, 47250781900800, 47250781900800,
+STORE, 47250781900800, 47250781925375,
+ERASE, 47250781925376, 47250781925376,
+STORE, 47250781925376, 47250781941759,
+STORE, 47250781925376, 47250781954047,
+ERASE, 47250781900800, 47250781900800,
+STORE, 47250781900800, 47250781917183,
+STORE, 47250781917184, 47250781925375,
+ERASE, 47250780086272, 47250780086272,
+STORE, 47250780086272, 47250780090367,
+STORE, 47250780090368, 47250780094463,
+ERASE, 94425324986368, 94425324986368,
+STORE, 94425324986368, 94425325002751,
+STORE, 94425325002752, 94425325006847,
+ERASE, 140382015176704, 140382015176704,
+STORE, 140382015176704, 140382015180799,
+STORE, 140382015180800, 140382015184895,
+ERASE, 47250779979776, 47250779979776,
+STORE, 94425351438336, 94425351573503,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736801144832, 140737488351231,
+ERASE, 140736801144832, 140736801144832,
+STORE, 140736801144832, 140736801148927,
+STORE, 94629429358592, 94629430071295,
+ERASE, 94629429358592, 94629429358592,
+STORE, 94629429358592, 94629429407743,
+STORE, 94629429407744, 94629430071295,
+ERASE, 94629429407744, 94629429407744,
+STORE, 94629429407744, 94629429952511,
+STORE, 94629429952512, 94629430050815,
+STORE, 94629430050816, 94629430071295,
+STORE, 139801685483520, 139801685655551,
+ERASE, 139801685483520, 139801685483520,
+STORE, 139801685483520, 139801685487615,
+STORE, 139801685487616, 139801685655551,
+ERASE, 139801685487616, 139801685487616,
+STORE, 139801685487616, 139801685610495,
+STORE, 139801685610496, 139801685643263,
+STORE, 139801685643264, 139801685651455,
+STORE, 139801685651456, 139801685655551,
+STORE, 140736801198080, 140736801202175,
+STORE, 140736801185792, 140736801198079,
+STORE, 47831109513216, 47831109521407,
+STORE, 47831109521408, 47831109529599,
+STORE, 47831109529600, 47831109636095,
+STORE, 47831109545984, 47831109636095,
+STORE, 47831109529600, 47831109545983,
+ERASE, 47831109545984, 47831109545984,
+STORE, 47831109545984, 47831109619711,
+STORE, 47831109619712, 47831109636095,
+STORE, 47831109599232, 47831109619711,
+STORE, 47831109545984, 47831109599231,
+ERASE, 47831109545984, 47831109545984,
+STORE, 47831109545984, 47831109599231,
+STORE, 47831109615616, 47831109619711,
+STORE, 47831109599232, 47831109615615,
+ERASE, 47831109599232, 47831109599232,
+STORE, 47831109599232, 47831109615615,
+STORE, 47831109627904, 47831109636095,
+STORE, 47831109619712, 47831109627903,
+ERASE, 47831109619712, 47831109619712,
+STORE, 47831109619712, 47831109627903,
+ERASE, 47831109627904, 47831109627904,
+STORE, 47831109627904, 47831109636095,
+STORE, 47831109636096, 47831111475199,
+STORE, 47831109775360, 47831111475199,
+STORE, 47831109636096, 47831109775359,
+ERASE, 47831109775360, 47831109775360,
+STORE, 47831109775360, 47831111434239,
+STORE, 47831111434240, 47831111475199,
+STORE, 47831111118848, 47831111434239,
+STORE, 47831109775360, 47831111118847,
+ERASE, 47831109775360, 47831109775360,
+STORE, 47831109775360, 47831111118847,
+STORE, 47831111430144, 47831111434239,
+STORE, 47831111118848, 47831111430143,
+ERASE, 47831111118848, 47831111118848,
+STORE, 47831111118848, 47831111430143,
+STORE, 47831111458816, 47831111475199,
+STORE, 47831111434240, 47831111458815,
+ERASE, 47831111434240, 47831111434240,
+STORE, 47831111434240, 47831111458815,
+ERASE, 47831111458816, 47831111458816,
+STORE, 47831111458816, 47831111475199,
+STORE, 47831111458816, 47831111487487,
+ERASE, 47831111434240, 47831111434240,
+STORE, 47831111434240, 47831111450623,
+STORE, 47831111450624, 47831111458815,
+ERASE, 47831109619712, 47831109619712,
+STORE, 47831109619712, 47831109623807,
+STORE, 47831109623808, 47831109627903,
+ERASE, 94629430050816, 94629430050816,
+STORE, 94629430050816, 94629430067199,
+STORE, 94629430067200, 94629430071295,
+ERASE, 139801685643264, 139801685643264,
+STORE, 139801685643264, 139801685647359,
+STORE, 139801685647360, 139801685651455,
+ERASE, 47831109513216, 47831109513216,
+STORE, 140737488347136, 140737488351231,
+STORE, 140729419612160, 140737488351231,
+ERASE, 140729419612160, 140729419612160,
+STORE, 140729419612160, 140729419616255,
+STORE, 94443354148864, 94443354861567,
+ERASE, 94443354148864, 94443354148864,
+STORE, 94443354148864, 94443354198015,
+STORE, 94443354198016, 94443354861567,
+ERASE, 94443354198016, 94443354198016,
+STORE, 94443354198016, 94443354742783,
+STORE, 94443354742784, 94443354841087,
+STORE, 94443354841088, 94443354861567,
+STORE, 139741700038656, 139741700210687,
+ERASE, 139741700038656, 139741700038656,
+STORE, 139741700038656, 139741700042751,
+STORE, 139741700042752, 139741700210687,
+ERASE, 139741700042752, 139741700042752,
+STORE, 139741700042752, 139741700165631,
+STORE, 139741700165632, 139741700198399,
+STORE, 139741700198400, 139741700206591,
+STORE, 139741700206592, 139741700210687,
+STORE, 140729420574720, 140729420578815,
+STORE, 140729420562432, 140729420574719,
+STORE, 47891094958080, 47891094966271,
+STORE, 47891094966272, 47891094974463,
+STORE, 47891094974464, 47891095080959,
+STORE, 47891094990848, 47891095080959,
+STORE, 47891094974464, 47891094990847,
+ERASE, 47891094990848, 47891094990848,
+STORE, 47891094990848, 47891095064575,
+STORE, 47891095064576, 47891095080959,
+STORE, 47891095044096, 47891095064575,
+STORE, 47891094990848, 47891095044095,
+ERASE, 47891094990848, 47891094990848,
+STORE, 47891094990848, 47891095044095,
+STORE, 47891095060480, 47891095064575,
+STORE, 47891095044096, 47891095060479,
+ERASE, 47891095044096, 47891095044096,
+STORE, 47891095044096, 47891095060479,
+STORE, 47891095072768, 47891095080959,
+STORE, 47891095064576, 47891095072767,
+ERASE, 47891095064576, 47891095064576,
+STORE, 47891095064576, 47891095072767,
+ERASE, 47891095072768, 47891095072768,
+STORE, 47891095072768, 47891095080959,
+STORE, 47891095080960, 47891096920063,
+STORE, 47891095220224, 47891096920063,
+STORE, 47891095080960, 47891095220223,
+ERASE, 47891095220224, 47891095220224,
+STORE, 47891095220224, 47891096879103,
+STORE, 47891096879104, 47891096920063,
+STORE, 47891096563712, 47891096879103,
+STORE, 47891095220224, 47891096563711,
+ERASE, 47891095220224, 47891095220224,
+STORE, 47891095220224, 47891096563711,
+STORE, 47891096875008, 47891096879103,
+STORE, 47891096563712, 47891096875007,
+ERASE, 47891096563712, 47891096563712,
+STORE, 47891096563712, 47891096875007,
+STORE, 47891096903680, 47891096920063,
+STORE, 47891096879104, 47891096903679,
+ERASE, 47891096879104, 47891096879104,
+STORE, 47891096879104, 47891096903679,
+ERASE, 47891096903680, 47891096903680,
+STORE, 47891096903680, 47891096920063,
+STORE, 47891096903680, 47891096932351,
+ERASE, 47891096879104, 47891096879104,
+STORE, 47891096879104, 47891096895487,
+STORE, 47891096895488, 47891096903679,
+ERASE, 47891095064576, 47891095064576,
+STORE, 47891095064576, 47891095068671,
+STORE, 47891095068672, 47891095072767,
+ERASE, 94443354841088, 94443354841088,
+STORE, 94443354841088, 94443354857471,
+STORE, 94443354857472, 94443354861567,
+ERASE, 139741700198400, 139741700198400,
+STORE, 139741700198400, 139741700202495,
+STORE, 139741700202496, 139741700206591,
+ERASE, 47891094958080, 47891094958080,
+STORE, 94443360825344, 94443360960511,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722961661952, 140737488351231,
+ERASE, 140722961661952, 140722961661952,
+STORE, 140722961661952, 140722961666047,
+STORE, 94878388944896, 94878389657599,
+ERASE, 94878388944896, 94878388944896,
+STORE, 94878388944896, 94878388994047,
+STORE, 94878388994048, 94878389657599,
+ERASE, 94878388994048, 94878388994048,
+STORE, 94878388994048, 94878389538815,
+STORE, 94878389538816, 94878389637119,
+STORE, 94878389637120, 94878389657599,
+STORE, 140210690056192, 140210690228223,
+ERASE, 140210690056192, 140210690056192,
+STORE, 140210690056192, 140210690060287,
+STORE, 140210690060288, 140210690228223,
+ERASE, 140210690060288, 140210690060288,
+STORE, 140210690060288, 140210690183167,
+STORE, 140210690183168, 140210690215935,
+STORE, 140210690215936, 140210690224127,
+STORE, 140210690224128, 140210690228223,
+STORE, 140722963148800, 140722963152895,
+STORE, 140722963136512, 140722963148799,
+STORE, 47422104940544, 47422104948735,
+STORE, 47422104948736, 47422104956927,
+STORE, 47422104956928, 47422105063423,
+STORE, 47422104973312, 47422105063423,
+STORE, 47422104956928, 47422104973311,
+ERASE, 47422104973312, 47422104973312,
+STORE, 47422104973312, 47422105047039,
+STORE, 47422105047040, 47422105063423,
+STORE, 47422105026560, 47422105047039,
+STORE, 47422104973312, 47422105026559,
+ERASE, 47422104973312, 47422104973312,
+STORE, 47422104973312, 47422105026559,
+STORE, 47422105042944, 47422105047039,
+STORE, 47422105026560, 47422105042943,
+ERASE, 47422105026560, 47422105026560,
+STORE, 47422105026560, 47422105042943,
+STORE, 47422105055232, 47422105063423,
+STORE, 47422105047040, 47422105055231,
+ERASE, 47422105047040, 47422105047040,
+STORE, 47422105047040, 47422105055231,
+ERASE, 47422105055232, 47422105055232,
+STORE, 47422105055232, 47422105063423,
+STORE, 47422105063424, 47422106902527,
+STORE, 47422105202688, 47422106902527,
+STORE, 47422105063424, 47422105202687,
+ERASE, 47422105202688, 47422105202688,
+STORE, 47422105202688, 47422106861567,
+STORE, 47422106861568, 47422106902527,
+STORE, 47422106546176, 47422106861567,
+STORE, 47422105202688, 47422106546175,
+ERASE, 47422105202688, 47422105202688,
+STORE, 47422105202688, 47422106546175,
+STORE, 47422106857472, 47422106861567,
+STORE, 47422106546176, 47422106857471,
+ERASE, 47422106546176, 47422106546176,
+STORE, 47422106546176, 47422106857471,
+STORE, 47422106886144, 47422106902527,
+STORE, 47422106861568, 47422106886143,
+ERASE, 47422106861568, 47422106861568,
+STORE, 47422106861568, 47422106886143,
+ERASE, 47422106886144, 47422106886144,
+STORE, 47422106886144, 47422106902527,
+STORE, 47422106886144, 47422106914815,
+ERASE, 47422106861568, 47422106861568,
+STORE, 47422106861568, 47422106877951,
+STORE, 47422106877952, 47422106886143,
+ERASE, 47422105047040, 47422105047040,
+STORE, 47422105047040, 47422105051135,
+STORE, 47422105051136, 47422105055231,
+ERASE, 94878389637120, 94878389637120,
+STORE, 94878389637120, 94878389653503,
+STORE, 94878389653504, 94878389657599,
+ERASE, 140210690215936, 140210690215936,
+STORE, 140210690215936, 140210690220031,
+STORE, 140210690220032, 140210690224127,
+ERASE, 47422104940544, 47422104940544,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727690309632, 140737488351231,
+ERASE, 140727690309632, 140727690309632,
+STORE, 140727690309632, 140727690313727,
+STORE, 94121892208640, 94121892921343,
+ERASE, 94121892208640, 94121892208640,
+STORE, 94121892208640, 94121892257791,
+STORE, 94121892257792, 94121892921343,
+ERASE, 94121892257792, 94121892257792,
+STORE, 94121892257792, 94121892802559,
+STORE, 94121892802560, 94121892900863,
+STORE, 94121892900864, 94121892921343,
+STORE, 140662438326272, 140662438498303,
+ERASE, 140662438326272, 140662438326272,
+STORE, 140662438326272, 140662438330367,
+STORE, 140662438330368, 140662438498303,
+ERASE, 140662438330368, 140662438330368,
+STORE, 140662438330368, 140662438453247,
+STORE, 140662438453248, 140662438486015,
+STORE, 140662438486016, 140662438494207,
+STORE, 140662438494208, 140662438498303,
+STORE, 140727690379264, 140727690383359,
+STORE, 140727690366976, 140727690379263,
+STORE, 46970356670464, 46970356678655,
+STORE, 46970356678656, 46970356686847,
+STORE, 46970356686848, 46970356793343,
+STORE, 46970356703232, 46970356793343,
+STORE, 46970356686848, 46970356703231,
+ERASE, 46970356703232, 46970356703232,
+STORE, 46970356703232, 46970356776959,
+STORE, 46970356776960, 46970356793343,
+STORE, 46970356756480, 46970356776959,
+STORE, 46970356703232, 46970356756479,
+ERASE, 46970356703232, 46970356703232,
+STORE, 46970356703232, 46970356756479,
+STORE, 46970356772864, 46970356776959,
+STORE, 46970356756480, 46970356772863,
+ERASE, 46970356756480, 46970356756480,
+STORE, 46970356756480, 46970356772863,
+STORE, 46970356785152, 46970356793343,
+STORE, 46970356776960, 46970356785151,
+ERASE, 46970356776960, 46970356776960,
+STORE, 46970356776960, 46970356785151,
+ERASE, 46970356785152, 46970356785152,
+STORE, 46970356785152, 46970356793343,
+STORE, 46970356793344, 46970358632447,
+STORE, 46970356932608, 46970358632447,
+STORE, 46970356793344, 46970356932607,
+ERASE, 46970356932608, 46970356932608,
+STORE, 46970356932608, 46970358591487,
+STORE, 46970358591488, 46970358632447,
+STORE, 46970358276096, 46970358591487,
+STORE, 46970356932608, 46970358276095,
+ERASE, 46970356932608, 46970356932608,
+STORE, 46970356932608, 46970358276095,
+STORE, 46970358587392, 46970358591487,
+STORE, 46970358276096, 46970358587391,
+ERASE, 46970358276096, 46970358276096,
+STORE, 46970358276096, 46970358587391,
+STORE, 46970358616064, 46970358632447,
+STORE, 46970358591488, 46970358616063,
+ERASE, 46970358591488, 46970358591488,
+STORE, 46970358591488, 46970358616063,
+ERASE, 46970358616064, 46970358616064,
+STORE, 46970358616064, 46970358632447,
+STORE, 46970358616064, 46970358644735,
+ERASE, 46970358591488, 46970358591488,
+STORE, 46970358591488, 46970358607871,
+STORE, 46970358607872, 46970358616063,
+ERASE, 46970356776960, 46970356776960,
+STORE, 46970356776960, 46970356781055,
+STORE, 46970356781056, 46970356785151,
+ERASE, 94121892900864, 94121892900864,
+STORE, 94121892900864, 94121892917247,
+STORE, 94121892917248, 94121892921343,
+ERASE, 140662438486016, 140662438486016,
+STORE, 140662438486016, 140662438490111,
+STORE, 140662438490112, 140662438494207,
+ERASE, 46970356670464, 46970356670464,
+STORE, 94121898610688, 94121898745855,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737189351424, 140737488351231,
+ERASE, 140737189351424, 140737189351424,
+STORE, 140737189351424, 140737189355519,
+STORE, 93847948832768, 93847949545471,
+ERASE, 93847948832768, 93847948832768,
+STORE, 93847948832768, 93847948881919,
+STORE, 93847948881920, 93847949545471,
+ERASE, 93847948881920, 93847948881920,
+STORE, 93847948881920, 93847949426687,
+STORE, 93847949426688, 93847949524991,
+STORE, 93847949524992, 93847949545471,
+STORE, 139698989985792, 139698990157823,
+ERASE, 139698989985792, 139698989985792,
+STORE, 139698989985792, 139698989989887,
+STORE, 139698989989888, 139698990157823,
+ERASE, 139698989989888, 139698989989888,
+STORE, 139698989989888, 139698990112767,
+STORE, 139698990112768, 139698990145535,
+STORE, 139698990145536, 139698990153727,
+STORE, 139698990153728, 139698990157823,
+STORE, 140737189744640, 140737189748735,
+STORE, 140737189732352, 140737189744639,
+STORE, 47933805010944, 47933805019135,
+STORE, 47933805019136, 47933805027327,
+STORE, 47933805027328, 47933805133823,
+STORE, 47933805043712, 47933805133823,
+STORE, 47933805027328, 47933805043711,
+ERASE, 47933805043712, 47933805043712,
+STORE, 47933805043712, 47933805117439,
+STORE, 47933805117440, 47933805133823,
+STORE, 47933805096960, 47933805117439,
+STORE, 47933805043712, 47933805096959,
+ERASE, 47933805043712, 47933805043712,
+STORE, 47933805043712, 47933805096959,
+STORE, 47933805113344, 47933805117439,
+STORE, 47933805096960, 47933805113343,
+ERASE, 47933805096960, 47933805096960,
+STORE, 47933805096960, 47933805113343,
+STORE, 47933805125632, 47933805133823,
+STORE, 47933805117440, 47933805125631,
+ERASE, 47933805117440, 47933805117440,
+STORE, 47933805117440, 47933805125631,
+ERASE, 47933805125632, 47933805125632,
+STORE, 47933805125632, 47933805133823,
+STORE, 47933805133824, 47933806972927,
+STORE, 47933805273088, 47933806972927,
+STORE, 47933805133824, 47933805273087,
+ERASE, 47933805273088, 47933805273088,
+STORE, 47933805273088, 47933806931967,
+STORE, 47933806931968, 47933806972927,
+STORE, 47933806616576, 47933806931967,
+STORE, 47933805273088, 47933806616575,
+ERASE, 47933805273088, 47933805273088,
+STORE, 47933805273088, 47933806616575,
+STORE, 47933806927872, 47933806931967,
+STORE, 47933806616576, 47933806927871,
+ERASE, 47933806616576, 47933806616576,
+STORE, 47933806616576, 47933806927871,
+STORE, 47933806956544, 47933806972927,
+STORE, 47933806931968, 47933806956543,
+ERASE, 47933806931968, 47933806931968,
+STORE, 47933806931968, 47933806956543,
+ERASE, 47933806956544, 47933806956544,
+STORE, 47933806956544, 47933806972927,
+STORE, 47933806956544, 47933806985215,
+ERASE, 47933806931968, 47933806931968,
+STORE, 47933806931968, 47933806948351,
+STORE, 47933806948352, 47933806956543,
+ERASE, 47933805117440, 47933805117440,
+STORE, 47933805117440, 47933805121535,
+STORE, 47933805121536, 47933805125631,
+ERASE, 93847949524992, 93847949524992,
+STORE, 93847949524992, 93847949541375,
+STORE, 93847949541376, 93847949545471,
+ERASE, 139698990145536, 139698990145536,
+STORE, 139698990145536, 139698990149631,
+STORE, 139698990149632, 139698990153727,
+ERASE, 47933805010944, 47933805010944,
+STORE, 140737488347136, 140737488351231,
+STORE, 140725553991680, 140737488351231,
+ERASE, 140725553991680, 140725553991680,
+STORE, 140725553991680, 140725553995775,
+STORE, 93980056248320, 93980056961023,
+ERASE, 93980056248320, 93980056248320,
+STORE, 93980056248320, 93980056297471,
+STORE, 93980056297472, 93980056961023,
+ERASE, 93980056297472, 93980056297472,
+STORE, 93980056297472, 93980056842239,
+STORE, 93980056842240, 93980056940543,
+STORE, 93980056940544, 93980056961023,
+STORE, 140146588971008, 140146589143039,
+ERASE, 140146588971008, 140146588971008,
+STORE, 140146588971008, 140146588975103,
+STORE, 140146588975104, 140146589143039,
+ERASE, 140146588975104, 140146588975104,
+STORE, 140146588975104, 140146589097983,
+STORE, 140146589097984, 140146589130751,
+STORE, 140146589130752, 140146589138943,
+STORE, 140146589138944, 140146589143039,
+STORE, 140725554860032, 140725554864127,
+STORE, 140725554847744, 140725554860031,
+STORE, 47486206025728, 47486206033919,
+STORE, 47486206033920, 47486206042111,
+STORE, 47486206042112, 47486206148607,
+STORE, 47486206058496, 47486206148607,
+STORE, 47486206042112, 47486206058495,
+ERASE, 47486206058496, 47486206058496,
+STORE, 47486206058496, 47486206132223,
+STORE, 47486206132224, 47486206148607,
+STORE, 47486206111744, 47486206132223,
+STORE, 47486206058496, 47486206111743,
+ERASE, 47486206058496, 47486206058496,
+STORE, 47486206058496, 47486206111743,
+STORE, 47486206128128, 47486206132223,
+STORE, 47486206111744, 47486206128127,
+ERASE, 47486206111744, 47486206111744,
+STORE, 47486206111744, 47486206128127,
+STORE, 47486206140416, 47486206148607,
+STORE, 47486206132224, 47486206140415,
+ERASE, 47486206132224, 47486206132224,
+STORE, 47486206132224, 47486206140415,
+ERASE, 47486206140416, 47486206140416,
+STORE, 47486206140416, 47486206148607,
+STORE, 47486206148608, 47486207987711,
+STORE, 47486206287872, 47486207987711,
+STORE, 47486206148608, 47486206287871,
+ERASE, 47486206287872, 47486206287872,
+STORE, 47486206287872, 47486207946751,
+STORE, 47486207946752, 47486207987711,
+STORE, 47486207631360, 47486207946751,
+STORE, 47486206287872, 47486207631359,
+ERASE, 47486206287872, 47486206287872,
+STORE, 47486206287872, 47486207631359,
+STORE, 47486207942656, 47486207946751,
+STORE, 47486207631360, 47486207942655,
+ERASE, 47486207631360, 47486207631360,
+STORE, 47486207631360, 47486207942655,
+STORE, 47486207971328, 47486207987711,
+STORE, 47486207946752, 47486207971327,
+ERASE, 47486207946752, 47486207946752,
+STORE, 47486207946752, 47486207971327,
+ERASE, 47486207971328, 47486207971328,
+STORE, 47486207971328, 47486207987711,
+STORE, 47486207971328, 47486207999999,
+ERASE, 47486207946752, 47486207946752,
+STORE, 47486207946752, 47486207963135,
+STORE, 47486207963136, 47486207971327,
+ERASE, 47486206132224, 47486206132224,
+STORE, 47486206132224, 47486206136319,
+STORE, 47486206136320, 47486206140415,
+ERASE, 93980056940544, 93980056940544,
+STORE, 93980056940544, 93980056956927,
+STORE, 93980056956928, 93980056961023,
+ERASE, 140146589130752, 140146589130752,
+STORE, 140146589130752, 140146589134847,
+STORE, 140146589134848, 140146589138943,
+ERASE, 47486206025728, 47486206025728,
+STORE, 93980070006784, 93980070141951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727334776832, 140737488351231,
+ERASE, 140727334776832, 140727334776832,
+STORE, 140727334776832, 140727334780927,
+STORE, 94049747247104, 94049747959807,
+ERASE, 94049747247104, 94049747247104,
+STORE, 94049747247104, 94049747296255,
+STORE, 94049747296256, 94049747959807,
+ERASE, 94049747296256, 94049747296256,
+STORE, 94049747296256, 94049747841023,
+STORE, 94049747841024, 94049747939327,
+STORE, 94049747939328, 94049747959807,
+STORE, 140227307216896, 140227307388927,
+ERASE, 140227307216896, 140227307216896,
+STORE, 140227307216896, 140227307220991,
+STORE, 140227307220992, 140227307388927,
+ERASE, 140227307220992, 140227307220992,
+STORE, 140227307220992, 140227307343871,
+STORE, 140227307343872, 140227307376639,
+STORE, 140227307376640, 140227307384831,
+STORE, 140227307384832, 140227307388927,
+STORE, 140727335337984, 140727335342079,
+STORE, 140727335325696, 140727335337983,
+STORE, 47405487779840, 47405487788031,
+STORE, 47405487788032, 47405487796223,
+STORE, 47405487796224, 47405487902719,
+STORE, 47405487812608, 47405487902719,
+STORE, 47405487796224, 47405487812607,
+ERASE, 47405487812608, 47405487812608,
+STORE, 47405487812608, 47405487886335,
+STORE, 47405487886336, 47405487902719,
+STORE, 47405487865856, 47405487886335,
+STORE, 47405487812608, 47405487865855,
+ERASE, 47405487812608, 47405487812608,
+STORE, 47405487812608, 47405487865855,
+STORE, 47405487882240, 47405487886335,
+STORE, 47405487865856, 47405487882239,
+ERASE, 47405487865856, 47405487865856,
+STORE, 47405487865856, 47405487882239,
+STORE, 47405487894528, 47405487902719,
+STORE, 47405487886336, 47405487894527,
+ERASE, 47405487886336, 47405487886336,
+STORE, 47405487886336, 47405487894527,
+ERASE, 47405487894528, 47405487894528,
+STORE, 47405487894528, 47405487902719,
+STORE, 47405487902720, 47405489741823,
+STORE, 47405488041984, 47405489741823,
+STORE, 47405487902720, 47405488041983,
+ERASE, 47405488041984, 47405488041984,
+STORE, 47405488041984, 47405489700863,
+STORE, 47405489700864, 47405489741823,
+STORE, 47405489385472, 47405489700863,
+STORE, 47405488041984, 47405489385471,
+ERASE, 47405488041984, 47405488041984,
+STORE, 47405488041984, 47405489385471,
+STORE, 47405489696768, 47405489700863,
+STORE, 47405489385472, 47405489696767,
+ERASE, 47405489385472, 47405489385472,
+STORE, 47405489385472, 47405489696767,
+STORE, 47405489725440, 47405489741823,
+STORE, 47405489700864, 47405489725439,
+ERASE, 47405489700864, 47405489700864,
+STORE, 47405489700864, 47405489725439,
+ERASE, 47405489725440, 47405489725440,
+STORE, 47405489725440, 47405489741823,
+STORE, 47405489725440, 47405489754111,
+ERASE, 47405489700864, 47405489700864,
+STORE, 47405489700864, 47405489717247,
+STORE, 47405489717248, 47405489725439,
+ERASE, 47405487886336, 47405487886336,
+STORE, 47405487886336, 47405487890431,
+STORE, 47405487890432, 47405487894527,
+ERASE, 94049747939328, 94049747939328,
+STORE, 94049747939328, 94049747955711,
+STORE, 94049747955712, 94049747959807,
+ERASE, 140227307376640, 140227307376640,
+STORE, 140227307376640, 140227307380735,
+STORE, 140227307380736, 140227307384831,
+ERASE, 47405487779840, 47405487779840,
+STORE, 94049758810112, 94049758945279,
+STORE, 140737488347136, 140737488351231,
+STORE, 140727079718912, 140737488351231,
+ERASE, 140727079718912, 140727079718912,
+STORE, 140727079718912, 140727079723007,
+STORE, 94250996527104, 94250997239807,
+ERASE, 94250996527104, 94250996527104,
+STORE, 94250996527104, 94250996576255,
+STORE, 94250996576256, 94250997239807,
+ERASE, 94250996576256, 94250996576256,
+STORE, 94250996576256, 94250997121023,
+STORE, 94250997121024, 94250997219327,
+STORE, 94250997219328, 94250997239807,
+STORE, 140060022587392, 140060022759423,
+ERASE, 140060022587392, 140060022587392,
+STORE, 140060022587392, 140060022591487,
+STORE, 140060022591488, 140060022759423,
+ERASE, 140060022591488, 140060022591488,
+STORE, 140060022591488, 140060022714367,
+STORE, 140060022714368, 140060022747135,
+STORE, 140060022747136, 140060022755327,
+STORE, 140060022755328, 140060022759423,
+STORE, 140727079788544, 140727079792639,
+STORE, 140727079776256, 140727079788543,
+STORE, 47572772409344, 47572772417535,
+STORE, 47572772417536, 47572772425727,
+STORE, 47572772425728, 47572772532223,
+STORE, 47572772442112, 47572772532223,
+STORE, 47572772425728, 47572772442111,
+ERASE, 47572772442112, 47572772442112,
+STORE, 47572772442112, 47572772515839,
+STORE, 47572772515840, 47572772532223,
+STORE, 47572772495360, 47572772515839,
+STORE, 47572772442112, 47572772495359,
+ERASE, 47572772442112, 47572772442112,
+STORE, 47572772442112, 47572772495359,
+STORE, 47572772511744, 47572772515839,
+STORE, 47572772495360, 47572772511743,
+ERASE, 47572772495360, 47572772495360,
+STORE, 47572772495360, 47572772511743,
+STORE, 47572772524032, 47572772532223,
+STORE, 47572772515840, 47572772524031,
+ERASE, 47572772515840, 47572772515840,
+STORE, 47572772515840, 47572772524031,
+ERASE, 47572772524032, 47572772524032,
+STORE, 47572772524032, 47572772532223,
+STORE, 47572772532224, 47572774371327,
+STORE, 47572772671488, 47572774371327,
+STORE, 47572772532224, 47572772671487,
+ERASE, 47572772671488, 47572772671488,
+STORE, 47572772671488, 47572774330367,
+STORE, 47572774330368, 47572774371327,
+STORE, 47572774014976, 47572774330367,
+STORE, 47572772671488, 47572774014975,
+ERASE, 47572772671488, 47572772671488,
+STORE, 47572772671488, 47572774014975,
+STORE, 47572774326272, 47572774330367,
+STORE, 47572774014976, 47572774326271,
+ERASE, 47572774014976, 47572774014976,
+STORE, 47572774014976, 47572774326271,
+STORE, 47572774354944, 47572774371327,
+STORE, 47572774330368, 47572774354943,
+ERASE, 47572774330368, 47572774330368,
+STORE, 47572774330368, 47572774354943,
+ERASE, 47572774354944, 47572774354944,
+STORE, 47572774354944, 47572774371327,
+STORE, 47572774354944, 47572774383615,
+ERASE, 47572774330368, 47572774330368,
+STORE, 47572774330368, 47572774346751,
+STORE, 47572774346752, 47572774354943,
+ERASE, 47572772515840, 47572772515840,
+STORE, 47572772515840, 47572772519935,
+STORE, 47572772519936, 47572772524031,
+ERASE, 94250997219328, 94250997219328,
+STORE, 94250997219328, 94250997235711,
+STORE, 94250997235712, 94250997239807,
+ERASE, 140060022747136, 140060022747136,
+STORE, 140060022747136, 140060022751231,
+STORE, 140060022751232, 140060022755327,
+ERASE, 47572772409344, 47572772409344,
+STORE, 94251018305536, 94251018440703,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730012389376, 140737488351231,
+ERASE, 140730012389376, 140730012389376,
+STORE, 140730012389376, 140730012393471,
+STORE, 94382607675392, 94382607695871,
+ERASE, 94382607675392, 94382607675392,
+STORE, 94382607675392, 94382607679487,
+STORE, 94382607679488, 94382607695871,
+ERASE, 94382607679488, 94382607679488,
+STORE, 94382607679488, 94382607683583,
+STORE, 94382607683584, 94382607687679,
+STORE, 94382607687680, 94382607695871,
+STORE, 140252451454976, 140252451627007,
+ERASE, 140252451454976, 140252451454976,
+STORE, 140252451454976, 140252451459071,
+STORE, 140252451459072, 140252451627007,
+ERASE, 140252451459072, 140252451459072,
+STORE, 140252451459072, 140252451581951,
+STORE, 140252451581952, 140252451614719,
+STORE, 140252451614720, 140252451622911,
+STORE, 140252451622912, 140252451627007,
+STORE, 140730013548544, 140730013552639,
+STORE, 140730013536256, 140730013548543,
+STORE, 47380343541760, 47380343549951,
+STORE, 47380343549952, 47380343558143,
+STORE, 47380343558144, 47380345397247,
+STORE, 47380343697408, 47380345397247,
+STORE, 47380343558144, 47380343697407,
+ERASE, 47380343697408, 47380343697408,
+STORE, 47380343697408, 47380345356287,
+STORE, 47380345356288, 47380345397247,
+STORE, 47380345040896, 47380345356287,
+STORE, 47380343697408, 47380345040895,
+ERASE, 47380343697408, 47380343697408,
+STORE, 47380343697408, 47380345040895,
+STORE, 47380345352192, 47380345356287,
+STORE, 47380345040896, 47380345352191,
+ERASE, 47380345040896, 47380345040896,
+STORE, 47380345040896, 47380345352191,
+STORE, 47380345380864, 47380345397247,
+STORE, 47380345356288, 47380345380863,
+ERASE, 47380345356288, 47380345356288,
+STORE, 47380345356288, 47380345380863,
+ERASE, 47380345380864, 47380345380864,
+STORE, 47380345380864, 47380345397247,
+ERASE, 47380345356288, 47380345356288,
+STORE, 47380345356288, 47380345372671,
+STORE, 47380345372672, 47380345380863,
+ERASE, 94382607687680, 94382607687680,
+STORE, 94382607687680, 94382607691775,
+STORE, 94382607691776, 94382607695871,
+ERASE, 140252451614720, 140252451614720,
+STORE, 140252451614720, 140252451618815,
+STORE, 140252451618816, 140252451622911,
+ERASE, 47380343541760, 47380343541760,
+STORE, 94382626803712, 94382626938879,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730900271104, 140737488351231,
+ERASE, 140730900271104, 140730900271104,
+STORE, 140730900271104, 140730900275199,
+STORE, 93855478120448, 93855478337535,
+ERASE, 93855478120448, 93855478120448,
+STORE, 93855478120448, 93855478198271,
+STORE, 93855478198272, 93855478337535,
+ERASE, 93855478198272, 93855478198272,
+STORE, 93855478198272, 93855478243327,
+STORE, 93855478243328, 93855478288383,
+STORE, 93855478288384, 93855478337535,
+STORE, 140092686573568, 140092686745599,
+ERASE, 140092686573568, 140092686573568,
+STORE, 140092686573568, 140092686577663,
+STORE, 140092686577664, 140092686745599,
+ERASE, 140092686577664, 140092686577664,
+STORE, 140092686577664, 140092686700543,
+STORE, 140092686700544, 140092686733311,
+STORE, 140092686733312, 140092686741503,
+STORE, 140092686741504, 140092686745599,
+STORE, 140730900537344, 140730900541439,
+STORE, 140730900525056, 140730900537343,
+STORE, 47540108423168, 47540108431359,
+STORE, 47540108431360, 47540108439551,
+STORE, 47540108439552, 47540110278655,
+STORE, 47540108578816, 47540110278655,
+STORE, 47540108439552, 47540108578815,
+ERASE, 47540108578816, 47540108578816,
+STORE, 47540108578816, 47540110237695,
+STORE, 47540110237696, 47540110278655,
+STORE, 47540109922304, 47540110237695,
+STORE, 47540108578816, 47540109922303,
+ERASE, 47540108578816, 47540108578816,
+STORE, 47540108578816, 47540109922303,
+STORE, 47540110233600, 47540110237695,
+STORE, 47540109922304, 47540110233599,
+ERASE, 47540109922304, 47540109922304,
+STORE, 47540109922304, 47540110233599,
+STORE, 47540110262272, 47540110278655,
+STORE, 47540110237696, 47540110262271,
+ERASE, 47540110237696, 47540110237696,
+STORE, 47540110237696, 47540110262271,
+ERASE, 47540110262272, 47540110262272,
+STORE, 47540110262272, 47540110278655,
+ERASE, 47540110237696, 47540110237696,
+STORE, 47540110237696, 47540110254079,
+STORE, 47540110254080, 47540110262271,
+ERASE, 93855478288384, 93855478288384,
+STORE, 93855478288384, 93855478333439,
+STORE, 93855478333440, 93855478337535,
+ERASE, 140092686733312, 140092686733312,
+STORE, 140092686733312, 140092686737407,
+STORE, 140092686737408, 140092686741503,
+ERASE, 47540108423168, 47540108423168,
+STORE, 93855492222976, 93855492358143,
+STORE, 93855492222976, 93855492493311,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733498146816, 140737488351231,
+ERASE, 140733498146816, 140733498146816,
+STORE, 140733498146816, 140733498150911,
+STORE, 94170739654656, 94170740367359,
+ERASE, 94170739654656, 94170739654656,
+STORE, 94170739654656, 94170739703807,
+STORE, 94170739703808, 94170740367359,
+ERASE, 94170739703808, 94170739703808,
+STORE, 94170739703808, 94170740248575,
+STORE, 94170740248576, 94170740346879,
+STORE, 94170740346880, 94170740367359,
+STORE, 140024788877312, 140024789049343,
+ERASE, 140024788877312, 140024788877312,
+STORE, 140024788877312, 140024788881407,
+STORE, 140024788881408, 140024789049343,
+ERASE, 140024788881408, 140024788881408,
+STORE, 140024788881408, 140024789004287,
+STORE, 140024789004288, 140024789037055,
+STORE, 140024789037056, 140024789045247,
+STORE, 140024789045248, 140024789049343,
+STORE, 140733499023360, 140733499027455,
+STORE, 140733499011072, 140733499023359,
+STORE, 47608006119424, 47608006127615,
+STORE, 47608006127616, 47608006135807,
+STORE, 47608006135808, 47608006242303,
+STORE, 47608006152192, 47608006242303,
+STORE, 47608006135808, 47608006152191,
+ERASE, 47608006152192, 47608006152192,
+STORE, 47608006152192, 47608006225919,
+STORE, 47608006225920, 47608006242303,
+STORE, 47608006205440, 47608006225919,
+STORE, 47608006152192, 47608006205439,
+ERASE, 47608006152192, 47608006152192,
+STORE, 47608006152192, 47608006205439,
+STORE, 47608006221824, 47608006225919,
+STORE, 47608006205440, 47608006221823,
+ERASE, 47608006205440, 47608006205440,
+STORE, 47608006205440, 47608006221823,
+STORE, 47608006234112, 47608006242303,
+STORE, 47608006225920, 47608006234111,
+ERASE, 47608006225920, 47608006225920,
+STORE, 47608006225920, 47608006234111,
+ERASE, 47608006234112, 47608006234112,
+STORE, 47608006234112, 47608006242303,
+STORE, 47608006242304, 47608008081407,
+STORE, 47608006381568, 47608008081407,
+STORE, 47608006242304, 47608006381567,
+ERASE, 47608006381568, 47608006381568,
+STORE, 47608006381568, 47608008040447,
+STORE, 47608008040448, 47608008081407,
+STORE, 47608007725056, 47608008040447,
+STORE, 47608006381568, 47608007725055,
+ERASE, 47608006381568, 47608006381568,
+STORE, 47608006381568, 47608007725055,
+STORE, 47608008036352, 47608008040447,
+STORE, 47608007725056, 47608008036351,
+ERASE, 47608007725056, 47608007725056,
+STORE, 47608007725056, 47608008036351,
+STORE, 47608008065024, 47608008081407,
+STORE, 47608008040448, 47608008065023,
+ERASE, 47608008040448, 47608008040448,
+STORE, 47608008040448, 47608008065023,
+ERASE, 47608008065024, 47608008065024,
+STORE, 47608008065024, 47608008081407,
+STORE, 47608008065024, 47608008093695,
+ERASE, 47608008040448, 47608008040448,
+STORE, 47608008040448, 47608008056831,
+STORE, 47608008056832, 47608008065023,
+ERASE, 47608006225920, 47608006225920,
+STORE, 47608006225920, 47608006230015,
+STORE, 47608006230016, 47608006234111,
+ERASE, 94170740346880, 94170740346880,
+STORE, 94170740346880, 94170740363263,
+STORE, 94170740363264, 94170740367359,
+ERASE, 140024789037056, 140024789037056,
+STORE, 140024789037056, 140024789041151,
+STORE, 140024789041152, 140024789045247,
+ERASE, 47608006119424, 47608006119424,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730264326144, 140737488351231,
+ERASE, 140730264326144, 140730264326144,
+STORE, 140730264326144, 140730264330239,
+STORE, 94653216407552, 94653217120255,
+ERASE, 94653216407552, 94653216407552,
+STORE, 94653216407552, 94653216456703,
+STORE, 94653216456704, 94653217120255,
+ERASE, 94653216456704, 94653216456704,
+STORE, 94653216456704, 94653217001471,
+STORE, 94653217001472, 94653217099775,
+STORE, 94653217099776, 94653217120255,
+STORE, 140103617011712, 140103617183743,
+ERASE, 140103617011712, 140103617011712,
+STORE, 140103617011712, 140103617015807,
+STORE, 140103617015808, 140103617183743,
+ERASE, 140103617015808, 140103617015808,
+STORE, 140103617015808, 140103617138687,
+STORE, 140103617138688, 140103617171455,
+STORE, 140103617171456, 140103617179647,
+STORE, 140103617179648, 140103617183743,
+STORE, 140730265427968, 140730265432063,
+STORE, 140730265415680, 140730265427967,
+STORE, 47529177985024, 47529177993215,
+STORE, 47529177993216, 47529178001407,
+STORE, 47529178001408, 47529178107903,
+STORE, 47529178017792, 47529178107903,
+STORE, 47529178001408, 47529178017791,
+ERASE, 47529178017792, 47529178017792,
+STORE, 47529178017792, 47529178091519,
+STORE, 47529178091520, 47529178107903,
+STORE, 47529178071040, 47529178091519,
+STORE, 47529178017792, 47529178071039,
+ERASE, 47529178017792, 47529178017792,
+STORE, 47529178017792, 47529178071039,
+STORE, 47529178087424, 47529178091519,
+STORE, 47529178071040, 47529178087423,
+ERASE, 47529178071040, 47529178071040,
+STORE, 47529178071040, 47529178087423,
+STORE, 47529178099712, 47529178107903,
+STORE, 47529178091520, 47529178099711,
+ERASE, 47529178091520, 47529178091520,
+STORE, 47529178091520, 47529178099711,
+ERASE, 47529178099712, 47529178099712,
+STORE, 47529178099712, 47529178107903,
+STORE, 47529178107904, 47529179947007,
+STORE, 47529178247168, 47529179947007,
+STORE, 47529178107904, 47529178247167,
+ERASE, 47529178247168, 47529178247168,
+STORE, 47529178247168, 47529179906047,
+STORE, 47529179906048, 47529179947007,
+STORE, 47529179590656, 47529179906047,
+STORE, 47529178247168, 47529179590655,
+ERASE, 47529178247168, 47529178247168,
+STORE, 47529178247168, 47529179590655,
+STORE, 47529179901952, 47529179906047,
+STORE, 47529179590656, 47529179901951,
+ERASE, 47529179590656, 47529179590656,
+STORE, 47529179590656, 47529179901951,
+STORE, 47529179930624, 47529179947007,
+STORE, 47529179906048, 47529179930623,
+ERASE, 47529179906048, 47529179906048,
+STORE, 47529179906048, 47529179930623,
+ERASE, 47529179930624, 47529179930624,
+STORE, 47529179930624, 47529179947007,
+STORE, 47529179930624, 47529179959295,
+ERASE, 47529179906048, 47529179906048,
+STORE, 47529179906048, 47529179922431,
+STORE, 47529179922432, 47529179930623,
+ERASE, 47529178091520, 47529178091520,
+STORE, 47529178091520, 47529178095615,
+STORE, 47529178095616, 47529178099711,
+ERASE, 94653217099776, 94653217099776,
+STORE, 94653217099776, 94653217116159,
+STORE, 94653217116160, 94653217120255,
+ERASE, 140103617171456, 140103617171456,
+STORE, 140103617171456, 140103617175551,
+STORE, 140103617175552, 140103617179647,
+ERASE, 47529177985024, 47529177985024,
+STORE, 94653241135104, 94653241270271,
+STORE, 140737488347136, 140737488351231,
+STORE, 140736284549120, 140737488351231,
+ERASE, 140736284549120, 140736284549120,
+STORE, 140736284549120, 140736284553215,
+STORE, 93963663822848, 93963664506879,
+ERASE, 93963663822848, 93963663822848,
+STORE, 93963663822848, 93963663884287,
+STORE, 93963663884288, 93963664506879,
+ERASE, 93963663884288, 93963663884288,
+STORE, 93963663884288, 93963664240639,
+STORE, 93963664240640, 93963664379903,
+STORE, 93963664379904, 93963664506879,
+STORE, 140450188439552, 140450188611583,
+ERASE, 140450188439552, 140450188439552,
+STORE, 140450188439552, 140450188443647,
+STORE, 140450188443648, 140450188611583,
+ERASE, 140450188443648, 140450188443648,
+STORE, 140450188443648, 140450188566527,
+STORE, 140450188566528, 140450188599295,
+STORE, 140450188599296, 140450188607487,
+STORE, 140450188607488, 140450188611583,
+STORE, 140736284577792, 140736284581887,
+STORE, 140736284565504, 140736284577791,
+STORE, 47182606557184, 47182606565375,
+STORE, 47182606565376, 47182606573567,
+STORE, 47182606573568, 47182608412671,
+STORE, 47182606712832, 47182608412671,
+STORE, 47182606573568, 47182606712831,
+ERASE, 47182606712832, 47182606712832,
+STORE, 47182606712832, 47182608371711,
+STORE, 47182608371712, 47182608412671,
+STORE, 47182608056320, 47182608371711,
+STORE, 47182606712832, 47182608056319,
+ERASE, 47182606712832, 47182606712832,
+STORE, 47182606712832, 47182608056319,
+STORE, 47182608367616, 47182608371711,
+STORE, 47182608056320, 47182608367615,
+ERASE, 47182608056320, 47182608056320,
+STORE, 47182608056320, 47182608367615,
+STORE, 47182608396288, 47182608412671,
+STORE, 47182608371712, 47182608396287,
+ERASE, 47182608371712, 47182608371712,
+STORE, 47182608371712, 47182608396287,
+ERASE, 47182608396288, 47182608396288,
+STORE, 47182608396288, 47182608412671,
+STORE, 47182608412672, 47182608523263,
+STORE, 47182608429056, 47182608523263,
+STORE, 47182608412672, 47182608429055,
+ERASE, 47182608429056, 47182608429056,
+STORE, 47182608429056, 47182608515071,
+STORE, 47182608515072, 47182608523263,
+STORE, 47182608490496, 47182608515071,
+STORE, 47182608429056, 47182608490495,
+ERASE, 47182608429056, 47182608429056,
+STORE, 47182608429056, 47182608490495,
+STORE, 47182608510976, 47182608515071,
+STORE, 47182608490496, 47182608510975,
+ERASE, 47182608490496, 47182608490496,
+STORE, 47182608490496, 47182608510975,
+ERASE, 47182608515072, 47182608515072,
+STORE, 47182608515072, 47182608523263,
+STORE, 47182608523264, 47182608568319,
+ERASE, 47182608523264, 47182608523264,
+STORE, 47182608523264, 47182608531455,
+STORE, 47182608531456, 47182608568319,
+STORE, 47182608551936, 47182608568319,
+STORE, 47182608531456, 47182608551935,
+ERASE, 47182608531456, 47182608531456,
+STORE, 47182608531456, 47182608551935,
+STORE, 47182608560128, 47182608568319,
+STORE, 47182608551936, 47182608560127,
+ERASE, 47182608551936, 47182608551936,
+STORE, 47182608551936, 47182608568319,
+ERASE, 47182608551936, 47182608551936,
+STORE, 47182608551936, 47182608560127,
+STORE, 47182608560128, 47182608568319,
+ERASE, 47182608560128, 47182608560128,
+STORE, 47182608560128, 47182608568319,
+STORE, 47182608568320, 47182608916479,
+STORE, 47182608609280, 47182608916479,
+STORE, 47182608568320, 47182608609279,
+ERASE, 47182608609280, 47182608609280,
+STORE, 47182608609280, 47182608891903,
+STORE, 47182608891904, 47182608916479,
+STORE, 47182608822272, 47182608891903,
+STORE, 47182608609280, 47182608822271,
+ERASE, 47182608609280, 47182608609280,
+STORE, 47182608609280, 47182608822271,
+STORE, 47182608887808, 47182608891903,
+STORE, 47182608822272, 47182608887807,
+ERASE, 47182608822272, 47182608822272,
+STORE, 47182608822272, 47182608887807,
+ERASE, 47182608891904, 47182608891904,
+STORE, 47182608891904, 47182608916479,
+STORE, 47182608916480, 47182611177471,
+STORE, 47182609068032, 47182611177471,
+STORE, 47182608916480, 47182609068031,
+ERASE, 47182609068032, 47182609068032,
+STORE, 47182609068032, 47182611161087,
+STORE, 47182611161088, 47182611177471,
+STORE, 47182611169280, 47182611177471,
+STORE, 47182611161088, 47182611169279,
+ERASE, 47182611161088, 47182611161088,
+STORE, 47182611161088, 47182611169279,
+ERASE, 47182611169280, 47182611169280,
+STORE, 47182611169280, 47182611177471,
+STORE, 47182611177472, 47182611312639,
+ERASE, 47182611177472, 47182611177472,
+STORE, 47182611177472, 47182611202047,
+STORE, 47182611202048, 47182611312639,
+STORE, 47182611263488, 47182611312639,
+STORE, 47182611202048, 47182611263487,
+ERASE, 47182611202048, 47182611202048,
+STORE, 47182611202048, 47182611263487,
+STORE, 47182611288064, 47182611312639,
+STORE, 47182611263488, 47182611288063,
+ERASE, 47182611263488, 47182611263488,
+STORE, 47182611263488, 47182611312639,
+ERASE, 47182611263488, 47182611263488,
+STORE, 47182611263488, 47182611288063,
+STORE, 47182611288064, 47182611312639,
+STORE, 47182611296256, 47182611312639,
+STORE, 47182611288064, 47182611296255,
+ERASE, 47182611288064, 47182611288064,
+STORE, 47182611288064, 47182611296255,
+ERASE, 47182611296256, 47182611296256,
+STORE, 47182611296256, 47182611312639,
+STORE, 47182611296256, 47182611320831,
+STORE, 47182611320832, 47182611484671,
+ERASE, 47182611320832, 47182611320832,
+STORE, 47182611320832, 47182611333119,
+STORE, 47182611333120, 47182611484671,
+STORE, 47182611431424, 47182611484671,
+STORE, 47182611333120, 47182611431423,
+ERASE, 47182611333120, 47182611333120,
+STORE, 47182611333120, 47182611431423,
+STORE, 47182611476480, 47182611484671,
+STORE, 47182611431424, 47182611476479,
+ERASE, 47182611431424, 47182611431424,
+STORE, 47182611431424, 47182611484671,
+ERASE, 47182611431424, 47182611431424,
+STORE, 47182611431424, 47182611476479,
+STORE, 47182611476480, 47182611484671,
+ERASE, 47182611476480, 47182611476480,
+STORE, 47182611476480, 47182611484671,
+STORE, 47182611484672, 47182612082687,
+STORE, 47182611603456, 47182612082687,
+STORE, 47182611484672, 47182611603455,
+ERASE, 47182611603456, 47182611603456,
+STORE, 47182611603456, 47182612029439,
+STORE, 47182612029440, 47182612082687,
+STORE, 47182611918848, 47182612029439,
+STORE, 47182611603456, 47182611918847,
+ERASE, 47182611603456, 47182611603456,
+STORE, 47182611603456, 47182611918847,
+STORE, 47182612025344, 47182612029439,
+STORE, 47182611918848, 47182612025343,
+ERASE, 47182611918848, 47182611918848,
+STORE, 47182611918848, 47182612025343,
+ERASE, 47182612029440, 47182612029440,
+STORE, 47182612029440, 47182612082687,
+STORE, 47182612082688, 47182615134207,
+STORE, 47182612627456, 47182615134207,
+STORE, 47182612082688, 47182612627455,
+ERASE, 47182612627456, 47182612627456,
+STORE, 47182612627456, 47182614913023,
+STORE, 47182614913024, 47182615134207,
+STORE, 47182614323200, 47182614913023,
+STORE, 47182612627456, 47182614323199,
+ERASE, 47182612627456, 47182612627456,
+STORE, 47182612627456, 47182614323199,
+STORE, 47182614908928, 47182614913023,
+STORE, 47182614323200, 47182614908927,
+ERASE, 47182614323200, 47182614323200,
+STORE, 47182614323200, 47182614908927,
+STORE, 47182615117824, 47182615134207,
+STORE, 47182614913024, 47182615117823,
+ERASE, 47182614913024, 47182614913024,
+STORE, 47182614913024, 47182615117823,
+ERASE, 47182615117824, 47182615117824,
+STORE, 47182615117824, 47182615134207,
+STORE, 47182615134208, 47182615166975,
+ERASE, 47182615134208, 47182615134208,
+STORE, 47182615134208, 47182615142399,
+STORE, 47182615142400, 47182615166975,
+STORE, 47182615154688, 47182615166975,
+STORE, 47182615142400, 47182615154687,
+ERASE, 47182615142400, 47182615142400,
+STORE, 47182615142400, 47182615154687,
+STORE, 47182615158784, 47182615166975,
+STORE, 47182615154688, 47182615158783,
+ERASE, 47182615154688, 47182615154688,
+STORE, 47182615154688, 47182615166975,
+ERASE, 47182615154688, 47182615154688,
+STORE, 47182615154688, 47182615158783,
+STORE, 47182615158784, 47182615166975,
+ERASE, 47182615158784, 47182615158784,
+STORE, 47182615158784, 47182615166975,
+STORE, 47182615166976, 47182615203839,
+ERASE, 47182615166976, 47182615166976,
+STORE, 47182615166976, 47182615175167,
+STORE, 47182615175168, 47182615203839,
+STORE, 47182615191552, 47182615203839,
+STORE, 47182615175168, 47182615191551,
+ERASE, 47182615175168, 47182615175168,
+STORE, 47182615175168, 47182615191551,
+STORE, 47182615195648, 47182615203839,
+STORE, 47182615191552, 47182615195647,
+ERASE, 47182615191552, 47182615191552,
+STORE, 47182615191552, 47182615203839,
+ERASE, 47182615191552, 47182615191552,
+STORE, 47182615191552, 47182615195647,
+STORE, 47182615195648, 47182615203839,
+ERASE, 47182615195648, 47182615195648,
+STORE, 47182615195648, 47182615203839,
+STORE, 47182615203840, 47182615678975,
+ERASE, 47182615203840, 47182615203840,
+STORE, 47182615203840, 47182615212031,
+STORE, 47182615212032, 47182615678975,
+STORE, 47182615547904, 47182615678975,
+STORE, 47182615212032, 47182615547903,
+ERASE, 47182615212032, 47182615212032,
+STORE, 47182615212032, 47182615547903,
+STORE, 47182615670784, 47182615678975,
+STORE, 47182615547904, 47182615670783,
+ERASE, 47182615547904, 47182615547904,
+STORE, 47182615547904, 47182615678975,
+ERASE, 47182615547904, 47182615547904,
+STORE, 47182615547904, 47182615670783,
+STORE, 47182615670784, 47182615678975,
+ERASE, 47182615670784, 47182615670784,
+STORE, 47182615670784, 47182615678975,
+STORE, 47182615678976, 47182615687167,
+STORE, 47182615687168, 47182615707647,
+ERASE, 47182615687168, 47182615687168,
+STORE, 47182615687168, 47182615691263,
+STORE, 47182615691264, 47182615707647,
+STORE, 47182615695360, 47182615707647,
+STORE, 47182615691264, 47182615695359,
+ERASE, 47182615691264, 47182615691264,
+STORE, 47182615691264, 47182615695359,
+STORE, 47182615699456, 47182615707647,
+STORE, 47182615695360, 47182615699455,
+ERASE, 47182615695360, 47182615695360,
+STORE, 47182615695360, 47182615707647,
+ERASE, 47182615695360, 47182615695360,
+STORE, 47182615695360, 47182615699455,
+STORE, 47182615699456, 47182615707647,
+ERASE, 47182615699456, 47182615699456,
+STORE, 47182615699456, 47182615707647,
+STORE, 47182615707648, 47182615715839,
+ERASE, 47182608371712, 47182608371712,
+STORE, 47182608371712, 47182608388095,
+STORE, 47182608388096, 47182608396287,
+ERASE, 47182615699456, 47182615699456,
+STORE, 47182615699456, 47182615703551,
+STORE, 47182615703552, 47182615707647,
+ERASE, 47182611288064, 47182611288064,
+STORE, 47182611288064, 47182611292159,
+STORE, 47182611292160, 47182611296255,
+ERASE, 47182615670784, 47182615670784,
+STORE, 47182615670784, 47182615674879,
+STORE, 47182615674880, 47182615678975,
+ERASE, 47182615195648, 47182615195648,
+STORE, 47182615195648, 47182615199743,
+STORE, 47182615199744, 47182615203839,
+ERASE, 47182615158784, 47182615158784,
+STORE, 47182615158784, 47182615162879,
+STORE, 47182615162880, 47182615166975,
+ERASE, 47182614913024, 47182614913024,
+STORE, 47182614913024, 47182615109631,
+STORE, 47182615109632, 47182615117823,
+ERASE, 47182612029440, 47182612029440,
+STORE, 47182612029440, 47182612066303,
+STORE, 47182612066304, 47182612082687,
+ERASE, 47182611476480, 47182611476480,
+STORE, 47182611476480, 47182611480575,
+STORE, 47182611480576, 47182611484671,
+ERASE, 47182611161088, 47182611161088,
+STORE, 47182611161088, 47182611165183,
+STORE, 47182611165184, 47182611169279,
+ERASE, 47182608891904, 47182608891904,
+STORE, 47182608891904, 47182608912383,
+STORE, 47182608912384, 47182608916479,
+ERASE, 47182608560128, 47182608560128,
+STORE, 47182608560128, 47182608564223,
+STORE, 47182608564224, 47182608568319,
+ERASE, 47182608515072, 47182608515072,
+STORE, 47182608515072, 47182608519167,
+STORE, 47182608519168, 47182608523263,
+ERASE, 93963664379904, 93963664379904,
+STORE, 93963664379904, 93963664502783,
+STORE, 93963664502784, 93963664506879,
+ERASE, 140450188599296, 140450188599296,
+STORE, 140450188599296, 140450188603391,
+STORE, 140450188603392, 140450188607487,
+ERASE, 47182606557184, 47182606557184,
+STORE, 93963694723072, 93963694858239,
+STORE, 140737488347136, 140737488351231,
+STORE, 140730313261056, 140737488351231,
+ERASE, 140730313261056, 140730313261056,
+STORE, 140730313261056, 140730313265151,
+STORE, 94386579017728, 94386579697663,
+ERASE, 94386579017728, 94386579017728,
+STORE, 94386579017728, 94386579083263,
+STORE, 94386579083264, 94386579697663,
+ERASE, 94386579083264, 94386579083264,
+STORE, 94386579083264, 94386579431423,
+STORE, 94386579431424, 94386579570687,
+STORE, 94386579570688, 94386579697663,
+STORE, 140124810838016, 140124811010047,
+ERASE, 140124810838016, 140124810838016,
+STORE, 140124810838016, 140124810842111,
+STORE, 140124810842112, 140124811010047,
+ERASE, 140124810842112, 140124810842112,
+STORE, 140124810842112, 140124810964991,
+STORE, 140124810964992, 140124810997759,
+STORE, 140124810997760, 140124811005951,
+STORE, 140124811005952, 140124811010047,
+STORE, 140730313601024, 140730313605119,
+STORE, 140730313588736, 140730313601023,
+STORE, 47507984158720, 47507984166911,
+STORE, 47507984166912, 47507984175103,
+STORE, 47507984175104, 47507986014207,
+STORE, 47507984314368, 47507986014207,
+STORE, 47507984175104, 47507984314367,
+ERASE, 47507984314368, 47507984314368,
+STORE, 47507984314368, 47507985973247,
+STORE, 47507985973248, 47507986014207,
+STORE, 47507985657856, 47507985973247,
+STORE, 47507984314368, 47507985657855,
+ERASE, 47507984314368, 47507984314368,
+STORE, 47507984314368, 47507985657855,
+STORE, 47507985969152, 47507985973247,
+STORE, 47507985657856, 47507985969151,
+ERASE, 47507985657856, 47507985657856,
+STORE, 47507985657856, 47507985969151,
+STORE, 47507985997824, 47507986014207,
+STORE, 47507985973248, 47507985997823,
+ERASE, 47507985973248, 47507985973248,
+STORE, 47507985973248, 47507985997823,
+ERASE, 47507985997824, 47507985997824,
+STORE, 47507985997824, 47507986014207,
+STORE, 47507986014208, 47507986124799,
+STORE, 47507986030592, 47507986124799,
+STORE, 47507986014208, 47507986030591,
+ERASE, 47507986030592, 47507986030592,
+STORE, 47507986030592, 47507986116607,
+STORE, 47507986116608, 47507986124799,
+STORE, 47507986092032, 47507986116607,
+STORE, 47507986030592, 47507986092031,
+ERASE, 47507986030592, 47507986030592,
+STORE, 47507986030592, 47507986092031,
+STORE, 47507986112512, 47507986116607,
+STORE, 47507986092032, 47507986112511,
+ERASE, 47507986092032, 47507986092032,
+STORE, 47507986092032, 47507986112511,
+ERASE, 47507986116608, 47507986116608,
+STORE, 47507986116608, 47507986124799,
+STORE, 47507986124800, 47507986169855,
+ERASE, 47507986124800, 47507986124800,
+STORE, 47507986124800, 47507986132991,
+STORE, 47507986132992, 47507986169855,
+STORE, 47507986153472, 47507986169855,
+STORE, 47507986132992, 47507986153471,
+ERASE, 47507986132992, 47507986132992,
+STORE, 47507986132992, 47507986153471,
+STORE, 47507986161664, 47507986169855,
+STORE, 47507986153472, 47507986161663,
+ERASE, 47507986153472, 47507986153472,
+STORE, 47507986153472, 47507986169855,
+ERASE, 47507986153472, 47507986153472,
+STORE, 47507986153472, 47507986161663,
+STORE, 47507986161664, 47507986169855,
+ERASE, 47507986161664, 47507986161664,
+STORE, 47507986161664, 47507986169855,
+STORE, 47507986169856, 47507986518015,
+STORE, 47507986210816, 47507986518015,
+STORE, 47507986169856, 47507986210815,
+ERASE, 47507986210816, 47507986210816,
+STORE, 47507986210816, 47507986493439,
+STORE, 47507986493440, 47507986518015,
+STORE, 47507986423808, 47507986493439,
+STORE, 47507986210816, 47507986423807,
+ERASE, 47507986210816, 47507986210816,
+STORE, 47507986210816, 47507986423807,
+STORE, 47507986489344, 47507986493439,
+STORE, 47507986423808, 47507986489343,
+ERASE, 47507986423808, 47507986423808,
+STORE, 47507986423808, 47507986489343,
+ERASE, 47507986493440, 47507986493440,
+STORE, 47507986493440, 47507986518015,
+STORE, 47507986518016, 47507988779007,
+STORE, 47507986669568, 47507988779007,
+STORE, 47507986518016, 47507986669567,
+ERASE, 47507986669568, 47507986669568,
+STORE, 47507986669568, 47507988762623,
+STORE, 47507988762624, 47507988779007,
+STORE, 47507988770816, 47507988779007,
+STORE, 47507988762624, 47507988770815,
+ERASE, 47507988762624, 47507988762624,
+STORE, 47507988762624, 47507988770815,
+ERASE, 47507988770816, 47507988770816,
+STORE, 47507988770816, 47507988779007,
+STORE, 47507988779008, 47507988914175,
+ERASE, 47507988779008, 47507988779008,
+STORE, 47507988779008, 47507988803583,
+STORE, 47507988803584, 47507988914175,
+STORE, 47507988865024, 47507988914175,
+STORE, 47507988803584, 47507988865023,
+ERASE, 47507988803584, 47507988803584,
+STORE, 47507988803584, 47507988865023,
+STORE, 47507988889600, 47507988914175,
+STORE, 47507988865024, 47507988889599,
+ERASE, 47507988865024, 47507988865024,
+STORE, 47507988865024, 47507988914175,
+ERASE, 47507988865024, 47507988865024,
+STORE, 47507988865024, 47507988889599,
+STORE, 47507988889600, 47507988914175,
+STORE, 47507988897792, 47507988914175,
+STORE, 47507988889600, 47507988897791,
+ERASE, 47507988889600, 47507988889600,
+STORE, 47507988889600, 47507988897791,
+ERASE, 47507988897792, 47507988897792,
+STORE, 47507988897792, 47507988914175,
+STORE, 47507988897792, 47507988922367,
+STORE, 47507988922368, 47507989086207,
+ERASE, 47507988922368, 47507988922368,
+STORE, 47507988922368, 47507988934655,
+STORE, 47507988934656, 47507989086207,
+STORE, 47507989032960, 47507989086207,
+STORE, 47507988934656, 47507989032959,
+ERASE, 47507988934656, 47507988934656,
+STORE, 47507988934656, 47507989032959,
+STORE, 47507989078016, 47507989086207,
+STORE, 47507989032960, 47507989078015,
+ERASE, 47507989032960, 47507989032960,
+STORE, 47507989032960, 47507989086207,
+ERASE, 47507989032960, 47507989032960,
+STORE, 47507989032960, 47507989078015,
+STORE, 47507989078016, 47507989086207,
+ERASE, 47507989078016, 47507989078016,
+STORE, 47507989078016, 47507989086207,
+STORE, 47507989086208, 47507989684223,
+STORE, 47507989204992, 47507989684223,
+STORE, 47507989086208, 47507989204991,
+ERASE, 47507989204992, 47507989204992,
+STORE, 47507989204992, 47507989630975,
+STORE, 47507989630976, 47507989684223,
+STORE, 47507989520384, 47507989630975,
+STORE, 47507989204992, 47507989520383,
+ERASE, 47507989204992, 47507989204992,
+STORE, 47507989204992, 47507989520383,
+STORE, 47507989626880, 47507989630975,
+STORE, 47507989520384, 47507989626879,
+ERASE, 47507989520384, 47507989520384,
+STORE, 47507989520384, 47507989626879,
+ERASE, 47507989630976, 47507989630976,
+STORE, 47507989630976, 47507989684223,
+STORE, 47507989684224, 47507992735743,
+STORE, 47507990228992, 47507992735743,
+STORE, 47507989684224, 47507990228991,
+ERASE, 47507990228992, 47507990228992,
+STORE, 47507990228992, 47507992514559,
+STORE, 47507992514560, 47507992735743,
+STORE, 47507991924736, 47507992514559,
+STORE, 47507990228992, 47507991924735,
+ERASE, 47507990228992, 47507990228992,
+STORE, 47507990228992, 47507991924735,
+STORE, 47507992510464, 47507992514559,
+STORE, 47507991924736, 47507992510463,
+ERASE, 47507991924736, 47507991924736,
+STORE, 47507991924736, 47507992510463,
+STORE, 47507992719360, 47507992735743,
+STORE, 47507992514560, 47507992719359,
+ERASE, 47507992514560, 47507992514560,
+STORE, 47507992514560, 47507992719359,
+ERASE, 47507992719360, 47507992719360,
+STORE, 47507992719360, 47507992735743,
+STORE, 47507992735744, 47507992768511,
+ERASE, 47507992735744, 47507992735744,
+STORE, 47507992735744, 47507992743935,
+STORE, 47507992743936, 47507992768511,
+STORE, 47507992756224, 47507992768511,
+STORE, 47507992743936, 47507992756223,
+ERASE, 47507992743936, 47507992743936,
+STORE, 47507992743936, 47507992756223,
+STORE, 47507992760320, 47507992768511,
+STORE, 47507992756224, 47507992760319,
+ERASE, 47507992756224, 47507992756224,
+STORE, 47507992756224, 47507992768511,
+ERASE, 47507992756224, 47507992756224,
+STORE, 47507992756224, 47507992760319,
+STORE, 47507992760320, 47507992768511,
+ERASE, 47507992760320, 47507992760320,
+STORE, 47507992760320, 47507992768511,
+STORE, 47507992768512, 47507992805375,
+ERASE, 47507992768512, 47507992768512,
+STORE, 47507992768512, 47507992776703,
+STORE, 47507992776704, 47507992805375,
+STORE, 47507992793088, 47507992805375,
+STORE, 47507992776704, 47507992793087,
+ERASE, 47507992776704, 47507992776704,
+STORE, 47507992776704, 47507992793087,
+STORE, 47507992797184, 47507992805375,
+STORE, 47507992793088, 47507992797183,
+ERASE, 47507992793088, 47507992793088,
+STORE, 47507992793088, 47507992805375,
+ERASE, 47507992793088, 47507992793088,
+STORE, 47507992793088, 47507992797183,
+STORE, 47507992797184, 47507992805375,
+ERASE, 47507992797184, 47507992797184,
+STORE, 47507992797184, 47507992805375,
+STORE, 47507992805376, 47507993280511,
+ERASE, 47507992805376, 47507992805376,
+STORE, 47507992805376, 47507992813567,
+STORE, 47507992813568, 47507993280511,
+STORE, 47507993149440, 47507993280511,
+STORE, 47507992813568, 47507993149439,
+ERASE, 47507992813568, 47507992813568,
+STORE, 47507992813568, 47507993149439,
+STORE, 47507993272320, 47507993280511,
+STORE, 47507993149440, 47507993272319,
+ERASE, 47507993149440, 47507993149440,
+STORE, 47507993149440, 47507993280511,
+ERASE, 47507993149440, 47507993149440,
+STORE, 47507993149440, 47507993272319,
+STORE, 47507993272320, 47507993280511,
+ERASE, 47507993272320, 47507993272320,
+STORE, 47507993272320, 47507993280511,
+STORE, 47507993280512, 47507993288703,
+STORE, 47507993288704, 47507993309183,
+ERASE, 47507993288704, 47507993288704,
+STORE, 47507993288704, 47507993292799,
+STORE, 47507993292800, 47507993309183,
+STORE, 47507993296896, 47507993309183,
+STORE, 47507993292800, 47507993296895,
+ERASE, 47507993292800, 47507993292800,
+STORE, 47507993292800, 47507993296895,
+STORE, 47507993300992, 47507993309183,
+STORE, 47507993296896, 47507993300991,
+ERASE, 47507993296896, 47507993296896,
+STORE, 47507993296896, 47507993309183,
+ERASE, 47507993296896, 47507993296896,
+STORE, 47507993296896, 47507993300991,
+STORE, 47507993300992, 47507993309183,
+ERASE, 47507993300992, 47507993300992,
+STORE, 47507993300992, 47507993309183,
+STORE, 47507993309184, 47507993317375,
+ERASE, 47507985973248, 47507985973248,
+STORE, 47507985973248, 47507985989631,
+STORE, 47507985989632, 47507985997823,
+ERASE, 47507993300992, 47507993300992,
+STORE, 47507993300992, 47507993305087,
+STORE, 47507993305088, 47507993309183,
+ERASE, 47507988889600, 47507988889600,
+STORE, 47507988889600, 47507988893695,
+STORE, 47507988893696, 47507988897791,
+ERASE, 47507993272320, 47507993272320,
+STORE, 47507993272320, 47507993276415,
+STORE, 47507993276416, 47507993280511,
+ERASE, 47507992797184, 47507992797184,
+STORE, 47507992797184, 47507992801279,
+STORE, 47507992801280, 47507992805375,
+ERASE, 47507992760320, 47507992760320,
+STORE, 47507992760320, 47507992764415,
+STORE, 47507992764416, 47507992768511,
+ERASE, 47507992514560, 47507992514560,
+STORE, 47507992514560, 47507992711167,
+STORE, 47507992711168, 47507992719359,
+ERASE, 47507989630976, 47507989630976,
+STORE, 47507989630976, 47507989667839,
+STORE, 47507989667840, 47507989684223,
+ERASE, 47507989078016, 47507989078016,
+STORE, 47507989078016, 47507989082111,
+STORE, 47507989082112, 47507989086207,
+ERASE, 47507988762624, 47507988762624,
+STORE, 47507988762624, 47507988766719,
+STORE, 47507988766720, 47507988770815,
+ERASE, 47507986493440, 47507986493440,
+STORE, 47507986493440, 47507986513919,
+STORE, 47507986513920, 47507986518015,
+ERASE, 47507986161664, 47507986161664,
+STORE, 47507986161664, 47507986165759,
+STORE, 47507986165760, 47507986169855,
+ERASE, 47507986116608, 47507986116608,
+STORE, 47507986116608, 47507986120703,
+STORE, 47507986120704, 47507986124799,
+ERASE, 94386579570688, 94386579570688,
+STORE, 94386579570688, 94386579693567,
+STORE, 94386579693568, 94386579697663,
+ERASE, 140124810997760, 140124810997760,
+STORE, 140124810997760, 140124811001855,
+STORE, 140124811001856, 140124811005951,
+ERASE, 47507984158720, 47507984158720,
+STORE, 94386583982080, 94386584117247,
+STORE, 94386583982080, 94386584256511,
+ERASE, 94386583982080, 94386583982080,
+STORE, 94386583982080, 94386584223743,
+STORE, 94386584223744, 94386584256511,
+ERASE, 94386584223744, 94386584223744,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733763395584, 140737488351231,
+ERASE, 140733763395584, 140733763395584,
+STORE, 140733763395584, 140733763399679,
+STORE, 94011546472448, 94011547152383,
+ERASE, 94011546472448, 94011546472448,
+STORE, 94011546472448, 94011546537983,
+STORE, 94011546537984, 94011547152383,
+ERASE, 94011546537984, 94011546537984,
+STORE, 94011546537984, 94011546886143,
+STORE, 94011546886144, 94011547025407,
+STORE, 94011547025408, 94011547152383,
+STORE, 139757597949952, 139757598121983,
+ERASE, 139757597949952, 139757597949952,
+STORE, 139757597949952, 139757597954047,
+STORE, 139757597954048, 139757598121983,
+ERASE, 139757597954048, 139757597954048,
+STORE, 139757597954048, 139757598076927,
+STORE, 139757598076928, 139757598109695,
+STORE, 139757598109696, 139757598117887,
+STORE, 139757598117888, 139757598121983,
+STORE, 140733763596288, 140733763600383,
+STORE, 140733763584000, 140733763596287,
+STORE, 47875197046784, 47875197054975,
+STORE, 47875197054976, 47875197063167,
+STORE, 47875197063168, 47875198902271,
+STORE, 47875197202432, 47875198902271,
+STORE, 47875197063168, 47875197202431,
+ERASE, 47875197202432, 47875197202432,
+STORE, 47875197202432, 47875198861311,
+STORE, 47875198861312, 47875198902271,
+STORE, 47875198545920, 47875198861311,
+STORE, 47875197202432, 47875198545919,
+ERASE, 47875197202432, 47875197202432,
+STORE, 47875197202432, 47875198545919,
+STORE, 47875198857216, 47875198861311,
+STORE, 47875198545920, 47875198857215,
+ERASE, 47875198545920, 47875198545920,
+STORE, 47875198545920, 47875198857215,
+STORE, 47875198885888, 47875198902271,
+STORE, 47875198861312, 47875198885887,
+ERASE, 47875198861312, 47875198861312,
+STORE, 47875198861312, 47875198885887,
+ERASE, 47875198885888, 47875198885888,
+STORE, 47875198885888, 47875198902271,
+STORE, 47875198902272, 47875199012863,
+STORE, 47875198918656, 47875199012863,
+STORE, 47875198902272, 47875198918655,
+ERASE, 47875198918656, 47875198918656,
+STORE, 47875198918656, 47875199004671,
+STORE, 47875199004672, 47875199012863,
+STORE, 47875198980096, 47875199004671,
+STORE, 47875198918656, 47875198980095,
+ERASE, 47875198918656, 47875198918656,
+STORE, 47875198918656, 47875198980095,
+STORE, 47875199000576, 47875199004671,
+STORE, 47875198980096, 47875199000575,
+ERASE, 47875198980096, 47875198980096,
+STORE, 47875198980096, 47875199000575,
+ERASE, 47875199004672, 47875199004672,
+STORE, 47875199004672, 47875199012863,
+STORE, 47875199012864, 47875199057919,
+ERASE, 47875199012864, 47875199012864,
+STORE, 47875199012864, 47875199021055,
+STORE, 47875199021056, 47875199057919,
+STORE, 47875199041536, 47875199057919,
+STORE, 47875199021056, 47875199041535,
+ERASE, 47875199021056, 47875199021056,
+STORE, 47875199021056, 47875199041535,
+STORE, 47875199049728, 47875199057919,
+STORE, 47875199041536, 47875199049727,
+ERASE, 47875199041536, 47875199041536,
+STORE, 47875199041536, 47875199057919,
+ERASE, 47875199041536, 47875199041536,
+STORE, 47875199041536, 47875199049727,
+STORE, 47875199049728, 47875199057919,
+ERASE, 47875199049728, 47875199049728,
+STORE, 47875199049728, 47875199057919,
+STORE, 47875199057920, 47875199406079,
+STORE, 47875199098880, 47875199406079,
+STORE, 47875199057920, 47875199098879,
+ERASE, 47875199098880, 47875199098880,
+STORE, 47875199098880, 47875199381503,
+STORE, 47875199381504, 47875199406079,
+STORE, 47875199311872, 47875199381503,
+STORE, 47875199098880, 47875199311871,
+ERASE, 47875199098880, 47875199098880,
+STORE, 47875199098880, 47875199311871,
+STORE, 47875199377408, 47875199381503,
+STORE, 47875199311872, 47875199377407,
+ERASE, 47875199311872, 47875199311872,
+STORE, 47875199311872, 47875199377407,
+ERASE, 47875199381504, 47875199381504,
+STORE, 47875199381504, 47875199406079,
+STORE, 47875199406080, 47875201667071,
+STORE, 47875199557632, 47875201667071,
+STORE, 47875199406080, 47875199557631,
+ERASE, 47875199557632, 47875199557632,
+STORE, 47875199557632, 47875201650687,
+STORE, 47875201650688, 47875201667071,
+STORE, 47875201658880, 47875201667071,
+STORE, 47875201650688, 47875201658879,
+ERASE, 47875201650688, 47875201650688,
+STORE, 47875201650688, 47875201658879,
+ERASE, 47875201658880, 47875201658880,
+STORE, 47875201658880, 47875201667071,
+STORE, 47875201667072, 47875201802239,
+ERASE, 47875201667072, 47875201667072,
+STORE, 47875201667072, 47875201691647,
+STORE, 47875201691648, 47875201802239,
+STORE, 47875201753088, 47875201802239,
+STORE, 47875201691648, 47875201753087,
+ERASE, 47875201691648, 47875201691648,
+STORE, 47875201691648, 47875201753087,
+STORE, 47875201777664, 47875201802239,
+STORE, 47875201753088, 47875201777663,
+ERASE, 47875201753088, 47875201753088,
+STORE, 47875201753088, 47875201802239,
+ERASE, 47875201753088, 47875201753088,
+STORE, 47875201753088, 47875201777663,
+STORE, 47875201777664, 47875201802239,
+STORE, 47875201785856, 47875201802239,
+STORE, 47875201777664, 47875201785855,
+ERASE, 47875201777664, 47875201777664,
+STORE, 47875201777664, 47875201785855,
+ERASE, 47875201785856, 47875201785856,
+STORE, 47875201785856, 47875201802239,
+STORE, 47875201785856, 47875201810431,
+STORE, 47875201810432, 47875201974271,
+ERASE, 47875201810432, 47875201810432,
+STORE, 47875201810432, 47875201822719,
+STORE, 47875201822720, 47875201974271,
+STORE, 47875201921024, 47875201974271,
+STORE, 47875201822720, 47875201921023,
+ERASE, 47875201822720, 47875201822720,
+STORE, 47875201822720, 47875201921023,
+STORE, 47875201966080, 47875201974271,
+STORE, 47875201921024, 47875201966079,
+ERASE, 47875201921024, 47875201921024,
+STORE, 47875201921024, 47875201974271,
+ERASE, 47875201921024, 47875201921024,
+STORE, 47875201921024, 47875201966079,
+STORE, 47875201966080, 47875201974271,
+ERASE, 47875201966080, 47875201966080,
+STORE, 47875201966080, 47875201974271,
+STORE, 47875201974272, 47875202572287,
+STORE, 47875202093056, 47875202572287,
+STORE, 47875201974272, 47875202093055,
+ERASE, 47875202093056, 47875202093056,
+STORE, 47875202093056, 47875202519039,
+STORE, 47875202519040, 47875202572287,
+STORE, 47875202408448, 47875202519039,
+STORE, 47875202093056, 47875202408447,
+ERASE, 47875202093056, 47875202093056,
+STORE, 47875202093056, 47875202408447,
+STORE, 47875202514944, 47875202519039,
+STORE, 47875202408448, 47875202514943,
+ERASE, 47875202408448, 47875202408448,
+STORE, 47875202408448, 47875202514943,
+ERASE, 47875202519040, 47875202519040,
+STORE, 47875202519040, 47875202572287,
+STORE, 47875202572288, 47875205623807,
+STORE, 47875203117056, 47875205623807,
+STORE, 47875202572288, 47875203117055,
+ERASE, 47875203117056, 47875203117056,
+STORE, 47875203117056, 47875205402623,
+STORE, 47875205402624, 47875205623807,
+STORE, 47875204812800, 47875205402623,
+STORE, 47875203117056, 47875204812799,
+ERASE, 47875203117056, 47875203117056,
+STORE, 47875203117056, 47875204812799,
+STORE, 47875205398528, 47875205402623,
+STORE, 47875204812800, 47875205398527,
+ERASE, 47875204812800, 47875204812800,
+STORE, 47875204812800, 47875205398527,
+STORE, 47875205607424, 47875205623807,
+STORE, 47875205402624, 47875205607423,
+ERASE, 47875205402624, 47875205402624,
+STORE, 47875205402624, 47875205607423,
+ERASE, 47875205607424, 47875205607424,
+STORE, 47875205607424, 47875205623807,
+STORE, 47875205623808, 47875205656575,
+ERASE, 47875205623808, 47875205623808,
+STORE, 47875205623808, 47875205631999,
+STORE, 47875205632000, 47875205656575,
+STORE, 47875205644288, 47875205656575,
+STORE, 47875205632000, 47875205644287,
+ERASE, 47875205632000, 47875205632000,
+STORE, 47875205632000, 47875205644287,
+STORE, 47875205648384, 47875205656575,
+STORE, 47875205644288, 47875205648383,
+ERASE, 47875205644288, 47875205644288,
+STORE, 47875205644288, 47875205656575,
+ERASE, 47875205644288, 47875205644288,
+STORE, 47875205644288, 47875205648383,
+STORE, 47875205648384, 47875205656575,
+ERASE, 47875205648384, 47875205648384,
+STORE, 47875205648384, 47875205656575,
+STORE, 47875205656576, 47875205693439,
+ERASE, 47875205656576, 47875205656576,
+STORE, 47875205656576, 47875205664767,
+STORE, 47875205664768, 47875205693439,
+STORE, 47875205681152, 47875205693439,
+STORE, 47875205664768, 47875205681151,
+ERASE, 47875205664768, 47875205664768,
+STORE, 47875205664768, 47875205681151,
+STORE, 47875205685248, 47875205693439,
+STORE, 47875205681152, 47875205685247,
+ERASE, 47875205681152, 47875205681152,
+STORE, 47875205681152, 47875205693439,
+ERASE, 47875205681152, 47875205681152,
+STORE, 47875205681152, 47875205685247,
+STORE, 47875205685248, 47875205693439,
+ERASE, 47875205685248, 47875205685248,
+STORE, 47875205685248, 47875205693439,
+STORE, 47875205693440, 47875206168575,
+ERASE, 47875205693440, 47875205693440,
+STORE, 47875205693440, 47875205701631,
+STORE, 47875205701632, 47875206168575,
+STORE, 47875206037504, 47875206168575,
+STORE, 47875205701632, 47875206037503,
+ERASE, 47875205701632, 47875205701632,
+STORE, 47875205701632, 47875206037503,
+STORE, 47875206160384, 47875206168575,
+STORE, 47875206037504, 47875206160383,
+ERASE, 47875206037504, 47875206037504,
+STORE, 47875206037504, 47875206168575,
+ERASE, 47875206037504, 47875206037504,
+STORE, 47875206037504, 47875206160383,
+STORE, 47875206160384, 47875206168575,
+ERASE, 47875206160384, 47875206160384,
+STORE, 47875206160384, 47875206168575,
+STORE, 47875206168576, 47875206176767,
+STORE, 47875206176768, 47875206197247,
+ERASE, 47875206176768, 47875206176768,
+STORE, 47875206176768, 47875206180863,
+STORE, 47875206180864, 47875206197247,
+STORE, 47875206184960, 47875206197247,
+STORE, 47875206180864, 47875206184959,
+ERASE, 47875206180864, 47875206180864,
+STORE, 47875206180864, 47875206184959,
+STORE, 47875206189056, 47875206197247,
+STORE, 47875206184960, 47875206189055,
+ERASE, 47875206184960, 47875206184960,
+STORE, 47875206184960, 47875206197247,
+ERASE, 47875206184960, 47875206184960,
+STORE, 47875206184960, 47875206189055,
+STORE, 47875206189056, 47875206197247,
+ERASE, 47875206189056, 47875206189056,
+STORE, 47875206189056, 47875206197247,
+STORE, 47875206197248, 47875206205439,
+ERASE, 47875198861312, 47875198861312,
+STORE, 47875198861312, 47875198877695,
+STORE, 47875198877696, 47875198885887,
+ERASE, 47875206189056, 47875206189056,
+STORE, 47875206189056, 47875206193151,
+STORE, 47875206193152, 47875206197247,
+ERASE, 47875201777664, 47875201777664,
+STORE, 47875201777664, 47875201781759,
+STORE, 47875201781760, 47875201785855,
+ERASE, 47875206160384, 47875206160384,
+STORE, 47875206160384, 47875206164479,
+STORE, 47875206164480, 47875206168575,
+ERASE, 47875205685248, 47875205685248,
+STORE, 47875205685248, 47875205689343,
+STORE, 47875205689344, 47875205693439,
+ERASE, 47875205648384, 47875205648384,
+STORE, 47875205648384, 47875205652479,
+STORE, 47875205652480, 47875205656575,
+ERASE, 47875205402624, 47875205402624,
+STORE, 47875205402624, 47875205599231,
+STORE, 47875205599232, 47875205607423,
+ERASE, 47875202519040, 47875202519040,
+STORE, 47875202519040, 47875202555903,
+STORE, 47875202555904, 47875202572287,
+ERASE, 47875201966080, 47875201966080,
+STORE, 47875201966080, 47875201970175,
+STORE, 47875201970176, 47875201974271,
+ERASE, 47875201650688, 47875201650688,
+STORE, 47875201650688, 47875201654783,
+STORE, 47875201654784, 47875201658879,
+ERASE, 47875199381504, 47875199381504,
+STORE, 47875199381504, 47875199401983,
+STORE, 47875199401984, 47875199406079,
+ERASE, 47875199049728, 47875199049728,
+STORE, 47875199049728, 47875199053823,
+STORE, 47875199053824, 47875199057919,
+ERASE, 47875199004672, 47875199004672,
+STORE, 47875199004672, 47875199008767,
+STORE, 47875199008768, 47875199012863,
+ERASE, 94011547025408, 94011547025408,
+STORE, 94011547025408, 94011547148287,
+STORE, 94011547148288, 94011547152383,
+ERASE, 139757598109696, 139757598109696,
+STORE, 139757598109696, 139757598113791,
+STORE, 139757598113792, 139757598117887,
+ERASE, 47875197046784, 47875197046784,
+STORE, 94011557584896, 94011557720063,
+STORE, 94011557584896, 94011557855231,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557851135,
+STORE, 94011557851136, 94011557855231,
+ERASE, 94011557851136, 94011557851136,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557847039,
+STORE, 94011557847040, 94011557851135,
+ERASE, 94011557847040, 94011557847040,
+STORE, 94011557584896, 94011557982207,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557978111,
+STORE, 94011557978112, 94011557982207,
+ERASE, 94011557978112, 94011557978112,
+ERASE, 94011557584896, 94011557584896,
+STORE, 94011557584896, 94011557974015,
+STORE, 94011557974016, 94011557978111,
+ERASE, 94011557974016, 94011557974016,
+STORE, 140737488347136, 140737488351231,
+STORE, 140734130360320, 140737488351231,
+ERASE, 140734130360320, 140734130360320,
+STORE, 140734130360320, 140734130364415,
+STORE, 94641232105472, 94641232785407,
+ERASE, 94641232105472, 94641232105472,
+STORE, 94641232105472, 94641232171007,
+STORE, 94641232171008, 94641232785407,
+ERASE, 94641232171008, 94641232171008,
+STORE, 94641232171008, 94641232519167,
+STORE, 94641232519168, 94641232658431,
+STORE, 94641232658432, 94641232785407,
+STORE, 139726599516160, 139726599688191,
+ERASE, 139726599516160, 139726599516160,
+STORE, 139726599516160, 139726599520255,
+STORE, 139726599520256, 139726599688191,
+ERASE, 139726599520256, 139726599520256,
+STORE, 139726599520256, 139726599643135,
+STORE, 139726599643136, 139726599675903,
+STORE, 139726599675904, 139726599684095,
+STORE, 139726599684096, 139726599688191,
+STORE, 140734130446336, 140734130450431,
+STORE, 140734130434048, 140734130446335,
+STORE, 47906195480576, 47906195488767,
+STORE, 47906195488768, 47906195496959,
+STORE, 47906195496960, 47906197336063,
+STORE, 47906195636224, 47906197336063,
+STORE, 47906195496960, 47906195636223,
+ERASE, 47906195636224, 47906195636224,
+STORE, 47906195636224, 47906197295103,
+STORE, 47906197295104, 47906197336063,
+STORE, 47906196979712, 47906197295103,
+STORE, 47906195636224, 47906196979711,
+ERASE, 47906195636224, 47906195636224,
+STORE, 47906195636224, 47906196979711,
+STORE, 47906197291008, 47906197295103,
+STORE, 47906196979712, 47906197291007,
+ERASE, 47906196979712, 47906196979712,
+STORE, 47906196979712, 47906197291007,
+STORE, 47906197319680, 47906197336063,
+STORE, 47906197295104, 47906197319679,
+ERASE, 47906197295104, 47906197295104,
+STORE, 47906197295104, 47906197319679,
+ERASE, 47906197319680, 47906197319680,
+STORE, 47906197319680, 47906197336063,
+STORE, 47906197336064, 47906197446655,
+STORE, 47906197352448, 47906197446655,
+STORE, 47906197336064, 47906197352447,
+ERASE, 47906197352448, 47906197352448,
+STORE, 47906197352448, 47906197438463,
+STORE, 47906197438464, 47906197446655,
+STORE, 47906197413888, 47906197438463,
+STORE, 47906197352448, 47906197413887,
+ERASE, 47906197352448, 47906197352448,
+STORE, 47906197352448, 47906197413887,
+STORE, 47906197434368, 47906197438463,
+STORE, 47906197413888, 47906197434367,
+ERASE, 47906197413888, 47906197413888,
+STORE, 47906197413888, 47906197434367,
+ERASE, 47906197438464, 47906197438464,
+STORE, 47906197438464, 47906197446655,
+STORE, 47906197446656, 47906197491711,
+ERASE, 47906197446656, 47906197446656,
+STORE, 47906197446656, 47906197454847,
+STORE, 47906197454848, 47906197491711,
+STORE, 47906197475328, 47906197491711,
+STORE, 47906197454848, 47906197475327,
+ERASE, 47906197454848, 47906197454848,
+STORE, 47906197454848, 47906197475327,
+STORE, 47906197483520, 47906197491711,
+STORE, 47906197475328, 47906197483519,
+ERASE, 47906197475328, 47906197475328,
+STORE, 47906197475328, 47906197491711,
+ERASE, 47906197475328, 47906197475328,
+STORE, 47906197475328, 47906197483519,
+STORE, 47906197483520, 47906197491711,
+ERASE, 47906197483520, 47906197483520,
+STORE, 47906197483520, 47906197491711,
+STORE, 47906197491712, 47906197839871,
+STORE, 47906197532672, 47906197839871,
+STORE, 47906197491712, 47906197532671,
+ERASE, 47906197532672, 47906197532672,
+STORE, 47906197532672, 47906197815295,
+STORE, 47906197815296, 47906197839871,
+STORE, 47906197745664, 47906197815295,
+STORE, 47906197532672, 47906197745663,
+ERASE, 47906197532672, 47906197532672,
+STORE, 47906197532672, 47906197745663,
+STORE, 47906197811200, 47906197815295,
+STORE, 47906197745664, 47906197811199,
+ERASE, 47906197745664, 47906197745664,
+STORE, 47906197745664, 47906197811199,
+ERASE, 47906197815296, 47906197815296,
+STORE, 47906197815296, 47906197839871,
+STORE, 47906197839872, 47906200100863,
+STORE, 47906197991424, 47906200100863,
+STORE, 47906197839872, 47906197991423,
+ERASE, 47906197991424, 47906197991424,
+STORE, 47906197991424, 47906200084479,
+STORE, 47906200084480, 47906200100863,
+STORE, 47906200092672, 47906200100863,
+STORE, 47906200084480, 47906200092671,
+ERASE, 47906200084480, 47906200084480,
+STORE, 47906200084480, 47906200092671,
+ERASE, 47906200092672, 47906200092672,
+STORE, 47906200092672, 47906200100863,
+STORE, 47906200100864, 47906200236031,
+ERASE, 47906200100864, 47906200100864,
+STORE, 47906200100864, 47906200125439,
+STORE, 47906200125440, 47906200236031,
+STORE, 47906200186880, 47906200236031,
+STORE, 47906200125440, 47906200186879,
+ERASE, 47906200125440, 47906200125440,
+STORE, 47906200125440, 47906200186879,
+STORE, 47906200211456, 47906200236031,
+STORE, 47906200186880, 47906200211455,
+ERASE, 47906200186880, 47906200186880,
+STORE, 47906200186880, 47906200236031,
+ERASE, 47906200186880, 47906200186880,
+STORE, 47906200186880, 47906200211455,
+STORE, 47906200211456, 47906200236031,
+STORE, 47906200219648, 47906200236031,
+STORE, 47906200211456, 47906200219647,
+ERASE, 47906200211456, 47906200211456,
+STORE, 47906200211456, 47906200219647,
+ERASE, 47906200219648, 47906200219648,
+STORE, 47906200219648, 47906200236031,
+STORE, 47906200219648, 47906200244223,
+STORE, 47906200244224, 47906200408063,
+ERASE, 47906200244224, 47906200244224,
+STORE, 47906200244224, 47906200256511,
+STORE, 47906200256512, 47906200408063,
+STORE, 47906200354816, 47906200408063,
+STORE, 47906200256512, 47906200354815,
+ERASE, 47906200256512, 47906200256512,
+STORE, 47906200256512, 47906200354815,
+STORE, 47906200399872, 47906200408063,
+STORE, 47906200354816, 47906200399871,
+ERASE, 47906200354816, 47906200354816,
+STORE, 47906200354816, 47906200408063,
+ERASE, 47906200354816, 47906200354816,
+STORE, 47906200354816, 47906200399871,
+STORE, 47906200399872, 47906200408063,
+ERASE, 47906200399872, 47906200399872,
+STORE, 47906200399872, 47906200408063,
+STORE, 47906200408064, 47906201006079,
+STORE, 47906200526848, 47906201006079,
+STORE, 47906200408064, 47906200526847,
+ERASE, 47906200526848, 47906200526848,
+STORE, 47906200526848, 47906200952831,
+STORE, 47906200952832, 47906201006079,
+STORE, 47906200842240, 47906200952831,
+STORE, 47906200526848, 47906200842239,
+ERASE, 47906200526848, 47906200526848,
+STORE, 47906200526848, 47906200842239,
+STORE, 47906200948736, 47906200952831,
+STORE, 47906200842240, 47906200948735,
+ERASE, 47906200842240, 47906200842240,
+STORE, 47906200842240, 47906200948735,
+ERASE, 47906200952832, 47906200952832,
+STORE, 47906200952832, 47906201006079,
+STORE, 47906201006080, 47906204057599,
+STORE, 47906201550848, 47906204057599,
+STORE, 47906201006080, 47906201550847,
+ERASE, 47906201550848, 47906201550848,
+STORE, 47906201550848, 47906203836415,
+STORE, 47906203836416, 47906204057599,
+STORE, 47906203246592, 47906203836415,
+STORE, 47906201550848, 47906203246591,
+ERASE, 47906201550848, 47906201550848,
+STORE, 47906201550848, 47906203246591,
+STORE, 47906203832320, 47906203836415,
+STORE, 47906203246592, 47906203832319,
+ERASE, 47906203246592, 47906203246592,
+STORE, 47906203246592, 47906203832319,
+STORE, 47906204041216, 47906204057599,
+STORE, 47906203836416, 47906204041215,
+ERASE, 47906203836416, 47906203836416,
+STORE, 47906203836416, 47906204041215,
+ERASE, 47906204041216, 47906204041216,
+STORE, 47906204041216, 47906204057599,
+STORE, 47906204057600, 47906204090367,
+ERASE, 47906204057600, 47906204057600,
+STORE, 47906204057600, 47906204065791,
+STORE, 47906204065792, 47906204090367,
+STORE, 47906204078080, 47906204090367,
+STORE, 47906204065792, 47906204078079,
+ERASE, 47906204065792, 47906204065792,
+STORE, 47906204065792, 47906204078079,
+STORE, 47906204082176, 47906204090367,
+STORE, 47906204078080, 47906204082175,
+ERASE, 47906204078080, 47906204078080,
+STORE, 47906204078080, 47906204090367,
+ERASE, 47906204078080, 47906204078080,
+STORE, 47906204078080, 47906204082175,
+STORE, 47906204082176, 47906204090367,
+ERASE, 47906204082176, 47906204082176,
+STORE, 47906204082176, 47906204090367,
+STORE, 47906204090368, 47906204127231,
+ERASE, 47906204090368, 47906204090368,
+STORE, 47906204090368, 47906204098559,
+STORE, 47906204098560, 47906204127231,
+STORE, 47906204114944, 47906204127231,
+STORE, 47906204098560, 47906204114943,
+ERASE, 47906204098560, 47906204098560,
+STORE, 47906204098560, 47906204114943,
+STORE, 47906204119040, 47906204127231,
+STORE, 47906204114944, 47906204119039,
+ERASE, 47906204114944, 47906204114944,
+STORE, 47906204114944, 47906204127231,
+ERASE, 47906204114944, 47906204114944,
+STORE, 47906204114944, 47906204119039,
+STORE, 47906204119040, 47906204127231,
+ERASE, 47906204119040, 47906204119040,
+STORE, 47906204119040, 47906204127231,
+STORE, 47906204127232, 47906204602367,
+ERASE, 47906204127232, 47906204127232,
+STORE, 47906204127232, 47906204135423,
+STORE, 47906204135424, 47906204602367,
+STORE, 47906204471296, 47906204602367,
+STORE, 47906204135424, 47906204471295,
+ERASE, 47906204135424, 47906204135424,
+STORE, 47906204135424, 47906204471295,
+STORE, 47906204594176, 47906204602367,
+STORE, 47906204471296, 47906204594175,
+ERASE, 47906204471296, 47906204471296,
+STORE, 47906204471296, 47906204602367,
+ERASE, 47906204471296, 47906204471296,
+STORE, 47906204471296, 47906204594175,
+STORE, 47906204594176, 47906204602367,
+ERASE, 47906204594176, 47906204594176,
+STORE, 47906204594176, 47906204602367,
+STORE, 47906204602368, 47906204610559,
+STORE, 47906204610560, 47906204631039,
+ERASE, 47906204610560, 47906204610560,
+STORE, 47906204610560, 47906204614655,
+STORE, 47906204614656, 47906204631039,
+STORE, 47906204618752, 47906204631039,
+STORE, 47906204614656, 47906204618751,
+ERASE, 47906204614656, 47906204614656,
+STORE, 47906204614656, 47906204618751,
+STORE, 47906204622848, 47906204631039,
+STORE, 47906204618752, 47906204622847,
+ERASE, 47906204618752, 47906204618752,
+STORE, 47906204618752, 47906204631039,
+ERASE, 47906204618752, 47906204618752,
+STORE, 47906204618752, 47906204622847,
+STORE, 47906204622848, 47906204631039,
+ERASE, 47906204622848, 47906204622848,
+STORE, 47906204622848, 47906204631039,
+STORE, 47906204631040, 47906204639231,
+ERASE, 47906197295104, 47906197295104,
+STORE, 47906197295104, 47906197311487,
+STORE, 47906197311488, 47906197319679,
+ERASE, 47906204622848, 47906204622848,
+STORE, 47906204622848, 47906204626943,
+STORE, 47906204626944, 47906204631039,
+ERASE, 47906200211456, 47906200211456,
+STORE, 47906200211456, 47906200215551,
+STORE, 47906200215552, 47906200219647,
+ERASE, 47906204594176, 47906204594176,
+STORE, 47906204594176, 47906204598271,
+STORE, 47906204598272, 47906204602367,
+ERASE, 47906204119040, 47906204119040,
+STORE, 47906204119040, 47906204123135,
+STORE, 47906204123136, 47906204127231,
+ERASE, 47906204082176, 47906204082176,
+STORE, 47906204082176, 47906204086271,
+STORE, 47906204086272, 47906204090367,
+ERASE, 47906203836416, 47906203836416,
+STORE, 47906203836416, 47906204033023,
+STORE, 47906204033024, 47906204041215,
+ERASE, 47906200952832, 47906200952832,
+STORE, 47906200952832, 47906200989695,
+STORE, 47906200989696, 47906201006079,
+ERASE, 47906200399872, 47906200399872,
+STORE, 47906200399872, 47906200403967,
+STORE, 47906200403968, 47906200408063,
+ERASE, 47906200084480, 47906200084480,
+STORE, 47906200084480, 47906200088575,
+STORE, 47906200088576, 47906200092671,
+ERASE, 47906197815296, 47906197815296,
+STORE, 47906197815296, 47906197835775,
+STORE, 47906197835776, 47906197839871,
+ERASE, 47906197483520, 47906197483520,
+STORE, 47906197483520, 47906197487615,
+STORE, 47906197487616, 47906197491711,
+ERASE, 47906197438464, 47906197438464,
+STORE, 47906197438464, 47906197442559,
+STORE, 47906197442560, 47906197446655,
+ERASE, 94641232658432, 94641232658432,
+STORE, 94641232658432, 94641232781311,
+STORE, 94641232781312, 94641232785407,
+ERASE, 139726599675904, 139726599675904,
+STORE, 139726599675904, 139726599679999,
+STORE, 139726599680000, 139726599684095,
+ERASE, 47906195480576, 47906195480576,
+STORE, 94641242615808, 94641242750975,
+ };
+ unsigned long set11[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140732658499584, 140737488351231,
+ERASE, 140732658499584, 140732658499584,
+STORE, 140732658499584, 140732658503679,
+STORE, 94029856579584, 94029856751615,
+ERASE, 94029856579584, 94029856579584,
+STORE, 94029856579584, 94029856595967,
+STORE, 94029856595968, 94029856751615,
+ERASE, 94029856595968, 94029856595968,
+STORE, 94029856595968, 94029856698367,
+STORE, 94029856698368, 94029856739327,
+STORE, 94029856739328, 94029856751615,
+STORE, 140014592573440, 140014592745471,
+ERASE, 140014592573440, 140014592573440,
+STORE, 140014592573440, 140014592577535,
+STORE, 140014592577536, 140014592745471,
+ERASE, 140014592577536, 140014592577536,
+STORE, 140014592577536, 140014592700415,
+STORE, 140014592700416, 140014592733183,
+STORE, 140014592733184, 140014592741375,
+STORE, 140014592741376, 140014592745471,
+STORE, 140732658565120, 140732658569215,
+STORE, 140732658552832, 140732658565119,
+ };
+
+ unsigned long set12[] = { /* contains 12 values. */
+STORE, 140737488347136, 140737488351231,
+STORE, 140732658499584, 140737488351231,
+ERASE, 140732658499584, 140732658499584,
+STORE, 140732658499584, 140732658503679,
+STORE, 94029856579584, 94029856751615,
+ERASE, 94029856579584, 94029856579584,
+STORE, 94029856579584, 94029856595967,
+STORE, 94029856595968, 94029856751615,
+ERASE, 94029856595968, 94029856595968,
+STORE, 94029856595968, 94029856698367,
+STORE, 94029856698368, 94029856739327,
+STORE, 94029856739328, 94029856751615,
+STORE, 140014592573440, 140014592745471,
+ERASE, 140014592573440, 140014592573440,
+STORE, 140014592573440, 140014592577535,
+STORE, 140014592577536, 140014592745471,
+ERASE, 140014592577536, 140014592577536,
+STORE, 140014592577536, 140014592700415,
+STORE, 140014592700416, 140014592733183,
+STORE, 140014592733184, 140014592741375,
+STORE, 140014592741376, 140014592745471,
+STORE, 140732658565120, 140732658569215,
+STORE, 140732658552832, 140732658565119,
+STORE, 140014592741375, 140014592741375, /* contrived */
+STORE, 140014592733184, 140014592741376, /* creates first entry retry. */
+ };
+ unsigned long set13[] = {
+STORE, 140373516247040, 140373516251135,/*: ffffa2e7b0e10d80 */
+STORE, 140373516251136, 140373516255231,/*: ffffa2e7b1195d80 */
+STORE, 140373516255232, 140373516443647,/*: ffffa2e7b0e109c0 */
+STORE, 140373516443648, 140373516587007,/*: ffffa2e7b05fecc0 */
+STORE, 140373516963840, 140373518647295,/*: ffffa2e7bfbdcc00 */
+STORE, 140373518647296, 140373518663679,/*: ffffa2e7bf5d59c0 */
+STORE, 140373518663680, 140373518684159,/*: deleted (257) */
+STORE, 140373518680064, 140373518684159,/*: ffffa2e7b0e1cb40 */
+STORE, 140373518684160, 140373518688254,/*: ffffa2e7b05fec00 */
+STORE, 140373518688256, 140373518692351,/*: ffffa2e7bfbdcd80 */
+STORE, 140373518692352, 140373518696447,/*: ffffa2e7b0749e40 */
+ };
+ unsigned long set14[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140731667996672, 140737488351231,
+SNULL, 140731668000767, 140737488351231,
+STORE, 140731667996672, 140731668000767,
+STORE, 140731667865600, 140731668000767,
+STORE, 94077521272832, 94077521313791,
+SNULL, 94077521301503, 94077521313791,
+STORE, 94077521272832, 94077521301503,
+STORE, 94077521301504, 94077521313791,
+ERASE, 94077521301504, 94077521313791,
+STORE, 94077521305600, 94077521313791,
+STORE, 139826134630400, 139826136883199,
+SNULL, 139826134773759, 139826136883199,
+STORE, 139826134630400, 139826134773759,
+STORE, 139826134773760, 139826136883199,
+ERASE, 139826134773760, 139826136883199,
+STORE, 139826136870912, 139826136879103,
+STORE, 139826136879104, 139826136883199,
+STORE, 140731668013056, 140731668017151,
+STORE, 140731668000768, 140731668013055,
+STORE, 139826136862720, 139826136870911,
+STORE, 139826132406272, 139826134630399,
+SNULL, 139826134056959, 139826134630399,
+STORE, 139826132406272, 139826134056959,
+STORE, 139826134056960, 139826134630399,
+SNULL, 139826134056960, 139826134626303,
+STORE, 139826134626304, 139826134630399,
+STORE, 139826134056960, 139826134626303,
+ERASE, 139826134056960, 139826134626303,
+STORE, 139826134056960, 139826134626303,
+ERASE, 139826134626304, 139826134630399,
+STORE, 139826134626304, 139826134630399,
+STORE, 139826136842240, 139826136862719,
+STORE, 139826130022400, 139826132406271,
+SNULL, 139826130022400, 139826130288639,
+STORE, 139826130288640, 139826132406271,
+STORE, 139826130022400, 139826130288639,
+SNULL, 139826132381695, 139826132406271,
+STORE, 139826130288640, 139826132381695,
+STORE, 139826132381696, 139826132406271,
+SNULL, 139826132381696, 139826132402175,
+STORE, 139826132402176, 139826132406271,
+STORE, 139826132381696, 139826132402175,
+ERASE, 139826132381696, 139826132402175,
+STORE, 139826132381696, 139826132402175,
+ERASE, 139826132402176, 139826132406271,
+STORE, 139826132402176, 139826132406271,
+STORE, 139826127806464, 139826130022399,
+SNULL, 139826127806464, 139826127904767,
+STORE, 139826127904768, 139826130022399,
+STORE, 139826127806464, 139826127904767,
+SNULL, 139826129997823, 139826130022399,
+STORE, 139826127904768, 139826129997823,
+STORE, 139826129997824, 139826130022399,
+SNULL, 139826129997824, 139826130006015,
+STORE, 139826130006016, 139826130022399,
+STORE, 139826129997824, 139826130006015,
+ERASE, 139826129997824, 139826130006015,
+STORE, 139826129997824, 139826130006015,
+ERASE, 139826130006016, 139826130022399,
+STORE, 139826130006016, 139826130022399,
+STORE, 139826124009472, 139826127806463,
+SNULL, 139826124009472, 139826125668351,
+STORE, 139826125668352, 139826127806463,
+STORE, 139826124009472, 139826125668351,
+SNULL, 139826127765503, 139826127806463,
+STORE, 139826125668352, 139826127765503,
+STORE, 139826127765504, 139826127806463,
+SNULL, 139826127765504, 139826127790079,
+STORE, 139826127790080, 139826127806463,
+STORE, 139826127765504, 139826127790079,
+ERASE, 139826127765504, 139826127790079,
+STORE, 139826127765504, 139826127790079,
+ERASE, 139826127790080, 139826127806463,
+STORE, 139826127790080, 139826127806463,
+STORE, 139826121748480, 139826124009471,
+SNULL, 139826121748480, 139826121900031,
+STORE, 139826121900032, 139826124009471,
+STORE, 139826121748480, 139826121900031,
+SNULL, 139826123993087, 139826124009471,
+STORE, 139826121900032, 139826123993087,
+STORE, 139826123993088, 139826124009471,
+SNULL, 139826123993088, 139826124001279,
+STORE, 139826124001280, 139826124009471,
+STORE, 139826123993088, 139826124001279,
+ERASE, 139826123993088, 139826124001279,
+STORE, 139826123993088, 139826124001279,
+ERASE, 139826124001280, 139826124009471,
+STORE, 139826124001280, 139826124009471,
+STORE, 139826119626752, 139826121748479,
+SNULL, 139826119626752, 139826119643135,
+STORE, 139826119643136, 139826121748479,
+STORE, 139826119626752, 139826119643135,
+SNULL, 139826121740287, 139826121748479,
+STORE, 139826119643136, 139826121740287,
+STORE, 139826121740288, 139826121748479,
+ERASE, 139826121740288, 139826121748479,
+STORE, 139826121740288, 139826121748479,
+STORE, 139826136834048, 139826136842239,
+STORE, 139826117496832, 139826119626751,
+SNULL, 139826117496832, 139826117525503,
+STORE, 139826117525504, 139826119626751,
+STORE, 139826117496832, 139826117525503,
+SNULL, 139826119618559, 139826119626751,
+STORE, 139826117525504, 139826119618559,
+STORE, 139826119618560, 139826119626751,
+ERASE, 139826119618560, 139826119626751,
+STORE, 139826119618560, 139826119626751,
+STORE, 139826115244032, 139826117496831,
+SNULL, 139826115244032, 139826115395583,
+STORE, 139826115395584, 139826117496831,
+STORE, 139826115244032, 139826115395583,
+SNULL, 139826117488639, 139826117496831,
+STORE, 139826115395584, 139826117488639,
+STORE, 139826117488640, 139826117496831,
+ERASE, 139826117488640, 139826117496831,
+STORE, 139826117488640, 139826117496831,
+STORE, 139826113073152, 139826115244031,
+SNULL, 139826113073152, 139826113142783,
+STORE, 139826113142784, 139826115244031,
+STORE, 139826113073152, 139826113142783,
+SNULL, 139826115235839, 139826115244031,
+STORE, 139826113142784, 139826115235839,
+STORE, 139826115235840, 139826115244031,
+ERASE, 139826115235840, 139826115244031,
+STORE, 139826115235840, 139826115244031,
+STORE, 139826109861888, 139826113073151,
+SNULL, 139826109861888, 139826110939135,
+STORE, 139826110939136, 139826113073151,
+STORE, 139826109861888, 139826110939135,
+SNULL, 139826113036287, 139826113073151,
+STORE, 139826110939136, 139826113036287,
+STORE, 139826113036288, 139826113073151,
+ERASE, 139826113036288, 139826113073151,
+STORE, 139826113036288, 139826113073151,
+STORE, 139826107727872, 139826109861887,
+SNULL, 139826107727872, 139826107756543,
+STORE, 139826107756544, 139826109861887,
+STORE, 139826107727872, 139826107756543,
+SNULL, 139826109853695, 139826109861887,
+STORE, 139826107756544, 139826109853695,
+STORE, 139826109853696, 139826109861887,
+ERASE, 139826109853696, 139826109861887,
+STORE, 139826109853696, 139826109861887,
+STORE, 139826105417728, 139826107727871,
+SNULL, 139826105417728, 139826105622527,
+STORE, 139826105622528, 139826107727871,
+STORE, 139826105417728, 139826105622527,
+SNULL, 139826107719679, 139826107727871,
+STORE, 139826105622528, 139826107719679,
+STORE, 139826107719680, 139826107727871,
+ERASE, 139826107719680, 139826107727871,
+STORE, 139826107719680, 139826107727871,
+STORE, 139826136825856, 139826136842239,
+STORE, 139826103033856, 139826105417727,
+SNULL, 139826103033856, 139826103226367,
+STORE, 139826103226368, 139826105417727,
+STORE, 139826103033856, 139826103226367,
+SNULL, 139826105319423, 139826105417727,
+STORE, 139826103226368, 139826105319423,
+STORE, 139826105319424, 139826105417727,
+ERASE, 139826105319424, 139826105417727,
+STORE, 139826105319424, 139826105417727,
+STORE, 139826100916224, 139826103033855,
+SNULL, 139826100916224, 139826100932607,
+STORE, 139826100932608, 139826103033855,
+STORE, 139826100916224, 139826100932607,
+SNULL, 139826103025663, 139826103033855,
+STORE, 139826100932608, 139826103025663,
+STORE, 139826103025664, 139826103033855,
+ERASE, 139826103025664, 139826103033855,
+STORE, 139826103025664, 139826103033855,
+STORE, 139826098348032, 139826100916223,
+SNULL, 139826098348032, 139826098814975,
+STORE, 139826098814976, 139826100916223,
+STORE, 139826098348032, 139826098814975,
+SNULL, 139826100908031, 139826100916223,
+STORE, 139826098814976, 139826100908031,
+STORE, 139826100908032, 139826100916223,
+ERASE, 139826100908032, 139826100916223,
+STORE, 139826100908032, 139826100916223,
+STORE, 139826096234496, 139826098348031,
+SNULL, 139826096234496, 139826096246783,
+STORE, 139826096246784, 139826098348031,
+STORE, 139826096234496, 139826096246783,
+SNULL, 139826098339839, 139826098348031,
+STORE, 139826096246784, 139826098339839,
+STORE, 139826098339840, 139826098348031,
+ERASE, 139826098339840, 139826098348031,
+STORE, 139826098339840, 139826098348031,
+STORE, 139826094055424, 139826096234495,
+SNULL, 139826094055424, 139826094133247,
+STORE, 139826094133248, 139826096234495,
+STORE, 139826094055424, 139826094133247,
+SNULL, 139826096226303, 139826096234495,
+STORE, 139826094133248, 139826096226303,
+STORE, 139826096226304, 139826096234495,
+ERASE, 139826096226304, 139826096234495,
+STORE, 139826096226304, 139826096234495,
+STORE, 139826136817664, 139826136842239,
+STORE, 139826091937792, 139826094055423,
+SNULL, 139826091937792, 139826091954175,
+STORE, 139826091954176, 139826094055423,
+STORE, 139826091937792, 139826091954175,
+SNULL, 139826094047231, 139826094055423,
+STORE, 139826091954176, 139826094047231,
+STORE, 139826094047232, 139826094055423,
+ERASE, 139826094047232, 139826094055423,
+STORE, 139826094047232, 139826094055423,
+STORE, 139826136809472, 139826136842239,
+SNULL, 139826127781887, 139826127790079,
+STORE, 139826127765504, 139826127781887,
+STORE, 139826127781888, 139826127790079,
+SNULL, 139826094051327, 139826094055423,
+STORE, 139826094047232, 139826094051327,
+STORE, 139826094051328, 139826094055423,
+SNULL, 139826096230399, 139826096234495,
+STORE, 139826096226304, 139826096230399,
+STORE, 139826096230400, 139826096234495,
+SNULL, 139826098343935, 139826098348031,
+STORE, 139826098339840, 139826098343935,
+STORE, 139826098343936, 139826098348031,
+SNULL, 139826130001919, 139826130006015,
+STORE, 139826129997824, 139826130001919,
+STORE, 139826130001920, 139826130006015,
+SNULL, 139826100912127, 139826100916223,
+STORE, 139826100908032, 139826100912127,
+STORE, 139826100912128, 139826100916223,
+SNULL, 139826103029759, 139826103033855,
+STORE, 139826103025664, 139826103029759,
+STORE, 139826103029760, 139826103033855,
+SNULL, 139826105413631, 139826105417727,
+STORE, 139826105319424, 139826105413631,
+STORE, 139826105413632, 139826105417727,
+SNULL, 139826107723775, 139826107727871,
+STORE, 139826107719680, 139826107723775,
+STORE, 139826107723776, 139826107727871,
+SNULL, 139826109857791, 139826109861887,
+STORE, 139826109853696, 139826109857791,
+STORE, 139826109857792, 139826109861887,
+SNULL, 139826113044479, 139826113073151,
+STORE, 139826113036288, 139826113044479,
+STORE, 139826113044480, 139826113073151,
+SNULL, 139826115239935, 139826115244031,
+STORE, 139826115235840, 139826115239935,
+STORE, 139826115239936, 139826115244031,
+SNULL, 139826117492735, 139826117496831,
+STORE, 139826117488640, 139826117492735,
+STORE, 139826117492736, 139826117496831,
+SNULL, 139826119622655, 139826119626751,
+STORE, 139826119618560, 139826119622655,
+STORE, 139826119622656, 139826119626751,
+SNULL, 139826121744383, 139826121748479,
+STORE, 139826121740288, 139826121744383,
+STORE, 139826121744384, 139826121748479,
+SNULL, 139826123997183, 139826124001279,
+STORE, 139826123993088, 139826123997183,
+STORE, 139826123997184, 139826124001279,
+SNULL, 139826132398079, 139826132402175,
+STORE, 139826132381696, 139826132398079,
+STORE, 139826132398080, 139826132402175,
+SNULL, 139826134622207, 139826134626303,
+STORE, 139826134056960, 139826134622207,
+STORE, 139826134622208, 139826134626303,
+SNULL, 94077521309695, 94077521313791,
+STORE, 94077521305600, 94077521309695,
+STORE, 94077521309696, 94077521313791,
+SNULL, 139826136875007, 139826136879103,
+STORE, 139826136870912, 139826136875007,
+STORE, 139826136875008, 139826136879103,
+ERASE, 139826136842240, 139826136862719,
+STORE, 94077554049024, 94077554184191,
+STORE, 139826136543232, 139826136842239,
+STORE, 139826136276992, 139826136842239,
+STORE, 139826136010752, 139826136842239,
+STORE, 139826135744512, 139826136842239,
+SNULL, 139826136543231, 139826136842239,
+STORE, 139826135744512, 139826136543231,
+STORE, 139826136543232, 139826136842239,
+SNULL, 139826136543232, 139826136809471,
+STORE, 139826136809472, 139826136842239,
+STORE, 139826136543232, 139826136809471,
+ };
+ unsigned long set15[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140722061451264, 140737488351231,
+SNULL, 140722061455359, 140737488351231,
+STORE, 140722061451264, 140722061455359,
+STORE, 140722061320192, 140722061455359,
+STORE, 94728600248320, 94728600289279,
+SNULL, 94728600276991, 94728600289279,
+STORE, 94728600248320, 94728600276991,
+STORE, 94728600276992, 94728600289279,
+ERASE, 94728600276992, 94728600289279,
+STORE, 94728600281088, 94728600289279,
+STORE, 139906806779904, 139906809032703,
+SNULL, 139906806923263, 139906809032703,
+STORE, 139906806779904, 139906806923263,
+STORE, 139906806923264, 139906809032703,
+ERASE, 139906806923264, 139906809032703,
+STORE, 139906809020416, 139906809028607,
+STORE, 139906809028608, 139906809032703,
+STORE, 140722061692928, 140722061697023,
+STORE, 140722061680640, 140722061692927,
+STORE, 139906809012224, 139906809020415,
+STORE, 139906804555776, 139906806779903,
+SNULL, 139906806206463, 139906806779903,
+STORE, 139906804555776, 139906806206463,
+STORE, 139906806206464, 139906806779903,
+SNULL, 139906806206464, 139906806775807,
+STORE, 139906806775808, 139906806779903,
+STORE, 139906806206464, 139906806775807,
+ERASE, 139906806206464, 139906806775807,
+STORE, 139906806206464, 139906806775807,
+ERASE, 139906806775808, 139906806779903,
+STORE, 139906806775808, 139906806779903,
+STORE, 139906808991744, 139906809012223,
+STORE, 139906802171904, 139906804555775,
+SNULL, 139906802171904, 139906802438143,
+STORE, 139906802438144, 139906804555775,
+STORE, 139906802171904, 139906802438143,
+SNULL, 139906804531199, 139906804555775,
+STORE, 139906802438144, 139906804531199,
+STORE, 139906804531200, 139906804555775,
+SNULL, 139906804531200, 139906804551679,
+STORE, 139906804551680, 139906804555775,
+STORE, 139906804531200, 139906804551679,
+ERASE, 139906804531200, 139906804551679,
+STORE, 139906804531200, 139906804551679,
+ERASE, 139906804551680, 139906804555775,
+STORE, 139906804551680, 139906804555775,
+STORE, 139906799955968, 139906802171903,
+SNULL, 139906799955968, 139906800054271,
+STORE, 139906800054272, 139906802171903,
+STORE, 139906799955968, 139906800054271,
+SNULL, 139906802147327, 139906802171903,
+STORE, 139906800054272, 139906802147327,
+STORE, 139906802147328, 139906802171903,
+SNULL, 139906802147328, 139906802155519,
+STORE, 139906802155520, 139906802171903,
+STORE, 139906802147328, 139906802155519,
+ERASE, 139906802147328, 139906802155519,
+STORE, 139906802147328, 139906802155519,
+ERASE, 139906802155520, 139906802171903,
+STORE, 139906802155520, 139906802171903,
+STORE, 139906796158976, 139906799955967,
+SNULL, 139906796158976, 139906797817855,
+STORE, 139906797817856, 139906799955967,
+STORE, 139906796158976, 139906797817855,
+SNULL, 139906799915007, 139906799955967,
+STORE, 139906797817856, 139906799915007,
+STORE, 139906799915008, 139906799955967,
+SNULL, 139906799915008, 139906799939583,
+STORE, 139906799939584, 139906799955967,
+STORE, 139906799915008, 139906799939583,
+ERASE, 139906799915008, 139906799939583,
+STORE, 139906799915008, 139906799939583,
+ERASE, 139906799939584, 139906799955967,
+STORE, 139906799939584, 139906799955967,
+STORE, 139906793897984, 139906796158975,
+SNULL, 139906793897984, 139906794049535,
+STORE, 139906794049536, 139906796158975,
+STORE, 139906793897984, 139906794049535,
+SNULL, 139906796142591, 139906796158975,
+STORE, 139906794049536, 139906796142591,
+STORE, 139906796142592, 139906796158975,
+SNULL, 139906796142592, 139906796150783,
+STORE, 139906796150784, 139906796158975,
+STORE, 139906796142592, 139906796150783,
+ERASE, 139906796142592, 139906796150783,
+STORE, 139906796142592, 139906796150783,
+ERASE, 139906796150784, 139906796158975,
+STORE, 139906796150784, 139906796158975,
+STORE, 139906791776256, 139906793897983,
+SNULL, 139906791776256, 139906791792639,
+STORE, 139906791792640, 139906793897983,
+STORE, 139906791776256, 139906791792639,
+SNULL, 139906793889791, 139906793897983,
+STORE, 139906791792640, 139906793889791,
+STORE, 139906793889792, 139906793897983,
+ERASE, 139906793889792, 139906793897983,
+STORE, 139906793889792, 139906793897983,
+STORE, 139906808983552, 139906808991743,
+STORE, 139906789646336, 139906791776255,
+SNULL, 139906789646336, 139906789675007,
+STORE, 139906789675008, 139906791776255,
+STORE, 139906789646336, 139906789675007,
+SNULL, 139906791768063, 139906791776255,
+STORE, 139906789675008, 139906791768063,
+STORE, 139906791768064, 139906791776255,
+ERASE, 139906791768064, 139906791776255,
+STORE, 139906791768064, 139906791776255,
+STORE, 139906787393536, 139906789646335,
+SNULL, 139906787393536, 139906787545087,
+STORE, 139906787545088, 139906789646335,
+STORE, 139906787393536, 139906787545087,
+SNULL, 139906789638143, 139906789646335,
+STORE, 139906787545088, 139906789638143,
+STORE, 139906789638144, 139906789646335,
+ERASE, 139906789638144, 139906789646335,
+STORE, 139906789638144, 139906789646335,
+STORE, 139906785222656, 139906787393535,
+SNULL, 139906785222656, 139906785292287,
+STORE, 139906785292288, 139906787393535,
+STORE, 139906785222656, 139906785292287,
+SNULL, 139906787385343, 139906787393535,
+STORE, 139906785292288, 139906787385343,
+STORE, 139906787385344, 139906787393535,
+ERASE, 139906787385344, 139906787393535,
+STORE, 139906787385344, 139906787393535,
+STORE, 139906782011392, 139906785222655,
+SNULL, 139906782011392, 139906783088639,
+STORE, 139906783088640, 139906785222655,
+STORE, 139906782011392, 139906783088639,
+SNULL, 139906785185791, 139906785222655,
+STORE, 139906783088640, 139906785185791,
+STORE, 139906785185792, 139906785222655,
+ERASE, 139906785185792, 139906785222655,
+STORE, 139906785185792, 139906785222655,
+STORE, 139906779877376, 139906782011391,
+SNULL, 139906779877376, 139906779906047,
+STORE, 139906779906048, 139906782011391,
+STORE, 139906779877376, 139906779906047,
+SNULL, 139906782003199, 139906782011391,
+STORE, 139906779906048, 139906782003199,
+STORE, 139906782003200, 139906782011391,
+ERASE, 139906782003200, 139906782011391,
+STORE, 139906782003200, 139906782011391,
+STORE, 139906777567232, 139906779877375,
+SNULL, 139906777567232, 139906777772031,
+STORE, 139906777772032, 139906779877375,
+STORE, 139906777567232, 139906777772031,
+SNULL, 139906779869183, 139906779877375,
+STORE, 139906777772032, 139906779869183,
+STORE, 139906779869184, 139906779877375,
+ERASE, 139906779869184, 139906779877375,
+STORE, 139906779869184, 139906779877375,
+STORE, 139906808975360, 139906808991743,
+STORE, 139906775183360, 139906777567231,
+SNULL, 139906775183360, 139906775375871,
+STORE, 139906775375872, 139906777567231,
+STORE, 139906775183360, 139906775375871,
+SNULL, 139906777468927, 139906777567231,
+STORE, 139906775375872, 139906777468927,
+STORE, 139906777468928, 139906777567231,
+ERASE, 139906777468928, 139906777567231,
+STORE, 139906777468928, 139906777567231,
+STORE, 139906773065728, 139906775183359,
+SNULL, 139906773065728, 139906773082111,
+STORE, 139906773082112, 139906775183359,
+STORE, 139906773065728, 139906773082111,
+SNULL, 139906775175167, 139906775183359,
+STORE, 139906773082112, 139906775175167,
+STORE, 139906775175168, 139906775183359,
+ERASE, 139906775175168, 139906775183359,
+STORE, 139906775175168, 139906775183359,
+STORE, 139906770497536, 139906773065727,
+SNULL, 139906770497536, 139906770964479,
+STORE, 139906770964480, 139906773065727,
+STORE, 139906770497536, 139906770964479,
+SNULL, 139906773057535, 139906773065727,
+STORE, 139906770964480, 139906773057535,
+STORE, 139906773057536, 139906773065727,
+ERASE, 139906773057536, 139906773065727,
+STORE, 139906773057536, 139906773065727,
+STORE, 139906768384000, 139906770497535,
+SNULL, 139906768384000, 139906768396287,
+STORE, 139906768396288, 139906770497535,
+STORE, 139906768384000, 139906768396287,
+SNULL, 139906770489343, 139906770497535,
+STORE, 139906768396288, 139906770489343,
+STORE, 139906770489344, 139906770497535,
+ERASE, 139906770489344, 139906770497535,
+STORE, 139906770489344, 139906770497535,
+STORE, 139906766204928, 139906768383999,
+SNULL, 139906766204928, 139906766282751,
+STORE, 139906766282752, 139906768383999,
+STORE, 139906766204928, 139906766282751,
+SNULL, 139906768375807, 139906768383999,
+STORE, 139906766282752, 139906768375807,
+STORE, 139906768375808, 139906768383999,
+ERASE, 139906768375808, 139906768383999,
+STORE, 139906768375808, 139906768383999,
+STORE, 139906808967168, 139906808991743,
+STORE, 139906764087296, 139906766204927,
+SNULL, 139906764087296, 139906764103679,
+STORE, 139906764103680, 139906766204927,
+STORE, 139906764087296, 139906764103679,
+SNULL, 139906766196735, 139906766204927,
+STORE, 139906764103680, 139906766196735,
+STORE, 139906766196736, 139906766204927,
+ERASE, 139906766196736, 139906766204927,
+STORE, 139906766196736, 139906766204927,
+STORE, 139906808958976, 139906808991743,
+SNULL, 139906799931391, 139906799939583,
+STORE, 139906799915008, 139906799931391,
+STORE, 139906799931392, 139906799939583,
+SNULL, 139906766200831, 139906766204927,
+STORE, 139906766196736, 139906766200831,
+STORE, 139906766200832, 139906766204927,
+SNULL, 139906768379903, 139906768383999,
+STORE, 139906768375808, 139906768379903,
+STORE, 139906768379904, 139906768383999,
+SNULL, 139906770493439, 139906770497535,
+STORE, 139906770489344, 139906770493439,
+STORE, 139906770493440, 139906770497535,
+SNULL, 139906802151423, 139906802155519,
+STORE, 139906802147328, 139906802151423,
+STORE, 139906802151424, 139906802155519,
+SNULL, 139906773061631, 139906773065727,
+STORE, 139906773057536, 139906773061631,
+STORE, 139906773061632, 139906773065727,
+SNULL, 139906775179263, 139906775183359,
+STORE, 139906775175168, 139906775179263,
+STORE, 139906775179264, 139906775183359,
+SNULL, 139906777563135, 139906777567231,
+STORE, 139906777468928, 139906777563135,
+STORE, 139906777563136, 139906777567231,
+SNULL, 139906779873279, 139906779877375,
+STORE, 139906779869184, 139906779873279,
+STORE, 139906779873280, 139906779877375,
+SNULL, 139906782007295, 139906782011391,
+STORE, 139906782003200, 139906782007295,
+STORE, 139906782007296, 139906782011391,
+SNULL, 139906785193983, 139906785222655,
+STORE, 139906785185792, 139906785193983,
+STORE, 139906785193984, 139906785222655,
+SNULL, 139906787389439, 139906787393535,
+STORE, 139906787385344, 139906787389439,
+STORE, 139906787389440, 139906787393535,
+SNULL, 139906789642239, 139906789646335,
+STORE, 139906789638144, 139906789642239,
+STORE, 139906789642240, 139906789646335,
+SNULL, 139906791772159, 139906791776255,
+STORE, 139906791768064, 139906791772159,
+STORE, 139906791772160, 139906791776255,
+SNULL, 139906793893887, 139906793897983,
+STORE, 139906793889792, 139906793893887,
+STORE, 139906793893888, 139906793897983,
+SNULL, 139906796146687, 139906796150783,
+STORE, 139906796142592, 139906796146687,
+STORE, 139906796146688, 139906796150783,
+SNULL, 139906804547583, 139906804551679,
+STORE, 139906804531200, 139906804547583,
+STORE, 139906804547584, 139906804551679,
+SNULL, 139906806771711, 139906806775807,
+STORE, 139906806206464, 139906806771711,
+STORE, 139906806771712, 139906806775807,
+SNULL, 94728600285183, 94728600289279,
+STORE, 94728600281088, 94728600285183,
+STORE, 94728600285184, 94728600289279,
+SNULL, 139906809024511, 139906809028607,
+STORE, 139906809020416, 139906809024511,
+STORE, 139906809024512, 139906809028607,
+ERASE, 139906808991744, 139906809012223,
+STORE, 94728620138496, 94728620273663,
+STORE, 139906808692736, 139906808991743,
+STORE, 139906808426496, 139906808991743,
+STORE, 139906808160256, 139906808991743,
+STORE, 139906807894016, 139906808991743,
+SNULL, 139906808692735, 139906808991743,
+STORE, 139906807894016, 139906808692735,
+STORE, 139906808692736, 139906808991743,
+SNULL, 139906808692736, 139906808958975,
+STORE, 139906808958976, 139906808991743,
+STORE, 139906808692736, 139906808958975,
+ };
+
+ unsigned long set16[] = {
+STORE, 94174808662016, 94174809321471,
+STORE, 94174811414528, 94174811426815,
+STORE, 94174811426816, 94174811430911,
+STORE, 94174811430912, 94174811443199,
+STORE, 94174841700352, 94174841835519,
+STORE, 140173257838592, 140173259497471,
+STORE, 140173259497472, 140173261594623,
+STORE, 140173261594624, 140173261611007,
+STORE, 140173261611008, 140173261619199,
+STORE, 140173261619200, 140173261635583,
+STORE, 140173261635584, 140173261778943,
+STORE, 140173263863808, 140173263871999,
+STORE, 140173263876096, 140173263880191,
+STORE, 140173263880192, 140173263884287,
+STORE, 140173263884288, 140173263888383,
+STORE, 140729801007104, 140729801142271,
+STORE, 140729801617408, 140729801629695,
+STORE, 140729801629696, 140729801633791,
+STORE, 140737488347136, 140737488351231,
+STORE, 140728166858752, 140737488351231,
+SNULL, 140728166862847, 140737488351231,
+STORE, 140728166858752, 140728166862847,
+STORE, 140728166727680, 140728166862847,
+STORE, 93912949866496, 93912950337535,
+SNULL, 93912950288383, 93912950337535,
+STORE, 93912949866496, 93912950288383,
+STORE, 93912950288384, 93912950337535,
+ERASE, 93912950288384, 93912950337535,
+STORE, 93912950292480, 93912950337535,
+STORE, 139921863385088, 139921865637887,
+SNULL, 139921863528447, 139921865637887,
+STORE, 139921863385088, 139921863528447,
+STORE, 139921863528448, 139921865637887,
+ERASE, 139921863528448, 139921865637887,
+STORE, 139921865625600, 139921865633791,
+STORE, 139921865633792, 139921865637887,
+STORE, 140728167899136, 140728167903231,
+STORE, 140728167886848, 140728167899135,
+STORE, 139921865601024, 139921865625599,
+STORE, 139921865592832, 139921865601023,
+STORE, 139921861251072, 139921863385087,
+SNULL, 139921861251072, 139921861279743,
+STORE, 139921861279744, 139921863385087,
+STORE, 139921861251072, 139921861279743,
+SNULL, 139921863376895, 139921863385087,
+STORE, 139921861279744, 139921863376895,
+STORE, 139921863376896, 139921863385087,
+ERASE, 139921863376896, 139921863385087,
+STORE, 139921863376896, 139921863385087,
+STORE, 139921858867200, 139921861251071,
+SNULL, 139921858867200, 139921859133439,
+STORE, 139921859133440, 139921861251071,
+STORE, 139921858867200, 139921859133439,
+SNULL, 139921861226495, 139921861251071,
+STORE, 139921859133440, 139921861226495,
+STORE, 139921861226496, 139921861251071,
+SNULL, 139921861226496, 139921861246975,
+STORE, 139921861246976, 139921861251071,
+STORE, 139921861226496, 139921861246975,
+ERASE, 139921861226496, 139921861246975,
+STORE, 139921861226496, 139921861246975,
+ERASE, 139921861246976, 139921861251071,
+STORE, 139921861246976, 139921861251071,
+STORE, 139921856675840, 139921858867199,
+SNULL, 139921856675840, 139921856765951,
+STORE, 139921856765952, 139921858867199,
+STORE, 139921856675840, 139921856765951,
+SNULL, 139921858859007, 139921858867199,
+STORE, 139921856765952, 139921858859007,
+STORE, 139921858859008, 139921858867199,
+ERASE, 139921858859008, 139921858867199,
+STORE, 139921858859008, 139921858867199,
+STORE, 139921854414848, 139921856675839,
+SNULL, 139921854414848, 139921854566399,
+STORE, 139921854566400, 139921856675839,
+STORE, 139921854414848, 139921854566399,
+SNULL, 139921856659455, 139921856675839,
+STORE, 139921854566400, 139921856659455,
+STORE, 139921856659456, 139921856675839,
+SNULL, 139921856659456, 139921856667647,
+STORE, 139921856667648, 139921856675839,
+STORE, 139921856659456, 139921856667647,
+ERASE, 139921856659456, 139921856667647,
+STORE, 139921856659456, 139921856667647,
+ERASE, 139921856667648, 139921856675839,
+STORE, 139921856667648, 139921856675839,
+STORE, 139921852284928, 139921854414847,
+SNULL, 139921852284928, 139921852313599,
+STORE, 139921852313600, 139921854414847,
+STORE, 139921852284928, 139921852313599,
+SNULL, 139921854406655, 139921854414847,
+STORE, 139921852313600, 139921854406655,
+STORE, 139921854406656, 139921854414847,
+ERASE, 139921854406656, 139921854414847,
+STORE, 139921854406656, 139921854414847,
+STORE, 139921850068992, 139921852284927,
+SNULL, 139921850068992, 139921850167295,
+STORE, 139921850167296, 139921852284927,
+STORE, 139921850068992, 139921850167295,
+SNULL, 139921852260351, 139921852284927,
+STORE, 139921850167296, 139921852260351,
+STORE, 139921852260352, 139921852284927,
+SNULL, 139921852260352, 139921852268543,
+STORE, 139921852268544, 139921852284927,
+STORE, 139921852260352, 139921852268543,
+ERASE, 139921852260352, 139921852268543,
+STORE, 139921852260352, 139921852268543,
+ERASE, 139921852268544, 139921852284927,
+STORE, 139921852268544, 139921852284927,
+STORE, 139921865584640, 139921865601023,
+STORE, 139921846272000, 139921850068991,
+SNULL, 139921846272000, 139921847930879,
+STORE, 139921847930880, 139921850068991,
+STORE, 139921846272000, 139921847930879,
+SNULL, 139921850028031, 139921850068991,
+STORE, 139921847930880, 139921850028031,
+STORE, 139921850028032, 139921850068991,
+SNULL, 139921850028032, 139921850052607,
+STORE, 139921850052608, 139921850068991,
+STORE, 139921850028032, 139921850052607,
+ERASE, 139921850028032, 139921850052607,
+STORE, 139921850028032, 139921850052607,
+ERASE, 139921850052608, 139921850068991,
+STORE, 139921850052608, 139921850068991,
+STORE, 139921844154368, 139921846271999,
+SNULL, 139921844154368, 139921844170751,
+STORE, 139921844170752, 139921846271999,
+STORE, 139921844154368, 139921844170751,
+SNULL, 139921846263807, 139921846271999,
+STORE, 139921844170752, 139921846263807,
+STORE, 139921846263808, 139921846271999,
+ERASE, 139921846263808, 139921846271999,
+STORE, 139921846263808, 139921846271999,
+STORE, 139921842036736, 139921844154367,
+SNULL, 139921842036736, 139921842053119,
+STORE, 139921842053120, 139921844154367,
+STORE, 139921842036736, 139921842053119,
+SNULL, 139921844146175, 139921844154367,
+STORE, 139921842053120, 139921844146175,
+STORE, 139921844146176, 139921844154367,
+ERASE, 139921844146176, 139921844154367,
+STORE, 139921844146176, 139921844154367,
+STORE, 139921839468544, 139921842036735,
+SNULL, 139921839468544, 139921839935487,
+STORE, 139921839935488, 139921842036735,
+STORE, 139921839468544, 139921839935487,
+SNULL, 139921842028543, 139921842036735,
+STORE, 139921839935488, 139921842028543,
+STORE, 139921842028544, 139921842036735,
+ERASE, 139921842028544, 139921842036735,
+STORE, 139921842028544, 139921842036735,
+STORE, 139921837355008, 139921839468543,
+SNULL, 139921837355008, 139921837367295,
+STORE, 139921837367296, 139921839468543,
+STORE, 139921837355008, 139921837367295,
+SNULL, 139921839460351, 139921839468543,
+STORE, 139921837367296, 139921839460351,
+STORE, 139921839460352, 139921839468543,
+ERASE, 139921839460352, 139921839468543,
+STORE, 139921839460352, 139921839468543,
+STORE, 139921865576448, 139921865601023,
+STORE, 139921865564160, 139921865601023,
+SNULL, 139921850044415, 139921850052607,
+STORE, 139921850028032, 139921850044415,
+STORE, 139921850044416, 139921850052607,
+SNULL, 139921839464447, 139921839468543,
+STORE, 139921839460352, 139921839464447,
+STORE, 139921839464448, 139921839468543,
+SNULL, 139921852264447, 139921852268543,
+STORE, 139921852260352, 139921852264447,
+STORE, 139921852264448, 139921852268543,
+SNULL, 139921842032639, 139921842036735,
+STORE, 139921842028544, 139921842032639,
+STORE, 139921842032640, 139921842036735,
+SNULL, 139921844150271, 139921844154367,
+STORE, 139921844146176, 139921844150271,
+STORE, 139921844150272, 139921844154367,
+SNULL, 139921846267903, 139921846271999,
+STORE, 139921846263808, 139921846267903,
+STORE, 139921846267904, 139921846271999,
+SNULL, 139921854410751, 139921854414847,
+STORE, 139921854406656, 139921854410751,
+STORE, 139921854410752, 139921854414847,
+SNULL, 139921856663551, 139921856667647,
+STORE, 139921856659456, 139921856663551,
+STORE, 139921856663552, 139921856667647,
+SNULL, 139921858863103, 139921858867199,
+STORE, 139921858859008, 139921858863103,
+STORE, 139921858863104, 139921858867199,
+SNULL, 139921861242879, 139921861246975,
+STORE, 139921861226496, 139921861242879,
+STORE, 139921861242880, 139921861246975,
+SNULL, 139921863380991, 139921863385087,
+STORE, 139921863376896, 139921863380991,
+STORE, 139921863380992, 139921863385087,
+SNULL, 93912950333439, 93912950337535,
+STORE, 93912950292480, 93912950333439,
+STORE, 93912950333440, 93912950337535,
+SNULL, 139921865629695, 139921865633791,
+STORE, 139921865625600, 139921865629695,
+STORE, 139921865629696, 139921865633791,
+ERASE, 139921865601024, 139921865625599,
+STORE, 93912968110080, 93912968245247,
+STORE, 139921828913152, 139921837355007,
+STORE, 139921865621504, 139921865625599,
+STORE, 139921865617408, 139921865621503,
+STORE, 139921865613312, 139921865617407,
+STORE, 139921865547776, 139921865564159,
+ };
+
+ unsigned long set17[] = {
+STORE, 94397057224704, 94397057646591,
+STORE, 94397057650688, 94397057691647,
+STORE, 94397057691648, 94397057695743,
+STORE, 94397075271680, 94397075406847,
+STORE, 139953169051648, 139953169063935,
+STORE, 139953169063936, 139953171156991,
+STORE, 139953171156992, 139953171161087,
+STORE, 139953171161088, 139953171165183,
+STORE, 139953171165184, 139953171632127,
+STORE, 139953171632128, 139953173725183,
+STORE, 139953173725184, 139953173729279,
+STORE, 139953173729280, 139953173733375,
+STORE, 139953173733376, 139953173749759,
+STORE, 139953173749760, 139953175842815,
+STORE, 139953175842816, 139953175846911,
+STORE, 139953175846912, 139953175851007,
+STORE, 139953175851008, 139953175867391,
+STORE, 139953175867392, 139953177960447,
+STORE, 139953177960448, 139953177964543,
+STORE, 139953177964544, 139953177968639,
+STORE, 139953177968640, 139953179627519,
+STORE, 139953179627520, 139953181724671,
+STORE, 139953181724672, 139953181741055,
+STORE, 139953181741056, 139953181749247,
+STORE, 139953181749248, 139953181765631,
+STORE, 139953181765632, 139953181863935,
+STORE, 139953181863936, 139953183956991,
+STORE, 139953183956992, 139953183961087,
+STORE, 139953183961088, 139953183965183,
+STORE, 139953183965184, 139953183981567,
+STORE, 139953183981568, 139953184010239,
+STORE, 139953184010240, 139953186103295,
+STORE, 139953186103296, 139953186107391,
+STORE, 139953186107392, 139953186111487,
+STORE, 139953186111488, 139953186263039,
+STORE, 139953186263040, 139953188356095,
+STORE, 139953188356096, 139953188360191,
+STORE, 139953188360192, 139953188364287,
+STORE, 139953188364288, 139953188372479,
+STORE, 139953188372480, 139953188462591,
+STORE, 139953188462592, 139953190555647,
+STORE, 139953190555648, 139953190559743,
+STORE, 139953190559744, 139953190563839,
+STORE, 139953190563840, 139953190830079,
+STORE, 139953190830080, 139953192923135,
+STORE, 139953192923136, 139953192939519,
+STORE, 139953192939520, 139953192943615,
+STORE, 139953192943616, 139953192947711,
+STORE, 139953192947712, 139953192976383,
+STORE, 139953192976384, 139953195073535,
+STORE, 139953195073536, 139953195077631,
+STORE, 139953195077632, 139953195081727,
+STORE, 139953195081728, 139953195225087,
+STORE, 139953197281280, 139953197318143,
+STORE, 139953197322240, 139953197326335,
+STORE, 139953197326336, 139953197330431,
+STORE, 139953197330432, 139953197334527,
+STORE, 140720477511680, 140720477646847,
+STORE, 140720478302208, 140720478314495,
+STORE, 140720478314496, 140720478318591,
+ };
+ unsigned long set18[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140724953673728, 140737488351231,
+SNULL, 140724953677823, 140737488351231,
+STORE, 140724953673728, 140724953677823,
+STORE, 140724953542656, 140724953677823,
+STORE, 94675199266816, 94675199311871,
+SNULL, 94675199303679, 94675199311871,
+STORE, 94675199266816, 94675199303679,
+STORE, 94675199303680, 94675199311871,
+ERASE, 94675199303680, 94675199311871,
+STORE, 94675199303680, 94675199311871,
+STORE, 140222970605568, 140222972858367,
+SNULL, 140222970748927, 140222972858367,
+STORE, 140222970605568, 140222970748927,
+STORE, 140222970748928, 140222972858367,
+ERASE, 140222970748928, 140222972858367,
+STORE, 140222972846080, 140222972854271,
+STORE, 140222972854272, 140222972858367,
+STORE, 140724954365952, 140724954370047,
+STORE, 140724954353664, 140724954365951,
+STORE, 140222972841984, 140222972846079,
+STORE, 140222972833792, 140222972841983,
+STORE, 140222968475648, 140222970605567,
+SNULL, 140222968475648, 140222968504319,
+STORE, 140222968504320, 140222970605567,
+STORE, 140222968475648, 140222968504319,
+SNULL, 140222970597375, 140222970605567,
+STORE, 140222968504320, 140222970597375,
+STORE, 140222970597376, 140222970605567,
+ERASE, 140222970597376, 140222970605567,
+STORE, 140222970597376, 140222970605567,
+ };
+ unsigned long set19[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140725182459904, 140737488351231,
+SNULL, 140725182463999, 140737488351231,
+STORE, 140725182459904, 140725182463999,
+STORE, 140725182328832, 140725182463999,
+STORE, 94730166636544, 94730166763519,
+SNULL, 94730166747135, 94730166763519,
+STORE, 94730166636544, 94730166747135,
+STORE, 94730166747136, 94730166763519,
+ERASE, 94730166747136, 94730166763519,
+STORE, 94730166751232, 94730166763519,
+STORE, 140656834555904, 140656836808703,
+SNULL, 140656834699263, 140656836808703,
+STORE, 140656834555904, 140656834699263,
+STORE, 140656834699264, 140656836808703,
+ERASE, 140656834699264, 140656836808703,
+STORE, 140656836796416, 140656836804607,
+STORE, 140656836804608, 140656836808703,
+STORE, 140725183389696, 140725183393791,
+STORE, 140725183377408, 140725183389695,
+STORE, 140656836788224, 140656836796415,
+STORE, 140656832331776, 140656834555903,
+SNULL, 140656833982463, 140656834555903,
+STORE, 140656832331776, 140656833982463,
+STORE, 140656833982464, 140656834555903,
+SNULL, 140656833982464, 140656834551807,
+STORE, 140656834551808, 140656834555903,
+STORE, 140656833982464, 140656834551807,
+ERASE, 140656833982464, 140656834551807,
+STORE, 140656833982464, 140656834551807,
+ERASE, 140656834551808, 140656834555903,
+STORE, 140656834551808, 140656834555903,
+STORE, 140656836763648, 140656836788223,
+STORE, 140656830070784, 140656832331775,
+SNULL, 140656830070784, 140656830222335,
+STORE, 140656830222336, 140656832331775,
+STORE, 140656830070784, 140656830222335,
+SNULL, 140656832315391, 140656832331775,
+STORE, 140656830222336, 140656832315391,
+STORE, 140656832315392, 140656832331775,
+SNULL, 140656832315392, 140656832323583,
+STORE, 140656832323584, 140656832331775,
+STORE, 140656832315392, 140656832323583,
+ERASE, 140656832315392, 140656832323583,
+STORE, 140656832315392, 140656832323583,
+ERASE, 140656832323584, 140656832331775,
+STORE, 140656832323584, 140656832331775,
+STORE, 140656827940864, 140656830070783,
+SNULL, 140656827940864, 140656827969535,
+STORE, 140656827969536, 140656830070783,
+STORE, 140656827940864, 140656827969535,
+SNULL, 140656830062591, 140656830070783,
+STORE, 140656827969536, 140656830062591,
+STORE, 140656830062592, 140656830070783,
+ERASE, 140656830062592, 140656830070783,
+STORE, 140656830062592, 140656830070783,
+STORE, 140656825724928, 140656827940863,
+SNULL, 140656825724928, 140656825823231,
+STORE, 140656825823232, 140656827940863,
+STORE, 140656825724928, 140656825823231,
+SNULL, 140656827916287, 140656827940863,
+STORE, 140656825823232, 140656827916287,
+STORE, 140656827916288, 140656827940863,
+SNULL, 140656827916288, 140656827924479,
+STORE, 140656827924480, 140656827940863,
+STORE, 140656827916288, 140656827924479,
+ERASE, 140656827916288, 140656827924479,
+STORE, 140656827916288, 140656827924479,
+ERASE, 140656827924480, 140656827940863,
+STORE, 140656827924480, 140656827940863,
+STORE, 140656821927936, 140656825724927,
+SNULL, 140656821927936, 140656823586815,
+STORE, 140656823586816, 140656825724927,
+STORE, 140656821927936, 140656823586815,
+SNULL, 140656825683967, 140656825724927,
+STORE, 140656823586816, 140656825683967,
+STORE, 140656825683968, 140656825724927,
+SNULL, 140656825683968, 140656825708543,
+STORE, 140656825708544, 140656825724927,
+STORE, 140656825683968, 140656825708543,
+ERASE, 140656825683968, 140656825708543,
+STORE, 140656825683968, 140656825708543,
+ERASE, 140656825708544, 140656825724927,
+STORE, 140656825708544, 140656825724927,
+STORE, 140656819806208, 140656821927935,
+SNULL, 140656819806208, 140656819822591,
+STORE, 140656819822592, 140656821927935,
+STORE, 140656819806208, 140656819822591,
+SNULL, 140656821919743, 140656821927935,
+STORE, 140656819822592, 140656821919743,
+STORE, 140656821919744, 140656821927935,
+ERASE, 140656821919744, 140656821927935,
+STORE, 140656821919744, 140656821927935,
+STORE, 140656836755456, 140656836763647,
+STORE, 140656817553408, 140656819806207,
+SNULL, 140656817553408, 140656817704959,
+STORE, 140656817704960, 140656819806207,
+STORE, 140656817553408, 140656817704959,
+SNULL, 140656819798015, 140656819806207,
+STORE, 140656817704960, 140656819798015,
+STORE, 140656819798016, 140656819806207,
+ERASE, 140656819798016, 140656819806207,
+STORE, 140656819798016, 140656819806207,
+STORE, 140656815382528, 140656817553407,
+SNULL, 140656815382528, 140656815452159,
+STORE, 140656815452160, 140656817553407,
+STORE, 140656815382528, 140656815452159,
+SNULL, 140656817545215, 140656817553407,
+STORE, 140656815452160, 140656817545215,
+STORE, 140656817545216, 140656817553407,
+ERASE, 140656817545216, 140656817553407,
+STORE, 140656817545216, 140656817553407,
+STORE, 140656812171264, 140656815382527,
+SNULL, 140656812171264, 140656813248511,
+STORE, 140656813248512, 140656815382527,
+STORE, 140656812171264, 140656813248511,
+SNULL, 140656815345663, 140656815382527,
+STORE, 140656813248512, 140656815345663,
+STORE, 140656815345664, 140656815382527,
+ERASE, 140656815345664, 140656815382527,
+STORE, 140656815345664, 140656815382527,
+STORE, 140656810037248, 140656812171263,
+SNULL, 140656810037248, 140656810065919,
+STORE, 140656810065920, 140656812171263,
+STORE, 140656810037248, 140656810065919,
+SNULL, 140656812163071, 140656812171263,
+STORE, 140656810065920, 140656812163071,
+STORE, 140656812163072, 140656812171263,
+ERASE, 140656812163072, 140656812171263,
+STORE, 140656812163072, 140656812171263,
+STORE, 140656807727104, 140656810037247,
+SNULL, 140656807727104, 140656807931903,
+STORE, 140656807931904, 140656810037247,
+STORE, 140656807727104, 140656807931903,
+SNULL, 140656810029055, 140656810037247,
+STORE, 140656807931904, 140656810029055,
+STORE, 140656810029056, 140656810037247,
+ERASE, 140656810029056, 140656810037247,
+STORE, 140656810029056, 140656810037247,
+STORE, 140656805343232, 140656807727103,
+SNULL, 140656805343232, 140656805535743,
+STORE, 140656805535744, 140656807727103,
+STORE, 140656805343232, 140656805535743,
+SNULL, 140656807628799, 140656807727103,
+STORE, 140656805535744, 140656807628799,
+STORE, 140656807628800, 140656807727103,
+ERASE, 140656807628800, 140656807727103,
+STORE, 140656807628800, 140656807727103,
+STORE, 140656836747264, 140656836763647,
+STORE, 140656802775040, 140656805343231,
+SNULL, 140656802775040, 140656803241983,
+STORE, 140656803241984, 140656805343231,
+STORE, 140656802775040, 140656803241983,
+SNULL, 140656805335039, 140656805343231,
+STORE, 140656803241984, 140656805335039,
+STORE, 140656805335040, 140656805343231,
+ERASE, 140656805335040, 140656805343231,
+STORE, 140656805335040, 140656805343231,
+STORE, 140656800661504, 140656802775039,
+SNULL, 140656800661504, 140656800673791,
+STORE, 140656800673792, 140656802775039,
+STORE, 140656800661504, 140656800673791,
+SNULL, 140656802766847, 140656802775039,
+STORE, 140656800673792, 140656802766847,
+STORE, 140656802766848, 140656802775039,
+ERASE, 140656802766848, 140656802775039,
+STORE, 140656802766848, 140656802775039,
+STORE, 140656798482432, 140656800661503,
+SNULL, 140656798482432, 140656798560255,
+STORE, 140656798560256, 140656800661503,
+STORE, 140656798482432, 140656798560255,
+SNULL, 140656800653311, 140656800661503,
+STORE, 140656798560256, 140656800653311,
+STORE, 140656800653312, 140656800661503,
+ERASE, 140656800653312, 140656800661503,
+STORE, 140656800653312, 140656800661503,
+STORE, 140656796364800, 140656798482431,
+SNULL, 140656796364800, 140656796381183,
+STORE, 140656796381184, 140656798482431,
+STORE, 140656796364800, 140656796381183,
+SNULL, 140656798474239, 140656798482431,
+STORE, 140656796381184, 140656798474239,
+STORE, 140656798474240, 140656798482431,
+ERASE, 140656798474240, 140656798482431,
+STORE, 140656798474240, 140656798482431,
+STORE, 140656836739072, 140656836763647,
+STORE, 140656836726784, 140656836763647,
+SNULL, 140656825700351, 140656825708543,
+STORE, 140656825683968, 140656825700351,
+STORE, 140656825700352, 140656825708543,
+SNULL, 140656798478335, 140656798482431,
+STORE, 140656798474240, 140656798478335,
+STORE, 140656798478336, 140656798482431,
+SNULL, 140656800657407, 140656800661503,
+STORE, 140656800653312, 140656800657407,
+STORE, 140656800657408, 140656800661503,
+SNULL, 140656802770943, 140656802775039,
+STORE, 140656802766848, 140656802770943,
+STORE, 140656802770944, 140656802775039,
+SNULL, 140656827920383, 140656827924479,
+STORE, 140656827916288, 140656827920383,
+STORE, 140656827920384, 140656827924479,
+SNULL, 140656805339135, 140656805343231,
+STORE, 140656805335040, 140656805339135,
+STORE, 140656805339136, 140656805343231,
+SNULL, 140656807723007, 140656807727103,
+STORE, 140656807628800, 140656807723007,
+STORE, 140656807723008, 140656807727103,
+SNULL, 140656810033151, 140656810037247,
+STORE, 140656810029056, 140656810033151,
+STORE, 140656810033152, 140656810037247,
+SNULL, 140656812167167, 140656812171263,
+STORE, 140656812163072, 140656812167167,
+STORE, 140656812167168, 140656812171263,
+SNULL, 140656815353855, 140656815382527,
+STORE, 140656815345664, 140656815353855,
+STORE, 140656815353856, 140656815382527,
+SNULL, 140656817549311, 140656817553407,
+STORE, 140656817545216, 140656817549311,
+STORE, 140656817549312, 140656817553407,
+SNULL, 140656819802111, 140656819806207,
+STORE, 140656819798016, 140656819802111,
+STORE, 140656819802112, 140656819806207,
+SNULL, 140656821923839, 140656821927935,
+STORE, 140656821919744, 140656821923839,
+STORE, 140656821923840, 140656821927935,
+SNULL, 140656830066687, 140656830070783,
+STORE, 140656830062592, 140656830066687,
+STORE, 140656830066688, 140656830070783,
+SNULL, 140656832319487, 140656832323583,
+STORE, 140656832315392, 140656832319487,
+STORE, 140656832319488, 140656832323583,
+SNULL, 140656834547711, 140656834551807,
+STORE, 140656833982464, 140656834547711,
+STORE, 140656834547712, 140656834551807,
+SNULL, 94730166759423, 94730166763519,
+STORE, 94730166751232, 94730166759423,
+STORE, 94730166759424, 94730166763519,
+SNULL, 140656836800511, 140656836804607,
+STORE, 140656836796416, 140656836800511,
+STORE, 140656836800512, 140656836804607,
+ERASE, 140656836763648, 140656836788223,
+STORE, 94730171318272, 94730171453439,
+STORE, 140656836784128, 140656836788223,
+STORE, 140656836780032, 140656836784127,
+STORE, 140656791920640, 140656796364799,
+STORE, 140656836775936, 140656836780031,
+STORE, 140656787476480, 140656791920639,
+STORE, 140656779083776, 140656787476479,
+SNULL, 140656779087871, 140656787476479,
+STORE, 140656779083776, 140656779087871,
+STORE, 140656779087872, 140656787476479,
+STORE, 140656836771840, 140656836775935,
+STORE, 140656774639616, 140656779083775,
+STORE, 140656766246912, 140656774639615,
+SNULL, 140656766251007, 140656774639615,
+STORE, 140656766246912, 140656766251007,
+STORE, 140656766251008, 140656774639615,
+ERASE, 140656791920640, 140656796364799,
+ERASE, 140656836780032, 140656836784127,
+ERASE, 140656787476480, 140656791920639,
+ERASE, 140656836775936, 140656836780031,
+STORE, 140656836780032, 140656836784127,
+STORE, 140656791920640, 140656796364799,
+STORE, 140656836775936, 140656836780031,
+STORE, 140656787476480, 140656791920639,
+ERASE, 140656774639616, 140656779083775,
+ };
+ unsigned long set20[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140735952392192, 140737488351231,
+SNULL, 140735952396287, 140737488351231,
+STORE, 140735952392192, 140735952396287,
+STORE, 140735952261120, 140735952396287,
+STORE, 94849008947200, 94849009414143,
+SNULL, 94849009364991, 94849009414143,
+STORE, 94849008947200, 94849009364991,
+STORE, 94849009364992, 94849009414143,
+ERASE, 94849009364992, 94849009414143,
+STORE, 94849009364992, 94849009414143,
+STORE, 140590397943808, 140590400196607,
+SNULL, 140590398087167, 140590400196607,
+STORE, 140590397943808, 140590398087167,
+STORE, 140590398087168, 140590400196607,
+ERASE, 140590398087168, 140590400196607,
+STORE, 140590400184320, 140590400192511,
+STORE, 140590400192512, 140590400196607,
+STORE, 140735952850944, 140735952855039,
+STORE, 140735952838656, 140735952850943,
+STORE, 140590400180224, 140590400184319,
+STORE, 140590400172032, 140590400180223,
+STORE, 140590395809792, 140590397943807,
+SNULL, 140590395809792, 140590395838463,
+STORE, 140590395838464, 140590397943807,
+STORE, 140590395809792, 140590395838463,
+SNULL, 140590397935615, 140590397943807,
+STORE, 140590395838464, 140590397935615,
+STORE, 140590397935616, 140590397943807,
+ERASE, 140590397935616, 140590397943807,
+STORE, 140590397935616, 140590397943807,
+STORE, 140590393425920, 140590395809791,
+SNULL, 140590393425920, 140590393692159,
+STORE, 140590393692160, 140590395809791,
+STORE, 140590393425920, 140590393692159,
+SNULL, 140590395785215, 140590395809791,
+STORE, 140590393692160, 140590395785215,
+STORE, 140590395785216, 140590395809791,
+SNULL, 140590395785216, 140590395805695,
+STORE, 140590395805696, 140590395809791,
+STORE, 140590395785216, 140590395805695,
+ERASE, 140590395785216, 140590395805695,
+STORE, 140590395785216, 140590395805695,
+ERASE, 140590395805696, 140590395809791,
+STORE, 140590395805696, 140590395809791,
+STORE, 140590391234560, 140590393425919,
+SNULL, 140590391234560, 140590391324671,
+STORE, 140590391324672, 140590393425919,
+STORE, 140590391234560, 140590391324671,
+SNULL, 140590393417727, 140590393425919,
+STORE, 140590391324672, 140590393417727,
+STORE, 140590393417728, 140590393425919,
+ERASE, 140590393417728, 140590393425919,
+STORE, 140590393417728, 140590393425919,
+STORE, 140590388973568, 140590391234559,
+SNULL, 140590388973568, 140590389125119,
+STORE, 140590389125120, 140590391234559,
+STORE, 140590388973568, 140590389125119,
+SNULL, 140590391218175, 140590391234559,
+STORE, 140590389125120, 140590391218175,
+STORE, 140590391218176, 140590391234559,
+SNULL, 140590391218176, 140590391226367,
+STORE, 140590391226368, 140590391234559,
+STORE, 140590391218176, 140590391226367,
+ERASE, 140590391218176, 140590391226367,
+STORE, 140590391218176, 140590391226367,
+ERASE, 140590391226368, 140590391234559,
+STORE, 140590391226368, 140590391234559,
+STORE, 140590386843648, 140590388973567,
+SNULL, 140590386843648, 140590386872319,
+STORE, 140590386872320, 140590388973567,
+STORE, 140590386843648, 140590386872319,
+SNULL, 140590388965375, 140590388973567,
+STORE, 140590386872320, 140590388965375,
+STORE, 140590388965376, 140590388973567,
+ERASE, 140590388965376, 140590388973567,
+STORE, 140590388965376, 140590388973567,
+STORE, 140590384627712, 140590386843647,
+SNULL, 140590384627712, 140590384726015,
+STORE, 140590384726016, 140590386843647,
+STORE, 140590384627712, 140590384726015,
+SNULL, 140590386819071, 140590386843647,
+STORE, 140590384726016, 140590386819071,
+STORE, 140590386819072, 140590386843647,
+SNULL, 140590386819072, 140590386827263,
+STORE, 140590386827264, 140590386843647,
+STORE, 140590386819072, 140590386827263,
+ERASE, 140590386819072, 140590386827263,
+STORE, 140590386819072, 140590386827263,
+ERASE, 140590386827264, 140590386843647,
+STORE, 140590386827264, 140590386843647,
+STORE, 140590400163840, 140590400180223,
+STORE, 140590380830720, 140590384627711,
+SNULL, 140590380830720, 140590382489599,
+STORE, 140590382489600, 140590384627711,
+STORE, 140590380830720, 140590382489599,
+SNULL, 140590384586751, 140590384627711,
+STORE, 140590382489600, 140590384586751,
+STORE, 140590384586752, 140590384627711,
+SNULL, 140590384586752, 140590384611327,
+STORE, 140590384611328, 140590384627711,
+STORE, 140590384586752, 140590384611327,
+ERASE, 140590384586752, 140590384611327,
+STORE, 140590384586752, 140590384611327,
+ERASE, 140590384611328, 140590384627711,
+STORE, 140590384611328, 140590384627711,
+STORE, 140590378713088, 140590380830719,
+SNULL, 140590378713088, 140590378729471,
+STORE, 140590378729472, 140590380830719,
+STORE, 140590378713088, 140590378729471,
+SNULL, 140590380822527, 140590380830719,
+STORE, 140590378729472, 140590380822527,
+STORE, 140590380822528, 140590380830719,
+ERASE, 140590380822528, 140590380830719,
+STORE, 140590380822528, 140590380830719,
+STORE, 140590376595456, 140590378713087,
+SNULL, 140590376595456, 140590376611839,
+STORE, 140590376611840, 140590378713087,
+STORE, 140590376595456, 140590376611839,
+SNULL, 140590378704895, 140590378713087,
+STORE, 140590376611840, 140590378704895,
+STORE, 140590378704896, 140590378713087,
+ERASE, 140590378704896, 140590378713087,
+STORE, 140590378704896, 140590378713087,
+STORE, 140590374027264, 140590376595455,
+SNULL, 140590374027264, 140590374494207,
+STORE, 140590374494208, 140590376595455,
+STORE, 140590374027264, 140590374494207,
+SNULL, 140590376587263, 140590376595455,
+STORE, 140590374494208, 140590376587263,
+STORE, 140590376587264, 140590376595455,
+ERASE, 140590376587264, 140590376595455,
+STORE, 140590376587264, 140590376595455,
+STORE, 140590371913728, 140590374027263,
+SNULL, 140590371913728, 140590371926015,
+STORE, 140590371926016, 140590374027263,
+STORE, 140590371913728, 140590371926015,
+SNULL, 140590374019071, 140590374027263,
+STORE, 140590371926016, 140590374019071,
+STORE, 140590374019072, 140590374027263,
+ERASE, 140590374019072, 140590374027263,
+STORE, 140590374019072, 140590374027263,
+STORE, 140590400155648, 140590400180223,
+STORE, 140590400143360, 140590400180223,
+SNULL, 140590384603135, 140590384611327,
+STORE, 140590384586752, 140590384603135,
+STORE, 140590384603136, 140590384611327,
+SNULL, 140590374023167, 140590374027263,
+STORE, 140590374019072, 140590374023167,
+STORE, 140590374023168, 140590374027263,
+SNULL, 140590386823167, 140590386827263,
+STORE, 140590386819072, 140590386823167,
+STORE, 140590386823168, 140590386827263,
+SNULL, 140590376591359, 140590376595455,
+ };
+ unsigned long set21[] = {
+STORE, 93874710941696, 93874711363583,
+STORE, 93874711367680, 93874711408639,
+STORE, 93874711408640, 93874711412735,
+STORE, 93874720989184, 93874721124351,
+STORE, 140708365086720, 140708365099007,
+STORE, 140708365099008, 140708367192063,
+STORE, 140708367192064, 140708367196159,
+STORE, 140708367196160, 140708367200255,
+STORE, 140708367200256, 140708367667199,
+STORE, 140708367667200, 140708369760255,
+STORE, 140708369760256, 140708369764351,
+STORE, 140708369764352, 140708369768447,
+STORE, 140708369768448, 140708369784831,
+STORE, 140708369784832, 140708371877887,
+STORE, 140708371877888, 140708371881983,
+STORE, 140708371881984, 140708371886079,
+STORE, 140708371886080, 140708371902463,
+STORE, 140708371902464, 140708373995519,
+STORE, 140708373995520, 140708373999615,
+STORE, 140708373999616, 140708374003711,
+STORE, 140708374003712, 140708375662591,
+STORE, 140708375662592, 140708377759743,
+STORE, 140708377759744, 140708377776127,
+STORE, 140708377776128, 140708377784319,
+STORE, 140708377784320, 140708377800703,
+STORE, 140708377800704, 140708377899007,
+STORE, 140708377899008, 140708379992063,
+STORE, 140708379992064, 140708379996159,
+STORE, 140708379996160, 140708380000255,
+STORE, 140708380000256, 140708380016639,
+STORE, 140708380016640, 140708380045311,
+STORE, 140708380045312, 140708382138367,
+STORE, 140708382138368, 140708382142463,
+STORE, 140708382142464, 140708382146559,
+STORE, 140708382146560, 140708382298111,
+STORE, 140708382298112, 140708384391167,
+STORE, 140708384391168, 140708384395263,
+STORE, 140708384395264, 140708384399359,
+STORE, 140708384399360, 140708384407551,
+STORE, 140708384407552, 140708384497663,
+STORE, 140708384497664, 140708386590719,
+STORE, 140708386590720, 140708386594815,
+STORE, 140708386594816, 140708386598911,
+STORE, 140708386598912, 140708386865151,
+STORE, 140708386865152, 140708388958207,
+STORE, 140708388958208, 140708388974591,
+STORE, 140708388974592, 140708388978687,
+STORE, 140708388978688, 140708388982783,
+STORE, 140708388982784, 140708389011455,
+STORE, 140708389011456, 140708391108607,
+STORE, 140708391108608, 140708391112703,
+STORE, 140708391112704, 140708391116799,
+STORE, 140708391116800, 140708391260159,
+STORE, 140708393291776, 140708393308159,
+STORE, 140708393308160, 140708393312255,
+STORE, 140708393312256, 140708393316351,
+STORE, 140708393316352, 140708393353215,
+STORE, 140708393353216, 140708393357311,
+STORE, 140708393357312, 140708393361407,
+STORE, 140708393361408, 140708393365503,
+STORE, 140708393365504, 140708393369599,
+STORE, 140730557042688, 140730557177855,
+STORE, 140730557235200, 140730557247487,
+STORE, 140730557247488, 140730557251583,
+ERASE, 140708393353216, 140708393357311,
+ERASE, 140708393312256, 140708393316351,
+ERASE, 140708393308160, 140708393312255,
+ERASE, 140708393291776, 140708393308159,
+ };
+ unsigned long set22[] = {
+STORE, 93951397134336, 93951397183487,
+STORE, 93951397183488, 93951397728255,
+STORE, 93951397728256, 93951397826559,
+STORE, 93951397826560, 93951397842943,
+STORE, 93951397842944, 93951397847039,
+STORE, 93951425974272, 93951426109439,
+STORE, 140685152665600, 140685152677887,
+STORE, 140685152677888, 140685152829439,
+STORE, 140685152829440, 140685154181119,
+STORE, 140685154181120, 140685154484223,
+STORE, 140685154484224, 140685154496511,
+STORE, 140685154496512, 140685154508799,
+STORE, 140685154508800, 140685154525183,
+STORE, 140685154525184, 140685154541567,
+STORE, 140685154541568, 140685154590719,
+STORE, 140685154590720, 140685154603007,
+STORE, 140685154603008, 140685154607103,
+STORE, 140685154607104, 140685154611199,
+STORE, 140685154611200, 140685154615295,
+STORE, 140685154615296, 140685154631679,
+STORE, 140685154639872, 140685154643967,
+STORE, 140685154643968, 140685154766847,
+STORE, 140685154766848, 140685154799615,
+STORE, 140685154803712, 140685154807807,
+STORE, 140685154807808, 140685154811903,
+STORE, 140685154811904, 140685154815999,
+STORE, 140722188902400, 140722189037567,
+STORE, 140722189512704, 140722189524991,
+STORE, 140722189524992, 140722189529087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733429354496, 140737488351231,
+SNULL, 140733429358591, 140737488351231,
+STORE, 140733429354496, 140733429358591,
+STORE, 140733429223424, 140733429358591,
+STORE, 94526683537408, 94526683660287,
+SNULL, 94526683553791, 94526683660287,
+STORE, 94526683537408, 94526683553791,
+STORE, 94526683553792, 94526683660287,
+ERASE, 94526683553792, 94526683660287,
+STORE, 94526683553792, 94526683623423,
+STORE, 94526683623424, 94526683647999,
+STORE, 94526683652096, 94526683660287,
+STORE, 140551363747840, 140551363923967,
+SNULL, 140551363751935, 140551363923967,
+STORE, 140551363747840, 140551363751935,
+STORE, 140551363751936, 140551363923967,
+ERASE, 140551363751936, 140551363923967,
+STORE, 140551363751936, 140551363874815,
+STORE, 140551363874816, 140551363907583,
+STORE, 140551363911680, 140551363919871,
+STORE, 140551363919872, 140551363923967,
+STORE, 140733429690368, 140733429694463,
+STORE, 140733429678080, 140733429690367,
+STORE, 140551363739648, 140551363747839,
+STORE, 140551363731456, 140551363739647,
+STORE, 140551363379200, 140551363731455,
+SNULL, 140551363379200, 140551363420159,
+STORE, 140551363420160, 140551363731455,
+STORE, 140551363379200, 140551363420159,
+SNULL, 140551363706879, 140551363731455,
+STORE, 140551363420160, 140551363706879,
+STORE, 140551363706880, 140551363731455,
+SNULL, 140551363420160, 140551363637247,
+STORE, 140551363637248, 140551363706879,
+STORE, 140551363420160, 140551363637247,
+ERASE, 140551363420160, 140551363637247,
+STORE, 140551363420160, 140551363637247,
+SNULL, 140551363637248, 140551363702783,
+STORE, 140551363702784, 140551363706879,
+STORE, 140551363637248, 140551363702783,
+ERASE, 140551363637248, 140551363702783,
+STORE, 140551363637248, 140551363702783,
+ERASE, 140551363706880, 140551363731455,
+STORE, 140551363706880, 140551363731455,
+STORE, 140551361531904, 140551363379199,
+SNULL, 140551361683455, 140551363379199,
+STORE, 140551361531904, 140551361683455,
+STORE, 140551361683456, 140551363379199,
+SNULL, 140551361683456, 140551363035135,
+STORE, 140551363035136, 140551363379199,
+STORE, 140551361683456, 140551363035135,
+ERASE, 140551361683456, 140551363035135,
+STORE, 140551361683456, 140551363035135,
+SNULL, 140551363035136, 140551363338239,
+STORE, 140551363338240, 140551363379199,
+STORE, 140551363035136, 140551363338239,
+ERASE, 140551363035136, 140551363338239,
+STORE, 140551363035136, 140551363379199,
+SNULL, 140551363338239, 140551363379199,
+STORE, 140551363035136, 140551363338239,
+STORE, 140551363338240, 140551363379199,
+SNULL, 140551363338240, 140551363362815,
+STORE, 140551363362816, 140551363379199,
+STORE, 140551363338240, 140551363362815,
+ERASE, 140551363338240, 140551363362815,
+STORE, 140551363338240, 140551363362815,
+ERASE, 140551363362816, 140551363379199,
+STORE, 140551363362816, 140551363379199,
+STORE, 140551361519616, 140551361531903,
+SNULL, 140551363350527, 140551363362815,
+STORE, 140551363338240, 140551363350527,
+STORE, 140551363350528, 140551363362815,
+SNULL, 140551363727359, 140551363731455,
+STORE, 140551363706880, 140551363727359,
+STORE, 140551363727360, 140551363731455,
+SNULL, 94526683656191, 94526683660287,
+STORE, 94526683652096, 94526683656191,
+STORE, 94526683656192, 94526683660287,
+SNULL, 140551363915775, 140551363919871,
+STORE, 140551363911680, 140551363915775,
+STORE, 140551363915776, 140551363919871,
+ERASE, 140551363739648, 140551363747839,
+STORE, 94526715490304, 94526715625471,
+STORE, 140551361253376, 140551361531903,
+STORE, 140551360987136, 140551361531903,
+STORE, 140551360720896, 140551361531903,
+STORE, 140551360454656, 140551361531903,
+SNULL, 140551361253375, 140551361531903,
+STORE, 140551360454656, 140551361253375,
+STORE, 140551361253376, 140551361531903,
+SNULL, 140551361253376, 140551361519615,
+STORE, 140551361519616, 140551361531903,
+STORE, 140551361253376, 140551361519615,
+ERASE, 140551361253376, 140551361519615,
+ };
+
+ unsigned long set23[] = {
+STORE, 94014447943680, 94014448156671,
+STORE, 94014450253824, 94014450257919,
+STORE, 94014450257920, 94014450266111,
+STORE, 94014450266112, 94014450278399,
+STORE, 94014464225280, 94014464630783,
+STORE, 139761764306944, 139761765965823,
+STORE, 139761765965824, 139761768062975,
+STORE, 139761768062976, 139761768079359,
+STORE, 139761768079360, 139761768087551,
+STORE, 139761768087552, 139761768103935,
+STORE, 139761768103936, 139761768116223,
+STORE, 139761768116224, 139761770209279,
+STORE, 139761770209280, 139761770213375,
+STORE, 139761770213376, 139761770217471,
+STORE, 139761770217472, 139761770360831,
+STORE, 139761770729472, 139761772412927,
+STORE, 139761772412928, 139761772429311,
+STORE, 139761772457984, 139761772462079,
+STORE, 139761772462080, 139761772466175,
+STORE, 139761772466176, 139761772470271,
+STORE, 140724336517120, 140724336652287,
+STORE, 140724336955392, 140724336967679,
+STORE, 140724336967680, 140724336971775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140721840295936, 140737488351231,
+SNULL, 140721840300031, 140737488351231,
+STORE, 140721840295936, 140721840300031,
+STORE, 140721840164864, 140721840300031,
+STORE, 93937913667584, 93937915830271,
+SNULL, 93937913729023, 93937915830271,
+STORE, 93937913667584, 93937913729023,
+STORE, 93937913729024, 93937915830271,
+ERASE, 93937913729024, 93937915830271,
+STORE, 93937915822080, 93937915830271,
+STORE, 140598835335168, 140598837587967,
+SNULL, 140598835478527, 140598837587967,
+STORE, 140598835335168, 140598835478527,
+STORE, 140598835478528, 140598837587967,
+ERASE, 140598835478528, 140598837587967,
+STORE, 140598837575680, 140598837583871,
+STORE, 140598837583872, 140598837587967,
+STORE, 140721841086464, 140721841090559,
+STORE, 140721841074176, 140721841086463,
+STORE, 140598837547008, 140598837575679,
+STORE, 140598837538816, 140598837547007,
+STORE, 140598831538176, 140598835335167,
+SNULL, 140598831538176, 140598833197055,
+STORE, 140598833197056, 140598835335167,
+STORE, 140598831538176, 140598833197055,
+SNULL, 140598835294207, 140598835335167,
+STORE, 140598833197056, 140598835294207,
+STORE, 140598835294208, 140598835335167,
+SNULL, 140598835294208, 140598835318783,
+STORE, 140598835318784, 140598835335167,
+STORE, 140598835294208, 140598835318783,
+ERASE, 140598835294208, 140598835318783,
+STORE, 140598835294208, 140598835318783,
+ERASE, 140598835318784, 140598835335167,
+STORE, 140598835318784, 140598835335167,
+SNULL, 140598835310591, 140598835318783,
+STORE, 140598835294208, 140598835310591,
+STORE, 140598835310592, 140598835318783,
+SNULL, 93937915826175, 93937915830271,
+STORE, 93937915822080, 93937915826175,
+STORE, 93937915826176, 93937915830271,
+SNULL, 140598837579775, 140598837583871,
+STORE, 140598837575680, 140598837579775,
+STORE, 140598837579776, 140598837583871,
+ERASE, 140598837547008, 140598837575679,
+STORE, 93937929179136, 93937929314303,
+STORE, 140598835855360, 140598837538815,
+STORE, 140737488347136, 140737488351231,
+STORE, 140728187723776, 140737488351231,
+SNULL, 140728187727871, 140737488351231,
+STORE, 140728187723776, 140728187727871,
+STORE, 140728187592704, 140728187727871,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140583951437824, 140583953690623,
+SNULL, 140583951581183, 140583953690623,
+STORE, 140583951437824, 140583951581183,
+STORE, 140583951581184, 140583953690623,
+ERASE, 140583951581184, 140583953690623,
+STORE, 140583953678336, 140583953686527,
+STORE, 140583953686528, 140583953690623,
+STORE, 140728189116416, 140728189120511,
+STORE, 140728189104128, 140728189116415,
+STORE, 140583953649664, 140583953678335,
+STORE, 140583953641472, 140583953649663,
+STORE, 140583948275712, 140583951437823,
+SNULL, 140583948275712, 140583949336575,
+STORE, 140583949336576, 140583951437823,
+STORE, 140583948275712, 140583949336575,
+SNULL, 140583951429631, 140583951437823,
+STORE, 140583949336576, 140583951429631,
+STORE, 140583951429632, 140583951437823,
+ERASE, 140583951429632, 140583951437823,
+STORE, 140583951429632, 140583951437823,
+STORE, 140583944478720, 140583948275711,
+SNULL, 140583944478720, 140583946137599,
+STORE, 140583946137600, 140583948275711,
+STORE, 140583944478720, 140583946137599,
+SNULL, 140583948234751, 140583948275711,
+STORE, 140583946137600, 140583948234751,
+STORE, 140583948234752, 140583948275711,
+SNULL, 140583948234752, 140583948259327,
+STORE, 140583948259328, 140583948275711,
+STORE, 140583948234752, 140583948259327,
+ERASE, 140583948234752, 140583948259327,
+STORE, 140583948234752, 140583948259327,
+ERASE, 140583948259328, 140583948275711,
+STORE, 140583948259328, 140583948275711,
+STORE, 140583953629184, 140583953649663,
+SNULL, 140583948251135, 140583948259327,
+STORE, 140583948234752, 140583948251135,
+STORE, 140583948251136, 140583948259327,
+SNULL, 140583951433727, 140583951437823,
+STORE, 140583951429632, 140583951433727,
+STORE, 140583951433728, 140583951437823,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140583953682431, 140583953686527,
+STORE, 140583953678336, 140583953682431,
+STORE, 140583953682432, 140583953686527,
+ERASE, 140583953649664, 140583953678335,
+STORE, 17821696, 17956863,
+STORE, 17821696, 18104319,
+STORE, 140583951945728, 140583953629183,
+STORE, 94014447943680, 94014448156671,
+STORE, 94014450253824, 94014450257919,
+STORE, 94014450257920, 94014450266111,
+STORE, 94014450266112, 94014450278399,
+STORE, 94014464225280, 94014465196031,
+STORE, 139761764306944, 139761765965823,
+STORE, 139761765965824, 139761768062975,
+STORE, 139761768062976, 139761768079359,
+STORE, 139761768079360, 139761768087551,
+STORE, 139761768087552, 139761768103935,
+STORE, 139761768103936, 139761768116223,
+STORE, 139761768116224, 139761770209279,
+STORE, 139761770209280, 139761770213375,
+STORE, 139761770213376, 139761770217471,
+STORE, 139761770217472, 139761770360831,
+STORE, 139761770729472, 139761772412927,
+STORE, 139761772412928, 139761772429311,
+STORE, 139761772457984, 139761772462079,
+STORE, 139761772462080, 139761772466175,
+STORE, 139761772466176, 139761772470271,
+STORE, 140724336517120, 140724336652287,
+STORE, 140724336955392, 140724336967679,
+STORE, 140724336967680, 140724336971775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726063296512, 140737488351231,
+SNULL, 140726063300607, 140737488351231,
+STORE, 140726063296512, 140726063300607,
+STORE, 140726063165440, 140726063300607,
+STORE, 94016795934720, 94016798158847,
+SNULL, 94016796045311, 94016798158847,
+STORE, 94016795934720, 94016796045311,
+STORE, 94016796045312, 94016798158847,
+ERASE, 94016796045312, 94016798158847,
+STORE, 94016798138368, 94016798150655,
+STORE, 94016798150656, 94016798158847,
+STORE, 139975915966464, 139975918219263,
+SNULL, 139975916109823, 139975918219263,
+STORE, 139975915966464, 139975916109823,
+STORE, 139975916109824, 139975918219263,
+ERASE, 139975916109824, 139975918219263,
+STORE, 139975918206976, 139975918215167,
+STORE, 139975918215168, 139975918219263,
+STORE, 140726064541696, 140726064545791,
+STORE, 140726064529408, 140726064541695,
+STORE, 139975918178304, 139975918206975,
+STORE, 139975918170112, 139975918178303,
+STORE, 139975912169472, 139975915966463,
+SNULL, 139975912169472, 139975913828351,
+STORE, 139975913828352, 139975915966463,
+STORE, 139975912169472, 139975913828351,
+SNULL, 139975915925503, 139975915966463,
+STORE, 139975913828352, 139975915925503,
+STORE, 139975915925504, 139975915966463,
+SNULL, 139975915925504, 139975915950079,
+STORE, 139975915950080, 139975915966463,
+STORE, 139975915925504, 139975915950079,
+ERASE, 139975915925504, 139975915950079,
+STORE, 139975915925504, 139975915950079,
+ERASE, 139975915950080, 139975915966463,
+STORE, 139975915950080, 139975915966463,
+SNULL, 139975915941887, 139975915950079,
+STORE, 139975915925504, 139975915941887,
+STORE, 139975915941888, 139975915950079,
+SNULL, 94016798146559, 94016798150655,
+STORE, 94016798138368, 94016798146559,
+STORE, 94016798146560, 94016798150655,
+SNULL, 139975918211071, 139975918215167,
+STORE, 139975918206976, 139975918211071,
+STORE, 139975918211072, 139975918215167,
+ERASE, 139975918178304, 139975918206975,
+STORE, 94016804925440, 94016805060607,
+STORE, 94596177661952, 94596177772543,
+STORE, 94596179865600, 94596179873791,
+STORE, 94596179873792, 94596179877887,
+STORE, 94596179877888, 94596179886079,
+STORE, 94596211597312, 94596211863551,
+STORE, 140127351840768, 140127353499647,
+STORE, 140127353499648, 140127355596799,
+STORE, 140127355596800, 140127355613183,
+STORE, 140127355613184, 140127355621375,
+STORE, 140127355621376, 140127355637759,
+STORE, 140127355637760, 140127355781119,
+STORE, 140127357841408, 140127357849599,
+STORE, 140127357878272, 140127357882367,
+STORE, 140127357882368, 140127357886463,
+STORE, 140127357886464, 140127357890559,
+STORE, 140726167252992, 140726167392255,
+STORE, 140726167838720, 140726167851007,
+STORE, 140726167851008, 140726167855103,
+STORE, 140737488347136, 140737488351231,
+STORE, 140731874017280, 140737488351231,
+SNULL, 140731874021375, 140737488351231,
+STORE, 140731874017280, 140731874021375,
+STORE, 140731873886208, 140731874021375,
+STORE, 94178682265600, 94178684489727,
+SNULL, 94178682376191, 94178684489727,
+STORE, 94178682265600, 94178682376191,
+STORE, 94178682376192, 94178684489727,
+ERASE, 94178682376192, 94178684489727,
+STORE, 94178684469248, 94178684481535,
+STORE, 94178684481536, 94178684489727,
+STORE, 140460853403648, 140460855656447,
+SNULL, 140460853547007, 140460855656447,
+STORE, 140460853403648, 140460853547007,
+STORE, 140460853547008, 140460855656447,
+ERASE, 140460853547008, 140460855656447,
+STORE, 140460855644160, 140460855652351,
+STORE, 140460855652352, 140460855656447,
+STORE, 140731874103296, 140731874107391,
+STORE, 140731874091008, 140731874103295,
+STORE, 140460855615488, 140460855644159,
+STORE, 140460855607296, 140460855615487,
+STORE, 140460849606656, 140460853403647,
+SNULL, 140460849606656, 140460851265535,
+STORE, 140460851265536, 140460853403647,
+STORE, 140460849606656, 140460851265535,
+SNULL, 140460853362687, 140460853403647,
+STORE, 140460851265536, 140460853362687,
+STORE, 140460853362688, 140460853403647,
+SNULL, 140460853362688, 140460853387263,
+STORE, 140460853387264, 140460853403647,
+STORE, 140460853362688, 140460853387263,
+ERASE, 140460853362688, 140460853387263,
+STORE, 140460853362688, 140460853387263,
+ERASE, 140460853387264, 140460853403647,
+STORE, 140460853387264, 140460853403647,
+SNULL, 140460853379071, 140460853387263,
+STORE, 140460853362688, 140460853379071,
+STORE, 140460853379072, 140460853387263,
+SNULL, 94178684477439, 94178684481535,
+STORE, 94178684469248, 94178684477439,
+STORE, 94178684477440, 94178684481535,
+SNULL, 140460855648255, 140460855652351,
+STORE, 140460855644160, 140460855648255,
+STORE, 140460855648256, 140460855652351,
+ERASE, 140460855615488, 140460855644159,
+STORE, 94178692063232, 94178692198399,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733096603648, 140737488351231,
+SNULL, 140733096611839, 140737488351231,
+STORE, 140733096603648, 140733096611839,
+STORE, 140733096472576, 140733096611839,
+STORE, 94796716122112, 94796718325759,
+SNULL, 94796716224511, 94796718325759,
+STORE, 94796716122112, 94796716224511,
+STORE, 94796716224512, 94796718325759,
+ERASE, 94796716224512, 94796718325759,
+STORE, 94796718317568, 94796718325759,
+STORE, 139667892793344, 139667895046143,
+SNULL, 139667892936703, 139667895046143,
+STORE, 139667892793344, 139667892936703,
+STORE, 139667892936704, 139667895046143,
+ERASE, 139667892936704, 139667895046143,
+STORE, 139667895033856, 139667895042047,
+STORE, 139667895042048, 139667895046143,
+STORE, 140733096857600, 140733096861695,
+STORE, 140733096845312, 140733096857599,
+STORE, 139667895005184, 139667895033855,
+STORE, 139667894996992, 139667895005183,
+STORE, 139667890532352, 139667892793343,
+SNULL, 139667890532352, 139667890683903,
+STORE, 139667890683904, 139667892793343,
+STORE, 139667890532352, 139667890683903,
+SNULL, 139667892776959, 139667892793343,
+STORE, 139667890683904, 139667892776959,
+STORE, 139667892776960, 139667892793343,
+SNULL, 139667892776960, 139667892785151,
+STORE, 139667892785152, 139667892793343,
+STORE, 139667892776960, 139667892785151,
+ERASE, 139667892776960, 139667892785151,
+STORE, 139667892776960, 139667892785151,
+ERASE, 139667892785152, 139667892793343,
+STORE, 139667892785152, 139667892793343,
+STORE, 139667886735360, 139667890532351,
+SNULL, 139667886735360, 139667888394239,
+STORE, 139667888394240, 139667890532351,
+STORE, 139667886735360, 139667888394239,
+SNULL, 139667890491391, 139667890532351,
+STORE, 139667888394240, 139667890491391,
+STORE, 139667890491392, 139667890532351,
+SNULL, 139667890491392, 139667890515967,
+STORE, 139667890515968, 139667890532351,
+STORE, 139667890491392, 139667890515967,
+ERASE, 139667890491392, 139667890515967,
+STORE, 139667890491392, 139667890515967,
+ERASE, 139667890515968, 139667890532351,
+STORE, 139667890515968, 139667890532351,
+STORE, 139667884167168, 139667886735359,
+SNULL, 139667884167168, 139667884634111,
+STORE, 139667884634112, 139667886735359,
+STORE, 139667884167168, 139667884634111,
+SNULL, 139667886727167, 139667886735359,
+STORE, 139667884634112, 139667886727167,
+STORE, 139667886727168, 139667886735359,
+ERASE, 139667886727168, 139667886735359,
+STORE, 139667886727168, 139667886735359,
+STORE, 139667882053632, 139667884167167,
+SNULL, 139667882053632, 139667882065919,
+STORE, 139667882065920, 139667884167167,
+STORE, 139667882053632, 139667882065919,
+SNULL, 139667884158975, 139667884167167,
+STORE, 139667882065920, 139667884158975,
+STORE, 139667884158976, 139667884167167,
+ERASE, 139667884158976, 139667884167167,
+STORE, 139667884158976, 139667884167167,
+STORE, 139667879837696, 139667882053631,
+SNULL, 139667879837696, 139667879935999,
+STORE, 139667879936000, 139667882053631,
+STORE, 139667879837696, 139667879935999,
+SNULL, 139667882029055, 139667882053631,
+STORE, 139667879936000, 139667882029055,
+STORE, 139667882029056, 139667882053631,
+SNULL, 139667882029056, 139667882037247,
+STORE, 139667882037248, 139667882053631,
+STORE, 139667882029056, 139667882037247,
+ERASE, 139667882029056, 139667882037247,
+STORE, 139667882029056, 139667882037247,
+ERASE, 139667882037248, 139667882053631,
+STORE, 139667882037248, 139667882053631,
+STORE, 139667894988800, 139667895005183,
+SNULL, 139667890507775, 139667890515967,
+STORE, 139667890491392, 139667890507775,
+STORE, 139667890507776, 139667890515967,
+SNULL, 139667882033151, 139667882037247,
+STORE, 139667882029056, 139667882033151,
+STORE, 139667882033152, 139667882037247,
+SNULL, 139667884163071, 139667884167167,
+STORE, 139667884158976, 139667884163071,
+STORE, 139667884163072, 139667884167167,
+SNULL, 139667886731263, 139667886735359,
+STORE, 139667886727168, 139667886731263,
+STORE, 139667886731264, 139667886735359,
+SNULL, 139667892781055, 139667892785151,
+STORE, 139667892776960, 139667892781055,
+STORE, 139667892781056, 139667892785151,
+SNULL, 94796718321663, 94796718325759,
+STORE, 94796718317568, 94796718321663,
+STORE, 94796718321664, 94796718325759,
+SNULL, 139667895037951, 139667895042047,
+STORE, 139667895033856, 139667895037951,
+STORE, 139667895037952, 139667895042047,
+ERASE, 139667895005184, 139667895033855,
+STORE, 94796726063104, 94796726198271,
+STORE, 139667893305344, 139667894988799,
+STORE, 139667895005184, 139667895033855,
+STORE, 94796726063104, 94796726333439,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722489507840, 140737488351231,
+SNULL, 140722489516031, 140737488351231,
+STORE, 140722489507840, 140722489516031,
+STORE, 140722489376768, 140722489516031,
+STORE, 93980993265664, 93980995489791,
+SNULL, 93980993376255, 93980995489791,
+STORE, 93980993265664, 93980993376255,
+STORE, 93980993376256, 93980995489791,
+ERASE, 93980993376256, 93980995489791,
+STORE, 93980995469312, 93980995481599,
+STORE, 93980995481600, 93980995489791,
+STORE, 140261313593344, 140261315846143,
+SNULL, 140261313736703, 140261315846143,
+STORE, 140261313593344, 140261313736703,
+STORE, 140261313736704, 140261315846143,
+ERASE, 140261313736704, 140261315846143,
+STORE, 140261315833856, 140261315842047,
+STORE, 140261315842048, 140261315846143,
+STORE, 140722489675776, 140722489679871,
+STORE, 140722489663488, 140722489675775,
+STORE, 140261315805184, 140261315833855,
+STORE, 140261315796992, 140261315805183,
+STORE, 140261309796352, 140261313593343,
+SNULL, 140261309796352, 140261311455231,
+STORE, 140261311455232, 140261313593343,
+STORE, 140261309796352, 140261311455231,
+SNULL, 140261313552383, 140261313593343,
+STORE, 140261311455232, 140261313552383,
+STORE, 140261313552384, 140261313593343,
+SNULL, 140261313552384, 140261313576959,
+STORE, 140261313576960, 140261313593343,
+STORE, 140261313552384, 140261313576959,
+ERASE, 140261313552384, 140261313576959,
+STORE, 140261313552384, 140261313576959,
+ERASE, 140261313576960, 140261313593343,
+STORE, 140261313576960, 140261313593343,
+SNULL, 140261313568767, 140261313576959,
+STORE, 140261313552384, 140261313568767,
+STORE, 140261313568768, 140261313576959,
+SNULL, 93980995477503, 93980995481599,
+STORE, 93980995469312, 93980995477503,
+STORE, 93980995477504, 93980995481599,
+SNULL, 140261315837951, 140261315842047,
+STORE, 140261315833856, 140261315837951,
+STORE, 140261315837952, 140261315842047,
+ERASE, 140261315805184, 140261315833855,
+STORE, 93980997443584, 93980997578751,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140737488338944, 140737488351231,
+STORE, 140734059450368, 140737488351231,
+SNULL, 140734059462655, 140737488351231,
+STORE, 140734059450368, 140734059462655,
+STORE, 140734059319296, 140734059462655,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140307554983936, 140307557236735,
+SNULL, 140307555127295, 140307557236735,
+STORE, 140307554983936, 140307555127295,
+STORE, 140307555127296, 140307557236735,
+ERASE, 140307555127296, 140307557236735,
+STORE, 140307557224448, 140307557232639,
+STORE, 140307557232640, 140307557236735,
+STORE, 140734059483136, 140734059487231,
+STORE, 140734059470848, 140734059483135,
+STORE, 140307557195776, 140307557224447,
+STORE, 140307557187584, 140307557195775,
+STORE, 140307551821824, 140307554983935,
+SNULL, 140307551821824, 140307552882687,
+STORE, 140307552882688, 140307554983935,
+STORE, 140307551821824, 140307552882687,
+SNULL, 140307554975743, 140307554983935,
+STORE, 140307552882688, 140307554975743,
+STORE, 140307554975744, 140307554983935,
+ERASE, 140307554975744, 140307554983935,
+STORE, 140307554975744, 140307554983935,
+STORE, 140307548024832, 140307551821823,
+SNULL, 140307548024832, 140307549683711,
+STORE, 140307549683712, 140307551821823,
+STORE, 140307548024832, 140307549683711,
+SNULL, 140307551780863, 140307551821823,
+STORE, 140307549683712, 140307551780863,
+STORE, 140307551780864, 140307551821823,
+SNULL, 140307551780864, 140307551805439,
+STORE, 140307551805440, 140307551821823,
+STORE, 140307551780864, 140307551805439,
+ERASE, 140307551780864, 140307551805439,
+STORE, 140307551780864, 140307551805439,
+ERASE, 140307551805440, 140307551821823,
+STORE, 140307551805440, 140307551821823,
+STORE, 140307557175296, 140307557195775,
+SNULL, 140307551797247, 140307551805439,
+STORE, 140307551780864, 140307551797247,
+STORE, 140307551797248, 140307551805439,
+SNULL, 140307554979839, 140307554983935,
+STORE, 140307554975744, 140307554979839,
+STORE, 140307554979840, 140307554983935,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140307557228543, 140307557232639,
+STORE, 140307557224448, 140307557228543,
+STORE, 140307557228544, 140307557232639,
+ERASE, 140307557195776, 140307557224447,
+STORE, 39698432, 39833599,
+STORE, 39698432, 39981055,
+STORE, 94306485321728, 94306485432319,
+STORE, 94306487525376, 94306487533567,
+STORE, 94306487533568, 94306487537663,
+STORE, 94306487537664, 94306487545855,
+STORE, 94306488868864, 94306489004031,
+STORE, 140497673998336, 140497675657215,
+STORE, 140497675657216, 140497677754367,
+STORE, 140497677754368, 140497677770751,
+STORE, 140497677770752, 140497677778943,
+STORE, 140497677778944, 140497677795327,
+STORE, 140497677795328, 140497677938687,
+STORE, 140497679998976, 140497680007167,
+STORE, 140497680035840, 140497680039935,
+STORE, 140497680039936, 140497680044031,
+STORE, 140497680044032, 140497680048127,
+STORE, 140732780462080, 140732780601343,
+STORE, 140732782239744, 140732782252031,
+STORE, 140732782252032, 140732782256127,
+STORE, 94236915900416, 94236916011007,
+STORE, 94236918104064, 94236918112255,
+STORE, 94236918112256, 94236918116351,
+STORE, 94236918116352, 94236918124543,
+STORE, 94236939489280, 94236939624447,
+STORE, 140046091743232, 140046093402111,
+STORE, 140046093402112, 140046095499263,
+STORE, 140046095499264, 140046095515647,
+STORE, 140046095515648, 140046095523839,
+STORE, 140046095523840, 140046095540223,
+STORE, 140046095540224, 140046095683583,
+STORE, 140046097743872, 140046097752063,
+STORE, 140046097780736, 140046097784831,
+STORE, 140046097784832, 140046097788927,
+STORE, 140046097788928, 140046097793023,
+STORE, 140726694449152, 140726694588415,
+STORE, 140726695313408, 140726695325695,
+STORE, 140726695325696, 140726695329791,
+STORE, 94894582779904, 94894582992895,
+STORE, 94894585090048, 94894585094143,
+STORE, 94894585094144, 94894585102335,
+STORE, 94894585102336, 94894585114623,
+STORE, 94894592868352, 94894594293759,
+STORE, 139733563842560, 139733565501439,
+STORE, 139733565501440, 139733567598591,
+STORE, 139733567598592, 139733567614975,
+STORE, 139733567614976, 139733567623167,
+STORE, 139733567623168, 139733567639551,
+STORE, 139733567639552, 139733567651839,
+STORE, 139733567651840, 139733569744895,
+STORE, 139733569744896, 139733569748991,
+STORE, 139733569748992, 139733569753087,
+STORE, 139733569753088, 139733569896447,
+STORE, 139733570265088, 139733571948543,
+STORE, 139733571948544, 139733571964927,
+STORE, 139733571993600, 139733571997695,
+STORE, 139733571997696, 139733572001791,
+STORE, 139733572001792, 139733572005887,
+STORE, 140726369255424, 140726369394687,
+STORE, 140726370402304, 140726370414591,
+STORE, 140726370414592, 140726370418687,
+STORE, 94899236483072, 94899236696063,
+STORE, 94899238793216, 94899238797311,
+STORE, 94899238797312, 94899238805503,
+STORE, 94899238805504, 94899238817791,
+STORE, 94899263045632, 94899263979519,
+STORE, 140040959893504, 140040961552383,
+STORE, 140040961552384, 140040963649535,
+STORE, 140040963649536, 140040963665919,
+STORE, 140040963665920, 140040963674111,
+STORE, 140040963674112, 140040963690495,
+STORE, 140040963690496, 140040963702783,
+STORE, 140040963702784, 140040965795839,
+STORE, 140040965795840, 140040965799935,
+STORE, 140040965799936, 140040965804031,
+STORE, 140040965804032, 140040965947391,
+STORE, 140040966316032, 140040967999487,
+STORE, 140040967999488, 140040968015871,
+STORE, 140040968044544, 140040968048639,
+STORE, 140040968048640, 140040968052735,
+STORE, 140040968052736, 140040968056831,
+STORE, 140729921359872, 140729921499135,
+STORE, 140729921613824, 140729921626111,
+STORE, 140729921626112, 140729921630207,
+STORE, 94818265190400, 94818265403391,
+STORE, 94818267500544, 94818267504639,
+STORE, 94818267504640, 94818267512831,
+STORE, 94818267512832, 94818267525119,
+STORE, 94818283372544, 94818285858815,
+STORE, 139818425675776, 139818427334655,
+STORE, 139818427334656, 139818429431807,
+STORE, 139818429431808, 139818429448191,
+STORE, 139818429448192, 139818429456383,
+STORE, 139818429456384, 139818429472767,
+STORE, 139818429472768, 139818429485055,
+STORE, 139818429485056, 139818431578111,
+STORE, 139818431578112, 139818431582207,
+STORE, 139818431582208, 139818431586303,
+STORE, 139818431586304, 139818431729663,
+STORE, 139818432098304, 139818433781759,
+STORE, 139818433781760, 139818433798143,
+STORE, 139818433826816, 139818433830911,
+STORE, 139818433830912, 139818433835007,
+STORE, 139818433835008, 139818433839103,
+STORE, 140726170509312, 140726170648575,
+STORE, 140726171824128, 140726171836415,
+STORE, 140726171836416, 140726171840511,
+STORE, 94611513188352, 94611513401343,
+STORE, 94611515498496, 94611515502591,
+STORE, 94611515502592, 94611515510783,
+STORE, 94611515510784, 94611515523071,
+STORE, 94611516502016, 94611516907519,
+STORE, 140596246388736, 140596248047615,
+STORE, 140596248047616, 140596250144767,
+STORE, 140596250144768, 140596250161151,
+STORE, 140596250161152, 140596250169343,
+STORE, 140596250169344, 140596250185727,
+STORE, 140596250185728, 140596250198015,
+STORE, 140596250198016, 140596252291071,
+STORE, 140596252291072, 140596252295167,
+STORE, 140596252295168, 140596252299263,
+STORE, 140596252299264, 140596252442623,
+STORE, 140596252811264, 140596254494719,
+STORE, 140596254494720, 140596254511103,
+STORE, 140596254539776, 140596254543871,
+STORE, 140596254543872, 140596254547967,
+STORE, 140596254547968, 140596254552063,
+STORE, 140731551338496, 140731551477759,
+STORE, 140731551780864, 140731551793151,
+STORE, 140731551793152, 140731551797247,
+STORE, 94313835851776, 94313836064767,
+STORE, 94313838161920, 94313838166015,
+STORE, 94313838166016, 94313838174207,
+STORE, 94313838174208, 94313838186495,
+STORE, 94313858416640, 94313861906431,
+STORE, 140693503918080, 140693505576959,
+STORE, 140693505576960, 140693507674111,
+STORE, 140693507674112, 140693507690495,
+STORE, 140693507690496, 140693507698687,
+STORE, 140693507698688, 140693507715071,
+STORE, 140693507715072, 140693507727359,
+STORE, 140693507727360, 140693509820415,
+STORE, 140693509820416, 140693509824511,
+STORE, 140693509824512, 140693509828607,
+STORE, 140693509828608, 140693509971967,
+STORE, 140693510340608, 140693512024063,
+STORE, 140693512024064, 140693512040447,
+STORE, 140693512069120, 140693512073215,
+STORE, 140693512073216, 140693512077311,
+STORE, 140693512077312, 140693512081407,
+STORE, 140721116065792, 140721116205055,
+STORE, 140721117831168, 140721117843455,
+STORE, 140721117843456, 140721117847551,
+STORE, 94843650150400, 94843650363391,
+STORE, 94843652460544, 94843652464639,
+STORE, 94843652464640, 94843652472831,
+STORE, 94843652472832, 94843652485119,
+STORE, 94843685388288, 94843686281215,
+STORE, 140484193681408, 140484195340287,
+STORE, 140484195340288, 140484197437439,
+STORE, 140484197437440, 140484197453823,
+STORE, 140484197453824, 140484197462015,
+STORE, 140484197462016, 140484197478399,
+STORE, 140484197478400, 140484197490687,
+STORE, 140484197490688, 140484199583743,
+STORE, 140484199583744, 140484199587839,
+STORE, 140484199587840, 140484199591935,
+STORE, 140484199591936, 140484199735295,
+STORE, 140484200103936, 140484201787391,
+STORE, 140484201787392, 140484201803775,
+STORE, 140484201832448, 140484201836543,
+STORE, 140484201836544, 140484201840639,
+STORE, 140484201840640, 140484201844735,
+STORE, 140726294315008, 140726294454271,
+STORE, 140726295646208, 140726295658495,
+STORE, 140726295658496, 140726295662591,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140720422371328, 140737488351231,
+SNULL, 140720422379519, 140737488351231,
+STORE, 140720422371328, 140720422379519,
+STORE, 140720422240256, 140720422379519,
+STORE, 94417967845376, 94417970180095,
+SNULL, 94417968058367, 94417970180095,
+STORE, 94417967845376, 94417968058367,
+STORE, 94417968058368, 94417970180095,
+ERASE, 94417968058368, 94417970180095,
+STORE, 94417970155520, 94417970167807,
+STORE, 94417970167808, 94417970180095,
+STORE, 140252450045952, 140252452298751,
+SNULL, 140252450189311, 140252452298751,
+STORE, 140252450045952, 140252450189311,
+STORE, 140252450189312, 140252452298751,
+ERASE, 140252450189312, 140252452298751,
+STORE, 140252452286464, 140252452294655,
+STORE, 140252452294656, 140252452298751,
+STORE, 140720422416384, 140720422420479,
+STORE, 140720422404096, 140720422416383,
+STORE, 140252452257792, 140252452286463,
+STORE, 140252452249600, 140252452257791,
+STORE, 140252447932416, 140252450045951,
+SNULL, 140252447932416, 140252447944703,
+STORE, 140252447944704, 140252450045951,
+STORE, 140252447932416, 140252447944703,
+SNULL, 140252450037759, 140252450045951,
+STORE, 140252447944704, 140252450037759,
+STORE, 140252450037760, 140252450045951,
+ERASE, 140252450037760, 140252450045951,
+STORE, 140252450037760, 140252450045951,
+STORE, 140252444135424, 140252447932415,
+SNULL, 140252444135424, 140252445794303,
+STORE, 140252445794304, 140252447932415,
+STORE, 140252444135424, 140252445794303,
+SNULL, 140252447891455, 140252447932415,
+STORE, 140252445794304, 140252447891455,
+STORE, 140252447891456, 140252447932415,
+SNULL, 140252447891456, 140252447916031,
+STORE, 140252447916032, 140252447932415,
+STORE, 140252447891456, 140252447916031,
+ERASE, 140252447891456, 140252447916031,
+STORE, 140252447891456, 140252447916031,
+ERASE, 140252447916032, 140252447932415,
+STORE, 140252447916032, 140252447932415,
+STORE, 140252452241408, 140252452257791,
+SNULL, 140252447907839, 140252447916031,
+STORE, 140252447891456, 140252447907839,
+STORE, 140252447907840, 140252447916031,
+SNULL, 140252450041855, 140252450045951,
+STORE, 140252450037760, 140252450041855,
+STORE, 140252450041856, 140252450045951,
+SNULL, 94417970159615, 94417970167807,
+STORE, 94417970155520, 94417970159615,
+STORE, 94417970159616, 94417970167807,
+SNULL, 140252452290559, 140252452294655,
+STORE, 140252452286464, 140252452290559,
+STORE, 140252452290560, 140252452294655,
+ERASE, 140252452257792, 140252452286463,
+STORE, 94417996333056, 94417996468223,
+STORE, 140252450557952, 140252452241407,
+STORE, 94417996333056, 94417996603391,
+STORE, 94417996333056, 94417996738559,
+STORE, 94417996333056, 94417996910591,
+SNULL, 94417996881919, 94417996910591,
+STORE, 94417996333056, 94417996881919,
+STORE, 94417996881920, 94417996910591,
+ERASE, 94417996881920, 94417996910591,
+STORE, 94417996333056, 94417997017087,
+STORE, 94417996333056, 94417997152255,
+SNULL, 94417997135871, 94417997152255,
+STORE, 94417996333056, 94417997135871,
+STORE, 94417997135872, 94417997152255,
+ERASE, 94417997135872, 94417997152255,
+STORE, 94417996333056, 94417997291519,
+SNULL, 94417997271039, 94417997291519,
+STORE, 94417996333056, 94417997271039,
+STORE, 94417997271040, 94417997291519,
+ERASE, 94417997271040, 94417997291519,
+STORE, 94417996333056, 94417997406207,
+SNULL, 94417997381631, 94417997406207,
+STORE, 94417996333056, 94417997381631,
+STORE, 94417997381632, 94417997406207,
+ERASE, 94417997381632, 94417997406207,
+STORE, 94417996333056, 94417997516799,
+SNULL, 94417997488127, 94417997516799,
+STORE, 94417996333056, 94417997488127,
+STORE, 94417997488128, 94417997516799,
+ERASE, 94417997488128, 94417997516799,
+STORE, 94417996333056, 94417997643775,
+SNULL, 94417997631487, 94417997643775,
+STORE, 94417996333056, 94417997631487,
+STORE, 94417997631488, 94417997643775,
+ERASE, 94417997631488, 94417997643775,
+SNULL, 94417997590527, 94417997631487,
+STORE, 94417996333056, 94417997590527,
+STORE, 94417997590528, 94417997631487,
+ERASE, 94417997590528, 94417997631487,
+STORE, 94417996333056, 94417997733887,
+STORE, 94417996333056, 94417997869055,
+STORE, 94417996333056, 94417998004223,
+SNULL, 94417998000127, 94417998004223,
+STORE, 94417996333056, 94417998000127,
+STORE, 94417998000128, 94417998004223,
+ERASE, 94417998000128, 94417998004223,
+STORE, 94049170993152, 94049171206143,
+STORE, 94049173303296, 94049173307391,
+STORE, 94049173307392, 94049173315583,
+STORE, 94049173315584, 94049173327871,
+STORE, 94049176236032, 94049183645695,
+STORE, 139807795544064, 139807797202943,
+STORE, 139807797202944, 139807799300095,
+STORE, 139807799300096, 139807799316479,
+STORE, 139807799316480, 139807799324671,
+STORE, 139807799324672, 139807799341055,
+STORE, 139807799341056, 139807799353343,
+STORE, 139807799353344, 139807801446399,
+STORE, 139807801446400, 139807801450495,
+STORE, 139807801450496, 139807801454591,
+STORE, 139807801454592, 139807801597951,
+STORE, 139807801966592, 139807803650047,
+STORE, 139807803650048, 139807803666431,
+STORE, 139807803695104, 139807803699199,
+STORE, 139807803699200, 139807803703295,
+STORE, 139807803703296, 139807803707391,
+STORE, 140727555538944, 140727555678207,
+STORE, 140727555940352, 140727555952639,
+STORE, 140727555952640, 140727555956735,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722483441664, 140737488351231,
+SNULL, 140722483449855, 140737488351231,
+STORE, 140722483441664, 140722483449855,
+STORE, 140722483310592, 140722483449855,
+STORE, 94416704921600, 94416707145727,
+SNULL, 94416705032191, 94416707145727,
+STORE, 94416704921600, 94416705032191,
+STORE, 94416705032192, 94416707145727,
+ERASE, 94416705032192, 94416707145727,
+STORE, 94416707125248, 94416707137535,
+STORE, 94416707137536, 94416707145727,
+STORE, 140555439296512, 140555441549311,
+SNULL, 140555439439871, 140555441549311,
+STORE, 140555439296512, 140555439439871,
+STORE, 140555439439872, 140555441549311,
+ERASE, 140555439439872, 140555441549311,
+STORE, 140555441537024, 140555441545215,
+STORE, 140555441545216, 140555441549311,
+STORE, 140722484781056, 140722484785151,
+STORE, 140722484768768, 140722484781055,
+STORE, 140555441508352, 140555441537023,
+STORE, 140555441500160, 140555441508351,
+STORE, 140555435499520, 140555439296511,
+SNULL, 140555435499520, 140555437158399,
+STORE, 140555437158400, 140555439296511,
+STORE, 140555435499520, 140555437158399,
+SNULL, 140555439255551, 140555439296511,
+STORE, 140555437158400, 140555439255551,
+STORE, 140555439255552, 140555439296511,
+SNULL, 140555439255552, 140555439280127,
+STORE, 140555439280128, 140555439296511,
+STORE, 140555439255552, 140555439280127,
+ERASE, 140555439255552, 140555439280127,
+STORE, 140555439255552, 140555439280127,
+ERASE, 140555439280128, 140555439296511,
+STORE, 140555439280128, 140555439296511,
+SNULL, 140555439271935, 140555439280127,
+STORE, 140555439255552, 140555439271935,
+STORE, 140555439271936, 140555439280127,
+SNULL, 94416707133439, 94416707137535,
+STORE, 94416707125248, 94416707133439,
+STORE, 94416707133440, 94416707137535,
+SNULL, 140555441541119, 140555441545215,
+STORE, 140555441537024, 140555441541119,
+STORE, 140555441541120, 140555441545215,
+ERASE, 140555441508352, 140555441537023,
+STORE, 94416724672512, 94416724807679,
+STORE, 94686636953600, 94686637166591,
+STORE, 94686639263744, 94686639267839,
+STORE, 94686639267840, 94686639276031,
+STORE, 94686639276032, 94686639288319,
+STORE, 94686662193152, 94686663163903,
+STORE, 140312944431104, 140312946089983,
+STORE, 140312946089984, 140312948187135,
+STORE, 140312948187136, 140312948203519,
+STORE, 140312948203520, 140312948211711,
+STORE, 140312948211712, 140312948228095,
+STORE, 140312948228096, 140312948240383,
+STORE, 140312948240384, 140312950333439,
+STORE, 140312950333440, 140312950337535,
+STORE, 140312950337536, 140312950341631,
+STORE, 140312950341632, 140312950484991,
+STORE, 140312950853632, 140312952537087,
+STORE, 140312952537088, 140312952553471,
+STORE, 140312952582144, 140312952586239,
+STORE, 140312952586240, 140312952590335,
+STORE, 140312952590336, 140312952594431,
+STORE, 140730598920192, 140730599059455,
+STORE, 140730599108608, 140730599120895,
+STORE, 140730599120896, 140730599124991,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140726234079232, 140737488351231,
+SNULL, 140726234087423, 140737488351231,
+STORE, 140726234079232, 140726234087423,
+STORE, 140726233948160, 140726234087423,
+STORE, 94589467578368, 94589469802495,
+SNULL, 94589467688959, 94589469802495,
+STORE, 94589467578368, 94589467688959,
+STORE, 94589467688960, 94589469802495,
+ERASE, 94589467688960, 94589469802495,
+STORE, 94589469782016, 94589469794303,
+STORE, 94589469794304, 94589469802495,
+STORE, 140587082842112, 140587085094911,
+SNULL, 140587082985471, 140587085094911,
+STORE, 140587082842112, 140587082985471,
+STORE, 140587082985472, 140587085094911,
+ERASE, 140587082985472, 140587085094911,
+STORE, 140587085082624, 140587085090815,
+STORE, 140587085090816, 140587085094911,
+STORE, 140726234103808, 140726234107903,
+STORE, 140726234091520, 140726234103807,
+STORE, 140587085053952, 140587085082623,
+STORE, 140587085045760, 140587085053951,
+STORE, 140587079045120, 140587082842111,
+SNULL, 140587079045120, 140587080703999,
+STORE, 140587080704000, 140587082842111,
+STORE, 140587079045120, 140587080703999,
+SNULL, 140587082801151, 140587082842111,
+STORE, 140587080704000, 140587082801151,
+STORE, 140587082801152, 140587082842111,
+SNULL, 140587082801152, 140587082825727,
+STORE, 140587082825728, 140587082842111,
+STORE, 140587082801152, 140587082825727,
+ERASE, 140587082801152, 140587082825727,
+STORE, 140587082801152, 140587082825727,
+ERASE, 140587082825728, 140587082842111,
+STORE, 140587082825728, 140587082842111,
+SNULL, 140587082817535, 140587082825727,
+STORE, 140587082801152, 140587082817535,
+STORE, 140587082817536, 140587082825727,
+SNULL, 94589469790207, 94589469794303,
+STORE, 94589469782016, 94589469790207,
+STORE, 94589469790208, 94589469794303,
+SNULL, 140587085086719, 140587085090815,
+STORE, 140587085082624, 140587085086719,
+STORE, 140587085086720, 140587085090815,
+ERASE, 140587085053952, 140587085082623,
+STORE, 94589477507072, 94589477642239,
+STORE, 94225448325120, 94225448538111,
+STORE, 94225450635264, 94225450639359,
+STORE, 94225450639360, 94225450647551,
+STORE, 94225450647552, 94225450659839,
+STORE, 94225470246912, 94225473548287,
+STORE, 140199245496320, 140199247155199,
+STORE, 140199247155200, 140199249252351,
+STORE, 140199249252352, 140199249268735,
+STORE, 140199249268736, 140199249276927,
+STORE, 140199249276928, 140199249293311,
+STORE, 140199249293312, 140199249305599,
+STORE, 140199249305600, 140199251398655,
+STORE, 140199251398656, 140199251402751,
+STORE, 140199251402752, 140199251406847,
+STORE, 140199251406848, 140199251550207,
+STORE, 140199251918848, 140199253602303,
+STORE, 140199253602304, 140199253618687,
+STORE, 140199253647360, 140199253651455,
+STORE, 140199253651456, 140199253655551,
+STORE, 140199253655552, 140199253659647,
+STORE, 140726264414208, 140726264553471,
+STORE, 140726265843712, 140726265855999,
+STORE, 140726265856000, 140726265860095,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733508358144, 140737488351231,
+SNULL, 140733508366335, 140737488351231,
+STORE, 140733508358144, 140733508366335,
+STORE, 140733508227072, 140733508366335,
+STORE, 94766263947264, 94766266171391,
+SNULL, 94766264057855, 94766266171391,
+STORE, 94766263947264, 94766264057855,
+STORE, 94766264057856, 94766266171391,
+ERASE, 94766264057856, 94766266171391,
+STORE, 94766266150912, 94766266163199,
+STORE, 94766266163200, 94766266171391,
+STORE, 140693985132544, 140693987385343,
+SNULL, 140693985275903, 140693987385343,
+STORE, 140693985132544, 140693985275903,
+STORE, 140693985275904, 140693987385343,
+ERASE, 140693985275904, 140693987385343,
+STORE, 140693987373056, 140693987381247,
+STORE, 140693987381248, 140693987385343,
+STORE, 140733509939200, 140733509943295,
+STORE, 140733509926912, 140733509939199,
+STORE, 140693987344384, 140693987373055,
+STORE, 140693987336192, 140693987344383,
+STORE, 140693981335552, 140693985132543,
+SNULL, 140693981335552, 140693982994431,
+STORE, 140693982994432, 140693985132543,
+STORE, 140693981335552, 140693982994431,
+SNULL, 140693985091583, 140693985132543,
+STORE, 140693982994432, 140693985091583,
+STORE, 140693985091584, 140693985132543,
+SNULL, 140693985091584, 140693985116159,
+STORE, 140693985116160, 140693985132543,
+STORE, 140693985091584, 140693985116159,
+ERASE, 140693985091584, 140693985116159,
+STORE, 140693985091584, 140693985116159,
+ERASE, 140693985116160, 140693985132543,
+STORE, 140693985116160, 140693985132543,
+SNULL, 140693985107967, 140693985116159,
+STORE, 140693985091584, 140693985107967,
+STORE, 140693985107968, 140693985116159,
+SNULL, 94766266159103, 94766266163199,
+STORE, 94766266150912, 94766266159103,
+STORE, 94766266159104, 94766266163199,
+SNULL, 140693987377151, 140693987381247,
+STORE, 140693987373056, 140693987377151,
+STORE, 140693987377152, 140693987381247,
+ERASE, 140693987344384, 140693987373055,
+STORE, 94766282035200, 94766282170367,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724769353728, 140737488351231,
+SNULL, 140724769361919, 140737488351231,
+STORE, 140724769353728, 140724769361919,
+STORE, 140724769222656, 140724769361919,
+STORE, 94710460526592, 94710462750719,
+SNULL, 94710460637183, 94710462750719,
+STORE, 94710460526592, 94710460637183,
+STORE, 94710460637184, 94710462750719,
+ERASE, 94710460637184, 94710462750719,
+STORE, 94710462730240, 94710462742527,
+STORE, 94710462742528, 94710462750719,
+STORE, 140469764395008, 140469766647807,
+SNULL, 140469764538367, 140469766647807,
+STORE, 140469764395008, 140469764538367,
+STORE, 140469764538368, 140469766647807,
+ERASE, 140469764538368, 140469766647807,
+STORE, 140469766635520, 140469766643711,
+STORE, 140469766643712, 140469766647807,
+STORE, 140724770877440, 140724770881535,
+STORE, 140724770865152, 140724770877439,
+STORE, 140469766606848, 140469766635519,
+STORE, 140469766598656, 140469766606847,
+STORE, 140469760598016, 140469764395007,
+SNULL, 140469760598016, 140469762256895,
+STORE, 140469762256896, 140469764395007,
+STORE, 140469760598016, 140469762256895,
+SNULL, 140469764354047, 140469764395007,
+STORE, 140469762256896, 140469764354047,
+STORE, 140469764354048, 140469764395007,
+SNULL, 140469764354048, 140469764378623,
+STORE, 140469764378624, 140469764395007,
+STORE, 140469764354048, 140469764378623,
+ERASE, 140469764354048, 140469764378623,
+STORE, 140469764354048, 140469764378623,
+ERASE, 140469764378624, 140469764395007,
+STORE, 140469764378624, 140469764395007,
+SNULL, 140469764370431, 140469764378623,
+STORE, 140469764354048, 140469764370431,
+STORE, 140469764370432, 140469764378623,
+SNULL, 94710462738431, 94710462742527,
+STORE, 94710462730240, 94710462738431,
+STORE, 94710462738432, 94710462742527,
+SNULL, 140469766639615, 140469766643711,
+STORE, 140469766635520, 140469766639615,
+STORE, 140469766639616, 140469766643711,
+ERASE, 140469766606848, 140469766635519,
+STORE, 94710485581824, 94710485716991,
+STORE, 94105755795456, 94105756008447,
+STORE, 94105758105600, 94105758109695,
+STORE, 94105758109696, 94105758117887,
+STORE, 94105758117888, 94105758130175,
+STORE, 94105788981248, 94105794871295,
+STORE, 140641190031360, 140641191690239,
+STORE, 140641191690240, 140641193787391,
+STORE, 140641193787392, 140641193803775,
+STORE, 140641193803776, 140641193811967,
+STORE, 140641193811968, 140641193828351,
+STORE, 140641193828352, 140641193840639,
+STORE, 140641193840640, 140641195933695,
+STORE, 140641195933696, 140641195937791,
+STORE, 140641195937792, 140641195941887,
+STORE, 140641195941888, 140641196085247,
+STORE, 140641196453888, 140641198137343,
+STORE, 140641198137344, 140641198153727,
+STORE, 140641198182400, 140641198186495,
+STORE, 140641198186496, 140641198190591,
+STORE, 140641198190592, 140641198194687,
+STORE, 140731980034048, 140731980173311,
+STORE, 140731981078528, 140731981090815,
+STORE, 140731981090816, 140731981094911,
+STORE, 93828086431744, 93828086644735,
+STORE, 93828088741888, 93828088745983,
+STORE, 93828088745984, 93828088754175,
+STORE, 93828088754176, 93828088766463,
+STORE, 93828094193664, 93828096831487,
+STORE, 139844717334528, 139844718993407,
+STORE, 139844718993408, 139844721090559,
+STORE, 139844721090560, 139844721106943,
+STORE, 139844721106944, 139844721115135,
+STORE, 139844721115136, 139844721131519,
+STORE, 139844721131520, 139844721143807,
+STORE, 139844721143808, 139844723236863,
+STORE, 139844723236864, 139844723240959,
+STORE, 139844723240960, 139844723245055,
+STORE, 139844723245056, 139844723388415,
+STORE, 139844723757056, 139844725440511,
+STORE, 139844725440512, 139844725456895,
+STORE, 139844725485568, 139844725489663,
+STORE, 139844725489664, 139844725493759,
+STORE, 139844725493760, 139844725497855,
+STORE, 140729996185600, 140729996324863,
+STORE, 140729996828672, 140729996840959,
+STORE, 140729996840960, 140729996845055,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722494771200, 140737488351231,
+SNULL, 140722494775295, 140737488351231,
+STORE, 140722494771200, 140722494775295,
+STORE, 140722494640128, 140722494775295,
+STORE, 94324011311104, 94324013535231,
+SNULL, 94324011421695, 94324013535231,
+STORE, 94324011311104, 94324011421695,
+STORE, 94324011421696, 94324013535231,
+ERASE, 94324011421696, 94324013535231,
+STORE, 94324013514752, 94324013527039,
+STORE, 94324013527040, 94324013535231,
+STORE, 140151462309888, 140151464562687,
+SNULL, 140151462453247, 140151464562687,
+STORE, 140151462309888, 140151462453247,
+STORE, 140151462453248, 140151464562687,
+ERASE, 140151462453248, 140151464562687,
+STORE, 140151464550400, 140151464558591,
+STORE, 140151464558592, 140151464562687,
+STORE, 140722495467520, 140722495471615,
+STORE, 140722495455232, 140722495467519,
+STORE, 140151464521728, 140151464550399,
+STORE, 140151464513536, 140151464521727,
+STORE, 140151458512896, 140151462309887,
+SNULL, 140151458512896, 140151460171775,
+STORE, 140151460171776, 140151462309887,
+STORE, 140151458512896, 140151460171775,
+SNULL, 140151462268927, 140151462309887,
+STORE, 140151460171776, 140151462268927,
+STORE, 140151462268928, 140151462309887,
+SNULL, 140151462268928, 140151462293503,
+STORE, 140151462293504, 140151462309887,
+STORE, 140151462268928, 140151462293503,
+ERASE, 140151462268928, 140151462293503,
+STORE, 140151462268928, 140151462293503,
+ERASE, 140151462293504, 140151462309887,
+STORE, 140151462293504, 140151462309887,
+SNULL, 140151462285311, 140151462293503,
+STORE, 140151462268928, 140151462285311,
+STORE, 140151462285312, 140151462293503,
+SNULL, 94324013522943, 94324013527039,
+STORE, 94324013514752, 94324013522943,
+STORE, 94324013522944, 94324013527039,
+SNULL, 140151464554495, 140151464558591,
+STORE, 140151464550400, 140151464554495,
+STORE, 140151464554496, 140151464558591,
+ERASE, 140151464521728, 140151464550399,
+STORE, 94324024778752, 94324024913919,
+STORE, 94899262967808, 94899263180799,
+STORE, 94899265277952, 94899265282047,
+STORE, 94899265282048, 94899265290239,
+STORE, 94899265290240, 94899265302527,
+STORE, 94899295469568, 94899298689023,
+STORE, 140434388418560, 140434390077439,
+STORE, 140434390077440, 140434392174591,
+STORE, 140434392174592, 140434392190975,
+STORE, 140434392190976, 140434392199167,
+STORE, 140434392199168, 140434392215551,
+STORE, 140434392215552, 140434392227839,
+STORE, 140434392227840, 140434394320895,
+STORE, 140434394320896, 140434394324991,
+STORE, 140434394324992, 140434394329087,
+STORE, 140434394329088, 140434394472447,
+STORE, 140434394841088, 140434396524543,
+STORE, 140434396524544, 140434396540927,
+STORE, 140434396569600, 140434396573695,
+STORE, 140434396573696, 140434396577791,
+STORE, 140434396577792, 140434396581887,
+STORE, 140720618135552, 140720618274815,
+STORE, 140720618418176, 140720618430463,
+STORE, 140720618430464, 140720618434559,
+STORE, 94425529798656, 94425530011647,
+STORE, 94425532108800, 94425532112895,
+STORE, 94425532112896, 94425532121087,
+STORE, 94425532121088, 94425532133375,
+STORE, 94425557753856, 94425566576639,
+STORE, 140600528470016, 140600530128895,
+STORE, 140600530128896, 140600532226047,
+STORE, 140600532226048, 140600532242431,
+STORE, 140600532242432, 140600532250623,
+STORE, 140600532250624, 140600532267007,
+STORE, 140600532267008, 140600532279295,
+STORE, 140600532279296, 140600534372351,
+STORE, 140600534372352, 140600534376447,
+STORE, 140600534376448, 140600534380543,
+STORE, 140600534380544, 140600534523903,
+STORE, 140600534892544, 140600536575999,
+STORE, 140600536576000, 140600536592383,
+STORE, 140600536621056, 140600536625151,
+STORE, 140600536625152, 140600536629247,
+STORE, 140600536629248, 140600536633343,
+STORE, 140721857785856, 140721857925119,
+STORE, 140721858068480, 140721858080767,
+STORE, 140721858080768, 140721858084863,
+STORE, 94425529798656, 94425530011647,
+STORE, 94425532108800, 94425532112895,
+STORE, 94425532112896, 94425532121087,
+STORE, 94425532121088, 94425532133375,
+STORE, 94425557753856, 94425568772095,
+STORE, 140600528470016, 140600530128895,
+STORE, 140600530128896, 140600532226047,
+STORE, 140600532226048, 140600532242431,
+STORE, 140600532242432, 140600532250623,
+STORE, 140600532250624, 140600532267007,
+STORE, 140600532267008, 140600532279295,
+STORE, 140600532279296, 140600534372351,
+STORE, 140600534372352, 140600534376447,
+STORE, 140600534376448, 140600534380543,
+STORE, 140600534380544, 140600534523903,
+STORE, 140600534892544, 140600536575999,
+STORE, 140600536576000, 140600536592383,
+STORE, 140600536621056, 140600536625151,
+STORE, 140600536625152, 140600536629247,
+STORE, 140600536629248, 140600536633343,
+STORE, 140721857785856, 140721857925119,
+STORE, 140721858068480, 140721858080767,
+STORE, 140721858080768, 140721858084863,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735611645952, 140737488351231,
+SNULL, 140735611654143, 140737488351231,
+STORE, 140735611645952, 140735611654143,
+STORE, 140735611514880, 140735611654143,
+STORE, 94592137641984, 94592139866111,
+SNULL, 94592137752575, 94592139866111,
+STORE, 94592137641984, 94592137752575,
+STORE, 94592137752576, 94592139866111,
+ERASE, 94592137752576, 94592139866111,
+STORE, 94592139845632, 94592139857919,
+STORE, 94592139857920, 94592139866111,
+STORE, 140350425030656, 140350427283455,
+SNULL, 140350425174015, 140350427283455,
+STORE, 140350425030656, 140350425174015,
+STORE, 140350425174016, 140350427283455,
+ERASE, 140350425174016, 140350427283455,
+STORE, 140350427271168, 140350427279359,
+STORE, 140350427279360, 140350427283455,
+STORE, 140735612043264, 140735612047359,
+STORE, 140735612030976, 140735612043263,
+STORE, 140350427242496, 140350427271167,
+STORE, 140350427234304, 140350427242495,
+STORE, 140350421233664, 140350425030655,
+SNULL, 140350421233664, 140350422892543,
+STORE, 140350422892544, 140350425030655,
+STORE, 140350421233664, 140350422892543,
+SNULL, 140350424989695, 140350425030655,
+STORE, 140350422892544, 140350424989695,
+STORE, 140350424989696, 140350425030655,
+SNULL, 140350424989696, 140350425014271,
+STORE, 140350425014272, 140350425030655,
+STORE, 140350424989696, 140350425014271,
+ERASE, 140350424989696, 140350425014271,
+STORE, 140350424989696, 140350425014271,
+ERASE, 140350425014272, 140350425030655,
+STORE, 140350425014272, 140350425030655,
+SNULL, 140350425006079, 140350425014271,
+STORE, 140350424989696, 140350425006079,
+STORE, 140350425006080, 140350425014271,
+SNULL, 94592139853823, 94592139857919,
+STORE, 94592139845632, 94592139853823,
+STORE, 94592139853824, 94592139857919,
+SNULL, 140350427275263, 140350427279359,
+STORE, 140350427271168, 140350427275263,
+STORE, 140350427275264, 140350427279359,
+ERASE, 140350427242496, 140350427271167,
+STORE, 94592164823040, 94592164958207,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723500535808, 140737488351231,
+SNULL, 140723500543999, 140737488351231,
+STORE, 140723500535808, 140723500543999,
+STORE, 140723500404736, 140723500543999,
+STORE, 94458379010048, 94458381234175,
+SNULL, 94458379120639, 94458381234175,
+STORE, 94458379010048, 94458379120639,
+STORE, 94458379120640, 94458381234175,
+ERASE, 94458379120640, 94458381234175,
+STORE, 94458381213696, 94458381225983,
+STORE, 94458381225984, 94458381234175,
+STORE, 139771674230784, 139771676483583,
+SNULL, 139771674374143, 139771676483583,
+STORE, 139771674230784, 139771674374143,
+STORE, 139771674374144, 139771676483583,
+ERASE, 139771674374144, 139771676483583,
+STORE, 139771676471296, 139771676479487,
+STORE, 139771676479488, 139771676483583,
+STORE, 140723500769280, 140723500773375,
+STORE, 140723500756992, 140723500769279,
+STORE, 139771676442624, 139771676471295,
+STORE, 139771676434432, 139771676442623,
+STORE, 139771670433792, 139771674230783,
+SNULL, 139771670433792, 139771672092671,
+STORE, 139771672092672, 139771674230783,
+STORE, 139771670433792, 139771672092671,
+SNULL, 139771674189823, 139771674230783,
+STORE, 139771672092672, 139771674189823,
+STORE, 139771674189824, 139771674230783,
+SNULL, 139771674189824, 139771674214399,
+STORE, 139771674214400, 139771674230783,
+STORE, 139771674189824, 139771674214399,
+ERASE, 139771674189824, 139771674214399,
+STORE, 139771674189824, 139771674214399,
+ERASE, 139771674214400, 139771674230783,
+STORE, 139771674214400, 139771674230783,
+SNULL, 139771674206207, 139771674214399,
+STORE, 139771674189824, 139771674206207,
+STORE, 139771674206208, 139771674214399,
+SNULL, 94458381221887, 94458381225983,
+STORE, 94458381213696, 94458381221887,
+STORE, 94458381221888, 94458381225983,
+SNULL, 139771676475391, 139771676479487,
+STORE, 139771676471296, 139771676475391,
+STORE, 139771676475392, 139771676479487,
+ERASE, 139771676442624, 139771676471295,
+STORE, 94458401873920, 94458402009087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731316264960, 140737488351231,
+SNULL, 140731316273151, 140737488351231,
+STORE, 140731316264960, 140731316273151,
+STORE, 140731316133888, 140731316273151,
+STORE, 94437830881280, 94437833215999,
+SNULL, 94437831094271, 94437833215999,
+STORE, 94437830881280, 94437831094271,
+STORE, 94437831094272, 94437833215999,
+ERASE, 94437831094272, 94437833215999,
+STORE, 94437833191424, 94437833203711,
+STORE, 94437833203712, 94437833215999,
+STORE, 140265986031616, 140265988284415,
+SNULL, 140265986174975, 140265988284415,
+STORE, 140265986031616, 140265986174975,
+STORE, 140265986174976, 140265988284415,
+ERASE, 140265986174976, 140265988284415,
+STORE, 140265988272128, 140265988280319,
+STORE, 140265988280320, 140265988284415,
+STORE, 140731316318208, 140731316322303,
+STORE, 140731316305920, 140731316318207,
+STORE, 140265988243456, 140265988272127,
+STORE, 140265988235264, 140265988243455,
+STORE, 140265983918080, 140265986031615,
+SNULL, 140265983918080, 140265983930367,
+STORE, 140265983930368, 140265986031615,
+STORE, 140265983918080, 140265983930367,
+SNULL, 140265986023423, 140265986031615,
+STORE, 140265983930368, 140265986023423,
+STORE, 140265986023424, 140265986031615,
+ERASE, 140265986023424, 140265986031615,
+STORE, 140265986023424, 140265986031615,
+STORE, 140265980121088, 140265983918079,
+SNULL, 140265980121088, 140265981779967,
+STORE, 140265981779968, 140265983918079,
+STORE, 140265980121088, 140265981779967,
+SNULL, 140265983877119, 140265983918079,
+STORE, 140265981779968, 140265983877119,
+STORE, 140265983877120, 140265983918079,
+SNULL, 140265983877120, 140265983901695,
+STORE, 140265983901696, 140265983918079,
+STORE, 140265983877120, 140265983901695,
+ERASE, 140265983877120, 140265983901695,
+STORE, 140265983877120, 140265983901695,
+ERASE, 140265983901696, 140265983918079,
+STORE, 140265983901696, 140265983918079,
+STORE, 140265988227072, 140265988243455,
+SNULL, 140265983893503, 140265983901695,
+STORE, 140265983877120, 140265983893503,
+STORE, 140265983893504, 140265983901695,
+SNULL, 140265986027519, 140265986031615,
+STORE, 140265986023424, 140265986027519,
+STORE, 140265986027520, 140265986031615,
+SNULL, 94437833195519, 94437833203711,
+STORE, 94437833191424, 94437833195519,
+STORE, 94437833195520, 94437833203711,
+SNULL, 140265988276223, 140265988280319,
+STORE, 140265988272128, 140265988276223,
+STORE, 140265988276224, 140265988280319,
+ERASE, 140265988243456, 140265988272127,
+STORE, 94437847638016, 94437847773183,
+STORE, 140265986543616, 140265988227071,
+STORE, 94437847638016, 94437847908351,
+STORE, 94437847638016, 94437848043519,
+STORE, 94437847638016, 94437848190975,
+SNULL, 94437848178687, 94437848190975,
+STORE, 94437847638016, 94437848178687,
+STORE, 94437848178688, 94437848190975,
+ERASE, 94437848178688, 94437848190975,
+STORE, 94437847638016, 94437848330239,
+STORE, 94437847638016, 94437848465407,
+SNULL, 94437848444927, 94437848465407,
+STORE, 94437847638016, 94437848444927,
+STORE, 94437848444928, 94437848465407,
+ERASE, 94437848444928, 94437848465407,
+STORE, 94437847638016, 94437848584191,
+STORE, 94437847638016, 94437848719359,
+SNULL, 94437848678399, 94437848719359,
+STORE, 94437847638016, 94437848678399,
+STORE, 94437848678400, 94437848719359,
+ERASE, 94437848678400, 94437848719359,
+STORE, 94437847638016, 94437848842239,
+SNULL, 94437848825855, 94437848842239,
+STORE, 94437847638016, 94437848825855,
+STORE, 94437848825856, 94437848842239,
+ERASE, 94437848825856, 94437848842239,
+STORE, 94437847638016, 94437848961023,
+STORE, 94437847638016, 94437849096191,
+STORE, 94661814710272, 94661814923263,
+STORE, 94661817020416, 94661817024511,
+STORE, 94661817024512, 94661817032703,
+STORE, 94661817032704, 94661817044991,
+STORE, 94661840424960, 94661841240063,
+STORE, 140582259814400, 140582261473279,
+STORE, 140582261473280, 140582263570431,
+STORE, 140582263570432, 140582263586815,
+STORE, 140582263586816, 140582263595007,
+STORE, 140582263595008, 140582263611391,
+STORE, 140582263611392, 140582263623679,
+STORE, 140582263623680, 140582265716735,
+STORE, 140582265716736, 140582265720831,
+STORE, 140582265720832, 140582265724927,
+STORE, 140582265724928, 140582265868287,
+STORE, 140582266236928, 140582267920383,
+STORE, 140582267920384, 140582267936767,
+STORE, 140582267965440, 140582267969535,
+STORE, 140582267969536, 140582267973631,
+STORE, 140582267973632, 140582267977727,
+STORE, 140735472508928, 140735472648191,
+STORE, 140735472672768, 140735472685055,
+STORE, 140735472685056, 140735472689151,
+STORE, 94440069140480, 94440069353471,
+STORE, 94440071450624, 94440071454719,
+STORE, 94440071454720, 94440071462911,
+STORE, 94440071462912, 94440071475199,
+STORE, 94440072122368, 94440079048703,
+STORE, 140112218095616, 140112219754495,
+STORE, 140112219754496, 140112221851647,
+STORE, 140112221851648, 140112221868031,
+STORE, 140112221868032, 140112221876223,
+STORE, 140112221876224, 140112221892607,
+STORE, 140112221892608, 140112221904895,
+STORE, 140112221904896, 140112223997951,
+STORE, 140112223997952, 140112224002047,
+STORE, 140112224002048, 140112224006143,
+STORE, 140112224006144, 140112224149503,
+STORE, 140112224518144, 140112226201599,
+STORE, 140112226201600, 140112226217983,
+STORE, 140112226246656, 140112226250751,
+STORE, 140112226250752, 140112226254847,
+STORE, 140112226254848, 140112226258943,
+STORE, 140737460969472, 140737461108735,
+STORE, 140737462083584, 140737462095871,
+STORE, 140737462095872, 140737462099967,
+STORE, 94257654345728, 94257654390783,
+STORE, 94257656483840, 94257656487935,
+STORE, 94257656487936, 94257656492031,
+STORE, 94257656492032, 94257656496127,
+STORE, 94257665859584, 94257665994751,
+STORE, 140507070345216, 140507070386175,
+STORE, 140507070386176, 140507072483327,
+STORE, 140507072483328, 140507072487423,
+STORE, 140507072487424, 140507072491519,
+STORE, 140507072491520, 140507072516095,
+STORE, 140507072516096, 140507072561151,
+STORE, 140507072561152, 140507074654207,
+STORE, 140507074654208, 140507074658303,
+STORE, 140507074658304, 140507074662399,
+STORE, 140507074662400, 140507074744319,
+STORE, 140507074744320, 140507076841471,
+STORE, 140507076841472, 140507076845567,
+STORE, 140507076845568, 140507076849663,
+STORE, 140507076849664, 140507076857855,
+STORE, 140507076857856, 140507076886527,
+STORE, 140507076886528, 140507078979583,
+STORE, 140507078979584, 140507078983679,
+STORE, 140507078983680, 140507078987775,
+STORE, 140507078987776, 140507079086079,
+STORE, 140507079086080, 140507081179135,
+STORE, 140507081179136, 140507081183231,
+STORE, 140507081183232, 140507081187327,
+STORE, 140507081187328, 140507081203711,
+STORE, 140507081203712, 140507081220095,
+STORE, 140507081220096, 140507083317247,
+STORE, 140507083317248, 140507083321343,
+STORE, 140507083321344, 140507083325439,
+STORE, 140507083325440, 140507083792383,
+STORE, 140507083792384, 140507085885439,
+STORE, 140507085885440, 140507085889535,
+STORE, 140507085889536, 140507085893631,
+STORE, 140507085893632, 140507085905919,
+STORE, 140507085905920, 140507087998975,
+STORE, 140507087998976, 140507088003071,
+STORE, 140507088003072, 140507088007167,
+STORE, 140507088007168, 140507088125951,
+STORE, 140507088125952, 140507090219007,
+STORE, 140507090219008, 140507090223103,
+STORE, 140507090223104, 140507090227199,
+STORE, 140507090227200, 140507090268159,
+STORE, 140507090268160, 140507091927039,
+STORE, 140507091927040, 140507094024191,
+STORE, 140507094024192, 140507094040575,
+STORE, 140507094040576, 140507094048767,
+STORE, 140507094048768, 140507094065151,
+STORE, 140507094065152, 140507094216703,
+STORE, 140507094216704, 140507096309759,
+STORE, 140507096309760, 140507096313855,
+STORE, 140507096313856, 140507096317951,
+STORE, 140507096317952, 140507096326143,
+STORE, 140507096326144, 140507096379391,
+STORE, 140507096379392, 140507098472447,
+STORE, 140507098472448, 140507098476543,
+STORE, 140507098476544, 140507098480639,
+STORE, 140507098480640, 140507098623999,
+STORE, 140507098980352, 140507100663807,
+STORE, 140507100663808, 140507100692479,
+STORE, 140507100721152, 140507100725247,
+STORE, 140507100725248, 140507100729343,
+STORE, 140507100729344, 140507100733439,
+STORE, 140728152780800, 140728152915967,
+STORE, 140728153698304, 140728153710591,
+STORE, 140728153710592, 140728153714687,
+STORE, 140507068137472, 140507070345215,
+SNULL, 140507068137472, 140507068190719,
+STORE, 140507068190720, 140507070345215,
+STORE, 140507068137472, 140507068190719,
+SNULL, 140507070287871, 140507070345215,
+STORE, 140507068190720, 140507070287871,
+STORE, 140507070287872, 140507070345215,
+SNULL, 140507070287872, 140507070296063,
+STORE, 140507070296064, 140507070345215,
+STORE, 140507070287872, 140507070296063,
+ERASE, 140507070287872, 140507070296063,
+STORE, 140507070287872, 140507070296063,
+ERASE, 140507070296064, 140507070345215,
+STORE, 140507070296064, 140507070345215,
+STORE, 140507100692480, 140507100721151,
+STORE, 140507065810944, 140507068137471,
+SNULL, 140507065810944, 140507065843711,
+STORE, 140507065843712, 140507068137471,
+STORE, 140507065810944, 140507065843711,
+SNULL, 140507067940863, 140507068137471,
+STORE, 140507065843712, 140507067940863,
+STORE, 140507067940864, 140507068137471,
+SNULL, 140507067940864, 140507067949055,
+STORE, 140507067949056, 140507068137471,
+STORE, 140507067940864, 140507067949055,
+ERASE, 140507067940864, 140507067949055,
+STORE, 140507067940864, 140507067949055,
+ERASE, 140507067949056, 140507068137471,
+STORE, 140507067949056, 140507068137471,
+SNULL, 140507067944959, 140507067949055,
+STORE, 140507067940864, 140507067944959,
+STORE, 140507067944960, 140507067949055,
+SNULL, 140507070291967, 140507070296063,
+STORE, 140507070287872, 140507070291967,
+STORE, 140507070291968, 140507070296063,
+ERASE, 140507100692480, 140507100721151,
+STORE, 140507063705600, 140507065810943,
+SNULL, 140507063705600, 140507063709695,
+STORE, 140507063709696, 140507065810943,
+STORE, 140507063705600, 140507063709695,
+SNULL, 140507065802751, 140507065810943,
+STORE, 140507063709696, 140507065802751,
+STORE, 140507065802752, 140507065810943,
+ERASE, 140507065802752, 140507065810943,
+STORE, 140507065802752, 140507065810943,
+SNULL, 140507065806847, 140507065810943,
+STORE, 140507065802752, 140507065806847,
+STORE, 140507065806848, 140507065810943,
+STORE, 140507061600256, 140507063705599,
+SNULL, 140507061600256, 140507061604351,
+STORE, 140507061604352, 140507063705599,
+STORE, 140507061600256, 140507061604351,
+SNULL, 140507063697407, 140507063705599,
+STORE, 140507061604352, 140507063697407,
+STORE, 140507063697408, 140507063705599,
+ERASE, 140507063697408, 140507063705599,
+STORE, 140507063697408, 140507063705599,
+SNULL, 140507063701503, 140507063705599,
+STORE, 140507063697408, 140507063701503,
+STORE, 140507063701504, 140507063705599,
+STORE, 140507059490816, 140507061600255,
+SNULL, 140507059490816, 140507059499007,
+STORE, 140507059499008, 140507061600255,
+STORE, 140507059490816, 140507059499007,
+SNULL, 140507061592063, 140507061600255,
+STORE, 140507059499008, 140507061592063,
+STORE, 140507061592064, 140507061600255,
+ERASE, 140507061592064, 140507061600255,
+STORE, 140507061592064, 140507061600255,
+SNULL, 140507061596159, 140507061600255,
+STORE, 140507061592064, 140507061596159,
+STORE, 140507061596160, 140507061600255,
+STORE, 140507057377280, 140507059490815,
+SNULL, 140507057377280, 140507057389567,
+STORE, 140507057389568, 140507059490815,
+STORE, 140507057377280, 140507057389567,
+SNULL, 140507059482623, 140507059490815,
+STORE, 140507057389568, 140507059482623,
+STORE, 140507059482624, 140507059490815,
+ERASE, 140507059482624, 140507059490815,
+STORE, 140507059482624, 140507059490815,
+SNULL, 140507059486719, 140507059490815,
+STORE, 140507059482624, 140507059486719,
+STORE, 140507059486720, 140507059490815,
+STORE, 140507055255552, 140507057377279,
+SNULL, 140507055255552, 140507055276031,
+STORE, 140507055276032, 140507057377279,
+STORE, 140507055255552, 140507055276031,
+SNULL, 140507057369087, 140507057377279,
+STORE, 140507055276032, 140507057369087,
+STORE, 140507057369088, 140507057377279,
+ERASE, 140507057369088, 140507057377279,
+STORE, 140507057369088, 140507057377279,
+SNULL, 140507057373183, 140507057377279,
+STORE, 140507057369088, 140507057373183,
+STORE, 140507057373184, 140507057377279,
+STORE, 140507098693632, 140507098980351,
+SNULL, 140507098959871, 140507098980351,
+STORE, 140507098693632, 140507098959871,
+STORE, 140507098959872, 140507098980351,
+SNULL, 140507098959872, 140507098976255,
+STORE, 140507098976256, 140507098980351,
+STORE, 140507098959872, 140507098976255,
+ERASE, 140507098959872, 140507098976255,
+STORE, 140507098959872, 140507098976255,
+ERASE, 140507098976256, 140507098980351,
+STORE, 140507098976256, 140507098980351,
+STORE, 140507100692480, 140507100721151,
+STORE, 140507053125632, 140507055255551,
+SNULL, 140507053125632, 140507053154303,
+STORE, 140507053154304, 140507055255551,
+STORE, 140507053125632, 140507053154303,
+SNULL, 140507055247359, 140507055255551,
+STORE, 140507053154304, 140507055247359,
+STORE, 140507055247360, 140507055255551,
+ERASE, 140507055247360, 140507055255551,
+STORE, 140507055247360, 140507055255551,
+STORE, 140507051012096, 140507053125631,
+SNULL, 140507051012096, 140507051024383,
+STORE, 140507051024384, 140507053125631,
+STORE, 140507051012096, 140507051024383,
+SNULL, 140507053117439, 140507053125631,
+STORE, 140507051024384, 140507053117439,
+STORE, 140507053117440, 140507053125631,
+ERASE, 140507053117440, 140507053125631,
+STORE, 140507053117440, 140507053125631,
+SNULL, 140507053121535, 140507053125631,
+STORE, 140507053117440, 140507053121535,
+STORE, 140507053121536, 140507053125631,
+SNULL, 140507055251455, 140507055255551,
+STORE, 140507055247360, 140507055251455,
+STORE, 140507055251456, 140507055255551,
+SNULL, 140507098972159, 140507098976255,
+STORE, 140507098959872, 140507098972159,
+STORE, 140507098972160, 140507098976255,
+ERASE, 140507100692480, 140507100721151,
+STORE, 140507100717056, 140507100721151,
+ERASE, 140507100717056, 140507100721151,
+STORE, 140507100717056, 140507100721151,
+ERASE, 140507100717056, 140507100721151,
+STORE, 140507100717056, 140507100721151,
+ERASE, 140507100717056, 140507100721151,
+STORE, 140507100717056, 140507100721151,
+ERASE, 140507100717056, 140507100721151,
+STORE, 140507100692480, 140507100721151,
+ERASE, 140507068137472, 140507068190719,
+ERASE, 140507068190720, 140507070287871,
+ERASE, 140507070287872, 140507070291967,
+ERASE, 140507070291968, 140507070296063,
+ERASE, 140507070296064, 140507070345215,
+ERASE, 140507065810944, 140507065843711,
+ERASE, 140507065843712, 140507067940863,
+ERASE, 140507067940864, 140507067944959,
+ERASE, 140507067944960, 140507067949055,
+ERASE, 140507067949056, 140507068137471,
+ERASE, 140507063705600, 140507063709695,
+ERASE, 140507063709696, 140507065802751,
+ERASE, 140507065802752, 140507065806847,
+ERASE, 140507065806848, 140507065810943,
+ERASE, 140507061600256, 140507061604351,
+ERASE, 140507061604352, 140507063697407,
+ERASE, 140507063697408, 140507063701503,
+ERASE, 140507063701504, 140507063705599,
+ERASE, 140507059490816, 140507059499007,
+ERASE, 140507059499008, 140507061592063,
+ERASE, 140507061592064, 140507061596159,
+ERASE, 140507061596160, 140507061600255,
+ERASE, 140507057377280, 140507057389567,
+ERASE, 140507057389568, 140507059482623,
+ERASE, 140507059482624, 140507059486719,
+ERASE, 140507059486720, 140507059490815,
+ERASE, 140507055255552, 140507055276031,
+ERASE, 140507055276032, 140507057369087,
+ERASE, 140507057369088, 140507057373183,
+ERASE, 140507057373184, 140507057377279,
+ERASE, 140507098693632, 140507098959871,
+ERASE, 140507098959872, 140507098972159,
+ERASE, 140507098972160, 140507098976255,
+ERASE, 140507098976256, 140507098980351,
+ERASE, 140507051012096, 140507051024383,
+ERASE, 140507051024384, 140507053117439,
+ERASE, 140507053117440, 140507053121535,
+ERASE, 140507053121536, 140507053125631,
+STORE, 94036448296960, 94036448509951,
+STORE, 94036450607104, 94036450611199,
+STORE, 94036450611200, 94036450619391,
+STORE, 94036450619392, 94036450631679,
+STORE, 94036482445312, 94036502376447,
+STORE, 140469487013888, 140469488672767,
+STORE, 140469488672768, 140469490769919,
+STORE, 140469490769920, 140469490786303,
+STORE, 140469490786304, 140469490794495,
+STORE, 140469490794496, 140469490810879,
+STORE, 140469490810880, 140469490823167,
+STORE, 140469490823168, 140469492916223,
+STORE, 140469492916224, 140469492920319,
+STORE, 140469492920320, 140469492924415,
+STORE, 140469492924416, 140469493067775,
+STORE, 140469493436416, 140469495119871,
+STORE, 140469495119872, 140469495136255,
+STORE, 140469495164928, 140469495169023,
+STORE, 140469495169024, 140469495173119,
+STORE, 140469495173120, 140469495177215,
+STORE, 140732281446400, 140732281585663,
+STORE, 140732282736640, 140732282748927,
+STORE, 140732282748928, 140732282753023,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723411931136, 140737488351231,
+SNULL, 140723411939327, 140737488351231,
+STORE, 140723411931136, 140723411939327,
+STORE, 140723411800064, 140723411939327,
+STORE, 93993768685568, 93993770909695,
+SNULL, 93993768796159, 93993770909695,
+STORE, 93993768685568, 93993768796159,
+STORE, 93993768796160, 93993770909695,
+ERASE, 93993768796160, 93993770909695,
+STORE, 93993770889216, 93993770901503,
+STORE, 93993770901504, 93993770909695,
+STORE, 140508681740288, 140508683993087,
+SNULL, 140508681883647, 140508683993087,
+STORE, 140508681740288, 140508681883647,
+STORE, 140508681883648, 140508683993087,
+ERASE, 140508681883648, 140508683993087,
+STORE, 140508683980800, 140508683988991,
+STORE, 140508683988992, 140508683993087,
+STORE, 140723412070400, 140723412074495,
+STORE, 140723412058112, 140723412070399,
+STORE, 140508683952128, 140508683980799,
+STORE, 140508683943936, 140508683952127,
+STORE, 140508677943296, 140508681740287,
+SNULL, 140508677943296, 140508679602175,
+STORE, 140508679602176, 140508681740287,
+STORE, 140508677943296, 140508679602175,
+SNULL, 140508681699327, 140508681740287,
+STORE, 140508679602176, 140508681699327,
+STORE, 140508681699328, 140508681740287,
+SNULL, 140508681699328, 140508681723903,
+STORE, 140508681723904, 140508681740287,
+STORE, 140508681699328, 140508681723903,
+ERASE, 140508681699328, 140508681723903,
+STORE, 140508681699328, 140508681723903,
+ERASE, 140508681723904, 140508681740287,
+STORE, 140508681723904, 140508681740287,
+SNULL, 140508681715711, 140508681723903,
+STORE, 140508681699328, 140508681715711,
+STORE, 140508681715712, 140508681723903,
+SNULL, 93993770897407, 93993770901503,
+STORE, 93993770889216, 93993770897407,
+STORE, 93993770897408, 93993770901503,
+SNULL, 140508683984895, 140508683988991,
+STORE, 140508683980800, 140508683984895,
+STORE, 140508683984896, 140508683988991,
+ERASE, 140508683952128, 140508683980799,
+STORE, 93993791582208, 93993791717375,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140734685458432, 140737488351231,
+SNULL, 140734685466623, 140737488351231,
+STORE, 140734685458432, 140734685466623,
+STORE, 140734685327360, 140734685466623,
+STORE, 93832321548288, 93832323772415,
+SNULL, 93832321658879, 93832323772415,
+STORE, 93832321548288, 93832321658879,
+STORE, 93832321658880, 93832323772415,
+ERASE, 93832321658880, 93832323772415,
+STORE, 93832323751936, 93832323764223,
+STORE, 93832323764224, 93832323772415,
+STORE, 140650945118208, 140650947371007,
+SNULL, 140650945261567, 140650947371007,
+STORE, 140650945118208, 140650945261567,
+STORE, 140650945261568, 140650947371007,
+ERASE, 140650945261568, 140650947371007,
+STORE, 140650947358720, 140650947366911,
+STORE, 140650947366912, 140650947371007,
+STORE, 140734686081024, 140734686085119,
+STORE, 140734686068736, 140734686081023,
+STORE, 140650947330048, 140650947358719,
+STORE, 140650947321856, 140650947330047,
+STORE, 140650941321216, 140650945118207,
+SNULL, 140650941321216, 140650942980095,
+STORE, 140650942980096, 140650945118207,
+STORE, 140650941321216, 140650942980095,
+SNULL, 140650945077247, 140650945118207,
+STORE, 140650942980096, 140650945077247,
+STORE, 140650945077248, 140650945118207,
+SNULL, 140650945077248, 140650945101823,
+STORE, 140650945101824, 140650945118207,
+STORE, 140650945077248, 140650945101823,
+ERASE, 140650945077248, 140650945101823,
+STORE, 140650945077248, 140650945101823,
+ERASE, 140650945101824, 140650945118207,
+STORE, 140650945101824, 140650945118207,
+SNULL, 140650945093631, 140650945101823,
+STORE, 140650945077248, 140650945093631,
+STORE, 140650945093632, 140650945101823,
+SNULL, 93832323760127, 93832323764223,
+STORE, 93832323751936, 93832323760127,
+STORE, 93832323760128, 93832323764223,
+SNULL, 140650947362815, 140650947366911,
+STORE, 140650947358720, 140650947362815,
+STORE, 140650947362816, 140650947366911,
+ERASE, 140650947330048, 140650947358719,
+STORE, 93832331890688, 93832332025855,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728333520896, 140737488351231,
+SNULL, 140728333529087, 140737488351231,
+STORE, 140728333520896, 140728333529087,
+STORE, 140728333389824, 140728333529087,
+STORE, 94872734732288, 94872736956415,
+SNULL, 94872734842879, 94872736956415,
+STORE, 94872734732288, 94872734842879,
+STORE, 94872734842880, 94872736956415,
+ERASE, 94872734842880, 94872736956415,
+STORE, 94872736935936, 94872736948223,
+STORE, 94872736948224, 94872736956415,
+STORE, 139755193257984, 139755195510783,
+SNULL, 139755193401343, 139755195510783,
+STORE, 139755193257984, 139755193401343,
+STORE, 139755193401344, 139755195510783,
+ERASE, 139755193401344, 139755195510783,
+STORE, 139755195498496, 139755195506687,
+STORE, 139755195506688, 139755195510783,
+STORE, 140728333926400, 140728333930495,
+STORE, 140728333914112, 140728333926399,
+STORE, 139755195469824, 139755195498495,
+STORE, 139755195461632, 139755195469823,
+STORE, 139755189460992, 139755193257983,
+SNULL, 139755189460992, 139755191119871,
+STORE, 139755191119872, 139755193257983,
+STORE, 139755189460992, 139755191119871,
+SNULL, 139755193217023, 139755193257983,
+STORE, 139755191119872, 139755193217023,
+STORE, 139755193217024, 139755193257983,
+SNULL, 139755193217024, 139755193241599,
+STORE, 139755193241600, 139755193257983,
+STORE, 139755193217024, 139755193241599,
+ERASE, 139755193217024, 139755193241599,
+STORE, 139755193217024, 139755193241599,
+ERASE, 139755193241600, 139755193257983,
+STORE, 139755193241600, 139755193257983,
+SNULL, 139755193233407, 139755193241599,
+STORE, 139755193217024, 139755193233407,
+STORE, 139755193233408, 139755193241599,
+SNULL, 94872736944127, 94872736948223,
+STORE, 94872736935936, 94872736944127,
+STORE, 94872736944128, 94872736948223,
+SNULL, 139755195502591, 139755195506687,
+STORE, 139755195498496, 139755195502591,
+STORE, 139755195502592, 139755195506687,
+ERASE, 139755195469824, 139755195498495,
+STORE, 94872749744128, 94872749879295,
+STORE, 94720243642368, 94720243855359,
+STORE, 94720245952512, 94720245956607,
+STORE, 94720245956608, 94720245964799,
+STORE, 94720245964800, 94720245977087,
+STORE, 94720277745664, 94720278151167,
+STORE, 140453174497280, 140453176156159,
+STORE, 140453176156160, 140453178253311,
+STORE, 140453178253312, 140453178269695,
+STORE, 140453178269696, 140453178277887,
+STORE, 140453178277888, 140453178294271,
+STORE, 140453178294272, 140453178306559,
+STORE, 140453178306560, 140453180399615,
+STORE, 140453180399616, 140453180403711,
+STORE, 140453180403712, 140453180407807,
+STORE, 140453180407808, 140453180551167,
+STORE, 140453180919808, 140453182603263,
+STORE, 140453182603264, 140453182619647,
+STORE, 140453182648320, 140453182652415,
+STORE, 140453182652416, 140453182656511,
+STORE, 140453182656512, 140453182660607,
+STORE, 140733223923712, 140733224062975,
+STORE, 140733224808448, 140733224820735,
+STORE, 140733224820736, 140733224824831,
+STORE, 94321091141632, 94321091354623,
+STORE, 94321093451776, 94321093455871,
+STORE, 94321093455872, 94321093464063,
+STORE, 94321093464064, 94321093476351,
+STORE, 94321115873280, 94321117229055,
+STORE, 139695978840064, 139695980498943,
+STORE, 139695980498944, 139695982596095,
+STORE, 139695982596096, 139695982612479,
+STORE, 139695982612480, 139695982620671,
+STORE, 139695982620672, 139695982637055,
+STORE, 139695982637056, 139695982649343,
+STORE, 139695982649344, 139695984742399,
+STORE, 139695984742400, 139695984746495,
+STORE, 139695984746496, 139695984750591,
+STORE, 139695984750592, 139695984893951,
+STORE, 139695985262592, 139695986946047,
+STORE, 139695986946048, 139695986962431,
+STORE, 139695986991104, 139695986995199,
+STORE, 139695986995200, 139695986999295,
+STORE, 139695986999296, 139695987003391,
+STORE, 140734650564608, 140734650703871,
+STORE, 140734650785792, 140734650798079,
+STORE, 140734650798080, 140734650802175,
+STORE, 94523438456832, 94523438669823,
+STORE, 94523440766976, 94523440771071,
+STORE, 94523440771072, 94523440779263,
+STORE, 94523440779264, 94523440791551,
+STORE, 94523464544256, 94523465842687,
+STORE, 140453231493120, 140453233151999,
+STORE, 140453233152000, 140453235249151,
+STORE, 140453235249152, 140453235265535,
+STORE, 140453235265536, 140453235273727,
+STORE, 140453235273728, 140453235290111,
+STORE, 140453235290112, 140453235302399,
+STORE, 140453235302400, 140453237395455,
+STORE, 140453237395456, 140453237399551,
+STORE, 140453237399552, 140453237403647,
+STORE, 140453237403648, 140453237547007,
+STORE, 140453237915648, 140453239599103,
+STORE, 140453239599104, 140453239615487,
+STORE, 140453239644160, 140453239648255,
+STORE, 140453239648256, 140453239652351,
+STORE, 140453239652352, 140453239656447,
+STORE, 140734679445504, 140734679584767,
+STORE, 140734680018944, 140734680031231,
+STORE, 140734680031232, 140734680035327,
+STORE, 94614776987648, 94614777200639,
+STORE, 94614779297792, 94614779301887,
+STORE, 94614779301888, 94614779310079,
+STORE, 94614779310080, 94614779322367,
+STORE, 94614798467072, 94614800699391,
+STORE, 139677037182976, 139677038841855,
+STORE, 139677038841856, 139677040939007,
+STORE, 139677040939008, 139677040955391,
+STORE, 139677040955392, 139677040963583,
+STORE, 139677040963584, 139677040979967,
+STORE, 139677040979968, 139677040992255,
+STORE, 139677040992256, 139677043085311,
+STORE, 139677043085312, 139677043089407,
+STORE, 139677043089408, 139677043093503,
+STORE, 139677043093504, 139677043236863,
+STORE, 139677043605504, 139677045288959,
+STORE, 139677045288960, 139677045305343,
+STORE, 139677045334016, 139677045338111,
+STORE, 139677045338112, 139677045342207,
+STORE, 139677045342208, 139677045346303,
+STORE, 140721604411392, 140721604550655,
+STORE, 140721606135808, 140721606148095,
+STORE, 140721606148096, 140721606152191,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140729280544768, 140737488351231,
+SNULL, 140729280552959, 140737488351231,
+STORE, 140729280544768, 140729280552959,
+STORE, 140729280413696, 140729280552959,
+STORE, 94863939334144, 94863941558271,
+SNULL, 94863939444735, 94863941558271,
+STORE, 94863939334144, 94863939444735,
+STORE, 94863939444736, 94863941558271,
+ERASE, 94863939444736, 94863941558271,
+STORE, 94863941537792, 94863941550079,
+STORE, 94863941550080, 94863941558271,
+STORE, 139691047276544, 139691049529343,
+SNULL, 139691047419903, 139691049529343,
+STORE, 139691047276544, 139691047419903,
+STORE, 139691047419904, 139691049529343,
+ERASE, 139691047419904, 139691049529343,
+STORE, 139691049517056, 139691049525247,
+STORE, 139691049525248, 139691049529343,
+STORE, 140729281679360, 140729281683455,
+STORE, 140729281667072, 140729281679359,
+STORE, 139691049488384, 139691049517055,
+STORE, 139691049480192, 139691049488383,
+STORE, 139691043479552, 139691047276543,
+SNULL, 139691043479552, 139691045138431,
+STORE, 139691045138432, 139691047276543,
+STORE, 139691043479552, 139691045138431,
+SNULL, 139691047235583, 139691047276543,
+STORE, 139691045138432, 139691047235583,
+STORE, 139691047235584, 139691047276543,
+SNULL, 139691047235584, 139691047260159,
+STORE, 139691047260160, 139691047276543,
+STORE, 139691047235584, 139691047260159,
+ERASE, 139691047235584, 139691047260159,
+STORE, 139691047235584, 139691047260159,
+ERASE, 139691047260160, 139691047276543,
+STORE, 139691047260160, 139691047276543,
+SNULL, 139691047251967, 139691047260159,
+STORE, 139691047235584, 139691047251967,
+STORE, 139691047251968, 139691047260159,
+SNULL, 94863941545983, 94863941550079,
+STORE, 94863941537792, 94863941545983,
+STORE, 94863941545984, 94863941550079,
+SNULL, 139691049521151, 139691049525247,
+STORE, 139691049517056, 139691049521151,
+STORE, 139691049521152, 139691049525247,
+ERASE, 139691049488384, 139691049517055,
+STORE, 94863951294464, 94863951429631,
+STORE, 93998209294336, 93998209507327,
+STORE, 93998211604480, 93998211608575,
+STORE, 93998211608576, 93998211616767,
+STORE, 93998211616768, 93998211629055,
+STORE, 93998227210240, 93998227615743,
+STORE, 140243029913600, 140243031572479,
+STORE, 140243031572480, 140243033669631,
+STORE, 140243033669632, 140243033686015,
+STORE, 140243033686016, 140243033694207,
+STORE, 140243033694208, 140243033710591,
+STORE, 140243033710592, 140243033722879,
+STORE, 140243033722880, 140243035815935,
+STORE, 140243035815936, 140243035820031,
+STORE, 140243035820032, 140243035824127,
+STORE, 140243035824128, 140243035967487,
+STORE, 140243036336128, 140243038019583,
+STORE, 140243038019584, 140243038035967,
+STORE, 140243038064640, 140243038068735,
+STORE, 140243038068736, 140243038072831,
+STORE, 140243038072832, 140243038076927,
+STORE, 140734976479232, 140734976618495,
+STORE, 140734977978368, 140734977990655,
+STORE, 140734977990656, 140734977994751,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722742775808, 140737488351231,
+SNULL, 140722742783999, 140737488351231,
+STORE, 140722742775808, 140722742783999,
+STORE, 140722742644736, 140722742783999,
+STORE, 93857673662464, 93857675997183,
+SNULL, 93857673875455, 93857675997183,
+STORE, 93857673662464, 93857673875455,
+STORE, 93857673875456, 93857675997183,
+ERASE, 93857673875456, 93857675997183,
+STORE, 93857675972608, 93857675984895,
+STORE, 93857675984896, 93857675997183,
+STORE, 140629677498368, 140629679751167,
+SNULL, 140629677641727, 140629679751167,
+STORE, 140629677498368, 140629677641727,
+STORE, 140629677641728, 140629679751167,
+ERASE, 140629677641728, 140629679751167,
+STORE, 140629679738880, 140629679747071,
+STORE, 140629679747072, 140629679751167,
+STORE, 140722743222272, 140722743226367,
+STORE, 140722743209984, 140722743222271,
+STORE, 140629679710208, 140629679738879,
+STORE, 140629679702016, 140629679710207,
+STORE, 140629675384832, 140629677498367,
+SNULL, 140629675384832, 140629675397119,
+STORE, 140629675397120, 140629677498367,
+STORE, 140629675384832, 140629675397119,
+SNULL, 140629677490175, 140629677498367,
+STORE, 140629675397120, 140629677490175,
+STORE, 140629677490176, 140629677498367,
+ERASE, 140629677490176, 140629677498367,
+STORE, 140629677490176, 140629677498367,
+STORE, 140629671587840, 140629675384831,
+SNULL, 140629671587840, 140629673246719,
+STORE, 140629673246720, 140629675384831,
+STORE, 140629671587840, 140629673246719,
+SNULL, 140629675343871, 140629675384831,
+STORE, 140629673246720, 140629675343871,
+STORE, 140629675343872, 140629675384831,
+SNULL, 140629675343872, 140629675368447,
+STORE, 140629675368448, 140629675384831,
+STORE, 140629675343872, 140629675368447,
+ERASE, 140629675343872, 140629675368447,
+STORE, 140629675343872, 140629675368447,
+ERASE, 140629675368448, 140629675384831,
+STORE, 140629675368448, 140629675384831,
+STORE, 140629679693824, 140629679710207,
+SNULL, 140629675360255, 140629675368447,
+STORE, 140629675343872, 140629675360255,
+STORE, 140629675360256, 140629675368447,
+SNULL, 140629677494271, 140629677498367,
+STORE, 140629677490176, 140629677494271,
+STORE, 140629677494272, 140629677498367,
+SNULL, 93857675976703, 93857675984895,
+STORE, 93857675972608, 93857675976703,
+STORE, 93857675976704, 93857675984895,
+SNULL, 140629679742975, 140629679747071,
+STORE, 140629679738880, 140629679742975,
+STORE, 140629679742976, 140629679747071,
+ERASE, 140629679710208, 140629679738879,
+STORE, 93857705832448, 93857705967615,
+STORE, 140629678010368, 140629679693823,
+STORE, 93857705832448, 93857706102783,
+STORE, 93857705832448, 93857706237951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735922421760, 140737488351231,
+SNULL, 140735922429951, 140737488351231,
+STORE, 140735922421760, 140735922429951,
+STORE, 140735922290688, 140735922429951,
+STORE, 94651136139264, 94651138363391,
+SNULL, 94651136249855, 94651138363391,
+STORE, 94651136139264, 94651136249855,
+STORE, 94651136249856, 94651138363391,
+ERASE, 94651136249856, 94651138363391,
+STORE, 94651138342912, 94651138355199,
+STORE, 94651138355200, 94651138363391,
+STORE, 140325788266496, 140325790519295,
+SNULL, 140325788409855, 140325790519295,
+STORE, 140325788266496, 140325788409855,
+STORE, 140325788409856, 140325790519295,
+ERASE, 140325788409856, 140325790519295,
+STORE, 140325790507008, 140325790515199,
+STORE, 140325790515200, 140325790519295,
+STORE, 140735923572736, 140735923576831,
+STORE, 140735923560448, 140735923572735,
+STORE, 140325790478336, 140325790507007,
+STORE, 140325790470144, 140325790478335,
+STORE, 140325784469504, 140325788266495,
+SNULL, 140325784469504, 140325786128383,
+STORE, 140325786128384, 140325788266495,
+STORE, 140325784469504, 140325786128383,
+SNULL, 140325788225535, 140325788266495,
+STORE, 140325786128384, 140325788225535,
+STORE, 140325788225536, 140325788266495,
+SNULL, 140325788225536, 140325788250111,
+STORE, 140325788250112, 140325788266495,
+STORE, 140325788225536, 140325788250111,
+ERASE, 140325788225536, 140325788250111,
+STORE, 140325788225536, 140325788250111,
+ERASE, 140325788250112, 140325788266495,
+STORE, 140325788250112, 140325788266495,
+SNULL, 140325788241919, 140325788250111,
+STORE, 140325788225536, 140325788241919,
+STORE, 140325788241920, 140325788250111,
+SNULL, 94651138351103, 94651138355199,
+STORE, 94651138342912, 94651138351103,
+STORE, 94651138351104, 94651138355199,
+SNULL, 140325790511103, 140325790515199,
+STORE, 140325790507008, 140325790511103,
+STORE, 140325790511104, 140325790515199,
+ERASE, 140325790478336, 140325790507007,
+STORE, 94651146297344, 94651146432511,
+STORE, 94212330168320, 94212330381311,
+STORE, 94212332478464, 94212332482559,
+STORE, 94212332482560, 94212332490751,
+STORE, 94212332490752, 94212332503039,
+STORE, 94212348891136, 94212349825023,
+STORE, 140611630604288, 140611632263167,
+STORE, 140611632263168, 140611634360319,
+STORE, 140611634360320, 140611634376703,
+STORE, 140611634376704, 140611634384895,
+STORE, 140611634384896, 140611634401279,
+STORE, 140611634401280, 140611634413567,
+STORE, 140611634413568, 140611636506623,
+STORE, 140611636506624, 140611636510719,
+STORE, 140611636510720, 140611636514815,
+STORE, 140611636514816, 140611636658175,
+STORE, 140611637026816, 140611638710271,
+STORE, 140611638710272, 140611638726655,
+STORE, 140611638755328, 140611638759423,
+STORE, 140611638759424, 140611638763519,
+STORE, 140611638763520, 140611638767615,
+STORE, 140726974533632, 140726974672895,
+STORE, 140726974943232, 140726974955519,
+STORE, 140726974955520, 140726974959615,
+STORE, 94572463521792, 94572463734783,
+STORE, 94572465831936, 94572465836031,
+STORE, 94572465836032, 94572465844223,
+STORE, 94572465844224, 94572465856511,
+STORE, 94572491534336, 94572492865535,
+STORE, 140644351492096, 140644353150975,
+STORE, 140644353150976, 140644355248127,
+STORE, 140644355248128, 140644355264511,
+STORE, 140644355264512, 140644355272703,
+STORE, 140644355272704, 140644355289087,
+STORE, 140644355289088, 140644355301375,
+STORE, 140644355301376, 140644357394431,
+STORE, 140644357394432, 140644357398527,
+STORE, 140644357398528, 140644357402623,
+STORE, 140644357402624, 140644357545983,
+STORE, 140644357914624, 140644359598079,
+STORE, 140644359598080, 140644359614463,
+STORE, 140644359643136, 140644359647231,
+STORE, 140644359647232, 140644359651327,
+STORE, 140644359651328, 140644359655423,
+STORE, 140727841824768, 140727841964031,
+STORE, 140727843188736, 140727843201023,
+STORE, 140727843201024, 140727843205119,
+STORE, 94144315457536, 94144315670527,
+STORE, 94144317767680, 94144317771775,
+STORE, 94144317771776, 94144317779967,
+STORE, 94144317779968, 94144317792255,
+STORE, 94144318369792, 94144320815103,
+STORE, 140316717645824, 140316719304703,
+STORE, 140316719304704, 140316721401855,
+STORE, 140316721401856, 140316721418239,
+STORE, 140316721418240, 140316721426431,
+STORE, 140316721426432, 140316721442815,
+STORE, 140316721442816, 140316721455103,
+STORE, 140316721455104, 140316723548159,
+STORE, 140316723548160, 140316723552255,
+STORE, 140316723552256, 140316723556351,
+STORE, 140316723556352, 140316723699711,
+STORE, 140316724068352, 140316725751807,
+STORE, 140316725751808, 140316725768191,
+STORE, 140316725796864, 140316725800959,
+STORE, 140316725800960, 140316725805055,
+STORE, 140316725805056, 140316725809151,
+STORE, 140725744283648, 140725744422911,
+STORE, 140725745852416, 140725745864703,
+STORE, 140725745864704, 140725745868799,
+STORE, 94646858846208, 94646859059199,
+STORE, 94646861156352, 94646861160447,
+STORE, 94646861160448, 94646861168639,
+STORE, 94646861168640, 94646861180927,
+STORE, 94646879805440, 94646881894399,
+STORE, 140435449745408, 140435451404287,
+STORE, 140435451404288, 140435453501439,
+STORE, 140435453501440, 140435453517823,
+STORE, 140435453517824, 140435453526015,
+STORE, 140435453526016, 140435453542399,
+STORE, 140435453542400, 140435453554687,
+STORE, 140435453554688, 140435455647743,
+STORE, 140435455647744, 140435455651839,
+STORE, 140435455651840, 140435455655935,
+STORE, 140435455655936, 140435455799295,
+STORE, 140435456167936, 140435457851391,
+STORE, 140435457851392, 140435457867775,
+STORE, 140435457896448, 140435457900543,
+STORE, 140435457900544, 140435457904639,
+STORE, 140435457904640, 140435457908735,
+STORE, 140721033818112, 140721033957375,
+STORE, 140721034018816, 140721034031103,
+STORE, 140721034031104, 140721034035199,
+STORE, 94872903438336, 94872903651327,
+STORE, 94872905748480, 94872905752575,
+STORE, 94872905752576, 94872905760767,
+STORE, 94872905760768, 94872905773055,
+STORE, 94872931246080, 94872931651583,
+STORE, 139771607810048, 139771609468927,
+STORE, 139771609468928, 139771611566079,
+STORE, 139771611566080, 139771611582463,
+STORE, 139771611582464, 139771611590655,
+STORE, 139771611590656, 139771611607039,
+STORE, 139771611607040, 139771611619327,
+STORE, 139771611619328, 139771613712383,
+STORE, 139771613712384, 139771613716479,
+STORE, 139771613716480, 139771613720575,
+STORE, 139771613720576, 139771613863935,
+STORE, 139771614232576, 139771615916031,
+STORE, 139771615916032, 139771615932415,
+STORE, 139771615961088, 139771615965183,
+STORE, 139771615965184, 139771615969279,
+STORE, 139771615969280, 139771615973375,
+STORE, 140725402931200, 140725403070463,
+STORE, 140725403852800, 140725403865087,
+STORE, 140725403865088, 140725403869183,
+STORE, 94740737736704, 94740737949695,
+STORE, 94740740046848, 94740740050943,
+STORE, 94740740050944, 94740740059135,
+STORE, 94740740059136, 94740740071423,
+STORE, 94740743249920, 94740744724479,
+STORE, 140640287010816, 140640288669695,
+STORE, 140640288669696, 140640290766847,
+STORE, 140640290766848, 140640290783231,
+STORE, 140640290783232, 140640290791423,
+STORE, 140640290791424, 140640290807807,
+STORE, 140640290807808, 140640290820095,
+STORE, 140640290820096, 140640292913151,
+STORE, 140640292913152, 140640292917247,
+STORE, 140640292917248, 140640292921343,
+STORE, 140640292921344, 140640293064703,
+STORE, 140640293433344, 140640295116799,
+STORE, 140640295116800, 140640295133183,
+STORE, 140640295161856, 140640295165951,
+STORE, 140640295165952, 140640295170047,
+STORE, 140640295170048, 140640295174143,
+STORE, 140725133303808, 140725133443071,
+STORE, 140725133684736, 140725133697023,
+STORE, 140725133697024, 140725133701119,
+STORE, 140737488347136, 140737488351231,
+STORE, 140722826371072, 140737488351231,
+SNULL, 140722826375167, 140737488351231,
+STORE, 140722826371072, 140722826375167,
+STORE, 140722826240000, 140722826375167,
+STORE, 94113818611712, 94113820835839,
+SNULL, 94113818722303, 94113820835839,
+STORE, 94113818611712, 94113818722303,
+STORE, 94113818722304, 94113820835839,
+ERASE, 94113818722304, 94113820835839,
+STORE, 94113820815360, 94113820827647,
+STORE, 94113820827648, 94113820835839,
+STORE, 139628194508800, 139628196761599,
+SNULL, 139628194652159, 139628196761599,
+STORE, 139628194508800, 139628194652159,
+STORE, 139628194652160, 139628196761599,
+ERASE, 139628194652160, 139628196761599,
+STORE, 139628196749312, 139628196757503,
+STORE, 139628196757504, 139628196761599,
+STORE, 140722826727424, 140722826731519,
+STORE, 140722826715136, 140722826727423,
+STORE, 139628196720640, 139628196749311,
+STORE, 139628196712448, 139628196720639,
+STORE, 139628190711808, 139628194508799,
+SNULL, 139628190711808, 139628192370687,
+STORE, 139628192370688, 139628194508799,
+STORE, 139628190711808, 139628192370687,
+SNULL, 139628194467839, 139628194508799,
+STORE, 139628192370688, 139628194467839,
+STORE, 139628194467840, 139628194508799,
+SNULL, 139628194467840, 139628194492415,
+STORE, 139628194492416, 139628194508799,
+STORE, 139628194467840, 139628194492415,
+ERASE, 139628194467840, 139628194492415,
+STORE, 139628194467840, 139628194492415,
+ERASE, 139628194492416, 139628194508799,
+STORE, 139628194492416, 139628194508799,
+SNULL, 139628194484223, 139628194492415,
+STORE, 139628194467840, 139628194484223,
+STORE, 139628194484224, 139628194492415,
+SNULL, 94113820823551, 94113820827647,
+STORE, 94113820815360, 94113820823551,
+STORE, 94113820823552, 94113820827647,
+SNULL, 139628196753407, 139628196757503,
+STORE, 139628196749312, 139628196753407,
+STORE, 139628196753408, 139628196757503,
+ERASE, 139628196720640, 139628196749311,
+STORE, 94113830850560, 94113830985727,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731865833472, 140737488351231,
+SNULL, 140731865841663, 140737488351231,
+STORE, 140731865833472, 140731865841663,
+STORE, 140731865702400, 140731865841663,
+STORE, 94763339386880, 94763341611007,
+SNULL, 94763339497471, 94763341611007,
+STORE, 94763339386880, 94763339497471,
+STORE, 94763339497472, 94763341611007,
+ERASE, 94763339497472, 94763341611007,
+STORE, 94763341590528, 94763341602815,
+STORE, 94763341602816, 94763341611007,
+STORE, 139778398486528, 139778400739327,
+SNULL, 139778398629887, 139778400739327,
+STORE, 139778398486528, 139778398629887,
+STORE, 139778398629888, 139778400739327,
+ERASE, 139778398629888, 139778400739327,
+STORE, 139778400727040, 139778400735231,
+STORE, 139778400735232, 139778400739327,
+STORE, 140731865858048, 140731865862143,
+STORE, 140731865845760, 140731865858047,
+STORE, 139778400698368, 139778400727039,
+STORE, 139778400690176, 139778400698367,
+STORE, 139778394689536, 139778398486527,
+SNULL, 139778394689536, 139778396348415,
+STORE, 139778396348416, 139778398486527,
+STORE, 139778394689536, 139778396348415,
+SNULL, 139778398445567, 139778398486527,
+STORE, 139778396348416, 139778398445567,
+STORE, 139778398445568, 139778398486527,
+SNULL, 139778398445568, 139778398470143,
+STORE, 139778398470144, 139778398486527,
+STORE, 139778398445568, 139778398470143,
+ERASE, 139778398445568, 139778398470143,
+STORE, 139778398445568, 139778398470143,
+ERASE, 139778398470144, 139778398486527,
+STORE, 139778398470144, 139778398486527,
+SNULL, 139778398461951, 139778398470143,
+STORE, 139778398445568, 139778398461951,
+STORE, 139778398461952, 139778398470143,
+SNULL, 94763341598719, 94763341602815,
+STORE, 94763341590528, 94763341598719,
+STORE, 94763341598720, 94763341602815,
+SNULL, 139778400731135, 139778400735231,
+STORE, 139778400727040, 139778400731135,
+STORE, 139778400731136, 139778400735231,
+ERASE, 139778400698368, 139778400727039,
+STORE, 94763362197504, 94763362332671,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140737488338944, 140737488351231,
+STORE, 140732053192704, 140737488351231,
+SNULL, 140732053204991, 140737488351231,
+STORE, 140732053192704, 140732053204991,
+STORE, 140732053061632, 140732053204991,
+STORE, 4194304, 26279935,
+STORE, 28372992, 28454911,
+STORE, 28454912, 29806591,
+STORE, 140176018599936, 140176020852735,
+SNULL, 140176018743295, 140176020852735,
+STORE, 140176018599936, 140176018743295,
+STORE, 140176018743296, 140176020852735,
+ERASE, 140176018743296, 140176020852735,
+STORE, 140176020840448, 140176020848639,
+STORE, 140176020848640, 140176020852735,
+STORE, 140732053381120, 140732053385215,
+STORE, 140732053368832, 140732053381119,
+STORE, 140176020811776, 140176020840447,
+STORE, 140176020803584, 140176020811775,
+STORE, 140176014766080, 140176018599935,
+SNULL, 140176014766080, 140176016474111,
+STORE, 140176016474112, 140176018599935,
+STORE, 140176014766080, 140176016474111,
+SNULL, 140176018567167, 140176018599935,
+STORE, 140176016474112, 140176018567167,
+STORE, 140176018567168, 140176018599935,
+ERASE, 140176018567168, 140176018599935,
+STORE, 140176018567168, 140176018599935,
+STORE, 140176012570624, 140176014766079,
+SNULL, 140176012570624, 140176012664831,
+STORE, 140176012664832, 140176014766079,
+STORE, 140176012570624, 140176012664831,
+SNULL, 140176014757887, 140176014766079,
+STORE, 140176012664832, 140176014757887,
+STORE, 140176014757888, 140176014766079,
+ERASE, 140176014757888, 140176014766079,
+STORE, 140176014757888, 140176014766079,
+STORE, 140176010051584, 140176012570623,
+SNULL, 140176010051584, 140176010465279,
+STORE, 140176010465280, 140176012570623,
+STORE, 140176010051584, 140176010465279,
+SNULL, 140176012558335, 140176012570623,
+STORE, 140176010465280, 140176012558335,
+STORE, 140176012558336, 140176012570623,
+ERASE, 140176012558336, 140176012570623,
+STORE, 140176012558336, 140176012570623,
+STORE, 140176007417856, 140176010051583,
+SNULL, 140176007417856, 140176007946239,
+STORE, 140176007946240, 140176010051583,
+STORE, 140176007417856, 140176007946239,
+SNULL, 140176010043391, 140176010051583,
+STORE, 140176007946240, 140176010043391,
+STORE, 140176010043392, 140176010051583,
+ERASE, 140176010043392, 140176010051583,
+STORE, 140176010043392, 140176010051583,
+STORE, 140176005304320, 140176007417855,
+SNULL, 140176005304320, 140176005316607,
+STORE, 140176005316608, 140176007417855,
+STORE, 140176005304320, 140176005316607,
+SNULL, 140176007409663, 140176007417855,
+STORE, 140176005316608, 140176007409663,
+STORE, 140176007409664, 140176007417855,
+ERASE, 140176007409664, 140176007417855,
+STORE, 140176007409664, 140176007417855,
+STORE, 140176003100672, 140176005304319,
+SNULL, 140176003100672, 140176003203071,
+STORE, 140176003203072, 140176005304319,
+STORE, 140176003100672, 140176003203071,
+SNULL, 140176005296127, 140176005304319,
+STORE, 140176003203072, 140176005296127,
+STORE, 140176005296128, 140176005304319,
+ERASE, 140176005296128, 140176005304319,
+STORE, 140176005296128, 140176005304319,
+STORE, 140176020795392, 140176020811775,
+STORE, 140175999938560, 140176003100671,
+SNULL, 140175999938560, 140176000999423,
+STORE, 140176000999424, 140176003100671,
+STORE, 140175999938560, 140176000999423,
+SNULL, 140176003092479, 140176003100671,
+STORE, 140176000999424, 140176003092479,
+STORE, 140176003092480, 140176003100671,
+ERASE, 140176003092480, 140176003100671,
+STORE, 140176003092480, 140176003100671,
+STORE, 140175996141568, 140175999938559,
+SNULL, 140175996141568, 140175997800447,
+STORE, 140175997800448, 140175999938559,
+STORE, 140175996141568, 140175997800447,
+SNULL, 140175999897599, 140175999938559,
+STORE, 140175997800448, 140175999897599,
+STORE, 140175999897600, 140175999938559,
+SNULL, 140175999897600, 140175999922175,
+STORE, 140175999922176, 140175999938559,
+STORE, 140175999897600, 140175999922175,
+ERASE, 140175999897600, 140175999922175,
+STORE, 140175999897600, 140175999922175,
+ERASE, 140175999922176, 140175999938559,
+STORE, 140175999922176, 140175999938559,
+STORE, 140176020783104, 140176020811775,
+SNULL, 140175999913983, 140175999922175,
+STORE, 140175999897600, 140175999913983,
+STORE, 140175999913984, 140175999922175,
+SNULL, 140176003096575, 140176003100671,
+STORE, 140176003092480, 140176003096575,
+STORE, 140176003096576, 140176003100671,
+SNULL, 140176005300223, 140176005304319,
+STORE, 140176005296128, 140176005300223,
+STORE, 140176005300224, 140176005304319,
+SNULL, 140176007413759, 140176007417855,
+STORE, 140176007409664, 140176007413759,
+STORE, 140176007413760, 140176007417855,
+SNULL, 140176010047487, 140176010051583,
+STORE, 140176010043392, 140176010047487,
+STORE, 140176010047488, 140176010051583,
+SNULL, 140176012566527, 140176012570623,
+STORE, 140176012558336, 140176012566527,
+STORE, 140176012566528, 140176012570623,
+SNULL, 140176014761983, 140176014766079,
+STORE, 140176014757888, 140176014761983,
+STORE, 140176014761984, 140176014766079,
+SNULL, 140176018571263, 140176018599935,
+STORE, 140176018567168, 140176018571263,
+STORE, 140176018571264, 140176018599935,
+SNULL, 28405759, 28454911,
+STORE, 28372992, 28405759,
+STORE, 28405760, 28454911,
+SNULL, 140176020844543, 140176020848639,
+STORE, 140176020840448, 140176020844543,
+STORE, 140176020844544, 140176020848639,
+ERASE, 140176020811776, 140176020840447,
+STORE, 53080064, 53215231,
+STORE, 140176019099648, 140176020783103,
+STORE, 140176020836352, 140176020840447,
+STORE, 140176018964480, 140176019099647,
+STORE, 53080064, 53358591,
+STORE, 140175994044416, 140175996141567,
+STORE, 140176020828160, 140176020840447,
+STORE, 140176020819968, 140176020840447,
+STORE, 140176020783104, 140176020819967,
+STORE, 140176018948096, 140176019099647,
+STORE, 53080064, 53493759,
+STORE, 53080064, 53649407,
+STORE, 140176018939904, 140176019099647,
+STORE, 140176018931712, 140176019099647,
+STORE, 53080064, 53784575,
+STORE, 53080064, 53919743,
+STORE, 140176018915328, 140176019099647,
+STORE, 140176018907136, 140176019099647,
+STORE, 53080064, 54059007,
+STORE, 140175993769984, 140175996141567,
+STORE, 140176018747392, 140176019099647,
+STORE, 53080064, 54198271,
+SNULL, 54190079, 54198271,
+STORE, 53080064, 54190079,
+STORE, 54190080, 54198271,
+ERASE, 54190080, 54198271,
+SNULL, 54181887, 54190079,
+STORE, 53080064, 54181887,
+STORE, 54181888, 54190079,
+ERASE, 54181888, 54190079,
+SNULL, 54173695, 54181887,
+STORE, 53080064, 54173695,
+STORE, 54173696, 54181887,
+ERASE, 54173696, 54181887,
+SNULL, 54165503, 54173695,
+STORE, 53080064, 54165503,
+STORE, 54165504, 54173695,
+ERASE, 54165504, 54173695,
+STORE, 140175993753600, 140175996141567,
+STORE, 140175993688064, 140175996141567,
+STORE, 140175993655296, 140175996141567,
+STORE, 140175991558144, 140175996141567,
+STORE, 140175991492608, 140175996141567,
+STORE, 53080064, 54312959,
+STORE, 140175991361536, 140175996141567,
+STORE, 140175991099392, 140175996141567,
+STORE, 140175991091200, 140175996141567,
+STORE, 140175991074816, 140175996141567,
+STORE, 140175991066624, 140175996141567,
+STORE, 140175991058432, 140175996141567,
+STORE, 53080064, 54448127,
+SNULL, 54439935, 54448127,
+STORE, 53080064, 54439935,
+STORE, 54439936, 54448127,
+ERASE, 54439936, 54448127,
+SNULL, 54431743, 54439935,
+STORE, 53080064, 54431743,
+STORE, 54431744, 54439935,
+ERASE, 54431744, 54439935,
+SNULL, 54419455, 54431743,
+STORE, 53080064, 54419455,
+STORE, 54419456, 54431743,
+ERASE, 54419456, 54431743,
+SNULL, 54403071, 54419455,
+STORE, 53080064, 54403071,
+STORE, 54403072, 54419455,
+ERASE, 54403072, 54419455,
+STORE, 140175991042048, 140175996141567,
+STORE, 53080064, 54538239,
+SNULL, 54534143, 54538239,
+STORE, 53080064, 54534143,
+STORE, 54534144, 54538239,
+ERASE, 54534144, 54538239,
+SNULL, 54530047, 54534143,
+STORE, 53080064, 54530047,
+STORE, 54530048, 54534143,
+ERASE, 54530048, 54534143,
+SNULL, 54525951, 54530047,
+STORE, 53080064, 54525951,
+STORE, 54525952, 54530047,
+ERASE, 54525952, 54530047,
+SNULL, 54521855, 54525951,
+STORE, 53080064, 54521855,
+STORE, 54521856, 54525951,
+ERASE, 54521856, 54525951,
+SNULL, 54517759, 54521855,
+STORE, 53080064, 54517759,
+STORE, 54517760, 54521855,
+ERASE, 54517760, 54521855,
+SNULL, 54513663, 54517759,
+STORE, 53080064, 54513663,
+STORE, 54513664, 54517759,
+ERASE, 54513664, 54517759,
+SNULL, 54509567, 54513663,
+STORE, 53080064, 54509567,
+STORE, 54509568, 54513663,
+ERASE, 54509568, 54513663,
+STORE, 140175991025664, 140175996141567,
+STORE, 140175990992896, 140175996141567,
+STORE, 53080064, 54644735,
+SNULL, 54628351, 54644735,
+STORE, 53080064, 54628351,
+STORE, 54628352, 54644735,
+ERASE, 54628352, 54644735,
+SNULL, 54616063, 54628351,
+STORE, 53080064, 54616063,
+STORE, 54616064, 54628351,
+ERASE, 54616064, 54628351,
+STORE, 140175988895744, 140175996141567,
+STORE, 53080064, 54767615,
+STORE, 140175988879360, 140175996141567,
+STORE, 140175988617216, 140175996141567,
+STORE, 140175988609024, 140175996141567,
+STORE, 140175988600832, 140175996141567,
+STORE, 53080064, 54906879,
+SNULL, 54898687, 54906879,
+STORE, 53080064, 54898687,
+STORE, 54898688, 54906879,
+ERASE, 54898688, 54906879,
+SNULL, 54853631, 54898687,
+STORE, 53080064, 54853631,
+STORE, 54853632, 54898687,
+ERASE, 54853632, 54898687,
+STORE, 140175986503680, 140175996141567,
+STORE, 53080064, 54996991,
+STORE, 140175986495488, 140175996141567,
+STORE, 140175986487296, 140175996141567,
+STORE, 140175985438720, 140175996141567,
+STORE, 53080064, 55136255,
+STORE, 140175985405952, 140175996141567,
+STORE, 140175985139712, 140175996141567,
+SNULL, 140176018964479, 140176019099647,
+STORE, 140176018747392, 140176018964479,
+STORE, 140176018964480, 140176019099647,
+ERASE, 140176018964480, 140176019099647,
+STORE, 140175983042560, 140175996141567,
+STORE, 140175982518272, 140175996141567,
+STORE, 140175980421120, 140175996141567,
+STORE, 53080064, 55287807,
+STORE, 53080064, 55427071,
+STORE, 140176019091456, 140176019099647,
+STORE, 140176019083264, 140176019099647,
+STORE, 140176019075072, 140176019099647,
+STORE, 140176019066880, 140176019099647,
+STORE, 140176019058688, 140176019099647,
+STORE, 140175980158976, 140175996141567,
+STORE, 140176019050496, 140176019099647,
+STORE, 140176019042304, 140176019099647,
+STORE, 140176019034112, 140176019099647,
+STORE, 140176019025920, 140176019099647,
+STORE, 140176019017728, 140176019099647,
+STORE, 140176019009536, 140176019099647,
+STORE, 140176019001344, 140176019099647,
+STORE, 140176018993152, 140176019099647,
+STORE, 140176018984960, 140176019099647,
+STORE, 140176018976768, 140176019099647,
+STORE, 140176018968576, 140176019099647,
+STORE, 140175978061824, 140175996141567,
+STORE, 53080064, 55603199,
+STORE, 140175978029056, 140175996141567,
+STORE, 140175977996288, 140175996141567,
+STORE, 53080064, 55738367,
+STORE, 53080064, 55881727,
+STORE, 140175977963520, 140175996141567,
+STORE, 140175977930752, 140175996141567,
+STORE, 53080064, 56041471,
+STORE, 140175977897984, 140175996141567,
+STORE, 140175977865216, 140175996141567,
+SNULL, 55881727, 56041471,
+STORE, 53080064, 55881727,
+STORE, 55881728, 56041471,
+ERASE, 55881728, 56041471,
+SNULL, 55721983, 55881727,
+STORE, 53080064, 55721983,
+STORE, 55721984, 55881727,
+ERASE, 55721984, 55881727,
+SNULL, 55570431, 55721983,
+STORE, 53080064, 55570431,
+STORE, 55570432, 55721983,
+ERASE, 55570432, 55721983,
+STORE, 140175977857024, 140175996141567,
+STORE, 140175975759872, 140175996141567,
+STORE, 53080064, 55754751,
+STORE, 53080064, 55943167,
+STORE, 140175975751680, 140175996141567,
+STORE, 140175975743488, 140175996141567,
+STORE, 140175975735296, 140175996141567,
+STORE, 140175975727104, 140175996141567,
+STORE, 140175975718912, 140175996141567,
+STORE, 140175975710720, 140175996141567,
+STORE, 140175975702528, 140175996141567,
+STORE, 140175975694336, 140175996141567,
+STORE, 140175975686144, 140175996141567,
+STORE, 140175975677952, 140175996141567,
+STORE, 140175975669760, 140175996141567,
+STORE, 140175974621184, 140175996141567,
+STORE, 140175974612992, 140175996141567,
+STORE, 53080064, 56139775,
+STORE, 140175972515840, 140175996141567,
+STORE, 53080064, 56401919,
+STORE, 140175970418688, 140175996141567,
+STORE, 140175970410496, 140175996141567,
+STORE, 140175970402304, 140175996141567,
+STORE, 140175970394112, 140175996141567,
+STORE, 53080064, 56569855,
+STORE, 140175969865728, 140175996141567,
+SNULL, 140175985139711, 140175996141567,
+STORE, 140175969865728, 140175985139711,
+STORE, 140175985139712, 140175996141567,
+SNULL, 140175985139712, 140175985405951,
+STORE, 140175985405952, 140175996141567,
+STORE, 140175985139712, 140175985405951,
+ERASE, 140175985139712, 140175985405951,
+STORE, 140175965671424, 140175985139711,
+STORE, 140175985397760, 140175996141567,
+STORE, 140175985389568, 140175996141567,
+STORE, 140175985381376, 140175996141567,
+STORE, 140175985373184, 140175996141567,
+STORE, 140175985364992, 140175996141567,
+STORE, 140175985356800, 140175996141567,
+STORE, 140175985348608, 140175996141567,
+STORE, 140175985340416, 140175996141567,
+STORE, 140175985332224, 140175996141567,
+STORE, 140175985324032, 140175996141567,
+STORE, 140175985315840, 140175996141567,
+STORE, 140175985307648, 140175996141567,
+STORE, 140175985299456, 140175996141567,
+STORE, 140175985291264, 140175996141567,
+STORE, 140175985283072, 140175996141567,
+STORE, 140175985274880, 140175996141567,
+STORE, 140175963574272, 140175985139711,
+STORE, 140175985266688, 140175996141567,
+STORE, 140175961477120, 140175985139711,
+STORE, 53080064, 56831999,
+STORE, 140175959379968, 140175985139711,
+STORE, 140175985258496, 140175996141567,
+STORE, 140175957282816, 140175985139711,
+STORE, 140175985250304, 140175996141567,
+STORE, 140175985242112, 140175996141567,
+STORE, 140175985233920, 140175996141567,
+STORE, 140175985225728, 140175996141567,
+STORE, 140175985217536, 140175996141567,
+STORE, 140175957151744, 140175985139711,
+STORE, 140175956627456, 140175985139711,
+SNULL, 140175980158975, 140175985139711,
+STORE, 140175956627456, 140175980158975,
+STORE, 140175980158976, 140175985139711,
+SNULL, 140175980158976, 140175980421119,
+STORE, 140175980421120, 140175985139711,
+STORE, 140175980158976, 140175980421119,
+ERASE, 140175980158976, 140175980421119,
+STORE, 140175954530304, 140175980158975,
+STORE, 140175985209344, 140175996141567,
+STORE, 53080064, 57094143,
+STORE, 140175952433152, 140175980158975,
+STORE, 140175985192960, 140175996141567,
+STORE, 140175985184768, 140175996141567,
+STORE, 140175985176576, 140175996141567,
+STORE, 140175985168384, 140175996141567,
+STORE, 140175985160192, 140175996141567,
+STORE, 140175985152000, 140175996141567,
+STORE, 140175985143808, 140175996141567,
+STORE, 140175980412928, 140175985139711,
+STORE, 140175980404736, 140175985139711,
+STORE, 140175980396544, 140175985139711,
+STORE, 140175980388352, 140175985139711,
+STORE, 140175980380160, 140175985139711,
+STORE, 140175980371968, 140175985139711,
+STORE, 140175980363776, 140175985139711,
+STORE, 140175980355584, 140175985139711,
+STORE, 140175980347392, 140175985139711,
+STORE, 140175980339200, 140175985139711,
+STORE, 53080064, 57356287,
+SNULL, 140176018747392, 140176018907135,
+STORE, 140176018907136, 140176018964479,
+STORE, 140176018747392, 140176018907135,
+ERASE, 140176018747392, 140176018907135,
+STORE, 140175952146432, 140175980158975,
+STORE, 140175950049280, 140175980158975,
+SNULL, 140175952146431, 140175980158975,
+STORE, 140175950049280, 140175952146431,
+STORE, 140175952146432, 140175980158975,
+SNULL, 140175952146432, 140175952433151,
+STORE, 140175952433152, 140175980158975,
+STORE, 140175952146432, 140175952433151,
+ERASE, 140175952146432, 140175952433151,
+STORE, 140176018898944, 140176018964479,
+STORE, 53080064, 57749503,
+STORE, 140175949520896, 140175952146431,
+STORE, 140175947423744, 140175952146431,
+SNULL, 140175993769983, 140175996141567,
+STORE, 140175985143808, 140175993769983,
+STORE, 140175993769984, 140175996141567,
+SNULL, 140175993769984, 140175994044415,
+STORE, 140175994044416, 140175996141567,
+STORE, 140175993769984, 140175994044415,
+ERASE, 140175993769984, 140175994044415,
+STORE, 140176018890752, 140176018964479,
+STORE, 140176018882560, 140176018964479,
+STORE, 140176018874368, 140176018964479,
+STORE, 140176018866176, 140176018964479,
+STORE, 140176018849792, 140176018964479,
+STORE, 140176018841600, 140176018964479,
+STORE, 140176018825216, 140176018964479,
+STORE, 140176018817024, 140176018964479,
+STORE, 140176018800640, 140176018964479,
+STORE, 140176018792448, 140176018964479,
+STORE, 140176018759680, 140176018964479,
+STORE, 140176018751488, 140176018964479,
+STORE, 140175994028032, 140175996141567,
+STORE, 140176018743296, 140176018964479,
+STORE, 140175994011648, 140175996141567,
+STORE, 140175994003456, 140175996141567,
+STORE, 140175993987072, 140175996141567,
+STORE, 140175993978880, 140175996141567,
+STORE, 140175993946112, 140175996141567,
+STORE, 140175993937920, 140175996141567,
+STORE, 140175993921536, 140175996141567,
+STORE, 140175993913344, 140175996141567,
+STORE, 140175993896960, 140175996141567,
+STORE, 140175993888768, 140175996141567,
+STORE, 140175993872384, 140175996141567,
+STORE, 140175993864192, 140175996141567,
+STORE, 140175993831424, 140175996141567,
+STORE, 140175993823232, 140175996141567,
+STORE, 140175993806848, 140175996141567,
+STORE, 140175993798656, 140175996141567,
+STORE, 140175993782272, 140175996141567,
+STORE, 140175993774080, 140175996141567,
+STORE, 140175980322816, 140175985139711,
+STORE, 140175980314624, 140175985139711,
+STORE, 140175980281856, 140175985139711,
+STORE, 140175980273664, 140175985139711,
+STORE, 140175980257280, 140175985139711,
+STORE, 140175945326592, 140175952146431,
+STORE, 140175980249088, 140175985139711,
+STORE, 140175980232704, 140175985139711,
+STORE, 140175980224512, 140175985139711,
+STORE, 140175980208128, 140175985139711,
+STORE, 140175980199936, 140175985139711,
+STORE, 140175980167168, 140175985139711,
+STORE, 140175952433152, 140175985139711,
+STORE, 140175952416768, 140175985139711,
+STORE, 140175952408576, 140175985139711,
+STORE, 140175952392192, 140175985139711,
+STORE, 140175952384000, 140175985139711,
+STORE, 140175952367616, 140175985139711,
+STORE, 140175943229440, 140175952146431,
+STORE, 140175952359424, 140175985139711,
+STORE, 140175952326656, 140175985139711,
+STORE, 140175952318464, 140175985139711,
+STORE, 140175952302080, 140175985139711,
+STORE, 140175952293888, 140175985139711,
+STORE, 140175952277504, 140175985139711,
+STORE, 140175952269312, 140175985139711,
+STORE, 140175952252928, 140175985139711,
+STORE, 140175952244736, 140175985139711,
+STORE, 140175952211968, 140175985139711,
+STORE, 140175952203776, 140175985139711,
+STORE, 140175952187392, 140175985139711,
+STORE, 140175952179200, 140175985139711,
+STORE, 140175952162816, 140175985139711,
+STORE, 140175952154624, 140175985139711,
+STORE, 140175943213056, 140175952146431,
+STORE, 140175943213056, 140175985139711,
+STORE, 140175943180288, 140175985139711,
+STORE, 140175943172096, 140175985139711,
+STORE, 140175943155712, 140175985139711,
+STORE, 140175943147520, 140175985139711,
+STORE, 140175943131136, 140175985139711,
+STORE, 140175943122944, 140175985139711,
+STORE, 140175943106560, 140175985139711,
+STORE, 140175943098368, 140175985139711,
+STORE, 140175943065600, 140175985139711,
+STORE, 140175943057408, 140175985139711,
+STORE, 140175943041024, 140175985139711,
+STORE, 140175943032832, 140175985139711,
+STORE, 140175943016448, 140175985139711,
+STORE, 140175943008256, 140175985139711,
+STORE, 140175942991872, 140175985139711,
+STORE, 140175942983680, 140175985139711,
+STORE, 140175942950912, 140175985139711,
+STORE, 140175942942720, 140175985139711,
+STORE, 140175942926336, 140175985139711,
+STORE, 140175942918144, 140175985139711,
+STORE, 140175942901760, 140175985139711,
+STORE, 140175942893568, 140175985139711,
+STORE, 140175942877184, 140175985139711,
+STORE, 140175942868992, 140175985139711,
+STORE, 140175942836224, 140175985139711,
+STORE, 140175942828032, 140175985139711,
+STORE, 140175942811648, 140175985139711,
+STORE, 140175942803456, 140175985139711,
+STORE, 140175942787072, 140175985139711,
+STORE, 140175942778880, 140175985139711,
+STORE, 140175942762496, 140175985139711,
+STORE, 140175942754304, 140175985139711,
+STORE, 140175942721536, 140175985139711,
+STORE, 140175942713344, 140175985139711,
+STORE, 140175942696960, 140175985139711,
+STORE, 140175942688768, 140175985139711,
+STORE, 140175942672384, 140175985139711,
+STORE, 140175942664192, 140175985139711,
+STORE, 140175942647808, 140175985139711,
+STORE, 140175942639616, 140175985139711,
+STORE, 140175942606848, 140175985139711,
+STORE, 140175942598656, 140175985139711,
+STORE, 140175942582272, 140175985139711,
+STORE, 140175942574080, 140175985139711,
+STORE, 140175942557696, 140175985139711,
+STORE, 140175942549504, 140175985139711,
+STORE, 140175942533120, 140175985139711,
+STORE, 140175942524928, 140175985139711,
+STORE, 140175942492160, 140175985139711,
+STORE, 140175942483968, 140175985139711,
+STORE, 140175942467584, 140175985139711,
+STORE, 140175942459392, 140175985139711,
+STORE, 140175942443008, 140175985139711,
+STORE, 140175942434816, 140175985139711,
+STORE, 140175942418432, 140175985139711,
+STORE, 140175942410240, 140175985139711,
+STORE, 140175942377472, 140175985139711,
+STORE, 140175942369280, 140175985139711,
+STORE, 140175942352896, 140175985139711,
+STORE, 140175942344704, 140175985139711,
+STORE, 140175942328320, 140175985139711,
+STORE, 140175942320128, 140175985139711,
+STORE, 140175942303744, 140175985139711,
+STORE, 140175942295552, 140175985139711,
+STORE, 140175942262784, 140175985139711,
+STORE, 140175942254592, 140175985139711,
+STORE, 140175942238208, 140175985139711,
+STORE, 140175942230016, 140175985139711,
+STORE, 140175942213632, 140175985139711,
+STORE, 140175942205440, 140175985139711,
+STORE, 140175942189056, 140175985139711,
+STORE, 140175942180864, 140175985139711,
+STORE, 140175942148096, 140175985139711,
+STORE, 140175942139904, 140175985139711,
+STORE, 140175942123520, 140175985139711,
+STORE, 140175942115328, 140175985139711,
+STORE, 140175942098944, 140175985139711,
+STORE, 140175942090752, 140175985139711,
+STORE, 140175942074368, 140175985139711,
+STORE, 140175942066176, 140175985139711,
+STORE, 140175942033408, 140175985139711,
+STORE, 140175942025216, 140175985139711,
+STORE, 140175942008832, 140175985139711,
+STORE, 140175942000640, 140175985139711,
+STORE, 140175941984256, 140175985139711,
+STORE, 140175941976064, 140175985139711,
+STORE, 140175941959680, 140175985139711,
+STORE, 140175939862528, 140175985139711,
+STORE, 140175939854336, 140175985139711,
+STORE, 140175939821568, 140175985139711,
+STORE, 140175939813376, 140175985139711,
+STORE, 140175939796992, 140175985139711,
+STORE, 140175939788800, 140175985139711,
+STORE, 140175939772416, 140175985139711,
+STORE, 140175939764224, 140175985139711,
+STORE, 140175939747840, 140175985139711,
+STORE, 140175939739648, 140175985139711,
+STORE, 140175939706880, 140175985139711,
+STORE, 140175939698688, 140175985139711,
+STORE, 140175939682304, 140175985139711,
+STORE, 140175939674112, 140175985139711,
+STORE, 140175939657728, 140175985139711,
+STORE, 140175939649536, 140175985139711,
+STORE, 140175939633152, 140175985139711,
+STORE, 140175939624960, 140175985139711,
+STORE, 140175939592192, 140175985139711,
+STORE, 140175939584000, 140175985139711,
+STORE, 140175939567616, 140175985139711,
+STORE, 140175939559424, 140175985139711,
+STORE, 140175939543040, 140175985139711,
+STORE, 140175939534848, 140175985139711,
+STORE, 140175939518464, 140175985139711,
+STORE, 140175939510272, 140175985139711,
+STORE, 140175939477504, 140175985139711,
+STORE, 140175939469312, 140175985139711,
+STORE, 140175939452928, 140175985139711,
+STORE, 140175939444736, 140175985139711,
+STORE, 140175939428352, 140175985139711,
+STORE, 140175939420160, 140175985139711,
+STORE, 140175939403776, 140175985139711,
+STORE, 140175939395584, 140175985139711,
+STORE, 140175939362816, 140175985139711,
+STORE, 140175939354624, 140175985139711,
+STORE, 140175939338240, 140175985139711,
+STORE, 140175939330048, 140175985139711,
+STORE, 140175939313664, 140175985139711,
+STORE, 140175939305472, 140175985139711,
+STORE, 140175939289088, 140175985139711,
+STORE, 140175939280896, 140175985139711,
+STORE, 140175939248128, 140175985139711,
+STORE, 140175939239936, 140175985139711,
+STORE, 140175939223552, 140175985139711,
+STORE, 140175939215360, 140175985139711,
+STORE, 140175939198976, 140175985139711,
+STORE, 140175939190784, 140175985139711,
+STORE, 140175939174400, 140175985139711,
+STORE, 140175939166208, 140175985139711,
+STORE, 140175939133440, 140175985139711,
+STORE, 140175939125248, 140175985139711,
+STORE, 140175939108864, 140175985139711,
+STORE, 140175939100672, 140175985139711,
+STORE, 140175939084288, 140175985139711,
+STORE, 140175939076096, 140175985139711,
+STORE, 140175939059712, 140175985139711,
+STORE, 140175939051520, 140175985139711,
+STORE, 140175939018752, 140175985139711,
+STORE, 140175939010560, 140175985139711,
+STORE, 140175938994176, 140175985139711,
+STORE, 140175938985984, 140175985139711,
+STORE, 140175938969600, 140175985139711,
+STORE, 140175938961408, 140175985139711,
+STORE, 140175938945024, 140175985139711,
+STORE, 140175938936832, 140175985139711,
+STORE, 140175938904064, 140175985139711,
+STORE, 140175938895872, 140175985139711,
+STORE, 140175938879488, 140175985139711,
+STORE, 140175938871296, 140175985139711,
+STORE, 140175938854912, 140175985139711,
+STORE, 140175938846720, 140175985139711,
+STORE, 140175938830336, 140175985139711,
+STORE, 140175938822144, 140175985139711,
+STORE, 140175938789376, 140175985139711,
+STORE, 140175938781184, 140175985139711,
+STORE, 140175938764800, 140175985139711,
+STORE, 140175938756608, 140175985139711,
+STORE, 140175938740224, 140175985139711,
+STORE, 140175938732032, 140175985139711,
+STORE, 140175938715648, 140175985139711,
+STORE, 140175938707456, 140175985139711,
+STORE, 140175938674688, 140175985139711,
+STORE, 140175938666496, 140175985139711,
+STORE, 140175938650112, 140175985139711,
+STORE, 140175938641920, 140175985139711,
+STORE, 140175938625536, 140175985139711,
+STORE, 140175938617344, 140175985139711,
+STORE, 140175938600960, 140175985139711,
+STORE, 140175938592768, 140175985139711,
+STORE, 140175938560000, 140175985139711,
+STORE, 140175938551808, 140175985139711,
+STORE, 140175938535424, 140175985139711,
+STORE, 140175938527232, 140175985139711,
+STORE, 140175938510848, 140175985139711,
+STORE, 140175938502656, 140175985139711,
+STORE, 140175938486272, 140175985139711,
+STORE, 140175938478080, 140175985139711,
+STORE, 140175938445312, 140175985139711,
+STORE, 140175938437120, 140175985139711,
+STORE, 140175938420736, 140175985139711,
+STORE, 140175938412544, 140175985139711,
+STORE, 140175938396160, 140175985139711,
+STORE, 140175938387968, 140175985139711,
+STORE, 140175938371584, 140175985139711,
+STORE, 140175938363392, 140175985139711,
+STORE, 140175938330624, 140175985139711,
+STORE, 140175938322432, 140175985139711,
+STORE, 140175938306048, 140175985139711,
+STORE, 140175938297856, 140175985139711,
+STORE, 140175938281472, 140175985139711,
+STORE, 140175938273280, 140175985139711,
+STORE, 140175938256896, 140175985139711,
+STORE, 140175938248704, 140175985139711,
+STORE, 140175938215936, 140175985139711,
+STORE, 140175938207744, 140175985139711,
+STORE, 140175938191360, 140175985139711,
+STORE, 140175938183168, 140175985139711,
+STORE, 140175938166784, 140175985139711,
+STORE, 140175938158592, 140175985139711,
+STORE, 140175938142208, 140175985139711,
+STORE, 140175936045056, 140175985139711,
+STORE, 140175936036864, 140175985139711,
+STORE, 140175936004096, 140175985139711,
+STORE, 140175935995904, 140175985139711,
+STORE, 140175935979520, 140175985139711,
+STORE, 140175935971328, 140175985139711,
+STORE, 140175935954944, 140175985139711,
+STORE, 140175935946752, 140175985139711,
+STORE, 140175935930368, 140175985139711,
+STORE, 140175935922176, 140175985139711,
+STORE, 140175935889408, 140175985139711,
+STORE, 140175935881216, 140175985139711,
+STORE, 140175935864832, 140175985139711,
+STORE, 140175935856640, 140175985139711,
+STORE, 140175935840256, 140175985139711,
+STORE, 140175935832064, 140175985139711,
+STORE, 140175935815680, 140175985139711,
+STORE, 140175935807488, 140175985139711,
+STORE, 140175935774720, 140175985139711,
+STORE, 140175935766528, 140175985139711,
+STORE, 140175935750144, 140175985139711,
+STORE, 140175935741952, 140175985139711,
+STORE, 140175935725568, 140175985139711,
+STORE, 140175935717376, 140175985139711,
+STORE, 140175935700992, 140175985139711,
+STORE, 140175935692800, 140175985139711,
+STORE, 140175935660032, 140175985139711,
+STORE, 140175935651840, 140175985139711,
+STORE, 140175935635456, 140175985139711,
+STORE, 140175935627264, 140175985139711,
+STORE, 140175935610880, 140175985139711,
+STORE, 140175935602688, 140175985139711,
+STORE, 140175935586304, 140175985139711,
+STORE, 140175935578112, 140175985139711,
+STORE, 140175935545344, 140175985139711,
+STORE, 140175935537152, 140175985139711,
+STORE, 140175935520768, 140175985139711,
+STORE, 140175935512576, 140175985139711,
+STORE, 140175935496192, 140175985139711,
+STORE, 140175935488000, 140175985139711,
+STORE, 140175935471616, 140175985139711,
+STORE, 140175935463424, 140175985139711,
+STORE, 140175935430656, 140175985139711,
+STORE, 140175935422464, 140175985139711,
+STORE, 140175935406080, 140175985139711,
+STORE, 140175935397888, 140175985139711,
+STORE, 140175935381504, 140175985139711,
+STORE, 140175935373312, 140175985139711,
+STORE, 140175935356928, 140175985139711,
+STORE, 140175935348736, 140175985139711,
+STORE, 140175935315968, 140175985139711,
+STORE, 140175935307776, 140175985139711,
+STORE, 140175935291392, 140175985139711,
+STORE, 140175935283200, 140175985139711,
+STORE, 140175935266816, 140175985139711,
+STORE, 140175935258624, 140175985139711,
+STORE, 140175935242240, 140175985139711,
+STORE, 140175935234048, 140175985139711,
+STORE, 140175935201280, 140175985139711,
+STORE, 140175935193088, 140175985139711,
+STORE, 140175935176704, 140175985139711,
+STORE, 140175935168512, 140175985139711,
+STORE, 140175935152128, 140175985139711,
+STORE, 140175935143936, 140175985139711,
+STORE, 140175935127552, 140175985139711,
+STORE, 140175935119360, 140175985139711,
+STORE, 140175935086592, 140175985139711,
+STORE, 140175935078400, 140175985139711,
+STORE, 140175935062016, 140175985139711,
+STORE, 140175935053824, 140175985139711,
+STORE, 140175935037440, 140175985139711,
+STORE, 140175935029248, 140175985139711,
+STORE, 140175935012864, 140175985139711,
+STORE, 140175935004672, 140175985139711,
+STORE, 140175934971904, 140175985139711,
+STORE, 140175934963712, 140175985139711,
+STORE, 140175934947328, 140175985139711,
+STORE, 140175934939136, 140175985139711,
+STORE, 140175934922752, 140175985139711,
+STORE, 140175934914560, 140175985139711,
+STORE, 140175934898176, 140175985139711,
+STORE, 140175934889984, 140175985139711,
+STORE, 140175934857216, 140175985139711,
+STORE, 140175934849024, 140175985139711,
+STORE, 140175934832640, 140175985139711,
+STORE, 140175934824448, 140175985139711,
+STORE, 140175934808064, 140175985139711,
+STORE, 140175934799872, 140175985139711,
+STORE, 140175934783488, 140175985139711,
+STORE, 140175934775296, 140175985139711,
+STORE, 140175934742528, 140175985139711,
+STORE, 140175934734336, 140175985139711,
+STORE, 140175934717952, 140175985139711,
+STORE, 140175934709760, 140175985139711,
+STORE, 140175934693376, 140175985139711,
+STORE, 140175934685184, 140175985139711,
+STORE, 140175934668800, 140175985139711,
+STORE, 140175934660608, 140175985139711,
+STORE, 140175934627840, 140175985139711,
+STORE, 140175934619648, 140175985139711,
+STORE, 140175934603264, 140175985139711,
+STORE, 140175934595072, 140175985139711,
+STORE, 140175934578688, 140175985139711,
+STORE, 140175934570496, 140175985139711,
+STORE, 140175934554112, 140175985139711,
+STORE, 140175934545920, 140175985139711,
+STORE, 140175934513152, 140175985139711,
+STORE, 140175934504960, 140175985139711,
+STORE, 140175934488576, 140175985139711,
+STORE, 140175934480384, 140175985139711,
+STORE, 140175934464000, 140175985139711,
+STORE, 140175934455808, 140175985139711,
+STORE, 140175934439424, 140175985139711,
+STORE, 140175934431232, 140175985139711,
+STORE, 140175934398464, 140175985139711,
+STORE, 140175934390272, 140175985139711,
+STORE, 140175934373888, 140175985139711,
+STORE, 140175934365696, 140175985139711,
+STORE, 140175934349312, 140175985139711,
+STORE, 140175934341120, 140175985139711,
+STORE, 140175934324736, 140175985139711,
+STORE, 140175932227584, 140175985139711,
+STORE, 140175932219392, 140175985139711,
+STORE, 140175932186624, 140175985139711,
+STORE, 140175932178432, 140175985139711,
+STORE, 140175932162048, 140175985139711,
+STORE, 140175932153856, 140175985139711,
+STORE, 140175932137472, 140175985139711,
+STORE, 53080064, 57884671,
+STORE, 140175932129280, 140175985139711,
+STORE, 140175932112896, 140175985139711,
+STORE, 140175932104704, 140175985139711,
+STORE, 140175932071936, 140175985139711,
+STORE, 140175932063744, 140175985139711,
+STORE, 140175932047360, 140175985139711,
+STORE, 140175932039168, 140175985139711,
+STORE, 140175932022784, 140175985139711,
+STORE, 140175932014592, 140175985139711,
+STORE, 140175931998208, 140175985139711,
+STORE, 140175931990016, 140175985139711,
+STORE, 140175931957248, 140175985139711,
+STORE, 140175931949056, 140175985139711,
+STORE, 140175931932672, 140175985139711,
+STORE, 140175931924480, 140175985139711,
+STORE, 140175931908096, 140175985139711,
+STORE, 140175931899904, 140175985139711,
+STORE, 140175931883520, 140175985139711,
+STORE, 140175931875328, 140175985139711,
+STORE, 140175931842560, 140175985139711,
+STORE, 140175931834368, 140175985139711,
+STORE, 140175931817984, 140175985139711,
+STORE, 140175931809792, 140175985139711,
+STORE, 140175931793408, 140175985139711,
+STORE, 140175931785216, 140175985139711,
+STORE, 140175931768832, 140175985139711,
+STORE, 140175931760640, 140175985139711,
+STORE, 140175931727872, 140175985139711,
+STORE, 140175931719680, 140175985139711,
+STORE, 140175931703296, 140175985139711,
+STORE, 140175931695104, 140175985139711,
+STORE, 140175931678720, 140175985139711,
+STORE, 140175931670528, 140175985139711,
+STORE, 140175931654144, 140175985139711,
+STORE, 140175931645952, 140175985139711,
+STORE, 140175931613184, 140175985139711,
+STORE, 140175931604992, 140175985139711,
+STORE, 140175931588608, 140175985139711,
+STORE, 140175931580416, 140175985139711,
+STORE, 140175931564032, 140175985139711,
+STORE, 140175931555840, 140175985139711,
+STORE, 140175931539456, 140175985139711,
+STORE, 140175931531264, 140175985139711,
+STORE, 140175931498496, 140175985139711,
+STORE, 140175931490304, 140175985139711,
+STORE, 140175931473920, 140175985139711,
+STORE, 140175931465728, 140175985139711,
+STORE, 140175931449344, 140175985139711,
+STORE, 140175931441152, 140175985139711,
+STORE, 140175931424768, 140175985139711,
+STORE, 140175931416576, 140175985139711,
+STORE, 140175931383808, 140175985139711,
+STORE, 140175931375616, 140175985139711,
+STORE, 140175931359232, 140175985139711,
+STORE, 140175931351040, 140175985139711,
+STORE, 140175931334656, 140175985139711,
+STORE, 140175931326464, 140175985139711,
+STORE, 140175931310080, 140175985139711,
+STORE, 140175931301888, 140175985139711,
+STORE, 140175931269120, 140175985139711,
+STORE, 140175931260928, 140175985139711,
+STORE, 140175931244544, 140175985139711,
+STORE, 140175931236352, 140175985139711,
+STORE, 140175931219968, 140175985139711,
+STORE, 140175931211776, 140175985139711,
+STORE, 140175931195392, 140175985139711,
+STORE, 140175931187200, 140175985139711,
+STORE, 140175931154432, 140175985139711,
+STORE, 140175931146240, 140175985139711,
+STORE, 140175931129856, 140175985139711,
+STORE, 140175931121664, 140175985139711,
+STORE, 140175931105280, 140175985139711,
+STORE, 140175931097088, 140175985139711,
+STORE, 140175931080704, 140175985139711,
+STORE, 140175931072512, 140175985139711,
+STORE, 140175931039744, 140175985139711,
+STORE, 140175931031552, 140175985139711,
+STORE, 140175931015168, 140175985139711,
+STORE, 140175931006976, 140175985139711,
+STORE, 140175930990592, 140175985139711,
+STORE, 140175930982400, 140175985139711,
+STORE, 140175930966016, 140175985139711,
+STORE, 140175930957824, 140175985139711,
+STORE, 140175930925056, 140175985139711,
+STORE, 140175930916864, 140175985139711,
+STORE, 140175930900480, 140175985139711,
+STORE, 140175930892288, 140175985139711,
+STORE, 140175930875904, 140175985139711,
+STORE, 140175930867712, 140175985139711,
+STORE, 140175930851328, 140175985139711,
+STORE, 140175930843136, 140175985139711,
+STORE, 140175930810368, 140175985139711,
+STORE, 140175930802176, 140175985139711,
+STORE, 140175930785792, 140175985139711,
+STORE, 140175930777600, 140175985139711,
+STORE, 140175930761216, 140175985139711,
+STORE, 140175930753024, 140175985139711,
+STORE, 140175930736640, 140175985139711,
+STORE, 140175930728448, 140175985139711,
+STORE, 140175930695680, 140175985139711,
+STORE, 140175930687488, 140175985139711,
+STORE, 140175930671104, 140175985139711,
+STORE, 140175930662912, 140175985139711,
+STORE, 140175930646528, 140175985139711,
+STORE, 140175930638336, 140175985139711,
+STORE, 140175930621952, 140175985139711,
+STORE, 140175930613760, 140175985139711,
+STORE, 140175930580992, 140175985139711,
+STORE, 140175930572800, 140175985139711,
+STORE, 140175930556416, 140175985139711,
+STORE, 140175930548224, 140175985139711,
+STORE, 140175930531840, 140175985139711,
+STORE, 140175930523648, 140175985139711,
+STORE, 140175930507264, 140175985139711,
+STORE, 140175928410112, 140175985139711,
+STORE, 140175928401920, 140175985139711,
+STORE, 140175928369152, 140175985139711,
+STORE, 140175928360960, 140175985139711,
+STORE, 140175928344576, 140175985139711,
+STORE, 140175928336384, 140175985139711,
+STORE, 140175928320000, 140175985139711,
+STORE, 140175928311808, 140175985139711,
+STORE, 140175928295424, 140175985139711,
+STORE, 140175927242752, 140175985139711,
+SNULL, 140175956627455, 140175985139711,
+STORE, 140175927242752, 140175956627455,
+STORE, 140175956627456, 140175985139711,
+ };
+ unsigned long set24[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140735281639424, 140737488351231,
+SNULL, 140735281643519, 140737488351231,
+STORE, 140735281639424, 140735281643519,
+STORE, 140735281508352, 140735281643519,
+STORE, 94717834911744, 94717834928127,
+SNULL, 94717834915839, 94717834928127,
+STORE, 94717834911744, 94717834915839,
+STORE, 94717834915840, 94717834928127,
+ERASE, 94717834915840, 94717834928127,
+STORE, 94717834919936, 94717834928127,
+STORE, 140428246065152, 140428248317951,
+SNULL, 140428246208511, 140428248317951,
+STORE, 140428246065152, 140428246208511,
+STORE, 140428246208512, 140428248317951,
+ERASE, 140428246208512, 140428248317951,
+STORE, 140428248305664, 140428248313855,
+STORE, 140428248313856, 140428248317951,
+STORE, 140735281811456, 140735281815551,
+STORE, 140735281799168, 140735281811455,
+STORE, 140428248297472, 140428248305663,
+STORE, 140428243841024, 140428246065151,
+SNULL, 140428245491711, 140428246065151,
+STORE, 140428243841024, 140428245491711,
+STORE, 140428245491712, 140428246065151,
+SNULL, 140428245491712, 140428246061055,
+STORE, 140428246061056, 140428246065151,
+STORE, 140428245491712, 140428246061055,
+ERASE, 140428245491712, 140428246061055,
+STORE, 140428245491712, 140428246061055,
+ERASE, 140428246061056, 140428246065151,
+STORE, 140428246061056, 140428246065151,
+STORE, 140428248268800, 140428248297471,
+STORE, 140428241625088, 140428243841023,
+SNULL, 140428241625088, 140428241723391,
+STORE, 140428241723392, 140428243841023,
+STORE, 140428241625088, 140428241723391,
+SNULL, 140428243816447, 140428243841023,
+STORE, 140428241723392, 140428243816447,
+STORE, 140428243816448, 140428243841023,
+SNULL, 140428243816448, 140428243824639,
+STORE, 140428243824640, 140428243841023,
+STORE, 140428243816448, 140428243824639,
+ERASE, 140428243816448, 140428243824639,
+STORE, 140428243816448, 140428243824639,
+ERASE, 140428243824640, 140428243841023,
+STORE, 140428243824640, 140428243841023,
+STORE, 140428237828096, 140428241625087,
+SNULL, 140428237828096, 140428239486975,
+STORE, 140428239486976, 140428241625087,
+STORE, 140428237828096, 140428239486975,
+SNULL, 140428241584127, 140428241625087,
+STORE, 140428239486976, 140428241584127,
+STORE, 140428241584128, 140428241625087,
+SNULL, 140428241584128, 140428241608703,
+STORE, 140428241608704, 140428241625087,
+STORE, 140428241584128, 140428241608703,
+ERASE, 140428241584128, 140428241608703,
+STORE, 140428241584128, 140428241608703,
+ERASE, 140428241608704, 140428241625087,
+STORE, 140428241608704, 140428241625087,
+STORE, 140428235567104, 140428237828095,
+SNULL, 140428235567104, 140428235718655,
+STORE, 140428235718656, 140428237828095,
+STORE, 140428235567104, 140428235718655,
+SNULL, 140428237811711, 140428237828095,
+STORE, 140428235718656, 140428237811711,
+STORE, 140428237811712, 140428237828095,
+SNULL, 140428237811712, 140428237819903,
+STORE, 140428237819904, 140428237828095,
+STORE, 140428237811712, 140428237819903,
+ERASE, 140428237811712, 140428237819903,
+STORE, 140428237811712, 140428237819903,
+ERASE, 140428237819904, 140428237828095,
+STORE, 140428237819904, 140428237828095,
+STORE, 140428233445376, 140428235567103,
+SNULL, 140428233445376, 140428233461759,
+STORE, 140428233461760, 140428235567103,
+STORE, 140428233445376, 140428233461759,
+SNULL, 140428235558911, 140428235567103,
+STORE, 140428233461760, 140428235558911,
+STORE, 140428235558912, 140428235567103,
+ERASE, 140428235558912, 140428235567103,
+STORE, 140428235558912, 140428235567103,
+STORE, 140428231315456, 140428233445375,
+SNULL, 140428231315456, 140428231344127,
+STORE, 140428231344128, 140428233445375,
+STORE, 140428231315456, 140428231344127,
+SNULL, 140428233437183, 140428233445375,
+STORE, 140428231344128, 140428233437183,
+STORE, 140428233437184, 140428233445375,
+ERASE, 140428233437184, 140428233445375,
+STORE, 140428233437184, 140428233445375,
+STORE, 140428248260608, 140428248268799,
+STORE, 140428229062656, 140428231315455,
+SNULL, 140428229062656, 140428229214207,
+STORE, 140428229214208, 140428231315455,
+STORE, 140428229062656, 140428229214207,
+SNULL, 140428231307263, 140428231315455,
+STORE, 140428229214208, 140428231307263,
+STORE, 140428231307264, 140428231315455,
+ERASE, 140428231307264, 140428231315455,
+STORE, 140428231307264, 140428231315455,
+STORE, 140428226891776, 140428229062655,
+SNULL, 140428226891776, 140428226961407,
+STORE, 140428226961408, 140428229062655,
+STORE, 140428226891776, 140428226961407,
+SNULL, 140428229054463, 140428229062655,
+STORE, 140428226961408, 140428229054463,
+STORE, 140428229054464, 140428229062655,
+ERASE, 140428229054464, 140428229062655,
+STORE, 140428229054464, 140428229062655,
+STORE, 140428223680512, 140428226891775,
+SNULL, 140428223680512, 140428224757759,
+STORE, 140428224757760, 140428226891775,
+STORE, 140428223680512, 140428224757759,
+SNULL, 140428226854911, 140428226891775,
+STORE, 140428224757760, 140428226854911,
+STORE, 140428226854912, 140428226891775,
+ERASE, 140428226854912, 140428226891775,
+STORE, 140428226854912, 140428226891775,
+STORE, 140428221546496, 140428223680511,
+SNULL, 140428221546496, 140428221575167,
+STORE, 140428221575168, 140428223680511,
+STORE, 140428221546496, 140428221575167,
+SNULL, 140428223672319, 140428223680511,
+STORE, 140428221575168, 140428223672319,
+STORE, 140428223672320, 140428223680511,
+ERASE, 140428223672320, 140428223680511,
+STORE, 140428223672320, 140428223680511,
+STORE, 140428219236352, 140428221546495,
+SNULL, 140428219236352, 140428219441151,
+STORE, 140428219441152, 140428221546495,
+STORE, 140428219236352, 140428219441151,
+SNULL, 140428221538303, 140428221546495,
+STORE, 140428219441152, 140428221538303,
+STORE, 140428221538304, 140428221546495,
+ERASE, 140428221538304, 140428221546495,
+STORE, 140428221538304, 140428221546495,
+STORE, 140428216852480, 140428219236351,
+SNULL, 140428216852480, 140428217044991,
+STORE, 140428217044992, 140428219236351,
+STORE, 140428216852480, 140428217044991,
+SNULL, 140428219138047, 140428219236351,
+STORE, 140428217044992, 140428219138047,
+STORE, 140428219138048, 140428219236351,
+ERASE, 140428219138048, 140428219236351,
+STORE, 140428219138048, 140428219236351,
+STORE, 140428248252416, 140428248268799,
+STORE, 140428214284288, 140428216852479,
+SNULL, 140428214284288, 140428214751231,
+STORE, 140428214751232, 140428216852479,
+STORE, 140428214284288, 140428214751231,
+SNULL, 140428216844287, 140428216852479,
+STORE, 140428214751232, 140428216844287,
+STORE, 140428216844288, 140428216852479,
+ERASE, 140428216844288, 140428216852479,
+STORE, 140428216844288, 140428216852479,
+STORE, 140428212170752, 140428214284287,
+SNULL, 140428212170752, 140428212183039,
+STORE, 140428212183040, 140428214284287,
+STORE, 140428212170752, 140428212183039,
+SNULL, 140428214276095, 140428214284287,
+STORE, 140428212183040, 140428214276095,
+STORE, 140428214276096, 140428214284287,
+ERASE, 140428214276096, 140428214284287,
+STORE, 140428214276096, 140428214284287,
+STORE, 140428209991680, 140428212170751,
+SNULL, 140428209991680, 140428210069503,
+STORE, 140428210069504, 140428212170751,
+STORE, 140428209991680, 140428210069503,
+SNULL, 140428212162559, 140428212170751,
+STORE, 140428210069504, 140428212162559,
+STORE, 140428212162560, 140428212170751,
+ERASE, 140428212162560, 140428212170751,
+STORE, 140428212162560, 140428212170751,
+STORE, 140428207874048, 140428209991679,
+SNULL, 140428207874048, 140428207890431,
+STORE, 140428207890432, 140428209991679,
+STORE, 140428207874048, 140428207890431,
+SNULL, 140428209983487, 140428209991679,
+STORE, 140428207890432, 140428209983487,
+STORE, 140428209983488, 140428209991679,
+ERASE, 140428209983488, 140428209991679,
+STORE, 140428209983488, 140428209991679,
+STORE, 140428248244224, 140428248268799,
+STORE, 140428248231936, 140428248268799,
+SNULL, 140428241600511, 140428241608703,
+STORE, 140428241584128, 140428241600511,
+STORE, 140428241600512, 140428241608703,
+SNULL, 140428209987583, 140428209991679,
+STORE, 140428209983488, 140428209987583,
+STORE, 140428209987584, 140428209991679,
+SNULL, 140428212166655, 140428212170751,
+STORE, 140428212162560, 140428212166655,
+STORE, 140428212166656, 140428212170751,
+SNULL, 140428214280191, 140428214284287,
+STORE, 140428214276096, 140428214280191,
+STORE, 140428214280192, 140428214284287,
+SNULL, 140428243820543, 140428243824639,
+STORE, 140428243816448, 140428243820543,
+STORE, 140428243820544, 140428243824639,
+SNULL, 140428216848383, 140428216852479,
+STORE, 140428216844288, 140428216848383,
+STORE, 140428216848384, 140428216852479,
+SNULL, 140428219232255, 140428219236351,
+STORE, 140428219138048, 140428219232255,
+STORE, 140428219232256, 140428219236351,
+SNULL, 140428221542399, 140428221546495,
+STORE, 140428221538304, 140428221542399,
+STORE, 140428221542400, 140428221546495,
+SNULL, 140428223676415, 140428223680511,
+STORE, 140428223672320, 140428223676415,
+STORE, 140428223676416, 140428223680511,
+SNULL, 140428226863103, 140428226891775,
+STORE, 140428226854912, 140428226863103,
+STORE, 140428226863104, 140428226891775,
+SNULL, 140428229058559, 140428229062655,
+STORE, 140428229054464, 140428229058559,
+STORE, 140428229058560, 140428229062655,
+SNULL, 140428231311359, 140428231315455,
+STORE, 140428231307264, 140428231311359,
+STORE, 140428231311360, 140428231315455,
+SNULL, 140428233441279, 140428233445375,
+STORE, 140428233437184, 140428233441279,
+STORE, 140428233441280, 140428233445375,
+SNULL, 140428235563007, 140428235567103,
+STORE, 140428235558912, 140428235563007,
+STORE, 140428235563008, 140428235567103,
+SNULL, 140428237815807, 140428237819903,
+STORE, 140428237811712, 140428237815807,
+STORE, 140428237815808, 140428237819903,
+SNULL, 140428246056959, 140428246061055,
+STORE, 140428245491712, 140428246056959,
+STORE, 140428246056960, 140428246061055,
+SNULL, 94717834924031, 94717834928127,
+STORE, 94717834919936, 94717834924031,
+STORE, 94717834924032, 94717834928127,
+SNULL, 140428248309759, 140428248313855,
+STORE, 140428248305664, 140428248309759,
+STORE, 140428248309760, 140428248313855,
+ERASE, 140428248268800, 140428248297471,
+STORE, 94717843058688, 94717843193855,
+STORE, 94749677137920, 94749677559807,
+STORE, 94749677563904, 94749677604863,
+STORE, 94749677604864, 94749677608959,
+STORE, 94749710970880, 94749711241215,
+STORE, 140490884894720, 140490884935679,
+STORE, 140490884935680, 140490887032831,
+STORE, 140490887032832, 140490887036927,
+STORE, 140490887036928, 140490887041023,
+STORE, 140490887041024, 140490887065599,
+STORE, 140490887065600, 140490887110655,
+STORE, 140490887110656, 140490889203711,
+STORE, 140490889203712, 140490889207807,
+STORE, 140490889207808, 140490889211903,
+STORE, 140490889211904, 140490889293823,
+STORE, 140490889293824, 140490891390975,
+STORE, 140490891390976, 140490891395071,
+STORE, 140490891395072, 140490891399167,
+STORE, 140490891399168, 140490891407359,
+STORE, 140490891407360, 140490891436031,
+STORE, 140490891436032, 140490893529087,
+STORE, 140490893529088, 140490893533183,
+STORE, 140490893533184, 140490893537279,
+STORE, 140490893537280, 140490901979135,
+STORE, 140490901979136, 140490901991423,
+STORE, 140490901991424, 140490904084479,
+STORE, 140490904084480, 140490904088575,
+STORE, 140490904088576, 140490904092671,
+STORE, 140490904092672, 140490904559615,
+STORE, 140490904559616, 140490906652671,
+STORE, 140490906652672, 140490906656767,
+STORE, 140490906656768, 140490906660863,
+STORE, 140490906660864, 140490906677247,
+STORE, 140490906677248, 140490908770303,
+STORE, 140490908770304, 140490908774399,
+STORE, 140490908774400, 140490908778495,
+STORE, 140490908778496, 140490908794879,
+STORE, 140490908794880, 140490910887935,
+STORE, 140490910887936, 140490910892031,
+STORE, 140490910892032, 140490910896127,
+STORE, 140490910896128, 140490912555007,
+STORE, 140490912555008, 140490914652159,
+STORE, 140490914652160, 140490914668543,
+STORE, 140490914668544, 140490914676735,
+STORE, 140490914676736, 140490914693119,
+STORE, 140490914693120, 140490914791423,
+STORE, 140490914791424, 140490916884479,
+STORE, 140490916884480, 140490916888575,
+STORE, 140490916888576, 140490916892671,
+STORE, 140490916892672, 140490916909055,
+STORE, 140490916909056, 140490916937727,
+STORE, 140490916937728, 140490919030783,
+STORE, 140490919030784, 140490919034879,
+STORE, 140490919034880, 140490919038975,
+STORE, 140490919038976, 140490919190527,
+STORE, 140490919190528, 140490921283583,
+STORE, 140490921283584, 140490921287679,
+STORE, 140490921287680, 140490921291775,
+STORE, 140490921291776, 140490921299967,
+STORE, 140490921299968, 140490921390079,
+STORE, 140490921390080, 140490923483135,
+STORE, 140490923483136, 140490923487231,
+STORE, 140490923487232, 140490923491327,
+STORE, 140490923491328, 140490923757567,
+STORE, 140490923757568, 140490925850623,
+STORE, 140490925850624, 140490925867007,
+STORE, 140490925867008, 140490925871103,
+STORE, 140490925871104, 140490925875199,
+STORE, 140490925875200, 140490925903871,
+STORE, 140490925903872, 140490928001023,
+STORE, 140490928001024, 140490928005119,
+STORE, 140490928005120, 140490928009215,
+STORE, 140490928009216, 140490928152575,
+STORE, 140490930184192, 140490930221055,
+STORE, 140490930221056, 140490930237439,
+STORE, 140490930237440, 140490930241535,
+STORE, 140490930241536, 140490930245631,
+STORE, 140490930245632, 140490930249727,
+STORE, 140490930249728, 140490930253823,
+STORE, 140490930253824, 140490930257919,
+STORE, 140490930257920, 140490930262015,
+STORE, 140724611694592, 140724611829759,
+STORE, 140724612427776, 140724612440063,
+STORE, 140724612440064, 140724612444159,
+STORE, 94103163662336, 94103163772927,
+STORE, 94103165865984, 94103165874175,
+STORE, 94103165874176, 94103165878271,
+STORE, 94103165878272, 94103165886463,
+STORE, 94103182548992, 94103182684159,
+STORE, 140092694708224, 140092696367103,
+STORE, 140092696367104, 140092698464255,
+STORE, 140092698464256, 140092698480639,
+STORE, 140092698480640, 140092698488831,
+STORE, 140092698488832, 140092698505215,
+STORE, 140092698505216, 140092698648575,
+STORE, 140092700708864, 140092700717055,
+STORE, 140092700745728, 140092700749823,
+STORE, 140092700749824, 140092700753919,
+STORE, 140092700753920, 140092700758015,
+STORE, 140736800911360, 140736801046527,
+STORE, 140736802308096, 140736802320383,
+STORE, 140736802320384, 140736802324479,
+STORE, 93948802064384, 93948802174975,
+STORE, 93948804268032, 93948804276223,
+STORE, 93948804276224, 93948804280319,
+STORE, 93948804280320, 93948804288511,
+STORE, 93948806266880, 93948806402047,
+STORE, 140222999113728, 140223000772607,
+STORE, 140223000772608, 140223002869759,
+STORE, 140223002869760, 140223002886143,
+STORE, 140223002886144, 140223002894335,
+STORE, 140223002894336, 140223002910719,
+STORE, 140223002910720, 140223003054079,
+STORE, 140223005114368, 140223005122559,
+STORE, 140223005151232, 140223005155327,
+STORE, 140223005155328, 140223005159423,
+STORE, 140223005159424, 140223005163519,
+STORE, 140720877506560, 140720877641727,
+STORE, 140720878231552, 140720878243839,
+STORE, 140720878243840, 140720878247935,
+STORE, 140737488347136, 140737488351231,
+STORE, 140733232087040, 140737488351231,
+SNULL, 140733232091135, 140737488351231,
+STORE, 140733232087040, 140733232091135,
+STORE, 140733231955968, 140733232091135,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140161681321984, 140161683574783,
+SNULL, 140161681465343, 140161683574783,
+STORE, 140161681321984, 140161681465343,
+STORE, 140161681465344, 140161683574783,
+ERASE, 140161681465344, 140161683574783,
+STORE, 140161683562496, 140161683570687,
+STORE, 140161683570688, 140161683574783,
+STORE, 140733232214016, 140733232218111,
+STORE, 140733232201728, 140733232214015,
+STORE, 140161683533824, 140161683562495,
+STORE, 140161683525632, 140161683533823,
+STORE, 140161678159872, 140161681321983,
+SNULL, 140161678159872, 140161679220735,
+STORE, 140161679220736, 140161681321983,
+STORE, 140161678159872, 140161679220735,
+SNULL, 140161681313791, 140161681321983,
+STORE, 140161679220736, 140161681313791,
+STORE, 140161681313792, 140161681321983,
+ERASE, 140161681313792, 140161681321983,
+STORE, 140161681313792, 140161681321983,
+STORE, 140161674362880, 140161678159871,
+SNULL, 140161674362880, 140161676021759,
+STORE, 140161676021760, 140161678159871,
+STORE, 140161674362880, 140161676021759,
+SNULL, 140161678118911, 140161678159871,
+STORE, 140161676021760, 140161678118911,
+STORE, 140161678118912, 140161678159871,
+SNULL, 140161678118912, 140161678143487,
+STORE, 140161678143488, 140161678159871,
+STORE, 140161678118912, 140161678143487,
+ERASE, 140161678118912, 140161678143487,
+STORE, 140161678118912, 140161678143487,
+ERASE, 140161678143488, 140161678159871,
+STORE, 140161678143488, 140161678159871,
+STORE, 140161683513344, 140161683533823,
+SNULL, 140161678135295, 140161678143487,
+STORE, 140161678118912, 140161678135295,
+STORE, 140161678135296, 140161678143487,
+SNULL, 140161681317887, 140161681321983,
+STORE, 140161681313792, 140161681317887,
+STORE, 140161681317888, 140161681321983,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140161683566591, 140161683570687,
+STORE, 140161683562496, 140161683566591,
+STORE, 140161683566592, 140161683570687,
+ERASE, 140161683533824, 140161683562495,
+STORE, 25477120, 25612287,
+STORE, 25477120, 25759743,
+STORE, 140161681829888, 140161683513343,
+STORE, 25477120, 25915391,
+STORE, 25477120, 26054655,
+SNULL, 25800703, 26054655,
+STORE, 25477120, 25800703,
+STORE, 25800704, 26054655,
+ERASE, 25800704, 26054655,
+STORE, 140737488347136, 140737488351231,
+STORE, 140723218452480, 140737488351231,
+SNULL, 140723218456575, 140737488351231,
+STORE, 140723218452480, 140723218456575,
+STORE, 140723218321408, 140723218456575,
+STORE, 4194304, 26279935,
+STORE, 28372992, 28454911,
+STORE, 28454912, 29806591,
+STORE, 140398872264704, 140398874517503,
+SNULL, 140398872408063, 140398874517503,
+STORE, 140398872264704, 140398872408063,
+STORE, 140398872408064, 140398874517503,
+ERASE, 140398872408064, 140398874517503,
+STORE, 140398874505216, 140398874513407,
+STORE, 140398874513408, 140398874517503,
+STORE, 140723219247104, 140723219251199,
+STORE, 140723219234816, 140723219247103,
+STORE, 140398874476544, 140398874505215,
+STORE, 140398874468352, 140398874476543,
+STORE, 140398868430848, 140398872264703,
+SNULL, 140398868430848, 140398870138879,
+STORE, 140398870138880, 140398872264703,
+STORE, 140398868430848, 140398870138879,
+SNULL, 140398872231935, 140398872264703,
+STORE, 140398870138880, 140398872231935,
+STORE, 140398872231936, 140398872264703,
+ERASE, 140398872231936, 140398872264703,
+STORE, 140398872231936, 140398872264703,
+STORE, 140398866235392, 140398868430847,
+SNULL, 140398866235392, 140398866329599,
+STORE, 140398866329600, 140398868430847,
+STORE, 140398866235392, 140398866329599,
+SNULL, 140398868422655, 140398868430847,
+STORE, 140398866329600, 140398868422655,
+STORE, 140398868422656, 140398868430847,
+ERASE, 140398868422656, 140398868430847,
+STORE, 140398868422656, 140398868430847,
+STORE, 140398863716352, 140398866235391,
+SNULL, 140398863716352, 140398864130047,
+STORE, 140398864130048, 140398866235391,
+STORE, 140398863716352, 140398864130047,
+SNULL, 140398866223103, 140398866235391,
+STORE, 140398864130048, 140398866223103,
+STORE, 140398866223104, 140398866235391,
+ERASE, 140398866223104, 140398866235391,
+STORE, 140398866223104, 140398866235391,
+STORE, 140398861082624, 140398863716351,
+SNULL, 140398861082624, 140398861611007,
+STORE, 140398861611008, 140398863716351,
+STORE, 140398861082624, 140398861611007,
+SNULL, 140398863708159, 140398863716351,
+STORE, 140398861611008, 140398863708159,
+STORE, 140398863708160, 140398863716351,
+ERASE, 140398863708160, 140398863716351,
+STORE, 140398863708160, 140398863716351,
+STORE, 140398858969088, 140398861082623,
+SNULL, 140398858969088, 140398858981375,
+STORE, 140398858981376, 140398861082623,
+STORE, 140398858969088, 140398858981375,
+SNULL, 140398861074431, 140398861082623,
+STORE, 140398858981376, 140398861074431,
+STORE, 140398861074432, 140398861082623,
+ERASE, 140398861074432, 140398861082623,
+STORE, 140398861074432, 140398861082623,
+STORE, 140398856765440, 140398858969087,
+SNULL, 140398856765440, 140398856867839,
+STORE, 140398856867840, 140398858969087,
+STORE, 140398856765440, 140398856867839,
+SNULL, 140398858960895, 140398858969087,
+STORE, 140398856867840, 140398858960895,
+STORE, 140398858960896, 140398858969087,
+ERASE, 140398858960896, 140398858969087,
+STORE, 140398858960896, 140398858969087,
+STORE, 140398874460160, 140398874476543,
+STORE, 140398853603328, 140398856765439,
+SNULL, 140398853603328, 140398854664191,
+STORE, 140398854664192, 140398856765439,
+STORE, 140398853603328, 140398854664191,
+SNULL, 140398856757247, 140398856765439,
+STORE, 140398854664192, 140398856757247,
+STORE, 140398856757248, 140398856765439,
+ERASE, 140398856757248, 140398856765439,
+STORE, 140398856757248, 140398856765439,
+STORE, 140398849806336, 140398853603327,
+SNULL, 140398849806336, 140398851465215,
+STORE, 140398851465216, 140398853603327,
+STORE, 140398849806336, 140398851465215,
+SNULL, 140398853562367, 140398853603327,
+STORE, 140398851465216, 140398853562367,
+STORE, 140398853562368, 140398853603327,
+SNULL, 140398853562368, 140398853586943,
+STORE, 140398853586944, 140398853603327,
+STORE, 140398853562368, 140398853586943,
+ERASE, 140398853562368, 140398853586943,
+STORE, 140398853562368, 140398853586943,
+ERASE, 140398853586944, 140398853603327,
+STORE, 140398853586944, 140398853603327,
+STORE, 140398874447872, 140398874476543,
+SNULL, 140398853578751, 140398853586943,
+STORE, 140398853562368, 140398853578751,
+STORE, 140398853578752, 140398853586943,
+SNULL, 140398856761343, 140398856765439,
+STORE, 140398856757248, 140398856761343,
+STORE, 140398856761344, 140398856765439,
+SNULL, 140398858964991, 140398858969087,
+STORE, 140398858960896, 140398858964991,
+STORE, 140398858964992, 140398858969087,
+SNULL, 140398861078527, 140398861082623,
+STORE, 140398861074432, 140398861078527,
+STORE, 140398861078528, 140398861082623,
+SNULL, 140398863712255, 140398863716351,
+STORE, 140398863708160, 140398863712255,
+STORE, 140398863712256, 140398863716351,
+SNULL, 140398866231295, 140398866235391,
+STORE, 140398866223104, 140398866231295,
+STORE, 140398866231296, 140398866235391,
+SNULL, 140398868426751, 140398868430847,
+STORE, 140398868422656, 140398868426751,
+STORE, 140398868426752, 140398868430847,
+SNULL, 140398872236031, 140398872264703,
+STORE, 140398872231936, 140398872236031,
+STORE, 140398872236032, 140398872264703,
+SNULL, 28405759, 28454911,
+STORE, 28372992, 28405759,
+STORE, 28405760, 28454911,
+SNULL, 140398874509311, 140398874513407,
+STORE, 140398874505216, 140398874509311,
+STORE, 140398874509312, 140398874513407,
+ERASE, 140398874476544, 140398874505215,
+STORE, 43278336, 43413503,
+STORE, 140398872764416, 140398874447871,
+STORE, 140398874501120, 140398874505215,
+STORE, 140398872629248, 140398872764415,
+STORE, 43278336, 43556863,
+STORE, 140398847709184, 140398849806335,
+STORE, 140398874492928, 140398874505215,
+STORE, 140398874484736, 140398874505215,
+STORE, 140398874447872, 140398874484735,
+STORE, 140398872612864, 140398872764415,
+STORE, 43278336, 43692031,
+STORE, 43278336, 43880447,
+STORE, 140398872604672, 140398872764415,
+STORE, 140398872596480, 140398872764415,
+STORE, 43278336, 44044287,
+STORE, 140398872580096, 140398872764415,
+STORE, 140737488347136, 140737488351231,
+STORE, 140734403092480, 140737488351231,
+SNULL, 140734403096575, 140737488351231,
+STORE, 140734403092480, 140734403096575,
+STORE, 140734402961408, 140734403096575,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140240662380544, 140240664633343,
+SNULL, 140240662523903, 140240664633343,
+STORE, 140240662380544, 140240662523903,
+STORE, 140240662523904, 140240664633343,
+ERASE, 140240662523904, 140240664633343,
+STORE, 140240664621056, 140240664629247,
+STORE, 140240664629248, 140240664633343,
+STORE, 140734403145728, 140734403149823,
+STORE, 140734403133440, 140734403145727,
+STORE, 140240664592384, 140240664621055,
+STORE, 140240664584192, 140240664592383,
+STORE, 140240659218432, 140240662380543,
+SNULL, 140240659218432, 140240660279295,
+STORE, 140240660279296, 140240662380543,
+STORE, 140240659218432, 140240660279295,
+SNULL, 140240662372351, 140240662380543,
+STORE, 140240660279296, 140240662372351,
+STORE, 140240662372352, 140240662380543,
+ERASE, 140240662372352, 140240662380543,
+STORE, 140240662372352, 140240662380543,
+STORE, 140240655421440, 140240659218431,
+SNULL, 140240655421440, 140240657080319,
+STORE, 140240657080320, 140240659218431,
+STORE, 140240655421440, 140240657080319,
+SNULL, 140240659177471, 140240659218431,
+STORE, 140240657080320, 140240659177471,
+STORE, 140240659177472, 140240659218431,
+SNULL, 140240659177472, 140240659202047,
+STORE, 140240659202048, 140240659218431,
+STORE, 140240659177472, 140240659202047,
+ERASE, 140240659177472, 140240659202047,
+STORE, 140240659177472, 140240659202047,
+ERASE, 140240659202048, 140240659218431,
+STORE, 140240659202048, 140240659218431,
+STORE, 140240664571904, 140240664592383,
+SNULL, 140240659193855, 140240659202047,
+STORE, 140240659177472, 140240659193855,
+STORE, 140240659193856, 140240659202047,
+SNULL, 140240662376447, 140240662380543,
+STORE, 140240662372352, 140240662376447,
+STORE, 140240662376448, 140240662380543,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140240664625151, 140240664629247,
+STORE, 140240664621056, 140240664625151,
+STORE, 140240664625152, 140240664629247,
+ERASE, 140240664592384, 140240664621055,
+STORE, 30646272, 30781439,
+STORE, 30646272, 30928895,
+STORE, 140240662888448, 140240664571903,
+STORE, 94256659468288, 94256659578879,
+STORE, 94256661671936, 94256661680127,
+STORE, 94256661680128, 94256661684223,
+STORE, 94256661684224, 94256661692415,
+STORE, 94256687980544, 94256688115711,
+STORE, 139801712504832, 139801714163711,
+STORE, 139801714163712, 139801716260863,
+STORE, 139801716260864, 139801716277247,
+STORE, 139801716277248, 139801716285439,
+STORE, 139801716285440, 139801716301823,
+STORE, 139801716301824, 139801716445183,
+STORE, 139801718505472, 139801718513663,
+STORE, 139801718542336, 139801718546431,
+STORE, 139801718546432, 139801718550527,
+STORE, 139801718550528, 139801718554623,
+STORE, 140721575538688, 140721575673855,
+STORE, 140721577013248, 140721577025535,
+STORE, 140721577025536, 140721577029631,
+STORE, 140737488347136, 140737488351231,
+STORE, 140729259393024, 140737488351231,
+SNULL, 140729259397119, 140737488351231,
+STORE, 140729259393024, 140729259397119,
+STORE, 140729259261952, 140729259397119,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 139682376638464, 139682378891263,
+SNULL, 139682376781823, 139682378891263,
+STORE, 139682376638464, 139682376781823,
+STORE, 139682376781824, 139682378891263,
+ERASE, 139682376781824, 139682378891263,
+STORE, 139682378878976, 139682378887167,
+STORE, 139682378887168, 139682378891263,
+STORE, 140729260462080, 140729260466175,
+STORE, 140729260449792, 140729260462079,
+STORE, 139682378850304, 139682378878975,
+STORE, 139682378842112, 139682378850303,
+STORE, 139682373476352, 139682376638463,
+SNULL, 139682373476352, 139682374537215,
+STORE, 139682374537216, 139682376638463,
+STORE, 139682373476352, 139682374537215,
+SNULL, 139682376630271, 139682376638463,
+STORE, 139682374537216, 139682376630271,
+STORE, 139682376630272, 139682376638463,
+ERASE, 139682376630272, 139682376638463,
+STORE, 139682376630272, 139682376638463,
+STORE, 139682369679360, 139682373476351,
+SNULL, 139682369679360, 139682371338239,
+STORE, 139682371338240, 139682373476351,
+STORE, 139682369679360, 139682371338239,
+SNULL, 139682373435391, 139682373476351,
+STORE, 139682371338240, 139682373435391,
+STORE, 139682373435392, 139682373476351,
+SNULL, 139682373435392, 139682373459967,
+STORE, 139682373459968, 139682373476351,
+STORE, 139682373435392, 139682373459967,
+ERASE, 139682373435392, 139682373459967,
+STORE, 139682373435392, 139682373459967,
+ERASE, 139682373459968, 139682373476351,
+STORE, 139682373459968, 139682373476351,
+STORE, 139682378829824, 139682378850303,
+SNULL, 139682373451775, 139682373459967,
+STORE, 139682373435392, 139682373451775,
+STORE, 139682373451776, 139682373459967,
+SNULL, 139682376634367, 139682376638463,
+STORE, 139682376630272, 139682376634367,
+STORE, 139682376634368, 139682376638463,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 139682378883071, 139682378887167,
+STORE, 139682378878976, 139682378883071,
+STORE, 139682378883072, 139682378887167,
+ERASE, 139682378850304, 139682378878975,
+STORE, 10022912, 10158079,
+STORE, 10022912, 10305535,
+STORE, 139682377146368, 139682378829823,
+STORE, 140737488347136, 140737488351231,
+STORE, 140731831926784, 140737488351231,
+SNULL, 140731831930879, 140737488351231,
+STORE, 140731831926784, 140731831930879,
+STORE, 140731831795712, 140731831930879,
+STORE, 94615305261056, 94615307485183,
+SNULL, 94615305371647, 94615307485183,
+STORE, 94615305261056, 94615305371647,
+STORE, 94615305371648, 94615307485183,
+ERASE, 94615305371648, 94615307485183,
+STORE, 94615307464704, 94615307476991,
+STORE, 94615307476992, 94615307485183,
+STORE, 140163912994816, 140163915247615,
+SNULL, 140163913138175, 140163915247615,
+STORE, 140163912994816, 140163913138175,
+STORE, 140163913138176, 140163915247615,
+ERASE, 140163913138176, 140163915247615,
+STORE, 140163915235328, 140163915243519,
+STORE, 140163915243520, 140163915247615,
+STORE, 140731832217600, 140731832221695,
+STORE, 140731832205312, 140731832217599,
+STORE, 140163915206656, 140163915235327,
+STORE, 140163915198464, 140163915206655,
+STORE, 140163909197824, 140163912994815,
+SNULL, 140163909197824, 140163910856703,
+STORE, 140163910856704, 140163912994815,
+STORE, 140163909197824, 140163910856703,
+SNULL, 140163912953855, 140163912994815,
+STORE, 140163910856704, 140163912953855,
+STORE, 140163912953856, 140163912994815,
+SNULL, 140163912953856, 140163912978431,
+STORE, 140163912978432, 140163912994815,
+STORE, 140163912953856, 140163912978431,
+ERASE, 140163912953856, 140163912978431,
+STORE, 140163912953856, 140163912978431,
+ERASE, 140163912978432, 140163912994815,
+STORE, 140163912978432, 140163912994815,
+SNULL, 140163912970239, 140163912978431,
+STORE, 140163912953856, 140163912970239,
+STORE, 140163912970240, 140163912978431,
+SNULL, 94615307472895, 94615307476991,
+STORE, 94615307464704, 94615307472895,
+STORE, 94615307472896, 94615307476991,
+SNULL, 140163915239423, 140163915243519,
+STORE, 140163915235328, 140163915239423,
+STORE, 140163915239424, 140163915243519,
+ERASE, 140163915206656, 140163915235327,
+STORE, 94615330672640, 94615330807807,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725254479872, 140737488351231,
+SNULL, 140725254488063, 140737488351231,
+STORE, 140725254479872, 140725254488063,
+STORE, 140725254348800, 140725254488063,
+STORE, 94572781277184, 94572785741823,
+SNULL, 94572783312895, 94572785741823,
+STORE, 94572781277184, 94572783312895,
+STORE, 94572783312896, 94572785741823,
+ERASE, 94572783312896, 94572785741823,
+STORE, 94572785405952, 94572785455103,
+STORE, 94572785455104, 94572785741823,
+STORE, 139636001341440, 139636003594239,
+SNULL, 139636001484799, 139636003594239,
+STORE, 139636001341440, 139636001484799,
+STORE, 139636001484800, 139636003594239,
+ERASE, 139636001484800, 139636003594239,
+STORE, 139636003581952, 139636003590143,
+STORE, 139636003590144, 139636003594239,
+STORE, 140725255557120, 140725255561215,
+STORE, 140725255544832, 140725255557119,
+STORE, 139636003553280, 139636003581951,
+STORE, 139636003545088, 139636003553279,
+STORE, 139635998773248, 139636001341439,
+SNULL, 139635998773248, 139635999240191,
+STORE, 139635999240192, 139636001341439,
+STORE, 139635998773248, 139635999240191,
+SNULL, 139636001333247, 139636001341439,
+STORE, 139635999240192, 139636001333247,
+STORE, 139636001333248, 139636001341439,
+ERASE, 139636001333248, 139636001341439,
+STORE, 139636001333248, 139636001341439,
+STORE, 139635996569600, 139635998773247,
+SNULL, 139635996569600, 139635996671999,
+STORE, 139635996672000, 139635998773247,
+STORE, 139635996569600, 139635996671999,
+SNULL, 139635998765055, 139635998773247,
+STORE, 139635996672000, 139635998765055,
+STORE, 139635998765056, 139635998773247,
+ERASE, 139635998765056, 139635998773247,
+STORE, 139635998765056, 139635998773247,
+STORE, 139635994353664, 139635996569599,
+SNULL, 139635994353664, 139635994451967,
+STORE, 139635994451968, 139635996569599,
+STORE, 139635994353664, 139635994451967,
+SNULL, 139635996545023, 139635996569599,
+STORE, 139635994451968, 139635996545023,
+STORE, 139635996545024, 139635996569599,
+SNULL, 139635996545024, 139635996553215,
+STORE, 139635996553216, 139635996569599,
+STORE, 139635996545024, 139635996553215,
+ERASE, 139635996545024, 139635996553215,
+STORE, 139635996545024, 139635996553215,
+ERASE, 139635996553216, 139635996569599,
+STORE, 139635996553216, 139635996569599,
+STORE, 139635992223744, 139635994353663,
+SNULL, 139635992223744, 139635992252415,
+STORE, 139635992252416, 139635994353663,
+STORE, 139635992223744, 139635992252415,
+SNULL, 139635994345471, 139635994353663,
+STORE, 139635992252416, 139635994345471,
+STORE, 139635994345472, 139635994353663,
+ERASE, 139635994345472, 139635994353663,
+STORE, 139635994345472, 139635994353663,
+STORE, 139635988426752, 139635992223743,
+SNULL, 139635988426752, 139635990085631,
+STORE, 139635990085632, 139635992223743,
+STORE, 139635988426752, 139635990085631,
+SNULL, 139635992182783, 139635992223743,
+STORE, 139635990085632, 139635992182783,
+STORE, 139635992182784, 139635992223743,
+SNULL, 139635992182784, 139635992207359,
+STORE, 139635992207360, 139635992223743,
+STORE, 139635992182784, 139635992207359,
+ERASE, 139635992182784, 139635992207359,
+STORE, 139635992182784, 139635992207359,
+ERASE, 139635992207360, 139635992223743,
+STORE, 139635992207360, 139635992223743,
+STORE, 139636003536896, 139636003553279,
+SNULL, 139635992199167, 139635992207359,
+STORE, 139635992182784, 139635992199167,
+STORE, 139635992199168, 139635992207359,
+SNULL, 139635996549119, 139635996553215,
+STORE, 139635996545024, 139635996549119,
+STORE, 139635996549120, 139635996553215,
+SNULL, 139635994349567, 139635994353663,
+STORE, 139635994345472, 139635994349567,
+STORE, 139635994349568, 139635994353663,
+SNULL, 139635998769151, 139635998773247,
+STORE, 139635998765056, 139635998769151,
+STORE, 139635998769152, 139635998773247,
+SNULL, 139636001337343, 139636001341439,
+STORE, 139636001333248, 139636001337343,
+STORE, 139636001337344, 139636001341439,
+SNULL, 94572785418239, 94572785455103,
+STORE, 94572785405952, 94572785418239,
+STORE, 94572785418240, 94572785455103,
+SNULL, 139636003586047, 139636003590143,
+STORE, 139636003581952, 139636003586047,
+STORE, 139636003586048, 139636003590143,
+ERASE, 139636003553280, 139636003581951,
+STORE, 94572798435328, 94572798570495,
+STORE, 139636001853440, 139636003536895,
+STORE, 139635981426688, 139635988426751,
+STORE, 139635980615680, 139635981426687,
+STORE, 94572798435328, 94572798705663,
+STORE, 94572798435328, 94572798840831,
+STORE, 94572798435328, 94572798975999,
+STORE, 94572798435328, 94572799111167,
+STORE, 94572798435328, 94572799246335,
+STORE, 94572798435328, 94572799381503,
+STORE, 94572798435328, 94572799516671,
+STORE, 94572798435328, 94572799651839,
+STORE, 94572798435328, 94572799787007,
+STORE, 94572798435328, 94572799922175,
+STORE, 94572798435328, 94572800057343,
+STORE, 94572798435328, 94572800192511,
+STORE, 94572798435328, 94572800327679,
+STORE, 94572798435328, 94572800462847,
+STORE, 94572798435328, 94572800598015,
+STORE, 94572798435328, 94572800733183,
+STORE, 94572798435328, 94572800868351,
+STORE, 94572798435328, 94572801003519,
+STORE, 94572798435328, 94572801138687,
+STORE, 94572798435328, 94572801273855,
+STORE, 94572798435328, 94572801409023,
+STORE, 94572798435328, 94572801544191,
+STORE, 94572798435328, 94572801679359,
+STORE, 94572798435328, 94572801814527,
+STORE, 94572798435328, 94572801949695,
+STORE, 94572798435328, 94572802084863,
+STORE, 94572798435328, 94572802220031,
+STORE, 94572798435328, 94572802355199,
+STORE, 94572798435328, 94572802490367,
+STORE, 94572798435328, 94572802625535,
+STORE, 94572798435328, 94572802760703,
+STORE, 94572798435328, 94572802895871,
+STORE, 94572798435328, 94572803031039,
+STORE, 94572798435328, 94572803166207,
+STORE, 94572798435328, 94572803301375,
+STORE, 94572798435328, 94572803436543,
+STORE, 94572798435328, 94572803571711,
+STORE, 94572798435328, 94572803706879,
+STORE, 94572798435328, 94572803842047,
+STORE, 94572798435328, 94572803977215,
+STORE, 94572798435328, 94572804112383,
+STORE, 94572798435328, 94572804247551,
+STORE, 94572798435328, 94572804382719,
+STORE, 94572798435328, 94572804517887,
+STORE, 94572798435328, 94572804653055,
+STORE, 94572798435328, 94572804788223,
+STORE, 94572798435328, 94572804923391,
+STORE, 94572798435328, 94572805058559,
+STORE, 94572798435328, 94572805193727,
+STORE, 94572798435328, 94572805328895,
+STORE, 94572798435328, 94572805464063,
+STORE, 94572798435328, 94572805599231,
+STORE, 94572798435328, 94572805734399,
+STORE, 94572798435328, 94572805869567,
+STORE, 94572798435328, 94572806004735,
+STORE, 94572798435328, 94572806139903,
+STORE, 94572798435328, 94572806275071,
+STORE, 94572798435328, 94572806410239,
+STORE, 94572798435328, 94572806545407,
+STORE, 94572798435328, 94572806680575,
+STORE, 94572798435328, 94572806815743,
+STORE, 94572798435328, 94572806950911,
+STORE, 94572798435328, 94572807086079,
+STORE, 94572798435328, 94572807221247,
+STORE, 94572798435328, 94572807356415,
+STORE, 94572798435328, 94572807491583,
+STORE, 94572798435328, 94572807626751,
+STORE, 94572798435328, 94572807761919,
+STORE, 94572798435328, 94572807897087,
+STORE, 94572798435328, 94572808032255,
+STORE, 94572798435328, 94572808167423,
+STORE, 94572798435328, 94572808302591,
+STORE, 94572798435328, 94572808437759,
+STORE, 94572798435328, 94572808572927,
+ERASE, 139635981426688, 139635988426751,
+STORE, 139635985088512, 139635988426751,
+STORE, 139635778273280, 139635980615679,
+STORE, 139635567632384, 139635778273279,
+STORE, 94572798435328, 94572808716287,
+STORE, 139635984564224, 139635985088511,
+STORE, 139635559239680, 139635567632383,
+SNULL, 139635559243775, 139635567632383,
+STORE, 139635559239680, 139635559243775,
+STORE, 139635559243776, 139635567632383,
+STORE, 139635550846976, 139635559239679,
+SNULL, 139635550851071, 139635559239679,
+STORE, 139635550846976, 139635550851071,
+STORE, 139635550851072, 139635559239679,
+STORE, 139635542454272, 139635550846975,
+STORE, 139635408236544, 139635542454271,
+SNULL, 139635408236544, 139635426590719,
+STORE, 139635426590720, 139635542454271,
+STORE, 139635408236544, 139635426590719,
+ERASE, 139635408236544, 139635426590719,
+STORE, 139635292372992, 139635542454271,
+SNULL, 139635359481855, 139635542454271,
+STORE, 139635292372992, 139635359481855,
+STORE, 139635359481856, 139635542454271,
+SNULL, 139635359481856, 139635426590719,
+STORE, 139635426590720, 139635542454271,
+STORE, 139635359481856, 139635426590719,
+ERASE, 139635359481856, 139635426590719,
+SNULL, 139635542458367, 139635550846975,
+STORE, 139635542454272, 139635542458367,
+STORE, 139635542458368, 139635550846975,
+STORE, 139635418198016, 139635426590719,
+SNULL, 139635493699583, 139635542454271,
+STORE, 139635426590720, 139635493699583,
+STORE, 139635493699584, 139635542454271,
+ERASE, 139635493699584, 139635542454271,
+SNULL, 139635426725887, 139635493699583,
+STORE, 139635426590720, 139635426725887,
+STORE, 139635426725888, 139635493699583,
+SNULL, 139635292508159, 139635359481855,
+STORE, 139635292372992, 139635292508159,
+STORE, 139635292508160, 139635359481855,
+SNULL, 139635418202111, 139635426590719,
+STORE, 139635418198016, 139635418202111,
+STORE, 139635418202112, 139635426590719,
+STORE, 139635225264128, 139635292372991,
+STORE, 139635534061568, 139635542454271,
+SNULL, 139635534065663, 139635542454271,
+STORE, 139635534061568, 139635534065663,
+STORE, 139635534065664, 139635542454271,
+STORE, 139635525668864, 139635534061567,
+SNULL, 139635525672959, 139635534061567,
+STORE, 139635525668864, 139635525672959,
+STORE, 139635525672960, 139635534061567,
+SNULL, 139635225399295, 139635292372991,
+STORE, 139635225264128, 139635225399295,
+STORE, 139635225399296, 139635292372991,
+STORE, 139635091046400, 139635225264127,
+SNULL, 139635158155263, 139635225264127,
+STORE, 139635091046400, 139635158155263,
+STORE, 139635158155264, 139635225264127,
+ERASE, 139635158155264, 139635225264127,
+STORE, 139634956828672, 139635158155263,
+STORE, 139635517276160, 139635525668863,
+SNULL, 139635517280255, 139635525668863,
+STORE, 139635517276160, 139635517280255,
+STORE, 139635517280256, 139635525668863,
+SNULL, 139634956828672, 139635091046399,
+STORE, 139635091046400, 139635158155263,
+STORE, 139634956828672, 139635091046399,
+SNULL, 139635091181567, 139635158155263,
+STORE, 139635091046400, 139635091181567,
+STORE, 139635091181568, 139635158155263,
+SNULL, 139635023937535, 139635091046399,
+STORE, 139634956828672, 139635023937535,
+STORE, 139635023937536, 139635091046399,
+ERASE, 139635023937536, 139635091046399,
+STORE, 139634956828672, 139635091046399,
+SNULL, 139634956828672, 139635023937535,
+STORE, 139635023937536, 139635091046399,
+STORE, 139634956828672, 139635023937535,
+SNULL, 139635024072703, 139635091046399,
+STORE, 139635023937536, 139635024072703,
+STORE, 139635024072704, 139635091046399,
+STORE, 139635508883456, 139635517276159,
+SNULL, 139635508887551, 139635517276159,
+STORE, 139635508883456, 139635508887551,
+STORE, 139635508887552, 139635517276159,
+STORE, 139634822610944, 139635023937535,
+SNULL, 139634822610944, 139634956828671,
+STORE, 139634956828672, 139635023937535,
+STORE, 139634822610944, 139634956828671,
+SNULL, 139634956963839, 139635023937535,
+STORE, 139634956828672, 139634956963839,
+STORE, 139634956963840, 139635023937535,
+STORE, 139635500490752, 139635508883455,
+SNULL, 139634889719807, 139634956828671,
+STORE, 139634822610944, 139634889719807,
+STORE, 139634889719808, 139634956828671,
+ERASE, 139634889719808, 139634956828671,
+SNULL, 139635500494847, 139635508883455,
+STORE, 139635500490752, 139635500494847,
+STORE, 139635500494848, 139635508883455,
+SNULL, 139634822746111, 139634889719807,
+STORE, 139634822610944, 139634822746111,
+STORE, 139634822746112, 139634889719807,
+STORE, 139635409805312, 139635418198015,
+STORE, 139634822746112, 139634956828671,
+SNULL, 139634822746112, 139634889719807,
+STORE, 139634889719808, 139634956828671,
+STORE, 139634822746112, 139634889719807,
+SNULL, 139634889854975, 139634956828671,
+STORE, 139634889719808, 139634889854975,
+STORE, 139634889854976, 139634956828671,
+SNULL, 139635409809407, 139635418198015,
+STORE, 139635409805312, 139635409809407,
+STORE, 139635409809408, 139635418198015,
+STORE, 139635401412608, 139635409805311,
+STORE, 139634688393216, 139634822610943,
+SNULL, 139634755502079, 139634822610943,
+STORE, 139634688393216, 139634755502079,
+STORE, 139634755502080, 139634822610943,
+ERASE, 139634755502080, 139634822610943,
+SNULL, 139635401416703, 139635409805311,
+STORE, 139635401412608, 139635401416703,
+STORE, 139635401416704, 139635409805311,
+STORE, 139634554175488, 139634755502079,
+SNULL, 139634554175488, 139634688393215,
+STORE, 139634688393216, 139634755502079,
+STORE, 139634554175488, 139634688393215,
+SNULL, 139634688528383, 139634755502079,
+STORE, 139634688393216, 139634688528383,
+STORE, 139634688528384, 139634755502079,
+STORE, 139635393019904, 139635401412607,
+SNULL, 139634621284351, 139634688393215,
+STORE, 139634554175488, 139634621284351,
+STORE, 139634621284352, 139634688393215,
+ERASE, 139634621284352, 139634688393215,
+SNULL, 139634554310655, 139634621284351,
+STORE, 139634554175488, 139634554310655,
+STORE, 139634554310656, 139634621284351,
+STORE, 139634554310656, 139634688393215,
+SNULL, 139635393023999, 139635401412607,
+STORE, 139635393019904, 139635393023999,
+STORE, 139635393024000, 139635401412607,
+SNULL, 139634554310656, 139634621284351,
+STORE, 139634621284352, 139634688393215,
+STORE, 139634554310656, 139634621284351,
+SNULL, 139634621419519, 139634688393215,
+STORE, 139634621284352, 139634621419519,
+STORE, 139634621419520, 139634688393215,
+STORE, 139635384627200, 139635393019903,
+SNULL, 139635384631295, 139635393019903,
+STORE, 139635384627200, 139635384631295,
+STORE, 139635384631296, 139635393019903,
+STORE, 139635376234496, 139635384627199,
+SNULL, 139635376238591, 139635384627199,
+STORE, 139635376234496, 139635376238591,
+STORE, 139635376238592, 139635384627199,
+STORE, 139635367841792, 139635376234495,
+SNULL, 139635367845887, 139635376234495,
+STORE, 139635367841792, 139635367845887,
+STORE, 139635367845888, 139635376234495,
+STORE, 139634419957760, 139634554175487,
+SNULL, 139634487066623, 139634554175487,
+STORE, 139634419957760, 139634487066623,
+STORE, 139634487066624, 139634554175487,
+ERASE, 139634487066624, 139634554175487,
+STORE, 139635216871424, 139635225264127,
+SNULL, 139635216875519, 139635225264127,
+STORE, 139635216871424, 139635216875519,
+STORE, 139635216875520, 139635225264127,
+SNULL, 139634420092927, 139634487066623,
+STORE, 139634419957760, 139634420092927,
+STORE, 139634420092928, 139634487066623,
+STORE, 139635208478720, 139635216871423,
+SNULL, 139635208482815, 139635216871423,
+STORE, 139635208478720, 139635208482815,
+STORE, 139635208482816, 139635216871423,
+STORE, 139635200086016, 139635208478719,
+SNULL, 139635200090111, 139635208478719,
+STORE, 139635200086016, 139635200090111,
+STORE, 139635200090112, 139635208478719,
+STORE, 139635191693312, 139635200086015,
+SNULL, 139635191697407, 139635200086015,
+STORE, 139635191693312, 139635191697407,
+STORE, 139635191697408, 139635200086015,
+STORE, 139635183300608, 139635191693311,
+SNULL, 139635183304703, 139635191693311,
+STORE, 139635183300608, 139635183304703,
+STORE, 139635183304704, 139635191693311,
+STORE, 139634420092928, 139634554175487,
+SNULL, 139634420092928, 139634487066623,
+STORE, 139634487066624, 139634554175487,
+STORE, 139634420092928, 139634487066623,
+SNULL, 139634487201791, 139634554175487,
+STORE, 139634487066624, 139634487201791,
+STORE, 139634487201792, 139634554175487,
+ERASE, 139635559239680, 139635559243775,
+ERASE, 139635559243776, 139635567632383,
+ERASE, 139635550846976, 139635550851071,
+ERASE, 139635550851072, 139635559239679,
+ERASE, 139635542454272, 139635542458367,
+ERASE, 139635542458368, 139635550846975,
+ERASE, 139635418198016, 139635418202111,
+ERASE, 139635418202112, 139635426590719,
+ERASE, 139635534061568, 139635534065663,
+ERASE, 139635534065664, 139635542454271,
+ERASE, 139635525668864, 139635525672959,
+ERASE, 139635525672960, 139635534061567,
+ERASE, 139635517276160, 139635517280255,
+ERASE, 139635517280256, 139635525668863,
+ERASE, 139635508883456, 139635508887551,
+ERASE, 139635508887552, 139635517276159,
+ERASE, 139635500490752, 139635500494847,
+ERASE, 139635500494848, 139635508883455,
+ERASE, 139635409805312, 139635409809407,
+ERASE, 139635409809408, 139635418198015,
+ERASE, 139635401412608, 139635401416703,
+ERASE, 139635401416704, 139635409805311,
+ERASE, 139635393019904, 139635393023999,
+ERASE, 139635393024000, 139635401412607,
+ERASE, 139635384627200, 139635384631295,
+ERASE, 139635384631296, 139635393019903,
+ };
+ unsigned long set25[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722547441664, 140737488351231,
+SNULL, 140722547449855, 140737488351231,
+STORE, 140722547441664, 140722547449855,
+STORE, 140722547310592, 140722547449855,
+STORE, 94827521732608, 94827523956735,
+SNULL, 94827521843199, 94827523956735,
+STORE, 94827521732608, 94827521843199,
+STORE, 94827521843200, 94827523956735,
+ERASE, 94827521843200, 94827523956735,
+STORE, 94827523936256, 94827523948543,
+STORE, 94827523948544, 94827523956735,
+STORE, 139816136847360, 139816139100159,
+SNULL, 139816136990719, 139816139100159,
+STORE, 139816136847360, 139816136990719,
+STORE, 139816136990720, 139816139100159,
+ERASE, 139816136990720, 139816139100159,
+STORE, 139816139087872, 139816139096063,
+STORE, 139816139096064, 139816139100159,
+STORE, 140722548142080, 140722548146175,
+STORE, 140722548129792, 140722548142079,
+STORE, 139816139059200, 139816139087871,
+STORE, 139816139051008, 139816139059199,
+STORE, 139816133050368, 139816136847359,
+SNULL, 139816133050368, 139816134709247,
+STORE, 139816134709248, 139816136847359,
+STORE, 139816133050368, 139816134709247,
+SNULL, 139816136806399, 139816136847359,
+STORE, 139816134709248, 139816136806399,
+STORE, 139816136806400, 139816136847359,
+SNULL, 139816136806400, 139816136830975,
+STORE, 139816136830976, 139816136847359,
+STORE, 139816136806400, 139816136830975,
+ERASE, 139816136806400, 139816136830975,
+STORE, 139816136806400, 139816136830975,
+ERASE, 139816136830976, 139816136847359,
+STORE, 139816136830976, 139816136847359,
+SNULL, 139816136822783, 139816136830975,
+STORE, 139816136806400, 139816136822783,
+STORE, 139816136822784, 139816136830975,
+SNULL, 94827523944447, 94827523948543,
+STORE, 94827523936256, 94827523944447,
+STORE, 94827523944448, 94827523948543,
+SNULL, 139816139091967, 139816139096063,
+STORE, 139816139087872, 139816139091967,
+STORE, 139816139091968, 139816139096063,
+ERASE, 139816139059200, 139816139087871,
+STORE, 94827534970880, 94827535106047,
+STORE, 94114394132480, 94114394345471,
+STORE, 94114396442624, 94114396446719,
+STORE, 94114396446720, 94114396454911,
+STORE, 94114396454912, 94114396467199,
+STORE, 94114421575680, 94114427715583,
+STORE, 139934313955328, 139934315614207,
+STORE, 139934315614208, 139934317711359,
+STORE, 139934317711360, 139934317727743,
+STORE, 139934317727744, 139934317735935,
+STORE, 139934317735936, 139934317752319,
+STORE, 139934317752320, 139934317764607,
+STORE, 139934317764608, 139934319857663,
+STORE, 139934319857664, 139934319861759,
+STORE, 139934319861760, 139934319865855,
+STORE, 139934319865856, 139934320009215,
+STORE, 139934320377856, 139934322061311,
+STORE, 139934322061312, 139934322077695,
+STORE, 139934322106368, 139934322110463,
+STORE, 139934322110464, 139934322114559,
+STORE, 139934322114560, 139934322118655,
+STORE, 140731200376832, 140731200516095,
+STORE, 140731200929792, 140731200942079,
+STORE, 140731200942080, 140731200946175,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140734133174272, 140737488351231,
+SNULL, 140734133182463, 140737488351231,
+STORE, 140734133174272, 140734133182463,
+STORE, 140734133043200, 140734133182463,
+STORE, 94412675600384, 94412677824511,
+SNULL, 94412675710975, 94412677824511,
+STORE, 94412675600384, 94412675710975,
+STORE, 94412675710976, 94412677824511,
+ERASE, 94412675710976, 94412677824511,
+STORE, 94412677804032, 94412677816319,
+STORE, 94412677816320, 94412677824511,
+STORE, 140320087945216, 140320090198015,
+SNULL, 140320088088575, 140320090198015,
+STORE, 140320087945216, 140320088088575,
+STORE, 140320088088576, 140320090198015,
+ERASE, 140320088088576, 140320090198015,
+STORE, 140320090185728, 140320090193919,
+STORE, 140320090193920, 140320090198015,
+STORE, 140734134591488, 140734134595583,
+STORE, 140734134579200, 140734134591487,
+STORE, 140320090157056, 140320090185727,
+STORE, 140320090148864, 140320090157055,
+STORE, 140320084148224, 140320087945215,
+SNULL, 140320084148224, 140320085807103,
+STORE, 140320085807104, 140320087945215,
+STORE, 140320084148224, 140320085807103,
+SNULL, 140320087904255, 140320087945215,
+STORE, 140320085807104, 140320087904255,
+STORE, 140320087904256, 140320087945215,
+SNULL, 140320087904256, 140320087928831,
+STORE, 140320087928832, 140320087945215,
+STORE, 140320087904256, 140320087928831,
+ERASE, 140320087904256, 140320087928831,
+STORE, 140320087904256, 140320087928831,
+ERASE, 140320087928832, 140320087945215,
+STORE, 140320087928832, 140320087945215,
+SNULL, 140320087920639, 140320087928831,
+STORE, 140320087904256, 140320087920639,
+STORE, 140320087920640, 140320087928831,
+SNULL, 94412677812223, 94412677816319,
+STORE, 94412677804032, 94412677812223,
+STORE, 94412677812224, 94412677816319,
+SNULL, 140320090189823, 140320090193919,
+STORE, 140320090185728, 140320090189823,
+STORE, 140320090189824, 140320090193919,
+ERASE, 140320090157056, 140320090185727,
+STORE, 94412684546048, 94412684681215,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723005485056, 140737488351231,
+SNULL, 140723005493247, 140737488351231,
+STORE, 140723005485056, 140723005493247,
+STORE, 140723005353984, 140723005493247,
+STORE, 94387431936000, 94387434160127,
+SNULL, 94387432046591, 94387434160127,
+STORE, 94387431936000, 94387432046591,
+STORE, 94387432046592, 94387434160127,
+ERASE, 94387432046592, 94387434160127,
+STORE, 94387434139648, 94387434151935,
+STORE, 94387434151936, 94387434160127,
+STORE, 140151675392000, 140151677644799,
+SNULL, 140151675535359, 140151677644799,
+STORE, 140151675392000, 140151675535359,
+STORE, 140151675535360, 140151677644799,
+ERASE, 140151675535360, 140151677644799,
+STORE, 140151677632512, 140151677640703,
+STORE, 140151677640704, 140151677644799,
+STORE, 140723005784064, 140723005788159,
+STORE, 140723005771776, 140723005784063,
+STORE, 140151677603840, 140151677632511,
+STORE, 140151677595648, 140151677603839,
+STORE, 140151671595008, 140151675391999,
+SNULL, 140151671595008, 140151673253887,
+STORE, 140151673253888, 140151675391999,
+STORE, 140151671595008, 140151673253887,
+SNULL, 140151675351039, 140151675391999,
+STORE, 140151673253888, 140151675351039,
+STORE, 140151675351040, 140151675391999,
+SNULL, 140151675351040, 140151675375615,
+STORE, 140151675375616, 140151675391999,
+STORE, 140151675351040, 140151675375615,
+ERASE, 140151675351040, 140151675375615,
+STORE, 140151675351040, 140151675375615,
+ERASE, 140151675375616, 140151675391999,
+STORE, 140151675375616, 140151675391999,
+SNULL, 140151675367423, 140151675375615,
+STORE, 140151675351040, 140151675367423,
+STORE, 140151675367424, 140151675375615,
+SNULL, 94387434147839, 94387434151935,
+STORE, 94387434139648, 94387434147839,
+STORE, 94387434147840, 94387434151935,
+SNULL, 140151677636607, 140151677640703,
+STORE, 140151677632512, 140151677636607,
+STORE, 140151677636608, 140151677640703,
+ERASE, 140151677603840, 140151677632511,
+STORE, 94387458818048, 94387458953215,
+STORE, 94909010997248, 94909011210239,
+STORE, 94909013307392, 94909013311487,
+STORE, 94909013311488, 94909013319679,
+STORE, 94909013319680, 94909013331967,
+STORE, 94909014827008, 94909023371263,
+STORE, 140712411975680, 140712413634559,
+STORE, 140712413634560, 140712415731711,
+STORE, 140712415731712, 140712415748095,
+STORE, 140712415748096, 140712415756287,
+STORE, 140712415756288, 140712415772671,
+STORE, 140712415772672, 140712415784959,
+STORE, 140712415784960, 140712417878015,
+STORE, 140712417878016, 140712417882111,
+STORE, 140712417882112, 140712417886207,
+STORE, 140712417886208, 140712418029567,
+STORE, 140712418398208, 140712420081663,
+STORE, 140712420081664, 140712420098047,
+STORE, 140712420126720, 140712420130815,
+STORE, 140712420130816, 140712420134911,
+STORE, 140712420134912, 140712420139007,
+STORE, 140729293111296, 140729293250559,
+STORE, 140729293307904, 140729293320191,
+STORE, 140729293320192, 140729293324287,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140720541691904, 140737488351231,
+SNULL, 140720541700095, 140737488351231,
+STORE, 140720541691904, 140720541700095,
+STORE, 140720541560832, 140720541700095,
+STORE, 94203603419136, 94203605643263,
+SNULL, 94203603529727, 94203605643263,
+STORE, 94203603419136, 94203603529727,
+STORE, 94203603529728, 94203605643263,
+ERASE, 94203603529728, 94203605643263,
+STORE, 94203605622784, 94203605635071,
+STORE, 94203605635072, 94203605643263,
+STORE, 139847623081984, 139847625334783,
+SNULL, 139847623225343, 139847625334783,
+STORE, 139847623081984, 139847623225343,
+STORE, 139847623225344, 139847625334783,
+ERASE, 139847623225344, 139847625334783,
+STORE, 139847625322496, 139847625330687,
+STORE, 139847625330688, 139847625334783,
+STORE, 140720542547968, 140720542552063,
+STORE, 140720542535680, 140720542547967,
+STORE, 139847625293824, 139847625322495,
+STORE, 139847625285632, 139847625293823,
+STORE, 139847619284992, 139847623081983,
+SNULL, 139847619284992, 139847620943871,
+STORE, 139847620943872, 139847623081983,
+STORE, 139847619284992, 139847620943871,
+SNULL, 139847623041023, 139847623081983,
+STORE, 139847620943872, 139847623041023,
+STORE, 139847623041024, 139847623081983,
+SNULL, 139847623041024, 139847623065599,
+STORE, 139847623065600, 139847623081983,
+STORE, 139847623041024, 139847623065599,
+ERASE, 139847623041024, 139847623065599,
+STORE, 139847623041024, 139847623065599,
+ERASE, 139847623065600, 139847623081983,
+STORE, 139847623065600, 139847623081983,
+SNULL, 139847623057407, 139847623065599,
+STORE, 139847623041024, 139847623057407,
+STORE, 139847623057408, 139847623065599,
+SNULL, 94203605630975, 94203605635071,
+STORE, 94203605622784, 94203605630975,
+STORE, 94203605630976, 94203605635071,
+SNULL, 139847625326591, 139847625330687,
+STORE, 139847625322496, 139847625326591,
+STORE, 139847625326592, 139847625330687,
+ERASE, 139847625293824, 139847625322495,
+STORE, 94203634880512, 94203635015679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721428738048, 140737488351231,
+SNULL, 140721428746239, 140737488351231,
+STORE, 140721428738048, 140721428746239,
+STORE, 140721428606976, 140721428746239,
+STORE, 93968808378368, 93968810602495,
+SNULL, 93968808488959, 93968810602495,
+STORE, 93968808378368, 93968808488959,
+STORE, 93968808488960, 93968810602495,
+ERASE, 93968808488960, 93968810602495,
+STORE, 93968810582016, 93968810594303,
+STORE, 93968810594304, 93968810602495,
+STORE, 140397757026304, 140397759279103,
+SNULL, 140397757169663, 140397759279103,
+STORE, 140397757026304, 140397757169663,
+STORE, 140397757169664, 140397759279103,
+ERASE, 140397757169664, 140397759279103,
+STORE, 140397759266816, 140397759275007,
+STORE, 140397759275008, 140397759279103,
+STORE, 140721430368256, 140721430372351,
+STORE, 140721430355968, 140721430368255,
+STORE, 140397759238144, 140397759266815,
+STORE, 140397759229952, 140397759238143,
+STORE, 140397753229312, 140397757026303,
+SNULL, 140397753229312, 140397754888191,
+STORE, 140397754888192, 140397757026303,
+STORE, 140397753229312, 140397754888191,
+SNULL, 140397756985343, 140397757026303,
+STORE, 140397754888192, 140397756985343,
+STORE, 140397756985344, 140397757026303,
+SNULL, 140397756985344, 140397757009919,
+STORE, 140397757009920, 140397757026303,
+STORE, 140397756985344, 140397757009919,
+ERASE, 140397756985344, 140397757009919,
+STORE, 140397756985344, 140397757009919,
+ERASE, 140397757009920, 140397757026303,
+STORE, 140397757009920, 140397757026303,
+SNULL, 140397757001727, 140397757009919,
+STORE, 140397756985344, 140397757001727,
+STORE, 140397757001728, 140397757009919,
+SNULL, 93968810590207, 93968810594303,
+STORE, 93968810582016, 93968810590207,
+STORE, 93968810590208, 93968810594303,
+SNULL, 140397759270911, 140397759275007,
+STORE, 140397759266816, 140397759270911,
+STORE, 140397759270912, 140397759275007,
+ERASE, 140397759238144, 140397759266815,
+STORE, 93968837025792, 93968837160959,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721751044096, 140737488351231,
+SNULL, 140721751052287, 140737488351231,
+STORE, 140721751044096, 140721751052287,
+STORE, 140721750913024, 140721751052287,
+STORE, 94426051657728, 94426053881855,
+SNULL, 94426051768319, 94426053881855,
+STORE, 94426051657728, 94426051768319,
+STORE, 94426051768320, 94426053881855,
+ERASE, 94426051768320, 94426053881855,
+STORE, 94426053861376, 94426053873663,
+STORE, 94426053873664, 94426053881855,
+STORE, 140228456181760, 140228458434559,
+SNULL, 140228456325119, 140228458434559,
+STORE, 140228456181760, 140228456325119,
+STORE, 140228456325120, 140228458434559,
+ERASE, 140228456325120, 140228458434559,
+STORE, 140228458422272, 140228458430463,
+STORE, 140228458430464, 140228458434559,
+STORE, 140721751117824, 140721751121919,
+STORE, 140721751105536, 140721751117823,
+STORE, 140228458393600, 140228458422271,
+STORE, 140228458385408, 140228458393599,
+STORE, 140228452384768, 140228456181759,
+SNULL, 140228452384768, 140228454043647,
+STORE, 140228454043648, 140228456181759,
+STORE, 140228452384768, 140228454043647,
+SNULL, 140228456140799, 140228456181759,
+STORE, 140228454043648, 140228456140799,
+STORE, 140228456140800, 140228456181759,
+SNULL, 140228456140800, 140228456165375,
+STORE, 140228456165376, 140228456181759,
+STORE, 140228456140800, 140228456165375,
+ERASE, 140228456140800, 140228456165375,
+STORE, 140228456140800, 140228456165375,
+ERASE, 140228456165376, 140228456181759,
+STORE, 140228456165376, 140228456181759,
+SNULL, 140228456157183, 140228456165375,
+STORE, 140228456140800, 140228456157183,
+STORE, 140228456157184, 140228456165375,
+SNULL, 94426053869567, 94426053873663,
+STORE, 94426053861376, 94426053869567,
+STORE, 94426053869568, 94426053873663,
+SNULL, 140228458426367, 140228458430463,
+STORE, 140228458422272, 140228458426367,
+STORE, 140228458426368, 140228458430463,
+ERASE, 140228458393600, 140228458422271,
+STORE, 94426073681920, 94426073817087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732727623680, 140737488351231,
+SNULL, 140732727631871, 140737488351231,
+STORE, 140732727623680, 140732727631871,
+STORE, 140732727492608, 140732727631871,
+STORE, 94537485996032, 94537488220159,
+SNULL, 94537486106623, 94537488220159,
+STORE, 94537485996032, 94537486106623,
+STORE, 94537486106624, 94537488220159,
+ERASE, 94537486106624, 94537488220159,
+STORE, 94537488199680, 94537488211967,
+STORE, 94537488211968, 94537488220159,
+STORE, 140446578036736, 140446580289535,
+SNULL, 140446578180095, 140446580289535,
+STORE, 140446578036736, 140446578180095,
+STORE, 140446578180096, 140446580289535,
+ERASE, 140446578180096, 140446580289535,
+STORE, 140446580277248, 140446580285439,
+STORE, 140446580285440, 140446580289535,
+STORE, 140732727758848, 140732727762943,
+STORE, 140732727746560, 140732727758847,
+STORE, 140446580248576, 140446580277247,
+STORE, 140446580240384, 140446580248575,
+STORE, 140446574239744, 140446578036735,
+SNULL, 140446574239744, 140446575898623,
+STORE, 140446575898624, 140446578036735,
+STORE, 140446574239744, 140446575898623,
+SNULL, 140446577995775, 140446578036735,
+STORE, 140446575898624, 140446577995775,
+STORE, 140446577995776, 140446578036735,
+SNULL, 140446577995776, 140446578020351,
+STORE, 140446578020352, 140446578036735,
+STORE, 140446577995776, 140446578020351,
+ERASE, 140446577995776, 140446578020351,
+STORE, 140446577995776, 140446578020351,
+ERASE, 140446578020352, 140446578036735,
+STORE, 140446578020352, 140446578036735,
+SNULL, 140446578012159, 140446578020351,
+STORE, 140446577995776, 140446578012159,
+STORE, 140446578012160, 140446578020351,
+SNULL, 94537488207871, 94537488211967,
+STORE, 94537488199680, 94537488207871,
+STORE, 94537488207872, 94537488211967,
+SNULL, 140446580281343, 140446580285439,
+STORE, 140446580277248, 140446580281343,
+STORE, 140446580281344, 140446580285439,
+ERASE, 140446580248576, 140446580277247,
+STORE, 94537489014784, 94537489149951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728766808064, 140737488351231,
+SNULL, 140728766816255, 140737488351231,
+STORE, 140728766808064, 140728766816255,
+STORE, 140728766676992, 140728766816255,
+STORE, 94418513866752, 94418516090879,
+SNULL, 94418513977343, 94418516090879,
+STORE, 94418513866752, 94418513977343,
+STORE, 94418513977344, 94418516090879,
+ERASE, 94418513977344, 94418516090879,
+STORE, 94418516070400, 94418516082687,
+STORE, 94418516082688, 94418516090879,
+STORE, 140556479520768, 140556481773567,
+SNULL, 140556479664127, 140556481773567,
+STORE, 140556479520768, 140556479664127,
+STORE, 140556479664128, 140556481773567,
+ERASE, 140556479664128, 140556481773567,
+STORE, 140556481761280, 140556481769471,
+STORE, 140556481769472, 140556481773567,
+STORE, 140728767148032, 140728767152127,
+STORE, 140728767135744, 140728767148031,
+STORE, 140556481732608, 140556481761279,
+STORE, 140556481724416, 140556481732607,
+STORE, 140556475723776, 140556479520767,
+SNULL, 140556475723776, 140556477382655,
+STORE, 140556477382656, 140556479520767,
+STORE, 140556475723776, 140556477382655,
+SNULL, 140556479479807, 140556479520767,
+STORE, 140556477382656, 140556479479807,
+STORE, 140556479479808, 140556479520767,
+SNULL, 140556479479808, 140556479504383,
+STORE, 140556479504384, 140556479520767,
+STORE, 140556479479808, 140556479504383,
+ERASE, 140556479479808, 140556479504383,
+STORE, 140556479479808, 140556479504383,
+ERASE, 140556479504384, 140556479520767,
+STORE, 140556479504384, 140556479520767,
+SNULL, 140556479496191, 140556479504383,
+STORE, 140556479479808, 140556479496191,
+STORE, 140556479496192, 140556479504383,
+SNULL, 94418516078591, 94418516082687,
+STORE, 94418516070400, 94418516078591,
+STORE, 94418516078592, 94418516082687,
+SNULL, 140556481765375, 140556481769471,
+STORE, 140556481761280, 140556481765375,
+STORE, 140556481765376, 140556481769471,
+ERASE, 140556481732608, 140556481761279,
+STORE, 94418541113344, 94418541248511,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723945873408, 140737488351231,
+SNULL, 140723945881599, 140737488351231,
+STORE, 140723945873408, 140723945881599,
+STORE, 140723945742336, 140723945881599,
+STORE, 94543169773568, 94543171997695,
+SNULL, 94543169884159, 94543171997695,
+STORE, 94543169773568, 94543169884159,
+STORE, 94543169884160, 94543171997695,
+ERASE, 94543169884160, 94543171997695,
+STORE, 94543171977216, 94543171989503,
+STORE, 94543171989504, 94543171997695,
+STORE, 139890420883456, 139890423136255,
+SNULL, 139890421026815, 139890423136255,
+STORE, 139890420883456, 139890421026815,
+STORE, 139890421026816, 139890423136255,
+ERASE, 139890421026816, 139890423136255,
+STORE, 139890423123968, 139890423132159,
+STORE, 139890423132160, 139890423136255,
+STORE, 140723946102784, 140723946106879,
+STORE, 140723946090496, 140723946102783,
+STORE, 139890423095296, 139890423123967,
+STORE, 139890423087104, 139890423095295,
+STORE, 139890417086464, 139890420883455,
+SNULL, 139890417086464, 139890418745343,
+STORE, 139890418745344, 139890420883455,
+STORE, 139890417086464, 139890418745343,
+SNULL, 139890420842495, 139890420883455,
+STORE, 139890418745344, 139890420842495,
+STORE, 139890420842496, 139890420883455,
+SNULL, 139890420842496, 139890420867071,
+STORE, 139890420867072, 139890420883455,
+STORE, 139890420842496, 139890420867071,
+ERASE, 139890420842496, 139890420867071,
+STORE, 139890420842496, 139890420867071,
+ERASE, 139890420867072, 139890420883455,
+STORE, 139890420867072, 139890420883455,
+SNULL, 139890420858879, 139890420867071,
+STORE, 139890420842496, 139890420858879,
+STORE, 139890420858880, 139890420867071,
+SNULL, 94543171985407, 94543171989503,
+STORE, 94543171977216, 94543171985407,
+STORE, 94543171985408, 94543171989503,
+SNULL, 139890423128063, 139890423132159,
+STORE, 139890423123968, 139890423128063,
+STORE, 139890423128064, 139890423132159,
+ERASE, 139890423095296, 139890423123967,
+STORE, 94543197097984, 94543197233151,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140736205979648, 140737488351231,
+SNULL, 140736205987839, 140737488351231,
+STORE, 140736205979648, 140736205987839,
+STORE, 140736205848576, 140736205987839,
+STORE, 94913209913344, 94913212137471,
+SNULL, 94913210023935, 94913212137471,
+STORE, 94913209913344, 94913210023935,
+STORE, 94913210023936, 94913212137471,
+ERASE, 94913210023936, 94913212137471,
+STORE, 94913212116992, 94913212129279,
+STORE, 94913212129280, 94913212137471,
+STORE, 140006323052544, 140006325305343,
+SNULL, 140006323195903, 140006325305343,
+STORE, 140006323052544, 140006323195903,
+STORE, 140006323195904, 140006325305343,
+ERASE, 140006323195904, 140006325305343,
+STORE, 140006325293056, 140006325301247,
+STORE, 140006325301248, 140006325305343,
+STORE, 140736206716928, 140736206721023,
+STORE, 140736206704640, 140736206716927,
+STORE, 140006325264384, 140006325293055,
+STORE, 140006325256192, 140006325264383,
+STORE, 140006319255552, 140006323052543,
+SNULL, 140006319255552, 140006320914431,
+STORE, 140006320914432, 140006323052543,
+STORE, 140006319255552, 140006320914431,
+SNULL, 140006323011583, 140006323052543,
+STORE, 140006320914432, 140006323011583,
+STORE, 140006323011584, 140006323052543,
+SNULL, 140006323011584, 140006323036159,
+STORE, 140006323036160, 140006323052543,
+STORE, 140006323011584, 140006323036159,
+ERASE, 140006323011584, 140006323036159,
+STORE, 140006323011584, 140006323036159,
+ERASE, 140006323036160, 140006323052543,
+STORE, 140006323036160, 140006323052543,
+SNULL, 140006323027967, 140006323036159,
+STORE, 140006323011584, 140006323027967,
+STORE, 140006323027968, 140006323036159,
+SNULL, 94913212125183, 94913212129279,
+STORE, 94913212116992, 94913212125183,
+STORE, 94913212125184, 94913212129279,
+SNULL, 140006325297151, 140006325301247,
+STORE, 140006325293056, 140006325297151,
+STORE, 140006325297152, 140006325301247,
+ERASE, 140006325264384, 140006325293055,
+STORE, 94913239932928, 94913240068095,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140726926897152, 140737488351231,
+SNULL, 140726926905343, 140737488351231,
+STORE, 140726926897152, 140726926905343,
+STORE, 140726926766080, 140726926905343,
+STORE, 94213246820352, 94213249044479,
+SNULL, 94213246930943, 94213249044479,
+STORE, 94213246820352, 94213246930943,
+STORE, 94213246930944, 94213249044479,
+ERASE, 94213246930944, 94213249044479,
+STORE, 94213249024000, 94213249036287,
+STORE, 94213249036288, 94213249044479,
+STORE, 140368830242816, 140368832495615,
+SNULL, 140368830386175, 140368832495615,
+STORE, 140368830242816, 140368830386175,
+STORE, 140368830386176, 140368832495615,
+ERASE, 140368830386176, 140368832495615,
+STORE, 140368832483328, 140368832491519,
+STORE, 140368832491520, 140368832495615,
+STORE, 140726926999552, 140726927003647,
+STORE, 140726926987264, 140726926999551,
+STORE, 140368832454656, 140368832483327,
+STORE, 140368832446464, 140368832454655,
+STORE, 140368826445824, 140368830242815,
+SNULL, 140368826445824, 140368828104703,
+STORE, 140368828104704, 140368830242815,
+STORE, 140368826445824, 140368828104703,
+SNULL, 140368830201855, 140368830242815,
+STORE, 140368828104704, 140368830201855,
+STORE, 140368830201856, 140368830242815,
+SNULL, 140368830201856, 140368830226431,
+STORE, 140368830226432, 140368830242815,
+STORE, 140368830201856, 140368830226431,
+ERASE, 140368830201856, 140368830226431,
+STORE, 140368830201856, 140368830226431,
+ERASE, 140368830226432, 140368830242815,
+STORE, 140368830226432, 140368830242815,
+SNULL, 140368830218239, 140368830226431,
+STORE, 140368830201856, 140368830218239,
+STORE, 140368830218240, 140368830226431,
+SNULL, 94213249032191, 94213249036287,
+STORE, 94213249024000, 94213249032191,
+STORE, 94213249032192, 94213249036287,
+SNULL, 140368832487423, 140368832491519,
+STORE, 140368832483328, 140368832487423,
+STORE, 140368832487424, 140368832491519,
+ERASE, 140368832454656, 140368832483327,
+STORE, 94213267435520, 94213267570687,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728954130432, 140737488351231,
+SNULL, 140728954138623, 140737488351231,
+STORE, 140728954130432, 140728954138623,
+STORE, 140728953999360, 140728954138623,
+STORE, 94672570966016, 94672573190143,
+SNULL, 94672571076607, 94672573190143,
+STORE, 94672570966016, 94672571076607,
+STORE, 94672571076608, 94672573190143,
+ERASE, 94672571076608, 94672573190143,
+STORE, 94672573169664, 94672573181951,
+STORE, 94672573181952, 94672573190143,
+STORE, 140201696735232, 140201698988031,
+SNULL, 140201696878591, 140201698988031,
+STORE, 140201696735232, 140201696878591,
+STORE, 140201696878592, 140201698988031,
+ERASE, 140201696878592, 140201698988031,
+STORE, 140201698975744, 140201698983935,
+STORE, 140201698983936, 140201698988031,
+STORE, 140728954163200, 140728954167295,
+STORE, 140728954150912, 140728954163199,
+STORE, 140201698947072, 140201698975743,
+STORE, 140201698938880, 140201698947071,
+STORE, 140201692938240, 140201696735231,
+SNULL, 140201692938240, 140201694597119,
+STORE, 140201694597120, 140201696735231,
+STORE, 140201692938240, 140201694597119,
+SNULL, 140201696694271, 140201696735231,
+STORE, 140201694597120, 140201696694271,
+STORE, 140201696694272, 140201696735231,
+SNULL, 140201696694272, 140201696718847,
+STORE, 140201696718848, 140201696735231,
+STORE, 140201696694272, 140201696718847,
+ERASE, 140201696694272, 140201696718847,
+STORE, 140201696694272, 140201696718847,
+ERASE, 140201696718848, 140201696735231,
+STORE, 140201696718848, 140201696735231,
+SNULL, 140201696710655, 140201696718847,
+STORE, 140201696694272, 140201696710655,
+STORE, 140201696710656, 140201696718847,
+SNULL, 94672573177855, 94672573181951,
+STORE, 94672573169664, 94672573177855,
+STORE, 94672573177856, 94672573181951,
+SNULL, 140201698979839, 140201698983935,
+STORE, 140201698975744, 140201698979839,
+STORE, 140201698979840, 140201698983935,
+ERASE, 140201698947072, 140201698975743,
+STORE, 94672595689472, 94672595824639,
+STORE, 94114394132480, 94114394345471,
+STORE, 94114396442624, 94114396446719,
+STORE, 94114396446720, 94114396454911,
+STORE, 94114396454912, 94114396467199,
+STORE, 94114421575680, 94114428256255,
+STORE, 139934313955328, 139934315614207,
+STORE, 139934315614208, 139934317711359,
+STORE, 139934317711360, 139934317727743,
+STORE, 139934317727744, 139934317735935,
+STORE, 139934317735936, 139934317752319,
+STORE, 139934317752320, 139934317764607,
+STORE, 139934317764608, 139934319857663,
+STORE, 139934319857664, 139934319861759,
+STORE, 139934319861760, 139934319865855,
+STORE, 139934319865856, 139934320009215,
+STORE, 139934320377856, 139934322061311,
+STORE, 139934322061312, 139934322077695,
+STORE, 139934322106368, 139934322110463,
+STORE, 139934322110464, 139934322114559,
+STORE, 139934322114560, 139934322118655,
+STORE, 140731200376832, 140731200516095,
+STORE, 140731200929792, 140731200942079,
+STORE, 140731200942080, 140731200946175,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721532362752, 140737488351231,
+SNULL, 140721532370943, 140737488351231,
+STORE, 140721532362752, 140721532370943,
+STORE, 140721532231680, 140721532370943,
+STORE, 94467222597632, 94467224821759,
+SNULL, 94467222708223, 94467224821759,
+STORE, 94467222597632, 94467222708223,
+STORE, 94467222708224, 94467224821759,
+ERASE, 94467222708224, 94467224821759,
+STORE, 94467224801280, 94467224813567,
+STORE, 94467224813568, 94467224821759,
+STORE, 140191433543680, 140191435796479,
+SNULL, 140191433687039, 140191435796479,
+STORE, 140191433543680, 140191433687039,
+STORE, 140191433687040, 140191435796479,
+ERASE, 140191433687040, 140191435796479,
+STORE, 140191435784192, 140191435792383,
+STORE, 140191435792384, 140191435796479,
+STORE, 140721533034496, 140721533038591,
+STORE, 140721533022208, 140721533034495,
+STORE, 140191435755520, 140191435784191,
+STORE, 140191435747328, 140191435755519,
+STORE, 140191429746688, 140191433543679,
+SNULL, 140191429746688, 140191431405567,
+STORE, 140191431405568, 140191433543679,
+STORE, 140191429746688, 140191431405567,
+SNULL, 140191433502719, 140191433543679,
+STORE, 140191431405568, 140191433502719,
+STORE, 140191433502720, 140191433543679,
+SNULL, 140191433502720, 140191433527295,
+STORE, 140191433527296, 140191433543679,
+STORE, 140191433502720, 140191433527295,
+ERASE, 140191433502720, 140191433527295,
+STORE, 140191433502720, 140191433527295,
+ERASE, 140191433527296, 140191433543679,
+STORE, 140191433527296, 140191433543679,
+SNULL, 140191433519103, 140191433527295,
+STORE, 140191433502720, 140191433519103,
+STORE, 140191433519104, 140191433527295,
+SNULL, 94467224809471, 94467224813567,
+STORE, 94467224801280, 94467224809471,
+STORE, 94467224809472, 94467224813567,
+SNULL, 140191435788287, 140191435792383,
+STORE, 140191435784192, 140191435788287,
+STORE, 140191435788288, 140191435792383,
+ERASE, 140191435755520, 140191435784191,
+STORE, 94467251847168, 94467251982335,
+STORE, 94367895400448, 94367895613439,
+STORE, 94367897710592, 94367897714687,
+STORE, 94367897714688, 94367897722879,
+STORE, 94367897722880, 94367897735167,
+STORE, 94367925264384, 94367926861823,
+STORE, 139801317548032, 139801319206911,
+STORE, 139801319206912, 139801321304063,
+STORE, 139801321304064, 139801321320447,
+STORE, 139801321320448, 139801321328639,
+STORE, 139801321328640, 139801321345023,
+STORE, 139801321345024, 139801321357311,
+STORE, 139801321357312, 139801323450367,
+STORE, 139801323450368, 139801323454463,
+STORE, 139801323454464, 139801323458559,
+STORE, 139801323458560, 139801323601919,
+STORE, 139801323970560, 139801325654015,
+STORE, 139801325654016, 139801325670399,
+STORE, 139801325699072, 139801325703167,
+STORE, 139801325703168, 139801325707263,
+STORE, 139801325707264, 139801325711359,
+STORE, 140724442861568, 140724443000831,
+STORE, 140724443611136, 140724443623423,
+STORE, 140724443623424, 140724443627519,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731353149440, 140737488351231,
+SNULL, 140731353157631, 140737488351231,
+STORE, 140731353149440, 140731353157631,
+STORE, 140731353018368, 140731353157631,
+STORE, 94310379503616, 94310381838335,
+SNULL, 94310379716607, 94310381838335,
+STORE, 94310379503616, 94310379716607,
+STORE, 94310379716608, 94310381838335,
+ERASE, 94310379716608, 94310381838335,
+STORE, 94310381813760, 94310381826047,
+STORE, 94310381826048, 94310381838335,
+STORE, 140515434659840, 140515436912639,
+SNULL, 140515434803199, 140515436912639,
+STORE, 140515434659840, 140515434803199,
+STORE, 140515434803200, 140515436912639,
+ERASE, 140515434803200, 140515436912639,
+STORE, 140515436900352, 140515436908543,
+STORE, 140515436908544, 140515436912639,
+STORE, 140731353886720, 140731353890815,
+STORE, 140731353874432, 140731353886719,
+STORE, 140515436871680, 140515436900351,
+STORE, 140515436863488, 140515436871679,
+STORE, 140515432546304, 140515434659839,
+SNULL, 140515432546304, 140515432558591,
+STORE, 140515432558592, 140515434659839,
+STORE, 140515432546304, 140515432558591,
+SNULL, 140515434651647, 140515434659839,
+STORE, 140515432558592, 140515434651647,
+STORE, 140515434651648, 140515434659839,
+ERASE, 140515434651648, 140515434659839,
+STORE, 140515434651648, 140515434659839,
+STORE, 140515428749312, 140515432546303,
+SNULL, 140515428749312, 140515430408191,
+STORE, 140515430408192, 140515432546303,
+STORE, 140515428749312, 140515430408191,
+SNULL, 140515432505343, 140515432546303,
+STORE, 140515430408192, 140515432505343,
+STORE, 140515432505344, 140515432546303,
+SNULL, 140515432505344, 140515432529919,
+STORE, 140515432529920, 140515432546303,
+STORE, 140515432505344, 140515432529919,
+ERASE, 140515432505344, 140515432529919,
+STORE, 140515432505344, 140515432529919,
+ERASE, 140515432529920, 140515432546303,
+STORE, 140515432529920, 140515432546303,
+STORE, 140515436855296, 140515436871679,
+SNULL, 140515432521727, 140515432529919,
+STORE, 140515432505344, 140515432521727,
+STORE, 140515432521728, 140515432529919,
+SNULL, 140515434655743, 140515434659839,
+STORE, 140515434651648, 140515434655743,
+STORE, 140515434655744, 140515434659839,
+SNULL, 94310381817855, 94310381826047,
+STORE, 94310381813760, 94310381817855,
+STORE, 94310381817856, 94310381826047,
+SNULL, 140515436904447, 140515436908543,
+STORE, 140515436900352, 140515436904447,
+STORE, 140515436904448, 140515436908543,
+ERASE, 140515436871680, 140515436900351,
+STORE, 94310395457536, 94310395592703,
+STORE, 140515435171840, 140515436855295,
+STORE, 94310395457536, 94310395727871,
+STORE, 94310395457536, 94310395863039,
+STORE, 94310395457536, 94310396047359,
+SNULL, 94310396022783, 94310396047359,
+STORE, 94310395457536, 94310396022783,
+STORE, 94310396022784, 94310396047359,
+ERASE, 94310396022784, 94310396047359,
+STORE, 94310395457536, 94310396157951,
+STORE, 94310395457536, 94310396293119,
+SNULL, 94310396276735, 94310396293119,
+STORE, 94310395457536, 94310396276735,
+STORE, 94310396276736, 94310396293119,
+ERASE, 94310396276736, 94310396293119,
+STORE, 94310395457536, 94310396411903,
+SNULL, 94310396383231, 94310396411903,
+STORE, 94310395457536, 94310396383231,
+STORE, 94310396383232, 94310396411903,
+ERASE, 94310396383232, 94310396411903,
+STORE, 94310395457536, 94310396522495,
+STORE, 94310395457536, 94310396674047,
+SNULL, 94310396657663, 94310396674047,
+STORE, 94310395457536, 94310396657663,
+STORE, 94310396657664, 94310396674047,
+ERASE, 94310396657664, 94310396674047,
+SNULL, 94310396624895, 94310396657663,
+STORE, 94310395457536, 94310396624895,
+STORE, 94310396624896, 94310396657663,
+ERASE, 94310396624896, 94310396657663,
+STORE, 94310395457536, 94310396776447,
+SNULL, 94310396764159, 94310396776447,
+STORE, 94310395457536, 94310396764159,
+STORE, 94310396764160, 94310396776447,
+ERASE, 94310396764160, 94310396776447,
+SNULL, 94310396739583, 94310396764159,
+STORE, 94310395457536, 94310396739583,
+STORE, 94310396739584, 94310396764159,
+ERASE, 94310396739584, 94310396764159,
+STORE, 94310395457536, 94310396882943,
+STORE, 94310395457536, 94310397018111,
+STORE, 94310395457536, 94310397161471,
+STORE, 94310395457536, 94310397300735,
+SNULL, 94310397292543, 94310397300735,
+STORE, 94310395457536, 94310397292543,
+STORE, 94310397292544, 94310397300735,
+ERASE, 94310397292544, 94310397300735,
+STORE, 94359222210560, 94359222423551,
+STORE, 94359224520704, 94359224524799,
+STORE, 94359224524800, 94359224532991,
+STORE, 94359224532992, 94359224545279,
+STORE, 94359238348800, 94359239385087,
+STORE, 140675699838976, 140675701497855,
+STORE, 140675701497856, 140675703595007,
+STORE, 140675703595008, 140675703611391,
+STORE, 140675703611392, 140675703619583,
+STORE, 140675703619584, 140675703635967,
+STORE, 140675703635968, 140675703648255,
+STORE, 140675703648256, 140675705741311,
+STORE, 140675705741312, 140675705745407,
+STORE, 140675705745408, 140675705749503,
+STORE, 140675705749504, 140675705892863,
+STORE, 140675706261504, 140675707944959,
+STORE, 140675707944960, 140675707961343,
+STORE, 140675707990016, 140675707994111,
+STORE, 140675707994112, 140675707998207,
+STORE, 140675707998208, 140675708002303,
+STORE, 140721324634112, 140721324773375,
+STORE, 140721324810240, 140721324822527,
+STORE, 140721324822528, 140721324826623,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724099678208, 140737488351231,
+SNULL, 140724099686399, 140737488351231,
+STORE, 140724099678208, 140724099686399,
+STORE, 140724099547136, 140724099686399,
+STORE, 94586638516224, 94586640850943,
+SNULL, 94586638729215, 94586640850943,
+STORE, 94586638516224, 94586638729215,
+STORE, 94586638729216, 94586640850943,
+ERASE, 94586638729216, 94586640850943,
+STORE, 94586640826368, 94586640838655,
+STORE, 94586640838656, 94586640850943,
+STORE, 140371033796608, 140371036049407,
+SNULL, 140371033939967, 140371036049407,
+STORE, 140371033796608, 140371033939967,
+STORE, 140371033939968, 140371036049407,
+ERASE, 140371033939968, 140371036049407,
+STORE, 140371036037120, 140371036045311,
+STORE, 140371036045312, 140371036049407,
+STORE, 140724100001792, 140724100005887,
+STORE, 140724099989504, 140724100001791,
+STORE, 140371036008448, 140371036037119,
+STORE, 140371036000256, 140371036008447,
+STORE, 140371031683072, 140371033796607,
+SNULL, 140371031683072, 140371031695359,
+STORE, 140371031695360, 140371033796607,
+STORE, 140371031683072, 140371031695359,
+SNULL, 140371033788415, 140371033796607,
+STORE, 140371031695360, 140371033788415,
+STORE, 140371033788416, 140371033796607,
+ERASE, 140371033788416, 140371033796607,
+STORE, 140371033788416, 140371033796607,
+STORE, 140371027886080, 140371031683071,
+SNULL, 140371027886080, 140371029544959,
+STORE, 140371029544960, 140371031683071,
+STORE, 140371027886080, 140371029544959,
+SNULL, 140371031642111, 140371031683071,
+STORE, 140371029544960, 140371031642111,
+STORE, 140371031642112, 140371031683071,
+SNULL, 140371031642112, 140371031666687,
+STORE, 140371031666688, 140371031683071,
+STORE, 140371031642112, 140371031666687,
+ERASE, 140371031642112, 140371031666687,
+STORE, 140371031642112, 140371031666687,
+ERASE, 140371031666688, 140371031683071,
+STORE, 140371031666688, 140371031683071,
+STORE, 140371035992064, 140371036008447,
+SNULL, 140371031658495, 140371031666687,
+STORE, 140371031642112, 140371031658495,
+STORE, 140371031658496, 140371031666687,
+SNULL, 140371033792511, 140371033796607,
+STORE, 140371033788416, 140371033792511,
+STORE, 140371033792512, 140371033796607,
+SNULL, 94586640830463, 94586640838655,
+STORE, 94586640826368, 94586640830463,
+STORE, 94586640830464, 94586640838655,
+SNULL, 140371036041215, 140371036045311,
+STORE, 140371036037120, 140371036041215,
+STORE, 140371036041216, 140371036045311,
+ERASE, 140371036008448, 140371036037119,
+STORE, 94586663849984, 94586663985151,
+STORE, 140371034308608, 140371035992063,
+STORE, 94586663849984, 94586664120319,
+STORE, 94586663849984, 94586664255487,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140727532937216, 140737488351231,
+SNULL, 140727532945407, 140737488351231,
+STORE, 140727532937216, 140727532945407,
+STORE, 140727532806144, 140727532945407,
+STORE, 94849780191232, 94849782525951,
+SNULL, 94849780404223, 94849782525951,
+STORE, 94849780191232, 94849780404223,
+STORE, 94849780404224, 94849782525951,
+ERASE, 94849780404224, 94849782525951,
+STORE, 94849782501376, 94849782513663,
+STORE, 94849782513664, 94849782525951,
+STORE, 140382070218752, 140382072471551,
+SNULL, 140382070362111, 140382072471551,
+STORE, 140382070218752, 140382070362111,
+STORE, 140382070362112, 140382072471551,
+ERASE, 140382070362112, 140382072471551,
+STORE, 140382072459264, 140382072467455,
+STORE, 140382072467456, 140382072471551,
+STORE, 140727533092864, 140727533096959,
+STORE, 140727533080576, 140727533092863,
+STORE, 140382072430592, 140382072459263,
+STORE, 140382072422400, 140382072430591,
+STORE, 140382068105216, 140382070218751,
+SNULL, 140382068105216, 140382068117503,
+STORE, 140382068117504, 140382070218751,
+STORE, 140382068105216, 140382068117503,
+SNULL, 140382070210559, 140382070218751,
+STORE, 140382068117504, 140382070210559,
+STORE, 140382070210560, 140382070218751,
+ERASE, 140382070210560, 140382070218751,
+STORE, 140382070210560, 140382070218751,
+STORE, 140382064308224, 140382068105215,
+SNULL, 140382064308224, 140382065967103,
+STORE, 140382065967104, 140382068105215,
+STORE, 140382064308224, 140382065967103,
+SNULL, 140382068064255, 140382068105215,
+STORE, 140382065967104, 140382068064255,
+STORE, 140382068064256, 140382068105215,
+SNULL, 140382068064256, 140382068088831,
+STORE, 140382068088832, 140382068105215,
+STORE, 140382068064256, 140382068088831,
+ERASE, 140382068064256, 140382068088831,
+STORE, 140382068064256, 140382068088831,
+ERASE, 140382068088832, 140382068105215,
+STORE, 140382068088832, 140382068105215,
+STORE, 140382072414208, 140382072430591,
+SNULL, 140382068080639, 140382068088831,
+STORE, 140382068064256, 140382068080639,
+STORE, 140382068080640, 140382068088831,
+SNULL, 140382070214655, 140382070218751,
+STORE, 140382070210560, 140382070214655,
+STORE, 140382070214656, 140382070218751,
+SNULL, 94849782505471, 94849782513663,
+STORE, 94849782501376, 94849782505471,
+STORE, 94849782505472, 94849782513663,
+SNULL, 140382072463359, 140382072467455,
+STORE, 140382072459264, 140382072463359,
+STORE, 140382072463360, 140382072467455,
+ERASE, 140382072430592, 140382072459263,
+STORE, 94849782845440, 94849782980607,
+STORE, 140382070730752, 140382072414207,
+STORE, 94849782845440, 94849783115775,
+STORE, 94849782845440, 94849783250943,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722594377728, 140737488351231,
+SNULL, 140722594385919, 140737488351231,
+STORE, 140722594377728, 140722594385919,
+STORE, 140722594246656, 140722594385919,
+STORE, 94421466353664, 94421468577791,
+SNULL, 94421466464255, 94421468577791,
+STORE, 94421466353664, 94421466464255,
+STORE, 94421466464256, 94421468577791,
+ERASE, 94421466464256, 94421468577791,
+STORE, 94421468557312, 94421468569599,
+STORE, 94421468569600, 94421468577791,
+STORE, 140345458057216, 140345460310015,
+SNULL, 140345458200575, 140345460310015,
+STORE, 140345458057216, 140345458200575,
+STORE, 140345458200576, 140345460310015,
+ERASE, 140345458200576, 140345460310015,
+STORE, 140345460297728, 140345460305919,
+STORE, 140345460305920, 140345460310015,
+STORE, 140722595557376, 140722595561471,
+STORE, 140722595545088, 140722595557375,
+STORE, 140345460269056, 140345460297727,
+STORE, 140345460260864, 140345460269055,
+STORE, 140345454260224, 140345458057215,
+SNULL, 140345454260224, 140345455919103,
+STORE, 140345455919104, 140345458057215,
+STORE, 140345454260224, 140345455919103,
+SNULL, 140345458016255, 140345458057215,
+STORE, 140345455919104, 140345458016255,
+STORE, 140345458016256, 140345458057215,
+SNULL, 140345458016256, 140345458040831,
+STORE, 140345458040832, 140345458057215,
+STORE, 140345458016256, 140345458040831,
+ERASE, 140345458016256, 140345458040831,
+STORE, 140345458016256, 140345458040831,
+ERASE, 140345458040832, 140345458057215,
+STORE, 140345458040832, 140345458057215,
+SNULL, 140345458032639, 140345458040831,
+STORE, 140345458016256, 140345458032639,
+STORE, 140345458032640, 140345458040831,
+SNULL, 94421468565503, 94421468569599,
+STORE, 94421468557312, 94421468565503,
+STORE, 94421468565504, 94421468569599,
+SNULL, 140345460301823, 140345460305919,
+STORE, 140345460297728, 140345460301823,
+STORE, 140345460301824, 140345460305919,
+ERASE, 140345460269056, 140345460297727,
+STORE, 94421496004608, 94421496139775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140726096302080, 140737488351231,
+SNULL, 140726096310271, 140737488351231,
+STORE, 140726096302080, 140726096310271,
+STORE, 140726096171008, 140726096310271,
+STORE, 94101992124416, 94101994459135,
+SNULL, 94101992337407, 94101994459135,
+STORE, 94101992124416, 94101992337407,
+STORE, 94101992337408, 94101994459135,
+ERASE, 94101992337408, 94101994459135,
+STORE, 94101994434560, 94101994446847,
+STORE, 94101994446848, 94101994459135,
+STORE, 140192085594112, 140192087846911,
+SNULL, 140192085737471, 140192087846911,
+STORE, 140192085594112, 140192085737471,
+STORE, 140192085737472, 140192087846911,
+ERASE, 140192085737472, 140192087846911,
+STORE, 140192087834624, 140192087842815,
+STORE, 140192087842816, 140192087846911,
+STORE, 140726096375808, 140726096379903,
+STORE, 140726096363520, 140726096375807,
+STORE, 140192087805952, 140192087834623,
+STORE, 140192087797760, 140192087805951,
+STORE, 140192083480576, 140192085594111,
+SNULL, 140192083480576, 140192083492863,
+STORE, 140192083492864, 140192085594111,
+STORE, 140192083480576, 140192083492863,
+SNULL, 140192085585919, 140192085594111,
+STORE, 140192083492864, 140192085585919,
+STORE, 140192085585920, 140192085594111,
+ERASE, 140192085585920, 140192085594111,
+STORE, 140192085585920, 140192085594111,
+STORE, 140192079683584, 140192083480575,
+SNULL, 140192079683584, 140192081342463,
+STORE, 140192081342464, 140192083480575,
+STORE, 140192079683584, 140192081342463,
+SNULL, 140192083439615, 140192083480575,
+STORE, 140192081342464, 140192083439615,
+STORE, 140192083439616, 140192083480575,
+SNULL, 140192083439616, 140192083464191,
+STORE, 140192083464192, 140192083480575,
+STORE, 140192083439616, 140192083464191,
+ERASE, 140192083439616, 140192083464191,
+STORE, 140192083439616, 140192083464191,
+ERASE, 140192083464192, 140192083480575,
+STORE, 140192083464192, 140192083480575,
+STORE, 140192087789568, 140192087805951,
+SNULL, 140192083455999, 140192083464191,
+STORE, 140192083439616, 140192083455999,
+STORE, 140192083456000, 140192083464191,
+SNULL, 140192085590015, 140192085594111,
+STORE, 140192085585920, 140192085590015,
+STORE, 140192085590016, 140192085594111,
+SNULL, 94101994438655, 94101994446847,
+STORE, 94101994434560, 94101994438655,
+STORE, 94101994438656, 94101994446847,
+SNULL, 140192087838719, 140192087842815,
+STORE, 140192087834624, 140192087838719,
+STORE, 140192087838720, 140192087842815,
+ERASE, 140192087805952, 140192087834623,
+STORE, 94102011887616, 94102012022783,
+STORE, 140192086106112, 140192087789567,
+STORE, 94102011887616, 94102012157951,
+STORE, 94102011887616, 94102012293119,
+STORE, 94102011887616, 94102012440575,
+SNULL, 94102012428287, 94102012440575,
+STORE, 94102011887616, 94102012428287,
+STORE, 94102012428288, 94102012440575,
+ERASE, 94102012428288, 94102012440575,
+STORE, 94102011887616, 94102012579839,
+STORE, 94102011887616, 94102012715007,
+SNULL, 94102012694527, 94102012715007,
+STORE, 94102011887616, 94102012694527,
+STORE, 94102012694528, 94102012715007,
+ERASE, 94102012694528, 94102012715007,
+STORE, 94102011887616, 94102012833791,
+STORE, 94102011887616, 94102012968959,
+SNULL, 94102012927999, 94102012968959,
+STORE, 94102011887616, 94102012927999,
+STORE, 94102012928000, 94102012968959,
+ERASE, 94102012928000, 94102012968959,
+STORE, 94102011887616, 94102013091839,
+SNULL, 94102013075455, 94102013091839,
+STORE, 94102011887616, 94102013075455,
+STORE, 94102013075456, 94102013091839,
+ERASE, 94102013075456, 94102013091839,
+STORE, 94102011887616, 94102013210623,
+STORE, 94102011887616, 94102013345791,
+STORE, 93968727965696, 93968728178687,
+STORE, 93968730275840, 93968730279935,
+STORE, 93968730279936, 93968730288127,
+STORE, 93968730288128, 93968730300415,
+STORE, 93968731140096, 93968732704767,
+STORE, 140588443168768, 140588444827647,
+STORE, 140588444827648, 140588446924799,
+STORE, 140588446924800, 140588446941183,
+STORE, 140588446941184, 140588446949375,
+STORE, 140588446949376, 140588446965759,
+STORE, 140588446965760, 140588446978047,
+STORE, 140588446978048, 140588449071103,
+STORE, 140588449071104, 140588449075199,
+STORE, 140588449075200, 140588449079295,
+STORE, 140588449079296, 140588449222655,
+STORE, 140588449591296, 140588451274751,
+STORE, 140588451274752, 140588451291135,
+STORE, 140588451319808, 140588451323903,
+STORE, 140588451323904, 140588451327999,
+STORE, 140588451328000, 140588451332095,
+STORE, 140733877239808, 140733877379071,
+STORE, 140733878702080, 140733878714367,
+STORE, 140733878714368, 140733878718463,
+STORE, 93968727965696, 93968728178687,
+STORE, 93968730275840, 93968730279935,
+STORE, 93968730279936, 93968730288127,
+STORE, 93968730288128, 93968730300415,
+STORE, 93968731140096, 93968732991487,
+STORE, 140588443168768, 140588444827647,
+STORE, 140588444827648, 140588446924799,
+STORE, 140588446924800, 140588446941183,
+STORE, 140588446941184, 140588446949375,
+STORE, 140588446949376, 140588446965759,
+STORE, 140588446965760, 140588446978047,
+STORE, 140588446978048, 140588449071103,
+STORE, 140588449071104, 140588449075199,
+STORE, 140588449075200, 140588449079295,
+STORE, 140588449079296, 140588449222655,
+STORE, 140588449591296, 140588451274751,
+STORE, 140588451274752, 140588451291135,
+STORE, 140588451319808, 140588451323903,
+STORE, 140588451323904, 140588451327999,
+STORE, 140588451328000, 140588451332095,
+STORE, 140733877239808, 140733877379071,
+STORE, 140733878702080, 140733878714367,
+STORE, 140733878714368, 140733878718463,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733054472192, 140737488351231,
+SNULL, 140733054480383, 140737488351231,
+STORE, 140733054472192, 140733054480383,
+STORE, 140733054341120, 140733054480383,
+STORE, 93992873623552, 93992875847679,
+SNULL, 93992873734143, 93992875847679,
+STORE, 93992873623552, 93992873734143,
+STORE, 93992873734144, 93992875847679,
+ERASE, 93992873734144, 93992875847679,
+STORE, 93992875827200, 93992875839487,
+STORE, 93992875839488, 93992875847679,
+STORE, 139790881488896, 139790883741695,
+SNULL, 139790881632255, 139790883741695,
+STORE, 139790881488896, 139790881632255,
+STORE, 139790881632256, 139790883741695,
+ERASE, 139790881632256, 139790883741695,
+STORE, 139790883729408, 139790883737599,
+STORE, 139790883737600, 139790883741695,
+STORE, 140733054754816, 140733054758911,
+STORE, 140733054742528, 140733054754815,
+STORE, 139790883700736, 139790883729407,
+STORE, 139790883692544, 139790883700735,
+STORE, 139790877691904, 139790881488895,
+SNULL, 139790877691904, 139790879350783,
+STORE, 139790879350784, 139790881488895,
+STORE, 139790877691904, 139790879350783,
+SNULL, 139790881447935, 139790881488895,
+STORE, 139790879350784, 139790881447935,
+STORE, 139790881447936, 139790881488895,
+SNULL, 139790881447936, 139790881472511,
+STORE, 139790881472512, 139790881488895,
+STORE, 139790881447936, 139790881472511,
+ERASE, 139790881447936, 139790881472511,
+STORE, 139790881447936, 139790881472511,
+ERASE, 139790881472512, 139790881488895,
+STORE, 139790881472512, 139790881488895,
+SNULL, 139790881464319, 139790881472511,
+STORE, 139790881447936, 139790881464319,
+STORE, 139790881464320, 139790881472511,
+SNULL, 93992875835391, 93992875839487,
+STORE, 93992875827200, 93992875835391,
+STORE, 93992875835392, 93992875839487,
+SNULL, 139790883733503, 139790883737599,
+STORE, 139790883729408, 139790883733503,
+STORE, 139790883733504, 139790883737599,
+ERASE, 139790883700736, 139790883729407,
+STORE, 93992877031424, 93992877166591,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728550887424, 140737488351231,
+SNULL, 140728550895615, 140737488351231,
+STORE, 140728550887424, 140728550895615,
+STORE, 140728550756352, 140728550895615,
+STORE, 94707634077696, 94707636301823,
+SNULL, 94707634188287, 94707636301823,
+STORE, 94707634077696, 94707634188287,
+STORE, 94707634188288, 94707636301823,
+ERASE, 94707634188288, 94707636301823,
+STORE, 94707636281344, 94707636293631,
+STORE, 94707636293632, 94707636301823,
+STORE, 140553545666560, 140553547919359,
+SNULL, 140553545809919, 140553547919359,
+STORE, 140553545666560, 140553545809919,
+STORE, 140553545809920, 140553547919359,
+ERASE, 140553545809920, 140553547919359,
+STORE, 140553547907072, 140553547915263,
+STORE, 140553547915264, 140553547919359,
+STORE, 140728552374272, 140728552378367,
+STORE, 140728552361984, 140728552374271,
+STORE, 140553547878400, 140553547907071,
+STORE, 140553547870208, 140553547878399,
+STORE, 140553541869568, 140553545666559,
+SNULL, 140553541869568, 140553543528447,
+STORE, 140553543528448, 140553545666559,
+STORE, 140553541869568, 140553543528447,
+SNULL, 140553545625599, 140553545666559,
+STORE, 140553543528448, 140553545625599,
+STORE, 140553545625600, 140553545666559,
+SNULL, 140553545625600, 140553545650175,
+STORE, 140553545650176, 140553545666559,
+STORE, 140553545625600, 140553545650175,
+ERASE, 140553545625600, 140553545650175,
+STORE, 140553545625600, 140553545650175,
+ERASE, 140553545650176, 140553545666559,
+STORE, 140553545650176, 140553545666559,
+SNULL, 140553545641983, 140553545650175,
+STORE, 140553545625600, 140553545641983,
+STORE, 140553545641984, 140553545650175,
+SNULL, 94707636289535, 94707636293631,
+STORE, 94707636281344, 94707636289535,
+STORE, 94707636289536, 94707636293631,
+SNULL, 140553547911167, 140553547915263,
+STORE, 140553547907072, 140553547911167,
+STORE, 140553547911168, 140553547915263,
+ERASE, 140553547878400, 140553547907071,
+STORE, 94707651411968, 94707651547135,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732168695808, 140737488351231,
+SNULL, 140732168703999, 140737488351231,
+STORE, 140732168695808, 140732168703999,
+STORE, 140732168564736, 140732168703999,
+STORE, 94454287859712, 94454290083839,
+SNULL, 94454287970303, 94454290083839,
+STORE, 94454287859712, 94454287970303,
+STORE, 94454287970304, 94454290083839,
+ERASE, 94454287970304, 94454290083839,
+STORE, 94454290063360, 94454290075647,
+STORE, 94454290075648, 94454290083839,
+STORE, 140564947107840, 140564949360639,
+SNULL, 140564947251199, 140564949360639,
+STORE, 140564947107840, 140564947251199,
+STORE, 140564947251200, 140564949360639,
+ERASE, 140564947251200, 140564949360639,
+STORE, 140564949348352, 140564949356543,
+STORE, 140564949356544, 140564949360639,
+STORE, 140732168843264, 140732168847359,
+STORE, 140732168830976, 140732168843263,
+STORE, 140564949319680, 140564949348351,
+STORE, 140564949311488, 140564949319679,
+STORE, 140564943310848, 140564947107839,
+SNULL, 140564943310848, 140564944969727,
+STORE, 140564944969728, 140564947107839,
+STORE, 140564943310848, 140564944969727,
+SNULL, 140564947066879, 140564947107839,
+STORE, 140564944969728, 140564947066879,
+STORE, 140564947066880, 140564947107839,
+SNULL, 140564947066880, 140564947091455,
+STORE, 140564947091456, 140564947107839,
+STORE, 140564947066880, 140564947091455,
+ERASE, 140564947066880, 140564947091455,
+STORE, 140564947066880, 140564947091455,
+ERASE, 140564947091456, 140564947107839,
+STORE, 140564947091456, 140564947107839,
+SNULL, 140564947083263, 140564947091455,
+STORE, 140564947066880, 140564947083263,
+STORE, 140564947083264, 140564947091455,
+SNULL, 94454290071551, 94454290075647,
+STORE, 94454290063360, 94454290071551,
+STORE, 94454290071552, 94454290075647,
+SNULL, 140564949352447, 140564949356543,
+STORE, 140564949348352, 140564949352447,
+STORE, 140564949352448, 140564949356543,
+ERASE, 140564949319680, 140564949348351,
+STORE, 94454316236800, 94454316371967,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735155617792, 140737488351231,
+SNULL, 140735155625983, 140737488351231,
+STORE, 140735155617792, 140735155625983,
+STORE, 140735155486720, 140735155625983,
+STORE, 93915969556480, 93915971780607,
+SNULL, 93915969667071, 93915971780607,
+STORE, 93915969556480, 93915969667071,
+STORE, 93915969667072, 93915971780607,
+ERASE, 93915969667072, 93915971780607,
+STORE, 93915971760128, 93915971772415,
+STORE, 93915971772416, 93915971780607,
+STORE, 140141164605440, 140141166858239,
+SNULL, 140141164748799, 140141166858239,
+STORE, 140141164605440, 140141164748799,
+STORE, 140141164748800, 140141166858239,
+ERASE, 140141164748800, 140141166858239,
+STORE, 140141166845952, 140141166854143,
+STORE, 140141166854144, 140141166858239,
+STORE, 140735155691520, 140735155695615,
+STORE, 140735155679232, 140735155691519,
+STORE, 140141166817280, 140141166845951,
+STORE, 140141166809088, 140141166817279,
+STORE, 140141160808448, 140141164605439,
+SNULL, 140141160808448, 140141162467327,
+STORE, 140141162467328, 140141164605439,
+STORE, 140141160808448, 140141162467327,
+SNULL, 140141164564479, 140141164605439,
+STORE, 140141162467328, 140141164564479,
+STORE, 140141164564480, 140141164605439,
+SNULL, 140141164564480, 140141164589055,
+STORE, 140141164589056, 140141164605439,
+STORE, 140141164564480, 140141164589055,
+ERASE, 140141164564480, 140141164589055,
+STORE, 140141164564480, 140141164589055,
+ERASE, 140141164589056, 140141164605439,
+STORE, 140141164589056, 140141164605439,
+SNULL, 140141164580863, 140141164589055,
+STORE, 140141164564480, 140141164580863,
+STORE, 140141164580864, 140141164589055,
+SNULL, 93915971768319, 93915971772415,
+STORE, 93915971760128, 93915971768319,
+STORE, 93915971768320, 93915971772415,
+SNULL, 140141166850047, 140141166854143,
+STORE, 140141166845952, 140141166850047,
+STORE, 140141166850048, 140141166854143,
+ERASE, 140141166817280, 140141166845951,
+STORE, 93916002775040, 93916002910207,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728988409856, 140737488351231,
+SNULL, 140728988418047, 140737488351231,
+STORE, 140728988409856, 140728988418047,
+STORE, 140728988278784, 140728988418047,
+STORE, 94021634813952, 94021637038079,
+SNULL, 94021634924543, 94021637038079,
+STORE, 94021634813952, 94021634924543,
+STORE, 94021634924544, 94021637038079,
+ERASE, 94021634924544, 94021637038079,
+STORE, 94021637017600, 94021637029887,
+STORE, 94021637029888, 94021637038079,
+STORE, 140638014038016, 140638016290815,
+SNULL, 140638014181375, 140638016290815,
+STORE, 140638014038016, 140638014181375,
+STORE, 140638014181376, 140638016290815,
+ERASE, 140638014181376, 140638016290815,
+STORE, 140638016278528, 140638016286719,
+STORE, 140638016286720, 140638016290815,
+STORE, 140728988536832, 140728988540927,
+STORE, 140728988524544, 140728988536831,
+STORE, 140638016249856, 140638016278527,
+STORE, 140638016241664, 140638016249855,
+STORE, 140638010241024, 140638014038015,
+SNULL, 140638010241024, 140638011899903,
+STORE, 140638011899904, 140638014038015,
+STORE, 140638010241024, 140638011899903,
+SNULL, 140638013997055, 140638014038015,
+STORE, 140638011899904, 140638013997055,
+STORE, 140638013997056, 140638014038015,
+SNULL, 140638013997056, 140638014021631,
+STORE, 140638014021632, 140638014038015,
+STORE, 140638013997056, 140638014021631,
+ERASE, 140638013997056, 140638014021631,
+STORE, 140638013997056, 140638014021631,
+ERASE, 140638014021632, 140638014038015,
+STORE, 140638014021632, 140638014038015,
+SNULL, 140638014013439, 140638014021631,
+STORE, 140638013997056, 140638014013439,
+STORE, 140638014013440, 140638014021631,
+SNULL, 94021637025791, 94021637029887,
+STORE, 94021637017600, 94021637025791,
+STORE, 94021637025792, 94021637029887,
+SNULL, 140638016282623, 140638016286719,
+STORE, 140638016278528, 140638016282623,
+STORE, 140638016282624, 140638016286719,
+ERASE, 140638016249856, 140638016278527,
+STORE, 94021643124736, 94021643259903,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731219275776, 140737488351231,
+SNULL, 140731219283967, 140737488351231,
+STORE, 140731219275776, 140731219283967,
+STORE, 140731219144704, 140731219283967,
+STORE, 93888803647488, 93888805871615,
+SNULL, 93888803758079, 93888805871615,
+STORE, 93888803647488, 93888803758079,
+STORE, 93888803758080, 93888805871615,
+ERASE, 93888803758080, 93888805871615,
+STORE, 93888805851136, 93888805863423,
+STORE, 93888805863424, 93888805871615,
+STORE, 139630576934912, 139630579187711,
+SNULL, 139630577078271, 139630579187711,
+STORE, 139630576934912, 139630577078271,
+STORE, 139630577078272, 139630579187711,
+ERASE, 139630577078272, 139630579187711,
+STORE, 139630579175424, 139630579183615,
+STORE, 139630579183616, 139630579187711,
+STORE, 140731219718144, 140731219722239,
+STORE, 140731219705856, 140731219718143,
+STORE, 139630579146752, 139630579175423,
+STORE, 139630579138560, 139630579146751,
+STORE, 139630573137920, 139630576934911,
+SNULL, 139630573137920, 139630574796799,
+STORE, 139630574796800, 139630576934911,
+STORE, 139630573137920, 139630574796799,
+SNULL, 139630576893951, 139630576934911,
+STORE, 139630574796800, 139630576893951,
+STORE, 139630576893952, 139630576934911,
+SNULL, 139630576893952, 139630576918527,
+STORE, 139630576918528, 139630576934911,
+STORE, 139630576893952, 139630576918527,
+ERASE, 139630576893952, 139630576918527,
+STORE, 139630576893952, 139630576918527,
+ERASE, 139630576918528, 139630576934911,
+STORE, 139630576918528, 139630576934911,
+SNULL, 139630576910335, 139630576918527,
+STORE, 139630576893952, 139630576910335,
+STORE, 139630576910336, 139630576918527,
+SNULL, 93888805859327, 93888805863423,
+STORE, 93888805851136, 93888805859327,
+STORE, 93888805859328, 93888805863423,
+SNULL, 139630579179519, 139630579183615,
+STORE, 139630579175424, 139630579179519,
+STORE, 139630579179520, 139630579183615,
+ERASE, 139630579146752, 139630579175423,
+STORE, 93888822235136, 93888822370303,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733391151104, 140737488351231,
+SNULL, 140733391159295, 140737488351231,
+STORE, 140733391151104, 140733391159295,
+STORE, 140733391020032, 140733391159295,
+STORE, 94393875324928, 94393877549055,
+SNULL, 94393875435519, 94393877549055,
+STORE, 94393875324928, 94393875435519,
+STORE, 94393875435520, 94393877549055,
+ERASE, 94393875435520, 94393877549055,
+STORE, 94393877528576, 94393877540863,
+STORE, 94393877540864, 94393877549055,
+STORE, 140292111740928, 140292113993727,
+SNULL, 140292111884287, 140292113993727,
+STORE, 140292111740928, 140292111884287,
+STORE, 140292111884288, 140292113993727,
+ERASE, 140292111884288, 140292113993727,
+STORE, 140292113981440, 140292113989631,
+STORE, 140292113989632, 140292113993727,
+STORE, 140733391532032, 140733391536127,
+STORE, 140733391519744, 140733391532031,
+STORE, 140292113952768, 140292113981439,
+STORE, 140292113944576, 140292113952767,
+STORE, 140292107943936, 140292111740927,
+SNULL, 140292107943936, 140292109602815,
+STORE, 140292109602816, 140292111740927,
+STORE, 140292107943936, 140292109602815,
+SNULL, 140292111699967, 140292111740927,
+STORE, 140292109602816, 140292111699967,
+STORE, 140292111699968, 140292111740927,
+SNULL, 140292111699968, 140292111724543,
+STORE, 140292111724544, 140292111740927,
+STORE, 140292111699968, 140292111724543,
+ERASE, 140292111699968, 140292111724543,
+STORE, 140292111699968, 140292111724543,
+ERASE, 140292111724544, 140292111740927,
+STORE, 140292111724544, 140292111740927,
+SNULL, 140292111716351, 140292111724543,
+STORE, 140292111699968, 140292111716351,
+STORE, 140292111716352, 140292111724543,
+SNULL, 94393877536767, 94393877540863,
+STORE, 94393877528576, 94393877536767,
+STORE, 94393877536768, 94393877540863,
+SNULL, 140292113985535, 140292113989631,
+STORE, 140292113981440, 140292113985535,
+STORE, 140292113985536, 140292113989631,
+ERASE, 140292113952768, 140292113981439,
+STORE, 94393909342208, 94393909477375,
+STORE, 94458367512576, 94458367725567,
+STORE, 94458369822720, 94458369826815,
+STORE, 94458369826816, 94458369835007,
+STORE, 94458369835008, 94458369847295,
+STORE, 94458393292800, 94458399666175,
+STORE, 140619773841408, 140619775500287,
+STORE, 140619775500288, 140619777597439,
+STORE, 140619777597440, 140619777613823,
+STORE, 140619777613824, 140619777622015,
+STORE, 140619777622016, 140619777638399,
+STORE, 140619777638400, 140619777650687,
+STORE, 140619777650688, 140619779743743,
+STORE, 140619779743744, 140619779747839,
+STORE, 140619779747840, 140619779751935,
+STORE, 140619779751936, 140619779895295,
+STORE, 140619780263936, 140619781947391,
+STORE, 140619781947392, 140619781963775,
+STORE, 140619781992448, 140619781996543,
+STORE, 140619781996544, 140619782000639,
+STORE, 140619782000640, 140619782004735,
+STORE, 140725811675136, 140725811814399,
+STORE, 140725812813824, 140725812826111,
+STORE, 140725812826112, 140725812830207,
+STORE, 94458367512576, 94458367725567,
+STORE, 94458369822720, 94458369826815,
+STORE, 94458369826816, 94458369835007,
+STORE, 94458369835008, 94458369847295,
+STORE, 94458393292800, 94458400366591,
+STORE, 140619773841408, 140619775500287,
+STORE, 140619775500288, 140619777597439,
+STORE, 140619777597440, 140619777613823,
+STORE, 140619777613824, 140619777622015,
+STORE, 140619777622016, 140619777638399,
+STORE, 140619777638400, 140619777650687,
+STORE, 140619777650688, 140619779743743,
+STORE, 140619779743744, 140619779747839,
+STORE, 140619779747840, 140619779751935,
+STORE, 140619779751936, 140619779895295,
+STORE, 140619780263936, 140619781947391,
+STORE, 140619781947392, 140619781963775,
+STORE, 140619781992448, 140619781996543,
+STORE, 140619781996544, 140619782000639,
+STORE, 140619782000640, 140619782004735,
+STORE, 140725811675136, 140725811814399,
+STORE, 140725812813824, 140725812826111,
+STORE, 140725812826112, 140725812830207,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728740679680, 140737488351231,
+SNULL, 140728740687871, 140737488351231,
+STORE, 140728740679680, 140728740687871,
+STORE, 140728740548608, 140728740687871,
+STORE, 94764075249664, 94764077473791,
+SNULL, 94764075360255, 94764077473791,
+STORE, 94764075249664, 94764075360255,
+STORE, 94764075360256, 94764077473791,
+ERASE, 94764075360256, 94764077473791,
+STORE, 94764077453312, 94764077465599,
+STORE, 94764077465600, 94764077473791,
+STORE, 139766406791168, 139766409043967,
+SNULL, 139766406934527, 139766409043967,
+STORE, 139766406791168, 139766406934527,
+STORE, 139766406934528, 139766409043967,
+ERASE, 139766406934528, 139766409043967,
+STORE, 139766409031680, 139766409039871,
+STORE, 139766409039872, 139766409043967,
+STORE, 140728740913152, 140728740917247,
+STORE, 140728740900864, 140728740913151,
+STORE, 139766409003008, 139766409031679,
+STORE, 139766408994816, 139766409003007,
+STORE, 139766402994176, 139766406791167,
+SNULL, 139766402994176, 139766404653055,
+STORE, 139766404653056, 139766406791167,
+STORE, 139766402994176, 139766404653055,
+SNULL, 139766406750207, 139766406791167,
+STORE, 139766404653056, 139766406750207,
+STORE, 139766406750208, 139766406791167,
+SNULL, 139766406750208, 139766406774783,
+STORE, 139766406774784, 139766406791167,
+STORE, 139766406750208, 139766406774783,
+ERASE, 139766406750208, 139766406774783,
+STORE, 139766406750208, 139766406774783,
+ERASE, 139766406774784, 139766406791167,
+STORE, 139766406774784, 139766406791167,
+SNULL, 139766406766591, 139766406774783,
+STORE, 139766406750208, 139766406766591,
+STORE, 139766406766592, 139766406774783,
+SNULL, 94764077461503, 94764077465599,
+STORE, 94764077453312, 94764077461503,
+STORE, 94764077461504, 94764077465599,
+SNULL, 139766409035775, 139766409039871,
+STORE, 139766409031680, 139766409035775,
+STORE, 139766409035776, 139766409039871,
+ERASE, 139766409003008, 139766409031679,
+STORE, 94764090458112, 94764090593279,
+STORE, 94758057480192, 94758057590783,
+STORE, 94758059683840, 94758059692031,
+STORE, 94758059692032, 94758059696127,
+STORE, 94758059696128, 94758059704319,
+STORE, 94758083215360, 94758083350527,
+STORE, 139951456772096, 139951458430975,
+STORE, 139951458430976, 139951460528127,
+STORE, 139951460528128, 139951460544511,
+STORE, 139951460544512, 139951460552703,
+STORE, 139951460552704, 139951460569087,
+STORE, 139951460569088, 139951460712447,
+STORE, 139951462772736, 139951462780927,
+STORE, 139951462809600, 139951462813695,
+STORE, 139951462813696, 139951462817791,
+STORE, 139951462817792, 139951462821887,
+STORE, 140734098313216, 140734098452479,
+STORE, 140734098911232, 140734098923519,
+STORE, 140734098923520, 140734098927615,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724904095744, 140737488351231,
+SNULL, 140724904103935, 140737488351231,
+STORE, 140724904095744, 140724904103935,
+STORE, 140724903964672, 140724904103935,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140408497864704, 140408500117503,
+SNULL, 140408498008063, 140408500117503,
+STORE, 140408497864704, 140408498008063,
+STORE, 140408498008064, 140408500117503,
+ERASE, 140408498008064, 140408500117503,
+STORE, 140408500105216, 140408500113407,
+STORE, 140408500113408, 140408500117503,
+STORE, 140724905369600, 140724905373695,
+STORE, 140724905357312, 140724905369599,
+STORE, 140408500076544, 140408500105215,
+STORE, 140408500068352, 140408500076543,
+STORE, 140408494702592, 140408497864703,
+SNULL, 140408494702592, 140408495763455,
+STORE, 140408495763456, 140408497864703,
+STORE, 140408494702592, 140408495763455,
+SNULL, 140408497856511, 140408497864703,
+STORE, 140408495763456, 140408497856511,
+STORE, 140408497856512, 140408497864703,
+ERASE, 140408497856512, 140408497864703,
+STORE, 140408497856512, 140408497864703,
+STORE, 140408490905600, 140408494702591,
+SNULL, 140408490905600, 140408492564479,
+STORE, 140408492564480, 140408494702591,
+STORE, 140408490905600, 140408492564479,
+SNULL, 140408494661631, 140408494702591,
+STORE, 140408492564480, 140408494661631,
+STORE, 140408494661632, 140408494702591,
+SNULL, 140408494661632, 140408494686207,
+STORE, 140408494686208, 140408494702591,
+STORE, 140408494661632, 140408494686207,
+ERASE, 140408494661632, 140408494686207,
+STORE, 140408494661632, 140408494686207,
+ERASE, 140408494686208, 140408494702591,
+STORE, 140408494686208, 140408494702591,
+STORE, 140408500056064, 140408500076543,
+SNULL, 140408494678015, 140408494686207,
+STORE, 140408494661632, 140408494678015,
+STORE, 140408494678016, 140408494686207,
+SNULL, 140408497860607, 140408497864703,
+STORE, 140408497856512, 140408497860607,
+STORE, 140408497860608, 140408497864703,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140408500109311, 140408500113407,
+STORE, 140408500105216, 140408500109311,
+STORE, 140408500109312, 140408500113407,
+ERASE, 140408500076544, 140408500105215,
+STORE, 25235456, 25370623,
+STORE, 25235456, 25518079,
+STORE, 140408498372608, 140408500056063,
+STORE, 94543937388544, 94543937499135,
+STORE, 94543939592192, 94543939600383,
+STORE, 94543939600384, 94543939604479,
+STORE, 94543939604480, 94543939612671,
+STORE, 94543941447680, 94543941582847,
+STORE, 140282621947904, 140282623606783,
+STORE, 140282623606784, 140282625703935,
+STORE, 140282625703936, 140282625720319,
+STORE, 140282625720320, 140282625728511,
+STORE, 140282625728512, 140282625744895,
+STORE, 140282625744896, 140282625888255,
+STORE, 140282627948544, 140282627956735,
+STORE, 140282627985408, 140282627989503,
+STORE, 140282627989504, 140282627993599,
+STORE, 140282627993600, 140282627997695,
+STORE, 140728295723008, 140728295862271,
+STORE, 140728296476672, 140728296488959,
+STORE, 140728296488960, 140728296493055,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431510691839,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431510691839,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140737488338944, 140737488351231,
+STORE, 140736944451584, 140737488351231,
+SNULL, 140736944463871, 140737488351231,
+STORE, 140736944451584, 140736944463871,
+STORE, 140736944320512, 140736944463871,
+STORE, 4194304, 26279935,
+STORE, 28372992, 28454911,
+STORE, 28454912, 29806591,
+STORE, 139693609893888, 139693612146687,
+SNULL, 139693610037247, 139693612146687,
+STORE, 139693609893888, 139693610037247,
+STORE, 139693610037248, 139693612146687,
+ERASE, 139693610037248, 139693612146687,
+STORE, 139693612134400, 139693612142591,
+STORE, 139693612142592, 139693612146687,
+STORE, 140736945152000, 140736945156095,
+STORE, 140736945139712, 140736945151999,
+STORE, 139693612105728, 139693612134399,
+STORE, 139693612097536, 139693612105727,
+STORE, 139693606060032, 139693609893887,
+SNULL, 139693606060032, 139693607768063,
+STORE, 139693607768064, 139693609893887,
+STORE, 139693606060032, 139693607768063,
+SNULL, 139693609861119, 139693609893887,
+STORE, 139693607768064, 139693609861119,
+STORE, 139693609861120, 139693609893887,
+ERASE, 139693609861120, 139693609893887,
+STORE, 139693609861120, 139693609893887,
+STORE, 139693603864576, 139693606060031,
+SNULL, 139693603864576, 139693603958783,
+STORE, 139693603958784, 139693606060031,
+STORE, 139693603864576, 139693603958783,
+SNULL, 139693606051839, 139693606060031,
+STORE, 139693603958784, 139693606051839,
+STORE, 139693606051840, 139693606060031,
+ERASE, 139693606051840, 139693606060031,
+STORE, 139693606051840, 139693606060031,
+STORE, 139693601345536, 139693603864575,
+SNULL, 139693601345536, 139693601759231,
+STORE, 139693601759232, 139693603864575,
+STORE, 139693601345536, 139693601759231,
+SNULL, 139693603852287, 139693603864575,
+STORE, 139693601759232, 139693603852287,
+STORE, 139693603852288, 139693603864575,
+ERASE, 139693603852288, 139693603864575,
+STORE, 139693603852288, 139693603864575,
+STORE, 139693598711808, 139693601345535,
+SNULL, 139693598711808, 139693599240191,
+STORE, 139693599240192, 139693601345535,
+STORE, 139693598711808, 139693599240191,
+SNULL, 139693601337343, 139693601345535,
+STORE, 139693599240192, 139693601337343,
+STORE, 139693601337344, 139693601345535,
+ERASE, 139693601337344, 139693601345535,
+STORE, 139693601337344, 139693601345535,
+STORE, 139693596598272, 139693598711807,
+SNULL, 139693596598272, 139693596610559,
+STORE, 139693596610560, 139693598711807,
+STORE, 139693596598272, 139693596610559,
+SNULL, 139693598703615, 139693598711807,
+STORE, 139693596610560, 139693598703615,
+STORE, 139693598703616, 139693598711807,
+ERASE, 139693598703616, 139693598711807,
+STORE, 139693598703616, 139693598711807,
+STORE, 139693594394624, 139693596598271,
+SNULL, 139693594394624, 139693594497023,
+STORE, 139693594497024, 139693596598271,
+STORE, 139693594394624, 139693594497023,
+SNULL, 139693596590079, 139693596598271,
+STORE, 139693594497024, 139693596590079,
+STORE, 139693596590080, 139693596598271,
+ERASE, 139693596590080, 139693596598271,
+STORE, 139693596590080, 139693596598271,
+STORE, 139693612089344, 139693612105727,
+STORE, 139693591232512, 139693594394623,
+SNULL, 139693591232512, 139693592293375,
+STORE, 139693592293376, 139693594394623,
+STORE, 139693591232512, 139693592293375,
+SNULL, 139693594386431, 139693594394623,
+STORE, 139693592293376, 139693594386431,
+STORE, 139693594386432, 139693594394623,
+ERASE, 139693594386432, 139693594394623,
+STORE, 139693594386432, 139693594394623,
+STORE, 139693587435520, 139693591232511,
+SNULL, 139693587435520, 139693589094399,
+STORE, 139693589094400, 139693591232511,
+STORE, 139693587435520, 139693589094399,
+SNULL, 139693591191551, 139693591232511,
+STORE, 139693589094400, 139693591191551,
+STORE, 139693591191552, 139693591232511,
+SNULL, 139693591191552, 139693591216127,
+STORE, 139693591216128, 139693591232511,
+STORE, 139693591191552, 139693591216127,
+ERASE, 139693591191552, 139693591216127,
+STORE, 139693591191552, 139693591216127,
+ERASE, 139693591216128, 139693591232511,
+STORE, 139693591216128, 139693591232511,
+STORE, 139693612077056, 139693612105727,
+SNULL, 139693591207935, 139693591216127,
+STORE, 139693591191552, 139693591207935,
+STORE, 139693591207936, 139693591216127,
+SNULL, 139693594390527, 139693594394623,
+STORE, 139693594386432, 139693594390527,
+STORE, 139693594390528, 139693594394623,
+SNULL, 139693596594175, 139693596598271,
+STORE, 139693596590080, 139693596594175,
+STORE, 139693596594176, 139693596598271,
+SNULL, 139693598707711, 139693598711807,
+STORE, 139693598703616, 139693598707711,
+STORE, 139693598707712, 139693598711807,
+SNULL, 139693601341439, 139693601345535,
+STORE, 139693601337344, 139693601341439,
+STORE, 139693601341440, 139693601345535,
+SNULL, 139693603860479, 139693603864575,
+STORE, 139693603852288, 139693603860479,
+STORE, 139693603860480, 139693603864575,
+SNULL, 139693606055935, 139693606060031,
+STORE, 139693606051840, 139693606055935,
+STORE, 139693606055936, 139693606060031,
+SNULL, 139693609865215, 139693609893887,
+STORE, 139693609861120, 139693609865215,
+STORE, 139693609865216, 139693609893887,
+SNULL, 28405759, 28454911,
+STORE, 28372992, 28405759,
+STORE, 28405760, 28454911,
+SNULL, 139693612138495, 139693612142591,
+STORE, 139693612134400, 139693612138495,
+STORE, 139693612138496, 139693612142591,
+ERASE, 139693612105728, 139693612134399,
+STORE, 39976960, 40112127,
+STORE, 139693610393600, 139693612077055,
+STORE, 139693612130304, 139693612134399,
+STORE, 139693610258432, 139693610393599,
+STORE, 39976960, 40255487,
+STORE, 139693585338368, 139693587435519,
+STORE, 139693612122112, 139693612134399,
+STORE, 139693612113920, 139693612134399,
+STORE, 139693612077056, 139693612113919,
+STORE, 139693610242048, 139693610393599,
+STORE, 39976960, 40390655,
+STORE, 39976960, 40546303,
+STORE, 139693610233856, 139693610393599,
+STORE, 139693610225664, 139693610393599,
+STORE, 39976960, 40714239,
+STORE, 139693610209280, 139693610393599,
+STORE, 39976960, 40861695,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431528759295,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140729993904128, 140737488351231,
+SNULL, 140729993912319, 140737488351231,
+STORE, 140729993904128, 140729993912319,
+STORE, 140729993773056, 140729993912319,
+STORE, 93926271991808, 93926274215935,
+SNULL, 93926272102399, 93926274215935,
+STORE, 93926271991808, 93926272102399,
+STORE, 93926272102400, 93926274215935,
+ERASE, 93926272102400, 93926274215935,
+STORE, 93926274195456, 93926274207743,
+STORE, 93926274207744, 93926274215935,
+STORE, 139962167296000, 139962169548799,
+SNULL, 139962167439359, 139962169548799,
+STORE, 139962167296000, 139962167439359,
+STORE, 139962167439360, 139962169548799,
+ERASE, 139962167439360, 139962169548799,
+STORE, 139962169536512, 139962169544703,
+STORE, 139962169544704, 139962169548799,
+STORE, 140729995096064, 140729995100159,
+STORE, 140729995083776, 140729995096063,
+STORE, 139962169507840, 139962169536511,
+STORE, 139962169499648, 139962169507839,
+STORE, 139962163499008, 139962167295999,
+SNULL, 139962163499008, 139962165157887,
+STORE, 139962165157888, 139962167295999,
+STORE, 139962163499008, 139962165157887,
+SNULL, 139962167255039, 139962167295999,
+STORE, 139962165157888, 139962167255039,
+STORE, 139962167255040, 139962167295999,
+SNULL, 139962167255040, 139962167279615,
+STORE, 139962167279616, 139962167295999,
+STORE, 139962167255040, 139962167279615,
+ERASE, 139962167255040, 139962167279615,
+STORE, 139962167255040, 139962167279615,
+ERASE, 139962167279616, 139962167295999,
+STORE, 139962167279616, 139962167295999,
+SNULL, 139962167271423, 139962167279615,
+STORE, 139962167255040, 139962167271423,
+STORE, 139962167271424, 139962167279615,
+SNULL, 93926274203647, 93926274207743,
+STORE, 93926274195456, 93926274203647,
+STORE, 93926274203648, 93926274207743,
+SNULL, 139962169540607, 139962169544703,
+STORE, 139962169536512, 139962169540607,
+STORE, 139962169540608, 139962169544703,
+ERASE, 139962169507840, 139962169536511,
+STORE, 93926291120128, 93926291255295,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724960579584, 140737488351231,
+SNULL, 140724960587775, 140737488351231,
+STORE, 140724960579584, 140724960587775,
+STORE, 140724960448512, 140724960587775,
+STORE, 94246489489408, 94246491713535,
+SNULL, 94246489599999, 94246491713535,
+STORE, 94246489489408, 94246489599999,
+STORE, 94246489600000, 94246491713535,
+ERASE, 94246489600000, 94246491713535,
+STORE, 94246491693056, 94246491705343,
+STORE, 94246491705344, 94246491713535,
+STORE, 140098174926848, 140098177179647,
+SNULL, 140098175070207, 140098177179647,
+STORE, 140098174926848, 140098175070207,
+STORE, 140098175070208, 140098177179647,
+ERASE, 140098175070208, 140098177179647,
+STORE, 140098177167360, 140098177175551,
+STORE, 140098177175552, 140098177179647,
+STORE, 140724961439744, 140724961443839,
+STORE, 140724961427456, 140724961439743,
+STORE, 140098177138688, 140098177167359,
+STORE, 140098177130496, 140098177138687,
+STORE, 140098171129856, 140098174926847,
+SNULL, 140098171129856, 140098172788735,
+STORE, 140098172788736, 140098174926847,
+STORE, 140098171129856, 140098172788735,
+SNULL, 140098174885887, 140098174926847,
+STORE, 140098172788736, 140098174885887,
+STORE, 140098174885888, 140098174926847,
+SNULL, 140098174885888, 140098174910463,
+STORE, 140098174910464, 140098174926847,
+STORE, 140098174885888, 140098174910463,
+ERASE, 140098174885888, 140098174910463,
+STORE, 140098174885888, 140098174910463,
+ERASE, 140098174910464, 140098174926847,
+STORE, 140098174910464, 140098174926847,
+SNULL, 140098174902271, 140098174910463,
+STORE, 140098174885888, 140098174902271,
+STORE, 140098174902272, 140098174910463,
+SNULL, 94246491701247, 94246491705343,
+STORE, 94246491693056, 94246491701247,
+STORE, 94246491701248, 94246491705343,
+SNULL, 140098177171455, 140098177175551,
+STORE, 140098177167360, 140098177171455,
+STORE, 140098177171456, 140098177175551,
+ERASE, 140098177138688, 140098177167359,
+STORE, 94246516998144, 94246517133311,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140730522918912, 140737488351231,
+SNULL, 140730522927103, 140737488351231,
+STORE, 140730522918912, 140730522927103,
+STORE, 140730522787840, 140730522927103,
+STORE, 94196043120640, 94196045344767,
+SNULL, 94196043231231, 94196045344767,
+STORE, 94196043120640, 94196043231231,
+STORE, 94196043231232, 94196045344767,
+ERASE, 94196043231232, 94196045344767,
+STORE, 94196045324288, 94196045336575,
+STORE, 94196045336576, 94196045344767,
+STORE, 139815918940160, 139815921192959,
+SNULL, 139815919083519, 139815921192959,
+STORE, 139815918940160, 139815919083519,
+STORE, 139815919083520, 139815921192959,
+ERASE, 139815919083520, 139815921192959,
+STORE, 139815921180672, 139815921188863,
+STORE, 139815921188864, 139815921192959,
+STORE, 140730523344896, 140730523348991,
+STORE, 140730523332608, 140730523344895,
+STORE, 139815921152000, 139815921180671,
+STORE, 139815921143808, 139815921151999,
+STORE, 139815915143168, 139815918940159,
+SNULL, 139815915143168, 139815916802047,
+STORE, 139815916802048, 139815918940159,
+STORE, 139815915143168, 139815916802047,
+SNULL, 139815918899199, 139815918940159,
+STORE, 139815916802048, 139815918899199,
+STORE, 139815918899200, 139815918940159,
+SNULL, 139815918899200, 139815918923775,
+STORE, 139815918923776, 139815918940159,
+STORE, 139815918899200, 139815918923775,
+ERASE, 139815918899200, 139815918923775,
+STORE, 139815918899200, 139815918923775,
+ERASE, 139815918923776, 139815918940159,
+STORE, 139815918923776, 139815918940159,
+SNULL, 139815918915583, 139815918923775,
+STORE, 139815918899200, 139815918915583,
+STORE, 139815918915584, 139815918923775,
+SNULL, 94196045332479, 94196045336575,
+STORE, 94196045324288, 94196045332479,
+STORE, 94196045332480, 94196045336575,
+SNULL, 139815921184767, 139815921188863,
+STORE, 139815921180672, 139815921184767,
+STORE, 139815921184768, 139815921188863,
+ERASE, 139815921152000, 139815921180671,
+STORE, 94196076183552, 94196076318719,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722460393472, 140737488351231,
+SNULL, 140722460401663, 140737488351231,
+STORE, 140722460393472, 140722460401663,
+STORE, 140722460262400, 140722460401663,
+STORE, 94569810399232, 94569812623359,
+SNULL, 94569810509823, 94569812623359,
+STORE, 94569810399232, 94569810509823,
+STORE, 94569810509824, 94569812623359,
+ERASE, 94569810509824, 94569812623359,
+STORE, 94569812602880, 94569812615167,
+STORE, 94569812615168, 94569812623359,
+STORE, 139681565450240, 139681567703039,
+SNULL, 139681565593599, 139681567703039,
+STORE, 139681565450240, 139681565593599,
+STORE, 139681565593600, 139681567703039,
+ERASE, 139681565593600, 139681567703039,
+STORE, 139681567690752, 139681567698943,
+STORE, 139681567698944, 139681567703039,
+STORE, 140722460569600, 140722460573695,
+STORE, 140722460557312, 140722460569599,
+STORE, 139681567662080, 139681567690751,
+STORE, 139681567653888, 139681567662079,
+STORE, 139681561653248, 139681565450239,
+SNULL, 139681561653248, 139681563312127,
+STORE, 139681563312128, 139681565450239,
+STORE, 139681561653248, 139681563312127,
+SNULL, 139681565409279, 139681565450239,
+STORE, 139681563312128, 139681565409279,
+STORE, 139681565409280, 139681565450239,
+SNULL, 139681565409280, 139681565433855,
+STORE, 139681565433856, 139681565450239,
+STORE, 139681565409280, 139681565433855,
+ERASE, 139681565409280, 139681565433855,
+STORE, 139681565409280, 139681565433855,
+ERASE, 139681565433856, 139681565450239,
+STORE, 139681565433856, 139681565450239,
+SNULL, 139681565425663, 139681565433855,
+STORE, 139681565409280, 139681565425663,
+STORE, 139681565425664, 139681565433855,
+SNULL, 94569812611071, 94569812615167,
+STORE, 94569812602880, 94569812611071,
+STORE, 94569812611072, 94569812615167,
+SNULL, 139681567694847, 139681567698943,
+STORE, 139681567690752, 139681567694847,
+STORE, 139681567694848, 139681567698943,
+ERASE, 139681567662080, 139681567690751,
+STORE, 94569818066944, 94569818202111,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431534280703,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725452365824, 140737488351231,
+SNULL, 140725452374015, 140737488351231,
+STORE, 140725452365824, 140725452374015,
+STORE, 140725452234752, 140725452374015,
+STORE, 94395067465728, 94395069689855,
+SNULL, 94395067576319, 94395069689855,
+STORE, 94395067465728, 94395067576319,
+STORE, 94395067576320, 94395069689855,
+ERASE, 94395067576320, 94395069689855,
+STORE, 94395069669376, 94395069681663,
+STORE, 94395069681664, 94395069689855,
+STORE, 140269941211136, 140269943463935,
+SNULL, 140269941354495, 140269943463935,
+STORE, 140269941211136, 140269941354495,
+STORE, 140269941354496, 140269943463935,
+ERASE, 140269941354496, 140269943463935,
+STORE, 140269943451648, 140269943459839,
+STORE, 140269943459840, 140269943463935,
+STORE, 140725452558336, 140725452562431,
+STORE, 140725452546048, 140725452558335,
+STORE, 140269943422976, 140269943451647,
+STORE, 140269943414784, 140269943422975,
+STORE, 140269937414144, 140269941211135,
+SNULL, 140269937414144, 140269939073023,
+STORE, 140269939073024, 140269941211135,
+STORE, 140269937414144, 140269939073023,
+SNULL, 140269941170175, 140269941211135,
+STORE, 140269939073024, 140269941170175,
+STORE, 140269941170176, 140269941211135,
+SNULL, 140269941170176, 140269941194751,
+STORE, 140269941194752, 140269941211135,
+STORE, 140269941170176, 140269941194751,
+ERASE, 140269941170176, 140269941194751,
+STORE, 140269941170176, 140269941194751,
+ERASE, 140269941194752, 140269941211135,
+STORE, 140269941194752, 140269941211135,
+SNULL, 140269941186559, 140269941194751,
+STORE, 140269941170176, 140269941186559,
+STORE, 140269941186560, 140269941194751,
+SNULL, 94395069677567, 94395069681663,
+STORE, 94395069669376, 94395069677567,
+STORE, 94395069677568, 94395069681663,
+SNULL, 140269943455743, 140269943459839,
+STORE, 140269943451648, 140269943455743,
+STORE, 140269943455744, 140269943459839,
+ERASE, 140269943422976, 140269943451647,
+STORE, 94395101691904, 94395101827071,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733860118528, 140737488351231,
+SNULL, 140733860126719, 140737488351231,
+STORE, 140733860118528, 140733860126719,
+STORE, 140733859987456, 140733860126719,
+STORE, 94484752990208, 94484755214335,
+SNULL, 94484753100799, 94484755214335,
+STORE, 94484752990208, 94484753100799,
+STORE, 94484753100800, 94484755214335,
+ERASE, 94484753100800, 94484755214335,
+STORE, 94484755193856, 94484755206143,
+STORE, 94484755206144, 94484755214335,
+STORE, 139958922309632, 139958924562431,
+SNULL, 139958922452991, 139958924562431,
+STORE, 139958922309632, 139958922452991,
+STORE, 139958922452992, 139958924562431,
+ERASE, 139958922452992, 139958924562431,
+STORE, 139958924550144, 139958924558335,
+STORE, 139958924558336, 139958924562431,
+STORE, 140733860253696, 140733860257791,
+STORE, 140733860241408, 140733860253695,
+STORE, 139958924521472, 139958924550143,
+STORE, 139958924513280, 139958924521471,
+STORE, 139958918512640, 139958922309631,
+SNULL, 139958918512640, 139958920171519,
+STORE, 139958920171520, 139958922309631,
+STORE, 139958918512640, 139958920171519,
+SNULL, 139958922268671, 139958922309631,
+STORE, 139958920171520, 139958922268671,
+STORE, 139958922268672, 139958922309631,
+SNULL, 139958922268672, 139958922293247,
+STORE, 139958922293248, 139958922309631,
+STORE, 139958922268672, 139958922293247,
+ERASE, 139958922268672, 139958922293247,
+STORE, 139958922268672, 139958922293247,
+ERASE, 139958922293248, 139958922309631,
+STORE, 139958922293248, 139958922309631,
+SNULL, 139958922285055, 139958922293247,
+STORE, 139958922268672, 139958922285055,
+STORE, 139958922285056, 139958922293247,
+SNULL, 94484755202047, 94484755206143,
+STORE, 94484755193856, 94484755202047,
+STORE, 94484755202048, 94484755206143,
+SNULL, 139958924554239, 139958924558335,
+STORE, 139958924550144, 139958924554239,
+STORE, 139958924554240, 139958924558335,
+ERASE, 139958924521472, 139958924550143,
+STORE, 94484777615360, 94484777750527,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731051036672, 140737488351231,
+SNULL, 140731051044863, 140737488351231,
+STORE, 140731051036672, 140731051044863,
+STORE, 140731050905600, 140731051044863,
+STORE, 93945822998528, 93945825222655,
+SNULL, 93945823109119, 93945825222655,
+STORE, 93945822998528, 93945823109119,
+STORE, 93945823109120, 93945825222655,
+ERASE, 93945823109120, 93945825222655,
+STORE, 93945825202176, 93945825214463,
+STORE, 93945825214464, 93945825222655,
+STORE, 140153503997952, 140153506250751,
+SNULL, 140153504141311, 140153506250751,
+STORE, 140153503997952, 140153504141311,
+STORE, 140153504141312, 140153506250751,
+ERASE, 140153504141312, 140153506250751,
+STORE, 140153506238464, 140153506246655,
+STORE, 140153506246656, 140153506250751,
+STORE, 140731051331584, 140731051335679,
+STORE, 140731051319296, 140731051331583,
+STORE, 140153506209792, 140153506238463,
+STORE, 140153506201600, 140153506209791,
+STORE, 140153500200960, 140153503997951,
+SNULL, 140153500200960, 140153501859839,
+STORE, 140153501859840, 140153503997951,
+STORE, 140153500200960, 140153501859839,
+SNULL, 140153503956991, 140153503997951,
+STORE, 140153501859840, 140153503956991,
+STORE, 140153503956992, 140153503997951,
+SNULL, 140153503956992, 140153503981567,
+STORE, 140153503981568, 140153503997951,
+STORE, 140153503956992, 140153503981567,
+ERASE, 140153503956992, 140153503981567,
+STORE, 140153503956992, 140153503981567,
+ERASE, 140153503981568, 140153503997951,
+STORE, 140153503981568, 140153503997951,
+SNULL, 140153503973375, 140153503981567,
+STORE, 140153503956992, 140153503973375,
+STORE, 140153503973376, 140153503981567,
+SNULL, 93945825210367, 93945825214463,
+STORE, 93945825202176, 93945825210367,
+STORE, 93945825210368, 93945825214463,
+SNULL, 140153506242559, 140153506246655,
+STORE, 140153506238464, 140153506242559,
+STORE, 140153506242560, 140153506246655,
+ERASE, 140153506209792, 140153506238463,
+STORE, 93945854537728, 93945854672895,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431537885183,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140736025325568, 140737488351231,
+SNULL, 140736025333759, 140737488351231,
+STORE, 140736025325568, 140736025333759,
+STORE, 140736025194496, 140736025333759,
+STORE, 94809095172096, 94809097396223,
+SNULL, 94809095282687, 94809097396223,
+STORE, 94809095172096, 94809095282687,
+STORE, 94809095282688, 94809097396223,
+ERASE, 94809095282688, 94809097396223,
+STORE, 94809097375744, 94809097388031,
+STORE, 94809097388032, 94809097396223,
+STORE, 140194992517120, 140194994769919,
+SNULL, 140194992660479, 140194994769919,
+STORE, 140194992517120, 140194992660479,
+STORE, 140194992660480, 140194994769919,
+ERASE, 140194992660480, 140194994769919,
+STORE, 140194994757632, 140194994765823,
+STORE, 140194994765824, 140194994769919,
+STORE, 140736026173440, 140736026177535,
+STORE, 140736026161152, 140736026173439,
+STORE, 140194994728960, 140194994757631,
+STORE, 140194994720768, 140194994728959,
+STORE, 140194988720128, 140194992517119,
+SNULL, 140194988720128, 140194990379007,
+STORE, 140194990379008, 140194992517119,
+STORE, 140194988720128, 140194990379007,
+SNULL, 140194992476159, 140194992517119,
+STORE, 140194990379008, 140194992476159,
+STORE, 140194992476160, 140194992517119,
+SNULL, 140194992476160, 140194992500735,
+STORE, 140194992500736, 140194992517119,
+STORE, 140194992476160, 140194992500735,
+ERASE, 140194992476160, 140194992500735,
+STORE, 140194992476160, 140194992500735,
+ERASE, 140194992500736, 140194992517119,
+STORE, 140194992500736, 140194992517119,
+SNULL, 140194992492543, 140194992500735,
+STORE, 140194992476160, 140194992492543,
+STORE, 140194992492544, 140194992500735,
+SNULL, 94809097383935, 94809097388031,
+STORE, 94809097375744, 94809097383935,
+STORE, 94809097383936, 94809097388031,
+SNULL, 140194994761727, 140194994765823,
+STORE, 140194994757632, 140194994761727,
+STORE, 140194994761728, 140194994765823,
+ERASE, 140194994728960, 140194994757631,
+STORE, 94809124286464, 94809124421631,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140726342660096, 140737488351231,
+SNULL, 140726342668287, 140737488351231,
+STORE, 140726342660096, 140726342668287,
+STORE, 140726342529024, 140726342668287,
+STORE, 94140331462656, 94140333686783,
+SNULL, 94140331573247, 94140333686783,
+STORE, 94140331462656, 94140331573247,
+STORE, 94140331573248, 94140333686783,
+ERASE, 94140331573248, 94140333686783,
+STORE, 94140333666304, 94140333678591,
+STORE, 94140333678592, 94140333686783,
+STORE, 140714077208576, 140714079461375,
+SNULL, 140714077351935, 140714079461375,
+STORE, 140714077208576, 140714077351935,
+STORE, 140714077351936, 140714079461375,
+ERASE, 140714077351936, 140714079461375,
+STORE, 140714079449088, 140714079457279,
+STORE, 140714079457280, 140714079461375,
+STORE, 140726343933952, 140726343938047,
+STORE, 140726343921664, 140726343933951,
+STORE, 140714079420416, 140714079449087,
+STORE, 140714079412224, 140714079420415,
+STORE, 140714073411584, 140714077208575,
+SNULL, 140714073411584, 140714075070463,
+STORE, 140714075070464, 140714077208575,
+STORE, 140714073411584, 140714075070463,
+SNULL, 140714077167615, 140714077208575,
+STORE, 140714075070464, 140714077167615,
+STORE, 140714077167616, 140714077208575,
+SNULL, 140714077167616, 140714077192191,
+STORE, 140714077192192, 140714077208575,
+STORE, 140714077167616, 140714077192191,
+ERASE, 140714077167616, 140714077192191,
+STORE, 140714077167616, 140714077192191,
+ERASE, 140714077192192, 140714077208575,
+STORE, 140714077192192, 140714077208575,
+SNULL, 140714077183999, 140714077192191,
+STORE, 140714077167616, 140714077183999,
+STORE, 140714077184000, 140714077192191,
+SNULL, 94140333674495, 94140333678591,
+STORE, 94140333666304, 94140333674495,
+STORE, 94140333674496, 94140333678591,
+SNULL, 140714079453183, 140714079457279,
+STORE, 140714079449088, 140714079453183,
+STORE, 140714079453184, 140714079457279,
+ERASE, 140714079420416, 140714079449087,
+STORE, 94140341432320, 94140341567487,
+STORE, 94431504838656, 94431505051647,
+STORE, 94431507148800, 94431507152895,
+STORE, 94431507152896, 94431507161087,
+STORE, 94431507161088, 94431507173375,
+STORE, 94431510286336, 94431539601407,
+STORE, 139818797948928, 139818799607807,
+STORE, 139818799607808, 139818801704959,
+STORE, 139818801704960, 139818801721343,
+STORE, 139818801721344, 139818801729535,
+STORE, 139818801729536, 139818801745919,
+STORE, 139818801745920, 139818801758207,
+STORE, 139818801758208, 139818803851263,
+STORE, 139818803851264, 139818803855359,
+STORE, 139818803855360, 139818803859455,
+STORE, 139818803859456, 139818804002815,
+STORE, 139818804371456, 139818806054911,
+STORE, 139818806054912, 139818806071295,
+STORE, 139818806099968, 139818806104063,
+STORE, 139818806104064, 139818806108159,
+STORE, 139818806108160, 139818806112255,
+STORE, 140731430457344, 140731430596607,
+STORE, 140731431227392, 140731431239679,
+STORE, 140731431239680, 140731431243775,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725843607552, 140737488351231,
+SNULL, 140725843615743, 140737488351231,
+STORE, 140725843607552, 140725843615743,
+STORE, 140725843476480, 140725843615743,
+STORE, 94889043505152, 94889045839871,
+SNULL, 94889043718143, 94889045839871,
+STORE, 94889043505152, 94889043718143,
+STORE, 94889043718144, 94889045839871,
+ERASE, 94889043718144, 94889045839871,
+STORE, 94889045815296, 94889045827583,
+STORE, 94889045827584, 94889045839871,
+STORE, 140250965946368, 140250968199167,
+SNULL, 140250966089727, 140250968199167,
+STORE, 140250965946368, 140250966089727,
+STORE, 140250966089728, 140250968199167,
+ERASE, 140250966089728, 140250968199167,
+STORE, 140250968186880, 140250968195071,
+STORE, 140250968195072, 140250968199167,
+STORE, 140725844500480, 140725844504575,
+STORE, 140725844488192, 140725844500479,
+STORE, 140250968158208, 140250968186879,
+STORE, 140250968150016, 140250968158207,
+STORE, 140250963832832, 140250965946367,
+SNULL, 140250963832832, 140250963845119,
+STORE, 140250963845120, 140250965946367,
+STORE, 140250963832832, 140250963845119,
+SNULL, 140250965938175, 140250965946367,
+STORE, 140250963845120, 140250965938175,
+STORE, 140250965938176, 140250965946367,
+ERASE, 140250965938176, 140250965946367,
+STORE, 140250965938176, 140250965946367,
+STORE, 140250960035840, 140250963832831,
+SNULL, 140250960035840, 140250961694719,
+STORE, 140250961694720, 140250963832831,
+STORE, 140250960035840, 140250961694719,
+SNULL, 140250963791871, 140250963832831,
+STORE, 140250961694720, 140250963791871,
+STORE, 140250963791872, 140250963832831,
+SNULL, 140250963791872, 140250963816447,
+STORE, 140250963816448, 140250963832831,
+STORE, 140250963791872, 140250963816447,
+ERASE, 140250963791872, 140250963816447,
+STORE, 140250963791872, 140250963816447,
+ERASE, 140250963816448, 140250963832831,
+STORE, 140250963816448, 140250963832831,
+STORE, 140250968141824, 140250968158207,
+SNULL, 140250963808255, 140250963816447,
+STORE, 140250963791872, 140250963808255,
+STORE, 140250963808256, 140250963816447,
+SNULL, 140250965942271, 140250965946367,
+STORE, 140250965938176, 140250965942271,
+STORE, 140250965942272, 140250965946367,
+SNULL, 94889045819391, 94889045827583,
+STORE, 94889045815296, 94889045819391,
+STORE, 94889045819392, 94889045827583,
+SNULL, 140250968190975, 140250968195071,
+STORE, 140250968186880, 140250968190975,
+STORE, 140250968190976, 140250968195071,
+ERASE, 140250968158208, 140250968186879,
+STORE, 94889052213248, 94889052348415,
+STORE, 140250966458368, 140250968141823,
+STORE, 94889052213248, 94889052483583,
+STORE, 94889052213248, 94889052618751,
+STORE, 94170851819520, 94170852032511,
+STORE, 94170854129664, 94170854133759,
+STORE, 94170854133760, 94170854141951,
+STORE, 94170854141952, 94170854154239,
+STORE, 94170866515968, 94170867740671,
+STORE, 140062030422016, 140062032080895,
+STORE, 140062032080896, 140062034178047,
+STORE, 140062034178048, 140062034194431,
+STORE, 140062034194432, 140062034202623,
+STORE, 140062034202624, 140062034219007,
+STORE, 140062034219008, 140062034231295,
+STORE, 140062034231296, 140062036324351,
+STORE, 140062036324352, 140062036328447,
+STORE, 140062036328448, 140062036332543,
+STORE, 140062036332544, 140062036475903,
+STORE, 140062036844544, 140062038527999,
+STORE, 140062038528000, 140062038544383,
+STORE, 140062038573056, 140062038577151,
+STORE, 140062038577152, 140062038581247,
+STORE, 140062038581248, 140062038585343,
+STORE, 140736210550784, 140736210690047,
+STORE, 140736210759680, 140736210771967,
+STORE, 140736210771968, 140736210776063,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724272365568, 140737488351231,
+SNULL, 140724272373759, 140737488351231,
+STORE, 140724272365568, 140724272373759,
+STORE, 140724272234496, 140724272373759,
+STORE, 94607711965184, 94607714189311,
+SNULL, 94607712075775, 94607714189311,
+STORE, 94607711965184, 94607712075775,
+STORE, 94607712075776, 94607714189311,
+ERASE, 94607712075776, 94607714189311,
+STORE, 94607714168832, 94607714181119,
+STORE, 94607714181120, 94607714189311,
+STORE, 140054949253120, 140054951505919,
+SNULL, 140054949396479, 140054951505919,
+STORE, 140054949253120, 140054949396479,
+STORE, 140054949396480, 140054951505919,
+ERASE, 140054949396480, 140054951505919,
+STORE, 140054951493632, 140054951501823,
+STORE, 140054951501824, 140054951505919,
+STORE, 140724272992256, 140724272996351,
+STORE, 140724272979968, 140724272992255,
+STORE, 140054951464960, 140054951493631,
+STORE, 140054951456768, 140054951464959,
+STORE, 140054945456128, 140054949253119,
+SNULL, 140054945456128, 140054947115007,
+STORE, 140054947115008, 140054949253119,
+STORE, 140054945456128, 140054947115007,
+SNULL, 140054949212159, 140054949253119,
+STORE, 140054947115008, 140054949212159,
+STORE, 140054949212160, 140054949253119,
+SNULL, 140054949212160, 140054949236735,
+STORE, 140054949236736, 140054949253119,
+STORE, 140054949212160, 140054949236735,
+ERASE, 140054949212160, 140054949236735,
+STORE, 140054949212160, 140054949236735,
+ERASE, 140054949236736, 140054949253119,
+STORE, 140054949236736, 140054949253119,
+SNULL, 140054949228543, 140054949236735,
+STORE, 140054949212160, 140054949228543,
+STORE, 140054949228544, 140054949236735,
+SNULL, 94607714177023, 94607714181119,
+STORE, 94607714168832, 94607714177023,
+STORE, 94607714177024, 94607714181119,
+SNULL, 140054951497727, 140054951501823,
+STORE, 140054951493632, 140054951497727,
+STORE, 140054951497728, 140054951501823,
+ERASE, 140054951464960, 140054951493631,
+STORE, 94607733374976, 94607733510143,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733586923520, 140737488351231,
+SNULL, 140733586931711, 140737488351231,
+STORE, 140733586923520, 140733586931711,
+STORE, 140733586792448, 140733586931711,
+STORE, 93901634904064, 93901637128191,
+SNULL, 93901635014655, 93901637128191,
+STORE, 93901634904064, 93901635014655,
+STORE, 93901635014656, 93901637128191,
+ERASE, 93901635014656, 93901637128191,
+STORE, 93901637107712, 93901637119999,
+STORE, 93901637120000, 93901637128191,
+STORE, 140086104784896, 140086107037695,
+SNULL, 140086104928255, 140086107037695,
+STORE, 140086104784896, 140086104928255,
+STORE, 140086104928256, 140086107037695,
+ERASE, 140086104928256, 140086107037695,
+STORE, 140086107025408, 140086107033599,
+STORE, 140086107033600, 140086107037695,
+STORE, 140733587263488, 140733587267583,
+STORE, 140733587251200, 140733587263487,
+STORE, 140086106996736, 140086107025407,
+STORE, 140086106988544, 140086106996735,
+STORE, 140086100987904, 140086104784895,
+SNULL, 140086100987904, 140086102646783,
+STORE, 140086102646784, 140086104784895,
+STORE, 140086100987904, 140086102646783,
+SNULL, 140086104743935, 140086104784895,
+STORE, 140086102646784, 140086104743935,
+STORE, 140086104743936, 140086104784895,
+SNULL, 140086104743936, 140086104768511,
+STORE, 140086104768512, 140086104784895,
+STORE, 140086104743936, 140086104768511,
+ERASE, 140086104743936, 140086104768511,
+STORE, 140086104743936, 140086104768511,
+ERASE, 140086104768512, 140086104784895,
+STORE, 140086104768512, 140086104784895,
+SNULL, 140086104760319, 140086104768511,
+STORE, 140086104743936, 140086104760319,
+STORE, 140086104760320, 140086104768511,
+SNULL, 93901637115903, 93901637119999,
+STORE, 93901637107712, 93901637115903,
+STORE, 93901637115904, 93901637119999,
+SNULL, 140086107029503, 140086107033599,
+STORE, 140086107025408, 140086107029503,
+STORE, 140086107029504, 140086107033599,
+ERASE, 140086106996736, 140086107025407,
+STORE, 93901662715904, 93901662851071,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723365613568, 140737488351231,
+SNULL, 140723365621759, 140737488351231,
+STORE, 140723365613568, 140723365621759,
+STORE, 140723365482496, 140723365621759,
+STORE, 94759193546752, 94759195770879,
+SNULL, 94759193657343, 94759195770879,
+STORE, 94759193546752, 94759193657343,
+STORE, 94759193657344, 94759195770879,
+ERASE, 94759193657344, 94759195770879,
+STORE, 94759195750400, 94759195762687,
+STORE, 94759195762688, 94759195770879,
+STORE, 140607636246528, 140607638499327,
+SNULL, 140607636389887, 140607638499327,
+STORE, 140607636246528, 140607636389887,
+STORE, 140607636389888, 140607638499327,
+ERASE, 140607636389888, 140607638499327,
+STORE, 140607638487040, 140607638495231,
+STORE, 140607638495232, 140607638499327,
+STORE, 140723365900288, 140723365904383,
+STORE, 140723365888000, 140723365900287,
+STORE, 140607638458368, 140607638487039,
+STORE, 140607638450176, 140607638458367,
+STORE, 140607632449536, 140607636246527,
+SNULL, 140607632449536, 140607634108415,
+STORE, 140607634108416, 140607636246527,
+STORE, 140607632449536, 140607634108415,
+SNULL, 140607636205567, 140607636246527,
+STORE, 140607634108416, 140607636205567,
+STORE, 140607636205568, 140607636246527,
+SNULL, 140607636205568, 140607636230143,
+STORE, 140607636230144, 140607636246527,
+STORE, 140607636205568, 140607636230143,
+ERASE, 140607636205568, 140607636230143,
+STORE, 140607636205568, 140607636230143,
+ERASE, 140607636230144, 140607636246527,
+STORE, 140607636230144, 140607636246527,
+SNULL, 140607636221951, 140607636230143,
+STORE, 140607636205568, 140607636221951,
+STORE, 140607636221952, 140607636230143,
+SNULL, 94759195758591, 94759195762687,
+STORE, 94759195750400, 94759195758591,
+STORE, 94759195758592, 94759195762687,
+SNULL, 140607638491135, 140607638495231,
+STORE, 140607638487040, 140607638491135,
+STORE, 140607638491136, 140607638495231,
+ERASE, 140607638458368, 140607638487039,
+STORE, 94759204995072, 94759205130239,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732503789568, 140737488351231,
+SNULL, 140732503797759, 140737488351231,
+STORE, 140732503789568, 140732503797759,
+STORE, 140732503658496, 140732503797759,
+STORE, 94077792956416, 94077795180543,
+SNULL, 94077793067007, 94077795180543,
+STORE, 94077792956416, 94077793067007,
+STORE, 94077793067008, 94077795180543,
+ERASE, 94077793067008, 94077795180543,
+STORE, 94077795160064, 94077795172351,
+STORE, 94077795172352, 94077795180543,
+STORE, 140359874252800, 140359876505599,
+SNULL, 140359874396159, 140359876505599,
+STORE, 140359874252800, 140359874396159,
+STORE, 140359874396160, 140359876505599,
+ERASE, 140359874396160, 140359876505599,
+STORE, 140359876493312, 140359876501503,
+STORE, 140359876501504, 140359876505599,
+STORE, 140732504465408, 140732504469503,
+STORE, 140732504453120, 140732504465407,
+STORE, 140359876464640, 140359876493311,
+STORE, 140359876456448, 140359876464639,
+STORE, 140359870455808, 140359874252799,
+SNULL, 140359870455808, 140359872114687,
+STORE, 140359872114688, 140359874252799,
+STORE, 140359870455808, 140359872114687,
+SNULL, 140359874211839, 140359874252799,
+STORE, 140359872114688, 140359874211839,
+STORE, 140359874211840, 140359874252799,
+SNULL, 140359874211840, 140359874236415,
+STORE, 140359874236416, 140359874252799,
+STORE, 140359874211840, 140359874236415,
+ERASE, 140359874211840, 140359874236415,
+STORE, 140359874211840, 140359874236415,
+ERASE, 140359874236416, 140359874252799,
+STORE, 140359874236416, 140359874252799,
+SNULL, 140359874228223, 140359874236415,
+STORE, 140359874211840, 140359874228223,
+STORE, 140359874228224, 140359874236415,
+SNULL, 94077795168255, 94077795172351,
+STORE, 94077795160064, 94077795168255,
+STORE, 94077795168256, 94077795172351,
+SNULL, 140359876497407, 140359876501503,
+STORE, 140359876493312, 140359876497407,
+STORE, 140359876497408, 140359876501503,
+ERASE, 140359876464640, 140359876493311,
+STORE, 94077808717824, 94077808852991,
+STORE, 94549486252032, 94549486465023,
+STORE, 94549488562176, 94549488566271,
+STORE, 94549488566272, 94549488574463,
+STORE, 94549488574464, 94549488586751,
+STORE, 94549503492096, 94549506121727,
+STORE, 140085800894464, 140085802553343,
+STORE, 140085802553344, 140085804650495,
+STORE, 140085804650496, 140085804666879,
+STORE, 140085804666880, 140085804675071,
+STORE, 140085804675072, 140085804691455,
+STORE, 140085804691456, 140085804703743,
+STORE, 140085804703744, 140085806796799,
+STORE, 140085806796800, 140085806800895,
+STORE, 140085806800896, 140085806804991,
+STORE, 140085806804992, 140085806948351,
+STORE, 140085807316992, 140085809000447,
+STORE, 140085809000448, 140085809016831,
+STORE, 140085809045504, 140085809049599,
+STORE, 140085809049600, 140085809053695,
+STORE, 140085809053696, 140085809057791,
+STORE, 140731810545664, 140731810684927,
+STORE, 140731810967552, 140731810979839,
+STORE, 140731810979840, 140731810983935,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724752330752, 140737488351231,
+SNULL, 140724752338943, 140737488351231,
+STORE, 140724752330752, 140724752338943,
+STORE, 140724752199680, 140724752338943,
+STORE, 94656357539840, 94656359874559,
+SNULL, 94656357752831, 94656359874559,
+STORE, 94656357539840, 94656357752831,
+STORE, 94656357752832, 94656359874559,
+ERASE, 94656357752832, 94656359874559,
+STORE, 94656359849984, 94656359862271,
+STORE, 94656359862272, 94656359874559,
+STORE, 139632585203712, 139632587456511,
+SNULL, 139632585347071, 139632587456511,
+STORE, 139632585203712, 139632585347071,
+STORE, 139632585347072, 139632587456511,
+ERASE, 139632585347072, 139632587456511,
+STORE, 139632587444224, 139632587452415,
+STORE, 139632587452416, 139632587456511,
+STORE, 139632587440128, 139632587444223,
+STORE, 139632587427840, 139632587440127,
+STORE, 139632587399168, 139632587427839,
+STORE, 139632587390976, 139632587399167,
+STORE, 139632583090176, 139632585203711,
+SNULL, 139632583090176, 139632583102463,
+STORE, 139632583102464, 139632585203711,
+STORE, 139632583090176, 139632583102463,
+SNULL, 139632585195519, 139632585203711,
+STORE, 139632583102464, 139632585195519,
+STORE, 139632585195520, 139632585203711,
+ERASE, 139632585195520, 139632585203711,
+STORE, 139632585195520, 139632585203711,
+STORE, 139632579293184, 139632583090175,
+SNULL, 139632579293184, 139632580952063,
+STORE, 139632580952064, 139632583090175,
+STORE, 139632579293184, 139632580952063,
+SNULL, 139632583049215, 139632583090175,
+STORE, 139632580952064, 139632583049215,
+STORE, 139632583049216, 139632583090175,
+SNULL, 139632583049216, 139632583073791,
+STORE, 139632583073792, 139632583090175,
+STORE, 139632583049216, 139632583073791,
+ERASE, 139632583049216, 139632583073791,
+STORE, 139632583049216, 139632583073791,
+ERASE, 139632583073792, 139632583090175,
+STORE, 139632583073792, 139632583090175,
+STORE, 139632587382784, 139632587399167,
+SNULL, 139632583065599, 139632583073791,
+STORE, 139632583049216, 139632583065599,
+STORE, 139632583065600, 139632583073791,
+SNULL, 139632585199615, 139632585203711,
+STORE, 139632585195520, 139632585199615,
+STORE, 139632585199616, 139632585203711,
+SNULL, 94656359854079, 94656359862271,
+STORE, 94656359849984, 94656359854079,
+STORE, 94656359854080, 94656359862271,
+SNULL, 139632587448319, 139632587452415,
+STORE, 139632587444224, 139632587448319,
+STORE, 139632587448320, 139632587452415,
+ERASE, 139632587399168, 139632587427839,
+STORE, 94656378912768, 94656379047935,
+STORE, 139632585699328, 139632587382783,
+STORE, 94656378912768, 94656379183103,
+STORE, 94656378912768, 94656379318271,
+STORE, 94656378912768, 94656379494399,
+SNULL, 94656379469823, 94656379494399,
+STORE, 94656378912768, 94656379469823,
+STORE, 94656379469824, 94656379494399,
+ERASE, 94656379469824, 94656379494399,
+STORE, 94656378912768, 94656379621375,
+STORE, 94656378912768, 94656379756543,
+STORE, 94656378912768, 94656379912191,
+STORE, 94656378912768, 94656380055551,
+STORE, 94656378912768, 94656380190719,
+STORE, 94656378912768, 94656380338175,
+SNULL, 94656380313599, 94656380338175,
+STORE, 94656378912768, 94656380313599,
+STORE, 94656380313600, 94656380338175,
+ERASE, 94656380313600, 94656380338175,
+STORE, 94656378912768, 94656380448767,
+SNULL, 94656380432383, 94656380448767,
+STORE, 94656378912768, 94656380432383,
+STORE, 94656380432384, 94656380448767,
+ERASE, 94656380432384, 94656380448767,
+STORE, 94656378912768, 94656380567551,
+STORE, 94656378912768, 94656380719103,
+STORE, 94656378912768, 94656380858367,
+STORE, 94656378912768, 94656380997631,
+STORE, 94656378912768, 94656381132799,
+SNULL, 94656381124607, 94656381132799,
+STORE, 94656378912768, 94656381124607,
+STORE, 94656381124608, 94656381132799,
+ERASE, 94656381124608, 94656381132799,
+STORE, 94656378912768, 94656381276159,
+STORE, 94656378912768, 94656381427711,
+STORE, 94604087611392, 94604087824383,
+STORE, 94604089921536, 94604089925631,
+STORE, 94604089925632, 94604089933823,
+STORE, 94604089933824, 94604089946111,
+STORE, 94604105125888, 94604106424319,
+STORE, 140454937694208, 140454939353087,
+STORE, 140454939353088, 140454941450239,
+STORE, 140454941450240, 140454941466623,
+STORE, 140454941466624, 140454941474815,
+STORE, 140454941474816, 140454941491199,
+STORE, 140454941491200, 140454941503487,
+STORE, 140454941503488, 140454943596543,
+STORE, 140454943596544, 140454943600639,
+STORE, 140454943600640, 140454943604735,
+STORE, 140454943604736, 140454943748095,
+STORE, 140454944116736, 140454945800191,
+STORE, 140454945800192, 140454945816575,
+STORE, 140454945845248, 140454945849343,
+STORE, 140454945849344, 140454945853439,
+STORE, 140454945853440, 140454945857535,
+STORE, 140728438214656, 140728438353919,
+STORE, 140728439095296, 140728439107583,
+STORE, 140728439107584, 140728439111679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140727821099008, 140737488351231,
+SNULL, 140727821107199, 140737488351231,
+STORE, 140727821099008, 140727821107199,
+STORE, 140727820967936, 140727821107199,
+STORE, 94088457240576, 94088459575295,
+SNULL, 94088457453567, 94088459575295,
+STORE, 94088457240576, 94088457453567,
+STORE, 94088457453568, 94088459575295,
+ERASE, 94088457453568, 94088459575295,
+STORE, 94088459550720, 94088459563007,
+STORE, 94088459563008, 94088459575295,
+STORE, 140234378989568, 140234381242367,
+SNULL, 140234379132927, 140234381242367,
+STORE, 140234378989568, 140234379132927,
+STORE, 140234379132928, 140234381242367,
+ERASE, 140234379132928, 140234381242367,
+STORE, 140234381230080, 140234381238271,
+STORE, 140234381238272, 140234381242367,
+STORE, 140727822077952, 140727822082047,
+STORE, 140727822065664, 140727822077951,
+STORE, 140234381201408, 140234381230079,
+STORE, 140234381193216, 140234381201407,
+STORE, 140234376876032, 140234378989567,
+SNULL, 140234376876032, 140234376888319,
+STORE, 140234376888320, 140234378989567,
+STORE, 140234376876032, 140234376888319,
+SNULL, 140234378981375, 140234378989567,
+STORE, 140234376888320, 140234378981375,
+STORE, 140234378981376, 140234378989567,
+ERASE, 140234378981376, 140234378989567,
+STORE, 140234378981376, 140234378989567,
+STORE, 140234373079040, 140234376876031,
+SNULL, 140234373079040, 140234374737919,
+STORE, 140234374737920, 140234376876031,
+STORE, 140234373079040, 140234374737919,
+SNULL, 140234376835071, 140234376876031,
+STORE, 140234374737920, 140234376835071,
+STORE, 140234376835072, 140234376876031,
+SNULL, 140234376835072, 140234376859647,
+STORE, 140234376859648, 140234376876031,
+STORE, 140234376835072, 140234376859647,
+ERASE, 140234376835072, 140234376859647,
+STORE, 140234376835072, 140234376859647,
+ERASE, 140234376859648, 140234376876031,
+STORE, 140234376859648, 140234376876031,
+STORE, 140234381185024, 140234381201407,
+SNULL, 140234376851455, 140234376859647,
+STORE, 140234376835072, 140234376851455,
+STORE, 140234376851456, 140234376859647,
+SNULL, 140234378985471, 140234378989567,
+STORE, 140234378981376, 140234378985471,
+STORE, 140234378985472, 140234378989567,
+SNULL, 94088459554815, 94088459563007,
+STORE, 94088459550720, 94088459554815,
+STORE, 94088459554816, 94088459563007,
+SNULL, 140234381234175, 140234381238271,
+STORE, 140234381230080, 140234381234175,
+STORE, 140234381234176, 140234381238271,
+ERASE, 140234381201408, 140234381230079,
+STORE, 94088468852736, 94088468987903,
+STORE, 140234379501568, 140234381185023,
+STORE, 94088468852736, 94088469123071,
+STORE, 94088468852736, 94088469258239,
+STORE, 94110050402304, 94110050615295,
+STORE, 94110052712448, 94110052716543,
+STORE, 94110052716544, 94110052724735,
+STORE, 94110052724736, 94110052737023,
+STORE, 94110061875200, 94110062415871,
+STORE, 140139439357952, 140139441016831,
+STORE, 140139441016832, 140139443113983,
+STORE, 140139443113984, 140139443130367,
+STORE, 140139443130368, 140139443138559,
+STORE, 140139443138560, 140139443154943,
+STORE, 140139443154944, 140139443167231,
+STORE, 140139443167232, 140139445260287,
+STORE, 140139445260288, 140139445264383,
+STORE, 140139445264384, 140139445268479,
+STORE, 140139445268480, 140139445411839,
+STORE, 140139445780480, 140139447463935,
+STORE, 140139447463936, 140139447480319,
+STORE, 140139447508992, 140139447513087,
+STORE, 140139447513088, 140139447517183,
+STORE, 140139447517184, 140139447521279,
+STORE, 140731901427712, 140731901566975,
+STORE, 140731902259200, 140731902271487,
+STORE, 140731902271488, 140731902275583,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140727282622464, 140737488351231,
+SNULL, 140727282630655, 140737488351231,
+STORE, 140727282622464, 140727282630655,
+STORE, 140727282491392, 140727282630655,
+STORE, 94266649866240, 94266652200959,
+SNULL, 94266650079231, 94266652200959,
+STORE, 94266649866240, 94266650079231,
+STORE, 94266650079232, 94266652200959,
+ERASE, 94266650079232, 94266652200959,
+STORE, 94266652176384, 94266652188671,
+STORE, 94266652188672, 94266652200959,
+STORE, 139888497991680, 139888500244479,
+SNULL, 139888498135039, 139888500244479,
+STORE, 139888497991680, 139888498135039,
+STORE, 139888498135040, 139888500244479,
+ERASE, 139888498135040, 139888500244479,
+STORE, 139888500232192, 139888500240383,
+STORE, 139888500240384, 139888500244479,
+STORE, 140727283113984, 140727283118079,
+STORE, 140727283101696, 140727283113983,
+STORE, 139888500203520, 139888500232191,
+STORE, 139888500195328, 139888500203519,
+STORE, 139888495878144, 139888497991679,
+SNULL, 139888495878144, 139888495890431,
+STORE, 139888495890432, 139888497991679,
+STORE, 139888495878144, 139888495890431,
+SNULL, 139888497983487, 139888497991679,
+STORE, 139888495890432, 139888497983487,
+STORE, 139888497983488, 139888497991679,
+ERASE, 139888497983488, 139888497991679,
+STORE, 139888497983488, 139888497991679,
+STORE, 139888492081152, 139888495878143,
+SNULL, 139888492081152, 139888493740031,
+STORE, 139888493740032, 139888495878143,
+STORE, 139888492081152, 139888493740031,
+SNULL, 139888495837183, 139888495878143,
+STORE, 139888493740032, 139888495837183,
+STORE, 139888495837184, 139888495878143,
+SNULL, 139888495837184, 139888495861759,
+STORE, 139888495861760, 139888495878143,
+STORE, 139888495837184, 139888495861759,
+ERASE, 139888495837184, 139888495861759,
+STORE, 139888495837184, 139888495861759,
+ERASE, 139888495861760, 139888495878143,
+STORE, 139888495861760, 139888495878143,
+STORE, 139888500187136, 139888500203519,
+SNULL, 139888495853567, 139888495861759,
+STORE, 139888495837184, 139888495853567,
+STORE, 139888495853568, 139888495861759,
+SNULL, 139888497987583, 139888497991679,
+STORE, 139888497983488, 139888497987583,
+STORE, 139888497987584, 139888497991679,
+SNULL, 94266652180479, 94266652188671,
+STORE, 94266652176384, 94266652180479,
+STORE, 94266652180480, 94266652188671,
+SNULL, 139888500236287, 139888500240383,
+STORE, 139888500232192, 139888500236287,
+STORE, 139888500236288, 139888500240383,
+ERASE, 139888500203520, 139888500232191,
+STORE, 94266678542336, 94266678677503,
+STORE, 139888498503680, 139888500187135,
+STORE, 94266678542336, 94266678812671,
+STORE, 94266678542336, 94266678947839,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722507702272, 140737488351231,
+SNULL, 140722507710463, 140737488351231,
+STORE, 140722507702272, 140722507710463,
+STORE, 140722507571200, 140722507710463,
+STORE, 94313981394944, 94313983729663,
+SNULL, 94313981607935, 94313983729663,
+STORE, 94313981394944, 94313981607935,
+STORE, 94313981607936, 94313983729663,
+ERASE, 94313981607936, 94313983729663,
+STORE, 94313983705088, 94313983717375,
+STORE, 94313983717376, 94313983729663,
+STORE, 140456286076928, 140456288329727,
+SNULL, 140456286220287, 140456288329727,
+STORE, 140456286076928, 140456286220287,
+STORE, 140456286220288, 140456288329727,
+ERASE, 140456286220288, 140456288329727,
+STORE, 140456288317440, 140456288325631,
+STORE, 140456288325632, 140456288329727,
+STORE, 140722507997184, 140722508001279,
+STORE, 140722507984896, 140722507997183,
+STORE, 140456288288768, 140456288317439,
+STORE, 140456288280576, 140456288288767,
+STORE, 140456283963392, 140456286076927,
+SNULL, 140456283963392, 140456283975679,
+STORE, 140456283975680, 140456286076927,
+STORE, 140456283963392, 140456283975679,
+SNULL, 140456286068735, 140456286076927,
+STORE, 140456283975680, 140456286068735,
+STORE, 140456286068736, 140456286076927,
+ERASE, 140456286068736, 140456286076927,
+STORE, 140456286068736, 140456286076927,
+STORE, 140456280166400, 140456283963391,
+SNULL, 140456280166400, 140456281825279,
+STORE, 140456281825280, 140456283963391,
+STORE, 140456280166400, 140456281825279,
+SNULL, 140456283922431, 140456283963391,
+STORE, 140456281825280, 140456283922431,
+STORE, 140456283922432, 140456283963391,
+SNULL, 140456283922432, 140456283947007,
+STORE, 140456283947008, 140456283963391,
+STORE, 140456283922432, 140456283947007,
+ERASE, 140456283922432, 140456283947007,
+STORE, 140456283922432, 140456283947007,
+ERASE, 140456283947008, 140456283963391,
+STORE, 140456283947008, 140456283963391,
+STORE, 140456288272384, 140456288288767,
+SNULL, 140456283938815, 140456283947007,
+STORE, 140456283922432, 140456283938815,
+STORE, 140456283938816, 140456283947007,
+SNULL, 140456286072831, 140456286076927,
+STORE, 140456286068736, 140456286072831,
+STORE, 140456286072832, 140456286076927,
+SNULL, 94313983709183, 94313983717375,
+STORE, 94313983705088, 94313983709183,
+STORE, 94313983709184, 94313983717375,
+SNULL, 140456288321535, 140456288325631,
+STORE, 140456288317440, 140456288321535,
+STORE, 140456288321536, 140456288325631,
+ERASE, 140456288288768, 140456288317439,
+STORE, 94314006716416, 94314006851583,
+STORE, 140456286588928, 140456288272383,
+STORE, 94314006716416, 94314006986751,
+STORE, 94314006716416, 94314007121919,
+STORE, 93948644454400, 93948644667391,
+STORE, 93948646764544, 93948646768639,
+STORE, 93948646768640, 93948646776831,
+STORE, 93948646776832, 93948646789119,
+STORE, 93948664999936, 93948667142143,
+STORE, 140187350659072, 140187352317951,
+STORE, 140187352317952, 140187354415103,
+STORE, 140187354415104, 140187354431487,
+STORE, 140187354431488, 140187354439679,
+STORE, 140187354439680, 140187354456063,
+STORE, 140187354456064, 140187354468351,
+STORE, 140187354468352, 140187356561407,
+STORE, 140187356561408, 140187356565503,
+STORE, 140187356565504, 140187356569599,
+STORE, 140187356569600, 140187356712959,
+STORE, 140187357081600, 140187358765055,
+STORE, 140187358765056, 140187358781439,
+STORE, 140187358810112, 140187358814207,
+STORE, 140187358814208, 140187358818303,
+STORE, 140187358818304, 140187358822399,
+STORE, 140730484518912, 140730484658175,
+STORE, 140730485690368, 140730485702655,
+STORE, 140730485702656, 140730485706751,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721211551744, 140737488351231,
+SNULL, 140721211559935, 140737488351231,
+STORE, 140721211551744, 140721211559935,
+STORE, 140721211420672, 140721211559935,
+STORE, 94105221423104, 94105223757823,
+SNULL, 94105221636095, 94105223757823,
+STORE, 94105221423104, 94105221636095,
+STORE, 94105221636096, 94105223757823,
+ERASE, 94105221636096, 94105223757823,
+STORE, 94105223733248, 94105223745535,
+STORE, 94105223745536, 94105223757823,
+STORE, 140474453676032, 140474455928831,
+SNULL, 140474453819391, 140474455928831,
+STORE, 140474453676032, 140474453819391,
+STORE, 140474453819392, 140474455928831,
+ERASE, 140474453819392, 140474455928831,
+STORE, 140474455916544, 140474455924735,
+STORE, 140474455924736, 140474455928831,
+STORE, 140721211703296, 140721211707391,
+STORE, 140721211691008, 140721211703295,
+STORE, 140474455887872, 140474455916543,
+STORE, 140474455879680, 140474455887871,
+STORE, 140474451562496, 140474453676031,
+SNULL, 140474451562496, 140474451574783,
+STORE, 140474451574784, 140474453676031,
+STORE, 140474451562496, 140474451574783,
+SNULL, 140474453667839, 140474453676031,
+STORE, 140474451574784, 140474453667839,
+STORE, 140474453667840, 140474453676031,
+ERASE, 140474453667840, 140474453676031,
+STORE, 140474453667840, 140474453676031,
+STORE, 140474447765504, 140474451562495,
+SNULL, 140474447765504, 140474449424383,
+STORE, 140474449424384, 140474451562495,
+STORE, 140474447765504, 140474449424383,
+SNULL, 140474451521535, 140474451562495,
+STORE, 140474449424384, 140474451521535,
+STORE, 140474451521536, 140474451562495,
+SNULL, 140474451521536, 140474451546111,
+STORE, 140474451546112, 140474451562495,
+STORE, 140474451521536, 140474451546111,
+ERASE, 140474451521536, 140474451546111,
+STORE, 140474451521536, 140474451546111,
+ERASE, 140474451546112, 140474451562495,
+STORE, 140474451546112, 140474451562495,
+STORE, 140474455871488, 140474455887871,
+SNULL, 140474451537919, 140474451546111,
+STORE, 140474451521536, 140474451537919,
+STORE, 140474451537920, 140474451546111,
+SNULL, 140474453671935, 140474453676031,
+STORE, 140474453667840, 140474453671935,
+STORE, 140474453671936, 140474453676031,
+SNULL, 94105223737343, 94105223745535,
+STORE, 94105223733248, 94105223737343,
+STORE, 94105223737344, 94105223745535,
+SNULL, 140474455920639, 140474455924735,
+STORE, 140474455916544, 140474455920639,
+STORE, 140474455920640, 140474455924735,
+ERASE, 140474455887872, 140474455916543,
+STORE, 94105238712320, 94105238847487,
+STORE, 140474454188032, 140474455871487,
+STORE, 94105238712320, 94105238982655,
+STORE, 94105238712320, 94105239117823,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732356354048, 140737488351231,
+SNULL, 140732356362239, 140737488351231,
+STORE, 140732356354048, 140732356362239,
+STORE, 140732356222976, 140732356362239,
+STORE, 94461165989888, 94461168324607,
+SNULL, 94461166202879, 94461168324607,
+STORE, 94461165989888, 94461166202879,
+STORE, 94461166202880, 94461168324607,
+ERASE, 94461166202880, 94461168324607,
+STORE, 94461168300032, 94461168312319,
+STORE, 94461168312320, 94461168324607,
+STORE, 140317255110656, 140317257363455,
+SNULL, 140317255254015, 140317257363455,
+STORE, 140317255110656, 140317255254015,
+STORE, 140317255254016, 140317257363455,
+ERASE, 140317255254016, 140317257363455,
+STORE, 140317257351168, 140317257359359,
+STORE, 140317257359360, 140317257363455,
+STORE, 140732356583424, 140732356587519,
+STORE, 140732356571136, 140732356583423,
+STORE, 140317257322496, 140317257351167,
+STORE, 140317257314304, 140317257322495,
+STORE, 140317252997120, 140317255110655,
+SNULL, 140317252997120, 140317253009407,
+STORE, 140317253009408, 140317255110655,
+STORE, 140317252997120, 140317253009407,
+SNULL, 140317255102463, 140317255110655,
+STORE, 140317253009408, 140317255102463,
+STORE, 140317255102464, 140317255110655,
+ERASE, 140317255102464, 140317255110655,
+STORE, 140317255102464, 140317255110655,
+STORE, 140317249200128, 140317252997119,
+SNULL, 140317249200128, 140317250859007,
+STORE, 140317250859008, 140317252997119,
+STORE, 140317249200128, 140317250859007,
+SNULL, 140317252956159, 140317252997119,
+STORE, 140317250859008, 140317252956159,
+STORE, 140317252956160, 140317252997119,
+SNULL, 140317252956160, 140317252980735,
+STORE, 140317252980736, 140317252997119,
+STORE, 140317252956160, 140317252980735,
+ERASE, 140317252956160, 140317252980735,
+STORE, 140317252956160, 140317252980735,
+ERASE, 140317252980736, 140317252997119,
+STORE, 140317252980736, 140317252997119,
+STORE, 140317257306112, 140317257322495,
+SNULL, 140317252972543, 140317252980735,
+STORE, 140317252956160, 140317252972543,
+STORE, 140317252972544, 140317252980735,
+SNULL, 140317255106559, 140317255110655,
+STORE, 140317255102464, 140317255106559,
+STORE, 140317255106560, 140317255110655,
+SNULL, 94461168304127, 94461168312319,
+STORE, 94461168300032, 94461168304127,
+STORE, 94461168304128, 94461168312319,
+SNULL, 140317257355263, 140317257359359,
+STORE, 140317257351168, 140317257355263,
+STORE, 140317257355264, 140317257359359,
+ERASE, 140317257322496, 140317257351167,
+STORE, 94461195268096, 94461195403263,
+STORE, 140317255622656, 140317257306111,
+STORE, 94461195268096, 94461195538431,
+STORE, 94461195268096, 94461195673599,
+STORE, 94110050402304, 94110050615295,
+STORE, 94110052712448, 94110052716543,
+STORE, 94110052716544, 94110052724735,
+STORE, 94110052724736, 94110052737023,
+STORE, 94110061875200, 94110062415871,
+STORE, 140139439357952, 140139441016831,
+STORE, 140139441016832, 140139443113983,
+STORE, 140139443113984, 140139443130367,
+STORE, 140139443130368, 140139443138559,
+STORE, 140139443138560, 140139443154943,
+STORE, 140139443154944, 140139443167231,
+STORE, 140139443167232, 140139445260287,
+STORE, 140139445260288, 140139445264383,
+STORE, 140139445264384, 140139445268479,
+STORE, 140139445268480, 140139445411839,
+STORE, 140139445780480, 140139447463935,
+STORE, 140139447463936, 140139447480319,
+STORE, 140139447508992, 140139447513087,
+STORE, 140139447513088, 140139447517183,
+STORE, 140139447517184, 140139447521279,
+STORE, 140731901427712, 140731901566975,
+STORE, 140731902259200, 140731902271487,
+STORE, 140731902271488, 140731902275583,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140720941613056, 140737488351231,
+SNULL, 140720941621247, 140737488351231,
+STORE, 140720941613056, 140720941621247,
+STORE, 140720941481984, 140720941621247,
+STORE, 93902377721856, 93902379945983,
+SNULL, 93902377832447, 93902379945983,
+STORE, 93902377721856, 93902377832447,
+STORE, 93902377832448, 93902379945983,
+ERASE, 93902377832448, 93902379945983,
+STORE, 93902379925504, 93902379937791,
+STORE, 93902379937792, 93902379945983,
+STORE, 139836543635456, 139836545888255,
+SNULL, 139836543778815, 139836545888255,
+STORE, 139836543635456, 139836543778815,
+STORE, 139836543778816, 139836545888255,
+ERASE, 139836543778816, 139836545888255,
+STORE, 139836545875968, 139836545884159,
+STORE, 139836545884160, 139836545888255,
+STORE, 140720941711360, 140720941715455,
+STORE, 140720941699072, 140720941711359,
+STORE, 139836545847296, 139836545875967,
+STORE, 139836545839104, 139836545847295,
+STORE, 139836539838464, 139836543635455,
+SNULL, 139836539838464, 139836541497343,
+STORE, 139836541497344, 139836543635455,
+STORE, 139836539838464, 139836541497343,
+SNULL, 139836543594495, 139836543635455,
+STORE, 139836541497344, 139836543594495,
+STORE, 139836543594496, 139836543635455,
+SNULL, 139836543594496, 139836543619071,
+STORE, 139836543619072, 139836543635455,
+STORE, 139836543594496, 139836543619071,
+ERASE, 139836543594496, 139836543619071,
+STORE, 139836543594496, 139836543619071,
+ERASE, 139836543619072, 139836543635455,
+STORE, 139836543619072, 139836543635455,
+SNULL, 139836543610879, 139836543619071,
+STORE, 139836543594496, 139836543610879,
+STORE, 139836543610880, 139836543619071,
+SNULL, 93902379933695, 93902379937791,
+STORE, 93902379925504, 93902379933695,
+STORE, 93902379933696, 93902379937791,
+SNULL, 139836545880063, 139836545884159,
+STORE, 139836545875968, 139836545880063,
+STORE, 139836545880064, 139836545884159,
+ERASE, 139836545847296, 139836545875967,
+STORE, 93902396891136, 93902397026303,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140736538206208, 140737488351231,
+SNULL, 140736538214399, 140737488351231,
+STORE, 140736538206208, 140736538214399,
+STORE, 140736538075136, 140736538214399,
+STORE, 94173471399936, 94173473734655,
+SNULL, 94173471612927, 94173473734655,
+STORE, 94173471399936, 94173471612927,
+STORE, 94173471612928, 94173473734655,
+ERASE, 94173471612928, 94173473734655,
+STORE, 94173473710080, 94173473722367,
+STORE, 94173473722368, 94173473734655,
+STORE, 140035513556992, 140035515809791,
+SNULL, 140035513700351, 140035515809791,
+STORE, 140035513556992, 140035513700351,
+STORE, 140035513700352, 140035515809791,
+ERASE, 140035513700352, 140035515809791,
+STORE, 140035515797504, 140035515805695,
+STORE, 140035515805696, 140035515809791,
+STORE, 140736538329088, 140736538333183,
+STORE, 140736538316800, 140736538329087,
+STORE, 140035515768832, 140035515797503,
+STORE, 140035515760640, 140035515768831,
+STORE, 140035511443456, 140035513556991,
+SNULL, 140035511443456, 140035511455743,
+STORE, 140035511455744, 140035513556991,
+STORE, 140035511443456, 140035511455743,
+SNULL, 140035513548799, 140035513556991,
+STORE, 140035511455744, 140035513548799,
+STORE, 140035513548800, 140035513556991,
+ERASE, 140035513548800, 140035513556991,
+STORE, 140035513548800, 140035513556991,
+STORE, 140035507646464, 140035511443455,
+SNULL, 140035507646464, 140035509305343,
+STORE, 140035509305344, 140035511443455,
+STORE, 140035507646464, 140035509305343,
+SNULL, 140035511402495, 140035511443455,
+STORE, 140035509305344, 140035511402495,
+STORE, 140035511402496, 140035511443455,
+SNULL, 140035511402496, 140035511427071,
+STORE, 140035511427072, 140035511443455,
+STORE, 140035511402496, 140035511427071,
+ERASE, 140035511402496, 140035511427071,
+STORE, 140035511402496, 140035511427071,
+ERASE, 140035511427072, 140035511443455,
+STORE, 140035511427072, 140035511443455,
+STORE, 140035515752448, 140035515768831,
+SNULL, 140035511418879, 140035511427071,
+STORE, 140035511402496, 140035511418879,
+STORE, 140035511418880, 140035511427071,
+SNULL, 140035513552895, 140035513556991,
+STORE, 140035513548800, 140035513552895,
+STORE, 140035513552896, 140035513556991,
+SNULL, 94173473714175, 94173473722367,
+STORE, 94173473710080, 94173473714175,
+STORE, 94173473714176, 94173473722367,
+SNULL, 140035515801599, 140035515805695,
+STORE, 140035515797504, 140035515801599,
+STORE, 140035515801600, 140035515805695,
+ERASE, 140035515768832, 140035515797503,
+STORE, 94173478645760, 94173478780927,
+STORE, 140035514068992, 140035515752447,
+STORE, 94173478645760, 94173478916095,
+STORE, 94173478645760, 94173479051263,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140724216176640, 140737488351231,
+SNULL, 140724216184831, 140737488351231,
+STORE, 140724216176640, 140724216184831,
+STORE, 140724216045568, 140724216184831,
+STORE, 94870930628608, 94870932963327,
+SNULL, 94870930841599, 94870932963327,
+STORE, 94870930628608, 94870930841599,
+STORE, 94870930841600, 94870932963327,
+ERASE, 94870930841600, 94870932963327,
+STORE, 94870932938752, 94870932951039,
+STORE, 94870932951040, 94870932963327,
+STORE, 140453683736576, 140453685989375,
+SNULL, 140453683879935, 140453685989375,
+STORE, 140453683736576, 140453683879935,
+STORE, 140453683879936, 140453685989375,
+ERASE, 140453683879936, 140453685989375,
+STORE, 140453685977088, 140453685985279,
+STORE, 140453685985280, 140453685989375,
+STORE, 140724216832000, 140724216836095,
+STORE, 140724216819712, 140724216831999,
+STORE, 140453685948416, 140453685977087,
+STORE, 140453685940224, 140453685948415,
+STORE, 140453681623040, 140453683736575,
+SNULL, 140453681623040, 140453681635327,
+STORE, 140453681635328, 140453683736575,
+STORE, 140453681623040, 140453681635327,
+SNULL, 140453683728383, 140453683736575,
+STORE, 140453681635328, 140453683728383,
+STORE, 140453683728384, 140453683736575,
+ERASE, 140453683728384, 140453683736575,
+STORE, 140453683728384, 140453683736575,
+STORE, 140453677826048, 140453681623039,
+SNULL, 140453677826048, 140453679484927,
+STORE, 140453679484928, 140453681623039,
+STORE, 140453677826048, 140453679484927,
+SNULL, 140453681582079, 140453681623039,
+STORE, 140453679484928, 140453681582079,
+STORE, 140453681582080, 140453681623039,
+SNULL, 140453681582080, 140453681606655,
+STORE, 140453681606656, 140453681623039,
+STORE, 140453681582080, 140453681606655,
+ERASE, 140453681582080, 140453681606655,
+STORE, 140453681582080, 140453681606655,
+ERASE, 140453681606656, 140453681623039,
+STORE, 140453681606656, 140453681623039,
+STORE, 140453685932032, 140453685948415,
+SNULL, 140453681598463, 140453681606655,
+STORE, 140453681582080, 140453681598463,
+STORE, 140453681598464, 140453681606655,
+SNULL, 140453683732479, 140453683736575,
+STORE, 140453683728384, 140453683732479,
+STORE, 140453683732480, 140453683736575,
+SNULL, 94870932942847, 94870932951039,
+STORE, 94870932938752, 94870932942847,
+STORE, 94870932942848, 94870932951039,
+SNULL, 140453685981183, 140453685985279,
+STORE, 140453685977088, 140453685981183,
+STORE, 140453685981184, 140453685985279,
+ERASE, 140453685948416, 140453685977087,
+STORE, 94870940565504, 94870940700671,
+STORE, 140453684248576, 140453685932031,
+STORE, 94870940565504, 94870940835839,
+STORE, 94870940565504, 94870940971007,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731275661312, 140737488351231,
+SNULL, 140731275669503, 140737488351231,
+STORE, 140731275661312, 140731275669503,
+STORE, 140731275530240, 140731275669503,
+STORE, 94642788548608, 94642790883327,
+SNULL, 94642788761599, 94642790883327,
+STORE, 94642788548608, 94642788761599,
+STORE, 94642788761600, 94642790883327,
+ERASE, 94642788761600, 94642790883327,
+STORE, 94642790858752, 94642790871039,
+STORE, 94642790871040, 94642790883327,
+STORE, 140228458749952, 140228461002751,
+SNULL, 140228458893311, 140228461002751,
+STORE, 140228458749952, 140228458893311,
+STORE, 140228458893312, 140228461002751,
+ERASE, 140228458893312, 140228461002751,
+STORE, 140228460990464, 140228460998655,
+STORE, 140228460998656, 140228461002751,
+STORE, 140731276349440, 140731276353535,
+STORE, 140731276337152, 140731276349439,
+STORE, 140228460961792, 140228460990463,
+STORE, 140228460953600, 140228460961791,
+STORE, 140228456636416, 140228458749951,
+SNULL, 140228456636416, 140228456648703,
+STORE, 140228456648704, 140228458749951,
+STORE, 140228456636416, 140228456648703,
+SNULL, 140228458741759, 140228458749951,
+STORE, 140228456648704, 140228458741759,
+STORE, 140228458741760, 140228458749951,
+ERASE, 140228458741760, 140228458749951,
+STORE, 140228458741760, 140228458749951,
+STORE, 140228452839424, 140228456636415,
+SNULL, 140228452839424, 140228454498303,
+STORE, 140228454498304, 140228456636415,
+STORE, 140228452839424, 140228454498303,
+SNULL, 140228456595455, 140228456636415,
+STORE, 140228454498304, 140228456595455,
+STORE, 140228456595456, 140228456636415,
+SNULL, 140228456595456, 140228456620031,
+STORE, 140228456620032, 140228456636415,
+STORE, 140228456595456, 140228456620031,
+ERASE, 140228456595456, 140228456620031,
+STORE, 140228456595456, 140228456620031,
+ERASE, 140228456620032, 140228456636415,
+STORE, 140228456620032, 140228456636415,
+STORE, 140228460945408, 140228460961791,
+SNULL, 140228456611839, 140228456620031,
+STORE, 140228456595456, 140228456611839,
+STORE, 140228456611840, 140228456620031,
+SNULL, 140228458745855, 140228458749951,
+STORE, 140228458741760, 140228458745855,
+STORE, 140228458745856, 140228458749951,
+SNULL, 94642790862847, 94642790871039,
+STORE, 94642790858752, 94642790862847,
+STORE, 94642790862848, 94642790871039,
+SNULL, 140228460994559, 140228460998655,
+STORE, 140228460990464, 140228460994559,
+STORE, 140228460994560, 140228460998655,
+ERASE, 140228460961792, 140228460990463,
+STORE, 94642801549312, 94642801684479,
+STORE, 140228459261952, 140228460945407,
+STORE, 94642801549312, 94642801819647,
+STORE, 94642801549312, 94642801954815,
+STORE, 94604087611392, 94604087824383,
+STORE, 94604089921536, 94604089925631,
+STORE, 94604089925632, 94604089933823,
+STORE, 94604089933824, 94604089946111,
+STORE, 94604105125888, 94604106424319,
+STORE, 140454937694208, 140454939353087,
+STORE, 140454939353088, 140454941450239,
+STORE, 140454941450240, 140454941466623,
+STORE, 140454941466624, 140454941474815,
+STORE, 140454941474816, 140454941491199,
+STORE, 140454941491200, 140454941503487,
+STORE, 140454941503488, 140454943596543,
+STORE, 140454943596544, 140454943600639,
+STORE, 140454943600640, 140454943604735,
+STORE, 140454943604736, 140454943748095,
+STORE, 140454944116736, 140454945800191,
+STORE, 140454945800192, 140454945816575,
+STORE, 140454945845248, 140454945849343,
+STORE, 140454945849344, 140454945853439,
+STORE, 140454945853440, 140454945857535,
+STORE, 140728438214656, 140728438353919,
+STORE, 140728439095296, 140728439107583,
+STORE, 140728439107584, 140728439111679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721843453952, 140737488351231,
+SNULL, 140721843462143, 140737488351231,
+STORE, 140721843453952, 140721843462143,
+STORE, 140721843322880, 140721843462143,
+STORE, 94465962455040, 94465964789759,
+SNULL, 94465962668031, 94465964789759,
+STORE, 94465962455040, 94465962668031,
+STORE, 94465962668032, 94465964789759,
+ERASE, 94465962668032, 94465964789759,
+STORE, 94465964765184, 94465964777471,
+STORE, 94465964777472, 94465964789759,
+STORE, 139913488314368, 139913490567167,
+SNULL, 139913488457727, 139913490567167,
+STORE, 139913488314368, 139913488457727,
+STORE, 139913488457728, 139913490567167,
+ERASE, 139913488457728, 139913490567167,
+STORE, 139913490554880, 139913490563071,
+STORE, 139913490563072, 139913490567167,
+STORE, 140721843503104, 140721843507199,
+STORE, 140721843490816, 140721843503103,
+STORE, 139913490526208, 139913490554879,
+STORE, 139913490518016, 139913490526207,
+STORE, 139913486200832, 139913488314367,
+SNULL, 139913486200832, 139913486213119,
+STORE, 139913486213120, 139913488314367,
+STORE, 139913486200832, 139913486213119,
+SNULL, 139913488306175, 139913488314367,
+STORE, 139913486213120, 139913488306175,
+STORE, 139913488306176, 139913488314367,
+ERASE, 139913488306176, 139913488314367,
+STORE, 139913488306176, 139913488314367,
+STORE, 139913482403840, 139913486200831,
+SNULL, 139913482403840, 139913484062719,
+STORE, 139913484062720, 139913486200831,
+STORE, 139913482403840, 139913484062719,
+SNULL, 139913486159871, 139913486200831,
+STORE, 139913484062720, 139913486159871,
+STORE, 139913486159872, 139913486200831,
+SNULL, 139913486159872, 139913486184447,
+STORE, 139913486184448, 139913486200831,
+STORE, 139913486159872, 139913486184447,
+ERASE, 139913486159872, 139913486184447,
+STORE, 139913486159872, 139913486184447,
+ERASE, 139913486184448, 139913486200831,
+STORE, 139913486184448, 139913486200831,
+STORE, 139913490509824, 139913490526207,
+SNULL, 139913486176255, 139913486184447,
+STORE, 139913486159872, 139913486176255,
+STORE, 139913486176256, 139913486184447,
+SNULL, 139913488310271, 139913488314367,
+STORE, 139913488306176, 139913488310271,
+STORE, 139913488310272, 139913488314367,
+SNULL, 94465964769279, 94465964777471,
+STORE, 94465964765184, 94465964769279,
+STORE, 94465964769280, 94465964777471,
+SNULL, 139913490558975, 139913490563071,
+STORE, 139913490554880, 139913490558975,
+STORE, 139913490558976, 139913490563071,
+ERASE, 139913490526208, 139913490554879,
+STORE, 94465970024448, 94465970159615,
+STORE, 139913488826368, 139913490509823,
+STORE, 94465970024448, 94465970294783,
+STORE, 94465970024448, 94465970429951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140720583307264, 140737488351231,
+SNULL, 140720583315455, 140737488351231,
+STORE, 140720583307264, 140720583315455,
+STORE, 140720583176192, 140720583315455,
+STORE, 94212322082816, 94212324417535,
+SNULL, 94212322295807, 94212324417535,
+STORE, 94212322082816, 94212322295807,
+STORE, 94212322295808, 94212324417535,
+ERASE, 94212322295808, 94212324417535,
+STORE, 94212324392960, 94212324405247,
+STORE, 94212324405248, 94212324417535,
+STORE, 139659688538112, 139659690790911,
+SNULL, 139659688681471, 139659690790911,
+STORE, 139659688538112, 139659688681471,
+STORE, 139659688681472, 139659690790911,
+ERASE, 139659688681472, 139659690790911,
+STORE, 139659690778624, 139659690786815,
+STORE, 139659690786816, 139659690790911,
+STORE, 140720584781824, 140720584785919,
+STORE, 140720584769536, 140720584781823,
+STORE, 139659690749952, 139659690778623,
+STORE, 139659690741760, 139659690749951,
+STORE, 139659686424576, 139659688538111,
+SNULL, 139659686424576, 139659686436863,
+STORE, 139659686436864, 139659688538111,
+STORE, 139659686424576, 139659686436863,
+SNULL, 139659688529919, 139659688538111,
+STORE, 139659686436864, 139659688529919,
+STORE, 139659688529920, 139659688538111,
+ERASE, 139659688529920, 139659688538111,
+STORE, 139659688529920, 139659688538111,
+STORE, 139659682627584, 139659686424575,
+SNULL, 139659682627584, 139659684286463,
+STORE, 139659684286464, 139659686424575,
+STORE, 139659682627584, 139659684286463,
+SNULL, 139659686383615, 139659686424575,
+STORE, 139659684286464, 139659686383615,
+STORE, 139659686383616, 139659686424575,
+SNULL, 139659686383616, 139659686408191,
+STORE, 139659686408192, 139659686424575,
+STORE, 139659686383616, 139659686408191,
+ERASE, 139659686383616, 139659686408191,
+STORE, 139659686383616, 139659686408191,
+ERASE, 139659686408192, 139659686424575,
+STORE, 139659686408192, 139659686424575,
+STORE, 139659690733568, 139659690749951,
+SNULL, 139659686399999, 139659686408191,
+STORE, 139659686383616, 139659686399999,
+STORE, 139659686400000, 139659686408191,
+SNULL, 139659688534015, 139659688538111,
+STORE, 139659688529920, 139659688534015,
+STORE, 139659688534016, 139659688538111,
+SNULL, 94212324397055, 94212324405247,
+STORE, 94212324392960, 94212324397055,
+STORE, 94212324397056, 94212324405247,
+SNULL, 139659690782719, 139659690786815,
+STORE, 139659690778624, 139659690782719,
+STORE, 139659690782720, 139659690786815,
+ERASE, 139659690749952, 139659690778623,
+STORE, 94212355014656, 94212355149823,
+STORE, 139659689050112, 139659690733567,
+STORE, 94212355014656, 94212355284991,
+STORE, 94212355014656, 94212355420159,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140727689830400, 140737488351231,
+SNULL, 140727689838591, 140737488351231,
+STORE, 140727689830400, 140727689838591,
+STORE, 140727689699328, 140727689838591,
+STORE, 94572390281216, 94572392615935,
+SNULL, 94572390494207, 94572392615935,
+STORE, 94572390281216, 94572390494207,
+STORE, 94572390494208, 94572392615935,
+ERASE, 94572390494208, 94572392615935,
+STORE, 94572392591360, 94572392603647,
+STORE, 94572392603648, 94572392615935,
+STORE, 140575923769344, 140575926022143,
+SNULL, 140575923912703, 140575926022143,
+STORE, 140575923769344, 140575923912703,
+STORE, 140575923912704, 140575926022143,
+ERASE, 140575923912704, 140575926022143,
+STORE, 140575926009856, 140575926018047,
+STORE, 140575926018048, 140575926022143,
+STORE, 140727689871360, 140727689875455,
+STORE, 140727689859072, 140727689871359,
+STORE, 140575925981184, 140575926009855,
+STORE, 140575925972992, 140575925981183,
+STORE, 140575921655808, 140575923769343,
+SNULL, 140575921655808, 140575921668095,
+STORE, 140575921668096, 140575923769343,
+STORE, 140575921655808, 140575921668095,
+SNULL, 140575923761151, 140575923769343,
+STORE, 140575921668096, 140575923761151,
+STORE, 140575923761152, 140575923769343,
+ERASE, 140575923761152, 140575923769343,
+STORE, 140575923761152, 140575923769343,
+STORE, 140575917858816, 140575921655807,
+SNULL, 140575917858816, 140575919517695,
+STORE, 140575919517696, 140575921655807,
+STORE, 140575917858816, 140575919517695,
+SNULL, 140575921614847, 140575921655807,
+STORE, 140575919517696, 140575921614847,
+STORE, 140575921614848, 140575921655807,
+SNULL, 140575921614848, 140575921639423,
+STORE, 140575921639424, 140575921655807,
+STORE, 140575921614848, 140575921639423,
+ERASE, 140575921614848, 140575921639423,
+STORE, 140575921614848, 140575921639423,
+ERASE, 140575921639424, 140575921655807,
+STORE, 140575921639424, 140575921655807,
+STORE, 140575925964800, 140575925981183,
+SNULL, 140575921631231, 140575921639423,
+STORE, 140575921614848, 140575921631231,
+STORE, 140575921631232, 140575921639423,
+SNULL, 140575923765247, 140575923769343,
+STORE, 140575923761152, 140575923765247,
+STORE, 140575923765248, 140575923769343,
+SNULL, 94572392595455, 94572392603647,
+STORE, 94572392591360, 94572392595455,
+STORE, 94572392595456, 94572392603647,
+SNULL, 140575926013951, 140575926018047,
+STORE, 140575926009856, 140575926013951,
+STORE, 140575926013952, 140575926018047,
+ERASE, 140575925981184, 140575926009855,
+STORE, 94572402278400, 94572402413567,
+STORE, 140575924281344, 140575925964799,
+STORE, 94572402278400, 94572402548735,
+STORE, 94572402278400, 94572402683903,
+STORE, 94572402278400, 94572402851839,
+SNULL, 94572402827263, 94572402851839,
+STORE, 94572402278400, 94572402827263,
+STORE, 94572402827264, 94572402851839,
+ERASE, 94572402827264, 94572402851839,
+STORE, 94572402278400, 94572402966527,
+STORE, 94572402278400, 94572403109887,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725520506880, 140737488351231,
+SNULL, 140725520515071, 140737488351231,
+STORE, 140725520506880, 140725520515071,
+STORE, 140725520375808, 140725520515071,
+STORE, 93829948788736, 93829951012863,
+SNULL, 93829948899327, 93829951012863,
+STORE, 93829948788736, 93829948899327,
+STORE, 93829948899328, 93829951012863,
+ERASE, 93829948899328, 93829951012863,
+STORE, 93829950992384, 93829951004671,
+STORE, 93829951004672, 93829951012863,
+STORE, 140133696794624, 140133699047423,
+SNULL, 140133696937983, 140133699047423,
+STORE, 140133696794624, 140133696937983,
+STORE, 140133696937984, 140133699047423,
+ERASE, 140133696937984, 140133699047423,
+STORE, 140133699035136, 140133699043327,
+STORE, 140133699043328, 140133699047423,
+STORE, 140725520875520, 140725520879615,
+STORE, 140725520863232, 140725520875519,
+STORE, 140133699006464, 140133699035135,
+STORE, 140133698998272, 140133699006463,
+STORE, 140133692997632, 140133696794623,
+SNULL, 140133692997632, 140133694656511,
+STORE, 140133694656512, 140133696794623,
+STORE, 140133692997632, 140133694656511,
+SNULL, 140133696753663, 140133696794623,
+STORE, 140133694656512, 140133696753663,
+STORE, 140133696753664, 140133696794623,
+SNULL, 140133696753664, 140133696778239,
+STORE, 140133696778240, 140133696794623,
+STORE, 140133696753664, 140133696778239,
+ERASE, 140133696753664, 140133696778239,
+STORE, 140133696753664, 140133696778239,
+ERASE, 140133696778240, 140133696794623,
+STORE, 140133696778240, 140133696794623,
+SNULL, 140133696770047, 140133696778239,
+STORE, 140133696753664, 140133696770047,
+STORE, 140133696770048, 140133696778239,
+SNULL, 93829951000575, 93829951004671,
+STORE, 93829950992384, 93829951000575,
+STORE, 93829951000576, 93829951004671,
+SNULL, 140133699039231, 140133699043327,
+STORE, 140133699035136, 140133699039231,
+STORE, 140133699039232, 140133699043327,
+ERASE, 140133699006464, 140133699035135,
+STORE, 93829978693632, 93829978828799,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140736118022144, 140737488351231,
+SNULL, 140736118030335, 140737488351231,
+STORE, 140736118022144, 140736118030335,
+STORE, 140736117891072, 140736118030335,
+STORE, 94467663982592, 94467666206719,
+SNULL, 94467664093183, 94467666206719,
+STORE, 94467663982592, 94467664093183,
+STORE, 94467664093184, 94467666206719,
+ERASE, 94467664093184, 94467666206719,
+STORE, 94467666186240, 94467666198527,
+STORE, 94467666198528, 94467666206719,
+STORE, 140525377327104, 140525379579903,
+SNULL, 140525377470463, 140525379579903,
+STORE, 140525377327104, 140525377470463,
+STORE, 140525377470464, 140525379579903,
+ERASE, 140525377470464, 140525379579903,
+STORE, 140525379567616, 140525379575807,
+STORE, 140525379575808, 140525379579903,
+STORE, 140736118771712, 140736118775807,
+STORE, 140736118759424, 140736118771711,
+STORE, 140525379538944, 140525379567615,
+STORE, 140525379530752, 140525379538943,
+STORE, 140525373530112, 140525377327103,
+SNULL, 140525373530112, 140525375188991,
+STORE, 140525375188992, 140525377327103,
+STORE, 140525373530112, 140525375188991,
+SNULL, 140525377286143, 140525377327103,
+STORE, 140525375188992, 140525377286143,
+STORE, 140525377286144, 140525377327103,
+SNULL, 140525377286144, 140525377310719,
+STORE, 140525377310720, 140525377327103,
+STORE, 140525377286144, 140525377310719,
+ERASE, 140525377286144, 140525377310719,
+STORE, 140525377286144, 140525377310719,
+ERASE, 140525377310720, 140525377327103,
+STORE, 140525377310720, 140525377327103,
+SNULL, 140525377302527, 140525377310719,
+STORE, 140525377286144, 140525377302527,
+STORE, 140525377302528, 140525377310719,
+SNULL, 94467666194431, 94467666198527,
+STORE, 94467666186240, 94467666194431,
+STORE, 94467666194432, 94467666198527,
+SNULL, 140525379571711, 140525379575807,
+STORE, 140525379567616, 140525379571711,
+STORE, 140525379571712, 140525379575807,
+ERASE, 140525379538944, 140525379567615,
+STORE, 94467693379584, 94467693514751,
+STORE, 94200172744704, 94200172957695,
+STORE, 94200175054848, 94200175058943,
+STORE, 94200175058944, 94200175067135,
+STORE, 94200175067136, 94200175079423,
+STORE, 94200196673536, 94200198905855,
+STORE, 140053867720704, 140053869379583,
+STORE, 140053869379584, 140053871476735,
+STORE, 140053871476736, 140053871493119,
+STORE, 140053871493120, 140053871501311,
+STORE, 140053871501312, 140053871517695,
+STORE, 140053871517696, 140053871529983,
+STORE, 140053871529984, 140053873623039,
+STORE, 140053873623040, 140053873627135,
+STORE, 140053873627136, 140053873631231,
+STORE, 140053873631232, 140053873774591,
+STORE, 140053874143232, 140053875826687,
+STORE, 140053875826688, 140053875843071,
+STORE, 140053875871744, 140053875875839,
+STORE, 140053875875840, 140053875879935,
+STORE, 140053875879936, 140053875884031,
+STORE, 140728538484736, 140728538623999,
+STORE, 140728538652672, 140728538664959,
+STORE, 140728538664960, 140728538669055,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732307775488, 140737488351231,
+SNULL, 140732307783679, 140737488351231,
+STORE, 140732307775488, 140732307783679,
+STORE, 140732307644416, 140732307783679,
+STORE, 93831417630720, 93831419965439,
+SNULL, 93831417843711, 93831419965439,
+STORE, 93831417630720, 93831417843711,
+STORE, 93831417843712, 93831419965439,
+ERASE, 93831417843712, 93831419965439,
+STORE, 93831419940864, 93831419953151,
+STORE, 93831419953152, 93831419965439,
+STORE, 140241062088704, 140241064341503,
+SNULL, 140241062232063, 140241064341503,
+STORE, 140241062088704, 140241062232063,
+STORE, 140241062232064, 140241064341503,
+ERASE, 140241062232064, 140241064341503,
+STORE, 140241064329216, 140241064337407,
+STORE, 140241064337408, 140241064341503,
+STORE, 140732308140032, 140732308144127,
+STORE, 140732308127744, 140732308140031,
+STORE, 140241064300544, 140241064329215,
+STORE, 140241064292352, 140241064300543,
+STORE, 140241059975168, 140241062088703,
+SNULL, 140241059975168, 140241059987455,
+STORE, 140241059987456, 140241062088703,
+STORE, 140241059975168, 140241059987455,
+SNULL, 140241062080511, 140241062088703,
+STORE, 140241059987456, 140241062080511,
+STORE, 140241062080512, 140241062088703,
+ERASE, 140241062080512, 140241062088703,
+STORE, 140241062080512, 140241062088703,
+STORE, 140241056178176, 140241059975167,
+SNULL, 140241056178176, 140241057837055,
+STORE, 140241057837056, 140241059975167,
+STORE, 140241056178176, 140241057837055,
+SNULL, 140241059934207, 140241059975167,
+STORE, 140241057837056, 140241059934207,
+STORE, 140241059934208, 140241059975167,
+SNULL, 140241059934208, 140241059958783,
+STORE, 140241059958784, 140241059975167,
+STORE, 140241059934208, 140241059958783,
+ERASE, 140241059934208, 140241059958783,
+STORE, 140241059934208, 140241059958783,
+ERASE, 140241059958784, 140241059975167,
+STORE, 140241059958784, 140241059975167,
+STORE, 140241064284160, 140241064300543,
+SNULL, 140241059950591, 140241059958783,
+STORE, 140241059934208, 140241059950591,
+STORE, 140241059950592, 140241059958783,
+SNULL, 140241062084607, 140241062088703,
+STORE, 140241062080512, 140241062084607,
+STORE, 140241062084608, 140241062088703,
+SNULL, 93831419944959, 93831419953151,
+STORE, 93831419940864, 93831419944959,
+STORE, 93831419944960, 93831419953151,
+SNULL, 140241064333311, 140241064337407,
+STORE, 140241064329216, 140241064333311,
+STORE, 140241064333312, 140241064337407,
+ERASE, 140241064300544, 140241064329215,
+STORE, 93831435284480, 93831435419647,
+STORE, 140241062600704, 140241064284159,
+STORE, 93831435284480, 93831435554815,
+STORE, 93831435284480, 93831435689983,
+STORE, 93831435284480, 93831435862015,
+SNULL, 93831435837439, 93831435862015,
+STORE, 93831435284480, 93831435837439,
+STORE, 93831435837440, 93831435862015,
+ERASE, 93831435837440, 93831435862015,
+STORE, 93831435284480, 93831435972607,
+STORE, 93831435284480, 93831436107775,
+SNULL, 93831436091391, 93831436107775,
+STORE, 93831435284480, 93831436091391,
+STORE, 93831436091392, 93831436107775,
+ERASE, 93831436091392, 93831436107775,
+STORE, 93831435284480, 93831436226559,
+STORE, 93831435284480, 93831436361727,
+STORE, 93831435284480, 93831436505087,
+STORE, 93831435284480, 93831436652543,
+STORE, 93831435284480, 93831436787711,
+STORE, 93831435284480, 93831436926975,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140728546775040, 140737488351231,
+SNULL, 140728546783231, 140737488351231,
+STORE, 140728546775040, 140728546783231,
+STORE, 140728546643968, 140728546783231,
+STORE, 94456178786304, 94456181010431,
+SNULL, 94456178896895, 94456181010431,
+STORE, 94456178786304, 94456178896895,
+STORE, 94456178896896, 94456181010431,
+ERASE, 94456178896896, 94456181010431,
+STORE, 94456180989952, 94456181002239,
+STORE, 94456181002240, 94456181010431,
+STORE, 140221893091328, 140221895344127,
+SNULL, 140221893234687, 140221895344127,
+STORE, 140221893091328, 140221893234687,
+STORE, 140221893234688, 140221895344127,
+ERASE, 140221893234688, 140221895344127,
+STORE, 140221895331840, 140221895340031,
+STORE, 140221895340032, 140221895344127,
+STORE, 140728547803136, 140728547807231,
+STORE, 140728547790848, 140728547803135,
+STORE, 140221895303168, 140221895331839,
+STORE, 140221895294976, 140221895303167,
+STORE, 140221889294336, 140221893091327,
+SNULL, 140221889294336, 140221890953215,
+STORE, 140221890953216, 140221893091327,
+STORE, 140221889294336, 140221890953215,
+SNULL, 140221893050367, 140221893091327,
+STORE, 140221890953216, 140221893050367,
+STORE, 140221893050368, 140221893091327,
+SNULL, 140221893050368, 140221893074943,
+STORE, 140221893074944, 140221893091327,
+STORE, 140221893050368, 140221893074943,
+ERASE, 140221893050368, 140221893074943,
+STORE, 140221893050368, 140221893074943,
+ERASE, 140221893074944, 140221893091327,
+STORE, 140221893074944, 140221893091327,
+SNULL, 140221893066751, 140221893074943,
+STORE, 140221893050368, 140221893066751,
+STORE, 140221893066752, 140221893074943,
+SNULL, 94456180998143, 94456181002239,
+STORE, 94456180989952, 94456180998143,
+STORE, 94456180998144, 94456181002239,
+SNULL, 140221895335935, 140221895340031,
+STORE, 140221895331840, 140221895335935,
+STORE, 140221895335936, 140221895340031,
+ERASE, 140221895303168, 140221895331839,
+STORE, 94456203730944, 94456203866111,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140734438637568, 140737488351231,
+SNULL, 140734438645759, 140737488351231,
+STORE, 140734438637568, 140734438645759,
+STORE, 140734438506496, 140734438645759,
+STORE, 94652233351168, 94652235575295,
+SNULL, 94652233461759, 94652235575295,
+STORE, 94652233351168, 94652233461759,
+STORE, 94652233461760, 94652235575295,
+ERASE, 94652233461760, 94652235575295,
+STORE, 94652235554816, 94652235567103,
+STORE, 94652235567104, 94652235575295,
+STORE, 140536493195264, 140536495448063,
+SNULL, 140536493338623, 140536495448063,
+STORE, 140536493195264, 140536493338623,
+STORE, 140536493338624, 140536495448063,
+ERASE, 140536493338624, 140536495448063,
+STORE, 140536495435776, 140536495443967,
+STORE, 140536495443968, 140536495448063,
+STORE, 140734439002112, 140734439006207,
+STORE, 140734438989824, 140734439002111,
+STORE, 140536495407104, 140536495435775,
+STORE, 140536495398912, 140536495407103,
+STORE, 140536489398272, 140536493195263,
+SNULL, 140536489398272, 140536491057151,
+STORE, 140536491057152, 140536493195263,
+STORE, 140536489398272, 140536491057151,
+SNULL, 140536493154303, 140536493195263,
+STORE, 140536491057152, 140536493154303,
+STORE, 140536493154304, 140536493195263,
+SNULL, 140536493154304, 140536493178879,
+STORE, 140536493178880, 140536493195263,
+STORE, 140536493154304, 140536493178879,
+ERASE, 140536493154304, 140536493178879,
+STORE, 140536493154304, 140536493178879,
+ERASE, 140536493178880, 140536493195263,
+STORE, 140536493178880, 140536493195263,
+SNULL, 140536493170687, 140536493178879,
+STORE, 140536493154304, 140536493170687,
+STORE, 140536493170688, 140536493178879,
+SNULL, 94652235563007, 94652235567103,
+STORE, 94652235554816, 94652235563007,
+STORE, 94652235563008, 94652235567103,
+SNULL, 140536495439871, 140536495443967,
+STORE, 140536495435776, 140536495439871,
+STORE, 140536495439872, 140536495443967,
+ERASE, 140536495407104, 140536495435775,
+STORE, 94652265619456, 94652265754623,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140721814200320, 140737488351231,
+SNULL, 140721814208511, 140737488351231,
+STORE, 140721814200320, 140721814208511,
+STORE, 140721814069248, 140721814208511,
+STORE, 94062800691200, 94062802915327,
+SNULL, 94062800801791, 94062802915327,
+STORE, 94062800691200, 94062800801791,
+STORE, 94062800801792, 94062802915327,
+ERASE, 94062800801792, 94062802915327,
+STORE, 94062802894848, 94062802907135,
+STORE, 94062802907136, 94062802915327,
+STORE, 139717739700224, 139717741953023,
+SNULL, 139717739843583, 139717741953023,
+STORE, 139717739700224, 139717739843583,
+STORE, 139717739843584, 139717741953023,
+ERASE, 139717739843584, 139717741953023,
+STORE, 139717741940736, 139717741948927,
+STORE, 139717741948928, 139717741953023,
+STORE, 140721814224896, 140721814228991,
+STORE, 140721814212608, 140721814224895,
+STORE, 139717741912064, 139717741940735,
+STORE, 139717741903872, 139717741912063,
+STORE, 139717735903232, 139717739700223,
+SNULL, 139717735903232, 139717737562111,
+STORE, 139717737562112, 139717739700223,
+STORE, 139717735903232, 139717737562111,
+SNULL, 139717739659263, 139717739700223,
+STORE, 139717737562112, 139717739659263,
+STORE, 139717739659264, 139717739700223,
+SNULL, 139717739659264, 139717739683839,
+STORE, 139717739683840, 139717739700223,
+STORE, 139717739659264, 139717739683839,
+ERASE, 139717739659264, 139717739683839,
+STORE, 139717739659264, 139717739683839,
+ERASE, 139717739683840, 139717739700223,
+STORE, 139717739683840, 139717739700223,
+SNULL, 139717739675647, 139717739683839,
+STORE, 139717739659264, 139717739675647,
+STORE, 139717739675648, 139717739683839,
+SNULL, 94062802903039, 94062802907135,
+STORE, 94062802894848, 94062802903039,
+STORE, 94062802903040, 94062802907135,
+SNULL, 139717741944831, 139717741948927,
+STORE, 139717741940736, 139717741944831,
+STORE, 139717741944832, 139717741948927,
+ERASE, 139717741912064, 139717741940735,
+STORE, 94062814060544, 94062814195711,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723945754624, 140737488351231,
+SNULL, 140723945762815, 140737488351231,
+STORE, 140723945754624, 140723945762815,
+STORE, 140723945623552, 140723945762815,
+STORE, 94886119305216, 94886121639935,
+SNULL, 94886119518207, 94886121639935,
+STORE, 94886119305216, 94886119518207,
+STORE, 94886119518208, 94886121639935,
+ERASE, 94886119518208, 94886121639935,
+STORE, 94886121615360, 94886121627647,
+STORE, 94886121627648, 94886121639935,
+STORE, 140152532131840, 140152534384639,
+SNULL, 140152532275199, 140152534384639,
+STORE, 140152532131840, 140152532275199,
+STORE, 140152532275200, 140152534384639,
+ERASE, 140152532275200, 140152534384639,
+STORE, 140152534372352, 140152534380543,
+STORE, 140152534380544, 140152534384639,
+STORE, 140723946213376, 140723946217471,
+STORE, 140723946201088, 140723946213375,
+STORE, 140152534343680, 140152534372351,
+STORE, 140152534335488, 140152534343679,
+STORE, 140152530018304, 140152532131839,
+SNULL, 140152530018304, 140152530030591,
+STORE, 140152530030592, 140152532131839,
+STORE, 140152530018304, 140152530030591,
+SNULL, 140152532123647, 140152532131839,
+STORE, 140152530030592, 140152532123647,
+STORE, 140152532123648, 140152532131839,
+ERASE, 140152532123648, 140152532131839,
+STORE, 140152532123648, 140152532131839,
+STORE, 140152526221312, 140152530018303,
+SNULL, 140152526221312, 140152527880191,
+STORE, 140152527880192, 140152530018303,
+STORE, 140152526221312, 140152527880191,
+SNULL, 140152529977343, 140152530018303,
+STORE, 140152527880192, 140152529977343,
+STORE, 140152529977344, 140152530018303,
+SNULL, 140152529977344, 140152530001919,
+STORE, 140152530001920, 140152530018303,
+STORE, 140152529977344, 140152530001919,
+ERASE, 140152529977344, 140152530001919,
+STORE, 140152529977344, 140152530001919,
+ERASE, 140152530001920, 140152530018303,
+STORE, 140152530001920, 140152530018303,
+STORE, 140152534327296, 140152534343679,
+SNULL, 140152529993727, 140152530001919,
+STORE, 140152529977344, 140152529993727,
+STORE, 140152529993728, 140152530001919,
+SNULL, 140152532127743, 140152532131839,
+STORE, 140152532123648, 140152532127743,
+STORE, 140152532127744, 140152532131839,
+SNULL, 94886121619455, 94886121627647,
+STORE, 94886121615360, 94886121619455,
+STORE, 94886121619456, 94886121627647,
+SNULL, 140152534376447, 140152534380543,
+STORE, 140152534372352, 140152534376447,
+STORE, 140152534376448, 140152534380543,
+ERASE, 140152534343680, 140152534372351,
+STORE, 94886129770496, 94886129905663,
+STORE, 140152532643840, 140152534327295,
+STORE, 94886129770496, 94886130040831,
+STORE, 94886129770496, 94886130175999,
+STORE, 94886129770496, 94886130348031,
+SNULL, 94886130323455, 94886130348031,
+STORE, 94886129770496, 94886130323455,
+STORE, 94886130323456, 94886130348031,
+ERASE, 94886130323456, 94886130348031,
+STORE, 94886129770496, 94886130458623,
+STORE, 94886129770496, 94886130606079,
+SNULL, 94886130573311, 94886130606079,
+STORE, 94886129770496, 94886130573311,
+STORE, 94886130573312, 94886130606079,
+ERASE, 94886130573312, 94886130606079,
+STORE, 94886129770496, 94886130724863,
+STORE, 94886129770496, 94886130876415,
+STORE, 94886129770496, 94886131023871,
+STORE, 94886129770496, 94886131175423,
+STORE, 94886129770496, 94886131318783,
+STORE, 94886129770496, 94886131453951,
+SNULL, 94886131449855, 94886131453951,
+STORE, 94886129770496, 94886131449855,
+STORE, 94886131449856, 94886131453951,
+ERASE, 94886131449856, 94886131453951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735450779648, 140737488351231,
+SNULL, 140735450787839, 140737488351231,
+STORE, 140735450779648, 140735450787839,
+STORE, 140735450648576, 140735450787839,
+STORE, 93947794079744, 93947796414463,
+SNULL, 93947794292735, 93947796414463,
+STORE, 93947794079744, 93947794292735,
+STORE, 93947794292736, 93947796414463,
+ERASE, 93947794292736, 93947796414463,
+STORE, 93947796389888, 93947796402175,
+STORE, 93947796402176, 93947796414463,
+STORE, 139841993433088, 139841995685887,
+SNULL, 139841993576447, 139841995685887,
+STORE, 139841993433088, 139841993576447,
+STORE, 139841993576448, 139841995685887,
+ERASE, 139841993576448, 139841995685887,
+STORE, 139841995673600, 139841995681791,
+STORE, 139841995681792, 139841995685887,
+STORE, 140735451308032, 140735451312127,
+STORE, 140735451295744, 140735451308031,
+STORE, 139841995644928, 139841995673599,
+STORE, 139841995636736, 139841995644927,
+STORE, 139841991319552, 139841993433087,
+SNULL, 139841991319552, 139841991331839,
+STORE, 139841991331840, 139841993433087,
+STORE, 139841991319552, 139841991331839,
+SNULL, 139841993424895, 139841993433087,
+STORE, 139841991331840, 139841993424895,
+STORE, 139841993424896, 139841993433087,
+ERASE, 139841993424896, 139841993433087,
+STORE, 139841993424896, 139841993433087,
+STORE, 139841987522560, 139841991319551,
+SNULL, 139841987522560, 139841989181439,
+STORE, 139841989181440, 139841991319551,
+STORE, 139841987522560, 139841989181439,
+SNULL, 139841991278591, 139841991319551,
+STORE, 139841989181440, 139841991278591,
+STORE, 139841991278592, 139841991319551,
+SNULL, 139841991278592, 139841991303167,
+STORE, 139841991303168, 139841991319551,
+STORE, 139841991278592, 139841991303167,
+ERASE, 139841991278592, 139841991303167,
+STORE, 139841991278592, 139841991303167,
+ERASE, 139841991303168, 139841991319551,
+STORE, 139841991303168, 139841991319551,
+STORE, 139841995628544, 139841995644927,
+SNULL, 139841991294975, 139841991303167,
+STORE, 139841991278592, 139841991294975,
+STORE, 139841991294976, 139841991303167,
+SNULL, 139841993428991, 139841993433087,
+STORE, 139841993424896, 139841993428991,
+STORE, 139841993428992, 139841993433087,
+SNULL, 93947796393983, 93947796402175,
+STORE, 93947796389888, 93947796393983,
+STORE, 93947796393984, 93947796402175,
+SNULL, 139841995677695, 139841995681791,
+STORE, 139841995673600, 139841995677695,
+STORE, 139841995677696, 139841995681791,
+ERASE, 139841995644928, 139841995673599,
+STORE, 93947829739520, 93947829874687,
+STORE, 139841993945088, 139841995628543,
+STORE, 93947829739520, 93947830009855,
+STORE, 93947829739520, 93947830145023,
+STORE, 94659351814144, 94659352027135,
+STORE, 94659354124288, 94659354128383,
+STORE, 94659354128384, 94659354136575,
+STORE, 94659354136576, 94659354148863,
+STORE, 94659383476224, 94659385057279,
+STORE, 139959054557184, 139959056216063,
+STORE, 139959056216064, 139959058313215,
+STORE, 139959058313216, 139959058329599,
+STORE, 139959058329600, 139959058337791,
+STORE, 139959058337792, 139959058354175,
+STORE, 139959058354176, 139959058366463,
+STORE, 139959058366464, 139959060459519,
+STORE, 139959060459520, 139959060463615,
+STORE, 139959060463616, 139959060467711,
+STORE, 139959060467712, 139959060611071,
+STORE, 139959060979712, 139959062663167,
+STORE, 139959062663168, 139959062679551,
+STORE, 139959062708224, 139959062712319,
+STORE, 139959062712320, 139959062716415,
+STORE, 139959062716416, 139959062720511,
+STORE, 140735532539904, 140735532679167,
+STORE, 140735532830720, 140735532843007,
+STORE, 140735532843008, 140735532847103,
+STORE, 93894361829376, 93894362042367,
+STORE, 93894364139520, 93894364143615,
+STORE, 93894364143616, 93894364151807,
+STORE, 93894364151808, 93894364164095,
+STORE, 93894396944384, 93894397624319,
+STORE, 140075612573696, 140075614232575,
+STORE, 140075614232576, 140075616329727,
+STORE, 140075616329728, 140075616346111,
+STORE, 140075616346112, 140075616354303,
+STORE, 140075616354304, 140075616370687,
+STORE, 140075616370688, 140075616382975,
+STORE, 140075616382976, 140075618476031,
+STORE, 140075618476032, 140075618480127,
+STORE, 140075618480128, 140075618484223,
+STORE, 140075618484224, 140075618627583,
+STORE, 140075618996224, 140075620679679,
+STORE, 140075620679680, 140075620696063,
+STORE, 140075620724736, 140075620728831,
+STORE, 140075620728832, 140075620732927,
+STORE, 140075620732928, 140075620737023,
+STORE, 140720830312448, 140720830451711,
+STORE, 140720830631936, 140720830644223,
+STORE, 140720830644224, 140720830648319,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735116226560, 140737488351231,
+SNULL, 140735116234751, 140737488351231,
+STORE, 140735116226560, 140735116234751,
+STORE, 140735116095488, 140735116234751,
+STORE, 94873398054912, 94873400279039,
+SNULL, 94873398165503, 94873400279039,
+STORE, 94873398054912, 94873398165503,
+STORE, 94873398165504, 94873400279039,
+ERASE, 94873398165504, 94873400279039,
+STORE, 94873400258560, 94873400270847,
+STORE, 94873400270848, 94873400279039,
+STORE, 140303828606976, 140303830859775,
+SNULL, 140303828750335, 140303830859775,
+STORE, 140303828606976, 140303828750335,
+STORE, 140303828750336, 140303830859775,
+ERASE, 140303828750336, 140303830859775,
+STORE, 140303830847488, 140303830855679,
+STORE, 140303830855680, 140303830859775,
+STORE, 140735116251136, 140735116255231,
+STORE, 140735116238848, 140735116251135,
+STORE, 140303830818816, 140303830847487,
+STORE, 140303830810624, 140303830818815,
+STORE, 140303824809984, 140303828606975,
+SNULL, 140303824809984, 140303826468863,
+STORE, 140303826468864, 140303828606975,
+STORE, 140303824809984, 140303826468863,
+SNULL, 140303828566015, 140303828606975,
+STORE, 140303826468864, 140303828566015,
+STORE, 140303828566016, 140303828606975,
+SNULL, 140303828566016, 140303828590591,
+STORE, 140303828590592, 140303828606975,
+STORE, 140303828566016, 140303828590591,
+ERASE, 140303828566016, 140303828590591,
+STORE, 140303828566016, 140303828590591,
+ERASE, 140303828590592, 140303828606975,
+STORE, 140303828590592, 140303828606975,
+SNULL, 140303828582399, 140303828590591,
+STORE, 140303828566016, 140303828582399,
+STORE, 140303828582400, 140303828590591,
+SNULL, 94873400266751, 94873400270847,
+STORE, 94873400258560, 94873400266751,
+STORE, 94873400266752, 94873400270847,
+SNULL, 140303830851583, 140303830855679,
+STORE, 140303830847488, 140303830851583,
+STORE, 140303830851584, 140303830855679,
+ERASE, 140303830818816, 140303830847487,
+STORE, 94873413713920, 94873413849087,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140732349956096, 140737488351231,
+SNULL, 140732349964287, 140737488351231,
+STORE, 140732349956096, 140732349964287,
+STORE, 140732349825024, 140732349964287,
+STORE, 94009652736000, 94009655070719,
+SNULL, 94009652948991, 94009655070719,
+STORE, 94009652736000, 94009652948991,
+STORE, 94009652948992, 94009655070719,
+ERASE, 94009652948992, 94009655070719,
+STORE, 94009655046144, 94009655058431,
+STORE, 94009655058432, 94009655070719,
+STORE, 140295688531968, 140295690784767,
+SNULL, 140295688675327, 140295690784767,
+STORE, 140295688531968, 140295688675327,
+STORE, 140295688675328, 140295690784767,
+ERASE, 140295688675328, 140295690784767,
+STORE, 140295690772480, 140295690780671,
+STORE, 140295690780672, 140295690784767,
+STORE, 140732350005248, 140732350009343,
+STORE, 140732349992960, 140732350005247,
+STORE, 140295690743808, 140295690772479,
+STORE, 140295690735616, 140295690743807,
+STORE, 140295686418432, 140295688531967,
+SNULL, 140295686418432, 140295686430719,
+STORE, 140295686430720, 140295688531967,
+STORE, 140295686418432, 140295686430719,
+SNULL, 140295688523775, 140295688531967,
+STORE, 140295686430720, 140295688523775,
+STORE, 140295688523776, 140295688531967,
+ERASE, 140295688523776, 140295688531967,
+STORE, 140295688523776, 140295688531967,
+STORE, 140295682621440, 140295686418431,
+SNULL, 140295682621440, 140295684280319,
+STORE, 140295684280320, 140295686418431,
+STORE, 140295682621440, 140295684280319,
+SNULL, 140295686377471, 140295686418431,
+STORE, 140295684280320, 140295686377471,
+STORE, 140295686377472, 140295686418431,
+SNULL, 140295686377472, 140295686402047,
+STORE, 140295686402048, 140295686418431,
+STORE, 140295686377472, 140295686402047,
+ERASE, 140295686377472, 140295686402047,
+STORE, 140295686377472, 140295686402047,
+ERASE, 140295686402048, 140295686418431,
+STORE, 140295686402048, 140295686418431,
+STORE, 140295690727424, 140295690743807,
+SNULL, 140295686393855, 140295686402047,
+STORE, 140295686377472, 140295686393855,
+STORE, 140295686393856, 140295686402047,
+SNULL, 140295688527871, 140295688531967,
+STORE, 140295688523776, 140295688527871,
+STORE, 140295688527872, 140295688531967,
+SNULL, 94009655050239, 94009655058431,
+STORE, 94009655046144, 94009655050239,
+STORE, 94009655050240, 94009655058431,
+SNULL, 140295690776575, 140295690780671,
+STORE, 140295690772480, 140295690776575,
+STORE, 140295690776576, 140295690780671,
+ERASE, 140295690743808, 140295690772479,
+STORE, 94009672114176, 94009672249343,
+STORE, 140295689043968, 140295690727423,
+STORE, 94009672114176, 94009672384511,
+STORE, 94009672114176, 94009672519679,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722376515584, 140737488351231,
+SNULL, 140722376523775, 140737488351231,
+STORE, 140722376515584, 140722376523775,
+STORE, 140722376384512, 140722376523775,
+STORE, 94089815773184, 94089818107903,
+SNULL, 94089815986175, 94089818107903,
+STORE, 94089815773184, 94089815986175,
+STORE, 94089815986176, 94089818107903,
+ERASE, 94089815986176, 94089818107903,
+STORE, 94089818083328, 94089818095615,
+STORE, 94089818095616, 94089818107903,
+STORE, 140265595711488, 140265597964287,
+SNULL, 140265595854847, 140265597964287,
+STORE, 140265595711488, 140265595854847,
+STORE, 140265595854848, 140265597964287,
+ERASE, 140265595854848, 140265597964287,
+STORE, 140265597952000, 140265597960191,
+STORE, 140265597960192, 140265597964287,
+STORE, 140722378297344, 140722378301439,
+STORE, 140722378285056, 140722378297343,
+STORE, 140265597923328, 140265597951999,
+STORE, 140265597915136, 140265597923327,
+STORE, 140265593597952, 140265595711487,
+SNULL, 140265593597952, 140265593610239,
+STORE, 140265593610240, 140265595711487,
+STORE, 140265593597952, 140265593610239,
+SNULL, 140265595703295, 140265595711487,
+STORE, 140265593610240, 140265595703295,
+STORE, 140265595703296, 140265595711487,
+ERASE, 140265595703296, 140265595711487,
+STORE, 140265595703296, 140265595711487,
+STORE, 140265589800960, 140265593597951,
+SNULL, 140265589800960, 140265591459839,
+STORE, 140265591459840, 140265593597951,
+STORE, 140265589800960, 140265591459839,
+SNULL, 140265593556991, 140265593597951,
+STORE, 140265591459840, 140265593556991,
+STORE, 140265593556992, 140265593597951,
+SNULL, 140265593556992, 140265593581567,
+STORE, 140265593581568, 140265593597951,
+STORE, 140265593556992, 140265593581567,
+ERASE, 140265593556992, 140265593581567,
+STORE, 140265593556992, 140265593581567,
+ERASE, 140265593581568, 140265593597951,
+STORE, 140265593581568, 140265593597951,
+STORE, 140265597906944, 140265597923327,
+SNULL, 140265593573375, 140265593581567,
+STORE, 140265593556992, 140265593573375,
+STORE, 140265593573376, 140265593581567,
+SNULL, 140265595707391, 140265595711487,
+STORE, 140265595703296, 140265595707391,
+STORE, 140265595707392, 140265595711487,
+SNULL, 94089818087423, 94089818095615,
+STORE, 94089818083328, 94089818087423,
+STORE, 94089818087424, 94089818095615,
+SNULL, 140265597956095, 140265597960191,
+STORE, 140265597952000, 140265597956095,
+STORE, 140265597956096, 140265597960191,
+ERASE, 140265597923328, 140265597951999,
+STORE, 94089837146112, 94089837281279,
+STORE, 140265596223488, 140265597906943,
+STORE, 94089837146112, 94089837416447,
+STORE, 94089837146112, 94089837551615,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735265218560, 140737488351231,
+SNULL, 140735265226751, 140737488351231,
+STORE, 140735265218560, 140735265226751,
+STORE, 140735265087488, 140735265226751,
+STORE, 94250422370304, 94250424705023,
+SNULL, 94250422583295, 94250424705023,
+STORE, 94250422370304, 94250422583295,
+STORE, 94250422583296, 94250424705023,
+ERASE, 94250422583296, 94250424705023,
+STORE, 94250424680448, 94250424692735,
+STORE, 94250424692736, 94250424705023,
+STORE, 140344442474496, 140344444727295,
+SNULL, 140344442617855, 140344444727295,
+STORE, 140344442474496, 140344442617855,
+STORE, 140344442617856, 140344444727295,
+ERASE, 140344442617856, 140344444727295,
+STORE, 140344444715008, 140344444723199,
+STORE, 140344444723200, 140344444727295,
+STORE, 140735265341440, 140735265345535,
+STORE, 140735265329152, 140735265341439,
+STORE, 140344444686336, 140344444715007,
+STORE, 140344444678144, 140344444686335,
+STORE, 140344440360960, 140344442474495,
+SNULL, 140344440360960, 140344440373247,
+STORE, 140344440373248, 140344442474495,
+STORE, 140344440360960, 140344440373247,
+SNULL, 140344442466303, 140344442474495,
+STORE, 140344440373248, 140344442466303,
+STORE, 140344442466304, 140344442474495,
+ERASE, 140344442466304, 140344442474495,
+STORE, 140344442466304, 140344442474495,
+STORE, 140344436563968, 140344440360959,
+SNULL, 140344436563968, 140344438222847,
+STORE, 140344438222848, 140344440360959,
+STORE, 140344436563968, 140344438222847,
+SNULL, 140344440319999, 140344440360959,
+STORE, 140344438222848, 140344440319999,
+STORE, 140344440320000, 140344440360959,
+SNULL, 140344440320000, 140344440344575,
+STORE, 140344440344576, 140344440360959,
+STORE, 140344440320000, 140344440344575,
+ERASE, 140344440320000, 140344440344575,
+STORE, 140344440320000, 140344440344575,
+ERASE, 140344440344576, 140344440360959,
+STORE, 140344440344576, 140344440360959,
+STORE, 140344444669952, 140344444686335,
+SNULL, 140344440336383, 140344440344575,
+STORE, 140344440320000, 140344440336383,
+STORE, 140344440336384, 140344440344575,
+SNULL, 140344442470399, 140344442474495,
+STORE, 140344442466304, 140344442470399,
+STORE, 140344442470400, 140344442474495,
+SNULL, 94250424684543, 94250424692735,
+STORE, 94250424680448, 94250424684543,
+STORE, 94250424684544, 94250424692735,
+SNULL, 140344444719103, 140344444723199,
+STORE, 140344444715008, 140344444719103,
+STORE, 140344444719104, 140344444723199,
+ERASE, 140344444686336, 140344444715007,
+STORE, 94250445512704, 94250445647871,
+STORE, 140344442986496, 140344444669951,
+STORE, 94250445512704, 94250445783039,
+STORE, 94250445512704, 94250445918207,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725762719744, 140737488351231,
+SNULL, 140725762727935, 140737488351231,
+STORE, 140725762719744, 140725762727935,
+STORE, 140725762588672, 140725762727935,
+STORE, 94819009097728, 94819011432447,
+SNULL, 94819009310719, 94819011432447,
+STORE, 94819009097728, 94819009310719,
+STORE, 94819009310720, 94819011432447,
+ERASE, 94819009310720, 94819011432447,
+STORE, 94819011407872, 94819011420159,
+STORE, 94819011420160, 94819011432447,
+STORE, 139987985596416, 139987987849215,
+SNULL, 139987985739775, 139987987849215,
+STORE, 139987985596416, 139987985739775,
+STORE, 139987985739776, 139987987849215,
+ERASE, 139987985739776, 139987987849215,
+STORE, 139987987836928, 139987987845119,
+STORE, 139987987845120, 139987987849215,
+STORE, 140725763072000, 140725763076095,
+STORE, 140725763059712, 140725763071999,
+STORE, 139987987808256, 139987987836927,
+STORE, 139987987800064, 139987987808255,
+STORE, 139987983482880, 139987985596415,
+SNULL, 139987983482880, 139987983495167,
+STORE, 139987983495168, 139987985596415,
+STORE, 139987983482880, 139987983495167,
+SNULL, 139987985588223, 139987985596415,
+STORE, 139987983495168, 139987985588223,
+STORE, 139987985588224, 139987985596415,
+ERASE, 139987985588224, 139987985596415,
+STORE, 139987985588224, 139987985596415,
+STORE, 139987979685888, 139987983482879,
+SNULL, 139987979685888, 139987981344767,
+STORE, 139987981344768, 139987983482879,
+STORE, 139987979685888, 139987981344767,
+SNULL, 139987983441919, 139987983482879,
+STORE, 139987981344768, 139987983441919,
+STORE, 139987983441920, 139987983482879,
+SNULL, 139987983441920, 139987983466495,
+STORE, 139987983466496, 139987983482879,
+STORE, 139987983441920, 139987983466495,
+ERASE, 139987983441920, 139987983466495,
+STORE, 139987983441920, 139987983466495,
+ERASE, 139987983466496, 139987983482879,
+STORE, 139987983466496, 139987983482879,
+STORE, 139987987791872, 139987987808255,
+SNULL, 139987983458303, 139987983466495,
+STORE, 139987983441920, 139987983458303,
+STORE, 139987983458304, 139987983466495,
+SNULL, 139987985592319, 139987985596415,
+STORE, 139987985588224, 139987985592319,
+STORE, 139987985592320, 139987985596415,
+SNULL, 94819011411967, 94819011420159,
+STORE, 94819011407872, 94819011411967,
+STORE, 94819011411968, 94819011420159,
+SNULL, 139987987841023, 139987987845119,
+STORE, 139987987836928, 139987987841023,
+STORE, 139987987841024, 139987987845119,
+ERASE, 139987987808256, 139987987836927,
+STORE, 94819028176896, 94819028312063,
+STORE, 139987986108416, 139987987791871,
+STORE, 94819028176896, 94819028447231,
+STORE, 94819028176896, 94819028582399,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722475413504, 140737488351231,
+SNULL, 140722475421695, 140737488351231,
+STORE, 140722475413504, 140722475421695,
+STORE, 140722475282432, 140722475421695,
+STORE, 94620599119872, 94620601343999,
+SNULL, 94620599230463, 94620601343999,
+STORE, 94620599119872, 94620599230463,
+STORE, 94620599230464, 94620601343999,
+ERASE, 94620599230464, 94620601343999,
+STORE, 94620601323520, 94620601335807,
+STORE, 94620601335808, 94620601343999,
+STORE, 139891763060736, 139891765313535,
+SNULL, 139891763204095, 139891765313535,
+STORE, 139891763060736, 139891763204095,
+STORE, 139891763204096, 139891765313535,
+ERASE, 139891763204096, 139891765313535,
+STORE, 139891765301248, 139891765309439,
+STORE, 139891765309440, 139891765313535,
+STORE, 140722475700224, 140722475704319,
+STORE, 140722475687936, 140722475700223,
+STORE, 139891765272576, 139891765301247,
+STORE, 139891765264384, 139891765272575,
+STORE, 139891759263744, 139891763060735,
+SNULL, 139891759263744, 139891760922623,
+STORE, 139891760922624, 139891763060735,
+STORE, 139891759263744, 139891760922623,
+SNULL, 139891763019775, 139891763060735,
+STORE, 139891760922624, 139891763019775,
+STORE, 139891763019776, 139891763060735,
+SNULL, 139891763019776, 139891763044351,
+STORE, 139891763044352, 139891763060735,
+STORE, 139891763019776, 139891763044351,
+ERASE, 139891763019776, 139891763044351,
+STORE, 139891763019776, 139891763044351,
+ERASE, 139891763044352, 139891763060735,
+STORE, 139891763044352, 139891763060735,
+SNULL, 139891763036159, 139891763044351,
+STORE, 139891763019776, 139891763036159,
+STORE, 139891763036160, 139891763044351,
+SNULL, 94620601331711, 94620601335807,
+STORE, 94620601323520, 94620601331711,
+STORE, 94620601331712, 94620601335807,
+SNULL, 139891765305343, 139891765309439,
+STORE, 139891765301248, 139891765305343,
+STORE, 139891765305344, 139891765309439,
+ERASE, 139891765272576, 139891765301247,
+STORE, 94620610027520, 94620610162687,
+STORE, 94031976210432, 94031976423423,
+STORE, 94031978520576, 94031978524671,
+STORE, 94031978524672, 94031978532863,
+STORE, 94031978532864, 94031978545151,
+STORE, 94031990398976, 94031992565759,
+STORE, 140336240640000, 140336242298879,
+STORE, 140336242298880, 140336244396031,
+STORE, 140336244396032, 140336244412415,
+STORE, 140336244412416, 140336244420607,
+STORE, 140336244420608, 140336244436991,
+STORE, 140336244436992, 140336244449279,
+STORE, 140336244449280, 140336246542335,
+STORE, 140336246542336, 140336246546431,
+STORE, 140336246546432, 140336246550527,
+STORE, 140336246550528, 140336246693887,
+STORE, 140336247062528, 140336248745983,
+STORE, 140336248745984, 140336248762367,
+STORE, 140336248791040, 140336248795135,
+STORE, 140336248795136, 140336248799231,
+STORE, 140336248799232, 140336248803327,
+STORE, 140728500064256, 140728500203519,
+STORE, 140728501501952, 140728501514239,
+STORE, 140728501514240, 140728501518335,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140730503987200, 140737488351231,
+SNULL, 140730503995391, 140737488351231,
+STORE, 140730503987200, 140730503995391,
+STORE, 140730503856128, 140730503995391,
+STORE, 93866544205824, 93866546429951,
+SNULL, 93866544316415, 93866546429951,
+STORE, 93866544205824, 93866544316415,
+STORE, 93866544316416, 93866546429951,
+ERASE, 93866544316416, 93866546429951,
+STORE, 93866546409472, 93866546421759,
+STORE, 93866546421760, 93866546429951,
+STORE, 140216311959552, 140216314212351,
+SNULL, 140216312102911, 140216314212351,
+STORE, 140216311959552, 140216312102911,
+STORE, 140216312102912, 140216314212351,
+ERASE, 140216312102912, 140216314212351,
+STORE, 140216314200064, 140216314208255,
+STORE, 140216314208256, 140216314212351,
+STORE, 140730504626176, 140730504630271,
+STORE, 140730504613888, 140730504626175,
+STORE, 140216314171392, 140216314200063,
+STORE, 140216314163200, 140216314171391,
+STORE, 140216308162560, 140216311959551,
+SNULL, 140216308162560, 140216309821439,
+STORE, 140216309821440, 140216311959551,
+STORE, 140216308162560, 140216309821439,
+SNULL, 140216311918591, 140216311959551,
+STORE, 140216309821440, 140216311918591,
+STORE, 140216311918592, 140216311959551,
+SNULL, 140216311918592, 140216311943167,
+STORE, 140216311943168, 140216311959551,
+STORE, 140216311918592, 140216311943167,
+ERASE, 140216311918592, 140216311943167,
+STORE, 140216311918592, 140216311943167,
+ERASE, 140216311943168, 140216311959551,
+STORE, 140216311943168, 140216311959551,
+SNULL, 140216311934975, 140216311943167,
+STORE, 140216311918592, 140216311934975,
+STORE, 140216311934976, 140216311943167,
+SNULL, 93866546417663, 93866546421759,
+STORE, 93866546409472, 93866546417663,
+STORE, 93866546417664, 93866546421759,
+SNULL, 140216314204159, 140216314208255,
+STORE, 140216314200064, 140216314204159,
+STORE, 140216314204160, 140216314208255,
+ERASE, 140216314171392, 140216314200063,
+STORE, 93866550386688, 93866550521855,
+STORE, 94074292674560, 94074292887551,
+STORE, 94074294984704, 94074294988799,
+STORE, 94074294988800, 94074294996991,
+STORE, 94074294996992, 94074295009279,
+STORE, 94074300219392, 94074301378559,
+STORE, 139781563256832, 139781564915711,
+STORE, 139781564915712, 139781567012863,
+STORE, 139781567012864, 139781567029247,
+STORE, 139781567029248, 139781567037439,
+STORE, 139781567037440, 139781567053823,
+STORE, 139781567053824, 139781567066111,
+STORE, 139781567066112, 139781569159167,
+STORE, 139781569159168, 139781569163263,
+STORE, 139781569163264, 139781569167359,
+STORE, 139781569167360, 139781569310719,
+STORE, 139781569679360, 139781571362815,
+STORE, 139781571362816, 139781571379199,
+STORE, 139781571407872, 139781571411967,
+STORE, 139781571411968, 139781571416063,
+STORE, 139781571416064, 139781571420159,
+STORE, 140723688488960, 140723688628223,
+STORE, 140723689005056, 140723689017343,
+STORE, 140723689017344, 140723689021439,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735189745664, 140737488351231,
+SNULL, 140735189753855, 140737488351231,
+STORE, 140735189745664, 140735189753855,
+STORE, 140735189614592, 140735189753855,
+STORE, 94172072177664, 94172074512383,
+SNULL, 94172072390655, 94172074512383,
+STORE, 94172072177664, 94172072390655,
+STORE, 94172072390656, 94172074512383,
+ERASE, 94172072390656, 94172074512383,
+STORE, 94172074487808, 94172074500095,
+STORE, 94172074500096, 94172074512383,
+STORE, 140687827263488, 140687829516287,
+SNULL, 140687827406847, 140687829516287,
+STORE, 140687827263488, 140687827406847,
+STORE, 140687827406848, 140687829516287,
+ERASE, 140687827406848, 140687829516287,
+STORE, 140687829504000, 140687829512191,
+STORE, 140687829512192, 140687829516287,
+STORE, 140735189766144, 140735189770239,
+STORE, 140735189753856, 140735189766143,
+STORE, 140687829475328, 140687829503999,
+STORE, 140687829467136, 140687829475327,
+STORE, 140687825149952, 140687827263487,
+SNULL, 140687825149952, 140687825162239,
+STORE, 140687825162240, 140687827263487,
+STORE, 140687825149952, 140687825162239,
+SNULL, 140687827255295, 140687827263487,
+STORE, 140687825162240, 140687827255295,
+STORE, 140687827255296, 140687827263487,
+ERASE, 140687827255296, 140687827263487,
+STORE, 140687827255296, 140687827263487,
+STORE, 140687821352960, 140687825149951,
+SNULL, 140687821352960, 140687823011839,
+STORE, 140687823011840, 140687825149951,
+STORE, 140687821352960, 140687823011839,
+SNULL, 140687825108991, 140687825149951,
+STORE, 140687823011840, 140687825108991,
+STORE, 140687825108992, 140687825149951,
+SNULL, 140687825108992, 140687825133567,
+STORE, 140687825133568, 140687825149951,
+STORE, 140687825108992, 140687825133567,
+ERASE, 140687825108992, 140687825133567,
+STORE, 140687825108992, 140687825133567,
+ERASE, 140687825133568, 140687825149951,
+STORE, 140687825133568, 140687825149951,
+STORE, 140687829458944, 140687829475327,
+SNULL, 140687825125375, 140687825133567,
+STORE, 140687825108992, 140687825125375,
+STORE, 140687825125376, 140687825133567,
+SNULL, 140687827259391, 140687827263487,
+STORE, 140687827255296, 140687827259391,
+STORE, 140687827259392, 140687827263487,
+SNULL, 94172074491903, 94172074500095,
+STORE, 94172074487808, 94172074491903,
+STORE, 94172074491904, 94172074500095,
+SNULL, 140687829508095, 140687829512191,
+STORE, 140687829504000, 140687829508095,
+STORE, 140687829508096, 140687829512191,
+ERASE, 140687829475328, 140687829503999,
+STORE, 94172092432384, 94172092567551,
+STORE, 140687827775488, 140687829458943,
+STORE, 94172092432384, 94172092702719,
+STORE, 94172092432384, 94172092837887,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140737229504512, 140737488351231,
+SNULL, 140737229512703, 140737488351231,
+STORE, 140737229504512, 140737229512703,
+STORE, 140737229373440, 140737229512703,
+STORE, 94155246866432, 94155249090559,
+SNULL, 94155246977023, 94155249090559,
+STORE, 94155246866432, 94155246977023,
+STORE, 94155246977024, 94155249090559,
+ERASE, 94155246977024, 94155249090559,
+STORE, 94155249070080, 94155249082367,
+STORE, 94155249082368, 94155249090559,
+STORE, 140640993693696, 140640995946495,
+SNULL, 140640993837055, 140640995946495,
+STORE, 140640993693696, 140640993837055,
+STORE, 140640993837056, 140640995946495,
+ERASE, 140640993837056, 140640995946495,
+STORE, 140640995934208, 140640995942399,
+STORE, 140640995942400, 140640995946495,
+STORE, 140737230004224, 140737230008319,
+STORE, 140737229991936, 140737230004223,
+STORE, 140640995905536, 140640995934207,
+STORE, 140640995897344, 140640995905535,
+STORE, 140640989896704, 140640993693695,
+SNULL, 140640989896704, 140640991555583,
+STORE, 140640991555584, 140640993693695,
+STORE, 140640989896704, 140640991555583,
+SNULL, 140640993652735, 140640993693695,
+STORE, 140640991555584, 140640993652735,
+STORE, 140640993652736, 140640993693695,
+SNULL, 140640993652736, 140640993677311,
+STORE, 140640993677312, 140640993693695,
+STORE, 140640993652736, 140640993677311,
+ERASE, 140640993652736, 140640993677311,
+STORE, 140640993652736, 140640993677311,
+ERASE, 140640993677312, 140640993693695,
+STORE, 140640993677312, 140640993693695,
+SNULL, 140640993669119, 140640993677311,
+STORE, 140640993652736, 140640993669119,
+STORE, 140640993669120, 140640993677311,
+SNULL, 94155249078271, 94155249082367,
+STORE, 94155249070080, 94155249078271,
+STORE, 94155249078272, 94155249082367,
+SNULL, 140640995938303, 140640995942399,
+STORE, 140640995934208, 140640995938303,
+STORE, 140640995938304, 140640995942399,
+ERASE, 140640995905536, 140640995934207,
+STORE, 94155281035264, 94155281170431,
+STORE, 94088066453504, 94088066564095,
+STORE, 94088068657152, 94088068665343,
+STORE, 94088068665344, 94088068669439,
+STORE, 94088068669440, 94088068677631,
+STORE, 94088090214400, 94088090349567,
+STORE, 140503024627712, 140503026286591,
+STORE, 140503026286592, 140503028383743,
+STORE, 140503028383744, 140503028400127,
+STORE, 140503028400128, 140503028408319,
+STORE, 140503028408320, 140503028424703,
+STORE, 140503028424704, 140503028568063,
+STORE, 140503030628352, 140503030636543,
+STORE, 140503030665216, 140503030669311,
+STORE, 140503030669312, 140503030673407,
+STORE, 140503030673408, 140503030677503,
+STORE, 140730894725120, 140730894864383,
+STORE, 140730894880768, 140730894893055,
+STORE, 140730894893056, 140730894897151,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140730434342912, 140737488351231,
+SNULL, 140730434351103, 140737488351231,
+STORE, 140730434342912, 140730434351103,
+STORE, 140730434211840, 140730434351103,
+STORE, 4194304, 5128191,
+STORE, 7221248, 7241727,
+STORE, 7241728, 7249919,
+STORE, 140109041938432, 140109044191231,
+SNULL, 140109042081791, 140109044191231,
+STORE, 140109041938432, 140109042081791,
+STORE, 140109042081792, 140109044191231,
+ERASE, 140109042081792, 140109044191231,
+STORE, 140109044178944, 140109044187135,
+STORE, 140109044187136, 140109044191231,
+STORE, 140730434850816, 140730434854911,
+STORE, 140730434838528, 140730434850815,
+STORE, 140109044150272, 140109044178943,
+STORE, 140109044142080, 140109044150271,
+STORE, 140109038776320, 140109041938431,
+SNULL, 140109038776320, 140109039837183,
+STORE, 140109039837184, 140109041938431,
+STORE, 140109038776320, 140109039837183,
+SNULL, 140109041930239, 140109041938431,
+STORE, 140109039837184, 140109041930239,
+STORE, 140109041930240, 140109041938431,
+ERASE, 140109041930240, 140109041938431,
+STORE, 140109041930240, 140109041938431,
+STORE, 140109034979328, 140109038776319,
+SNULL, 140109034979328, 140109036638207,
+STORE, 140109036638208, 140109038776319,
+STORE, 140109034979328, 140109036638207,
+SNULL, 140109038735359, 140109038776319,
+STORE, 140109036638208, 140109038735359,
+STORE, 140109038735360, 140109038776319,
+SNULL, 140109038735360, 140109038759935,
+STORE, 140109038759936, 140109038776319,
+STORE, 140109038735360, 140109038759935,
+ERASE, 140109038735360, 140109038759935,
+STORE, 140109038735360, 140109038759935,
+ERASE, 140109038759936, 140109038776319,
+STORE, 140109038759936, 140109038776319,
+STORE, 140109044129792, 140109044150271,
+SNULL, 140109038751743, 140109038759935,
+STORE, 140109038735360, 140109038751743,
+STORE, 140109038751744, 140109038759935,
+SNULL, 140109041934335, 140109041938431,
+STORE, 140109041930240, 140109041934335,
+STORE, 140109041934336, 140109041938431,
+SNULL, 7233535, 7241727,
+STORE, 7221248, 7233535,
+STORE, 7233536, 7241727,
+SNULL, 140109044183039, 140109044187135,
+STORE, 140109044178944, 140109044183039,
+STORE, 140109044183040, 140109044187135,
+ERASE, 140109044150272, 140109044178943,
+STORE, 20000768, 20135935,
+STORE, 20000768, 20283391,
+STORE, 140109042446336, 140109044129791,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140730853408768, 140737488351231,
+SNULL, 140730853416959, 140737488351231,
+STORE, 140730853408768, 140730853416959,
+STORE, 140730853277696, 140730853416959,
+STORE, 94865902977024, 94865905311743,
+SNULL, 94865903190015, 94865905311743,
+STORE, 94865902977024, 94865903190015,
+STORE, 94865903190016, 94865905311743,
+ERASE, 94865903190016, 94865905311743,
+STORE, 94865905287168, 94865905299455,
+STORE, 94865905299456, 94865905311743,
+STORE, 139768865738752, 139768867991551,
+SNULL, 139768865882111, 139768867991551,
+STORE, 139768865738752, 139768865882111,
+STORE, 139768865882112, 139768867991551,
+ERASE, 139768865882112, 139768867991551,
+STORE, 139768867979264, 139768867987455,
+STORE, 139768867987456, 139768867991551,
+STORE, 140730853957632, 140730853961727,
+STORE, 140730853945344, 140730853957631,
+STORE, 139768867950592, 139768867979263,
+STORE, 139768867942400, 139768867950591,
+STORE, 139768863625216, 139768865738751,
+SNULL, 139768863625216, 139768863637503,
+STORE, 139768863637504, 139768865738751,
+STORE, 139768863625216, 139768863637503,
+SNULL, 139768865730559, 139768865738751,
+STORE, 139768863637504, 139768865730559,
+STORE, 139768865730560, 139768865738751,
+ERASE, 139768865730560, 139768865738751,
+STORE, 139768865730560, 139768865738751,
+STORE, 139768859828224, 139768863625215,
+SNULL, 139768859828224, 139768861487103,
+STORE, 139768861487104, 139768863625215,
+STORE, 139768859828224, 139768861487103,
+SNULL, 139768863584255, 139768863625215,
+STORE, 139768861487104, 139768863584255,
+STORE, 139768863584256, 139768863625215,
+SNULL, 139768863584256, 139768863608831,
+STORE, 139768863608832, 139768863625215,
+STORE, 139768863584256, 139768863608831,
+ERASE, 139768863584256, 139768863608831,
+STORE, 139768863584256, 139768863608831,
+ERASE, 139768863608832, 139768863625215,
+STORE, 139768863608832, 139768863625215,
+STORE, 139768867934208, 139768867950591,
+SNULL, 139768863600639, 139768863608831,
+STORE, 139768863584256, 139768863600639,
+STORE, 139768863600640, 139768863608831,
+SNULL, 139768865734655, 139768865738751,
+STORE, 139768865730560, 139768865734655,
+STORE, 139768865734656, 139768865738751,
+SNULL, 94865905291263, 94865905299455,
+STORE, 94865905287168, 94865905291263,
+STORE, 94865905291264, 94865905299455,
+SNULL, 139768867983359, 139768867987455,
+STORE, 139768867979264, 139768867983359,
+STORE, 139768867983360, 139768867987455,
+ERASE, 139768867950592, 139768867979263,
+STORE, 94865923670016, 94865923805183,
+STORE, 139768866250752, 139768867934207,
+STORE, 94865923670016, 94865923940351,
+STORE, 94865923670016, 94865924075519,
+STORE, 94865923670016, 94865924222975,
+SNULL, 94865924210687, 94865924222975,
+STORE, 94865923670016, 94865924210687,
+STORE, 94865924210688, 94865924222975,
+ERASE, 94865924210688, 94865924222975,
+STORE, 94865923670016, 94865924349951,
+STORE, 94865923670016, 94865924493311,
+STORE, 94865923670016, 94865924640767,
+SNULL, 94865924603903, 94865924640767,
+STORE, 94865923670016, 94865924603903,
+STORE, 94865924603904, 94865924640767,
+ERASE, 94865924603904, 94865924640767,
+STORE, 94865923670016, 94865924747263,
+STORE, 94865923670016, 94865924898815,
+SNULL, 94865924874239, 94865924898815,
+STORE, 94865923670016, 94865924874239,
+STORE, 94865924874240, 94865924898815,
+ERASE, 94865924874240, 94865924898815,
+STORE, 94865923670016, 94865925025791,
+SNULL, 94865925013503, 94865925025791,
+STORE, 94865923670016, 94865925013503,
+STORE, 94865925013504, 94865925025791,
+ERASE, 94865925013504, 94865925025791,
+SNULL, 94865924988927, 94865925013503,
+STORE, 94865923670016, 94865924988927,
+STORE, 94865924988928, 94865925013503,
+ERASE, 94865924988928, 94865925013503,
+STORE, 94865923670016, 94865925152767,
+SNULL, 94865925136383, 94865925152767,
+STORE, 94865923670016, 94865925136383,
+STORE, 94865925136384, 94865925152767,
+ERASE, 94865925136384, 94865925152767,
+STORE, 94865923670016, 94865925292031,
+SNULL, 94865925279743, 94865925292031,
+STORE, 94865923670016, 94865925279743,
+STORE, 94865925279744, 94865925292031,
+ERASE, 94865925279744, 94865925292031,
+SNULL, 94865925255167, 94865925279743,
+STORE, 94865923670016, 94865925255167,
+STORE, 94865925255168, 94865925279743,
+ERASE, 94865925255168, 94865925279743,
+STORE, 94865923670016, 94865925406719,
+SNULL, 94865925394431, 94865925406719,
+STORE, 94865923670016, 94865925394431,
+STORE, 94865925394432, 94865925406719,
+ERASE, 94865925394432, 94865925406719,
+STORE, 94865923670016, 94865925545983,
+SNULL, 94865925533695, 94865925545983,
+STORE, 94865923670016, 94865925533695,
+STORE, 94865925533696, 94865925545983,
+ERASE, 94865925533696, 94865925545983,
+SNULL, 94865925492735, 94865925533695,
+STORE, 94865923670016, 94865925492735,
+STORE, 94865925492736, 94865925533695,
+ERASE, 94865925492736, 94865925533695,
+STORE, 94865923670016, 94865925627903,
+SNULL, 94865925599231, 94865925627903,
+STORE, 94865923670016, 94865925599231,
+STORE, 94865925599232, 94865925627903,
+ERASE, 94865925599232, 94865925627903,
+STORE, 94865923670016, 94865925738495,
+SNULL, 94865925726207, 94865925738495,
+STORE, 94865923670016, 94865925726207,
+STORE, 94865925726208, 94865925738495,
+ERASE, 94865925726208, 94865925738495,
+STORE, 94865923670016, 94865925877759,
+SNULL, 94865925865471, 94865925877759,
+STORE, 94865923670016, 94865925865471,
+STORE, 94865925865472, 94865925877759,
+ERASE, 94865925865472, 94865925877759,
+STORE, 94865923670016, 94865926021119,
+SNULL, 94865926008831, 94865926021119,
+STORE, 94865923670016, 94865926008831,
+STORE, 94865926008832, 94865926021119,
+ERASE, 94865926008832, 94865926021119,
+SNULL, 94865925971967, 94865926008831,
+STORE, 94865923670016, 94865925971967,
+STORE, 94865925971968, 94865926008831,
+ERASE, 94865925971968, 94865926008831,
+STORE, 94865923670016, 94865926115327,
+STORE, 94865923670016, 94865926254591,
+SNULL, 94865926246399, 94865926254591,
+STORE, 94865923670016, 94865926246399,
+STORE, 94865926246400, 94865926254591,
+ERASE, 94865926246400, 94865926254591,
+STORE, 94865923670016, 94865926385663,
+STORE, 94865923670016, 94865926537215,
+STORE, 94865923670016, 94865926672383,
+STORE, 94865923670016, 94865926815743,
+STORE, 94865923670016, 94865926955007,
+STORE, 94865923670016, 94865927094271,
+STORE, 94865923670016, 94865927233535,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140731148435456, 140737488351231,
+SNULL, 140731148443647, 140737488351231,
+STORE, 140731148435456, 140731148443647,
+STORE, 140731148304384, 140731148443647,
+STORE, 94090775400448, 94090777735167,
+SNULL, 94090775613439, 94090777735167,
+STORE, 94090775400448, 94090775613439,
+STORE, 94090775613440, 94090777735167,
+ERASE, 94090775613440, 94090777735167,
+STORE, 94090777710592, 94090777722879,
+STORE, 94090777722880, 94090777735167,
+STORE, 140301090283520, 140301092536319,
+SNULL, 140301090426879, 140301092536319,
+STORE, 140301090283520, 140301090426879,
+STORE, 140301090426880, 140301092536319,
+ERASE, 140301090426880, 140301092536319,
+STORE, 140301092524032, 140301092532223,
+STORE, 140301092532224, 140301092536319,
+STORE, 140731148570624, 140731148574719,
+STORE, 140731148558336, 140731148570623,
+STORE, 140301092495360, 140301092524031,
+STORE, 140301092487168, 140301092495359,
+STORE, 140301088169984, 140301090283519,
+SNULL, 140301088169984, 140301088182271,
+STORE, 140301088182272, 140301090283519,
+STORE, 140301088169984, 140301088182271,
+SNULL, 140301090275327, 140301090283519,
+STORE, 140301088182272, 140301090275327,
+STORE, 140301090275328, 140301090283519,
+ERASE, 140301090275328, 140301090283519,
+STORE, 140301090275328, 140301090283519,
+STORE, 140301084372992, 140301088169983,
+SNULL, 140301084372992, 140301086031871,
+STORE, 140301086031872, 140301088169983,
+STORE, 140301084372992, 140301086031871,
+SNULL, 140301088129023, 140301088169983,
+STORE, 140301086031872, 140301088129023,
+STORE, 140301088129024, 140301088169983,
+SNULL, 140301088129024, 140301088153599,
+STORE, 140301088153600, 140301088169983,
+STORE, 140301088129024, 140301088153599,
+ERASE, 140301088129024, 140301088153599,
+STORE, 140301088129024, 140301088153599,
+ERASE, 140301088153600, 140301088169983,
+STORE, 140301088153600, 140301088169983,
+STORE, 140301092478976, 140301092495359,
+SNULL, 140301088145407, 140301088153599,
+STORE, 140301088129024, 140301088145407,
+STORE, 140301088145408, 140301088153599,
+SNULL, 140301090279423, 140301090283519,
+STORE, 140301090275328, 140301090279423,
+STORE, 140301090279424, 140301090283519,
+SNULL, 94090777714687, 94090777722879,
+STORE, 94090777710592, 94090777714687,
+STORE, 94090777714688, 94090777722879,
+SNULL, 140301092528127, 140301092532223,
+STORE, 140301092524032, 140301092528127,
+STORE, 140301092528128, 140301092532223,
+ERASE, 140301092495360, 140301092524031,
+STORE, 94090794590208, 94090794725375,
+STORE, 140301090795520, 140301092478975,
+STORE, 94090794590208, 94090794860543,
+STORE, 94090794590208, 94090794995711,
+STORE, 94090794590208, 94090795163647,
+SNULL, 94090795139071, 94090795163647,
+STORE, 94090794590208, 94090795139071,
+STORE, 94090795139072, 94090795163647,
+ERASE, 94090795139072, 94090795163647,
+STORE, 94090794590208, 94090795278335,
+STORE, 94090794590208, 94090795425791,
+SNULL, 94090795388927, 94090795425791,
+STORE, 94090794590208, 94090795388927,
+STORE, 94090795388928, 94090795425791,
+ERASE, 94090795388928, 94090795425791,
+STORE, 94090794590208, 94090795528191,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733084430336, 140737488351231,
+SNULL, 140733084438527, 140737488351231,
+STORE, 140733084430336, 140733084438527,
+STORE, 140733084299264, 140733084438527,
+STORE, 94116169183232, 94116171517951,
+SNULL, 94116169396223, 94116171517951,
+STORE, 94116169183232, 94116169396223,
+STORE, 94116169396224, 94116171517951,
+ERASE, 94116169396224, 94116171517951,
+STORE, 94116171493376, 94116171505663,
+STORE, 94116171505664, 94116171517951,
+STORE, 139772214128640, 139772216381439,
+SNULL, 139772214271999, 139772216381439,
+STORE, 139772214128640, 139772214271999,
+STORE, 139772214272000, 139772216381439,
+ERASE, 139772214272000, 139772216381439,
+STORE, 139772216369152, 139772216377343,
+STORE, 139772216377344, 139772216381439,
+STORE, 140733085270016, 140733085274111,
+STORE, 140733085257728, 140733085270015,
+STORE, 139772216340480, 139772216369151,
+STORE, 139772216332288, 139772216340479,
+STORE, 139772212015104, 139772214128639,
+SNULL, 139772212015104, 139772212027391,
+STORE, 139772212027392, 139772214128639,
+STORE, 139772212015104, 139772212027391,
+SNULL, 139772214120447, 139772214128639,
+STORE, 139772212027392, 139772214120447,
+STORE, 139772214120448, 139772214128639,
+ERASE, 139772214120448, 139772214128639,
+STORE, 139772214120448, 139772214128639,
+STORE, 139772208218112, 139772212015103,
+SNULL, 139772208218112, 139772209876991,
+STORE, 139772209876992, 139772212015103,
+STORE, 139772208218112, 139772209876991,
+SNULL, 139772211974143, 139772212015103,
+STORE, 139772209876992, 139772211974143,
+STORE, 139772211974144, 139772212015103,
+SNULL, 139772211974144, 139772211998719,
+STORE, 139772211998720, 139772212015103,
+STORE, 139772211974144, 139772211998719,
+ERASE, 139772211974144, 139772211998719,
+STORE, 139772211974144, 139772211998719,
+ERASE, 139772211998720, 139772212015103,
+STORE, 139772211998720, 139772212015103,
+STORE, 139772216324096, 139772216340479,
+SNULL, 139772211990527, 139772211998719,
+STORE, 139772211974144, 139772211990527,
+STORE, 139772211990528, 139772211998719,
+SNULL, 139772214124543, 139772214128639,
+STORE, 139772214120448, 139772214124543,
+STORE, 139772214124544, 139772214128639,
+SNULL, 94116171497471, 94116171505663,
+STORE, 94116171493376, 94116171497471,
+STORE, 94116171497472, 94116171505663,
+SNULL, 139772216373247, 139772216377343,
+STORE, 139772216369152, 139772216373247,
+STORE, 139772216373248, 139772216377343,
+ERASE, 139772216340480, 139772216369151,
+STORE, 94116199383040, 94116199518207,
+STORE, 139772214640640, 139772216324095,
+STORE, 94116199383040, 94116199653375,
+STORE, 94116199383040, 94116199788543,
+STORE, 140737488347136, 140737488351231,
+STORE, 140726067826688, 140737488351231,
+SNULL, 140726067830783, 140737488351231,
+STORE, 140726067826688, 140726067830783,
+STORE, 140726067695616, 140726067830783,
+STORE, 94535150673920, 94535152898047,
+SNULL, 94535150784511, 94535152898047,
+STORE, 94535150673920, 94535150784511,
+STORE, 94535150784512, 94535152898047,
+ERASE, 94535150784512, 94535152898047,
+STORE, 94535152877568, 94535152889855,
+STORE, 94535152889856, 94535152898047,
+STORE, 140381257314304, 140381259567103,
+SNULL, 140381257457663, 140381259567103,
+STORE, 140381257314304, 140381257457663,
+STORE, 140381257457664, 140381259567103,
+ERASE, 140381257457664, 140381259567103,
+STORE, 140381259554816, 140381259563007,
+STORE, 140381259563008, 140381259567103,
+STORE, 140726068060160, 140726068064255,
+STORE, 140726068047872, 140726068060159,
+STORE, 140381259526144, 140381259554815,
+STORE, 140381259517952, 140381259526143,
+STORE, 140381253517312, 140381257314303,
+SNULL, 140381253517312, 140381255176191,
+STORE, 140381255176192, 140381257314303,
+STORE, 140381253517312, 140381255176191,
+SNULL, 140381257273343, 140381257314303,
+STORE, 140381255176192, 140381257273343,
+STORE, 140381257273344, 140381257314303,
+SNULL, 140381257273344, 140381257297919,
+STORE, 140381257297920, 140381257314303,
+STORE, 140381257273344, 140381257297919,
+ERASE, 140381257273344, 140381257297919,
+STORE, 140381257273344, 140381257297919,
+ERASE, 140381257297920, 140381257314303,
+STORE, 140381257297920, 140381257314303,
+SNULL, 140381257289727, 140381257297919,
+STORE, 140381257273344, 140381257289727,
+STORE, 140381257289728, 140381257297919,
+SNULL, 94535152885759, 94535152889855,
+STORE, 94535152877568, 94535152885759,
+STORE, 94535152885760, 94535152889855,
+SNULL, 140381259558911, 140381259563007,
+STORE, 140381259554816, 140381259558911,
+STORE, 140381259558912, 140381259563007,
+ERASE, 140381259526144, 140381259554815,
+STORE, 94535186296832, 94535186431999,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140729189425152, 140737488351231,
+SNULL, 140729189433343, 140737488351231,
+STORE, 140729189425152, 140729189433343,
+STORE, 140729189294080, 140729189433343,
+STORE, 94428200128512, 94428202352639,
+SNULL, 94428200239103, 94428202352639,
+STORE, 94428200128512, 94428200239103,
+STORE, 94428200239104, 94428202352639,
+ERASE, 94428200239104, 94428202352639,
+STORE, 94428202332160, 94428202344447,
+STORE, 94428202344448, 94428202352639,
+STORE, 139707216986112, 139707219238911,
+SNULL, 139707217129471, 139707219238911,
+STORE, 139707216986112, 139707217129471,
+STORE, 139707217129472, 139707219238911,
+ERASE, 139707217129472, 139707219238911,
+STORE, 139707219226624, 139707219234815,
+STORE, 139707219234816, 139707219238911,
+STORE, 140729189785600, 140729189789695,
+STORE, 140729189773312, 140729189785599,
+STORE, 139707219197952, 139707219226623,
+STORE, 139707219189760, 139707219197951,
+STORE, 139707213189120, 139707216986111,
+SNULL, 139707213189120, 139707214847999,
+STORE, 139707214848000, 139707216986111,
+STORE, 139707213189120, 139707214847999,
+SNULL, 139707216945151, 139707216986111,
+STORE, 139707214848000, 139707216945151,
+STORE, 139707216945152, 139707216986111,
+SNULL, 139707216945152, 139707216969727,
+STORE, 139707216969728, 139707216986111,
+STORE, 139707216945152, 139707216969727,
+ERASE, 139707216945152, 139707216969727,
+STORE, 139707216945152, 139707216969727,
+ERASE, 139707216969728, 139707216986111,
+STORE, 139707216969728, 139707216986111,
+SNULL, 139707216961535, 139707216969727,
+STORE, 139707216945152, 139707216961535,
+STORE, 139707216961536, 139707216969727,
+SNULL, 94428202340351, 94428202344447,
+STORE, 94428202332160, 94428202340351,
+STORE, 94428202340352, 94428202344447,
+SNULL, 139707219230719, 139707219234815,
+STORE, 139707219226624, 139707219230719,
+STORE, 139707219230720, 139707219234815,
+ERASE, 139707219197952, 139707219226623,
+STORE, 94428208599040, 94428208734207,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722000953344, 140737488351231,
+SNULL, 140722000961535, 140737488351231,
+STORE, 140722000953344, 140722000961535,
+STORE, 140722000822272, 140722000961535,
+STORE, 94636494757888, 94636496982015,
+SNULL, 94636494868479, 94636496982015,
+STORE, 94636494757888, 94636494868479,
+STORE, 94636494868480, 94636496982015,
+ERASE, 94636494868480, 94636496982015,
+STORE, 94636496961536, 94636496973823,
+STORE, 94636496973824, 94636496982015,
+STORE, 140142275100672, 140142277353471,
+SNULL, 140142275244031, 140142277353471,
+STORE, 140142275100672, 140142275244031,
+STORE, 140142275244032, 140142277353471,
+ERASE, 140142275244032, 140142277353471,
+STORE, 140142277341184, 140142277349375,
+STORE, 140142277349376, 140142277353471,
+STORE, 140722002747392, 140722002751487,
+STORE, 140722002735104, 140722002747391,
+STORE, 140142277312512, 140142277341183,
+STORE, 140142277304320, 140142277312511,
+STORE, 140142271303680, 140142275100671,
+SNULL, 140142271303680, 140142272962559,
+STORE, 140142272962560, 140142275100671,
+STORE, 140142271303680, 140142272962559,
+SNULL, 140142275059711, 140142275100671,
+STORE, 140142272962560, 140142275059711,
+STORE, 140142275059712, 140142275100671,
+SNULL, 140142275059712, 140142275084287,
+STORE, 140142275084288, 140142275100671,
+STORE, 140142275059712, 140142275084287,
+ERASE, 140142275059712, 140142275084287,
+STORE, 140142275059712, 140142275084287,
+ERASE, 140142275084288, 140142275100671,
+STORE, 140142275084288, 140142275100671,
+SNULL, 140142275076095, 140142275084287,
+STORE, 140142275059712, 140142275076095,
+STORE, 140142275076096, 140142275084287,
+SNULL, 94636496969727, 94636496973823,
+STORE, 94636496961536, 94636496969727,
+STORE, 94636496969728, 94636496973823,
+SNULL, 140142277345279, 140142277349375,
+STORE, 140142277341184, 140142277345279,
+STORE, 140142277345280, 140142277349375,
+ERASE, 140142277312512, 140142277341183,
+STORE, 94636516286464, 94636516421631,
+STORE, 94071103692800, 94071103905791,
+STORE, 94071106002944, 94071106007039,
+STORE, 94071106007040, 94071106015231,
+STORE, 94071106015232, 94071106027519,
+STORE, 94071138521088, 94071140368383,
+STORE, 140145668190208, 140145669849087,
+STORE, 140145669849088, 140145671946239,
+STORE, 140145671946240, 140145671962623,
+STORE, 140145671962624, 140145671970815,
+STORE, 140145671970816, 140145671987199,
+STORE, 140145671987200, 140145671999487,
+STORE, 140145671999488, 140145674092543,
+STORE, 140145674092544, 140145674096639,
+STORE, 140145674096640, 140145674100735,
+STORE, 140145674100736, 140145674244095,
+STORE, 140145674612736, 140145676296191,
+STORE, 140145676296192, 140145676312575,
+STORE, 140145676341248, 140145676345343,
+STORE, 140145676345344, 140145676349439,
+STORE, 140145676349440, 140145676353535,
+STORE, 140734927740928, 140734927880191,
+STORE, 140734928842752, 140734928855039,
+STORE, 140734928855040, 140734928859135,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722342535168, 140737488351231,
+SNULL, 140722342543359, 140737488351231,
+STORE, 140722342535168, 140722342543359,
+STORE, 140722342404096, 140722342543359,
+STORE, 94399699714048, 94399702048767,
+SNULL, 94399699927039, 94399702048767,
+STORE, 94399699714048, 94399699927039,
+STORE, 94399699927040, 94399702048767,
+ERASE, 94399699927040, 94399702048767,
+STORE, 94399702024192, 94399702036479,
+STORE, 94399702036480, 94399702048767,
+STORE, 139811024748544, 139811027001343,
+SNULL, 139811024891903, 139811027001343,
+STORE, 139811024748544, 139811024891903,
+STORE, 139811024891904, 139811027001343,
+ERASE, 139811024891904, 139811027001343,
+STORE, 139811026989056, 139811026997247,
+STORE, 139811026997248, 139811027001343,
+STORE, 140722342707200, 140722342711295,
+STORE, 140722342694912, 140722342707199,
+STORE, 139811026960384, 139811026989055,
+STORE, 139811026952192, 139811026960383,
+STORE, 139811022635008, 139811024748543,
+SNULL, 139811022635008, 139811022647295,
+STORE, 139811022647296, 139811024748543,
+STORE, 139811022635008, 139811022647295,
+SNULL, 139811024740351, 139811024748543,
+STORE, 139811022647296, 139811024740351,
+STORE, 139811024740352, 139811024748543,
+ERASE, 139811024740352, 139811024748543,
+STORE, 139811024740352, 139811024748543,
+STORE, 139811018838016, 139811022635007,
+SNULL, 139811018838016, 139811020496895,
+STORE, 139811020496896, 139811022635007,
+STORE, 139811018838016, 139811020496895,
+SNULL, 139811022594047, 139811022635007,
+STORE, 139811020496896, 139811022594047,
+STORE, 139811022594048, 139811022635007,
+SNULL, 139811022594048, 139811022618623,
+STORE, 139811022618624, 139811022635007,
+STORE, 139811022594048, 139811022618623,
+ERASE, 139811022594048, 139811022618623,
+STORE, 139811022594048, 139811022618623,
+ERASE, 139811022618624, 139811022635007,
+STORE, 139811022618624, 139811022635007,
+STORE, 139811026944000, 139811026960383,
+SNULL, 139811022610431, 139811022618623,
+STORE, 139811022594048, 139811022610431,
+STORE, 139811022610432, 139811022618623,
+SNULL, 139811024744447, 139811024748543,
+STORE, 139811024740352, 139811024744447,
+STORE, 139811024744448, 139811024748543,
+SNULL, 94399702028287, 94399702036479,
+STORE, 94399702024192, 94399702028287,
+STORE, 94399702028288, 94399702036479,
+SNULL, 139811026993151, 139811026997247,
+STORE, 139811026989056, 139811026993151,
+STORE, 139811026993152, 139811026997247,
+ERASE, 139811026960384, 139811026989055,
+STORE, 94399723880448, 94399724015615,
+STORE, 139811025260544, 139811026943999,
+STORE, 94399723880448, 94399724150783,
+STORE, 94399723880448, 94399724285951,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140735364939776, 140737488351231,
+SNULL, 140735364947967, 140737488351231,
+STORE, 140735364939776, 140735364947967,
+STORE, 140735364808704, 140735364947967,
+STORE, 94421528674304, 94421531009023,
+SNULL, 94421528887295, 94421531009023,
+STORE, 94421528674304, 94421528887295,
+STORE, 94421528887296, 94421531009023,
+ERASE, 94421528887296, 94421531009023,
+STORE, 94421530984448, 94421530996735,
+STORE, 94421530996736, 94421531009023,
+STORE, 140162004742144, 140162006994943,
+SNULL, 140162004885503, 140162006994943,
+STORE, 140162004742144, 140162004885503,
+STORE, 140162004885504, 140162006994943,
+ERASE, 140162004885504, 140162006994943,
+STORE, 140162006982656, 140162006990847,
+STORE, 140162006990848, 140162006994943,
+STORE, 140735365402624, 140735365406719,
+STORE, 140735365390336, 140735365402623,
+STORE, 140162006953984, 140162006982655,
+STORE, 140162006945792, 140162006953983,
+STORE, 140162002628608, 140162004742143,
+SNULL, 140162002628608, 140162002640895,
+STORE, 140162002640896, 140162004742143,
+STORE, 140162002628608, 140162002640895,
+SNULL, 140162004733951, 140162004742143,
+STORE, 140162002640896, 140162004733951,
+STORE, 140162004733952, 140162004742143,
+ERASE, 140162004733952, 140162004742143,
+STORE, 140162004733952, 140162004742143,
+STORE, 140161998831616, 140162002628607,
+SNULL, 140161998831616, 140162000490495,
+STORE, 140162000490496, 140162002628607,
+STORE, 140161998831616, 140162000490495,
+SNULL, 140162002587647, 140162002628607,
+STORE, 140162000490496, 140162002587647,
+STORE, 140162002587648, 140162002628607,
+SNULL, 140162002587648, 140162002612223,
+STORE, 140162002612224, 140162002628607,
+STORE, 140162002587648, 140162002612223,
+ERASE, 140162002587648, 140162002612223,
+STORE, 140162002587648, 140162002612223,
+ERASE, 140162002612224, 140162002628607,
+STORE, 140162002612224, 140162002628607,
+STORE, 140162006937600, 140162006953983,
+SNULL, 140162002604031, 140162002612223,
+STORE, 140162002587648, 140162002604031,
+STORE, 140162002604032, 140162002612223,
+SNULL, 140162004738047, 140162004742143,
+STORE, 140162004733952, 140162004738047,
+STORE, 140162004738048, 140162004742143,
+SNULL, 94421530988543, 94421530996735,
+STORE, 94421530984448, 94421530988543,
+STORE, 94421530988544, 94421530996735,
+SNULL, 140162006986751, 140162006990847,
+STORE, 140162006982656, 140162006986751,
+STORE, 140162006986752, 140162006990847,
+ERASE, 140162006953984, 140162006982655,
+STORE, 94421551697920, 94421551833087,
+STORE, 140162005254144, 140162006937599,
+STORE, 94421551697920, 94421551968255,
+STORE, 94421551697920, 94421552103423,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140733498486784, 140737488351231,
+SNULL, 140733498494975, 140737488351231,
+STORE, 140733498486784, 140733498494975,
+STORE, 140733498355712, 140733498494975,
+STORE, 94567985836032, 94567988170751,
+SNULL, 94567986049023, 94567988170751,
+STORE, 94567985836032, 94567986049023,
+STORE, 94567986049024, 94567988170751,
+ERASE, 94567986049024, 94567988170751,
+STORE, 94567988146176, 94567988158463,
+STORE, 94567988158464, 94567988170751,
+STORE, 139634278572032, 139634280824831,
+SNULL, 139634278715391, 139634280824831,
+STORE, 139634278572032, 139634278715391,
+STORE, 139634278715392, 139634280824831,
+ERASE, 139634278715392, 139634280824831,
+STORE, 139634280812544, 139634280820735,
+STORE, 139634280820736, 139634280824831,
+STORE, 140733498544128, 140733498548223,
+STORE, 140733498531840, 140733498544127,
+STORE, 139634280783872, 139634280812543,
+STORE, 139634280775680, 139634280783871,
+STORE, 139634276458496, 139634278572031,
+SNULL, 139634276458496, 139634276470783,
+STORE, 139634276470784, 139634278572031,
+STORE, 139634276458496, 139634276470783,
+SNULL, 139634278563839, 139634278572031,
+STORE, 139634276470784, 139634278563839,
+STORE, 139634278563840, 139634278572031,
+ERASE, 139634278563840, 139634278572031,
+STORE, 139634278563840, 139634278572031,
+STORE, 139634272661504, 139634276458495,
+SNULL, 139634272661504, 139634274320383,
+STORE, 139634274320384, 139634276458495,
+STORE, 139634272661504, 139634274320383,
+SNULL, 139634276417535, 139634276458495,
+STORE, 139634274320384, 139634276417535,
+STORE, 139634276417536, 139634276458495,
+SNULL, 139634276417536, 139634276442111,
+STORE, 139634276442112, 139634276458495,
+STORE, 139634276417536, 139634276442111,
+ERASE, 139634276417536, 139634276442111,
+STORE, 139634276417536, 139634276442111,
+ERASE, 139634276442112, 139634276458495,
+STORE, 139634276442112, 139634276458495,
+STORE, 139634280767488, 139634280783871,
+SNULL, 139634276433919, 139634276442111,
+STORE, 139634276417536, 139634276433919,
+STORE, 139634276433920, 139634276442111,
+SNULL, 139634278567935, 139634278572031,
+STORE, 139634278563840, 139634278567935,
+STORE, 139634278567936, 139634278572031,
+SNULL, 94567988150271, 94567988158463,
+STORE, 94567988146176, 94567988150271,
+STORE, 94567988150272, 94567988158463,
+SNULL, 139634280816639, 139634280820735,
+STORE, 139634280812544, 139634280816639,
+STORE, 139634280816640, 139634280820735,
+ERASE, 139634280783872, 139634280812543,
+STORE, 94567996379136, 94567996514303,
+STORE, 139634279084032, 139634280767487,
+STORE, 94567996379136, 94567996649471,
+STORE, 94567996379136, 94567996784639,
+STORE, 94567996379136, 94567996960767,
+SNULL, 94567996932095, 94567996960767,
+STORE, 94567996379136, 94567996932095,
+STORE, 94567996932096, 94567996960767,
+ERASE, 94567996932096, 94567996960767,
+STORE, 94567996379136, 94567997071359,
+STORE, 94567996379136, 94567997206527,
+SNULL, 94567997186047, 94567997206527,
+STORE, 94567996379136, 94567997186047,
+STORE, 94567997186048, 94567997206527,
+ERASE, 94567997186048, 94567997206527,
+STORE, 94567996379136, 94567997358079,
+STORE, 94567996379136, 94567997493247,
+SNULL, 94567997476863, 94567997493247,
+STORE, 94567996379136, 94567997476863,
+STORE, 94567997476864, 94567997493247,
+ERASE, 94567997476864, 94567997493247,
+STORE, 94567996379136, 94567997612031,
+STORE, 94567996379136, 94567997767679,
+SNULL, 94567997739007, 94567997767679,
+STORE, 94567996379136, 94567997739007,
+STORE, 94567997739008, 94567997767679,
+ERASE, 94567997739008, 94567997767679,
+SNULL, 94567997698047, 94567997739007,
+STORE, 94567996379136, 94567997698047,
+STORE, 94567997698048, 94567997739007,
+ERASE, 94567997698048, 94567997739007,
+STORE, 94567996379136, 94567997853695,
+STORE, 94567996379136, 94567997988863,
+STORE, 94567996379136, 94567998132223,
+STORE, 94567996379136, 94567998275583,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140723667759104, 140737488351231,
+SNULL, 140723667767295, 140737488351231,
+STORE, 140723667759104, 140723667767295,
+STORE, 140723667628032, 140723667767295,
+STORE, 94231598800896, 94231601135615,
+SNULL, 94231599013887, 94231601135615,
+STORE, 94231598800896, 94231599013887,
+STORE, 94231599013888, 94231601135615,
+ERASE, 94231599013888, 94231601135615,
+STORE, 94231601111040, 94231601123327,
+STORE, 94231601123328, 94231601135615,
+STORE, 140269472649216, 140269474902015,
+SNULL, 140269472792575, 140269474902015,
+STORE, 140269472649216, 140269472792575,
+STORE, 140269472792576, 140269474902015,
+ERASE, 140269472792576, 140269474902015,
+STORE, 140269474889728, 140269474897919,
+STORE, 140269474897920, 140269474902015,
+STORE, 140723667836928, 140723667841023,
+STORE, 140723667824640, 140723667836927,
+STORE, 140269474861056, 140269474889727,
+STORE, 140269474852864, 140269474861055,
+STORE, 140269470535680, 140269472649215,
+SNULL, 140269470535680, 140269470547967,
+STORE, 140269470547968, 140269472649215,
+STORE, 140269470535680, 140269470547967,
+SNULL, 140269472641023, 140269472649215,
+STORE, 140269470547968, 140269472641023,
+STORE, 140269472641024, 140269472649215,
+ERASE, 140269472641024, 140269472649215,
+STORE, 140269472641024, 140269472649215,
+STORE, 140269466738688, 140269470535679,
+SNULL, 140269466738688, 140269468397567,
+STORE, 140269468397568, 140269470535679,
+STORE, 140269466738688, 140269468397567,
+SNULL, 140269470494719, 140269470535679,
+STORE, 140269468397568, 140269470494719,
+STORE, 140269470494720, 140269470535679,
+SNULL, 140269470494720, 140269470519295,
+STORE, 140269470519296, 140269470535679,
+STORE, 140269470494720, 140269470519295,
+ERASE, 140269470494720, 140269470519295,
+STORE, 140269470494720, 140269470519295,
+ERASE, 140269470519296, 140269470535679,
+STORE, 140269470519296, 140269470535679,
+STORE, 140269474844672, 140269474861055,
+SNULL, 140269470511103, 140269470519295,
+STORE, 140269470494720, 140269470511103,
+STORE, 140269470511104, 140269470519295,
+SNULL, 140269472645119, 140269472649215,
+STORE, 140269472641024, 140269472645119,
+STORE, 140269472645120, 140269472649215,
+SNULL, 94231601115135, 94231601123327,
+STORE, 94231601111040, 94231601115135,
+STORE, 94231601115136, 94231601123327,
+SNULL, 140269474893823, 140269474897919,
+STORE, 140269474889728, 140269474893823,
+STORE, 140269474893824, 140269474897919,
+ERASE, 140269474861056, 140269474889727,
+STORE, 94231626592256, 94231626727423,
+STORE, 140269473161216, 140269474844671,
+STORE, 94231626592256, 94231626862591,
+STORE, 94231626592256, 94231626997759,
+STORE, 94327178862592, 94327179075583,
+STORE, 94327181172736, 94327181176831,
+STORE, 94327181176832, 94327181185023,
+STORE, 94327181185024, 94327181197311,
+STORE, 94327185715200, 94327186685951,
+STORE, 140172071755776, 140172073414655,
+STORE, 140172073414656, 140172075511807,
+STORE, 140172075511808, 140172075528191,
+STORE, 140172075528192, 140172075536383,
+STORE, 140172075536384, 140172075552767,
+STORE, 140172075552768, 140172075565055,
+STORE, 140172075565056, 140172077658111,
+STORE, 140172077658112, 140172077662207,
+STORE, 140172077662208, 140172077666303,
+STORE, 140172077666304, 140172077809663,
+STORE, 140172078178304, 140172079861759,
+STORE, 140172079861760, 140172079878143,
+STORE, 140172079878144, 140172079906815,
+STORE, 140172079906816, 140172079910911,
+STORE, 140172079910912, 140172079915007,
+STORE, 140172079915008, 140172079919103,
+STORE, 140720358359040, 140720358494207,
+STORE, 140720358498304, 140720358510591,
+STORE, 140720358510592, 140720358514687,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140722548621312, 140737488351231,
+SNULL, 140722548629503, 140737488351231,
+STORE, 140722548621312, 140722548629503,
+STORE, 140722548490240, 140722548629503,
+STORE, 93949289504768, 93949291728895,
+SNULL, 93949289615359, 93949291728895,
+STORE, 93949289504768, 93949289615359,
+STORE, 93949289615360, 93949291728895,
+ERASE, 93949289615360, 93949291728895,
+STORE, 93949291708416, 93949291720703,
+STORE, 93949291720704, 93949291728895,
+STORE, 140305861902336, 140305864155135,
+SNULL, 140305862045695, 140305864155135,
+STORE, 140305861902336, 140305862045695,
+STORE, 140305862045696, 140305864155135,
+ERASE, 140305862045696, 140305864155135,
+STORE, 140305864142848, 140305864151039,
+STORE, 140305864151040, 140305864155135,
+STORE, 140722549821440, 140722549825535,
+STORE, 140722549809152, 140722549821439,
+STORE, 140305864114176, 140305864142847,
+STORE, 140305864105984, 140305864114175,
+STORE, 140305858105344, 140305861902335,
+SNULL, 140305858105344, 140305859764223,
+STORE, 140305859764224, 140305861902335,
+STORE, 140305858105344, 140305859764223,
+SNULL, 140305861861375, 140305861902335,
+STORE, 140305859764224, 140305861861375,
+STORE, 140305861861376, 140305861902335,
+SNULL, 140305861861376, 140305861885951,
+STORE, 140305861885952, 140305861902335,
+STORE, 140305861861376, 140305861885951,
+ERASE, 140305861861376, 140305861885951,
+STORE, 140305861861376, 140305861885951,
+ERASE, 140305861885952, 140305861902335,
+STORE, 140305861885952, 140305861902335,
+SNULL, 140305861877759, 140305861885951,
+STORE, 140305861861376, 140305861877759,
+STORE, 140305861877760, 140305861885951,
+SNULL, 93949291716607, 93949291720703,
+STORE, 93949291708416, 93949291716607,
+STORE, 93949291716608, 93949291720703,
+SNULL, 140305864146943, 140305864151039,
+STORE, 140305864142848, 140305864146943,
+STORE, 140305864146944, 140305864151039,
+ERASE, 140305864114176, 140305864142847,
+STORE, 93949324136448, 93949324271615,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140725754908672, 140737488351231,
+SNULL, 140725754916863, 140737488351231,
+STORE, 140725754908672, 140725754916863,
+STORE, 140725754777600, 140725754916863,
+STORE, 94831184375808, 94831186599935,
+SNULL, 94831184486399, 94831186599935,
+STORE, 94831184375808, 94831184486399,
+STORE, 94831184486400, 94831186599935,
+ERASE, 94831184486400, 94831186599935,
+STORE, 94831186579456, 94831186591743,
+STORE, 94831186591744, 94831186599935,
+STORE, 140605482479616, 140605484732415,
+SNULL, 140605482622975, 140605484732415,
+STORE, 140605482479616, 140605482622975,
+STORE, 140605482622976, 140605484732415,
+ERASE, 140605482622976, 140605484732415,
+STORE, 140605484720128, 140605484728319,
+STORE, 140605484728320, 140605484732415,
+STORE, 140725755670528, 140725755674623,
+STORE, 140725755658240, 140725755670527,
+STORE, 140605484691456, 140605484720127,
+STORE, 140605484683264, 140605484691455,
+STORE, 140605478682624, 140605482479615,
+SNULL, 140605478682624, 140605480341503,
+STORE, 140605480341504, 140605482479615,
+STORE, 140605478682624, 140605480341503,
+SNULL, 140605482438655, 140605482479615,
+STORE, 140605480341504, 140605482438655,
+STORE, 140605482438656, 140605482479615,
+SNULL, 140605482438656, 140605482463231,
+STORE, 140605482463232, 140605482479615,
+STORE, 140605482438656, 140605482463231,
+ERASE, 140605482438656, 140605482463231,
+STORE, 140605482438656, 140605482463231,
+ERASE, 140605482463232, 140605482479615,
+STORE, 140605482463232, 140605482479615,
+SNULL, 140605482455039, 140605482463231,
+STORE, 140605482438656, 140605482455039,
+STORE, 140605482455040, 140605482463231,
+SNULL, 94831186587647, 94831186591743,
+STORE, 94831186579456, 94831186587647,
+STORE, 94831186587648, 94831186591743,
+SNULL, 140605484724223, 140605484728319,
+STORE, 140605484720128, 140605484724223,
+STORE, 140605484724224, 140605484728319,
+ERASE, 140605484691456, 140605484720127,
+STORE, 94831217156096, 94831217291263,
+STORE, 94327178862592, 94327179075583,
+STORE, 94327181172736, 94327181176831,
+STORE, 94327181176832, 94327181185023,
+STORE, 94327181185024, 94327181197311,
+STORE, 94327185715200, 94327186685951,
+STORE, 140172071755776, 140172073414655,
+STORE, 140172073414656, 140172075511807,
+STORE, 140172075511808, 140172075528191,
+STORE, 140172075528192, 140172075536383,
+STORE, 140172075536384, 140172075552767,
+STORE, 140172075552768, 140172075565055,
+STORE, 140172075565056, 140172077658111,
+STORE, 140172077658112, 140172077662207,
+STORE, 140172077662208, 140172077666303,
+STORE, 140172077666304, 140172077809663,
+STORE, 140172078178304, 140172079861759,
+STORE, 140172079861760, 140172079878143,
+STORE, 140172079878144, 140172079906815,
+STORE, 140172079906816, 140172079910911,
+STORE, 140172079910912, 140172079915007,
+STORE, 140172079915008, 140172079919103,
+STORE, 140720358359040, 140720358494207,
+STORE, 140720358498304, 140720358510591,
+STORE, 140720358510592, 140720358514687,
+STORE, 140737488347136, 140737488351231,
+STORE, 140737488343040, 140737488351231,
+STORE, 140737488338944, 140737488351231,
+STORE, 140734529933312, 140737488351231,
+SNULL, 140734529945599, 140737488351231,
+STORE, 140734529933312, 140734529945599,
+STORE, 140734529802240, 140734529945599,
+STORE, 4194304, 26279935,
+STORE, 28372992, 28454911,
+STORE, 28454912, 29806591,
+STORE, 140249744060416, 140249746313215,
+SNULL, 140249744203775, 140249746313215,
+STORE, 140249744060416, 140249744203775,
+STORE, 140249744203776, 140249746313215,
+ERASE, 140249744203776, 140249746313215,
+STORE, 140249746300928, 140249746309119,
+STORE, 140249746309120, 140249746313215,
+STORE, 140734530174976, 140734530179071,
+STORE, 140734530162688, 140734530174975,
+STORE, 140249746272256, 140249746300927,
+STORE, 140249746264064, 140249746272255,
+STORE, 140249740226560, 140249744060415,
+SNULL, 140249740226560, 140249741934591,
+STORE, 140249741934592, 140249744060415,
+STORE, 140249740226560, 140249741934591,
+SNULL, 140249744027647, 140249744060415,
+STORE, 140249741934592, 140249744027647,
+STORE, 140249744027648, 140249744060415,
+ERASE, 140249744027648, 140249744060415,
+STORE, 140249744027648, 140249744060415,
+STORE, 140249738031104, 140249740226559,
+SNULL, 140249738031104, 140249738125311,
+STORE, 140249738125312, 140249740226559,
+STORE, 140249738031104, 140249738125311,
+SNULL, 140249740218367, 140249740226559,
+STORE, 140249738125312, 140249740218367,
+STORE, 140249740218368, 140249740226559,
+ERASE, 140249740218368, 140249740226559,
+STORE, 140249740218368, 140249740226559,
+STORE, 140249735512064, 140249738031103,
+SNULL, 140249735512064, 140249735925759,
+STORE, 140249735925760, 140249738031103,
+STORE, 140249735512064, 140249735925759,
+SNULL, 140249738018815, 140249738031103,
+STORE, 140249735925760, 140249738018815,
+STORE, 140249738018816, 140249738031103,
+ERASE, 140249738018816, 140249738031103,
+STORE, 140249738018816, 140249738031103,
+STORE, 140249732878336, 140249735512063,
+SNULL, 140249732878336, 140249733406719,
+STORE, 140249733406720, 140249735512063,
+STORE, 140249732878336, 140249733406719,
+SNULL, 140249735503871, 140249735512063,
+STORE, 140249733406720, 140249735503871,
+STORE, 140249735503872, 140249735512063,
+ERASE, 140249735503872, 140249735512063,
+STORE, 140249735503872, 140249735512063,
+STORE, 140249730764800, 140249732878335,
+SNULL, 140249730764800, 140249730777087,
+STORE, 140249730777088, 140249732878335,
+STORE, 140249730764800, 140249730777087,
+SNULL, 140249732870143, 140249732878335,
+STORE, 140249730777088, 140249732870143,
+STORE, 140249732870144, 140249732878335,
+ERASE, 140249732870144, 140249732878335,
+STORE, 140249732870144, 140249732878335,
+STORE, 140249728561152, 140249730764799,
+SNULL, 140249728561152, 140249728663551,
+STORE, 140249728663552, 140249730764799,
+STORE, 140249728561152, 140249728663551,
+SNULL, 140249730756607, 140249730764799,
+STORE, 140249728663552, 140249730756607,
+STORE, 140249730756608, 140249730764799,
+ERASE, 140249730756608, 140249730764799,
+STORE, 140249730756608, 140249730764799,
+STORE, 140249746255872, 140249746272255,
+STORE, 140249725399040, 140249728561151,
+SNULL, 140249725399040, 140249726459903,
+STORE, 140249726459904, 140249728561151,
+STORE, 140249725399040, 140249726459903,
+SNULL, 140249728552959, 140249728561151,
+STORE, 140249726459904, 140249728552959,
+STORE, 140249728552960, 140249728561151,
+ERASE, 140249728552960, 140249728561151,
+STORE, 140249728552960, 140249728561151,
+STORE, 140249721602048, 140249725399039,
+SNULL, 140249721602048, 140249723260927,
+STORE, 140249723260928, 140249725399039,
+STORE, 140249721602048, 140249723260927,
+SNULL, 140249725358079, 140249725399039,
+STORE, 140249723260928, 140249725358079,
+STORE, 140249725358080, 140249725399039,
+SNULL, 140249725358080, 140249725382655,
+STORE, 140249725382656, 140249725399039,
+STORE, 140249725358080, 140249725382655,
+ERASE, 140249725358080, 140249725382655,
+STORE, 140249725358080, 140249725382655,
+ERASE, 140249725382656, 140249725399039,
+STORE, 140249725382656, 140249725399039,
+STORE, 140249746243584, 140249746272255,
+SNULL, 140249725374463, 140249725382655,
+STORE, 140249725358080, 140249725374463,
+STORE, 140249725374464, 140249725382655,
+SNULL, 140249728557055, 140249728561151,
+STORE, 140249728552960, 140249728557055,
+STORE, 140249728557056, 140249728561151,
+SNULL, 140249730760703, 140249730764799,
+STORE, 140249730756608, 140249730760703,
+STORE, 140249730760704, 140249730764799,
+SNULL, 140249732874239, 140249732878335,
+STORE, 140249732870144, 140249732874239,
+STORE, 140249732874240, 140249732878335,
+SNULL, 140249735507967, 140249735512063,
+STORE, 140249735503872, 140249735507967,
+STORE, 140249735507968, 140249735512063,
+SNULL, 140249738027007, 140249738031103,
+STORE, 140249738018816, 140249738027007,
+STORE, 140249738027008, 140249738031103,
+SNULL, 140249740222463, 140249740226559,
+STORE, 140249740218368, 140249740222463,
+STORE, 140249740222464, 140249740226559,
+SNULL, 140249744031743, 140249744060415,
+STORE, 140249744027648, 140249744031743,
+STORE, 140249744031744, 140249744060415,
+SNULL, 28405759, 28454911,
+STORE, 28372992, 28405759,
+STORE, 28405760, 28454911,
+SNULL, 140249746305023, 140249746309119,
+STORE, 140249746300928, 140249746305023,
+STORE, 140249746305024, 140249746309119,
+ERASE, 140249746272256, 140249746300927,
+STORE, 33853440, 33988607,
+STORE, 140249744560128, 140249746243583,
+STORE, 140249746296832, 140249746300927,
+STORE, 140249744424960, 140249744560127,
+STORE, 33853440, 34131967,
+STORE, 140249719504896, 140249721602047,
+STORE, 140249746288640, 140249746300927,
+STORE, 140249746280448, 140249746300927,
+STORE, 140249746243584, 140249746280447,
+STORE, 140249744408576, 140249744560127,
+STORE, 33853440, 34267135,
+STORE, 33853440, 34422783,
+STORE, 140249744400384, 140249744560127,
+STORE, 140249744392192, 140249744560127,
+STORE, 33853440, 34557951,
+STORE, 33853440, 34693119,
+STORE, 140249744375808, 140249744560127,
+STORE, 140249744367616, 140249744560127,
+STORE, 33853440, 34832383,
+STORE, 140249719230464, 140249721602047,
+STORE, 140249744207872, 140249744560127,
+STORE, 33853440, 34971647,
+SNULL, 34963455, 34971647,
+STORE, 33853440, 34963455,
+STORE, 34963456, 34971647,
+ERASE, 34963456, 34971647,
+SNULL, 34955263, 34963455,
+STORE, 33853440, 34955263,
+STORE, 34955264, 34963455,
+ERASE, 34955264, 34963455,
+SNULL, 34947071, 34955263,
+STORE, 33853440, 34947071,
+STORE, 34947072, 34955263,
+ERASE, 34947072, 34955263,
+SNULL, 34938879, 34947071,
+STORE, 33853440, 34938879,
+STORE, 34938880, 34947071,
+ERASE, 34938880, 34947071,
+STORE, 140249719214080, 140249721602047,
+STORE, 140249719148544, 140249721602047,
+STORE, 140249719115776, 140249721602047,
+STORE, 140249717018624, 140249721602047,
+STORE, 140249716953088, 140249721602047,
+STORE, 33853440, 35086335,
+STORE, 140249716822016, 140249721602047,
+STORE, 140249716559872, 140249721602047,
+STORE, 140249716551680, 140249721602047,
+STORE, 140249716535296, 140249721602047,
+STORE, 140249716527104, 140249721602047,
+STORE, 140249716518912, 140249721602047,
+STORE, 33853440, 35221503,
+SNULL, 35213311, 35221503,
+STORE, 33853440, 35213311,
+STORE, 35213312, 35221503,
+ERASE, 35213312, 35221503,
+SNULL, 35205119, 35213311,
+STORE, 33853440, 35205119,
+STORE, 35205120, 35213311,
+ERASE, 35205120, 35213311,
+SNULL, 35192831, 35205119,
+STORE, 33853440, 35192831,
+STORE, 35192832, 35205119,
+ERASE, 35192832, 35205119,
+SNULL, 35176447, 35192831,
+STORE, 33853440, 35176447,
+STORE, 35176448, 35192831,
+ERASE, 35176448, 35192831,
+STORE, 140249716502528, 140249721602047,
+STORE, 33853440, 35311615,
+SNULL, 35307519, 35311615,
+STORE, 33853440, 35307519,
+STORE, 35307520, 35311615,
+ERASE, 35307520, 35311615,
+SNULL, 35303423, 35307519,
+STORE, 33853440, 35303423,
+STORE, 35303424, 35307519,
+ERASE, 35303424, 35307519,
+SNULL, 35299327, 35303423,
+STORE, 33853440, 35299327,
+STORE, 35299328, 35303423,
+ERASE, 35299328, 35303423,
+SNULL, 35295231, 35299327,
+STORE, 33853440, 35295231,
+STORE, 35295232, 35299327,
+ERASE, 35295232, 35299327,
+SNULL, 35291135, 35295231,
+STORE, 33853440, 35291135,
+STORE, 35291136, 35295231,
+ERASE, 35291136, 35295231,
+SNULL, 35287039, 35291135,
+STORE, 33853440, 35287039,
+STORE, 35287040, 35291135,
+ERASE, 35287040, 35291135,
+SNULL, 35282943, 35287039,
+STORE, 33853440, 35282943,
+STORE, 35282944, 35287039,
+ERASE, 35282944, 35287039,
+STORE, 140249716486144, 140249721602047,
+STORE, 140249716453376, 140249721602047,
+STORE, 33853440, 35418111,
+SNULL, 35401727, 35418111,
+STORE, 33853440, 35401727,
+STORE, 35401728, 35418111,
+ERASE, 35401728, 35418111,
+SNULL, 35389439, 35401727,
+STORE, 33853440, 35389439,
+STORE, 35389440, 35401727,
+ERASE, 35389440, 35401727,
+STORE, 140249714356224, 140249721602047,
+STORE, 33853440, 35540991,
+STORE, 140249714339840, 140249721602047,
+STORE, 140249714077696, 140249721602047,
+STORE, 140249714069504, 140249721602047,
+STORE, 140249714061312, 140249721602047,
+STORE, 33853440, 35680255,
+SNULL, 35672063, 35680255,
+STORE, 33853440, 35672063,
+STORE, 35672064, 35680255,
+ERASE, 35672064, 35680255,
+SNULL, 35627007, 35672063,
+STORE, 33853440, 35627007,
+STORE, 35627008, 35672063,
+ERASE, 35627008, 35672063,
+STORE, 140249711964160, 140249721602047,
+STORE, 33853440, 35762175,
+SNULL, 35753983, 35762175,
+STORE, 33853440, 35753983,
+STORE, 35753984, 35762175,
+ERASE, 35753984, 35762175,
+SNULL, 35745791, 35753983,
+STORE, 33853440, 35745791,
+STORE, 35745792, 35753983,
+ERASE, 35745792, 35753983,
+STORE, 140249711955968, 140249721602047,
+STORE, 140249711947776, 140249721602047,
+STORE, 140249710899200, 140249721602047,
+STORE, 140249710866432, 140249721602047,
+STORE, 140249710600192, 140249721602047,
+SNULL, 140249744424959, 140249744560127,
+STORE, 140249744207872, 140249744424959,
+STORE, 140249744424960, 140249744560127,
+ERASE, 140249744424960, 140249744560127,
+STORE, 140249708503040, 140249721602047,
+STORE, 33853440, 35885055,
+STORE, 140249707978752, 140249721602047,
+STORE, 140249705881600, 140249721602047,
+STORE, 33853440, 36036607,
+STORE, 33853440, 36175871,
+STORE, 140249744551936, 140249744560127,
+STORE, 140249744543744, 140249744560127,
+STORE, 140249744535552, 140249744560127,
+STORE, 140249744527360, 140249744560127,
+STORE, 140249744519168, 140249744560127,
+STORE, 140249705619456, 140249721602047,
+STORE, 140249744510976, 140249744560127,
+STORE, 140249744502784, 140249744560127,
+STORE, 140249744494592, 140249744560127,
+STORE, 140249744486400, 140249744560127,
+STORE, 140249744478208, 140249744560127,
+STORE, 140249744470016, 140249744560127,
+STORE, 140249744461824, 140249744560127,
+STORE, 140249744453632, 140249744560127,
+STORE, 140249744445440, 140249744560127,
+STORE, 140249744437248, 140249744560127,
+STORE, 140249744429056, 140249744560127,
+STORE, 140249703522304, 140249721602047,
+STORE, 33853440, 36311039,
+STORE, 140249703489536, 140249721602047,
+STORE, 33853440, 36474879,
+STORE, 140249703456768, 140249721602047,
+STORE, 33853440, 36622335,
+STORE, 140249703424000, 140249721602047,
+STORE, 140249703391232, 140249721602047,
+STORE, 33853440, 36810751,
+STORE, 140249703358464, 140249721602047,
+STORE, 140249703325696, 140249721602047,
+SNULL, 36655103, 36810751,
+STORE, 33853440, 36655103,
+STORE, 36655104, 36810751,
+ERASE, 36655104, 36810751,
+SNULL, 36438015, 36655103,
+STORE, 33853440, 36438015,
+STORE, 36438016, 36655103,
+ERASE, 36438016, 36655103,
+STORE, 140249703317504, 140249721602047,
+STORE, 140249701220352, 140249721602047,
+STORE, 33853440, 36585471,
+STORE, 33853440, 36782079,
+STORE, 140249701212160, 140249721602047,
+STORE, 140249701203968, 140249721602047,
+STORE, 140249701195776, 140249721602047,
+STORE, 140249701187584, 140249721602047,
+STORE, 140249701179392, 140249721602047,
+STORE, 140249701171200, 140249721602047,
+STORE, 140249701163008, 140249721602047,
+STORE, 140249701154816, 140249721602047,
+STORE, 140249701146624, 140249721602047,
+STORE, 140249701138432, 140249721602047,
+STORE, 140249701130240, 140249721602047,
+STORE, 140249700081664, 140249721602047,
+STORE, 140249700073472, 140249721602047,
+STORE, 33853440, 36978687,
+STORE, 140249697976320, 140249721602047,
+STORE, 33853440, 37240831,
+STORE, 140249695879168, 140249721602047,
+STORE, 140249695870976, 140249721602047,
+STORE, 140249695862784, 140249721602047,
+STORE, 140249695854592, 140249721602047,
+STORE, 140249695326208, 140249721602047,
+SNULL, 140249710600191, 140249721602047,
+STORE, 140249695326208, 140249710600191,
+STORE, 140249710600192, 140249721602047,
+SNULL, 140249710600192, 140249710866431,
+STORE, 140249710866432, 140249721602047,
+STORE, 140249710600192, 140249710866431,
+ERASE, 140249710600192, 140249710866431,
+STORE, 140249691131904, 140249710600191,
+STORE, 33853440, 37474303,
+STORE, 140249710858240, 140249721602047,
+STORE, 140249710850048, 140249721602047,
+STORE, 140249710841856, 140249721602047,
+STORE, 140249710833664, 140249721602047,
+STORE, 140249710825472, 140249721602047,
+STORE, 140249710817280, 140249721602047,
+STORE, 140249710809088, 140249721602047,
+STORE, 140249710800896, 140249721602047,
+STORE, 140249710792704, 140249721602047,
+STORE, 140249710784512, 140249721602047,
+STORE, 140249710776320, 140249721602047,
+STORE, 140249710768128, 140249721602047,
+STORE, 140249710759936, 140249721602047,
+STORE, 140249710751744, 140249721602047,
+STORE, 140249710743552, 140249721602047,
+STORE, 140249710735360, 140249721602047,
+STORE, 140249689034752, 140249710600191,
+STORE, 140249710727168, 140249721602047,
+STORE, 140249686937600, 140249710600191,
+STORE, 33853440, 37867519,
+STORE, 140249684840448, 140249710600191,
+STORE, 140249710718976, 140249721602047,
+STORE, 140249682743296, 140249710600191,
+STORE, 140249710710784, 140249721602047,
+STORE, 140249710702592, 140249721602047,
+STORE, 140249710694400, 140249721602047,
+STORE, 140249710686208, 140249721602047,
+STORE, 140249710678016, 140249721602047,
+STORE, 140249682612224, 140249710600191,
+STORE, 140249682087936, 140249710600191,
+SNULL, 140249705619455, 140249710600191,
+STORE, 140249682087936, 140249705619455,
+STORE, 140249705619456, 140249710600191,
+SNULL, 140249705619456, 140249705881599,
+STORE, 140249705881600, 140249710600191,
+STORE, 140249705619456, 140249705881599,
+ERASE, 140249705619456, 140249705881599,
+STORE, 140249679990784, 140249705619455,
+STORE, 140249710669824, 140249721602047,
+STORE, 140249677893632, 140249705619455,
+STORE, 140249710653440, 140249721602047,
+STORE, 140249710645248, 140249721602047,
+STORE, 140249710637056, 140249721602047,
+STORE, 140249710628864, 140249721602047,
+STORE, 140249710620672, 140249721602047,
+STORE, 140249710612480, 140249721602047,
+STORE, 140249710604288, 140249721602047,
+STORE, 140249705873408, 140249710600191,
+STORE, 140249705865216, 140249710600191,
+STORE, 140249705857024, 140249710600191,
+STORE, 140249705848832, 140249710600191,
+STORE, 140249705840640, 140249710600191,
+STORE, 140249705832448, 140249710600191,
+STORE, 140249705824256, 140249710600191,
+STORE, 140249705816064, 140249710600191,
+STORE, 140249705807872, 140249710600191,
+STORE, 140249705799680, 140249710600191,
+STORE, 33853440, 38129663,
+SNULL, 140249744207872, 140249744367615,
+STORE, 140249744367616, 140249744424959,
+STORE, 140249744207872, 140249744367615,
+ERASE, 140249744207872, 140249744367615,
+STORE, 140249677606912, 140249705619455,
+STORE, 140249675509760, 140249705619455,
+SNULL, 140249677606911, 140249705619455,
+STORE, 140249675509760, 140249677606911,
+STORE, 140249677606912, 140249705619455,
+SNULL, 140249677606912, 140249677893631,
+STORE, 140249677893632, 140249705619455,
+STORE, 140249677606912, 140249677893631,
+ERASE, 140249677606912, 140249677893631,
+STORE, 140249744359424, 140249744424959,
+STORE, 33853440, 38391807,
+STORE, 140249674981376, 140249677606911,
+STORE, 140249672884224, 140249677606911,
+SNULL, 140249719230463, 140249721602047,
+STORE, 140249710604288, 140249719230463,
+STORE, 140249719230464, 140249721602047,
+SNULL, 140249719230464, 140249719504895,
+STORE, 140249719504896, 140249721602047,
+STORE, 140249719230464, 140249719504895,
+ERASE, 140249719230464, 140249719504895,
+STORE, 140249744351232, 140249744424959,
+STORE, 140249744343040, 140249744424959,
+STORE, 140249744334848, 140249744424959,
+STORE, 140249744326656, 140249744424959,
+STORE, 140249744310272, 140249744424959,
+STORE, 140249744302080, 140249744424959,
+STORE, 140249744285696, 140249744424959,
+STORE, 140249744277504, 140249744424959,
+STORE, 140249744261120, 140249744424959,
+STORE, 140249744252928, 140249744424959,
+STORE, 140249744220160, 140249744424959,
+STORE, 140249744211968, 140249744424959,
+STORE, 140249719488512, 140249721602047,
+STORE, 140249744203776, 140249744424959,
+STORE, 140249719472128, 140249721602047,
+STORE, 140249719463936, 140249721602047,
+STORE, 140249719447552, 140249721602047,
+STORE, 140249719439360, 140249721602047,
+STORE, 140249719406592, 140249721602047,
+STORE, 140249719398400, 140249721602047,
+STORE, 140249719382016, 140249721602047,
+STORE, 140249719373824, 140249721602047,
+STORE, 140249719357440, 140249721602047,
+STORE, 140249719349248, 140249721602047,
+STORE, 140249719332864, 140249721602047,
+STORE, 140249719324672, 140249721602047,
+STORE, 140249719291904, 140249721602047,
+STORE, 140249719283712, 140249721602047,
+STORE, 140249719267328, 140249721602047,
+STORE, 140249719259136, 140249721602047,
+STORE, 140249719242752, 140249721602047,
+STORE, 140249719234560, 140249721602047,
+STORE, 140249705783296, 140249710600191,
+STORE, 140249705775104, 140249710600191,
+STORE, 140249705742336, 140249710600191,
+STORE, 140249705734144, 140249710600191,
+STORE, 140249705717760, 140249710600191,
+STORE, 140249670787072, 140249677606911,
+STORE, 140249705709568, 140249710600191,
+STORE, 140249705693184, 140249710600191,
+STORE, 140249705684992, 140249710600191,
+STORE, 140249705668608, 140249710600191,
+STORE, 140249705660416, 140249710600191,
+STORE, 140249705627648, 140249710600191,
+STORE, 140249677893632, 140249710600191,
+STORE, 140249677877248, 140249710600191,
+STORE, 140249677869056, 140249710600191,
+STORE, 140249677852672, 140249710600191,
+STORE, 140249677844480, 140249710600191,
+STORE, 140249677828096, 140249710600191,
+STORE, 140249668689920, 140249677606911,
+STORE, 140249677819904, 140249710600191,
+STORE, 140249677787136, 140249710600191,
+STORE, 140249677778944, 140249710600191,
+STORE, 140249677762560, 140249710600191,
+STORE, 140249677754368, 140249710600191,
+STORE, 140249677737984, 140249710600191,
+STORE, 140249677729792, 140249710600191,
+STORE, 140249677713408, 140249710600191,
+STORE, 140249677705216, 140249710600191,
+STORE, 140249677672448, 140249710600191,
+STORE, 140249677664256, 140249710600191,
+STORE, 140249677647872, 140249710600191,
+STORE, 140249677639680, 140249710600191,
+STORE, 140249677623296, 140249710600191,
+STORE, 140249677615104, 140249710600191,
+STORE, 140249668673536, 140249677606911,
+STORE, 140249668673536, 140249710600191,
+STORE, 140249668640768, 140249710600191,
+STORE, 140249668632576, 140249710600191,
+STORE, 140249668616192, 140249710600191,
+STORE, 140249668608000, 140249710600191,
+STORE, 140249668591616, 140249710600191,
+STORE, 140249668583424, 140249710600191,
+STORE, 140249668567040, 140249710600191,
+STORE, 140249668558848, 140249710600191,
+STORE, 140249668526080, 140249710600191,
+STORE, 140249668517888, 140249710600191,
+STORE, 140249668501504, 140249710600191,
+STORE, 140249668493312, 140249710600191,
+STORE, 140249668476928, 140249710600191,
+STORE, 140249668468736, 140249710600191,
+STORE, 140249668452352, 140249710600191,
+STORE, 140249668444160, 140249710600191,
+STORE, 140249668411392, 140249710600191,
+STORE, 140249668403200, 140249710600191,
+STORE, 140249668386816, 140249710600191,
+STORE, 140249668378624, 140249710600191,
+STORE, 140249668362240, 140249710600191,
+STORE, 140249668354048, 140249710600191,
+STORE, 140249668337664, 140249710600191,
+STORE, 140249668329472, 140249710600191,
+STORE, 140249668296704, 140249710600191,
+STORE, 140249668288512, 140249710600191,
+STORE, 140249668272128, 140249710600191,
+STORE, 140249668263936, 140249710600191,
+STORE, 140249668247552, 140249710600191,
+STORE, 140249668239360, 140249710600191,
+STORE, 140249668222976, 140249710600191,
+STORE, 140249668214784, 140249710600191,
+STORE, 140249668182016, 140249710600191,
+STORE, 140249668173824, 140249710600191,
+STORE, 140249668157440, 140249710600191,
+STORE, 140249668149248, 140249710600191,
+STORE, 140249668132864, 140249710600191,
+STORE, 140249668124672, 140249710600191,
+STORE, 140249668108288, 140249710600191,
+STORE, 140249668100096, 140249710600191,
+STORE, 140249668067328, 140249710600191,
+STORE, 140249668059136, 140249710600191,
+STORE, 140249668042752, 140249710600191,
+STORE, 140249668034560, 140249710600191,
+STORE, 140249668018176, 140249710600191,
+STORE, 140249668009984, 140249710600191,
+STORE, 140249667993600, 140249710600191,
+STORE, 140249667985408, 140249710600191,
+STORE, 140249667952640, 140249710600191,
+STORE, 140249667944448, 140249710600191,
+STORE, 140249667928064, 140249710600191,
+STORE, 140249667919872, 140249710600191,
+STORE, 140249667903488, 140249710600191,
+STORE, 140249667895296, 140249710600191,
+STORE, 140249667878912, 140249710600191,
+STORE, 140249667870720, 140249710600191,
+STORE, 140249667837952, 140249710600191,
+STORE, 140249667829760, 140249710600191,
+STORE, 140249667813376, 140249710600191,
+STORE, 140249667805184, 140249710600191,
+STORE, 140249667788800, 140249710600191,
+STORE, 140249667780608, 140249710600191,
+STORE, 140249667764224, 140249710600191,
+STORE, 140249667756032, 140249710600191,
+STORE, 140249667723264, 140249710600191,
+STORE, 140249667715072, 140249710600191,
+STORE, 140249667698688, 140249710600191,
+STORE, 140249667690496, 140249710600191,
+STORE, 140249667674112, 140249710600191,
+STORE, 140249667665920, 140249710600191,
+STORE, 140249667649536, 140249710600191,
+STORE, 140249667641344, 140249710600191,
+STORE, 140249667608576, 140249710600191,
+STORE, 140249667600384, 140249710600191,
+STORE, 140249667584000, 140249710600191,
+STORE, 140249667575808, 140249710600191,
+STORE, 140249667559424, 140249710600191,
+STORE, 140249667551232, 140249710600191,
+STORE, 140249667534848, 140249710600191,
+STORE, 140249667526656, 140249710600191,
+STORE, 140249667493888, 140249710600191,
+STORE, 140249667485696, 140249710600191,
+STORE, 140249667469312, 140249710600191,
+STORE, 140249667461120, 140249710600191,
+STORE, 140249667444736, 140249710600191,
+STORE, 140249667436544, 140249710600191,
+STORE, 140249667420160, 140249710600191,
+STORE, 140249665323008, 140249710600191,
+STORE, 140249665314816, 140249710600191,
+STORE, 140249665282048, 140249710600191,
+STORE, 140249665273856, 140249710600191,
+STORE, 140249665257472, 140249710600191,
+STORE, 140249665249280, 140249710600191,
+STORE, 140249665232896, 140249710600191,
+STORE, 140249665224704, 140249710600191,
+STORE, 140249665208320, 140249710600191,
+STORE, 140249665200128, 140249710600191,
+STORE, 140249665167360, 140249710600191,
+STORE, 140249665159168, 140249710600191,
+STORE, 140249665142784, 140249710600191,
+STORE, 140249665134592, 140249710600191,
+STORE, 140249665118208, 140249710600191,
+STORE, 140249665110016, 140249710600191,
+STORE, 140249665093632, 140249710600191,
+STORE, 140249665085440, 140249710600191,
+STORE, 140249665052672, 140249710600191,
+STORE, 140249665044480, 140249710600191,
+STORE, 140249665028096, 140249710600191,
+STORE, 140249665019904, 140249710600191,
+STORE, 140249665003520, 140249710600191,
+STORE, 140249664995328, 140249710600191,
+STORE, 140249664978944, 140249710600191,
+STORE, 140249664970752, 140249710600191,
+STORE, 140249664937984, 140249710600191,
+STORE, 140249664929792, 140249710600191,
+STORE, 140249664913408, 140249710600191,
+STORE, 140249664905216, 140249710600191,
+STORE, 140249664888832, 140249710600191,
+STORE, 140249664880640, 140249710600191,
+STORE, 140249664864256, 140249710600191,
+STORE, 140249664856064, 140249710600191,
+STORE, 140249664823296, 140249710600191,
+STORE, 140249664815104, 140249710600191,
+STORE, 140249664798720, 140249710600191,
+STORE, 140249664790528, 140249710600191,
+STORE, 140249664774144, 140249710600191,
+STORE, 140249664765952, 140249710600191,
+STORE, 140249664749568, 140249710600191,
+STORE, 140249664741376, 140249710600191,
+STORE, 140249664708608, 140249710600191,
+STORE, 140249664700416, 140249710600191,
+STORE, 140249664684032, 140249710600191,
+STORE, 140249664675840, 140249710600191,
+STORE, 140249664659456, 140249710600191,
+STORE, 140249664651264, 140249710600191,
+STORE, 140249664634880, 140249710600191,
+STORE, 140249664626688, 140249710600191,
+STORE, 140249664593920, 140249710600191,
+STORE, 140249664585728, 140249710600191,
+STORE, 140249664569344, 140249710600191,
+STORE, 140249664561152, 140249710600191,
+STORE, 140249664544768, 140249710600191,
+STORE, 140249664536576, 140249710600191,
+STORE, 140249664520192, 140249710600191,
+STORE, 140249664512000, 140249710600191,
+STORE, 140249664479232, 140249710600191,
+STORE, 140249664471040, 140249710600191,
+STORE, 140249664454656, 140249710600191,
+STORE, 140249664446464, 140249710600191,
+STORE, 140249664430080, 140249710600191,
+STORE, 140249664421888, 140249710600191,
+STORE, 140249664405504, 140249710600191,
+STORE, 140249664397312, 140249710600191,
+STORE, 140249664364544, 140249710600191,
+STORE, 140249664356352, 140249710600191,
+STORE, 140249664339968, 140249710600191,
+STORE, 140249664331776, 140249710600191,
+STORE, 140249664315392, 140249710600191,
+STORE, 140249664307200, 140249710600191,
+STORE, 140249664290816, 140249710600191,
+STORE, 140249664282624, 140249710600191,
+STORE, 140249664249856, 140249710600191,
+STORE, 140249664241664, 140249710600191,
+STORE, 140249664225280, 140249710600191,
+STORE, 140249664217088, 140249710600191,
+STORE, 140249664200704, 140249710600191,
+STORE, 140249664192512, 140249710600191,
+STORE, 140249664176128, 140249710600191,
+STORE, 140249664167936, 140249710600191,
+STORE, 140249664135168, 140249710600191,
+STORE, 140249664126976, 140249710600191,
+STORE, 140249664110592, 140249710600191,
+STORE, 140249664102400, 140249710600191,
+STORE, 140249664086016, 140249710600191,
+STORE, 140249664077824, 140249710600191,
+STORE, 140249664061440, 140249710600191,
+STORE, 140249664053248, 140249710600191,
+STORE, 140249664020480, 140249710600191,
+STORE, 140249664012288, 140249710600191,
+STORE, 140249663995904, 140249710600191,
+STORE, 140249663987712, 140249710600191,
+STORE, 140249663971328, 140249710600191,
+STORE, 140249663963136, 140249710600191,
+STORE, 140249663946752, 140249710600191,
+STORE, 140249663938560, 140249710600191,
+STORE, 140249663905792, 140249710600191,
+STORE, 140249663897600, 140249710600191,
+STORE, 140249663881216, 140249710600191,
+STORE, 140249663873024, 140249710600191,
+STORE, 140249663856640, 140249710600191,
+STORE, 140249663848448, 140249710600191,
+STORE, 140249663832064, 140249710600191,
+STORE, 140249663823872, 140249710600191,
+STORE, 140249663791104, 140249710600191,
+STORE, 140249663782912, 140249710600191,
+STORE, 140249663766528, 140249710600191,
+STORE, 140249663758336, 140249710600191,
+STORE, 140249663741952, 140249710600191,
+STORE, 140249663733760, 140249710600191,
+STORE, 140249663717376, 140249710600191,
+STORE, 140249663709184, 140249710600191,
+STORE, 140249663676416, 140249710600191,
+STORE, 140249663668224, 140249710600191,
+STORE, 140249663651840, 140249710600191,
+STORE, 140249663643648, 140249710600191,
+STORE, 140249663627264, 140249710600191,
+STORE, 33853440, 38526975,
+STORE, 140249663619072, 140249710600191,
+STORE, 140249663602688, 140249710600191,
+STORE, 140249661505536, 140249710600191,
+STORE, 140249661497344, 140249710600191,
+STORE, 140249661464576, 140249710600191,
+STORE, 140249661456384, 140249710600191,
+STORE, 140249661440000, 140249710600191,
+STORE, 140249661431808, 140249710600191,
+STORE, 140249661415424, 140249710600191,
+STORE, 140249661407232, 140249710600191,
+STORE, 140249661390848, 140249710600191,
+STORE, 140249661382656, 140249710600191,
+STORE, 140249661349888, 140249710600191,
+STORE, 140249661341696, 140249710600191,
+STORE, 140249661325312, 140249710600191,
+STORE, 140249661317120, 140249710600191,
+STORE, 140249661300736, 140249710600191,
+STORE, 140249661292544, 140249710600191,
+STORE, 140249661276160, 140249710600191,
+STORE, 140249661267968, 140249710600191,
+STORE, 140249661235200, 140249710600191,
+STORE, 140249661227008, 140249710600191,
+STORE, 140249661210624, 140249710600191,
+STORE, 140249661202432, 140249710600191,
+STORE, 140249661186048, 140249710600191,
+STORE, 140249661177856, 140249710600191,
+STORE, 140249661161472, 140249710600191,
+STORE, 140249661153280, 140249710600191,
+STORE, 140249661120512, 140249710600191,
+STORE, 140249661112320, 140249710600191,
+STORE, 140249661095936, 140249710600191,
+STORE, 140249661087744, 140249710600191,
+STORE, 140249661071360, 140249710600191,
+STORE, 140249661063168, 140249710600191,
+STORE, 140249661046784, 140249710600191,
+STORE, 140249661038592, 140249710600191,
+STORE, 140249661005824, 140249710600191,
+STORE, 140249660997632, 140249710600191,
+STORE, 140249660981248, 140249710600191,
+STORE, 140249660973056, 140249710600191,
+STORE, 140249660956672, 140249710600191,
+STORE, 140249660948480, 140249710600191,
+STORE, 140249660932096, 140249710600191,
+STORE, 140249660923904, 140249710600191,
+STORE, 140249660891136, 140249710600191,
+STORE, 140249660882944, 140249710600191,
+STORE, 140249660866560, 140249710600191,
+STORE, 140249660858368, 140249710600191,
+STORE, 140249660841984, 140249710600191,
+STORE, 140249660833792, 140249710600191,
+STORE, 140249660817408, 140249710600191,
+STORE, 140249660809216, 140249710600191,
+STORE, 140249660776448, 140249710600191,
+STORE, 140249660768256, 140249710600191,
+STORE, 140249660751872, 140249710600191,
+STORE, 140249660743680, 140249710600191,
+STORE, 140249660727296, 140249710600191,
+STORE, 140249660719104, 140249710600191,
+STORE, 140249660702720, 140249710600191,
+STORE, 140249660694528, 140249710600191,
+STORE, 140249660661760, 140249710600191,
+STORE, 140249660653568, 140249710600191,
+STORE, 140249660637184, 140249710600191,
+STORE, 140249660628992, 140249710600191,
+STORE, 140249660612608, 140249710600191,
+STORE, 140249660604416, 140249710600191,
+STORE, 140249660588032, 140249710600191,
+STORE, 140249660579840, 140249710600191,
+STORE, 140249660547072, 140249710600191,
+STORE, 140249660538880, 140249710600191,
+STORE, 140249660522496, 140249710600191,
+STORE, 140249660514304, 140249710600191,
+STORE, 140249660497920, 140249710600191,
+STORE, 140249660489728, 140249710600191,
+STORE, 140249660473344, 140249710600191,
+STORE, 140249660465152, 140249710600191,
+STORE, 140249660432384, 140249710600191,
+STORE, 140249660424192, 140249710600191,
+STORE, 140249660407808, 140249710600191,
+STORE, 140249660399616, 140249710600191,
+STORE, 140249660383232, 140249710600191,
+STORE, 140249660375040, 140249710600191,
+STORE, 140249660358656, 140249710600191,
+STORE, 140249660350464, 140249710600191,
+STORE, 140249660317696, 140249710600191,
+STORE, 140249660309504, 140249710600191,
+STORE, 140249660293120, 140249710600191,
+STORE, 140249660284928, 140249710600191,
+STORE, 140249660268544, 140249710600191,
+STORE, 140249660260352, 140249710600191,
+STORE, 140249660243968, 140249710600191,
+STORE, 140249660235776, 140249710600191,
+STORE, 140249660203008, 140249710600191,
+STORE, 140249660194816, 140249710600191,
+STORE, 140249660178432, 140249710600191,
+STORE, 140249660170240, 140249710600191,
+STORE, 140249660153856, 140249710600191,
+STORE, 140249660145664, 140249710600191,
+STORE, 140249660129280, 140249710600191,
+STORE, 140249660121088, 140249710600191,
+STORE, 140249660088320, 140249710600191,
+STORE, 140249660080128, 140249710600191,
+STORE, 140249660063744, 140249710600191,
+STORE, 140249660055552, 140249710600191,
+STORE, 140249660039168, 140249710600191,
+STORE, 140249660030976, 140249710600191,
+STORE, 140249660014592, 140249710600191,
+STORE, 140249660006400, 140249710600191,
+STORE, 140249659973632, 140249710600191,
+STORE, 140249659965440, 140249710600191,
+STORE, 140249659949056, 140249710600191,
+STORE, 140249659940864, 140249710600191,
+STORE, 140249659924480, 140249710600191,
+STORE, 140249659916288, 140249710600191,
+STORE, 140249659899904, 140249710600191,
+STORE, 140249659891712, 140249710600191,
+STORE, 140249659858944, 140249710600191,
+STORE, 140249659850752, 140249710600191,
+STORE, 140249659834368, 140249710600191,
+STORE, 140249659826176, 140249710600191,
+STORE, 140249659809792, 140249710600191,
+STORE, 140249659801600, 140249710600191,
+STORE, 140249659785216, 140249710600191,
+STORE, 140249657688064, 140249710600191,
+STORE, 140249657679872, 140249710600191,
+STORE, 140249657647104, 140249710600191,
+STORE, 140249657638912, 140249710600191,
+STORE, 140249657622528, 140249710600191,
+STORE, 140249657614336, 140249710600191,
+STORE, 140249657597952, 140249710600191,
+STORE, 140249657589760, 140249710600191,
+STORE, 140249657573376, 140249710600191,
+STORE, 140249657565184, 140249710600191,
+STORE, 140249657532416, 140249710600191,
+STORE, 140249657524224, 140249710600191,
+STORE, 140249657507840, 140249710600191,
+STORE, 140249657499648, 140249710600191,
+STORE, 140249657483264, 140249710600191,
+STORE, 140249657475072, 140249710600191,
+STORE, 140249657458688, 140249710600191,
+STORE, 140249657450496, 140249710600191,
+STORE, 140249657417728, 140249710600191,
+STORE, 140249657409536, 140249710600191,
+STORE, 140249657393152, 140249710600191,
+STORE, 140249657384960, 140249710600191,
+STORE, 140249657368576, 140249710600191,
+STORE, 140249657360384, 140249710600191,
+STORE, 140249657344000, 140249710600191,
+STORE, 140249657335808, 140249710600191,
+STORE, 140249657303040, 140249710600191,
+STORE, 140249657294848, 140249710600191,
+STORE, 140249657278464, 140249710600191,
+STORE, 140249657270272, 140249710600191,
+STORE, 140249657253888, 140249710600191,
+STORE, 140249657245696, 140249710600191,
+STORE, 140249657229312, 140249710600191,
+STORE, 140249657221120, 140249710600191,
+STORE, 140249657188352, 140249710600191,
+STORE, 140249657180160, 140249710600191,
+STORE, 140249657163776, 140249710600191,
+STORE, 140249657155584, 140249710600191,
+STORE, 140249657139200, 140249710600191,
+STORE, 140249657131008, 140249710600191,
+STORE, 140249657114624, 140249710600191,
+STORE, 140249657106432, 140249710600191,
+STORE, 140249657073664, 140249710600191,
+STORE, 140249657065472, 140249710600191,
+STORE, 140249657049088, 140249710600191,
+STORE, 140249657040896, 140249710600191,
+STORE, 140249657024512, 140249710600191,
+STORE, 140249657016320, 140249710600191,
+STORE, 140249656999936, 140249710600191,
+STORE, 140249656991744, 140249710600191,
+STORE, 140249656958976, 140249710600191,
+STORE, 140249656950784, 140249710600191,
+STORE, 140249656934400, 140249710600191,
+STORE, 140249656926208, 140249710600191,
+STORE, 140249656909824, 140249710600191,
+STORE, 140249656901632, 140249710600191,
+STORE, 140249656885248, 140249710600191,
+STORE, 140249656877056, 140249710600191,
+STORE, 140249656844288, 140249710600191,
+STORE, 140249656836096, 140249710600191,
+STORE, 140249656819712, 140249710600191,
+STORE, 140249656811520, 140249710600191,
+STORE, 140249656795136, 140249710600191,
+STORE, 33853440, 38662143,
+STORE, 140249656786944, 140249710600191,
+STORE, 140249656770560, 140249710600191,
+STORE, 140249656762368, 140249710600191,
+STORE, 140249656729600, 140249710600191,
+STORE, 140249656721408, 140249710600191,
+STORE, 140249656705024, 140249710600191,
+STORE, 140249656696832, 140249710600191,
+STORE, 140249656680448, 140249710600191,
+STORE, 140249656672256, 140249710600191,
+STORE, 140249656655872, 140249710600191,
+STORE, 140249656647680, 140249710600191,
+STORE, 140249656614912, 140249710600191,
+STORE, 140249656606720, 140249710600191,
+STORE, 140249656590336, 140249710600191,
+STORE, 140249656582144, 140249710600191,
+STORE, 140249656565760, 140249710600191,
+STORE, 140249656557568, 140249710600191,
+STORE, 140249656541184, 140249710600191,
+STORE, 140249656532992, 140249710600191,
+STORE, 140249656500224, 140249710600191,
+STORE, 140249656492032, 140249710600191,
+STORE, 140249656475648, 140249710600191,
+STORE, 140249656467456, 140249710600191,
+STORE, 140249656451072, 140249710600191,
+STORE, 140249656442880, 140249710600191,
+STORE, 140249656426496, 140249710600191,
+STORE, 140249656418304, 140249710600191,
+STORE, 140249656385536, 140249710600191,
+STORE, 140249656377344, 140249710600191,
+STORE, 140249656360960, 140249710600191,
+STORE, 140249656352768, 140249710600191,
+STORE, 140249656336384, 140249710600191,
+STORE, 140249656328192, 140249710600191,
+STORE, 140249656311808, 140249710600191,
+STORE, 140249656303616, 140249710600191,
+STORE, 140249656270848, 140249710600191,
+STORE, 140249656262656, 140249710600191,
+STORE, 140249656246272, 140249710600191,
+STORE, 140249656238080, 140249710600191,
+STORE, 140249656221696, 140249710600191,
+STORE, 140249656213504, 140249710600191,
+STORE, 140249656197120, 140249710600191,
+STORE, 140249656188928, 140249710600191,
+STORE, 140249656156160, 140249710600191,
+STORE, 140249656147968, 140249710600191,
+STORE, 140249656131584, 140249710600191,
+STORE, 140249656123392, 140249710600191,
+STORE, 140249656107008, 140249710600191,
+STORE, 140249656098816, 140249710600191,
+STORE, 140249656082432, 140249710600191,
+STORE, 140249656074240, 140249710600191,
+STORE, 140249656041472, 140249710600191,
+STORE, 140249656033280, 140249710600191,
+STORE, 140249656016896, 140249710600191,
+STORE, 140249656008704, 140249710600191,
+STORE, 140249655992320, 140249710600191,
+STORE, 140249655984128, 140249710600191,
+STORE, 140249655967744, 140249710600191,
+STORE, 140249653870592, 140249710600191,
+STORE, 140249653862400, 140249710600191,
+STORE, 140249653829632, 140249710600191,
+STORE, 140249653821440, 140249710600191,
+STORE, 140249653805056, 140249710600191,
+STORE, 140249653796864, 140249710600191,
+STORE, 140249653780480, 140249710600191,
+STORE, 140249653772288, 140249710600191,
+STORE, 140249653755904, 140249710600191,
+STORE, 140249652703232, 140249710600191,
+SNULL, 140249682087935, 140249710600191,
+STORE, 140249652703232, 140249682087935,
+STORE, 140249682087936, 140249710600191,
+ };
+
+ unsigned long set26[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140729464770560, 140737488351231,
+SNULL, 140729464774655, 140737488351231,
+STORE, 140729464770560, 140729464774655,
+STORE, 140729464639488, 140729464774655,
+STORE, 4194304, 5066751,
+STORE, 7159808, 7172095,
+STORE, 7172096, 7180287,
+STORE, 140729465114624, 140729465118719,
+STORE, 140729465102336, 140729465114623,
+STORE, 30867456, 30875647,
+STORE, 30867456, 31010815,
+STORE, 140109040988160, 140109042671615,
+STORE, 140109040959488, 140109040988159,
+STORE, 140109040943104, 140109040959487,
+ERASE, 140109040943104, 140109040959487,
+STORE, 140109040840704, 140109040959487,
+ERASE, 140109040840704, 140109040959487,
+STORE, 140109040951296, 140109040959487,
+ERASE, 140109040951296, 140109040959487,
+STORE, 140109040955392, 140109040959487,
+ERASE, 140109040955392, 140109040959487,
+ };
+ unsigned long set27[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140726128070656, 140737488351231,
+SNULL, 140726128074751, 140737488351231,
+STORE, 140726128070656, 140726128074751,
+STORE, 140726127939584, 140726128074751,
+STORE, 94478497189888, 94478499303423,
+SNULL, 94478497202175, 94478499303423,
+STORE, 94478497189888, 94478497202175,
+STORE, 94478497202176, 94478499303423,
+ERASE, 94478497202176, 94478499303423,
+STORE, 94478499295232, 94478499303423,
+STORE, 140415605723136, 140415607975935,
+SNULL, 140415605866495, 140415607975935,
+STORE, 140415605723136, 140415605866495,
+STORE, 140415605866496, 140415607975935,
+ERASE, 140415605866496, 140415607975935,
+STORE, 140415607963648, 140415607971839,
+STORE, 140415607971840, 140415607975935,
+STORE, 140726130024448, 140726130028543,
+STORE, 140726130012160, 140726130024447,
+STORE, 140415607934976, 140415607963647,
+STORE, 140415607926784, 140415607934975,
+STORE, 140415603245056, 140415605723135,
+SNULL, 140415603245056, 140415603613695,
+STORE, 140415603613696, 140415605723135,
+STORE, 140415603245056, 140415603613695,
+SNULL, 140415605710847, 140415605723135,
+STORE, 140415603613696, 140415605710847,
+STORE, 140415605710848, 140415605723135,
+ERASE, 140415605710848, 140415605723135,
+STORE, 140415605710848, 140415605723135,
+STORE, 140415599370240, 140415603245055,
+SNULL, 140415599370240, 140415601111039,
+STORE, 140415601111040, 140415603245055,
+STORE, 140415599370240, 140415601111039,
+SNULL, 140415603208191, 140415603245055,
+STORE, 140415601111040, 140415603208191,
+STORE, 140415603208192, 140415603245055,
+ERASE, 140415603208192, 140415603245055,
+STORE, 140415603208192, 140415603245055,
+STORE, 140415595692032, 140415599370239,
+SNULL, 140415595692032, 140415597207551,
+STORE, 140415597207552, 140415599370239,
+STORE, 140415595692032, 140415597207551,
+SNULL, 140415599304703, 140415599370239,
+STORE, 140415597207552, 140415599304703,
+STORE, 140415599304704, 140415599370239,
+SNULL, 140415599304704, 140415599353855,
+STORE, 140415599353856, 140415599370239,
+STORE, 140415599304704, 140415599353855,
+ERASE, 140415599304704, 140415599353855,
+STORE, 140415599304704, 140415599353855,
+ERASE, 140415599353856, 140415599370239,
+STORE, 140415599353856, 140415599370239,
+STORE, 140415593500672, 140415595692031,
+SNULL, 140415593500672, 140415593590783,
+STORE, 140415593590784, 140415595692031,
+STORE, 140415593500672, 140415593590783,
+SNULL, 140415595683839, 140415595692031,
+STORE, 140415593590784, 140415595683839,
+STORE, 140415595683840, 140415595692031,
+ERASE, 140415595683840, 140415595692031,
+STORE, 140415595683840, 140415595692031,
+STORE, 140415589703680, 140415593500671,
+SNULL, 140415589703680, 140415591362559,
+STORE, 140415591362560, 140415593500671,
+STORE, 140415589703680, 140415591362559,
+SNULL, 140415593459711, 140415593500671,
+STORE, 140415591362560, 140415593459711,
+STORE, 140415593459712, 140415593500671,
+SNULL, 140415593459712, 140415593484287,
+STORE, 140415593484288, 140415593500671,
+STORE, 140415593459712, 140415593484287,
+ERASE, 140415593459712, 140415593484287,
+STORE, 140415593459712, 140415593484287,
+ERASE, 140415593484288, 140415593500671,
+STORE, 140415593484288, 140415593500671,
+STORE, 140415587590144, 140415589703679,
+SNULL, 140415587590144, 140415587602431,
+STORE, 140415587602432, 140415589703679,
+STORE, 140415587590144, 140415587602431,
+SNULL, 140415589695487, 140415589703679,
+STORE, 140415587602432, 140415589695487,
+STORE, 140415589695488, 140415589703679,
+ERASE, 140415589695488, 140415589703679,
+STORE, 140415589695488, 140415589703679,
+STORE, 140415607918592, 140415607934975,
+STORE, 140415585398784, 140415587590143,
+SNULL, 140415585398784, 140415585480703,
+STORE, 140415585480704, 140415587590143,
+STORE, 140415585398784, 140415585480703,
+SNULL, 140415587573759, 140415587590143,
+STORE, 140415585480704, 140415587573759,
+STORE, 140415587573760, 140415587590143,
+SNULL, 140415587573760, 140415587581951,
+STORE, 140415587581952, 140415587590143,
+STORE, 140415587573760, 140415587581951,
+ERASE, 140415587573760, 140415587581951,
+STORE, 140415587573760, 140415587581951,
+ERASE, 140415587581952, 140415587590143,
+STORE, 140415587581952, 140415587590143,
+STORE, 140415583182848, 140415585398783,
+SNULL, 140415583182848, 140415583281151,
+STORE, 140415583281152, 140415585398783,
+STORE, 140415583182848, 140415583281151,
+SNULL, 140415585374207, 140415585398783,
+STORE, 140415583281152, 140415585374207,
+STORE, 140415585374208, 140415585398783,
+SNULL, 140415585374208, 140415585382399,
+STORE, 140415585382400, 140415585398783,
+STORE, 140415585374208, 140415585382399,
+ERASE, 140415585374208, 140415585382399,
+STORE, 140415585374208, 140415585382399,
+ERASE, 140415585382400, 140415585398783,
+STORE, 140415585382400, 140415585398783,
+STORE, 140415580979200, 140415583182847,
+SNULL, 140415580979200, 140415581081599,
+STORE, 140415581081600, 140415583182847,
+STORE, 140415580979200, 140415581081599,
+SNULL, 140415583174655, 140415583182847,
+STORE, 140415581081600, 140415583174655,
+STORE, 140415583174656, 140415583182847,
+ERASE, 140415583174656, 140415583182847,
+STORE, 140415583174656, 140415583182847,
+STORE, 140415578816512, 140415580979199,
+SNULL, 140415578816512, 140415578877951,
+STORE, 140415578877952, 140415580979199,
+STORE, 140415578816512, 140415578877951,
+SNULL, 140415580971007, 140415580979199,
+STORE, 140415578877952, 140415580971007,
+STORE, 140415580971008, 140415580979199,
+ERASE, 140415580971008, 140415580979199,
+STORE, 140415580971008, 140415580979199,
+STORE, 140415576563712, 140415578816511,
+SNULL, 140415576563712, 140415576715263,
+STORE, 140415576715264, 140415578816511,
+STORE, 140415576563712, 140415576715263,
+SNULL, 140415578808319, 140415578816511,
+STORE, 140415576715264, 140415578808319,
+STORE, 140415578808320, 140415578816511,
+ERASE, 140415578808320, 140415578816511,
+STORE, 140415578808320, 140415578816511,
+STORE, 140415574392832, 140415576563711,
+SNULL, 140415574392832, 140415574462463,
+STORE, 140415574462464, 140415576563711,
+STORE, 140415574392832, 140415574462463,
+SNULL, 140415576555519, 140415576563711,
+STORE, 140415574462464, 140415576555519,
+STORE, 140415576555520, 140415576563711,
+ERASE, 140415576555520, 140415576563711,
+STORE, 140415576555520, 140415576563711,
+STORE, 140415607910400, 140415607934975,
+STORE, 140415571230720, 140415574392831,
+SNULL, 140415571230720, 140415572291583,
+STORE, 140415572291584, 140415574392831,
+STORE, 140415571230720, 140415572291583,
+SNULL, 140415574384639, 140415574392831,
+STORE, 140415572291584, 140415574384639,
+STORE, 140415574384640, 140415574392831,
+ERASE, 140415574384640, 140415574392831,
+STORE, 140415574384640, 140415574392831,
+STORE, 140415607902208, 140415607934975,
+SNULL, 140415593476095, 140415593484287,
+STORE, 140415593459712, 140415593476095,
+STORE, 140415593476096, 140415593484287,
+SNULL, 140415574388735, 140415574392831,
+STORE, 140415574384640, 140415574388735,
+STORE, 140415574388736, 140415574392831,
+SNULL, 140415576559615, 140415576563711,
+STORE, 140415576555520, 140415576559615,
+STORE, 140415576559616, 140415576563711,
+SNULL, 140415589699583, 140415589703679,
+STORE, 140415589695488, 140415589699583,
+STORE, 140415589699584, 140415589703679,
+SNULL, 140415585378303, 140415585382399,
+STORE, 140415585374208, 140415585378303,
+STORE, 140415585378304, 140415585382399,
+SNULL, 140415578812415, 140415578816511,
+STORE, 140415578808320, 140415578812415,
+STORE, 140415578812416, 140415578816511,
+SNULL, 140415580975103, 140415580979199,
+STORE, 140415580971008, 140415580975103,
+STORE, 140415580975104, 140415580979199,
+SNULL, 140415583178751, 140415583182847,
+STORE, 140415583174656, 140415583178751,
+STORE, 140415583178752, 140415583182847,
+SNULL, 140415587577855, 140415587581951,
+STORE, 140415587573760, 140415587577855,
+STORE, 140415587577856, 140415587581951,
+SNULL, 140415595687935, 140415595692031,
+STORE, 140415595683840, 140415595687935,
+STORE, 140415595687936, 140415595692031,
+STORE, 140415607894016, 140415607934975,
+SNULL, 140415599345663, 140415599353855,
+STORE, 140415599304704, 140415599345663,
+STORE, 140415599345664, 140415599353855,
+SNULL, 140415603240959, 140415603245055,
+STORE, 140415603208192, 140415603240959,
+STORE, 140415603240960, 140415603245055,
+SNULL, 140415605719039, 140415605723135,
+STORE, 140415605710848, 140415605719039,
+STORE, 140415605719040, 140415605723135,
+SNULL, 94478499299327, 94478499303423,
+STORE, 94478499295232, 94478499299327,
+STORE, 94478499299328, 94478499303423,
+SNULL, 140415607967743, 140415607971839,
+STORE, 140415607963648, 140415607967743,
+STORE, 140415607967744, 140415607971839,
+ERASE, 140415607934976, 140415607963647,
+STORE, 94478511173632, 94478511378431,
+STORE, 140415606210560, 140415607894015,
+STORE, 140415607934976, 140415607963647,
+STORE, 94478511173632, 94478511513599,
+STORE, 94478511173632, 94478511648767,
+SNULL, 94478511615999, 94478511648767,
+STORE, 94478511173632, 94478511615999,
+STORE, 94478511616000, 94478511648767,
+ERASE, 94478511616000, 94478511648767,
+STORE, 94478511173632, 94478511751167,
+SNULL, 94478511747071, 94478511751167,
+STORE, 94478511173632, 94478511747071,
+STORE, 94478511747072, 94478511751167,
+ERASE, 94478511747072, 94478511751167,
+STORE, 94478511173632, 94478511882239,
+SNULL, 94478511878143, 94478511882239,
+STORE, 94478511173632, 94478511878143,
+STORE, 94478511878144, 94478511882239,
+ERASE, 94478511878144, 94478511882239,
+STORE, 94478511173632, 94478512013311,
+SNULL, 94478512009215, 94478512013311,
+STORE, 94478511173632, 94478512009215,
+STORE, 94478512009216, 94478512013311,
+ERASE, 94478512009216, 94478512013311,
+STORE, 94478511173632, 94478512144383,
+STORE, 94478511173632, 94478512279551,
+STORE, 140415606181888, 140415606210559,
+STORE, 140415569100800, 140415571230719,
+SNULL, 140415569100800, 140415569129471,
+STORE, 140415569129472, 140415571230719,
+STORE, 140415569100800, 140415569129471,
+SNULL, 140415571222527, 140415571230719,
+STORE, 140415569129472, 140415571222527,
+STORE, 140415571222528, 140415571230719,
+ERASE, 140415571222528, 140415571230719,
+STORE, 140415571222528, 140415571230719,
+STORE, 140415566905344, 140415569100799,
+SNULL, 140415566905344, 140415566987263,
+STORE, 140415566987264, 140415569100799,
+STORE, 140415566905344, 140415566987263,
+SNULL, 140415569084415, 140415569100799,
+STORE, 140415566987264, 140415569084415,
+STORE, 140415569084416, 140415569100799,
+SNULL, 140415569084416, 140415569092607,
+STORE, 140415569092608, 140415569100799,
+STORE, 140415569084416, 140415569092607,
+ERASE, 140415569084416, 140415569092607,
+STORE, 140415569084416, 140415569092607,
+ERASE, 140415569092608, 140415569100799,
+STORE, 140415569092608, 140415569100799,
+SNULL, 140415569088511, 140415569092607,
+STORE, 140415569084416, 140415569088511,
+STORE, 140415569088512, 140415569092607,
+SNULL, 140415571226623, 140415571230719,
+STORE, 140415571222528, 140415571226623,
+STORE, 140415571226624, 140415571230719,
+ERASE, 140415606181888, 140415606210559,
+STORE, 140415606181888, 140415606210559,
+STORE, 140415564759040, 140415566905343,
+SNULL, 140415564759040, 140415564804095,
+STORE, 140415564804096, 140415566905343,
+STORE, 140415564759040, 140415564804095,
+SNULL, 140415566897151, 140415566905343,
+STORE, 140415564804096, 140415566897151,
+STORE, 140415566897152, 140415566905343,
+ERASE, 140415566897152, 140415566905343,
+STORE, 140415566897152, 140415566905343,
+STORE, 140415562588160, 140415564759039,
+SNULL, 140415562588160, 140415562629119,
+STORE, 140415562629120, 140415564759039,
+STORE, 140415562588160, 140415562629119,
+SNULL, 140415564726271, 140415564759039,
+STORE, 140415562629120, 140415564726271,
+STORE, 140415564726272, 140415564759039,
+SNULL, 140415564726272, 140415564734463,
+STORE, 140415564734464, 140415564759039,
+STORE, 140415564726272, 140415564734463,
+ERASE, 140415564726272, 140415564734463,
+STORE, 140415564726272, 140415564734463,
+ERASE, 140415564734464, 140415564759039,
+STORE, 140415564734464, 140415564759039,
+SNULL, 140415564730367, 140415564734463,
+STORE, 140415564726272, 140415564730367,
+STORE, 140415564730368, 140415564734463,
+SNULL, 140415566901247, 140415566905343,
+STORE, 140415566897152, 140415566901247,
+STORE, 140415566901248, 140415566905343,
+ERASE, 140415606181888, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415605944320, 140415606210559,
+ERASE, 140415605944320, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 94478511173632, 94478512414719,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 140415606206464, 140415606210559,
+ERASE, 140415606206464, 140415606210559,
+STORE, 94478511173632, 94478512652287,
+STORE, 94478511173632, 94478512787455,
+STORE, 94478511173632, 94478512922623,
+STORE, 94478511173632, 94478513057791,
+STORE, 140415537422336, 140415562588159,
+STORE, 94478511173632, 94478513192959,
+STORE, 94478511173632, 94478513356799,
+STORE, 94478511173632, 94478513491967,
+STORE, 94478511173632, 94478513627135,
+STORE, 94478511173632, 94478513790975,
+STORE, 94478511173632, 94478513926143,
+STORE, 94478511173632, 94478514061311,
+STORE, 94478511173632, 94478514196479,
+STORE, 94478511173632, 94478514331647,
+STORE, 94478511173632, 94478514606079,
+STORE, 94478511173632, 94478514741247,
+STORE, 94478511173632, 94478514876415,
+STORE, 94478511173632, 94478515011583,
+STORE, 94478511173632, 94478515146751,
+STORE, 94478511173632, 94478515281919,
+STORE, 94478511173632, 94478515474431,
+STORE, 94478511173632, 94478515609599,
+STORE, 94478511173632, 94478515744767,
+STORE, 140415536922624, 140415562588159,
+STORE, 94478511173632, 94478515879935,
+STORE, 94478511173632, 94478516015103,
+STORE, 94478511173632, 94478516150271,
+STORE, 94478511173632, 94478516285439,
+STORE, 94478511173632, 94478516420607,
+STORE, 94478511173632, 94478516555775,
+STORE, 94478511173632, 94478516690943,
+STORE, 94478511173632, 94478516826111,
+STORE, 94478511173632, 94478516961279,
+STORE, 94478511173632, 94478517231615,
+STORE, 94478511173632, 94478517366783,
+STORE, 94478511173632, 94478517501951,
+STORE, 94478511173632, 94478517637119,
+STORE, 94478511173632, 94478517772287,
+STORE, 94478511173632, 94478517907455,
+STORE, 94478511173632, 94478518042623,
+STORE, 94478511173632, 94478518177791,
+STORE, 94478511173632, 94478518312959,
+STORE, 94478511173632, 94478518448127,
+STORE, 140415535910912, 140415562588159,
+SNULL, 140415536922623, 140415562588159,
+STORE, 140415535910912, 140415536922623,
+STORE, 140415536922624, 140415562588159,
+SNULL, 140415536922624, 140415537422335,
+STORE, 140415537422336, 140415562588159,
+STORE, 140415536922624, 140415537422335,
+ERASE, 140415536922624, 140415537422335,
+STORE, 94478511173632, 94478518583295,
+STORE, 94478511173632, 94478518718463,
+STORE, 94478511173632, 94478518853631,
+STORE, 94478511173632, 94478518988799,
+STORE, 94478511173632, 94478519123967,
+STORE, 94478511173632, 94478519259135,
+STORE, 140415509696512, 140415535910911,
+ERASE, 140415537422336, 140415562588159,
+STORE, 140415482433536, 140415509696511,
+ };
+ unsigned long set28[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140722475622400, 140737488351231,
+SNULL, 140722475626495, 140737488351231,
+STORE, 140722475622400, 140722475626495,
+STORE, 140722475491328, 140722475626495,
+STORE, 93865834291200, 93865836548095,
+SNULL, 93865834422271, 93865836548095,
+STORE, 93865834291200, 93865834422271,
+STORE, 93865834422272, 93865836548095,
+ERASE, 93865834422272, 93865836548095,
+STORE, 93865836519424, 93865836527615,
+STORE, 93865836527616, 93865836548095,
+STORE, 139918411104256, 139918413357055,
+SNULL, 139918411247615, 139918413357055,
+STORE, 139918411104256, 139918411247615,
+STORE, 139918411247616, 139918413357055,
+ERASE, 139918411247616, 139918413357055,
+STORE, 139918413344768, 139918413352959,
+STORE, 139918413352960, 139918413357055,
+STORE, 140722476642304, 140722476646399,
+STORE, 140722476630016, 140722476642303,
+STORE, 139918413316096, 139918413344767,
+STORE, 139918413307904, 139918413316095,
+STORE, 139918408888320, 139918411104255,
+SNULL, 139918408888320, 139918408986623,
+STORE, 139918408986624, 139918411104255,
+STORE, 139918408888320, 139918408986623,
+SNULL, 139918411079679, 139918411104255,
+STORE, 139918408986624, 139918411079679,
+STORE, 139918411079680, 139918411104255,
+SNULL, 139918411079680, 139918411087871,
+STORE, 139918411087872, 139918411104255,
+STORE, 139918411079680, 139918411087871,
+ERASE, 139918411079680, 139918411087871,
+STORE, 139918411079680, 139918411087871,
+ERASE, 139918411087872, 139918411104255,
+STORE, 139918411087872, 139918411104255,
+STORE, 139918405091328, 139918408888319,
+SNULL, 139918405091328, 139918406750207,
+STORE, 139918406750208, 139918408888319,
+STORE, 139918405091328, 139918406750207,
+SNULL, 139918408847359, 139918408888319,
+STORE, 139918406750208, 139918408847359,
+STORE, 139918408847360, 139918408888319,
+SNULL, 139918408847360, 139918408871935,
+STORE, 139918408871936, 139918408888319,
+STORE, 139918408847360, 139918408871935,
+ERASE, 139918408847360, 139918408871935,
+STORE, 139918408847360, 139918408871935,
+ERASE, 139918408871936, 139918408888319,
+STORE, 139918408871936, 139918408888319,
+STORE, 139918413299712, 139918413316095,
+SNULL, 139918408863743, 139918408871935,
+STORE, 139918408847360, 139918408863743,
+STORE, 139918408863744, 139918408871935,
+SNULL, 139918411083775, 139918411087871,
+STORE, 139918411079680, 139918411083775,
+STORE, 139918411083776, 139918411087871,
+SNULL, 93865836523519, 93865836527615,
+STORE, 93865836519424, 93865836523519,
+STORE, 93865836523520, 93865836527615,
+SNULL, 139918413348863, 139918413352959,
+STORE, 139918413344768, 139918413348863,
+STORE, 139918413348864, 139918413352959,
+ERASE, 139918413316096, 139918413344767,
+STORE, 93865848528896, 93865848664063,
+ };
+ unsigned long set29[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140734467944448, 140737488351231,
+SNULL, 140734467948543, 140737488351231,
+STORE, 140734467944448, 140734467948543,
+STORE, 140734467813376, 140734467948543,
+STORE, 94880407924736, 94880410177535,
+SNULL, 94880408055807, 94880410177535,
+STORE, 94880407924736, 94880408055807,
+STORE, 94880408055808, 94880410177535,
+ERASE, 94880408055808, 94880410177535,
+STORE, 94880410148864, 94880410157055,
+STORE, 94880410157056, 94880410177535,
+STORE, 140143367815168, 140143370067967,
+SNULL, 140143367958527, 140143370067967,
+STORE, 140143367815168, 140143367958527,
+STORE, 140143367958528, 140143370067967,
+ERASE, 140143367958528, 140143370067967,
+STORE, 140143370055680, 140143370063871,
+STORE, 140143370063872, 140143370067967,
+STORE, 140734468329472, 140734468333567,
+STORE, 140734468317184, 140734468329471,
+STORE, 140143370027008, 140143370055679,
+STORE, 140143370018816, 140143370027007,
+STORE, 140143365599232, 140143367815167,
+SNULL, 140143365599232, 140143365697535,
+STORE, 140143365697536, 140143367815167,
+STORE, 140143365599232, 140143365697535,
+SNULL, 140143367790591, 140143367815167,
+STORE, 140143365697536, 140143367790591,
+STORE, 140143367790592, 140143367815167,
+SNULL, 140143367790592, 140143367798783,
+STORE, 140143367798784, 140143367815167,
+STORE, 140143367790592, 140143367798783,
+ERASE, 140143367790592, 140143367798783,
+STORE, 140143367790592, 140143367798783,
+ERASE, 140143367798784, 140143367815167,
+STORE, 140143367798784, 140143367815167,
+STORE, 140143361802240, 140143365599231,
+SNULL, 140143361802240, 140143363461119,
+STORE, 140143363461120, 140143365599231,
+STORE, 140143361802240, 140143363461119,
+SNULL, 140143365558271, 140143365599231,
+STORE, 140143363461120, 140143365558271,
+STORE, 140143365558272, 140143365599231,
+SNULL, 140143365558272, 140143365582847,
+STORE, 140143365582848, 140143365599231,
+STORE, 140143365558272, 140143365582847,
+ERASE, 140143365558272, 140143365582847,
+STORE, 140143365558272, 140143365582847,
+ERASE, 140143365582848, 140143365599231,
+STORE, 140143365582848, 140143365599231,
+STORE, 140143370010624, 140143370027007,
+SNULL, 140143365574655, 140143365582847,
+STORE, 140143365558272, 140143365574655,
+STORE, 140143365574656, 140143365582847,
+SNULL, 140143367794687, 140143367798783,
+STORE, 140143367790592, 140143367794687,
+STORE, 140143367794688, 140143367798783,
+SNULL, 94880410152959, 94880410157055,
+STORE, 94880410148864, 94880410152959,
+STORE, 94880410152960, 94880410157055,
+SNULL, 140143370059775, 140143370063871,
+STORE, 140143370055680, 140143370059775,
+STORE, 140143370059776, 140143370063871,
+ERASE, 140143370027008, 140143370055679,
+STORE, 94880442400768, 94880442535935,
+STORE, 140143353409536, 140143361802239,
+SNULL, 140143353413631, 140143361802239,
+STORE, 140143353409536, 140143353413631,
+STORE, 140143353413632, 140143361802239,
+STORE, 140143345016832, 140143353409535,
+STORE, 140143210799104, 140143345016831,
+SNULL, 140143210799104, 140143239364607,
+STORE, 140143239364608, 140143345016831,
+STORE, 140143210799104, 140143239364607,
+ERASE, 140143210799104, 140143239364607,
+SNULL, 140143306473471, 140143345016831,
+STORE, 140143239364608, 140143306473471,
+STORE, 140143306473472, 140143345016831,
+ERASE, 140143306473472, 140143345016831,
+SNULL, 140143239499775, 140143306473471,
+STORE, 140143239364608, 140143239499775,
+STORE, 140143239499776, 140143306473471,
+SNULL, 140143345020927, 140143353409535,
+STORE, 140143345016832, 140143345020927,
+STORE, 140143345020928, 140143353409535,
+STORE, 140143336624128, 140143345016831,
+SNULL, 140143336628223, 140143345016831,
+STORE, 140143336624128, 140143336628223,
+STORE, 140143336628224, 140143345016831,
+STORE, 140143328231424, 140143336624127,
+SNULL, 140143328235519, 140143336624127,
+STORE, 140143328231424, 140143328235519,
+STORE, 140143328235520, 140143336624127,
+STORE, 140143319838720, 140143328231423,
+SNULL, 140143319842815, 140143328231423,
+STORE, 140143319838720, 140143319842815,
+STORE, 140143319842816, 140143328231423,
+STORE, 140143311446016, 140143319838719,
+STORE, 140143105146880, 140143239364607,
+STORE, 140143096754176, 140143105146879,
+STORE, 140143029645312, 140143096754175,
+ERASE, 140143029645312, 140143096754175,
+STORE, 140142962536448, 140143096754175,
+SNULL, 140142962536448, 140142970929151,
+STORE, 140142970929152, 140143096754175,
+STORE, 140142962536448, 140142970929151,
+ERASE, 140142962536448, 140142970929151,
+STORE, 140142962536448, 140142970929151,
+STORE, 140142828318720, 140142962536447,
+STORE, 140142819926016, 140142828318719,
+SNULL, 140142828318720, 140142836711423,
+STORE, 140142836711424, 140142962536447,
+STORE, 140142828318720, 140142836711423,
+ERASE, 140142828318720, 140142836711423,
+SNULL, 140143172255743, 140143239364607,
+STORE, 140143105146880, 140143172255743,
+STORE, 140143172255744, 140143239364607,
+ERASE, 140143172255744, 140143239364607,
+SNULL, 140143105282047, 140143172255743,
+STORE, 140143105146880, 140143105282047,
+STORE, 140143105282048, 140143172255743,
+SNULL, 140143038038015, 140143096754175,
+STORE, 140142970929152, 140143038038015,
+STORE, 140143038038016, 140143096754175,
+ERASE, 140143038038016, 140143096754175,
+SNULL, 140142971064319, 140143038038015,
+STORE, 140142970929152, 140142971064319,
+STORE, 140142971064320, 140143038038015,
+SNULL, 140142903820287, 140142962536447,
+STORE, 140142836711424, 140142903820287,
+STORE, 140142903820288, 140142962536447,
+ERASE, 140142903820288, 140142962536447,
+SNULL, 140142836846591, 140142903820287,
+STORE, 140142836711424, 140142836846591,
+STORE, 140142836846592, 140142903820287,
+STORE, 140142685708288, 140142819926015,
+SNULL, 140143311450111, 140143319838719,
+STORE, 140143311446016, 140143311450111,
+STORE, 140143311450112, 140143319838719,
+SNULL, 140142962540543, 140142970929151,
+STORE, 140142962536448, 140142962540543,
+STORE, 140142962540544, 140142970929151,
+SNULL, 140142685708288, 140142702493695,
+STORE, 140142702493696, 140142819926015,
+STORE, 140142685708288, 140142702493695,
+ERASE, 140142685708288, 140142702493695,
+SNULL, 140142769602559, 140142819926015,
+STORE, 140142702493696, 140142769602559,
+STORE, 140142769602560, 140142819926015,
+ERASE, 140142769602560, 140142819926015,
+SNULL, 140142702628863, 140142769602559,
+STORE, 140142702493696, 140142702628863,
+STORE, 140142702628864, 140142769602559,
+STORE, 140143230971904, 140143239364607,
+SNULL, 140143230975999, 140143239364607,
+STORE, 140143230971904, 140143230975999,
+STORE, 140143230976000, 140143239364607,
+SNULL, 140143096758271, 140143105146879,
+STORE, 140143096754176, 140143096758271,
+STORE, 140143096758272, 140143105146879,
+STORE, 140143222579200, 140143230971903,
+SNULL, 140143222583295, 140143230971903,
+STORE, 140143222579200, 140143222583295,
+STORE, 140143222583296, 140143230971903,
+STORE, 140143214186496, 140143222579199,
+SNULL, 140142819930111, 140142828318719,
+STORE, 140142819926016, 140142819930111,
+STORE, 140142819930112, 140142828318719,
+STORE, 140143205793792, 140143222579199,
+SNULL, 140143205793792, 140143214186495,
+STORE, 140143214186496, 140143222579199,
+STORE, 140143205793792, 140143214186495,
+SNULL, 140143214190591, 140143222579199,
+STORE, 140143214186496, 140143214190591,
+STORE, 140143214190592, 140143222579199,
+SNULL, 140143205797887, 140143214186495,
+STORE, 140143205793792, 140143205797887,
+STORE, 140143205797888, 140143214186495,
+STORE, 140143197401088, 140143205793791,
+SNULL, 140143197405183, 140143205793791,
+STORE, 140143197401088, 140143197405183,
+STORE, 140143197405184, 140143205793791,
+STORE, 140143189008384, 140143197401087,
+STORE, 140143180615680, 140143197401087,
+STORE, 140143088361472, 140143096754175,
+SNULL, 140143180619775, 140143197401087,
+STORE, 140143180615680, 140143180619775,
+STORE, 140143180619776, 140143197401087,
+SNULL, 140143180619776, 140143189008383,
+STORE, 140143189008384, 140143197401087,
+STORE, 140143180619776, 140143189008383,
+SNULL, 140143189012479, 140143197401087,
+STORE, 140143189008384, 140143189012479,
+STORE, 140143189012480, 140143197401087,
+SNULL, 140143088365567, 140143096754175,
+STORE, 140143088361472, 140143088365567,
+STORE, 140143088365568, 140143096754175,
+STORE, 140143079968768, 140143088361471,
+SNULL, 140143079972863, 140143088361471,
+STORE, 140143079968768, 140143079972863,
+STORE, 140143079972864, 140143088361471,
+STORE, 140143071576064, 140143079968767,
+SNULL, 140143071580159, 140143079968767,
+STORE, 140143071576064, 140143071580159,
+STORE, 140143071580160, 140143079968767,
+STORE, 140143063183360, 140143071576063,
+STORE, 140143054790656, 140143071576063,
+SNULL, 140143054794751, 140143071576063,
+STORE, 140143054790656, 140143054794751,
+STORE, 140143054794752, 140143071576063,
+SNULL, 140143054794752, 140143063183359,
+STORE, 140143063183360, 140143071576063,
+STORE, 140143054794752, 140143063183359,
+SNULL, 140143063187455, 140143071576063,
+STORE, 140143063183360, 140143063187455,
+STORE, 140143063187456, 140143071576063,
+STORE, 140143046397952, 140143054790655,
+STORE, 140142954143744, 140142962536447,
+STORE, 140142945751040, 140142962536447,
+STORE, 140142937358336, 140142962536447,
+STORE, 140142928965632, 140142962536447,
+STORE, 140142568275968, 140142702493695,
+SNULL, 140142635384831, 140142702493695,
+STORE, 140142568275968, 140142635384831,
+STORE, 140142635384832, 140142702493695,
+ERASE, 140142635384832, 140142702493695,
+STORE, 140142920572928, 140142962536447,
+STORE, 140142912180224, 140142962536447,
+STORE, 140142568275968, 140142702493695,
+SNULL, 140142568275968, 140142635384831,
+STORE, 140142635384832, 140142702493695,
+STORE, 140142568275968, 140142635384831,
+SNULL, 140142635519999, 140142702493695,
+STORE, 140142635384832, 140142635519999,
+STORE, 140142635520000, 140142702493695,
+STORE, 140142819930112, 140142836711423,
+STORE, 140142811533312, 140142819926015,
+STORE, 140142434058240, 140142635384831,
+SNULL, 140142501167103, 140142635384831,
+STORE, 140142434058240, 140142501167103,
+STORE, 140142501167104, 140142635384831,
+SNULL, 140142501167104, 140142568275967,
+STORE, 140142568275968, 140142635384831,
+STORE, 140142501167104, 140142568275967,
+ERASE, 140142501167104, 140142568275967,
+STORE, 140142299840512, 140142501167103,
+STORE, 140142803140608, 140142819926015,
+SNULL, 140142366949375, 140142501167103,
+STORE, 140142299840512, 140142366949375,
+STORE, 140142366949376, 140142501167103,
+SNULL, 140142366949376, 140142434058239,
+STORE, 140142434058240, 140142501167103,
+STORE, 140142366949376, 140142434058239,
+ERASE, 140142366949376, 140142434058239,
+STORE, 140142794747904, 140142819926015,
+STORE, 140142786355200, 140142819926015,
+STORE, 140142299840512, 140142501167103,
+STORE, 140142777962496, 140142819926015,
+STORE, 140142559883264, 140142568275967,
+STORE, 140142232731648, 140142501167103,
+STORE, 140142551490560, 140142568275967,
+SNULL, 140142777962496, 140142803140607,
+STORE, 140142803140608, 140142819926015,
+STORE, 140142777962496, 140142803140607,
+SNULL, 140142803144703, 140142819926015,
+STORE, 140142803140608, 140142803144703,
+STORE, 140142803144704, 140142819926015,
+STORE, 140142543097856, 140142568275967,
+STORE, 140142098513920, 140142501167103,
+SNULL, 140142165622783, 140142501167103,
+STORE, 140142098513920, 140142165622783,
+STORE, 140142165622784, 140142501167103,
+SNULL, 140142165622784, 140142232731647,
+STORE, 140142232731648, 140142501167103,
+STORE, 140142165622784, 140142232731647,
+ERASE, 140142165622784, 140142232731647,
+SNULL, 140142568411135, 140142635384831,
+STORE, 140142568275968, 140142568411135,
+STORE, 140142568411136, 140142635384831,
+STORE, 140141964296192, 140142165622783,
+SNULL, 140142912180224, 140142928965631,
+STORE, 140142928965632, 140142962536447,
+STORE, 140142912180224, 140142928965631,
+SNULL, 140142928969727, 140142962536447,
+STORE, 140142928965632, 140142928969727,
+STORE, 140142928969728, 140142962536447,
+STORE, 140141830078464, 140142165622783,
+SNULL, 140142912184319, 140142928965631,
+STORE, 140142912180224, 140142912184319,
+STORE, 140142912184320, 140142928965631,
+SNULL, 140142232731648, 140142434058239,
+STORE, 140142434058240, 140142501167103,
+STORE, 140142232731648, 140142434058239,
+SNULL, 140142434193407, 140142501167103,
+STORE, 140142434058240, 140142434193407,
+STORE, 140142434193408, 140142501167103,
+SNULL, 140142232731648, 140142299840511,
+STORE, 140142299840512, 140142434058239,
+STORE, 140142232731648, 140142299840511,
+SNULL, 140142299975679, 140142434058239,
+STORE, 140142299840512, 140142299975679,
+STORE, 140142299975680, 140142434058239,
+SNULL, 140142928969728, 140142954143743,
+STORE, 140142954143744, 140142962536447,
+STORE, 140142928969728, 140142954143743,
+SNULL, 140142954147839, 140142962536447,
+STORE, 140142954143744, 140142954147839,
+STORE, 140142954147840, 140142962536447,
+STORE, 140141830078464, 140142299840511,
+SNULL, 140142543097856, 140142559883263,
+STORE, 140142559883264, 140142568275967,
+STORE, 140142543097856, 140142559883263,
+SNULL, 140142559887359, 140142568275967,
+STORE, 140142559883264, 140142559887359,
+STORE, 140142559887360, 140142568275967,
+STORE, 140142534705152, 140142559883263,
+SNULL, 140142928969728, 140142945751039,
+STORE, 140142945751040, 140142954143743,
+STORE, 140142928969728, 140142945751039,
+SNULL, 140142945755135, 140142954143743,
+STORE, 140142945751040, 140142945755135,
+STORE, 140142945755136, 140142954143743,
+SNULL, 140142299975680, 140142366949375,
+STORE, 140142366949376, 140142434058239,
+STORE, 140142299975680, 140142366949375,
+SNULL, 140142367084543, 140142434058239,
+STORE, 140142366949376, 140142367084543,
+STORE, 140142367084544, 140142434058239,
+SNULL, 140142928969728, 140142937358335,
+STORE, 140142937358336, 140142945751039,
+STORE, 140142928969728, 140142937358335,
+SNULL, 140142937362431, 140142945751039,
+STORE, 140142937358336, 140142937362431,
+STORE, 140142937362432, 140142945751039,
+SNULL, 140141830078464, 140142232731647,
+STORE, 140142232731648, 140142299840511,
+STORE, 140141830078464, 140142232731647,
+SNULL, 140142232866815, 140142299840511,
+STORE, 140142232731648, 140142232866815,
+STORE, 140142232866816, 140142299840511,
+SNULL, 140142534705152, 140142543097855,
+STORE, 140142543097856, 140142559883263,
+STORE, 140142534705152, 140142543097855,
+SNULL, 140142543101951, 140142559883263,
+STORE, 140142543097856, 140142543101951,
+STORE, 140142543101952, 140142559883263,
+STORE, 140142526312448, 140142543097855,
+STORE, 140142517919744, 140142543097855,
+SNULL, 140141830078464, 140142098513919,
+STORE, 140142098513920, 140142232731647,
+STORE, 140141830078464, 140142098513919,
+SNULL, 140142098649087, 140142232731647,
+STORE, 140142098513920, 140142098649087,
+STORE, 140142098649088, 140142232731647,
+SNULL, 140142031405055, 140142098513919,
+STORE, 140141830078464, 140142031405055,
+STORE, 140142031405056, 140142098513919,
+ERASE, 140142031405056, 140142098513919,
+SNULL, 140141830078464, 140141964296191,
+STORE, 140141964296192, 140142031405055,
+STORE, 140141830078464, 140141964296191,
+SNULL, 140141964431359, 140142031405055,
+STORE, 140141964296192, 140141964431359,
+STORE, 140141964431360, 140142031405055,
+STORE, 140142509527040, 140142543097855,
+SNULL, 140141897187327, 140141964296191,
+STORE, 140141830078464, 140141897187327,
+STORE, 140141897187328, 140141964296191,
+ERASE, 140141897187328, 140141964296191,
+SNULL, 140141830213631, 140141897187327,
+STORE, 140141830078464, 140141830213631,
+STORE, 140141830213632, 140141897187327,
+SNULL, 140142803144704, 140142811533311,
+STORE, 140142811533312, 140142819926015,
+STORE, 140142803144704, 140142811533311,
+SNULL, 140142811537407, 140142819926015,
+STORE, 140142811533312, 140142811537407,
+STORE, 140142811537408, 140142819926015,
+SNULL, 140142098649088, 140142165622783,
+STORE, 140142165622784, 140142232731647,
+STORE, 140142098649088, 140142165622783,
+SNULL, 140142165757951, 140142232731647,
+STORE, 140142165622784, 140142165757951,
+STORE, 140142165757952, 140142232731647,
+STORE, 140142090121216, 140142098513919,
+SNULL, 140142777962496, 140142786355199,
+STORE, 140142786355200, 140142803140607,
+STORE, 140142777962496, 140142786355199,
+SNULL, 140142786359295, 140142803140607,
+STORE, 140142786355200, 140142786359295,
+STORE, 140142786359296, 140142803140607,
+SNULL, 140142509527040, 140142534705151,
+STORE, 140142534705152, 140142543097855,
+STORE, 140142509527040, 140142534705151,
+SNULL, 140142534709247, 140142543097855,
+STORE, 140142534705152, 140142534709247,
+STORE, 140142534709248, 140142543097855,
+STORE, 140142081728512, 140142098513919,
+SNULL, 140142786359296, 140142794747903,
+STORE, 140142794747904, 140142803140607,
+STORE, 140142786359296, 140142794747903,
+SNULL, 140142794751999, 140142803140607,
+STORE, 140142794747904, 140142794751999,
+STORE, 140142794752000, 140142803140607,
+STORE, 140142073335808, 140142098513919,
+SNULL, 140142073339903, 140142098513919,
+STORE, 140142073335808, 140142073339903,
+STORE, 140142073339904, 140142098513919,
+SNULL, 140142543101952, 140142551490559,
+STORE, 140142551490560, 140142559883263,
+STORE, 140142543101952, 140142551490559,
+SNULL, 140142551494655, 140142559883263,
+STORE, 140142551490560, 140142551494655,
+STORE, 140142551494656, 140142559883263,
+SNULL, 140142509527040, 140142517919743,
+STORE, 140142517919744, 140142534705151,
+STORE, 140142509527040, 140142517919743,
+SNULL, 140142517923839, 140142534705151,
+STORE, 140142517919744, 140142517923839,
+STORE, 140142517923840, 140142534705151,
+STORE, 140142064943104, 140142073335807,
+SNULL, 140142073339904, 140142090121215,
+STORE, 140142090121216, 140142098513919,
+STORE, 140142073339904, 140142090121215,
+SNULL, 140142090125311, 140142098513919,
+STORE, 140142090121216, 140142090125311,
+STORE, 140142090125312, 140142098513919,
+STORE, 140142056550400, 140142073335807,
+SNULL, 140142056554495, 140142073335807,
+STORE, 140142056550400, 140142056554495,
+STORE, 140142056554496, 140142073335807,
+STORE, 140142048157696, 140142056550399,
+SNULL, 140142509531135, 140142517919743,
+STORE, 140142509527040, 140142509531135,
+STORE, 140142509531136, 140142517919743,
+SNULL, 140142777966591, 140142786355199,
+STORE, 140142777962496, 140142777966591,
+STORE, 140142777966592, 140142786355199,
+SNULL, 140143046402047, 140143054790655,
+STORE, 140143046397952, 140143046402047,
+STORE, 140143046402048, 140143054790655,
+SNULL, 140142912184320, 140142920572927,
+STORE, 140142920572928, 140142928965631,
+STORE, 140142912184320, 140142920572927,
+SNULL, 140142920577023, 140142928965631,
+STORE, 140142920572928, 140142920577023,
+STORE, 140142920577024, 140142928965631,
+STORE, 140142039764992, 140142056550399,
+STORE, 140141955903488, 140141964296191,
+SNULL, 140142819930112, 140142828318719,
+STORE, 140142828318720, 140142836711423,
+STORE, 140142819930112, 140142828318719,
+SNULL, 140142828322815, 140142836711423,
+STORE, 140142828318720, 140142828322815,
+STORE, 140142828322816, 140142836711423,
+SNULL, 140142517923840, 140142526312447,
+STORE, 140142526312448, 140142534705151,
+STORE, 140142517923840, 140142526312447,
+SNULL, 140142526316543, 140142534705151,
+STORE, 140142526312448, 140142526316543,
+STORE, 140142526316544, 140142534705151,
+STORE, 140141947510784, 140141964296191,
+SNULL, 140142056554496, 140142064943103,
+STORE, 140142064943104, 140142073335807,
+STORE, 140142056554496, 140142064943103,
+SNULL, 140142064947199, 140142073335807,
+STORE, 140142064943104, 140142064947199,
+STORE, 140142064947200, 140142073335807,
+SNULL, 140142073339904, 140142081728511,
+STORE, 140142081728512, 140142090121215,
+STORE, 140142073339904, 140142081728511,
+SNULL, 140142081732607, 140142090121215,
+STORE, 140142081728512, 140142081732607,
+STORE, 140142081732608, 140142090121215,
+STORE, 140141939118080, 140141964296191,
+STORE, 140141930725376, 140141964296191,
+STORE, 140141922332672, 140141964296191,
+STORE, 140141913939968, 140141964296191,
+SNULL, 140141913939968, 140141922332671,
+STORE, 140141922332672, 140141964296191,
+STORE, 140141913939968, 140141922332671,
+SNULL, 140141922336767, 140141964296191,
+STORE, 140141922332672, 140141922336767,
+STORE, 140141922336768, 140141964296191,
+STORE, 140141905547264, 140141922332671,
+SNULL, 140141905551359, 140141922332671,
+STORE, 140141905547264, 140141905551359,
+STORE, 140141905551360, 140141922332671,
+STORE, 140141821685760, 140141830078463,
+STORE, 140141813293056, 140141830078463,
+STORE, 140141804900352, 140141830078463,
+STORE, 140141796507648, 140141830078463,
+SNULL, 140141796511743, 140141830078463,
+STORE, 140141796507648, 140141796511743,
+STORE, 140141796511744, 140141830078463,
+SNULL, 140141922336768, 140141955903487,
+STORE, 140141955903488, 140141964296191,
+STORE, 140141922336768, 140141955903487,
+SNULL, 140141955907583, 140141964296191,
+STORE, 140141955903488, 140141955907583,
+STORE, 140141955907584, 140141964296191,
+STORE, 140141788114944, 140141796507647,
+STORE, 140141779722240, 140141796507647,
+SNULL, 140141779722240, 140141788114943,
+STORE, 140141788114944, 140141796507647,
+STORE, 140141779722240, 140141788114943,
+SNULL, 140141788119039, 140141796507647,
+STORE, 140141788114944, 140141788119039,
+STORE, 140141788119040, 140141796507647,
+SNULL, 140141922336768, 140141947510783,
+STORE, 140141947510784, 140141955903487,
+STORE, 140141922336768, 140141947510783,
+SNULL, 140141947514879, 140141955903487,
+STORE, 140141947510784, 140141947514879,
+STORE, 140141947514880, 140141955903487,
+SNULL, 140142039764992, 140142048157695,
+STORE, 140142048157696, 140142056550399,
+STORE, 140142039764992, 140142048157695,
+SNULL, 140142048161791, 140142056550399,
+STORE, 140142048157696, 140142048161791,
+STORE, 140142048161792, 140142056550399,
+SNULL, 140142039769087, 140142048157695,
+STORE, 140142039764992, 140142039769087,
+STORE, 140142039769088, 140142048157695,
+SNULL, 140141796511744, 140141804900351,
+STORE, 140141804900352, 140141830078463,
+STORE, 140141796511744, 140141804900351,
+SNULL, 140141804904447, 140141830078463,
+STORE, 140141804900352, 140141804904447,
+STORE, 140141804904448, 140141830078463,
+STORE, 140141771329536, 140141788114943,
+STORE, 140141762936832, 140141788114943,
+STORE, 140141754544128, 140141788114943,
+SNULL, 140141804904448, 140141821685759,
+STORE, 140141821685760, 140141830078463,
+STORE, 140141804904448, 140141821685759,
+SNULL, 140141821689855, 140141830078463,
+STORE, 140141821685760, 140141821689855,
+STORE, 140141821689856, 140141830078463,
+SNULL, 140141922336768, 140141939118079,
+STORE, 140141939118080, 140141947510783,
+STORE, 140141922336768, 140141939118079,
+SNULL, 140141939122175, 140141947510783,
+STORE, 140141939118080, 140141939122175,
+STORE, 140141939122176, 140141947510783,
+SNULL, 140141905551360, 140141913939967,
+STORE, 140141913939968, 140141922332671,
+STORE, 140141905551360, 140141913939967,
+SNULL, 140141913944063, 140141922332671,
+STORE, 140141913939968, 140141913944063,
+STORE, 140141913944064, 140141922332671,
+STORE, 140141746151424, 140141788114943,
+STORE, 140141737758720, 140141788114943,
+SNULL, 140141804904448, 140141813293055,
+STORE, 140141813293056, 140141821685759,
+STORE, 140141804904448, 140141813293055,
+SNULL, 140141813297151, 140141821685759,
+STORE, 140141813293056, 140141813297151,
+STORE, 140141813297152, 140141821685759,
+STORE, 140141729366016, 140141788114943,
+STORE, 140141720973312, 140141788114943,
+STORE, 140141712580608, 140141788114943,
+SNULL, 140141712584703, 140141788114943,
+STORE, 140141712580608, 140141712584703,
+STORE, 140141712584704, 140141788114943,
+SNULL, 140141922336768, 140141930725375,
+STORE, 140141930725376, 140141939118079,
+STORE, 140141922336768, 140141930725375,
+SNULL, 140141930729471, 140141939118079,
+STORE, 140141930725376, 140141930729471,
+STORE, 140141930729472, 140141939118079,
+STORE, 140141704187904, 140141712580607,
+SNULL, 140141704191999, 140141712580607,
+STORE, 140141704187904, 140141704191999,
+STORE, 140141704192000, 140141712580607,
+STORE, 140141695795200, 140141704187903,
+STORE, 140141687402496, 140141704187903,
+SNULL, 140141712584704, 140141771329535,
+STORE, 140141771329536, 140141788114943,
+STORE, 140141712584704, 140141771329535,
+SNULL, 140141771333631, 140141788114943,
+STORE, 140141771329536, 140141771333631,
+STORE, 140141771333632, 140141788114943,
+SNULL, 140141771333632, 140141779722239,
+STORE, 140141779722240, 140141788114943,
+STORE, 140141771333632, 140141779722239,
+SNULL, 140141779726335, 140141788114943,
+STORE, 140141779722240, 140141779726335,
+STORE, 140141779726336, 140141788114943,
+STORE, 140141679009792, 140141704187903,
+SNULL, 140141679013887, 140141704187903,
+STORE, 140141679009792, 140141679013887,
+STORE, 140141679013888, 140141704187903,
+STORE, 140141670617088, 140141679009791,
+SNULL, 140141670621183, 140141679009791,
+STORE, 140141670617088, 140141670621183,
+STORE, 140141670621184, 140141679009791,
+STORE, 140141662224384, 140141670617087,
+SNULL, 140141712584704, 140141737758719,
+STORE, 140141737758720, 140141771329535,
+STORE, 140141712584704, 140141737758719,
+SNULL, 140141737762815, 140141771329535,
+STORE, 140141737758720, 140141737762815,
+STORE, 140141737762816, 140141771329535,
+SNULL, 140141712584704, 140141729366015,
+STORE, 140141729366016, 140141737758719,
+STORE, 140141712584704, 140141729366015,
+SNULL, 140141729370111, 140141737758719,
+STORE, 140141729366016, 140141729370111,
+STORE, 140141729370112, 140141737758719,
+SNULL, 140141737762816, 140141746151423,
+STORE, 140141746151424, 140141771329535,
+STORE, 140141737762816, 140141746151423,
+SNULL, 140141746155519, 140141771329535,
+STORE, 140141746151424, 140141746155519,
+STORE, 140141746155520, 140141771329535,
+STORE, 140141653831680, 140141670617087,
+SNULL, 140141746155520, 140141762936831,
+STORE, 140141762936832, 140141771329535,
+STORE, 140141746155520, 140141762936831,
+SNULL, 140141762940927, 140141771329535,
+STORE, 140141762936832, 140141762940927,
+STORE, 140141762940928, 140141771329535,
+STORE, 140141645438976, 140141670617087,
+SNULL, 140141645443071, 140141670617087,
+STORE, 140141645438976, 140141645443071,
+STORE, 140141645443072, 140141670617087,
+SNULL, 140141712584704, 140141720973311,
+STORE, 140141720973312, 140141729366015,
+STORE, 140141712584704, 140141720973311,
+SNULL, 140141720977407, 140141729366015,
+STORE, 140141720973312, 140141720977407,
+STORE, 140141720977408, 140141729366015,
+STORE, 140141637046272, 140141645438975,
+SNULL, 140141637050367, 140141645438975,
+STORE, 140141637046272, 140141637050367,
+STORE, 140141637050368, 140141645438975,
+STORE, 140141628653568, 140141637046271,
+SNULL, 140141628657663, 140141637046271,
+STORE, 140141628653568, 140141628657663,
+STORE, 140141628657664, 140141637046271,
+STORE, 140141620260864, 140141628653567,
+SNULL, 140141679013888, 140141687402495,
+STORE, 140141687402496, 140141704187903,
+STORE, 140141679013888, 140141687402495,
+SNULL, 140141687406591, 140141704187903,
+STORE, 140141687402496, 140141687406591,
+STORE, 140141687406592, 140141704187903,
+SNULL, 140141746155520, 140141754544127,
+STORE, 140141754544128, 140141762936831,
+STORE, 140141746155520, 140141754544127,
+SNULL, 140141754548223, 140141762936831,
+STORE, 140141754544128, 140141754548223,
+STORE, 140141754548224, 140141762936831,
+SNULL, 140141687406592, 140141695795199,
+STORE, 140141695795200, 140141704187903,
+STORE, 140141687406592, 140141695795199,
+SNULL, 140141695799295, 140141704187903,
+STORE, 140141695795200, 140141695799295,
+STORE, 140141695799296, 140141704187903,
+STORE, 140141611868160, 140141628653567,
+SNULL, 140141611872255, 140141628653567,
+STORE, 140141611868160, 140141611872255,
+STORE, 140141611872256, 140141628653567,
+SNULL, 140141645443072, 140141662224383,
+STORE, 140141662224384, 140141670617087,
+STORE, 140141645443072, 140141662224383,
+SNULL, 140141662228479, 140141670617087,
+STORE, 140141662224384, 140141662228479,
+STORE, 140141662228480, 140141670617087,
+STORE, 140141603475456, 140141611868159,
+SNULL, 140141603479551, 140141611868159,
+STORE, 140141603475456, 140141603479551,
+STORE, 140141603479552, 140141611868159,
+STORE, 140141595082752, 140141603475455,
+SNULL, 140141645443072, 140141653831679,
+STORE, 140141653831680, 140141662224383,
+STORE, 140141645443072, 140141653831679,
+SNULL, 140141653835775, 140141662224383,
+STORE, 140141653831680, 140141653835775,
+STORE, 140141653835776, 140141662224383,
+STORE, 140141586690048, 140141603475455,
+SNULL, 140141611872256, 140141620260863,
+STORE, 140141620260864, 140141628653567,
+STORE, 140141611872256, 140141620260863,
+SNULL, 140141620264959, 140141628653567,
+STORE, 140141620260864, 140141620264959,
+STORE, 140141620264960, 140141628653567,
+SNULL, 140141586690048, 140141595082751,
+STORE, 140141595082752, 140141603475455,
+STORE, 140141586690048, 140141595082751,
+SNULL, 140141595086847, 140141603475455,
+STORE, 140141595082752, 140141595086847,
+STORE, 140141595086848, 140141603475455,
+STORE, 140141578297344, 140141595082751,
+SNULL, 140141578301439, 140141595082751,
+STORE, 140141578297344, 140141578301439,
+STORE, 140141578301440, 140141595082751,
+SNULL, 140141578301440, 140141586690047,
+STORE, 140141586690048, 140141595082751,
+STORE, 140141578301440, 140141586690047,
+SNULL, 140141586694143, 140141595082751,
+STORE, 140141586690048, 140141586694143,
+STORE, 140141586694144, 140141595082751,
+STORE, 140143370027008, 140143370055679,
+STORE, 140143309254656, 140143311446015,
+SNULL, 140143309254656, 140143309344767,
+STORE, 140143309344768, 140143311446015,
+STORE, 140143309254656, 140143309344767,
+SNULL, 140143311437823, 140143311446015,
+STORE, 140143309344768, 140143311437823,
+STORE, 140143311437824, 140143311446015,
+ERASE, 140143311437824, 140143311446015,
+STORE, 140143311437824, 140143311446015,
+SNULL, 140143311441919, 140143311446015,
+STORE, 140143311437824, 140143311441919,
+STORE, 140143311441920, 140143311446015,
+ERASE, 140143370027008, 140143370055679,
+ERASE, 140142912180224, 140142912184319,
+ERASE, 140142912184320, 140142920572927,
+ERASE, 140142945751040, 140142945755135,
+ERASE, 140142945755136, 140142954143743,
+ERASE, 140142090121216, 140142090125311,
+ERASE, 140142090125312, 140142098513919,
+ERASE, 140142794747904, 140142794751999,
+ERASE, 140142794752000, 140142803140607,
+ERASE, 140141913939968, 140141913944063,
+ERASE, 140141913944064, 140141922332671,
+ERASE, 140141746151424, 140141746155519,
+ERASE, 140141746155520, 140141754544127,
+ERASE, 140142954143744, 140142954147839,
+ERASE, 140142954147840, 140142962536447,
+ERASE, 140142081728512, 140142081732607,
+ERASE, 140142081732608, 140142090121215,
+ERASE, 140141905547264, 140141905551359,
+ERASE, 140141905551360, 140141913939967,
+ERASE, 140141729366016, 140141729370111,
+ERASE, 140141729370112, 140141737758719,
+ERASE, 140142920572928, 140142920577023,
+ERASE, 140142920577024, 140142928965631,
+ERASE, 140142039764992, 140142039769087,
+ERASE, 140142039769088, 140142048157695,
+ERASE, 140141679009792, 140141679013887,
+ERASE, 140141679013888, 140141687402495,
+ERASE, 140142551490560, 140142551494655,
+ERASE, 140142551494656, 140142559883263,
+ERASE, 140141947510784, 140141947514879,
+ERASE, 140141947514880, 140141955903487,
+ERASE, 140141771329536, 140141771333631,
+ERASE, 140141771333632, 140141779722239,
+ERASE, 140142928965632, 140142928969727,
+ERASE, 140142928969728, 140142937358335,
+ERASE, 140142073335808, 140142073339903,
+ERASE, 140142073339904, 140142081728511,
+ERASE, 140142543097856, 140142543101951,
+ERASE, 140142543101952, 140142551490559,
+ERASE, 140141955903488, 140141955907583,
+ERASE, 140141955907584, 140141964296191,
+ERASE, 140141704187904, 140141704191999,
+ERASE, 140141704192000, 140141712580607,
+ERASE, 140142786355200, 140142786359295,
+ERASE, 140142786359296, 140142794747903,
+ERASE, 140142056550400, 140142056554495,
+ERASE, 140142056554496, 140142064943103,
+ERASE, 140142828318720, 140142828322815,
+ERASE, 140142828322816, 140142836711423,
+ERASE, 140141788114944, 140141788119039,
+ERASE, 140141788119040, 140141796507647,
+ERASE, 140141695795200, 140141695799295,
+ERASE, 140141695799296, 140141704187903,
+ERASE, 140141578297344, 140141578301439,
+ERASE, 140141578301440, 140141586690047,
+ERASE, 140141611868160, 140141611872255,
+ERASE, 140141611872256, 140141620260863,
+ERASE, 140142811533312, 140142811537407,
+ERASE, 140142811537408, 140142819926015,
+ERASE, 140142064943104, 140142064947199,
+ERASE, 140142064947200, 140142073335807,
+ERASE, 140141628653568, 140141628657663,
+ERASE, 140141628657664, 140141637046271,
+ERASE, 140143046397952, 140143046402047,
+ERASE, 140143046402048, 140143054790655,
+ERASE, 140141796507648, 140141796511743,
+ERASE, 140141796511744, 140141804900351,
+ERASE, 140142803140608, 140142803144703,
+ERASE, 140142803144704, 140142811533311,
+ERASE, 140142509527040, 140142509531135,
+ERASE, 140142509531136, 140142517919743,
+ERASE, 140141821685760, 140141821689855,
+ERASE, 140141821689856, 140141830078463,
+ERASE, 140142777962496, 140142777966591,
+ERASE, 140142777966592, 140142786355199,
+ERASE, 140141804900352, 140141804904447,
+ERASE, 140141804904448, 140141813293055,
+ERASE, 140141930725376, 140141930729471,
+ERASE, 140141930729472, 140141939118079,
+ERASE, 140142937358336, 140142937362431,
+ERASE, 140142937362432, 140142945751039,
+ERASE, 140142559883264, 140142559887359,
+ERASE, 140142559887360, 140142568275967,
+ERASE, 140142534705152, 140142534709247,
+ERASE, 140142534709248, 140142543097855,
+ERASE, 140142048157696, 140142048161791,
+ERASE, 140142048161792, 140142056550399,
+ERASE, 140141754544128, 140141754548223,
+ERASE, 140141754548224, 140141762936831,
+ERASE, 140141939118080, 140141939122175,
+ERASE, 140141939122176, 140141947510783,
+ERASE, 140141653831680, 140141653835775,
+ERASE, 140141653835776, 140141662224383,
+ERASE, 140141712580608, 140141712584703,
+ERASE, 140141712584704, 140141720973311,
+ERASE, 140141645438976, 140141645443071,
+ERASE, 140141645443072, 140141653831679,
+ERASE, 140141687402496, 140141687406591,
+ERASE, 140141687406592, 140141695795199,
+ERASE, 140141662224384, 140141662228479,
+ERASE, 140141662228480, 140141670617087,
+ERASE, 140141922332672, 140141922336767,
+ERASE, 140141922336768, 140141930725375,
+ERASE, 140141737758720, 140141737762815,
+ERASE, 140141737762816, 140141746151423,
+ERASE, 140141637046272, 140141637050367,
+ERASE, 140141637050368, 140141645438975,
+ERASE, 140142517919744, 140142517923839,
+ERASE, 140142517923840, 140142526312447,
+ERASE, 140143096754176, 140143096758271,
+ERASE, 140143096758272, 140143105146879,
+ERASE, 140141595082752, 140141595086847,
+ERASE, 140141595086848, 140141603475455,
+ERASE, 140141762936832, 140141762940927,
+ERASE, 140141762940928, 140141771329535,
+ERASE, 140143311446016, 140143311450111,
+ERASE, 140143311450112, 140143319838719,
+ERASE, 140142526312448, 140142526316543,
+ERASE, 140142526316544, 140142534705151,
+ERASE, 140142819926016, 140142819930111,
+ERASE, 140142819930112, 140142828318719,
+ERASE, 140143180615680, 140143180619775,
+ERASE, 140143180619776, 140143189008383,
+ERASE, 140142962536448, 140142962540543,
+ERASE, 140142962540544, 140142970929151,
+ERASE, 140143214186496, 140143214190591,
+ERASE, 140143214190592, 140143222579199,
+ERASE, 140143088361472, 140143088365567,
+ERASE, 140143088365568, 140143096754175,
+ERASE, 140141586690048, 140141586694143,
+ERASE, 140141586694144, 140141595082751,
+ERASE, 140143230971904, 140143230975999,
+ERASE, 140143230976000, 140143239364607,
+ERASE, 140141779722240, 140141779726335,
+ERASE, 140141779726336, 140141788114943,
+ERASE, 140141670617088, 140141670621183,
+ERASE, 140141670621184, 140141679009791,
+ERASE, 140141813293056, 140141813297151,
+ERASE, 140141813297152, 140141821685759,
+ERASE, 140143222579200, 140143222583295,
+ERASE, 140143222583296, 140143230971903,
+ERASE, 140143189008384, 140143189012479,
+ERASE, 140143189012480, 140143197401087,
+ERASE, 140143071576064, 140143071580159,
+ERASE, 140143071580160, 140143079968767,
+ERASE, 140141620260864, 140141620264959,
+ERASE, 140141620264960, 140141628653567,
+ERASE, 140141603475456, 140141603479551,
+ERASE, 140141603479552, 140141611868159,
+ERASE, 140141720973312, 140141720977407,
+ERASE, 140141720977408, 140141729366015,
+ERASE, 140143079968768, 140143079972863,
+ERASE, 140143079972864, 140143088361471,
+ERASE, 140143205793792, 140143205797887,
+ERASE, 140143205797888, 140143214186495,
+ };
+ unsigned long set30[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140733436743680, 140737488351231,
+SNULL, 140733436747775, 140737488351231,
+STORE, 140733436743680, 140733436747775,
+STORE, 140733436612608, 140733436747775,
+STORE, 94630728904704, 94630731157503,
+SNULL, 94630729035775, 94630731157503,
+STORE, 94630728904704, 94630729035775,
+STORE, 94630729035776, 94630731157503,
+ERASE, 94630729035776, 94630731157503,
+STORE, 94630731128832, 94630731137023,
+STORE, 94630731137024, 94630731157503,
+STORE, 140165750841344, 140165753094143,
+SNULL, 140165750984703, 140165753094143,
+STORE, 140165750841344, 140165750984703,
+STORE, 140165750984704, 140165753094143,
+ERASE, 140165750984704, 140165753094143,
+STORE, 140165753081856, 140165753090047,
+STORE, 140165753090048, 140165753094143,
+STORE, 140733436887040, 140733436891135,
+STORE, 140733436874752, 140733436887039,
+STORE, 140165753053184, 140165753081855,
+STORE, 140165753044992, 140165753053183,
+STORE, 140165748625408, 140165750841343,
+SNULL, 140165748625408, 140165748723711,
+STORE, 140165748723712, 140165750841343,
+STORE, 140165748625408, 140165748723711,
+SNULL, 140165750816767, 140165750841343,
+STORE, 140165748723712, 140165750816767,
+STORE, 140165750816768, 140165750841343,
+SNULL, 140165750816768, 140165750824959,
+STORE, 140165750824960, 140165750841343,
+STORE, 140165750816768, 140165750824959,
+ERASE, 140165750816768, 140165750824959,
+STORE, 140165750816768, 140165750824959,
+ERASE, 140165750824960, 140165750841343,
+STORE, 140165750824960, 140165750841343,
+STORE, 140165744828416, 140165748625407,
+SNULL, 140165744828416, 140165746487295,
+STORE, 140165746487296, 140165748625407,
+STORE, 140165744828416, 140165746487295,
+SNULL, 140165748584447, 140165748625407,
+STORE, 140165746487296, 140165748584447,
+STORE, 140165748584448, 140165748625407,
+SNULL, 140165748584448, 140165748609023,
+STORE, 140165748609024, 140165748625407,
+STORE, 140165748584448, 140165748609023,
+ERASE, 140165748584448, 140165748609023,
+STORE, 140165748584448, 140165748609023,
+ERASE, 140165748609024, 140165748625407,
+STORE, 140165748609024, 140165748625407,
+STORE, 140165753036800, 140165753053183,
+SNULL, 140165748600831, 140165748609023,
+STORE, 140165748584448, 140165748600831,
+STORE, 140165748600832, 140165748609023,
+SNULL, 140165750820863, 140165750824959,
+STORE, 140165750816768, 140165750820863,
+STORE, 140165750820864, 140165750824959,
+SNULL, 94630731132927, 94630731137023,
+STORE, 94630731128832, 94630731132927,
+STORE, 94630731132928, 94630731137023,
+SNULL, 140165753085951, 140165753090047,
+STORE, 140165753081856, 140165753085951,
+STORE, 140165753085952, 140165753090047,
+ERASE, 140165753053184, 140165753081855,
+STORE, 94630743547904, 94630743683071,
+STORE, 140165736435712, 140165744828415,
+SNULL, 140165736439807, 140165744828415,
+STORE, 140165736435712, 140165736439807,
+STORE, 140165736439808, 140165744828415,
+STORE, 140165728043008, 140165736435711,
+STORE, 140165593825280, 140165728043007,
+SNULL, 140165593825280, 140165653725183,
+STORE, 140165653725184, 140165728043007,
+STORE, 140165593825280, 140165653725183,
+ERASE, 140165593825280, 140165653725183,
+SNULL, 140165720834047, 140165728043007,
+STORE, 140165653725184, 140165720834047,
+STORE, 140165720834048, 140165728043007,
+ERASE, 140165720834048, 140165728043007,
+SNULL, 140165653860351, 140165720834047,
+STORE, 140165653725184, 140165653860351,
+STORE, 140165653860352, 140165720834047,
+SNULL, 140165728047103, 140165736435711,
+STORE, 140165728043008, 140165728047103,
+STORE, 140165728047104, 140165736435711,
+STORE, 140165645332480, 140165653725183,
+SNULL, 140165645336575, 140165653725183,
+STORE, 140165645332480, 140165645336575,
+STORE, 140165645336576, 140165653725183,
+STORE, 140165636939776, 140165645332479,
+SNULL, 140165636943871, 140165645332479,
+STORE, 140165636939776, 140165636943871,
+STORE, 140165636943872, 140165645332479,
+STORE, 140165628547072, 140165636939775,
+SNULL, 140165628551167, 140165636939775,
+STORE, 140165628547072, 140165628551167,
+STORE, 140165628551168, 140165636939775,
+STORE, 140165620154368, 140165628547071,
+STORE, 140165611761664, 140165628547071,
+STORE, 140165603368960, 140165628547071,
+STORE, 140165469151232, 140165603368959,
+SNULL, 140165469151232, 140165519507455,
+STORE, 140165519507456, 140165603368959,
+STORE, 140165469151232, 140165519507455,
+ERASE, 140165469151232, 140165519507455,
+SNULL, 140165586616319, 140165603368959,
+STORE, 140165519507456, 140165586616319,
+STORE, 140165586616320, 140165603368959,
+ERASE, 140165586616320, 140165603368959,
+STORE, 140165594976256, 140165628547071,
+STORE, 140165385289728, 140165586616319,
+SNULL, 140165452398591, 140165586616319,
+STORE, 140165385289728, 140165452398591,
+STORE, 140165452398592, 140165586616319,
+SNULL, 140165452398592, 140165519507455,
+STORE, 140165519507456, 140165586616319,
+STORE, 140165452398592, 140165519507455,
+ERASE, 140165452398592, 140165519507455,
+STORE, 140165251072000, 140165452398591,
+SNULL, 140165318180863, 140165452398591,
+STORE, 140165251072000, 140165318180863,
+STORE, 140165318180864, 140165452398591,
+SNULL, 140165318180864, 140165385289727,
+STORE, 140165385289728, 140165452398591,
+STORE, 140165318180864, 140165385289727,
+ERASE, 140165318180864, 140165385289727,
+SNULL, 140165519642623, 140165586616319,
+STORE, 140165519507456, 140165519642623,
+STORE, 140165519642624, 140165586616319,
+SNULL, 140165594976256, 140165611761663,
+STORE, 140165611761664, 140165628547071,
+STORE, 140165594976256, 140165611761663,
+SNULL, 140165611765759, 140165628547071,
+STORE, 140165611761664, 140165611765759,
+STORE, 140165611765760, 140165628547071,
+STORE, 140165385289728, 140165519507455,
+SNULL, 140165385424895, 140165519507455,
+STORE, 140165385289728, 140165385424895,
+STORE, 140165385424896, 140165519507455,
+SNULL, 140165594976256, 140165603368959,
+STORE, 140165603368960, 140165611761663,
+STORE, 140165594976256, 140165603368959,
+SNULL, 140165603373055, 140165611761663,
+STORE, 140165603368960, 140165603373055,
+STORE, 140165603373056, 140165611761663,
+SNULL, 140165251207167, 140165318180863,
+STORE, 140165251072000, 140165251207167,
+STORE, 140165251207168, 140165318180863,
+STORE, 140165376897024, 140165385289727,
+SNULL, 140165376901119, 140165385289727,
+STORE, 140165376897024, 140165376901119,
+STORE, 140165376901120, 140165385289727,
+SNULL, 140165385424896, 140165452398591,
+STORE, 140165452398592, 140165519507455,
+STORE, 140165385424896, 140165452398591,
+SNULL, 140165452533759, 140165519507455,
+STORE, 140165452398592, 140165452533759,
+STORE, 140165452533760, 140165519507455,
+STORE, 140165368504320, 140165376897023,
+SNULL, 140165594980351, 140165603368959,
+STORE, 140165594976256, 140165594980351,
+STORE, 140165594980352, 140165603368959,
+SNULL, 140165368508415, 140165376897023,
+STORE, 140165368504320, 140165368508415,
+STORE, 140165368508416, 140165376897023,
+SNULL, 140165611765760, 140165620154367,
+STORE, 140165620154368, 140165628547071,
+STORE, 140165611765760, 140165620154367,
+SNULL, 140165620158463, 140165628547071,
+STORE, 140165620154368, 140165620158463,
+STORE, 140165620158464, 140165628547071,
+STORE, 140165360111616, 140165368504319,
+STORE, 140165351718912, 140165368504319,
+STORE, 140165343326208, 140165368504319,
+SNULL, 140165343326208, 140165351718911,
+STORE, 140165351718912, 140165368504319,
+STORE, 140165343326208, 140165351718911,
+SNULL, 140165351723007, 140165368504319,
+STORE, 140165351718912, 140165351723007,
+STORE, 140165351723008, 140165368504319,
+SNULL, 140165343330303, 140165351718911,
+STORE, 140165343326208, 140165343330303,
+STORE, 140165343330304, 140165351718911,
+SNULL, 140165351723008, 140165360111615,
+STORE, 140165360111616, 140165368504319,
+STORE, 140165351723008, 140165360111615,
+SNULL, 140165360115711, 140165368504319,
+STORE, 140165360111616, 140165360115711,
+STORE, 140165360115712, 140165368504319,
+STORE, 140165334933504, 140165343326207,
+SNULL, 140165334937599, 140165343326207,
+STORE, 140165334933504, 140165334937599,
+STORE, 140165334937600, 140165343326207,
+STORE, 140165326540800, 140165334933503,
+STORE, 140165242679296, 140165251071999,
+SNULL, 140165242683391, 140165251071999,
+STORE, 140165242679296, 140165242683391,
+STORE, 140165242683392, 140165251071999,
+STORE, 140165234286592, 140165242679295,
+STORE, 140165225893888, 140165242679295,
+SNULL, 140165225897983, 140165242679295,
+STORE, 140165225893888, 140165225897983,
+STORE, 140165225897984, 140165242679295,
+SNULL, 140165225897984, 140165234286591,
+STORE, 140165234286592, 140165242679295,
+STORE, 140165225897984, 140165234286591,
+SNULL, 140165234290687, 140165242679295,
+STORE, 140165234286592, 140165234290687,
+STORE, 140165234290688, 140165242679295,
+SNULL, 140165326544895, 140165334933503,
+STORE, 140165326540800, 140165326544895,
+STORE, 140165326544896, 140165334933503,
+STORE, 140165217501184, 140165225893887,
+STORE, 140165209108480, 140165225893887,
+SNULL, 140165209108480, 140165217501183,
+STORE, 140165217501184, 140165225893887,
+STORE, 140165209108480, 140165217501183,
+SNULL, 140165217505279, 140165225893887,
+STORE, 140165217501184, 140165217505279,
+STORE, 140165217505280, 140165225893887,
+SNULL, 140165209112575, 140165217501183,
+STORE, 140165209108480, 140165209112575,
+STORE, 140165209112576, 140165217501183,
+STORE, 140165200715776, 140165209108479,
+STORE, 140165066498048, 140165200715775,
+SNULL, 140165066498048, 140165116854271,
+STORE, 140165116854272, 140165200715775,
+STORE, 140165066498048, 140165116854271,
+ERASE, 140165066498048, 140165116854271,
+SNULL, 140165183963135, 140165200715775,
+STORE, 140165116854272, 140165183963135,
+STORE, 140165183963136, 140165200715775,
+ERASE, 140165183963136, 140165200715775,
+SNULL, 140165116989439, 140165183963135,
+STORE, 140165116854272, 140165116989439,
+STORE, 140165116989440, 140165183963135,
+STORE, 140165192323072, 140165209108479,
+STORE, 140165108461568, 140165116854271,
+STORE, 140164974243840, 140165108461567,
+STORE, 140164965851136, 140164974243839,
+SNULL, 140164974243840, 140164982636543,
+STORE, 140164982636544, 140165108461567,
+STORE, 140164974243840, 140164982636543,
+ERASE, 140164974243840, 140164982636543,
+STORE, 140164965851136, 140164982636543,
+STORE, 140164957458432, 140164982636543,
+STORE, 140164949065728, 140164982636543,
+STORE, 140164940673024, 140164982636543,
+STORE, 140164806455296, 140164940673023,
+STORE, 140164798062592, 140164806455295,
+STORE, 140164789669888, 140164806455295,
+STORE, 140164655452160, 140164789669887,
+STORE, 140164647059456, 140164655452159,
+STORE, 140164638666752, 140164655452159,
+SNULL, 140164655452160, 140164714201087,
+STORE, 140164714201088, 140164789669887,
+STORE, 140164655452160, 140164714201087,
+ERASE, 140164655452160, 140164714201087,
+STORE, 140164705808384, 140164714201087,
+STORE, 140164697415680, 140164714201087,
+STORE, 140164504449024, 140164638666751,
+SNULL, 140164504449024, 140164512874495,
+STORE, 140164512874496, 140164638666751,
+STORE, 140164504449024, 140164512874495,
+ERASE, 140164504449024, 140164512874495,
+STORE, 140164689022976, 140164714201087,
+STORE, 140164680630272, 140164714201087,
+SNULL, 140164680634367, 140164714201087,
+STORE, 140164680630272, 140164680634367,
+STORE, 140164680634368, 140164714201087,
+STORE, 140164378656768, 140164638666751,
+SNULL, 140165192323072, 140165200715775,
+STORE, 140165200715776, 140165209108479,
+STORE, 140165192323072, 140165200715775,
+SNULL, 140165200719871, 140165209108479,
+STORE, 140165200715776, 140165200719871,
+STORE, 140165200719872, 140165209108479,
+SNULL, 140165049745407, 140165108461567,
+STORE, 140164982636544, 140165049745407,
+STORE, 140165049745408, 140165108461567,
+ERASE, 140165049745408, 140165108461567,
+SNULL, 140164982771711, 140165049745407,
+STORE, 140164982636544, 140164982771711,
+STORE, 140164982771712, 140165049745407,
+STORE, 140164244439040, 140164638666751,
+SNULL, 140164311547903, 140164638666751,
+STORE, 140164244439040, 140164311547903,
+STORE, 140164311547904, 140164638666751,
+SNULL, 140164311547904, 140164378656767,
+STORE, 140164378656768, 140164638666751,
+STORE, 140164311547904, 140164378656767,
+ERASE, 140164311547904, 140164378656767,
+SNULL, 140164806455296, 140164848418815,
+STORE, 140164848418816, 140164940673023,
+STORE, 140164806455296, 140164848418815,
+ERASE, 140164806455296, 140164848418815,
+SNULL, 140164915527679, 140164940673023,
+STORE, 140164848418816, 140164915527679,
+STORE, 140164915527680, 140164940673023,
+ERASE, 140164915527680, 140164940673023,
+STORE, 140164110221312, 140164311547903,
+SNULL, 140164177330175, 140164311547903,
+STORE, 140164110221312, 140164177330175,
+STORE, 140164177330176, 140164311547903,
+SNULL, 140164177330176, 140164244439039,
+STORE, 140164244439040, 140164311547903,
+STORE, 140164177330176, 140164244439039,
+ERASE, 140164177330176, 140164244439039,
+SNULL, 140164781309951, 140164789669887,
+STORE, 140164714201088, 140164781309951,
+STORE, 140164781309952, 140164789669887,
+ERASE, 140164781309952, 140164789669887,
+STORE, 140163976003584, 140164177330175,
+SNULL, 140164043112447, 140164177330175,
+STORE, 140163976003584, 140164043112447,
+STORE, 140164043112448, 140164177330175,
+SNULL, 140164043112448, 140164110221311,
+STORE, 140164110221312, 140164177330175,
+STORE, 140164043112448, 140164110221311,
+ERASE, 140164043112448, 140164110221311,
+SNULL, 140164579983359, 140164638666751,
+STORE, 140164378656768, 140164579983359,
+STORE, 140164579983360, 140164638666751,
+ERASE, 140164579983360, 140164638666751,
+STORE, 140163841785856, 140164043112447,
+SNULL, 140163908894719, 140164043112447,
+STORE, 140163841785856, 140163908894719,
+STORE, 140163908894720, 140164043112447,
+SNULL, 140163908894720, 140163976003583,
+STORE, 140163976003584, 140164043112447,
+STORE, 140163908894720, 140163976003583,
+ERASE, 140163908894720, 140163976003583,
+SNULL, 140164940673024, 140164965851135,
+STORE, 140164965851136, 140164982636543,
+STORE, 140164940673024, 140164965851135,
+SNULL, 140164965855231, 140164982636543,
+STORE, 140164965851136, 140164965855231,
+STORE, 140164965855232, 140164982636543,
+SNULL, 140164965855232, 140164974243839,
+STORE, 140164974243840, 140164982636543,
+STORE, 140164965855232, 140164974243839,
+SNULL, 140164974247935, 140164982636543,
+STORE, 140164974243840, 140164974247935,
+STORE, 140164974247936, 140164982636543,
+SNULL, 140164445765631, 140164579983359,
+STORE, 140164378656768, 140164445765631,
+STORE, 140164445765632, 140164579983359,
+SNULL, 140164445765632, 140164512874495,
+STORE, 140164512874496, 140164579983359,
+STORE, 140164445765632, 140164512874495,
+ERASE, 140164445765632, 140164512874495,
+SNULL, 140164378791935, 140164445765631,
+STORE, 140164378656768, 140164378791935,
+STORE, 140164378791936, 140164445765631,
+SNULL, 140164789673983, 140164806455295,
+STORE, 140164789669888, 140164789673983,
+STORE, 140164789673984, 140164806455295,
+SNULL, 140164789673984, 140164798062591,
+STORE, 140164798062592, 140164806455295,
+STORE, 140164789673984, 140164798062591,
+SNULL, 140164798066687, 140164806455295,
+STORE, 140164798062592, 140164798066687,
+STORE, 140164798066688, 140164806455295,
+SNULL, 140164638670847, 140164655452159,
+STORE, 140164638666752, 140164638670847,
+STORE, 140164638670848, 140164655452159,
+STORE, 140165100068864, 140165116854271,
+STORE, 140165091676160, 140165116854271,
+STORE, 140165083283456, 140165116854271,
+SNULL, 140164244574207, 140164311547903,
+STORE, 140164244439040, 140164244574207,
+STORE, 140164244574208, 140164311547903,
+SNULL, 140164848553983, 140164915527679,
+STORE, 140164848418816, 140164848553983,
+STORE, 140164848553984, 140164915527679,
+SNULL, 140164110356479, 140164177330175,
+STORE, 140164110221312, 140164110356479,
+STORE, 140164110356480, 140164177330175,
+SNULL, 140164714336255, 140164781309951,
+STORE, 140164714201088, 140164714336255,
+STORE, 140164714336256, 140164781309951,
+SNULL, 140163976138751, 140164043112447,
+STORE, 140163976003584, 140163976138751,
+STORE, 140163976138752, 140164043112447,
+SNULL, 140164513009663, 140164579983359,
+STORE, 140164512874496, 140164513009663,
+STORE, 140164513009664, 140164579983359,
+SNULL, 140163841921023, 140163908894719,
+STORE, 140163841785856, 140163841921023,
+STORE, 140163841921024, 140163908894719,
+SNULL, 140165083283456, 140165100068863,
+STORE, 140165100068864, 140165116854271,
+STORE, 140165083283456, 140165100068863,
+SNULL, 140165100072959, 140165116854271,
+STORE, 140165100068864, 140165100072959,
+STORE, 140165100072960, 140165116854271,
+SNULL, 140165100072960, 140165108461567,
+STORE, 140165108461568, 140165116854271,
+STORE, 140165100072960, 140165108461567,
+SNULL, 140165108465663, 140165116854271,
+STORE, 140165108461568, 140165108465663,
+STORE, 140165108465664, 140165116854271,
+STORE, 140165074890752, 140165100068863,
+SNULL, 140165074894847, 140165100068863,
+STORE, 140165074890752, 140165074894847,
+STORE, 140165074894848, 140165100068863,
+STORE, 140165066498048, 140165074890751,
+STORE, 140165058105344, 140165074890751,
+STORE, 140164932280320, 140164965851135,
+SNULL, 140165192327167, 140165200715775,
+STORE, 140165192323072, 140165192327167,
+STORE, 140165192327168, 140165200715775,
+STORE, 140164923887616, 140164965851135,
+SNULL, 140164923891711, 140164965851135,
+STORE, 140164923887616, 140164923891711,
+STORE, 140164923891712, 140164965851135,
+SNULL, 140164680634368, 140164705808383,
+STORE, 140164705808384, 140164714201087,
+STORE, 140164680634368, 140164705808383,
+SNULL, 140164705812479, 140164714201087,
+STORE, 140164705808384, 140164705812479,
+STORE, 140164705812480, 140164714201087,
+SNULL, 140164680634368, 140164697415679,
+STORE, 140164697415680, 140164705808383,
+STORE, 140164680634368, 140164697415679,
+SNULL, 140164697419775, 140164705808383,
+STORE, 140164697415680, 140164697419775,
+STORE, 140164697419776, 140164705808383,
+STORE, 140164840026112, 140164848418815,
+STORE, 140164831633408, 140164848418815,
+STORE, 140164823240704, 140164848418815,
+SNULL, 140165074894848, 140165083283455,
+STORE, 140165083283456, 140165100068863,
+STORE, 140165074894848, 140165083283455,
+SNULL, 140165083287551, 140165100068863,
+STORE, 140165083283456, 140165083287551,
+STORE, 140165083287552, 140165100068863,
+SNULL, 140165083287552, 140165091676159,
+STORE, 140165091676160, 140165100068863,
+STORE, 140165083287552, 140165091676159,
+SNULL, 140165091680255, 140165100068863,
+STORE, 140165091676160, 140165091680255,
+STORE, 140165091680256, 140165100068863,
+SNULL, 140164638670848, 140164647059455,
+STORE, 140164647059456, 140164655452159,
+STORE, 140164638670848, 140164647059455,
+SNULL, 140164647063551, 140164655452159,
+STORE, 140164647059456, 140164647063551,
+STORE, 140164647063552, 140164655452159,
+SNULL, 140164923891712, 140164940673023,
+STORE, 140164940673024, 140164965851135,
+STORE, 140164923891712, 140164940673023,
+SNULL, 140164940677119, 140164965851135,
+STORE, 140164940673024, 140164940677119,
+STORE, 140164940677120, 140164965851135,
+SNULL, 140164940677120, 140164949065727,
+STORE, 140164949065728, 140164965851135,
+STORE, 140164940677120, 140164949065727,
+SNULL, 140164949069823, 140164965851135,
+STORE, 140164949065728, 140164949069823,
+STORE, 140164949069824, 140164965851135,
+SNULL, 140164949069824, 140164957458431,
+STORE, 140164957458432, 140164965851135,
+STORE, 140164949069824, 140164957458431,
+SNULL, 140164957462527, 140164965851135,
+STORE, 140164957458432, 140164957462527,
+STORE, 140164957462528, 140164965851135,
+SNULL, 140164680634368, 140164689022975,
+STORE, 140164689022976, 140164697415679,
+STORE, 140164680634368, 140164689022975,
+SNULL, 140164689027071, 140164697415679,
+STORE, 140164689022976, 140164689027071,
+STORE, 140164689027072, 140164697415679,
+STORE, 140164814848000, 140164848418815,
+SNULL, 140165058105344, 140165066498047,
+STORE, 140165066498048, 140165074890751,
+STORE, 140165058105344, 140165066498047,
+SNULL, 140165066502143, 140165074890751,
+STORE, 140165066498048, 140165066502143,
+STORE, 140165066502144, 140165074890751,
+SNULL, 140165058109439, 140165066498047,
+STORE, 140165058105344, 140165058109439,
+STORE, 140165058109440, 140165066498047,
+STORE, 140164798066688, 140164814847999,
+SNULL, 140164798066688, 140164806455295,
+STORE, 140164806455296, 140164814847999,
+STORE, 140164798066688, 140164806455295,
+SNULL, 140164806459391, 140164814847999,
+STORE, 140164806455296, 140164806459391,
+STORE, 140164806459392, 140164814847999,
+SNULL, 140164923891712, 140164932280319,
+STORE, 140164932280320, 140164940673023,
+STORE, 140164923891712, 140164932280319,
+SNULL, 140164932284415, 140164940673023,
+STORE, 140164932280320, 140164932284415,
+STORE, 140164932284416, 140164940673023,
+STORE, 140164672237568, 140164680630271,
+STORE, 140164663844864, 140164680630271,
+STORE, 140164647063552, 140164680630271,
+SNULL, 140164647063552, 140164655452159,
+STORE, 140164655452160, 140164680630271,
+STORE, 140164647063552, 140164655452159,
+SNULL, 140164655456255, 140164680630271,
+STORE, 140164655452160, 140164655456255,
+STORE, 140164655456256, 140164680630271,
+STORE, 140164630274048, 140164638666751,
+SNULL, 140164814852095, 140164848418815,
+STORE, 140164814848000, 140164814852095,
+STORE, 140164814852096, 140164848418815,
+SNULL, 140164814852096, 140164831633407,
+STORE, 140164831633408, 140164848418815,
+STORE, 140164814852096, 140164831633407,
+SNULL, 140164831637503, 140164848418815,
+STORE, 140164831633408, 140164831637503,
+STORE, 140164831637504, 140164848418815,
+STORE, 140164621881344, 140164638666751,
+SNULL, 140164831637504, 140164840026111,
+STORE, 140164840026112, 140164848418815,
+STORE, 140164831637504, 140164840026111,
+SNULL, 140164840030207, 140164848418815,
+STORE, 140164840026112, 140164840030207,
+STORE, 140164840030208, 140164848418815,
+STORE, 140164613488640, 140164638666751,
+SNULL, 140164613492735, 140164638666751,
+STORE, 140164613488640, 140164613492735,
+STORE, 140164613492736, 140164638666751,
+STORE, 140164605095936, 140164613488639,
+SNULL, 140164605100031, 140164613488639,
+STORE, 140164605095936, 140164605100031,
+STORE, 140164605100032, 140164613488639,
+STORE, 140164596703232, 140164605095935,
+STORE, 140164588310528, 140164605095935,
+SNULL, 140164588314623, 140164605095935,
+STORE, 140164588310528, 140164588314623,
+STORE, 140164588314624, 140164605095935,
+STORE, 140164504481792, 140164512874495,
+STORE, 140164496089088, 140164512874495,
+SNULL, 140164496089088, 140164504481791,
+STORE, 140164504481792, 140164512874495,
+STORE, 140164496089088, 140164504481791,
+SNULL, 140164504485887, 140164512874495,
+STORE, 140164504481792, 140164504485887,
+STORE, 140164504485888, 140164512874495,
+SNULL, 140164613492736, 140164630274047,
+STORE, 140164630274048, 140164638666751,
+STORE, 140164613492736, 140164630274047,
+SNULL, 140164630278143, 140164638666751,
+STORE, 140164630274048, 140164630278143,
+STORE, 140164630278144, 140164638666751,
+STORE, 140164487696384, 140164504481791,
+STORE, 140164479303680, 140164504481791,
+SNULL, 140164814852096, 140164823240703,
+STORE, 140164823240704, 140164831633407,
+STORE, 140164814852096, 140164823240703,
+SNULL, 140164823244799, 140164831633407,
+STORE, 140164823240704, 140164823244799,
+STORE, 140164823244800, 140164831633407,
+STORE, 140164470910976, 140164504481791,
+SNULL, 140164470910976, 140164496089087,
+STORE, 140164496089088, 140164504481791,
+STORE, 140164470910976, 140164496089087,
+SNULL, 140164496093183, 140164504481791,
+STORE, 140164496089088, 140164496093183,
+STORE, 140164496093184, 140164504481791,
+SNULL, 140164655456256, 140164672237567,
+STORE, 140164672237568, 140164680630271,
+STORE, 140164655456256, 140164672237567,
+SNULL, 140164672241663, 140164680630271,
+STORE, 140164672237568, 140164672241663,
+STORE, 140164672241664, 140164680630271,
+STORE, 140164462518272, 140164496089087,
+STORE, 140164454125568, 140164496089087,
+SNULL, 140164655456256, 140164663844863,
+STORE, 140164663844864, 140164672237567,
+STORE, 140164655456256, 140164663844863,
+SNULL, 140164663848959, 140164672237567,
+STORE, 140164663844864, 140164663848959,
+STORE, 140164663848960, 140164672237567,
+STORE, 140164370264064, 140164378656767,
+STORE, 140164361871360, 140164378656767,
+STORE, 140164353478656, 140164378656767,
+STORE, 140164345085952, 140164378656767,
+SNULL, 140164345085952, 140164353478655,
+STORE, 140164353478656, 140164378656767,
+STORE, 140164345085952, 140164353478655,
+SNULL, 140164353482751, 140164378656767,
+STORE, 140164353478656, 140164353482751,
+STORE, 140164353482752, 140164378656767,
+SNULL, 140164454125568, 140164487696383,
+STORE, 140164487696384, 140164496089087,
+STORE, 140164454125568, 140164487696383,
+SNULL, 140164487700479, 140164496089087,
+STORE, 140164487696384, 140164487700479,
+STORE, 140164487700480, 140164496089087,
+STORE, 140164336693248, 140164353478655,
+SNULL, 140164336697343, 140164353478655,
+STORE, 140164336693248, 140164336697343,
+STORE, 140164336697344, 140164353478655,
+STORE, 140164328300544, 140164336693247,
+SNULL, 140164454125568, 140164479303679,
+STORE, 140164479303680, 140164487696383,
+STORE, 140164454125568, 140164479303679,
+SNULL, 140164479307775, 140164487696383,
+STORE, 140164479303680, 140164479307775,
+STORE, 140164479307776, 140164487696383,
+STORE, 140164319907840, 140164336693247,
+STORE, 140164236046336, 140164244439039,
+SNULL, 140164588314624, 140164596703231,
+STORE, 140164596703232, 140164605095935,
+STORE, 140164588314624, 140164596703231,
+SNULL, 140164596707327, 140164605095935,
+STORE, 140164596703232, 140164596707327,
+STORE, 140164596707328, 140164605095935,
+SNULL, 140164454125568, 140164462518271,
+STORE, 140164462518272, 140164479303679,
+STORE, 140164454125568, 140164462518271,
+SNULL, 140164462522367, 140164479303679,
+STORE, 140164462518272, 140164462522367,
+STORE, 140164462522368, 140164479303679,
+STORE, 140164227653632, 140164244439039,
+SNULL, 140164227657727, 140164244439039,
+STORE, 140164227653632, 140164227657727,
+STORE, 140164227657728, 140164244439039,
+SNULL, 140164462522368, 140164470910975,
+STORE, 140164470910976, 140164479303679,
+STORE, 140164462522368, 140164470910975,
+SNULL, 140164470915071, 140164479303679,
+STORE, 140164470910976, 140164470915071,
+STORE, 140164470915072, 140164479303679,
+SNULL, 140164613492736, 140164621881343,
+STORE, 140164621881344, 140164630274047,
+STORE, 140164613492736, 140164621881343,
+SNULL, 140164621885439, 140164630274047,
+STORE, 140164621881344, 140164621885439,
+STORE, 140164621885440, 140164630274047,
+SNULL, 140164353482752, 140164370264063,
+STORE, 140164370264064, 140164378656767,
+STORE, 140164353482752, 140164370264063,
+SNULL, 140164370268159, 140164378656767,
+STORE, 140164370264064, 140164370268159,
+STORE, 140164370268160, 140164378656767,
+STORE, 140164219260928, 140164227653631,
+SNULL, 140164319911935, 140164336693247,
+STORE, 140164319907840, 140164319911935,
+STORE, 140164319911936, 140164336693247,
+SNULL, 140164336697344, 140164345085951,
+STORE, 140164345085952, 140164353478655,
+STORE, 140164336697344, 140164345085951,
+SNULL, 140164345090047, 140164353478655,
+STORE, 140164345085952, 140164345090047,
+STORE, 140164345090048, 140164353478655,
+SNULL, 140164319911936, 140164328300543,
+STORE, 140164328300544, 140164336693247,
+STORE, 140164319911936, 140164328300543,
+SNULL, 140164328304639, 140164336693247,
+STORE, 140164328300544, 140164328304639,
+STORE, 140164328304640, 140164336693247,
+SNULL, 140164454129663, 140164462518271,
+STORE, 140164454125568, 140164454129663,
+STORE, 140164454129664, 140164462518271,
+STORE, 140164210868224, 140164227653631,
+STORE, 140164202475520, 140164227653631,
+STORE, 140164194082816, 140164227653631,
+SNULL, 140164194086911, 140164227653631,
+STORE, 140164194082816, 140164194086911,
+STORE, 140164194086912, 140164227653631,
+SNULL, 140164353482752, 140164361871359,
+STORE, 140164361871360, 140164370264063,
+STORE, 140164353482752, 140164361871359,
+SNULL, 140164361875455, 140164370264063,
+STORE, 140164361871360, 140164361875455,
+STORE, 140164361875456, 140164370264063,
+SNULL, 140164227657728, 140164236046335,
+STORE, 140164236046336, 140164244439039,
+STORE, 140164227657728, 140164236046335,
+SNULL, 140164236050431, 140164244439039,
+STORE, 140164236046336, 140164236050431,
+STORE, 140164236050432, 140164244439039,
+STORE, 140164185690112, 140164194082815,
+SNULL, 140164194086912, 140164219260927,
+STORE, 140164219260928, 140164227653631,
+STORE, 140164194086912, 140164219260927,
+SNULL, 140164219265023, 140164227653631,
+STORE, 140164219260928, 140164219265023,
+STORE, 140164219265024, 140164227653631,
+STORE, 140164101828608, 140164110221311,
+STORE, 140164093435904, 140164110221311,
+STORE, 140164085043200, 140164110221311,
+SNULL, 140164085047295, 140164110221311,
+STORE, 140164085043200, 140164085047295,
+STORE, 140164085047296, 140164110221311,
+STORE, 140164076650496, 140164085043199,
+SNULL, 140164185694207, 140164194082815,
+STORE, 140164185690112, 140164185694207,
+STORE, 140164185694208, 140164194082815,
+SNULL, 140164085047296, 140164101828607,
+STORE, 140164101828608, 140164110221311,
+STORE, 140164085047296, 140164101828607,
+SNULL, 140164101832703, 140164110221311,
+STORE, 140164101828608, 140164101832703,
+STORE, 140164101832704, 140164110221311,
+SNULL, 140164085047296, 140164093435903,
+STORE, 140164093435904, 140164101828607,
+STORE, 140164085047296, 140164093435903,
+SNULL, 140164093439999, 140164101828607,
+STORE, 140164093435904, 140164093439999,
+STORE, 140164093440000, 140164101828607,
+SNULL, 140164194086912, 140164202475519,
+STORE, 140164202475520, 140164219260927,
+STORE, 140164194086912, 140164202475519,
+SNULL, 140164202479615, 140164219260927,
+STORE, 140164202475520, 140164202479615,
+STORE, 140164202479616, 140164219260927,
+SNULL, 140164202479616, 140164210868223,
+STORE, 140164210868224, 140164219260927,
+STORE, 140164202479616, 140164210868223,
+SNULL, 140164210872319, 140164219260927,
+STORE, 140164210868224, 140164210872319,
+STORE, 140164210872320, 140164219260927,
+SNULL, 140164076654591, 140164085043199,
+STORE, 140164076650496, 140164076654591,
+STORE, 140164076654592, 140164085043199,
+STORE, 140164068257792, 140164076650495,
+SNULL, 140164068261887, 140164076650495,
+STORE, 140164068257792, 140164068261887,
+STORE, 140164068261888, 140164076650495,
+STORE, 140165753053184, 140165753081855,
+STORE, 140165725851648, 140165728043007,
+SNULL, 140165725851648, 140165725941759,
+STORE, 140165725941760, 140165728043007,
+STORE, 140165725851648, 140165725941759,
+SNULL, 140165728034815, 140165728043007,
+STORE, 140165725941760, 140165728034815,
+STORE, 140165728034816, 140165728043007,
+ERASE, 140165728034816, 140165728043007,
+STORE, 140165728034816, 140165728043007,
+SNULL, 140165728038911, 140165728043007,
+STORE, 140165728034816, 140165728038911,
+STORE, 140165728038912, 140165728043007,
+ERASE, 140165753053184, 140165753081855,
+ERASE, 140164638666752, 140164638670847,
+ERASE, 140164638670848, 140164647059455,
+ERASE, 140165091676160, 140165091680255,
+ERASE, 140165091680256, 140165100068863,
+ERASE, 140164613488640, 140164613492735,
+ERASE, 140164613492736, 140164621881343,
+ERASE, 140164319907840, 140164319911935,
+ERASE, 140164319911936, 140164328300543,
+ERASE, 140165620154368, 140165620158463,
+ERASE, 140165620158464, 140165628547071,
+ERASE, 140164798062592, 140164798066687,
+ERASE, 140164798066688, 140164806455295,
+ERASE, 140164789669888, 140164789673983,
+ERASE, 140164789673984, 140164798062591,
+ERASE, 140164965851136, 140164965855231,
+ERASE, 140164965855232, 140164974243839,
+ERASE, 140165074890752, 140165074894847,
+ERASE, 140165074894848, 140165083283455,
+ERASE, 140164672237568, 140164672241663,
+ERASE, 140164672241664, 140164680630271,
+ERASE, 140164454125568, 140164454129663,
+ERASE, 140164454129664, 140164462518271,
+ERASE, 140165200715776, 140165200719871,
+ERASE, 140165200719872, 140165209108479,
+ERASE, 140164932280320, 140164932284415,
+ERASE, 140164932284416, 140164940673023,
+ERASE, 140164663844864, 140164663848959,
+ERASE, 140164663848960, 140164672237567,
+ERASE, 140164697415680, 140164697419775,
+ERASE, 140164697419776, 140164705808383,
+ERASE, 140164831633408, 140164831637503,
+ERASE, 140164831637504, 140164840026111,
+ERASE, 140165192323072, 140165192327167,
+ERASE, 140165192327168, 140165200715775,
+ERASE, 140165108461568, 140165108465663,
+ERASE, 140165108465664, 140165116854271,
+ERASE, 140164840026112, 140164840030207,
+ERASE, 140164840030208, 140164848418815,
+ERASE, 140164647059456, 140164647063551,
+ERASE, 140164647063552, 140164655452159,
+ERASE, 140165083283456, 140165083287551,
+ERASE, 140165083287552, 140165091676159,
+ERASE, 140164923887616, 140164923891711,
+ERASE, 140164923891712, 140164932280319,
+ERASE, 140164823240704, 140164823244799,
+ERASE, 140164823244800, 140164831633407,
+ERASE, 140164227653632, 140164227657727,
+ERASE, 140164227657728, 140164236046335,
+ERASE, 140164957458432, 140164957462527,
+ERASE, 140164957462528, 140164965851135,
+ERASE, 140164680630272, 140164680634367,
+ERASE, 140164680634368, 140164689022975,
+ERASE, 140164974243840, 140164974247935,
+ERASE, 140164974247936, 140164982636543,
+ERASE, 140165066498048, 140165066502143,
+ERASE, 140165066502144, 140165074890751,
+ERASE, 140164621881344, 140164621885439,
+ERASE, 140164621885440, 140164630274047,
+ERASE, 140164949065728, 140164949069823,
+ERASE, 140164949069824, 140164957458431,
+ERASE, 140164588310528, 140164588314623,
+ERASE, 140164588314624, 140164596703231,
+ERASE, 140164806455296, 140164806459391,
+ERASE, 140164806459392, 140164814847999,
+ERASE, 140164940673024, 140164940677119,
+ERASE, 140164940677120, 140164949065727,
+ERASE, 140164596703232, 140164596707327,
+ERASE, 140164596707328, 140164605095935,
+ERASE, 140164605095936, 140164605100031,
+ERASE, 140164605100032, 140164613488639,
+ERASE, 140164655452160, 140164655456255,
+ERASE, 140164655456256, 140164663844863,
+ERASE, 140164705808384, 140164705812479,
+ERASE, 140164705812480, 140164714201087,
+ERASE, 140164689022976, 140164689027071,
+ERASE, 140164689027072, 140164697415679,
+ERASE, 140164630274048, 140164630278143,
+ERASE, 140164630278144, 140164638666751,
+ERASE, 140164479303680, 140164479307775,
+ERASE, 140164479307776, 140164487696383,
+ERASE, 140164236046336, 140164236050431,
+ERASE, 140164236050432, 140164244439039,
+ERASE, 140164085043200, 140164085047295,
+ERASE, 140164085047296, 140164093435903,
+ERASE, 140164345085952, 140164345090047,
+ERASE, 140164345090048, 140164353478655,
+ERASE, 140164101828608, 140164101832703,
+ERASE, 140164101832704, 140164110221311,
+ERASE, 140164370264064, 140164370268159,
+ERASE, 140164370268160, 140164378656767,
+ERASE, 140164336693248, 140164336697343,
+ERASE, 140164336697344, 140164345085951,
+ERASE, 140164194082816, 140164194086911,
+ERASE, 140164194086912, 140164202475519,
+ERASE, 140164353478656, 140164353482751,
+ERASE, 140164353482752, 140164361871359,
+ERASE, 140164210868224, 140164210872319,
+ERASE, 140164210872320, 140164219260927,
+ERASE, 140164814848000, 140164814852095,
+ERASE, 140164814852096, 140164823240703,
+ERASE, 140164504481792, 140164504485887,
+ERASE, 140164504485888, 140164512874495,
+ERASE, 140165100068864, 140165100072959,
+ERASE, 140165100072960, 140165108461567,
+ERASE, 140164361871360, 140164361875455,
+ERASE, 140164361875456, 140164370264063,
+ERASE, 140164470910976, 140164470915071,
+ERASE, 140164470915072, 140164479303679,
+ERASE, 140164076650496, 140164076654591,
+ERASE, 140164076654592, 140164085043199,
+ERASE, 140164202475520, 140164202479615,
+ERASE, 140164202479616, 140164210868223,
+ERASE, 140164462518272, 140164462522367,
+ERASE, 140164462522368, 140164470910975,
+ERASE, 140165351718912, 140165351723007,
+ERASE, 140165351723008, 140165360111615,
+ERASE, 140164328300544, 140164328304639,
+ERASE, 140164328304640, 140164336693247,
+ERASE, 140164093435904, 140164093439999,
+ERASE, 140164093440000, 140164101828607,
+ERASE, 140165603368960, 140165603373055,
+ERASE, 140165603373056, 140165611761663,
+ERASE, 140165368504320, 140165368508415,
+ERASE, 140165368508416, 140165376897023,
+ERASE, 140165334933504, 140165334937599,
+ERASE, 140165334937600, 140165343326207,
+ERASE, 140165594976256, 140165594980351,
+ERASE, 140165594980352, 140165603368959,
+ERASE, 140164487696384, 140164487700479,
+ERASE, 140164487700480, 140164496089087,
+ERASE, 140164219260928, 140164219265023,
+ERASE, 140164219265024, 140164227653631,
+ERASE, 140164185690112, 140164185694207,
+ERASE, 140164185694208, 140164194082815,
+ERASE, 140164068257792, 140164068261887,
+ERASE, 140164068261888, 140164076650495,
+ERASE, 140165225893888, 140165225897983,
+ERASE, 140165225897984, 140165234286591,
+ERASE, 140165058105344, 140165058109439,
+ };
+ unsigned long set31[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140730890784768, 140737488351231,
+SNULL, 140730890788863, 140737488351231,
+STORE, 140730890784768, 140730890788863,
+STORE, 140730890653696, 140730890788863,
+STORE, 94577123659776, 94577125912575,
+SNULL, 94577123790847, 94577125912575,
+STORE, 94577123659776, 94577123790847,
+STORE, 94577123790848, 94577125912575,
+ERASE, 94577123790848, 94577125912575,
+STORE, 94577125883904, 94577125892095,
+STORE, 94577125892096, 94577125912575,
+STORE, 140624060407808, 140624062660607,
+SNULL, 140624060551167, 140624062660607,
+STORE, 140624060407808, 140624060551167,
+STORE, 140624060551168, 140624062660607,
+ERASE, 140624060551168, 140624062660607,
+STORE, 140624062648320, 140624062656511,
+STORE, 140624062656512, 140624062660607,
+STORE, 140730892140544, 140730892144639,
+STORE, 140730892128256, 140730892140543,
+STORE, 140624062619648, 140624062648319,
+STORE, 140624062611456, 140624062619647,
+STORE, 140624058191872, 140624060407807,
+SNULL, 140624058191872, 140624058290175,
+STORE, 140624058290176, 140624060407807,
+STORE, 140624058191872, 140624058290175,
+SNULL, 140624060383231, 140624060407807,
+STORE, 140624058290176, 140624060383231,
+STORE, 140624060383232, 140624060407807,
+SNULL, 140624060383232, 140624060391423,
+STORE, 140624060391424, 140624060407807,
+STORE, 140624060383232, 140624060391423,
+ERASE, 140624060383232, 140624060391423,
+STORE, 140624060383232, 140624060391423,
+ERASE, 140624060391424, 140624060407807,
+STORE, 140624060391424, 140624060407807,
+STORE, 140624054394880, 140624058191871,
+SNULL, 140624054394880, 140624056053759,
+STORE, 140624056053760, 140624058191871,
+STORE, 140624054394880, 140624056053759,
+SNULL, 140624058150911, 140624058191871,
+STORE, 140624056053760, 140624058150911,
+STORE, 140624058150912, 140624058191871,
+SNULL, 140624058150912, 140624058175487,
+STORE, 140624058175488, 140624058191871,
+STORE, 140624058150912, 140624058175487,
+ERASE, 140624058150912, 140624058175487,
+STORE, 140624058150912, 140624058175487,
+ERASE, 140624058175488, 140624058191871,
+STORE, 140624058175488, 140624058191871,
+STORE, 140624062603264, 140624062619647,
+SNULL, 140624058167295, 140624058175487,
+STORE, 140624058150912, 140624058167295,
+STORE, 140624058167296, 140624058175487,
+SNULL, 140624060387327, 140624060391423,
+STORE, 140624060383232, 140624060387327,
+STORE, 140624060387328, 140624060391423,
+SNULL, 94577125887999, 94577125892095,
+STORE, 94577125883904, 94577125887999,
+STORE, 94577125888000, 94577125892095,
+SNULL, 140624062652415, 140624062656511,
+STORE, 140624062648320, 140624062652415,
+STORE, 140624062652416, 140624062656511,
+ERASE, 140624062619648, 140624062648319,
+STORE, 94577157709824, 94577157844991,
+STORE, 140624046002176, 140624054394879,
+SNULL, 140624046006271, 140624054394879,
+STORE, 140624046002176, 140624046006271,
+STORE, 140624046006272, 140624054394879,
+STORE, 140624037609472, 140624046002175,
+STORE, 140623903391744, 140624037609471,
+SNULL, 140623903391744, 140623940157439,
+STORE, 140623940157440, 140624037609471,
+STORE, 140623903391744, 140623940157439,
+ERASE, 140623903391744, 140623940157439,
+SNULL, 140624007266303, 140624037609471,
+STORE, 140623940157440, 140624007266303,
+STORE, 140624007266304, 140624037609471,
+ERASE, 140624007266304, 140624037609471,
+SNULL, 140623940292607, 140624007266303,
+STORE, 140623940157440, 140623940292607,
+STORE, 140623940292608, 140624007266303,
+SNULL, 140624037613567, 140624046002175,
+STORE, 140624037609472, 140624037613567,
+STORE, 140624037613568, 140624046002175,
+STORE, 140624029216768, 140624037609471,
+SNULL, 140624029220863, 140624037609471,
+STORE, 140624029216768, 140624029220863,
+STORE, 140624029220864, 140624037609471,
+STORE, 140624020824064, 140624029216767,
+SNULL, 140624020828159, 140624029216767,
+STORE, 140624020824064, 140624020828159,
+STORE, 140624020828160, 140624029216767,
+STORE, 140624012431360, 140624020824063,
+SNULL, 140624012435455, 140624020824063,
+STORE, 140624012431360, 140624012435455,
+STORE, 140624012435456, 140624020824063,
+STORE, 140623931764736, 140623940157439,
+STORE, 140623797547008, 140623931764735,
+SNULL, 140623797547008, 140623805939711,
+STORE, 140623805939712, 140623931764735,
+STORE, 140623797547008, 140623805939711,
+ERASE, 140623797547008, 140623805939711,
+SNULL, 140623873048575, 140623931764735,
+STORE, 140623805939712, 140623873048575,
+STORE, 140623873048576, 140623931764735,
+ERASE, 140623873048576, 140623931764735,
+STORE, 140623923372032, 140623940157439,
+STORE, 140623914979328, 140623940157439,
+STORE, 140623906586624, 140623940157439,
+STORE, 140623671721984, 140623873048575,
+SNULL, 140623738830847, 140623873048575,
+STORE, 140623671721984, 140623738830847,
+STORE, 140623738830848, 140623873048575,
+SNULL, 140623738830848, 140623805939711,
+STORE, 140623805939712, 140623873048575,
+STORE, 140623738830848, 140623805939711,
+ERASE, 140623738830848, 140623805939711,
+SNULL, 140623806074879, 140623873048575,
+STORE, 140623805939712, 140623806074879,
+STORE, 140623806074880, 140623873048575,
+SNULL, 140623906586624, 140623931764735,
+STORE, 140623931764736, 140623940157439,
+STORE, 140623906586624, 140623931764735,
+SNULL, 140623931768831, 140623940157439,
+STORE, 140623931764736, 140623931768831,
+STORE, 140623931768832, 140623940157439,
+STORE, 140623537504256, 140623738830847,
+SNULL, 140623537504256, 140623671721983,
+STORE, 140623671721984, 140623738830847,
+STORE, 140623537504256, 140623671721983,
+SNULL, 140623671857151, 140623738830847,
+STORE, 140623671721984, 140623671857151,
+STORE, 140623671857152, 140623738830847,
+SNULL, 140623604613119, 140623671721983,
+STORE, 140623537504256, 140623604613119,
+STORE, 140623604613120, 140623671721983,
+ERASE, 140623604613120, 140623671721983,
+SNULL, 140623537639423, 140623604613119,
+STORE, 140623537504256, 140623537639423,
+STORE, 140623537639424, 140623604613119,
+STORE, 140623537639424, 140623671721983,
+SNULL, 140623537639424, 140623604613119,
+STORE, 140623604613120, 140623671721983,
+STORE, 140623537639424, 140623604613119,
+SNULL, 140623604748287, 140623671721983,
+STORE, 140623604613120, 140623604748287,
+STORE, 140623604748288, 140623671721983,
+STORE, 140623898193920, 140623931764735,
+SNULL, 140623898193920, 140623923372031,
+STORE, 140623923372032, 140623931764735,
+STORE, 140623898193920, 140623923372031,
+SNULL, 140623923376127, 140623931764735,
+STORE, 140623923372032, 140623923376127,
+STORE, 140623923376128, 140623931764735,
+STORE, 140623889801216, 140623923372031,
+SNULL, 140623889801216, 140623898193919,
+STORE, 140623898193920, 140623923372031,
+STORE, 140623889801216, 140623898193919,
+SNULL, 140623898198015, 140623923372031,
+STORE, 140623898193920, 140623898198015,
+STORE, 140623898198016, 140623923372031,
+SNULL, 140623889805311, 140623898193919,
+STORE, 140623889801216, 140623889805311,
+STORE, 140623889805312, 140623898193919,
+SNULL, 140623898198016, 140623906586623,
+STORE, 140623906586624, 140623923372031,
+STORE, 140623898198016, 140623906586623,
+SNULL, 140623906590719, 140623923372031,
+STORE, 140623906586624, 140623906590719,
+STORE, 140623906590720, 140623923372031,
+STORE, 140623881408512, 140623889801215,
+SNULL, 140623906590720, 140623914979327,
+STORE, 140623914979328, 140623923372031,
+STORE, 140623906590720, 140623914979327,
+SNULL, 140623914983423, 140623923372031,
+STORE, 140623914979328, 140623914983423,
+STORE, 140623914983424, 140623923372031,
+SNULL, 140623881412607, 140623889801215,
+STORE, 140623881408512, 140623881412607,
+STORE, 140623881412608, 140623889801215,
+STORE, 140623797547008, 140623805939711,
+STORE, 140623789154304, 140623805939711,
+STORE, 140623780761600, 140623805939711,
+SNULL, 140623780761600, 140623789154303,
+STORE, 140623789154304, 140623805939711,
+STORE, 140623780761600, 140623789154303,
+SNULL, 140623789158399, 140623805939711,
+STORE, 140623789154304, 140623789158399,
+STORE, 140623789158400, 140623805939711,
+STORE, 140623772368896, 140623789154303,
+STORE, 140623763976192, 140623789154303,
+SNULL, 140623763976192, 140623780761599,
+STORE, 140623780761600, 140623789154303,
+STORE, 140623763976192, 140623780761599,
+SNULL, 140623780765695, 140623789154303,
+STORE, 140623780761600, 140623780765695,
+STORE, 140623780765696, 140623789154303,
+SNULL, 140623789158400, 140623797547007,
+STORE, 140623797547008, 140623805939711,
+STORE, 140623789158400, 140623797547007,
+SNULL, 140623797551103, 140623805939711,
+STORE, 140623797547008, 140623797551103,
+STORE, 140623797551104, 140623805939711,
+SNULL, 140623763976192, 140623772368895,
+STORE, 140623772368896, 140623780761599,
+STORE, 140623763976192, 140623772368895,
+SNULL, 140623772372991, 140623780761599,
+STORE, 140623772368896, 140623772372991,
+STORE, 140623772372992, 140623780761599,
+SNULL, 140623763980287, 140623772368895,
+STORE, 140623763976192, 140623763980287,
+STORE, 140623763980288, 140623772368895,
+STORE, 140623755583488, 140623763976191,
+STORE, 140623747190784, 140623763976191,
+SNULL, 140623747190784, 140623755583487,
+STORE, 140623755583488, 140623763976191,
+STORE, 140623747190784, 140623755583487,
+SNULL, 140623755587583, 140623763976191,
+STORE, 140623755583488, 140623755587583,
+STORE, 140623755587584, 140623763976191,
+STORE, 140623529111552, 140623537504255,
+SNULL, 140623747194879, 140623755583487,
+STORE, 140623747190784, 140623747194879,
+STORE, 140623747194880, 140623755583487,
+SNULL, 140623529115647, 140623537504255,
+STORE, 140623529111552, 140623529115647,
+STORE, 140623529115648, 140623537504255,
+STORE, 140623520718848, 140623529111551,
+SNULL, 140623520722943, 140623529111551,
+STORE, 140623520718848, 140623520722943,
+STORE, 140623520722944, 140623529111551,
+STORE, 140623512326144, 140623520718847,
+STORE, 140623503933440, 140623520718847,
+STORE, 140623495540736, 140623520718847,
+STORE, 140623361323008, 140623495540735,
+STORE, 140623227105280, 140623495540735,
+STORE, 140623218712576, 140623227105279,
+STORE, 140623084494848, 140623218712575,
+STORE, 140623076102144, 140623084494847,
+STORE, 140622941884416, 140623076102143,
+SNULL, 140622941884416, 140623000633343,
+STORE, 140623000633344, 140623076102143,
+STORE, 140622941884416, 140623000633343,
+ERASE, 140622941884416, 140623000633343,
+STORE, 140622992240640, 140623000633343,
+STORE, 140622983847936, 140623000633343,
+STORE, 140622849630208, 140622983847935,
+STORE, 140622841237504, 140622849630207,
+SNULL, 140622849630208, 140622866415615,
+STORE, 140622866415616, 140622983847935,
+STORE, 140622849630208, 140622866415615,
+ERASE, 140622849630208, 140622866415615,
+STORE, 140622858022912, 140622866415615,
+SNULL, 140622933524479, 140622983847935,
+STORE, 140622866415616, 140622933524479,
+STORE, 140622933524480, 140622983847935,
+ERASE, 140622933524480, 140622983847935,
+STORE, 140622975455232, 140623000633343,
+STORE, 140622707019776, 140622841237503,
+STORE, 140622967062528, 140623000633343,
+STORE, 140622572802048, 140622841237503,
+STORE, 140622958669824, 140623000633343,
+STORE, 140622438584320, 140622841237503,
+STORE, 140622950277120, 140623000633343,
+SNULL, 140622858027007, 140622866415615,
+STORE, 140622858022912, 140622858027007,
+STORE, 140622858027008, 140622866415615,
+STORE, 140622941884416, 140623000633343,
+STORE, 140622841237504, 140622858022911,
+SNULL, 140622841237504, 140622849630207,
+STORE, 140622849630208, 140622858022911,
+STORE, 140622841237504, 140622849630207,
+SNULL, 140622849634303, 140622858022911,
+STORE, 140622849630208, 140622849634303,
+STORE, 140622849634304, 140622858022911,
+STORE, 140622430191616, 140622438584319,
+SNULL, 140622430195711, 140622438584319,
+STORE, 140622430191616, 140622430195711,
+STORE, 140622430195712, 140622438584319,
+SNULL, 140623361323007, 140623495540735,
+STORE, 140623227105280, 140623361323007,
+STORE, 140623361323008, 140623495540735,
+SNULL, 140623361323008, 140623403286527,
+STORE, 140623403286528, 140623495540735,
+STORE, 140623361323008, 140623403286527,
+ERASE, 140623361323008, 140623403286527,
+SNULL, 140623470395391, 140623495540735,
+STORE, 140623403286528, 140623470395391,
+STORE, 140623470395392, 140623495540735,
+ERASE, 140623470395392, 140623495540735,
+SNULL, 140623227105280, 140623269068799,
+STORE, 140623269068800, 140623361323007,
+STORE, 140623227105280, 140623269068799,
+ERASE, 140623227105280, 140623269068799,
+SNULL, 140623084494848, 140623134851071,
+STORE, 140623134851072, 140623218712575,
+STORE, 140623084494848, 140623134851071,
+ERASE, 140623084494848, 140623134851071,
+SNULL, 140623201959935, 140623218712575,
+STORE, 140623134851072, 140623201959935,
+STORE, 140623201959936, 140623218712575,
+ERASE, 140623201959936, 140623218712575,
+SNULL, 140623067742207, 140623076102143,
+STORE, 140623000633344, 140623067742207,
+STORE, 140623067742208, 140623076102143,
+ERASE, 140623067742208, 140623076102143,
+STORE, 140622295973888, 140622430191615,
+SNULL, 140622295973888, 140622329544703,
+STORE, 140622329544704, 140622430191615,
+STORE, 140622295973888, 140622329544703,
+ERASE, 140622295973888, 140622329544703,
+SNULL, 140622866550783, 140622933524479,
+STORE, 140622866415616, 140622866550783,
+STORE, 140622866550784, 140622933524479,
+SNULL, 140622707019775, 140622841237503,
+STORE, 140622438584320, 140622707019775,
+STORE, 140622707019776, 140622841237503,
+SNULL, 140622707019776, 140622732197887,
+STORE, 140622732197888, 140622841237503,
+STORE, 140622707019776, 140622732197887,
+ERASE, 140622707019776, 140622732197887,
+SNULL, 140622799306751, 140622841237503,
+STORE, 140622732197888, 140622799306751,
+STORE, 140622799306752, 140622841237503,
+ERASE, 140622799306752, 140622841237503,
+SNULL, 140622572802047, 140622707019775,
+STORE, 140622438584320, 140622572802047,
+STORE, 140622572802048, 140622707019775,
+SNULL, 140622572802048, 140622597980159,
+STORE, 140622597980160, 140622707019775,
+STORE, 140622572802048, 140622597980159,
+ERASE, 140622572802048, 140622597980159,
+SNULL, 140622438584320, 140622463762431,
+STORE, 140622463762432, 140622572802047,
+STORE, 140622438584320, 140622463762431,
+ERASE, 140622438584320, 140622463762431,
+SNULL, 140622530871295, 140622572802047,
+STORE, 140622463762432, 140622530871295,
+STORE, 140622530871296, 140622572802047,
+ERASE, 140622530871296, 140622572802047,
+STORE, 140622195326976, 140622430191615,
+SNULL, 140622262435839, 140622430191615,
+STORE, 140622195326976, 140622262435839,
+STORE, 140622262435840, 140622430191615,
+SNULL, 140622262435840, 140622329544703,
+STORE, 140622329544704, 140622430191615,
+STORE, 140622262435840, 140622329544703,
+ERASE, 140622262435840, 140622329544703,
+SNULL, 140622841241599, 140622849630207,
+STORE, 140622841237504, 140622841241599,
+STORE, 140622841241600, 140622849630207,
+STORE, 140623487148032, 140623520718847,
+STORE, 140623478755328, 140623520718847,
+SNULL, 140622941884416, 140622983847935,
+STORE, 140622983847936, 140623000633343,
+STORE, 140622941884416, 140622983847935,
+SNULL, 140622983852031, 140623000633343,
+STORE, 140622983847936, 140622983852031,
+STORE, 140622983852032, 140623000633343,
+STORE, 140623394893824, 140623403286527,
+SNULL, 140623394897919, 140623403286527,
+STORE, 140623394893824, 140623394897919,
+STORE, 140623394897920, 140623403286527,
+SNULL, 140623403421695, 140623470395391,
+STORE, 140623403286528, 140623403421695,
+STORE, 140623403421696, 140623470395391,
+SNULL, 140623478755328, 140623503933439,
+STORE, 140623503933440, 140623520718847,
+STORE, 140623478755328, 140623503933439,
+SNULL, 140623503937535, 140623520718847,
+STORE, 140623503933440, 140623503937535,
+STORE, 140623503937536, 140623520718847,
+SNULL, 140623336177663, 140623361323007,
+STORE, 140623269068800, 140623336177663,
+STORE, 140623336177664, 140623361323007,
+ERASE, 140623336177664, 140623361323007,
+SNULL, 140623269203967, 140623336177663,
+STORE, 140623269068800, 140623269203967,
+STORE, 140623269203968, 140623336177663,
+SNULL, 140623134986239, 140623201959935,
+STORE, 140623134851072, 140623134986239,
+STORE, 140623134986240, 140623201959935,
+SNULL, 140623000768511, 140623067742207,
+STORE, 140623000633344, 140623000768511,
+STORE, 140623000768512, 140623067742207,
+SNULL, 140622396653567, 140622430191615,
+STORE, 140622329544704, 140622396653567,
+STORE, 140622396653568, 140622430191615,
+ERASE, 140622396653568, 140622430191615,
+SNULL, 140622732333055, 140622799306751,
+STORE, 140622732197888, 140622732333055,
+STORE, 140622732333056, 140622799306751,
+SNULL, 140622941884416, 140622975455231,
+STORE, 140622975455232, 140622983847935,
+STORE, 140622941884416, 140622975455231,
+SNULL, 140622975459327, 140622983847935,
+STORE, 140622975455232, 140622975459327,
+STORE, 140622975459328, 140622983847935,
+SNULL, 140622665089023, 140622707019775,
+STORE, 140622597980160, 140622665089023,
+STORE, 140622665089024, 140622707019775,
+ERASE, 140622665089024, 140622707019775,
+SNULL, 140622598115327, 140622665089023,
+STORE, 140622597980160, 140622598115327,
+STORE, 140622598115328, 140622665089023,
+SNULL, 140622463897599, 140622530871295,
+STORE, 140622463762432, 140622463897599,
+STORE, 140622463897600, 140622530871295,
+SNULL, 140622195462143, 140622262435839,
+STORE, 140622195326976, 140622195462143,
+STORE, 140622195462144, 140622262435839,
+STORE, 140623386501120, 140623394893823,
+SNULL, 140622941884416, 140622950277119,
+STORE, 140622950277120, 140622975455231,
+STORE, 140622941884416, 140622950277119,
+SNULL, 140622950281215, 140622975455231,
+STORE, 140622950277120, 140622950281215,
+STORE, 140622950281216, 140622975455231,
+SNULL, 140622941888511, 140622950277119,
+STORE, 140622941884416, 140622941888511,
+STORE, 140622941888512, 140622950277119,
+STORE, 140623378108416, 140623394893823,
+SNULL, 140623478755328, 140623495540735,
+STORE, 140623495540736, 140623503933439,
+STORE, 140623478755328, 140623495540735,
+SNULL, 140623495544831, 140623503933439,
+STORE, 140623495540736, 140623495544831,
+STORE, 140623495544832, 140623503933439,
+SNULL, 140623478755328, 140623487148031,
+STORE, 140623487148032, 140623495540735,
+STORE, 140623478755328, 140623487148031,
+SNULL, 140623487152127, 140623495540735,
+STORE, 140623487148032, 140623487152127,
+STORE, 140623487152128, 140623495540735,
+SNULL, 140623218716671, 140623227105279,
+STORE, 140623218712576, 140623218716671,
+STORE, 140623218716672, 140623227105279,
+SNULL, 140623076106239, 140623084494847,
+STORE, 140623076102144, 140623076106239,
+STORE, 140623076106240, 140623084494847,
+SNULL, 140622329679871, 140622396653567,
+STORE, 140622329544704, 140622329679871,
+STORE, 140622329679872, 140622396653567,
+SNULL, 140622950281216, 140622958669823,
+STORE, 140622958669824, 140622975455231,
+STORE, 140622950281216, 140622958669823,
+SNULL, 140622958673919, 140622975455231,
+STORE, 140622958669824, 140622958673919,
+STORE, 140622958673920, 140622975455231,
+SNULL, 140623503937536, 140623512326143,
+STORE, 140623512326144, 140623520718847,
+STORE, 140623503937536, 140623512326143,
+SNULL, 140623512330239, 140623520718847,
+STORE, 140623512326144, 140623512330239,
+STORE, 140623512330240, 140623520718847,
+SNULL, 140623378108416, 140623386501119,
+STORE, 140623386501120, 140623394893823,
+STORE, 140623378108416, 140623386501119,
+SNULL, 140623386505215, 140623394893823,
+STORE, 140623386501120, 140623386505215,
+STORE, 140623386505216, 140623394893823,
+STORE, 140623369715712, 140623386501119,
+STORE, 140623361323008, 140623386501119,
+STORE, 140623352930304, 140623386501119,
+SNULL, 140623352930304, 140623361323007,
+STORE, 140623361323008, 140623386501119,
+STORE, 140623352930304, 140623361323007,
+SNULL, 140623361327103, 140623386501119,
+STORE, 140623361323008, 140623361327103,
+STORE, 140623361327104, 140623386501119,
+SNULL, 140623478759423, 140623487148031,
+STORE, 140623478755328, 140623478759423,
+STORE, 140623478759424, 140623487148031,
+STORE, 140623344537600, 140623361323007,
+STORE, 140623260676096, 140623269068799,
+SNULL, 140622958673920, 140622967062527,
+STORE, 140622967062528, 140622975455231,
+STORE, 140622958673920, 140622967062527,
+SNULL, 140622967066623, 140622975455231,
+STORE, 140622967062528, 140622967066623,
+STORE, 140622967066624, 140622975455231,
+STORE, 140623252283392, 140623269068799,
+STORE, 140623243890688, 140623269068799,
+SNULL, 140622983852032, 140622992240639,
+STORE, 140622992240640, 140623000633343,
+STORE, 140622983852032, 140622992240639,
+SNULL, 140622992244735, 140623000633343,
+STORE, 140622992240640, 140622992244735,
+STORE, 140622992244736, 140623000633343,
+STORE, 140623235497984, 140623269068799,
+STORE, 140623218716672, 140623235497983,
+STORE, 140623210319872, 140623218712575,
+STORE, 140623126458368, 140623134851071,
+SNULL, 140623210323967, 140623218712575,
+STORE, 140623210319872, 140623210323967,
+STORE, 140623210323968, 140623218712575,
+SNULL, 140623218716672, 140623227105279,
+STORE, 140623227105280, 140623235497983,
+STORE, 140623218716672, 140623227105279,
+SNULL, 140623227109375, 140623235497983,
+STORE, 140623227105280, 140623227109375,
+STORE, 140623227109376, 140623235497983,
+STORE, 140623118065664, 140623134851071,
+STORE, 140623109672960, 140623134851071,
+SNULL, 140623109677055, 140623134851071,
+STORE, 140623109672960, 140623109677055,
+STORE, 140623109677056, 140623134851071,
+STORE, 140623101280256, 140623109672959,
+STORE, 140623092887552, 140623109672959,
+SNULL, 140623092887552, 140623101280255,
+STORE, 140623101280256, 140623109672959,
+STORE, 140623092887552, 140623101280255,
+SNULL, 140623101284351, 140623109672959,
+STORE, 140623101280256, 140623101284351,
+STORE, 140623101284352, 140623109672959,
+SNULL, 140623361327104, 140623378108415,
+STORE, 140623378108416, 140623386501119,
+STORE, 140623361327104, 140623378108415,
+SNULL, 140623378112511, 140623386501119,
+STORE, 140623378108416, 140623378112511,
+STORE, 140623378112512, 140623386501119,
+SNULL, 140623235497984, 140623243890687,
+STORE, 140623243890688, 140623269068799,
+STORE, 140623235497984, 140623243890687,
+SNULL, 140623243894783, 140623269068799,
+STORE, 140623243890688, 140623243894783,
+STORE, 140623243894784, 140623269068799,
+SNULL, 140623361327104, 140623369715711,
+STORE, 140623369715712, 140623378108415,
+STORE, 140623361327104, 140623369715711,
+SNULL, 140623369719807, 140623378108415,
+STORE, 140623369715712, 140623369719807,
+STORE, 140623369719808, 140623378108415,
+SNULL, 140623243894784, 140623252283391,
+STORE, 140623252283392, 140623269068799,
+STORE, 140623243894784, 140623252283391,
+SNULL, 140623252287487, 140623269068799,
+STORE, 140623252283392, 140623252287487,
+STORE, 140623252287488, 140623269068799,
+SNULL, 140623235502079, 140623243890687,
+STORE, 140623235497984, 140623235502079,
+STORE, 140623235502080, 140623243890687,
+SNULL, 140623344541695, 140623361323007,
+STORE, 140623344537600, 140623344541695,
+STORE, 140623344541696, 140623361323007,
+STORE, 140623076106240, 140623092887551,
+SNULL, 140623076106240, 140623084494847,
+STORE, 140623084494848, 140623092887551,
+STORE, 140623076106240, 140623084494847,
+SNULL, 140623084498943, 140623092887551,
+STORE, 140623084494848, 140623084498943,
+STORE, 140623084498944, 140623092887551,
+SNULL, 140623344541696, 140623352930303,
+STORE, 140623352930304, 140623361323007,
+STORE, 140623344541696, 140623352930303,
+SNULL, 140623352934399, 140623361323007,
+STORE, 140623352930304, 140623352934399,
+STORE, 140623352934400, 140623361323007,
+SNULL, 140623109677056, 140623118065663,
+STORE, 140623118065664, 140623134851071,
+STORE, 140623109677056, 140623118065663,
+SNULL, 140623118069759, 140623134851071,
+STORE, 140623118065664, 140623118069759,
+STORE, 140623118069760, 140623134851071,
+STORE, 140622832844800, 140622841237503,
+STORE, 140622824452096, 140622841237503,
+SNULL, 140622824452096, 140622832844799,
+STORE, 140622832844800, 140622841237503,
+STORE, 140622824452096, 140622832844799,
+SNULL, 140622832848895, 140622841237503,
+STORE, 140622832844800, 140622832848895,
+STORE, 140622832848896, 140622841237503,
+STORE, 140622816059392, 140622832844799,
+SNULL, 140623092891647, 140623101280255,
+STORE, 140623092887552, 140623092891647,
+STORE, 140623092891648, 140623101280255,
+SNULL, 140623118069760, 140623126458367,
+STORE, 140623126458368, 140623134851071,
+STORE, 140623118069760, 140623126458367,
+SNULL, 140623126462463, 140623134851071,
+STORE, 140623126458368, 140623126462463,
+STORE, 140623126462464, 140623134851071,
+SNULL, 140623252287488, 140623260676095,
+STORE, 140623260676096, 140623269068799,
+STORE, 140623252287488, 140623260676095,
+SNULL, 140623260680191, 140623269068799,
+STORE, 140623260676096, 140623260680191,
+STORE, 140623260680192, 140623269068799,
+STORE, 140622807666688, 140622832844799,
+STORE, 140622723805184, 140622732197887,
+STORE, 140622715412480, 140622732197887,
+STORE, 140622707019776, 140622732197887,
+SNULL, 140622707023871, 140622732197887,
+STORE, 140622707019776, 140622707023871,
+STORE, 140622707023872, 140622732197887,
+STORE, 140622698627072, 140622707019775,
+STORE, 140622690234368, 140622707019775,
+SNULL, 140622690238463, 140622707019775,
+STORE, 140622690234368, 140622690238463,
+STORE, 140622690238464, 140622707019775,
+SNULL, 140622807666688, 140622816059391,
+STORE, 140622816059392, 140622832844799,
+STORE, 140622807666688, 140622816059391,
+SNULL, 140622816063487, 140622832844799,
+STORE, 140622816059392, 140622816063487,
+STORE, 140622816063488, 140622832844799,
+STORE, 140622681841664, 140622690234367,
+STORE, 140622673448960, 140622690234367,
+SNULL, 140622673453055, 140622690234367,
+STORE, 140622673448960, 140622673453055,
+STORE, 140622673453056, 140622690234367,
+STORE, 140622589587456, 140622597980159,
+SNULL, 140622807670783, 140622816059391,
+STORE, 140622807666688, 140622807670783,
+STORE, 140622807670784, 140622816059391,
+STORE, 140622581194752, 140622597980159,
+SNULL, 140622581198847, 140622597980159,
+STORE, 140622581194752, 140622581198847,
+STORE, 140622581198848, 140622597980159,
+SNULL, 140622816063488, 140622824452095,
+STORE, 140622824452096, 140622832844799,
+STORE, 140622816063488, 140622824452095,
+SNULL, 140622824456191, 140622832844799,
+STORE, 140622824452096, 140622824456191,
+STORE, 140622824456192, 140622832844799,
+STORE, 140622572802048, 140622581194751,
+SNULL, 140622572806143, 140622581194751,
+STORE, 140622572802048, 140622572806143,
+STORE, 140622572806144, 140622581194751,
+STORE, 140622564409344, 140622572802047,
+STORE, 140622556016640, 140622572802047,
+SNULL, 140622556016640, 140622564409343,
+STORE, 140622564409344, 140622572802047,
+STORE, 140622556016640, 140622564409343,
+SNULL, 140622564413439, 140622572802047,
+STORE, 140622564409344, 140622564413439,
+STORE, 140622564413440, 140622572802047,
+SNULL, 140622690238464, 140622698627071,
+STORE, 140622698627072, 140622707019775,
+STORE, 140622690238464, 140622698627071,
+SNULL, 140622698631167, 140622707019775,
+STORE, 140622698627072, 140622698631167,
+STORE, 140622698631168, 140622707019775,
+SNULL, 140622707023872, 140622723805183,
+STORE, 140622723805184, 140622732197887,
+STORE, 140622707023872, 140622723805183,
+SNULL, 140622723809279, 140622732197887,
+STORE, 140622723805184, 140622723809279,
+STORE, 140622723809280, 140622732197887,
+SNULL, 140622707023872, 140622715412479,
+STORE, 140622715412480, 140622723805183,
+STORE, 140622707023872, 140622715412479,
+SNULL, 140622715416575, 140622723805183,
+STORE, 140622715412480, 140622715416575,
+STORE, 140622715416576, 140622723805183,
+STORE, 140622547623936, 140622564409343,
+SNULL, 140622547628031, 140622564409343,
+STORE, 140622547623936, 140622547628031,
+STORE, 140622547628032, 140622564409343,
+STORE, 140622539231232, 140622547623935,
+SNULL, 140622539235327, 140622547623935,
+STORE, 140622539231232, 140622539235327,
+STORE, 140622539235328, 140622547623935,
+SNULL, 140622581198848, 140622589587455,
+STORE, 140622589587456, 140622597980159,
+STORE, 140622581198848, 140622589587455,
+SNULL, 140622589591551, 140622597980159,
+STORE, 140622589587456, 140622589591551,
+STORE, 140622589591552, 140622597980159,
+STORE, 140622455369728, 140622463762431,
+SNULL, 140622455373823, 140622463762431,
+STORE, 140622455369728, 140622455373823,
+STORE, 140622455373824, 140622463762431,
+STORE, 140622446977024, 140622455369727,
+SNULL, 140622446981119, 140622455369727,
+STORE, 140622446977024, 140622446981119,
+STORE, 140622446981120, 140622455369727,
+SNULL, 140622547628032, 140622556016639,
+STORE, 140622556016640, 140622564409343,
+STORE, 140622547628032, 140622556016639,
+SNULL, 140622556020735, 140622564409343,
+STORE, 140622556016640, 140622556020735,
+STORE, 140622556020736, 140622564409343,
+STORE, 140622430195712, 140622446977023,
+STORE, 140622421798912, 140622430191615,
+SNULL, 140622430195712, 140622438584319,
+STORE, 140622438584320, 140622446977023,
+STORE, 140622430195712, 140622438584319,
+SNULL, 140622438588415, 140622446977023,
+STORE, 140622438584320, 140622438588415,
+STORE, 140622438588416, 140622446977023,
+STORE, 140622413406208, 140622430191615,
+STORE, 140622405013504, 140622430191615,
+SNULL, 140622405013504, 140622413406207,
+STORE, 140622413406208, 140622430191615,
+STORE, 140622405013504, 140622413406207,
+SNULL, 140622413410303, 140622430191615,
+STORE, 140622413406208, 140622413410303,
+STORE, 140622413410304, 140622430191615,
+SNULL, 140622673453056, 140622681841663,
+STORE, 140622681841664, 140622690234367,
+STORE, 140622673453056, 140622681841663,
+SNULL, 140622681845759, 140622690234367,
+STORE, 140622681841664, 140622681845759,
+STORE, 140622681845760, 140622690234367,
+STORE, 140622321152000, 140622329544703,
+SNULL, 140622413410304, 140622421798911,
+STORE, 140622421798912, 140622430191615,
+STORE, 140622413410304, 140622421798911,
+SNULL, 140622421803007, 140622430191615,
+STORE, 140622421798912, 140622421803007,
+STORE, 140622421803008, 140622430191615,
+STORE, 140622312759296, 140622329544703,
+SNULL, 140622312763391, 140622329544703,
+STORE, 140622312759296, 140622312763391,
+STORE, 140622312763392, 140622329544703,
+SNULL, 140622405017599, 140622413406207,
+STORE, 140622405013504, 140622405017599,
+STORE, 140622405017600, 140622413406207,
+STORE, 140622304366592, 140622312759295,
+SNULL, 140622304370687, 140622312759295,
+STORE, 140622304366592, 140622304370687,
+STORE, 140622304370688, 140622312759295,
+SNULL, 140622312763392, 140622321151999,
+STORE, 140622321152000, 140622329544703,
+STORE, 140622312763392, 140622321151999,
+SNULL, 140622321156095, 140622329544703,
+STORE, 140622321152000, 140622321156095,
+STORE, 140622321156096, 140622329544703,
+STORE, 140624062619648, 140624062648319,
+STORE, 140624010240000, 140624012431359,
+SNULL, 140624010240000, 140624010330111,
+STORE, 140624010330112, 140624012431359,
+STORE, 140624010240000, 140624010330111,
+SNULL, 140624012423167, 140624012431359,
+STORE, 140624010330112, 140624012423167,
+STORE, 140624012423168, 140624012431359,
+ERASE, 140624012423168, 140624012431359,
+STORE, 140624012423168, 140624012431359,
+SNULL, 140624012427263, 140624012431359,
+STORE, 140624012423168, 140624012427263,
+STORE, 140624012427264, 140624012431359,
+ERASE, 140624062619648, 140624062648319,
+ERASE, 140622849630208, 140622849634303,
+ERASE, 140622849634304, 140622858022911,
+ERASE, 140623394893824, 140623394897919,
+ERASE, 140623394897920, 140623403286527,
+ERASE, 140623361323008, 140623361327103,
+ERASE, 140623361327104, 140623369715711,
+ERASE, 140623084494848, 140623084498943,
+ERASE, 140623084498944, 140623092887551,
+ERASE, 140623931764736, 140623931768831,
+ERASE, 140623931768832, 140623940157439,
+ERASE, 140622841237504, 140622841241599,
+ERASE, 140622841241600, 140622849630207,
+ERASE, 140623487148032, 140623487152127,
+ERASE, 140623487152128, 140623495540735,
+ERASE, 140623109672960, 140623109677055,
+ERASE, 140623109677056, 140623118065663,
+ERASE, 140622983847936, 140622983852031,
+ERASE, 140622983852032, 140622992240639,
+ERASE, 140623352930304, 140623352934399,
+ERASE, 140623352934400, 140623361323007,
+ERASE, 140622564409344, 140622564413439,
+ERASE, 140622564413440, 140622572802047,
+ERASE, 140622430191616, 140622430195711,
+ERASE, 140622430195712, 140622438584319,
+ERASE, 140622958669824, 140622958673919,
+ERASE, 140622958673920, 140622967062527,
+ERASE, 140622992240640, 140622992244735,
+ERASE, 140622992244736, 140623000633343,
+ERASE, 140623227105280, 140623227109375,
+ERASE, 140623227109376, 140623235497983,
+ERASE, 140622321152000, 140622321156095,
+ERASE, 140622321156096, 140622329544703,
+ERASE, 140622858022912, 140622858027007,
+ERASE, 140622858027008, 140622866415615,
+ERASE, 140622975455232, 140622975459327,
+ERASE, 140622975459328, 140622983847935,
+ERASE, 140623378108416, 140623378112511,
+ERASE, 140623378112512, 140623386501119,
+ERASE, 140623495540736, 140623495544831,
+ERASE, 140623495544832, 140623503933439,
+ERASE, 140623118065664, 140623118069759,
+ERASE, 140623118069760, 140623126458367,
+ERASE, 140622572802048, 140622572806143,
+ERASE, 140622572806144, 140622581194751,
+ERASE, 140622421798912, 140622421803007,
+ERASE, 140622421803008, 140622430191615,
+ERASE, 140622967062528, 140622967066623,
+ERASE, 140622967066624, 140622975455231,
+ERASE, 140623252283392, 140623252287487,
+ERASE, 140623252287488, 140623260676095,
+ERASE, 140622673448960, 140622673453055,
+ERASE, 140622673453056, 140622681841663,
+ERASE, 140623076102144, 140623076106239,
+ERASE, 140623076106240, 140623084494847,
+ERASE, 140623101280256, 140623101284351,
+ERASE, 140623101284352, 140623109672959,
+ERASE, 140622715412480, 140622715416575,
+ERASE, 140622715416576, 140622723805183,
+ERASE, 140622405013504, 140622405017599,
+ERASE, 140622405017600, 140622413406207,
+ERASE, 140623478755328, 140623478759423,
+ERASE, 140623478759424, 140623487148031,
+ERASE, 140623906586624, 140623906590719,
+ERASE, 140623906590720, 140623914979327,
+ERASE, 140622950277120, 140622950281215,
+ERASE, 140622950281216, 140622958669823,
+ };
+ unsigned long set32[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140731244212224, 140737488351231,
+SNULL, 140731244216319, 140737488351231,
+STORE, 140731244212224, 140731244216319,
+STORE, 140731244081152, 140731244216319,
+STORE, 94427773984768, 94427776237567,
+SNULL, 94427774115839, 94427776237567,
+STORE, 94427773984768, 94427774115839,
+STORE, 94427774115840, 94427776237567,
+ERASE, 94427774115840, 94427776237567,
+STORE, 94427776208896, 94427776217087,
+STORE, 94427776217088, 94427776237567,
+STORE, 140401464893440, 140401467146239,
+SNULL, 140401465036799, 140401467146239,
+STORE, 140401464893440, 140401465036799,
+STORE, 140401465036800, 140401467146239,
+ERASE, 140401465036800, 140401467146239,
+STORE, 140401467133952, 140401467142143,
+STORE, 140401467142144, 140401467146239,
+STORE, 140731244507136, 140731244511231,
+STORE, 140731244494848, 140731244507135,
+STORE, 140401467105280, 140401467133951,
+STORE, 140401467097088, 140401467105279,
+STORE, 140401462677504, 140401464893439,
+SNULL, 140401462677504, 140401462775807,
+STORE, 140401462775808, 140401464893439,
+STORE, 140401462677504, 140401462775807,
+SNULL, 140401464868863, 140401464893439,
+STORE, 140401462775808, 140401464868863,
+STORE, 140401464868864, 140401464893439,
+SNULL, 140401464868864, 140401464877055,
+STORE, 140401464877056, 140401464893439,
+STORE, 140401464868864, 140401464877055,
+ERASE, 140401464868864, 140401464877055,
+STORE, 140401464868864, 140401464877055,
+ERASE, 140401464877056, 140401464893439,
+STORE, 140401464877056, 140401464893439,
+STORE, 140401458880512, 140401462677503,
+SNULL, 140401458880512, 140401460539391,
+STORE, 140401460539392, 140401462677503,
+STORE, 140401458880512, 140401460539391,
+SNULL, 140401462636543, 140401462677503,
+STORE, 140401460539392, 140401462636543,
+STORE, 140401462636544, 140401462677503,
+SNULL, 140401462636544, 140401462661119,
+STORE, 140401462661120, 140401462677503,
+STORE, 140401462636544, 140401462661119,
+ERASE, 140401462636544, 140401462661119,
+STORE, 140401462636544, 140401462661119,
+ERASE, 140401462661120, 140401462677503,
+STORE, 140401462661120, 140401462677503,
+STORE, 140401467088896, 140401467105279,
+SNULL, 140401462652927, 140401462661119,
+STORE, 140401462636544, 140401462652927,
+STORE, 140401462652928, 140401462661119,
+SNULL, 140401464872959, 140401464877055,
+STORE, 140401464868864, 140401464872959,
+STORE, 140401464872960, 140401464877055,
+SNULL, 94427776212991, 94427776217087,
+STORE, 94427776208896, 94427776212991,
+STORE, 94427776212992, 94427776217087,
+SNULL, 140401467138047, 140401467142143,
+STORE, 140401467133952, 140401467138047,
+STORE, 140401467138048, 140401467142143,
+ERASE, 140401467105280, 140401467133951,
+STORE, 94427784683520, 94427784818687,
+STORE, 140401450487808, 140401458880511,
+SNULL, 140401450491903, 140401458880511,
+STORE, 140401450487808, 140401450491903,
+STORE, 140401450491904, 140401458880511,
+STORE, 140401442095104, 140401450487807,
+STORE, 140401307877376, 140401442095103,
+SNULL, 140401307877376, 140401340055551,
+STORE, 140401340055552, 140401442095103,
+STORE, 140401307877376, 140401340055551,
+ERASE, 140401307877376, 140401340055551,
+SNULL, 140401407164415, 140401442095103,
+STORE, 140401340055552, 140401407164415,
+STORE, 140401407164416, 140401442095103,
+ERASE, 140401407164416, 140401442095103,
+SNULL, 140401340190719, 140401407164415,
+STORE, 140401340055552, 140401340190719,
+STORE, 140401340190720, 140401407164415,
+SNULL, 140401442099199, 140401450487807,
+STORE, 140401442095104, 140401442099199,
+STORE, 140401442099200, 140401450487807,
+STORE, 140401433702400, 140401442095103,
+SNULL, 140401433706495, 140401442095103,
+STORE, 140401433702400, 140401433706495,
+STORE, 140401433706496, 140401442095103,
+STORE, 140401425309696, 140401433702399,
+SNULL, 140401425313791, 140401433702399,
+STORE, 140401425309696, 140401425313791,
+STORE, 140401425313792, 140401433702399,
+STORE, 140401416916992, 140401425309695,
+SNULL, 140401416921087, 140401425309695,
+STORE, 140401416916992, 140401416921087,
+STORE, 140401416921088, 140401425309695,
+STORE, 140401408524288, 140401416916991,
+STORE, 140401205837824, 140401340055551,
+SNULL, 140401272946687, 140401340055551,
+STORE, 140401205837824, 140401272946687,
+STORE, 140401272946688, 140401340055551,
+ERASE, 140401272946688, 140401340055551,
+SNULL, 140401205972991, 140401272946687,
+STORE, 140401205837824, 140401205972991,
+STORE, 140401205972992, 140401272946687,
+STORE, 140401331662848, 140401340055551,
+STORE, 140401323270144, 140401340055551,
+STORE, 140401138728960, 140401205837823,
+STORE, 140401314877440, 140401340055551,
+SNULL, 140401408528383, 140401416916991,
+STORE, 140401408524288, 140401408528383,
+STORE, 140401408528384, 140401416916991,
+SNULL, 140401138864127, 140401205837823,
+STORE, 140401138728960, 140401138864127,
+STORE, 140401138864128, 140401205837823,
+STORE, 140401004511232, 140401138728959,
+SNULL, 140401071620095, 140401138728959,
+STORE, 140401004511232, 140401071620095,
+STORE, 140401071620096, 140401138728959,
+ERASE, 140401071620096, 140401138728959,
+STORE, 140400870293504, 140401071620095,
+SNULL, 140400937402367, 140401071620095,
+STORE, 140400870293504, 140400937402367,
+STORE, 140400937402368, 140401071620095,
+SNULL, 140400937402368, 140401004511231,
+STORE, 140401004511232, 140401071620095,
+STORE, 140400937402368, 140401004511231,
+ERASE, 140400937402368, 140401004511231,
+STORE, 140401306484736, 140401340055551,
+SNULL, 140401306484736, 140401323270143,
+STORE, 140401323270144, 140401340055551,
+STORE, 140401306484736, 140401323270143,
+SNULL, 140401323274239, 140401340055551,
+STORE, 140401323270144, 140401323274239,
+STORE, 140401323274240, 140401340055551,
+SNULL, 140401004646399, 140401071620095,
+STORE, 140401004511232, 140401004646399,
+STORE, 140401004646400, 140401071620095,
+SNULL, 140400870428671, 140400937402367,
+STORE, 140400870293504, 140400870428671,
+STORE, 140400870428672, 140400937402367,
+SNULL, 140401306488831, 140401323270143,
+STORE, 140401306484736, 140401306488831,
+STORE, 140401306488832, 140401323270143,
+STORE, 140401298092032, 140401306484735,
+SNULL, 140401306488832, 140401314877439,
+STORE, 140401314877440, 140401323270143,
+STORE, 140401306488832, 140401314877439,
+SNULL, 140401314881535, 140401323270143,
+STORE, 140401314877440, 140401314881535,
+STORE, 140401314881536, 140401323270143,
+SNULL, 140401323274240, 140401331662847,
+STORE, 140401331662848, 140401340055551,
+STORE, 140401323274240, 140401331662847,
+SNULL, 140401331666943, 140401340055551,
+STORE, 140401331662848, 140401331666943,
+STORE, 140401331666944, 140401340055551,
+SNULL, 140401298096127, 140401306484735,
+STORE, 140401298092032, 140401298096127,
+STORE, 140401298096128, 140401306484735,
+STORE, 140401289699328, 140401298092031,
+STORE, 140401281306624, 140401298092031,
+STORE, 140401130336256, 140401138728959,
+SNULL, 140401281306624, 140401289699327,
+STORE, 140401289699328, 140401298092031,
+STORE, 140401281306624, 140401289699327,
+SNULL, 140401289703423, 140401298092031,
+STORE, 140401289699328, 140401289703423,
+STORE, 140401289703424, 140401298092031,
+STORE, 140401121943552, 140401138728959,
+STORE, 140401113550848, 140401138728959,
+SNULL, 140401281310719, 140401289699327,
+STORE, 140401281306624, 140401281310719,
+STORE, 140401281310720, 140401289699327,
+SNULL, 140401113550848, 140401121943551,
+STORE, 140401121943552, 140401138728959,
+STORE, 140401113550848, 140401121943551,
+SNULL, 140401121947647, 140401138728959,
+STORE, 140401121943552, 140401121947647,
+STORE, 140401121947648, 140401138728959,
+STORE, 140401105158144, 140401121943551,
+SNULL, 140401121947648, 140401130336255,
+STORE, 140401130336256, 140401138728959,
+STORE, 140401121947648, 140401130336255,
+SNULL, 140401130340351, 140401138728959,
+STORE, 140401130336256, 140401130340351,
+STORE, 140401130340352, 140401138728959,
+STORE, 140401096765440, 140401121943551,
+SNULL, 140401096765440, 140401113550847,
+STORE, 140401113550848, 140401121943551,
+STORE, 140401096765440, 140401113550847,
+SNULL, 140401113554943, 140401121943551,
+STORE, 140401113550848, 140401113554943,
+STORE, 140401113554944, 140401121943551,
+STORE, 140401088372736, 140401113550847,
+SNULL, 140401088372736, 140401096765439,
+STORE, 140401096765440, 140401113550847,
+STORE, 140401088372736, 140401096765439,
+SNULL, 140401096769535, 140401113550847,
+STORE, 140401096765440, 140401096769535,
+STORE, 140401096769536, 140401113550847,
+SNULL, 140401096769536, 140401105158143,
+STORE, 140401105158144, 140401113550847,
+STORE, 140401096769536, 140401105158143,
+SNULL, 140401105162239, 140401113550847,
+STORE, 140401105158144, 140401105162239,
+STORE, 140401105162240, 140401113550847,
+SNULL, 140401088376831, 140401096765439,
+STORE, 140401088372736, 140401088376831,
+STORE, 140401088376832, 140401096765439,
+STORE, 140401079980032, 140401088372735,
+STORE, 140400996118528, 140401004511231,
+SNULL, 140401079984127, 140401088372735,
+STORE, 140401079980032, 140401079984127,
+STORE, 140401079984128, 140401088372735,
+SNULL, 140400996122623, 140401004511231,
+STORE, 140400996118528, 140400996122623,
+STORE, 140400996122624, 140401004511231,
+STORE, 140400987725824, 140400996118527,
+STORE, 140400979333120, 140400996118527,
+STORE, 140400803184640, 140400870293503,
+SNULL, 140400803319807, 140400870293503,
+STORE, 140400803184640, 140400803319807,
+STORE, 140400803319808, 140400870293503,
+SNULL, 140400979333120, 140400987725823,
+STORE, 140400987725824, 140400996118527,
+STORE, 140400979333120, 140400987725823,
+SNULL, 140400987729919, 140400996118527,
+STORE, 140400987725824, 140400987729919,
+STORE, 140400987729920, 140400996118527,
+STORE, 140400970940416, 140400987725823,
+STORE, 140400962547712, 140400987725823,
+STORE, 140400668966912, 140400803184639,
+STORE, 140400954155008, 140400987725823,
+STORE, 140400945762304, 140400987725823,
+STORE, 140400660574208, 140400668966911,
+STORE, 140400593465344, 140400660574207,
+STORE, 140400585072640, 140400593465343,
+STORE, 140400450854912, 140400585072639,
+STORE, 140400442462208, 140400450854911,
+STORE, 140400434069504, 140400450854911,
+STORE, 140400299851776, 140400434069503,
+STORE, 140400291459072, 140400299851775,
+SNULL, 140400299851776, 140400333422591,
+STORE, 140400333422592, 140400434069503,
+STORE, 140400299851776, 140400333422591,
+ERASE, 140400299851776, 140400333422591,
+STORE, 140400325029888, 140400333422591,
+STORE, 140400157241344, 140400291459071,
+STORE, 140400316637184, 140400333422591,
+STORE, 140400308244480, 140400333422591,
+STORE, 140400023023616, 140400291459071,
+STORE, 140400291459072, 140400333422591,
+SNULL, 140400023023616, 140400064987135,
+STORE, 140400064987136, 140400291459071,
+STORE, 140400023023616, 140400064987135,
+ERASE, 140400023023616, 140400064987135,
+STORE, 140400056594432, 140400064987135,
+SNULL, 140400056598527, 140400064987135,
+STORE, 140400056594432, 140400056598527,
+STORE, 140400056598528, 140400064987135,
+STORE, 140399989485568, 140400056594431,
+SNULL, 140400291459072, 140400316637183,
+STORE, 140400316637184, 140400333422591,
+STORE, 140400291459072, 140400316637183,
+SNULL, 140400316641279, 140400333422591,
+STORE, 140400316637184, 140400316641279,
+STORE, 140400316641280, 140400333422591,
+STORE, 140399855267840, 140400056594431,
+SNULL, 140399855267840, 140399863660543,
+STORE, 140399863660544, 140400056594431,
+STORE, 140399855267840, 140399863660543,
+ERASE, 140399855267840, 140399863660543,
+SNULL, 140400736075775, 140400803184639,
+STORE, 140400668966912, 140400736075775,
+STORE, 140400736075776, 140400803184639,
+ERASE, 140400736075776, 140400803184639,
+SNULL, 140400669102079, 140400736075775,
+STORE, 140400668966912, 140400669102079,
+STORE, 140400669102080, 140400736075775,
+STORE, 140400669102080, 140400803184639,
+SNULL, 140400669102080, 140400736075775,
+STORE, 140400736075776, 140400803184639,
+STORE, 140400669102080, 140400736075775,
+SNULL, 140400736210943, 140400803184639,
+STORE, 140400736075776, 140400736210943,
+STORE, 140400736210944, 140400803184639,
+ERASE, 140400593465344, 140400660574207,
+SNULL, 140400450854912, 140400467640319,
+STORE, 140400467640320, 140400585072639,
+STORE, 140400450854912, 140400467640319,
+ERASE, 140400450854912, 140400467640319,
+STORE, 140399729442816, 140400056594431,
+SNULL, 140400400531455, 140400434069503,
+STORE, 140400333422592, 140400400531455,
+STORE, 140400400531456, 140400434069503,
+ERASE, 140400400531456, 140400434069503,
+SNULL, 140400333557759, 140400400531455,
+STORE, 140400333422592, 140400333557759,
+STORE, 140400333557760, 140400400531455,
+SNULL, 140400157241343, 140400291459071,
+STORE, 140400064987136, 140400157241343,
+STORE, 140400157241344, 140400291459071,
+SNULL, 140400157241344, 140400199204863,
+STORE, 140400199204864, 140400291459071,
+STORE, 140400157241344, 140400199204863,
+ERASE, 140400157241344, 140400199204863,
+SNULL, 140400266313727, 140400291459071,
+STORE, 140400199204864, 140400266313727,
+STORE, 140400266313728, 140400291459071,
+ERASE, 140400266313728, 140400291459071,
+SNULL, 140400132095999, 140400157241343,
+STORE, 140400064987136, 140400132095999,
+STORE, 140400132096000, 140400157241343,
+ERASE, 140400132096000, 140400157241343,
+SNULL, 140400065122303, 140400132095999,
+STORE, 140400064987136, 140400065122303,
+STORE, 140400065122304, 140400132095999,
+SNULL, 140400945762304, 140400954155007,
+STORE, 140400954155008, 140400987725823,
+STORE, 140400945762304, 140400954155007,
+SNULL, 140400954159103, 140400987725823,
+STORE, 140400954155008, 140400954159103,
+STORE, 140400954159104, 140400987725823,
+SNULL, 140400434069504, 140400442462207,
+STORE, 140400442462208, 140400450854911,
+STORE, 140400434069504, 140400442462207,
+SNULL, 140400442466303, 140400450854911,
+STORE, 140400442462208, 140400442466303,
+STORE, 140400442466304, 140400450854911,
+SNULL, 140400291463167, 140400316637183,
+STORE, 140400291459072, 140400291463167,
+STORE, 140400291463168, 140400316637183,
+STORE, 140400652181504, 140400668966911,
+STORE, 140400643788800, 140400668966911,
+SNULL, 140400291463168, 140400299851775,
+STORE, 140400299851776, 140400316637183,
+STORE, 140400291463168, 140400299851775,
+SNULL, 140400299855871, 140400316637183,
+STORE, 140400299851776, 140400299855871,
+STORE, 140400299855872, 140400316637183,
+STORE, 140400635396096, 140400668966911,
+SNULL, 140400635396096, 140400643788799,
+STORE, 140400643788800, 140400668966911,
+STORE, 140400635396096, 140400643788799,
+SNULL, 140400643792895, 140400668966911,
+STORE, 140400643788800, 140400643792895,
+STORE, 140400643792896, 140400668966911,
+SNULL, 140399989485567, 140400056594431,
+STORE, 140399729442816, 140399989485567,
+STORE, 140399989485568, 140400056594431,
+ERASE, 140399989485568, 140400056594431,
+SNULL, 140399930769407, 140399989485567,
+STORE, 140399729442816, 140399930769407,
+STORE, 140399930769408, 140399989485567,
+ERASE, 140399930769408, 140399989485567,
+SNULL, 140400945766399, 140400954155007,
+STORE, 140400945762304, 140400945766399,
+STORE, 140400945766400, 140400954155007,
+SNULL, 140400534749183, 140400585072639,
+STORE, 140400467640320, 140400534749183,
+STORE, 140400534749184, 140400585072639,
+ERASE, 140400534749184, 140400585072639,
+SNULL, 140399796551679, 140399930769407,
+STORE, 140399729442816, 140399796551679,
+STORE, 140399796551680, 140399930769407,
+SNULL, 140399796551680, 140399863660543,
+STORE, 140399863660544, 140399930769407,
+STORE, 140399796551680, 140399863660543,
+ERASE, 140399796551680, 140399863660543,
+SNULL, 140400199340031, 140400266313727,
+STORE, 140400199204864, 140400199340031,
+STORE, 140400199340032, 140400266313727,
+STORE, 140400627003392, 140400643788799,
+SNULL, 140400316641280, 140400325029887,
+STORE, 140400325029888, 140400333422591,
+STORE, 140400316641280, 140400325029887,
+SNULL, 140400325033983, 140400333422591,
+STORE, 140400325029888, 140400325033983,
+STORE, 140400325033984, 140400333422591,
+SNULL, 140400627003392, 140400635396095,
+STORE, 140400635396096, 140400643788799,
+STORE, 140400627003392, 140400635396095,
+SNULL, 140400635400191, 140400643788799,
+STORE, 140400635396096, 140400635400191,
+STORE, 140400635400192, 140400643788799,
+SNULL, 140400434073599, 140400442462207,
+STORE, 140400434069504, 140400434073599,
+STORE, 140400434073600, 140400442462207,
+STORE, 140400618610688, 140400635396095,
+STORE, 140400610217984, 140400635396095,
+SNULL, 140400954159104, 140400962547711,
+STORE, 140400962547712, 140400987725823,
+STORE, 140400954159104, 140400962547711,
+SNULL, 140400962551807, 140400987725823,
+STORE, 140400962547712, 140400962551807,
+STORE, 140400962551808, 140400987725823,
+SNULL, 140400299855872, 140400308244479,
+STORE, 140400308244480, 140400316637183,
+STORE, 140400299855872, 140400308244479,
+SNULL, 140400308248575, 140400316637183,
+STORE, 140400308244480, 140400308248575,
+STORE, 140400308248576, 140400316637183,
+STORE, 140400601825280, 140400635396095,
+SNULL, 140400601829375, 140400635396095,
+STORE, 140400601825280, 140400601829375,
+STORE, 140400601829376, 140400635396095,
+STORE, 140400576679936, 140400593465343,
+SNULL, 140400576684031, 140400593465343,
+STORE, 140400576679936, 140400576684031,
+STORE, 140400576684032, 140400593465343,
+SNULL, 140400643792896, 140400652181503,
+STORE, 140400652181504, 140400668966911,
+STORE, 140400643792896, 140400652181503,
+SNULL, 140400652185599, 140400668966911,
+STORE, 140400652181504, 140400652185599,
+STORE, 140400652185600, 140400668966911,
+STORE, 140399595225088, 140399796551679,
+SNULL, 140399662333951, 140399796551679,
+STORE, 140399595225088, 140399662333951,
+STORE, 140399662333952, 140399796551679,
+SNULL, 140399662333952, 140399729442815,
+STORE, 140399729442816, 140399796551679,
+STORE, 140399662333952, 140399729442815,
+ERASE, 140399662333952, 140399729442815,
+SNULL, 140399863795711, 140399930769407,
+STORE, 140399863660544, 140399863795711,
+STORE, 140399863795712, 140399930769407,
+STORE, 140400568287232, 140400576679935,
+SNULL, 140400568291327, 140400576679935,
+STORE, 140400568287232, 140400568291327,
+STORE, 140400568291328, 140400576679935,
+SNULL, 140400467775487, 140400534749183,
+STORE, 140400467640320, 140400467775487,
+STORE, 140400467775488, 140400534749183,
+SNULL, 140399729577983, 140399796551679,
+STORE, 140399729442816, 140399729577983,
+STORE, 140399729577984, 140399796551679,
+SNULL, 140400601829376, 140400627003391,
+STORE, 140400627003392, 140400635396095,
+STORE, 140400601829376, 140400627003391,
+SNULL, 140400627007487, 140400635396095,
+STORE, 140400627003392, 140400627007487,
+STORE, 140400627007488, 140400635396095,
+STORE, 140400559894528, 140400568287231,
+STORE, 140400551501824, 140400568287231,
+STORE, 140400543109120, 140400568287231,
+STORE, 140400459247616, 140400467640319,
+STORE, 140400442466304, 140400467640319,
+SNULL, 140399595360255, 140399662333951,
+STORE, 140399595225088, 140399595360255,
+STORE, 140399595360256, 140399662333951,
+SNULL, 140400962551808, 140400970940415,
+STORE, 140400970940416, 140400987725823,
+STORE, 140400962551808, 140400970940415,
+SNULL, 140400970944511, 140400987725823,
+STORE, 140400970940416, 140400970944511,
+STORE, 140400970944512, 140400987725823,
+SNULL, 140400652185600, 140400660574207,
+STORE, 140400660574208, 140400668966911,
+STORE, 140400652185600, 140400660574207,
+SNULL, 140400660578303, 140400668966911,
+STORE, 140400660574208, 140400660578303,
+STORE, 140400660578304, 140400668966911,
+SNULL, 140400576684032, 140400585072639,
+STORE, 140400585072640, 140400593465343,
+STORE, 140400576684032, 140400585072639,
+SNULL, 140400585076735, 140400593465343,
+STORE, 140400585072640, 140400585076735,
+STORE, 140400585076736, 140400593465343,
+STORE, 140400425676800, 140400434069503,
+STORE, 140400417284096, 140400434069503,
+STORE, 140400408891392, 140400434069503,
+SNULL, 140400408891392, 140400417284095,
+STORE, 140400417284096, 140400434069503,
+STORE, 140400408891392, 140400417284095,
+SNULL, 140400417288191, 140400434069503,
+STORE, 140400417284096, 140400417288191,
+STORE, 140400417288192, 140400434069503,
+STORE, 140400283066368, 140400291459071,
+SNULL, 140400601829376, 140400618610687,
+STORE, 140400618610688, 140400627003391,
+STORE, 140400601829376, 140400618610687,
+SNULL, 140400618614783, 140400627003391,
+STORE, 140400618610688, 140400618614783,
+STORE, 140400618614784, 140400627003391,
+SNULL, 140400601829376, 140400610217983,
+STORE, 140400610217984, 140400618610687,
+STORE, 140400601829376, 140400610217983,
+SNULL, 140400610222079, 140400618610687,
+STORE, 140400610217984, 140400610222079,
+STORE, 140400610222080, 140400618610687,
+STORE, 140400274673664, 140400291459071,
+STORE, 140400190812160, 140400199204863,
+STORE, 140400182419456, 140400199204863,
+SNULL, 140400442466304, 140400450854911,
+STORE, 140400450854912, 140400467640319,
+STORE, 140400442466304, 140400450854911,
+SNULL, 140400450859007, 140400467640319,
+STORE, 140400450854912, 140400450859007,
+STORE, 140400450859008, 140400467640319,
+SNULL, 140400543109120, 140400559894527,
+STORE, 140400559894528, 140400568287231,
+STORE, 140400543109120, 140400559894527,
+SNULL, 140400559898623, 140400568287231,
+STORE, 140400559894528, 140400559898623,
+STORE, 140400559898624, 140400568287231,
+SNULL, 140400450859008, 140400459247615,
+STORE, 140400459247616, 140400467640319,
+STORE, 140400450859008, 140400459247615,
+SNULL, 140400459251711, 140400467640319,
+STORE, 140400459247616, 140400459251711,
+STORE, 140400459251712, 140400467640319,
+SNULL, 140400543113215, 140400559894527,
+STORE, 140400543109120, 140400543113215,
+STORE, 140400543113216, 140400559894527,
+SNULL, 140400970944512, 140400979333119,
+STORE, 140400979333120, 140400987725823,
+STORE, 140400970944512, 140400979333119,
+SNULL, 140400979337215, 140400987725823,
+STORE, 140400979333120, 140400979337215,
+STORE, 140400979337216, 140400987725823,
+STORE, 140400174026752, 140400199204863,
+SNULL, 140400174030847, 140400199204863,
+STORE, 140400174026752, 140400174030847,
+STORE, 140400174030848, 140400199204863,
+SNULL, 140400274673664, 140400283066367,
+STORE, 140400283066368, 140400291459071,
+STORE, 140400274673664, 140400283066367,
+SNULL, 140400283070463, 140400291459071,
+STORE, 140400283066368, 140400283070463,
+STORE, 140400283070464, 140400291459071,
+STORE, 140400165634048, 140400174026751,
+SNULL, 140400165638143, 140400174026751,
+STORE, 140400165634048, 140400165638143,
+STORE, 140400165638144, 140400174026751,
+SNULL, 140400174030848, 140400182419455,
+STORE, 140400182419456, 140400199204863,
+STORE, 140400174030848, 140400182419455,
+SNULL, 140400182423551, 140400199204863,
+STORE, 140400182419456, 140400182423551,
+STORE, 140400182423552, 140400199204863,
+SNULL, 140400182423552, 140400190812159,
+STORE, 140400190812160, 140400199204863,
+STORE, 140400182423552, 140400190812159,
+SNULL, 140400190816255, 140400199204863,
+STORE, 140400190812160, 140400190816255,
+STORE, 140400190816256, 140400199204863,
+STORE, 140400157241344, 140400165634047,
+SNULL, 140400157245439, 140400165634047,
+STORE, 140400157241344, 140400157245439,
+STORE, 140400157245440, 140400165634047,
+SNULL, 140400408895487, 140400417284095,
+STORE, 140400408891392, 140400408895487,
+STORE, 140400408895488, 140400417284095,
+SNULL, 140400417288192, 140400425676799,
+STORE, 140400425676800, 140400434069503,
+STORE, 140400417288192, 140400425676799,
+SNULL, 140400425680895, 140400434069503,
+STORE, 140400425676800, 140400425680895,
+STORE, 140400425680896, 140400434069503,
+STORE, 140400148848640, 140400157241343,
+SNULL, 140400148852735, 140400157241343,
+STORE, 140400148848640, 140400148852735,
+STORE, 140400148852736, 140400157241343,
+SNULL, 140400543113216, 140400551501823,
+STORE, 140400551501824, 140400559894527,
+STORE, 140400543113216, 140400551501823,
+SNULL, 140400551505919, 140400559894527,
+STORE, 140400551501824, 140400551505919,
+STORE, 140400551505920, 140400559894527,
+STORE, 140400140455936, 140400148848639,
+STORE, 140400048201728, 140400056594431,
+SNULL, 140400140460031, 140400148848639,
+STORE, 140400140455936, 140400140460031,
+STORE, 140400140460032, 140400148848639,
+STORE, 140400039809024, 140400056594431,
+SNULL, 140400039813119, 140400056594431,
+STORE, 140400039809024, 140400039813119,
+STORE, 140400039813120, 140400056594431,
+STORE, 140400031416320, 140400039809023,
+STORE, 140400023023616, 140400039809023,
+SNULL, 140400274677759, 140400283066367,
+STORE, 140400274673664, 140400274677759,
+STORE, 140400274677760, 140400283066367,
+STORE, 140400014630912, 140400039809023,
+STORE, 140400006238208, 140400039809023,
+STORE, 140399997845504, 140400039809023,
+SNULL, 140399997849599, 140400039809023,
+STORE, 140399997845504, 140399997849599,
+STORE, 140399997849600, 140400039809023,
+STORE, 140399989452800, 140399997845503,
+SNULL, 140399989456895, 140399997845503,
+STORE, 140399989452800, 140399989456895,
+STORE, 140399989456896, 140399997845503,
+STORE, 140399981060096, 140399989452799,
+SNULL, 140399981064191, 140399989452799,
+STORE, 140399981060096, 140399981064191,
+STORE, 140399981064192, 140399989452799,
+STORE, 140399972667392, 140399981060095,
+STORE, 140399964274688, 140399981060095,
+SNULL, 140399964278783, 140399981060095,
+STORE, 140399964274688, 140399964278783,
+STORE, 140399964278784, 140399981060095,
+SNULL, 140400039813120, 140400048201727,
+STORE, 140400048201728, 140400056594431,
+STORE, 140400039813120, 140400048201727,
+SNULL, 140400048205823, 140400056594431,
+STORE, 140400048201728, 140400048205823,
+STORE, 140400048205824, 140400056594431,
+SNULL, 140399997849600, 140400031416319,
+STORE, 140400031416320, 140400039809023,
+STORE, 140399997849600, 140400031416319,
+SNULL, 140400031420415, 140400039809023,
+STORE, 140400031416320, 140400031420415,
+STORE, 140400031420416, 140400039809023,
+STORE, 140399955881984, 140399964274687,
+SNULL, 140399955886079, 140399964274687,
+STORE, 140399955881984, 140399955886079,
+STORE, 140399955886080, 140399964274687,
+STORE, 140399947489280, 140399955881983,
+STORE, 140399939096576, 140399955881983,
+STORE, 140399855267840, 140399863660543,
+SNULL, 140399939100671, 140399955881983,
+STORE, 140399939096576, 140399939100671,
+STORE, 140399939100672, 140399955881983,
+SNULL, 140399997849600, 140400014630911,
+STORE, 140400014630912, 140400031416319,
+STORE, 140399997849600, 140400014630911,
+SNULL, 140400014635007, 140400031416319,
+STORE, 140400014630912, 140400014635007,
+STORE, 140400014635008, 140400031416319,
+SNULL, 140400014635008, 140400023023615,
+STORE, 140400023023616, 140400031416319,
+STORE, 140400014635008, 140400023023615,
+SNULL, 140400023027711, 140400031416319,
+STORE, 140400023023616, 140400023027711,
+STORE, 140400023027712, 140400031416319,
+SNULL, 140399997849600, 140400006238207,
+STORE, 140400006238208, 140400014630911,
+STORE, 140399997849600, 140400006238207,
+SNULL, 140400006242303, 140400014630911,
+STORE, 140400006238208, 140400006242303,
+STORE, 140400006242304, 140400014630911,
+STORE, 140399846875136, 140399863660543,
+STORE, 140399838482432, 140399863660543,
+SNULL, 140399838486527, 140399863660543,
+STORE, 140399838482432, 140399838486527,
+STORE, 140399838486528, 140399863660543,
+SNULL, 140399939100672, 140399947489279,
+STORE, 140399947489280, 140399955881983,
+STORE, 140399939100672, 140399947489279,
+SNULL, 140399947493375, 140399955881983,
+STORE, 140399947489280, 140399947493375,
+STORE, 140399947493376, 140399955881983,
+SNULL, 140399964278784, 140399972667391,
+STORE, 140399972667392, 140399981060095,
+STORE, 140399964278784, 140399972667391,
+SNULL, 140399972671487, 140399981060095,
+STORE, 140399972667392, 140399972671487,
+STORE, 140399972671488, 140399981060095,
+SNULL, 140399838486528, 140399855267839,
+STORE, 140399855267840, 140399863660543,
+STORE, 140399838486528, 140399855267839,
+SNULL, 140399855271935, 140399863660543,
+STORE, 140399855267840, 140399855271935,
+STORE, 140399855271936, 140399863660543,
+STORE, 140399830089728, 140399838482431,
+SNULL, 140399830093823, 140399838482431,
+STORE, 140399830089728, 140399830093823,
+STORE, 140399830093824, 140399838482431,
+STORE, 140399821697024, 140399830089727,
+SNULL, 140399821701119, 140399830089727,
+STORE, 140399821697024, 140399821701119,
+STORE, 140399821701120, 140399830089727,
+SNULL, 140399838486528, 140399846875135,
+STORE, 140399846875136, 140399855267839,
+STORE, 140399838486528, 140399846875135,
+SNULL, 140399846879231, 140399855267839,
+STORE, 140399846875136, 140399846879231,
+STORE, 140399846879232, 140399855267839,
+STORE, 140399813304320, 140399821697023,
+STORE, 140399804911616, 140399821697023,
+SNULL, 140399804915711, 140399821697023,
+STORE, 140399804911616, 140399804915711,
+STORE, 140399804915712, 140399821697023,
+STORE, 140399721050112, 140399729442815,
+SNULL, 140399804915712, 140399813304319,
+STORE, 140399813304320, 140399821697023,
+STORE, 140399804915712, 140399813304319,
+SNULL, 140399813308415, 140399821697023,
+STORE, 140399813304320, 140399813308415,
+STORE, 140399813308416, 140399821697023,
+SNULL, 140399721054207, 140399729442815,
+STORE, 140399721050112, 140399721054207,
+STORE, 140399721054208, 140399729442815,
+STORE, 140401467105280, 140401467133951,
+STORE, 140401279115264, 140401281306623,
+SNULL, 140401279115264, 140401279205375,
+STORE, 140401279205376, 140401281306623,
+STORE, 140401279115264, 140401279205375,
+SNULL, 140401281298431, 140401281306623,
+STORE, 140401279205376, 140401281298431,
+STORE, 140401281298432, 140401281306623,
+ERASE, 140401281298432, 140401281306623,
+STORE, 140401281298432, 140401281306623,
+SNULL, 140401281302527, 140401281306623,
+STORE, 140401281298432, 140401281302527,
+STORE, 140401281302528, 140401281306623,
+ERASE, 140401467105280, 140401467133951,
+ERASE, 140400056594432, 140400056598527,
+ERASE, 140400056598528, 140400064987135,
+ERASE, 140400635396096, 140400635400191,
+ERASE, 140400635400192, 140400643788799,
+ERASE, 140400408891392, 140400408895487,
+ERASE, 140400408895488, 140400417284095,
+ERASE, 140400299851776, 140400299855871,
+ERASE, 140400299855872, 140400308244479,
+ERASE, 140400627003392, 140400627007487,
+ERASE, 140400627007488, 140400635396095,
+ERASE, 140400954155008, 140400954159103,
+ERASE, 140400954159104, 140400962547711,
+ERASE, 140400291459072, 140400291463167,
+ERASE, 140400291463168, 140400299851775,
+ERASE, 140400643788800, 140400643792895,
+ERASE, 140400643792896, 140400652181503,
+ERASE, 140400325029888, 140400325033983,
+ERASE, 140400325033984, 140400333422591,
+ERASE, 140400610217984, 140400610222079,
+ERASE, 140400610222080, 140400618610687,
+ERASE, 140400190812160, 140400190816255,
+ERASE, 140400190816256, 140400199204863,
+ERASE, 140399964274688, 140399964278783,
+ERASE, 140399964278784, 140399972667391,
+ERASE, 140400945762304, 140400945766399,
+ERASE, 140400945766400, 140400954155007,
+ERASE, 140400568287232, 140400568291327,
+ERASE, 140400568291328, 140400576679935,
+ERASE, 140399972667392, 140399972671487,
+ERASE, 140399972671488, 140399981060095,
+ERASE, 140400962547712, 140400962551807,
+ERASE, 140400962551808, 140400970940415,
+ERASE, 140400987725824, 140400987729919,
+ERASE, 140400987729920, 140400996118527,
+ERASE, 140400652181504, 140400652185599,
+ERASE, 140400652185600, 140400660574207,
+ERASE, 140400450854912, 140400450859007,
+ERASE, 140400450859008, 140400459247615,
+ERASE, 140400031416320, 140400031420415,
+ERASE, 140400031420416, 140400039809023,
+ERASE, 140400308244480, 140400308248575,
+ERASE, 140400308248576, 140400316637183,
+ERASE, 140400434069504, 140400434073599,
+ERASE, 140400434073600, 140400442462207,
+ERASE, 140400543109120, 140400543113215,
+ERASE, 140400543113216, 140400551501823,
+ERASE, 140400023023616, 140400023027711,
+ERASE, 140400023027712, 140400031416319,
+ERASE, 140399813304320, 140399813308415,
+ERASE, 140399813308416, 140399821697023,
+ERASE, 140400316637184, 140400316641279,
+ERASE, 140400316641280, 140400325029887,
+ERASE, 140400585072640, 140400585076735,
+ERASE, 140400585076736, 140400593465343,
+ERASE, 140400148848640, 140400148852735,
+ERASE, 140400148852736, 140400157241343,
+ERASE, 140399955881984, 140399955886079,
+ERASE, 140399955886080, 140399964274687,
+ERASE, 140399821697024, 140399821701119,
+ERASE, 140399821701120, 140399830089727,
+ERASE, 140400601825280, 140400601829375,
+ERASE, 140400601829376, 140400610217983,
+ERASE, 140400979333120, 140400979337215,
+ERASE, 140400979337216, 140400987725823,
+ERASE, 140399997845504, 140399997849599,
+ERASE, 140399997849600, 140400006238207,
+ERASE, 140400459247616, 140400459251711,
+ERASE, 140400459251712, 140400467640319,
+ERASE, 140400551501824, 140400551505919,
+ERASE, 140400551505920, 140400559894527,
+ERASE, 140399939096576, 140399939100671,
+ERASE, 140399939100672, 140399947489279,
+ERASE, 140400442462208, 140400442466303,
+ERASE, 140400442466304, 140400450854911,
+ERASE, 140400576679936, 140400576684031,
+ERASE, 140400576684032, 140400585072639,
+ERASE, 140400559894528, 140400559898623,
+ERASE, 140400559898624, 140400568287231,
+ERASE, 140400417284096, 140400417288191,
+ERASE, 140400417288192, 140400425676799,
+ERASE, 140400283066368, 140400283070463,
+ERASE, 140400283070464, 140400291459071,
+ };
+ unsigned long set33[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140734562918400, 140737488351231,
+SNULL, 140734562922495, 140737488351231,
+STORE, 140734562918400, 140734562922495,
+STORE, 140734562787328, 140734562922495,
+STORE, 94133878984704, 94133881237503,
+SNULL, 94133879115775, 94133881237503,
+STORE, 94133878984704, 94133879115775,
+STORE, 94133879115776, 94133881237503,
+ERASE, 94133879115776, 94133881237503,
+STORE, 94133881208832, 94133881217023,
+STORE, 94133881217024, 94133881237503,
+STORE, 140583654043648, 140583656296447,
+SNULL, 140583654187007, 140583656296447,
+STORE, 140583654043648, 140583654187007,
+STORE, 140583654187008, 140583656296447,
+ERASE, 140583654187008, 140583656296447,
+STORE, 140583656284160, 140583656292351,
+STORE, 140583656292352, 140583656296447,
+STORE, 140734564319232, 140734564323327,
+STORE, 140734564306944, 140734564319231,
+STORE, 140583656255488, 140583656284159,
+STORE, 140583656247296, 140583656255487,
+STORE, 140583651827712, 140583654043647,
+SNULL, 140583651827712, 140583651926015,
+STORE, 140583651926016, 140583654043647,
+STORE, 140583651827712, 140583651926015,
+SNULL, 140583654019071, 140583654043647,
+STORE, 140583651926016, 140583654019071,
+STORE, 140583654019072, 140583654043647,
+SNULL, 140583654019072, 140583654027263,
+STORE, 140583654027264, 140583654043647,
+STORE, 140583654019072, 140583654027263,
+ERASE, 140583654019072, 140583654027263,
+STORE, 140583654019072, 140583654027263,
+ERASE, 140583654027264, 140583654043647,
+STORE, 140583654027264, 140583654043647,
+STORE, 140583648030720, 140583651827711,
+SNULL, 140583648030720, 140583649689599,
+STORE, 140583649689600, 140583651827711,
+STORE, 140583648030720, 140583649689599,
+SNULL, 140583651786751, 140583651827711,
+STORE, 140583649689600, 140583651786751,
+STORE, 140583651786752, 140583651827711,
+SNULL, 140583651786752, 140583651811327,
+STORE, 140583651811328, 140583651827711,
+STORE, 140583651786752, 140583651811327,
+ERASE, 140583651786752, 140583651811327,
+STORE, 140583651786752, 140583651811327,
+ERASE, 140583651811328, 140583651827711,
+STORE, 140583651811328, 140583651827711,
+STORE, 140583656239104, 140583656255487,
+SNULL, 140583651803135, 140583651811327,
+STORE, 140583651786752, 140583651803135,
+STORE, 140583651803136, 140583651811327,
+SNULL, 140583654023167, 140583654027263,
+STORE, 140583654019072, 140583654023167,
+STORE, 140583654023168, 140583654027263,
+SNULL, 94133881212927, 94133881217023,
+STORE, 94133881208832, 94133881212927,
+STORE, 94133881212928, 94133881217023,
+SNULL, 140583656288255, 140583656292351,
+STORE, 140583656284160, 140583656288255,
+STORE, 140583656288256, 140583656292351,
+ERASE, 140583656255488, 140583656284159,
+STORE, 94133881733120, 94133881868287,
+STORE, 140583639638016, 140583648030719,
+SNULL, 140583639642111, 140583648030719,
+STORE, 140583639638016, 140583639642111,
+STORE, 140583639642112, 140583648030719,
+STORE, 140583631245312, 140583639638015,
+STORE, 140583497027584, 140583631245311,
+SNULL, 140583497027584, 140583540621311,
+STORE, 140583540621312, 140583631245311,
+STORE, 140583497027584, 140583540621311,
+ERASE, 140583497027584, 140583540621311,
+SNULL, 140583607730175, 140583631245311,
+STORE, 140583540621312, 140583607730175,
+STORE, 140583607730176, 140583631245311,
+ERASE, 140583607730176, 140583631245311,
+SNULL, 140583540756479, 140583607730175,
+STORE, 140583540621312, 140583540756479,
+STORE, 140583540756480, 140583607730175,
+SNULL, 140583631249407, 140583639638015,
+STORE, 140583631245312, 140583631249407,
+STORE, 140583631249408, 140583639638015,
+STORE, 140583622852608, 140583631245311,
+SNULL, 140583622856703, 140583631245311,
+STORE, 140583622852608, 140583622856703,
+STORE, 140583622856704, 140583631245311,
+STORE, 140583614459904, 140583622852607,
+SNULL, 140583614463999, 140583622852607,
+STORE, 140583614459904, 140583614463999,
+STORE, 140583614464000, 140583622852607,
+STORE, 140583532228608, 140583540621311,
+SNULL, 140583532232703, 140583540621311,
+STORE, 140583532228608, 140583532232703,
+STORE, 140583532232704, 140583540621311,
+STORE, 140583523835904, 140583532228607,
+STORE, 140583515443200, 140583532228607,
+STORE, 140583507050496, 140583532228607,
+STORE, 140583372832768, 140583507050495,
+STORE, 140583364440064, 140583372832767,
+STORE, 140583230222336, 140583364440063,
+STORE, 140583096004608, 140583364440063,
+SNULL, 140583230222335, 140583364440063,
+STORE, 140583096004608, 140583230222335,
+STORE, 140583230222336, 140583364440063,
+SNULL, 140583230222336, 140583272185855,
+STORE, 140583272185856, 140583364440063,
+STORE, 140583230222336, 140583272185855,
+ERASE, 140583230222336, 140583272185855,
+STORE, 140582961786880, 140583230222335,
+SNULL, 140583372832768, 140583406403583,
+STORE, 140583406403584, 140583507050495,
+STORE, 140583372832768, 140583406403583,
+ERASE, 140583372832768, 140583406403583,
+SNULL, 140583473512447, 140583507050495,
+STORE, 140583406403584, 140583473512447,
+STORE, 140583473512448, 140583507050495,
+ERASE, 140583473512448, 140583507050495,
+SNULL, 140583096004607, 140583230222335,
+STORE, 140582961786880, 140583096004607,
+STORE, 140583096004608, 140583230222335,
+SNULL, 140583096004608, 140583137968127,
+STORE, 140583137968128, 140583230222335,
+STORE, 140583096004608, 140583137968127,
+ERASE, 140583096004608, 140583137968127,
+SNULL, 140583339294719, 140583364440063,
+STORE, 140583272185856, 140583339294719,
+STORE, 140583339294720, 140583364440063,
+ERASE, 140583339294720, 140583364440063,
+SNULL, 140583272321023, 140583339294719,
+STORE, 140583272185856, 140583272321023,
+STORE, 140583272321024, 140583339294719,
+SNULL, 140582961786880, 140583003750399,
+STORE, 140583003750400, 140583096004607,
+STORE, 140582961786880, 140583003750399,
+ERASE, 140582961786880, 140583003750399,
+ };
+
+ unsigned long set34[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140731327180800, 140737488351231,
+SNULL, 140731327184895, 140737488351231,
+STORE, 140731327180800, 140731327184895,
+STORE, 140731327049728, 140731327184895,
+STORE, 94632924487680, 94632926740479,
+SNULL, 94632924618751, 94632926740479,
+STORE, 94632924487680, 94632924618751,
+STORE, 94632924618752, 94632926740479,
+ERASE, 94632924618752, 94632926740479,
+STORE, 94632926711808, 94632926719999,
+STORE, 94632926720000, 94632926740479,
+STORE, 140012544888832, 140012547141631,
+SNULL, 140012545032191, 140012547141631,
+STORE, 140012544888832, 140012545032191,
+STORE, 140012545032192, 140012547141631,
+ERASE, 140012545032192, 140012547141631,
+STORE, 140012547129344, 140012547137535,
+STORE, 140012547137536, 140012547141631,
+STORE, 140731327725568, 140731327729663,
+STORE, 140731327713280, 140731327725567,
+STORE, 140012547100672, 140012547129343,
+STORE, 140012547092480, 140012547100671,
+STORE, 140012542672896, 140012544888831,
+SNULL, 140012542672896, 140012542771199,
+STORE, 140012542771200, 140012544888831,
+STORE, 140012542672896, 140012542771199,
+SNULL, 140012544864255, 140012544888831,
+STORE, 140012542771200, 140012544864255,
+STORE, 140012544864256, 140012544888831,
+SNULL, 140012544864256, 140012544872447,
+STORE, 140012544872448, 140012544888831,
+STORE, 140012544864256, 140012544872447,
+ERASE, 140012544864256, 140012544872447,
+STORE, 140012544864256, 140012544872447,
+ERASE, 140012544872448, 140012544888831,
+STORE, 140012544872448, 140012544888831,
+STORE, 140012538875904, 140012542672895,
+SNULL, 140012538875904, 140012540534783,
+STORE, 140012540534784, 140012542672895,
+STORE, 140012538875904, 140012540534783,
+SNULL, 140012542631935, 140012542672895,
+STORE, 140012540534784, 140012542631935,
+STORE, 140012542631936, 140012542672895,
+SNULL, 140012542631936, 140012542656511,
+STORE, 140012542656512, 140012542672895,
+STORE, 140012542631936, 140012542656511,
+ERASE, 140012542631936, 140012542656511,
+STORE, 140012542631936, 140012542656511,
+ERASE, 140012542656512, 140012542672895,
+STORE, 140012542656512, 140012542672895,
+STORE, 140012547084288, 140012547100671,
+SNULL, 140012542648319, 140012542656511,
+STORE, 140012542631936, 140012542648319,
+STORE, 140012542648320, 140012542656511,
+SNULL, 140012544868351, 140012544872447,
+STORE, 140012544864256, 140012544868351,
+STORE, 140012544868352, 140012544872447,
+SNULL, 94632926715903, 94632926719999,
+STORE, 94632926711808, 94632926715903,
+STORE, 94632926715904, 94632926719999,
+SNULL, 140012547133439, 140012547137535,
+STORE, 140012547129344, 140012547133439,
+STORE, 140012547133440, 140012547137535,
+ERASE, 140012547100672, 140012547129343,
+STORE, 94632939606016, 94632939741183,
+STORE, 140012530483200, 140012538875903,
+SNULL, 140012530487295, 140012538875903,
+STORE, 140012530483200, 140012530487295,
+STORE, 140012530487296, 140012538875903,
+STORE, 140012522090496, 140012530483199,
+STORE, 140012387872768, 140012522090495,
+SNULL, 140012387872768, 140012444188671,
+STORE, 140012444188672, 140012522090495,
+STORE, 140012387872768, 140012444188671,
+ERASE, 140012387872768, 140012444188671,
+SNULL, 140012511297535, 140012522090495,
+STORE, 140012444188672, 140012511297535,
+STORE, 140012511297536, 140012522090495,
+ERASE, 140012511297536, 140012522090495,
+SNULL, 140012444323839, 140012511297535,
+STORE, 140012444188672, 140012444323839,
+STORE, 140012444323840, 140012511297535,
+SNULL, 140012522094591, 140012530483199,
+STORE, 140012522090496, 140012522094591,
+STORE, 140012522094592, 140012530483199,
+STORE, 140012513697792, 140012522090495,
+SNULL, 140012513701887, 140012522090495,
+STORE, 140012513697792, 140012513701887,
+STORE, 140012513701888, 140012522090495,
+STORE, 140012435795968, 140012444188671,
+SNULL, 140012435800063, 140012444188671,
+STORE, 140012435795968, 140012435800063,
+STORE, 140012435800064, 140012444188671,
+STORE, 140012427403264, 140012435795967,
+SNULL, 140012427407359, 140012435795967,
+STORE, 140012427403264, 140012427407359,
+STORE, 140012427407360, 140012435795967,
+STORE, 140012419010560, 140012427403263,
+STORE, 140012410617856, 140012427403263,
+STORE, 140012276400128, 140012410617855,
+STORE, 140012268007424, 140012276400127,
+STORE, 140012133789696, 140012268007423,
+SNULL, 140012133789696, 140012175753215,
+STORE, 140012175753216, 140012268007423,
+STORE, 140012133789696, 140012175753215,
+ERASE, 140012133789696, 140012175753215,
+STORE, 140012041535488, 140012268007423,
+SNULL, 140012108644351, 140012268007423,
+STORE, 140012041535488, 140012108644351,
+STORE, 140012108644352, 140012268007423,
+SNULL, 140012108644352, 140012175753215,
+STORE, 140012175753216, 140012268007423,
+STORE, 140012108644352, 140012175753215,
+ERASE, 140012108644352, 140012175753215,
+SNULL, 140012276400128, 140012309970943,
+STORE, 140012309970944, 140012410617855,
+STORE, 140012276400128, 140012309970943,
+ERASE, 140012276400128, 140012309970943,
+STORE, 140012301578240, 140012309970943,
+STORE, 140012041535488, 140012268007423,
+SNULL, 140012242862079, 140012268007423,
+STORE, 140012041535488, 140012242862079,
+STORE, 140012242862080, 140012268007423,
+ERASE, 140012242862080, 140012268007423,
+SNULL, 140012041670655, 140012242862079,
+STORE, 140012041535488, 140012041670655,
+STORE, 140012041670656, 140012242862079,
+SNULL, 140012041670656, 140012108644351,
+STORE, 140012108644352, 140012242862079,
+STORE, 140012041670656, 140012108644351,
+SNULL, 140012108779519, 140012242862079,
+STORE, 140012108644352, 140012108779519,
+STORE, 140012108779520, 140012242862079,
+SNULL, 140012377079807, 140012410617855,
+STORE, 140012309970944, 140012377079807,
+STORE, 140012377079808, 140012410617855,
+ERASE, 140012377079808, 140012410617855,
+SNULL, 140012310106111, 140012377079807,
+STORE, 140012309970944, 140012310106111,
+STORE, 140012310106112, 140012377079807,
+SNULL, 140012410621951, 140012427403263,
+STORE, 140012410617856, 140012410621951,
+STORE, 140012410621952, 140012427403263,
+SNULL, 140012108779520, 140012175753215,
+STORE, 140012175753216, 140012242862079,
+STORE, 140012108779520, 140012175753215,
+SNULL, 140012175888383, 140012242862079,
+STORE, 140012175753216, 140012175888383,
+STORE, 140012175888384, 140012242862079,
+SNULL, 140012301582335, 140012309970943,
+STORE, 140012301578240, 140012301582335,
+STORE, 140012301582336, 140012309970943,
+SNULL, 140012410621952, 140012419010559,
+STORE, 140012419010560, 140012427403263,
+STORE, 140012410621952, 140012419010559,
+SNULL, 140012419014655, 140012427403263,
+STORE, 140012419010560, 140012419014655,
+STORE, 140012419014656, 140012427403263,
+SNULL, 140012268011519, 140012276400127,
+STORE, 140012268007424, 140012268011519,
+STORE, 140012268011520, 140012276400127,
+STORE, 140012402225152, 140012410617855,
+STORE, 140012393832448, 140012410617855,
+SNULL, 140012393832448, 140012402225151,
+STORE, 140012402225152, 140012410617855,
+STORE, 140012393832448, 140012402225151,
+SNULL, 140012402229247, 140012410617855,
+STORE, 140012402225152, 140012402229247,
+STORE, 140012402229248, 140012410617855,
+STORE, 140012385439744, 140012402225151,
+SNULL, 140012385439744, 140012393832447,
+STORE, 140012393832448, 140012402225151,
+STORE, 140012385439744, 140012393832447,
+SNULL, 140012393836543, 140012402225151,
+STORE, 140012393832448, 140012393836543,
+STORE, 140012393836544, 140012402225151,
+STORE, 140012293185536, 140012301578239,
+STORE, 140012284792832, 140012301578239,
+SNULL, 140012284792832, 140012293185535,
+STORE, 140012293185536, 140012301578239,
+STORE, 140012284792832, 140012293185535,
+SNULL, 140012293189631, 140012301578239,
+STORE, 140012293185536, 140012293189631,
+STORE, 140012293189632, 140012301578239,
+STORE, 140012268011520, 140012284792831,
+SNULL, 140012385443839, 140012393832447,
+STORE, 140012385439744, 140012385443839,
+STORE, 140012385443840, 140012393832447,
+STORE, 140012259614720, 140012268007423,
+SNULL, 140012259618815, 140012268007423,
+STORE, 140012259614720, 140012259618815,
+STORE, 140012259618816, 140012268007423,
+STORE, 140012251222016, 140012259614719,
+SNULL, 140012251226111, 140012259614719,
+STORE, 140012251222016, 140012251226111,
+STORE, 140012251226112, 140012259614719,
+SNULL, 140012284796927, 140012293185535,
+STORE, 140012284792832, 140012284796927,
+STORE, 140012284796928, 140012293185535,
+SNULL, 140012268011520, 140012276400127,
+STORE, 140012276400128, 140012284792831,
+STORE, 140012268011520, 140012276400127,
+SNULL, 140012276404223, 140012284792831,
+STORE, 140012276400128, 140012276404223,
+STORE, 140012276404224, 140012284792831,
+STORE, 140012033142784, 140012041535487,
+SNULL, 140012033146879, 140012041535487,
+STORE, 140012033142784, 140012033146879,
+STORE, 140012033146880, 140012041535487,
+STORE, 140012024750080, 140012033142783,
+STORE, 140012016357376, 140012033142783,
+SNULL, 140012016357376, 140012024750079,
+STORE, 140012024750080, 140012033142783,
+STORE, 140012016357376, 140012024750079,
+SNULL, 140012024754175, 140012033142783,
+STORE, 140012024750080, 140012024754175,
+STORE, 140012024754176, 140012033142783,
+SNULL, 140012016361471, 140012024750079,
+STORE, 140012016357376, 140012016361471,
+STORE, 140012016361472, 140012024750079,
+STORE, 140012007964672, 140012016357375,
+SNULL, 140012007968767, 140012016357375,
+STORE, 140012007964672, 140012007968767,
+STORE, 140012007968768, 140012016357375,
+STORE, 140011999571968, 140012007964671,
+STORE, 140011991179264, 140012007964671,
+STORE, 140011856961536, 140011991179263,
+STORE, 140011848568832, 140011856961535,
+STORE, 140011714351104, 140011848568831,
+SNULL, 140011714351104, 140011773100031,
+STORE, 140011773100032, 140011848568831,
+STORE, 140011714351104, 140011773100031,
+ERASE, 140011714351104, 140011773100031,
+STORE, 140011764707328, 140011773100031,
+STORE, 140011756314624, 140011773100031,
+STORE, 140011622096896, 140011756314623,
+STORE, 140011613704192, 140011622096895,
+STORE, 140011479486464, 140011613704191,
+STORE, 140011471093760, 140011479486463,
+SNULL, 140011479486464, 140011504664575,
+STORE, 140011504664576, 140011613704191,
+STORE, 140011479486464, 140011504664575,
+ERASE, 140011479486464, 140011504664575,
+STORE, 140011496271872, 140011504664575,
+STORE, 140011487879168, 140011504664575,
+STORE, 140011336876032, 140011471093759,
+SNULL, 140011336876032, 140011370446847,
+STORE, 140011370446848, 140011471093759,
+STORE, 140011336876032, 140011370446847,
+ERASE, 140011336876032, 140011370446847,
+STORE, 140011471093760, 140011487879167,
+STORE, 140011362054144, 140011370446847,
+SNULL, 140011362058239, 140011370446847,
+STORE, 140011362054144, 140011362058239,
+STORE, 140011362058240, 140011370446847,
+STORE, 140011353661440, 140011362054143,
+STORE, 140011345268736, 140011362054143,
+SNULL, 140011345272831, 140011362054143,
+STORE, 140011345268736, 140011345272831,
+STORE, 140011345272832, 140011362054143,
+STORE, 140011336876032, 140011345268735,
+STORE, 140011328483328, 140011345268735,
+SNULL, 140011328487423, 140011345268735,
+STORE, 140011328483328, 140011328487423,
+STORE, 140011328487424, 140011345268735,
+STORE, 140011320090624, 140011328483327,
+STORE, 140011185872896, 140011320090623,
+SNULL, 140011185872896, 140011236229119,
+STORE, 140011236229120, 140011320090623,
+STORE, 140011185872896, 140011236229119,
+ERASE, 140011185872896, 140011236229119,
+SNULL, 140011856961536, 140011907317759,
+STORE, 140011907317760, 140011991179263,
+STORE, 140011856961536, 140011907317759,
+ERASE, 140011856961536, 140011907317759,
+SNULL, 140011974426623, 140011991179263,
+STORE, 140011907317760, 140011974426623,
+STORE, 140011974426624, 140011991179263,
+ERASE, 140011974426624, 140011991179263,
+SNULL, 140011840208895, 140011848568831,
+STORE, 140011773100032, 140011840208895,
+STORE, 140011840208896, 140011848568831,
+ERASE, 140011840208896, 140011848568831,
+SNULL, 140011773235199, 140011840208895,
+STORE, 140011773100032, 140011773235199,
+STORE, 140011773235200, 140011840208895,
+STORE, 140011102011392, 140011320090623,
+SNULL, 140011169120255, 140011320090623,
+STORE, 140011102011392, 140011169120255,
+STORE, 140011169120256, 140011320090623,
+SNULL, 140011169120256, 140011236229119,
+STORE, 140011236229120, 140011320090623,
+STORE, 140011169120256, 140011236229119,
+ERASE, 140011169120256, 140011236229119,
+SNULL, 140011622096896, 140011638882303,
+STORE, 140011638882304, 140011756314623,
+STORE, 140011622096896, 140011638882303,
+ERASE, 140011622096896, 140011638882303,
+SNULL, 140011705991167, 140011756314623,
+STORE, 140011638882304, 140011705991167,
+STORE, 140011705991168, 140011756314623,
+ERASE, 140011705991168, 140011756314623,
+SNULL, 140011571773439, 140011613704191,
+STORE, 140011504664576, 140011571773439,
+STORE, 140011571773440, 140011613704191,
+ERASE, 140011571773440, 140011613704191,
+STORE, 140010967793664, 140011169120255,
+SNULL, 140011034902527, 140011169120255,
+STORE, 140010967793664, 140011034902527,
+STORE, 140011034902528, 140011169120255,
+SNULL, 140011034902528, 140011102011391,
+STORE, 140011102011392, 140011169120255,
+STORE, 140011034902528, 140011102011391,
+ERASE, 140011034902528, 140011102011391,
+STORE, 140010833575936, 140011034902527,
+SNULL, 140011437555711, 140011471093759,
+STORE, 140011370446848, 140011437555711,
+STORE, 140011437555712, 140011471093759,
+ERASE, 140011437555712, 140011471093759,
+SNULL, 140011370582015, 140011437555711,
+STORE, 140011370446848, 140011370582015,
+STORE, 140011370582016, 140011437555711,
+STORE, 140010699358208, 140011034902527,
+SNULL, 140011487883263, 140011504664575,
+STORE, 140011487879168, 140011487883263,
+STORE, 140011487883264, 140011504664575,
+SNULL, 140011345272832, 140011353661439,
+STORE, 140011353661440, 140011362054143,
+STORE, 140011345272832, 140011353661439,
+SNULL, 140011353665535, 140011362054143,
+STORE, 140011353661440, 140011353665535,
+STORE, 140011353665536, 140011362054143,
+SNULL, 140011328487424, 140011336876031,
+STORE, 140011336876032, 140011345268735,
+STORE, 140011328487424, 140011336876031,
+SNULL, 140011336880127, 140011345268735,
+STORE, 140011336876032, 140011336880127,
+STORE, 140011336880128, 140011345268735,
+SNULL, 140011303337983, 140011320090623,
+STORE, 140011236229120, 140011303337983,
+STORE, 140011303337984, 140011320090623,
+ERASE, 140011303337984, 140011320090623,
+SNULL, 140011907452927, 140011974426623,
+STORE, 140011907317760, 140011907452927,
+STORE, 140011907452928, 140011974426623,
+SNULL, 140011102146559, 140011169120255,
+STORE, 140011102011392, 140011102146559,
+STORE, 140011102146560, 140011169120255,
+SNULL, 140011639017471, 140011705991167,
+STORE, 140011638882304, 140011639017471,
+STORE, 140011639017472, 140011705991167,
+SNULL, 140011504799743, 140011571773439,
+STORE, 140011504664576, 140011504799743,
+STORE, 140011504799744, 140011571773439,
+SNULL, 140011613708287, 140011622096895,
+STORE, 140011613704192, 140011613708287,
+STORE, 140011613708288, 140011622096895,
+SNULL, 140010699358208, 140010967793663,
+STORE, 140010967793664, 140011034902527,
+STORE, 140010699358208, 140010967793663,
+SNULL, 140010967928831, 140011034902527,
+STORE, 140010967793664, 140010967928831,
+STORE, 140010967928832, 140011034902527,
+SNULL, 140010900684799, 140010967793663,
+STORE, 140010699358208, 140010900684799,
+STORE, 140010900684800, 140010967793663,
+ERASE, 140010900684800, 140010967793663,
+SNULL, 140010766467071, 140010900684799,
+STORE, 140010699358208, 140010766467071,
+STORE, 140010766467072, 140010900684799,
+SNULL, 140010766467072, 140010833575935,
+STORE, 140010833575936, 140010900684799,
+STORE, 140010766467072, 140010833575935,
+ERASE, 140010766467072, 140010833575935,
+SNULL, 140010699493375, 140010766467071,
+STORE, 140010699358208, 140010699493375,
+STORE, 140010699493376, 140010766467071,
+SNULL, 140011848572927, 140011856961535,
+STORE, 140011848568832, 140011848572927,
+STORE, 140011848572928, 140011856961535,
+STORE, 140011982786560, 140012007964671,
+STORE, 140011898925056, 140011907317759,
+SNULL, 140011898929151, 140011907317759,
+STORE, 140011898925056, 140011898929151,
+STORE, 140011898929152, 140011907317759,
+SNULL, 140011320094719, 140011328483327,
+STORE, 140011320090624, 140011320094719,
+STORE, 140011320094720, 140011328483327,
+STORE, 140011890532352, 140011898925055,
+STORE, 140011882139648, 140011898925055,
+SNULL, 140011882143743, 140011898925055,
+STORE, 140011882139648, 140011882143743,
+STORE, 140011882143744, 140011898925055,
+STORE, 140011873746944, 140011882139647,
+SNULL, 140011873751039, 140011882139647,
+STORE, 140011873746944, 140011873751039,
+STORE, 140011873751040, 140011882139647,
+SNULL, 140011236364287, 140011303337983,
+STORE, 140011236229120, 140011236364287,
+STORE, 140011236364288, 140011303337983,
+SNULL, 140011756318719, 140011773100031,
+STORE, 140011756314624, 140011756318719,
+STORE, 140011756318720, 140011773100031,
+SNULL, 140011756318720, 140011764707327,
+STORE, 140011764707328, 140011773100031,
+STORE, 140011756318720, 140011764707327,
+SNULL, 140011764711423, 140011773100031,
+STORE, 140011764707328, 140011764711423,
+STORE, 140011764711424, 140011773100031,
+SNULL, 140011471097855, 140011487879167,
+STORE, 140011471093760, 140011471097855,
+STORE, 140011471097856, 140011487879167,
+SNULL, 140010833711103, 140010900684799,
+STORE, 140010833575936, 140010833711103,
+STORE, 140010833711104, 140010900684799,
+SNULL, 140011982790655, 140012007964671,
+STORE, 140011982786560, 140011982790655,
+STORE, 140011982790656, 140012007964671,
+STORE, 140011865354240, 140011873746943,
+STORE, 140011848572928, 140011865354239,
+SNULL, 140011848572928, 140011856961535,
+STORE, 140011856961536, 140011865354239,
+STORE, 140011848572928, 140011856961535,
+SNULL, 140011856965631, 140011865354239,
+STORE, 140011856961536, 140011856965631,
+STORE, 140011856965632, 140011865354239,
+STORE, 140011747921920, 140011756314623,
+STORE, 140011739529216, 140011756314623,
+SNULL, 140011471097856, 140011479486463,
+STORE, 140011479486464, 140011487879167,
+STORE, 140011471097856, 140011479486463,
+SNULL, 140011479490559, 140011487879167,
+STORE, 140011479486464, 140011479490559,
+STORE, 140011479490560, 140011487879167,
+STORE, 140011731136512, 140011756314623,
+STORE, 140011722743808, 140011756314623,
+SNULL, 140011982790656, 140011999571967,
+STORE, 140011999571968, 140012007964671,
+STORE, 140011982790656, 140011999571967,
+SNULL, 140011999576063, 140012007964671,
+STORE, 140011999571968, 140011999576063,
+STORE, 140011999576064, 140012007964671,
+STORE, 140011714351104, 140011756314623,
+SNULL, 140011882143744, 140011890532351,
+STORE, 140011890532352, 140011898925055,
+STORE, 140011882143744, 140011890532351,
+SNULL, 140011890536447, 140011898925055,
+STORE, 140011890532352, 140011890536447,
+STORE, 140011890536448, 140011898925055,
+STORE, 140011630489600, 140011638882303,
+STORE, 140011613708288, 140011638882303,
+STORE, 140011605311488, 140011613704191,
+STORE, 140011596918784, 140011613704191,
+STORE, 140011588526080, 140011613704191,
+SNULL, 140011487883264, 140011496271871,
+STORE, 140011496271872, 140011504664575,
+STORE, 140011487883264, 140011496271871,
+SNULL, 140011496275967, 140011504664575,
+STORE, 140011496271872, 140011496275967,
+STORE, 140011496275968, 140011504664575,
+STORE, 140011580133376, 140011613704191,
+SNULL, 140011580137471, 140011613704191,
+STORE, 140011580133376, 140011580137471,
+STORE, 140011580137472, 140011613704191,
+SNULL, 140011982790656, 140011991179263,
+STORE, 140011991179264, 140011999571967,
+STORE, 140011982790656, 140011991179263,
+SNULL, 140011991183359, 140011999571967,
+STORE, 140011991179264, 140011991183359,
+STORE, 140011991183360, 140011999571967,
+SNULL, 140011865358335, 140011873746943,
+STORE, 140011865354240, 140011865358335,
+STORE, 140011865358336, 140011873746943,
+STORE, 140011462701056, 140011471093759,
+SNULL, 140011714351104, 140011739529215,
+STORE, 140011739529216, 140011756314623,
+STORE, 140011714351104, 140011739529215,
+SNULL, 140011739533311, 140011756314623,
+STORE, 140011739529216, 140011739533311,
+STORE, 140011739533312, 140011756314623,
+SNULL, 140011739533312, 140011747921919,
+STORE, 140011747921920, 140011756314623,
+STORE, 140011739533312, 140011747921919,
+SNULL, 140011747926015, 140011756314623,
+STORE, 140011747921920, 140011747926015,
+STORE, 140011747926016, 140011756314623,
+SNULL, 140011613708288, 140011630489599,
+STORE, 140011630489600, 140011638882303,
+STORE, 140011613708288, 140011630489599,
+SNULL, 140011630493695, 140011638882303,
+STORE, 140011630489600, 140011630493695,
+STORE, 140011630493696, 140011638882303,
+SNULL, 140011714351104, 140011722743807,
+STORE, 140011722743808, 140011739529215,
+STORE, 140011714351104, 140011722743807,
+SNULL, 140011722747903, 140011739529215,
+STORE, 140011722743808, 140011722747903,
+STORE, 140011722747904, 140011739529215,
+SNULL, 140011714355199, 140011722743807,
+STORE, 140011714351104, 140011714355199,
+STORE, 140011714355200, 140011722743807,
+SNULL, 140011722747904, 140011731136511,
+STORE, 140011731136512, 140011739529215,
+STORE, 140011722747904, 140011731136511,
+SNULL, 140011731140607, 140011739529215,
+STORE, 140011731136512, 140011731140607,
+STORE, 140011731140608, 140011739529215,
+STORE, 140011454308352, 140011471093759,
+STORE, 140011445915648, 140011471093759,
+SNULL, 140011580137472, 140011588526079,
+STORE, 140011588526080, 140011613704191,
+STORE, 140011580137472, 140011588526079,
+SNULL, 140011588530175, 140011613704191,
+STORE, 140011588526080, 140011588530175,
+STORE, 140011588530176, 140011613704191,
+SNULL, 140011445915648, 140011462701055,
+STORE, 140011462701056, 140011471093759,
+STORE, 140011445915648, 140011462701055,
+SNULL, 140011462705151, 140011471093759,
+STORE, 140011462701056, 140011462705151,
+STORE, 140011462705152, 140011471093759,
+SNULL, 140011588530176, 140011596918783,
+STORE, 140011596918784, 140011613704191,
+STORE, 140011588530176, 140011596918783,
+SNULL, 140011596922879, 140011613704191,
+STORE, 140011596918784, 140011596922879,
+STORE, 140011596922880, 140011613704191,
+SNULL, 140011596922880, 140011605311487,
+STORE, 140011605311488, 140011613704191,
+STORE, 140011596922880, 140011605311487,
+SNULL, 140011605315583, 140011613704191,
+STORE, 140011605311488, 140011605315583,
+STORE, 140011605315584, 140011613704191,
+SNULL, 140011613708288, 140011622096895,
+STORE, 140011622096896, 140011630489599,
+STORE, 140011613708288, 140011622096895,
+SNULL, 140011622100991, 140011630489599,
+STORE, 140011622096896, 140011622100991,
+STORE, 140011622100992, 140011630489599,
+STORE, 140011311697920, 140011320090623,
+STORE, 140011227836416, 140011236229119,
+STORE, 140011219443712, 140011236229119,
+SNULL, 140011219447807, 140011236229119,
+STORE, 140011219443712, 140011219447807,
+STORE, 140011219447808, 140011236229119,
+STORE, 140011211051008, 140011219443711,
+STORE, 140011202658304, 140011219443711,
+SNULL, 140011202662399, 140011219443711,
+STORE, 140011202658304, 140011202662399,
+STORE, 140011202662400, 140011219443711,
+STORE, 140011194265600, 140011202658303,
+STORE, 140011185872896, 140011202658303,
+STORE, 140011177480192, 140011202658303,
+STORE, 140011093618688, 140011102011391,
+SNULL, 140011445915648, 140011454308351,
+STORE, 140011454308352, 140011462701055,
+STORE, 140011445915648, 140011454308351,
+SNULL, 140011454312447, 140011462701055,
+STORE, 140011454308352, 140011454312447,
+STORE, 140011454312448, 140011462701055,
+STORE, 140011085225984, 140011102011391,
+SNULL, 140011085230079, 140011102011391,
+STORE, 140011085225984, 140011085230079,
+STORE, 140011085230080, 140011102011391,
+SNULL, 140011177484287, 140011202658303,
+STORE, 140011177480192, 140011177484287,
+STORE, 140011177484288, 140011202658303,
+SNULL, 140011445919743, 140011454308351,
+STORE, 140011445915648, 140011445919743,
+STORE, 140011445919744, 140011454308351,
+SNULL, 140011177484288, 140011185872895,
+STORE, 140011185872896, 140011202658303,
+STORE, 140011177484288, 140011185872895,
+SNULL, 140011185876991, 140011202658303,
+STORE, 140011185872896, 140011185876991,
+STORE, 140011185876992, 140011202658303,
+STORE, 140011076833280, 140011085225983,
+SNULL, 140011202662400, 140011211051007,
+STORE, 140011211051008, 140011219443711,
+STORE, 140011202662400, 140011211051007,
+SNULL, 140011211055103, 140011219443711,
+STORE, 140011211051008, 140011211055103,
+STORE, 140011211055104, 140011219443711,
+SNULL, 140011185876992, 140011194265599,
+STORE, 140011194265600, 140011202658303,
+STORE, 140011185876992, 140011194265599,
+SNULL, 140011194269695, 140011202658303,
+STORE, 140011194265600, 140011194269695,
+STORE, 140011194269696, 140011202658303,
+STORE, 140011068440576, 140011085225983,
+SNULL, 140011311702015, 140011320090623,
+STORE, 140011311697920, 140011311702015,
+STORE, 140011311702016, 140011320090623,
+STORE, 140011060047872, 140011085225983,
+SNULL, 140011060051967, 140011085225983,
+STORE, 140011060047872, 140011060051967,
+STORE, 140011060051968, 140011085225983,
+STORE, 140011051655168, 140011060047871,
+STORE, 140011043262464, 140011060047871,
+SNULL, 140011043266559, 140011060047871,
+STORE, 140011043262464, 140011043266559,
+STORE, 140011043266560, 140011060047871,
+SNULL, 140011219447808, 140011227836415,
+STORE, 140011227836416, 140011236229119,
+STORE, 140011219447808, 140011227836415,
+SNULL, 140011227840511, 140011236229119,
+STORE, 140011227836416, 140011227840511,
+STORE, 140011227840512, 140011236229119,
+SNULL, 140011085230080, 140011093618687,
+STORE, 140011093618688, 140011102011391,
+STORE, 140011085230080, 140011093618687,
+SNULL, 140011093622783, 140011102011391,
+STORE, 140011093618688, 140011093622783,
+STORE, 140011093622784, 140011102011391,
+STORE, 140010959400960, 140010967793663,
+STORE, 140010951008256, 140010967793663,
+SNULL, 140010951008256, 140010959400959,
+STORE, 140010959400960, 140010967793663,
+STORE, 140010951008256, 140010959400959,
+SNULL, 140010959405055, 140010967793663,
+STORE, 140010959400960, 140010959405055,
+STORE, 140010959405056, 140010967793663,
+STORE, 140010942615552, 140010959400959,
+STORE, 140010934222848, 140010959400959,
+SNULL, 140011060051968, 140011076833279,
+STORE, 140011076833280, 140011085225983,
+STORE, 140011060051968, 140011076833279,
+SNULL, 140011076837375, 140011085225983,
+STORE, 140011076833280, 140011076837375,
+STORE, 140011076837376, 140011085225983,
+SNULL, 140011043266560, 140011051655167,
+STORE, 140011051655168, 140011060047871,
+STORE, 140011043266560, 140011051655167,
+SNULL, 140011051659263, 140011060047871,
+STORE, 140011051655168, 140011051659263,
+STORE, 140011051659264, 140011060047871,
+STORE, 140010925830144, 140010959400959,
+SNULL, 140011060051968, 140011068440575,
+STORE, 140011068440576, 140011076833279,
+STORE, 140011060051968, 140011068440575,
+SNULL, 140011068444671, 140011076833279,
+STORE, 140011068440576, 140011068444671,
+STORE, 140011068444672, 140011076833279,
+STORE, 140010917437440, 140010959400959,
+STORE, 140010909044736, 140010959400959,
+STORE, 140010825183232, 140010833575935,
+SNULL, 140010909044736, 140010942615551,
+STORE, 140010942615552, 140010959400959,
+STORE, 140010909044736, 140010942615551,
+SNULL, 140010942619647, 140010959400959,
+STORE, 140010942615552, 140010942619647,
+STORE, 140010942619648, 140010959400959,
+SNULL, 140010909044736, 140010934222847,
+STORE, 140010934222848, 140010942615551,
+STORE, 140010909044736, 140010934222847,
+SNULL, 140010934226943, 140010942615551,
+STORE, 140010934222848, 140010934226943,
+STORE, 140010934226944, 140010942615551,
+SNULL, 140010909048831, 140010934222847,
+STORE, 140010909044736, 140010909048831,
+STORE, 140010909048832, 140010934222847,
+STORE, 140010816790528, 140010833575935,
+SNULL, 140010816794623, 140010833575935,
+STORE, 140010816790528, 140010816794623,
+STORE, 140010816794624, 140010833575935,
+STORE, 140010808397824, 140010816790527,
+SNULL, 140010942619648, 140010951008255,
+STORE, 140010951008256, 140010959400959,
+STORE, 140010942619648, 140010951008255,
+SNULL, 140010951012351, 140010959400959,
+STORE, 140010951008256, 140010951012351,
+STORE, 140010951012352, 140010959400959,
+STORE, 140010800005120, 140010816790527,
+SNULL, 140010800009215, 140010816790527,
+STORE, 140010800005120, 140010800009215,
+STORE, 140010800009216, 140010816790527,
+SNULL, 140010909048832, 140010925830143,
+STORE, 140010925830144, 140010934222847,
+STORE, 140010909048832, 140010925830143,
+SNULL, 140010925834239, 140010934222847,
+STORE, 140010925830144, 140010925834239,
+STORE, 140010925834240, 140010934222847,
+SNULL, 140010816794624, 140010825183231,
+STORE, 140010825183232, 140010833575935,
+STORE, 140010816794624, 140010825183231,
+SNULL, 140010825187327, 140010833575935,
+STORE, 140010825183232, 140010825187327,
+STORE, 140010825187328, 140010833575935,
+SNULL, 140010909048832, 140010917437439,
+STORE, 140010917437440, 140010925830143,
+STORE, 140010909048832, 140010917437439,
+SNULL, 140010917441535, 140010925830143,
+STORE, 140010917437440, 140010917441535,
+STORE, 140010917441536, 140010925830143,
+SNULL, 140010800009216, 140010808397823,
+STORE, 140010808397824, 140010816790527,
+STORE, 140010800009216, 140010808397823,
+SNULL, 140010808401919, 140010816790527,
+STORE, 140010808397824, 140010808401919,
+STORE, 140010808401920, 140010816790527,
+STORE, 140010791612416, 140010800005119,
+SNULL, 140010791616511, 140010800005119,
+STORE, 140010791612416, 140010791616511,
+STORE, 140010791616512, 140010800005119,
+STORE, 140012547100672, 140012547129343,
+STORE, 140012511506432, 140012513697791,
+SNULL, 140012511506432, 140012511596543,
+STORE, 140012511596544, 140012513697791,
+STORE, 140012511506432, 140012511596543,
+SNULL, 140012513689599, 140012513697791,
+STORE, 140012511596544, 140012513689599,
+STORE, 140012513689600, 140012513697791,
+ERASE, 140012513689600, 140012513697791,
+STORE, 140012513689600, 140012513697791,
+SNULL, 140012513693695, 140012513697791,
+STORE, 140012513689600, 140012513693695,
+STORE, 140012513693696, 140012513697791,
+ERASE, 140012547100672, 140012547129343,
+ERASE, 140011362054144, 140011362058239,
+ERASE, 140011362058240, 140011370446847,
+ERASE, 140011882139648, 140011882143743,
+ERASE, 140011882143744, 140011890532351,
+ERASE, 140011873746944, 140011873751039,
+ERASE, 140011873751040, 140011882139647,
+ERASE, 140011588526080, 140011588530175,
+ERASE, 140011588530176, 140011596918783,
+ERASE, 140011328483328, 140011328487423,
+ERASE, 140011328487424, 140011336876031,
+ERASE, 140011898925056, 140011898929151,
+ERASE, 140011898929152, 140011907317759,
+ERASE, 140011353661440, 140011353665535,
+ERASE, 140011353665536, 140011362054143,
+ERASE, 140011336876032, 140011336880127,
+ERASE, 140011336880128, 140011345268735,
+ERASE, 140011731136512, 140011731140607,
+ERASE, 140011731140608, 140011739529215,
+ERASE, 140011479486464, 140011479490559,
+ERASE, 140011479490560, 140011487879167,
+ERASE, 140011756314624, 140011756318719,
+ERASE, 140011756318720, 140011764707327,
+ERASE, 140011580133376, 140011580137471,
+ERASE, 140011580137472, 140011588526079,
+ERASE, 140011219443712, 140011219447807,
+ERASE, 140011219447808, 140011227836415,
+ERASE, 140011051655168, 140011051659263,
+ERASE, 140011051659264, 140011060047871,
+ERASE, 140011999571968, 140011999576063,
+ERASE, 140011999576064, 140012007964671,
+ERASE, 140011714351104, 140011714355199,
+ERASE, 140011714355200, 140011722743807,
+ERASE, 140011739529216, 140011739533311,
+ERASE, 140011739533312, 140011747921919,
+ERASE, 140011320090624, 140011320094719,
+ERASE, 140011320094720, 140011328483327,
+ERASE, 140011630489600, 140011630493695,
+ERASE, 140011630493696, 140011638882303,
+ERASE, 140011345268736, 140011345272831,
+ERASE, 140011345272832, 140011353661439,
+ERASE, 140011496271872, 140011496275967,
+ERASE, 140011496275968, 140011504664575,
+ERASE, 140011194265600, 140011194269695,
+ERASE, 140011194269696, 140011202658303,
+ERASE, 140011068440576, 140011068444671,
+ERASE, 140011068444672, 140011076833279,
+ERASE, 140010909044736, 140010909048831,
+ERASE, 140010909048832, 140010917437439,
+ERASE, 140011764707328, 140011764711423,
+ERASE, 140011764711424, 140011773100031,
+ERASE, 140011462701056, 140011462705151,
+ERASE, 140011462705152, 140011471093759,
+ERASE, 140011076833280, 140011076837375,
+ERASE, 140011076837376, 140011085225983,
+ERASE, 140011991179264, 140011991183359,
+ERASE, 140011991183360, 140011999571967,
+ERASE, 140011211051008, 140011211055103,
+ERASE, 140011211055104, 140011219443711,
+ERASE, 140010917437440, 140010917441535,
+ERASE, 140010917441536, 140010925830143,
+ERASE, 140011085225984, 140011085230079,
+ERASE, 140011085230080, 140011093618687,
+ERASE, 140011487879168, 140011487883263,
+ERASE, 140011487883264, 140011496271871,
+ERASE, 140011856961536, 140011856965631,
+ERASE, 140011856965632, 140011865354239,
+ERASE, 140011982786560, 140011982790655,
+ERASE, 140011982790656, 140011991179263,
+ERASE, 140011722743808, 140011722747903,
+ERASE, 140011722747904, 140011731136511,
+ERASE, 140011177480192, 140011177484287,
+ERASE, 140011177484288, 140011185872895,
+ERASE, 140011848568832, 140011848572927,
+ERASE, 140011848572928, 140011856961535,
+ERASE, 140011890532352, 140011890536447,
+ERASE, 140011890536448, 140011898925055,
+ERASE, 140011622096896, 140011622100991,
+ERASE, 140011622100992, 140011630489599,
+ERASE, 140011311697920, 140011311702015,
+ERASE, 140011311702016, 140011320090623,
+ERASE, 140011471093760, 140011471097855,
+ERASE, 140011471097856, 140011479486463,
+ERASE, 140011605311488, 140011605315583,
+ERASE, 140011605315584, 140011613704191,
+ERASE, 140010791612416, 140010791616511,
+ERASE, 140010791616512, 140010800005119,
+ERASE, 140010959400960, 140010959405055,
+ERASE, 140010959405056, 140010967793663,
+ERASE, 140011185872896, 140011185876991,
+ERASE, 140011185876992, 140011194265599,
+ERASE, 140011454308352, 140011454312447,
+ERASE, 140011454312448, 140011462701055,
+ERASE, 140011596918784, 140011596922879,
+ERASE, 140011596922880, 140011605311487,
+ERASE, 140011060047872, 140011060051967,
+ERASE, 140011060051968, 140011068440575,
+ERASE, 140010925830144, 140010925834239,
+ERASE, 140010925834240, 140010934222847,
+ERASE, 140011747921920, 140011747926015,
+ERASE, 140011747926016, 140011756314623,
+ERASE, 140011202658304, 140011202662399,
+ERASE, 140011202662400, 140011211051007,
+ERASE, 140010800005120, 140010800009215,
+ERASE, 140010800009216, 140010808397823,
+ERASE, 140011093618688, 140011093622783,
+ERASE, 140011093622784, 140011102011391,
+ERASE, 140010808397824, 140010808401919,
+ERASE, 140010808401920, 140010816790527,
+ERASE, 140012419010560, 140012419014655,
+ERASE, 140012419014656, 140012427403263,
+ERASE, 140010934222848, 140010934226943,
+ERASE, 140010934226944, 140010942615551,
+ERASE, 140010942615552, 140010942619647,
+ERASE, 140010942619648, 140010951008255,
+ERASE, 140011613704192, 140011613708287,
+ERASE, 140011613708288, 140011622096895,
+ERASE, 140011865354240, 140011865358335,
+ERASE, 140011865358336, 140011873746943,
+ERASE, 140012301578240, 140012301582335,
+ERASE, 140012301582336, 140012309970943,
+ERASE, 140012393832448, 140012393836543,
+ERASE, 140012393836544, 140012402225151,
+ERASE, 140012410617856, 140012410621951,
+ERASE, 140012410621952, 140012419010559,
+ERASE, 140012402225152, 140012402229247,
+ERASE, 140012402229248, 140012410617855,
+ERASE, 140012259614720, 140012259618815,
+ERASE, 140012259618816, 140012268007423,
+ERASE, 140012251222016, 140012251226111,
+ERASE, 140012251226112, 140012259614719,
+ERASE, 140012284792832, 140012284796927,
+ERASE, 140012284796928, 140012293185535,
+ERASE, 140011445915648, 140011445919743,
+ERASE, 140011445919744, 140011454308351,
+ERASE, 140010951008256, 140010951012351,
+ERASE, 140010951012352, 140010959400959,
+ERASE, 140011043262464, 140011043266559,
+ERASE, 140011043266560, 140011051655167,
+ERASE, 140010825183232, 140010825187327,
+ERASE, 140010825187328, 140010833575935,
+ERASE, 140012293185536, 140012293189631,
+ERASE, 140012293189632, 140012301578239,
+ERASE, 140012276400128, 140012276404223,
+ERASE, 140012276404224, 140012284792831,
+ERASE, 140012016357376, 140012016361471,
+ERASE, 140012016361472, 140012024750079,
+ERASE, 140012024750080, 140012024754175,
+ERASE, 140012024754176, 140012033142783,
+ERASE, 140011227836416, 140011227840511,
+ERASE, 140011227840512, 140011236229119,
+ERASE, 140010816790528, 140010816794623,
+ERASE, 140010816794624, 140010825183231,
+ERASE, 140012268007424, 140012268011519,
+ERASE, 140012268011520, 140012276400127,
+ERASE, 140012385439744, 140012385443839,
+ERASE, 140012385443840, 140012393832447,
+ERASE, 140012522090496, 140012522094591,
+ERASE, 140012522094592, 140012530483199,
+ERASE, 140012033142784, 140012033146879,
+ERASE, 140012033146880, 140012041535487,
+ };
+ unsigned long set35[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140730536939520, 140737488351231,
+SNULL, 140730536943615, 140737488351231,
+STORE, 140730536939520, 140730536943615,
+STORE, 140730536808448, 140730536943615,
+STORE, 94245239877632, 94245242130431,
+SNULL, 94245240008703, 94245242130431,
+STORE, 94245239877632, 94245240008703,
+STORE, 94245240008704, 94245242130431,
+ERASE, 94245240008704, 94245242130431,
+STORE, 94245242101760, 94245242109951,
+STORE, 94245242109952, 94245242130431,
+STORE, 140475575263232, 140475577516031,
+SNULL, 140475575406591, 140475577516031,
+STORE, 140475575263232, 140475575406591,
+STORE, 140475575406592, 140475577516031,
+ERASE, 140475575406592, 140475577516031,
+STORE, 140475577503744, 140475577511935,
+STORE, 140475577511936, 140475577516031,
+STORE, 140730538164224, 140730538168319,
+STORE, 140730538151936, 140730538164223,
+STORE, 140475577475072, 140475577503743,
+STORE, 140475577466880, 140475577475071,
+STORE, 140475573047296, 140475575263231,
+SNULL, 140475573047296, 140475573145599,
+STORE, 140475573145600, 140475575263231,
+STORE, 140475573047296, 140475573145599,
+SNULL, 140475575238655, 140475575263231,
+STORE, 140475573145600, 140475575238655,
+STORE, 140475575238656, 140475575263231,
+SNULL, 140475575238656, 140475575246847,
+STORE, 140475575246848, 140475575263231,
+STORE, 140475575238656, 140475575246847,
+ERASE, 140475575238656, 140475575246847,
+STORE, 140475575238656, 140475575246847,
+ERASE, 140475575246848, 140475575263231,
+STORE, 140475575246848, 140475575263231,
+STORE, 140475569250304, 140475573047295,
+SNULL, 140475569250304, 140475570909183,
+STORE, 140475570909184, 140475573047295,
+STORE, 140475569250304, 140475570909183,
+SNULL, 140475573006335, 140475573047295,
+STORE, 140475570909184, 140475573006335,
+STORE, 140475573006336, 140475573047295,
+SNULL, 140475573006336, 140475573030911,
+STORE, 140475573030912, 140475573047295,
+STORE, 140475573006336, 140475573030911,
+ERASE, 140475573006336, 140475573030911,
+STORE, 140475573006336, 140475573030911,
+ERASE, 140475573030912, 140475573047295,
+STORE, 140475573030912, 140475573047295,
+STORE, 140475577458688, 140475577475071,
+SNULL, 140475573022719, 140475573030911,
+STORE, 140475573006336, 140475573022719,
+STORE, 140475573022720, 140475573030911,
+SNULL, 140475575242751, 140475575246847,
+STORE, 140475575238656, 140475575242751,
+STORE, 140475575242752, 140475575246847,
+SNULL, 94245242105855, 94245242109951,
+STORE, 94245242101760, 94245242105855,
+STORE, 94245242105856, 94245242109951,
+SNULL, 140475577507839, 140475577511935,
+STORE, 140475577503744, 140475577507839,
+STORE, 140475577507840, 140475577511935,
+ERASE, 140475577475072, 140475577503743,
+STORE, 94245271216128, 94245271351295,
+STORE, 140475560857600, 140475569250303,
+SNULL, 140475560861695, 140475569250303,
+STORE, 140475560857600, 140475560861695,
+STORE, 140475560861696, 140475569250303,
+STORE, 140475552464896, 140475560857599,
+STORE, 140475418247168, 140475552464895,
+SNULL, 140475418247168, 140475428241407,
+STORE, 140475428241408, 140475552464895,
+STORE, 140475418247168, 140475428241407,
+ERASE, 140475418247168, 140475428241407,
+SNULL, 140475495350271, 140475552464895,
+STORE, 140475428241408, 140475495350271,
+STORE, 140475495350272, 140475552464895,
+ERASE, 140475495350272, 140475552464895,
+SNULL, 140475428376575, 140475495350271,
+STORE, 140475428241408, 140475428376575,
+STORE, 140475428376576, 140475495350271,
+SNULL, 140475552468991, 140475560857599,
+STORE, 140475552464896, 140475552468991,
+STORE, 140475552468992, 140475560857599,
+STORE, 140475544072192, 140475552464895,
+SNULL, 140475544076287, 140475552464895,
+STORE, 140475544072192, 140475544076287,
+STORE, 140475544076288, 140475552464895,
+STORE, 140475535679488, 140475544072191,
+SNULL, 140475535683583, 140475544072191,
+STORE, 140475535679488, 140475535683583,
+STORE, 140475535683584, 140475544072191,
+STORE, 140475527286784, 140475535679487,
+SNULL, 140475527290879, 140475535679487,
+STORE, 140475527286784, 140475527290879,
+STORE, 140475527290880, 140475535679487,
+STORE, 140475518894080, 140475527286783,
+STORE, 140475510501376, 140475527286783,
+STORE, 140475502108672, 140475527286783,
+STORE, 140475419848704, 140475428241407,
+STORE, 140475285630976, 140475419848703,
+SNULL, 140475285630976, 140475294023679,
+STORE, 140475294023680, 140475419848703,
+STORE, 140475285630976, 140475294023679,
+ERASE, 140475285630976, 140475294023679,
+STORE, 140475159805952, 140475419848703,
+STORE, 140475025588224, 140475419848703,
+SNULL, 140475092697087, 140475419848703,
+STORE, 140475025588224, 140475092697087,
+STORE, 140475092697088, 140475419848703,
+SNULL, 140475092697088, 140475159805951,
+STORE, 140475159805952, 140475419848703,
+STORE, 140475092697088, 140475159805951,
+ERASE, 140475092697088, 140475159805951,
+STORE, 140474891370496, 140475092697087,
+SNULL, 140474958479359, 140475092697087,
+STORE, 140474891370496, 140474958479359,
+STORE, 140474958479360, 140475092697087,
+SNULL, 140474958479360, 140475025588223,
+STORE, 140475025588224, 140475092697087,
+STORE, 140474958479360, 140475025588223,
+ERASE, 140474958479360, 140475025588223,
+SNULL, 140475361132543, 140475419848703,
+STORE, 140475159805952, 140475361132543,
+STORE, 140475361132544, 140475419848703,
+ERASE, 140475361132544, 140475419848703,
+SNULL, 140475159805952, 140475294023679,
+STORE, 140475294023680, 140475361132543,
+STORE, 140475159805952, 140475294023679,
+SNULL, 140475294158847, 140475361132543,
+STORE, 140475294023680, 140475294158847,
+STORE, 140475294158848, 140475361132543,
+SNULL, 140475226914815, 140475294023679,
+STORE, 140475159805952, 140475226914815,
+STORE, 140475226914816, 140475294023679,
+ERASE, 140475226914816, 140475294023679,
+SNULL, 140475025723391, 140475092697087,
+STORE, 140475025588224, 140475025723391,
+STORE, 140475025723392, 140475092697087,
+SNULL, 140475159941119, 140475226914815,
+STORE, 140475159805952, 140475159941119,
+STORE, 140475159941120, 140475226914815,
+SNULL, 140474891505663, 140474958479359,
+STORE, 140474891370496, 140474891505663,
+STORE, 140474891505664, 140474958479359,
+SNULL, 140475502108672, 140475518894079,
+STORE, 140475518894080, 140475527286783,
+STORE, 140475502108672, 140475518894079,
+SNULL, 140475518898175, 140475527286783,
+STORE, 140475518894080, 140475518898175,
+STORE, 140475518898176, 140475527286783,
+STORE, 140475411456000, 140475428241407,
+SNULL, 140475502112767, 140475518894079,
+STORE, 140475502108672, 140475502112767,
+STORE, 140475502112768, 140475518894079,
+SNULL, 140475411460095, 140475428241407,
+STORE, 140475411456000, 140475411460095,
+STORE, 140475411460096, 140475428241407,
+SNULL, 140475411460096, 140475419848703,
+STORE, 140475419848704, 140475428241407,
+STORE, 140475411460096, 140475419848703,
+SNULL, 140475419852799, 140475428241407,
+STORE, 140475419848704, 140475419852799,
+STORE, 140475419852800, 140475428241407,
+STORE, 140475403063296, 140475411455999,
+SNULL, 140475502112768, 140475510501375,
+STORE, 140475510501376, 140475518894079,
+STORE, 140475502112768, 140475510501375,
+SNULL, 140475510505471, 140475518894079,
+STORE, 140475510501376, 140475510505471,
+STORE, 140475510505472, 140475518894079,
+SNULL, 140475403067391, 140475411455999,
+STORE, 140475403063296, 140475403067391,
+STORE, 140475403067392, 140475411455999,
+STORE, 140475394670592, 140475403063295,
+SNULL, 140475394674687, 140475403063295,
+STORE, 140475394670592, 140475394674687,
+STORE, 140475394674688, 140475403063295,
+STORE, 140475386277888, 140475394670591,
+STORE, 140475377885184, 140475394670591,
+STORE, 140475369492480, 140475394670591,
+SNULL, 140475369496575, 140475394670591,
+STORE, 140475369492480, 140475369496575,
+STORE, 140475369496576, 140475394670591,
+SNULL, 140475369496576, 140475377885183,
+STORE, 140475377885184, 140475394670591,
+STORE, 140475369496576, 140475377885183,
+SNULL, 140475377889279, 140475394670591,
+STORE, 140475377885184, 140475377889279,
+STORE, 140475377889280, 140475394670591,
+STORE, 140475285630976, 140475294023679,
+SNULL, 140475377889280, 140475386277887,
+STORE, 140475386277888, 140475394670591,
+STORE, 140475377889280, 140475386277887,
+SNULL, 140475386281983, 140475394670591,
+STORE, 140475386277888, 140475386281983,
+STORE, 140475386281984, 140475394670591,
+SNULL, 140475285635071, 140475294023679,
+STORE, 140475285630976, 140475285635071,
+STORE, 140475285635072, 140475294023679,
+STORE, 140475277238272, 140475285630975,
+STORE, 140475268845568, 140475285630975,
+SNULL, 140475268845568, 140475277238271,
+STORE, 140475277238272, 140475285630975,
+STORE, 140475268845568, 140475277238271,
+SNULL, 140475277242367, 140475285630975,
+STORE, 140475277238272, 140475277242367,
+STORE, 140475277242368, 140475285630975,
+STORE, 140475260452864, 140475277238271,
+SNULL, 140475260452864, 140475268845567,
+STORE, 140475268845568, 140475277238271,
+STORE, 140475260452864, 140475268845567,
+SNULL, 140475268849663, 140475277238271,
+STORE, 140475268845568, 140475268849663,
+STORE, 140475268849664, 140475277238271,
+SNULL, 140475260456959, 140475268845567,
+STORE, 140475260452864, 140475260456959,
+STORE, 140475260456960, 140475268845567,
+STORE, 140475252060160, 140475260452863,
+SNULL, 140475252064255, 140475260452863,
+STORE, 140475252060160, 140475252064255,
+STORE, 140475252064256, 140475260452863,
+STORE, 140475243667456, 140475252060159,
+SNULL, 140475243671551, 140475252060159,
+STORE, 140475243667456, 140475243671551,
+STORE, 140475243671552, 140475252060159,
+STORE, 140475235274752, 140475243667455,
+STORE, 140475151413248, 140475159805951,
+STORE, 140474891505664, 140475025588223,
+STORE, 140475143020544, 140475159805951,
+SNULL, 140474891505664, 140474958479359,
+STORE, 140474958479360, 140475025588223,
+STORE, 140474891505664, 140474958479359,
+SNULL, 140474958614527, 140475025588223,
+STORE, 140474958479360, 140474958614527,
+STORE, 140474958614528, 140475025588223,
+STORE, 140474824261632, 140474891370495,
+SNULL, 140474824396799, 140474891370495,
+STORE, 140474824261632, 140474824396799,
+STORE, 140474824396800, 140474891370495,
+STORE, 140475134627840, 140475159805951,
+STORE, 140474690043904, 140474824261631,
+STORE, 140475126235136, 140475159805951,
+STORE, 140475117842432, 140475159805951,
+STORE, 140474622935040, 140474824261631,
+STORE, 140475109449728, 140475159805951,
+STORE, 140474488717312, 140474824261631,
+STORE, 140475101057024, 140475159805951,
+STORE, 140474480324608, 140474488717311,
+STORE, 140474413215744, 140474480324607,
+STORE, 140474404823040, 140474413215743,
+ERASE, 140474413215744, 140474480324607,
+STORE, 140474471931904, 140474488717311,
+STORE, 140474270605312, 140474404823039,
+SNULL, 140475101057024, 140475126235135,
+STORE, 140475126235136, 140475159805951,
+STORE, 140475101057024, 140475126235135,
+SNULL, 140475126239231, 140475159805951,
+STORE, 140475126235136, 140475126239231,
+STORE, 140475126239232, 140475159805951,
+STORE, 140474463539200, 140474488717311,
+STORE, 140474455146496, 140474488717311,
+SNULL, 140474455150591, 140474488717311,
+STORE, 140474455146496, 140474455150591,
+STORE, 140474455150592, 140474488717311,
+STORE, 140474446753792, 140474455146495,
+SNULL, 140474446757887, 140474455146495,
+STORE, 140474446753792, 140474446757887,
+STORE, 140474446757888, 140474455146495,
+STORE, 140474438361088, 140474446753791,
+STORE, 140474429968384, 140474446753791,
+SNULL, 140474429972479, 140474446753791,
+STORE, 140474429968384, 140474429972479,
+STORE, 140474429972480, 140474446753791,
+SNULL, 140475235278847, 140475243667455,
+STORE, 140475235274752, 140475235278847,
+STORE, 140475235278848, 140475243667455,
+SNULL, 140474757152767, 140474824261631,
+STORE, 140474488717312, 140474757152767,
+STORE, 140474757152768, 140474824261631,
+ERASE, 140474757152768, 140474824261631,
+SNULL, 140474488717312, 140474690043903,
+STORE, 140474690043904, 140474757152767,
+STORE, 140474488717312, 140474690043903,
+SNULL, 140474690179071, 140474757152767,
+STORE, 140474690043904, 140474690179071,
+STORE, 140474690179072, 140474757152767,
+SNULL, 140474488717312, 140474622935039,
+STORE, 140474622935040, 140474690043903,
+STORE, 140474488717312, 140474622935039,
+SNULL, 140474623070207, 140474690043903,
+STORE, 140474622935040, 140474623070207,
+STORE, 140474623070208, 140474690043903,
+SNULL, 140475101057024, 140475117842431,
+STORE, 140475117842432, 140475126235135,
+STORE, 140475101057024, 140475117842431,
+SNULL, 140475117846527, 140475126235135,
+STORE, 140475117842432, 140475117846527,
+STORE, 140475117846528, 140475126235135,
+SNULL, 140474555826175, 140474622935039,
+STORE, 140474488717312, 140474555826175,
+STORE, 140474555826176, 140474622935039,
+ERASE, 140474555826176, 140474622935039,
+STORE, 140474136387584, 140474404823039,
+SNULL, 140474136387584, 140474153172991,
+STORE, 140474153172992, 140474404823039,
+STORE, 140474136387584, 140474153172991,
+ERASE, 140474136387584, 140474153172991,
+STORE, 140474018955264, 140474404823039,
+STORE, 140473884737536, 140474404823039,
+SNULL, 140474086064127, 140474404823039,
+STORE, 140473884737536, 140474086064127,
+STORE, 140474086064128, 140474404823039,
+SNULL, 140474086064128, 140474153172991,
+STORE, 140474153172992, 140474404823039,
+STORE, 140474086064128, 140474153172991,
+ERASE, 140474086064128, 140474153172991,
+STORE, 140473750519808, 140474086064127,
+SNULL, 140473817628671, 140474086064127,
+STORE, 140473750519808, 140473817628671,
+STORE, 140473817628672, 140474086064127,
+SNULL, 140473817628672, 140473884737535,
+STORE, 140473884737536, 140474086064127,
+STORE, 140473817628672, 140473884737535,
+ERASE, 140473817628672, 140473884737535,
+SNULL, 140475126239232, 140475151413247,
+STORE, 140475151413248, 140475159805951,
+STORE, 140475126239232, 140475151413247,
+SNULL, 140475151417343, 140475159805951,
+STORE, 140475151413248, 140475151417343,
+STORE, 140475151417344, 140475159805951,
+SNULL, 140474270605311, 140474404823039,
+STORE, 140474153172992, 140474270605311,
+STORE, 140474270605312, 140474404823039,
+SNULL, 140474270605312, 140474287390719,
+STORE, 140474287390720, 140474404823039,
+STORE, 140474270605312, 140474287390719,
+ERASE, 140474270605312, 140474287390719,
+SNULL, 140474429972480, 140474438361087,
+STORE, 140474438361088, 140474446753791,
+STORE, 140474429972480, 140474438361087,
+SNULL, 140474438365183, 140474446753791,
+STORE, 140474438361088, 140474438365183,
+STORE, 140474438365184, 140474446753791,
+STORE, 140474815868928, 140474824261631,
+SNULL, 140474815873023, 140474824261631,
+STORE, 140474815868928, 140474815873023,
+STORE, 140474815873024, 140474824261631,
+SNULL, 140474220281855, 140474270605311,
+STORE, 140474153172992, 140474220281855,
+STORE, 140474220281856, 140474270605311,
+ERASE, 140474220281856, 140474270605311,
+SNULL, 140474488852479, 140474555826175,
+STORE, 140474488717312, 140474488852479,
+STORE, 140474488852480, 140474555826175,
+SNULL, 140475101057024, 140475109449727,
+STORE, 140475109449728, 140475117842431,
+STORE, 140475101057024, 140475109449727,
+SNULL, 140475109453823, 140475117842431,
+STORE, 140475109449728, 140475109453823,
+STORE, 140475109453824, 140475117842431,
+SNULL, 140473951846399, 140474086064127,
+STORE, 140473884737536, 140473951846399,
+STORE, 140473951846400, 140474086064127,
+SNULL, 140473951846400, 140474018955263,
+STORE, 140474018955264, 140474086064127,
+STORE, 140473951846400, 140474018955263,
+ERASE, 140473951846400, 140474018955263,
+SNULL, 140473884872703, 140473951846399,
+STORE, 140473884737536, 140473884872703,
+STORE, 140473884872704, 140473951846399,
+SNULL, 140474019090431, 140474086064127,
+STORE, 140474018955264, 140474019090431,
+STORE, 140474019090432, 140474086064127,
+SNULL, 140473750654975, 140473817628671,
+STORE, 140473750519808, 140473750654975,
+STORE, 140473750654976, 140473817628671,
+SNULL, 140474455150592, 140474463539199,
+STORE, 140474463539200, 140474488717311,
+STORE, 140474455150592, 140474463539199,
+SNULL, 140474463543295, 140474488717311,
+STORE, 140474463539200, 140474463543295,
+STORE, 140474463543296, 140474488717311,
+STORE, 140474807476224, 140474815868927,
+SNULL, 140474463543296, 140474471931903,
+STORE, 140474471931904, 140474488717311,
+STORE, 140474463543296, 140474471931903,
+SNULL, 140474471935999, 140474488717311,
+STORE, 140474471931904, 140474471935999,
+STORE, 140474471936000, 140474488717311,
+STORE, 140474799083520, 140474815868927,
+STORE, 140474790690816, 140474815868927,
+SNULL, 140474790690816, 140474799083519,
+STORE, 140474799083520, 140474815868927,
+STORE, 140474790690816, 140474799083519,
+SNULL, 140474799087615, 140474815868927,
+STORE, 140474799083520, 140474799087615,
+STORE, 140474799087616, 140474815868927,
+SNULL, 140474354499583, 140474404823039,
+STORE, 140474287390720, 140474354499583,
+STORE, 140474354499584, 140474404823039,
+ERASE, 140474354499584, 140474404823039,
+SNULL, 140474287525887, 140474354499583,
+STORE, 140474287390720, 140474287525887,
+STORE, 140474287525888, 140474354499583,
+STORE, 140474782298112, 140474799083519,
+STORE, 140474773905408, 140474799083519,
+SNULL, 140474773909503, 140474799083519,
+STORE, 140474773905408, 140474773909503,
+STORE, 140474773909504, 140474799083519,
+SNULL, 140475126239232, 140475134627839,
+STORE, 140475134627840, 140475151413247,
+STORE, 140475126239232, 140475134627839,
+SNULL, 140475134631935, 140475151413247,
+STORE, 140475134627840, 140475134631935,
+STORE, 140475134631936, 140475151413247,
+STORE, 140474765512704, 140474773905407,
+STORE, 140474614542336, 140474622935039,
+SNULL, 140474153308159, 140474220281855,
+STORE, 140474153172992, 140474153308159,
+STORE, 140474153308160, 140474220281855,
+SNULL, 140474404827135, 140474413215743,
+STORE, 140474404823040, 140474404827135,
+STORE, 140474404827136, 140474413215743,
+STORE, 140474606149632, 140474622935039,
+SNULL, 140474606153727, 140474622935039,
+STORE, 140474606149632, 140474606153727,
+STORE, 140474606153728, 140474622935039,
+STORE, 140474597756928, 140474606149631,
+SNULL, 140474597761023, 140474606149631,
+STORE, 140474597756928, 140474597761023,
+STORE, 140474597761024, 140474606149631,
+SNULL, 140475134631936, 140475143020543,
+STORE, 140475143020544, 140475151413247,
+STORE, 140475134631936, 140475143020543,
+SNULL, 140475143024639, 140475151413247,
+STORE, 140475143020544, 140475143024639,
+STORE, 140475143024640, 140475151413247,
+STORE, 140474589364224, 140474597756927,
+SNULL, 140474606153728, 140474614542335,
+STORE, 140474614542336, 140474622935039,
+STORE, 140474606153728, 140474614542335,
+SNULL, 140474614546431, 140474622935039,
+STORE, 140474614542336, 140474614546431,
+STORE, 140474614546432, 140474622935039,
+SNULL, 140474765516799, 140474773905407,
+STORE, 140474765512704, 140474765516799,
+STORE, 140474765516800, 140474773905407,
+STORE, 140474580971520, 140474597756927,
+SNULL, 140474773909504, 140474782298111,
+STORE, 140474782298112, 140474799083519,
+STORE, 140474773909504, 140474782298111,
+SNULL, 140474782302207, 140474799083519,
+STORE, 140474782298112, 140474782302207,
+STORE, 140474782302208, 140474799083519,
+SNULL, 140474471936000, 140474480324607,
+STORE, 140474480324608, 140474488717311,
+STORE, 140474471936000, 140474480324607,
+SNULL, 140474480328703, 140474488717311,
+STORE, 140474480324608, 140474480328703,
+STORE, 140474480328704, 140474488717311,
+STORE, 140474572578816, 140474597756927,
+SNULL, 140474572582911, 140474597756927,
+STORE, 140474572578816, 140474572582911,
+STORE, 140474572582912, 140474597756927,
+SNULL, 140474782302208, 140474790690815,
+STORE, 140474790690816, 140474799083519,
+STORE, 140474782302208, 140474790690815,
+SNULL, 140474790694911, 140474799083519,
+STORE, 140474790690816, 140474790694911,
+STORE, 140474790694912, 140474799083519,
+STORE, 140474564186112, 140474572578815,
+STORE, 140474421575680, 140474429968383,
+STORE, 140474396430336, 140474404823039,
+SNULL, 140474396434431, 140474404823039,
+STORE, 140474396430336, 140474396434431,
+STORE, 140474396434432, 140474404823039,
+STORE, 140474388037632, 140474396430335,
+SNULL, 140474799087616, 140474807476223,
+STORE, 140474807476224, 140474815868927,
+STORE, 140474799087616, 140474807476223,
+SNULL, 140474807480319, 140474815868927,
+STORE, 140474807476224, 140474807480319,
+STORE, 140474807480320, 140474815868927,
+SNULL, 140475101061119, 140475109449727,
+STORE, 140475101057024, 140475101061119,
+STORE, 140475101061120, 140475109449727,
+STORE, 140474379644928, 140474396430335,
+SNULL, 140474572582912, 140474589364223,
+STORE, 140474589364224, 140474597756927,
+STORE, 140474572582912, 140474589364223,
+SNULL, 140474589368319, 140474597756927,
+STORE, 140474589364224, 140474589368319,
+STORE, 140474589368320, 140474597756927,
+STORE, 140474371252224, 140474396430335,
+STORE, 140474362859520, 140474396430335,
+STORE, 140474278998016, 140474287390719,
+STORE, 140474270605312, 140474287390719,
+STORE, 140474262212608, 140474287390719,
+SNULL, 140474262216703, 140474287390719,
+STORE, 140474262212608, 140474262216703,
+STORE, 140474262216704, 140474287390719,
+STORE, 140474253819904, 140474262212607,
+SNULL, 140474253823999, 140474262212607,
+STORE, 140474253819904, 140474253823999,
+STORE, 140474253824000, 140474262212607,
+SNULL, 140474362859520, 140474388037631,
+STORE, 140474388037632, 140474396430335,
+STORE, 140474362859520, 140474388037631,
+SNULL, 140474388041727, 140474396430335,
+STORE, 140474388037632, 140474388041727,
+STORE, 140474388041728, 140474396430335,
+SNULL, 140474362859520, 140474379644927,
+STORE, 140474379644928, 140474388037631,
+STORE, 140474362859520, 140474379644927,
+SNULL, 140474379649023, 140474388037631,
+STORE, 140474379644928, 140474379649023,
+STORE, 140474379649024, 140474388037631,
+STORE, 140474245427200, 140474253819903,
+STORE, 140474237034496, 140474253819903,
+STORE, 140474228641792, 140474253819903,
+STORE, 140474144780288, 140474153172991,
+SNULL, 140474228645887, 140474253819903,
+STORE, 140474228641792, 140474228645887,
+STORE, 140474228645888, 140474253819903,
+SNULL, 140474564190207, 140474572578815,
+STORE, 140474564186112, 140474564190207,
+STORE, 140474564190208, 140474572578815,
+STORE, 140474136387584, 140474153172991,
+SNULL, 140474362859520, 140474371252223,
+STORE, 140474371252224, 140474379644927,
+STORE, 140474362859520, 140474371252223,
+SNULL, 140474371256319, 140474379644927,
+STORE, 140474371252224, 140474371256319,
+STORE, 140474371256320, 140474379644927,
+STORE, 140474127994880, 140474153172991,
+STORE, 140474119602176, 140474153172991,
+SNULL, 140474421579775, 140474429968383,
+STORE, 140474421575680, 140474421579775,
+STORE, 140474421579776, 140474429968383,
+STORE, 140474111209472, 140474153172991,
+SNULL, 140474111213567, 140474153172991,
+STORE, 140474111209472, 140474111213567,
+STORE, 140474111213568, 140474153172991,
+SNULL, 140474262216704, 140474270605311,
+STORE, 140474270605312, 140474287390719,
+STORE, 140474262216704, 140474270605311,
+SNULL, 140474270609407, 140474287390719,
+STORE, 140474270605312, 140474270609407,
+STORE, 140474270609408, 140474287390719,
+STORE, 140474102816768, 140474111209471,
+SNULL, 140474102820863, 140474111209471,
+STORE, 140474102816768, 140474102820863,
+STORE, 140474102820864, 140474111209471,
+SNULL, 140474270609408, 140474278998015,
+STORE, 140474278998016, 140474287390719,
+STORE, 140474270609408, 140474278998015,
+SNULL, 140474279002111, 140474287390719,
+STORE, 140474278998016, 140474279002111,
+STORE, 140474279002112, 140474287390719,
+STORE, 140474094424064, 140474102816767,
+SNULL, 140474572582912, 140474580971519,
+STORE, 140474580971520, 140474589364223,
+STORE, 140474572582912, 140474580971519,
+SNULL, 140474580975615, 140474589364223,
+STORE, 140474580971520, 140474580975615,
+STORE, 140474580975616, 140474589364223,
+SNULL, 140474362863615, 140474371252223,
+STORE, 140474362859520, 140474362863615,
+STORE, 140474362863616, 140474371252223,
+STORE, 140474010562560, 140474018955263,
+SNULL, 140474228645888, 140474245427199,
+STORE, 140474245427200, 140474253819903,
+STORE, 140474228645888, 140474245427199,
+SNULL, 140474245431295, 140474253819903,
+STORE, 140474245427200, 140474245431295,
+STORE, 140474245431296, 140474253819903,
+SNULL, 140474111213568, 140474136387583,
+STORE, 140474136387584, 140474153172991,
+STORE, 140474111213568, 140474136387583,
+SNULL, 140474136391679, 140474153172991,
+STORE, 140474136387584, 140474136391679,
+STORE, 140474136391680, 140474153172991,
+STORE, 140474002169856, 140474018955263,
+STORE, 140473993777152, 140474018955263,
+SNULL, 140474111213568, 140474127994879,
+STORE, 140474127994880, 140474136387583,
+STORE, 140474111213568, 140474127994879,
+SNULL, 140474127998975, 140474136387583,
+STORE, 140474127994880, 140474127998975,
+STORE, 140474127998976, 140474136387583,
+SNULL, 140474228645888, 140474237034495,
+STORE, 140474237034496, 140474245427199,
+STORE, 140474228645888, 140474237034495,
+SNULL, 140474237038591, 140474245427199,
+STORE, 140474237034496, 140474237038591,
+STORE, 140474237038592, 140474245427199,
+SNULL, 140474136391680, 140474144780287,
+STORE, 140474144780288, 140474153172991,
+STORE, 140474136391680, 140474144780287,
+SNULL, 140474144784383, 140474153172991,
+STORE, 140474144780288, 140474144784383,
+STORE, 140474144784384, 140474153172991,
+STORE, 140473985384448, 140474018955263,
+STORE, 140473976991744, 140474018955263,
+STORE, 140473968599040, 140474018955263,
+SNULL, 140473968603135, 140474018955263,
+STORE, 140473968599040, 140473968603135,
+STORE, 140473968603136, 140474018955263,
+SNULL, 140474111213568, 140474119602175,
+STORE, 140474119602176, 140474127994879,
+STORE, 140474111213568, 140474119602175,
+SNULL, 140474119606271, 140474127994879,
+STORE, 140474119602176, 140474119606271,
+STORE, 140474119606272, 140474127994879,
+STORE, 140473960206336, 140473968599039,
+SNULL, 140474094428159, 140474102816767,
+STORE, 140474094424064, 140474094428159,
+STORE, 140474094428160, 140474102816767,
+STORE, 140473876344832, 140473884737535,
+STORE, 140473867952128, 140473884737535,
+STORE, 140473859559424, 140473884737535,
+SNULL, 140473859563519, 140473884737535,
+STORE, 140473859559424, 140473859563519,
+STORE, 140473859563520, 140473884737535,
+SNULL, 140473968603136, 140473993777151,
+STORE, 140473993777152, 140474018955263,
+STORE, 140473968603136, 140473993777151,
+SNULL, 140473993781247, 140474018955263,
+STORE, 140473993777152, 140473993781247,
+STORE, 140473993781248, 140474018955263,
+SNULL, 140473960210431, 140473968599039,
+STORE, 140473960206336, 140473960210431,
+STORE, 140473960210432, 140473968599039,
+SNULL, 140473993781248, 140474010562559,
+STORE, 140474010562560, 140474018955263,
+STORE, 140473993781248, 140474010562559,
+SNULL, 140474010566655, 140474018955263,
+STORE, 140474010562560, 140474010566655,
+STORE, 140474010566656, 140474018955263,
+SNULL, 140473968603136, 140473985384447,
+STORE, 140473985384448, 140473993777151,
+STORE, 140473968603136, 140473985384447,
+SNULL, 140473985388543, 140473993777151,
+STORE, 140473985384448, 140473985388543,
+STORE, 140473985388544, 140473993777151,
+SNULL, 140473993781248, 140474002169855,
+STORE, 140474002169856, 140474010562559,
+STORE, 140473993781248, 140474002169855,
+SNULL, 140474002173951, 140474010562559,
+STORE, 140474002169856, 140474002173951,
+STORE, 140474002173952, 140474010562559,
+STORE, 140473851166720, 140473859559423,
+SNULL, 140473851170815, 140473859559423,
+STORE, 140473851166720, 140473851170815,
+STORE, 140473851170816, 140473859559423,
+SNULL, 140473968603136, 140473976991743,
+STORE, 140473976991744, 140473985384447,
+STORE, 140473968603136, 140473976991743,
+SNULL, 140473976995839, 140473985384447,
+STORE, 140473976991744, 140473976995839,
+STORE, 140473976995840, 140473985384447,
+STORE, 140473842774016, 140473851166719,
+SNULL, 140473859563520, 140473867952127,
+STORE, 140473867952128, 140473884737535,
+STORE, 140473859563520, 140473867952127,
+SNULL, 140473867956223, 140473884737535,
+STORE, 140473867952128, 140473867956223,
+STORE, 140473867956224, 140473884737535,
+SNULL, 140473867956224, 140473876344831,
+STORE, 140473876344832, 140473884737535,
+STORE, 140473867956224, 140473876344831,
+SNULL, 140473876348927, 140473884737535,
+STORE, 140473876344832, 140473876348927,
+STORE, 140473876348928, 140473884737535,
+STORE, 140473834381312, 140473851166719,
+SNULL, 140473834385407, 140473851166719,
+STORE, 140473834381312, 140473834385407,
+STORE, 140473834385408, 140473851166719,
+SNULL, 140473834385408, 140473842774015,
+STORE, 140473842774016, 140473851166719,
+STORE, 140473834385408, 140473842774015,
+SNULL, 140473842778111, 140473851166719,
+STORE, 140473842774016, 140473842778111,
+STORE, 140473842778112, 140473851166719,
+STORE, 140473825988608, 140473834381311,
+SNULL, 140473825992703, 140473834381311,
+STORE, 140473825988608, 140473825992703,
+STORE, 140473825992704, 140473834381311,
+STORE, 140475577475072, 140475577503743,
+STORE, 140475499917312, 140475502108671,
+SNULL, 140475499917312, 140475500007423,
+STORE, 140475500007424, 140475502108671,
+STORE, 140475499917312, 140475500007423,
+SNULL, 140475502100479, 140475502108671,
+STORE, 140475500007424, 140475502100479,
+STORE, 140475502100480, 140475502108671,
+ERASE, 140475502100480, 140475502108671,
+STORE, 140475502100480, 140475502108671,
+SNULL, 140475502104575, 140475502108671,
+STORE, 140475502100480, 140475502104575,
+STORE, 140475502104576, 140475502108671,
+ERASE, 140475577475072, 140475577503743,
+ERASE, 140475235274752, 140475235278847,
+ERASE, 140475235278848, 140475243667455,
+ERASE, 140474815868928, 140474815873023,
+ERASE, 140474815873024, 140474824261631,
+ERASE, 140474606149632, 140474606153727,
+ERASE, 140474606153728, 140474614542335,
+ERASE, 140474270605312, 140474270609407,
+ERASE, 140474270609408, 140474278998015,
+ERASE, 140474438361088, 140474438365183,
+ERASE, 140474438365184, 140474446753791,
+ERASE, 140474597756928, 140474597761023,
+ERASE, 140474597761024, 140474606149631,
+ERASE, 140475126235136, 140475126239231,
+ERASE, 140475126239232, 140475134627839,
+ERASE, 140474463539200, 140474463543295,
+ERASE, 140474463543296, 140474471931903,
+ERASE, 140474388037632, 140474388041727,
+ERASE, 140474388041728, 140474396430335,
+ERASE, 140474404823040, 140474404827135,
+ERASE, 140474404827136, 140474413215743,
+ERASE, 140474278998016, 140474279002111,
+ERASE, 140474279002112, 140474287390719,
+ERASE, 140474094424064, 140474094428159,
+ERASE, 140474094428160, 140474102816767,
+ERASE, 140473867952128, 140473867956223,
+ERASE, 140473867956224, 140473876344831,
+ERASE, 140475151413248, 140475151417343,
+ERASE, 140475151417344, 140475159805951,
+ERASE, 140474455146496, 140474455150591,
+ERASE, 140474455150592, 140474463539199,
+ERASE, 140474807476224, 140474807480319,
+ERASE, 140474807480320, 140474815868927,
+ERASE, 140475117842432, 140475117846527,
+ERASE, 140475117846528, 140475126235135,
+ERASE, 140474446753792, 140474446757887,
+ERASE, 140474446757888, 140474455146495,
+ERASE, 140474429968384, 140474429972479,
+ERASE, 140474429972480, 140474438361087,
+ERASE, 140474782298112, 140474782302207,
+ERASE, 140474782302208, 140474790690815,
+ERASE, 140474136387584, 140474136391679,
+ERASE, 140474136391680, 140474144780287,
+ERASE, 140474002169856, 140474002173951,
+ERASE, 140474002173952, 140474010562559,
+ERASE, 140475134627840, 140475134631935,
+ERASE, 140475134631936, 140475143020543,
+ERASE, 140474471931904, 140474471935999,
+ERASE, 140474471936000, 140474480324607,
+ERASE, 140474396430336, 140474396434431,
+ERASE, 140474396434432, 140474404823039,
+ };
+ unsigned long set36[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140723893125120, 140737488351231,
+SNULL, 140723893129215, 140737488351231,
+STORE, 140723893125120, 140723893129215,
+STORE, 140723892994048, 140723893129215,
+STORE, 94076829786112, 94076832038911,
+SNULL, 94076829917183, 94076832038911,
+STORE, 94076829786112, 94076829917183,
+STORE, 94076829917184, 94076832038911,
+ERASE, 94076829917184, 94076832038911,
+STORE, 94076832010240, 94076832018431,
+STORE, 94076832018432, 94076832038911,
+STORE, 140122444345344, 140122446598143,
+SNULL, 140122444488703, 140122446598143,
+STORE, 140122444345344, 140122444488703,
+STORE, 140122444488704, 140122446598143,
+ERASE, 140122444488704, 140122446598143,
+STORE, 140122446585856, 140122446594047,
+STORE, 140122446594048, 140122446598143,
+STORE, 140723893538816, 140723893542911,
+STORE, 140723893526528, 140723893538815,
+STORE, 140122446557184, 140122446585855,
+STORE, 140122446548992, 140122446557183,
+STORE, 140122442129408, 140122444345343,
+SNULL, 140122442129408, 140122442227711,
+STORE, 140122442227712, 140122444345343,
+STORE, 140122442129408, 140122442227711,
+SNULL, 140122444320767, 140122444345343,
+STORE, 140122442227712, 140122444320767,
+STORE, 140122444320768, 140122444345343,
+SNULL, 140122444320768, 140122444328959,
+STORE, 140122444328960, 140122444345343,
+STORE, 140122444320768, 140122444328959,
+ERASE, 140122444320768, 140122444328959,
+STORE, 140122444320768, 140122444328959,
+ERASE, 140122444328960, 140122444345343,
+STORE, 140122444328960, 140122444345343,
+STORE, 140122438332416, 140122442129407,
+SNULL, 140122438332416, 140122439991295,
+STORE, 140122439991296, 140122442129407,
+STORE, 140122438332416, 140122439991295,
+SNULL, 140122442088447, 140122442129407,
+STORE, 140122439991296, 140122442088447,
+STORE, 140122442088448, 140122442129407,
+SNULL, 140122442088448, 140122442113023,
+STORE, 140122442113024, 140122442129407,
+STORE, 140122442088448, 140122442113023,
+ERASE, 140122442088448, 140122442113023,
+STORE, 140122442088448, 140122442113023,
+ERASE, 140122442113024, 140122442129407,
+STORE, 140122442113024, 140122442129407,
+STORE, 140122446540800, 140122446557183,
+SNULL, 140122442104831, 140122442113023,
+STORE, 140122442088448, 140122442104831,
+STORE, 140122442104832, 140122442113023,
+SNULL, 140122444324863, 140122444328959,
+STORE, 140122444320768, 140122444324863,
+STORE, 140122444324864, 140122444328959,
+SNULL, 94076832014335, 94076832018431,
+STORE, 94076832010240, 94076832014335,
+STORE, 94076832014336, 94076832018431,
+SNULL, 140122446589951, 140122446594047,
+STORE, 140122446585856, 140122446589951,
+STORE, 140122446589952, 140122446594047,
+ERASE, 140122446557184, 140122446585855,
+STORE, 94076845723648, 94076845858815,
+STORE, 140122429939712, 140122438332415,
+SNULL, 140122429943807, 140122438332415,
+STORE, 140122429939712, 140122429943807,
+STORE, 140122429943808, 140122438332415,
+STORE, 140122421547008, 140122429939711,
+STORE, 140122287329280, 140122421547007,
+SNULL, 140122287329280, 140122301399039,
+STORE, 140122301399040, 140122421547007,
+STORE, 140122287329280, 140122301399039,
+ERASE, 140122287329280, 140122301399039,
+SNULL, 140122368507903, 140122421547007,
+STORE, 140122301399040, 140122368507903,
+STORE, 140122368507904, 140122421547007,
+ERASE, 140122368507904, 140122421547007,
+SNULL, 140122301534207, 140122368507903,
+STORE, 140122301399040, 140122301534207,
+STORE, 140122301534208, 140122368507903,
+SNULL, 140122421551103, 140122429939711,
+STORE, 140122421547008, 140122421551103,
+STORE, 140122421551104, 140122429939711,
+STORE, 140122413154304, 140122421547007,
+SNULL, 140122413158399, 140122421547007,
+STORE, 140122413154304, 140122413158399,
+STORE, 140122413158400, 140122421547007,
+STORE, 140122404761600, 140122413154303,
+SNULL, 140122404765695, 140122413154303,
+STORE, 140122404761600, 140122404765695,
+STORE, 140122404765696, 140122413154303,
+STORE, 140122396368896, 140122404761599,
+SNULL, 140122396372991, 140122404761599,
+STORE, 140122396368896, 140122396372991,
+STORE, 140122396372992, 140122404761599,
+STORE, 140122387976192, 140122396368895,
+STORE, 140122167181312, 140122301399039,
+SNULL, 140122234290175, 140122301399039,
+STORE, 140122167181312, 140122234290175,
+STORE, 140122234290176, 140122301399039,
+ERASE, 140122234290176, 140122301399039,
+SNULL, 140122167316479, 140122234290175,
+STORE, 140122167181312, 140122167316479,
+STORE, 140122167316480, 140122234290175,
+STORE, 140122379583488, 140122396368895,
+STORE, 140122371190784, 140122396368895,
+STORE, 140122167316480, 140122301399039,
+STORE, 140122158788608, 140122167181311,
+SNULL, 140122371190784, 140122387976191,
+STORE, 140122387976192, 140122396368895,
+STORE, 140122371190784, 140122387976191,
+SNULL, 140122387980287, 140122396368895,
+STORE, 140122387976192, 140122387980287,
+STORE, 140122387980288, 140122396368895,
+SNULL, 140122167316480, 140122234290175,
+STORE, 140122234290176, 140122301399039,
+STORE, 140122167316480, 140122234290175,
+SNULL, 140122234425343, 140122301399039,
+STORE, 140122234290176, 140122234425343,
+STORE, 140122234425344, 140122301399039,
+STORE, 140122024570880, 140122158788607,
+SNULL, 140122024570880, 140122032963583,
+STORE, 140122032963584, 140122158788607,
+STORE, 140122024570880, 140122032963583,
+ERASE, 140122024570880, 140122032963583,
+STORE, 140121898745856, 140122158788607,
+STORE, 140121890353152, 140121898745855,
+SNULL, 140122100072447, 140122158788607,
+STORE, 140121898745856, 140122100072447,
+STORE, 140122100072448, 140122158788607,
+ERASE, 140122100072448, 140122158788607,
+SNULL, 140121965854719, 140122100072447,
+STORE, 140121898745856, 140121965854719,
+STORE, 140121965854720, 140122100072447,
+SNULL, 140121965854720, 140122032963583,
+STORE, 140122032963584, 140122100072447,
+STORE, 140121965854720, 140122032963583,
+ERASE, 140121965854720, 140122032963583,
+SNULL, 140121898881023, 140121965854719,
+STORE, 140121898745856, 140121898881023,
+STORE, 140121898881024, 140121965854719,
+SNULL, 140121890357247, 140121898745855,
+STORE, 140121890353152, 140121890357247,
+STORE, 140121890357248, 140121898745855,
+SNULL, 140122371190784, 140122379583487,
+STORE, 140122379583488, 140122387976191,
+STORE, 140122371190784, 140122379583487,
+SNULL, 140122379587583, 140122387976191,
+STORE, 140122379583488, 140122379587583,
+STORE, 140122379587584, 140122387976191,
+SNULL, 140122033098751, 140122100072447,
+STORE, 140122032963584, 140122033098751,
+STORE, 140122033098752, 140122100072447,
+SNULL, 140122158792703, 140122167181311,
+STORE, 140122158788608, 140122158792703,
+STORE, 140122158792704, 140122167181311,
+STORE, 140122150395904, 140122158788607,
+STORE, 140122142003200, 140122158788607,
+SNULL, 140122142007295, 140122158788607,
+STORE, 140122142003200, 140122142007295,
+STORE, 140122142007296, 140122158788607,
+SNULL, 140122371194879, 140122379583487,
+STORE, 140122371190784, 140122371194879,
+STORE, 140122371194880, 140122379583487,
+SNULL, 140122142007296, 140122150395903,
+STORE, 140122150395904, 140122158788607,
+STORE, 140122142007296, 140122150395903,
+SNULL, 140122150399999, 140122158788607,
+STORE, 140122150395904, 140122150399999,
+STORE, 140122150400000, 140122158788607,
+STORE, 140122133610496, 140122142003199,
+STORE, 140122125217792, 140122142003199,
+STORE, 140122116825088, 140122142003199,
+SNULL, 140122116829183, 140122142003199,
+STORE, 140122116825088, 140122116829183,
+STORE, 140122116829184, 140122142003199,
+SNULL, 140122116829184, 140122133610495,
+STORE, 140122133610496, 140122142003199,
+STORE, 140122116829184, 140122133610495,
+SNULL, 140122133614591, 140122142003199,
+STORE, 140122133610496, 140122133614591,
+STORE, 140122133614592, 140122142003199,
+SNULL, 140122116829184, 140122125217791,
+STORE, 140122125217792, 140122133610495,
+STORE, 140122116829184, 140122125217791,
+SNULL, 140122125221887, 140122133610495,
+STORE, 140122125217792, 140122125221887,
+STORE, 140122125221888, 140122133610495,
+STORE, 140122108432384, 140122116825087,
+SNULL, 140122108436479, 140122116825087,
+STORE, 140122108432384, 140122108436479,
+STORE, 140122108436480, 140122116825087,
+STORE, 140122024570880, 140122032963583,
+STORE, 140122016178176, 140122032963583,
+SNULL, 140122016182271, 140122032963583,
+STORE, 140122016178176, 140122016182271,
+STORE, 140122016182272, 140122032963583,
+SNULL, 140122016182272, 140122024570879,
+STORE, 140122024570880, 140122032963583,
+STORE, 140122016182272, 140122024570879,
+SNULL, 140122024574975, 140122032963583,
+STORE, 140122024570880, 140122024574975,
+STORE, 140122024574976, 140122032963583,
+STORE, 140122007785472, 140122016178175,
+SNULL, 140122007789567, 140122016178175,
+STORE, 140122007785472, 140122007789567,
+STORE, 140122007789568, 140122016178175,
+STORE, 140121999392768, 140122007785471,
+STORE, 140121991000064, 140122007785471,
+SNULL, 140121991004159, 140122007785471,
+STORE, 140121991000064, 140121991004159,
+STORE, 140121991004160, 140122007785471,
+SNULL, 140121991004160, 140121999392767,
+STORE, 140121999392768, 140122007785471,
+STORE, 140121991004160, 140121999392767,
+SNULL, 140121999396863, 140122007785471,
+STORE, 140121999392768, 140121999396863,
+STORE, 140121999396864, 140122007785471,
+STORE, 140121982607360, 140121991000063,
+STORE, 140121823244288, 140121890353151,
+ERASE, 140121823244288, 140121890353151,
+STORE, 140121756135424, 140121890353151,
+SNULL, 140121756135424, 140121764528127,
+STORE, 140121764528128, 140121890353151,
+STORE, 140121756135424, 140121764528127,
+ERASE, 140121756135424, 140121764528127,
+SNULL, 140121831636991, 140121890353151,
+STORE, 140121764528128, 140121831636991,
+STORE, 140121831636992, 140121890353151,
+ERASE, 140121831636992, 140121890353151,
+STORE, 140121974214656, 140121991000063,
+STORE, 140121630310400, 140121831636991,
+SNULL, 140121697419263, 140121831636991,
+STORE, 140121630310400, 140121697419263,
+STORE, 140121697419264, 140121831636991,
+SNULL, 140121697419264, 140121764528127,
+STORE, 140121764528128, 140121831636991,
+STORE, 140121697419264, 140121764528127,
+ERASE, 140121697419264, 140121764528127,
+STORE, 140121881960448, 140121890353151,
+STORE, 140121630310400, 140121831636991,
+STORE, 140121873567744, 140121890353151,
+SNULL, 140121630310400, 140121697419263,
+STORE, 140121697419264, 140121831636991,
+STORE, 140121630310400, 140121697419263,
+SNULL, 140121697554431, 140121831636991,
+STORE, 140121697419264, 140121697554431,
+STORE, 140121697554432, 140121831636991,
+STORE, 140121865175040, 140121890353151,
+STORE, 140121856782336, 140121890353151,
+STORE, 140121848389632, 140121890353151,
+STORE, 140121839996928, 140121890353151,
+STORE, 140121496092672, 140121697419263,
+STORE, 140121487699968, 140121496092671,
+STORE, 140121420591104, 140121487699967,
+STORE, 140121412198400, 140121420591103,
+ERASE, 140121420591104, 140121487699967,
+STORE, 140121479307264, 140121496092671,
+STORE, 140121277980672, 140121412198399,
+SNULL, 140121277980672, 140121294766079,
+STORE, 140121294766080, 140121412198399,
+STORE, 140121277980672, 140121294766079,
+ERASE, 140121277980672, 140121294766079,
+STORE, 140121470914560, 140121496092671,
+STORE, 140121462521856, 140121496092671,
+STORE, 140121160548352, 140121412198399,
+STORE, 140121454129152, 140121496092671,
+SNULL, 140121227657215, 140121412198399,
+STORE, 140121160548352, 140121227657215,
+STORE, 140121227657216, 140121412198399,
+SNULL, 140121227657216, 140121294766079,
+STORE, 140121294766080, 140121412198399,
+STORE, 140121227657216, 140121294766079,
+ERASE, 140121227657216, 140121294766079,
+STORE, 140121445736448, 140121496092671,
+STORE, 140121437343744, 140121496092671,
+SNULL, 140121437343744, 140121445736447,
+STORE, 140121445736448, 140121496092671,
+STORE, 140121437343744, 140121445736447,
+SNULL, 140121445740543, 140121496092671,
+STORE, 140121445736448, 140121445740543,
+STORE, 140121445740544, 140121496092671,
+SNULL, 140121697554432, 140121764528127,
+STORE, 140121764528128, 140121831636991,
+STORE, 140121697554432, 140121764528127,
+SNULL, 140121764663295, 140121831636991,
+STORE, 140121764528128, 140121764663295,
+STORE, 140121764663296, 140121831636991,
+SNULL, 140121496092672, 140121630310399,
+STORE, 140121630310400, 140121697419263,
+STORE, 140121496092672, 140121630310399,
+SNULL, 140121630445567, 140121697419263,
+STORE, 140121630310400, 140121630445567,
+STORE, 140121630445568, 140121697419263,
+SNULL, 140121445740544, 140121454129151,
+STORE, 140121454129152, 140121496092671,
+STORE, 140121445740544, 140121454129151,
+SNULL, 140121454133247, 140121496092671,
+STORE, 140121454129152, 140121454133247,
+STORE, 140121454133248, 140121496092671,
+STORE, 140121026330624, 140121227657215,
+SNULL, 140121093439487, 140121227657215,
+STORE, 140121026330624, 140121093439487,
+STORE, 140121093439488, 140121227657215,
+SNULL, 140121093439488, 140121160548351,
+STORE, 140121160548352, 140121227657215,
+STORE, 140121093439488, 140121160548351,
+ERASE, 140121093439488, 140121160548351,
+SNULL, 140121563201535, 140121630310399,
+STORE, 140121496092672, 140121563201535,
+STORE, 140121563201536, 140121630310399,
+ERASE, 140121563201536, 140121630310399,
+STORE, 140120892112896, 140121093439487,
+SNULL, 140120959221759, 140121093439487,
+STORE, 140120892112896, 140120959221759,
+STORE, 140120959221760, 140121093439487,
+SNULL, 140120959221760, 140121026330623,
+STORE, 140121026330624, 140121093439487,
+STORE, 140120959221760, 140121026330623,
+ERASE, 140120959221760, 140121026330623,
+STORE, 140120757895168, 140120959221759,
+SNULL, 140121361874943, 140121412198399,
+STORE, 140121294766080, 140121361874943,
+STORE, 140121361874944, 140121412198399,
+ERASE, 140121361874944, 140121412198399,
+SNULL, 140121294901247, 140121361874943,
+STORE, 140121294766080, 140121294901247,
+STORE, 140121294901248, 140121361874943,
+STORE, 140120623677440, 140120959221759,
+SNULL, 140120690786303, 140120959221759,
+STORE, 140120623677440, 140120690786303,
+STORE, 140120690786304, 140120959221759,
+SNULL, 140120690786304, 140120757895167,
+STORE, 140120757895168, 140120959221759,
+STORE, 140120690786304, 140120757895167,
+ERASE, 140120690786304, 140120757895167,
+SNULL, 140121160683519, 140121227657215,
+STORE, 140121160548352, 140121160683519,
+STORE, 140121160683520, 140121227657215,
+SNULL, 140121974214656, 140121982607359,
+STORE, 140121982607360, 140121991000063,
+STORE, 140121974214656, 140121982607359,
+SNULL, 140121982611455, 140121991000063,
+STORE, 140121982607360, 140121982611455,
+STORE, 140121982611456, 140121991000063,
+SNULL, 140121839996928, 140121873567743,
+STORE, 140121873567744, 140121890353151,
+STORE, 140121839996928, 140121873567743,
+SNULL, 140121873571839, 140121890353151,
+STORE, 140121873567744, 140121873571839,
+STORE, 140121873571840, 140121890353151,
+SNULL, 140121873571840, 140121881960447,
+STORE, 140121881960448, 140121890353151,
+STORE, 140121873571840, 140121881960447,
+SNULL, 140121881964543, 140121890353151,
+STORE, 140121881960448, 140121881964543,
+STORE, 140121881964544, 140121890353151,
+SNULL, 140121840001023, 140121873567743,
+STORE, 140121839996928, 140121840001023,
+STORE, 140121840001024, 140121873567743,
+SNULL, 140121840001024, 140121865175039,
+STORE, 140121865175040, 140121873567743,
+STORE, 140121840001024, 140121865175039,
+SNULL, 140121865179135, 140121873567743,
+STORE, 140121865175040, 140121865179135,
+STORE, 140121865179136, 140121873567743,
+SNULL, 140121437347839, 140121445736447,
+STORE, 140121437343744, 140121437347839,
+STORE, 140121437347840, 140121445736447,
+STORE, 140121621917696, 140121630310399,
+STORE, 140121613524992, 140121630310399,
+SNULL, 140121026465791, 140121093439487,
+STORE, 140121026330624, 140121026465791,
+STORE, 140121026465792, 140121093439487,
+SNULL, 140121496227839, 140121563201535,
+STORE, 140121496092672, 140121496227839,
+STORE, 140121496227840, 140121563201535,
+SNULL, 140120757895168, 140120892112895,
+STORE, 140120892112896, 140120959221759,
+STORE, 140120757895168, 140120892112895,
+SNULL, 140120892248063, 140120959221759,
+STORE, 140120892112896, 140120892248063,
+STORE, 140120892248064, 140120959221759,
+SNULL, 140120825004031, 140120892112895,
+STORE, 140120757895168, 140120825004031,
+STORE, 140120825004032, 140120892112895,
+ERASE, 140120825004032, 140120892112895,
+SNULL, 140120623812607, 140120690786303,
+STORE, 140120623677440, 140120623812607,
+STORE, 140120623812608, 140120690786303,
+SNULL, 140120758030335, 140120825004031,
+STORE, 140120757895168, 140120758030335,
+STORE, 140120758030336, 140120825004031,
+SNULL, 140121454133248, 140121462521855,
+STORE, 140121462521856, 140121496092671,
+STORE, 140121454133248, 140121462521855,
+SNULL, 140121462525951, 140121496092671,
+STORE, 140121462521856, 140121462525951,
+STORE, 140121462525952, 140121496092671,
+STORE, 140121605132288, 140121630310399,
+SNULL, 140121605136383, 140121630310399,
+STORE, 140121605132288, 140121605136383,
+STORE, 140121605136384, 140121630310399,
+STORE, 140121596739584, 140121605132287,
+SNULL, 140121605136384, 140121621917695,
+STORE, 140121621917696, 140121630310399,
+STORE, 140121605136384, 140121621917695,
+SNULL, 140121621921791, 140121630310399,
+STORE, 140121621917696, 140121621921791,
+STORE, 140121621921792, 140121630310399,
+STORE, 140121588346880, 140121605132287,
+STORE, 140121579954176, 140121605132287,
+SNULL, 140121412202495, 140121420591103,
+STORE, 140121412198400, 140121412202495,
+STORE, 140121412202496, 140121420591103,
+SNULL, 140121974218751, 140121982607359,
+STORE, 140121974214656, 140121974218751,
+STORE, 140121974218752, 140121982607359,
+SNULL, 140121462525952, 140121479307263,
+STORE, 140121479307264, 140121496092671,
+STORE, 140121462525952, 140121479307263,
+SNULL, 140121479311359, 140121496092671,
+STORE, 140121479307264, 140121479311359,
+STORE, 140121479311360, 140121496092671,
+STORE, 140121571561472, 140121605132287,
+SNULL, 140121571565567, 140121605132287,
+STORE, 140121571561472, 140121571565567,
+STORE, 140121571565568, 140121605132287,
+STORE, 140121428951040, 140121437343743,
+SNULL, 140121428955135, 140121437343743,
+STORE, 140121428951040, 140121428955135,
+STORE, 140121428955136, 140121437343743,
+SNULL, 140121840001024, 140121856782335,
+STORE, 140121856782336, 140121865175039,
+STORE, 140121840001024, 140121856782335,
+SNULL, 140121856786431, 140121865175039,
+STORE, 140121856782336, 140121856786431,
+STORE, 140121856786432, 140121865175039,
+STORE, 140121403805696, 140121412198399,
+SNULL, 140121840001024, 140121848389631,
+STORE, 140121848389632, 140121856782335,
+STORE, 140121840001024, 140121848389631,
+SNULL, 140121848393727, 140121856782335,
+STORE, 140121848389632, 140121848393727,
+STORE, 140121848393728, 140121856782335,
+SNULL, 140121479311360, 140121487699967,
+STORE, 140121487699968, 140121496092671,
+STORE, 140121479311360, 140121487699967,
+SNULL, 140121487704063, 140121496092671,
+STORE, 140121487699968, 140121487704063,
+STORE, 140121487704064, 140121496092671,
+STORE, 140121395412992, 140121412198399,
+STORE, 140121387020288, 140121412198399,
+SNULL, 140121387024383, 140121412198399,
+STORE, 140121387020288, 140121387024383,
+STORE, 140121387024384, 140121412198399,
+SNULL, 140121605136384, 140121613524991,
+STORE, 140121613524992, 140121621917695,
+STORE, 140121605136384, 140121613524991,
+SNULL, 140121613529087, 140121621917695,
+STORE, 140121613524992, 140121613529087,
+STORE, 140121613529088, 140121621917695,
+SNULL, 140121462525952, 140121470914559,
+STORE, 140121470914560, 140121479307263,
+STORE, 140121462525952, 140121470914559,
+SNULL, 140121470918655, 140121479307263,
+STORE, 140121470914560, 140121470918655,
+STORE, 140121470918656, 140121479307263,
+STORE, 140121378627584, 140121387020287,
+SNULL, 140121378631679, 140121387020287,
+STORE, 140121378627584, 140121378631679,
+STORE, 140121378631680, 140121387020287,
+SNULL, 140121571565568, 140121596739583,
+STORE, 140121596739584, 140121605132287,
+STORE, 140121571565568, 140121596739583,
+SNULL, 140121596743679, 140121605132287,
+STORE, 140121596739584, 140121596743679,
+STORE, 140121596743680, 140121605132287,
+SNULL, 140121387024384, 140121403805695,
+STORE, 140121403805696, 140121412198399,
+STORE, 140121387024384, 140121403805695,
+SNULL, 140121403809791, 140121412198399,
+STORE, 140121403805696, 140121403809791,
+STORE, 140121403809792, 140121412198399,
+STORE, 140121370234880, 140121378627583,
+SNULL, 140121387024384, 140121395412991,
+STORE, 140121395412992, 140121403805695,
+STORE, 140121387024384, 140121395412991,
+SNULL, 140121395417087, 140121403805695,
+STORE, 140121395412992, 140121395417087,
+STORE, 140121395417088, 140121403805695,
+SNULL, 140121571565568, 140121588346879,
+STORE, 140121588346880, 140121596739583,
+STORE, 140121571565568, 140121588346879,
+SNULL, 140121588350975, 140121596739583,
+STORE, 140121588346880, 140121588350975,
+STORE, 140121588350976, 140121596739583,
+SNULL, 140121571565568, 140121579954175,
+STORE, 140121579954176, 140121588346879,
+STORE, 140121571565568, 140121579954175,
+SNULL, 140121579958271, 140121588346879,
+STORE, 140121579954176, 140121579958271,
+STORE, 140121579958272, 140121588346879,
+STORE, 140121286373376, 140121294766079,
+STORE, 140121277980672, 140121294766079,
+SNULL, 140121277980672, 140121286373375,
+STORE, 140121286373376, 140121294766079,
+STORE, 140121277980672, 140121286373375,
+SNULL, 140121286377471, 140121294766079,
+STORE, 140121286373376, 140121286377471,
+STORE, 140121286377472, 140121294766079,
+STORE, 140121269587968, 140121286373375,
+STORE, 140121261195264, 140121286373375,
+SNULL, 140121261195264, 140121269587967,
+STORE, 140121269587968, 140121286373375,
+STORE, 140121261195264, 140121269587967,
+SNULL, 140121269592063, 140121286373375,
+STORE, 140121269587968, 140121269592063,
+STORE, 140121269592064, 140121286373375,
+STORE, 140121252802560, 140121269587967,
+SNULL, 140121252806655, 140121269587967,
+STORE, 140121252802560, 140121252806655,
+STORE, 140121252806656, 140121269587967,
+STORE, 140121244409856, 140121252802559,
+STORE, 140121236017152, 140121252802559,
+SNULL, 140121236017152, 140121244409855,
+STORE, 140121244409856, 140121252802559,
+STORE, 140121236017152, 140121244409855,
+SNULL, 140121244413951, 140121252802559,
+STORE, 140121244409856, 140121244413951,
+STORE, 140121244413952, 140121252802559,
+SNULL, 140121370238975, 140121378627583,
+STORE, 140121370234880, 140121370238975,
+STORE, 140121370238976, 140121378627583,
+STORE, 140121152155648, 140121160548351,
+STORE, 140121143762944, 140121160548351,
+STORE, 140121135370240, 140121160548351,
+SNULL, 140121135374335, 140121160548351,
+STORE, 140121135370240, 140121135374335,
+STORE, 140121135374336, 140121160548351,
+STORE, 140121126977536, 140121135370239,
+STORE, 140121118584832, 140121135370239,
+STORE, 140121110192128, 140121135370239,
+SNULL, 140121110192128, 140121118584831,
+STORE, 140121118584832, 140121135370239,
+STORE, 140121110192128, 140121118584831,
+SNULL, 140121118588927, 140121135370239,
+STORE, 140121118584832, 140121118588927,
+STORE, 140121118588928, 140121135370239,
+STORE, 140121101799424, 140121118584831,
+STORE, 140121017937920, 140121026330623,
+STORE, 140121009545216, 140121026330623,
+SNULL, 140121009545216, 140121017937919,
+STORE, 140121017937920, 140121026330623,
+STORE, 140121009545216, 140121017937919,
+SNULL, 140121017942015, 140121026330623,
+STORE, 140121017937920, 140121017942015,
+STORE, 140121017942016, 140121026330623,
+SNULL, 140121269592064, 140121277980671,
+STORE, 140121277980672, 140121286373375,
+STORE, 140121269592064, 140121277980671,
+SNULL, 140121277984767, 140121286373375,
+STORE, 140121277980672, 140121277984767,
+STORE, 140121277984768, 140121286373375,
+STORE, 140121001152512, 140121017937919,
+SNULL, 140121252806656, 140121261195263,
+STORE, 140121261195264, 140121269587967,
+STORE, 140121252806656, 140121261195263,
+SNULL, 140121261199359, 140121269587967,
+STORE, 140121261195264, 140121261199359,
+STORE, 140121261199360, 140121269587967,
+SNULL, 140121135374336, 140121152155647,
+STORE, 140121152155648, 140121160548351,
+STORE, 140121135374336, 140121152155647,
+SNULL, 140121152159743, 140121160548351,
+STORE, 140121152155648, 140121152159743,
+STORE, 140121152159744, 140121160548351,
+STORE, 140120992759808, 140121017937919,
+STORE, 140120984367104, 140121017937919,
+STORE, 140120975974400, 140121017937919,
+SNULL, 140121101799424, 140121110192127,
+STORE, 140121110192128, 140121118584831,
+STORE, 140121101799424, 140121110192127,
+SNULL, 140121110196223, 140121118584831,
+STORE, 140121110192128, 140121110196223,
+STORE, 140121110196224, 140121118584831,
+SNULL, 140121118588928, 140121126977535,
+STORE, 140121126977536, 140121135370239,
+STORE, 140121118588928, 140121126977535,
+SNULL, 140121126981631, 140121135370239,
+STORE, 140121126977536, 140121126981631,
+STORE, 140121126981632, 140121135370239,
+STORE, 140120967581696, 140121017937919,
+STORE, 140120883720192, 140120892112895,
+SNULL, 140120883724287, 140120892112895,
+STORE, 140120883720192, 140120883724287,
+STORE, 140120883724288, 140120892112895,
+STORE, 140120875327488, 140120883720191,
+SNULL, 140121101803519, 140121110192127,
+STORE, 140121101799424, 140121101803519,
+STORE, 140121101803520, 140121110192127,
+SNULL, 140121135374336, 140121143762943,
+STORE, 140121143762944, 140121152155647,
+STORE, 140121135374336, 140121143762943,
+SNULL, 140121143767039, 140121152155647,
+STORE, 140121143762944, 140121143767039,
+STORE, 140121143767040, 140121152155647,
+STORE, 140120866934784, 140120883720191,
+SNULL, 140120967581696, 140120984367103,
+STORE, 140120984367104, 140121017937919,
+STORE, 140120967581696, 140120984367103,
+SNULL, 140120984371199, 140121017937919,
+STORE, 140120984367104, 140120984371199,
+STORE, 140120984371200, 140121017937919,
+STORE, 140120858542080, 140120883720191,
+SNULL, 140121236021247, 140121244409855,
+STORE, 140121236017152, 140121236021247,
+STORE, 140121236021248, 140121244409855,
+SNULL, 140120984371200, 140121009545215,
+STORE, 140121009545216, 140121017937919,
+STORE, 140120984371200, 140121009545215,
+SNULL, 140121009549311, 140121017937919,
+STORE, 140121009545216, 140121009549311,
+STORE, 140121009549312, 140121017937919,
+SNULL, 140120984371200, 140120992759807,
+STORE, 140120992759808, 140121009545215,
+STORE, 140120984371200, 140120992759807,
+SNULL, 140120992763903, 140121009545215,
+STORE, 140120992759808, 140120992763903,
+STORE, 140120992763904, 140121009545215,
+SNULL, 140120992763904, 140121001152511,
+STORE, 140121001152512, 140121009545215,
+STORE, 140120992763904, 140121001152511,
+SNULL, 140121001156607, 140121009545215,
+STORE, 140121001152512, 140121001156607,
+STORE, 140121001156608, 140121009545215,
+STORE, 140120850149376, 140120883720191,
+SNULL, 140120850153471, 140120883720191,
+STORE, 140120850149376, 140120850153471,
+STORE, 140120850153472, 140120883720191,
+SNULL, 140120967585791, 140120984367103,
+STORE, 140120967581696, 140120967585791,
+STORE, 140120967585792, 140120984367103,
+SNULL, 140120850153472, 140120866934783,
+STORE, 140120866934784, 140120883720191,
+STORE, 140120850153472, 140120866934783,
+SNULL, 140120866938879, 140120883720191,
+STORE, 140120866934784, 140120866938879,
+STORE, 140120866938880, 140120883720191,
+STORE, 140120841756672, 140120850149375,
+SNULL, 140120967585792, 140120975974399,
+STORE, 140120975974400, 140120984367103,
+STORE, 140120967585792, 140120975974399,
+SNULL, 140120975978495, 140120984367103,
+STORE, 140120975974400, 140120975978495,
+STORE, 140120975978496, 140120984367103,
+SNULL, 140120866938880, 140120875327487,
+STORE, 140120875327488, 140120883720191,
+STORE, 140120866938880, 140120875327487,
+SNULL, 140120875331583, 140120883720191,
+STORE, 140120875327488, 140120875331583,
+STORE, 140120875331584, 140120883720191,
+STORE, 140120833363968, 140120850149375,
+STORE, 140120749502464, 140120757895167,
+STORE, 140120741109760, 140120757895167,
+STORE, 140120732717056, 140120757895167,
+STORE, 140120724324352, 140120757895167,
+SNULL, 140120724324352, 140120732717055,
+STORE, 140120732717056, 140120757895167,
+STORE, 140120724324352, 140120732717055,
+SNULL, 140120732721151, 140120757895167,
+STORE, 140120732717056, 140120732721151,
+STORE, 140120732721152, 140120757895167,
+STORE, 140120715931648, 140120732717055,
+SNULL, 140120715935743, 140120732717055,
+STORE, 140120715931648, 140120715935743,
+STORE, 140120715935744, 140120732717055,
+SNULL, 140120850153472, 140120858542079,
+STORE, 140120858542080, 140120866934783,
+STORE, 140120850153472, 140120858542079,
+SNULL, 140120858546175, 140120866934783,
+STORE, 140120858542080, 140120858546175,
+STORE, 140120858546176, 140120866934783,
+STORE, 140120707538944, 140120715931647,
+SNULL, 140120707543039, 140120715931647,
+STORE, 140120707538944, 140120707543039,
+STORE, 140120707543040, 140120715931647,
+SNULL, 140120833368063, 140120850149375,
+STORE, 140120833363968, 140120833368063,
+STORE, 140120833368064, 140120850149375,
+SNULL, 140120833368064, 140120841756671,
+STORE, 140120841756672, 140120850149375,
+STORE, 140120833368064, 140120841756671,
+SNULL, 140120841760767, 140120850149375,
+STORE, 140120841756672, 140120841760767,
+STORE, 140120841760768, 140120850149375,
+STORE, 140120699146240, 140120707538943,
+SNULL, 140120715935744, 140120724324351,
+STORE, 140120724324352, 140120732717055,
+STORE, 140120715935744, 140120724324351,
+SNULL, 140120724328447, 140120732717055,
+STORE, 140120724324352, 140120724328447,
+STORE, 140120724328448, 140120732717055,
+SNULL, 140120732721152, 140120741109759,
+STORE, 140120741109760, 140120757895167,
+STORE, 140120732721152, 140120741109759,
+SNULL, 140120741113855, 140120757895167,
+STORE, 140120741109760, 140120741113855,
+STORE, 140120741113856, 140120757895167,
+SNULL, 140120741113856, 140120749502463,
+STORE, 140120749502464, 140120757895167,
+STORE, 140120741113856, 140120749502463,
+SNULL, 140120749506559, 140120757895167,
+STORE, 140120749502464, 140120749506559,
+STORE, 140120749506560, 140120757895167,
+SNULL, 140120699150335, 140120707538943,
+STORE, 140120699146240, 140120699150335,
+STORE, 140120699150336, 140120707538943,
+STORE, 140122446557184, 140122446585855,
+STORE, 140122368999424, 140122371190783,
+SNULL, 140122368999424, 140122369089535,
+STORE, 140122369089536, 140122371190783,
+STORE, 140122368999424, 140122369089535,
+SNULL, 140122371182591, 140122371190783,
+STORE, 140122369089536, 140122371182591,
+STORE, 140122371182592, 140122371190783,
+ERASE, 140122371182592, 140122371190783,
+STORE, 140122371182592, 140122371190783,
+SNULL, 140122371186687, 140122371190783,
+STORE, 140122371182592, 140122371186687,
+STORE, 140122371186688, 140122371190783,
+ERASE, 140122446557184, 140122446585855,
+ERASE, 140121445736448, 140121445740543,
+ERASE, 140121445740544, 140121454129151,
+ERASE, 140121621917696, 140121621921791,
+ERASE, 140121621921792, 140121630310399,
+ERASE, 140121579954176, 140121579958271,
+ERASE, 140121579958272, 140121588346879,
+ERASE, 140121261195264, 140121261199359,
+ERASE, 140121261199360, 140121269587967,
+ERASE, 140121454129152, 140121454133247,
+ERASE, 140121454133248, 140121462521855,
+ERASE, 140121588346880, 140121588350975,
+ERASE, 140121588350976, 140121596739583,
+ERASE, 140121135370240, 140121135374335,
+ERASE, 140121135374336, 140121143762943,
+ERASE, 140121881960448, 140121881964543,
+ERASE, 140121881964544, 140121890353151,
+ERASE, 140121428951040, 140121428955135,
+ERASE, 140121428955136, 140121437343743,
+ERASE, 140121387020288, 140121387024383,
+ERASE, 140121387024384, 140121395412991,
+ERASE, 140121487699968, 140121487704063,
+ERASE, 140121487704064, 140121496092671,
+ERASE, 140121437343744, 140121437347839,
+ERASE, 140121437347840, 140121445736447,
+ERASE, 140121613524992, 140121613529087,
+ERASE, 140121613529088, 140121621917695,
+ERASE, 140121856782336, 140121856786431,
+ERASE, 140121856786432, 140121865175039,
+ERASE, 140121252802560, 140121252806655,
+ERASE, 140121252806656, 140121261195263,
+ERASE, 140121839996928, 140121840001023,
+ERASE, 140121840001024, 140121848389631,
+ERASE, 140121596739584, 140121596743679,
+ERASE, 140121596743680, 140121605132287,
+ERASE, 140121009545216, 140121009549311,
+ERASE, 140121009549312, 140121017937919,
+ERASE, 140120724324352, 140120724328447,
+ERASE, 140120724328448, 140120732717055,
+ERASE, 140120883720192, 140120883724287,
+ERASE, 140120883724288, 140120892112895,
+ERASE, 140121982607360, 140121982611455,
+ERASE, 140121982611456, 140121991000063,
+ERASE, 140121571561472, 140121571565567,
+ERASE, 140121571565568, 140121579954175,
+ERASE, 140121286373376, 140121286377471,
+ERASE, 140121286377472, 140121294766079,
+ERASE, 140120875327488, 140120875331583,
+ERASE, 140120875331584, 140120883720191,
+ERASE, 140121848389632, 140121848393727,
+ERASE, 140121848393728, 140121856782335,
+ERASE, 140121370234880, 140121370238975,
+ERASE, 140121370238976, 140121378627583,
+ERASE, 140121143762944, 140121143767039,
+ERASE, 140121143767040, 140121152155647,
+ERASE, 140121118584832, 140121118588927,
+ERASE, 140121118588928, 140121126977535,
+ERASE, 140120866934784, 140120866938879,
+ERASE, 140120866938880, 140120875327487,
+ERASE, 140120741109760, 140120741113855,
+ERASE, 140120741113856, 140120749502463,
+ERASE, 140121865175040, 140121865179135,
+ERASE, 140121865179136, 140121873567743,
+ERASE, 140121403805696, 140121403809791,
+ERASE, 140121403809792, 140121412198399,
+ERASE, 140121236017152, 140121236021247,
+ERASE, 140121236021248, 140121244409855,
+ERASE, 140120732717056, 140120732721151,
+ERASE, 140120732721152, 140120741109759,
+ERASE, 140121017937920, 140121017942015,
+ERASE, 140121017942016, 140121026330623,
+ERASE, 140121873567744, 140121873571839,
+ERASE, 140121873571840, 140121881960447,
+ERASE, 140121470914560, 140121470918655,
+ERASE, 140121470918656, 140121479307263,
+ERASE, 140121126977536, 140121126981631,
+ERASE, 140121126981632, 140121135370239,
+ERASE, 140120850149376, 140120850153471,
+ERASE, 140120850153472, 140120858542079,
+ERASE, 140120707538944, 140120707543039,
+ERASE, 140120707543040, 140120715931647,
+ERASE, 140121479307264, 140121479311359,
+ERASE, 140121479311360, 140121487699967,
+ERASE, 140120967581696, 140120967585791,
+ERASE, 140120967585792, 140120975974399,
+ERASE, 140120841756672, 140120841760767,
+ERASE, 140120841760768, 140120850149375,
+ERASE, 140121412198400, 140121412202495,
+ERASE, 140121412202496, 140121420591103,
+ERASE, 140122158788608, 140122158792703,
+ERASE, 140122158792704, 140122167181311,
+ERASE, 140122142003200, 140122142007295,
+ERASE, 140122142007296, 140122150395903,
+ERASE, 140121101799424, 140121101803519,
+ERASE, 140121101803520, 140121110192127,
+ERASE, 140120858542080, 140120858546175,
+ERASE, 140120858546176, 140120866934783,
+ERASE, 140120833363968, 140120833368063,
+ERASE, 140120833368064, 140120841756671,
+ERASE, 140121277980672, 140121277984767,
+ERASE, 140121277984768, 140121286373375,
+ERASE, 140121001152512, 140121001156607,
+ERASE, 140121001156608, 140121009545215,
+ERASE, 140120749502464, 140120749506559,
+ERASE, 140120749506560, 140120757895167,
+ERASE, 140121605132288, 140121605136383,
+ERASE, 140121605136384, 140121613524991,
+ERASE, 140121378627584, 140121378631679,
+ERASE, 140121378631680, 140121387020287,
+ERASE, 140121110192128, 140121110196223,
+ERASE, 140121110196224, 140121118584831,
+ERASE, 140121462521856, 140121462525951,
+ERASE, 140121462525952, 140121470914559,
+ERASE, 140121395412992, 140121395417087,
+ERASE, 140121395417088, 140121403805695,
+ERASE, 140121152155648, 140121152159743,
+ERASE, 140121152159744, 140121160548351,
+ERASE, 140120992759808, 140120992763903,
+ERASE, 140120992763904, 140121001152511,
+ERASE, 140122387976192, 140122387980287,
+ERASE, 140122387980288, 140122396368895,
+ERASE, 140121890353152, 140121890357247,
+ERASE, 140121890357248, 140121898745855,
+ERASE, 140121269587968, 140121269592063,
+ERASE, 140121269592064, 140121277980671,
+ };
+ unsigned long set37[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140722404016128, 140737488351231,
+SNULL, 140722404020223, 140737488351231,
+STORE, 140722404016128, 140722404020223,
+STORE, 140722403885056, 140722404020223,
+STORE, 94637010001920, 94637012254719,
+SNULL, 94637010132991, 94637012254719,
+STORE, 94637010001920, 94637010132991,
+STORE, 94637010132992, 94637012254719,
+ERASE, 94637010132992, 94637012254719,
+STORE, 94637012226048, 94637012234239,
+STORE, 94637012234240, 94637012254719,
+STORE, 139760240594944, 139760242847743,
+SNULL, 139760240738303, 139760242847743,
+STORE, 139760240594944, 139760240738303,
+STORE, 139760240738304, 139760242847743,
+ERASE, 139760240738304, 139760242847743,
+STORE, 139760242835456, 139760242843647,
+STORE, 139760242843648, 139760242847743,
+STORE, 140722405232640, 140722405236735,
+STORE, 140722405220352, 140722405232639,
+STORE, 139760242806784, 139760242835455,
+STORE, 139760242798592, 139760242806783,
+STORE, 139760238379008, 139760240594943,
+SNULL, 139760238379008, 139760238477311,
+STORE, 139760238477312, 139760240594943,
+STORE, 139760238379008, 139760238477311,
+SNULL, 139760240570367, 139760240594943,
+STORE, 139760238477312, 139760240570367,
+STORE, 139760240570368, 139760240594943,
+SNULL, 139760240570368, 139760240578559,
+STORE, 139760240578560, 139760240594943,
+STORE, 139760240570368, 139760240578559,
+ERASE, 139760240570368, 139760240578559,
+STORE, 139760240570368, 139760240578559,
+ERASE, 139760240578560, 139760240594943,
+STORE, 139760240578560, 139760240594943,
+STORE, 139760234582016, 139760238379007,
+SNULL, 139760234582016, 139760236240895,
+STORE, 139760236240896, 139760238379007,
+STORE, 139760234582016, 139760236240895,
+SNULL, 139760238338047, 139760238379007,
+STORE, 139760236240896, 139760238338047,
+STORE, 139760238338048, 139760238379007,
+SNULL, 139760238338048, 139760238362623,
+STORE, 139760238362624, 139760238379007,
+STORE, 139760238338048, 139760238362623,
+ERASE, 139760238338048, 139760238362623,
+STORE, 139760238338048, 139760238362623,
+ERASE, 139760238362624, 139760238379007,
+STORE, 139760238362624, 139760238379007,
+STORE, 139760242790400, 139760242806783,
+SNULL, 139760238354431, 139760238362623,
+STORE, 139760238338048, 139760238354431,
+STORE, 139760238354432, 139760238362623,
+SNULL, 139760240574463, 139760240578559,
+STORE, 139760240570368, 139760240574463,
+STORE, 139760240574464, 139760240578559,
+SNULL, 94637012230143, 94637012234239,
+STORE, 94637012226048, 94637012230143,
+STORE, 94637012230144, 94637012234239,
+SNULL, 139760242839551, 139760242843647,
+STORE, 139760242835456, 139760242839551,
+STORE, 139760242839552, 139760242843647,
+ERASE, 139760242806784, 139760242835455,
+STORE, 94637033324544, 94637033459711,
+STORE, 139760226189312, 139760234582015,
+SNULL, 139760226193407, 139760234582015,
+STORE, 139760226189312, 139760226193407,
+STORE, 139760226193408, 139760234582015,
+STORE, 139760217796608, 139760226189311,
+STORE, 139760083578880, 139760217796607,
+SNULL, 139760083578880, 139760114860031,
+STORE, 139760114860032, 139760217796607,
+STORE, 139760083578880, 139760114860031,
+ERASE, 139760083578880, 139760114860031,
+SNULL, 139760181968895, 139760217796607,
+STORE, 139760114860032, 139760181968895,
+STORE, 139760181968896, 139760217796607,
+ERASE, 139760181968896, 139760217796607,
+SNULL, 139760114995199, 139760181968895,
+STORE, 139760114860032, 139760114995199,
+STORE, 139760114995200, 139760181968895,
+SNULL, 139760217800703, 139760226189311,
+STORE, 139760217796608, 139760217800703,
+STORE, 139760217800704, 139760226189311,
+STORE, 139760209403904, 139760217796607,
+SNULL, 139760209407999, 139760217796607,
+STORE, 139760209403904, 139760209407999,
+STORE, 139760209408000, 139760217796607,
+STORE, 139760201011200, 139760209403903,
+SNULL, 139760201015295, 139760209403903,
+STORE, 139760201011200, 139760201015295,
+STORE, 139760201015296, 139760209403903,
+STORE, 139760192618496, 139760201011199,
+SNULL, 139760192622591, 139760201011199,
+STORE, 139760192618496, 139760192622591,
+STORE, 139760192622592, 139760201011199,
+STORE, 139760184225792, 139760192618495,
+STORE, 139759980642304, 139760114860031,
+STORE, 139759972249600, 139759980642303,
+STORE, 139759963856896, 139759980642303,
+STORE, 139759955464192, 139759980642303,
+STORE, 139759888355328, 139759955464191,
+SNULL, 139760047751167, 139760114860031,
+STORE, 139759980642304, 139760047751167,
+STORE, 139760047751168, 139760114860031,
+ERASE, 139760047751168, 139760114860031,
+SNULL, 139759980777471, 139760047751167,
+STORE, 139759980642304, 139759980777471,
+STORE, 139759980777472, 139760047751167,
+STORE, 139759980777472, 139760114860031,
+SNULL, 139759980777472, 139760047751167,
+STORE, 139760047751168, 139760114860031,
+STORE, 139759980777472, 139760047751167,
+SNULL, 139760047886335, 139760114860031,
+STORE, 139760047751168, 139760047886335,
+STORE, 139760047886336, 139760114860031,
+STORE, 139759821246464, 139759955464191,
+SNULL, 139759821246464, 139759888355327,
+STORE, 139759888355328, 139759955464191,
+STORE, 139759821246464, 139759888355327,
+ERASE, 139759821246464, 139759888355327,
+ERASE, 139759888355328, 139759955464191,
+ };
+ unsigned long set38[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140730666221568, 140737488351231,
+SNULL, 140730666225663, 140737488351231,
+STORE, 140730666221568, 140730666225663,
+STORE, 140730666090496, 140730666225663,
+STORE, 94177584803840, 94177587056639,
+SNULL, 94177584934911, 94177587056639,
+STORE, 94177584803840, 94177584934911,
+STORE, 94177584934912, 94177587056639,
+ERASE, 94177584934912, 94177587056639,
+STORE, 94177587027968, 94177587036159,
+STORE, 94177587036160, 94177587056639,
+STORE, 140614382714880, 140614384967679,
+SNULL, 140614382858239, 140614384967679,
+STORE, 140614382714880, 140614382858239,
+STORE, 140614382858240, 140614384967679,
+ERASE, 140614382858240, 140614384967679,
+STORE, 140614384955392, 140614384963583,
+STORE, 140614384963584, 140614384967679,
+STORE, 140730666315776, 140730666319871,
+STORE, 140730666303488, 140730666315775,
+STORE, 140614384926720, 140614384955391,
+STORE, 140614384918528, 140614384926719,
+STORE, 140614380498944, 140614382714879,
+SNULL, 140614380498944, 140614380597247,
+STORE, 140614380597248, 140614382714879,
+STORE, 140614380498944, 140614380597247,
+SNULL, 140614382690303, 140614382714879,
+STORE, 140614380597248, 140614382690303,
+STORE, 140614382690304, 140614382714879,
+SNULL, 140614382690304, 140614382698495,
+STORE, 140614382698496, 140614382714879,
+STORE, 140614382690304, 140614382698495,
+ERASE, 140614382690304, 140614382698495,
+STORE, 140614382690304, 140614382698495,
+ERASE, 140614382698496, 140614382714879,
+STORE, 140614382698496, 140614382714879,
+STORE, 140614376701952, 140614380498943,
+SNULL, 140614376701952, 140614378360831,
+STORE, 140614378360832, 140614380498943,
+STORE, 140614376701952, 140614378360831,
+SNULL, 140614380457983, 140614380498943,
+STORE, 140614378360832, 140614380457983,
+STORE, 140614380457984, 140614380498943,
+SNULL, 140614380457984, 140614380482559,
+STORE, 140614380482560, 140614380498943,
+STORE, 140614380457984, 140614380482559,
+ERASE, 140614380457984, 140614380482559,
+STORE, 140614380457984, 140614380482559,
+ERASE, 140614380482560, 140614380498943,
+STORE, 140614380482560, 140614380498943,
+STORE, 140614384910336, 140614384926719,
+SNULL, 140614380474367, 140614380482559,
+STORE, 140614380457984, 140614380474367,
+STORE, 140614380474368, 140614380482559,
+SNULL, 140614382694399, 140614382698495,
+STORE, 140614382690304, 140614382694399,
+STORE, 140614382694400, 140614382698495,
+SNULL, 94177587032063, 94177587036159,
+STORE, 94177587027968, 94177587032063,
+STORE, 94177587032064, 94177587036159,
+SNULL, 140614384959487, 140614384963583,
+STORE, 140614384955392, 140614384959487,
+STORE, 140614384959488, 140614384963583,
+ERASE, 140614384926720, 140614384955391,
+STORE, 94177619791872, 94177619927039,
+STORE, 140614368309248, 140614376701951,
+SNULL, 140614368313343, 140614376701951,
+STORE, 140614368309248, 140614368313343,
+STORE, 140614368313344, 140614376701951,
+STORE, 140614359916544, 140614368309247,
+STORE, 140614225698816, 140614359916543,
+SNULL, 140614225698816, 140614276481023,
+STORE, 140614276481024, 140614359916543,
+STORE, 140614225698816, 140614276481023,
+ERASE, 140614225698816, 140614276481023,
+SNULL, 140614343589887, 140614359916543,
+STORE, 140614276481024, 140614343589887,
+STORE, 140614343589888, 140614359916543,
+ERASE, 140614343589888, 140614359916543,
+SNULL, 140614276616191, 140614343589887,
+STORE, 140614276481024, 140614276616191,
+STORE, 140614276616192, 140614343589887,
+SNULL, 140614359920639, 140614368309247,
+STORE, 140614359916544, 140614359920639,
+STORE, 140614359920640, 140614368309247,
+STORE, 140614351523840, 140614359916543,
+SNULL, 140614351527935, 140614359916543,
+STORE, 140614351523840, 140614351527935,
+STORE, 140614351527936, 140614359916543,
+STORE, 140614268088320, 140614276481023,
+SNULL, 140614268092415, 140614276481023,
+STORE, 140614268088320, 140614268092415,
+STORE, 140614268092416, 140614276481023,
+STORE, 140614259695616, 140614268088319,
+SNULL, 140614259699711, 140614268088319,
+STORE, 140614259695616, 140614259699711,
+STORE, 140614259699712, 140614268088319,
+STORE, 140614251302912, 140614259695615,
+STORE, 140614242910208, 140614259695615,
+STORE, 140614108692480, 140614242910207,
+SNULL, 140614108692480, 140614142263295,
+STORE, 140614142263296, 140614242910207,
+STORE, 140614108692480, 140614142263295,
+ERASE, 140614108692480, 140614142263295,
+STORE, 140614133870592, 140614142263295,
+STORE, 140613999652864, 140614133870591,
+SNULL, 140613999652864, 140614008045567,
+STORE, 140614008045568, 140614133870591,
+STORE, 140613999652864, 140614008045567,
+ERASE, 140613999652864, 140614008045567,
+STORE, 140613999652864, 140614008045567,
+STORE, 140613865435136, 140613999652863,
+SNULL, 140613865435136, 140613873827839,
+STORE, 140613873827840, 140613999652863,
+STORE, 140613865435136, 140613873827839,
+ERASE, 140613865435136, 140613873827839,
+SNULL, 140614209372159, 140614242910207,
+STORE, 140614142263296, 140614209372159,
+STORE, 140614209372160, 140614242910207,
+ERASE, 140614209372160, 140614242910207,
+SNULL, 140614142398463, 140614209372159,
+STORE, 140614142263296, 140614142398463,
+STORE, 140614142398464, 140614209372159,
+SNULL, 140614075154431, 140614133870591,
+STORE, 140614008045568, 140614075154431,
+STORE, 140614075154432, 140614133870591,
+ERASE, 140614075154432, 140614133870591,
+SNULL, 140614008180735, 140614075154431,
+STORE, 140614008045568, 140614008180735,
+STORE, 140614008180736, 140614075154431,
+SNULL, 140613940936703, 140613999652863,
+STORE, 140613873827840, 140613940936703,
+STORE, 140613940936704, 140613999652863,
+ERASE, 140613940936704, 140613999652863,
+SNULL, 140614242914303, 140614259695615,
+STORE, 140614242910208, 140614242914303,
+STORE, 140614242914304, 140614259695615,
+STORE, 140613739610112, 140613940936703,
+STORE, 140614234517504, 140614242910207,
+SNULL, 140614242914304, 140614251302911,
+STORE, 140614251302912, 140614259695615,
+STORE, 140614242914304, 140614251302911,
+SNULL, 140614251307007, 140614259695615,
+STORE, 140614251302912, 140614251307007,
+STORE, 140614251307008, 140614259695615,
+SNULL, 140613739610112, 140613873827839,
+STORE, 140613873827840, 140613940936703,
+STORE, 140613739610112, 140613873827839,
+SNULL, 140613873963007, 140613940936703,
+STORE, 140613873827840, 140613873963007,
+STORE, 140613873963008, 140613940936703,
+SNULL, 140614133874687, 140614142263295,
+STORE, 140614133870592, 140614133874687,
+STORE, 140614133874688, 140614142263295,
+SNULL, 140613806718975, 140613873827839,
+STORE, 140613739610112, 140613806718975,
+STORE, 140613806718976, 140613873827839,
+ERASE, 140613806718976, 140613873827839,
+STORE, 140614226124800, 140614242910207,
+SNULL, 140613739745279, 140613806718975,
+STORE, 140613739610112, 140613739745279,
+STORE, 140613739745280, 140613806718975,
+SNULL, 140613999656959, 140614008045567,
+STORE, 140613999652864, 140613999656959,
+STORE, 140613999656960, 140614008045567,
+SNULL, 140614226124800, 140614234517503,
+STORE, 140614234517504, 140614242910207,
+STORE, 140614226124800, 140614234517503,
+SNULL, 140614234521599, 140614242910207,
+STORE, 140614234517504, 140614234521599,
+STORE, 140614234521600, 140614242910207,
+STORE, 140614217732096, 140614234517503,
+STORE, 140614125477888, 140614133870591,
+SNULL, 140614125481983, 140614133870591,
+STORE, 140614125477888, 140614125481983,
+STORE, 140614125481984, 140614133870591,
+STORE, 140614117085184, 140614125477887,
+SNULL, 140614217736191, 140614234517503,
+STORE, 140614217732096, 140614217736191,
+STORE, 140614217736192, 140614234517503,
+SNULL, 140614117089279, 140614125477887,
+STORE, 140614117085184, 140614117089279,
+STORE, 140614117089280, 140614125477887,
+SNULL, 140614217736192, 140614226124799,
+STORE, 140614226124800, 140614234517503,
+STORE, 140614217736192, 140614226124799,
+SNULL, 140614226128895, 140614234517503,
+STORE, 140614226124800, 140614226128895,
+STORE, 140614226128896, 140614234517503,
+STORE, 140614108692480, 140614117085183,
+STORE, 140614100299776, 140614117085183,
+STORE, 140614091907072, 140614117085183,
+SNULL, 140614091907072, 140614108692479,
+STORE, 140614108692480, 140614117085183,
+STORE, 140614091907072, 140614108692479,
+SNULL, 140614108696575, 140614117085183,
+STORE, 140614108692480, 140614108696575,
+STORE, 140614108696576, 140614117085183,
+SNULL, 140614091907072, 140614100299775,
+STORE, 140614100299776, 140614108692479,
+STORE, 140614091907072, 140614100299775,
+SNULL, 140614100303871, 140614108692479,
+STORE, 140614100299776, 140614100303871,
+STORE, 140614100303872, 140614108692479,
+STORE, 140614083514368, 140614100299775,
+SNULL, 140614083518463, 140614100299775,
+STORE, 140614083514368, 140614083518463,
+STORE, 140614083518464, 140614100299775,
+STORE, 140613991260160, 140613999652863,
+SNULL, 140614083518464, 140614091907071,
+STORE, 140614091907072, 140614100299775,
+STORE, 140614083518464, 140614091907071,
+SNULL, 140614091911167, 140614100299775,
+STORE, 140614091907072, 140614091911167,
+STORE, 140614091911168, 140614100299775,
+SNULL, 140613991264255, 140613999652863,
+STORE, 140613991260160, 140613991264255,
+STORE, 140613991264256, 140613999652863,
+STORE, 140613982867456, 140613991260159,
+SNULL, 140613982871551, 140613991260159,
+STORE, 140613982867456, 140613982871551,
+STORE, 140613982871552, 140613991260159,
+STORE, 140613974474752, 140613982867455,
+SNULL, 140613974478847, 140613982867455,
+STORE, 140613974474752, 140613974478847,
+STORE, 140613974478848, 140613982867455,
+STORE, 140613966082048, 140613974474751,
+STORE, 140613739745280, 140613873827839,
+SNULL, 140613739745280, 140613806718975,
+STORE, 140613806718976, 140613873827839,
+STORE, 140613739745280, 140613806718975,
+SNULL, 140613806854143, 140613873827839,
+STORE, 140613806718976, 140613806854143,
+STORE, 140613806854144, 140613873827839,
+SNULL, 140613966086143, 140613974474751,
+STORE, 140613966082048, 140613966086143,
+STORE, 140613966086144, 140613974474751,
+STORE, 140613957689344, 140613966082047,
+STORE, 140613605392384, 140613739610111,
+STORE, 140613949296640, 140613966082047,
+STORE, 140613596999680, 140613605392383,
+STORE, 140613529890816, 140613596999679,
+STORE, 140613521498112, 140613529890815,
+STORE, 140613513105408, 140613529890815,
+STORE, 140613378887680, 140613513105407,
+SNULL, 140613378887680, 140613404065791,
+STORE, 140613404065792, 140613513105407,
+STORE, 140613378887680, 140613404065791,
+ERASE, 140613378887680, 140613404065791,
+STORE, 140613395673088, 140613404065791,
+STORE, 140613261455360, 140613395673087,
+SNULL, 140613261455360, 140613269848063,
+STORE, 140613269848064, 140613395673087,
+STORE, 140613261455360, 140613269848063,
+ERASE, 140613261455360, 140613269848063,
+STORE, 140613261455360, 140613269848063,
+STORE, 140613253062656, 140613269848063,
+STORE, 140613118844928, 140613253062655,
+STORE, 140613110452224, 140613118844927,
+SNULL, 140613118844928, 140613135630335,
+STORE, 140613135630336, 140613253062655,
+STORE, 140613118844928, 140613135630335,
+ERASE, 140613118844928, 140613135630335,
+STORE, 140613127237632, 140613135630335,
+STORE, 140613110452224, 140613135630335,
+STORE, 140612976234496, 140613110452223,
+STORE, 140612967841792, 140612976234495,
+STORE, 140612833624064, 140612967841791,
+STORE, 140612825231360, 140612833624063,
+STORE, 140612816838656, 140612833624063,
+STORE, 140612682620928, 140612816838655,
+STORE, 140612674228224, 140612682620927,
+SNULL, 140612682620928, 140612732977151,
+STORE, 140612732977152, 140612816838655,
+STORE, 140612682620928, 140612732977151,
+ERASE, 140612682620928, 140612732977151,
+SNULL, 140613672501247, 140613739610111,
+STORE, 140613605392384, 140613672501247,
+STORE, 140613672501248, 140613739610111,
+ERASE, 140613672501248, 140613739610111,
+SNULL, 140613605527551, 140613672501247,
+STORE, 140613605392384, 140613605527551,
+STORE, 140613605527552, 140613672501247,
+ERASE, 140613529890816, 140613596999679,
+STORE, 140612540010496, 140612674228223,
+SNULL, 140612540010496, 140612598759423,
+STORE, 140612598759424, 140612674228223,
+STORE, 140612540010496, 140612598759423,
+ERASE, 140612540010496, 140612598759423,
+SNULL, 140613471174655, 140613513105407,
+STORE, 140613404065792, 140613471174655,
+STORE, 140613471174656, 140613513105407,
+ERASE, 140613471174656, 140613513105407,
+SNULL, 140613404200959, 140613471174655,
+STORE, 140613404065792, 140613404200959,
+STORE, 140613404200960, 140613471174655,
+SNULL, 140613336956927, 140613395673087,
+STORE, 140613269848064, 140613336956927,
+STORE, 140613336956928, 140613395673087,
+ERASE, 140613336956928, 140613395673087,
+SNULL, 140612833624064, 140612867194879,
+STORE, 140612867194880, 140612967841791,
+STORE, 140612833624064, 140612867194879,
+ERASE, 140612833624064, 140612867194879,
+SNULL, 140612976234496, 140613001412607,
+STORE, 140613001412608, 140613110452223,
+STORE, 140612976234496, 140613001412607,
+ERASE, 140612976234496, 140613001412607,
+SNULL, 140613202739199, 140613253062655,
+STORE, 140613135630336, 140613202739199,
+STORE, 140613202739200, 140613253062655,
+ERASE, 140613202739200, 140613253062655,
+SNULL, 140613135765503, 140613202739199,
+STORE, 140613135630336, 140613135765503,
+STORE, 140613135765504, 140613202739199,
+SNULL, 140612816842751, 140612833624063,
+STORE, 140612816838656, 140612816842751,
+STORE, 140612816842752, 140612833624063,
+SNULL, 140613110456319, 140613135630335,
+STORE, 140613110452224, 140613110456319,
+STORE, 140613110456320, 140613135630335,
+SNULL, 140613949300735, 140613966082047,
+STORE, 140613949296640, 140613949300735,
+STORE, 140613949300736, 140613966082047,
+SNULL, 140613110456320, 140613118844927,
+STORE, 140613118844928, 140613135630335,
+STORE, 140613110456320, 140613118844927,
+SNULL, 140613118849023, 140613135630335,
+STORE, 140613118844928, 140613118849023,
+STORE, 140613118849024, 140613135630335,
+SNULL, 140612800086015, 140612816838655,
+STORE, 140612732977152, 140612800086015,
+STORE, 140612800086016, 140612816838655,
+ERASE, 140612800086016, 140612816838655,
+SNULL, 140613253062656, 140613261455359,
+STORE, 140613261455360, 140613269848063,
+STORE, 140613253062656, 140613261455359,
+SNULL, 140613261459455, 140613269848063,
+STORE, 140613261455360, 140613261459455,
+STORE, 140613261459456, 140613269848063,
+SNULL, 140612674232319, 140612682620927,
+STORE, 140612674228224, 140612674232319,
+STORE, 140612674232320, 140612682620927,
+STORE, 140613731217408, 140613739610111,
+STORE, 140613722824704, 140613739610111,
+SNULL, 140613949300736, 140613957689343,
+STORE, 140613957689344, 140613966082047,
+STORE, 140613949300736, 140613957689343,
+SNULL, 140613957693439, 140613966082047,
+STORE, 140613957689344, 140613957693439,
+STORE, 140613957693440, 140613966082047,
+STORE, 140612464541696, 140612674228223,
+SNULL, 140612531650559, 140612674228223,
+STORE, 140612464541696, 140612531650559,
+STORE, 140612531650560, 140612674228223,
+SNULL, 140612531650560, 140612598759423,
+STORE, 140612598759424, 140612674228223,
+STORE, 140612531650560, 140612598759423,
+ERASE, 140612531650560, 140612598759423,
+SNULL, 140612665868287, 140612674228223,
+STORE, 140612598759424, 140612665868287,
+STORE, 140612665868288, 140612674228223,
+ERASE, 140612665868288, 140612674228223,
+SNULL, 140613269983231, 140613336956927,
+STORE, 140613269848064, 140613269983231,
+STORE, 140613269983232, 140613336956927,
+SNULL, 140612934303743, 140612967841791,
+STORE, 140612867194880, 140612934303743,
+STORE, 140612934303744, 140612967841791,
+ERASE, 140612934303744, 140612967841791,
+SNULL, 140613068521471, 140613110452223,
+STORE, 140613001412608, 140613068521471,
+STORE, 140613068521472, 140613110452223,
+ERASE, 140613068521472, 140613110452223,
+STORE, 140613714432000, 140613739610111,
+SNULL, 140613001547775, 140613068521471,
+STORE, 140613001412608, 140613001547775,
+STORE, 140613001547776, 140613068521471,
+SNULL, 140612733112319, 140612800086015,
+STORE, 140612732977152, 140612733112319,
+STORE, 140612733112320, 140612800086015,
+SNULL, 140613513109503, 140613529890815,
+STORE, 140613513105408, 140613513109503,
+STORE, 140613513109504, 140613529890815,
+STORE, 140613706039296, 140613739610111,
+STORE, 140613697646592, 140613739610111,
+STORE, 140613689253888, 140613739610111,
+SNULL, 140613689257983, 140613739610111,
+STORE, 140613689253888, 140613689257983,
+STORE, 140613689257984, 140613739610111,
+SNULL, 140613253066751, 140613261455359,
+STORE, 140613253062656, 140613253066751,
+STORE, 140613253066752, 140613261455359,
+STORE, 140613680861184, 140613689253887,
+STORE, 140613588606976, 140613605392383,
+SNULL, 140613689257984, 140613731217407,
+STORE, 140613731217408, 140613739610111,
+STORE, 140613689257984, 140613731217407,
+SNULL, 140613731221503, 140613739610111,
+STORE, 140613731217408, 140613731221503,
+STORE, 140613731221504, 140613739610111,
+STORE, 140613580214272, 140613605392383,
+SNULL, 140612464676863, 140612531650559,
+STORE, 140612464541696, 140612464676863,
+STORE, 140612464676864, 140612531650559,
+SNULL, 140612598894591, 140612665868287,
+STORE, 140612598759424, 140612598894591,
+STORE, 140612598894592, 140612665868287,
+SNULL, 140612867330047, 140612934303743,
+STORE, 140612867194880, 140612867330047,
+STORE, 140612867330048, 140612934303743,
+STORE, 140613571821568, 140613605392383,
+SNULL, 140613571825663, 140613605392383,
+STORE, 140613571821568, 140613571825663,
+STORE, 140613571825664, 140613605392383,
+SNULL, 140613689257984, 140613722824703,
+STORE, 140613722824704, 140613731217407,
+STORE, 140613689257984, 140613722824703,
+SNULL, 140613722828799, 140613731217407,
+STORE, 140613722824704, 140613722828799,
+STORE, 140613722828800, 140613731217407,
+SNULL, 140613689257984, 140613714431999,
+STORE, 140613714432000, 140613722824703,
+STORE, 140613689257984, 140613714431999,
+SNULL, 140613714436095, 140613722824703,
+STORE, 140613714432000, 140613714436095,
+STORE, 140613714436096, 140613722824703,
+SNULL, 140612816842752, 140612825231359,
+STORE, 140612825231360, 140612833624063,
+STORE, 140612816842752, 140612825231359,
+SNULL, 140612825235455, 140612833624063,
+STORE, 140612825231360, 140612825235455,
+STORE, 140612825235456, 140612833624063,
+SNULL, 140613395677183, 140613404065791,
+STORE, 140613395673088, 140613395677183,
+STORE, 140613395677184, 140613404065791,
+SNULL, 140613689257984, 140613706039295,
+STORE, 140613706039296, 140613714431999,
+STORE, 140613689257984, 140613706039295,
+SNULL, 140613706043391, 140613714431999,
+STORE, 140613706039296, 140613706043391,
+STORE, 140613706043392, 140613714431999,
+SNULL, 140613118849024, 140613127237631,
+STORE, 140613127237632, 140613135630335,
+STORE, 140613118849024, 140613127237631,
+SNULL, 140613127241727, 140613135630335,
+STORE, 140613127237632, 140613127241727,
+STORE, 140613127241728, 140613135630335,
+SNULL, 140613571825664, 140613580214271,
+STORE, 140613580214272, 140613605392383,
+STORE, 140613571825664, 140613580214271,
+SNULL, 140613580218367, 140613605392383,
+STORE, 140613580214272, 140613580218367,
+STORE, 140613580218368, 140613605392383,
+SNULL, 140613689257984, 140613697646591,
+STORE, 140613697646592, 140613706039295,
+STORE, 140613689257984, 140613697646591,
+SNULL, 140613697650687, 140613706039295,
+STORE, 140613697646592, 140613697650687,
+STORE, 140613697650688, 140613706039295,
+SNULL, 140613680865279, 140613689253887,
+STORE, 140613680861184, 140613680865279,
+STORE, 140613680865280, 140613689253887,
+STORE, 140613563428864, 140613571821567,
+SNULL, 140613563432959, 140613571821567,
+STORE, 140613563428864, 140613563432959,
+STORE, 140613563432960, 140613571821567,
+SNULL, 140613580218368, 140613588606975,
+STORE, 140613588606976, 140613605392383,
+STORE, 140613580218368, 140613588606975,
+SNULL, 140613588611071, 140613605392383,
+STORE, 140613588606976, 140613588611071,
+STORE, 140613588611072, 140613605392383,
+SNULL, 140613513109504, 140613521498111,
+STORE, 140613521498112, 140613529890815,
+STORE, 140613513109504, 140613521498111,
+SNULL, 140613521502207, 140613529890815,
+STORE, 140613521498112, 140613521502207,
+STORE, 140613521502208, 140613529890815,
+SNULL, 140613588611072, 140613596999679,
+STORE, 140613596999680, 140613605392383,
+STORE, 140613588611072, 140613596999679,
+SNULL, 140613597003775, 140613605392383,
+STORE, 140613596999680, 140613597003775,
+STORE, 140613597003776, 140613605392383,
+STORE, 140613555036160, 140613563428863,
+SNULL, 140613555040255, 140613563428863,
+STORE, 140613555036160, 140613555040255,
+STORE, 140613555040256, 140613563428863,
+STORE, 140613546643456, 140613555036159,
+STORE, 140613538250752, 140613555036159,
+SNULL, 140613538250752, 140613546643455,
+STORE, 140613546643456, 140613555036159,
+STORE, 140613538250752, 140613546643455,
+SNULL, 140613546647551, 140613555036159,
+STORE, 140613546643456, 140613546647551,
+STORE, 140613546647552, 140613555036159,
+STORE, 140613504712704, 140613513105407,
+STORE, 140613496320000, 140613513105407,
+SNULL, 140613496324095, 140613513105407,
+STORE, 140613496320000, 140613496324095,
+STORE, 140613496324096, 140613513105407,
+STORE, 140613487927296, 140613496319999,
+SNULL, 140613487931391, 140613496319999,
+STORE, 140613487927296, 140613487931391,
+STORE, 140613487931392, 140613496319999,
+STORE, 140613479534592, 140613487927295,
+SNULL, 140612967845887, 140612976234495,
+STORE, 140612967841792, 140612967845887,
+STORE, 140612967845888, 140612976234495,
+STORE, 140613387280384, 140613395673087,
+STORE, 140613378887680, 140613395673087,
+SNULL, 140613378887680, 140613387280383,
+STORE, 140613387280384, 140613395673087,
+STORE, 140613378887680, 140613387280383,
+SNULL, 140613387284479, 140613395673087,
+STORE, 140613387280384, 140613387284479,
+STORE, 140613387284480, 140613395673087,
+STORE, 140613370494976, 140613387280383,
+STORE, 140613362102272, 140613387280383,
+SNULL, 140613479538687, 140613487927295,
+STORE, 140613479534592, 140613479538687,
+STORE, 140613479538688, 140613487927295,
+STORE, 140613353709568, 140613387280383,
+STORE, 140613345316864, 140613387280383,
+STORE, 140613244669952, 140613253062655,
+SNULL, 140613345320959, 140613387280383,
+STORE, 140613345316864, 140613345320959,
+STORE, 140613345320960, 140613387280383,
+SNULL, 140613538254847, 140613546643455,
+STORE, 140613538250752, 140613538254847,
+STORE, 140613538254848, 140613546643455,
+STORE, 140613236277248, 140613253062655,
+STORE, 140613227884544, 140613253062655,
+STORE, 140613219491840, 140613253062655,
+STORE, 140613211099136, 140613253062655,
+SNULL, 140613211103231, 140613253062655,
+STORE, 140613211099136, 140613211103231,
+STORE, 140613211103232, 140613253062655,
+STORE, 140613102059520, 140613110452223,
+STORE, 140613093666816, 140613110452223,
+SNULL, 140613093670911, 140613110452223,
+STORE, 140613093666816, 140613093670911,
+STORE, 140613093670912, 140613110452223,
+STORE, 140613085274112, 140613093666815,
+SNULL, 140613496324096, 140613504712703,
+STORE, 140613504712704, 140613513105407,
+STORE, 140613496324096, 140613504712703,
+SNULL, 140613504716799, 140613513105407,
+STORE, 140613504712704, 140613504716799,
+STORE, 140613504716800, 140613513105407,
+SNULL, 140613345320960, 140613378887679,
+STORE, 140613378887680, 140613387280383,
+STORE, 140613345320960, 140613378887679,
+SNULL, 140613378891775, 140613387280383,
+STORE, 140613378887680, 140613378891775,
+STORE, 140613378891776, 140613387280383,
+SNULL, 140613345320960, 140613362102271,
+STORE, 140613362102272, 140613378887679,
+STORE, 140613345320960, 140613362102271,
+SNULL, 140613362106367, 140613378887679,
+STORE, 140613362102272, 140613362106367,
+STORE, 140613362106368, 140613378887679,
+SNULL, 140613362106368, 140613370494975,
+STORE, 140613370494976, 140613378887679,
+STORE, 140613362106368, 140613370494975,
+SNULL, 140613370499071, 140613378887679,
+STORE, 140613370494976, 140613370499071,
+STORE, 140613370499072, 140613378887679,
+STORE, 140613076881408, 140613093666815,
+STORE, 140612993019904, 140613001412607,
+SNULL, 140613076885503, 140613093666815,
+STORE, 140613076881408, 140613076885503,
+STORE, 140613076885504, 140613093666815,
+SNULL, 140613093670912, 140613102059519,
+STORE, 140613102059520, 140613110452223,
+STORE, 140613093670912, 140613102059519,
+SNULL, 140613102063615, 140613110452223,
+STORE, 140613102059520, 140613102063615,
+STORE, 140613102063616, 140613110452223,
+SNULL, 140613076885504, 140613085274111,
+STORE, 140613085274112, 140613093666815,
+STORE, 140613076885504, 140613085274111,
+SNULL, 140613085278207, 140613093666815,
+STORE, 140613085274112, 140613085278207,
+STORE, 140613085278208, 140613093666815,
+STORE, 140612984627200, 140613001412607,
+STORE, 140612967845888, 140612984627199,
+SNULL, 140613211103232, 140613219491839,
+STORE, 140613219491840, 140613253062655,
+STORE, 140613211103232, 140613219491839,
+SNULL, 140613219495935, 140613253062655,
+STORE, 140613219491840, 140613219495935,
+STORE, 140613219495936, 140613253062655,
+STORE, 140612959449088, 140612967841791,
+STORE, 140612951056384, 140612967841791,
+SNULL, 140612951060479, 140612967841791,
+STORE, 140612951056384, 140612951060479,
+STORE, 140612951060480, 140612967841791,
+SNULL, 140613345320960, 140613353709567,
+STORE, 140613353709568, 140613362102271,
+STORE, 140613345320960, 140613353709567,
+SNULL, 140613353713663, 140613362102271,
+STORE, 140613353709568, 140613353713663,
+STORE, 140613353713664, 140613362102271,
+SNULL, 140613219495936, 140613244669951,
+STORE, 140613244669952, 140613253062655,
+STORE, 140613219495936, 140613244669951,
+SNULL, 140613244674047, 140613253062655,
+STORE, 140613244669952, 140613244674047,
+STORE, 140613244674048, 140613253062655,
+STORE, 140612942663680, 140612951056383,
+SNULL, 140613219495936, 140613236277247,
+STORE, 140613236277248, 140613244669951,
+STORE, 140613219495936, 140613236277247,
+SNULL, 140613236281343, 140613244669951,
+STORE, 140613236277248, 140613236281343,
+STORE, 140613236281344, 140613244669951,
+SNULL, 140613219495936, 140613227884543,
+STORE, 140613227884544, 140613236277247,
+STORE, 140613219495936, 140613227884543,
+SNULL, 140613227888639, 140613236277247,
+STORE, 140613227884544, 140613227888639,
+STORE, 140613227888640, 140613236277247,
+SNULL, 140612984627200, 140612993019903,
+STORE, 140612993019904, 140613001412607,
+STORE, 140612984627200, 140612993019903,
+SNULL, 140612993023999, 140613001412607,
+STORE, 140612993019904, 140612993023999,
+STORE, 140612993024000, 140613001412607,
+STORE, 140612858802176, 140612867194879,
+STORE, 140612850409472, 140612867194879,
+SNULL, 140612951060480, 140612959449087,
+STORE, 140612959449088, 140612967841791,
+STORE, 140612951060480, 140612959449087,
+SNULL, 140612959453183, 140612967841791,
+STORE, 140612959449088, 140612959453183,
+STORE, 140612959453184, 140612967841791,
+SNULL, 140612967845888, 140612976234495,
+STORE, 140612976234496, 140612984627199,
+STORE, 140612967845888, 140612976234495,
+SNULL, 140612976238591, 140612984627199,
+STORE, 140612976234496, 140612976238591,
+STORE, 140612976238592, 140612984627199,
+STORE, 140612842016768, 140612867194879,
+SNULL, 140612842020863, 140612867194879,
+STORE, 140612842016768, 140612842020863,
+STORE, 140612842020864, 140612867194879,
+SNULL, 140612984631295, 140612993019903,
+STORE, 140612984627200, 140612984631295,
+STORE, 140612984631296, 140612993019903,
+STORE, 140612825235456, 140612842016767,
+STORE, 140612808445952, 140612816838655,
+SNULL, 140612942667775, 140612951056383,
+STORE, 140612942663680, 140612942667775,
+STORE, 140612942667776, 140612951056383,
+STORE, 140612724584448, 140612732977151,
+SNULL, 140612724588543, 140612732977151,
+STORE, 140612724584448, 140612724588543,
+STORE, 140612724588544, 140612732977151,
+STORE, 140612716191744, 140612724584447,
+SNULL, 140612842020864, 140612850409471,
+STORE, 140612850409472, 140612867194879,
+STORE, 140612842020864, 140612850409471,
+SNULL, 140612850413567, 140612867194879,
+STORE, 140612850409472, 140612850413567,
+STORE, 140612850413568, 140612867194879,
+SNULL, 140612850413568, 140612858802175,
+STORE, 140612858802176, 140612867194879,
+STORE, 140612850413568, 140612858802175,
+SNULL, 140612858806271, 140612867194879,
+STORE, 140612858802176, 140612858806271,
+STORE, 140612858806272, 140612867194879,
+STORE, 140612707799040, 140612724584447,
+SNULL, 140612707803135, 140612724584447,
+STORE, 140612707799040, 140612707803135,
+STORE, 140612707803136, 140612724584447,
+SNULL, 140612707803136, 140612716191743,
+STORE, 140612716191744, 140612724584447,
+STORE, 140612707803136, 140612716191743,
+SNULL, 140612716195839, 140612724584447,
+STORE, 140612716191744, 140612716195839,
+STORE, 140612716195840, 140612724584447,
+SNULL, 140612808450047, 140612816838655,
+STORE, 140612808445952, 140612808450047,
+STORE, 140612808450048, 140612816838655,
+SNULL, 140612825235456, 140612833624063,
+STORE, 140612833624064, 140612842016767,
+STORE, 140612825235456, 140612833624063,
+SNULL, 140612833628159, 140612842016767,
+STORE, 140612833624064, 140612833628159,
+STORE, 140612833628160, 140612842016767,
+STORE, 140612699406336, 140612707799039,
+SNULL, 140612699410431, 140612707799039,
+STORE, 140612699406336, 140612699410431,
+STORE, 140612699410432, 140612707799039,
+STORE, 140614384926720, 140614384955391,
+STORE, 140614349332480, 140614351523839,
+SNULL, 140614349332480, 140614349422591,
+STORE, 140614349422592, 140614351523839,
+STORE, 140614349332480, 140614349422591,
+SNULL, 140614351515647, 140614351523839,
+STORE, 140614349422592, 140614351515647,
+STORE, 140614351515648, 140614351523839,
+ERASE, 140614351515648, 140614351523839,
+STORE, 140614351515648, 140614351523839,
+SNULL, 140614351519743, 140614351523839,
+STORE, 140614351515648, 140614351519743,
+STORE, 140614351519744, 140614351523839,
+ERASE, 140614384926720, 140614384955391,
+ERASE, 140613949296640, 140613949300735,
+ERASE, 140613949300736, 140613957689343,
+ERASE, 140613689253888, 140613689257983,
+ERASE, 140613689257984, 140613697646591,
+ERASE, 140613563428864, 140613563432959,
+ERASE, 140613563432960, 140613571821567,
+ERASE, 140613211099136, 140613211103231,
+ERASE, 140613211103232, 140613219491839,
+ERASE, 140614133870592, 140614133874687,
+ERASE, 140614133874688, 140614142263295,
+ERASE, 140612967841792, 140612967845887,
+ERASE, 140612967845888, 140612976234495,
+ERASE, 140613076881408, 140613076885503,
+ERASE, 140613076885504, 140613085274111,
+ERASE, 140612850409472, 140612850413567,
+ERASE, 140612850413568, 140612858802175,
+ERASE, 140613110452224, 140613110456319,
+ERASE, 140613110456320, 140613118844927,
+ERASE, 140613706039296, 140613706043391,
+ERASE, 140613706043392, 140613714431999,
+ERASE, 140613521498112, 140613521502207,
+ERASE, 140613521502208, 140613529890815,
+ERASE, 140613362102272, 140613362106367,
+ERASE, 140613362106368, 140613370494975,
+ERASE, 140613253062656, 140613253066751,
+ERASE, 140613253066752, 140613261455359,
+ERASE, 140612816838656, 140612816842751,
+ERASE, 140612816842752, 140612825231359,
+ERASE, 140613261455360, 140613261459455,
+ERASE, 140613261459456, 140613269848063,
+ERASE, 140613118844928, 140613118849023,
+ERASE, 140613118849024, 140613127237631,
+ERASE, 140613714432000, 140613714436095,
+ERASE, 140613714436096, 140613722824703,
+ERASE, 140613496320000, 140613496324095,
+ERASE, 140613496324096, 140613504712703,
+ERASE, 140613513105408, 140613513109503,
+ERASE, 140613513109504, 140613521498111,
+ERASE, 140613697646592, 140613697650687,
+ERASE, 140613697650688, 140613706039295,
+ERASE, 140613093666816, 140613093670911,
+ERASE, 140613093670912, 140613102059519,
+ERASE, 140612993019904, 140612993023999,
+ERASE, 140612993024000, 140613001412607,
+ERASE, 140613127237632, 140613127241727,
+ERASE, 140613127241728, 140613135630335,
+ERASE, 140613957689344, 140613957693439,
+ERASE, 140613957693440, 140613966082047,
+ERASE, 140613571821568, 140613571825663,
+ERASE, 140613571825664, 140613580214271,
+ERASE, 140613479534592, 140613479538687,
+ERASE, 140613479538688, 140613487927295,
+ERASE, 140612984627200, 140612984631295,
+ERASE, 140612984631296, 140612993019903,
+ERASE, 140613588606976, 140613588611071,
+ERASE, 140613588611072, 140613596999679,
+ERASE, 140613680861184, 140613680865279,
+ERASE, 140613680865280, 140613689253887,
+ERASE, 140613345316864, 140613345320959,
+ERASE, 140613345320960, 140613353709567,
+ERASE, 140613596999680, 140613597003775,
+ERASE, 140613597003776, 140613605392383,
+ERASE, 140613966082048, 140613966086143,
+ERASE, 140613966086144, 140613974474751,
+ERASE, 140613731217408, 140613731221503,
+ERASE, 140613731221504, 140613739610111,
+ERASE, 140613395673088, 140613395677183,
+ERASE, 140613395677184, 140613404065791,
+ERASE, 140612825231360, 140612825235455,
+ERASE, 140612825235456, 140612833624063,
+ERASE, 140612674228224, 140612674232319,
+ERASE, 140612674232320, 140612682620927,
+ERASE, 140613722824704, 140613722828799,
+ERASE, 140613722828800, 140613731217407,
+ERASE, 140613487927296, 140613487931391,
+ERASE, 140613487931392, 140613496319999,
+ERASE, 140613102059520, 140613102063615,
+ERASE, 140613102063616, 140613110452223,
+ERASE, 140614242910208, 140614242914303,
+ERASE, 140614242914304, 140614251302911,
+ERASE, 140612808445952, 140612808450047,
+ERASE, 140612808450048, 140612816838655,
+ERASE, 140613236277248, 140613236281343,
+ERASE, 140613236281344, 140613244669951,
+ERASE, 140613580214272, 140613580218367,
+ERASE, 140613580218368, 140613588606975,
+ERASE, 140613370494976, 140613370499071,
+ERASE, 140613370499072, 140613378887679,
+ERASE, 140613244669952, 140613244674047,
+ERASE, 140613244674048, 140613253062655,
+ERASE, 140612724584448, 140612724588543,
+ERASE, 140612724588544, 140612732977151,
+ERASE, 140612707799040, 140612707803135,
+ERASE, 140612707803136, 140612716191743,
+ERASE, 140613504712704, 140613504716799,
+ERASE, 140613504716800, 140613513105407,
+ };
+
+ unsigned long set39[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140736271417344, 140737488351231,
+SNULL, 140736271421439, 140737488351231,
+STORE, 140736271417344, 140736271421439,
+STORE, 140736271286272, 140736271421439,
+STORE, 94412930822144, 94412933074943,
+SNULL, 94412930953215, 94412933074943,
+STORE, 94412930822144, 94412930953215,
+STORE, 94412930953216, 94412933074943,
+ERASE, 94412930953216, 94412933074943,
+STORE, 94412933046272, 94412933054463,
+STORE, 94412933054464, 94412933074943,
+STORE, 140326136901632, 140326139154431,
+SNULL, 140326137044991, 140326139154431,
+STORE, 140326136901632, 140326137044991,
+STORE, 140326137044992, 140326139154431,
+ERASE, 140326137044992, 140326139154431,
+STORE, 140326139142144, 140326139150335,
+STORE, 140326139150336, 140326139154431,
+STORE, 140736271585280, 140736271589375,
+STORE, 140736271572992, 140736271585279,
+STORE, 140326139113472, 140326139142143,
+STORE, 140326139105280, 140326139113471,
+STORE, 140326134685696, 140326136901631,
+SNULL, 140326134685696, 140326134783999,
+STORE, 140326134784000, 140326136901631,
+STORE, 140326134685696, 140326134783999,
+SNULL, 140326136877055, 140326136901631,
+STORE, 140326134784000, 140326136877055,
+STORE, 140326136877056, 140326136901631,
+SNULL, 140326136877056, 140326136885247,
+STORE, 140326136885248, 140326136901631,
+STORE, 140326136877056, 140326136885247,
+ERASE, 140326136877056, 140326136885247,
+STORE, 140326136877056, 140326136885247,
+ERASE, 140326136885248, 140326136901631,
+STORE, 140326136885248, 140326136901631,
+STORE, 140326130888704, 140326134685695,
+SNULL, 140326130888704, 140326132547583,
+STORE, 140326132547584, 140326134685695,
+STORE, 140326130888704, 140326132547583,
+SNULL, 140326134644735, 140326134685695,
+STORE, 140326132547584, 140326134644735,
+STORE, 140326134644736, 140326134685695,
+SNULL, 140326134644736, 140326134669311,
+STORE, 140326134669312, 140326134685695,
+STORE, 140326134644736, 140326134669311,
+ERASE, 140326134644736, 140326134669311,
+STORE, 140326134644736, 140326134669311,
+ERASE, 140326134669312, 140326134685695,
+STORE, 140326134669312, 140326134685695,
+STORE, 140326139097088, 140326139113471,
+SNULL, 140326134661119, 140326134669311,
+STORE, 140326134644736, 140326134661119,
+STORE, 140326134661120, 140326134669311,
+SNULL, 140326136881151, 140326136885247,
+STORE, 140326136877056, 140326136881151,
+STORE, 140326136881152, 140326136885247,
+SNULL, 94412933050367, 94412933054463,
+STORE, 94412933046272, 94412933050367,
+STORE, 94412933050368, 94412933054463,
+SNULL, 140326139146239, 140326139150335,
+STORE, 140326139142144, 140326139146239,
+STORE, 140326139146240, 140326139150335,
+ERASE, 140326139113472, 140326139142143,
+STORE, 94412939493376, 94412939628543,
+STORE, 140326122496000, 140326130888703,
+SNULL, 140326122500095, 140326130888703,
+STORE, 140326122496000, 140326122500095,
+STORE, 140326122500096, 140326130888703,
+STORE, 140326114103296, 140326122495999,
+STORE, 140325979885568, 140326114103295,
+SNULL, 140325979885568, 140326043910143,
+STORE, 140326043910144, 140326114103295,
+STORE, 140325979885568, 140326043910143,
+ERASE, 140325979885568, 140326043910143,
+SNULL, 140326111019007, 140326114103295,
+STORE, 140326043910144, 140326111019007,
+STORE, 140326111019008, 140326114103295,
+ERASE, 140326111019008, 140326114103295,
+SNULL, 140326044045311, 140326111019007,
+STORE, 140326043910144, 140326044045311,
+STORE, 140326044045312, 140326111019007,
+SNULL, 140326114107391, 140326122495999,
+STORE, 140326114103296, 140326114107391,
+STORE, 140326114107392, 140326122495999,
+STORE, 140326035517440, 140326043910143,
+SNULL, 140326035521535, 140326043910143,
+STORE, 140326035517440, 140326035521535,
+STORE, 140326035521536, 140326043910143,
+STORE, 140326027124736, 140326035517439,
+SNULL, 140326027128831, 140326035517439,
+STORE, 140326027124736, 140326027128831,
+STORE, 140326027128832, 140326035517439,
+STORE, 140326018732032, 140326027124735,
+SNULL, 140326018736127, 140326027124735,
+STORE, 140326018732032, 140326018736127,
+STORE, 140326018736128, 140326027124735,
+STORE, 140326010339328, 140326018732031,
+STORE, 140326001946624, 140326018732031,
+STORE, 140325993553920, 140326018732031,
+STORE, 140325859336192, 140325993553919,
+SNULL, 140325859336192, 140325909692415,
+STORE, 140325909692416, 140325993553919,
+STORE, 140325859336192, 140325909692415,
+ERASE, 140325859336192, 140325909692415,
+SNULL, 140325976801279, 140325993553919,
+STORE, 140325909692416, 140325976801279,
+STORE, 140325976801280, 140325993553919,
+ERASE, 140325976801280, 140325993553919,
+STORE, 140325985161216, 140326018732031,
+STORE, 140325775474688, 140325976801279,
+STORE, 140325708365824, 140325976801279,
+SNULL, 140325708500991, 140325976801279,
+STORE, 140325708365824, 140325708500991,
+STORE, 140325708500992, 140325976801279,
+SNULL, 140325708500992, 140325909692415,
+STORE, 140325909692416, 140325976801279,
+STORE, 140325708500992, 140325909692415,
+SNULL, 140325909827583, 140325976801279,
+STORE, 140325909692416, 140325909827583,
+STORE, 140325909827584, 140325976801279,
+SNULL, 140325842583551, 140325909692415,
+STORE, 140325708500992, 140325842583551,
+STORE, 140325842583552, 140325909692415,
+ERASE, 140325842583552, 140325909692415,
+SNULL, 140325708500992, 140325775474687,
+STORE, 140325775474688, 140325842583551,
+STORE, 140325708500992, 140325775474687,
+SNULL, 140325775609855, 140325842583551,
+STORE, 140325775474688, 140325775609855,
+STORE, 140325775609856, 140325842583551,
+STORE, 140325775609856, 140325909692415,
+SNULL, 140325775609856, 140325842583551,
+STORE, 140325842583552, 140325909692415,
+STORE, 140325775609856, 140325842583551,
+SNULL, 140325842718719, 140325909692415,
+STORE, 140325842583552, 140325842718719,
+STORE, 140325842718720, 140325909692415,
+SNULL, 140325985161216, 140325993553919,
+STORE, 140325993553920, 140326018732031,
+STORE, 140325985161216, 140325993553919,
+SNULL, 140325993558015, 140326018732031,
+STORE, 140325993553920, 140325993558015,
+STORE, 140325993558016, 140326018732031,
+SNULL, 140325985165311, 140325993553919,
+STORE, 140325985161216, 140325985165311,
+STORE, 140325985165312, 140325993553919,
+SNULL, 140325993558016, 140326001946623,
+STORE, 140326001946624, 140326018732031,
+STORE, 140325993558016, 140326001946623,
+SNULL, 140326001950719, 140326018732031,
+STORE, 140326001946624, 140326001950719,
+STORE, 140326001950720, 140326018732031,
+SNULL, 140326001950720, 140326010339327,
+STORE, 140326010339328, 140326018732031,
+STORE, 140326001950720, 140326010339327,
+SNULL, 140326010343423, 140326018732031,
+STORE, 140326010339328, 140326010343423,
+STORE, 140326010343424, 140326018732031,
+STORE, 140325699973120, 140325708365823,
+STORE, 140325691580416, 140325708365823,
+STORE, 140325683187712, 140325708365823,
+SNULL, 140325683191807, 140325708365823,
+STORE, 140325683187712, 140325683191807,
+STORE, 140325683191808, 140325708365823,
+SNULL, 140325683191808, 140325699973119,
+STORE, 140325699973120, 140325708365823,
+STORE, 140325683191808, 140325699973119,
+SNULL, 140325699977215, 140325708365823,
+STORE, 140325699973120, 140325699977215,
+STORE, 140325699977216, 140325708365823,
+STORE, 140325674795008, 140325683187711,
+STORE, 140325666402304, 140325683187711,
+STORE, 140325658009600, 140325683187711,
+SNULL, 140325658009600, 140325666402303,
+STORE, 140325666402304, 140325683187711,
+STORE, 140325658009600, 140325666402303,
+SNULL, 140325666406399, 140325683187711,
+STORE, 140325666402304, 140325666406399,
+STORE, 140325666406400, 140325683187711,
+SNULL, 140325683191808, 140325691580415,
+STORE, 140325691580416, 140325699973119,
+STORE, 140325683191808, 140325691580415,
+SNULL, 140325691584511, 140325699973119,
+STORE, 140325691580416, 140325691584511,
+STORE, 140325691584512, 140325699973119,
+SNULL, 140325666406400, 140325674795007,
+STORE, 140325674795008, 140325683187711,
+STORE, 140325666406400, 140325674795007,
+SNULL, 140325674799103, 140325683187711,
+STORE, 140325674795008, 140325674799103,
+STORE, 140325674799104, 140325683187711,
+STORE, 140325649616896, 140325666402303,
+SNULL, 140325649616896, 140325658009599,
+STORE, 140325658009600, 140325666402303,
+STORE, 140325649616896, 140325658009599,
+SNULL, 140325658013695, 140325666402303,
+STORE, 140325658009600, 140325658013695,
+STORE, 140325658013696, 140325666402303,
+SNULL, 140325649620991, 140325658009599,
+STORE, 140325649616896, 140325649620991,
+STORE, 140325649620992, 140325658009599,
+STORE, 140325641224192, 140325649616895,
+STORE, 140325632831488, 140325649616895,
+SNULL, 140325632835583, 140325649616895,
+STORE, 140325632831488, 140325632835583,
+STORE, 140325632835584, 140325649616895,
+STORE, 140325624438784, 140325632831487,
+SNULL, 140325624442879, 140325632831487,
+STORE, 140325624438784, 140325624442879,
+STORE, 140325624442880, 140325632831487,
+SNULL, 140325632835584, 140325641224191,
+STORE, 140325641224192, 140325649616895,
+STORE, 140325632835584, 140325641224191,
+SNULL, 140325641228287, 140325649616895,
+STORE, 140325641224192, 140325641228287,
+STORE, 140325641228288, 140325649616895,
+STORE, 140325616046080, 140325624438783,
+SNULL, 140325616050175, 140325624438783,
+STORE, 140325616046080, 140325616050175,
+STORE, 140325616050176, 140325624438783,
+STORE, 140325607653376, 140325616046079,
+SNULL, 140325607657471, 140325616046079,
+STORE, 140325607653376, 140325607657471,
+STORE, 140325607657472, 140325616046079,
+STORE, 140325599260672, 140325607653375,
+STORE, 140325590867968, 140325607653375,
+STORE, 140325456650240, 140325590867967,
+SNULL, 140325456650240, 140325507039231,
+STORE, 140325507039232, 140325590867967,
+STORE, 140325456650240, 140325507039231,
+ERASE, 140325456650240, 140325507039231,
+STORE, 140325498646528, 140325507039231,
+STORE, 140325364428800, 140325498646527,
+SNULL, 140325364428800, 140325372821503,
+STORE, 140325372821504, 140325498646527,
+STORE, 140325364428800, 140325372821503,
+ERASE, 140325364428800, 140325372821503,
+STORE, 140325364428800, 140325372821503,
+STORE, 140325356036096, 140325372821503,
+STORE, 140325221818368, 140325356036095,
+SNULL, 140325221818368, 140325238603775,
+STORE, 140325238603776, 140325356036095,
+STORE, 140325221818368, 140325238603775,
+ERASE, 140325221818368, 140325238603775,
+STORE, 140325230211072, 140325238603775,
+STORE, 140325221818368, 140325238603775,
+STORE, 140325087600640, 140325221818367,
+STORE, 140325079207936, 140325087600639,
+SNULL, 140325087600640, 140325104386047,
+STORE, 140325104386048, 140325221818367,
+STORE, 140325087600640, 140325104386047,
+ERASE, 140325087600640, 140325104386047,
+STORE, 140325095993344, 140325104386047,
+STORE, 140325079207936, 140325104386047,
+STORE, 140324944990208, 140325079207935,
+SNULL, 140324944990208, 140324970168319,
+STORE, 140324970168320, 140325079207935,
+STORE, 140324944990208, 140324970168319,
+ERASE, 140324944990208, 140324970168319,
+STORE, 140324961775616, 140324970168319,
+STORE, 140324953382912, 140324970168319,
+STORE, 140324819165184, 140324953382911,
+STORE, 140324684947456, 140324953382911,
+STORE, 140324676554752, 140324684947455,
+STORE, 140324668162048, 140324684947455,
+STORE, 140324533944320, 140324668162047,
+STORE, 140324525551616, 140324533944319,
+SNULL, 140324533944320, 140324567515135,
+STORE, 140324567515136, 140324668162047,
+STORE, 140324533944320, 140324567515135,
+ERASE, 140324533944320, 140324567515135,
+STORE, 140324559122432, 140324567515135,
+STORE, 140324391333888, 140324525551615,
+SNULL, 140325574148095, 140325590867967,
+STORE, 140325507039232, 140325574148095,
+STORE, 140325574148096, 140325590867967,
+ERASE, 140325574148096, 140325590867967,
+SNULL, 140325439930367, 140325498646527,
+STORE, 140325372821504, 140325439930367,
+STORE, 140325439930368, 140325498646527,
+ERASE, 140325439930368, 140325498646527,
+SNULL, 140325305712639, 140325356036095,
+STORE, 140325238603776, 140325305712639,
+STORE, 140325305712640, 140325356036095,
+ERASE, 140325305712640, 140325356036095,
+SNULL, 140325171494911, 140325221818367,
+STORE, 140325104386048, 140325171494911,
+STORE, 140325171494912, 140325221818367,
+ERASE, 140325171494912, 140325221818367,
+SNULL, 140325104521215, 140325171494911,
+STORE, 140325104386048, 140325104521215,
+STORE, 140325104521216, 140325171494911,
+STORE, 140324257116160, 140324525551615,
+SNULL, 140324257116160, 140324299079679,
+STORE, 140324299079680, 140324525551615,
+STORE, 140324257116160, 140324299079679,
+ERASE, 140324257116160, 140324299079679,
+SNULL, 140325037277183, 140325079207935,
+STORE, 140324970168320, 140325037277183,
+STORE, 140325037277184, 140325079207935,
+ERASE, 140325037277184, 140325079207935,
+SNULL, 140324819165183, 140324953382911,
+STORE, 140324684947456, 140324819165183,
+STORE, 140324819165184, 140324953382911,
+SNULL, 140324819165184, 140324835950591,
+STORE, 140324835950592, 140324953382911,
+STORE, 140324819165184, 140324835950591,
+ERASE, 140324819165184, 140324835950591,
+SNULL, 140324903059455, 140324953382911,
+STORE, 140324835950592, 140324903059455,
+STORE, 140324903059456, 140324953382911,
+ERASE, 140324903059456, 140324953382911,
+SNULL, 140324684947456, 140324701732863,
+STORE, 140324701732864, 140324819165183,
+STORE, 140324684947456, 140324701732863,
+ERASE, 140324684947456, 140324701732863,
+SNULL, 140324768841727, 140324819165183,
+STORE, 140324701732864, 140324768841727,
+STORE, 140324768841728, 140324819165183,
+ERASE, 140324768841728, 140324819165183,
+SNULL, 140324634623999, 140324668162047,
+STORE, 140324567515136, 140324634623999,
+STORE, 140324634624000, 140324668162047,
+ERASE, 140324634624000, 140324668162047,
+SNULL, 140324391333887, 140324525551615,
+STORE, 140324299079680, 140324391333887,
+STORE, 140324391333888, 140324525551615,
+SNULL, 140324391333888, 140324433297407,
+STORE, 140324433297408, 140324525551615,
+STORE, 140324391333888, 140324433297407,
+ERASE, 140324391333888, 140324433297407,
+SNULL, 140325507174399, 140325574148095,
+STORE, 140325507039232, 140325507174399,
+STORE, 140325507174400, 140325574148095,
+SNULL, 140325590867968, 140325599260671,
+STORE, 140325599260672, 140325607653375,
+STORE, 140325590867968, 140325599260671,
+SNULL, 140325599264767, 140325607653375,
+STORE, 140325599260672, 140325599264767,
+STORE, 140325599264768, 140325607653375,
+SNULL, 140325372956671, 140325439930367,
+STORE, 140325372821504, 140325372956671,
+STORE, 140325372956672, 140325439930367,
+SNULL, 140324668166143, 140324684947455,
+STORE, 140324668162048, 140324668166143,
+STORE, 140324668166144, 140324684947455,
+SNULL, 140324525555711, 140324533944319,
+STORE, 140324525551616, 140324525555711,
+STORE, 140324525555712, 140324533944319,
+SNULL, 140324953382912, 140324961775615,
+STORE, 140324961775616, 140324970168319,
+STORE, 140324953382912, 140324961775615,
+SNULL, 140324961779711, 140324970168319,
+STORE, 140324961775616, 140324961779711,
+STORE, 140324961779712, 140324970168319,
+SNULL, 140325079212031, 140325104386047,
+STORE, 140325079207936, 140325079212031,
+STORE, 140325079212032, 140325104386047,
+SNULL, 140325221818368, 140325230211071,
+STORE, 140325230211072, 140325238603775,
+STORE, 140325221818368, 140325230211071,
+SNULL, 140325230215167, 140325238603775,
+STORE, 140325230211072, 140325230215167,
+STORE, 140325230215168, 140325238603775,
+SNULL, 140325356036096, 140325364428799,
+STORE, 140325364428800, 140325372821503,
+STORE, 140325356036096, 140325364428799,
+SNULL, 140325364432895, 140325372821503,
+ };
+ unsigned long set40[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140734309167104, 140737488351231,
+SNULL, 140734309171199, 140737488351231,
+STORE, 140734309167104, 140734309171199,
+STORE, 140734309036032, 140734309171199,
+STORE, 94270500081664, 94270502334463,
+SNULL, 94270500212735, 94270502334463,
+STORE, 94270500081664, 94270500212735,
+STORE, 94270500212736, 94270502334463,
+ERASE, 94270500212736, 94270502334463,
+STORE, 94270502305792, 94270502313983,
+STORE, 94270502313984, 94270502334463,
+STORE, 140321935110144, 140321937362943,
+SNULL, 140321935253503, 140321937362943,
+STORE, 140321935110144, 140321935253503,
+STORE, 140321935253504, 140321937362943,
+ERASE, 140321935253504, 140321937362943,
+STORE, 140321937350656, 140321937358847,
+STORE, 140321937358848, 140321937362943,
+STORE, 140734309625856, 140734309629951,
+STORE, 140734309613568, 140734309625855,
+STORE, 140321937321984, 140321937350655,
+STORE, 140321937313792, 140321937321983,
+STORE, 140321932894208, 140321935110143,
+SNULL, 140321932894208, 140321932992511,
+STORE, 140321932992512, 140321935110143,
+STORE, 140321932894208, 140321932992511,
+SNULL, 140321935085567, 140321935110143,
+STORE, 140321932992512, 140321935085567,
+STORE, 140321935085568, 140321935110143,
+SNULL, 140321935085568, 140321935093759,
+STORE, 140321935093760, 140321935110143,
+STORE, 140321935085568, 140321935093759,
+ERASE, 140321935085568, 140321935093759,
+STORE, 140321935085568, 140321935093759,
+ERASE, 140321935093760, 140321935110143,
+STORE, 140321935093760, 140321935110143,
+STORE, 140321929097216, 140321932894207,
+SNULL, 140321929097216, 140321930756095,
+STORE, 140321930756096, 140321932894207,
+STORE, 140321929097216, 140321930756095,
+SNULL, 140321932853247, 140321932894207,
+STORE, 140321930756096, 140321932853247,
+STORE, 140321932853248, 140321932894207,
+SNULL, 140321932853248, 140321932877823,
+STORE, 140321932877824, 140321932894207,
+STORE, 140321932853248, 140321932877823,
+ERASE, 140321932853248, 140321932877823,
+STORE, 140321932853248, 140321932877823,
+ERASE, 140321932877824, 140321932894207,
+STORE, 140321932877824, 140321932894207,
+STORE, 140321937305600, 140321937321983,
+SNULL, 140321932869631, 140321932877823,
+STORE, 140321932853248, 140321932869631,
+STORE, 140321932869632, 140321932877823,
+SNULL, 140321935089663, 140321935093759,
+STORE, 140321935085568, 140321935089663,
+STORE, 140321935089664, 140321935093759,
+SNULL, 94270502309887, 94270502313983,
+STORE, 94270502305792, 94270502309887,
+STORE, 94270502309888, 94270502313983,
+SNULL, 140321937354751, 140321937358847,
+STORE, 140321937350656, 140321937354751,
+STORE, 140321937354752, 140321937358847,
+ERASE, 140321937321984, 140321937350655,
+STORE, 94270507364352, 94270507499519,
+STORE, 140321920704512, 140321929097215,
+SNULL, 140321920708607, 140321929097215,
+STORE, 140321920704512, 140321920708607,
+STORE, 140321920708608, 140321929097215,
+STORE, 140321912311808, 140321920704511,
+STORE, 140321778094080, 140321912311807,
+SNULL, 140321778094080, 140321816051711,
+STORE, 140321816051712, 140321912311807,
+STORE, 140321778094080, 140321816051711,
+ERASE, 140321778094080, 140321816051711,
+SNULL, 140321883160575, 140321912311807,
+STORE, 140321816051712, 140321883160575,
+STORE, 140321883160576, 140321912311807,
+ERASE, 140321883160576, 140321912311807,
+SNULL, 140321816186879, 140321883160575,
+STORE, 140321816051712, 140321816186879,
+STORE, 140321816186880, 140321883160575,
+SNULL, 140321912315903, 140321920704511,
+STORE, 140321912311808, 140321912315903,
+STORE, 140321912315904, 140321920704511,
+STORE, 140321903919104, 140321912311807,
+SNULL, 140321903923199, 140321912311807,
+STORE, 140321903919104, 140321903923199,
+STORE, 140321903923200, 140321912311807,
+STORE, 140321895526400, 140321903919103,
+SNULL, 140321895530495, 140321903919103,
+STORE, 140321895526400, 140321895530495,
+STORE, 140321895530496, 140321903919103,
+STORE, 140321887133696, 140321895526399,
+SNULL, 140321887137791, 140321895526399,
+STORE, 140321887133696, 140321887137791,
+STORE, 140321887137792, 140321895526399,
+STORE, 140321807659008, 140321816051711,
+STORE, 140321673441280, 140321807659007,
+SNULL, 140321673441280, 140321681833983,
+STORE, 140321681833984, 140321807659007,
+STORE, 140321673441280, 140321681833983,
+ERASE, 140321673441280, 140321681833983,
+SNULL, 140321748942847, 140321807659007,
+STORE, 140321681833984, 140321748942847,
+STORE, 140321748942848, 140321807659007,
+ERASE, 140321748942848, 140321807659007,
+STORE, 140321799266304, 140321816051711,
+STORE, 140321790873600, 140321816051711,
+STORE, 140321782480896, 140321816051711,
+STORE, 140321547616256, 140321748942847,
+SNULL, 140321614725119, 140321748942847,
+STORE, 140321547616256, 140321614725119,
+STORE, 140321614725120, 140321748942847,
+SNULL, 140321614725120, 140321681833983,
+STORE, 140321681833984, 140321748942847,
+STORE, 140321614725120, 140321681833983,
+ERASE, 140321614725120, 140321681833983,
+SNULL, 140321681969151, 140321748942847,
+STORE, 140321681833984, 140321681969151,
+STORE, 140321681969152, 140321748942847,
+STORE, 140321547616256, 140321681833983,
+SNULL, 140321547616256, 140321614725119,
+STORE, 140321614725120, 140321681833983,
+STORE, 140321547616256, 140321614725119,
+SNULL, 140321614860287, 140321681833983,
+STORE, 140321614725120, 140321614860287,
+STORE, 140321614860288, 140321681833983,
+SNULL, 140321547751423, 140321614725119,
+STORE, 140321547616256, 140321547751423,
+STORE, 140321547751424, 140321614725119,
+STORE, 140321480507392, 140321547616255,
+SNULL, 140321782480896, 140321799266303,
+STORE, 140321799266304, 140321816051711,
+STORE, 140321782480896, 140321799266303,
+SNULL, 140321799270399, 140321816051711,
+STORE, 140321799266304, 140321799270399,
+STORE, 140321799270400, 140321816051711,
+STORE, 140321774088192, 140321799266303,
+SNULL, 140321774088192, 140321790873599,
+STORE, 140321790873600, 140321799266303,
+STORE, 140321774088192, 140321790873599,
+SNULL, 140321790877695, 140321799266303,
+STORE, 140321790873600, 140321790877695,
+STORE, 140321790877696, 140321799266303,
+SNULL, 140321480642559, 140321547616255,
+STORE, 140321480507392, 140321480642559,
+STORE, 140321480642560, 140321547616255,
+SNULL, 140321774088192, 140321782480895,
+STORE, 140321782480896, 140321790873599,
+STORE, 140321774088192, 140321782480895,
+SNULL, 140321782484991, 140321790873599,
+STORE, 140321782480896, 140321782484991,
+STORE, 140321782484992, 140321790873599,
+SNULL, 140321799270400, 140321807659007,
+STORE, 140321807659008, 140321816051711,
+STORE, 140321799270400, 140321807659007,
+SNULL, 140321807663103, 140321816051711,
+STORE, 140321807659008, 140321807663103,
+STORE, 140321807663104, 140321816051711,
+STORE, 140321765695488, 140321782480895,
+STORE, 140321757302784, 140321782480895,
+SNULL, 140321757306879, 140321782480895,
+STORE, 140321757302784, 140321757306879,
+STORE, 140321757306880, 140321782480895,
+STORE, 140321472114688, 140321480507391,
+STORE, 140321463721984, 140321480507391,
+SNULL, 140321463726079, 140321480507391,
+STORE, 140321463721984, 140321463726079,
+STORE, 140321463726080, 140321480507391,
+SNULL, 140321757306880, 140321774088191,
+STORE, 140321774088192, 140321782480895,
+STORE, 140321757306880, 140321774088191,
+SNULL, 140321774092287, 140321782480895,
+STORE, 140321774088192, 140321774092287,
+STORE, 140321774092288, 140321782480895,
+SNULL, 140321463726080, 140321472114687,
+STORE, 140321472114688, 140321480507391,
+STORE, 140321463726080, 140321472114687,
+SNULL, 140321472118783, 140321480507391,
+STORE, 140321472114688, 140321472118783,
+STORE, 140321472118784, 140321480507391,
+SNULL, 140321757306880, 140321765695487,
+STORE, 140321765695488, 140321774088191,
+STORE, 140321757306880, 140321765695487,
+SNULL, 140321765699583, 140321774088191,
+STORE, 140321765695488, 140321765699583,
+STORE, 140321765699584, 140321774088191,
+STORE, 140321455329280, 140321463721983,
+SNULL, 140321455333375, 140321463721983,
+STORE, 140321455329280, 140321455333375,
+STORE, 140321455333376, 140321463721983,
+STORE, 140321446936576, 140321455329279,
+STORE, 140321438543872, 140321455329279,
+STORE, 140321430151168, 140321455329279,
+SNULL, 140321430155263, 140321455329279,
+STORE, 140321430151168, 140321430155263,
+STORE, 140321430155264, 140321455329279,
+SNULL, 140321430155264, 140321446936575,
+STORE, 140321446936576, 140321455329279,
+STORE, 140321430155264, 140321446936575,
+SNULL, 140321446940671, 140321455329279,
+STORE, 140321446936576, 140321446940671,
+STORE, 140321446940672, 140321455329279,
+SNULL, 140321430155264, 140321438543871,
+STORE, 140321438543872, 140321446936575,
+STORE, 140321430155264, 140321438543871,
+SNULL, 140321438547967, 140321446936575,
+STORE, 140321438543872, 140321438547967,
+STORE, 140321438547968, 140321446936575,
+STORE, 140321421758464, 140321430151167,
+SNULL, 140321421762559, 140321430151167,
+STORE, 140321421758464, 140321421762559,
+STORE, 140321421762560, 140321430151167,
+STORE, 140321413365760, 140321421758463,
+SNULL, 140321413369855, 140321421758463,
+STORE, 140321413365760, 140321413369855,
+STORE, 140321413369856, 140321421758463,
+STORE, 140321404973056, 140321413365759,
+SNULL, 140321404977151, 140321413365759,
+STORE, 140321404973056, 140321404977151,
+STORE, 140321404977152, 140321413365759,
+STORE, 140321396580352, 140321404973055,
+STORE, 140321388187648, 140321404973055,
+STORE, 140321253969920, 140321388187647,
+SNULL, 140321253969920, 140321279180799,
+STORE, 140321279180800, 140321388187647,
+STORE, 140321253969920, 140321279180799,
+ERASE, 140321253969920, 140321279180799,
+SNULL, 140321346289663, 140321388187647,
+STORE, 140321279180800, 140321346289663,
+STORE, 140321346289664, 140321388187647,
+ERASE, 140321346289664, 140321388187647,
+STORE, 140321144963072, 140321346289663,
+STORE, 140321379794944, 140321404973055,
+STORE, 140321371402240, 140321404973055,
+STORE, 140321010745344, 140321346289663,
+STORE, 140321363009536, 140321404973055,
+SNULL, 140321077854207, 140321346289663,
+STORE, 140321010745344, 140321077854207,
+STORE, 140321077854208, 140321346289663,
+SNULL, 140321077854208, 140321144963071,
+STORE, 140321144963072, 140321346289663,
+STORE, 140321077854208, 140321144963071,
+ERASE, 140321077854208, 140321144963071,
+STORE, 140321354616832, 140321404973055,
+STORE, 140321136570368, 140321144963071,
+STORE, 140320943636480, 140321077854207,
+STORE, 140320876527616, 140321077854207,
+STORE, 140321128177664, 140321144963071,
+SNULL, 140320876662783, 140321077854207,
+STORE, 140320876527616, 140320876662783,
+STORE, 140320876662784, 140321077854207,
+STORE, 140321119784960, 140321144963071,
+STORE, 140321111392256, 140321144963071,
+STORE, 140320742309888, 140320876527615,
+STORE, 140321102999552, 140321144963071,
+STORE, 140320608092160, 140320876527615,
+SNULL, 140320675201023, 140320876527615,
+STORE, 140320608092160, 140320675201023,
+STORE, 140320675201024, 140320876527615,
+SNULL, 140320675201024, 140320742309887,
+STORE, 140320742309888, 140320876527615,
+STORE, 140320675201024, 140320742309887,
+ERASE, 140320675201024, 140320742309887,
+STORE, 140321094606848, 140321144963071,
+STORE, 140321086214144, 140321144963071,
+STORE, 140320608092160, 140320876527615,
+SNULL, 140320608092160, 140320675201023,
+STORE, 140320675201024, 140320876527615,
+STORE, 140320608092160, 140320675201023,
+SNULL, 140320675336191, 140320876527615,
+STORE, 140320675201024, 140320675336191,
+STORE, 140320675336192, 140320876527615,
+STORE, 140320599699456, 140320608092159,
+STORE, 140320591306752, 140320608092159,
+STORE, 140320457089024, 140320591306751,
+STORE, 140320448696320, 140320457089023,
+STORE, 140320314478592, 140320448696319,
+SNULL, 140321144963072, 140321279180799,
+STORE, 140321279180800, 140321346289663,
+STORE, 140321144963072, 140321279180799,
+SNULL, 140321279315967, 140321346289663,
+STORE, 140321279180800, 140321279315967,
+STORE, 140321279315968, 140321346289663,
+SNULL, 140321086214144, 140321136570367,
+STORE, 140321136570368, 140321144963071,
+STORE, 140321086214144, 140321136570367,
+SNULL, 140321136574463, 140321144963071,
+STORE, 140321136570368, 140321136574463,
+STORE, 140321136574464, 140321144963071,
+SNULL, 140321212071935, 140321279180799,
+STORE, 140321144963072, 140321212071935,
+STORE, 140321212071936, 140321279180799,
+ERASE, 140321212071936, 140321279180799,
+SNULL, 140321145098239, 140321212071935,
+STORE, 140321144963072, 140321145098239,
+STORE, 140321145098240, 140321212071935,
+SNULL, 140320876662784, 140321010745343,
+STORE, 140321010745344, 140321077854207,
+STORE, 140320876662784, 140321010745343,
+SNULL, 140321010880511, 140321077854207,
+STORE, 140321010745344, 140321010880511,
+STORE, 140321010880512, 140321077854207,
+SNULL, 140321354616832, 140321379794943,
+STORE, 140321379794944, 140321404973055,
+STORE, 140321354616832, 140321379794943,
+SNULL, 140321379799039, 140321404973055,
+STORE, 140321379794944, 140321379799039,
+STORE, 140321379799040, 140321404973055,
+SNULL, 140320876662784, 140320943636479,
+STORE, 140320943636480, 140321010745343,
+STORE, 140320876662784, 140320943636479,
+SNULL, 140320943771647, 140321010745343,
+STORE, 140320943636480, 140320943771647,
+STORE, 140320943771648, 140321010745343,
+SNULL, 140320809418751, 140320876527615,
+STORE, 140320675336192, 140320809418751,
+STORE, 140320809418752, 140320876527615,
+ERASE, 140320809418752, 140320876527615,
+SNULL, 140320675336192, 140320742309887,
+STORE, 140320742309888, 140320809418751,
+STORE, 140320675336192, 140320742309887,
+SNULL, 140320742445055, 140320809418751,
+STORE, 140320742309888, 140320742445055,
+STORE, 140320742445056, 140320809418751,
+SNULL, 140320608227327, 140320675201023,
+STORE, 140320608092160, 140320608227327,
+STORE, 140320608227328, 140320675201023,
+SNULL, 140320457089024, 140320473874431,
+STORE, 140320473874432, 140320591306751,
+STORE, 140320457089024, 140320473874431,
+ERASE, 140320457089024, 140320473874431,
+SNULL, 140320540983295, 140320591306751,
+STORE, 140320473874432, 140320540983295,
+STORE, 140320540983296, 140320591306751,
+ERASE, 140320540983296, 140320591306751,
+SNULL, 140320314478592, 140320339656703,
+STORE, 140320339656704, 140320448696319,
+STORE, 140320314478592, 140320339656703,
+ERASE, 140320314478592, 140320339656703,
+SNULL, 140321086214144, 140321128177663,
+STORE, 140321128177664, 140321136570367,
+STORE, 140321086214144, 140321128177663,
+SNULL, 140321128181759, 140321136570367,
+STORE, 140321128177664, 140321128181759,
+STORE, 140321128181760, 140321136570367,
+SNULL, 140321354616832, 140321371402239,
+STORE, 140321371402240, 140321379794943,
+STORE, 140321354616832, 140321371402239,
+SNULL, 140321371406335, 140321379794943,
+STORE, 140321371402240, 140321371406335,
+STORE, 140321371406336, 140321379794943,
+SNULL, 140320591310847, 140320608092159,
+STORE, 140320591306752, 140320591310847,
+STORE, 140320591310848, 140320608092159,
+SNULL, 140321354616832, 140321363009535,
+STORE, 140321363009536, 140321371402239,
+STORE, 140321354616832, 140321363009535,
+SNULL, 140321363013631, 140321371402239,
+STORE, 140321363009536, 140321363013631,
+STORE, 140321363013632, 140321371402239,
+SNULL, 140321086214144, 140321119784959,
+STORE, 140321119784960, 140321128177663,
+STORE, 140321086214144, 140321119784959,
+SNULL, 140321119789055, 140321128177663,
+STORE, 140321119784960, 140321119789055,
+STORE, 140321119789056, 140321128177663,
+SNULL, 140321086218239, 140321119784959,
+STORE, 140321086214144, 140321086218239,
+STORE, 140321086218240, 140321119784959,
+SNULL, 140321086218240, 140321094606847,
+STORE, 140321094606848, 140321119784959,
+STORE, 140321086218240, 140321094606847,
+SNULL, 140321094610943, 140321119784959,
+STORE, 140321094606848, 140321094610943,
+STORE, 140321094610944, 140321119784959,
+SNULL, 140320474009599, 140320540983295,
+STORE, 140320473874432, 140320474009599,
+STORE, 140320474009600, 140320540983295,
+SNULL, 140320406765567, 140320448696319,
+STORE, 140320339656704, 140320406765567,
+STORE, 140320406765568, 140320448696319,
+ERASE, 140320406765568, 140320448696319,
+SNULL, 140320339791871, 140320406765567,
+STORE, 140320339656704, 140320339791871,
+STORE, 140320339791872, 140320406765567,
+STORE, 140321270788096, 140321279180799,
+STORE, 140321262395392, 140321279180799,
+STORE, 140321254002688, 140321279180799,
+SNULL, 140321254002688, 140321262395391,
+STORE, 140321262395392, 140321279180799,
+STORE, 140321254002688, 140321262395391,
+SNULL, 140321262399487, 140321279180799,
+STORE, 140321262395392, 140321262399487,
+STORE, 140321262399488, 140321279180799,
+STORE, 140321245609984, 140321262395391,
+STORE, 140321237217280, 140321262395391,
+SNULL, 140321237217280, 140321245609983,
+STORE, 140321245609984, 140321262395391,
+STORE, 140321237217280, 140321245609983,
+SNULL, 140321245614079, 140321262395391,
+STORE, 140321245609984, 140321245614079,
+STORE, 140321245614080, 140321262395391,
+SNULL, 140321379799040, 140321388187647,
+STORE, 140321388187648, 140321404973055,
+STORE, 140321379799040, 140321388187647,
+SNULL, 140321388191743, 140321404973055,
+STORE, 140321388187648, 140321388191743,
+STORE, 140321388191744, 140321404973055,
+SNULL, 140321354620927, 140321363009535,
+STORE, 140321354616832, 140321354620927,
+STORE, 140321354620928, 140321363009535,
+SNULL, 140321388191744, 140321396580351,
+STORE, 140321396580352, 140321404973055,
+STORE, 140321388191744, 140321396580351,
+SNULL, 140321396584447, 140321404973055,
+STORE, 140321396580352, 140321396584447,
+STORE, 140321396584448, 140321404973055,
+SNULL, 140321094610944, 140321111392255,
+STORE, 140321111392256, 140321119784959,
+STORE, 140321094610944, 140321111392255,
+SNULL, 140321111396351, 140321119784959,
+STORE, 140321111392256, 140321111396351,
+STORE, 140321111396352, 140321119784959,
+STORE, 140321228824576, 140321245609983,
+SNULL, 140321094610944, 140321102999551,
+STORE, 140321102999552, 140321111392255,
+STORE, 140321094610944, 140321102999551,
+SNULL, 140321103003647, 140321111392255,
+STORE, 140321102999552, 140321103003647,
+STORE, 140321103003648, 140321111392255,
+STORE, 140321220431872, 140321245609983,
+SNULL, 140321220435967, 140321245609983,
+STORE, 140321220431872, 140321220435967,
+STORE, 140321220435968, 140321245609983,
+STORE, 140320868134912, 140320876527615,
+SNULL, 140320868139007, 140320876527615,
+STORE, 140320868134912, 140320868139007,
+STORE, 140320868139008, 140320876527615,
+SNULL, 140320591310848, 140320599699455,
+STORE, 140320599699456, 140320608092159,
+STORE, 140320591310848, 140320599699455,
+SNULL, 140320599703551, 140320608092159,
+STORE, 140320599699456, 140320599703551,
+STORE, 140320599703552, 140320608092159,
+STORE, 140320859742208, 140320868134911,
+SNULL, 140321262399488, 140321270788095,
+STORE, 140321270788096, 140321279180799,
+STORE, 140321262399488, 140321270788095,
+SNULL, 140321270792191, 140321279180799,
+STORE, 140321270788096, 140321270792191,
+STORE, 140321270792192, 140321279180799,
+STORE, 140320851349504, 140320868134911,
+STORE, 140320842956800, 140320868134911,
+STORE, 140320834564096, 140320868134911,
+STORE, 140320826171392, 140320868134911,
+SNULL, 140320826171392, 140320834564095,
+STORE, 140320834564096, 140320868134911,
+STORE, 140320826171392, 140320834564095,
+SNULL, 140320834568191, 140320868134911,
+STORE, 140320834564096, 140320834568191,
+STORE, 140320834568192, 140320868134911,
+SNULL, 140321220435968, 140321228824575,
+STORE, 140321228824576, 140321245609983,
+STORE, 140321220435968, 140321228824575,
+SNULL, 140321228828671, 140321245609983,
+STORE, 140321228824576, 140321228828671,
+STORE, 140321228828672, 140321245609983,
+STORE, 140320817778688, 140320834564095,
+SNULL, 140320817782783, 140320834564095,
+STORE, 140320817778688, 140320817782783,
+STORE, 140320817782784, 140320834564095,
+STORE, 140320582914048, 140320591306751,
+SNULL, 140321228828672, 140321237217279,
+STORE, 140321237217280, 140321245609983,
+STORE, 140321228828672, 140321237217279,
+SNULL, 140321237221375, 140321245609983,
+STORE, 140321237217280, 140321237221375,
+STORE, 140321237221376, 140321245609983,
+SNULL, 140320448700415, 140320457089023,
+STORE, 140320448696320, 140320448700415,
+STORE, 140320448700416, 140320457089023,
+SNULL, 140321245614080, 140321254002687,
+STORE, 140321254002688, 140321262395391,
+STORE, 140321245614080, 140321254002687,
+SNULL, 140321254006783, 140321262395391,
+STORE, 140321254002688, 140321254006783,
+STORE, 140321254006784, 140321262395391,
+STORE, 140320574521344, 140320591306751,
+SNULL, 140320574525439, 140320591306751,
+STORE, 140320574521344, 140320574525439,
+STORE, 140320574525440, 140320591306751,
+STORE, 140320566128640, 140320574521343,
+SNULL, 140320566132735, 140320574521343,
+STORE, 140320566128640, 140320566132735,
+STORE, 140320566132736, 140320574521343,
+SNULL, 140320574525440, 140320582914047,
+STORE, 140320582914048, 140320591306751,
+STORE, 140320574525440, 140320582914047,
+SNULL, 140320582918143, 140320591306751,
+STORE, 140320582914048, 140320582918143,
+STORE, 140320582918144, 140320591306751,
+STORE, 140320557735936, 140320566128639,
+SNULL, 140320557740031, 140320566128639,
+STORE, 140320557735936, 140320557740031,
+STORE, 140320557740032, 140320566128639,
+STORE, 140320549343232, 140320557735935,
+STORE, 140320465481728, 140320473874431,
+STORE, 140320448700416, 140320473874431,
+SNULL, 140320834568192, 140320859742207,
+STORE, 140320859742208, 140320868134911,
+STORE, 140320834568192, 140320859742207,
+SNULL, 140320859746303, 140320868134911,
+STORE, 140320859742208, 140320859746303,
+STORE, 140320859746304, 140320868134911,
+STORE, 140320440303616, 140320448696319,
+STORE, 140320431910912, 140320448696319,
+SNULL, 140320834568192, 140320851349503,
+STORE, 140320851349504, 140320859742207,
+STORE, 140320834568192, 140320851349503,
+SNULL, 140320851353599, 140320859742207,
+STORE, 140320851349504, 140320851353599,
+STORE, 140320851353600, 140320859742207,
+SNULL, 140320817782784, 140320826171391,
+STORE, 140320826171392, 140320834564095,
+STORE, 140320817782784, 140320826171391,
+SNULL, 140320826175487, 140320834564095,
+STORE, 140320826171392, 140320826175487,
+STORE, 140320826175488, 140320834564095,
+SNULL, 140320834568192, 140320842956799,
+STORE, 140320842956800, 140320851349503,
+STORE, 140320834568192, 140320842956799,
+SNULL, 140320842960895, 140320851349503,
+STORE, 140320842956800, 140320842960895,
+STORE, 140320842960896, 140320851349503,
+STORE, 140320423518208, 140320448696319,
+SNULL, 140320423522303, 140320448696319,
+STORE, 140320423518208, 140320423522303,
+STORE, 140320423522304, 140320448696319,
+STORE, 140320415125504, 140320423518207,
+STORE, 140320331264000, 140320339656703,
+STORE, 140320322871296, 140320339656703,
+STORE, 140320314478592, 140320339656703,
+SNULL, 140320314482687, 140320339656703,
+STORE, 140320314478592, 140320314482687,
+STORE, 140320314482688, 140320339656703,
+STORE, 140320306085888, 140320314478591,
+SNULL, 140320306089983, 140320314478591,
+STORE, 140320306085888, 140320306089983,
+STORE, 140320306089984, 140320314478591,
+STORE, 140320297693184, 140320306085887,
+SNULL, 140320297697279, 140320306085887,
+STORE, 140320297693184, 140320297697279,
+STORE, 140320297697280, 140320306085887,
+STORE, 140320289300480, 140320297693183,
+STORE, 140320280907776, 140320297693183,
+SNULL, 140320280911871, 140320297693183,
+STORE, 140320280907776, 140320280911871,
+STORE, 140320280911872, 140320297693183,
+SNULL, 140320423522304, 140320431910911,
+STORE, 140320431910912, 140320448696319,
+STORE, 140320423522304, 140320431910911,
+SNULL, 140320431915007, 140320448696319,
+STORE, 140320431910912, 140320431915007,
+STORE, 140320431915008, 140320448696319,
+SNULL, 140320549347327, 140320557735935,
+STORE, 140320549343232, 140320549347327,
+STORE, 140320549347328, 140320557735935,
+STORE, 140320272515072, 140320280907775,
+SNULL, 140320448700416, 140320457089023,
+STORE, 140320457089024, 140320473874431,
+STORE, 140320448700416, 140320457089023,
+SNULL, 140320457093119, 140320473874431,
+STORE, 140320457089024, 140320457093119,
+STORE, 140320457093120, 140320473874431,
+STORE, 140320264122368, 140320280907775,
+SNULL, 140320457093120, 140320465481727,
+STORE, 140320465481728, 140320473874431,
+STORE, 140320457093120, 140320465481727,
+SNULL, 140320465485823, 140320473874431,
+STORE, 140320465481728, 140320465485823,
+STORE, 140320465485824, 140320473874431,
+SNULL, 140320431915008, 140320440303615,
+STORE, 140320440303616, 140320448696319,
+STORE, 140320431915008, 140320440303615,
+SNULL, 140320440307711, 140320448696319,
+STORE, 140320440303616, 140320440307711,
+STORE, 140320440307712, 140320448696319,
+STORE, 140320255729664, 140320280907775,
+STORE, 140320247336960, 140320280907775,
+SNULL, 140320247341055, 140320280907775,
+STORE, 140320247336960, 140320247341055,
+STORE, 140320247341056, 140320280907775,
+STORE, 140320238944256, 140320247336959,
+STORE, 140320230551552, 140320247336959,
+SNULL, 140320230551552, 140320238944255,
+STORE, 140320238944256, 140320247336959,
+STORE, 140320230551552, 140320238944255,
+SNULL, 140320238948351, 140320247336959,
+STORE, 140320238944256, 140320238948351,
+STORE, 140320238948352, 140320247336959,
+SNULL, 140320314482688, 140320331263999,
+STORE, 140320331264000, 140320339656703,
+STORE, 140320314482688, 140320331263999,
+SNULL, 140320331268095, 140320339656703,
+STORE, 140320331264000, 140320331268095,
+STORE, 140320331268096, 140320339656703,
+SNULL, 140320280911872, 140320289300479,
+STORE, 140320289300480, 140320297693183,
+STORE, 140320280911872, 140320289300479,
+SNULL, 140320289304575, 140320297693183,
+STORE, 140320289300480, 140320289304575,
+STORE, 140320289304576, 140320297693183,
+SNULL, 140320415129599, 140320423518207,
+STORE, 140320415125504, 140320415129599,
+STORE, 140320415129600, 140320423518207,
+STORE, 140320222158848, 140320238944255,
+STORE, 140320213766144, 140320238944255,
+STORE, 140320205373440, 140320238944255,
+SNULL, 140320205377535, 140320238944255,
+STORE, 140320205373440, 140320205377535,
+STORE, 140320205377536, 140320238944255,
+SNULL, 140320314482688, 140320322871295,
+STORE, 140320322871296, 140320331263999,
+STORE, 140320314482688, 140320322871295,
+SNULL, 140320322875391, 140320331263999,
+STORE, 140320322871296, 140320322875391,
+STORE, 140320322875392, 140320331263999,
+SNULL, 140320247341056, 140320272515071,
+STORE, 140320272515072, 140320280907775,
+STORE, 140320247341056, 140320272515071,
+SNULL, 140320272519167, 140320280907775,
+STORE, 140320272515072, 140320272519167,
+STORE, 140320272519168, 140320280907775,
+SNULL, 140320247341056, 140320264122367,
+STORE, 140320264122368, 140320272515071,
+STORE, 140320247341056, 140320264122367,
+SNULL, 140320264126463, 140320272515071,
+STORE, 140320264122368, 140320264126463,
+STORE, 140320264126464, 140320272515071,
+SNULL, 140320205377536, 140320230551551,
+STORE, 140320230551552, 140320238944255,
+STORE, 140320205377536, 140320230551551,
+SNULL, 140320230555647, 140320238944255,
+STORE, 140320230551552, 140320230555647,
+STORE, 140320230555648, 140320238944255,
+STORE, 140320196980736, 140320205373439,
+SNULL, 140320196984831, 140320205373439,
+STORE, 140320196980736, 140320196984831,
+STORE, 140320196984832, 140320205373439,
+STORE, 140320188588032, 140320196980735,
+SNULL, 140320247341056, 140320255729663,
+STORE, 140320255729664, 140320264122367,
+STORE, 140320247341056, 140320255729663,
+SNULL, 140320255733759, 140320264122367,
+STORE, 140320255729664, 140320255733759,
+STORE, 140320255733760, 140320264122367,
+STORE, 140320180195328, 140320196980735,
+SNULL, 140320180199423, 140320196980735,
+STORE, 140320180195328, 140320180199423,
+STORE, 140320180199424, 140320196980735,
+STORE, 140320171802624, 140320180195327,
+STORE, 140320163409920, 140320180195327,
+SNULL, 140320163414015, 140320180195327,
+STORE, 140320163409920, 140320163414015,
+STORE, 140320163414016, 140320180195327,
+SNULL, 140320205377536, 140320222158847,
+STORE, 140320222158848, 140320230551551,
+STORE, 140320205377536, 140320222158847,
+SNULL, 140320222162943, 140320230551551,
+STORE, 140320222158848, 140320222162943,
+STORE, 140320222162944, 140320230551551,
+SNULL, 140320205377536, 140320213766143,
+STORE, 140320213766144, 140320222158847,
+STORE, 140320205377536, 140320213766143,
+SNULL, 140320213770239, 140320222158847,
+STORE, 140320213766144, 140320213770239,
+STORE, 140320213770240, 140320222158847,
+STORE, 140320155017216, 140320163409919,
+SNULL, 140320180199424, 140320188588031,
+STORE, 140320188588032, 140320196980735,
+STORE, 140320180199424, 140320188588031,
+SNULL, 140320188592127, 140320196980735,
+STORE, 140320188588032, 140320188592127,
+STORE, 140320188592128, 140320196980735,
+SNULL, 140320155021311, 140320163409919,
+STORE, 140320155017216, 140320155021311,
+STORE, 140320155021312, 140320163409919,
+SNULL, 140320163414016, 140320171802623,
+STORE, 140320171802624, 140320180195327,
+STORE, 140320163414016, 140320171802623,
+SNULL, 140320171806719, 140320180195327,
+STORE, 140320171802624, 140320171806719,
+STORE, 140320171806720, 140320180195327,
+STORE, 140320146624512, 140320155017215,
+SNULL, 140320146628607, 140320155017215,
+STORE, 140320146624512, 140320146628607,
+STORE, 140320146628608, 140320155017215,
+STORE, 140321937321984, 140321937350655,
+STORE, 140321884942336, 140321887133695,
+SNULL, 140321884942336, 140321885032447,
+STORE, 140321885032448, 140321887133695,
+STORE, 140321884942336, 140321885032447,
+SNULL, 140321887125503, 140321887133695,
+STORE, 140321885032448, 140321887125503,
+STORE, 140321887125504, 140321887133695,
+ERASE, 140321887125504, 140321887133695,
+STORE, 140321887125504, 140321887133695,
+SNULL, 140321887129599, 140321887133695,
+STORE, 140321887125504, 140321887129599,
+STORE, 140321887129600, 140321887133695,
+ERASE, 140321937321984, 140321937350655,
+ERASE, 140321086214144, 140321086218239,
+ERASE, 140321086218240, 140321094606847,
+ERASE, 140321119784960, 140321119789055,
+ERASE, 140321119789056, 140321128177663,
+ERASE, 140321245609984, 140321245614079,
+ERASE, 140321245614080, 140321254002687,
+ERASE, 140320574521344, 140320574525439,
+ERASE, 140320574525440, 140320582914047,
+ERASE, 140320297693184, 140320297697279,
+ERASE, 140320297697280, 140320306085887,
+ERASE, 140321354616832, 140321354620927,
+ERASE, 140321354620928, 140321363009535,
+ERASE, 140320834564096, 140320834568191,
+ERASE, 140320834568192, 140320842956799,
+ERASE, 140320591306752, 140320591310847,
+ERASE, 140320591310848, 140320599699455,
+ERASE, 140321136570368, 140321136574463,
+ERASE, 140321136574464, 140321144963071,
+ERASE, 140321237217280, 140321237221375,
+ERASE, 140321237221376, 140321245609983,
+ERASE, 140321363009536, 140321363013631,
+ERASE, 140321363013632, 140321371402239,
+ERASE, 140320599699456, 140320599703551,
+ERASE, 140320599703552, 140320608092159,
+ERASE, 140321396580352, 140321396584447,
+ERASE, 140321396584448, 140321404973055,
+ERASE, 140320566128640, 140320566132735,
+ERASE, 140320566132736, 140320574521343,
+ERASE, 140321094606848, 140321094610943,
+ERASE, 140321094610944, 140321102999551,
+ERASE, 140320582914048, 140320582918143,
+ERASE, 140320582918144, 140320591306751,
+ERASE, 140320289300480, 140320289304575,
+ERASE, 140320289304576, 140320297693183,
+ERASE, 140320163409920, 140320163414015,
+ };
+ unsigned long set41[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140728157171712, 140737488351231,
+SNULL, 140728157175807, 140737488351231,
+STORE, 140728157171712, 140728157175807,
+STORE, 140728157040640, 140728157175807,
+STORE, 94376106364928, 94376108613631,
+SNULL, 94376106487807, 94376108613631,
+STORE, 94376106364928, 94376106487807,
+STORE, 94376106487808, 94376108613631,
+SNULL, 94376106487808, 94376108613631,
+STORE, 94376108584960, 94376108593151,
+STORE, 94376108593152, 94376108613631,
+STORE, 140113496432640, 140113498685439,
+SNULL, 140113496575999, 140113498685439,
+STORE, 140113496432640, 140113496575999,
+STORE, 140113496576000, 140113498685439,
+SNULL, 140113496576000, 140113498685439,
+STORE, 140113498673152, 140113498681343,
+STORE, 140113498681344, 140113498685439,
+STORE, 140728157609984, 140728157618175,
+STORE, 140728157593600, 140728157609983,
+STORE, 140113498636288, 140113498673151,
+STORE, 140113498628096, 140113498636287,
+STORE, 140113492635648, 140113496432639,
+SNULL, 140113492635648, 140113494294527,
+STORE, 140113494294528, 140113496432639,
+STORE, 140113492635648, 140113494294527,
+SNULL, 140113496391679, 140113496432639,
+STORE, 140113494294528, 140113496391679,
+STORE, 140113496391680, 140113496432639,
+SNULL, 140113496391680, 140113496416255,
+STORE, 140113496416256, 140113496432639,
+STORE, 140113496391680, 140113496416255,
+SNULL, 140113496391680, 140113496416255,
+STORE, 140113496391680, 140113496416255,
+SNULL, 140113496416256, 140113496432639,
+STORE, 140113496416256, 140113496432639,
+SNULL, 140113496408063, 140113496416255,
+STORE, 140113496391680, 140113496408063,
+STORE, 140113496408064, 140113496416255,
+SNULL, 94376108589055, 94376108593151,
+STORE, 94376108584960, 94376108589055,
+STORE, 94376108589056, 94376108593151,
+SNULL, 140113498677247, 140113498681343,
+STORE, 140113498673152, 140113498677247,
+STORE, 140113498677248, 140113498681343,
+SNULL, 140113498636288, 140113498673151,
+STORE, 94376135090176, 94376135094271,
+STORE, 94376135090176, 94376135098367,
+STORE, 94376139288576, 94376139292671,
+STORE, 94376143482880, 94376143486975,
+STORE, 94376147677184, 94376147681279,
+STORE, 94376151871488, 94376151875583,
+STORE, 94376156065792, 94376156069887,
+STORE, 94376160260096, 94376160264191,
+STORE, 94376164454400, 94376164458495,
+STORE, 94376168648704, 94376168652799,
+STORE, 94376172843008, 94376172847103,
+STORE, 94376177037312, 94376177041407,
+STORE, 94376181231616, 94376181235711,
+STORE, 94376185425920, 94376185430015,
+STORE, 94376189620224, 94376189624319,
+STORE, 94376193814528, 94376193818623,
+STORE, 94376198008832, 94376198012927,
+STORE, 94376202203136, 94376202207231,
+STORE, 94376206397440, 94376206401535,
+STORE, 94376210591744, 94376210595839,
+STORE, 94376214786048, 94376214790143,
+STORE, 94376218980352, 94376218984447,
+STORE, 94376223174656, 94376223178751,
+STORE, 94376227368960, 94376227373055,
+STORE, 94376231563264, 94376231567359,
+STORE, 94376235757568, 94376235761663,
+STORE, 94376239951872, 94376239955967,
+STORE, 94376244146176, 94376244150271,
+STORE, 94376248340480, 94376248344575,
+STORE, 94376252534784, 94376252538879,
+STORE, 94376256729088, 94376256733183,
+STORE, 94376260923392, 94376260927487,
+STORE, 94376265117696, 94376265121791,
+STORE, 94376269312000, 94376269316095,
+STORE, 94376273506304, 94376273510399,
+STORE, 94376277700608, 94376277704703,
+STORE, 94376281894912, 94376281899007,
+STORE, 94376286089216, 94376286093311,
+STORE, 94376290283520, 94376290287615,
+STORE, 94376294477824, 94376294481919,
+STORE, 94376298672128, 94376298676223,
+STORE, 94376302866432, 94376302870527,
+STORE, 94376307060736, 94376307064831,
+STORE, 94376311255040, 94376311259135,
+STORE, 94376315449344, 94376315453439,
+STORE, 94376319643648, 94376319647743,
+STORE, 94376323837952, 94376323842047,
+STORE, 94376328032256, 94376328036351,
+STORE, 94376332226560, 94376332230655,
+STORE, 94376336420864, 94376336424959,
+STORE, 94376340615168, 94376340619263,
+STORE, 94376344809472, 94376344813567,
+STORE, 94376349003776, 94376349007871,
+STORE, 94376353198080, 94376353202175,
+STORE, 94376357392384, 94376357396479,
+STORE, 94376361586688, 94376361590783,
+STORE, 94376365780992, 94376365785087,
+STORE, 94376369975296, 94376369979391,
+STORE, 94376374169600, 94376374173695,
+STORE, 94376378363904, 94376378367999,
+STORE, 94376382558208, 94376382562303,
+STORE, 94376386752512, 94376386756607,
+STORE, 94376390946816, 94376390950911,
+STORE, 94376395141120, 94376395145215,
+STORE, 94376399335424, 94376399339519,
+STORE, 94376403529728, 94376403533823,
+STORE, 94376407724032, 94376407728127,
+STORE, 94376411918336, 94376411922431,
+STORE, 94376416112640, 94376416116735,
+STORE, 94376420306944, 94376420311039,
+STORE, 94376424501248, 94376424505343,
+STORE, 94376428695552, 94376428699647,
+STORE, 94376432889856, 94376432893951,
+STORE, 94376437084160, 94376437088255,
+STORE, 94376441278464, 94376441282559,
+STORE, 94376445472768, 94376445476863,
+STORE, 94376449667072, 94376449671167,
+STORE, 94376453861376, 94376453865471,
+STORE, 94376458055680, 94376458059775,
+STORE, 94376462249984, 94376462254079,
+STORE, 94376466444288, 94376466448383,
+STORE, 94376470638592, 94376470642687,
+STORE, 94376474832896, 94376474836991,
+STORE, 94376479027200, 94376479031295,
+STORE, 94376483221504, 94376483225599,
+STORE, 94376487415808, 94376487419903,
+STORE, 94376491610112, 94376491614207,
+STORE, 94376495804416, 94376495808511,
+STORE, 94376499998720, 94376500002815,
+STORE, 94376504193024, 94376504197119,
+STORE, 94376508387328, 94376508391423,
+STORE, 94376512581632, 94376512585727,
+STORE, 94376516775936, 94376516780031,
+STORE, 94376520970240, 94376520974335,
+STORE, 94376525164544, 94376525168639,
+STORE, 94376529358848, 94376529362943,
+STORE, 94376533553152, 94376533557247,
+STORE, 94376537747456, 94376537751551,
+STORE, 94376541941760, 94376541945855,
+STORE, 94376546136064, 94376546140159,
+STORE, 94376550330368, 94376550334463,
+STORE, 94376554524672, 94376554528767,
+STORE, 94376558718976, 94376558723071,
+STORE, 94376562913280, 94376562917375,
+STORE, 94376567107584, 94376567111679,
+STORE, 94376571301888, 94376571305983,
+STORE, 94376575496192, 94376575500287,
+STORE, 94376579690496, 94376579694591,
+STORE, 94376583884800, 94376583888895,
+STORE, 94376588079104, 94376588083199,
+STORE, 94376592273408, 94376592277503,
+STORE, 94376596467712, 94376596471807,
+STORE, 94376600662016, 94376600666111,
+STORE, 94376604856320, 94376604860415,
+STORE, 94376609050624, 94376609054719,
+STORE, 94376613244928, 94376613249023,
+STORE, 94376617439232, 94376617443327,
+STORE, 94376621633536, 94376621637631,
+STORE, 94376625827840, 94376625831935,
+STORE, 94376630022144, 94376630026239,
+STORE, 94376634216448, 94376634220543,
+STORE, 94376638410752, 94376638414847,
+STORE, 94376642605056, 94376642609151,
+STORE, 94376646799360, 94376646803455,
+STORE, 94376650993664, 94376650997759,
+STORE, 94376655187968, 94376655192063,
+STORE, 94376659382272, 94376659386367,
+STORE, 94376663576576, 94376663580671,
+STORE, 94376667770880, 94376667774975,
+STORE, 94376671965184, 94376671969279,
+STORE, 94376676159488, 94376676163583,
+STORE, 94376680353792, 94376680357887,
+STORE, 94376684548096, 94376684552191,
+STORE, 94376688742400, 94376688746495,
+STORE, 94376692936704, 94376692940799,
+STORE, 94376697131008, 94376697135103,
+STORE, 94376701325312, 94376701329407,
+STORE, 94376705519616, 94376705523711,
+STORE, 94376709713920, 94376709718015,
+STORE, 94376713908224, 94376713912319,
+STORE, 94376718102528, 94376718106623,
+STORE, 94376722296832, 94376722300927,
+STORE, 94376726491136, 94376726495231,
+STORE, 94376730685440, 94376730689535,
+STORE, 94376734879744, 94376734883839,
+STORE, 94376739074048, 94376739078143,
+STORE, 94376743268352, 94376743272447,
+STORE, 94376747462656, 94376747466751,
+STORE, 94376751656960, 94376751661055,
+STORE, 94376755851264, 94376755855359,
+STORE, 94376760045568, 94376760049663,
+STORE, 94376764239872, 94376764243967,
+STORE, 94376768434176, 94376768438271,
+STORE, 94376772628480, 94376772632575,
+STORE, 94376776822784, 94376776826879,
+STORE, 94376781017088, 94376781021183,
+STORE, 94376785211392, 94376785215487,
+STORE, 94376789405696, 94376789409791,
+STORE, 94376793600000, 94376793604095,
+STORE, 94376797794304, 94376797798399,
+STORE, 94376801988608, 94376801992703,
+STORE, 94376806182912, 94376806187007,
+STORE, 94376810377216, 94376810381311,
+STORE, 94376814571520, 94376814575615,
+STORE, 94376818765824, 94376818769919,
+STORE, 94376822960128, 94376822964223,
+STORE, 94376827154432, 94376827158527,
+STORE, 94376831348736, 94376831352831,
+STORE, 94376835543040, 94376835547135,
+STORE, 94376839737344, 94376839741439,
+STORE, 94376843931648, 94376843935743,
+STORE, 94376848125952, 94376848130047,
+STORE, 94376852320256, 94376852324351,
+STORE, 94376856514560, 94376856518655,
+STORE, 94376860708864, 94376860712959,
+STORE, 94376864903168, 94376864907263,
+STORE, 94376869097472, 94376869101567,
+STORE, 94376873291776, 94376873295871,
+STORE, 94376877486080, 94376877490175,
+STORE, 94376881680384, 94376881684479,
+STORE, 94376885874688, 94376885878783,
+STORE, 94376890068992, 94376890073087,
+STORE, 94376894263296, 94376894267391,
+STORE, 94376898457600, 94376898461695,
+STORE, 94376902651904, 94376902655999,
+STORE, 94376906846208, 94376906850303,
+STORE, 94376911040512, 94376911044607,
+STORE, 94376915234816, 94376915238911,
+STORE, 94376919429120, 94376919433215,
+STORE, 94376923623424, 94376923627519,
+STORE, 94376927817728, 94376927821823,
+STORE, 94376932012032, 94376932016127,
+STORE, 94376936206336, 94376936210431,
+STORE, 94376940400640, 94376940404735,
+STORE, 94376944594944, 94376944599039,
+STORE, 94376948789248, 94376948793343,
+STORE, 94376952983552, 94376952987647,
+STORE, 94376957177856, 94376957181951,
+STORE, 94376961372160, 94376961376255,
+STORE, 94376965566464, 94376965570559,
+STORE, 94376969760768, 94376969764863,
+STORE, 94376973955072, 94376973959167,
+STORE, 94376978149376, 94376978153471,
+STORE, 94376982343680, 94376982347775,
+STORE, 94376986537984, 94376986542079,
+STORE, 94376990732288, 94376990736383,
+STORE, 94376994926592, 94376994930687,
+STORE, 94376999120896, 94376999124991,
+STORE, 94377003315200, 94377003319295,
+STORE, 94377007509504, 94377007513599,
+STORE, 94377011703808, 94377011707903,
+STORE, 94377015898112, 94377015902207,
+STORE, 94377020092416, 94377020096511,
+STORE, 94377024286720, 94377024290815,
+STORE, 94377028481024, 94377028485119,
+STORE, 94377032675328, 94377032679423,
+STORE, 94377036869632, 94377036873727,
+STORE, 94377041063936, 94377041068031,
+STORE, 94377045258240, 94377045262335,
+STORE, 94377049452544, 94377049456639,
+STORE, 94377053646848, 94377053650943,
+STORE, 94377057841152, 94377057845247,
+STORE, 94377062035456, 94377062039551,
+STORE, 94377066229760, 94377066233855,
+STORE, 94377070424064, 94377070428159,
+STORE, 94377074618368, 94377074622463,
+STORE, 94377078812672, 94377078816767,
+STORE, 94377083006976, 94377083011071,
+STORE, 94377087201280, 94377087205375,
+STORE, 94377091395584, 94377091399679,
+STORE, 94377095589888, 94377095593983,
+STORE, 94377099784192, 94377099788287,
+STORE, 94377103978496, 94377103982591,
+STORE, 94377108172800, 94377108176895,
+STORE, 94377112367104, 94377112371199,
+STORE, 94377116561408, 94377116565503,
+STORE, 94377120755712, 94377120759807,
+STORE, 94377124950016, 94377124954111,
+STORE, 94377129144320, 94377129148415,
+STORE, 94377133338624, 94377133342719,
+STORE, 94377137532928, 94377137537023,
+STORE, 94377141727232, 94377141731327,
+STORE, 94377145921536, 94377145925631,
+STORE, 94377150115840, 94377150119935,
+STORE, 94377154310144, 94377154314239,
+STORE, 94377158504448, 94377158508543,
+STORE, 94377162698752, 94377162702847,
+STORE, 94377166893056, 94377166897151,
+STORE, 94377171087360, 94377171091455,
+STORE, 94377175281664, 94377175285759,
+STORE, 94377179475968, 94377179480063,
+STORE, 94377183670272, 94377183674367,
+STORE, 94377187864576, 94377187868671,
+STORE, 94377192058880, 94377192062975,
+STORE, 94377196253184, 94377196257279,
+STORE, 94377200447488, 94377200451583,
+STORE, 94377204641792, 94377204645887,
+SNULL, 94376135094271, 94376135098367,
+STORE, 94376135090176, 94376135094271,
+STORE, 94376135094272, 94376135098367,
+SNULL, 94376135094272, 94377208836095,
+ };
+ unsigned long set42[] = {
+STORE, 314572800, 1388314623,
+STORE, 1462157312, 1462169599,
+STORE, 1462169600, 1462185983,
+STORE, 1462185984, 1462190079,
+STORE, 1462190080, 1462194175,
+STORE, 1462194176, 1462198271,
+STORE, 1879986176, 1881800703,
+STORE, 1881800704, 1882034175,
+STORE, 1882034176, 1882193919,
+STORE, 1882193920, 1882406911,
+STORE, 1882406912, 1882451967,
+STORE, 1882451968, 1882996735,
+STORE, 1882996736, 1885892607,
+STORE, 1885892608, 1885896703,
+STORE, 1885896704, 1885904895,
+STORE, 1885904896, 1885908991,
+STORE, 1885908992, 1885913087,
+STORE, 1885913088, 1885966335,
+STORE, 1885966336, 1886232575,
+STORE, 1886232576, 1886236671,
+STORE, 1886236672, 1886240767,
+STORE, 1886240768, 1886244863,
+STORE, 1886244864, 1886248959,
+STORE, 1886248960, 1886294015,
+STORE, 1886294016, 1886494719,
+STORE, 1886494720, 1886498815,
+STORE, 1886498816, 1886502911,
+STORE, 1886502912, 1886507007,
+STORE, 1886507008, 1886511103,
+STORE, 1886511104, 1886556159,
+STORE, 1886556160, 1886629887,
+STORE, 1886629888, 1886633983,
+STORE, 1886633984, 1886638079,
+STORE, 1886638080, 1886642175,
+STORE, 1886642176, 1886646271,
+STORE, 1886646272, 1886666751,
+STORE, 1886666752, 1886670847,
+STORE, 1886670848, 1886674943,
+STORE, 1886674944, 1886679039,
+STORE, 1886679040, 1895419903,
+STORE, 1895419904, 1895550975,
+STORE, 1895550976, 1896148991,
+STORE, 1896148992, 1897189375,
+STORE, 1897189376, 1897701375,
+STORE, 1897701376, 1897803775,
+STORE, 1897803776, 1897816063,
+STORE, 1897816064, 1899913215,
+STORE, 1899913216, 1909379071,
+STORE, 1909379072, 1909387263,
+STORE, 1909387264, 1909391359,
+STORE, 1909391360, 1909432319,
+STORE, 1909432320, 1909436415,
+STORE, 1909436416, 1909440511,
+STORE, 1909440512, 1909460991,
+STORE, 1909460992, 1909547007,
+STORE, 1909547008, 1909551103,
+STORE, 1909551104, 1909555199,
+STORE, 1909555200, 1909559295,
+STORE, 1909559296, 1909563391,
+STORE, 1909563392, 1909739519,
+STORE, 1909739520, 1910566911,
+STORE, 1910566912, 1910571007,
+STORE, 1910571008, 1910575103,
+STORE, 1910575104, 1910579199,
+STORE, 1910579200, 1910583295,
+STORE, 1910583296, 1910587391,
+STORE, 1910587392, 1910620159,
+STORE, 1910620160, 1910624255,
+STORE, 1910624256, 1910628351,
+STORE, 1910628352, 1910632447,
+STORE, 1910632448, 1910652927,
+STORE, 1910652928, 1910657023,
+STORE, 1910657024, 1910661119,
+STORE, 1910661120, 1910665215,
+STORE, 1910665216, 1910669311,
+STORE, 1910669312, 1910677503,
+STORE, 1910677504, 1910681599,
+STORE, 1910681600, 1910685695,
+STORE, 1910685696, 1910689791,
+STORE, 1910689792, 1910697983,
+STORE, 1910697984, 1910702079,
+STORE, 1910702080, 1910706175,
+STORE, 1910706176, 1910710271,
+STORE, 1910710272, 1914093567,
+STORE, 1914093568, 1914097663,
+STORE, 1914097664, 1969434623,
+STORE, 1969434624, 1977819135,
+STORE, 3290435584, 3426750463,
+STORE, 3426750464, 3426754559,
+STORE, 3426754560, 3426762751,
+STORE, 3426762752, 3426766847,
+STORE, 3426766848, 3426770943,
+STORE, 3427037184, 3427061759,
+STORE, 3427061760, 3427135487,
+STORE, 3427135488, 3427143679,
+STORE, 3427143680, 3427147775,
+STORE, 3427147776, 3427209215,
+STORE, 3427319808, 3432116223,
+STORE, 3432116224, 3450130431,
+STORE, 3450130432, 3451027455,
+STORE, 3451027456, 3451031551,
+STORE, 3451031552, 3451461631,
+STORE, 3451736064, 3456688127,
+STORE, 3456688128, 3475222527,
+STORE, 3475222528, 3476119551,
+STORE, 3476119552, 3476127743,
+STORE, 3476127744, 3476553727,
+STORE, 3476631552, 3477315583,
+STORE, 3477315584, 3479949311,
+STORE, 3479949312, 3480002559,
+STORE, 3480002560, 3480006655,
+STORE, 3480006656, 3480432639,
+STORE, 3480539136, 3480543231,
+STORE, 3480543232, 3480547327,
+STORE, 3480547328, 3480555519,
+STORE, 3480854528, 3480903679,
+STORE, 3480903680, 3480969215,
+STORE, 3480969216, 3480977407,
+STORE, 3480977408, 3480981503,
+STORE, 3481030656, 3481092095,
+STORE, 3481092096, 3481235455,
+STORE, 3481235456, 3481243647,
+STORE, 3481243648, 3481247743,
+STORE, 3481436160, 3481444351,
+STORE, 3481444352, 3481456639,
+STORE, 3481456640, 3481460735,
+STORE, 3481460736, 3481464831,
+STORE, 3481587712, 3481645055,
+STORE, 3481645056, 3481772031,
+STORE, 3481772032, 3481776127,
+STORE, 3481776128, 3481780223,
+STORE, 3481874432, 3481935871,
+STORE, 3481935872, 3482030079,
+STORE, 3482030080, 3482038271,
+STORE, 3482038272, 3482042367,
+STORE, 3482198016, 3482230783,
+STORE, 3482230784, 3482271743,
+STORE, 3482271744, 3482279935,
+STORE, 3482279936, 3482284031,
+STORE, 3482562560, 3482566655,
+STORE, 3482566656, 3482570751,
+STORE, 3482570752, 3482574847,
+STORE, 3482636288, 3482689535,
+STORE, 3482689536, 3482746879,
+STORE, 3482746880, 3482755071,
+STORE, 3482755072, 3482759167,
+STORE, 3482972160, 3483062271,
+STORE, 3483062272, 3483242495,
+STORE, 3483242496, 3483246591,
+STORE, 3483246592, 3483250687,
+STORE, 3483398144, 3483688959,
+STORE, 3483688960, 3484114943,
+STORE, 3484114944, 3484131327,
+STORE, 3484131328, 3484135423,
+STORE, 3484135424, 3484143615,
+STORE, 3484184576, 3484475391,
+STORE, 3484475392, 3485028351,
+STORE, 3485028352, 3485057023,
+STORE, 3485057024, 3485061119,
+STORE, 3485360128, 3485364223,
+STORE, 3485364224, 3485368319,
+STORE, 3485368320, 3485372415,
+STORE, 3485589504, 3485593599,
+STORE, 3485593600, 3485597695,
+STORE, 3485597696, 3485601791,
+STORE, 3485913088, 3485937663,
+STORE, 3485937664, 3485974527,
+STORE, 3485974528, 3485982719,
+STORE, 3485982720, 3485986815,
+STORE, 3486052352, 3486056447,
+STORE, 3486056448, 3486064639,
+STORE, 3486064640, 3486068735,
+STORE, 3486068736, 3486072831,
+STORE, 3486294016, 3486302207,
+STORE, 3486302208, 3486306303,
+STORE, 3486306304, 3486310399,
+STORE, 3486310400, 3486314495,
+STORE, 3486670848, 3486679039,
+STORE, 3486679040, 3486683135,
+STORE, 3486683136, 3486687231,
+STORE, 3486687232, 3486691327,
+STORE, 3486863360, 3486871551,
+STORE, 3486871552, 3486875647,
+STORE, 3486875648, 3486879743,
+STORE, 3486879744, 3486883839,
+STORE, 3487584256, 3522543615,
+STORE, 3522543616, 3523321855,
+STORE, 3523321856, 3523342335,
+STORE, 3523342336, 3523387391,
+STORE, 3523387392, 3523391487,
+STORE, 3523391488, 3523395583,
+STORE, 3523477504, 3523686399,
+STORE, 3523686400, 3523981311,
+STORE, 3523981312, 3523997695,
+STORE, 3523997696, 3524001791,
+STORE, 3524177920, 3525013503,
+STORE, 3525013504, 3526582271,
+STORE, 3526582272, 3526606847,
+STORE, 3526606848, 3526610943,
+STORE, 3526610944, 3526615039,
+STORE, 3526672384, 3526746111,
+STORE, 3526746112, 3526860799,
+STORE, 3526860800, 3526868991,
+STORE, 3526868992, 3526873087,
+STORE, 3527000064, 3527475199,
+STORE, 3527475200, 3527479295,
+STORE, 3527479296, 3527573503,
+STORE, 3527573504, 3527581695,
+STORE, 3527581696, 3527585791,
+STORE, 3527585792, 3527606271,
+STORE, 3527909376, 3527913471,
+STORE, 3527913472, 3527917567,
+STORE, 3527917568, 3527921663,
+STORE, 3527950336, 3528011775,
+STORE, 3528011776, 3528093695,
+STORE, 3528093696, 3528101887,
+STORE, 3528101888, 3528105983,
+STORE, 3528228864, 3528241151,
+STORE, 3528241152, 3528261631,
+STORE, 3528261632, 3528265727,
+STORE, 3528273920, 3528593407,
+STORE, 3528593408, 3528609791,
+STORE, 3528609792, 3528638463,
+STORE, 3528638464, 3528642559,
+STORE, 3528642560, 3528646655,
+STORE, 3528880128, 3528912895,
+STORE, 3528912896, 3528962047,
+STORE, 3528962048, 3528966143,
+STORE, 3528966144, 3528970239,
+STORE, 3528982528, 3530293247,
+STORE, 3530366976, 3530825727,
+STORE, 3530825728, 3531317247,
+STORE, 3531317248, 3541041151,
+STORE, 3541041152, 3541303295,
+STORE, 3541430272, 3566206975,
+STORE, 3566206976, 3566993407,
+STORE, 3567239168, 3587571711,
+STORE, 3587571712, 3588284415,
+STORE, 3588284416, 3588661247,
+STORE, 3588661248, 3589066751,
+STORE, 3589066752, 3589574655,
+STORE, 3589574656, 3590078463,
+STORE, 3590078464, 3590373375,
+STORE, 3590373376, 3590668287,
+STORE, 3590668288, 3590963199,
+STORE, 3590963200, 3591294975,
+STORE, 3591294976, 3591602175,
+STORE, 3591602176, 3591933951,
+STORE, 3591933952, 3592241151,
+STORE, 3592241152, 3592572927,
+STORE, 3592572928, 3592876031,
+STORE, 3592876032, 3593211903,
+STORE, 3593211904, 3593547775,
+STORE, 3593547776, 3593650175,
+STORE, 3593650176, 3593928703,
+STORE, 3593928704, 3593936895,
+STORE, 3593936896, 3593940991,
+STORE, 3594006528, 3594301439,
+STORE, 3594301440, 3594739711,
+STORE, 3594739712, 3594756095,
+STORE, 3594756096, 3594760191,
+STORE, 3594760192, 3594768383,
+STORE, 3594952704, 3595051007,
+STORE, 3595051008, 3595223039,
+STORE, 3595223040, 3595227135,
+STORE, 3595227136, 3595235327,
+STORE, 3595431936, 3595775999,
+STORE, 3595776000, 3596701695,
+STORE, 3596701696, 3596742655,
+STORE, 3596742656, 3596746751,
+STORE, 3596746752, 3596750847,
+STORE, 3596767232, 3597070335,
+STORE, 3597070336, 3597402111,
+STORE, 3597402112, 3598188543,
+STORE, 3598262272, 3623428095,
+STORE, 3623428096, 3623432191,
+STORE, 3623432192, 3623436287,
+STORE, 3623436288, 3623440383,
+STORE, 3623616512, 3623878655,
+STORE, 3624169472, 3624300543,
+STORE, 3627524096, 3628523519,
+STORE, 3628523520, 3629522943,
+STORE, 3696631808, 3730186239,
+STORE, 3730186240, 3763740671,
+STORE, 3763740672, 3764027391,
+STORE, 3764027392, 3765133311,
+STORE, 3765133312, 3765145599,
+STORE, 3765145600, 3765149695,
+STORE, 3765178368, 3766022143,
+STORE, 3766022144, 3768791039,
+STORE, 3768791040, 3768840191,
+STORE, 3768840192, 3768844287,
+STORE, 3768897536, 3768913919,
+STORE, 3768913920, 3768934399,
+STORE, 3768934400, 3768938495,
+STORE, 3769016320, 3769147391,
+STORE, 3769147392, 3769233407,
+STORE, 3769233408, 3769356287,
+STORE, 3769356288, 3769360383,
+STORE, 3769360384, 3769368575,
+STORE, 3769376768, 3794542591,
+STORE, 3794542592, 3794599935,
+STORE, 3794599936, 3794731007,
+STORE, 3794731008, 3794735103,
+STORE, 3794735104, 3794743295,
+STORE, 3794849792, 3794980863,
+STORE, 3794980864, 3794984959,
+STORE, 3794984960, 3794989055,
+STORE, 3794989056, 3794993151,
+STORE, 3794993152, 3794997247,
+STORE, 3795103744, 3795128319,
+STORE, 3795128320, 3795165183,
+STORE, 3795165184, 3795169279,
+STORE, 3795169280, 3795173375,
+STORE, 3795210240, 3795357695,
+STORE, 3795357696, 3795365887,
+STORE, 3795365888, 3795374079,
+STORE, 3795374080, 3795378175,
+STORE, 3795378176, 3795382271,
+STORE, 3795406848, 3795738623,
+STORE, 3795738624, 3795742719,
+STORE, 3795742720, 3795755007,
+STORE, 3795755008, 3795759103,
+STORE, 3795763200, 3795894271,
+STORE, 3795894272, 3796041727,
+STORE, 3796041728, 3796054015,
+STORE, 3796054016, 3796066303,
+STORE, 3796066304, 3796070399,
+STORE, 3796176896, 3796205567,
+STORE, 3796205568, 3796250623,
+STORE, 3796250624, 3796254719,
+STORE, 3796254720, 3796258815,
+STORE, 3796262912, 3796393983,
+STORE, 3796393984, 3796516863,
+STORE, 3796516864, 3796873215,
+STORE, 3796873216, 3796885503,
+STORE, 3796885504, 3796889599,
+STORE, 3796963328, 3796967423,
+STORE, 3796967424, 3796975615,
+STORE, 3796975616, 3796979711,
+STORE, 3797000192, 3797307391,
+STORE, 3797307392, 3797311487,
+STORE, 3797311488, 3797315583,
+STORE, 3797315584, 3797323775,
+STORE, 3797327872, 3797450751,
+STORE, 3797450752, 3797458943,
+STORE, 3797458944, 3797471231,
+STORE, 3797471232, 3797475327,
+STORE, 3797577728, 3797700607,
+STORE, 3797700608, 3797721087,
+STORE, 3797721088, 3797733375,
+STORE, 3797733376, 3797741567,
+STORE, 3797741568, 3797864447,
+STORE, 3797864448, 3797995519,
+STORE, 3797995520, 3798048767,
+STORE, 3798048768, 3798179839,
+STORE, 3798179840, 3798188031,
+STORE, 3798188032, 3798192127,
+STORE, 3798290432, 3798302719,
+STORE, 3798302720, 3798323199,
+STORE, 3798323200, 3798327295,
+STORE, 3798327296, 3798331391,
+STORE, 3798429696, 3798433791,
+STORE, 3798433792, 3798552575,
+STORE, 3798552576, 3798556671,
+STORE, 3798556672, 3798568959,
+STORE, 3798568960, 3798573055,
+STORE, 3798573056, 3798581247,
+STORE, 3798618112, 3798749183,
+STORE, 3798749184, 3798855679,
+STORE, 3798855680, 3798966271,
+STORE, 3798966272, 3798982655,
+STORE, 3798982656, 3798986751,
+STORE, 3799101440, 3799171071,
+STORE, 3799171072, 3799240703,
+STORE, 3799240704, 3799248895,
+STORE, 3799248896, 3799252991,
+STORE, 3799326720, 3799650303,
+STORE, 3799650304, 3800629247,
+STORE, 3800629248, 3800641535,
+STORE, 3800641536, 3800645631,
+STORE, 3800645632, 3800649727,
+STORE, 3800649728, 3800903679,
+STORE, 3800903680, 3800936447,
+STORE, 3800936448, 3800969215,
+STORE, 3800969216, 3800981503,
+STORE, 3800981504, 3800985599,
+STORE, 3801001984, 3801133055,
+STORE, 3801133056, 3801202687,
+STORE, 3801202688, 3801591807,
+STORE, 3801591808, 3801599999,
+STORE, 3801600000, 3801604095,
+STORE, 3801604096, 3801608191,
+STORE, 3801608192, 3801739263,
+STORE, 3801739264, 3801755647,
+STORE, 3801755648, 3801796607,
+STORE, 3801796608, 3801804799,
+STORE, 3801804800, 3801808895,
+STORE, 3801878528, 3801944063,
+STORE, 3801944064, 3802116095,
+STORE, 3802116096, 3802124287,
+STORE, 3802124288, 3802128383,
+STORE, 3802136576, 3803447295,
+STORE, 3803492352, 3803553791,
+STORE, 3803553792, 3804233727,
+STORE, 3804233728, 3806068735,
+STORE, 3806121984, 3806253055,
+STORE, 3806253056, 3806674943,
+STORE, 3806674944, 3807117311,
+STORE, 3807117312, 3807379455,
+STORE, 3807379456, 3807432703,
+STORE, 3807432704, 3807563775,
+STORE, 3807563776, 3809202175,
+STORE, 3809202176, 3810250751,
+STORE, 3810250752, 3827027967,
+STORE, 3827027968, 3829125119,
+STORE, 3829125120, 3837513727,
+STORE, 3837513728, 3839610879,
+STORE, 3839610880, 3847999487,
+STORE, 3847999488, 3856392191,
+STORE, 3856392192, 3864784895,
+STORE, 3864784896, 3868983295,
+STORE, 3868983296, 3885760511,
+STORE, 3885760512, 3886809087,
+STORE, 3886809088, 3887857663,
+STORE, 3887857664, 3888119807,
+STORE, 3888144384, 3888148479,
+STORE, 3888148480, 3888218111,
+STORE, 3888218112, 3888222207,
+STORE, 3888222208, 3888353279,
+STORE, 3888353280, 3889172479,
+STORE, 3889172480, 3892314111,
+STORE, 3892314112, 3892576255,
+STORE, 3892588544, 3892637695,
+STORE, 3892637696, 3892686847,
+STORE, 3892686848, 3892744191,
+STORE, 3892748288, 3892785151,
+STORE, 3892785152, 3895459839,
+STORE, 3895459840, 3895721983,
+STORE, 3895738368, 3895885823,
+STORE, 3895885824, 3897081855,
+STORE, 3897081856, 3906482175,
+STORE, 3906482176, 3916144639,
+STORE, 3916144640, 3925766143,
+STORE, 3925766144, 3926974463,
+STORE, 3926974464, 3928367103,
+STORE, 3928367104, 3928911871,
+STORE, 3928911872, 3933995007,
+STORE, 3933995008, 3935830015,
+STORE, 3935830016, 3935846399,
+STORE, 3935879168, 3936010239,
+STORE, 3936010240, 3936026623,
+STORE, 3936026624, 3936034815,
+STORE, 3936034816, 3936051199,
+STORE, 3936051200, 3936055295,
+STORE, 3936071680, 3936137215,
+STORE, 3936137216, 3936202751,
+STORE, 3936202752, 3936219135,
+STORE, 3936235520, 3936251903,
+STORE, 3936268288, 3936276479,
+STORE, 3936276480, 3936284671,
+STORE, 3936284672, 3936288767,
+STORE, 3936288768, 3936292863,
+STORE, 3936296960, 3936354303,
+STORE, 3936354304, 3936616447,
+STORE, 3936628736, 3936669695,
+STORE, 3936669696, 3936747519,
+STORE, 3936747520, 3936870399,
+STORE, 3936870400, 3936874495,
+STORE, 3936874496, 3936878591,
+STORE, 3936882688, 3936903167,
+STORE, 3936911360, 3936948223,
+STORE, 3936948224, 3936964607,
+STORE, 3936964608, 3937103871,
+STORE, 3937103872, 3937107967,
+STORE, 3937132544, 3937161215,
+STORE, 3937189888, 3937255423,
+STORE, 3937255424, 3938512895,
+STORE, 3938512896, 3945435135,
+STORE, 3945435136, 3945476095,
+STORE, 3945476096, 3945484287,
+STORE, 3945484288, 3945496575,
+STORE, 3945500672, 3945541631,
+STORE, 3945558016, 3945566207,
+STORE, 3945566208, 3945594879,
+STORE, 3945594880, 3945598975,
+STORE, 3945598976, 3945603071,
+STORE, 3945611264, 3945742335,
+STORE, 3945742336, 3945844735,
+STORE, 3945844736, 3945848831,
+STORE, 3945848832, 3945861119,
+STORE, 3945861120, 3945865215,
+STORE, 3945869312, 3945897983,
+STORE, 3945897984, 3946303487,
+STORE, 3946303488, 3946397695,
+STORE, 3946397696, 3946569727,
+STORE, 3946569728, 3946573823,
+STORE, 3946573824, 3946594303,
+STORE, 3946594304, 3946663935,
+STORE, 3946663936, 3946708991,
+STORE, 3946708992, 3946823679,
+STORE, 3946823680, 3946827775,
+STORE, 3946827776, 3946831871,
+STORE, 3946831872, 3946860543,
+STORE, 3946893312, 3946897407,
+STORE, 3946897408, 3946905599,
+STORE, 3946905600, 3946909695,
+STORE, 3946909696, 3946913791,
+STORE, 3946913792, 3946930175,
+STORE, 3946930176, 3946967039,
+STORE, 3946967040, 3947102207,
+STORE, 3947102208, 3948412927,
+STORE, 3948441600, 3948556287,
+STORE, 3948556288, 3948576767,
+STORE, 3948576768, 3948597247,
+STORE, 3948597248, 3948605439,
+STORE, 3948605440, 3948609535,
+STORE, 3948609536, 3948654591,
+STORE, 3948654592, 3948781567,
+STORE, 3948781568, 3948822527,
+STORE, 3948822528, 3948904447,
+STORE, 3948904448, 3948908543,
+STORE, 3948908544, 3948912639,
+STORE, 3948945408, 3949043711,
+STORE, 3949043712, 3949174783,
+STORE, 3949174784, 3949191167,
+STORE, 3949191168, 3949195263,
+STORE, 3949207552, 3949252607,
+STORE, 3949252608, 3949256703,
+STORE, 3949256704, 3949363199,
+STORE, 3949363200, 3949367295,
+STORE, 3949367296, 3949379583,
+STORE, 3949379584, 3949383679,
+STORE, 3949383680, 3949400063,
+STORE, 3949400064, 3949404159,
+STORE, 3949416448, 3949481983,
+STORE, 3949481984, 3949486079,
+STORE, 3949486080, 3949592575,
+STORE, 3949592576, 3949596671,
+STORE, 3949596672, 3949621247,
+STORE, 3949621248, 3949662207,
+STORE, 3949662208, 3949666303,
+STORE, 3949694976, 3949727743,
+STORE, 3949727744, 3949731839,
+STORE, 3949731840, 3949838335,
+STORE, 3949838336, 3949842431,
+STORE, 3949842432, 3949846527,
+STORE, 3949846528, 3949854719,
+STORE, 3949854720, 3949858815,
+STORE, 3949858816, 3949862911,
+STORE, 3949867008, 3949891583,
+STORE, 3949891584, 3949928447,
+STORE, 3949928448, 3949993983,
+STORE, 3949993984, 3950043135,
+STORE, 3950043136, 3950059519,
+STORE, 3950059520, 3950096383,
+STORE, 3950096384, 3950100479,
+STORE, 3950100480, 3950104575,
+STORE, 3950104576, 3950157823,
+STORE, 3950157824, 3950292991,
+STORE, 3950292992, 3950346239,
+STORE, 3950346240, 3950477311,
+STORE, 3950477312, 3950485503,
+STORE, 3950485504, 3950489599,
+STORE, 3950493696, 3950510079,
+STORE, 3950510080, 3950661631,
+STORE, 3950661632, 3951005695,
+STORE, 3951005696, 3951026175,
+STORE, 3951026176, 3951030271,
+STORE, 3951030272, 3951054847,
+STORE, 3951054848, 3951116287,
+STORE, 3951116288, 3951144959,
+STORE, 3951144960, 3951149055,
+STORE, 3951149056, 3951194111,
+STORE, 3951194112, 3951202303,
+STORE, 3951202304, 3951206399,
+STORE, 3951210496, 3951226879,
+STORE, 3951226880, 3951329279,
+STORE, 3951329280, 3951366143,
+STORE, 3951366144, 3951411199,
+STORE, 3951411200, 3951415295,
+STORE, 3951415296, 3951419391,
+STORE, 3951419392, 3951452159,
+STORE, 3951452160, 3951566847,
+STORE, 3951566848, 3951812607,
+STORE, 3951812608, 3952173055,
+STORE, 3952173056, 3952214015,
+STORE, 3952214016, 3952218111,
+STORE, 3952222208, 3952250879,
+STORE, 3952250880, 3952369663,
+STORE, 3952369664, 3952488447,
+STORE, 3952488448, 3952627711,
+STORE, 3952627712, 3952635903,
+STORE, 3952635904, 3952639999,
+STORE, 3952652288, 3952668671,
+STORE, 3952668672, 3953000447,
+STORE, 3953000448, 3953004543,
+STORE, 3953004544, 3953008639,
+STORE, 3953008640, 3953012735,
+STORE, 3953012736, 3953037311,
+STORE, 3953037312, 3953151999,
+STORE, 3953152000, 3953291263,
+STORE, 3953291264, 3953324031,
+STORE, 3953324032, 3953364991,
+STORE, 3953364992, 3953373183,
+STORE, 3953373184, 3953377279,
+STORE, 3953381376, 3953410047,
+STORE, 3953410048, 3953491967,
+STORE, 3953491968, 3953643519,
+STORE, 3953643520, 3953651711,
+STORE, 3953651712, 3953655807,
+STORE, 3953659904, 3953766399,
+STORE, 3953766400, 3953774591,
+STORE, 3953774592, 3953786879,
+STORE, 3953786880, 3953790975,
+STORE, 3953790976, 3953823743,
+STORE, 3953823744, 3953963007,
+STORE, 3953963008, 3954024447,
+STORE, 3954024448, 3954118655,
+STORE, 3954118656, 3954122751,
+STORE, 3954122752, 3954126847,
+STORE, 3954130944, 3954184191,
+STORE, 3954184192, 3954294783,
+STORE, 3954294784, 3954323455,
+STORE, 3954323456, 3954393087,
+STORE, 3954393088, 3954397183,
+STORE, 3954397184, 3954401279,
+STORE, 3954401280, 3954405375,
+STORE, 3954409472, 3954528255,
+STORE, 3954528256, 3954737151,
+STORE, 3954737152, 3955052543,
+STORE, 3955052544, 3955060735,
+STORE, 3955060736, 3955064831,
+STORE, 3955068928, 3955105791,
+STORE, 3955105792, 3955167231,
+STORE, 3955167232, 3955277823,
+STORE, 3955277824, 3955310591,
+STORE, 3955310592, 3955351551,
+STORE, 3955351552, 3955359743,
+STORE, 3955359744, 3955363839,
+STORE, 3955363840, 3955392511,
+STORE, 3955392512, 3955453951,
+STORE, 3955453952, 3955601407,
+STORE, 3955601408, 3955777535,
+STORE, 3955777536, 3955982335,
+STORE, 3955982336, 3956011007,
+STORE, 3956011008, 3956015103,
+STORE, 3956023296, 3956039679,
+STORE, 3956039680, 3956125695,
+STORE, 3956125696, 3956129791,
+STORE, 3956129792, 3956133887,
+STORE, 3956133888, 3956137983,
+STORE, 3956142080, 3956449279,
+STORE, 3956449280, 3956543487,
+STORE, 3956543488, 3956719615,
+STORE, 3956719616, 3956731903,
+STORE, 3956731904, 3956735999,
+STORE, 3956744192, 3956793343,
+STORE, 3956793344, 3956887551,
+STORE, 3956887552, 3956953087,
+STORE, 3956953088, 3957035007,
+STORE, 3957035008, 3957039103,
+STORE, 3957039104, 3957047295,
+STORE, 3957047296, 3957071871,
+STORE, 3957071872, 3957231615,
+STORE, 3957231616, 3957563391,
+STORE, 3957563392, 3957579775,
+STORE, 3957579776, 3957583871,
+STORE, 3957592064, 3957608447,
+STORE, 3957608448, 3957878783,
+STORE, 3957878784, 3958591487,
+STORE, 3958591488, 3958599679,
+STORE, 3958599680, 3958607871,
+STORE, 3958607872, 3958620159,
+STORE, 3958620160, 3958624255,
+STORE, 3958624256, 3963199487,
+STORE, 3963199488, 3963285503,
+STORE, 3963285504, 3963371519,
+STORE, 3963371520, 3963428863,
+STORE, 3963428864, 3963555839,
+STORE, 3963555840, 3963559935,
+STORE, 3963559936, 3963564031,
+STORE, 3963568128, 3963596799,
+STORE, 3963596800, 3963682815,
+STORE, 3963682816, 3963695103,
+STORE, 3963695104, 3963711487,
+STORE, 3963711488, 3963715583,
+STORE, 3963719680, 3963752447,
+STORE, 3963752448, 3963846655,
+STORE, 3963846656, 3963932671,
+STORE, 3963932672, 3964444671,
+STORE, 3964444672, 3964448767,
+STORE, 3964448768, 3965808639,
+STORE, 3965808640, 3965845503,
+STORE, 3965845504, 3965849599,
+STORE, 3965853696, 3965935615,
+STORE, 3965935616, 3966017535,
+STORE, 3966017536, 3966103551,
+STORE, 3966103552, 3966685183,
+STORE, 3966685184, 3967705087,
+STORE, 3967705088, 3967758335,
+STORE, 3967758336, 3967762431,
+STORE, 3967762432, 3967770623,
+STORE, 3967770624, 3967799295,
+STORE, 3967799296, 3967848447,
+STORE, 3967848448, 3967868927,
+STORE, 3967868928, 3967901695,
+STORE, 3967901696, 3967905791,
+STORE, 3967905792, 3967909887,
+STORE, 3967909888, 3967995903,
+STORE, 3967995904, 3968077823,
+STORE, 3968077824, 3968159743,
+STORE, 3968159744, 3968167935,
+STORE, 3968167936, 3968172031,
+STORE, 3968172032, 3968192511,
+STORE, 3968192512, 3968196607,
+STORE, 3968196608, 3968200703,
+STORE, 3968208896, 3968516095,
+STORE, 3968516096, 3968528383,
+STORE, 3968528384, 3968552959,
+STORE, 3968552960, 3968557055,
+STORE, 3968561152, 3968593919,
+STORE, 3968593920, 3968626687,
+STORE, 3968626688, 3971153919,
+STORE, 3971153920, 3973754879,
+STORE, 3973754880, 3973804031,
+STORE, 3973804032, 3973820415,
+STORE, 3973820416, 3973832703,
+STORE, 3973840896, 3973873663,
+STORE, 3973873664, 3973967871,
+STORE, 3973967872, 3973976063,
+STORE, 3973976064, 3973984255,
+STORE, 3973984256, 3973988351,
+STORE, 3973988352, 3973992447,
+STORE, 3973996544, 3974008831,
+STORE, 3974008832, 3974045695,
+STORE, 3974045696, 3974139903,
+STORE, 3974139904, 3974254591,
+STORE, 3974254592, 3974275071,
+STORE, 3974275072, 3974291455,
+STORE, 3974291456, 3974295551,
+STORE, 3974295552, 3974373375,
+STORE, 3974373376, 3974524927,
+STORE, 3974524928, 3974529023,
+STORE, 3974529024, 3974537215,
+STORE, 3974537216, 3974541311,
+STORE, 3974541312, 3974545407,
+STORE, 3974545408, 3974627327,
+STORE, 3974627328, 3974680575,
+STORE, 3974680576, 3974811647,
+STORE, 3974811648, 3974819839,
+STORE, 3974819840, 3974823935,
+STORE, 3974832128, 3974918143,
+STORE, 3974918144, 3974963199,
+STORE, 3974963200, 3975077887,
+STORE, 3975077888, 3975090175,
+STORE, 3975090176, 3975094271,
+STORE, 3975094272, 3975102463,
+STORE, 3975102464, 3975114751,
+STORE, 3975114752, 3975266303,
+STORE, 3975266304, 3975274495,
+STORE, 3975274496, 3975286783,
+STORE, 3975286784, 3975290879,
+STORE, 3975290880, 3975299071,
+STORE, 3975299072, 3975315455,
+STORE, 3975315456, 3975430143,
+STORE, 3975430144, 3975536639,
+STORE, 3975536640, 3975651327,
+STORE, 3975651328, 3975655423,
+STORE, 3975655424, 3975659519,
+STORE, 3975659520, 3975770111,
+STORE, 3975770112, 3975778303,
+STORE, 3975778304, 3975790591,
+STORE, 3975790592, 3975794687,
+STORE, 3975794688, 3975798783,
+STORE, 3975798784, 3975831551,
+STORE, 3975831552, 3975872511,
+STORE, 3975872512, 3975987199,
+STORE, 3975987200, 3976134655,
+STORE, 3976134656, 3977175039,
+STORE, 3977175040, 3977183231,
+STORE, 3977183232, 3977191423,
+STORE, 3977191424, 3977195519,
+STORE, 3977199616, 3977248767,
+STORE, 3977248768, 3977539583,
+STORE, 3977539584, 3977965567,
+STORE, 3977965568, 3977981951,
+STORE, 3977981952, 3977986047,
+STORE, 3977986048, 3977994239,
+STORE, 3977994240, 3978002431,
+STORE, 3978002432, 3978084351,
+STORE, 3978084352, 3978125311,
+STORE, 3978125312, 3978174463,
+STORE, 3978174464, 3978178559,
+STORE, 3978178560, 3978182655,
+STORE, 3978182656, 3978207231,
+STORE, 3978207232, 3978297343,
+STORE, 3978297344, 3978301439,
+STORE, 3978301440, 3978305535,
+STORE, 3978305536, 3978309631,
+STORE, 3978309632, 3978317823,
+STORE, 3978317824, 3978625023,
+STORE, 3978625024, 3978657791,
+STORE, 3978657792, 3978727423,
+STORE, 3978727424, 3978735615,
+STORE, 3978735616, 3978739711,
+STORE, 3978739712, 3978760191,
+STORE, 3978760192, 3978842111,
+STORE, 3978842112, 3978850303,
+STORE, 3978850304, 3978858495,
+STORE, 3978858496, 3978862591,
+STORE, 3978862592, 3978895359,
+STORE, 3978895360, 3979014143,
+STORE, 3979014144, 3979132927,
+STORE, 3979132928, 3979288575,
+STORE, 3979288576, 3979481087,
+STORE, 3979481088, 3979489279,
+STORE, 3979489280, 3979493375,
+STORE, 3979497472, 3979583487,
+STORE, 3979583488, 3979673599,
+STORE, 3979673600, 3979718655,
+STORE, 3979718656, 3979829247,
+STORE, 3979829248, 3979841535,
+STORE, 3979841536, 3979882495,
+STORE, 3979882496, 3979964415,
+STORE, 3979964416, 3980013567,
+STORE, 3980013568, 3980148735,
+STORE, 3980148736, 3980152831,
+STORE, 3980152832, 3980320767,
+STORE, 3980320768, 3980337151,
+STORE, 3980337152, 3980341247,
+STORE, 3980345344, 3980365823,
+STORE, 3980365824, 3980423167,
+STORE, 3980423168, 3980460031,
+STORE, 3980460032, 3980500991,
+STORE, 3980500992, 3980509183,
+STORE, 3980509184, 3980513279,
+STORE, 3980513280, 3980546047,
+STORE, 3980546048, 3980660735,
+STORE, 3980660736, 3980951551,
+STORE, 3980951552, 3981500415,
+STORE, 3981500416, 3981529087,
+STORE, 3981529088, 3981533183,
+STORE, 3981537280, 3981549567,
+STORE, 3981549568, 3981598719,
+STORE, 3981598720, 3981717503,
+STORE, 3981717504, 3982127103,
+STORE, 3982127104, 3982675967,
+STORE, 3982675968, 3982733311,
+STORE, 3982733312, 3982737407,
+STORE, 3982741504, 3982860287,
+STORE, 3982860288, 3982905343,
+STORE, 3982905344, 3982966783,
+STORE, 3982966784, 3982974975,
+STORE, 3982974976, 3982979071,
+STORE, 3982979072, 3983032319,
+STORE, 3983032320, 3983085567,
+STORE, 3983085568, 3983208447,
+STORE, 3983208448, 3983212543,
+STORE, 3983212544, 3983220735,
+STORE, 3983220736, 3983224831,
+STORE, 3983224832, 3983237119,
+STORE, 3983237120, 3983351807,
+STORE, 3983351808, 3983376383,
+STORE, 3983376384, 3983392767,
+STORE, 3983392768, 3983396863,
+STORE, 3983396864, 3983400959,
+STORE, 3983400960, 3983417343,
+STORE, 3983417344, 3983753215,
+STORE, 3983753216, 3983757311,
+STORE, 3983757312, 3983761407,
+STORE, 3983761408, 3983765503,
+STORE, 3983765504, 3983769599,
+STORE, 3983769600, 3983880191,
+STORE, 3983880192, 3983892479,
+STORE, 3983892480, 3983900671,
+STORE, 3983900672, 3983904767,
+STORE, 3983904768, 3983908863,
+STORE, 3983908864, 3983941631,
+STORE, 3983941632, 3983990783,
+STORE, 3983990784, 3984097279,
+STORE, 3984097280, 3984105471,
+STORE, 3984105472, 3984117759,
+STORE, 3984117760, 3984121855,
+STORE, 3984121856, 3984125951,
+STORE, 3984125952, 3984134143,
+STORE, 3984134144, 3984150527,
+STORE, 3984150528, 3984416767,
+STORE, 3984416768, 3984470015,
+STORE, 3984470016, 3984564223,
+STORE, 3984564224, 3984568319,
+STORE, 3984572416, 3984629759,
+STORE, 3984629760, 3984805887,
+STORE, 3984805888, 3985096703,
+STORE, 3985096704, 3985104895,
+STORE, 3985104896, 3985108991,
+STORE, 3985113088, 3986862079,
+STORE, 3986862080, 3993640959,
+STORE, 3993640960, 3993739263,
+STORE, 3993739264, 3993743359,
+STORE, 3993743360, 3993759743,
+STORE, 3993759744, 3993780223,
+STORE, 3993780224, 3993784319,
+STORE, 3993784320, 3993792511,
+STORE, 3993792512, 3993796607,
+STORE, 3993796608, 3993800703,
+STORE, 3993804800, 3994214399,
+STORE, 3994214400, 3994218495,
+STORE, 3994218496, 3994222591,
+STORE, 3994222592, 3994226687,
+STORE, 3994230784, 3994243071,
+STORE, 3994243072, 3994255359,
+STORE, 3994255360, 3994304511,
+STORE, 3994304512, 3994386431,
+STORE, 3994386432, 3994509311,
+STORE, 3994509312, 3994521599,
+STORE, 3994521600, 3994525695,
+STORE, 3994529792, 3994542079,
+STORE, 3994542080, 3994660863,
+STORE, 3994660864, 3994705919,
+STORE, 3994705920, 3994796031,
+STORE, 3994796032, 3994800127,
+STORE, 3994800128, 3994804223,
+STORE, 3994804224, 3994812415,
+STORE, 3994812416, 3994845183,
+STORE, 3994845184, 3994898431,
+STORE, 3994898432, 3994902527,
+STORE, 3994902528, 3994906623,
+STORE, 3994910720, 3994931199,
+STORE, 3994931200, 3995181055,
+STORE, 3995181056, 3995222015,
+STORE, 3995222016, 3995275263,
+STORE, 3995275264, 3995279359,
+STORE, 3995279360, 3995283455,
+STORE, 3995283456, 3995291647,
+STORE, 3995291648, 3995324415,
+STORE, 3995324416, 3995451391,
+STORE, 3995451392, 3995697151,
+STORE, 3995697152, 3996078079,
+STORE, 3996078080, 3996086271,
+STORE, 3996086272, 3996090367,
+STORE, 3996094464, 3996119039,
+STORE, 3996119040, 3996200959,
+STORE, 3996200960, 3996229631,
+STORE, 3996229632, 3996233727,
+STORE, 3996233728, 3996282879,
+STORE, 3996282880, 3996291071,
+STORE, 3996291072, 3996295167,
+STORE, 3996299264, 3996311551,
+STORE, 3996311552, 3996430335,
+STORE, 3996430336, 3996467199,
+STORE, 3996467200, 3996504063,
+STORE, 3996504064, 3996512255,
+STORE, 3996512256, 3996516351,
+STORE, 3996516352, 3996540927,
+STORE, 3996540928, 3996671999,
+STORE, 3996672000, 3996676095,
+STORE, 3996676096, 3996684287,
+STORE, 3996684288, 3996688383,
+STORE, 3996688384, 3996692479,
+STORE, 3996692480, 3996717055,
+STORE, 3996717056, 3997048831,
+STORE, 3997048832, 3997057023,
+STORE, 3997057024, 3997073407,
+STORE, 3997073408, 3997077503,
+STORE, 3997077504, 3997081599,
+STORE, 3997081600, 3997097983,
+STORE, 3997097984, 3997179903,
+STORE, 3997179904, 3997356031,
+STORE, 3997356032, 3997650943,
+STORE, 3997650944, 3997675519,
+STORE, 3997675520, 3997679615,
+STORE, 3997683712, 3997700095,
+STORE, 3997700096, 3997745151,
+STORE, 3997745152, 3997802495,
+STORE, 3997802496, 3997810687,
+STORE, 3997810688, 3997814783,
+STORE, 3997814784, 3998064639,
+STORE, 3998064640, 3998081023,
+STORE, 3998081024, 3998085119,
+STORE, 3998085120, 3998130175,
+STORE, 3998130176, 3998134271,
+STORE, 3998134272, 3998142463,
+STORE, 3998142464, 3998179327,
+STORE, 3998179328, 3998212095,
+STORE, 3998212096, 3998326783,
+STORE, 3998326784, 3998351359,
+STORE, 3998351360, 3998392319,
+STORE, 3998392320, 3998396415,
+STORE, 3998396416, 3998400511,
+STORE, 3998400512, 3998433279,
+STORE, 3998433280, 3998466047,
+STORE, 3998466048, 3998613503,
+STORE, 3998613504, 3998666751,
+STORE, 3998666752, 3998724095,
+STORE, 3998724096, 3998732287,
+STORE, 3998732288, 3998736383,
+STORE, 3998736384, 3998760959,
+STORE, 3998760960, 3998777343,
+STORE, 3998777344, 3998822399,
+STORE, 3998822400, 3998826495,
+STORE, 3998826496, 3998830591,
+STORE, 3998830592, 3998863359,
+STORE, 3998863360, 3998900223,
+STORE, 3998900224, 3999043583,
+STORE, 3999043584, 3999121407,
+STORE, 3999121408, 3999215615,
+STORE, 3999215616, 3999223807,
+STORE, 3999223808, 3999227903,
+STORE, 3999227904, 3999236095,
+STORE, 3999236096, 3999268863,
+STORE, 3999268864, 3999301631,
+STORE, 3999301632, 3999354879,
+STORE, 3999354880, 3999428607,
+STORE, 3999428608, 3999436799,
+STORE, 3999436800, 3999440895,
+STORE, 3999444992, 3999461375,
+STORE, 3999461376, 3999584255,
+STORE, 3999584256, 3999760383,
+STORE, 3999760384, 4000219135,
+STORE, 4000219136, 4000235519,
+STORE, 4000235520, 4000251903,
+STORE, 4000251904, 4000501759,
+STORE, 4000501760, 4000505855,
+STORE, 4000505856, 4000509951,
+STORE, 4000509952, 4000518143,
+STORE, 4000518144, 4000522239,
+STORE, 4000522240, 4000587775,
+STORE, 4000587776, 4000645119,
+STORE, 4000645120, 4000813055,
+STORE, 4000813056, 4000817151,
+STORE, 4000821248, 4000837631,
+STORE, 4000837632, 4000870399,
+STORE, 4000870400, 4000874495,
+STORE, 4000874496, 4000878591,
+STORE, 4000878592, 4000882687,
+STORE, 4000882688, 4000886783,
+STORE, 4000886784, 4000890879,
+STORE, 4000890880, 4000907263,
+STORE, 4000907264, 4001214463,
+STORE, 4001214464, 4001558527,
+STORE, 4001558528, 4002484223,
+STORE, 4002484224, 4002525183,
+STORE, 4002525184, 4002529279,
+STORE, 4002529280, 4002533375,
+STORE, 4002533376, 4002537471,
+STORE, 4002537472, 4002660351,
+STORE, 4002660352, 4002779135,
+STORE, 4002779136, 4002791423,
+STORE, 4002791424, 4002799615,
+STORE, 4002799616, 4002807807,
+STORE, 4002807808, 4002811903,
+STORE, 4002811904, 4002828287,
+STORE, 4002828288, 4002910207,
+STORE, 4002910208, 4003028991,
+STORE, 4003028992, 4003037183,
+STORE, 4003037184, 4003045375,
+STORE, 4003045376, 4003049471,
+STORE, 4003049472, 4003053567,
+STORE, 4003053568, 4003057663,
+STORE, 4003057664, 4003065855,
+STORE, 4003065856, 4003135487,
+STORE, 4003135488, 4003446783,
+STORE, 4003446784, 4003450879,
+STORE, 4003450880, 4003454975,
+STORE, 4003454976, 4003459071,
+STORE, 4003459072, 4003463167,
+STORE, 4003463168, 4003495935,
+STORE, 4003495936, 4003569663,
+STORE, 4003569664, 4003573759,
+STORE, 4003573760, 4003704831,
+STORE, 4003704832, 4003708927,
+STORE, 4003708928, 4003713023,
+STORE, 4003713024, 4003737599,
+STORE, 4003737600, 4003770367,
+STORE, 4003770368, 4003876863,
+STORE, 4003876864, 4003880959,
+STORE, 4003880960, 4003885055,
+STORE, 4003885056, 4003889151,
+STORE, 4003889152, 4003893247,
+STORE, 4003893248, 4003897343,
+STORE, 4003897344, 4003962879,
+STORE, 4003962880, 4004069375,
+STORE, 4004069376, 4004093951,
+STORE, 4004093952, 4004118527,
+STORE, 4004118528, 4004122623,
+STORE, 4004122624, 4004126719,
+STORE, 4004126720, 4004155391,
+STORE, 4004155392, 4004286463,
+STORE, 4004286464, 4004384767,
+STORE, 4004384768, 4004388863,
+STORE, 4004388864, 4004646911,
+STORE, 4004646912, 4004655103,
+STORE, 4004655104, 4004659199,
+STORE, 4004659200, 4004667391,
+STORE, 4004667392, 4004683775,
+STORE, 4004683776, 4004814847,
+STORE, 4004814848, 4004818943,
+STORE, 4004818944, 4004823039,
+STORE, 4004823040, 4004827135,
+STORE, 4004827136, 4004835327,
+STORE, 4004835328, 4004954111,
+STORE, 4004954112, 4005085183,
+STORE, 4005085184, 4005306367,
+STORE, 4005306368, 4005765119,
+STORE, 4005765120, 4005789695,
+STORE, 4005789696, 4005793791,
+STORE, 4005793792, 4005801983,
+STORE, 4005801984, 4005920767,
+STORE, 4005920768, 4005945343,
+STORE, 4005945344, 4005949439,
+STORE, 4005949440, 4005986303,
+STORE, 4005986304, 4005990399,
+STORE, 4005990400, 4005994495,
+STORE, 4005994496, 4006002687,
+STORE, 4006002688, 4006109183,
+STORE, 4006109184, 4006117375,
+STORE, 4006117376, 4006121471,
+STORE, 4006121472, 4006133759,
+STORE, 4006133760, 4006137855,
+STORE, 4006137856, 4006141951,
+STORE, 4006141952, 4006150143,
+STORE, 4006150144, 4006391807,
+STORE, 4006391808, 4006445055,
+STORE, 4006445056, 4006563839,
+STORE, 4006563840, 4006572031,
+STORE, 4006572032, 4006576127,
+STORE, 4006576128, 4006584319,
+STORE, 4006584320, 4006694911,
+STORE, 4006694912, 4006739967,
+STORE, 4006739968, 4006776831,
+STORE, 4006776832, 4006785023,
+STORE, 4006785024, 4006789119,
+STORE, 4006789120, 4006797311,
+STORE, 4006797312, 4006813695,
+STORE, 4006813696, 4006846463,
+STORE, 4006846464, 4006977535,
+STORE, 4006977536, 4007006207,
+STORE, 4007006208, 4007010303,
+STORE, 4007010304, 4007067647,
+STORE, 4007067648, 4007075839,
+STORE, 4007075840, 4007084031,
+STORE, 4007084032, 4007100415,
+STORE, 4007100416, 4007116799,
+STORE, 4007116800, 4007133183,
+STORE, 4007133184, 4007153663,
+STORE, 4007153664, 4007178239,
+STORE, 4007178240, 4007202815,
+STORE, 4007202816, 4007206911,
+STORE, 4007206912, 4007272447,
+STORE, 4007272448, 4007276543,
+STORE, 4007276544, 4007280639,
+STORE, 4007280640, 4007284735,
+STORE, 4007284736, 4007292927,
+STORE, 4007292928, 4007423999,
+STORE, 4007424000, 4007448575,
+STORE, 4007448576, 4007452671,
+STORE, 4007452672, 4007505919,
+STORE, 4007505920, 4007510015,
+STORE, 4007510016, 4007514111,
+STORE, 4007514112, 4007645183,
+STORE, 4007645184, 4007776255,
+STORE, 4007776256, 4007780351,
+STORE, 4007780352, 4007784447,
+STORE, 4007784448, 4007788543,
+STORE, 4007788544, 4007809023,
+STORE, 4007809024, 4007829503,
+STORE, 4007829504, 4007960575,
+STORE, 4007960576, 4008091647,
+STORE, 4008091648, 4008296447,
+STORE, 4008296448, 4008890367,
+STORE, 4008890368, 4008898559,
+STORE, 4008898560, 4008902655,
+STORE, 4008902656, 4008996863,
+STORE, 4008996864, 4009041919,
+STORE, 4009041920, 4009082879,
+STORE, 4009082880, 4009091071,
+STORE, 4009091072, 4009107455,
+STORE, 4009107456, 4009349119,
+STORE, 4009349120, 4009373695,
+STORE, 4009373696, 4009414655,
+STORE, 4009414656, 4009422847,
+STORE, 4009422848, 4009426943,
+STORE, 4009426944, 4009447423,
+STORE, 4009447424, 4009471999,
+STORE, 4009472000, 4009512959,
+STORE, 4009512960, 4009594879,
+STORE, 4009594880, 4009598975,
+STORE, 4009598976, 4009697279,
+STORE, 4009697280, 4009713663,
+STORE, 4009713664, 4009717759,
+STORE, 4009717760, 4009721855,
+STORE, 4009721856, 4009730047,
+STORE, 4009730048, 4009861119,
+STORE, 4009861120, 4009951231,
+STORE, 4009951232, 4010131455,
+STORE, 4010131456, 4010135551,
+STORE, 4010135552, 4010139647,
+STORE, 4010139648, 4010143743,
+STORE, 4010143744, 4010164223,
+STORE, 4010164224, 4010295295,
+STORE, 4010295296, 4010299391,
+STORE, 4010299392, 4010491903,
+STORE, 4010491904, 4010495999,
+STORE, 4010496000, 4010668031,
+STORE, 4010668032, 4011028479,
+STORE, 4011028480, 4011053055,
+STORE, 4011053056, 4011057151,
+STORE, 4011057152, 4011118591,
+STORE, 4011118592, 4011126783,
+STORE, 4011126784, 4011130879,
+STORE, 4011130880, 4011143167,
+STORE, 4011143168, 4011147263,
+STORE, 4011147264, 4011167743,
+STORE, 4011167744, 4011171839,
+STORE, 4011171840, 4011360255,
+STORE, 4011360256, 4011364351,
+STORE, 4011364352, 4011626495,
+STORE, 4011626496, 4012216319,
+STORE, 4012216320, 4012228607,
+STORE, 4012228608, 4012232703,
+STORE, 4012232704, 4012236799,
+STORE, 4012236800, 4012240895,
+STORE, 4012240896, 4012261375,
+STORE, 4012261376, 4012392447,
+STORE, 4012392448, 4012466175,
+STORE, 4012466176, 4012597247,
+STORE, 4012597248, 4012601343,
+STORE, 4012601344, 4012605439,
+STORE, 4012605440, 4012609535,
+STORE, 4012609536, 4012679167,
+STORE, 4012679168, 4013563903,
+STORE, 4013563904, 4015366143,
+STORE, 4015366144, 4015411199,
+STORE, 4015411200, 4015415295,
+STORE, 4015415296, 4015419391,
+STORE, 4015419392, 4015542271,
+STORE, 4015542272, 4015550463,
+STORE, 4015550464, 4015558655,
+STORE, 4015558656, 4015562751,
+STORE, 4015562752, 4015583231,
+STORE, 4015583232, 4015587327,
+STORE, 4015587328, 4015603711,
+STORE, 4015665152, 4015669247,
+STORE, 4015669248, 4015812607,
+STORE, 4015812608, 4015816703,
+STORE, 4015816704, 4016111615,
+STORE, 4016111616, 4016467967,
+STORE, 4016467968, 4016508927,
+STORE, 4016508928, 4016517119,
+STORE, 4016517120, 4016525311,
+STORE, 4016525312, 4016586751,
+STORE, 4016586752, 4016664575,
+STORE, 4016664576, 4016697343,
+STORE, 4016697344, 4016742399,
+STORE, 4016742400, 4016746495,
+STORE, 4016746496, 4016750591,
+STORE, 4016750592, 4016758783,
+STORE, 4016799744, 4016844799,
+STORE, 4016844800, 4016902143,
+STORE, 4016902144, 4016992255,
+STORE, 4016992256, 4017000447,
+STORE, 4017000448, 4017004543,
+STORE, 4017004544, 4017008639,
+STORE, 4017008640, 4017016831,
+STORE, 4017016832, 4017020927,
+STORE, 4017020928, 4017127423,
+STORE, 4017127424, 4017131519,
+STORE, 4017131520, 4017229823,
+STORE, 4017229824, 4017422335,
+STORE, 4017422336, 4017438719,
+STORE, 4017438720, 4017442815,
+STORE, 4017442816, 4017446911,
+STORE, 4017446912, 4017455103,
+STORE, 4017455104, 4017766399,
+STORE, 4017766400, 4017909759,
+STORE, 4017909760, 4018081791,
+STORE, 4018081792, 4018089983,
+STORE, 4018089984, 4018094079,
+STORE, 4018094080, 4018098175,
+STORE, 4018098176, 4018327551,
+STORE, 4018327552, 4018331647,
+STORE, 4018331648, 4018339839,
+STORE, 4018339840, 4018348031,
+STORE, 4018348032, 4018610175,
+STORE, 4018610176, 4018626559,
+STORE, 4018626560, 4018647039,
+STORE, 4018647040, 4018651135,
+STORE, 4018651136, 4018749439,
+STORE, 4018749440, 4018761727,
+STORE, 4018761728, 4018802687,
+STORE, 4018802688, 4018806783,
+STORE, 4018806784, 4018810879,
+STORE, 4018810880, 4018814975,
+STORE, 4018814976, 4018823167,
+STORE, 4018823168, 4018954239,
+STORE, 4018954240, 4019007487,
+STORE, 4019007488, 4019068927,
+STORE, 4019068928, 4019077119,
+STORE, 4019077120, 4019081215,
+STORE, 4019081216, 4019093503,
+STORE, 4019093504, 4019208191,
+STORE, 4019208192, 4019232767,
+STORE, 4019232768, 4019265535,
+STORE, 4019265536, 4019269631,
+STORE, 4019269632, 4019277823,
+STORE, 4019277824, 4019458047,
+STORE, 4019458048, 4019519487,
+STORE, 4019519488, 4019613695,
+STORE, 4019613696, 4019621887,
+STORE, 4019621888, 4019625983,
+STORE, 4019625984, 4019630079,
+STORE, 4019630080, 4019744767,
+STORE, 4019744768, 4019822591,
+STORE, 4019822592, 4019929087,
+STORE, 4019929088, 4019941375,
+STORE, 4019941376, 4019945471,
+STORE, 4019945472, 4019961855,
+STORE, 4019961856, 4019994623,
+STORE, 4019994624, 4019998719,
+STORE, 4019998720, 4020002815,
+STORE, 4020002816, 4020006911,
+STORE, 4020006912, 4020011007,
+STORE, 4020011008, 4020256767,
+STORE, 4020256768, 4020326399,
+STORE, 4020326400, 4020457471,
+STORE, 4020457472, 4020469759,
+STORE, 4020469760, 4020473855,
+STORE, 4020473856, 4020482047,
+STORE, 4020482048, 4020711423,
+STORE, 4020711424, 4020715519,
+STORE, 4020715520, 4020719615,
+STORE, 4020719616, 4020723711,
+STORE, 4020723712, 4020805631,
+STORE, 4020805632, 4021051391,
+STORE, 4021051392, 4021460991,
+STORE, 4021460992, 4021469183,
+STORE, 4021469184, 4021473279,
+STORE, 4021473280, 4021571583,
+STORE, 4021571584, 4021633023,
+STORE, 4021633024, 4021727231,
+STORE, 4021727232, 4021735423,
+STORE, 4021735424, 4021739519,
+STORE, 4021739520, 4021747711,
+STORE, 4021747712, 4021829631,
+STORE, 4021829632, 4021866495,
+STORE, 4021866496, 4021919743,
+STORE, 4021919744, 4021927935,
+STORE, 4021927936, 4021932031,
+STORE, 4021932032, 4021944319,
+STORE, 4021944320, 4022157311,
+STORE, 4022157312, 4022161407,
+STORE, 4022161408, 4022173695,
+STORE, 4022173696, 4022177791,
+STORE, 4022177792, 4022472703,
+STORE, 4022472704, 4022509567,
+STORE, 4022509568, 4022583295,
+STORE, 4022583296, 4022587391,
+STORE, 4022587392, 4022591487,
+STORE, 4022591488, 4022607871,
+STORE, 4022607872, 4022657023,
+STORE, 4022657024, 4022722559,
+STORE, 4022722560, 4022730751,
+STORE, 4022730752, 4022734847,
+STORE, 4022734848, 4022865919,
+STORE, 4022865920, 4022943743,
+STORE, 4022943744, 4023062527,
+STORE, 4023062528, 4023074815,
+STORE, 4023074816, 4023078911,
+STORE, 4023078912, 4023128063,
+STORE, 4023128064, 4023218175,
+STORE, 4023218176, 4023361535,
+STORE, 4023361536, 4023373823,
+STORE, 4023373824, 4023377919,
+STORE, 4023377920, 4023558143,
+STORE, 4023558144, 4023631871,
+STORE, 4023631872, 4023816191,
+STORE, 4023816192, 4023820287,
+STORE, 4023820288, 4023824383,
+STORE, 4023824384, 4023832575,
+STORE, 4023832576, 4024078335,
+STORE, 4024078336, 4024197119,
+STORE, 4024197120, 4024389631,
+STORE, 4024389632, 4024406015,
+STORE, 4024406016, 4024410111,
+STORE, 4024410112, 4024422399,
+STORE, 4024422400, 4024619007,
+STORE, 4024619008, 4024639487,
+STORE, 4024639488, 4024655871,
+STORE, 4024655872, 4024664063,
+STORE, 4024664064, 4024668159,
+STORE, 4024668160, 4024676351,
+STORE, 4024676352, 4024905727,
+STORE, 4024905728, 4024909823,
+STORE, 4024909824, 4024918015,
+STORE, 4024918016, 4024922111,
+STORE, 4024922112, 4024930303,
+STORE, 4024930304, 4025110527,
+STORE, 4025110528, 4025176063,
+STORE, 4025176064, 4025208831,
+STORE, 4025208832, 4025212927,
+STORE, 4025212928, 4025217023,
+STORE, 4025217024, 4025348095,
+STORE, 4025348096, 4025372671,
+STORE, 4025372672, 4025458687,
+STORE, 4025458688, 4025466879,
+STORE, 4025466880, 4025565183,
+STORE, 4025565184, 4025757695,
+STORE, 4025757696, 4026249215,
+STORE, 4026249216, 4026261503,
+STORE, 4026261504, 4026265599,
+STORE, 4026265600, 4026269695,
+STORE, 4026269696, 4026302463,
+STORE, 4026302464, 4026306559,
+STORE, 4026306560, 4026314751,
+STORE, 4026314752, 4026318847,
+STORE, 4026318848, 4026322943,
+STORE, 4026322944, 4026327039,
+STORE, 4026327040, 4026654719,
+STORE, 4026654720, 4026671103,
+STORE, 4026671104, 4026720255,
+STORE, 4026720256, 4026724351,
+STORE, 4026724352, 4026728447,
+STORE, 4026728448, 4026732543,
+STORE, 4026732544, 4026863615,
+STORE, 4026863616, 4027027455,
+STORE, 4027027456, 4027031551,
+STORE, 4027031552, 4027514879,
+STORE, 4027514880, 4027531263,
+STORE, 4027531264, 4027535359,
+STORE, 4027535360, 4027539455,
+STORE, 4027539456, 4027785215,
+STORE, 4027785216, 4027789311,
+STORE, 4027789312, 4027793407,
+STORE, 4027793408, 4027797503,
+STORE, 4027797504, 4027863039,
+STORE, 4027863040, 4027899903,
+STORE, 4027899904, 4027949055,
+STORE, 4027949056, 4027957247,
+STORE, 4027957248, 4027961343,
+STORE, 4027961344, 4027965439,
+STORE, 4027965440, 4028194815,
+STORE, 4028194816, 4028252159,
+STORE, 4028252160, 4028338175,
+STORE, 4028338176, 4028350463,
+STORE, 4028350464, 4028354559,
+STORE, 4028354560, 4028452863,
+STORE, 4028452864, 4028489727,
+STORE, 4028489728, 4028530687,
+STORE, 4028530688, 4028538879,
+STORE, 4028538880, 4028542975,
+STORE, 4028542976, 4028551167,
+STORE, 4028551168, 4028665855,
+STORE, 4028665856, 4029349887,
+STORE, 4029349888, 4030468095,
+STORE, 4030468096, 4030513151,
+STORE, 4030513152, 4030517247,
+STORE, 4030517248, 4030525439,
+STORE, 4030525440, 4030529535,
+STORE, 4030529536, 4030758911,
+STORE, 4030758912, 4030828543,
+STORE, 4030828544, 4030943231,
+STORE, 4030943232, 4030951423,
+STORE, 4030951424, 4030955519,
+STORE, 4030955520, 4030967807,
+STORE, 4030967808, 4031131647,
+STORE, 4031131648, 4031135743,
+STORE, 4031135744, 4031139839,
+STORE, 4031139840, 4031148031,
+STORE, 4031148032, 4031152127,
+STORE, 4031152128, 4031160319,
+STORE, 4031160320, 4031504383,
+STORE, 4031504384, 4031598591,
+STORE, 4031598592, 4031754239,
+STORE, 4031754240, 4031766527,
+STORE, 4031766528, 4031770623,
+STORE, 4031770624, 4031774719,
+STORE, 4031774720, 4031782911,
+STORE, 4031782912, 4031799295,
+STORE, 4031799296, 4031856639,
+STORE, 4031856640, 4031983615,
+STORE, 4031983616, 4031987711,
+STORE, 4031987712, 4031991807,
+STORE, 4031991808, 4032270335,
+STORE, 4032270336, 4032274431,
+STORE, 4032274432, 4032282623,
+STORE, 4032282624, 4032286719,
+STORE, 4032286720, 4032290815,
+STORE, 4032290816, 4032389119,
+STORE, 4032389120, 4032397311,
+STORE, 4032397312, 4032405503,
+STORE, 4032405504, 4032413695,
+STORE, 4032413696, 4032417791,
+STORE, 4032417792, 4032565247,
+STORE, 4032565248, 4032593919,
+STORE, 4032593920, 4032737279,
+STORE, 4032737280, 4032741375,
+STORE, 4032741376, 4032745471,
+STORE, 4032745472, 4032770047,
+STORE, 4032770048, 4032933887,
+STORE, 4032933888, 4032999423,
+STORE, 4032999424, 4033032191,
+STORE, 4033032192, 4033036287,
+STORE, 4033036288, 4033040383,
+STORE, 4033040384, 4033105919,
+STORE, 4033105920, 4033396735,
+STORE, 4033396736, 4033822719,
+STORE, 4033822720, 4033839103,
+STORE, 4033839104, 4033843199,
+STORE, 4033843200, 4033851391,
+STORE, 4033851392, 4033863679,
+STORE, 4033863680, 4033880063,
+STORE, 4033880064, 4033933311,
+STORE, 4033933312, 4034023423,
+STORE, 4034023424, 4034031615,
+STORE, 4034031616, 4034035711,
+STORE, 4034035712, 4034043903,
+STORE, 4034043904, 4034142207,
+STORE, 4034142208, 4034191359,
+STORE, 4034191360, 4034260991,
+STORE, 4034260992, 4034269183,
+STORE, 4034269184, 4034273279,
+STORE, 4034273280, 4034281471,
+STORE, 4034281472, 4034412543,
+STORE, 4034412544, 4034445311,
+STORE, 4034445312, 4034490367,
+STORE, 4034490368, 4034494463,
+STORE, 4034494464, 4034498559,
+STORE, 4034498560, 4034662399,
+STORE, 4034662400, 4034666495,
+STORE, 4034666496, 4034670591,
+STORE, 4034670592, 4034674687,
+STORE, 4034674688, 4034678783,
+STORE, 4034678784, 4034682879,
+STORE, 4034682880, 4034781183,
+STORE, 4034781184, 4035043327,
+STORE, 4035043328, 4035047423,
+STORE, 4035047424, 4035055615,
+STORE, 4035055616, 4035059711,
+STORE, 4035059712, 4035063807,
+STORE, 4035063808, 4035067903,
+STORE, 4035067904, 4035100671,
+STORE, 4035100672, 4035375103,
+STORE, 4035375104, 4035383295,
+STORE, 4035383296, 4035395583,
+STORE, 4035395584, 4035399679,
+STORE, 4035399680, 4035403775,
+STORE, 4035403776, 4035407871,
+STORE, 4035407872, 4035411967,
+STORE, 4035411968, 4035477503,
+STORE, 4035477504, 4035608575,
+STORE, 4035608576, 4035641343,
+STORE, 4035641344, 4035682303,
+STORE, 4035682304, 4035686399,
+STORE, 4035686400, 4035690495,
+STORE, 4035690496, 4035694591,
+STORE, 4035694592, 4035743743,
+STORE, 4035743744, 4035784703,
+STORE, 4035784704, 4035829759,
+STORE, 4035829760, 4035837951,
+STORE, 4035837952, 4035842047,
+STORE, 4035842048, 4035846143,
+STORE, 4035846144, 4035850239,
+STORE, 4035850240, 4036001791,
+STORE, 4036001792, 4036005887,
+STORE, 4036005888, 4036214783,
+STORE, 4036214784, 4036218879,
+STORE, 4036218880, 4036603903,
+STORE, 4036603904, 4036648959,
+STORE, 4036648960, 4036653055,
+STORE, 4036653056, 4036657151,
+STORE, 4036657152, 4036665343,
+STORE, 4036665344, 4036780031,
+STORE, 4036780032, 4036829183,
+STORE, 4036829184, 4036984831,
+STORE, 4036984832, 4036993023,
+STORE, 4036993024, 4036997119,
+STORE, 4036997120, 4037001215,
+STORE, 4037001216, 4037009407,
+STORE, 4037009408, 4037025791,
+STORE, 4037025792, 4037095423,
+STORE, 4037095424, 4037181439,
+STORE, 4037181440, 4037193727,
+STORE, 4037193728, 4037197823,
+STORE, 4037197824, 4037206015,
+STORE, 4037206016, 4037320703,
+STORE, 4037320704, 4037337087,
+STORE, 4037337088, 4037349375,
+STORE, 4037349376, 4037357567,
+STORE, 4037357568, 4037361663,
+STORE, 4037369856, 4037386239,
+STORE, 4037386240, 4037672959,
+STORE, 4037672960, 4037689343,
+STORE, 4037689344, 4037730303,
+STORE, 4037730304, 4037734399,
+STORE, 4037734400, 4037738495,
+STORE, 4037738496, 4037742591,
+STORE, 4037742592, 4037758975,
+STORE, 4037758976, 4037890047,
+STORE, 4037890048, 4037931007,
+STORE, 4037931008, 4037976063,
+STORE, 4037976064, 4037984255,
+STORE, 4037984256, 4037988351,
+STORE, 4037988352, 4038053887,
+STORE, 4038053888, 4038184959,
+STORE, 4038184960, 4038189055,
+STORE, 4038189056, 4038197247,
+STORE, 4038197248, 4038201343,
+STORE, 4038201344, 4038205439,
+STORE, 4038205440, 4038209535,
+STORE, 4038217728, 4038250495,
+STORE, 4038250496, 4038512639,
+STORE, 4038512640, 4038516735,
+STORE, 4038516736, 4038520831,
+STORE, 4038520832, 4038524927,
+STORE, 4038524928, 4038529023,
+STORE, 4038529024, 4038533119,
+STORE, 4038541312, 4038623231,
+STORE, 4038623232, 4038754303,
+STORE, 4038754304, 4038885375,
+STORE, 4038885376, 4038889471,
+STORE, 4038897664, 4038963199,
+STORE, 4038963200, 4038967295,
+STORE, 4038967296, 4038983679,
+STORE, 4038983680, 4039114751,
+STORE, 4039114752, 4039245823,
+STORE, 4039245824, 4039376895,
+STORE, 4039376896, 4040687615,
+STORE, 4040687616, 4040691711,
+STORE, 4040691712, 4040806399,
+STORE, 4040806400, 4040937471,
+STORE, 4040937472, 4040941567,
+STORE, 4040945664, 4040949759,
+STORE, 4040949760, 4041080831,
+STORE, 4041080832, 4041211903,
+STORE, 4041211904, 4043046911,
+STORE, 4043046912, 4043051007,
+STORE, 4043051008, 4043055103,
+STORE, 4043055104, 4043137023,
+STORE, 4043137024, 4043141119,
+STORE, 4043141120, 4043145215,
+STORE, 4043145216, 4043153407,
+STORE, 4043153408, 4043186175,
+STORE, 4043186176, 4043317247,
+STORE, 4043317248, 4043448319,
+STORE, 4043448320, 4043579391,
+STORE, 4043579392, 4043583487,
+STORE, 4043583488, 4043599871,
+STORE, 4043599872, 4043661311,
+STORE, 4043661312, 4043792383,
+STORE, 4043792384, 4043796479,
+STORE, 4043796480, 4043800575,
+STORE, 4043800576, 4043816959,
+STORE, 4043816960, 4043821055,
+STORE, 4043821056, 4043825151,
+STORE, 4043825152, 4043829247,
+STORE, 4043829248, 4043833343,
+STORE, 4043833344, 4047241215,
+STORE, 4047241216, 4047249407,
+STORE, 4047249408, 4047253503,
+STORE, 4047253504, 4047323135,
+STORE, 4047323136, 4047327231,
+STORE, 4047327232, 4047458303,
+STORE, 4047458304, 4047589375,
+STORE, 4047589376, 4047720447,
+STORE, 4047720448, 4047773695,
+STORE, 4047773696, 4047790079,
+STORE, 4047790080, 4047921151,
+STORE, 4047921152, 4048052223,
+STORE, 4048052224, 4048183295,
+STORE, 4048183296, 4049002495,
+STORE, 4049002496, 4049133567,
+STORE, 4049133568, 4049154047,
+STORE, 4049154048, 4049158143,
+STORE, 4049158144, 4049162239,
+STORE, 4049162240, 4049166335,
+STORE, 4049166336, 4049174527,
+STORE, 4049174528, 4049182719,
+STORE, 4049182720, 4049186815,
+STORE, 4049186816, 4049190911,
+STORE, 4049190912, 4049195007,
+STORE, 4049195008, 4049203199,
+STORE, 4049203200, 4049207295,
+STORE, 4049207296, 4049211391,
+STORE, 4049211392, 4049215487,
+STORE, 4049215488, 4049219583,
+STORE, 4049219584, 4049227775,
+STORE, 4049227776, 4049231871,
+STORE, 4049231872, 4049235967,
+STORE, 4049235968, 4049244159,
+STORE, 4049244160, 4049248255,
+STORE, 4049248256, 4049252351,
+STORE, 4049252352, 4049256447,
+STORE, 4049256448, 4049268735,
+STORE, 4049268736, 4049272831,
+STORE, 4049272832, 4049313791,
+STORE, 4049313792, 4049723391,
+STORE, 4049723392, 4049727487,
+STORE, 4049727488, 4049858559,
+STORE, 4049858560, 4049989631,
+STORE, 4049989632, 4049993727,
+STORE, 4049993728, 4050026495,
+STORE, 4050026496, 4050030591,
+STORE, 4050030592, 4050161663,
+STORE, 4050161664, 4050169855,
+STORE, 4050169856, 4050223103,
+STORE, 4050223104, 4050632703,
+STORE, 4050632704, 4050636799,
+STORE, 4050636800, 4050640895,
+STORE, 4050640896, 4050644991,
+STORE, 4050644992, 4050661375,
+STORE, 4050661376, 4050665471,
+STORE, 4050665472, 4050673663,
+STORE, 4050673664, 4050677759,
+STORE, 4050677760, 4050694143,
+STORE, 4050694144, 4050702335,
+STORE, 4050702336, 4050956287,
+STORE, 4050956288, 4051963903,
+STORE, 4051963904, 4051980287,
+STORE, 4051980288, 4051988479,
+STORE, 4051988480, 4052000767,
+STORE, 4052000768, 4052004863,
+STORE, 4052004864, 4052029439,
+STORE, 4284014592, 4284018687,
+STORE, 4284018688, 4292403199,
+SNULL, 4041080832, 4041211903,
+SNULL, 3795763200, 3795894271,
+STORE, 3629522944, 3696631807,
+SNULL, 3663077375, 3696631807,
+STORE, 3629522944, 3663077375,
+STORE, 3663077376, 3696631807,
+SNULL, 3663077376, 3696631807,
+STORE, 3663077376, 3696631807,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3626471424, 3627524095,
+SNULL, 3626471424, 3626475519,
+STORE, 3626475520, 3627524095,
+STORE, 3626471424, 3626475519,
+SNULL, 3627519999, 3627524095,
+STORE, 3626475520, 3627519999,
+STORE, 3627520000, 3627524095,
+STORE, 3625418752, 3626475519,
+SNULL, 3625418752, 3625422847,
+STORE, 3625422848, 3626475519,
+STORE, 3625418752, 3625422847,
+SNULL, 3626467327, 3626475519,
+STORE, 3625422848, 3626467327,
+STORE, 3626467328, 3626475519,
+STORE, 3624366080, 3625422847,
+SNULL, 3624366080, 3624370175,
+STORE, 3624370176, 3625422847,
+STORE, 3624366080, 3624370175,
+SNULL, 3625414655, 3625422847,
+STORE, 3624370176, 3625414655,
+STORE, 3625414656, 3625422847,
+STORE, 4041191424, 4041211903,
+SNULL, 4041195519, 4041211903,
+STORE, 4041191424, 4041195519,
+STORE, 4041195520, 4041211903,
+STORE, 4041170944, 4041191423,
+SNULL, 4041175039, 4041191423,
+STORE, 4041170944, 4041175039,
+STORE, 4041175040, 4041191423,
+SNULL, 3625426943, 3626467327,
+STORE, 3625422848, 3625426943,
+STORE, 3625426944, 3626467327,
+STORE, 4041162752, 4041170943,
+SNULL, 3626479615, 3627519999,
+STORE, 3626475520, 3626479615,
+STORE, 3626479616, 3627519999,
+STORE, 4041154560, 4041162751,
+STORE, 4041154560, 4041170943,
+STORE, 4041134080, 4041154559,
+SNULL, 4041138175, 4041154559,
+STORE, 4041134080, 4041138175,
+STORE, 4041138176, 4041154559,
+SNULL, 3624374271, 3625414655,
+STORE, 3624370176, 3624374271,
+STORE, 3624374272, 3625414655,
+STORE, 4041125888, 4041134079,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+STORE, 3487174656, 3487584255,
+STORE, 4041121792, 4041125887,
+SNULL, 4041121792, 4041125887,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 3487174656, 3487584255,
+STORE, 3222274048, 3223326719,
+SNULL, 3222274048, 3222278143,
+STORE, 3222278144, 3223326719,
+STORE, 3222274048, 3222278143,
+SNULL, 3223322623, 3223326719,
+STORE, 3222278144, 3223322623,
+STORE, 3223322624, 3223326719,
+STORE, 3221221376, 3222278143,
+SNULL, 3221221376, 3221225471,
+STORE, 3221225472, 3222278143,
+STORE, 3221221376, 3221225471,
+SNULL, 3222269951, 3222278143,
+STORE, 3221225472, 3222269951,
+STORE, 3222269952, 3222278143,
+STORE, 3220168704, 3221225471,
+SNULL, 3220168704, 3220172799,
+STORE, 3220172800, 3221225471,
+STORE, 3220168704, 3220172799,
+SNULL, 3221217279, 3221225471,
+STORE, 3220172800, 3221217279,
+STORE, 3221217280, 3221225471,
+STORE, 4041117696, 4041125887,
+STORE, 4041117696, 4041134079,
+STORE, 3219083264, 3220172799,
+SNULL, 3219083264, 3219087359,
+STORE, 3219087360, 3220172799,
+STORE, 3219083264, 3219087359,
+SNULL, 3220164607, 3220172799,
+STORE, 3219087360, 3220164607,
+STORE, 3220164608, 3220172799,
+STORE, 4041109504, 4041117695,
+STORE, 4041109504, 4041134079,
+STORE, 3217997824, 3219087359,
+SNULL, 3217997824, 3218001919,
+STORE, 3218001920, 3219087359,
+STORE, 3217997824, 3218001919,
+SNULL, 3219079167, 3219087359,
+STORE, 3218001920, 3219079167,
+STORE, 3219079168, 3219087359,
+STORE, 4041101312, 4041109503,
+STORE, 4041101312, 4041134079,
+STORE, 3216912384, 3218001919,
+SNULL, 3216912384, 3216916479,
+STORE, 3216916480, 3218001919,
+STORE, 3216912384, 3216916479,
+SNULL, 3217993727, 3218001919,
+STORE, 3216916480, 3217993727,
+STORE, 3217993728, 3218001919,
+STORE, 4041093120, 4041101311,
+STORE, 4041093120, 4041134079,
+STORE, 3215826944, 3216916479,
+SNULL, 3215826944, 3215831039,
+STORE, 3215831040, 3216916479,
+STORE, 3215826944, 3215831039,
+SNULL, 3216908287, 3216916479,
+STORE, 3215831040, 3216908287,
+STORE, 3216908288, 3216916479,
+STORE, 4016779264, 4016799743,
+SNULL, 4016783359, 4016799743,
+STORE, 4016779264, 4016783359,
+STORE, 4016783360, 4016799743,
+STORE, 4016758784, 4016779263,
+SNULL, 4016762879, 4016779263,
+STORE, 4016758784, 4016762879,
+STORE, 4016762880, 4016779263,
+SNULL, 3222282239, 3223322623,
+STORE, 3222278144, 3222282239,
+STORE, 3222282240, 3223322623,
+STORE, 4041084928, 4041093119,
+STORE, 4041084928, 4041134079,
+SNULL, 3221229567, 3222269951,
+STORE, 3221225472, 3221229567,
+STORE, 3221229568, 3222269951,
+STORE, 4015644672, 4015665151,
+STORE, 4038889472, 4038897663,
+SNULL, 4015648767, 4015665151,
+STORE, 4015644672, 4015648767,
+STORE, 4015648768, 4015665151,
+STORE, 4015624192, 4015644671,
+SNULL, 4015628287, 4015644671,
+STORE, 4015624192, 4015628287,
+STORE, 4015628288, 4015644671,
+SNULL, 3219091455, 3220164607,
+STORE, 3219087360, 3219091455,
+STORE, 3219091456, 3220164607,
+STORE, 4015603712, 4015624191,
+SNULL, 4015607807, 4015624191,
+STORE, 4015603712, 4015607807,
+STORE, 4015607808, 4015624191,
+SNULL, 3218006015, 3219079167,
+STORE, 3218001920, 3218006015,
+STORE, 3218006016, 3219079167,
+STORE, 3949674496, 3949694975,
+SNULL, 3949678591, 3949694975,
+STORE, 3949674496, 3949678591,
+STORE, 3949678592, 3949694975,
+SNULL, 3216920575, 3217993727,
+STORE, 3216916480, 3216920575,
+STORE, 3216920576, 3217993727,
+STORE, 3948924928, 3948945407,
+SNULL, 3948929023, 3948945407,
+STORE, 3948924928, 3948929023,
+STORE, 3948929024, 3948945407,
+SNULL, 3215835135, 3216908287,
+STORE, 3215831040, 3215835135,
+STORE, 3215835136, 3216908287,
+SNULL, 3220176895, 3221217279,
+STORE, 3220172800, 3220176895,
+STORE, 3220176896, 3221217279,
+STORE, 3214786560, 3215826943,
+STORE, 3213733888, 3214786559,
+SNULL, 3213733888, 3213737983,
+STORE, 3213737984, 3214786559,
+STORE, 3213733888, 3213737983,
+SNULL, 3214782463, 3214786559,
+STORE, 3213737984, 3214782463,
+STORE, 3214782464, 3214786559,
+STORE, 4038533120, 4038541311,
+STORE, 3948421120, 3948441599,
+SNULL, 3948425215, 3948441599,
+STORE, 3948421120, 3948425215,
+STORE, 3948425216, 3948441599,
+SNULL, 3213742079, 3214782463,
+STORE, 3213737984, 3213742079,
+STORE, 3213742080, 3214782463,
+STORE, 4038209536, 4038217727,
+STORE, 3212681216, 3213737983,
+SNULL, 3212681216, 3212685311,
+STORE, 3212685312, 3213737983,
+STORE, 3212681216, 3212685311,
+SNULL, 3213729791, 3213737983,
+STORE, 3212685312, 3213729791,
+STORE, 3213729792, 3213737983,
+STORE, 3795763200, 3795894271,
+STORE, 3946872832, 3946893311,
+SNULL, 3946876927, 3946893311,
+STORE, 3946872832, 3946876927,
+STORE, 3946876928, 3946893311,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+STORE, 3487174656, 3487584255,
+SNULL, 3212689407, 3213729791,
+STORE, 3212685312, 3212689407,
+STORE, 3212689408, 3213729791,
+STORE, 4041080832, 4041084927,
+STORE, 4040941568, 4040945663,
+STORE, 4037361664, 4037369855,
+STORE, 4000817152, 4000821247,
+STORE, 3999440896, 3999444991,
+STORE, 3212161024, 3212681215,
+SNULL, 3212161024, 3212439551,
+STORE, 3212439552, 3212681215,
+STORE, 3212161024, 3212439551,
+SNULL, 3212161024, 3212439551,
+SNULL, 3212464127, 3212681215,
+STORE, 3212439552, 3212464127,
+STORE, 3212464128, 3212681215,
+SNULL, 3212464128, 3212681215,
+SNULL, 3212439552, 3212451839,
+STORE, 3212451840, 3212464127,
+STORE, 3212439552, 3212451839,
+SNULL, 3212439552, 3212451839,
+STORE, 3212439552, 3212451839,
+SNULL, 3212451840, 3212455935,
+STORE, 3212455936, 3212464127,
+STORE, 3212451840, 3212455935,
+SNULL, 3212451840, 3212455935,
+STORE, 3212451840, 3212455935,
+SNULL, 3212455936, 3212460031,
+STORE, 3212460032, 3212464127,
+STORE, 3212455936, 3212460031,
+SNULL, 3212455936, 3212460031,
+STORE, 3212455936, 3212460031,
+SNULL, 3212460032, 3212464127,
+STORE, 3212460032, 3212464127,
+STORE, 3997679616, 3997683711,
+SNULL, 4049235968, 4049240063,
+STORE, 4049240064, 4049244159,
+STORE, 4049235968, 4049240063,
+SNULL, 4049240064, 4049244159,
+STORE, 4049240064, 4049244159,
+SNULL, 3997679616, 3997683711,
+SNULL, 3999440896, 3999444991,
+SNULL, 4000817152, 4000821247,
+SNULL, 4040941568, 4040945663,
+SNULL, 4041080832, 4041084927,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 3487174656, 3487584255,
+SNULL, 3212451840, 3212455935,
+STORE, 3212451840, 3212455935,
+STORE, 4041080832, 4041084927,
+STORE, 3623890944, 3624169471,
+SNULL, 4041080832, 4041084927,
+STORE, 4041080832, 4041084927,
+SNULL, 4041080832, 4041084927,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+STORE, 4041080832, 4041084927,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+STORE, 3211386880, 3212439551,
+SNULL, 3211386880, 3211390975,
+STORE, 3211390976, 3212439551,
+STORE, 3211386880, 3211390975,
+SNULL, 3212435455, 3212439551,
+STORE, 3211390976, 3212435455,
+STORE, 3212435456, 3212439551,
+STORE, 4040941568, 4040945663,
+STORE, 3937169408, 3937189887,
+STORE, 3623485440, 3623616511,
+SNULL, 717225983, 1388314623,
+STORE, 314572800, 717225983,
+STORE, 717225984, 1388314623,
+SNULL, 717225984, 1388314623,
+STORE, 3937112064, 3937132543,
+SNULL, 3937116159, 3937132543,
+STORE, 3937112064, 3937116159,
+STORE, 3937116160, 3937132543,
+SNULL, 3211395071, 3212435455,
+STORE, 3211390976, 3211395071,
+STORE, 3211395072, 3212435455,
+STORE, 4000817152, 4000821247,
+STORE, 3974823936, 3974832127,
+STORE, 3595284480, 3595431935,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+STORE, 3487174656, 3487584255,
+STORE, 3999440896, 3999444991,
+STORE, 3997679616, 3997683711,
+STORE, 3996295168, 3996299263,
+STORE, 3996090368, 3996094463,
+STORE, 3210866688, 3211386879,
+SNULL, 3210866688, 3211001855,
+STORE, 3211001856, 3211386879,
+STORE, 3210866688, 3211001855,
+SNULL, 3210866688, 3211001855,
+SNULL, 3211038719, 3211386879,
+STORE, 3211001856, 3211038719,
+STORE, 3211038720, 3211386879,
+SNULL, 3211038720, 3211386879,
+SNULL, 3211001856, 3211022335,
+STORE, 3211022336, 3211038719,
+STORE, 3211001856, 3211022335,
+SNULL, 3211001856, 3211022335,
+STORE, 3211001856, 3211022335,
+SNULL, 3211022336, 3211030527,
+STORE, 3211030528, 3211038719,
+STORE, 3211022336, 3211030527,
+SNULL, 3211022336, 3211030527,
+STORE, 3211022336, 3211030527,
+SNULL, 3211030528, 3211034623,
+STORE, 3211034624, 3211038719,
+STORE, 3211030528, 3211034623,
+SNULL, 3211030528, 3211034623,
+STORE, 3211030528, 3211034623,
+SNULL, 3211034624, 3211038719,
+STORE, 3211034624, 3211038719,
+STORE, 3994906624, 3994910719,
+SNULL, 4049240064, 4049244159,
+STORE, 4049240064, 4049244159,
+SNULL, 3994906624, 3994910719,
+SNULL, 3996090368, 3996094463,
+SNULL, 3996295168, 3996299263,
+SNULL, 3997679616, 3997683711,
+SNULL, 3999440896, 3999444991,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 3487174656, 3487584255,
+SNULL, 3211022336, 3211030527,
+STORE, 3211022336, 3211030527,
+STORE, 3999440896, 3999444991,
+STORE, 3210199040, 3211001855,
+SNULL, 3999440896, 3999444991,
+STORE, 3999440896, 3999444991,
+SNULL, 3999440896, 3999444991,
+STORE, 3594821632, 3594952703,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 4048183296, 4048592895,
+STORE, 4048592896, 4049002495,
+STORE, 4048183296, 4048592895,
+STORE, 4048183296, 4049002495,
+SNULL, 1914101759, 1969434623,
+STORE, 1914097664, 1914101759,
+STORE, 1914101760, 1969434623,
+STORE, 3567108096, 3567239167,
+STORE, 3973832704, 3973840895,
+STORE, 3209113600, 3210199039,
+SNULL, 3209113600, 3209117695,
+STORE, 3209117696, 3210199039,
+STORE, 3209113600, 3209117695,
+SNULL, 3210194943, 3210199039,
+STORE, 3209117696, 3210194943,
+STORE, 3210194944, 3210199039,
+STORE, 3935858688, 3935879167,
+SNULL, 3935862783, 3935879167,
+STORE, 3935858688, 3935862783,
+STORE, 3935862784, 3935879167,
+SNULL, 3209121791, 3210194943,
+STORE, 3209117696, 3209121791,
+STORE, 3209121792, 3210194943,
+STORE, 3528749056, 3528880127,
+STORE, 3968200704, 3968208895,
+STORE, 3208028160, 3209117695,
+SNULL, 3208028160, 3208032255,
+STORE, 3208032256, 3209117695,
+STORE, 3208028160, 3208032255,
+SNULL, 3209109503, 3209117695,
+STORE, 3208032256, 3209109503,
+STORE, 3209109504, 3209117695,
+STORE, 3888123904, 3888144383,
+SNULL, 3888127999, 3888144383,
+STORE, 3888123904, 3888127999,
+STORE, 3888128000, 3888144383,
+SNULL, 3208036351, 3209109503,
+STORE, 3208032256, 3208036351,
+STORE, 3208036352, 3209109503,
+SNULL, 3968200704, 3968208895,
+SNULL, 3888123904, 3888144383,
+SNULL, 3209109504, 3209113599,
+STORE, 3209113600, 3209117695,
+STORE, 3209109504, 3209113599,
+SNULL, 3208028160, 3209113599,
+STORE, 3208060928, 3209117695,
+SNULL, 3208060928, 3208065023,
+STORE, 3208065024, 3209117695,
+STORE, 3208060928, 3208065023,
+SNULL, 3209109503, 3209117695,
+STORE, 3208065024, 3209109503,
+STORE, 3209109504, 3209117695,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3888123904, 3888144383,
+SNULL, 3888127999, 3888144383,
+STORE, 3888123904, 3888127999,
+STORE, 3888128000, 3888144383,
+SNULL, 3208069119, 3209109503,
+STORE, 3208065024, 3208069119,
+STORE, 3208069120, 3209109503,
+STORE, 3968200704, 3968208895,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3527778304, 3527909375,
+STORE, 3999440896, 3999444991,
+STORE, 3997679616, 3997683711,
+STORE, 1914097664, 1914105855,
+STORE, 1914105856, 1969434623,
+STORE, 3957583872, 3957592063,
+STORE, 3206975488, 3208065023,
+SNULL, 3206975488, 3206979583,
+STORE, 3206979584, 3208065023,
+STORE, 3206975488, 3206979583,
+SNULL, 3208056831, 3208065023,
+STORE, 3206979584, 3208056831,
+STORE, 3208056832, 3208065023,
+STORE, 3956736000, 3956744191,
+STORE, 3205890048, 3206979583,
+SNULL, 3205890048, 3205894143,
+STORE, 3205894144, 3206979583,
+STORE, 3205890048, 3205894143,
+SNULL, 3206971391, 3206979583,
+STORE, 3205894144, 3206971391,
+STORE, 3206971392, 3206979583,
+STORE, 3806101504, 3806121983,
+SNULL, 3806105599, 3806121983,
+STORE, 3806101504, 3806105599,
+STORE, 3806105600, 3806121983,
+SNULL, 3206983679, 3208056831,
+STORE, 3206979584, 3206983679,
+STORE, 3206983680, 3208056831,
+STORE, 3806081024, 3806101503,
+SNULL, 3806085119, 3806101503,
+STORE, 3806081024, 3806085119,
+STORE, 3806085120, 3806101503,
+SNULL, 3205898239, 3206971391,
+STORE, 3205894144, 3205898239,
+STORE, 3205898240, 3206971391,
+STORE, 3956015104, 3956023295,
+STORE, 3204804608, 3205894143,
+SNULL, 3204804608, 3204808703,
+STORE, 3204808704, 3205894143,
+STORE, 3204804608, 3204808703,
+SNULL, 3205885951, 3205894143,
+STORE, 3204808704, 3205885951,
+STORE, 3205885952, 3205894143,
+STORE, 3803471872, 3803492351,
+STORE, 3803451392, 3803471871,
+STORE, 3803451392, 3803492351,
+SNULL, 3957583872, 3957592063,
+SNULL, 3806101504, 3806121983,
+SNULL, 3206975487, 3206979583,
+STORE, 3206971392, 3206975487,
+STORE, 3206975488, 3206979583,
+SNULL, 3208056832, 3208060927,
+STORE, 3208060928, 3208065023,
+STORE, 3208056832, 3208060927,
+SNULL, 3206975488, 3208060927,
+STORE, 3801845760, 3801878527,
+STORE, 3806101504, 3806121983,
+SNULL, 3806105599, 3806121983,
+STORE, 3806101504, 3806105599,
+STORE, 3806105600, 3806121983,
+SNULL, 3204812799, 3205885951,
+STORE, 3204808704, 3204812799,
+STORE, 3204812800, 3205885951,
+STORE, 1914097664, 1914109951,
+STORE, 1914109952, 1969434623,
+STORE, 3957583872, 3957592063,
+STORE, 3206971392, 3208065023,
+SNULL, 3206971392, 3206979583,
+STORE, 3206979584, 3208065023,
+STORE, 3206971392, 3206979583,
+SNULL, 3208056831, 3208065023,
+STORE, 3206979584, 3208056831,
+STORE, 3208056832, 3208065023,
+STORE, 3801825280, 3801845759,
+SNULL, 3801829375, 3801845759,
+STORE, 3801825280, 3801829375,
+STORE, 3801829376, 3801845759,
+SNULL, 3206983679, 3208056831,
+STORE, 3206979584, 3206983679,
+STORE, 3206983680, 3208056831,
+STORE, 3202707456, 3204804607,
+SNULL, 3202707456, 3204804607,
+STORE, 3202707456, 3204804607,
+STORE, 3200610304, 3202707455,
+SNULL, 3202707456, 3204804607,
+SNULL, 3200610304, 3202707455,
+STORE, 3202707456, 3204804607,
+SNULL, 3202707456, 3204804607,
+STORE, 3202707456, 3204804607,
+SNULL, 3202707456, 3204804607,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3527647232, 3527778303,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+STORE, 3487059968, 3487584255,
+SNULL, 3487059968, 3487301631,
+STORE, 3487301632, 3487584255,
+STORE, 3487059968, 3487301631,
+SNULL, 3487059968, 3487301631,
+SNULL, 3487563775, 3487584255,
+STORE, 3487301632, 3487563775,
+STORE, 3487563776, 3487584255,
+SNULL, 3487563776, 3487584255,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3524046848, 3524177919,
+STORE, 3487170560, 3487301631,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3487039488, 3487170559,
+STORE, 3487039488, 3487301631,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3204280320, 3204804607,
+SNULL, 3204280320, 3204448255,
+STORE, 3204448256, 3204804607,
+STORE, 3204280320, 3204448255,
+SNULL, 3204280320, 3204448255,
+SNULL, 3204710399, 3204804607,
+STORE, 3204448256, 3204710399,
+STORE, 3204710400, 3204804607,
+SNULL, 3204710400, 3204804607,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3996295168, 3996299263,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+SNULL, 3996295168, 3996299263,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3486908416, 3487039487,
+STORE, 3486908416, 3487301631,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3223326720, 3290435583,
+SNULL, 3223326720, 3256881151,
+STORE, 3256881152, 3290435583,
+STORE, 3223326720, 3256881151,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+STORE, 3201826816, 3202351103,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+STORE, 3202351104, 3204448255,
+SNULL, 3202351104, 3204448255,
+SNULL, 3803471871, 3803492351,
+STORE, 3803451392, 3803471871,
+STORE, 3803471872, 3803492351,
+SNULL, 3803471872, 3803492351,
+SNULL, 3803451392, 3803471871,
+STORE, 3798999040, 3799101439,
+SNULL, 3798999040, 3799101439,
+STORE, 3952644096, 3952652287,
+STORE, 3203362816, 3204448255,
+SNULL, 3203362816, 3203366911,
+STORE, 3203366912, 3204448255,
+STORE, 3203362816, 3203366911,
+SNULL, 3204444159, 3204448255,
+STORE, 3203366912, 3204444159,
+STORE, 3204444160, 3204448255,
+STORE, 3803471872, 3803492351,
+SNULL, 3803475967, 3803492351,
+STORE, 3803471872, 3803475967,
+STORE, 3803475968, 3803492351,
+SNULL, 3203371007, 3204444159,
+STORE, 3203366912, 3203371007,
+STORE, 3203371008, 3204444159,
+STORE, 3199729664, 3201826815,
+SNULL, 3199729664, 3201826815,
+STORE, 3199729664, 3201826815,
+SNULL, 3199729664, 3201826815,
+STORE, 3199729664, 3201826815,
+SNULL, 3199729664, 3201826815,
+STORE, 3199729664, 3201826815,
+SNULL, 3199729664, 3201826815,
+STORE, 3199729664, 3201826815,
+SNULL, 3199729664, 3201826815,
+STORE, 3200774144, 3201826815,
+SNULL, 3200774144, 3200778239,
+STORE, 3200778240, 3201826815,
+STORE, 3200774144, 3200778239,
+SNULL, 3201822719, 3201826815,
+STORE, 3200778240, 3201822719,
+STORE, 3201822720, 3201826815,
+STORE, 3803451392, 3803471871,
+SNULL, 3803455487, 3803471871,
+STORE, 3803451392, 3803455487,
+STORE, 3803455488, 3803471871,
+SNULL, 3200782335, 3201822719,
+STORE, 3200778240, 3200782335,
+STORE, 3200782336, 3201822719,
+STORE, 3949666304, 3949674495,
+STORE, 3949408256, 3949416447,
+STORE, 3199688704, 3200778239,
+SNULL, 3199688704, 3199692799,
+STORE, 3199692800, 3200778239,
+STORE, 3199688704, 3199692799,
+SNULL, 3200770047, 3200778239,
+STORE, 3199692800, 3200770047,
+STORE, 3200770048, 3200778239,
+STORE, 3799306240, 3799326719,
+SNULL, 3799310335, 3799326719,
+STORE, 3799306240, 3799310335,
+STORE, 3799310336, 3799326719,
+SNULL, 3199696895, 3200770047,
+STORE, 3199692800, 3199696895,
+STORE, 3199696896, 3200770047,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+STORE, 3799277568, 3799306239,
+SNULL, 3799277568, 3799306239,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+SNULL, 4041162751, 4041170943,
+STORE, 4041154560, 4041162751,
+STORE, 4041162752, 4041170943,
+SNULL, 4041162752, 4041170943,
+SNULL, 4041154560, 4041162751,
+SNULL, 4041191424, 4041211903,
+SNULL, 4041170944, 4041191423,
+SNULL, 3626471423, 3626475519,
+STORE, 3626467328, 3626471423,
+STORE, 3626471424, 3626475519,
+SNULL, 3626471424, 3627524095,
+SNULL, 3625418751, 3625422847,
+STORE, 3625414656, 3625418751,
+STORE, 3625418752, 3625422847,
+SNULL, 3625418752, 3626471423,
+STORE, 3627393024, 3627524095,
+STORE, 3627261952, 3627393023,
+STORE, 3627261952, 3627524095,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+STORE, 3195494400, 3197591551,
+SNULL, 3197591552, 3199688703,
+SNULL, 3195494400, 3197591551,
+STORE, 3197591552, 3199688703,
+SNULL, 3197591552, 3199688703,
+STORE, 3197591552, 3199688703,
+STORE, 3195494400, 3197591551,
+SNULL, 3197591552, 3199688703,
+SNULL, 3195494400, 3197591551,
+STORE, 3798999040, 3799101439,
+SNULL, 3798999040, 3799101439,
+/*
+ * mmap: unmapped_area_topdown: ffff9a9f14ddaa80
+ * Gap was found: mt 4041162752 gap_end 4041183232
+ * mmap: window was 4052029440 - 4096 size 28672
+ * mmap: mas.min 4041154560 max 4041191423 mas.last 4041191423
+ * mmap: mas.index 4041162752 align mask 0 offset 0
+ * mmap: rb_find_vma find on 4041162752 => ffff9a9f03d19678 (ffff9a9f03d19678)
+ */
+ };
+
+ unsigned long set43[] = {
+STORE, 140737488347136, 140737488351231,
+STORE, 140734187720704, 140737488351231,
+SNULL, 140734187724800, 140737488351231,
+STORE, 140734187589632, 140734187724799,
+STORE, 4194304, 6443007,
+STORE, 4337664, 6443007,
+STORE, 4194304, 4337663,
+SNULL, 4337664, 6443007,
+STORE, 6430720, 6443007,
+STORE, 206158430208, 206160674815,
+STORE, 206158569472, 206160674815,
+STORE, 206158430208, 206158569471,
+SNULL, 206158569472, 206160674815,
+STORE, 206160662528, 206160670719,
+STORE, 206160670720, 206160674815,
+STORE, 140734188756992, 140734188765183,
+STORE, 140734188740608, 140734188756991,
+STORE, 140501948112896, 140501948116991,
+ };
+
+ int count = 0;
+ void *ptr = NULL;
+
+ MA_STATE(mas, mt, 0, 0);
+
+ mt_set_non_kernel(3);
+ check_erase2_testset(mt, set, ARRAY_SIZE(set));
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set2, ARRAY_SIZE(set2));
+ start = 140735933894656;
+ MT_BUG_ON(mt, !!mt_find(mt, &start, 140735933906943UL));
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(2);
+ mt_init_flags(mt, 0);
+ check_erase2_testset(mt, set3, ARRAY_SIZE(set3));
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, 0);
+ check_erase2_testset(mt, set4, ARRAY_SIZE(set4));
+ rcu_read_lock();
+ mas_for_each(&mas, entry, ULONG_MAX) {
+ if (xa_is_zero(entry))
+ continue;
+ }
+ rcu_read_unlock();
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ mt_set_non_kernel(100);
+ check_erase2_testset(mt, set5, ARRAY_SIZE(set5));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set6, ARRAY_SIZE(set6));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set7, ARRAY_SIZE(set7));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set8, ARRAY_SIZE(set8));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set9, ARRAY_SIZE(set9));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set10, ARRAY_SIZE(set10));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set11, ARRAY_SIZE(set11));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 12288, 140014592737280, 0x2000);
+ MT_BUG_ON(mt, mas.last != 140014592573439);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mas.tree = mt;
+ count = 0;
+ mas.index = 0;
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set12, ARRAY_SIZE(set12));
+ rcu_barrier();
+ mas_for_each(&mas, entry, ULONG_MAX) {
+ if (xa_is_zero(entry))
+ continue;
+ BUG_ON(count > 12);
+ count++;
+ }
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set13, ARRAY_SIZE(set13));
+ mtree_erase(mt, 140373516443648);
+ rcu_read_lock();
+ mas_empty_area_rev(&mas, 0, 140373518663680, 4096);
+ rcu_read_unlock();
+ mtree_destroy(mt);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set14, ARRAY_SIZE(set14));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set15, ARRAY_SIZE(set15));
+ rcu_barrier();
+ mtree_destroy(mt);
+
+ /* set16 was to find a bug on limit updating at slot 0. */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set16, ARRAY_SIZE(set16));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 139921865637888, 0x6000);
+ MT_BUG_ON(mt, mas.last != 139921865547775);
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ /*
+ * set17 found a bug in walking backwards and not counting nulls at
+ * the end. This could cause a gap to be missed if the null had any
+ * size.
+ */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set17, ARRAY_SIZE(set17));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 139953197334528, 0x1000);
+ MT_BUG_ON(mt, mas.last != 139953197322239);
+/* MT_BUG_ON(mt, mas.index != 139953197318144); */
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ /*
+ * set18 found a bug in walking backwards and not setting the max from
+ * the node, but using the parent node. This was only an issue if the
+ * next slot in the parent had what we needed.
+ */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set18, ARRAY_SIZE(set18));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 140222972858368, 2215936);
+ MT_BUG_ON(mt, mas.last != 140222968475647);
+ /*MT_BUG_ON(mt, mas.index != 140222966259712); */
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ /*
+ * set19 found 2 bugs in prev.
+ * 1. If we hit root without finding anything, then there was an
+ * infinite loop.
+ * 2. The first ascending wasn't using the correct slot which may have
+ * caused missed entries.
+ */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set19, ARRAY_SIZE(set19));
+ rcu_barrier();
+ mas.index = 140656779083776;
+ entry = mas_find(&mas, ULONG_MAX);
+ MT_BUG_ON(mt, entry != xa_mk_value(140656779083776));
+ entry = mas_prev(&mas, 0);
+ MT_BUG_ON(mt, entry != xa_mk_value(140656766251008));
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ /*
+ * set20 found a bug in mas_may_move_gap due to the slot being
+ * overwritten during the __mas_add operation and setting it to zero.
+ */
+ mt_set_non_kernel(99);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set20, ARRAY_SIZE(set20));
+ rcu_barrier();
+ check_load(mt, 94849009414144, NULL);
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set21, ARRAY_SIZE(set21));
+ rcu_barrier();
+ mt_validate(mt);
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(999);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set22, ARRAY_SIZE(set22));
+ rcu_barrier();
+ mt_validate(mt);
+ ptr = mtree_load(mt, 140551363362816);
+ MT_BUG_ON(mt, ptr == mtree_load(mt, 140551363420159));
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set23, ARRAY_SIZE(set23));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+
+ mt_set_non_kernel(99);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set24, ARRAY_SIZE(set24));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set25, ARRAY_SIZE(set25));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* Split on NULL followed by delete - causes gap issues. */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set26, ARRAY_SIZE(set26));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 140109042671616, 409600);
+ MT_BUG_ON(mt, mas.last != 140109040959487);
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* Split on NULL followed by delete - causes gap issues. */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set27, ARRAY_SIZE(set27));
+ rcu_barrier();
+ MT_BUG_ON(mt, 0 != mtree_load(mt, 140415537422336));
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set28, ARRAY_SIZE(set28));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 139918413357056, 2097152);
+ /* Search for the size of gap then align it (offset 0) */
+ mas.index = (mas.last + 1 - 2097152 - 0) & (~2093056);
+ MT_BUG_ON(mt, mas.index != 139918401601536);
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* This test found issues with retry moving rebalanced nodes so the
+ * incorrect parent pivot was updated.
+ */
+ mt_set_non_kernel(999);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set29, ARRAY_SIZE(set29));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* This test found issues with deleting all entries in a node when
+ * surrounded by entries in the next nodes, then deleting the entries
+ * surrounding the node filled with deleted entries.
+ */
+ mt_set_non_kernel(999);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set30, ARRAY_SIZE(set30));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* This test found an issue with deleting all entries in a node that was
+ * the end node and mas_gap incorrectly set next = curr, and curr = prev
+ * then moved next to the left, losing data.
+ */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set31, ARRAY_SIZE(set31));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set32, ARRAY_SIZE(set32));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+/*
+ * mmap: empty_area_topdown: ffff88821c9cb600 Gap was found:
+ * mt 140582827569152 gap_end 140582869532672
+ * mmap: window was 140583656296448 - 4096 size 134217728
+ * mmap: mas.min 94133881868288 max 140582961786879 mas.last 140582961786879
+ * mmap: mas.index 140582827569152 align mask 0 offset 0
+ * mmap: rb_find_vma find on
+ * 140582827569152 => ffff88821c5bad00 (ffff88821c5bad00)
+ */
+
+ /* move gap failed due to an entirely empty node */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set33, ARRAY_SIZE(set33));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 140583656296448, 134217728);
+ MT_BUG_ON(mt, mas.last != 140583003750399);
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /*
+ * Incorrect gap in tree caused by mas_prev not setting the limits
+ * correctly while walking down.
+ */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set34, ARRAY_SIZE(set34));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* Empty leaf at the end of a parent caused incorrect gap. */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set35, ARRAY_SIZE(set35));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mt_set_non_kernel(99);
+ /* Empty leaf at the end of a parent caused incorrect gap. */
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set36, ARRAY_SIZE(set36));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set37, ARRAY_SIZE(set37));
+ rcu_barrier();
+ MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712));
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set38, ARRAY_SIZE(set38));
+ rcu_barrier();
+ MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712));
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set39, ARRAY_SIZE(set39));
+ rcu_barrier();
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set40, ARRAY_SIZE(set40));
+ rcu_barrier();
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set41, ARRAY_SIZE(set41));
+ rcu_barrier();
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* move gap failed due to an entirely empty node. */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set42, ARRAY_SIZE(set42));
+ rcu_barrier();
+ mas_empty_area_rev(&mas, 4096, 4052029440, 28672);
+ MT_BUG_ON(mt, mas.last != 4041211903);
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* gap calc off by one */
+ mt_set_non_kernel(99);
+ mas_reset(&mas);
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ check_erase2_testset(mt, set43, ARRAY_SIZE(set43));
+ rcu_barrier();
+ mt_set_non_kernel(0);
+ mt_validate(mt);
+ mtree_destroy(mt);
+}
+#endif
+
+/* End of VM testcases */
+
+/* RCU stress testing */
+
+/* RCU reader helper function */
+static void rcu_reader_register(struct rcu_test_struct2 *test)
+{
+ rcu_register_thread();
+ uatomic_inc(&test->thread_count);
+
+ while (!test->start)
+ usleep(test->pause * 100);
+}
+
+static void rcu_reader_setup(struct rcu_reader_struct *reader,
+ unsigned int id, struct rcu_test_struct2 *test)
+{
+ reader->id = id;
+ reader->test = test;
+ reader->mod = reader->id % 10;
+ reader->del = (reader->mod + 1) % 10;
+ reader->flip = (reader->mod + 2) % 10;
+ reader->add = (reader->mod + 3) % 10;
+ reader->next = (reader->mod + 4) % 10;
+}
+/* RCU reader in increasing index */
+static void *rcu_reader_fwd(void *ptr)
+
+{
+ struct rcu_reader_struct *reader = (struct rcu_reader_struct *)ptr;
+ struct rcu_test_struct2 *test = reader->test;
+ unsigned long index = reader->id;
+ bool toggled, modified, deleted, added;
+ int i;
+ void *entry, *prev = NULL;
+ MA_STATE(mas, test->mt, 0, 0);
+
+ rcu_reader_register(test);
+ toggled = modified = deleted = added = false;
+
+ while (!test->stop) {
+ i = 0;
+ /* mas_for_each ?*/
+ rcu_read_lock();
+ mas_set(&mas, test->index[index]);
+ mas_for_each(&mas, entry, test->last[index + 9]) {
+ unsigned long r_start, r_end, alt_start;
+ void *expected, *alt;
+
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+
+ if (i == reader->del) {
+ if (!deleted) {
+ alt_start = test->index[index + reader->flip];
+ /* delete occurred. */
+ if (mas.index == alt_start) {
+ uatomic_inc(&test->seen_deleted);
+ deleted = true;
+ }
+ }
+ if (deleted) {
+ i = reader->flip;
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+ }
+ }
+
+ if (!added && (i == reader->add)) {
+ alt_start = test->index[index + reader->next];
+ if (mas.index == r_start) {
+ uatomic_inc(&test->seen_added);
+ added = true;
+ } else if (mas.index == alt_start) {
+ i = reader->next;
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+ }
+ }
+
+ RCU_MT_BUG_ON(test, mas.index != r_start);
+ RCU_MT_BUG_ON(test, mas.last != r_end);
+
+ if (i == reader->flip) {
+ alt = xa_mk_value(index + i + RCU_RANGE_COUNT);
+ if (prev) {
+ if (toggled && entry == expected)
+ uatomic_inc(&test->seen_toggle);
+ else if (!toggled && entry == alt)
+ uatomic_inc(&test->seen_toggle);
+ }
+
+ if (entry == expected)
+ toggled = false;
+ else if (entry == alt)
+ toggled = true;
+ else {
+ printk("!!%lu-%lu -> %p not %p or %p\n", mas.index, mas.last, entry, expected, alt);
+ RCU_MT_BUG_ON(test, 1);
+ }
+
+ prev = entry;
+ } else if (i == reader->mod) {
+ alt = xa_mk_value(index + i * 2 + 1 +
+ RCU_RANGE_COUNT);
+ if (entry != expected) {
+ if (!modified)
+ uatomic_inc(&test->seen_modified);
+ modified = true;
+ } else {
+ if (modified)
+ uatomic_inc(&test->seen_modified);
+ modified = false;
+ }
+
+ if (modified)
+ RCU_MT_BUG_ON(test, entry != alt);
+
+ } else {
+ if (entry != expected)
+ printk("!!%lu-%lu -> %p not %p\n", mas.index, mas.last, entry, expected);
+ RCU_MT_BUG_ON(test, entry != expected);
+ }
+
+ i++;
+ }
+ rcu_read_unlock();
+ usleep(test->pause);
+ }
+
+ rcu_unregister_thread();
+ return NULL;
+}
+/* RCU reader in decreasing index */
+static void *rcu_reader_rev(void *ptr)
+{
+ struct rcu_reader_struct *reader = (struct rcu_reader_struct *)ptr;
+ struct rcu_test_struct2 *test = reader->test;
+ unsigned long index = reader->id;
+ bool toggled, modified, deleted, added;
+ int i;
+ void *prev = NULL;
+ MA_STATE(mas, test->mt, 0, 0);
+
+ rcu_reader_register(test);
+ toggled = modified = deleted = added = false;
+
+
+ while (!test->stop) {
+ void *entry;
+
+ i = 9;
+ mas_set(&mas, test->index[index + i]);
+
+ rcu_read_lock();
+ while (i--) {
+ unsigned long r_start, r_end, alt_start;
+ void *expected, *alt;
+ int line = __LINE__;
+
+ entry = mas_prev(&mas, test->index[index]);
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+
+ if (i == reader->del) {
+ alt_start = test->index[index + reader->mod];
+ if (mas.index == alt_start) {
+ line = __LINE__;
+ if (!deleted)
+ uatomic_inc(&test->seen_deleted);
+ deleted = true;
+ }
+ if (deleted) {
+ line = __LINE__;
+ i = reader->mod;
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+ }
+ }
+ if (!added && (i == reader->add)) {
+ alt_start = test->index[index + reader->flip];
+ if (mas.index == r_start) {
+ line = __LINE__;
+ uatomic_inc(&test->seen_added);
+ added = true;
+ } else if (mas.index == alt_start) {
+ line = __LINE__;
+ i = reader->flip;
+ r_start = test->index[index + i];
+ r_end = test->last[index + i];
+ expected = xa_mk_value(r_start);
+ }
+ }
+
+ if (i == reader->mod)
+ line = __LINE__;
+ else if (i == reader->flip)
+ line = __LINE__;
+
+ if (mas.index != r_start) {
+ alt = xa_mk_value(index + i * 2 + 1 +
+ RCU_RANGE_COUNT);
+ mt_dump(test->mt);
+ printk("Error: %lu-%lu %p != %lu-%lu %p %p line %d i %d\n",
+ mas.index, mas.last, entry,
+ r_start, r_end, expected, alt,
+ line, i);
+ }
+ RCU_MT_BUG_ON(test, mas.index != r_start);
+ RCU_MT_BUG_ON(test, mas.last != r_end);
+
+ if (i == reader->mod) {
+ alt = xa_mk_value(index + i * 2 + 1 +
+ RCU_RANGE_COUNT);
+
+ if (entry != expected) {
+ if (!modified)
+ uatomic_inc(&test->seen_modified);
+ modified = true;
+ } else {
+ if (modified)
+ uatomic_inc(&test->seen_modified);
+ modified = false;
+ }
+ if (modified)
+ RCU_MT_BUG_ON(test, entry != alt);
+
+
+ } else if (i == reader->flip) {
+ alt = xa_mk_value(index + i +
+ RCU_RANGE_COUNT);
+ if (prev) {
+ if (toggled && entry == expected)
+ uatomic_inc(&test->seen_toggle);
+ else if (!toggled && entry == alt)
+ uatomic_inc(&test->seen_toggle);
+ }
+
+ if (entry == expected)
+ toggled = false;
+ else if (entry == alt)
+ toggled = true;
+ else {
+ printk("%lu-%lu %p != %p or %p\n",
+ mas.index, mas.last, entry,
+ expected, alt);
+ RCU_MT_BUG_ON(test, 1);
+ }
+
+ prev = entry;
+ } else {
+ if (entry != expected)
+ printk("%lu-%lu %p != %p\n", mas.index,
+ mas.last, entry, expected);
+ RCU_MT_BUG_ON(test, entry != expected);
+ }
+ }
+ rcu_read_unlock();
+ usleep(test->pause);
+ }
+
+ rcu_unregister_thread();
+ return NULL;
+}
+
+static void rcu_stress_rev(struct maple_tree *mt, struct rcu_test_struct2 *test,
+ int count, struct rcu_reader_struct *test_reader)
+{
+ int i, j = 10000;
+ bool toggle = true;
+
+ test->start = true; /* Release the hounds! */
+ usleep(5);
+
+ while (j--) {
+ toggle = !toggle;
+ i = count;
+ while (i--) {
+ unsigned long start, end;
+ struct rcu_reader_struct *this = &test_reader[i];
+
+ /* Mod offset */
+ if (j == 600) {
+ start = test->index[this->id + this->mod];
+ end = test->last[this->id + this->mod];
+ mtree_store_range(mt, start, end,
+ xa_mk_value(this->id + this->mod * 2 +
+ 1 + RCU_RANGE_COUNT),
+ GFP_KERNEL);
+ }
+
+ /* Toggle */
+ if (!(j % 5)) {
+ start = test->index[this->id + this->flip];
+ end = test->last[this->id + this->flip];
+ mtree_store_range(mt, start, end,
+ xa_mk_value((toggle ? start :
+ this->id + this->flip +
+ RCU_RANGE_COUNT)),
+ GFP_KERNEL);
+ }
+
+ /* delete */
+ if (j == 400) {
+ start = test->index[this->id + this->del];
+ end = test->last[this->id + this->del];
+ mtree_store_range(mt, start, end, NULL, GFP_KERNEL);
+ }
+
+ /* add */
+ if (j == 500) {
+ start = test->index[this->id + this->add];
+ end = test->last[this->id + this->add];
+ mtree_store_range(mt, start, end,
+ xa_mk_value(start), GFP_KERNEL);
+ }
+ }
+ usleep(test->pause);
+ /* If a test fails, don't flood the console */
+ if (test->stop)
+ break;
+ }
+}
+
+static void rcu_stress_fwd(struct maple_tree *mt, struct rcu_test_struct2 *test,
+ int count, struct rcu_reader_struct *test_reader)
+{
+ int j, i;
+ bool toggle = true;
+
+ test->start = true; /* Release the hounds! */
+ usleep(5);
+ for (j = 0; j < 10000; j++) {
+ toggle = !toggle;
+ for (i = 0; i < count; i++) {
+ unsigned long start, end;
+ struct rcu_reader_struct *this = &test_reader[i];
+
+ /* Mod offset */
+ if (j == 600) {
+ start = test->index[this->id + this->mod];
+ end = test->last[this->id + this->mod];
+ mtree_store_range(mt, start, end,
+ xa_mk_value(this->id + this->mod * 2 +
+ 1 + RCU_RANGE_COUNT),
+ GFP_KERNEL);
+ }
+
+ /* Toggle */
+ if (!(j % 5)) {
+ start = test->index[this->id + this->flip];
+ end = test->last[this->id + this->flip];
+ mtree_store_range(mt, start, end,
+ xa_mk_value((toggle ? start :
+ this->id + this->flip +
+ RCU_RANGE_COUNT)),
+ GFP_KERNEL);
+ }
+
+ /* delete */
+ if (j == 400) {
+ start = test->index[this->id + this->del];
+ end = test->last[this->id + this->del];
+ mtree_store_range(mt, start, end, NULL, GFP_KERNEL);
+ }
+
+ /* add */
+ if (j == 500) {
+ start = test->index[this->id + this->add];
+ end = test->last[this->id + this->add];
+ mtree_store_range(mt, start, end,
+ xa_mk_value(start), GFP_KERNEL);
+ }
+ }
+ usleep(test->pause);
+ /* If a test fails, don't flood the console */
+ if (test->stop)
+ break;
+ }
+}
+
+/*
+ * This is to check:
+ * 1. Range that is not ever present
+ * 2. Range that is always present
+ * 3. Things being added but not removed.
+ * 4. Things being removed but not added.
+ * 5. Things are being added and removed, searches my succeed or fail
+ *
+ * This sets up two readers for every 10 entries; one forward and one reverse
+ * reading.
+ */
+static void rcu_stress(struct maple_tree *mt, bool forward)
+{
+ unsigned int count, i;
+ unsigned long r, seed;
+ pthread_t readers[RCU_RANGE_COUNT / 5];
+ struct rcu_test_struct2 test;
+ struct rcu_reader_struct test_reader[RCU_RANGE_COUNT / 5];
+ void *(*function)(void *);
+
+ /* Test setup */
+ test.mt = mt;
+ test.pause = 5;
+ test.seen_toggle = 0;
+ test.seen_deleted = 0;
+ test.seen_added = 0;
+ test.seen_modified = 0;
+ test.thread_count = 0;
+ test.start = test.stop = false;
+ seed = time(NULL);
+ srand(seed);
+ for (i = 0; i < RCU_RANGE_COUNT; i++) {
+ r = seed + rand();
+ mtree_store_range(mt, seed, r,
+ xa_mk_value(seed), GFP_KERNEL);
+
+ /* Record start and end of entry */
+ test.index[i] = seed;
+ test.last[i] = r;
+ seed = 1 + r + rand() % 10;
+ }
+
+ i = count = ARRAY_SIZE(readers);
+ while (i--) {
+ unsigned long id;
+
+ id = i / 2 * 10;
+ if (i % 2)
+ function = rcu_reader_fwd;
+ else
+ function = rcu_reader_rev;
+
+ rcu_reader_setup(&test_reader[i], id, &test);
+ if (pthread_create(&readers[i], NULL, *function,
+ &test_reader[i])) {
+ perror("creating reader thread");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(readers); i++) {
+ struct rcu_reader_struct *this = &test_reader[i];
+ int add = this->id + this->add;
+
+ /* Remove add entries from the tree for later addition */
+ mtree_store_range(mt, test.index[add], test.last[add],
+ NULL, GFP_KERNEL);
+ }
+
+ mt_set_in_rcu(mt);
+ do {
+ usleep(5);
+ } while (test.thread_count > ARRAY_SIZE(readers));
+
+ if (forward)
+ rcu_stress_fwd(mt, &test, count, test_reader);
+ else
+ rcu_stress_rev(mt, &test, count, test_reader);
+
+ test.stop = true;
+ while (count--)
+ pthread_join(readers[count], NULL);
+
+ mt_validate(mt);
+}
+
+
+struct rcu_test_struct {
+ struct maple_tree *mt; /* the maple tree */
+ int count; /* Number of times to check value(s) */
+ unsigned long index; /* The first index to check */
+ void *entry1; /* The first entry value */
+ void *entry2; /* The second entry value */
+ void *entry3; /* The third entry value */
+
+ bool update_2;
+ bool update_3;
+ unsigned long range_start;
+ unsigned long range_end;
+ unsigned int loop_sleep;
+ unsigned int val_sleep;
+
+ unsigned int failed; /* failed detection for other threads */
+ unsigned int seen_entry2; /* Number of threads that have seen the new value */
+ unsigned int seen_entry3; /* Number of threads that have seen the new value */
+ unsigned int seen_both; /* Number of threads that have seen both new values */
+ unsigned int seen_toggle;
+ unsigned int seen_added;
+ unsigned int seen_removed;
+ unsigned long last; /* The end of the range to write. */
+
+ unsigned long removed; /* The index of the removed entry */
+ unsigned long added; /* The index of the removed entry */
+ unsigned long toggle; /* The index of the removed entry */
+};
+
+static inline
+int eval_rcu_entry(struct rcu_test_struct *test, void *entry, bool *update_2,
+ bool *update_3)
+{
+ if (entry == test->entry1)
+ return 0;
+
+ if (entry == test->entry2) {
+ if (!(*update_2)) {
+ uatomic_inc(&test->seen_entry2);
+ *update_2 = true;
+ if (update_3)
+ uatomic_inc(&test->seen_both);
+ }
+ return 0;
+ }
+
+ if (entry == test->entry3) {
+ if (!(*update_3)) {
+ uatomic_inc(&test->seen_entry3);
+ *update_3 = true;
+ if (update_2)
+ uatomic_inc(&test->seen_both);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * rcu_val() - Read a given value in the tree test->count times using the
+ * regular API
+ *
+ * @ptr: The pointer to the rcu_test_struct
+ */
+static void *rcu_val(void *ptr)
+{
+ struct rcu_test_struct *test = (struct rcu_test_struct *)ptr;
+ unsigned long count = test->count;
+ bool update_2 = false;
+ bool update_3 = false;
+ void *entry;
+
+ rcu_register_thread();
+ while (count--) {
+ usleep(test->val_sleep);
+ /*
+ * No locking required, regular API locking is handled in the
+ * maple tree code
+ */
+ entry = mtree_load(test->mt, test->index);
+ MT_BUG_ON(test->mt, eval_rcu_entry(test, entry, &update_2,
+ &update_3));
+ }
+ rcu_unregister_thread();
+ return NULL;
+}
+
+/*
+ * rcu_loop() - Loop over a section of the maple tree, checking for an expected
+ * value using the advanced API
+ *
+ * @ptr - The pointer to the rcu_test_struct
+ */
+static void *rcu_loop(void *ptr)
+{
+ struct rcu_test_struct *test = (struct rcu_test_struct *)ptr;
+ unsigned long count = test->count;
+ void *entry, *expected;
+ bool update_2 = false;
+ bool update_3 = false;
+ MA_STATE(mas, test->mt, test->range_start, test->range_start);
+
+ rcu_register_thread();
+
+ /*
+ * Loop through the test->range_start - test->range_end test->count
+ * times
+ */
+ while (count--) {
+ usleep(test->loop_sleep);
+ rcu_read_lock();
+ mas_for_each(&mas, entry, test->range_end) {
+ /* The expected value is based on the start range. */
+ expected = xa_mk_value(mas.index ? mas.index / 10 : 0);
+
+ /* Out of the interesting range */
+ if (mas.index < test->index || mas.index > test->last) {
+ if (entry != expected) {
+ printk("%lx - %lx = %p not %p\n",
+ mas.index, mas.last, entry, expected);
+ }
+ MT_BUG_ON(test->mt, entry != expected);
+ continue;
+ }
+
+ if (entry == expected)
+ continue; /* Not seen. */
+
+ /* In the interesting range */
+ MT_BUG_ON(test->mt, eval_rcu_entry(test, entry,
+ &update_2,
+ &update_3));
+ }
+ rcu_read_unlock();
+ mas_set(&mas, test->range_start);
+ }
+
+ rcu_unregister_thread();
+ return NULL;
+}
+
+static noinline
+void run_check_rcu(struct maple_tree *mt, struct rcu_test_struct *vals)
+{
+
+ int i;
+ void *(*function)(void *);
+ pthread_t readers[20];
+
+ mt_set_in_rcu(mt);
+ MT_BUG_ON(mt, !mt_in_rcu(mt));
+
+ for (i = 0; i < ARRAY_SIZE(readers); i++) {
+ if (i % 2)
+ function = rcu_loop;
+ else
+ function = rcu_val;
+
+ if (pthread_create(&readers[i], NULL, *function, vals)) {
+ perror("creating reader thread");
+ exit(1);
+ }
+ }
+
+ usleep(5); /* small yield to ensure all threads are at least started. */
+ mtree_store_range(mt, vals->index, vals->last, vals->entry2,
+ GFP_KERNEL);
+ while (i--)
+ pthread_join(readers[i], NULL);
+
+ /* Make sure the test caught at least one update. */
+ MT_BUG_ON(mt, !vals->seen_entry2);
+}
+
+static noinline
+void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals)
+{
+
+ int i;
+ void *(*function)(void *);
+ pthread_t readers[20];
+ unsigned int index = vals->index;
+
+ mt_set_in_rcu(mt);
+ MT_BUG_ON(mt, !mt_in_rcu(mt));
+
+ for (i = 0; i < ARRAY_SIZE(readers); i++) {
+ if (i % 2)
+ function = rcu_loop;
+ else
+ function = rcu_val;
+
+ if (pthread_create(&readers[i], NULL, *function, vals)) {
+ perror("creating reader thread");
+ exit(1);
+ }
+ }
+
+ usleep(5); /* small yield to ensure all threads are at least started. */
+
+ while (index <= vals->last) {
+ mtree_store(mt, index,
+ (index % 2 ? vals->entry2 : vals->entry3),
+ GFP_KERNEL);
+ index++;
+ usleep(5);
+ }
+
+ while (i--)
+ pthread_join(readers[i], NULL);
+
+ /* Make sure the test caught at least one update. */
+ MT_BUG_ON(mt, !vals->seen_entry2);
+ MT_BUG_ON(mt, !vals->seen_entry3);
+ MT_BUG_ON(mt, !vals->seen_both);
+}
+static noinline void check_rcu_simulated(struct maple_tree *mt)
+{
+ unsigned long i, nr_entries = 1000;
+ unsigned long target = 4320;
+ unsigned long val = 0xDEAD;
+
+ MA_STATE(mas_writer, mt, 0, 0);
+ MA_STATE(mas_reader, mt, target, target);
+
+ rcu_register_thread();
+
+ mt_set_in_rcu(mt);
+ mas_lock(&mas_writer);
+ for (i = 0; i <= nr_entries; i++) {
+ mas_writer.index = i * 10;
+ mas_writer.last = i * 10 + 5;
+ mas_store_gfp(&mas_writer, xa_mk_value(i), GFP_KERNEL);
+ }
+ mas_unlock(&mas_writer);
+
+ /* Overwrite one entry with a new value. */
+ mas_set_range(&mas_writer, target, target + 5);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ mas_reset(&mas_reader);
+
+
+ /* Overwrite 1/2 the entry */
+ mas_set_range(&mas_writer, target, target + 2);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
+ rcu_read_unlock();
+
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ mas_reset(&mas_reader);
+
+ /* Overwrite last 1/2 the entry */
+ mas_set_range(&mas_writer, target + 2, target + 5);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ rcu_read_unlock();
+
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ mas_reset(&mas_reader);
+
+ /* Overwrite more than the entry */
+ mas_set_range(&mas_writer, target - 5, target + 15);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ mas_reset(&mas_reader);
+
+ /* Overwrite more than the node. */
+ mas_set_range(&mas_writer, target - 400, target + 400);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ mas_reset(&mas_reader);
+
+ /* Overwrite the tree */
+ mas_set_range(&mas_writer, 0, ULONG_MAX);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ /* Clear out tree & recreate it */
+ mas_lock(&mas_writer);
+ mas_set_range(&mas_writer, 0, ULONG_MAX);
+ mas_store_gfp(&mas_writer, NULL, GFP_KERNEL);
+ mas_set_range(&mas_writer, 0, 0);
+ for (i = 0; i <= nr_entries; i++) {
+ mas_writer.index = i * 10;
+ mas_writer.last = i * 10 + 5;
+ mas_store_gfp(&mas_writer, xa_mk_value(i), GFP_KERNEL);
+ }
+ mas_unlock(&mas_writer);
+
+ /* next check */
+ /* Overwrite one entry with a new value. */
+ mas_reset(&mas_reader);
+ mas_set_range(&mas_writer, target, target + 5);
+ mas_set_range(&mas_reader, target, target);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_prev(&mas_reader, 0);
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_next(&mas_reader, ULONG_MAX) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ /* Restore value. */
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(target/10), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+
+ /* prev check */
+ /* Overwrite one entry with a new value. */
+ mas_reset(&mas_reader);
+ mas_set_range(&mas_writer, target, target + 5);
+ mas_set_range(&mas_reader, target, target);
+ rcu_read_lock();
+ MT_BUG_ON(mt, mas_walk(&mas_reader) != xa_mk_value(target/10));
+ mas_next(&mas_reader, ULONG_MAX);
+ mas_lock(&mas_writer);
+ mas_store_gfp(&mas_writer, xa_mk_value(val), GFP_KERNEL);
+ mas_unlock(&mas_writer);
+ MT_BUG_ON(mt, mas_prev(&mas_reader, 0) != xa_mk_value(val));
+ rcu_read_unlock();
+
+ rcu_unregister_thread();
+}
+
+static noinline void check_rcu_threaded(struct maple_tree *mt)
+{
+ unsigned long i, nr_entries = 1000;
+ struct rcu_test_struct vals;
+
+ vals.val_sleep = 200;
+ vals.loop_sleep = 110;
+
+ rcu_register_thread();
+ for (i = 0; i <= nr_entries; i++)
+ mtree_store_range(mt, i*10, i*10 + 5,
+ xa_mk_value(i), GFP_KERNEL);
+ /* Store across several slots. */
+ vals.count = 1000;
+ vals.mt = mt;
+ vals.index = 8650;
+ vals.last = 8666;
+ vals.entry1 = xa_mk_value(865);
+ vals.entry2 = xa_mk_value(8650);
+ vals.entry3 = xa_mk_value(8650);
+ vals.range_start = 0;
+ vals.range_end = ULONG_MAX;
+ vals.seen_entry2 = 0;
+ vals.seen_entry3 = 0;
+
+ run_check_rcu(mt, &vals);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= nr_entries; i++)
+ mtree_store_range(mt, i*10, i*10 + 5,
+ xa_mk_value(i), GFP_KERNEL);
+
+ /* 4390-4395: value 439 (0x1b7) [0x36f] */
+ /* Store across several slots. */
+ /* Spanning store. */
+ vals.count = 10000;
+ vals.mt = mt;
+ vals.index = 4390;
+ vals.last = 4398;
+ vals.entry1 = xa_mk_value(4390);
+ vals.entry2 = xa_mk_value(439);
+ vals.entry3 = xa_mk_value(439);
+ vals.seen_entry2 = 0;
+ vals.range_start = 4316;
+ vals.range_end = 5035;
+ run_check_rcu(mt, &vals);
+ mtree_destroy(mt);
+
+
+ /* Forward writer for rcu stress */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ rcu_stress(mt, true);
+ mtree_destroy(mt);
+
+ /* Reverse writer for rcu stress */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ rcu_stress(mt, false);
+ mtree_destroy(mt);
+
+ /* Slow reader test with spanning store. */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= nr_entries; i++)
+ mtree_store_range(mt, i*10, i*10 + 5,
+ xa_mk_value(i), GFP_KERNEL);
+
+ /* 4390-4395: value 439 (0x1b7) [0x36f] */
+ /* Store across several slots. */
+ /* Spanning store. */
+ vals.count = 15000;
+ vals.mt = mt;
+ vals.index = 4390;
+ vals.last = 4398;
+ vals.entry1 = xa_mk_value(4390);
+ vals.entry2 = xa_mk_value(439);
+ vals.entry3 = xa_mk_value(4391);
+ vals.seen_toggle = 0;
+ vals.seen_added = 0;
+ vals.seen_removed = 0;
+ vals.range_start = 4316;
+ vals.range_end = 5035;
+ vals.removed = 4360;
+ vals.added = 4396;
+ vals.toggle = 4347;
+ vals.val_sleep = 400;
+ vals.loop_sleep = 200;
+ vals.seen_entry2 = 0;
+ vals.seen_entry3 = 0;
+ vals.seen_both = 0;
+ vals.entry3 = xa_mk_value(438);
+
+ run_check_rcu_slowread(mt, &vals);
+ rcu_unregister_thread();
+}
+/* End of RCU stress testing */
+
+/* Check tree structure by depth first searching */
+static void mas_dfs_preorder(struct ma_state *mas)
+{
+
+ struct maple_enode *prev;
+ unsigned char end, slot = 0;
+
+ if (mas->node == MAS_START) {
+ mas_start(mas);
+ return;
+ }
+
+ if (mte_is_leaf(mas->node) && mte_is_root(mas->node))
+ goto done;
+
+walk_up:
+ end = mas_data_end(mas);
+ if (mte_is_leaf(mas->node) ||
+ (slot > end)) {
+ if (mte_is_root(mas->node))
+ goto done;
+
+ slot = mte_parent_slot(mas->node) + 1;
+ mas_ascend(mas);
+ goto walk_up;
+ }
+
+ prev = mas->node;
+ mas->node = mas_get_slot(mas, slot);
+ if (!mas->node || slot > end) {
+ if (mte_is_root(prev))
+ goto done;
+
+ mas->node = prev;
+ slot = mte_parent_slot(mas->node) + 1;
+ mas_ascend(mas);
+ goto walk_up;
+ }
+
+ return;
+done:
+ mas->node = MAS_NONE;
+}
+
+
+static void check_dfs_preorder(struct maple_tree *mt)
+{
+ unsigned long e, count = 0, max = 1000;
+
+ MA_STATE(mas, mt, 0, 0);
+
+ if (MAPLE_32BIT)
+ e = 37;
+ else
+ e = 74;
+
+ check_seq(mt, max, false);
+ do {
+ count++;
+ mas_dfs_preorder(&mas);
+ } while (!mas_is_none(&mas));
+ MT_BUG_ON(mt, count != e);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ mas_reset(&mas);
+ count = 0;
+ if (!MAPLE_32BIT)
+ e = 77;
+
+ check_seq(mt, max, false);
+ do {
+ count++;
+ mas_dfs_preorder(&mas);
+ } while (!mas_is_none(&mas));
+ /*printk("count %lu\n", count); */
+ MT_BUG_ON(mt, count != e);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ mas_reset(&mas);
+ count = 0;
+ check_rev_seq(mt, max, false);
+ do {
+ count++;
+ mas_dfs_preorder(&mas);
+ } while (!mas_is_none(&mas));
+ /*printk("count %lu\n", count); */
+ MT_BUG_ON(mt, count != e);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ mas_reset(&mas);
+ mt_zero_nr_tallocated();
+ mt_set_non_kernel(200);
+ mas_expected_entries(&mas, max);
+ for (count = 0; count <= max; count++) {
+ mas.index = mas.last = count;
+ mas_store(&mas, xa_mk_value(count));
+ MT_BUG_ON(mt, mas_is_err(&mas));
+ }
+ mas_destroy(&mas);
+ rcu_barrier();
+ /*
+ * pr_info(" ->seq test of 0-%lu %luK in %d active (%d total)\n",
+ * max, mt_get_alloc_size()/1024, mt_nr_allocated(),
+ * mt_nr_tallocated());
+ */
+
+}
+/* End of depth first search tests */
+
+/* Preallocation testing */
+static noinline void check_prealloc(struct maple_tree *mt)
+{
+ unsigned long i, max = 100;
+ unsigned long allocated;
+ unsigned char height;
+ struct maple_node *mn;
+ void *ptr = check_prealloc;
+ MA_STATE(mas, mt, 10, 20);
+
+ mt_set_non_kernel(1000);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_destroy(&mas);
+ allocated = mas_allocated(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ mas_destroy(&mas);
+ allocated = mas_allocated(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
+ ma_free_rcu(mn);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ mas_destroy(&mas);
+ allocated = mas_allocated(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ mas_destroy(&mas);
+ allocated = mas_allocated(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+ ma_free_rcu(mn);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mn = mas_pop_node(&mas);
+ MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
+ mas_push_node(&mas, mn);
+ MT_BUG_ON(mt, mas_allocated(&mas) != allocated);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ mas_destroy(&mas);
+ allocated = mas_allocated(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_store_prealloc(&mas, ptr);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_store_prealloc(&mas, ptr);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_store_prealloc(&mas, ptr);
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_store_prealloc(&mas, ptr);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ mt_set_non_kernel(1);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL & GFP_NOWAIT) == 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+ mas_destroy(&mas);
+
+
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated == 0);
+ MT_BUG_ON(mt, allocated != 1 + height * 3);
+ mas_store_prealloc(&mas, ptr);
+ MT_BUG_ON(mt, mas_allocated(&mas) != 0);
+ mt_set_non_kernel(1);
+ MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL & GFP_NOWAIT) == 0);
+ allocated = mas_allocated(&mas);
+ height = mas_mt_height(&mas);
+ MT_BUG_ON(mt, allocated != 0);
+}
+/* End of preallocation testing */
+
+/* Spanning writes, writes that span nodes and layers of the tree */
+static noinline void check_spanning_write(struct maple_tree *mt)
+{
+ unsigned long i, max = 5000;
+ MA_STATE(mas, mt, 1200, 2380);
+
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 1205);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ for (i = 1; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mtree_lock(mt);
+ mas_set_range(&mas, 9, 50006); /* Will expand to 0 - ULONG_MAX */
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 1205);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mt_validate(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning store that requires a right cousin rebalance */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 0, 12900); /* Spans more than 2 levels */
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 1205);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test non-alloc tree spanning store */
+ mt_init_flags(mt, 0);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 0, 300);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 15);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning store that requires a right sibling rebalance */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 0, 12865);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 15);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning store that requires a left sibling rebalance */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 90, 13665);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 95);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning store that requires a left cousin rebalance */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 46805, 49995);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 46815);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /*
+ * Test spanning store that requires a left cousin rebalance all the way
+ * to root
+ */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mas_set_range(&mas, 32395, 49995);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 46815);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /*
+ * Test spanning store that requires a right cousin rebalance all the
+ * way to root
+ */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+ mas_set_range(&mas, 38875, 43190);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 38900);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning store ending at full node (depth 2)*/
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+ mtree_lock(mt);
+ mas_set(&mas, 47606);
+ mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
+ mas_set(&mas, 47607);
+ mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
+ mas_set(&mas, 47608);
+ mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
+ mas_set(&mas, 47609);
+ mas_store_gfp(&mas, check_spanning_write, GFP_KERNEL);
+ /* Ensure the parent node is full */
+ mas_ascend(&mas);
+ MT_BUG_ON(mt, (mas_data_end(&mas)) != mt_slot_count(mas.node) - 1);
+ mas_set_range(&mas, 11516, 48940);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ /* Test spanning write with many levels of no siblings */
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+ mas_set_range(&mas, 43200, 49999);
+ mtree_lock(mt);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mas_set(&mas, 43200);
+ MT_BUG_ON(mt, mas_walk(&mas) != NULL);
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+
+ mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+ for (i = 0; i <= 100; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+
+ mtree_lock(mt);
+ mas_set_range(&mas, 76, 875);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ mtree_unlock(mt);
+}
+/* End of spanning write testing */
+
+/* Writes to a NULL area that are adjacent to other NULLs */
+static noinline void check_null_expand(struct maple_tree *mt)
+{
+ unsigned long i, max = 100;
+ unsigned char data_end;
+ MA_STATE(mas, mt, 959, 959);
+
+ for (i = 0; i <= max; i++)
+ mtree_test_store_range(mt, i * 10, i * 10 + 5, &i);
+ /* Test expanding null at start. */
+ mas_lock(&mas);
+ mas_walk(&mas);
+ data_end = mas_data_end(&mas);
+ mas_set_range(&mas, 959, 963);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ MT_BUG_ON(mt, mtree_load(mt, 963) != NULL);
+ MT_BUG_ON(mt, data_end != mas_data_end(&mas));
+
+ /* Test expanding null at end. */
+ mas_set(&mas, 880);
+ mas_walk(&mas);
+ data_end = mas_data_end(&mas);
+ mas_set_range(&mas, 884, 887);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ MT_BUG_ON(mt, mtree_load(mt, 884) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 889) != NULL);
+#if CONFIG_64BIT
+ MT_BUG_ON(mt, data_end != mas_data_end(&mas));
+#endif
+
+ /* Test expanding null at start and end. */
+ mas_set(&mas, 890);
+ mas_walk(&mas);
+ data_end = mas_data_end(&mas);
+ mas_set_range(&mas, 900, 905);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ MT_BUG_ON(mt, mtree_load(mt, 899) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 900) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 905) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 906) != NULL);
+#if CONFIG_64BIT
+ MT_BUG_ON(mt, data_end - 2 != mas_data_end(&mas));
+#endif
+
+ /* Test expanding null across multiple slots. */
+ mas_set(&mas, 800);
+ mas_walk(&mas);
+ data_end = mas_data_end(&mas);
+ mas_set_range(&mas, 810, 825);
+ mas_store_gfp(&mas, NULL, GFP_KERNEL);
+ MT_BUG_ON(mt, mtree_load(mt, 809) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 810) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 825) != NULL);
+ MT_BUG_ON(mt, mtree_load(mt, 826) != NULL);
+#if CONFIG_64BIT
+ MT_BUG_ON(mt, data_end - 4 != mas_data_end(&mas));
+#endif
+ mas_unlock(&mas);
+}
+/* End of NULL area expansions */
+
+/* Checking for no memory is best done outside the kernel */
+static noinline void check_nomem(struct maple_tree *mt)
+{
+ MA_STATE(ms, mt, 1, 1);
+
+ MT_BUG_ON(mt, !mtree_empty(mt));
+ /* Ensure no bypassing of allocation failures */
+ mt_set_non_kernel(0);
+
+ /* Storing something at 1 requires memory allocation */
+ MT_BUG_ON(mt, mtree_insert(mt, 1, &ms, GFP_ATOMIC) != -ENOMEM);
+ /* Storing something at 0 does not */
+ MT_BUG_ON(mt, mtree_insert(mt, 0, &ms, GFP_ATOMIC) != 0);
+
+ /*
+ * Simulate two threads racing; the first one fails to allocate
+ * memory to insert an entry at 1, then the second one succeeds
+ * in allocating memory to insert an entry at 2. The first one
+ * then needs to free the node it allocated. LeakSanitizer will
+ * notice this, as will the 'nr_allocated' debugging aid in the
+ * userspace test suite.
+ */
+ mtree_lock(mt);
+ mas_store(&ms, &ms); /* insert 1 -> &ms, fails. */
+ MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM));
+ mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */
+ MT_BUG_ON(mt, ms.node != MAS_START);
+ mtree_unlock(mt);
+ MT_BUG_ON(mt, mtree_insert(mt, 2, mt, GFP_KERNEL) != 0);
+ mtree_lock(mt);
+ mas_store(&ms, &ms); /* insert 1 -> &ms */
+ mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */
+ mtree_unlock(mt);
+ mtree_destroy(mt);
+}
+
+static noinline void check_locky(struct maple_tree *mt)
+{
+ MA_STATE(ms, mt, 2, 2);
+ MA_STATE(reader, mt, 2, 2);
+
+ mt_set_non_kernel(2);
+ mt_set_in_rcu(mt);
+ mas_lock(&ms);
+ mas_store(&ms, &ms);
+ mas_set_range(&ms, 1, 3);
+ mas_store(&ms, &reader);
+ mas_unlock(&ms);
+ mt_clear_in_rcu(mt);
+}
+
+extern void test_kmem_cache_bulk(void);
+
void farmer_tests(void)
{
struct maple_node *node;
@@ -39,6 +35756,59 @@ void farmer_tests(void)
mt_dump(&tree);
ma_free_rcu(node);
+
+ /* Check things that will make lockdep angry */
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_locky(&tree);
+ mtree_destroy(&tree);
+ test_kmem_cache_bulk();
+
+ mt_init_flags(&tree, 0);
+ check_dfs_preorder(&tree);
+ mtree_destroy(&tree);
+
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_prealloc(&tree);
+ mtree_destroy(&tree);
+
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_spanning_write(&tree);
+ mtree_destroy(&tree);
+
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_null_expand(&tree);
+ mtree_destroy(&tree);
+
+ /* RCU testing */
+ mt_init_flags(&tree, 0);
+ check_erase_testset(&tree);
+ mtree_destroy(&tree);
+
+ mt_init_flags(&tree, 0);
+ check_new_node(&tree);
+ mtree_destroy(&tree);
+
+ if (!MAPLE_32BIT) {
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_rcu_simulated(&tree);
+ mtree_destroy(&tree);
+
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_rcu_threaded(&tree);
+ mtree_destroy(&tree);
+ }
+
+
+#if defined(CONFIG_64BIT)
+ /* Captures from VMs that found previous errors */
+ mt_init_flags(&tree, 0);
+ check_erase2_sets(&tree);
+ mtree_destroy(&tree);
+#endif
+
+
+ /* No memory handling */
+ check_nomem(&tree);
}
void maple_tree_tests(void)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index f07aef7c592c..bc63c69e4a5e 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -74,6 +74,7 @@ TARGETS += sync
TARGETS += syscall_user_dispatch
TARGETS += sysctl
TARGETS += tc-testing
+TARGETS += tdx
TARGETS += timens
ifneq (1, $(quicktest))
TARGETS += timers
diff --git a/tools/testing/selftests/alsa/.gitignore b/tools/testing/selftests/alsa/.gitignore
index 3bb7c41266a8..2b0d11797f25 100644
--- a/tools/testing/selftests/alsa/.gitignore
+++ b/tools/testing/selftests/alsa/.gitignore
@@ -1 +1,2 @@
mixer-test
+pcm-test
diff --git a/tools/testing/selftests/alsa/Makefile b/tools/testing/selftests/alsa/Makefile
index fd8ddce2b1a6..a8c0383878d3 100644
--- a/tools/testing/selftests/alsa/Makefile
+++ b/tools/testing/selftests/alsa/Makefile
@@ -6,7 +6,20 @@ LDLIBS += $(shell pkg-config --libs alsa)
ifeq ($(LDLIBS),)
LDLIBS += -lasound
endif
+CFLAGS += -L$(OUTPUT) -Wl,-rpath=./
-TEST_GEN_PROGS := mixer-test
+OVERRIDE_TARGETS = 1
+
+TEST_GEN_PROGS := mixer-test pcm-test
+
+TEST_GEN_PROGS_EXTENDED := libatest.so
+
+TEST_FILES := conf.d
include ../lib.mk
+
+$(OUTPUT)/libatest.so: conf.c alsa-local.h
+ $(CC) $(CFLAGS) -shared -fPIC $< $(LDLIBS) -o $@
+
+$(OUTPUT)/%: %.c $(TEST_GEN_PROGS_EXTENDED) alsa-local.h
+ $(CC) $(CFLAGS) $< $(LDLIBS) -latest -o $@
diff --git a/tools/testing/selftests/alsa/alsa-local.h b/tools/testing/selftests/alsa/alsa-local.h
new file mode 100644
index 000000000000..65f197ea9773
--- /dev/null
+++ b/tools/testing/selftests/alsa/alsa-local.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// kselftest configuration helpers for the hw specific configuration
+//
+// Original author: Jaroslav Kysela <perex@perex.cz>
+// Copyright (c) 2022 Red Hat Inc.
+
+#ifndef __ALSA_LOCAL_H
+#define __ALSA_LOCAL_H
+
+#include <alsa/asoundlib.h>
+
+snd_config_t *get_alsalib_config(void);
+
+void conf_load(void);
+void conf_free(void);
+snd_config_t *conf_by_card(int card);
+snd_config_t *conf_get_subtree(snd_config_t *root, const char *key1, const char *key2);
+int conf_get_count(snd_config_t *root, const char *key1, const char *key2);
+const char *conf_get_string(snd_config_t *root, const char *key1, const char *key2, const char *def);
+long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long def);
+int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def);
+
+#endif /* __ALSA_LOCAL_H */
diff --git a/tools/testing/selftests/alsa/conf.c b/tools/testing/selftests/alsa/conf.c
new file mode 100644
index 000000000000..c7ffc8f04195
--- /dev/null
+++ b/tools/testing/selftests/alsa/conf.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// kselftest configuration helpers for the hw specific configuration
+//
+// Original author: Jaroslav Kysela <perex@perex.cz>
+// Copyright (c) 2022 Red Hat Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+#include <dirent.h>
+#include <regex.h>
+#include <sys/stat.h>
+
+#include "../kselftest.h"
+#include "alsa-local.h"
+
+#define SYSFS_ROOT "/sys"
+
+struct card_data {
+ int card;
+ snd_config_t *config;
+ const char *filename;
+ struct card_data *next;
+};
+
+static struct card_data *conf_cards;
+
+static const char *alsa_config =
+"ctl.hw {\n"
+" @args [ CARD ]\n"
+" @args.CARD.type string\n"
+" type hw\n"
+" card $CARD\n"
+"}\n"
+"pcm.hw {\n"
+" @args [ CARD DEV SUBDEV ]\n"
+" @args.CARD.type string\n"
+" @args.DEV.type integer\n"
+" @args.SUBDEV.type integer\n"
+" type hw\n"
+" card $CARD\n"
+" device $DEV\n"
+" subdevice $SUBDEV\n"
+"}\n"
+;
+
+#ifdef SND_LIB_VER
+#if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6)
+#define LIB_HAS_LOAD_STRING
+#endif
+#endif
+
+#ifndef LIB_HAS_LOAD_STRING
+static int snd_config_load_string(snd_config_t **config, const char *s,
+ size_t size)
+{
+ snd_input_t *input;
+ snd_config_t *dst;
+ int err;
+
+ assert(config && s);
+ if (size == 0)
+ size = strlen(s);
+ err = snd_input_buffer_open(&input, s, size);
+ if (err < 0)
+ return err;
+ err = snd_config_top(&dst);
+ if (err < 0) {
+ snd_input_close(input);
+ return err;
+ }
+ err = snd_config_load(dst, input);
+ snd_input_close(input);
+ if (err < 0) {
+ snd_config_delete(dst);
+ return err;
+ }
+ *config = dst;
+ return 0;
+}
+#endif
+
+snd_config_t *get_alsalib_config(void)
+{
+ snd_config_t *config;
+ int err;
+
+ err = snd_config_load_string(&config, alsa_config, strlen(alsa_config));
+ if (err < 0) {
+ ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n",
+ snd_strerror(err));
+ ksft_exit_fail();
+ }
+ return config;
+}
+
+static struct card_data *conf_data_by_card(int card, bool msg)
+{
+ struct card_data *conf;
+
+ for (conf = conf_cards; conf; conf = conf->next) {
+ if (conf->card == card) {
+ if (msg)
+ ksft_print_msg("using hw card config %s for card %d\n",
+ conf->filename, card);
+ return conf;
+ }
+ }
+ return NULL;
+}
+
+static int dump_config_tree(snd_config_t *top)
+{
+ snd_output_t *out;
+ int err;
+
+ err = snd_output_stdio_attach(&out, stdout, 0);
+ if (err < 0)
+ ksft_exit_fail_msg("stdout attach\n");
+ if (snd_config_save(top, out))
+ ksft_exit_fail_msg("config save\n");
+ snd_output_close(out);
+}
+
+static snd_config_t *load(const char *filename)
+{
+ snd_config_t *dst;
+ snd_input_t *input;
+ int err;
+
+ err = snd_input_stdio_open(&input, filename, "r");
+ if (err < 0)
+ ksft_exit_fail_msg("Unable to parse filename %s\n", filename);
+ err = snd_config_top(&dst);
+ if (err < 0)
+ ksft_exit_fail_msg("Out of memory\n");
+ err = snd_config_load(dst, input);
+ snd_input_close(input);
+ if (err < 0)
+ ksft_exit_fail_msg("Unable to parse filename %s\n", filename);
+ return dst;
+}
+
+static char *sysfs_get(const char *sysfs_root, const char *id)
+{
+ char path[PATH_MAX], link[PATH_MAX + 1];
+ struct stat sb;
+ ssize_t len;
+ char *e;
+ int fd;
+
+ if (id[0] == '/')
+ id++;
+ snprintf(path, sizeof(path), "%s/%s", sysfs_root, id);
+ if (lstat(path, &sb) != 0)
+ return NULL;
+ if (S_ISLNK(sb.st_mode)) {
+ len = readlink(path, link, sizeof(link) - 1);
+ if (len <= 0) {
+ ksft_exit_fail_msg("sysfs: cannot read link '%s': %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
+ link[len] = '\0';
+ e = strrchr(link, '/');
+ if (e)
+ return strdup(e + 1);
+ return NULL;
+ }
+ if (S_ISDIR(sb.st_mode))
+ return NULL;
+ if ((sb.st_mode & S_IRUSR) == 0)
+ return NULL;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return NULL;
+ ksft_exit_fail_msg("sysfs: open failed for '%s': %s\n",
+ path, strerror(errno));
+ }
+ len = read(fd, path, sizeof(path)-1);
+ close(fd);
+ if (len < 0)
+ ksft_exit_fail_msg("sysfs: unable to read value '%s': %s\n",
+ path, errno);
+ while (len > 0 && path[len-1] == '\n')
+ len--;
+ path[len] = '\0';
+ e = strdup(path);
+ if (e == NULL)
+ ksft_exit_fail_msg("Out of memory\n");
+ return e;
+}
+
+static bool sysfs_match(const char *sysfs_root, snd_config_t *config)
+{
+ snd_config_t *node, *path_config, *regex_config;
+ snd_config_iterator_t i, next;
+ const char *path_string, *regex_string, *v;
+ regex_t re;
+ regmatch_t match[1];
+ int iter = 0, ret;
+
+ snd_config_for_each(i, next, config) {
+ node = snd_config_iterator_entry(i);
+ if (snd_config_search(node, "path", &path_config))
+ ksft_exit_fail_msg("Missing path field in the sysfs block\n");
+ if (snd_config_search(node, "regex", &regex_config))
+ ksft_exit_fail_msg("Missing regex field in the sysfs block\n");
+ if (snd_config_get_string(path_config, &path_string))
+ ksft_exit_fail_msg("Path field in the sysfs block is not a string\n");
+ if (snd_config_get_string(regex_config, &regex_string))
+ ksft_exit_fail_msg("Regex field in the sysfs block is not a string\n");
+ iter++;
+ v = sysfs_get(sysfs_root, path_string);
+ if (!v)
+ return false;
+ if (regcomp(&re, regex_string, REG_EXTENDED))
+ ksft_exit_fail_msg("Wrong regex '%s'\n", regex_string);
+ ret = regexec(&re, v, 1, match, 0);
+ regfree(&re);
+ if (ret)
+ return false;
+ }
+ return iter > 0;
+}
+
+static bool test_filename1(int card, const char *filename, const char *sysfs_card_root)
+{
+ struct card_data *data, *data2;
+ snd_config_t *config, *sysfs_config, *card_config, *sysfs_card_config, *node;
+ snd_config_iterator_t i, next;
+
+ config = load(filename);
+ if (snd_config_search(config, "sysfs", &sysfs_config) ||
+ snd_config_get_type(sysfs_config) != SND_CONFIG_TYPE_COMPOUND)
+ ksft_exit_fail_msg("Missing global sysfs block in filename %s\n", filename);
+ if (snd_config_search(config, "card", &card_config) ||
+ snd_config_get_type(card_config) != SND_CONFIG_TYPE_COMPOUND)
+ ksft_exit_fail_msg("Missing global card block in filename %s\n", filename);
+ if (!sysfs_match(SYSFS_ROOT, sysfs_config))
+ return false;
+ snd_config_for_each(i, next, card_config) {
+ node = snd_config_iterator_entry(i);
+ if (snd_config_search(node, "sysfs", &sysfs_card_config) ||
+ snd_config_get_type(sysfs_card_config) != SND_CONFIG_TYPE_COMPOUND)
+ ksft_exit_fail_msg("Missing card sysfs block in filename %s\n", filename);
+ if (!sysfs_match(sysfs_card_root, sysfs_card_config))
+ continue;
+ data = malloc(sizeof(*data));
+ if (!data)
+ ksft_exit_fail_msg("Out of memory\n");
+ data2 = conf_data_by_card(card, false);
+ if (data2)
+ ksft_exit_fail_msg("Duplicate card '%s' <-> '%s'\n", filename, data2->filename);
+ data->card = card;
+ data->filename = filename;
+ data->config = node;
+ data->next = conf_cards;
+ conf_cards = data;
+ return true;
+ }
+ return false;
+}
+
+static bool test_filename(const char *filename)
+{
+ char fn[128];
+ int card;
+
+ for (card = 0; card < 32; card++) {
+ snprintf(fn, sizeof(fn), "%s/class/sound/card%d", SYSFS_ROOT, card);
+ if (access(fn, R_OK) == 0 && test_filename1(card, filename, fn))
+ return true;
+ }
+ return false;
+}
+
+static int filename_filter(const struct dirent *dirent)
+{
+ size_t flen;
+
+ if (dirent == NULL)
+ return 0;
+ if (dirent->d_type == DT_DIR)
+ return 0;
+ flen = strlen(dirent->d_name);
+ if (flen <= 5)
+ return 0;
+ if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
+ return 1;
+ return 0;
+}
+
+void conf_load(void)
+{
+ const char *fn = "conf.d";
+ struct dirent **namelist;
+ int n, j;
+
+ n = scandir(fn, &namelist, filename_filter, alphasort);
+ if (n < 0)
+ ksft_exit_fail_msg("scandir: %s\n", strerror(errno));
+ for (j = 0; j < n; j++) {
+ size_t sl = strlen(fn) + strlen(namelist[j]->d_name) + 2;
+ char *filename = malloc(sl);
+ if (filename == NULL)
+ ksft_exit_fail_msg("Out of memory\n");
+ sprintf(filename, "%s/%s", fn, namelist[j]->d_name);
+ if (test_filename(filename))
+ filename = NULL;
+ free(filename);
+ free(namelist[j]);
+ }
+ free(namelist);
+}
+
+void conf_free(void)
+{
+ struct card_data *conf;
+
+ while (conf_cards) {
+ conf = conf_cards;
+ conf_cards = conf->next;
+ snd_config_delete(conf->config);
+ }
+}
+
+snd_config_t *conf_by_card(int card)
+{
+ struct card_data *conf;
+
+ conf = conf_data_by_card(card, true);
+ if (conf)
+ return conf->config;
+ return NULL;
+}
+
+static int conf_get_by_keys(snd_config_t *root, const char *key1,
+ const char *key2, snd_config_t **result)
+{
+ int ret;
+
+ if (key1) {
+ ret = snd_config_search(root, key1, &root);
+ if (ret != -ENOENT && ret < 0)
+ return ret;
+ }
+ if (key2)
+ ret = snd_config_search(root, key2, &root);
+ if (ret >= 0)
+ *result = root;
+ return ret;
+}
+
+snd_config_t *conf_get_subtree(snd_config_t *root, const char *key1, const char *key2)
+{
+ int ret;
+
+ if (!root)
+ return NULL;
+ ret = conf_get_by_keys(root, key1, key2, &root);
+ if (ret == -ENOENT)
+ return NULL;
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
+ return root;
+}
+
+int conf_get_count(snd_config_t *root, const char *key1, const char *key2)
+{
+ snd_config_t *cfg;
+ snd_config_iterator_t i, next;
+ int count, ret;
+
+ if (!root)
+ return -1;
+ ret = conf_get_by_keys(root, key1, key2, &cfg);
+ if (ret == -ENOENT)
+ return -1;
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND)
+ ksft_exit_fail_msg("key '%s'.'%s' is not a compound\n", key1, key2);
+ count = 0;
+ snd_config_for_each(i, next, cfg)
+ count++;
+ return count;
+}
+
+const char *conf_get_string(snd_config_t *root, const char *key1, const char *key2, const char *def)
+{
+ snd_config_t *cfg;
+ const char *s;
+ int ret;
+
+ if (!root)
+ return def;
+ ret = conf_get_by_keys(root, key1, key2, &cfg);
+ if (ret == -ENOENT)
+ return def;
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
+ if (snd_config_get_string(cfg, &s))
+ ksft_exit_fail_msg("key '%s'.'%s' is not a string\n", key1, key2);
+ return s;
+}
+
+long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long def)
+{
+ snd_config_t *cfg;
+ long l;
+ int ret;
+
+ if (!root)
+ return def;
+ ret = conf_get_by_keys(root, key1, key2, &cfg);
+ if (ret == -ENOENT)
+ return def;
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
+ if (snd_config_get_integer(cfg, &l))
+ ksft_exit_fail_msg("key '%s'.'%s' is not an integer\n", key1, key2);
+ return l;
+}
+
+int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def)
+{
+ snd_config_t *cfg;
+ long l;
+ int ret;
+
+ if (!root)
+ return def;
+ ret = conf_get_by_keys(root, key1, key2, &cfg);
+ if (ret == -ENOENT)
+ return def;
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
+ ret = snd_config_get_bool(cfg);
+ if (ret < 0)
+ ksft_exit_fail_msg("key '%s'.'%s' is not an bool\n", key1, key2);
+ return !!ret;
+}
diff --git a/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf b/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf
new file mode 100644
index 000000000000..9eca985e0c08
--- /dev/null
+++ b/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf
@@ -0,0 +1,79 @@
+#
+# Example configuration for Lenovo ThinkPad P1 Gen2
+#
+
+#
+# Use regex match for the string read from the given sysfs path
+#
+# The sysfs root directory (/sys) is hardwired in the test code
+# (may be changed on demand).
+#
+# All strings must match.
+#
+sysfs [
+ {
+ path "class/dmi/id/product_sku"
+ regex "LENOVO_MT_20QU_BU_Think_FM_ThinkPad P1 Gen 2"
+ }
+]
+
+card.hda {
+ #
+ # Use regex match for the /sys/class/sound/card*/ tree (relative)
+ #
+ sysfs [
+ {
+ path "device/subsystem_device"
+ regex "0x229e"
+ }
+ {
+ path "device/subsystem_vendor"
+ regex "0x17aa"
+ }
+ ]
+
+ #
+ # PCM configuration
+ #
+ # pcm.0.0 - device 0 subdevice 0
+ #
+ pcm.0.0 {
+ PLAYBACK {
+ #
+ # Uncomment to override values for specific tests
+ #
+ #test_name1 {
+ # access RW_INTERLEAVED
+ # format S16_LE
+ # rate 48000
+ # channels 2
+ # period_size 512
+ # buffer_size 4096
+ #}
+ #test_name2 {
+ # access RW_INTERLEAVED
+ # format S16_LE
+ # rate 48000
+ # channels 2
+ # period_size 24000
+ # buffer_size 192000
+ #}
+ }
+ CAPTURE {
+ # use default tests, check for the presence
+ }
+ }
+ #
+ # uncomment to force the missing device checks
+ #
+ #pcm.0.2 {
+ # PLAYBACK {
+ # # check for the presence
+ # }
+ #}
+ #pcm.0.3 {
+ # CAPTURE {
+ # # check for the presence
+ # }
+ #}
+}
diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c
index a38b89c28030..05f1749ae19d 100644
--- a/tools/testing/selftests/alsa/mixer-test.c
+++ b/tools/testing/selftests/alsa/mixer-test.c
@@ -26,6 +26,7 @@
#include <stdint.h>
#include "../kselftest.h"
+#include "alsa-local.h"
#define TESTS_PER_CONTROL 7
@@ -50,56 +51,11 @@ struct ctl_data {
struct ctl_data *next;
};
-static const char *alsa_config =
-"ctl.hw {\n"
-" @args [ CARD ]\n"
-" @args.CARD.type string\n"
-" type hw\n"
-" card $CARD\n"
-"}\n"
-;
-
int num_cards = 0;
int num_controls = 0;
struct card_data *card_list = NULL;
struct ctl_data *ctl_list = NULL;
-#ifdef SND_LIB_VER
-#if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6)
-#define LIB_HAS_LOAD_STRING
-#endif
-#endif
-
-#ifndef LIB_HAS_LOAD_STRING
-static int snd_config_load_string(snd_config_t **config, const char *s,
- size_t size)
-{
- snd_input_t *input;
- snd_config_t *dst;
- int err;
-
- assert(config && s);
- if (size == 0)
- size = strlen(s);
- err = snd_input_buffer_open(&input, s, size);
- if (err < 0)
- return err;
- err = snd_config_top(&dst);
- if (err < 0) {
- snd_input_close(input);
- return err;
- }
- err = snd_config_load(dst, input);
- snd_input_close(input);
- if (err < 0) {
- snd_config_delete(dst);
- return err;
- }
- *config = dst;
- return 0;
-}
-#endif
-
static void find_controls(void)
{
char name[32];
@@ -112,12 +68,7 @@ static void find_controls(void)
if (snd_card_next(&card) < 0 || card < 0)
return;
- err = snd_config_load_string(&config, alsa_config, strlen(alsa_config));
- if (err < 0) {
- ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n",
- snd_strerror(err));
- ksft_exit_fail();
- }
+ config = get_alsalib_config();
while (card >= 0) {
sprintf(name, "hw:%d", card);
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c
new file mode 100644
index 000000000000..f293c7d81009
--- /dev/null
+++ b/tools/testing/selftests/alsa/pcm-test.c
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// kselftest for the ALSA PCM API
+//
+// Original author: Jaroslav Kysela <perex@perex.cz>
+// Copyright (c) 2022 Red Hat Inc.
+
+// This test will iterate over all cards detected in the system, exercising
+// every PCM device it can find. This may conflict with other system
+// software if there is audio activity so is best run on a system with a
+// minimal active userspace.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "../kselftest.h"
+#include "alsa-local.h"
+
+typedef struct timespec timestamp_t;
+
+struct pcm_data {
+ snd_pcm_t *handle;
+ int card;
+ int device;
+ int subdevice;
+ snd_pcm_stream_t stream;
+ snd_config_t *pcm_config;
+ struct pcm_data *next;
+};
+
+int num_pcms = 0;
+struct pcm_data *pcm_list = NULL;
+
+int num_missing = 0;
+struct pcm_data *pcm_missing = NULL;
+
+struct time_test_def {
+ const char *cfg_prefix;
+ const char *format;
+ long rate;
+ long channels;
+ long period_size;
+ long buffer_size;
+};
+
+void timestamp_now(timestamp_t *tstamp)
+{
+ if (clock_gettime(CLOCK_MONOTONIC_RAW, tstamp))
+ ksft_exit_fail_msg("clock_get_time\n");
+}
+
+long long timestamp_diff_ms(timestamp_t *tstamp)
+{
+ timestamp_t now, diff;
+ timestamp_now(&now);
+ if (tstamp->tv_nsec > now.tv_nsec) {
+ diff.tv_sec = now.tv_sec - tstamp->tv_sec - 1;
+ diff.tv_nsec = (now.tv_nsec + 1000000000L) - tstamp->tv_nsec;
+ } else {
+ diff.tv_sec = now.tv_sec - tstamp->tv_sec;
+ diff.tv_nsec = now.tv_nsec - tstamp->tv_nsec;
+ }
+ return (diff.tv_sec * 1000) + ((diff.tv_nsec + 500000L) / 1000000L);
+}
+
+static long device_from_id(snd_config_t *node)
+{
+ const char *id;
+ char *end;
+ long v;
+
+ if (snd_config_get_id(node, &id))
+ ksft_exit_fail_msg("snd_config_get_id\n");
+ errno = 0;
+ v = strtol(id, &end, 10);
+ if (errno || *end)
+ return -1;
+ return v;
+}
+
+static void missing_device(int card, int device, int subdevice, snd_pcm_stream_t stream)
+{
+ struct pcm_data *pcm_data;
+
+ for (pcm_data = pcm_list; pcm_data != NULL; pcm_data = pcm_data->next) {
+ if (pcm_data->card != card)
+ continue;
+ if (pcm_data->device != device)
+ continue;
+ if (pcm_data->subdevice != subdevice)
+ continue;
+ if (pcm_data->stream != stream)
+ continue;
+ return;
+ }
+ pcm_data = calloc(1, sizeof(*pcm_data));
+ if (!pcm_data)
+ ksft_exit_fail_msg("Out of memory\n");
+ pcm_data->card = card;
+ pcm_data->device = device;
+ pcm_data->subdevice = subdevice;
+ pcm_data->stream = stream;
+ pcm_data->next = pcm_missing;
+ pcm_missing = pcm_data;
+ num_missing++;
+}
+
+static void missing_devices(int card, snd_config_t *card_config)
+{
+ snd_config_t *pcm_config, *node1, *node2;
+ snd_config_iterator_t i1, i2, next1, next2;
+ int device, subdevice;
+
+ pcm_config = conf_get_subtree(card_config, "pcm", NULL);
+ if (!pcm_config)
+ return;
+ snd_config_for_each(i1, next1, pcm_config) {
+ node1 = snd_config_iterator_entry(i1);
+ device = device_from_id(node1);
+ if (device < 0)
+ continue;
+ if (snd_config_get_type(node1) != SND_CONFIG_TYPE_COMPOUND)
+ continue;
+ snd_config_for_each(i2, next2, node1) {
+ node2 = snd_config_iterator_entry(i2);
+ subdevice = device_from_id(node2);
+ if (subdevice < 0)
+ continue;
+ if (conf_get_subtree(node2, "PLAYBACK", NULL))
+ missing_device(card, device, subdevice, SND_PCM_STREAM_PLAYBACK);
+ if (conf_get_subtree(node2, "CAPTURE", NULL))
+ missing_device(card, device, subdevice, SND_PCM_STREAM_CAPTURE);
+ }
+ }
+}
+
+static void find_pcms(void)
+{
+ char name[32], key[64];
+ int card, dev, subdev, count, direction, err;
+ snd_pcm_stream_t stream;
+ struct pcm_data *pcm_data;
+ snd_ctl_t *handle;
+ snd_pcm_info_t *pcm_info;
+ snd_config_t *config, *card_config, *pcm_config;
+
+ snd_pcm_info_alloca(&pcm_info);
+
+ card = -1;
+ if (snd_card_next(&card) < 0 || card < 0)
+ return;
+
+ config = get_alsalib_config();
+
+ while (card >= 0) {
+ sprintf(name, "hw:%d", card);
+
+ err = snd_ctl_open_lconf(&handle, name, 0, config);
+ if (err < 0) {
+ ksft_print_msg("Failed to get hctl for card %d: %s\n",
+ card, snd_strerror(err));
+ goto next_card;
+ }
+
+ card_config = conf_by_card(card);
+
+ dev = -1;
+ while (1) {
+ if (snd_ctl_pcm_next_device(handle, &dev) < 0)
+ ksft_exit_fail_msg("snd_ctl_pcm_next_device\n");
+ if (dev < 0)
+ break;
+
+ for (direction = 0; direction < 2; direction++) {
+ stream = direction ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK;
+ sprintf(key, "pcm.%d.%s", dev, snd_pcm_stream_name(stream));
+ pcm_config = conf_get_subtree(card_config, key, NULL);
+ if (conf_get_bool(card_config, key, "skip", false)) {
+ ksft_print_msg("skipping pcm %d.%d.%s\n", card, dev, snd_pcm_stream_name(stream));
+ continue;
+ }
+ snd_pcm_info_set_device(pcm_info, dev);
+ snd_pcm_info_set_subdevice(pcm_info, 0);
+ snd_pcm_info_set_stream(pcm_info, stream);
+ err = snd_ctl_pcm_info(handle, pcm_info);
+ if (err == -ENOENT)
+ continue;
+ if (err < 0)
+ ksft_exit_fail_msg("snd_ctl_pcm_info: %d:%d:%d\n",
+ dev, 0, stream);
+ count = snd_pcm_info_get_subdevices_count(pcm_info);
+ for (subdev = 0; subdev < count; subdev++) {
+ sprintf(key, "pcm.%d.%d.%s", dev, subdev, snd_pcm_stream_name(stream));
+ if (conf_get_bool(card_config, key, "skip", false)) {
+ ksft_print_msg("skipping pcm %d.%d.%d.%s\n", card, dev,
+ subdev, snd_pcm_stream_name(stream));
+ continue;
+ }
+ pcm_data = calloc(1, sizeof(*pcm_data));
+ if (!pcm_data)
+ ksft_exit_fail_msg("Out of memory\n");
+ pcm_data->card = card;
+ pcm_data->device = dev;
+ pcm_data->subdevice = subdev;
+ pcm_data->stream = stream;
+ pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL);
+ pcm_data->next = pcm_list;
+ pcm_list = pcm_data;
+ num_pcms++;
+ }
+ }
+ }
+
+ /* check for missing devices */
+ missing_devices(card, card_config);
+
+ next_card:
+ snd_ctl_close(handle);
+ if (snd_card_next(&card) < 0) {
+ ksft_print_msg("snd_card_next");
+ break;
+ }
+ }
+
+ snd_config_delete(config);
+}
+
+static void test_pcm_time1(struct pcm_data *data,
+ const struct time_test_def *test)
+{
+ char name[64], key[128], msg[256];
+ const char *cs;
+ int i, err;
+ snd_pcm_t *handle = NULL;
+ snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ snd_pcm_format_t format;
+ unsigned char *samples = NULL;
+ snd_pcm_sframes_t frames;
+ long long ms;
+ long rate, channels, period_size, buffer_size;
+ unsigned int rchannels;
+ unsigned int rrate;
+ snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold;
+ timestamp_t tstamp;
+ bool pass = false, automatic = true;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_sw_params_t *sw_params;
+ bool skip = false;
+
+ snd_pcm_hw_params_alloca(&hw_params);
+ snd_pcm_sw_params_alloca(&sw_params);
+
+ cs = conf_get_string(data->pcm_config, test->cfg_prefix, "format", test->format);
+ format = snd_pcm_format_value(cs);
+ if (format == SND_PCM_FORMAT_UNKNOWN)
+ ksft_exit_fail_msg("Wrong format '%s'\n", cs);
+ rate = conf_get_long(data->pcm_config, test->cfg_prefix, "rate", test->rate);
+ channels = conf_get_long(data->pcm_config, test->cfg_prefix, "channels", test->channels);
+ period_size = conf_get_long(data->pcm_config, test->cfg_prefix, "period_size", test->period_size);
+ buffer_size = conf_get_long(data->pcm_config, test->cfg_prefix, "buffer_size", test->buffer_size);
+
+ automatic = strcmp(test->format, snd_pcm_format_name(format)) == 0 &&
+ test->rate == rate &&
+ test->channels == channels &&
+ test->period_size == period_size &&
+ test->buffer_size == buffer_size;
+
+ samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8);
+ if (!samples)
+ ksft_exit_fail_msg("Out of memory\n");
+ snd_pcm_format_set_silence(format, samples, rate * channels);
+
+ sprintf(name, "hw:%d,%d,%d", data->card, data->device, data->subdevice);
+ err = snd_pcm_open(&handle, name, data->stream, 0);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "Failed to get pcm handle: %s", snd_strerror(err));
+ goto __close;
+ }
+
+ err = snd_pcm_hw_params_any(handle, hw_params);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_any: %s", snd_strerror(err));
+ goto __close;
+ }
+ err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate_resample: %s", snd_strerror(err));
+ goto __close;
+ }
+ err = snd_pcm_hw_params_set_access(handle, hw_params, access);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_access %s: %s",
+ snd_pcm_access_name(access), snd_strerror(err));
+ goto __close;
+ }
+__format:
+ err = snd_pcm_hw_params_set_format(handle, hw_params, format);
+ if (err < 0) {
+ if (automatic && format == SND_PCM_FORMAT_S16_LE) {
+ format = SND_PCM_FORMAT_S32_LE;
+ ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n",
+ test->cfg_prefix,
+ data->card, data->device, data->subdevice,
+ snd_pcm_stream_name(data->stream),
+ snd_pcm_access_name(access));
+ }
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s",
+ snd_pcm_format_name(format), snd_strerror(err));
+ goto __close;
+ }
+ rchannels = channels;
+ err = snd_pcm_hw_params_set_channels_near(handle, hw_params, &rchannels);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_channels %ld: %s", channels, snd_strerror(err));
+ goto __close;
+ }
+ if (rchannels != channels) {
+ snprintf(msg, sizeof(msg), "channels unsupported %ld != %ld", channels, rchannels);
+ skip = true;
+ goto __close;
+ }
+ rrate = rate;
+ err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate %ld: %s", rate, snd_strerror(err));
+ goto __close;
+ }
+ if (rrate != rate) {
+ snprintf(msg, sizeof(msg), "rate unsupported %ld != %ld", rate, rrate);
+ skip = true;
+ goto __close;
+ }
+ rperiod_size = period_size;
+ err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &rperiod_size, 0);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_period_size %ld: %s", period_size, snd_strerror(err));
+ goto __close;
+ }
+ rbuffer_size = buffer_size;
+ err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &rbuffer_size);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_buffer_size %ld: %s", buffer_size, snd_strerror(err));
+ goto __close;
+ }
+ err = snd_pcm_hw_params(handle, hw_params);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_hw_params: %s", snd_strerror(err));
+ goto __close;
+ }
+
+ err = snd_pcm_sw_params_current(handle, sw_params);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_sw_params_current: %s", snd_strerror(err));
+ goto __close;
+ }
+ if (data->stream == SND_PCM_STREAM_PLAYBACK) {
+ start_threshold = (rbuffer_size / rperiod_size) * rperiod_size;
+ } else {
+ start_threshold = rperiod_size;
+ }
+ err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, start_threshold);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_start_threshold %ld: %s", (long)start_threshold, snd_strerror(err));
+ goto __close;
+ }
+ err = snd_pcm_sw_params_set_avail_min(handle, sw_params, rperiod_size);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_avail_min %ld: %s", (long)rperiod_size, snd_strerror(err));
+ goto __close;
+ }
+ err = snd_pcm_sw_params(handle, sw_params);
+ if (err < 0) {
+ snprintf(msg, sizeof(msg), "snd_pcm_sw_params: %s", snd_strerror(err));
+ goto __close;
+ }
+
+ ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
+ test->cfg_prefix,
+ data->card, data->device, data->subdevice,
+ snd_pcm_stream_name(data->stream),
+ snd_pcm_access_name(access),
+ snd_pcm_format_name(format),
+ (long)rate, (long)channels,
+ (long)rperiod_size, (long)rbuffer_size,
+ (long)start_threshold);
+
+ timestamp_now(&tstamp);
+ for (i = 0; i < 4; i++) {
+ if (data->stream == SND_PCM_STREAM_PLAYBACK) {
+ frames = snd_pcm_writei(handle, samples, rate);
+ if (frames < 0) {
+ snprintf(msg, sizeof(msg),
+ "Write failed: expected %d, wrote %li", rate, frames);
+ goto __close;
+ }
+ if (frames < rate) {
+ snprintf(msg, sizeof(msg),
+ "expected %d, wrote %li", rate, frames);
+ goto __close;
+ }
+ } else {
+ frames = snd_pcm_readi(handle, samples, rate);
+ if (frames < 0) {
+ snprintf(msg, sizeof(msg),
+ "expected %d, wrote %li", rate, frames);
+ goto __close;
+ }
+ if (frames < rate) {
+ snprintf(msg, sizeof(msg),
+ "expected %d, wrote %li", rate, frames);
+ goto __close;
+ }
+ }
+ }
+
+ snd_pcm_drain(handle);
+ ms = timestamp_diff_ms(&tstamp);
+ if (ms < 3900 || ms > 4100) {
+ snprintf(msg, sizeof(msg), "time mismatch: expected 4000ms got %lld", ms);
+ goto __close;
+ }
+
+ msg[0] = '\0';
+ pass = true;
+__close:
+ if (!skip) {
+ ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n",
+ test->cfg_prefix,
+ data->card, data->device, data->subdevice,
+ snd_pcm_stream_name(data->stream),
+ msg[0] ? " " : "", msg);
+ } else {
+ ksft_test_result_skip("%s.%d.%d.%d.%s%s%s\n",
+ test->cfg_prefix,
+ data->card, data->device,
+ data->subdevice,
+ snd_pcm_stream_name(data->stream),
+ msg[0] ? " " : "", msg);
+ }
+ free(samples);
+ if (handle)
+ snd_pcm_close(handle);
+}
+
+static const struct time_test_def time_tests[] = {
+ /* name format rate chan period buffer */
+ { "8k.1.big", "S16_LE", 8000, 2, 8000, 32000 },
+ { "8k.2.big", "S16_LE", 8000, 2, 8000, 32000 },
+ { "44k1.2.big", "S16_LE", 44100, 2, 22050, 192000 },
+ { "48k.2.small", "S16_LE", 48000, 2, 512, 4096 },
+ { "48k.2.big", "S16_LE", 48000, 2, 24000, 192000 },
+ { "48k.6.big", "S16_LE", 48000, 6, 48000, 576000 },
+ { "96k.2.big", "S16_LE", 96000, 2, 48000, 192000 },
+};
+
+int main(void)
+{
+ struct pcm_data *pcm;
+ int i;
+
+ ksft_print_header();
+
+ conf_load();
+
+ find_pcms();
+
+ ksft_set_plan(num_missing + num_pcms * ARRAY_SIZE(time_tests));
+
+ for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) {
+ ksft_test_result(false, "test.missing.%d.%d.%d.%s\n",
+ pcm->card, pcm->device, pcm->subdevice,
+ snd_pcm_stream_name(pcm->stream));
+ }
+
+ for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
+ for (i = 0; i < ARRAY_SIZE(time_tests); i++) {
+ test_pcm_time1(pcm, &time_tests[i]);
+ }
+ }
+
+ conf_free();
+
+ ksft_exit_pass();
+
+ return 0;
+}
diff --git a/tools/testing/selftests/amd-pstate/Makefile b/tools/testing/selftests/amd-pstate/Makefile
index 199867f44b32..5f195ee756d6 100644
--- a/tools/testing/selftests/amd-pstate/Makefile
+++ b/tools/testing/selftests/amd-pstate/Makefile
@@ -4,6 +4,15 @@
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
all:
-TEST_PROGS := amd-pstate-ut.sh
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
+
+ifeq (x86,$(ARCH))
+TEST_GEN_FILES += ../../../power/x86/amd_pstate_tracer/amd_pstate_trace.py
+TEST_GEN_FILES += ../../../power/x86/intel_pstate_tracer/intel_pstate_tracer.py
+endif
+
+TEST_PROGS := run.sh
+TEST_FILES := basic.sh tbench.sh gitsource.sh
include ../lib.mk
diff --git a/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh b/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh
deleted file mode 100755
index f8e82d91ffcf..000000000000
--- a/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-# amd-pstate-ut is a test module for testing the amd-pstate driver.
-# It can only run on x86 architectures and current cpufreq driver
-# must be amd-pstate.
-# (1) It can help all users to verify their processor support
-# (SBIOS/Firmware or Hardware).
-# (2) Kernel can have a basic function test to avoid the kernel
-# regression during the update.
-# (3) We can introduce more functional or performance tests to align
-# the result together, it will benefit power and performance scale optimization.
-
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
-# amd-pstate-ut only run on x86/x86_64 AMD systems.
-ARCH=$(uname -m 2>/dev/null | sed -e 's/i.86/x86/' -e 's/x86_64/x86/')
-VENDOR=$(cat /proc/cpuinfo | grep -m 1 'vendor_id' | awk '{print $NF}')
-
-if ! echo "$ARCH" | grep -q x86; then
- echo "$0 # Skipped: Test can only run on x86 architectures."
- exit $ksft_skip
-fi
-
-if ! echo "$VENDOR" | grep -iq amd; then
- echo "$0 # Skipped: Test can only run on AMD CPU."
- echo "$0 # Current cpu vendor is $VENDOR."
- exit $ksft_skip
-fi
-
-scaling_driver=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_driver)
-if [ "$scaling_driver" != "amd-pstate" ]; then
- echo "$0 # Skipped: Test can only run on amd-pstate driver."
- echo "$0 # Please set X86_AMD_PSTATE enabled."
- echo "$0 # Current cpufreq scaling drvier is $scaling_driver."
- exit $ksft_skip
-fi
-
-msg="Skip all tests:"
-if [ ! -w /dev ]; then
- echo $msg please run this as root >&2
- exit $ksft_skip
-fi
-
-if ! /sbin/modprobe -q -n amd-pstate-ut; then
- echo "amd-pstate-ut: module amd-pstate-ut is not found [SKIP]"
- exit $ksft_skip
-fi
-if /sbin/modprobe -q amd-pstate-ut; then
- /sbin/modprobe -q -r amd-pstate-ut
- echo "amd-pstate-ut: ok"
-else
- echo "amd-pstate-ut: [FAIL]"
- exit 1
-fi
diff --git a/tools/testing/selftests/amd-pstate/basic.sh b/tools/testing/selftests/amd-pstate/basic.sh
new file mode 100755
index 000000000000..e4c43193e4a3
--- /dev/null
+++ b/tools/testing/selftests/amd-pstate/basic.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# amd-pstate-ut is a test module for testing the amd-pstate driver.
+# It can only run on x86 architectures and current cpufreq driver
+# must be amd-pstate.
+# (1) It can help all users to verify their processor support
+# (SBIOS/Firmware or Hardware).
+# (2) Kernel can have a basic function test to avoid the kernel
+# regression during the update.
+# (3) We can introduce more functional or performance tests to align
+# the result together, it will benefit power and performance scale optimization.
+
+# protect against multiple inclusion
+if [ $FILE_BASIC ]; then
+ return 0
+else
+ FILE_BASIC=DONE
+fi
+
+amd_pstate_basic()
+{
+ printf "\n---------------------------------------------\n"
+ printf "*** Running AMD P-state ut ***"
+ printf "\n---------------------------------------------\n"
+
+ if ! /sbin/modprobe -q -n amd-pstate-ut; then
+ echo "amd-pstate-ut: module amd-pstate-ut is not found [SKIP]"
+ exit $ksft_skip
+ fi
+ if /sbin/modprobe -q amd-pstate-ut; then
+ /sbin/modprobe -q -r amd-pstate-ut
+ echo "amd-pstate-basic: ok"
+ else
+ echo "amd-pstate-basic: [FAIL]"
+ exit 1
+ fi
+}
diff --git a/tools/testing/selftests/amd-pstate/gitsource.sh b/tools/testing/selftests/amd-pstate/gitsource.sh
new file mode 100755
index 000000000000..dbc1fe45599d
--- /dev/null
+++ b/tools/testing/selftests/amd-pstate/gitsource.sh
@@ -0,0 +1,354 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# Testing and monitor the cpu desire performance, frequency, load,
+# power consumption and throughput etc. when this script trigger
+# gitsource test.
+# 1) Download and tar gitsource codes.
+# 2) Run gitsource benchmark on specific governors, ondemand or schedutil.
+# 3) Run tbench benchmark comparative test on acpi-cpufreq kernel driver.
+# 4) Get desire performance, frequency, load by perf.
+# 5) Get power consumption and throughput by amd_pstate_trace.py.
+# 6) Get run time by /usr/bin/time.
+# 7) Analyse test results and save it in file selftest.gitsource.csv.
+#8) Plot png images about time, energy and performance per watt for each test.
+
+# protect against multiple inclusion
+if [ $FILE_GITSOURCE ]; then
+ return 0
+else
+ FILE_GITSOURCE=DONE
+fi
+
+git_name="git-2.15.1"
+git_tar="$git_name.tar.gz"
+gitsource_url="https://github.com/git/git/archive/refs/tags/v2.15.1.tar.gz"
+gitsource_governors=("ondemand" "schedutil")
+
+# $1: governor, $2: round, $3: des-perf, $4: freq, $5: load, $6: time $7: energy, $8: PPW
+store_csv_gitsource()
+{
+ echo "$1, $2, $3, $4, $5, $6, $7, $8" | tee -a $OUTFILE_GIT.csv > /dev/null 2>&1
+}
+
+# clear some special lines
+clear_csv_gitsource()
+{
+ if [ -f $OUTFILE_GIT.csv ]; then
+ sed -i '/Comprison(%)/d' $OUTFILE_GIT.csv
+ sed -i "/$(scaling_name)/d" $OUTFILE_GIT.csv
+ fi
+}
+
+# find string $1 in file csv and get the number of lines
+get_lines_csv_gitsource()
+{
+ if [ -f $OUTFILE_GIT.csv ]; then
+ return `grep -c "$1" $OUTFILE_GIT.csv`
+ else
+ return 0
+ fi
+}
+
+pre_clear_gitsource()
+{
+ post_clear_gitsource
+ rm -rf gitsource_*.png
+ clear_csv_gitsource
+}
+
+post_clear_gitsource()
+{
+ rm -rf results/tracer-gitsource*
+ rm -rf $OUTFILE_GIT*.log
+ rm -rf $OUTFILE_GIT*.result
+}
+
+install_gitsource()
+{
+ if [ ! -d $git_name ]; then
+ printf "Download gitsource, please wait a moment ...\n\n"
+ wget -O $git_tar $gitsource_url > /dev/null 2>&1
+
+ printf "Tar gitsource ...\n\n"
+ tar -xzf $git_tar
+ fi
+}
+
+# $1: governor, $2: loop
+run_gitsource()
+{
+ echo "Launching amd pstate tracer for $1 #$2 tracer_interval: $TRACER_INTERVAL"
+ ./amd_pstate_trace.py -n tracer-gitsource-$1-$2 -i $TRACER_INTERVAL > /dev/null 2>&1 &
+
+ printf "Make and test gitsource for $1 #$2 make_cpus: $MAKE_CPUS\n"
+ cd $git_name
+ perf stat -a --per-socket -I 1000 -e power/energy-pkg/ /usr/bin/time -o ../$OUTFILE_GIT.time-gitsource-$1-$2.log make test -j$MAKE_CPUS > ../$OUTFILE_GIT-perf-$1-$2.log 2>&1
+ cd ..
+
+ for job in `jobs -p`
+ do
+ echo "Waiting for job id $job"
+ wait $job
+ done
+}
+
+# $1: governor, $2: loop
+parse_gitsource()
+{
+ awk '{print $5}' results/tracer-gitsource-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_GIT-des-perf-$1-$2.log
+ avg_des_perf=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_GIT-des-perf-$1-$2.log)
+ printf "Gitsource-$1-#$2 avg des perf: $avg_des_perf\n" | tee -a $OUTFILE_GIT.result
+
+ awk '{print $7}' results/tracer-gitsource-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_GIT-freq-$1-$2.log
+ avg_freq=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_GIT-freq-$1-$2.log)
+ printf "Gitsource-$1-#$2 avg freq: $avg_freq\n" | tee -a $OUTFILE_GIT.result
+
+ awk '{print $11}' results/tracer-gitsource-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_GIT-load-$1-$2.log
+ avg_load=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_GIT-load-$1-$2.log)
+ printf "Gitsource-$1-#$2 avg load: $avg_load\n" | tee -a $OUTFILE_GIT.result
+
+ grep user $OUTFILE_GIT.time-gitsource-$1-$2.log | awk '{print $1}' | sed -e 's/user//' > $OUTFILE_GIT-time-$1-$2.log
+ time_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_GIT-time-$1-$2.log)
+ printf "Gitsource-$1-#$2 user time(s): $time_sum\n" | tee -a $OUTFILE_GIT.result
+
+ grep Joules $OUTFILE_GIT-perf-$1-$2.log | awk '{print $4}' > $OUTFILE_GIT-energy-$1-$2.log
+ en_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_GIT-energy-$1-$2.log)
+ printf "Gitsource-$1-#$2 power consumption(J): $en_sum\n" | tee -a $OUTFILE_GIT.result
+
+ # Permance is the number of run gitsource per second, denoted 1/t, where 1 is the number of run gitsource in t
+ # senconds. It is well known that P=E/t, where P is power measured in watts(W), E is energy measured in joules(J),
+ # and t is time measured in seconds(s). This means that performance per watt becomes
+ # 1/t 1/t 1
+ # ----- = ----- = ---
+ # P E/t E
+ # with unit given by 1 per joule.
+ ppw=`echo "scale=9;1/$en_sum" | bc | awk '{printf "%.9f", $0}'`
+ printf "Gitsource-$1-#$2 performance per watt(1/J): $ppw\n" | tee -a $OUTFILE_GIT.result
+ printf "\n" | tee -a $OUTFILE_GIT.result
+
+ driver_name=`echo $(scaling_name)`
+ store_csv_gitsource "$driver_name-$1" $2 $avg_des_perf $avg_freq $avg_load $time_sum $en_sum $ppw
+}
+
+# $1: governor
+loop_gitsource()
+{
+ printf "\nGitsource total test times is $LOOP_TIMES for $1\n\n"
+ for i in `seq 1 $LOOP_TIMES`
+ do
+ run_gitsource $1 $i
+ parse_gitsource $1 $i
+ done
+}
+
+# $1: governor
+gather_gitsource()
+{
+ printf "Gitsource test result for $1 (loops:$LOOP_TIMES)" | tee -a $OUTFILE_GIT.result
+ printf "\n--------------------------------------------------\n" | tee -a $OUTFILE_GIT.result
+
+ grep "Gitsource-$1-#" $OUTFILE_GIT.result | grep "avg des perf:" | awk '{print $NF}' > $OUTFILE_GIT-des-perf-$1.log
+ avg_des_perf=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_GIT-des-perf-$1.log)
+ printf "Gitsource-$1 avg des perf: $avg_des_perf\n" | tee -a $OUTFILE_GIT.result
+
+ grep "Gitsource-$1-#" $OUTFILE_GIT.result | grep "avg freq:" | awk '{print $NF}' > $OUTFILE_GIT-freq-$1.log
+ avg_freq=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_GIT-freq-$1.log)
+ printf "Gitsource-$1 avg freq: $avg_freq\n" | tee -a $OUTFILE_GIT.result
+
+ grep "Gitsource-$1-#" $OUTFILE_GIT.result | grep "avg load:" | awk '{print $NF}' > $OUTFILE_GIT-load-$1.log
+ avg_load=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_GIT-load-$1.log)
+ printf "Gitsource-$1 avg load: $avg_load\n" | tee -a $OUTFILE_GIT.result
+
+ grep "Gitsource-$1-#" $OUTFILE_GIT.result | grep "user time(s):" | awk '{print $NF}' > $OUTFILE_GIT-time-$1.log
+ time_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_GIT-time-$1.log)
+ printf "Gitsource-$1 total user time(s): $time_sum\n" | tee -a $OUTFILE_GIT.result
+
+ avg_time=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_GIT-time-$1.log)
+ printf "Gitsource-$1 avg user times(s): $avg_time\n" | tee -a $OUTFILE_GIT.result
+
+ grep "Gitsource-$1-#" $OUTFILE_GIT.result | grep "power consumption(J):" | awk '{print $NF}' > $OUTFILE_GIT-energy-$1.log
+ en_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_GIT-energy-$1.log)
+ printf "Gitsource-$1 total power consumption(J): $en_sum\n" | tee -a $OUTFILE_GIT.result
+
+ avg_en=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_GIT-energy-$1.log)
+ printf "Gitsource-$1 avg power consumption(J): $avg_en\n" | tee -a $OUTFILE_GIT.result
+
+ # Permance is the number of run gitsource per second, denoted 1/t, where 1 is the number of run gitsource in t
+ # senconds. It is well known that P=E/t, where P is power measured in watts(W), E is energy measured in joules(J),
+ # and t is time measured in seconds(s). This means that performance per watt becomes
+ # 1/t 1/t 1
+ # ----- = ----- = ---
+ # P E/t E
+ # with unit given by 1 per joule.
+ ppw=`echo "scale=9;1/$avg_en" | bc | awk '{printf "%.9f", $0}'`
+ printf "Gitsource-$1 performance per watt(1/J): $ppw\n" | tee -a $OUTFILE_GIT.result
+ printf "\n" | tee -a $OUTFILE_GIT.result
+
+ driver_name=`echo $(scaling_name)`
+ store_csv_gitsource "$driver_name-$1" "Average" $avg_des_perf $avg_freq $avg_load $avg_time $avg_en $ppw
+}
+
+# $1: base scaling_driver $2: base governor $3: comparison scaling_driver $4: comparison governor
+__calc_comp_gitsource()
+{
+ base=`grep "$1-$2" $OUTFILE_GIT.csv | grep "Average"`
+ comp=`grep "$3-$4" $OUTFILE_GIT.csv | grep "Average"`
+
+ if [ -n "$base" -a -n "$comp" ]; then
+ printf "\n==================================================\n" | tee -a $OUTFILE_GIT.result
+ printf "Gitsource comparison $1-$2 VS $3-$4" | tee -a $OUTFILE_GIT.result
+ printf "\n==================================================\n" | tee -a $OUTFILE_GIT.result
+
+ # get the base values
+ des_perf_base=`echo "$base" | awk '{print $3}' | sed s/,//`
+ freq_base=`echo "$base" | awk '{print $4}' | sed s/,//`
+ load_base=`echo "$base" | awk '{print $5}' | sed s/,//`
+ time_base=`echo "$base" | awk '{print $6}' | sed s/,//`
+ energy_base=`echo "$base" | awk '{print $7}' | sed s/,//`
+ ppw_base=`echo "$base" | awk '{print $8}' | sed s/,//`
+
+ # get the comparison values
+ des_perf_comp=`echo "$comp" | awk '{print $3}' | sed s/,//`
+ freq_comp=`echo "$comp" | awk '{print $4}' | sed s/,//`
+ load_comp=`echo "$comp" | awk '{print $5}' | sed s/,//`
+ time_comp=`echo "$comp" | awk '{print $6}' | sed s/,//`
+ energy_comp=`echo "$comp" | awk '{print $7}' | sed s/,//`
+ ppw_comp=`echo "$comp" | awk '{print $8}' | sed s/,//`
+
+ # compare the base and comp values
+ des_perf_drop=`echo "scale=4;($des_perf_comp-$des_perf_base)*100/$des_perf_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 des perf base: $des_perf_base comprison: $des_perf_comp percent: $des_perf_drop\n" | tee -a $OUTFILE_GIT.result
+
+ freq_drop=`echo "scale=4;($freq_comp-$freq_base)*100/$freq_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 freq base: $freq_base comprison: $freq_comp percent: $freq_drop\n" | tee -a $OUTFILE_GIT.result
+
+ load_drop=`echo "scale=4;($load_comp-$load_base)*100/$load_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 load base: $load_base comprison: $load_comp percent: $load_drop\n" | tee -a $OUTFILE_GIT.result
+
+ time_drop=`echo "scale=4;($time_comp-$time_base)*100/$time_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 time base: $time_base comprison: $time_comp percent: $time_drop\n" | tee -a $OUTFILE_GIT.result
+
+ energy_drop=`echo "scale=4;($energy_comp-$energy_base)*100/$energy_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 energy base: $energy_base comprison: $energy_comp percent: $energy_drop\n" | tee -a $OUTFILE_GIT.result
+
+ ppw_drop=`echo "scale=4;($ppw_comp-$ppw_base)*100/$ppw_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Gitsource-$1 performance per watt base: $ppw_base comprison: $ppw_comp percent: $ppw_drop\n" | tee -a $OUTFILE_GIT.result
+ printf "\n" | tee -a $OUTFILE_GIT.result
+
+ store_csv_gitsource "$1-$2 VS $3-$4" "Comprison(%)" "$des_perf_drop" "$freq_drop" "$load_drop" "$time_drop" "$energy_drop" "$ppw_drop"
+ fi
+}
+
+# calculate the comparison(%)
+calc_comp_gitsource()
+{
+ # acpi-cpufreq-ondemand VS acpi-cpufreq-schedutil
+ __calc_comp_gitsource ${all_scaling_names[0]} ${gitsource_governors[0]} ${all_scaling_names[0]} ${gitsource_governors[1]}
+
+ # amd-pstate-ondemand VS amd-pstate-schedutil
+ __calc_comp_gitsource ${all_scaling_names[1]} ${gitsource_governors[0]} ${all_scaling_names[1]} ${gitsource_governors[1]}
+
+ # acpi-cpufreq-ondemand VS amd-pstate-ondemand
+ __calc_comp_gitsource ${all_scaling_names[0]} ${gitsource_governors[0]} ${all_scaling_names[1]} ${gitsource_governors[0]}
+
+ # acpi-cpufreq-schedutil VS amd-pstate-schedutil
+ __calc_comp_gitsource ${all_scaling_names[0]} ${gitsource_governors[1]} ${all_scaling_names[1]} ${gitsource_governors[1]}
+}
+
+# $1: file_name, $2: title, $3: ylable, $4: column
+plot_png_gitsource()
+{
+ # all_scaling_names[1] all_scaling_names[0] flag
+ # amd-pstate acpi-cpufreq
+ # N N 0
+ # N Y 1
+ # Y N 2
+ # Y Y 3
+ ret=`grep -c "${all_scaling_names[1]}" $OUTFILE_GIT.csv`
+ if [ $ret -eq 0 ]; then
+ ret=`grep -c "${all_scaling_names[0]}" $OUTFILE_GIT.csv`
+ if [ $ret -eq 0 ]; then
+ flag=0
+ else
+ flag=1
+ fi
+ else
+ ret=`grep -c "${all_scaling_names[0]}" $OUTFILE_GIT.csv`
+ if [ $ret -eq 0 ]; then
+ flag=2
+ else
+ flag=3
+ fi
+ fi
+
+ gnuplot << EOF
+ set term png
+ set output "$1"
+
+ set title "$2"
+ set xlabel "Test Cycles (round)"
+ set ylabel "$3"
+
+ set grid
+ set style data histogram
+ set style fill solid 0.5 border
+ set boxwidth 0.8
+
+ if ($flag == 1) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${gitsource_governors[0]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${gitsource_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${gitsource_governors[1]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${gitsource_governors[1]}"
+ } else {
+ if ($flag == 2) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${gitsource_governors[0]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${gitsource_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${gitsource_governors[1]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${gitsource_governors[1]}"
+ } else {
+ if ($flag == 3 ) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${gitsource_governors[0]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${gitsource_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${gitsource_governors[1]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${gitsource_governors[1]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${gitsource_governors[0]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${gitsource_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${gitsource_governors[1]}/p' $OUTFILE_GIT.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${gitsource_governors[1]}"
+ }
+ }
+ }
+ quit
+EOF
+}
+
+amd_pstate_gitsource()
+{
+ printf "\n---------------------------------------------\n"
+ printf "*** Running gitsource ***"
+ printf "\n---------------------------------------------\n"
+
+ pre_clear_gitsource
+
+ install_gitsource
+
+ get_lines_csv_gitsource "Governor"
+ if [ $? -eq 0 ]; then
+ # add titles and unit for csv file
+ store_csv_gitsource "Governor" "Round" "Des-perf" "Freq" "Load" "Time" "Energy" "Performance Per Watt"
+ store_csv_gitsource "Unit" "" "" "GHz" "" "s" "J" "1/J"
+ fi
+
+ backup_governor
+ for governor in ${gitsource_governors[*]} ; do
+ printf "\nSpecified governor is $governor\n\n"
+ switch_governor $governor
+ loop_gitsource $governor
+ gather_gitsource $governor
+ done
+ restore_governor
+
+ plot_png_gitsource "gitsource_time.png" "Gitsource Benchmark Time" "Time (s)" 6
+ plot_png_gitsource "gitsource_energy.png" "Gitsource Benchmark Energy" "Energy (J)" 7
+ plot_png_gitsource "gitsource_ppw.png" "Gitsource Benchmark Performance Per Watt" "Performance Per Watt (1/J)" 8
+
+ calc_comp_gitsource
+
+ post_clear_gitsource
+}
diff --git a/tools/testing/selftests/amd-pstate/run.sh b/tools/testing/selftests/amd-pstate/run.sh
new file mode 100755
index 000000000000..57cad57e59c0
--- /dev/null
+++ b/tools/testing/selftests/amd-pstate/run.sh
@@ -0,0 +1,387 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# protect against multiple inclusion
+if [ $FILE_MAIN ]; then
+ return 0
+else
+ FILE_MAIN=DONE
+fi
+
+source basic.sh
+source tbench.sh
+source gitsource.sh
+
+# amd-pstate-ut only run on x86/x86_64 AMD systems.
+ARCH=$(uname -m 2>/dev/null | sed -e 's/i.86/x86/' -e 's/x86_64/x86/')
+VENDOR=$(cat /proc/cpuinfo | grep -m 1 'vendor_id' | awk '{print $NF}')
+
+msg="Skip all tests:"
+FUNC=all
+OUTFILE=selftest
+OUTFILE_TBENCH="$OUTFILE.tbench"
+OUTFILE_GIT="$OUTFILE.gitsource"
+
+SYSFS=
+CPUROOT=
+CPUFREQROOT=
+MAKE_CPUS=
+
+TIME_LIMIT=100
+PROCESS_NUM=128
+LOOP_TIMES=3
+TRACER_INTERVAL=10
+CURRENT_TEST=amd-pstate
+COMPARATIVE_TEST=
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+all_scaling_names=("acpi-cpufreq" "amd-pstate")
+
+# Get current cpufreq scaling driver name
+scaling_name()
+{
+ if [ "$COMPARATIVE_TEST" = "" ]; then
+ echo "$CURRENT_TEST"
+ else
+ echo "$COMPARATIVE_TEST"
+ fi
+}
+
+# Counts CPUs with cpufreq directories
+count_cpus()
+{
+ count=0;
+
+ for cpu in `ls $CPUROOT | grep "cpu[0-9].*"`; do
+ if [ -d $CPUROOT/$cpu/cpufreq ]; then
+ let count=count+1;
+ fi
+ done
+
+ echo $count;
+}
+
+# $1: policy
+find_current_governor()
+{
+ cat $CPUFREQROOT/$1/scaling_governor
+}
+
+backup_governor()
+{
+ policies=$(ls $CPUFREQROOT| grep "policy[0-9].*")
+ for policy in $policies; do
+ cur_gov=$(find_current_governor $policy)
+ echo "$policy $cur_gov" >> $OUTFILE.backup_governor.log
+ done
+
+ printf "Governor $cur_gov backup done.\n"
+}
+
+restore_governor()
+{
+ i=0;
+
+ policies=$(awk '{print $1}' $OUTFILE.backup_governor.log)
+ for policy in $policies; do
+ let i++;
+ governor=$(sed -n ''$i'p' $OUTFILE.backup_governor.log | awk '{print $2}')
+
+ # switch governor
+ echo $governor > $CPUFREQROOT/$policy/scaling_governor
+ done
+
+ printf "Governor restored to $governor.\n"
+}
+
+# $1: governor
+switch_governor()
+{
+ policies=$(ls $CPUFREQROOT| grep "policy[0-9].*")
+ for policy in $policies; do
+ filepath=$CPUFREQROOT/$policy/scaling_available_governors
+
+ # Exit if cpu isn't managed by cpufreq core
+ if [ ! -f $filepath ]; then
+ return;
+ fi
+
+ echo $1 > $CPUFREQROOT/$policy/scaling_governor
+ done
+
+ printf "Switched governor to $1.\n"
+}
+
+# All amd-pstate tests
+amd_pstate_all()
+{
+ printf "\n=============================================\n"
+ printf "***** Running AMD P-state Sanity Tests *****\n"
+ printf "=============================================\n\n"
+
+ count=$(count_cpus)
+ if [ $count = 0 ]; then
+ printf "No cpu is managed by cpufreq core, exiting\n"
+ exit;
+ else
+ printf "AMD P-state manages: $count CPUs\n"
+ fi
+
+ # unit test for amd-pstate kernel driver
+ amd_pstate_basic
+
+ # tbench
+ amd_pstate_tbench
+
+ # gitsource
+ amd_pstate_gitsource
+}
+
+help()
+{
+ printf "Usage: $0 [OPTION...]
+ [-h <help>]
+ [-o <output-file-for-dump>]
+ [-c <all: All testing,
+ basic: Basic testing,
+ tbench: Tbench testing,
+ gitsource: Gitsource testing.>]
+ [-t <tbench time limit>]
+ [-p <tbench process number>]
+ [-l <loop times for tbench>]
+ [-i <amd tracer interval>]
+ [-m <comparative test: acpi-cpufreq>]
+ \n"
+ exit 2
+}
+
+parse_arguments()
+{
+ while getopts ho:c:t:p:l:i:m: arg
+ do
+ case $arg in
+ h) # --help
+ help
+ ;;
+
+ c) # --func_type (Function to perform: basic, tbench, gitsource (default: all))
+ FUNC=$OPTARG
+ ;;
+
+ o) # --output-file (Output file to store dumps)
+ OUTFILE=$OPTARG
+ ;;
+
+ t) # --tbench-time-limit
+ TIME_LIMIT=$OPTARG
+ ;;
+
+ p) # --tbench-process-number
+ PROCESS_NUM=$OPTARG
+ ;;
+
+ l) # --tbench/gitsource-loop-times
+ LOOP_TIMES=$OPTARG
+ ;;
+
+ i) # --amd-tracer-interval
+ TRACER_INTERVAL=$OPTARG
+ ;;
+
+ m) # --comparative-test
+ COMPARATIVE_TEST=$OPTARG
+ ;;
+
+ *)
+ help
+ ;;
+ esac
+ done
+}
+
+command_perf()
+{
+ if ! command -v perf > /dev/null; then
+ echo $msg please install perf. >&2
+ exit $ksft_skip
+ fi
+}
+
+command_tbench()
+{
+ if ! command -v tbench > /dev/null; then
+ if apt policy dbench > /dev/null 2>&1; then
+ echo $msg apt install dbench >&2
+ exit $ksft_skip
+ elif yum list available | grep dbench > /dev/null 2>&1; then
+ echo $msg yum install dbench >&2
+ exit $ksft_skip
+ fi
+ fi
+
+ if ! command -v tbench > /dev/null; then
+ echo $msg please install tbench. >&2
+ exit $ksft_skip
+ fi
+}
+
+prerequisite()
+{
+ if ! echo "$ARCH" | grep -q x86; then
+ echo "$0 # Skipped: Test can only run on x86 architectures."
+ exit $ksft_skip
+ fi
+
+ if ! echo "$VENDOR" | grep -iq amd; then
+ echo "$0 # Skipped: Test can only run on AMD CPU."
+ echo "$0 # Current cpu vendor is $VENDOR."
+ exit $ksft_skip
+ fi
+
+ scaling_driver=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_driver)
+ if [ "$COMPARATIVE_TEST" = "" ]; then
+ if [ "$scaling_driver" != "$CURRENT_TEST" ]; then
+ echo "$0 # Skipped: Test can only run on $CURRENT_TEST driver or run comparative test."
+ echo "$0 # Please set X86_AMD_PSTATE enabled or run comparative test."
+ echo "$0 # Current cpufreq scaling drvier is $scaling_driver."
+ exit $ksft_skip
+ fi
+ else
+ case "$FUNC" in
+ "tbench" | "gitsource")
+ if [ "$scaling_driver" != "$COMPARATIVE_TEST" ]; then
+ echo "$0 # Skipped: Comparison test can only run on $COMPARISON_TEST driver."
+ echo "$0 # Current cpufreq scaling drvier is $scaling_driver."
+ exit $ksft_skip
+ fi
+ ;;
+
+ *)
+ echo "$0 # Skipped: Comparison test are only for tbench or gitsource."
+ echo "$0 # Current comparative test is for $FUNC."
+ exit $ksft_skip
+ ;;
+ esac
+ fi
+
+ if [ ! -w /dev ]; then
+ echo $msg please run this as root >&2
+ exit $ksft_skip
+ fi
+
+ case "$FUNC" in
+ "all")
+ command_perf
+ command_tbench
+ ;;
+
+ "tbench")
+ command_perf
+ command_tbench
+ ;;
+
+ "gitsource")
+ command_perf
+ ;;
+ esac
+
+ SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+
+ if [ ! -d "$SYSFS" ]; then
+ echo $msg sysfs is not mounted >&2
+ exit 2
+ fi
+
+ CPUROOT=$SYSFS/devices/system/cpu
+ CPUFREQROOT="$CPUROOT/cpufreq"
+
+ if ! ls $CPUROOT/cpu* > /dev/null 2>&1; then
+ echo $msg cpus not available in sysfs >&2
+ exit 2
+ fi
+
+ if ! ls $CPUROOT/cpufreq > /dev/null 2>&1; then
+ echo $msg cpufreq directory not available in sysfs >&2
+ exit 2
+ fi
+}
+
+do_test()
+{
+ # Check if CPUs are managed by cpufreq or not
+ count=$(count_cpus)
+ MAKE_CPUS=$((count*2))
+
+ if [ $count = 0 ]; then
+ echo "No cpu is managed by cpufreq core, exiting"
+ exit 2;
+ fi
+
+ case "$FUNC" in
+ "all")
+ amd_pstate_all
+ ;;
+
+ "basic")
+ amd_pstate_basic
+ ;;
+
+ "tbench")
+ amd_pstate_tbench
+ ;;
+
+ "gitsource")
+ amd_pstate_gitsource
+ ;;
+
+ *)
+ echo "Invalid [-f] function type"
+ help
+ ;;
+ esac
+}
+
+# clear dumps
+pre_clear_dumps()
+{
+ case "$FUNC" in
+ "all")
+ rm -rf $OUTFILE.log
+ rm -rf $OUTFILE.backup_governor.log
+ rm -rf *.png
+ ;;
+
+ "tbench")
+ rm -rf $OUTFILE.log
+ rm -rf $OUTFILE.backup_governor.log
+ rm -rf tbench_*.png
+ ;;
+
+ "gitsource")
+ rm -rf $OUTFILE.log
+ rm -rf $OUTFILE.backup_governor.log
+ rm -rf gitsource_*.png
+ ;;
+
+ *)
+ ;;
+ esac
+}
+
+post_clear_dumps()
+{
+ rm -rf $OUTFILE.log
+ rm -rf $OUTFILE.backup_governor.log
+}
+
+# Parse arguments
+parse_arguments $@
+
+# Make sure all requirements are met
+prerequisite
+
+# Run requested functions
+pre_clear_dumps
+do_test | tee -a $OUTFILE.log
+post_clear_dumps
diff --git a/tools/testing/selftests/amd-pstate/tbench.sh b/tools/testing/selftests/amd-pstate/tbench.sh
new file mode 100755
index 000000000000..49c9850341f6
--- /dev/null
+++ b/tools/testing/selftests/amd-pstate/tbench.sh
@@ -0,0 +1,339 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# Testing and monitor the cpu desire performance, frequency, load,
+# power consumption and throughput etc.when this script trigger tbench
+# test cases.
+# 1) Run tbench benchmark on specific governors, ondemand or schedutil.
+# 2) Run tbench benchmark comparative test on acpi-cpufreq kernel driver.
+# 3) Get desire performance, frequency, load by perf.
+# 4) Get power consumption and throughput by amd_pstate_trace.py.
+# 5) Analyse test results and save it in file selftest.tbench.csv.
+# 6) Plot png images about performance, energy and performance per watt for each test.
+
+# protect against multiple inclusion
+if [ $FILE_TBENCH ]; then
+ return 0
+else
+ FILE_TBENCH=DONE
+fi
+
+tbench_governors=("ondemand" "schedutil")
+
+# $1: governor, $2: round, $3: des-perf, $4: freq, $5: load, $6: performance, $7: energy, $8: performance per watt
+store_csv_tbench()
+{
+ echo "$1, $2, $3, $4, $5, $6, $7, $8" | tee -a $OUTFILE_TBENCH.csv > /dev/null 2>&1
+}
+
+# clear some special lines
+clear_csv_tbench()
+{
+ if [ -f $OUTFILE_TBENCH.csv ]; then
+ sed -i '/Comprison(%)/d' $OUTFILE_TBENCH.csv
+ sed -i "/$(scaling_name)/d" $OUTFILE_TBENCH.csv
+ fi
+}
+
+# find string $1 in file csv and get the number of lines
+get_lines_csv_tbench()
+{
+ if [ -f $OUTFILE_TBENCH.csv ]; then
+ return `grep -c "$1" $OUTFILE_TBENCH.csv`
+ else
+ return 0
+ fi
+}
+
+pre_clear_tbench()
+{
+ post_clear_tbench
+ rm -rf tbench_*.png
+ clear_csv_tbench
+}
+
+post_clear_tbench()
+{
+ rm -rf results/tracer-tbench*
+ rm -rf $OUTFILE_TBENCH*.log
+ rm -rf $OUTFILE_TBENCH*.result
+
+}
+
+# $1: governor, $2: loop
+run_tbench()
+{
+ echo "Launching amd pstate tracer for $1 #$2 tracer_interval: $TRACER_INTERVAL"
+ ./amd_pstate_trace.py -n tracer-tbench-$1-$2 -i $TRACER_INTERVAL > /dev/null 2>&1 &
+
+ printf "Test tbench for $1 #$2 time_limit: $TIME_LIMIT procs_num: $PROCESS_NUM\n"
+ tbench_srv > /dev/null 2>&1 &
+ perf stat -a --per-socket -I 1000 -e power/energy-pkg/ tbench -t $TIME_LIMIT $PROCESS_NUM > $OUTFILE_TBENCH-perf-$1-$2.log 2>&1
+
+ pid=`pidof tbench_srv`
+ kill $pid
+
+ for job in `jobs -p`
+ do
+ echo "Waiting for job id $job"
+ wait $job
+ done
+}
+
+# $1: governor, $2: loop
+parse_tbench()
+{
+ awk '{print $5}' results/tracer-tbench-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_TBENCH-des-perf-$1-$2.log
+ avg_des_perf=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_TBENCH-des-perf-$1-$2.log)
+ printf "Tbench-$1-#$2 avg des perf: $avg_des_perf\n" | tee -a $OUTFILE_TBENCH.result
+
+ awk '{print $7}' results/tracer-tbench-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_TBENCH-freq-$1-$2.log
+ avg_freq=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_TBENCH-freq-$1-$2.log)
+ printf "Tbench-$1-#$2 avg freq: $avg_freq\n" | tee -a $OUTFILE_TBENCH.result
+
+ awk '{print $11}' results/tracer-tbench-$1-$2/cpu.csv | sed -e '1d' | sed s/,// > $OUTFILE_TBENCH-load-$1-$2.log
+ avg_load=$(awk 'BEGIN {i=0; sum=0};{i++; sum += $1};END {print sum/i}' $OUTFILE_TBENCH-load-$1-$2.log)
+ printf "Tbench-$1-#$2 avg load: $avg_load\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep Throughput $OUTFILE_TBENCH-perf-$1-$2.log | awk '{print $2}' > $OUTFILE_TBENCH-throughput-$1-$2.log
+ tp_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_TBENCH-throughput-$1-$2.log)
+ printf "Tbench-$1-#$2 throughput(MB/s): $tp_sum\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep Joules $OUTFILE_TBENCH-perf-$1-$2.log | awk '{print $4}' > $OUTFILE_TBENCH-energy-$1-$2.log
+ en_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_TBENCH-energy-$1-$2.log)
+ printf "Tbench-$1-#$2 power consumption(J): $en_sum\n" | tee -a $OUTFILE_TBENCH.result
+
+ # Permance is throughput per second, denoted T/t, where T is throught rendered in t seconds.
+ # It is well known that P=E/t, where P is power measured in watts(W), E is energy measured in joules(J),
+ # and t is time measured in seconds(s). This means that performance per watt becomes
+ # T/t T/t T
+ # --- = --- = ---
+ # P E/t E
+ # with unit given by MB per joule.
+ ppw=`echo "scale=4;($TIME_LIMIT-1)*$tp_sum/$en_sum" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1-#$2 performance per watt(MB/J): $ppw\n" | tee -a $OUTFILE_TBENCH.result
+ printf "\n" | tee -a $OUTFILE_TBENCH.result
+
+ driver_name=`echo $(scaling_name)`
+ store_csv_tbench "$driver_name-$1" $2 $avg_des_perf $avg_freq $avg_load $tp_sum $en_sum $ppw
+}
+
+# $1: governor
+loop_tbench()
+{
+ printf "\nTbench total test times is $LOOP_TIMES for $1\n\n"
+ for i in `seq 1 $LOOP_TIMES`
+ do
+ run_tbench $1 $i
+ parse_tbench $1 $i
+ done
+}
+
+# $1: governor
+gather_tbench()
+{
+ printf "Tbench test result for $1 (loops:$LOOP_TIMES)" | tee -a $OUTFILE_TBENCH.result
+ printf "\n--------------------------------------------------\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep "Tbench-$1-#" $OUTFILE_TBENCH.result | grep "avg des perf:" | awk '{print $NF}' > $OUTFILE_TBENCH-des-perf-$1.log
+ avg_des_perf=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_TBENCH-des-perf-$1.log)
+ printf "Tbench-$1 avg des perf: $avg_des_perf\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep "Tbench-$1-#" $OUTFILE_TBENCH.result | grep "avg freq:" | awk '{print $NF}' > $OUTFILE_TBENCH-freq-$1.log
+ avg_freq=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_TBENCH-freq-$1.log)
+ printf "Tbench-$1 avg freq: $avg_freq\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep "Tbench-$1-#" $OUTFILE_TBENCH.result | grep "avg load:" | awk '{print $NF}' > $OUTFILE_TBENCH-load-$1.log
+ avg_load=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_TBENCH-load-$1.log)
+ printf "Tbench-$1 avg load: $avg_load\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep "Tbench-$1-#" $OUTFILE_TBENCH.result | grep "throughput(MB/s):" | awk '{print $NF}' > $OUTFILE_TBENCH-throughput-$1.log
+ tp_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_TBENCH-throughput-$1.log)
+ printf "Tbench-$1 total throughput(MB/s): $tp_sum\n" | tee -a $OUTFILE_TBENCH.result
+
+ avg_tp=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_TBENCH-throughput-$1.log)
+ printf "Tbench-$1 avg throughput(MB/s): $avg_tp\n" | tee -a $OUTFILE_TBENCH.result
+
+ grep "Tbench-$1-#" $OUTFILE_TBENCH.result | grep "power consumption(J):" | awk '{print $NF}' > $OUTFILE_TBENCH-energy-$1.log
+ en_sum=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum}' $OUTFILE_TBENCH-energy-$1.log)
+ printf "Tbench-$1 total power consumption(J): $en_sum\n" | tee -a $OUTFILE_TBENCH.result
+
+ avg_en=$(awk 'BEGIN {sum=0};{sum += $1};END {print sum/'$LOOP_TIMES'}' $OUTFILE_TBENCH-energy-$1.log)
+ printf "Tbench-$1 avg power consumption(J): $avg_en\n" | tee -a $OUTFILE_TBENCH.result
+
+ # Permance is throughput per second, denoted T/t, where T is throught rendered in t seconds.
+ # It is well known that P=E/t, where P is power measured in watts(W), E is energy measured in joules(J),
+ # and t is time measured in seconds(s). This means that performance per watt becomes
+ # T/t T/t T
+ # --- = --- = ---
+ # P E/t E
+ # with unit given by MB per joule.
+ ppw=`echo "scale=4;($TIME_LIMIT-1)*$avg_tp/$avg_en" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 performance per watt(MB/J): $ppw\n" | tee -a $OUTFILE_TBENCH.result
+ printf "\n" | tee -a $OUTFILE_TBENCH.result
+
+ driver_name=`echo $(scaling_name)`
+ store_csv_tbench "$driver_name-$1" "Average" $avg_des_perf $avg_freq $avg_load $avg_tp $avg_en $ppw
+}
+
+# $1: base scaling_driver $2: base governor $3: comparative scaling_driver $4: comparative governor
+__calc_comp_tbench()
+{
+ base=`grep "$1-$2" $OUTFILE_TBENCH.csv | grep "Average"`
+ comp=`grep "$3-$4" $OUTFILE_TBENCH.csv | grep "Average"`
+
+ if [ -n "$base" -a -n "$comp" ]; then
+ printf "\n==================================================\n" | tee -a $OUTFILE_TBENCH.result
+ printf "Tbench comparison $1-$2 VS $3-$4" | tee -a $OUTFILE_TBENCH.result
+ printf "\n==================================================\n" | tee -a $OUTFILE_TBENCH.result
+
+ # get the base values
+ des_perf_base=`echo "$base" | awk '{print $3}' | sed s/,//`
+ freq_base=`echo "$base" | awk '{print $4}' | sed s/,//`
+ load_base=`echo "$base" | awk '{print $5}' | sed s/,//`
+ perf_base=`echo "$base" | awk '{print $6}' | sed s/,//`
+ energy_base=`echo "$base" | awk '{print $7}' | sed s/,//`
+ ppw_base=`echo "$base" | awk '{print $8}' | sed s/,//`
+
+ # get the comparative values
+ des_perf_comp=`echo "$comp" | awk '{print $3}' | sed s/,//`
+ freq_comp=`echo "$comp" | awk '{print $4}' | sed s/,//`
+ load_comp=`echo "$comp" | awk '{print $5}' | sed s/,//`
+ perf_comp=`echo "$comp" | awk '{print $6}' | sed s/,//`
+ energy_comp=`echo "$comp" | awk '{print $7}' | sed s/,//`
+ ppw_comp=`echo "$comp" | awk '{print $8}' | sed s/,//`
+
+ # compare the base and comp values
+ des_perf_drop=`echo "scale=4;($des_perf_comp-$des_perf_base)*100/$des_perf_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 des perf base: $des_perf_base comprison: $des_perf_comp percent: $des_perf_drop\n" | tee -a $OUTFILE_TBENCH.result
+
+ freq_drop=`echo "scale=4;($freq_comp-$freq_base)*100/$freq_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 freq base: $freq_base comprison: $freq_comp percent: $freq_drop\n" | tee -a $OUTFILE_TBENCH.result
+
+ load_drop=`echo "scale=4;($load_comp-$load_base)*100/$load_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 load base: $load_base comprison: $load_comp percent: $load_drop\n" | tee -a $OUTFILE_TBENCH.result
+
+ perf_drop=`echo "scale=4;($perf_comp-$perf_base)*100/$perf_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 perf base: $perf_base comprison: $perf_comp percent: $perf_drop\n" | tee -a $OUTFILE_TBENCH.result
+
+ energy_drop=`echo "scale=4;($energy_comp-$energy_base)*100/$energy_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 energy base: $energy_base comprison: $energy_comp percent: $energy_drop\n" | tee -a $OUTFILE_TBENCH.result
+
+ ppw_drop=`echo "scale=4;($ppw_comp-$ppw_base)*100/$ppw_base" | bc | awk '{printf "%.4f", $0}'`
+ printf "Tbench-$1 performance per watt base: $ppw_base comprison: $ppw_comp percent: $ppw_drop\n" | tee -a $OUTFILE_TBENCH.result
+ printf "\n" | tee -a $OUTFILE_TBENCH.result
+
+ store_csv_tbench "$1-$2 VS $3-$4" "Comprison(%)" "$des_perf_drop" "$freq_drop" "$load_drop" "$perf_drop" "$energy_drop" "$ppw_drop"
+ fi
+}
+
+# calculate the comparison(%)
+calc_comp_tbench()
+{
+ # acpi-cpufreq-ondemand VS acpi-cpufreq-schedutil
+ __calc_comp_tbench ${all_scaling_names[0]} ${tbench_governors[0]} ${all_scaling_names[0]} ${tbench_governors[1]}
+
+ # amd-pstate-ondemand VS amd-pstate-schedutil
+ __calc_comp_tbench ${all_scaling_names[1]} ${tbench_governors[0]} ${all_scaling_names[1]} ${tbench_governors[1]}
+
+ # acpi-cpufreq-ondemand VS amd-pstate-ondemand
+ __calc_comp_tbench ${all_scaling_names[0]} ${tbench_governors[0]} ${all_scaling_names[1]} ${tbench_governors[0]}
+
+ # acpi-cpufreq-schedutil VS amd-pstate-schedutil
+ __calc_comp_tbench ${all_scaling_names[0]} ${tbench_governors[1]} ${all_scaling_names[1]} ${tbench_governors[1]}
+}
+
+# $1: file_name, $2: title, $3: ylable, $4: column
+plot_png_tbench()
+{
+ # all_scaling_names[1] all_scaling_names[0] flag
+ # amd-pstate acpi-cpufreq
+ # N N 0
+ # N Y 1
+ # Y N 2
+ # Y Y 3
+ ret=`grep -c "${all_scaling_names[1]}" $OUTFILE_TBENCH.csv`
+ if [ $ret -eq 0 ]; then
+ ret=`grep -c "${all_scaling_names[0]}" $OUTFILE_TBENCH.csv`
+ if [ $ret -eq 0 ]; then
+ flag=0
+ else
+ flag=1
+ fi
+ else
+ ret=`grep -c "${all_scaling_names[0]}" $OUTFILE_TBENCH.csv`
+ if [ $ret -eq 0 ]; then
+ flag=2
+ else
+ flag=3
+ fi
+ fi
+
+ gnuplot << EOF
+ set term png
+ set output "$1"
+
+ set title "$2"
+ set xlabel "Test Cycles (round)"
+ set ylabel "$3"
+
+ set grid
+ set style data histogram
+ set style fill solid 0.5 border
+ set boxwidth 0.8
+
+ if ($flag == 1) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${tbench_governors[0]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${tbench_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${tbench_governors[1]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${tbench_governors[1]}"
+ } else {
+ if ($flag == 2) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${tbench_governors[0]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${tbench_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${tbench_governors[1]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${tbench_governors[1]}"
+ } else {
+ if ($flag == 3 ) {
+ plot \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${tbench_governors[0]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${tbench_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[0]}-${tbench_governors[1]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[0]}-${tbench_governors[1]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${tbench_governors[0]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${tbench_governors[0]}", \
+ "<(sed -n -e 's/,//g' -e '/${all_scaling_names[1]}-${tbench_governors[1]}/p' $OUTFILE_TBENCH.csv)" using $4:xtic(2) title "${all_scaling_names[1]}-${tbench_governors[1]}"
+ }
+ }
+ }
+ quit
+EOF
+}
+
+amd_pstate_tbench()
+{
+ printf "\n---------------------------------------------\n"
+ printf "*** Running tbench ***"
+ printf "\n---------------------------------------------\n"
+
+ pre_clear_tbench
+
+ get_lines_csv_tbench "Governor"
+ if [ $? -eq 0 ]; then
+ # add titles and unit for csv file
+ store_csv_tbench "Governor" "Round" "Des-perf" "Freq" "Load" "Performance" "Energy" "Performance Per Watt"
+ store_csv_tbench "Unit" "" "" "GHz" "" "MB/s" "J" "MB/J"
+ fi
+
+ backup_governor
+ for governor in ${tbench_governors[*]} ; do
+ printf "\nSpecified governor is $governor\n\n"
+ switch_governor $governor
+ loop_tbench $governor
+ gather_tbench $governor
+ done
+ restore_governor
+
+ plot_png_tbench "tbench_perfromance.png" "Tbench Benchmark Performance" "Performance" 6
+ plot_png_tbench "tbench_energy.png" "Tbench Benchmark Energy" "Energy (J)" 7
+ plot_png_tbench "tbench_ppw.png" "Tbench Benchmark Performance Per Watt" "Performance Per Watt (MB/J)" 8
+
+ calc_comp_tbench
+
+ post_clear_tbench
+}
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index 9f1a7b5c6193..9f255bc5f31c 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -33,6 +33,12 @@
*/
typedef void (*sigill_fn)(void);
+static void cssc_sigill(void)
+{
+ /* CNT x0, x0 */
+ asm volatile(".inst 0xdac01c00" : : : "x0");
+}
+
static void rng_sigill(void)
{
asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
@@ -56,6 +62,12 @@ static void sve2_sigill(void)
asm volatile(".inst 0x4408A000" : : : "z0");
}
+static void sve2p1_sigill(void)
+{
+ /* BFADD Z0.H, Z0.H, Z0.H */
+ asm volatile(".inst 0x65000000" : : : "z0");
+}
+
static void sveaes_sigill(void)
{
/* AESD z0.b, z0.b, z0.b */
@@ -119,6 +131,13 @@ static const struct hwcap_data {
bool sigill_reliable;
} hwcaps[] = {
{
+ .name = "CSSC",
+ .at_hwcap = AT_HWCAP2,
+ .hwcap_bit = HWCAP2_CSSC,
+ .cpuinfo = "cssc",
+ .sigill_fn = cssc_sigill,
+ },
+ {
.name = "RNG",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_RNG,
@@ -126,6 +145,12 @@ static const struct hwcap_data {
.sigill_fn = rng_sigill,
},
{
+ .name = "RPRFM",
+ .at_hwcap = AT_HWCAP2,
+ .hwcap_bit = HWCAP2_RPRFM,
+ .cpuinfo = "rprfm",
+ },
+ {
.name = "SME",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SME,
@@ -149,6 +174,13 @@ static const struct hwcap_data {
.sigill_fn = sve2_sigill,
},
{
+ .name = "SVE 2.1",
+ .at_hwcap = AT_HWCAP2,
+ .hwcap_bit = HWCAP2_SVE2P1,
+ .cpuinfo = "sve2p1",
+ .sigill_fn = sve2p1_sigill,
+ },
+ {
.name = "SVE AES",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEAES,
diff --git a/tools/testing/selftests/arm64/abi/syscall-abi-asm.S b/tools/testing/selftests/arm64/abi/syscall-abi-asm.S
index b523c21c2278..acd5e9f3bc0b 100644
--- a/tools/testing/selftests/arm64/abi/syscall-abi-asm.S
+++ b/tools/testing/selftests/arm64/abi/syscall-abi-asm.S
@@ -153,7 +153,7 @@ do_syscall:
// Only set a non-zero FFR, test patterns must be zero since the
// syscall should clear it - this lets us handle FA64.
ldr x2, =ffr_in
- ldr p0, [x2, #0]
+ ldr p0, [x2]
ldr x2, [x2, #0]
cbz x2, 2f
wrffr p0.b
@@ -298,7 +298,7 @@ do_syscall:
cbz x2, 1f
ldr x2, =ffr_out
rdffr p0.b
- str p0, [x2, #0]
+ str p0, [x2]
1:
// Restore callee saved registers x19-x30
diff --git a/tools/testing/selftests/arm64/fp/fp-stress.c b/tools/testing/selftests/arm64/fp/fp-stress.c
index 4e62a9199f97..f8b2f41aac36 100644
--- a/tools/testing/selftests/arm64/fp/fp-stress.c
+++ b/tools/testing/selftests/arm64/fp/fp-stress.c
@@ -39,10 +39,12 @@ struct child_data {
static int epoll_fd;
static struct child_data *children;
+static struct epoll_event *evs;
+static int tests;
static int num_children;
static bool terminate;
-static void drain_output(bool flush);
+static int startup_pipe[2];
static int num_processors(void)
{
@@ -82,12 +84,36 @@ static void child_start(struct child_data *child, const char *program)
}
/*
+ * Duplicate the read side of the startup pipe to
+ * FD 3 so we can close everything else.
+ */
+ ret = dup2(startup_pipe[0], 3);
+ if (ret == -1) {
+ fprintf(stderr, "dup2() %d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
* Very dumb mechanism to clean open FDs other than
* stdio. We don't want O_CLOEXEC for the pipes...
*/
- for (i = 3; i < 8192; i++)
+ for (i = 4; i < 8192; i++)
close(i);
+ /*
+ * Read from the startup pipe, there should be no data
+ * and we should block until it is closed. We just
+ * carry on on error since this isn't super critical.
+ */
+ ret = read(3, &i, sizeof(i));
+ if (ret < 0)
+ fprintf(stderr, "read(startp pipe) failed: %s (%d)\n",
+ strerror(errno), errno);
+ if (ret > 0)
+ fprintf(stderr, "%d bytes of data on startup pipe\n",
+ ret);
+ close(3);
+
ret = execl(program, program, NULL);
fprintf(stderr, "execl(%s) failed: %d (%s)\n",
program, errno, strerror(errno));
@@ -112,12 +138,6 @@ static void child_start(struct child_data *child, const char *program)
ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n",
child->name, strerror(errno), errno);
}
-
- /*
- * Keep output flowing during child startup so logs
- * are more timely, can help debugging.
- */
- drain_output(false);
}
}
@@ -290,12 +310,12 @@ static void start_fpsimd(struct child_data *child, int cpu, int copy)
{
int ret;
- child_start(child, "./fpsimd-test");
-
ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy);
if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
+ child_start(child, "./fpsimd-test");
+
ksft_print_msg("Started %s\n", child->name);
}
@@ -307,12 +327,12 @@ static void start_sve(struct child_data *child, int vl, int cpu)
if (ret < 0)
ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl);
- child_start(child, "./sve-test");
-
ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu);
if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
+ child_start(child, "./sve-test");
+
ksft_print_msg("Started %s\n", child->name);
}
@@ -320,16 +340,16 @@ static void start_ssve(struct child_data *child, int vl, int cpu)
{
int ret;
+ ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);
+ if (ret == -1)
+ ksft_exit_fail_msg("asprintf() failed\n");
+
ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT);
if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
child_start(child, "./ssve-test");
- ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);
- if (ret == -1)
- ksft_exit_fail_msg("asprintf() failed\n");
-
ksft_print_msg("Started %s\n", child->name);
}
@@ -341,12 +361,12 @@ static void start_za(struct child_data *child, int vl, int cpu)
if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
- child_start(child, "./za-test");
-
ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu);
if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
+ child_start(child, "./za-test");
+
ksft_print_msg("Started %s\n", child->name);
}
@@ -375,11 +395,11 @@ static void probe_vls(int vls[], int *vl_count, int set_vl)
/* Handle any pending output without blocking */
static void drain_output(bool flush)
{
- struct epoll_event ev;
int ret = 1;
+ int i;
while (ret > 0) {
- ret = epoll_wait(epoll_fd, &ev, 1, 0);
+ ret = epoll_wait(epoll_fd, evs, tests, 0);
if (ret < 0) {
if (errno == EINTR)
continue;
@@ -387,8 +407,8 @@ static void drain_output(bool flush)
strerror(errno), errno);
}
- if (ret == 1)
- child_output(ev.data.ptr, ev.events, flush);
+ for (i = 0; i < ret; i++)
+ child_output(evs[i].data.ptr, evs[i].events, flush);
}
}
@@ -401,10 +421,11 @@ int main(int argc, char **argv)
{
int ret;
int timeout = 10;
- int cpus, tests, i, j, c;
+ int cpus, i, j, c;
int sve_vl_count, sme_vl_count, fpsimd_per_cpu;
+ bool all_children_started = false;
+ int seen_children;
int sve_vls[MAX_VLS], sme_vls[MAX_VLS];
- struct epoll_event ev;
struct sigaction sa;
while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
@@ -465,6 +486,12 @@ int main(int argc, char **argv)
strerror(errno), ret);
epoll_fd = ret;
+ /* Create a pipe which children will block on before execing */
+ ret = pipe(startup_pipe);
+ if (ret != 0)
+ ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
+ strerror(errno), errno);
+
/* Get signal handers ready before we start any children */
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_exit_signal;
@@ -484,6 +511,11 @@ int main(int argc, char **argv)
ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
strerror(errno), errno);
+ evs = calloc(tests, sizeof(*evs));
+ if (!evs)
+ ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
+ tests);
+
for (i = 0; i < cpus; i++) {
for (j = 0; j < fpsimd_per_cpu; j++)
start_fpsimd(&children[num_children++], i, j);
@@ -497,6 +529,13 @@ int main(int argc, char **argv)
}
}
+ /*
+ * All children started, close the startup pipe and let them
+ * run.
+ */
+ close(startup_pipe[0]);
+ close(startup_pipe[1]);
+
for (;;) {
/* Did we get a signal asking us to exit? */
if (terminate)
@@ -510,7 +549,7 @@ int main(int argc, char **argv)
* useful in emulation where we will both be slow and
* likely to have a large set of VLs.
*/
- ret = epoll_wait(epoll_fd, &ev, 1, 1000);
+ ret = epoll_wait(epoll_fd, evs, tests, 1000);
if (ret < 0) {
if (errno == EINTR)
continue;
@@ -519,13 +558,40 @@ int main(int argc, char **argv)
}
/* Output? */
- if (ret == 1) {
- child_output(ev.data.ptr, ev.events, false);
+ if (ret > 0) {
+ for (i = 0; i < ret; i++) {
+ child_output(evs[i].data.ptr, evs[i].events,
+ false);
+ }
continue;
}
/* Otherwise epoll_wait() timed out */
+ /*
+ * If the child processes have not produced output they
+ * aren't actually running the tests yet .
+ */
+ if (!all_children_started) {
+ seen_children = 0;
+
+ for (i = 0; i < num_children; i++)
+ if (children[i].output_seen ||
+ children[i].exited)
+ seen_children++;
+
+ if (seen_children != num_children) {
+ ksft_print_msg("Waiting for %d children\n",
+ num_children - seen_children);
+ continue;
+ }
+
+ all_children_started = true;
+ }
+
+ ksft_print_msg("Sending signals, timeout remaining: %d\n",
+ timeout);
+
for (i = 0; i < num_children; i++)
child_tickle(&children[i]);
diff --git a/tools/testing/selftests/arm64/mte/check_buffer_fill.c b/tools/testing/selftests/arm64/mte/check_buffer_fill.c
index 75fc482d63b6..1dbbbd47dd50 100644
--- a/tools/testing/selftests/arm64/mte/check_buffer_fill.c
+++ b/tools/testing/selftests/arm64/mte/check_buffer_fill.c
@@ -32,7 +32,7 @@ static int check_buffer_by_byte(int mem_type, int mode)
bool err;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
- item = sizeof(sizes)/sizeof(int);
+ item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true);
@@ -69,7 +69,7 @@ static int check_buffer_underflow_by_byte(int mem_type, int mode,
char *und_ptr = NULL;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
- item = sizeof(sizes)/sizeof(int);
+ item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
underflow_range, 0);
@@ -165,7 +165,7 @@ static int check_buffer_overflow_by_byte(int mem_type, int mode,
char *over_ptr = NULL;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
- item = sizeof(sizes)/sizeof(int);
+ item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
0, overflow_range);
@@ -338,7 +338,7 @@ static int check_buffer_by_block(int mem_type, int mode)
int i, item, result = KSFT_PASS;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
- item = sizeof(sizes)/sizeof(int);
+ item = ARRAY_SIZE(sizes);
cur_mte_cxt.fault_valid = false;
for (i = 0; i < item; i++) {
result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]);
@@ -366,7 +366,7 @@ static int check_memory_initial_tags(int mem_type, int mode, int mapping)
{
char *ptr;
int run, fd;
- int total = sizeof(sizes)/sizeof(int);
+ int total = ARRAY_SIZE(sizes);
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
for (run = 0; run < total; run++) {
@@ -404,7 +404,7 @@ int main(int argc, char *argv[])
{
int err;
size_t page_size = getpagesize();
- int item = sizeof(sizes)/sizeof(int);
+ int item = ARRAY_SIZE(sizes);
sizes[item - 3] = page_size - 1;
sizes[item - 2] = page_size;
diff --git a/tools/testing/selftests/arm64/mte/check_mmap_options.c b/tools/testing/selftests/arm64/mte/check_mmap_options.c
index a04b12c21ac9..17694caaff53 100644
--- a/tools/testing/selftests/arm64/mte/check_mmap_options.c
+++ b/tools/testing/selftests/arm64/mte/check_mmap_options.c
@@ -61,9 +61,8 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
{
char *ptr, *map_ptr;
int run, result, map_size;
- int item = sizeof(sizes)/sizeof(int);
+ int item = ARRAY_SIZE(sizes);
- item = sizeof(sizes)/sizeof(int);
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
for (run = 0; run < item; run++) {
map_size = sizes[run] + OVERFLOW + UNDERFLOW;
@@ -93,7 +92,7 @@ static int check_file_memory_mapping(int mem_type, int mode, int mapping, int ta
{
char *ptr, *map_ptr;
int run, fd, map_size;
- int total = sizeof(sizes)/sizeof(int);
+ int total = ARRAY_SIZE(sizes);
int result = KSFT_PASS;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
@@ -132,7 +131,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
{
char *ptr, *map_ptr;
int run, prot_flag, result, fd, map_size;
- int total = sizeof(sizes)/sizeof(int);
+ int total = ARRAY_SIZE(sizes);
prot_flag = PROT_READ | PROT_WRITE;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
@@ -187,7 +186,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
int main(int argc, char *argv[])
{
int err;
- int item = sizeof(sizes)/sizeof(int);
+ int item = ARRAY_SIZE(sizes);
err = mte_default_setup();
if (err)
diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO b/tools/testing/selftests/arm64/signal/testcases/TODO
index 110ff9fd195d..1f7fba8194fe 100644
--- a/tools/testing/selftests/arm64/signal/testcases/TODO
+++ b/tools/testing/selftests/arm64/signal/testcases/TODO
@@ -1,2 +1 @@
- Validate that register contents are saved and restored as expected.
-- Support and validate extra_context.
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
index e1c625b20ac4..d2eda7b5de26 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.c
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019 ARM Limited */
+
+#include <ctype.h>
+#include <string.h>
+
#include "testcases.h"
struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
@@ -109,7 +113,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
bool terminated = false;
size_t offs = 0;
int flags = 0;
- int new_flags;
+ int new_flags, i;
struct extra_context *extra = NULL;
struct sve_context *sve = NULL;
struct za_context *za = NULL;
@@ -117,6 +121,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
void *extra_data = NULL;
size_t extra_sz = 0;
+ char magic[4];
if (!err)
return false;
@@ -194,11 +199,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
/*
* A still unknown Magic: potentially freshly added
* to the Kernel code and still unknown to the
- * tests.
+ * tests. Magic numbers are supposed to be allocated
+ * as somewhat meaningful ASCII strings so try to
+ * print as such as well as the raw number.
*/
+ memcpy(magic, &head->magic, sizeof(magic));
+ for (i = 0; i < sizeof(magic); i++)
+ if (!isalnum(magic[i]))
+ magic[i] = '?';
+
fprintf(stdout,
- "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
- head->magic);
+ "SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n",
+ head->magic,
+ magic[3], magic[2], magic[1], magic[0]);
break;
}
diff --git a/tools/testing/selftests/bpf/map_tests/sk_storage_map.c b/tools/testing/selftests/bpf/map_tests/sk_storage_map.c
index 099eb4dfd4f7..18405c3b7cee 100644
--- a/tools/testing/selftests/bpf/map_tests/sk_storage_map.c
+++ b/tools/testing/selftests/bpf/map_tests/sk_storage_map.c
@@ -458,7 +458,7 @@ static void test_sk_storage_map_basic(void)
struct {
int cnt;
int lock;
- } value = { .cnt = 0xeB9f, .lock = 0, }, lookup_value;
+ } value = { .cnt = 0xeB9f, .lock = 1, }, lookup_value;
struct bpf_map_create_opts bad_xattr;
int btf_fd, map_fd, sk_fd, err;
@@ -483,38 +483,41 @@ static void test_sk_storage_map_basic(void)
"err:%d errno:%d\n", err, errno);
err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
BPF_F_LOCK);
- CHECK(err || lookup_value.cnt != value.cnt,
+ CHECK(err || lookup_value.lock || lookup_value.cnt != value.cnt,
"bpf_map_lookup_elem_flags(BPF_F_LOCK)",
- "err:%d errno:%d cnt:%x(%x)\n",
- err, errno, lookup_value.cnt, value.cnt);
+ "err:%d errno:%d lock:%x cnt:%x(%x)\n",
+ err, errno, lookup_value.lock, lookup_value.cnt, value.cnt);
/* Bump the cnt and update with BPF_EXIST | BPF_F_LOCK */
value.cnt += 1;
+ value.lock = 2;
err = bpf_map_update_elem(map_fd, &sk_fd, &value,
BPF_EXIST | BPF_F_LOCK);
CHECK(err, "bpf_map_update_elem(BPF_EXIST|BPF_F_LOCK)",
"err:%d errno:%d\n", err, errno);
err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
BPF_F_LOCK);
- CHECK(err || lookup_value.cnt != value.cnt,
+ CHECK(err || lookup_value.lock || lookup_value.cnt != value.cnt,
"bpf_map_lookup_elem_flags(BPF_F_LOCK)",
- "err:%d errno:%d cnt:%x(%x)\n",
- err, errno, lookup_value.cnt, value.cnt);
+ "err:%d errno:%d lock:%x cnt:%x(%x)\n",
+ err, errno, lookup_value.lock, lookup_value.cnt, value.cnt);
/* Bump the cnt and update with BPF_EXIST */
value.cnt += 1;
+ value.lock = 2;
err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_EXIST);
CHECK(err, "bpf_map_update_elem(BPF_EXIST)",
"err:%d errno:%d\n", err, errno);
err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
BPF_F_LOCK);
- CHECK(err || lookup_value.cnt != value.cnt,
+ CHECK(err || lookup_value.lock || lookup_value.cnt != value.cnt,
"bpf_map_lookup_elem_flags(BPF_F_LOCK)",
- "err:%d errno:%d cnt:%x(%x)\n",
- err, errno, lookup_value.cnt, value.cnt);
+ "err:%d errno:%d lock:%x cnt:%x(%x)\n",
+ err, errno, lookup_value.lock, lookup_value.cnt, value.cnt);
/* Update with BPF_NOEXIST */
value.cnt += 1;
+ value.lock = 2;
err = bpf_map_update_elem(map_fd, &sk_fd, &value,
BPF_NOEXIST | BPF_F_LOCK);
CHECK(!err || errno != EEXIST,
@@ -526,22 +529,23 @@ static void test_sk_storage_map_basic(void)
value.cnt -= 1;
err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
BPF_F_LOCK);
- CHECK(err || lookup_value.cnt != value.cnt,
+ CHECK(err || lookup_value.lock || lookup_value.cnt != value.cnt,
"bpf_map_lookup_elem_flags(BPF_F_LOCK)",
- "err:%d errno:%d cnt:%x(%x)\n",
- err, errno, lookup_value.cnt, value.cnt);
+ "err:%d errno:%d lock:%x cnt:%x(%x)\n",
+ err, errno, lookup_value.lock, lookup_value.cnt, value.cnt);
/* Bump the cnt again and update with map_flags == 0 */
value.cnt += 1;
+ value.lock = 2;
err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
CHECK(err, "bpf_map_update_elem()", "err:%d errno:%d\n",
err, errno);
err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
BPF_F_LOCK);
- CHECK(err || lookup_value.cnt != value.cnt,
+ CHECK(err || lookup_value.lock || lookup_value.cnt != value.cnt,
"bpf_map_lookup_elem_flags(BPF_F_LOCK)",
- "err:%d errno:%d cnt:%x(%x)\n",
- err, errno, lookup_value.cnt, value.cnt);
+ "err:%d errno:%d lock:%x cnt:%x(%x)\n",
+ err, errno, lookup_value.lock, lookup_value.cnt, value.cnt);
/* Test delete elem */
err = bpf_map_delete_elem(map_fd, &sk_fd);
diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
index d457a55ff408..a4b4133d39e9 100644
--- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
@@ -358,10 +358,12 @@ static int get_syms(char ***symsp, size_t *cntp)
* We attach to almost all kernel functions and some of them
* will cause 'suspicious RCU usage' when fprobe is attached
* to them. Filter out the current culprits - arch_cpu_idle
- * and rcu_* functions.
+ * default_idle and rcu_* functions.
*/
if (!strcmp(name, "arch_cpu_idle"))
continue;
+ if (!strcmp(name, "default_idle"))
+ continue;
if (!strncmp(name, "rcu_", 4))
continue;
if (!strcmp(name, "bpf_dispatcher_xdp_func"))
@@ -400,7 +402,7 @@ error:
return err;
}
-static void test_bench_attach(void)
+void serial_test_kprobe_multi_bench_attach(void)
{
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
struct kprobe_multi_empty *skel = NULL;
@@ -468,6 +470,4 @@ void test_kprobe_multi_test(void)
test_attach_api_syms();
if (test__start_subtest("attach_api_fails"))
test_attach_api_fails();
- if (test__start_subtest("bench_attach"))
- test_bench_attach();
}
diff --git a/tools/testing/selftests/bpf/prog_tests/varlen.c b/tools/testing/selftests/bpf/prog_tests/varlen.c
index dd324b4933db..4d7056f8f177 100644
--- a/tools/testing/selftests/bpf/prog_tests/varlen.c
+++ b/tools/testing/selftests/bpf/prog_tests/varlen.c
@@ -63,6 +63,13 @@ void test_varlen(void)
CHECK_VAL(data->total4, size1 + size2);
CHECK(memcmp(data->payload4, exp_str, size1 + size2), "content_check",
"doesn't match!\n");
+
+ CHECK_VAL(bss->ret_bad_read, -EFAULT);
+ CHECK_VAL(data->payload_bad[0], 0x42);
+ CHECK_VAL(data->payload_bad[1], 0x42);
+ CHECK_VAL(data->payload_bad[2], 0);
+ CHECK_VAL(data->payload_bad[3], 0x42);
+ CHECK_VAL(data->payload_bad[4], 0x42);
cleanup:
test_varlen__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/progs/test_varlen.c b/tools/testing/selftests/bpf/progs/test_varlen.c
index 3987ff174f1f..20eb7d422c41 100644
--- a/tools/testing/selftests/bpf/progs/test_varlen.c
+++ b/tools/testing/selftests/bpf/progs/test_varlen.c
@@ -19,6 +19,7 @@ __u64 payload1_len1 = 0;
__u64 payload1_len2 = 0;
__u64 total1 = 0;
char payload1[MAX_LEN + MAX_LEN] = {};
+__u64 ret_bad_read = 0;
/* .data */
int payload2_len1 = -1;
@@ -36,6 +37,8 @@ int payload4_len2 = -1;
int total4= -1;
char payload4[MAX_LEN + MAX_LEN] = { 1 };
+char payload_bad[5] = { 0x42, 0x42, 0x42, 0x42, 0x42 };
+
SEC("raw_tp/sys_enter")
int handler64_unsigned(void *regs)
{
@@ -61,6 +64,8 @@ int handler64_unsigned(void *regs)
total1 = payload - (void *)payload1;
+ ret_bad_read = bpf_probe_read_kernel_str(payload_bad + 2, 1, (void *) -1);
+
return 0;
}
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 0e9a47f97890..3fef451d8831 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1010,7 +1010,7 @@ static inline const char *str_msg(const struct msg *msg, char *buf)
msg->subtest_done.have_log);
break;
case MSG_TEST_LOG:
- sprintf(buf, "MSG_TEST_LOG (cnt: %ld, last: %d)",
+ sprintf(buf, "MSG_TEST_LOG (cnt: %zu, last: %d)",
strlen(msg->test_log.log_buf),
msg->test_log.is_last);
break;
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 2dbcbf363c18..b605a70d4f6b 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -1260,7 +1260,7 @@ static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt)
bzero(&info, sizeof(info));
info.xlated_prog_len = xlated_prog_len;
- info.xlated_prog_insns = (__u64)*buf;
+ info.xlated_prog_insns = (__u64)(unsigned long)*buf;
if (bpf_obj_get_info_by_fd(fd_prog, &info, &info_len)) {
perror("second bpf_obj_get_info_by_fd failed");
goto out_free_buf;
diff --git a/tools/testing/selftests/bpf/verifier/ref_tracking.c b/tools/testing/selftests/bpf/verifier/ref_tracking.c
index f18ce867271f..fd683a32a276 100644
--- a/tools/testing/selftests/bpf/verifier/ref_tracking.c
+++ b/tools/testing/selftests/bpf/verifier/ref_tracking.c
@@ -1044,3 +1044,39 @@
.result_unpriv = REJECT,
.errstr_unpriv = "unknown func",
},
+{
+ "reference tracking: try to leak released ptr reg",
+ .insns = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ BPF_MOV64_REG(BPF_REG_9, BPF_REG_0),
+
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_MOV64_IMM(BPF_REG_2, 8),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_ringbuf_reserve),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
+
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_EMIT_CALL(BPF_FUNC_ringbuf_discard),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+
+ BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_8, 0),
+ BPF_EXIT_INSN()
+ },
+ .fixup_map_array_48b = { 4 },
+ .fixup_map_ringbuf = { 11 },
+ .result = ACCEPT,
+ .result_unpriv = REJECT,
+ .errstr_unpriv = "R8 !read_ok"
+},
diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c
index 4c52cc6f2f9c..e8bbbdb77e0d 100644
--- a/tools/testing/selftests/cgroup/cgroup_util.c
+++ b/tools/testing/selftests/cgroup/cgroup_util.c
@@ -555,6 +555,7 @@ int proc_mount_contains(const char *option)
ssize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t size)
{
char path[PATH_MAX];
+ ssize_t ret;
if (!pid)
snprintf(path, sizeof(path), "/proc/%s/%s",
@@ -562,8 +563,8 @@ ssize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t
else
snprintf(path, sizeof(path), "/proc/%d/%s", pid, item);
- size = read_text(path, buf, size);
- return size < 0 ? -1 : size;
+ ret = read_text(path, buf, size);
+ return ret < 0 ? -1 : ret;
}
int proc_read_strstr(int pid, bool thread, const char *item, const char *needle)
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 526d2c42d870..186e1c26867e 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -16,7 +16,12 @@ skip_test() {
[[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!"
# Set sched verbose flag, if available
-[[ -d /sys/kernel/debug/sched ]] && echo Y > /sys/kernel/debug/sched/verbose
+if [[ -d /sys/kernel/debug/sched ]]
+then
+ # Used to restore the original setting during cleanup
+ SCHED_DEBUG=$(cat /sys/kernel/debug/sched/verbose)
+ echo Y > /sys/kernel/debug/sched/verbose
+fi
# Get wait_inotify location
WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify
@@ -25,7 +30,7 @@ WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify
CGROUP2=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
[[ -n "$CGROUP2" ]] || skip_test "Cgroup v2 mount point not found!"
-CPUS=$(lscpu | grep "^CPU(s)" | sed -e "s/.*:[[:space:]]*//")
+CPUS=$(lscpu | grep "^CPU(s):" | sed -e "s/.*:[[:space:]]*//")
[[ $CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!"
# Set verbose flag and delay factor
@@ -54,6 +59,15 @@ echo +cpuset > cgroup.subtree_control
[[ -d test ]] || mkdir test
cd test
+cleanup()
+{
+ online_cpus
+ rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
+ cd ..
+ rmdir test > /dev/null 2>&1
+ echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose
+}
+
# Pause in ms
pause()
{
@@ -666,6 +680,7 @@ test_inotify()
fi
}
+trap cleanup 0 2 3 6
run_state_test TEST_MATRIX
test_isolated
test_inotify
diff --git a/tools/testing/selftests/cgroup/test_kmem.c b/tools/testing/selftests/cgroup/test_kmem.c
index 22b31ebb3513..258ddc565deb 100644
--- a/tools/testing/selftests/cgroup/test_kmem.c
+++ b/tools/testing/selftests/cgroup/test_kmem.c
@@ -19,12 +19,12 @@
/*
- * Memory cgroup charging is performed using percpu batches 32 pages
+ * Memory cgroup charging is performed using percpu batches 64 pages
* big (look at MEMCG_CHARGE_BATCH), whereas memory.stat is exact. So
* the maximum discrepancy between charge and vmstat entries is number
- * of cpus multiplied by 32 pages.
+ * of cpus multiplied by 64 pages.
*/
-#define MAX_VMSTAT_ERROR (4096 * 32 * get_nprocs())
+#define MAX_VMSTAT_ERROR (4096 * 64 * get_nprocs())
static int alloc_dcache(const char *cgroup, void *arg)
diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh
index a90f394f9aa9..d374878cc0ba 100755
--- a/tools/testing/selftests/efivarfs/efivarfs.sh
+++ b/tools/testing/selftests/efivarfs/efivarfs.sh
@@ -87,6 +87,11 @@ test_create_read()
{
local file=$efivarfs_mount/$FUNCNAME-$test_guid
./create-read $file
+ if [ $? -ne 0 ]; then
+ echo "create and read $file failed"
+ file_cleanup $file
+ exit 1
+ fi
file_cleanup $file
}
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
index 8d26d5505808..3eea2abf68f9 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
@@ -38,11 +38,18 @@ cnt_trace() {
test_event_enabled() {
val=$1
+ check_times=10 # wait for 10 * SLEEP_TIME at most
- e=`cat $EVENT_ENABLE`
- if [ "$e" != $val ]; then
- fail "Expected $val but found $e"
- fi
+ while [ $check_times -ne 0 ]; do
+ e=`cat $EVENT_ENABLE`
+ if [ "$e" == $val ]; then
+ return 0
+ fi
+ sleep $SLEEP_TIME
+ check_times=$((check_times - 1))
+ done
+
+ fail "Expected $val but found $e"
}
run_enable_disable() {
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 5f6cbec847fc..779f3e62ec90 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -142,9 +142,15 @@ finish_ftrace() {
check_requires() { # Check required files and tracers
for i in "$@" ; do
+ p=${i%:program}
r=${i%:README}
t=${i%:tracer}
- if [ $t != $i ]; then
+ if [ $p != $i ]; then
+ if ! which $p ; then
+ echo "Required program $p is not found."
+ exit_unresolved
+ fi
+ elif [ $t != $i ]; then
if ! grep -wq $t available_tracers ; then
echo "Required tracer $t is not configured."
exit_unsupported
diff --git a/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc b/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc
index 22bff122b933..ba1038953873 100644
--- a/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc
+++ b/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc
@@ -46,10 +46,10 @@ cat trace
grep -q "tracer: preemptoff" trace || fail
# Check the end of the section
-egrep -q "5.....us : <stack trace>" trace || fail
+grep -E -q "5.....us : <stack trace>" trace || fail
# Check for 500ms of latency
-egrep -q "latency: 5..... us" trace || fail
+grep -E -q "latency: 5..... us" trace || fail
reset_tracer
@@ -69,10 +69,10 @@ cat trace
grep -q "tracer: irqsoff" trace || fail
# Check the end of the section
-egrep -q "5.....us : <stack trace>" trace || fail
+grep -E -q "5.....us : <stack trace>" trace || fail
# Check for 500ms of latency
-egrep -q "latency: 5..... us" trace || fail
+grep -E -q "latency: 5..... us" trace || fail
reset_tracer
exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc b/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
index 11be10e1bf96..e8f0fac9a110 100644
--- a/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
+++ b/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
@@ -1,12 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test wakeup tracer
-# requires: wakeup:tracer
-
-if ! which chrt ; then
- echo "chrt is not found. This test requires nice command."
- exit_unresolved
-fi
+# requires: wakeup:tracer chrt:program
echo wakeup > current_tracer
echo 1 > tracing_on
diff --git a/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc b/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
index 3a77198b3c69..79807656785b 100644
--- a/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
+++ b/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
@@ -1,12 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test wakeup RT tracer
-# requires: wakeup_rt:tracer
-
-if ! which chrt ; then
- echo "chrt is not found. This test requires chrt command."
- exit_unresolved
-fi
+# requires: wakeup_rt:tracer chrt:program
echo wakeup_rt > current_tracer
echo 1 > tracing_on
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc
index 41119e0440e9..04c5dd7d0acc 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test field variable support
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc
index 9098f1e7433f..f7447d800899 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event combined histogram trigger
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc
index adaabb873ed4..91339c130832 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger onchange action
-# requires: set_event "onchange(var)":README
+# requires: set_event "onchange(var)":README ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc
index 20e39471052e..d645abcf11c4 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger onmatch action
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc
index f4b03ab7c287..c369247efb35 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger onmatch-onmax action
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc
index 71c9b5911c70..e28dc5f11b2b 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger onmax action
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc
index 67fa328b830f..147967e86584 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger snapshot action
-# requires: set_event snapshot events/sched/sched_process_fork/hist "onchange(var)":README "snapshot()":README
+# requires: set_event snapshot events/sched/sched_process_fork/hist "onchange(var)":README "snapshot()":README ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-eprobe.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-eprobe.tc
index 6461c375694f..c2a8ab01e13b 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-eprobe.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-eprobe.tc
@@ -14,7 +14,7 @@ FIELD="filename"
SYNTH="synth_open"
EPROBE="eprobe_open"
-echo "$SYNTH u64 filename; s64 ret;" > synthetic_events
+echo "$SYNTH unsigned long filename; long ret;" > synthetic_events
echo "hist:keys=common_pid:__arg__1=$FIELD" > events/$SYSTEM/$START/trigger
echo "hist:keys=common_pid:filename=\$__arg__1,ret=ret:onmatch($SYSTEM.$START).trace($SYNTH,\$filename,\$ret)" > events/$SYSTEM/$END/trigger
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-dynstring.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-dynstring.tc
index 3d65c856eca3..213d890ed188 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-dynstring.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-dynstring.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger trace action with dynamic string param
-# requires: set_event synthetic_events events/sched/sched_process_exec/hist "char name[]' >> synthetic_events":README
+# requires: set_event synthetic_events events/sched/sched_process_exec/hist "char name[]' >> synthetic_events":README ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc
index c126d2350a6d..d7312047ce28 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger trace action
-# requires: set_event synthetic_events events/sched/sched_process_fork/hist "trace(<synthetic_event>":README
+# requires: set_event synthetic_events events/sched/sched_process_fork/hist "trace(<synthetic_event>":README ping:program
fail() { #msg
echo $1
diff --git a/tools/testing/selftests/gpio/gpio-sim.sh b/tools/testing/selftests/gpio/gpio-sim.sh
index 341e3de00896..9f539d454ee4 100755
--- a/tools/testing/selftests/gpio/gpio-sim.sh
+++ b/tools/testing/selftests/gpio/gpio-sim.sh
@@ -27,7 +27,7 @@ remove_chip() {
continue
fi
- LINES=`ls $CONFIGFS_DIR/$CHIP/$BANK/ | egrep ^line`
+ LINES=`ls $CONFIGFS_DIR/$CHIP/$BANK/ | grep -E ^line`
if [ "$?" = 0 ]; then
for LINE in $LINES; do
if [ -e $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog ]; then
diff --git a/tools/testing/selftests/kselftest_deps.sh b/tools/testing/selftests/kselftest_deps.sh
index 708cb5429633..7424a1f5babc 100755
--- a/tools/testing/selftests/kselftest_deps.sh
+++ b/tools/testing/selftests/kselftest_deps.sh
@@ -90,7 +90,7 @@ pass_libs=()
pass_cnt=0
# Get all TARGETS from selftests Makefile
-targets=$(egrep "^TARGETS +|^TARGETS =" Makefile | cut -d "=" -f2)
+targets=$(grep -E "^TARGETS +|^TARGETS =" Makefile | cut -d "=" -f2)
# Single test case
if [ $# -eq 2 ]
diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 2f0d705db9db..05d980fb083d 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -41,6 +41,7 @@
/x86_64/svm_vmcall_test
/x86_64/svm_int_ctl_test
/x86_64/svm_nested_soft_inject_test
+/x86_64/svm_nested_shutdown_test
/x86_64/sync_regs_test
/x86_64/tsc_msrs_test
/x86_64/tsc_scaling_sync
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 0172eb6cb6ee..4a2caef2c939 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -101,6 +101,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/state_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test
TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test
TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test
+TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_shutdown_test
TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_soft_inject_test
TEST_GEN_PROGS_x86_64 += x86_64/tsc_scaling_sync
TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index e8ca0d8a6a7e..5da0c5e2a7af 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -748,6 +748,19 @@ struct ex_regs {
uint64_t rflags;
};
+struct idt_entry {
+ uint16_t offset0;
+ uint16_t selector;
+ uint16_t ist : 3;
+ uint16_t : 5;
+ uint16_t type : 4;
+ uint16_t : 1;
+ uint16_t dpl : 2;
+ uint16_t p : 1;
+ uint16_t offset1;
+ uint32_t offset2; uint32_t reserved;
+};
+
void vm_init_descriptor_tables(struct kvm_vm *vm);
void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
void vm_install_exception_handler(struct kvm_vm *vm, int vector,
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c
index 39c4409ef56a..41c1c73c464d 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c
@@ -1074,19 +1074,6 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
}
}
-struct idt_entry {
- uint16_t offset0;
- uint16_t selector;
- uint16_t ist : 3;
- uint16_t : 5;
- uint16_t type : 4;
- uint16_t : 1;
- uint16_t dpl : 2;
- uint16_t p : 1;
- uint16_t offset1;
- uint32_t offset2; uint32_t reserved;
-};
-
static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr,
int dpl, unsigned short selector)
{
diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_shutdown_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_shutdown_test.c
new file mode 100644
index 000000000000..e73fcdef47bb
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/svm_nested_shutdown_test.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * svm_nested_shutdown_test
+ *
+ * Copyright (C) 2022, Red Hat, Inc.
+ *
+ * Nested SVM testing: test that unintercepted shutdown in L2 doesn't crash the host
+ */
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "svm_util.h"
+
+static void l2_guest_code(struct svm_test_data *svm)
+{
+ __asm__ __volatile__("ud2");
+}
+
+static void l1_guest_code(struct svm_test_data *svm, struct idt_entry *idt)
+{
+ #define L2_GUEST_STACK_SIZE 64
+ unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+ struct vmcb *vmcb = svm->vmcb;
+
+ generic_svm_setup(svm, l2_guest_code,
+ &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+ vmcb->control.intercept &= ~(BIT(INTERCEPT_SHUTDOWN));
+
+ idt[6].p = 0; // #UD is intercepted but its injection will cause #NP
+ idt[11].p = 0; // #NP is not intercepted and will cause another
+ // #NP that will be converted to #DF
+ idt[8].p = 0; // #DF will cause #NP which will cause SHUTDOWN
+
+ run_guest(vmcb, svm->vmcb_gpa);
+
+ /* should not reach here */
+ GUEST_ASSERT(0);
+}
+
+int main(int argc, char *argv[])
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_run *run;
+ vm_vaddr_t svm_gva;
+ struct kvm_vm *vm;
+
+ TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
+
+ vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
+ vm_init_descriptor_tables(vm);
+ vcpu_init_descriptor_tables(vcpu);
+
+ vcpu_alloc_svm(vm, &svm_gva);
+
+ vcpu_args_set(vcpu, 2, svm_gva, vm->idt);
+ run = vcpu->run;
+
+ vcpu_run(vcpu);
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
+ "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n",
+ run->exit_reason,
+ exit_reason_str(run->exit_reason));
+
+ kvm_vm_free(vm);
+}
diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c
index 70b44f0b52fe..ead5d878a71c 100644
--- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c
+++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c
@@ -3,6 +3,7 @@
#include "kvm_util.h"
#include "processor.h"
#include "vmx.h"
+#include "svm_util.h"
#include <string.h>
#include <sys/ioctl.h>
@@ -20,10 +21,11 @@ static void l2_guest_code(void)
: : [port] "d" (ARBITRARY_IO_PORT) : "rax");
}
-void l1_guest_code(struct vmx_pages *vmx)
-{
#define L2_GUEST_STACK_SIZE 64
- unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+
+void l1_guest_code_vmx(struct vmx_pages *vmx)
+{
GUEST_ASSERT(vmx->vmcs_gpa);
GUEST_ASSERT(prepare_for_vmx_operation(vmx));
@@ -38,24 +40,53 @@ void l1_guest_code(struct vmx_pages *vmx)
GUEST_DONE();
}
+void l1_guest_code_svm(struct svm_test_data *svm)
+{
+ struct vmcb *vmcb = svm->vmcb;
+
+ generic_svm_setup(svm, l2_guest_code,
+ &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+ /* don't intercept shutdown to test the case of SVM allowing to do so */
+ vmcb->control.intercept &= ~(BIT(INTERCEPT_SHUTDOWN));
+
+ run_guest(vmcb, svm->vmcb_gpa);
+
+ /* should not reach here, L1 should crash */
+ GUEST_ASSERT(0);
+}
+
int main(void)
{
struct kvm_vcpu *vcpu;
struct kvm_run *run;
struct kvm_vcpu_events events;
- vm_vaddr_t vmx_pages_gva;
struct ucall uc;
- TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
+ bool has_vmx = kvm_cpu_has(X86_FEATURE_VMX);
+ bool has_svm = kvm_cpu_has(X86_FEATURE_SVM);
+
+ TEST_REQUIRE(has_vmx || has_svm);
TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT));
- vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
- vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1);
+ if (has_vmx) {
+ vm_vaddr_t vmx_pages_gva;
+
+ vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code_vmx);
+ vcpu_alloc_vmx(vm, &vmx_pages_gva);
+ vcpu_args_set(vcpu, 1, vmx_pages_gva);
+ } else {
+ vm_vaddr_t svm_gva;
+
+ vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code_svm);
+ vcpu_alloc_svm(vm, &svm_gva);
+ vcpu_args_set(vcpu, 1, svm_gva);
+ }
+
+ vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1);
run = vcpu->run;
- vcpu_alloc_vmx(vm, &vmx_pages_gva);
- vcpu_args_set(vcpu, 1, vmx_pages_gva);
vcpu_run(vcpu);
TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
@@ -78,13 +109,21 @@ int main(void)
"No triple fault pending");
vcpu_run(vcpu);
- switch (get_ucall(vcpu, &uc)) {
- case UCALL_DONE:
- break;
- case UCALL_ABORT:
- REPORT_GUEST_ASSERT(uc);
- default:
- TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
- }
+ if (has_svm) {
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
+ "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n",
+ run->exit_reason,
+ exit_reason_str(run->exit_reason));
+ } else {
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_DONE:
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ default:
+ TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
+ }
+ }
+ return 0;
}
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index da9290817866..792c3f0a59b4 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -75,7 +75,7 @@ TEST(abi_version)
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
- ASSERT_EQ(2, landlock_create_ruleset(NULL, 0,
+ ASSERT_EQ(3, landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
@@ -263,23 +263,6 @@ TEST(ruleset_fd_transfer)
.allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
};
int ruleset_fd_tx, dir_fd;
- union {
- /* Aligned ancillary data buffer. */
- char buf[CMSG_SPACE(sizeof(ruleset_fd_tx))];
- struct cmsghdr _align;
- } cmsg_tx = {};
- char data_tx = '.';
- struct iovec io = {
- .iov_base = &data_tx,
- .iov_len = sizeof(data_tx),
- };
- struct msghdr msg = {
- .msg_iov = &io,
- .msg_iovlen = 1,
- .msg_control = &cmsg_tx.buf,
- .msg_controllen = sizeof(cmsg_tx.buf),
- };
- struct cmsghdr *cmsg;
int socket_fds[2];
pid_t child;
int status;
@@ -298,33 +281,20 @@ TEST(ruleset_fd_transfer)
&path_beneath_attr, 0));
ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
- cmsg = CMSG_FIRSTHDR(&msg);
- ASSERT_NE(NULL, cmsg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(ruleset_fd_tx));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsg), &ruleset_fd_tx, sizeof(ruleset_fd_tx));
-
/* Sends the ruleset FD over a socketpair and then close it. */
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
socket_fds));
- ASSERT_EQ(sizeof(data_tx), sendmsg(socket_fds[0], &msg, 0));
+ ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx));
ASSERT_EQ(0, close(socket_fds[0]));
ASSERT_EQ(0, close(ruleset_fd_tx));
child = fork();
ASSERT_LE(0, child);
if (child == 0) {
- int ruleset_fd_rx;
+ const int ruleset_fd_rx = recv_fd(socket_fds[1]);
- *(char *)msg.msg_iov->iov_base = '\0';
- ASSERT_EQ(sizeof(data_tx),
- recvmsg(socket_fds[1], &msg, MSG_CMSG_CLOEXEC));
- ASSERT_EQ('.', *(char *)msg.msg_iov->iov_base);
+ ASSERT_LE(0, ruleset_fd_rx);
ASSERT_EQ(0, close(socket_fds[1]));
- cmsg = CMSG_FIRSTHDR(&msg);
- ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(ruleset_fd_tx)));
- memcpy(&ruleset_fd_rx, CMSG_DATA(cmsg), sizeof(ruleset_fd_tx));
/* Enforces the received ruleset on the child. */
ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h
index 7ba18eb23783..d7987ae8d7fc 100644
--- a/tools/testing/selftests/landlock/common.h
+++ b/tools/testing/selftests/landlock/common.h
@@ -10,6 +10,7 @@
#include <errno.h>
#include <linux/landlock.h>
#include <sys/capability.h>
+#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -17,6 +18,10 @@
#include "../kselftest_harness.h"
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+#endif
+
/*
* TEST_F_FORK() is useful when a test drop privileges but the corresponding
* FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory
@@ -140,14 +145,12 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
}
/* We cannot put such helpers in a library because of kselftest_harness.h . */
-__attribute__((__unused__)) static void
-disable_caps(struct __test_metadata *const _metadata)
+static void __maybe_unused disable_caps(struct __test_metadata *const _metadata)
{
_init_caps(_metadata, false);
}
-__attribute__((__unused__)) static void
-drop_caps(struct __test_metadata *const _metadata)
+static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
{
_init_caps(_metadata, true);
}
@@ -176,14 +179,80 @@ static void _effective_cap(struct __test_metadata *const _metadata,
}
}
-__attribute__((__unused__)) static void
-set_cap(struct __test_metadata *const _metadata, const cap_value_t caps)
+static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
+ const cap_value_t caps)
{
_effective_cap(_metadata, caps, CAP_SET);
}
-__attribute__((__unused__)) static void
-clear_cap(struct __test_metadata *const _metadata, const cap_value_t caps)
+static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
+ const cap_value_t caps)
{
_effective_cap(_metadata, caps, CAP_CLEAR);
}
+
+/* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */
+static int __maybe_unused recv_fd(int usock)
+{
+ int fd_rx;
+ union {
+ /* Aligned ancillary data buffer. */
+ char buf[CMSG_SPACE(sizeof(fd_rx))];
+ struct cmsghdr _align;
+ } cmsg_rx = {};
+ char data = '\0';
+ struct iovec io = {
+ .iov_base = &data,
+ .iov_len = sizeof(data),
+ };
+ struct msghdr msg = {
+ .msg_iov = &io,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg_rx.buf,
+ .msg_controllen = sizeof(cmsg_rx.buf),
+ };
+ struct cmsghdr *cmsg;
+ int res;
+
+ res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC);
+ if (res < 0)
+ return -errno;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx)))
+ return -EIO;
+
+ memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx));
+ return fd_rx;
+}
+
+/* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */
+static int __maybe_unused send_fd(int usock, int fd_tx)
+{
+ union {
+ /* Aligned ancillary data buffer. */
+ char buf[CMSG_SPACE(sizeof(fd_tx))];
+ struct cmsghdr _align;
+ } cmsg_tx = {};
+ char data_tx = '.';
+ struct iovec io = {
+ .iov_base = &data_tx,
+ .iov_len = sizeof(data_tx),
+ };
+ struct msghdr msg = {
+ .msg_iov = &io,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg_tx.buf,
+ .msg_controllen = sizeof(cmsg_tx.buf),
+ };
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx));
+
+ if (sendmsg(usock, &msg, 0) < 0)
+ return -errno;
+ return 0;
+}
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 45de42a027c5..d5dab986f612 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -58,6 +58,7 @@ static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
static const char dir_s3d1[] = TMP_DIR "/s3d1";
+static const char file1_s3d1[] = TMP_DIR "/s3d1/f1";
/* dir_s3d2 is a mount point. */
static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
@@ -83,6 +84,7 @@ static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
* │   ├── f1
* │   └── f2
* └── s3d1
+ *    ├── f1
* └── s3d2
* └── s3d3
*/
@@ -208,6 +210,7 @@ static void create_layout1(struct __test_metadata *const _metadata)
create_file(_metadata, file1_s2d3);
create_file(_metadata, file2_s2d3);
+ create_file(_metadata, file1_s3d1);
create_directory(_metadata, dir_s3d2);
set_cap(_metadata, CAP_SYS_ADMIN);
ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700"));
@@ -230,6 +233,7 @@ static void remove_layout1(struct __test_metadata *const _metadata)
EXPECT_EQ(0, remove_path(file1_s2d2));
EXPECT_EQ(0, remove_path(file1_s2d1));
+ EXPECT_EQ(0, remove_path(file1_s3d1));
EXPECT_EQ(0, remove_path(dir_s3d3));
set_cap(_metadata, CAP_SYS_ADMIN);
umount(dir_s3d2);
@@ -406,9 +410,10 @@ TEST_F_FORK(layout1, inval)
#define ACCESS_FILE ( \
LANDLOCK_ACCESS_FS_EXECUTE | \
LANDLOCK_ACCESS_FS_WRITE_FILE | \
- LANDLOCK_ACCESS_FS_READ_FILE)
+ LANDLOCK_ACCESS_FS_READ_FILE | \
+ LANDLOCK_ACCESS_FS_TRUNCATE)
-#define ACCESS_LAST LANDLOCK_ACCESS_FS_REFER
+#define ACCESS_LAST LANDLOCK_ACCESS_FS_TRUNCATE
#define ACCESS_ALL ( \
ACCESS_FILE | \
@@ -422,7 +427,7 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_MAKE_FIFO | \
LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
LANDLOCK_ACCESS_FS_MAKE_SYM | \
- ACCESS_LAST)
+ LANDLOCK_ACCESS_FS_REFER)
/* clang-format on */
@@ -3157,6 +3162,463 @@ TEST_F_FORK(layout1, proc_pipe)
ASSERT_EQ(0, close(pipe_fds[1]));
}
+/* Invokes truncate(2) and returns its errno or 0. */
+static int test_truncate(const char *const path)
+{
+ if (truncate(path, 10) < 0)
+ return errno;
+ return 0;
+}
+
+/*
+ * Invokes creat(2) and returns its errno or 0.
+ * Closes the opened file descriptor on success.
+ */
+static int test_creat(const char *const path)
+{
+ int fd = creat(path, 0600);
+
+ if (fd < 0)
+ return errno;
+
+ /*
+ * Mixing error codes from close(2) and creat(2) should not lead to any
+ * (access type) confusion for this test.
+ */
+ if (close(fd) < 0)
+ return errno;
+ return 0;
+}
+
+/*
+ * Exercises file truncation when it's not restricted,
+ * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed.
+ */
+TEST_F_FORK(layout1, truncate_unhandled)
+{
+ const char *const file_r = file1_s1d1;
+ const char *const file_w = file2_s1d1;
+ const char *const file_none = file1_s1d2;
+ const struct rule rules[] = {
+ {
+ .path = file_r,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE,
+ },
+ {
+ .path = file_w,
+ .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ /* Implicitly: No rights for file_none. */
+ {},
+ };
+
+ const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE;
+ int ruleset_fd;
+
+ /* Enable Landlock. */
+ ruleset_fd = create_ruleset(_metadata, handled, rules);
+
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /*
+ * Checks read right: truncate and open with O_TRUNC work, unless the
+ * file is attempted to be opened for writing.
+ */
+ EXPECT_EQ(0, test_truncate(file_r));
+ EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_creat(file_r));
+
+ /*
+ * Checks write right: truncate and open with O_TRUNC work, unless the
+ * file is attempted to be opened for reading.
+ */
+ EXPECT_EQ(0, test_truncate(file_w));
+ EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC));
+ EXPECT_EQ(0, test_creat(file_w));
+
+ /*
+ * Checks "no rights" case: truncate works but all open attempts fail,
+ * including creat.
+ */
+ EXPECT_EQ(0, test_truncate(file_none));
+ EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_creat(file_none));
+}
+
+TEST_F_FORK(layout1, truncate)
+{
+ const char *const file_rwt = file1_s1d1;
+ const char *const file_rw = file2_s1d1;
+ const char *const file_rt = file1_s1d2;
+ const char *const file_t = file2_s1d2;
+ const char *const file_none = file1_s1d3;
+ const char *const dir_t = dir_s2d1;
+ const char *const file_in_dir_t = file1_s2d1;
+ const char *const dir_w = dir_s3d1;
+ const char *const file_in_dir_w = file1_s3d1;
+ const struct rule rules[] = {
+ {
+ .path = file_rwt,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_TRUNCATE,
+ },
+ {
+ .path = file_rw,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {
+ .path = file_rt,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_TRUNCATE,
+ },
+ {
+ .path = file_t,
+ .access = LANDLOCK_ACCESS_FS_TRUNCATE,
+ },
+ /* Implicitly: No access rights for file_none. */
+ {
+ .path = dir_t,
+ .access = LANDLOCK_ACCESS_FS_TRUNCATE,
+ },
+ {
+ .path = dir_w,
+ .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {},
+ };
+ const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_TRUNCATE;
+ int ruleset_fd;
+
+ /* Enable Landlock. */
+ ruleset_fd = create_ruleset(_metadata, handled, rules);
+
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* Checks read, write and truncate rights: truncation works. */
+ EXPECT_EQ(0, test_truncate(file_rwt));
+ EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC));
+
+ /* Checks read and write rights: no truncate variant works. */
+ EXPECT_EQ(EACCES, test_truncate(file_rw));
+ EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC));
+
+ /*
+ * Checks read and truncate rights: truncation works.
+ *
+ * Note: Files can get truncated using open() even with O_RDONLY.
+ */
+ EXPECT_EQ(0, test_truncate(file_rt));
+ EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC));
+
+ /* Checks truncate right: truncate works, but can't open file. */
+ EXPECT_EQ(0, test_truncate(file_t));
+ EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC));
+
+ /* Checks "no rights" case: No form of truncation works. */
+ EXPECT_EQ(EACCES, test_truncate(file_none));
+ EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
+
+ /*
+ * Checks truncate right on directory: truncate works on contained
+ * files.
+ */
+ EXPECT_EQ(0, test_truncate(file_in_dir_t));
+ EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC));
+ EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC));
+
+ /*
+ * Checks creat in dir_w: This requires the truncate right when
+ * overwriting an existing file, but does not require it when the file
+ * is new.
+ */
+ EXPECT_EQ(EACCES, test_creat(file_in_dir_w));
+
+ ASSERT_EQ(0, unlink(file_in_dir_w));
+ EXPECT_EQ(0, test_creat(file_in_dir_w));
+}
+
+/* Invokes ftruncate(2) and returns its errno or 0. */
+static int test_ftruncate(int fd)
+{
+ if (ftruncate(fd, 10) < 0)
+ return errno;
+ return 0;
+}
+
+TEST_F_FORK(layout1, ftruncate)
+{
+ /*
+ * This test opens a new file descriptor at different stages of
+ * Landlock restriction:
+ *
+ * without restriction: ftruncate works
+ * something else but truncate restricted: ftruncate works
+ * truncate restricted and permitted: ftruncate works
+ * truncate restricted and not permitted: ftruncate fails
+ *
+ * Whether this works or not is expected to depend on the time when the
+ * FD was opened, not to depend on the time when ftruncate() was
+ * called.
+ */
+ const char *const path = file1_s1d1;
+ const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE;
+ const struct rule layer1[] = {
+ {
+ .path = path,
+ .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {},
+ };
+ const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE;
+ const struct rule layer2[] = {
+ {
+ .path = path,
+ .access = LANDLOCK_ACCESS_FS_TRUNCATE,
+ },
+ {},
+ };
+ const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE;
+ const struct rule layer3[] = {
+ {
+ .path = path,
+ .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {},
+ };
+ int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd;
+
+ fd_layer0 = open(path, O_WRONLY);
+ EXPECT_EQ(0, test_ftruncate(fd_layer0));
+
+ ruleset_fd = create_ruleset(_metadata, handled1, layer1);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ fd_layer1 = open(path, O_WRONLY);
+ EXPECT_EQ(0, test_ftruncate(fd_layer0));
+ EXPECT_EQ(0, test_ftruncate(fd_layer1));
+
+ ruleset_fd = create_ruleset(_metadata, handled2, layer2);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ fd_layer2 = open(path, O_WRONLY);
+ EXPECT_EQ(0, test_ftruncate(fd_layer0));
+ EXPECT_EQ(0, test_ftruncate(fd_layer1));
+ EXPECT_EQ(0, test_ftruncate(fd_layer2));
+
+ ruleset_fd = create_ruleset(_metadata, handled3, layer3);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ fd_layer3 = open(path, O_WRONLY);
+ EXPECT_EQ(0, test_ftruncate(fd_layer0));
+ EXPECT_EQ(0, test_ftruncate(fd_layer1));
+ EXPECT_EQ(0, test_ftruncate(fd_layer2));
+ EXPECT_EQ(EACCES, test_ftruncate(fd_layer3));
+
+ ASSERT_EQ(0, close(fd_layer0));
+ ASSERT_EQ(0, close(fd_layer1));
+ ASSERT_EQ(0, close(fd_layer2));
+ ASSERT_EQ(0, close(fd_layer3));
+}
+
+/* clang-format off */
+FIXTURE(ftruncate) {};
+/* clang-format on */
+
+FIXTURE_SETUP(ftruncate)
+{
+ prepare_layout(_metadata);
+ create_file(_metadata, file1_s1d1);
+}
+
+FIXTURE_TEARDOWN(ftruncate)
+{
+ EXPECT_EQ(0, remove_path(file1_s1d1));
+ cleanup_layout(_metadata);
+}
+
+FIXTURE_VARIANT(ftruncate)
+{
+ const __u64 handled;
+ const __u64 permitted;
+ const int expected_open_result;
+ const int expected_ftruncate_result;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(ftruncate, w_w) {
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ .expected_open_result = 0,
+ .expected_ftruncate_result = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(ftruncate, t_t) {
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_TRUNCATE,
+ .permitted = LANDLOCK_ACCESS_FS_TRUNCATE,
+ .expected_open_result = 0,
+ .expected_ftruncate_result = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(ftruncate, wt_w) {
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
+ .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE,
+ .expected_open_result = 0,
+ .expected_ftruncate_result = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(ftruncate, wt_wt) {
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
+ .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_TRUNCATE,
+ .expected_open_result = 0,
+ .expected_ftruncate_result = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(ftruncate, wt_t) {
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
+ .permitted = LANDLOCK_ACCESS_FS_TRUNCATE,
+ .expected_open_result = EACCES,
+};
+
+TEST_F_FORK(ftruncate, open_and_ftruncate)
+{
+ const char *const path = file1_s1d1;
+ const struct rule rules[] = {
+ {
+ .path = path,
+ .access = variant->permitted,
+ },
+ {},
+ };
+ int fd, ruleset_fd;
+
+ /* Enable Landlock. */
+ ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ fd = open(path, O_WRONLY);
+ EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
+ if (fd >= 0) {
+ EXPECT_EQ(variant->expected_ftruncate_result,
+ test_ftruncate(fd));
+ ASSERT_EQ(0, close(fd));
+ }
+}
+
+TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
+{
+ int child, fd, status;
+ int socket_fds[2];
+
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
+ socket_fds));
+
+ child = fork();
+ ASSERT_LE(0, child);
+ if (child == 0) {
+ /*
+ * Enables Landlock in the child process, open a file descriptor
+ * where truncation is forbidden and send it to the
+ * non-landlocked parent process.
+ */
+ const char *const path = file1_s1d1;
+ const struct rule rules[] = {
+ {
+ .path = path,
+ .access = variant->permitted,
+ },
+ {},
+ };
+ int fd, ruleset_fd;
+
+ ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ fd = open(path, O_WRONLY);
+ ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
+
+ if (fd >= 0) {
+ ASSERT_EQ(0, send_fd(socket_fds[0], fd));
+ ASSERT_EQ(0, close(fd));
+ }
+
+ ASSERT_EQ(0, close(socket_fds[0]));
+
+ _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+ return;
+ }
+
+ if (variant->expected_open_result == 0) {
+ fd = recv_fd(socket_fds[1]);
+ ASSERT_LE(0, fd);
+
+ EXPECT_EQ(variant->expected_ftruncate_result,
+ test_ftruncate(fd));
+ ASSERT_EQ(0, close(fd));
+ }
+
+ ASSERT_EQ(child, waitpid(child, &status, 0));
+ ASSERT_EQ(1, WIFEXITED(status));
+ ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+
+ ASSERT_EQ(0, close(socket_fds[0]));
+ ASSERT_EQ(0, close(socket_fds[1]));
+}
+
+TEST(memfd_ftruncate)
+{
+ int fd;
+
+ fd = memfd_create("name", MFD_CLOEXEC);
+ ASSERT_LE(0, fd);
+
+ /*
+ * Checks that ftruncate is permitted on file descriptors that are
+ * created in ways other than open(2).
+ */
+ EXPECT_EQ(0, test_ftruncate(fd));
+
+ ASSERT_EQ(0, close(fd));
+}
+
/* clang-format off */
FIXTURE(layout1_bind) {};
/* clang-format on */
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index a3ea3d4a206d..291144c284fb 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -123,6 +123,11 @@ endef
clean:
$(CLEAN)
+# Enables to extend CFLAGS and LDFLAGS from command line, e.g.
+# make USERCFLAGS=-Werror USERLDFLAGS=-static
+CFLAGS += $(USERCFLAGS)
+LDFLAGS += $(USERLDFLAGS)
+
# When make O= with kselftest target from main level
# the following aren't defined.
#
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 3d7adee7a3e6..ff8fe93f679c 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
bind_bhash
cmsg_sender
+diag_uid
fin_ack_lat
gro
hwtstamp_config
diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile
index 969620ae9928..1e4b397cece6 100644
--- a/tools/testing/selftests/net/af_unix/Makefile
+++ b/tools/testing/selftests/net/af_unix/Makefile
@@ -1,3 +1,3 @@
-TEST_GEN_PROGS := test_unix_oob unix_connect
+TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect
include ../../lib.mk
diff --git a/tools/testing/selftests/net/af_unix/diag_uid.c b/tools/testing/selftests/net/af_unix/diag_uid.c
new file mode 100644
index 000000000000..5b88f7129fea
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/diag_uid.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates. */
+
+#define _GNU_SOURCE
+#include <sched.h>
+
+#include <unistd.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/sock_diag.h>
+#include <linux/unix_diag.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "../../kselftest_harness.h"
+
+FIXTURE(diag_uid)
+{
+ int netlink_fd;
+ int unix_fd;
+ __u32 inode;
+ __u64 cookie;
+};
+
+FIXTURE_VARIANT(diag_uid)
+{
+ int unshare;
+ int udiag_show;
+};
+
+FIXTURE_VARIANT_ADD(diag_uid, uid)
+{
+ .unshare = 0,
+ .udiag_show = UDIAG_SHOW_UID
+};
+
+FIXTURE_VARIANT_ADD(diag_uid, uid_unshare)
+{
+ .unshare = CLONE_NEWUSER,
+ .udiag_show = UDIAG_SHOW_UID
+};
+
+FIXTURE_SETUP(diag_uid)
+{
+ struct stat file_stat;
+ socklen_t optlen;
+ int ret;
+
+ if (variant->unshare)
+ ASSERT_EQ(unshare(variant->unshare), 0);
+
+ self->netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
+ ASSERT_NE(self->netlink_fd, -1);
+
+ self->unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_NE(self->unix_fd, -1);
+
+ ret = fstat(self->unix_fd, &file_stat);
+ ASSERT_EQ(ret, 0);
+
+ self->inode = file_stat.st_ino;
+
+ optlen = sizeof(self->cookie);
+ ret = getsockopt(self->unix_fd, SOL_SOCKET, SO_COOKIE, &self->cookie, &optlen);
+ ASSERT_EQ(ret, 0);
+}
+
+FIXTURE_TEARDOWN(diag_uid)
+{
+ close(self->netlink_fd);
+ close(self->unix_fd);
+}
+
+int send_request(struct __test_metadata *_metadata,
+ FIXTURE_DATA(diag_uid) *self,
+ const FIXTURE_VARIANT(diag_uid) *variant)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct unix_diag_req udr;
+ } req = {
+ .nlh = {
+ .nlmsg_len = sizeof(req),
+ .nlmsg_type = SOCK_DIAG_BY_FAMILY,
+ .nlmsg_flags = NLM_F_REQUEST
+ },
+ .udr = {
+ .sdiag_family = AF_UNIX,
+ .udiag_ino = self->inode,
+ .udiag_cookie = {
+ (__u32)self->cookie,
+ (__u32)(self->cookie >> 32)
+ },
+ .udiag_show = variant->udiag_show
+ }
+ };
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK
+ };
+ struct iovec iov = {
+ .iov_base = &req,
+ .iov_len = sizeof(req)
+ };
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+ };
+
+ return sendmsg(self->netlink_fd, &msg, 0);
+}
+
+void render_response(struct __test_metadata *_metadata,
+ struct unix_diag_req *udr, __u32 len)
+{
+ unsigned int rta_len = len - NLMSG_LENGTH(sizeof(*udr));
+ struct rtattr *attr;
+ uid_t uid;
+
+ ASSERT_GT(len, sizeof(*udr));
+ ASSERT_EQ(udr->sdiag_family, AF_UNIX);
+
+ attr = (struct rtattr *)(udr + 1);
+ ASSERT_NE(RTA_OK(attr, rta_len), 0);
+ ASSERT_EQ(attr->rta_type, UNIX_DIAG_UID);
+
+ uid = *(uid_t *)RTA_DATA(attr);
+ ASSERT_EQ(uid, getuid());
+}
+
+void receive_response(struct __test_metadata *_metadata,
+ FIXTURE_DATA(diag_uid) *self)
+{
+ long buf[8192 / sizeof(long)];
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK
+ };
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
+ };
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+ };
+ struct unix_diag_req *udr;
+ struct nlmsghdr *nlh;
+ int ret;
+
+ ret = recvmsg(self->netlink_fd, &msg, 0);
+ ASSERT_GT(ret, 0);
+
+ nlh = (struct nlmsghdr *)buf;
+ ASSERT_NE(NLMSG_OK(nlh, ret), 0);
+ ASSERT_EQ(nlh->nlmsg_type, SOCK_DIAG_BY_FAMILY);
+
+ render_response(_metadata, NLMSG_DATA(nlh), nlh->nlmsg_len);
+
+ nlh = NLMSG_NEXT(nlh, ret);
+ ASSERT_EQ(NLMSG_OK(nlh, ret), 0);
+}
+
+TEST_F(diag_uid, 1)
+{
+ int ret;
+
+ ret = send_request(_metadata, self, variant);
+ ASSERT_GT(ret, 0);
+
+ receive_response(_metadata, self);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config
index ead7963b9bf0..bd89198cd817 100644
--- a/tools/testing/selftests/net/config
+++ b/tools/testing/selftests/net/config
@@ -43,5 +43,5 @@ CONFIG_NET_ACT_TUNNEL_KEY=m
CONFIG_NET_ACT_MIRRED=m
CONFIG_BAREUDP=m
CONFIG_IPV6_IOAM6_LWTUNNEL=y
-CONFIG_CRYPTO_SM4=y
+CONFIG_CRYPTO_SM4_GENERIC=y
CONFIG_AMT=m
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 31c3b6ebd388..21ca91473c09 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -4196,10 +4196,13 @@ elif [ "$TESTS" = "ipv6" ]; then
TESTS="$TESTS_IPV6"
fi
-which nettest >/dev/null
-if [ $? -ne 0 ]; then
- echo "'nettest' command not found; skipping tests"
- exit $ksft_skip
+# nettest can be run from PATH or from same directory as this selftest
+if ! which nettest >/dev/null; then
+ PATH=$PWD:$PATH
+ if ! which nettest >/dev/null; then
+ echo "'nettest' command not found; skipping tests"
+ exit $ksft_skip
+ fi
fi
declare -i nfail=0
diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index ee5e98204d3d..a47b26ab48f2 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -1228,6 +1228,17 @@ ipv4_fcnal()
run_cmd "$IP ro add 172.16.101.0/24 nhid 21"
run_cmd "$IP ro del 172.16.101.0/24 nexthop via 172.16.1.7 dev veth1 nexthop via 172.16.1.8 dev veth1"
log_test $? 2 "Delete multipath route with only nh id based entry"
+
+ run_cmd "$IP nexthop add id 22 via 172.16.1.6 dev veth1"
+ run_cmd "$IP ro add 172.16.102.0/24 nhid 22"
+ run_cmd "$IP ro del 172.16.102.0/24 dev veth1"
+ log_test $? 2 "Delete route when specifying only nexthop device"
+
+ run_cmd "$IP ro del 172.16.102.0/24 via 172.16.1.6"
+ log_test $? 2 "Delete route when specifying only gateway"
+
+ run_cmd "$IP ro del 172.16.102.0/24"
+ log_test $? 0 "Delete route when not specifying nexthop attributes"
}
ipv4_grp_fcnal()
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index 2271a8727f62..5637b5dadabd 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -1711,13 +1711,21 @@ ipv4_del_addr_test()
$IP addr add dev dummy1 172.16.104.1/24
$IP addr add dev dummy1 172.16.104.11/24
+ $IP addr add dev dummy1 172.16.104.12/24
+ $IP addr add dev dummy1 172.16.104.13/24
$IP addr add dev dummy2 172.16.104.1/24
$IP addr add dev dummy2 172.16.104.11/24
+ $IP addr add dev dummy2 172.16.104.12/24
$IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
+ $IP route add 172.16.106.0/24 dev lo src 172.16.104.12
+ $IP route add table 0 172.16.107.0/24 via 172.16.104.2 src 172.16.104.13
$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
+ $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
set +e
# removing address from device in vrf should only remove route from vrf table
+ echo " Regular FIB info"
+
$IP addr del dev dummy2 172.16.104.11/24
$IP ro ls vrf red | grep -q 172.16.105.0/24
log_test $? 1 "Route removed from VRF when source address deleted"
@@ -1735,6 +1743,35 @@ ipv4_del_addr_test()
$IP ro ls vrf red | grep -q 172.16.105.0/24
log_test $? 0 "Route in VRF is not removed by address delete"
+ # removing address from device in vrf should only remove route from vrf
+ # table even when the associated fib info only differs in table ID
+ echo " Identical FIB info with different table ID"
+
+ $IP addr del dev dummy2 172.16.104.12/24
+ $IP ro ls vrf red | grep -q 172.16.106.0/24
+ log_test $? 1 "Route removed from VRF when source address deleted"
+
+ $IP ro ls | grep -q 172.16.106.0/24
+ log_test $? 0 "Route in default VRF not removed"
+
+ $IP addr add dev dummy2 172.16.104.12/24
+ $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
+
+ $IP addr del dev dummy1 172.16.104.12/24
+ $IP ro ls | grep -q 172.16.106.0/24
+ log_test $? 1 "Route removed in default VRF when source address deleted"
+
+ $IP ro ls vrf red | grep -q 172.16.106.0/24
+ log_test $? 0 "Route in VRF is not removed by address delete"
+
+ # removing address from device in default vrf should remove route from
+ # the default vrf even when route was inserted with a table ID of 0.
+ echo " Table ID 0"
+
+ $IP addr del dev dummy1 172.16.104.13/24
+ $IP ro ls | grep -q 172.16.107.0/24
+ log_test $? 1 "Route removed in default VRF when source address deleted"
+
$IP li del dummy1
$IP li del dummy2
cleanup
diff --git a/tools/testing/selftests/net/io_uring_zerocopy_tx.sh b/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
index 32aa6e9dacc2..9ac4456d48fc 100755
--- a/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
+++ b/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
@@ -29,7 +29,7 @@ if [[ "$#" -eq "0" ]]; then
for IP in "${IPs[@]}"; do
for mode in $(seq 1 3); do
$0 "$IP" udp -m "$mode" -t 1 -n 32
- $0 "$IP" tcp -m "$mode" -t 1 -n 32
+ $0 "$IP" tcp -m "$mode" -t 1 -n 1
done
done
diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index f3dd5f2a0272..2eeaf4aca644 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -2152,7 +2152,7 @@ remove_tests()
pm_nl_set_limits $ns2 1 3
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
- run_tests $ns1 $ns2 10.0.1.1 0 -1 -2 slow
+ run_tests $ns1 $ns2 10.0.1.1 0 -1 -2 speed_10
chk_join_nr 3 3 3
chk_add_nr 1 1
chk_rm_nr 2 2
@@ -2165,7 +2165,7 @@ remove_tests()
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal
pm_nl_set_limits $ns2 3 3
- run_tests $ns1 $ns2 10.0.1.1 0 -3 0 slow
+ run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10
chk_join_nr 3 3 3
chk_add_nr 3 3
chk_rm_nr 3 3 invert
@@ -2178,7 +2178,7 @@ remove_tests()
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal
pm_nl_set_limits $ns2 3 3
- run_tests $ns1 $ns2 10.0.1.1 0 -3 0 slow
+ run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10
chk_join_nr 1 1 1
chk_add_nr 3 3
chk_rm_nr 3 1 invert
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
index 0879da915014..80d36f7cfee8 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
@@ -35,8 +35,9 @@ init()
ns1="ns1-$rndh"
ns2="ns2-$rndh"
+ ns_sbox="ns_sbox-$rndh"
- for netns in "$ns1" "$ns2";do
+ for netns in "$ns1" "$ns2" "$ns_sbox";do
ip netns add $netns || exit $ksft_skip
ip -net $netns link set lo up
ip netns exec $netns sysctl -q net.mptcp.enabled=1
@@ -73,7 +74,7 @@ init()
cleanup()
{
- for netns in "$ns1" "$ns2"; do
+ for netns in "$ns1" "$ns2" "$ns_sbox"; do
ip netns del $netns
done
rm -f "$cin" "$cout"
@@ -243,7 +244,7 @@ do_mptcp_sockopt_tests()
{
local lret=0
- ./mptcp_sockopt
+ ip netns exec "$ns_sbox" ./mptcp_sockopt
lret=$?
if [ $lret -ne 0 ]; then
@@ -252,7 +253,7 @@ do_mptcp_sockopt_tests()
return
fi
- ./mptcp_sockopt -6
+ ip netns exec "$ns_sbox" ./mptcp_sockopt -6
lret=$?
if [ $lret -ne 0 ]; then
diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh
index ffa13a957a36..40aeb5a71a2a 100755
--- a/tools/testing/selftests/net/mptcp/simult_flows.sh
+++ b/tools/testing/selftests/net/mptcp/simult_flows.sh
@@ -247,9 +247,10 @@ run_test()
tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1
tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2
- # time is measured in ms, account for transfer size, affegated link speed
+ # time is measured in ms, account for transfer size, aggregated link speed
# and header overhead (10%)
- local time=$((size * 8 * 1000 * 10 / (( $rate1 + $rate2) * 1024 *1024 * 9) ))
+ # ms byte -> bit 10% mbit -> kbit -> bit 10%
+ local time=$((1000 * size * 8 * 10 / ((rate1 + rate2) * 1000 * 1000 * 9) ))
# mptcp_connect will do some sleeps to allow the mp_join handshake
# completion (see mptcp_connect): 200ms on each side, add some slack
diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh
index 736e358dc549..dfe3d287f01d 100755
--- a/tools/testing/selftests/net/pmtu.sh
+++ b/tools/testing/selftests/net/pmtu.sh
@@ -686,10 +686,12 @@ setup_xfrm() {
}
setup_nettest_xfrm() {
- which nettest >/dev/null
- if [ $? -ne 0 ]; then
- echo "'nettest' command not found; skipping tests"
- return 1
+ if ! which nettest >/dev/null; then
+ PATH=$PWD:$PATH
+ if ! which nettest >/dev/null; then
+ echo "'nettest' command not found; skipping tests"
+ return 1
+ fi
fi
[ ${1} -eq 6 ] && proto="-6" || proto=""
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index 0900c5438fbb..275491be3da2 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -782,7 +782,7 @@ kci_test_ipsec_offload()
tmpl proto esp src $srcip dst $dstip spi 9 \
mode transport reqid 42
check_err $?
- ip x p add dir out src $dstip/24 dst $srcip/24 \
+ ip x p add dir in src $dstip/24 dst $srcip/24 \
tmpl proto esp src $dstip dst $srcip spi 9 \
mode transport reqid 42
check_err $?
diff --git a/tools/testing/selftests/net/toeplitz.sh b/tools/testing/selftests/net/toeplitz.sh
index 0a49907cd4fe..da5bfd834eff 100755
--- a/tools/testing/selftests/net/toeplitz.sh
+++ b/tools/testing/selftests/net/toeplitz.sh
@@ -32,7 +32,7 @@ DEV="eth0"
# This is determined by reading the RSS indirection table using ethtool.
get_rss_cfg_num_rxqs() {
echo $(ethtool -x "${DEV}" |
- egrep [[:space:]]+[0-9]+:[[:space:]]+ |
+ grep -E [[:space:]]+[0-9]+:[[:space:]]+ |
cut -d: -f2- |
awk '{$1=$1};1' |
tr ' ' '\n' |
diff --git a/tools/testing/selftests/net/udpgro.sh b/tools/testing/selftests/net/udpgro.sh
index ebbd0b282432..0c743752669a 100755
--- a/tools/testing/selftests/net/udpgro.sh
+++ b/tools/testing/selftests/net/udpgro.sh
@@ -5,6 +5,8 @@
readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
+BPF_FILE="../bpf/xdp_dummy.bpf.o"
+
# set global exit status, but never reset nonzero one.
check_err()
{
@@ -34,7 +36,7 @@ cfg_veth() {
ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
ip -netns "${PEER_NS}" link set dev veth1 up
- ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
+ ip -n "${PEER_NS}" link set veth1 xdp object ${BPF_FILE} section xdp
}
run_one() {
@@ -50,7 +52,7 @@ run_one() {
echo "failed" &
# Hack: let bg programs complete the startup
- sleep 0.1
+ sleep 0.2
./udpgso_bench_tx ${tx_args}
ret=$?
wait $(jobs -p)
@@ -117,7 +119,7 @@ run_one_2sock() {
echo "failed" &
# Hack: let bg programs complete the startup
- sleep 0.1
+ sleep 0.2
./udpgso_bench_tx ${tx_args} -p 12345
sleep 0.1
# first UDP GSO socket should be closed at this point
@@ -195,8 +197,8 @@ run_all() {
return $ret
}
-if [ ! -f ../bpf/xdp_dummy.o ]; then
- echo "Missing xdp_dummy helper. Build bpf selftest first"
+if [ ! -f ${BPF_FILE} ]; then
+ echo "Missing ${BPF_FILE}. Build bpf selftest first"
exit -1
fi
diff --git a/tools/testing/selftests/net/udpgro_bench.sh b/tools/testing/selftests/net/udpgro_bench.sh
index fad2d1a71cac..894972877e8b 100755
--- a/tools/testing/selftests/net/udpgro_bench.sh
+++ b/tools/testing/selftests/net/udpgro_bench.sh
@@ -5,6 +5,8 @@
readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
+BPF_FILE="../bpf/xdp_dummy.bpf.o"
+
cleanup() {
local -r jobs="$(jobs -p)"
local -r ns="$(ip netns list|grep $PEER_NS)"
@@ -34,12 +36,12 @@ run_one() {
ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
ip -netns "${PEER_NS}" link set dev veth1 up
- ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
+ ip -n "${PEER_NS}" link set veth1 xdp object ${BPF_FILE} section xdp
ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r &
# Hack: let bg programs complete the startup
- sleep 0.1
+ sleep 0.2
./udpgso_bench_tx ${tx_args}
}
@@ -80,8 +82,8 @@ run_all() {
run_udp "${ipv6_args}"
}
-if [ ! -f ../bpf/xdp_dummy.o ]; then
- echo "Missing xdp_dummy helper. Build bpf selftest first"
+if [ ! -f ${BPF_FILE} ]; then
+ echo "Missing ${BPF_FILE}. Build bpf selftest first"
exit -1
fi
diff --git a/tools/testing/selftests/net/udpgro_frglist.sh b/tools/testing/selftests/net/udpgro_frglist.sh
index 832c738cc3c2..c9c4b9d65839 100755
--- a/tools/testing/selftests/net/udpgro_frglist.sh
+++ b/tools/testing/selftests/net/udpgro_frglist.sh
@@ -5,6 +5,8 @@
readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
+BPF_FILE="../bpf/xdp_dummy.bpf.o"
+
cleanup() {
local -r jobs="$(jobs -p)"
local -r ns="$(ip netns list|grep $PEER_NS)"
@@ -36,7 +38,7 @@ run_one() {
ip netns exec "${PEER_NS}" ethtool -K veth1 rx-gro-list on
- ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
+ ip -n "${PEER_NS}" link set veth1 xdp object ${BPF_FILE} section xdp
tc -n "${PEER_NS}" qdisc add dev veth1 clsact
tc -n "${PEER_NS}" filter add dev veth1 ingress prio 4 protocol ipv6 bpf object-file ../bpf/nat6to4.o section schedcls/ingress6/nat_6 direct-action
tc -n "${PEER_NS}" filter add dev veth1 egress prio 4 protocol ip bpf object-file ../bpf/nat6to4.o section schedcls/egress4/snat4 direct-action
@@ -44,7 +46,7 @@ run_one() {
ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
# Hack: let bg programs complete the startup
- sleep 0.1
+ sleep 0.2
./udpgso_bench_tx ${tx_args}
}
@@ -81,8 +83,8 @@ run_all() {
run_udp "${ipv6_args}"
}
-if [ ! -f ../bpf/xdp_dummy.o ]; then
- echo "Missing xdp_dummy helper. Build bpf selftest first"
+if [ ! -f ${BPF_FILE} ]; then
+ echo "Missing ${BPF_FILE}. Build bpf selftest first"
exit -1
fi
diff --git a/tools/testing/selftests/net/udpgro_fwd.sh b/tools/testing/selftests/net/udpgro_fwd.sh
index 1bcd82e1f662..c079565add39 100755
--- a/tools/testing/selftests/net/udpgro_fwd.sh
+++ b/tools/testing/selftests/net/udpgro_fwd.sh
@@ -1,6 +1,7 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+BPF_FILE="../bpf/xdp_dummy.bpf.o"
readonly BASE="ns-$(mktemp -u XXXXXX)"
readonly SRC=2
readonly DST=1
@@ -46,7 +47,7 @@ create_ns() {
ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
done
- ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
+ ip -n $NS_DST link set veth$DST xdp object ${BPF_FILE} section xdp 2>/dev/null
}
create_vxlan_endpoint() {
diff --git a/tools/testing/selftests/net/veth.sh b/tools/testing/selftests/net/veth.sh
index 430895d1a2b6..2d073595c620 100755
--- a/tools/testing/selftests/net/veth.sh
+++ b/tools/testing/selftests/net/veth.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+BPF_FILE="../bpf/xdp_dummy.bpf.o"
readonly STATS="$(mktemp -p /tmp ns-XXXXXX)"
readonly BASE=`basename $STATS`
readonly SRC=2
@@ -216,8 +217,8 @@ while getopts "hs:" option; do
esac
done
-if [ ! -f ../bpf/xdp_dummy.o ]; then
- echo "Missing xdp_dummy helper. Build bpf selftest first"
+if [ ! -f ${BPF_FILE} ]; then
+ echo "Missing ${BPF_FILE}. Build bpf selftest first"
exit 1
fi
@@ -288,14 +289,14 @@ if [ $CPUS -gt 1 ]; then
ip netns exec $NS_DST ethtool -L veth$DST rx 1 tx 2 2>/dev/null
ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
printf "%-60s" "bad setting: XDP with RX nr less than TX"
- ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
+ ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} \
section xdp 2>/dev/null &&\
echo "fail - set operation successful ?!?" || echo " ok "
# the following tests will run with multiple channels active
ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
ip netns exec $NS_DST ethtool -L veth$DST rx 2
- ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
+ ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} \
section xdp 2>/dev/null
printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
@@ -311,7 +312,7 @@ if [ $CPUS -gt 2 ]; then
chk_channels "setting invalid channels nr" $DST 2 2
fi
-ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
+ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp 2>/dev/null
chk_gro_flag "with xdp attached - gro flag" $DST on
chk_gro_flag " - peer gro flag" $SRC off
chk_tso_flag " - tso flag" $SRC off
diff --git a/tools/testing/selftests/netfilter/rpath.sh b/tools/testing/selftests/netfilter/rpath.sh
index 2d8da7bd8ab7..f7311e66d219 100755
--- a/tools/testing/selftests/netfilter/rpath.sh
+++ b/tools/testing/selftests/netfilter/rpath.sh
@@ -15,7 +15,7 @@ fi
if ip6tables-legacy --version >/dev/null 2>&1; then
ip6tables='ip6tables-legacy'
-elif ! ip6tables --version >/dev/null 2>&1; then
+elif ip6tables --version >/dev/null 2>&1; then
ip6tables='ip6tables'
else
ip6tables=''
@@ -62,9 +62,11 @@ ip -net "$ns1" a a fec0:42::2/64 dev v0 nodad
ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad
# firewall matches to test
-ip netns exec "$ns2" "$iptables" -t raw -A PREROUTING -s 192.168.0.0/16 -m rpfilter
-ip netns exec "$ns2" "$ip6tables" -t raw -A PREROUTING -s fec0::/16 -m rpfilter
-ip netns exec "$ns2" nft -f - <<EOF
+[ -n "$iptables" ] && ip netns exec "$ns2" \
+ "$iptables" -t raw -A PREROUTING -s 192.168.0.0/16 -m rpfilter
+[ -n "$ip6tables" ] && ip netns exec "$ns2" \
+ "$ip6tables" -t raw -A PREROUTING -s fec0::/16 -m rpfilter
+[ -n "$nft" ] && ip netns exec "$ns2" $nft -f - <<EOF
table inet t {
chain c {
type filter hook prerouting priority raw;
@@ -106,8 +108,8 @@ testrun() {
if [ -n "$nft" ]; then
(
echo "delete table inet t";
- ip netns exec "$ns2" nft -s list table inet t;
- ) | ip netns exec "$ns2" nft -f -
+ ip netns exec "$ns2" $nft -s list table inet t;
+ ) | ip netns exec "$ns2" $nft -f -
fi
# test 1: martian traffic should fail rpfilter matches
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index 69ea659caca9..22f1e1d73fa8 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -95,6 +95,7 @@ all: run
sysroot: sysroot/$(ARCH)/include
sysroot/$(ARCH)/include:
+ $(Q)rm -rf sysroot/$(ARCH) sysroot/sysroot
$(QUIET_MKDIR)mkdir -p sysroot
$(Q)$(MAKE) -C ../../../include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone
$(Q)mv sysroot/sysroot sysroot/$(ARCH)
@@ -133,3 +134,5 @@ clean:
$(Q)rm -rf initramfs
$(call QUIET_CLEAN, run.out)
$(Q)rm -rf run.out
+
+.PHONY: sysroot/$(ARCH)/include
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 78bced95ac63..f14f5076fb6d 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -565,6 +565,13 @@ int run_stdlib(int min, int max)
CASE_TEST(strchr_foobar_z); EXPECT_STRZR(1, strchr("foobar", 'z')); break;
CASE_TEST(strrchr_foobar_o); EXPECT_STREQ(1, strrchr("foobar", 'o'), "obar"); break;
CASE_TEST(strrchr_foobar_z); EXPECT_STRZR(1, strrchr("foobar", 'z')); break;
+ CASE_TEST(memcmp_20_20); EXPECT_EQ(1, memcmp("aaa\x20", "aaa\x20", 4), 0); break;
+ CASE_TEST(memcmp_20_60); EXPECT_LT(1, memcmp("aaa\x20", "aaa\x60", 4), 0); break;
+ CASE_TEST(memcmp_60_20); EXPECT_GT(1, memcmp("aaa\x60", "aaa\x20", 4), 0); break;
+ CASE_TEST(memcmp_20_e0); EXPECT_LT(1, memcmp("aaa\x20", "aaa\xe0", 4), 0); break;
+ CASE_TEST(memcmp_e0_20); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x20", 4), 0); break;
+ CASE_TEST(memcmp_80_e0); EXPECT_LT(1, memcmp("aaa\x80", "aaa\xe0", 4), 0); break;
+ CASE_TEST(memcmp_e0_80); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x80", 4), 0); break;
case __LINE__:
return ret; /* must be last */
/* note: do not set any defaults so as to permit holes above */
diff --git a/tools/testing/selftests/proc/proc-uptime-002.c b/tools/testing/selftests/proc/proc-uptime-002.c
index e7ceabed7f51..7d0aa22bdc12 100644
--- a/tools/testing/selftests/proc/proc-uptime-002.c
+++ b/tools/testing/selftests/proc/proc-uptime-002.c
@@ -17,6 +17,7 @@
// while shifting across CPUs.
#undef NDEBUG
#include <assert.h>
+#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
@@ -54,7 +55,7 @@ int main(void)
len += sizeof(unsigned long);
free(m);
m = malloc(len);
- } while (sys_sched_getaffinity(0, len, m) == -EINVAL);
+ } while (sys_sched_getaffinity(0, len, m) == -1 && errno == EINVAL);
fd = open("/proc/uptime", O_RDONLY);
assert(fd >= 0);
diff --git a/tools/testing/selftests/rcutorture/bin/config2csv.sh b/tools/testing/selftests/rcutorture/bin/config2csv.sh
index d5a16631b16e..0cf55f1bf654 100755
--- a/tools/testing/selftests/rcutorture/bin/config2csv.sh
+++ b/tools/testing/selftests/rcutorture/bin/config2csv.sh
@@ -30,9 +30,8 @@ else
fi
scenarios="`echo $scenariosarg | sed -e "s/\<CFLIST\>/$defaultconfigs/g"`"
-T=/tmp/config2latex.sh.$$
+T=`mktemp -d /tmp/config2latex.sh.XXXXXX`
trap 'rm -rf $T' 0
-mkdir $T
cat << '---EOF---' >> $T/p.awk
END {
diff --git a/tools/testing/selftests/rcutorture/bin/config_override.sh b/tools/testing/selftests/rcutorture/bin/config_override.sh
index 90016c359e83..b3d2e7efa40c 100755
--- a/tools/testing/selftests/rcutorture/bin/config_override.sh
+++ b/tools/testing/selftests/rcutorture/bin/config_override.sh
@@ -29,9 +29,8 @@ else
exit 1
fi
-T=${TMPDIR-/tmp}/config_override.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/config_override.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
sed < $override -e 's/^/grep -v "/' -e 's/=.*$/="/' |
awk '
diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh
index 31584cee84d7..83fac1852ab2 100755
--- a/tools/testing/selftests/rcutorture/bin/configcheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh
@@ -7,9 +7,8 @@
#
# Authors: Paul E. McKenney <paulmck@linux.ibm.com>
-T=${TMPDIR-/tmp}/abat-chk-config.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/configcheck.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
cat $1 > $T/.config
diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh
index d6e5ce084b1c..28bdb3ac7ba6 100755
--- a/tools/testing/selftests/rcutorture/bin/configinit.sh
+++ b/tools/testing/selftests/rcutorture/bin/configinit.sh
@@ -15,9 +15,8 @@
#
# Authors: Paul E. McKenney <paulmck@linux.ibm.com>
-T=${TMPDIR-/tmp}/configinit.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/configinit.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
# Capture config spec file.
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-again.sh b/tools/testing/selftests/rcutorture/bin/kvm-again.sh
index 0941f1ddab65..8a968fbda02c 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-again.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-again.sh
@@ -12,9 +12,8 @@
scriptname=$0
args="$*"
-T=${TMPDIR-/tmp}/kvm-again.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-again.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
if ! test -d tools/testing/selftests/rcutorture/bin
then
@@ -51,27 +50,56 @@ RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
PATH=${RCUTORTURE}/bin:$PATH; export PATH
. functions.sh
+bootargs=
dryrun=
dur=
default_link="cp -R"
-rundir="`pwd`/tools/testing/selftests/rcutorture/res/`date +%Y.%m.%d-%H.%M.%S-again`"
+resdir="`pwd`/tools/testing/selftests/rcutorture/res"
+rundir="$resdir/`date +%Y.%m.%d-%H.%M.%S-again`"
+got_datestamp=
+got_rundir=
startdate="`date`"
starttime="`get_starttime`"
usage () {
echo "Usage: $scriptname $oldrun [ arguments ]:"
+ echo " --bootargs kernel-boot-arguments"
+ echo " --datestamp string"
echo " --dryrun"
echo " --duration minutes | <seconds>s | <hours>h | <days>d"
echo " --link hard|soft|copy"
echo " --remote"
echo " --rundir /new/res/path"
+ echo "Command line: $scriptname $args"
exit 1
}
while test $# -gt 0
do
case "$1" in
+ --bootargs|--bootarg)
+ checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--'
+ bootargs="$bootargs $2"
+ shift
+ ;;
+ --datestamp)
+ checkarg --datestamp "(relative pathname)" "$#" "$2" '^[a-zA-Z0-9._/-]*$' '^--'
+ if test -n "$got_rundir" || test -n "$got_datestamp"
+ then
+ echo Only one of --datestamp or --rundir may be specified
+ usage
+ fi
+ got_datestamp=y
+ ds=$2
+ rundir="$resdir/$ds"
+ if test -e "$rundir"
+ then
+ echo "--datestamp $2: Already exists."
+ usage
+ fi
+ shift
+ ;;
--dryrun)
dryrun=1
;;
@@ -113,6 +141,12 @@ do
;;
--rundir)
checkarg --rundir "(absolute pathname)" "$#" "$2" '^/' '^error'
+ if test -n "$got_rundir" || test -n "$got_datestamp"
+ then
+ echo Only one of --datestamp or --rundir may be specified
+ usage
+ fi
+ got_rundir=y
rundir=$2
if test -e "$rundir"
then
@@ -122,8 +156,11 @@ do
shift
;;
*)
- echo Unknown argument $1
- usage
+ if test -n "$1"
+ then
+ echo Unknown argument $1
+ usage
+ fi
;;
esac
shift
@@ -156,7 +193,7 @@ do
qemu_cmd_dir="`dirname "$i"`"
kernel_dir="`echo $qemu_cmd_dir | sed -e 's/\.[0-9]\+$//'`"
jitter_dir="`dirname "$kernel_dir"`"
- kvm-transform.sh "$kernel_dir/bzImage" "$qemu_cmd_dir/console.log" "$jitter_dir" $dur < $T/qemu-cmd > $i
+ kvm-transform.sh "$kernel_dir/bzImage" "$qemu_cmd_dir/console.log" "$jitter_dir" $dur "$bootargs" < $T/qemu-cmd > $i
if test -n "$arg_remote"
then
echo "# TORTURE_KCONFIG_GDB_ARG=''" >> $i
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-assign-cpus.sh b/tools/testing/selftests/rcutorture/bin/kvm-assign-cpus.sh
index f99b2c146f83..46b08cd16ba5 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-assign-cpus.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-assign-cpus.sh
@@ -7,9 +7,8 @@
#
# Usage: kvm-assign-cpus.sh /path/to/sysfs
-T=/tmp/kvm-assign-cpus.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-assign-cpus.sh.XXXXXX`"
trap 'rm -rf $T' 0 2
-mkdir $T
sysfsdir=${1-/sys/devices/system/node}
if ! cd "$sysfsdir" > $T/msg 2>&1
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
index 5ad973dca820..e28a82851f7c 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
@@ -23,9 +23,8 @@ then
fi
resdir=${2}
-T=${TMPDIR-/tmp}/test-linux.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-build.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
cp ${config_template} $T/config
cat << ___EOF___ >> $T/config
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-end-run-stats.sh b/tools/testing/selftests/rcutorture/bin/kvm-end-run-stats.sh
index ee886b40a5d2..2b56baceb05d 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-end-run-stats.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-end-run-stats.sh
@@ -18,9 +18,8 @@ then
exit 1
fi
-T=${TMPDIR-/tmp}/kvm-end-run-stats.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-end-run-stats.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
PATH=${RCUTORTURE}/bin:$PATH; export PATH
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index 0789c5606d2a..1df7e695edf7 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -30,7 +30,7 @@ do
resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'`
head -1 $resdir/log
fi
- TORTURE_SUITE="`cat $i/../torture_suite`"
+ TORTURE_SUITE="`cat $i/../torture_suite`" ; export TORTURE_SUITE
configfile=`echo $i | sed -e 's,^.*/,,'`
rm -f $i/console.log.*.diags
case "${TORTURE_SUITE}" in
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-remote.sh b/tools/testing/selftests/rcutorture/bin/kvm-remote.sh
index 9f0a5d5ff2dd..a2328163eba1 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-remote.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-remote.sh
@@ -34,19 +34,18 @@ fi
shift
# Pathnames:
-# T: /tmp/kvm-remote.sh.$$
-# resdir: /tmp/kvm-remote.sh.$$/res
-# rundir: /tmp/kvm-remote.sh.$$/res/$ds ("-remote" suffix)
+# T: /tmp/kvm-remote.sh.NNNNNN where "NNNNNN" is set by mktemp
+# resdir: /tmp/kvm-remote.sh.NNNNNN/res
+# rundir: /tmp/kvm-remote.sh.NNNNNN/res/$ds ("-remote" suffix)
# oldrun: `pwd`/tools/testing/.../res/$otherds
#
# Pathname segments:
-# TD: kvm-remote.sh.$$
+# TD: kvm-remote.sh.NNNNNN
# ds: yyyy.mm.dd-hh.mm.ss-remote
-TD=kvm-remote.sh.$$
-T=${TMPDIR-/tmp}/$TD
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-remote.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
+TD="`basename "$T"`"
resdir="$T/res"
ds=`date +%Y.%m.%d-%H.%M.%S`-remote
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-batch.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-batch.sh
index 1e29d656501b..c3808c490d92 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-batch.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-batch.sh
@@ -13,9 +13,8 @@
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
-T=${TMPDIR-/tmp}/kvm-test-1-run-batch.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-test-1-run-batch.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
echo ---- Running batch $*
# Check arguments
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-qemu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-qemu.sh
index 44280582c594..76f24cd5825b 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-qemu.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run-qemu.sh
@@ -17,9 +17,8 @@
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
-T=${TMPDIR-/tmp}/kvm-test-1-run-qemu.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-test-1-run-qemu.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
resdir="$1"
if ! test -d "$resdir"
@@ -109,7 +108,7 @@ do
if test $kruntime -lt $seconds
then
echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1
- grep "^(qemu) qemu:" $resdir/kvm-test-1-run.sh.out >> $resdir/Warnings 2>&1
+ grep "^(qemu) qemu:" $resdir/kvm-test-1-run*.sh.out >> $resdir/Warnings 2>&1
killpid="`sed -n "s/^(qemu) qemu: terminating on signal [0-9]* from pid \([0-9]*\).*$/\1/p" $resdir/Warnings`"
if test -n "$killpid"
then
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 f4c8055dbf7a..d2a3710a5f2a 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -25,9 +25,8 @@
#
# Authors: Paul E. McKenney <paulmck@linux.ibm.com>
-T=${TMPDIR-/tmp}/kvm-test-1-run.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm-test-1-run.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
. functions.sh
. $CONFIGFRAG/ver_functions.sh
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-transform.sh b/tools/testing/selftests/rcutorture/bin/kvm-transform.sh
index d40b4e60a50c..75a2610a27f3 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-transform.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-transform.sh
@@ -3,10 +3,14 @@
#
# Transform a qemu-cmd file to allow reuse.
#
-# Usage: kvm-transform.sh bzImage console.log jitter_dir [ seconds ] < qemu-cmd-in > qemu-cmd-out
+# Usage: kvm-transform.sh bzImage console.log jitter_dir seconds [ bootargs ] < qemu-cmd-in > qemu-cmd-out
#
# bzImage: Kernel and initrd from the same prior kvm.sh run.
# console.log: File into which to place console output.
+# jitter_dir: Jitter directory for TORTURE_JITTER_START and
+# TORTURE_JITTER_STOP environment variables.
+# seconds: Run duaration for *.shutdown_secs module parameter.
+# bootargs: New kernel boot parameters. Beware of Robert Tables.
#
# The original qemu-cmd file is provided on standard input.
# The transformed qemu-cmd file is on standard output.
@@ -17,6 +21,9 @@
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
+T=`mktemp -d /tmp/kvm-transform.sh.XXXXXXXXXX`
+trap 'rm -rf $T' 0 2
+
image="$1"
if test -z "$image"
then
@@ -41,9 +48,17 @@ then
echo "Invalid duration, should be numeric in seconds: '$seconds'"
exit 1
fi
+bootargs="$5"
+
+# Build awk program.
+echo "BEGIN {" > $T/bootarg.awk
+echo $bootargs | tr -s ' ' '\012' |
+ awk -v dq='"' '/./ { print "\tbootarg[" NR "] = " dq $1 dq ";" }' >> $T/bootarg.awk
+echo $bootargs | tr -s ' ' '\012' | sed -e 's/=.*$//' |
+ awk -v dq='"' '/./ { print "\tbootpar[" NR "] = " dq $1 dq ";" }' >> $T/bootarg.awk
+cat >> $T/bootarg.awk << '___EOF___'
+}
-awk -v image="$image" -v consolelog="$consolelog" -v jitter_dir="$jitter_dir" \
- -v seconds="$seconds" '
/^# seconds=/ {
if (seconds == "")
print $0;
@@ -70,13 +85,7 @@ awk -v image="$image" -v consolelog="$consolelog" -v jitter_dir="$jitter_dir" \
{
line = "";
for (i = 1; i <= NF; i++) {
- if ("" seconds != "" && $i ~ /\.shutdown_secs=[0-9]*$/) {
- sub(/[0-9]*$/, seconds, $i);
- if (line == "")
- line = $i;
- else
- line = line " " $i;
- } else if (line == "") {
+ if (line == "") {
line = $i;
} else {
line = line " " $i;
@@ -87,7 +96,44 @@ awk -v image="$image" -v consolelog="$consolelog" -v jitter_dir="$jitter_dir" \
} else if ($i == "-kernel") {
i++;
line = line " " image;
+ } else if ($i == "-append") {
+ for (i++; i <= NF; i++) {
+ arg = $i;
+ lq = "";
+ rq = "";
+ if ("" seconds != "" && $i ~ /\.shutdown_secs=[0-9]*$/)
+ sub(/[0-9]*$/, seconds, arg);
+ if (arg ~ /^"/) {
+ lq = substr(arg, 1, 1);
+ arg = substr(arg, 2);
+ }
+ if (arg ~ /"$/) {
+ rq = substr(arg, length($i), 1);
+ arg = substr(arg, 1, length($i) - 1);
+ }
+ par = arg;
+ gsub(/=.*$/, "", par);
+ j = 1;
+ while (bootpar[j] != "") {
+ if (bootpar[j] == par) {
+ arg = "";
+ break;
+ }
+ j++;
+ }
+ if (line == "")
+ line = lq arg;
+ else
+ line = line " " lq arg;
+ }
+ for (j in bootarg)
+ line = line " " bootarg[j];
+ line = line rq;
}
}
print line;
-}'
+}
+___EOF___
+
+awk -v image="$image" -v consolelog="$consolelog" -v jitter_dir="$jitter_dir" \
+ -v seconds="$seconds" -f $T/bootarg.awk
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 6c734818a875..7710b1e1cdda 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -14,9 +14,8 @@
scriptname=$0
args="$*"
-T=${TMPDIR-/tmp}/kvm.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/kvm.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
cd `dirname $scriptname`/../../../../../
diff --git a/tools/testing/selftests/rcutorture/bin/parse-build.sh b/tools/testing/selftests/rcutorture/bin/parse-build.sh
index 2dbfca3589b1..5a0b7ffcf047 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-build.sh
@@ -15,9 +15,8 @@
F=$1
title=$2
-T=${TMPDIR-/tmp}/parse-build.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/parse-build.sh.XXXXXX`"
trap 'rm -rf $T' 0
-mkdir $T
. functions.sh
diff --git a/tools/testing/selftests/rcutorture/bin/torture.sh b/tools/testing/selftests/rcutorture/bin/torture.sh
index d477618e7261..130d0de4c3bb 100755
--- a/tools/testing/selftests/rcutorture/bin/torture.sh
+++ b/tools/testing/selftests/rcutorture/bin/torture.sh
@@ -206,9 +206,8 @@ ds="`date +%Y.%m.%d-%H.%M.%S`-torture"
startdate="`date`"
starttime="`get_starttime`"
-T=/tmp/torture.sh.$$
+T="`mktemp -d ${TMPDIR-/tmp}/torture.sh.XXXXXX`"
trap 'rm -rf $T' 0 2
-mkdir $T
echo " --- " $scriptname $args | tee -a $T/log
echo " --- Results directory: " $ds | tee -a $T/log
@@ -278,6 +277,8 @@ function torture_one {
then
cat $T/$curflavor.out | tee -a $T/log
echo retcode=$retcode | tee -a $T/log
+ else
+ echo $resdir > $T/last-resdir
fi
if test "$retcode" == 0
then
@@ -303,10 +304,12 @@ function torture_set {
shift
curflavor=$flavor
torture_one "$@"
+ mv $T/last-resdir $T/last-resdir-nodebug || :
if test "$do_kasan" = "yes"
then
curflavor=${flavor}-kasan
torture_one "$@" --kasan
+ mv $T/last-resdir $T/last-resdir-kasan || :
fi
if test "$do_kcsan" = "yes"
then
@@ -317,6 +320,7 @@ function torture_set {
cur_kcsan_kmake_args="$kcsan_kmake_args"
fi
torture_one "$@" --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" $kcsan_kmake_tag $cur_kcsan_kmake_args --kcsan
+ mv $T/last-resdir $T/last-resdir-kcsan || :
fi
}
@@ -326,20 +330,34 @@ then
echo " --- allmodconfig:" Start `date` | tee -a $T/log
amcdir="tools/testing/selftests/rcutorture/res/$ds/allmodconfig"
mkdir -p "$amcdir"
- echo " --- make clean" > "$amcdir/Make.out" 2>&1
+ echo " --- make clean" | tee $amcdir/log > "$amcdir/Make.out" 2>&1
make -j$MAKE_ALLOTED_CPUS clean >> "$amcdir/Make.out" 2>&1
- echo " --- make allmodconfig" >> "$amcdir/Make.out" 2>&1
- cp .config $amcdir
- make -j$MAKE_ALLOTED_CPUS allmodconfig >> "$amcdir/Make.out" 2>&1
- echo " --- make " >> "$amcdir/Make.out" 2>&1
- make -j$MAKE_ALLOTED_CPUS >> "$amcdir/Make.out" 2>&1
- retcode="$?"
- echo $retcode > "$amcdir/Make.exitcode"
- if test "$retcode" == 0
+ retcode=$?
+ buildphase='"make clean"'
+ if test "$retcode" -eq 0
+ then
+ echo " --- make allmodconfig" | tee -a $amcdir/log >> "$amcdir/Make.out" 2>&1
+ cp .config $amcdir
+ make -j$MAKE_ALLOTED_CPUS allmodconfig >> "$amcdir/Make.out" 2>&1
+ retcode=$?
+ buildphase='"make allmodconfig"'
+ fi
+ if test "$retcode" -eq 0
+ then
+ echo " --- make " | tee -a $amcdir/log >> "$amcdir/Make.out" 2>&1
+ make -j$MAKE_ALLOTED_CPUS >> "$amcdir/Make.out" 2>&1
+ retcode="$?"
+ echo $retcode > "$amcdir/Make.exitcode"
+ buildphase='"make"'
+ fi
+ if test "$retcode" -eq 0
then
echo "allmodconfig($retcode)" $amcdir >> $T/successes
+ echo Success >> $amcdir/log
else
echo "allmodconfig($retcode)" $amcdir >> $T/failures
+ echo " --- allmodconfig Test summary:" >> $amcdir/log
+ echo " --- Summary: Exit code $retcode from $buildphase, see Make.out" >> $amcdir/log
fi
fi
@@ -379,11 +397,48 @@ then
else
primlist=
fi
+firsttime=1
+do_kasan_save="$do_kasan"
+do_kcsan_save="$do_kcsan"
for prim in $primlist
do
- torture_bootargs="refscale.scale_type="$prim" refscale.nreaders=$HALF_ALLOTED_CPUS refscale.loops=10000 refscale.holdoff=20 torture.disable_onoff_at_boot"
- torture_set "refscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture refscale --allcpus --duration 5 --kconfig "CONFIG_TASKS_TRACE_RCU=y CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --bootargs "verbose_batched=$VERBOSE_BATCH_CPUS torture.verbose_sleep_frequency=8 torture.verbose_sleep_duration=$VERBOSE_BATCH_CPUS" --trust-make
+ if test -n "$firsttime"
+ then
+ torture_bootargs="refscale.scale_type="$prim" refscale.nreaders=$HALF_ALLOTED_CPUS refscale.loops=10000 refscale.holdoff=20 torture.disable_onoff_at_boot"
+ torture_set "refscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture refscale --allcpus --duration 5 --kconfig "CONFIG_TASKS_TRACE_RCU=y CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --bootargs "verbose_batched=$VERBOSE_BATCH_CPUS torture.verbose_sleep_frequency=8 torture.verbose_sleep_duration=$VERBOSE_BATCH_CPUS" --trust-make
+ mv $T/last-resdir-nodebug $T/first-resdir-nodebug || :
+ if test -f "$T/last-resdir-kasan"
+ then
+ mv $T/last-resdir-kasan $T/first-resdir-kasan || :
+ fi
+ if test -f "$T/last-resdir-kcsan"
+ then
+ mv $T/last-resdir-kcsan $T/first-resdir-kcsan || :
+ fi
+ firsttime=
+ do_kasan=
+ do_kcsan=
+ else
+ torture_bootargs=
+ for i in $T/first-resdir-*
+ do
+ case "$i" in
+ *-nodebug)
+ torture_suffix=
+ ;;
+ *-kasan)
+ torture_suffix="-kasan"
+ ;;
+ *-kcsan)
+ torture_suffix="-kcsan"
+ ;;
+ esac
+ torture_set "refscale-$prim$torture_suffix" tools/testing/selftests/rcutorture/bin/kvm-again.sh "`cat "$i"`" --duration 5 --bootargs "refscale.scale_type=$prim"
+ done
+ fi
done
+do_kasan="$do_kasan_save"
+do_kcsan="$do_kcsan_save"
if test "$do_rcuscale" = yes
then
@@ -391,11 +446,48 @@ then
else
primlist=
fi
+firsttime=1
+do_kasan_save="$do_kasan"
+do_kcsan_save="$do_kcsan"
for prim in $primlist
do
- torture_bootargs="rcuscale.scale_type="$prim" rcuscale.nwriters=$HALF_ALLOTED_CPUS rcuscale.holdoff=20 torture.disable_onoff_at_boot"
- torture_set "rcuscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 5 --kconfig "CONFIG_TASKS_TRACE_RCU=y CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --trust-make
+ if test -n "$firsttime"
+ then
+ torture_bootargs="rcuscale.scale_type="$prim" rcuscale.nwriters=$HALF_ALLOTED_CPUS rcuscale.holdoff=20 torture.disable_onoff_at_boot"
+ torture_set "rcuscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 5 --kconfig "CONFIG_TASKS_TRACE_RCU=y CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --trust-make
+ mv $T/last-resdir-nodebug $T/first-resdir-nodebug || :
+ if test -f "$T/last-resdir-kasan"
+ then
+ mv $T/last-resdir-kasan $T/first-resdir-kasan || :
+ fi
+ if test -f "$T/last-resdir-kcsan"
+ then
+ mv $T/last-resdir-kcsan $T/first-resdir-kcsan || :
+ fi
+ firsttime=
+ do_kasan=
+ do_kcsan=
+ else
+ torture_bootargs=
+ for i in $T/first-resdir-*
+ do
+ case "$i" in
+ *-nodebug)
+ torture_suffix=
+ ;;
+ *-kasan)
+ torture_suffix="-kasan"
+ ;;
+ *-kcsan)
+ torture_suffix="-kcsan"
+ ;;
+ esac
+ torture_set "rcuscale-$prim$torture_suffix" tools/testing/selftests/rcutorture/bin/kvm-again.sh "`cat "$i"`" --duration 5 --bootargs "rcuscale.scale_type=$prim"
+ done
+ fi
done
+do_kasan="$do_kasan_save"
+do_kcsan="$do_kcsan_save"
if test "$do_kvfree" = "yes"
then
@@ -458,7 +550,10 @@ if test -n "$tdir" && test $compress_concurrency -gt 0
then
# KASAN vmlinux files can approach 1GB in size, so compress them.
echo Looking for K[AC]SAN files to compress: `date` > "$tdir/log-xz" 2>&1
- find "$tdir" -type d -name '*-k[ac]san' -print > $T/xz-todo
+ find "$tdir" -type d -name '*-k[ac]san' -print > $T/xz-todo-all
+ find "$tdir" -type f -name 're-run' -print | sed -e 's,/re-run,,' |
+ grep -e '-k[ac]san$' > $T/xz-todo-copy
+ sort $T/xz-todo-all $T/xz-todo-copy | uniq -u > $T/xz-todo
ncompresses=0
batchno=1
if test -s $T/xz-todo
@@ -490,6 +585,24 @@ then
echo Waiting for final batch $batchno of $ncompresses compressions `date` | tee -a "$tdir/log-xz" | tee -a $T/log
fi
wait
+ if test -s $T/xz-todo-copy
+ then
+ # The trick here is that we need corresponding
+ # vmlinux files from corresponding scenarios.
+ echo Linking vmlinux.xz files to re-use scenarios `date` | tee -a "$tdir/log-xz" | tee -a $T/log
+ dirstash="`pwd`"
+ for i in `cat $T/xz-todo-copy`
+ do
+ cd $i
+ find . -name vmlinux -print > $T/xz-todo-copy-vmlinux
+ for v in `cat $T/xz-todo-copy-vmlinux`
+ do
+ rm -f "$v"
+ cp -l `cat $i/re-run`/"$i/$v".xz "`dirname "$v"`"
+ done
+ cd "$dirstash"
+ done
+ fi
echo Size after compressing $n2compress files: `du -sh $tdir | awk '{ print $1 }'` `date` 2>&1 | tee -a "$tdir/log-xz" | tee -a $T/log
echo Total duration `get_starttime_duration $starttime`. | tee -a $T/log
else
diff --git a/tools/testing/selftests/rtc/rtctest.c b/tools/testing/selftests/rtc/rtctest.c
index 2b9d929a24ed..63ce02d1d5cc 100644
--- a/tools/testing/selftests/rtc/rtctest.c
+++ b/tools/testing/selftests/rtc/rtctest.c
@@ -31,7 +31,6 @@ FIXTURE(rtc) {
FIXTURE_SETUP(rtc) {
self->fd = open(rtc_file, O_RDONLY);
- ASSERT_NE(-1, self->fd);
}
FIXTURE_TEARDOWN(rtc) {
@@ -42,6 +41,10 @@ TEST_F(rtc, date_read) {
int rc;
struct rtc_time rtc_tm;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
/* Read the RTC time/date */
rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
ASSERT_NE(-1, rc);
@@ -85,6 +88,10 @@ TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
struct rtc_time rtc_tm;
time_t start_rtc_read, prev_rtc_read;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
@@ -119,6 +126,10 @@ TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
int i, rc, irq = 0;
unsigned long data;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
@@ -144,6 +155,10 @@ TEST_F(rtc, uie_select) {
int i, rc, irq = 0;
unsigned long data;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
@@ -183,6 +198,10 @@ TEST_F(rtc, alarm_alm_set) {
time_t secs, new;
int rc;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@@ -237,6 +256,10 @@ TEST_F(rtc, alarm_wkalm_set) {
time_t secs, new;
int rc;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
@@ -285,6 +308,10 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
time_t secs, new;
int rc;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@@ -339,6 +366,10 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
time_t secs, new;
int rc;
+ if (self->fd == -1 && errno == ENOENT)
+ SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ ASSERT_NE(-1, self->fd);
+
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 4ae6c8991307..9c2f448bb3a9 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -392,6 +392,8 @@ TEST(mode_filter_without_nnp)
.filter = filter,
};
long ret;
+ cap_t cap = cap_get_proc();
+ cap_flag_value_t is_cap_sys_admin = 0;
ret = prctl(PR_GET_NO_NEW_PRIVS, 0, NULL, 0, 0);
ASSERT_LE(0, ret) {
@@ -400,8 +402,8 @@ TEST(mode_filter_without_nnp)
errno = 0;
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
/* Succeeds with CAP_SYS_ADMIN, fails without */
- /* TODO(wad) check caps not euid */
- if (geteuid()) {
+ cap_get_flag(cap, CAP_SYS_ADMIN, CAP_EFFECTIVE, &is_cap_sys_admin);
+ if (!is_cap_sys_admin) {
EXPECT_EQ(-1, ret);
EXPECT_EQ(EACCES, errno);
} else {
diff --git a/tools/testing/selftests/splice/short_splice_read.sh b/tools/testing/selftests/splice/short_splice_read.sh
index 22b6c8910b18..4710e09f49fa 100755
--- a/tools/testing/selftests/splice/short_splice_read.sh
+++ b/tools/testing/selftests/splice/short_splice_read.sh
@@ -127,7 +127,7 @@ expect_success "proc_handler: special read splice" test_splice /proc/sys/kernel/
if ! [ -d /sys/module/test_module/sections ] ; then
expect_success "test_module kernel module load" modprobe test_module
fi
-expect_failure "kernfs attr splice" test_splice /sys/module/test_module/coresize
-expect_failure "kernfs binattr splice" test_splice /sys/module/test_module/sections/.init.text
+expect_success "kernfs attr splice" test_splice /sys/module/test_module/coresize
+expect_success "kernfs binattr splice" test_splice /sys/module/test_module/sections/.init.text
exit $ret
diff --git a/tools/testing/selftests/tdx/Makefile b/tools/testing/selftests/tdx/Makefile
new file mode 100644
index 000000000000..8dd43517cd55
--- /dev/null
+++ b/tools/testing/selftests/tdx/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CFLAGS += -O3 -Wl,-no-as-needed -Wall -static
+
+TEST_GEN_PROGS := tdx_guest_test
+
+include ../lib.mk
diff --git a/tools/testing/selftests/tdx/config b/tools/testing/selftests/tdx/config
new file mode 100644
index 000000000000..aa1edc829ab6
--- /dev/null
+++ b/tools/testing/selftests/tdx/config
@@ -0,0 +1 @@
+CONFIG_TDX_GUEST_DRIVER=y
diff --git a/tools/testing/selftests/tdx/tdx_guest_test.c b/tools/testing/selftests/tdx/tdx_guest_test.c
new file mode 100644
index 000000000000..2a2afd856798
--- /dev/null
+++ b/tools/testing/selftests/tdx/tdx_guest_test.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test TDX guest features
+ *
+ * Copyright (C) 2022 Intel Corporation.
+ *
+ * Author: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
+ */
+
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include "../kselftest_harness.h"
+#include "../../../../include/uapi/linux/tdx-guest.h"
+
+#define TDX_GUEST_DEVNAME "/dev/tdx_guest"
+#define HEX_DUMP_SIZE 8
+#define DEBUG 0
+
+/**
+ * struct tdreport_type - Type header of TDREPORT_STRUCT.
+ * @type: Type of the TDREPORT (0 - SGX, 81 - TDX, rest are reserved)
+ * @sub_type: Subtype of the TDREPORT (Default value is 0).
+ * @version: TDREPORT version (Default value is 0).
+ * @reserved: Added for future extension.
+ *
+ * More details can be found in TDX v1.0 module specification, sec
+ * titled "REPORTTYPE".
+ */
+struct tdreport_type {
+ __u8 type;
+ __u8 sub_type;
+ __u8 version;
+ __u8 reserved;
+};
+
+/**
+ * struct reportmac - TDX guest report data, MAC and TEE hashes.
+ * @type: TDREPORT type header.
+ * @reserved1: Reserved for future extension.
+ * @cpu_svn: CPU security version.
+ * @tee_tcb_info_hash: SHA384 hash of TEE TCB INFO.
+ * @tee_td_info_hash: SHA384 hash of TDINFO_STRUCT.
+ * @reportdata: User defined unique data passed in TDG.MR.REPORT request.
+ * @reserved2: Reserved for future extension.
+ * @mac: CPU MAC ID.
+ *
+ * It is MAC-protected and contains hashes of the remainder of the
+ * report structure along with user provided report data. More details can
+ * be found in TDX v1.0 Module specification, sec titled "REPORTMACSTRUCT"
+ */
+struct reportmac {
+ struct tdreport_type type;
+ __u8 reserved1[12];
+ __u8 cpu_svn[16];
+ __u8 tee_tcb_info_hash[48];
+ __u8 tee_td_info_hash[48];
+ __u8 reportdata[64];
+ __u8 reserved2[32];
+ __u8 mac[32];
+};
+
+/**
+ * struct td_info - TDX guest measurements and configuration.
+ * @attr: TDX Guest attributes (like debug, spet_disable, etc).
+ * @xfam: Extended features allowed mask.
+ * @mrtd: Build time measurement register.
+ * @mrconfigid: Software-defined ID for non-owner-defined configuration
+ * of the guest - e.g., run-time or OS configuration.
+ * @mrowner: Software-defined ID for the guest owner.
+ * @mrownerconfig: Software-defined ID for owner-defined configuration of
+ * the guest - e.g., specific to the workload.
+ * @rtmr: Run time measurement registers.
+ * @reserved: Added for future extension.
+ *
+ * It contains the measurements and initial configuration of the TDX guest
+ * that was locked at initialization and a set of measurement registers
+ * that are run-time extendable. More details can be found in TDX v1.0
+ * Module specification, sec titled "TDINFO_STRUCT".
+ */
+struct td_info {
+ __u8 attr[8];
+ __u64 xfam;
+ __u64 mrtd[6];
+ __u64 mrconfigid[6];
+ __u64 mrowner[6];
+ __u64 mrownerconfig[6];
+ __u64 rtmr[24];
+ __u64 reserved[14];
+};
+
+/*
+ * struct tdreport - Output of TDCALL[TDG.MR.REPORT].
+ * @reportmac: Mac protected header of size 256 bytes.
+ * @tee_tcb_info: Additional attestable elements in the TCB are not
+ * reflected in the reportmac.
+ * @reserved: Added for future extension.
+ * @tdinfo: Measurements and configuration data of size 512 bytes.
+ *
+ * More details can be found in TDX v1.0 Module specification, sec
+ * titled "TDREPORT_STRUCT".
+ */
+struct tdreport {
+ struct reportmac reportmac;
+ __u8 tee_tcb_info[239];
+ __u8 reserved[17];
+ struct td_info tdinfo;
+};
+
+static void print_array_hex(const char *title, const char *prefix_str,
+ const void *buf, int len)
+{
+ int i, j, line_len, rowsize = HEX_DUMP_SIZE;
+ const __u8 *ptr = buf;
+
+ printf("\t\t%s", title);
+
+ for (j = 0; j < len; j += rowsize) {
+ line_len = rowsize < (len - j) ? rowsize : (len - j);
+ printf("%s%.8x:", prefix_str, j);
+ for (i = 0; i < line_len; i++)
+ printf(" %.2x", ptr[j + i]);
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+TEST(verify_report)
+{
+ struct tdx_report_req req;
+ struct tdreport *tdreport;
+ int devfd, i;
+
+ devfd = open(TDX_GUEST_DEVNAME, O_RDWR | O_SYNC);
+ ASSERT_LT(0, devfd);
+
+ /* Generate sample report data */
+ for (i = 0; i < TDX_REPORTDATA_LEN; i++)
+ req.reportdata[i] = i;
+
+ /* Get TDREPORT */
+ ASSERT_EQ(0, ioctl(devfd, TDX_CMD_GET_REPORT0, &req));
+
+ if (DEBUG) {
+ print_array_hex("\n\t\tTDX report data\n", "",
+ req.reportdata, sizeof(req.reportdata));
+
+ print_array_hex("\n\t\tTDX tdreport data\n", "",
+ req.tdreport, sizeof(req.tdreport));
+ }
+
+ /* Make sure TDREPORT data includes the REPORTDATA passed */
+ tdreport = (struct tdreport *)req.tdreport;
+ ASSERT_EQ(0, memcmp(&tdreport->reportmac.reportdata[0],
+ req.reportdata, sizeof(req.reportdata)));
+
+ ASSERT_EQ(0, close(devfd));
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/timens/.gitignore b/tools/testing/selftests/timens/.gitignore
index fe1eb8271b35..cae8dca0fbff 100644
--- a/tools/testing/selftests/timens/.gitignore
+++ b/tools/testing/selftests/timens/.gitignore
@@ -8,3 +8,4 @@ procfs
timens
timer
timerfd
+vfork_exec
diff --git a/tools/testing/selftests/timens/Makefile b/tools/testing/selftests/timens/Makefile
index 3a5936cc10ab..f0d51d4d2c87 100644
--- a/tools/testing/selftests/timens/Makefile
+++ b/tools/testing/selftests/timens/Makefile
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex
+TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex vfork_exec
TEST_GEN_PROGS_EXTENDED := gettime_perf
CFLAGS := -Wall -Werror -pthread
diff --git a/tools/testing/selftests/timens/vfork_exec.c b/tools/testing/selftests/timens/vfork_exec.c
new file mode 100644
index 000000000000..beb7614941fb
--- /dev/null
+++ b/tools/testing/selftests/timens/vfork_exec.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "log.h"
+#include "timens.h"
+
+#define OFFSET (36000)
+
+struct thread_args {
+ char *tst_name;
+ struct timespec *now;
+};
+
+static void *tcheck(void *_args)
+{
+ struct thread_args *args = _args;
+ struct timespec *now = args->now, tst;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ _gettime(CLOCK_MONOTONIC, &tst, i);
+ if (abs(tst.tv_sec - now->tv_sec) > 5) {
+ pr_fail("%s: in-thread: unexpected value: %ld (%ld)\n",
+ args->tst_name, tst.tv_sec, now->tv_sec);
+ return (void *)1UL;
+ }
+ }
+ return NULL;
+}
+
+static int check_in_thread(char *tst_name, struct timespec *now)
+{
+ struct thread_args args = {
+ .tst_name = tst_name,
+ .now = now,
+ };
+ pthread_t th;
+ void *retval;
+
+ if (pthread_create(&th, NULL, tcheck, &args))
+ return pr_perror("thread");
+ if (pthread_join(th, &retval))
+ return pr_perror("pthread_join");
+ return !(retval == NULL);
+}
+
+static int check(char *tst_name, struct timespec *now)
+{
+ struct timespec tst;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ _gettime(CLOCK_MONOTONIC, &tst, i);
+ if (abs(tst.tv_sec - now->tv_sec) > 5)
+ return pr_fail("%s: unexpected value: %ld (%ld)\n",
+ tst_name, tst.tv_sec, now->tv_sec);
+ }
+ if (check_in_thread(tst_name, now))
+ return 1;
+ ksft_test_result_pass("%s\n", tst_name);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct timespec now;
+ int status;
+ pid_t pid;
+
+ if (argc > 1) {
+ char *endptr;
+
+ ksft_cnt.ksft_pass = 1;
+ now.tv_sec = strtoul(argv[1], &endptr, 0);
+ if (*endptr != 0)
+ return pr_perror("strtoul");
+
+ return check("child after exec", &now);
+ }
+
+ nscheck();
+
+ ksft_set_plan(4);
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (unshare_timens())
+ return 1;
+
+ if (_settime(CLOCK_MONOTONIC, OFFSET))
+ return 1;
+
+ if (check("parent before vfork", &now))
+ return 1;
+
+ pid = vfork();
+ if (pid < 0)
+ return pr_perror("fork");
+
+ if (pid == 0) {
+ char now_str[64];
+ char *cargv[] = {"exec", now_str, NULL};
+ char *cenv[] = {NULL};
+
+ /* Check for proper vvar offsets after execve. */
+ snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
+ execve("/proc/self/exe", cargv, cenv);
+ pr_perror("execve");
+ _exit(1);
+ }
+
+ if (waitpid(pid, &status, 0) != pid)
+ return pr_perror("waitpid");
+
+ if (status)
+ ksft_exit_fail();
+ ksft_inc_pass_cnt();
+ ksft_test_result_pass("wait for child\n");
+
+ /* Check that we are still in the source timens. */
+ if (check("parent after vfork", &now))
+ return 1;
+
+ ksft_exit_pass();
+ return 0;
+}
diff --git a/tools/testing/selftests/tpm2/Makefile b/tools/testing/selftests/tpm2/Makefile
index 1a5db1eb8ed5..a9bf9459fb25 100644
--- a/tools/testing/selftests/tpm2/Makefile
+++ b/tools/testing/selftests/tpm2/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
include ../lib.mk
-TEST_PROGS := test_smoke.sh test_space.sh
+TEST_PROGS := test_smoke.sh test_space.sh test_async.sh
TEST_PROGS_EXTENDED := tpm2.py tpm2_tests.py
diff --git a/tools/testing/selftests/tpm2/test_async.sh b/tools/testing/selftests/tpm2/test_async.sh
new file mode 100755
index 000000000000..43bf5bd772fd
--- /dev/null
+++ b/tools/testing/selftests/tpm2/test_async.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+[ -e /dev/tpm0 ] || exit $ksft_skip
+[ -e /dev/tpmrm0 ] || exit $ksft_skip
+
+python3 -m unittest -v tpm2_tests.AsyncTest
diff --git a/tools/testing/selftests/tpm2/test_smoke.sh b/tools/testing/selftests/tpm2/test_smoke.sh
index 3e5ff29ee1dd..58af963e5b55 100755
--- a/tools/testing/selftests/tpm2/test_smoke.sh
+++ b/tools/testing/selftests/tpm2/test_smoke.sh
@@ -7,4 +7,3 @@ ksft_skip=4
[ -e /dev/tpm0 ] || exit $ksft_skip
python3 -m unittest -v tpm2_tests.SmokeTest
-python3 -m unittest -v tpm2_tests.AsyncTest
diff --git a/tools/testing/selftests/vDSO/vdso_test_getcpu.c b/tools/testing/selftests/vDSO/vdso_test_getcpu.c
index fc25ede131b8..1df5d057d79f 100644
--- a/tools/testing/selftests/vDSO/vdso_test_getcpu.c
+++ b/tools/testing/selftests/vDSO/vdso_test_getcpu.c
@@ -14,7 +14,11 @@
#include "../kselftest.h"
#include "parse_vdso.h"
+#if defined(__riscv)
+const char *version = "LINUX_4.15";
+#else
const char *version = "LINUX_2.6";
+#endif
const char *name = "__vdso_getcpu";
struct getcpu_cache;
diff --git a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c
index 8ccc73ed8240..e411f287a426 100644
--- a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c
+++ b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c
@@ -27,6 +27,9 @@
#if defined(__aarch64__)
const char *version = "LINUX_2.6.39";
const char *name = "__kernel_gettimeofday";
+#elif defined(__riscv)
+const char *version = "LINUX_4.15";
+const char *name = "__vdso_gettimeofday";
#else
const char *version = "LINUX_2.6";
const char *name = "__vdso_gettimeofday";
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index 7b9dc2426f18..a8fbf8548bc0 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -33,3 +33,5 @@ memfd_secret
soft-dirty
split_huge_page_test
ksm_tests
+local_config.h
+local_config.mk
diff --git a/tools/testing/selftests/vm/pkey-x86.h b/tools/testing/selftests/vm/pkey-x86.h
index b078ce9c6d2a..72c14cd3ddc7 100644
--- a/tools/testing/selftests/vm/pkey-x86.h
+++ b/tools/testing/selftests/vm/pkey-x86.h
@@ -104,6 +104,18 @@ static inline int cpu_has_pkeys(void)
return 1;
}
+static inline int cpu_max_xsave_size(void)
+{
+ unsigned long XSTATE_CPUID = 0xd;
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ __cpuid_count(XSTATE_CPUID, 0, eax, ebx, ecx, edx);
+ return ecx;
+}
+
static inline u32 pkey_bit_position(int pkey)
{
return pkey * PKEY_BITS_PER_PKEY;
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index 291bc1e07842..95f403a0c46d 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -18,12 +18,13 @@
* do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks
*
* Compile like this:
- * gcc -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
- * gcc -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
+ * gcc -mxsave -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
+ * gcc -mxsave -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
*/
#define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__
#include <errno.h>
+#include <linux/elf.h>
#include <linux/futex.h>
#include <time.h>
#include <sys/time.h>
@@ -1550,6 +1551,129 @@ void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
do_not_expect_pkey_fault("plain read on recently PROT_EXEC area");
}
+#if defined(__i386__) || defined(__x86_64__)
+void test_ptrace_modifies_pkru(int *ptr, u16 pkey)
+{
+ u32 new_pkru;
+ pid_t child;
+ int status, ret;
+ int pkey_offset = pkey_reg_xstate_offset();
+ size_t xsave_size = cpu_max_xsave_size();
+ void *xsave;
+ u32 *pkey_register;
+ u64 *xstate_bv;
+ struct iovec iov;
+
+ new_pkru = ~read_pkey_reg();
+ /* Don't make PROT_EXEC mappings inaccessible */
+ new_pkru &= ~3;
+
+ child = fork();
+ pkey_assert(child >= 0);
+ dprintf3("[%d] fork() ret: %d\n", getpid(), child);
+ if (!child) {
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+ /* Stop and allow the tracer to modify PKRU directly */
+ raise(SIGSTOP);
+
+ /*
+ * need __read_pkey_reg() version so we do not do shadow_pkey_reg
+ * checking
+ */
+ if (__read_pkey_reg() != new_pkru)
+ exit(1);
+
+ /* Stop and allow the tracer to clear XSTATE_BV for PKRU */
+ raise(SIGSTOP);
+
+ if (__read_pkey_reg() != 0)
+ exit(1);
+
+ /* Stop and allow the tracer to examine PKRU */
+ raise(SIGSTOP);
+
+ exit(0);
+ }
+
+ pkey_assert(child == waitpid(child, &status, 0));
+ dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
+ pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
+
+ xsave = (void *)malloc(xsave_size);
+ pkey_assert(xsave > 0);
+
+ /* Modify the PKRU register directly */
+ iov.iov_base = xsave;
+ iov.iov_len = xsave_size;
+ ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+
+ pkey_register = (u32 *)(xsave + pkey_offset);
+ pkey_assert(*pkey_register == read_pkey_reg());
+
+ *pkey_register = new_pkru;
+
+ ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+
+ /* Test that the modification is visible in ptrace before any execution */
+ memset(xsave, 0xCC, xsave_size);
+ ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+ pkey_assert(*pkey_register == new_pkru);
+
+ /* Execute the tracee */
+ ret = ptrace(PTRACE_CONT, child, 0, 0);
+ pkey_assert(ret == 0);
+
+ /* Test that the tracee saw the PKRU value change */
+ pkey_assert(child == waitpid(child, &status, 0));
+ dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
+ pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
+
+ /* Test that the modification is visible in ptrace after execution */
+ memset(xsave, 0xCC, xsave_size);
+ ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+ pkey_assert(*pkey_register == new_pkru);
+
+ /* Clear the PKRU bit from XSTATE_BV */
+ xstate_bv = (u64 *)(xsave + 512);
+ *xstate_bv &= ~(1 << 9);
+
+ ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+
+ /* Test that the modification is visible in ptrace before any execution */
+ memset(xsave, 0xCC, xsave_size);
+ ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+ pkey_assert(*pkey_register == 0);
+
+ ret = ptrace(PTRACE_CONT, child, 0, 0);
+ pkey_assert(ret == 0);
+
+ /* Test that the tracee saw the PKRU value go to 0 */
+ pkey_assert(child == waitpid(child, &status, 0));
+ dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
+ pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
+
+ /* Test that the modification is visible in ptrace after execution */
+ memset(xsave, 0xCC, xsave_size);
+ ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
+ pkey_assert(ret == 0);
+ pkey_assert(*pkey_register == 0);
+
+ ret = ptrace(PTRACE_CONT, child, 0, 0);
+ pkey_assert(ret == 0);
+ pkey_assert(child == waitpid(child, &status, 0));
+ dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
+ pkey_assert(WIFEXITED(status));
+ pkey_assert(WEXITSTATUS(status) == 0);
+ free(xsave);
+}
+#endif
+
void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
{
int size = PAGE_SIZE;
@@ -1585,6 +1709,9 @@ void (*pkey_tests[])(int *ptr, u16 pkey) = {
test_pkey_syscalls_bad_args,
test_pkey_alloc_exhaust,
test_pkey_alloc_free_attach_pkey0,
+#if defined(__i386__) || defined(__x86_64__)
+ test_ptrace_modifies_pkru,
+#endif
};
void run_tests_once(void)
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c
index f45e510500c0..bc71cbca0dde 100644
--- a/tools/testing/selftests/watchdog/watchdog-test.c
+++ b/tools/testing/selftests/watchdog/watchdog-test.c
@@ -1,6 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Watchdog Driver Test Program
+* Watchdog Driver Test Program
+* - Tests all ioctls
+* - Tests Magic Close - CONFIG_WATCHDOG_NOWAYOUT
+* - Could be tested against softdog driver on systems that
+* don't have watchdog hardware.
+* - TODO:
+* - Enhance test to add coverage for WDIOC_GETTEMP.
+*
+* Reference: Documentation/watchdog/watchdog-api.rst
*/
#include <errno.h>
@@ -19,13 +27,14 @@
int fd;
const char v = 'V';
-static const char sopts[] = "bdehp:t:Tn:NLf:i";
+static const char sopts[] = "bdehp:st:Tn:NLf:i";
static const struct option lopts[] = {
{"bootstatus", no_argument, NULL, 'b'},
{"disable", no_argument, NULL, 'd'},
{"enable", no_argument, NULL, 'e'},
{"help", no_argument, NULL, 'h'},
{"pingrate", required_argument, NULL, 'p'},
+ {"status", no_argument, NULL, 's'},
{"timeout", required_argument, NULL, 't'},
{"gettimeout", no_argument, NULL, 'T'},
{"pretimeout", required_argument, NULL, 'n'},
@@ -74,6 +83,7 @@ static void usage(char *progname)
printf(" -f, --file\t\tOpen watchdog device file\n");
printf("\t\t\tDefault is /dev/watchdog\n");
printf(" -i, --info\t\tShow watchdog_info\n");
+ printf(" -s, --status\t\tGet status & supported features\n");
printf(" -b, --bootstatus\tGet last boot status (Watchdog/POR)\n");
printf(" -d, --disable\t\tTurn off the watchdog timer\n");
printf(" -e, --enable\t\tTurn on the watchdog timer\n");
@@ -91,6 +101,73 @@ static void usage(char *progname)
printf("Example: %s -t 12 -T -n 7 -N\n", progname);
}
+struct wdiof_status {
+ int flag;
+ const char *status_str;
+};
+
+#define WDIOF_NUM_STATUS 8
+
+static const struct wdiof_status wdiof_status[WDIOF_NUM_STATUS] = {
+ {WDIOF_SETTIMEOUT, "Set timeout (in seconds)"},
+ {WDIOF_MAGICCLOSE, "Supports magic close char"},
+ {WDIOF_PRETIMEOUT, "Pretimeout (in seconds), get/set"},
+ {WDIOF_ALARMONLY, "Watchdog triggers a management or other external alarm not a reboot"},
+ {WDIOF_KEEPALIVEPING, "Keep alive ping reply"},
+ {WDIOS_DISABLECARD, "Turn off the watchdog timer"},
+ {WDIOS_ENABLECARD, "Turn on the watchdog timer"},
+ {WDIOS_TEMPPANIC, "Kernel panic on temperature trip"},
+};
+
+static void print_status(int flags)
+{
+ int wdiof = 0;
+
+ if (flags == WDIOS_UNKNOWN) {
+ printf("Unknown status error from WDIOC_GETSTATUS\n");
+ return;
+ }
+
+ for (wdiof = 0; wdiof < WDIOF_NUM_STATUS; wdiof++) {
+ if (flags & wdiof_status[wdiof].flag)
+ printf("Support/Status: %s\n",
+ wdiof_status[wdiof].status_str);
+ }
+}
+
+#define WDIOF_NUM_BOOTSTATUS 7
+
+static const struct wdiof_status wdiof_bootstatus[WDIOF_NUM_BOOTSTATUS] = {
+ {WDIOF_OVERHEAT, "Reset due to CPU overheat"},
+ {WDIOF_FANFAULT, "Fan failed"},
+ {WDIOF_EXTERN1, "External relay 1"},
+ {WDIOF_EXTERN2, "External relay 2"},
+ {WDIOF_POWERUNDER, "Power bad/power fault"},
+ {WDIOF_CARDRESET, "Card previously reset the CPU"},
+ {WDIOF_POWEROVER, "Power over voltage"},
+};
+
+static void print_boot_status(int flags)
+{
+ int wdiof = 0;
+
+ if (flags == WDIOF_UNKNOWN) {
+ printf("Unknown flag error from WDIOC_GETBOOTSTATUS\n");
+ return;
+ }
+
+ if (flags == 0) {
+ printf("Last boot is caused by: Power-On-Reset\n");
+ return;
+ }
+
+ for (wdiof = 0; wdiof < WDIOF_NUM_BOOTSTATUS; wdiof++) {
+ if (flags & wdiof_bootstatus[wdiof].flag)
+ printf("Last boot is caused by: %s\n",
+ wdiof_bootstatus[wdiof].status_str);
+ }
+}
+
int main(int argc, char *argv[])
{
int flags;
@@ -100,6 +177,7 @@ int main(int argc, char *argv[])
int oneshot = 0;
char *file = "/dev/watchdog";
struct watchdog_info info;
+ int temperature;
setbuf(stdout, NULL);
@@ -140,8 +218,7 @@ int main(int argc, char *argv[])
oneshot = 1;
ret = ioctl(fd, WDIOC_GETBOOTSTATUS, &flags);
if (!ret)
- printf("Last boot is caused by: %s.\n", (flags != 0) ?
- "Watchdog" : "Power-On-Reset");
+ print_boot_status(flags);
else
printf("WDIOC_GETBOOTSTATUS error '%s'\n", strerror(errno));
break;
@@ -171,6 +248,21 @@ int main(int argc, char *argv[])
ping_rate = DEFAULT_PING_RATE;
printf("Watchdog ping rate set to %u seconds.\n", ping_rate);
break;
+ case 's':
+ flags = 0;
+ oneshot = 1;
+ ret = ioctl(fd, WDIOC_GETSTATUS, &flags);
+ if (!ret)
+ print_status(flags);
+ else
+ printf("WDIOC_GETSTATUS error '%s'\n", strerror(errno));
+ ret = ioctl(fd, WDIOC_GETTEMP, &temperature);
+ if (ret)
+ printf("WDIOC_GETTEMP: '%s'\n", strerror(errno));
+ else
+ printf("Temperature %d\n", temperature);
+
+ break;
case 't':
flags = strtoul(optarg, NULL, 0);
ret = ioctl(fd, WDIOC_SETTIMEOUT, &flags);
@@ -228,7 +320,7 @@ int main(int argc, char *argv[])
printf(" identity:\t\t%s\n", info.identity);
printf(" firmware_version:\t%u\n",
info.firmware_version);
- printf(" options:\t\t%08x\n", info.options);
+ print_status(info.options);
break;
default:
@@ -249,6 +341,10 @@ int main(int argc, char *argv[])
sleep(ping_rate);
}
end:
+ /*
+ * Send specific magic character 'V' just in case Magic Close is
+ * enabled to ensure watchdog gets disabled on close.
+ */
ret = write(fd, &v, 1);
if (ret < 0)
printf("Stopping watchdog ticks failed (%d)...\n", errno);
diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config
index ce2a04717300..6327c9c400e0 100644
--- a/tools/testing/selftests/wireguard/qemu/kernel.config
+++ b/tools/testing/selftests/wireguard/qemu/kernel.config
@@ -64,8 +64,6 @@ CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
-CONFIG_RANDOM_TRUST_CPU=y
-CONFIG_RANDOM_TRUST_BOOTLOADER=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_LOG_BUF_SHIFT=18
CONFIG_PRINTK_TIME=y
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index b8ec6c15bccb..4dee343909b1 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -903,7 +903,7 @@ out_err:
return NULL;
}
-static void osnoise_usage(void)
+static void osnoise_usage(int err)
{
int i;
@@ -923,7 +923,7 @@ static void osnoise_usage(void)
for (i = 0; msg[i]; i++)
fprintf(stderr, "%s\n", msg[i]);
- exit(1);
+ exit(err);
}
int osnoise_main(int argc, char *argv[])
@@ -941,8 +941,7 @@ int osnoise_main(int argc, char *argv[])
}
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
- osnoise_usage();
- exit(0);
+ osnoise_usage(0);
} else if (strncmp(argv[1], "-", 1) == 0) {
/* the user skipped the tool, call the default one */
osnoise_top_main(argc, argv);
@@ -956,6 +955,6 @@ int osnoise_main(int argc, char *argv[])
}
usage:
- osnoise_usage();
+ osnoise_usage(1);
exit(1);
}
diff --git a/tools/tracing/rtla/src/rtla.c b/tools/tracing/rtla/src/rtla.c
index 09bd21b8af81..52e8f1825281 100644
--- a/tools/tracing/rtla/src/rtla.c
+++ b/tools/tracing/rtla/src/rtla.c
@@ -14,7 +14,7 @@
/*
* rtla_usage - print rtla usage
*/
-static void rtla_usage(void)
+static void rtla_usage(int err)
{
int i;
@@ -33,7 +33,7 @@ static void rtla_usage(void)
for (i = 0; msg[i]; i++)
fprintf(stderr, "%s\n", msg[i]);
- exit(1);
+ exit(err);
}
/*
@@ -70,11 +70,9 @@ int main(int argc, char *argv[])
goto usage;
if (strcmp(argv[1], "-h") == 0) {
- rtla_usage();
- exit(0);
+ rtla_usage(0);
} else if (strcmp(argv[1], "--help") == 0) {
- rtla_usage();
- exit(0);
+ rtla_usage(0);
}
retval = run_command(argc, argv, 1);
@@ -82,6 +80,6 @@ int main(int argc, char *argv[])
exit(0);
usage:
- rtla_usage();
+ rtla_usage(1);
exit(1);
}
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 97abbf494fee..21cdcc5c4a29 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -14,7 +14,7 @@
#include "timerlat.h"
-static void timerlat_usage(void)
+static void timerlat_usage(int err)
{
int i;
@@ -34,7 +34,7 @@ static void timerlat_usage(void)
for (i = 0; msg[i]; i++)
fprintf(stderr, "%s\n", msg[i]);
- exit(1);
+ exit(err);
}
int timerlat_main(int argc, char *argv[])
@@ -52,8 +52,7 @@ int timerlat_main(int argc, char *argv[])
}
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
- timerlat_usage();
- exit(0);
+ timerlat_usage(0);
} else if (strncmp(argv[1], "-", 1) == 0) {
/* the user skipped the tool, call the default one */
timerlat_top_main(argc, argv);
@@ -67,6 +66,6 @@ int timerlat_main(int argc, char *argv[])
}
usage:
- timerlat_usage();
+ timerlat_usage(1);
exit(1);
}
diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile
new file mode 100644
index 000000000000..3d0f3888a58c
--- /dev/null
+++ b/tools/verification/rv/Makefile
@@ -0,0 +1,141 @@
+NAME := rv
+# Follow the kernel version
+VERSION := $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion | grep -v make)
+
+# From libtracefs:
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+ $(if $(or $(findstring environment,$(origin $(1))),\
+ $(findstring command line,$(origin $(1)))),,\
+ $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
+$(call allow-override,PKG_CONFIG,pkg-config)
+$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
+$(call allow-override,LDCONFIG,ldconfig)
+
+INSTALL = install
+MKDIR = mkdir
+FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
+ -fasynchronous-unwind-tables -fstack-clash-protection
+WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
+
+TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs)
+
+CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include
+LDFLAGS := -ggdb $(EXTRA_LDFLAGS)
+LIBS := $$($(PKG_CONFIG) --libs libtracefs)
+
+SRC := $(wildcard src/*.c)
+HDR := $(wildcard src/*.h)
+OBJ := $(SRC:.c=.o)
+DIRS := src
+FILES := Makefile README.txt
+CEXT := bz2
+TARBALL := $(NAME)-$(VERSION).tar.$(CEXT)
+TAROPTS := -cvjf $(TARBALL)
+BINDIR := /usr/bin
+DATADIR := /usr/share
+DOCDIR := $(DATADIR)/doc
+MANDIR := $(DATADIR)/man
+LICDIR := $(DATADIR)/licenses
+SRCTREE := $(or $(BUILD_SRC),$(CURDIR))
+
+# If running from the tarball, man pages are stored in the Documentation
+# dir. If running from the kernel source, man pages are stored in
+# Documentation/tools/rv/.
+ifneq ($(wildcard Documentation/.*),)
+DOCSRC = Documentation/
+else
+DOCSRC = $(SRCTREE)/../../../Documentation/tools/rv/
+endif
+
+LIBTRACEEVENT_MIN_VERSION = 1.5
+LIBTRACEFS_MIN_VERSION = 1.3
+
+.PHONY: all warnings show_warnings
+all: warnings rv
+
+TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
+ifeq ("$(TEST_LIBTRACEEVENT)", "n")
+WARNINGS = show_warnings
+MISSING_LIBS += echo "** libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher";
+MISSING_PACKAGES += "libtraceevent-devel"
+MISSING_SOURCE += echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ ";
+endif
+
+TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
+ifeq ("$(TEST_LIBTRACEFS)", "n")
+WARNINGS = show_warnings
+MISSING_LIBS += echo "** libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher";
+MISSING_PACKAGES += "libtracefs-devel"
+MISSING_SOURCE += echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ ";
+endif
+
+define show_dependencies
+ @echo "********************************************"; \
+ echo "** NOTICE: Failed build dependencies"; \
+ echo "**"; \
+ echo "** Required Libraries:"; \
+ $(MISSING_LIBS) \
+ echo "**"; \
+ echo "** Consider installing the latest libtracefs from your"; \
+ echo "** distribution, e.g., 'dnf install $(MISSING_PACKAGES)' on Fedora,"; \
+ echo "** or from source:"; \
+ echo "**"; \
+ $(MISSING_SOURCE) \
+ echo "**"; \
+ echo "********************************************"
+endef
+
+show_warnings:
+ $(call show_dependencies);
+
+ifneq ("$(WARNINGS)", "")
+ERROR_OUT = $(error Please add the necessary dependencies)
+
+warnings: $(WARNINGS)
+ $(ERROR_OUT)
+endif
+
+rv: $(OBJ)
+ $(CC) -o rv $(LDFLAGS) $(OBJ) $(LIBS)
+
+.PHONY: install
+install: doc_install
+ $(MKDIR) -p $(DESTDIR)$(BINDIR)
+ $(INSTALL) rv -m 755 $(DESTDIR)$(BINDIR)
+ $(STRIP) $(DESTDIR)$(BINDIR)/rv
+
+.PHONY: clean tarball
+clean: doc_clean
+ @test ! -f rv || rm rv
+ @test ! -f $(TARBALL) || rm -f $(TARBALL)
+ @rm -rf *~ $(OBJ) *.tar.$(CEXT)
+
+tarball: clean
+ rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION)
+ echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
+ cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
+ mkdir $(NAME)-$(VERSION)/Documentation/
+ cp -rp $(SRCTREE)/../../../Documentation/tools/rv/* $(NAME)-$(VERSION)/Documentation/
+ tar $(TAROPTS) --exclude='*~' $(NAME)-$(VERSION)
+ rm -rf $(NAME)-$(VERSION)
+
+.PHONY: doc doc_clean doc_install
+doc:
+ $(MAKE) -C $(DOCSRC)
+
+doc_clean:
+ $(MAKE) -C $(DOCSRC) clean
+
+doc_install:
+ $(MAKE) -C $(DOCSRC) install
diff --git a/tools/verification/rv/README.txt b/tools/verification/rv/README.txt
new file mode 100644
index 000000000000..e96be0dfff59
--- /dev/null
+++ b/tools/verification/rv/README.txt
@@ -0,0 +1,38 @@
+RV: Runtime Verification
+
+Runtime Verification (RV) is a lightweight (yet rigorous) method that
+complements classical exhaustive verification techniques (such as model
+checking and theorem proving) with a more practical approach for
+complex systems.
+
+The rv tool is the interface for a collection of monitors that aim
+analysing the logical and timing behavior of Linux.
+
+Installing RV
+
+RV depends on the following libraries and tools:
+
+ - libtracefs
+ - libtraceevent
+
+It also depends on python3-docutils to compile man pages.
+
+For development, we suggest the following steps for compiling rtla:
+
+ $ git clone git://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git
+ $ cd libtraceevent/
+ $ make
+ $ sudo make install
+ $ cd ..
+ $ git clone git://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git
+ $ cd libtracefs/
+ $ make
+ $ sudo make install
+ $ cd ..
+ $ cd $rv_src
+ $ make
+ $ sudo make install
+
+For further information, please see rv manpage and the kernel documentation:
+ Runtime Verification:
+ Documentation/trace/rv/runtime-verification.rst
diff --git a/tools/verification/rv/include/in_kernel.h b/tools/verification/rv/include/in_kernel.h
new file mode 100644
index 000000000000..3090638c8d71
--- /dev/null
+++ b/tools/verification/rv/include/in_kernel.h
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+int ikm_list_monitors(void);
+int ikm_run_monitor(char *monitor, int argc, char **argv);
diff --git a/tools/verification/rv/include/rv.h b/tools/verification/rv/include/rv.h
new file mode 100644
index 000000000000..770fd6da3610
--- /dev/null
+++ b/tools/verification/rv/include/rv.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define MAX_DESCRIPTION 1024
+#define MAX_DA_NAME_LEN 24
+
+struct monitor {
+ char name[MAX_DA_NAME_LEN];
+ char desc[MAX_DESCRIPTION];
+ int enabled;
+};
+
+int should_stop(void);
diff --git a/tools/verification/rv/include/trace.h b/tools/verification/rv/include/trace.h
new file mode 100644
index 000000000000..8d89e8c303fa
--- /dev/null
+++ b/tools/verification/rv/include/trace.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <tracefs.h>
+
+struct trace_instance {
+ struct tracefs_instance *inst;
+ struct tep_handle *tep;
+ struct trace_seq *seq;
+};
+
+int trace_instance_init(struct trace_instance *trace, char *name);
+int trace_instance_start(struct trace_instance *trace);
+void trace_instance_destroy(struct trace_instance *trace);
+
+int collect_registered_events(struct tep_event *event, struct tep_record *record,
+ int cpu, void *context);
diff --git a/tools/verification/rv/include/utils.h b/tools/verification/rv/include/utils.h
new file mode 100644
index 000000000000..f24ae8282bd2
--- /dev/null
+++ b/tools/verification/rv/include/utils.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define MAX_PATH 1024
+
+void debug_msg(const char *fmt, ...);
+void err_msg(const char *fmt, ...);
+
+extern int config_debug;
diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c
new file mode 100644
index 000000000000..50848d79b38b
--- /dev/null
+++ b/tools/verification/rv/src/in_kernel.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * in kernel monitor support: allows rv to control in-kernel monitors.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <trace.h>
+#include <utils.h>
+#include <rv.h>
+
+static int config_has_id;
+static int config_my_pid;
+static int config_trace;
+
+static char *config_initial_reactor;
+static char *config_reactor;
+
+/*
+ * __ikm_read_enable - reads monitor's enable status
+ *
+ * __does not log errors.
+ *
+ * Returns the current status, or -1 if the monitor does not exist,
+ * __hence not logging errors.
+ */
+static int __ikm_read_enable(char *monitor_name)
+{
+ char path[MAX_PATH];
+ long long enabled;
+ int retval;
+
+ snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name);
+
+ retval = tracefs_instance_file_read_number(NULL, path, &enabled);
+ if (retval < 0)
+ return -1;
+
+ return enabled;
+}
+
+/*
+ * ikm_read_enable - reads monitor's enable status
+ *
+ * Returns the current status, or -1 on error.
+ */
+static int ikm_read_enable(char *monitor_name)
+{
+ int enabled;
+
+ enabled = __ikm_read_enable(monitor_name);
+ if (enabled < 0) {
+ err_msg("ikm: fail read enabled: %d\n", enabled);
+ return -1;
+ }
+
+ debug_msg("ikm: read enabled: %d\n", enabled);
+
+ return enabled;
+}
+
+/*
+ * ikm_write_enable - write to the monitor's enable file
+ *
+ * Return the number of bytes written, -1 on error.
+ */
+static int ikm_write_enable(char *monitor_name, char *enable_disable)
+{
+ char path[MAX_PATH];
+ int retval;
+
+ debug_msg("ikm: writing enabled: %s\n", enable_disable);
+
+ snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name);
+ retval = tracefs_instance_file_write(NULL, path, enable_disable);
+ if (retval < strlen(enable_disable)) {
+ err_msg("ikm: writing enabled: %s\n", enable_disable);
+ return -1;
+ }
+
+ return retval;
+}
+
+/*
+ * ikm_enable - enable a monitor
+ *
+ * Returns -1 on failure. Success otherwise.
+ */
+static int ikm_enable(char *monitor_name)
+{
+ return ikm_write_enable(monitor_name, "1");
+}
+
+/*
+ * ikm_disable - disable a monitor
+ *
+ * Returns -1 on failure. Success otherwise.
+ */
+static int ikm_disable(char *monitor_name)
+{
+ return ikm_write_enable(monitor_name, "0");
+}
+
+/*
+ * ikm_read_desc - read monitors' description
+ *
+ * Return a dynamically allocated string with the monitor's
+ * description, NULL otherwise.
+ */
+static char *ikm_read_desc(char *monitor_name)
+{
+ char path[MAX_PATH];
+ char *desc;
+
+ snprintf(path, MAX_PATH, "rv/monitors/%s/desc", monitor_name);
+ desc = tracefs_instance_file_read(NULL, path, NULL);
+ if (!desc) {
+ err_msg("ikm: error reading monitor %s desc\n", monitor_name);
+ return NULL;
+ }
+
+ *strstr(desc, "\n") = '\0';
+
+ return desc;
+}
+
+/*
+ * ikm_fill_monitor_definition - fill monitor's definition
+ *
+ * Returns -1 on error, 0 otherwise.
+ */
+static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
+{
+ int enabled;
+ char *desc;
+
+ enabled = ikm_read_enable(name);
+ if (enabled < 0) {
+ err_msg("ikm: monitor %s fail to read enable file, bug?\n", name);
+ return -1;
+ }
+
+ desc = ikm_read_desc(name);
+ if (!desc) {
+ err_msg("ikm: monitor %s does not have desc file, bug?\n", name);
+ return -1;
+ }
+
+ strncpy(ikm->name, name, MAX_DA_NAME_LEN);
+ ikm->enabled = enabled;
+ strncpy(ikm->desc, desc, MAX_DESCRIPTION);
+
+ free(desc);
+
+ return 0;
+}
+
+/*
+ * ikm_write_reactor - switch the reactor to *reactor
+ *
+ * Return the number or characters written, -1 on error.
+ */
+static int ikm_write_reactor(char *monitor_name, char *reactor)
+{
+ char path[MAX_PATH];
+ int retval;
+
+ snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name);
+ retval = tracefs_instance_file_write(NULL, path, reactor);
+ debug_msg("ikm: write \"%s\" reactors: %d\n", reactor, retval);
+
+ return retval;
+}
+
+/*
+ * ikm_read_reactor - read the reactors file
+ *
+ * Returns a dynamically allocated string with monitor's
+ * available reactors, or NULL on error.
+ */
+static char *ikm_read_reactor(char *monitor_name)
+{
+ char path[MAX_PATH];
+ char *reactors;
+
+ snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name);
+ reactors = tracefs_instance_file_read(NULL, path, NULL);
+ if (!reactors) {
+ err_msg("ikm: fail reading monitor's %s reactors file\n", monitor_name);
+ return NULL;
+ }
+
+ return reactors;
+}
+
+/*
+ * ikm_get_current_reactor - get the current enabled reactor
+ *
+ * Reads the reactors file and find the currently enabled
+ * [reactor].
+ *
+ * Returns a dynamically allocated memory with the current
+ * reactor. NULL otherwise.
+ */
+static char *ikm_get_current_reactor(char *monitor_name)
+{
+ char *reactors = ikm_read_reactor(monitor_name);
+ char *start;
+ char *end;
+ char *curr_reactor;
+
+ if (!reactors)
+ return NULL;
+
+ start = strstr(reactors, "[");
+ if (!start)
+ goto out_free;
+
+ start++;
+
+ end = strstr(start, "]");
+ if (!end)
+ goto out_free;
+
+ *end = '\0';
+
+ curr_reactor = calloc(strlen(start) + 1, sizeof(char));
+ if (!curr_reactor)
+ goto out_free;
+
+ strncpy(curr_reactor, start, strlen(start));
+ debug_msg("ikm: read current reactor %s\n", curr_reactor);
+
+out_free:
+ free(reactors);
+
+ return curr_reactor;
+}
+
+static int ikm_has_id(char *monitor_name)
+{
+ char path[MAX_PATH];
+ char *format;
+ int has_id;
+
+ snprintf(path, MAX_PATH, "events/rv/event_%s/format", monitor_name);
+ format = tracefs_instance_file_read(NULL, path, NULL);
+ if (!format) {
+ err_msg("ikm: fail reading monitor's %s format event file\n", monitor_name);
+ return -1;
+ }
+
+ /* print fmt: "%d: %s x %s -> %s %s", REC->id, ... */
+ has_id = !!strstr(format, "REC->id");
+
+ debug_msg("ikm: monitor %s has id: %s\n", monitor_name, has_id ? "yes" : "no");
+
+ free(format);
+
+ return has_id;
+}
+
+/**
+ * ikm_list_monitors - list all available monitors
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int ikm_list_monitors(void)
+{
+ char *available_monitors;
+ struct monitor ikm;
+ char *curr, *next;
+ int retval;
+
+ available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
+
+ if (!available_monitors) {
+ err_msg("ikm: available monitors is not available, is CONFIG_RV enabled?\n");
+ return -1;
+ }
+
+ curr = available_monitors;
+ do {
+ next = strstr(curr, "\n");
+ *next = '\0';
+
+ retval = ikm_fill_monitor_definition(curr, &ikm);
+ if (retval)
+ err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr);
+
+ printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ curr = ++next;
+
+ } while (strlen(curr));
+
+ free(available_monitors);
+
+ return 0;
+}
+
+static void ikm_print_header(struct trace_seq *s)
+{
+ trace_seq_printf(s, "%16s-%-8s %5s %5s ", "<TASK>", "PID", "[CPU]", "TYPE");
+ if (config_has_id)
+ trace_seq_printf(s, "%8s ", "ID");
+
+ trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n",
+ "STATE",
+ "EVENT",
+ "NEXT_STATE",
+ "FINAL");
+
+ trace_seq_printf(s, "%16s %-8s %5s %5s ", " | ", " | ", " | ", " | ");
+
+ if (config_has_id)
+ trace_seq_printf(s, "%8s ", " | ");
+
+ trace_seq_printf(s, "%24s %-24s %-24s %s\n",
+ " | ",
+ " | ",
+ " | ",
+ "|");
+
+}
+
+/*
+ * ikm_event_handler - callback to handle event events
+ *
+ * Called any time a rv:"monitor"_event events is generated.
+ * It parses and print event.
+ */
+static int
+ikm_event_handler(struct trace_seq *s, struct tep_record *record,
+ struct tep_event *trace_event, void *context)
+{
+ /* if needed: struct trace_instance *inst = context; */
+ char *state, *event, *next_state;
+ unsigned long long final_state;
+ unsigned long long pid;
+ unsigned long long id;
+ int cpu = record->cpu;
+ int val;
+
+ if (config_has_id)
+ tep_get_field_val(s, trace_event, "id", record, &id, 1);
+
+ tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
+
+ if (config_has_id && (config_my_pid == id))
+ return 0;
+ else if (config_my_pid && (config_my_pid == pid))
+ return 0;
+
+ tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM, TEP_PRINT_PID);
+
+ trace_seq_printf(s, "[%.3d] event ", cpu);
+
+ if (config_has_id)
+ trace_seq_printf(s, "%8llu ", id);
+
+ state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
+ event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
+ next_state = tep_get_field_raw(s, trace_event, "next_state", record, &val, 0);
+ tep_get_field_val(s, trace_event, "final_state", record, &final_state, 1);
+
+ trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n",
+ state,
+ event,
+ next_state,
+ final_state ? "Y" : "N");
+
+ trace_seq_do_printf(s);
+ trace_seq_reset(s);
+
+ return 0;
+}
+
+/*
+ * ikm_error_handler - callback to handle error events
+ *
+ * Called any time a rv:"monitor"_errors events is generated.
+ * It parses and print event.
+ */
+static int
+ikm_error_handler(struct trace_seq *s, struct tep_record *record,
+ struct tep_event *trace_event, void *context)
+{
+ unsigned long long pid, id;
+ int cpu = record->cpu;
+ char *state, *event;
+ int val;
+
+ if (config_has_id)
+ tep_get_field_val(s, trace_event, "id", record, &id, 1);
+
+ tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
+
+ if (config_has_id && config_my_pid == id)
+ return 0;
+ else if (config_my_pid == pid)
+ return 0;
+
+ trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu);
+
+ if (config_has_id)
+ trace_seq_printf(s, "%8llu ", id);
+
+ state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
+ event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
+
+ trace_seq_printf(s, "%24s x %s\n", state, event);
+
+ trace_seq_do_printf(s);
+ trace_seq_reset(s);
+
+ return 0;
+}
+
+/*
+ * ikm_setup_trace_instance - set up a tracing instance to collect data
+ *
+ * Create a trace instance, enable rv: events and enable the trace.
+ *
+ * Returns the trace_instance * with all set, NULL otherwise.
+ */
+static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
+{
+ char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
+ struct trace_instance *inst;
+ int retval;
+
+ if (!config_trace)
+ return NULL;
+
+ config_has_id = ikm_has_id(monitor_name);
+ if (config_has_id < 0) {
+ err_msg("ikm: failed to read monitor %s event format\n", monitor_name);
+ goto out_err;
+ }
+
+ /* alloc data */
+ inst = calloc(1, sizeof(*inst));
+ if (!inst) {
+ err_msg("ikm: failed to allocate trace instance");
+ goto out_err;
+ }
+
+ retval = trace_instance_init(inst, monitor_name);
+ if (retval)
+ goto out_free;
+
+ /* enable events */
+ snprintf(event, sizeof(event), "event_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ goto out_inst;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_event_handler, NULL);
+
+ snprintf(event, sizeof(event), "error_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ goto out_inst;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_error_handler, NULL);
+
+ /* ready to enable */
+ tracefs_trace_on(inst->inst);
+
+ return inst;
+
+out_inst:
+ trace_instance_destroy(inst);
+out_free:
+ free(inst);
+out_err:
+ return NULL;
+}
+
+/**
+ * ikm_destroy_trace_instance - destroy a previously created instance
+ */
+static void ikm_destroy_trace_instance(struct trace_instance *inst)
+{
+ if (!inst)
+ return;
+
+ trace_instance_destroy(inst);
+ free(inst);
+}
+
+/*
+ * ikm_usage_print_reactors - print all available reactors, one per line.
+ */
+static void ikm_usage_print_reactors(void)
+{
+ char *reactors = tracefs_instance_file_read(NULL, "rv/available_reactors", NULL);
+ char *start, *end;
+
+ if (!reactors)
+ return;
+
+ fprintf(stderr, " available reactors:");
+
+ start = reactors;
+ end = strstr(start, "\n");
+
+ while (end) {
+ *end = '\0';
+
+ fprintf(stderr, " %s", start);
+
+ start = ++end;
+ end = strstr(start, "\n");
+ };
+
+ fprintf(stderr, "\n");
+}
+/*
+ * ikm_usage - print usage
+ */
+static void ikm_usage(int exit_val, char *monitor_name, const char *fmt, ...)
+{
+
+ char message[1024];
+ va_list ap;
+ int i;
+
+ static const char *const usage[] = {
+ "",
+ " -h/--help: print this menu and the reactor list",
+ " -r/--reactor 'reactor': enables the 'reactor'",
+ " -s/--self: when tracing (-t), also trace rv command",
+ " -t/--trace: trace monitor's event",
+ " -v/--verbose: print debug messages",
+ "",
+ NULL,
+ };
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, " %s\n", message);
+
+ fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", monitor_name);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+
+ ikm_usage_print_reactors();
+ exit(exit_val);
+}
+
+/*
+ * parse_arguments - parse arguments and set config
+ */
+static int parse_arguments(char *monitor_name, int argc, char **argv)
+{
+ int c, retval;
+
+ config_my_pid = getpid();
+
+ while (1) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"reactor", required_argument, 0, 'r'},
+ {"self", no_argument, 0, 's'},
+ {"trace", no_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ /* getopt_long stores the option index here. */
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hr:stv", long_options, &option_index);
+
+ /* detect the end of the options. */
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ ikm_usage(0, monitor_name, "help:");
+ break;
+ case 'r':
+ config_reactor = optarg;
+ break;
+ case 's':
+ config_my_pid = 0;
+ break;
+ case 't':
+ config_trace = 1;
+ break;
+ case 'v':
+ config_debug = 1;
+ break;
+ }
+ }
+
+ if (config_reactor) {
+ config_initial_reactor = ikm_get_current_reactor(monitor_name);
+ if (!config_initial_reactor)
+ ikm_usage(1, monitor_name,
+ "ikm: failed to read current reactor, are reactors enabled?");
+
+ retval = ikm_write_reactor(monitor_name, config_reactor);
+ if (retval <= 0)
+ ikm_usage(1, monitor_name,
+ "ikm: failed to set %s reactor, is it available?",
+ config_reactor);
+ }
+
+ debug_msg("ikm: my pid is %d\n", config_my_pid);
+
+ return 0;
+}
+
+/**
+ * ikm_run_monitor - apply configs and run the monitor
+ *
+ * Returns 1 if a monitor was found an executed, 0 if no
+ * monitors were found, or -1 on error.
+ */
+int ikm_run_monitor(char *monitor_name, int argc, char **argv)
+{
+ struct trace_instance *inst = NULL;
+ int retval;
+
+ /*
+ * Check if monitor exists by seeing it is enabled.
+ */
+ retval = __ikm_read_enable(monitor_name);
+ if (retval < 0)
+ return 0;
+
+ if (retval) {
+ err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name);
+ return -1;
+ }
+
+ /* we should be good to go */
+ retval = parse_arguments(monitor_name, argc, argv);
+ if (retval)
+ ikm_usage(1, monitor_name, "ikm: failed parsing arguments");
+
+ if (config_trace) {
+ inst = ikm_setup_trace_instance(monitor_name);
+ if (!inst)
+ return -1;
+ }
+
+ retval = ikm_enable(monitor_name);
+ if (retval < 0)
+ goto out_free_instance;
+
+ if (config_trace)
+ ikm_print_header(inst->seq);
+
+ while (!should_stop()) {
+ if (config_trace) {
+ retval = tracefs_iterate_raw_events(inst->tep,
+ inst->inst,
+ NULL,
+ 0,
+ collect_registered_events,
+ inst);
+ if (retval) {
+ err_msg("ikm: error reading trace buffer\n");
+ break;
+ }
+ }
+
+ sleep(1);
+ }
+
+ ikm_disable(monitor_name);
+ ikm_destroy_trace_instance(inst);
+
+ if (config_reactor && config_initial_reactor)
+ ikm_write_reactor(monitor_name, config_initial_reactor);
+
+ return 1;
+
+out_free_instance:
+ ikm_destroy_trace_instance(inst);
+ if (config_reactor && config_initial_reactor)
+ ikm_write_reactor(monitor_name, config_initial_reactor);
+ return -1;
+}
diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c
new file mode 100644
index 000000000000..e601cd9c411e
--- /dev/null
+++ b/tools/verification/rv/src/rv.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rv tool, the interface for the Linux kernel RV subsystem and home of
+ * user-space controlled monitors.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <trace.h>
+#include <utils.h>
+#include <in_kernel.h>
+
+static int stop_session;
+
+/*
+ * stop_rv - tell monitors to stop
+ */
+static void stop_rv(int sig)
+{
+ stop_session = 1;
+}
+
+/**
+ * should_stop - check if the monitor should stop.
+ *
+ * Returns 1 if the monitor should stop, 0 otherwise.
+ */
+int should_stop(void)
+{
+ return stop_session;
+}
+
+/*
+ * rv_list - list all available monitors
+ */
+static void rv_list(int argc, char **argv)
+{
+ static const char *const usage[] = {
+ "",
+ " usage: rv list [-h]",
+ "",
+ " list all available monitors",
+ "",
+ " -h/--help: print this menu",
+ NULL,
+ };
+ int i;
+
+ if (argc > 1) {
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ /* more than 1 is always usage */
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+
+ /* but only -h is valid */
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ exit(0);
+ else
+ exit(1);
+ }
+
+ ikm_list_monitors();
+ exit(0);
+}
+
+/*
+ * rv_mon - try to run a monitor passed as argument
+ */
+static void rv_mon(int argc, char **argv)
+{
+ char *monitor_name;
+ int i, run;
+
+ static const char *const usage[] = {
+ "",
+ " usage: rv mon [-h] monitor [monitor options]",
+ "",
+ " run a monitor",
+ "",
+ " -h/--help: print this menu",
+ "",
+ " monitor [monitor options]: the monitor, passing",
+ " the arguments to the [monitor options]",
+ NULL,
+ };
+
+ /* requires at least one argument */
+ if (argc == 1) {
+
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+ exit(1);
+ } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+ exit(0);
+ }
+
+ monitor_name = argv[1];
+ /*
+ * Call all possible monitor implementations, looking
+ * for the [monitor].
+ */
+ run += ikm_run_monitor(monitor_name, argc-1, &argv[1]);
+
+ if (!run)
+ err_msg("rv: monitor %s does not exist\n", monitor_name);
+ exit(!run);
+}
+
+static void usage(int exit_val, const char *fmt, ...)
+{
+ char message[1024];
+ va_list ap;
+ int i;
+
+ static const char *const usage[] = {
+ "",
+ " usage: rv command [-h] [command_options]",
+ "",
+ " -h/--help: print this menu",
+ "",
+ " command: run one of the following command:",
+ " list: list all available monitors",
+ " mon: run a monitor",
+ "",
+ " [command options]: each command has its own set of options",
+ " run rv command -h for further information",
+ NULL,
+ };
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "rv version %s: %s\n", VERSION, message);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+
+ exit(exit_val);
+}
+
+/*
+ * main - select which main sending the command
+ *
+ * main itself redirects the arguments to the sub-commands
+ * to handle the options.
+ *
+ * subcommands should exit.
+ */
+int main(int argc, char **argv)
+{
+ if (geteuid())
+ usage(1, "%s needs root permission", argv[0]);
+
+ if (argc <= 1)
+ usage(1, "%s requires a command", argv[0]);
+
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ usage(0, "help");
+
+ if (!strcmp(argv[1], "list"))
+ rv_list(--argc, &argv[1]);
+
+ if (!strcmp(argv[1], "mon")) {
+ /*
+ * monitor's main should monitor should_stop() function.
+ * and exit.
+ */
+ signal(SIGINT, stop_rv);
+
+ rv_mon(argc - 1, &argv[1]);
+ }
+
+ /* invalid sub-command */
+ usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]);
+}
diff --git a/tools/verification/rv/src/trace.c b/tools/verification/rv/src/trace.c
new file mode 100644
index 000000000000..2c7deed47f8d
--- /dev/null
+++ b/tools/verification/rv/src/trace.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * trace helpers.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <sys/sendfile.h>
+#include <tracefs.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <rv.h>
+#include <trace.h>
+#include <utils.h>
+
+/*
+ * create_instance - create a trace instance with *instance_name
+ */
+static struct tracefs_instance *create_instance(char *instance_name)
+{
+ return tracefs_instance_create(instance_name);
+}
+
+/*
+ * destroy_instance - remove a trace instance and free the data
+ */
+static void destroy_instance(struct tracefs_instance *inst)
+{
+ tracefs_instance_destroy(inst);
+ tracefs_instance_free(inst);
+}
+
+/**
+ * collect_registered_events - call the existing callback function for the event
+ *
+ * If an event has a registered callback function, call it.
+ * Otherwise, ignore the event.
+ *
+ * Returns 0 if the event was collected, 1 if the tool should stop collecting trace.
+ */
+int
+collect_registered_events(struct tep_event *event, struct tep_record *record,
+ int cpu, void *context)
+{
+ struct trace_instance *trace = context;
+ struct trace_seq *s = trace->seq;
+
+ if (should_stop())
+ return 1;
+
+ if (!event->handler)
+ return 0;
+
+ event->handler(s, record, event, context);
+
+ return 0;
+}
+
+/**
+ * trace_instance_destroy - destroy and free a rv trace instance
+ */
+void trace_instance_destroy(struct trace_instance *trace)
+{
+ if (trace->inst) {
+ destroy_instance(trace->inst);
+ trace->inst = NULL;
+ }
+
+ if (trace->seq) {
+ free(trace->seq);
+ trace->seq = NULL;
+ }
+
+ if (trace->tep) {
+ tep_free(trace->tep);
+ trace->tep = NULL;
+ }
+}
+
+/**
+ * trace_instance_init - create an trace instance
+ *
+ * It is more than the tracefs instance, as it contains other
+ * things required for the tracing, such as the local events and
+ * a seq file.
+ *
+ * Note that the trace instance is returned disabled. This allows
+ * the tool to apply some other configs, like setting priority
+ * to the kernel threads, before starting generating trace entries.
+ *
+ * Returns 0 on success, non-zero otherwise.
+ */
+int trace_instance_init(struct trace_instance *trace, char *name)
+{
+ trace->seq = calloc(1, sizeof(*trace->seq));
+ if (!trace->seq)
+ goto out_err;
+
+ trace_seq_init(trace->seq);
+
+ trace->inst = create_instance(name);
+ if (!trace->inst)
+ goto out_err;
+
+ trace->tep = tracefs_local_events(NULL);
+ if (!trace->tep)
+ goto out_err;
+
+ /*
+ * Let the main enable the record after setting some other
+ * things such as the priority of the tracer's threads.
+ */
+ tracefs_trace_off(trace->inst);
+
+ return 0;
+
+out_err:
+ trace_instance_destroy(trace);
+ return 1;
+}
+
+/**
+ * trace_instance_start - start tracing a given rv instance
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int trace_instance_start(struct trace_instance *trace)
+{
+ return tracefs_trace_on(trace->inst);
+}
diff --git a/tools/verification/rv/src/utils.c b/tools/verification/rv/src/utils.c
new file mode 100644
index 000000000000..5677b439dc2f
--- /dev/null
+++ b/tools/verification/rv/src/utils.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * util functions.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <utils.h>
+
+int config_debug;
+
+#define MAX_MSG_LENGTH 1024
+
+/**
+ * err_msg - print an error message to the stderr
+ */
+void err_msg(const char *fmt, ...)
+{
+ char message[MAX_MSG_LENGTH];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "%s", message);
+}
+
+/**
+ * debug_msg - print a debug message to stderr if debug is set
+ */
+void debug_msg(const char *fmt, ...)
+{
+ char message[MAX_MSG_LENGTH];
+ va_list ap;
+
+ if (!config_debug)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "%s", message);
+}
diff --git a/tools/vm/slabinfo-gnuplot.sh b/tools/vm/slabinfo-gnuplot.sh
index 26e193ffd2a2..873a892147e5 100644
--- a/tools/vm/slabinfo-gnuplot.sh
+++ b/tools/vm/slabinfo-gnuplot.sh
@@ -150,7 +150,7 @@ do_preprocess()
let lines=3
out=`basename "$in"`"-slabs-by-loss"
`cat "$in" | grep -A "$lines" 'Slabs sorted by loss' |\
- egrep -iv '\-\-|Name|Slabs'\
+ grep -E -iv '\-\-|Name|Slabs'\
| awk '{print $1" "$4+$2*$3" "$4}' > "$out"`
if [ $? -eq 0 ]; then
do_slabs_plotting "$out"
@@ -159,7 +159,7 @@ do_preprocess()
let lines=3
out=`basename "$in"`"-slabs-by-size"
`cat "$in" | grep -A "$lines" 'Slabs sorted by size' |\
- egrep -iv '\-\-|Name|Slabs'\
+ grep -E -iv '\-\-|Name|Slabs'\
| awk '{print $1" "$4" "$4-$2*$3}' > "$out"`
if [ $? -eq 0 ]; then
do_slabs_plotting "$out"
diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c
index 0fffaeedee76..cfaeaea71042 100644
--- a/tools/vm/slabinfo.c
+++ b/tools/vm/slabinfo.c
@@ -157,9 +157,11 @@ static unsigned long read_obj(const char *name)
{
FILE *f = fopen(name, "r");
- if (!f)
+ if (!f) {
buffer[0] = 0;
- else {
+ if (errno == EACCES)
+ fatal("%s, Try using superuser\n", strerror(errno));
+ } else {
if (!fgets(buffer, sizeof(buffer), f))
buffer[0] = 0;
fclose(f);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 25d7872b29c1..fab4d3790578 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
goto out_err_no_arch_destroy_vm;
}
- kvm->max_halt_poll_ns = halt_poll_ns;
-
r = kvm_arch_init_vm(kvm, type);
if (r)
goto out_err_no_arch_destroy_vm;
@@ -3377,9 +3375,6 @@ static void grow_halt_poll_ns(struct kvm_vcpu *vcpu)
if (val < grow_start)
val = grow_start;
- if (val > vcpu->kvm->max_halt_poll_ns)
- val = vcpu->kvm->max_halt_poll_ns;
-
vcpu->halt_poll_ns = val;
out:
trace_kvm_halt_poll_ns_grow(vcpu->vcpu_id, val, old);
@@ -3483,6 +3478,24 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
}
}
+static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = vcpu->kvm;
+
+ if (kvm->override_halt_poll_ns) {
+ /*
+ * Ensure kvm->max_halt_poll_ns is not read before
+ * kvm->override_halt_poll_ns.
+ *
+ * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
+ */
+ smp_rmb();
+ return READ_ONCE(kvm->max_halt_poll_ns);
+ }
+
+ return READ_ONCE(halt_poll_ns);
+}
+
/*
* Emulate a vCPU halt condition, e.g. HLT on x86, WFI on arm, etc... If halt
* polling is enabled, busy wait for a short time before blocking to avoid the
@@ -3491,12 +3504,18 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
*/
void kvm_vcpu_halt(struct kvm_vcpu *vcpu)
{
+ unsigned int max_halt_poll_ns = kvm_vcpu_max_halt_poll_ns(vcpu);
bool halt_poll_allowed = !kvm_arch_no_poll(vcpu);
- bool do_halt_poll = halt_poll_allowed && vcpu->halt_poll_ns;
ktime_t start, cur, poll_end;
bool waited = false;
+ bool do_halt_poll;
u64 halt_ns;
+ if (vcpu->halt_poll_ns > max_halt_poll_ns)
+ vcpu->halt_poll_ns = max_halt_poll_ns;
+
+ do_halt_poll = halt_poll_allowed && vcpu->halt_poll_ns;
+
start = cur = poll_end = ktime_get();
if (do_halt_poll) {
ktime_t stop = ktime_add_ns(start, vcpu->halt_poll_ns);
@@ -3535,18 +3554,21 @@ out:
update_halt_poll_stats(vcpu, start, poll_end, !waited);
if (halt_poll_allowed) {
+ /* Recompute the max halt poll time in case it changed. */
+ max_halt_poll_ns = kvm_vcpu_max_halt_poll_ns(vcpu);
+
if (!vcpu_valid_wakeup(vcpu)) {
shrink_halt_poll_ns(vcpu);
- } else if (vcpu->kvm->max_halt_poll_ns) {
+ } else if (max_halt_poll_ns) {
if (halt_ns <= vcpu->halt_poll_ns)
;
/* we had a long block, shrink polling */
else if (vcpu->halt_poll_ns &&
- halt_ns > vcpu->kvm->max_halt_poll_ns)
+ halt_ns > max_halt_poll_ns)
shrink_halt_poll_ns(vcpu);
/* we had a short halt and our poll time is too small */
- else if (vcpu->halt_poll_ns < vcpu->kvm->max_halt_poll_ns &&
- halt_ns < vcpu->kvm->max_halt_poll_ns)
+ else if (vcpu->halt_poll_ns < max_halt_poll_ns &&
+ halt_ns < max_halt_poll_ns)
grow_halt_poll_ns(vcpu);
} else {
vcpu->halt_poll_ns = 0;
@@ -4581,6 +4603,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
return -EINVAL;
kvm->max_halt_poll_ns = cap->args[0];
+
+ /*
+ * Ensure kvm->override_halt_poll_ns does not become visible
+ * before kvm->max_halt_poll_ns.
+ *
+ * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
+ */
+ smp_wmb();
+ kvm->override_halt_poll_ns = true;
+
return 0;
}
case KVM_CAP_DIRTY_LOG_RING:
diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c
index 346e47f15572..7c248193ca26 100644
--- a/virt/kvm/pfncache.c
+++ b/virt/kvm/pfncache.c
@@ -297,7 +297,12 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
if (!gpc->valid || old_uhva != gpc->uhva) {
ret = hva_to_pfn_retry(kvm, gpc);
} else {
- /* If the HVA→PFN mapping was already valid, don't unmap it. */
+ /*
+ * If the HVA→PFN mapping was already valid, don't unmap it.
+ * But do update gpc->khva because the offset within the page
+ * may have changed.
+ */
+ gpc->khva = old_khva + page_offset;
old_pfn = KVM_PFN_ERR_FAULT;
old_khva = NULL;
ret = 0;